--- linux-4.4.0.orig/Documentation/ABI/stable/sysfs-bus-vmbus
+++ linux-4.4.0/Documentation/ABI/stable/sysfs-bus-vmbus
@@ -27,3 +27,17 @@
 		Virtual Processors.
 		Format: <channel's child_relid:the bound cpu's number>
 Users:		tools/hv/lsvmbus
+
+What:		/sys/bus/vmbus/devices/vmbus_*/device
+Date:		Dec. 2015
+KernelVersion:	4.5
+Contact:	K. Y. Srinivasan <kys@microsoft.com>
+Description:	The 16 bit device ID of the device
+Users:		tools/hv/lsvmbus and user level RDMA libraries
+
+What:		/sys/bus/vmbus/devices/vmbus_*/vendor
+Date:		Dec. 2015
+KernelVersion:	4.5
+Contact:	K. Y. Srinivasan <kys@microsoft.com>
+Description:	The 16 bit vendor ID of the device
+Users:		tools/hv/lsvmbus and user level RDMA libraries
--- linux-4.4.0.orig/Documentation/ABI/testing/debugfs-aufs
+++ linux-4.4.0/Documentation/ABI/testing/debugfs-aufs
@@ -0,0 +1,50 @@
+What:		/debug/aufs/si_<id>/
+Date:		March 2009
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		Under /debug/aufs, a directory named si_<id> is created
+		per aufs mount, where <id> is a unique id generated
+		internally.
+
+What:		/debug/aufs/si_<id>/plink
+Date:		Apr 2013
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		It has three lines and shows the information about the
+		pseudo-link. The first line is a single number
+		representing a number of buckets. The second line is a
+		number of pseudo-links per buckets (separated by a
+		blank). The last line is a single number representing a
+		total number of psedo-links.
+		When the aufs mount option 'noplink' is specified, it
+		will show "1\n0\n0\n".
+
+What:		/debug/aufs/si_<id>/xib
+Date:		March 2009
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		It shows the consumed blocks by xib (External Inode Number
+		Bitmap), its block size and file size.
+		When the aufs mount option 'noxino' is specified, it
+		will be empty. About XINO files, see the aufs manual.
+
+What:		/debug/aufs/si_<id>/xino0, xino1 ... xinoN
+Date:		March 2009
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		It shows the consumed blocks by xino (External Inode Number
+		Translation Table), its link count, block size and file
+		size.
+		When the aufs mount option 'noxino' is specified, it
+		will be empty. About XINO files, see the aufs manual.
+
+What:		/debug/aufs/si_<id>/xigen
+Date:		March 2009
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		It shows the consumed blocks by xigen (External Inode
+		Generation Table), its block size and file size.
+		If CONFIG_AUFS_EXPORT is disabled, this entry will not
+		be created.
+		When the aufs mount option 'noxino' is specified, it
+		will be empty. About XINO files, see the aufs manual.
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-aufs
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-aufs
@@ -0,0 +1,31 @@
+What:		/sys/fs/aufs/si_<id>/
+Date:		March 2009
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		Under /sys/fs/aufs, a directory named si_<id> is created
+		per aufs mount, where <id> is a unique id generated
+		internally.
+
+What:		/sys/fs/aufs/si_<id>/br0, br1 ... brN
+Date:		March 2009
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		It shows the abolute path of a member directory (which
+		is called branch) in aufs, and its permission.
+
+What:		/sys/fs/aufs/si_<id>/brid0, brid1 ... bridN
+Date:		July 2013
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		It shows the id of a member directory (which is called
+		branch) in aufs.
+
+What:		/sys/fs/aufs/si_<id>/xi_path
+Date:		March 2009
+Contact:	J. R. Okajima <hooanon05g@gmail.com>
+Description:
+		It shows the abolute path of XINO (External Inode Number
+		Bitmap, Translation Table and Generation Table) file
+		even if it is the default path.
+		When the aufs mount option 'noxino' is specified, it
+		will be empty. About XINO files, see the aufs manual.
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-bus-iio
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-bus-iio
@@ -1470,7 +1470,8 @@
 KernelVersion:	4.3
 Contact:	linux-iio@vger.kernel.org
 Description:
-		Raw (unscaled no offset etc.) percentage reading of a substance.
+		Raw (unscaled no offset etc.) reading of a substance. Units
+		after application of scale and offset are percents.
 
 What:		/sys/bus/iio/devices/iio:deviceX/in_resistance_raw
 What:		/sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
@@ -1,4 +1,4 @@
-What		/sys/bus/iio/devices/iio:deviceX/in_proximity_raw
+What		/sys/bus/iio/devices/iio:deviceX/in_proximity_input
 Date:		March 2014
 KernelVersion:	3.15
 Contact:	Matt Ranostay <mranostay@gmail.com>
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-bus-mei
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-bus-mei
@@ -4,7 +4,7 @@
 Contact:	Samuel Ortiz <sameo@linux.intel.com>
 		linux-mei@linux.intel.com
 Description:	Stores the same MODALIAS value emitted by uevent
-		Format: mei:<mei device name>:<device uuid>:
+		Format: mei:<mei device name>:<device uuid>:<protocol version>
 
 What:		/sys/bus/mei/devices/.../name
 Date:		May 2015
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-bus-usb
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-bus-usb
@@ -134,19 +134,21 @@
 		enabled for the device. Developer can write y/Y/1 or n/N/0 to
 		the file to enable/disable the feature.
 
-What:		/sys/bus/usb/devices/.../power/usb3_hardware_lpm
-Date:		June 2015
+What:		/sys/bus/usb/devices/.../power/usb3_hardware_lpm_u1
+		/sys/bus/usb/devices/.../power/usb3_hardware_lpm_u2
+Date:		November 2015
 Contact:	Kevin Strasser <kevin.strasser@linux.intel.com>
+		Lu Baolu <baolu.lu@linux.intel.com>
 Description:
 		If CONFIG_PM is set and a USB 3.0 lpm-capable device is plugged
 		in to a xHCI host which supports link PM, it will check if U1
 		and U2 exit latencies have been set in the BOS descriptor; if
-		the check is is passed and the host supports USB3 hardware LPM,
+		the check is passed and the host supports USB3 hardware LPM,
 		USB3 hardware LPM will be enabled for the device and the USB
-		device directory will contain a file named
-		power/usb3_hardware_lpm. The file holds a string value (enable
-		or disable) indicating whether or not USB3 hardware LPM is
-		enabled for the device.
+		device directory will contain two files named
+		power/usb3_hardware_lpm_u1 and power/usb3_hardware_lpm_u2. These
+		files hold a string value (enable or disable) indicating whether
+		or not USB3 hardware LPM U1 or U2 is enabled for the device.
 
 What:		/sys/bus/usb/devices/.../removable
 Date:		February 2012
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-class-cxl
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-class-cxl
@@ -159,7 +159,7 @@
                 Decimal value of the Per Process MMIO space length.
 Users:		https://github.com/ibm-capi/libcxl
 
-What:           /sys/class/cxl/<afu>m/pp_mmio_off
+What:           /sys/class/cxl/<afu>m/pp_mmio_off (not in a guest)
 Date:           September 2014
 Contact:        linuxppc-dev@lists.ozlabs.org
 Description:    read only
@@ -183,7 +183,7 @@
                 Identifies the revision level of the PSL.
 Users:		https://github.com/ibm-capi/libcxl
 
-What:           /sys/class/cxl/<card>/base_image
+What:           /sys/class/cxl/<card>/base_image (not in a guest)
 Date:           September 2014
 Contact:        linuxppc-dev@lists.ozlabs.org
 Description:    read only
@@ -193,7 +193,7 @@
                 during the initial program load.
 Users:		https://github.com/ibm-capi/libcxl
 
-What:           /sys/class/cxl/<card>/image_loaded
+What:           /sys/class/cxl/<card>/image_loaded (not in a guest)
 Date:           September 2014
 Contact:        linuxppc-dev@lists.ozlabs.org
 Description:    read only
@@ -201,7 +201,7 @@
                 onto the card.
 Users:		https://github.com/ibm-capi/libcxl
 
-What:           /sys/class/cxl/<card>/load_image_on_perst
+What:           /sys/class/cxl/<card>/load_image_on_perst (not in a guest)
 Date:           December 2014
 Contact:        linuxppc-dev@lists.ozlabs.org
 Description:    read/write
@@ -224,7 +224,7 @@
                 to reload the FPGA depending on load_image_on_perst.
 Users:		https://github.com/ibm-capi/libcxl
 
-What:		/sys/class/cxl/<card>/perst_reloads_same_image
+What:		/sys/class/cxl/<card>/perst_reloads_same_image (not in a guest)
 Date:		July 2015
 Contact:	linuxppc-dev@lists.ozlabs.org
 Description:	read/write
@@ -233,3 +233,11 @@
 		0 = don't trust, the image may be different (default)
 		1 = trust that the image will not change.
 Users:		https://github.com/ibm-capi/libcxl
+
+What:           /sys/class/cxl/<card>/psl_timebase_synced
+Date:           March 2016
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Returns 1 if the psl timebase register is synchronized
+                with the core timebase register, 0 otherwise.
+Users:          https://github.com/ibm-capi/libcxl
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-class-devfreq
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-class-devfreq
@@ -54,6 +54,8 @@
 		In order to activate this ABI, the devfreq target device
 		driver should provide the list of available frequencies
 		with its profile.
+		If the transition table is bigger than PAGE_SIZE, reading
+		this will return an -EFBIG error.
 
 What:		/sys/class/devfreq/.../userspace/set_freq
 Date:		September 2011
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -271,3 +271,119 @@
 			- WriteBack: data is written only to the cache line and
 				     the modified cache line is written to main
 				     memory only when it is replaced
+
+What:		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats
+		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/turbo_stat
+		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/sub_turbo_stat
+		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/unthrottle
+		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/powercap
+		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/overtemp
+		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/supply_fault
+		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/overcurrent
+		/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/occ_reset
+Date:		March 2016
+Contact:	Linux kernel mailing list <linux-kernel@vger.kernel.org>
+		Linux for PowerPC mailing list <linuxppc-dev@ozlabs.org>
+Description:	POWERNV CPUFreq driver's frequency throttle stats directory and
+		attributes
+
+		'cpuX/cpufreq/throttle_stats' directory contains the CPU frequency
+		throttle stat attributes for the chip. The throttle stats of a cpu
+		is common across all the cpus belonging to a chip. Below are the
+		throttle attributes exported in the 'throttle_stats' directory:
+
+		- turbo_stat : This file gives the total number of times the max
+		frequency is throttled to lower frequency in turbo (at and above
+		nominal frequency) range of frequencies.
+
+		- sub_turbo_stat : This file gives the total number of times the
+		max frequency is throttled to lower frequency in sub-turbo(below
+		nominal frequency) range of frequencies.
+
+		- unthrottle : This file gives the total number of times the max
+		frequency is unthrottled after being throttled.
+
+		- powercap : This file gives the total number of times the max
+		frequency is throttled due to 'Power Capping'.
+
+		- overtemp : This file gives the total number of times the max
+		frequency is throttled due to 'CPU Over Temperature'.
+
+		- supply_fault : This file gives the total number of times the
+		max frequency is throttled due to 'Power Supply Failure'.
+
+		- overcurrent : This file gives the total number of times the
+		max frequency is throttled due to 'Overcurrent'.
+
+		- occ_reset : This file gives the total number of times the max
+		frequency is throttled due to 'OCC Reset'.
+
+		The sysfs attributes representing different throttle reasons like
+		powercap, overtemp, supply_fault, overcurrent and occ_reset map to
+		the reasons provided by OCC firmware for throttling the frequency.
+
+What:		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats
+		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats/turbo_stat
+		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats/sub_turbo_stat
+		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats/unthrottle
+		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats/powercap
+		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats/overtemp
+		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats/supply_fault
+		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats/overcurrent
+		/sys/devices/system/cpu/cpufreq/policyX/throttle_stats/occ_reset
+Date:		March 2016
+Contact:	Linux kernel mailing list <linux-kernel@vger.kernel.org>
+		Linux for PowerPC mailing list <linuxppc-dev@ozlabs.org>
+Description:	POWERNV CPUFreq driver's frequency throttle stats directory and
+		attributes
+
+		'policyX/throttle_stats' directory and all the attributes are same as
+		the /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats directory and
+		attributes which give the frequency throttle information of the chip.
+
+What:		/sys/devices/system/cpu/vulnerabilities
+		/sys/devices/system/cpu/vulnerabilities/gather_data_sampling
+		/sys/devices/system/cpu/vulnerabilities/itlb_multihit
+		/sys/devices/system/cpu/vulnerabilities/l1tf
+		/sys/devices/system/cpu/vulnerabilities/mds
+		/sys/devices/system/cpu/vulnerabilities/meltdown
+		/sys/devices/system/cpu/vulnerabilities/mmio_stale_data
+		/sys/devices/system/cpu/vulnerabilities/spec_store_bypass
+		/sys/devices/system/cpu/vulnerabilities/spectre_v1
+		/sys/devices/system/cpu/vulnerabilities/spectre_v2
+		/sys/devices/system/cpu/vulnerabilities/srbds
+		/sys/devices/system/cpu/vulnerabilities/tsx_async_abort
+		/sys/devices/system/cpu/vulnerabilities/vmscape
+Date:		January 2018
+Contact:	Linux kernel mailing list <linux-kernel@vger.kernel.org>
+Description:	Information about CPU vulnerabilities
+
+		The files are named after the code names of CPU
+		vulnerabilities. The output of those files reflects the
+		state of the CPUs in the system. Possible output values:
+
+		"Not affected"	  CPU is not affected by the vulnerability
+		"Vulnerable"	  CPU is affected and no mitigation in effect
+		"Mitigation: $M"  CPU is affected and mitigation $M is in effect
+
+		See also: Documentation/admin-guide/hw-vuln/index.rst
+
+What:		/sys/devices/system/cpu/smt
+		/sys/devices/system/cpu/smt/active
+		/sys/devices/system/cpu/smt/control
+Date:		June 2018
+Contact:	Linux kernel mailing list <linux-kernel@vger.kernel.org>
+Description:	Control Symetric Multi Threading (SMT)
+
+		active:  Tells whether SMT is active (enabled and siblings online)
+
+		control: Read/write interface to control SMT. Possible
+			 values:
+
+			 "on"		SMT is enabled
+			 "off"		SMT is disabled
+			 "forceoff"	SMT is force disabled. Cannot be changed.
+			 "notsupported" SMT is not supported by the CPU
+
+			 If control status is "forceoff" or "notsupported" writes
+			 are rejected.
--- linux-4.4.0.orig/Documentation/ABI/testing/sysfs-kernel-livepatch
+++ linux-4.4.0/Documentation/ABI/testing/sysfs-kernel-livepatch
@@ -33,7 +33,7 @@
 		The object directory contains subdirectories for each function
 		that is patched within the object.
 
-What:		/sys/kernel/livepatch/<patch>/<object>/<function>
+What:		/sys/kernel/livepatch/<patch>/<object>/<function,sympos>
 Date:		Nov 2014
 KernelVersion:	3.19.0
 Contact:	live-patching@vger.kernel.org
@@ -41,4 +41,8 @@
 		The function directory contains attributes regarding the
 		properties and state of the patched function.
 
+		The directory name contains the patched function name and a
+		sympos number corresponding to the nth occurrence of the symbol
+		name in kallsyms for the patched object.
+
 		There are currently no such attributes.
--- linux-4.4.0.orig/Documentation/Changes
+++ linux-4.4.0/Documentation/Changes
@@ -25,7 +25,7 @@
 o  GNU make               3.80                    # make --version
 o  binutils               2.12                    # ld -v
 o  util-linux             2.10o                   # fdformat --version
-o  module-init-tools      0.9.10                  # depmod -V
+o  kmod                   13                      # depmod -V
 o  e2fsprogs              1.41.4                  # e2fsck -V
 o  jfsutils               1.1.3                   # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V
@@ -132,12 +132,6 @@
 reproduce the Oops with that option, then you can still decode that Oops
 with ksymoops.
 
-Module-Init-Tools
------------------
-
-A new module loader is now in the kernel that requires module-init-tools
-to use.  It is backward compatible with the 2.4.x series kernels.
-
 Mkinitrd
 --------
 
@@ -319,14 +313,15 @@
 ----------
 o  <ftp://ftp.kernel.org/pub/linux/utils/util-linux/>
 
+Kmod
+----
+o  <https://www.kernel.org/pub/linux/utils/kernel/kmod/>
+o  <https://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git>
+
 Ksymoops
 --------
 o  <ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.4/>
 
-Module-Init-Tools
------------------
-o  <ftp://ftp.kernel.org/pub/linux/kernel/people/rusty/modules/>
-
 Mkinitrd
 --------
 o  <https://code.launchpad.net/initrd-tools/main>
--- linux-4.4.0.orig/Documentation/DMA-attributes.txt
+++ linux-4.4.0/Documentation/DMA-attributes.txt
@@ -100,3 +100,20 @@
 be mapped as contiguous chunk into device dma address space. By
 specifying this attribute the allocated buffer is forced to be contiguous
 also in physical memory.
+
+DMA_ATTR_NO_WARN
+----------------
+
+This tells the DMA-mapping subsystem to suppress allocation failure reports
+(similarly to __GFP_NOWARN).
+
+On some architectures allocation failures are reported with error messages
+to the system logs.  Although this can help to identify and debug problems,
+drivers which handle failures (eg, retry later) have no problems with them,
+and can actually flood the system logs with error messages that aren't any
+problem at all, depending on the implementation of the retry mechanism.
+
+So, this provides a way for drivers to avoid those error messages on calls
+where allocation failures are not a problem, and shouldn't bother the logs.
+
+NOTE: At the moment DMA_ATTR_NO_WARN is only implemented on PowerPC.
--- linux-4.4.0.orig/Documentation/DocBook/gpu.tmpl
+++ linux-4.4.0/Documentation/DocBook/gpu.tmpl
@@ -2350,6 +2350,12 @@
 !Edrivers/gpu/drm/drm_dp_helper.c
     </sect2>
     <sect2>
+      <title>Display Port Dual Mode Adaptor Helper Functions Reference</title>
+!Pdrivers/gpu/drm/drm_dp_dual_mode_helper.c dp dual mode helpers
+!Iinclude/drm/drm_dp_dual_mode_helper.h
+!Edrivers/gpu/drm/drm_dp_dual_mode_helper.c
+    </sect2>
+    <sect2>
       <title>Display Port MST Helper Functions Reference</title>
 !Pdrivers/gpu/drm/drm_dp_mst_topology.c dp mst helper
 !Iinclude/drm/drm_dp_mst_helper.h
@@ -2543,7 +2549,7 @@
 	<td valign="top" >Description/Restrictions</td>
 	</tr>
 	<tr>
-	<td rowspan="37" valign="top" >DRM</td>
+	<td rowspan="42" valign="top" >DRM</td>
 	<td valign="top" >Generic</td>
 	<td valign="top" >“rotation”</td>
 	<td valign="top" >BITMASK</td>
@@ -2795,7 +2801,7 @@
 	<td valign="top" >property to suggest an Y offset for a connector</td>
 	</tr>
 	<tr>
-	<td rowspan="3" valign="top" >Optional</td>
+	<td rowspan="8" valign="top" >Optional</td>
 	<td valign="top" >“scaling mode”</td>
 	<td valign="top" >ENUM</td>
 	<td valign="top" >{ "None", "Full", "Center", "Full aspect" }</td>
@@ -2819,6 +2825,61 @@
 	<td valign="top" >TBD</td>
 	</tr>
 	<tr>
+	<td valign="top" >“DEGAMMA_LUT”</td>
+	<td valign="top" >BLOB</td>
+	<td valign="top" >0</td>
+	<td valign="top" >CRTC</td>
+	<td valign="top" >DRM property to set the degamma lookup table
+		(LUT) mapping pixel data from the framebuffer before it is
+		given to the transformation matrix. The data is an interpreted
+		as an array of struct drm_color_lut elements. Hardware might
+		choose not to use the full precision of the LUT elements nor
+		use all the elements of the LUT (for example the hardware
+		might choose to interpolate between LUT[0] and LUT[4]). </td>
+	</tr>
+	<tr>
+	<td valign="top" >“DEGAMMA_LUT_SIZE”</td>
+	<td valign="top" >RANGE | IMMUTABLE</td>
+	<td valign="top" >Min=0, Max=UINT_MAX</td>
+	<td valign="top" >CRTC</td>
+	<td valign="top" >DRM property to gives the size of the lookup
+		table to be set on the DEGAMMA_LUT property (the size depends
+		on the underlying hardware).</td>
+	</tr>
+	<tr>
+	<td valign="top" >“CTM”</td>
+	<td valign="top" >BLOB</td>
+	<td valign="top" >0</td>
+	<td valign="top" >CRTC</td>
+	<td valign="top" >DRM property to set the current
+		transformation matrix (CTM) apply to pixel data after the
+		lookup through the degamma LUT and before the lookup through
+		the gamma LUT. The data is an interpreted as a struct
+		drm_color_ctm.</td>
+	</tr>
+	<tr>
+	<td valign="top" >“GAMMA_LUT”</td>
+	<td valign="top" >BLOB</td>
+	<td valign="top" >0</td>
+	<td valign="top" >CRTC</td>
+	<td valign="top" >DRM property to set the gamma lookup table
+		(LUT) mapping pixel data after to the transformation matrix to
+		data sent to the connector. The data is an interpreted as an
+		array of struct drm_color_lut elements. Hardware might choose
+		not to use the full precision of the LUT elements nor use all
+		the elements of the LUT (for example the hardware might choose
+		to interpolate between LUT[0] and LUT[4]).</td>
+	</tr>
+	<tr>
+	<td valign="top" >“GAMMA_LUT_SIZE”</td>
+	<td valign="top" >RANGE | IMMUTABLE</td>
+	<td valign="top" >Min=0, Max=UINT_MAX</td>
+	<td valign="top" >CRTC</td>
+	<td valign="top" >DRM property to gives the size of the lookup
+		table to be set on the GAMMA_LUT property (the size depends on
+		the underlying hardware).</td>
+	</tr>
+	<tr>
 	<td rowspan="20" valign="top" >i915</td>
 	<td rowspan="2" valign="top" >Generic</td>
 	<td valign="top" >"Broadcast RGB"</td>
--- linux-4.4.0.orig/Documentation/DocBook/libata.tmpl
+++ linux-4.4.0/Documentation/DocBook/libata.tmpl
@@ -324,7 +324,7 @@
 
 	<sect2><title>High-level taskfile hooks</title>
 	<programlisting>
-void (*qc_prep) (struct ata_queued_cmd *qc);
+enum ata_completion_errors (*qc_prep) (struct ata_queued_cmd *qc);
 int (*qc_issue) (struct ata_queued_cmd *qc);
 	</programlisting>
 
--- linux-4.4.0.orig/Documentation/Makefile
+++ linux-4.4.0/Documentation/Makefile
@@ -1,4 +1,3 @@
 subdir-y := accounting auxdisplay blackfin connector \
-	filesystems filesystems ia64 laptops mic misc-devices \
-	networking pcmcia prctl ptp spi timers vDSO video4linux \
-	watchdog
+	filesystems filesystems ia64 laptops misc-devices \
+	pcmcia prctl ptp spi timers vDSO video4linux watchdog
--- linux-4.4.0.orig/Documentation/accounting/getdelays.c
+++ linux-4.4.0/Documentation/accounting/getdelays.c
@@ -135,7 +135,7 @@
 	msg.g.version = 0x1;
 	na = (struct nlattr *) GENLMSG_DATA(&msg);
 	na->nla_type = nla_type;
-	na->nla_len = nla_len + 1 + NLA_HDRLEN;
+	na->nla_len = nla_len + NLA_HDRLEN;
 	memcpy(NLA_DATA(na), nla_data, nla_len);
 	msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
 
--- linux-4.4.0.orig/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst
+++ linux-4.4.0/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst
@@ -0,0 +1,99 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+GDS - Gather Data Sampling
+==========================
+
+Gather Data Sampling is a hardware vulnerability which allows unprivileged
+speculative access to data which was previously stored in vector registers.
+
+Problem
+-------
+When a gather instruction performs loads from memory, different data elements
+are merged into the destination vector register. However, when a gather
+instruction that is transiently executed encounters a fault, stale data from
+architectural or internal vector registers may get transiently forwarded to the
+destination vector register instead. This will allow a malicious attacker to
+infer stale data using typical side channel techniques like cache timing
+attacks. GDS is a purely sampling-based attack.
+
+The attacker uses gather instructions to infer the stale vector register data.
+The victim does not need to do anything special other than use the vector
+registers. The victim does not need to use gather instructions to be
+vulnerable.
+
+Because the buffers are shared between Hyper-Threads cross Hyper-Thread attacks
+are possible.
+
+Attack scenarios
+----------------
+Without mitigation, GDS can infer stale data across virtually all
+permission boundaries:
+
+	Non-enclaves can infer SGX enclave data
+	Userspace can infer kernel data
+	Guests can infer data from hosts
+	Guest can infer guest from other guests
+	Users can infer data from other users
+
+Because of this, it is important to ensure that the mitigation stays enabled in
+lower-privilege contexts like guests and when running outside SGX enclaves.
+
+The hardware enforces the mitigation for SGX. Likewise, VMMs should  ensure
+that guests are not allowed to disable the GDS mitigation. If a host erred and
+allowed this, a guest could theoretically disable GDS mitigation, mount an
+attack, and re-enable it.
+
+Mitigation mechanism
+--------------------
+This issue is mitigated in microcode. The microcode defines the following new
+bits:
+
+ ================================   ===   ============================
+ IA32_ARCH_CAPABILITIES[GDS_CTRL]   R/O   Enumerates GDS vulnerability
+                                          and mitigation support.
+ IA32_ARCH_CAPABILITIES[GDS_NO]     R/O   Processor is not vulnerable.
+ IA32_MCU_OPT_CTRL[GDS_MITG_DIS]    R/W   Disables the mitigation
+                                          0 by default.
+ IA32_MCU_OPT_CTRL[GDS_MITG_LOCK]   R/W   Locks GDS_MITG_DIS=0. Writes
+                                          to GDS_MITG_DIS are ignored
+                                          Can't be cleared once set.
+ ================================   ===   ============================
+
+GDS can also be mitigated on systems that don't have updated microcode by
+disabling AVX. This can be done by setting "clearcpuid=avx" on the kernel
+command-line.
+
+Mitigation control on the kernel command line
+---------------------------------------------
+The mitigation can be disabled by setting "gather_data_sampling=off" or
+"mitigations=off" on the kernel command line. Not specifying either will
+default to the mitigation being enabled.
+
+GDS System Information
+------------------------
+The kernel provides vulnerability status information through sysfs. For
+GDS this can be accessed by the following sysfs file:
+
+/sys/devices/system/cpu/vulnerabilities/gather_data_sampling
+
+The possible values contained in this file are:
+
+ ============================== =============================================
+ Not affected                   Processor not vulnerable.
+ Vulnerable                     Processor vulnerable and mitigation disabled.
+ Vulnerable: No microcode       Processor vulnerable and microcode is missing
+                                mitigation.
+ Mitigation: Microcode          Processor is vulnerable and mitigation is in
+                                effect.
+ Mitigation: Microcode (locked) Processor is vulnerable and mitigation is in
+                                effect and cannot be disabled.
+ Unknown: Dependent on
+ hypervisor status              Running on a virtual guest processor that is
+                                affected but with no way to know if host
+                                processor is mitigated or vulnerable.
+ ============================== =============================================
+
+GDS Default mitigation
+----------------------
+The updated microcode will enable the mitigation by default. The kernel's
+default action is to leave the mitigation enabled.
--- linux-4.4.0.orig/Documentation/admin-guide/hw-vuln/index.rst
+++ linux-4.4.0/Documentation/admin-guide/hw-vuln/index.rst
@@ -0,0 +1,18 @@
+========================
+Hardware vulnerabilities
+========================
+
+This section describes CPU vulnerabilities and provides an overview of the
+possible mitigations along with guidance for selecting mitigations if they
+are configurable at compile, boot or run time.
+
+.. toctree::
+   :maxdepth: 1
+
+   l1tf
+   mds
+   tsx_async_abort
+   special-register-buffer-data-sampling.rst
+   processor_mmio_stale_data
+   gather_data_sampling.rst
+   vmscape.rst
--- linux-4.4.0.orig/Documentation/admin-guide/hw-vuln/l1tf.rst
+++ linux-4.4.0/Documentation/admin-guide/hw-vuln/l1tf.rst
@@ -0,0 +1,615 @@
+L1TF - L1 Terminal Fault
+========================
+
+L1 Terminal Fault is a hardware vulnerability which allows unprivileged
+speculative access to data which is available in the Level 1 Data Cache
+when the page table entry controlling the virtual address, which is used
+for the access, has the Present bit cleared or other reserved bits set.
+
+Affected processors
+-------------------
+
+This vulnerability affects a wide range of Intel processors. The
+vulnerability is not present on:
+
+   - Processors from AMD, Centaur and other non Intel vendors
+
+   - Older processor models, where the CPU family is < 6
+
+   - A range of Intel ATOM processors (Cedarview, Cloverview, Lincroft,
+     Penwell, Pineview, Silvermont, Airmont, Merrifield)
+
+   - The Intel XEON PHI family
+
+   - Intel processors which have the ARCH_CAP_RDCL_NO bit set in the
+     IA32_ARCH_CAPABILITIES MSR. If the bit is set the CPU is not affected
+     by the Meltdown vulnerability either. These CPUs should become
+     available by end of 2018.
+
+Whether a processor is affected or not can be read out from the L1TF
+vulnerability file in sysfs. See :ref:`l1tf_sys_info`.
+
+Related CVEs
+------------
+
+The following CVE entries are related to the L1TF vulnerability:
+
+   =============  =================  ==============================
+   CVE-2018-3615  L1 Terminal Fault  SGX related aspects
+   CVE-2018-3620  L1 Terminal Fault  OS, SMM related aspects
+   CVE-2018-3646  L1 Terminal Fault  Virtualization related aspects
+   =============  =================  ==============================
+
+Problem
+-------
+
+If an instruction accesses a virtual address for which the relevant page
+table entry (PTE) has the Present bit cleared or other reserved bits set,
+then speculative execution ignores the invalid PTE and loads the referenced
+data if it is present in the Level 1 Data Cache, as if the page referenced
+by the address bits in the PTE was still present and accessible.
+
+While this is a purely speculative mechanism and the instruction will raise
+a page fault when it is retired eventually, the pure act of loading the
+data and making it available to other speculative instructions opens up the
+opportunity for side channel attacks to unprivileged malicious code,
+similar to the Meltdown attack.
+
+While Meltdown breaks the user space to kernel space protection, L1TF
+allows to attack any physical memory address in the system and the attack
+works across all protection domains. It allows an attack of SGX and also
+works from inside virtual machines because the speculation bypasses the
+extended page table (EPT) protection mechanism.
+
+
+Attack scenarios
+----------------
+
+1. Malicious user space
+^^^^^^^^^^^^^^^^^^^^^^^
+
+   Operating Systems store arbitrary information in the address bits of a
+   PTE which is marked non present. This allows a malicious user space
+   application to attack the physical memory to which these PTEs resolve.
+   In some cases user-space can maliciously influence the information
+   encoded in the address bits of the PTE, thus making attacks more
+   deterministic and more practical.
+
+   The Linux kernel contains a mitigation for this attack vector, PTE
+   inversion, which is permanently enabled and has no performance
+   impact. The kernel ensures that the address bits of PTEs, which are not
+   marked present, never point to cacheable physical memory space.
+
+   A system with an up to date kernel is protected against attacks from
+   malicious user space applications.
+
+2. Malicious guest in a virtual machine
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   The fact that L1TF breaks all domain protections allows malicious guest
+   OSes, which can control the PTEs directly, and malicious guest user
+   space applications, which run on an unprotected guest kernel lacking the
+   PTE inversion mitigation for L1TF, to attack physical host memory.
+
+   A special aspect of L1TF in the context of virtualization is symmetric
+   multi threading (SMT). The Intel implementation of SMT is called
+   HyperThreading. The fact that Hyperthreads on the affected processors
+   share the L1 Data Cache (L1D) is important for this. As the flaw allows
+   only to attack data which is present in L1D, a malicious guest running
+   on one Hyperthread can attack the data which is brought into the L1D by
+   the context which runs on the sibling Hyperthread of the same physical
+   core. This context can be host OS, host user space or a different guest.
+
+   If the processor does not support Extended Page Tables, the attack is
+   only possible, when the hypervisor does not sanitize the content of the
+   effective (shadow) page tables.
+
+   While solutions exist to mitigate these attack vectors fully, these
+   mitigations are not enabled by default in the Linux kernel because they
+   can affect performance significantly. The kernel provides several
+   mechanisms which can be utilized to address the problem depending on the
+   deployment scenario. The mitigations, their protection scope and impact
+   are described in the next sections.
+
+   The default mitigations and the rationale for choosing them are explained
+   at the end of this document. See :ref:`default_mitigations`.
+
+.. _l1tf_sys_info:
+
+L1TF system information
+-----------------------
+
+The Linux kernel provides a sysfs interface to enumerate the current L1TF
+status of the system: whether the system is vulnerable, and which
+mitigations are active. The relevant sysfs file is:
+
+/sys/devices/system/cpu/vulnerabilities/l1tf
+
+The possible values in this file are:
+
+  ===========================   ===============================
+  'Not affected'		The processor is not vulnerable
+  'Mitigation: PTE Inversion'	The host protection is active
+  ===========================   ===============================
+
+If KVM/VMX is enabled and the processor is vulnerable then the following
+information is appended to the 'Mitigation: PTE Inversion' part:
+
+  - SMT status:
+
+    =====================  ================
+    'VMX: SMT vulnerable'  SMT is enabled
+    'VMX: SMT disabled'    SMT is disabled
+    =====================  ================
+
+  - L1D Flush mode:
+
+    ================================  ====================================
+    'L1D vulnerable'		      L1D flushing is disabled
+
+    'L1D conditional cache flushes'   L1D flush is conditionally enabled
+
+    'L1D cache flushes'		      L1D flush is unconditionally enabled
+    ================================  ====================================
+
+The resulting grade of protection is discussed in the following sections.
+
+
+Host mitigation mechanism
+-------------------------
+
+The kernel is unconditionally protected against L1TF attacks from malicious
+user space running on the host.
+
+
+Guest mitigation mechanisms
+---------------------------
+
+.. _l1d_flush:
+
+1. L1D flush on VMENTER
+^^^^^^^^^^^^^^^^^^^^^^^
+
+   To make sure that a guest cannot attack data which is present in the L1D
+   the hypervisor flushes the L1D before entering the guest.
+
+   Flushing the L1D evicts not only the data which should not be accessed
+   by a potentially malicious guest, it also flushes the guest
+   data. Flushing the L1D has a performance impact as the processor has to
+   bring the flushed guest data back into the L1D. Depending on the
+   frequency of VMEXIT/VMENTER and the type of computations in the guest
+   performance degradation in the range of 1% to 50% has been observed. For
+   scenarios where guest VMEXIT/VMENTER are rare the performance impact is
+   minimal. Virtio and mechanisms like posted interrupts are designed to
+   confine the VMEXITs to a bare minimum, but specific configurations and
+   application scenarios might still suffer from a high VMEXIT rate.
+
+   The kernel provides two L1D flush modes:
+    - conditional ('cond')
+    - unconditional ('always')
+
+   The conditional mode avoids L1D flushing after VMEXITs which execute
+   only audited code paths before the corresponding VMENTER. These code
+   paths have been verified that they cannot expose secrets or other
+   interesting data to an attacker, but they can leak information about the
+   address space layout of the hypervisor.
+
+   Unconditional mode flushes L1D on all VMENTER invocations and provides
+   maximum protection. It has a higher overhead than the conditional
+   mode. The overhead cannot be quantified correctly as it depends on the
+   workload scenario and the resulting number of VMEXITs.
+
+   The general recommendation is to enable L1D flush on VMENTER. The kernel
+   defaults to conditional mode on affected processors.
+
+   **Note**, that L1D flush does not prevent the SMT problem because the
+   sibling thread will also bring back its data into the L1D which makes it
+   attackable again.
+
+   L1D flush can be controlled by the administrator via the kernel command
+   line and sysfs control files. See :ref:`mitigation_control_command_line`
+   and :ref:`mitigation_control_kvm`.
+
+.. _guest_confinement:
+
+2. Guest VCPU confinement to dedicated physical cores
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   To address the SMT problem, it is possible to make a guest or a group of
+   guests affine to one or more physical cores. The proper mechanism for
+   that is to utilize exclusive cpusets to ensure that no other guest or
+   host tasks can run on these cores.
+
+   If only a single guest or related guests run on sibling SMT threads on
+   the same physical core then they can only attack their own memory and
+   restricted parts of the host memory.
+
+   Host memory is attackable, when one of the sibling SMT threads runs in
+   host OS (hypervisor) context and the other in guest context. The amount
+   of valuable information from the host OS context depends on the context
+   which the host OS executes, i.e. interrupts, soft interrupts and kernel
+   threads. The amount of valuable data from these contexts cannot be
+   declared as non-interesting for an attacker without deep inspection of
+   the code.
+
+   **Note**, that assigning guests to a fixed set of physical cores affects
+   the ability of the scheduler to do load balancing and might have
+   negative effects on CPU utilization depending on the hosting
+   scenario. Disabling SMT might be a viable alternative for particular
+   scenarios.
+
+   For further information about confining guests to a single or to a group
+   of cores consult the cpusets documentation:
+
+   https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt
+
+.. _interrupt_isolation:
+
+3. Interrupt affinity
+^^^^^^^^^^^^^^^^^^^^^
+
+   Interrupts can be made affine to logical CPUs. This is not universally
+   true because there are types of interrupts which are truly per CPU
+   interrupts, e.g. the local timer interrupt. Aside of that multi queue
+   devices affine their interrupts to single CPUs or groups of CPUs per
+   queue without allowing the administrator to control the affinities.
+
+   Moving the interrupts, which can be affinity controlled, away from CPUs
+   which run untrusted guests, reduces the attack vector space.
+
+   Whether the interrupts with are affine to CPUs, which run untrusted
+   guests, provide interesting data for an attacker depends on the system
+   configuration and the scenarios which run on the system. While for some
+   of the interrupts it can be assumed that they won't expose interesting
+   information beyond exposing hints about the host OS memory layout, there
+   is no way to make general assumptions.
+
+   Interrupt affinity can be controlled by the administrator via the
+   /proc/irq/$NR/smp_affinity[_list] files. Limited documentation is
+   available at:
+
+   https://www.kernel.org/doc/Documentation/IRQ-affinity.txt
+
+.. _smt_control:
+
+4. SMT control
+^^^^^^^^^^^^^^
+
+   To prevent the SMT issues of L1TF it might be necessary to disable SMT
+   completely. Disabling SMT can have a significant performance impact, but
+   the impact depends on the hosting scenario and the type of workloads.
+   The impact of disabling SMT needs also to be weighted against the impact
+   of other mitigation solutions like confining guests to dedicated cores.
+
+   The kernel provides a sysfs interface to retrieve the status of SMT and
+   to control it. It also provides a kernel command line interface to
+   control SMT.
+
+   The kernel command line interface consists of the following options:
+
+     =========== ==========================================================
+     nosmt	 Affects the bring up of the secondary CPUs during boot. The
+		 kernel tries to bring all present CPUs online during the
+		 boot process. "nosmt" makes sure that from each physical
+		 core only one - the so called primary (hyper) thread is
+		 activated. Due to a design flaw of Intel processors related
+		 to Machine Check Exceptions the non primary siblings have
+		 to be brought up at least partially and are then shut down
+		 again.  "nosmt" can be undone via the sysfs interface.
+
+     nosmt=force Has the same effect as "nosmt" but it does not allow to
+		 undo the SMT disable via the sysfs interface.
+     =========== ==========================================================
+
+   The sysfs interface provides two files:
+
+   - /sys/devices/system/cpu/smt/control
+   - /sys/devices/system/cpu/smt/active
+
+   /sys/devices/system/cpu/smt/control:
+
+     This file allows to read out the SMT control state and provides the
+     ability to disable or (re)enable SMT. The possible states are:
+
+	==============  ===================================================
+	on		SMT is supported by the CPU and enabled. All
+			logical CPUs can be onlined and offlined without
+			restrictions.
+
+	off		SMT is supported by the CPU and disabled. Only
+			the so called primary SMT threads can be onlined
+			and offlined without restrictions. An attempt to
+			online a non-primary sibling is rejected
+
+	forceoff	Same as 'off' but the state cannot be controlled.
+			Attempts to write to the control file are rejected.
+
+	notsupported	The processor does not support SMT. It's therefore
+			not affected by the SMT implications of L1TF.
+			Attempts to write to the control file are rejected.
+	==============  ===================================================
+
+     The possible states which can be written into this file to control SMT
+     state are:
+
+     - on
+     - off
+     - forceoff
+
+   /sys/devices/system/cpu/smt/active:
+
+     This file reports whether SMT is enabled and active, i.e. if on any
+     physical core two or more sibling threads are online.
+
+   SMT control is also possible at boot time via the l1tf kernel command
+   line parameter in combination with L1D flush control. See
+   :ref:`mitigation_control_command_line`.
+
+5. Disabling EPT
+^^^^^^^^^^^^^^^^
+
+  Disabling EPT for virtual machines provides full mitigation for L1TF even
+  with SMT enabled, because the effective page tables for guests are
+  managed and sanitized by the hypervisor. Though disabling EPT has a
+  significant performance impact especially when the Meltdown mitigation
+  KPTI is enabled.
+
+  EPT can be disabled in the hypervisor via the 'kvm-intel.ept' parameter.
+
+There is ongoing research and development for new mitigation mechanisms to
+address the performance impact of disabling SMT or EPT.
+
+.. _mitigation_control_command_line:
+
+Mitigation control on the kernel command line
+---------------------------------------------
+
+The kernel command line allows to control the L1TF mitigations at boot
+time with the option "l1tf=". The valid arguments for this option are:
+
+  ============  =============================================================
+  full		Provides all available mitigations for the L1TF
+		vulnerability. Disables SMT and enables all mitigations in
+		the hypervisors, i.e. unconditional L1D flushing
+
+		SMT control and L1D flush control via the sysfs interface
+		is still possible after boot.  Hypervisors will issue a
+		warning when the first VM is started in a potentially
+		insecure configuration, i.e. SMT enabled or L1D flush
+		disabled.
+
+  full,force	Same as 'full', but disables SMT and L1D flush runtime
+		control. Implies the 'nosmt=force' command line option.
+		(i.e. sysfs control of SMT is disabled.)
+
+  flush		Leaves SMT enabled and enables the default hypervisor
+		mitigation, i.e. conditional L1D flushing
+
+		SMT control and L1D flush control via the sysfs interface
+		is still possible after boot.  Hypervisors will issue a
+		warning when the first VM is started in a potentially
+		insecure configuration, i.e. SMT enabled or L1D flush
+		disabled.
+
+  flush,nosmt	Disables SMT and enables the default hypervisor mitigation,
+		i.e. conditional L1D flushing.
+
+		SMT control and L1D flush control via the sysfs interface
+		is still possible after boot.  Hypervisors will issue a
+		warning when the first VM is started in a potentially
+		insecure configuration, i.e. SMT enabled or L1D flush
+		disabled.
+
+  flush,nowarn	Same as 'flush', but hypervisors will not warn when a VM is
+		started in a potentially insecure configuration.
+
+  off		Disables hypervisor mitigations and doesn't emit any
+		warnings.
+		It also drops the swap size and available RAM limit restrictions
+		on both hypervisor and bare metal.
+
+  ============  =============================================================
+
+The default is 'flush'. For details about L1D flushing see :ref:`l1d_flush`.
+
+
+.. _mitigation_control_kvm:
+
+Mitigation control for KVM - module parameter
+-------------------------------------------------------------
+
+The KVM hypervisor mitigation mechanism, flushing the L1D cache when
+entering a guest, can be controlled with a module parameter.
+
+The option/parameter is "kvm-intel.vmentry_l1d_flush=". It takes the
+following arguments:
+
+  ============  ==============================================================
+  always	L1D cache flush on every VMENTER.
+
+  cond		Flush L1D on VMENTER only when the code between VMEXIT and
+		VMENTER can leak host memory which is considered
+		interesting for an attacker. This still can leak host memory
+		which allows e.g. to determine the hosts address space layout.
+
+  never		Disables the mitigation
+  ============  ==============================================================
+
+The parameter can be provided on the kernel command line, as a module
+parameter when loading the modules and at runtime modified via the sysfs
+file:
+
+/sys/module/kvm_intel/parameters/vmentry_l1d_flush
+
+The default is 'cond'. If 'l1tf=full,force' is given on the kernel command
+line, then 'always' is enforced and the kvm-intel.vmentry_l1d_flush
+module parameter is ignored and writes to the sysfs file are rejected.
+
+.. _mitigation_selection:
+
+Mitigation selection guide
+--------------------------
+
+1. No virtualization in use
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   The system is protected by the kernel unconditionally and no further
+   action is required.
+
+2. Virtualization with trusted guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   If the guest comes from a trusted source and the guest OS kernel is
+   guaranteed to have the L1TF mitigations in place the system is fully
+   protected against L1TF and no further action is required.
+
+   To avoid the overhead of the default L1D flushing on VMENTER the
+   administrator can disable the flushing via the kernel command line and
+   sysfs control files. See :ref:`mitigation_control_command_line` and
+   :ref:`mitigation_control_kvm`.
+
+
+3. Virtualization with untrusted guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+3.1. SMT not supported or disabled
+""""""""""""""""""""""""""""""""""
+
+  If SMT is not supported by the processor or disabled in the BIOS or by
+  the kernel, it's only required to enforce L1D flushing on VMENTER.
+
+  Conditional L1D flushing is the default behaviour and can be tuned. See
+  :ref:`mitigation_control_command_line` and :ref:`mitigation_control_kvm`.
+
+3.2. EPT not supported or disabled
+""""""""""""""""""""""""""""""""""
+
+  If EPT is not supported by the processor or disabled in the hypervisor,
+  the system is fully protected. SMT can stay enabled and L1D flushing on
+  VMENTER is not required.
+
+  EPT can be disabled in the hypervisor via the 'kvm-intel.ept' parameter.
+
+3.3. SMT and EPT supported and active
+"""""""""""""""""""""""""""""""""""""
+
+  If SMT and EPT are supported and active then various degrees of
+  mitigations can be employed:
+
+  - L1D flushing on VMENTER:
+
+    L1D flushing on VMENTER is the minimal protection requirement, but it
+    is only potent in combination with other mitigation methods.
+
+    Conditional L1D flushing is the default behaviour and can be tuned. See
+    :ref:`mitigation_control_command_line` and :ref:`mitigation_control_kvm`.
+
+  - Guest confinement:
+
+    Confinement of guests to a single or a group of physical cores which
+    are not running any other processes, can reduce the attack surface
+    significantly, but interrupts, soft interrupts and kernel threads can
+    still expose valuable data to a potential attacker. See
+    :ref:`guest_confinement`.
+
+  - Interrupt isolation:
+
+    Isolating the guest CPUs from interrupts can reduce the attack surface
+    further, but still allows a malicious guest to explore a limited amount
+    of host physical memory. This can at least be used to gain knowledge
+    about the host address space layout. The interrupts which have a fixed
+    affinity to the CPUs which run the untrusted guests can depending on
+    the scenario still trigger soft interrupts and schedule kernel threads
+    which might expose valuable information. See
+    :ref:`interrupt_isolation`.
+
+The above three mitigation methods combined can provide protection to a
+certain degree, but the risk of the remaining attack surface has to be
+carefully analyzed. For full protection the following methods are
+available:
+
+  - Disabling SMT:
+
+    Disabling SMT and enforcing the L1D flushing provides the maximum
+    amount of protection. This mitigation is not depending on any of the
+    above mitigation methods.
+
+    SMT control and L1D flushing can be tuned by the command line
+    parameters 'nosmt', 'l1tf', 'kvm-intel.vmentry_l1d_flush' and at run
+    time with the matching sysfs control files. See :ref:`smt_control`,
+    :ref:`mitigation_control_command_line` and
+    :ref:`mitigation_control_kvm`.
+
+  - Disabling EPT:
+
+    Disabling EPT provides the maximum amount of protection as well. It is
+    not depending on any of the above mitigation methods. SMT can stay
+    enabled and L1D flushing is not required, but the performance impact is
+    significant.
+
+    EPT can be disabled in the hypervisor via the 'kvm-intel.ept'
+    parameter.
+
+3.4. Nested virtual machines
+""""""""""""""""""""""""""""
+
+When nested virtualization is in use, three operating systems are involved:
+the bare metal hypervisor, the nested hypervisor and the nested virtual
+machine.  VMENTER operations from the nested hypervisor into the nested
+guest will always be processed by the bare metal hypervisor. If KVM is the
+bare metal hypervisor it will:
+
+ - Flush the L1D cache on every switch from the nested hypervisor to the
+   nested virtual machine, so that the nested hypervisor's secrets are not
+   exposed to the nested virtual machine;
+
+ - Flush the L1D cache on every switch from the nested virtual machine to
+   the nested hypervisor; this is a complex operation, and flushing the L1D
+   cache avoids that the bare metal hypervisor's secrets are exposed to the
+   nested virtual machine;
+
+ - Instruct the nested hypervisor to not perform any L1D cache flush. This
+   is an optimization to avoid double L1D flushing.
+
+
+.. _default_mitigations:
+
+Default mitigations
+-------------------
+
+  The kernel default mitigations for vulnerable processors are:
+
+  - PTE inversion to protect against malicious user space. This is done
+    unconditionally and cannot be controlled. The swap storage is limited
+    to ~16TB.
+
+  - L1D conditional flushing on VMENTER when EPT is enabled for
+    a guest.
+
+  The kernel does not by default enforce the disabling of SMT, which leaves
+  SMT systems vulnerable when running untrusted guests with EPT enabled.
+
+  The rationale for this choice is:
+
+  - Force disabling SMT can break existing setups, especially with
+    unattended updates.
+
+  - If regular users run untrusted guests on their machine, then L1TF is
+    just an add on to other malware which might be embedded in an untrusted
+    guest, e.g. spam-bots or attacks on the local network.
+
+    There is no technical way to prevent a user from running untrusted code
+    on their machines blindly.
+
+  - It's technically extremely unlikely and from today's knowledge even
+    impossible that L1TF can be exploited via the most popular attack
+    mechanisms like JavaScript because these mechanisms have no way to
+    control PTEs. If this would be possible and not other mitigation would
+    be possible, then the default might be different.
+
+  - The administrators of cloud and hosting setups have to carefully
+    analyze the risk for their scenarios and make the appropriate
+    mitigation choices, which might even vary across their deployed
+    machines and also result in other changes of their overall setup.
+    There is no way for the kernel to provide a sensible default for this
+    kind of scenarios.
--- linux-4.4.0.orig/Documentation/admin-guide/hw-vuln/mds.rst
+++ linux-4.4.0/Documentation/admin-guide/hw-vuln/mds.rst
@@ -0,0 +1,311 @@
+MDS - Microarchitectural Data Sampling
+======================================
+
+Microarchitectural Data Sampling is a hardware vulnerability which allows
+unprivileged speculative access to data which is available in various CPU
+internal buffers.
+
+Affected processors
+-------------------
+
+This vulnerability affects a wide range of Intel processors. The
+vulnerability is not present on:
+
+   - Processors from AMD, Centaur and other non Intel vendors
+
+   - Older processor models, where the CPU family is < 6
+
+   - Some Atoms (Bonnell, Saltwell, Goldmont, GoldmontPlus)
+
+   - Intel processors which have the ARCH_CAP_MDS_NO bit set in the
+     IA32_ARCH_CAPABILITIES MSR.
+
+Whether a processor is affected or not can be read out from the MDS
+vulnerability file in sysfs. See :ref:`mds_sys_info`.
+
+Not all processors are affected by all variants of MDS, but the mitigation
+is identical for all of them so the kernel treats them as a single
+vulnerability.
+
+Related CVEs
+------------
+
+The following CVE entries are related to the MDS vulnerability:
+
+   ==============  =====  ===================================================
+   CVE-2018-12126  MSBDS  Microarchitectural Store Buffer Data Sampling
+   CVE-2018-12130  MFBDS  Microarchitectural Fill Buffer Data Sampling
+   CVE-2018-12127  MLPDS  Microarchitectural Load Port Data Sampling
+   CVE-2019-11091  MDSUM  Microarchitectural Data Sampling Uncacheable Memory
+   ==============  =====  ===================================================
+
+Problem
+-------
+
+When performing store, load, L1 refill operations, processors write data
+into temporary microarchitectural structures (buffers). The data in the
+buffer can be forwarded to load operations as an optimization.
+
+Under certain conditions, usually a fault/assist caused by a load
+operation, data unrelated to the load memory address can be speculatively
+forwarded from the buffers. Because the load operation causes a fault or
+assist and its result will be discarded, the forwarded data will not cause
+incorrect program execution or state changes. But a malicious operation
+may be able to forward this speculative data to a disclosure gadget which
+allows in turn to infer the value via a cache side channel attack.
+
+Because the buffers are potentially shared between Hyper-Threads cross
+Hyper-Thread attacks are possible.
+
+Deeper technical information is available in the MDS specific x86
+architecture section: :ref:`Documentation/x86/mds.rst <mds>`.
+
+
+Attack scenarios
+----------------
+
+Attacks against the MDS vulnerabilities can be mounted from malicious non
+priviledged user space applications running on hosts or guest. Malicious
+guest OSes can obviously mount attacks as well.
+
+Contrary to other speculation based vulnerabilities the MDS vulnerability
+does not allow the attacker to control the memory target address. As a
+consequence the attacks are purely sampling based, but as demonstrated with
+the TLBleed attack samples can be postprocessed successfully.
+
+Web-Browsers
+^^^^^^^^^^^^
+
+  It's unclear whether attacks through Web-Browsers are possible at
+  all. The exploitation through Java-Script is considered very unlikely,
+  but other widely used web technologies like Webassembly could possibly be
+  abused.
+
+
+.. _mds_sys_info:
+
+MDS system information
+-----------------------
+
+The Linux kernel provides a sysfs interface to enumerate the current MDS
+status of the system: whether the system is vulnerable, and which
+mitigations are active. The relevant sysfs file is:
+
+/sys/devices/system/cpu/vulnerabilities/mds
+
+The possible values in this file are:
+
+  .. list-table::
+
+     * - 'Not affected'
+       - The processor is not vulnerable
+     * - 'Vulnerable'
+       - The processor is vulnerable, but no mitigation enabled
+     * - 'Vulnerable: Clear CPU buffers attempted, no microcode'
+       - The processor is vulnerable but microcode is not updated.
+
+         The mitigation is enabled on a best effort basis. See :ref:`vmwerv`
+     * - 'Mitigation: Clear CPU buffers'
+       - The processor is vulnerable and the CPU buffer clearing mitigation is
+         enabled.
+
+If the processor is vulnerable then the following information is appended
+to the above information:
+
+    ========================  ============================================
+    'SMT vulnerable'          SMT is enabled
+    'SMT mitigated'           SMT is enabled and mitigated
+    'SMT disabled'            SMT is disabled
+    'SMT Host state unknown'  Kernel runs in a VM, Host SMT state unknown
+    ========================  ============================================
+
+.. _vmwerv:
+
+Best effort mitigation mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+  If the processor is vulnerable, but the availability of the microcode based
+  mitigation mechanism is not advertised via CPUID the kernel selects a best
+  effort mitigation mode.  This mode invokes the mitigation instructions
+  without a guarantee that they clear the CPU buffers.
+
+  This is done to address virtualization scenarios where the host has the
+  microcode update applied, but the hypervisor is not yet updated to expose
+  the CPUID to the guest. If the host has updated microcode the protection
+  takes effect otherwise a few cpu cycles are wasted pointlessly.
+
+  The state in the mds sysfs file reflects this situation accordingly.
+
+
+Mitigation mechanism
+-------------------------
+
+The kernel detects the affected CPUs and the presence of the microcode
+which is required.
+
+If a CPU is affected and the microcode is available, then the kernel
+enables the mitigation by default. The mitigation can be controlled at boot
+time via a kernel command line option. See
+:ref:`mds_mitigation_control_command_line`.
+
+.. _cpu_buffer_clear:
+
+CPU buffer clearing
+^^^^^^^^^^^^^^^^^^^
+
+  The mitigation for MDS clears the affected CPU buffers on return to user
+  space and when entering a guest.
+
+  If SMT is enabled it also clears the buffers on idle entry when the CPU
+  is only affected by MSBDS and not any other MDS variant, because the
+  other variants cannot be protected against cross Hyper-Thread attacks.
+
+  For CPUs which are only affected by MSBDS the user space, guest and idle
+  transition mitigations are sufficient and SMT is not affected.
+
+.. _virt_mechanism:
+
+Virtualization mitigation
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+  The protection for host to guest transition depends on the L1TF
+  vulnerability of the CPU:
+
+  - CPU is affected by L1TF:
+
+    If the L1D flush mitigation is enabled and up to date microcode is
+    available, the L1D flush mitigation is automatically protecting the
+    guest transition.
+
+    If the L1D flush mitigation is disabled then the MDS mitigation is
+    invoked explicit when the host MDS mitigation is enabled.
+
+    For details on L1TF and virtualization see:
+    :ref:`Documentation/admin-guide/hw-vuln//l1tf.rst <mitigation_control_kvm>`.
+
+  - CPU is not affected by L1TF:
+
+    CPU buffers are flushed before entering the guest when the host MDS
+    mitigation is enabled.
+
+  The resulting MDS protection matrix for the host to guest transition:
+
+  ============ ===== ============= ============ =================
+   L1TF         MDS   VMX-L1FLUSH   Host MDS     MDS-State
+
+   Don't care   No    Don't care    N/A          Not affected
+
+   Yes          Yes   Disabled      Off          Vulnerable
+
+   Yes          Yes   Disabled      Full         Mitigated
+
+   Yes          Yes   Enabled       Don't care   Mitigated
+
+   No           Yes   N/A           Off          Vulnerable
+
+   No           Yes   N/A           Full         Mitigated
+  ============ ===== ============= ============ =================
+
+  This only covers the host to guest transition, i.e. prevents leakage from
+  host to guest, but does not protect the guest internally. Guests need to
+  have their own protections.
+
+.. _xeon_phi:
+
+XEON PHI specific considerations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+  The XEON PHI processor family is affected by MSBDS which can be exploited
+  cross Hyper-Threads when entering idle states. Some XEON PHI variants allow
+  to use MWAIT in user space (Ring 3) which opens an potential attack vector
+  for malicious user space. The exposure can be disabled on the kernel
+  command line with the 'ring3mwait=disable' command line option.
+
+  XEON PHI is not affected by the other MDS variants and MSBDS is mitigated
+  before the CPU enters a idle state. As XEON PHI is not affected by L1TF
+  either disabling SMT is not required for full protection.
+
+.. _mds_smt_control:
+
+SMT control
+^^^^^^^^^^^
+
+  All MDS variants except MSBDS can be attacked cross Hyper-Threads. That
+  means on CPUs which are affected by MFBDS or MLPDS it is necessary to
+  disable SMT for full protection. These are most of the affected CPUs; the
+  exception is XEON PHI, see :ref:`xeon_phi`.
+
+  Disabling SMT can have a significant performance impact, but the impact
+  depends on the type of workloads.
+
+  See the relevant chapter in the L1TF mitigation documentation for details:
+  :ref:`Documentation/admin-guide/hw-vuln/l1tf.rst <smt_control>`.
+
+
+.. _mds_mitigation_control_command_line:
+
+Mitigation control on the kernel command line
+---------------------------------------------
+
+The kernel command line allows to control the MDS mitigations at boot
+time with the option "mds=". The valid arguments for this option are:
+
+  ============  =============================================================
+  full		If the CPU is vulnerable, enable all available mitigations
+		for the MDS vulnerability, CPU buffer clearing on exit to
+		userspace and when entering a VM. Idle transitions are
+		protected as well if SMT is enabled.
+
+		It does not automatically disable SMT.
+
+  full,nosmt	The same as mds=full, with SMT disabled on vulnerable
+		CPUs.  This is the complete mitigation.
+
+  off		Disables MDS mitigations completely.
+
+  ============  =============================================================
+
+Not specifying this option is equivalent to "mds=full". For processors
+that are affected by both TAA (TSX Asynchronous Abort) and MDS,
+specifying just "mds=off" without an accompanying "tsx_async_abort=off"
+will have no effect as the same mitigation is used for both
+vulnerabilities.
+
+Mitigation selection guide
+--------------------------
+
+1. Trusted userspace
+^^^^^^^^^^^^^^^^^^^^
+
+   If all userspace applications are from a trusted source and do not
+   execute untrusted code which is supplied externally, then the mitigation
+   can be disabled.
+
+
+2. Virtualization with trusted guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   The same considerations as above versus trusted user space apply.
+
+3. Virtualization with untrusted guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   The protection depends on the state of the L1TF mitigations.
+   See :ref:`virt_mechanism`.
+
+   If the MDS mitigation is enabled and SMT is disabled, guest to host and
+   guest to guest attacks are prevented.
+
+.. _mds_default_mitigations:
+
+Default mitigations
+-------------------
+
+  The kernel default mitigations for vulnerable processors are:
+
+  - Enable CPU buffer clearing
+
+  The kernel does not by default enforce the disabling of SMT, which leaves
+  SMT systems vulnerable when running untrusted code. The same rationale as
+  for L1TF applies.
+  See :ref:`Documentation/admin-guide/hw-vuln//l1tf.rst <default_mitigations>`.
--- linux-4.4.0.orig/Documentation/admin-guide/hw-vuln/special-register-buffer-data-sampling.rst
+++ linux-4.4.0/Documentation/admin-guide/hw-vuln/special-register-buffer-data-sampling.rst
@@ -0,0 +1,149 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+SRBDS - Special Register Buffer Data Sampling
+=============================================
+
+SRBDS is a hardware vulnerability that allows MDS :doc:`mds` techniques to
+infer values returned from special register accesses.  Special register
+accesses are accesses to off core registers.  According to Intel's evaluation,
+the special register reads that have a security expectation of privacy are
+RDRAND, RDSEED and SGX EGETKEY.
+
+When RDRAND, RDSEED and EGETKEY instructions are used, the data is moved
+to the core through the special register mechanism that is susceptible
+to MDS attacks.
+
+Affected processors
+--------------------
+Core models (desktop, mobile, Xeon-E3) that implement RDRAND and/or RDSEED may
+be affected.
+
+A processor is affected by SRBDS if its Family_Model and stepping is
+in the following list, with the exception of the listed processors
+exporting MDS_NO while Intel TSX is available yet not enabled. The
+latter class of processors are only affected when Intel TSX is enabled
+by software using TSX_CTRL_MSR otherwise they are not affected.
+
+  =============  ============  ========
+  common name    Family_Model  Stepping
+  =============  ============  ========
+  IvyBridge      06_3AH        All
+
+  Haswell        06_3CH        All
+  Haswell_L      06_45H        All
+  Haswell_G      06_46H        All
+
+  Broadwell_G    06_47H        All
+  Broadwell      06_3DH        All
+
+  Skylake_L      06_4EH        All
+  Skylake        06_5EH        All
+
+  Kabylake_L     06_8EH        <= 0xC
+  Kabylake       06_9EH        <= 0xD
+  =============  ============  ========
+
+Related CVEs
+------------
+
+The following CVE entry is related to this SRBDS issue:
+
+    ==============  =====  =====================================
+    CVE-2020-0543   SRBDS  Special Register Buffer Data Sampling
+    ==============  =====  =====================================
+
+Attack scenarios
+----------------
+An unprivileged user can extract values returned from RDRAND and RDSEED
+executed on another core or sibling thread using MDS techniques.
+
+
+Mitigation mechanism
+-------------------
+Intel will release microcode updates that modify the RDRAND, RDSEED, and
+EGETKEY instructions to overwrite secret special register data in the shared
+staging buffer before the secret data can be accessed by another logical
+processor.
+
+During execution of the RDRAND, RDSEED, or EGETKEY instructions, off-core
+accesses from other logical processors will be delayed until the special
+register read is complete and the secret data in the shared staging buffer is
+overwritten.
+
+This has three effects on performance:
+
+#. RDRAND, RDSEED, or EGETKEY instructions have higher latency.
+
+#. Executing RDRAND at the same time on multiple logical processors will be
+   serialized, resulting in an overall reduction in the maximum RDRAND
+   bandwidth.
+
+#. Executing RDRAND, RDSEED or EGETKEY will delay memory accesses from other
+   logical processors that miss their core caches, with an impact similar to
+   legacy locked cache-line-split accesses.
+
+The microcode updates provide an opt-out mechanism (RNGDS_MITG_DIS) to disable
+the mitigation for RDRAND and RDSEED instructions executed outside of Intel
+Software Guard Extensions (Intel SGX) enclaves. On logical processors that
+disable the mitigation using this opt-out mechanism, RDRAND and RDSEED do not
+take longer to execute and do not impact performance of sibling logical
+processors memory accesses. The opt-out mechanism does not affect Intel SGX
+enclaves (including execution of RDRAND or RDSEED inside an enclave, as well
+as EGETKEY execution).
+
+IA32_MCU_OPT_CTRL MSR Definition
+--------------------------------
+Along with the mitigation for this issue, Intel added a new thread-scope
+IA32_MCU_OPT_CTRL MSR, (address 0x123). The presence of this MSR and
+RNGDS_MITG_DIS (bit 0) is enumerated by CPUID.(EAX=07H,ECX=0).EDX[SRBDS_CTRL =
+9]==1. This MSR is introduced through the microcode update.
+
+Setting IA32_MCU_OPT_CTRL[0] (RNGDS_MITG_DIS) to 1 for a logical processor
+disables the mitigation for RDRAND and RDSEED executed outside of an Intel SGX
+enclave on that logical processor. Opting out of the mitigation for a
+particular logical processor does not affect the RDRAND and RDSEED mitigations
+for other logical processors.
+
+Note that inside of an Intel SGX enclave, the mitigation is applied regardless
+of the value of RNGDS_MITG_DS.
+
+Mitigation control on the kernel command line
+---------------------------------------------
+The kernel command line allows control over the SRBDS mitigation at boot time
+with the option "srbds=".  The option for this is:
+
+  ============= =============================================================
+  off           This option disables SRBDS mitigation for RDRAND and RDSEED on
+                affected platforms.
+  ============= =============================================================
+
+SRBDS System Information
+-----------------------
+The Linux kernel provides vulnerability status information through sysfs.  For
+SRBDS this can be accessed by the following sysfs file:
+/sys/devices/system/cpu/vulnerabilities/srbds
+
+The possible values contained in this file are:
+
+ ============================== =============================================
+ Not affected                   Processor not vulnerable
+ Vulnerable                     Processor vulnerable and mitigation disabled
+ Vulnerable: No microcode       Processor vulnerable and microcode is missing
+                                mitigation
+ Mitigation: Microcode          Processor is vulnerable and mitigation is in
+                                effect.
+ Mitigation: TSX disabled       Processor is only vulnerable when TSX is
+                                enabled while this system was booted with TSX
+                                disabled.
+ Unknown: Dependent on
+ hypervisor status              Running on virtual guest processor that is
+                                affected but with no way to know if host
+                                processor is mitigated or vulnerable.
+ ============================== =============================================
+
+SRBDS Default mitigation
+------------------------
+This new microcode serializes processor access during execution of RDRAND,
+RDSEED ensures that the shared buffer is overwritten before it is released for
+reuse.  Use the "srbds=off" kernel command line to disable the mitigation for
+RDRAND and RDSEED.
--- linux-4.4.0.orig/Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
+++ linux-4.4.0/Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
@@ -0,0 +1,279 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+TAA - TSX Asynchronous Abort
+======================================
+
+TAA is a hardware vulnerability that allows unprivileged speculative access to
+data which is available in various CPU internal buffers by using asynchronous
+aborts within an Intel TSX transactional region.
+
+Affected processors
+-------------------
+
+This vulnerability only affects Intel processors that support Intel
+Transactional Synchronization Extensions (TSX) when the TAA_NO bit (bit 8)
+is 0 in the IA32_ARCH_CAPABILITIES MSR.  On processors where the MDS_NO bit
+(bit 5) is 0 in the IA32_ARCH_CAPABILITIES MSR, the existing MDS mitigations
+also mitigate against TAA.
+
+Whether a processor is affected or not can be read out from the TAA
+vulnerability file in sysfs. See :ref:`tsx_async_abort_sys_info`.
+
+Related CVEs
+------------
+
+The following CVE entry is related to this TAA issue:
+
+   ==============  =====  ===================================================
+   CVE-2019-11135  TAA    TSX Asynchronous Abort (TAA) condition on some
+                          microprocessors utilizing speculative execution may
+                          allow an authenticated user to potentially enable
+                          information disclosure via a side channel with
+                          local access.
+   ==============  =====  ===================================================
+
+Problem
+-------
+
+When performing store, load or L1 refill operations, processors write
+data into temporary microarchitectural structures (buffers). The data in
+those buffers can be forwarded to load operations as an optimization.
+
+Intel TSX is an extension to the x86 instruction set architecture that adds
+hardware transactional memory support to improve performance of multi-threaded
+software. TSX lets the processor expose and exploit concurrency hidden in an
+application due to dynamically avoiding unnecessary synchronization.
+
+TSX supports atomic memory transactions that are either committed (success) or
+aborted. During an abort, operations that happened within the transactional region
+are rolled back. An asynchronous abort takes place, among other options, when a
+different thread accesses a cache line that is also used within the transactional
+region when that access might lead to a data race.
+
+Immediately after an uncompleted asynchronous abort, certain speculatively
+executed loads may read data from those internal buffers and pass it to dependent
+operations. This can be then used to infer the value via a cache side channel
+attack.
+
+Because the buffers are potentially shared between Hyper-Threads cross
+Hyper-Thread attacks are possible.
+
+The victim of a malicious actor does not need to make use of TSX. Only the
+attacker needs to begin a TSX transaction and raise an asynchronous abort
+which in turn potenitally leaks data stored in the buffers.
+
+More detailed technical information is available in the TAA specific x86
+architecture section: :ref:`Documentation/x86/tsx_async_abort.rst <tsx_async_abort>`.
+
+
+Attack scenarios
+----------------
+
+Attacks against the TAA vulnerability can be implemented from unprivileged
+applications running on hosts or guests.
+
+As for MDS, the attacker has no control over the memory addresses that can
+be leaked. Only the victim is responsible for bringing data to the CPU. As
+a result, the malicious actor has to sample as much data as possible and
+then postprocess it to try to infer any useful information from it.
+
+A potential attacker only has read access to the data. Also, there is no direct
+privilege escalation by using this technique.
+
+
+.. _tsx_async_abort_sys_info:
+
+TAA system information
+-----------------------
+
+The Linux kernel provides a sysfs interface to enumerate the current TAA status
+of mitigated systems. The relevant sysfs file is:
+
+/sys/devices/system/cpu/vulnerabilities/tsx_async_abort
+
+The possible values in this file are:
+
+.. list-table::
+
+   * - 'Vulnerable'
+     - The CPU is affected by this vulnerability and the microcode and kernel mitigation are not applied.
+   * - 'Vulnerable: Clear CPU buffers attempted, no microcode'
+     - The system tries to clear the buffers but the microcode might not support the operation.
+   * - 'Mitigation: Clear CPU buffers'
+     - The microcode has been updated to clear the buffers. TSX is still enabled.
+   * - 'Mitigation: TSX disabled'
+     - TSX is disabled.
+   * - 'Not affected'
+     - The CPU is not affected by this issue.
+
+.. _ucode_needed:
+
+Best effort mitigation mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the processor is vulnerable, but the availability of the microcode-based
+mitigation mechanism is not advertised via CPUID the kernel selects a best
+effort mitigation mode.  This mode invokes the mitigation instructions
+without a guarantee that they clear the CPU buffers.
+
+This is done to address virtualization scenarios where the host has the
+microcode update applied, but the hypervisor is not yet updated to expose the
+CPUID to the guest. If the host has updated microcode the protection takes
+effect; otherwise a few CPU cycles are wasted pointlessly.
+
+The state in the tsx_async_abort sysfs file reflects this situation
+accordingly.
+
+
+Mitigation mechanism
+--------------------
+
+The kernel detects the affected CPUs and the presence of the microcode which is
+required. If a CPU is affected and the microcode is available, then the kernel
+enables the mitigation by default.
+
+
+The mitigation can be controlled at boot time via a kernel command line option.
+See :ref:`taa_mitigation_control_command_line`.
+
+.. _virt_mechanism:
+
+Virtualization mitigation
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Affected systems where the host has TAA microcode and TAA is mitigated by
+having disabled TSX previously, are not vulnerable regardless of the status
+of the VMs.
+
+In all other cases, if the host either does not have the TAA microcode or
+the kernel is not mitigated, the system might be vulnerable.
+
+
+.. _taa_mitigation_control_command_line:
+
+Mitigation control on the kernel command line
+---------------------------------------------
+
+The kernel command line allows to control the TAA mitigations at boot time with
+the option "tsx_async_abort=". The valid arguments for this option are:
+
+  ============  =============================================================
+  off		This option disables the TAA mitigation on affected platforms.
+                If the system has TSX enabled (see next parameter) and the CPU
+                is affected, the system is vulnerable.
+
+  full	        TAA mitigation is enabled. If TSX is enabled, on an affected
+                system it will clear CPU buffers on ring transitions. On
+                systems which are MDS-affected and deploy MDS mitigation,
+                TAA is also mitigated. Specifying this option on those
+                systems will have no effect.
+
+  full,nosmt    The same as tsx_async_abort=full, with SMT disabled on
+                vulnerable CPUs that have TSX enabled. This is the complete
+                mitigation. When TSX is disabled, SMT is not disabled because
+                CPU is not vulnerable to cross-thread TAA attacks.
+  ============  =============================================================
+
+Not specifying this option is equivalent to "tsx_async_abort=full". For
+processors that are affected by both TAA and MDS, specifying just
+"tsx_async_abort=off" without an accompanying "mds=off" will have no
+effect as the same mitigation is used for both vulnerabilities.
+
+The kernel command line also allows to control the TSX feature using the
+parameter "tsx=" on CPUs which support TSX control. MSR_IA32_TSX_CTRL is used
+to control the TSX feature and the enumeration of the TSX feature bits (RTM
+and HLE) in CPUID.
+
+The valid options are:
+
+  ============  =============================================================
+  off		Disables TSX on the system.
+
+                Note that this option takes effect only on newer CPUs which are
+                not vulnerable to MDS, i.e., have MSR_IA32_ARCH_CAPABILITIES.MDS_NO=1
+                and which get the new IA32_TSX_CTRL MSR through a microcode
+                update. This new MSR allows for the reliable deactivation of
+                the TSX functionality.
+
+  on		Enables TSX.
+
+                Although there are mitigations for all known security
+                vulnerabilities, TSX has been known to be an accelerator for
+                several previous speculation-related CVEs, and so there may be
+                unknown security risks associated with leaving it enabled.
+
+  auto		Disables TSX if X86_BUG_TAA is present, otherwise enables TSX
+                on the system.
+  ============  =============================================================
+
+Not specifying this option is equivalent to "tsx=off".
+
+The following combinations of the "tsx_async_abort" and "tsx" are possible. For
+affected platforms tsx=auto is equivalent to tsx=off and the result will be:
+
+  =========  ==========================   =========================================
+  tsx=on     tsx_async_abort=full         The system will use VERW to clear CPU
+                                          buffers. Cross-thread attacks are still
+					  possible on SMT machines.
+  tsx=on     tsx_async_abort=full,nosmt   As above, cross-thread attacks on SMT
+                                          mitigated.
+  tsx=on     tsx_async_abort=off          The system is vulnerable.
+  tsx=off    tsx_async_abort=full         TSX might be disabled if microcode
+                                          provides a TSX control MSR. If so,
+					  system is not vulnerable.
+  tsx=off    tsx_async_abort=full,nosmt   Ditto
+  tsx=off    tsx_async_abort=off          ditto
+  =========  ==========================   =========================================
+
+
+For unaffected platforms "tsx=on" and "tsx_async_abort=full" does not clear CPU
+buffers.  For platforms without TSX control (MSR_IA32_ARCH_CAPABILITIES.MDS_NO=0)
+"tsx" command line argument has no effect.
+
+For the affected platforms below table indicates the mitigation status for the
+combinations of CPUID bit MD_CLEAR and IA32_ARCH_CAPABILITIES MSR bits MDS_NO
+and TSX_CTRL_MSR.
+
+  =======  =========  =============  ========================================
+  MDS_NO   MD_CLEAR   TSX_CTRL_MSR   Status
+  =======  =========  =============  ========================================
+    0          0            0        Vulnerable (needs microcode)
+    0          1            0        MDS and TAA mitigated via VERW
+    1          1            0        MDS fixed, TAA vulnerable if TSX enabled
+                                     because MD_CLEAR has no meaning and
+                                     VERW is not guaranteed to clear buffers
+    1          X            1        MDS fixed, TAA can be mitigated by
+                                     VERW or TSX_CTRL_MSR
+  =======  =========  =============  ========================================
+
+Mitigation selection guide
+--------------------------
+
+1. Trusted userspace and guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If all user space applications are from a trusted source and do not execute
+untrusted code which is supplied externally, then the mitigation can be
+disabled. The same applies to virtualized environments with trusted guests.
+
+
+2. Untrusted userspace and guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If there are untrusted applications or guests on the system, enabling TSX
+might allow a malicious actor to leak data from the host or from other
+processes running on the same physical core.
+
+If the microcode is available and the TSX is disabled on the host, attacks
+are prevented in a virtualized environment as well, even if the VMs do not
+explicitly enable the mitigation.
+
+
+.. _taa_default_mitigations:
+
+Default mitigations
+-------------------
+
+The kernel's default action for vulnerable processors is:
+
+  - Deploy TSX disable mitigation (tsx_async_abort=full tsx=off).
--- linux-4.4.0.orig/Documentation/admin-guide/hw-vuln/vmscape.rst
+++ linux-4.4.0/Documentation/admin-guide/hw-vuln/vmscape.rst
@@ -0,0 +1,105 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+VMSCAPE
+=======
+
+VMSCAPE is a vulnerability that may allow a guest to influence the branch
+prediction in host userspace. It particularly affects hypervisors like QEMU.
+
+Even if a hypervisor may not have any sensitive data like disk encryption keys,
+guest-userspace may be able to attack the guest-kernel using the hypervisor as
+a confused deputy.
+
+Affected processors
+-------------------
+
+The following CPU families are affected by VMSCAPE:
+
+**Intel processors:**
+  - Skylake generation (Parts without Enhanced-IBRS)
+  - Cascade Lake generation - (Parts affected by ITS guest/host separation)
+  - Alder Lake and newer (Parts affected by BHI)
+
+Note that, BHI affected parts that use BHB clearing software mitigation e.g.
+Icelake are not vulnerable to VMSCAPE.
+
+**AMD processors:**
+  - Zen series (families 0x17, 0x19)
+
+**Hygon processors:**
+  - Family 0x18
+
+Mitigation
+----------
+
+Conditional IBPB
+----------------
+
+Kernel tracks when a CPU has run a potentially malicious guest and issues an
+IBPB before the first exit to userspace after VM-exit. If userspace did not run
+between VM-exit and the next VM-entry, no IBPB is issued.
+
+Note that the existing userspace mitigation against Spectre-v2 is effective in
+protecting the userspace. They are insufficient to protect the userspace VMMs
+from a malicious guest. This is because Spectre-v2 mitigations are applied at
+context switch time, while the userspace VMM can run after a VM-exit without a
+context switch.
+
+Vulnerability enumeration and mitigation is not applied inside a guest. This is
+because nested hypervisors should already be deploying IBPB to isolate
+themselves from nested guests.
+
+SMT considerations
+------------------
+
+When Simultaneous Multi-Threading (SMT) is enabled, hypervisors can be
+vulnerable to cross-thread attacks. For complete protection against VMSCAPE
+attacks in SMT environments, STIBP should be enabled.
+
+The kernel will issue a warning if SMT is enabled without adequate STIBP
+protection. Warning is not issued when:
+
+- SMT is disabled
+- STIBP is enabled system-wide
+- Intel eIBRS is enabled (which implies STIBP protection)
+
+System information and options
+------------------------------
+
+The sysfs file showing VMSCAPE mitigation status is:
+
+  /sys/devices/system/cpu/vulnerabilities/vmscape
+
+The possible values in this file are:
+
+ * 'Not affected':
+
+   The processor is not vulnerable to VMSCAPE attacks.
+
+ * 'Vulnerable':
+
+   The processor is vulnerable and no mitigation has been applied.
+
+ * 'Mitigation: IBPB before exit to userspace':
+
+   Conditional IBPB mitigation is enabled. The kernel tracks when a CPU has
+   run a potentially malicious guest and issues an IBPB before the first
+   exit to userspace after VM-exit.
+
+Mitigation control on the kernel command line
+----------------------------------------------
+
+The mitigation can be controlled via the ``vmscape=`` command line parameter:
+
+ * ``vmscape=off``:
+
+   Disable the VMSCAPE mitigation.
+
+ * ``vmscape=ibpb``:
+
+   Enable conditional IBPB mitigation (default when CONFIG_MITIGATION_VMSCAPE=y).
+
+ * ``vmscape=force``:
+
+   Force vulnerability detection and mitigation even on processors that are
+   not known to be affected.
--- linux-4.4.0.orig/Documentation/admin-guide/index.rst
+++ linux-4.4.0/Documentation/admin-guide/index.rst
@@ -0,0 +1,14 @@
+The Linux kernel user's and administrator's guide
+=================================================
+
+The following is a collection of user-oriented documents that have been
+added to the kernel over time.  There is, as yet, little overall order or
+organization here — this material was not written to be a single, coherent
+document!  With luck things will improve quickly over time.
+
+This section describes CPU vulnerabilities and their mitigations.
+
+.. toctree::
+   :maxdepth: 1
+
+   hw-vuln/index
--- linux-4.4.0.orig/Documentation/arm/kernel_mode_neon.txt
+++ linux-4.4.0/Documentation/arm/kernel_mode_neon.txt
@@ -6,7 +6,7 @@
 * Use only NEON instructions, or VFP instructions that don't rely on support
   code
 * Isolate your NEON code in a separate compilation unit, and compile it with
-  '-mfpu=neon -mfloat-abi=softfp'
+  '-march=armv7-a -mfpu=neon -mfloat-abi=softfp'
 * Put kernel_neon_begin() and kernel_neon_end() calls around the calls into your
   NEON code
 * Don't sleep in your NEON code, and be aware that it will be executed with
@@ -87,7 +87,7 @@
 Therefore, the recommended and only supported way of using NEON/VFP in the
 kernel is by adhering to the following rules:
 * isolate the NEON code in a separate compilation unit and compile it with
-  '-mfpu=neon -mfloat-abi=softfp';
+  '-march=armv7-a -mfpu=neon -mfloat-abi=softfp';
 * issue the calls to kernel_neon_begin(), kernel_neon_end() as well as the calls
   into the unit containing the NEON code from a compilation unit which is *not*
   built with the GCC flag '-mfpu=neon' set.
--- linux-4.4.0.orig/Documentation/arm64/tagged-pointers.txt
+++ linux-4.4.0/Documentation/arm64/tagged-pointers.txt
@@ -11,24 +11,56 @@
 The kernel configures the translation tables so that translations made
 via TTBR0 (i.e. userspace mappings) have the top byte (bits 63:56) of
 the virtual address ignored by the translation hardware. This frees up
-this byte for application use, with the following caveats:
+this byte for application use.
 
-	(1) The kernel requires that all user addresses passed to EL1
-	    are tagged with tag 0x00. This means that any syscall
-	    parameters containing user virtual addresses *must* have
-	    their top byte cleared before trapping to the kernel.
-
-	(2) Non-zero tags are not preserved when delivering signals.
-	    This means that signal handlers in applications making use
-	    of tags cannot rely on the tag information for user virtual
-	    addresses being maintained for fields inside siginfo_t.
-	    One exception to this rule is for signals raised in response
-	    to watchpoint debug exceptions, where the tag information
-	    will be preserved.
-
-	(3) Special care should be taken when using tagged pointers,
-	    since it is likely that C compilers will not hazard two
-	    virtual addresses differing only in the upper byte.
+
+Passing tagged addresses to the kernel
+--------------------------------------
+
+All interpretation of userspace memory addresses by the kernel assumes
+an address tag of 0x00.
+
+This includes, but is not limited to, addresses found in:
+
+ - pointer arguments to system calls, including pointers in structures
+   passed to system calls,
+
+ - the stack pointer (sp), e.g. when interpreting it to deliver a
+   signal,
+
+ - the frame pointer (x29) and frame records, e.g. when interpreting
+   them to generate a backtrace or call graph.
+
+Using non-zero address tags in any of these locations may result in an
+error code being returned, a (fatal) signal being raised, or other modes
+of failure.
+
+For these reasons, passing non-zero address tags to the kernel via
+system calls is forbidden, and using a non-zero address tag for sp is
+strongly discouraged.
+
+Programs maintaining a frame pointer and frame records that use non-zero
+address tags may suffer impaired or inaccurate debug and profiling
+visibility.
+
+
+Preserving tags
+---------------
+
+Non-zero tags are not preserved when delivering signals. This means that
+signal handlers in applications making use of tags cannot rely on the
+tag information for user virtual addresses being maintained for fields
+inside siginfo_t. One exception to this rule is for signals raised in
+response to watchpoint debug exceptions, where the tag information will
+be preserved.
 
 The architecture prevents the use of a tagged PC, so the upper byte will
 be set to a sign-extension of bit 55 on exception return.
+
+
+Other considerations
+--------------------
+
+Special care should be taken when using tagged pointers, since it is
+likely that C compilers will not hazard two virtual addresses differing
+only in the upper byte.
--- linux-4.4.0.orig/Documentation/cgroups/namespace.txt
+++ linux-4.4.0/Documentation/cgroups/namespace.txt
@@ -0,0 +1,142 @@
+			CGroup Namespaces
+
+CGroup Namespace provides a mechanism to virtualize the view of the
+/proc/<pid>/cgroup file. The CLONE_NEWCGROUP clone-flag can be used with
+clone() and unshare() syscalls to create a new cgroup namespace.
+The process running inside the cgroup namespace will have its /proc/<pid>/cgroup
+output restricted to cgroupns-root. cgroupns-root is the cgroup of the process
+at the time of creation of the cgroup namespace.
+
+Prior to CGroup Namespace, the /proc/<pid>/cgroup file used to show complete
+path of the cgroup of a process. In a container setup (where a set of cgroups
+and namespaces are intended to isolate processes), the /proc/<pid>/cgroup file
+may leak potential system level information to the isolated processes.
+
+For Example:
+  $ cat /proc/self/cgroup
+  0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/batchjobs/container_id1
+
+The path '/batchjobs/container_id1' can generally be considered as system-data
+and its desirable to not expose it to the isolated process.
+
+CGroup Namespaces can be used to restrict visibility of this path.
+For Example:
+  # Before creating cgroup namespace
+  $ ls -l /proc/self/ns/cgroup
+  lrwxrwxrwx 1 root root 0 2014-07-15 10:37 /proc/self/ns/cgroup -> cgroup:[4026531835]
+  $ cat /proc/self/cgroup
+  0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/batchjobs/container_id1
+
+  # unshare(CLONE_NEWCGROUP) and exec /bin/bash
+  $ ~/unshare -c
+  [ns]$ ls -l /proc/self/ns/cgroup
+  lrwxrwxrwx 1 root root 0 2014-07-15 10:35 /proc/self/ns/cgroup -> cgroup:[4026532183]
+  # From within new cgroupns, process sees that its in the root cgroup
+  [ns]$ cat /proc/self/cgroup
+  0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/
+
+  # From global cgroupns:
+  $ cat /proc/<pid>/cgroup
+  0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/batchjobs/container_id1
+
+  # Unshare cgroupns along with userns and mountns
+  # Following calls unshare(CLONE_NEWCGROUP|CLONE_NEWUSER|CLONE_NEWNS), then
+  # sets up uid/gid map and execs /bin/bash
+  $ ~/unshare -c -u -m
+  # Originally, we were in /batchjobs/container_id1 cgroup. Mount our own cgroup
+  # hierarchy.
+  [ns]$ mount -t cgroup cgroup /tmp/cgroup
+  [ns]$ ls -l /tmp/cgroup
+  total 0
+  -r--r--r-- 1 root root 0 2014-10-13 09:32 cgroup.controllers
+  -r--r--r-- 1 root root 0 2014-10-13 09:32 cgroup.populated
+  -rw-r--r-- 1 root root 0 2014-10-13 09:25 cgroup.procs
+  -rw-r--r-- 1 root root 0 2014-10-13 09:32 cgroup.subtree_control
+
+The cgroupns-root (/batchjobs/container_id1 in above example) becomes the
+filesystem root for the namespace specific cgroupfs mount.
+
+The virtualization of /proc/self/cgroup file combined with restricting
+the view of cgroup hierarchy by namespace-private cgroupfs mount
+should provide a completely isolated cgroup view inside the container.
+
+In its current form, the cgroup namespaces patcheset provides following
+behavior:
+
+(1) The 'cgroupns-root' for a cgroup namespace is the cgroup in which
+    the process calling unshare is running.
+    For ex. if a process in /batchjobs/container_id1 cgroup calls unshare,
+    cgroup /batchjobs/container_id1 becomes the cgroupns-root.
+    For the init_cgroup_ns, this is the real root ('/') cgroup
+    (identified in code as cgrp_dfl_root.cgrp).
+
+(2) The cgroupns-root cgroup does not change even if the namespace
+    creator process later moves to a different cgroup.
+    $ ~/unshare -c # unshare cgroupns in some cgroup
+    [ns]$ cat /proc/self/cgroup
+    0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/
+    [ns]$ mkdir sub_cgrp_1
+    [ns]$ echo 0 > sub_cgrp_1/cgroup.procs
+    [ns]$ cat /proc/self/cgroup
+    0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/sub_cgrp_1
+
+(3) Each process gets its CGROUPNS specific view of /proc/<pid>/cgroup
+(a) Processes running inside the cgroup namespace will be able to see
+    cgroup paths (in /proc/self/cgroup) only inside their root cgroup
+    [ns]$ sleep 100000 &  # From within unshared cgroupns
+    [1] 7353
+    [ns]$ echo 7353 > sub_cgrp_1/cgroup.procs
+    [ns]$ cat /proc/7353/cgroup
+    0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/sub_cgrp_1
+
+(b) From global cgroupns, the real cgroup path will be visible:
+    $ cat /proc/7353/cgroup
+    0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/batchjobs/container_id1/sub_cgrp_1
+
+(c) From a sibling cgroupns (cgroupns root-ed at a different cgroup), cgroup
+    path relative to its own cgroupns-root will be shown:
+    # ns2's cgroupns-root is at '/batchjobs/container_id2'
+    [ns2]$ cat /proc/7353/cgroup
+    0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/../container_id2/sub_cgrp_1
+
+    Note that the relative path always starts with '/' to indicate that its
+    relative to the cgroupns-root of the caller.
+
+(4) Processes inside a cgroupns can move in-and-out of the cgroupns-root
+    (if they have proper access to external cgroups).
+    # From inside cgroupns (with cgroupns-root at /batchjobs/container_id1), and
+    # assuming that the global hierarchy is still accessible inside cgroupns:
+    $ cat /proc/7353/cgroup
+    0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/sub_cgrp_1
+    $ echo 7353 > batchjobs/container_id2/cgroup.procs
+    $ cat /proc/7353/cgroup
+    0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/../container_id2
+
+    Note that this kind of setup is not encouraged. A task inside cgroupns
+    should only be exposed to its own cgroupns hierarchy. Otherwise it makes
+    the virtualization of /proc/<pid>/cgroup less useful.
+
+(5) Setns to another cgroup namespace is allowed when:
+    (a) the process has CAP_SYS_ADMIN in its current userns
+    (b) the process has CAP_SYS_ADMIN in the target cgroupns' userns
+    No implicit cgroup changes happen with attaching to another cgroupns. It
+    is expected that the somone moves the attaching process under the target
+    cgroupns-root.
+
+(6) When some thread from a multi-threaded process unshares its
+    cgroup-namespace, the new cgroupns gets applied to the entire process (all
+    the threads). For the unified-hierarchy this is expected as it only allows
+    process-level containerization.  For the legacy hierarchies this may be
+    unexpected.  So all the threads in the process will have the same cgroup.
+
+(7) The cgroup namespace is alive as long as there is atleast 1
+    process inside it. When the last process exits, the cgroup
+    namespace is destroyed. The cgroupns-root and the actual cgroups
+    remain though.
+
+(8) Namespace specific cgroup hierarchy can be mounted by a process running
+    inside cgroupns:
+    $ mount -t cgroup -o __DEVEL__sane_behavior cgroup $MOUNT_POINT
+
+    This will mount the unified cgroup hierarchy with cgroupns-root as the
+    filesystem root. The process needs CAP_SYS_ADMIN in its userns and mntns.
--- linux-4.4.0.orig/Documentation/crypto/api-kpp.rst
+++ linux-4.4.0/Documentation/crypto/api-kpp.rst
@@ -0,0 +1,92 @@
+Key-agreement Protocol Primitives (KPP) Cipher Algorithm Definitions
+--------------------------------------------------------------------
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_request
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: crypto_kpp
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_alg
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_secret
+
+Key-agreement Protocol Primitives (KPP) Cipher API
+--------------------------------------------------
+
+.. kernel-doc:: include/crypto/kpp.h
+   :doc: Generic Key-agreement Protocol Primitives API
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: crypto_alloc_kpp
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: crypto_free_kpp
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: crypto_kpp_set_secret
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: crypto_kpp_generate_public_key
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: crypto_kpp_compute_shared_secret
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: crypto_kpp_maxsize
+
+Key-agreement Protocol Primitives (KPP) Cipher Request Handle
+-------------------------------------------------------------
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_request_alloc
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_request_free
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_request_set_callback
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_request_set_input
+
+.. kernel-doc:: include/crypto/kpp.h
+   :functions: kpp_request_set_output
+
+ECDH Helper Functions
+---------------------
+
+.. kernel-doc:: include/crypto/ecdh.h
+   :doc: ECDH Helper Functions
+
+.. kernel-doc:: include/crypto/ecdh.h
+   :functions: ecdh
+
+.. kernel-doc:: include/crypto/ecdh.h
+   :functions: crypto_ecdh_key_len
+
+.. kernel-doc:: include/crypto/ecdh.h
+   :functions: crypto_ecdh_encode_key
+
+.. kernel-doc:: include/crypto/ecdh.h
+   :functions: crypto_ecdh_decode_key
+
+DH Helper Functions
+-------------------
+
+.. kernel-doc:: include/crypto/dh.h
+   :doc: DH Helper Functions
+
+.. kernel-doc:: include/crypto/dh.h
+   :functions: dh
+
+.. kernel-doc:: include/crypto/dh.h
+   :functions: crypto_dh_key_len
+
+.. kernel-doc:: include/crypto/dh.h
+   :functions: crypto_dh_encode_key
+
+.. kernel-doc:: include/crypto/dh.h
+   :functions: crypto_dh_decode_key
--- linux-4.4.0.orig/Documentation/device-mapper/thin-provisioning.txt
+++ linux-4.4.0/Documentation/device-mapper/thin-provisioning.txt
@@ -112,9 +112,11 @@
 free space on the data device drops below this level then a dm event
 will be triggered which a userspace daemon should catch allowing it to
 extend the pool device.  Only one such event will be sent.
-Resuming a device with a new table itself triggers an event so the
-userspace daemon can use this to detect a situation where a new table
-already exceeds the threshold.
+
+No special event is triggered if a just resumed device's free space is below
+the low water mark. However, resuming a device always triggers an
+event; a userspace daemon should verify that free space exceeds the low
+water mark when handling this event.
 
 A low water mark for the metadata device is maintained in the kernel and
 will trigger a dm event if free space on the metadata device drops below
--- linux-4.4.0.orig/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -23,6 +23,7 @@
   during suspend.
 - ti,no-reset-on-init: When present, the module should not be reset at init
 - ti,no-idle-on-init: When present, the module should not be idled at init
+- ti,no-idle: When present, the module is never allowed to idle.
 
 Example:
 
--- linux-4.4.0.orig/Documentation/devicetree/bindings/arm/pmu.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/arm/pmu.txt
@@ -24,6 +24,7 @@
 	"qcom,scorpion-pmu"
 	"qcom,scorpion-mp-pmu"
 	"qcom,krait-pmu"
+	"cavium,thunder-pmu"
 - interrupts : 1 combined interrupt or 1 per core. If the interrupt is a per-cpu
                interrupt (PPI) then 1 interrupt should be specified.
 
--- linux-4.4.0.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -30,6 +30,10 @@
 - target-supply     : regulator for SATA target power
 - phys              : reference to the SATA PHY node
 - phy-names         : must be "sata-phy"
+- ports-implemented : Mask that indicates which ports that the HBA supports
+		      are available for software to use. Useful if PORTS_IMPL
+		      is not programmed by the BIOS, which is true with
+		      some embedded SOC's.
 
 Required properties when using sub-nodes:
 - #address-cells    : number of cells to encode an address
--- linux-4.4.0.orig/Documentation/devicetree/bindings/clock/imx31-clock.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/clock/imx31-clock.txt
@@ -77,7 +77,7 @@
 clks: ccm@53f80000{
 	compatible = "fsl,imx31-ccm";
 	reg = <0x53f80000 0x4000>;
-	interrupts = <0 31 0x04 0 53 0x04>;
+	interrupts = <31>, <53>;
 	#clock-cells = <1>;
 };
 
--- linux-4.4.0.orig/Documentation/devicetree/bindings/clock/imx35-clock.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/clock/imx35-clock.txt
@@ -94,6 +94,7 @@
 	csi_sel			79
 	iim_gate		80
 	gpu2d_gate		81
+	ckli_gate		82
 
 Examples:
 
--- linux-4.4.0.orig/Documentation/devicetree/bindings/clock/sunxi.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -18,6 +18,7 @@
 	"allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
 	"allwinner,sun4i-a10-axi-clk" - for the AXI clock
 	"allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23
+	"allwinner,sun4i-a10-gates-clk" - for generic gates on all compatible SoCs
 	"allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
 	"allwinner,sun4i-a10-ahb-clk" - for the AHB clock
 	"allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13
@@ -43,6 +44,7 @@
 	"allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31
 	"allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
 	"allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23
+	"allwinner,sun8i-h3-apb0-gates-clk" - for the APB0 gates on H3
 	"allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80
 	"allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
 	"allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80
--- linux-4.4.0.orig/Documentation/devicetree/bindings/dma/snps-dma.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/dma/snps-dma.txt
@@ -58,6 +58,6 @@
 		interrupts = <0 35 0x4>;
 		status = "disabled";
 		dmas = <&dmahost 12 0 1>,
-			<&dmahost 13 0 1 0>;
+			<&dmahost 13 1 0>;
 		dma-names = "rx", "rx";
 	};
--- linux-4.4.0.orig/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
@@ -4,6 +4,12 @@
 
   Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
 
+  or
+
+  compatible: "cavium,octeon-7890-twsi"
+
+  Compatibility with cn78XX SOCs.
+
 - reg: The base address of the TWSI/I2C bus controller register bank.
 
 - #address-cells: Must be <1>.
--- linux-4.4.0.orig/Documentation/devicetree/bindings/iio/adc/avia-hx711.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/iio/adc/avia-hx711.txt
@@ -0,0 +1,18 @@
+* AVIA HX711 ADC chip for weight cells
+  Bit-banging driver
+
+Required properties:
+ - compatible:	Should be "avia,hx711"
+ - sck-gpios:	Definition of the GPIO for the clock
+ - dout-gpios:	Definition of the GPIO for data-out
+		See Documentation/devicetree/bindings/gpio/gpio.txt
+ - avdd-supply:	Definition of the regulator used as analog supply
+
+Example:
+weight@0 {
+	compatible = "avia,hx711";
+	sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
+	dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
+	avdd-suppy = <&avdd>;
+};
+
--- linux-4.4.0.orig/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt
@@ -12,6 +12,11 @@
 - vref-supply: The regulator supply ADC reference voltage.
 - #io-channel-cells: Should be 1, see ../iio-bindings.txt
 
+Optional properties:
+- resets: Must contain an entry for each entry in reset-names if need support
+	  this option. See ../reset/reset.txt for details.
+- reset-names: Must include the name "saradc-apb".
+
 Example:
 	saradc: saradc@2006c000 {
 		compatible = "rockchip,saradc";
@@ -19,6 +24,8 @@
 		interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
 		clock-names = "saradc", "apb_pclk";
+		resets = <&cru SRST_SARADC>;
+		reset-names = "saradc-apb";
 		#io-channel-cells = <1>;
 		vref-supply = <&vcc18>;
 	};
--- linux-4.4.0.orig/Documentation/devicetree/bindings/iio/dac/ad5592r.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/iio/dac/ad5592r.txt
@@ -0,0 +1,155 @@
+Analog Devices AD5592R/AD5593R DAC/ADC device driver
+
+Required properties for the AD5592R:
+	- compatible: Must be "adi,ad5592r"
+	- reg: SPI chip select number for the device
+	- spi-max-frequency: Max SPI frequency to use (< 30000000)
+	- spi-cpol: The AD5592R requires inverse clock polarity (CPOL) mode
+
+Required properties for the AD5593R:
+	- compatible: Must be "adi,ad5593r"
+	- reg: I2C address of the device
+
+Required properties for all supported chips:
+	- #address-cells: Should be 1.
+	- #size-cells: Should be 0.
+	- channel nodes:
+	  Each child node represents one channel and has the following
+	  Required properties:
+		* reg: Pin on which this channel is connected to.
+		* adi,mode: Mode or function of this channel.
+			    Macros specifying the valid values
+			    can be found in <dt-bindings/iio/adi,ad5592r.h>.
+
+			    The following values are currently supported:
+				* CH_MODE_UNUSED (the pin is unused)
+				* CH_MODE_ADC (the pin is ADC input)
+				* CH_MODE_DAC (the pin is DAC output)
+				* CH_MODE_DAC_AND_ADC (the pin is DAC output
+					but can be monitored by an ADC, since
+					there is no disadvantage this
+					this should be considered as the
+					preferred DAC mode)
+				* CH_MODE_GPIO (the pin is registered
+					with GPIOLIB)
+	 Optional properties:
+		* adi,off-state: State of this channel when unused or the
+				 device gets removed. Macros specifying the
+				 valid values can be found in
+				 <dt-bindings/iio/adi,ad5592r.h>.
+
+				* CH_OFFSTATE_PULLDOWN (the pin is pulled down)
+				* CH_OFFSTATE_OUT_LOW  (the pin is output low)
+				* CH_OFFSTATE_OUT_HIGH (the pin is output high)
+				* CH_OFFSTATE_OUT_TRISTATE (the pin is
+					tristated output)
+
+
+Optional properties:
+	- vref-supply: Phandle to the external reference voltage supply. This should
+	  only be set if there is an external reference voltage connected to the VREF
+	  pin. If the property is not set the internal 2.5V reference is used.
+	- reset-gpios : GPIO spec for the RESET pin. If specified, it will be
+	  asserted during driver probe.
+	- gpio-controller: Marks the device node as a GPIO controller.
+	- #gpio-cells: Should be 2. The first cell is the GPIO number and the second
+	  cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>.
+
+AD5592R Example:
+
+	#include <dt-bindings/iio/adi,ad5592r.h>
+
+	vref: regulator-vref {
+		compatible = "regulator-fixed";
+		regulator-name = "vref-ad559x";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	ad5592r@0 {
+		#size-cells = <0>;
+		#address-cells = <1>;
+		#gpio-cells = <2>;
+		compatible = "adi,ad5592r";
+		reg = <0>;
+
+		spi-max-frequency = <1000000>;
+		spi-cpol;
+
+		vref-supply = <&vref>; /* optional */
+		reset-gpios = <&gpio0 86 0>;  /* optional */
+		gpio-controller;
+
+		channel@0 {
+			reg = <0>;
+			adi,mode = <CH_MODE_DAC>;
+		};
+		channel@1 {
+			reg = <1>;
+			adi,mode = <CH_MODE_ADC>;
+		};
+		channel@2 {
+			reg = <2>;
+			adi,mode = <CH_MODE_DAC_AND_ADC>;
+		};
+		channel@3 {
+			reg = <3>;
+			adi,mode = <CH_MODE_DAC_AND_ADC>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+		channel@4 {
+			reg = <4>;
+			adi,mode = <CH_MODE_UNUSED>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+		channel@5 {
+			reg = <5>;
+			adi,mode = <CH_MODE_GPIO>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+		channel@6 {
+			reg = <6>;
+			adi,mode = <CH_MODE_GPIO>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+		channel@7 {
+			reg = <7>;
+			adi,mode = <CH_MODE_GPIO>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+	};
+
+AD5593R Example:
+
+	#include <dt-bindings/iio/adi,ad5592r.h>
+
+	ad5593r@10 {
+		#size-cells = <0>;
+		#address-cells = <1>;
+		#gpio-cells = <2>;
+		compatible = "adi,ad5593r";
+		reg = <0x10>;
+		gpio-controller;
+
+		channel@0 {
+			reg = <0>;
+			adi,mode = <CH_MODE_DAC>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+		channel@1 {
+			reg = <1>;
+			adi,mode = <CH_MODE_ADC>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+		channel@2 {
+			reg = <2>;
+			adi,mode = <CH_MODE_DAC_AND_ADC>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+		channel@6 {
+			reg = <6>;
+			adi,mode = <CH_MODE_GPIO>;
+			adi,off-state = <CH_OFFSTATE_PULLDOWN>;
+		};
+	};
--- linux-4.4.0.orig/Documentation/devicetree/bindings/iio/humidity/hts221.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/iio/humidity/hts221.txt
@@ -0,0 +1,22 @@
+* HTS221 STM humidity + temperature sensor
+
+Required properties:
+- compatible: should be "st,hts221"
+- reg: i2c address of the sensor / spi cs line
+
+Optional properties:
+- interrupt-parent: should be the phandle for the interrupt controller
+- interrupts: interrupt mapping for IRQ. It should be configured with
+  flags IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING.
+
+  Refer to interrupt-controller/interrupts.txt for generic interrupt
+  client node bindings.
+
+Example:
+
+hts221@5f {
+	compatible = "st,hts221";
+	reg = <0x5f>;
+	interrupt-parent = <&gpio0>;
+	interrupts = <0 IRQ_TYPE_EDGE_RISING>;
+};
--- linux-4.4.0.orig/Documentation/devicetree/bindings/iio/st-sensors.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/iio/st-sensors.txt
@@ -16,6 +16,10 @@
 - st,drdy-int-pin: the pin on the package that will be used to signal
   "data ready" (valid values: 1 or 2). This property is not configurable
   on all sensors.
+- drive-open-drain: the interrupt/data ready line will be configured
+  as open drain, which is useful if several sensors share the same
+  interrupt line. (This binding is taken from pinctrl/pinctrl-bindings.txt)
+  This is a boolean property.
 
 Sensors may also have applicable pin control settings, those use the
 standard bindings from pinctrl/pinctrl-bindings.txt.
@@ -36,6 +40,9 @@
 - st,lsm303dlm-accel
 - st,lsm330-accel
 - st,lsm303agr-accel
+- st,lis2dh12-accel
+- st,h3lis331dl-accel
+- st,lng2dm-accel
 
 Gyroscopes:
 - st,l3g4200d-gyro
@@ -57,3 +64,4 @@
 - st,lps001wp-press
 - st,lps25h-press
 - st,lps331ap-press
+- st,lps22hb-press
--- linux-4.4.0.orig/Documentation/devicetree/bindings/net/can/microchip,mcp251x.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/net/can/microchip,mcp251x.txt
@@ -4,6 +4,7 @@
  - compatible: Should be one of the following:
    - "microchip,mcp2510" for MCP2510.
    - "microchip,mcp2515" for MCP2515.
+   - "microchip,mcp25625" for MCP25625.
  - reg: SPI chip select.
  - clocks: The clock feeding the CAN controller.
  - interrupt-parent: The parent interrupt controller.
--- linux-4.4.0.orig/Documentation/devicetree/bindings/net/cavium-mdio.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/net/cavium-mdio.txt
@@ -1,9 +1,12 @@
 * System Management Interface (SMI) / MDIO
 
 Properties:
-- compatible: "cavium,octeon-3860-mdio"
+- compatible: One of:
 
-  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+   "cavium,octeon-3860-mdio": Compatibility with all cn3XXX, cn5XXX
+                       and cn6XXX SOCs.
+
+   "cavium,thunder-8890-mdio": Compatibility with all cn8XXX SOCs.
 
 - reg: The base address of the MDIO bus controller register bank.
 
@@ -25,3 +28,57 @@
 			reg = <0>;
 		};
 	};
+
+
+* System Management Interface (SMI) / MDIO Nexus
+
+  Several mdio buses may be gathered as children of a single PCI
+  device, this PCI device is the nexus of the buses.
+
+Properties:
+
+- compatible: "cavium,thunder-8890-mdio-nexus";
+
+- reg: The PCI device and function numbers of the nexus device.
+
+- #address-cells: Must be <2>.
+
+- #size-cells: Must be <2>.
+
+- ranges: As needed for mapping of the MDIO bus device registers.
+
+- assigned-addresses: As needed for mapping of the MDIO bus device registers.
+
+Example:
+
+        mdio-nexus@1,3 {
+                compatible = "cavium,thunder-8890-mdio-nexus";
+                #address-cells = <2>;
+                #size-cells = <2>;
+                reg = <0x0b00 0 0 0 0>; /* DEVFN = 0x0b (1:3) */
+                assigned-addresses = <0x03000000 0x87e0 0x05000000 0x0 0x800000>;
+                ranges = <0x87e0 0x05000000 0x03000000 0x87e0 0x05000000 0x0 0x800000>;
+
+                mdio0@87e0,05003800 {
+                        compatible = "cavium,thunder-8890-mdio";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+                        reg = <0x87e0 0x05003800 0x0 0x30>;
+
+                        ethernet-phy@0 {
+                                ...
+                                reg = <0>;
+                        };
+                };
+                mdio0@87e0,05003880 {
+                        compatible = "cavium,thunder-8890-mdio";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+                        reg = <0x87e0 0x05003880 0x0 0x30>;
+
+                        ethernet-phy@0 {
+                                ...
+                                reg = <0>;
+                        };
+                };
+        };
--- linux-4.4.0.orig/Documentation/devicetree/bindings/net/macb.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/net/macb.txt
@@ -8,6 +8,7 @@
   Use "cdns,pc302-gem" for Picochip picoXcell pc302 and later devices based on
   the Cadence GEM, or the generic form: "cdns,gem".
   Use "atmel,sama5d2-gem" for the GEM IP (10/100) available on Atmel sama5d2 SoCs.
+  Use "atmel,sama5d3-macb" for the 10/100Mbit IP available on Atmel sama5d3 SoCs.
   Use "atmel,sama5d3-gem" for the Gigabit IP available on Atmel sama5d3 SoCs.
   Use "atmel,sama5d4-gem" for the GEM IP (10/100) available on Atmel sama5d4 SoCs.
   Use "cdns,zynqmp-gem" for Zynq Ultrascale+ MPSoC.
--- linux-4.4.0.orig/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
@@ -27,7 +27,7 @@
 		clock-frequency = <100000>;
 
 		interrupt-parent = <&gpio1>;
-		interrupts = <29 GPIO_ACTIVE_HIGH>;
+		interrupts = <29 IRQ_TYPE_LEVEL_HIGH>;
 
 		enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
 		firmware-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;
--- linux-4.4.0.orig/Documentation/devicetree/bindings/net/nfc/pn544.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/net/nfc/pn544.txt
@@ -27,7 +27,7 @@
 		clock-frequency = <400000>;
 
 		interrupt-parent = <&gpio1>;
-		interrupts = <17 GPIO_ACTIVE_HIGH>;
+		interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
 
 		enable-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
 		firmware-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
--- linux-4.4.0.orig/Documentation/devicetree/bindings/numa.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/numa.txt
@@ -0,0 +1,275 @@
+==============================================================================
+NUMA binding description.
+==============================================================================
+
+==============================================================================
+1 - Introduction
+==============================================================================
+
+Systems employing a Non Uniform Memory Access (NUMA) architecture contain
+collections of hardware resources including processors, memory, and I/O buses,
+that comprise what is commonly known as a NUMA node.
+Processor accesses to memory within the local NUMA node is generally faster
+than processor accesses to memory outside of the local NUMA node.
+DT defines interfaces that allow the platform to convey NUMA node
+topology information to OS.
+
+==============================================================================
+2 - numa-node-id
+==============================================================================
+
+For the purpose of identification, each NUMA node is associated with a unique
+token known as a node id. For the purpose of this binding
+a node id is a 32-bit integer.
+
+A device node is associated with a NUMA node by the presence of a
+numa-node-id property which contains the node id of the device.
+
+Example:
+	/* numa node 0 */
+	numa-node-id = <0>;
+
+	/* numa node 1 */
+	numa-node-id = <1>;
+
+==============================================================================
+3 - distance-map
+==============================================================================
+
+The optional device tree node distance-map describes the relative
+distance (memory latency) between all numa nodes.
+
+- compatible : Should at least contain "numa-distance-map-v1".
+
+- distance-matrix
+  This property defines a matrix to describe the relative distances
+  between all numa nodes.
+  It is represented as a list of node pairs and their relative distance.
+
+  Note:
+	1. Each entry represents distance from first node to second node.
+	The distances are equal in either direction.
+	2. The distance from a node to self (local distance) is represented
+	with value 10 and all internode distance should be represented with
+	a value greater than 10.
+	3. distance-matrix should have entries in lexicographical ascending
+	order of nodes.
+	4. There must be only one device node distance-map which must
+	reside in the root node.
+	5. If the distance-map node is not present, a default
+	distance-matrix is used.
+
+Example:
+	4 nodes connected in mesh/ring topology as below,
+
+		0_______20______1
+		|               |
+		|               |
+		20             20
+		|               |
+		|               |
+		|_______________|
+		3       20      2
+
+	if relative distance for each hop is 20,
+	then internode distance would be,
+	      0 -> 1 = 20
+	      1 -> 2 = 20
+	      2 -> 3 = 20
+	      3 -> 0 = 20
+	      0 -> 2 = 40
+	      1 -> 3 = 40
+
+     and dt presentation for this distance matrix is,
+
+		distance-map {
+			 compatible = "numa-distance-map-v1";
+			 distance-matrix = <0 0  10>,
+					   <0 1  20>,
+					   <0 2  40>,
+					   <0 3  20>,
+					   <1 0  20>,
+					   <1 1  10>,
+					   <1 2  20>,
+					   <1 3  40>,
+					   <2 0  40>,
+					   <2 1  20>,
+					   <2 2  10>,
+					   <2 3  20>,
+					   <3 0  20>,
+					   <3 1  40>,
+					   <3 2  20>,
+					   <3 3  10>;
+		};
+
+==============================================================================
+4 - Example dts
+==============================================================================
+
+Dual socket system consists of 2 boards connected through ccn bus and
+each board having one socket/soc of 8 cpus, memory and pci bus.
+
+	memory@c00000 {
+		device_type = "memory";
+		reg = <0x0 0xc00000 0x0 0x80000000>;
+		/* node 0 */
+		numa-node-id = <0>;
+	};
+
+	memory@10000000000 {
+		device_type = "memory";
+		reg = <0x100 0x0 0x0 0x80000000>;
+		/* node 1 */
+		numa-node-id = <1>;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x0>;
+			enable-method = "psci";
+			/* node 0 */
+			numa-node-id = <0>;
+		};
+		cpu@1 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x1>;
+			enable-method = "psci";
+			numa-node-id = <0>;
+		};
+		cpu@2 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x2>;
+			enable-method = "psci";
+			numa-node-id = <0>;
+		};
+		cpu@3 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x3>;
+			enable-method = "psci";
+			numa-node-id = <0>;
+		};
+		cpu@4 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x4>;
+			enable-method = "psci";
+			numa-node-id = <0>;
+		};
+		cpu@5 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x5>;
+			enable-method = "psci";
+			numa-node-id = <0>;
+		};
+		cpu@6 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x6>;
+			enable-method = "psci";
+			numa-node-id = <0>;
+		};
+		cpu@7 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x7>;
+			enable-method = "psci";
+			numa-node-id = <0>;
+		};
+		cpu@8 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x8>;
+			enable-method = "psci";
+			/* node 1 */
+			numa-node-id = <1>;
+		};
+		cpu@9 {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0x9>;
+			enable-method = "psci";
+			numa-node-id = <1>;
+		};
+		cpu@a {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0xa>;
+			enable-method = "psci";
+			numa-node-id = <1>;
+		};
+		cpu@b {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0xb>;
+			enable-method = "psci";
+			numa-node-id = <1>;
+		};
+		cpu@c {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0xc>;
+			enable-method = "psci";
+			numa-node-id = <1>;
+		};
+		cpu@d {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0xd>;
+			enable-method = "psci";
+			numa-node-id = <1>;
+		};
+		cpu@e {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0xe>;
+			enable-method = "psci";
+			numa-node-id = <1>;
+		};
+		cpu@f {
+			device_type = "cpu";
+			compatible =  "arm,armv8";
+			reg = <0x0 0xf>;
+			enable-method = "psci";
+			numa-node-id = <1>;
+		};
+	};
+
+	pcie0: pcie0@848000000000 {
+		compatible = "arm,armv8";
+		device_type = "pci";
+		bus-range = <0 255>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0x8480 0x00000000 0 0x10000000>;  /* Configuration space */
+		ranges = <0x03000000 0x8010 0x00000000 0x8010 0x00000000 0x70 0x00000000>;
+		/* node 0 */
+		numa-node-id = <0>;
+        };
+
+	pcie1: pcie1@948000000000 {
+		compatible = "arm,armv8";
+		device_type = "pci";
+		bus-range = <0 255>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0x9480 0x00000000 0 0x10000000>;  /* Configuration space */
+		ranges = <0x03000000 0x9010 0x00000000 0x9010 0x00000000 0x70 0x00000000>;
+		/* node 1 */
+		numa-node-id = <1>;
+        };
+
+	distance-map {
+		compatible = "numa-distance-map-v1";
+		distance-matrix = <0 0 10>,
+				  <0 1 20>,
+				  <1 1 10>;
+	};
--- linux-4.4.0.orig/Documentation/devicetree/bindings/pci/pci-thunder-ecam.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/pci/pci-thunder-ecam.txt
@@ -0,0 +1,30 @@
+* ThunderX PCI host controller for pass-1.x silicon
+
+Firmware-initialized PCI host controller to on-chip devices found on
+some Cavium ThunderX processors.  These devices have ECAM-based config
+access, but the BARs are all at fixed addresses.  We handle the fixed
+addresses by synthesizing Enhanced Allocation (EA) capabilities for
+these devices.
+
+The properties and their meanings are identical to those described in
+host-generic-pci.txt except as listed below.
+
+Properties of the host controller node that differ from
+host-generic-pci.txt:
+
+- compatible     : Must be "cavium,pci-host-thunder-ecam"
+
+Example:
+
+	pcie@84b000000000 {
+		compatible = "cavium,pci-host-thunder-ecam";
+		device_type = "pci";
+		msi-parent = <&its>;
+		msi-map = <0 &its 0x30000 0x10000>;
+		bus-range = <0 31>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		#stream-id-cells = <1>;
+		reg = <0x84b0 0x00000000 0 0x02000000>;  /* Configuration space */
+		ranges = <0x03000000 0x8180 0x00000000 0x8180 0x00000000 0x80 0x00000000>; /* mem ranges */
+	};
--- linux-4.4.0.orig/Documentation/devicetree/bindings/pci/pci-thunder-pem.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/pci/pci-thunder-pem.txt
@@ -0,0 +1,43 @@
+* ThunderX PEM PCIe host controller
+
+Firmware-initialized PCI host controller found on some Cavium
+ThunderX processors.
+
+The properties and their meanings are identical to those described in
+host-generic-pci.txt except as listed below.
+
+Properties of the host controller node that differ from
+host-generic-pci.txt:
+
+- compatible     : Must be "cavium,pci-host-thunder-pem"
+
+- reg            : Two entries: First the configuration space for down
+                   stream devices base address and size, as accessed
+                   from the parent bus. Second, the register bank of
+                   the PEM device PCIe bridge.
+
+Example:
+
+    pci@87e0,c2000000 {
+	compatible = "cavium,pci-host-thunder-pem";
+	device_type = "pci";
+	msi-parent = <&its>;
+	msi-map = <0 &its 0x10000 0x10000>;
+	bus-range = <0x8f 0xc7>;
+	#size-cells = <2>;
+	#address-cells = <3>;
+
+	reg = <0x8880 0x8f000000 0x0 0x39000000>,  /* Configuration space */
+	      <0x87e0 0xc2000000 0x0 0x00010000>; /* PEM space */
+	ranges = <0x01000000 0x00 0x00020000 0x88b0 0x00020000 0x00 0x00010000>, /* I/O */
+		 <0x03000000 0x00 0x10000000 0x8890 0x10000000 0x0f 0xf0000000>, /* mem64 */
+		 <0x43000000 0x10 0x00000000 0x88a0 0x00000000 0x10 0x00000000>, /* mem64-pref */
+		 <0x03000000 0x87e0 0xc2f00000 0x87e0 0xc2000000 0x00 0x00100000>; /* mem64 PEM BAR4 */
+
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0 0 0 7>;
+	interrupt-map = <0 0 0 1 &gic0 0 0 0 24 4>, /* INTA */
+			<0 0 0 2 &gic0 0 0 0 25 4>, /* INTB */
+			<0 0 0 3 &gic0 0 0 0 26 4>, /* INTC */
+			<0 0 0 4 &gic0 0 0 0 27 4>; /* INTD */
+    };
--- linux-4.4.0.orig/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt
@@ -134,12 +134,12 @@
 mfio81		dreq0, mips_trace_data, eth_debug
 mfio82		dreq1, mips_trace_data, eth_debug
 mfio83		mips_pll_lock, mips_trace_data, usb_debug
-mfio84		sys_pll_lock, mips_trace_data, usb_debug
-mfio85		wifi_pll_lock, mips_trace_data, sdhost_debug
-mfio86		bt_pll_lock, mips_trace_data, sdhost_debug
-mfio87		rpu_v_pll_lock, dreq2, socif_debug
-mfio88		rpu_l_pll_lock, dreq3, socif_debug
-mfio89		audio_pll_lock, dreq4, dreq5
+mfio84		audio_pll_lock, mips_trace_data, usb_debug
+mfio85		rpu_v_pll_lock, mips_trace_data, sdhost_debug
+mfio86		rpu_l_pll_lock, mips_trace_data, sdhost_debug
+mfio87		sys_pll_lock, dreq2, socif_debug
+mfio88		wifi_pll_lock, dreq3, socif_debug
+mfio89		bt_pll_lock, dreq4, dreq5
 tck
 trstn
 tdi
--- linux-4.4.0.orig/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
@@ -35,6 +35,15 @@
 - ti,palmas-enable-dvfs2: Enable DVFS2. Configure pins for DVFS2 mode.
 	Selection primary or secondary function associated to GPADC_START
 	and SYSEN2 pin/pad for DVFS2 interface
+- ti,palmas-override-powerhold: This is applicable for PMICs for which
+	GPIO7 is configured in POWERHOLD mode which has higher priority
+	over DEV_ON bit and keeps the PMIC supplies on even after the DEV_ON
+	bit is turned off. This property enables driver to over ride the
+	POWERHOLD value to GPIO7 so as to turn off the PMIC in power off
+	scenarios. So for GPIO7 if ti,palmas-override-powerhold is set
+	then the GPIO_7 field should never be muxed to anything else.
+	It should be set to POWERHOLD by default and only in case of
+	power off scenarios the driver will over ride the mux value.
 
 This binding uses the following generic properties as defined in
 pinctrl-bindings.txt:
--- linux-4.4.0.orig/Documentation/devicetree/bindings/powerpc/fsl/fman.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/powerpc/fsl/fman.txt
@@ -110,6 +110,13 @@
 		Usage: required
 		Definition: See soc/fsl/qman.txt and soc/fsl/bman.txt
 
+- fsl,erratum-a050385
+		Usage: optional
+		Value type: boolean
+		Definition: A boolean property. Indicates the presence of the
+		erratum A050385 which indicates that DMA transactions that are
+		split can result in a FMan lock.
+
 =============================================================================
 FMan MURAM Node
 
--- linux-4.4.0.orig/Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt
@@ -0,0 +1,18 @@
+* OMAP PWM for dual-mode timers
+
+Required properties:
+- compatible: Shall contain "ti,omap-dmtimer-pwm".
+- ti,timers: phandle to PWM capable OMAP timer. See arm/omap/timer.txt for info
+  about these timers.
+- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
+  the cells format.
+
+Optional properties:
+- ti,prescaler: Should be a value between 0 and 7, see the timers datasheet
+
+Example:
+	pwm9: dmtimer-pwm@9 {
+		compatible = "ti,omap-dmtimer-pwm";
+		ti,timers = <&timer9>;
+		#pwm-cells = <3>;
+	};
--- linux-4.4.0.orig/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
@@ -81,9 +81,9 @@
 	l14, l15, l16, l17, l18
 
 pm8941:
-	s1, s2, s3, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14,
-	l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3,
-	mvs1, mvs2
+	s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
+	l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3,
+	5vs1, 5vs2
 
 The content of each sub-node is defined by the standard binding for regulators -
 see regulator.txt - with additional custom properties described below:
--- linux-4.4.0.orig/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt
@@ -27,4 +27,4 @@
 
  - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V)
  - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output
-                          resistor, the other values are in ohm.
+                          resistor, the other values are in kOhm.
--- linux-4.4.0.orig/Documentation/devicetree/bindings/sound/rt5660.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/sound/rt5660.txt
@@ -0,0 +1,47 @@
+RT5660 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5660".
+
+- reg : The I2C address of the device.
+
+Optional properties:
+
+- clocks: The phandle of the master clock to the CODEC
+- clock-names: Should be "mclk"
+
+- realtek,in1-differential
+- realtek,in3-differential
+  Boolean. Indicate MIC1/3 input are differential, rather than single-ended.
+
+- realtek,poweroff-in-suspend
+  Boolean. If the codec will be powered off in suspend, the resume should be
+  added delay time for waiting codec power ready.
+
+- realtek,dmic1-data-pin
+  0: dmic1 is not used
+  1: using GPIO2 pin as dmic1 data pin
+  2: using IN1P pin as dmic1 data pin
+
+Pins on the device (for linking into audio routes) for RT5660:
+
+  * DMIC L1
+  * DMIC R1
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN3P
+  * IN3N
+  * SPO
+  * LOUTL
+  * LOUTR
+
+Example:
+
+rt5660 {
+	compatible = "realtek,rt5660";
+	reg = <0x1c>;
+};
--- linux-4.4.0.orig/Documentation/devicetree/bindings/sound/wm8994.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/sound/wm8994.txt
@@ -14,9 +14,15 @@
   - #gpio-cells : Must be 2. The first cell is the pin number and the
     second cell is used to specify optional parameters (currently unused).
 
-  - AVDD2-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply,
-    SPKVDD1-supply, SPKVDD2-supply : power supplies for the device, as covered
-    in Documentation/devicetree/bindings/regulator/regulator.txt
+  - power supplies for the device, as covered in
+    Documentation/devicetree/bindings/regulator/regulator.txt, depending
+    on compatible:
+    - for wlf,wm1811 and wlf,wm8958:
+      AVDD1-supply, AVDD2-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply,
+      DCVDD-supply, CPVDD-supply, SPKVDD1-supply, SPKVDD2-supply
+    - for wlf,wm8994:
+      AVDD1-supply, AVDD2-supply, DBVDD-supply, DCVDD-supply, CPVDD-supply,
+      SPKVDD1-supply, SPKVDD2-supply
 
 Optional properties:
 
@@ -68,11 +74,11 @@
 
 	lineout1-se;
 
+	AVDD1-supply = <&regulator>;
 	AVDD2-supply = <&regulator>;
 	CPVDD-supply = <&regulator>;
-	DBVDD1-supply = <&regulator>;
-	DBVDD2-supply = <&regulator>;
-	DBVDD3-supply = <&regulator>;
+	DBVDD-supply = <&regulator>;
+	DCVDD-supply = <&regulator>;
 	SPKVDD1-supply = <&regulator>;
 	SPKVDD2-supply = <&regulator>;
 };
--- linux-4.4.0.orig/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ linux-4.4.0/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -31,6 +31,7 @@
 atmel	Atmel Corporation
 auo	AU Optronics Corporation
 avago	Avago Technologies
+avia	avia semiconductor
 avic	Shanghai AVIC Optoelectronics Co., Ltd.
 axis	Axis Communications AB
 bosch	Bosch Sensortec GmbH
--- linux-4.4.0.orig/Documentation/filesystems/affs.txt
+++ linux-4.4.0/Documentation/filesystems/affs.txt
@@ -93,13 +93,15 @@
 
   - R maps to r for user, group and others. On directories, R implies x.
 
-  - If both W and D are allowed, w will be set.
+  - W maps to w.
 
   - E maps to x.
 
-  - H and P are always retained and ignored under Linux.
+  - D is ignored.
 
-  - A is always reset when a file is written to.
+  - H, S and P are always retained and ignored under Linux.
+
+  - A is cleared when a file is written to.
 
 User id and group id will be used unless set[gu]id are given as mount
 options. Since most of the Amiga file systems are single user systems
@@ -111,11 +113,13 @@
 
 The Linux rwxrwxrwx file mode is handled as follows:
 
-  - r permission will set R for user, group and others.
+  - r permission will allow R for user, group and others.
+
+  - w permission will allow W for user, group and others.
 
-  - w permission will set W and D for user, group and others.
+  - x permission of the user will allow E for plain files.
 
-  - x permission of the user will set E for plain files.
+  - D will be allowed for user, group and others.
 
   - All other flags (suid, sgid, ...) are ignored and will
     not be retained.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/README
+++ linux-4.4.0/Documentation/filesystems/aufs/README
@@ -0,0 +1,390 @@
+
+Aufs4 -- advanced multi layered unification filesystem version 4.x
+http://aufs.sf.net
+Junjiro R. Okajima
+
+
+0. Introduction
+----------------------------------------
+In the early days, aufs was entirely re-designed and re-implemented
+Unionfs Version 1.x series. Adding many original ideas, approaches,
+improvements and implementations, it becomes totally different from
+Unionfs while keeping the basic features.
+Recently, Unionfs Version 2.x series begin taking some of the same
+approaches to aufs1's.
+Unionfs is being developed by Professor Erez Zadok at Stony Brook
+University and his team.
+
+Aufs4 supports linux-4.0 and later, and for linux-3.x series try aufs3.
+If you want older kernel version support, try aufs2-2.6.git or
+aufs2-standalone.git repository, aufs1 from CVS on SourceForge.
+
+Note: it becomes clear that "Aufs was rejected. Let's give it up."
+      According to Christoph Hellwig, linux rejects all union-type
+      filesystems but UnionMount.
+<http://marc.info/?l=linux-kernel&m=123938533724484&w=2>
+
+PS. Al Viro seems have a plan to merge aufs as well as overlayfs and
+    UnionMount, and he pointed out an issue around a directory mutex
+    lock and aufs addressed it. But it is still unsure whether aufs will
+    be merged (or any other union solution).
+<http://marc.info/?l=linux-kernel&m=136312705029295&w=1>
+
+
+1. Features
+----------------------------------------
+- unite several directories into a single virtual filesystem. The member
+  directory is called as a branch.
+- you can specify the permission flags to the branch, which are 'readonly',
+  'readwrite' and 'whiteout-able.'
+- by upper writable branch, internal copyup and whiteout, files/dirs on
+  readonly branch are modifiable logically.
+- dynamic branch manipulation, add, del.
+- etc...
+
+Also there are many enhancements in aufs, such as:
+- test only the highest one for the directory permission (dirperm1)
+- copyup on open (coo=)
+- 'move' policy for copy-up between two writable branches, after
+  checking free space.
+- xattr, acl
+- readdir(3) in userspace.
+- keep inode number by external inode number table
+- keep the timestamps of file/dir in internal copyup operation
+- seekable directory, supporting NFS readdir.
+- whiteout is hardlinked in order to reduce the consumption of inodes
+  on branch
+- do not copyup, nor create a whiteout when it is unnecessary
+- revert a single systemcall when an error occurs in aufs
+- remount interface instead of ioctl
+- maintain /etc/mtab by an external command, /sbin/mount.aufs.
+- loopback mounted filesystem as a branch
+- kernel thread for removing the dir who has a plenty of whiteouts
+- support copyup sparse file (a file which has a 'hole' in it)
+- default permission flags for branches
+- selectable permission flags for ro branch, whether whiteout can
+  exist or not
+- export via NFS.
+- support <sysfs>/fs/aufs and <debugfs>/aufs.
+- support multiple writable branches, some policies to select one
+  among multiple writable branches.
+- a new semantics for link(2) and rename(2) to support multiple
+  writable branches.
+- no glibc changes are required.
+- pseudo hardlink (hardlink over branches)
+- allow a direct access manually to a file on branch, e.g. bypassing aufs.
+  including NFS or remote filesystem branch.
+- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX.
+- and more...
+
+Currently these features are dropped temporary from aufs4.
+See design/08plan.txt in detail.
+- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs
+  (robr)
+- statistics of aufs thread (/sys/fs/aufs/stat)
+
+Features or just an idea in the future (see also design/*.txt),
+- reorder the branch index without del/re-add.
+- permanent xino files for NFSD
+- an option for refreshing the opened files after add/del branches
+- light version, without branch manipulation. (unnecessary?)
+- copyup in userspace
+- inotify in userspace
+- readv/writev
+
+
+2. Download
+----------------------------------------
+There are three GIT trees for aufs4, aufs4-linux.git,
+aufs4-standalone.git, and aufs-util.git. Note that there is no "4" in
+"aufs-util.git."
+While the aufs-util is always necessary, you need either of aufs4-linux
+or aufs4-standalone.
+
+The aufs4-linux tree includes the whole linux mainline GIT tree,
+git://git.kernel.org/.../torvalds/linux.git.
+And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot
+build aufs4 as an external kernel module.
+Several extra patches are not included in this tree. Only
+aufs4-standalone tree contains them. They are described in the later
+section "Configuration and Compilation."
+
+On the other hand, the aufs4-standalone tree has only aufs source files
+and necessary patches, and you can select CONFIG_AUFS_FS=m.
+But you need to apply all aufs patches manually.
+
+You will find GIT branches whose name is in form of "aufs4.x" where "x"
+represents the linux kernel version, "linux-4.x". For instance,
+"aufs4.0" is for linux-4.0. For latest "linux-4.x-rcN", use
+"aufs4.x-rcN" branch.
+
+o aufs4-linux tree
+$ git clone --reference /your/linux/git/tree \
+	git://github.com/sfjro/aufs4-linux.git aufs4-linux.git
+- if you don't have linux GIT tree, then remove "--reference ..."
+$ cd aufs4-linux.git
+$ git checkout origin/aufs4.0
+
+Or You may want to directly git-pull aufs into your linux GIT tree, and
+leave the patch-work to GIT.
+$ cd /your/linux/git/tree
+$ git remote add aufs4 git://github.com/sfjro/aufs4-linux.git
+$ git fetch aufs4
+$ git checkout -b my4.0 v4.0
+$ (add your local change...)
+$ git pull aufs4 aufs4.0
+- now you have v4.0 + your_changes + aufs4.0 in you my4.0 branch.
+- you may need to solve some conflicts between your_changes and
+  aufs4.0. in this case, git-rerere is recommended so that you can
+  solve the similar conflicts automatically when you upgrade to 4.1 or
+  later in the future.
+
+o aufs4-standalone tree
+$ git clone git://github.com/sfjro/aufs4-standalone.git aufs4-standalone.git
+$ cd aufs4-standalone.git
+$ git checkout origin/aufs4.0
+
+o aufs-util tree
+$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git
+- note that the public aufs-util.git is on SourceForge instead of
+  GitHUB.
+$ cd aufs-util.git
+$ git checkout origin/aufs4.0
+
+Note: The 4.x-rcN branch is to be used with `rc' kernel versions ONLY.
+The minor version number, 'x' in '4.x', of aufs may not always
+follow the minor version number of the kernel.
+Because changes in the kernel that cause the use of a new
+minor version number do not always require changes to aufs-util.
+
+Since aufs-util has its own minor version number, you may not be
+able to find a GIT branch in aufs-util for your kernel's
+exact minor version number.
+In this case, you should git-checkout the branch for the
+nearest lower number.
+
+For (an unreleased) example:
+If you are using "linux-4.10" and the "aufs4.10" branch
+does not exist in aufs-util repository, then "aufs4.9", "aufs4.8"
+or something numerically smaller is the branch for your kernel.
+
+Also you can view all branches by
+	$ git branch -a
+
+
+3. Configuration and Compilation
+----------------------------------------
+Make sure you have git-checkout'ed the correct branch.
+
+For aufs4-linux tree,
+- enable CONFIG_AUFS_FS.
+- set other aufs configurations if necessary.
+
+For aufs4-standalone tree,
+There are several ways to build.
+
+1.
+- apply ./aufs4-kbuild.patch to your kernel source files.
+- apply ./aufs4-base.patch too.
+- apply ./aufs4-mmap.patch too.
+- apply ./aufs4-standalone.patch too, if you have a plan to set
+  CONFIG_AUFS_FS=m. otherwise you don't need ./aufs4-standalone.patch.
+- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your
+  kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild.
+- enable CONFIG_AUFS_FS, you can select either
+  =m or =y.
+- and build your kernel as usual.
+- install the built kernel.
+  Note: Since linux-3.9, every filesystem module requires an alias
+  "fs-<fsname>". You should make sure that "fs-aufs" is listed in your
+  modules.aliases file if you set CONFIG_AUFS_FS=m.
+- install the header files too by "make headers_install" to the
+  directory where you specify. By default, it is $PWD/usr.
+  "make help" shows a brief note for headers_install.
+- and reboot your system.
+
+2.
+- module only (CONFIG_AUFS_FS=m).
+- apply ./aufs4-base.patch to your kernel source files.
+- apply ./aufs4-mmap.patch too.
+- apply ./aufs4-standalone.patch too.
+- build your kernel, don't forget "make headers_install", and reboot.
+- edit ./config.mk and set other aufs configurations if necessary.
+  Note: You should read $PWD/fs/aufs/Kconfig carefully which describes
+  every aufs configurations.
+- build the module by simple "make".
+  Note: Since linux-3.9, every filesystem module requires an alias
+  "fs-<fsname>". You should make sure that "fs-aufs" is listed in your
+  modules.aliases file.
+- you can specify ${KDIR} make variable which points to your kernel
+  source tree.
+- install the files
+  + run "make install" to install the aufs module, or copy the built
+    $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply).
+  + run "make install_headers" (instead of headers_install) to install
+    the modified aufs header file (you can specify DESTDIR which is
+    available in aufs standalone version's Makefile only), or copy
+    $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever
+    you like manually. By default, the target directory is $PWD/usr.
+- no need to apply aufs4-kbuild.patch, nor copying source files to your
+  kernel source tree.
+
+Note: The header file aufs_type.h is necessary to build aufs-util
+      as well as "make headers_install" in the kernel source tree.
+      headers_install is subject to be forgotten, but it is essentially
+      necessary, not only for building aufs-util.
+      You may not meet problems without headers_install in some older
+      version though.
+
+And then,
+- read README in aufs-util, build and install it
+- note that your distribution may contain an obsoleted version of
+  aufs_type.h in /usr/include/linux or something. When you build aufs
+  utilities, make sure that your compiler refers the correct aufs header
+  file which is built by "make headers_install."
+- if you want to use readdir(3) in userspace or pathconf(3) wrapper,
+  then run "make install_ulib" too. And refer to the aufs manual in
+  detail.
+
+There several other patches in aufs4-standalone.git. They are all
+optional. When you meet some problems, they will help you.
+- aufs4-loopback.patch
+  Supports a nested loopback mount in a branch-fs. This patch is
+  unnecessary until aufs produces a message like "you may want to try
+  another patch for loopback file".
+- vfs-ino.patch
+  Modifies a system global kernel internal function get_next_ino() in
+  order to stop assigning 0 for an inode-number. Not directly related to
+  aufs, but recommended generally.
+- tmpfs-idr.patch
+  Keeps the tmpfs inode number as the lowest value. Effective to reduce
+  the size of aufs XINO files for tmpfs branch. Also it prevents the
+  duplication of inode number, which is important for backup tools and
+  other utilities. When you find aufs XINO files for tmpfs branch
+  growing too much, try this patch.
+- lockdep-debug.patch
+  Because aufs is not only an ordinary filesystem (callee of VFS), but
+  also a caller of VFS functions for branch filesystems, subclassing of
+  the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging
+  feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will
+  need to apply this debug patch to expand several constant values.
+  If don't know what LOCKDEP, then you don't have apply this patch.
+
+
+4. Usage
+----------------------------------------
+At first, make sure aufs-util are installed, and please read the aufs
+manual, aufs.5 in aufs-util.git tree.
+$ man -l aufs.5
+
+And then,
+$ mkdir /tmp/rw /tmp/aufs
+# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs
+
+Here is another example. The result is equivalent.
+# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs
+  Or
+# mount -t aufs -o br:/tmp/rw none /tmp/aufs
+# mount -o remount,append:${HOME} /tmp/aufs
+
+Then, you can see whole tree of your home dir through /tmp/aufs. If
+you modify a file under /tmp/aufs, the one on your home directory is
+not affected, instead the same named file will be newly created under
+/tmp/rw. And all of your modification to a file will be applied to
+the one under /tmp/rw. This is called the file based Copy on Write
+(COW) method.
+Aufs mount options are described in aufs.5.
+If you run chroot or something and make your aufs as a root directory,
+then you need to customize the shutdown script. See the aufs manual in
+detail.
+
+Additionally, there are some sample usages of aufs which are a
+diskless system with network booting, and LiveCD over NFS.
+See sample dir in CVS tree on SourceForge.
+
+
+5. Contact
+----------------------------------------
+When you have any problems or strange behaviour in aufs, please let me
+know with:
+- /proc/mounts (instead of the output of mount(8))
+- /sys/module/aufs/*
+- /sys/fs/aufs/* (if you have them)
+- /debug/aufs/* (if you have them)
+- linux kernel version
+  if your kernel is not plain, for example modified by distributor,
+  the url where i can download its source is necessary too.
+- aufs version which was printed at loading the module or booting the
+  system, instead of the date you downloaded.
+- configuration (define/undefine CONFIG_AUFS_xxx)
+- kernel configuration or /proc/config.gz (if you have it)
+- behaviour which you think to be incorrect
+- actual operation, reproducible one is better
+- mailto: aufs-users at lists.sourceforge.net
+
+Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches,
+and Feature Requests) on SourceForge. Please join and write to
+aufs-users ML.
+
+
+6. Acknowledgements
+----------------------------------------
+Thanks to everyone who have tried and are using aufs, whoever
+have reported a bug or any feedback.
+
+Especially donators:
+Tomas Matejicek(slax.org) made a donation (much more than once).
+	Since Apr 2010, Tomas M (the author of Slax and Linux Live
+	scripts) is making "doubling" donations.
+	Unfortunately I cannot list all of the donators, but I really
+	appreciate.
+	It ends Aug 2010, but the ordinary donation URL is still available.
+	<http://sourceforge.net/donate/index.php?group_id=167503>
+Dai Itasaka made a donation (2007/8).
+Chuck Smith made a donation (2008/4, 10 and 12).
+Henk Schoneveld made a donation (2008/9).
+Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10).
+Francois Dupoux made a donation (2008/11).
+Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public
+	aufs2 GIT tree (2009/2).
+William Grant made a donation (2009/3).
+Patrick Lane made a donation (2009/4).
+The Mail Archive (mail-archive.com) made donations (2009/5).
+Nippy Networks (Ed Wildgoose) made a donation (2009/7).
+New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11).
+Pavel Pronskiy made a donation (2011/2).
+Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy
+	Networks (Ed Wildgoose) made a donation for hardware (2011/3).
+Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and
+11).
+Sam Liddicott made a donation (2011/9).
+Era Scarecrow made a donation (2013/4).
+Bor Ratajc made a donation (2013/4).
+Alessandro Gorreta made a donation (2013/4).
+POIRETTE Marc made a donation (2013/4).
+Alessandro Gorreta made a donation (2013/4).
+lauri kasvandik made a donation (2013/5).
+"pemasu from Finland" made a donation (2013/7).
+The Parted Magic Project made a donation (2013/9 and 11).
+Pavel Barta made a donation (2013/10).
+Nikolay Pertsev made a donation (2014/5).
+James B made a donation (2014/7 and 2015/7).
+Stefano Di Biase made a donation (2014/8).
+Daniel Epellei made a donation (2015/1).
+
+Thank you very much.
+Donations are always, including future donations, very important and
+helpful for me to keep on developing aufs.
+
+
+7.
+----------------------------------------
+If you are an experienced user, no explanation is needed. Aufs is
+just a linux filesystem.
+
+
+Enjoy!
+
+# Local variables: ;
+# mode: text;
+# End: ;
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/01intro.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/01intro.txt
@@ -0,0 +1,170 @@
+
+# Copyright (C) 2005-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Introduction
+----------------------------------------
+
+aufs [ei ju: ef es] | [a u f s]
+1. abbrev. for "advanced multi-layered unification filesystem".
+2. abbrev. for "another unionfs".
+3. abbrev. for "auf das" in German which means "on the" in English.
+   Ex. "Butter aufs Brot"(G) means "butter onto bread"(E).
+   But "Filesystem aufs Filesystem" is hard to understand.
+
+AUFS is a filesystem with features:
+- multi layered stackable unification filesystem, the member directory
+  is called as a branch.
+- branch permission and attribute, 'readonly', 'real-readonly',
+  'readwrite', 'whiteout-able', 'link-able whiteout', etc. and their
+  combination.
+- internal "file copy-on-write".
+- logical deletion, whiteout.
+- dynamic branch manipulation, adding, deleting and changing permission.
+- allow bypassing aufs, user's direct branch access.
+- external inode number translation table and bitmap which maintains the
+  persistent aufs inode number.
+- seekable directory, including NFS readdir.
+- file mapping, mmap and sharing pages.
+- pseudo-link, hardlink over branches.
+- loopback mounted filesystem as a branch.
+- several policies to select one among multiple writable branches.
+- revert a single systemcall when an error occurs in aufs.
+- and more...
+
+
+Multi Layered Stackable Unification Filesystem
+----------------------------------------------------------------------
+Most people already knows what it is.
+It is a filesystem which unifies several directories and provides a
+merged single directory. When users access a file, the access will be
+passed/re-directed/converted (sorry, I am not sure which English word is
+correct) to the real file on the member filesystem. The member
+filesystem is called 'lower filesystem' or 'branch' and has a mode
+'readonly' and 'readwrite.' And the deletion for a file on the lower
+readonly branch is handled by creating 'whiteout' on the upper writable
+branch.
+
+On LKML, there have been discussions about UnionMount (Jan Blunck,
+Bharata B Rao and Valerie Aurora) and Unionfs (Erez Zadok). They took
+different approaches to implement the merged-view.
+The former tries putting it into VFS, and the latter implements as a
+separate filesystem.
+(If I misunderstand about these implementations, please let me know and
+I shall correct it. Because it is a long time ago when I read their
+source files last time).
+
+UnionMount's approach will be able to small, but may be hard to share
+branches between several UnionMount since the whiteout in it is
+implemented in the inode on branch filesystem and always
+shared. According to Bharata's post, readdir does not seems to be
+finished yet.
+There are several missing features known in this implementations such as
+- for users, the inode number may change silently. eg. copy-up.
+- link(2) may break by copy-up.
+- read(2) may get an obsoleted filedata (fstat(2) too).
+- fcntl(F_SETLK) may be broken by copy-up.
+- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after
+  open(O_RDWR).
+
+In linux-3.18, "overlay" filesystem (formerly known as "overlayfs") was
+merged into mainline. This is another implementation of UnionMount as a
+separated filesystem. All the limitations and known problems which
+UnionMount are equally inherited to "overlay" filesystem.
+
+Unionfs has a longer history. When I started implementing a stackable
+filesystem (Aug 2005), it already existed. It has virtual super_block,
+inode, dentry and file objects and they have an array pointing lower
+same kind objects. After contributing many patches for Unionfs, I
+re-started my project AUFS (Jun 2006).
+
+In AUFS, the structure of filesystem resembles to Unionfs, but I
+implemented my own ideas, approaches and enhancements and it became
+totally different one.
+
+Comparing DM snapshot and fs based implementation
+- the number of bytes to be copied between devices is much smaller.
+- the type of filesystem must be one and only.
+- the fs must be writable, no readonly fs, even for the lower original
+  device. so the compression fs will not be usable. but if we use
+  loopback mount, we may address this issue.
+  for instance,
+	mount /cdrom/squashfs.img /sq
+	losetup /sq/ext2.img
+	losetup /somewhere/cow
+	dmsetup "snapshot /dev/loop0 /dev/loop1 ..."
+- it will be difficult (or needs more operations) to extract the
+  difference between the original device and COW.
+- DM snapshot-merge may help a lot when users try merging. in the
+  fs-layer union, users will use rsync(1).
+
+You may want to read my old paper "Filesystems in LiveCD"
+(http://aufs.sourceforge.net/aufs2/report/sq/sq.pdf).
+
+
+Several characters/aspects/persona of aufs
+----------------------------------------------------------------------
+
+Aufs has several characters, aspects or persona.
+1. a filesystem, callee of VFS helper
+2. sub-VFS, caller of VFS helper for branches
+3. a virtual filesystem which maintains persistent inode number
+4. reader/writer of files on branches such like an application
+
+1. Callee of VFS Helper
+As an ordinary linux filesystem, aufs is a callee of VFS. For instance,
+unlink(2) from an application reaches sys_unlink() kernel function and
+then vfs_unlink() is called. vfs_unlink() is one of VFS helper and it
+calls filesystem specific unlink operation. Actually aufs implements the
+unlink operation but it behaves like a redirector.
+
+2. Caller of VFS Helper for Branches
+aufs_unlink() passes the unlink request to the branch filesystem as if
+it were called from VFS. So the called unlink operation of the branch
+filesystem acts as usual. As a caller of VFS helper, aufs should handle
+every necessary pre/post operation for the branch filesystem.
+- acquire the lock for the parent dir on a branch
+- lookup in a branch
+- revalidate dentry on a branch
+- mnt_want_write() for a branch
+- vfs_unlink() for a branch
+- mnt_drop_write() for a branch
+- release the lock on a branch
+
+3. Persistent Inode Number
+One of the most important issue for a filesystem is to maintain inode
+numbers. This is particularly important to support exporting a
+filesystem via NFS. Aufs is a virtual filesystem which doesn't have a
+backend block device for its own. But some storage is necessary to
+keep and maintain the inode numbers. It may be a large space and may not
+suit to keep in memory. Aufs rents some space from its first writable
+branch filesystem (by default) and creates file(s) on it. These files
+are created by aufs internally and removed soon (currently) keeping
+opened.
+Note: Because these files are removed, they are totally gone after
+      unmounting aufs. It means the inode numbers are not persistent
+      across unmount or reboot. I have a plan to make them really
+      persistent which will be important for aufs on NFS server.
+
+4. Read/Write Files Internally (copy-on-write)
+Because a branch can be readonly, when you write a file on it, aufs will
+"copy-up" it to the upper writable branch internally. And then write the
+originally requested thing to the file. Generally kernel doesn't
+open/read/write file actively. In aufs, even a single write may cause a
+internal "file copy". This behaviour is very similar to cp(1) command.
+
+Some people may think it is better to pass such work to user space
+helper, instead of doing in kernel space. Actually I am still thinking
+about it. But currently I have implemented it in kernel space.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/02struct.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/02struct.txt
@@ -0,0 +1,258 @@
+
+# Copyright (C) 2005-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Basic Aufs Internal Structure
+
+Superblock/Inode/Dentry/File Objects
+----------------------------------------------------------------------
+As like an ordinary filesystem, aufs has its own
+superblock/inode/dentry/file objects. All these objects have a
+dynamically allocated array and store the same kind of pointers to the
+lower filesystem, branch.
+For example, when you build a union with one readwrite branch and one
+readonly, mounted /au, /rw and /ro respectively.
+- /au = /rw + /ro
+- /ro/fileA exists but /rw/fileA
+
+Aufs lookup operation finds /ro/fileA and gets dentry for that. These
+pointers are stored in a aufs dentry. The array in aufs dentry will be,
+- [0] = NULL (because /rw/fileA doesn't exist)
+- [1] = /ro/fileA
+
+This style of an array is essentially same to the aufs
+superblock/inode/dentry/file objects.
+
+Because aufs supports manipulating branches, ie. add/delete/change
+branches dynamically, these objects has its own generation. When
+branches are changed, the generation in aufs superblock is
+incremented. And a generation in other object are compared when it is
+accessed. When a generation in other objects are obsoleted, aufs
+refreshes the internal array.
+
+
+Superblock
+----------------------------------------------------------------------
+Additionally aufs superblock has some data for policies to select one
+among multiple writable branches, XIB files, pseudo-links and kobject.
+See below in detail.
+About the policies which supports copy-down a directory, see
+wbr_policy.txt too.
+
+
+Branch and XINO(External Inode Number Translation Table)
+----------------------------------------------------------------------
+Every branch has its own xino (external inode number translation table)
+file. The xino file is created and unlinked by aufs internally. When two
+members of a union exist on the same filesystem, they share the single
+xino file.
+The struct of a xino file is simple, just a sequence of aufs inode
+numbers which is indexed by the lower inode number.
+In the above sample, assume the inode number of /ro/fileA is i111 and
+aufs assigns the inode number i999 for fileA. Then aufs writes 999 as
+4(8) bytes at 111 * 4(8) bytes offset in the xino file.
+
+When the inode numbers are not contiguous, the xino file will be sparse
+which has a hole in it and doesn't consume as much disk space as it
+might appear. If your branch filesystem consumes disk space for such
+holes, then you should specify 'xino=' option at mounting aufs.
+
+Aufs has a mount option to free the disk blocks for such holes in XINO
+files on tmpfs or ramdisk. But it is not so effective actually. If you
+meet a problem of disk shortage due to XINO files, then you should try
+"tmpfs-ino.patch" (and "vfs-ino.patch" too) in aufs4-standalone.git.
+The patch localizes the assignment inumbers per tmpfs-mount and avoid
+the holes in XINO files.
+
+Also a writable branch has three kinds of "whiteout bases". All these
+are existed when the branch is joined to aufs, and their names are
+whiteout-ed doubly, so that users will never see their names in aufs
+hierarchy.
+1. a regular file which will be hardlinked to all whiteouts.
+2. a directory to store a pseudo-link.
+3. a directory to store an "orphan"-ed file temporary.
+
+1. Whiteout Base
+   When you remove a file on a readonly branch, aufs handles it as a
+   logical deletion and creates a whiteout on the upper writable branch
+   as a hardlink of this file in order not to consume inode on the
+   writable branch.
+2. Pseudo-link Dir
+   See below, Pseudo-link.
+3. Step-Parent Dir
+   When "fileC" exists on the lower readonly branch only and it is
+   opened and removed with its parent dir, and then user writes
+   something into it, then aufs copies-up fileC to this
+   directory. Because there is no other dir to store fileC. After
+   creating a file under this dir, the file is unlinked.
+
+Because aufs supports manipulating branches, ie. add/delete/change
+dynamically, a branch has its own id. When the branch order changes,
+aufs finds the new index by searching the branch id.
+
+
+Pseudo-link
+----------------------------------------------------------------------
+Assume "fileA" exists on the lower readonly branch only and it is
+hardlinked to "fileB" on the branch. When you write something to fileA,
+aufs copies-up it to the upper writable branch. Additionally aufs
+creates a hardlink under the Pseudo-link Directory of the writable
+branch. The inode of a pseudo-link is kept in aufs super_block as a
+simple list. If fileB is read after unlinking fileA, aufs returns
+filedata from the pseudo-link instead of the lower readonly
+branch. Because the pseudo-link is based upon the inode, to keep the
+inode number by xino (see above) is essentially necessary.
+
+All the hardlinks under the Pseudo-link Directory of the writable branch
+should be restored in a proper location later. Aufs provides a utility
+to do this. The userspace helpers executed at remounting and unmounting
+aufs by default.
+During this utility is running, it puts aufs into the pseudo-link
+maintenance mode. In this mode, only the process which began the
+maintenance mode (and its child processes) is allowed to operate in
+aufs. Some other processes which are not related to the pseudo-link will
+be allowed to run too, but the rest have to return an error or wait
+until the maintenance mode ends. If a process already acquires an inode
+mutex (in VFS), it has to return an error.
+
+
+XIB(external inode number bitmap)
+----------------------------------------------------------------------
+Addition to the xino file per a branch, aufs has an external inode number
+bitmap in a superblock object. It is also an internal file such like a
+xino file.
+It is a simple bitmap to mark whether the aufs inode number is in-use or
+not.
+To reduce the file I/O, aufs prepares a single memory page to cache xib.
+
+As well as XINO files, aufs has a feature to truncate/refresh XIB to
+reduce the number of consumed disk blocks for these files.
+
+
+Virtual or Vertical Dir, and Readdir in Userspace
+----------------------------------------------------------------------
+In order to support multiple layers (branches), aufs readdir operation
+constructs a virtual dir block on memory. For readdir, aufs calls
+vfs_readdir() internally for each dir on branches, merges their entries
+with eliminating the whiteout-ed ones, and sets it to file (dir)
+object. So the file object has its entry list until it is closed. The
+entry list will be updated when the file position is zero and becomes
+obsoleted. This decision is made in aufs automatically.
+
+The dynamically allocated memory block for the name of entries has a
+unit of 512 bytes (by default) and stores the names contiguously (no
+padding). Another block for each entry is handled by kmem_cache too.
+During building dir blocks, aufs creates hash list and judging whether
+the entry is whiteouted by its upper branch or already listed.
+The merged result is cached in the corresponding inode object and
+maintained by a customizable life-time option.
+
+Some people may call it can be a security hole or invite DoS attack
+since the opened and once readdir-ed dir (file object) holds its entry
+list and becomes a pressure for system memory. But I'd say it is similar
+to files under /proc or /sys. The virtual files in them also holds a
+memory page (generally) while they are opened. When an idea to reduce
+memory for them is introduced, it will be applied to aufs too.
+For those who really hate this situation, I've developed readdir(3)
+library which operates this merging in userspace. You just need to set
+LD_PRELOAD environment variable, and aufs will not consume no memory in
+kernel space for readdir(3).
+
+
+Workqueue
+----------------------------------------------------------------------
+Aufs sometimes requires privilege access to a branch. For instance,
+in copy-up/down operation. When a user process is going to make changes
+to a file which exists in the lower readonly branch only, and the mode
+of one of ancestor directories may not be writable by a user
+process. Here aufs copy-up the file with its ancestors and they may
+require privilege to set its owner/group/mode/etc.
+This is a typical case of a application character of aufs (see
+Introduction).
+
+Aufs uses workqueue synchronously for this case. It creates its own
+workqueue. The workqueue is a kernel thread and has privilege. Aufs
+passes the request to call mkdir or write (for example), and wait for
+its completion. This approach solves a problem of a signal handler
+simply.
+If aufs didn't adopt the workqueue and changed the privilege of the
+process, then the process may receive the unexpected SIGXFSZ or other
+signals.
+
+Also aufs uses the system global workqueue ("events" kernel thread) too
+for asynchronous tasks, such like handling inotify/fsnotify, re-creating a
+whiteout base and etc. This is unrelated to a privilege.
+Most of aufs operation tries acquiring a rw_semaphore for aufs
+superblock at the beginning, at the same time waits for the completion
+of all queued asynchronous tasks.
+
+
+Whiteout
+----------------------------------------------------------------------
+The whiteout in aufs is very similar to Unionfs's. That is represented
+by its filename. UnionMount takes an approach of a file mode, but I am
+afraid several utilities (find(1) or something) will have to support it.
+
+Basically the whiteout represents "logical deletion" which stops aufs to
+lookup further, but also it represents "dir is opaque" which also stop
+further lookup.
+
+In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively.
+In order to make several functions in a single systemcall to be
+revertible, aufs adopts an approach to rename a directory to a temporary
+unique whiteouted name.
+For example, in rename(2) dir where the target dir already existed, aufs
+renames the target dir to a temporary unique whiteouted name before the
+actual rename on a branch, and then handles other actions (make it opaque,
+update the attributes, etc). If an error happens in these actions, aufs
+simply renames the whiteouted name back and returns an error. If all are
+succeeded, aufs registers a function to remove the whiteouted unique
+temporary name completely and asynchronously to the system global
+workqueue.
+
+
+Copy-up
+----------------------------------------------------------------------
+It is a well-known feature or concept.
+When user modifies a file on a readonly branch, aufs operate "copy-up"
+internally and makes change to the new file on the upper writable branch.
+When the trigger systemcall does not update the timestamps of the parent
+dir, aufs reverts it after copy-up.
+
+
+Move-down (aufs3.9 and later)
+----------------------------------------------------------------------
+"Copy-up" is one of the essential feature in aufs. It copies a file from
+the lower readonly branch to the upper writable branch when a user
+changes something about the file.
+"Move-down" is an opposite action of copy-up. Basically this action is
+ran manually instead of automatically and internally.
+For desgin and implementation, aufs has to consider these issues.
+- whiteout for the file may exist on the lower branch.
+- ancestor directories may not exist on the lower branch.
+- diropq for the ancestor directories may exist on the upper branch.
+- free space on the lower branch will reduce.
+- another access to the file may happen during moving-down, including
+  UDBA (see "Revalidate Dentry and UDBA").
+- the file should not be hard-linked nor pseudo-linked. they should be
+  handled by auplink utility later.
+
+Sometimes users want to move-down a file from the upper writable branch
+to the lower readonly or writable branch. For instance,
+- the free space of the upper writable branch is going to run out.
+- create a new intermediate branch between the upper and lower branch.
+- etc.
+
+For this purpose, use "aumvdown" command in aufs-util.git.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/03atomic_open.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/03atomic_open.txt
@@ -0,0 +1,85 @@
+
+# Copyright (C) 2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Support for a branch who has its ->atomic_open()
+----------------------------------------------------------------------
+The filesystems who implement its ->atomic_open() are not majority. For
+example NFSv4 does, and aufs should call NFSv4 ->atomic_open,
+particularly for open(O_CREAT|O_EXCL, 0400) case. Other than
+->atomic_open(), NFSv4 returns an error for this open(2). While I am not
+sure whether all filesystems who have ->atomic_open() behave like this,
+but NFSv4 surely returns the error.
+
+In order to support ->atomic_open() for aufs, there are a few
+approaches.
+
+A. Introduce aufs_atomic_open()
+   - calls one of VFS:do_last(), lookup_open() or atomic_open() for
+     branch fs.
+B. Introduce aufs_atomic_open() calling create, open and chmod. this is
+   an aufs user Pip Cet's approach
+   - calls aufs_create(), VFS finish_open() and notify_change().
+   - pass fake-mode to finish_open(), and then correct the mode by
+     notify_change().
+C. Extend aufs_open() to call branch fs's ->atomic_open()
+   - no aufs_atomic_open().
+   - aufs_lookup() registers the TID to an aufs internal object.
+   - aufs_create() does nothing when the matching TID is registered, but
+     registers the mode.
+   - aufs_open() calls branch fs's ->atomic_open() when the matching
+     TID is registered.
+D. Extend aufs_open() to re-try branch fs's ->open() with superuser's
+   credential
+   - no aufs_atomic_open().
+   - aufs_create() registers the TID to an internal object. this info
+     represents "this process created this file just now."
+   - when aufs gets EACCES from branch fs's ->open(), then confirm the
+     registered TID and re-try open() with superuser's credential.
+
+Pros and cons for each approach.
+
+A.
+   - straightforward but highly depends upon VFS internal.
+   - the atomic behavaiour is kept.
+   - some of parameters such as nameidata are hard to reproduce for
+     branch fs.
+   - large overhead.
+B.
+   - easy to implement.
+   - the atomic behavaiour is lost.
+C.
+   - the atomic behavaiour is kept.
+   - dirty and tricky.
+   - VFS checks whether the file is created correctly after calling
+     ->create(), which means this approach doesn't work.
+D.
+   - easy to implement.
+   - the atomic behavaiour is lost.
+   - to open a file with superuser's credential and give it to a user
+     process is a bad idea, since the file object keeps the credential
+     in it. It may affect LSM or something. This approach doesn't work
+     either.
+
+The approach A is ideal, but it hard to implement. So here is a
+variation of A, which is to be implemented.
+
+A-1. Introduce aufs_atomic_open()
+     - calls branch fs ->atomic_open() if exists. otherwise calls
+       vfs_create() and finish_open().
+     - the demerit is that the several checks after branch fs
+       ->atomic_open() are lost. in the ordinary case, the checks are
+       done by VFS:do_last(), lookup_open() and atomic_open(). some can
+       be implemented in aufs, but not all I am afraid.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/03lookup.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/03lookup.txt
@@ -0,0 +1,113 @@
+
+# Copyright (C) 2005-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Lookup in a Branch
+----------------------------------------------------------------------
+Since aufs has a character of sub-VFS (see Introduction), it operates
+lookup for branches as VFS does. It may be a heavy work. But almost all
+lookup operation in aufs is the simplest case, ie. lookup only an entry
+directly connected to its parent. Digging down the directory hierarchy
+is unnecessary. VFS has a function lookup_one_len() for that use, and
+aufs calls it.
+
+When a branch is a remote filesystem, aufs basically relies upon its
+->d_revalidate(), also aufs forces the hardest revalidate tests for
+them.
+For d_revalidate, aufs implements three levels of revalidate tests. See
+"Revalidate Dentry and UDBA" in detail.
+
+
+Test Only the Highest One for the Directory Permission (dirperm1 option)
+----------------------------------------------------------------------
+Let's try case study.
+- aufs has two branches, upper readwrite and lower readonly.
+  /au = /rw + /ro
+- "dirA" exists under /ro, but /rw. and its mode is 0700.
+- user invoked "chmod a+rx /au/dirA"
+- the internal copy-up is activated and "/rw/dirA" is created and its
+  permission bits are set to world readable.
+- then "/au/dirA" becomes world readable?
+
+In this case, /ro/dirA is still 0700 since it exists in readonly branch,
+or it may be a natively readonly filesystem. If aufs respects the lower
+branch, it should not respond readdir request from other users. But user
+allowed it by chmod. Should really aufs rejects showing the entries
+under /ro/dirA?
+
+To be honest, I don't have a good solution for this case. So aufs
+implements 'dirperm1' and 'nodirperm1' mount options, and leave it to
+users.
+When dirperm1 is specified, aufs checks only the highest one for the
+directory permission, and shows the entries. Otherwise, as usual, checks
+every dir existing on all branches and rejects the request.
+
+As a side effect, dirperm1 option improves the performance of aufs
+because the number of permission check is reduced when the number of
+branch is many.
+
+
+Revalidate Dentry and UDBA (User's Direct Branch Access)
+----------------------------------------------------------------------
+Generally VFS helpers re-validate a dentry as a part of lookup.
+0. digging down the directory hierarchy.
+1. lock the parent dir by its i_mutex.
+2. lookup the final (child) entry.
+3. revalidate it.
+4. call the actual operation (create, unlink, etc.)
+5. unlock the parent dir
+
+If the filesystem implements its ->d_revalidate() (step 3), then it is
+called. Actually aufs implements it and checks the dentry on a branch is
+still valid.
+But it is not enough. Because aufs has to release the lock for the
+parent dir on a branch at the end of ->lookup() (step 2) and
+->d_revalidate() (step 3) while the i_mutex of the aufs dir is still
+held by VFS.
+If the file on a branch is changed directly, eg. bypassing aufs, after
+aufs released the lock, then the subsequent operation may cause
+something unpleasant result.
+
+This situation is a result of VFS architecture, ->lookup() and
+->d_revalidate() is separated. But I never say it is wrong. It is a good
+design from VFS's point of view. It is just not suitable for sub-VFS
+character in aufs.
+
+Aufs supports such case by three level of revalidation which is
+selectable by user.
+1. Simple Revalidate
+   Addition to the native flow in VFS's, confirm the child-parent
+   relationship on the branch just after locking the parent dir on the
+   branch in the "actual operation" (step 4). When this validation
+   fails, aufs returns EBUSY. ->d_revalidate() (step 3) in aufs still
+   checks the validation of the dentry on branches.
+2. Monitor Changes Internally by Inotify/Fsnotify
+   Addition to above, in the "actual operation" (step 4) aufs re-lookup
+   the dentry on the branch, and returns EBUSY if it finds different
+   dentry.
+   Additionally, aufs sets the inotify/fsnotify watch for every dir on branches
+   during it is in cache. When the event is notified, aufs registers a
+   function to kernel 'events' thread by schedule_work(). And the
+   function sets some special status to the cached aufs dentry and inode
+   private data. If they are not cached, then aufs has nothing to
+   do. When the same file is accessed through aufs (step 0-3) later,
+   aufs will detect the status and refresh all necessary data.
+   In this mode, aufs has to ignore the event which is fired by aufs
+   itself.
+3. No Extra Validation
+   This is the simplest test and doesn't add any additional revalidation
+   test, and skip the revalidation in step 4. It is useful and improves
+   aufs performance when system surely hide the aufs branches from user,
+   by over-mounting something (or another method).
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/04branch.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/04branch.txt
@@ -0,0 +1,74 @@
+
+# Copyright (C) 2005-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Branch Manipulation
+
+Since aufs supports dynamic branch manipulation, ie. add/remove a branch
+and changing its permission/attribute, there are a lot of works to do.
+
+
+Add a Branch
+----------------------------------------------------------------------
+o Confirm the adding dir exists outside of aufs, including loopback
+  mount, and its various attributes.
+o Initialize the xino file and whiteout bases if necessary.
+  See struct.txt.
+
+o Check the owner/group/mode of the directory
+  When the owner/group/mode of the adding directory differs from the
+  existing branch, aufs issues a warning because it may impose a
+  security risk.
+  For example, when a upper writable branch has a world writable empty
+  top directory, a malicious user can create any files on the writable
+  branch directly, like copy-up and modify manually. If something like
+  /etc/{passwd,shadow} exists on the lower readonly branch but the upper
+  writable branch, and the writable branch is world-writable, then a
+  malicious guy may create /etc/passwd on the writable branch directly
+  and the infected file will be valid in aufs.
+  I am afraid it can be a security issue, but aufs can do nothing except
+  producing a warning.
+
+
+Delete a Branch
+----------------------------------------------------------------------
+o Confirm the deleting branch is not busy
+  To be general, there is one merit to adopt "remount" interface to
+  manipulate branches. It is to discard caches. At deleting a branch,
+  aufs checks the still cached (and connected) dentries and inodes. If
+  there are any, then they are all in-use. An inode without its
+  corresponding dentry can be alive alone (for example, inotify/fsnotify case).
+
+  For the cached one, aufs checks whether the same named entry exists on
+  other branches.
+  If the cached one is a directory, because aufs provides a merged view
+  to users, as long as one dir is left on any branch aufs can show the
+  dir to users. In this case, the branch can be removed from aufs.
+  Otherwise aufs rejects deleting the branch.
+
+  If any file on the deleting branch is opened by aufs, then aufs
+  rejects deleting.
+
+
+Modify the Permission of a Branch
+----------------------------------------------------------------------
+o Re-initialize or remove the xino file and whiteout bases if necessary.
+  See struct.txt.
+
+o rw --> ro: Confirm the modifying branch is not busy
+  Aufs rejects the request if any of these conditions are true.
+  - a file on the branch is mmap-ed.
+  - a regular file on the branch is opened for write and there is no
+    same named entry on the upper branch.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/05wbr_policy.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/05wbr_policy.txt
@@ -0,0 +1,64 @@
+
+# Copyright (C) 2005-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Policies to Select One among Multiple Writable Branches
+----------------------------------------------------------------------
+When the number of writable branch is more than one, aufs has to decide
+the target branch for file creation or copy-up. By default, the highest
+writable branch which has the parent (or ancestor) dir of the target
+file is chosen (top-down-parent policy).
+By user's request, aufs implements some other policies to select the
+writable branch, for file creation several policies, round-robin,
+most-free-space, and other policies. For copy-up, top-down-parent,
+bottom-up-parent, bottom-up and others.
+
+As expected, the round-robin policy selects the branch in circular. When
+you have two writable branches and creates 10 new files, 5 files will be
+created for each branch. mkdir(2) systemcall is an exception. When you
+create 10 new directories, all will be created on the same branch.
+And the most-free-space policy selects the one which has most free
+space among the writable branches. The amount of free space will be
+checked by aufs internally, and users can specify its time interval.
+
+The policies for copy-up is more simple,
+top-down-parent is equivalent to the same named on in create policy,
+bottom-up-parent selects the writable branch where the parent dir
+exists and the nearest upper one from the copyup-source,
+bottom-up selects the nearest upper writable branch from the
+copyup-source, regardless the existence of the parent dir.
+
+There are some rules or exceptions to apply these policies.
+- If there is a readonly branch above the policy-selected branch and
+  the parent dir is marked as opaque (a variation of whiteout), or the
+  target (creating) file is whiteout-ed on the upper readonly branch,
+  then the result of the policy is ignored and the target file will be
+  created on the nearest upper writable branch than the readonly branch.
+- If there is a writable branch above the policy-selected branch and
+  the parent dir is marked as opaque or the target file is whiteouted
+  on the branch, then the result of the policy is ignored and the target
+  file will be created on the highest one among the upper writable
+  branches who has diropq or whiteout. In case of whiteout, aufs removes
+  it as usual.
+- link(2) and rename(2) systemcalls are exceptions in every policy.
+  They try selecting the branch where the source exists as possible
+  since copyup a large file will take long time. If it can't be,
+  ie. the branch where the source exists is readonly, then they will
+  follow the copyup policy.
+- There is an exception for rename(2) when the target exists.
+  If the rename target exists, aufs compares the index of the branches
+  where the source and the target exists and selects the higher
+  one. If the selected branch is readonly, then aufs follows the
+  copyup policy.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/06fhsm.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/06fhsm.txt
@@ -0,0 +1,120 @@
+
+# Copyright (C) 2011-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You 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
+
+
+File-based Hierarchical Storage Management (FHSM)
+----------------------------------------------------------------------
+Hierarchical Storage Management (or HSM) is a well-known feature in the
+storage world. Aufs provides this feature as file-based with multiple
+writable branches, based upon the principle of "Colder, the Lower".
+Here the word "colder" means that the less used files, and "lower" means
+that the position in the order of the stacked branches vertically.
+These multiple writable branches are prioritized, ie. the topmost one
+should be the fastest drive and be used heavily.
+
+o Characters in aufs FHSM story
+- aufs itself and a new branch attribute.
+- a new ioctl interface to move-down and to establish a connection with
+  the daemon ("move-down" is a converse of "copy-up").
+- userspace tool and daemon.
+
+The userspace daemon establishes a connection with aufs and waits for
+the notification. The notified information is very similar to struct
+statfs containing the number of consumed blocks and inodes.
+When the consumed blocks/inodes of a branch exceeds the user-specified
+upper watermark, the daemon activates its move-down process until the
+consumed blocks/inodes reaches the user-specified lower watermark.
+
+The actual move-down is done by aufs based upon the request from
+user-space since we need to maintain the inode number and the internal
+pointer arrays in aufs.
+
+Currently aufs FHSM handles the regular files only. Additionally they
+must not be hard-linked nor pseudo-linked.
+
+
+o Cowork of aufs and the user-space daemon
+  During the userspace daemon established the connection, aufs sends a
+  small notification to it whenever aufs writes something into the
+  writable branch. But it may cost high since aufs issues statfs(2)
+  internally. So user can specify a new option to cache the
+  info. Actually the notification is controlled by these factors.
+  + the specified cache time.
+  + classified as "force" by aufs internally.
+  Until the specified time expires, aufs doesn't send the info
+  except the forced cases. When aufs decide forcing, the info is always
+  notified to userspace.
+  For example, the number of free inodes is generally large enough and
+  the shortage of it happens rarely. So aufs doesn't force the
+  notification when creating a new file, directory and others. This is
+  the typical case which aufs doesn't force.
+  When aufs writes the actual filedata and the files consumes any of new
+  blocks, the aufs forces notifying.
+
+
+o Interfaces in aufs
+- New branch attribute.
+  + fhsm
+    Specifies that the branch is managed by FHSM feature. In other word,
+    participant in the FHSM.
+    When nofhsm is set to the branch, it will not be the source/target
+    branch of the move-down operation. This attribute is set
+    independently from coo and moo attributes, and if you want full
+    FHSM, you should specify them as well.
+- New mount option.
+  + fhsm_sec
+    Specifies a second to suppress many less important info to be
+    notified.
+- New ioctl.
+  + AUFS_CTL_FHSM_FD
+    create a new file descriptor which userspace can read the notification
+    (a subset of struct statfs) from aufs.
+- Module parameter 'brs'
+  It has to be set to 1. Otherwise the new mount option 'fhsm' will not
+  be set.
+- mount helpers /sbin/mount.aufs and /sbin/umount.aufs
+  When there are two or more branches with fhsm attributes,
+  /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs
+  terminates it. As a result of remounting and branch-manipulation, the
+  number of branches with fhsm attribute can be one. In this case,
+  /sbin/mount.aufs will terminate the user-space daemon.
+
+
+Finally the operation is done as these steps in kernel-space.
+- make sure that,
+  + no one else is using the file.
+  + the file is not hard-linked.
+  + the file is not pseudo-linked.
+  + the file is a regular file.
+  + the parent dir is not opaqued.
+- find the target writable branch.
+- make sure the file is not whiteout-ed by the upper (than the target)
+  branch.
+- make the parent dir on the target branch.
+- mutex lock the inode on the branch.
+- unlink the whiteout on the target branch (if exists).
+- lookup and create the whiteout-ed temporary name on the target branch.
+- copy the file as the whiteout-ed temporary name on the target branch.
+- rename the whiteout-ed temporary name to the original name.
+- unlink the file on the source branch.
+- maintain the internal pointer array and the external inode number
+  table (XINO).
+- maintain the timestamps and other attributes of the parent dir and the
+  file.
+
+And of course, in every step, an error may happen. So the operation
+should restore the original file state after an error happens.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/06mmap.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/06mmap.txt
@@ -0,0 +1,72 @@
+
+# Copyright (C) 2005-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+mmap(2) -- File Memory Mapping
+----------------------------------------------------------------------
+In aufs, the file-mapped pages are handled by a branch fs directly, no
+interaction with aufs. It means aufs_mmap() calls the branch fs's
+->mmap().
+This approach is simple and good, but there is one problem.
+Under /proc, several entries show the mmapped files by its path (with
+device and inode number), and the printed path will be the path on the
+branch fs's instead of virtual aufs's.
+This is not a problem in most cases, but some utilities lsof(1) (and its
+user) may expect the path on aufs.
+
+To address this issue, aufs adds a new member called vm_prfile in struct
+vm_area_struct (and struct vm_region). The original vm_file points to
+the file on the branch fs in order to handle everything correctly as
+usual. The new vm_prfile points to a virtual file in aufs, and the
+show-functions in procfs refers to vm_prfile if it is set.
+Also we need to maintain several other places where touching vm_file
+such like
+- fork()/clone() copies vma and the reference count of vm_file is
+  incremented.
+- merging vma maintains the ref count too.
+
+This is not a good approach. It just fakes the printed path. But it
+leaves all behaviour around f_mapping unchanged. This is surely an
+advantage.
+Actually aufs had adopted another complicated approach which calls
+generic_file_mmap() and handles struct vm_operations_struct. In this
+approach, aufs met a hard problem and I could not solve it without
+switching the approach.
+
+There may be one more another approach which is
+- bind-mount the branch-root onto the aufs-root internally
+- grab the new vfsmount (ie. struct mount)
+- lazy-umount the branch-root internally
+- in open(2) the aufs-file, open the branch-file with the hidden
+  vfsmount (instead of the original branch's vfsmount)
+- ideally this "bind-mount and lazy-umount" should be done atomically,
+  but it may be possible from userspace by the mount helper.
+
+Adding the internal hidden vfsmount and using it in opening a file, the
+file path under /proc will be printed correctly. This approach looks
+smarter, but is not possible I am afraid.
+- aufs-root may be bind-mount later. when it happens, another hidden
+  vfsmount will be required.
+- it is hard to get the chance to bind-mount and lazy-umount
+  + in kernel-space, FS can have vfsmount in open(2) via
+    file->f_path, and aufs can know its vfsmount. But several locks are
+    already acquired, and if aufs tries to bind-mount and lazy-umount
+    here, then it may cause a deadlock.
+  + in user-space, bind-mount doesn't invoke the mount helper.
+- since /proc shows dev and ino, aufs has to give vma these info. it
+  means a new member vm_prinode will be necessary. this is essentially
+  equivalent to vm_prfile described above.
+
+I have to give up this "looks-smater" approach.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/06xattr.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/06xattr.txt
@@ -0,0 +1,96 @@
+
+# Copyright (C) 2014-2015 Junjiro R. Okajima
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You 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
+
+
+Listing XATTR/EA and getting the value
+----------------------------------------------------------------------
+For the inode standard attributes (owner, group, timestamps, etc.), aufs
+shows the values from the topmost existing file. This behaviour is good
+for the non-dir entries since the bahaviour exactly matches the shown
+information. But for the directories, aufs considers all the same named
+entries on the lower branches. Which means, if one of the lower entry
+rejects readdir call, then aufs returns an error even if the topmost
+entry allows it. This behaviour is necessary to respect the branch fs's
+security, but can make users confused since the user-visible standard
+attributes don't match the behaviour.
+To address this issue, aufs has a mount option called dirperm1 which
+checks the permission for the topmost entry only, and ignores the lower
+entry's permission.
+
+A similar issue can happen around XATTR.
+getxattr(2) and listxattr(2) families behave as if dirperm1 option is
+always set. Otherwise these very unpleasant situation would happen.
+- listxattr(2) may return the duplicated entries.
+- users may not be able to remove or reset the XATTR forever,
+
+
+XATTR/EA support in the internal (copy,move)-(up,down)
+----------------------------------------------------------------------
+Generally the extended attributes of inode are categorized as these.
+- "security" for LSM and capability.
+- "system" for posix ACL, 'acl' mount option is required for the branch
+  fs generally.
+- "trusted" for userspace, CAP_SYS_ADMIN is required.
+- "user" for userspace, 'user_xattr' mount option is required for the
+  branch fs generally.
+
+Moreover there are some other categories. Aufs handles these rather
+unpopular categories as the ordinary ones, ie. there is no special
+condition nor exception.
+
+In copy-up, the support for XATTR on the dst branch may differ from the
+src branch. In this case, the copy-up operation will get an error and
+the original user operation which triggered the copy-up will fail. It
+can happen that even all copy-up will fail.
+When both of src and dst branches support XATTR and if an error occurs
+during copying XATTR, then the copy-up should fail obviously. That is a
+good reason and aufs should return an error to userspace. But when only
+the src branch support that XATTR, aufs should not return an error.
+For example, the src branch supports ACL but the dst branch doesn't
+because the dst branch may natively un-support it or temporary
+un-support it due to "noacl" mount option. Of course, the dst branch fs
+may NOT return an error even if the XATTR is not supported. It is
+totally up to the branch fs.
+
+Anyway when the aufs internal copy-up gets an error from the dst branch
+fs, then aufs tries removing the just copied entry and returns the error
+to the userspace. The worst case of this situation will be all copy-up
+will fail.
+
+For the copy-up operation, there two basic approaches.
+- copy the specified XATTR only (by category above), and return the
+  error unconditionally if it happens.
+- copy all XATTR, and ignore the error on the specified category only.
+
+In order to support XATTR and to implement the correct behaviour, aufs
+chooses the latter approach and introduces some new branch attributes,
+"icexsec", "icexsys", "icextr", "icexusr", and "icexoth".
+They correspond to the XATTR namespaces (see above). Additionally, to be
+convenient, "icex" is also provided which means all "icex*" attributes
+are set (here the word "icex" stands for "ignore copy-error on XATTR").
+
+The meaning of these attributes is to ignore the error from setting
+XATTR on that branch.
+Note that aufs tries copying all XATTR unconditionally, and ignores the
+error from the dst branch according to the specified attributes.
+
+Some XATTR may have its default value. The default value may come from
+the parent dir or the environment. If the default value is set at the
+file creating-time, it will be overwritten by copy-up.
+Some contradiction may happen I am afraid.
+Do we need another attribute to stop copying XATTR? I am unsure. For
+now, aufs implements the branch attributes to ignore the error.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/07export.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/07export.txt
@@ -0,0 +1,58 @@
+
+# Copyright (C) 2005-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Export Aufs via NFS
+----------------------------------------------------------------------
+Here is an approach.
+- like xino/xib, add a new file 'xigen' which stores aufs inode
+  generation.
+- iget_locked(): initialize aufs inode generation for a new inode, and
+  store it in xigen file.
+- destroy_inode(): increment aufs inode generation and store it in xigen
+  file. it is necessary even if it is not unlinked, because any data of
+  inode may be changed by UDBA.
+- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise
+  build file handle by
+  + branch id (4 bytes)
+  + superblock generation (4 bytes)
+  + inode number (4 or 8 bytes)
+  + parent dir inode number (4 or 8 bytes)
+  + inode generation (4 bytes))
+  + return value of exportfs_encode_fh() for the parent on a branch (4
+    bytes)
+  + file handle for a branch (by exportfs_encode_fh())
+- fh_to_dentry():
+  + find the index of a branch from its id in handle, and check it is
+    still exist in aufs.
+  + 1st level: get the inode number from handle and search it in cache.
+  + 2nd level: if not found in cache, get the parent inode number from
+    the handle and search it in cache. and then open the found parent
+    dir, find the matching inode number by vfs_readdir() and get its
+    name, and call lookup_one_len() for the target dentry.
+  + 3rd level: if the parent dir is not cached, call
+    exportfs_decode_fh() for a branch and get the parent on a branch,
+    build a pathname of it, convert it a pathname in aufs, call
+    path_lookup(). now aufs gets a parent dir dentry, then handle it as
+    the 2nd level.
+  + to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount
+    for every branch, but not itself. to get this, (currently) aufs
+    searches in current->nsproxy->mnt_ns list. it may not be a good
+    idea, but I didn't get other approach.
+  + test the generation of the gotten inode.
+- every inode operation: they may get EBUSY due to UDBA. in this case,
+  convert it into ESTALE for NFSD.
+- readdir(): call lockdep_on/off() because filldir in NFSD calls
+  lookup_one_len(), vfs_getattr(), encode_fh() and others.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/08shwh.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/08shwh.txt
@@ -0,0 +1,52 @@
+
+# Copyright (C) 2005-2015 Junjiro R. Okajima
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Show Whiteout Mode (shwh)
+----------------------------------------------------------------------
+Generally aufs hides the name of whiteouts. But in some cases, to show
+them is very useful for users. For instance, creating a new middle layer
+(branch) by merging existing layers.
+
+(borrowing aufs1 HOW-TO from a user, Michael Towers)
+When you have three branches,
+- Bottom: 'system', squashfs (underlying base system), read-only
+- Middle: 'mods', squashfs, read-only
+- Top: 'overlay', ram (tmpfs), read-write
+
+The top layer is loaded at boot time and saved at shutdown, to preserve
+the changes made to the system during the session.
+When larger changes have been made, or smaller changes have accumulated,
+the size of the saved top layer data grows. At this point, it would be
+nice to be able to merge the two overlay branches ('mods' and 'overlay')
+and rewrite the 'mods' squashfs, clearing the top layer and thus
+restoring save and load speed.
+
+This merging is simplified by the use of another aufs mount, of just the
+two overlay branches using the 'shwh' option.
+# mount -t aufs -o ro,shwh,br:/livesys/overlay=ro+wh:/livesys/mods=rr+wh \
+	aufs /livesys/merge_union
+
+A merged view of these two branches is then available at
+/livesys/merge_union, and the new feature is that the whiteouts are
+visible!
+Note that in 'shwh' mode the aufs mount must be 'ro', which will disable
+writing to all branches. Also the default mode for all branches is 'ro'.
+It is now possible to save the combined contents of the two overlay
+branches to a new squashfs, e.g.:
+# mksquashfs /livesys/merge_union /path/to/newmods.squash
+
+This new squashfs archive can be stored on the boot device and the
+initramfs will use it to replace the old one at the next boot.
--- linux-4.4.0.orig/Documentation/filesystems/aufs/design/10dynop.txt
+++ linux-4.4.0/Documentation/filesystems/aufs/design/10dynop.txt
@@ -0,0 +1,47 @@
+
+# Copyright (C) 2010-2015 Junjiro R. Okajima
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU 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/>.
+
+Dynamically customizable FS operations
+----------------------------------------------------------------------
+Generally FS operations (struct inode_operations, struct
+address_space_operations, struct file_operations, etc.) are defined as
+"static const", but it never means that FS have only one set of
+operation. Some FS have multiple sets of them. For instance, ext2 has
+three sets, one for XIP, for NOBH, and for normal.
+Since aufs overrides and redirects these operations, sometimes aufs has
+to change its behaviour according to the branch FS type. More importantly
+VFS acts differently if a function (member in the struct) is set or
+not. It means aufs should have several sets of operations and select one
+among them according to the branch FS definition.
+
+In order to solve this problem and not to affect the behaviour of VFS,
+aufs defines these operations dynamically. For instance, aufs defines
+dummy direct_IO function for struct address_space_operations, but it may
+not be set to the address_space_operations actually. When the branch FS
+doesn't have it, aufs doesn't set it to its address_space_operations
+while the function definition itself is still alive. So the behaviour
+itself will not change, and it will return an error when direct_IO is
+not set.
+
+The lifetime of these dynamically generated operation object is
+maintained by aufs branch object. When the branch is removed from aufs,
+the reference counter of the object is decremented. When it reaches
+zero, the dynamically generated operation object will be freed.
+
+This approach is designed to support AIO (io_submit), Direct I/O and
+XIP (DAX) mainly.
+Currently this approach is applied to address_space_operations for
+regular files only.
--- linux-4.4.0.orig/Documentation/filesystems/efivarfs.txt
+++ linux-4.4.0/Documentation/filesystems/efivarfs.txt
@@ -14,3 +14,10 @@
 efivarfs is typically mounted like this,
 
 	mount -t efivarfs none /sys/firmware/efi/efivars
+
+Due to the presence of numerous firmware bugs where removing non-standard
+UEFI variables causes the system firmware to fail to POST, efivarfs
+files that are not well-known standardized variables are created
+as immutable files.  This doesn't prevent removal - "chattr -i" will work -
+but it does prevent this kind of failure from being accomplished
+accidentally.
--- linux-4.4.0.orig/Documentation/filesystems/ext4.txt
+++ linux-4.4.0/Documentation/filesystems/ext4.txt
@@ -233,7 +233,7 @@
 data_err=abort		Abort the journal if an error occurs in a file
 			data buffer in ordered mode.
 
-grpid			Give objects the same group ID as their creator.
+grpid			New objects have the group ID of their parent.
 bsdgroups
 
 nogrpid		(*)	New objects have the group ID of their creator.
--- linux-4.4.0.orig/Documentation/filesystems/porting
+++ linux-4.4.0/Documentation/filesystems/porting
@@ -287,8 +287,8 @@
 and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
 be in order of zeroing blocks using block_truncate_page or similar helpers,
 size update and on finally on-disk truncation which should not fail.
-inode_change_ok now includes the size checks for ATTR_SIZE and must be called
-in the beginning of ->setattr unconditionally.
+setattr_prepare (which used to be inode_change_ok) now includes the size checks
+for ATTR_SIZE and must be called in the beginning of ->setattr unconditionally.
 
 [mandatory]
 
--- linux-4.4.0.orig/Documentation/filesystems/proc.txt
+++ linux-4.4.0/Documentation/filesystems/proc.txt
@@ -346,7 +346,7 @@
 a7cb1000-a7cb2000 ---p 00000000 00:00 0
 a7cb2000-a7eb2000 rw-p 00000000 00:00 0
 a7eb2000-a7eb3000 ---p 00000000 00:00 0
-a7eb3000-a7ed5000 rw-p 00000000 00:00 0          [stack:1001]
+a7eb3000-a7ed5000 rw-p 00000000 00:00 0
 a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
 a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
 a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
@@ -378,40 +378,11 @@
 
  [heap]                   = the heap of the program
  [stack]                  = the stack of the main process
- [stack:1001]             = the stack of the thread with tid 1001
  [vdso]                   = the "virtual dynamic shared object",
                             the kernel system call handler
 
  or if empty, the mapping is anonymous.
 
-The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint
-of the individual tasks of a process. In this file you will see a mapping marked
-as [stack] if that task sees it as a stack. This is a key difference from the
-content of /proc/PID/maps, where you will see all mappings that are being used
-as stack by all of those tasks. Hence, for the example above, the task-level
-map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
-
-08048000-08049000 r-xp 00000000 03:00 8312       /opt/test
-08049000-0804a000 rw-p 00001000 03:00 8312       /opt/test
-0804a000-0806b000 rw-p 00000000 00:00 0          [heap]
-a7cb1000-a7cb2000 ---p 00000000 00:00 0
-a7cb2000-a7eb2000 rw-p 00000000 00:00 0
-a7eb2000-a7eb3000 ---p 00000000 00:00 0
-a7eb3000-a7ed5000 rw-p 00000000 00:00 0          [stack]
-a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
-a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
-a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
-a800b000-a800e000 rw-p 00000000 00:00 0
-a800e000-a8022000 r-xp 00000000 03:00 14462      /lib/libpthread.so.0
-a8022000-a8023000 r--p 00013000 03:00 14462      /lib/libpthread.so.0
-a8023000-a8024000 rw-p 00014000 03:00 14462      /lib/libpthread.so.0
-a8024000-a8027000 rw-p 00000000 00:00 0
-a8027000-a8043000 r-xp 00000000 03:00 8317       /lib/ld-linux.so.2
-a8043000-a8044000 r--p 0001b000 03:00 8317       /lib/ld-linux.so.2
-a8044000-a8045000 rw-p 0001c000 03:00 8317       /lib/ld-linux.so.2
-aff35000-aff4a000 rw-p 00000000 00:00 0
-ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
-
 The /proc/PID/smaps is an extension based on maps, showing the memory
 consumption for each of the process's mappings. For each of mappings there
 is a series of lines such as the following:
@@ -495,7 +466,9 @@
 
 Note that there is no guarantee that every flag and associated mnemonic will
 be present in all further kernel releases. Things get changed, the flags may
-be vanished or the reverse -- new added.
+be vanished or the reverse -- new added. Interpretation of their meaning
+might change in future as well. So each consumer of these flags has to
+follow each specific kernel version for the exact semantic.
 
 This file is only present if the CONFIG_MMU kernel configuration option is
 enabled.
--- linux-4.4.0.orig/Documentation/filesystems/sysfs.txt
+++ linux-4.4.0/Documentation/filesystems/sysfs.txt
@@ -211,12 +211,10 @@
   is 4096. 
 
 - show() methods should return the number of bytes printed into the
-  buffer. This is the return value of scnprintf().
+  buffer.
 
-- show() must not use snprintf() when formatting the value to be
-  returned to user space. If you can guarantee that an overflow
-  will never happen you can use sprintf() otherwise you must use
-  scnprintf().
+- show() should only use sysfs_emit() or sysfs_emit_at() when formatting
+  the value to be returned to user space.
 
 - store() should return the number of bytes used from the buffer. If the
   entire buffer has been used, just return the count argument.
--- linux-4.4.0.orig/Documentation/gpio/driver.txt
+++ linux-4.4.0/Documentation/gpio/driver.txt
@@ -165,6 +165,12 @@
   to the container using container_of().
   (See Documentation/driver-model/design-patterns.txt)
 
+  If there is a need to exclude certain GPIOs from the IRQ domain, one can
+  set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
+  called. This allocates .irq_valid_mask with as many bits set as there are
+  GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
+  mask. The mask must be filled in before gpiochip_irqchip_add() is called.
+
 * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
   gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
   data. (Notice handler data, since the irqchip data is likely used by the
--- linux-4.4.0.orig/Documentation/hid/hid-alps.txt
+++ linux-4.4.0/Documentation/hid/hid-alps.txt
@@ -0,0 +1,139 @@
+ALPS HID Touchpad Protocol
+----------------------
+
+Introduction
+------------
+Currently ALPS HID driver supports U1 Touchpad device.
+
+U1 devuce basic information.
+Vender ID	0x044E
+Product ID	0x120B
+Version ID	0x0121
+
+
+HID Descriptor
+------------
+Byte	Field			Value	Notes
+0	wHIDDescLength		001E	Length of HID Descriptor : 30 bytes
+2	bcdVersion		0100	Compliant with Version 1.00
+4	wReportDescLength	00B2	Report Descriptor is 178 Bytes (0x00B2)
+6	wReportDescRegister	0002	Identifier to read Report Descriptor
+8	wInputRegister		0003	Identifier to read Input Report
+10	wMaxInputLength		0053	Input Report is 80 Bytes + 2
+12	wOutputRegister		0000	Identifier to read Output Report
+14	wMaxOutputLength	0000	No Output Reports
+16	wCommandRegister	0005	Identifier for Command Register
+18	wDataRegister		0006	Identifier for Data Register
+20	wVendorID		044E	Vendor ID 0x044E
+22	wProductID		120B	Product ID 0x120B
+24	wVersionID		0121	Version 01.21
+26	RESERVED		0000	RESERVED
+
+
+Report ID
+------------
+ReportID-1	(Input Reports)	(HIDUsage-Mouse) for TP&SP
+ReportID-2	(Input Reports)	(HIDUsage-keyboard) for TP
+ReportID-3	(Input Reports)	(Vendor Usage: Max 10 finger data) for TP
+ReportID-4	(Input Reports)	(Vendor Usage: ON bit data) for GP
+ReportID-5	(Feature Reports)	Feature Reports
+ReportID-6	(Input Reports)	(Vendor Usage: StickPointer data) for SP
+ReportID-7	(Feature Reports)	Flash update (Bootloader)
+
+
+Data pattern
+------------
+Case1	ReportID_1	TP/SP	Relative/Relative
+Case2	ReportID_3	TP	Absolute
+	ReportID_6	SP	Absolute
+
+
+Command Read/Write
+------------------
+To read/write to RAM, need to send a commands to the device.
+The command format is as below.
+
+DataByte(SET_REPORT)
+Byte1	Command Byte
+Byte2	Address - Byte 0 (LSB)
+Byte3	Address - Byte 1
+Byte4	Address - Byte 2
+Byte5	Address - Byte 3 (MSB)
+Byte6	Value Byte
+Byte7	Checksum
+
+Command Byte is read=0xD1/write=0xD2 .
+Address is read/write RAM address.
+Value Byte is writing data when you send the write commands.
+When you read RAM, there is no meaning.
+
+DataByte(GET_REPORT)
+Byte1	Response Byte
+Byte2	Address - Byte 0 (LSB)
+Byte3	Address - Byte 1
+Byte4	Address - Byte 2
+Byte5	Address - Byte 3 (MSB)
+Byte6	Value Byte
+Byte7	Checksum
+
+Read value is stored in Value Byte.
+
+
+Packet Format
+Touchpad data byte
+------------------
+	b7	b6	b5	b4	b3	b2	b1	b0
+1	0	0	SW6	SW5	SW4	SW3	SW2	SW1
+2	0	0	0	Fcv	Fn3	Fn2	Fn1	Fn0
+3	Xa0_7	Xa0_6	Xa0_5	Xa0_4	Xa0_3	Xa0_2	Xa0_1	Xa0_0
+4	Xa0_15	Xa0_14	Xa0_13	Xa0_12	Xa0_11	Xa0_10	Xa0_9	Xa0_8
+5	Ya0_7	Ya0_6	Ya0_5	Ya0_4	Ya0_3	Ya0_2	Ya0_1	Ya0_0
+6	Ya0_15	Ya0_14	Ya0_13	Ya0_12	Ya0_11	Ya0_10	Ya0_9	Ya0_8
+7	LFB0	Zs0_6	Zs0_5	Zs0_4	Zs0_3	Zs0_2	Zs0_1	Zs0_0
+
+8	Xa1_7	Xa1_6	Xa1_5	Xa1_4	Xa1_3	Xa1_2	Xa1_1	Xa1_0
+9	Xa1_15	Xa1_14	Xa1_13	Xa1_12	Xa1_11	Xa1_10	Xa1_9	Xa1_8
+10	Ya1_7	Ya1_6	Ya1_5	Ya1_4	Ya1_3	Ya1_2	Ya1_1	Ya1_0
+11	Ya1_15	Ya1_14	Ya1_13	Ya1_12	Ya1_11	Ya1_10	Ya1_9	Ya1_8
+12	LFB1	Zs1_6	Zs1_5	Zs1_4	Zs1_3	Zs1_2	Zs1_1	Zs1_0
+
+13	Xa2_7	Xa2_6	Xa2_5	Xa2_4	Xa2_3	Xa2_2	Xa2_1	Xa2_0
+14	Xa2_15	Xa2_14	Xa2_13	Xa2_12	Xa2_11	Xa2_10	Xa2_9	Xa2_8
+15	Ya2_7	Ya2_6	Ya2_5	Ya2_4	Ya2_3	Ya2_2	Ya2_1	Ya2_0
+16	Ya2_15	Ya2_14	Ya2_13	Ya2_12	Ya2_11	Ya2_10	Ya2_9	Ya2_8
+17	LFB2	Zs2_6	Zs2_5	Zs2_4	Zs2_3	Zs2_2	Zs2_1	Zs2_0
+
+18	Xa3_7	Xa3_6	Xa3_5	Xa3_4	Xa3_3	Xa3_2	Xa3_1	Xa3_0
+19	Xa3_15	Xa3_14	Xa3_13	Xa3_12	Xa3_11	Xa3_10	Xa3_9	Xa3_8
+20	Ya3_7	Ya3_6	Ya3_5	Ya3_4	Ya3_3	Ya3_2	Ya3_1	Ya3_0
+21	Ya3_15	Ya3_14	Ya3_13	Ya3_12	Ya3_11	Ya3_10	Ya3_9	Ya3_8
+22	LFB3	Zs3_6	Zs3_5	Zs3_4	Zs3_3	Zs3_2	Zs3_1	Zs3_0
+
+23	Xa4_7	Xa4_6	Xa4_5	Xa4_4	Xa4_3	Xa4_2	Xa4_1	Xa4_0
+24	Xa4_15	Xa4_14	Xa4_13	Xa4_12	Xa4_11	Xa4_10	Xa4_9	Xa4_8
+25	Ya4_7	Ya4_6	Ya4_5	Ya4_4	Ya4_3	Ya4_2	Ya4_1	Ya4_0
+26	Ya4_15	Ya4_14	Ya4_13	Ya4_12	Ya4_11	Ya4_10	Ya4_9	Ya4_8
+27	LFB4	Zs4_6	Zs4_5	Zs4_4	Zs4_3	Zs4_2	Zs4_1	Zs4_0
+
+
+SW1-SW6:	SW ON/OFF status
+Xan_15-0(16bit):X Absolute data of the "n"th finger
+Yan_15-0(16bit):Y Absolute data of the "n"th finger
+Zsn_6-0(7bit):	Operation area of the "n"th finger
+
+
+StickPointer data byte
+------------------
+	b7	b6	b5	b4	b3	b2	b1	b0
+Byte1	1	1	1	0	1	SW3	SW2	SW1
+Byte2	X7	X6	X5	X4	X3	X2	X1	X0
+Byte3	X15	X14	X13	X12	X11	X10	X9	X8
+Byte4	Y7	Y6	Y5	Y4	Y3	Y2	Y1	Y0
+Byte5	Y15	Y14	Y13	Y12	Y11	Y10	Y9	Y8
+Byte6	Z7	Z6	Z5	Z4	Z3	Z2	Z1	Z0
+Byte7	T&P	Z14	Z13	Z12	Z11	Z10	Z9	Z8
+
+SW1-SW3:	SW ON/OFF status
+Xn_15-0(16bit):X Absolute data
+Yn_15-0(16bit):Y Absolute data
+Zn_14-0(15bit):Z
--- linux-4.4.0.orig/Documentation/hid/uhid.txt
+++ linux-4.4.0/Documentation/hid/uhid.txt
@@ -160,7 +160,7 @@
   UHID_OUTPUT:
   This is sent if the HID device driver wants to send raw data to the I/O
   device on the interrupt channel. You should read the payload and forward it to
-  the device. The payload is of type "struct uhid_data_req".
+  the device. The payload is of type "struct uhid_output_req".
   This may be received even though you haven't received UHID_OPEN, yet.
 
   UHID_GET_REPORT:
--- linux-4.4.0.orig/Documentation/hw-vuln/processor_mmio_stale_data.rst
+++ linux-4.4.0/Documentation/hw-vuln/processor_mmio_stale_data.rst
@@ -0,0 +1,246 @@
+=========================================
+Processor MMIO Stale Data Vulnerabilities
+=========================================
+
+Processor MMIO Stale Data Vulnerabilities are a class of memory-mapped I/O
+(MMIO) vulnerabilities that can expose data. The sequences of operations for
+exposing data range from simple to very complex. Because most of the
+vulnerabilities require the attacker to have access to MMIO, many environments
+are not affected. System environments using virtualization where MMIO access is
+provided to untrusted guests may need mitigation. These vulnerabilities are
+not transient execution attacks. However, these vulnerabilities may propagate
+stale data into core fill buffers where the data can subsequently be inferred
+by an unmitigated transient execution attack. Mitigation for these
+vulnerabilities includes a combination of microcode update and software
+changes, depending on the platform and usage model. Some of these mitigations
+are similar to those used to mitigate Microarchitectural Data Sampling (MDS) or
+those used to mitigate Special Register Buffer Data Sampling (SRBDS).
+
+Data Propagators
+================
+Propagators are operations that result in stale data being copied or moved from
+one microarchitectural buffer or register to another. Processor MMIO Stale Data
+Vulnerabilities are operations that may result in stale data being directly
+read into an architectural, software-visible state or sampled from a buffer or
+register.
+
+Fill Buffer Stale Data Propagator (FBSDP)
+-----------------------------------------
+Stale data may propagate from fill buffers (FB) into the non-coherent portion
+of the uncore on some non-coherent writes. Fill buffer propagation by itself
+does not make stale data architecturally visible. Stale data must be propagated
+to a location where it is subject to reading or sampling.
+
+Sideband Stale Data Propagator (SSDP)
+-------------------------------------
+The sideband stale data propagator (SSDP) is limited to the client (including
+Intel Xeon server E3) uncore implementation. The sideband response buffer is
+shared by all client cores. For non-coherent reads that go to sideband
+destinations, the uncore logic returns 64 bytes of data to the core, including
+both requested data and unrequested stale data, from a transaction buffer and
+the sideband response buffer. As a result, stale data from the sideband
+response and transaction buffers may now reside in a core fill buffer.
+
+Primary Stale Data Propagator (PSDP)
+------------------------------------
+The primary stale data propagator (PSDP) is limited to the client (including
+Intel Xeon server E3) uncore implementation. Similar to the sideband response
+buffer, the primary response buffer is shared by all client cores. For some
+processors, MMIO primary reads will return 64 bytes of data to the core fill
+buffer including both requested data and unrequested stale data. This is
+similar to the sideband stale data propagator.
+
+Vulnerabilities
+===============
+Device Register Partial Write (DRPW) (CVE-2022-21166)
+-----------------------------------------------------
+Some endpoint MMIO registers incorrectly handle writes that are smaller than
+the register size. Instead of aborting the write or only copying the correct
+subset of bytes (for example, 2 bytes for a 2-byte write), more bytes than
+specified by the write transaction may be written to the register. On
+processors affected by FBSDP, this may expose stale data from the fill buffers
+of the core that created the write transaction.
+
+Shared Buffers Data Sampling (SBDS) (CVE-2022-21125)
+----------------------------------------------------
+After propagators may have moved data around the uncore and copied stale data
+into client core fill buffers, processors affected by MFBDS can leak data from
+the fill buffer. It is limited to the client (including Intel Xeon server E3)
+uncore implementation.
+
+Shared Buffers Data Read (SBDR) (CVE-2022-21123)
+------------------------------------------------
+It is similar to Shared Buffer Data Sampling (SBDS) except that the data is
+directly read into the architectural software-visible state. It is limited to
+the client (including Intel Xeon server E3) uncore implementation.
+
+Affected Processors
+===================
+Not all the CPUs are affected by all the variants. For instance, most
+processors for the server market (excluding Intel Xeon E3 processors) are
+impacted by only Device Register Partial Write (DRPW).
+
+Below is the list of affected Intel processors [#f1]_:
+
+   ===================  ============  =========
+   Common name          Family_Model  Steppings
+   ===================  ============  =========
+   HASWELL_X            06_3FH        2,4
+   SKYLAKE_L            06_4EH        3
+   BROADWELL_X          06_4FH        All
+   SKYLAKE_X            06_55H        3,4,6,7,11
+   BROADWELL_D          06_56H        3,4,5
+   SKYLAKE              06_5EH        3
+   ICELAKE_X            06_6AH        4,5,6
+   ICELAKE_D            06_6CH        1
+   ICELAKE_L            06_7EH        5
+   ATOM_TREMONT_D       06_86H        All
+   LAKEFIELD            06_8AH        1
+   KABYLAKE_L           06_8EH        9 to 12
+   ATOM_TREMONT         06_96H        1
+   ATOM_TREMONT_L       06_9CH        0
+   KABYLAKE             06_9EH        9 to 13
+   COMETLAKE            06_A5H        2,3,5
+   COMETLAKE_L          06_A6H        0,1
+   ROCKETLAKE           06_A7H        1
+   ===================  ============  =========
+
+If a CPU is in the affected processor list, but not affected by a variant, it
+is indicated by new bits in MSR IA32_ARCH_CAPABILITIES. As described in a later
+section, mitigation largely remains the same for all the variants, i.e. to
+clear the CPU fill buffers via VERW instruction.
+
+New bits in MSRs
+================
+Newer processors and microcode update on existing affected processors added new
+bits to IA32_ARCH_CAPABILITIES MSR. These bits can be used to enumerate
+specific variants of Processor MMIO Stale Data vulnerabilities and mitigation
+capability.
+
+MSR IA32_ARCH_CAPABILITIES
+--------------------------
+Bit 13 - SBDR_SSDP_NO - When set, processor is not affected by either the
+	 Shared Buffers Data Read (SBDR) vulnerability or the sideband stale
+	 data propagator (SSDP).
+Bit 14 - FBSDP_NO - When set, processor is not affected by the Fill Buffer
+	 Stale Data Propagator (FBSDP).
+Bit 15 - PSDP_NO - When set, processor is not affected by Primary Stale Data
+	 Propagator (PSDP).
+Bit 17 - FB_CLEAR - When set, VERW instruction will overwrite CPU fill buffer
+	 values as part of MD_CLEAR operations. Processors that do not
+	 enumerate MDS_NO (meaning they are affected by MDS) but that do
+	 enumerate support for both L1D_FLUSH and MD_CLEAR implicitly enumerate
+	 FB_CLEAR as part of their MD_CLEAR support.
+Bit 18 - FB_CLEAR_CTRL - Processor supports read and write to MSR
+	 IA32_MCU_OPT_CTRL[FB_CLEAR_DIS]. On such processors, the FB_CLEAR_DIS
+	 bit can be set to cause the VERW instruction to not perform the
+	 FB_CLEAR action. Not all processors that support FB_CLEAR will support
+	 FB_CLEAR_CTRL.
+
+MSR IA32_MCU_OPT_CTRL
+---------------------
+Bit 3 - FB_CLEAR_DIS - When set, VERW instruction does not perform the FB_CLEAR
+action. This may be useful to reduce the performance impact of FB_CLEAR in
+cases where system software deems it warranted (for example, when performance
+is more critical, or the untrusted software has no MMIO access). Note that
+FB_CLEAR_DIS has no impact on enumeration (for example, it does not change
+FB_CLEAR or MD_CLEAR enumeration) and it may not be supported on all processors
+that enumerate FB_CLEAR.
+
+Mitigation
+==========
+Like MDS, all variants of Processor MMIO Stale Data vulnerabilities  have the
+same mitigation strategy to force the CPU to clear the affected buffers before
+an attacker can extract the secrets.
+
+This is achieved by using the otherwise unused and obsolete VERW instruction in
+combination with a microcode update. The microcode clears the affected CPU
+buffers when the VERW instruction is executed.
+
+Kernel reuses the MDS function to invoke the buffer clearing:
+
+	mds_clear_cpu_buffers()
+
+On MDS affected CPUs, the kernel already invokes CPU buffer clear on
+kernel/userspace, hypervisor/guest and C-state (idle) transitions. No
+additional mitigation is needed on such CPUs.
+
+For CPUs not affected by MDS or TAA, mitigation is needed only for the attacker
+with MMIO capability. Therefore, VERW is not required for kernel/userspace. For
+virtualization case, VERW is only needed at VMENTER for a guest with MMIO
+capability.
+
+Mitigation points
+-----------------
+Return to user space
+^^^^^^^^^^^^^^^^^^^^
+Same mitigation as MDS when affected by MDS/TAA, otherwise no mitigation
+needed.
+
+C-State transition
+^^^^^^^^^^^^^^^^^^
+Control register writes by CPU during C-state transition can propagate data
+from fill buffer to uncore buffers. Execute VERW before C-state transition to
+clear CPU fill buffers.
+
+Guest entry point
+^^^^^^^^^^^^^^^^^
+Same mitigation as MDS when processor is also affected by MDS/TAA, otherwise
+execute VERW at VMENTER only for MMIO capable guests. On CPUs not affected by
+MDS/TAA, guest without MMIO access cannot extract secrets using Processor MMIO
+Stale Data vulnerabilities, so there is no need to execute VERW for such guests.
+
+Mitigation control on the kernel command line
+---------------------------------------------
+The kernel command line allows to control the Processor MMIO Stale Data
+mitigations at boot time with the option "mmio_stale_data=". The valid
+arguments for this option are:
+
+  ==========  =================================================================
+  full        If the CPU is vulnerable, enable mitigation; CPU buffer clearing
+              on exit to userspace and when entering a VM. Idle transitions are
+              protected as well. It does not automatically disable SMT.
+  full,nosmt  Same as full, with SMT disabled on vulnerable CPUs. This is the
+              complete mitigation.
+  off         Disables mitigation completely.
+  ==========  =================================================================
+
+If the CPU is affected and mmio_stale_data=off is not supplied on the kernel
+command line, then the kernel selects the appropriate mitigation.
+
+Mitigation status information
+-----------------------------
+The Linux kernel provides a sysfs interface to enumerate the current
+vulnerability status of the system: whether the system is vulnerable, and
+which mitigations are active. The relevant sysfs file is:
+
+	/sys/devices/system/cpu/vulnerabilities/mmio_stale_data
+
+The possible values in this file are:
+
+  .. list-table::
+
+     * - 'Not affected'
+       - The processor is not vulnerable
+     * - 'Vulnerable'
+       - The processor is vulnerable, but no mitigation enabled
+     * - 'Vulnerable: Clear CPU buffers attempted, no microcode'
+       - The processor is vulnerable, but microcode is not updated. The
+         mitigation is enabled on a best effort basis.
+     * - 'Mitigation: Clear CPU buffers'
+       - The processor is vulnerable and the CPU buffer clearing mitigation is
+         enabled.
+
+If the processor is vulnerable then the following information is appended to
+the above information:
+
+  ========================  ===========================================
+  'SMT vulnerable'          SMT is enabled
+  'SMT disabled'            SMT is disabled
+  'SMT Host state unknown'  Kernel runs in a VM, Host SMT state unknown
+  ========================  ===========================================
+
+References
+----------
+.. [#f1] Affected Processors
+   https://www.intel.com/content/www/us/en/developer/topic-technology/software-security-guidance/processors-affected-consolidated-product-cpu-model.html
--- linux-4.4.0.orig/Documentation/hw-vuln/special-register-buffer-data-sampling.rst
+++ linux-4.4.0/Documentation/hw-vuln/special-register-buffer-data-sampling.rst
@@ -0,0 +1,149 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+SRBDS - Special Register Buffer Data Sampling
+=============================================
+
+SRBDS is a hardware vulnerability that allows MDS :doc:`mds` techniques to
+infer values returned from special register accesses.  Special register
+accesses are accesses to off core registers.  According to Intel's evaluation,
+the special register reads that have a security expectation of privacy are
+RDRAND, RDSEED and SGX EGETKEY.
+
+When RDRAND, RDSEED and EGETKEY instructions are used, the data is moved
+to the core through the special register mechanism that is susceptible
+to MDS attacks.
+
+Affected processors
+--------------------
+Core models (desktop, mobile, Xeon-E3) that implement RDRAND and/or RDSEED may
+be affected.
+
+A processor is affected by SRBDS if its Family_Model and stepping is
+in the following list, with the exception of the listed processors
+exporting MDS_NO while Intel TSX is available yet not enabled. The
+latter class of processors are only affected when Intel TSX is enabled
+by software using TSX_CTRL_MSR otherwise they are not affected.
+
+  =============  ============  ========
+  common name    Family_Model  Stepping
+  =============  ============  ========
+  IvyBridge      06_3AH        All
+
+  Haswell        06_3CH        All
+  Haswell_L      06_45H        All
+  Haswell_G      06_46H        All
+
+  Broadwell_G    06_47H        All
+  Broadwell      06_3DH        All
+
+  Skylake_L      06_4EH        All
+  Skylake        06_5EH        All
+
+  Kabylake_L     06_8EH        <= 0xC
+  Kabylake       06_9EH        <= 0xD
+  =============  ============  ========
+
+Related CVEs
+------------
+
+The following CVE entry is related to this SRBDS issue:
+
+    ==============  =====  =====================================
+    CVE-2020-0543   SRBDS  Special Register Buffer Data Sampling
+    ==============  =====  =====================================
+
+Attack scenarios
+----------------
+An unprivileged user can extract values returned from RDRAND and RDSEED
+executed on another core or sibling thread using MDS techniques.
+
+
+Mitigation mechanism
+-------------------
+Intel will release microcode updates that modify the RDRAND, RDSEED, and
+EGETKEY instructions to overwrite secret special register data in the shared
+staging buffer before the secret data can be accessed by another logical
+processor.
+
+During execution of the RDRAND, RDSEED, or EGETKEY instructions, off-core
+accesses from other logical processors will be delayed until the special
+register read is complete and the secret data in the shared staging buffer is
+overwritten.
+
+This has three effects on performance:
+
+#. RDRAND, RDSEED, or EGETKEY instructions have higher latency.
+
+#. Executing RDRAND at the same time on multiple logical processors will be
+   serialized, resulting in an overall reduction in the maximum RDRAND
+   bandwidth.
+
+#. Executing RDRAND, RDSEED or EGETKEY will delay memory accesses from other
+   logical processors that miss their core caches, with an impact similar to
+   legacy locked cache-line-split accesses.
+
+The microcode updates provide an opt-out mechanism (RNGDS_MITG_DIS) to disable
+the mitigation for RDRAND and RDSEED instructions executed outside of Intel
+Software Guard Extensions (Intel SGX) enclaves. On logical processors that
+disable the mitigation using this opt-out mechanism, RDRAND and RDSEED do not
+take longer to execute and do not impact performance of sibling logical
+processors memory accesses. The opt-out mechanism does not affect Intel SGX
+enclaves (including execution of RDRAND or RDSEED inside an enclave, as well
+as EGETKEY execution).
+
+IA32_MCU_OPT_CTRL MSR Definition
+--------------------------------
+Along with the mitigation for this issue, Intel added a new thread-scope
+IA32_MCU_OPT_CTRL MSR, (address 0x123). The presence of this MSR and
+RNGDS_MITG_DIS (bit 0) is enumerated by CPUID.(EAX=07H,ECX=0).EDX[SRBDS_CTRL =
+9]==1. This MSR is introduced through the microcode update.
+
+Setting IA32_MCU_OPT_CTRL[0] (RNGDS_MITG_DIS) to 1 for a logical processor
+disables the mitigation for RDRAND and RDSEED executed outside of an Intel SGX
+enclave on that logical processor. Opting out of the mitigation for a
+particular logical processor does not affect the RDRAND and RDSEED mitigations
+for other logical processors.
+
+Note that inside of an Intel SGX enclave, the mitigation is applied regardless
+of the value of RNGDS_MITG_DS.
+
+Mitigation control on the kernel command line
+---------------------------------------------
+The kernel command line allows control over the SRBDS mitigation at boot time
+with the option "srbds=".  The option for this is:
+
+  ============= =============================================================
+  off           This option disables SRBDS mitigation for RDRAND and RDSEED on
+                affected platforms.
+  ============= =============================================================
+
+SRBDS System Information
+-----------------------
+The Linux kernel provides vulnerability status information through sysfs.  For
+SRBDS this can be accessed by the following sysfs file:
+/sys/devices/system/cpu/vulnerabilities/srbds
+
+The possible values contained in this file are:
+
+ ============================== =============================================
+ Not affected                   Processor not vulnerable
+ Vulnerable                     Processor vulnerable and mitigation disabled
+ Vulnerable: No microcode       Processor vulnerable and microcode is missing
+                                mitigation
+ Mitigation: Microcode          Processor is vulnerable and mitigation is in
+                                effect.
+ Mitigation: TSX disabled       Processor is only vulnerable when TSX is
+                                enabled while this system was booted with TSX
+                                disabled.
+ Unknown: Dependent on
+ hypervisor status              Running on virtual guest processor that is
+                                affected but with no way to know if host
+                                processor is mitigated or vulnerable.
+ ============================== =============================================
+
+SRBDS Default mitigation
+------------------------
+This new microcode serializes processor access during execution of RDRAND,
+RDSEED ensures that the shared buffer is overwritten before it is released for
+reuse.  Use the "srbds=off" kernel command line to disable the mitigation for
+RDRAND and RDSEED.
--- linux-4.4.0.orig/Documentation/hwmon/ina2xx
+++ linux-4.4.0/Documentation/hwmon/ina2xx
@@ -32,7 +32,7 @@
     Datasheet: Publicly available at the Texas Instruments website
                http://www.ti.com/
 
-Author: Lothar Felten <l-felten@ti.com>
+Author: Lothar Felten <lothar.felten@gmail.com>
 
 Description
 -----------
--- linux-4.4.0.orig/Documentation/kernel-parameters.txt
+++ linux-4.4.0/Documentation/kernel-parameters.txt
@@ -193,6 +193,12 @@
 			(e.g. thinkpad_acpi, sony_acpi, etc.) instead
 			of the ACPI video.ko driver.
 
+	acpi_force_32bit_fadt_addr
+			force FADT to use 32 bit addresses rather than the
+			64 bit X_* addresses. Some firmware have broken 64
+			bit addresses for force ACPI ignore these and use
+			the older legacy 32 bit addresss.
+
 	acpica_no_return_repair [HW, ACPI]
 			Disable AML predefined validation mechanism
 			This mechanism can repair the evaluation result to make
@@ -652,7 +658,7 @@
 
 	clearcpuid=BITNUM [X86]
 			Disable CPUID feature X for the kernel. See
-			arch/x86/include/asm/cpufeature.h for the valid bit
+			arch/x86/include/asm/cpufeatures.h for the valid bit
 			numbers. Note the Linux specific bits are not necessarily
 			stable over kernel options, but the vendor specific
 			ones should be.
@@ -750,6 +756,10 @@
 			/proc/<pid>/coredump_filter.
 			See also Documentation/filesystems/proc.txt.
 
+	cpufreq_driver= [X86] Allow only the named cpu frequency scaling driver
+			to register. Example: cpufreq_driver=powernow-k8
+			Format: { none | STRING }
+
 	cpuidle.off=1	[CPU_IDLE]
 			disable the cpuidle sub-system
 
@@ -961,11 +971,6 @@
 			See Documentation/x86/intel_mpx.txt for more
 			information about the feature.
 
-	eagerfpu=	[X86]
-			on	enable eager fpu restore
-			off	disable eager fpu restore
-			auto	selects the default scheme, which automatically
-				enables eagerfpu restore for xsaveopt.
 
 	module.async_probe [KNL]
 			Enable asynchronous probe on this module.
@@ -1249,12 +1254,30 @@
 			Format: off | on
 			default: on
 
+	gather_data_sampling=
+			[X86,INTEL] Control the Gather Data Sampling (GDS)
+			mitigation.
+
+			Gather Data Sampling is a hardware vulnerability which
+			allows unprivileged speculative access to data which was
+			previously stored in vector registers.
+
+			This issue is mitigated by default in updated microcode.
+			The mitigation may have a performance impact but can be
+			disabled.
+
+			off:    Disable GDS mitigation.
+
 	gcov_persist=	[GCOV] When non-zero (default), profiling data for
 			kernel modules is saved and remains accessible via
 			debugfs, even when the module is unloaded/reloaded.
 			When zero, profiling data is discarded and associated
 			debugfs files are removed at module unload time.
 
+	goldfish	[X86] Enable the goldfish android emulator platform.
+			Don't use this when you are not running on the
+			android emulator
+
 	gpt		[EFI] Forces disk with valid GPT signature but
 			invalid Protective MBR to be treated as GPT. If the
 			primary GPT is corrupted, it enables the backup/alternate
@@ -1371,7 +1394,14 @@
 	i8042.nopnp	[HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
 			     controllers
 	i8042.notimeout	[HW] Ignore timeout condition signalled by controller
-	i8042.reset	[HW] Reset the controller during init and cleanup
+	i8042.reset	[HW] Reset the controller during init, cleanup and
+			     suspend-to-ram transitions, only during s2r
+			     transitions, or never reset
+			Format: { 1 | Y | y | 0 | N | n }
+			1, Y, y: always reset controller
+			0, N, n: don't ever reset controller
+			Default: only on s2r transitions on x86; most other
+			architectures force reset to be always executed
 	i8042.unlock	[HW] Unlock (ignore) the keylock
 	i8042.kbdreset  [HW] Reset device connected to KBD port
 
@@ -1759,6 +1789,23 @@
 			KVM MMU at runtime.
 			Default is 0 (off)
 
+	kvm.nx_huge_pages=
+			[KVM] Controls the sw workaround for bug
+			X86_BUG_ITLB_MULTIHIT.
+			force	: Always deploy workaround.
+			off	: Default. Never deploy workaround.
+			auto	: Deploy workaround based on presence of
+				  X86_BUG_ITLB_MULTIHIT.
+
+			If the sw workaround is enabled for the host, guests
+			need not enable it for nested guests.
+
+	kvm.nx_huge_pages_recovery_ratio=
+			[KVM] Controls how many 4KiB pages are periodically zapped
+			back to huge pages.  0 disables the recovery, otherwise if
+			the value is N KVM will zap 1/Nth of the 4KiB pages every
+			minute.  The default is 60.
+
 	kvm-amd.nested=	[KVM,AMD] Allow nested virtualization in KVM/SVM.
 			Default is 1 (enabled)
 
@@ -1787,10 +1834,84 @@
 			(virtualized real and unpaged mode) on capable
 			Intel chips. Default is 1 (enabled)
 
+	kvm-intel.vmentry_l1d_flush=[KVM,Intel] Mitigation for L1 Terminal Fault
+			CVE-2018-3620.
+
+			Valid arguments: never, cond, always
+
+			always: L1D cache flush on every VMENTER.
+			cond:	Flush L1D on VMENTER only when the code between
+				VMEXIT and VMENTER can leak host memory.
+			never:	Disables the mitigation
+
+			Default is cond (do L1 cache flush in specific instances)
+
 	kvm-intel.vpid=	[KVM,Intel] Disable Virtual Processor Identification
 			feature (tagged TLBs) on capable Intel chips.
 			Default is 1 (enabled)
 
+	l1tf=           [X86] Control mitigation of the L1TF vulnerability on
+			      affected CPUs
+
+			The kernel PTE inversion protection is unconditionally
+			enabled and cannot be disabled.
+
+			full
+				Provides all available mitigations for the
+				L1TF vulnerability. Disables SMT and
+				enables all mitigations in the
+				hypervisors, i.e. unconditional L1D flush.
+
+				SMT control and L1D flush control via the
+				sysfs interface is still possible after
+				boot.  Hypervisors will issue a warning
+				when the first VM is started in a
+				potentially insecure configuration,
+				i.e. SMT enabled or L1D flush disabled.
+
+			full,force
+				Same as 'full', but disables SMT and L1D
+				flush runtime control. Implies the
+				'nosmt=force' command line option.
+				(i.e. sysfs control of SMT is disabled.)
+
+			flush
+				Leaves SMT enabled and enables the default
+				hypervisor mitigation, i.e. conditional
+				L1D flush.
+
+				SMT control and L1D flush control via the
+				sysfs interface is still possible after
+				boot.  Hypervisors will issue a warning
+				when the first VM is started in a
+				potentially insecure configuration,
+				i.e. SMT enabled or L1D flush disabled.
+
+			flush,nosmt
+
+				Disables SMT and enables the default
+				hypervisor mitigation.
+
+				SMT control and L1D flush control via the
+				sysfs interface is still possible after
+				boot.  Hypervisors will issue a warning
+				when the first VM is started in a
+				potentially insecure configuration,
+				i.e. SMT enabled or L1D flush disabled.
+
+			flush,nowarn
+				Same as 'flush', but hypervisors will not
+				warn when a VM is started in a potentially
+				insecure configuration.
+
+			off
+				Disables hypervisor mitigations and doesn't
+				emit any warnings.
+
+			Default is 'flush'.
+
+			For details see: Documentation/admin-guide/hw-vuln/l1tf.rst
+
 	l2cr=		[PPC]
 
 	l3cr=		[PPC]
@@ -2029,6 +2150,38 @@
 			Format: <first>,<last>
 			Specifies range of consoles to be captured by the MDA.
 
+	mds=		[X86,INTEL]
+			Control mitigation for the Micro-architectural Data
+			Sampling (MDS) vulnerability.
+
+			Certain CPUs are vulnerable to an exploit against CPU
+			internal buffers which can forward information to a
+			disclosure gadget under certain conditions.
+
+			In vulnerable processors, the speculatively
+			forwarded data can be used in a cache side channel
+			attack, to access data to which the attacker does
+			not have direct access.
+
+			This parameter controls the MDS mitigation. The
+			options are:
+
+			full       - Enable MDS mitigation on vulnerable CPUs
+			full,nosmt - Enable MDS mitigation and disable
+				     SMT on vulnerable CPUs
+			off        - Unconditionally disable MDS mitigation
+
+			On TAA-affected machines, mds=off can be prevented by
+			an active TAA mitigation as both vulnerabilities are
+			mitigated with the same mechanism so in order to disable
+			this mitigation, you need to specify tsx_async_abort=off
+			too.
+
+			Not specifying this option is equivalent to
+			mds=full.
+
+			For details see: Documentation/admin-guide/hw-vuln/mds.rst
+
 	mem=nn[KMG]	[KNL,BOOT] Force usage of a specific amount of memory
 			Amount of memory to be used when the kernel is not able
 			to see the whole system memory or for test.
@@ -2143,6 +2296,58 @@
 			in the "bleeding edge" mini2440 support kernel at
 			http://repo.or.cz/w/linux-2.6/mini2440.git
 
+	mitigations=
+			[X86,PPC,S390] Control optional mitigations for CPU
+			vulnerabilities.  This is a set of curated,
+			arch-independent options, each of which is an
+			aggregation of existing arch-specific options.
+
+			off
+				Disable all optional CPU mitigations.  This
+				improves system performance, but it may also
+				expose users to several CPU vulnerabilities.
+				Equivalent to: gather_data_sampling=off [X86]
+					       kvm.nx_huge_pages=off [X86]
+					       l1tf=off [X86]
+					       mds=off [X86]
+					       mmio_stale_data=off [X86]
+					       no_entry_flush [PPC]
+					       no_uaccess_flush [PPC]
+					       nobp=0 [S390]
+					       nopti [X86,PPC]
+					       nospectre_v1 [PPC]
+					       nospectre_v1 [X86]
+					       nospectre_v2 [X86,PPC,S390,ARM64]
+					       spec_store_bypass_disable=off [X86,PPC]
+					       spectre_bhi=off [X86]
+					       spectre_v2_user=off [X86]
+					       ssbd=force-off [ARM64]
+					       tsx_async_abort=off [X86]
+					       vmscape=off [X86]
+
+
+				Exceptions:
+					       This does not have any effect on
+					       kvm.nx_huge_pages when
+					       kvm.nx_huge_pages=force.
+
+			auto (default)
+				Mitigate all CPU vulnerabilities, but leave SMT
+				enabled, even if it's vulnerable.  This is for
+				users who don't want to be surprised by SMT
+				getting disabled across kernel upgrades, or who
+				have other ways of avoiding SMT-based attacks.
+				Equivalent to: (default behavior)
+
+			auto,nosmt
+				Mitigate all CPU vulnerabilities, disabling SMT
+				if needed.  This is for users who always want to
+				be fully mitigated, even if it means losing SMT.
+				Equivalent to: l1tf=flush,nosmt [X86]
+					       mds=full,nosmt [X86]
+					       tsx_async_abort=full,nosmt [X86]
+					       mmio_stale_data=full,nosmt [X86]
+
 	mminit_loglevel=
 			[KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this
 			parameter allows control of the logging verbosity for
@@ -2151,6 +2356,40 @@
 			log everything. Information is printed at KERN_DEBUG
 			so loglevel=8 may also need to be specified.
 
+	mmio_stale_data=
+			[X86,INTEL] Control mitigation for the Processor
+			MMIO Stale Data vulnerabilities.
+
+			Processor MMIO Stale Data is a class of
+			vulnerabilities that may expose data after an MMIO
+			operation. Exposed data could originate or end in
+			the same CPU buffers as affected by MDS and TAA.
+			Therefore, similar to MDS and TAA, the mitigation
+			is to clear the affected CPU buffers.
+
+			This parameter controls the mitigation. The
+			options are:
+
+			full       - Enable mitigation on vulnerable CPUs
+
+			full,nosmt - Enable mitigation and disable SMT on
+				     vulnerable CPUs.
+
+			off        - Unconditionally disable mitigation
+
+			On MDS or TAA affected machines,
+			mmio_stale_data=off can be prevented by an active
+			MDS or TAA mitigation as these vulnerabilities are
+			mitigated with the same mechanism so in order to
+			disable this mitigation, you need to specify
+			mds=off and tsx_async_abort=off too.
+
+			Not specifying this option is equivalent to
+			mmio_stale_data=full.
+
+			For details see:
+			Documentation/admin-guide/hw-vuln/processor_mmio_stale_data.rst
+
 	module.sig_enforce
 			[KNL] When CONFIG_MODULE_SIG is set, this means that
 			modules without (valid) signatures will fail to load.
@@ -2391,6 +2630,9 @@
 
 	noalign		[KNL,ARM]
 
+	noaltinstr	[S390] Disables alternative instructions patching
+			(CPU alternatives feature).
+
 	noapic		[SMP,APIC] Tells the kernel to not make use of any
 			IOAPICs that may be present in the system.
 
@@ -2411,6 +2653,8 @@
 
 	noefi		Disable EFI runtime services support.
 
+	no_entry_flush	[PPC] Don't flush the L1-D cache when entering the kernel.
+
 	noexec		[IA-64]
 
 	noexec		[X86]
@@ -2418,6 +2662,16 @@
 			noexec=on: enable non-executable mappings (default)
 			noexec=off: disable non-executable mappings
 
+	noibrs		[X86]
+			Don't use indirect branch restricted speculation (IBRS)
+			feature when running in secure environment,
+			to avoid performance overhead.
+
+	noibpb		[X86]
+			Don't use indirect branch prediction barrier (IBPB)
+			feature when running in secure environment,
+			to avoid performance overhead.
+
 	nosmap		[X86]
 			Disable SMAP (Supervisor Mode Access Prevention)
 			even if it is supported by processor.
@@ -2441,6 +2695,25 @@
 
 	nohugeiomap	[KNL,x86] Disable kernel huge I/O mappings.
 
+	nosmt		[KNL,x86] Disable symmetric multithreading (SMT).
+			nosmt=force: Force disable SMT, cannot be undone
+				     via the sysfs control file.
+
+	nospectre_v1	[X86,PPC] Disable mitigations for Spectre Variant 1
+			(bounds check bypass). With this option data leaks are
+			possible in the system.
+
+	nospectre_v2	[X86,PPC_FSL_BOOK3E] Disable all mitigations for the Spectre variant 2
+			(indirect branch prediction) vulnerability. System may
+			allow data leaks with this option, which is equivalent
+			to spectre_v2=off.
+
+	nospec_store_bypass_disable
+			[HW] Disable all mitigations for the Speculative Store Bypass vulnerability
+
+	no_uaccess_flush
+			[PPC] Don't flush the L1-D cache after accessing user data.
+
 	noxsave		[BUGS=X86] Disables x86 extended register state save
 			and restore using xsave. The kernel will fallback to
 			enabling legacy floating-point and sse state.
@@ -2508,6 +2781,8 @@
 
 	nointroute	[IA-64]
 
+	noinvpcid	[X86] Disable the INVPCID cpu feature.
+
 	nojitter	[IA-64] Disables jitter checking for ITC timers.
 
 	no-kvmclock	[X86,KVM] Disable paravirtualized KVM clock driver
@@ -2542,11 +2817,11 @@
 	nopat		[X86] Disable PAT (page attribute table extension of
 			pagetables) support.
 
+	nopcid		[X86-64] Disable the PCID cpu feature.
+
 	norandmaps	Don't use address space randomization.  Equivalent to
 			echo 0 > /proc/sys/kernel/randomize_va_space
 
-	noreplace-paravirt	[X86,IA-64,PV_OPS] Don't patch paravirt_ops
-
 	noreplace-smp	[X86-32,SMP] Don't replace SMP instructions
 			with UP alternatives
 
@@ -2750,6 +3025,12 @@
 		nomsi		[MSI] If the PCI_MSI kernel config parameter is
 				enabled, this kernel boot option can be used to
 				disable the use of MSI interrupts system-wide.
+		clearmsi	[X86] Clears MSI/MSI-X enable bits early in boot
+				time in order to avoid issues like adapters
+				screaming irqs and preventing boot progress.
+				Also, it enforces the PCI Local Bus spec
+				rule that those bits should be 0 in system reset
+				events (useful for kexec/kdump cases).
 		noioapicquirk	[APIC] Disable all boot interrupt quirks.
 				Safety option to keep boot IRQs enabled. This
 				should never be necessary.
@@ -3039,6 +3320,21 @@
 	pt.		[PARIDE]
 			See Documentation/blockdev/paride.txt.
 
+	pti=		[X86_64] Control Page Table Isolation of user and
+			kernel address spaces.  Disabling this feature
+			removes hardening, but improves performance of
+			system calls and interrupts.
+
+			on   - unconditionally enable
+			off  - unconditionally disable
+			auto - kernel detects whether your CPU model is
+			       vulnerable to issues that PTI mitigates
+
+			Not specifying this option is equivalent to pti=auto.
+
+	nopti		[X86_64]
+			Equivalent to pti=off
+
 	pty.legacy_count=
 			[KNL] Number of legacy pty's. Overwrites compiled-in
 			default number.
@@ -3328,6 +3624,13 @@
 			Run specified binary instead of /init from the ramdisk,
 			used for early userspace startup. See initrd.
 
+	rdrand=		[X86]
+			force - Override the decision by the kernel to hide the
+				advertisement of RDRAND support (this affects
+				certain AMD processors because of buggy BIOS
+				support, specifically around the suspend/resume
+				path).
+
 	reboot=		[KNL]
 			Format (x86 or x86_64):
 				[w[arm] | c[old] | h[ard] | s[oft] | g[pio]] \
@@ -3392,6 +3695,18 @@
 
 	retain_initrd	[RAM] Keep initrd memory after extraction
 
+	retbleed=	[X86] Control mitigation of RETBleed (Arbitrary
+			Speculative Code Execution with Return Instructions)
+			vulnerability.
+
+			off         - unconditionally disable
+			auto        - automatically select a migitation
+
+			Selecting 'auto' will choose a mitigation method at run
+			time according to the CPU.
+
+			Not specifying this option is equivalent to retbleed=auto.
+
 	rfkill.default_state=
 		0	"airplane mode".  All wifi, bluetooth, wimax, gps, fm,
 			etc. communication is blocked by default.
@@ -3564,11 +3879,172 @@
 	sonypi.*=	[HW] Sony Programmable I/O Control Device driver
 			See Documentation/laptops/sonypi.txt
 
+	spectre_bhi=	[X86] Control mitigation of Branch History Injection
+			(BHI) vulnerability.  This setting affects the
+			deployment of the HW BHI control and the SW BHB
+			clearing sequence.
+
+			on   - (default) Enable the HW or SW mitigation
+			       as needed.
+			off  - Disable the mitigation.
+			auto - Enable the HW mitigation if needed, but
+			       *don't* enable the SW mitigation except
+			       for KVM.  The system may be vulnerable.
+
+	spectre_v2=	[X86] Control mitigation of Spectre variant 2
+			(indirect branch speculation) vulnerability.
+			The default operation protects the kernel from
+			user space attacks.
+
+			on   - unconditionally enable, implies
+			       spectre_v2_user=on
+			off  - unconditionally disable, implies
+			       spectre_v2_user=off
+			auto - kernel detects whether your CPU model is
+			       vulnerable
+
+			Selecting 'on' will, and 'auto' may, choose a
+			mitigation method at run time according to the
+			CPU, the available microcode, the setting of the
+			CONFIG_RETPOLINE configuration option, and the
+			compiler with which the kernel was built.
+
+			Selecting 'on' will also enable the mitigation
+			against user space to user space task attacks.
+
+			Selecting 'off' will disable both the kernel and
+			the user space protections.
+
+			Specific mitigations can also be selected manually:
+
+			retpoline	  - replace indirect branches
+			retpoline,generic - Retpolines
+			retpoline,lfence  - LFENCE; indirect branch
+			retpoline,amd     - alias for retpoline,lfence
+			eibrs		  - enhanced IBRS
+			eibrs,retpoline   - enhanced IBRS + Retpolines
+			eibrs,lfence      - enhanced IBRS + LFENCE
+			ibrs		  - use IBRS to protect kernel
+
+			Not specifying this option is equivalent to
+			spectre_v2=auto.
+
+	spectre_v2_user=
+			[X86] Control mitigation of Spectre variant 2
+		        (indirect branch speculation) vulnerability between
+		        user space tasks
+
+			on	- Unconditionally enable mitigations. Is
+				  enforced by spectre_v2=on
+
+			off     - Unconditionally disable mitigations. Is
+				  enforced by spectre_v2=off
+
+			prctl   - Indirect branch speculation is enabled,
+				  but mitigation can be enabled via prctl
+				  per thread.  The mitigation control state
+				  is inherited on fork.
+
+			prctl,ibpb
+				- Like "prctl" above, but only STIBP is
+				  controlled per thread. IBPB is issued
+				  always when switching between different user
+				  space processes.
+
+			seccomp
+				- Same as "prctl" above, but all seccomp
+				  threads will enable the mitigation unless
+				  they explicitly opt out.
+
+			seccomp,ibpb
+				- Like "seccomp" above, but only STIBP is
+				  controlled per thread. IBPB is issued
+				  always when switching between different
+				  user space processes.
+
+			auto    - Kernel selects the mitigation depending on
+				  the available CPU features and vulnerability.
+
+			Default mitigation:
+			If CONFIG_SECCOMP=y then "seccomp", otherwise "prctl"
+
+			Not specifying this option is equivalent to
+			spectre_v2_user=auto.
+
+	spec_store_bypass_disable=
+			[HW] Control Speculative Store Bypass (SSB) Disable mitigation
+			(Speculative Store Bypass vulnerability)
+
+			Certain CPUs are vulnerable to an exploit against a
+			a common industry wide performance optimization known
+			as "Speculative Store Bypass" in which recent stores
+			to the same memory location may not be observed by
+			later loads during speculative execution. The idea
+			is that such stores are unlikely and that they can
+			be detected prior to instruction retirement at the
+			end of a particular speculation execution window.
+
+			In vulnerable processors, the speculatively forwarded
+			store can be used in a cache side channel attack, for
+			example to read memory to which the attacker does not
+			directly have access (e.g. inside sandboxed code).
+
+			This parameter controls whether the Speculative Store
+			Bypass optimization is used.
+
+			on      - Unconditionally disable Speculative Store Bypass
+			off     - Unconditionally enable Speculative Store Bypass
+			auto    - Kernel detects whether the CPU model contains an
+				  implementation of Speculative Store Bypass and
+				  picks the most appropriate mitigation. If the
+				  CPU is not vulnerable, "off" is selected. If the
+				  CPU is vulnerable the default mitigation is
+				  architecture and Kconfig dependent. See below.
+			prctl   - Control Speculative Store Bypass per thread
+				  via prctl. Speculative Store Bypass is enabled
+				  for a process by default. The state of the control
+				  is inherited on fork.
+			seccomp - Same as "prctl" above, but all seccomp threads
+				  will disable SSB unless they explicitly opt out.
+
+			Not specifying this option is equivalent to
+			spec_store_bypass_disable=auto.
+
+			Default mitigations:
+			X86:	If CONFIG_SECCOMP=y "seccomp", otherwise "prctl"
+
 	spia_io_base=	[HW,MTD]
 	spia_fio_base=
 	spia_pedr=
 	spia_peddr=
 
+	srbds=		[X86,INTEL]
+			Control the Special Register Buffer Data Sampling
+			(SRBDS) mitigation.
+
+			Certain CPUs are vulnerable to an MDS-like
+			exploit which can leak bits from the random
+			number generator.
+
+			By default, this issue is mitigated by
+			microcode.  However, the microcode fix can cause
+			the RDRAND and RDSEED instructions to become
+			much slower.  Among other effects, this will
+			result in reduced throughput from /dev/urandom.
+
+			The microcode mitigation can be disabled with
+			the following option:
+
+			off:    Disable mitigation and remove
+				performance impact to RDRAND and RDSEED
+
+	stack_guard_gap=	[MM]
+			override the default stack gap protection. The value
+			is in page units and it defines how many pages prior
+			to (for stacks growing down) resp. after (for stacks
+			growing up) the main stack are reserved for no other
+			mapping. Default value is 256 pages.
+
 	stacktrace	[FTRACE]
 			Enabled the stack tracer on boot up.
 
@@ -3834,6 +4310,76 @@
 			platforms where RDTSC is slow and this accounting
 			can add overhead.
 
+	tsx=		[X86] Control Transactional Synchronization
+			Extensions (TSX) feature in Intel processors that
+			support TSX control.
+
+			This parameter controls the TSX feature. The options are:
+
+			on	- Enable TSX on the system. Although there are
+				mitigations for all known security vulnerabilities,
+				TSX has been known to be an accelerator for
+				several previous speculation-related CVEs, and
+				so there may be unknown	security risks associated
+				with leaving it enabled.
+
+			off	- Disable TSX on the system. (Note that this
+				option takes effect only on newer CPUs which are
+				not vulnerable to MDS, i.e., have
+				MSR_IA32_ARCH_CAPABILITIES.MDS_NO=1 and which get
+				the new IA32_TSX_CTRL MSR through a microcode
+				update. This new MSR allows for the reliable
+				deactivation of the TSX functionality.)
+
+			auto	- Disable TSX if X86_BUG_TAA is present,
+				  otherwise enable TSX on the system.
+
+			Not specifying this option is equivalent to tsx=off.
+
+			See Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
+			for more details.
+
+	tsx_async_abort= [X86,INTEL] Control mitigation for the TSX Async
+			Abort (TAA) vulnerability.
+
+			Similar to Micro-architectural Data Sampling (MDS)
+			certain CPUs that support Transactional
+			Synchronization Extensions (TSX) are vulnerable to an
+			exploit against CPU internal buffers which can forward
+			information to a disclosure gadget under certain
+			conditions.
+
+			In vulnerable processors, the speculatively forwarded
+			data can be used in a cache side channel attack, to
+			access data to which the attacker does not have direct
+			access.
+
+			This parameter controls the TAA mitigation.  The
+			options are:
+
+			full       - Enable TAA mitigation on vulnerable CPUs
+				     if TSX is enabled.
+
+			full,nosmt - Enable TAA mitigation and disable SMT on
+				     vulnerable CPUs. If TSX is disabled, SMT
+				     is not disabled because CPU is not
+				     vulnerable to cross-thread TAA attacks.
+			off        - Unconditionally disable TAA mitigation
+
+			On MDS-affected machines, tsx_async_abort=off can be
+			prevented by an active MDS mitigation as both vulnerabilities
+			are mitigated with the same mechanism so in order to disable
+			this mitigation, you need to specify mds=off too.
+
+			Not specifying this option is equivalent to
+			tsx_async_abort=full.  On CPUs which are MDS affected
+			and deploy MDS mitigation, TAA mitigation is not
+			required and doesn't provide any additional
+			mitigation.
+
+			For details see:
+			Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
+
 	turbografx.map[2|3]=	[HW,JOY]
 			TurboGraFX parallel port interface
 			Format:
@@ -3928,6 +4474,8 @@
 					sector if the number is odd);
 				i = IGNORE_DEVICE (don't bind to this
 					device);
+				j = NO_REPORT_LUNS (don't use report luns
+					command, uas only);
 				l = NOT_LOCKABLE (don't try to lock and
 					unlock ejectable media);
 				m = MAX_SECTORS_64 (don't transfer more
@@ -4036,6 +4584,16 @@
 	vmpanic=	[KNL,S390] Perform z/VM CP command after kernel panic.
 			Format: <command>
 
+	vmscape=	[X86] Controls mitigation for VMscape attacks.
+			VMscape attacks can leak information from a userspace
+			hypervisor to a guest via speculative side-channels.
+
+			off		- disable the mitigation
+			ibpb		- use Indirect Branch Prediction Barrier (IBPB)
+					  mitigation (default)
+			force		- force vulnerability detection even on
+					  unaffected processors
+
 	vmpoff=		[KNL,S390] Perform z/VM CP command after power off.
 			Format: <command>
 
@@ -4175,6 +4733,14 @@
 			Disables the PV optimizations forcing the HVM guest to
 			run as generic HVM guest with no PV drivers.
 
+	xen.event_eoi_delay=	[XEN]
+			How long to delay EOI handling in case of event
+			storms (jiffies). Default is 10.
+
+	xen.event_loop_timeout=	[XEN]
+			After which time (jiffies) the event handling loop
+			should start to delay EOI handling. Default is 2.
+
 	xirc2ps_cs=	[NET,PCMCIA]
 			Format:
 			<irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]]
--- linux-4.4.0.orig/Documentation/memory-barriers.txt
+++ linux-4.4.0/Documentation/memory-barriers.txt
@@ -1655,17 +1655,18 @@
 SMP memory barriers are reduced to compiler barriers on uniprocessor compiled
 systems because it is assumed that a CPU will appear to be self-consistent,
 and will order overlapping accesses correctly with respect to itself.
+However, see the subsection on "Virtual Machine Guests" below.
 
 [!] Note that SMP memory barriers _must_ be used to control the ordering of
 references to shared memory on SMP systems, though the use of locking instead
 is sufficient.
 
 Mandatory barriers should not be used to control SMP effects, since mandatory
-barriers unnecessarily impose overhead on UP systems. They may, however, be
-used to control MMIO effects on accesses through relaxed memory I/O windows.
-These are required even on non-SMP systems as they affect the order in which
-memory operations appear to a device by prohibiting both the compiler and the
-CPU from reordering them.
+barriers impose unnecessary overhead on both SMP and UP systems. They may,
+however, be used to control MMIO effects on accesses through relaxed memory I/O
+windows.  These barriers are required even on non-SMP systems as they affect
+the order in which memory operations appear to a device by prohibiting both the
+compiler and the CPU from reordering them.
 
 
 There are some more advanced barrier functions:
@@ -2948,6 +2949,23 @@
 
 See the subsection on "Cache Coherency" above.
 
+VIRTUAL MACHINE GUESTS
+-------------------
+
+Guests running within virtual machines might be affected by SMP effects even if
+the guest itself is compiled without SMP support.  This is an artifact of
+interfacing with an SMP host while running an UP kernel.  Using mandatory
+barriers for this use-case would be possible but is often suboptimal.
+
+To handle this case optimally, low-level virt_mb() etc macros are available.
+These have the same effect as smp_mb() etc when SMP is enabled, but generate
+identical code for SMP and non-SMP systems. For example, virtual machine guests
+should use virt_mb() rather than smp_mb() when synchronizing against a
+(possibly SMP) host.
+
+These are equivalent to smp_mb() etc counterparts in all other respects,
+in particular, they do not control MMIO effects: to control
+MMIO effects, use mandatory barriers.
 
 ============
 EXAMPLE USES
--- linux-4.4.0.orig/Documentation/memory-hotplug.txt
+++ linux-4.4.0/Documentation/memory-hotplug.txt
@@ -256,10 +256,27 @@
 
 5.2. How to online memory
 ------------
-Even if the memory is hot-added, it is not at ready-to-use state.
-For using newly added memory, you have to "online" the memory block.
+When the memory is hot-added, the kernel decides whether or not to "online"
+it according to the policy which can be read from "auto_online_blocks" file:
 
-For onlining, you have to write "online" to the memory block's state file as:
+% cat /sys/devices/system/memory/auto_online_blocks
+
+The default is "offline" which means the newly added memory is not in a
+ready-to-use state and you have to "online" the newly added memory blocks
+manually. Automatic onlining can be requested by writing "online" to
+"auto_online_blocks" file:
+
+% echo online > /sys/devices/system/memory/auto_online_blocks
+
+This sets a global policy and impacts all memory blocks that will subsequently
+be hotplugged. Currently offline blocks keep their state. It is possible, under
+certain circumstances, that some memory blocks will be added but will fail to
+online. User space tools can check their "state" files
+(/sys/devices/system/memory/memoryXXX/state) and try to online them manually.
+
+If the automatic onlining wasn't requested, failed, or some memory block was
+offlined it is possible to change the individual block's state by writing to the
+"state" file:
 
 % echo online > /sys/devices/system/memory/memoryXXX/state
 
--- linux-4.4.0.orig/Documentation/misc-devices/mei/mei-amt-version.c
+++ linux-4.4.0/Documentation/misc-devices/mei/mei-amt-version.c
@@ -370,7 +370,7 @@
 			unsigned int expected_sz)
 {
 	uint32_t in_buf_sz;
-	uint32_t out_buf_sz;
+	ssize_t out_buf_sz;
 	ssize_t written;
 	uint32_t status;
 	struct amt_host_if_resp_header *msg_hdr;
--- linux-4.4.0.orig/Documentation/module-signing.txt
+++ linux-4.4.0/Documentation/module-signing.txt
@@ -271,3 +271,9 @@
 the private key to sign modules and compromise the operating system.  The
 private key must be either destroyed or moved to a secure location and not kept
 in the root node of the kernel source tree.
+
+If you use the same private key to sign modules for multiple kernel
+configurations, you must ensure that the module version information is
+sufficient to prevent loading a module into a different kernel.  Either
+set CONFIG_MODVERSIONS=y or ensure that each configuration has a different
+kernel release string by changing EXTRAVERSION or CONFIG_LOCALVERSION.
--- linux-4.4.0.orig/Documentation/networking/00-INDEX
+++ linux-4.4.0/Documentation/networking/00-INDEX
@@ -72,6 +72,8 @@
 	- The DNS resolver module allows kernel servies to make DNS queries.
 driver.txt
 	- Softnet driver issues.
+ena.txt
+	- info on Amazon's Elastic Network Adapter (ENA)
 e100.txt
 	- info on Intel's EtherExpress PRO/100 line of 10/100 boards
 e1000.txt
--- linux-4.4.0.orig/Documentation/networking/ip-sysctl.txt
+++ linux-4.4.0/Documentation/networking/ip-sysctl.txt
@@ -112,14 +112,11 @@
 
 IP Fragmentation:
 
-ipfrag_high_thresh - INTEGER
-	Maximum memory used to reassemble IP fragments. When
-	ipfrag_high_thresh bytes of memory is allocated for this purpose,
-	the fragment handler will toss packets until ipfrag_low_thresh
-	is reached. This also serves as a maximum limit to namespaces
-	different from the initial one.
+ipfrag_high_thresh - LONG INTEGER
+	Maximum memory used to reassemble IP fragments.
 
-ipfrag_low_thresh - INTEGER
+ipfrag_low_thresh - LONG INTEGER
+	(Obsolete since linux-4.4.174, backported from linux-4.17)
 	Maximum memory used to reassemble IP fragments before the kernel
 	begins to remove incomplete fragment queues to free up resources.
 	The kernel still accepts new fragments for defragmentation.
@@ -223,6 +220,14 @@
 	Path MTU discovery (MTU probing).  If MTU probing is enabled,
 	this is the initial MSS used by the connection.
 
+tcp_min_snd_mss - INTEGER
+	TCP SYN and SYNACK messages usually advertise an ADVMSS option,
+	as described in RFC 1122 and RFC 6691.
+	If this ADVMSS option is smaller than tcp_min_snd_mss,
+	it is silently capped to tcp_min_snd_mss.
+
+	Default : 48 (at least 8 bytes of payload per segment)
+
 tcp_congestion_control - STRING
 	Set the congestion control algorithm to be used for new
 	connections. The algorithm "reno" is always available, but
@@ -390,6 +395,7 @@
 	minimum RTT when it is moved to a longer path (e.g., due to traffic
 	engineering). A longer window makes the filter more resistant to RTT
 	inflations such as transient congestion. The unit is seconds.
+	Possible values: 0 - 86400 (1 day)
 	Default: 300
 
 tcp_moderate_rcvbuf - BOOLEAN
@@ -862,12 +868,14 @@
 icmp_msgs_per_sec - INTEGER
 	Limit maximal number of ICMP packets sent per second from this host.
 	Only messages whose type matches icmp_ratemask (see below) are
-	controlled by this limit.
+	controlled by this limit. For security reasons, the precise count
+	of messages per second is randomized.
 	Default: 1000
 
 icmp_msgs_burst - INTEGER
 	icmp_msgs_per_sec controls number of ICMP packets sent per second,
 	while icmp_msgs_burst controls the burst size of these packets.
+	For security reasons, the precise burst size is randomized.
 	Default: 50
 
 icmp_ratemask - INTEGER
--- linux-4.4.0.orig/Documentation/networking/l2tp.txt
+++ linux-4.4.0/Documentation/networking/l2tp.txt
@@ -177,10 +177,10 @@
 
 The following debug mask bits are available:
 
-PPPOL2TP_MSG_DEBUG    verbose debug (if compiled in)
-PPPOL2TP_MSG_CONTROL  userspace - kernel interface
-PPPOL2TP_MSG_SEQ      sequence numbers handling
-PPPOL2TP_MSG_DATA     data packets
+L2TP_MSG_DEBUG    verbose debug (if compiled in)
+L2TP_MSG_CONTROL  userspace - kernel interface
+L2TP_MSG_SEQ      sequence numbers handling
+L2TP_MSG_DATA     data packets
 
 If enabled, files under a l2tp debugfs directory can be used to dump
 kernel state about L2TP tunnels and sessions. To access it, the
--- linux-4.4.0.orig/Documentation/networking/netdev-FAQ.txt
+++ linux-4.4.0/Documentation/networking/netdev-FAQ.txt
@@ -168,6 +168,15 @@
    dash marker line as described in Documentation/SubmittingPatches to
    temporarily embed that information into the patch that you send.
 
+Q: Are all networking bug fixes backported to all stable releases?
+
+A: Due to capacity, Dave could only take care of the backports for the last
+   2 stable releases. For earlier stable releases, each stable branch maintainer
+   is supposed to take care of them. If you find any patch is missing from an
+   earlier stable branch, please notify stable@vger.kernel.org with either a
+   commit ID or a formal patch backported, and CC Dave and other relevant
+   networking developers.
+
 Q: Someone said that the comment style and coding convention is different
    for the networking content.  Is this true?
 
--- linux-4.4.0.orig/Documentation/networking/netfilter-sysctl.txt
+++ linux-4.4.0/Documentation/networking/netfilter-sysctl.txt
@@ -0,0 +1,10 @@
+/proc/sys/net/netfilter/* Variables:
+
+nf_log_all_netns - BOOLEAN
+	0 - disabled (default)
+	not 0 - enabled
+
+	By default, only init_net namespace can log packets into kernel log
+	with LOG target; this aims to prevent containers from flooding host
+	kernel log. If enabled, this target also works in other network
+	namespaces. This variable is only accessible from init_net.
--- linux-4.4.0.orig/Documentation/pinctrl.txt
+++ linux-4.4.0/Documentation/pinctrl.txt
@@ -831,7 +831,7 @@
 range dealing with pin config and pin multiplexing get placed into a
 different memory range and a separate section of the data sheet.
 
-A flag "strict" in struct pinctrl_desc is available to check and deny
+A flag "strict" in struct pinmux_ops is available to check and deny
 simultaneous access to the same pin from GPIO and pin multiplexing
 consumers on hardware of this type. The pinctrl driver should set this flag
 accordingly.
--- linux-4.4.0.orig/Documentation/power/runtime_pm.txt
+++ linux-4.4.0/Documentation/power/runtime_pm.txt
@@ -371,6 +371,12 @@
     - increment the device's usage counter, run pm_runtime_resume(dev) and
       return its result
 
+  int pm_runtime_get_if_in_use(struct device *dev);
+    - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
+      runtime PM status is RPM_ACTIVE and the runtime PM usage counter is
+      nonzero, increment the counter and return 1; otherwise return 0 without
+      changing the counter
+
   void pm_runtime_put_noidle(struct device *dev);
     - decrement the device's usage counter
 
--- linux-4.4.0.orig/Documentation/powerpc/cxl.txt
+++ linux-4.4.0/Documentation/powerpc/cxl.txt
@@ -116,6 +116,8 @@
 User API
 ========
 
+1. AFU character devices
+
     For AFUs operating in AFU directed mode, two character device
     files will be created. /dev/cxl/afu0.0m will correspond to a
     master context and /dev/cxl/afu0.0s will correspond to a slave
@@ -362,6 +364,59 @@
         reserved fields:
             For future extensions and padding
 
+
+2. Card character device (powerVM guest only)
+
+    In a powerVM guest, an extra character device is created for the
+    card. The device is only used to write (flash) a new image on the
+    FPGA accelerator. Once the image is written and verified, the
+    device tree is updated and the card is reset to reload the updated
+    image.
+
+open
+----
+
+    Opens the device and allocates a file descriptor to be used with
+    the rest of the API. The device can only be opened once.
+
+ioctl
+-----
+
+CXL_IOCTL_DOWNLOAD_IMAGE:
+CXL_IOCTL_VALIDATE_IMAGE:
+    Starts and controls flashing a new FPGA image. Partial
+    reconfiguration is not supported (yet), so the image must contain
+    a copy of the PSL and AFU(s). Since an image can be quite large,
+    the caller may have to iterate, splitting the image in smaller
+    chunks.
+
+    Takes a pointer to a struct cxl_adapter_image:
+        struct cxl_adapter_image {
+            __u64 flags;
+            __u64 data;
+            __u64 len_data;
+            __u64 len_image;
+            __u64 reserved1;
+            __u64 reserved2;
+            __u64 reserved3;
+            __u64 reserved4;
+        };
+
+    flags:
+        These flags indicate which optional fields are present in
+        this struct. Currently all fields are mandatory.
+
+    data:
+        Pointer to a buffer with part of the image to write to the
+        card.
+
+    len_data:
+        Size of the buffer pointed to by data.
+
+    len_image:
+        Full size of the image.
+
+
 Sysfs Class
 ===========
 
--- linux-4.4.0.orig/Documentation/powerpc/transactional_memory.txt
+++ linux-4.4.0/Documentation/powerpc/transactional_memory.txt
@@ -167,6 +167,8 @@
 For signals taken in non-TM or suspended mode, we use the
 normal/non-checkpointed stack pointer.
 
+Any transaction initiated inside a sighandler and suspended on return
+from the sighandler to the kernel will get reclaimed and discarded.
 
 Failure cause codes used by kernel
 ==================================
--- linux-4.4.0.orig/Documentation/prctl/seccomp_filter.txt
+++ linux-4.4.0/Documentation/prctl/seccomp_filter.txt
@@ -138,6 +138,15 @@
 	allow use of ptrace, even of other sandboxed processes, without
 	extreme care; ptracers can use this mechanism to escape.)
 
+``SECCOMP_RET_LOG``:
+	Results in the system call being executed after it is logged. This
+	should be used by application developers to learn which syscalls their
+	application needs without having to iterate through multiple test and
+	development cycles to build the list.
+
+	This action will only be logged if "log" is present in the
+	actions_logged sysctl string.
+
 SECCOMP_RET_ALLOW:
 	Results in the system call being executed.
 
@@ -166,7 +175,41 @@
 and a more generic example of a higher level macro interface for BPF
 program generation.
 
+Sysctls
+=======
+
+Seccomp's sysctl files can be found in the ``/proc/sys/kernel/seccomp/``
+directory. Here's a description of each file in that directory:
 
+``actions_avail``:
+	A read-only ordered list of seccomp return values (refer to the
+	``SECCOMP_RET_*`` macros above) in string form. The ordering, from
+	left-to-right, is the least permissive return value to the most
+	permissive return value.
+
+	The list represents the set of seccomp return values supported
+	by the kernel. A userspace program may use this list to
+	determine if the actions found in the ``seccomp.h``, when the
+	program was built, differs from the set of actions actually
+	supported in the current running kernel.
+
+``actions_logged``:
+	A read-write ordered list of seccomp return values (refer to the
+	``SECCOMP_RET_*`` macros above) that are allowed to be logged. Writes
+	to the file do not need to be in ordered form but reads from the file
+	will be ordered in the same way as the actions_avail sysctl.
+
+	It is important to note that the value of ``actions_logged`` does not
+	prevent certain actions from being logged when the audit subsystem is
+	configured to audit a task. If the action is not found in
+	``actions_logged`` list, the final decision on whether to audit the
+	action for that task is ultimately left up to the audit subsystem to
+	decide for all seccomp return values other than ``SECCOMP_RET_ALLOW``.
+
+	The ``allow`` string is not accepted in the ``actions_logged`` sysctl
+	as it is not possible to log ``SECCOMP_RET_ALLOW`` actions. Attempting
+	to write ``allow`` to the sysctl will result in an EINVAL being
+	returned.
 
 Adding architecture support
 -----------------------
--- linux-4.4.0.orig/Documentation/printk-formats.txt
+++ linux-4.4.0/Documentation/printk-formats.txt
@@ -273,11 +273,10 @@
 
 	%pC	pll1
 	%pCn	pll1
-	%pCr	1560000000
 
 	For printing struct clk structures. '%pC' and '%pCn' print the name
 	(Common Clock Framework) or address (legacy clock framework) of the
-	structure; '%pCr' prints the current clock rate.
+	structure.
 
 	Passed by reference.
 
--- linux-4.4.0.orig/Documentation/ptp/testptp.c
+++ linux-4.4.0/Documentation/ptp/testptp.c
@@ -277,13 +277,15 @@
 			       "  %d external time stamp channels\n"
 			       "  %d programmable periodic signals\n"
 			       "  %d pulse per second\n"
-			       "  %d programmable pins\n",
+			       "  %d programmable pins\n"
+			       "  %d cross timestamping\n",
 			       caps.max_adj,
 			       caps.n_alarm,
 			       caps.n_ext_ts,
 			       caps.n_per_out,
 			       caps.pps,
-			       caps.n_pins);
+			       caps.n_pins,
+			       caps.cross_timestamping);
 		}
 	}
 
--- linux-4.4.0.orig/Documentation/rbtree.txt
+++ linux-4.4.0/Documentation/rbtree.txt
@@ -190,6 +190,39 @@
   for (node = rb_first(&mytree); node; node = rb_next(node))
 	printk("key=%s\n", rb_entry(node, struct mytype, node)->keystring);
 
+Cached rbtrees
+--------------
+
+Computing the leftmost (smallest) node is quite a common task for binary
+search trees, such as for traversals or users relying on a the particular
+order for their own logic. To this end, users can use 'struct rb_root_cached'
+to optimize O(logN) rb_first() calls to a simple pointer fetch avoiding
+potentially expensive tree iterations. This is done at negligible runtime
+overhead for maintanence; albeit larger memory footprint.
+
+Similar to the rb_root structure, cached rbtrees are initialized to be
+empty via:
+
+  struct rb_root_cached mytree = RB_ROOT_CACHED;
+
+Cached rbtree is simply a regular rb_root with an extra pointer to cache the
+leftmost node. This allows rb_root_cached to exist wherever rb_root does,
+which permits augmented trees to be supported as well as only a few extra
+interfaces:
+
+  struct rb_node *rb_first_cached(struct rb_root_cached *tree);
+  void rb_insert_color_cached(struct rb_node *, struct rb_root_cached *, bool);
+  void rb_erase_cached(struct rb_node *node, struct rb_root_cached *);
+
+Both insert and erase calls have their respective counterpart of augmented
+trees:
+
+  void rb_insert_augmented_cached(struct rb_node *node, struct rb_root_cached *,
+				  bool, struct rb_augment_callbacks *);
+  void rb_erase_augmented_cached(struct rb_node *, struct rb_root_cached *,
+				 struct rb_augment_callbacks *);
+
+
 Support for Augmented rbtrees
 -----------------------------
 
--- linux-4.4.0.orig/Documentation/scsi/scsi_eh.txt
+++ linux-4.4.0/Documentation/scsi/scsi_eh.txt
@@ -263,19 +263,23 @@
 
  3. scmd recovered
     ACTION: scsi_eh_finish_cmd() is invoked to EH-finish scmd
-	- shost->host_failed--
 	- clear scmd->eh_eflags
 	- scsi_setup_cmd_retry()
 	- move from local eh_work_q to local eh_done_q
     LOCKING: none
+    CONCURRENCY: at most one thread per separate eh_work_q to
+		 keep queue manipulation lockless
 
  4. EH completes
     ACTION: scsi_eh_flush_done_q() retries scmds or notifies upper
-	    layer of failure.
+	    layer of failure. May be called concurrently but must have
+	    a no more than one thread per separate eh_work_q to
+	    manipulate the queue locklessly
 	- scmd is removed from eh_done_q and scmd->eh_entry is cleared
 	- if retry is necessary, scmd is requeued using
           scsi_queue_insert()
 	- otherwise, scsi_finish_command() is invoked for scmd
+	- zero shost->host_failed
     LOCKING: queue or finish function performs appropriate locking
 
 
--- linux-4.4.0.orig/Documentation/security/00-INDEX
+++ linux-4.4.0/Documentation/security/00-INDEX
@@ -24,3 +24,7 @@
 	- documentation on the TOMOYO Linux Security Module.
 IMA-templates.txt
 	- documentation on the template management mechanism for IMA.
+l1tf.txt
+	- Describes CPU vulnerabilities and provides an overview of the
+          possible mitigations along with guidiance for selecting miti-
+          gations if they are configurable at compile, boot or run time.
--- linux-4.4.0.orig/Documentation/security/keys-trusted-encrypted.txt
+++ linux-4.4.0/Documentation/security/keys-trusted-encrypted.txt
@@ -27,17 +27,26 @@
     keyctl print keyid
 
     options:
-       keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
-       keyauth=	  ascii hex auth for sealing key default 0x00...i
-		  (40 ascii zeros)
-       blobauth=  ascii hex auth for sealed data default 0x00...
-		  (40 ascii zeros)
-       blobauth=  ascii hex auth for sealed data default 0x00...
-		  (40 ascii zeros)
-       pcrinfo=	  ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
-       pcrlock=	  pcr number to be extended to "lock" blob
-       migratable= 0|1 indicating permission to reseal to new PCR values,
-                   default 1 (resealing allowed)
+       keyhandle=    ascii hex value of sealing key default 0x40000000 (SRK)
+       keyauth=	     ascii hex auth for sealing key default 0x00...i
+                     (40 ascii zeros)
+       blobauth=     ascii hex auth for sealed data default 0x00...
+                     (40 ascii zeros)
+       blobauth=     ascii hex auth for sealed data default 0x00...
+                     (40 ascii zeros)
+       pcrinfo=	     ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
+       pcrlock=	     pcr number to be extended to "lock" blob
+       migratable=   0|1 indicating permission to reseal to new PCR values,
+                     default 1 (resealing allowed)
+       hash=         hash algorithm name as a string. For TPM 1.x the only
+                     allowed value is sha1. For TPM 2.x the allowed values
+                     are sha1, sha256, sha384, sha512 and sm3-256.
+       policydigest= digest for the authorization policy. must be calculated
+                     with the same hash algorithm as specified by the 'hash='
+                     option.
+       policyhandle= handle to an authorization policy session that defines the
+                     same policy and with the same hash algorithm as was used to
+                     seal the key.
 
 "keyctl print" returns an ascii hex copy of the sealed key, which is in standard
 TPM_STORED_DATA format.  The key length for new keys are always in bytes.
--- linux-4.4.0.orig/Documentation/serial/tty.txt
+++ linux-4.4.0/Documentation/serial/tty.txt
@@ -213,9 +213,6 @@
 
 TTY_OTHER_CLOSED	Device is a pty and the other side has closed.
 
-TTY_OTHER_DONE		Device is a pty and the other side has closed and
-			all pending input processing has been completed.
-
 TTY_NO_WRITE_SPLIT	Prevent driver from splitting up writes into
 			smaller chunks.
 
--- linux-4.4.0.orig/Documentation/siphash.txt
+++ linux-4.4.0/Documentation/siphash.txt
@@ -0,0 +1,175 @@
+         SipHash - a short input PRF
+-----------------------------------------------
+Written by Jason A. Donenfeld <jason@zx2c4.com>
+
+SipHash is a cryptographically secure PRF -- a keyed hash function -- that
+performs very well for short inputs, hence the name. It was designed by
+cryptographers Daniel J. Bernstein and Jean-Philippe Aumasson. It is intended
+as a replacement for some uses of: `jhash`, `md5_transform`, `sha_transform`,
+and so forth.
+
+SipHash takes a secret key filled with randomly generated numbers and either
+an input buffer or several input integers. It spits out an integer that is
+indistinguishable from random. You may then use that integer as part of secure
+sequence numbers, secure cookies, or mask it off for use in a hash table.
+
+1. Generating a key
+
+Keys should always be generated from a cryptographically secure source of
+random numbers, either using get_random_bytes or get_random_once:
+
+siphash_key_t key;
+get_random_bytes(&key, sizeof(key));
+
+If you're not deriving your key from here, you're doing it wrong.
+
+2. Using the functions
+
+There are two variants of the function, one that takes a list of integers, and
+one that takes a buffer:
+
+u64 siphash(const void *data, size_t len, const siphash_key_t *key);
+
+And:
+
+u64 siphash_1u64(u64, const siphash_key_t *key);
+u64 siphash_2u64(u64, u64, const siphash_key_t *key);
+u64 siphash_3u64(u64, u64, u64, const siphash_key_t *key);
+u64 siphash_4u64(u64, u64, u64, u64, const siphash_key_t *key);
+u64 siphash_1u32(u32, const siphash_key_t *key);
+u64 siphash_2u32(u32, u32, const siphash_key_t *key);
+u64 siphash_3u32(u32, u32, u32, const siphash_key_t *key);
+u64 siphash_4u32(u32, u32, u32, u32, const siphash_key_t *key);
+
+If you pass the generic siphash function something of a constant length, it
+will constant fold at compile-time and automatically choose one of the
+optimized functions.
+
+3. Hashtable key function usage:
+
+struct some_hashtable {
+	DECLARE_HASHTABLE(hashtable, 8);
+	siphash_key_t key;
+};
+
+void init_hashtable(struct some_hashtable *table)
+{
+	get_random_bytes(&table->key, sizeof(table->key));
+}
+
+static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
+{
+	return &table->hashtable[siphash(input, sizeof(*input), &table->key) & (HASH_SIZE(table->hashtable) - 1)];
+}
+
+You may then iterate like usual over the returned hash bucket.
+
+4. Security
+
+SipHash has a very high security margin, with its 128-bit key. So long as the
+key is kept secret, it is impossible for an attacker to guess the outputs of
+the function, even if being able to observe many outputs, since 2^128 outputs
+is significant.
+
+Linux implements the "2-4" variant of SipHash.
+
+5. Struct-passing Pitfalls
+
+Often times the XuY functions will not be large enough, and instead you'll
+want to pass a pre-filled struct to siphash. When doing this, it's important
+to always ensure the struct has no padding holes. The easiest way to do this
+is to simply arrange the members of the struct in descending order of size,
+and to use offsetendof() instead of sizeof() for getting the size. For
+performance reasons, if possible, it's probably a good thing to align the
+struct to the right boundary. Here's an example:
+
+const struct {
+	struct in6_addr saddr;
+	u32 counter;
+	u16 dport;
+} __aligned(SIPHASH_ALIGNMENT) combined = {
+	.saddr = *(struct in6_addr *)saddr,
+	.counter = counter,
+	.dport = dport
+};
+u64 h = siphash(&combined, offsetofend(typeof(combined), dport), &secret);
+
+6. Resources
+
+Read the SipHash paper if you're interested in learning more:
+https://131002.net/siphash/siphash.pdf
+
+
+~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
+
+HalfSipHash - SipHash's insecure younger cousin
+-----------------------------------------------
+Written by Jason A. Donenfeld <jason@zx2c4.com>
+
+On the off-chance that SipHash is not fast enough for your needs, you might be
+able to justify using HalfSipHash, a terrifying but potentially useful
+possibility. HalfSipHash cuts SipHash's rounds down from "2-4" to "1-3" and,
+even scarier, uses an easily brute-forcable 64-bit key (with a 32-bit output)
+instead of SipHash's 128-bit key. However, this may appeal to some
+high-performance `jhash` users.
+
+Danger!
+
+Do not ever use HalfSipHash except for as a hashtable key function, and only
+then when you can be absolutely certain that the outputs will never be
+transmitted out of the kernel. This is only remotely useful over `jhash` as a
+means of mitigating hashtable flooding denial of service attacks.
+
+1. Generating a key
+
+Keys should always be generated from a cryptographically secure source of
+random numbers, either using get_random_bytes or get_random_once:
+
+hsiphash_key_t key;
+get_random_bytes(&key, sizeof(key));
+
+If you're not deriving your key from here, you're doing it wrong.
+
+2. Using the functions
+
+There are two variants of the function, one that takes a list of integers, and
+one that takes a buffer:
+
+u32 hsiphash(const void *data, size_t len, const hsiphash_key_t *key);
+
+And:
+
+u32 hsiphash_1u32(u32, const hsiphash_key_t *key);
+u32 hsiphash_2u32(u32, u32, const hsiphash_key_t *key);
+u32 hsiphash_3u32(u32, u32, u32, const hsiphash_key_t *key);
+u32 hsiphash_4u32(u32, u32, u32, u32, const hsiphash_key_t *key);
+
+If you pass the generic hsiphash function something of a constant length, it
+will constant fold at compile-time and automatically choose one of the
+optimized functions.
+
+3. Hashtable key function usage:
+
+struct some_hashtable {
+	DECLARE_HASHTABLE(hashtable, 8);
+	hsiphash_key_t key;
+};
+
+void init_hashtable(struct some_hashtable *table)
+{
+	get_random_bytes(&table->key, sizeof(table->key));
+}
+
+static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
+{
+	return &table->hashtable[hsiphash(input, sizeof(*input), &table->key) & (HASH_SIZE(table->hashtable) - 1)];
+}
+
+You may then iterate like usual over the returned hash bucket.
+
+4. Performance
+
+HalfSipHash is roughly 3 times slower than JenkinsHash. For many replacements,
+this will not be a problem, as the hashtable lookup isn't the bottleneck. And
+in general, this is probably a good sacrifice to make for the security and DoS
+resistance of HalfSipHash.
--- linux-4.4.0.orig/Documentation/spec_ctrl.txt
+++ linux-4.4.0/Documentation/spec_ctrl.txt
@@ -0,0 +1,103 @@
+===================
+Speculation Control
+===================
+
+Quite some CPUs have speculation-related misfeatures which are in
+fact vulnerabilities causing data leaks in various forms even across
+privilege domains.
+
+The kernel provides mitigation for such vulnerabilities in various
+forms. Some of these mitigations are compile-time configurable and some
+can be supplied on the kernel command line.
+
+There is also a class of mitigations which are very expensive, but they can
+be restricted to a certain set of processes or tasks in controlled
+environments. The mechanism to control these mitigations is via
+:manpage:`prctl(2)`.
+
+There are two prctl options which are related to this:
+
+ * PR_GET_SPECULATION_CTRL
+
+ * PR_SET_SPECULATION_CTRL
+
+PR_GET_SPECULATION_CTRL
+-----------------------
+
+PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature
+which is selected with arg2 of prctl(2). The return value uses bits 0-3 with
+the following meaning:
+
+==== ===================== ===================================================
+Bit  Define                Description
+==== ===================== ===================================================
+0    PR_SPEC_PRCTL         Mitigation can be controlled per task by
+                           PR_SET_SPECULATION_CTRL.
+1    PR_SPEC_ENABLE        The speculation feature is enabled, mitigation is
+                           disabled.
+2    PR_SPEC_DISABLE       The speculation feature is disabled, mitigation is
+                           enabled.
+3    PR_SPEC_FORCE_DISABLE Same as PR_SPEC_DISABLE, but cannot be undone. A
+                           subsequent prctl(..., PR_SPEC_ENABLE) will fail.
+==== ===================== ===================================================
+
+If all bits are 0 the CPU is not affected by the speculation misfeature.
+
+If PR_SPEC_PRCTL is set, then the per-task control of the mitigation is
+available. If not set, prctl(PR_SET_SPECULATION_CTRL) for the speculation
+misfeature will fail.
+
+PR_SET_SPECULATION_CTRL
+-----------------------
+
+PR_SET_SPECULATION_CTRL allows to control the speculation misfeature, which
+is selected by arg2 of :manpage:`prctl(2)` per task. arg3 is used to hand
+in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE or
+PR_SPEC_FORCE_DISABLE.
+
+Common error codes
+------------------
+======= =================================================================
+Value   Meaning
+======= =================================================================
+EINVAL  The prctl is not implemented by the architecture or unused
+        prctl(2) arguments are not 0.
+
+ENODEV  arg2 is selecting a not supported speculation misfeature.
+======= =================================================================
+
+PR_SET_SPECULATION_CTRL error codes
+-----------------------------------
+======= =================================================================
+Value   Meaning
+======= =================================================================
+0       Success
+
+ERANGE  arg3 is incorrect, i.e. it's neither PR_SPEC_ENABLE nor
+        PR_SPEC_DISABLE nor PR_SPEC_FORCE_DISABLE.
+
+ENXIO   Control of the selected speculation misfeature is not possible.
+        See PR_GET_SPECULATION_CTRL.
+
+EPERM   Speculation was disabled with PR_SPEC_FORCE_DISABLE and caller
+        tried to enable it again.
+======= =================================================================
+
+Speculation misfeature controls
+-------------------------------
+- PR_SPEC_STORE_BYPASS: Speculative Store Bypass
+
+  Invocations:
+   * prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, 0, 0, 0);
+   * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0);
+   * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0);
+   * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0);
+
+- PR_SPEC_INDIR_BRANCH: Indirect Branch Speculation in User Processes
+                        (Mitigate Spectre V2 style attacks against user processes)
+
+  Invocations:
+   * prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, 0, 0, 0);
+   * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_ENABLE, 0, 0);
+   * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_DISABLE, 0, 0);
+   * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_FORCE_DISABLE, 0, 0);
--- linux-4.4.0.orig/Documentation/speculation.txt
+++ linux-4.4.0/Documentation/speculation.txt
@@ -0,0 +1,90 @@
+This document explains potential effects of speculation, and how undesirable
+effects can be mitigated portably using common APIs.
+
+===========
+Speculation
+===========
+
+To improve performance and minimize average latencies, many contemporary CPUs
+employ speculative execution techniques such as branch prediction, performing
+work which may be discarded at a later stage.
+
+Typically speculative execution cannot be observed from architectural state,
+such as the contents of registers. However, in some cases it is possible to
+observe its impact on microarchitectural state, such as the presence or
+absence of data in caches. Such state may form side-channels which can be
+observed to extract secret information.
+
+For example, in the presence of branch prediction, it is possible for bounds
+checks to be ignored by code which is speculatively executed. Consider the
+following code:
+
+	int load_array(int *array, unsigned int index)
+	{
+		if (index >= MAX_ARRAY_ELEMS)
+			return 0;
+		else
+			return array[index];
+	}
+
+Which, on arm64, may be compiled to an assembly sequence such as:
+
+	CMP	<index>, #MAX_ARRAY_ELEMS
+	B.LT	less
+	MOV	<returnval>, #0
+	RET
+  less:
+	LDR	<returnval>, [<array>, <index>]
+	RET
+
+It is possible that a CPU mis-predicts the conditional branch, and
+speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This
+value will subsequently be discarded, but the speculated load may affect
+microarchitectural state which can be subsequently measured.
+
+More complex sequences involving multiple dependent memory accesses may
+result in sensitive information being leaked. Consider the following
+code, building on the prior example:
+
+	int load_dependent_arrays(int *arr1, int *arr2, int index)
+	{
+		int val1, val2,
+
+		val1 = load_array(arr1, index);
+		val2 = load_array(arr2, val1);
+
+		return val2;
+	}
+
+Under speculation, the first call to load_array() may return the value
+of an out-of-bounds address, while the second call will influence
+microarchitectural state dependent on this value. This may provide an
+arbitrary read primitive.
+
+====================================
+Mitigating speculation side-channels
+====================================
+
+The kernel provides a generic API to ensure that bounds checks are
+respected even under speculation. Architectures which are affected by
+speculation-based side-channels are expected to implement these
+primitives.
+
+The array_index_nospec() helper in <linux/nospec.h> can be used to
+prevent information from being leaked via side-channels.
+
+A call to array_index_nospec(index, size) returns a sanitized index
+value that is bounded to [0, size) even under cpu speculation
+conditions.
+
+This can be used to protect the earlier load_array() example:
+
+	int load_array(int *array, unsigned int index)
+	{
+		if (index >= MAX_ARRAY_ELEMS)
+			return 0;
+		else {
+			index = array_index_nospec(index, MAX_ARRAY_ELEMS);
+			return array[index];
+		}
+	}
--- linux-4.4.0.orig/Documentation/sysctl/fs.txt
+++ linux-4.4.0/Documentation/sysctl/fs.txt
@@ -32,7 +32,11 @@
 - nr_open
 - overflowuid
 - overflowgid
+- pipe-user-pages-hard
+- pipe-user-pages-soft
+- protected_fifos
 - protected_hardlinks
+- protected_regular
 - protected_symlinks
 - suid_dumpable
 - super-max
@@ -159,6 +163,45 @@
 
 ==============================================================
 
+pipe-user-pages-hard:
+
+Maximum total number of pages a non-privileged user may allocate for pipes.
+Once this limit is reached, no new pipes may be allocated until usage goes
+below the limit again. When set to 0, no limit is applied, which is the default
+setting.
+
+==============================================================
+
+pipe-user-pages-soft:
+
+Maximum total number of pages a non-privileged user may allocate for pipes
+before the pipe size gets limited to a single page. Once this limit is reached,
+new pipes will be limited to a single page in size for this user in order to
+limit total memory usage, and trying to increase them using fcntl() will be
+denied until usage goes below the limit again. The default value allows to
+allocate up to 1024 pipes at their default size. When set to 0, no limit is
+applied.
+
+==============================================================
+
+protected_fifos:
+
+The intent of this protection is to avoid unintentional writes to
+an attacker-controlled FIFO, where a program expected to create a regular
+file.
+
+When set to "0", writing to FIFOs is unrestricted.
+
+When set to "1" don't allow O_CREAT open on FIFOs that we don't own
+in world writable sticky directories, unless they are owned by the
+owner of the directory.
+
+When set to "2" it also applies to group writable sticky directories.
+
+This protection is based on the restrictions in Openwall.
+
+==============================================================
+
 protected_hardlinks:
 
 A long-standing class of security issues is the hardlink-based
@@ -179,6 +222,22 @@
 
 ==============================================================
 
+protected_regular:
+
+This protection is similar to protected_fifos, but it
+avoids writes to an attacker-controlled regular file, where a program
+expected to create one.
+
+When set to "0", writing to regular files is unrestricted.
+
+When set to "1" don't allow O_CREAT open on regular files that we
+don't own in world writable sticky directories, unless they are
+owned by the owner of the directory.
+
+When set to "2" it also applies to group writable sticky directories.
+
+==============================================================
+
 protected_symlinks:
 
 A long-standing class of security issues is the symlink-based
@@ -242,6 +301,13 @@
 
 ==============================================================
 
+mount-max:
+
+This denotes the maximum number of mounts that may exist
+in a mount namespace.
+
+==============================================================
+
 
 2. /proc/sys/fs/binfmt_misc
 ----------------------------------------------------------
--- linux-4.4.0.orig/Documentation/sysctl/kernel.txt
+++ linux-4.4.0/Documentation/sysctl/kernel.txt
@@ -69,6 +69,7 @@
 - reboot-cmd                  [ SPARC only ]
 - rtsig-max
 - rtsig-nr
+- seccomp/                    ==> Documentation/prctl/seccomp_filter.txt
 - sem
 - sem_next_id		      [ sysv ipc ]
 - sg-big-buff                 [ generic SCSI device (sg) ]
@@ -84,6 +85,7 @@
 - sysctl_writes_strict
 - tainted
 - threads-max
+- unprivileged_bpf_disabled
 - unknown_nmi_panic
 - watchdog
 - watchdog_thresh
@@ -810,14 +812,13 @@
        Each write syscall must fully contain the sysctl value to be
        written, and multiple writes on the same sysctl file descriptor
        will rewrite the sysctl value, regardless of file position.
-   0 - (default) Same behavior as above, but warn about processes that
-       perform writes to a sysctl file descriptor when the file position
-       is not 0.
-   1 - Respect file position when writing sysctl strings. Multiple writes
-       will append to the sysctl value buffer. Anything past the max length
-       of the sysctl value buffer will be ignored. Writes to numeric sysctl
-       entries must always be at file position 0 and the value must be
-       fully contained in the buffer sent in the write syscall.
+   0 - Same behavior as above, but warn about processes that perform writes
+       to a sysctl file descriptor when the file position is not 0.
+   1 - (default) Respect file position when writing sysctl strings. Multiple
+       writes will append to the sysctl value buffer. Anything past the max
+       length of the sysctl value buffer will be ignored. Writes to numeric
+       sysctl entries must always be at file position 0 and the value must
+       be fully contained in the buffer sent in the write syscall.
 
 ==============================================================
 
@@ -905,6 +906,26 @@
 
 ==============================================================
 
+unprivileged_bpf_disabled:
+
+Writing 1 to this entry will disable unprivileged calls to bpf();
+once disabled, calling bpf() without CAP_SYS_ADMIN will return
+-EPERM. Once set to 1, this can't be cleared from the running kernel
+anymore.
+
+Writing 2 to this entry will also disable unprivileged calls to bpf(),
+however, an admin can still change this setting later on, if needed, by
+writing 0 or 1 to this entry.
+
+If BPF_UNPRIV_DEFAULT_OFF is enabled in the kernel config, then this
+entry will default to 2 instead of 0.
+
+  0 - Unprivileged calls to bpf() are enabled
+  1 - Unprivileged calls to bpf() are disabled without recovery
+  2 - Unprivileged calls to bpf() are disabled
+
+==============================================================
+
 unknown_nmi_panic:
 
 The value in this file affects behavior of handling NMI. When the
--- linux-4.4.0.orig/Documentation/sysctl/net.txt
+++ linux-4.4.0/Documentation/sysctl/net.txt
@@ -43,6 +43,17 @@
 	1 - enable the JIT
 	2 - enable the JIT and ask the compiler to emit traces on kernel log.
 
+bpf_jit_harden
+--------------
+
+This enables hardening for the Berkeley Packet Filter Just in Time compiler.
+Supported are eBPF JIT backends. Enabling hardening trades off performance,
+but can mitigate JIT spraying.
+Values :
+	0 - disable JIT hardening (default value)
+	1 - enable JIT hardening for unprivileged users only
+	2 - enable JIT hardening for all users
+
 dev_weight
 --------------
 
--- linux-4.4.0.orig/Documentation/usb/power-management.txt
+++ linux-4.4.0/Documentation/usb/power-management.txt
@@ -365,11 +365,15 @@
 then the interface is considered to be idle, and the kernel may
 autosuspend the device.
 
-Drivers need not be concerned about balancing changes to the usage
-counter; the USB core will undo any remaining "get"s when a driver
-is unbound from its interface.  As a corollary, drivers must not call
-any of the usb_autopm_* functions after their disconnect() routine has
-returned.
+Drivers must be careful to balance their overall changes to the usage
+counter.  Unbalanced "get"s will remain in effect when a driver is
+unbound from its interface, preventing the device from going into
+runtime suspend should the interface be bound to a driver again.  On
+the other hand, drivers are allowed to achieve this balance by calling
+the ``usb_autopm_*`` functions even after their ``disconnect`` routine
+has returned -- say from within a work-queue routine -- provided they
+retain an active reference to the interface (via ``usb_get_intf`` and
+``usb_put_intf``).
 
 Drivers using the async routines are responsible for their own
 synchronization and mutual exclusion.
@@ -537,17 +541,18 @@
 		can write y/Y/1 or n/N/0 to the file to	enable/disable
 		USB2 hardware LPM manually. This is for	test purpose mainly.
 
-	power/usb3_hardware_lpm
+	power/usb3_hardware_lpm_u1
+	power/usb3_hardware_lpm_u2
 
 		When a USB 3.0 lpm-capable device is plugged in to a
 		xHCI host which supports link PM, it will check if U1
 		and U2 exit latencies have been set in the BOS
 		descriptor; if the check is is passed and the host
 		supports USB3 hardware LPM, USB3 hardware LPM will be
-		enabled for the device and this file will be created.
-		The file holds a string value (enable or disable)
-		indicating whether or not USB3 hardware LPM is
-		enabled for the device.
+		enabled for the device and these files will be created.
+		The files hold a string value (enable or disable)
+		indicating whether or not USB3 hardware LPM U1 or U2
+		is enabled for the device.
 
 	USB Port Power Control
 	----------------------
--- linux-4.4.0.orig/Documentation/virtual/kvm/api.txt
+++ linux-4.4.0/Documentation/virtual/kvm/api.txt
@@ -13,7 +13,7 @@
 
  - VM ioctls: These query and set attributes that affect an entire virtual
    machine, for example memory layout.  In addition a VM ioctl is used to
-   create virtual cpus (vcpus).
+   create virtual cpus (vcpus) and devices.
 
    Only run VM ioctls from the same process (address space) that was used
    to create the VM.
@@ -24,6 +24,11 @@
    Only run vcpu ioctls from the same thread that was used to create the
    vcpu.
 
+ - device ioctls: These query and set attributes that control the operation
+   of a single device.
+
+   device ioctls must be issued from the same process (address space) that
+   was used to create the VM.
 
 2. File descriptors
 -------------------
@@ -32,10 +37,11 @@
 open("/dev/kvm") obtains a handle to the kvm subsystem; this handle
 can be used to issue system ioctls.  A KVM_CREATE_VM ioctl on this
 handle will create a VM file descriptor which can be used to issue VM
-ioctls.  A KVM_CREATE_VCPU ioctl on a VM fd will create a virtual cpu
-and return a file descriptor pointing to it.  Finally, ioctls on a vcpu
-fd can be used to control the vcpu, including the important task of
-actually running guest code.
+ioctls.  A KVM_CREATE_VCPU or KVM_CREATE_DEVICE ioctl on a VM fd will
+create a virtual cpu or device and return a file descriptor pointing to
+the new resource.  Finally, ioctls on a vcpu or device fd can be used
+to control the vcpu or device.  For vcpus, this includes the important
+task of actually running guest code.
 
 In general file descriptors can be migrated among processes by means
 of fork() and the SCM_RIGHTS facility of unix domain socket.  These
@@ -122,14 +128,15 @@
 privileged user (CAP_SYS_ADMIN).
 
 
-4.3 KVM_GET_MSR_INDEX_LIST
+4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST
 
-Capability: basic
+Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST
 Architectures: x86
-Type: system
+Type: system ioctl
 Parameters: struct kvm_msr_list (in/out)
 Returns: 0 on success; -1 on error
 Errors:
+  EFAULT:    the msr index list cannot be read from or written to
   E2BIG:     the msr index list is to be to fit in the array specified by
              the user.
 
@@ -138,16 +145,23 @@
 	__u32 indices[0];
 };
 
-This ioctl returns the guest msrs that are supported.  The list varies
-by kvm version and host processor, but does not change otherwise.  The
-user fills in the size of the indices array in nmsrs, and in return
-kvm adjusts nmsrs to reflect the actual number of msrs and fills in
-the indices array with their numbers.
+The user fills in the size of the indices array in nmsrs, and in return
+kvm adjusts nmsrs to reflect the actual number of msrs and fills in the
+indices array with their numbers.
+
+KVM_GET_MSR_INDEX_LIST returns the guest msrs that are supported.  The list
+varies by kvm version and host processor, but does not change otherwise.
 
 Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are
 not returned in the MSR list, as different vcpus can have a different number
 of banks, as set via the KVM_X86_SETUP_MCE ioctl.
 
+KVM_GET_MSR_FEATURE_INDEX_LIST returns the list of MSRs that can be passed
+to the KVM_GET_MSRS system ioctl.  This lets userspace probe host capabilities
+and processor features that are exposed via MSRs (e.g., VMX capabilities).
+This list also varies by kvm version and host processor, but does not change
+otherwise.
+
 
 4.4 KVM_CHECK_EXTENSION
 
@@ -468,14 +482,22 @@
 
 4.18 KVM_GET_MSRS
 
-Capability: basic
+Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system)
 Architectures: x86
-Type: vcpu ioctl
+Type: system ioctl, vcpu ioctl
 Parameters: struct kvm_msrs (in/out)
-Returns: 0 on success, -1 on error
+Returns: number of msrs successfully returned;
+        -1 on error
 
+When used as a system ioctl:
+Reads the values of MSR-based features that are available for the VM.  This
+is similar to KVM_GET_SUPPORTED_CPUID, but it returns MSR indices and values.
+The list of msr-based features can be obtained using KVM_GET_MSR_FEATURE_INDEX_LIST
+in a system ioctl.
+
+When used as a vcpu ioctl:
 Reads model-specific registers from the vcpu.  Supported msr indices can
-be obtained using KVM_GET_MSR_INDEX_LIST.
+be obtained using KVM_GET_MSR_INDEX_LIST in a system ioctl.
 
 struct kvm_msrs {
 	__u32 nmsrs; /* number of msrs in entries */
@@ -1451,6 +1473,7 @@
 		struct kvm_irq_routing_irqchip irqchip;
 		struct kvm_irq_routing_msi msi;
 		struct kvm_irq_routing_s390_adapter adapter;
+		struct kvm_irq_routing_hv_sint hv_sint;
 		__u32 pad[8];
 	} u;
 };
@@ -1459,6 +1482,7 @@
 #define KVM_IRQ_ROUTING_IRQCHIP 1
 #define KVM_IRQ_ROUTING_MSI 2
 #define KVM_IRQ_ROUTING_S390_ADAPTER 3
+#define KVM_IRQ_ROUTING_HV_SINT 4
 
 No flags are specified so far, the corresponding field must be set to zero.
 
@@ -1482,6 +1506,10 @@
 	__u32 adapter_id;
 };
 
+struct kvm_irq_routing_hv_sint {
+	__u32 vcpu;
+	__u32 sint;
+};
 
 4.53 KVM_ASSIGN_SET_MSIX_NR (deprecated)
 
@@ -1991,6 +2019,7 @@
   PPC   | KVM_REG_PPC_TM_VSCR           | 32
   PPC   | KVM_REG_PPC_TM_DSCR           | 64
   PPC   | KVM_REG_PPC_TM_TAR            | 64
+  PPC   | KVM_REG_PPC_TM_XER            | 64
         |                               |
   MIPS  | KVM_REG_MIPS_R0               | 64
           ...
@@ -3331,6 +3360,28 @@
 it is still asserted.  Vector is the LAPIC interrupt vector for which the
 EOI was received.
 
+		struct kvm_hyperv_exit {
+#define KVM_EXIT_HYPERV_SYNIC          1
+			__u32 type;
+			union {
+				struct {
+					__u32 msr;
+					__u64 control;
+					__u64 evt_page;
+					__u64 msg_page;
+				} synic;
+			} u;
+		};
+		/* KVM_EXIT_HYPERV */
+                struct kvm_hyperv_exit hyperv;
+Indicates that the VCPU exits into userspace to process some tasks
+related to Hyper-V emulation.
+Valid values for 'type' are:
+	KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about
+Hyper-V SynIC state change. Notification is used to remap SynIC
+event/message pages and to enable/disable SynIC messages/events processing
+in userspace.
+
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -3685,3 +3736,16 @@
 H_RANDOM hypercall backed by a hardware random-number generator.
 If present, the kernel H_RANDOM handler can be enabled for guest use
 with the KVM_CAP_PPC_ENABLE_HCALL capability.
+
+8.2 KVM_CAP_HYPERV_SYNIC
+
+Architectures: x86
+This capability, if KVM_CHECK_EXTENSION indicates that it is
+available, means that that the kernel has an implementation of the
+Hyper-V Synthetic interrupt controller(SynIC). Hyper-V SynIC is
+used to support Windows Hyper-V based guest paravirt drivers(VMBus).
+
+In order to use SynIC, it has to be activated by setting this
+capability via KVM_ENABLE_CAP ioctl on the vcpu fd. Note that this
+will disable the use of APIC hardware virtualization even if supported
+by the CPU, as it's incompatible with SynIC auto-EOI behavior.
--- linux-4.4.0.orig/Documentation/virtual/kvm/locking.txt
+++ linux-4.4.0/Documentation/virtual/kvm/locking.txt
@@ -132,7 +132,7 @@
 ------------
 
 Name:		kvm_lock
-Type:		spinlock_t
+Type:		mutex
 Arch:		any
 Protects:	- vm_list
 
--- linux-4.4.0.orig/Documentation/virtual/kvm/mmu.txt
+++ linux-4.4.0/Documentation/virtual/kvm/mmu.txt
@@ -152,8 +152,8 @@
     shadow pages) so role.quadrant takes values in the range 0..3.  Each
     quadrant maps 1GB virtual address space.
   role.access:
-    Inherited guest access permissions in the form uwx.  Note execute
-    permission is positive, not negative.
+    Inherited guest access permissions from the parent ptes in the form uwx.
+    Note execute permission is positive, not negative.
   role.invalid:
     The page is invalid and should not be used.  It is a root page that is
     currently pinned (by a cpu hardware register pointing to it); once it is
@@ -358,7 +358,8 @@
 - if CR4.SMEP is enabled: since we've turned the page into a kernel page,
   the kernel may now execute it.  We handle this by also setting spte.nx.
   If we get a user fetch or read fault, we'll change spte.u=1 and
-  spte.nx=gpte.nx back.
+  spte.nx=gpte.nx back.  For this to work, KVM forces EFER.NX to 1 when
+  shadow paging is in use.
 - if CR4.SMAP is disabled: since the page has been changed to a kernel
   page, it can not be reused when CR4.SMAP is enabled. We set
   CR4.SMAP && !CR0.WP into shadow page's role to avoid this case. Note,
@@ -391,11 +392,11 @@
   write-protected pages
 - the guest page must be wholly contained by a single memory slot
 
-To check the last two conditions, the mmu maintains a ->write_count set of
+To check the last two conditions, the mmu maintains a ->disallow_lpage set of
 arrays for each memory slot and large page size.  Every write protected page
-causes its write_count to be incremented, thus preventing instantiation of
+causes its disallow_lpage to be incremented, thus preventing instantiation of
 a large spte.  The frames at the end of an unaligned memory slot have
-artificially inflated ->write_counts so they can never be instantiated.
+artificially inflated ->disallow_lpages so they can never be instantiated.
 
 Zapping all pages (page generation count)
 =========================================
--- linux-4.4.0.orig/Documentation/vm/ksm.txt
+++ linux-4.4.0/Documentation/vm/ksm.txt
@@ -80,6 +80,50 @@
                    Default: 0 (must be changed to 1 to activate KSM,
                                except if CONFIG_SYSFS is disabled)
 
+max_page_sharing - Maximum sharing allowed for each KSM page. This
+                   enforces a deduplication limit to avoid the virtual
+                   memory rmap lists to grow too large. The minimum
+                   value is 2 as a newly created KSM page will have at
+                   least two sharers. The rmap walk has O(N)
+                   complexity where N is the number of rmap_items
+                   (i.e. virtual mappings) that are sharing the page,
+                   which is in turn capped by max_page_sharing. So
+                   this effectively spread the the linear O(N)
+                   computational complexity from rmap walk context
+                   over different KSM pages. The ksmd walk over the
+                   stable_node "chains" is also O(N), but N is the
+                   number of stable_node "dups", not the number of
+                   rmap_items, so it has not a significant impact on
+                   ksmd performance. In practice the best stable_node
+                   "dup" candidate will be kept and found at the head
+                   of the "dups" list. The higher this value the
+                   faster KSM will merge the memory (because there
+                   will be fewer stable_node dups queued into the
+                   stable_node chain->hlist to check for pruning) and
+                   the higher the deduplication factor will be, but
+                   the slowest the worst case rmap walk could be for
+                   any given KSM page. Slowing down the rmap_walk
+                   means there will be higher latency for certain
+                   virtual memory operations happening during
+                   swapping, compaction, NUMA balancing and page
+                   migration, in turn decreasing responsiveness for
+                   the caller of those virtual memory operations. The
+                   scheduler latency of other tasks not involved with
+                   the VM operations doing the rmap walk is not
+                   affected by this parameter as the rmap walks are
+                   always schedule friendly themselves.
+
+stable_node_chains_prune_millisecs - How frequently to walk the whole
+                   list of stable_node "dups" linked in the
+                   stable_node "chains" in order to prune stale
+                   stable_nodes. Smaller milllisecs values will free
+                   up the KSM metadata with lower latency, but they
+                   will make ksmd use more CPU during the scan. This
+                   only applies to the stable_node chains so it's a
+                   noop if not a single KSM page hit the
+                   max_page_sharing yet (there would be no stable_node
+                   chains in such case).
+
 The effectiveness of KSM and MADV_MERGEABLE is shown in /sys/kernel/mm/ksm/:
 
 pages_shared     - how many shared pages are being used
@@ -88,10 +132,29 @@
 pages_volatile   - how many pages changing too fast to be placed in a tree
 full_scans       - how many times all mergeable areas have been scanned
 
+stable_node_chains - number of stable node chains allocated, this is
+		     effectively the number of KSM pages that hit the
+		     max_page_sharing limit
+stable_node_dups   - number of stable node dups queued into the
+		     stable_node chains
+
 A high ratio of pages_sharing to pages_shared indicates good sharing, but
 a high ratio of pages_unshared to pages_sharing indicates wasted effort.
 pages_volatile embraces several different kinds of activity, but a high
 proportion there would also indicate poor use of madvise MADV_MERGEABLE.
 
+The maximum possible page_sharing/page_shared ratio is limited by the
+max_page_sharing tunable. To increase the ratio max_page_sharing must
+be increased accordingly.
+
+The stable_node_dups/stable_node_chains ratio is also affected by the
+max_page_sharing tunable, and an high ratio may indicate fragmentation
+in the stable_node dups, which could be solved by introducing
+fragmentation algorithms in ksmd which would refile rmap_items from
+one stable_node dup to another stable_node dup, in order to freeup
+stable_node "dups" with few rmap_items in them, but that may increase
+the ksmd CPU usage and possibly slowdown the readonly computations on
+the KSM pages of the applications.
+
 Izik Eidus,
 Hugh Dickins, 17 Nov 2009
--- linux-4.4.0.orig/Documentation/x86/conf.py
+++ linux-4.4.0/Documentation/x86/conf.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8; mode: python -*-
+
+project = "X86 architecture specific documentation"
+
+tags.add("subproject")
+
+latex_documents = [
+    ('index', 'x86.tex', project,
+     'The kernel development community', 'manual'),
+]
--- linux-4.4.0.orig/Documentation/x86/index.rst
+++ linux-4.4.0/Documentation/x86/index.rst
@@ -0,0 +1,9 @@
+==========================
+x86 architecture specifics
+==========================
+
+.. toctree::
+   :maxdepth: 1
+
+   mds
+   tsx_async_abort
--- linux-4.4.0.orig/Documentation/x86/mds.rst
+++ linux-4.4.0/Documentation/x86/mds.rst
@@ -0,0 +1,193 @@
+Microarchitectural Data Sampling (MDS) mitigation
+=================================================
+
+.. _mds:
+
+Overview
+--------
+
+Microarchitectural Data Sampling (MDS) is a family of side channel attacks
+on internal buffers in Intel CPUs. The variants are:
+
+ - Microarchitectural Store Buffer Data Sampling (MSBDS) (CVE-2018-12126)
+ - Microarchitectural Fill Buffer Data Sampling (MFBDS) (CVE-2018-12130)
+ - Microarchitectural Load Port Data Sampling (MLPDS) (CVE-2018-12127)
+ - Microarchitectural Data Sampling Uncacheable Memory (MDSUM) (CVE-2019-11091)
+
+MSBDS leaks Store Buffer Entries which can be speculatively forwarded to a
+dependent load (store-to-load forwarding) as an optimization. The forward
+can also happen to a faulting or assisting load operation for a different
+memory address, which can be exploited under certain conditions. Store
+buffers are partitioned between Hyper-Threads so cross thread forwarding is
+not possible. But if a thread enters or exits a sleep state the store
+buffer is repartitioned which can expose data from one thread to the other.
+
+MFBDS leaks Fill Buffer Entries. Fill buffers are used internally to manage
+L1 miss situations and to hold data which is returned or sent in response
+to a memory or I/O operation. Fill buffers can forward data to a load
+operation and also write data to the cache. When the fill buffer is
+deallocated it can retain the stale data of the preceding operations which
+can then be forwarded to a faulting or assisting load operation, which can
+be exploited under certain conditions. Fill buffers are shared between
+Hyper-Threads so cross thread leakage is possible.
+
+MLPDS leaks Load Port Data. Load ports are used to perform load operations
+from memory or I/O. The received data is then forwarded to the register
+file or a subsequent operation. In some implementations the Load Port can
+contain stale data from a previous operation which can be forwarded to
+faulting or assisting loads under certain conditions, which again can be
+exploited eventually. Load ports are shared between Hyper-Threads so cross
+thread leakage is possible.
+
+MDSUM is a special case of MSBDS, MFBDS and MLPDS. An uncacheable load from
+memory that takes a fault or assist can leave data in a microarchitectural
+structure that may later be observed using one of the same methods used by
+MSBDS, MFBDS or MLPDS.
+
+Exposure assumptions
+--------------------
+
+It is assumed that attack code resides in user space or in a guest with one
+exception. The rationale behind this assumption is that the code construct
+needed for exploiting MDS requires:
+
+ - to control the load to trigger a fault or assist
+
+ - to have a disclosure gadget which exposes the speculatively accessed
+   data for consumption through a side channel.
+
+ - to control the pointer through which the disclosure gadget exposes the
+   data
+
+The existence of such a construct in the kernel cannot be excluded with
+100% certainty, but the complexity involved makes it extremly unlikely.
+
+There is one exception, which is untrusted BPF. The functionality of
+untrusted BPF is limited, but it needs to be thoroughly investigated
+whether it can be used to create such a construct.
+
+
+Mitigation strategy
+-------------------
+
+All variants have the same mitigation strategy at least for the single CPU
+thread case (SMT off): Force the CPU to clear the affected buffers.
+
+This is achieved by using the otherwise unused and obsolete VERW
+instruction in combination with a microcode update. The microcode clears
+the affected CPU buffers when the VERW instruction is executed.
+
+For virtualization there are two ways to achieve CPU buffer
+clearing. Either the modified VERW instruction or via the L1D Flush
+command. The latter is issued when L1TF mitigation is enabled so the extra
+VERW can be avoided. If the CPU is not affected by L1TF then VERW needs to
+be issued.
+
+If the VERW instruction with the supplied segment selector argument is
+executed on a CPU without the microcode update there is no side effect
+other than a small number of pointlessly wasted CPU cycles.
+
+This does not protect against cross Hyper-Thread attacks except for MSBDS
+which is only exploitable cross Hyper-thread when one of the Hyper-Threads
+enters a C-state.
+
+The kernel provides a function to invoke the buffer clearing:
+
+    mds_clear_cpu_buffers()
+
+The mitigation is invoked on kernel/userspace, hypervisor/guest and C-state
+(idle) transitions.
+
+As a special quirk to address virtualization scenarios where the host has
+the microcode updated, but the hypervisor does not (yet) expose the
+MD_CLEAR CPUID bit to guests, the kernel issues the VERW instruction in the
+hope that it might actually clear the buffers. The state is reflected
+accordingly.
+
+According to current knowledge additional mitigations inside the kernel
+itself are not required because the necessary gadgets to expose the leaked
+data cannot be controlled in a way which allows exploitation from malicious
+user space or VM guests.
+
+Kernel internal mitigation modes
+--------------------------------
+
+ ======= ============================================================
+ off      Mitigation is disabled. Either the CPU is not affected or
+          mds=off is supplied on the kernel command line
+
+ full     Mitigation is enabled. CPU is affected and MD_CLEAR is
+          advertised in CPUID.
+
+ vmwerv	  Mitigation is enabled. CPU is affected and MD_CLEAR is not
+	  advertised in CPUID. That is mainly for virtualization
+	  scenarios where the host has the updated microcode but the
+	  hypervisor does not expose MD_CLEAR in CPUID. It's a best
+	  effort approach without guarantee.
+ ======= ============================================================
+
+If the CPU is affected and mds=off is not supplied on the kernel command
+line then the kernel selects the appropriate mitigation mode depending on
+the availability of the MD_CLEAR CPUID bit.
+
+Mitigation points
+-----------------
+
+1. Return to user space
+^^^^^^^^^^^^^^^^^^^^^^^
+
+   When transitioning from kernel to user space the CPU buffers are flushed
+   on affected CPUs when the mitigation is not disabled on the kernel
+   command line. The migitation is enabled through the static key
+   mds_user_clear.
+
+   The mitigation is invoked in prepare_exit_to_usermode() which covers
+   all but one of the kernel to user space transitions.  The exception
+   is when we return from a Non Maskable Interrupt (NMI), which is
+   handled directly in do_nmi().
+
+   (The reason that NMI is special is that prepare_exit_to_usermode() can
+    enable IRQs.  In NMI context, NMIs are blocked, and we don't want to
+    enable IRQs with NMIs blocked.)
+
+
+2. C-State transition
+^^^^^^^^^^^^^^^^^^^^^
+
+   When a CPU goes idle and enters a C-State the CPU buffers need to be
+   cleared on affected CPUs when SMT is active. This addresses the
+   repartitioning of the store buffer when one of the Hyper-Threads enters
+   a C-State.
+
+   When SMT is inactive, i.e. either the CPU does not support it or all
+   sibling threads are offline CPU buffer clearing is not required.
+
+   The idle clearing is enabled on CPUs which are only affected by MSBDS
+   and not by any other MDS variant. The other MDS variants cannot be
+   protected against cross Hyper-Thread attacks because the Fill Buffer and
+   the Load Ports are shared. So on CPUs affected by other variants, the
+   idle clearing would be a window dressing exercise and is therefore not
+   activated.
+
+   The invocation is controlled by the static key mds_idle_clear which is
+   switched depending on the chosen mitigation mode and the SMT state of
+   the system.
+
+   The buffer clear is only invoked before entering the C-State to prevent
+   that stale data from the idling CPU from spilling to the Hyper-Thread
+   sibling after the store buffer got repartitioned and all entries are
+   available to the non idle sibling.
+
+   When coming out of idle the store buffer is partitioned again so each
+   sibling has half of it available. The back from idle CPU could be then
+   speculatively exposed to contents of the sibling. The buffers are
+   flushed either on exit to user space or on VMENTER so malicious code
+   in user space or the guest cannot speculatively access them.
+
+   The mitigation is hooked into all variants of halt()/mwait(), but does
+   not cover the legacy ACPI IO-Port mechanism because the ACPI idle driver
+   has been superseded by the intel_idle driver around 2010 and is
+   preferred on all affected CPUs which are expected to gain the MD_CLEAR
+   functionality in microcode. Aside of that the IO-Port mechanism is a
+   legacy interface which is only used on older systems which are either
+   not affected or do not receive microcode updates anymore.
--- linux-4.4.0.orig/Documentation/x86/pat.txt
+++ linux-4.4.0/Documentation/x86/pat.txt
@@ -196,3 +196,35 @@
 "debugpat" boot parameter. With this parameter, various debug messages are
 printed to dmesg log.
 
+PAT Initialization
+------------------
+
+The following table describes how PAT is initialized under various
+configurations. The PAT MSR must be updated by Linux in order to support WC
+and WT attributes. Otherwise, the PAT MSR has the value programmed in it
+by the firmware. Note, Xen enables WC attribute in the PAT MSR for guests.
+
+ MTRR PAT   Call Sequence               PAT State  PAT MSR
+ =========================================================
+ E    E     MTRR -> PAT init            Enabled    OS
+ E    D     MTRR -> PAT init            Disabled    -
+ D    E     MTRR -> PAT disable         Disabled   BIOS
+ D    D     MTRR -> PAT disable         Disabled    -
+ -    np/E  PAT  -> PAT disable         Disabled   BIOS
+ -    np/D  PAT  -> PAT disable         Disabled    -
+ E    !P/E  MTRR -> PAT init            Disabled   BIOS
+ D    !P/E  MTRR -> PAT disable         Disabled   BIOS
+ !M   !P/E  MTRR stub -> PAT disable    Disabled   BIOS
+
+ Legend
+ ------------------------------------------------
+ E         Feature enabled in CPU
+ D	   Feature disabled/unsupported in CPU
+ np	   "nopat" boot option specified
+ !P	   CONFIG_X86_PAT option unset
+ !M	   CONFIG_MTRR option unset
+ Enabled   PAT state set to enabled
+ Disabled  PAT state set to disabled
+ OS        PAT initializes PAT MSR with OS setting
+ BIOS      PAT keeps PAT MSR with BIOS setting
+
--- linux-4.4.0.orig/Documentation/x86/pti.txt
+++ linux-4.4.0/Documentation/x86/pti.txt
@@ -0,0 +1,186 @@
+Overview
+========
+
+Page Table Isolation (pti, previously known as KAISER[1]) is a
+countermeasure against attacks on the shared user/kernel address
+space such as the "Meltdown" approach[2].
+
+To mitigate this class of attacks, we create an independent set of
+page tables for use only when running userspace applications.  When
+the kernel is entered via syscalls, interrupts or exceptions, the
+page tables are switched to the full "kernel" copy.  When the system
+switches back to user mode, the user copy is used again.
+
+The userspace page tables contain only a minimal amount of kernel
+data: only what is needed to enter/exit the kernel such as the
+entry/exit functions themselves and the interrupt descriptor table
+(IDT).  There are a few strictly unnecessary things that get mapped
+such as the first C function when entering an interrupt (see
+comments in pti.c).
+
+This approach helps to ensure that side-channel attacks leveraging
+the paging structures do not function when PTI is enabled.  It can be
+enabled by setting CONFIG_PAGE_TABLE_ISOLATION=y at compile time.
+Once enabled at compile-time, it can be disabled at boot with the
+'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt).
+
+Page Table Management
+=====================
+
+When PTI is enabled, the kernel manages two sets of page tables.
+The first set is very similar to the single set which is present in
+kernels without PTI.  This includes a complete mapping of userspace
+that the kernel can use for things like copy_to_user().
+
+Although _complete_, the user portion of the kernel page tables is
+crippled by setting the NX bit in the top level.  This ensures
+that any missed kernel->user CR3 switch will immediately crash
+userspace upon executing its first instruction.
+
+The userspace page tables map only the kernel data needed to enter
+and exit the kernel.  This data is entirely contained in the 'struct
+cpu_entry_area' structure which is placed in the fixmap which gives
+each CPU's copy of the area a compile-time-fixed virtual address.
+
+For new userspace mappings, the kernel makes the entries in its
+page tables like normal.  The only difference is when the kernel
+makes entries in the top (PGD) level.  In addition to setting the
+entry in the main kernel PGD, a copy of the entry is made in the
+userspace page tables' PGD.
+
+This sharing at the PGD level also inherently shares all the lower
+layers of the page tables.  This leaves a single, shared set of
+userspace page tables to manage.  One PTE to lock, one set of
+accessed bits, dirty bits, etc...
+
+Overhead
+========
+
+Protection against side-channel attacks is important.  But,
+this protection comes at a cost:
+
+1. Increased Memory Use
+  a. Each process now needs an order-1 PGD instead of order-0.
+     (Consumes an additional 4k per process).
+  b. The 'cpu_entry_area' structure must be 2MB in size and 2MB
+     aligned so that it can be mapped by setting a single PMD
+     entry.  This consumes nearly 2MB of RAM once the kernel
+     is decompressed, but no space in the kernel image itself.
+
+2. Runtime Cost
+  a. CR3 manipulation to switch between the page table copies
+     must be done at interrupt, syscall, and exception entry
+     and exit (it can be skipped when the kernel is interrupted,
+     though.)  Moves to CR3 are on the order of a hundred
+     cycles, and are required at every entry and exit.
+  b. A "trampoline" must be used for SYSCALL entry.  This
+     trampoline depends on a smaller set of resources than the
+     non-PTI SYSCALL entry code, so requires mapping fewer
+     things into the userspace page tables.  The downside is
+     that stacks must be switched at entry time.
+  c. Global pages are disabled for all kernel structures not
+     mapped into both kernel and userspace page tables.  This
+     feature of the MMU allows different processes to share TLB
+     entries mapping the kernel.  Losing the feature means more
+     TLB misses after a context switch.  The actual loss of
+     performance is very small, however, never exceeding 1%.
+  d. Process Context IDentifiers (PCID) is a CPU feature that
+     allows us to skip flushing the entire TLB when switching page
+     tables by setting a special bit in CR3 when the page tables
+     are changed.  This makes switching the page tables (at context
+     switch, or kernel entry/exit) cheaper.  But, on systems with
+     PCID support, the context switch code must flush both the user
+     and kernel entries out of the TLB.  The user PCID TLB flush is
+     deferred until the exit to userspace, minimizing the cost.
+     See intel.com/sdm for the gory PCID/INVPCID details.
+  e. The userspace page tables must be populated for each new
+     process.  Even without PTI, the shared kernel mappings
+     are created by copying top-level (PGD) entries into each
+     new process.  But, with PTI, there are now *two* kernel
+     mappings: one in the kernel page tables that maps everything
+     and one for the entry/exit structures.  At fork(), we need to
+     copy both.
+  f. In addition to the fork()-time copying, there must also
+     be an update to the userspace PGD any time a set_pgd() is done
+     on a PGD used to map userspace.  This ensures that the kernel
+     and userspace copies always map the same userspace
+     memory.
+  g. On systems without PCID support, each CR3 write flushes
+     the entire TLB.  That means that each syscall, interrupt
+     or exception flushes the TLB.
+  h. INVPCID is a TLB-flushing instruction which allows flushing
+     of TLB entries for non-current PCIDs.  Some systems support
+     PCIDs, but do not support INVPCID.  On these systems, addresses
+     can only be flushed from the TLB for the current PCID.  When
+     flushing a kernel address, we need to flush all PCIDs, so a
+     single kernel address flush will require a TLB-flushing CR3
+     write upon the next use of every PCID.
+
+Possible Future Work
+====================
+1. We can be more careful about not actually writing to CR3
+   unless its value is actually changed.
+2. Allow PTI to be enabled/disabled at runtime in addition to the
+   boot-time switching.
+
+Testing
+========
+
+To test stability of PTI, the following test procedure is recommended,
+ideally doing all of these in parallel:
+
+1. Set CONFIG_DEBUG_ENTRY=y
+2. Run several copies of all of the tools/testing/selftests/x86/ tests
+   (excluding MPX and protection_keys) in a loop on multiple CPUs for
+   several minutes.  These tests frequently uncover corner cases in the
+   kernel entry code.  In general, old kernels might cause these tests
+   themselves to crash, but they should never crash the kernel.
+3. Run the 'perf' tool in a mode (top or record) that generates many
+   frequent performance monitoring non-maskable interrupts (see "NMI"
+   in /proc/interrupts).  This exercises the NMI entry/exit code which
+   is known to trigger bugs in code paths that did not expect to be
+   interrupted, including nested NMIs.  Using "-c" boosts the rate of
+   NMIs, and using two -c with separate counters encourages nested NMIs
+   and less deterministic behavior.
+
+	while true; do perf record -c 10000 -e instructions,cycles -a sleep 10; done
+
+4. Launch a KVM virtual machine.
+5. Run 32-bit binaries on systems supporting the SYSCALL instruction.
+   This has been a lightly-tested code path and needs extra scrutiny.
+
+Debugging
+=========
+
+Bugs in PTI cause a few different signatures of crashes
+that are worth noting here.
+
+ * Failures of the selftests/x86 code.  Usually a bug in one of the
+   more obscure corners of entry_64.S
+ * Crashes in early boot, especially around CPU bringup.  Bugs
+   in the trampoline code or mappings cause these.
+ * Crashes at the first interrupt.  Caused by bugs in entry_64.S,
+   like screwing up a page table switch.  Also caused by
+   incorrectly mapping the IRQ handler entry code.
+ * Crashes at the first NMI.  The NMI code is separate from main
+   interrupt handlers and can have bugs that do not affect
+   normal interrupts.  Also caused by incorrectly mapping NMI
+   code.  NMIs that interrupt the entry code must be very
+   careful and can be the cause of crashes that show up when
+   running perf.
+ * Kernel crashes at the first exit to userspace.  entry_64.S
+   bugs, or failing to map some of the exit code.
+ * Crashes at first interrupt that interrupts userspace. The paths
+   in entry_64.S that return to userspace are sometimes separate
+   from the ones that return to the kernel.
+ * Double faults: overflowing the kernel stack because of page
+   faults upon page faults.  Caused by touching non-pti-mapped
+   data in the entry code, or forgetting to switch to kernel
+   CR3 before calling into C functions which are not pti-mapped.
+ * Userspace segfaults early in boot, sometimes manifesting
+   as mount(8) failing to mount the rootfs.  These have
+   tended to be TLB invalidation issues.  Usually invalidating
+   the wrong PCID, or otherwise missing an invalidation.
+
+1. https://gruss.cc/files/kaiser.pdf
+2. https://meltdownattack.com/meltdown.pdf
--- linux-4.4.0.orig/Documentation/x86/tsx_async_abort.rst
+++ linux-4.4.0/Documentation/x86/tsx_async_abort.rst
@@ -0,0 +1,117 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+TSX Async Abort (TAA) mitigation
+================================
+
+.. _tsx_async_abort:
+
+Overview
+--------
+
+TSX Async Abort (TAA) is a side channel attack on internal buffers in some
+Intel processors similar to Microachitectural Data Sampling (MDS).  In this
+case certain loads may speculatively pass invalid data to dependent operations
+when an asynchronous abort condition is pending in a Transactional
+Synchronization Extensions (TSX) transaction.  This includes loads with no
+fault or assist condition. Such loads may speculatively expose stale data from
+the same uarch data structures as in MDS, with same scope of exposure i.e.
+same-thread and cross-thread. This issue affects all current processors that
+support TSX.
+
+Mitigation strategy
+-------------------
+
+a) TSX disable - one of the mitigations is to disable TSX. A new MSR
+IA32_TSX_CTRL will be available in future and current processors after
+microcode update which can be used to disable TSX. In addition, it
+controls the enumeration of the TSX feature bits (RTM and HLE) in CPUID.
+
+b) Clear CPU buffers - similar to MDS, clearing the CPU buffers mitigates this
+vulnerability. More details on this approach can be found in
+:ref:`Documentation/admin-guide/hw-vuln/mds.rst <mds>`.
+
+Kernel internal mitigation modes
+--------------------------------
+
+ =============    ============================================================
+ off              Mitigation is disabled. Either the CPU is not affected or
+                  tsx_async_abort=off is supplied on the kernel command line.
+
+ tsx disabled     Mitigation is enabled. TSX feature is disabled by default at
+                  bootup on processors that support TSX control.
+
+ verw             Mitigation is enabled. CPU is affected and MD_CLEAR is
+                  advertised in CPUID.
+
+ ucode needed     Mitigation is enabled. CPU is affected and MD_CLEAR is not
+                  advertised in CPUID. That is mainly for virtualization
+                  scenarios where the host has the updated microcode but the
+                  hypervisor does not expose MD_CLEAR in CPUID. It's a best
+                  effort approach without guarantee.
+ =============    ============================================================
+
+If the CPU is affected and the "tsx_async_abort" kernel command line parameter is
+not provided then the kernel selects an appropriate mitigation depending on the
+status of RTM and MD_CLEAR CPUID bits.
+
+Below tables indicate the impact of tsx=on|off|auto cmdline options on state of
+TAA mitigation, VERW behavior and TSX feature for various combinations of
+MSR_IA32_ARCH_CAPABILITIES bits.
+
+1. "tsx=off"
+
+=========  =========  ============  ============  ==============  ===================  ======================
+MSR_IA32_ARCH_CAPABILITIES bits     Result with cmdline tsx=off
+----------------------------------  -------------------------------------------------------------------------
+TAA_NO     MDS_NO     TSX_CTRL_MSR  TSX state     VERW can clear  TAA mitigation       TAA mitigation
+                                    after bootup  CPU buffers     tsx_async_abort=off  tsx_async_abort=full
+=========  =========  ============  ============  ==============  ===================  ======================
+    0          0           0         HW default         Yes           Same as MDS           Same as MDS
+    0          0           1        Invalid case   Invalid case       Invalid case          Invalid case
+    0          1           0         HW default         No         Need ucode update     Need ucode update
+    0          1           1          Disabled          Yes           TSX disabled          TSX disabled
+    1          X           1          Disabled           X             None needed           None needed
+=========  =========  ============  ============  ==============  ===================  ======================
+
+2. "tsx=on"
+
+=========  =========  ============  ============  ==============  ===================  ======================
+MSR_IA32_ARCH_CAPABILITIES bits     Result with cmdline tsx=on
+----------------------------------  -------------------------------------------------------------------------
+TAA_NO     MDS_NO     TSX_CTRL_MSR  TSX state     VERW can clear  TAA mitigation       TAA mitigation
+                                    after bootup  CPU buffers     tsx_async_abort=off  tsx_async_abort=full
+=========  =========  ============  ============  ==============  ===================  ======================
+    0          0           0         HW default        Yes            Same as MDS          Same as MDS
+    0          0           1        Invalid case   Invalid case       Invalid case         Invalid case
+    0          1           0         HW default        No          Need ucode update     Need ucode update
+    0          1           1          Enabled          Yes               None              Same as MDS
+    1          X           1          Enabled          X              None needed          None needed
+=========  =========  ============  ============  ==============  ===================  ======================
+
+3. "tsx=auto"
+
+=========  =========  ============  ============  ==============  ===================  ======================
+MSR_IA32_ARCH_CAPABILITIES bits     Result with cmdline tsx=auto
+----------------------------------  -------------------------------------------------------------------------
+TAA_NO     MDS_NO     TSX_CTRL_MSR  TSX state     VERW can clear  TAA mitigation       TAA mitigation
+                                    after bootup  CPU buffers     tsx_async_abort=off  tsx_async_abort=full
+=========  =========  ============  ============  ==============  ===================  ======================
+    0          0           0         HW default    Yes                Same as MDS           Same as MDS
+    0          0           1        Invalid case  Invalid case        Invalid case          Invalid case
+    0          1           0         HW default    No              Need ucode update     Need ucode update
+    0          1           1          Disabled      Yes               TSX disabled          TSX disabled
+    1          X           1          Enabled       X                 None needed           None needed
+=========  =========  ============  ============  ==============  ===================  ======================
+
+In the tables, TSX_CTRL_MSR is a new bit in MSR_IA32_ARCH_CAPABILITIES that
+indicates whether MSR_IA32_TSX_CTRL is supported.
+
+There are two control bits in IA32_TSX_CTRL MSR:
+
+      Bit 0: When set it disables the Restricted Transactional Memory (RTM)
+             sub-feature of TSX (will force all transactions to abort on the
+             XBEGIN instruction).
+
+      Bit 1: When set it disables the enumeration of the RTM and HLE feature
+             (i.e. it will make CPUID(EAX=7).EBX{bit4} and
+             CPUID(EAX=7).EBX{bit11} read as 0).
--- linux-4.4.0.orig/Documentation/x86/zero-page.txt
+++ linux-4.4.0/Documentation/x86/zero-page.txt
@@ -31,6 +31,8 @@
 1E9/001	ALL	eddbuf_entries	Number of entries in eddbuf (below)
 1EA/001	ALL	edd_mbr_sig_buf_entries	Number of entries in edd_mbr_sig_buffer
 				(below)
+1EB/001	ALL     kbd_status      Numlock is enabled
+1EC/001	ALL     secure_boot	Secure boot is enabled in the firmware
 1EF/001	ALL	sentinel	Used to detect broken bootloaders
 290/040	ALL	edd_mbr_sig_buffer EDD MBR signatures
 2D0/A00	ALL	e820_map	E820 memory map table
--- linux-4.4.0.orig/Kbuild
+++ linux-4.4.0/Kbuild
@@ -6,31 +6,6 @@
 # 3) Generate asm-offsets.h (may need bounds.h and timeconst.h)
 # 4) Check for missing system calls
 
-# Default sed regexp - multiline due to syntax constraints
-define sed-y
-	"/^->/{s:->#\(.*\):/* \1 */:; \
-	s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
-	s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
-	s:->::; p;}"
-endef
-
-# Use filechk to avoid rebuilds when a header changes, but the resulting file
-# does not
-define filechk_offsets
-	(set -e; \
-	 echo "#ifndef $2"; \
-	 echo "#define $2"; \
-	 echo "/*"; \
-	 echo " * DO NOT MODIFY."; \
-	 echo " *"; \
-	 echo " * This file was generated by Kbuild"; \
-	 echo " */"; \
-	 echo ""; \
-	 sed -ne $(sed-y); \
-	 echo ""; \
-	 echo "#endif" )
-endef
-
 #####
 # 1) Generate bounds.h
 
--- linux-4.4.0.orig/MAINTAINERS
+++ linux-4.4.0/MAINTAINERS
@@ -230,13 +230,13 @@
 
 ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
 M:	Hans de Goede <hdegoede@redhat.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/abituguru.c
 
 ABIT UGURU 3 HARDWARE MONITOR DRIVER
 M:	Alistair John Strachan <alistair@devzero.co.uk>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/abituguru3.c
 
@@ -373,14 +373,14 @@
 
 ADM1025 HARDWARE MONITOR DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/adm1025
 F:	drivers/hwmon/adm1025.c
 
 ADM1029 HARDWARE MONITOR DRIVER
 M:	Corentin Labbe <clabbe.montjoie@gmail.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/adm1029.c
 
@@ -425,7 +425,7 @@
 
 ADS1015 HARDWARE MONITOR DRIVER
 M:	Dirk Eibach <eibach@gdsys.de>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/ads1015
 F:	drivers/hwmon/ads1015.c
@@ -438,7 +438,7 @@
 
 ADT7475 HARDWARE MONITOR DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/adt7475
 F:	drivers/hwmon/adt7475.c
@@ -606,6 +606,15 @@
 F:	include/linux/altera_uart.h
 F:	include/linux/altera_jtaguart.h
 
+AMAZON ETHERNET DRIVERS
+M:	Netanel Belgazal <netanel@annapurnalabs.com>
+R:	Saeed Bishara <saeed@annapurnalabs.com>
+R:	Zorik Machulsky <zorik@annapurnalabs.com>
+L:	netdev@vger.kernel.org
+S:	Supported
+F:	Documentation/networking/ena.txt
+F:	drivers/net/ethernet/amazon/
+
 AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER
 M:	Tom Lendacky <thomas.lendacky@amd.com>
 L:	linux-crypto@vger.kernel.org
@@ -615,7 +624,7 @@
 
 AMD FAM15H PROCESSOR POWER MONITORING DRIVER
 M:	Andreas Herrmann <herrmann.der.user@googlemail.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/fam15h_power
 F:	drivers/hwmon/fam15h_power.c
@@ -779,7 +788,7 @@
 
 APPLE SMC DRIVER
 M:	Henrik Rydberg <rydberg@bitmath.org>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Odd fixes
 F:	drivers/hwmon/applesmc.c
 
@@ -799,7 +808,9 @@
 M:	Keyur Chudgar <kchudgar@apm.com>
 S:	Supported
 F:	drivers/net/ethernet/apm/xgene/
+F:	drivers/net/phy/mdio-xgene.c
 F:	Documentation/devicetree/bindings/net/apm-xgene-enet.txt
+F:	Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
 
 APTINA CAMERA SENSOR PLL
 M:	Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
@@ -1777,7 +1788,7 @@
 
 ASC7621 HARDWARE MONITOR DRIVER
 M:	George Joseph <george.joseph@fairview5.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/asc7621
 F:	drivers/hwmon/asc7621.c
@@ -1864,7 +1875,7 @@
 
 ATK0110 HWMON DRIVER
 M:	Luca Tettamanti <kronos.it@gmail.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/asus_atk0110.c
 
@@ -2029,6 +2040,19 @@
 F:	include/uapi/linux/audit.h
 F:	kernel/audit*
 
+AUFS (advanced multi layered unification filesystem) FILESYSTEM
+M:	"J. R. Okajima" <hooanon05g@gmail.com>
+L:	linux-unionfs@vger.kernel.org
+L:	aufs-users@lists.sourceforge.net (members only)
+W:	http://aufs.sourceforge.net
+T:	git://github.com/sfjro/aufs4-linux.git
+S:	Supported
+F:	Documentation/filesystems/aufs/
+F:	Documentation/ABI/testing/debugfs-aufs
+F:	Documentation/ABI/testing/sysfs-aufs
+F:	fs/aufs/
+F:	include/uapi/linux/aufs_type.h
+
 AUXILIARY DISPLAY DRIVERS
 M:	Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
 W:	http://miguelojeda.es/auxdisplay.htm
@@ -2635,6 +2659,14 @@
 F:	drivers/iio/light/cm*
 F:	Documentation/devicetree/bindings/i2c/trivial-devices.txt
 
+CAVIUM I2C DRIVER
+M:	Jan Glauber <jglauber@cavium.com>
+M:	David Daney <david.daney@cavium.com>
+W:	http://www.cavium.com
+S:	Supported
+F:	drivers/i2c/busses/i2c-octeon*
+F:	drivers/i2c/busses/i2c-thunderx*
+
 CAVIUM LIQUIDIO NETWORK DRIVER
 M:     Derek Chickles <derek.chickles@caviumnetworks.com>
 M:     Satanand Burla <satananda.burla@caviumnetworks.com>
@@ -2984,7 +3016,7 @@
 
 CORETEMP HARDWARE MONITORING DRIVER
 M:	Fenghua Yu <fenghua.yu@intel.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/coretemp
 F:	drivers/hwmon/coretemp.c
@@ -3549,7 +3581,7 @@
 
 DME1737 HARDWARE MONITOR DRIVER
 M:	Juerg Haefliger <juergh@gmail.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/dme1737
 F:	drivers/hwmon/dme1737.c
@@ -4074,6 +4106,12 @@
 S:	Maintained
 F:	drivers/edac/sb_edac.c
 
+EDAC-SKYLAKE
+M:	Tony Luck <tony.luck@intel.com>
+L:	linux-edac@vger.kernel.org
+S:	Maintained
+F:	drivers/edac/skx_edac.c
+
 EDAC-XGENE
 APPLIED MICRO (APM) X-GENE SOC EDAC
 M:     Loc Ho <lho@apm.com>
@@ -4097,8 +4135,8 @@
 F:	arch/ia64/kernel/efi.c
 F:	arch/x86/boot/compressed/eboot.[ch]
 F:	arch/x86/include/asm/efi.h
-F:	arch/x86/platform/efi/*
-F:	drivers/firmware/efi/*
+F:	arch/x86/platform/efi/
+F:	drivers/firmware/efi/
 F:	include/linux/efi*.h
 
 EFI VARIABLE FILESYSTEM
@@ -4116,6 +4154,13 @@
 S:	Maintained
 F:	drivers/video/fbdev/efifb.c
 
+EFI TEST DRIVER
+L:	linux-efi@vger.kernel.org
+M:	Ivan Hu <ivan.hu@canonical.com>
+M:	Matt Fleming <matt@codeblueprint.co.uk>
+S:	Maintained
+F:	drivers/firmware/efi/test/
+
 EFS FILESYSTEM
 W:	http://aeschi.ch.eu.org/efs/
 S:	Orphan
@@ -4262,7 +4307,7 @@
 
 F71805F HARDWARE MONITORING DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/f71805f
 F:	drivers/hwmon/f71805f.c
@@ -4341,7 +4386,7 @@
 
 FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:	Riku Voipio <riku.voipio@iki.fi>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/f75375s.c
 F:	include/linux/f75375s.h
@@ -4883,8 +4928,8 @@
 HARDWARE MONITORING
 M:	Jean Delvare <jdelvare@suse.com>
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
-W:	http://www.lm-sensors.org/
+L:	linux-hwmon@vger.kernel.org
+W:	http://hwmon.wiki.kernel.org/
 T:	quilt http://jdelvare.nerim.net/devel/linux/jdelvare-hwmon/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:	Maintained
@@ -5120,6 +5165,7 @@
 F:	drivers/hid/hid-hyperv.c
 F:	drivers/hv/
 F:	drivers/input/serio/hyperv-keyboard.c
+F:	drivers/pci/host/pci-hyperv.c
 F:	drivers/net/hyperv/
 F:	drivers/scsi/storvsc_drv.c
 F:	drivers/video/fbdev/hyperv_fb.c
@@ -5283,12 +5329,27 @@
 S:	Supported
 F:	drivers/net/ethernet/ibm/ibmveth.*
 
+IBM Power SRIOV Virtual NIC Device Driver
+M:	Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
+M:	John Allen <jallen@linux.vnet.ibm.com>
+L:	netdev@vger.kernel.org
+S:	Supported
+F:	drivers/net/ethernet/ibm/ibmvnic.*
+
 IBM Power Virtual SCSI Device Drivers
 M:	Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
 L:	linux-scsi@vger.kernel.org
 S:	Supported
 F:	drivers/scsi/ibmvscsi/ibmvscsi*
-F:	drivers/scsi/ibmvscsi/viosrp.h
+F:	include/scsi/viosrp.h
+
+IBM Power Virtual SCSI Device Target Driver
+M:	Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+M:	Michael Cyr <mikecyr@linux.vnet.ibm.com>
+L:	linux-scsi@vger.kernel.org
+L:	target-devel@vger.kernel.org
+S:	Supported
+F:	drivers/scsi/ibmvscsi_tgt/
 
 IBM Power Virtual FC Device Drivers
 M:	Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
@@ -5393,7 +5454,7 @@
 
 INA209 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/ina209
 F:	Documentation/devicetree/bindings/i2c/ina209.txt
@@ -5401,7 +5462,7 @@
 
 INA2XX HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/ina2xx
 F:	drivers/hwmon/ina2xx.c
@@ -5502,6 +5563,18 @@
 S:	Supported
 F:	drivers/scsi/isci/
 
+INTEL HID EVENT DRIVER
+M:	Alex Hung <alex.hung@canonical.com>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/intel-hid.c
+
+INTEL VIRTUAL BUTTON DRIVER
+M:	AceLan Kao <acelan.kao@canonical.com>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/intel-vbtn.c
+
 INTEL IDLE DRIVER
 M:	Len Brown <lenb@kernel.org>
 L:	linux-pm@vger.kernel.org
@@ -5684,12 +5757,23 @@
 F:	drivers/dma/mic_x100_dma.h
 F	Documentation/mic/
 
-INTEL PMC IPC DRIVER
+INTEL PMC/P-Unit IPC DRIVER
 M:	Zha Qipeng<qipeng.zha@intel.com>
 L:	platform-driver-x86@vger.kernel.org
 S:	Maintained
 F:	drivers/platform/x86/intel_pmc_ipc.c
+F:	drivers/platform/x86/intel_punit_ipc.c
 F:	arch/x86/include/asm/intel_pmc_ipc.h
+F:	arch/x86/include/asm/intel_punit_ipc.h
+
+INTEL TELEMETRY DRIVER
+M:	Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/intel_telemetry_core.c
+F:	arch/x86/include/asm/intel_telemetry.h
+F:	drivers/platform/x86/intel_telemetry_pltdrv.c
+F:	drivers/platform/x86/intel_telemetry_debugfs.c
 
 IOC3 ETHERNET DRIVER
 M:	Ralf Baechle <ralf@linux-mips.org>
@@ -5884,7 +5968,7 @@
 
 IT87 HARDWARE MONITORING DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/it87
 F:	drivers/hwmon/it87.c
@@ -5920,7 +6004,7 @@
 
 JC42.4 TEMPERATURE SENSOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/jc42.c
 F:	Documentation/hwmon/jc42
@@ -5970,14 +6054,14 @@
 
 K10TEMP HARDWARE MONITORING DRIVER
 M:	Clemens Ladisch <clemens@ladisch.de>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/k10temp
 F:	drivers/hwmon/k10temp.c
 
 K8TEMP HARDWARE MONITORING DRIVER
 M:	Rudolf Marek <r.marek@assembler.cz>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/k8temp
 F:	drivers/hwmon/k8temp.c
@@ -6485,27 +6569,27 @@
 
 LM73 HARDWARE MONITOR DRIVER
 M:	Guillaume Ligneul <guillaume.ligneul@gmail.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/lm73.c
 
 LM78 HARDWARE MONITOR DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/lm78
 F:	drivers/hwmon/lm78.c
 
 LM83 HARDWARE MONITOR DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/lm83
 F:	drivers/hwmon/lm83.c
 
 LM90 HARDWARE MONITOR DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/lm90
 F:	Documentation/devicetree/bindings/hwmon/lm90.txt
@@ -6513,7 +6597,7 @@
 
 LM95234 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/lm95234
 F:	drivers/hwmon/lm95234.c
@@ -6580,7 +6664,7 @@
 
 LTC4261 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/ltc4261
 F:	drivers/hwmon/ltc4261.c
@@ -6749,28 +6833,28 @@
 
 MAX16065 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/max16065
 F:	drivers/hwmon/max16065.c
 
 MAX20751 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/max20751
 F:	drivers/hwmon/max20751.c
 
 MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:	"Hans J. Koch" <hjk@hansjkoch.de>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/max6650
 F:	drivers/hwmon/max6650.c
 
 MAX6697 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/max6697
 F:	Documentation/devicetree/bindings/i2c/max6697.txt
@@ -7303,7 +7387,7 @@
 
 NCT6775 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/nct6775
 F:	drivers/hwmon/nct6775.c
@@ -7586,6 +7670,12 @@
 T:	git git://github.com/jonmason/ntb.git
 F:	drivers/ntb/hw/intel/
 
+NTB AMD DRIVER
+M:	Xiangliang Yu <Xiangliang.Yu@amd.com>
+L:	linux-ntb@googlegroups.com
+S:	Supported
+F:	drivers/ntb/hw/amd/
+
 NTFS FILESYSTEM
 M:	Anton Altaparmakov <anton@tuxera.com>
 L:	linux-ntfs-dev@lists.sourceforge.net
@@ -8064,7 +8154,7 @@
 
 PC87360 HARDWARE MONITORING DRIVER
 M:	Jim Cromie <jim.cromie@gmail.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/pc87360
 F:	drivers/hwmon/pc87360.c
@@ -8076,7 +8166,7 @@
 
 PC87427 HARDWARE MONITORING DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/pc87427
 F:	drivers/hwmon/pc87427.c
@@ -8217,6 +8307,7 @@
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	Documentation/devicetree/bindings/pci/host-generic-pci.txt
+F:	drivers/pci/host/pci-host-common.c
 F:	drivers/pci/host/pci-host-generic.c
 
 PCIE DRIVER FOR ST SPEAR13XX
@@ -8248,6 +8339,14 @@
 F:	Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
 F:	drivers/pci/host/pcie-hisi.c
 
+PCIE DRIVER FOR CAVIUM THUNDERX
+M:	David Daney <david.daney@cavium.com>
+L:	linux-pci@vger.kernel.org
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Supported
+F:	Documentation/devicetree/bindings/pci/pci-thunder-*
+F:	drivers/pci/host/pci-thunder-*
+
 PCMCIA SUBSYSTEM
 P:	Linux PCMCIA Team
 L:	linux-pcmcia@lists.infradead.org
@@ -8415,8 +8514,8 @@
 
 PMBUS HARDWARE MONITORING DRIVERS
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
-W:	http://www.lm-sensors.org/
+L:	linux-hwmon@vger.kernel.org
+W:	http://hwmon.wiki.kernel.org/
 W:	http://www.roeck-us.net/linux/drivers/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:	Maintained
@@ -8610,7 +8709,7 @@
 
 PWM FAN DRIVER
 M:	Kamil Debski <k.debski@samsung.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/hwmon/pwm-fan.txt
 F:	Documentation/hwmon/pwm-fan
@@ -9749,6 +9848,13 @@
 F:	arch/arm/mach-s3c24xx/bast-ide.c
 F:	arch/arm/mach-s3c24xx/bast-irq.c
 
+SIPHASH PRF ROUTINES
+M:	Jason A. Donenfeld <Jason@zx2c4.com>
+S:	Maintained
+F:	lib/siphash.c
+F:	lib/test_siphash.c
+F:	include/linux/siphash.h
+
 TI DAVINCI MACHINE SUPPORT
 M:	Sekhar Nori <nsekhar@ti.com>
 M:	Kevin Hilman <khilman@deeprootsystems.com>
@@ -9882,28 +9988,28 @@
 
 SMM665 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/smm665
 F:	drivers/hwmon/smm665.c
 
 SMSC EMC2103 HARDWARE MONITOR DRIVER
 M:	Steve Glendinning <steve.glendinning@shawell.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/emc2103
 F:	drivers/hwmon/emc2103.c
 
 SMSC SCH5627 HARDWARE MONITOR DRIVER
 M:	Hans de Goede <hdegoede@redhat.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Supported
 F:	Documentation/hwmon/sch5627
 F:	drivers/hwmon/sch5627.c
 
 SMSC47B397 HARDWARE MONITOR DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/smsc47b397
 F:	drivers/hwmon/smsc47b397.c
@@ -10135,6 +10241,7 @@
 
 STABLE BRANCH
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+M:	Sasha Levin <sashal@kernel.org>
 L:	stable@vger.kernel.org
 S:	Supported
 F:	Documentation/stable_kernel_rules.txt
@@ -10289,9 +10396,11 @@
 F:	drivers/net/ethernet/dlink/sundance.c
 
 SUPERH
+M:	Yoshinori Sato <ysato@users.sourceforge.jp>
+M:	Rich Felker <dalias@libc.org>
 L:	linux-sh@vger.kernel.org
 Q:	http://patchwork.kernel.org/project/linux-sh/list/
-S:	Orphan
+S:	Maintained
 F:	Documentation/sh/
 F:	arch/sh/
 F:	drivers/sh/
@@ -10828,7 +10937,7 @@
 
 TMP401 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/tmp401
 F:	drivers/hwmon/tmp401.c
@@ -11090,13 +11199,6 @@
 S:	Maintained
 F:	drivers/net/usb/dm9601.c
 
-USB DIAMOND RIO500 DRIVER
-M:	Cesar Miquel <miquel@df.uba.ar>
-L:	rio500-users@lists.sourceforge.net
-W:	http://rio500.sourceforge.net
-S:	Maintained
-F:	drivers/usb/misc/rio500*
-
 USB EHCI DRIVER
 M:	Alan Stern <stern@rowland.harvard.edu>
 L:	linux-usb@vger.kernel.org
@@ -11562,14 +11664,14 @@
 
 VT1211 HARDWARE MONITOR DRIVER
 M:	Juerg Haefliger <juergh@gmail.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/vt1211
 F:	drivers/hwmon/vt1211.c
 
 VT8231 HARDWARE MONITOR DRIVER
 M:	Roger Lucas <vt8231@hiddenengine.co.uk>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/vt8231.c
 
@@ -11588,21 +11690,21 @@
 
 W83791D HARDWARE MONITORING DRIVER
 M:	Marc Hulsman <m.hulsman@tudelft.nl>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/w83791d
 F:	drivers/hwmon/w83791d.c
 
 W83793 HARDWARE MONITORING DRIVER
 M:	Rudolf Marek <r.marek@assembler.cz>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	Documentation/hwmon/w83793
 F:	drivers/hwmon/w83793.c
 
 W83795 HARDWARE MONITORING DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
-L:	lm-sensors@lm-sensors.org
+L:	linux-hwmon@vger.kernel.org
 S:	Maintained
 F:	drivers/hwmon/w83795.c
 
--- linux-4.4.0.orig/Makefile
+++ linux-4.4.0/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 4
-SUBLEVEL = 0
+SUBLEVEL = 262
 EXTRAVERSION =
 NAME = Blurry Fish Butt
 
@@ -87,10 +87,12 @@
 ifneq ($(filter 4.%,$(MAKE_VERSION)),)	# make-4
 ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
   quiet=silent_
+  tools_silent=s
 endif
 else					# make-3.8x
 ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
   quiet=silent_
+  tools_silent=-s
 endif
 endif
 
@@ -128,6 +130,10 @@
 # Cancel implicit rules on top Makefile
 $(CURDIR)/Makefile Makefile: ;
 
+ifneq ($(words $(subst :, ,$(CURDIR))), 1)
+  $(error main directory cannot contain spaces nor colons)
+endif
+
 ifneq ($(KBUILD_OUTPUT),)
 # Invoke a second make in the output directory, passing relevant variables
 # check that the output directory actually exists
@@ -297,14 +303,9 @@
 
 HOSTCC       = gcc
 HOSTCXX      = g++
-HOSTCFLAGS   = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
+HOSTCFLAGS   := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
 HOSTCXXFLAGS = -O2
 
-ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1)
-HOSTCFLAGS  += -Wno-unused-value -Wno-unused-parameter \
-		-Wno-missing-field-initializers -fno-delete-null-pointer-checks
-endif
-
 # Decide whether to build built-in, modular, or both.
 # Normally, just do built-in.
 
@@ -312,12 +313,8 @@
 KBUILD_BUILTIN := 1
 
 # If we have only "make modules", don't compile built-in objects.
-# When we're building modules with modversions, we need to consider
-# the built-in objects during the descend as well, in order to
-# make sure the checksums are up to date before we record them.
-
 ifeq ($(MAKECMDGOALS),modules)
-  KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
+  KBUILD_BUILTIN :=
 endif
 
 # If we have "make <whatever> modules", compile modules
@@ -352,7 +349,7 @@
 AWK		= awk
 GENKSYMS	= scripts/genksyms/genksyms
 INSTALLKERNEL  := installkernel
-DEPMOD		= /sbin/depmod
+DEPMOD		= depmod
 PERL		= perl
 PYTHON		= python
 CHECK		= sparse
@@ -364,8 +361,14 @@
 LDFLAGS_MODULE  =
 CFLAGS_KERNEL	=
 AFLAGS_KERNEL	=
-CFLAGS_GCOV	= -fprofile-arcs -ftest-coverage
+CFLAGS_GCOV	= -fprofile-arcs -ftest-coverage -fno-tree-loop-im
 
+# Prefer linux-backports-modules
+ifneq ($(KBUILD_SRC),)
+ifneq ($(shell if test -e $(KBUILD_OUTPUT)/ubuntu-build; then echo yes; fi),yes)
+UBUNTUINCLUDE := -I/usr/src/linux-headers-lbm-$(KERNELRELEASE)
+endif
+endif
 
 # Use USERINCLUDE when you must reference the UAPI directories only.
 USERINCLUDE    := \
@@ -378,6 +381,7 @@
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
 LINUXINCLUDE    := \
+		$(UBUNTUINCLUDE) \
 		-I$(srctree)/arch/$(hdr-arch)/include \
 		-Iarch/$(hdr-arch)/include/generated/uapi \
 		-Iarch/$(hdr-arch)/include/generated \
@@ -385,17 +389,21 @@
 		-Iinclude \
 		$(USERINCLUDE)
 
+# UBUNTU: Include our third party driver stuff too
+LINUXINCLUDE   += -Iubuntu/include $(if $(KBUILD_SRC),-I$(srctree)/ubuntu/include)
+
 KBUILD_CPPFLAGS := -D__KERNEL__
 
 KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
 		   -fno-strict-aliasing -fno-common \
 		   -Werror-implicit-function-declaration \
 		   -Wno-format-security \
-		   -std=gnu89
+		   -std=gnu89 $(call cc-option,-fno-PIE)
+
 
 KBUILD_AFLAGS_KERNEL :=
 KBUILD_CFLAGS_KERNEL :=
-KBUILD_AFLAGS   := -D__ASSEMBLY__
+KBUILD_AFLAGS   := -D__ASSEMBLY__ $(call cc-option,-fno-PIE)
 KBUILD_AFLAGS_MODULE  := -DMODULE
 KBUILD_CFLAGS_MODULE  := -DMODULE
 KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
@@ -411,7 +419,8 @@
 export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
 
 export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
-export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN
+export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV
+export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE
 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
@@ -495,6 +504,12 @@
                 endif
         endif
 endif
+# install and module_install need also be processed one by one
+ifneq ($(filter install,$(MAKECMDGOALS)),)
+        ifneq ($(filter modules_install,$(MAKECMDGOALS)),)
+	        mixed-targets := 1
+        endif
+endif
 
 ifeq ($(mixed-targets),1)
 # ===========================================================================
@@ -546,7 +561,7 @@
 
 # Objects we will link into vmlinux / subdirs we need to visit
 init-y		:= init/
-drivers-y	:= drivers/ sound/ firmware/
+drivers-y	:= drivers/ sound/ firmware/ ubuntu/
 net-y		:= net/
 libs-y		:= lib/
 core-y		:= usr/
@@ -598,6 +613,28 @@
 # Defaults to vmlinux, but the arch makefile usually adds further targets
 all: vmlinux
 
+ifeq ($(cc-name),clang)
+ifneq ($(CROSS_COMPILE),)
+CLANG_TARGET	:= --target=$(notdir $(CROSS_COMPILE:%-=%))
+GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)elfedit))
+CLANG_PREFIX	:= --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE))
+GCC_TOOLCHAIN	:= $(realpath $(GCC_TOOLCHAIN_DIR)/..)
+endif
+ifneq ($(GCC_TOOLCHAIN),)
+CLANG_GCC_TC	:= --gcc-toolchain=$(GCC_TOOLCHAIN)
+endif
+KBUILD_CFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) $(CLANG_PREFIX)
+KBUILD_AFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) $(CLANG_PREFIX)
+KBUILD_CFLAGS += $(call cc-option, -no-integrated-as)
+KBUILD_AFLAGS += $(call cc-option, -no-integrated-as)
+endif
+
+# force no-pie for distro compilers that enable pie by default
+KBUILD_CFLAGS += $(call cc-option, -fno-pie)
+KBUILD_CFLAGS += $(call cc-option, -no-pie)
+KBUILD_AFLAGS += $(call cc-option, -fno-pie)
+KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)
+
 # The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default
 # values of the respective KBUILD_* variables
 ARCH_CPPFLAGS :=
@@ -606,15 +643,32 @@
 include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS	+= $(call cc-option,-fno-delete-null-pointer-checks,)
+KBUILD_CFLAGS	+= $(call cc-disable-warning,frame-address,)
+KBUILD_CFLAGS	+= $(call cc-disable-warning, format-truncation)
+KBUILD_CFLAGS	+= $(call cc-disable-warning, format-overflow)
+KBUILD_CFLAGS	+= $(call cc-disable-warning, int-in-bool-context)
+KBUILD_CFLAGS	+= $(call cc-disable-warning, address-of-packed-member)
+KBUILD_CFLAGS	+= $(call cc-disable-warning, attribute-alias)
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS	+= -Os $(call cc-disable-warning,maybe-uninitialized,)
+KBUILD_CFLAGS	+= -Os
 else
+ifdef CONFIG_PROFILE_ALL_BRANCHES
 KBUILD_CFLAGS	+= -O2
+else
+KBUILD_CFLAGS   += -O2
+endif
 endif
 
 # Tell gcc to never replace conditional load with a non-conditional one
 KBUILD_CFLAGS	+= $(call cc-option,--param=allow-store-data-races=0)
+KBUILD_CFLAGS	+= $(call cc-option,-fno-allow-store-data-races)
+
+# check for 'asm goto'
+ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y)
+	KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
+	KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO
+endif
 
 ifdef CONFIG_READABLE_ASM
 # Disable optimizations that make assembler listings hard to read.
@@ -669,8 +723,6 @@
 
 ifeq ($(cc-name),clang)
 KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,)
-KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,)
-KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable)
 KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier)
 KBUILD_CFLAGS += $(call cc-disable-warning, gnu)
 # Quiet clang warning: comparison of unsigned expression < 0 is always false
@@ -682,11 +734,12 @@
 KBUILD_CFLAGS += $(call cc-option, -fcatch-undefined-behavior)
 else
 
-# This warning generated too much noise in a regular build.
-# Use make W=1 to enable this warning (see scripts/Makefile.build)
+# These warnings generated too much noise in a regular build.
+# Use make W=1 to enable them (see scripts/Makefile.extrawarn)
 KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
 endif
 
+KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable)
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS	+= -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
@@ -723,6 +776,13 @@
 ifndef CC_FLAGS_FTRACE
 CC_FLAGS_FTRACE := -pg
 endif
+ifdef CONFIG_FTRACE_MCOUNT_RECORD
+  # gcc 5 supports generating the mcount tables directly
+  ifeq ($(call cc-option-yn,-mrecord-mcount),y)
+    CC_FLAGS_FTRACE	+= -mrecord-mcount
+    export CC_USING_RECORD_MCOUNT := 1
+  endif
+endif
 export CC_FLAGS_FTRACE
 ifdef CONFIG_HAVE_FENTRY
 CC_USING_FENTRY	:= $(call cc-option, -mfentry -DCC_USING_FENTRY)
@@ -752,9 +812,35 @@
 # disable pointer signed / unsigned warnings in gcc 4.0
 KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign)
 
+# disable stringop warnings in gcc 8+
+KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation)
+
+# We'll want to enable this eventually, but it's not going away for 5.7 at least
+KBUILD_CFLAGS += $(call cc-disable-warning, zero-length-bounds)
+KBUILD_CFLAGS += $(call cc-disable-warning, array-bounds)
+KBUILD_CFLAGS += $(call cc-disable-warning, stringop-overflow)
+
+# Another good warning that we'll want to enable eventually
+KBUILD_CFLAGS += $(call cc-disable-warning, restrict)
+
+# Enabled with W=2, disabled by default as noisy
+KBUILD_CFLAGS += $(call cc-disable-warning, maybe-uninitialized)
+
 # disable invalid "can't wrap" optimizations for signed / pointers
 KBUILD_CFLAGS	+= $(call cc-option,-fno-strict-overflow)
 
+# clang sets -fmerge-all-constants by default as optimization, but this
+# is non-conforming behavior for C and in fact breaks the kernel, so we
+# need to disable it here generally.
+KBUILD_CFLAGS	+= $(call cc-option,-fno-merge-all-constants)
+
+# for gcc -fno-merge-all-constants disables everything, but it is fine
+# to have actual conforming behavior enabled.
+KBUILD_CFLAGS	+= $(call cc-option,-fmerge-constants)
+
+# Make sure -fstack-check isn't enabled (like gentoo apparently did)
+KBUILD_CFLAGS  += $(call cc-option,-fno-stack-check,)
+
 # conserve stack if available
 KBUILD_CFLAGS   += $(call cc-option,-fconserve-stack)
 
@@ -770,12 +856,6 @@
 # use the deterministic mode of AR if available
 KBUILD_ARFLAGS := $(call ar-option,D)
 
-# check for 'asm goto'
-ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
-	KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
-	KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO
-endif
-
 include scripts/Makefile.kasan
 include scripts/Makefile.extrawarn
 
@@ -1005,7 +1085,7 @@
 
 define filechk_version.h
 	(echo \#define LINUX_VERSION_CODE $(shell                         \
-	expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
+	expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 255); \
 	echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
 endef
 
@@ -1060,6 +1140,7 @@
 	  $(error Headers not exportable for the $(SRCARCH) architecture))
 	$(Q)$(MAKE) $(hdr-inst)=include/uapi
 	$(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst)
+	$(Q)$(MAKE) $(hdr-inst)=ubuntu/include dst=include oldheaders=
 
 PHONY += headers_check_all
 headers_check_all: headers_install_all
@@ -1069,6 +1150,7 @@
 headers_check: headers_install
 	$(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1
 	$(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst) HDRCHECK=1
+	$(Q)$(MAKE) $(hdr-inst)=ubuntu/include dst=include oldheaders= HDRCHECK=1
 
 # ---------------------------------------------------------------------------
 # Kernel selftest
@@ -1089,6 +1171,13 @@
 
 all: modules
 
+# When we're building modules with modversions, we need to consider
+# the built-in objects during the descend as well, in order to
+# make sure the checksums are up to date before we record them.
+ifdef CONFIG_MODVERSIONS
+  KBUILD_BUILTIN := 1
+endif
+
 # Build modules
 #
 # A module can be listed more than once in obj-m resulting in
@@ -1259,7 +1348,9 @@
 	@echo  '  firmware_install- Install all firmware to INSTALL_FW_PATH'
 	@echo  '                    (default: $$(INSTALL_MOD_PATH)/lib/firmware)'
 	@echo  '  dir/            - Build all files in dir and below'
-	@echo  '  dir/file.[oisS] - Build specified target only'
+	@echo  '  dir/file.[ois]  - Build specified target only'
+	@echo  '  dir/file.ll     - Build the LLVM assembly file'
+	@echo  '                    (requires compiler support for LLVM assembly generation)'
 	@echo  '  dir/file.lst    - Build specified mixed source/assembly target only'
 	@echo  '                    (requires a recent binutils and recent build (System.map))'
 	@echo  '  dir/file.ko     - Build module including final link'
@@ -1366,9 +1457,6 @@
 
 # We are always building modules
 KBUILD_MODULES := 1
-PHONY += crmodverdir
-crmodverdir:
-	$(cmd_crmodverdir)
 
 PHONY += $(objtree)/Module.symvers
 $(objtree)/Module.symvers:
@@ -1380,7 +1468,7 @@
 
 module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
 PHONY += $(module-dirs) modules
-$(module-dirs): crmodverdir $(objtree)/Module.symvers
+$(module-dirs): prepare $(objtree)/Module.symvers
 	$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
 
 modules: $(module-dirs)
@@ -1420,7 +1508,8 @@
 
 # Dummies...
 PHONY += prepare scripts
-prepare: ;
+prepare:
+	$(cmd_crmodverdir)
 scripts: ;
 endif # KBUILD_EXTMOD
 
@@ -1435,6 +1524,7 @@
 		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
 		-o -name '*.symtypes' -o -name 'modules.order' \
 		-o -name modules.builtin -o -name '.tmp_*.o.*' \
+		-o -name '*.ll' \
 		-o -name '*.gcno' \) -type f -print | xargs rm -f
 
 # Generate tags for editors
@@ -1499,11 +1589,11 @@
 # Clear a bunch of variables before executing the submake
 tools/: FORCE
 	$(Q)mkdir -p $(objtree)/tools
-	$(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/
+	$(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/
 
 tools/%: FORCE
 	$(Q)mkdir -p $(objtree)/tools
-	$(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/ $*
+	$(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/ $*
 
 # Single targets
 # ---------------------------------------------------------------------------
@@ -1538,20 +1628,19 @@
 	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
 %.symtypes: %.c prepare scripts FORCE
 	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.ll: %.c prepare scripts FORCE
+	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
 
 # Modules
 /: prepare scripts FORCE
-	$(cmd_crmodverdir)
 	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
 	$(build)=$(build-dir)
 # Make sure the latest headers are built for Documentation
 Documentation/: headers_install
 %/: prepare scripts FORCE
-	$(cmd_crmodverdir)
 	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
 	$(build)=$(build-dir)
 %.ko: prepare scripts FORCE
-	$(cmd_crmodverdir)
 	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1)   \
 	$(build)=$(build-dir) $(@:.ko=.o)
 	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
--- linux-4.4.0.orig/Ubuntu.md
+++ linux-4.4.0/Ubuntu.md
@@ -0,0 +1,8 @@
+Name:    linux
+Version: 4.4.0
+Series:  16.04 (xenial)
+Description:
+    This is the source code for the Ubuntu linux kernel for the 16.04 series. This
+    source tree is used to produce the flavours: generic, lowlatency.
+    This kernel is configured to support the widest range of desktop, laptop and
+    server configurations.
--- linux-4.4.0.orig/arch/Kconfig
+++ linux-4.4.0/arch/Kconfig
@@ -5,6 +5,9 @@
 config KEXEC_CORE
 	bool
 
+config HOTPLUG_SMT
+	bool
+
 config OPROFILE
 	tristate "OProfile system profiling"
 	depends on PROFILING
@@ -217,6 +220,9 @@
 config GENERIC_IDLE_POLL_SETUP
        bool
 
+config ARCH_HAS_CPU_FINALIZE_INIT
+	bool
+
 # Select if arch init_task initializer is different to init/init_task.c
 config ARCH_INIT_TASK
        bool
--- linux-4.4.0.orig/arch/alpha/include/asm/Kbuild
+++ linux-4.4.0/arch/alpha/include/asm/Kbuild
@@ -3,6 +3,7 @@
 generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += exec.h
+generic-y += export.h
 generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
--- linux-4.4.0.orig/arch/alpha/include/asm/futex.h
+++ linux-4.4.0/arch/alpha/include/asm/futex.h
@@ -29,18 +29,10 @@
 	:	"r" (uaddr), "r"(oparg)				\
 	:	"memory")
 
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -66,17 +58,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/alpha/include/asm/io.h
+++ linux-4.4.0/arch/alpha/include/asm/io.h
@@ -491,10 +491,10 @@
 }
 #endif
 
-#define ioread16be(p) be16_to_cpu(ioread16(p))
-#define ioread32be(p) be32_to_cpu(ioread32(p))
-#define iowrite16be(v,p) iowrite16(cpu_to_be16(v), (p))
-#define iowrite32be(v,p) iowrite32(cpu_to_be32(v), (p))
+#define ioread16be(p) swab16(ioread16(p))
+#define ioread32be(p) swab32(ioread32(p))
+#define iowrite16be(v,p) iowrite16(swab16(v), (p))
+#define iowrite32be(v,p) iowrite32(swab32(v), (p))
 
 #define inb_p		inb
 #define inw_p		inw
--- linux-4.4.0.orig/arch/alpha/include/asm/irq.h
+++ linux-4.4.0/arch/alpha/include/asm/irq.h
@@ -55,15 +55,15 @@
 
 #elif defined(CONFIG_ALPHA_DP264) || \
       defined(CONFIG_ALPHA_LYNX)  || \
-      defined(CONFIG_ALPHA_SHARK) || \
-      defined(CONFIG_ALPHA_EIGER)
+      defined(CONFIG_ALPHA_SHARK)
 # define NR_IRQS	64
 
 #elif defined(CONFIG_ALPHA_TITAN)
 #define NR_IRQS		80
 
 #elif defined(CONFIG_ALPHA_RAWHIDE) || \
-	defined(CONFIG_ALPHA_TAKARA)
+      defined(CONFIG_ALPHA_TAKARA) || \
+      defined(CONFIG_ALPHA_EIGER)
 # define NR_IRQS	128
 
 #elif defined(CONFIG_ALPHA_WILDFIRE)
--- linux-4.4.0.orig/arch/alpha/include/asm/mmu_context.h
+++ linux-4.4.0/arch/alpha/include/asm/mmu_context.h
@@ -7,6 +7,7 @@
  * Copyright (C) 1996, Linus Torvalds
  */
 
+#include <linux/sched.h>
 #include <asm/machvec.h>
 #include <asm/compiler.h>
 #include <asm-generic/mm_hooks.h>
--- linux-4.4.0.orig/arch/alpha/include/asm/termios.h
+++ linux-4.4.0/arch/alpha/include/asm/termios.h
@@ -72,9 +72,15 @@
 })
 
 #define user_termios_to_kernel_termios(k, u) \
-	copy_from_user(k, u, sizeof(struct termios))
+	copy_from_user(k, u, sizeof(struct termios2))
 
 #define kernel_termios_to_user_termios(u, k) \
+	copy_to_user(u, k, sizeof(struct termios2))
+
+#define user_termios_to_kernel_termios_1(k, u) \
+	copy_from_user(k, u, sizeof(struct termios))
+
+#define kernel_termios_to_user_termios_1(u, k) \
 	copy_to_user(u, k, sizeof(struct termios))
 
 #endif	/* _ALPHA_TERMIOS_H */
--- linux-4.4.0.orig/arch/alpha/include/asm/types.h
+++ linux-4.4.0/arch/alpha/include/asm/types.h
@@ -1,6 +1,6 @@
 #ifndef _ALPHA_TYPES_H
 #define _ALPHA_TYPES_H
 
-#include <asm-generic/int-ll64.h>
+#include <uapi/asm/types.h>
 
 #endif /* _ALPHA_TYPES_H */
--- linux-4.4.0.orig/arch/alpha/include/asm/uaccess.h
+++ linux-4.4.0/arch/alpha/include/asm/uaccess.h
@@ -341,86 +341,42 @@
  * Complex access routines
  */
 
-/* This little bit of silliness is to get the GP loaded for a function
-   that ordinarily wouldn't.  Otherwise we could have it done by the macro
-   directly, which can be optimized the linker.  */
-#ifdef MODULE
-#define __module_address(sym)		"r"(sym),
-#define __module_call(ra, arg, sym)	"jsr $" #ra ",(%" #arg ")," #sym
-#else
-#define __module_address(sym)
-#define __module_call(ra, arg, sym)	"bsr $" #ra "," #sym " !samegp"
-#endif
+extern long __copy_user(void *to, const void *from, long len);
 
-extern void __copy_user(void);
-
-extern inline long
-__copy_tofrom_user_nocheck(void *to, const void *from, long len)
-{
-	register void * __cu_to __asm__("$6") = to;
-	register const void * __cu_from __asm__("$7") = from;
-	register long __cu_len __asm__("$0") = len;
-
-	__asm__ __volatile__(
-		__module_call(28, 3, __copy_user)
-		: "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to)
-		: __module_address(__copy_user)
-		  "0" (__cu_len), "1" (__cu_from), "2" (__cu_to)
-		: "$1", "$2", "$3", "$4", "$5", "$28", "memory");
-
-	return __cu_len;
-}
-
-extern inline long
-__copy_tofrom_user(void *to, const void *from, long len, const void __user *validate)
-{
-	if (__access_ok((unsigned long)validate, len, get_fs()))
-		len = __copy_tofrom_user_nocheck(to, from, len);
-	return len;
-}
-
-#define __copy_to_user(to, from, n)					\
-({									\
-	__chk_user_ptr(to);						\
-	__copy_tofrom_user_nocheck((__force void *)(to), (from), (n));	\
+#define __copy_to_user(to, from, n)			\
+({							\
+	__chk_user_ptr(to);				\
+	__copy_user((__force void *)(to), (from), (n));	\
 })
-#define __copy_from_user(to, from, n)					\
-({									\
-	__chk_user_ptr(from);						\
-	__copy_tofrom_user_nocheck((to), (__force void *)(from), (n));	\
+#define __copy_from_user(to, from, n)			\
+({							\
+	__chk_user_ptr(from);				\
+	__copy_user((to), (__force void *)(from), (n));	\
 })
 
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
 
-
 extern inline long
 copy_to_user(void __user *to, const void *from, long n)
 {
-	return __copy_tofrom_user((__force void *)to, from, n, to);
+	if (likely(__access_ok((unsigned long)to, n, get_fs())))
+		n = __copy_user((__force void *)to, from, n);
+	return n;
 }
 
 extern inline long
 copy_from_user(void *to, const void __user *from, long n)
 {
-	return __copy_tofrom_user(to, (__force void *)from, n, from);
+	long res = n;
+	if (likely(__access_ok((unsigned long)from, n, get_fs())))
+		res = __copy_from_user_inatomic(to, from, n);
+	if (unlikely(res))
+		memset(to + (n - res), 0, res);
+	return res;
 }
 
-extern void __do_clear_user(void);
-
-extern inline long
-__clear_user(void __user *to, long len)
-{
-	register void __user * __cl_to __asm__("$6") = to;
-	register long __cl_len __asm__("$0") = len;
-	__asm__ __volatile__(
-		__module_call(28, 2, __do_clear_user)
-		: "=r"(__cl_len), "=r"(__cl_to)
-		: __module_address(__do_clear_user)
-		  "0"(__cl_len), "1"(__cl_to)
-		: "$1", "$2", "$3", "$4", "$5", "$28", "memory");
-	return __cl_len;
-}
+extern long __clear_user(void __user *to, long len);
 
 extern inline long
 clear_user(void __user *to, long len)
@@ -430,9 +386,6 @@
 	return len;
 }
 
-#undef __module_address
-#undef __module_call
-
 #define user_addr_max() \
         (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)
 
--- linux-4.4.0.orig/arch/alpha/include/asm/xchg.h
+++ linux-4.4.0/arch/alpha/include/asm/xchg.h
@@ -11,6 +11,10 @@
  * Atomic exchange.
  * Since it can be used to implement critical sections
  * it must clobber "memory" (also for interrupts in UP).
+ *
+ * The leading and the trailing memory barriers guarantee that these
+ * operations are fully ordered.
+ *
  */
 
 static inline unsigned long
@@ -18,6 +22,7 @@
 {
 	unsigned long ret, tmp, addr64;
 
+	smp_mb();
 	__asm__ __volatile__(
 	"	andnot	%4,7,%3\n"
 	"	insbl	%1,%4,%1\n"
@@ -42,6 +47,7 @@
 {
 	unsigned long ret, tmp, addr64;
 
+	smp_mb();
 	__asm__ __volatile__(
 	"	andnot	%4,7,%3\n"
 	"	inswl	%1,%4,%1\n"
@@ -66,6 +72,7 @@
 {
 	unsigned long dummy;
 
+	smp_mb();
 	__asm__ __volatile__(
 	"1:	ldl_l %0,%4\n"
 	"	bis $31,%3,%1\n"
@@ -86,6 +93,7 @@
 {
 	unsigned long dummy;
 
+	smp_mb();
 	__asm__ __volatile__(
 	"1:	ldq_l %0,%4\n"
 	"	bis $31,%3,%1\n"
@@ -127,10 +135,12 @@
  * store NEW in MEM.  Return the initial value in MEM.  Success is
  * indicated by comparing RETURN with OLD.
  *
- * The memory barrier should be placed in SMP only when we actually
- * make the change. If we don't change anything (so if the returned
- * prev is equal to old) then we aren't acquiring anything new and
- * we don't need any memory barrier as far I can tell.
+ * The leading and the trailing memory barriers guarantee that these
+ * operations are fully ordered.
+ *
+ * The trailing memory barrier is placed in SMP unconditionally, in
+ * order to guarantee that dependency ordering is preserved when a
+ * dependency is headed by an unsuccessful operation.
  */
 
 static inline unsigned long
@@ -138,6 +148,7 @@
 {
 	unsigned long prev, tmp, cmp, addr64;
 
+	smp_mb();
 	__asm__ __volatile__(
 	"	andnot	%5,7,%4\n"
 	"	insbl	%1,%5,%1\n"
@@ -149,8 +160,8 @@
 	"	or	%1,%2,%2\n"
 	"	stq_c	%2,0(%4)\n"
 	"	beq	%2,3f\n"
-		__ASM__MB
 	"2:\n"
+		__ASM__MB
 	".subsection 2\n"
 	"3:	br	1b\n"
 	".previous"
@@ -165,6 +176,7 @@
 {
 	unsigned long prev, tmp, cmp, addr64;
 
+	smp_mb();
 	__asm__ __volatile__(
 	"	andnot	%5,7,%4\n"
 	"	inswl	%1,%5,%1\n"
@@ -176,8 +188,8 @@
 	"	or	%1,%2,%2\n"
 	"	stq_c	%2,0(%4)\n"
 	"	beq	%2,3f\n"
-		__ASM__MB
 	"2:\n"
+		__ASM__MB
 	".subsection 2\n"
 	"3:	br	1b\n"
 	".previous"
@@ -192,6 +204,7 @@
 {
 	unsigned long prev, cmp;
 
+	smp_mb();
 	__asm__ __volatile__(
 	"1:	ldl_l %0,%5\n"
 	"	cmpeq %0,%3,%1\n"
@@ -199,8 +212,8 @@
 	"	mov %4,%1\n"
 	"	stl_c %1,%2\n"
 	"	beq %1,3f\n"
-		__ASM__MB
 	"2:\n"
+		__ASM__MB
 	".subsection 2\n"
 	"3:	br 1b\n"
 	".previous"
@@ -215,6 +228,7 @@
 {
 	unsigned long prev, cmp;
 
+	smp_mb();
 	__asm__ __volatile__(
 	"1:	ldq_l %0,%5\n"
 	"	cmpeq %0,%3,%1\n"
@@ -222,8 +236,8 @@
 	"	mov %4,%1\n"
 	"	stq_c %1,%2\n"
 	"	beq %1,3f\n"
-		__ASM__MB
 	"2:\n"
+		__ASM__MB
 	".subsection 2\n"
 	"3:	br 1b\n"
 	".previous"
--- linux-4.4.0.orig/arch/alpha/include/uapi/asm/ioctls.h
+++ linux-4.4.0/arch/alpha/include/uapi/asm/ioctls.h
@@ -31,6 +31,11 @@
 #define TCXONC		_IO('t', 30)
 #define TCFLSH		_IO('t', 31)
 
+#define TCGETS2		_IOR('T', 42, struct termios2)
+#define TCSETS2		_IOW('T', 43, struct termios2)
+#define TCSETSW2	_IOW('T', 44, struct termios2)
+#define TCSETSF2	_IOW('T', 45, struct termios2)
+
 #define TIOCSWINSZ	_IOW('t', 103, struct winsize)
 #define TIOCGWINSZ	_IOR('t', 104, struct winsize)
 #define	TIOCSTART	_IO('t', 110)		/* start output, like ^Q */
--- linux-4.4.0.orig/arch/alpha/include/uapi/asm/termbits.h
+++ linux-4.4.0/arch/alpha/include/uapi/asm/termbits.h
@@ -25,6 +25,19 @@
 	speed_t c_ospeed;		/* output speed */
 };
 
+/* Alpha has identical termios and termios2 */
+
+struct termios2 {
+	tcflag_t c_iflag;		/* input mode flags */
+	tcflag_t c_oflag;		/* output mode flags */
+	tcflag_t c_cflag;		/* control mode flags */
+	tcflag_t c_lflag;		/* local mode flags */
+	cc_t c_cc[NCCS];		/* control characters */
+	cc_t c_line;			/* line discipline (== c_cc[19]) */
+	speed_t c_ispeed;		/* input speed */
+	speed_t c_ospeed;		/* output speed */
+};
+
 /* Alpha has matching termios and ktermios */
 
 struct ktermios {
@@ -147,6 +160,7 @@
 #define B3000000  00034
 #define B3500000  00035
 #define B4000000  00036
+#define BOTHER    00037
 
 #define CSIZE	00001400
 #define   CS5	00000000
@@ -164,6 +178,9 @@
 #define CMSPAR	  010000000000		/* mark or space (stick) parity */
 #define CRTSCTS	  020000000000		/* flow control */
 
+#define CIBAUD	07600000
+#define IBSHIFT	16
+
 /* c_lflag bits */
 #define ISIG	0x00000080
 #define ICANON	0x00000100
--- linux-4.4.0.orig/arch/alpha/include/uapi/asm/types.h
+++ linux-4.4.0/arch/alpha/include/uapi/asm/types.h
@@ -9,8 +9,18 @@
  * need to be careful to avoid a name clashes.
  */
 
-#ifndef __KERNEL__
+/*
+ * This is here because we used to use l64 for alpha
+ * and we don't want to impact user mode with our change to ll64
+ * in the kernel.
+ *
+ * However, some user programs are fine with this.  They can
+ * flag __SANE_USERSPACE_TYPES__ to get int-ll64.h here.
+ */
+#if !defined(__SANE_USERSPACE_TYPES__) && !defined(__KERNEL__)
 #include <asm-generic/int-l64.h>
+#else
+#include <asm-generic/int-ll64.h>
 #endif
 
 #endif /* _UAPI_ALPHA_TYPES_H */
--- linux-4.4.0.orig/arch/alpha/kernel/Makefile
+++ linux-4.4.0/arch/alpha/kernel/Makefile
@@ -8,7 +8,7 @@
 
 obj-y    := entry.o traps.o process.o osf_sys.o irq.o \
 	    irq_alpha.o signal.o setup.o ptrace.o time.o \
-	    alpha_ksyms.o systbls.o err_common.o io.o
+	    systbls.o err_common.o io.o
 
 obj-$(CONFIG_VGA_HOSE)	+= console.o
 obj-$(CONFIG_SMP)	+= smp.o
--- linux-4.4.0.orig/arch/alpha/kernel/console.c
+++ linux-4.4.0/arch/alpha/kernel/console.c
@@ -20,6 +20,7 @@
 struct pci_controller *pci_vga_hose;
 static struct resource alpha_vga = {
 	.name	= "alpha-vga+",
+	.flags	= IORESOURCE_IO,
 	.start	= 0x3C0,
 	.end	= 0x3DF
 };
--- linux-4.4.0.orig/arch/alpha/kernel/machvec_impl.h
+++ linux-4.4.0/arch/alpha/kernel/machvec_impl.h
@@ -144,9 +144,11 @@
    else beforehand.  Fine.  We'll do it ourselves.  */
 #if 0
 #define ALIAS_MV(system) \
-  struct alpha_machine_vector alpha_mv __attribute__((alias(#system "_mv")));
+  struct alpha_machine_vector alpha_mv __attribute__((alias(#system "_mv"))); \
+  EXPORT_SYMBOL(alpha_mv);
 #else
 #define ALIAS_MV(system) \
-  asm(".global alpha_mv\nalpha_mv = " #system "_mv");
+  asm(".global alpha_mv\nalpha_mv = " #system "_mv"); \
+  EXPORT_SYMBOL(alpha_mv);
 #endif
 #endif /* GENERIC */
--- linux-4.4.0.orig/arch/alpha/kernel/module.c
+++ linux-4.4.0/arch/alpha/kernel/module.c
@@ -160,7 +160,7 @@
 
 	/* The small sections were sorted to the end of the segment.
 	   The following should definitely cover them.  */
-	gp = (u64)me->module_core + me->core_size - 0x8000;
+	gp = (u64)me->core_layout.base + me->core_layout.size - 0x8000;
 	got = sechdrs[me->arch.gotsecindex].sh_addr;
 
 	for (i = 0; i < n; i++) {
--- linux-4.4.0.orig/arch/alpha/kernel/osf_sys.c
+++ linux-4.4.0/arch/alpha/kernel/osf_sys.c
@@ -526,24 +526,19 @@
 SYSCALL_DEFINE1(osf_utsname, char __user *, name)
 {
 	int error;
+	char tmp[5 * 32];
 
 	down_read(&uts_sem);
-	error = -EFAULT;
-	if (copy_to_user(name + 0, utsname()->sysname, 32))
-		goto out;
-	if (copy_to_user(name + 32, utsname()->nodename, 32))
-		goto out;
-	if (copy_to_user(name + 64, utsname()->release, 32))
-		goto out;
-	if (copy_to_user(name + 96, utsname()->version, 32))
-		goto out;
-	if (copy_to_user(name + 128, utsname()->machine, 32))
-		goto out;
+	memcpy(tmp + 0 * 32, utsname()->sysname, 32);
+	memcpy(tmp + 1 * 32, utsname()->nodename, 32);
+	memcpy(tmp + 2 * 32, utsname()->release, 32);
+	memcpy(tmp + 3 * 32, utsname()->version, 32);
+	memcpy(tmp + 4 * 32, utsname()->machine, 32);
+	up_read(&uts_sem);
 
-	error = 0;
- out:
-	up_read(&uts_sem);	
-	return error;
+	if (copy_to_user(name, tmp, sizeof(tmp)))
+		return -EFAULT;
+	return 0;
 }
 
 SYSCALL_DEFINE0(getpagesize)
@@ -561,24 +556,22 @@
  */
 SYSCALL_DEFINE2(osf_getdomainname, char __user *, name, int, namelen)
 {
-	unsigned len;
-	int i;
-
-	if (!access_ok(VERIFY_WRITE, name, namelen))
-		return -EFAULT;
+	int len, err = 0;
+	char *kname;
+	char tmp[32];
 
-	len = namelen;
-	if (len > 32)
-		len = 32;
+	if (namelen < 0 || namelen > 32)
+		namelen = 32;
 
 	down_read(&uts_sem);
-	for (i = 0; i < len; ++i) {
-		__put_user(utsname()->domainname[i], name + i);
-		if (utsname()->domainname[i] == '\0')
-			break;
-	}
+	kname = utsname()->domainname;
+	len = strnlen(kname, namelen);
+	len = min(len + 1, namelen);
+	memcpy(tmp, kname, len);
 	up_read(&uts_sem);
 
+	if (copy_to_user(name, tmp, len))
+		return -EFAULT;
 	return 0;
 }
 
@@ -741,13 +734,14 @@
 	};
 	unsigned long offset;
 	const char *res;
-	long len, err = -EINVAL;
+	long len;
+	char tmp[__NEW_UTS_LEN + 1];
 
 	offset = command-1;
 	if (offset >= ARRAY_SIZE(sysinfo_table)) {
 		/* Digital UNIX has a few unpublished interfaces here */
 		printk("sysinfo(%d)", command);
-		goto out;
+		return -EINVAL;
 	}
 
 	down_read(&uts_sem);
@@ -755,13 +749,11 @@
 	len = strlen(res)+1;
 	if ((unsigned long)len > (unsigned long)count)
 		len = count;
-	if (copy_to_user(buf, res, len))
-		err = -EFAULT;
-	else
-		err = 0;
+	memcpy(tmp, res, len);
 	up_read(&uts_sem);
- out:
-	return err;
+	if (copy_to_user(buf, tmp, len))
+		return -EFAULT;
+	return 0;
 }
 
 SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer,
@@ -1188,8 +1180,10 @@
 	if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur)))
 		return -EFAULT;
 
-	err = 0;
-	err |= put_user(status, ustatus);
+	err = put_user(status, ustatus);
+	if (ret < 0)
+		return err ? err : ret;
+
 	err |= __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec);
 	err |= __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec);
 	err |= __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec);
--- linux-4.4.0.orig/arch/alpha/kernel/pci-sysfs.c
+++ linux-4.4.0/arch/alpha/kernel/pci-sysfs.c
@@ -77,10 +77,10 @@
 	if (i >= PCI_ROM_RESOURCE)
 		return -ENODEV;
 
-	if (!__pci_mmap_fits(pdev, i, vma, sparse))
+	if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
 		return -EINVAL;
 
-	if (iomem_is_exclusive(res->start))
+	if (!__pci_mmap_fits(pdev, i, vma, sparse))
 		return -EINVAL;
 
 	pcibios_resource_to_bus(pdev->bus, &bar, res);
--- linux-4.4.0.orig/arch/alpha/kernel/pci_impl.h
+++ linux-4.4.0/arch/alpha/kernel/pci_impl.h
@@ -143,7 +143,8 @@
 };
 
 #if defined(CONFIG_ALPHA_SRM) && \
-    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA))
+    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
+     defined(CONFIG_ALPHA_AVANTI))
 # define NEED_SRM_SAVE_RESTORE
 #else
 # undef NEED_SRM_SAVE_RESTORE
--- linux-4.4.0.orig/arch/alpha/kernel/process.c
+++ linux-4.4.0/arch/alpha/kernel/process.c
@@ -273,12 +273,13 @@
 	   application calling fork.  */
 	if (clone_flags & CLONE_SETTLS)
 		childti->pcb.unique = regs->r20;
+	else
+		regs->r20 = 0;	/* OSF/1 has some strange fork() semantics.  */
 	childti->pcb.usp = usp ?: rdusp();
 	*childregs = *regs;
 	childregs->r0 = 0;
 	childregs->r19 = 0;
 	childregs->r20 = 1;	/* OSF/1 has some strange fork() semantics.  */
-	regs->r20 = 0;
 	stack = ((struct switch_stack *) regs) - 1;
 	*childstack = *stack;
 	childstack->r26 = (unsigned long) ret_from_fork;
--- linux-4.4.0.orig/arch/alpha/kernel/setup.c
+++ linux-4.4.0/arch/alpha/kernel/setup.c
@@ -115,6 +115,7 @@
 
 #ifdef CONFIG_ALPHA_GENERIC
 struct alpha_machine_vector alpha_mv;
+EXPORT_SYMBOL(alpha_mv);
 #endif
 
 #ifndef alpha_using_srm
--- linux-4.4.0.orig/arch/alpha/lib/Makefile
+++ linux-4.4.0/arch/alpha/lib/Makefile
@@ -20,12 +20,8 @@
 	checksum.o \
 	csum_partial_copy.o \
 	$(ev67-y)strlen.o \
-	$(ev67-y)strcat.o \
-	strcpy.o \
-	$(ev67-y)strncat.o \
-	strncpy.o \
-	$(ev6-y)stxcpy.o \
-	$(ev6-y)stxncpy.o \
+	stycpy.o \
+	styncpy.o \
 	$(ev67-y)strchr.o \
 	$(ev67-y)strrchr.o \
 	$(ev6-y)memchr.o \
@@ -46,11 +42,20 @@
 AFLAGS___divlu.o = -DDIV       -DINTSIZE
 AFLAGS___remlu.o =       -DREM -DINTSIZE
 
-$(obj)/__divqu.o: $(obj)/$(ev6-y)divide.S
-	$(cmd_as_o_S)
-$(obj)/__remqu.o: $(obj)/$(ev6-y)divide.S
-	$(cmd_as_o_S)
-$(obj)/__divlu.o: $(obj)/$(ev6-y)divide.S
-	$(cmd_as_o_S)
-$(obj)/__remlu.o: $(obj)/$(ev6-y)divide.S
-	$(cmd_as_o_S)
+$(addprefix $(obj)/,__divqu.o __remqu.o __divlu.o __remlu.o): \
+						$(src)/$(ev6-y)divide.S FORCE
+	$(call if_changed_rule,as_o_S)
+
+# There are direct branches between {str*cpy,str*cat} and stx*cpy.
+# Ensure the branches are within range by merging these objects.
+
+LDFLAGS_stycpy.o := -r
+LDFLAGS_styncpy.o := -r
+
+$(obj)/stycpy.o: $(obj)/strcpy.o $(obj)/$(ev67-y)strcat.o \
+		 $(obj)/$(ev6-y)stxcpy.o FORCE
+	$(call if_changed,ld)
+
+$(obj)/styncpy.o: $(obj)/strncpy.o $(obj)/$(ev67-y)strncat.o \
+		 $(obj)/$(ev6-y)stxncpy.o FORCE
+	$(call if_changed,ld)
--- linux-4.4.0.orig/arch/alpha/lib/callback_srm.S
+++ linux-4.4.0/arch/alpha/lib/callback_srm.S
@@ -3,6 +3,7 @@
  */
 
 #include <asm/console.h>
+#include <asm/export.h>
 
 .text
 #define HWRPB_CRB_OFFSET 0xc0
@@ -92,6 +93,10 @@
 CALLBACK(save_env, CCB_SAVE_ENV, 1)
 CALLBACK(pswitch, CCB_PSWITCH, 3)
 CALLBACK(bios_emul, CCB_BIOS_EMUL, 5)
+
+EXPORT_SYMBOL(callback_getenv)
+EXPORT_SYMBOL(callback_setenv)
+EXPORT_SYMBOL(callback_save_env)
 	
 .data
 __alpha_using_srm:		# For use by bootpheader
--- linux-4.4.0.orig/arch/alpha/lib/checksum.c
+++ linux-4.4.0/arch/alpha/lib/checksum.c
@@ -50,6 +50,7 @@
 		(__force u64)saddr + (__force u64)daddr +
 		(__force u64)sum + ((len + proto) << 8));
 }
+EXPORT_SYMBOL(csum_tcpudp_magic);
 
 __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
 				   unsigned short len,
@@ -148,6 +149,7 @@
 {
 	return (__force __sum16)~do_csum(iph,ihl*4);
 }
+EXPORT_SYMBOL(ip_fast_csum);
 
 /*
  * computes the checksum of a memory block at buff, length len,
@@ -182,3 +184,4 @@
 {
 	return (__force __sum16)~from64to16(do_csum(buff,len));
 }
+EXPORT_SYMBOL(ip_compute_csum);
--- linux-4.4.0.orig/arch/alpha/lib/clear_page.S
+++ linux-4.4.0/arch/alpha/lib/clear_page.S
@@ -3,7 +3,7 @@
  *
  * Zero an entire page.
  */
-
+#include <asm/export.h>
 	.text
 	.align 4
 	.global clear_page
@@ -37,3 +37,4 @@
 	nop
 
 	.end clear_page
+	EXPORT_SYMBOL(clear_page)
--- linux-4.4.0.orig/arch/alpha/lib/clear_user.S
+++ linux-4.4.0/arch/alpha/lib/clear_user.S
@@ -8,22 +8,8 @@
  * right "bytes left to zero" value (and that it is updated only _after_
  * a successful copy).  There is also some rather minor exception setup
  * stuff.
- *
- * NOTE! This is not directly C-callable, because the calling semantics
- * are different:
- *
- * Inputs:
- *	length in $0
- *	destination address in $6
- *	exception pointer in $7
- *	return address in $28 (exceptions expect it there)
- *
- * Outputs:
- *	bytes left to copy in $0
- *
- * Clobbers:
- *	$1,$2,$3,$4,$5,$6
  */
+#include <asm/export.h>
 
 /* Allow an exception for an insn; exit if we get one.  */
 #define EX(x,y...)			\
@@ -37,62 +23,63 @@
 	.set noreorder
 	.align 4
 
-	.globl __do_clear_user
-	.ent __do_clear_user
-	.frame	$30, 0, $28
+	.globl __clear_user
+	.ent __clear_user
+	.frame	$30, 0, $26
 	.prologue 0
 
 $loop:
 	and	$1, 3, $4	# e0    :
 	beq	$4, 1f		# .. e1 :
 
-0:	EX( stq_u $31, 0($6) )	# e0    : zero one word
+0:	EX( stq_u $31, 0($16) )	# e0    : zero one word
 	subq	$0, 8, $0	# .. e1 :
 	subq	$4, 1, $4	# e0    :
-	addq	$6, 8, $6	# .. e1 :
+	addq	$16, 8, $16	# .. e1 :
 	bne	$4, 0b		# e1    :
 	unop			#       :
 
 1:	bic	$1, 3, $1	# e0    :
 	beq	$1, $tail	# .. e1 :
 
-2:	EX( stq_u $31, 0($6) )	# e0    : zero four words
+2:	EX( stq_u $31, 0($16) )	# e0    : zero four words
 	subq	$0, 8, $0	# .. e1 :
-	EX( stq_u $31, 8($6) )	# e0    :
+	EX( stq_u $31, 8($16) )	# e0    :
 	subq	$0, 8, $0	# .. e1 :
-	EX( stq_u $31, 16($6) )	# e0    :
+	EX( stq_u $31, 16($16) )	# e0    :
 	subq	$0, 8, $0	# .. e1 :
-	EX( stq_u $31, 24($6) )	# e0    :
+	EX( stq_u $31, 24($16) )	# e0    :
 	subq	$0, 8, $0	# .. e1 :
 	subq	$1, 4, $1	# e0    :
-	addq	$6, 32, $6	# .. e1 :
+	addq	$16, 32, $16	# .. e1 :
 	bne	$1, 2b		# e1    :
 
 $tail:
 	bne	$2, 1f		# e1    : is there a tail to do?
-	ret	$31, ($28), 1	# .. e1 :
+	ret	$31, ($26), 1	# .. e1 :
 
-1:	EX( ldq_u $5, 0($6) )	# e0    :
+1:	EX( ldq_u $5, 0($16) )	# e0    :
 	clr	$0		# .. e1 :
 	nop			# e1    :
 	mskqh	$5, $0, $5	# e0    :
-	EX( stq_u $5, 0($6) )	# e0    :
-	ret	$31, ($28), 1	# .. e1 :
+	EX( stq_u $5, 0($16) )	# e0    :
+	ret	$31, ($26), 1	# .. e1 :
 
-__do_clear_user:
-	and	$6, 7, $4	# e0    : find dest misalignment
+__clear_user:
+	and	$17, $17, $0
+	and	$16, 7, $4	# e0    : find dest misalignment
 	beq	$0, $zerolength # .. e1 :
 	addq	$0, $4, $1	# e0    : bias counter
 	and	$1, 7, $2	# e1    : number of bytes in tail
 	srl	$1, 3, $1	# e0    :
 	beq	$4, $loop	# .. e1 :
 
-	EX( ldq_u $5, 0($6) )	# e0    : load dst word to mask back in
+	EX( ldq_u $5, 0($16) )	# e0    : load dst word to mask back in
 	beq	$1, $oneword	# .. e1 : sub-word store?
 
-	mskql	$5, $6, $5	# e0    : take care of misaligned head
-	addq	$6, 8, $6	# .. e1 :
-	EX( stq_u $5, -8($6) )	# e0    :
+	mskql	$5, $16, $5	# e0    : take care of misaligned head
+	addq	$16, 8, $16	# .. e1 :
+	EX( stq_u $5, -8($16) )	# e0    :
 	addq	$0, $4, $0	# .. e1 : bytes left -= 8 - misalignment
 	subq	$1, 1, $1	# e0    :
 	subq	$0, 8, $0	# .. e1 :
@@ -100,14 +87,15 @@
 	unop			#       :
 
 $oneword:
-	mskql	$5, $6, $4	# e0    :
+	mskql	$5, $16, $4	# e0    :
 	mskqh	$5, $2, $5	# e0    :
 	or	$5, $4, $5	# e1    :
-	EX( stq_u $5, 0($6) )	# e0    :
+	EX( stq_u $5, 0($16) )	# e0    :
 	clr	$0		# .. e1 :
 
 $zerolength:
 $exception:
-	ret	$31, ($28), 1	# .. e1 :
+	ret	$31, ($26), 1	# .. e1 :
 
-	.end __do_clear_user
+	.end __clear_user
+	EXPORT_SYMBOL(__clear_user)
--- linux-4.4.0.orig/arch/alpha/lib/copy_page.S
+++ linux-4.4.0/arch/alpha/lib/copy_page.S
@@ -3,7 +3,7 @@
  *
  * Copy an entire page.
  */
-
+#include <asm/export.h>
 	.text
 	.align 4
 	.global copy_page
@@ -47,3 +47,4 @@
 	nop
 
 	.end copy_page
+	EXPORT_SYMBOL(copy_page)
--- linux-4.4.0.orig/arch/alpha/lib/copy_user.S
+++ linux-4.4.0/arch/alpha/lib/copy_user.S
@@ -9,23 +9,10 @@
  * contains the right "bytes left to copy" value (and that it is updated
  * only _after_ a successful copy). There is also some rather minor
  * exception setup stuff..
- *
- * NOTE! This is not directly C-callable, because the calling semantics are
- * different:
- *
- * Inputs:
- *	length in $0
- *	destination address in $6
- *	source address in $7
- *	return address in $28
- *
- * Outputs:
- *	bytes left to copy in $0
- *
- * Clobbers:
- *	$1,$2,$3,$4,$5,$6,$7
  */
 
+#include <asm/export.h>
+
 /* Allow an exception for an insn; exit if we get one.  */
 #define EXI(x,y...)			\
 	99: x,##y;			\
@@ -47,58 +34,59 @@
 	.ent __copy_user
 __copy_user:
 	.prologue 0
-	and $6,7,$3
+	and $18,$18,$0
+	and $16,7,$3
 	beq $0,$35
 	beq $3,$36
 	subq $3,8,$3
 	.align 4
 $37:
-	EXI( ldq_u $1,0($7) )
-	EXO( ldq_u $2,0($6) )
-	extbl $1,$7,$1
-	mskbl $2,$6,$2
-	insbl $1,$6,$1
+	EXI( ldq_u $1,0($17) )
+	EXO( ldq_u $2,0($16) )
+	extbl $1,$17,$1
+	mskbl $2,$16,$2
+	insbl $1,$16,$1
 	addq $3,1,$3
 	bis $1,$2,$1
-	EXO( stq_u $1,0($6) )
+	EXO( stq_u $1,0($16) )
 	subq $0,1,$0
-	addq $6,1,$6
-	addq $7,1,$7
+	addq $16,1,$16
+	addq $17,1,$17
 	beq $0,$41
 	bne $3,$37
 $36:
-	and $7,7,$1
+	and $17,7,$1
 	bic $0,7,$4
 	beq $1,$43
 	beq $4,$48
-	EXI( ldq_u $3,0($7) )
+	EXI( ldq_u $3,0($17) )
 	.align 4
 $50:
-	EXI( ldq_u $2,8($7) )
+	EXI( ldq_u $2,8($17) )
 	subq $4,8,$4
-	extql $3,$7,$3
-	extqh $2,$7,$1
+	extql $3,$17,$3
+	extqh $2,$17,$1
 	bis $3,$1,$1
-	EXO( stq $1,0($6) )
-	addq $7,8,$7
+	EXO( stq $1,0($16) )
+	addq $17,8,$17
 	subq $0,8,$0
-	addq $6,8,$6
+	addq $16,8,$16
 	bis $2,$2,$3
 	bne $4,$50
 $48:
 	beq $0,$41
 	.align 4
 $57:
-	EXI( ldq_u $1,0($7) )
-	EXO( ldq_u $2,0($6) )
-	extbl $1,$7,$1
-	mskbl $2,$6,$2
-	insbl $1,$6,$1
+	EXI( ldq_u $1,0($17) )
+	EXO( ldq_u $2,0($16) )
+	extbl $1,$17,$1
+	mskbl $2,$16,$2
+	insbl $1,$16,$1
 	bis $1,$2,$1
-	EXO( stq_u $1,0($6) )
+	EXO( stq_u $1,0($16) )
 	subq $0,1,$0
-	addq $6,1,$6
-	addq $7,1,$7
+	addq $16,1,$16
+	addq $17,1,$17
 	bne $0,$57
 	br $31,$41
 	.align 4
@@ -106,40 +94,27 @@
 	beq $4,$65
 	.align 4
 $66:
-	EXI( ldq $1,0($7) )
+	EXI( ldq $1,0($17) )
 	subq $4,8,$4
-	EXO( stq $1,0($6) )
-	addq $7,8,$7
+	EXO( stq $1,0($16) )
+	addq $17,8,$17
 	subq $0,8,$0
-	addq $6,8,$6
+	addq $16,8,$16
 	bne $4,$66
 $65:
 	beq $0,$41
-	EXI( ldq $2,0($7) )
-	EXO( ldq $1,0($6) )
+	EXI( ldq $2,0($17) )
+	EXO( ldq $1,0($16) )
 	mskql $2,$0,$2
 	mskqh $1,$0,$1
 	bis $2,$1,$2
-	EXO( stq $2,0($6) )
+	EXO( stq $2,0($16) )
 	bis $31,$31,$0
 $41:
 $35:
-$exitout:
-	ret $31,($28),1
-
 $exitin:
-	/* A stupid byte-by-byte zeroing of the rest of the output
-	   buffer.  This cures security holes by never leaving 
-	   random kernel data around to be copied elsewhere.  */
-
-	mov $0,$1
-$101:
-	EXO ( ldq_u $2,0($6) )
-	subq $1,1,$1
-	mskbl $2,$6,$2
-	EXO ( stq_u $2,0($6) )
-	addq $6,1,$6
-	bgt $1,$101
-	ret $31,($28),1
+$exitout:
+	ret $31,($26),1
 
 	.end __copy_user
+EXPORT_SYMBOL(__copy_user)
--- linux-4.4.0.orig/arch/alpha/lib/csum_ipv6_magic.S
+++ linux-4.4.0/arch/alpha/lib/csum_ipv6_magic.S
@@ -12,6 +12,7 @@
  * added by Ivan Kokshaysky <ink@jurassic.park.msu.ru>
  */
 
+#include <asm/export.h>
 	.globl csum_ipv6_magic
 	.align 4
 	.ent csum_ipv6_magic
@@ -113,3 +114,4 @@
 	ret			# .. e1 :
 
 	.end csum_ipv6_magic
+	EXPORT_SYMBOL(csum_ipv6_magic)
--- linux-4.4.0.orig/arch/alpha/lib/csum_partial_copy.c
+++ linux-4.4.0/arch/alpha/lib/csum_partial_copy.c
@@ -374,6 +374,7 @@
 	}
 	return (__force __wsum)checksum;
 }
+EXPORT_SYMBOL(csum_partial_copy_from_user);
 
 __wsum
 csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
@@ -386,3 +387,4 @@
 	set_fs(oldfs);
 	return checksum;
 }
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
--- linux-4.4.0.orig/arch/alpha/lib/dec_and_lock.c
+++ linux-4.4.0/arch/alpha/lib/dec_and_lock.c
@@ -7,6 +7,7 @@
 
 #include <linux/spinlock.h>
 #include <linux/atomic.h>
+#include <linux/export.h>
 
   asm (".text					\n\
 	.global _atomic_dec_and_lock		\n\
@@ -39,3 +40,4 @@
 	spin_unlock(lock);
 	return 0;
 }
+EXPORT_SYMBOL(_atomic_dec_and_lock);
--- linux-4.4.0.orig/arch/alpha/lib/divide.S
+++ linux-4.4.0/arch/alpha/lib/divide.S
@@ -45,6 +45,7 @@
  *	$28 - compare status
  */
 
+#include <asm/export.h>
 #define halt .long 0
 
 /*
@@ -151,6 +152,7 @@
 	addq	$30,STACK,$30
 	ret	$31,($23),1
 	.end	ufunction
+EXPORT_SYMBOL(ufunction)
 
 /*
  * Uhh.. Ugly signed division. I'd rather not have it at all, but
@@ -193,3 +195,4 @@
 	addq	$30,STACK,$30
 	ret	$31,($23),1
 	.end	sfunction
+EXPORT_SYMBOL(sfunction)
--- linux-4.4.0.orig/arch/alpha/lib/ev6-clear_page.S
+++ linux-4.4.0/arch/alpha/lib/ev6-clear_page.S
@@ -3,7 +3,7 @@
  *
  * Zero an entire page.
  */
-
+#include <asm/export.h>
         .text
         .align 4
         .global clear_page
@@ -52,3 +52,4 @@
 	nop
 
 	.end clear_page
+	EXPORT_SYMBOL(clear_page)
--- linux-4.4.0.orig/arch/alpha/lib/ev6-clear_user.S
+++ linux-4.4.0/arch/alpha/lib/ev6-clear_user.S
@@ -9,21 +9,6 @@
  * a successful copy).  There is also some rather minor exception setup
  * stuff.
  *
- * NOTE! This is not directly C-callable, because the calling semantics
- * are different:
- *
- * Inputs:
- *	length in $0
- *	destination address in $6
- *	exception pointer in $7
- *	return address in $28 (exceptions expect it there)
- *
- * Outputs:
- *	bytes left to copy in $0
- *
- * Clobbers:
- *	$1,$2,$3,$4,$5,$6
- *
  * Much of the information about 21264 scheduling/coding comes from:
  *	Compiler Writer's Guide for the Alpha 21264
  *	abbreviated as 'CWG' in other comments here
@@ -43,6 +28,7 @@
  *	want to leave a hole (and we also want to avoid repeating lots of work)
  */
 
+#include <asm/export.h>
 /* Allow an exception for an insn; exit if we get one.  */
 #define EX(x,y...)			\
 	99: x,##y;			\
@@ -55,14 +41,15 @@
 	.set noreorder
 	.align 4
 
-	.globl __do_clear_user
-	.ent __do_clear_user
-	.frame	$30, 0, $28
+	.globl __clear_user
+	.ent __clear_user
+	.frame	$30, 0, $26
 	.prologue 0
 
 				# Pipeline info : Slotting & Comments
-__do_clear_user:
-	and	$6, 7, $4	# .. E  .. ..	: find dest head misalignment
+__clear_user:
+	and	$17, $17, $0
+	and	$16, 7, $4	# .. E  .. ..	: find dest head misalignment
 	beq	$0, $zerolength # U  .. .. ..	:  U L U L
 
 	addq	$0, $4, $1	# .. .. .. E	: bias counter
@@ -74,14 +61,14 @@
 
 /*
  * Head is not aligned.  Write (8 - $4) bytes to head of destination
- * This means $6 is known to be misaligned
+ * This means $16 is known to be misaligned
  */
-	EX( ldq_u $5, 0($6) )	# .. .. .. L	: load dst word to mask back in
+	EX( ldq_u $5, 0($16) )	# .. .. .. L	: load dst word to mask back in
 	beq	$1, $onebyte	# .. .. U  ..	: sub-word store?
-	mskql	$5, $6, $5	# .. U  .. ..	: take care of misaligned head
-	addq	$6, 8, $6	# E  .. .. .. 	: L U U L
+	mskql	$5, $16, $5	# .. U  .. ..	: take care of misaligned head
+	addq	$16, 8, $16	# E  .. .. .. 	: L U U L
 
-	EX( stq_u $5, -8($6) )	# .. .. .. L	:
+	EX( stq_u $5, -8($16) )	# .. .. .. L	:
 	subq	$1, 1, $1	# .. .. E  ..	:
 	addq	$0, $4, $0	# .. E  .. ..	: bytes left -= 8 - misalignment
 	subq	$0, 8, $0	# E  .. .. ..	: U L U L
@@ -92,11 +79,11 @@
  * values upon initial entry to the loop
  * $1 is number of quadwords to clear (zero is a valid value)
  * $2 is number of trailing bytes (0..7) ($2 never used...)
- * $6 is known to be aligned 0mod8
+ * $16 is known to be aligned 0mod8
  */
 $headalign:
 	subq	$1, 16, $4	# .. .. .. E	: If < 16, we can not use the huge loop
-	and	$6, 0x3f, $2	# .. .. E  ..	: Forward work for huge loop
+	and	$16, 0x3f, $2	# .. .. E  ..	: Forward work for huge loop
 	subq	$2, 0x40, $3	# .. E  .. ..	: bias counter (huge loop)
 	blt	$4, $trailquad	# U  .. .. ..	: U L U L
 
@@ -113,21 +100,21 @@
 	beq	$3, $bigalign	# U  .. .. ..	: U L U L : Aligned 0mod64
 
 $alignmod64:
-	EX( stq_u $31, 0($6) )	# .. .. .. L
+	EX( stq_u $31, 0($16) )	# .. .. .. L
 	addq	$3, 8, $3	# .. .. E  ..
 	subq	$0, 8, $0	# .. E  .. ..
 	nop			# E  .. .. ..	: U L U L
 
 	nop			# .. .. .. E
 	subq	$1, 1, $1	# .. .. E  ..
-	addq	$6, 8, $6	# .. E  .. ..
+	addq	$16, 8, $16	# .. E  .. ..
 	blt	$3, $alignmod64	# U  .. .. ..	: U L U L
 
 $bigalign:
 /*
  * $0 is the number of bytes left
  * $1 is the number of quads left
- * $6 is aligned 0mod64
+ * $16 is aligned 0mod64
  * we know that we'll be taking a minimum of one trip through
  * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle
  * We are _not_ going to update $0 after every single store.  That
@@ -144,39 +131,39 @@
 	nop			# E :
 	nop			# E :
 	nop			# E :
-	bis	$6,$6,$3	# E : U L U L : Initial wh64 address is dest
+	bis	$16,$16,$3	# E : U L U L : Initial wh64 address is dest
 	/* This might actually help for the current trip... */
 
 $do_wh64:
 	wh64	($3)		# .. .. .. L1	: memory subsystem hint
 	subq	$1, 16, $4	# .. .. E  ..	: Forward calculation - repeat the loop?
-	EX( stq_u $31, 0($6) )	# .. L  .. ..
+	EX( stq_u $31, 0($16) )	# .. L  .. ..
 	subq	$0, 8, $0	# E  .. .. ..	: U L U L
 
-	addq	$6, 128, $3	# E : Target address of wh64
-	EX( stq_u $31, 8($6) )	# L :
-	EX( stq_u $31, 16($6) )	# L :
+	addq	$16, 128, $3	# E : Target address of wh64
+	EX( stq_u $31, 8($16) )	# L :
+	EX( stq_u $31, 16($16) )	# L :
 	subq	$0, 16, $0	# E : U L L U
 
 	nop			# E :
-	EX( stq_u $31, 24($6) )	# L :
-	EX( stq_u $31, 32($6) )	# L :
+	EX( stq_u $31, 24($16) )	# L :
+	EX( stq_u $31, 32($16) )	# L :
 	subq	$0, 168, $5	# E : U L L U : two trips through the loop left?
 	/* 168 = 192 - 24, since we've already completed some stores */
 
 	subq	$0, 16, $0	# E :
-	EX( stq_u $31, 40($6) )	# L :
-	EX( stq_u $31, 48($6) )	# L :
-	cmovlt	$5, $6, $3	# E : U L L U : Latency 2, extra mapping cycle
+	EX( stq_u $31, 40($16) )	# L :
+	EX( stq_u $31, 48($16) )	# L :
+	cmovlt	$5, $16, $3	# E : U L L U : Latency 2, extra mapping cycle
 
 	subq	$1, 8, $1	# E :
 	subq	$0, 16, $0	# E :
-	EX( stq_u $31, 56($6) )	# L :
+	EX( stq_u $31, 56($16) )	# L :
 	nop			# E : U L U L
 
 	nop			# E :
 	subq	$0, 8, $0	# E :
-	addq	$6, 64, $6	# E :
+	addq	$16, 64, $16	# E :
 	bge	$4, $do_wh64	# U : U L U L
 
 $trailquad:
@@ -189,14 +176,14 @@
 	beq	$1, $trailbytes	# U  .. .. ..	: U L U L : Only 0..7 bytes to go
 
 $onequad:
-	EX( stq_u $31, 0($6) )	# .. .. .. L
+	EX( stq_u $31, 0($16) )	# .. .. .. L
 	subq	$1, 1, $1	# .. .. E  ..
 	subq	$0, 8, $0	# .. E  .. ..
 	nop			# E  .. .. ..	: U L U L
 
 	nop			# .. .. .. E
 	nop			# .. .. E  ..
-	addq	$6, 8, $6	# .. E  .. ..
+	addq	$16, 8, $16	# .. E  .. ..
 	bgt	$1, $onequad	# U  .. .. ..	: U L U L
 
 	# We have an unknown number of bytes left to go.
@@ -210,9 +197,9 @@
 	# so we will use $0 as the loop counter
 	# We know for a fact that $0 > 0 zero due to previous context
 $onebyte:
-	EX( stb $31, 0($6) )	# .. .. .. L
+	EX( stb $31, 0($16) )	# .. .. .. L
 	subq	$0, 1, $0	# .. .. E  ..	:
-	addq	$6, 1, $6	# .. E  .. ..	:
+	addq	$16, 1, $16	# .. E  .. ..	:
 	bgt	$0, $onebyte	# U  .. .. ..	: U L U L
 
 $zerolength:
@@ -220,6 +207,6 @@
 	nop			# .. .. .. E	:
 	nop			# .. .. E  ..	:
 	nop			# .. E  .. ..	:
-	ret	$31, ($28), 1	# L0 .. .. ..	: L U L U
-	.end __do_clear_user
-
+	ret	$31, ($26), 1	# L0 .. .. ..	: L U L U
+	.end __clear_user
+	EXPORT_SYMBOL(__clear_user)
--- linux-4.4.0.orig/arch/alpha/lib/ev6-copy_page.S
+++ linux-4.4.0/arch/alpha/lib/ev6-copy_page.S
@@ -56,7 +56,7 @@
    destination pages are in the dcache, but it is my guess that this is
    less important than the dcache miss case.  */
 
-
+#include <asm/export.h>
 	.text
 	.align 4
 	.global copy_page
@@ -201,3 +201,4 @@
 	nop
 
 	.end copy_page
+	EXPORT_SYMBOL(copy_page)
--- linux-4.4.0.orig/arch/alpha/lib/ev6-copy_user.S
+++ linux-4.4.0/arch/alpha/lib/ev6-copy_user.S
@@ -12,21 +12,6 @@
  * only _after_ a successful copy). There is also some rather minor
  * exception setup stuff..
  *
- * NOTE! This is not directly C-callable, because the calling semantics are
- * different:
- *
- * Inputs:
- *	length in $0
- *	destination address in $6
- *	source address in $7
- *	return address in $28
- *
- * Outputs:
- *	bytes left to copy in $0
- *
- * Clobbers:
- *	$1,$2,$3,$4,$5,$6,$7
- *
  * Much of the information about 21264 scheduling/coding comes from:
  *	Compiler Writer's Guide for the Alpha 21264
  *	abbreviated as 'CWG' in other comments here
@@ -37,6 +22,7 @@
  *	L	- lower subcluster; L0 - subcluster L0; L1 - subcluster L1
  */
 
+#include <asm/export.h>
 /* Allow an exception for an insn; exit if we get one.  */
 #define EXI(x,y...)			\
 	99: x,##y;			\
@@ -59,10 +45,11 @@
 				# Pipeline info: Slotting & Comments
 __copy_user:
 	.prologue 0
-	subq $0, 32, $1		# .. E  .. ..	: Is this going to be a small copy?
+	andq $18, $18, $0
+	subq $18, 32, $1	# .. E  .. ..	: Is this going to be a small copy?
 	beq $0, $zerolength	# U  .. .. ..	: U L U L
 
-	and $6,7,$3		# .. .. .. E	: is leading dest misalignment
+	and $16,7,$3		# .. .. .. E	: is leading dest misalignment
 	ble $1, $onebyteloop	# .. .. U  ..	: 1st branch : small amount of data
 	beq $3, $destaligned	# .. U  .. ..	: 2nd (one cycle fetcher stall)
 	subq $3, 8, $3		# E  .. .. ..	: L U U L : trip counter
@@ -72,17 +59,17 @@
  * We know we have at least one trip through this loop
  */
 $aligndest:
-	EXI( ldbu $1,0($7) )	# .. .. .. L	: Keep loads separate from stores
-	addq $6,1,$6		# .. .. E  ..	: Section 3.8 in the CWG
+	EXI( ldbu $1,0($17) )	# .. .. .. L	: Keep loads separate from stores
+	addq $16,1,$16		# .. .. E  ..	: Section 3.8 in the CWG
 	addq $3,1,$3		# .. E  .. ..	:
 	nop			# E  .. .. ..	: U L U L
 
 /*
- * the -1 is to compensate for the inc($6) done in a previous quadpack
+ * the -1 is to compensate for the inc($16) done in a previous quadpack
  * which allows us zero dependencies within either quadpack in the loop
  */
-	EXO( stb $1,-1($6) )	# .. .. .. L	:
-	addq $7,1,$7		# .. .. E  ..	: Section 3.8 in the CWG
+	EXO( stb $1,-1($16) )	# .. .. .. L	:
+	addq $17,1,$17		# .. .. E  ..	: Section 3.8 in the CWG
 	subq $0,1,$0		# .. E  .. ..	:
 	bne $3, $aligndest	# U  .. .. ..	: U L U L
 
@@ -91,29 +78,29 @@
  * If we arrived via branch, we have a minimum of 32 bytes
  */
 $destaligned:
-	and $7,7,$1		# .. .. .. E	: Check _current_ source alignment
+	and $17,7,$1		# .. .. .. E	: Check _current_ source alignment
 	bic $0,7,$4		# .. .. E  ..	: number bytes as a quadword loop
-	EXI( ldq_u $3,0($7) )	# .. L  .. ..	: Forward fetch for fallthrough code
+	EXI( ldq_u $3,0($17) )	# .. L  .. ..	: Forward fetch for fallthrough code
 	beq $1,$quadaligned	# U  .. .. ..	: U L U L
 
 /*
- * In the worst case, we've just executed an ldq_u here from 0($7)
+ * In the worst case, we've just executed an ldq_u here from 0($17)
  * and we'll repeat it once if we take the branch
  */
 
 /* Misaligned quadword loop - not unrolled.  Leave it that way. */
 $misquad:
-	EXI( ldq_u $2,8($7) )	# .. .. .. L	:
+	EXI( ldq_u $2,8($17) )	# .. .. .. L	:
 	subq $4,8,$4		# .. .. E  ..	:
-	extql $3,$7,$3		# .. U  .. ..	:
-	extqh $2,$7,$1		# U  .. .. ..	: U U L L
+	extql $3,$17,$3		# .. U  .. ..	:
+	extqh $2,$17,$1		# U  .. .. ..	: U U L L
 
 	bis $3,$1,$1		# .. .. .. E	:
-	EXO( stq $1,0($6) )	# .. .. L  ..	:
-	addq $7,8,$7		# .. E  .. ..	:
+	EXO( stq $1,0($16) )	# .. .. L  ..	:
+	addq $17,8,$17		# .. E  .. ..	:
 	subq $0,8,$0		# E  .. .. ..	: U L L U
 
-	addq $6,8,$6		# .. .. .. E	:
+	addq $16,8,$16		# .. .. .. E	:
 	bis $2,$2,$3		# .. .. E  ..	:
 	nop			# .. E  .. ..	:
 	bne $4,$misquad		# U  .. .. ..	: U L U L
@@ -124,8 +111,8 @@
 	beq $0,$zerolength	# U  .. .. ..	: U L U L
 
 /* We know we have at least one trip through the byte loop */
-	EXI ( ldbu $2,0($7) )	# .. .. .. L	: No loads in the same quad
-	addq $6,1,$6		# .. .. E  ..	: as the store (Section 3.8 in CWG)
+	EXI ( ldbu $2,0($17) )	# .. .. .. L	: No loads in the same quad
+	addq $16,1,$16		# .. .. E  ..	: as the store (Section 3.8 in CWG)
 	nop			# .. E  .. ..	:
 	br $31, $dirtyentry	# L0 .. .. ..	: L U U L
 /* Do the trailing byte loop load, then hop into the store part of the loop */
@@ -135,8 +122,8 @@
  * Based upon the usage context, it's worth the effort to unroll this loop
  * $0 - number of bytes to be moved
  * $4 - number of bytes to move as quadwords
- * $6 is current destination address
- * $7 is current source address
+ * $16 is current destination address
+ * $17 is current source address
  */
 $quadaligned:
 	subq	$4, 32, $2	# .. .. .. E	: do not unroll for small stuff
@@ -154,29 +141,29 @@
  * instruction memory hint instruction).
  */
 $unroll4:
-	EXI( ldq $1,0($7) )	# .. .. .. L
-	EXI( ldq $2,8($7) )	# .. .. L  ..
+	EXI( ldq $1,0($17) )	# .. .. .. L
+	EXI( ldq $2,8($17) )	# .. .. L  ..
 	subq	$4,32,$4	# .. E  .. ..
 	nop			# E  .. .. ..	: U U L L
 
-	addq	$7,16,$7	# .. .. .. E
-	EXO( stq $1,0($6) )	# .. .. L  ..
-	EXO( stq $2,8($6) )	# .. L  .. ..
+	addq	$17,16,$17	# .. .. .. E
+	EXO( stq $1,0($16) )	# .. .. L  ..
+	EXO( stq $2,8($16) )	# .. L  .. ..
 	subq	$0,16,$0	# E  .. .. ..	: U L L U
 
-	addq	$6,16,$6	# .. .. .. E
-	EXI( ldq $1,0($7) )	# .. .. L  ..
-	EXI( ldq $2,8($7) )	# .. L  .. ..
+	addq	$16,16,$16	# .. .. .. E
+	EXI( ldq $1,0($17) )	# .. .. L  ..
+	EXI( ldq $2,8($17) )	# .. L  .. ..
 	subq	$4, 32, $3	# E  .. .. ..	: U U L L : is there enough for another trip?
 
-	EXO( stq $1,0($6) )	# .. .. .. L
-	EXO( stq $2,8($6) )	# .. .. L  ..
+	EXO( stq $1,0($16) )	# .. .. .. L
+	EXO( stq $2,8($16) )	# .. .. L  ..
 	subq	$0,16,$0	# .. E  .. ..
-	addq	$7,16,$7	# E  .. .. ..	: U L L U
+	addq	$17,16,$17	# E  .. .. ..	: U L L U
 
 	nop			# .. .. .. E
 	nop			# .. .. E  ..
-	addq	$6,16,$6	# .. E  .. ..
+	addq	$16,16,$16	# .. E  .. ..
 	bgt	$3,$unroll4	# U  .. .. ..	: U L U L
 
 	nop
@@ -185,14 +172,14 @@
 	beq	$4, $noquads
 
 $onequad:
-	EXI( ldq $1,0($7) )
+	EXI( ldq $1,0($17) )
 	subq	$4,8,$4
-	addq	$7,8,$7
+	addq	$17,8,$17
 	nop
 
-	EXO( stq $1,0($6) )
+	EXO( stq $1,0($16) )
 	subq	$0,8,$0
-	addq	$6,8,$6
+	addq	$16,8,$16
 	bne	$4,$onequad
 
 $noquads:
@@ -206,54 +193,33 @@
  * There's no point in doing a lot of complex alignment calculations to try to
  * to quadword stuff for a small amount of data.
  *	$0 - remaining number of bytes left to copy
- *	$6 - current dest addr
- *	$7 - current source addr
+ *	$16 - current dest addr
+ *	$17 - current source addr
  */
 
 $onebyteloop:
-	EXI ( ldbu $2,0($7) )	# .. .. .. L	: No loads in the same quad
-	addq $6,1,$6		# .. .. E  ..	: as the store (Section 3.8 in CWG)
+	EXI ( ldbu $2,0($17) )	# .. .. .. L	: No loads in the same quad
+	addq $16,1,$16		# .. .. E  ..	: as the store (Section 3.8 in CWG)
 	nop			# .. E  .. ..	:
 	nop			# E  .. .. ..	: U L U L
 
 $dirtyentry:
 /*
- * the -1 is to compensate for the inc($6) done in a previous quadpack
+ * the -1 is to compensate for the inc($16) done in a previous quadpack
  * which allows us zero dependencies within either quadpack in the loop
  */
-	EXO ( stb $2,-1($6) )	# .. .. .. L	:
-	addq $7,1,$7		# .. .. E  ..	: quadpack as the load
+	EXO ( stb $2,-1($16) )	# .. .. .. L	:
+	addq $17,1,$17		# .. .. E  ..	: quadpack as the load
 	subq $0,1,$0		# .. E  .. ..	: change count _after_ copy
 	bgt $0,$onebyteloop	# U  .. .. ..	: U L U L
 
 $zerolength:
+$exitin:
 $exitout:			# Destination for exception recovery(?)
 	nop			# .. .. .. E
 	nop			# .. .. E  ..
 	nop			# .. E  .. ..
-	ret $31,($28),1		# L0 .. .. ..	: L U L U
-
-$exitin:
-
-	/* A stupid byte-by-byte zeroing of the rest of the output
-	   buffer.  This cures security holes by never leaving 
-	   random kernel data around to be copied elsewhere.  */
-
-	nop
-	nop
-	nop
-	mov	$0,$1
-
-$101:
-	EXO ( stb $31,0($6) )	# L
-	subq $1,1,$1		# E
-	addq $6,1,$6		# E
-	bgt $1,$101		# U
-
-	nop
-	nop
-	nop
-	ret $31,($28),1		# L0
+	ret $31,($26),1		# L0 .. .. ..	: L U L U
 
 	.end __copy_user
-
+	EXPORT_SYMBOL(__copy_user)
--- linux-4.4.0.orig/arch/alpha/lib/ev6-csum_ipv6_magic.S
+++ linux-4.4.0/arch/alpha/lib/ev6-csum_ipv6_magic.S
@@ -52,6 +52,7 @@
  * may cause additional delay in rare cases (load-load replay traps).
  */
 
+#include <asm/export.h>
 	.globl csum_ipv6_magic
 	.align 4
 	.ent csum_ipv6_magic
@@ -148,3 +149,4 @@
 	ret			# L0 : L U L U
 
 	.end csum_ipv6_magic
+	EXPORT_SYMBOL(csum_ipv6_magic)
--- linux-4.4.0.orig/arch/alpha/lib/ev6-divide.S
+++ linux-4.4.0/arch/alpha/lib/ev6-divide.S
@@ -55,6 +55,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
+#include <asm/export.h>
 #define halt .long 0
 
 /*
@@ -205,6 +206,7 @@
 	addq	$30,STACK,$30		# E :
 	ret	$31,($23),1		# L0 : L U U L
 	.end	ufunction
+EXPORT_SYMBOL(ufunction)
 
 /*
  * Uhh.. Ugly signed division. I'd rather not have it at all, but
@@ -257,3 +259,4 @@
 	addq	$30,STACK,$30		# E :
 	ret	$31,($23),1		# L0 : L U U L
 	.end	sfunction
+EXPORT_SYMBOL(sfunction)
--- linux-4.4.0.orig/arch/alpha/lib/ev6-memchr.S
+++ linux-4.4.0/arch/alpha/lib/ev6-memchr.S
@@ -27,7 +27,7 @@
  *	L	- lower subcluster; L0 - subcluster L0; L1 - subcluster L1
  * Try not to change the actual algorithm if possible for consistency.
  */
-
+#include <asm/export.h>
         .set noreorder
         .set noat
 
@@ -189,3 +189,4 @@
 	ret			# L0 :
 
         .end memchr
+	EXPORT_SYMBOL(memchr)
--- linux-4.4.0.orig/arch/alpha/lib/ev6-memcpy.S
+++ linux-4.4.0/arch/alpha/lib/ev6-memcpy.S
@@ -19,7 +19,7 @@
  * Temp usage notes:
  *	$1,$2,		- scratch
  */
-
+#include <asm/export.h>
 	.set noreorder
 	.set noat
 
@@ -242,6 +242,7 @@
 	nop				# E :
 
 	.end memcpy
+	EXPORT_SYMBOL(memcpy)
 
 /* For backwards module compatibility.  */
 __memcpy = memcpy
--- linux-4.4.0.orig/arch/alpha/lib/ev6-memset.S
+++ linux-4.4.0/arch/alpha/lib/ev6-memset.S
@@ -26,7 +26,7 @@
  * as fixes will need to be made in multiple places.  The performance gain
  * is worth it.
  */
-
+#include <asm/export.h>
 	.set noat
 	.set noreorder
 .text
@@ -229,6 +229,7 @@
 	nop
 	ret $31,($26),1		# L0 :
 	.end ___memset
+	EXPORT_SYMBOL(___memset)
 
 	/*
 	 * This is the original body of code, prior to replication and
@@ -406,6 +407,7 @@
 	nop
 	ret $31,($26),1		# L0 :
 	.end __constant_c_memset
+	EXPORT_SYMBOL(__constant_c_memset)
 
 	/*
 	 * This is a replicant of the __constant_c_memset code, rescheduled
@@ -594,6 +596,9 @@
 	ret $31,($26),1		# L0 :
 
 	.end __memsetw
+	EXPORT_SYMBOL(__memsetw)
 
 memset = ___memset
 __memset = ___memset
+	EXPORT_SYMBOL(memset)
+	EXPORT_SYMBOL(__memset)
--- linux-4.4.0.orig/arch/alpha/lib/ev67-strcat.S
+++ linux-4.4.0/arch/alpha/lib/ev67-strcat.S
@@ -19,7 +19,7 @@
  * string once.
  */
 
-
+#include <asm/export.h>
 	.text
 
 	.align 4
@@ -52,3 +52,4 @@
 	br	__stxcpy	# L0 :
 
 	.end strcat
+	EXPORT_SYMBOL(strcat)
--- linux-4.4.0.orig/arch/alpha/lib/ev67-strchr.S
+++ linux-4.4.0/arch/alpha/lib/ev67-strchr.S
@@ -15,7 +15,7 @@
  *	L	- lower subcluster; L0 - subcluster L0; L1 - subcluster L1
  * Try not to change the actual algorithm if possible for consistency.
  */
-
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 	.set noreorder
@@ -86,3 +86,4 @@
 	ret			# L0 :
 
 	.end strchr
+	EXPORT_SYMBOL(strchr)
--- linux-4.4.0.orig/arch/alpha/lib/ev67-strlen.S
+++ linux-4.4.0/arch/alpha/lib/ev67-strlen.S
@@ -17,7 +17,7 @@
  *	U	- upper subcluster; U0 - subcluster U0; U1 - subcluster U1
  *	L	- lower subcluster; L0 - subcluster L0; L1 - subcluster L1
  */
-
+#include <asm/export.h>
 	.set noreorder
 	.set noat
 
@@ -47,3 +47,4 @@
 	ret	$31, ($26)	# L0 :
 
 	.end	strlen
+	EXPORT_SYMBOL(strlen)
--- linux-4.4.0.orig/arch/alpha/lib/ev67-strncat.S
+++ linux-4.4.0/arch/alpha/lib/ev67-strncat.S
@@ -20,7 +20,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-
+#include <asm/export.h>
 	.text
 
 	.align 4
@@ -92,3 +92,4 @@
 	ret			# L0 :
 
 	.end strncat
+	EXPORT_SYMBOL(strncat)
--- linux-4.4.0.orig/arch/alpha/lib/ev67-strrchr.S
+++ linux-4.4.0/arch/alpha/lib/ev67-strrchr.S
@@ -18,7 +18,7 @@
  *	L	- lower subcluster; L0 - subcluster L0; L1 - subcluster L1
  */
 
-
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 	.set noreorder
@@ -107,3 +107,4 @@
 	nop
 
 	.end strrchr
+	EXPORT_SYMBOL(strrchr)
--- linux-4.4.0.orig/arch/alpha/lib/fpreg.c
+++ linux-4.4.0/arch/alpha/lib/fpreg.c
@@ -4,6 +4,9 @@
  * (C) Copyright 1998 Linus Torvalds
  */
 
+#include <linux/compiler.h>
+#include <linux/export.h>
+
 #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 #define STT(reg,val)  asm volatile ("ftoit $f"#reg",%0" : "=r"(val));
 #else
@@ -52,6 +55,7 @@
 	}
 	return val;
 }
+EXPORT_SYMBOL(alpha_read_fp_reg);
 
 #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 #define LDT(reg,val)  asm volatile ("itoft %0,$f"#reg : : "r"(val));
@@ -97,6 +101,7 @@
 	      case 31: LDT(31, val); break;
 	}
 }
+EXPORT_SYMBOL(alpha_write_fp_reg);
 
 #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 #define STS(reg,val)  asm volatile ("ftois $f"#reg",%0" : "=r"(val));
@@ -146,6 +151,7 @@
 	}
 	return val;
 }
+EXPORT_SYMBOL(alpha_read_fp_reg_s);
 
 #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 #define LDS(reg,val)  asm volatile ("itofs %0,$f"#reg : : "r"(val));
@@ -191,3 +197,4 @@
 	      case 31: LDS(31, val); break;
 	}
 }
+EXPORT_SYMBOL(alpha_write_fp_reg_s);
--- linux-4.4.0.orig/arch/alpha/lib/memchr.S
+++ linux-4.4.0/arch/alpha/lib/memchr.S
@@ -31,7 +31,7 @@
       - only minimum number of quadwords may be accessed
       - the third argument is an unsigned long
 */
-
+#include <asm/export.h>
         .set noreorder
         .set noat
 
@@ -162,3 +162,4 @@
 	ret			# .. e1 :
 
         .end memchr
+	EXPORT_SYMBOL(memchr)
--- linux-4.4.0.orig/arch/alpha/lib/memcpy.c
+++ linux-4.4.0/arch/alpha/lib/memcpy.c
@@ -16,6 +16,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/export.h>
 
 /*
  * This should be done in one go with ldq_u*2/mask/stq_u. Do it
@@ -158,6 +159,4 @@
 	__memcpy_unaligned_up ((unsigned long) dest, (unsigned long) src, n);
 	return dest;
 }
-
-/* For backward modules compatibility, define __memcpy.  */
-asm("__memcpy = memcpy; .globl __memcpy");
+EXPORT_SYMBOL(memcpy);
--- linux-4.4.0.orig/arch/alpha/lib/memmove.S
+++ linux-4.4.0/arch/alpha/lib/memmove.S
@@ -6,7 +6,7 @@
  * This is hand-massaged output from the original memcpy.c.  We defer to
  * memcpy whenever possible; the backwards copy loops are not unrolled.
  */
-        
+#include <asm/export.h>
 	.set noat
 	.set noreorder
 	.text
@@ -179,3 +179,4 @@
 	nop
 
 	.end memmove
+	EXPORT_SYMBOL(memmove)
--- linux-4.4.0.orig/arch/alpha/lib/memset.S
+++ linux-4.4.0/arch/alpha/lib/memset.S
@@ -13,7 +13,7 @@
  * The scheduling comments are according to the EV5 documentation (and done by 
  * hand, so they might well be incorrect, please do tell me about it..)
  */
-
+#include <asm/export.h>
 	.set noat
 	.set noreorder
 .text
@@ -106,6 +106,8 @@
 end:
 	ret $31,($26),1		/* E1 */
 	.end ___memset
+EXPORT_SYMBOL(___memset)
+EXPORT_SYMBOL(__constant_c_memset)
 
 	.align 5
 	.ent __memsetw
@@ -122,6 +124,9 @@
 	br __constant_c_memset	/* .. E1 */
 
 	.end __memsetw
+EXPORT_SYMBOL(__memsetw)
 
 memset = ___memset
 __memset = ___memset
+	EXPORT_SYMBOL(memset)
+	EXPORT_SYMBOL(__memset)
--- linux-4.4.0.orig/arch/alpha/lib/strcat.S
+++ linux-4.4.0/arch/alpha/lib/strcat.S
@@ -4,6 +4,7 @@
  *
  * Append a null-terminated string from SRC to DST.
  */
+#include <asm/export.h>
 
 	.text
 
@@ -50,3 +51,4 @@
 	br	__stxcpy
 
 	.end strcat
+EXPORT_SYMBOL(strcat);
--- linux-4.4.0.orig/arch/alpha/lib/strchr.S
+++ linux-4.4.0/arch/alpha/lib/strchr.S
@@ -5,7 +5,7 @@
  * Return the address of a given character within a null-terminated
  * string, or null if it is not found.
  */
-
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 	.set noreorder
@@ -68,3 +68,4 @@
 	ret			# .. e1 :
 
 	.end strchr
+	EXPORT_SYMBOL(strchr)
--- linux-4.4.0.orig/arch/alpha/lib/strcpy.S
+++ linux-4.4.0/arch/alpha/lib/strcpy.S
@@ -5,7 +5,7 @@
  * Copy a null-terminated string from SRC to DST.  Return a pointer
  * to the null-terminator in the source.
  */
-
+#include <asm/export.h>
 	.text
 
 	.align 3
@@ -21,3 +21,4 @@
 	br	__stxcpy	# do the copy
 
 	.end strcpy
+	EXPORT_SYMBOL(strcpy)
--- linux-4.4.0.orig/arch/alpha/lib/strlen.S
+++ linux-4.4.0/arch/alpha/lib/strlen.S
@@ -11,7 +11,7 @@
  *	  do this instead of the 9 instructions that
  *	  binary search needs).
  */
-
+#include <asm/export.h>
 	.set noreorder
 	.set noat
 
@@ -55,3 +55,4 @@
 	ret	$31, ($26)
 
 	.end	strlen
+	EXPORT_SYMBOL(strlen)
--- linux-4.4.0.orig/arch/alpha/lib/strncat.S
+++ linux-4.4.0/arch/alpha/lib/strncat.S
@@ -9,7 +9,7 @@
  * past count, whereas libc may write to count+1.  This follows the generic
  * implementation in lib/string.c and is, IMHO, more sensible.
  */
-
+#include <asm/export.h>
 	.text
 
 	.align 3
@@ -82,3 +82,4 @@
 	ret
 
 	.end strncat
+	EXPORT_SYMBOL(strncat)
--- linux-4.4.0.orig/arch/alpha/lib/strncpy.S
+++ linux-4.4.0/arch/alpha/lib/strncpy.S
@@ -10,7 +10,7 @@
  * version has cropped that bit o' nastiness as well as assuming that
  * __stxncpy is in range of a branch.
  */
-
+#include <asm/export.h>
 	.set noat
 	.set noreorder
 
@@ -79,3 +79,4 @@
 	ret
 
 	.end	strncpy
+	EXPORT_SYMBOL(strncpy)
--- linux-4.4.0.orig/arch/alpha/lib/strrchr.S
+++ linux-4.4.0/arch/alpha/lib/strrchr.S
@@ -5,7 +5,7 @@
  * Return the address of the last occurrence of a given character
  * within a null-terminated string, or null if it is not found.
  */
-
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 	.set noreorder
@@ -85,3 +85,4 @@
 	ret			# .. e1 :
 
 	.end strrchr
+	EXPORT_SYMBOL(strrchr)
--- linux-4.4.0.orig/arch/alpha/mm/fault.c
+++ linux-4.4.0/arch/alpha/mm/fault.c
@@ -77,7 +77,7 @@
 /* Macro for exception fixup code to access integer registers.  */
 #define dpf_reg(r)							\
 	(((unsigned long *)regs)[(r) <= 8 ? (r) : (r) <= 15 ? (r)-16 :	\
-				 (r) <= 18 ? (r)+8 : (r)-10])
+				 (r) <= 18 ? (r)+10 : (r)-10])
 
 asmlinkage void
 do_page_fault(unsigned long address, unsigned long mmcsr,
--- linux-4.4.0.orig/arch/arc/Kconfig
+++ linux-4.4.0/arch/arc/Kconfig
@@ -96,7 +96,7 @@
 
 choice
 	prompt "ARC Instruction Set"
-	default ISA_ARCOMPACT
+	default ISA_ARCV2
 
 config ISA_ARCOMPACT
 	bool "ARCompact ISA"
@@ -278,14 +278,6 @@
 	default "0xA0000000"
 	depends on ARC_HAS_DCCM
 
-config ARC_HAS_HW_MPY
-	bool "Use Hardware Multiplier (Normal or Faster XMAC)"
-	default y
-	help
-	  Influences how gcc generates code for MPY operations.
-	  If enabled, MPYxx insns are generated, provided by Standard/XMAC
-	  Multipler. Otherwise software multipy lib is used
-
 choice
 	prompt "MMU Version"
 	default ARC_MMU_V3 if ARC_CPU_770
@@ -387,7 +379,7 @@
 
 config ARC_STAR_9000923308
 	bool "Workaround for llock/scond livelock"
-	default y
+	default n
 	depends on ISA_ARCV2 && SMP && ARC_HAS_LLSC
 
 config ARC_HAS_SWAPE
@@ -479,7 +471,6 @@
 
 config ARC_EMUL_UNALIGNED
 	bool "Emulate unaligned memory access (userspace only)"
-	default N
 	select SYSCTL_ARCH_UNALIGN_NO_WARN
 	select SYSCTL_ARCH_UNALIGN_ALLOW
 	depends on ISA_ARCOMPACT
--- linux-4.4.0.orig/arch/arc/Makefile
+++ linux-4.4.0/arch/arc/Makefile
@@ -12,9 +12,9 @@
 CROSS_COMPILE := arc-linux-
 endif
 
-KBUILD_DEFCONFIG := nsim_700_defconfig
+KBUILD_DEFCONFIG := nsim_hs_defconfig
 
-cflags-y	+= -fno-common -pipe -fno-builtin -D__linux__
+cflags-y	+= -fno-common -pipe -fno-builtin -mmedium-calls -D__linux__
 cflags-$(CONFIG_ISA_ARCOMPACT)	+= -mA7
 cflags-$(CONFIG_ISA_ARCV2)	+= -mcpu=archs
 
@@ -48,8 +48,6 @@
 
 endif
 
-cflags-$(CONFIG_ARC_DW2_UNWIND)		+= -fasynchronous-unwind-tables
-
 # By default gcc 4.8 generates dwarf4 which kernel unwinder can't grok
 ifeq ($(atleast_gcc48),y)
 cflags-$(CONFIG_ARC_DW2_UNWIND)		+= -gdwarf-2
@@ -74,10 +72,6 @@
 # --build-id w/o "-marclinux". Default arc-elf32-ld is OK
 ldflags-$(upto_gcc44)			+= -marclinux
 
-ifndef CONFIG_ARC_HAS_HW_MPY
-	cflags-y	+= -mno-mpy
-endif
-
 LIBGCC	:= $(shell $(CC) $(cflags-y) --print-libgcc-file-name)
 
 # Modules with short calls might break for calls into builtin-kernel
@@ -114,6 +108,7 @@
 
 boot_targets += uImage uImage.bin uImage.gz
 
+PHONY += $(boot_targets)
 $(boot_targets): vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
@@ -125,16 +120,3 @@
 
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
-
-# Hacks to enable final link due to absence of link-time branch relexation
-# and gcc choosing optimal(shorter) branches at -O3
-#
-# vineetg Feb 2010: -mlong-calls switched off for overall kernel build
-# However lib/decompress_inflate.o (.init.text) calls
-# zlib_inflate_workspacesize (.text) causing relocation errors.
-# Thus forcing all exten calls in this file to be long calls
-export CFLAGS_decompress_inflate.o = -mmedium-calls
-export CFLAGS_initramfs.o = -mmedium-calls
-ifdef CONFIG_SMP
-export CFLAGS_core.o = -mmedium-calls
-endif
--- linux-4.4.0.orig/arch/arc/boot/dts/axs10x_mb.dtsi
+++ linux-4.4.0/arch/arc/boot/dts/axs10x_mb.dtsi
@@ -44,6 +44,7 @@
 			interrupt-names = "macirq";
 			phy-mode = "rgmii";
 			snps,pbl = < 32 >;
+			snps,multicast-filter-bins = <256>;
 			clocks = <&apbclk>;
 			clock-names = "stmmaceth";
 			max-speed = <100>;
--- linux-4.4.0.orig/arch/arc/configs/axs101_defconfig
+++ linux-4.4.0/arch/arc/configs/axs101_defconfig
@@ -1,6 +1,5 @@
 CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_CROSS_MEMORY_ATTACH is not set
@@ -12,12 +11,12 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../arc_initramfs/"
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
+CONFIG_ISA_ARCOMPACT=y
 CONFIG_MODULES=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARC_PLAT_AXS10X=y
@@ -98,6 +97,7 @@
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
--- linux-4.4.0.orig/arch/arc/configs/axs103_defconfig
+++ linux-4.4.0/arch/arc/configs/axs103_defconfig
@@ -1,6 +1,5 @@
 CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_CROSS_MEMORY_ATTACH is not set
@@ -12,7 +11,6 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/"
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
@@ -104,6 +102,7 @@
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
--- linux-4.4.0.orig/arch/arc/configs/axs103_smp_defconfig
+++ linux-4.4.0/arch/arc/configs/axs103_smp_defconfig
@@ -1,6 +1,5 @@
 CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_CROSS_MEMORY_ATTACH is not set
@@ -12,7 +11,6 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/"
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
@@ -105,6 +103,7 @@
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
--- linux-4.4.0.orig/arch/arc/configs/nsim_700_defconfig
+++ linux-4.4.0/arch/arc/configs/nsim_700_defconfig
@@ -11,11 +11,11 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../arc_initramfs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
+CONFIG_ISA_ARCOMPACT=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 # CONFIG_LBDAF is not set
--- linux-4.4.0.orig/arch/arc/configs/nsim_hs_defconfig
+++ linux-4.4.0/arch/arc/configs/nsim_hs_defconfig
@@ -12,7 +12,6 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 # CONFIG_SLUB_DEBUG is not set
--- linux-4.4.0.orig/arch/arc/configs/nsim_hs_smp_defconfig
+++ linux-4.4.0/arch/arc/configs/nsim_hs_smp_defconfig
@@ -9,7 +9,6 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 # CONFIG_SLUB_DEBUG is not set
--- linux-4.4.0.orig/arch/arc/configs/nsimosci_defconfig
+++ linux-4.4.0/arch/arc/configs/nsimosci_defconfig
@@ -12,11 +12,11 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../arc_initramfs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
+CONFIG_ISA_ARCOMPACT=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 # CONFIG_LBDAF is not set
@@ -69,5 +69,6 @@
 CONFIG_TMPFS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
--- linux-4.4.0.orig/arch/arc/configs/nsimosci_hs_defconfig
+++ linux-4.4.0/arch/arc/configs/nsimosci_hs_defconfig
@@ -12,7 +12,6 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 # CONFIG_SLUB_DEBUG is not set
@@ -69,5 +68,6 @@
 CONFIG_TMPFS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
--- linux-4.4.0.orig/arch/arc/configs/nsimosci_hs_smp_defconfig
+++ linux-4.4.0/arch/arc/configs/nsimosci_hs_smp_defconfig
@@ -9,7 +9,6 @@
 # CONFIG_UTS_NS is not set
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/"
 # CONFIG_COMPAT_BRK is not set
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
@@ -88,6 +87,7 @@
 CONFIG_TMPFS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_FTRACE=y
--- linux-4.4.0.orig/arch/arc/configs/tb10x_defconfig
+++ linux-4.4.0/arch/arc/configs/tb10x_defconfig
@@ -19,6 +19,7 @@
 # CONFIG_AIO is not set
 CONFIG_EMBEDDED=y
 # CONFIG_COMPAT_BRK is not set
+CONFIG_ISA_ARCOMPACT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
--- linux-4.4.0.orig/arch/arc/configs/vdk_hs38_defconfig
+++ linux-4.4.0/arch/arc/configs/vdk_hs38_defconfig
@@ -89,6 +89,7 @@
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
--- linux-4.4.0.orig/arch/arc/configs/vdk_hs38_smp_defconfig
+++ linux-4.4.0/arch/arc/configs/vdk_hs38_smp_defconfig
@@ -91,6 +91,7 @@
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
--- linux-4.4.0.orig/arch/arc/include/asm/arcregs.h
+++ linux-4.4.0/arch/arc/include/asm/arcregs.h
@@ -374,12 +374,6 @@
 	return IS_ENABLED(CONFIG_ISA_ARCOMPACT);
 }
 
-#if defined(CONFIG_ISA_ARCOMPACT) && !defined(_CPU_DEFAULT_A7)
-#error "Toolchain not configured for ARCompact builds"
-#elif defined(CONFIG_ISA_ARCV2) && !defined(_CPU_DEFAULT_HS)
-#error "Toolchain not configured for ARCv2 builds"
-#endif
-
 #endif /* __ASEMBLY__ */
 
 #endif /* _ASM_ARC_ARCREGS_H */
--- linux-4.4.0.orig/arch/arc/include/asm/bitops.h
+++ linux-4.4.0/arch/arc/include/asm/bitops.h
@@ -35,21 +35,6 @@
 									\
 	m += nr >> 5;							\
 									\
-	/*								\
-	 * ARC ISA micro-optimization:					\
-	 *								\
-	 * Instructions dealing with bitpos only consider lower 5 bits	\
-	 * e.g (x << 33) is handled like (x << 1) by ASL instruction	\
-	 *  (mem pointer still needs adjustment to point to next word)	\
-	 *								\
-	 * Hence the masking to clamp @nr arg can be elided in general.	\
-	 *								\
-	 * However if @nr is a constant (above assumed in a register),	\
-	 * and greater than 31, gcc can optimize away (x << 33) to 0,	\
-	 * as overflow, given the 32-bit ISA. Thus masking needs to be	\
-	 * done for const @nr, but no code is generated due to gcc	\
-	 * const prop.							\
-	 */								\
 	nr &= 0x1f;							\
 									\
 	__asm__ __volatile__(						\
@@ -301,7 +286,7 @@
 /*
  * __ffs: Similar to ffs, but zero based (0-31)
  */
-static inline __attribute__ ((const)) int __ffs(unsigned long word)
+static inline __attribute__ ((const)) unsigned long __ffs(unsigned long word)
 {
 	if (!word)
 		return word;
@@ -361,9 +346,9 @@
 /*
  * __ffs: Similar to ffs, but zero based (0-31)
  */
-static inline __attribute__ ((const)) int __ffs(unsigned long x)
+static inline __attribute__ ((const)) unsigned long __ffs(unsigned long x)
 {
-	int n;
+	unsigned long n;
 
 	asm volatile(
 	"	ffs.f	%0, %1		\n"  /* 0:31; 31(Z) if src 0 */
--- linux-4.4.0.orig/arch/arc/include/asm/bug.h
+++ linux-4.4.0/arch/arc/include/asm/bug.h
@@ -23,7 +23,8 @@
 
 #define BUG()	do {								\
 	pr_warn("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
-	dump_stack();								\
+	barrier_before_unreachable();						\
+	__builtin_trap();							\
 } while (0)
 
 #define HAVE_ARCH_BUG
--- linux-4.4.0.orig/arch/arc/include/asm/cache.h
+++ linux-4.4.0/arch/arc/include/asm/cache.h
@@ -88,7 +88,9 @@
 #define ARC_REG_SLC_FLUSH	0x904
 #define ARC_REG_SLC_INVALIDATE	0x905
 #define ARC_REG_SLC_RGN_START	0x914
+#define ARC_REG_SLC_RGN_START1	0x915
 #define ARC_REG_SLC_RGN_END	0x916
+#define ARC_REG_SLC_RGN_END1	0x917
 
 /* Bit val in SLC_CONTROL */
 #define SLC_CTRL_IM		0x040
--- linux-4.4.0.orig/arch/arc/include/asm/cacheflush.h
+++ linux-4.4.0/arch/arc/include/asm/cacheflush.h
@@ -85,6 +85,10 @@
  */
 #define PG_dc_clean	PG_arch_1
 
+#define CACHE_COLORS_NUM	4
+#define CACHE_COLORS_MSK	(CACHE_COLORS_NUM - 1)
+#define CACHE_COLOR(addr)	(((unsigned long)(addr) >> (PAGE_SHIFT)) & CACHE_COLORS_MSK)
+
 /*
  * Simple wrapper over config option
  * Bootup code ensures that hardware matches kernel configuration
@@ -94,8 +98,6 @@
 	return IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
 }
 
-#define CACHE_COLOR(addr)	(((unsigned long)(addr) >> (PAGE_SHIFT)) & 1)
-
 /*
  * checks if two addresses (after page aligning) index into same cache set
  */
--- linux-4.4.0.orig/arch/arc/include/asm/delay.h
+++ linux-4.4.0/arch/arc/include/asm/delay.h
@@ -17,15 +17,21 @@
 #ifndef __ASM_ARC_UDELAY_H
 #define __ASM_ARC_UDELAY_H
 
+#include <asm-generic/types.h>
 #include <asm/param.h>		/* HZ */
 
+extern unsigned long loops_per_jiffy;
+
 static inline void __delay(unsigned long loops)
 {
 	__asm__ __volatile__(
-	"	lp  1f	\n"
-	"	nop	\n"
-	"1:		\n"
-	: "+l"(loops));
+	"	mov lp_count, %0	\n"
+	"	lp  1f			\n"
+	"	nop			\n"
+	"1:				\n"
+	:
+        : "r"(loops)
+        : "lp_count");
 }
 
 extern void __bad_udelay(void);
--- linux-4.4.0.orig/arch/arc/include/asm/elf.h
+++ linux-4.4.0/arch/arc/include/asm/elf.h
@@ -27,7 +27,7 @@
 #define  R_ARC_S25W_PCREL	0x11
 
 /*to set parameters in the core dumps */
-#define ELF_ARCH		EM_ARCOMPACT
+#define ELF_ARCH		EM_ARC_INUSE
 #define ELF_CLASS		ELFCLASS32
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
@@ -55,7 +55,7 @@
  * the loader.  We need to make sure that it is out of the way of the program
  * that it will "exec", and that there is sufficient room for the brk.
  */
-#define ELF_ET_DYN_BASE		(2 * TASK_SIZE / 3)
+#define ELF_ET_DYN_BASE		(2UL * TASK_SIZE / 3)
 
 /*
  * When the program starts, a1 contains a pointer to a function to be
--- linux-4.4.0.orig/arch/arc/include/asm/entry-arcv2.h
+++ linux-4.4.0/arch/arc/include/asm/entry-arcv2.h
@@ -16,6 +16,7 @@
 	;
 	; Now manually save: r12, sp, fp, gp, r25
 
+	PUSH	r30
 	PUSH	r12
 
 	; Saving pt_regs->sp correctly requires some extra work due to the way
@@ -72,6 +73,7 @@
 	POPAX	AUX_USER_SP
 1:
 	POP	r12
+	POP	r30
 
 .endm
 
--- linux-4.4.0.orig/arch/arc/include/asm/entry.h
+++ linux-4.4.0/arch/arc/include/asm/entry.h
@@ -142,7 +142,7 @@
 
 #ifdef CONFIG_ARC_CURR_IN_REG
 	; Retrieve orig r25 and save it with rest of callee_regs
-	ld.as   r12, [r12, PT_user_r25]
+	ld	r12, [r12, PT_user_r25]
 	PUSH	r12
 #else
 	PUSH	r25
@@ -198,7 +198,7 @@
 
 	; SP is back to start of pt_regs
 #ifdef CONFIG_ARC_CURR_IN_REG
-	st.as   r12, [sp, PT_user_r25]
+	st	r12, [sp, PT_user_r25]
 #endif
 .endm
 
--- linux-4.4.0.orig/arch/arc/include/asm/futex.h
+++ linux-4.4.0/arch/arc/include/asm/futex.h
@@ -73,20 +73,11 @@
 
 #endif
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
-		return -EFAULT;
-
 #ifndef CONFIG_ARC_HAS_LLSC
 	preempt_disable();	/* to guarantee atomic r-m-w of futex op */
 #endif
@@ -118,30 +109,9 @@
 	preempt_enable();
 #endif
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (oldval == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (oldval != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (oldval < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (oldval >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (oldval <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (oldval > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/arc/include/asm/io.h
+++ linux-4.4.0/arch/arc/include/asm/io.h
@@ -12,6 +12,16 @@
 #include <linux/types.h>
 #include <asm/byteorder.h>
 #include <asm/page.h>
+#include <asm/unaligned.h>
+
+#ifdef CONFIG_ISA_ARCV2
+#include <asm/barrier.h>
+#define __iormb()		rmb()
+#define __iowmb()		wmb()
+#else
+#define __iormb()		do { } while (0)
+#define __iowmb()		do { } while (0)
+#endif
 
 extern void __iomem *ioremap(unsigned long physaddr, unsigned long size);
 extern void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
@@ -22,6 +32,15 @@
 #define ioremap_wc(phy, sz)		ioremap(phy, sz)
 #define ioremap_wt(phy, sz)		ioremap(phy, sz)
 
+/*
+ * io{read,write}{16,32}be() macros
+ */
+#define ioread16be(p)		({ u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
+#define ioread32be(p)		({ u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
+
+#define iowrite16be(v,p)	({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); })
+#define iowrite32be(v,p)	({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); })
+
 /* Change struct page to physical address */
 #define page_to_phys(page)		(page_to_pfn(page) << PAGE_SHIFT)
 
@@ -67,6 +86,42 @@
 	return w;
 }
 
+/*
+ * {read,write}s{b,w,l}() repeatedly access the same IO address in
+ * native endianness in 8-, 16-, 32-bit chunks {into,from} memory,
+ * @count times
+ */
+#define __raw_readsx(t,f) \
+static inline void __raw_reads##f(const volatile void __iomem *addr,	\
+				  void *ptr, unsigned int count)	\
+{									\
+	bool is_aligned = ((unsigned long)ptr % ((t) / 8)) == 0;	\
+	u##t *buf = ptr;						\
+									\
+	if (!count)							\
+		return;							\
+									\
+	/* Some ARC CPU's don't support unaligned accesses */		\
+	if (is_aligned) {						\
+		do {							\
+			u##t x = __raw_read##f(addr);			\
+			*buf++ = x;					\
+		} while (--count);					\
+	} else {							\
+		do {							\
+			u##t x = __raw_read##f(addr);			\
+			put_unaligned(x, buf++);			\
+		} while (--count);					\
+	}								\
+}
+
+#define __raw_readsb __raw_readsb
+__raw_readsx(8, b)
+#define __raw_readsw __raw_readsw
+__raw_readsx(16, w)
+#define __raw_readsl __raw_readsl
+__raw_readsx(32, l)
+
 #define __raw_writeb __raw_writeb
 static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
 {
@@ -99,14 +154,34 @@
 
 }
 
-#ifdef CONFIG_ISA_ARCV2
-#include <asm/barrier.h>
-#define __iormb()		rmb()
-#define __iowmb()		wmb()
-#else
-#define __iormb()		do { } while (0)
-#define __iowmb()		do { } while (0)
-#endif
+#define __raw_writesx(t,f)						\
+static inline void __raw_writes##f(volatile void __iomem *addr, 	\
+				   const void *ptr, unsigned int count)	\
+{									\
+	bool is_aligned = ((unsigned long)ptr % ((t) / 8)) == 0;	\
+	const u##t *buf = ptr;						\
+									\
+	if (!count)							\
+		return;							\
+									\
+	/* Some ARC CPU's don't support unaligned accesses */		\
+	if (is_aligned) {						\
+		do {							\
+			__raw_write##f(*buf++, addr);			\
+		} while (--count);					\
+	} else {							\
+		do {							\
+			__raw_write##f(get_unaligned(buf++), addr);	\
+		} while (--count);					\
+	}								\
+}
+
+#define __raw_writesb __raw_writesb
+__raw_writesx(8, b)
+#define __raw_writesw __raw_writesw
+__raw_writesx(16, w)
+#define __raw_writesl __raw_writesl
+__raw_writesx(32, l)
 
 /*
  * MMIO can also get buffered/optimized in micro-arch, so barriers needed
@@ -123,21 +198,35 @@
 #define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
 #define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
 #define readl(c)		({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+#define readsb(p,d,l)		({ __raw_readsb(p,d,l); __iormb(); })
+#define readsw(p,d,l)		({ __raw_readsw(p,d,l); __iormb(); })
+#define readsl(p,d,l)		({ __raw_readsl(p,d,l); __iormb(); })
 
 #define writeb(v,c)		({ __iowmb(); writeb_relaxed(v,c); })
 #define writew(v,c)		({ __iowmb(); writew_relaxed(v,c); })
 #define writel(v,c)		({ __iowmb(); writel_relaxed(v,c); })
+#define writesb(p,d,l)		({ __iowmb(); __raw_writesb(p,d,l); })
+#define writesw(p,d,l)		({ __iowmb(); __raw_writesw(p,d,l); })
+#define writesl(p,d,l)		({ __iowmb(); __raw_writesl(p,d,l); })
 
 /*
- * Relaxed API for drivers which can handle any ordering themselves
+ * Relaxed API for drivers which can handle barrier ordering themselves
+ *
+ * Also these are defined to perform little endian accesses.
+ * To provide the typical device register semantics of fixed endian,
+ * swap the byte order for Big Endian
+ *
+ * http://lkml.kernel.org/r/201603100845.30602.arnd@arndb.de
  */
 #define readb_relaxed(c)	__raw_readb(c)
-#define readw_relaxed(c)	__raw_readw(c)
-#define readl_relaxed(c)	__raw_readl(c)
+#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
+					__raw_readw(c)); __r; })
+#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
+					__raw_readl(c)); __r; })
 
 #define writeb_relaxed(v,c)	__raw_writeb(v,c)
-#define writew_relaxed(v,c)	__raw_writew(v,c)
-#define writel_relaxed(v,c)	__raw_writel(v,c)
+#define writew_relaxed(v,c)	__raw_writew((__force u16) cpu_to_le16(v),c)
+#define writel_relaxed(v,c)	__raw_writel((__force u32) cpu_to_le32(v),c)
 
 #include <asm-generic/io.h>
 
--- linux-4.4.0.orig/arch/arc/include/asm/irqflags-arcv2.h
+++ linux-4.4.0/arch/arc/include/asm/irqflags-arcv2.h
@@ -22,6 +22,7 @@
 #define AUX_IRQ_CTRL		0x00E
 #define AUX_IRQ_ACT		0x043	/* Active Intr across all levels */
 #define AUX_IRQ_LVL_PEND	0x200	/* Pending Intr across all levels */
+#define AUX_IRQ_HINT		0x201	/* For generating Soft Interrupts */
 #define AUX_IRQ_PRIORITY	0x206
 #define ICAUSE			0x40a
 #define AUX_IRQ_SELECT		0x40b
@@ -112,6 +113,16 @@
 	return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
+static inline void arc_softirq_trigger(int irq)
+{
+	write_aux_reg(AUX_IRQ_HINT, irq);
+}
+
+static inline void arc_softirq_clear(int irq)
+{
+	write_aux_reg(AUX_IRQ_HINT, 0);
+}
+
 #else
 
 .macro IRQ_DISABLE  scratch
--- linux-4.4.0.orig/arch/arc/include/asm/irqflags-compact.h
+++ linux-4.4.0/arch/arc/include/asm/irqflags-compact.h
@@ -188,10 +188,10 @@
 .endm
 
 .macro IRQ_ENABLE  scratch
+	TRACE_ASM_IRQ_ENABLE
 	lr	\scratch, [status32]
 	or	\scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
 	flag	\scratch
-	TRACE_ASM_IRQ_ENABLE
 .endm
 
 #endif	/* __ASSEMBLY__ */
--- linux-4.4.0.orig/arch/arc/include/asm/linkage.h
+++ linux-4.4.0/arch/arc/include/asm/linkage.h
@@ -12,6 +12,8 @@
 #ifdef __ASSEMBLY__
 
 #define ASM_NL		 `	/* use '`' to mark new line in macro */
+#define __ALIGN		.align 4
+#define __ALIGN_STR	__stringify(__ALIGN)
 
 /* annotation for data we want in DCCM - if enabled in .config */
 .macro ARCFP_DATA nm
--- linux-4.4.0.orig/arch/arc/include/asm/mach_desc.h
+++ linux-4.4.0/arch/arc/include/asm/mach_desc.h
@@ -34,9 +34,7 @@
 	const char		*name;
 	const char		**dt_compat;
 	void			(*init_early)(void);
-#ifdef CONFIG_SMP
 	void			(*init_per_cpu)(unsigned int);
-#endif
 	void			(*init_machine)(void);
 	void			(*init_late)(void);
 
--- linux-4.4.0.orig/arch/arc/include/asm/page.h
+++ linux-4.4.0/arch/arc/include/asm/page.h
@@ -17,6 +17,7 @@
 #define free_user_page(page, addr)	free_page(addr)
 
 #define clear_page(paddr)		memset((paddr), 0, PAGE_SIZE)
+#define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 #define copy_page(to, from)		memcpy((to), (from), PAGE_SIZE)
 
 struct vm_area_struct;
@@ -102,7 +103,7 @@
 #define virt_addr_valid(kaddr)  pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 /* Default Permissions for stack/heaps pages (Non Executable) */
-#define VM_DATA_DEFAULT_FLAGS   (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE)
+#define VM_DATA_DEFAULT_FLAGS   (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #define WANT_PAGE_VIRTUAL   1
 
--- linux-4.4.0.orig/arch/arc/include/asm/perf_event.h
+++ linux-4.4.0/arch/arc/include/asm/perf_event.h
@@ -103,7 +103,8 @@
 
 	/* counts condition */
 	[PERF_COUNT_HW_INSTRUCTIONS] = "iall",
-	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "ijmp", /* Excludes ZOL jumps */
+	/* All jump instructions that are taken */
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "ijmptak",
 	[PERF_COUNT_ARC_BPOK]         = "bpok",	  /* NP-NT, PT-T, PNT-NT */
 #ifdef CONFIG_ISA_ARCV2
 	[PERF_COUNT_HW_BRANCH_MISSES] = "bpmp",
--- linux-4.4.0.orig/arch/arc/include/asm/pgtable.h
+++ linux-4.4.0/arch/arc/include/asm/pgtable.h
@@ -110,7 +110,7 @@
 #define ___DEF (_PAGE_PRESENT | _PAGE_CACHEABLE)
 
 /* Set of bits not changed in pte_modify */
-#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SPECIAL)
 
 /* More Abbrevaited helpers */
 #define PAGE_U_NONE     __pgprot(___DEF)
@@ -277,8 +277,7 @@
 
 #define mk_pte(page, prot)	pfn_pte(page_to_pfn(page), prot)
 #define pte_pfn(pte)		(pte_val(pte) >> PAGE_SHIFT)
-#define pfn_pte(pfn, prot)	(__pte(((pte_t)(pfn) << PAGE_SHIFT) | \
-				 pgprot_val(prot)))
+#define pfn_pte(pfn, prot)	(__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)))
 #define __pte_index(addr)	(((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 
 /*
@@ -373,7 +372,7 @@
 
 /* Decode a PTE containing swap "identifier "into constituents */
 #define __swp_type(pte_lookalike)	(((pte_lookalike).val) & 0x1f)
-#define __swp_offset(pte_lookalike)	((pte_lookalike).val << 13)
+#define __swp_offset(pte_lookalike)	((pte_lookalike).val >> 13)
 
 /* NOPs, to keep generic kernel happy */
 #define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
--- linux-4.4.0.orig/arch/arc/include/asm/ptrace.h
+++ linux-4.4.0/arch/arc/include/asm/ptrace.h
@@ -84,7 +84,7 @@
 	unsigned long fp;
 	unsigned long sp;	/* user/kernel sp depending on where we came from  */
 
-	unsigned long r12;
+	unsigned long r12, r30;
 
 	/*------- Below list auto saved by h/w -----------*/
 	unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
--- linux-4.4.0.orig/arch/arc/include/asm/uaccess.h
+++ linux-4.4.0/arch/arc/include/asm/uaccess.h
@@ -83,7 +83,10 @@
 	"2:	;nop\n"				\
 	"	.section .fixup, \"ax\"\n"	\
 	"	.align 4\n"			\
-	"3:	mov %0, %3\n"			\
+	"3:	# return -EFAULT\n"		\
+	"	mov %0, %3\n"			\
+	"	# zero out dst ptr\n"		\
+	"	mov %1,  0\n"			\
 	"	j   2b\n"			\
 	"	.previous\n"			\
 	"	.section __ex_table, \"a\"\n"	\
@@ -101,7 +104,11 @@
 	"2:	;nop\n"				\
 	"	.section .fixup, \"ax\"\n"	\
 	"	.align 4\n"			\
-	"3:	mov %0, %3\n"			\
+	"3:	# return -EFAULT\n"		\
+	"	mov %0, %3\n"			\
+	"	# zero out dst ptr\n"		\
+	"	mov %1,  0\n"			\
+	"	mov %R1, 0\n"			\
 	"	j   2b\n"			\
 	"	.previous\n"			\
 	"	.section __ex_table, \"a\"\n"	\
@@ -202,7 +209,7 @@
 		*/
 		  "=&r" (tmp), "+r" (to), "+r" (from)
 		:
-		: "lp_count", "lp_start", "lp_end", "memory");
+		: "lp_count", "memory");
 
 		return n;
 	}
@@ -431,7 +438,7 @@
 		 */
 		  "=&r" (tmp), "+r" (to), "+r" (from)
 		:
-		: "lp_count", "lp_start", "lp_end", "memory");
+		: "lp_count", "memory");
 
 		return n;
 	}
@@ -651,7 +658,7 @@
 	"	.previous			\n"
 	: "+r"(d_char), "+r"(res)
 	: "i"(0)
-	: "lp_count", "lp_start", "lp_end", "memory");
+	: "lp_count", "memory");
 
 	return res;
 }
@@ -666,6 +673,7 @@
 		return 0;
 
 	__asm__ __volatile__(
+	"	mov	lp_count, %5		\n"
 	"	lp	3f			\n"
 	"1:	ldb.ab  %3, [%2, 1]		\n"
 	"	breq.d	%3, 0, 3f               \n"
@@ -682,8 +690,8 @@
 	"	.word   1b, 4b			\n"
 	"	.previous			\n"
 	: "+r"(res), "+r"(dst), "+r"(src), "=r"(val)
-	: "g"(-EFAULT), "l"(count)
-	: "memory");
+	: "g"(-EFAULT), "r"(count)
+	: "lp_count", "memory");
 
 	return res;
 }
--- linux-4.4.0.orig/arch/arc/kernel/entry-arcv2.S
+++ linux-4.4.0/arch/arc/kernel/entry-arcv2.S
@@ -45,11 +45,12 @@
 VECTOR	handle_interrupt	; (16) Timer0
 VECTOR	handle_interrupt	; unused (Timer1)
 VECTOR	handle_interrupt	; unused (WDT)
-VECTOR	handle_interrupt	; (19) ICI (inter core interrupt)
-VECTOR	handle_interrupt
-VECTOR	handle_interrupt
-VECTOR	handle_interrupt
-VECTOR	handle_interrupt	; (23) End of fixed IRQs
+VECTOR	handle_interrupt	; (19) Inter core Interrupt (IPI)
+VECTOR	handle_interrupt	; (20) perf Interrupt
+VECTOR	handle_interrupt	; (21) Software Triggered Intr (Self IPI)
+VECTOR	handle_interrupt	; unused
+VECTOR	handle_interrupt	; (23) unused
+# End of fixed IRQs
 
 .rept CONFIG_ARC_NUMBER_OF_INTERRUPTS - 8
 	VECTOR	handle_interrupt
@@ -211,7 +212,11 @@
 ; (since IRQ NOT allowed in DS in ARCv2, this can only happen if orig
 ; entry was via Exception in DS which got preempted in kernel).
 ;
-; IRQ RTIE won't reliably restore DE bit and/or BTA, needs handling
+; IRQ RTIE won't reliably restore DE bit and/or BTA, needs workaround
+;
+; Solution is return from Intr w/o any delay slot quirks into a kernel trampoline
+; and from pure kernel mode return to delay slot which handles DS bit/BTA correctly
+
 .Lintr_ret_to_delay_slot:
 debug_marker_ds:
 
@@ -222,18 +227,23 @@
 	ld	r2, [sp, PT_ret]
 	ld	r3, [sp, PT_status32]
 
+	; STAT32 for Int return created from scratch
+	; (No delay dlot, disable Further intr in trampoline)
+
 	bic  	r0, r3, STATUS_U_MASK|STATUS_DE_MASK|STATUS_IE_MASK|STATUS_L_MASK
 	st	r0, [sp, PT_status32]
 
 	mov	r1, .Lintr_ret_to_delay_slot_2
 	st	r1, [sp, PT_ret]
 
+	; Orig exception PC/STAT32 safekept @orig_r0 and @event stack slots
 	st	r2, [sp, 0]
 	st	r3, [sp, 4]
 
 	b	.Lisr_ret_fast_path
 
 .Lintr_ret_to_delay_slot_2:
+	; Trampoline to restore orig exception PC/STAT32/BTA/AUX_USER_SP
 	sub	sp, sp, SZ_PT_REGS
 	st	r9, [sp, -4]
 
@@ -243,11 +253,19 @@
 	ld	r9, [sp, 4]
 	sr	r9, [erstatus]
 
+	; restore AUX_USER_SP if returning to U mode
+	bbit0	r9, STATUS_U_BIT, 1f
+	ld	r9, [sp, PT_sp]
+	sr	r9, [AUX_USER_SP]
+
+1:
 	ld	r9, [sp, 8]
 	sr	r9, [erbta]
 
 	ld	r9, [sp, -4]
 	add	sp, sp, SZ_PT_REGS
+
+	; return from pure kernel mode to delay slot
 	rtie
 
 END(ret_from_exception)
--- linux-4.4.0.orig/arch/arc/kernel/entry.S
+++ linux-4.4.0/arch/arc/kernel/entry.S
@@ -104,6 +104,12 @@
 	lr  r0, [efa]
 	mov r1, sp
 
+	; hardware auto-disables MMU, re-enable it to allow kernel vaddr
+	; access for say stack unwinding of modules for crash dumps
+	lr	r3, [ARC_REG_PID]
+	or	r3, r3, MMU_ENABLE
+	sr	r3, [ARC_REG_PID]
+
 	lsr  	r3, r2, 8
 	bmsk 	r3, r3, 7
 	brne    r3, ECR_C_MCHK_DUP_TLB, 1f
--- linux-4.4.0.orig/arch/arc/kernel/head.S
+++ linux-4.4.0/arch/arc/kernel/head.S
@@ -17,6 +17,7 @@
 #include <asm/entry.h>
 #include <asm/arcregs.h>
 #include <asm/cache.h>
+#include <asm/irqflags.h>
 
 .macro CPU_EARLY_SETUP
 
@@ -47,6 +48,15 @@
 	sr	r5, [ARC_REG_DC_CTRL]
 
 1:
+
+#ifdef CONFIG_ISA_ARCV2
+	; Unaligned access is disabled at reset, so re-enable early as
+	; gcc 7.3.1 (ARC GNU 2018.03) onwards generates unaligned access
+	; by default
+	lr	r5, [status32]
+	bset	r5, r5, STATUS_AD_BIT
+	kflag	r5
+#endif
 .endm
 
 	.section .init.text, "ax",@progbits
--- linux-4.4.0.orig/arch/arc/kernel/irq.c
+++ linux-4.4.0/arch/arc/kernel/irq.c
@@ -31,10 +31,10 @@
 	/* a SMP H/w block could do IPI IRQ request here */
 	if (plat_smp_ops.init_per_cpu)
 		plat_smp_ops.init_per_cpu(smp_processor_id());
+#endif
 
 	if (machine_desc->init_per_cpu)
 		machine_desc->init_per_cpu(smp_processor_id());
-#endif
 }
 
 /*
--- linux-4.4.0.orig/arch/arc/kernel/mcip.c
+++ linux-4.4.0/arch/arc/kernel/mcip.c
@@ -11,9 +11,12 @@
 #include <linux/smp.h>
 #include <linux/irq.h>
 #include <linux/spinlock.h>
+#include <asm/irqflags-arcv2.h>
 #include <asm/mcip.h>
 #include <asm/setup.h>
 
+#define SOFTIRQ_IRQ	21
+
 static char smp_cpuinfo_buf[128];
 static int idu_detected;
 
@@ -22,6 +25,7 @@
 static void mcip_setup_per_cpu(int cpu)
 {
 	smp_ipi_irq_setup(cpu, IPI_IRQ);
+	smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ);
 }
 
 static void mcip_ipi_send(int cpu)
@@ -29,6 +33,12 @@
 	unsigned long flags;
 	int ipi_was_pending;
 
+	/* ARConnect can only send IPI to others */
+	if (unlikely(cpu == raw_smp_processor_id())) {
+		arc_softirq_trigger(SOFTIRQ_IRQ);
+		return;
+	}
+
 	/*
 	 * NOTE: We must spin here if the other cpu hasn't yet
 	 * serviced a previous message. This can burn lots
@@ -63,6 +73,11 @@
 	unsigned long flags;
 	unsigned int __maybe_unused copy;
 
+	if (unlikely(irq == SOFTIRQ_IRQ)) {
+		arc_softirq_clear(irq);
+		return;
+	}
+
 	raw_spin_lock_irqsave(&mcip_lock, flags);
 
 	/* Who sent the IPI */
--- linux-4.4.0.orig/arch/arc/kernel/perf_event.c
+++ linux-4.4.0/arch/arc/kernel/perf_event.c
@@ -486,8 +486,8 @@
 	/* loop thru all available h/w condition indexes */
 	for (j = 0; j < cc_bcr.c; j++) {
 		write_aux_reg(ARC_REG_CC_INDEX, j);
-		cc_name.indiv.word0 = read_aux_reg(ARC_REG_CC_NAME0);
-		cc_name.indiv.word1 = read_aux_reg(ARC_REG_CC_NAME1);
+		cc_name.indiv.word0 = le32_to_cpu(read_aux_reg(ARC_REG_CC_NAME0));
+		cc_name.indiv.word1 = le32_to_cpu(read_aux_reg(ARC_REG_CC_NAME1));
 
 		/* See if it has been mapped to a perf event_id */
 		for (i = 0; i < ARRAY_SIZE(arc_pmu_ev_hw_map); i++) {
--- linux-4.4.0.orig/arch/arc/kernel/process.c
+++ linux-4.4.0/arch/arc/kernel/process.c
@@ -153,6 +153,26 @@
 		task_thread_info(current)->thr_ptr;
 	}
 
+
+	/*
+	 * setup usermode thread pointer #1:
+	 * when child is picked by scheduler, __switch_to() uses @c_callee to
+	 * populate usermode callee regs: this works (despite being in a kernel
+	 * function) since special return path for child @ret_from_fork()
+	 * ensures those regs are not clobbered all the way to RTIE to usermode
+	 */
+	c_callee->r25 = task_thread_info(p)->thr_ptr;
+
+#ifdef CONFIG_ARC_CURR_IN_REG
+	/*
+	 * setup usermode thread pointer #2:
+	 * however for this special use of r25 in kernel, __switch_to() sets
+	 * r25 for kernel needs and only in the final return path is usermode
+	 * r25 setup, from pt_regs->user_r25. So set that up as well
+	 */
+	c_regs->user_r25 = c_callee->r25;
+#endif
+
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/arc/kernel/setup.c
+++ linux-4.4.0/arch/arc/kernel/setup.c
@@ -12,6 +12,7 @@
 #include <linux/root_dev.h>
 #include <linux/console.h>
 #include <linux/module.h>
+#include <linux/sizes.h>
 #include <linux/cpu.h>
 #include <linux/clk-provider.h>
 #include <linux/of_fdt.h>
@@ -232,8 +233,6 @@
 
 			n += scnprintf(buf + n, len - n, "mpy[opt %d] ", opt);
 		}
-		n += scnprintf(buf + n, len - n, "%s",
-			       IS_USED_CFG(CONFIG_ARC_HAS_HW_MPY));
 	}
 
 	n += scnprintf(buf + n, len - n, "%s%s%s%s%s%s%s%s\n",
@@ -310,12 +309,12 @@
 	if ((unsigned int)__arc_dccm_base != cpu->dccm.base_addr)
 		panic("Linux built with incorrect DCCM Base address\n");
 
-	if (CONFIG_ARC_DCCM_SZ != cpu->dccm.sz)
+	if (CONFIG_ARC_DCCM_SZ * SZ_1K != cpu->dccm.sz)
 		panic("Linux built with incorrect DCCM Size\n");
 #endif
 
 #ifdef CONFIG_ARC_HAS_ICCM
-	if (CONFIG_ARC_ICCM_SZ != cpu->iccm.sz)
+	if (CONFIG_ARC_ICCM_SZ * SZ_1K != cpu->iccm.sz)
 		panic("Linux built with incorrect ICCM Size\n");
 #endif
 
@@ -332,10 +331,6 @@
 		pr_warn("CONFIG_ARC_FPU_SAVE_RESTORE needed for working apps\n");
 	else if (!cpu->extn.fpu_dp && fpu_enabled)
 		panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n");
-
-	if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic &&
-	    !IS_ENABLED(CONFIG_ARC_STAR_9000923308))
-		panic("llock/scond livelock workaround missing\n");
 }
 
 /*
--- linux-4.4.0.orig/arch/arc/kernel/signal.c
+++ linux-4.4.0/arch/arc/kernel/signal.c
@@ -107,13 +107,13 @@
 	struct user_regs_struct uregs;
 
 	err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
-	if (!err)
-		set_current_blocked(&set);
-
 	err |= __copy_from_user(&uregs.scratch,
 				&(sf->uc.uc_mcontext.regs.scratch),
 				sizeof(sf->uc.uc_mcontext.regs.scratch));
+	if (err)
+		return err;
 
+	set_current_blocked(&set);
 	regs->bta	= uregs.scratch.bta;
 	regs->lp_start	= uregs.scratch.lp_start;
 	regs->lp_end	= uregs.scratch.lp_end;
@@ -138,7 +138,7 @@
 	regs->r0	= uregs.scratch.r0;
 	regs->sp	= uregs.scratch.sp;
 
-	return err;
+	return 0;
 }
 
 static inline int is_do_ss_needed(unsigned int magic)
--- linux-4.4.0.orig/arch/arc/kernel/stacktrace.c
+++ linux-4.4.0/arch/arc/kernel/stacktrace.c
@@ -39,15 +39,15 @@
 
 #ifdef CONFIG_ARC_DW2_UNWIND
 
-static void seed_unwind_frame_info(struct task_struct *tsk,
-				   struct pt_regs *regs,
-				   struct unwind_frame_info *frame_info)
+static int
+seed_unwind_frame_info(struct task_struct *tsk, struct pt_regs *regs,
+		       struct unwind_frame_info *frame_info)
 {
 	/*
 	 * synchronous unwinding (e.g. dump_stack)
 	 *  - uses current values of SP and friends
 	 */
-	if (tsk == NULL && regs == NULL) {
+	if (regs == NULL && (tsk == NULL || tsk == current)) {
 		unsigned long fp, sp, blink, ret;
 		frame_info->task = current;
 
@@ -66,11 +66,15 @@
 		frame_info->call_frame = 0;
 	} else if (regs == NULL) {
 		/*
-		 * Asynchronous unwinding of sleeping task
-		 *  - Gets SP etc from task's pt_regs (saved bottom of kernel
-		 *    mode stack of task)
+		 * Asynchronous unwinding of a likely sleeping task
+		 *  - first ensure it is actually sleeping
+		 *  - if so, it will be in __switch_to, kernel mode SP of task
+		 *    is safe-kept and BLINK at a well known location in there
 		 */
 
+		if (tsk->state == TASK_RUNNING)
+			return -1;
+
 		frame_info->task = tsk;
 
 		frame_info->regs.r27 = TSK_K_FP(tsk);
@@ -104,6 +108,8 @@
 		frame_info->regs.r63 = regs->ret;
 		frame_info->call_frame = 0;
 	}
+
+	return 0;
 }
 
 #endif
@@ -113,11 +119,12 @@
 		int (*consumer_fn) (unsigned int, void *), void *arg)
 {
 #ifdef CONFIG_ARC_DW2_UNWIND
-	int ret = 0;
+	int ret = 0, cnt = 0;
 	unsigned int address;
 	struct unwind_frame_info frame_info;
 
-	seed_unwind_frame_info(tsk, regs, &frame_info);
+	if (seed_unwind_frame_info(tsk, regs, &frame_info))
+		return 0;
 
 	while (1) {
 		address = UNW_PC(&frame_info);
@@ -133,6 +140,11 @@
 			break;
 
 		frame_info.regs.r63 = frame_info.regs.r31;
+
+		if (cnt++ > 128) {
+			printk("unwinder looping too long, aborting !\n");
+			return 0;
+		}
 	}
 
 	return address;		/* return the last address it saw */
@@ -142,7 +154,7 @@
 	 * prelogue is setup (callee regs saved and then fp set and not other
 	 * way around
 	 */
-	pr_warn("CONFIG_ARC_DW2_UNWIND needs to be enabled\n");
+	pr_warn_once("CONFIG_ARC_DW2_UNWIND needs to be enabled\n");
 	return 0;
 
 #endif
--- linux-4.4.0.orig/arch/arc/kernel/time.c
+++ linux-4.4.0/arch/arc/kernel/time.c
@@ -130,14 +130,17 @@
 		cycle_t  full;
 	} stamp;
 
-
-	__asm__ __volatile(
-	"1:						\n"
-	"	lr		%0, [AUX_RTC_LOW]	\n"
-	"	lr		%1, [AUX_RTC_HIGH]	\n"
-	"	lr		%2, [AUX_RTC_CTRL]	\n"
-	"	bbit0.nt	%2, 31, 1b		\n"
-	: "=r" (stamp.low), "=r" (stamp.high), "=r" (status));
+	/*
+	 * hardware has an internal state machine which tracks readout of
+	 * low/high and updates the CTRL.status if
+	 *  - interrupt/exception taken between the two reads
+	 *  - high increments after low has been read
+	 */
+	do {
+		stamp.low = read_aux_reg(AUX_RTC_LOW);
+		stamp.high = read_aux_reg(AUX_RTC_HIGH);
+		status = read_aux_reg(AUX_RTC_CTRL);
+	} while (!(status & _BITUL(31)));
 
 	return stamp.full;
 }
--- linux-4.4.0.orig/arch/arc/kernel/traps.c
+++ linux-4.4.0/arch/arc/kernel/traps.c
@@ -155,3 +155,12 @@
 
 	insterror_is_error(address, regs);
 }
+
+/*
+ * abort() call generated by older gcc for __builtin_trap()
+ */
+void abort(void)
+{
+	__asm__ __volatile__("trap_s  5\n");
+}
+EXPORT_SYMBOL(abort);
--- linux-4.4.0.orig/arch/arc/kernel/unaligned.c
+++ linux-4.4.0/arch/arc/kernel/unaligned.c
@@ -241,8 +241,9 @@
 	if (state.fault)
 		goto fault;
 
+	/* clear any remanants of delay slot */
 	if (delay_mode(regs)) {
-		regs->ret = regs->bta;
+		regs->ret = regs->bta & ~1U;
 		regs->status32 &= ~STATUS_DE_MASK;
 	} else {
 		regs->ret += state.instr_len;
--- linux-4.4.0.orig/arch/arc/kernel/unwind.c
+++ linux-4.4.0/arch/arc/kernel/unwind.c
@@ -183,11 +183,6 @@
 				       MAX_DMA_ADDRESS);
 }
 
-static void *unw_hdr_alloc(unsigned long sz)
-{
-	return kmalloc(sz, GFP_KERNEL);
-}
-
 static void init_unwind_table(struct unwind_table *table, const char *name,
 			      const void *core_start, unsigned long core_size,
 			      const void *init_start, unsigned long init_size,
@@ -368,6 +363,10 @@
 }
 
 #ifdef CONFIG_MODULES
+static void *unw_hdr_alloc(unsigned long sz)
+{
+	return kmalloc(sz, GFP_KERNEL);
+}
 
 static struct unwind_table *last_table;
 
@@ -385,8 +384,8 @@
 		return NULL;
 
 	init_unwind_table(table, module->name,
-			  module->module_core, module->core_size,
-			  module->module_init, module->init_size,
+			  module->core_layout.base, module->core_layout.size,
+			  module->init_layout.base, module->init_layout.size,
 			  table_start, table_size,
 			  NULL, 0);
 
--- linux-4.4.0.orig/arch/arc/mm/cache.c
+++ linux-4.4.0/arch/arc/mm/cache.c
@@ -543,6 +543,7 @@
 	static DEFINE_SPINLOCK(lock);
 	unsigned long flags;
 	unsigned int ctrl;
+	phys_addr_t end;
 
 	spin_lock_irqsave(&lock, flags);
 
@@ -572,8 +573,16 @@
 	 * END needs to be setup before START (latter triggers the operation)
 	 * END can't be same as START, so add (l2_line_sz - 1) to sz
 	 */
-	write_aux_reg(ARC_REG_SLC_RGN_END, (paddr + sz + l2_line_sz - 1));
-	write_aux_reg(ARC_REG_SLC_RGN_START, paddr);
+	end = paddr + sz + l2_line_sz - 1;
+	if (is_pae40_enabled())
+		write_aux_reg(ARC_REG_SLC_RGN_END1, upper_32_bits(end));
+
+	write_aux_reg(ARC_REG_SLC_RGN_END, lower_32_bits(end));
+
+	if (is_pae40_enabled())
+		write_aux_reg(ARC_REG_SLC_RGN_START1, upper_32_bits(paddr));
+
+	write_aux_reg(ARC_REG_SLC_RGN_START, lower_32_bits(paddr));
 
 	while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
 
@@ -812,7 +821,7 @@
 void flush_cache_page(struct vm_area_struct *vma, unsigned long u_vaddr,
 		      unsigned long pfn)
 {
-	unsigned int paddr = pfn << PAGE_SHIFT;
+	phys_addr_t paddr = pfn << PAGE_SHIFT;
 
 	u_vaddr &= PAGE_MASK;
 
@@ -832,8 +841,9 @@
 		     unsigned long u_vaddr)
 {
 	/* TBD: do we really need to clear the kernel mapping */
-	__flush_dcache_page(page_address(page), u_vaddr);
-	__flush_dcache_page(page_address(page), page_address(page));
+	__flush_dcache_page((phys_addr_t)page_address(page), u_vaddr);
+	__flush_dcache_page((phys_addr_t)page_address(page),
+			    (phys_addr_t)page_address(page));
 
 }
 
@@ -914,6 +924,15 @@
 
 	printk(arc_cache_mumbojumbo(0, str, sizeof(str)));
 
+	/*
+	 * Only master CPU needs to execute rest of function:
+	 *  - Assume SMP so all cores will have same cache config so
+	 *    any geomtry checks will be same for all
+	 *  - IOC setup / dma callbacks only need to be setup once
+	 */
+	if (cpu)
+		return;
+
 	if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) {
 		struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
 
@@ -951,11 +970,16 @@
 		/* check for D-Cache aliasing on ARCompact: ARCv2 has PIPT */
 		if (is_isa_arcompact()) {
 			int handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
+			int num_colors = dc->sz_k/dc->assoc/TO_KB(PAGE_SIZE);
 
-			if (dc->alias && !handled)
-				panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
-			else if (!dc->alias && handled)
+			if (dc->alias) {
+				if (!handled)
+					panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
+				if (CACHE_COLORS_NUM != num_colors)
+					panic("CACHE_COLORS_NUM not optimized for config\n");
+			} else if (!dc->alias && handled) {
 				panic("Disable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
+			}
 		}
 	}
 
--- linux-4.4.0.orig/arch/arc/mm/mmap.c
+++ linux-4.4.0/arch/arc/mm/mmap.c
@@ -64,7 +64,7 @@
 
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
--- linux-4.4.0.orig/arch/arc/mm/tlb.c
+++ linux-4.4.0/arch/arc/mm/tlb.c
@@ -885,9 +885,6 @@
 
 	local_irq_save(flags);
 
-	/* re-enable the MMU */
-	write_aux_reg(ARC_REG_PID, MMU_ENABLE | read_aux_reg(ARC_REG_PID));
-
 	/* loop thru all sets of TLB */
 	for (set = 0; set < mmu->sets; set++) {
 
--- linux-4.4.0.orig/arch/arm/Kconfig
+++ linux-4.4.0/arch/arm/Kconfig
@@ -2,6 +2,7 @@
 	bool
 	default y
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+	select ARCH_HAS_CPU_FINALIZE_INIT if MMU
 	select ARCH_HAS_ELF_RANDOMIZE
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_HAVE_CUSTOM_GPIO_H
@@ -37,6 +38,7 @@
 	select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32
 	select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
 	select HAVE_ARCH_TRACEHOOK
+	select HAVE_ARM_SMCCC if CPU_V7
 	select HAVE_BPF_JIT
 	select HAVE_CC_STACKPROTECTOR
 	select HAVE_CONTEXT_TRACKING
@@ -675,7 +677,9 @@
 	select HAVE_S3C_RTC if RTC_CLASS
 	select MULTI_IRQ_HANDLER
 	select NEED_MACH_IO_H
+	select S3C2410_WATCHDOG
 	select SAMSUNG_ATAGS
+	select WATCHDOG
 	help
 	  Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443
 	  and S3C2450 SoCs based systems, such as the Simtec Electronics BAST
@@ -1422,8 +1426,7 @@
 
 config BL_SWITCHER
 	bool "big.LITTLE switcher support"
-	depends on BIG_LITTLE && MCPM && HOTPLUG_CPU
-	select ARM_CPU_SUSPEND
+	depends on BIG_LITTLE && MCPM && HOTPLUG_CPU && ARM_GIC
 	select CPU_PM
 	help
 	  The big.LITTLE "switcher" provides the core functionality to
@@ -1475,13 +1478,14 @@
 config HOTPLUG_CPU
 	bool "Support for hot-pluggable CPUs"
 	depends on SMP
+	select GENERIC_IRQ_MIGRATION
 	help
 	  Say Y here to experiment with turning CPUs off and on.  CPUs
 	  can be controlled through /sys/devices/system/cpu.
 
 config ARM_PSCI
 	bool "Support for the ARM Power State Coordination Interface (PSCI)"
-	depends on CPU_V7
+	depends on HAVE_ARM_SMCCC
 	select ARM_PSCI_FW
 	help
 	  Say Y here if you want Linux to communicate with system firmware
@@ -1999,7 +2003,7 @@
 config KEXEC
 	bool "Kexec system call (EXPERIMENTAL)"
 	depends on (!SMP || PM_SLEEP_SMP)
-	depends on !CPU_V7M
+	depends on MMU
 	select KEXEC_CORE
 	help
 	  kexec is a system call that implements the ability to shutdown your
@@ -2140,7 +2144,8 @@
 	def_bool y
 
 config ARM_CPU_SUSPEND
-	def_bool PM_SLEEP
+	def_bool PM_SLEEP || BL_SWITCHER
+	depends on ARCH_SUSPEND_POSSIBLE
 
 config ARCH_HIBERNATION_POSSIBLE
 	bool
@@ -2154,6 +2159,7 @@
 source "drivers/Kconfig"
 
 source "drivers/firmware/Kconfig"
+source "ubuntu/Kconfig"
 
 source "fs/Kconfig"
 
--- linux-4.4.0.orig/arch/arm/Kconfig-nommu
+++ linux-4.4.0/arch/arm/Kconfig-nommu
@@ -34,8 +34,7 @@
 	  used instead of the auto-probing which utilizes the register.
 
 config REMAP_VECTORS_TO_RAM
-	bool 'Install vectors to the beginning of RAM' if DRAM_BASE
-	depends on DRAM_BASE
+	bool 'Install vectors to the beginning of RAM'
 	help
 	  The kernel needs to change the hardware exception vectors.
 	  In nommu mode, the hardware exception vectors are normally
--- linux-4.4.0.orig/arch/arm/Kconfig.debug
+++ linux-4.4.0/arch/arm/Kconfig.debug
@@ -162,10 +162,9 @@
 		  mobile SoCs in the Kona family of chips (e.g. bcm28155,
 		  bcm11351, etc...)
 
-	config DEBUG_BCM63XX
+	config DEBUG_BCM63XX_UART
 		bool "Kernel low-level debugging on BCM63XX UART"
 		depends on ARCH_BCM_63XX
-		select DEBUG_UART_BCM63XX
 
 	config DEBUG_BERLIN_UART
 		bool "Marvell Berlin SoC Debug UART"
@@ -1261,21 +1260,21 @@
 	depends on ARCH_OMAP2PLUS
 
 config DEBUG_IMX_UART_PORT
-	int "i.MX Debug UART Port Selection" if DEBUG_IMX1_UART || \
-						DEBUG_IMX25_UART || \
-						DEBUG_IMX21_IMX27_UART || \
-						DEBUG_IMX31_UART || \
-						DEBUG_IMX35_UART || \
-						DEBUG_IMX50_UART || \
-						DEBUG_IMX51_UART || \
-						DEBUG_IMX53_UART || \
-						DEBUG_IMX6Q_UART || \
-						DEBUG_IMX6SL_UART || \
-						DEBUG_IMX6SX_UART || \
-						DEBUG_IMX6UL_UART || \
-						DEBUG_IMX7D_UART
+	int "i.MX Debug UART Port Selection"
+	depends on DEBUG_IMX1_UART || \
+		   DEBUG_IMX25_UART || \
+		   DEBUG_IMX21_IMX27_UART || \
+		   DEBUG_IMX31_UART || \
+		   DEBUG_IMX35_UART || \
+		   DEBUG_IMX50_UART || \
+		   DEBUG_IMX51_UART || \
+		   DEBUG_IMX53_UART || \
+		   DEBUG_IMX6Q_UART || \
+		   DEBUG_IMX6SL_UART || \
+		   DEBUG_IMX6SX_UART || \
+		   DEBUG_IMX6UL_UART || \
+		   DEBUG_IMX7D_UART
 	default 1
-	depends on ARCH_MXC
 	help
 	  Choose UART port on which kernel low-level debug messages
 	  should be output.
@@ -1348,7 +1347,7 @@
 	default "debug/vf.S" if DEBUG_VF_UART
 	default "debug/vt8500.S" if DEBUG_VT8500_UART0
 	default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
-	default "debug/bcm63xx.S" if DEBUG_UART_BCM63XX
+	default "debug/bcm63xx.S" if DEBUG_BCM63XX_UART
 	default "debug/digicolor.S" if DEBUG_DIGICOLOR_UA0
 	default "mach/debug-macro.S"
 
@@ -1364,10 +1363,6 @@
 		ARCH_IOP33X || ARCH_IXP4XX || \
 		ARCH_LPC32XX || ARCH_MV78XX0 || ARCH_ORION5X || ARCH_RPC
 
-# Compatibility options for BCM63xx
-config DEBUG_UART_BCM63XX
-	def_bool ARCH_BCM_63XX
-
 config DEBUG_UART_PHYS
 	hex "Physical base address of debug UART"
 	default 0x00100a00 if DEBUG_NETX_UART
@@ -1462,7 +1457,7 @@
 	default 0xfffb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1
 	default 0xfffb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2
 	default 0xfffb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3
-	default 0xfffe8600 if DEBUG_UART_BCM63XX
+	default 0xfffe8600 if DEBUG_BCM63XX_UART
 	default 0xfffff700 if ARCH_IOP33X
 	depends on ARCH_EP93XX || \
 	        DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
@@ -1474,7 +1469,7 @@
 		DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \
 		DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \
 		DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \
-		DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
+		DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \
 		DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \
 		DEBUG_AT91_UART
 
@@ -1515,7 +1510,7 @@
 	default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT
 	default 0xfc40ab00 if DEBUG_BRCMSTB_UART
 	default 0xfc705000 if DEBUG_ZTE_ZX
-	default 0xfcfe8600 if DEBUG_UART_BCM63XX
+	default 0xfcfe8600 if DEBUG_BCM63XX_UART
 	default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
 	default 0xfd000000 if ARCH_SPEAR13XX
 	default 0xfd012000 if ARCH_MV78XX0
@@ -1566,7 +1561,7 @@
 		DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
 		DEBUG_NETX_UART || \
 		DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
-		DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
+		DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \
 		DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0
 
 config DEBUG_UART_8250_SHIFT
--- linux-4.4.0.orig/arch/arm/boot/compressed/Makefile
+++ linux-4.4.0/arch/arm/boot/compressed/Makefile
@@ -3,6 +3,7 @@
 #
 # create a compressed vmlinuz image from the original vmlinux
 #
+KBUILD_CFLAGS := $(filter-out -fstack-protector, $(KBUILD_CFLAGS)) -fno-stack-protector
 
 OBJS		=
 
--- linux-4.4.0.orig/arch/arm/boot/compressed/head.S
+++ linux-4.4.0/arch/arm/boot/compressed/head.S
@@ -776,7 +776,7 @@
 		orrne	r0, r0, #1		@ MMU enabled
 		movne	r1, #0xfffffffd		@ domain 0 = client
 		bic     r6, r6, #1 << 31        @ 32-bit translation system
-		bic     r6, r6, #3 << 0         @ use only ttbr0
+		bic     r6, r6, #(7 << 0) | (1 << 4)	@ use only ttbr0
 		mcrne	p15, 0, r3, c2, c0, 0	@ load page table pointer
 		mcrne	p15, 0, r1, c3, c0, 0	@ load domain access control
 		mcrne   p15, 0, r6, c2, c0, 2   @ load ttb control
@@ -1074,9 +1074,9 @@
 __armv7_mmu_cache_off:
 		mrc	p15, 0, r0, c1, c0
 #ifdef CONFIG_MMU
-		bic	r0, r0, #0x000d
+		bic	r0, r0, #0x0005
 #else
-		bic	r0, r0, #0x000c
+		bic	r0, r0, #0x0004
 #endif
 		mcr	p15, 0, r0, c1, c0	@ turn MMU and cache off
 		mov	r12, lr
--- linux-4.4.0.orig/arch/arm/boot/compressed/libfdt_env.h
+++ linux-4.4.0/arch/arm/boot/compressed/libfdt_env.h
@@ -1,10 +1,14 @@
 #ifndef _ARM_LIBFDT_ENV_H
 #define _ARM_LIBFDT_ENV_H
 
+#include <linux/limits.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <asm/byteorder.h>
 
+#define INT32_MAX	S32_MAX
+#define UINT32_MAX	U32_MAX
+
 typedef __be16 fdt16_t;
 typedef __be32 fdt32_t;
 typedef __be64 fdt64_t;
--- linux-4.4.0.orig/arch/arm/boot/dts/Makefile
+++ linux-4.4.0/arch/arm/boot/dts/Makefile
@@ -166,6 +166,7 @@
 	kirkwood-ds109.dtb \
 	kirkwood-ds110jv10.dtb \
 	kirkwood-ds111.dtb \
+	kirkwood-ds112.dtb \
 	kirkwood-ds209.dtb \
 	kirkwood-ds210.dtb \
 	kirkwood-ds212.dtb \
--- linux-4.4.0.orig/arch/arm/boot/dts/am335x-evm.dts
+++ linux-4.4.0/arch/arm/boot/dts/am335x-evm.dts
@@ -697,6 +697,7 @@
 	pinctrl-0 = <&cpsw_default>;
 	pinctrl-1 = <&cpsw_sleep>;
 	status = "okay";
+	slaves = <1>;
 };
 
 &davinci_mdio {
@@ -704,15 +705,14 @@
 	pinctrl-0 = <&davinci_mdio_default>;
 	pinctrl-1 = <&davinci_mdio_sleep>;
 	status = "okay";
-};
 
-&cpsw_emac0 {
-	phy_id = <&davinci_mdio>, <0>;
-	phy-mode = "rgmii-txid";
+	ethphy0: ethernet-phy@0 {
+		reg = <0>;
+	};
 };
 
-&cpsw_emac1 {
-	phy_id = <&davinci_mdio>, <1>;
+&cpsw_emac0 {
+	phy-handle = <&ethphy0>;
 	phy-mode = "rgmii-txid";
 };
 
--- linux-4.4.0.orig/arch/arm/boot/dts/am335x-evmsk.dts
+++ linux-4.4.0/arch/arm/boot/dts/am335x-evmsk.dts
@@ -668,6 +668,7 @@
 	ti,non-removable;
 	bus-width = <4>;
 	cap-power-off-card;
+	keep-power-in-suspend;
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc2_pins>;
 
--- linux-4.4.0.orig/arch/arm/boot/dts/am33xx.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/am33xx.dtsi
@@ -142,10 +142,11 @@
 				};
 
 				scm_conf: scm_conf@0 {
-					compatible = "syscon";
+					compatible = "syscon", "simple-bus";
 					reg = <0x0 0x800>;
 					#address-cells = <1>;
 					#size-cells = <1>;
+					ranges = <0 0 0x800>;
 
 					scm_clocks: clocks {
 						#address-cells = <1>;
--- linux-4.4.0.orig/arch/arm/boot/dts/am3517.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/am3517.dtsi
@@ -74,6 +74,11 @@
 	};
 };
 
+/* Table Table 5-79 of the TRM shows 480ab000 is reserved */
+&usb_otg_hs {
+	status = "disabled";
+};
+
 &iva {
 	status = "disabled";
 };
--- linux-4.4.0.orig/arch/arm/boot/dts/am4372.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/am4372.dtsi
@@ -807,7 +807,8 @@
 			reg = <0x48038000 0x2000>,
 			      <0x46000000 0x400000>;
 			reg-names = "mpu", "dat";
-			interrupts = <80>, <81>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "tx", "rx";
 			status = "disabled";
 			dmas = <&edma 8>,
@@ -821,7 +822,8 @@
 			reg = <0x4803C000 0x2000>,
 			      <0x46400000 0x400000>;
 			reg-names = "mpu", "dat";
-			interrupts = <82>, <83>;
+			interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "tx", "rx";
 			status = "disabled";
 			dmas = <&edma 10>,
@@ -1000,6 +1002,8 @@
 				ti,hwmods = "dss_dispc";
 				clocks = <&disp_clk>;
 				clock-names = "fck";
+
+				max-memory-bandwidth = <230000000>;
 			};
 
 			rfbi: rfbi@4832a800 {
--- linux-4.4.0.orig/arch/arm/boot/dts/am437x-gp-evm.dts
+++ linux-4.4.0/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -79,7 +79,7 @@
 		};
 
 	lcd0: display {
-		compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
+		compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
 		label = "lcd";
 
 		panel-timing {
--- linux-4.4.0.orig/arch/arm/boot/dts/am437x-sk-evm.dts
+++ linux-4.4.0/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -508,6 +508,8 @@
 
 		touchscreen-size-x = <480>;
 		touchscreen-size-y = <272>;
+
+		wakeup-source;
 	};
 
 	tlv320aic3106: tlv320aic3106@1b {
--- linux-4.4.0.orig/arch/arm/boot/dts/am43x-epos-evm.dts
+++ linux-4.4.0/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -41,7 +41,7 @@
 	};
 
 	lcd0: display {
-		compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
+		compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
 		label = "lcd";
 
 		panel-timing {
@@ -792,3 +792,8 @@
 	tx-num-evt = <32>;
 	rx-num-evt = <32>;
 };
+
+&synctimer_32kclk {
+	assigned-clocks = <&mux_synctimer32k_ck>;
+	assigned-clock-parents = <&clkdiv32k_ick>;
+};
--- linux-4.4.0.orig/arch/arm/boot/dts/am57xx-beagle-x15.dts
+++ linux-4.4.0/arch/arm/boot/dts/am57xx-beagle-x15.dts
@@ -411,6 +411,7 @@
 		interrupt-controller;
 
 		ti,system-power-controller;
+		ti,palmas-override-powerhold;
 
 		tps659038_pmic {
 			compatible = "ti,tps659038-pmic";
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-375.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/armada-375.dtsi
@@ -176,9 +176,9 @@
 				reg = <0x8000 0x1000>;
 				cache-unified;
 				cache-level = <2>;
-				arm,double-linefill-incr = <1>;
+				arm,double-linefill-incr = <0>;
 				arm,double-linefill-wrap = <0>;
-				arm,double-linefill = <1>;
+				arm,double-linefill = <0>;
 				prefetch-data = <1>;
 			};
 
@@ -529,7 +529,7 @@
 			};
 
 			sata@a0000 {
-				compatible = "marvell,orion-sata";
+				compatible = "marvell,armada-370-sata";
 				reg = <0xa0000 0x5000>;
 				interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&gateclk 14>, <&gateclk 20>;
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-385-linksys.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -58,8 +58,8 @@
 	soc {
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
-			  MBUS_ID(0x09, 0x09) 0 0xf1100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0xf1110000 0x10000>;
+			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
 
 		internal-regs {
 
@@ -117,7 +117,7 @@
 			};
 
 			/* USB part of the eSATA/USB 2.0 port */
-			usb@50000 {
+			usb@58000 {
 				status = "okay";
 			};
 
@@ -245,7 +245,7 @@
 		button@2 {
 			label = "Factory Reset Button";
 			linux,code = <KEY_RESTART>;
-			gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
 		};
 	};
 
@@ -260,7 +260,7 @@
 		};
 
 		sata {
-			gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+			gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
 			default-state = "off";
 		};
 	};
@@ -313,7 +313,7 @@
 
 &pinctrl {
 	keys_pin: keys-pin {
-		marvell,pins = "mpp24", "mpp47";
+		marvell,pins = "mpp24", "mpp29";
 		marvell,function = "gpio";
 	};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-388-gp.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-388-gp.dts
@@ -89,7 +89,7 @@
 					pinctrl-names = "default";
 					pinctrl-0 = <&pca0_pins>;
 					interrupt-parent = <&gpio0>;
-					interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+					interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
 					gpio-controller;
 					#gpio-cells = <2>;
 					interrupt-controller;
@@ -101,7 +101,7 @@
 					compatible = "nxp,pca9555";
 					pinctrl-names = "default";
 					interrupt-parent = <&gpio0>;
-					interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+					interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
 					gpio-controller;
 					#gpio-cells = <2>;
 					interrupt-controller;
@@ -294,16 +294,6 @@
 	};
 
 	reg_usb2_1_vbus: v5-vbus1 {
-		compatible = "regulator-fixed";
-		regulator-name = "v5.0-vbus1";
-		regulator-min-microvolt = <5000000>;
-		regulator-max-microvolt = <5000000>;
-		enable-active-high;
-		regulator-always-on;
-		gpio = <&expander0 4 GPIO_ACTIVE_HIGH>;
-	};
-
-	reg_usb2_1_vbus: v5-vbus1 {
 		compatible = "regulator-fixed";
 		regulator-name = "v5.0-vbus1";
 		regulator-min-microvolt = <5000000>;
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-38x.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/armada-38x.dtsi
@@ -143,9 +143,9 @@
 				reg = <0x8000 0x1000>;
 				cache-unified;
 				cache-level = <2>;
-				arm,double-linefill-incr = <1>;
+				arm,double-linefill-incr = <0>;
 				arm,double-linefill-wrap = <0>;
-				arm,double-linefill = <1>;
+				arm,double-linefill = <0>;
 				prefetch-data = <1>;
 			};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-390.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/armada-390.dtsi
@@ -47,6 +47,8 @@
 #include "armada-39x.dtsi"
 
 / {
+	compatible = "marvell,armada390";
+
 	soc {
 		internal-regs {
 			pinctrl@18000 {
@@ -54,4 +56,5 @@
 				reg = <0x18000 0x20>;
 			};
 		};
+	};
 };
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-39x.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/armada-39x.dtsi
@@ -104,9 +104,9 @@
 				reg = <0x8000 0x1000>;
 				cache-unified;
 				cache-level = <2>;
-				arm,double-linefill-incr = <1>;
+				arm,double-linefill-incr = <0>;
 				arm,double-linefill-wrap = <0>;
-				arm,double-linefill = <1>;
+				arm,double-linefill = <0>;
 				prefetch-data = <1>;
 			};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-axpwifiap.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-axpwifiap.dts
@@ -70,8 +70,8 @@
 	soc {
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
-			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		pcie-controller {
 			status = "okay";
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-db.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-db.dts
@@ -76,8 +76,8 @@
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
 			  MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
-			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		devbus-bootcs {
 			status = "okay";
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-gp.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-gp.dts
@@ -95,8 +95,8 @@
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
 			  MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
-			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		devbus-bootcs {
 			status = "okay";
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
@@ -65,8 +65,8 @@
 	soc {
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000
 			MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
-			MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		pcie-controller {
 			status = "okay";
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
@@ -70,8 +70,8 @@
 	soc {
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
-			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		pcie-controller {
 			status = "okay";
@@ -304,13 +304,13 @@
 		button@1 {
 			label = "WPS";
 			linux,code = <KEY_WPS_BUTTON>;
-			gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+			gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
 		};
 
 		button@2 {
 			label = "Factory Reset Button";
 			linux,code = <KEY_RESTART>;
-			gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+			gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
 		};
 	};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-matrix.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-matrix.dts
@@ -68,8 +68,8 @@
 	soc {
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
-			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		internal-regs {
 			serial@12000 {
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
@@ -64,8 +64,8 @@
 	soc {
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
-			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		pcie-controller {
 			status = "okay";
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
@@ -65,9 +65,9 @@
 	soc {
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
-			  MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x8000000
-			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x01, 0x2f) 0 0 0xe8000000 0x8000000
+			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		devbus-bootcs {
 			status = "okay";
--- linux-4.4.0.orig/arch/arm/boot/dts/armada-xp-synology-ds414.dts
+++ linux-4.4.0/arch/arm/boot/dts/armada-xp-synology-ds414.dts
@@ -78,8 +78,8 @@
 	soc {
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
-			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 
 		pcie-controller {
 			status = "okay";
--- linux-4.4.0.orig/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+++ linux-4.4.0/arch/arm/boot/dts/at91-sama5d2_xplained.dts
@@ -122,6 +122,8 @@
 			uart1: serial@f8020000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_uart1_default>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
 				status = "okay";
 			};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/at91-sama5d3_xplained.dts
+++ linux-4.4.0/arch/arm/boot/dts/at91-sama5d3_xplained.dts
@@ -162,9 +162,10 @@
 			};
 
 			adc0: adc@f8018000 {
+				atmel,adc-vref = <3300>;
+				atmel,adc-channels-used = <0xfe>;
 				pinctrl-0 = <
 					&pinctrl_adc0_adtrg
-					&pinctrl_adc0_ad0
 					&pinctrl_adc0_ad1
 					&pinctrl_adc0_ad2
 					&pinctrl_adc0_ad3
@@ -172,8 +173,6 @@
 					&pinctrl_adc0_ad5
 					&pinctrl_adc0_ad6
 					&pinctrl_adc0_ad7
-					&pinctrl_adc0_ad8
-					&pinctrl_adc0_ad9
 					>;
 				status = "okay";
 			};
@@ -232,6 +231,11 @@
 						atmel,pins =
 							<AT91_PIOE 9 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;	/* PE9, conflicts with A9 */
 					};
+					pinctrl_usb_default: usb_default {
+						atmel,pins =
+							<AT91_PIOE 3 AT91_PERIPH_GPIO AT91_PINCTRL_NONE
+							 AT91_PIOE 4 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+					};
 				};
 			};
 		};
@@ -289,6 +293,8 @@
 					   &pioE 3 GPIO_ACTIVE_LOW
 					   &pioE 4 GPIO_ACTIVE_LOW
 					  >;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb_default>;
 			status = "okay";
 		};
 
@@ -303,6 +309,7 @@
 		regulator-name = "mmc0-card-supply";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
 	};
 
 	gpio_keys {
--- linux-4.4.0.orig/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+++ linux-4.4.0/arch/arm/boot/dts/at91-sama5d4_xplained.dts
@@ -86,10 +86,12 @@
 			macb0: ethernet@f8020000 {
 				phy-mode = "rmii";
 				status = "okay";
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_macb0_rmii &pinctrl_macb0_phy_irq>;
 
 				phy0: ethernet-phy@1 {
 					interrupt-parent = <&pioE>;
-					interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+					interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
 					reg = <1>;
 				};
 			};
@@ -108,6 +110,8 @@
 			};
 
 			usart3: serial@fc00c000 {
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
 				status = "okay";
 			};
 
@@ -148,10 +152,19 @@
 						atmel,pins =
 							<AT91_PIOE 31 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;
 					};
+					pinctrl_usb_default: usb_default {
+						atmel,pins =
+							<AT91_PIOE 11 AT91_PERIPH_GPIO AT91_PINCTRL_NONE
+							 AT91_PIOE 14 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+					};
 					pinctrl_key_gpio: key_gpio_0 {
 						atmel,pins =
 							<AT91_PIOE 8 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
 					};
+					pinctrl_macb0_phy_irq: macb0_phy_irq_0 {
+						atmel,pins =
+							<AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+					};
 				};
 			};
 		};
@@ -169,6 +182,8 @@
 					   &pioE 11 GPIO_ACTIVE_HIGH
 					   &pioE 14 GPIO_ACTIVE_HIGH
 					  >;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb_default>;
 			status = "okay";
 		};
 
@@ -262,5 +277,6 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 		vin-supply = <&vcc_3v3_reg>;
+		regulator-always-on;
 	};
 };
--- linux-4.4.0.orig/arch/arm/boot/dts/at91-sama5d4ek.dts
+++ linux-4.4.0/arch/arm/boot/dts/at91-sama5d4ek.dts
@@ -160,8 +160,15 @@
 			};
 
 			macb0: ethernet@f8020000 {
+				pinctrl-0 = <&pinctrl_macb0_rmii &pinctrl_macb0_phy_irq>;
 				phy-mode = "rmii";
 				status = "okay";
+
+				ethernet-phy@1 {
+					reg = <0x1>;
+					interrupt-parent = <&pioE>;
+					interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+				};
 			};
 
 			mmc1: mmc@fc000000 {
@@ -193,6 +200,10 @@
 
 			pinctrl@fc06a000 {
 				board {
+					pinctrl_macb0_phy_irq: macb0_phy_irq {
+						atmel,pins =
+							<AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+					};
 					pinctrl_mmc0_cd: mmc0_cd {
 						atmel,pins =
 							<AT91_PIOE 5 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
--- linux-4.4.0.orig/arch/arm/boot/dts/at91sam9g25.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/at91sam9g25.dtsi
@@ -21,7 +21,7 @@
 				atmel,mux-mask = <
 				      /*    A         B          C     */
 				       0xffffffff 0xffe0399f 0xc000001c  /* pioA */
-				       0x0007ffff 0x8000fe3f 0x00000000  /* pioB */
+				       0x0007ffff 0x00047e3f 0x00000000  /* pioB */
 				       0x80000000 0x07c0ffff 0xb83fffff  /* pioC */
 				       0x003fffff 0x003f8000 0x00000000  /* pioD */
 				      >;
--- linux-4.4.0.orig/arch/arm/boot/dts/at91sam9g45.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -546,7 +546,7 @@
 					};
 				};
 
-				uart1 {
+				usart1 {
 					pinctrl_usart1: usart1-0 {
 						atmel,pins =
 							<AT91_PIOB 4 AT91_PERIPH_A AT91_PINCTRL_PULL_UP	/* PB4 periph A with pullup */
--- linux-4.4.0.orig/arch/arm/boot/dts/at91sam9x5.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -106,7 +106,7 @@
 
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91sam9x5-pmc", "syscon";
-				reg = <0xfffffc00 0x100>;
+				reg = <0xfffffc00 0x200>;
 				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
 				interrupt-controller;
 				#address-cells = <1>;
--- linux-4.4.0.orig/arch/arm/boot/dts/bcm-cygnus.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -110,7 +110,7 @@
 			reg = <0x18008000 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
+			interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
 			clock-frequency = <100000>;
 			status = "disabled";
 		};
@@ -138,7 +138,7 @@
 			reg = <0x1800b000 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
+			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
 			clock-frequency = <100000>;
 			status = "disabled";
 		};
--- linux-4.4.0.orig/arch/arm/boot/dts/bcm5301x.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/bcm5301x.dtsi
@@ -54,14 +54,14 @@
 		timer@0200 {
 			compatible = "arm,cortex-a9-global-timer";
 			reg = <0x0200 0x100>;
-			interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_PPI 11 IRQ_TYPE_EDGE_RISING>;
 			clocks = <&clk_periph>;
 		};
 
 		local-timer@0600 {
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0x0600 0x100>;
-			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_PPI 13 IRQ_TYPE_EDGE_RISING>;
 			clocks = <&clk_periph>;
 		};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/da850-evm.dts
+++ linux-4.4.0/arch/arm/boot/dts/da850-evm.dts
@@ -85,6 +85,7 @@
 				#size-cells = <1>;
 				compatible = "m25p64";
 				spi-max-frequency = <30000000>;
+				m25p,fast-read;
 				reg = <0>;
 				partition@0 {
 					label = "U-Boot-SPL";
@@ -146,7 +147,7 @@
 
 	sound {
 		compatible = "simple-audio-card";
-		simple-audio-card,name = "DA850/OMAP-L138 EVM";
+		simple-audio-card,name = "DA850-OMAPL138 EVM";
 		simple-audio-card,widgets =
 			"Line", "Line In",
 			"Line", "Line Out";
--- linux-4.4.0.orig/arch/arm/boot/dts/da850.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/da850.dtsi
@@ -267,11 +267,7 @@
 			compatible = "ti,dm6441-gpio";
 			gpio-controller;
 			reg = <0x226000 0x1000>;
-			interrupts = <42 IRQ_TYPE_EDGE_BOTH
-				43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH
-				45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH
-				47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH
-				49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>;
+			interrupts = <42 43 44 45 46 47 48 49 50>;
 			ti,ngpio = <144>;
 			ti,davinci-gpio-unbanked = <0>;
 			status = "disabled";
--- linux-4.4.0.orig/arch/arm/boot/dts/dm814x.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/dm814x.dtsi
@@ -138,7 +138,7 @@
 			};
 
 			uart1: uart@20000 {
-				compatible = "ti,omap3-uart";
+				compatible = "ti,am3352-uart", "ti,omap3-uart";
 				ti,hwmods = "uart1";
 				reg = <0x20000 0x2000>;
 				clock-frequency = <48000000>;
@@ -148,7 +148,7 @@
 			};
 
 			uart2: uart@22000 {
-				compatible = "ti,omap3-uart";
+				compatible = "ti,am3352-uart", "ti,omap3-uart";
 				ti,hwmods = "uart2";
 				reg = <0x22000 0x2000>;
 				clock-frequency = <48000000>;
@@ -158,7 +158,7 @@
 			};
 
 			uart3: uart@24000 {
-				compatible = "ti,omap3-uart";
+				compatible = "ti,am3352-uart", "ti,omap3-uart";
 				ti,hwmods = "uart3";
 				reg = <0x24000 0x2000>;
 				clock-frequency = <48000000>;
@@ -189,10 +189,11 @@
 				ranges = <0 0x160000 0x16d000>;
 
 				scm_conf: scm_conf@0 {
-					compatible = "syscon";
+					compatible = "syscon", "simple-bus";
 					reg = <0x0 0x800>;
 					#address-cells = <1>;
 					#size-cells = <1>;
+					ranges = <0 0 0x800>;
 
 					scm_clocks: clocks {
 						#address-cells = <1>;
--- linux-4.4.0.orig/arch/arm/boot/dts/dm816x.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/dm816x.dtsi
@@ -347,7 +347,7 @@
 		};
 
 		uart1: uart@48020000 {
-			compatible = "ti,omap3-uart";
+			compatible = "ti,am3352-uart", "ti,omap3-uart";
 			ti,hwmods = "uart1";
 			reg = <0x48020000 0x2000>;
 			clock-frequency = <48000000>;
@@ -357,7 +357,7 @@
 		};
 
 		uart2: uart@48022000 {
-			compatible = "ti,omap3-uart";
+			compatible = "ti,am3352-uart", "ti,omap3-uart";
 			ti,hwmods = "uart2";
 			reg = <0x48022000 0x2000>;
 			clock-frequency = <48000000>;
@@ -367,7 +367,7 @@
 		};
 
 		uart3: uart@48024000 {
-			compatible = "ti,omap3-uart";
+			compatible = "ti,am3352-uart", "ti,omap3-uart";
 			ti,hwmods = "uart3";
 			reg = <0x48024000 0x2000>;
 			clock-frequency = <48000000>;
--- linux-4.4.0.orig/arch/arm/boot/dts/dra7-evm.dts
+++ linux-4.4.0/arch/arm/boot/dts/dra7-evm.dts
@@ -410,6 +410,8 @@
 	tps659038: tps659038@58 {
 		compatible = "ti,tps659038";
 		reg = <0x58>;
+		ti,palmas-override-powerhold;
+		ti,system-power-controller;
 
 		tps659038_pmic {
 			compatible = "ti,tps659038-pmic";
--- linux-4.4.0.orig/arch/arm/boot/dts/dra7.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/dra7.dtsi
@@ -227,6 +227,8 @@
 				device_type = "pci";
 				ranges = <0x81000000 0 0          0x03000 0 0x00010000
 					  0x82000000 0 0x20013000 0x13000 0 0xffed000>;
+				dma-ranges = <0x02000000 0x0 0x00000000 0x00000000 0x1 0x00000000>;
+				bus-range = <0x00 0xff>;
 				#interrupt-cells = <1>;
 				num-lanes = <1>;
 				ti,hwmods = "pcie1";
@@ -262,6 +264,8 @@
 				device_type = "pci";
 				ranges = <0x81000000 0 0          0x03000 0 0x00010000
 					  0x82000000 0 0x30013000 0x13000 0 0xffed000>;
+				dma-ranges = <0x02000000 0x0 0x00000000 0x00000000 0x1 0x00000000>;
+				bus-range = <0x00 0xff>;
 				#interrupt-cells = <1>;
 				num-lanes = <1>;
 				ti,hwmods = "pcie2";
@@ -1497,6 +1501,16 @@
 			       0x48485200 0x2E00>;
 			#address-cells = <1>;
 			#size-cells = <1>;
+
+			/*
+			 * Do not allow gating of cpsw clock as workaround
+			 * for errata i877. Keeping internal clock disabled
+			 * causes the device switching characteristics
+			 * to degrade over time and eventually fail to meet
+			 * the data manual delay time/skew specs.
+			 */
+			ti,no-idle;
+
 			/*
 			 * rx_thresh_pend
 			 * rx_pend
@@ -1537,7 +1551,7 @@
 			};
 		};
 
-		dcan1: can@481cc000 {
+		dcan1: can@4ae3c000 {
 			compatible = "ti,dra7-d_can";
 			ti,hwmods = "dcan1";
 			reg = <0x4ae3c000 0x2000>;
@@ -1547,7 +1561,7 @@
 			status = "disabled";
 		};
 
-		dcan2: can@481d0000 {
+		dcan2: can@48480000 {
 			compatible = "ti,dra7-d_can";
 			ti,hwmods = "dcan2";
 			reg = <0x48480000 0x2000>;
--- linux-4.4.0.orig/arch/arm/boot/dts/exynos3250.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/exynos3250.dtsi
@@ -150,6 +150,9 @@
 			interrupt-controller;
 			#interrupt-cells = <3>;
 			interrupt-parent = <&gic>;
+			clock-names = "clkout8";
+			clocks = <&cmu CLK_FIN_PLL>;
+			#clock-cells = <1>;
 		};
 
 		mipi_phy: video-phy@10020710 {
@@ -322,7 +325,7 @@
 		};
 
 		hsotg: hsotg@12480000 {
-			compatible = "snps,dwc2";
+			compatible = "samsung,s3c6400-hsotg", "snps,dwc2";
 			reg = <0x12480000 0x20000>;
 			interrupts = <0 141 0>;
 			clocks = <&cmu CLK_USBOTG>;
--- linux-4.4.0.orig/arch/arm/boot/dts/exynos4210-trats.dts
+++ linux-4.4.0/arch/arm/boot/dts/exynos4210-trats.dts
@@ -298,6 +298,8 @@
 		compatible = "maxim,max8997-pmic";
 
 		reg = <0x66>;
+		interrupt-parent = <&gpx0>;
+		interrupts = <7 0>;
 
 		max8997,pmic-buck1-uses-gpio-dvs;
 		max8997,pmic-buck2-uses-gpio-dvs;
--- linux-4.4.0.orig/arch/arm/boot/dts/exynos4412-trats2.dts
+++ linux-4.4.0/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -359,7 +359,7 @@
 		reg = <0>;
 		vdd3-supply = <&lcd_vdd3_reg>;
 		vci-supply = <&ldo25_reg>;
-		reset-gpios = <&gpy4 5 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&gpf2 1 GPIO_ACTIVE_HIGH>;
 		power-on-delay= <50>;
 		reset-delay = <100>;
 		init-delay = <100>;
--- linux-4.4.0.orig/arch/arm/boot/dts/exynos5250-snow-rev5.dts
+++ linux-4.4.0/arch/arm/boot/dts/exynos5250-snow-rev5.dts
@@ -23,6 +23,14 @@
 
 		samsung,model = "Snow-I2S-MAX98090";
 		samsung,audio-codec = <&max98090>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98090 0>, <&hdmi>;
+		};
 	};
 };
 
@@ -34,6 +42,9 @@
 		interrupt-parent = <&gpx0>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&max98090_irq>;
+		clocks = <&pmu_system_controller 0>;
+		clock-names = "mclk";
+		#sound-dai-cells = <1>;
 	};
 };
 
--- linux-4.4.0.orig/arch/arm/boot/dts/exynos5250-spring.dts
+++ linux-4.4.0/arch/arm/boot/dts/exynos5250-spring.dts
@@ -112,7 +112,7 @@
 		compatible = "samsung,s5m8767-pmic";
 		reg = <0x66>;
 		interrupt-parent = <&gpx3>;
-		interrupts = <2 IRQ_TYPE_NONE>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&s5m8767_irq &s5m8767_dvs &s5m8767_ds>;
 		wakeup-source;
--- linux-4.4.0.orig/arch/arm/boot/dts/exynos5420-arndale-octa.dts
+++ linux-4.4.0/arch/arm/boot/dts/exynos5420-arndale-octa.dts
@@ -75,7 +75,7 @@
 		s2mps11,buck4-ramp-enable = <1>;
 
 		interrupt-parent = <&gpx3>;
-		interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&s2mps11_irq>;
 
@@ -97,6 +97,7 @@
 				regulator-name = "PVDD_APIO_1V8";
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
 			};
 
 			ldo3_reg: LDO3 {
@@ -135,6 +136,7 @@
 				regulator-name = "PVDD_ABB_1V8";
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
 			};
 
 			ldo9_reg: LDO9 {
--- linux-4.4.0.orig/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi
@@ -0,0 +1,25 @@
+/*
+ * Device tree sources for Exynos5420 TMU sensor configuration
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ * Copyright (c) 2017 Krzysztof Kozlowski <krzk@kernel.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 <dt-bindings/thermal/thermal_exynos.h>
+
+#thermal-sensor-cells = <0>;
+samsung,tmu_gain = <8>;
+samsung,tmu_reference_voltage = <16>;
+samsung,tmu_noise_cancel_mode = <4>;
+samsung,tmu_efuse_value = <55>;
+samsung,tmu_min_efuse_value = <0>;
+samsung,tmu_max_efuse_value = <100>;
+samsung,tmu_first_point_trim = <25>;
+samsung,tmu_second_point_trim = <85>;
+samsung,tmu_default_temp_offset = <50>;
+samsung,tmu_cal_type = <TYPE_ONE_POINT_TRIMMING>;
--- linux-4.4.0.orig/arch/arm/boot/dts/exynos5420.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/exynos5420.dtsi
@@ -777,7 +777,7 @@
 		interrupts = <0 65 0>;
 		clocks = <&clock CLK_TMU>;
 		clock-names = "tmu_apbif";
-		#include "exynos4412-tmu-sensor-conf.dtsi"
+		#include "exynos5420-tmu-sensor-conf.dtsi"
 	};
 
 	tmu_cpu1: tmu@10064000 {
@@ -786,7 +786,7 @@
 		interrupts = <0 183 0>;
 		clocks = <&clock CLK_TMU>;
 		clock-names = "tmu_apbif";
-		#include "exynos4412-tmu-sensor-conf.dtsi"
+		#include "exynos5420-tmu-sensor-conf.dtsi"
 	};
 
 	tmu_cpu2: tmu@10068000 {
@@ -795,7 +795,7 @@
 		interrupts = <0 184 0>;
 		clocks = <&clock CLK_TMU>, <&clock CLK_TMU>;
 		clock-names = "tmu_apbif", "tmu_triminfo_apbif";
-		#include "exynos4412-tmu-sensor-conf.dtsi"
+		#include "exynos5420-tmu-sensor-conf.dtsi"
 	};
 
 	tmu_cpu3: tmu@1006c000 {
@@ -804,7 +804,7 @@
 		interrupts = <0 185 0>;
 		clocks = <&clock CLK_TMU>, <&clock CLK_TMU_GPU>;
 		clock-names = "tmu_apbif", "tmu_triminfo_apbif";
-		#include "exynos4412-tmu-sensor-conf.dtsi"
+		#include "exynos5420-tmu-sensor-conf.dtsi"
 	};
 
 	tmu_gpu: tmu@100a0000 {
@@ -813,7 +813,7 @@
 		interrupts = <0 215 0>;
 		clocks = <&clock CLK_TMU_GPU>, <&clock CLK_TMU>;
 		clock-names = "tmu_apbif", "tmu_triminfo_apbif";
-		#include "exynos4412-tmu-sensor-conf.dtsi"
+		#include "exynos5420-tmu-sensor-conf.dtsi"
 	};
 
 	thermal-zones {
--- linux-4.4.0.orig/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts
+++ linux-4.4.0/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts
@@ -81,8 +81,8 @@
 	imx27-phycard-s-rdk {
 		pinctrl_i2c1: i2c1grp {
 			fsl,pins = <
-				MX27_PAD_I2C2_SDA__I2C2_SDA 0x0
-				MX27_PAD_I2C2_SCL__I2C2_SCL 0x0
+				MX27_PAD_I2C_DATA__I2C_DATA 0x0
+				MX27_PAD_I2C_CLK__I2C_CLK 0x0
 			>;
 		};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/imx31.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx31.dtsi
@@ -30,11 +30,11 @@
 		};
 	};
 
-	avic: avic-interrupt-controller@60000000 {
+	avic: interrupt-controller@68000000 {
 		compatible = "fsl,imx31-avic", "fsl,avic";
 		interrupt-controller;
 		#interrupt-cells = <1>;
-		reg = <0x60000000 0x100000>;
+		reg = <0x68000000 0x100000>;
 	};
 
 	soc {
@@ -110,13 +110,6 @@
 				interrupts = <19>;
 				clocks = <&clks 25>;
 			};
-
-			clks: ccm@53f80000{
-				compatible = "fsl,imx31-ccm";
-				reg = <0x53f80000 0x4000>;
-				interrupts = <0 31 0x04 0 53 0x04>;
-				#clock-cells = <1>;
-			};
 		};
 
 		aips@53f00000 { /* AIPS2 */
@@ -126,6 +119,13 @@
 			reg = <0x53f00000 0x100000>;
 			ranges;
 
+			clks: ccm@53f80000{
+				compatible = "fsl,imx31-ccm";
+				reg = <0x53f80000 0x4000>;
+				interrupts = <31>, <53>;
+				#clock-cells = <1>;
+			};
+
 			gpt: timer@53f90000 {
 				compatible = "fsl,imx31-gpt";
 				reg = <0x53f90000 0x4000>;
--- linux-4.4.0.orig/arch/arm/boot/dts/imx50-evk.dts
+++ linux-4.4.0/arch/arm/boot/dts/imx50-evk.dts
@@ -66,7 +66,7 @@
 				MX50_PAD_CSPI_MISO__CSPI_MISO		0x00
 				MX50_PAD_CSPI_MOSI__CSPI_MOSI		0x00
 				MX50_PAD_CSPI_SS0__GPIO4_11		0xc4
-				MX50_PAD_ECSPI1_MOSI__CSPI_SS1		0xf4
+				MX50_PAD_ECSPI1_MOSI__GPIO4_13		0x84
 			>;
 		};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/imx53-qsb-common.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx53-qsb-common.dtsi
@@ -130,6 +130,17 @@
 	};
 };
 
+&cpu0 {
+	/* CPU rated to 1GHz, not 1.2GHz as per the default settings */
+	operating-points = <
+		/* kHz   uV */
+		166666  850000
+		400000  900000
+		800000  1050000
+		1000000 1200000
+	>;
+};
+
 &esdhc1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_esdhc1>;
--- linux-4.4.0.orig/arch/arm/boot/dts/imx53-qsrb.dts
+++ linux-4.4.0/arch/arm/boot/dts/imx53-qsrb.dts
@@ -23,7 +23,7 @@
 	imx53-qsrb {
 		pinctrl_pmic: pmicgrp {
 			fsl,pins = <
-				MX53_PAD_CSI0_DAT5__GPIO5_23	0x1e4 /* IRQ */
+				MX53_PAD_CSI0_DAT5__GPIO5_23	0x1c4 /* IRQ */
 			>;
 		};
 	};
--- linux-4.4.0.orig/arch/arm/boot/dts/imx53-voipac-dmm-668.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx53-voipac-dmm-668.dtsi
@@ -17,12 +17,8 @@
 
 	memory@70000000 {
 		device_type = "memory";
-		reg = <0x70000000 0x20000000>;
-	};
-
-	memory@b0000000 {
-		device_type = "memory";
-		reg = <0xb0000000 0x20000000>;
+		reg = <0x70000000 0x20000000>,
+		      <0xb0000000 0x20000000>;
 	};
 
 	regulators {
--- linux-4.4.0.orig/arch/arm/boot/dts/imx6dl.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx6dl.dtsi
@@ -30,7 +30,7 @@
 				/* kHz    uV */
 				996000  1250000
 				792000  1175000
-				396000  1075000
+				396000  1150000
 			>;
 			fsl,soc-operating-points = <
 				/* ARM kHz  SOC-PU uV */
--- linux-4.4.0.orig/arch/arm/boot/dts/imx6q.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx6q.dtsi
@@ -95,7 +95,7 @@
 					clocks = <&clks IMX6Q_CLK_ECSPI5>,
 						 <&clks IMX6Q_CLK_ECSPI5>;
 					clock-names = "ipg", "per";
-					dmas = <&sdma 11 7 1>, <&sdma 12 7 2>;
+					dmas = <&sdma 11 8 1>, <&sdma 12 8 2>;
 					dma-names = "rx", "tx";
 					status = "disabled";
 				};
--- linux-4.4.0.orig/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
@@ -319,8 +319,6 @@
 		compatible = "fsl,imx6q-nitrogen6_max-sgtl5000",
 			     "fsl,imx-audio-sgtl5000";
 		model = "imx6q-nitrogen6_max-sgtl5000";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_sgtl5000>;
 		ssi-controller = <&ssi1>;
 		audio-codec = <&codec>;
 		audio-routing =
@@ -401,6 +399,8 @@
 
 	codec: sgtl5000@0a {
 		compatible = "fsl,sgtl5000";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_sgtl5000>;
 		reg = <0x0a>;
 		clocks = <&clks 201>;
 		VDDA-supply = <&reg_2p5v>;
--- linux-4.4.0.orig/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
@@ -90,6 +90,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet>;
 	phy-mode = "rgmii";
+	phy-reset-duration = <10>; /* in msecs */
 	phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
 	phy-supply = <&vdd_eth_io_reg>;
 	status = "disabled";
--- linux-4.4.0.orig/arch/arm/boot/dts/imx6qdl-udoo.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx6qdl-udoo.dtsi
@@ -39,7 +39,7 @@
 &fec {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-4.4.0.orig/arch/arm/boot/dts/imx6qdl.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx6qdl.dtsi
@@ -221,7 +221,7 @@
 					clocks = <&clks IMX6QDL_CLK_SPDIF_GCLK>, <&clks IMX6QDL_CLK_OSC>,
 						 <&clks IMX6QDL_CLK_SPDIF>, <&clks IMX6QDL_CLK_ASRC>,
 						 <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_ESAI_EXTAL>,
-						 <&clks IMX6QDL_CLK_IPG>, <&clks IMX6QDL_CLK_MLB>,
+						 <&clks IMX6QDL_CLK_IPG>, <&clks IMX6QDL_CLK_DUMMY>,
 						 <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_SPBA>;
 					clock-names = "core",  "rxtx0",
 						      "rxtx1", "rxtx2",
@@ -853,7 +853,7 @@
 				compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma";
 				reg = <0x020ec000 0x4000>;
 				interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clks IMX6QDL_CLK_SDMA>,
+				clocks = <&clks IMX6QDL_CLK_IPG>,
 					 <&clks IMX6QDL_CLK_SDMA>;
 				clock-names = "ipg", "ahb";
 				#dma-cells = <3>;
--- linux-4.4.0.orig/arch/arm/boot/dts/imx6sl.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx6sl.dtsi
@@ -657,7 +657,7 @@
 				reg = <0x020ec000 0x4000>;
 				interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6SL_CLK_SDMA>,
-					 <&clks IMX6SL_CLK_SDMA>;
+					 <&clks IMX6SL_CLK_AHB>;
 				clock-names = "ipg", "ahb";
 				#dma-cells = <3>;
 				/* imx6sl reuses imx6q sdma firmware */
--- linux-4.4.0.orig/arch/arm/boot/dts/imx6sx.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/imx6sx.dtsi
@@ -732,7 +732,7 @@
 				compatible = "fsl,imx6sx-sdma", "fsl,imx6q-sdma";
 				reg = <0x020ec000 0x4000>;
 				interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clks IMX6SX_CLK_SDMA>,
+				clocks = <&clks IMX6SX_CLK_IPG>,
 					 <&clks IMX6SX_CLK_SDMA>;
 				clock-names = "ipg", "ahb";
 				#dma-cells = <3>;
@@ -1250,7 +1250,7 @@
 				  /* non-prefetchable memory */
 				  0x82000000 0 0x08000000 0x08000000 0 0x00f00000>;
 			num-lanes = <1>;
-			interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>,
 				 <&clks IMX6SX_CLK_PCIE_AXI>,
 				 <&clks IMX6SX_CLK_LVDS1_OUT>,
--- linux-4.4.0.orig/arch/arm/boot/dts/kirkwood-dnskw.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/kirkwood-dnskw.dtsi
@@ -35,8 +35,8 @@
 		compatible = "gpio-fan";
 		pinctrl-0 = <&pmx_fan_high_speed &pmx_fan_low_speed>;
 		pinctrl-names = "default";
-		gpios = <&gpio1 14 GPIO_ACTIVE_LOW
-			 &gpio1 13 GPIO_ACTIVE_LOW>;
+		gpios = <&gpio1 14 GPIO_ACTIVE_HIGH
+			 &gpio1 13 GPIO_ACTIVE_HIGH>;
 		gpio-fan,speed-map = <0    0
 				      3000 1
 				      6000 2>;
--- linux-4.4.0.orig/arch/arm/boot/dts/kirkwood-ds112.dts
+++ linux-4.4.0/arch/arm/boot/dts/kirkwood-ds112.dts
@@ -14,7 +14,7 @@
 #include "kirkwood-synology.dtsi"
 
 / {
-	model = "Synology DS111";
+	model = "Synology DS112";
 	compatible = "synology,ds111", "marvell,kirkwood";
 
 	memory {
--- linux-4.4.0.orig/arch/arm/boot/dts/kirkwood-ib62x0.dts
+++ linux-4.4.0/arch/arm/boot/dts/kirkwood-ib62x0.dts
@@ -113,7 +113,7 @@
 
 	partition@e0000 {
 		label = "u-boot environment";
-		reg = <0xe0000 0x100000>;
+		reg = <0xe0000 0x20000>;
 	};
 
 	partition@100000 {
--- linux-4.4.0.orig/arch/arm/boot/dts/kirkwood-lswvl.dts
+++ linux-4.4.0/arch/arm/boot/dts/kirkwood-lswvl.dts
@@ -1,7 +1,8 @@
 /*
  * Device Tree file for Buffalo Linkstation LS-WVL/VL
  *
- * Copyright (C) 2015, rogershimizu@gmail.com
+ * Copyright (C) 2015, 2016
+ * Roger Shimizu <rogershimizu@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -156,21 +157,21 @@
 		button@1 {
 			label = "Function Button";
 			linux,code = <KEY_OPTION>;
-			gpios = <&gpio0 45 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
 		};
 
 		button@2 {
 			label = "Power-on Switch";
 			linux,code = <KEY_RESERVED>;
 			linux,input-type = <5>;
-			gpios = <&gpio0 46 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
 		};
 
 		button@3 {
 			label = "Power-auto Switch";
 			linux,code = <KEY_ESC>;
 			linux,input-type = <5>;
-			gpios = <&gpio0 47 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
 		};
 	};
 
@@ -185,38 +186,38 @@
 
 		led@1 {
 			label = "lswvl:red:alarm";
-			gpios = <&gpio0 36 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
 		};
 
 		led@2 {
 			label = "lswvl:red:func";
-			gpios = <&gpio0 37 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
 		};
 
 		led@3 {
 			label = "lswvl:amber:info";
-			gpios = <&gpio0 38 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
 		};
 
 		led@4 {
 			label = "lswvl:blue:func";
-			gpios = <&gpio0 39 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
 		};
 
 		led@5 {
 			label = "lswvl:blue:power";
-			gpios = <&gpio0 40 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
 			default-state = "keep";
 		};
 
 		led@6 {
 			label = "lswvl:red:hdderr0";
-			gpios = <&gpio0 34 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
 		};
 
 		led@7 {
 			label = "lswvl:red:hdderr1";
-			gpios = <&gpio0 35 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
@@ -233,7 +234,7 @@
 				3250 1
 				5000 0>;
 
-		alarm-gpios = <&gpio0 43 GPIO_ACTIVE_HIGH>;
+		alarm-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
 	};
 
 	restart_poweroff {
--- linux-4.4.0.orig/arch/arm/boot/dts/kirkwood-lswxl.dts
+++ linux-4.4.0/arch/arm/boot/dts/kirkwood-lswxl.dts
@@ -1,7 +1,8 @@
 /*
  * Device Tree file for Buffalo Linkstation LS-WXL/WSXL
  *
- * Copyright (C) 2015, rogershimizu@gmail.com
+ * Copyright (C) 2015, 2016
+ * Roger Shimizu <rogershimizu@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -156,21 +157,21 @@
 		button@1 {
 			label = "Function Button";
 			linux,code = <KEY_OPTION>;
-			gpios = <&gpio1 41 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
 		};
 
 		button@2 {
 			label = "Power-on Switch";
 			linux,code = <KEY_RESERVED>;
 			linux,input-type = <5>;
-			gpios = <&gpio1 42 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
 		};
 
 		button@3 {
 			label = "Power-auto Switch";
 			linux,code = <KEY_ESC>;
 			linux,input-type = <5>;
-			gpios = <&gpio1 43 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
 		};
 	};
 
@@ -185,12 +186,12 @@
 
 		led@1 {
 			label = "lswxl:blue:func";
-			gpios = <&gpio1 36 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
 		};
 
 		led@2 {
 			label = "lswxl:red:alarm";
-			gpios = <&gpio1 49 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
 		};
 
 		led@3 {
@@ -200,23 +201,23 @@
 
 		led@4 {
 			label = "lswxl:blue:power";
-			gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
 		};
 
 		led@5 {
 			label = "lswxl:red:func";
-			gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
-			default-state = "keep";
+			gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
 		};
 
 		led@6 {
 			label = "lswxl:red:hdderr0";
-			gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
 		};
 
 		led@7 {
 			label = "lswxl:red:hdderr1";
-			gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
@@ -225,15 +226,15 @@
 		pinctrl-0 = <&pmx_fan_low &pmx_fan_high &pmx_fan_lock>;
 		pinctrl-names = "default";
 
-		gpios = <&gpio0 47 GPIO_ACTIVE_LOW
-			 &gpio0 48 GPIO_ACTIVE_LOW>;
+		gpios = <&gpio1 16 GPIO_ACTIVE_LOW
+			 &gpio1 15 GPIO_ACTIVE_LOW>;
 
 		gpio-fan,speed-map = <0 3
 				1500 2
 				3250 1
 				5000 0>;
 
-		alarm-gpios = <&gpio1 49 GPIO_ACTIVE_HIGH>;
+		alarm-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
 	};
 
 	restart_poweroff {
@@ -256,7 +257,7 @@
 			enable-active-high;
 			regulator-always-on;
 			regulator-boot-on;
-			gpio = <&gpio0 37 GPIO_ACTIVE_HIGH>;
+			gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
 		};
 		hdd_power0: regulator@2 {
 			compatible = "regulator-fixed";
--- linux-4.4.0.orig/arch/arm/boot/dts/kirkwood-openblocks_a7.dts
+++ linux-4.4.0/arch/arm/boot/dts/kirkwood-openblocks_a7.dts
@@ -53,7 +53,8 @@
 		};
 
 		pinctrl: pin-controller@10000 {
-			pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>;
+			pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header
+				     &pmx_gpio_header_gpo>;
 			pinctrl-names = "default";
 
 			pmx_uart0: pmx-uart0 {
@@ -85,11 +86,16 @@
 			 * ground.
 			 */
 			pmx_gpio_header: pmx-gpio-header {
-				marvell,pins = "mpp17", "mpp7", "mpp29", "mpp28",
+				marvell,pins = "mpp17", "mpp29", "mpp28",
 					       "mpp35", "mpp34", "mpp40";
 				marvell,function = "gpio";
 			};
 
+			pmx_gpio_header_gpo: pxm-gpio-header-gpo {
+				marvell,pins = "mpp7";
+				marvell,function = "gpo";
+			};
+
 			pmx_gpio_init: pmx-init {
 				marvell,pins = "mpp38";
 				marvell,function = "gpio";
--- linux-4.4.0.orig/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts
+++ linux-4.4.0/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts
@@ -88,7 +88,7 @@
 	interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc1_pins &mmc1_cd>;
-	cd-gpios = <&gpio4 31 IRQ_TYPE_LEVEL_LOW>;		/* gpio127 */
+	cd-gpios = <&gpio4 31 GPIO_ACTIVE_LOW>;		/* gpio127 */
 	vmmc-supply = <&vmmc1>;
 	bus-width = <4>;
 	cap-power-off-card;
--- linux-4.4.0.orig/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
@@ -90,6 +90,8 @@
 };
 
 &i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
 	clock-frequency = <2600000>;
 
 	twl: twl@48 {
@@ -122,6 +124,7 @@
 		interrupt-parent = <&gpio5>;
 		interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; /* gpio 152 */
 		ref-clock-frequency = <26000000>;
+		tcxo-clock-frequency = <26000000>;
 	};
 };
 
@@ -136,6 +139,12 @@
 			OMAP3_CORE1_IOPAD(0x218e, PIN_OUTPUT | MUX_MODE4)	/* mcbsp1_fsr.gpio_157 */
 		>;
 	};
+	i2c1_pins: pinmux_i2c1_pins {
+		pinctrl-single,pins = <
+			OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0)        /* i2c1_scl.i2c1_scl */
+			OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0)        /* i2c1_sda.i2c1_sda */
+		>;
+	};
 };
 
 &omap3_pmx_core2 {
@@ -160,3 +169,7 @@
 &twl_gpio {
 	ti,use-leds;
 };
+
+&twl_keypad {
+	status = "disabled";
+};
--- linux-4.4.0.orig/arch/arm/boot/dts/ls1021a-qds.dts
+++ linux-4.4.0/arch/arm/boot/dts/ls1021a-qds.dts
@@ -215,7 +215,7 @@
 				reg = <0x2a>;
 				VDDA-supply = <&reg_3p3v>;
 				VDDIO-supply = <&reg_3p3v>;
-				clocks = <&sys_mclk 1>;
+				clocks = <&sys_mclk>;
 			};
 		};
 	};
--- linux-4.4.0.orig/arch/arm/boot/dts/ls1021a-twr.dts
+++ linux-4.4.0/arch/arm/boot/dts/ls1021a-twr.dts
@@ -167,7 +167,7 @@
 		reg = <0x0a>;
 		VDDA-supply = <&reg_3p3v>;
 		VDDIO-supply = <&reg_3p3v>;
-		clocks = <&sys_mclk 1>;
+		clocks = <&sys_mclk>;
 	};
 };
 
--- linux-4.4.0.orig/arch/arm/boot/dts/ls1021a.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/ls1021a.dtsi
@@ -132,7 +132,7 @@
 		};
 
 		esdhc: esdhc@1560000 {
-			compatible = "fsl,esdhc";
+			compatible = "fsl,ls1021a-esdhc", "fsl,esdhc";
 			reg = <0x0 0x1560000 0x0 0x10000>;
 			interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
 			clock-frequency = <0>;
--- linux-4.4.0.orig/arch/arm/boot/dts/mmp2.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/mmp2.dtsi
@@ -180,7 +180,7 @@
 				clocks = <&soc_clocks MMP2_CLK_GPIO>;
 				resets = <&soc_clocks MMP2_CLK_GPIO>;
 				interrupt-controller;
-				#interrupt-cells = <1>;
+				#interrupt-cells = <2>;
 				ranges;
 
 				gcb0: gpio@d4019000 {
@@ -220,12 +220,15 @@
 				status = "disabled";
 			};
 
-			twsi2: i2c@d4025000 {
+			twsi2: i2c@d4031000 {
 				compatible = "mrvl,mmp-twsi";
-				reg = <0xd4025000 0x1000>;
-				interrupts = <58>;
+				reg = <0xd4031000 0x1000>;
+				interrupt-parent = <&intcmux17>;
+				interrupts = <0>;
 				clocks = <&soc_clocks MMP2_CLK_TWSI1>;
 				resets = <&soc_clocks MMP2_CLK_TWSI1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
 				status = "disabled";
 			};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/moxart-uc7112lx.dts
+++ linux-4.4.0/arch/arm/boot/dts/moxart-uc7112lx.dts
@@ -6,7 +6,7 @@
  */
 
 /dts-v1/;
-/include/ "moxart.dtsi"
+#include "moxart.dtsi"
 
 / {
 	model = "MOXA UC-7112-LX";
--- linux-4.4.0.orig/arch/arm/boot/dts/moxart.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/moxart.dtsi
@@ -6,6 +6,7 @@
  */
 
 /include/ "skeleton.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
 
 / {
 	compatible = "moxa,moxart";
@@ -36,8 +37,8 @@
 		ranges;
 
 		intc: interrupt-controller@98800000 {
-			compatible = "moxa,moxart-ic";
-			reg = <0x98800000 0x38>;
+			compatible = "moxa,moxart-ic", "faraday,ftintc010";
+			reg = <0x98800000 0x100>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
 			interrupt-mask = <0x00080000>;
@@ -59,7 +60,7 @@
 		timer: timer@98400000 {
 			compatible = "moxa,moxart-timer";
 			reg = <0x98400000 0x42>;
-			interrupts = <19 1>;
+			interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
 			clocks = <&clk_apb>;
 		};
 
@@ -80,7 +81,7 @@
 		dma: dma@90500000 {
 			compatible = "moxa,moxart-dma";
 			reg = <0x90500080 0x40>;
-			interrupts = <24 0>;
+			interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
 			#dma-cells = <1>;
 		};
 
@@ -93,7 +94,7 @@
 		sdhci: sdhci@98e00000 {
 			compatible = "moxa,moxart-sdhci";
 			reg = <0x98e00000 0x5C>;
-			interrupts = <5 0>;
+			interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clk_apb>;
 			dmas =  <&dma 5>,
 				<&dma 5>;
@@ -120,7 +121,7 @@
 		mac0: mac@90900000 {
 			compatible = "moxa,moxart-mac";
 			reg = <0x90900000 0x90>;
-			interrupts = <25 0>;
+			interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
 			phy-handle = <&ethphy0>;
 			phy-mode = "mii";
 			status = "disabled";
@@ -129,7 +130,7 @@
 		mac1: mac@92000000 {
 			compatible = "moxa,moxart-mac";
 			reg = <0x92000000 0x90>;
-			interrupts = <27 0>;
+			interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
 			phy-handle = <&ethphy1>;
 			phy-mode = "mii";
 			status = "disabled";
@@ -138,7 +139,7 @@
 		uart0: uart@98200000 {
 			compatible = "ns16550a";
 			reg = <0x98200000 0x20>;
-			interrupts = <31 8>;
+			interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clock-frequency = <14745600>;
--- linux-4.4.0.orig/arch/arm/boot/dts/omap3-gta04.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -28,6 +28,7 @@
 
 	aliases {
 		display0 = &lcd;
+		display1 = &tv0;
 	};
 
 	gpio-keys {
@@ -70,7 +71,7 @@
 		#sound-dai-cells = <0>;
 	};
 
-	spi_lcd {
+	spi_lcd: spi_lcd {
 		compatible = "spi-gpio";
 		#address-cells = <0x1>;
 		#size-cells = <0x0>;
@@ -459,6 +460,12 @@
 	regulator-max-microvolt = <3150000>;
 };
 
+/* Needed to power the DPI pins */
+
+&vpll2 {
+	regulator-always-on;
+};
+
 &dss {
 	pinctrl-names = "default";
 	pinctrl-0 = < &dss_dpi_pins >;
@@ -522,22 +529,22 @@
 
 		bootloaders@80000 {
 			label = "U-Boot";
-			reg = <0x80000 0x1e0000>;
+			reg = <0x80000 0x1c0000>;
 		};
 
-		bootloaders_env@260000 {
+		bootloaders_env@240000 {
 			label = "U-Boot Env";
-			reg = <0x260000 0x20000>;
+			reg = <0x240000 0x40000>;
 		};
 
 		kernel@280000 {
 			label = "Kernel";
-			reg = <0x280000 0x400000>;
+			reg = <0x280000 0x600000>;
 		};
 
-		filesystem@680000 {
+		filesystem@880000 {
 			label = "File System";
-			reg = <0x680000 0xf980000>;
+			reg = <0x880000 0>;	/* 0 = MTDPART_SIZ_FULL */
 		};
 	};
 };
--- linux-4.4.0.orig/arch/arm/boot/dts/omap3-n900.dts
+++ linux-4.4.0/arch/arm/boot/dts/omap3-n900.dts
@@ -697,6 +697,8 @@
 	vmmc_aux-supply = <&vsim>;
 	bus-width = <8>;
 	non-removable;
+	no-sdio;
+	no-sd;
 };
 
 &mmc3 {
--- linux-4.4.0.orig/arch/arm/boot/dts/omap3-overo-base.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/omap3-overo-base.dtsi
@@ -223,7 +223,9 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>;
+	ranges = <0 0 0x30000000 0x1000000>,	/* CS0 */
+		 <4 0 0x2b000000 0x1000000>,	/* CS4 */
+		 <5 0 0x2c000000 0x1000000>;	/* CS5 */
 
 	nand@0,0 {
 		linux,mtd-name= "micron,mt29c4g96maz";
--- linux-4.4.0.orig/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
@@ -55,8 +55,6 @@
 #include "omap-gpmc-smsc9221.dtsi"
 
 &gpmc {
-	ranges = <5 0 0x2c000000 0x1000000>;	/* CS5 */
-
 	ethernet@gpmc {
 		reg = <5 0 0xff>;
 		interrupt-parent = <&gpio6>;
--- linux-4.4.0.orig/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
@@ -27,8 +27,6 @@
 #include "omap-gpmc-smsc9221.dtsi"
 
 &gpmc {
-	ranges = <5 0 0x2c000000 0x1000000>;	/* CS5 */
-
 	ethernet@gpmc {
 		reg = <5 0 0xff>;
 		interrupt-parent = <&gpio6>;
--- linux-4.4.0.orig/arch/arm/boot/dts/omap3-overo-tobiduo-common.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/omap3-overo-tobiduo-common.dtsi
@@ -15,9 +15,6 @@
 #include "omap-gpmc-smsc9221.dtsi"
 
 &gpmc {
-	ranges = <4 0 0x2b000000 0x1000000>,	/* CS4 */
-		 <5 0 0x2c000000 0x1000000>;	/* CS5 */
-
 	smsc1: ethernet@gpmc {
 		reg = <5 0 0xff>;
 		interrupt-parent = <&gpio6>;
--- linux-4.4.0.orig/arch/arm/boot/dts/omap3-tao3530.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/omap3-tao3530.dtsi
@@ -225,7 +225,7 @@
 	pinctrl-0 = <&mmc1_pins>;
 	vmmc-supply = <&vmmc1>;
 	vmmc_aux-supply = <&vsim>;
-	cd-gpios = <&twl_gpio 0 GPIO_ACTIVE_HIGH>;
+	cd-gpios = <&twl_gpio 0 GPIO_ACTIVE_LOW>;
 	bus-width = <8>;
 };
 
--- linux-4.4.0.orig/arch/arm/boot/dts/omap4-sdp.dts
+++ linux-4.4.0/arch/arm/boot/dts/omap4-sdp.dts
@@ -33,6 +33,7 @@
 		gpio = <&gpio2 16 GPIO_ACTIVE_HIGH>;  /* gpio line 48 */
 		enable-active-high;
 		regulator-boot-on;
+		startup-delay-us = <25000>;
 	};
 
 	vbat: fixedregulator-vbat {
--- linux-4.4.0.orig/arch/arm/boot/dts/omap4.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/omap4.dtsi
@@ -844,14 +844,12 @@
 			usbhsohci: ohci@4a064800 {
 				compatible = "ti,ohci-omap3";
 				reg = <0x4a064800 0x400>;
-				interrupt-parent = <&gic>;
 				interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
 			usbhsehci: ehci@4a064c00 {
 				compatible = "ti,ehci-omap";
 				reg = <0x4a064c00 0x400>;
-				interrupt-parent = <&gic>;
 				interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
 			};
 		};
--- linux-4.4.0.orig/arch/arm/boot/dts/omap5-board-common.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/omap5-board-common.dtsi
@@ -130,6 +130,16 @@
 	};
 };
 
+&gpio8 {
+	/* TI trees use GPIO instead of msecure, see also muxing */
+	p234 {
+		gpio-hog;
+		gpios = <10 GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "gpio8_234/msecure";
+	};
+};
+
 &omap5_pmx_core {
 	pinctrl-names = "default";
 	pinctrl-0 = <
@@ -213,6 +223,13 @@
 		>;
 	};
 
+	/* TI trees use GPIO mode; msecure mode does not work reliably? */
+	palmas_msecure_pins: palmas_msecure_pins {
+		pinctrl-single,pins = <
+			OMAP5_IOPAD(0x180, PIN_OUTPUT | MUX_MODE6) /* gpio8_234 */
+		>;
+	};
+
 	usbhost_pins: pinmux_usbhost_pins {
 		pinctrl-single,pins = <
 			0x84 (PIN_INPUT | MUX_MODE0) /* usbb2_hsic_strobe */
@@ -278,6 +295,12 @@
 			&usbhost_wkup_pins
 	>;
 
+	palmas_sys_nirq_pins: pinmux_palmas_sys_nirq_pins {
+		pinctrl-single,pins = <
+			OMAP5_IOPAD(0x068, PIN_INPUT_PULLUP | MUX_MODE0) /* sys_nirq1 */
+		>;
+	};
+
 	usbhost_wkup_pins: pinmux_usbhost_wkup_pins {
 		pinctrl-single,pins = <
 			0x1A (PIN_OUTPUT | MUX_MODE0) /* fref_clk1_out, USB hub clk */
@@ -345,6 +368,8 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		ti,system-power-controller;
+		pinctrl-names = "default";
+		pinctrl-0 = <&palmas_sys_nirq_pins &palmas_msecure_pins>;
 
 		extcon_usb3: palmas_usb {
 			compatible = "ti,palmas-usb-vid";
@@ -358,6 +383,14 @@
 			#clock-cells = <0>;
 		};
 
+		rtc {
+			compatible = "ti,palmas-rtc";
+			interrupt-parent = <&palmas>;
+			interrupts = <8 IRQ_TYPE_NONE>;
+			ti,backup-battery-chargeable;
+			ti,backup-battery-charge-high-current;
+		};
+
 		palmas_pmic {
 			compatible = "ti,palmas-pmic";
 			interrupt-parent = <&palmas>;
--- linux-4.4.0.orig/arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts
+++ linux-4.4.0/arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts
@@ -1,7 +1,8 @@
 /*
  * Device Tree file for Buffalo Linkstation LS-WTGL
  *
- * Copyright (C) 2015, Roger Shimizu <rogershimizu@gmail.com>
+ * Copyright (C) 2015, 2016
+ * Roger Shimizu <rogershimizu@gmail.com>
  *
  * This file is dual-licensed: you can use it either under the terms
  * of the GPL or the X11 license, at your option. Note that this dual
@@ -69,8 +70,6 @@
 
 		internal-regs {
 			pinctrl: pinctrl@10000 {
-				pinctrl-0 = <&pmx_usb_power &pmx_power_hdd
-					&pmx_fan_low &pmx_fan_high &pmx_fan_lock>;
 				pinctrl-names = "default";
 
 				pmx_led_power: pmx-leds {
@@ -162,6 +161,7 @@
 		led@1 {
 			label = "lswtgl:blue:power";
 			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+			default-state = "keep";
 		};
 
 		led@2 {
@@ -188,7 +188,7 @@
 				3250 1
 				5000 0>;
 
-		alarm-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+		alarm-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
 	};
 
 	restart_poweroff {
@@ -227,6 +227,37 @@
 		};
 	};
 };
+
+&devbus_bootcs {
+	status = "okay";
+	devbus,keep-config;
+
+	flash@0 {
+		compatible = "jedec-flash";
+		reg = <0 0x40000>;
+		bank-width = <1>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			header@0 {
+				reg = <0 0x30000>;
+				read-only;
+			};
+
+			uboot@30000 {
+				reg = <0x30000 0xF000>;
+				read-only;
+			};
+
+			uboot_env@3F000 {
+				reg = <0x3F000 0x1000>;
+			};
+		};
+	};
+};
 
 &mdio {
 	status = "okay";
--- linux-4.4.0.orig/arch/arm/boot/dts/picoxcell-pc3x2.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/picoxcell-pc3x2.dtsi
@@ -54,18 +54,21 @@
 		emac: gem@30000 {
 			compatible = "cadence,gem";
 			reg = <0x30000 0x10000>;
+			interrupt-parent = <&vic0>;
 			interrupts = <31>;
 		};
 
 		dmac1: dmac@40000 {
 			compatible = "snps,dw-dmac";
 			reg = <0x40000 0x10000>;
+			interrupt-parent = <&vic0>;
 			interrupts = <25>;
 		};
 
 		dmac2: dmac@50000 {
 			compatible = "snps,dw-dmac";
 			reg = <0x50000 0x10000>;
+			interrupt-parent = <&vic0>;
 			interrupts = <26>;
 		};
 
@@ -243,6 +246,7 @@
 		axi2pico@c0000000 {
 			compatible = "picochip,axi2pico-pc3x2";
 			reg = <0xc0000000 0x10000>;
+			interrupt-parent = <&vic0>;
 			interrupts = <13 14 15 16 17 18 19 20 21>;
 		};
 	};
--- linux-4.4.0.orig/arch/arm/boot/dts/pxa27x.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/pxa27x.dtsi
@@ -13,6 +13,7 @@
 			interrupts = <25>;
 			#dma-channels = <32>;
 			#dma-cells = <2>;
+			#dma-requests = <75>;
 			status = "okay";
 		};
 
@@ -26,7 +27,7 @@
 			clocks = <&clks CLK_NONE>;
 		};
 
-		pxa27x_ohci: usb@4c000000 {
+		usb0: usb@4c000000 {
 			compatible = "marvell,pxa-ohci";
 			reg = <0x4c000000 0x10000>;
 			interrupts = <3>;
@@ -62,7 +63,7 @@
 			clocks = <&clks CLK_PWM1>;
 		};
 
-		pwri2c: i2c@40f000180 {
+		pwri2c: i2c@40f00180 {
 			compatible = "mrvl,pxa-i2c";
 			reg = <0x40f00180 0x24>;
 			interrupts = <6>;
--- linux-4.4.0.orig/arch/arm/boot/dts/pxa2xx.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/pxa2xx.dtsi
@@ -117,13 +117,6 @@
 			status = "disabled";
 		};
 
-		usb0: ohci@4c000000 {
-			compatible = "marvell,pxa-ohci";
-			reg = <0x4c000000 0x10000>;
-			interrupts = <3>;
-			status = "disabled";
-		};
-
 		mmc0: mmc@41100000 {
 			compatible = "marvell,pxa-mmc";
 			reg = <0x41100000 0x1000>;
--- linux-4.4.0.orig/arch/arm/boot/dts/pxa3xx.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/pxa3xx.dtsi
@@ -12,6 +12,7 @@
 			interrupts = <25>;
 			#dma-channels = <32>;
 			#dma-cells = <2>;
+			#dma-requests = <100>;
 			status = "okay";
 		};
 
@@ -30,7 +31,7 @@
 			reg = <0x43100000 90>;
 			interrupts = <45>;
 			clocks = <&clks CLK_NAND>;
-			dmas = <&pdma 97>;
+			dmas = <&pdma 97 3>;
 			dma-names = "data";
 			#address-cells = <1>;
 			#size-cells = <1>;	
@@ -87,7 +88,7 @@
 			status = "disabled";
 		};
 
-		pxa3xx_ohci: usb@4c000000 {
+		usb0: usb@4c000000 {
 			compatible = "marvell,pxa-ohci";
 			reg = <0x4c000000 0x10000>;
 			interrupts = <3>;
--- linux-4.4.0.orig/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -5,6 +5,7 @@
 #include <dt-bindings/reset/qcom,gcc-msm8960.h>
 #include <dt-bindings/clock/qcom,mmcc-msm8960.h>
 #include <dt-bindings/soc/qcom,gsbi.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 / {
 	model = "Qualcomm APQ8064";
@@ -354,22 +355,50 @@
 
 					compatible = "qcom,pm8921-gpio";
 					reg = <0x150>;
-					interrupts = <192 1>, <193 1>, <194 1>,
-						     <195 1>, <196 1>, <197 1>,
-						     <198 1>, <199 1>, <200 1>,
-						     <201 1>, <202 1>, <203 1>,
-						     <204 1>, <205 1>, <206 1>,
-						     <207 1>, <208 1>, <209 1>,
-						     <210 1>, <211 1>, <212 1>,
-						     <213 1>, <214 1>, <215 1>,
-						     <216 1>, <217 1>, <218 1>,
-						     <219 1>, <220 1>, <221 1>,
-						     <222 1>, <223 1>, <224 1>,
-						     <225 1>, <226 1>, <227 1>,
-						     <228 1>, <229 1>, <230 1>,
-						     <231 1>, <232 1>, <233 1>,
-						     <234 1>, <235 1>;
-
+					interrupts = <192 IRQ_TYPE_NONE>,
+						     <193 IRQ_TYPE_NONE>,
+						     <194 IRQ_TYPE_NONE>,
+						     <195 IRQ_TYPE_NONE>,
+						     <196 IRQ_TYPE_NONE>,
+						     <197 IRQ_TYPE_NONE>,
+						     <198 IRQ_TYPE_NONE>,
+						     <199 IRQ_TYPE_NONE>,
+						     <200 IRQ_TYPE_NONE>,
+						     <201 IRQ_TYPE_NONE>,
+						     <202 IRQ_TYPE_NONE>,
+						     <203 IRQ_TYPE_NONE>,
+						     <204 IRQ_TYPE_NONE>,
+						     <205 IRQ_TYPE_NONE>,
+						     <206 IRQ_TYPE_NONE>,
+						     <207 IRQ_TYPE_NONE>,
+						     <208 IRQ_TYPE_NONE>,
+						     <209 IRQ_TYPE_NONE>,
+						     <210 IRQ_TYPE_NONE>,
+						     <211 IRQ_TYPE_NONE>,
+						     <212 IRQ_TYPE_NONE>,
+						     <213 IRQ_TYPE_NONE>,
+						     <214 IRQ_TYPE_NONE>,
+						     <215 IRQ_TYPE_NONE>,
+						     <216 IRQ_TYPE_NONE>,
+						     <217 IRQ_TYPE_NONE>,
+						     <218 IRQ_TYPE_NONE>,
+						     <219 IRQ_TYPE_NONE>,
+						     <220 IRQ_TYPE_NONE>,
+						     <221 IRQ_TYPE_NONE>,
+						     <222 IRQ_TYPE_NONE>,
+						     <223 IRQ_TYPE_NONE>,
+						     <224 IRQ_TYPE_NONE>,
+						     <225 IRQ_TYPE_NONE>,
+						     <226 IRQ_TYPE_NONE>,
+						     <227 IRQ_TYPE_NONE>,
+						     <228 IRQ_TYPE_NONE>,
+						     <229 IRQ_TYPE_NONE>,
+						     <230 IRQ_TYPE_NONE>,
+						     <231 IRQ_TYPE_NONE>,
+						     <232 IRQ_TYPE_NONE>,
+						     <233 IRQ_TYPE_NONE>,
+						     <234 IRQ_TYPE_NONE>,
+						     <235 IRQ_TYPE_NONE>;
 					gpio-controller;
 					#gpio-cells = <2>;
 
@@ -381,9 +410,18 @@
 					gpio-controller;
 					#gpio-cells = <2>;
 					interrupts =
-					<128 1>, <129 1>, <130 1>, <131 1>,
-					<132 1>, <133 1>, <134 1>, <135 1>,
-					<136 1>, <137 1>, <138 1>, <139 1>;
+					<128 IRQ_TYPE_NONE>,
+					<129 IRQ_TYPE_NONE>,
+					<130 IRQ_TYPE_NONE>,
+					<131 IRQ_TYPE_NONE>,
+					<132 IRQ_TYPE_NONE>,
+					<133 IRQ_TYPE_NONE>,
+					<134 IRQ_TYPE_NONE>,
+					<135 IRQ_TYPE_NONE>,
+					<136 IRQ_TYPE_NONE>,
+					<137 IRQ_TYPE_NONE>,
+					<138 IRQ_TYPE_NONE>,
+					<139 IRQ_TYPE_NONE>;
 				};
 
 				rtc@11d {
@@ -539,7 +577,7 @@
 		};
 
 		sata0: sata@29000000 {
-			compatible		= "generic-ahci";
+			compatible		= "qcom,apq8064-ahci", "generic-ahci";
 			status			= "disabled";
 			reg			= <0x29000000 0x180>;
 			interrupts		= <GIC_SPI 209 IRQ_TYPE_NONE>;
@@ -561,6 +599,7 @@
 
 			phys			= <&sata_phy0>;
 			phy-names		= "sata-phy";
+			ports-implemented	= <0x1>;
 		};
 
 		/* Temporary fixed regulator */
--- linux-4.4.0.orig/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
+++ linux-4.4.0/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -180,7 +180,7 @@
 };
 
 &extal1_clk {
-	clock-frequency = <25000000>;
+	clock-frequency = <24000000>;
 };
 &extal2_clk {
 	clock-frequency = <48000000>;
--- linux-4.4.0.orig/arch/arm/boot/dts/r8a7740.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/r8a7740.dtsi
@@ -461,7 +461,7 @@
 		cpg_clocks: cpg_clocks@e6150000 {
 			compatible = "renesas,r8a7740-cpg-clocks";
 			reg = <0xe6150000 0x10000>;
-			clocks = <&extal1_clk>, <&extalr_clk>;
+			clocks = <&extal1_clk>, <&extal2_clk>, <&extalr_clk>;
 			#clock-cells = <1>;
 			clock-output-names = "system", "pllc0", "pllc1",
 					     "pllc2", "r",
--- linux-4.4.0.orig/arch/arm/boot/dts/r8a7779.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/r8a7779.dtsi
@@ -63,6 +63,14 @@
 		      <0xf0000100 0x100>;
 	};
 
+	timer@f0000200 {
+		compatible = "arm,cortex-a9-global-timer";
+		reg = <0xf0000200 0x100>;
+		interrupts = <GIC_PPI 11
+			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
+		clocks = <&cpg_clocks R8A7779_CLK_ZS>;
+	};
+
 	timer@f0000600 {
 		compatible = "arm,cortex-a9-twd-timer";
 		reg = <0xf0000600 0x20>;
--- linux-4.4.0.orig/arch/arm/boot/dts/r8a7790.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/r8a7790.dtsi
@@ -1360,8 +1360,11 @@
 			compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>;
 			clocks = <&p_clk>,
-				<&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>,
-				<&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>,
+				<&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>,
+				<&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>,
+				<&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>,
+				<&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>,
+				<&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>,
 				<&p_clk>,
 				<&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>,
 				<&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>,
@@ -1409,7 +1412,8 @@
 	};
 
 	msiof0: spi@e6e20000 {
-		compatible = "renesas,msiof-r8a7790";
+		compatible = "renesas,msiof-r8a7790",
+			     "renesas,rcar-gen2-msiof";
 		reg = <0 0xe6e20000 0 0x0064>;
 		interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp0_clks R8A7790_CLK_MSIOF0>;
@@ -1422,7 +1426,8 @@
 	};
 
 	msiof1: spi@e6e10000 {
-		compatible = "renesas,msiof-r8a7790";
+		compatible = "renesas,msiof-r8a7790",
+			     "renesas,rcar-gen2-msiof";
 		reg = <0 0xe6e10000 0 0x0064>;
 		interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7790_CLK_MSIOF1>;
@@ -1435,7 +1440,8 @@
 	};
 
 	msiof2: spi@e6e00000 {
-		compatible = "renesas,msiof-r8a7790";
+		compatible = "renesas,msiof-r8a7790",
+			     "renesas,rcar-gen2-msiof";
 		reg = <0 0xe6e00000 0 0x0064>;
 		interrupts = <0 158 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7790_CLK_MSIOF2>;
@@ -1448,7 +1454,8 @@
 	};
 
 	msiof3: spi@e6c90000 {
-		compatible = "renesas,msiof-r8a7790";
+		compatible = "renesas,msiof-r8a7790",
+			     "renesas,rcar-gen2-msiof";
 		reg = <0 0xe6c90000 0 0x0064>;
 		interrupts = <0 159 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7790_CLK_MSIOF3>;
--- linux-4.4.0.orig/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ linux-4.4.0/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -280,7 +280,7 @@
 	x2_clk: x2-clock {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
-		clock-frequency = <148500000>;
+		clock-frequency = <74250000>;
 	};
 
 	x13_clk: x13-clock {
--- linux-4.4.0.orig/arch/arm/boot/dts/r8a7791.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/r8a7791.dtsi
@@ -1374,8 +1374,11 @@
 			compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>;
 			clocks = <&p_clk>,
-				<&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>,
-				<&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>,
+				<&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>,
+				<&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>,
+				<&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>,
+				<&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>,
+				<&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>,
 				<&p_clk>,
 				<&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>,
 				<&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>,
--- linux-4.4.0.orig/arch/arm/boot/dts/r8a7794.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/r8a7794.dtsi
@@ -1023,7 +1023,7 @@
 		mstp7_clks: mstp7_clks@e615014c {
 			compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe615014c 0 4>, <0 0xe61501c4 0 4>;
-			clocks = <&mp_clk>, <&mp_clk>,
+			clocks = <&mp_clk>, <&hp_clk>,
 				 <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>,
 				 <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>;
 			#clock-cells = <1>;
--- linux-4.4.0.orig/arch/arm/boot/dts/rk3288.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/rk3288.dtsi
@@ -205,6 +205,7 @@
 			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
 			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		clock-frequency = <24000000>;
+		arm,no-tick-in-suspend;
 	};
 
 	timer: timer@ff810000 {
--- linux-4.4.0.orig/arch/arm/boot/dts/s3c6410-mini6410.dts
+++ linux-4.4.0/arch/arm/boot/dts/s3c6410-mini6410.dts
@@ -167,6 +167,10 @@
 	};
 };
 
+&clocks {
+	clocks = <&fin_pll>;
+};
+
 &sdhci0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
--- linux-4.4.0.orig/arch/arm/boot/dts/s3c6410-smdk6410.dts
+++ linux-4.4.0/arch/arm/boot/dts/s3c6410-smdk6410.dts
@@ -71,6 +71,10 @@
 	};
 };
 
+&clocks {
+	clocks = <&fin_pll>;
+};
+
 &sdhci0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
--- linux-4.4.0.orig/arch/arm/boot/dts/s5pv210.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/s5pv210.dtsi
@@ -99,19 +99,16 @@
 		};
 
 		clocks: clock-controller@e0100000 {
-			compatible = "samsung,s5pv210-clock", "simple-bus";
+			compatible = "samsung,s5pv210-clock";
 			reg = <0xe0100000 0x10000>;
 			clock-names = "xxti", "xusbxti";
 			clocks = <&xxti>, <&xusbxti>;
 			#clock-cells = <1>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges;
+		};
 
-			pmu_syscon: syscon@e0108000 {
-				compatible = "samsung-s5pv210-pmu", "syscon";
-				reg = <0xe0108000 0x8000>;
-			};
+		pmu_syscon: syscon@e0108000 {
+			compatible = "samsung-s5pv210-pmu", "syscon";
+			reg = <0xe0108000 0x8000>;
 		};
 
 		pinctrl0: pinctrl@e0200000 {
@@ -228,43 +225,36 @@
 			status = "disabled";
 		};
 
-		audio-subsystem {
-			compatible = "samsung,s5pv210-audss", "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges;
-
-			clk_audss: clock-controller@eee10000 {
-				compatible = "samsung,s5pv210-audss-clock";
-				reg = <0xeee10000 0x1000>;
-				clock-names = "hclk", "xxti",
-						"fout_epll",
-						"sclk_audio0";
-				clocks = <&clocks DOUT_HCLKP>, <&xxti>,
-						<&clocks FOUT_EPLL>,
-						<&clocks SCLK_AUDIO0>;
-				#clock-cells = <1>;
-			};
+		clk_audss: clock-controller@eee10000 {
+			compatible = "samsung,s5pv210-audss-clock";
+			reg = <0xeee10000 0x1000>;
+			clock-names = "hclk", "xxti",
+				      "fout_epll",
+				      "sclk_audio0";
+			clocks = <&clocks DOUT_HCLKP>, <&xxti>,
+				 <&clocks FOUT_EPLL>,
+				 <&clocks SCLK_AUDIO0>;
+			#clock-cells = <1>;
+		};
 
-			i2s0: i2s@eee30000 {
-				compatible = "samsung,s5pv210-i2s";
-				reg = <0xeee30000 0x1000>;
-				interrupt-parent = <&vic2>;
-				interrupts = <16>;
-				dma-names = "rx", "tx", "tx-sec";
-				dmas = <&pdma1 9>, <&pdma1 10>, <&pdma1 11>;
-				clock-names = "iis",
-						"i2s_opclk0",
-						"i2s_opclk1";
-				clocks = <&clk_audss CLK_I2S>,
-						<&clk_audss CLK_I2S>,
-						<&clk_audss CLK_DOUT_AUD_BUS>;
-				samsung,idma-addr = <0xc0010000>;
-				pinctrl-names = "default";
-				pinctrl-0 = <&i2s0_bus>;
-				#sound-dai-cells = <0>;
-				status = "disabled";
-			};
+		i2s0: i2s@eee30000 {
+			compatible = "samsung,s5pv210-i2s";
+			reg = <0xeee30000 0x1000>;
+			interrupt-parent = <&vic2>;
+			interrupts = <16>;
+			dma-names = "rx", "tx", "tx-sec";
+			dmas = <&pdma1 9>, <&pdma1 10>, <&pdma1 11>;
+			clock-names = "iis",
+				      "i2s_opclk0",
+				      "i2s_opclk1";
+			clocks = <&clk_audss CLK_I2S>,
+				 <&clk_audss CLK_I2S>,
+				 <&clk_audss CLK_DOUT_AUD_BUS>;
+			samsung,idma-addr = <0xc0010000>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2s0_bus>;
+			#sound-dai-cells = <0>;
+			status = "disabled";
 		};
 
 		i2s1: i2s@e2100000 {
@@ -461,6 +451,7 @@
 			compatible = "samsung,exynos4210-ohci";
 			reg = <0xec300000 0x100>;
 			interrupts = <23>;
+			interrupt-parent = <&vic1>;
 			clocks = <&clocks CLK_USB_HOST>;
 			clock-names = "usbhost";
 			#address-cells = <1>;
--- linux-4.4.0.orig/arch/arm/boot/dts/sama5d2-pinfunc.h
+++ linux-4.4.0/arch/arm/boot/dts/sama5d2-pinfunc.h
@@ -90,7 +90,7 @@
 #define PIN_PA14__I2SC1_MCK		PINMUX_PIN(PIN_PA14, 4, 2)
 #define PIN_PA14__FLEXCOM3_IO2		PINMUX_PIN(PIN_PA14, 5, 1)
 #define PIN_PA14__D9			PINMUX_PIN(PIN_PA14, 6, 2)
-#define PIN_PA15			14
+#define PIN_PA15			15
 #define PIN_PA15__GPIO			PINMUX_PIN(PIN_PA15, 0, 0)
 #define PIN_PA15__SPI0_MOSI		PINMUX_PIN(PIN_PA15, 1, 1)
 #define PIN_PA15__TF1			PINMUX_PIN(PIN_PA15, 2, 1)
@@ -517,7 +517,7 @@
 #define PIN_PC9__GPIO			PINMUX_PIN(PIN_PC9, 0, 0)
 #define PIN_PC9__FIQ			PINMUX_PIN(PIN_PC9, 1, 3)
 #define PIN_PC9__GTSUCOMP		PINMUX_PIN(PIN_PC9, 2, 1)
-#define PIN_PC9__ISC_D0			PINMUX_PIN(PIN_PC9, 2, 1)
+#define PIN_PC9__ISC_D0			PINMUX_PIN(PIN_PC9, 3, 1)
 #define PIN_PC9__TIOA4			PINMUX_PIN(PIN_PC9, 4, 2)
 #define PIN_PC10			74
 #define PIN_PC10__GPIO			PINMUX_PIN(PIN_PC10, 0, 0)
@@ -837,8 +837,8 @@
 #define PIN_PD23__ISC_FIELD		PINMUX_PIN(PIN_PD23, 6, 4)
 #define PIN_PD24			120
 #define PIN_PD24__GPIO			PINMUX_PIN(PIN_PD24, 0, 0)
-#define PIN_PD24__UTXD2			PINMUX_PIN(PIN_PD23, 1, 2)
-#define PIN_PD24__FLEXCOM4_IO3		PINMUX_PIN(PIN_PD23, 3, 3)
+#define PIN_PD24__UTXD2			PINMUX_PIN(PIN_PD24, 1, 2)
+#define PIN_PD24__FLEXCOM4_IO3		PINMUX_PIN(PIN_PD24, 3, 3)
 #define PIN_PD25			121
 #define PIN_PD25__GPIO			PINMUX_PIN(PIN_PD25, 0, 0)
 #define PIN_PD25__SPI1_SPCK		PINMUX_PIN(PIN_PD25, 1, 3)
--- linux-4.4.0.orig/arch/arm/boot/dts/sama5d2.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sama5d2.dtsi
@@ -856,6 +856,13 @@
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xf801c000 0x100>;
 				interrupts = <24 IRQ_TYPE_LEVEL_HIGH 7>;
+				dmas = <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(35))>,
+				       <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(36))>;
+				dma-names = "tx", "rx";
 				clocks = <&uart0_clk>;
 				clock-names = "usart";
 				status = "disabled";
@@ -865,6 +872,13 @@
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xf8020000 0x100>;
 				interrupts = <25 IRQ_TYPE_LEVEL_HIGH 7>;
+				dmas = <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(37))>,
+				       <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(38))>;
+				dma-names = "tx", "rx";
 				clocks = <&uart1_clk>;
 				clock-names = "usart";
 				status = "disabled";
@@ -874,6 +888,13 @@
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xf8024000 0x100>;
 				interrupts = <26 IRQ_TYPE_LEVEL_HIGH 7>;
+				dmas = <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(39))>,
+				       <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(40))>;
+				dma-names = "tx", "rx";
 				clocks = <&uart2_clk>;
 				clock-names = "usart";
 				status = "disabled";
@@ -985,6 +1006,13 @@
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfc008000 0x100>;
 				interrupts = <27 IRQ_TYPE_LEVEL_HIGH 7>;
+				dmas = <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(41))>,
+				       <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(42))>;
+				dma-names = "tx", "rx";
 				clocks = <&uart3_clk>;
 				clock-names = "usart";
 				status = "disabled";
@@ -993,6 +1021,13 @@
 			uart4: serial@fc00c000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfc00c000 0x100>;
+				dmas = <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(43))>,
+				       <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+					 AT91_XDMAC_DT_PERID(44))>;
+				dma-names = "tx", "rx";
 				interrupts = <28 IRQ_TYPE_LEVEL_HIGH 7>;
 				clocks = <&uart4_clk>;
 				clock-names = "usart";
--- linux-4.4.0.orig/arch/arm/boot/dts/sama5d3.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sama5d3.dtsi
@@ -1106,49 +1106,49 @@
 					usart0_clk: usart0_clk {
 						#clock-cells = <0>;
 						reg = <12>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					usart1_clk: usart1_clk {
 						#clock-cells = <0>;
 						reg = <13>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					usart2_clk: usart2_clk {
 						#clock-cells = <0>;
 						reg = <14>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					usart3_clk: usart3_clk {
 						#clock-cells = <0>;
 						reg = <15>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					uart0_clk: uart0_clk {
 						#clock-cells = <0>;
 						reg = <16>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					twi0_clk: twi0_clk {
 						reg = <18>;
 						#clock-cells = <0>;
-						atmel,clk-output-range = <0 16625000>;
+						atmel,clk-output-range = <0 41500000>;
 					};
 
 					twi1_clk: twi1_clk {
 						#clock-cells = <0>;
 						reg = <19>;
-						atmel,clk-output-range = <0 16625000>;
+						atmel,clk-output-range = <0 41500000>;
 					};
 
 					twi2_clk: twi2_clk {
 						#clock-cells = <0>;
 						reg = <20>;
-						atmel,clk-output-range = <0 16625000>;
+						atmel,clk-output-range = <0 41500000>;
 					};
 
 					mci0_clk: mci0_clk {
@@ -1164,19 +1164,19 @@
 					spi0_clk: spi0_clk {
 						#clock-cells = <0>;
 						reg = <24>;
-						atmel,clk-output-range = <0 133000000>;
+						atmel,clk-output-range = <0 166000000>;
 					};
 
 					spi1_clk: spi1_clk {
 						#clock-cells = <0>;
 						reg = <25>;
-						atmel,clk-output-range = <0 133000000>;
+						atmel,clk-output-range = <0 166000000>;
 					};
 
 					tcb0_clk: tcb0_clk {
 						#clock-cells = <0>;
 						reg = <26>;
-						atmel,clk-output-range = <0 133000000>;
+						atmel,clk-output-range = <0 166000000>;
 					};
 
 					pwm_clk: pwm_clk {
@@ -1187,7 +1187,7 @@
 					adc_clk: adc_clk {
 						#clock-cells = <0>;
 						reg = <29>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					dma0_clk: dma0_clk {
@@ -1218,13 +1218,13 @@
 					ssc0_clk: ssc0_clk {
 						#clock-cells = <0>;
 						reg = <38>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					ssc1_clk: ssc1_clk {
 						#clock-cells = <0>;
 						reg = <39>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					sha_clk: sha_clk {
--- linux-4.4.0.orig/arch/arm/boot/dts/sama5d3_can.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sama5d3_can.dtsi
@@ -37,13 +37,13 @@
 					can0_clk: can0_clk {
 						#clock-cells = <0>;
 						reg = <40>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					can1_clk: can1_clk {
 						#clock-cells = <0>;
 						reg = <41>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 				};
 			};
--- linux-4.4.0.orig/arch/arm/boot/dts/sama5d3_emac.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sama5d3_emac.dtsi
@@ -41,7 +41,7 @@
 			};
 
 			macb1: ethernet@f802c000 {
-				compatible = "cdns,at91sam9260-macb", "cdns,macb";
+				compatible = "atmel,sama5d3-macb", "cdns,at91sam9260-macb", "cdns,macb";
 				reg = <0xf802c000 0x100>;
 				interrupts = <35 IRQ_TYPE_LEVEL_HIGH 3>;
 				pinctrl-names = "default";
--- linux-4.4.0.orig/arch/arm/boot/dts/sama5d3_tcb1.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sama5d3_tcb1.dtsi
@@ -23,6 +23,7 @@
 					tcb1_clk: tcb1_clk {
 						#clock-cells = <0>;
 						reg = <27>;
+						atmel,clk-output-range = <0 166000000>;
 					};
 				};
 			};
--- linux-4.4.0.orig/arch/arm/boot/dts/sama5d3_uart.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sama5d3_uart.dtsi
@@ -42,13 +42,13 @@
 					uart0_clk: uart0_clk {
 						#clock-cells = <0>;
 						reg = <16>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 
 					uart1_clk: uart1_clk {
 						#clock-cells = <0>;
 						reg = <17>;
-						atmel,clk-output-range = <0 66000000>;
+						atmel,clk-output-range = <0 83000000>;
 					};
 				};
 			};
--- linux-4.4.0.orig/arch/arm/boot/dts/sama5d4.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sama5d4.dtsi
@@ -1342,7 +1342,7 @@
 			dbgu: serial@fc069000 {
 				compatible = "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart";
 				reg = <0xfc069000 0x200>;
-				interrupts = <2 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts = <45 IRQ_TYPE_LEVEL_HIGH 7>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				clocks = <&dbgu_clk>;
@@ -1354,7 +1354,7 @@
 			pinctrl@fc06a000 {
 				#address-cells = <1>;
 				#size-cells = <1>;
-				compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+				compatible = "atmel,sama5d3-pinctrl", "atmel,at91sam9x5-pinctrl", "simple-bus";
 				ranges = <0xfc068000 0xfc068000 0x100
 					  0xfc06a000 0xfc06a000 0x4000>;
 				/* WARNING: revisit as pin spec has changed */
--- linux-4.4.0.orig/arch/arm/boot/dts/socfpga.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/socfpga.dtsi
@@ -738,7 +738,7 @@
 		timer@fffec600 {
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xfffec600 0x100>;
-			interrupts = <1 13 0xf04>;
+			interrupts = <1 13 0xf01>;
 			clocks = <&mpu_periph_clk>;
 		};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/socfpga_arria10.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/socfpga_arria10.dtsi
@@ -652,7 +652,7 @@
 		timer3: timer3@ffd00100 {
 			compatible = "snps,dw-apb-timer";
 			interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>;
-			reg = <0xffd01000 0x100>;
+			reg = <0xffd00100 0x100>;
 			clocks = <&l4_sys_free_clk>;
 			clock-names = "timer";
 		};
--- linux-4.4.0.orig/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts
+++ linux-4.4.0/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts
@@ -88,7 +88,7 @@
 	status = "okay";
 	speed-mode = <0>;
 
-	adxl345: adxl345@0 {
+	adxl345: adxl345@53 {
 		compatible = "adi,adxl345";
 		reg = <0x53>;
 
--- linux-4.4.0.orig/arch/arm/boot/dts/spear1310-evb.dts
+++ linux-4.4.0/arch/arm/boot/dts/spear1310-evb.dts
@@ -349,7 +349,7 @@
 			spi0: spi@e0100000 {
 				status = "okay";
 				num-cs = <3>;
-				cs-gpios = <&gpio1 7 0>, <&spics 0>, <&spics 1>;
+				cs-gpios = <&gpio1 7 0>, <&spics 0 0>, <&spics 1 0>;
 
 				stmpe610@0 {
 					compatible = "st,stmpe610";
--- linux-4.4.0.orig/arch/arm/boot/dts/spear1340.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/spear1340.dtsi
@@ -141,8 +141,8 @@
 				reg = <0xb4100000 0x1000>;
 				interrupts = <0 105 0x4>;
 				status = "disabled";
-				dmas = <&dwdma0 0x600 0 0 1>, /* 0xC << 11 */
-					<&dwdma0 0x680 0 1 0>; /* 0xD << 7 */
+				dmas = <&dwdma0 12 0 1>,
+					<&dwdma0 13 1 0>;
 				dma-names = "tx", "rx";
 			};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/spear13xx.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/spear13xx.dtsi
@@ -100,7 +100,7 @@
 			reg = <0xb2800000 0x1000>;
 			interrupts = <0 29 0x4>;
 			status = "disabled";
-			dmas = <&dwdma0 0 0 0 0>;
+			dmas = <&dwdma0 0 0 0>;
 			dma-names = "data";
 		};
 
@@ -288,8 +288,8 @@
 				#size-cells = <0>;
 				interrupts = <0 31 0x4>;
 				status = "disabled";
-				dmas = <&dwdma0 0x2000 0 0 0>, /* 0x4 << 11 */
-					<&dwdma0 0x0280 0 0 0>;  /* 0x5 << 7 */
+				dmas = <&dwdma0 4 0 0>,
+					<&dwdma0 5 0 0>;
 				dma-names = "tx", "rx";
 			};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/spear600.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/spear600.dtsi
@@ -194,6 +194,7 @@
 			rtc@fc900000 {
 				compatible = "st,spear600-rtc";
 				reg = <0xfc900000 0x1000>;
+				interrupt-parent = <&vic0>;
 				interrupts = <10>;
 				status = "disabled";
 			};
--- linux-4.4.0.orig/arch/arm/boot/dts/ste-dbx5x0.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/ste-dbx5x0.dtsi
@@ -186,7 +186,7 @@
 			      <0xa0410100 0x100>;
 		};
 
-		scu@a04100000 {
+		scu@a0410000 {
 			compatible = "arm,cortex-a9-scu";
 			reg = <0xa0410000 0x100>;
 		};
@@ -894,7 +894,7 @@
 			power-domains = <&pm_domains DOMAIN_VAPE>;
 		};
 
-		ssp@80002000 {
+		spi@80002000 {
 			compatible = "arm,pl022", "arm,primecell";
 			reg = <0x80002000 0x1000>;
 			interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>;
@@ -908,7 +908,7 @@
 			power-domains = <&pm_domains DOMAIN_VAPE>;
 		};
 
-		ssp@80003000 {
+		spi@80003000 {
 			compatible = "arm,pl022", "arm,primecell";
 			reg = <0x80003000 0x1000>;
 			interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>;
--- linux-4.4.0.orig/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi
@@ -607,16 +607,20 @@
 
 			mcde {
 				lcd_default_mode: lcd_default {
-					default_mux {
+					default_mux1 {
 						/* Mux in VSI0 and all the data lines */
 						function = "lcd";
 						groups =
 						"lcdvsi0_a_1", /* VSI0 for LCD */
 						"lcd_d0_d7_a_1", /* Data lines */
 						"lcd_d8_d11_a_1", /* TV-out */
-						"lcdaclk_b_1", /* Clock line for TV-out */
 						"lcdvsi1_a_1"; /* VSI1 for HDMI */
 					};
+					default_mux2 {
+						function = "lcda";
+						groups =
+						"lcdaclk_b_1"; /* Clock line for TV-out */
+					};
 					default_cfg1 {
 						pins =
 						"GPIO68_E1", /* VSI0 */
--- linux-4.4.0.orig/arch/arm/boot/dts/ste-hrefprev60.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/ste-hrefprev60.dtsi
@@ -57,7 +57,7 @@
 			};
 		};
 
-		ssp@80002000 {
+		spi@80002000 {
 			/*
 			 * On the first generation boards, this SSP/SPI port was connected
 			 * to the AB8500.
--- linux-4.4.0.orig/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
@@ -127,22 +127,14 @@
 			};
 			mmcsd_default_mode: mmcsd_default {
 				mmcsd_default_cfg1 {
-					/* MCCLK */
-					pins = "GPIO8_B10";
-					ste,output = <0>;
-				};
-				mmcsd_default_cfg2 {
-					/* MCCMDDIR, MCDAT0DIR, MCDAT31DIR, MCDATDIR2 */
-					pins = "GPIO10_C11", "GPIO15_A12",
-					"GPIO16_C13", "GPIO23_D15";
-					ste,output = <1>;
-				};
-				mmcsd_default_cfg3 {
-					/* MCCMD, MCDAT3-0, MCMSFBCLK */
-					pins = "GPIO9_A10", "GPIO11_B11",
-					"GPIO12_A11", "GPIO13_C12",
-					"GPIO14_B12", "GPIO24_C15";
-					ste,input = <1>;
+					/*
+					 * MCCLK, MCCMDDIR, MCDAT0DIR, MCDAT31DIR, MCDATDIR2
+					 * MCCMD, MCDAT3-0, MCMSFBCLK
+					 */
+					pins = "GPIO8_B10", "GPIO9_A10", "GPIO10_C11", "GPIO11_B11",
+					       "GPIO12_A11", "GPIO13_C12", "GPIO14_B12", "GPIO15_A12",
+					       "GPIO16_C13", "GPIO23_D15", "GPIO24_C15";
+					ste,output = <2>;
 				};
 			};
 		};
@@ -802,10 +794,21 @@
 			clock-names = "mclk", "apb_pclk";
 			interrupt-parent = <&vica>;
 			interrupts = <22>;
-			max-frequency = <48000000>;
+			max-frequency = <400000>;
 			bus-width = <4>;
 			cap-mmc-highspeed;
 			cap-sd-highspeed;
+			full-pwr-cycle;
+			/*
+			 * The STw4811 circuit used with the Nomadik strictly
+			 * requires that all of these signal direction pins be
+			 * routed and used for its 4-bit levelshifter.
+			 */
+			st,sig-dir-dat0;
+			st,sig-dir-dat2;
+			st,sig-dir-dat31;
+			st,sig-dir-cmd;
+			st,sig-pin-fbclk;
 			pinctrl-names = "default";
 			pinctrl-0 = <&mmcsd_default_mux>, <&mmcsd_default_mode>;
 			vmmc-supply = <&vmmc_regulator>;
--- linux-4.4.0.orig/arch/arm/boot/dts/ste-snowball.dts
+++ linux-4.4.0/arch/arm/boot/dts/ste-snowball.dts
@@ -311,7 +311,7 @@
 			pinctrl-1 = <&i2c3_sleep_mode>;
 		};
 
-		ssp@80002000 {
+		spi@80002000 {
 			pinctrl-names = "default";
 			pinctrl-0 = <&ssp0_snowball_mode>;
 		};
--- linux-4.4.0.orig/arch/arm/boot/dts/ste-u300.dts
+++ linux-4.4.0/arch/arm/boot/dts/ste-u300.dts
@@ -451,7 +451,7 @@
 			dma-names = "rx";
 		};
 
-		spi: ssp@c0006000 {
+		spi: spi@c0006000 {
 			compatible = "arm,pl022", "arm,primecell";
 			reg = <0xc0006000 0x1000>;
 			interrupt-parent = <&vica>;
--- linux-4.4.0.orig/arch/arm/boot/dts/stih407-family.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/stih407-family.dtsi
@@ -497,8 +497,9 @@
 			interrupt-names = "mmcirq";
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_mmc0>;
-			clock-names = "mmc";
-			clocks = <&clk_s_c0_flexgen CLK_MMC_0>;
+			clock-names = "mmc", "icn";
+			clocks = <&clk_s_c0_flexgen CLK_MMC_0>,
+				 <&clk_s_c0_flexgen CLK_RX_ICN_HVA>;
 			bus-width = <8>;
 			non-removable;
 		};
@@ -512,8 +513,9 @@
 			interrupt-names = "mmcirq";
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_sd1>;
-			clock-names = "mmc";
-			clocks = <&clk_s_c0_flexgen CLK_MMC_1>;
+			clock-names = "mmc", "icn";
+			clocks = <&clk_s_c0_flexgen CLK_MMC_1>,
+				 <&clk_s_c0_flexgen CLK_RX_ICN_HVA>;
 			resets = <&softreset STIH407_MMC1_SOFTRESET>;
 			bus-width = <4>;
 		};
--- linux-4.4.0.orig/arch/arm/boot/dts/stih407.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/stih407.dtsi
@@ -8,6 +8,7 @@
  */
 #include "stih407-clock.dtsi"
 #include "stih407-family.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 / {
 	soc {
 		sti-display-subsystem {
@@ -112,7 +113,7 @@
 					 <&clk_s_d2_quadfs 0>,
 					 <&clk_s_d2_quadfs 1>;
 
-				hdmi,hpd-gpio = <&pio5 3>;
+				hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>;
 				reset-names = "hdmi";
 				resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
 				ddc = <&hdmiddc>;
--- linux-4.4.0.orig/arch/arm/boot/dts/stih410.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/stih410.dtsi
@@ -9,6 +9,7 @@
 #include "stih410-clock.dtsi"
 #include "stih407-family.dtsi"
 #include "stih410-pinctrl.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 / {
 	aliases {
 		bdisp0 = &bdisp0;
@@ -41,7 +42,8 @@
 			compatible = "st,st-ohci-300x";
 			reg = <0x9a03c00 0x100>;
 			interrupts = <GIC_SPI 180 IRQ_TYPE_NONE>;
-			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+				 <&clk_s_c0_flexgen CLK_RX_ICN_DISP_0>;
 			resets = <&powerdown STIH407_USB2_PORT0_POWERDOWN>,
 				 <&softreset STIH407_USB2_PORT0_SOFTRESET>;
 			reset-names = "power", "softreset";
@@ -57,7 +59,8 @@
 			interrupts = <GIC_SPI 151 IRQ_TYPE_NONE>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_usb0>;
-			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+				 <&clk_s_c0_flexgen CLK_RX_ICN_DISP_0>;
 			resets = <&powerdown STIH407_USB2_PORT0_POWERDOWN>,
 				 <&softreset STIH407_USB2_PORT0_SOFTRESET>;
 			reset-names = "power", "softreset";
@@ -71,7 +74,8 @@
 			compatible = "st,st-ohci-300x";
 			reg = <0x9a83c00 0x100>;
 			interrupts = <GIC_SPI 181 IRQ_TYPE_NONE>;
-			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+				 <&clk_s_c0_flexgen CLK_RX_ICN_DISP_0>;
 			resets = <&powerdown STIH407_USB2_PORT1_POWERDOWN>,
 				 <&softreset STIH407_USB2_PORT1_SOFTRESET>;
 			reset-names = "power", "softreset";
@@ -87,7 +91,8 @@
 			interrupts = <GIC_SPI 153 IRQ_TYPE_NONE>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_usb1>;
-			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+				 <&clk_s_c0_flexgen CLK_RX_ICN_DISP_0>;
 			resets = <&powerdown STIH407_USB2_PORT1_POWERDOWN>,
 				 <&softreset STIH407_USB2_PORT1_SOFTRESET>;
 			reset-names = "power", "softreset";
@@ -199,7 +204,7 @@
 					 <&clk_s_d2_quadfs 0>,
 					 <&clk_s_d2_quadfs 1>;
 
-				hdmi,hpd-gpio = <&pio5 3>;
+				hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>;
 				reset-names = "hdmi";
 				resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
 				ddc = <&hdmiddc>;
--- linux-4.4.0.orig/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ linux-4.4.0/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -84,6 +84,7 @@
 		regulator-name = "emac-3v3";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <20000>;
 		enable-active-high;
 		gpio = <&pio 7 15 GPIO_ACTIVE_HIGH>;
 	};
--- linux-4.4.0.orig/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+++ linux-4.4.0/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -66,6 +66,7 @@
 		regulator-name = "emac-3v3";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <20000>;
 		enable-active-high;
 		gpio = <&pio 7 19 GPIO_ACTIVE_HIGH>;
 	};
--- linux-4.4.0.orig/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
+++ linux-4.4.0/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
@@ -80,6 +80,7 @@
 		regulator-name = "emac-3v3";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <20000>;
 		enable-active-high;
 		gpio = <&pio 7 19 GPIO_ACTIVE_HIGH>;   /* PH19 */
 	};
--- linux-4.4.0.orig/arch/arm/boot/dts/sun4i-a10.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -137,7 +137,7 @@
 			trips {
 				cpu_alert0: cpu_alert0 {
 					/* milliCelsius */
-					temperature = <850000>;
+					temperature = <85000>;
 					hysteresis = <2000>;
 					type = "passive";
 				};
--- linux-4.4.0.orig/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts
+++ linux-4.4.0/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts
@@ -79,6 +79,7 @@
 		regulator-name = "emac-3v3";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <20000>;
 		enable-active-high;
 		gpio = <&pio 0 2 GPIO_ACTIVE_HIGH>;
 	};
--- linux-4.4.0.orig/arch/arm/boot/dts/sun5i-a13.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -83,7 +83,7 @@
 			trips {
 				cpu_alert0: cpu_alert0 {
 					/* milliCelsius */
-					temperature = <850000>;
+					temperature = <85000>;
 					hysteresis = <2000>;
 					type = "passive";
 				};
--- linux-4.4.0.orig/arch/arm/boot/dts/sun5i-r8-chip.dts
+++ linux-4.4.0/arch/arm/boot/dts/sun5i-r8-chip.dts
@@ -52,7 +52,7 @@
 
 / {
 	model = "NextThing C.H.I.P.";
-	compatible = "nextthing,chip", "allwinner,sun5i-r8";
+	compatible = "nextthing,chip", "allwinner,sun5i-r8", "allwinner,sun5i-a13";
 
 	aliases {
 		i2c0 = &i2c0;
--- linux-4.4.0.orig/arch/arm/boot/dts/sun6i-a31.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -167,7 +167,7 @@
 	};
 
 	pmu {
-		compatible = "arm,cortex-a7-pmu", "arm,cortex-a15-pmu";
+		compatible = "arm,cortex-a7-pmu";
 		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
--- linux-4.4.0.orig/arch/arm/boot/dts/sun7i-a20.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -167,7 +167,7 @@
 	};
 
 	pmu {
-		compatible = "arm,cortex-a7-pmu", "arm,cortex-a15-pmu";
+		compatible = "arm,cortex-a7-pmu";
 		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
 	};
--- linux-4.4.0.orig/arch/arm/boot/dts/tegra20-paz00.dts
+++ linux-4.4.0/arch/arm/boot/dts/tegra20-paz00.dts
@@ -565,6 +565,7 @@
 			regulator-name = "+3VS,vdd_pnl";
 			regulator-min-microvolt = <3300000>;
 			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
 			gpio = <&gpio TEGRA_GPIO(A, 4) GPIO_ACTIVE_HIGH>;
 			enable-active-high;
 		};
--- linux-4.4.0.orig/arch/arm/boot/dts/tegra30-apalis.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/tegra30-apalis.dtsi
@@ -147,14 +147,14 @@
 
 			/* Apalis MMC1 */
 			sdmmc3_clk_pa6 {
-				nvidia,pins = "sdmmc3_clk_pa6",
-					      "sdmmc3_cmd_pa7";
+				nvidia,pins = "sdmmc3_clk_pa6";
 				nvidia,function = "sdmmc3";
 				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
 				nvidia,tristate = <TEGRA_PIN_DISABLE>;
 			};
 			sdmmc3_dat0_pb7 {
-				nvidia,pins = "sdmmc3_dat0_pb7",
+				nvidia,pins = "sdmmc3_cmd_pa7",
+					      "sdmmc3_dat0_pb7",
 					      "sdmmc3_dat1_pb6",
 					      "sdmmc3_dat2_pb5",
 					      "sdmmc3_dat3_pb4",
--- linux-4.4.0.orig/arch/arm/boot/dts/tegra30-cardhu.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/tegra30-cardhu.dtsi
@@ -201,6 +201,7 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0x70>;
+			reset-gpio = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_LOW>;
 		};
 	};
 
--- linux-4.4.0.orig/arch/arm/boot/dts/tegra30.dtsi
+++ linux-4.4.0/arch/arm/boot/dts/tegra30.dtsi
@@ -823,7 +823,7 @@
 		nvidia,elastic-limit = <16>;
 		nvidia,term-range-adj = <6>;
 		nvidia,xcvr-setup = <51>;
-		nvidia.xcvr-setup-use-fuses;
+		nvidia,xcvr-setup-use-fuses;
 		nvidia,xcvr-lsfslew = <1>;
 		nvidia,xcvr-lsrslew = <1>;
 		nvidia,xcvr-hsslew = <32>;
@@ -860,7 +860,7 @@
 		nvidia,elastic-limit = <16>;
 		nvidia,term-range-adj = <6>;
 		nvidia,xcvr-setup = <51>;
-		nvidia.xcvr-setup-use-fuses;
+		nvidia,xcvr-setup-use-fuses;
 		nvidia,xcvr-lsfslew = <2>;
 		nvidia,xcvr-lsrslew = <2>;
 		nvidia,xcvr-hsslew = <32>;
@@ -896,7 +896,7 @@
 		nvidia,elastic-limit = <16>;
 		nvidia,term-range-adj = <6>;
 		nvidia,xcvr-setup = <51>;
-		nvidia.xcvr-setup-use-fuses;
+		nvidia,xcvr-setup-use-fuses;
 		nvidia,xcvr-lsfslew = <2>;
 		nvidia,xcvr-lsrslew = <2>;
 		nvidia,xcvr-hsslew = <32>;
--- linux-4.4.0.orig/arch/arm/common/icst.c
+++ linux-4.4.0/arch/arm/common/icst.c
@@ -16,7 +16,7 @@
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
-
+#include <asm/div64.h>
 #include <asm/hardware/icst.h>
 
 /*
@@ -29,7 +29,11 @@
 
 unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco)
 {
-	return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * p->s2div[vco.s]);
+	u64 dividend = p->ref * 2 * (u64)(vco.v + 8);
+	u32 divisor = (vco.r + 2) * p->s2div[vco.s];
+
+	do_div(dividend, divisor);
+	return (unsigned long)dividend;
 }
 
 EXPORT_SYMBOL(icst_hz);
@@ -58,6 +62,7 @@
 
 		if (f > p->vco_min && f <= p->vco_max)
 			break;
+		i++;
 	} while (i < 8);
 
 	if (i >= 8)
--- linux-4.4.0.orig/arch/arm/common/mcpm_entry.c
+++ linux-4.4.0/arch/arm/common/mcpm_entry.c
@@ -379,7 +379,7 @@
 	unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 	phys_reset_t phys_reset;
 
-	mcpm_set_entry_vector(cpu, cluster, cpu_resume);
+	mcpm_set_entry_vector(cpu, cluster, cpu_resume_no_hyp);
 	setup_mm_for_reboot();
 
 	__mcpm_cpu_going_down(cpu, cluster);
--- linux-4.4.0.orig/arch/arm/common/sa1111.c
+++ linux-4.4.0/arch/arm/common/sa1111.c
@@ -869,9 +869,9 @@
 
 #ifdef CONFIG_PM
 
-static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
+static int sa1111_suspend_noirq(struct device *dev)
 {
-	struct sa1111 *sachip = platform_get_drvdata(dev);
+	struct sa1111 *sachip = dev_get_drvdata(dev);
 	struct sa1111_save_data *save;
 	unsigned long flags;
 	unsigned int val;
@@ -934,9 +934,9 @@
  *	restored by their respective drivers, and must be called
  *	via LDM after this function.
  */
-static int sa1111_resume(struct platform_device *dev)
+static int sa1111_resume_noirq(struct device *dev)
 {
-	struct sa1111 *sachip = platform_get_drvdata(dev);
+	struct sa1111 *sachip = dev_get_drvdata(dev);
 	struct sa1111_save_data *save;
 	unsigned long flags, id;
 	void __iomem *base;
@@ -952,7 +952,7 @@
 	id = sa1111_readl(sachip->base + SA1111_SKID);
 	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
 		__sa1111_remove(sachip);
-		platform_set_drvdata(dev, NULL);
+		dev_set_drvdata(dev, NULL);
 		kfree(save);
 		return 0;
 	}
@@ -1003,8 +1003,8 @@
 }
 
 #else
-#define sa1111_suspend NULL
-#define sa1111_resume  NULL
+#define sa1111_suspend_noirq NULL
+#define sa1111_resume_noirq  NULL
 #endif
 
 static int sa1111_probe(struct platform_device *pdev)
@@ -1038,6 +1038,11 @@
 	return 0;
 }
 
+static struct dev_pm_ops sa1111_pm_ops = {
+	.suspend_noirq = sa1111_suspend_noirq,
+	.resume_noirq = sa1111_resume_noirq,
+};
+
 /*
  *	Not sure if this should be on the system bus or not yet.
  *	We really want some way to register a system device at
@@ -1050,10 +1055,9 @@
 static struct platform_driver sa1111_device_driver = {
 	.probe		= sa1111_probe,
 	.remove		= sa1111_remove,
-	.suspend	= sa1111_suspend,
-	.resume		= sa1111_resume,
 	.driver		= {
 		.name	= "sa1111",
+		.pm	= &sa1111_pm_ops,
 	},
 };
 
--- linux-4.4.0.orig/arch/arm/configs/badge4_defconfig
+++ linux-4.4.0/arch/arm/configs/badge4_defconfig
@@ -97,7 +97,6 @@
 CONFIG_USB_SERIAL_CYBERJACK=m
 CONFIG_USB_SERIAL_XIRCOM=m
 CONFIG_USB_SERIAL_OMNINET=m
-CONFIG_USB_RIO500=m
 CONFIG_EXT2_FS=m
 CONFIG_EXT3_FS=m
 CONFIG_MSDOS_FS=y
--- linux-4.4.0.orig/arch/arm/configs/corgi_defconfig
+++ linux-4.4.0/arch/arm/configs/corgi_defconfig
@@ -207,7 +207,6 @@
 CONFIG_USB_SERIAL_OMNINET=m
 CONFIG_USB_EMI62=m
 CONFIG_USB_EMI26=m
-CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
 CONFIG_USB_LED=m
--- linux-4.4.0.orig/arch/arm/configs/imx_v4_v5_defconfig
+++ linux-4.4.0/arch/arm/configs/imx_v4_v5_defconfig
@@ -145,9 +145,11 @@
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_UDC=y
 CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_CHIPIDEA_ULPI=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
+CONFIG_USB_ULPI_BUS=y
 CONFIG_MMC=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
--- linux-4.4.0.orig/arch/arm/configs/omap2plus_defconfig
+++ linux-4.4.0/arch/arm/configs/omap2plus_defconfig
@@ -221,6 +221,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=6
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
--- linux-4.4.0.orig/arch/arm/configs/s3c2410_defconfig
+++ linux-4.4.0/arch/arm/configs/s3c2410_defconfig
@@ -87,9 +87,9 @@
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
@@ -354,7 +354,6 @@
 CONFIG_USB_EMI26=m
 CONFIG_USB_ADUTUX=m
 CONFIG_USB_SEVSEG=m
-CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
 CONFIG_USB_LED=m
--- linux-4.4.0.orig/arch/arm/configs/spitz_defconfig
+++ linux-4.4.0/arch/arm/configs/spitz_defconfig
@@ -202,7 +202,6 @@
 CONFIG_USB_SERIAL_OMNINET=m
 CONFIG_USB_EMI62=m
 CONFIG_USB_EMI26=m
-CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
 CONFIG_USB_LED=m
--- linux-4.4.0.orig/arch/arm/crypto/aes-ce-glue.c
+++ linux-4.4.0/arch/arm/crypto/aes-ce-glue.c
@@ -15,6 +15,7 @@
 #include <crypto/ablk_helper.h>
 #include <crypto/algapi.h>
 #include <linux/module.h>
+#include <crypto/xts.h>
 
 MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions");
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
@@ -87,8 +88,13 @@
 		u32 *rki = ctx->key_enc + (i * kwords);
 		u32 *rko = rki + kwords;
 
+#ifndef CONFIG_CPU_BIG_ENDIAN
 		rko[0] = ror32(ce_aes_sub(rki[kwords - 1]), 8);
 		rko[0] = rko[0] ^ rki[0] ^ rcon[i];
+#else
+		rko[0] = rol32(ce_aes_sub(rki[kwords - 1]), 8);
+		rko[0] = rko[0] ^ rki[0] ^ (rcon[i] << 24);
+#endif
 		rko[1] = rko[0] ^ rki[1];
 		rko[2] = rko[1] ^ rki[2];
 		rko[3] = rko[2] ^ rki[3];
@@ -152,6 +158,10 @@
 	struct crypto_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
 	int ret;
 
+	ret = xts_check_key(tfm, in_key, key_len);
+	if (ret)
+		return ret;
+
 	ret = ce_aes_expandkey(&ctx->key1, in_key, key_len / 2);
 	if (!ret)
 		ret = ce_aes_expandkey(&ctx->key2, &in_key[key_len / 2],
@@ -279,7 +289,7 @@
 		err = blkcipher_walk_done(desc, &walk,
 					  walk.nbytes % AES_BLOCK_SIZE);
 	}
-	if (nbytes) {
+	if (walk.nbytes % AES_BLOCK_SIZE) {
 		u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE;
 		u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE;
 		u8 __aligned(8) tail[AES_BLOCK_SIZE];
--- linux-4.4.0.orig/arch/arm/crypto/aesbs-glue.c
+++ linux-4.4.0/arch/arm/crypto/aesbs-glue.c
@@ -13,6 +13,7 @@
 #include <crypto/ablk_helper.h>
 #include <crypto/algapi.h>
 #include <linux/module.h>
+#include <crypto/xts.h>
 
 #include "aes_glue.h"
 
@@ -89,6 +90,11 @@
 {
 	struct aesbs_xts_ctx *ctx = crypto_tfm_ctx(tfm);
 	int bits = key_len * 4;
+	int err;
+
+	err = xts_check_key(tfm, in_key, key_len);
+	if (err)
+		return err;
 
 	if (private_AES_set_encrypt_key(in_key, bits, &ctx->enc.rk)) {
 		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
@@ -259,6 +265,8 @@
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
+	if (err)
+		return err;
 
 	/* generate the initial tweak */
 	AES_encrypt(walk.iv, walk.iv, &ctx->twkey);
@@ -283,6 +291,8 @@
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
+	if (err)
+		return err;
 
 	/* generate the initial tweak */
 	AES_encrypt(walk.iv, walk.iv, &ctx->twkey);
@@ -357,7 +367,7 @@
 }, {
 	.cra_name		= "cbc(aes)",
 	.cra_driver_name	= "cbc-aes-neonbs",
-	.cra_priority		= 300,
+	.cra_priority		= 250,
 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
 	.cra_blocksize		= AES_BLOCK_SIZE,
 	.cra_ctxsize		= sizeof(struct async_helper_ctx),
@@ -377,7 +387,7 @@
 }, {
 	.cra_name		= "ctr(aes)",
 	.cra_driver_name	= "ctr-aes-neonbs",
-	.cra_priority		= 300,
+	.cra_priority		= 250,
 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
 	.cra_blocksize		= 1,
 	.cra_ctxsize		= sizeof(struct async_helper_ctx),
@@ -397,7 +407,7 @@
 }, {
 	.cra_name		= "xts(aes)",
 	.cra_driver_name	= "xts-aes-neonbs",
-	.cra_priority		= 300,
+	.cra_priority		= 250,
 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
 	.cra_blocksize		= AES_BLOCK_SIZE,
 	.cra_ctxsize		= sizeof(struct async_helper_ctx),
--- linux-4.4.0.orig/arch/arm/crypto/ghash-ce-glue.c
+++ linux-4.4.0/arch/arm/crypto/ghash-ce-glue.c
@@ -226,6 +226,27 @@
 	}
 }
 
+static int ghash_async_import(struct ahash_request *req, const void *in)
+{
+	struct ahash_request *cryptd_req = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+
+	desc->tfm = cryptd_ahash_child(ctx->cryptd_tfm);
+	desc->flags = req->base.flags;
+
+	return crypto_shash_import(desc, in);
+}
+
+static int ghash_async_export(struct ahash_request *req, void *out)
+{
+	struct ahash_request *cryptd_req = ahash_request_ctx(req);
+	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+
+	return crypto_shash_export(desc, out);
+}
+
 static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
 			      unsigned int keylen)
 {
@@ -274,7 +295,10 @@
 	.final			= ghash_async_final,
 	.setkey			= ghash_async_setkey,
 	.digest			= ghash_async_digest,
+	.import			= ghash_async_import,
+	.export			= ghash_async_export,
 	.halg.digestsize	= GHASH_DIGEST_SIZE,
+	.halg.statesize		= sizeof(struct ghash_desc_ctx),
 	.halg.base		= {
 		.cra_name	= "ghash",
 		.cra_driver_name = "ghash-ce",
--- linux-4.4.0.orig/arch/arm/crypto/sha256-armv4.pl
+++ linux-4.4.0/arch/arm/crypto/sha256-armv4.pl
@@ -205,10 +205,11 @@
 .global	sha256_block_data_order
 .type	sha256_block_data_order,%function
 sha256_block_data_order:
+.Lsha256_block_data_order:
 #if __ARM_ARCH__<7
 	sub	r3,pc,#8		@ sha256_block_data_order
 #else
-	adr	r3,sha256_block_data_order
+	adr	r3,.Lsha256_block_data_order
 #endif
 #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
 	ldr	r12,.LOPENSSL_armcap
--- linux-4.4.0.orig/arch/arm/crypto/sha256-core.S_shipped
+++ linux-4.4.0/arch/arm/crypto/sha256-core.S_shipped
@@ -86,10 +86,11 @@
 .global	sha256_block_data_order
 .type	sha256_block_data_order,%function
 sha256_block_data_order:
+.Lsha256_block_data_order:
 #if __ARM_ARCH__<7
 	sub	r3,pc,#8		@ sha256_block_data_order
 #else
-	adr	r3,sha256_block_data_order
+	adr	r3,.Lsha256_block_data_order
 #endif
 #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
 	ldr	r12,.LOPENSSL_armcap
--- linux-4.4.0.orig/arch/arm/crypto/sha512-armv4.pl
+++ linux-4.4.0/arch/arm/crypto/sha512-armv4.pl
@@ -267,10 +267,11 @@
 .global	sha512_block_data_order
 .type	sha512_block_data_order,%function
 sha512_block_data_order:
+.Lsha512_block_data_order:
 #if __ARM_ARCH__<7
 	sub	r3,pc,#8		@ sha512_block_data_order
 #else
-	adr	r3,sha512_block_data_order
+	adr	r3,.Lsha512_block_data_order
 #endif
 #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
 	ldr	r12,.LOPENSSL_armcap
--- linux-4.4.0.orig/arch/arm/crypto/sha512-core.S_shipped
+++ linux-4.4.0/arch/arm/crypto/sha512-core.S_shipped
@@ -134,10 +134,11 @@
 .global	sha512_block_data_order
 .type	sha512_block_data_order,%function
 sha512_block_data_order:
+.Lsha512_block_data_order:
 #if __ARM_ARCH__<7
 	sub	r3,pc,#8		@ sha512_block_data_order
 #else
-	adr	r3,sha512_block_data_order
+	adr	r3,.Lsha512_block_data_order
 #endif
 #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
 	ldr	r12,.LOPENSSL_armcap
--- linux-4.4.0.orig/arch/arm/include/asm/Kbuild
+++ linux-4.4.0/arch/arm/include/asm/Kbuild
@@ -36,4 +36,3 @@
 generic-y += termios.h
 generic-y += timex.h
 generic-y += trace_clock.h
-generic-y += unaligned.h
--- linux-4.4.0.orig/arch/arm/include/asm/arch_gicv3.h
+++ linux-4.4.0/arch/arm/include/asm/arch_gicv3.h
@@ -22,9 +22,7 @@
 
 #include <linux/io.h>
 #include <asm/barrier.h>
-
-#define __ACCESS_CP15(CRn, Op1, CRm, Op2)	p15, Op1, %0, CRn, CRm, Op2
-#define __ACCESS_CP15_64(Op1, CRm)		p15, Op1, %Q0, %R0, CRm
+#include <asm/cp15.h>
 
 #define ICC_EOIR1			__ACCESS_CP15(c12, 0, c12, 1)
 #define ICC_DIR				__ACCESS_CP15(c12, 0, c11, 1)
@@ -102,57 +100,55 @@
 
 static inline void gic_write_eoir(u32 irq)
 {
-	asm volatile("mcr " __stringify(ICC_EOIR1) : : "r" (irq));
+	write_sysreg(irq, ICC_EOIR1);
 	isb();
 }
 
 static inline void gic_write_dir(u32 val)
 {
-	asm volatile("mcr " __stringify(ICC_DIR) : : "r" (val));
+	write_sysreg(val, ICC_DIR);
 	isb();
 }
 
 static inline u32 gic_read_iar(void)
 {
-	u32 irqstat;
+	u32 irqstat = read_sysreg(ICC_IAR1);
+
+	dsb(sy);
 
-	asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat));
 	return irqstat;
 }
 
 static inline void gic_write_pmr(u32 val)
 {
-	asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val));
+	write_sysreg(val, ICC_PMR);
 }
 
 static inline void gic_write_ctlr(u32 val)
 {
-	asm volatile("mcr " __stringify(ICC_CTLR) : : "r" (val));
+	write_sysreg(val, ICC_CTLR);
 	isb();
 }
 
 static inline void gic_write_grpen1(u32 val)
 {
-	asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val));
+	write_sysreg(val, ICC_IGRPEN1);
 	isb();
 }
 
 static inline void gic_write_sgi1r(u64 val)
 {
-	asm volatile("mcrr " __stringify(ICC_SGI1R) : : "r" (val));
+	write_sysreg(val, ICC_SGI1R);
 }
 
 static inline u32 gic_read_sre(void)
 {
-	u32 val;
-
-	asm volatile("mrc " __stringify(ICC_SRE) : "=r" (val));
-	return val;
+	return read_sysreg(ICC_SRE);
 }
 
 static inline void gic_write_sre(u32 val)
 {
-	asm volatile("mcr " __stringify(ICC_SRE) : : "r" (val));
+	write_sysreg(val, ICC_SRE);
 	isb();
 }
 
--- linux-4.4.0.orig/arch/arm/include/asm/assembler.h
+++ linux-4.4.0/arch/arm/include/asm/assembler.h
@@ -441,11 +441,34 @@
 	.size \name , . - \name
 	.endm
 
+	.macro	csdb
+#ifdef CONFIG_THUMB2_KERNEL
+	.inst.w	0xf3af8014
+#else
+	.inst	0xe320f014
+#endif
+	.endm
+
 	.macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
 #ifndef CONFIG_CPU_USE_DOMAINS
 	adds	\tmp, \addr, #\size - 1
 	sbcccs	\tmp, \tmp, \limit
 	bcs	\bad
+#ifdef CONFIG_CPU_SPECTRE
+	movcs	\addr, #0
+	csdb
+#endif
+#endif
+	.endm
+
+	.macro uaccess_mask_range_ptr, addr:req, size:req, limit:req, tmp:req
+#ifdef CONFIG_CPU_SPECTRE
+	sub	\tmp, \limit, #1
+	subs	\tmp, \tmp, \addr	@ tmp = limit - 1 - addr
+	addhs	\tmp, \tmp, #1		@ if (tmp >= 0) {
+	subhss	\tmp, \tmp, \size	@ tmp = limit - (addr + size) }
+	movlo	\addr, #0		@ if (tmp < 0) addr = NULL
+	csdb
 #endif
 	.endm
 
@@ -512,4 +535,32 @@
 #endif
 	.endm
 
+	.macro	bug, msg, line
+#ifdef CONFIG_THUMB2_KERNEL
+1:	.inst	0xde02
+#else
+1:	.inst	0xe7f001f2
+#endif
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+	.pushsection .rodata.str, "aMS", %progbits, 1
+2:	.asciz	"\msg"
+	.popsection
+	.pushsection __bug_table, "aw"
+	.align	2
+	.word	1b, 2b
+	.hword	\line
+	.popsection
+#endif
+	.endm
+
+#ifdef CONFIG_KPROBES
+#define _ASM_NOKPROBE(entry)				\
+	.pushsection "_kprobe_blacklist", "aw" ;	\
+	.balign 4 ;					\
+	.long entry;					\
+	.popsection
+#else
+#define _ASM_NOKPROBE(entry)
+#endif
+
 #endif /* __ASM_ASSEMBLER_H__ */
--- linux-4.4.0.orig/arch/arm/include/asm/barrier.h
+++ linux-4.4.0/arch/arm/include/asm/barrier.h
@@ -10,12 +10,20 @@
 #define sev()	__asm__ __volatile__ ("sev" : : : "memory")
 #define wfe()	__asm__ __volatile__ ("wfe" : : : "memory")
 #define wfi()	__asm__ __volatile__ ("wfi" : : : "memory")
+#else
+#define wfe()	do { } while (0)
 #endif
 
 #if __LINUX_ARM_ARCH__ >= 7
 #define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory")
 #define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory")
 #define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory")
+#ifdef CONFIG_THUMB2_KERNEL
+#define CSDB	".inst.w 0xf3af8014"
+#else
+#define CSDB	".inst	0xe320f014"
+#endif
+#define csdb() __asm__ __volatile__(CSDB : : : "memory")
 #elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
 #define isb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
 				    : : "r" (0) : "memory")
@@ -36,6 +44,13 @@
 #define dmb(x) __asm__ __volatile__ ("" : : : "memory")
 #endif
 
+#ifndef CSDB
+#define CSDB
+#endif
+#ifndef csdb
+#define csdb()
+#endif
+
 #ifdef CONFIG_ARM_HEAVY_MB
 extern void (*soc_mb)(void);
 extern void arm_heavy_mb(void);
@@ -93,5 +108,26 @@
 #define smp_mb__before_atomic()	smp_mb()
 #define smp_mb__after_atomic()	smp_mb()
 
+#ifdef CONFIG_CPU_SPECTRE
+static inline unsigned long array_index_mask_nospec(unsigned long idx,
+						    unsigned long sz)
+{
+	unsigned long mask;
+
+	asm volatile(
+		"cmp	%1, %2\n"
+	"	sbc	%0, %1, %1\n"
+	CSDB
+	: "=r" (mask)
+	: "r" (idx), "Ir" (sz)
+	: "cc");
+
+	return mask;
+}
+#define array_index_mask_nospec array_index_mask_nospec
+#endif
+
+#include <asm-generic/barrier.h>
+
 #endif /* !__ASSEMBLY__ */
 #endif /* __ASM_BARRIER_H */
--- linux-4.4.0.orig/arch/arm/include/asm/bugs.h
+++ linux-4.4.0/arch/arm/include/asm/bugs.h
@@ -1,6 +1,4 @@
 /*
- *  arch/arm/include/asm/bugs.h
- *
  *  Copyright (C) 1995-2003 Russell King
  *
  * This program is free software; you can redistribute it and/or modify
@@ -10,12 +8,12 @@
 #ifndef __ASM_BUGS_H
 #define __ASM_BUGS_H
 
-#ifdef CONFIG_MMU
 extern void check_writebuffer_bugs(void);
 
-#define check_bugs() check_writebuffer_bugs()
+#ifdef CONFIG_MMU
+extern void check_other_bugs(void);
 #else
-#define check_bugs() do { } while (0)
+#define check_other_bugs() do { } while (0)
 #endif
 
 #endif
--- linux-4.4.0.orig/arch/arm/include/asm/cp15.h
+++ linux-4.4.0/arch/arm/include/asm/cp15.h
@@ -49,6 +49,24 @@
 
 #ifdef CONFIG_CPU_CP15
 
+#define __ACCESS_CP15(CRn, Op1, CRm, Op2)	\
+	"mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32
+#define __ACCESS_CP15_64(Op1, CRm)		\
+	"mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64
+
+#define __read_sysreg(r, w, c, t) ({				\
+	t __val;						\
+	asm volatile(r " " c : "=r" (__val));			\
+	__val;							\
+})
+#define read_sysreg(...)		__read_sysreg(__VA_ARGS__)
+
+#define __write_sysreg(v, r, w, c, t)	asm volatile(w " " c : : "r" ((t)(v)))
+#define write_sysreg(v, ...)		__write_sysreg(v, __VA_ARGS__)
+
+#define BPIALL				__ACCESS_CP15(c7, 0, c5, 6)
+#define ICIALLU				__ACCESS_CP15(c7, 0, c5, 0)
+
 extern unsigned long cr_alignment;	/* defined in entry-armv.S */
 
 static inline unsigned long get_cr(void)
--- linux-4.4.0.orig/arch/arm/include/asm/cputype.h
+++ linux-4.4.0/arch/arm/include/asm/cputype.h
@@ -74,14 +74,26 @@
 #define ARM_CPU_PART_CORTEX_A12		0x4100c0d0
 #define ARM_CPU_PART_CORTEX_A17		0x4100c0e0
 #define ARM_CPU_PART_CORTEX_A15		0x4100c0f0
+#define ARM_CPU_PART_CORTEX_A53		0x4100d030
+#define ARM_CPU_PART_CORTEX_A57		0x4100d070
+#define ARM_CPU_PART_CORTEX_A72		0x4100d080
+#define ARM_CPU_PART_CORTEX_A73		0x4100d090
+#define ARM_CPU_PART_CORTEX_A75		0x4100d0a0
 #define ARM_CPU_PART_MASK		0xff00fff0
 
+/* Broadcom cores */
+#define ARM_CPU_PART_BRAHMA_B15		0x420000f0
+
 #define ARM_CPU_XSCALE_ARCH_MASK	0xe000
 #define ARM_CPU_XSCALE_ARCH_V1		0x2000
 #define ARM_CPU_XSCALE_ARCH_V2		0x4000
 #define ARM_CPU_XSCALE_ARCH_V3		0x6000
 
+/* Qualcomm implemented cores */
+#define ARM_CPU_PART_SCORPION		0x510002d0
+
 extern unsigned int processor_id;
+struct proc_info_list *lookup_processor(u32 midr);
 
 #ifdef CONFIG_CPU_CP15
 #define read_cpuid(reg)							\
--- linux-4.4.0.orig/arch/arm/include/asm/dma-mapping.h
+++ linux-4.4.0/arch/arm/include/asm/dma-mapping.h
@@ -119,7 +119,7 @@
 /* The ARM override for dma_max_pfn() */
 static inline unsigned long dma_max_pfn(struct device *dev)
 {
-	return PHYS_PFN_OFFSET + dma_to_pfn(dev, *dev->dma_mask);
+	return dma_to_pfn(dev, *dev->dma_mask);
 }
 #define dma_max_pfn(dev) dma_max_pfn(dev)
 
--- linux-4.4.0.orig/arch/arm/include/asm/elf.h
+++ linux-4.4.0/arch/arm/include/asm/elf.h
@@ -112,12 +112,8 @@
 #define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE	4096
 
-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
-   use of this is to invoke "./ld.so someprog" to test out a new version of
-   the loader.  We need to make sure that it is out of the way of the program
-   that it will "exec", and that there is sufficient room for the brk.  */
-
-#define ELF_ET_DYN_BASE	(TASK_SIZE / 3 * 2)
+/* This is the base location for PIE (ET_DYN with INTERP) loads. */
+#define ELF_ET_DYN_BASE		0x400000UL
 
 /* When the program starts, a1 contains a pointer to a function to be 
    registered with atexit, as per the SVR4 ABI.  A value of 0 means we 
--- linux-4.4.0.orig/arch/arm/include/asm/floppy.h
+++ linux-4.4.0/arch/arm/include/asm/floppy.h
@@ -17,7 +17,7 @@
 
 #define fd_outb(val,port)			\
 	do {					\
-		if ((port) == FD_DOR)		\
+		if ((port) == (u32)FD_DOR)	\
 			fd_setdor((val));	\
 		else				\
 			outb((val),(port));	\
--- linux-4.4.0.orig/arch/arm/include/asm/ftrace.h
+++ linux-4.4.0/arch/arm/include/asm/ftrace.h
@@ -54,6 +54,24 @@
 
 #define ftrace_return_address(n) return_address(n)
 
+#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+
+static inline bool arch_syscall_match_sym_name(const char *sym,
+					       const char *name)
+{
+	if (!strcmp(sym, "sys_mmap2"))
+		sym = "sys_mmap_pgoff";
+	else if (!strcmp(sym, "sys_statfs64_wrapper"))
+		sym = "sys_statfs64";
+	else if (!strcmp(sym, "sys_fstatfs64_wrapper"))
+		sym = "sys_fstatfs64";
+	else if (!strcmp(sym, "sys_arm_fadvise64_64"))
+		sym = "sys_fadvise64_64";
+
+	/* Ignore case since sym may start with "SyS" instead of "sys" */
+	return !strcasecmp(sym, name);
+}
+
 #endif /* ifndef __ASSEMBLY__ */
 
 #endif /* _ASM_ARM_FTRACE */
--- linux-4.4.0.orig/arch/arm/include/asm/futex.h
+++ linux-4.4.0/arch/arm/include/asm/futex.h
@@ -128,20 +128,10 @@
 #endif /* !SMP */
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret, tmp;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 #ifndef CONFIG_SMP
 	preempt_disable();
 #endif
@@ -172,17 +162,14 @@
 	preempt_enable();
 #endif
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	/*
+	 * Store unconditionally. If ret != 0 the extra store is the least
+	 * of the worries but GCC cannot figure out that __futex_atomic_op()
+	 * is either setting ret to -EFAULT or storing the old value in
+	 * oldval which results in a uninitialized warning at the call site.
+	 */
+	*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/arm/include/asm/irq.h
+++ linux-4.4.0/arch/arm/include/asm/irq.h
@@ -24,7 +24,6 @@
 #ifndef __ASSEMBLY__
 struct irqaction;
 struct pt_regs;
-extern void migrate_irqs(void);
 
 extern void asm_do_IRQ(unsigned int, struct pt_regs *);
 void handle_IRQ(unsigned int, struct pt_regs *);
--- linux-4.4.0.orig/arch/arm/include/asm/kgdb.h
+++ linux-4.4.0/arch/arm/include/asm/kgdb.h
@@ -76,7 +76,7 @@
 
 #define KGDB_MAX_NO_CPUS	1
 #define BUFMAX			400
-#define NUMREGBYTES		(DBG_MAX_REG_NUM << 2)
+#define NUMREGBYTES		(GDB_MAX_REGS << 2)
 #define NUMCRITREGBYTES		(32 << 2)
 
 #define _R0			0
--- linux-4.4.0.orig/arch/arm/include/asm/kvm_arm.h
+++ linux-4.4.0/arch/arm/include/asm/kvm_arm.h
@@ -161,8 +161,7 @@
 #else
 #define VTTBR_X		(5 - KVM_T0SZ)
 #endif
-#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
-#define VTTBR_BADDR_MASK  (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
+#define VTTBR_BADDR_MASK  (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_X)
 #define VTTBR_VMID_SHIFT  (48LLU)
 #define VTTBR_VMID_MASK	  (0xffLLU << VTTBR_VMID_SHIFT)
 
@@ -209,6 +208,7 @@
 #define HSR_EC_IABT_HYP	(0x21)
 #define HSR_EC_DABT	(0x24)
 #define HSR_EC_DABT_HYP	(0x25)
+#define HSR_EC_MAX	(0x3f)
 
 #define HSR_WFI_IS_WFE		(1U << 0)
 
--- linux-4.4.0.orig/arch/arm/include/asm/kvm_mmu.h
+++ linux-4.4.0/arch/arm/include/asm/kvm_mmu.h
@@ -204,18 +204,12 @@
 	 * and iterate over the range.
 	 */
 
-	bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached;
-
 	VM_BUG_ON(size & ~PAGE_MASK);
 
-	if (!need_flush && !icache_is_pipt())
-		goto vipt_cache;
-
 	while (size) {
 		void *va = kmap_atomic_pfn(pfn);
 
-		if (need_flush)
-			kvm_flush_dcache_to_poc(va, PAGE_SIZE);
+		kvm_flush_dcache_to_poc(va, PAGE_SIZE);
 
 		if (icache_is_pipt())
 			__cpuc_coherent_user_range((unsigned long)va,
@@ -227,7 +221,6 @@
 		kunmap_atomic(va);
 	}
 
-vipt_cache:
 	if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) {
 		/* any kind of VIPT cache */
 		__flush_icache_all();
--- linux-4.4.0.orig/arch/arm/include/asm/mmu_context.h
+++ linux-4.4.0/arch/arm/include/asm/mmu_context.h
@@ -61,6 +61,7 @@
 		cpu_switch_mm(mm->pgd, mm);
 }
 
+#ifndef MODULE
 #define finish_arch_post_lock_switch \
 	finish_arch_post_lock_switch
 static inline void finish_arch_post_lock_switch(void)
@@ -82,6 +83,7 @@
 		preempt_enable_no_resched();
 	}
 }
+#endif /* !MODULE */
 
 #endif	/* CONFIG_MMU */
 
--- linux-4.4.0.orig/arch/arm/include/asm/percpu.h
+++ linux-4.4.0/arch/arm/include/asm/percpu.h
@@ -16,6 +16,8 @@
 #ifndef _ASM_ARM_PERCPU_H_
 #define _ASM_ARM_PERCPU_H_
 
+#include <asm/thread_info.h>
+
 /*
  * Same as asm-generic/percpu.h, except that we store the per cpu offset
  * in the TPIDRPRW. TPIDRPRW only exists on V6K and V7
--- linux-4.4.0.orig/arch/arm/include/asm/pgtable-2level.h
+++ linux-4.4.0/arch/arm/include/asm/pgtable-2level.h
@@ -193,6 +193,7 @@
 
 #define pmd_large(pmd)		(pmd_val(pmd) & 2)
 #define pmd_bad(pmd)		(pmd_val(pmd) & 2)
+#define pmd_present(pmd)	(pmd_val(pmd))
 
 #define copy_pmd(pmdpd,pmdps)		\
 	do {				\
--- linux-4.4.0.orig/arch/arm/include/asm/pgtable-3level.h
+++ linux-4.4.0/arch/arm/include/asm/pgtable-3level.h
@@ -212,6 +212,7 @@
 						: !!(pmd_val(pmd) & (val)))
 #define pmd_isclear(pmd, val)	(!(pmd_val(pmd) & (val)))
 
+#define pmd_present(pmd)	(pmd_isset((pmd), L_PMD_SECT_VALID))
 #define pmd_young(pmd)		(pmd_isset((pmd), PMD_SECT_AF))
 #define pte_special(pte)	(pte_isset((pte), L_PTE_SPECIAL))
 static inline pte_t pte_mkspecial(pte_t pte)
@@ -257,10 +258,10 @@
 #define pfn_pmd(pfn,prot)	(__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
 #define mk_pmd(page,prot)	pfn_pmd(page_to_pfn(page),prot)
 
-/* represent a notpresent pmd by zero, this is used by pmdp_invalidate */
+/* represent a notpresent pmd by faulting entry, this is used by pmdp_invalidate */
 static inline pmd_t pmd_mknotpresent(pmd_t pmd)
 {
-	return __pmd(0);
+	return __pmd(pmd_val(pmd) & ~L_PMD_SECT_VALID);
 }
 
 static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
--- linux-4.4.0.orig/arch/arm/include/asm/pgtable.h
+++ linux-4.4.0/arch/arm/include/asm/pgtable.h
@@ -182,7 +182,6 @@
 #define pgd_offset_k(addr)	pgd_offset(&init_mm, addr)
 
 #define pmd_none(pmd)		(!pmd_val(pmd))
-#define pmd_present(pmd)	(pmd_val(pmd))
 
 static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 {
--- linux-4.4.0.orig/arch/arm/include/asm/proc-fns.h
+++ linux-4.4.0/arch/arm/include/asm/proc-fns.h
@@ -23,7 +23,7 @@
 /*
  * Don't change this structure - ASM code relies on it.
  */
-extern struct processor {
+struct processor {
 	/* MISC
 	 * get data abort address/flags
 	 */
@@ -37,6 +37,10 @@
 	 */
 	void (*_proc_init)(void);
 	/*
+	 * Check for processor bugs
+	 */
+	void (*check_bugs)(void);
+	/*
 	 * Disable any processor specifics
 	 */
 	void (*_proc_fin)(void);
@@ -75,9 +79,13 @@
 	unsigned int suspend_size;
 	void (*do_suspend)(void *);
 	void (*do_resume)(void *);
-} processor;
+};
 
 #ifndef MULTI_CPU
+static inline void init_proc_vtable(const struct processor *p)
+{
+}
+
 extern void cpu_proc_init(void);
 extern void cpu_proc_fin(void);
 extern int cpu_do_idle(void);
@@ -94,17 +102,50 @@
 extern void cpu_do_suspend(void *);
 extern void cpu_do_resume(void *);
 #else
-#define cpu_proc_init			processor._proc_init
-#define cpu_proc_fin			processor._proc_fin
-#define cpu_reset			processor.reset
-#define cpu_do_idle			processor._do_idle
-#define cpu_dcache_clean_area		processor.dcache_clean_area
-#define cpu_set_pte_ext			processor.set_pte_ext
-#define cpu_do_switch_mm		processor.switch_mm
 
-/* These three are private to arch/arm/kernel/suspend.c */
-#define cpu_do_suspend			processor.do_suspend
-#define cpu_do_resume			processor.do_resume
+extern struct processor processor;
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+#include <linux/smp.h>
+/*
+ * This can't be a per-cpu variable because we need to access it before
+ * per-cpu has been initialised.  We have a couple of functions that are
+ * called in a pre-emptible context, and so can't use smp_processor_id()
+ * there, hence PROC_TABLE().  We insist in init_proc_vtable() that the
+ * function pointers for these are identical across all CPUs.
+ */
+extern struct processor *cpu_vtable[];
+#define PROC_VTABLE(f)			cpu_vtable[smp_processor_id()]->f
+#define PROC_TABLE(f)			cpu_vtable[0]->f
+static inline void init_proc_vtable(const struct processor *p)
+{
+	unsigned int cpu = smp_processor_id();
+	*cpu_vtable[cpu] = *p;
+	WARN_ON_ONCE(cpu_vtable[cpu]->dcache_clean_area !=
+		     cpu_vtable[0]->dcache_clean_area);
+	WARN_ON_ONCE(cpu_vtable[cpu]->set_pte_ext !=
+		     cpu_vtable[0]->set_pte_ext);
+}
+#else
+#define PROC_VTABLE(f)			processor.f
+#define PROC_TABLE(f)			processor.f
+static inline void init_proc_vtable(const struct processor *p)
+{
+	processor = *p;
+}
+#endif
+
+#define cpu_proc_init			PROC_VTABLE(_proc_init)
+#define cpu_check_bugs			PROC_VTABLE(check_bugs)
+#define cpu_proc_fin			PROC_VTABLE(_proc_fin)
+#define cpu_reset			PROC_VTABLE(reset)
+#define cpu_do_idle			PROC_VTABLE(_do_idle)
+#define cpu_dcache_clean_area		PROC_TABLE(dcache_clean_area)
+#define cpu_set_pte_ext			PROC_TABLE(set_pte_ext)
+#define cpu_do_switch_mm		PROC_VTABLE(switch_mm)
+
+/* These two are private to arch/arm/kernel/suspend.c */
+#define cpu_do_suspend			PROC_VTABLE(do_suspend)
+#define cpu_do_resume			PROC_VTABLE(do_resume)
 #endif
 
 extern void cpu_resume(void);
--- linux-4.4.0.orig/arch/arm/include/asm/processor.h
+++ linux-4.4.0/arch/arm/include/asm/processor.h
@@ -77,7 +77,11 @@
 unsigned long get_wchan(struct task_struct *p);
 
 #if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
-#define cpu_relax()			smp_mb()
+#define cpu_relax()						\
+	do {							\
+		smp_mb();					\
+		__asm__ __volatile__("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");	\
+	} while (0)
 #else
 #define cpu_relax()			barrier()
 #endif
--- linux-4.4.0.orig/arch/arm/include/asm/psci.h
+++ linux-4.4.0/arch/arm/include/asm/psci.h
@@ -16,7 +16,7 @@
 
 extern struct smp_operations psci_smp_ops;
 
-#ifdef CONFIG_ARM_PSCI
+#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
 bool psci_smp_available(void);
 #else
 static inline bool psci_smp_available(void) { return false; }
--- linux-4.4.0.orig/arch/arm/include/asm/suspend.h
+++ linux-4.4.0/arch/arm/include/asm/suspend.h
@@ -7,6 +7,7 @@
 };
 
 extern void cpu_resume(void);
+extern void cpu_resume_no_hyp(void);
 extern void cpu_resume_arm(void);
 extern int cpu_suspend(unsigned long, int (*)(unsigned long));
 
--- linux-4.4.0.orig/arch/arm/include/asm/system_misc.h
+++ linux-4.4.0/arch/arm/include/asm/system_misc.h
@@ -7,6 +7,7 @@
 #include <linux/linkage.h>
 #include <linux/irqflags.h>
 #include <linux/reboot.h>
+#include <linux/percpu.h>
 
 extern void cpu_init(void);
 
@@ -14,6 +15,20 @@
 extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
 extern void (*arm_pm_idle)(void);
 
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+typedef void (*harden_branch_predictor_fn_t)(void);
+DECLARE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn);
+static inline void harden_branch_predictor(void)
+{
+	harden_branch_predictor_fn_t fn = per_cpu(harden_branch_predictor_fn,
+						  smp_processor_id());
+	if (fn)
+		fn();
+}
+#else
+#define harden_branch_predictor() do { } while (0)
+#endif
+
 #define UDBG_UNDEFINED	(1 << 0)
 #define UDBG_SYSCALL	(1 << 1)
 #define UDBG_BADABORT	(1 << 2)
--- linux-4.4.0.orig/arch/arm/include/asm/thread_info.h
+++ linux-4.4.0/arch/arm/include/asm/thread_info.h
@@ -124,10 +124,10 @@
 struct user_vfp;
 struct user_vfp_exc;
 
-extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *,
-					   struct user_vfp_exc __user *);
-extern int vfp_restore_user_hwstate(struct user_vfp __user *,
-				    struct user_vfp_exc __user *);
+extern int vfp_preserve_user_clear_hwstate(struct user_vfp *,
+					   struct user_vfp_exc *);
+extern int vfp_restore_user_hwstate(struct user_vfp *,
+				    struct user_vfp_exc *);
 #endif
 
 /*
--- linux-4.4.0.orig/arch/arm/include/asm/tlb.h
+++ linux-4.4.0/arch/arm/include/asm/tlb.h
@@ -257,6 +257,14 @@
 	tlb_add_flush(tlb, addr);
 }
 
+static inline void
+tlb_flush_pmd_range(struct mmu_gather *tlb, unsigned long address,
+		    unsigned long size)
+{
+	tlb_add_flush(tlb, address);
+	tlb_add_flush(tlb, address + size - PMD_SIZE);
+}
+
 #define pte_free_tlb(tlb, ptep, addr)	__pte_free_tlb(tlb, ptep, addr)
 #define pmd_free_tlb(tlb, pmdp, addr)	__pmd_free_tlb(tlb, pmdp, addr)
 #define pud_free_tlb(tlb, pudp, addr)	pud_free((tlb)->mm, pudp)
--- linux-4.4.0.orig/arch/arm/include/asm/uaccess.h
+++ linux-4.4.0/arch/arm/include/asm/uaccess.h
@@ -99,6 +99,14 @@
 static inline void set_fs(mm_segment_t fs)
 {
 	current_thread_info()->addr_limit = fs;
+
+	/*
+	 * Prevent a mispredicted conditional call to set_fs from forwarding
+	 * the wrong address limit to access_ok under speculation.
+	 */
+	dsb(nsh);
+	isb();
+
 	modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
 }
 
@@ -123,6 +131,39 @@
 	flag; })
 
 /*
+ * This is a type: either unsigned long, if the argument fits into
+ * that type, or otherwise unsigned long long.
+ */
+#define __inttype(x) \
+	__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
+
+/*
+ * Sanitise a uaccess pointer such that it becomes NULL if addr+size
+ * is above the current addr_limit.
+ */
+#define uaccess_mask_range_ptr(ptr, size)			\
+	((__typeof__(ptr))__uaccess_mask_range_ptr(ptr, size))
+static inline void __user *__uaccess_mask_range_ptr(const void __user *ptr,
+						    size_t size)
+{
+	void __user *safe_ptr = (void __user *)ptr;
+	unsigned long tmp;
+
+	asm volatile(
+	"	sub	%1, %3, #1\n"
+	"	subs	%1, %1, %0\n"
+	"	addhs	%1, %1, #1\n"
+	"	subhss	%1, %1, %2\n"
+	"	movlo	%0, #0\n"
+	: "+r" (safe_ptr), "=&r" (tmp)
+	: "r" (size), "r" (current_thread_info()->addr_limit)
+	: "cc");
+
+	csdb();
+	return safe_ptr;
+}
+
+/*
  * Single-value transfer routines.  They automatically use the right
  * size if we just have the right pointer type.  Note that the functions
  * which read from user space (*get_*) need to take care not to leak
@@ -191,7 +232,7 @@
 	({								\
 		unsigned long __limit = current_thread_info()->addr_limit - 1; \
 		register const typeof(*(p)) __user *__p asm("r0") = (p);\
-		register typeof(x) __r2 asm("r2");			\
+		register __inttype(x) __r2 asm("r2");			\
 		register unsigned long __l asm("r1") = __limit;		\
 		register int __e asm("r0");				\
 		unsigned int __ua_flags = uaccess_save_and_enable();	\
@@ -238,49 +279,23 @@
 extern int __put_user_4(void *, unsigned int);
 extern int __put_user_8(void *, unsigned long long);
 
-#define __put_user_x(__r2, __p, __e, __l, __s)				\
-	   __asm__ __volatile__ (					\
-		__asmeq("%0", "r0") __asmeq("%2", "r2")			\
-		__asmeq("%3", "r1")					\
-		"bl	__put_user_" #__s				\
-		: "=&r" (__e)						\
-		: "0" (__p), "r" (__r2), "r" (__l)			\
-		: "ip", "lr", "cc")
-
-#define __put_user_check(x, p)						\
+#define __put_user_check(__pu_val, __ptr, __err, __s)			\
 	({								\
 		unsigned long __limit = current_thread_info()->addr_limit - 1; \
-		const typeof(*(p)) __user *__tmp_p = (p);		\
-		register const typeof(*(p)) __r2 asm("r2") = (x);	\
-		register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \
+		register typeof(__pu_val) __r2 asm("r2") = __pu_val;	\
+		register const void __user *__p asm("r0") = __ptr;	\
 		register unsigned long __l asm("r1") = __limit;		\
 		register int __e asm("r0");				\
-		unsigned int __ua_flags = uaccess_save_and_enable();	\
-		switch (sizeof(*(__p))) {				\
-		case 1:							\
-			__put_user_x(__r2, __p, __e, __l, 1);		\
-			break;						\
-		case 2:							\
-			__put_user_x(__r2, __p, __e, __l, 2);		\
-			break;						\
-		case 4:							\
-			__put_user_x(__r2, __p, __e, __l, 4);		\
-			break;						\
-		case 8:							\
-			__put_user_x(__r2, __p, __e, __l, 8);		\
-			break;						\
-		default: __e = __put_user_bad(); break;			\
-		}							\
-		uaccess_restore(__ua_flags);				\
-		__e;							\
+		__asm__ __volatile__ (					\
+			__asmeq("%0", "r0") __asmeq("%2", "r2")		\
+			__asmeq("%3", "r1")				\
+			"bl	__put_user_" #__s			\
+			: "=&r" (__e)					\
+			: "0" (__p), "r" (__r2), "r" (__l)		\
+			: "ip", "lr", "cc");				\
+		__err = __e;						\
 	})
 
-#define put_user(x, p)							\
-	({								\
-		might_fault();						\
-		__put_user_check(x, p);					\
-	 })
-
 #else /* CONFIG_MMU */
 
 /*
@@ -298,7 +313,7 @@
 }
 
 #define get_user(x, p)	__get_user(x, p)
-#define put_user(x, p)	__put_user(x, p)
+#define __put_user_check __put_user_nocheck
 
 #endif /* CONFIG_MMU */
 
@@ -307,6 +322,16 @@
 #define user_addr_max() \
 	(segment_eq(get_fs(), KERNEL_DS) ? ~0UL : get_fs())
 
+#ifdef CONFIG_CPU_SPECTRE
+/*
+ * When mitigating Spectre variant 1, it is not worth fixing the non-
+ * verifying accessors, because we need to add verification of the
+ * address space there.  Force these to use the standard get_user()
+ * version instead.
+ */
+#define __get_user(x, ptr) get_user(x, ptr)
+#else
+
 /*
  * The "__xxx" versions of the user access functions do not verify the
  * address space - it must have been done previously with a separate
@@ -323,12 +348,6 @@
 	__gu_err;							\
 })
 
-#define __get_user_error(x, ptr, err)					\
-({									\
-	__get_user_err((x), (ptr), err);				\
-	(void) 0;							\
-})
-
 #define __get_user_err(x, ptr, err)					\
 do {									\
 	unsigned long __gu_addr = (unsigned long)(ptr);			\
@@ -368,6 +387,13 @@
 #define __get_user_asm_byte(x, addr, err)			\
 	__get_user_asm(x, addr, err, ldrb)
 
+#if __LINUX_ARM_ARCH__ >= 6
+
+#define __get_user_asm_half(x, addr, err)			\
+	__get_user_asm(x, addr, err, ldrh)
+
+#else
+
 #ifndef __ARMEB__
 #define __get_user_asm_half(x, __gu_addr, err)			\
 ({								\
@@ -386,39 +412,62 @@
 })
 #endif
 
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
 #define __get_user_asm_word(x, addr, err)			\
 	__get_user_asm(x, addr, err, ldr)
+#endif
 
-#define __put_user(x, ptr)						\
+
+#define __put_user_switch(x, ptr, __err, __fn)				\
+	do {								\
+		const __typeof__(*(ptr)) __user *__pu_ptr = (ptr);	\
+		__typeof__(*(ptr)) __pu_val = (x);			\
+		unsigned int __ua_flags;				\
+		might_fault();						\
+		__ua_flags = uaccess_save_and_enable();			\
+		switch (sizeof(*(ptr))) {				\
+		case 1: __fn(__pu_val, __pu_ptr, __err, 1); break;	\
+		case 2:	__fn(__pu_val, __pu_ptr, __err, 2); break;	\
+		case 4:	__fn(__pu_val, __pu_ptr, __err, 4); break;	\
+		case 8:	__fn(__pu_val, __pu_ptr, __err, 8); break;	\
+		default: __err = __put_user_bad(); break;		\
+		}							\
+		uaccess_restore(__ua_flags);				\
+	} while (0)
+
+#define put_user(x, ptr)						\
 ({									\
-	long __pu_err = 0;						\
-	__put_user_err((x), (ptr), __pu_err);				\
+	int __pu_err = 0;						\
+	__put_user_switch((x), (ptr), __pu_err, __put_user_check);	\
 	__pu_err;							\
 })
 
-#define __put_user_error(x, ptr, err)					\
+#ifdef CONFIG_CPU_SPECTRE
+/*
+ * When mitigating Spectre variant 1.1, all accessors need to include
+ * verification of the address space.
+ */
+#define __put_user(x, ptr) put_user(x, ptr)
+
+#else
+#define __put_user(x, ptr)						\
 ({									\
-	__put_user_err((x), (ptr), err);				\
-	(void) 0;							\
+	long __pu_err = 0;						\
+	__put_user_switch((x), (ptr), __pu_err, __put_user_nocheck);	\
+	__pu_err;							\
 })
 
-#define __put_user_err(x, ptr, err)					\
-do {									\
-	unsigned long __pu_addr = (unsigned long)(ptr);			\
-	unsigned int __ua_flags;					\
-	__typeof__(*(ptr)) __pu_val = (x);				\
-	__chk_user_ptr(ptr);						\
-	might_fault();							\
-	__ua_flags = uaccess_save_and_enable();				\
-	switch (sizeof(*(ptr))) {					\
-	case 1: __put_user_asm_byte(__pu_val, __pu_addr, err);	break;	\
-	case 2: __put_user_asm_half(__pu_val, __pu_addr, err);	break;	\
-	case 4: __put_user_asm_word(__pu_val, __pu_addr, err);	break;	\
-	case 8:	__put_user_asm_dword(__pu_val, __pu_addr, err);	break;	\
-	default: __put_user_bad();					\
-	}								\
-	uaccess_restore(__ua_flags);					\
-} while (0)
+#define __put_user_nocheck(x, __pu_ptr, __err, __size)			\
+	do {								\
+		unsigned long __pu_addr = (unsigned long)__pu_ptr;	\
+		__put_user_nocheck_##__size(x, __pu_addr, __err);	\
+	} while (0)
+
+#define __put_user_nocheck_1 __put_user_asm_byte
+#define __put_user_nocheck_2 __put_user_asm_half
+#define __put_user_nocheck_4 __put_user_asm_word
+#define __put_user_nocheck_8 __put_user_asm_dword
 
 #define __put_user_asm(x, __pu_addr, err, instr)		\
 	__asm__ __volatile__(					\
@@ -440,6 +489,13 @@
 #define __put_user_asm_byte(x, __pu_addr, err)			\
 	__put_user_asm(x, __pu_addr, err, strb)
 
+#if __LINUX_ARM_ARCH__ >= 6
+
+#define __put_user_asm_half(x, __pu_addr, err)			\
+	__put_user_asm(x, __pu_addr, err, strh)
+
+#else
+
 #ifndef __ARMEB__
 #define __put_user_asm_half(x, __pu_addr, err)			\
 ({								\
@@ -456,6 +512,8 @@
 })
 #endif
 
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
 #define __put_user_asm_word(x, __pu_addr, err)			\
 	__put_user_asm(x, __pu_addr, err, str)
 
@@ -488,6 +546,7 @@
 	: "r" (x), "i" (-EFAULT)				\
 	: "cc")
 
+#endif /* !CONFIG_CPU_SPECTRE */
 
 #ifdef CONFIG_MMU
 extern unsigned long __must_check
--- linux-4.4.0.orig/arch/arm/include/asm/unaligned.h
+++ linux-4.4.0/arch/arm/include/asm/unaligned.h
@@ -0,0 +1,27 @@
+#ifndef __ASM_ARM_UNALIGNED_H
+#define __ASM_ARM_UNALIGNED_H
+
+/*
+ * We generally want to set CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS on ARMv6+,
+ * but we don't want to use linux/unaligned/access_ok.h since that can lead
+ * to traps on unaligned stm/ldm or strd/ldrd.
+ */
+#include <asm/byteorder.h>
+
+#if defined(__LITTLE_ENDIAN)
+# include <linux/unaligned/le_struct.h>
+# include <linux/unaligned/be_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned	__get_unaligned_le
+# define put_unaligned	__put_unaligned_le
+#elif defined(__BIG_ENDIAN)
+# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/le_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned	__get_unaligned_be
+# define put_unaligned	__put_unaligned_be
+#else
+# error need to define endianess
+#endif
+
+#endif /* __ASM_ARM_UNALIGNED_H */
--- linux-4.4.0.orig/arch/arm/include/asm/vdso.h
+++ linux-4.4.0/arch/arm/include/asm/vdso.h
@@ -11,8 +11,6 @@
 
 void arm_install_vdso(struct mm_struct *mm, unsigned long addr);
 
-extern char vdso_start, vdso_end;
-
 extern unsigned int vdso_total_pages;
 
 #else /* CONFIG_VDSO */
--- linux-4.4.0.orig/arch/arm/include/asm/xen/events.h
+++ linux-4.4.0/arch/arm/include/asm/xen/events.h
@@ -16,7 +16,7 @@
 	return raw_irqs_disabled_flags(regs->ARM_cpsr);
 }
 
-#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((ptr),	\
+#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((long long*)(ptr),\
 							    atomic64_t,	\
 							    counter), (val))
 
--- linux-4.4.0.orig/arch/arm/include/asm/xen/page-coherent.h
+++ linux-4.4.0/arch/arm/include/asm/xen/page-coherent.h
@@ -35,14 +35,21 @@
 	     dma_addr_t dev_addr, unsigned long offset, size_t size,
 	     enum dma_data_direction dir, struct dma_attrs *attrs)
 {
-	bool local = XEN_PFN_DOWN(dev_addr) == page_to_xen_pfn(page);
+	unsigned long page_pfn = page_to_xen_pfn(page);
+	unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
+	unsigned long compound_pages =
+		(1<<compound_order(page)) * XEN_PFN_PER_PAGE;
+	bool local = (page_pfn <= dev_pfn) &&
+		(dev_pfn - page_pfn < compound_pages);
+
 	/*
-	 * Dom0 is mapped 1:1, while the Linux page can be spanned accross
-	 * multiple Xen page, it's not possible to have a mix of local and
-	 * foreign Xen page. So if the first xen_pfn == mfn the page is local
-	 * otherwise it's a foreign page grant-mapped in dom0. If the page is
-	 * local we can safely call the native dma_ops function, otherwise we
-	 * call the xen specific function.
+	 * Dom0 is mapped 1:1, while the Linux page can span across
+	 * multiple Xen pages, it's not possible for it to contain a
+	 * mix of local and foreign Xen pages. So if the first xen_pfn
+	 * == mfn the page is local otherwise it's a foreign page
+	 * grant-mapped in dom0. If the page is local we can safely
+	 * call the native dma_ops function, otherwise we call the xen
+	 * specific function.
 	 */
 	if (local)
 		__generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
--- linux-4.4.0.orig/arch/arm/kernel/Makefile
+++ linux-4.4.0/arch/arm/kernel/Makefile
@@ -30,6 +30,7 @@
 obj-y		+= entry-armv.o
 endif
 
+obj-$(CONFIG_MMU)		+= bugs.o
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
 obj-$(CONFIG_FIQ)		+= fiq.o fiqasm.o
@@ -73,7 +74,6 @@
 obj-$(CONFIG_PERF_EVENTS)	+= perf_regs.o perf_callchain.o
 obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event_xscale.o perf_event_v6.o \
 				   perf_event_v7.o
-CFLAGS_pj4-cp0.o		:= -marm
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 obj-$(CONFIG_VDSO)		+= vdso.o
@@ -88,8 +88,9 @@
 
 obj-$(CONFIG_ARM_VIRT_EXT)	+= hyp-stub.o
 ifeq ($(CONFIG_ARM_PSCI),y)
-obj-y				+= psci-call.o
 obj-$(CONFIG_SMP)		+= psci_smp.o
 endif
 
+obj-$(CONFIG_HAVE_ARM_SMCCC)	+= smccc-call.o
+
 extra-y := $(head-y) vmlinux.lds
--- linux-4.4.0.orig/arch/arm/kernel/armksyms.c
+++ linux-4.4.0/arch/arm/kernel/armksyms.c
@@ -16,6 +16,7 @@
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/arm-smccc.h>
 
 #include <asm/checksum.h>
 #include <asm/ftrace.h>
@@ -175,3 +176,8 @@
 EXPORT_SYMBOL(__pv_phys_pfn_offset);
 EXPORT_SYMBOL(__pv_offset);
 #endif
+
+#ifdef CONFIG_HAVE_ARM_SMCCC
+EXPORT_SYMBOL(arm_smccc_smc);
+EXPORT_SYMBOL(arm_smccc_hvc);
+#endif
--- linux-4.4.0.orig/arch/arm/kernel/bugs.c
+++ linux-4.4.0/arch/arm/kernel/bugs.c
@@ -0,0 +1,19 @@
+// SPDX-Identifier: GPL-2.0
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <asm/bugs.h>
+#include <asm/proc-fns.h>
+
+void check_other_bugs(void)
+{
+#ifdef MULTI_CPU
+	if (cpu_check_bugs)
+		cpu_check_bugs();
+#endif
+}
+
+void __init arch_cpu_finalize_init(void)
+{
+	check_writebuffer_bugs();
+	check_other_bugs();
+}
--- linux-4.4.0.orig/arch/arm/kernel/devtree.c
+++ linux-4.4.0/arch/arm/kernel/devtree.c
@@ -87,6 +87,8 @@
 		return;
 
 	for_each_child_of_node(cpus, cpu) {
+		const __be32 *cell;
+		int prop_bytes;
 		u32 hwid;
 
 		if (of_node_cmp(cpu->type, "cpu"))
@@ -98,7 +100,8 @@
 		 * properties is considered invalid to build the
 		 * cpu_logical_map.
 		 */
-		if (of_property_read_u32(cpu, "reg", &hwid)) {
+		cell = of_get_property(cpu, "reg", &prop_bytes);
+		if (!cell || prop_bytes < sizeof(*cell)) {
 			pr_debug(" * %s missing reg property\n",
 				     cpu->full_name);
 			of_node_put(cpu);
@@ -106,10 +109,15 @@
 		}
 
 		/*
-		 * 8 MSBs must be set to 0 in the DT since the reg property
+		 * Bits n:24 must be set to 0 in the DT since the reg property
 		 * defines the MPIDR[23:0].
 		 */
-		if (hwid & ~MPIDR_HWID_BITMASK) {
+		do {
+			hwid = be32_to_cpu(*cell++);
+			prop_bytes -= sizeof(*cell);
+		} while (!hwid && prop_bytes > 0);
+
+		if (prop_bytes || (hwid & ~MPIDR_HWID_BITMASK)) {
 			of_node_put(cpu);
 			return;
 		}
--- linux-4.4.0.orig/arch/arm/kernel/entry-common.S
+++ linux-4.4.0/arch/arm/kernel/entry-common.S
@@ -223,9 +223,7 @@
 	tst	r10, #_TIF_SYSCALL_WORK		@ are we tracing syscalls?
 	bne	__sys_trace
 
-	cmp	scno, #NR_syscalls		@ check upper syscall limit
-	badr	lr, ret_fast_syscall		@ return address
-	ldrcc	pc, [tbl, scno, lsl #2]		@ call sys_* routine
+	invoke_syscall tbl, scno, r10, ret_fast_syscall
 
 	add	r1, sp, #S_OFF
 2:	cmp	scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)
@@ -258,27 +256,20 @@
 	mov	r1, scno
 	add	r0, sp, #S_OFF
 	bl	syscall_trace_enter
-
-	badr	lr, __sys_trace_return		@ return address
-	mov	scno, r0			@ syscall number (possibly new)
-	add	r1, sp, #S_R0 + S_OFF		@ pointer to regs
-	cmp	scno, #NR_syscalls		@ check upper syscall limit
-	ldmccia	r1, {r0 - r6}			@ have to reload r0 - r6
-	stmccia	sp, {r4, r5}			@ and update the stack args
-	ldrcc	pc, [tbl, scno, lsl #2]		@ call sys_* routine
+	mov	scno, r0
+	invoke_syscall tbl, scno, r10, __sys_trace_return, reload=1
 	cmp	scno, #-1			@ skip the syscall?
 	bne	2b
 	add	sp, sp, #S_OFF			@ restore stack
-	b	ret_slow_syscall
 
-__sys_trace_return:
-	str	r0, [sp, #S_R0 + S_OFF]!	@ save returned r0
+__sys_trace_return_nosave:
+	enable_irq_notrace
 	mov	r0, sp
 	bl	syscall_trace_exit
 	b	ret_slow_syscall
 
-__sys_trace_return_nosave:
-	enable_irq_notrace
+__sys_trace_return:
+	str	r0, [sp, #S_R0 + S_OFF]!	@ save returned r0
 	mov	r0, sp
 	bl	syscall_trace_exit
 	b	ret_slow_syscall
@@ -317,6 +308,10 @@
 		bic	scno, r0, #__NR_OABI_SYSCALL_BASE
 		cmp	scno, #__NR_syscall - __NR_SYSCALL_BASE
 		cmpne	scno, #NR_syscalls	@ check range
+#ifdef CONFIG_CPU_SPECTRE
+		movhs	scno, #0
+		csdb
+#endif
 		stmloia	sp, {r5, r6}		@ shuffle args
 		movlo	r0, r1
 		movlo	r1, r2
--- linux-4.4.0.orig/arch/arm/kernel/entry-header.S
+++ linux-4.4.0/arch/arm/kernel/entry-header.S
@@ -295,6 +295,8 @@
 	mov	r2, sp
 	ldr	r1, [r2, #\offset + S_PSR]	@ get calling cpsr
 	ldr	lr, [r2, #\offset + S_PC]!	@ get pc
+	tst	r1, #PSR_I_BIT | 0x0f
+	bne	1f
 	msr	spsr_cxsf, r1			@ save in spsr_svc
 #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K)
 	@ We must avoid clrex due to Cortex-A15 erratum #830321
@@ -309,6 +311,7 @@
 						@ after ldm {}^
 	add	sp, sp, #\offset + S_FRAME_SIZE
 	movs	pc, lr				@ return & move spsr_svc into cpsr
+1:	bug	"Returning to usermode but unexpected PSR bits set?", \@
 #elif defined(CONFIG_CPU_V7M)
 	@ V7M restore.
 	@ Note that we don't need to do clrex here as clearing the local
@@ -324,6 +327,8 @@
 	ldr	r1, [sp, #\offset + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #\offset + S_PC]	@ get pc
 	add	sp, sp, #\offset + S_SP
+	tst	r1, #PSR_I_BIT | 0x0f
+	bne	1f
 	msr	spsr_cxsf, r1			@ save in spsr_svc
 
 	@ We must avoid clrex due to Cortex-A15 erratum #830321
@@ -336,6 +341,7 @@
 	.endif
 	add	sp, sp, #S_FRAME_SIZE - S_SP
 	movs	pc, lr				@ return & move spsr_svc into cpsr
+1:	bug	"Returning to usermode but unexpected PSR bits set?", \@
 #endif	/* !CONFIG_THUMB2_KERNEL */
 	.endm
 
@@ -367,6 +373,31 @@
 #endif
 	.endm
 
+	.macro	invoke_syscall, table, nr, tmp, ret, reload=0
+#ifdef CONFIG_CPU_SPECTRE
+	mov	\tmp, \nr
+	cmp	\tmp, #NR_syscalls		@ check upper syscall limit
+	movcs	\tmp, #0
+	csdb
+	badr	lr, \ret			@ return address
+	.if	\reload
+	add	r1, sp, #S_R0 + S_OFF		@ pointer to regs
+	ldmccia	r1, {r0 - r6}			@ reload r0-r6
+	stmccia	sp, {r4, r5}			@ update stack arguments
+	.endif
+	ldrcc	pc, [\table, \tmp, lsl #2]	@ call sys_* routine
+#else
+	cmp	\nr, #NR_syscalls		@ check upper syscall limit
+	badr	lr, \ret			@ return address
+	.if	\reload
+	add	r1, sp, #S_R0 + S_OFF		@ pointer to regs
+	ldmccia	r1, {r0 - r6}			@ reload r0-r6
+	stmccia	sp, {r4, r5}			@ update stack arguments
+	.endif
+	ldrcc	pc, [\table, \nr, lsl #2]	@ call sys_* routine
+#endif
+	.endm
+
 /*
  * These are the registers used in the syscall handler, and allow us to
  * have in theory up to 7 arguments to a function - r0 to r6.
--- linux-4.4.0.orig/arch/arm/kernel/ftrace.c
+++ linux-4.4.0/arch/arm/kernel/ftrace.c
@@ -29,11 +29,6 @@
 #endif
 
 #ifdef CONFIG_DYNAMIC_FTRACE
-#ifdef CONFIG_OLD_MCOUNT
-#define OLD_MCOUNT_ADDR	((unsigned long) mcount)
-#define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old)
-
-#define	OLD_NOP		0xe1a00000	/* mov r0, r0 */
 
 static int __ftrace_modify_code(void *data)
 {
@@ -51,6 +46,12 @@
 	stop_machine(__ftrace_modify_code, &command, NULL);
 }
 
+#ifdef CONFIG_OLD_MCOUNT
+#define OLD_MCOUNT_ADDR	((unsigned long) mcount)
+#define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old)
+
+#define	OLD_NOP		0xe1a00000	/* mov r0, r0 */
+
 static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
 {
 	return rec->arch.old_mcount ? OLD_NOP : NOP;
--- linux-4.4.0.orig/arch/arm/kernel/head-common.S
+++ linux-4.4.0/arch/arm/kernel/head-common.S
@@ -122,6 +122,9 @@
 	.long	init_thread_union + THREAD_START_SP @ sp
 	.size	__mmap_switched_data, . - __mmap_switched_data
 
+	__FINIT
+	.text
+
 /*
  * This provides a C-API version of __lookup_processor_type
  */
@@ -133,9 +136,6 @@
 	ldmfd	sp!, {r4 - r6, r9, pc}
 ENDPROC(lookup_processor_type)
 
-	__FINIT
-	.text
-
 /*
  * Read processor ID register (CP#15, CR0), and look up in the linker-built
  * supported processor list.  Note that we can't use the absolute addresses
--- linux-4.4.0.orig/arch/arm/kernel/head.S
+++ linux-4.4.0/arch/arm/kernel/head.S
@@ -674,11 +674,7 @@
 	bcc	1b
 	bx	lr
 #else
-#ifdef CONFIG_CPU_ENDIAN_BE8
-	moveq	r0, #0x00004000	@ set bit 22, mov to mvn instruction
-#else
 	moveq	r0, #0x400000	@ set bit 22, mov to mvn instruction
-#endif
 	b	2f
 1:	ldr	ip, [r7, r3]
 #ifdef CONFIG_CPU_ENDIAN_BE8
@@ -687,7 +683,7 @@
 	tst	ip, #0x000f0000	@ check the rotation field
 	orrne	ip, ip, r6, lsl #24 @ mask in offset bits 31-24
 	biceq	ip, ip, #0x00004000 @ clear bit 22
-	orreq	ip, ip, r0      @ mask in offset bits 7-0
+	orreq	ip, ip, r0, ror #8  @ mask in offset bits 7-0
 #else
 	bic	ip, ip, #0x000000ff
 	tst	ip, #0xf00	@ check the rotation field
--- linux-4.4.0.orig/arch/arm/kernel/hw_breakpoint.c
+++ linux-4.4.0/arch/arm/kernel/hw_breakpoint.c
@@ -688,6 +688,12 @@
 	arch_install_hw_breakpoint(bp);
 }
 
+static int watchpoint_fault_on_uaccess(struct pt_regs *regs,
+				       struct arch_hw_breakpoint *info)
+{
+	return !user_mode(regs) && info->ctrl.privilege == ARM_BREAKPOINT_USER;
+}
+
 static void watchpoint_handler(unsigned long addr, unsigned int fsr,
 			       struct pt_regs *regs)
 {
@@ -747,16 +753,27 @@
 		}
 
 		pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
+
+		/*
+		 * If we triggered a user watchpoint from a uaccess routine,
+		 * then handle the stepping ourselves since userspace really
+		 * can't help us with this.
+		 */
+		if (watchpoint_fault_on_uaccess(regs, info))
+			goto step;
+
 		perf_bp_event(wp, regs);
 
 		/*
-		 * If no overflow handler is present, insert a temporary
-		 * mismatch breakpoint so we can single-step over the
-		 * watchpoint trigger.
+		 * Defer stepping to the overflow handler if one is installed.
+		 * Otherwise, insert a temporary mismatch breakpoint so that
+		 * we can single-step over the watchpoint trigger.
 		 */
-		if (!wp->overflow_handler)
-			enable_single_step(wp, instruction_pointer(regs));
+		if (wp->overflow_handler)
+			goto unlock;
 
+step:
+		enable_single_step(wp, instruction_pointer(regs));
 unlock:
 		rcu_read_unlock();
 	}
@@ -1066,6 +1083,22 @@
 		return 0;
 	}
 
+	/*
+	 * Scorpion CPUs (at least those in APQ8060) seem to set DBGPRSR.SPD
+	 * whenever a WFI is issued, even if the core is not powered down, in
+	 * violation of the architecture.  When DBGPRSR.SPD is set, accesses to
+	 * breakpoint and watchpoint registers are treated as undefined, so
+	 * this results in boot time and runtime failures when these are
+	 * accessed and we unexpectedly take a trap.
+	 *
+	 * It's not clear if/how this can be worked around, so we blacklist
+	 * Scorpion CPUs to avoid these issues.
+	*/
+	if (read_cpuid_part() == ARM_CPU_PART_SCORPION) {
+		pr_info("Scorpion CPU detected. Hardware breakpoints and watchpoints disabled\n");
+		return 0;
+	}
+
 	has_ossr = core_has_os_save_restore();
 
 	/* Determine how many BRPs/WRPs are available. */
--- linux-4.4.0.orig/arch/arm/kernel/irq.c
+++ linux-4.4.0/arch/arm/kernel/irq.c
@@ -31,7 +31,6 @@
 #include <linux/smp.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
-#include <linux/ratelimit.h>
 #include <linux/errno.h>
 #include <linux/list.h>
 #include <linux/kallsyms.h>
@@ -119,64 +118,3 @@
 	return nr_irqs;
 }
 #endif
-
-#ifdef CONFIG_HOTPLUG_CPU
-static bool migrate_one_irq(struct irq_desc *desc)
-{
-	struct irq_data *d = irq_desc_get_irq_data(desc);
-	const struct cpumask *affinity = irq_data_get_affinity_mask(d);
-	struct irq_chip *c;
-	bool ret = false;
-
-	/*
-	 * If this is a per-CPU interrupt, or the affinity does not
-	 * include this CPU, then we have nothing to do.
-	 */
-	if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity))
-		return false;
-
-	if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
-		affinity = cpu_online_mask;
-		ret = true;
-	}
-
-	c = irq_data_get_irq_chip(d);
-	if (!c->irq_set_affinity)
-		pr_debug("IRQ%u: unable to set affinity\n", d->irq);
-	else if (c->irq_set_affinity(d, affinity, false) == IRQ_SET_MASK_OK && ret)
-		cpumask_copy(irq_data_get_affinity_mask(d), affinity);
-
-	return ret;
-}
-
-/*
- * The current CPU has been marked offline.  Migrate IRQs off this CPU.
- * If the affinity settings do not allow other CPUs, force them onto any
- * available CPU.
- *
- * Note: we must iterate over all IRQs, whether they have an attached
- * action structure or not, as we need to get chained interrupts too.
- */
-void migrate_irqs(void)
-{
-	unsigned int i;
-	struct irq_desc *desc;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	for_each_irq_desc(i, desc) {
-		bool affinity_broken;
-
-		raw_spin_lock(&desc->lock);
-		affinity_broken = migrate_one_irq(desc);
-		raw_spin_unlock(&desc->lock);
-
-		if (affinity_broken)
-			pr_warn_ratelimited("IRQ%u no longer affine to CPU%u\n",
-				i, smp_processor_id());
-	}
-
-	local_irq_restore(flags);
-}
-#endif /* CONFIG_HOTPLUG_CPU */
--- linux-4.4.0.orig/arch/arm/kernel/machine_kexec.c
+++ linux-4.4.0/arch/arm/kernel/machine_kexec.c
@@ -87,8 +87,11 @@
 
 	set_cpu_online(smp_processor_id(), false);
 	atomic_dec(&waiting_for_crash_ipi);
-	while (1)
+
+	while (1) {
 		cpu_relax();
+		wfe();
+	}
 }
 
 static void machine_kexec_mask_interrupts(void)
--- linux-4.4.0.orig/arch/arm/kernel/module-plts.c
+++ linux-4.4.0/arch/arm/kernel/module-plts.c
@@ -32,7 +32,7 @@
 
 static bool in_init(const struct module *mod, u32 addr)
 {
-	return addr - (u32)mod->module_init < mod->init_size;
+	return addr - (u32)mod->init_layout.base < mod->init_layout.size;
 }
 
 u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
--- linux-4.4.0.orig/arch/arm/kernel/patch.c
+++ linux-4.4.0/arch/arm/kernel/patch.c
@@ -15,7 +15,7 @@
 	unsigned int insn;
 };
 
-static DEFINE_SPINLOCK(patch_lock);
+static DEFINE_RAW_SPINLOCK(patch_lock);
 
 static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags)
 	__acquires(&patch_lock)
@@ -32,7 +32,7 @@
 		return addr;
 
 	if (flags)
-		spin_lock_irqsave(&patch_lock, *flags);
+		raw_spin_lock_irqsave(&patch_lock, *flags);
 	else
 		__acquire(&patch_lock);
 
@@ -47,7 +47,7 @@
 	clear_fixmap(fixmap);
 
 	if (flags)
-		spin_unlock_irqrestore(&patch_lock, *flags);
+		raw_spin_unlock_irqrestore(&patch_lock, *flags);
 	else
 		__release(&patch_lock);
 }
--- linux-4.4.0.orig/arch/arm/kernel/perf_event_v7.c
+++ linux-4.4.0/arch/arm/kernel/perf_event_v7.c
@@ -35,133 +35,117 @@
  * but the encodings are considered to be `reserved' in the case that
  * they are not available.
  */
-enum armv7_perf_types {
-	ARMV7_PERFCTR_PMNC_SW_INCR			= 0x00,
-	ARMV7_PERFCTR_L1_ICACHE_REFILL			= 0x01,
-	ARMV7_PERFCTR_ITLB_REFILL			= 0x02,
-	ARMV7_PERFCTR_L1_DCACHE_REFILL			= 0x03,
-	ARMV7_PERFCTR_L1_DCACHE_ACCESS			= 0x04,
-	ARMV7_PERFCTR_DTLB_REFILL			= 0x05,
-	ARMV7_PERFCTR_MEM_READ				= 0x06,
-	ARMV7_PERFCTR_MEM_WRITE				= 0x07,
-	ARMV7_PERFCTR_INSTR_EXECUTED			= 0x08,
-	ARMV7_PERFCTR_EXC_TAKEN				= 0x09,
-	ARMV7_PERFCTR_EXC_EXECUTED			= 0x0A,
-	ARMV7_PERFCTR_CID_WRITE				= 0x0B,
-
-	/*
-	 * ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS.
-	 * It counts:
-	 *  - all (taken) branch instructions,
-	 *  - instructions that explicitly write the PC,
-	 *  - exception generating instructions.
-	 */
-	ARMV7_PERFCTR_PC_WRITE				= 0x0C,
-	ARMV7_PERFCTR_PC_IMM_BRANCH			= 0x0D,
-	ARMV7_PERFCTR_PC_PROC_RETURN			= 0x0E,
-	ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS		= 0x0F,
-	ARMV7_PERFCTR_PC_BRANCH_MIS_PRED		= 0x10,
-	ARMV7_PERFCTR_CLOCK_CYCLES			= 0x11,
-	ARMV7_PERFCTR_PC_BRANCH_PRED			= 0x12,
-
-	/* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */
-	ARMV7_PERFCTR_MEM_ACCESS			= 0x13,
-	ARMV7_PERFCTR_L1_ICACHE_ACCESS			= 0x14,
-	ARMV7_PERFCTR_L1_DCACHE_WB			= 0x15,
-	ARMV7_PERFCTR_L2_CACHE_ACCESS			= 0x16,
-	ARMV7_PERFCTR_L2_CACHE_REFILL			= 0x17,
-	ARMV7_PERFCTR_L2_CACHE_WB			= 0x18,
-	ARMV7_PERFCTR_BUS_ACCESS			= 0x19,
-	ARMV7_PERFCTR_MEM_ERROR				= 0x1A,
-	ARMV7_PERFCTR_INSTR_SPEC			= 0x1B,
-	ARMV7_PERFCTR_TTBR_WRITE			= 0x1C,
-	ARMV7_PERFCTR_BUS_CYCLES			= 0x1D,
+#define ARMV7_PERFCTR_PMNC_SW_INCR			0x00
+#define ARMV7_PERFCTR_L1_ICACHE_REFILL			0x01
+#define ARMV7_PERFCTR_ITLB_REFILL			0x02
+#define ARMV7_PERFCTR_L1_DCACHE_REFILL			0x03
+#define ARMV7_PERFCTR_L1_DCACHE_ACCESS			0x04
+#define ARMV7_PERFCTR_DTLB_REFILL			0x05
+#define ARMV7_PERFCTR_MEM_READ				0x06
+#define ARMV7_PERFCTR_MEM_WRITE				0x07
+#define ARMV7_PERFCTR_INSTR_EXECUTED			0x08
+#define ARMV7_PERFCTR_EXC_TAKEN				0x09
+#define ARMV7_PERFCTR_EXC_EXECUTED			0x0A
+#define ARMV7_PERFCTR_CID_WRITE				0x0B
 
-	ARMV7_PERFCTR_CPU_CYCLES			= 0xFF
-};
+/*
+ * ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS.
+ * It counts:
+ *  - all (taken) branch instructions,
+ *  - instructions that explicitly write the PC,
+ *  - exception generating instructions.
+ */
+#define ARMV7_PERFCTR_PC_WRITE				0x0C
+#define ARMV7_PERFCTR_PC_IMM_BRANCH			0x0D
+#define ARMV7_PERFCTR_PC_PROC_RETURN			0x0E
+#define ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS		0x0F
+#define ARMV7_PERFCTR_PC_BRANCH_MIS_PRED		0x10
+#define ARMV7_PERFCTR_CLOCK_CYCLES			0x11
+#define ARMV7_PERFCTR_PC_BRANCH_PRED			0x12
+
+/* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */
+#define ARMV7_PERFCTR_MEM_ACCESS			0x13
+#define ARMV7_PERFCTR_L1_ICACHE_ACCESS			0x14
+#define ARMV7_PERFCTR_L1_DCACHE_WB			0x15
+#define ARMV7_PERFCTR_L2_CACHE_ACCESS			0x16
+#define ARMV7_PERFCTR_L2_CACHE_REFILL			0x17
+#define ARMV7_PERFCTR_L2_CACHE_WB			0x18
+#define ARMV7_PERFCTR_BUS_ACCESS			0x19
+#define ARMV7_PERFCTR_MEM_ERROR				0x1A
+#define ARMV7_PERFCTR_INSTR_SPEC			0x1B
+#define ARMV7_PERFCTR_TTBR_WRITE			0x1C
+#define ARMV7_PERFCTR_BUS_CYCLES			0x1D
+
+#define ARMV7_PERFCTR_CPU_CYCLES			0xFF
 
 /* ARMv7 Cortex-A8 specific event types */
-enum armv7_a8_perf_types {
-	ARMV7_A8_PERFCTR_L2_CACHE_ACCESS		= 0x43,
-	ARMV7_A8_PERFCTR_L2_CACHE_REFILL		= 0x44,
-	ARMV7_A8_PERFCTR_L1_ICACHE_ACCESS		= 0x50,
-	ARMV7_A8_PERFCTR_STALL_ISIDE			= 0x56,
-};
+#define ARMV7_A8_PERFCTR_L2_CACHE_ACCESS		0x43
+#define ARMV7_A8_PERFCTR_L2_CACHE_REFILL		0x44
+#define ARMV7_A8_PERFCTR_L1_ICACHE_ACCESS		0x50
+#define ARMV7_A8_PERFCTR_STALL_ISIDE			0x56
 
 /* ARMv7 Cortex-A9 specific event types */
-enum armv7_a9_perf_types {
-	ARMV7_A9_PERFCTR_INSTR_CORE_RENAME		= 0x68,
-	ARMV7_A9_PERFCTR_STALL_ICACHE			= 0x60,
-	ARMV7_A9_PERFCTR_STALL_DISPATCH			= 0x66,
-};
+#define ARMV7_A9_PERFCTR_INSTR_CORE_RENAME		0x68
+#define ARMV7_A9_PERFCTR_STALL_ICACHE			0x60
+#define ARMV7_A9_PERFCTR_STALL_DISPATCH			0x66
 
 /* ARMv7 Cortex-A5 specific event types */
-enum armv7_a5_perf_types {
-	ARMV7_A5_PERFCTR_PREFETCH_LINEFILL		= 0xc2,
-	ARMV7_A5_PERFCTR_PREFETCH_LINEFILL_DROP		= 0xc3,
-};
+#define ARMV7_A5_PERFCTR_PREFETCH_LINEFILL		0xc2
+#define ARMV7_A5_PERFCTR_PREFETCH_LINEFILL_DROP		0xc3
 
 /* ARMv7 Cortex-A15 specific event types */
-enum armv7_a15_perf_types {
-	ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_READ		= 0x40,
-	ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_WRITE	= 0x41,
-	ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_READ		= 0x42,
-	ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_WRITE	= 0x43,
-
-	ARMV7_A15_PERFCTR_DTLB_REFILL_L1_READ		= 0x4C,
-	ARMV7_A15_PERFCTR_DTLB_REFILL_L1_WRITE		= 0x4D,
-
-	ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_READ		= 0x50,
-	ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_WRITE		= 0x51,
-	ARMV7_A15_PERFCTR_L2_CACHE_REFILL_READ		= 0x52,
-	ARMV7_A15_PERFCTR_L2_CACHE_REFILL_WRITE		= 0x53,
+#define ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_READ		0x40
+#define ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_WRITE	0x41
+#define ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_READ		0x42
+#define ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_WRITE	0x43
+
+#define ARMV7_A15_PERFCTR_DTLB_REFILL_L1_READ		0x4C
+#define ARMV7_A15_PERFCTR_DTLB_REFILL_L1_WRITE		0x4D
+
+#define ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_READ		0x50
+#define ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_WRITE		0x51
+#define ARMV7_A15_PERFCTR_L2_CACHE_REFILL_READ		0x52
+#define ARMV7_A15_PERFCTR_L2_CACHE_REFILL_WRITE		0x53
 
-	ARMV7_A15_PERFCTR_PC_WRITE_SPEC			= 0x76,
-};
+#define ARMV7_A15_PERFCTR_PC_WRITE_SPEC			0x76
 
 /* ARMv7 Cortex-A12 specific event types */
-enum armv7_a12_perf_types {
-	ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ		= 0x40,
-	ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE	= 0x41,
+#define ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ		0x40
+#define ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE	0x41
 
-	ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ		= 0x50,
-	ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE		= 0x51,
+#define ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ		0x50
+#define ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE		0x51
 
-	ARMV7_A12_PERFCTR_PC_WRITE_SPEC			= 0x76,
+#define ARMV7_A12_PERFCTR_PC_WRITE_SPEC			0x76
 
-	ARMV7_A12_PERFCTR_PF_TLB_REFILL			= 0xe7,
-};
+#define ARMV7_A12_PERFCTR_PF_TLB_REFILL			0xe7
 
 /* ARMv7 Krait specific event types */
-enum krait_perf_types {
-	KRAIT_PMRESR0_GROUP0				= 0xcc,
-	KRAIT_PMRESR1_GROUP0				= 0xd0,
-	KRAIT_PMRESR2_GROUP0				= 0xd4,
-	KRAIT_VPMRESR0_GROUP0				= 0xd8,
+#define KRAIT_PMRESR0_GROUP0				0xcc
+#define KRAIT_PMRESR1_GROUP0				0xd0
+#define KRAIT_PMRESR2_GROUP0				0xd4
+#define KRAIT_VPMRESR0_GROUP0				0xd8
 
-	KRAIT_PERFCTR_L1_ICACHE_ACCESS			= 0x10011,
-	KRAIT_PERFCTR_L1_ICACHE_MISS			= 0x10010,
+#define KRAIT_PERFCTR_L1_ICACHE_ACCESS			0x10011
+#define KRAIT_PERFCTR_L1_ICACHE_MISS			0x10010
 
-	KRAIT_PERFCTR_L1_ITLB_ACCESS			= 0x12222,
-	KRAIT_PERFCTR_L1_DTLB_ACCESS			= 0x12210,
-};
+#define KRAIT_PERFCTR_L1_ITLB_ACCESS			0x12222
+#define KRAIT_PERFCTR_L1_DTLB_ACCESS			0x12210
 
 /* ARMv7 Scorpion specific event types */
-enum scorpion_perf_types {
-	SCORPION_LPM0_GROUP0				= 0x4c,
-	SCORPION_LPM1_GROUP0				= 0x50,
-	SCORPION_LPM2_GROUP0				= 0x54,
-	SCORPION_L2LPM_GROUP0				= 0x58,
-	SCORPION_VLPM_GROUP0				= 0x5c,
+#define SCORPION_LPM0_GROUP0				0x4c
+#define SCORPION_LPM1_GROUP0				0x50
+#define SCORPION_LPM2_GROUP0				0x54
+#define SCORPION_L2LPM_GROUP0				0x58
+#define SCORPION_VLPM_GROUP0				0x5c
 
-	SCORPION_ICACHE_ACCESS				= 0x10053,
-	SCORPION_ICACHE_MISS				= 0x10052,
+#define SCORPION_ICACHE_ACCESS				0x10053
+#define SCORPION_ICACHE_MISS				0x10052
 
-	SCORPION_DTLB_ACCESS				= 0x12013,
-	SCORPION_DTLB_MISS				= 0x12012,
+#define SCORPION_DTLB_ACCESS				0x12013
+#define SCORPION_DTLB_MISS				0x12012
 
-	SCORPION_ITLB_MISS				= 0x12021,
-};
+#define SCORPION_ITLB_MISS				0x12021
 
 /*
  * Cortex-A8 HW events mapping
@@ -547,6 +531,134 @@
 	[C(BPU)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
 };
 
+PMU_FORMAT_ATTR(event, "config:0-7");
+
+static struct attribute *armv7_pmu_format_attrs[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group armv7_pmu_format_attr_group = {
+	.name = "format",
+	.attrs = armv7_pmu_format_attrs,
+};
+
+#define ARMV7_EVENT_ATTR_RESOLVE(m) #m
+#define ARMV7_EVENT_ATTR(name, config) \
+	PMU_EVENT_ATTR_STRING(name, armv7_event_attr_##name, \
+			      "event=" ARMV7_EVENT_ATTR_RESOLVE(config))
+
+ARMV7_EVENT_ATTR(sw_incr, ARMV7_PERFCTR_PMNC_SW_INCR);
+ARMV7_EVENT_ATTR(l1i_cache_refill, ARMV7_PERFCTR_L1_ICACHE_REFILL);
+ARMV7_EVENT_ATTR(l1i_tlb_refill, ARMV7_PERFCTR_ITLB_REFILL);
+ARMV7_EVENT_ATTR(l1d_cache_refill, ARMV7_PERFCTR_L1_DCACHE_REFILL);
+ARMV7_EVENT_ATTR(l1d_cache, ARMV7_PERFCTR_L1_DCACHE_ACCESS);
+ARMV7_EVENT_ATTR(l1d_tlb_refill, ARMV7_PERFCTR_DTLB_REFILL);
+ARMV7_EVENT_ATTR(ld_retired, ARMV7_PERFCTR_MEM_READ);
+ARMV7_EVENT_ATTR(st_retired, ARMV7_PERFCTR_MEM_WRITE);
+ARMV7_EVENT_ATTR(inst_retired, ARMV7_PERFCTR_INSTR_EXECUTED);
+ARMV7_EVENT_ATTR(exc_taken, ARMV7_PERFCTR_EXC_TAKEN);
+ARMV7_EVENT_ATTR(exc_return, ARMV7_PERFCTR_EXC_EXECUTED);
+ARMV7_EVENT_ATTR(cid_write_retired, ARMV7_PERFCTR_CID_WRITE);
+ARMV7_EVENT_ATTR(pc_write_retired, ARMV7_PERFCTR_PC_WRITE);
+ARMV7_EVENT_ATTR(br_immed_retired, ARMV7_PERFCTR_PC_IMM_BRANCH);
+ARMV7_EVENT_ATTR(br_return_retired, ARMV7_PERFCTR_PC_PROC_RETURN);
+ARMV7_EVENT_ATTR(unaligned_ldst_retired, ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS);
+ARMV7_EVENT_ATTR(br_mis_pred, ARMV7_PERFCTR_PC_BRANCH_MIS_PRED);
+ARMV7_EVENT_ATTR(cpu_cycles, ARMV7_PERFCTR_CLOCK_CYCLES);
+ARMV7_EVENT_ATTR(br_pred, ARMV7_PERFCTR_PC_BRANCH_PRED);
+
+static struct attribute *armv7_pmuv1_event_attrs[] = {
+	&armv7_event_attr_sw_incr.attr.attr,
+	&armv7_event_attr_l1i_cache_refill.attr.attr,
+	&armv7_event_attr_l1i_tlb_refill.attr.attr,
+	&armv7_event_attr_l1d_cache_refill.attr.attr,
+	&armv7_event_attr_l1d_cache.attr.attr,
+	&armv7_event_attr_l1d_tlb_refill.attr.attr,
+	&armv7_event_attr_ld_retired.attr.attr,
+	&armv7_event_attr_st_retired.attr.attr,
+	&armv7_event_attr_inst_retired.attr.attr,
+	&armv7_event_attr_exc_taken.attr.attr,
+	&armv7_event_attr_exc_return.attr.attr,
+	&armv7_event_attr_cid_write_retired.attr.attr,
+	&armv7_event_attr_pc_write_retired.attr.attr,
+	&armv7_event_attr_br_immed_retired.attr.attr,
+	&armv7_event_attr_br_return_retired.attr.attr,
+	&armv7_event_attr_unaligned_ldst_retired.attr.attr,
+	&armv7_event_attr_br_mis_pred.attr.attr,
+	&armv7_event_attr_cpu_cycles.attr.attr,
+	&armv7_event_attr_br_pred.attr.attr,
+	NULL,
+};
+
+static struct attribute_group armv7_pmuv1_events_attr_group = {
+	.name = "events",
+	.attrs = armv7_pmuv1_event_attrs,
+};
+
+static const struct attribute_group *armv7_pmuv1_attr_groups[] = {
+	&armv7_pmuv1_events_attr_group,
+	&armv7_pmu_format_attr_group,
+	NULL,
+};
+
+ARMV7_EVENT_ATTR(mem_access, ARMV7_PERFCTR_MEM_ACCESS);
+ARMV7_EVENT_ATTR(l1i_cache, ARMV7_PERFCTR_L1_ICACHE_ACCESS);
+ARMV7_EVENT_ATTR(l1d_cache_wb, ARMV7_PERFCTR_L1_DCACHE_WB);
+ARMV7_EVENT_ATTR(l2d_cache, ARMV7_PERFCTR_L2_CACHE_ACCESS);
+ARMV7_EVENT_ATTR(l2d_cache_refill, ARMV7_PERFCTR_L2_CACHE_REFILL);
+ARMV7_EVENT_ATTR(l2d_cache_wb, ARMV7_PERFCTR_L2_CACHE_WB);
+ARMV7_EVENT_ATTR(bus_access, ARMV7_PERFCTR_BUS_ACCESS);
+ARMV7_EVENT_ATTR(memory_error, ARMV7_PERFCTR_MEM_ERROR);
+ARMV7_EVENT_ATTR(inst_spec, ARMV7_PERFCTR_INSTR_SPEC);
+ARMV7_EVENT_ATTR(ttbr_write_retired, ARMV7_PERFCTR_TTBR_WRITE);
+ARMV7_EVENT_ATTR(bus_cycles, ARMV7_PERFCTR_BUS_CYCLES);
+
+static struct attribute *armv7_pmuv2_event_attrs[] = {
+	&armv7_event_attr_sw_incr.attr.attr,
+	&armv7_event_attr_l1i_cache_refill.attr.attr,
+	&armv7_event_attr_l1i_tlb_refill.attr.attr,
+	&armv7_event_attr_l1d_cache_refill.attr.attr,
+	&armv7_event_attr_l1d_cache.attr.attr,
+	&armv7_event_attr_l1d_tlb_refill.attr.attr,
+	&armv7_event_attr_ld_retired.attr.attr,
+	&armv7_event_attr_st_retired.attr.attr,
+	&armv7_event_attr_inst_retired.attr.attr,
+	&armv7_event_attr_exc_taken.attr.attr,
+	&armv7_event_attr_exc_return.attr.attr,
+	&armv7_event_attr_cid_write_retired.attr.attr,
+	&armv7_event_attr_pc_write_retired.attr.attr,
+	&armv7_event_attr_br_immed_retired.attr.attr,
+	&armv7_event_attr_br_return_retired.attr.attr,
+	&armv7_event_attr_unaligned_ldst_retired.attr.attr,
+	&armv7_event_attr_br_mis_pred.attr.attr,
+	&armv7_event_attr_cpu_cycles.attr.attr,
+	&armv7_event_attr_br_pred.attr.attr,
+	&armv7_event_attr_mem_access.attr.attr,
+	&armv7_event_attr_l1i_cache.attr.attr,
+	&armv7_event_attr_l1d_cache_wb.attr.attr,
+	&armv7_event_attr_l2d_cache.attr.attr,
+	&armv7_event_attr_l2d_cache_refill.attr.attr,
+	&armv7_event_attr_l2d_cache_wb.attr.attr,
+	&armv7_event_attr_bus_access.attr.attr,
+	&armv7_event_attr_memory_error.attr.attr,
+	&armv7_event_attr_inst_spec.attr.attr,
+	&armv7_event_attr_ttbr_write_retired.attr.attr,
+	&armv7_event_attr_bus_cycles.attr.attr,
+	NULL,
+};
+
+static struct attribute_group armv7_pmuv2_events_attr_group = {
+	.name = "events",
+	.attrs = armv7_pmuv2_event_attrs,
+};
+
+static const struct attribute_group *armv7_pmuv2_attr_groups[] = {
+	&armv7_pmuv2_events_attr_group,
+	&armv7_pmu_format_attr_group,
+	NULL,
+};
+
 /*
  * Perf Events' indices
  */
@@ -1085,6 +1197,7 @@
 	armv7pmu_init(cpu_pmu);
 	cpu_pmu->name		= "armv7_cortex_a8";
 	cpu_pmu->map_event	= armv7_a8_map_event;
+	cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
 	return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1093,6 +1206,7 @@
 	armv7pmu_init(cpu_pmu);
 	cpu_pmu->name		= "armv7_cortex_a9";
 	cpu_pmu->map_event	= armv7_a9_map_event;
+	cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
 	return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1101,6 +1215,7 @@
 	armv7pmu_init(cpu_pmu);
 	cpu_pmu->name		= "armv7_cortex_a5";
 	cpu_pmu->map_event	= armv7_a5_map_event;
+	cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
 	return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1110,6 +1225,7 @@
 	cpu_pmu->name		= "armv7_cortex_a15";
 	cpu_pmu->map_event	= armv7_a15_map_event;
 	cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+	cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
 	return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1119,6 +1235,7 @@
 	cpu_pmu->name		= "armv7_cortex_a7";
 	cpu_pmu->map_event	= armv7_a7_map_event;
 	cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+	cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
 	return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1128,6 +1245,7 @@
 	cpu_pmu->name		= "armv7_cortex_a12";
 	cpu_pmu->map_event	= armv7_a12_map_event;
 	cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+	cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
 	return armv7_probe_num_events(cpu_pmu);
 }
 
@@ -1135,6 +1253,7 @@
 {
 	int ret = armv7_a12_pmu_init(cpu_pmu);
 	cpu_pmu->name = "armv7_cortex_a17";
+	cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/arm/kernel/pj4-cp0.c
+++ linux-4.4.0/arch/arm/kernel/pj4-cp0.c
@@ -66,9 +66,13 @@
 
 	__asm__ __volatile__ (
 		"mcr	p15, 0, %1, c1, c0, 2\n\t"
+#ifdef CONFIG_THUMB2_KERNEL
+		"isb\n\t"
+#else
 		"mrc	p15, 0, %0, c1, c0, 2\n\t"
 		"mov	%0, %0\n\t"
 		"sub	pc, pc, #4\n\t"
+#endif
 		: "=r" (temp) : "r" (value));
 }
 
--- linux-4.4.0.orig/arch/arm/kernel/ptrace.c
+++ linux-4.4.0/arch/arm/kernel/ptrace.c
@@ -227,8 +227,8 @@
 };
 
 static struct undef_hook thumb_break_hook = {
-	.instr_mask	= 0xffff,
-	.instr_val	= 0xde01,
+	.instr_mask	= 0xffffffff,
+	.instr_val	= 0x0000de01,
 	.cpsr_mask	= PSR_T_BIT,
 	.cpsr_val	= PSR_T_BIT,
 	.fn		= break_trap,
@@ -600,7 +600,7 @@
 		   const void *kbuf, const void __user *ubuf)
 {
 	int ret;
-	struct pt_regs newregs;
+	struct pt_regs newregs = *task_pt_regs(target);
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 				 &newregs,
@@ -733,8 +733,8 @@
 	if (ret)
 		return ret;
 
-	vfp_flush_hwstate(thread);
 	thread->vfpstate.hard = new_vfp;
+	vfp_flush_hwstate(thread);
 
 	return 0;
 }
@@ -932,18 +932,19 @@
 {
 	current_thread_info()->syscall = scno;
 
-	/* Do the secure computing check first; failures should be fast. */
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
+
+	/* Do seccomp after ptrace; syscall may have changed. */
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
 	if (secure_computing() == -1)
 		return -1;
 #else
 	/* XXX: remove this once OABI gets fixed */
-	secure_computing_strict(scno);
+	secure_computing_strict(current_thread_info()->syscall);
 #endif
 
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
-
+	/* Tracer or seccomp may have changed syscall. */
 	scno = current_thread_info()->syscall;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
--- linux-4.4.0.orig/arch/arm/kernel/setup.c
+++ linux-4.4.0/arch/arm/kernel/setup.c
@@ -113,6 +113,11 @@
 
 #ifdef MULTI_CPU
 struct processor processor __read_mostly;
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+struct processor *cpu_vtable[NR_CPUS] = {
+	[0] = &processor,
+};
+#endif
 #endif
 #ifdef MULTI_TLB
 struct cpu_tlb_fns cpu_tlb __read_mostly;
@@ -599,28 +604,33 @@
 }
 #endif
 
-static void __init setup_processor(void)
+/*
+ * locate processor in the list of supported processor types.  The linker
+ * builds this table for us from the entries in arch/arm/mm/proc-*.S
+ */
+struct proc_info_list *lookup_processor(u32 midr)
 {
-	struct proc_info_list *list;
+	struct proc_info_list *list = lookup_processor_type(midr);
 
-	/*
-	 * locate processor in the list of supported processor
-	 * types.  The linker builds this table for us from the
-	 * entries in arch/arm/mm/proc-*.S
-	 */
-	list = lookup_processor_type(read_cpuid_id());
 	if (!list) {
-		pr_err("CPU configuration botched (ID %08x), unable to continue.\n",
-		       read_cpuid_id());
-		while (1);
+		pr_err("CPU%u: configuration botched (ID %08x), CPU halted\n",
+		       smp_processor_id(), midr);
+		while (1)
+		/* can't use cpu_relax() here as it may require MMU setup */;
 	}
 
+	return list;
+}
+
+static void __init setup_processor(void)
+{
+	unsigned int midr = read_cpuid_id();
+	struct proc_info_list *list = lookup_processor(midr);
+
 	cpu_name = list->cpu_name;
 	__cpu_architecture = __get_cpu_architecture();
 
-#ifdef MULTI_CPU
-	processor = *list->proc;
-#endif
+	init_proc_vtable(list->proc);
 #ifdef MULTI_TLB
 	cpu_tlb = *list->tlb;
 #endif
@@ -632,7 +642,7 @@
 #endif
 
 	pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
-		cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
+		list->cpu_name, midr, midr & 15,
 		proc_arch[cpu_architecture()], get_cr());
 
 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
--- linux-4.4.0.orig/arch/arm/kernel/signal.c
+++ linux-4.4.0/arch/arm/kernel/signal.c
@@ -94,34 +94,34 @@
 
 static int preserve_vfp_context(struct vfp_sigframe __user *frame)
 {
-	const unsigned long magic = VFP_MAGIC;
-	const unsigned long size = VFP_STORAGE_SIZE;
+	struct vfp_sigframe kframe;
 	int err = 0;
 
-	__put_user_error(magic, &frame->magic, err);
-	__put_user_error(size, &frame->size, err);
+	memset(&kframe, 0, sizeof(kframe));
+	kframe.magic = VFP_MAGIC;
+	kframe.size = VFP_STORAGE_SIZE;
 
+	err = vfp_preserve_user_clear_hwstate(&kframe.ufp, &kframe.ufp_exc);
 	if (err)
-		return -EFAULT;
+		return err;
 
-	return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc);
+	return __copy_to_user(frame, &kframe, sizeof(kframe));
 }
 
-static int restore_vfp_context(struct vfp_sigframe __user *frame)
+static int restore_vfp_context(struct vfp_sigframe __user *auxp)
 {
-	unsigned long magic;
-	unsigned long size;
-	int err = 0;
+	struct vfp_sigframe frame;
+	int err;
 
-	__get_user_error(magic, &frame->magic, err);
-	__get_user_error(size, &frame->size, err);
+	err = __copy_from_user(&frame, (char __user *) auxp, sizeof(frame));
 
 	if (err)
-		return -EFAULT;
-	if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
+		return err;
+
+	if (frame.magic != VFP_MAGIC || frame.size != VFP_STORAGE_SIZE)
 		return -EINVAL;
 
-	return vfp_restore_user_hwstate(&frame->ufp, &frame->ufp_exc);
+	return vfp_restore_user_hwstate(&frame.ufp, &frame.ufp_exc);
 }
 
 #endif
@@ -141,6 +141,7 @@
 
 static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
 {
+	struct sigcontext context;
 	struct aux_sigframe __user *aux;
 	sigset_t set;
 	int err;
@@ -149,23 +150,26 @@
 	if (err == 0)
 		set_current_blocked(&set);
 
-	__get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
-	__get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
-	__get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
-	__get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
-	__get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
-	__get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
-	__get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
-	__get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
-	__get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
-	__get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
-	__get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
-	__get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
-	__get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
-	__get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
-	__get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
-	__get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
-	__get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
+	err |= __copy_from_user(&context, &sf->uc.uc_mcontext, sizeof(context));
+	if (err == 0) {
+		regs->ARM_r0 = context.arm_r0;
+		regs->ARM_r1 = context.arm_r1;
+		regs->ARM_r2 = context.arm_r2;
+		regs->ARM_r3 = context.arm_r3;
+		regs->ARM_r4 = context.arm_r4;
+		regs->ARM_r5 = context.arm_r5;
+		regs->ARM_r6 = context.arm_r6;
+		regs->ARM_r7 = context.arm_r7;
+		regs->ARM_r8 = context.arm_r8;
+		regs->ARM_r9 = context.arm_r9;
+		regs->ARM_r10 = context.arm_r10;
+		regs->ARM_fp = context.arm_fp;
+		regs->ARM_ip = context.arm_ip;
+		regs->ARM_sp = context.arm_sp;
+		regs->ARM_lr = context.arm_lr;
+		regs->ARM_pc = context.arm_pc;
+		regs->ARM_cpsr = context.arm_cpsr;
+	}
 
 	err |= !valid_user_regs(regs);
 
@@ -253,30 +257,35 @@
 setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
 {
 	struct aux_sigframe __user *aux;
+	struct sigcontext context;
 	int err = 0;
 
-	__put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
-	__put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
-	__put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
-	__put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
-	__put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
-	__put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
-	__put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
-	__put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
-	__put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
-	__put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
-	__put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
-	__put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
-	__put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
-	__put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
-	__put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
-	__put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
-	__put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
-
-	__put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err);
-	__put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err);
-	__put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err);
-	__put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
+	context = (struct sigcontext) {
+		.arm_r0        = regs->ARM_r0,
+		.arm_r1        = regs->ARM_r1,
+		.arm_r2        = regs->ARM_r2,
+		.arm_r3        = regs->ARM_r3,
+		.arm_r4        = regs->ARM_r4,
+		.arm_r5        = regs->ARM_r5,
+		.arm_r6        = regs->ARM_r6,
+		.arm_r7        = regs->ARM_r7,
+		.arm_r8        = regs->ARM_r8,
+		.arm_r9        = regs->ARM_r9,
+		.arm_r10       = regs->ARM_r10,
+		.arm_fp        = regs->ARM_fp,
+		.arm_ip        = regs->ARM_ip,
+		.arm_sp        = regs->ARM_sp,
+		.arm_lr        = regs->ARM_lr,
+		.arm_pc        = regs->ARM_pc,
+		.arm_cpsr      = regs->ARM_cpsr,
+
+		.trap_no       = current->thread.trap_no,
+		.error_code    = current->thread.error_code,
+		.fault_address = current->thread.address,
+		.oldmask       = set->sig[0],
+	};
+
+	err |= __copy_to_user(&sf->uc.uc_mcontext, &context, sizeof(context));
 
 	err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
 
@@ -293,7 +302,7 @@
 	if (err == 0)
 		err |= preserve_vfp_context(&aux->vfp);
 #endif
-	__put_user_error(0, &aux->end_magic, err);
+	err |= __put_user(0, &aux->end_magic);
 
 	return err;
 }
@@ -425,7 +434,7 @@
 	/*
 	 * Set uc.uc_flags to a value which sc.trap_no would never have.
 	 */
-	__put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err);
+	err = __put_user(0x5ac3c35a, &frame->uc.uc_flags);
 
 	err |= setup_sigframe(frame, regs, set);
 	if (err == 0)
@@ -445,8 +454,8 @@
 
 	err |= copy_siginfo_to_user(&frame->info, &ksig->info);
 
-	__put_user_error(0, &frame->sig.uc.uc_flags, err);
-	__put_user_error(NULL, &frame->sig.uc.uc_link, err);
+	err |= __put_user(0, &frame->sig.uc.uc_flags);
+	err |= __put_user(NULL, &frame->sig.uc.uc_link);
 
 	err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp);
 	err |= setup_sigframe(&frame->sig, regs, set);
--- linux-4.4.0.orig/arch/arm/kernel/sleep.S
+++ linux-4.4.0/arch/arm/kernel/sleep.S
@@ -119,6 +119,14 @@
 	.text
 	.align
 
+#ifdef CONFIG_MCPM
+	.arm
+THUMB(	.thumb			)
+ENTRY(cpu_resume_no_hyp)
+ARM_BE8(setend be)			@ ensure we are in BE mode
+	b	no_hyp
+#endif
+
 #ifdef CONFIG_MMU
 	.arm
 ENTRY(cpu_resume_arm)
@@ -134,6 +142,7 @@
 	bl	__hyp_stub_install_secondary
 #endif
 	safe_svcmode_maskall r1
+no_hyp:
 	mov	r1, #0
 	ALT_SMP(mrc p15, 0, r0, c0, c0, 5)
 	ALT_UP_B(1f)
@@ -163,6 +172,9 @@
 #ifdef CONFIG_MMU
 ENDPROC(cpu_resume_arm)
 #endif
+#ifdef CONFIG_MCPM
+ENDPROC(cpu_resume_no_hyp)
+#endif
 
 	.align 2
 _sleep_save_sp:
--- linux-4.4.0.orig/arch/arm/kernel/smccc-call.S
+++ linux-4.4.0/arch/arm/kernel/smccc-call.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/linkage.h>
+
+#include <asm/opcodes-sec.h>
+#include <asm/opcodes-virt.h>
+#include <asm/unwind.h>
+
+	/*
+	 * Wrap c macros in asm macros to delay expansion until after the
+	 * SMCCC asm macro is expanded.
+	 */
+	.macro SMCCC_SMC
+	__SMC(0)
+	.endm
+
+	.macro SMCCC_HVC
+	__HVC(0)
+	.endm
+
+	.macro SMCCC instr
+UNWIND(	.fnstart)
+	mov	r12, sp
+	push	{r4-r7}
+UNWIND(	.save	{r4-r7})
+	ldm	r12, {r4-r7}
+	\instr
+	pop	{r4-r7}
+	ldr	r12, [sp, #(4 * 4)]
+	stm	r12, {r0-r3}
+	bx	lr
+UNWIND(	.fnend)
+	.endm
+
+/*
+ * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
+ *		  unsigned long a3, unsigned long a4, unsigned long a5,
+ *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_smc)
+	SMCCC SMCCC_SMC
+ENDPROC(arm_smccc_smc)
+
+/*
+ * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
+ *		  unsigned long a3, unsigned long a4, unsigned long a5,
+ *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_hvc)
+	SMCCC SMCCC_HVC
+ENDPROC(arm_smccc_hvc)
--- linux-4.4.0.orig/arch/arm/kernel/smp.c
+++ linux-4.4.0/arch/arm/kernel/smp.c
@@ -27,8 +27,10 @@
 #include <linux/completion.h>
 #include <linux/cpufreq.h>
 #include <linux/irq_work.h>
+#include <linux/slab.h>
 
 #include <linux/atomic.h>
+#include <asm/bugs.h>
 #include <asm/smp.h>
 #include <asm/cacheflush.h>
 #include <asm/cpu.h>
@@ -39,6 +41,7 @@
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
+#include <asm/procinfo.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
@@ -95,6 +98,30 @@
 #endif
 }
 
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+static int secondary_biglittle_prepare(unsigned int cpu)
+{
+	if (!cpu_vtable[cpu])
+		cpu_vtable[cpu] = kzalloc(sizeof(*cpu_vtable[cpu]), GFP_KERNEL);
+
+	return cpu_vtable[cpu] ? 0 : -ENOMEM;
+}
+
+static void secondary_biglittle_init(void)
+{
+	init_proc_vtable(lookup_processor(read_cpuid_id())->proc);
+}
+#else
+static int secondary_biglittle_prepare(unsigned int cpu)
+{
+	return 0;
+}
+
+static void secondary_biglittle_init(void)
+{
+}
+#endif
+
 int __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
 	int ret;
@@ -102,6 +129,10 @@
 	if (!smp_ops.smp_boot_secondary)
 		return -ENOSYS;
 
+	ret = secondary_biglittle_prepare(cpu);
+	if (ret)
+		return ret;
+
 	/*
 	 * We need to tell the secondary core where to find
 	 * its stack and the page tables.
@@ -218,7 +249,7 @@
 	/*
 	 * OK - migrate IRQs away from this CPU
 	 */
-	migrate_irqs();
+	irq_migrate_all_off_this_cpu();
 
 	/*
 	 * Flush user cache and TLB mappings, and then remove this CPU
@@ -353,6 +384,8 @@
 	struct mm_struct *mm = &init_mm;
 	unsigned int cpu;
 
+	secondary_biglittle_init();
+
 	/*
 	 * The identity mapping is uncached (strongly ordered), so
 	 * switch away from it before attempting any exclusive accesses.
@@ -396,6 +429,9 @@
 	 * before we continue - which happens after __cpu_up returns.
 	 */
 	set_cpu_online(cpu, true);
+
+	check_other_bugs();
+
 	complete(&cpu_running);
 
 	local_irq_enable();
@@ -563,8 +599,10 @@
 	local_fiq_disable();
 	local_irq_disable();
 
-	while (1)
+	while (1) {
 		cpu_relax();
+		wfe();
+	}
 }
 
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
@@ -687,6 +725,21 @@
 		pr_warn("SMP: failed to stop secondary CPUs\n");
 }
 
+/* In case panic() and panic() called at the same time on CPU1 and CPU2,
+ * and CPU 1 calls panic_smp_self_stop() before crash_smp_send_stop()
+ * CPU1 can't receive the ipi irqs from CPU2, CPU1 will be always online,
+ * kdump fails. So split out the panic_smp_self_stop() and add
+ * set_cpu_online(smp_processor_id(), false).
+ */
+void panic_smp_self_stop(void)
+{
+	pr_debug("CPU %u will stop doing anything useful since another CPU has paniced\n",
+	         smp_processor_id());
+	set_cpu_online(smp_processor_id(), false);
+	while (1)
+		cpu_relax();
+}
+
 /*
  * not supported here
  */
--- linux-4.4.0.orig/arch/arm/kernel/smp_tlb.c
+++ linux-4.4.0/arch/arm/kernel/smp_tlb.c
@@ -9,6 +9,7 @@
  */
 #include <linux/preempt.h>
 #include <linux/smp.h>
+#include <linux/uaccess.h>
 
 #include <asm/smp_plat.h>
 #include <asm/tlbflush.h>
@@ -40,8 +41,11 @@
 static inline void ipi_flush_tlb_page(void *arg)
 {
 	struct tlb_args *ta = (struct tlb_args *)arg;
+	unsigned int __ua_flags = uaccess_save_and_enable();
 
 	local_flush_tlb_page(ta->ta_vma, ta->ta_start);
+
+	uaccess_restore(__ua_flags);
 }
 
 static inline void ipi_flush_tlb_kernel_page(void *arg)
@@ -54,8 +58,11 @@
 static inline void ipi_flush_tlb_range(void *arg)
 {
 	struct tlb_args *ta = (struct tlb_args *)arg;
+	unsigned int __ua_flags = uaccess_save_and_enable();
 
 	local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
+
+	uaccess_restore(__ua_flags);
 }
 
 static inline void ipi_flush_tlb_kernel_range(void *arg)
--- linux-4.4.0.orig/arch/arm/kernel/stacktrace.c
+++ linux-4.4.0/arch/arm/kernel/stacktrace.c
@@ -19,6 +19,19 @@
  * A simple function epilogue looks like this:
  *	ldm	sp, {fp, sp, pc}
  *
+ * When compiled with clang, pc and sp are not pushed. A simple function
+ * prologue looks like this when built with clang:
+ *
+ *	stmdb	{..., fp, lr}
+ *	add	fp, sp, #x
+ *	sub	sp, sp, #y
+ *
+ * A simple function epilogue looks like this when built with clang:
+ *
+ *	sub	sp, fp, #x
+ *	ldm	{..., fp, pc}
+ *
+ *
  * Note that with framepointer enabled, even the leaf functions have the same
  * prologue and epilogue, therefore we can ignore the LR value in this case.
  */
@@ -31,6 +44,16 @@
 	low = frame->sp;
 	high = ALIGN(low, THREAD_SIZE);
 
+#ifdef CONFIG_CC_IS_CLANG
+	/* check current frame pointer is within bounds */
+	if (fp < low + 4 || fp > high - 4)
+		return -EINVAL;
+
+	frame->sp = frame->fp;
+	frame->fp = *(unsigned long *)(fp);
+	frame->pc = frame->lr;
+	frame->lr = *(unsigned long *)(fp + 4);
+#else
 	/* check current frame pointer is within bounds */
 	if (fp < low + 12 || fp > high - 4)
 		return -EINVAL;
@@ -39,6 +62,7 @@
 	frame->fp = *(unsigned long *)(fp - 12);
 	frame->sp = *(unsigned long *)(fp - 8);
 	frame->pc = *(unsigned long *)(fp - 4);
+#endif
 
 	return 0;
 }
--- linux-4.4.0.orig/arch/arm/kernel/suspend.c
+++ linux-4.4.0/arch/arm/kernel/suspend.c
@@ -1,6 +1,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 
+#include <asm/bugs.h>
 #include <asm/cacheflush.h>
 #include <asm/idmap.h>
 #include <asm/pgalloc.h>
@@ -34,6 +35,7 @@
 		cpu_switch_mm(mm->pgd, mm);
 		local_flush_bp_all();
 		local_flush_tlb_all();
+		check_other_bugs();
 	}
 
 	return ret;
--- linux-4.4.0.orig/arch/arm/kernel/sys_oabi-compat.c
+++ linux-4.4.0/arch/arm/kernel/sys_oabi-compat.c
@@ -276,11 +276,16 @@
 				    int maxevents, int timeout)
 {
 	struct epoll_event *kbuf;
+	struct oabi_epoll_event e;
 	mm_segment_t fs;
 	long ret, err, i;
 
-	if (maxevents <= 0 || maxevents > (INT_MAX/sizeof(struct epoll_event)))
+	if (maxevents <= 0 ||
+			maxevents > (INT_MAX/sizeof(*kbuf)) ||
+			maxevents > (INT_MAX/sizeof(*events)))
 		return -EINVAL;
+	if (!access_ok(VERIFY_WRITE, events, sizeof(*events) * maxevents))
+		return -EFAULT;
 	kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL);
 	if (!kbuf)
 		return -ENOMEM;
@@ -290,8 +295,11 @@
 	set_fs(fs);
 	err = 0;
 	for (i = 0; i < ret; i++) {
-		__put_user_error(kbuf[i].events, &events->events, err);
-		__put_user_error(kbuf[i].data,   &events->data,   err);
+		e.events = kbuf[i].events;
+		e.data = kbuf[i].data;
+		err = __copy_to_user(events, &e, sizeof(e));
+		if (err)
+			break;
 		events++;
 	}
 	kfree(kbuf);
@@ -317,14 +325,18 @@
 
 	if (nsops < 1 || nsops > SEMOPM)
 		return -EINVAL;
+	if (!access_ok(VERIFY_READ, tsops, sizeof(*tsops) * nsops))
+		return -EFAULT;
 	sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL);
 	if (!sops)
 		return -ENOMEM;
 	err = 0;
 	for (i = 0; i < nsops; i++) {
-		__get_user_error(sops[i].sem_num, &tsops->sem_num, err);
-		__get_user_error(sops[i].sem_op,  &tsops->sem_op,  err);
-		__get_user_error(sops[i].sem_flg, &tsops->sem_flg, err);
+		struct oabi_sembuf osb;
+		err |= __copy_from_user(&osb, tsops, sizeof(osb));
+		sops[i].sem_num = osb.sem_num;
+		sops[i].sem_op = osb.sem_op;
+		sops[i].sem_flg = osb.sem_flg;
 		tsops++;
 	}
 	if (timeout) {
--- linux-4.4.0.orig/arch/arm/kernel/traps.c
+++ linux-4.4.0/arch/arm/kernel/traps.c
@@ -19,6 +19,7 @@
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
 #include <linux/kdebug.h>
+#include <linux/kprobes.h>
 #include <linux/module.h>
 #include <linux/kexec.h>
 #include <linux/bug.h>
@@ -132,30 +133,26 @@
 	set_fs(fs);
 }
 
-static void dump_instr(const char *lvl, struct pt_regs *regs)
+static void __dump_instr(const char *lvl, struct pt_regs *regs)
 {
 	unsigned long addr = instruction_pointer(regs);
 	const int thumb = thumb_mode(regs);
 	const int width = thumb ? 4 : 8;
-	mm_segment_t fs;
 	char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
 	int i;
 
 	/*
-	 * We need to switch to kernel mode so that we can use __get_user
-	 * to safely read from kernel space.  Note that we now dump the
-	 * code first, just in case the backtrace kills us.
+	 * Note that we now dump the code first, just in case the backtrace
+	 * kills us.
 	 */
-	fs = get_fs();
-	set_fs(KERNEL_DS);
 
 	for (i = -4; i < 1 + !!thumb; i++) {
 		unsigned int val, bad;
 
 		if (thumb)
-			bad = __get_user(val, &((u16 *)addr)[i]);
+			bad = get_user(val, &((u16 *)addr)[i]);
 		else
-			bad = __get_user(val, &((u32 *)addr)[i]);
+			bad = get_user(val, &((u32 *)addr)[i]);
 
 		if (!bad)
 			p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
@@ -166,8 +163,20 @@
 		}
 	}
 	printk("%sCode: %s\n", lvl, str);
+}
 
-	set_fs(fs);
+static void dump_instr(const char *lvl, struct pt_regs *regs)
+{
+	mm_segment_t fs;
+
+	if (!user_mode(regs)) {
+		fs = get_fs();
+		set_fs(KERNEL_DS);
+		__dump_instr(lvl, regs);
+		set_fs(fs);
+	} else {
+		__dump_instr(lvl, regs);
+	}
 }
 
 #ifdef CONFIG_ARM_UNWIND
@@ -387,7 +396,8 @@
 	raw_spin_unlock_irqrestore(&undef_lock, flags);
 }
 
-static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
+static nokprobe_inline
+int call_undef_hook(struct pt_regs *regs, unsigned int instr)
 {
 	struct undef_hook *hook;
 	unsigned long flags;
@@ -460,6 +470,7 @@
 
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
+NOKPROBE_SYMBOL(do_undefinstr)
 
 /*
  * Handle FIQ similarly to NMI on x86 systems.
--- linux-4.4.0.orig/arch/arm/kernel/unwind.c
+++ linux-4.4.0/arch/arm/kernel/unwind.c
@@ -93,7 +93,7 @@
 static const struct unwind_idx *__origin_unwind_idx;
 extern const struct unwind_idx __stop_unwind_idx[];
 
-static DEFINE_SPINLOCK(unwind_lock);
+static DEFINE_RAW_SPINLOCK(unwind_lock);
 static LIST_HEAD(unwind_tables);
 
 /* Convert a prel31 symbol to an absolute address */
@@ -201,7 +201,7 @@
 		/* module unwind tables */
 		struct unwind_table *table;
 
-		spin_lock_irqsave(&unwind_lock, flags);
+		raw_spin_lock_irqsave(&unwind_lock, flags);
 		list_for_each_entry(table, &unwind_tables, list) {
 			if (addr >= table->begin_addr &&
 			    addr < table->end_addr) {
@@ -213,7 +213,7 @@
 				break;
 			}
 		}
-		spin_unlock_irqrestore(&unwind_lock, flags);
+		raw_spin_unlock_irqrestore(&unwind_lock, flags);
 	}
 
 	pr_debug("%s: idx = %p\n", __func__, idx);
@@ -529,9 +529,9 @@
 	tab->begin_addr = text_addr;
 	tab->end_addr = text_addr + text_size;
 
-	spin_lock_irqsave(&unwind_lock, flags);
+	raw_spin_lock_irqsave(&unwind_lock, flags);
 	list_add_tail(&tab->list, &unwind_tables);
-	spin_unlock_irqrestore(&unwind_lock, flags);
+	raw_spin_unlock_irqrestore(&unwind_lock, flags);
 
 	return tab;
 }
@@ -543,9 +543,9 @@
 	if (!tab)
 		return;
 
-	spin_lock_irqsave(&unwind_lock, flags);
+	raw_spin_lock_irqsave(&unwind_lock, flags);
 	list_del(&tab->list);
-	spin_unlock_irqrestore(&unwind_lock, flags);
+	raw_spin_unlock_irqrestore(&unwind_lock, flags);
 
 	kfree(tab);
 }
--- linux-4.4.0.orig/arch/arm/kernel/vdso.c
+++ linux-4.4.0/arch/arm/kernel/vdso.c
@@ -38,6 +38,8 @@
 
 static struct page **vdso_text_pagelist;
 
+extern char vdso_start[], vdso_end[];
+
 /* Total number of pages needed for the data and text portions of the VDSO. */
 unsigned int vdso_total_pages __read_mostly;
 
@@ -83,6 +85,8 @@
 	 */
 	np = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
 	if (!np)
+		np = of_find_compatible_node(NULL, NULL, "arm,armv8-timer");
+	if (!np)
 		goto out_put;
 
 	if (of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
@@ -178,13 +182,13 @@
 	unsigned int text_pages;
 	int i;
 
-	if (memcmp(&vdso_start, "\177ELF", 4)) {
+	if (memcmp(vdso_start, "\177ELF", 4)) {
 		pr_err("VDSO is not a valid ELF object!\n");
 		return -ENOEXEC;
 	}
 
-	text_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
-	pr_debug("vdso: %i text pages at base %p\n", text_pages, &vdso_start);
+	text_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
+	pr_debug("vdso: %i text pages at base %p\n", text_pages, vdso_start);
 
 	/* Allocate the VDSO text pagelist */
 	vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *),
@@ -199,7 +203,7 @@
 	for (i = 0; i < text_pages; i++) {
 		struct page *page;
 
-		page = virt_to_page(&vdso_start + i * PAGE_SIZE);
+		page = virt_to_page(vdso_start + i * PAGE_SIZE);
 		vdso_text_pagelist[i] = page;
 	}
 
@@ -210,7 +214,7 @@
 
 	cntvct_ok = cntvct_functional();
 
-	patch_vdso(&vdso_start);
+	patch_vdso(vdso_start);
 
 	return 0;
 }
--- linux-4.4.0.orig/arch/arm/kvm/arm.c
+++ linux-4.4.0/arch/arm/kvm/arm.c
@@ -155,8 +155,6 @@
 {
 	int i;
 
-	kvm_free_stage2_pgd(kvm);
-
 	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
 		if (kvm->vcpus[i]) {
 			kvm_arch_vcpu_free(kvm->vcpus[i]);
@@ -746,7 +744,7 @@
 static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
 			       const struct kvm_vcpu_init *init)
 {
-	unsigned int i;
+	unsigned int i, ret;
 	int phys_target = kvm_target_cpu();
 
 	if (init->target != phys_target)
@@ -781,9 +779,14 @@
 	vcpu->arch.target = phys_target;
 
 	/* Now we know what it is, we can reset it. */
-	return kvm_reset_vcpu(vcpu);
-}
+	ret = kvm_reset_vcpu(vcpu);
+	if (ret) {
+		vcpu->arch.target = -1;
+		bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);
+	}
 
+	return ret;
+}
 
 static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
 					 struct kvm_vcpu_init *init)
--- linux-4.4.0.orig/arch/arm/kvm/guest.c
+++ linux-4.4.0/arch/arm/kvm/guest.c
@@ -155,7 +155,7 @@
 	u64 val;
 
 	val = kvm_arm_timer_get_reg(vcpu, reg->id);
-	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id));
+	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
 }
 
 static unsigned long num_core_regs(void)
--- linux-4.4.0.orig/arch/arm/kvm/handle_exit.c
+++ linux-4.4.0/arch/arm/kvm/handle_exit.c
@@ -45,7 +45,7 @@
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -54,7 +54,16 @@
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	/*
+	 * "If an SMC instruction executed at Non-secure EL1 is
+	 * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
+	 * Trap exception, not a Secure Monitor Call exception [...]"
+	 *
+	 * We need to advance the PC after the trap, as it would
+	 * otherwise return to the same address...
+	 */
+	vcpu_set_reg(vcpu, 0, ~0UL);
+	kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
 	return 1;
 }
 
@@ -100,7 +109,19 @@
 	return 1;
 }
 
+static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+	u32 hsr = kvm_vcpu_get_hsr(vcpu);
+
+	kvm_pr_unimpl("Unknown exception class: hsr: %#08x\n",
+		      hsr);
+
+	kvm_inject_undefined(vcpu);
+	return 1;
+}
+
 static exit_handle_fn arm_exit_handlers[] = {
+	[0 ... HSR_EC_MAX]	= kvm_handle_unknown_ec,
 	[HSR_EC_WFI]		= kvm_handle_wfx,
 	[HSR_EC_CP15_32]	= kvm_handle_cp15_32,
 	[HSR_EC_CP15_64]	= kvm_handle_cp15_64,
@@ -122,13 +143,6 @@
 {
 	u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
 
-	if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) ||
-	    !arm_exit_handlers[hsr_ec]) {
-		kvm_err("Unknown exception class: hsr: %#08x\n",
-			(unsigned int)kvm_vcpu_get_hsr(vcpu));
-		BUG();
-	}
-
 	return arm_exit_handlers[hsr_ec];
 }
 
--- linux-4.4.0.orig/arch/arm/kvm/init.S
+++ linux-4.4.0/arch/arm/kvm/init.S
@@ -110,7 +110,6 @@
 	@  - Write permission implies XN: disabled
 	@  - Instruction cache: enabled
 	@  - Data/Unified cache: enabled
-	@  - Memory alignment checks: enabled
 	@  - MMU: enabled (this code must be run from an identity mapping)
 	mrc	p15, 4, r0, c1, c0, 0	@ HSCR
 	ldr	r2, =HSCTLR_MASK
@@ -118,8 +117,8 @@
 	mrc	p15, 0, r1, c1, c0, 0	@ SCTLR
 	ldr	r2, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C)
 	and	r1, r1, r2
- ARM(	ldr	r2, =(HSCTLR_M | HSCTLR_A)			)
- THUMB(	ldr	r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE)		)
+ ARM(	ldr	r2, =(HSCTLR_M)					)
+ THUMB(	ldr	r2, =(HSCTLR_M | HSCTLR_TE)			)
 	orr	r1, r1, r2
 	orr	r0, r0, r1
 	isb
--- linux-4.4.0.orig/arch/arm/kvm/mmio.c
+++ linux-4.4.0/arch/arm/kvm/mmio.c
@@ -87,11 +87,10 @@
 
 /**
  * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ *			     or in-kernel IO emulation
+ *
  * @vcpu: The VCPU pointer
  * @run:  The VCPU run struct containing the mmio data
- *
- * This should only be called after returning from userspace for MMIO load
- * emulation.
  */
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
@@ -99,6 +98,12 @@
 	unsigned int len;
 	int mask;
 
+	/* Detect an already handled MMIO return */
+	if (unlikely(!vcpu->mmio_needed))
+		return 0;
+
+	vcpu->mmio_needed = 0;
+
 	if (!run->mmio.is_write) {
 		len = run->mmio.len;
 		if (len > sizeof(unsigned long))
@@ -113,11 +118,17 @@
 		}
 
 		trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
-			       data);
+			       &data);
 		data = vcpu_data_host_to_guest(vcpu, data, len);
 		vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
 	}
 
+	/*
+	 * The MMIO instruction is emulated and should not be re-executed
+	 * in the guest.
+	 */
+	kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+
 	return 0;
 }
 
@@ -151,11 +162,6 @@
 	vcpu->arch.mmio_decode.sign_extend = sign_extend;
 	vcpu->arch.mmio_decode.rt = rt;
 
-	/*
-	 * The MMIO instruction is emulated and should not be re-executed
-	 * in the guest.
-	 */
-	kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
 	return 0;
 }
 
@@ -189,14 +195,14 @@
 		data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
 					       len);
 
-		trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
+		trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, &data);
 		mmio_write_buf(data_buf, len, data);
 
 		ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
 				       data_buf);
 	} else {
 		trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,
-			       fault_ipa, 0);
+			       fault_ipa, NULL);
 
 		ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len,
 				      data_buf);
@@ -206,14 +212,18 @@
 	run->mmio.is_write	= is_write;
 	run->mmio.phys_addr	= fault_ipa;
 	run->mmio.len		= len;
-	memcpy(run->mmio.data, data_buf, len);
+	vcpu->mmio_needed	= 1;
 
 	if (!ret) {
 		/* We handled the access successfully in the kernel. */
+		if (!is_write)
+			memcpy(run->mmio.data, data_buf, len);
 		kvm_handle_mmio_return(vcpu, run);
 		return 1;
 	}
 
+	if (is_write)
+		memcpy(run->mmio.data, data_buf, len);
 	run->exit_reason	= KVM_EXIT_MMIO;
 	return 0;
 }
--- linux-4.4.0.orig/arch/arm/kvm/mmu.c
+++ linux-4.4.0/arch/arm/kvm/mmu.c
@@ -738,6 +738,7 @@
  */
 static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size)
 {
+	assert_spin_locked(&kvm->mmu_lock);
 	unmap_range(kvm, kvm->arch.pgd, start, size);
 }
 
@@ -796,6 +797,7 @@
 	int idx;
 
 	idx = srcu_read_lock(&kvm->srcu);
+	down_read(&current->mm->mmap_sem);
 	spin_lock(&kvm->mmu_lock);
 
 	slots = kvm_memslots(kvm);
@@ -803,6 +805,7 @@
 		stage2_unmap_memslot(kvm, memslot);
 
 	spin_unlock(&kvm->mmu_lock);
+	up_read(&current->mm->mmap_sem);
 	srcu_read_unlock(&kvm->srcu, idx);
 }
 
@@ -813,21 +816,25 @@
  * Walks the level-1 page table pointed to by kvm->arch.pgd and frees all
  * underlying level-2 and level-3 tables before freeing the actual level-1 table
  * and setting the struct pointer to NULL.
- *
- * Note we don't need locking here as this is only called when the VM is
- * destroyed, which can only be done once.
  */
 void kvm_free_stage2_pgd(struct kvm *kvm)
 {
-	if (kvm->arch.pgd == NULL)
-		return;
+	void *pgd = NULL;
+	void *hwpgd = NULL;
 
-	unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
-	kvm_free_hwpgd(kvm_get_hwpgd(kvm));
-	if (KVM_PREALLOC_LEVEL > 0)
-		kfree(kvm->arch.pgd);
+	spin_lock(&kvm->mmu_lock);
+	if (kvm->arch.pgd) {
+		unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
+		pgd = READ_ONCE(kvm->arch.pgd);
+		hwpgd = kvm_get_hwpgd(kvm);
+		kvm->arch.pgd = NULL;
+	}
+	spin_unlock(&kvm->mmu_lock);
 
-	kvm->arch.pgd = NULL;
+	if (hwpgd)
+		kvm_free_hwpgd(hwpgd);
+	if (KVM_PREALLOC_LEVEL > 0 && pgd)
+		kfree(pgd);
 }
 
 static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
@@ -855,6 +862,9 @@
 	pmd_t *pmd;
 
 	pud = stage2_get_pud(kvm, cache, addr);
+	if (!pud)
+		return NULL;
+
 	if (pud_none(*pud)) {
 		if (!cache)
 			return NULL;
@@ -874,23 +884,42 @@
 	pmd = stage2_get_pmd(kvm, cache, addr);
 	VM_BUG_ON(!pmd);
 
-	/*
-	 * Mapping in huge pages should only happen through a fault.  If a
-	 * page is merged into a transparent huge page, the individual
-	 * subpages of that huge page should be unmapped through MMU
-	 * notifiers before we get here.
-	 *
-	 * Merging of CompoundPages is not supported; they should become
-	 * splitting first, unmapped, merged, and mapped back in on-demand.
-	 */
-	VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd));
-
 	old_pmd = *pmd;
-	kvm_set_pmd(pmd, *new_pmd);
-	if (pmd_present(old_pmd))
+	if (pmd_present(old_pmd)) {
+		/*
+		 * Multiple vcpus faulting on the same PMD entry, can
+		 * lead to them sequentially updating the PMD with the
+		 * same value. Following the break-before-make
+		 * (pmd_clear() followed by tlb_flush()) process can
+		 * hinder forward progress due to refaults generated
+		 * on missing translations.
+		 *
+		 * Skip updating the page table if the entry is
+		 * unchanged.
+		 */
+		if (pmd_val(old_pmd) == pmd_val(*new_pmd))
+			return 0;
+
+		/*
+		 * Mapping in huge pages should only happen through a
+		 * fault.  If a page is merged into a transparent huge
+		 * page, the individual subpages of that huge page
+		 * should be unmapped through MMU notifiers before we
+		 * get here.
+		 *
+		 * Merging of CompoundPages is not supported; they
+		 * should become splitting first, unmapped, merged,
+		 * and mapped back in on-demand.
+		 */
+		VM_BUG_ON(pmd_pfn(old_pmd) != pmd_pfn(*new_pmd));
+
+		pmd_clear(pmd);
 		kvm_tlb_flush_vmid_ipa(kvm, addr);
-	else
+	} else {
 		get_page(virt_to_page(pmd));
+	}
+
+	kvm_set_pmd(pmd, *new_pmd);
 	return 0;
 }
 
@@ -939,12 +968,18 @@
 
 	/* Create 2nd stage page table mapping - Level 3 */
 	old_pte = *pte;
-	kvm_set_pte(pte, *new_pte);
-	if (pte_present(old_pte))
+	if (pte_present(old_pte)) {
+		/* Skip page table update if there is no change */
+		if (pte_val(old_pte) == pte_val(*new_pte))
+			return 0;
+
+		kvm_set_pte(pte, __pte(0));
 		kvm_tlb_flush_vmid_ipa(kvm, addr);
-	else
+	} else {
 		get_page(virt_to_page(pte));
+	}
 
+	kvm_set_pte(pte, *new_pte);
 	return 0;
 }
 
@@ -1607,12 +1642,16 @@
 
 int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
 {
+	if (!kvm->arch.pgd)
+		return 0;
 	trace_kvm_age_hva(start, end);
 	return handle_hva_to_gpa(kvm, start, end, kvm_age_hva_handler, NULL);
 }
 
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
 {
+	if (!kvm->arch.pgd)
+		return 0;
 	trace_kvm_test_age_hva(hva);
 	return handle_hva_to_gpa(kvm, hva, hva, kvm_test_age_hva_handler, NULL);
 }
@@ -1750,10 +1789,11 @@
 	 * Prevent userspace from creating a memory region outside of the IPA
 	 * space addressable by the KVM guest IPA space.
 	 */
-	if (memslot->base_gfn + memslot->npages >=
+	if (memslot->base_gfn + memslot->npages >
 	    (KVM_PHYS_SIZE >> PAGE_SHIFT))
 		return -EFAULT;
 
+	down_read(&current->mm->mmap_sem);
 	/*
 	 * A memory region could potentially cover multiple VMAs, and any holes
 	 * between them, so iterate over all of them to find out if we can map
@@ -1797,8 +1837,10 @@
 			pa += vm_start - vma->vm_start;
 
 			/* IO region dirty page logging not allowed */
-			if (memslot->flags & KVM_MEM_LOG_DIRTY_PAGES)
-				return -EINVAL;
+			if (memslot->flags & KVM_MEM_LOG_DIRTY_PAGES) {
+				ret = -EINVAL;
+				goto out;
+			}
 
 			ret = kvm_phys_addr_ioremap(kvm, gpa, pa,
 						    vm_end - vm_start,
@@ -1810,7 +1852,7 @@
 	} while (hva < reg_end);
 
 	if (change == KVM_MR_FLAGS_ONLY)
-		return ret;
+		goto out;
 
 	spin_lock(&kvm->mmu_lock);
 	if (ret)
@@ -1818,6 +1860,8 @@
 	else
 		stage2_flush_memslot(kvm, memslot);
 	spin_unlock(&kvm->mmu_lock);
+out:
+	up_read(&current->mm->mmap_sem);
 	return ret;
 }
 
@@ -1847,6 +1891,7 @@
 
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
 {
+	kvm_free_stage2_pgd(kvm);
 }
 
 void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
--- linux-4.4.0.orig/arch/arm/kvm/psci.c
+++ linux-4.4.0/arch/arm/kvm/psci.c
@@ -208,9 +208,10 @@
 
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
-	int ret = 1;
+	struct kvm *kvm = vcpu->kvm;
 	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
 	unsigned long val;
+	int ret = 1;
 
 	switch (psci_fn) {
 	case PSCI_0_2_FN_PSCI_VERSION:
@@ -230,7 +231,9 @@
 		break;
 	case PSCI_0_2_FN_CPU_ON:
 	case PSCI_0_2_FN64_CPU_ON:
+		mutex_lock(&kvm->lock);
 		val = kvm_psci_vcpu_on(vcpu);
+		mutex_unlock(&kvm->lock);
 		break;
 	case PSCI_0_2_FN_AFFINITY_INFO:
 	case PSCI_0_2_FN64_AFFINITY_INFO:
@@ -279,6 +282,7 @@
 
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
+	struct kvm *kvm = vcpu->kvm;
 	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
 	unsigned long val;
 
@@ -288,7 +292,9 @@
 		val = PSCI_RET_SUCCESS;
 		break;
 	case KVM_PSCI_FN_CPU_ON:
+		mutex_lock(&kvm->lock);
 		val = kvm_psci_vcpu_on(vcpu);
+		mutex_unlock(&kvm->lock);
 		break;
 	default:
 		val = PSCI_RET_NOT_SUPPORTED;
--- linux-4.4.0.orig/arch/arm/lib/Makefile
+++ linux-4.4.0/arch/arm/lib/Makefile
@@ -35,7 +35,7 @@
 $(obj)/csumpartialcopyuser.o:	$(obj)/csumpartialcopygeneric.S
 
 ifeq ($(CONFIG_KERNEL_MODE_NEON),y)
-  NEON_FLAGS			:= -mfloat-abi=softfp -mfpu=neon
+  NEON_FLAGS			:= -march=armv7-a -mfloat-abi=softfp -mfpu=neon
   CFLAGS_xor-neon.o		+= $(NEON_FLAGS)
   obj-$(CONFIG_XOR_BLOCKS)	+= xor-neon.o
 endif
--- linux-4.4.0.orig/arch/arm/lib/copy_from_user.S
+++ linux-4.4.0/arch/arm/lib/copy_from_user.S
@@ -90,12 +90,17 @@
 	.text
 
 ENTRY(arm_copy_from_user)
+#ifdef CONFIG_CPU_SPECTRE
+	get_thread_info r3
+	ldr	r3, [r3, #TI_ADDR_LIMIT]
+	uaccess_mask_range_ptr r1, r2, r3, ip
+#endif
 
 #include "copy_template.S"
 
 ENDPROC(arm_copy_from_user)
 
-	.pushsection .fixup,"ax"
+	.pushsection .text.fixup,"ax"
 	.align 0
 	copy_abort_preamble
 	ldmfd	sp!, {r1, r2}
--- linux-4.4.0.orig/arch/arm/lib/csumpartialcopyuser.S
+++ linux-4.4.0/arch/arm/lib/csumpartialcopyuser.S
@@ -85,7 +85,11 @@
 		.pushsection .text.fixup,"ax"
 		.align	4
 9001:		mov	r4, #-EFAULT
+#ifdef CONFIG_CPU_SW_DOMAIN_PAN
+		ldr	r5, [sp, #9*4]		@ *err_ptr
+#else
 		ldr	r5, [sp, #8*4]		@ *err_ptr
+#endif
 		str	r4, [r5]
 		ldmia	sp, {r1, r2}		@ retrieve dst, len
 		add	r2, r2, r1
--- linux-4.4.0.orig/arch/arm/lib/getuser.S
+++ linux-4.4.0/arch/arm/lib/getuser.S
@@ -38,9 +38,16 @@
 	mov	r0, #0
 	ret	lr
 ENDPROC(__get_user_1)
+_ASM_NOKPROBE(__get_user_1)
 
 ENTRY(__get_user_2)
 	check_uaccess r0, 2, r1, r2, __get_user_bad
+#if __LINUX_ARM_ARCH__ >= 6
+
+2: TUSER(ldrh)	r2, [r0]
+
+#else
+
 #ifdef CONFIG_CPU_USE_DOMAINS
 rb	.req	ip
 2:	ldrbt	r2, [r0], #1
@@ -55,9 +62,13 @@
 #else
 	orr	r2, rb, r2, lsl #8
 #endif
+
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
 	mov	r0, #0
 	ret	lr
 ENDPROC(__get_user_2)
+_ASM_NOKPROBE(__get_user_2)
 
 ENTRY(__get_user_4)
 	check_uaccess r0, 4, r1, r2, __get_user_bad
@@ -65,9 +76,10 @@
 	mov	r0, #0
 	ret	lr
 ENDPROC(__get_user_4)
+_ASM_NOKPROBE(__get_user_4)
 
 ENTRY(__get_user_8)
-	check_uaccess r0, 8, r1, r2, __get_user_bad
+	check_uaccess r0, 8, r1, r2, __get_user_bad8
 #ifdef CONFIG_THUMB2_KERNEL
 5: TUSER(ldr)	r2, [r0]
 6: TUSER(ldr)	r3, [r0, #4]
@@ -78,6 +90,7 @@
 	mov	r0, #0
 	ret	lr
 ENDPROC(__get_user_8)
+_ASM_NOKPROBE(__get_user_8)
 
 #ifdef __ARMEB__
 ENTRY(__get_user_32t_8)
@@ -91,6 +104,7 @@
 	mov	r0, #0
 	ret	lr
 ENDPROC(__get_user_32t_8)
+_ASM_NOKPROBE(__get_user_32t_8)
 
 ENTRY(__get_user_64t_1)
 	check_uaccess r0, 1, r1, r2, __get_user_bad8
@@ -98,6 +112,7 @@
 	mov	r0, #0
 	ret	lr
 ENDPROC(__get_user_64t_1)
+_ASM_NOKPROBE(__get_user_64t_1)
 
 ENTRY(__get_user_64t_2)
 	check_uaccess r0, 2, r1, r2, __get_user_bad8
@@ -114,6 +129,7 @@
 	mov	r0, #0
 	ret	lr
 ENDPROC(__get_user_64t_2)
+_ASM_NOKPROBE(__get_user_64t_2)
 
 ENTRY(__get_user_64t_4)
 	check_uaccess r0, 4, r1, r2, __get_user_bad8
@@ -121,6 +137,7 @@
 	mov	r0, #0
 	ret	lr
 ENDPROC(__get_user_64t_4)
+_ASM_NOKPROBE(__get_user_64t_4)
 #endif
 
 __get_user_bad8:
@@ -131,11 +148,15 @@
 	ret	lr
 ENDPROC(__get_user_bad)
 ENDPROC(__get_user_bad8)
+_ASM_NOKPROBE(__get_user_bad)
+_ASM_NOKPROBE(__get_user_bad8)
 
 .pushsection __ex_table, "a"
 	.long	1b, __get_user_bad
 	.long	2b, __get_user_bad
+#if __LINUX_ARM_ARCH__ < 6
 	.long	3b, __get_user_bad
+#endif
 	.long	4b, __get_user_bad
 	.long	5b, __get_user_bad8
 	.long	6b, __get_user_bad8
--- linux-4.4.0.orig/arch/arm/lib/putuser.S
+++ linux-4.4.0/arch/arm/lib/putuser.S
@@ -41,16 +41,13 @@
 
 ENTRY(__put_user_2)
 	check_uaccess r0, 2, r1, ip, __put_user_bad
-	mov	ip, r2, lsr #8
-#ifdef CONFIG_THUMB2_KERNEL
-#ifndef __ARMEB__
-2: TUSER(strb)	r2, [r0]
-3: TUSER(strb)	ip, [r0, #1]
+#if __LINUX_ARM_ARCH__ >= 6
+
+2: TUSER(strh)	r2, [r0]
+
 #else
-2: TUSER(strb)	ip, [r0]
-3: TUSER(strb)	r2, [r0, #1]
-#endif
-#else	/* !CONFIG_THUMB2_KERNEL */
+
+	mov	ip, r2, lsr #8
 #ifndef __ARMEB__
 2: TUSER(strb)	r2, [r0], #1
 3: TUSER(strb)	ip, [r0]
@@ -58,7 +55,8 @@
 2: TUSER(strb)	ip, [r0], #1
 3: TUSER(strb)	r2, [r0]
 #endif
-#endif	/* CONFIG_THUMB2_KERNEL */
+
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
 	mov	r0, #0
 	ret	lr
 ENDPROC(__put_user_2)
@@ -91,7 +89,9 @@
 .pushsection __ex_table, "a"
 	.long	1b, __put_user_bad
 	.long	2b, __put_user_bad
+#if __LINUX_ARM_ARCH__ < 6
 	.long	3b, __put_user_bad
+#endif
 	.long	4b, __put_user_bad
 	.long	5b, __put_user_bad
 	.long	6b, __put_user_bad
--- linux-4.4.0.orig/arch/arm/lib/xor-neon.c
+++ linux-4.4.0/arch/arm/lib/xor-neon.c
@@ -14,7 +14,7 @@
 MODULE_LICENSE("GPL");
 
 #ifndef __ARM_NEON__
-#error You should compile this file with '-mfloat-abi=softfp -mfpu=neon'
+#error You should compile this file with '-march=armv7-a -mfloat-abi=softfp -mfpu=neon'
 #endif
 
 /*
--- linux-4.4.0.orig/arch/arm/mach-at91/pm.c
+++ linux-4.4.0/arch/arm/mach-at91/pm.c
@@ -286,6 +286,22 @@
 		at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
 }
 
+static void sama5d3_ddr_standby(void)
+{
+	u32 lpr0;
+	u32 saved_lpr0;
+
+	saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
+	lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB;
+	lpr0 |= AT91_DDRSDRC_LPCB_POWER_DOWN;
+
+	at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
+
+	cpu_do_idle();
+
+	at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
+}
+
 /* We manage both DDRAM/SDRAM controllers, we need more than one value to
  * remember.
  */
@@ -316,11 +332,11 @@
 		at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
 }
 
-static const struct of_device_id const ramc_ids[] __initconst = {
+static const struct of_device_id ramc_ids[] __initconst = {
 	{ .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
 	{ .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
 	{ .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
-	{ .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby },
+	{ .compatible = "atmel,sama5d3-ddramc", .data = sama5d3_ddr_standby },
 	{ /*sentinel*/ }
 };
 
@@ -377,13 +393,13 @@
 	sram_pool = gen_pool_get(&pdev->dev, NULL);
 	if (!sram_pool) {
 		pr_warn("%s: sram pool unavailable!\n", __func__);
-		return;
+		goto out_put_device;
 	}
 
 	sram_base = gen_pool_alloc(sram_pool, at91_pm_suspend_in_sram_sz);
 	if (!sram_base) {
 		pr_warn("%s: unable to alloc sram!\n", __func__);
-		return;
+		goto out_put_device;
 	}
 
 	sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base);
@@ -391,12 +407,17 @@
 					at91_pm_suspend_in_sram_sz, false);
 	if (!at91_suspend_sram_fn) {
 		pr_warn("SRAM: Could not map\n");
-		return;
+		goto out_put_device;
 	}
 
 	/* Copy the pm suspend handler to SRAM */
 	at91_suspend_sram_fn = fncpy(at91_suspend_sram_fn,
 			&at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
+	return;
+
+out_put_device:
+	put_device(&pdev->dev);
+	return;
 }
 
 static void __init at91_pm_init(void)
--- linux-4.4.0.orig/arch/arm/mach-bcm/bcm_kona_smc.c
+++ linux-4.4.0/arch/arm/mach-bcm/bcm_kona_smc.c
@@ -33,7 +33,7 @@
 	unsigned result;
 };
 
-static const struct of_device_id const bcm_kona_smc_ids[] __initconst = {
+static const struct of_device_id bcm_kona_smc_ids[] __initconst = {
 	{.compatible = "brcm,kona-smc"},
 	{.compatible = "bcm,kona-smc"}, /* deprecated name */
 	{},
--- linux-4.4.0.orig/arch/arm/mach-cns3xxx/core.c
+++ linux-4.4.0/arch/arm/mach-cns3xxx/core.c
@@ -346,7 +346,7 @@
 	.power_off	= csn3xxx_usb_power_off,
 };
 
-static const struct of_dev_auxdata const cns3xxx_auxdata[] __initconst = {
+static const struct of_dev_auxdata cns3xxx_auxdata[] __initconst = {
 	{ "intel,usb-ehci", CNS3XXX_USB_BASE, "ehci-platform", &cns3xxx_usb_ehci_pdata },
 	{ "intel,usb-ohci", CNS3XXX_USB_OHCI_BASE, "ohci-platform", &cns3xxx_usb_ohci_pdata },
 	{ "cavium,cns3420-ahci", CNS3XXX_SATA2_BASE, "ahci", NULL },
--- linux-4.4.0.orig/arch/arm/mach-cns3xxx/pcie.c
+++ linux-4.4.0/arch/arm/mach-cns3xxx/pcie.c
@@ -83,7 +83,7 @@
 	} else /* remote PCI bus */
 		base = cnspci->cfg1_regs + ((busno & 0xf) << 20);
 
-	return base + (where & 0xffc) + (devfn << 12);
+	return base + where + (devfn << 12);
 }
 
 static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
@@ -220,13 +220,13 @@
 	u32 mask = (0x1ull << (size * 8)) - 1;
 	int shift = (where % 4) * 8;
 
-	v = readl_relaxed(base + (where & 0xffc));
+	v = readl_relaxed(base);
 
 	v &= ~(mask << shift);
 	v |= (val & mask) << shift;
 
-	writel_relaxed(v, base + (where & 0xffc));
-	readl_relaxed(base + (where & 0xffc));
+	writel_relaxed(v, base);
+	readl_relaxed(base);
 }
 
 static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
--- linux-4.4.0.orig/arch/arm/mach-davinci/board-da850-evm.c
+++ linux-4.4.0/arch/arm/mach-davinci/board-da850-evm.c
@@ -1479,6 +1479,8 @@
 	if (ret)
 		pr_warn("%s: dsp/rproc registration failed: %d\n",
 			__func__, ret);
+
+	regulator_has_full_constraints();
 }
 
 #ifdef CONFIG_SERIAL_8250_CONSOLE
--- linux-4.4.0.orig/arch/arm/mach-davinci/da850.c
+++ linux-4.4.0/arch/arm/mach-davinci/da850.c
@@ -298,6 +298,16 @@
 	.gpsc		= 1,
 };
 
+/*
+ * In order to avoid adding the emac_clk to the clock lookup table twice (and
+ * screwing up the linked list in the process) create a separate clock for
+ * mdio inheriting the rate from emac_clk.
+ */
+static struct clk mdio_clk = {
+	.name		= "mdio",
+	.parent		= &emac_clk,
+};
+
 static struct clk mcasp_clk = {
 	.name		= "mcasp",
 	.parent		= &pll0_sysclk2,
@@ -462,7 +472,7 @@
 	CLK(NULL,		"arm",		&arm_clk),
 	CLK(NULL,		"rmii",		&rmii_clk),
 	CLK("davinci_emac.1",	NULL,		&emac_clk),
-	CLK("davinci_mdio.0",	"fck",		&emac_clk),
+	CLK("davinci_mdio.0",	"fck",		&mdio_clk),
 	CLK("davinci-mcasp.0",	NULL,		&mcasp_clk),
 	CLK("da8xx_lcdc.0",	"fck",		&lcdc_clk),
 	CLK("da830-mmc.0",	NULL,		&mmcsd0_clk),
--- linux-4.4.0.orig/arch/arm/mach-davinci/devices-da8xx.c
+++ linux-4.4.0/arch/arm/mach-davinci/devices-da8xx.c
@@ -660,6 +660,9 @@
 	.id		= 0,
 	.num_resources	= ARRAY_SIZE(da8xx_lcdc_resources),
 	.resource	= da8xx_lcdc_resources,
+	.dev		= {
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	}
 };
 
 int __init da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata)
@@ -795,6 +798,8 @@
 	.resource	= da8xx_rproc_resources,
 };
 
+static bool rproc_mem_inited __initdata;
+
 #if IS_ENABLED(CONFIG_DA8XX_REMOTEPROC)
 
 static phys_addr_t rproc_base __initdata;
@@ -833,6 +838,8 @@
 	ret = dma_declare_contiguous(&da8xx_dsp.dev, rproc_size, rproc_base, 0);
 	if (ret)
 		pr_err("%s: dma_declare_contiguous failed %d\n", __func__, ret);
+	else
+		rproc_mem_inited = true;
 }
 
 #else
@@ -847,6 +854,12 @@
 {
 	int ret;
 
+	if (!rproc_mem_inited) {
+		pr_warn("%s: memory not reserved for DSP, not registering DSP device\n",
+			__func__);
+		return -ENOMEM;
+	}
+
 	ret = platform_device_register(&da8xx_dsp);
 	if (ret)
 		pr_err("%s: can't register DSP device: %d\n", __func__, ret);
--- linux-4.4.0.orig/arch/arm/mach-davinci/sleep.S
+++ linux-4.4.0/arch/arm/mach-davinci/sleep.S
@@ -37,6 +37,7 @@
 #define DEEPSLEEP_SLEEPENABLE_BIT	BIT(31)
 
 	.text
+	.arch	armv5te
 /*
  * Move DaVinci into deep sleep state
  *
--- linux-4.4.0.orig/arch/arm/mach-exynos/Kconfig
+++ linux-4.4.0/arch/arm/mach-exynos/Kconfig
@@ -26,6 +26,7 @@
 	select S5P_DEV_MFC
 	select SRAM
 	select THERMAL
+	select THERMAL_OF
 	select MFD_SYSCON
 	help
 	  Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
--- linux-4.4.0.orig/arch/arm/mach-exynos/firmware.c
+++ linux-4.4.0/arch/arm/mach-exynos/firmware.c
@@ -207,6 +207,7 @@
 		return;
 
 	addr = of_get_address(nd, 0, NULL, NULL);
+	of_node_put(nd);
 	if (!addr) {
 		pr_err("%s: No address specified.\n", __func__);
 		return;
--- linux-4.4.0.orig/arch/arm/mach-exynos/pm_domains.c
+++ linux-4.4.0/arch/arm/mach-exynos/pm_domains.c
@@ -92,7 +92,7 @@
 			if (IS_ERR(pd->clk[i]))
 				break;
 
-			if (IS_ERR(pd->clk[i]))
+			if (IS_ERR(pd->pclk[i]))
 				continue; /* Skip on first power up */
 			if (clk_set_parent(pd->clk[i], pd->pclk[i]))
 				pr_err("%s: error setting parent to clock%d\n",
--- linux-4.4.0.orig/arch/arm/mach-exynos/suspend.c
+++ linux-4.4.0/arch/arm/mach-exynos/suspend.c
@@ -260,6 +260,7 @@
 					  NULL);
 	if (!domain) {
 		iounmap(pmu_base_addr);
+		pmu_base_addr = NULL;
 		return -ENOMEM;
 	}
 
@@ -507,8 +508,27 @@
 
 static void exynos5420_prepare_pm_resume(void)
 {
+	unsigned int mpidr, cluster;
+
+	mpidr = read_cpuid_mpidr();
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
 	if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
 		WARN_ON(mcpm_cpu_powered_up());
+
+	if (IS_ENABLED(CONFIG_HW_PERF_EVENTS) && cluster != 0) {
+		/*
+		 * When system is resumed on the LITTLE/KFC core (cluster 1),
+		 * the DSCR is not properly updated until the power is turned
+		 * on also for the cluster 0. Enable it for a while to
+		 * propagate the SPNIDEN and SPIDEN signals from Secure JTAG
+		 * block and avoid undefined instruction issue on CP14 reset.
+		 */
+		pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN,
+				EXYNOS_COMMON_CONFIGURATION(0));
+		pmu_raw_writel(0,
+				EXYNOS_COMMON_CONFIGURATION(0));
+	}
 }
 
 static void exynos5420_pm_resume(void)
@@ -724,8 +744,10 @@
 
 	if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
 		pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
+		of_node_put(np);
 		return;
 	}
+	of_node_put(np);
 
 	pm_data = (const struct exynos_pm_data *) match->data;
 
--- linux-4.4.0.orig/arch/arm/mach-footbridge/dc21285.c
+++ linux-4.4.0/arch/arm/mach-footbridge/dc21285.c
@@ -69,15 +69,15 @@
 	if (addr)
 		switch (size) {
 		case 1:
-			asm("ldrb	%0, [%1, %2]"
+			asm volatile("ldrb	%0, [%1, %2]"
 				: "=r" (v) : "r" (addr), "r" (where) : "cc");
 			break;
 		case 2:
-			asm("ldrh	%0, [%1, %2]"
+			asm volatile("ldrh	%0, [%1, %2]"
 				: "=r" (v) : "r" (addr), "r" (where) : "cc");
 			break;
 		case 4:
-			asm("ldr	%0, [%1, %2]"
+			asm volatile("ldr	%0, [%1, %2]"
 				: "=r" (v) : "r" (addr), "r" (where) : "cc");
 			break;
 		}
@@ -103,17 +103,17 @@
 	if (addr)
 		switch (size) {
 		case 1:
-			asm("strb	%0, [%1, %2]"
+			asm volatile("strb	%0, [%1, %2]"
 				: : "r" (value), "r" (addr), "r" (where)
 				: "cc");
 			break;
 		case 2:
-			asm("strh	%0, [%1, %2]"
+			asm volatile("strh	%0, [%1, %2]"
 				: : "r" (value), "r" (addr), "r" (where)
 				: "cc");
 			break;
 		case 4:
-			asm("str	%0, [%1, %2]"
+			asm volatile("str	%0, [%1, %2]"
 				: : "r" (value), "r" (addr), "r" (where)
 				: "cc");
 			break;
--- linux-4.4.0.orig/arch/arm/mach-highbank/Makefile
+++ linux-4.4.0/arch/arm/mach-highbank/Makefile
@@ -1,3 +1,5 @@
+KBUILD_CFLAGS += -I$(srctree)/arch/arm/mach-highbank/include
+
 obj-y					:= highbank.o system.o smc.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
--- linux-4.4.0.orig/arch/arm/mach-hisi/hotplug.c
+++ linux-4.4.0/arch/arm/mach-hisi/hotplug.c
@@ -148,13 +148,20 @@
 	struct device_node *node;
 
 	node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
-	if (node) {
-		ctrl_base = of_iomap(node, 0);
-		id = HI3620_CTRL;
-		return 0;
+	if (!node) {
+		id = ERROR_CTRL;
+		return -ENOENT;
 	}
-	id = ERROR_CTRL;
-	return -ENOENT;
+
+	ctrl_base = of_iomap(node, 0);
+	of_node_put(node);
+	if (!ctrl_base) {
+		id = ERROR_CTRL;
+		return -ENOMEM;
+	}
+
+	id = HI3620_CTRL;
+	return 0;
 }
 
 void hi3xxx_set_cpu(int cpu, bool enable)
@@ -173,11 +180,15 @@
 	struct device_node *np;
 
 	np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl");
-	if (np) {
-		ctrl_base = of_iomap(np, 0);
-		return true;
-	}
-	return false;
+	if (!np)
+		return false;
+
+	ctrl_base = of_iomap(np, 0);
+	of_node_put(np);
+	if (!ctrl_base)
+		return false;
+
+	return true;
 }
 
 void hix5hd2_set_cpu(int cpu, bool enable)
@@ -219,10 +230,10 @@
 
 	if (!ctrl_base) {
 		np = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl");
-		if (np)
-			ctrl_base = of_iomap(np, 0);
-		else
-			BUG();
+		BUG_ON(!np);
+		ctrl_base = of_iomap(np, 0);
+		of_node_put(np);
+		BUG_ON(!ctrl_base);
 	}
 
 	if (enable) {
--- linux-4.4.0.orig/arch/arm/mach-imx/Kconfig
+++ linux-4.4.0/arch/arm/mach-imx/Kconfig
@@ -562,6 +562,7 @@
 	select ARM_GIC
 	select HAVE_IMX_ANATOP
 	select HAVE_IMX_MMDC
+	select HAVE_IMX_SRC
 	help
 		This enables support for Freescale i.MX7 Dual processor.
 
--- linux-4.4.0.orig/arch/arm/mach-imx/Makefile
+++ linux-4.4.0/arch/arm/mach-imx/Makefile
@@ -91,6 +91,10 @@
 obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o
 obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o
 endif
+ifeq ($(CONFIG_ARM_CPU_SUSPEND),y)
+AFLAGS_resume-imx6.o :=-Wa,-march=armv7-a
+obj-$(CONFIG_SOC_IMX6) += resume-imx6.o
+endif
 obj-$(CONFIG_SOC_IMX6) += pm-imx6.o
 
 obj-$(CONFIG_SOC_IMX50) += mach-imx50.o
--- linux-4.4.0.orig/arch/arm/mach-imx/common.h
+++ linux-4.4.0/arch/arm/mach-imx/common.h
@@ -115,17 +115,17 @@
 int imx_cpu_kill(unsigned int cpu);
 
 #ifdef CONFIG_SUSPEND
-void v7_cpu_resume(void);
 void imx53_suspend(void __iomem *ocram_vbase);
 extern const u32 imx53_suspend_sz;
 void imx6_suspend(void __iomem *ocram_vbase);
 #else
-static inline void v7_cpu_resume(void) {}
 static inline void imx53_suspend(void __iomem *ocram_vbase) {}
 static const u32 imx53_suspend_sz;
 static inline void imx6_suspend(void __iomem *ocram_vbase) {}
 #endif
 
+void v7_cpu_resume(void);
+
 void imx6_pm_ccm_init(const char *ccm_compat);
 void imx6q_pm_init(void);
 void imx6dl_pm_init(void);
--- linux-4.4.0.orig/arch/arm/mach-imx/cpu.c
+++ linux-4.4.0/arch/arm/mach-imx/cpu.c
@@ -133,6 +133,9 @@
 	case MXC_CPU_IMX6UL:
 		soc_id = "i.MX6UL";
 		break;
+	case MXC_CPU_IMX6ULL:
+		soc_id = "i.MX6ULL";
+		break;
 	case MXC_CPU_IMX7D:
 		soc_id = "i.MX7D";
 		break;
--- linux-4.4.0.orig/arch/arm/mach-imx/cpuidle-imx6q.c
+++ linux-4.4.0/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -14,30 +14,23 @@
 #include "cpuidle.h"
 #include "hardware.h"
 
-static atomic_t master = ATOMIC_INIT(0);
-static DEFINE_SPINLOCK(master_lock);
+static int num_idle_cpus = 0;
+static DEFINE_SPINLOCK(cpuidle_lock);
 
 static int imx6q_enter_wait(struct cpuidle_device *dev,
 			    struct cpuidle_driver *drv, int index)
 {
-	if (atomic_inc_return(&master) == num_online_cpus()) {
-		/*
-		 * With this lock, we prevent other cpu to exit and enter
-		 * this function again and become the master.
-		 */
-		if (!spin_trylock(&master_lock))
-			goto idle;
+	spin_lock(&cpuidle_lock);
+	if (++num_idle_cpus == num_online_cpus())
 		imx6_set_lpm(WAIT_UNCLOCKED);
-		cpu_do_idle();
-		imx6_set_lpm(WAIT_CLOCKED);
-		spin_unlock(&master_lock);
-		goto done;
-	}
+	spin_unlock(&cpuidle_lock);
 
-idle:
 	cpu_do_idle();
-done:
-	atomic_dec(&master);
+
+	spin_lock(&cpuidle_lock);
+	if (num_idle_cpus-- == num_online_cpus())
+		imx6_set_lpm(WAIT_CLOCKED);
+	spin_unlock(&cpuidle_lock);
 
 	return index;
 }
--- linux-4.4.0.orig/arch/arm/mach-imx/cpuidle-imx6sx.c
+++ linux-4.4.0/arch/arm/mach-imx/cpuidle-imx6sx.c
@@ -14,6 +14,7 @@
 
 #include "common.h"
 #include "cpuidle.h"
+#include "hardware.h"
 
 static int imx6sx_idle_finish(unsigned long val)
 {
@@ -97,7 +98,7 @@
 	 * except for power up sw2iso which need to be
 	 * larger than LDO ramp up time.
 	 */
-	imx_gpc_set_arm_power_up_timing(2, 1);
+	imx_gpc_set_arm_power_up_timing(cpu_is_imx6sx() ? 0xf : 0x2, 1);
 	imx_gpc_set_arm_power_down_timing(1, 1);
 
 	return cpuidle_register(&imx6sx_cpuidle_driver, NULL);
--- linux-4.4.0.orig/arch/arm/mach-imx/mach-imx6ul.c
+++ linux-4.4.0/arch/arm/mach-imx/mach-imx6ul.c
@@ -46,7 +46,7 @@
 static void __init imx6ul_enet_phy_init(void)
 {
 	if (IS_BUILTIN(CONFIG_PHYLIB))
-		phy_register_fixup_for_uid(PHY_ID_KSZ8081, 0xffffffff,
+		phy_register_fixup_for_uid(PHY_ID_KSZ8081, MICREL_PHY_ID_MASK,
 					   ksz8081_phy_fixup);
 }
 
--- linux-4.4.0.orig/arch/arm/mach-imx/mxc.h
+++ linux-4.4.0/arch/arm/mach-imx/mxc.h
@@ -39,6 +39,7 @@
 #define MXC_CPU_IMX6SX		0x62
 #define MXC_CPU_IMX6Q		0x63
 #define MXC_CPU_IMX6UL		0x64
+#define MXC_CPU_IMX6ULL		0x65
 #define MXC_CPU_IMX7D		0x72
 
 #define IMX_DDR_TYPE_LPDDR2		1
@@ -171,6 +172,11 @@
 	return __mxc_cpu_type == MXC_CPU_IMX6UL;
 }
 
+static inline bool cpu_is_imx6ull(void)
+{
+	return __mxc_cpu_type == MXC_CPU_IMX6ULL;
+}
+
 static inline bool cpu_is_imx6q(void)
 {
 	return __mxc_cpu_type == MXC_CPU_IMX6Q;
--- linux-4.4.0.orig/arch/arm/mach-imx/pm-imx5.c
+++ linux-4.4.0/arch/arm/mach-imx/pm-imx5.c
@@ -301,14 +301,14 @@
 	if (!ocram_pool) {
 		pr_warn("%s: ocram pool unavailable!\n", __func__);
 		ret = -ENODEV;
-		goto put_node;
+		goto put_device;
 	}
 
 	ocram_base = gen_pool_alloc(ocram_pool, size);
 	if (!ocram_base) {
 		pr_warn("%s: unable to alloc ocram!\n", __func__);
 		ret = -ENOMEM;
-		goto put_node;
+		goto put_device;
 	}
 
 	phys = gen_pool_virt_to_phys(ocram_pool, ocram_base);
@@ -318,6 +318,8 @@
 	if (virt_out)
 		*virt_out = virt;
 
+put_device:
+	put_device(&pdev->dev);
 put_node:
 	of_node_put(node);
 
--- linux-4.4.0.orig/arch/arm/mach-imx/pm-imx6.c
+++ linux-4.4.0/arch/arm/mach-imx/pm-imx6.c
@@ -295,7 +295,7 @@
 		val &= ~BM_CLPCR_SBYOS;
 		if (cpu_is_imx6sl())
 			val |= BM_CLPCR_BYPASS_PMIC_READY;
-		if (cpu_is_imx6sl() || cpu_is_imx6sx())
+		if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul())
 			val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
 		else
 			val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
@@ -310,7 +310,7 @@
 		val |= 0x3 << BP_CLPCR_STBY_COUNT;
 		val |= BM_CLPCR_VSTBY;
 		val |= BM_CLPCR_SBYOS;
-		if (cpu_is_imx6sl())
+		if (cpu_is_imx6sl() || cpu_is_imx6sx())
 			val |= BM_CLPCR_BYPASS_PMIC_READY;
 		if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul())
 			val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
@@ -602,6 +602,28 @@
 				   IMX6Q_GPR1_GINT);
 }
 
+static void imx6_pm_stby_poweroff(void)
+{
+	imx6_set_lpm(STOP_POWER_OFF);
+	imx6q_suspend_finish(0);
+
+	mdelay(1000);
+
+	pr_emerg("Unable to poweroff system\n");
+}
+
+static int imx6_pm_stby_poweroff_probe(void)
+{
+	if (pm_power_off) {
+		pr_warn("%s: pm_power_off already claimed  %p %pf!\n",
+			__func__, pm_power_off, pm_power_off);
+		return -EBUSY;
+	}
+
+	pm_power_off = imx6_pm_stby_poweroff;
+	return 0;
+}
+
 void __init imx6_pm_ccm_init(const char *ccm_compat)
 {
 	struct device_node *np;
@@ -618,6 +640,9 @@
 	val = readl_relaxed(ccm_base + CLPCR);
 	val &= ~BM_CLPCR_LPM;
 	writel_relaxed(val, ccm_base + CLPCR);
+
+	if (of_property_read_bool(np, "fsl,pmic-stby-poweroff"))
+		imx6_pm_stby_poweroff_probe();
 }
 
 void __init imx6q_pm_init(void)
--- linux-4.4.0.orig/arch/arm/mach-imx/resume-imx6.S
+++ linux-4.4.0/arch/arm/mach-imx/resume-imx6.S
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
+#include "hardware.h"
+
+/*
+ * The following code must assume it is running from physical address
+ * where absolute virtual addresses to the data section have to be
+ * turned into relative ones.
+ */
+
+ENTRY(v7_cpu_resume)
+	bl	v7_invalidate_l1
+#ifdef CONFIG_CACHE_L2X0
+	bl	l2c310_early_resume
+#endif
+	b	cpu_resume
+ENDPROC(v7_cpu_resume)
--- linux-4.4.0.orig/arch/arm/mach-imx/suspend-imx6.S
+++ linux-4.4.0/arch/arm/mach-imx/suspend-imx6.S
@@ -73,6 +73,7 @@
 #define MX6Q_CCM_CCR	0x0
 
 	.align 3
+	.arm
 
 	.macro  sync_l2_cache
 
@@ -333,17 +334,3 @@
 
 	ret	lr
 ENDPROC(imx6_suspend)
-
-/*
- * The following code must assume it is running from physical address
- * where absolute virtual addresses to the data section have to be
- * turned into relative ones.
- */
-
-ENTRY(v7_cpu_resume)
-	bl	v7_invalidate_l1
-#ifdef CONFIG_CACHE_L2X0
-	bl	l2c310_early_resume
-#endif
-	b	cpu_resume
-ENDPROC(v7_cpu_resume)
--- linux-4.4.0.orig/arch/arm/mach-integrator/impd1.c
+++ linux-4.4.0/arch/arm/mach-integrator/impd1.c
@@ -394,7 +394,11 @@
 					      sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup),
 					      GFP_KERNEL);
 			chipname = devm_kstrdup(&dev->dev, devname, GFP_KERNEL);
-			mmciname = kasprintf(GFP_KERNEL, "lm%x:00700", dev->id);
+			mmciname = devm_kasprintf(&dev->dev, GFP_KERNEL,
+						  "lm%x:00700", dev->id);
+			if (!lookup || !chipname || !mmciname)
+				return -ENOMEM;
+
 			lookup->dev_id = mmciname;
 			/*
 			 * Offsets on GPIO block 1:
--- linux-4.4.0.orig/arch/arm/mach-iop13xx/setup.c
+++ linux-4.4.0/arch/arm/mach-iop13xx/setup.c
@@ -300,7 +300,7 @@
 	}
 };
 
-static u64 iop13xx_adma_dmamask = DMA_BIT_MASK(64);
+static u64 iop13xx_adma_dmamask = DMA_BIT_MASK(32);
 static struct iop_adma_platform_data iop13xx_adma_0_data = {
 	.hw_id = 0,
 	.pool_size = PAGE_SIZE,
@@ -324,7 +324,7 @@
 	.resource = iop13xx_adma_0_resources,
 	.dev = {
 		.dma_mask = &iop13xx_adma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = (void *) &iop13xx_adma_0_data,
 	},
 };
@@ -336,7 +336,7 @@
 	.resource = iop13xx_adma_1_resources,
 	.dev = {
 		.dma_mask = &iop13xx_adma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = (void *) &iop13xx_adma_1_data,
 	},
 };
@@ -348,7 +348,7 @@
 	.resource = iop13xx_adma_2_resources,
 	.dev = {
 		.dma_mask = &iop13xx_adma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = (void *) &iop13xx_adma_2_data,
 	},
 };
--- linux-4.4.0.orig/arch/arm/mach-iop13xx/tpmi.c
+++ linux-4.4.0/arch/arm/mach-iop13xx/tpmi.c
@@ -152,7 +152,7 @@
 	}
 };
 
-u64 iop13xx_tpmi_mask = DMA_BIT_MASK(64);
+u64 iop13xx_tpmi_mask = DMA_BIT_MASK(32);
 static struct platform_device iop13xx_tpmi_0_device = {
 	.name = "iop-tpmi",
 	.id = 0,
@@ -160,7 +160,7 @@
 	.resource = iop13xx_tpmi_0_resources,
 	.dev = {
 		.dma_mask          = &iop13xx_tpmi_mask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 	},
 };
 
@@ -171,7 +171,7 @@
 	.resource = iop13xx_tpmi_1_resources,
 	.dev = {
 		.dma_mask          = &iop13xx_tpmi_mask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 	},
 };
 
@@ -182,7 +182,7 @@
 	.resource = iop13xx_tpmi_2_resources,
 	.dev = {
 		.dma_mask          = &iop13xx_tpmi_mask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 	},
 };
 
@@ -193,7 +193,7 @@
 	.resource = iop13xx_tpmi_3_resources,
 	.dev = {
 		.dma_mask          = &iop13xx_tpmi_mask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 	},
 };
 
--- linux-4.4.0.orig/arch/arm/mach-iop32x/n2100.c
+++ linux-4.4.0/arch/arm/mach-iop32x/n2100.c
@@ -75,8 +75,7 @@
 /*
  * N2100 PCI.
  */
-static int __init
-n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	int irq;
 
--- linux-4.4.0.orig/arch/arm/mach-ks8695/board-acs5k.c
+++ linux-4.4.0/arch/arm/mach-ks8695/board-acs5k.c
@@ -92,7 +92,7 @@
 	},
 };
 
-static void acs5k_i2c_init(void)
+static void __init acs5k_i2c_init(void)
 {
 	/* The gpio interface */
 	platform_device_register(&acs5k_i2c_device);
--- linux-4.4.0.orig/arch/arm/mach-mvebu/Kconfig
+++ linux-4.4.0/arch/arm/mach-mvebu/Kconfig
@@ -37,7 +37,7 @@
 config MACH_ARMADA_375
 	bool "Marvell Armada 375 boards" if ARCH_MULTI_V7
 	select ARM_ERRATA_720789
-	select ARM_ERRATA_753970
+	select PL310_ERRATA_753970
 	select ARM_GIC
 	select ARMADA_375_CLK
 	select HAVE_ARM_SCU
@@ -52,7 +52,7 @@
 config MACH_ARMADA_38X
 	bool "Marvell Armada 380/385 boards" if ARCH_MULTI_V7
 	select ARM_ERRATA_720789
-	select ARM_ERRATA_753970
+	select PL310_ERRATA_753970
 	select ARM_GIC
 	select ARMADA_38X_CLK
 	select HAVE_ARM_SCU
--- linux-4.4.0.orig/arch/arm/mach-mvebu/coherency.c
+++ linux-4.4.0/arch/arm/mach-mvebu/coherency.c
@@ -162,22 +162,16 @@
 }
 
 /*
- * This ioremap hook is used on Armada 375/38x to ensure that PCIe
- * memory areas are mapped as MT_UNCACHED instead of MT_DEVICE. This
- * is needed as a workaround for a deadlock issue between the PCIe
- * interface and the cache controller.
+ * This ioremap hook is used on Armada 375/38x to ensure that all MMIO
+ * areas are mapped as MT_UNCACHED instead of MT_DEVICE. This is
+ * needed for the HW I/O coherency mechanism to work properly without
+ * deadlock.
  */
 static void __iomem *
-armada_pcie_wa_ioremap_caller(phys_addr_t phys_addr, size_t size,
-			      unsigned int mtype, void *caller)
+armada_wa_ioremap_caller(phys_addr_t phys_addr, size_t size,
+			 unsigned int mtype, void *caller)
 {
-	struct resource pcie_mem;
-
-	mvebu_mbus_get_pcie_mem_aperture(&pcie_mem);
-
-	if (pcie_mem.start <= phys_addr && (phys_addr + size) <= pcie_mem.end)
-		mtype = MT_UNCACHED;
-
+	mtype = MT_UNCACHED;
 	return __arm_ioremap_caller(phys_addr, size, mtype, caller);
 }
 
@@ -186,7 +180,7 @@
 	struct device_node *cache_dn;
 
 	coherency_cpu_base = of_iomap(np, 0);
-	arch_ioremap_caller = armada_pcie_wa_ioremap_caller;
+	arch_ioremap_caller = armada_wa_ioremap_caller;
 
 	/*
 	 * We should switch the PL310 to I/O coherency mode only if
--- linux-4.4.0.orig/arch/arm/mach-mvebu/pmsu.c
+++ linux-4.4.0/arch/arm/mach-mvebu/pmsu.c
@@ -117,8 +117,8 @@
 		PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
 }
 
-extern unsigned char mvebu_boot_wa_start;
-extern unsigned char mvebu_boot_wa_end;
+extern unsigned char mvebu_boot_wa_start[];
+extern unsigned char mvebu_boot_wa_end[];
 
 /*
  * This function sets up the boot address workaround needed for SMP
@@ -131,7 +131,7 @@
 			     phys_addr_t resume_addr_reg)
 {
 	void __iomem *sram_virt_base;
-	u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start;
+	u32 code_len = mvebu_boot_wa_end - mvebu_boot_wa_start;
 
 	mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
 	mvebu_mbus_add_window_by_id(crypto_eng_target, crypto_eng_attribute,
--- linux-4.4.0.orig/arch/arm/mach-omap1/board-ams-delta.c
+++ linux-4.4.0/arch/arm/mach-omap1/board-ams-delta.c
@@ -511,6 +511,9 @@
 {
 	struct modem_private_data *priv = port->private_data;
 
+	if (!priv)
+		return;
+
 	if (IS_ERR(priv->regulator))
 		return;
 
--- linux-4.4.0.orig/arch/arm/mach-omap1/clock.c
+++ linux-4.4.0/arch/arm/mach-omap1/clock.c
@@ -1031,17 +1031,17 @@
 		return -ENOMEM;
 	c->dent = d;
 
-	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
+	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount);
 	if (!d) {
 		err = -ENOMEM;
 		goto err_out;
 	}
-	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
+	d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate);
 	if (!d) {
 		err = -ENOMEM;
 		goto err_out;
 	}
-	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
+	d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags);
 	if (!d) {
 		err = -ENOMEM;
 		goto err_out;
--- linux-4.4.0.orig/arch/arm/mach-omap1/dma.c
+++ linux-4.4.0/arch/arm/mach-omap1/dma.c
@@ -31,7 +31,6 @@
 #include "soc.h"
 
 #define OMAP1_DMA_BASE			(0xfffed800)
-#define OMAP1_LOGICAL_DMA_CH_COUNT	17
 
 static u32 enable_1510_mode;
 
@@ -311,8 +310,6 @@
 		goto exit_iounmap;
 	}
 
-	d->lch_count		= OMAP1_LOGICAL_DMA_CH_COUNT;
-
 	/* Valid attributes for omap1 plus processors */
 	if (cpu_is_omap15xx())
 		d->dev_caps = ENABLE_1510_MODE;
@@ -329,13 +326,14 @@
 	d->dev_caps		|= CLEAR_CSR_ON_READ;
 	d->dev_caps		|= IS_WORD_16;
 
-	if (cpu_is_omap15xx())
-		d->chan_count = 9;
-	else if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
-		if (!(d->dev_caps & ENABLE_1510_MODE))
-			d->chan_count = 16;
+	/* available logical channels */
+	if (cpu_is_omap15xx()) {
+		d->lch_count = 9;
+	} else {
+		if (d->dev_caps & ENABLE_1510_MODE)
+			d->lch_count = 9;
 		else
-			d->chan_count = 9;
+			d->lch_count = 16;
 	}
 
 	p = dma_plat_info;
--- linux-4.4.0.orig/arch/arm/mach-omap1/id.c
+++ linux-4.4.0/arch/arm/mach-omap1/id.c
@@ -200,10 +200,10 @@
 		printk(KERN_INFO "Unknown OMAP cpu type: 0x%02x\n", cpu_type);
 	}
 
-	printk(KERN_INFO "OMAP%04x", omap_revision >> 16);
+	pr_info("OMAP%04x", omap_revision >> 16);
 	if ((omap_revision >> 8) & 0xff)
-		printk(KERN_INFO "%x", (omap_revision >> 8) & 0xff);
-	printk(KERN_INFO " revision %i handled as %02xxx id: %08x%08x\n",
+		pr_cont("%x", (omap_revision >> 8) & 0xff);
+	pr_cont(" revision %i handled as %02xxx id: %08x%08x\n",
 	       die_rev, omap_revision & 0xff, system_serial_low,
 	       system_serial_high);
 }
--- linux-4.4.0.orig/arch/arm/mach-omap2/clockdomains7xx_data.c
+++ linux-4.4.0/arch/arm/mach-omap2/clockdomains7xx_data.c
@@ -524,7 +524,7 @@
 	.dep_bit	  = DRA7XX_PCIE_STATDEP_SHIFT,
 	.wkdep_srcs	  = pcie_wkup_sleep_deps,
 	.sleepdep_srcs	  = pcie_wkup_sleep_deps,
-	.flags		  = CLKDM_CAN_HWSUP_SWSUP,
+	.flags		  = CLKDM_CAN_SWSUP,
 };
 
 static struct clockdomain atl_7xx_clkdm = {
--- linux-4.4.0.orig/arch/arm/mach-omap2/cpuidle34xx.c
+++ linux-4.4.0/arch/arm/mach-omap2/cpuidle34xx.c
@@ -34,6 +34,7 @@
 #include "pm.h"
 #include "control.h"
 #include "common.h"
+#include "soc.h"
 
 /* Mach specific information to be recorded in the C-state driver_data */
 struct omap3_idle_statedata {
@@ -315,6 +316,69 @@
 	.safe_state_index = 0,
 };
 
+/*
+ * Numbers based on measurements made in October 2009 for PM optimized kernel
+ * with CPU freq enabled on device Nokia N900. Assumes OPP2 (main idle OPP,
+ * and worst case latencies).
+ */
+static struct cpuidle_driver omap3430_idle_driver = {
+	.name             = "omap3430_idle",
+	.owner            = THIS_MODULE,
+	.states = {
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 110 + 162,
+			.target_residency = 5,
+			.name		  = "C1",
+			.desc		  = "MPU ON + CORE ON",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 106 + 180,
+			.target_residency = 309,
+			.name		  = "C2",
+			.desc		  = "MPU ON + CORE ON",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 107 + 410,
+			.target_residency = 46057,
+			.name		  = "C3",
+			.desc		  = "MPU RET + CORE ON",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 121 + 3374,
+			.target_residency = 46057,
+			.name		  = "C4",
+			.desc		  = "MPU OFF + CORE ON",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 855 + 1146,
+			.target_residency = 46057,
+			.name		  = "C5",
+			.desc		  = "MPU RET + CORE RET",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 7580 + 4134,
+			.target_residency = 484329,
+			.name		  = "C6",
+			.desc		  = "MPU OFF + CORE RET",
+		},
+		{
+			.enter		  = omap3_enter_idle_bm,
+			.exit_latency	  = 7505 + 15274,
+			.target_residency = 484329,
+			.name		  = "C7",
+			.desc		  = "MPU OFF + CORE OFF",
+		},
+	},
+	.state_count = ARRAY_SIZE(omap3_idle_data),
+	.safe_state_index = 0,
+};
+
 /* Public functions */
 
 /**
@@ -333,5 +397,8 @@
 	if (!mpu_pd || !core_pd || !per_pd || !cam_pd)
 		return -ENODEV;
 
-	return cpuidle_register(&omap3_idle_driver, NULL);
+	if (cpu_is_omap3430())
+		return cpuidle_register(&omap3430_idle_driver, NULL);
+	else
+		return cpuidle_register(&omap3_idle_driver, NULL);
 }
--- linux-4.4.0.orig/arch/arm/mach-omap2/display.c
+++ linux-4.4.0/arch/arm/mach-omap2/display.c
@@ -115,6 +115,7 @@
 	u32 enable_mask, enable_shift;
 	u32 pipd_mask, pipd_shift;
 	u32 reg;
+	int ret;
 
 	if (dsi_id == 0) {
 		enable_mask = OMAP4_DSI1_LANEENABLE_MASK;
@@ -130,7 +131,11 @@
 		return -ENODEV;
 	}
 
-	regmap_read(omap4_dsi_mux_syscon, OMAP4_DSIPHY_SYSCON_OFFSET, &reg);
+	ret = regmap_read(omap4_dsi_mux_syscon,
+					  OMAP4_DSIPHY_SYSCON_OFFSET,
+					  &reg);
+	if (ret)
+		return ret;
 
 	reg &= ~enable_mask;
 	reg &= ~pipd_mask;
--- linux-4.4.0.orig/arch/arm/mach-omap2/gpmc-onenand.c
+++ linux-4.4.0/arch/arm/mach-omap2/gpmc-onenand.c
@@ -101,10 +101,8 @@
 
 static void set_onenand_cfg(void __iomem *onenand_base)
 {
-	u32 reg;
+	u32 reg = ONENAND_SYS_CFG1_RDY | ONENAND_SYS_CFG1_INT;
 
-	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
-	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
 	reg |=	(latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
 		ONENAND_SYS_CFG1_BL_16;
 	if (onenand_flags & ONENAND_FLAG_SYNCREAD)
@@ -123,6 +121,7 @@
 		reg |= ONENAND_SYS_CFG1_VHF;
 	else
 		reg &= ~ONENAND_SYS_CFG1_VHF;
+
 	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
 }
 
@@ -289,6 +288,7 @@
 		}
 	}
 
+	onenand_async.sync_write = true;
 	omap2_onenand_calc_async_timings(&t);
 
 	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
@@ -367,7 +367,7 @@
 	return ret;
 }
 
-void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
+int gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
 {
 	int err;
 	struct device *dev = &gpmc_onenand_device.dev;
@@ -393,15 +393,17 @@
 	if (err < 0) {
 		dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
 			gpmc_onenand_data->cs, err);
-		return;
+		return err;
 	}
 
 	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
 							ONENAND_IO_SIZE - 1;
 
-	if (platform_device_register(&gpmc_onenand_device) < 0) {
+	err = platform_device_register(&gpmc_onenand_device);
+	if (err) {
 		dev_err(dev, "Unable to register OneNAND device\n");
 		gpmc_cs_free(gpmc_onenand_data->cs);
-		return;
 	}
+
+	return err;
 }
--- linux-4.4.0.orig/arch/arm/mach-omap2/id.c
+++ linux-4.4.0/arch/arm/mach-omap2/id.c
@@ -199,8 +199,8 @@
 
 	pr_info("%s", soc_name);
 	if ((omap_rev() >> 8) & 0x0f)
-		pr_info("%s", soc_rev);
-	pr_info("\n");
+		pr_cont("%s", soc_rev);
+	pr_cont("\n");
 }
 
 #define OMAP3_SHOW_FEATURE(feat)		\
--- linux-4.4.0.orig/arch/arm/mach-omap2/io.c
+++ linux-4.4.0/arch/arm/mach-omap2/io.c
@@ -368,6 +368,7 @@
 void __init dra7xx_map_io(void)
 {
 	iotable_init(dra7xx_io_desc, ARRAY_SIZE(dra7xx_io_desc));
+	omap_barriers_init();
 }
 #endif
 /*
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap-headsmp.S
+++ linux-4.4.0/arch/arm/mach-omap2/omap-headsmp.S
@@ -17,6 +17,7 @@
 
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <asm/assembler.h>
 
 #include "omap44xx.h"
 
@@ -56,7 +57,7 @@
 	cmp	r0, r4
 	bne	wait_2
 	ldr	r12, =API_HYP_ENTRY
-	adr	r0, hyp_boot
+	badr	r0, hyp_boot
 	smc	#0
 hyp_boot:
 	b	secondary_startup
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -243,10 +243,9 @@
 		save_state = 1;
 		break;
 	case PWRDM_POWER_RET:
-		if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE)) {
+		if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE))
 			save_state = 0;
-			break;
-		}
+		break;
 	default:
 		/*
 		 * CPUx CSWR is invalid hardware state. Also CPUx OSWR
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap-secure.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap-secure.c
@@ -73,6 +73,27 @@
 	return omap_secure_memblock_base;
 }
 
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
+u32 omap3_save_secure_ram(void __iomem *addr, int size)
+{
+	u32 ret;
+	u32 param[5];
+
+	if (size != OMAP3_SAVE_SECURE_RAM_SZ)
+		return OMAP3_SAVE_SECURE_RAM_SZ;
+
+	param[0] = 4;		/* Number of arguments */
+	param[1] = __pa(addr);	/* Physical address for saving */
+	param[2] = 0;
+	param[3] = 1;
+	param[4] = 1;
+
+	ret = save_secure_ram_context(__pa(param));
+
+	return ret;
+}
+#endif
+
 /**
  * rx51_secure_dispatcher: Routine to dispatch secure PPA API calls
  * @idx: The PPA API index
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap-secure.h
+++ linux-4.4.0/arch/arm/mach-omap2/omap-secure.h
@@ -31,6 +31,8 @@
 /* Maximum Secure memory storage size */
 #define OMAP_SECURE_RAM_STORAGE	(88 * SZ_1K)
 
+#define OMAP3_SAVE_SECURE_RAM_SZ	0x803F
+
 /* Secure low power HAL API index */
 #define OMAP4_HAL_SAVESECURERAM_INDEX	0x1a
 #define OMAP4_HAL_SAVEHW_INDEX		0x1b
@@ -64,6 +66,8 @@
 extern u32 omap_smc3(u32 id, u32 process, u32 flag, u32 pargs);
 extern phys_addr_t omap_secure_ram_mempool_base(void);
 extern int omap_secure_ram_reserve_memblock(void);
+extern u32 save_secure_ram_context(u32 args_pa);
+extern u32 omap3_save_secure_ram(void __iomem *save_regs, int size);
 
 extern u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs,
 				  u32 arg1, u32 arg2, u32 arg3, u32 arg4);
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap4-common.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap4-common.c
@@ -131,6 +131,9 @@
 	struct device_node *np;
 	struct gen_pool *sram_pool;
 
+	if (!soc_is_omap44xx() && !soc_is_omap54xx())
+		return 0;
+
 	np = of_find_compatible_node(NULL, NULL, "ti,omap4-mpu");
 	if (!np)
 		pr_warn("%s:Unable to allocate sram needed to handle errata I688\n",
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap_device.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap_device.c
@@ -190,12 +190,22 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct omap_device *od;
+	int err;
 
 	switch (event) {
-	case BUS_NOTIFY_DEL_DEVICE:
+	case BUS_NOTIFY_REMOVED_DEVICE:
 		if (pdev->archdata.od)
 			omap_device_delete(pdev->archdata.od);
 		break;
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		od = to_omap_device(pdev);
+		if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) {
+			dev_info(dev, "enabled after unload, idling\n");
+			err = omap_device_idle(pdev);
+			if (err)
+				dev_err(dev, "failed to idle\n");
+		}
+		break;
 	case BUS_NOTIFY_ADD_DEVICE:
 		if (pdev->dev.of_node)
 			omap_device_build_from_dt(pdev);
@@ -257,7 +267,7 @@
  * function returns a value different than the value the caller got
  * the last time it called this function.
  *
- * If any hwmods exist for the omap_device assoiated with @pdev,
+ * If any hwmods exist for the omap_device associated with @pdev,
  * return the context loss counter for that hwmod, otherwise return
  * zero.
  */
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap_hwmod.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap_hwmod.c
@@ -1416,9 +1416,7 @@
 	    (sf & SYSC_HAS_CLOCKACTIVITY))
 		_set_clockactivity(oh, oh->class->sysc->clockact, &v);
 
-	/* If the cached value is the same as the new value, skip the write */
-	if (oh->_sysc_cache != v)
-		_write_sysconfig(v, oh);
+	_write_sysconfig(v, oh);
 
 	/*
 	 * Set the autoidle bit only after setting the smartidle bit
@@ -1481,7 +1479,9 @@
 		_set_master_standbymode(oh, idlemode, &v);
 	}
 
-	_write_sysconfig(v, oh);
+	/* If the cached value is the same as the new value, skip the write */
+	if (oh->_sysc_cache != v)
+		_write_sysconfig(v, oh);
 }
 
 /**
@@ -2200,17 +2200,22 @@
  */
 static int _idle(struct omap_hwmod *oh)
 {
+	if (oh->flags & HWMOD_NO_IDLE) {
+		oh->_int_flags |= _HWMOD_SKIP_ENABLE;
+		return 0;
+	}
+
 	pr_debug("omap_hwmod: %s: idling\n", oh->name);
 
+	if (_are_all_hardreset_lines_asserted(oh))
+		return 0;
+
 	if (oh->_state != _HWMOD_STATE_ENABLED) {
 		WARN(1, "omap_hwmod: %s: idle state can only be entered from enabled state\n",
 			oh->name);
 		return -EINVAL;
 	}
 
-	if (_are_all_hardreset_lines_asserted(oh))
-		return 0;
-
 	if (oh->class->sysc)
 		_idle_sysc(oh);
 	_del_initiator_dep(oh, mpu_oh);
@@ -2257,6 +2262,9 @@
 	int ret, i;
 	u8 prev_state;
 
+	if (_are_all_hardreset_lines_asserted(oh))
+		return 0;
+
 	if (oh->_state != _HWMOD_STATE_IDLE &&
 	    oh->_state != _HWMOD_STATE_ENABLED) {
 		WARN(1, "omap_hwmod: %s: disabled state can only be entered from idle, or enabled state\n",
@@ -2264,9 +2272,6 @@
 		return -EINVAL;
 	}
 
-	if (_are_all_hardreset_lines_asserted(oh))
-		return 0;
-
 	pr_debug("omap_hwmod: %s: disabling\n", oh->name);
 
 	if (oh->class->pre_shutdown) {
@@ -2504,6 +2509,8 @@
 			oh->flags |= HWMOD_INIT_NO_RESET;
 		if (of_find_property(np, "ti,no-idle-on-init", NULL))
 			oh->flags |= HWMOD_INIT_NO_IDLE;
+		if (of_find_property(np, "ti,no-idle", NULL))
+			oh->flags |= HWMOD_NO_IDLE;
 	}
 
 	oh->_state = _HWMOD_STATE_INITIALIZED;
@@ -2519,7 +2526,7 @@
  * a stub; implementing this properly requires iclk autoidle usecounting in
  * the clock code.   No return value.
  */
-static void __init _setup_iclk_autoidle(struct omap_hwmod *oh)
+static void _setup_iclk_autoidle(struct omap_hwmod *oh)
 {
 	struct omap_hwmod_ocp_if *os;
 	struct list_head *p;
@@ -2554,9 +2561,9 @@
  * reset.  Returns 0 upon success or a negative error code upon
  * failure.
  */
-static int __init _setup_reset(struct omap_hwmod *oh)
+static int _setup_reset(struct omap_hwmod *oh)
 {
-	int r;
+	int r = 0;
 
 	if (oh->_state != _HWMOD_STATE_INITIALIZED)
 		return -EINVAL;
@@ -2615,7 +2622,7 @@
  *
  * No return value.
  */
-static void __init _setup_postsetup(struct omap_hwmod *oh)
+static void _setup_postsetup(struct omap_hwmod *oh)
 {
 	u8 postsetup_state;
 
@@ -2630,7 +2637,7 @@
 	 * XXX HWMOD_INIT_NO_IDLE does not belong in hwmod data -
 	 * it should be set by the core code as a runtime flag during startup
 	 */
-	if ((oh->flags & HWMOD_INIT_NO_IDLE) &&
+	if ((oh->flags & (HWMOD_INIT_NO_IDLE | HWMOD_NO_IDLE)) &&
 	    (postsetup_state == _HWMOD_STATE_IDLE)) {
 		oh->_int_flags |= _HWMOD_SKIP_ENABLE;
 		postsetup_state = _HWMOD_STATE_ENABLED;
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap_hwmod.h
+++ linux-4.4.0/arch/arm/mach-omap2/omap_hwmod.h
@@ -41,6 +41,7 @@
 extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type1;
 extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2;
 extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type3;
+extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type4;
 
 /*
  * OCP SYSCONFIG bit shifts/masks TYPE1. These are for IPs compliant
@@ -81,6 +82,16 @@
 #define SYSC_TYPE3_MIDLEMODE_SHIFT	2
 #define SYSC_TYPE3_MIDLEMODE_MASK	(0x3 << SYSC_TYPE3_MIDLEMODE_SHIFT)
 
+/*
+ * OCP SYSCONFIG bit shifts/masks TYPE4.
+ */
+#define SYSC_TYPE4_SIDLEMODE_SHIFT	2
+#define SYSC_TYPE4_SIDLEMODE_MASK	(0x3 << SYSC_TYPE4_SIDLEMODE_SHIFT)
+#define SYSC_TYPE4_SOFTRESET_SHIFT	1
+#define SYSC_TYPE4_SOFTRESET_MASK	(1 << SYSC_TYPE4_SOFTRESET_SHIFT)
+#define SYSC_TYPE4_AUTOIDLE_SHIFT	0
+#define SYSC_TYPE4_AUTOIDLE_MASK	(1 << SYSC_TYPE4_AUTOIDLE_SHIFT)
+
 /* OCP SYSSTATUS bit shifts/masks */
 #define SYSS_RESETDONE_SHIFT		0
 #define SYSS_RESETDONE_MASK		(1 << SYSS_RESETDONE_SHIFT)
@@ -525,6 +536,8 @@
  *     or idled.
  * HWMOD_OPT_CLKS_NEEDED: The optional clocks are needed for the module to
  *     operate and they need to be handled at the same time as the main_clk.
+ * HWMOD_NO_IDLE: Do not idle the hwmod at all. Useful to handle certain
+ *     IPs like CPSW on DRA7, where clocks to this module cannot be disabled.
  */
 #define HWMOD_SWSUP_SIDLE			(1 << 0)
 #define HWMOD_SWSUP_MSTANDBY			(1 << 1)
@@ -541,6 +554,7 @@
 #define HWMOD_SWSUP_SIDLE_ACT			(1 << 12)
 #define HWMOD_RECONFIG_IO_CHAIN			(1 << 13)
 #define HWMOD_OPT_CLKS_NEEDED			(1 << 14)
+#define HWMOD_NO_IDLE				(1 << 15)
 
 /*
  * omap_hwmod._int_flags definitions
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
@@ -223,6 +223,7 @@
 	.sysc_offs	= 0x84,
 	.syss_offs	= 0x88,
 	.sysc_flags	= SYSS_HAS_RESET_STATUS,
+	.sysc_fields    = &omap_hwmod_sysc_type4,
 };
 
 static struct omap_hwmod_class am33xx_aes0_hwmod_class = {
@@ -1020,7 +1021,8 @@
 	.rev_offs	= 0x0000,
 	.sysc_offs	= 0x0010,
 	.syss_offs	= 0x0014,
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.sysc_flags	= SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			  SYSC_HAS_RESET_STATUS,
 	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
 			  SIDLE_SMART_WKUP),
 	.sysc_fields	= &omap_hwmod_sysc_type2,
@@ -1474,6 +1476,7 @@
 {
 	RSTCTRL(am33xx_pruss_hwmod, AM43XX_RM_PER_RSTCTRL_OFFSET);
 	RSTCTRL(am33xx_gfx_hwmod, AM43XX_RM_GFX_RSTCTRL_OFFSET);
+	RSTST(am33xx_pruss_hwmod, AM43XX_RM_PER_RSTST_OFFSET);
 	RSTST(am33xx_gfx_hwmod, AM43XX_RM_GFX_RSTST_OFFSET);
 }
 
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -723,8 +723,20 @@
  * display serial interface controller
  */
 
+static struct omap_hwmod_class_sysconfig omap3xxx_dsi_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
 static struct omap_hwmod_class omap3xxx_dsi_hwmod_class = {
 	.name = "dsi",
+	.sysc	= &omap3xxx_dsi_sysc,
 };
 
 static struct omap_hwmod_irq_info omap3xxx_dsi1_irqs[] = {
@@ -3873,16 +3885,20 @@
  * Return: 0 if device named @dev_name is not likely to be accessible,
  * or 1 if it is likely to be accessible.
  */
-static int __init omap3xxx_hwmod_is_hs_ip_block_usable(struct device_node *bus,
-						       const char *dev_name)
+static bool __init omap3xxx_hwmod_is_hs_ip_block_usable(struct device_node *bus,
+							const char *dev_name)
 {
+	struct device_node *node;
+	bool available;
+
 	if (!bus)
-		return (omap_type() == OMAP2_DEVICE_TYPE_GP) ? 1 : 0;
+		return omap_type() == OMAP2_DEVICE_TYPE_GP;
 
-	if (of_device_is_available(of_find_node_by_name(bus, dev_name)))
-		return 1;
+	node = of_get_child_by_name(bus, dev_name);
+	available = of_device_is_available(node);
+	of_node_put(node);
 
-	return 0;
+	return available;
 }
 
 int __init omap3xxx_hwmod_init(void)
@@ -3951,15 +3967,20 @@
 
 	if (h_sham && omap3xxx_hwmod_is_hs_ip_block_usable(bus, "sham")) {
 		r = omap_hwmod_register_links(h_sham);
-		if (r < 0)
+		if (r < 0) {
+			of_node_put(bus);
 			return r;
+		}
 	}
 
 	if (h_aes && omap3xxx_hwmod_is_hs_ip_block_usable(bus, "aes")) {
 		r = omap_hwmod_register_links(h_aes);
-		if (r < 0)
+		if (r < 0) {
+			of_node_put(bus);
 			return r;
+		}
 	}
+	of_node_put(bus);
 
 	/*
 	 * Register hwmod links specific to certain ES levels of a
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -4691,6 +4691,59 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/*
+    Crypto modules AES0/1 belong to:
+	PD_L4_PER power domain
+	CD_L4_SEC clock domain
+	On the L3, the AES modules are mapped to
+	L3_CLK2: Peripherals and multimedia sub clock domain
+*/
+
+static struct omap_hwmod_class_sysconfig omap4_aes1_sysc = {
+	.rev_offs	= 0x80,
+	.sysc_offs	= 0x84,
+	.syss_offs	= 0x88,
+	.sysc_flags	= SYSS_HAS_RESET_STATUS,
+	.sysc_fields	= &omap_hwmod_sysc_type4,
+};
+
+static struct omap_hwmod_class omap4_aes1_hwmod_class = {
+	.name		= "aes1",
+	.sysc		= &omap4_aes1_sysc,
+};
+
+static struct omap_hwmod omap4_aes1_hwmod = {
+	.name		= "aes",
+	.class		= &omap4_aes1_hwmod_class,
+	.clkdm_name	= "l4_secure_clkdm",
+	.main_clk	= "aes1_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs = OMAP4_CM_L4SEC_AES1_CLKCTRL_OFFSET,
+			.context_offs = OMAP4_RM_L4SEC_AES1_CONTEXT_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* l3_main_2 -> aes1 */
+static struct omap_hwmod_addr_space omap4_aes1_addrs[] = {
+	{
+		.pa_start	= 0x4B500000,
+		.pa_end		= 0x4B500000 + SZ_1M - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap4_l3_main_2__aes1 = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap4_aes1_hwmod,
+	.clk		= "aes1_fck",
+	.addr		= omap4_aes1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
 	&omap44xx_l3_main_1__dmm,
 	&omap44xx_mpu__dmm,
@@ -4836,6 +4889,7 @@
 	&omap44xx_l4_abe__wd_timer3_dma,
 	&omap44xx_mpu__emif1,
 	&omap44xx_mpu__emif2,
+	&omap4_l3_main_2__aes1,
 	NULL,
 };
 
--- linux-4.4.0.orig/arch/arm/mach-omap2/omap_hwmod_common_data.c
+++ linux-4.4.0/arch/arm/mach-omap2/omap_hwmod_common_data.c
@@ -59,6 +59,16 @@
 	.sidle_shift	= SYSC_TYPE3_SIDLEMODE_SHIFT,
 };
 
+/**
+ * struct omap_hwmod_sysc_type4 - TYPE4 sysconfig scheme.
+ * Used by some IPs on AM33xx
+ */
+struct omap_hwmod_sysc_fields omap_hwmod_sysc_type4 = {
+	.sidle_shift	= SYSC_TYPE4_SIDLEMODE_SHIFT,
+	.srst_shift	= SYSC_TYPE4_SOFTRESET_SHIFT,
+	.autoidle_shift	= SYSC_TYPE4_AUTOIDLE_SHIFT,
+};
+
 struct omap_dss_dispc_dev_attr omap2_3_dss_dispc_dev_attr = {
 	.manager_count		= 2,
 	.has_framedonetv_irq	= 0
--- linux-4.4.0.orig/arch/arm/mach-omap2/pdata-quirks.c
+++ linux-4.4.0/arch/arm/mach-omap2/pdata-quirks.c
@@ -522,7 +522,6 @@
 		if (of_machine_is_compatible(quirks->compatible)) {
 			if (quirks->fn)
 				quirks->fn();
-			break;
 		}
 		quirks++;
 	}
--- linux-4.4.0.orig/arch/arm/mach-omap2/pm.c
+++ linux-4.4.0/arch/arm/mach-omap2/pm.c
@@ -231,7 +231,7 @@
 	cpu_idle_poll_ctrl(false);
 }
 
-static void omap_pm_finish(void)
+static void omap_pm_wake(void)
 {
 	if (cpu_is_omap34xx())
 		omap_prcm_irq_complete();
@@ -241,7 +241,7 @@
 	.begin		= omap_pm_begin,
 	.end		= omap_pm_end,
 	.enter		= omap_pm_enter,
-	.finish		= omap_pm_finish,
+	.wake		= omap_pm_wake,
 	.valid		= suspend_valid_only_mem,
 };
 
--- linux-4.4.0.orig/arch/arm/mach-omap2/pm.h
+++ linux-4.4.0/arch/arm/mach-omap2/pm.h
@@ -81,10 +81,6 @@
 /* ... and its pointer from SRAM after copy */
 extern void (*omap3_do_wfi_sram)(void);
 
-/* save_secure_ram_context function pointer and size, for copy to SRAM */
-extern int save_secure_ram_context(u32 *addr);
-extern unsigned int save_secure_ram_context_sz;
-
 extern void omap3_save_scratchpad_contents(void);
 
 #define PM_RTA_ERRATUM_i608		(1 << 0)
--- linux-4.4.0.orig/arch/arm/mach-omap2/pm34xx.c
+++ linux-4.4.0/arch/arm/mach-omap2/pm34xx.c
@@ -48,6 +48,7 @@
 #include "prm3xxx.h"
 #include "pm.h"
 #include "sdrc.h"
+#include "omap-secure.h"
 #include "sram.h"
 #include "control.h"
 #include "vc.h"
@@ -66,7 +67,6 @@
 
 static LIST_HEAD(pwrst_list);
 
-static int (*_omap_save_secure_sram)(u32 *addr);
 void (*omap3_do_wfi_sram)(void);
 
 static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
@@ -121,8 +121,8 @@
 		 * will hang the system.
 		 */
 		pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
-		ret = _omap_save_secure_sram((u32 *)(unsigned long)
-				__pa(omap3_secure_ram_storage));
+		ret = omap3_save_secure_ram(omap3_secure_ram_storage,
+					    OMAP3_SAVE_SECURE_RAM_SZ);
 		pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
 		/* Following is for error tracking, it should not happen */
 		if (ret) {
@@ -431,15 +431,10 @@
  *
  * The minimum set of functions is pushed to SRAM for execution:
  * - omap3_do_wfi for erratum i581 WA,
- * - save_secure_ram_context for security extensions.
  */
 void omap_push_sram_idle(void)
 {
 	omap3_do_wfi_sram = omap_sram_push(omap3_do_wfi, omap3_do_wfi_sz);
-
-	if (omap_type() != OMAP2_DEVICE_TYPE_GP)
-		_omap_save_secure_sram = omap_sram_push(save_secure_ram_context,
-				save_secure_ram_context_sz);
 }
 
 static void __init pm_errata_configure(void)
@@ -551,7 +546,7 @@
 	clkdm_add_wkdep(neon_clkdm, mpu_clkdm);
 	if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
 		omap3_secure_ram_storage =
-			kmalloc(0x803F, GFP_KERNEL);
+			kmalloc(OMAP3_SAVE_SECURE_RAM_SZ, GFP_KERNEL);
 		if (!omap3_secure_ram_storage)
 			pr_err("Memory allocation failed when allocating for secure sram context\n");
 
--- linux-4.4.0.orig/arch/arm/mach-omap2/prcm43xx.h
+++ linux-4.4.0/arch/arm/mach-omap2/prcm43xx.h
@@ -39,6 +39,7 @@
 
 /* RM RSTST offsets */
 #define AM43XX_RM_GFX_RSTST_OFFSET			0x0014
+#define AM43XX_RM_PER_RSTST_OFFSET			0x0014
 #define AM43XX_RM_WKUP_RSTST_OFFSET			0x0014
 
 /* CM instances */
--- linux-4.4.0.orig/arch/arm/mach-omap2/prm33xx.c
+++ linux-4.4.0/arch/arm/mach-omap2/prm33xx.c
@@ -176,17 +176,6 @@
 	return v;
 }
 
-static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
-{
-	u32 v;
-
-	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
-	v &= AM33XX_LASTPOWERSTATEENTERED_MASK;
-	v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT;
-
-	return v;
-}
-
 static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
 {
 	am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
@@ -357,7 +346,6 @@
 	.pwrdm_set_next_pwrst		= am33xx_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst		= am33xx_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst		= am33xx_pwrdm_read_pwrst,
-	.pwrdm_read_prev_pwrst		= am33xx_pwrdm_read_prev_pwrst,
 	.pwrdm_set_logic_retst		= am33xx_pwrdm_set_logic_retst,
 	.pwrdm_read_logic_pwrst		= am33xx_pwrdm_read_logic_pwrst,
 	.pwrdm_read_logic_retst		= am33xx_pwrdm_read_logic_retst,
--- linux-4.4.0.orig/arch/arm/mach-omap2/prm3xxx.c
+++ linux-4.4.0/arch/arm/mach-omap2/prm3xxx.c
@@ -430,7 +430,7 @@
  * registers, and omap3xxx_prm_reconfigure_io_chain() must be called.
  * No return value.
  */
-static void __init omap3xxx_prm_enable_io_wakeup(void)
+static void omap3xxx_prm_enable_io_wakeup(void)
 {
 	if (prm_features & PRM_HAS_IO_WAKEUP)
 		omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
--- linux-4.4.0.orig/arch/arm/mach-omap2/prm44xx.c
+++ linux-4.4.0/arch/arm/mach-omap2/prm44xx.c
@@ -344,7 +344,7 @@
  * to occur, WAKEUPENABLE bits must be set in the pad mux registers, and
  * omap44xx_prm_reconfigure_io_chain() must be called.  No return value.
  */
-static void __init omap44xx_prm_enable_io_wakeup(void)
+static void omap44xx_prm_enable_io_wakeup(void)
 {
 	s32 inst = omap4_prmst_get_prm_dev_inst();
 
--- linux-4.4.0.orig/arch/arm/mach-omap2/prm_common.c
+++ linux-4.4.0/arch/arm/mach-omap2/prm_common.c
@@ -533,8 +533,10 @@
 
 	prm_ll_data->reset_system();
 
-	while (1)
+	while (1) {
 		cpu_relax();
+		wfe();
+	}
 }
 
 /**
@@ -706,7 +708,7 @@
 };
 #endif
 
-static const struct of_device_id const omap_prcm_dt_match_table[] __initconst = {
+static const struct of_device_id omap_prcm_dt_match_table[] __initconst = {
 #ifdef CONFIG_SOC_AM33XX
 	{ .compatible = "ti,am3-prcm", .data = &am3_prm_data },
 #endif
--- linux-4.4.0.orig/arch/arm/mach-omap2/sleep34xx.S
+++ linux-4.4.0/arch/arm/mach-omap2/sleep34xx.S
@@ -86,22 +86,20 @@
 	stmfd	sp!, {lr}	@ save registers on stack
 	/* Setup so that we will disable and enable l2 */
 	mov	r1, #0x1
-	adrl	r2, l2dis_3630	@ may be too distant for plain adr
-	str	r1, [r2]
+	adrl	r3, l2dis_3630_offset	@ may be too distant for plain adr
+	ldr	r2, [r3]		@ value for offset
+	str	r1, [r2, r3]		@ write to l2dis_3630
 	ldmfd	sp!, {pc}	@ restore regs and return
 ENDPROC(enable_omap3630_toggle_l2_on_restore)
 
-	.text
-/* Function to call rom code to save secure ram context */
-	.align	3
+/*
+ * Function to call rom code to save secure ram context.
+ *
+ * r0 = physical address of the parameters
+ */
 ENTRY(save_secure_ram_context)
 	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack
-	adr	r3, api_params		@ r3 points to parameters
-	str	r0, [r3,#0x4]		@ r0 has sdram address
-	ldr	r12, high_mask
-	and	r3, r3, r12
-	ldr	r12, sram_phy_addr_mask
-	orr	r3, r3, r12
+	mov	r3, r0			@ physical address of parameters
 	mov	r0, #25			@ set service ID for PPA
 	mov	r12, r0			@ copy secure service ID in r12
 	mov	r1, #0			@ set task id for ROM code in r1
@@ -115,16 +113,7 @@
 	nop
 	nop
 	ldmfd	sp!, {r4 - r11, pc}
-	.align
-sram_phy_addr_mask:
-	.word	SRAM_BASE_P
-high_mask:
-	.word	0xffff
-api_params:
-	.word	0x4, 0x0, 0x0, 0x1, 0x1
 ENDPROC(save_secure_ram_context)
-ENTRY(save_secure_ram_context_sz)
-	.word	. - save_secure_ram_context
 
 /*
  * ======================
@@ -289,12 +278,6 @@
 	bic	r5, r5, #0x40
 	str	r5, [r4]
 
-/*
- * PC-relative stores lead to undefined behaviour in Thumb-2: use a r7 as a
- * base instead.
- * Be careful not to clobber r7 when maintaing this code.
- */
-
 is_dll_in_lock_mode:
 	/* Is dll in lock mode? */
 	ldr	r4, sdrc_dlla_ctrl
@@ -302,11 +285,7 @@
 	tst	r5, #0x4
 	bne	exit_nonoff_modes	@ Return if locked
 	/* wait till dll locks */
-	adr	r7, kick_counter
 wait_dll_lock_timed:
-	ldr	r4, wait_dll_lock_counter
-	add	r4, r4, #1
-	str	r4, [r7, #wait_dll_lock_counter - kick_counter]
 	ldr	r4, sdrc_dlla_status
 	/* Wait 20uS for lock */
 	mov	r6, #8
@@ -330,9 +309,6 @@
 	orr	r6, r6, #(1<<3)		@ enable dll
 	str	r6, [r4]
 	dsb
-	ldr	r4, kick_counter
-	add	r4, r4, #1
-	str	r4, [r7]		@ kick_counter
 	b	wait_dll_lock_timed
 
 exit_nonoff_modes:
@@ -360,15 +336,6 @@
 	.word	SDRC_DLLA_STATUS_V
 sdrc_dlla_ctrl:
 	.word	SDRC_DLLA_CTRL_V
-	/*
-	 * When exporting to userspace while the counters are in SRAM,
-	 * these 2 words need to be at the end to facilitate retrival!
-	 */
-kick_counter:
-	.word	0
-wait_dll_lock_counter:
-	.word	0
-
 ENTRY(omap3_do_wfi_sz)
 	.word	. - omap3_do_wfi
 
@@ -437,7 +404,9 @@
 	cmp	r2, #0x0	@ Check if target power state was OFF or RET
 	bne	logic_l1_restore
 
-	ldr	r0, l2dis_3630
+	adr	r1, l2dis_3630_offset	@ address for offset
+	ldr	r0, [r1]		@ value for offset
+	ldr	r0, [r1, r0]		@ value at l2dis_3630
 	cmp	r0, #0x1	@ should we disable L2 on 3630?
 	bne	skipl2dis
 	mrc	p15, 0, r0, c1, c0, 1
@@ -449,12 +418,14 @@
 	and	r1, #0x700
 	cmp	r1, #0x300
 	beq	l2_inv_gp
+	adr	r0, l2_inv_api_params_offset
+	ldr	r3, [r0]
+	add	r3, r3, r0		@ r3 points to dummy parameters
 	mov	r0, #40			@ set service ID for PPA
 	mov	r12, r0			@ copy secure Service ID in r12
 	mov	r1, #0			@ set task id for ROM code in r1
 	mov	r2, #4			@ set some flags in r2, r6
 	mov	r6, #0xff
-	adr	r3, l2_inv_api_params	@ r3 points to dummy parameters
 	dsb				@ data write barrier
 	dmb				@ data memory barrier
 	smc	#1			@ call SMI monitor (smi #1)
@@ -488,8 +459,8 @@
 	b	logic_l1_restore
 
 	.align
-l2_inv_api_params:
-	.word	0x1, 0x00
+l2_inv_api_params_offset:
+	.long	l2_inv_api_params - .
 l2_inv_gp:
 	/* Execute smi to invalidate L2 cache */
 	mov r12, #0x1			@ set up to invalidate L2
@@ -506,7 +477,9 @@
 	mov	r12, #0x2
 	smc	#0			@ Call SMI monitor (smieq)
 logic_l1_restore:
-	ldr	r1, l2dis_3630
+	adr	r0, l2dis_3630_offset	@ adress for offset
+	ldr	r1, [r0]		@ value for offset
+	ldr	r1, [r0, r1]		@ value at l2dis_3630
 	cmp	r1, #0x1		@ Test if L2 re-enable needed on 3630
 	bne	skipl2reen
 	mrc	p15, 0, r1, c1, c0, 1
@@ -535,9 +508,17 @@
 	.word	CONTROL_STAT
 control_mem_rta:
 	.word	CONTROL_MEM_RTA_CTRL
+l2dis_3630_offset:
+	.long	l2dis_3630 - .
+
+	.data
 l2dis_3630:
 	.word	0
 
+	.data
+l2_inv_api_params:
+	.word	0x1, 0x00
+
 /*
  * Internal functions
  */
--- linux-4.4.0.orig/arch/arm/mach-omap2/sleep44xx.S
+++ linux-4.4.0/arch/arm/mach-omap2/sleep44xx.S
@@ -29,12 +29,6 @@
 	dsb
 .endm
 
-ppa_zero_params:
-	.word		0x0
-
-ppa_por_params:
-	.word		1, 0
-
 #ifdef CONFIG_ARCH_OMAP4
 
 /*
@@ -266,7 +260,9 @@
 	beq	skip_ns_smp_enable
 ppa_actrl_retry:
 	mov     r0, #OMAP4_PPA_CPU_ACTRL_SMP_INDEX
-	adr	r3, ppa_zero_params		@ Pointer to parameters
+	adr	r1, ppa_zero_params_offset
+	ldr	r3, [r1]
+	add	r3, r3, r1			@ Pointer to ppa_zero_params
 	mov	r1, #0x0			@ Process ID
 	mov	r2, #0x4			@ Flag
 	mov	r6, #0xff
@@ -303,7 +299,9 @@
 	ldr     r0, =OMAP4_PPA_L2_POR_INDEX
 	ldr     r1, =OMAP44XX_SAR_RAM_BASE
 	ldr     r4, [r1, #L2X0_PREFETCH_CTRL_OFFSET]
-	adr     r3, ppa_por_params
+	adr     r1, ppa_por_params_offset
+	ldr	r3, [r1]
+	add	r3, r3, r1			@ Pointer to ppa_por_params
 	str     r4, [r3, #0x04]
 	mov	r1, #0x0			@ Process ID
 	mov	r2, #0x4			@ Flag
@@ -328,6 +326,8 @@
 #endif
 
 	b	cpu_resume			@ Jump to generic resume
+ppa_por_params_offset:
+	.long	ppa_por_params - .
 ENDPROC(omap4_cpu_resume)
 #endif	/* CONFIG_ARCH_OMAP4 */
 
@@ -380,4 +380,13 @@
 	nop
 
 	ldmfd	sp!, {pc}
+ppa_zero_params_offset:
+	.long	ppa_zero_params - .
 ENDPROC(omap_do_wfi)
+
+	.data
+ppa_zero_params:
+	.word		0
+
+ppa_por_params:
+	.word		1, 0
--- linux-4.4.0.orig/arch/arm/mach-omap2/timer.c
+++ linux-4.4.0/arch/arm/mach-omap2/timer.c
@@ -136,12 +136,6 @@
 	.tick_resume		= omap2_gp_timer_shutdown,
 };
 
-static struct property device_disabled = {
-	.name = "status",
-	.length = sizeof("disabled"),
-	.value = "disabled",
-};
-
 static const struct of_device_id omap_timer_match[] __initconst = {
 	{ .compatible = "ti,omap2420-timer", },
 	{ .compatible = "ti,omap3430-timer", },
@@ -183,8 +177,17 @@
 				  of_get_property(np, "ti,timer-secure", NULL)))
 			continue;
 
-		if (!of_device_is_compatible(np, "ti,omap-counter32k"))
-			of_add_property(np, &device_disabled);
+		if (!of_device_is_compatible(np, "ti,omap-counter32k")) {
+			struct property *prop;
+
+			prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+			if (!prop)
+				return NULL;
+			prop->name = "status";
+			prop->value = "disabled";
+			prop->length = strlen(prop->value);
+			of_add_property(np, prop);
+		}
 		return np;
 	}
 
@@ -496,8 +499,7 @@
 	__omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon",
 			2, "timer_sys_ck", NULL, false);
 
-	if (of_have_populated_dt())
-		clocksource_probe();
+	clocksource_probe();
 }
 
 #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX)
@@ -505,6 +507,8 @@
 {
 	__omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure",
 			2, "timer_sys_ck", NULL, false);
+
+	clocksource_probe();
 }
 #endif /* CONFIG_ARCH_OMAP3 */
 
@@ -513,6 +517,8 @@
 {
 	__omap_sync32k_timer_init(2, "timer_sys_ck", NULL,
 			1, "timer_sys_ck", "ti,timer-alwon", true);
+
+	clocksource_probe();
 }
 #endif
 
--- linux-4.4.0.orig/arch/arm/mach-omap2/vc.c
+++ linux-4.4.0/arch/arm/mach-omap2/vc.c
@@ -559,7 +559,7 @@
 	u8 hsscll_12;
 };
 
-static const struct i2c_init_data const omap4_i2c_timing_data[] __initconst = {
+static const struct i2c_init_data omap4_i2c_timing_data[] __initconst = {
 	{
 		.load = 50,
 		.loadbits = 0x3,
--- linux-4.4.0.orig/arch/arm/mach-prima2/Kconfig
+++ linux-4.4.0/arch/arm/mach-prima2/Kconfig
@@ -1,6 +1,7 @@
 menuconfig ARCH_SIRF
 	bool "CSR SiRF" if ARCH_MULTI_V7
 	select ARCH_HAS_RESET_CONTROLLER
+	select RESET_CONTROLLER
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_IRQ_CHIP
 	select NO_IOPORT_MAP
--- linux-4.4.0.orig/arch/arm/mach-pxa/balloon3.c
+++ linux-4.4.0/arch/arm/mach-pxa/balloon3.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
 #include <linux/fb.h>
--- linux-4.4.0.orig/arch/arm/mach-pxa/cm-x300.c
+++ linux-4.4.0/arch/arm/mach-pxa/cm-x300.c
@@ -547,7 +547,7 @@
 	.exit		= cm_x300_u2d_exit,
 };
 
-static void cm_x300_init_u2d(void)
+static void __init cm_x300_init_u2d(void)
 {
 	pxa3xx_set_u2d_info(&cm_x300_u2d_platform_data);
 }
--- linux-4.4.0.orig/arch/arm/mach-pxa/colibri-pxa270-income.c
+++ linux-4.4.0/arch/arm/mach-pxa/colibri-pxa270-income.c
@@ -17,6 +17,7 @@
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
--- linux-4.4.0.orig/arch/arm/mach-pxa/corgi.c
+++ linux-4.4.0/arch/arm/mach-pxa/corgi.c
@@ -18,6 +18,7 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/mmc/host.h>
 #include <linux/mtd/physmap.h>
 #include <linux/pm.h>
--- linux-4.4.0.orig/arch/arm/mach-pxa/devices.c
+++ linux-4.4.0/arch/arm/mach-pxa/devices.c
@@ -1203,6 +1203,7 @@
 
 static struct mmp_dma_platdata pxa_dma_pdata = {
 	.dma_channels	= 0,
+	.nb_requestors	= 0,
 };
 
 static struct resource pxa_dma_resource[] = {
@@ -1231,8 +1232,9 @@
 	.resource	= pxa_dma_resource,
 };
 
-void __init pxa2xx_set_dmac_info(int nb_channels)
+void __init pxa2xx_set_dmac_info(int nb_channels, int nb_requestors)
 {
 	pxa_dma_pdata.dma_channels = nb_channels;
+	pxa_dma_pdata.nb_requestors = nb_requestors;
 	pxa_register_device(&pxa2xx_pxa_dma, &pxa_dma_pdata);
 }
--- linux-4.4.0.orig/arch/arm/mach-pxa/idp.c
+++ linux-4.4.0/arch/arm/mach-pxa/idp.c
@@ -83,7 +83,8 @@
 };
 
 static struct smc91x_platdata smc91x_platdata = {
-	.flags = SMC91X_USE_32BIT | SMC91X_USE_DMA | SMC91X_NOWAIT,
+	.flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+		 SMC91X_USE_DMA | SMC91X_NOWAIT,
 };
 
 static struct platform_device smc91x_device = {
--- linux-4.4.0.orig/arch/arm/mach-pxa/irq.c
+++ linux-4.4.0/arch/arm/mach-pxa/irq.c
@@ -185,7 +185,7 @@
 {
 	int i;
 
-	for (i = 0; i < pxa_internal_irq_nr / 32; i++) {
+	for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) {
 		void __iomem *base = irq_base(i);
 
 		saved_icmr[i] = __raw_readl(base + ICMR);
@@ -204,7 +204,7 @@
 {
 	int i;
 
-	for (i = 0; i < pxa_internal_irq_nr / 32; i++) {
+	for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) {
 		void __iomem *base = irq_base(i);
 
 		__raw_writel(saved_icmr[i], base + ICMR);
--- linux-4.4.0.orig/arch/arm/mach-pxa/littleton.c
+++ linux-4.4.0/arch/arm/mach-pxa/littleton.c
@@ -183,7 +183,7 @@
 	.lcd_conn		= LCD_COLOR_TFT_16BPP,
 };
 
-static void littleton_init_lcd(void)
+static void __init littleton_init_lcd(void)
 {
 	pxa_set_fb_info(NULL, &littleton_lcd_info);
 }
--- linux-4.4.0.orig/arch/arm/mach-pxa/pxa25x.c
+++ linux-4.4.0/arch/arm/mach-pxa/pxa25x.c
@@ -206,7 +206,7 @@
 		register_syscore_ops(&pxa_irq_syscore_ops);
 		register_syscore_ops(&pxa2xx_mfp_syscore_ops);
 
-		pxa2xx_set_dmac_info(16);
+		pxa2xx_set_dmac_info(16, 40);
 		pxa_register_device(&pxa25x_device_gpio, &pxa25x_gpio_info);
 		ret = platform_add_devices(pxa25x_devices,
 					   ARRAY_SIZE(pxa25x_devices));
--- linux-4.4.0.orig/arch/arm/mach-pxa/pxa27x.c
+++ linux-4.4.0/arch/arm/mach-pxa/pxa27x.c
@@ -309,7 +309,7 @@
 		if (!of_have_populated_dt()) {
 			pxa_register_device(&pxa27x_device_gpio,
 					    &pxa27x_gpio_info);
-			pxa2xx_set_dmac_info(32);
+			pxa2xx_set_dmac_info(32, 75);
 			ret = platform_add_devices(devices,
 						   ARRAY_SIZE(devices));
 		}
--- linux-4.4.0.orig/arch/arm/mach-pxa/pxa3xx.c
+++ linux-4.4.0/arch/arm/mach-pxa/pxa3xx.c
@@ -450,7 +450,7 @@
 		if (of_have_populated_dt())
 			return 0;
 
-		pxa2xx_set_dmac_info(32);
+		pxa2xx_set_dmac_info(32, 100);
 		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
 		if (ret)
 			return ret;
--- linux-4.4.0.orig/arch/arm/mach-pxa/pxa_cplds_irqs.c
+++ linux-4.4.0/arch/arm/mach-pxa/pxa_cplds_irqs.c
@@ -41,30 +41,35 @@
 	unsigned long pending;
 	unsigned int bit;
 
-	pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
-	for_each_set_bit(bit, &pending, CPLDS_NB_IRQ)
-		generic_handle_irq(irq_find_mapping(fpga->irqdomain, bit));
+	do {
+		pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
+		for_each_set_bit(bit, &pending, CPLDS_NB_IRQ) {
+			generic_handle_irq(irq_find_mapping(fpga->irqdomain,
+							    bit));
+		}
+	} while (pending);
 
 	return IRQ_HANDLED;
 }
 
-static void cplds_irq_mask_ack(struct irq_data *d)
+static void cplds_irq_mask(struct irq_data *d)
 {
 	struct cplds *fpga = irq_data_get_irq_chip_data(d);
 	unsigned int cplds_irq = irqd_to_hwirq(d);
-	unsigned int set, bit = BIT(cplds_irq);
+	unsigned int bit = BIT(cplds_irq);
 
 	fpga->irq_mask &= ~bit;
 	writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
-	set = readl(fpga->base + FPGA_IRQ_SET_CLR);
-	writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
 }
 
 static void cplds_irq_unmask(struct irq_data *d)
 {
 	struct cplds *fpga = irq_data_get_irq_chip_data(d);
 	unsigned int cplds_irq = irqd_to_hwirq(d);
-	unsigned int bit = BIT(cplds_irq);
+	unsigned int set, bit = BIT(cplds_irq);
+
+	set = readl(fpga->base + FPGA_IRQ_SET_CLR);
+	writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
 
 	fpga->irq_mask |= bit;
 	writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
@@ -72,7 +77,8 @@
 
 static struct irq_chip cplds_irq_chip = {
 	.name		= "pxa_cplds",
-	.irq_mask_ack	= cplds_irq_mask_ack,
+	.irq_ack	= cplds_irq_mask,
+	.irq_mask	= cplds_irq_mask,
 	.irq_unmask	= cplds_irq_unmask,
 	.flags		= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
 };
--- linux-4.4.0.orig/arch/arm/mach-pxa/tosa-bt.c
+++ linux-4.4.0/arch/arm/mach-pxa/tosa-bt.c
@@ -132,3 +132,7 @@
 	},
 };
 module_platform_driver(tosa_bt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dmitry Baryshkov");
+MODULE_DESCRIPTION("Bluetooth built-in chip control");
--- linux-4.4.0.orig/arch/arm/mach-pxa/trizeps4.c
+++ linux-4.4.0/arch/arm/mach-pxa/trizeps4.c
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
--- linux-4.4.0.orig/arch/arm/mach-pxa/vpac270.c
+++ linux-4.4.0/arch/arm/mach-pxa/vpac270.c
@@ -15,6 +15,7 @@
 #include <linux/irq.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
+#include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/mtd/mtd.h>
--- linux-4.4.0.orig/arch/arm/mach-pxa/xcep.c
+++ linux-4.4.0/arch/arm/mach-pxa/xcep.c
@@ -120,7 +120,8 @@
 };
 
 static struct smc91x_platdata xcep_smc91x_info = {
-	.flags	= SMC91X_USE_32BIT | SMC91X_NOWAIT | SMC91X_USE_DMA,
+	.flags	= SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+		  SMC91X_NOWAIT | SMC91X_USE_DMA,
 };
 
 static struct platform_device smc91x_device = {
--- linux-4.4.0.orig/arch/arm/mach-pxa/zeus.c
+++ linux-4.4.0/arch/arm/mach-pxa/zeus.c
@@ -13,6 +13,7 @@
 
 #include <linux/cpufreq.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/irq.h>
 #include <linux/pm.h>
 #include <linux/gpio.h>
@@ -557,7 +558,7 @@
 	.flags		= ENABLE_PORT_ALL | POWER_SENSE_LOW,
 };
 
-static void zeus_register_ohci(void)
+static void __init zeus_register_ohci(void)
 {
 	/* Port 2 is shared between host and client interface. */
 	UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE;
--- linux-4.4.0.orig/arch/arm/mach-pxa/zylonite.c
+++ linux-4.4.0/arch/arm/mach-pxa/zylonite.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
--- linux-4.4.0.orig/arch/arm/mach-realview/core.c
+++ linux-4.4.0/arch/arm/mach-realview/core.c
@@ -95,7 +95,8 @@
 };
 
 static struct smc91x_platdata smc91x_platdata = {
-	.flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+	.flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+		 SMC91X_NOWAIT,
 };
 
 static struct platform_device realview_eth_device = {
--- linux-4.4.0.orig/arch/arm/mach-rpc/dma.c
+++ linux-4.4.0/arch/arm/mach-rpc/dma.c
@@ -131,7 +131,7 @@
 	} while (1);
 
 	idma->state = ~DMA_ST_AB;
-	disable_irq(irq);
+	disable_irq_nosync(irq);
 
 	return IRQ_HANDLED;
 }
@@ -174,6 +174,9 @@
 				DMA_FROM_DEVICE : DMA_TO_DEVICE);
 		}
 
+		idma->dma_addr = idma->dma.sg->dma_address;
+		idma->dma_len = idma->dma.sg->length;
+
 		iomd_writeb(DMA_CR_C, dma_base + CR);
 		idma->state = DMA_ST_AB;
 	}
--- linux-4.4.0.orig/arch/arm/mach-rpc/irq.c
+++ linux-4.4.0/arch/arm/mach-rpc/irq.c
@@ -117,7 +117,7 @@
 
 void __init rpc_init_irq(void)
 {
-	unsigned int irq, clr, set = 0;
+	unsigned int irq, clr, set;
 
 	iomd_writeb(0, IOMD_IRQMASKA);
 	iomd_writeb(0, IOMD_IRQMASKB);
@@ -129,6 +129,7 @@
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
 		clr = IRQ_NOREQUEST;
+		set = 0;
 
 		if (irq <= 6 || (irq >= 9 && irq <= 15))
 			clr |= IRQ_NOPROBE;
--- linux-4.4.0.orig/arch/arm/mach-s3c24xx/mach-osiris-dvs.c
+++ linux-4.4.0/arch/arm/mach-s3c24xx/mach-osiris-dvs.c
@@ -70,16 +70,16 @@
 
 	switch (val) {
 	case CPUFREQ_PRECHANGE:
-		if (old_dvs & !new_dvs ||
-		    cur_dvs & !new_dvs) {
+		if ((old_dvs && !new_dvs) ||
+		    (cur_dvs && !new_dvs)) {
 			pr_debug("%s: exiting dvs\n", __func__);
 			cur_dvs = false;
 			gpio_set_value(OSIRIS_GPIO_DVS, 1);
 		}
 		break;
 	case CPUFREQ_POSTCHANGE:
-		if (!old_dvs & new_dvs ||
-		    !cur_dvs & new_dvs) {
+		if ((!old_dvs && new_dvs) ||
+		    (!cur_dvs && new_dvs)) {
 			pr_debug("entering dvs\n");
 			cur_dvs = true;
 			gpio_set_value(OSIRIS_GPIO_DVS, 0);
--- linux-4.4.0.orig/arch/arm/mach-s3c64xx/dev-audio.c
+++ linux-4.4.0/arch/arm/mach-s3c64xx/dev-audio.c
@@ -54,12 +54,12 @@
 
 static struct resource s3c64xx_iis0_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_I2S0_OUT),
-	[2] = DEFINE_RES_DMA(DMACH_I2S0_IN),
 };
 
-static struct s3c_audio_pdata i2sv3_pdata = {
+static struct s3c_audio_pdata i2s0_pdata = {
 	.cfg_gpio = s3c64xx_i2s_cfg_gpio,
+	.dma_playback = DMACH_I2S0_OUT,
+	.dma_capture = DMACH_I2S0_IN,
 };
 
 struct platform_device s3c64xx_device_iis0 = {
@@ -68,15 +68,19 @@
 	.num_resources	  = ARRAY_SIZE(s3c64xx_iis0_resource),
 	.resource	  = s3c64xx_iis0_resource,
 	.dev = {
-		.platform_data = &i2sv3_pdata,
+		.platform_data = &i2s0_pdata,
 	},
 };
 EXPORT_SYMBOL(s3c64xx_device_iis0);
 
 static struct resource s3c64xx_iis1_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_I2S1_OUT),
-	[2] = DEFINE_RES_DMA(DMACH_I2S1_IN),
+};
+
+static struct s3c_audio_pdata i2s1_pdata = {
+	.cfg_gpio = s3c64xx_i2s_cfg_gpio,
+	.dma_playback = DMACH_I2S1_OUT,
+	.dma_capture = DMACH_I2S1_IN,
 };
 
 struct platform_device s3c64xx_device_iis1 = {
@@ -85,19 +89,19 @@
 	.num_resources	  = ARRAY_SIZE(s3c64xx_iis1_resource),
 	.resource	  = s3c64xx_iis1_resource,
 	.dev = {
-		.platform_data = &i2sv3_pdata,
+		.platform_data = &i2s1_pdata,
 	},
 };
 EXPORT_SYMBOL(s3c64xx_device_iis1);
 
 static struct resource s3c64xx_iisv4_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX),
-	[2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX),
 };
 
 static struct s3c_audio_pdata i2sv4_pdata = {
 	.cfg_gpio = s3c64xx_i2s_cfg_gpio,
+	.dma_playback = DMACH_HSI_I2SV40_TX,
+	.dma_capture = DMACH_HSI_I2SV40_RX,
 	.type = {
 		.i2s = {
 			.quirks = QUIRK_PRI_6CHAN,
@@ -142,12 +146,12 @@
 
 static struct resource s3c64xx_pcm0_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
-	[2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm0_pdata = {
 	.cfg_gpio = s3c64xx_pcm_cfg_gpio,
+	.dma_capture = DMACH_PCM0_RX,
+	.dma_playback = DMACH_PCM0_TX,
 };
 
 struct platform_device s3c64xx_device_pcm0 = {
@@ -163,12 +167,12 @@
 
 static struct resource s3c64xx_pcm1_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
-	[2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm1_pdata = {
 	.cfg_gpio = s3c64xx_pcm_cfg_gpio,
+	.dma_playback = DMACH_PCM1_TX,
+	.dma_capture = DMACH_PCM1_RX,
 };
 
 struct platform_device s3c64xx_device_pcm1 = {
@@ -196,13 +200,14 @@
 
 static struct resource s3c64xx_ac97_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
-	[2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
-	[3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
-	[4] = DEFINE_RES_IRQ(IRQ_AC97),
+	[1] = DEFINE_RES_IRQ(IRQ_AC97),
 };
 
-static struct s3c_audio_pdata s3c_ac97_pdata;
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+	.dma_playback = DMACH_AC97_PCMOUT,
+	.dma_capture = DMACH_AC97_PCMIN,
+	.dma_capture_mic = DMACH_AC97_MICIN,
+};
 
 static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
 
--- linux-4.4.0.orig/arch/arm/mach-s3c64xx/include/mach/dma.h
+++ linux-4.4.0/arch/arm/mach-s3c64xx/include/mach/dma.h
@@ -14,38 +14,38 @@
 #define S3C64XX_DMA_CHAN(name)		((unsigned long)(name))
 
 /* DMA0/SDMA0 */
-#define DMACH_UART0		S3C64XX_DMA_CHAN("uart0_tx")
-#define DMACH_UART0_SRC2	S3C64XX_DMA_CHAN("uart0_rx")
-#define DMACH_UART1		S3C64XX_DMA_CHAN("uart1_tx")
-#define DMACH_UART1_SRC2	S3C64XX_DMA_CHAN("uart1_rx")
-#define DMACH_UART2		S3C64XX_DMA_CHAN("uart2_tx")
-#define DMACH_UART2_SRC2	S3C64XX_DMA_CHAN("uart2_rx")
-#define DMACH_UART3		S3C64XX_DMA_CHAN("uart3_tx")
-#define DMACH_UART3_SRC2	S3C64XX_DMA_CHAN("uart3_rx")
-#define DMACH_PCM0_TX		S3C64XX_DMA_CHAN("pcm0_tx")
-#define DMACH_PCM0_RX		S3C64XX_DMA_CHAN("pcm0_rx")
-#define DMACH_I2S0_OUT		S3C64XX_DMA_CHAN("i2s0_tx")
-#define DMACH_I2S0_IN		S3C64XX_DMA_CHAN("i2s0_rx")
+#define DMACH_UART0		"uart0_tx"
+#define DMACH_UART0_SRC2	"uart0_rx"
+#define DMACH_UART1		"uart1_tx"
+#define DMACH_UART1_SRC2	"uart1_rx"
+#define DMACH_UART2		"uart2_tx"
+#define DMACH_UART2_SRC2	"uart2_rx"
+#define DMACH_UART3		"uart3_tx"
+#define DMACH_UART3_SRC2	"uart3_rx"
+#define DMACH_PCM0_TX		"pcm0_tx"
+#define DMACH_PCM0_RX		"pcm0_rx"
+#define DMACH_I2S0_OUT		"i2s0_tx"
+#define DMACH_I2S0_IN		"i2s0_rx"
 #define DMACH_SPI0_TX		S3C64XX_DMA_CHAN("spi0_tx")
 #define DMACH_SPI0_RX		S3C64XX_DMA_CHAN("spi0_rx")
-#define DMACH_HSI_I2SV40_TX	S3C64XX_DMA_CHAN("i2s2_tx")
-#define DMACH_HSI_I2SV40_RX	S3C64XX_DMA_CHAN("i2s2_rx")
+#define DMACH_HSI_I2SV40_TX	"i2s2_tx"
+#define DMACH_HSI_I2SV40_RX	"i2s2_rx"
 
 /* DMA1/SDMA1 */
-#define DMACH_PCM1_TX		S3C64XX_DMA_CHAN("pcm1_tx")
-#define DMACH_PCM1_RX		S3C64XX_DMA_CHAN("pcm1_rx")
-#define DMACH_I2S1_OUT		S3C64XX_DMA_CHAN("i2s1_tx")
-#define DMACH_I2S1_IN		S3C64XX_DMA_CHAN("i2s1_rx")
+#define DMACH_PCM1_TX		"pcm1_tx"
+#define DMACH_PCM1_RX		"pcm1_rx"
+#define DMACH_I2S1_OUT		"i2s1_tx"
+#define DMACH_I2S1_IN		"i2s1_rx"
 #define DMACH_SPI1_TX		S3C64XX_DMA_CHAN("spi1_tx")
 #define DMACH_SPI1_RX		S3C64XX_DMA_CHAN("spi1_rx")
-#define DMACH_AC97_PCMOUT	S3C64XX_DMA_CHAN("ac97_out")
-#define DMACH_AC97_PCMIN	S3C64XX_DMA_CHAN("ac97_in")
-#define DMACH_AC97_MICIN	S3C64XX_DMA_CHAN("ac97_mic")
-#define DMACH_PWM		S3C64XX_DMA_CHAN("pwm")
-#define DMACH_IRDA		S3C64XX_DMA_CHAN("irda")
-#define DMACH_EXTERNAL		S3C64XX_DMA_CHAN("external")
-#define DMACH_SECURITY_RX	S3C64XX_DMA_CHAN("sec_rx")
-#define DMACH_SECURITY_TX	S3C64XX_DMA_CHAN("sec_tx")
+#define DMACH_AC97_PCMOUT	"ac97_out"
+#define DMACH_AC97_PCMIN	"ac97_in"
+#define DMACH_AC97_MICIN	"ac97_mic"
+#define DMACH_PWM		"pwm"
+#define DMACH_IRDA		"irda"
+#define DMACH_EXTERNAL		"external"
+#define DMACH_SECURITY_RX	"sec_rx"
+#define DMACH_SECURITY_TX	"sec_tx"
 
 enum dma_ch {
 	DMACH_MAX = 32
--- linux-4.4.0.orig/arch/arm/mach-sa1100/clock.c
+++ linux-4.4.0/arch/arm/mach-sa1100/clock.c
@@ -125,6 +125,8 @@
 }
 
 static struct clkops clk_36864_ops = {
+	.enable		= clk_cpu_enable,
+	.disable	= clk_cpu_disable,
 	.get_rate	= clk_36864_get_rate,
 };
 
@@ -140,9 +142,8 @@
 	CLKDEV_INIT(NULL, "OSTIMER0", &clk_36864),
 };
 
-static int __init sa11xx_clk_init(void)
+int __init sa11xx_clk_init(void)
 {
 	clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs));
 	return 0;
 }
-core_initcall(sa11xx_clk_init);
--- linux-4.4.0.orig/arch/arm/mach-sa1100/generic.c
+++ linux-4.4.0/arch/arm/mach-sa1100/generic.c
@@ -34,6 +34,7 @@
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
+#include <mach/reset.h>
 
 #include "generic.h"
 #include <clocksource/pxa.h>
@@ -95,6 +96,8 @@
 
 void sa11x0_restart(enum reboot_mode mode, const char *cmd)
 {
+	clear_reset_status(RESET_STATUS_ALL);
+
 	if (mode == REBOOT_SOFT) {
 		/* Jump into ROM at address 0 */
 		soft_restart(0);
@@ -388,6 +391,7 @@
 	sa11x0_init_irq_nodt(IRQ_GPIO0_SC, irq_resource.start);
 
 	sa1100_init_gpio();
+	sa11xx_clk_init();
 }
 
 /*
--- linux-4.4.0.orig/arch/arm/mach-sa1100/generic.h
+++ linux-4.4.0/arch/arm/mach-sa1100/generic.h
@@ -44,3 +44,5 @@
 #else
 static inline int sa11x0_pm_init(void) { return 0; }
 #endif
+
+int sa11xx_clk_init(void);
--- linux-4.4.0.orig/arch/arm/mach-sa1100/pleb.c
+++ linux-4.4.0/arch/arm/mach-sa1100/pleb.c
@@ -45,7 +45,7 @@
 };
 
 static struct smc91x_platdata smc91x_platdata = {
-	.flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+	.flags = SMC91X_USE_16BIT | SMC91X_USE_8BIT | SMC91X_NOWAIT,
 };
 
 static struct platform_device smc91x_device = {
--- linux-4.4.0.orig/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
+++ linux-4.4.0/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
@@ -41,39 +41,26 @@
 
 #define REGULATOR_IRQ_MASK	BIT(2)	/* IRQ2, active low */
 
-static void __iomem *irqc;
-
-static const u8 da9063_mask_regs[] = {
-	DA9063_REG_IRQ_MASK_A,
-	DA9063_REG_IRQ_MASK_B,
-	DA9063_REG_IRQ_MASK_C,
-	DA9063_REG_IRQ_MASK_D,
-};
-
-/* DA9210 System Control and Event Registers */
+/* start of DA9210 System Control and Event Registers */
 #define DA9210_REG_MASK_A		0x54
-#define DA9210_REG_MASK_B		0x55
-
-static const u8 da9210_mask_regs[] = {
-	DA9210_REG_MASK_A,
-	DA9210_REG_MASK_B,
-};
 
-static void da9xxx_mask_irqs(struct i2c_client *client, const u8 regs[],
-			     unsigned int nregs)
-{
-	unsigned int i;
-
-	dev_info(&client->dev, "Masking %s interrupt sources\n", client->name);
+static void __iomem *irqc;
 
-	for (i = 0; i < nregs; i++) {
-		int error = i2c_smbus_write_byte_data(client, regs[i], ~0);
-		if (error) {
-			dev_err(&client->dev, "i2c error %d\n", error);
-			return;
-		}
-	}
-}
+/* first byte sets the memory pointer, following are consecutive reg values */
+static u8 da9063_irq_clr[] = { DA9063_REG_IRQ_MASK_A, 0xff, 0xff, 0xff, 0xff };
+static u8 da9210_irq_clr[] = { DA9210_REG_MASK_A, 0xff, 0xff };
+
+static struct i2c_msg da9xxx_msgs[2] = {
+	{
+		.addr = 0x58,
+		.len = ARRAY_SIZE(da9063_irq_clr),
+		.buf = da9063_irq_clr,
+	}, {
+		.addr = 0x68,
+		.len = ARRAY_SIZE(da9210_irq_clr),
+		.buf = da9210_irq_clr,
+	},
+};
 
 static int regulator_quirk_notify(struct notifier_block *nb,
 				  unsigned long action, void *data)
@@ -93,12 +80,15 @@
 	client = to_i2c_client(dev);
 	dev_dbg(dev, "Detected %s\n", client->name);
 
-	if ((client->addr == 0x58 && !strcmp(client->name, "da9063")))
-		da9xxx_mask_irqs(client, da9063_mask_regs,
-				 ARRAY_SIZE(da9063_mask_regs));
-	else if (client->addr == 0x68 && !strcmp(client->name, "da9210"))
-		da9xxx_mask_irqs(client, da9210_mask_regs,
-				 ARRAY_SIZE(da9210_mask_regs));
+	if ((client->addr == 0x58 && !strcmp(client->name, "da9063")) ||
+	    (client->addr == 0x68 && !strcmp(client->name, "da9210"))) {
+		int ret;
+
+		dev_info(&client->dev, "clearing da9063/da9210 interrupts\n");
+		ret = i2c_transfer(client->adapter, da9xxx_msgs, ARRAY_SIZE(da9xxx_msgs));
+		if (ret != ARRAY_SIZE(da9xxx_msgs))
+			dev_err(&client->dev, "i2c error %d\n", ret);
+	}
 
 	mon = ioread32(irqc + IRQC_MONITOR);
 	if (mon & REGULATOR_IRQ_MASK)
--- linux-4.4.0.orig/arch/arm/mach-socfpga/headsmp.S
+++ linux-4.4.0/arch/arm/mach-socfpga/headsmp.S
@@ -13,6 +13,7 @@
 #include <asm/assembler.h>
 
 	.arch	armv7-a
+	.arm
 
 ENTRY(secondary_trampoline)
 	/* CPU1 will always fetch from 0x0 when it is brought out of reset.
--- linux-4.4.0.orig/arch/arm/mach-socfpga/pm.c
+++ linux-4.4.0/arch/arm/mach-socfpga/pm.c
@@ -60,14 +60,14 @@
 	if (!ocram_pool) {
 		pr_warn("%s: ocram pool unavailable!\n", __func__);
 		ret = -ENODEV;
-		goto put_node;
+		goto put_device;
 	}
 
 	ocram_base = gen_pool_alloc(ocram_pool, socfpga_sdram_self_refresh_sz);
 	if (!ocram_base) {
 		pr_warn("%s: unable to alloc ocram!\n", __func__);
 		ret = -ENOMEM;
-		goto put_node;
+		goto put_device;
 	}
 
 	ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base);
@@ -78,7 +78,7 @@
 	if (!suspend_ocram_base) {
 		pr_warn("%s: __arm_ioremap_exec failed!\n", __func__);
 		ret = -ENOMEM;
-		goto put_node;
+		goto put_device;
 	}
 
 	/* Copy the code that puts DDR in self refresh to ocram */
@@ -92,6 +92,8 @@
 	if (!socfpga_sdram_self_refresh_in_ocram)
 		ret = -EFAULT;
 
+put_device:
+	put_device(&pdev->dev);
 put_node:
 	of_node_put(np);
 
--- linux-4.4.0.orig/arch/arm/mach-spear/time.c
+++ linux-4.4.0/arch/arm/mach-spear/time.c
@@ -204,7 +204,7 @@
 	setup_irq(irq, &spear_timer_irq);
 }
 
-static const struct of_device_id const timer_of_match[] __initconst = {
+static const struct of_device_id timer_of_match[] __initconst = {
 	{ .compatible = "st,spear-timer", },
 	{ },
 };
--- linux-4.4.0.orig/arch/arm/mach-tegra/Kconfig
+++ linux-4.4.0/arch/arm/mach-tegra/Kconfig
@@ -12,8 +12,6 @@
 	select ARCH_HAS_RESET_CONTROLLER
 	select RESET_CONTROLLER
 	select SOC_BUS
-	select USB_ULPI if USB_PHY
-	select USB_ULPI_VIEWPORT if USB_PHY
 	help
 	  This enables support for NVIDIA Tegra based systems.
 
--- linux-4.4.0.orig/arch/arm/mach-tegra/reset-handler.S
+++ linux-4.4.0/arch/arm/mach-tegra/reset-handler.S
@@ -56,16 +56,16 @@
 	cmp	r6, #TEGRA20
 	beq	1f				@ Yes
 	/* Clear the flow controller flags for this CPU. */
-	cpu_to_csr_reg r1, r0
+	cpu_to_csr_reg r3, r0
 	mov32	r2, TEGRA_FLOW_CTRL_BASE
-	ldr	r1, [r2, r1]
+	ldr	r1, [r2, r3]
 	/* Clear event & intr flag */
 	orr	r1, r1, \
 		#FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
 	movw	r0, #0x3FFD	@ enable, cluster_switch, immed, bitmaps
 				@ & ext flags for CPU power mgnt
 	bic	r1, r1, r0
-	str	r1, [r2]
+	str	r1, [r2, r3]
 1:
 
 	mov32	r9, 0xc09
--- linux-4.4.0.orig/arch/arm/mach-tegra/sleep-tegra30.S
+++ linux-4.4.0/arch/arm/mach-tegra/sleep-tegra30.S
@@ -379,6 +379,14 @@
 	pll_locked r1, r0, CLK_RESET_PLLC_BASE
 	pll_locked r1, r0, CLK_RESET_PLLX_BASE
 
+	tegra_get_soc_id TEGRA_APB_MISC_BASE, r1
+	cmp	r1, #TEGRA30
+	beq	1f
+	ldr	r1, [r0, #CLK_RESET_PLLP_BASE]
+	bic	r1, r1, #(1<<31)	@ disable PllP bypass
+	str	r1, [r0, #CLK_RESET_PLLP_BASE]
+1:
+
 	mov32	r7, TEGRA_TMRUS_BASE
 	ldr	r1, [r7]
 	add	r1, r1, #LOCK_DELAY
@@ -638,7 +646,10 @@
 	str	r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
 
 	/* disable PLLP, PLLA, PLLC and PLLX */
+	tegra_get_soc_id TEGRA_APB_MISC_BASE, r1
+	cmp	r1, #TEGRA30
 	ldr	r0, [r5, #CLK_RESET_PLLP_BASE]
+	orrne	r0, r0, #(1 << 31)	@ enable PllP bypass on fast cluster
 	bic	r0, r0, #(1 << 30)
 	str	r0, [r5, #CLK_RESET_PLLP_BASE]
 	ldr	r0, [r5, #CLK_RESET_PLLA_BASE]
--- linux-4.4.0.orig/arch/arm/mach-tegra/tegra.c
+++ linux-4.4.0/arch/arm/mach-tegra/tegra.c
@@ -155,8 +155,8 @@
 };
 
 DT_MACHINE_START(TEGRA_DT, "NVIDIA Tegra SoC (Flattened Device Tree)")
-	.l2c_aux_val	= 0x3c400001,
-	.l2c_aux_mask	= 0xc20fc3fe,
+	.l2c_aux_val	= 0x3c400000,
+	.l2c_aux_mask	= 0xc20fc3ff,
 	.smp		= smp_ops(tegra_smp_ops),
 	.map_io		= tegra_map_common_io,
 	.init_early	= tegra_init_early,
--- linux-4.4.0.orig/arch/arm/mach-ux500/pm.c
+++ linux-4.4.0/arch/arm/mach-ux500/pm.c
@@ -134,8 +134,8 @@
  */
 bool prcmu_is_cpu_in_wfi(int cpu)
 {
-	return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
-		     PRCM_ARM_WFI_STANDBY_WFI0;
+	return readl(PRCM_ARM_WFI_STANDBY) &
+		(cpu ? PRCM_ARM_WFI_STANDBY_WFI1 : PRCM_ARM_WFI_STANDBY_WFI0);
 }
 
 /*
--- linux-4.4.0.orig/arch/arm/mach-vexpress/spc.c
+++ linux-4.4.0/arch/arm/mach-vexpress/spc.c
@@ -555,8 +555,9 @@
 
 static int __init ve_spc_clk_init(void)
 {
-	int cpu;
+	int cpu, cluster;
 	struct clk *clk;
+	bool init_opp_table[MAX_CLUSTERS] = { false };
 
 	if (!info)
 		return 0; /* Continue only if SPC is initialised */
@@ -582,8 +583,17 @@
 			continue;
 		}
 
+		cluster = topology_physical_package_id(cpu_dev->id);
+		if (init_opp_table[cluster])
+			continue;
+
 		if (ve_init_opp_table(cpu_dev))
 			pr_warn("failed to initialise cpu%d opp table\n", cpu);
+		else if (dev_pm_opp_set_sharing_cpus(cpu_dev,
+			 topology_core_cpumask(cpu_dev->id)))
+			pr_warn("failed to mark OPPs shared for cpu%d\n", cpu);
+		else
+			init_opp_table[cluster] = true;
 	}
 
 	platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0);
--- linux-4.4.0.orig/arch/arm/mach-zynq/common.c
+++ linux-4.4.0/arch/arm/mach-zynq/common.c
@@ -59,7 +59,7 @@
 static void __init zynq_memory_init(void)
 {
 	if (!__pa(PAGE_OFFSET))
-		memblock_reserve(__pa(PAGE_OFFSET), __pa(swapper_pg_dir));
+		memblock_reserve(__pa(PAGE_OFFSET), 0x80000);
 }
 
 static struct platform_device zynq_cpuidle_device = {
--- linux-4.4.0.orig/arch/arm/mach-zynq/platsmp.c
+++ linux-4.4.0/arch/arm/mach-zynq/platsmp.c
@@ -65,7 +65,7 @@
 			* 0x4: Jump by mov instruction
 			* 0x8: Jumping address
 			*/
-			memcpy((__force void *)zero, &zynq_secondary_trampoline,
+			memcpy_toio(zero, &zynq_secondary_trampoline,
 							trampoline_size);
 			writel(address, zero + trampoline_size);
 
--- linux-4.4.0.orig/arch/arm/mm/Kconfig
+++ linux-4.4.0/arch/arm/mm/Kconfig
@@ -396,6 +396,7 @@
 	select CPU_CP15_MPU if !MMU
 	select CPU_HAS_ASID if MMU
 	select CPU_PABRT_V7
+	select CPU_SPECTRE if MMU
 	select CPU_TLB_V7 if MMU
 
 # ARMv7M
@@ -793,6 +794,28 @@
 	help
 	  Say Y here to disable branch prediction.  If unsure, say N.
 
+config CPU_SPECTRE
+	bool
+
+config HARDEN_BRANCH_PREDICTOR
+	bool "Harden the branch predictor against aliasing attacks" if EXPERT
+	depends on CPU_SPECTRE
+	default y
+	help
+	   Speculation attacks against some high-performance processors rely
+	   on being able to manipulate the branch predictor for a victim
+	   context by executing aliasing branches in the attacker context.
+	   Such attacks can be partially mitigated against by clearing
+	   internal branch predictor state and limiting the prediction
+	   logic in some situations.
+
+	   This config option will take CPU-specific actions to harden
+	   the branch predictor against aliasing attacks and may rely on
+	   specific instruction sequences or control bits being set by
+	   the system firmware.
+
+	   If unsure, say Y.
+
 config TLS_REG_EMUL
 	bool
 	select NEED_KUSER_HELPERS
--- linux-4.4.0.orig/arch/arm/mm/Makefile
+++ linux-4.4.0/arch/arm/mm/Makefile
@@ -92,7 +92,7 @@
 obj-$(CONFIG_CPU_FEROCEON)	+= proc-feroceon.o
 obj-$(CONFIG_CPU_V6)		+= proc-v6.o
 obj-$(CONFIG_CPU_V6K)		+= proc-v6.o
-obj-$(CONFIG_CPU_V7)		+= proc-v7.o
+obj-$(CONFIG_CPU_V7)		+= proc-v7.o proc-v7-bugs.o
 obj-$(CONFIG_CPU_V7M)		+= proc-v7m.o
 
 AFLAGS_proc-v6.o	:=-Wa,-march=armv6
--- linux-4.4.0.orig/arch/arm/mm/alignment.c
+++ linux-4.4.0/arch/arm/mm/alignment.c
@@ -767,6 +767,36 @@
 	return NULL;
 }
 
+static int alignment_get_arm(struct pt_regs *regs, u32 *ip, unsigned long *inst)
+{
+	u32 instr = 0;
+	int fault;
+
+	if (user_mode(regs))
+		fault = get_user(instr, ip);
+	else
+		fault = probe_kernel_address(ip, instr);
+
+	*inst = __mem_to_opcode_arm(instr);
+
+	return fault;
+}
+
+static int alignment_get_thumb(struct pt_regs *regs, u16 *ip, u16 *inst)
+{
+	u16 instr = 0;
+	int fault;
+
+	if (user_mode(regs))
+		fault = get_user(instr, ip);
+	else
+		fault = probe_kernel_address(ip, instr);
+
+	*inst = __mem_to_opcode_thumb16(instr);
+
+	return fault;
+}
+
 static int
 do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
@@ -774,10 +804,10 @@
 	unsigned long instr = 0, instrptr;
 	int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
 	unsigned int type;
-	unsigned int fault;
 	u16 tinstr = 0;
 	int isize = 4;
 	int thumb2_32b = 0;
+	int fault;
 
 	if (interrupts_enabled(regs))
 		local_irq_enable();
@@ -786,15 +816,14 @@
 
 	if (thumb_mode(regs)) {
 		u16 *ptr = (u16 *)(instrptr & ~1);
-		fault = probe_kernel_address(ptr, tinstr);
-		tinstr = __mem_to_opcode_thumb16(tinstr);
+
+		fault = alignment_get_thumb(regs, ptr, &tinstr);
 		if (!fault) {
 			if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
 			    IS_T32(tinstr)) {
 				/* Thumb-2 32-bit */
-				u16 tinst2 = 0;
-				fault = probe_kernel_address(ptr + 1, tinst2);
-				tinst2 = __mem_to_opcode_thumb16(tinst2);
+				u16 tinst2;
+				fault = alignment_get_thumb(regs, ptr + 1, &tinst2);
 				instr = __opcode_thumb32_compose(tinstr, tinst2);
 				thumb2_32b = 1;
 			} else {
@@ -803,8 +832,7 @@
 			}
 		}
 	} else {
-		fault = probe_kernel_address((void *)instrptr, instr);
-		instr = __mem_to_opcode_arm(instr);
+		fault = alignment_get_arm(regs, (void *)instrptr, &instr);
 	}
 
 	if (fault) {
--- linux-4.4.0.orig/arch/arm/mm/cache-l2x0.c
+++ linux-4.4.0/arch/arm/mm/cache-l2x0.c
@@ -1228,20 +1228,28 @@
 
 	ret = of_property_read_u32(np, "prefetch-data", &val);
 	if (ret == 0) {
-		if (val)
+		if (val) {
 			prefetch |= L310_PREFETCH_CTRL_DATA_PREFETCH;
-		else
+			*aux_val |= L310_PREFETCH_CTRL_DATA_PREFETCH;
+		} else {
 			prefetch &= ~L310_PREFETCH_CTRL_DATA_PREFETCH;
+			*aux_val &= ~L310_PREFETCH_CTRL_DATA_PREFETCH;
+		}
+		*aux_mask &= ~L310_PREFETCH_CTRL_DATA_PREFETCH;
 	} else if (ret != -EINVAL) {
 		pr_err("L2C-310 OF prefetch-data property value is missing\n");
 	}
 
 	ret = of_property_read_u32(np, "prefetch-instr", &val);
 	if (ret == 0) {
-		if (val)
+		if (val) {
 			prefetch |= L310_PREFETCH_CTRL_INSTR_PREFETCH;
-		else
+			*aux_val |= L310_PREFETCH_CTRL_INSTR_PREFETCH;
+		} else {
 			prefetch &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH;
+			*aux_val &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH;
+		}
+		*aux_mask &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH;
 	} else if (ret != -EINVAL) {
 		pr_err("L2C-310 OF prefetch-instr property value is missing\n");
 	}
--- linux-4.4.0.orig/arch/arm/mm/cache-v7.S
+++ linux-4.4.0/arch/arm/mm/cache-v7.S
@@ -359,14 +359,16 @@
 	ALT_UP(W(nop))
 #endif
 	mcrne	p15, 0, r0, c7, c14, 1		@ clean & invalidate D / U line
+	addne	r0, r0, r2
 
 	tst	r1, r3
 	bic	r1, r1, r3
 	mcrne	p15, 0, r1, c7, c14, 1		@ clean & invalidate D / U line
-1:
-	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D / U line
-	add	r0, r0, r2
 	cmp	r0, r1
+1:
+	mcrlo	p15, 0, r0, c7, c6, 1		@ invalidate D / U line
+	addlo	r0, r0, r2
+	cmplo	r0, r1
 	blo	1b
 	dsb	st
 	ret	lr
--- linux-4.4.0.orig/arch/arm/mm/dma-mapping.c
+++ linux-4.4.0/arch/arm/mm/dma-mapping.c
@@ -774,13 +774,31 @@
 	__arm_dma_free(dev, size, cpu_addr, handle, attrs, true);
 }
 
+/*
+ * The whole dma_get_sgtable() idea is fundamentally unsafe - it seems
+ * that the intention is to allow exporting memory allocated via the
+ * coherent DMA APIs through the dma_buf API, which only accepts a
+ * scattertable.  This presents a couple of problems:
+ * 1. Not all memory allocated via the coherent DMA APIs is backed by
+ *    a struct page
+ * 2. Passing coherent DMA memory into the streaming APIs is not allowed
+ *    as we will try to flush the memory through a different alias to that
+ *    actually being used (and the flushes are redundant.)
+ */
 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));
+	unsigned long pfn = dma_to_pfn(dev, handle);
+	struct page *page;
 	int ret;
 
+	/* If the PFN is not valid, we do not have a struct page */
+	if (!pfn_valid(pfn))
+		return -ENXIO;
+
+	page = pfn_to_page(pfn);
+
 	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
 	if (unlikely(ret))
 		return ret;
--- linux-4.4.0.orig/arch/arm/mm/dump.c
+++ linux-4.4.0/arch/arm/mm/dump.c
@@ -126,8 +126,8 @@
 		.val	= PMD_SECT_USER,
 		.set	= "USR",
 	}, {
-		.mask	= L_PMD_SECT_RDONLY,
-		.val	= L_PMD_SECT_RDONLY,
+		.mask	= L_PMD_SECT_RDONLY | PMD_SECT_AP2,
+		.val	= L_PMD_SECT_RDONLY | PMD_SECT_AP2,
 		.set	= "ro",
 		.clear	= "RW",
 #elif __LINUX_ARM_ARCH__ >= 6
--- linux-4.4.0.orig/arch/arm/mm/fault.c
+++ linux-4.4.0/arch/arm/mm/fault.c
@@ -163,6 +163,9 @@
 {
 	struct siginfo si;
 
+	if (addr > TASK_SIZE)
+		harden_branch_predictor();
+
 #ifdef CONFIG_DEBUG_USER
 	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
 	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
@@ -211,7 +214,7 @@
 {
 	unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;
 
-	if (fsr & FSR_WRITE)
+	if ((fsr & FSR_WRITE) && !(fsr & FSR_CM))
 		mask = VM_WRITE;
 	if (fsr & FSR_LNX_PF)
 		mask = VM_EXEC;
@@ -281,7 +284,7 @@
 
 	if (user_mode(regs))
 		flags |= FAULT_FLAG_USER;
-	if (fsr & FSR_WRITE)
+	if ((fsr & FSR_WRITE) && !(fsr & FSR_CM))
 		flags |= FAULT_FLAG_WRITE;
 
 	/*
@@ -314,8 +317,11 @@
 	 * 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))
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+		if (!user_mode(regs))
+			goto no_context;
 		return 0;
+	}
 
 	/*
 	 * Major/minor page fault accounting is only done on the
@@ -610,9 +616,9 @@
 
 void __init early_abt_enable(void)
 {
-	fsr_info[22].fn = early_abort_handler;
+	fsr_info[FSR_FS_AEA].fn = early_abort_handler;
 	local_abt_enable();
-	fsr_info[22].fn = do_bad;
+	fsr_info[FSR_FS_AEA].fn = do_bad;
 }
 
 #ifndef CONFIG_ARM_LPAE
--- linux-4.4.0.orig/arch/arm/mm/fault.h
+++ linux-4.4.0/arch/arm/mm/fault.h
@@ -5,17 +5,22 @@
  * Fault status register encodings.  We steal bit 31 for our own purposes.
  */
 #define FSR_LNX_PF		(1 << 31)
+#define FSR_CM			(1 << 13)
 #define FSR_WRITE		(1 << 11)
 #define FSR_FS4			(1 << 10)
 #define FSR_FS3_0		(15)
 #define FSR_FS5_0		(0x3f)
 
 #ifdef CONFIG_ARM_LPAE
+#define FSR_FS_AEA		17
+
 static inline int fsr_fs(unsigned int fsr)
 {
 	return fsr & FSR_FS5_0;
 }
 #else
+#define FSR_FS_AEA		22
+
 static inline int fsr_fs(unsigned int fsr)
 {
 	return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6;
--- linux-4.4.0.orig/arch/arm/mm/init.c
+++ linux-4.4.0/arch/arm/mm/init.c
@@ -611,8 +611,8 @@
 		.start  = (unsigned long)_stext,
 		.end    = (unsigned long)__init_begin,
 #ifdef CONFIG_ARM_LPAE
-		.mask   = ~L_PMD_SECT_RDONLY,
-		.prot   = L_PMD_SECT_RDONLY,
+		.mask   = ~(L_PMD_SECT_RDONLY | PMD_SECT_AP2),
+		.prot   = L_PMD_SECT_RDONLY | PMD_SECT_AP2,
 #else
 		.mask   = ~(PMD_SECT_APX | PMD_SECT_AP_WRITE),
 		.prot   = PMD_SECT_APX | PMD_SECT_AP_WRITE,
@@ -691,7 +691,8 @@
 		if (t->flags & PF_KTHREAD)
 			continue;
 		for_each_thread(t, s)
-			set_section_perms(perms, n, true, s->mm);
+			if (s->mm)
+				set_section_perms(perms, n, true, s->mm);
 	}
 	read_unlock(&tasklist_lock);
 	set_section_perms(perms, n, true, current->active_mm);
@@ -716,19 +717,28 @@
 	return 0;
 }
 
+static int kernel_set_to_readonly __read_mostly;
+
 void mark_rodata_ro(void)
 {
+	kernel_set_to_readonly = 1;
 	stop_machine(__mark_rodata_ro, NULL, NULL);
 }
 
 void set_kernel_text_rw(void)
 {
+	if (!kernel_set_to_readonly)
+		return;
+
 	set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), false,
 				current->active_mm);
 }
 
 void set_kernel_text_ro(void)
 {
+	if (!kernel_set_to_readonly)
+		return;
+
 	set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true,
 				current->active_mm);
 }
--- linux-4.4.0.orig/arch/arm/mm/ioremap.c
+++ linux-4.4.0/arch/arm/mm/ioremap.c
@@ -460,7 +460,7 @@
 
 int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
 {
-	BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT);
+	BUG_ON(offset + SZ_64K - 1 > IO_SPACE_LIMIT);
 
 	return ioremap_page_range(PCI_IO_VIRT_BASE + offset,
 				  PCI_IO_VIRT_BASE + offset + SZ_64K,
--- linux-4.4.0.orig/arch/arm/mm/mmap.c
+++ linux-4.4.0/arch/arm/mm/mmap.c
@@ -89,7 +89,7 @@
 
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
@@ -140,7 +140,7 @@
 			addr = PAGE_ALIGN(addr);
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-				(!vma || addr + len <= vma->vm_start))
+				(!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
--- linux-4.4.0.orig/arch/arm/mm/mmu.c
+++ linux-4.4.0/arch/arm/mm/mmu.c
@@ -572,7 +572,7 @@
 	 * in the Short-descriptor translation table format descriptors.
 	 */
 	if (cpu_arch == CPU_ARCH_ARMv7 &&
-		(read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) == 4) {
+		(read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) >= 4) {
 		user_pmd_table |= PMD_PXNTABLE;
 	}
 #endif
@@ -1184,15 +1184,15 @@
 
 	high_memory = __va(arm_lowmem_limit - 1) + 1;
 
+	if (!memblock_limit)
+		memblock_limit = arm_lowmem_limit;
+
 	/*
 	 * Round the memblock limit down to a pmd size.  This
 	 * helps to ensure that we will allocate memory from the
 	 * last full pmd, which should be mapped.
 	 */
-	if (memblock_limit)
-		memblock_limit = round_down(memblock_limit, PMD_SIZE);
-	if (!memblock_limit)
-		memblock_limit = arm_lowmem_limit;
+	memblock_limit = round_down(memblock_limit, PMD_SIZE);
 
 	memblock_set_current_limit(memblock_limit);
 }
--- linux-4.4.0.orig/arch/arm/mm/pageattr.c
+++ linux-4.4.0/arch/arm/mm/pageattr.c
@@ -55,6 +55,9 @@
 	if (end < MODULES_VADDR || start >= MODULES_END)
 		return -EINVAL;
 
+	if (!numpages)
+		return 0;
+
 	data.set_mask = set_mask;
 	data.clear_mask = clear_mask;
 
--- linux-4.4.0.orig/arch/arm/mm/proc-macros.S
+++ linux-4.4.0/arch/arm/mm/proc-macros.S
@@ -4,6 +4,7 @@
  *  VMA_VM_FLAGS
  *  VM_EXEC
  */
+#include <linux/const.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 
@@ -30,7 +31,7 @@
  * act_mm - get current->active_mm
  */
 	.macro	act_mm, rd
-	bic	\rd, sp, #8128
+	bic	\rd, sp, #(THREAD_SIZE - 1) & ~63
 	bic	\rd, \rd, #63
 	ldr	\rd, [\rd, #TI_TASK]
 	ldr	\rd, [\rd, #TSK_ACTIVE_MM]
@@ -258,13 +259,21 @@
 	mcr	p15, 0, ip, c7, c10, 4		@ data write barrier
 	.endm
 
-.macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0
+.macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0, bugs=0
+/*
+ * If we are building for big.Little with branch predictor hardening,
+ * we need the processor function tables to remain available after boot.
+ */
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+	.section ".rodata"
+#endif
 	.type	\name\()_processor_functions, #object
 	.align 2
 ENTRY(\name\()_processor_functions)
 	.word	\dabort
 	.word	\pabort
 	.word	cpu_\name\()_proc_init
+	.word	\bugs
 	.word	cpu_\name\()_proc_fin
 	.word	cpu_\name\()_reset
 	.word	cpu_\name\()_do_idle
@@ -293,6 +302,9 @@
 	.endif
 
 	.size	\name\()_processor_functions, . - \name\()_processor_functions
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+	.previous
+#endif
 .endm
 
 .macro define_cache_functions name:req
--- linux-4.4.0.orig/arch/arm/mm/proc-v7-2level.S
+++ linux-4.4.0/arch/arm/mm/proc-v7-2level.S
@@ -41,11 +41,6 @@
  *	even on Cortex-A8 revisions not affected by 430973.
  *	If IBE is not set, the flush BTAC/BTB won't do anything.
  */
-ENTRY(cpu_ca8_switch_mm)
-#ifdef CONFIG_MMU
-	mov	r2, #0
-	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
-#endif
 ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_MMU
 	mmid	r1, r1				@ get mm->context.id
@@ -66,7 +61,6 @@
 #endif
 	bx	lr
 ENDPROC(cpu_v7_switch_mm)
-ENDPROC(cpu_ca8_switch_mm)
 
 /*
  *	cpu_v7_set_pte_ext(ptep, pte)
--- linux-4.4.0.orig/arch/arm/mm/proc-v7-bugs.c
+++ linux-4.4.0/arch/arm/mm/proc-v7-bugs.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/arm-smccc.h>
+#include <linux/kernel.h>
+#include <linux/psci.h>
+#include <linux/smp.h>
+
+#include <asm/cp15.h>
+#include <asm/cputype.h>
+#include <asm/proc-fns.h>
+#include <asm/system_misc.h>
+
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn);
+
+extern void cpu_v7_iciallu_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
+extern void cpu_v7_bpiall_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
+extern void cpu_v7_smc_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
+extern void cpu_v7_hvc_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
+
+static void harden_branch_predictor_bpiall(void)
+{
+	write_sysreg(0, BPIALL);
+}
+
+static void harden_branch_predictor_iciallu(void)
+{
+	write_sysreg(0, ICIALLU);
+}
+
+static void __maybe_unused call_smc_arch_workaround_1(void)
+{
+	arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+}
+
+static void __maybe_unused call_hvc_arch_workaround_1(void)
+{
+	arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+}
+
+static void cpu_v7_spectre_init(void)
+{
+	const char *spectre_v2_method = NULL;
+	int cpu = smp_processor_id();
+
+	if (per_cpu(harden_branch_predictor_fn, cpu))
+		return;
+
+	switch (read_cpuid_part()) {
+	case ARM_CPU_PART_CORTEX_A8:
+	case ARM_CPU_PART_CORTEX_A9:
+	case ARM_CPU_PART_CORTEX_A12:
+	case ARM_CPU_PART_CORTEX_A17:
+	case ARM_CPU_PART_CORTEX_A73:
+	case ARM_CPU_PART_CORTEX_A75:
+		per_cpu(harden_branch_predictor_fn, cpu) =
+			harden_branch_predictor_bpiall;
+		spectre_v2_method = "BPIALL";
+		break;
+
+	case ARM_CPU_PART_CORTEX_A15:
+	case ARM_CPU_PART_BRAHMA_B15:
+		per_cpu(harden_branch_predictor_fn, cpu) =
+			harden_branch_predictor_iciallu;
+		spectre_v2_method = "ICIALLU";
+		break;
+
+#ifdef CONFIG_ARM_PSCI
+	default:
+		/* Other ARM CPUs require no workaround */
+		if (read_cpuid_implementor() == ARM_CPU_IMP_ARM)
+			break;
+		/* fallthrough */
+		/* Cortex A57/A72 require firmware workaround */
+	case ARM_CPU_PART_CORTEX_A57:
+	case ARM_CPU_PART_CORTEX_A72: {
+		struct arm_smccc_res res;
+
+		if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
+			break;
+
+		switch (psci_ops.conduit) {
+		case PSCI_CONDUIT_HVC:
+			arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+					  ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+			if ((int)res.a0 != 0)
+				break;
+			per_cpu(harden_branch_predictor_fn, cpu) =
+				call_hvc_arch_workaround_1;
+			cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
+			spectre_v2_method = "hypervisor";
+			break;
+
+		case PSCI_CONDUIT_SMC:
+			arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+					  ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+			if ((int)res.a0 != 0)
+				break;
+			per_cpu(harden_branch_predictor_fn, cpu) =
+				call_smc_arch_workaround_1;
+			cpu_do_switch_mm = cpu_v7_smc_switch_mm;
+			spectre_v2_method = "firmware";
+			break;
+
+		default:
+			break;
+		}
+	}
+#endif
+	}
+
+	if (spectre_v2_method)
+		pr_info("CPU%u: Spectre v2: using %s workaround\n",
+			smp_processor_id(), spectre_v2_method);
+}
+#else
+static void cpu_v7_spectre_init(void)
+{
+}
+#endif
+
+static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned,
+						  u32 mask, const char *msg)
+{
+	u32 aux_cr;
+
+	asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (aux_cr));
+
+	if ((aux_cr & mask) != mask) {
+		if (!*warned)
+			pr_err("CPU%u: %s", smp_processor_id(), msg);
+		*warned = true;
+		return false;
+	}
+	return true;
+}
+
+static DEFINE_PER_CPU(bool, spectre_warned);
+
+static bool check_spectre_auxcr(bool *warned, u32 bit)
+{
+	return IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR) &&
+		cpu_v7_check_auxcr_set(warned, bit,
+				       "Spectre v2: firmware did not set auxiliary control register IBE bit, system vulnerable\n");
+}
+
+void cpu_v7_ca8_ibe(void)
+{
+	if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(6)))
+		cpu_v7_spectre_init();
+}
+
+void cpu_v7_ca15_ibe(void)
+{
+	if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(0)))
+		cpu_v7_spectre_init();
+}
+
+void cpu_v7_bugs_init(void)
+{
+	cpu_v7_spectre_init();
+}
--- linux-4.4.0.orig/arch/arm/mm/proc-v7.S
+++ linux-4.4.0/arch/arm/mm/proc-v7.S
@@ -9,6 +9,7 @@
  *
  *  This is the "shell" of the ARMv7 processor support.
  */
+#include <linux/arm-smccc.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
@@ -87,6 +88,37 @@
 	ret	lr
 ENDPROC(cpu_v7_dcache_clean_area)
 
+#ifdef CONFIG_ARM_PSCI
+	.arch_extension sec
+ENTRY(cpu_v7_smc_switch_mm)
+	stmfd	sp!, {r0 - r3}
+	movw	r0, #:lower16:ARM_SMCCC_ARCH_WORKAROUND_1
+	movt	r0, #:upper16:ARM_SMCCC_ARCH_WORKAROUND_1
+	smc	#0
+	ldmfd	sp!, {r0 - r3}
+	b	cpu_v7_switch_mm
+ENDPROC(cpu_v7_smc_switch_mm)
+	.arch_extension virt
+ENTRY(cpu_v7_hvc_switch_mm)
+	stmfd	sp!, {r0 - r3}
+	movw	r0, #:lower16:ARM_SMCCC_ARCH_WORKAROUND_1
+	movt	r0, #:upper16:ARM_SMCCC_ARCH_WORKAROUND_1
+	hvc	#0
+	ldmfd	sp!, {r0 - r3}
+	b	cpu_v7_switch_mm
+ENDPROC(cpu_v7_hvc_switch_mm)
+#endif
+ENTRY(cpu_v7_iciallu_switch_mm)
+	mov	r3, #0
+	mcr	p15, 0, r3, c7, c5, 0		@ ICIALLU
+	b	cpu_v7_switch_mm
+ENDPROC(cpu_v7_iciallu_switch_mm)
+ENTRY(cpu_v7_bpiall_switch_mm)
+	mov	r3, #0
+	mcr	p15, 0, r3, c7, c5, 6		@ flush BTAC/BTB
+	b	cpu_v7_switch_mm
+ENDPROC(cpu_v7_bpiall_switch_mm)
+
 	string	cpu_v7_name, "ARMv7 Processor"
 	.align
 
@@ -152,31 +184,6 @@
 ENDPROC(cpu_v7_do_resume)
 #endif
 
-/*
- * Cortex-A8
- */
-	globl_equ	cpu_ca8_proc_init,	cpu_v7_proc_init
-	globl_equ	cpu_ca8_proc_fin,	cpu_v7_proc_fin
-	globl_equ	cpu_ca8_reset,		cpu_v7_reset
-	globl_equ	cpu_ca8_do_idle,	cpu_v7_do_idle
-	globl_equ	cpu_ca8_dcache_clean_area, cpu_v7_dcache_clean_area
-	globl_equ	cpu_ca8_set_pte_ext,	cpu_v7_set_pte_ext
-	globl_equ	cpu_ca8_suspend_size,	cpu_v7_suspend_size
-#ifdef CONFIG_ARM_CPU_SUSPEND
-	globl_equ	cpu_ca8_do_suspend,	cpu_v7_do_suspend
-	globl_equ	cpu_ca8_do_resume,	cpu_v7_do_resume
-#endif
-
-/*
- * Cortex-A9 processor functions
- */
-	globl_equ	cpu_ca9mp_proc_init,	cpu_v7_proc_init
-	globl_equ	cpu_ca9mp_proc_fin,	cpu_v7_proc_fin
-	globl_equ	cpu_ca9mp_reset,	cpu_v7_reset
-	globl_equ	cpu_ca9mp_do_idle,	cpu_v7_do_idle
-	globl_equ	cpu_ca9mp_dcache_clean_area, cpu_v7_dcache_clean_area
-	globl_equ	cpu_ca9mp_switch_mm,	cpu_v7_switch_mm
-	globl_equ	cpu_ca9mp_set_pte_ext,	cpu_v7_set_pte_ext
 .globl	cpu_ca9mp_suspend_size
 .equ	cpu_ca9mp_suspend_size, cpu_v7_suspend_size + 4 * 2
 #ifdef CONFIG_ARM_CPU_SUSPEND
@@ -488,12 +495,79 @@
 
 	__INITDATA
 
+	.weak cpu_v7_bugs_init
+
 	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
-	define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
+	define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
+
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+	@ generic v7 bpiall on context switch
+	globl_equ	cpu_v7_bpiall_proc_init,	cpu_v7_proc_init
+	globl_equ	cpu_v7_bpiall_proc_fin,		cpu_v7_proc_fin
+	globl_equ	cpu_v7_bpiall_reset,		cpu_v7_reset
+	globl_equ	cpu_v7_bpiall_do_idle,		cpu_v7_do_idle
+	globl_equ	cpu_v7_bpiall_dcache_clean_area, cpu_v7_dcache_clean_area
+	globl_equ	cpu_v7_bpiall_set_pte_ext,	cpu_v7_set_pte_ext
+	globl_equ	cpu_v7_bpiall_suspend_size,	cpu_v7_suspend_size
+#ifdef CONFIG_ARM_CPU_SUSPEND
+	globl_equ	cpu_v7_bpiall_do_suspend,	cpu_v7_do_suspend
+	globl_equ	cpu_v7_bpiall_do_resume,	cpu_v7_do_resume
+#endif
+	define_processor_functions v7_bpiall, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
+
+#define HARDENED_BPIALL_PROCESSOR_FUNCTIONS v7_bpiall_processor_functions
+#else
+#define HARDENED_BPIALL_PROCESSOR_FUNCTIONS v7_processor_functions
+#endif
+
 #ifndef CONFIG_ARM_LPAE
-	define_processor_functions ca8, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
-	define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
+	@ Cortex-A8 - always needs bpiall switch_mm implementation
+	globl_equ	cpu_ca8_proc_init,	cpu_v7_proc_init
+	globl_equ	cpu_ca8_proc_fin,	cpu_v7_proc_fin
+	globl_equ	cpu_ca8_reset,		cpu_v7_reset
+	globl_equ	cpu_ca8_do_idle,	cpu_v7_do_idle
+	globl_equ	cpu_ca8_dcache_clean_area, cpu_v7_dcache_clean_area
+	globl_equ	cpu_ca8_set_pte_ext,	cpu_v7_set_pte_ext
+	globl_equ	cpu_ca8_switch_mm,	cpu_v7_bpiall_switch_mm
+	globl_equ	cpu_ca8_suspend_size,	cpu_v7_suspend_size
+#ifdef CONFIG_ARM_CPU_SUSPEND
+	globl_equ	cpu_ca8_do_suspend,	cpu_v7_do_suspend
+	globl_equ	cpu_ca8_do_resume,	cpu_v7_do_resume
 #endif
+	define_processor_functions ca8, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_ca8_ibe
+
+	@ Cortex-A9 - needs more registers preserved across suspend/resume
+	@ and bpiall switch_mm for hardening
+	globl_equ	cpu_ca9mp_proc_init,	cpu_v7_proc_init
+	globl_equ	cpu_ca9mp_proc_fin,	cpu_v7_proc_fin
+	globl_equ	cpu_ca9mp_reset,	cpu_v7_reset
+	globl_equ	cpu_ca9mp_do_idle,	cpu_v7_do_idle
+	globl_equ	cpu_ca9mp_dcache_clean_area, cpu_v7_dcache_clean_area
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+	globl_equ	cpu_ca9mp_switch_mm,	cpu_v7_bpiall_switch_mm
+#else
+	globl_equ	cpu_ca9mp_switch_mm,	cpu_v7_switch_mm
+#endif
+	globl_equ	cpu_ca9mp_set_pte_ext,	cpu_v7_set_pte_ext
+	define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
+#endif
+
+	@ Cortex-A15 - needs iciallu switch_mm for hardening
+	globl_equ	cpu_ca15_proc_init,	cpu_v7_proc_init
+	globl_equ	cpu_ca15_proc_fin,	cpu_v7_proc_fin
+	globl_equ	cpu_ca15_reset,		cpu_v7_reset
+	globl_equ	cpu_ca15_do_idle,	cpu_v7_do_idle
+	globl_equ	cpu_ca15_dcache_clean_area, cpu_v7_dcache_clean_area
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+	globl_equ	cpu_ca15_switch_mm,	cpu_v7_iciallu_switch_mm
+#else
+	globl_equ	cpu_ca15_switch_mm,	cpu_v7_switch_mm
+#endif
+	globl_equ	cpu_ca15_set_pte_ext,	cpu_v7_set_pte_ext
+	globl_equ	cpu_ca15_suspend_size,	cpu_v7_suspend_size
+	globl_equ	cpu_ca15_do_suspend,	cpu_v7_do_suspend
+	globl_equ	cpu_ca15_do_resume,	cpu_v7_do_resume
+	define_processor_functions ca15, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_ca15_ibe
 #ifdef CONFIG_CPU_PJ4B
 	define_processor_functions pj4b, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
 #endif
@@ -600,7 +674,7 @@
 __v7_ca12mp_proc_info:
 	.long	0x410fc0d0
 	.long	0xff0ffff0
-	__v7_proc __v7_ca12mp_proc_info, __v7_ca12mp_setup
+	__v7_proc __v7_ca12mp_proc_info, __v7_ca12mp_setup, proc_fns = HARDENED_BPIALL_PROCESSOR_FUNCTIONS
 	.size	__v7_ca12mp_proc_info, . - __v7_ca12mp_proc_info
 
 	/*
@@ -610,7 +684,7 @@
 __v7_ca15mp_proc_info:
 	.long	0x410fc0f0
 	.long	0xff0ffff0
-	__v7_proc __v7_ca15mp_proc_info, __v7_ca15mp_setup
+	__v7_proc __v7_ca15mp_proc_info, __v7_ca15mp_setup, proc_fns = ca15_processor_functions
 	.size	__v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
 
 	/*
@@ -620,7 +694,7 @@
 __v7_b15mp_proc_info:
 	.long	0x420f00f0
 	.long	0xff0ffff0
-	__v7_proc __v7_b15mp_proc_info, __v7_b15mp_setup
+	__v7_proc __v7_b15mp_proc_info, __v7_b15mp_setup, proc_fns = ca15_processor_functions
 	.size	__v7_b15mp_proc_info, . - __v7_b15mp_proc_info
 
 	/*
@@ -630,9 +704,25 @@
 __v7_ca17mp_proc_info:
 	.long	0x410fc0e0
 	.long	0xff0ffff0
-	__v7_proc __v7_ca17mp_proc_info, __v7_ca17mp_setup
+	__v7_proc __v7_ca17mp_proc_info, __v7_ca17mp_setup, proc_fns = HARDENED_BPIALL_PROCESSOR_FUNCTIONS
 	.size	__v7_ca17mp_proc_info, . - __v7_ca17mp_proc_info
 
+	/* ARM Ltd. Cortex A73 processor */
+	.type	__v7_ca73_proc_info, #object
+__v7_ca73_proc_info:
+	.long	0x410fd090
+	.long	0xff0ffff0
+	__v7_proc __v7_ca73_proc_info, __v7_setup, proc_fns = HARDENED_BPIALL_PROCESSOR_FUNCTIONS
+	.size	__v7_ca73_proc_info, . - __v7_ca73_proc_info
+
+	/* ARM Ltd. Cortex A75 processor */
+	.type	__v7_ca75_proc_info, #object
+__v7_ca75_proc_info:
+	.long	0x410fd0a0
+	.long	0xff0ffff0
+	__v7_proc __v7_ca75_proc_info, __v7_setup, proc_fns = HARDENED_BPIALL_PROCESSOR_FUNCTIONS
+	.size	__v7_ca75_proc_info, . - __v7_ca75_proc_info
+
 	/*
 	 * Qualcomm Inc. Krait processors.
 	 */
--- linux-4.4.0.orig/arch/arm/plat-iop/adma.c
+++ linux-4.4.0/arch/arm/plat-iop/adma.c
@@ -143,7 +143,7 @@
 	.resource = iop3xx_dma_0_resources,
 	.dev = {
 		.dma_mask = &iop3xx_adma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = (void *) &iop3xx_dma_0_data,
 	},
 };
@@ -155,7 +155,7 @@
 	.resource = iop3xx_dma_1_resources,
 	.dev = {
 		.dma_mask = &iop3xx_adma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = (void *) &iop3xx_dma_1_data,
 	},
 };
@@ -167,7 +167,7 @@
 	.resource = iop3xx_aau_resources,
 	.dev = {
 		.dma_mask = &iop3xx_adma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = (void *) &iop3xx_aau_data,
 	},
 };
--- linux-4.4.0.orig/arch/arm/plat-omap/dmtimer.c
+++ linux-4.4.0/arch/arm/plat-omap/dmtimer.c
@@ -854,11 +854,8 @@
 	timer->irq = irq->start;
 	timer->pdev = pdev;
 
-	/* Skip pm_runtime_enable for OMAP1 */
-	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
-		pm_runtime_enable(dev);
-		pm_runtime_irq_safe(dev);
-	}
+	pm_runtime_enable(dev);
+	pm_runtime_irq_safe(dev);
 
 	if (!timer->reserved) {
 		ret = pm_runtime_get_sync(dev);
--- linux-4.4.0.orig/arch/arm/plat-orion/common.c
+++ linux-4.4.0/arch/arm/plat-orion/common.c
@@ -645,7 +645,7 @@
 	.resource	= orion_xor0_shared_resources,
 	.dev            = {
 		.dma_mask               = &orion_xor_dmamask,
-		.coherent_dma_mask      = DMA_BIT_MASK(64),
+		.coherent_dma_mask      = DMA_BIT_MASK(32),
 		.platform_data          = &orion_xor0_pdata,
 	},
 };
@@ -706,7 +706,7 @@
 	.resource	= orion_xor1_shared_resources,
 	.dev            = {
 		.dma_mask               = &orion_xor_dmamask,
-		.coherent_dma_mask      = DMA_BIT_MASK(64),
+		.coherent_dma_mask      = DMA_BIT_MASK(32),
 		.platform_data          = &orion_xor1_pdata,
 	},
 };
--- linux-4.4.0.orig/arch/arm/plat-pxa/include/plat/dma.h
+++ linux-4.4.0/arch/arm/plat-pxa/include/plat/dma.h
@@ -95,6 +95,6 @@
 }
 #endif
 
-extern void __init pxa2xx_set_dmac_info(int nb_channels);
+extern void __init pxa2xx_set_dmac_info(int nb_channels, int nb_requestors);
 
 #endif /* __PLAT_DMA_H */
--- linux-4.4.0.orig/arch/arm/plat-pxa/ssp.c
+++ linux-4.4.0/arch/arm/plat-pxa/ssp.c
@@ -231,25 +231,16 @@
 
 static int pxa_ssp_remove(struct platform_device *pdev)
 {
-	struct resource *res;
 	struct ssp_device *ssp;
 
 	ssp = platform_get_drvdata(pdev);
 	if (ssp == NULL)
 		return -ENODEV;
 
-	iounmap(ssp->mmio_base);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, resource_size(res));
-
-	clk_put(ssp->clk);
-
 	mutex_lock(&ssp_lock);
 	list_del(&ssp->node);
 	mutex_unlock(&ssp_lock);
 
-	kfree(ssp);
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/arm/plat-samsung/Kconfig
+++ linux-4.4.0/arch/arm/plat-samsung/Kconfig
@@ -239,6 +239,7 @@
 	bool "Samsung PM Suspend debug"
 	depends on PM && DEBUG_KERNEL
 	depends on DEBUG_EXYNOS_UART || DEBUG_S3C24XX_UART || DEBUG_S3C2410_UART
+	depends on DEBUG_LL && MMU
 	help
 	  Say Y here if you want verbose debugging from the PM Suspend and
 	  Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
@@ -255,7 +256,7 @@
 
 config SAMSUNG_PM_CHECK
 	bool "S3C2410 PM Suspend Memory CRC"
-	depends on PM
+	depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210)
 	select CRC32
 	help
 	  Enable the PM code's memory area checksum over sleep. This option
--- linux-4.4.0.orig/arch/arm/plat-samsung/devs.c
+++ linux-4.4.0/arch/arm/plat-samsung/devs.c
@@ -65,6 +65,7 @@
 #include <linux/platform_data/usb-ohci-s3c2410.h>
 #include <plat/usb-phy.h>
 #include <plat/regs-spi.h>
+#include <linux/platform_data/asoc-s3c.h>
 #include <linux/platform_data/spi-s3c64xx.h>
 
 static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
@@ -74,9 +75,12 @@
 static struct resource s3c_ac97_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97),
 	[1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97),
-	[2] = DEFINE_RES_DMA_NAMED(DMACH_PCM_OUT, "PCM out"),
-	[3] = DEFINE_RES_DMA_NAMED(DMACH_PCM_IN, "PCM in"),
-	[4] = DEFINE_RES_DMA_NAMED(DMACH_MIC_IN, "Mic in"),
+};
+
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+	.dma_playback = (void *)DMACH_PCM_OUT,
+	.dma_capture = (void *)DMACH_PCM_IN,
+	.dma_capture_mic = (void *)DMACH_MIC_IN,
 };
 
 struct platform_device s3c_device_ac97 = {
@@ -87,6 +91,7 @@
 	.dev		= {
 		.dma_mask		= &samsung_device_dma_mask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &s3c_ac97_pdata,
 	}
 };
 #endif /* CONFIG_CPU_S3C2440 */
--- linux-4.4.0.orig/arch/arm/probes/kprobes/core.c
+++ linux-4.4.0/arch/arm/probes/kprobes/core.c
@@ -433,6 +433,7 @@
 	struct hlist_node *tmp;
 	unsigned long flags, orig_ret_address = 0;
 	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+	kprobe_opcode_t *correct_ret_addr = NULL;
 
 	INIT_HLIST_HEAD(&empty_rp);
 	kretprobe_hash_lock(current, &head, &flags);
@@ -455,14 +456,34 @@
 			/* another task is sharing our hash bucket */
 			continue;
 
+		orig_ret_address = (unsigned long)ri->ret_addr;
+
+		if (orig_ret_address != trampoline_address)
+			/*
+			 * This is the real return address. Any other
+			 * instances associated with this task are for
+			 * other calls deeper on the call stack
+			 */
+			break;
+	}
+
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
+	correct_ret_addr = ri->ret_addr;
+	hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+		if (ri->task != current)
+			/* another task is sharing our hash bucket */
+			continue;
+
+		orig_ret_address = (unsigned long)ri->ret_addr;
 		if (ri->rp && ri->rp->handler) {
 			__this_cpu_write(current_kprobe, &ri->rp->kp);
 			get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
+			ri->ret_addr = correct_ret_addr;
 			ri->rp->handler(ri, regs);
 			__this_cpu_write(current_kprobe, NULL);
 		}
 
-		orig_ret_address = (unsigned long)ri->ret_addr;
 		recycle_rp_inst(ri, &empty_rp);
 
 		if (orig_ret_address != trampoline_address)
@@ -474,7 +495,6 @@
 			break;
 	}
 
-	kretprobe_assert(ri, orig_ret_address, trampoline_address);
 	kretprobe_hash_unlock(current, &flags);
 
 	hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
--- linux-4.4.0.orig/arch/arm/probes/kprobes/opt-arm.c
+++ linux-4.4.0/arch/arm/probes/kprobes/opt-arm.c
@@ -165,13 +165,14 @@
 {
 	unsigned long flags;
 	struct kprobe *p = &op->kp;
-	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	struct kprobe_ctlblk *kcb;
 
 	/* Save skipped registers */
 	regs->ARM_pc = (unsigned long)op->kp.addr;
 	regs->ARM_ORIG_r0 = ~0UL;
 
 	local_irq_save(flags);
+	kcb = get_kprobe_ctlblk();
 
 	if (kprobe_running()) {
 		kprobes_inc_nmissed_count(&op->kp);
@@ -191,6 +192,7 @@
 
 	local_irq_restore(flags);
 }
+NOKPROBE_SYMBOL(optimized_callback)
 
 int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig)
 {
--- linux-4.4.0.orig/arch/arm/probes/kprobes/test-core.c
+++ linux-4.4.0/arch/arm/probes/kprobes/test-core.c
@@ -976,7 +976,10 @@
 void __naked __kprobes_test_case_start(void)
 {
 	__asm__ __volatile__ (
-		"stmdb	sp!, {r4-r11}				\n\t"
+		"mov	r2, sp					\n\t"
+		"bic	r3, r2, #7				\n\t"
+		"mov	sp, r3					\n\t"
+		"stmdb	sp!, {r2-r11}				\n\t"
 		"sub	sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
 		"bic	r0, lr, #1  @ r0 = inline data		\n\t"
 		"mov	r1, sp					\n\t"
@@ -996,7 +999,8 @@
 		"movne	pc, r0					\n\t"
 		"mov	r0, r4					\n\t"
 		"add	sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
-		"ldmia	sp!, {r4-r11}				\n\t"
+		"ldmia	sp!, {r2-r11}				\n\t"
+		"mov	sp, r2					\n\t"
 		"mov	pc, r0					\n\t"
 	);
 }
@@ -1012,7 +1016,8 @@
 		"bxne	r0					\n\t"
 		"mov	r0, r4					\n\t"
 		"add	sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
-		"ldmia	sp!, {r4-r11}				\n\t"
+		"ldmia	sp!, {r2-r11}				\n\t"
+		"mov	sp, r2					\n\t"
 		"bx	r0					\n\t"
 	);
 }
--- linux-4.4.0.orig/arch/arm/vfp/vfpmodule.c
+++ linux-4.4.0/arch/arm/vfp/vfpmodule.c
@@ -558,12 +558,11 @@
  * Save the current VFP state into the provided structures and prepare
  * for entry into a new function (signal handler).
  */
-int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
-				    struct user_vfp_exc __user *ufp_exc)
+int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp,
+				    struct user_vfp_exc *ufp_exc)
 {
 	struct thread_info *thread = current_thread_info();
 	struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
-	int err = 0;
 
 	/* Ensure that the saved hwstate is up-to-date. */
 	vfp_sync_hwstate(thread);
@@ -572,22 +571,19 @@
 	 * Copy the floating point registers. There can be unused
 	 * registers see asm/hwcap.h for details.
 	 */
-	err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs,
-			      sizeof(hwstate->fpregs));
+	memcpy(&ufp->fpregs, &hwstate->fpregs, sizeof(hwstate->fpregs));
+
 	/*
 	 * Copy the status and control register.
 	 */
-	__put_user_error(hwstate->fpscr, &ufp->fpscr, err);
+	ufp->fpscr = hwstate->fpscr;
 
 	/*
 	 * Copy the exception registers.
 	 */
-	__put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err);
-	__put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
-	__put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);
-
-	if (err)
-		return -EFAULT;
+	ufp_exc->fpexc = hwstate->fpexc;
+	ufp_exc->fpinst = hwstate->fpinst;
+	ufp_exc->fpinst2 = hwstate->fpinst2;
 
 	/* Ensure that VFP is disabled. */
 	vfp_flush_hwstate(thread);
@@ -601,13 +597,11 @@
 }
 
 /* Sanitise and restore the current VFP state from the provided structures. */
-int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
-			     struct user_vfp_exc __user *ufp_exc)
+int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc)
 {
 	struct thread_info *thread = current_thread_info();
 	struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
 	unsigned long fpexc;
-	int err = 0;
 
 	/* Disable VFP to avoid corrupting the new thread state. */
 	vfp_flush_hwstate(thread);
@@ -616,17 +610,16 @@
 	 * Copy the floating point registers. There can be unused
 	 * registers see asm/hwcap.h for details.
 	 */
-	err |= __copy_from_user(&hwstate->fpregs, &ufp->fpregs,
-				sizeof(hwstate->fpregs));
+	memcpy(&hwstate->fpregs, &ufp->fpregs, sizeof(hwstate->fpregs));
 	/*
 	 * Copy the status and control register.
 	 */
-	__get_user_error(hwstate->fpscr, &ufp->fpscr, err);
+	hwstate->fpscr = ufp->fpscr;
 
 	/*
 	 * Sanitise and restore the exception registers.
 	 */
-	__get_user_error(fpexc, &ufp_exc->fpexc, err);
+	fpexc = ufp_exc->fpexc;
 
 	/* Ensure the VFP is enabled. */
 	fpexc |= FPEXC_EN;
@@ -635,10 +628,10 @@
 	fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
 	hwstate->fpexc = fpexc;
 
-	__get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
-	__get_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);
+	hwstate->fpinst = ufp_exc->fpinst;
+	hwstate->fpinst2 = ufp_exc->fpinst2;
 
-	return err ? -EFAULT : 0;
+	return 0;
 }
 
 /*
--- linux-4.4.0.orig/arch/arm/xen/enlighten.c
+++ linux-4.4.0/arch/arm/xen/enlighten.c
@@ -239,8 +239,7 @@
 	 * for secondary CPUs as they are brought up.
 	 * For uniformity we use VCPUOP_register_vcpu_info even on cpu0.
 	 */
-	xen_vcpu_info = __alloc_percpu(sizeof(struct vcpu_info),
-			                       sizeof(struct vcpu_info));
+	xen_vcpu_info = alloc_percpu(struct vcpu_info);
 	if (xen_vcpu_info == NULL)
 		return -ENOMEM;
 
--- linux-4.4.0.orig/arch/arm/xen/mm.c
+++ linux-4.4.0/arch/arm/xen/mm.c
@@ -199,6 +199,7 @@
 	.unmap_page = xen_swiotlb_unmap_page,
 	.dma_supported = xen_swiotlb_dma_supported,
 	.set_dma_mask = xen_swiotlb_set_dma_mask,
+	.mmap = xen_swiotlb_dma_mmap,
 };
 
 int __init xen_mm_init(void)
--- linux-4.4.0.orig/arch/arm/xen/p2m.c
+++ linux-4.4.0/arch/arm/xen/p2m.c
@@ -91,10 +91,39 @@
 	int i;
 
 	for (i = 0; i < count; i++) {
+		struct gnttab_unmap_grant_ref unmap;
+		int rc;
+
 		if (map_ops[i].status)
 			continue;
-		set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT,
-				    map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT);
+		if (likely(set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT,
+				    map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT)))
+			continue;
+
+		/*
+		 * Signal an error for this slot. This in turn requires
+		 * immediate unmapping.
+		 */
+		map_ops[i].status = GNTST_general_error;
+		unmap.host_addr = map_ops[i].host_addr,
+		unmap.handle = map_ops[i].handle;
+		map_ops[i].handle = ~0;
+		if (map_ops[i].flags & GNTMAP_device_map)
+			unmap.dev_bus_addr = map_ops[i].dev_bus_addr;
+		else
+			unmap.dev_bus_addr = 0;
+
+		/*
+		 * Pre-populate the status field, to be recognizable in
+		 * the log message below.
+		 */
+		unmap.status = 1;
+
+		rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
+					       &unmap, 1);
+		if (rc || unmap.status != GNTST_okay)
+			pr_err_once("gnttab unmap failed: rc=%d st=%d\n",
+				    rc, unmap.status);
 	}
 
 	return 0;
--- linux-4.4.0.orig/arch/arm64/Kconfig
+++ linux-4.4.0/arch/arm64/Kconfig
@@ -3,6 +3,8 @@
 	select ACPI_CCA_REQUIRED if ACPI
 	select ACPI_GENERIC_GSI if ACPI
 	select ACPI_REDUCED_HARDWARE_ONLY if ACPI
+	select ACPI_SPCR_TABLE if ACPI
+	select ACPI_MCFG if ACPI
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 	select ARCH_HAS_ELF_RANDOMIZE
 	select ARCH_HAS_GCOV_PROFILE_ALL
@@ -10,6 +12,7 @@
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select ARCH_SUPPORTS_ATOMIC_RMW
+	select ARCH_SUPPORTS_NUMA_BALANCING
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
 	select ARCH_WANT_FRAME_POINTERS
@@ -54,6 +57,7 @@
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_BPF_JIT
+	select HAVE_EBPF_JIT
 	select HAVE_C_RECORDMCOUNT
 	select HAVE_CC_STACKPROTECTOR
 	select HAVE_CMPXCHG_DOUBLE
@@ -71,6 +75,7 @@
 	select HAVE_GENERIC_DMA_COHERENT
 	select HAVE_HW_BREAKPOINT if PERF_EVENTS
 	select HAVE_MEMBLOCK
+	select HAVE_MEMBLOCK_NODE_MAP if NUMA
 	select HAVE_PATA_PLATFORM
 	select HAVE_PERF_EVENTS
 	select HAVE_PERF_REGS
@@ -85,13 +90,15 @@
 	select OF
 	select OF_EARLY_FLATTREE
 	select OF_RESERVED_MEM
+	select PCI_ECAM if ACPI
 	select PERF_USE_VMALLOC
 	select POWER_RESET
 	select POWER_SUPPLY
-	select RTC_LIB
 	select SPARSE_IRQ
 	select SYSCTL_EXCEPTION_TRACE
 	select HAVE_CONTEXT_TRACKING
+	select HAVE_ARM_SMCCC
+	select OF_NUMA if NUMA && OF
 	help
 	  ARM 64-bit (AArch64) Linux support.
 
@@ -374,6 +381,20 @@
 
 	  If unsure, say Y.
 
+config ARM64_ERRATUM_1024718
+	bool "Cortex-A55: 1024718: Update of DBM/AP bits without break before make might result in incorrect update"
+	default y
+	help
+	  This option adds work around for Arm Cortex-A55 Erratum 1024718.
+
+	  Affected Cortex-A55 cores (r0p0, r0p1, r1p0) could cause incorrect
+	  update of the hardware dirty bit when the DBM/AP bits are updated
+	  without a break-before-make. The work around is to disable the usage
+	  of hardware DBM locally on the affected cores. CPUs not affected by
+	  erratum will continue to use the feature.
+
+	  If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
 	bool "Cavium erratum 22375, 24313"
 	default y
@@ -391,6 +412,15 @@
 
 	  If unsure, say Y.
 
+config CAVIUM_ERRATUM_23144
+	bool "Cavium erratum 23144: ITS SYNC hang on dual socket system"
+	depends on NUMA
+	default y
+	help
+	  ITS SYNC command hang for cross node io and collections/cpu mapping.
+
+	  If unsure, say Y.
+
 config CAVIUM_ERRATUM_23154
 	bool "Cavium erratum 23154: Access to ICC_IAR1_EL1 is not sync'ed"
 	default y
@@ -401,6 +431,17 @@
 
 	  If unsure, say Y.
 
+config CAVIUM_ERRATUM_27456
+	bool "Cavium erratum 27456: Broadcast TLBI instructions may cause icache corruption"
+	default y
+	help
+	  On ThunderX T88 pass 1.x through 2.1 parts, broadcast TLBI
+	  instructions may cause the icache to become corrupted if it
+	  contains data for a non-current ASID.  The fix is to
+	  invalidate the icache when changing the mm context.
+
+	  If unsure, say Y.
+
 endmenu
 
 
@@ -503,6 +544,30 @@
 	  Say Y here to experiment with turning CPUs off and on.  CPUs
 	  can be controlled through /sys/devices/system/cpu.
 
+# Common NUMA Features
+config NUMA
+	bool "Numa Memory Allocation and Scheduler Support"
+	depends on SMP
+	help
+	  Enable NUMA (Non Uniform Memory Access) support.
+
+	  The kernel will try to allocate memory used by a CPU on the
+	  local memory of the CPU and add some more
+	  NUMA awareness to the kernel.
+
+config NODES_SHIFT
+	int "Maximum NUMA Nodes (as a power of 2)"
+	range 1 10
+	default "2"
+	depends on NEED_MULTIPLE_NODES
+	help
+	  Specify the maximum number of NUMA Nodes available on the target
+	  system.  Increases memory reserved to accommodate various tables.
+
+config USE_PERCPU_NUMA_NODE_ID
+	def_bool y
+	depends on NUMA
+
 source kernel/Kconfig.preempt
 source kernel/Kconfig.hz
 
@@ -570,6 +635,7 @@
 config FORCE_MAX_ZONEORDER
 	int
 	default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
+	default "13" if (ARCH_THUNDER && ARM64_4K_PAGES)
 	default "12" if (ARM64_16K_PAGES && TRANSPARENT_HUGEPAGE)
 	default "11"
 	help
@@ -708,6 +774,15 @@
 
 menu "Boot options"
 
+config ARM64_ACPI_PARKING_PROTOCOL
+	bool "Enable support for the ARM64 ACPI parking protocol"
+	depends on ACPI
+	help
+	  Enable support for the ARM64 ACPI parking protocol. If disabled
+	  the kernel will not allow booting through the ARM64 ACPI parking
+	  protocol even if the corresponding data is present in the ACPI
+	  MADT table.
+
 config CMDLINE
 	string "Default kernel command string"
 	default ""
@@ -764,7 +839,7 @@
 config COMPAT
 	bool "Kernel support for 32-bit EL0"
 	depends on ARM64_4K_PAGES || EXPERT
-	select COMPAT_BINFMT_ELF
+	select COMPAT_BINFMT_ELF if BINFMT_ELF
 	select HAVE_UID16
 	select OLD_SIGSUSPEND3
 	select COMPAT_OLD_SIGACTION
@@ -784,6 +859,10 @@
 	def_bool y
 	depends on COMPAT && SYSVIPC
 
+config KEYS_COMPAT
+	def_bool y
+	depends on COMPAT && KEYS
+
 endmenu
 
 menu "Power management options"
@@ -807,6 +886,8 @@
 
 source "drivers/Kconfig"
 
+source "ubuntu/Kconfig"
+
 source "drivers/firmware/Kconfig"
 
 source "drivers/acpi/Kconfig"
--- linux-4.4.0.orig/arch/arm64/Kconfig.platforms
+++ linux-4.4.0/arch/arm64/Kconfig.platforms
@@ -9,6 +9,7 @@
 	bool "Marvell Berlin SoC Family"
 	select ARCH_REQUIRE_GPIOLIB
 	select DW_APB_ICTL
+	select DW_APB_TIMER_OF
 	help
 	  This enables support for Marvell Berlin SoC Family
 
@@ -90,8 +91,6 @@
 	bool "NVIDIA Tegra132 SoC"
 	depends on ARCH_TEGRA
 	select PINCTRL_TEGRA124
-	select USB_ULPI if USB_PHY
-	select USB_ULPI_VIEWPORT if USB_PHY
 	help
 	  Enable support for NVIDIA Tegra132 SoC, based on the Denver
 	  ARMv8 CPU.  The Tegra132 SoC is similar to the Tegra124 SoC,
--- linux-4.4.0.orig/arch/arm64/Makefile
+++ linux-4.4.0/arch/arm64/Makefile
@@ -10,7 +10,7 @@
 #
 # Copyright (C) 1995-2001 by Russell King
 
-LDFLAGS_vmlinux	:=-p --no-undefined -X
+LDFLAGS_vmlinux	:=--no-undefined -X
 CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
 OBJCOPYFLAGS	:=-O binary -R .note -R .note.gnu.build-id -R .comment -S
 GZFLAGS		:=-9
@@ -27,6 +27,7 @@
 endif
 
 KBUILD_CFLAGS	+= -mgeneral-regs-only $(lseinstr)
+KBUILD_CFLAGS	+= $(call cc-option, -mpc-relative-literal-loads)
 KBUILD_AFLAGS	+= $(lseinstr)
 
 ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
@@ -43,6 +44,7 @@
 
 ifeq ($(CONFIG_ARM64_ERRATUM_843419), y)
 KBUILD_CFLAGS_MODULE	+= -mcmodel=large
+KBUILD_CFLAGS_MODULE	+= $(call cc-option, -mpc-relative-literal-loads)
 endif
 
 # Default value
@@ -55,6 +57,10 @@
 TEXT_OFFSET := 0x00080000
 endif
 
+ifeq ($(cc-name),clang)
+KBUILD_CFLAGS += $(call cc-disable-warning, asm-operand-widths)
+endif
+
 # KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - 3)) - (1 << 61)
 # in 32-bit arithmetic
 KASAN_SHADOW_OFFSET := $(shell printf "0x%08x00000000\n" $$(( \
--- linux-4.4.0.orig/arch/arm64/boot/Makefile
+++ linux-4.4.0/arch/arm64/boot/Makefile
@@ -14,7 +14,7 @@
 # Based on the ia64 boot/Makefile.
 #
 
-targets := Image Image.gz
+targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo
 
 $(obj)/Image: vmlinux FORCE
 	$(call if_changed,objcopy)
--- linux-4.4.0.orig/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
@@ -56,10 +56,10 @@
 
 	pmu {
 		compatible = "arm,armv8-pmuv3";
-		interrupts = <0 120 8>,
-			     <0 121 8>,
-			     <0 122 8>,
-			     <0 123 8>;
+		interrupts = <0 170 4>,
+			     <0 171 4>,
+			     <0 172 4>,
+			     <0 173 4>;
 		interrupt-affinity = <&cpu0>,
 				     <&cpu1>,
 				     <&cpu2>,
@@ -249,7 +249,7 @@
 
 		sysmgr: sysmgr@ffd12000 {
 			compatible = "altr,sys-mgr", "syscon";
-			reg = <0xffd12000 0x1000>;
+			reg = <0xffd12000 0x228>;
 		};
 
 		/* Local timer */
--- linux-4.4.0.orig/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi
@@ -84,7 +84,7 @@
 			clock-names = "uartclk", "apb_pclk";
 		};
 
-		spi0: ssp@e1020000 {
+		spi0: spi@e1020000 {
 			status = "disabled";
 			compatible = "arm,pl022", "arm,primecell";
 			#gpio-cells = <2>;
@@ -95,7 +95,7 @@
 			clock-names = "apb_pclk";
 		};
 
-		spi1: ssp@e1030000 {
+		spi1: spi@e1030000 {
 			status = "disabled";
 			compatible = "arm,pl022", "arm,primecell";
 			#gpio-cells = <2>;
--- linux-4.4.0.orig/arch/arm64/boot/dts/apm/apm-merlin.dts
+++ linux-4.4.0/arch/arm64/boot/dts/apm/apm-merlin.dts
@@ -70,3 +70,9 @@
 &xgenet1 {
 	status = "ok";
 };
+
+&mdio {
+	sgenet0phy: phy@0 {
+		reg = <0x0>;
+	};
+};
--- linux-4.4.0.orig/arch/arm64/boot/dts/apm/apm-mustang.dts
+++ linux-4.4.0/arch/arm64/boot/dts/apm/apm-mustang.dts
@@ -74,3 +74,15 @@
 &xgenet {
 	status = "ok";
 };
+
+&mdio {
+	menet0phy: phy@3 {
+		reg = <0x3>;
+	};
+	sgenet0phy: phy@4 {
+		reg = <0x4>;
+	};
+	sgenet1phy: phy@5 {
+		reg = <0x5>;
+	};
+};
--- linux-4.4.0.orig/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
@@ -239,10 +239,18 @@
 				     <0x0 0x2f 0x1>;
 		};
 
+		mdio: mdio@1f610000 {
+			compatible = "apm,xgene-mdio-xfi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x0 0x1f610000 0x0 0xd100>;
+			clocks = <&xge0clk 0>;
+		};
+
 		sgenet0: ethernet@1f610000 {
 			compatible = "apm,xgene2-sgenet";
 			status = "disabled";
-			reg = <0x0 0x1f610000 0x0 0x10000>,
+			reg = <0x0 0x1f610000 0x0 0xd100>,
 			      <0x0 0x1f600000 0x0 0Xd100>,
 			      <0x0 0x20000000 0x0 0X20000>;
 			interrupts = <0 96 4>,
@@ -251,6 +259,7 @@
 			clocks = <&xge0clk 0>;
 			local-mac-address = [00 01 73 00 00 01];
 			phy-connection-type = "sgmii";
+			phy-handle = <&sgenet0phy>;
 		};
 
 		xgenet1: ethernet@1f620000 {
--- linux-4.4.0.orig/arch/arm64/boot/dts/apm/apm-storm.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/apm/apm-storm.dtsi
@@ -188,20 +188,11 @@
 				clocks = <&socplldiv2 0>;
 				reg = <0x0 0x1f21c000 0x0 0x1000>;
 				reg-names = "csr-reg";
-				csr-mask = <0x3>;
+				csr-mask = <0xa>;
+				enable-mask = <0xf>;
 				clock-output-names = "sge0clk";
 			};
 
-			sge1clk: sge1clk@1f21c000 {
-				compatible = "apm,xgene-device-clock";
-				#clock-cells = <1>;
-				clocks = <&socplldiv2 0>;
-				reg = <0x0 0x1f21c000 0x0 0x1000>;
-				reg-names = "csr-reg";
-				csr-mask = <0xc>;
-				clock-output-names = "sge1clk";
-			};
-
 			xge0clk: xge0clk@1f61c000 {
 				compatible = "apm,xgene-device-clock";
 				#clock-cells = <1>;
@@ -781,6 +772,14 @@
 			clocks = <&rtcclk 0>;
 		};
 
+		mdio: mdio@17020000 {
+			compatible = "apm,xgene-mdio-rgmii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x0 0x17020000 0x0 0xd100>;
+			clocks = <&menetclk 0>;
+		};
+
 		menet: ethernet@17020000 {
 			compatible = "apm,xgene-enet";
 			status = "disabled";
@@ -794,7 +793,7 @@
 			/* mac address will be overwritten by the bootloader */
 			local-mac-address = [00 00 00 00 00 00];
 			phy-connection-type = "rgmii";
-			phy-handle = <&menetphy>;
+			phy-handle = <&menet0phy>,<&menetphy>;
 			mdio {
 				compatible = "apm,xgene-mdio";
 				#address-cells = <1>;
@@ -820,6 +819,7 @@
 			clocks = <&sge0clk 0>;
 			local-mac-address = [00 00 00 00 00 00];
 			phy-connection-type = "sgmii";
+			phy-handle = <&sgenet0phy>;
 		};
 
 		sgenet1: ethernet@1f210030 {
@@ -833,9 +833,9 @@
 				     <0x0 0xAD 0x4>;
 			port-id = <1>;
 			dma-coherent;
-			clocks = <&sge1clk 0>;
 			local-mac-address = [00 00 00 00 00 00];
 			phy-connection-type = "sgmii";
+			phy-handle = <&sgenet1phy>;
 		};
 
 		xgenet: ethernet@1f610000 {
--- linux-4.4.0.orig/arch/arm64/boot/dts/arm/juno-clocks.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/arm/juno-clocks.dtsi
@@ -8,10 +8,10 @@
  */
 
 	/* SoC fixed clocks */
-	soc_uartclk: refclk7273800hz {
+	soc_uartclk: refclk7372800hz {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
-		clock-frequency = <7273800>;
+		clock-frequency = <7372800>;
 		clock-output-names = "juno:uartclk";
 	};
 
--- linux-4.4.0.orig/arch/arm64/boot/dts/broadcom/ns2.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/broadcom/ns2.dtsi
@@ -30,6 +30,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/memreserve/ 0x81000000 0x00200000;
+
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 /memreserve/ 0x84b00000 0x00000008;
--- linux-4.4.0.orig/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
@@ -360,6 +360,11 @@
 		             <1 10 0xff01>;
 	};
 
+	pmu {
+		compatible = "cavium,thunder-pmu", "arm,armv8-pmuv3";
+		interrupts = <1 7 4>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <2>;
--- linux-4.4.0.orig/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -54,6 +54,7 @@
 			reg = <0x000>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SLEEP_0>;
+			#cooling-cells = <2>;
 		};
 
 		cpu1: cpu@1 {
@@ -70,6 +71,7 @@
 			reg = <0x100>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SLEEP_0>;
+			#cooling-cells = <2>;
 		};
 
 		cpu3: cpu@101 {
--- linux-4.4.0.orig/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
@@ -105,7 +105,7 @@
 			led@6 {
 				label = "apq8016-sbc:blue:bt";
 				gpios = <&pm8916_mpps 3 GPIO_ACTIVE_HIGH>;
-				linux,default-trigger = "bt";
+				linux,default-trigger = "bluetooth-power";
 				default-state = "off";
 			};
 		};
--- linux-4.4.0.orig/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -262,6 +262,8 @@
 		#io-channel-cells = <1>;
 		clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
 		clock-names = "saradc", "apb_pclk";
+		resets = <&cru SRST_SARADC>;
+		reset-names = "saradc-apb";
 		status = "disabled";
 	};
 
@@ -517,7 +519,7 @@
 		#address-cells = <0>;
 
 		reg = <0x0 0xffb71000 0x0 0x1000>,
-		      <0x0 0xffb72000 0x0 0x1000>,
+		      <0x0 0xffb72000 0x0 0x2000>,
 		      <0x0 0xffb74000 0x0 0x2000>,
 		      <0x0 0xffb76000 0x0 0x2000>;
 		interrupts = <GIC_PPI 9
--- linux-4.4.0.orig/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
+++ linux-4.4.0/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
@@ -26,7 +26,7 @@
 		stdout-path = "serial0:115200n8";
 	};
 
-	memory {
+	memory@0 {
 		device_type = "memory";
 		reg = <0x0 0x0 0x40000000>;
 	};
--- linux-4.4.0.orig/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
+++ linux-4.4.0/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
@@ -71,7 +71,7 @@
 			     <1 10 0xf01>;
 	};
 
-	amba_apu {
+	amba_apu: amba_apu@0 {
 		compatible = "simple-bus";
 		#address-cells = <2>;
 		#size-cells = <1>;
@@ -191,7 +191,7 @@
 		};
 
 		i2c0: i2c@ff020000 {
-			compatible = "cdns,i2c-r1p10";
+			compatible = "cdns,i2c-r1p14";
 			status = "disabled";
 			interrupt-parent = <&gic>;
 			interrupts = <0 17 4>;
@@ -202,7 +202,7 @@
 		};
 
 		i2c1: i2c@ff030000 {
-			compatible = "cdns,i2c-r1p10";
+			compatible = "cdns,i2c-r1p14";
 			status = "disabled";
 			interrupt-parent = <&gic>;
 			interrupts = <0 18 4>;
--- linux-4.4.0.orig/arch/arm64/crypto/aes-ce-ccm-core.S
+++ linux-4.4.0/arch/arm64/crypto/aes-ce-ccm-core.S
@@ -9,6 +9,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/assembler.h>
 
 	.text
 	.arch	armv8-a+crypto
@@ -19,7 +20,7 @@
 	 */
 ENTRY(ce_aes_ccm_auth_data)
 	ldr	w8, [x3]			/* leftover from prev round? */
-	ld1	{v0.2d}, [x0]			/* load mac */
+	ld1	{v0.16b}, [x0]			/* load mac */
 	cbz	w8, 1f
 	sub	w8, w8, #16
 	eor	v1.16b, v1.16b, v1.16b
@@ -31,7 +32,7 @@
 	beq	8f				/* out of input? */
 	cbnz	w8, 0b
 	eor	v0.16b, v0.16b, v1.16b
-1:	ld1	{v3.2d}, [x4]			/* load first round key */
+1:	ld1	{v3.16b}, [x4]			/* load first round key */
 	prfm	pldl1strm, [x1]
 	cmp	w5, #12				/* which key size? */
 	add	x6, x4, #16
@@ -41,17 +42,17 @@
 	mov	v5.16b, v3.16b
 	b	4f
 2:	mov	v4.16b, v3.16b
-	ld1	{v5.2d}, [x6], #16		/* load 2nd round key */
+	ld1	{v5.16b}, [x6], #16		/* load 2nd round key */
 3:	aese	v0.16b, v4.16b
 	aesmc	v0.16b, v0.16b
-4:	ld1	{v3.2d}, [x6], #16		/* load next round key */
+4:	ld1	{v3.16b}, [x6], #16		/* load next round key */
 	aese	v0.16b, v5.16b
 	aesmc	v0.16b, v0.16b
-5:	ld1	{v4.2d}, [x6], #16		/* load next round key */
+5:	ld1	{v4.16b}, [x6], #16		/* load next round key */
 	subs	w7, w7, #3
 	aese	v0.16b, v3.16b
 	aesmc	v0.16b, v0.16b
-	ld1	{v5.2d}, [x6], #16		/* load next round key */
+	ld1	{v5.16b}, [x6], #16		/* load next round key */
 	bpl	3b
 	aese	v0.16b, v4.16b
 	subs	w2, w2, #16			/* last data? */
@@ -60,7 +61,7 @@
 	ld1	{v1.16b}, [x1], #16		/* load next input block */
 	eor	v0.16b, v0.16b, v1.16b		/* xor with mac */
 	bne	1b
-6:	st1	{v0.2d}, [x0]			/* store mac */
+6:	st1	{v0.16b}, [x0]			/* store mac */
 	beq	10f
 	adds	w2, w2, #16
 	beq	10f
@@ -73,13 +74,14 @@
 	beq	10f
 	ext	v0.16b, v0.16b, v0.16b, #1	/* rotate out the mac bytes */
 	b	7b
-8:	mov	w7, w8
+8:	cbz	w8, 91f
+	mov	w7, w8
 	add	w8, w8, #16
 9:	ext	v1.16b, v1.16b, v1.16b, #1
 	adds	w7, w7, #1
 	bne	9b
-	eor	v0.16b, v0.16b, v1.16b
-	st1	{v0.2d}, [x0]
+91:	eor	v0.16b, v0.16b, v1.16b
+	st1	{v0.16b}, [x0]
 10:	str	w8, [x3]
 	ret
 ENDPROC(ce_aes_ccm_auth_data)
@@ -89,27 +91,27 @@
 	 * 			 u32 rounds);
 	 */
 ENTRY(ce_aes_ccm_final)
-	ld1	{v3.2d}, [x2], #16		/* load first round key */
-	ld1	{v0.2d}, [x0]			/* load mac */
+	ld1	{v3.16b}, [x2], #16		/* load first round key */
+	ld1	{v0.16b}, [x0]			/* load mac */
 	cmp	w3, #12				/* which key size? */
 	sub	w3, w3, #2			/* modified # of rounds */
-	ld1	{v1.2d}, [x1]			/* load 1st ctriv */
+	ld1	{v1.16b}, [x1]			/* load 1st ctriv */
 	bmi	0f
 	bne	3f
 	mov	v5.16b, v3.16b
 	b	2f
 0:	mov	v4.16b, v3.16b
-1:	ld1	{v5.2d}, [x2], #16		/* load next round key */
+1:	ld1	{v5.16b}, [x2], #16		/* load next round key */
 	aese	v0.16b, v4.16b
 	aesmc	v0.16b, v0.16b
 	aese	v1.16b, v4.16b
 	aesmc	v1.16b, v1.16b
-2:	ld1	{v3.2d}, [x2], #16		/* load next round key */
+2:	ld1	{v3.16b}, [x2], #16		/* load next round key */
 	aese	v0.16b, v5.16b
 	aesmc	v0.16b, v0.16b
 	aese	v1.16b, v5.16b
 	aesmc	v1.16b, v1.16b
-3:	ld1	{v4.2d}, [x2], #16		/* load next round key */
+3:	ld1	{v4.16b}, [x2], #16		/* load next round key */
 	subs	w3, w3, #3
 	aese	v0.16b, v3.16b
 	aesmc	v0.16b, v0.16b
@@ -120,47 +122,47 @@
 	aese	v1.16b, v4.16b
 	/* final round key cancels out */
 	eor	v0.16b, v0.16b, v1.16b		/* en-/decrypt the mac */
-	st1	{v0.2d}, [x0]			/* store result */
+	st1	{v0.16b}, [x0]			/* store result */
 	ret
 ENDPROC(ce_aes_ccm_final)
 
 	.macro	aes_ccm_do_crypt,enc
 	ldr	x8, [x6, #8]			/* load lower ctr */
-	ld1	{v0.2d}, [x5]			/* load mac */
-	rev	x8, x8				/* keep swabbed ctr in reg */
+	ld1	{v0.16b}, [x5]			/* load mac */
+CPU_LE(	rev	x8, x8			)	/* keep swabbed ctr in reg */
 0:	/* outer loop */
-	ld1	{v1.1d}, [x6]			/* load upper ctr */
+	ld1	{v1.8b}, [x6]			/* load upper ctr */
 	prfm	pldl1strm, [x1]
 	add	x8, x8, #1
 	rev	x9, x8
 	cmp	w4, #12				/* which key size? */
 	sub	w7, w4, #2			/* get modified # of rounds */
 	ins	v1.d[1], x9			/* no carry in lower ctr */
-	ld1	{v3.2d}, [x3]			/* load first round key */
+	ld1	{v3.16b}, [x3]			/* load first round key */
 	add	x10, x3, #16
 	bmi	1f
 	bne	4f
 	mov	v5.16b, v3.16b
 	b	3f
 1:	mov	v4.16b, v3.16b
-	ld1	{v5.2d}, [x10], #16		/* load 2nd round key */
+	ld1	{v5.16b}, [x10], #16		/* load 2nd round key */
 2:	/* inner loop: 3 rounds, 2x interleaved */
 	aese	v0.16b, v4.16b
 	aesmc	v0.16b, v0.16b
 	aese	v1.16b, v4.16b
 	aesmc	v1.16b, v1.16b
-3:	ld1	{v3.2d}, [x10], #16		/* load next round key */
+3:	ld1	{v3.16b}, [x10], #16		/* load next round key */
 	aese	v0.16b, v5.16b
 	aesmc	v0.16b, v0.16b
 	aese	v1.16b, v5.16b
 	aesmc	v1.16b, v1.16b
-4:	ld1	{v4.2d}, [x10], #16		/* load next round key */
+4:	ld1	{v4.16b}, [x10], #16		/* load next round key */
 	subs	w7, w7, #3
 	aese	v0.16b, v3.16b
 	aesmc	v0.16b, v0.16b
 	aese	v1.16b, v3.16b
 	aesmc	v1.16b, v1.16b
-	ld1	{v5.2d}, [x10], #16		/* load next round key */
+	ld1	{v5.16b}, [x10], #16		/* load next round key */
 	bpl	2b
 	aese	v0.16b, v4.16b
 	aese	v1.16b, v4.16b
@@ -177,14 +179,14 @@
 	eor	v0.16b, v0.16b, v2.16b		/* xor mac with pt ^ rk[last] */
 	st1	{v1.16b}, [x0], #16		/* write output block */
 	bne	0b
-	rev	x8, x8
-	st1	{v0.2d}, [x5]			/* store mac */
+CPU_LE(	rev	x8, x8			)
+	st1	{v0.16b}, [x5]			/* store mac */
 	str	x8, [x6, #8]			/* store lsb end of ctr (BE) */
 5:	ret
 
 6:	eor	v0.16b, v0.16b, v5.16b		/* final round mac */
 	eor	v1.16b, v1.16b, v5.16b		/* final round enc */
-	st1	{v0.2d}, [x5]			/* store mac */
+	st1	{v0.16b}, [x5]			/* store mac */
 	add	w2, w2, #16			/* process partial tail block */
 7:	ldrb	w9, [x1], #1			/* get 1 byte of input */
 	umov	w6, v1.b[0]			/* get top crypted ctr byte */
--- linux-4.4.0.orig/arch/arm64/crypto/aes-ce-cipher.c
+++ linux-4.4.0/arch/arm64/crypto/aes-ce-cipher.c
@@ -47,24 +47,24 @@
 	kernel_neon_begin_partial(4);
 
 	__asm__("	ld1	{v0.16b}, %[in]			;"
-		"	ld1	{v1.2d}, [%[key]], #16		;"
+		"	ld1	{v1.16b}, [%[key]], #16		;"
 		"	cmp	%w[rounds], #10			;"
 		"	bmi	0f				;"
 		"	bne	3f				;"
 		"	mov	v3.16b, v1.16b			;"
 		"	b	2f				;"
 		"0:	mov	v2.16b, v1.16b			;"
-		"	ld1	{v3.2d}, [%[key]], #16		;"
+		"	ld1	{v3.16b}, [%[key]], #16		;"
 		"1:	aese	v0.16b, v2.16b			;"
 		"	aesmc	v0.16b, v0.16b			;"
-		"2:	ld1	{v1.2d}, [%[key]], #16		;"
+		"2:	ld1	{v1.16b}, [%[key]], #16		;"
 		"	aese	v0.16b, v3.16b			;"
 		"	aesmc	v0.16b, v0.16b			;"
-		"3:	ld1	{v2.2d}, [%[key]], #16		;"
+		"3:	ld1	{v2.16b}, [%[key]], #16		;"
 		"	subs	%w[rounds], %w[rounds], #3	;"
 		"	aese	v0.16b, v1.16b			;"
 		"	aesmc	v0.16b, v0.16b			;"
-		"	ld1	{v3.2d}, [%[key]], #16		;"
+		"	ld1	{v3.16b}, [%[key]], #16		;"
 		"	bpl	1b				;"
 		"	aese	v0.16b, v2.16b			;"
 		"	eor	v0.16b, v0.16b, v3.16b		;"
@@ -92,24 +92,24 @@
 	kernel_neon_begin_partial(4);
 
 	__asm__("	ld1	{v0.16b}, %[in]			;"
-		"	ld1	{v1.2d}, [%[key]], #16		;"
+		"	ld1	{v1.16b}, [%[key]], #16		;"
 		"	cmp	%w[rounds], #10			;"
 		"	bmi	0f				;"
 		"	bne	3f				;"
 		"	mov	v3.16b, v1.16b			;"
 		"	b	2f				;"
 		"0:	mov	v2.16b, v1.16b			;"
-		"	ld1	{v3.2d}, [%[key]], #16		;"
+		"	ld1	{v3.16b}, [%[key]], #16		;"
 		"1:	aesd	v0.16b, v2.16b			;"
 		"	aesimc	v0.16b, v0.16b			;"
-		"2:	ld1	{v1.2d}, [%[key]], #16		;"
+		"2:	ld1	{v1.16b}, [%[key]], #16		;"
 		"	aesd	v0.16b, v3.16b			;"
 		"	aesimc	v0.16b, v0.16b			;"
-		"3:	ld1	{v2.2d}, [%[key]], #16		;"
+		"3:	ld1	{v2.16b}, [%[key]], #16		;"
 		"	subs	%w[rounds], %w[rounds], #3	;"
 		"	aesd	v0.16b, v1.16b			;"
 		"	aesimc	v0.16b, v0.16b			;"
-		"	ld1	{v3.2d}, [%[key]], #16		;"
+		"	ld1	{v3.16b}, [%[key]], #16		;"
 		"	bpl	1b				;"
 		"	aesd	v0.16b, v2.16b			;"
 		"	eor	v0.16b, v0.16b, v3.16b		;"
@@ -173,7 +173,12 @@
 		u32 *rki = ctx->key_enc + (i * kwords);
 		u32 *rko = rki + kwords;
 
+#ifndef CONFIG_CPU_BIG_ENDIAN
 		rko[0] = ror32(aes_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0];
+#else
+		rko[0] = rol32(aes_sub(rki[kwords - 1]), 8) ^ (rcon[i] << 24) ^
+			 rki[0];
+#endif
 		rko[1] = rko[0] ^ rki[1];
 		rko[2] = rko[1] ^ rki[2];
 		rko[3] = rko[2] ^ rki[3];
--- linux-4.4.0.orig/arch/arm64/crypto/aes-ce.S
+++ linux-4.4.0/arch/arm64/crypto/aes-ce.S
@@ -10,6 +10,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/assembler.h>
 
 #define AES_ENTRY(func)		ENTRY(ce_ ## func)
 #define AES_ENDPROC(func)	ENDPROC(ce_ ## func)
--- linux-4.4.0.orig/arch/arm64/crypto/aes-glue.c
+++ linux-4.4.0/arch/arm64/crypto/aes-glue.c
@@ -15,6 +15,7 @@
 #include <crypto/algapi.h>
 #include <linux/module.h>
 #include <linux/cpufeature.h>
+#include <crypto/xts.h>
 
 #include "aes-ce-setkey.h"
 
@@ -85,6 +86,10 @@
 	struct crypto_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
 	int ret;
 
+	ret = xts_check_key(tfm, in_key, key_len);
+	if (ret)
+		return ret;
+
 	ret = aes_expandkey(&ctx->key1, in_key, key_len / 2);
 	if (!ret)
 		ret = aes_expandkey(&ctx->key2, &in_key[key_len / 2],
@@ -211,7 +216,7 @@
 		err = blkcipher_walk_done(desc, &walk,
 					  walk.nbytes % AES_BLOCK_SIZE);
 	}
-	if (nbytes) {
+	if (walk.nbytes % AES_BLOCK_SIZE) {
 		u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE;
 		u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE;
 		u8 __aligned(8) tail[AES_BLOCK_SIZE];
--- linux-4.4.0.orig/arch/arm64/crypto/aes-modes.S
+++ linux-4.4.0/arch/arm64/crypto/aes-modes.S
@@ -193,15 +193,16 @@
 	cbz		w6, .Lcbcencloop
 
 	ld1		{v0.16b}, [x5]			/* get iv */
-	enc_prepare	w3, x2, x5
+	enc_prepare	w3, x2, x6
 
 .Lcbcencloop:
 	ld1		{v1.16b}, [x1], #16		/* get next pt block */
 	eor		v0.16b, v0.16b, v1.16b		/* ..and xor with iv */
-	encrypt_block	v0, w3, x2, x5, w6
+	encrypt_block	v0, w3, x2, x6, w7
 	st1		{v0.16b}, [x0], #16
 	subs		w4, w4, #1
 	bne		.Lcbcencloop
+	st1		{v0.16b}, [x5]			/* return iv */
 	ret
 AES_ENDPROC(aes_cbc_encrypt)
 
@@ -211,7 +212,7 @@
 	cbz		w6, .LcbcdecloopNx
 
 	ld1		{v7.16b}, [x5]			/* get iv */
-	dec_prepare	w3, x2, x5
+	dec_prepare	w3, x2, x6
 
 .LcbcdecloopNx:
 #if INTERLEAVE >= 2
@@ -248,7 +249,7 @@
 .Lcbcdecloop:
 	ld1		{v1.16b}, [x1], #16		/* get next ct block */
 	mov		v0.16b, v1.16b			/* ...and copy to v0 */
-	decrypt_block	v0, w3, x2, x5, w6
+	decrypt_block	v0, w3, x2, x6, w7
 	eor		v0.16b, v0.16b, v7.16b		/* xor with iv => pt */
 	mov		v7.16b, v1.16b			/* ct is next iv */
 	st1		{v0.16b}, [x0], #16
@@ -256,6 +257,7 @@
 	bne		.Lcbcdecloop
 .Lcbcdecout:
 	FRAME_POP
+	st1		{v7.16b}, [x5]			/* return iv */
 	ret
 AES_ENDPROC(aes_cbc_decrypt)
 
@@ -267,24 +269,15 @@
 
 AES_ENTRY(aes_ctr_encrypt)
 	FRAME_PUSH
-	cbnz		w6, .Lctrfirst		/* 1st time around? */
-	umov		x5, v4.d[1]		/* keep swabbed ctr in reg */
-	rev		x5, x5
-#if INTERLEAVE >= 2
-	cmn		w5, w4			/* 32 bit overflow? */
-	bcs		.Lctrinc
-	add		x5, x5, #1		/* increment BE ctr */
-	b		.LctrincNx
-#else
-	b		.Lctrinc
-#endif
-.Lctrfirst:
+	cbz		w6, .Lctrnotfirst	/* 1st time around? */
 	enc_prepare	w3, x2, x6
 	ld1		{v4.16b}, [x5]
-	umov		x5, v4.d[1]		/* keep swabbed ctr in reg */
-	rev		x5, x5
+
+.Lctrnotfirst:
+	umov		x8, v4.d[1]		/* keep swabbed ctr in reg */
+	rev		x8, x8
 #if INTERLEAVE >= 2
-	cmn		w5, w4			/* 32 bit overflow? */
+	cmn		w8, w4			/* 32 bit overflow? */
 	bcs		.Lctrloop
 .LctrloopNx:
 	subs		w4, w4, #INTERLEAVE
@@ -292,11 +285,11 @@
 #if INTERLEAVE == 2
 	mov		v0.8b, v4.8b
 	mov		v1.8b, v4.8b
-	rev		x7, x5
-	add		x5, x5, #1
+	rev		x7, x8
+	add		x8, x8, #1
 	ins		v0.d[1], x7
-	rev		x7, x5
-	add		x5, x5, #1
+	rev		x7, x8
+	add		x8, x8, #1
 	ins		v1.d[1], x7
 	ld1		{v2.16b-v3.16b}, [x1], #32	/* get 2 input blocks */
 	do_encrypt_block2x
@@ -305,7 +298,7 @@
 	st1		{v0.16b-v1.16b}, [x0], #32
 #else
 	ldr		q8, =0x30000000200000001	/* addends 1,2,3[,0] */
-	dup		v7.4s, w5
+	dup		v7.4s, w8
 	mov		v0.16b, v4.16b
 	add		v7.4s, v7.4s, v8.4s
 	mov		v1.16b, v4.16b
@@ -323,18 +316,12 @@
 	eor		v2.16b, v7.16b, v2.16b
 	eor		v3.16b, v5.16b, v3.16b
 	st1		{v0.16b-v3.16b}, [x0], #64
-	add		x5, x5, #INTERLEAVE
+	add		x8, x8, #INTERLEAVE
 #endif
-	cbz		w4, .LctroutNx
-.LctrincNx:
-	rev		x7, x5
+	rev		x7, x8
 	ins		v4.d[1], x7
+	cbz		w4, .Lctrout
 	b		.LctrloopNx
-.LctroutNx:
-	sub		x5, x5, #1
-	rev		x7, x5
-	ins		v4.d[1], x7
-	b		.Lctrout
 .Lctr1x:
 	adds		w4, w4, #INTERLEAVE
 	beq		.Lctrout
@@ -342,30 +329,39 @@
 .Lctrloop:
 	mov		v0.16b, v4.16b
 	encrypt_block	v0, w3, x2, x6, w7
+
+	adds		x8, x8, #1		/* increment BE ctr */
+	rev		x7, x8
+	ins		v4.d[1], x7
+	bcs		.Lctrcarry		/* overflow? */
+
+.Lctrcarrydone:
 	subs		w4, w4, #1
 	bmi		.Lctrhalfblock		/* blocks < 0 means 1/2 block */
 	ld1		{v3.16b}, [x1], #16
 	eor		v3.16b, v0.16b, v3.16b
 	st1		{v3.16b}, [x0], #16
-	beq		.Lctrout
-.Lctrinc:
-	adds		x5, x5, #1		/* increment BE ctr */
-	rev		x7, x5
-	ins		v4.d[1], x7
-	bcc		.Lctrloop		/* no overflow? */
-	umov		x7, v4.d[0]		/* load upper word of ctr  */
-	rev		x7, x7			/* ... to handle the carry */
-	add		x7, x7, #1
-	rev		x7, x7
-	ins		v4.d[0], x7
-	b		.Lctrloop
+	bne		.Lctrloop
+
+.Lctrout:
+	st1		{v4.16b}, [x5]		/* return next CTR value */
+	FRAME_POP
+	ret
+
 .Lctrhalfblock:
 	ld1		{v3.8b}, [x1]
 	eor		v3.8b, v0.8b, v3.8b
 	st1		{v3.8b}, [x0]
-.Lctrout:
 	FRAME_POP
 	ret
+
+.Lctrcarry:
+	umov		x7, v4.d[0]		/* load upper word of ctr  */
+	rev		x7, x7			/* ... to handle the carry */
+	add		x7, x7, #1
+	rev		x7, x7
+	ins		v4.d[0], x7
+	b		.Lctrcarrydone
 AES_ENDPROC(aes_ctr_encrypt)
 	.ltorg
 
@@ -386,7 +382,8 @@
 	.endm
 
 .Lxts_mul_x:
-	.word		1, 0, 0x87, 0
+CPU_LE(	.quad		1, 0x87		)
+CPU_BE(	.quad		0x87, 1		)
 
 AES_ENTRY(aes_xts_encrypt)
 	FRAME_PUSH
--- linux-4.4.0.orig/arch/arm64/crypto/aes-neon.S
+++ linux-4.4.0/arch/arm64/crypto/aes-neon.S
@@ -9,6 +9,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/assembler.h>
 
 #define AES_ENTRY(func)		ENTRY(neon_ ## func)
 #define AES_ENDPROC(func)	ENDPROC(neon_ ## func)
@@ -83,13 +84,13 @@
 	.endm
 
 	.macro		do_block, enc, in, rounds, rk, rkp, i
-	ld1		{v15.16b}, [\rk]
+	ld1		{v15.4s}, [\rk]
 	add		\rkp, \rk, #16
 	mov		\i, \rounds
 1111:	eor		\in\().16b, \in\().16b, v15.16b		/* ^round key */
 	tbl		\in\().16b, {\in\().16b}, v13.16b	/* ShiftRows */
 	sub_bytes	\in
-	ld1		{v15.16b}, [\rkp], #16
+	ld1		{v15.4s}, [\rkp], #16
 	subs		\i, \i, #1
 	beq		2222f
 	.if		\enc == 1
@@ -229,7 +230,7 @@
 	.endm
 
 	.macro		do_block_2x, enc, in0, in1 rounds, rk, rkp, i
-	ld1		{v15.16b}, [\rk]
+	ld1		{v15.4s}, [\rk]
 	add		\rkp, \rk, #16
 	mov		\i, \rounds
 1111:	eor		\in0\().16b, \in0\().16b, v15.16b	/* ^round key */
@@ -237,7 +238,7 @@
 	sub_bytes_2x	\in0, \in1
 	tbl		\in0\().16b, {\in0\().16b}, v13.16b	/* ShiftRows */
 	tbl		\in1\().16b, {\in1\().16b}, v13.16b	/* ShiftRows */
-	ld1		{v15.16b}, [\rkp], #16
+	ld1		{v15.4s}, [\rkp], #16
 	subs		\i, \i, #1
 	beq		2222f
 	.if		\enc == 1
@@ -254,7 +255,7 @@
 	.endm
 
 	.macro		do_block_4x, enc, in0, in1, in2, in3, rounds, rk, rkp, i
-	ld1		{v15.16b}, [\rk]
+	ld1		{v15.4s}, [\rk]
 	add		\rkp, \rk, #16
 	mov		\i, \rounds
 1111:	eor		\in0\().16b, \in0\().16b, v15.16b	/* ^round key */
@@ -266,7 +267,7 @@
 	tbl		\in1\().16b, {\in1\().16b}, v13.16b	/* ShiftRows */
 	tbl		\in2\().16b, {\in2\().16b}, v13.16b	/* ShiftRows */
 	tbl		\in3\().16b, {\in3\().16b}, v13.16b	/* ShiftRows */
-	ld1		{v15.16b}, [\rkp], #16
+	ld1		{v15.4s}, [\rkp], #16
 	subs		\i, \i, #1
 	beq		2222f
 	.if		\enc == 1
@@ -306,12 +307,16 @@
 	.text
 	.align		4
 .LForward_ShiftRows:
-	.byte		0x0, 0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x3
-	.byte		0x8, 0xd, 0x2, 0x7, 0xc, 0x1, 0x6, 0xb
+CPU_LE(	.byte		0x0, 0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x3	)
+CPU_LE(	.byte		0x8, 0xd, 0x2, 0x7, 0xc, 0x1, 0x6, 0xb	)
+CPU_BE(	.byte		0xb, 0x6, 0x1, 0xc, 0x7, 0x2, 0xd, 0x8	)
+CPU_BE(	.byte		0x3, 0xe, 0x9, 0x4, 0xf, 0xa, 0x5, 0x0	)
 
 .LReverse_ShiftRows:
-	.byte		0x0, 0xd, 0xa, 0x7, 0x4, 0x1, 0xe, 0xb
-	.byte		0x8, 0x5, 0x2, 0xf, 0xc, 0x9, 0x6, 0x3
+CPU_LE(	.byte		0x0, 0xd, 0xa, 0x7, 0x4, 0x1, 0xe, 0xb	)
+CPU_LE(	.byte		0x8, 0x5, 0x2, 0xf, 0xc, 0x9, 0x6, 0x3	)
+CPU_BE(	.byte		0x3, 0x6, 0x9, 0xc, 0xf, 0x2, 0x5, 0x8	)
+CPU_BE(	.byte		0xb, 0xe, 0x1, 0x4, 0x7, 0xa, 0xd, 0x0	)
 
 .LForward_Sbox:
 	.byte		0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
--- linux-4.4.0.orig/arch/arm64/crypto/ghash-ce-core.S
+++ linux-4.4.0/arch/arm64/crypto/ghash-ce-core.S
@@ -29,8 +29,8 @@
 	 *			   struct ghash_key const *k, const char *head)
 	 */
 ENTRY(pmull_ghash_update)
-	ld1		{SHASH.16b}, [x3]
-	ld1		{XL.16b}, [x1]
+	ld1		{SHASH.2d}, [x3]
+	ld1		{XL.2d}, [x1]
 	movi		MASK.16b, #0xe1
 	ext		SHASH2.16b, SHASH.16b, SHASH.16b, #8
 	shl		MASK.2d, MASK.2d, #57
@@ -74,6 +74,6 @@
 
 	cbnz		w0, 0b
 
-	st1		{XL.16b}, [x1]
+	st1		{XL.2d}, [x1]
 	ret
 ENDPROC(pmull_ghash_update)
--- linux-4.4.0.orig/arch/arm64/crypto/sha1-ce-core.S
+++ linux-4.4.0/arch/arm64/crypto/sha1-ce-core.S
@@ -78,11 +78,12 @@
 	ld1r		{k3.4s}, [x6]
 
 	/* load state */
-	ldr		dga, [x0]
+	ld1		{dgav.4s}, [x0]
 	ldr		dgb, [x0, #16]
 
 	/* load sha1_ce_state::finalize */
-	ldr		w4, [x0, #:lo12:sha1_ce_offsetof_finalize]
+	ldr_l		w4, sha1_ce_offsetof_finalize, x4
+	ldr		w4, [x0, x4]
 
 	/* load input */
 0:	ld1		{v8.4s-v11.4s}, [x1], #64
@@ -132,7 +133,8 @@
 	 * the padding is handled by the C code in that case.
 	 */
 	cbz		x4, 3f
-	ldr		x4, [x0, #:lo12:sha1_ce_offsetof_count]
+	ldr_l		w4, sha1_ce_offsetof_count, x4
+	ldr		x4, [x0, x4]
 	movi		v9.2d, #0
 	mov		x8, #0x80000000
 	movi		v10.2d, #0
@@ -144,7 +146,7 @@
 	b		1b
 
 	/* store new state */
-3:	str		dga, [x0]
+3:	st1		{dgav.4s}, [x0]
 	str		dgb, [x0, #16]
 	ret
 ENDPROC(sha1_ce_transform)
--- linux-4.4.0.orig/arch/arm64/crypto/sha1-ce-glue.c
+++ linux-4.4.0/arch/arm64/crypto/sha1-ce-glue.c
@@ -17,9 +17,6 @@
 #include <linux/crypto.h>
 #include <linux/module.h>
 
-#define ASM_EXPORT(sym, val) \
-	asm(".globl " #sym "; .set " #sym ", %0" :: "I"(val));
-
 MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions");
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_LICENSE("GPL v2");
@@ -32,6 +29,9 @@
 asmlinkage void sha1_ce_transform(struct sha1_ce_state *sst, u8 const *src,
 				  int blocks);
 
+const u32 sha1_ce_offsetof_count = offsetof(struct sha1_ce_state, sst.count);
+const u32 sha1_ce_offsetof_finalize = offsetof(struct sha1_ce_state, finalize);
+
 static int sha1_ce_update(struct shash_desc *desc, const u8 *data,
 			  unsigned int len)
 {
@@ -50,12 +50,7 @@
 			 unsigned int len, u8 *out)
 {
 	struct sha1_ce_state *sctx = shash_desc_ctx(desc);
-	bool finalize = !sctx->sst.count && !(len % SHA1_BLOCK_SIZE);
-
-	ASM_EXPORT(sha1_ce_offsetof_count,
-		   offsetof(struct sha1_ce_state, sst.count));
-	ASM_EXPORT(sha1_ce_offsetof_finalize,
-		   offsetof(struct sha1_ce_state, finalize));
+	bool finalize = !sctx->sst.count && !(len % SHA1_BLOCK_SIZE) && len;
 
 	/*
 	 * Allow the asm code to perform the finalization if there is no
--- linux-4.4.0.orig/arch/arm64/crypto/sha2-ce-core.S
+++ linux-4.4.0/arch/arm64/crypto/sha2-ce-core.S
@@ -85,10 +85,11 @@
 	ld1		{v12.4s-v15.4s}, [x8]
 
 	/* load state */
-	ldp		dga, dgb, [x0]
+	ld1		{dgav.4s, dgbv.4s}, [x0]
 
 	/* load sha256_ce_state::finalize */
-	ldr		w4, [x0, #:lo12:sha256_ce_offsetof_finalize]
+	ldr_l		w4, sha256_ce_offsetof_finalize, x4
+	ldr		w4, [x0, x4]
 
 	/* load input */
 0:	ld1		{v16.4s-v19.4s}, [x1], #64
@@ -136,7 +137,8 @@
 	 * the padding is handled by the C code in that case.
 	 */
 	cbz		x4, 3f
-	ldr		x4, [x0, #:lo12:sha256_ce_offsetof_count]
+	ldr_l		w4, sha256_ce_offsetof_count, x4
+	ldr		x4, [x0, x4]
 	movi		v17.2d, #0
 	mov		x8, #0x80000000
 	movi		v18.2d, #0
@@ -148,6 +150,6 @@
 	b		1b
 
 	/* store new state */
-3:	stp		dga, dgb, [x0]
+3:	st1		{dgav.4s, dgbv.4s}, [x0]
 	ret
 ENDPROC(sha2_ce_transform)
--- linux-4.4.0.orig/arch/arm64/crypto/sha2-ce-glue.c
+++ linux-4.4.0/arch/arm64/crypto/sha2-ce-glue.c
@@ -17,9 +17,6 @@
 #include <linux/crypto.h>
 #include <linux/module.h>
 
-#define ASM_EXPORT(sym, val) \
-	asm(".globl " #sym "; .set " #sym ", %0" :: "I"(val));
-
 MODULE_DESCRIPTION("SHA-224/SHA-256 secure hash using ARMv8 Crypto Extensions");
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_LICENSE("GPL v2");
@@ -32,6 +29,11 @@
 asmlinkage void sha2_ce_transform(struct sha256_ce_state *sst, u8 const *src,
 				  int blocks);
 
+const u32 sha256_ce_offsetof_count = offsetof(struct sha256_ce_state,
+					      sst.count);
+const u32 sha256_ce_offsetof_finalize = offsetof(struct sha256_ce_state,
+						 finalize);
+
 static int sha256_ce_update(struct shash_desc *desc, const u8 *data,
 			    unsigned int len)
 {
@@ -50,12 +52,7 @@
 			   unsigned int len, u8 *out)
 {
 	struct sha256_ce_state *sctx = shash_desc_ctx(desc);
-	bool finalize = !sctx->sst.count && !(len % SHA256_BLOCK_SIZE);
-
-	ASM_EXPORT(sha256_ce_offsetof_count,
-		   offsetof(struct sha256_ce_state, sst.count));
-	ASM_EXPORT(sha256_ce_offsetof_finalize,
-		   offsetof(struct sha256_ce_state, finalize));
+	bool finalize = !sctx->sst.count && !(len % SHA256_BLOCK_SIZE) && len;
 
 	/*
 	 * Allow the asm code to perform the finalization if there is no
--- linux-4.4.0.orig/arch/arm64/include/asm/acpi.h
+++ linux-4.4.0/arch/arm64/include/asm/acpi.h
@@ -22,9 +22,9 @@
 #define ACPI_MADT_GICC_LENGTH	\
 	(acpi_gbl_FADT.header.revision < 6 ? 76 : 80)
 
-#define BAD_MADT_GICC_ENTRY(entry, end)						\
-	(!(entry) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||	\
-	 (entry)->header.length != ACPI_MADT_GICC_LENGTH)
+#define BAD_MADT_GICC_ENTRY(entry, end)					\
+	(!(entry) || (entry)->header.length != ACPI_MADT_GICC_LENGTH ||	\
+	(unsigned long)(entry) + ACPI_MADT_GICC_LENGTH > (end))
 
 /* Basic configuration for ACPI */
 #ifdef	CONFIG_ACPI
@@ -87,9 +87,26 @@
 static inline void acpi_init_cpus(void) { }
 #endif /* CONFIG_ACPI */
 
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+bool acpi_parking_protocol_valid(int cpu);
+void __init
+acpi_set_mailbox_entry(int cpu, struct acpi_madt_generic_interrupt *processor);
+#else
+static inline bool acpi_parking_protocol_valid(int cpu) { return false; }
+static inline void
+acpi_set_mailbox_entry(int cpu, struct acpi_madt_generic_interrupt *processor)
+{}
+#endif
+
 static inline const char *acpi_get_enable_method(int cpu)
 {
-	return acpi_psci_present() ? "psci" : NULL;
+	if (acpi_psci_present())
+		return "psci";
+
+	if (acpi_parking_protocol_valid(cpu))
+		return "parking-protocol";
+
+	return NULL;
 }
 
 #ifdef	CONFIG_ACPI_APEI
--- linux-4.4.0.orig/arch/arm64/include/asm/arch_gicv3.h
+++ linux-4.4.0/arch/arm64/include/asm/arch_gicv3.h
@@ -103,6 +103,7 @@
 	u64 irqstat;
 
 	asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
+	dsb(sy);
 	return irqstat;
 }
 
--- linux-4.4.0.orig/arch/arm64/include/asm/asm-uaccess.h
+++ linux-4.4.0/arch/arm64/include/asm/asm-uaccess.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_ASM_UACCESS_H
+#define __ASM_ASM_UACCESS_H
+
+/*
+ * Remove the address tag from a virtual address, if present.
+ */
+	.macro	clear_address_tag, dst, addr
+	tst	\addr, #(1 << 55)
+	bic	\dst, \addr, #(0xff << 56)
+	csel	\dst, \dst, \addr, eq
+	.endm
+
+#endif
--- linux-4.4.0.orig/arch/arm64/include/asm/assembler.h
+++ linux-4.4.0/arch/arm64/include/asm/assembler.h
@@ -23,6 +23,7 @@
 #ifndef __ASM_ASSEMBLER_H
 #define __ASM_ASSEMBLER_H
 
+#include <asm/cputype.h>
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 
@@ -147,22 +148,25 @@
 
 /*
  * Pseudo-ops for PC-relative adr/ldr/str <reg>, <symbol> where
- * <symbol> is within the range +/- 4 GB of the PC.
+ * <symbol> is within the range +/- 4 GB of the PC when running
+ * in core kernel context. In module context, a movz/movk sequence
+ * is used, since modules may be loaded far away from the kernel
+ * when KASLR is in effect.
  */
 	/*
 	 * @dst: destination register (64 bit wide)
 	 * @sym: name of the symbol
-	 * @tmp: optional scratch register to be used if <dst> == sp, which
-	 *       is not allowed in an adrp instruction
 	 */
-	.macro	adr_l, dst, sym, tmp=
-	.ifb	\tmp
+	.macro	adr_l, dst, sym
+#ifndef MODULE
 	adrp	\dst, \sym
 	add	\dst, \dst, :lo12:\sym
-	.else
-	adrp	\tmp, \sym
-	add	\dst, \tmp, :lo12:\sym
-	.endif
+#else
+	movz	\dst, #:abs_g3:\sym
+	movk	\dst, #:abs_g2_nc:\sym
+	movk	\dst, #:abs_g1_nc:\sym
+	movk	\dst, #:abs_g0_nc:\sym
+#endif
 	.endm
 
 	/*
@@ -173,6 +177,7 @@
 	 *       the address
 	 */
 	.macro	ldr_l, dst, sym, tmp=
+#ifndef MODULE
 	.ifb	\tmp
 	adrp	\dst, \sym
 	ldr	\dst, [\dst, :lo12:\sym]
@@ -180,6 +185,15 @@
 	adrp	\tmp, \sym
 	ldr	\dst, [\tmp, :lo12:\sym]
 	.endif
+#else
+	.ifb	\tmp
+	adr_l	\dst, \sym
+	ldr	\dst, [\dst]
+	.else
+	adr_l	\tmp, \sym
+	ldr	\dst, [\tmp]
+	.endif
+#endif
 	.endm
 
 	/*
@@ -189,8 +203,13 @@
 	 *       while <src> needs to be preserved.
 	 */
 	.macro	str_l, src, sym, tmp
+#ifndef MODULE
 	adrp	\tmp, \sym
 	str	\src, [\tmp, :lo12:\sym]
+#else
+	adr_l	\tmp, \sym
+	str	\src, [\tmp]
+#endif
 	.endm
 
 /*
@@ -204,4 +223,63 @@
 	.size	__pi_##x, . - x;	\
 	ENDPROC(x)
 
+	/*
+	 * mov_q - move an immediate constant into a 64-bit register using
+	 *         between 2 and 4 movz/movk instructions (depending on the
+	 *         magnitude and sign of the operand)
+	 */
+	.macro	mov_q, reg, val
+	.if (((\val) >> 31) == 0 || ((\val) >> 31) == 0x1ffffffff)
+	movz	\reg, :abs_g1_s:\val
+	.else
+	.if (((\val) >> 47) == 0 || ((\val) >> 47) == 0x1ffff)
+	movz	\reg, :abs_g2_s:\val
+	.else
+	movz	\reg, :abs_g3:\val
+	movk	\reg, :abs_g2_nc:\val
+	.endif
+	movk	\reg, :abs_g1_nc:\val
+	.endif
+	movk	\reg, :abs_g0_nc:\val
+	.endm
+
+/*
+ * Check the MIDR_EL1 of the current CPU for a given model and a range of
+ * variant/revision. See asm/cputype.h for the macros used below.
+ *
+ *	model:		MIDR_CPU_PART of CPU
+ *	rv_min:		Minimum of MIDR_CPU_VAR_REV()
+ *	rv_max:		Maximum of MIDR_CPU_VAR_REV()
+ *	res:		Result register.
+ *	tmp1, tmp2, tmp3: Temporary registers
+ *
+ * Corrupts: res, tmp1, tmp2, tmp3
+ * Returns:  0, if the CPU id doesn't match. Non-zero otherwise
+ */
+	.macro	cpu_midr_match model, rv_min, rv_max, res, tmp1, tmp2, tmp3
+	mrs		\res, midr_el1
+	mov_q		\tmp1, (MIDR_REVISION_MASK | MIDR_VARIANT_MASK)
+	mov_q		\tmp2, MIDR_CPU_MODEL_MASK
+	and		\tmp3, \res, \tmp2	// Extract model
+	and		\tmp1, \res, \tmp1	// rev & variant
+	mov_q		\tmp2, \model
+	cmp		\tmp3, \tmp2
+	cset		\res, eq
+	cbz		\res, .Ldone\@		// Model matches ?
+
+	.if (\rv_min != 0)			// Skip min check if rv_min == 0
+	mov_q		\tmp3, \rv_min
+	cmp		\tmp1, \tmp3
+	cset		\res, ge
+	.endif					// \rv_min != 0
+	/* Skip rv_max check if rv_min == rv_max && rv_min != 0 */
+	.if ((\rv_min != \rv_max) || \rv_min == 0)
+	mov_q		\tmp2, \rv_max
+	cmp		\tmp1, \tmp2
+	cset		\tmp2, le
+	and		\res, \res, \tmp2
+	.endif
+.Ldone\@:
+	.endm
+
 #endif	/* __ASM_ASSEMBLER_H */
--- linux-4.4.0.orig/arch/arm64/include/asm/atomic_lse.h
+++ linux-4.4.0/arch/arm64/include/asm/atomic_lse.h
@@ -114,7 +114,7 @@
 	/* LSE atomics */
 	"	mvn	%w[i], %w[i]\n"
 	"	stclr	%w[i], %[v]")
-	: [i] "+r" (w0), [v] "+Q" (v->counter)
+	: [i] "+&r" (w0), [v] "+Q" (v->counter)
 	: "r" (x1)
 	: "x30");
 }
@@ -131,7 +131,7 @@
 	/* LSE atomics */
 	"	neg	%w[i], %w[i]\n"
 	"	stadd	%w[i], %[v]")
-	: [i] "+r" (w0), [v] "+Q" (v->counter)
+	: [i] "+&r" (w0), [v] "+Q" (v->counter)
 	: "r" (x1)
 	: "x30");
 }
@@ -151,7 +151,7 @@
 	"	neg	%w[i], %w[i]\n"					\
 	"	ldadd" #mb "	%w[i], w30, %[v]\n"			\
 	"	add	%w[i], %w[i], w30")				\
-	: [i] "+r" (w0), [v] "+Q" (v->counter)				\
+	: [i] "+&r" (w0), [v] "+Q" (v->counter)				\
 	: "r" (x1)							\
 	: "x30" , ##cl);						\
 									\
@@ -255,7 +255,7 @@
 	/* LSE atomics */
 	"	mvn	%[i], %[i]\n"
 	"	stclr	%[i], %[v]")
-	: [i] "+r" (x0), [v] "+Q" (v->counter)
+	: [i] "+&r" (x0), [v] "+Q" (v->counter)
 	: "r" (x1)
 	: "x30");
 }
@@ -272,7 +272,7 @@
 	/* LSE atomics */
 	"	neg	%[i], %[i]\n"
 	"	stadd	%[i], %[v]")
-	: [i] "+r" (x0), [v] "+Q" (v->counter)
+	: [i] "+&r" (x0), [v] "+Q" (v->counter)
 	: "r" (x1)
 	: "x30");
 }
@@ -292,7 +292,7 @@
 	"	neg	%[i], %[i]\n"					\
 	"	ldadd" #mb "	%[i], x30, %[v]\n"			\
 	"	add	%[i], %[i], x30")				\
-	: [i] "+r" (x0), [v] "+Q" (v->counter)				\
+	: [i] "+&r" (x0), [v] "+Q" (v->counter)				\
 	: "r" (x1)							\
 	: "x30" , ##cl);						\
 									\
@@ -412,7 +412,7 @@
 	"	eor	%[old1], %[old1], %[oldval1]\n"			\
 	"	eor	%[old2], %[old2], %[oldval2]\n"			\
 	"	orr	%[old1], %[old1], %[old2]")			\
-	: [old1] "+r" (x0), [old2] "+r" (x1),				\
+	: [old1] "+&r" (x0), [old2] "+&r" (x1),				\
 	  [v] "+Q" (*(unsigned long *)ptr)				\
 	: [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),		\
 	  [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)		\
--- linux-4.4.0.orig/arch/arm64/include/asm/barrier.h
+++ linux-4.4.0/arch/arm64/include/asm/barrier.h
@@ -41,23 +41,33 @@
 
 #define smp_store_release(p, v)						\
 do {									\
+	union { typeof(*p) __val; char __c[1]; } __u =			\
+		{ .__val = (__force typeof(*p)) (v) }; 			\
 	compiletime_assert_atomic_type(*p);				\
 	switch (sizeof(*p)) {						\
 	case 1:								\
 		asm volatile ("stlrb %w1, %0"				\
-				: "=Q" (*p) : "r" (v) : "memory");	\
+				: "=Q" (*p)				\
+				: "r" (*(__u8 *)__u.__c)		\
+				: "memory");				\
 		break;							\
 	case 2:								\
 		asm volatile ("stlrh %w1, %0"				\
-				: "=Q" (*p) : "r" (v) : "memory");	\
+				: "=Q" (*p)				\
+				: "r" (*(__u16 *)__u.__c)		\
+				: "memory");				\
 		break;							\
 	case 4:								\
 		asm volatile ("stlr %w1, %0"				\
-				: "=Q" (*p) : "r" (v) : "memory");	\
+				: "=Q" (*p)				\
+				: "r" (*(__u32 *)__u.__c)		\
+				: "memory");				\
 		break;							\
 	case 8:								\
 		asm volatile ("stlr %1, %0"				\
-				: "=Q" (*p) : "r" (v) : "memory");	\
+				: "=Q" (*p)				\
+				: "r" (*(__u64 *)__u.__c)		\
+				: "memory");				\
 		break;							\
 	}								\
 } while (0)
--- linux-4.4.0.orig/arch/arm64/include/asm/bug.h
+++ linux-4.4.0/arch/arm64/include/asm/bug.h
@@ -20,9 +20,6 @@
 
 #include <asm/debug-monitors.h>
 
-#ifdef CONFIG_GENERIC_BUG
-#define HAVE_ARCH_BUG
-
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 #define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line)
 #define __BUGVERBOSE_LOCATION(file, line)				\
@@ -36,28 +33,36 @@
 #define _BUGVERBOSE_LOCATION(file, line)
 #endif
 
-#define _BUG_FLAGS(flags) __BUG_FLAGS(flags)
+#ifdef CONFIG_GENERIC_BUG
 
-#define __BUG_FLAGS(flags) asm volatile (		\
+#define __BUG_ENTRY(flags) 				\
 		".pushsection __bug_table,\"a\"\n\t"	\
 		".align 2\n\t"				\
 	"0:	.long 1f - 0b\n\t"			\
 _BUGVERBOSE_LOCATION(__FILE__, __LINE__)		\
 		".short " #flags "\n\t"			\
 		".popsection\n"				\
-							\
-	"1:	brk %[imm]"				\
-		:: [imm] "i" (BUG_BRK_IMM)		\
-)
-
-#define BUG() do {				\
-	_BUG_FLAGS(0);				\
-	unreachable();				\
+	"1:	"
+#else
+#define __BUG_ENTRY(flags) ""
+#endif
+
+#define __BUG_FLAGS(flags)				\
+	asm volatile (					\
+		__BUG_ENTRY(flags)			\
+		"brk %[imm]" :: [imm] "i" (BUG_BRK_IMM)	\
+	);
+
+
+#define BUG() do {					\
+	__BUG_FLAGS(0);					\
+	unreachable();					\
 } while (0)
 
-#define __WARN_TAINT(taint) _BUG_FLAGS(BUGFLAG_TAINT(taint))
+#define __WARN_TAINT(taint) 				\
+	__BUG_FLAGS(BUGFLAG_TAINT(taint))
 
-#endif /* ! CONFIG_GENERIC_BUG */
+#define HAVE_ARCH_BUG
 
 #include <asm-generic/bug.h>
 
--- linux-4.4.0.orig/arch/arm64/include/asm/cmpxchg.h
+++ linux-4.4.0/arch/arm64/include/asm/cmpxchg.h
@@ -49,7 +49,7 @@
 	"	swp" #acq_lse #rel #sz "\t%" #w "3, %" #w "0, %2\n"	\
 	"	nop\n"							\
 	"	" #nop_lse)						\
-	: "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr)			\
+	: "=&r" (ret), "=&r" (tmp), "+Q" (*(unsigned long *)ptr)	\
 	: "r" (x)							\
 	: cl);								\
 									\
--- linux-4.4.0.orig/arch/arm64/include/asm/compat.h
+++ linux-4.4.0/arch/arm64/include/asm/compat.h
@@ -234,6 +234,7 @@
 }
 
 #define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
+#define COMPAT_MINSIGSTKSZ	2048
 
 static inline void __user *arch_compat_alloc_user_space(long len)
 {
--- linux-4.4.0.orig/arch/arm64/include/asm/cpufeature.h
+++ linux-4.4.0/arch/arm64/include/asm/cpufeature.h
@@ -30,8 +30,11 @@
 #define ARM64_HAS_LSE_ATOMICS			5
 #define ARM64_WORKAROUND_CAVIUM_23154		6
 #define ARM64_WORKAROUND_834220			7
+#define ARM64_HAS_NO_HW_PREFETCH		8
+#define ARM64_WORKAROUND_CAVIUM_27456		9
+#define ARM64_HAS_32BIT_EL0			10
 
-#define ARM64_NCAPS				8
+#define ARM64_NCAPS				11
 
 #ifndef __ASSEMBLY__
 
@@ -39,9 +42,10 @@
 
 /* CPU feature register tracking */
 enum ftr_type {
-	FTR_EXACT,	/* Use a predefined safe value */
-	FTR_LOWER_SAFE,	/* Smaller value is safe */
-	FTR_HIGHER_SAFE,/* Bigger value is safe */
+	FTR_EXACT,			/* Use a predefined safe value */
+	FTR_LOWER_SAFE,			/* Smaller value is safe */
+	FTR_HIGHER_SAFE,		/* Bigger value is safe */
+	FTR_HIGHER_OR_ZERO_SAFE,	/* Bigger value is safe, but 0 is biggest */
 };
 
 #define FTR_STRICT	true	/* SANITY check strict matching required */
@@ -76,7 +80,7 @@
 	const char *desc;
 	u16 capability;
 	bool (*matches)(const struct arm64_cpu_capabilities *);
-	void (*enable)(void *);		/* Called on all active CPUs */
+	int (*enable)(void *);		/* Called on all active CPUs */
 	union {
 		struct {	/* To be used for erratum handling only */
 			u32 midr_model;
@@ -85,9 +89,10 @@
 
 		struct {	/* Feature register checking */
 			u32 sys_reg;
-			int field_pos;
-			int min_field_value;
-			int hwcap_type;
+			u8 field_pos;
+			u8 min_field_value;
+			u8 hwcap_type;
+			bool sign;
 			unsigned long hwcap;
 		};
 	};
@@ -117,15 +122,15 @@
 }
 
 static inline int __attribute_const__
-cpuid_feature_extract_field_width(u64 features, int field, int width)
+cpuid_feature_extract_signed_field_width(u64 features, int field, int width)
 {
 	return (s64)(features << (64 - width - field)) >> (64 - width);
 }
 
 static inline int __attribute_const__
-cpuid_feature_extract_field(u64 features, int field)
+cpuid_feature_extract_signed_field(u64 features, int field)
 {
-	return cpuid_feature_extract_field_width(features, field, 4);
+	return cpuid_feature_extract_signed_field_width(features, field, 4);
 }
 
 static inline unsigned int __attribute_const__
@@ -145,17 +150,23 @@
 	return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
 }
 
+static inline int __attribute_const__
+cpuid_feature_extract_field(u64 features, int field, bool sign)
+{
+	return (sign) ?
+		cpuid_feature_extract_signed_field(features, field) :
+		cpuid_feature_extract_unsigned_field(features, field);
+}
+
 static inline s64 arm64_ftr_value(struct arm64_ftr_bits *ftrp, u64 val)
 {
-	return ftrp->sign ?
-		cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width) :
-		cpuid_feature_extract_unsigned_field_width(val, ftrp->shift, ftrp->width);
+	return (s64)cpuid_feature_extract_field(val, ftrp->shift, ftrp->sign);
 }
 
 static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
 {
-	return cpuid_feature_extract_field(mmfr0, ID_AA64MMFR0_BIGENDEL_SHIFT) == 0x1 ||
-		cpuid_feature_extract_field(mmfr0, ID_AA64MMFR0_BIGENDEL0_SHIFT) == 0x1;
+	return cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL_SHIFT) == 0x1 ||
+		cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL0_SHIFT) == 0x1;
 }
 
 void __init setup_cpu_features(void);
@@ -179,6 +190,11 @@
 	return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
 }
 
+static inline bool system_supports_32bit_el0(void)
+{
+	return cpus_have_cap(ARM64_HAS_32BIT_EL0);
+}
+
 static inline bool system_supports_mixed_endian_el0(void)
 {
 	return id_aa64mmfr0_mixed_endian_el0(read_system_reg(SYS_ID_AA64MMFR0_EL1));
--- linux-4.4.0.orig/arch/arm64/include/asm/cputype.h
+++ linux-4.4.0/arch/arm64/include/asm/cputype.h
@@ -57,11 +57,25 @@
 #define MIDR_IMPLEMENTOR(midr)	\
 	(((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
 
-#define MIDR_CPU_PART(imp, partnum) \
+#define MIDR_CPU_VAR_REV(var, rev) \
+	(((var) << MIDR_VARIANT_SHIFT) | (rev))
+
+#define MIDR_CPU_MODEL(imp, partnum) \
 	(((imp)			<< MIDR_IMPLEMENTOR_SHIFT) | \
 	(0xf			<< MIDR_ARCHITECTURE_SHIFT) | \
 	((partnum)		<< MIDR_PARTNUM_SHIFT))
 
+#define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
+			     MIDR_ARCHITECTURE_MASK)
+
+#define MIDR_IS_CPU_MODEL_RANGE(midr, model, rv_min, rv_max)		\
+({									\
+	u32 _model = (midr) & MIDR_CPU_MODEL_MASK;			\
+	u32 rv = (midr) & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK);	\
+									\
+	_model == (model) && rv >= (rv_min) && rv <= (rv_max);		\
+ })
+
 #define ARM_CPU_IMP_ARM			0x41
 #define ARM_CPU_IMP_APM			0x50
 #define ARM_CPU_IMP_CAVIUM		0x43
@@ -70,11 +84,18 @@
 #define ARM_CPU_PART_FOUNDATION		0xD00
 #define ARM_CPU_PART_CORTEX_A57		0xD07
 #define ARM_CPU_PART_CORTEX_A53		0xD03
+#define ARM_CPU_PART_CORTEX_A55		0xD05
 
 #define APM_CPU_PART_POTENZA		0x000
 
 #define CAVIUM_CPU_PART_THUNDERX	0x0A1
 
+
+#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
+#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
+#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
+#define MIDR_THUNDERX	MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
+
 #ifndef __ASSEMBLY__
 
 /*
--- linux-4.4.0.orig/arch/arm64/include/asm/elf.h
+++ linux-4.4.0/arch/arm64/include/asm/elf.h
@@ -120,12 +120,11 @@
 #define ELF_EXEC_PAGESIZE	PAGE_SIZE
 
 /*
- * This is the location that an ET_DYN program is loaded if exec'ed.  Typical
- * use of this is to invoke "./ld.so someprog" to test out a new version of
- * the loader.  We need to make sure that it is out of the way of the program
- * that it will "exec", and that there is sufficient room for the brk.
+ * This is the base location for PIE (ET_DYN with INTERP) loads. On
+ * 64-bit, this is above 4GB to leave the entire 32-bit address
+ * space open for things that want to use the area for 32-bit pointers.
  */
-#define ELF_ET_DYN_BASE	(2 * TASK_SIZE_64 / 3)
+#define ELF_ET_DYN_BASE		(2 * TASK_SIZE_64 / 3)
 
 /*
  * When the program starts, a1 contains a pointer to a function to be
@@ -136,6 +135,7 @@
 
 #define SET_PERSONALITY(ex)		clear_thread_flag(TIF_32BIT);
 
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
 #define ARCH_DLINFO							\
 do {									\
 	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
@@ -156,15 +156,16 @@
 #define STACK_RND_MASK			(0x3ffff >> (PAGE_SHIFT - 12))
 #endif
 
-#ifdef CONFIG_COMPAT
-
 #ifdef __AARCH64EB__
 #define COMPAT_ELF_PLATFORM		("v8b")
 #else
 #define COMPAT_ELF_PLATFORM		("v8l")
 #endif
 
-#define COMPAT_ELF_ET_DYN_BASE		(2 * TASK_SIZE_32 / 3)
+#ifdef CONFIG_COMPAT
+
+/* PIE load location for compat arm. Must match ARM ELF_ET_DYN_BASE. */
+#define COMPAT_ELF_ET_DYN_BASE		0x000400000UL
 
 /* AArch32 registers. */
 #define COMPAT_ELF_NGREG		18
--- linux-4.4.0.orig/arch/arm64/include/asm/futex.h
+++ linux-4.4.0/arch/arm64/include/asm/futex.h
@@ -33,8 +33,8 @@
 "	prfm	pstl1strm, %2\n"					\
 "1:	ldxr	%w1, %2\n"						\
 	insn "\n"							\
-"2:	stlxr	%w3, %w0, %2\n"						\
-"	cbnz	%w3, 1b\n"						\
+"2:	stlxr	%w0, %w3, %2\n"						\
+"	cbnz	%w0, 1b\n"						\
 "	dmb	ish\n"							\
 "3:\n"									\
 "	.pushsection .fixup,\"ax\"\n"					\
@@ -53,41 +53,31 @@
 	: "memory")
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret, tmp;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 
 	switch (op) {
 	case FUTEX_OP_SET:
-		__futex_atomic_op("mov	%w0, %w4",
+		__futex_atomic_op("mov	%w3, %w4",
 				  ret, oldval, uaddr, tmp, oparg);
 		break;
 	case FUTEX_OP_ADD:
-		__futex_atomic_op("add	%w0, %w1, %w4",
+		__futex_atomic_op("add	%w3, %w1, %w4",
 				  ret, oldval, uaddr, tmp, oparg);
 		break;
 	case FUTEX_OP_OR:
-		__futex_atomic_op("orr	%w0, %w1, %w4",
+		__futex_atomic_op("orr	%w3, %w1, %w4",
 				  ret, oldval, uaddr, tmp, oparg);
 		break;
 	case FUTEX_OP_ANDN:
-		__futex_atomic_op("and	%w0, %w1, %w4",
+		__futex_atomic_op("and	%w3, %w1, %w4",
 				  ret, oldval, uaddr, tmp, ~oparg);
 		break;
 	case FUTEX_OP_XOR:
-		__futex_atomic_op("eor	%w0, %w1, %w4",
+		__futex_atomic_op("eor	%w3, %w1, %w4",
 				  ret, oldval, uaddr, tmp, oparg);
 		break;
 	default:
@@ -96,17 +86,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
@@ -121,6 +103,7 @@
 		return -EFAULT;
 
 	asm volatile("// futex_atomic_cmpxchg_inatomic\n"
+ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
 "	prfm	pstl1strm, %2\n"
 "1:	ldxr	%w1, %2\n"
 "	sub	%w3, %w1, %w4\n"
@@ -137,6 +120,7 @@
 "	.align	3\n"
 "	.quad	1b, 4b, 2b, 4b\n"
 "	.popsection\n"
+ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
 	: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
 	: "r" (oldval), "r" (newval), "Ir" (-EFAULT)
 	: "memory");
--- linux-4.4.0.orig/arch/arm64/include/asm/hardirq.h
+++ linux-4.4.0/arch/arm64/include/asm/hardirq.h
@@ -20,7 +20,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	5
+#define NR_IPI	6
 
 typedef struct {
 	unsigned int __softirq_pending;
--- linux-4.4.0.orig/arch/arm64/include/asm/jump_label.h
+++ linux-4.4.0/arch/arm64/include/asm/jump_label.h
@@ -28,7 +28,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
 {
-	asm goto("1: nop\n\t"
+	asm_volatile_goto("1: nop\n\t"
 		 ".pushsection __jump_table,  \"aw\"\n\t"
 		 ".align 3\n\t"
 		 ".quad 1b, %l[l_yes], %c0\n\t"
@@ -42,7 +42,7 @@
 
 static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
 {
-	asm goto("1: b %l[l_yes]\n\t"
+	asm_volatile_goto("1: b %l[l_yes]\n\t"
 		 ".pushsection __jump_table,  \"aw\"\n\t"
 		 ".align 3\n\t"
 		 ".quad 1b, %l[l_yes], %c0\n\t"
--- linux-4.4.0.orig/arch/arm64/include/asm/kvm_arm.h
+++ linux-4.4.0/arch/arm64/include/asm/kvm_arm.h
@@ -23,6 +23,8 @@
 #include <asm/types.h>
 
 /* Hyp Configuration Register (HCR) bits */
+#define HCR_API		(UL(1) << 41)
+#define HCR_APK		(UL(1) << 40)
 #define HCR_ID		(UL(1) << 33)
 #define HCR_CD		(UL(1) << 32)
 #define HCR_RW_SHIFT	31
@@ -81,6 +83,7 @@
 			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW)
 #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
 #define HCR_INT_OVERRIDE   (HCR_FMO | HCR_IMO)
+#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
 
 
 /* Hyp System Control Register (SCTLR_EL2) bits */
@@ -107,8 +110,6 @@
 #define TCR_EL2_MASK	(TCR_EL2_TG0 | TCR_EL2_SH0 | \
 			 TCR_EL2_ORGN0 | TCR_EL2_IRGN0 | TCR_EL2_T0SZ)
 
-#define TCR_EL2_FLAGS	(TCR_EL2_RES1 | TCR_EL2_PS_40B)
-
 /* VTCR_EL2 Registers bits */
 #define VTCR_EL2_RES1		(1 << 31)
 #define VTCR_EL2_PS_MASK	(7 << 16)
@@ -166,8 +167,7 @@
 #define VTTBR_X		(37 - VTCR_EL2_T0SZ_40B)
 #endif
 
-#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
-#define VTTBR_BADDR_MASK  (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
+#define VTTBR_BADDR_MASK  (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_X)
 #define VTTBR_VMID_SHIFT  (UL(48))
 #define VTTBR_VMID_MASK	  (UL(0xFF) << VTTBR_VMID_SHIFT)
 
--- linux-4.4.0.orig/arch/arm64/include/asm/kvm_emulate.h
+++ linux-4.4.0/arch/arm64/include/asm/kvm_emulate.h
@@ -41,6 +41,11 @@
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
+static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
+{
+	return !(vcpu->arch.hcr_el2 & HCR_RW);
+}
+
 static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
--- linux-4.4.0.orig/arch/arm64/include/asm/kvm_host.h
+++ linux-4.4.0/arch/arm64/include/asm/kvm_host.h
@@ -178,8 +178,10 @@
  * CP14 and CP15 live in the same array, as they are backed by the
  * same system registers.
  */
-#define vcpu_cp14(v,r)		((v)->arch.ctxt.copro[(r)])
-#define vcpu_cp15(v,r)		((v)->arch.ctxt.copro[(r)])
+#define CPx_BIAS		IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)
+
+#define vcpu_cp14(v,r)		((v)->arch.ctxt.copro[(r) ^ CPx_BIAS])
+#define vcpu_cp15(v,r)		((v)->arch.ctxt.copro[(r) ^ CPx_BIAS])
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
 #define vcpu_cp15_64_high(v,r)	vcpu_cp15((v),(r))
--- linux-4.4.0.orig/arch/arm64/include/asm/kvm_mmu.h
+++ linux-4.4.0/arch/arm64/include/asm/kvm_mmu.h
@@ -236,8 +236,7 @@
 {
 	void *va = page_address(pfn_to_page(pfn));
 
-	if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
-		kvm_flush_dcache_to_poc(va, size);
+	kvm_flush_dcache_to_poc(va, size);
 
 	if (!icache_is_aliasing()) {		/* PIPT */
 		flush_icache_range((unsigned long)va,
--- linux-4.4.0.orig/arch/arm64/include/asm/memory.h
+++ linux-4.4.0/arch/arm64/include/asm/memory.h
@@ -49,8 +49,10 @@
  * and PAGE_OFFSET - it must be within 128MB of the kernel text.
  */
 #define VA_BITS			(CONFIG_ARM64_VA_BITS)
-#define VA_START		(UL(0xffffffffffffffff) << VA_BITS)
-#define PAGE_OFFSET		(UL(0xffffffffffffffff) << (VA_BITS - 1))
+#define VA_START		(UL(0xffffffffffffffff) - \
+	(UL(1) << VA_BITS) + 1)
+#define PAGE_OFFSET		(UL(0xffffffffffffffff) - \
+	(UL(1) << (VA_BITS - 1)) + 1)
 #define MODULES_END		(PAGE_OFFSET)
 #define MODULES_VADDR		(MODULES_END - SZ_64M)
 #define PCI_IO_END		(MODULES_VADDR - SZ_2M)
--- linux-4.4.0.orig/arch/arm64/include/asm/mmu.h
+++ linux-4.4.0/arch/arm64/include/asm/mmu.h
@@ -28,7 +28,8 @@
  */
 #define ASID(mm)	((mm)->context.id.counter & 0xffff)
 
-extern void paging_init(void);
+extern void paging_init_map_mem(void);
+extern void paging_init_rest(void);
 extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
 extern void init_mem_pgprot(void);
 extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
--- linux-4.4.0.orig/arch/arm64/include/asm/mmzone.h
+++ linux-4.4.0/arch/arm64/include/asm/mmzone.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_MMZONE_H
+#define __ASM_MMZONE_H
+
+#ifdef CONFIG_NUMA
+
+#include <asm/numa.h>
+
+extern struct pglist_data *node_data[];
+#define NODE_DATA(nid)		(node_data[(nid)])
+
+#endif /* CONFIG_NUMA */
+#endif /* __ASM_MMZONE_H */
--- linux-4.4.0.orig/arch/arm64/include/asm/numa.h
+++ linux-4.4.0/arch/arm64/include/asm/numa.h
@@ -0,0 +1,45 @@
+#ifndef __ASM_NUMA_H
+#define __ASM_NUMA_H
+
+#include <asm/topology.h>
+
+#ifdef CONFIG_NUMA
+
+/* currently, arm64 implements flat NUMA topology */
+#define parent_node(node)	(node)
+
+int __node_distance(int from, int to);
+#define node_distance(a, b) __node_distance(a, b)
+
+extern nodemask_t numa_nodes_parsed __initdata;
+
+/* Mappings between node number and cpus on that node. */
+extern cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
+void numa_clear_node(unsigned int cpu);
+
+#ifdef CONFIG_DEBUG_PER_CPU_MAPS
+const struct cpumask *cpumask_of_node(int node);
+#else
+/* Returns a pointer to the cpumask of CPUs on Node 'node'. */
+static inline const struct cpumask *cpumask_of_node(int node)
+{
+	return node_to_cpumask_map[node];
+}
+#endif
+
+void __init arm64_numa_init(void);
+int __init numa_add_memblk(int nodeid, u64 start, u64 end);
+void __init numa_set_distance(int from, int to, int distance);
+void __init numa_free_distance(void);
+void __init early_map_cpu_to_node(unsigned int cpu, int nid);
+void numa_store_cpu_info(unsigned int cpu);
+
+#else	/* CONFIG_NUMA */
+
+static inline void numa_store_cpu_info(unsigned int cpu) { }
+static inline void arm64_numa_init(void) { }
+static inline void early_map_cpu_to_node(unsigned int cpu, int nid) { }
+
+#endif	/* CONFIG_NUMA */
+
+#endif	/* __ASM_NUMA_H */
--- linux-4.4.0.orig/arch/arm64/include/asm/opcodes.h
+++ linux-4.4.0/arch/arm64/include/asm/opcodes.h
@@ -1 +1,5 @@
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define CONFIG_CPU_ENDIAN_BE8 CONFIG_CPU_BIG_ENDIAN
+#endif
+
 #include <../../arm/include/asm/opcodes.h>
--- linux-4.4.0.orig/arch/arm64/include/asm/page.h
+++ linux-4.4.0/arch/arm64/include/asm/page.h
@@ -19,6 +19,8 @@
 #ifndef __ASM_PAGE_H
 #define __ASM_PAGE_H
 
+#include <linux/const.h>
+
 /* PAGE_SHIFT determines the page size */
 /* CONT_SHIFT determines the number of pages which can be tracked together  */
 #ifdef CONFIG_ARM64_64K_PAGES
--- linux-4.4.0.orig/arch/arm64/include/asm/percpu.h
+++ linux-4.4.0/arch/arm64/include/asm/percpu.h
@@ -44,50 +44,47 @@
 									\
 	switch (size) {							\
 	case 1:								\
-		do {							\
-			asm ("//__per_cpu_" #op "_1\n"			\
-			"ldxrb	  %w[ret], %[ptr]\n"			\
+		asm ("//__per_cpu_" #op "_1\n"				\
+		"1:	ldxrb	  %w[ret], %[ptr]\n"			\
 			#asm_op " %w[ret], %w[ret], %w[val]\n"		\
-			"stxrb	  %w[loop], %w[ret], %[ptr]\n"		\
-			: [loop] "=&r" (loop), [ret] "=&r" (ret),	\
-			  [ptr] "+Q"(*(u8 *)ptr)			\
-			: [val] "Ir" (val));				\
-		} while (loop);						\
+		"	stxrb	  %w[loop], %w[ret], %[ptr]\n"		\
+		"	cbnz	  %w[loop], 1b"				\
+		: [loop] "=&r" (loop), [ret] "=&r" (ret),		\
+		  [ptr] "+Q"(*(u8 *)ptr)				\
+		: [val] "Ir" (val));					\
 		break;							\
 	case 2:								\
-		do {							\
-			asm ("//__per_cpu_" #op "_2\n"			\
-			"ldxrh	  %w[ret], %[ptr]\n"			\
+		asm ("//__per_cpu_" #op "_2\n"				\
+		"1:	ldxrh	  %w[ret], %[ptr]\n"			\
 			#asm_op " %w[ret], %w[ret], %w[val]\n"		\
-			"stxrh	  %w[loop], %w[ret], %[ptr]\n"		\
-			: [loop] "=&r" (loop), [ret] "=&r" (ret),	\
-			  [ptr]  "+Q"(*(u16 *)ptr)			\
-			: [val] "Ir" (val));				\
-		} while (loop);						\
+		"	stxrh	  %w[loop], %w[ret], %[ptr]\n"		\
+		"	cbnz	  %w[loop], 1b"				\
+		: [loop] "=&r" (loop), [ret] "=&r" (ret),		\
+		  [ptr]  "+Q"(*(u16 *)ptr)				\
+		: [val] "Ir" (val));					\
 		break;							\
 	case 4:								\
-		do {							\
-			asm ("//__per_cpu_" #op "_4\n"			\
-			"ldxr	  %w[ret], %[ptr]\n"			\
+		asm ("//__per_cpu_" #op "_4\n"				\
+		"1:	ldxr	  %w[ret], %[ptr]\n"			\
 			#asm_op " %w[ret], %w[ret], %w[val]\n"		\
-			"stxr	  %w[loop], %w[ret], %[ptr]\n"		\
-			: [loop] "=&r" (loop), [ret] "=&r" (ret),	\
-			  [ptr] "+Q"(*(u32 *)ptr)			\
-			: [val] "Ir" (val));				\
-		} while (loop);						\
+		"	stxr	  %w[loop], %w[ret], %[ptr]\n"		\
+		"	cbnz	  %w[loop], 1b"				\
+		: [loop] "=&r" (loop), [ret] "=&r" (ret),		\
+		  [ptr] "+Q"(*(u32 *)ptr)				\
+		: [val] "Ir" (val));					\
 		break;							\
 	case 8:								\
-		do {							\
-			asm ("//__per_cpu_" #op "_8\n"			\
-			"ldxr	  %[ret], %[ptr]\n"			\
+		asm ("//__per_cpu_" #op "_8\n"				\
+		"1:	ldxr	  %[ret], %[ptr]\n"			\
 			#asm_op " %[ret], %[ret], %[val]\n"		\
-			"stxr	  %w[loop], %[ret], %[ptr]\n"		\
-			: [loop] "=&r" (loop), [ret] "=&r" (ret),	\
-			  [ptr] "+Q"(*(u64 *)ptr)			\
-			: [val] "Ir" (val));				\
-		} while (loop);						\
+		"	stxr	  %w[loop], %[ret], %[ptr]\n"		\
+		"	cbnz	  %w[loop], 1b"				\
+		: [loop] "=&r" (loop), [ret] "=&r" (ret),		\
+		  [ptr] "+Q"(*(u64 *)ptr)				\
+		: [val] "Ir" (val));					\
 		break;							\
 	default:							\
+		ret = 0;						\
 		BUILD_BUG();						\
 	}								\
 									\
@@ -117,6 +114,7 @@
 		ret = ACCESS_ONCE(*(u64 *)ptr);
 		break;
 	default:
+		ret = 0;
 		BUILD_BUG();
 	}
 
@@ -150,46 +148,43 @@
 
 	switch (size) {
 	case 1:
-		do {
-			asm ("//__percpu_xchg_1\n"
-			"ldxrb %w[ret], %[ptr]\n"
-			"stxrb %w[loop], %w[val], %[ptr]\n"
-			: [loop] "=&r"(loop), [ret] "=&r"(ret),
-			  [ptr] "+Q"(*(u8 *)ptr)
-			: [val] "r" (val));
-		} while (loop);
+		asm ("//__percpu_xchg_1\n"
+		"1:	ldxrb	%w[ret], %[ptr]\n"
+		"	stxrb	%w[loop], %w[val], %[ptr]\n"
+		"	cbnz	%w[loop], 1b"
+		: [loop] "=&r"(loop), [ret] "=&r"(ret),
+		  [ptr] "+Q"(*(u8 *)ptr)
+		: [val] "r" (val));
 		break;
 	case 2:
-		do {
-			asm ("//__percpu_xchg_2\n"
-			"ldxrh %w[ret], %[ptr]\n"
-			"stxrh %w[loop], %w[val], %[ptr]\n"
-			: [loop] "=&r"(loop), [ret] "=&r"(ret),
-			  [ptr] "+Q"(*(u16 *)ptr)
-			: [val] "r" (val));
-		} while (loop);
+		asm ("//__percpu_xchg_2\n"
+		"1:	ldxrh	%w[ret], %[ptr]\n"
+		"	stxrh	%w[loop], %w[val], %[ptr]\n"
+		"	cbnz	%w[loop], 1b"
+		: [loop] "=&r"(loop), [ret] "=&r"(ret),
+		  [ptr] "+Q"(*(u16 *)ptr)
+		: [val] "r" (val));
 		break;
 	case 4:
-		do {
-			asm ("//__percpu_xchg_4\n"
-			"ldxr %w[ret], %[ptr]\n"
-			"stxr %w[loop], %w[val], %[ptr]\n"
-			: [loop] "=&r"(loop), [ret] "=&r"(ret),
-			  [ptr] "+Q"(*(u32 *)ptr)
-			: [val] "r" (val));
-		} while (loop);
+		asm ("//__percpu_xchg_4\n"
+		"1:	ldxr	%w[ret], %[ptr]\n"
+		"	stxr	%w[loop], %w[val], %[ptr]\n"
+		"	cbnz	%w[loop], 1b"
+		: [loop] "=&r"(loop), [ret] "=&r"(ret),
+		  [ptr] "+Q"(*(u32 *)ptr)
+		: [val] "r" (val));
 		break;
 	case 8:
-		do {
-			asm ("//__percpu_xchg_8\n"
-			"ldxr %[ret], %[ptr]\n"
-			"stxr %w[loop], %[val], %[ptr]\n"
-			: [loop] "=&r"(loop), [ret] "=&r"(ret),
-			  [ptr] "+Q"(*(u64 *)ptr)
-			: [val] "r" (val));
-		} while (loop);
+		asm ("//__percpu_xchg_8\n"
+		"1:	ldxr	%[ret], %[ptr]\n"
+		"	stxr	%w[loop], %[val], %[ptr]\n"
+		"	cbnz	%w[loop], 1b"
+		: [loop] "=&r"(loop), [ret] "=&r"(ret),
+		  [ptr] "+Q"(*(u64 *)ptr)
+		: [val] "r" (val));
 		break;
 	default:
+		ret = 0;
 		BUILD_BUG();
 	}
 
--- linux-4.4.0.orig/arch/arm64/include/asm/pgtable-hwdef.h
+++ linux-4.4.0/arch/arm64/include/asm/pgtable-hwdef.h
@@ -117,7 +117,6 @@
  * Section
  */
 #define PMD_SECT_VALID		(_AT(pmdval_t, 1) << 0)
-#define PMD_SECT_PROT_NONE	(_AT(pmdval_t, 1) << 58)
 #define PMD_SECT_USER		(_AT(pmdval_t, 1) << 6)		/* AP[1] */
 #define PMD_SECT_RDONLY		(_AT(pmdval_t, 1) << 7)		/* AP[2] */
 #define PMD_SECT_S		(_AT(pmdval_t, 3) << 8)
--- linux-4.4.0.orig/arch/arm64/include/asm/pgtable.h
+++ linux-4.4.0/arch/arm64/include/asm/pgtable.h
@@ -34,7 +34,7 @@
 /*
  * VMALLOC and SPARSEMEM_VMEMMAP ranges.
  *
- * VMEMAP_SIZE: allows the whole VA space to be covered by a struct page array
+ * VMEMAP_SIZE: allows the whole linear region to be covered by a struct page array
  *	(rounded up to PUD_SIZE).
  * VMALLOC_START: beginning of the kernel VA space
  * VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space,
@@ -51,7 +51,9 @@
 
 #define VMALLOC_END		(PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
 
-#define vmemmap			((struct page *)(VMALLOC_END + SZ_64K))
+#define VMEMMAP_START		(VMALLOC_END + SZ_64K)
+#define vmemmap			((struct page *)VMEMMAP_START - \
+				 SECTION_ALIGN_DOWN(memstart_addr >> PAGE_SHIFT))
 
 #define FIRST_USER_ADDRESS	0UL
 
@@ -67,11 +69,11 @@
 #define PROT_DEFAULT		(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
 #define PROT_SECT_DEFAULT	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
-#define PROT_DEVICE_nGnRnE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
-#define PROT_DEVICE_nGnRE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
-#define PROT_NORMAL_NC		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_NC))
-#define PROT_NORMAL_WT		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_WT))
-#define PROT_NORMAL		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL))
+#define PROT_DEVICE_nGnRnE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
+#define PROT_DEVICE_nGnRE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE))
+#define PROT_NORMAL_NC		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
+#define PROT_NORMAL_WT		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
+#define PROT_NORMAL		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
 
 #define PROT_SECT_DEVICE_nGnRE	(PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
 #define PROT_SECT_NORMAL	(PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
@@ -81,7 +83,7 @@
 
 #define PAGE_KERNEL		__pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 #define PAGE_KERNEL_RO		__pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
-#define PAGE_KERNEL_ROX	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
+#define PAGE_KERNEL_ROX		__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
 #define PAGE_KERNEL_EXEC	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 #define PAGE_KERNEL_EXEC_CONT	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
 
@@ -153,6 +155,7 @@
 #define pte_write(pte)		(!!(pte_val(pte) & PTE_WRITE))
 #define pte_exec(pte)		(!(pte_val(pte) & PTE_UXN))
 #define pte_cont(pte)		(!!(pte_val(pte) & PTE_CONT))
+#define pte_user(pte)		(!!(pte_val(pte) & PTE_USER))
 
 #ifdef CONFIG_ARM64_HW_AFDBM
 #define pte_hw_dirty(pte)	(pte_write(pte) && !(pte_val(pte) & PTE_RDONLY))
@@ -163,8 +166,6 @@
 #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
 
 #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
-#define pte_valid_user(pte) \
-	((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
 #define pte_valid_not_user(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 
@@ -262,13 +263,13 @@
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep, pte_t pte)
 {
-	if (pte_valid_user(pte)) {
-		if (!pte_special(pte) && pte_exec(pte))
-			__sync_icache_dcache(pte, addr);
+	if (pte_present(pte)) {
 		if (pte_sw_dirty(pte) && pte_write(pte))
 			pte_val(pte) &= ~PTE_RDONLY;
 		else
 			pte_val(pte) |= PTE_RDONLY;
+		if (pte_user(pte) && pte_exec(pte) && !pte_special(pte))
+			__sync_icache_dcache(pte, addr);
 	}
 
 	/*
@@ -331,6 +332,21 @@
 	return __pgprot(pgprot_val(prot) & ~PTE_TABLE_BIT);
 }
 
+#ifdef CONFIG_NUMA_BALANCING
+/*
+ * See the comment in include/asm-generic/pgtable.h
+ */
+static inline int pte_protnone(pte_t pte)
+{
+	return (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) == PTE_PROT_NONE;
+}
+
+static inline int pmd_protnone(pmd_t pmd)
+{
+	return pte_protnone(pmd_pte(pmd));
+}
+#endif
+
 /*
  * THP definitions.
  */
@@ -346,6 +362,7 @@
 #endif /* CONFIG_HAVE_RCU_TABLE_FREE */
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+#define pmd_present(pmd)	pte_present(pmd_pte(pmd))
 #define pmd_dirty(pmd)		pte_dirty(pmd_pte(pmd))
 #define pmd_young(pmd)		pte_young(pmd_pte(pmd))
 #define pmd_wrprotect(pmd)	pte_pmd(pte_wrprotect(pmd_pte(pmd)))
@@ -354,7 +371,7 @@
 #define pmd_mkwrite(pmd)	pte_pmd(pte_mkwrite(pmd_pte(pmd)))
 #define pmd_mkdirty(pmd)	pte_pmd(pte_mkdirty(pmd_pte(pmd)))
 #define pmd_mkyoung(pmd)	pte_pmd(pte_mkyoung(pmd_pte(pmd)))
-#define pmd_mknotpresent(pmd)	(__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))
+#define pmd_mknotpresent(pmd)	(__pmd(pmd_val(pmd) & ~PMD_SECT_VALID))
 
 #define __HAVE_ARCH_PMD_WRITE
 #define pmd_write(pmd)		pte_write(pmd_pte(pmd))
@@ -393,7 +410,6 @@
 				     unsigned long size, pgprot_t vma_prot);
 
 #define pmd_none(pmd)		(!pmd_val(pmd))
-#define pmd_present(pmd)	(pmd_val(pmd))
 
 #define pmd_bad(pmd)		(!(pmd_val(pmd) & 2))
 
@@ -537,6 +553,21 @@
 }
 
 #ifdef CONFIG_ARM64_HW_AFDBM
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+extern int ptep_set_access_flags(struct vm_area_struct *vma,
+				 unsigned long address, pte_t *ptep,
+				 pte_t entry, int dirty);
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
+static inline int pmdp_set_access_flags(struct vm_area_struct *vma,
+					unsigned long address, pmd_t *pmdp,
+					pmd_t entry, int dirty)
+{
+	return ptep_set_access_flags(vma, address, (pte_t *)pmdp, pmd_pte(entry), dirty);
+}
+#endif
+
 /*
  * Atomic pte/pmd modifications.
  */
@@ -589,9 +620,9 @@
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
-static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
-				       unsigned long address, pmd_t *pmdp)
+#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
+static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
+					    unsigned long address, pmd_t *pmdp)
 {
 	return pte_pmd(ptep_get_and_clear(mm, address, (pte_t *)pmdp));
 }
@@ -639,6 +670,7 @@
  *	bits 0-1:	present (must be zero)
  *	bits 2-7:	swap type
  *	bits 8-57:	swap offset
+ *	bit  58:	PTE_PROT_NONE (must be zero)
  */
 #define __SWP_TYPE_SHIFT	2
 #define __SWP_TYPE_BITS		6
--- linux-4.4.0.orig/arch/arm64/include/asm/processor.h
+++ linux-4.4.0/arch/arm64/include/asm/processor.h
@@ -29,8 +29,10 @@
 
 #include <linux/string.h>
 
+#include <asm/alternative.h>
 #include <asm/fpsimd.h>
 #include <asm/hw_breakpoint.h>
+#include <asm/lse.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
@@ -177,15 +179,17 @@
 }
 
 #define ARCH_HAS_SPINLOCK_PREFETCH
-static inline void spin_lock_prefetch(const void *x)
+static inline void spin_lock_prefetch(const void *ptr)
 {
-	prefetchw(x);
+	asm volatile(ARM64_LSE_ATOMIC_INSN(
+		     "prfm pstl1strm, %a0",
+		     "nop") : : "p" (ptr));
 }
 
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 
 #endif
 
-void cpu_enable_pan(void *__unused);
+int cpu_enable_pan(void *__unused);
 
 #endif /* __ASM_PROCESSOR_H */
--- linux-4.4.0.orig/arch/arm64/include/asm/ptrace.h
+++ linux-4.4.0/arch/arm64/include/asm/ptrace.h
@@ -58,6 +58,7 @@
 #define COMPAT_PSR_Z_BIT	0x40000000
 #define COMPAT_PSR_N_BIT	0x80000000
 #define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
+#define COMPAT_PSR_GE_MASK	0x000f0000
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
 #define COMPAT_PSR_ENDSTATE	COMPAT_PSR_E_BIT
@@ -116,6 +117,8 @@
 	};
 	u64 orig_x0;
 	u64 syscallno;
+	u64 orig_addr_limit;
+	u64 unused;	// maintain 16 byte alignment
 };
 
 #define arch_has_single_step()	(1)
@@ -151,35 +154,9 @@
 	return regs->regs[0];
 }
 
-/*
- * Are the current registers suitable for user mode? (used to maintain
- * security in signal handlers)
- */
-static inline int valid_user_regs(struct user_pt_regs *regs)
-{
-	if (user_mode(regs) && (regs->pstate & PSR_I_BIT) == 0) {
-		regs->pstate &= ~(PSR_F_BIT | PSR_A_BIT);
-
-		/* The T bit is reserved for AArch64 */
-		if (!(regs->pstate & PSR_MODE32_BIT))
-			regs->pstate &= ~COMPAT_PSR_T_BIT;
-
-		return 1;
-	}
-
-	/*
-	 * Force PSR to something logical...
-	 */
-	regs->pstate &= PSR_f | PSR_s | (PSR_x & ~PSR_A_BIT) | \
-			COMPAT_PSR_T_BIT | PSR_MODE32_BIT;
-
-	if (!(regs->pstate & PSR_MODE32_BIT)) {
-		regs->pstate &= ~COMPAT_PSR_T_BIT;
-		regs->pstate |= PSR_MODE_EL0t;
-	}
-
-	return 0;
-}
+/* We must avoid circular header include via sched.h */
+struct task_struct;
+int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task);
 
 #define instruction_pointer(regs)	((unsigned long)(regs)->pc)
 
--- linux-4.4.0.orig/arch/arm64/include/asm/shmparam.h
+++ linux-4.4.0/arch/arm64/include/asm/shmparam.h
@@ -21,7 +21,7 @@
  * alignment value. Since we don't have aliasing D-caches, the rest of
  * the time we can safely use PAGE_SIZE.
  */
-#define COMPAT_SHMLBA	0x4000
+#define COMPAT_SHMLBA	(4 * PAGE_SIZE)
 
 #include <asm-generic/shmparam.h>
 
--- linux-4.4.0.orig/arch/arm64/include/asm/smp.h
+++ linux-4.4.0/arch/arm64/include/asm/smp.h
@@ -64,6 +64,15 @@
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
+#else
+static inline void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
+{
+	BUILD_BUG();
+}
+#endif
+
 extern int __cpu_disable(void);
 
 extern void __cpu_die(unsigned int cpu);
--- linux-4.4.0.orig/arch/arm64/include/asm/spinlock.h
+++ linux-4.4.0/arch/arm64/include/asm/spinlock.h
@@ -94,8 +94,8 @@
 	"	cbnz	%w1, 1f\n"
 	"	add	%w1, %w0, %3\n"
 	"	casa	%w0, %w1, %2\n"
-	"	and	%w1, %w1, #0xffff\n"
-	"	eor	%w1, %w1, %w0, lsr #16\n"
+	"	sub	%w1, %w1, %3\n"
+	"	eor	%w1, %w1, %w0\n"
 	"1:")
 	: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
 	: "I" (1 << TICKET_SHIFT)
@@ -312,4 +312,14 @@
 #define arch_read_relax(lock)	cpu_relax()
 #define arch_write_relax(lock)	cpu_relax()
 
+/*
+ * Accesses appearing in program order before a spin_lock() operation
+ * can be reordered with accesses inside the critical section, by virtue
+ * of arch_spin_lock being constructed using acquire semantics.
+ *
+ * In cases where this is problematic (e.g. try_to_wake_up), an
+ * smp_mb__before_spinlock() can restore the required ordering.
+ */
+#define smp_mb__before_spinlock()	smp_mb()
+
 #endif /* __ASM_SPINLOCK_H */
--- linux-4.4.0.orig/arch/arm64/include/asm/sysreg.h
+++ linux-4.4.0/arch/arm64/include/asm/sysreg.h
@@ -109,6 +109,7 @@
 #define ID_AA64PFR0_ASIMD_SUPPORTED	0x0
 #define ID_AA64PFR0_EL1_64BIT_ONLY	0x1
 #define ID_AA64PFR0_EL0_64BIT_ONLY	0x1
+#define ID_AA64PFR0_EL0_32BIT_64BIT	0x2
 
 /* id_aa64mmfr0 */
 #define ID_AA64MMFR0_TGRAN4_SHIFT	28
--- linux-4.4.0.orig/arch/arm64/include/asm/topology.h
+++ linux-4.4.0/arch/arm64/include/asm/topology.h
@@ -22,6 +22,16 @@
 void store_cpu_topology(unsigned int cpuid);
 const struct cpumask *cpu_coregroup_mask(int cpu);
 
+#ifdef CONFIG_NUMA
+
+struct pci_bus;
+int pcibus_to_node(struct pci_bus *bus);
+#define cpumask_of_pcibus(bus)	(pcibus_to_node(bus) == -1 ?		\
+				 cpu_all_mask :				\
+				 cpumask_of_node(pcibus_to_node(bus)))
+
+#endif /* CONFIG_NUMA */
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_ARM_TOPOLOGY_H */
--- linux-4.4.0.orig/arch/arm64/include/asm/uaccess.h
+++ linux-4.4.0/arch/arm64/include/asm/uaccess.h
@@ -21,6 +21,7 @@
 /*
  * User space memory access functions
  */
+#include <linux/bitops.h>
 #include <linux/string.h>
 #include <linux/thread_info.h>
 
@@ -92,16 +93,24 @@
  */
 #define __range_ok(addr, size)						\
 ({									\
+	unsigned long __addr = (unsigned long __force)(addr);		\
 	unsigned long flag, roksum;					\
 	__chk_user_ptr(addr);						\
 	asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls"		\
 		: "=&r" (flag), "=&r" (roksum)				\
-		: "1" (addr), "Ir" (size),				\
+		: "1" (__addr), "Ir" (size),				\
 		  "r" (current_thread_info()->addr_limit)		\
 		: "cc");						\
 	flag;								\
 })
 
+/*
+ * When dealing with data aborts, watchpoints, or instruction traps we may end
+ * up with a tagged userland pointer. Clear the tag to get a sane pointer to
+ * pass on to access_ok(), for instance.
+ */
+#define untagged_addr(addr)		sign_extend64(addr, 55)
+
 #define access_ok(type, addr, size)	__range_ok(addr, size)
 #define user_addr_max			get_fs
 
--- linux-4.4.0.orig/arch/arm64/include/uapi/asm/auxvec.h
+++ linux-4.4.0/arch/arm64/include/uapi/asm/auxvec.h
@@ -19,4 +19,6 @@
 /* vDSO location */
 #define AT_SYSINFO_EHDR	33
 
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
 #endif
--- linux-4.4.0.orig/arch/arm64/include/uapi/asm/ptrace.h
+++ linux-4.4.0/arch/arm64/include/uapi/asm/ptrace.h
@@ -76,6 +76,7 @@
 	__uint128_t	vregs[32];
 	__u32		fpsr;
 	__u32		fpcr;
+	__u32		__reserved[2];
 };
 
 struct user_hwdebug_state {
--- linux-4.4.0.orig/arch/arm64/kernel/Makefile
+++ linux-4.4.0/arch/arm64/kernel/Makefile
@@ -14,10 +14,10 @@
 arm64-obj-y		:= debug-monitors.o entry.o irq.o fpsimd.o		\
 			   entry-fpsimd.o process.o ptrace.o setup.o signal.o	\
 			   sys.o stacktrace.o time.o traps.o io.o vdso.o	\
-			   hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o	\
+			   hyp-stub.o psci.o cpu_ops.o insn.o	\
 			   return_address.o cpuinfo.o cpu_errata.o		\
 			   cpufeature.o alternative.o cacheinfo.o		\
-			   smp.o smp_spin_table.o topology.o
+			   smp.o smp_spin_table.o topology.o smccc-call.o
 
 extra-$(CONFIG_EFI)			:= efi-entry.o
 
@@ -41,6 +41,7 @@
 arm64-obj-$(CONFIG_PCI)			+= pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
 arm64-obj-$(CONFIG_ACPI)		+= acpi.o
+arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL)	+= acpi_parking_protocol.o
 
 obj-y					+= $(arm64-obj-y) vdso/
 obj-m					+= $(arm64-obj-m)
--- linux-4.4.0.orig/arch/arm64/kernel/acpi.c
+++ linux-4.4.0/arch/arm64/kernel/acpi.c
@@ -24,6 +24,7 @@
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/smp.h>
+#include <linux/serial_core.h>
 
 #include <asm/cputype.h>
 #include <asm/cpu_ops.h>
@@ -141,10 +142,14 @@
 	 */
 	if (table->revision < 5 ||
 	   (table->revision == 5 && fadt->minor_revision < 1)) {
-		pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n",
+		pr_err(FW_BUG "Unsupported FADT revision %d.%d, should be 5.1+\n",
 		       table->revision, fadt->minor_revision);
-		ret = -EINVAL;
-		goto out;
+
+		if (!fadt->arm_boot_flags) {
+			ret = -EINVAL;
+			goto out;
+		}
+		pr_err("FADT has ARM boot flags set, assuming 5.1\n");
 	}
 
 	if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) {
@@ -189,7 +194,7 @@
 	 */
 	if (param_acpi_off ||
 	    (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL)))
-		return;
+		goto done;
 
 	/*
 	 * ACPI is disabled at this point. Enable it in order to parse
@@ -209,6 +214,14 @@
 		if (!param_acpi_force)
 			disable_acpi();
 	}
+
+done:
+	if (acpi_disabled) {
+		if (earlycon_init_is_deferred)
+			early_init_dt_scan_chosen_stdout();
+	} else {
+		parse_spcr(earlycon_init_is_deferred);
+	}
 }
 
 #ifdef CONFIG_ACPI_APEI
--- linux-4.4.0.orig/arch/arm64/kernel/acpi_parking_protocol.c
+++ linux-4.4.0/arch/arm64/kernel/acpi_parking_protocol.c
@@ -0,0 +1,153 @@
+/*
+ * ARM64 ACPI Parking Protocol implementation
+ *
+ * Authors: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ *	    Mark Salter <msalter@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/acpi.h>
+#include <linux/types.h>
+
+#include <asm/cpu_ops.h>
+
+struct cpu_mailbox_entry {
+	phys_addr_t mailbox_addr;
+	u8 version;
+	u8 gic_cpu_id;
+};
+
+static struct cpu_mailbox_entry cpu_mailbox_entries[NR_CPUS];
+
+void __init acpi_set_mailbox_entry(int cpu,
+				   struct acpi_madt_generic_interrupt *p)
+{
+	struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
+
+	cpu_entry->mailbox_addr = p->parked_address;
+	cpu_entry->version = p->parking_version;
+	cpu_entry->gic_cpu_id = p->cpu_interface_number;
+}
+
+bool acpi_parking_protocol_valid(int cpu)
+{
+	struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
+
+	return cpu_entry->mailbox_addr && cpu_entry->version;
+}
+
+static int acpi_parking_protocol_cpu_init(unsigned int cpu)
+{
+	pr_debug("%s: ACPI parked addr=%llx\n", __func__,
+		  cpu_mailbox_entries[cpu].mailbox_addr);
+
+	return 0;
+}
+
+static int acpi_parking_protocol_cpu_prepare(unsigned int cpu)
+{
+	return 0;
+}
+
+struct parking_protocol_mailbox {
+	__le32 cpu_id;
+	__le32 reserved;
+	__le64 entry_point;
+};
+
+static int acpi_parking_protocol_cpu_boot(unsigned int cpu)
+{
+	struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
+	struct parking_protocol_mailbox __iomem *mailbox;
+	__le32 cpu_id;
+
+	/*
+	 * Map mailbox memory with attribute device nGnRE (ie ioremap -
+	 * this deviates from the parking protocol specifications since
+	 * the mailboxes are required to be mapped nGnRnE; the attribute
+	 * discrepancy is harmless insofar as the protocol specification
+	 * is concerned).
+	 * If the mailbox is mistakenly allocated in the linear mapping
+	 * by FW ioremap will fail since the mapping will be prevented
+	 * by the kernel (it clashes with the linear mapping attributes
+	 * specifications).
+	 */
+	mailbox = ioremap(cpu_entry->mailbox_addr, sizeof(*mailbox));
+	if (!mailbox)
+		return -EIO;
+
+	cpu_id = readl_relaxed(&mailbox->cpu_id);
+	/*
+	 * Check if firmware has set-up the mailbox entry properly
+	 * before kickstarting the respective cpu.
+	 */
+	if (cpu_id != ~0U) {
+		iounmap(mailbox);
+		return -ENXIO;
+	}
+
+	/*
+	 * We write the entry point and cpu id as LE regardless of the
+	 * native endianness of the kernel. Therefore, any boot-loaders
+	 * that read this address need to convert this address to the
+	 * Boot-Loader's endianness before jumping.
+	 */
+	writeq_relaxed(__pa(secondary_entry), &mailbox->entry_point);
+	writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id);
+
+	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+	iounmap(mailbox);
+
+	return 0;
+}
+
+static void acpi_parking_protocol_cpu_postboot(void)
+{
+	int cpu = smp_processor_id();
+	struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
+	struct parking_protocol_mailbox __iomem *mailbox;
+	__le64 entry_point;
+
+	/*
+	 * Map mailbox memory with attribute device nGnRE (ie ioremap -
+	 * this deviates from the parking protocol specifications since
+	 * the mailboxes are required to be mapped nGnRnE; the attribute
+	 * discrepancy is harmless insofar as the protocol specification
+	 * is concerned).
+	 * If the mailbox is mistakenly allocated in the linear mapping
+	 * by FW ioremap will fail since the mapping will be prevented
+	 * by the kernel (it clashes with the linear mapping attributes
+	 * specifications).
+	 */
+	mailbox = ioremap(cpu_entry->mailbox_addr, sizeof(*mailbox));
+	if (!mailbox)
+		return;
+
+	entry_point = readl_relaxed(&mailbox->entry_point);
+	/*
+	 * Check if firmware has cleared the entry_point as expected
+	 * by the protocol specification.
+	 */
+	WARN_ON(entry_point);
+
+	iounmap(mailbox);
+}
+
+const struct cpu_operations acpi_parking_protocol_ops = {
+	.name		= "parking-protocol",
+	.cpu_init	= acpi_parking_protocol_cpu_init,
+	.cpu_prepare	= acpi_parking_protocol_cpu_prepare,
+	.cpu_boot	= acpi_parking_protocol_cpu_boot,
+	.cpu_postboot	= acpi_parking_protocol_cpu_postboot
+};
--- linux-4.4.0.orig/arch/arm64/kernel/arm64ksyms.c
+++ linux-4.4.0/arch/arm64/kernel/arm64ksyms.c
@@ -26,6 +26,7 @@
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/arm-smccc.h>
 
 #include <asm/checksum.h>
 
@@ -68,3 +69,7 @@
 #ifdef CONFIG_FUNCTION_TRACER
 EXPORT_SYMBOL(_mcount);
 #endif
+
+	/* arm-smccc */
+EXPORT_SYMBOL(arm_smccc_smc);
+EXPORT_SYMBOL(arm_smccc_hvc);
--- linux-4.4.0.orig/arch/arm64/kernel/armv8_deprecated.c
+++ linux-4.4.0/arch/arm64/kernel/armv8_deprecated.c
@@ -64,6 +64,7 @@
 static LIST_HEAD(insn_emulation);
 static int nr_insn_emulated;
 static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
+static DEFINE_MUTEX(insn_emulation_mutex);
 
 static void register_emulation_hooks(struct insn_emulation_ops *ops)
 {
@@ -209,10 +210,10 @@
 				  loff_t *ppos)
 {
 	int ret = 0;
-	struct insn_emulation *insn = (struct insn_emulation *) table->data;
+	struct insn_emulation *insn = container_of(table->data, struct insn_emulation, current_mode);
 	enum insn_emulation_mode prev_mode = insn->current_mode;
 
-	table->data = &insn->current_mode;
+	mutex_lock(&insn_emulation_mutex);
 	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 
 	if (ret || !write || prev_mode == insn->current_mode)
@@ -225,7 +226,7 @@
 		update_insn_emulation_mode(insn, INSN_UNDEF);
 	}
 ret:
-	table->data = insn;
+	mutex_unlock(&insn_emulation_mutex);
 	return ret;
 }
 
@@ -255,7 +256,7 @@
 		sysctl->maxlen = sizeof(int);
 
 		sysctl->procname = insn->ops->name;
-		sysctl->data = insn;
+		sysctl->data = &insn->current_mode;
 		sysctl->extra1 = &insn->min;
 		sysctl->extra2 = &insn->max;
 		sysctl->proc_handler = emulation_proc_handler;
@@ -305,7 +306,8 @@
 	ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,	\
 		CONFIG_ARM64_PAN)				\
 	: "=&r" (res), "+r" (data), "=&r" (temp)		\
-	: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)		\
+	: "r" ((unsigned long)addr), "i" (-EAGAIN),		\
+	  "i" (-EFAULT)						\
 	: "memory")
 
 #define __user_swp_asm(data, addr, res, temp) \
@@ -604,7 +606,7 @@
 	},
 	{
 		/* Thumb mode */
-		.instr_mask	= 0x0000fff7,
+		.instr_mask	= 0xfffffff7,
 		.instr_val	= 0x0000b650,
 		.pstate_mask	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK),
 		.pstate_val	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR),
--- linux-4.4.0.orig/arch/arm64/kernel/asm-offsets.c
+++ linux-4.4.0/arch/arm64/kernel/asm-offsets.c
@@ -28,6 +28,7 @@
 #include <asm/suspend.h>
 #include <asm/vdso_datapage.h>
 #include <linux/kbuild.h>
+#include <linux/arm-smccc.h>
 
 int main(void)
 {
@@ -58,6 +59,7 @@
   DEFINE(S_PC,			offsetof(struct pt_regs, pc));
   DEFINE(S_ORIG_X0,		offsetof(struct pt_regs, orig_x0));
   DEFINE(S_SYSCALLNO,		offsetof(struct pt_regs, syscallno));
+  DEFINE(S_ORIG_ADDR_LIMIT,	offsetof(struct pt_regs, orig_addr_limit));
   DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
   BLANK();
   DEFINE(MM_CONTEXT_ID,		offsetof(struct mm_struct, context.id.counter));
@@ -161,5 +163,7 @@
   DEFINE(SLEEP_SAVE_SP_PHYS,	offsetof(struct sleep_save_sp, save_ptr_stash_phys));
   DEFINE(SLEEP_SAVE_SP_VIRT,	offsetof(struct sleep_save_sp, save_ptr_stash));
 #endif
+  DEFINE(ARM_SMCCC_RES_X0_OFFS,	offsetof(struct arm_smccc_res, a0));
+  DEFINE(ARM_SMCCC_RES_X2_OFFS,	offsetof(struct arm_smccc_res, a2));
   return 0;
 }
--- linux-4.4.0.orig/arch/arm64/kernel/cpu_errata.c
+++ linux-4.4.0/arch/arm64/kernel/cpu_errata.c
@@ -21,24 +21,12 @@
 #include <asm/cputype.h>
 #include <asm/cpufeature.h>
 
-#define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
-#define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
-#define MIDR_THUNDERX	MIDR_CPU_PART(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
-
-#define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
-			MIDR_ARCHITECTURE_MASK)
-
 static bool __maybe_unused
 is_affected_midr_range(const struct arm64_cpu_capabilities *entry)
 {
-	u32 midr = read_cpuid_id();
-
-	if ((midr & CPU_MODEL_MASK) != entry->midr_model)
-		return false;
-
-	midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK;
-
-	return (midr >= entry->midr_range_min && midr <= entry->midr_range_max);
+	return MIDR_IS_CPU_MODEL_RANGE(read_cpuid_id(), entry->midr_model,
+				       entry->midr_range_min,
+				       entry->midr_range_max);
 }
 
 #define MIDR_RANGE(model, min, max) \
@@ -100,6 +88,15 @@
 		MIDR_RANGE(MIDR_THUNDERX, 0x00, 0x01),
 	},
 #endif
+#ifdef CONFIG_CAVIUM_ERRATUM_27456
+	{
+	/* Cavium ThunderX, T88 pass 1.x - 2.1 */
+		.desc = "Cavium erratum 27456",
+		.capability = ARM64_WORKAROUND_CAVIUM_27456,
+		MIDR_RANGE(MIDR_THUNDERX, 0x00,
+			   (1 << MIDR_VARIANT_SHIFT) | 1),
+	},
+#endif
 	{
 	}
 };
--- linux-4.4.0.orig/arch/arm64/kernel/cpu_ops.c
+++ linux-4.4.0/arch/arm64/kernel/cpu_ops.c
@@ -25,19 +25,30 @@
 #include <asm/smp_plat.h>
 
 extern const struct cpu_operations smp_spin_table_ops;
+extern const struct cpu_operations acpi_parking_protocol_ops;
 extern const struct cpu_operations cpu_psci_ops;
 
 const struct cpu_operations *cpu_ops[NR_CPUS];
 
-static const struct cpu_operations *supported_cpu_ops[] __initconst = {
+static const struct cpu_operations *dt_supported_cpu_ops[] __initconst = {
 	&smp_spin_table_ops,
 	&cpu_psci_ops,
 	NULL,
 };
 
+static const struct cpu_operations *acpi_supported_cpu_ops[] __initconst = {
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+	&acpi_parking_protocol_ops,
+#endif
+	&cpu_psci_ops,
+	NULL,
+};
+
 static const struct cpu_operations * __init cpu_get_ops(const char *name)
 {
-	const struct cpu_operations **ops = supported_cpu_ops;
+	const struct cpu_operations **ops;
+
+	ops = acpi_disabled ? dt_supported_cpu_ops : acpi_supported_cpu_ops;
 
 	while (*ops) {
 		if (!strcmp(name, (*ops)->name))
@@ -73,10 +84,19 @@
 				pr_err("%s: missing enable-method property\n",
 					dn->full_name);
 		}
+		of_node_put(dn);
 	} else {
 		enable_method = acpi_get_enable_method(cpu);
-		if (!enable_method)
-			pr_err("Unsupported ACPI enable-method\n");
+		if (!enable_method) {
+			/*
+			 * In ACPI systems the boot CPU does not require
+			 * checking the enable method since for some
+			 * boot protocol (ie parking protocol) it need not
+			 * be initialized. Don't warn spuriously.
+			 */
+			if (cpu != 0)
+				pr_err("Unsupported ACPI enable-method\n");
+		}
 	}
 
 	return enable_method;
--- linux-4.4.0.orig/arch/arm64/kernel/cpufeature.c
+++ linux-4.4.0/arch/arm64/kernel/cpufeature.c
@@ -19,7 +19,9 @@
 #define pr_fmt(fmt) "CPU features: " fmt
 
 #include <linux/bsearch.h>
+#include <linux/cpumask.h>
 #include <linux/sort.h>
+#include <linux/stop_machine.h>
 #include <linux/types.h>
 #include <asm/cpu.h>
 #include <asm/cpufeature.h>
@@ -124,10 +126,12 @@
 };
 
 static struct arm64_ftr_bits ftr_ctr[] = {
-	U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1),	/* RAO */
-	ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0),
-	U_ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0),	/* CWG */
-	U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),	/* ERG */
+	U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1),	/* RES1 */
+	ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 30, 1, 0),
+	U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 29, 1, 1),	/* DIC */
+	U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 28, 1, 1),	/* IDC */
+	U_ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, 24, 4, 0),	/* CWG */
+	U_ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, 20, 4, 0),	/* ERG */
 	U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1),	/* DminLine */
 	/*
 	 * Linux can handle differing I-cache policies. Userspace JITs will
@@ -337,6 +341,10 @@
 	case FTR_LOWER_SAFE:
 		ret = new < cur ? new : cur;
 		break;
+	case FTR_HIGHER_OR_ZERO_SAFE:
+		if (!cur || !new)
+			break;
+		/* Fallthrough */
 	case FTR_HIGHER_SAFE:
 		ret = new > cur ? new : cur;
 		break;
@@ -592,7 +600,7 @@
 static bool
 feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
 {
-	int val = cpuid_feature_extract_field(reg, entry->field_pos);
+	int val = cpuid_feature_extract_field(reg, entry->field_pos, entry->sign);
 
 	return val >= entry->min_field_value;
 }
@@ -621,6 +629,18 @@
 	return has_sre;
 }
 
+static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry)
+{
+	u32 midr = read_cpuid_id();
+	u32 rv_min, rv_max;
+
+	/* Cavium ThunderX pass 1.x and 2.x */
+	rv_min = 0;
+	rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK;
+
+	return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max);
+}
+
 static const struct arm64_cpu_capabilities arm64_features[] = {
 	{
 		.desc = "GIC system register CPU interface",
@@ -628,6 +648,7 @@
 		.matches = has_useable_gicv3_cpuif,
 		.sys_reg = SYS_ID_AA64PFR0_EL1,
 		.field_pos = ID_AA64PFR0_GIC_SHIFT,
+		.sign = FTR_UNSIGNED,
 		.min_field_value = 1,
 	},
 #ifdef CONFIG_ARM64_PAN
@@ -637,6 +658,7 @@
 		.matches = has_cpuid_feature,
 		.sys_reg = SYS_ID_AA64MMFR1_EL1,
 		.field_pos = ID_AA64MMFR1_PAN_SHIFT,
+		.sign = FTR_UNSIGNED,
 		.min_field_value = 1,
 		.enable = cpu_enable_pan,
 	},
@@ -648,38 +670,54 @@
 		.matches = has_cpuid_feature,
 		.sys_reg = SYS_ID_AA64ISAR0_EL1,
 		.field_pos = ID_AA64ISAR0_ATOMICS_SHIFT,
+		.sign = FTR_UNSIGNED,
 		.min_field_value = 2,
 	},
 #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
+	{
+		.desc = "Software prefetching using PRFM",
+		.capability = ARM64_HAS_NO_HW_PREFETCH,
+		.matches = has_no_hw_prefetch,
+	},
+	{
+		.desc = "32-bit EL0 Support",
+		.capability = ARM64_HAS_32BIT_EL0,
+		.matches = has_cpuid_feature,
+		.sys_reg = SYS_ID_AA64PFR0_EL1,
+		.field_pos = ID_AA64PFR0_EL0_SHIFT,
+		.sign = FTR_UNSIGNED,
+		.min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT,
+	},
 	{},
 };
 
-#define HWCAP_CAP(reg, field, min_value, type, cap)		\
+#define HWCAP_CAP(reg, field, s, min_value, type, cap)	\
 	{							\
 		.desc = #cap,					\
 		.matches = has_cpuid_feature,			\
 		.sys_reg = reg,					\
 		.field_pos = field,				\
+		.sign = s,					\
 		.min_field_value = min_value,			\
 		.hwcap_type = type,				\
 		.hwcap = cap,					\
 	}
 
 static const struct arm64_cpu_capabilities arm64_hwcaps[] = {
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, 2, CAP_HWCAP, HWCAP_PMULL),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, 1, CAP_HWCAP, HWCAP_AES),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, 1, CAP_HWCAP, HWCAP_SHA1),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, 1, CAP_HWCAP, HWCAP_SHA2),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, 1, CAP_HWCAP, HWCAP_CRC32),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, 2, CAP_HWCAP, HWCAP_ATOMICS),
-	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, 0, CAP_HWCAP, HWCAP_FP),
-	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, 0, CAP_HWCAP, HWCAP_ASIMD),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_PMULL),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_AES),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA1),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA2),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_CRC32),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ATOMICS),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD),
 #ifdef CONFIG_COMPAT
-	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL),
-	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES),
-	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1),
-	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2),
-	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32),
+	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL),
+	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES),
+	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1),
+	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2),
+	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32),
 #endif
 	{},
 };
@@ -764,7 +802,13 @@
 
 	for (i = 0; caps[i].desc; i++)
 		if (caps[i].enable && cpus_have_cap(caps[i].capability))
-			on_each_cpu(caps[i].enable, NULL, true);
+			/*
+			 * Use stop_machine() as it schedules the work allowing
+			 * us to modify PSTATE, instead of on_each_cpu() which
+			 * uses an IPI, giving us a PSTATE that disappears when
+			 * we return.
+			 */
+			stop_machine(caps[i].enable, NULL, cpu_online_mask);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
--- linux-4.4.0.orig/arch/arm64/kernel/cpuinfo.c
+++ linux-4.4.0/arch/arm64/kernel/cpuinfo.c
@@ -22,6 +22,8 @@
 
 #include <linux/bitops.h>
 #include <linux/bug.h>
+#include <linux/compat.h>
+#include <linux/elf.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/personality.h>
@@ -85,7 +87,8 @@
 	"idivt",
 	"vfpd32",
 	"lpae",
-	"evtstrm"
+	"evtstrm",
+	NULL
 };
 
 static const char *const compat_hwcap2_str[] = {
@@ -101,6 +104,7 @@
 static int c_show(struct seq_file *m, void *v)
 {
 	int i, j;
+	bool compat = personality(current->personality) == PER_LINUX32;
 
 	for_each_online_cpu(i) {
 		struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
@@ -112,6 +116,9 @@
 		 * "processor".  Give glibc what it expects.
 		 */
 		seq_printf(m, "processor\t: %d\n", i);
+		if (compat)
+			seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
+				   MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
 
 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
 			   loops_per_jiffy / (500000UL/HZ),
@@ -124,7 +131,7 @@
 		 * software which does already (at least for 32-bit).
 		 */
 		seq_puts(m, "Features\t:");
-		if (personality(current->personality) == PER_LINUX32) {
+		if (compat) {
 #ifdef CONFIG_COMPAT
 			for (j = 0; compat_hwcap_str[j]; j++)
 				if (compat_elf_hwcap & (1 << j))
--- linux-4.4.0.orig/arch/arm64/kernel/debug-monitors.c
+++ linux-4.4.0/arch/arm64/kernel/debug-monitors.c
@@ -34,7 +34,7 @@
 /* Determine debug architecture. */
 u8 debug_monitors_arch(void)
 {
-	return cpuid_feature_extract_field(read_system_reg(SYS_ID_AA64DFR0_EL1),
+	return cpuid_feature_extract_unsigned_field(read_system_reg(SYS_ID_AA64DFR0_EL1),
 						ID_AA64DFR0_DEBUGVER_SHIFT);
 }
 
@@ -152,7 +152,6 @@
 	/* Clear the OS lock. */
 	on_each_cpu(clear_os_lock, NULL, 1);
 	isb();
-	local_dbg_enable();
 
 	/* Register hotplug handler. */
 	__register_cpu_notifier(&os_lock_nb);
@@ -186,20 +185,21 @@
 
 /* EL1 Single Step Handler hooks */
 static LIST_HEAD(step_hook);
-static DEFINE_RWLOCK(step_hook_lock);
+static DEFINE_SPINLOCK(step_hook_lock);
 
 void register_step_hook(struct step_hook *hook)
 {
-	write_lock(&step_hook_lock);
-	list_add(&hook->node, &step_hook);
-	write_unlock(&step_hook_lock);
+	spin_lock(&step_hook_lock);
+	list_add_rcu(&hook->node, &step_hook);
+	spin_unlock(&step_hook_lock);
 }
 
 void unregister_step_hook(struct step_hook *hook)
 {
-	write_lock(&step_hook_lock);
-	list_del(&hook->node);
-	write_unlock(&step_hook_lock);
+	spin_lock(&step_hook_lock);
+	list_del_rcu(&hook->node);
+	spin_unlock(&step_hook_lock);
+	synchronize_rcu();
 }
 
 /*
@@ -213,15 +213,15 @@
 	struct step_hook *hook;
 	int retval = DBG_HOOK_ERROR;
 
-	read_lock(&step_hook_lock);
+	rcu_read_lock();
 
-	list_for_each_entry(hook, &step_hook, node)	{
+	list_for_each_entry_rcu(hook, &step_hook, node)	{
 		retval = hook->fn(regs, esr);
 		if (retval == DBG_HOOK_HANDLED)
 			break;
 	}
 
-	read_unlock(&step_hook_lock);
+	rcu_read_unlock();
 
 	return retval;
 }
@@ -387,13 +387,13 @@
 	 * If single step is active for this thread, then set SPSR.SS
 	 * to 1 to avoid returning to the active-pending state.
 	 */
-	if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP))
+	if (test_tsk_thread_flag(task, TIF_SINGLESTEP))
 		set_regs_spsr_ss(task_pt_regs(task));
 }
 
 void user_fastforward_single_step(struct task_struct *task)
 {
-	if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP))
+	if (test_tsk_thread_flag(task, TIF_SINGLESTEP))
 		clear_regs_spsr_ss(task_pt_regs(task));
 }
 
@@ -422,8 +422,10 @@
 /* ptrace API */
 void user_enable_single_step(struct task_struct *task)
 {
-	set_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
-	set_regs_spsr_ss(task_pt_regs(task));
+	struct thread_info *ti = task_thread_info(task);
+
+	if (!test_and_set_ti_thread_flag(ti, TIF_SINGLESTEP))
+		set_regs_spsr_ss(task_pt_regs(task));
 }
 
 void user_disable_single_step(struct task_struct *task)
--- linux-4.4.0.orig/arch/arm64/kernel/efi.c
+++ linux-4.4.0/arch/arm64/kernel/efi.c
@@ -168,6 +168,14 @@
 	if (efi_enabled(EFI_DBG))
 		pr_info("Processing EFI memory map:\n");
 
+	/*
+	 * Discard memblocks discovered so far: if there are any at this
+	 * point, they originate from memory nodes in the DT, and UEFI
+	 * uses its own memory map instead.
+	 */
+	memblock_dump_all();
+	memblock_remove(0, ULLONG_MAX);
+
 	for_each_efi_memory_desc(&memmap, md) {
 		paddr = md->phys_addr;
 		npages = md->num_pages;
--- linux-4.4.0.orig/arch/arm64/kernel/entry-ftrace.S
+++ linux-4.4.0/arch/arm64/kernel/entry-ftrace.S
@@ -78,7 +78,6 @@
 	.macro mcount_get_lr reg
 	ldr	\reg, [x29]
 	ldr	\reg, [\reg, #8]
-	mcount_adjust_addr	\reg, \reg
 	.endm
 
 	.macro mcount_get_lr_addr reg
--- linux-4.4.0.orig/arch/arm64/kernel/entry.S
+++ linux-4.4.0/arch/arm64/kernel/entry.S
@@ -27,7 +27,9 @@
 #include <asm/cpufeature.h>
 #include <asm/errno.h>
 #include <asm/esr.h>
+#include <asm/memory.h>
 #include <asm/thread_info.h>
+#include <asm/asm-uaccess.h>
 #include <asm/unistd.h>
 
 /*
@@ -93,7 +95,13 @@
 	disable_step_tsk x19, x20		// exceptions when scheduling.
 	.else
 	add	x21, sp, #S_FRAME_SIZE
-	.endif
+	get_thread_info tsk
+	/* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
+	ldr	x20, [tsk, #TI_ADDR_LIMIT]
+	str	x20, [sp, #S_ORIG_ADDR_LIMIT]
+	mov	x20, #TASK_SIZE_64
+	str	x20, [tsk, #TI_ADDR_LIMIT]
+	.endif /* \el == 0 */
 	mrs	x22, elr_el1
 	mrs	x23, spsr_el1
 	stp	lr, x21, [sp, #S_LR]
@@ -117,6 +125,12 @@
 	.endm
 
 	.macro	kernel_exit, el
+	.if	\el != 0
+	/* Restore the task's original addr_limit. */
+	ldr	x20, [sp, #S_ORIG_ADDR_LIMIT]
+	str	x20, [tsk, #TI_ADDR_LIMIT]
+	.endif
+
 	ldp	x21, x22, [sp, #S_PC]		// load ELR, SPSR
 	.if	\el == 0
 	ct_user_enter
@@ -229,7 +243,7 @@
  * Invalid mode handlers
  */
 	.macro	inv_entry, el, reason, regsize = 64
-	kernel_entry el, \regsize
+	kernel_entry \el, \regsize
 	mov	x0, sp
 	mov	x1, #\reason
 	mrs	x2, esr_el1
@@ -303,12 +317,13 @@
 	/*
 	 * Data abort handling
 	 */
-	mrs	x0, far_el1
+	mrs	x3, far_el1
 	enable_dbg
 	// re-enable interrupts if they were enabled in the aborted context
 	tbnz	x23, #7, 1f			// PSR_I_BIT
 	enable_irq
 1:
+	clear_address_tag x0, x3
 	mov	x2, sp				// struct pt_regs
 	bl	do_mem_abort
 
@@ -470,7 +485,7 @@
 	// enable interrupts before calling the main handler
 	enable_dbg_and_irq
 	ct_user_exit
-	bic	x0, x26, #(0xff << 56)
+	clear_address_tag x0, x26
 	mov	x1, x25
 	mov	x2, sp
 	bl	do_mem_abort
@@ -549,7 +564,7 @@
 	mov	x0, sp
 	mov	x1, #BAD_SYNC
 	mov	x2, x25
-	bl	bad_mode
+	bl	bad_el0_sync
 	b	ret_to_user
 ENDPROC(el0_sync)
 
@@ -634,6 +649,9 @@
 	bl	do_notify_resume
 	b	ret_to_user
 work_resched:
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off		// the IRQs are off here, inform the tracing code
+#endif
 	bl	schedule
 
 /*
--- linux-4.4.0.orig/arch/arm64/kernel/fpsimd.c
+++ linux-4.4.0/arch/arm64/kernel/fpsimd.c
@@ -157,9 +157,11 @@
 
 void fpsimd_flush_thread(void)
 {
+	preempt_disable();
 	memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
 	fpsimd_flush_task_state(current);
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
+	preempt_enable();
 }
 
 /*
--- linux-4.4.0.orig/arch/arm64/kernel/head.S
+++ linux-4.4.0/arch/arm64/kernel/head.S
@@ -30,6 +30,7 @@
 #include <asm/cache.h>
 #include <asm/cputype.h>
 #include <asm/kernel-pgtable.h>
+#include <asm/kvm_arm.h>
 #include <asm/memory.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
@@ -423,7 +424,8 @@
 	str	xzr, [x6], #8			// Clear BSS
 	b	1b
 2:
-	adr_l	sp, initial_sp, x4
+	adrp	x4, initial_sp
+	add	sp, x4, :lo12:initial_sp
 	str_l	x21, __fdt_pointer, x5		// Save FDT pointer
 	str_l	x24, memstart_addr, x6		// Save PHYS_OFFSET
 	mov	x29, #0
@@ -446,6 +448,7 @@
  * booted in EL1 or EL2 respectively.
  */
 ENTRY(el2_setup)
+	msr	SPsel, #1			// We want to use SP_EL{1,2}
 	mrs	x0, CurrentEL
 	cmp	x0, #CurrentEL_EL2
 	b.ne	1f
@@ -463,7 +466,7 @@
 	ret
 
 	/* Hyp configuration. */
-2:	mov	x0, #(1 << 31)			// 64-bit EL1
+2:	mov_q	x0, HCR_HOST_NVHE_FLAGS
 	msr	hcr_el2, x0
 
 	/* Generic timers. */
@@ -476,8 +479,7 @@
 	/* GICv3 system register access */
 	mrs	x0, id_aa64pfr0_el1
 	ubfx	x0, x0, #24, #4
-	cmp	x0, #1
-	b.ne	3f
+	cbz	x0, 3f
 
 	mrs_s	x0, ICC_SRE_EL2
 	orr	x0, x0, #ICC_SRE_EL2_SRE	// Set ICC_SRE_EL2.SRE==1
@@ -512,9 +514,15 @@
 #endif
 
 	/* EL2 debug */
+	mrs	x0, id_aa64dfr0_el1		// Check ID_AA64DFR0_EL1 PMUVer
+	sbfx	x0, x0, #8, #4
+	cmp	x0, #1
+	b.lt	4f				// Skip if no PMU present
 	mrs	x0, pmcr_el0			// Disable debug access traps
 	ubfx	x0, x0, #11, #5			// to EL2 and allow access to
-	msr	mdcr_el2, x0			// all PMU counters from EL1
+4:
+	csel	x0, xzr, x0, lt			// all PMU counters from EL1
+	msr	mdcr_el2, x0			// (if they exist)
 
 	/* Stage-2 translation */
 	msr	vttbr_el2, xzr
--- linux-4.4.0.orig/arch/arm64/kernel/hw_breakpoint.c
+++ linux-4.4.0/arch/arm64/kernel/hw_breakpoint.c
@@ -35,6 +35,7 @@
 #include <asm/traps.h>
 #include <asm/cputype.h>
 #include <asm/system_misc.h>
+#include <asm/uaccess.h>
 
 /* Breakpoint currently in use for each BRP. */
 static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
@@ -503,13 +504,14 @@
 			/* Aligned */
 			break;
 		case 1:
-			/* Allow single byte watchpoint. */
-			if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
-				break;
 		case 2:
 			/* Allow halfword watchpoints and breakpoints. */
 			if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
 				break;
+		case 3:
+			/* Allow single byte watchpoint. */
+			if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
+				break;
 		default:
 			return -EINVAL;
 		}
@@ -690,7 +692,7 @@
 
 		/* Check if the watchpoint value matches. */
 		val = read_wb_reg(AARCH64_DBG_REG_WVR, i);
-		if (val != (addr & ~alignment_mask))
+		if (val != (untagged_addr(addr) & ~alignment_mask))
 			goto unlock;
 
 		/* Possible match, check the byte address select to confirm. */
--- linux-4.4.0.orig/arch/arm64/kernel/hyp-stub.S
+++ linux-4.4.0/arch/arm64/kernel/hyp-stub.S
@@ -26,6 +26,8 @@
 #include <asm/virt.h>
 
 	.text
+	.pushsection	.hyp.text, "ax"
+
 	.align 11
 
 ENTRY(__hyp_stub_vectors)
--- linux-4.4.0.orig/arch/arm64/kernel/image.h
+++ linux-4.4.0/arch/arm64/kernel/image.h
@@ -65,6 +65,16 @@
 #ifdef CONFIG_EFI
 
 /*
+ * Prevent the symbol aliases below from being emitted into the kallsyms
+ * table, by forcing them to be absolute symbols (which are conveniently
+ * ignored by scripts/kallsyms) rather than section relative symbols.
+ * The distinction is only relevant for partial linking, and only for symbols
+ * that are defined within a section declaration (which is not the case for
+ * the definitions below) so the resulting values will be identical.
+ */
+#define KALLSYMS_HIDE(sym)	ABSOLUTE(sym)
+
+/*
  * The EFI stub has its own symbol namespace prefixed by __efistub_, to
  * isolate it from the kernel proper. The following symbols are legally
  * accessed by the stub, so provide some aliases to make them accessible.
@@ -73,25 +83,25 @@
  * linked at. The routines below are all implemented in assembler in a
  * position independent manner
  */
-__efistub_memcmp		= __pi_memcmp;
-__efistub_memchr		= __pi_memchr;
-__efistub_memcpy		= __pi_memcpy;
-__efistub_memmove		= __pi_memmove;
-__efistub_memset		= __pi_memset;
-__efistub_strlen		= __pi_strlen;
-__efistub_strcmp		= __pi_strcmp;
-__efistub_strncmp		= __pi_strncmp;
-__efistub___flush_dcache_area	= __pi___flush_dcache_area;
+__efistub_memcmp		= KALLSYMS_HIDE(__pi_memcmp);
+__efistub_memchr		= KALLSYMS_HIDE(__pi_memchr);
+__efistub_memcpy		= KALLSYMS_HIDE(__pi_memcpy);
+__efistub_memmove		= KALLSYMS_HIDE(__pi_memmove);
+__efistub_memset		= KALLSYMS_HIDE(__pi_memset);
+__efistub_strlen		= KALLSYMS_HIDE(__pi_strlen);
+__efistub_strcmp		= KALLSYMS_HIDE(__pi_strcmp);
+__efistub_strncmp		= KALLSYMS_HIDE(__pi_strncmp);
+__efistub___flush_dcache_area	= KALLSYMS_HIDE(__pi___flush_dcache_area);
 
 #ifdef CONFIG_KASAN
-__efistub___memcpy		= __pi_memcpy;
-__efistub___memmove		= __pi_memmove;
-__efistub___memset		= __pi_memset;
+__efistub___memcpy		= KALLSYMS_HIDE(__pi_memcpy);
+__efistub___memmove		= KALLSYMS_HIDE(__pi_memmove);
+__efistub___memset		= KALLSYMS_HIDE(__pi_memset);
 #endif
 
-__efistub__text			= _text;
-__efistub__end			= _end;
-__efistub__edata		= _edata;
+__efistub__text			= KALLSYMS_HIDE(_text);
+__efistub__end			= KALLSYMS_HIDE(_end);
+__efistub__edata		= KALLSYMS_HIDE(_edata);
 
 #endif
 
--- linux-4.4.0.orig/arch/arm64/kernel/kgdb.c
+++ linux-4.4.0/arch/arm64/kernel/kgdb.c
@@ -215,22 +215,31 @@
 
 static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
+	if (user_mode(regs))
+		return DBG_HOOK_ERROR;
+
 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
-	return 0;
+	return DBG_HOOK_HANDLED;
 }
 
 static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
+	if (user_mode(regs))
+		return DBG_HOOK_ERROR;
+
 	compiled_break = 1;
 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
 
-	return 0;
+	return DBG_HOOK_HANDLED;
 }
 
 static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
-	kgdb_handle_exception(1, SIGTRAP, 0, regs);
-	return 0;
+	if (user_mode(regs))
+		return DBG_HOOK_ERROR;
+
+	kgdb_handle_exception(0, SIGTRAP, 0, regs);
+	return DBG_HOOK_HANDLED;
 }
 
 static struct break_hook kgdb_brkpt_hook = {
--- linux-4.4.0.orig/arch/arm64/kernel/pci.c
+++ linux-4.4.0/arch/arm64/kernel/pci.c
@@ -17,6 +17,9 @@
 #include <linux/mm.h>
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/pci-acpi.h>
+#include <linux/pci-ecam.h>
 #include <linux/slab.h>
 
 #include <asm/pci-bridge.h>
@@ -52,11 +55,16 @@
 }
 
 /*
- * Try to assign the IRQ number from DT when adding a new device
+ * Try to assign the IRQ number when probing a new device
  */
-int pcibios_add_device(struct pci_dev *dev)
+int pcibios_alloc_irq(struct pci_dev *dev)
 {
-	dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+	if (acpi_disabled)
+		dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+#ifdef CONFIG_ACPI
+	else
+		return acpi_pci_irq_enable(dev);
+#endif
 
 	return 0;
 }
@@ -76,11 +84,135 @@
 	return -ENXIO;
 }
 
+#ifdef CONFIG_NUMA
+
+int pcibus_to_node(struct pci_bus *bus)
+{
+	return dev_to_node(&bus->dev);
+}
+EXPORT_SYMBOL(pcibus_to_node);
+
+#endif
+
 #ifdef CONFIG_ACPI
-/* Root bridge scanning */
+
+struct acpi_pci_generic_root_info {
+	struct acpi_pci_root_info	common;
+	struct pci_config_window	*cfg;	/* config space mapping */
+};
+
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+{
+	struct pci_config_window *cfg = bus->sysdata;
+	struct acpi_device *adev = to_acpi_device(cfg->parent);
+	struct acpi_pci_root *root = acpi_driver_data(adev);
+
+	return root->segment;
+}
+
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+	if (!acpi_disabled) {
+		struct pci_config_window *cfg = bridge->bus->sysdata;
+		struct acpi_device *adev = to_acpi_device(cfg->parent);
+		ACPI_COMPANION_SET(&bridge->dev, adev);
+	}
+
+	return 0;
+}
+
+/*
+ * Lookup the bus range for the domain in MCFG, and set up config space
+ * mapping.
+ */
+static struct pci_config_window *
+pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
+{
+	struct resource *bus_res = &root->secondary;
+	u16 seg = root->segment;
+	struct pci_config_window *cfg;
+	struct resource cfgres;
+	unsigned int bsz;
+
+	/* Use address from _CBA if present, otherwise lookup MCFG */
+	if (!root->mcfg_addr)
+		root->mcfg_addr = pci_mcfg_lookup(seg, bus_res);
+
+	if (!root->mcfg_addr) {
+		dev_err(&root->device->dev, "%04x:%pR ECAM region not found\n",
+			seg, bus_res);
+		return NULL;
+	}
+
+	bsz = 1 << pci_generic_ecam_ops.bus_shift;
+	cfgres.start = root->mcfg_addr + bus_res->start * bsz;
+	cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1;
+	cfgres.flags = IORESOURCE_MEM;
+	cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res,
+			      &pci_generic_ecam_ops);
+	if (IS_ERR(cfg)) {
+		dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n",
+			seg, bus_res, PTR_ERR(cfg));
+		return NULL;
+	}
+
+	return cfg;
+}
+
+/* release_info: free resources allocated by init_info */
+static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
+{
+	struct acpi_pci_generic_root_info *ri;
+
+	ri = container_of(ci, struct acpi_pci_generic_root_info, common);
+	pci_ecam_free(ri->cfg);
+	kfree(ri);
+}
+
+static struct acpi_pci_root_ops acpi_pci_root_ops = {
+	.release_info = pci_acpi_generic_release_info,
+};
+
+/* Interface called from ACPI code to setup PCI host controller */
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-	/* TODO: Should be revisited when implementing PCI on ACPI */
-	return NULL;
+	int node = acpi_get_node(root->device->handle);
+	struct acpi_pci_generic_root_info *ri;
+	struct pci_bus *bus, *child;
+
+	ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node);
+	if (!ri)
+		return NULL;
+
+	ri->cfg = pci_acpi_setup_ecam_mapping(root);
+	if (!ri->cfg) {
+		kfree(ri);
+		return NULL;
+	}
+
+	acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops;
+	bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common,
+				   ri->cfg);
+	if (!bus)
+		return NULL;
+
+	pci_bus_size_bridges(bus);
+	pci_bus_assign_resources(bus);
+
+	list_for_each_entry(child, &bus->children, node)
+		pcie_bus_configure_settings(child);
+
+	return bus;
+}
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+	acpi_pci_add_bus(bus);
 }
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+	acpi_pci_remove_bus(bus);
+}
+
 #endif
--- linux-4.4.0.orig/arch/arm64/kernel/perf_event.c
+++ linux-4.4.0/arch/arm64/kernel/perf_event.c
@@ -29,60 +29,83 @@
  * ARMv8 PMUv3 Performance Events handling code.
  * Common event types.
  */
-enum armv8_pmuv3_perf_types {
-	/* Required events. */
-	ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR			= 0x00,
-	ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL			= 0x03,
-	ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS			= 0x04,
-	ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED			= 0x10,
-	ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES			= 0x11,
-	ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED			= 0x12,
-
-	/* At least one of the following is required. */
-	ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED			= 0x08,
-	ARMV8_PMUV3_PERFCTR_OP_SPEC				= 0x1B,
-
-	/* Common architectural events. */
-	ARMV8_PMUV3_PERFCTR_MEM_READ				= 0x06,
-	ARMV8_PMUV3_PERFCTR_MEM_WRITE				= 0x07,
-	ARMV8_PMUV3_PERFCTR_EXC_TAKEN				= 0x09,
-	ARMV8_PMUV3_PERFCTR_EXC_EXECUTED			= 0x0A,
-	ARMV8_PMUV3_PERFCTR_CID_WRITE				= 0x0B,
-	ARMV8_PMUV3_PERFCTR_PC_WRITE				= 0x0C,
-	ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH			= 0x0D,
-	ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN			= 0x0E,
-	ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS		= 0x0F,
-	ARMV8_PMUV3_PERFCTR_TTBR_WRITE				= 0x1C,
-
-	/* Common microarchitectural events. */
-	ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL			= 0x01,
-	ARMV8_PMUV3_PERFCTR_ITLB_REFILL				= 0x02,
-	ARMV8_PMUV3_PERFCTR_DTLB_REFILL				= 0x05,
-	ARMV8_PMUV3_PERFCTR_MEM_ACCESS				= 0x13,
-	ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS			= 0x14,
-	ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB			= 0x15,
-	ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS			= 0x16,
-	ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL			= 0x17,
-	ARMV8_PMUV3_PERFCTR_L2_CACHE_WB				= 0x18,
-	ARMV8_PMUV3_PERFCTR_BUS_ACCESS				= 0x19,
-	ARMV8_PMUV3_PERFCTR_MEM_ERROR				= 0x1A,
-	ARMV8_PMUV3_PERFCTR_BUS_CYCLES				= 0x1D,
-};
+
+/* Required events. */
+#define ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR			0x00
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL			0x03
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS			0x04
+#define ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED			0x10
+#define ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES			0x11
+#define ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED			0x12
+
+/* At least one of the following is required. */
+#define ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED			0x08
+#define ARMV8_PMUV3_PERFCTR_OP_SPEC				0x1B
+
+/* Common architectural events. */
+#define ARMV8_PMUV3_PERFCTR_MEM_READ				0x06
+#define ARMV8_PMUV3_PERFCTR_MEM_WRITE				0x07
+#define ARMV8_PMUV3_PERFCTR_EXC_TAKEN				0x09
+#define ARMV8_PMUV3_PERFCTR_EXC_EXECUTED			0x0A
+#define ARMV8_PMUV3_PERFCTR_CID_WRITE				0x0B
+#define ARMV8_PMUV3_PERFCTR_PC_WRITE				0x0C
+#define ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH			0x0D
+#define ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN			0x0E
+#define ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS		0x0F
+#define ARMV8_PMUV3_PERFCTR_TTBR_WRITE				0x1C
+#define ARMV8_PMUV3_PERFCTR_CHAIN				0x1E
+#define ARMV8_PMUV3_PERFCTR_BR_RETIRED				0x21
+
+/* Common microarchitectural events. */
+#define ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL			0x01
+#define ARMV8_PMUV3_PERFCTR_ITLB_REFILL				0x02
+#define ARMV8_PMUV3_PERFCTR_DTLB_REFILL				0x05
+#define ARMV8_PMUV3_PERFCTR_MEM_ACCESS				0x13
+#define ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS			0x14
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB			0x15
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS			0x16
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL			0x17
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_WB				0x18
+#define ARMV8_PMUV3_PERFCTR_BUS_ACCESS				0x19
+#define ARMV8_PMUV3_PERFCTR_MEM_ERROR				0x1A
+#define ARMV8_PMUV3_PERFCTR_BUS_CYCLES				0x1D
+#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE			0x1F
+#define ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE			0x20
+#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED			0x22
+#define ARMV8_PMUV3_PERFCTR_STALL_FRONTEND			0x23
+#define ARMV8_PMUV3_PERFCTR_STALL_BACKEND			0x24
+#define ARMV8_PMUV3_PERFCTR_L1D_TLB				0x25
+#define ARMV8_PMUV3_PERFCTR_L1I_TLB				0x26
+#define ARMV8_PMUV3_PERFCTR_L2I_CACHE				0x27
+#define ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL			0x28
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE			0x29
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL			0x2A
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE				0x2B
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB			0x2C
+#define ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL			0x2D
+#define ARMV8_PMUV3_PERFCTR_L21_TLB_REFILL			0x2E
+#define ARMV8_PMUV3_PERFCTR_L2D_TLB				0x2F
+#define ARMV8_PMUV3_PERFCTR_L21_TLB				0x30
+
+/* ARMv8 implementation defined event types. */
+#define ARMV8_IMPDEF_PERFCTR_L1_DCACHE_ACCESS_LD		0x40
+#define ARMV8_IMPDEF_PERFCTR_L1_DCACHE_ACCESS_ST		0x41
+#define ARMV8_IMPDEF_PERFCTR_L1_DCACHE_REFILL_LD		0x42
+#define ARMV8_IMPDEF_PERFCTR_L1_DCACHE_REFILL_ST		0x43
+#define ARMV8_IMPDEF_PERFCTR_DTLB_REFILL_LD			0x4C
+#define ARMV8_IMPDEF_PERFCTR_DTLB_REFILL_ST			0x4D
+#define ARMV8_IMPDEF_PERFCTR_DTLB_ACCESS_LD			0x4E
+#define ARMV8_IMPDEF_PERFCTR_DTLB_ACCESS_ST			0x4F
 
 /* ARMv8 Cortex-A53 specific event types. */
-enum armv8_a53_pmu_perf_types {
-	ARMV8_A53_PERFCTR_PREFETCH_LINEFILL			= 0xC2,
-};
+#define ARMV8_A53_PERFCTR_PREFETCH_LINEFILL			0xC2
 
-/* ARMv8 Cortex-A57 specific event types. */
-enum armv8_a57_perf_types {
-	ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_LD			= 0x40,
-	ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_ST			= 0x41,
-	ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_LD			= 0x42,
-	ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_ST			= 0x43,
-	ARMV8_A57_PERFCTR_DTLB_REFILL_LD			= 0x4c,
-	ARMV8_A57_PERFCTR_DTLB_REFILL_ST			= 0x4d,
-};
+/* ARMv8 Cavium ThunderX specific event types. */
+#define ARMV8_THUNDER_PERFCTR_L1_DCACHE_MISS_ST			0xE9
+#define ARMV8_THUNDER_PERFCTR_L1_DCACHE_PREF_ACCESS		0xEA
+#define ARMV8_THUNDER_PERFCTR_L1_DCACHE_PREF_MISS		0xEB
+#define ARMV8_THUNDER_PERFCTR_L1_ICACHE_PREF_ACCESS		0xEC
+#define ARMV8_THUNDER_PERFCTR_L1_ICACHE_PREF_MISS		0xED
 
 /* PMUv3 HW events mapping. */
 static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
@@ -116,6 +139,18 @@
 	[PERF_COUNT_HW_BUS_CYCLES]		= ARMV8_PMUV3_PERFCTR_BUS_CYCLES,
 };
 
+static const unsigned armv8_thunder_perf_map[PERF_COUNT_HW_MAX] = {
+	PERF_MAP_ALL_UNSUPPORTED,
+	[PERF_COUNT_HW_CPU_CYCLES]		= ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES,
+	[PERF_COUNT_HW_INSTRUCTIONS]		= ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED,
+	[PERF_COUNT_HW_CACHE_REFERENCES]	= ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS,
+	[PERF_COUNT_HW_CACHE_MISSES]		= ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= ARMV8_PMUV3_PERFCTR_PC_WRITE,
+	[PERF_COUNT_HW_BRANCH_MISSES]		= ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
+	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = ARMV8_PMUV3_PERFCTR_STALL_FRONTEND,
+	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= ARMV8_PMUV3_PERFCTR_STALL_BACKEND,
+};
+
 static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 						[PERF_COUNT_HW_CACHE_OP_MAX]
 						[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
@@ -159,16 +194,46 @@
 					      [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	PERF_CACHE_MAP_ALL_UNSUPPORTED,
 
-	[C(L1D)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_LD,
-	[C(L1D)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_LD,
-	[C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)]	= ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_ST,
-	[C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_ST,
+	[C(L1D)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_IMPDEF_PERFCTR_L1_DCACHE_ACCESS_LD,
+	[C(L1D)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_IMPDEF_PERFCTR_L1_DCACHE_REFILL_LD,
+	[C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)]	= ARMV8_IMPDEF_PERFCTR_L1_DCACHE_ACCESS_ST,
+	[C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_IMPDEF_PERFCTR_L1_DCACHE_REFILL_ST,
+
+	[C(L1I)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS,
+	[C(L1I)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL,
+
+	[C(DTLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_IMPDEF_PERFCTR_DTLB_REFILL_LD,
+	[C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_IMPDEF_PERFCTR_DTLB_REFILL_ST,
+
+	[C(ITLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_ITLB_REFILL,
+
+	[C(BPU)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED,
+	[C(BPU)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
+	[C(BPU)][C(OP_WRITE)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED,
+	[C(BPU)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
+};
+
+static const unsigned armv8_thunder_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+						   [PERF_COUNT_HW_CACHE_OP_MAX]
+						   [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+	PERF_CACHE_MAP_ALL_UNSUPPORTED,
+
+	[C(L1D)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_IMPDEF_PERFCTR_L1_DCACHE_ACCESS_LD,
+	[C(L1D)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_IMPDEF_PERFCTR_L1_DCACHE_REFILL_LD,
+	[C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)]	= ARMV8_IMPDEF_PERFCTR_L1_DCACHE_ACCESS_ST,
+	[C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_THUNDER_PERFCTR_L1_DCACHE_MISS_ST,
+	[C(L1D)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = ARMV8_THUNDER_PERFCTR_L1_DCACHE_PREF_ACCESS,
+	[C(L1D)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1_DCACHE_PREF_MISS,
 
 	[C(L1I)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS,
 	[C(L1I)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL,
+	[C(L1I)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = ARMV8_THUNDER_PERFCTR_L1_ICACHE_PREF_ACCESS,
+	[C(L1I)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1_ICACHE_PREF_MISS,
 
-	[C(DTLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_A57_PERFCTR_DTLB_REFILL_LD,
-	[C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_A57_PERFCTR_DTLB_REFILL_ST,
+	[C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_IMPDEF_PERFCTR_DTLB_ACCESS_LD,
+	[C(DTLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_IMPDEF_PERFCTR_DTLB_REFILL_LD,
+	[C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_DTLB_ACCESS_ST,
+	[C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_IMPDEF_PERFCTR_DTLB_REFILL_ST,
 
 	[C(ITLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_ITLB_REFILL,
 
@@ -178,6 +243,136 @@
 	[C(BPU)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
 };
 
+#define ARMV8_EVENT_ATTR_RESOLVE(m) #m
+#define ARMV8_EVENT_ATTR(name, config) \
+	PMU_EVENT_ATTR_STRING(name, armv8_event_attr_##name, \
+			      "event=" ARMV8_EVENT_ATTR_RESOLVE(config))
+
+ARMV8_EVENT_ATTR(sw_incr, ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR);
+ARMV8_EVENT_ATTR(l1i_cache_refill, ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL);
+ARMV8_EVENT_ATTR(l1i_tlb_refill, ARMV8_PMUV3_PERFCTR_ITLB_REFILL);
+ARMV8_EVENT_ATTR(l1d_cache_refill, ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL);
+ARMV8_EVENT_ATTR(l1d_cache, ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS);
+ARMV8_EVENT_ATTR(l1d_tlb_refill, ARMV8_PMUV3_PERFCTR_DTLB_REFILL);
+ARMV8_EVENT_ATTR(ld_retired, ARMV8_PMUV3_PERFCTR_MEM_READ);
+ARMV8_EVENT_ATTR(st_retired, ARMV8_PMUV3_PERFCTR_MEM_WRITE);
+ARMV8_EVENT_ATTR(inst_retired, ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED);
+ARMV8_EVENT_ATTR(exc_taken, ARMV8_PMUV3_PERFCTR_EXC_TAKEN);
+ARMV8_EVENT_ATTR(exc_return, ARMV8_PMUV3_PERFCTR_EXC_EXECUTED);
+ARMV8_EVENT_ATTR(cid_write_retired, ARMV8_PMUV3_PERFCTR_CID_WRITE);
+ARMV8_EVENT_ATTR(pc_write_retired, ARMV8_PMUV3_PERFCTR_PC_WRITE);
+ARMV8_EVENT_ATTR(br_immed_retired, ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH);
+ARMV8_EVENT_ATTR(br_return_retired, ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN);
+ARMV8_EVENT_ATTR(unaligned_ldst_retired, ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS);
+ARMV8_EVENT_ATTR(br_mis_pred, ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED);
+ARMV8_EVENT_ATTR(cpu_cycles, ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES);
+ARMV8_EVENT_ATTR(br_pred, ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED);
+ARMV8_EVENT_ATTR(mem_access, ARMV8_PMUV3_PERFCTR_MEM_ACCESS);
+ARMV8_EVENT_ATTR(l1i_cache, ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS);
+ARMV8_EVENT_ATTR(l1d_cache_wb, ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB);
+ARMV8_EVENT_ATTR(l2d_cache, ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS);
+ARMV8_EVENT_ATTR(l2d_cache_refill, ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l2d_cache_wb, ARMV8_PMUV3_PERFCTR_L2_CACHE_WB);
+ARMV8_EVENT_ATTR(bus_access, ARMV8_PMUV3_PERFCTR_BUS_ACCESS);
+ARMV8_EVENT_ATTR(memory_error, ARMV8_PMUV3_PERFCTR_MEM_ERROR);
+ARMV8_EVENT_ATTR(inst_spec, ARMV8_PMUV3_PERFCTR_OP_SPEC);
+ARMV8_EVENT_ATTR(ttbr_write_retired, ARMV8_PMUV3_PERFCTR_TTBR_WRITE);
+ARMV8_EVENT_ATTR(bus_cycles, ARMV8_PMUV3_PERFCTR_BUS_CYCLES);
+ARMV8_EVENT_ATTR(chain, ARMV8_PMUV3_PERFCTR_CHAIN);
+ARMV8_EVENT_ATTR(l1d_cache_allocate, ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(l2d_cache_allocate, ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(br_retired, ARMV8_PMUV3_PERFCTR_BR_RETIRED);
+ARMV8_EVENT_ATTR(br_mis_pred_retired, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED);
+ARMV8_EVENT_ATTR(stall_frontend, ARMV8_PMUV3_PERFCTR_STALL_FRONTEND);
+ARMV8_EVENT_ATTR(stall_backend, ARMV8_PMUV3_PERFCTR_STALL_BACKEND);
+ARMV8_EVENT_ATTR(l1d_tlb, ARMV8_PMUV3_PERFCTR_L1D_TLB);
+ARMV8_EVENT_ATTR(l1i_tlb, ARMV8_PMUV3_PERFCTR_L1I_TLB);
+ARMV8_EVENT_ATTR(l2i_cache, ARMV8_PMUV3_PERFCTR_L2I_CACHE);
+ARMV8_EVENT_ATTR(l2i_cache_refill, ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l3d_cache_allocate, ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(l3d_cache_refill, ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l3d_cache, ARMV8_PMUV3_PERFCTR_L3D_CACHE);
+ARMV8_EVENT_ATTR(l3d_cache_wb, ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB);
+ARMV8_EVENT_ATTR(l2d_tlb_refill, ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL);
+ARMV8_EVENT_ATTR(l21_tlb_refill, ARMV8_PMUV3_PERFCTR_L21_TLB_REFILL);
+ARMV8_EVENT_ATTR(l2d_tlb, ARMV8_PMUV3_PERFCTR_L2D_TLB);
+ARMV8_EVENT_ATTR(l21_tlb, ARMV8_PMUV3_PERFCTR_L21_TLB);
+
+static struct attribute *armv8_pmuv3_event_attrs[] = {
+	&armv8_event_attr_sw_incr.attr.attr,
+	&armv8_event_attr_l1i_cache_refill.attr.attr,
+	&armv8_event_attr_l1i_tlb_refill.attr.attr,
+	&armv8_event_attr_l1d_cache_refill.attr.attr,
+	&armv8_event_attr_l1d_cache.attr.attr,
+	&armv8_event_attr_l1d_tlb_refill.attr.attr,
+	&armv8_event_attr_ld_retired.attr.attr,
+	&armv8_event_attr_st_retired.attr.attr,
+	&armv8_event_attr_inst_retired.attr.attr,
+	&armv8_event_attr_exc_taken.attr.attr,
+	&armv8_event_attr_exc_return.attr.attr,
+	&armv8_event_attr_cid_write_retired.attr.attr,
+	&armv8_event_attr_pc_write_retired.attr.attr,
+	&armv8_event_attr_br_immed_retired.attr.attr,
+	&armv8_event_attr_br_return_retired.attr.attr,
+	&armv8_event_attr_unaligned_ldst_retired.attr.attr,
+	&armv8_event_attr_br_mis_pred.attr.attr,
+	&armv8_event_attr_cpu_cycles.attr.attr,
+	&armv8_event_attr_br_pred.attr.attr,
+	&armv8_event_attr_mem_access.attr.attr,
+	&armv8_event_attr_l1i_cache.attr.attr,
+	&armv8_event_attr_l1d_cache_wb.attr.attr,
+	&armv8_event_attr_l2d_cache.attr.attr,
+	&armv8_event_attr_l2d_cache_refill.attr.attr,
+	&armv8_event_attr_l2d_cache_wb.attr.attr,
+	&armv8_event_attr_bus_access.attr.attr,
+	&armv8_event_attr_memory_error.attr.attr,
+	&armv8_event_attr_inst_spec.attr.attr,
+	&armv8_event_attr_ttbr_write_retired.attr.attr,
+	&armv8_event_attr_bus_cycles.attr.attr,
+	&armv8_event_attr_chain.attr.attr,
+	&armv8_event_attr_l1d_cache_allocate.attr.attr,
+	&armv8_event_attr_l2d_cache_allocate.attr.attr,
+	&armv8_event_attr_br_retired.attr.attr,
+	&armv8_event_attr_br_mis_pred_retired.attr.attr,
+	&armv8_event_attr_stall_frontend.attr.attr,
+	&armv8_event_attr_stall_backend.attr.attr,
+	&armv8_event_attr_l1d_tlb.attr.attr,
+	&armv8_event_attr_l1i_tlb.attr.attr,
+	&armv8_event_attr_l2i_cache.attr.attr,
+	&armv8_event_attr_l2i_cache_refill.attr.attr,
+	&armv8_event_attr_l3d_cache_allocate.attr.attr,
+	&armv8_event_attr_l3d_cache_refill.attr.attr,
+	&armv8_event_attr_l3d_cache.attr.attr,
+	&armv8_event_attr_l3d_cache_wb.attr.attr,
+	&armv8_event_attr_l2d_tlb_refill.attr.attr,
+	&armv8_event_attr_l21_tlb_refill.attr.attr,
+	&armv8_event_attr_l2d_tlb.attr.attr,
+	&armv8_event_attr_l21_tlb.attr.attr,
+	NULL,
+};
+
+static struct attribute_group armv8_pmuv3_events_attr_group = {
+	.name = "events",
+	.attrs = armv8_pmuv3_event_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-9");
+
+static struct attribute *armv8_pmuv3_format_attrs[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group armv8_pmuv3_format_attr_group = {
+	.name = "format",
+	.attrs = armv8_pmuv3_format_attrs,
+};
+
+static const struct attribute_group *armv8_pmuv3_attr_groups[] = {
+	&armv8_pmuv3_events_attr_group,
+	&armv8_pmuv3_format_attr_group,
+	NULL,
+};
 
 /*
  * Perf Events' indices
@@ -209,6 +404,7 @@
 #define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
 #define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
 #define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
+#define ARMV8_PMCR_LC		(1 << 6) /* Overflow on 64 bit cycle counter */
 #define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
 #define	ARMV8_PMCR_N_MASK	0x1f
 #define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
@@ -222,8 +418,8 @@
 /*
  * PMXEVTYPER: Event selection reg
  */
-#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
-#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
+#define	ARMV8_EVTYPE_MASK	0xc800ffff	/* Mask for writable bits */
+#define	ARMV8_EVTYPE_EVENT	0xffff		/* Mask for EVENT bits */
 
 /*
  * Event filters for PMUv3
@@ -298,9 +494,16 @@
 	if (!armv8pmu_counter_valid(cpu_pmu, idx))
 		pr_err("CPU%u writing wrong counter %d\n",
 			smp_processor_id(), idx);
-	else if (idx == ARMV8_IDX_CYCLE_COUNTER)
-		asm volatile("msr pmccntr_el0, %0" :: "r" (value));
-	else if (armv8pmu_select_counter(idx) == idx)
+	else if (idx == ARMV8_IDX_CYCLE_COUNTER) {
+		/*
+		 * Set the upper 32bits as this is a 64bit counter but we only
+		 * count using the lower 32bits and we want an interrupt when
+		 * it overflows.
+		 */
+		u64 value64 = 0xffffffff00000000ULL | value;
+
+		asm volatile("msr pmccntr_el0, %0" :: "r" (value64));
+	} else if (armv8pmu_select_counter(idx) == idx)
 		asm volatile("msr pmxevcntr_el0, %0" :: "r" (value));
 }
 
@@ -572,11 +775,11 @@
 		armv8pmu_disable_intens(idx);
 	}
 
-	/* Initialize & Reset PMNC: C and P bits. */
-	armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C);
-
-	/* Disable access from userspace. */
-	asm volatile("msr pmuserenr_el0, %0" :: "r" (0));
+	/*
+	 * Initialize & Reset PMNC. Request overflow interrupt for
+	 * 64 bit cycle counter but cheat in armv8pmu_write_counter().
+	 */
+	armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C | ARMV8_PMCR_LC);
 }
 
 static int armv8_pmuv3_map_event(struct perf_event *event)
@@ -600,6 +803,13 @@
 				ARMV8_EVTYPE_EVENT);
 }
 
+static int armv8_thunder_map_event(struct perf_event *event)
+{
+	return armpmu_map_event(event, &armv8_thunder_perf_map,
+				&armv8_thunder_perf_cache_map,
+				ARMV8_EVTYPE_EVENT);
+}
+
 static void armv8pmu_read_num_pmnc_events(void *info)
 {
 	int *nb_cnt = info;
@@ -646,6 +856,7 @@
 	armv8_pmu_init(cpu_pmu);
 	cpu_pmu->name			= "armv8_cortex_a53";
 	cpu_pmu->map_event		= armv8_a53_map_event;
+	cpu_pmu->pmu.attr_groups	= armv8_pmuv3_attr_groups;
 	return armv8pmu_probe_num_events(cpu_pmu);
 }
 
@@ -654,6 +865,16 @@
 	armv8_pmu_init(cpu_pmu);
 	cpu_pmu->name			= "armv8_cortex_a57";
 	cpu_pmu->map_event		= armv8_a57_map_event;
+	cpu_pmu->pmu.attr_groups	= armv8_pmuv3_attr_groups;
+	return armv8pmu_probe_num_events(cpu_pmu);
+}
+
+static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
+{
+	armv8_pmu_init(cpu_pmu);
+	cpu_pmu->name			= "armv8_cavium_thunder";
+	cpu_pmu->map_event		= armv8_thunder_map_event;
+	cpu_pmu->pmu.attr_groups	= armv8_pmuv3_attr_groups;
 	return armv8pmu_probe_num_events(cpu_pmu);
 }
 
@@ -661,6 +882,7 @@
 	{.compatible = "arm,armv8-pmuv3",	.data = armv8_pmuv3_init},
 	{.compatible = "arm,cortex-a53-pmu",	.data = armv8_a53_pmu_init},
 	{.compatible = "arm,cortex-a57-pmu",	.data = armv8_a57_pmu_init},
+	{.compatible = "cavium,thunder-pmu",	.data = armv8_thunder_pmu_init},
 	{},
 };
 
@@ -673,6 +895,7 @@
 	.driver		= {
 		.name	= "armv8-pmu",
 		.of_match_table = armv8_pmu_of_device_ids,
+		.suppress_bind_attrs = true,
 	},
 	.probe		= armv8_pmu_device_probe,
 };
--- linux-4.4.0.orig/arch/arm64/kernel/perf_regs.c
+++ linux-4.4.0/arch/arm64/kernel/perf_regs.c
@@ -13,15 +13,34 @@
 		return 0;
 
 	/*
-	 * Compat (i.e. 32 bit) mode:
-	 * - PC has been set in the pt_regs struct in kernel_entry,
-	 * - Handle SP and LR here.
+	 * Our handling of compat tasks (PERF_SAMPLE_REGS_ABI_32) is weird, but
+	 * we're stuck with it for ABI compatability reasons.
+	 *
+	 * For a 32-bit consumer inspecting a 32-bit task, then it will look at
+	 * the first 16 registers (see arch/arm/include/uapi/asm/perf_regs.h).
+	 * These correspond directly to a prefix of the registers saved in our
+	 * 'struct pt_regs', with the exception of the PC, so we copy that down
+	 * (x15 corresponds to SP_hyp in the architecture).
+	 *
+	 * So far, so good.
+	 *
+	 * The oddity arises when a 64-bit consumer looks at a 32-bit task and
+	 * asks for registers beyond PERF_REG_ARM_MAX. In this case, we return
+	 * SP_usr, LR_usr and PC in the positions where the AArch64 SP, LR and
+	 * PC registers would normally live. The initial idea was to allow a
+	 * 64-bit unwinder to unwind a 32-bit task and, although it's not clear
+	 * how well that works in practice, somebody might be relying on it.
+	 *
+	 * At the time we make a sample, we don't know whether the consumer is
+	 * 32-bit or 64-bit, so we have to cater for both possibilities.
 	 */
 	if (compat_user_mode(regs)) {
 		if ((u32)idx == PERF_REG_ARM64_SP)
 			return regs->compat_sp;
 		if ((u32)idx == PERF_REG_ARM64_LR)
 			return regs->compat_lr;
+		if (idx == 15)
+			return regs->pc;
 	}
 
 	if ((u32)idx == PERF_REG_ARM64_SP)
--- linux-4.4.0.orig/arch/arm64/kernel/process.c
+++ linux-4.4.0/arch/arm64/kernel/process.c
@@ -251,6 +251,15 @@
 
 	memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
 
+	/*
+	 * In case p was allocated the same task_struct pointer as some
+	 * other recently-exited task, make sure p is disassociated from
+	 * any cpu that may have run that now-exited task recently.
+	 * Otherwise we could erroneously skip reloading the FPSIMD
+	 * registers for p.
+	 */
+	fpsimd_flush_task_state(p);
+
 	if (likely(!(p->flags & PF_KTHREAD))) {
 		*childregs = *current_pt_regs();
 		childregs->regs[0] = 0;
--- linux-4.4.0.orig/arch/arm64/kernel/psci.c
+++ linux-4.4.0/arch/arm64/kernel/psci.c
@@ -136,7 +136,6 @@
 
 static void cpu_psci_cpu_die(unsigned int cpu)
 {
-	int ret;
 	/*
 	 * There are no known implementations of PSCI actually using the
 	 * power state field, pass a sensible default for now.
@@ -144,14 +143,13 @@
 	u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN <<
 		    PSCI_0_2_POWER_STATE_TYPE_SHIFT;
 
-	ret = psci_ops.cpu_off(state);
-
-	pr_crit("unable to power off CPU%u (%d)\n", cpu, ret);
+	psci_ops.cpu_off(state);
 }
 
 static int cpu_psci_cpu_kill(unsigned int cpu)
 {
-	int err, i;
+	int err;
+	unsigned long start, end;
 
 	if (!psci_ops.affinity_info)
 		return 0;
@@ -161,16 +159,18 @@
 	 * while it is dying. So, try again a few times.
 	 */
 
-	for (i = 0; i < 10; i++) {
+	start = jiffies;
+	end = start + msecs_to_jiffies(100);
+	do {
 		err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
 		if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {
-			pr_info("CPU%d killed.\n", cpu);
+			pr_info("CPU%d killed (polled %d ms)\n", cpu,
+				jiffies_to_msecs(jiffies - start));
 			return 0;
 		}
 
-		msleep(10);
-		pr_info("Retrying again to check for CPU kill\n");
-	}
+		usleep_range(100, 1000);
+	} while (time_before(jiffies, end));
 
 	pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n",
 			cpu, err);
--- linux-4.4.0.orig/arch/arm64/kernel/ptrace.c
+++ linux-4.4.0/arch/arm64/kernel/ptrace.c
@@ -24,6 +24,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/nospec.h>
 #include <linux/smp.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
@@ -39,6 +40,7 @@
 #include <linux/elf.h>
 
 #include <asm/compat.h>
+#include <asm/cpufeature.h>
 #include <asm/debug-monitors.h>
 #include <asm/pgtable.h>
 #include <asm/syscall.h>
@@ -58,6 +60,12 @@
  */
 void ptrace_disable(struct task_struct *child)
 {
+	/*
+	 * This would be better off in core code, but PTRACE_DETACH has
+	 * grown its fair share of arch-specific worts and changing it
+	 * is likely to cause regressions on obscure architectures.
+	 */
+	user_disable_single_step(child);
 }
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
@@ -138,15 +146,20 @@
 
 	switch (note_type) {
 	case NT_ARM_HW_BREAK:
-		if (idx < ARM_MAX_BRP)
-			bp = tsk->thread.debug.hbp_break[idx];
+		if (idx >= ARM_MAX_BRP)
+			goto out;
+		idx = array_index_nospec(idx, ARM_MAX_BRP);
+		bp = tsk->thread.debug.hbp_break[idx];
 		break;
 	case NT_ARM_HW_WATCH:
-		if (idx < ARM_MAX_WRP)
-			bp = tsk->thread.debug.hbp_watch[idx];
+		if (idx >= ARM_MAX_WRP)
+			goto out;
+		idx = array_index_nospec(idx, ARM_MAX_WRP);
+		bp = tsk->thread.debug.hbp_watch[idx];
 		break;
 	}
 
+out:
 	return bp;
 }
 
@@ -159,19 +172,22 @@
 
 	switch (note_type) {
 	case NT_ARM_HW_BREAK:
-		if (idx < ARM_MAX_BRP) {
-			tsk->thread.debug.hbp_break[idx] = bp;
-			err = 0;
-		}
+		if (idx >= ARM_MAX_BRP)
+			goto out;
+		idx = array_index_nospec(idx, ARM_MAX_BRP);
+		tsk->thread.debug.hbp_break[idx] = bp;
+		err = 0;
 		break;
 	case NT_ARM_HW_WATCH:
-		if (idx < ARM_MAX_WRP) {
-			tsk->thread.debug.hbp_watch[idx] = bp;
-			err = 0;
-		}
+		if (idx >= ARM_MAX_WRP)
+			goto out;
+		idx = array_index_nospec(idx, ARM_MAX_WRP);
+		tsk->thread.debug.hbp_watch[idx] = bp;
+		err = 0;
 		break;
 	}
 
+out:
 	return err;
 }
 
@@ -443,6 +459,8 @@
 	/* (address, ctrl) registers */
 	limit = regset->n * regset->size;
 	while (count && offset < limit) {
+		if (count < PTRACE_HBP_ADDR_SZ)
+			return -EINVAL;
 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
 					 offset, offset + PTRACE_HBP_ADDR_SZ);
 		if (ret)
@@ -452,6 +470,8 @@
 			return ret;
 		offset += PTRACE_HBP_ADDR_SZ;
 
+		if (!count)
+			break;
 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl,
 					 offset, offset + PTRACE_HBP_CTRL_SZ);
 		if (ret)
@@ -488,13 +508,13 @@
 		   const void *kbuf, const void __user *ubuf)
 {
 	int ret;
-	struct user_pt_regs newregs;
+	struct user_pt_regs newregs = task_pt_regs(target)->user_regs;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
 	if (ret)
 		return ret;
 
-	if (!valid_user_regs(&newregs))
+	if (!valid_user_regs(&newregs, target))
 		return -EINVAL;
 
 	task_pt_regs(target)->user_regs = newregs;
@@ -518,7 +538,8 @@
 		   const void *kbuf, const void __user *ubuf)
 {
 	int ret;
-	struct user_fpsimd_state newstate;
+	struct user_fpsimd_state newstate =
+		target->thread.fpsimd_state.user_fpsimd;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
 	if (ret)
@@ -542,7 +563,7 @@
 		   const void *kbuf, const void __user *ubuf)
 {
 	int ret;
-	unsigned long tls;
+	unsigned long tls = target->thread.tp_value;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
 	if (ret)
@@ -568,7 +589,8 @@
 			   unsigned int pos, unsigned int count,
 			   const void *kbuf, const void __user *ubuf)
 {
-	int syscallno, ret;
+	int syscallno = task_pt_regs(target)->syscallno;
+	int ret;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &syscallno, 0, -1);
 	if (ret)
@@ -764,7 +786,7 @@
 
 	}
 
-	if (valid_user_regs(&newregs.user_regs))
+	if (valid_user_regs(&newregs.user_regs, target))
 		*task_pt_regs(target) = newregs;
 	else
 		ret = -EINVAL;
@@ -840,7 +862,7 @@
 			  const void __user *ubuf)
 {
 	int ret;
-	compat_ulong_t tls;
+	compat_ulong_t tls = target->thread.tp_value;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
 	if (ret)
@@ -1266,3 +1288,79 @@
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
 		tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
 }
+
+/*
+ * Bits which are always architecturally RES0 per ARM DDI 0487A.h
+ * Userspace cannot use these until they have an architectural meaning.
+ * We also reserve IL for the kernel; SS is handled dynamically.
+ */
+#define SPSR_EL1_AARCH64_RES0_BITS \
+	(GENMASK_ULL(63,32) | GENMASK_ULL(27, 22) | GENMASK_ULL(20, 10) | \
+	 GENMASK_ULL(5, 5))
+#define SPSR_EL1_AARCH32_RES0_BITS \
+	(GENMASK_ULL(63,32) | GENMASK_ULL(24, 22) | GENMASK_ULL(20,20))
+
+static int valid_compat_regs(struct user_pt_regs *regs)
+{
+	regs->pstate &= ~SPSR_EL1_AARCH32_RES0_BITS;
+
+	if (!system_supports_mixed_endian_el0()) {
+		if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+			regs->pstate |= COMPAT_PSR_E_BIT;
+		else
+			regs->pstate &= ~COMPAT_PSR_E_BIT;
+	}
+
+	if (user_mode(regs) && (regs->pstate & PSR_MODE32_BIT) &&
+	    (regs->pstate & COMPAT_PSR_A_BIT) == 0 &&
+	    (regs->pstate & COMPAT_PSR_I_BIT) == 0 &&
+	    (regs->pstate & COMPAT_PSR_F_BIT) == 0) {
+		return 1;
+	}
+
+	/*
+	 * Force PSR to a valid 32-bit EL0t, preserving the same bits as
+	 * arch/arm.
+	 */
+	regs->pstate &= COMPAT_PSR_N_BIT | COMPAT_PSR_Z_BIT |
+			COMPAT_PSR_C_BIT | COMPAT_PSR_V_BIT |
+			COMPAT_PSR_Q_BIT | COMPAT_PSR_IT_MASK |
+			COMPAT_PSR_GE_MASK | COMPAT_PSR_E_BIT |
+			COMPAT_PSR_T_BIT;
+	regs->pstate |= PSR_MODE32_BIT;
+
+	return 0;
+}
+
+static int valid_native_regs(struct user_pt_regs *regs)
+{
+	regs->pstate &= ~SPSR_EL1_AARCH64_RES0_BITS;
+
+	if (user_mode(regs) && !(regs->pstate & PSR_MODE32_BIT) &&
+	    (regs->pstate & PSR_D_BIT) == 0 &&
+	    (regs->pstate & PSR_A_BIT) == 0 &&
+	    (regs->pstate & PSR_I_BIT) == 0 &&
+	    (regs->pstate & PSR_F_BIT) == 0) {
+		return 1;
+	}
+
+	/* Force PSR to a valid 64-bit EL0t */
+	regs->pstate &= PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT;
+
+	return 0;
+}
+
+/*
+ * Are the current registers suitable for user mode? (used to maintain
+ * security in signal handlers)
+ */
+int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task)
+{
+	if (!test_tsk_thread_flag(task, TIF_SINGLESTEP))
+		regs->pstate &= ~DBG_SPSR_SS;
+
+	if (is_compat_thread(task_thread_info(task)))
+		return valid_compat_regs(regs);
+	else
+		return valid_native_regs(regs);
+}
--- linux-4.4.0.orig/arch/arm64/kernel/setup.c
+++ linux-4.4.0/arch/arm64/kernel/setup.c
@@ -53,6 +53,7 @@
 #include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
 #include <asm/kasan.h>
+#include <asm/numa.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/smp_plat.h>
@@ -319,7 +320,13 @@
 	/* Parse the ACPI tables for possible boot-time configuration */
 	acpi_boot_table_init();
 
-	paging_init();
+	paging_init_map_mem();
+
+	if (acpi_disabled)
+		unflatten_device_tree();
+
+	paging_init_rest();
+
 	relocate_initrd();
 
 	kasan_init();
@@ -328,12 +335,11 @@
 
 	early_ioremap_reset();
 
-	if (acpi_disabled) {
-		unflatten_device_tree();
+	if (acpi_disabled)
 		psci_dt_init();
-	} else {
+	else
 		psci_acpi_init();
-	}
+
 	xen_early_init();
 
 	cpu_read_bootcpu_ops();
@@ -372,6 +378,9 @@
 {
 	int i;
 
+	for_each_online_node(i)
+		register_one_node(i);
+
 	for_each_possible_cpu(i) {
 		struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
 		cpu->hotpluggable = 1;
--- linux-4.4.0.orig/arch/arm64/kernel/signal.c
+++ linux-4.4.0/arch/arm64/kernel/signal.c
@@ -115,7 +115,7 @@
 	 */
 	regs->syscallno = ~0UL;
 
-	err |= !valid_user_regs(&regs->user_regs);
+	err |= !valid_user_regs(&regs->user_regs, current);
 
 	if (err == 0) {
 		struct fpsimd_context *fpsimd_ctx =
@@ -307,7 +307,7 @@
 	/*
 	 * Check that the resulting registers are actually sane.
 	 */
-	ret |= !valid_user_regs(&regs->user_regs);
+	ret |= !valid_user_regs(&regs->user_regs, current);
 
 	/*
 	 * Fast forward the stepping logic so we step into the signal
--- linux-4.4.0.orig/arch/arm64/kernel/signal32.c
+++ linux-4.4.0/arch/arm64/kernel/signal32.c
@@ -356,7 +356,7 @@
 	 */
 	regs->syscallno = ~0UL;
 
-	err |= !valid_user_regs(&regs->user_regs);
+	err |= !valid_user_regs(&regs->user_regs, current);
 
 	aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace;
 	if (err == 0)
--- linux-4.4.0.orig/arch/arm64/kernel/smccc-call.S
+++ linux-4.4.0/arch/arm64/kernel/smccc-call.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+
+	.macro SMCCC instr
+	.cfi_startproc
+	\instr	#0
+	ldr	x4, [sp]
+	stp	x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
+	stp	x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
+	ret
+	.cfi_endproc
+	.endm
+
+/*
+ * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
+ *		  unsigned long a3, unsigned long a4, unsigned long a5,
+ *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_smc)
+	SMCCC	smc
+ENDPROC(arm_smccc_smc)
+
+/*
+ * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
+ *		  unsigned long a3, unsigned long a4, unsigned long a5,
+ *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_hvc)
+	SMCCC	hvc
+ENDPROC(arm_smccc_hvc)
--- linux-4.4.0.orig/arch/arm64/kernel/smp.c
+++ linux-4.4.0/arch/arm64/kernel/smp.c
@@ -45,6 +45,7 @@
 #include <asm/cputype.h>
 #include <asm/cpu_ops.h>
 #include <asm/mmu_context.h>
+#include <asm/numa.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
@@ -70,6 +71,7 @@
 	IPI_CPU_STOP,
 	IPI_TIMER,
 	IPI_IRQ_WORK,
+	IPI_WAKEUP
 };
 
 /*
@@ -115,6 +117,7 @@
 		}
 	} else {
 		pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
+		return ret;
 	}
 
 	secondary_data.stack = NULL;
@@ -125,13 +128,14 @@
 static void smp_store_cpu_info(unsigned int cpuid)
 {
 	store_cpu_topology(cpuid);
+	numa_store_cpu_info(cpuid);
 }
 
 /*
  * This is the secondary CPU boot entry.  We're using this CPUs
  * idle thread stack, but a set of temporary page tables.
  */
-asmlinkage void secondary_start_kernel(void)
+asmlinkage notrace void secondary_start_kernel(void)
 {
 	struct mm_struct *mm = &init_mm;
 	unsigned int cpu = smp_processor_id();
@@ -188,7 +192,6 @@
 	set_cpu_online(cpu, true);
 	complete(&cpu_running);
 
-	local_dbg_enable();
 	local_irq_enable();
 	local_async_enable();
 
@@ -334,8 +337,8 @@
 
 void __init smp_prepare_boot_cpu(void)
 {
-	cpuinfo_store_boot_cpu();
 	set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
+	cpuinfo_store_boot_cpu();
 }
 
 static u64 __init of_get_cpu_mpidr(struct device_node *dn)
@@ -445,6 +448,17 @@
 	/* map the logical cpu id to cpu MPIDR */
 	cpu_logical_map(cpu_count) = hwid;
 
+	/*
+	 * Set-up the ACPI parking protocol cpu entries
+	 * while initializing the cpu_logical_map to
+	 * avoid parsing MADT entries multiple times for
+	 * nothing (ie a valid cpu_logical_map entry should
+	 * contain a valid parking protocol data set to
+	 * initialize the cpu if the parking protocol is
+	 * the only available enable method).
+	 */
+	acpi_set_mailbox_entry(cpu_count, processor);
+
 	cpu_count++;
 }
 
@@ -518,6 +532,8 @@
 
 		pr_debug("cpu logical map 0x%llx\n", hwid);
 		cpu_logical_map(cpu_count) = hwid;
+
+		early_map_cpu_to_node(cpu_count, of_node_to_nid(dn));
 next:
 		cpu_count++;
 	}
@@ -627,6 +643,7 @@
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_TIMER, "Timer broadcast interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
+	S(IPI_WAKEUP, "CPU wake-up interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -670,6 +687,13 @@
 	smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC);
 }
 
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_WAKEUP);
+}
+#endif
+
 #ifdef CONFIG_IRQ_WORK
 void arch_irq_work_raise(void)
 {
@@ -747,6 +771,14 @@
 		break;
 #endif
 
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+	case IPI_WAKEUP:
+		WARN_ONCE(!acpi_parking_protocol_valid(cpu),
+			  "CPU%u: Wake-up IPI outside the ACPI parking protocol\n",
+			  cpu);
+		break;
+#endif
+
 	default:
 		pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
 		break;
@@ -769,11 +801,22 @@
 }
 #endif
 
+/*
+ * The number of CPUs online, not counting this CPU (which may not be
+ * fully online and so not counted in num_online_cpus()).
+ */
+static inline unsigned int num_other_online_cpus(void)
+{
+	unsigned int this_cpu_online = cpu_online(smp_processor_id());
+
+	return num_online_cpus() - this_cpu_online;
+}
+
 void smp_send_stop(void)
 {
 	unsigned long timeout;
 
-	if (num_online_cpus() > 1) {
+	if (num_other_online_cpus()) {
 		cpumask_t mask;
 
 		cpumask_copy(&mask, cpu_online_mask);
@@ -784,10 +827,10 @@
 
 	/* Wait up to one second for other CPUs to stop */
 	timeout = USEC_PER_SEC;
-	while (num_online_cpus() > 1 && timeout--)
+	while (num_other_online_cpus() && timeout--)
 		udelay(1);
 
-	if (num_online_cpus() > 1)
+	if (num_other_online_cpus())
 		pr_warning("SMP: failed to stop secondary CPUs\n");
 }
 
--- linux-4.4.0.orig/arch/arm64/kernel/suspend.c
+++ linux-4.4.0/arch/arm64/kernel/suspend.c
@@ -1,7 +1,9 @@
 #include <linux/ftrace.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
+#include <asm/alternative.h>
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #include <asm/debug-monitors.h>
 #include <asm/pgtable.h>
 #include <asm/memory.h>
@@ -111,6 +113,13 @@
 		set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
 
 		/*
+		 * PSTATE was not saved over suspend/resume, re-enable any
+		 * detected features that might not have been set correctly.
+		 */
+		asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,
+				CONFIG_ARM64_PAN));
+
+		/*
 		 * Restore HW breakpoint registers to sane values
 		 * before debug exceptions are possibly reenabled
 		 * through local_dbg_restore.
--- linux-4.4.0.orig/arch/arm64/kernel/traps.c
+++ linux-4.4.0/arch/arm64/kernel/traps.c
@@ -49,7 +49,7 @@
 	"Error"
 };
 
-int show_unhandled_signals = 1;
+int show_unhandled_signals = 0;
 
 /*
  * Dump out the contents of some memory nicely...
@@ -64,8 +64,7 @@
 
 	/*
 	 * We need to switch to kernel mode so that we can use __get_user
-	 * to safely read from kernel space.  Note that we now dump the
-	 * code first, just in case the backtrace kills us.
+	 * to safely read from kernel space.
 	 */
 	fs = get_fs();
 	set_fs(KERNEL_DS);
@@ -111,25 +110,16 @@
 	print_ip_sym(where);
 }
 
-static void dump_instr(const char *lvl, struct pt_regs *regs)
+static void __dump_instr(const char *lvl, struct pt_regs *regs)
 {
 	unsigned long addr = instruction_pointer(regs);
-	mm_segment_t fs;
 	char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
 	int i;
 
-	/*
-	 * We need to switch to kernel mode so that we can use __get_user
-	 * to safely read from kernel space.  Note that we now dump the
-	 * code first, just in case the backtrace kills us.
-	 */
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-
 	for (i = -4; i < 1; i++) {
 		unsigned int val, bad;
 
-		bad = __get_user(val, &((u32 *)addr)[i]);
+		bad = get_user(val, &((u32 *)addr)[i]);
 
 		if (!bad)
 			p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val);
@@ -139,8 +129,18 @@
 		}
 	}
 	printk("%sCode: %s\n", lvl, str);
+}
 
-	set_fs(fs);
+static void dump_instr(const char *lvl, struct pt_regs *regs)
+{
+	if (!user_mode(regs)) {
+		mm_segment_t fs = get_fs();
+		set_fs(KERNEL_DS);
+		__dump_instr(lvl, regs);
+		set_fs(fs);
+	} else {
+		__dump_instr(lvl, regs);
+	}
 }
 
 static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
@@ -239,10 +239,12 @@
 {
 	struct thread_info *thread = current_thread_info();
 	int ret;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&die_lock, flags);
 
 	oops_enter();
 
-	raw_spin_lock_irq(&die_lock);
 	console_verbose();
 	bust_spinlocks(1);
 	ret = __die(str, err, thread, regs);
@@ -252,13 +254,15 @@
 
 	bust_spinlocks(0);
 	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
-	raw_spin_unlock_irq(&die_lock);
 	oops_exit();
 
 	if (in_interrupt())
 		panic("Fatal exception in interrupt");
 	if (panic_on_oops)
 		panic("Fatal exception");
+
+	raw_spin_unlock_irqrestore(&die_lock, flags);
+
 	if (ret != NOTIFY_STOP)
 		do_exit(SIGSEGV);
 }
@@ -434,16 +438,32 @@
 }
 
 /*
- * bad_mode handles the impossible case in the exception vector.
+ * bad_mode handles the impossible case in the exception vector. This is always
+ * fatal.
  */
 asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
 {
-	siginfo_t info;
-	void __user *pc = (void __user *)instruction_pointer(regs);
 	console_verbose();
 
 	pr_crit("Bad mode in %s handler detected, code 0x%08x -- %s\n",
 		handler[reason], esr, esr_get_class_string(esr));
+
+	local_irq_disable();
+	panic("bad mode");
+}
+
+/*
+ * bad_el0_sync handles unexpected, but potentially recoverable synchronous
+ * exceptions taken from EL0. Unlike bad_mode, this returns.
+ */
+asmlinkage void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
+{
+	siginfo_t info;
+	void __user *pc = (void __user *)instruction_pointer(regs);
+	console_verbose();
+
+	pr_crit("Bad EL0 synchronous exception detected on CPU%d, code 0x%08x -- %s\n",
+		smp_processor_id(), esr, esr_get_class_string(esr));
 	__show_regs(regs);
 
 	info.si_signo = SIGILL;
@@ -451,7 +471,10 @@
 	info.si_code  = ILL_ILLOPC;
 	info.si_addr  = pc;
 
-	arm64_notify_die("Oops - bad mode", regs, &info, 0);
+	current->thread.fault_address = 0;
+	current->thread.fault_code = 0;
+
+	force_sig_info(info.si_signo, &info, current);
 }
 
 void __pte_error(const char *file, int line, unsigned long val)
--- linux-4.4.0.orig/arch/arm64/kernel/vdso.c
+++ linux-4.4.0/arch/arm64/kernel/vdso.c
@@ -36,7 +36,7 @@
 #include <asm/vdso.h>
 #include <asm/vdso_datapage.h>
 
-extern char vdso_start, vdso_end;
+extern char vdso_start[], vdso_end[];
 static unsigned long vdso_pages;
 static struct page **vdso_pagelist;
 
@@ -115,14 +115,14 @@
 {
 	int i;
 
-	if (memcmp(&vdso_start, "\177ELF", 4)) {
+	if (memcmp(vdso_start, "\177ELF", 4)) {
 		pr_err("vDSO is not a valid ELF object!\n");
 		return -EINVAL;
 	}
 
-	vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+	vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
 	pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
-		vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
+		vdso_pages + 1, vdso_pages, vdso_start, 1L, vdso_data);
 
 	/* Allocate the vDSO pagelist, plus a page for the data. */
 	vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
@@ -135,7 +135,7 @@
 
 	/* Grab the vDSO code pages. */
 	for (i = 0; i < vdso_pages; i++)
-		vdso_pagelist[i + 1] = virt_to_page(&vdso_start + i * PAGE_SIZE);
+		vdso_pagelist[i + 1] = virt_to_page(vdso_start + i * PAGE_SIZE);
 
 	/* Populate the special mapping structures */
 	vdso_spec[0] = (struct vm_special_mapping) {
--- linux-4.4.0.orig/arch/arm64/kvm/guest.c
+++ linux-4.4.0/arch/arm64/kvm/guest.c
@@ -48,6 +48,45 @@
 	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
 }
 
+static int validate_core_offset(const struct kvm_one_reg *reg)
+{
+	u64 off = core_reg_offset_from_id(reg->id);
+	int size;
+
+	switch (off) {
+	case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
+	     KVM_REG_ARM_CORE_REG(regs.regs[30]):
+	case KVM_REG_ARM_CORE_REG(regs.sp):
+	case KVM_REG_ARM_CORE_REG(regs.pc):
+	case KVM_REG_ARM_CORE_REG(regs.pstate):
+	case KVM_REG_ARM_CORE_REG(sp_el1):
+	case KVM_REG_ARM_CORE_REG(elr_el1):
+	case KVM_REG_ARM_CORE_REG(spsr[0]) ...
+	     KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]):
+		size = sizeof(__u64);
+		break;
+
+	case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ...
+	     KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
+		size = sizeof(__uint128_t);
+		break;
+
+	case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
+	case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
+		size = sizeof(__u32);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (KVM_REG_SIZE(reg->id) == size &&
+	    IS_ALIGNED(off, size / sizeof(__u32)))
+		return 0;
+
+	return -EINVAL;
+}
+
 static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	/*
@@ -67,6 +106,9 @@
 	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
 		return -ENOENT;
 
+	if (validate_core_offset(reg))
+		return -EINVAL;
+
 	if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
 		return -EFAULT;
 
@@ -89,6 +131,9 @@
 	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
 		return -ENOENT;
 
+	if (validate_core_offset(reg))
+		return -EINVAL;
+
 	if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
 		return -EINVAL;
 
@@ -98,17 +143,25 @@
 	}
 
 	if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) {
-		u32 mode = (*(u32 *)valp) & COMPAT_PSR_MODE_MASK;
+		u64 mode = (*(u64 *)valp) & COMPAT_PSR_MODE_MASK;
 		switch (mode) {
 		case COMPAT_PSR_MODE_USR:
+			if (!system_supports_32bit_el0())
+				return -EINVAL;
+			break;
 		case COMPAT_PSR_MODE_FIQ:
 		case COMPAT_PSR_MODE_IRQ:
 		case COMPAT_PSR_MODE_SVC:
 		case COMPAT_PSR_MODE_ABT:
 		case COMPAT_PSR_MODE_UND:
+			if (!vcpu_el1_is_32bit(vcpu))
+				return -EINVAL;
+			break;
 		case PSR_MODE_EL0t:
 		case PSR_MODE_EL1t:
 		case PSR_MODE_EL1h:
+			if (vcpu_el1_is_32bit(vcpu))
+				return -EINVAL;
 			break;
 		default:
 			err = -EINVAL;
@@ -186,7 +239,7 @@
 	u64 val;
 
 	val = kvm_arm_timer_get_reg(vcpu, reg->id);
-	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id));
+	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
 }
 
 /**
--- linux-4.4.0.orig/arch/arm64/kvm/handle_exit.c
+++ linux-4.4.0/arch/arm64/kvm/handle_exit.c
@@ -42,7 +42,7 @@
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -51,7 +51,7 @@
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
@@ -121,7 +121,19 @@
 	return ret;
 }
 
+static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+	u32 hsr = kvm_vcpu_get_hsr(vcpu);
+
+	kvm_pr_unimpl("Unknown exception class: hsr: %#08x -- %s\n",
+		      hsr, esr_get_class_string(hsr));
+
+	kvm_inject_undefined(vcpu);
+	return 1;
+}
+
 static exit_handle_fn arm_exit_handlers[] = {
+	[0 ... ESR_ELx_EC_MAX]	= kvm_handle_unknown_ec,
 	[ESR_ELx_EC_WFx]	= kvm_handle_wfx,
 	[ESR_ELx_EC_CP15_32]	= kvm_handle_cp15_32,
 	[ESR_ELx_EC_CP15_64]	= kvm_handle_cp15_64,
@@ -147,13 +159,6 @@
 	u32 hsr = kvm_vcpu_get_hsr(vcpu);
 	u8 hsr_ec = hsr >> ESR_ELx_EC_SHIFT;
 
-	if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) ||
-	    !arm_exit_handlers[hsr_ec]) {
-		kvm_err("Unknown exception class: hsr: %#08x -- %s\n",
-			hsr, esr_get_class_string(hsr));
-		BUG();
-	}
-
 	return arm_exit_handlers[hsr_ec];
 }
 
--- linux-4.4.0.orig/arch/arm64/kvm/hyp-init.S
+++ linux-4.4.0/arch/arm64/kvm/hyp-init.S
@@ -64,7 +64,7 @@
 	mrs	x4, tcr_el1
 	ldr	x5, =TCR_EL2_MASK
 	and	x4, x4, x5
-	ldr	x5, =TCR_EL2_FLAGS
+	mov	x5, #TCR_EL2_RES1
 	orr	x4, x4, x5
 
 #ifndef CONFIG_ARM64_VA_BITS_48
@@ -85,15 +85,18 @@
 	ldr_l	x5, idmap_t0sz
 	bfi	x4, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
 #endif
-	msr	tcr_el2, x4
-
-	ldr	x4, =VTCR_EL2_FLAGS
 	/*
 	 * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in
-	 * VTCR_EL2.
+	 * TCR_EL2 and VTCR_EL2.
 	 */
 	mrs	x5, ID_AA64MMFR0_EL1
 	bfi	x4, x5, #16, #3
+
+	msr	tcr_el2, x4
+
+	ldr	x4, =VTCR_EL2_FLAGS
+	bfi	x4, x5, #16, #3
+
 	msr	vtcr_el2, x4
 
 	mrs	x4, mair_el1
--- linux-4.4.0.orig/arch/arm64/kvm/hyp.S
+++ linux-4.4.0/arch/arm64/kvm/hyp.S
@@ -494,7 +494,7 @@
 .endm
 
 .macro deactivate_traps
-	mov	x2, #HCR_RW
+	mov_q	x2, HCR_HOST_NVHE_FLAGS
 	msr	hcr_el2, x2
 	msr	hstr_el2, xzr
 
--- linux-4.4.0.orig/arch/arm64/kvm/inject_fault.c
+++ linux-4.4.0/arch/arm64/kvm/inject_fault.c
@@ -130,7 +130,7 @@
 		esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT);
 
 	if (!is_iabt)
-		esr |= ESR_ELx_EC_DABT_LOW;
+		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
 
 	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
 }
--- linux-4.4.0.orig/arch/arm64/kvm/sys_regs.c
+++ linux-4.4.0/arch/arm64/kvm/sys_regs.c
@@ -687,7 +687,7 @@
 	} else {
 		u64 dfr = read_system_reg(SYS_ID_AA64DFR0_EL1);
 		u64 pfr = read_system_reg(SYS_ID_AA64PFR0_EL1);
-		u32 el3 = !!cpuid_feature_extract_field(pfr, ID_AA64PFR0_EL3_SHIFT);
+		u32 el3 = !!cpuid_feature_extract_unsigned_field(pfr, ID_AA64PFR0_EL3_SHIFT);
 
 		p->regval = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) |
 			     (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) |
@@ -1054,8 +1054,8 @@
 {
 	struct sys_reg_params params;
 	u32 hsr = kvm_vcpu_get_hsr(vcpu);
-	int Rt = (hsr >> 5) & 0xf;
-	int Rt2 = (hsr >> 10) & 0xf;
+	int Rt = (hsr >> 5) & 0x1f;
+	int Rt2 = (hsr >> 10) & 0x1f;
 
 	params.is_aarch32 = true;
 	params.is_32bit = false;
@@ -1106,7 +1106,7 @@
 {
 	struct sys_reg_params params;
 	u32 hsr = kvm_vcpu_get_hsr(vcpu);
-	int Rt  = (hsr >> 5) & 0xf;
+	int Rt  = (hsr >> 5) & 0x1f;
 
 	params.is_aarch32 = true;
 	params.is_32bit = true;
--- linux-4.4.0.orig/arch/arm64/lib/clear_user.S
+++ linux-4.4.0/arch/arm64/lib/clear_user.S
@@ -62,5 +62,7 @@
 	.section .fixup,"ax"
 	.align	2
 9:	mov	x0, x2			// return the original size
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
+	    CONFIG_ARM64_PAN)
 	ret
 	.previous
--- linux-4.4.0.orig/arch/arm64/lib/copy_from_user.S
+++ linux-4.4.0/arch/arm64/lib/copy_from_user.S
@@ -85,5 +85,7 @@
 	strb	wzr, [dst], #1			// zero remaining buffer space
 	cmp	dst, end
 	b.lo	9999b
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
+	    CONFIG_ARM64_PAN)
 	ret
 	.previous
--- linux-4.4.0.orig/arch/arm64/lib/copy_in_user.S
+++ linux-4.4.0/arch/arm64/lib/copy_in_user.S
@@ -81,5 +81,7 @@
 	.section .fixup,"ax"
 	.align	2
 9998:	sub	x0, end, dst			// bytes not copied
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
+	    CONFIG_ARM64_PAN)
 	ret
 	.previous
--- linux-4.4.0.orig/arch/arm64/lib/copy_page.S
+++ linux-4.4.0/arch/arm64/lib/copy_page.S
@@ -18,6 +18,8 @@
 #include <linux/const.h>
 #include <asm/assembler.h>
 #include <asm/page.h>
+#include <asm/cpufeature.h>
+#include <asm/alternative.h>
 
 /*
  * Copy a page from src to dest (both are page aligned)
@@ -27,20 +29,65 @@
  *	x1 - src
  */
 ENTRY(copy_page)
-	/* Assume cache line size is 64 bytes. */
-	prfm	pldl1strm, [x1, #64]
-1:	ldp	x2, x3, [x1]
+alternative_if_not ARM64_HAS_NO_HW_PREFETCH
+	nop
+	nop
+alternative_else
+	# Prefetch two cache lines ahead.
+	prfm    pldl1strm, [x1, #128]
+	prfm    pldl1strm, [x1, #256]
+alternative_endif
+
+	ldp	x2, x3, [x1]
 	ldp	x4, x5, [x1, #16]
 	ldp	x6, x7, [x1, #32]
 	ldp	x8, x9, [x1, #48]
-	add	x1, x1, #64
-	prfm	pldl1strm, [x1, #64]
+	ldp	x10, x11, [x1, #64]
+	ldp	x12, x13, [x1, #80]
+	ldp	x14, x15, [x1, #96]
+	ldp	x16, x17, [x1, #112]
+
+	mov	x18, #(PAGE_SIZE - 128)
+	add	x1, x1, #128
+1:
+	subs	x18, x18, #128
+
+alternative_if_not ARM64_HAS_NO_HW_PREFETCH
+	nop
+alternative_else
+	prfm    pldl1strm, [x1, #384]
+alternative_endif
+
 	stnp	x2, x3, [x0]
+	ldp	x2, x3, [x1]
 	stnp	x4, x5, [x0, #16]
+	ldp	x4, x5, [x1, #16]
 	stnp	x6, x7, [x0, #32]
+	ldp	x6, x7, [x1, #32]
 	stnp	x8, x9, [x0, #48]
-	add	x0, x0, #64
-	tst	x1, #(PAGE_SIZE - 1)
-	b.ne	1b
+	ldp	x8, x9, [x1, #48]
+	stnp	x10, x11, [x0, #64]
+	ldp	x10, x11, [x1, #64]
+	stnp	x12, x13, [x0, #80]
+	ldp	x12, x13, [x1, #80]
+	stnp	x14, x15, [x0, #96]
+	ldp	x14, x15, [x1, #96]
+	stnp	x16, x17, [x0, #112]
+	ldp	x16, x17, [x1, #112]
+
+	add	x0, x0, #128
+	add	x1, x1, #128
+
+	b.gt	1b
+
+	stnp	x2, x3, [x0]
+	stnp	x4, x5, [x0, #16]
+	stnp	x6, x7, [x0, #32]
+	stnp	x8, x9, [x0, #48]
+	stnp	x10, x11, [x0, #64]
+	stnp	x12, x13, [x0, #80]
+	stnp	x14, x15, [x0, #96]
+	stnp	x16, x17, [x0, #112]
+
 	ret
 ENDPROC(copy_page)
--- linux-4.4.0.orig/arch/arm64/lib/copy_to_user.S
+++ linux-4.4.0/arch/arm64/lib/copy_to_user.S
@@ -79,5 +79,7 @@
 	.section .fixup,"ax"
 	.align	2
 9998:	sub	x0, end, dst			// bytes not copied
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
+	    CONFIG_ARM64_PAN)
 	ret
 	.previous
--- linux-4.4.0.orig/arch/arm64/mm/Makefile
+++ linux-4.4.0/arch/arm64/mm/Makefile
@@ -4,6 +4,7 @@
 				   context.o proc.o pageattr.o
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
 obj-$(CONFIG_ARM64_PTDUMP)	+= dump.o
+obj-$(CONFIG_NUMA)		+= numa.o
 
 obj-$(CONFIG_KASAN)		+= kasan_init.o
 KASAN_SANITIZE_kasan_init.o	:= n
--- linux-4.4.0.orig/arch/arm64/mm/context.c
+++ linux-4.4.0/arch/arm64/mm/context.c
@@ -187,7 +187,8 @@
 
 static int asids_init(void)
 {
-	int fld = cpuid_feature_extract_field(read_cpuid(ID_AA64MMFR0_EL1), 4);
+	int fld = cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR0_EL1),
+						       ID_AA64MMFR0_ASID_SHIFT);
 
 	switch (fld) {
 	default:
--- linux-4.4.0.orig/arch/arm64/mm/dma-mapping.c
+++ linux-4.4.0/arch/arm64/mm/dma-mapping.c
@@ -933,6 +933,10 @@
 		ret = register_iommu_dma_ops_notifier(&platform_bus_type);
 	if (!ret)
 		ret = register_iommu_dma_ops_notifier(&amba_bustype);
+
+	/* handle devices queued before this arch_initcall */
+	if (!ret)
+		__iommu_attach_notifier(NULL, BUS_NOTIFY_ADD_DEVICE, NULL);
 	return ret;
 }
 arch_initcall(__iommu_dma_init);
--- linux-4.4.0.orig/arch/arm64/mm/fault.c
+++ linux-4.4.0/arch/arm64/mm/fault.c
@@ -29,7 +29,9 @@
 #include <linux/sched.h>
 #include <linux/highmem.h>
 #include <linux/perf_event.h>
+#include <linux/preempt.h>
 
+#include <asm/bug.h>
 #include <asm/cpufeature.h>
 #include <asm/exception.h>
 #include <asm/debug-monitors.h>
@@ -64,23 +66,74 @@
 			break;
 
 		pud = pud_offset(pgd, addr);
-		printk(", *pud=%016llx", pud_val(*pud));
+		pr_cont(", *pud=%016llx", pud_val(*pud));
 		if (pud_none(*pud) || pud_bad(*pud))
 			break;
 
 		pmd = pmd_offset(pud, addr);
-		printk(", *pmd=%016llx", pmd_val(*pmd));
+		pr_cont(", *pmd=%016llx", pmd_val(*pmd));
 		if (pmd_none(*pmd) || pmd_bad(*pmd))
 			break;
 
 		pte = pte_offset_map(pmd, addr);
-		printk(", *pte=%016llx", pte_val(*pte));
+		pr_cont(", *pte=%016llx", pte_val(*pte));
 		pte_unmap(pte);
 	} while(0);
 
-	printk("\n");
+	pr_cont("\n");
 }
 
+#ifdef CONFIG_ARM64_HW_AFDBM
+/*
+ * This function sets the access flags (dirty, accessed), as well as write
+ * permission, and only to a more permissive setting.
+ *
+ * It needs to cope with hardware update of the accessed/dirty state by other
+ * agents in the system and can safely skip the __sync_icache_dcache() call as,
+ * like set_pte_at(), the PTE is never changed from no-exec to exec here.
+ *
+ * Returns whether or not the PTE actually changed.
+ */
+int ptep_set_access_flags(struct vm_area_struct *vma,
+			  unsigned long address, pte_t *ptep,
+			  pte_t entry, int dirty)
+{
+	pteval_t old_pteval;
+	unsigned int tmp;
+
+	if (pte_same(*ptep, entry))
+		return 0;
+
+	/* only preserve the access flags and write permission */
+	pte_val(entry) &= PTE_AF | PTE_WRITE | PTE_DIRTY;
+
+	/* set PTE_RDONLY if actual read-only or clean PTE */
+	if (!pte_write(entry) || !pte_sw_dirty(entry))
+		pte_val(entry) |= PTE_RDONLY;
+
+	/*
+	 * Setting the flags must be done atomically to avoid racing with the
+	 * hardware update of the access/dirty state. The PTE_RDONLY bit must
+	 * be set to the most permissive (lowest value) of *ptep and entry
+	 * (calculated as: a & b == ~(~a | ~b)).
+	 */
+	pte_val(entry) ^= PTE_RDONLY;
+	asm volatile("//	ptep_set_access_flags\n"
+	"	prfm	pstl1strm, %2\n"
+	"1:	ldxr	%0, %2\n"
+	"	eor	%0, %0, %3		// negate PTE_RDONLY in *ptep\n"
+	"	orr	%0, %0, %4		// set flags\n"
+	"	eor	%0, %0, %3		// negate final PTE_RDONLY\n"
+	"	stxr	%w1, %0, %2\n"
+	"	cbnz	%w1, 1b\n"
+	: "=&r" (old_pteval), "=&r" (tmp), "+Q" (pte_val(*ptep))
+	: "L" (PTE_RDONLY), "r" (pte_val(entry)));
+
+	flush_tlb_fix_spurious_fault(vma, address);
+	return 1;
+}
+#endif
+
 /*
  * The kernel tried to access some page that wasn't present.
  */
@@ -261,8 +314,11 @@
 	 * 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))
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+		if (!user_mode(regs))
+			goto no_context;
 		return 0;
+	}
 
 	/*
 	 * Major/minor page fault accounting is only done on the initial
@@ -392,7 +448,7 @@
 	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 0 translation fault"	},
 	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 1 translation fault"	},
 	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 2 translation fault"	},
-	{ do_page_fault,	SIGSEGV, SEGV_MAPERR,	"level 3 translation fault"	},
+	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 3 translation fault"	},
 	{ do_bad,		SIGBUS,  0,		"unknown 8"			},
 	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 1 access flag fault"	},
 	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 2 access flag fault"	},
@@ -533,31 +589,53 @@
 	debug_fault_info[nr].name	= name;
 }
 
-asmlinkage int __exception do_debug_exception(unsigned long addr,
+asmlinkage int __exception do_debug_exception(unsigned long addr_if_watchpoint,
 					      unsigned int esr,
 					      struct pt_regs *regs)
 {
 	const struct fault_info *inf = debug_fault_info + DBG_ESR_EVT(esr);
+	unsigned long pc = instruction_pointer(regs);
 	struct siginfo info;
+	int rv;
 
-	if (!inf->fn(addr, esr, regs))
-		return 1;
+	/*
+	 * Tell lockdep we disabled irqs in entry.S. Do nothing if they were
+	 * already disabled to preserve the last enabled/disabled addresses.
+	 */
+	if (interrupts_enabled(regs))
+		trace_hardirqs_off();
 
-	pr_alert("Unhandled debug exception: %s (0x%08x) at 0x%016lx\n",
-		 inf->name, esr, addr);
+	if (!inf->fn(addr_if_watchpoint, esr, regs)) {
+		rv = 1;
+	} else {
+		pr_alert("Unhandled debug exception: %s (0x%08x) at 0x%016lx\n",
+			 inf->name, esr, pc);
 
-	info.si_signo = inf->sig;
-	info.si_errno = 0;
-	info.si_code  = inf->code;
-	info.si_addr  = (void __user *)addr;
-	arm64_notify_die("", regs, &info, 0);
+		info.si_signo = inf->sig;
+		info.si_errno = 0;
+		info.si_code  = inf->code;
+		info.si_addr  = (void __user *)pc;
+		arm64_notify_die("", regs, &info, 0);
+		rv = 0;
+	}
 
-	return 0;
+	if (interrupts_enabled(regs))
+		trace_hardirqs_on();
+
+	return rv;
 }
 
 #ifdef CONFIG_ARM64_PAN
-void cpu_enable_pan(void *__unused)
+int cpu_enable_pan(void *__unused)
 {
+	/*
+	 * We modify PSTATE. This won't work from irq context as the PSTATE
+	 * is discarded once we return from the exception.
+	 */
+	WARN_ON_ONCE(in_interrupt());
+
 	config_sctlr_el1(SCTLR_EL1_SPAN, 0);
+	asm(SET_PSTATE_PAN(1));
+	return 0;
 }
 #endif /* CONFIG_ARM64_PAN */
--- linux-4.4.0.orig/arch/arm64/mm/flush.c
+++ linux-4.4.0/arch/arm64/mm/flush.c
@@ -70,10 +70,6 @@
 {
 	struct page *page = pte_page(pte);
 
-	/* no flushing needed for anonymous pages */
-	if (!page_mapping(page))
-		return;
-
 	if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
 		__flush_dcache_area(page_address(page),
 				PAGE_SIZE << compound_order(page));
--- linux-4.4.0.orig/arch/arm64/mm/init.c
+++ linux-4.4.0/arch/arm64/mm/init.c
@@ -37,6 +37,7 @@
 
 #include <asm/fixmap.h>
 #include <asm/memory.h>
+#include <asm/numa.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/sizes.h>
@@ -77,6 +78,21 @@
 	return min(offset + (1ULL << 32), memblock_end_of_DRAM());
 }
 
+#ifdef CONFIG_NUMA
+
+static void __init zone_sizes_init(unsigned long min, unsigned long max)
+{
+	unsigned long max_zone_pfns[MAX_NR_ZONES]  = {0};
+
+	if (IS_ENABLED(CONFIG_ZONE_DMA))
+		max_zone_pfns[ZONE_DMA] = PFN_DOWN(max_zone_dma_phys());
+	max_zone_pfns[ZONE_NORMAL] = max;
+
+	free_area_init_nodes(max_zone_pfns);
+}
+
+#else
+
 static void __init zone_sizes_init(unsigned long min, unsigned long max)
 {
 	struct memblock_region *reg;
@@ -117,10 +133,16 @@
 	free_area_init_node(0, zone_size, min, zhole_size);
 }
 
+#endif /* CONFIG_NUMA */
+
 #ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
 {
-	return memblock_is_memory(pfn << PAGE_SHIFT);
+	phys_addr_t addr = pfn << PAGE_SHIFT;
+
+	if ((addr >> PAGE_SHIFT) != pfn)
+		return 0;
+	return memblock_is_memory(addr);
 }
 EXPORT_SYMBOL(pfn_valid);
 #endif
@@ -133,10 +155,15 @@
 static void arm64_memory_present(void)
 {
 	struct memblock_region *reg;
+	int nid = 0;
 
-	for_each_memblock(memory, reg)
-		memory_present(0, memblock_region_memory_base_pfn(reg),
-			       memblock_region_memory_end_pfn(reg));
+	for_each_memblock(memory, reg) {
+#ifdef CONFIG_NUMA
+		nid = reg->nid;
+#endif
+		memory_present(nid, memblock_region_memory_base_pfn(reg),
+				memblock_region_memory_end_pfn(reg));
+	}
 }
 #endif
 
@@ -178,10 +205,10 @@
 		arm64_dma_phys_limit = max_zone_dma_phys();
 	else
 		arm64_dma_phys_limit = PHYS_MASK + 1;
+	high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
 	dma_contiguous_reserve(arm64_dma_phys_limit);
 
 	memblock_allow_resize();
-	memblock_dump_all();
 }
 
 void __init bootmem_init(void)
@@ -193,6 +220,9 @@
 
 	early_memtest(min << PAGE_SHIFT, max << PAGE_SHIFT);
 
+	max_pfn = max_low_pfn = max;
+
+	arm64_numa_init();
 	/*
 	 * Sparsemem tries to allocate bootmem in memory_present(), so must be
 	 * done after the fixed reservations.
@@ -201,9 +231,6 @@
 
 	sparse_init();
 	zone_sizes_init(min, max);
-
-	high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
-	max_pfn = max_low_pfn = max;
 }
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
@@ -319,8 +346,8 @@
 #endif
 		  MLG(VMALLOC_START, VMALLOC_END),
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-		  MLG((unsigned long)vmemmap,
-		      (unsigned long)vmemmap + VMEMMAP_SIZE),
+		  MLG(VMEMMAP_START,
+		      VMEMMAP_START + VMEMMAP_SIZE),
 		  MLM((unsigned long)virt_to_page(PAGE_OFFSET),
 		      (unsigned long)virt_to_page(high_memory)),
 #endif
--- linux-4.4.0.orig/arch/arm64/mm/mmu.c
+++ linux-4.4.0/arch/arm64/mm/mmu.c
@@ -439,23 +439,32 @@
 }
 
 /*
- * paging_init() sets up the page tables, initialises the zone memory
- * maps and sets up the zero page.
+ * paging_init_map_mem() sets up the page tables so that memblock
+ * memory is usable.
  */
-void __init paging_init(void)
+void __init paging_init_map_mem(void)
 {
-	void *zero_page;
-
 	map_mem();
 	fixup_executable();
+}
 
+/*
+ * paging_init_rest() finishes setting up the page tables, initializes
+ * the zone memory maps and sets up the zero page.
+ */
+void __init paging_init_rest(void)
+{
 	/* allocate the zero page. */
-	zero_page = early_alloc(PAGE_SIZE);
+	void *zero_page = early_alloc(PAGE_SIZE);
 
 	bootmem_init();
+	memblock_dump_all();
 
 	empty_zero_page = virt_to_page(zero_page);
 
+	/* Ensure the zero page is visible to the page table walker */
+	dsb(ishst);
+
 	/*
 	 * TTBR0 is only used for the identity mapping at this stage. Make it
 	 * point to zero page to avoid speculatively fetching new entries.
@@ -649,9 +658,9 @@
 	/*
 	 * Check whether the physical FDT address is set and meets the minimum
 	 * alignment requirement. Since we are relying on MIN_FDT_ALIGN to be
-	 * at least 8 bytes so that we can always access the size field of the
-	 * FDT header after mapping the first chunk, double check here if that
-	 * is indeed the case.
+	 * at least 8 bytes so that we can always access the magic and size
+	 * fields of the FDT header after mapping the first chunk, double check
+	 * here if that is indeed the case.
 	 */
 	BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
 	if (!dt_phys || dt_phys % MIN_FDT_ALIGN)
@@ -679,7 +688,7 @@
 	create_mapping(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
 		       SWAPPER_BLOCK_SIZE, prot);
 
-	if (fdt_check_header(dt_virt) != 0)
+	if (fdt_magic(dt_virt) != FDT_MAGIC)
 		return NULL;
 
 	size = fdt_totalsize(dt_virt);
@@ -694,3 +703,15 @@
 
 	return dt_virt;
 }
+
+#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
+int pud_free_pmd_page(pud_t *pud, unsigned long addr)
+{
+	return pud_none(*pud);
+}
+
+int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
+{
+	return pmd_none(*pmd);
+}
+#endif
--- linux-4.4.0.orig/arch/arm64/mm/numa.c
+++ linux-4.4.0/arch/arm64/mm/numa.c
@@ -0,0 +1,396 @@
+/*
+ * NUMA support, based on the x86 implementation.
+ *
+ * Copyright (C) 2015 Cavium Inc.
+ * Author: Ganapatrao Kulkarni <gkulkarni@cavium.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
+EXPORT_SYMBOL(node_data);
+nodemask_t numa_nodes_parsed __initdata;
+static int cpu_to_node_map[NR_CPUS] = { [0 ... NR_CPUS-1] = NUMA_NO_NODE };
+
+static int numa_distance_cnt;
+static u8 *numa_distance;
+static int numa_off;
+
+static __init int numa_parse_early_param(char *opt)
+{
+	if (!opt)
+		return -EINVAL;
+	if (!strncmp(opt, "off", 3)) {
+		pr_info("%s\n", "NUMA turned off");
+		numa_off = 1;
+	}
+	return 0;
+}
+early_param("numa", numa_parse_early_param);
+
+cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
+EXPORT_SYMBOL(node_to_cpumask_map);
+
+#ifdef CONFIG_DEBUG_PER_CPU_MAPS
+
+/*
+ * Returns a pointer to the bitmask of CPUs on Node 'node'.
+ */
+const struct cpumask *cpumask_of_node(int node)
+{
+	if (WARN_ON(node >= nr_node_ids))
+		return cpu_none_mask;
+
+	if (WARN_ON(node_to_cpumask_map[node] == NULL))
+		return cpu_online_mask;
+
+	return node_to_cpumask_map[node];
+}
+EXPORT_SYMBOL(cpumask_of_node);
+
+#endif
+
+static void map_cpu_to_node(unsigned int cpu, int nid)
+{
+	set_cpu_numa_node(cpu, nid);
+	if (nid >= 0)
+		cpumask_set_cpu(cpu, node_to_cpumask_map[nid]);
+}
+
+void numa_clear_node(unsigned int cpu)
+{
+	int nid = cpu_to_node(cpu);
+
+	if (nid >= 0)
+		cpumask_clear_cpu(cpu, node_to_cpumask_map[nid]);
+	set_cpu_numa_node(cpu, NUMA_NO_NODE);
+}
+
+/*
+ * Allocate node_to_cpumask_map based on number of available nodes
+ * Requires node_possible_map to be valid.
+ *
+ * Note: cpumask_of_node() is not valid until after this is done.
+ * (Use CONFIG_DEBUG_PER_CPU_MAPS to check this.)
+ */
+static void __init setup_node_to_cpumask_map(void)
+{
+	unsigned int cpu;
+	int node;
+
+	/* setup nr_node_ids if not done yet */
+	if (nr_node_ids == MAX_NUMNODES)
+		setup_nr_node_ids();
+
+	/* allocate and clear the mapping */
+	for (node = 0; node < nr_node_ids; node++) {
+		alloc_bootmem_cpumask_var(&node_to_cpumask_map[node]);
+		cpumask_clear(node_to_cpumask_map[node]);
+	}
+
+	for_each_possible_cpu(cpu)
+		set_cpu_numa_node(cpu, NUMA_NO_NODE);
+
+	/* cpumask_of_node() will now work */
+	pr_debug("NUMA: Node to cpumask map for %d nodes\n", nr_node_ids);
+}
+
+/*
+ *  Set the cpu to node and mem mapping
+ */
+void numa_store_cpu_info(unsigned int cpu)
+{
+	map_cpu_to_node(cpu, numa_off ? 0 : cpu_to_node_map[cpu]);
+}
+
+void __init early_map_cpu_to_node(unsigned int cpu, int nid)
+{
+	/* fallback to node 0 */
+	if (nid < 0 || nid >= MAX_NUMNODES)
+		nid = 0;
+
+	cpu_to_node_map[cpu] = nid;
+}
+
+/**
+ * numa_add_memblk - Set node id to memblk
+ * @nid: NUMA node ID of the new memblk
+ * @start: Start address of the new memblk
+ * @size:  Size of the new memblk
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int __init numa_add_memblk(int nid, u64 start, u64 size)
+{
+	int ret;
+
+	ret = memblock_set_node(start, size, &memblock.memory, nid);
+	if (ret < 0) {
+		pr_err("NUMA: memblock [0x%llx - 0x%llx] failed to add on node %d\n",
+			start, (start + size - 1), nid);
+		return ret;
+	}
+
+	node_set(nid, numa_nodes_parsed);
+	pr_info("NUMA: Adding memblock [0x%llx - 0x%llx] on node %d\n",
+			start, (start + size - 1), nid);
+	return ret;
+}
+
+/**
+ * Initialize NODE_DATA for a node on the local memory
+ */
+static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn)
+{
+	const size_t nd_size = roundup(sizeof(pg_data_t), SMP_CACHE_BYTES);
+	u64 nd_pa;
+	void *nd;
+	int tnid;
+
+	pr_info("NUMA: Initmem setup node %d [mem %#010Lx-%#010Lx]\n",
+			nid, start_pfn << PAGE_SHIFT,
+			(end_pfn << PAGE_SHIFT) - 1);
+
+	nd_pa = memblock_alloc_try_nid(nd_size, SMP_CACHE_BYTES, nid);
+	nd = __va(nd_pa);
+
+	/* report and initialize */
+	pr_info("NUMA: NODE_DATA [mem %#010Lx-%#010Lx]\n",
+		nd_pa, nd_pa + nd_size - 1);
+	tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT);
+	if (tnid != nid)
+		pr_info("NUMA: NODE_DATA(%d) on node %d\n", nid, tnid);
+
+	node_data[nid] = nd;
+	memset(NODE_DATA(nid), 0, sizeof(pg_data_t));
+	NODE_DATA(nid)->node_id = nid;
+	NODE_DATA(nid)->node_start_pfn = start_pfn;
+	NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn;
+}
+
+/**
+ * numa_free_distance
+ *
+ * The current table is freed.
+ */
+void __init numa_free_distance(void)
+{
+	size_t size;
+
+	if (!numa_distance)
+		return;
+
+	size = numa_distance_cnt * numa_distance_cnt *
+		sizeof(numa_distance[0]);
+
+	memblock_free(__pa(numa_distance), size);
+	numa_distance_cnt = 0;
+	numa_distance = NULL;
+}
+
+/**
+ *
+ * Create a new NUMA distance table.
+ *
+ */
+static int __init numa_alloc_distance(void)
+{
+	size_t size;
+	u64 phys;
+	int i, j;
+
+	size = nr_node_ids * nr_node_ids * sizeof(numa_distance[0]);
+	phys = memblock_find_in_range(0, PFN_PHYS(max_pfn),
+				      size, PAGE_SIZE);
+	if (WARN_ON(!phys))
+		return -ENOMEM;
+
+	memblock_reserve(phys, size);
+
+	numa_distance = __va(phys);
+	numa_distance_cnt = nr_node_ids;
+
+	/* fill with the default distances */
+	for (i = 0; i < numa_distance_cnt; i++)
+		for (j = 0; j < numa_distance_cnt; j++)
+			numa_distance[i * numa_distance_cnt + j] = i == j ?
+				LOCAL_DISTANCE : REMOTE_DISTANCE;
+
+	pr_debug("NUMA: Initialized distance table, cnt=%d\n",
+			numa_distance_cnt);
+
+	return 0;
+}
+
+/**
+ * numa_set_distance - Set inter node NUMA distance from node to node.
+ * @from: the 'from' node to set distance
+ * @to: the 'to'  node to set distance
+ * @distance: NUMA distance
+ *
+ * Set the distance from node @from to @to to @distance.
+ * If distance table doesn't exist, a warning is printed.
+ *
+ * If @from or @to is higher than the highest known node or lower than zero
+ * or @distance doesn't make sense, the call is ignored.
+ *
+ */
+void __init numa_set_distance(int from, int to, int distance)
+{
+	if (!numa_distance) {
+		pr_warn_once("NUMA: Warning: distance table not allocated yet\n");
+		return;
+	}
+
+	if (from >= numa_distance_cnt || to >= numa_distance_cnt ||
+			from < 0 || to < 0) {
+		pr_warn_once("NUMA: Warning: node ids are out of bound, from=%d to=%d distance=%d\n",
+			    from, to, distance);
+		return;
+	}
+
+	if ((u8)distance != distance ||
+	    (from == to && distance != LOCAL_DISTANCE)) {
+		pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
+			     from, to, distance);
+		return;
+	}
+
+	numa_distance[from * numa_distance_cnt + to] = distance;
+}
+
+/**
+ * Return NUMA distance @from to @to
+ */
+int __node_distance(int from, int to)
+{
+	if (from >= numa_distance_cnt || to >= numa_distance_cnt)
+		return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE;
+	return numa_distance[from * numa_distance_cnt + to];
+}
+EXPORT_SYMBOL(__node_distance);
+
+static int __init numa_register_nodes(void)
+{
+	int nid;
+	struct memblock_region *mblk;
+
+	/* Check that valid nid is set to memblks */
+	for_each_memblock(memory, mblk)
+		if (mblk->nid == NUMA_NO_NODE || mblk->nid >= MAX_NUMNODES) {
+			pr_warn("NUMA: Warning: invalid memblk node %d [mem %#010Lx-%#010Lx]\n",
+				mblk->nid, mblk->base,
+				mblk->base + mblk->size - 1);
+			return -EINVAL;
+		}
+
+	/* Finally register nodes. */
+	for_each_node_mask(nid, numa_nodes_parsed) {
+		unsigned long start_pfn, end_pfn;
+
+		get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
+		setup_node_data(nid, start_pfn, end_pfn);
+		node_set_online(nid);
+	}
+
+	/* Setup online nodes to actual nodes*/
+	node_possible_map = numa_nodes_parsed;
+
+	return 0;
+}
+
+static int __init numa_init(int (*init_func)(void))
+{
+	int ret;
+
+	nodes_clear(numa_nodes_parsed);
+	nodes_clear(node_possible_map);
+	nodes_clear(node_online_map);
+	numa_free_distance();
+
+	ret = numa_alloc_distance();
+	if (ret < 0)
+		return ret;
+
+	ret = init_func();
+	if (ret < 0)
+		return ret;
+
+	if (nodes_empty(numa_nodes_parsed))
+		return -EINVAL;
+
+	ret = numa_register_nodes();
+	if (ret < 0)
+		return ret;
+
+	setup_node_to_cpumask_map();
+
+	/* init boot processor */
+	cpu_to_node_map[0] = 0;
+	map_cpu_to_node(0, 0);
+
+	return 0;
+}
+
+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node (node 0) and add memory blocks that cover all
+ * allowed memory. It is unlikely that this function fails.
+ */
+static int __init dummy_numa_init(void)
+{
+	int ret;
+	struct memblock_region *mblk;
+
+	pr_info("%s\n", "No NUMA configuration found");
+	pr_info("NUMA: Faking a node at [mem %#018Lx-%#018Lx]\n",
+	       0LLU, PFN_PHYS(max_pfn) - 1);
+
+	for_each_memblock(memory, mblk) {
+		ret = numa_add_memblk(0, mblk->base, mblk->size);
+		if (!ret)
+			continue;
+
+		pr_err("NUMA init failed\n");
+		return ret;
+	}
+
+	numa_off = 1;
+	return 0;
+}
+
+/**
+ * arm64_numa_init - Initialize NUMA
+ *
+ * Try each configured NUMA initialization method until one succeeds.  The
+ * last fallback is dummy single node config encomapssing whole memory.
+ */
+void __init arm64_numa_init(void)
+{
+	if (!numa_off) {
+		if (!numa_init(of_numa_init))
+			return;
+	}
+
+	numa_init(dummy_numa_init);
+}
--- linux-4.4.0.orig/arch/arm64/mm/pageattr.c
+++ linux-4.4.0/arch/arm64/mm/pageattr.c
@@ -57,6 +57,9 @@
 	if (end < MODULES_VADDR || end >= MODULES_END)
 		return -EINVAL;
 
+	if (!numpages)
+		return 0;
+
 	data.set_mask = set_mask;
 	data.clear_mask = clear_mask;
 
--- linux-4.4.0.orig/arch/arm64/mm/proc-macros.S
+++ linux-4.4.0/arch/arm64/mm/proc-macros.S
@@ -62,3 +62,15 @@
 	bfi	\valreg, \tmpreg, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
 #endif
 	.endm
+
+/*
+ * reset_pmuserenr_el0 - reset PMUSERENR_EL0 if PMUv3 present
+ */
+	.macro	reset_pmuserenr_el0, tmpreg
+	mrs	\tmpreg, id_aa64dfr0_el1	// Check ID_AA64DFR0_EL1 PMUVer
+	sbfx	\tmpreg, \tmpreg, #8, #4
+	cmp	\tmpreg, #1			// Skip if no PMU present
+	b.lt	9000f
+	msr	pmuserenr_el0, xzr		// Disable PMU access from EL0
+9000:
+	.endm
--- linux-4.4.0.orig/arch/arm64/mm/proc.S
+++ linux-4.4.0/arch/arm64/mm/proc.S
@@ -25,6 +25,8 @@
 #include <asm/hwcap.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
+#include <asm/cpufeature.h>
+#include <asm/alternative.h>
 
 #include "proc-macros.S"
 
@@ -117,6 +119,7 @@
 	 */
 	ubfx	x11, x11, #1, #1
 	msr	oslar_el1, x11
+	reset_pmuserenr_el0 x0			// Disable PMU access from EL0
 	mov	x0, x12
 	dsb	nsh		// Make sure local tlb invalidation completed
 	isb
@@ -136,7 +139,17 @@
 	bfi	x0, x1, #48, #16		// set the ASID
 	msr	ttbr0_el1, x0			// set TTBR0
 	isb
+alternative_if_not ARM64_WORKAROUND_CAVIUM_27456
 	ret
+	nop
+	nop
+	nop
+alternative_else
+	ic	iallu
+	dsb	nsh
+	isb
+	ret
+alternative_endif
 ENDPROC(cpu_do_switch_mm)
 
 	.section ".text.init", #alloc, #execinstr
@@ -155,6 +168,9 @@
 	msr	cpacr_el1, x0			// Enable FP/ASIMD
 	mov	x0, #1 << 12			// Reset mdscr_el1 and disable
 	msr	mdscr_el1, x0			// access to the DCC from EL0
+	isb					// Unmask debug exceptions now,
+	enable_dbg				// since this is per-cpu
+	reset_pmuserenr_el0 x0			// Disable PMU access from EL0
 	/*
 	 * Memory region attributes for LPAE:
 	 *
@@ -205,6 +221,11 @@
 	cbz	x9, 2f
 	cmp	x9, #2
 	b.lt	1f
+#ifdef CONFIG_ARM64_ERRATUM_1024718
+	/* Disable hardware DBM on Cortex-A55 r0p0, r0p1 & r1p0 */
+	cpu_midr_match MIDR_CORTEX_A55, MIDR_CPU_VAR_REV(0, 0), MIDR_CPU_VAR_REV(1, 0), x1, x2, x3, x4
+	cbnz	x1, 1f
+#endif
 	orr	x10, x10, #TCR_HD		// hardware Dirty flag update
 1:	orr	x10, x10, #TCR_HA		// hardware Access flag update
 2:
--- linux-4.4.0.orig/arch/arm64/net/bpf_jit_comp.c
+++ linux-4.4.0/arch/arm64/net/bpf_jit_comp.c
@@ -482,6 +482,7 @@
 		case BPF_JGE:
 			jmp_cond = A64_COND_CS;
 			break;
+		case BPF_JSET:
 		case BPF_JNE:
 			jmp_cond = A64_COND_NE;
 			break;
@@ -728,14 +729,14 @@
 		int ret;
 
 		ret = build_insn(insn, ctx);
-
-		if (ctx->image == NULL)
-			ctx->offset[i] = ctx->idx;
-
 		if (ret > 0) {
 			i++;
+			if (ctx->image == NULL)
+				ctx->offset[i] = ctx->idx;
 			continue;
 		}
+		if (ctx->image == NULL)
+			ctx->offset[i] = ctx->idx;
 		if (ret)
 			return ret;
 	}
@@ -753,7 +754,7 @@
 	/* Nothing to do here. We support Internal BPF. */
 }
 
-void bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
 {
 	struct bpf_binary_header *header;
 	struct jit_ctx ctx;
@@ -761,7 +762,7 @@
 	u8 *image_ptr;
 
 	if (!bpf_jit_enable)
-		return;
+		return prog;
 
 	if (!prog || !prog->len)
 		return;
@@ -771,7 +772,7 @@
 
 	ctx.offset = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
 	if (ctx.offset == NULL)
-		return;
+		return prog;
 
 	/* 1. Initial fake pass to compute ctx->idx. */
 
@@ -816,6 +817,7 @@
 	prog->jited = 1;
 out:
 	kfree(ctx.offset);
+	return prog;
 }
 
 void bpf_jit_free(struct bpf_prog *prog)
--- linux-4.4.0.orig/arch/avr32/include/asm/uaccess.h
+++ linux-4.4.0/arch/avr32/include/asm/uaccess.h
@@ -74,7 +74,7 @@
 
 extern __kernel_size_t copy_to_user(void __user *to, const void *from,
 				    __kernel_size_t n);
-extern __kernel_size_t copy_from_user(void *to, const void __user *from,
+extern __kernel_size_t ___copy_from_user(void *to, const void __user *from,
 				      __kernel_size_t n);
 
 static inline __kernel_size_t __copy_to_user(void __user *to, const void *from,
@@ -88,6 +88,15 @@
 {
 	return __copy_user(to, (const void __force *)from, n);
 }
+static inline __kernel_size_t copy_from_user(void *to,
+					       const void __user *from,
+					       __kernel_size_t n)
+{
+	size_t res = ___copy_from_user(to, from, n);
+	if (unlikely(res))
+		memset(to + (n - res), 0, res);
+	return res;
+}
 
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
--- linux-4.4.0.orig/arch/avr32/kernel/avr32_ksyms.c
+++ linux-4.4.0/arch/avr32/kernel/avr32_ksyms.c
@@ -36,7 +36,7 @@
 /*
  * Userspace access stuff.
  */
-EXPORT_SYMBOL(copy_from_user);
+EXPORT_SYMBOL(___copy_from_user);
 EXPORT_SYMBOL(copy_to_user);
 EXPORT_SYMBOL(__copy_user);
 EXPORT_SYMBOL(strncpy_from_user);
--- linux-4.4.0.orig/arch/avr32/kernel/module.c
+++ linux-4.4.0/arch/avr32/kernel/module.c
@@ -118,9 +118,9 @@
 	 * Increase core size to make room for GOT and set start
 	 * offset for GOT.
 	 */
-	module->core_size = ALIGN(module->core_size, 4);
-	module->arch.got_offset = module->core_size;
-	module->core_size += module->arch.got_size;
+	module->core_layout.size = ALIGN(module->core_layout.size, 4);
+	module->arch.got_offset = module->core_layout.size;
+	module->core_layout.size += module->arch.got_size;
 
 	return 0;
 
@@ -177,7 +177,7 @@
 			if (!info->got_initialized) {
 				Elf32_Addr *gotent;
 
-				gotent = (module->module_core
+				gotent = (module->core_layout.base
 					  + module->arch.got_offset
 					  + info->got_offset);
 				*gotent = relocation;
@@ -255,8 +255,8 @@
 			 */
 			pr_debug("GOTPC: PC=0x%x, got_offset=0x%lx, core=0x%p\n",
 				 relocation, module->arch.got_offset,
-				 module->module_core);
-			relocation -= ((unsigned long)module->module_core
+				 module->core_layout.base);
+			relocation -= ((unsigned long)module->core_layout.base
 				       + module->arch.got_offset);
 			*location = relocation;
 			break;
--- linux-4.4.0.orig/arch/avr32/lib/copy_user.S
+++ linux-4.4.0/arch/avr32/lib/copy_user.S
@@ -23,13 +23,13 @@
 	 */
 	.text
 	.align	1
-	.global	copy_from_user
-	.type	copy_from_user, @function
-copy_from_user:
+	.global	___copy_from_user
+	.type	___copy_from_user, @function
+___copy_from_user:
 	branch_if_kernel r8, __copy_user
 	ret_if_privileged r8, r11, r10, r10
 	rjmp	__copy_user
-	.size	copy_from_user, . - copy_from_user
+	.size	___copy_from_user, . - ___copy_from_user
 
 	.global	copy_to_user
 	.type	copy_to_user, @function
--- linux-4.4.0.orig/arch/avr32/mach-at32ap/pio.c
+++ linux-4.4.0/arch/avr32/mach-at32ap/pio.c
@@ -435,7 +435,7 @@
 	struct resource *regs;
 	struct pio_device *pio;
 
-	if (pdev->id > MAX_NR_PIO_DEVICES) {
+	if (pdev->id >= MAX_NR_PIO_DEVICES) {
 		dev_err(&pdev->dev, "only %d PIO devices supported\n",
 			MAX_NR_PIO_DEVICES);
 		return;
--- linux-4.4.0.orig/arch/blackfin/Kconfig
+++ linux-4.4.0/arch/blackfin/Kconfig
@@ -318,11 +318,14 @@
 
 config GPIO_ADI
 	def_bool y
+	depends on !PINCTRL
 	depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561)
 
-config PINCTRL
+config PINCTRL_BLACKFIN_ADI2
 	def_bool y
-	depends on BF54x || BF60x
+	depends on (BF54x || BF60x)
+	select PINCTRL
+	select PINCTRL_ADI2
 
 config MEM_MT48LC64M4A2FB_7E
 	bool
--- linux-4.4.0.orig/arch/blackfin/Kconfig.debug
+++ linux-4.4.0/arch/blackfin/Kconfig.debug
@@ -17,6 +17,7 @@
 
 config DEBUG_MMRS
 	tristate "Generate Blackfin MMR tree"
+	depends on !PINCTRL
 	select DEBUG_FS
 	help
 	  Create a tree of Blackfin MMRs via the debugfs tree.  If
--- linux-4.4.0.orig/arch/blackfin/include/asm/uaccess.h
+++ linux-4.4.0/arch/blackfin/include/asm/uaccess.h
@@ -177,11 +177,12 @@
 static inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-	if (access_ok(VERIFY_READ, from, n))
+	if (likely(access_ok(VERIFY_READ, from, n))) {
 		memcpy(to, (const void __force *)from, n);
-	else
-		return n;
-	return 0;
+		return 0;
+	}
+	memset(to, 0, n);
+	return n;
 }
 
 static inline unsigned long __must_check
--- linux-4.4.0.orig/arch/blackfin/mach-bf561/boards/cm_bf561.c
+++ linux-4.4.0/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -146,7 +146,8 @@
 #include <linux/smc91x.h>
 
 static struct smc91x_platdata smc91x_info = {
-	.flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+	.flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+		 SMC91X_NOWAIT,
 	.leda = RPC_LED_100_10,
 	.ledb = RPC_LED_TX_RX,
 };
--- linux-4.4.0.orig/arch/blackfin/mach-bf561/boards/ezkit.c
+++ linux-4.4.0/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -134,7 +134,8 @@
 #include <linux/smc91x.h>
 
 static struct smc91x_platdata smc91x_info = {
-	.flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+	.flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+		 SMC91X_NOWAIT,
 	.leda = RPC_LED_100_10,
 	.ledb = RPC_LED_TX_RX,
 };
--- linux-4.4.0.orig/arch/c6x/kernel/ptrace.c
+++ linux-4.4.0/arch/c6x/kernel/ptrace.c
@@ -69,46 +69,6 @@
 				   0, sizeof(*regs));
 }
 
-static int gpr_set(struct task_struct *target,
-		   const struct user_regset *regset,
-		   unsigned int pos, unsigned int count,
-		   const void *kbuf, const void __user *ubuf)
-{
-	int ret;
-	struct pt_regs *regs = task_pt_regs(target);
-
-	/* Don't copyin TSR or CSR */
-	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 &regs,
-				 0, PT_TSR * sizeof(long));
-	if (ret)
-		return ret;
-
-	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-					PT_TSR * sizeof(long),
-					(PT_TSR + 1) * sizeof(long));
-	if (ret)
-		return ret;
-
-	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 &regs,
-				 (PT_TSR + 1) * sizeof(long),
-				 PT_CSR * sizeof(long));
-	if (ret)
-		return ret;
-
-	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-					PT_CSR * sizeof(long),
-					(PT_CSR + 1) * sizeof(long));
-	if (ret)
-		return ret;
-
-	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 &regs,
-				 (PT_CSR + 1) * sizeof(long), -1);
-	return ret;
-}
-
 enum c6x_regset {
 	REGSET_GPR,
 };
@@ -120,7 +80,6 @@
 		.size = sizeof(u32),
 		.align = sizeof(u32),
 		.get = gpr_get,
-		.set = gpr_set
 	},
 };
 
--- linux-4.4.0.orig/arch/cris/arch-v32/drivers/cryptocop.c
+++ linux-4.4.0/arch/cris/arch-v32/drivers/cryptocop.c
@@ -2724,7 +2724,6 @@
 			     (unsigned long int)(oper.indata + prev_ix),
 			     noinpages,
 			     0,  /* read access only for in data */
-			     0, /* no force */
 			     inpages,
 			     NULL);
 
@@ -2740,8 +2739,7 @@
 				     current->mm,
 				     (unsigned long int)oper.cipher_outdata,
 				     nooutpages,
-				     1, /* write access for out data */
-				     0, /* no force */
+				     FOLL_WRITE, /* write access for out data */
 				     outpages,
 				     NULL);
 		up_read(&current->mm->mmap_sem);
--- linux-4.4.0.orig/arch/cris/boot/rescue/Makefile
+++ linux-4.4.0/arch/cris/boot/rescue/Makefile
@@ -10,6 +10,9 @@
 
 asflags-y += $(LINUXINCLUDE)
 ccflags-y += -O2 $(LINUXINCLUDE)
+
+ifdef CONFIG_ETRAX_AXISFLASHMAP
+
 arch-$(CONFIG_ETRAX_ARCH_V10) = v10
 arch-$(CONFIG_ETRAX_ARCH_V32) = v32
 
@@ -28,6 +31,11 @@
 	$(call if_changed,objcopy)
 	cp -p $(obj)/rescue.bin $(objtree)
 
+else
+$(obj)/rescue.bin:
+
+endif
+
 $(obj)/testrescue.bin: $(obj)/testrescue.o
 	$(OBJCOPY) $(OBJCOPYFLAGS) $(obj)/testrescue.o tr.bin
 # Pad it to 784 bytes
--- linux-4.4.0.orig/arch/cris/include/asm/uaccess.h
+++ linux-4.4.0/arch/cris/include/asm/uaccess.h
@@ -194,30 +194,6 @@
 extern unsigned long __copy_user_zeroing(void *to, const void __user *from, unsigned long n);
 extern unsigned long __do_clear_user(void __user *to, unsigned long n);
 
-static inline unsigned long
-__generic_copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-	if (access_ok(VERIFY_WRITE, to, n))
-		return __copy_user(to, from, n);
-	return n;
-}
-
-static inline unsigned long
-__generic_copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-	if (access_ok(VERIFY_READ, from, n))
-		return __copy_user_zeroing(to, from, n);
-	return n;
-}
-
-static inline unsigned long
-__generic_clear_user(void __user *to, unsigned long n)
-{
-	if (access_ok(VERIFY_WRITE, to, n))
-		return __do_clear_user(to, n);
-	return n;
-}
-
 static inline long
 __strncpy_from_user(char *dst, const char __user *src, long count)
 {
@@ -282,7 +258,7 @@
 	else if (n == 24)
 		__asm_copy_from_user_24(to, from, ret);
 	else
-		ret = __generic_copy_from_user(to, from, n);
+		ret = __copy_user_zeroing(to, from, n);
 
 	return ret;
 }
@@ -333,7 +309,7 @@
 	else if (n == 24)
 		__asm_copy_to_user_24(to, from, ret);
 	else
-		ret = __generic_copy_to_user(to, from, n);
+		ret = __copy_user(to, from, n);
 
 	return ret;
 }
@@ -366,26 +342,43 @@
 	else if (n == 24)
 		__asm_clear_24(to, ret);
 	else
-		ret = __generic_clear_user(to, n);
+		ret = __do_clear_user(to, n);
 
 	return ret;
 }
 
 
-#define clear_user(to, n)				\
-	(__builtin_constant_p(n) ?			\
-	 __constant_clear_user(to, n) :			\
-	 __generic_clear_user(to, n))
-
-#define copy_from_user(to, from, n)			\
-	(__builtin_constant_p(n) ?			\
-	 __constant_copy_from_user(to, from, n) :	\
-	 __generic_copy_from_user(to, from, n))
-
-#define copy_to_user(to, from, n)			\
-	(__builtin_constant_p(n) ?			\
-	 __constant_copy_to_user(to, from, n) :		\
-	 __generic_copy_to_user(to, from, n))
+static inline size_t clear_user(void __user *to, size_t n)
+{
+	if (unlikely(!access_ok(VERIFY_WRITE, to, n)))
+		return n;
+	if (__builtin_constant_p(n))
+		return __constant_clear_user(to, n);
+	else
+		return __do_clear_user(to, n);
+}
+
+static inline size_t copy_from_user(void *to, const void __user *from, size_t n)
+{
+	if (unlikely(!access_ok(VERIFY_READ, from, n))) {
+		memset(to, 0, n);
+		return n;
+	}
+	if (__builtin_constant_p(n))
+		return __constant_copy_from_user(to, from, n);
+	else
+		return __copy_user_zeroing(to, from, n);
+}
+
+static inline size_t copy_to_user(void __user *to, const void *from, size_t n)
+{
+	if (unlikely(!access_ok(VERIFY_WRITE, to, n)))
+		return n;
+	if (__builtin_constant_p(n))
+		return __constant_copy_to_user(to, from, n);
+	else
+		return __copy_user(to, from, n);
+}
 
 /* We let the __ versions of copy_from/to_user inline, because they're often
  * used in fast paths and have only a small space overhead.
--- linux-4.4.0.orig/arch/frv/include/asm/futex.h
+++ linux-4.4.0/arch/frv/include/asm/futex.h
@@ -7,7 +7,8 @@
 #include <asm/errno.h>
 #include <asm/uaccess.h>
 
-extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);
+extern int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr);
 
 static inline int
 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
--- linux-4.4.0.orig/arch/frv/include/asm/timex.h
+++ linux-4.4.0/arch/frv/include/asm/timex.h
@@ -16,5 +16,11 @@
 #define vxtime_lock()		do {} while (0)
 #define vxtime_unlock()		do {} while (0)
 
+/* This attribute is used in include/linux/jiffies.h alongside with
+ * __cacheline_aligned_in_smp. It is assumed that __cacheline_aligned_in_smp
+ * for frv does not contain another section specification.
+ */
+#define __jiffy_arch_data	__attribute__((__section__(".data")))
+
 #endif
 
--- linux-4.4.0.orig/arch/frv/include/asm/uaccess.h
+++ linux-4.4.0/arch/frv/include/asm/uaccess.h
@@ -263,19 +263,25 @@
 extern long __memset_user(void *dst, unsigned long count);
 extern long __memcpy_user(void *dst, const void *src, unsigned long count);
 
-#define clear_user(dst,count)			__memset_user(____force(dst), (count))
+#define __clear_user(dst,count)			__memset_user(____force(dst), (count))
 #define __copy_from_user_inatomic(to, from, n)	__memcpy_user((to), ____force(from), (n))
 #define __copy_to_user_inatomic(to, from, n)	__memcpy_user(____force(to), (from), (n))
 
 #else
 
-#define clear_user(dst,count)			(memset(____force(dst), 0, (count)), 0)
+#define __clear_user(dst,count)			(memset(____force(dst), 0, (count)), 0)
 #define __copy_from_user_inatomic(to, from, n)	(memcpy((to), ____force(from), (n)), 0)
 #define __copy_to_user_inatomic(to, from, n)	(memcpy(____force(to), (from), (n)), 0)
 
 #endif
 
-#define __clear_user clear_user
+static inline unsigned long __must_check
+clear_user(void __user *to, unsigned long n)
+{
+	if (likely(__access_ok(to, n)))
+		n = __clear_user(to, n);
+	return n;
+}
 
 static inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
--- linux-4.4.0.orig/arch/frv/kernel/futex.c
+++ linux-4.4.0/arch/frv/kernel/futex.c
@@ -186,20 +186,10 @@
 /*
  * do the futex operations
  */
-int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 
 	switch (op) {
@@ -225,18 +215,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS; break;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
 
 	return ret;
 
-} /* end futex_atomic_op_inuser() */
+} /* end arch_futex_atomic_op_inuser() */
--- linux-4.4.0.orig/arch/frv/mm/elf-fdpic.c
+++ linux-4.4.0/arch/frv/mm/elf-fdpic.c
@@ -74,7 +74,7 @@
 		addr = PAGE_ALIGN(addr);
 		vma = find_vma(current->mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			goto success;
 	}
 
--- linux-4.4.0.orig/arch/h8300/Makefile
+++ linux-4.4.0/arch/h8300/Makefile
@@ -23,7 +23,7 @@
 LDFLAGS += $(ldflags-y)
 
 ifeq ($(CROSS_COMPILE),)
-CROSS_COMPILE := h8300-unknown-linux-
+CROSS_COMPILE := $(call cc-cross-prefix, h8300-unknown-linux- h8300-linux-)
 endif
 
 core-y	+= arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/
--- linux-4.4.0.orig/arch/h8300/include/asm/thread_info.h
+++ linux-4.4.0/arch/h8300/include/asm/thread_info.h
@@ -31,7 +31,6 @@
 	int		   cpu;			/* cpu we're on */
 	int		   preempt_count;	/* 0 => preemptable, <0 => BUG */
 	mm_segment_t		addr_limit;
-	struct restart_block restart_block;
 };
 
 /*
@@ -44,9 +43,6 @@
 	.cpu =		0,			\
 	.preempt_count = INIT_PREEMPT_COUNT,	\
 	.addr_limit	= KERNEL_DS,		\
-	.restart_block	= {			\
-		.fn = do_no_restart_syscall,	\
-	},					\
 }
 
 #define init_thread_info	(init_thread_union.thread_info)
--- linux-4.4.0.orig/arch/h8300/kernel/asm-offsets.c
+++ linux-4.4.0/arch/h8300/kernel/asm-offsets.c
@@ -62,6 +62,9 @@
 	OFFSET(TI_FLAGS, thread_info, flags);
 	OFFSET(TI_CPU, thread_info, cpu);
 	OFFSET(TI_PRE, thread_info, preempt_count);
+#ifdef CONFIG_PREEMPTION
+	DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
+#endif
 
 	return 0;
 }
--- linux-4.4.0.orig/arch/h8300/kernel/ptrace.c
+++ linux-4.4.0/arch/h8300/kernel/ptrace.c
@@ -95,7 +95,8 @@
 	long *reg = (long *)&regs;
 
 	/* build user regs in buffer */
-	for (r = 0; r < ARRAY_SIZE(register_offset); r++)
+	BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0);
+	for (r = 0; r < sizeof(regs) / sizeof(long); r++)
 		*reg++ = h8300_get_reg(target, r);
 
 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
@@ -113,7 +114,8 @@
 	long *reg;
 
 	/* build user regs in buffer */
-	for (reg = (long *)&regs, r = 0; r < ARRAY_SIZE(register_offset); r++)
+	BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0);
+	for (reg = (long *)&regs, r = 0; r < sizeof(regs) / sizeof(long); r++)
 		*reg++ = h8300_get_reg(target, r);
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
@@ -122,7 +124,7 @@
 		return ret;
 
 	/* write back to pt_regs */
-	for (reg = (long *)&regs, r = 0; r < ARRAY_SIZE(register_offset); r++)
+	for (reg = (long *)&regs, r = 0; r < sizeof(regs) / sizeof(long); r++)
 		h8300_put_reg(target, r, *reg++);
 	return 0;
 }
--- linux-4.4.0.orig/arch/h8300/kernel/signal.c
+++ linux-4.4.0/arch/h8300/kernel/signal.c
@@ -79,7 +79,7 @@
 	unsigned int er0;
 
 	/* Always make any pending restarted system calls return -EINTR */
-	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+	current->restart_block.fn = do_no_restart_syscall;
 
 	/* restore passed registers */
 #define COPY(r)  do { err |= get_user(regs->r, &usc->sc_##r); } while (0)
--- linux-4.4.0.orig/arch/hexagon/include/asm/bitops.h
+++ linux-4.4.0/arch/hexagon/include/asm/bitops.h
@@ -211,7 +211,7 @@
  * This is defined the same way as ffs.
  * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
  */
-static inline long fls(int x)
+static inline int fls(int x)
 {
 	int r;
 
@@ -232,7 +232,7 @@
  * the libc and compiler builtin ffs routines, therefore
  * differs in spirit from the above ffz (man ffs).
  */
-static inline long ffs(int x)
+static inline int ffs(int x)
 {
 	int r;
 
--- linux-4.4.0.orig/arch/hexagon/include/asm/futex.h
+++ linux-4.4.0/arch/hexagon/include/asm/futex.h
@@ -31,18 +31,9 @@
 
 
 static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -72,30 +63,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (oldval == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (oldval != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (oldval < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (oldval >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (oldval <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (oldval > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/hexagon/include/asm/uaccess.h
+++ linux-4.4.0/arch/hexagon/include/asm/uaccess.h
@@ -103,7 +103,8 @@
 {
 	long res = __strnlen_user(src, n);
 
-	/* return from strnlen can't be zero -- that would be rubbish. */
+	if (unlikely(!res))
+		return -EFAULT;
 
 	if (res > n) {
 		copy_from_user(dst, src, n);
--- linux-4.4.0.orig/arch/hexagon/kernel/dma.c
+++ linux-4.4.0/arch/hexagon/kernel/dma.c
@@ -68,7 +68,7 @@
 			panic("Can't create %s() memory pool!", __func__);
 		else
 			gen_pool_add(coherent_pool,
-				pfn_to_virt(max_low_pfn),
+				(unsigned long)pfn_to_virt(max_low_pfn),
 				hexagon_coherent_pool_size, -1);
 	}
 
--- linux-4.4.0.orig/arch/hexagon/kernel/stacktrace.c
+++ linux-4.4.0/arch/hexagon/kernel/stacktrace.c
@@ -23,8 +23,6 @@
 #include <linux/thread_info.h>
 #include <linux/module.h>
 
-register unsigned long current_frame_pointer asm("r30");
-
 struct stackframe {
 	unsigned long fp;
 	unsigned long rets;
@@ -42,7 +40,7 @@
 
 	low = (unsigned long)task_stack_page(current);
 	high = low + THREAD_SIZE;
-	fp = current_frame_pointer;
+	fp = (unsigned long)__builtin_frame_address(0);
 
 	while (fp >= low && fp <= (high - sizeof(*frame))) {
 		frame = (struct stackframe *)fp;
--- linux-4.4.0.orig/arch/ia64/include/asm/barrier.h
+++ linux-4.4.0/arch/ia64/include/asm/barrier.h
@@ -77,7 +77,7 @@
 	___p1;								\
 })
 
-#define smp_store_mb(var, value)	do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
 /*
  * The group barrier in front of the rsm & ssm are necessary to ensure
--- linux-4.4.0.orig/arch/ia64/include/asm/bug.h
+++ linux-4.4.0/arch/ia64/include/asm/bug.h
@@ -3,7 +3,11 @@
 
 #ifdef CONFIG_BUG
 #define ia64_abort()	__builtin_trap()
-#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0)
+#define BUG() do {						\
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__);	\
+	barrier_before_unreachable();				\
+	ia64_abort();						\
+} while (0)
 
 /* should this BUG be made generic? */
 #define HAVE_ARCH_BUG
--- linux-4.4.0.orig/arch/ia64/include/asm/futex.h
+++ linux-4.4.0/arch/ia64/include/asm/futex.h
@@ -45,18 +45,9 @@
 } while (0)
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -84,17 +75,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/ia64/include/asm/io.h
+++ linux-4.4.0/arch/ia64/include/asm/io.h
@@ -436,6 +436,7 @@
 	return ioremap(phys_addr, size);
 }
 #define ioremap_cache ioremap_cache
+#define ioremap_uc ioremap_nocache
 
 
 /*
--- linux-4.4.0.orig/arch/ia64/include/asm/tlb.h
+++ linux-4.4.0/arch/ia64/include/asm/tlb.h
@@ -251,6 +251,16 @@
 	tlb->end_addr = address + PAGE_SIZE;
 }
 
+static inline void
+tlb_flush_pmd_range(struct mmu_gather *tlb, unsigned long address,
+		    unsigned long size)
+{
+	if (tlb->start_addr > address)
+		tlb->start_addr = address;
+	if (tlb->end_addr < address + size)
+		tlb->end_addr = address + size;
+}
+
 #define tlb_migrate_finish(mm)	platform_tlb_migrate_finish(mm)
 
 #define tlb_start_vma(tlb, vma)			do { } while (0)
--- linux-4.4.0.orig/arch/ia64/include/asm/uaccess.h
+++ linux-4.4.0/arch/ia64/include/asm/uaccess.h
@@ -263,17 +263,15 @@
 	__cu_len;									\
 })
 
-#define copy_from_user(to, from, n)							\
-({											\
-	void *__cu_to = (to);								\
-	const void __user *__cu_from = (from);						\
-	long __cu_len = (n);								\
-											\
-	__chk_user_ptr(__cu_from);							\
-	if (__access_ok(__cu_from, __cu_len, get_fs()))					\
-		__cu_len = __copy_user((__force void __user *) __cu_to, __cu_from, __cu_len);	\
-	__cu_len;									\
-})
+static inline unsigned long
+copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+	if (likely(__access_ok(from, n, get_fs())))
+		n = __copy_user((__force void __user *) to, from, n);
+	else
+		memset(to, 0, n);
+	return n;
+}
 
 #define __copy_in_user(to, from, size)	__copy_user((to), (from), (size))
 
--- linux-4.4.0.orig/arch/ia64/kernel/Makefile
+++ linux-4.4.0/arch/ia64/kernel/Makefile
@@ -42,7 +42,7 @@
 obj-$(CONFIG_INTEL_IOMMU)	+= pci-dma.o
 obj-$(CONFIG_SWIOTLB)		+= pci-swiotlb.o
 
-obj-$(CONFIG_BINFMT_ELF)	+= elfcore.o
+obj-$(CONFIG_ELF_CORE)		+= elfcore.o
 
 # fp_emulate() expects f2-f5,f16-f31 to contain the user-level state.
 CFLAGS_traps.o  += -mfixed-range=f2-f5,f16-f31
@@ -50,32 +50,10 @@
 # The gate DSO image is built using a special linker script.
 include $(src)/Makefile.gate
 
-# Calculate NR_IRQ = max(IA64_NATIVE_NR_IRQS, XEN_NR_IRQS, ...) based on config
-define sed-y
-	"/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
-endef
-quiet_cmd_nr_irqs = GEN     $@
-define cmd_nr_irqs
-	(set -e; \
-	 echo "#ifndef __ASM_NR_IRQS_H__"; \
-	 echo "#define __ASM_NR_IRQS_H__"; \
-	 echo "/*"; \
-	 echo " * DO NOT MODIFY."; \
-	 echo " *"; \
-	 echo " * This file was generated by Kbuild"; \
-	 echo " *"; \
-	 echo " */"; \
-	 echo ""; \
-	 sed -ne $(sed-y) $<; \
-	 echo ""; \
-	 echo "#endif" ) > $@
-endef
-
 # We use internal kbuild rules to avoid the "is up to date" message from make
 arch/$(SRCARCH)/kernel/nr-irqs.s: arch/$(SRCARCH)/kernel/nr-irqs.c
 	$(Q)mkdir -p $(dir $@)
 	$(call if_changed_dep,cc_s_c)
 
-include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
-	$(Q)mkdir -p $(dir $@)
-	$(call cmd,nr_irqs)
+include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s FORCE
+	$(call filechk,offsets,__ASM_NR_IRQS_H__)
--- linux-4.4.0.orig/arch/ia64/kernel/err_inject.c
+++ linux-4.4.0/arch/ia64/kernel/err_inject.c
@@ -143,7 +143,7 @@
 	int ret;
 
         ret = get_user_pages(current, current->mm, virt_addr,
-                        1, VM_READ, 0, NULL, NULL);
+			     1, FOLL_WRITE, NULL, NULL);
 	if (ret<=0) {
 #ifdef ERR_INJ_DEBUG
 		printk("Virtual address %lx is not existing.\n",virt_addr);
--- linux-4.4.0.orig/arch/ia64/kernel/module.c
+++ linux-4.4.0/arch/ia64/kernel/module.c
@@ -153,7 +153,7 @@
 static int
 apply_imm64 (struct module *mod, struct insn *insn, uint64_t val)
 {
-	if (slot(insn) != 2) {
+	if (slot(insn) != 1 && slot(insn) != 2) {
 		printk(KERN_ERR "%s: invalid slot number %d for IMM64\n",
 		       mod->name, slot(insn));
 		return 0;
@@ -165,7 +165,7 @@
 static int
 apply_imm60 (struct module *mod, struct insn *insn, uint64_t val)
 {
-	if (slot(insn) != 2) {
+	if (slot(insn) != 1 && slot(insn) != 2) {
 		printk(KERN_ERR "%s: invalid slot number %d for IMM60\n",
 		       mod->name, slot(insn));
 		return 0;
@@ -486,13 +486,13 @@
 static inline int
 in_init (const struct module *mod, uint64_t addr)
 {
-	return addr - (uint64_t) mod->module_init < mod->init_size;
+	return addr - (uint64_t) mod->init_layout.base < mod->init_layout.size;
 }
 
 static inline int
 in_core (const struct module *mod, uint64_t addr)
 {
-	return addr - (uint64_t) mod->module_core < mod->core_size;
+	return addr - (uint64_t) mod->core_layout.base < mod->core_layout.size;
 }
 
 static inline int
@@ -675,7 +675,7 @@
 		break;
 
 	      case RV_BDREL:
-		val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core);
+		val -= (uint64_t) (in_init(mod, val) ? mod->init_layout.base : mod->core_layout.base);
 		break;
 
 	      case RV_LTV:
@@ -810,15 +810,15 @@
 		 *     addresses have been selected...
 		 */
 		uint64_t gp;
-		if (mod->core_size > MAX_LTOFF)
+		if (mod->core_layout.size > MAX_LTOFF)
 			/*
 			 * This takes advantage of fact that SHF_ARCH_SMALL gets allocated
 			 * at the end of the module.
 			 */
-			gp = mod->core_size - MAX_LTOFF / 2;
+			gp = mod->core_layout.size - MAX_LTOFF / 2;
 		else
-			gp = mod->core_size / 2;
-		gp = (uint64_t) mod->module_core + ((gp + 7) & -8);
+			gp = mod->core_layout.size / 2;
+		gp = (uint64_t) mod->core_layout.base + ((gp + 7) & -8);
 		mod->arch.gp = gp;
 		DEBUGP("%s: placing gp at 0x%lx\n", __func__, gp);
 	}
@@ -912,8 +912,12 @@
 void
 module_arch_cleanup (struct module *mod)
 {
-	if (mod->arch.init_unw_table)
+	if (mod->arch.init_unw_table) {
 		unw_remove_unwind_table(mod->arch.init_unw_table);
-	if (mod->arch.core_unw_table)
+		mod->arch.init_unw_table = NULL;
+	}
+	if (mod->arch.core_unw_table) {
 		unw_remove_unwind_table(mod->arch.core_unw_table);
+		mod->arch.core_unw_table = NULL;
+	}
 }
--- linux-4.4.0.orig/arch/ia64/mm/numa.c
+++ linux-4.4.0/arch/ia64/mm/numa.c
@@ -49,6 +49,7 @@
 
 	return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0);
 }
+EXPORT_SYMBOL(paddr_to_nid);
 
 #if defined(CONFIG_SPARSEMEM) && defined(CONFIG_NUMA)
 /*
--- linux-4.4.0.orig/arch/m32r/include/asm/uaccess.h
+++ linux-4.4.0/arch/m32r/include/asm/uaccess.h
@@ -219,7 +219,7 @@
 #define __get_user_nocheck(x, ptr, size)				\
 ({									\
 	long __gu_err = 0;						\
-	unsigned long __gu_val;						\
+	unsigned long __gu_val = 0;					\
 	might_fault();							\
 	__get_user_size(__gu_val, (ptr), (size), __gu_err);		\
 	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
--- linux-4.4.0.orig/arch/m32r/kernel/setup.c
+++ linux-4.4.0/arch/m32r/kernel/setup.c
@@ -81,7 +81,10 @@
 };
 
 unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
+
 unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
 
 void __init setup_arch(char **);
 int get_cpuinfo(char *);
--- linux-4.4.0.orig/arch/m68k/Makefile
+++ linux-4.4.0/arch/m68k/Makefile
@@ -59,7 +59,10 @@
 cpuflags-$(CONFIG_M5206)	:= $(call cc-option,-mcpu=5206,-m5200)
 
 KBUILD_AFLAGS += $(cpuflags-y)
-KBUILD_CFLAGS += $(cpuflags-y) -pipe
+KBUILD_CFLAGS += $(cpuflags-y)
+
+KBUILD_CFLAGS += -pipe -ffreestanding
+
 ifdef CONFIG_MMU
 # without -fno-strength-reduce the 53c7xx.c driver fails ;-(
 KBUILD_CFLAGS += -fno-strength-reduce -ffixed-a2
--- linux-4.4.0.orig/arch/m68k/amiga/cia.c
+++ linux-4.4.0/arch/m68k/amiga/cia.c
@@ -88,10 +88,19 @@
 	struct ciabase *base = dev_id;
 	int mach_irq;
 	unsigned char ints;
+	unsigned long flags;
 
+	/* Interrupts get disabled while the timer irq flag is cleared and
+	 * the timer interrupt serviced.
+	 */
 	mach_irq = base->cia_irq;
+	local_irq_save(flags);
 	ints = cia_set_irq(base, CIA_ICR_ALL);
 	amiga_custom.intreq = base->int_mask;
+	if (ints & 1)
+		generic_handle_irq(mach_irq);
+	local_irq_restore(flags);
+	mach_irq++, ints >>= 1;
 	for (; ints; mach_irq++, ints >>= 1) {
 		if (ints & 1)
 			generic_handle_irq(mach_irq);
--- linux-4.4.0.orig/arch/m68k/atari/ataints.c
+++ linux-4.4.0/arch/m68k/atari/ataints.c
@@ -142,7 +142,7 @@
 	.name		= "MFP Timer D"
 };
 
-static irqreturn_t mfptimer_handler(int irq, void *dev_id)
+static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id)
 {
 	struct mfptimerbase *base = dev_id;
 	int mach_irq;
@@ -344,7 +344,7 @@
 	st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6;
 
 	/* request timer D dispatch handler */
-	if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED,
+	if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED,
 			stmfp_base.name, &stmfp_base))
 		pr_err("Couldn't register %s interrupt\n", stmfp_base.name);
 
--- linux-4.4.0.orig/arch/m68k/atari/time.c
+++ linux-4.4.0/arch/m68k/atari/time.c
@@ -24,6 +24,18 @@
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL_GPL(rtc_lock);
 
+static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id)
+{
+	irq_handler_t timer_routine = dev_id;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	timer_routine(0, NULL);
+	local_irq_restore(flags);
+
+	return IRQ_HANDLED;
+}
+
 void __init
 atari_sched_init(irq_handler_t timer_routine)
 {
@@ -32,7 +44,8 @@
     /* start timer C, div = 1:100 */
     st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
     /* install interrupt service routine for MFP Timer C */
-    if (request_irq(IRQ_MFP_TIMC, timer_routine, 0, "timer", timer_routine))
+    if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, 0, "timer",
+                    timer_routine))
 	pr_err("Couldn't register timer interrupt\n");
 }
 
--- linux-4.4.0.orig/arch/m68k/bvme6000/config.c
+++ linux-4.4.0/arch/m68k/bvme6000/config.c
@@ -46,11 +46,6 @@
 extern void bvme6000_reset (void);
 void bvme6000_set_vectors (void);
 
-/* Save tick handler routine pointer, will point to xtime_update() in
- * kernel/timer/timekeeping.c, called via bvme6000_process_int() */
-
-static irq_handler_t tick_handler;
-
 
 int __init bvme6000_parse_bootinfo(const struct bi_record *bi)
 {
@@ -160,12 +155,18 @@
 
 static irqreturn_t bvme6000_timer_int (int irq, void *dev_id)
 {
+    irq_handler_t timer_routine = dev_id;
+    unsigned long flags;
     volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
-    unsigned char msr = rtc->msr & 0xc0;
+    unsigned char msr;
 
+    local_irq_save(flags);
+    msr = rtc->msr & 0xc0;
     rtc->msr = msr | 0x20;		/* Ack the interrupt */
+    timer_routine(0, NULL);
+    local_irq_restore(flags);
 
-    return tick_handler(irq, dev_id);
+    return IRQ_HANDLED;
 }
 
 /*
@@ -184,9 +185,8 @@
 
     rtc->msr = 0;	/* Ensure timer registers accessible */
 
-    tick_handler = timer_routine;
-    if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0,
-				"timer", bvme6000_timer_int))
+    if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, "timer",
+                    timer_routine))
 	panic ("Couldn't register timer int");
 
     rtc->t1cr_omr = 0x04;	/* Mode 2, ext clk */
--- linux-4.4.0.orig/arch/m68k/coldfire/device.c
+++ linux-4.4.0/arch/m68k/coldfire/device.c
@@ -135,7 +135,11 @@
 	.id			= 0,
 	.num_resources		= ARRAY_SIZE(mcf_fec0_resources),
 	.resource		= mcf_fec0_resources,
-	.dev.platform_data	= FEC_PDATA,
+	.dev = {
+		.dma_mask		= &mcf_fec0.dev.coherent_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= FEC_PDATA,
+	}
 };
 
 #ifdef MCFFEC_BASE1
@@ -167,7 +171,11 @@
 	.id			= 1,
 	.num_resources		= ARRAY_SIZE(mcf_fec1_resources),
 	.resource		= mcf_fec1_resources,
-	.dev.platform_data	= FEC_PDATA,
+	.dev = {
+		.dma_mask		= &mcf_fec1.dev.coherent_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= FEC_PDATA,
+	}
 };
 #endif /* MCFFEC_BASE1 */
 #endif /* CONFIG_FEC */
--- linux-4.4.0.orig/arch/m68k/hp300/time.c
+++ linux-4.4.0/arch/m68k/hp300/time.c
@@ -37,13 +37,19 @@
 
 static irqreturn_t hp300_tick(int irq, void *dev_id)
 {
+	irq_handler_t timer_routine = dev_id;
+	unsigned long flags;
 	unsigned long tmp;
-	irq_handler_t vector = dev_id;
+
+	local_irq_save(flags);
 	in_8(CLOCKBASE + CLKSR);
 	asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
+	timer_routine(0, NULL);
+	local_irq_restore(flags);
+
 	/* Turn off the network and SCSI leds */
 	blinken_leds(0, 0xe0);
-	return vector(irq, NULL);
+	return IRQ_HANDLED;
 }
 
 u32 hp300_gettimeoffset(void)
--- linux-4.4.0.orig/arch/m68k/include/asm/bug.h
+++ linux-4.4.0/arch/m68k/include/asm/bug.h
@@ -7,16 +7,19 @@
 #ifndef CONFIG_SUN3
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	barrier_before_unreachable(); \
 	__builtin_trap(); \
 } while (0)
 #else
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	barrier_before_unreachable(); \
 	panic("BUG!"); \
 } while (0)
 #endif
 #else
 #define BUG() do { \
+	barrier_before_unreachable(); \
 	__builtin_trap(); \
 } while (0)
 #endif
--- linux-4.4.0.orig/arch/m68k/include/asm/delay.h
+++ linux-4.4.0/arch/m68k/include/asm/delay.h
@@ -114,6 +114,6 @@
  */
 #define	HZSCALE		(268435456 / (1000000 / HZ))
 
-#define ndelay(n) __delay(DIV_ROUND_UP((n) * ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6), 1000));
+#define ndelay(n) __delay(DIV_ROUND_UP((n) * ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6), 1000))
 
 #endif /* defined(_M68K_DELAY_H) */
--- linux-4.4.0.orig/arch/m68k/include/asm/m53xxacr.h
+++ linux-4.4.0/arch/m68k/include/asm/m53xxacr.h
@@ -88,9 +88,9 @@
  * coherency though in all cases. And for copyback caches we will need
  * to push cached data as well.
  */
-#define CACHE_INIT	  CACR_CINVA
-#define CACHE_INVALIDATE  CACR_CINVA
-#define CACHE_INVALIDATED CACR_CINVA
+#define CACHE_INIT        (CACHE_MODE + CACR_CINVA - CACR_EC)
+#define CACHE_INVALIDATE  (CACHE_MODE + CACR_CINVA)
+#define CACHE_INVALIDATED (CACHE_MODE + CACR_CINVA)
 
 #define ACR0_MODE	((CONFIG_RAMBASE & 0xff000000) + \
 			 (0x000f0000) + \
--- linux-4.4.0.orig/arch/m68k/include/asm/mac_via.h
+++ linux-4.4.0/arch/m68k/include/asm/mac_via.h
@@ -256,6 +256,7 @@
 
 struct irq_desc;
 
+extern void via_l2_flush(int writeback);
 extern void via_register_interrupts(void);
 extern void via_irq_enable(int);
 extern void via_irq_disable(int);
--- linux-4.4.0.orig/arch/m68k/include/asm/mcf_pgalloc.h
+++ linux-4.4.0/arch/m68k/include/asm/mcf_pgalloc.h
@@ -43,6 +43,7 @@
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page,
 				  unsigned long address)
 {
+	pgtable_page_dtor(page);
 	__free_page(page);
 }
 
@@ -73,8 +74,9 @@
 	return page;
 }
 
-extern inline void pte_free(struct mm_struct *mm, struct page *page)
+static inline void pte_free(struct mm_struct *mm, struct page *page)
 {
+	pgtable_page_dtor(page);
 	__free_page(page);
 }
 
--- linux-4.4.0.orig/arch/m68k/mac/config.c
+++ linux-4.4.0/arch/m68k/mac/config.c
@@ -60,7 +60,6 @@
 extern void iop_init(void);
 extern void via_init(void);
 extern void via_init_clock(irq_handler_t func);
-extern void via_flush_cache(void);
 extern void oss_init(void);
 extern void psc_init(void);
 extern void baboon_init(void);
@@ -131,21 +130,6 @@
 	return unknown;
 }
 
-/*
- * Flip into 24bit mode for an instant - flushes the L2 cache card. We
- * have to disable interrupts for this. Our IRQ handlers will crap
- * themselves if they take an IRQ in 24bit mode!
- */
-
-static void mac_cache_card_flush(int writeback)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	via_flush_cache();
-	local_irq_restore(flags);
-}
-
 void __init config_mac(void)
 {
 	if (!MACH_IS_MAC)
@@ -178,9 +162,8 @@
 	 * not.
 	 */
 
-	if (macintosh_config->ident == MAC_MODEL_IICI
-	    || macintosh_config->ident == MAC_MODEL_IIFX)
-		mach_l2_flush = mac_cache_card_flush;
+	if (macintosh_config->ident == MAC_MODEL_IICI)
+		mach_l2_flush = via_l2_flush;
 }
 
 
--- linux-4.4.0.orig/arch/m68k/mac/iop.c
+++ linux-4.4.0/arch/m68k/mac/iop.c
@@ -173,7 +173,7 @@
 
 static __inline__ void iop_stop(volatile struct mac_iop *iop)
 {
-	iop->status_ctrl &= ~IOP_RUN;
+	iop->status_ctrl = IOP_AUTOINC;
 }
 
 static __inline__ void iop_start(volatile struct mac_iop *iop)
@@ -181,14 +181,9 @@
 	iop->status_ctrl = IOP_RUN | IOP_AUTOINC;
 }
 
-static __inline__ void iop_bypass(volatile struct mac_iop *iop)
-{
-	iop->status_ctrl |= IOP_BYPASS;
-}
-
 static __inline__ void iop_interrupt(volatile struct mac_iop *iop)
 {
-	iop->status_ctrl |= IOP_IRQ;
+	iop->status_ctrl = IOP_IRQ | IOP_RUN | IOP_AUTOINC;
 }
 
 static int iop_alive(volatile struct mac_iop *iop)
@@ -239,7 +234,6 @@
 		} else {
 			iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_QUADRA;
 		}
-		iop_base[IOP_NUM_SCC]->status_ctrl = 0x87;
 		iop_scc_present = 1;
 	} else {
 		iop_base[IOP_NUM_SCC] = NULL;
@@ -251,7 +245,7 @@
 		} else {
 			iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_QUADRA;
 		}
-		iop_base[IOP_NUM_ISM]->status_ctrl = 0;
+		iop_stop(iop_base[IOP_NUM_ISM]);
 		iop_ism_present = 1;
 	} else {
 		iop_base[IOP_NUM_ISM] = NULL;
@@ -416,7 +410,8 @@
 	iop_free_msg(msg2);
 
 	iop_send_queue[iop_num][chan] = msg;
-	if (msg) iop_do_send(msg);
+	if (msg && iop_readb(iop, IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE)
+		iop_do_send(msg);
 }
 
 /*
@@ -497,16 +492,12 @@
 
 	if (!(q = iop_send_queue[iop_num][chan])) {
 		iop_send_queue[iop_num][chan] = msg;
+		iop_do_send(msg);
 	} else {
 		while (q->next) q = q->next;
 		q->next = msg;
 	}
 
-	if (iop_readb(iop_base[iop_num],
-	    IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE) {
-		iop_do_send(msg);
-	}
-
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/m68k/mac/via.c
+++ linux-4.4.0/arch/m68k/mac/via.c
@@ -54,16 +54,6 @@
 static int gIER,gIFR,gBufA,gBufB;
 
 /*
- * Timer defs.
- */
-
-#define TICK_SIZE		10000
-#define MAC_CLOCK_TICK		(783300/HZ)		/* ticks per HZ */
-#define MAC_CLOCK_LOW		(MAC_CLOCK_TICK&0xFF)
-#define MAC_CLOCK_HIGH		(MAC_CLOCK_TICK>>8)
-
-
-/*
  * On Macs with a genuine VIA chip there is no way to mask an individual slot
  * interrupt. This limitation also seems to apply to VIA clone logic cores in
  * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.)
@@ -278,22 +268,6 @@
 }
 
 /*
- * Start the 100 Hz clock
- */
-
-void __init via_init_clock(irq_handler_t func)
-{
-	via1[vACR] |= 0x40;
-	via1[vT1LL] = MAC_CLOCK_LOW;
-	via1[vT1LH] = MAC_CLOCK_HIGH;
-	via1[vT1CL] = MAC_CLOCK_LOW;
-	via1[vT1CH] = MAC_CLOCK_HIGH;
-
-	if (request_irq(IRQ_MAC_TIMER_1, func, 0, "timer", func))
-		pr_err("Couldn't register %s interrupt\n", "timer");
-}
-
-/*
  * Debugging dump, used in various places to see what's going on.
  */
 
@@ -321,37 +295,18 @@
 }
 
 /*
- * This is always executed with interrupts disabled.
- *
- * TBI: get time offset between scheduling timer ticks
- */
-
-u32 mac_gettimeoffset(void)
-{
-	unsigned long ticks, offset = 0;
-
-	/* read VIA1 timer 2 current value */
-	ticks = via1[vT1CL] | (via1[vT1CH] << 8);
-	/* The probability of underflow is less than 2% */
-	if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50)
-		/* Check for pending timer interrupt in VIA1 IFR */
-		if (via1[vIFR] & 0x40) offset = TICK_SIZE;
-
-	ticks = MAC_CLOCK_TICK - ticks;
-	ticks = ticks * 10000L / MAC_CLOCK_TICK;
-
-	return (ticks + offset) * 1000;
-}
-
-/*
  * Flush the L2 cache on Macs that have it by flipping
  * the system into 24-bit mode for an instant.
  */
 
-void via_flush_cache(void)
+void via_l2_flush(int writeback)
 {
+	unsigned long flags;
+
+	local_irq_save(flags);
 	via2[gBufB] &= ~VIA2B_vMode32;
 	via2[gBufB] |= VIA2B_vMode32;
+	local_irq_restore(flags);
 }
 
 /*
@@ -446,6 +401,8 @@
  * via6522.c :-), disable/pending masks added.
  */
 
+#define VIA_TIMER_1_INT BIT(6)
+
 void via1_irq(struct irq_desc *desc)
 {
 	int irq_num;
@@ -455,6 +412,21 @@
 	if (!events)
 		return;
 
+	irq_num = IRQ_MAC_TIMER_1;
+	irq_bit = VIA_TIMER_1_INT;
+	if (events & irq_bit) {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		via1[vIFR] = irq_bit;
+		generic_handle_irq(irq_num);
+		local_irq_restore(flags);
+
+		events &= ~irq_bit;
+		if (!events)
+			return;
+	}
+
 	irq_num = VIA1_SOURCE_BASE;
 	irq_bit = 1;
 	do {
@@ -619,3 +591,56 @@
 	return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ));
 }
 EXPORT_SYMBOL(via2_scsi_drq_pending);
+
+/* timer and clock source */
+
+#define VIA_CLOCK_FREQ     783360                /* VIA "phase 2" clock in Hz */
+#define VIA_TIMER_INTERVAL (1000000 / HZ)        /* microseconds per jiffy */
+#define VIA_TIMER_CYCLES   (VIA_CLOCK_FREQ / HZ) /* clock cycles per jiffy */
+
+#define VIA_TC             (VIA_TIMER_CYCLES - 2) /* including 0 and -1 */
+#define VIA_TC_LOW         (VIA_TC & 0xFF)
+#define VIA_TC_HIGH        (VIA_TC >> 8)
+
+void __init via_init_clock(irq_handler_t timer_routine)
+{
+	if (request_irq(IRQ_MAC_TIMER_1, timer_routine, 0, "timer", NULL)) {
+		pr_err("Couldn't register %s interrupt\n", "timer");
+		return;
+	}
+
+	via1[vT1LL] = VIA_TC_LOW;
+	via1[vT1LH] = VIA_TC_HIGH;
+	via1[vT1CL] = VIA_TC_LOW;
+	via1[vT1CH] = VIA_TC_HIGH;
+	via1[vACR] |= 0x40;
+}
+
+u32 mac_gettimeoffset(void)
+{
+	unsigned long flags;
+	u8 count_high;
+	u16 count, offset = 0;
+
+	/*
+	 * Timer counter wrap-around is detected with the timer interrupt flag
+	 * but reading the counter low byte (vT1CL) would reset the flag.
+	 * Also, accessing both counter registers is essentially a data race.
+	 * These problems are avoided by ignoring the low byte. Clock accuracy
+	 * is 256 times worse (error can reach 0.327 ms) but CPU overhead is
+	 * reduced by avoiding slow VIA register accesses.
+	 */
+
+	local_irq_save(flags);
+	count_high = via1[vT1CH];
+	if (count_high == 0xFF)
+		count_high = 0;
+	if (count_high > 0 && (via1[vIFR] & VIA_TIMER_1_INT))
+		offset = VIA_TIMER_CYCLES;
+	local_irq_restore(flags);
+
+	count = count_high << 8;
+	count = VIA_TIMER_CYCLES - count + offset;
+
+	return ((count * VIA_TIMER_INTERVAL) / VIA_TIMER_CYCLES) * 1000;
+}
--- linux-4.4.0.orig/arch/m68k/mm/kmap.c
+++ linux-4.4.0/arch/m68k/mm/kmap.c
@@ -88,7 +88,8 @@
 	for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
-			__iounmap(tmp->addr, tmp->size);
+			/* remove gap added in get_io_area() */
+			__iounmap(tmp->addr, tmp->size - IO_SIZE);
 			kfree(tmp);
 			return;
 		}
--- linux-4.4.0.orig/arch/m68k/mvme147/config.c
+++ linux-4.4.0/arch/m68k/mvme147/config.c
@@ -47,11 +47,6 @@
 
 static int bcd2int (unsigned char b);
 
-/* Save tick handler routine pointer, will point to xtime_update() in
- * kernel/time/timekeeping.c, called via mvme147_process_int() */
-
-irq_handler_t tick_handler;
-
 
 int __init mvme147_parse_bootinfo(const struct bi_record *bi)
 {
@@ -107,16 +102,23 @@
 
 static irqreturn_t mvme147_timer_int (int irq, void *dev_id)
 {
+	irq_handler_t timer_routine = dev_id;
+	unsigned long flags;
+
+	local_irq_save(flags);
 	m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
 	m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
-	return tick_handler(irq, dev_id);
+	timer_routine(0, NULL);
+	local_irq_restore(flags);
+
+	return IRQ_HANDLED;
 }
 
 
 void mvme147_sched_init (irq_handler_t timer_routine)
 {
-	tick_handler = timer_routine;
-	if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1", NULL))
+	if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1",
+			timer_routine))
 		pr_err("Couldn't register timer interrupt\n");
 
 	/* Init the clock with a value */
--- linux-4.4.0.orig/arch/m68k/mvme16x/config.c
+++ linux-4.4.0/arch/m68k/mvme16x/config.c
@@ -52,11 +52,6 @@
 
 int bcd2int (unsigned char b);
 
-/* Save tick handler routine pointer, will point to xtime_update() in
- * kernel/time/timekeeping.c, called via mvme16x_process_int() */
-
-static irq_handler_t tick_handler;
-
 
 unsigned short mvme16x_config;
 EXPORT_SYMBOL(mvme16x_config);
@@ -355,8 +350,15 @@
 
 static irqreturn_t mvme16x_timer_int (int irq, void *dev_id)
 {
-    *(volatile unsigned char *)0xfff4201b |= 8;
-    return tick_handler(irq, dev_id);
+	irq_handler_t timer_routine = dev_id;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	*(volatile unsigned char *)0xfff4201b |= 8;
+	timer_routine(0, NULL);
+	local_irq_restore(flags);
+
+	return IRQ_HANDLED;
 }
 
 void mvme16x_sched_init (irq_handler_t timer_routine)
@@ -364,14 +366,13 @@
     uint16_t brdno = be16_to_cpu(mvme_bdid.brdno);
     int irq;
 
-    tick_handler = timer_routine;
     /* Using PCCchip2 or MC2 chip tick timer 1 */
     *(volatile unsigned long *)0xfff42008 = 0;
     *(volatile unsigned long *)0xfff42004 = 10000;	/* 10ms */
     *(volatile unsigned char *)0xfff42017 |= 3;
     *(volatile unsigned char *)0xfff4201b = 0x16;
-    if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0,
-				"timer", mvme16x_timer_int))
+    if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, "timer",
+                    timer_routine))
 	panic ("Couldn't register timer int");
 
     if (brdno == 0x0162 || brdno == 0x172)
--- linux-4.4.0.orig/arch/m68k/q40/config.c
+++ linux-4.4.0/arch/m68k/q40/config.c
@@ -303,6 +303,7 @@
 {
 	int tmp = Q40_RTC_CTRL;
 
+	pll->pll_ctrl = 0;
 	pll->pll_value = tmp & Q40_RTC_PLL_MASK;
 	if (tmp & Q40_RTC_PLL_SIGN)
 		pll->pll_value = -pll->pll_value;
--- linux-4.4.0.orig/arch/m68k/q40/q40ints.c
+++ linux-4.4.0/arch/m68k/q40/q40ints.c
@@ -126,10 +126,10 @@
 	sound_ticks = ticks << 1;
 }
 
-static irq_handler_t q40_timer_routine;
-
-static irqreturn_t q40_timer_int (int irq, void * dev)
+static irqreturn_t q40_timer_int(int irq, void *dev_id)
 {
+	irq_handler_t timer_routine = dev_id;
+
 	ql_ticks = ql_ticks ? 0 : 1;
 	if (sound_ticks) {
 		unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
@@ -138,8 +138,13 @@
 		*DAC_RIGHT=sval;
 	}
 
-	if (!ql_ticks)
-		q40_timer_routine(irq, dev);
+	if (!ql_ticks) {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		timer_routine(0, NULL);
+		local_irq_restore(flags);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -147,11 +152,9 @@
 {
 	int timer_irq;
 
-	q40_timer_routine = timer_routine;
 	timer_irq = Q40_IRQ_FRAME;
 
-	if (request_irq(timer_irq, q40_timer_int, 0,
-				"timer", q40_timer_int))
+	if (request_irq(timer_irq, q40_timer_int, 0, "timer", timer_routine))
 		panic("Couldn't register timer int");
 
 	master_outb(-1, FRAME_CLEAR_REG);
--- linux-4.4.0.orig/arch/m68k/sun3/sun3ints.c
+++ linux-4.4.0/arch/m68k/sun3/sun3ints.c
@@ -61,8 +61,10 @@
 
 static irqreturn_t sun3_int5(int irq, void *dev_id)
 {
+	unsigned long flags;
 	unsigned int cnt;
 
+	local_irq_save(flags);
 #ifdef CONFIG_SUN3
 	intersil_clear();
 #endif
@@ -76,6 +78,7 @@
 	cnt = kstat_irqs_cpu(irq, 0);
 	if (!(cnt % 20))
 		sun3_leds(led_pattern[cnt % 160 / 20]);
+	local_irq_restore(flags);
 	return IRQ_HANDLED;
 }
 
--- linux-4.4.0.orig/arch/m68k/sun3x/time.c
+++ linux-4.4.0/arch/m68k/sun3x/time.c
@@ -77,15 +77,19 @@
 }
 
 #if 0
-static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sun3x_timer_tick(int irq, void *dev_id)
 {
-    void (*vector)(int, void *, struct pt_regs *) = dev_id;
+	irq_handler_t timer_routine = dev_id;
+	unsigned long flags;
 
-    /* Clear the pending interrupt - pulse the enable line low */
-    disable_irq(5);
-    enable_irq(5);
+	local_irq_save(flags);
+	/* Clear the pending interrupt - pulse the enable line low */
+	disable_irq(5);
+	enable_irq(5);
+	timer_routine(0, NULL);
+	local_irq_restore(flags);
 
-    vector(irq, NULL, regs);
+	return IRQ_HANDLED;
 }
 #endif
 
--- linux-4.4.0.orig/arch/metag/include/asm/atomic.h
+++ linux-4.4.0/arch/metag/include/asm/atomic.h
@@ -39,11 +39,10 @@
 #define atomic_dec(v) atomic_sub(1, (v))
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_if_positive(v)       atomic_sub_if_positive(1, v)
 
 #endif
 
-#define atomic_dec_if_positive(v)       atomic_sub_if_positive(1, v)
-
 #include <asm-generic/atomic64.h>
 
 #endif /* __ASM_METAG_ATOMIC_H */
--- linux-4.4.0.orig/arch/metag/include/asm/atomic_lnkget.h
+++ linux-4.4.0/arch/metag/include/asm/atomic_lnkget.h
@@ -61,7 +61,7 @@
 		"	CMPT	%0, #HI(0x02000000)\n"			\
 		"	BNZ 1b\n"					\
 		: "=&d" (temp), "=&da" (result)				\
-		: "da" (&v->counter), "bd" (i)				\
+		: "da" (&v->counter), "br" (i)				\
 		: "cc");						\
 									\
 	smp_mb();							\
--- linux-4.4.0.orig/arch/metag/include/asm/cmpxchg_lnkget.h
+++ linux-4.4.0/arch/metag/include/asm/cmpxchg_lnkget.h
@@ -73,7 +73,7 @@
 		      "	DCACHE	[%2], %0\n"
 #endif
 		      "2:\n"
-		      : "=&d" (temp), "=&da" (retval)
+		      : "=&d" (temp), "=&d" (retval)
 		      : "da" (m), "bd" (old), "da" (new)
 		      : "cc"
 		      );
--- linux-4.4.0.orig/arch/metag/include/asm/uaccess.h
+++ linux-4.4.0/arch/metag/include/asm/uaccess.h
@@ -28,24 +28,32 @@
 
 #define segment_eq(a, b)	((a).seg == (b).seg)
 
-#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
-/*
- * Explicitly allow NULL pointers here. Parts of the kernel such
- * as readv/writev use access_ok to validate pointers, but want
- * to allow NULL pointers for various reasons. NULL pointers are
- * safe to allow through because the first page is not mappable on
- * Meta.
- *
- * We also wish to avoid letting user code access the system area
- * and the kernel half of the address space.
- */
-#define __user_bad(addr, size) (((addr) > 0 && (addr) < META_MEMORY_BASE) || \
-				((addr) > PAGE_OFFSET &&		\
-				 (addr) < LINCORE_BASE))
-
 static inline int __access_ok(unsigned long addr, unsigned long size)
 {
-	return __kernel_ok || !__user_bad(addr, size);
+	/*
+	 * Allow access to the user mapped memory area, but not the system area
+	 * before it. The check extends to the top of the address space when
+	 * kernel access is allowed (there's no real reason to user copy to the
+	 * system area in any case).
+	 */
+	if (likely(addr >= META_MEMORY_BASE && addr < get_fs().seg &&
+		   size <= get_fs().seg - addr))
+		return true;
+	/*
+	 * Explicitly allow NULL pointers here. Parts of the kernel such
+	 * as readv/writev use access_ok to validate pointers, but want
+	 * to allow NULL pointers for various reasons. NULL pointers are
+	 * safe to allow through because the first page is not mappable on
+	 * Meta.
+	 */
+	if (!addr)
+		return true;
+	/* Allow access to core code memory area... */
+	if (addr >= LINCORE_CODE_BASE && addr <= LINCORE_CODE_LIMIT &&
+	    size <= LINCORE_CODE_LIMIT + 1 - addr)
+		return true;
+	/* ... but no other areas. */
+	return false;
 }
 
 #define access_ok(type, addr, size) __access_ok((unsigned long)(addr),	\
@@ -186,8 +194,13 @@
 extern long __must_check __strncpy_from_user(char *dst, const char __user *src,
 					     long count);
 
-#define strncpy_from_user(dst, src, count) __strncpy_from_user(dst, src, count)
-
+static inline long
+strncpy_from_user(char *dst, const char __user *src, long count)
+{
+	if (!access_ok(VERIFY_READ, src, 1))
+		return -EFAULT;
+	return __strncpy_from_user(dst, src, count);
+}
 /*
  * Return the size of a string (including the ending 0)
  *
@@ -197,19 +210,21 @@
 
 #define strlen_user(str) strnlen_user(str, 32767)
 
-extern unsigned long __must_check __copy_user_zeroing(void *to,
-						      const void __user *from,
-						      unsigned long n);
+extern unsigned long raw_copy_from_user(void *to, const void __user *from,
+					unsigned long n);
 
 static inline unsigned long
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-	if (access_ok(VERIFY_READ, from, n))
-		return __copy_user_zeroing(to, from, n);
-	return n;
+	unsigned long res = n;
+	if (likely(access_ok(VERIFY_READ, from, n)))
+		res = raw_copy_from_user(to, from, n);
+	if (unlikely(res))
+		memset(to + (n - res), 0, res);
+	return res;
 }
 
-#define __copy_from_user(to, from, n) __copy_user_zeroing(to, from, n)
+#define __copy_from_user(to, from, n) raw_copy_from_user(to, from, n)
 #define __copy_from_user_inatomic __copy_from_user
 
 extern unsigned long __must_check __copy_user(void __user *to,
--- linux-4.4.0.orig/arch/metag/kernel/module.c
+++ linux-4.4.0/arch/metag/kernel/module.c
@@ -176,8 +176,8 @@
 	tramp[1] = 0xac000001 | ((val & 0x0000ffff) << 3);
 
 	/* Init, or core PLT? */
-	if (location >= mod->module_core
-	    && location < mod->module_core + mod->core_size)
+	if (location >= mod->core_layout.base
+	    && location < mod->core_layout.base + mod->core_layout.size)
 		entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
 	else
 		entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
--- linux-4.4.0.orig/arch/metag/kernel/ptrace.c
+++ linux-4.4.0/arch/metag/kernel/ptrace.c
@@ -24,6 +24,16 @@
  * user_regset definitions.
  */
 
+static unsigned long user_txstatus(const struct pt_regs *regs)
+{
+	unsigned long data = (unsigned long)regs->ctx.Flags;
+
+	if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
+		data |= USER_GP_REGS_STATUS_CATCH_BIT;
+
+	return data;
+}
+
 int metag_gp_regs_copyout(const struct pt_regs *regs,
 			  unsigned int pos, unsigned int count,
 			  void *kbuf, void __user *ubuf)
@@ -62,9 +72,7 @@
 	if (ret)
 		goto out;
 	/* TXSTATUS */
-	data = (unsigned long)regs->ctx.Flags;
-	if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
-		data |= USER_GP_REGS_STATUS_CATCH_BIT;
+	data = user_txstatus(regs);
 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 				  &data, 4*25, 4*26);
 	if (ret)
@@ -119,6 +127,7 @@
 	if (ret)
 		goto out;
 	/* TXSTATUS */
+	data = user_txstatus(regs);
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 				 &data, 4*25, 4*26);
 	if (ret)
@@ -244,6 +253,8 @@
 	unsigned long long *ptr;
 	int ret, i;
 
+	if (count < 4*13)
+		return -EINVAL;
 	/* Read the entire pipeline before making any changes */
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 				 &rp, 0, 4*13);
@@ -303,7 +314,7 @@
 			const void *kbuf, const void __user *ubuf)
 {
 	int ret;
-	void __user *tls;
+	void __user *tls = target->thread.tls_ptr;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
 	if (ret)
--- linux-4.4.0.orig/arch/metag/lib/usercopy.c
+++ linux-4.4.0/arch/metag/lib/usercopy.c
@@ -29,7 +29,6 @@
 		COPY						 \
 		"1:\n"						 \
 		"	.section .fixup,\"ax\"\n"		 \
-		"	MOV D1Ar1,#0\n"				 \
 		FIXUP						 \
 		"	MOVT    D1Ar1,#HI(1b)\n"		 \
 		"	JUMP    D1Ar1,#LO(1b)\n"		 \
@@ -260,27 +259,31 @@
 		"MGETL	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
 		"22:\n"							\
 		"MSETL	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
-		"SUB	%3, %3, #32\n"					\
 		"23:\n"							\
-		"MGETL	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
+		"SUB	%3, %3, #32\n"					\
 		"24:\n"							\
+		"MGETL	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
+		"25:\n"							\
 		"MSETL	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"26:\n"							\
 		"SUB	%3, %3, #32\n"					\
 		"DCACHE	[%1+#-64], D0Ar6\n"				\
 		"BR	$Lloop"id"\n"					\
 									\
 		"MOV	RAPF, %1\n"					\
-		"25:\n"							\
+		"27:\n"							\
 		"MGETL	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
-		"26:\n"							\
+		"28:\n"							\
 		"MSETL	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"29:\n"							\
 		"SUB	%3, %3, #32\n"					\
-		"27:\n"							\
+		"30:\n"							\
 		"MGETL	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
-		"28:\n"							\
+		"31:\n"							\
 		"MSETL	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"32:\n"							\
 		"SUB	%0, %0, #8\n"					\
-		"29:\n"							\
+		"33:\n"							\
 		"SETL	[%0++], D0.7, D1.7\n"				\
 		"SUB	%3, %3, #32\n"					\
 		"1:"							\
@@ -312,11 +315,15 @@
 		"	.long 26b,3b\n"					\
 		"	.long 27b,3b\n"					\
 		"	.long 28b,3b\n"					\
-		"	.long 29b,4b\n"					\
+		"	.long 29b,3b\n"					\
+		"	.long 30b,3b\n"					\
+		"	.long 31b,3b\n"					\
+		"	.long 32b,3b\n"					\
+		"	.long 33b,4b\n"					\
 		"	.previous\n"					\
 		: "=r" (to), "=r" (from), "=r" (ret), "=d" (n)		\
 		: "0" (to), "1" (from), "2" (ret), "3" (n)		\
-		: "D1Ar1", "D0Ar2", "memory")
+		: "D1Ar1", "D0Ar2", "cc", "memory")
 
 /*	rewind 'to' and 'from'  pointers when a fault occurs
  *
@@ -342,7 +349,7 @@
 #define __asm_copy_to_user_64bit_rapf_loop(to,	from, ret, n, id)\
 	__asm_copy_user_64bit_rapf_loop(to, from, ret, n, id,		\
 		"LSR	D0Ar2, D0Ar2, #8\n"				\
-		"AND	D0Ar2, D0Ar2, #0x7\n"				\
+		"ANDS	D0Ar2, D0Ar2, #0x7\n"				\
 		"ADDZ	D0Ar2, D0Ar2, #4\n"				\
 		"SUB	D0Ar2, D0Ar2, #1\n"				\
 		"MOV	D1Ar1, #4\n"					\
@@ -403,47 +410,55 @@
 		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
 		"22:\n"							\
 		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
-		"SUB	%3, %3, #16\n"					\
 		"23:\n"							\
-		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
-		"24:\n"							\
-		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
 		"SUB	%3, %3, #16\n"					\
-		"25:\n"							\
+		"24:\n"							\
 		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
-		"26:\n"							\
+		"25:\n"							\
 		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"26:\n"							\
 		"SUB	%3, %3, #16\n"					\
 		"27:\n"							\
 		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
 		"28:\n"							\
 		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"29:\n"							\
+		"SUB	%3, %3, #16\n"					\
+		"30:\n"							\
+		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
+		"31:\n"							\
+		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"32:\n"							\
 		"SUB	%3, %3, #16\n"					\
 		"DCACHE	[%1+#-64], D0Ar6\n"				\
 		"BR	$Lloop"id"\n"					\
 									\
 		"MOV	RAPF, %1\n"					\
-		"29:\n"							\
+		"33:\n"							\
 		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
-		"30:\n"							\
+		"34:\n"							\
 		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"35:\n"							\
 		"SUB	%3, %3, #16\n"					\
-		"31:\n"							\
+		"36:\n"							\
 		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
-		"32:\n"							\
+		"37:\n"							\
 		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"38:\n"							\
 		"SUB	%3, %3, #16\n"					\
-		"33:\n"							\
+		"39:\n"							\
 		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
-		"34:\n"							\
+		"40:\n"							\
 		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"41:\n"							\
 		"SUB	%3, %3, #16\n"					\
-		"35:\n"							\
+		"42:\n"							\
 		"MGETD	D0FrT, D0.5, D0.6, D0.7, [%1++]\n"		\
-		"36:\n"							\
+		"43:\n"							\
 		"MSETD	[%0++], D0FrT, D0.5, D0.6, D0.7\n"		\
+		"44:\n"							\
 		"SUB	%0, %0, #4\n"					\
-		"37:\n"							\
+		"45:\n"							\
 		"SETD	[%0++], D0.7\n"					\
 		"SUB	%3, %3, #16\n"					\
 		"1:"							\
@@ -483,11 +498,19 @@
 		"	.long 34b,3b\n"					\
 		"	.long 35b,3b\n"					\
 		"	.long 36b,3b\n"					\
-		"	.long 37b,4b\n"					\
+		"	.long 37b,3b\n"					\
+		"	.long 38b,3b\n"					\
+		"	.long 39b,3b\n"					\
+		"	.long 40b,3b\n"					\
+		"	.long 41b,3b\n"					\
+		"	.long 42b,3b\n"					\
+		"	.long 43b,3b\n"					\
+		"	.long 44b,3b\n"					\
+		"	.long 45b,4b\n"					\
 		"	.previous\n"					\
 		: "=r" (to), "=r" (from), "=r" (ret), "=d" (n)		\
 		: "0" (to), "1" (from), "2" (ret), "3" (n)		\
-		: "D1Ar1", "D0Ar2", "memory")
+		: "D1Ar1", "D0Ar2", "cc", "memory")
 
 /*	rewind 'to' and 'from'  pointers when a fault occurs
  *
@@ -513,7 +536,7 @@
 #define __asm_copy_to_user_32bit_rapf_loop(to, from, ret, n, id)\
 	__asm_copy_user_32bit_rapf_loop(to, from, ret, n, id,		\
 		"LSR	D0Ar2, D0Ar2, #8\n"				\
-		"AND	D0Ar2, D0Ar2, #0x7\n"				\
+		"ANDS	D0Ar2, D0Ar2, #0x7\n"				\
 		"ADDZ	D0Ar2, D0Ar2, #4\n"				\
 		"SUB	D0Ar2, D0Ar2, #1\n"				\
 		"MOV	D1Ar1, #4\n"					\
@@ -538,23 +561,31 @@
 	if ((unsigned long) src & 1) {
 		__asm_copy_to_user_1(dst, src, retn);
 		n--;
+		if (retn)
+			return retn + n;
 	}
 	if ((unsigned long) dst & 1) {
 		/* Worst case - byte copy */
 		while (n > 0) {
 			__asm_copy_to_user_1(dst, src, retn);
 			n--;
+			if (retn)
+				return retn + n;
 		}
 	}
 	if (((unsigned long) src & 2) && n >= 2) {
 		__asm_copy_to_user_2(dst, src, retn);
 		n -= 2;
+		if (retn)
+			return retn + n;
 	}
 	if ((unsigned long) dst & 2) {
 		/* Second worst case - word copy */
 		while (n >= 2) {
 			__asm_copy_to_user_2(dst, src, retn);
 			n -= 2;
+			if (retn)
+				return retn + n;
 		}
 	}
 
@@ -569,6 +600,8 @@
 		while (n >= 8) {
 			__asm_copy_to_user_8x64(dst, src, retn);
 			n -= 8;
+			if (retn)
+				return retn + n;
 		}
 	}
 	if (n >= RAPF_MIN_BUF_SIZE) {
@@ -581,6 +614,8 @@
 		while (n >= 8) {
 			__asm_copy_to_user_8x64(dst, src, retn);
 			n -= 8;
+			if (retn)
+				return retn + n;
 		}
 	}
 #endif
@@ -588,11 +623,15 @@
 	while (n >= 16) {
 		__asm_copy_to_user_16(dst, src, retn);
 		n -= 16;
+		if (retn)
+			return retn + n;
 	}
 
 	while (n >= 4) {
 		__asm_copy_to_user_4(dst, src, retn);
 		n -= 4;
+		if (retn)
+			return retn + n;
 	}
 
 	switch (n) {
@@ -609,6 +648,10 @@
 		break;
 	}
 
+	/*
+	 * If we get here, retn correctly reflects the number of failing
+	 * bytes.
+	 */
 	return retn;
 }
 EXPORT_SYMBOL(__copy_user);
@@ -617,16 +660,14 @@
 	__asm_copy_user_cont(to, from, ret,	\
 		"	GETB D1Ar1,[%1++]\n"	\
 		"2:	SETB [%0++],D1Ar1\n",	\
-		"3:	ADD  %2,%2,#1\n"	\
-		"	SETB [%0++],D1Ar1\n",	\
+		"3:	ADD  %2,%2,#1\n",	\
 		"	.long 2b,3b\n")
 
 #define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
 	__asm_copy_user_cont(to, from, ret,		\
 		"	GETW D1Ar1,[%1++]\n"		\
 		"2:	SETW [%0++],D1Ar1\n" COPY,	\
-		"3:	ADD  %2,%2,#2\n"		\
-		"	SETW [%0++],D1Ar1\n" FIXUP,	\
+		"3:	ADD  %2,%2,#2\n" FIXUP,		\
 		"	.long 2b,3b\n" TENTRY)
 
 #define __asm_copy_from_user_2(to, from, ret) \
@@ -636,145 +677,26 @@
 	__asm_copy_from_user_2x_cont(to, from, ret,	\
 		"	GETB D1Ar1,[%1++]\n"		\
 		"4:	SETB [%0++],D1Ar1\n",		\
-		"5:	ADD  %2,%2,#1\n"		\
-		"	SETB [%0++],D1Ar1\n",		\
+		"5:	ADD  %2,%2,#1\n",		\
 		"	.long 4b,5b\n")
 
 #define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
 	__asm_copy_user_cont(to, from, ret,		\
 		"	GETD D1Ar1,[%1++]\n"		\
 		"2:	SETD [%0++],D1Ar1\n" COPY,	\
-		"3:	ADD  %2,%2,#4\n"		\
-		"	SETD [%0++],D1Ar1\n" FIXUP,	\
+		"3:	ADD  %2,%2,#4\n" FIXUP,		\
 		"	.long 2b,3b\n" TENTRY)
 
 #define __asm_copy_from_user_4(to, from, ret) \
 	__asm_copy_from_user_4x_cont(to, from, ret, "", "", "")
 
-#define __asm_copy_from_user_5(to, from, ret) \
-	__asm_copy_from_user_4x_cont(to, from, ret,	\
-		"	GETB D1Ar1,[%1++]\n"		\
-		"4:	SETB [%0++],D1Ar1\n",		\
-		"5:	ADD  %2,%2,#1\n"		\
-		"	SETB [%0++],D1Ar1\n",		\
-		"	.long 4b,5b\n")
-
-#define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-	__asm_copy_from_user_4x_cont(to, from, ret,	\
-		"	GETW D1Ar1,[%1++]\n"		\
-		"4:	SETW [%0++],D1Ar1\n" COPY,	\
-		"5:	ADD  %2,%2,#2\n"		\
-		"	SETW [%0++],D1Ar1\n" FIXUP,	\
-		"	.long 4b,5b\n" TENTRY)
-
-#define __asm_copy_from_user_6(to, from, ret) \
-	__asm_copy_from_user_6x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_7(to, from, ret) \
-	__asm_copy_from_user_6x_cont(to, from, ret,	\
-		"	GETB D1Ar1,[%1++]\n"		\
-		"6:	SETB [%0++],D1Ar1\n",		\
-		"7:	ADD  %2,%2,#1\n"		\
-		"	SETB [%0++],D1Ar1\n",		\
-		"	.long 6b,7b\n")
-
-#define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-	__asm_copy_from_user_4x_cont(to, from, ret,	\
-		"	GETD D1Ar1,[%1++]\n"		\
-		"4:	SETD [%0++],D1Ar1\n" COPY,	\
-		"5:	ADD  %2,%2,#4\n"			\
-		"	SETD [%0++],D1Ar1\n" FIXUP,		\
-		"	.long 4b,5b\n" TENTRY)
-
-#define __asm_copy_from_user_8(to, from, ret) \
-	__asm_copy_from_user_8x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_9(to, from, ret) \
-	__asm_copy_from_user_8x_cont(to, from, ret,	\
-		"	GETB D1Ar1,[%1++]\n"		\
-		"6:	SETB [%0++],D1Ar1\n",		\
-		"7:	ADD  %2,%2,#1\n"		\
-		"	SETB [%0++],D1Ar1\n",		\
-		"	.long 6b,7b\n")
-
-#define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-	__asm_copy_from_user_8x_cont(to, from, ret,	\
-		"	GETW D1Ar1,[%1++]\n"		\
-		"6:	SETW [%0++],D1Ar1\n" COPY,	\
-		"7:	ADD  %2,%2,#2\n"		\
-		"	SETW [%0++],D1Ar1\n" FIXUP,	\
-		"	.long 6b,7b\n" TENTRY)
-
-#define __asm_copy_from_user_10(to, from, ret) \
-	__asm_copy_from_user_10x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_11(to, from, ret)		\
-	__asm_copy_from_user_10x_cont(to, from, ret,	\
-		"	GETB D1Ar1,[%1++]\n"		\
-		"8:	SETB [%0++],D1Ar1\n",		\
-		"9:	ADD  %2,%2,#1\n"		\
-		"	SETB [%0++],D1Ar1\n",		\
-		"	.long 8b,9b\n")
-
-#define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-	__asm_copy_from_user_8x_cont(to, from, ret,	\
-		"	GETD D1Ar1,[%1++]\n"		\
-		"6:	SETD [%0++],D1Ar1\n" COPY,	\
-		"7:	ADD  %2,%2,#4\n"		\
-		"	SETD [%0++],D1Ar1\n" FIXUP,	\
-		"	.long 6b,7b\n" TENTRY)
-
-#define __asm_copy_from_user_12(to, from, ret) \
-	__asm_copy_from_user_12x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_13(to, from, ret) \
-	__asm_copy_from_user_12x_cont(to, from, ret,	\
-		"	GETB D1Ar1,[%1++]\n"		\
-		"8:	SETB [%0++],D1Ar1\n",		\
-		"9:	ADD  %2,%2,#1\n"		\
-		"	SETB [%0++],D1Ar1\n",		\
-		"	.long 8b,9b\n")
-
-#define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-	__asm_copy_from_user_12x_cont(to, from, ret,	\
-		"	GETW D1Ar1,[%1++]\n"		\
-		"8:	SETW [%0++],D1Ar1\n" COPY,	\
-		"9:	ADD  %2,%2,#2\n"		\
-		"	SETW [%0++],D1Ar1\n" FIXUP,	\
-		"	.long 8b,9b\n" TENTRY)
-
-#define __asm_copy_from_user_14(to, from, ret) \
-	__asm_copy_from_user_14x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_15(to, from, ret) \
-	__asm_copy_from_user_14x_cont(to, from, ret,	\
-		"	GETB D1Ar1,[%1++]\n"		\
-		"10:	SETB [%0++],D1Ar1\n",		\
-		"11:	ADD  %2,%2,#1\n"		\
-		"	SETB [%0++],D1Ar1\n",		\
-		"	.long 10b,11b\n")
-
-#define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-	__asm_copy_from_user_12x_cont(to, from, ret,	\
-		"	GETD D1Ar1,[%1++]\n"		\
-		"8:	SETD [%0++],D1Ar1\n" COPY,	\
-		"9:	ADD  %2,%2,#4\n"		\
-		"	SETD [%0++],D1Ar1\n" FIXUP,	\
-		"	.long 8b,9b\n" TENTRY)
-
-#define __asm_copy_from_user_16(to, from, ret) \
-	__asm_copy_from_user_16x_cont(to, from, ret, "", "", "")
-
 #define __asm_copy_from_user_8x64(to, from, ret) \
 	asm volatile (				\
 		"	GETL D0Ar2,D1Ar1,[%1++]\n"	\
 		"2:	SETL [%0++],D0Ar2,D1Ar1\n"	\
 		"1:\n"					\
 		"	.section .fixup,\"ax\"\n"	\
-		"	MOV D1Ar1,#0\n"			\
-		"	MOV D0Ar2,#0\n"			\
 		"3:	ADD  %2,%2,#8\n"		\
-		"	SETL [%0++],D0Ar2,D1Ar1\n"	\
 		"	MOVT    D0Ar2,#HI(1b)\n"	\
 		"	JUMP    D0Ar2,#LO(1b)\n"	\
 		"	.previous\n"			\
@@ -789,36 +711,57 @@
  *
  *	Rationale:
  *		A fault occurs while reading from user buffer, which is the
- *		source. Since the fault is at a single address, we only
- *		need to rewind by 8 bytes.
+ *		source.
  *		Since we don't write to kernel buffer until we read first,
  *		the kernel buffer is at the right state and needn't be
- *		corrected.
+ *		corrected, but the source must be rewound to the beginning of
+ *		the block, which is LSM_STEP*8 bytes.
+ *		LSM_STEP is bits 10:8 in TXSTATUS which is already read
+ *		and stored in D0Ar2
+ *
+ *		NOTE: If a fault occurs at the last operation in M{G,S}ETL
+ *			LSM_STEP will be 0. ie: we do 4 writes in our case, if
+ *			a fault happens at the 4th write, LSM_STEP will be 0
+ *			instead of 4. The code copes with that.
  */
 #define __asm_copy_from_user_64bit_rapf_loop(to, from, ret, n, id)	\
 	__asm_copy_user_64bit_rapf_loop(to, from, ret, n, id,		\
-		"SUB	%1, %1, #8\n")
+		"LSR	D0Ar2, D0Ar2, #5\n"				\
+		"ANDS	D0Ar2, D0Ar2, #0x38\n"				\
+		"ADDZ	D0Ar2, D0Ar2, #32\n"				\
+		"SUB	%1, %1, D0Ar2\n")
 
 /*	rewind 'from' pointer when a fault occurs
  *
  *	Rationale:
  *		A fault occurs while reading from user buffer, which is the
- *		source. Since the fault is at a single address, we only
- *		need to rewind by 4 bytes.
+ *		source.
  *		Since we don't write to kernel buffer until we read first,
  *		the kernel buffer is at the right state and needn't be
- *		corrected.
+ *		corrected, but the source must be rewound to the beginning of
+ *		the block, which is LSM_STEP*4 bytes.
+ *		LSM_STEP is bits 10:8 in TXSTATUS which is already read
+ *		and stored in D0Ar2
+ *
+ *		NOTE: If a fault occurs at the last operation in M{G,S}ETL
+ *			LSM_STEP will be 0. ie: we do 4 writes in our case, if
+ *			a fault happens at the 4th write, LSM_STEP will be 0
+ *			instead of 4. The code copes with that.
  */
 #define __asm_copy_from_user_32bit_rapf_loop(to, from, ret, n, id)	\
 	__asm_copy_user_32bit_rapf_loop(to, from, ret, n, id,		\
-		"SUB	%1, %1, #4\n")
+		"LSR	D0Ar2, D0Ar2, #6\n"				\
+		"ANDS	D0Ar2, D0Ar2, #0x1c\n"				\
+		"ADDZ	D0Ar2, D0Ar2, #16\n"				\
+		"SUB	%1, %1, D0Ar2\n")
 
 
-/* Copy from user to kernel, zeroing the bytes that were inaccessible in
-   userland.  The return-value is the number of bytes that were
-   inaccessible.  */
-unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
-				  unsigned long n)
+/*
+ * Copy from user to kernel. The return-value is the number of bytes that were
+ * inaccessible.
+ */
+unsigned long raw_copy_from_user(void *pdst, const void __user *psrc,
+				 unsigned long n)
 {
 	register char *dst asm ("A0.2") = pdst;
 	register const char __user *src asm ("A1.2") = psrc;
@@ -830,6 +773,8 @@
 	if ((unsigned long) src & 1) {
 		__asm_copy_from_user_1(dst, src, retn);
 		n--;
+		if (retn)
+			return retn + n;
 	}
 	if ((unsigned long) dst & 1) {
 		/* Worst case - byte copy */
@@ -837,12 +782,14 @@
 			__asm_copy_from_user_1(dst, src, retn);
 			n--;
 			if (retn)
-				goto copy_exception_bytes;
+				return retn + n;
 		}
 	}
 	if (((unsigned long) src & 2) && n >= 2) {
 		__asm_copy_from_user_2(dst, src, retn);
 		n -= 2;
+		if (retn)
+			return retn + n;
 	}
 	if ((unsigned long) dst & 2) {
 		/* Second worst case - word copy */
@@ -850,16 +797,10 @@
 			__asm_copy_from_user_2(dst, src, retn);
 			n -= 2;
 			if (retn)
-				goto copy_exception_bytes;
+				return retn + n;
 		}
 	}
 
-	/* We only need one check after the unalignment-adjustments,
-	   because if both adjustments were done, either both or
-	   neither reference had an exception.  */
-	if (retn != 0)
-		goto copy_exception_bytes;
-
 #ifdef USE_RAPF
 	/* 64 bit copy loop */
 	if (!(((unsigned long) src | (unsigned long) dst) & 7)) {
@@ -872,7 +813,7 @@
 			__asm_copy_from_user_8x64(dst, src, retn);
 			n -= 8;
 			if (retn)
-				goto copy_exception_bytes;
+				return retn + n;
 		}
 	}
 
@@ -888,7 +829,7 @@
 			__asm_copy_from_user_8x64(dst, src, retn);
 			n -= 8;
 			if (retn)
-				goto copy_exception_bytes;
+				return retn + n;
 		}
 	}
 #endif
@@ -898,7 +839,7 @@
 		n -= 4;
 
 		if (retn)
-			goto copy_exception_bytes;
+			return retn + n;
 	}
 
 	/* If we get here, there were no memory read faults.  */
@@ -924,21 +865,8 @@
 	/* If we get here, retn correctly reflects the number of failing
 	   bytes.  */
 	return retn;
-
- copy_exception_bytes:
-	/* We already have "retn" bytes cleared, and need to clear the
-	   remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
-	   memset is preferred here, since this isn't speed-critical code and
-	   we'd rather have this a leaf-function than calling memset.  */
-	{
-		char *endp;
-		for (endp = dst + n; dst < endp; dst++)
-			*dst = 0;
-	}
-
-	return retn + n;
 }
-EXPORT_SYMBOL(__copy_user_zeroing);
+EXPORT_SYMBOL(raw_copy_from_user);
 
 #define __asm_clear_8x64(to, ret) \
 	asm volatile (					\
--- linux-4.4.0.orig/arch/microblaze/Makefile
+++ linux-4.4.0/arch/microblaze/Makefile
@@ -75,19 +75,21 @@
 
 linux.bin linux.bin.gz linux.bin.ub: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+	@echo 'Kernel: $(boot)/$@ is ready' ' (#'`cat .version`')'
 
 simpleImage.%: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+	@echo 'Kernel: $(boot)/$@ is ready' ' (#'`cat .version`')'
 
 define archhelp
   echo '* linux.bin    - Create raw binary'
   echo '  linux.bin.gz - Create compressed raw binary'
   echo '  linux.bin.ub - Create U-Boot wrapped raw binary'
-  echo '  simpleImage.<dt> - ELF image with $(arch)/boot/dts/<dt>.dts linked in'
-  echo '                   - stripped elf with fdt blob'
-  echo '  simpleImage.<dt>.unstrip - full ELF image with fdt blob'
-  echo '  *_defconfig      - Select default config from arch/microblaze/configs'
-  echo ''
+  echo '  simpleImage.<dt> - Create the following images with <dt>.dtb linked in'
+  echo '                    simpleImage.<dt>        : raw image'
+  echo '                    simpleImage.<dt>.ub     : raw image with U-Boot header'
+  echo '                    simpleImage.<dt>.unstrip: ELF (identical to vmlinux)'
+  echo '                    simpleImage.<dt>.strip  : stripped ELF'
   echo '  Targets with <dt> embed a device tree blob inside the image'
   echo '  These targets support board with firmware that does not'
   echo '  support passing a device tree directly. Replace <dt> with the'
--- linux-4.4.0.orig/arch/microblaze/boot/Makefile
+++ linux-4.4.0/arch/microblaze/boot/Makefile
@@ -8,30 +8,28 @@
 
 $(obj)/linux.bin: vmlinux FORCE
 	$(call if_changed,objcopy)
-	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 $(obj)/linux.bin.ub: $(obj)/linux.bin FORCE
 	$(call if_changed,uimage)
-	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 $(obj)/linux.bin.gz: $(obj)/linux.bin FORCE
 	$(call if_changed,gzip)
-	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 quiet_cmd_cp = CP      $< $@$2
 	cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false)
 
-quiet_cmd_strip = STRIP   $@
+quiet_cmd_strip = STRIP   $< $@$2
 	cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \
-				-K _fdt_start vmlinux -o $@
+				-K _fdt_start $< -o $@$2
 
 UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR)
+UIMAGE_IN = $@
+UIMAGE_OUT = $@.ub
 
 $(obj)/simpleImage.%: vmlinux FORCE
 	$(call if_changed,cp,.unstrip)
 	$(call if_changed,objcopy)
 	$(call if_changed,uimage)
-	$(call if_changed,strip)
-	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
+	$(call if_changed,strip,.strip)
 
 clean-files += simpleImage.*.unstrip linux.bin.ub dts/*.dtb
--- linux-4.4.0.orig/arch/microblaze/include/asm/futex.h
+++ linux-4.4.0/arch/microblaze/include/asm/futex.h
@@ -29,18 +29,9 @@
 })
 
 static inline int
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -66,30 +57,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (oldval == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (oldval != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (oldval < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (oldval >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (oldval <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (oldval > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/microblaze/include/asm/uaccess.h
+++ linux-4.4.0/arch/microblaze/include/asm/uaccess.h
@@ -227,7 +227,7 @@
 
 #define __get_user(x, ptr)						\
 ({									\
-	unsigned long __gu_val;						\
+	unsigned long __gu_val = 0;					\
 	/*unsigned long __gu_ptr = (unsigned long)(ptr);*/		\
 	long __gu_err;							\
 	switch (sizeof(*(ptr))) {					\
@@ -373,10 +373,13 @@
 static inline long copy_from_user(void *to,
 		const void __user *from, unsigned long n)
 {
+	unsigned long res = n;
 	might_fault();
-	if (access_ok(VERIFY_READ, from, n))
-		return __copy_from_user(to, from, n);
-	return n;
+	if (likely(access_ok(VERIFY_READ, from, n)))
+		res = __copy_from_user(to, from, n);
+	if (unlikely(res))
+		memset(to + (n - res), 0, res);
+	return res;
 }
 
 #define __copy_to_user(to, from, n)	\
--- linux-4.4.0.orig/arch/microblaze/kernel/cpu/cache.c
+++ linux-4.4.0/arch/microblaze/kernel/cpu/cache.c
@@ -92,7 +92,8 @@
 #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size)	\
 do {									\
 	int align = ~(cache_line_length - 1);				\
-	end = min(start + cache_size, end);				\
+	if (start <  UINT_MAX - cache_size)				\
+		end = min(start + cache_size, end);			\
 	start &= align;							\
 } while (0)
 
--- linux-4.4.0.orig/arch/mips/Kconfig
+++ linux-4.4.0/arch/mips/Kconfig
@@ -9,9 +9,11 @@
 	select HAVE_CONTEXT_TRACKING
 	select HAVE_GENERIC_DMA_COHERENT
 	select HAVE_IDE
+	select HAVE_IRQ_EXIT_ON_IRQ_STACK
 	select HAVE_OPROFILE
 	select HAVE_PERF_EVENTS
 	select PERF_USE_VMALLOC
+	select HAVE_ARCH_COMPILER_H
 	select HAVE_ARCH_KGDB
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
@@ -771,6 +773,7 @@
 	select SYS_SUPPORTS_BIG_ENDIAN
 	select SYS_SUPPORTS_HIGHMEM
 	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select ZONE_DMA32 if 64BIT
 
 config SIBYTE_SENTOSA
 	bool "Sibyte BCM91250E-Sentosa"
@@ -814,6 +817,7 @@
 	select I8253
 	select I8259
 	select ISA
+	select MIPS_L1_CACHE_SHIFT_6
 	select SWAP_IO_SPACE if CPU_BIG_ENDIAN
 	select SYS_HAS_CPU_R4X00
 	select SYS_HAS_CPU_R5000
@@ -1463,7 +1467,7 @@
 	select CPU_SUPPORTS_HIGHMEM
 	select CPU_SUPPORTS_MSA
 	select GENERIC_CSUM
-	select MIPS_O32_FP64_SUPPORT if MIPS32_O32
+	select MIPS_O32_FP64_SUPPORT if 32BIT || MIPS32_O32
 	help
 	  Choose this option to build a kernel for release 6 or later of the
 	  MIPS64 architecture.  New MIPS processors, starting with the Warrior
@@ -2155,7 +2159,7 @@
 	select CPU_MIPSR2_IRQ_VI
 	select CPU_MIPSR2_IRQ_EI
 	select SYNC_R4K
-	select MIPS_GIC_IPI
+	select MIPS_GIC_IPI if MIPS_GIC
 	select MIPS_MT
 	select SMP
 	select SMP_UP
@@ -2253,7 +2257,7 @@
 config MIPS_CMP
 	bool "MIPS CMP framework support (DEPRECATED)"
 	depends on SYS_SUPPORTS_MIPS_CMP && !CPU_MIPSR6
-	select MIPS_GIC_IPI
+	select MIPS_GIC_IPI if MIPS_GIC
 	select SMP
 	select SYNC_R4K
 	select SYS_SUPPORTS_SMP
@@ -2273,7 +2277,7 @@
 	select MIPS_CM
 	select MIPS_CPC
 	select MIPS_CPS_PM if HOTPLUG_CPU
-	select MIPS_GIC_IPI
+	select MIPS_GIC_IPI if MIPS_GIC
 	select SMP
 	select SYNC_R4K if (CEVT_R4K || CSRC_R4K)
 	select SYS_SUPPORTS_HOTPLUG_CPU
@@ -2292,6 +2296,7 @@
 	bool
 
 config MIPS_GIC_IPI
+	depends on MIPS_GIC
 	bool
 
 config MIPS_CM
@@ -2970,6 +2975,7 @@
 config MIPS32_N32
 	bool "Kernel support for n32 binaries"
 	depends on 64BIT
+	select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
 	select COMPAT
 	select MIPS32_COMPAT
 	select SYSVIPC_COMPAT if SYSVIPC
@@ -2984,6 +2990,7 @@
 config BINFMT_ELF32
 	bool
 	default y if MIPS32_O32 || MIPS32_N32
+	select ELFCORE
 
 endmenu
 
--- linux-4.4.0.orig/arch/mips/Kconfig.debug
+++ linux-4.4.0/arch/mips/Kconfig.debug
@@ -113,42 +113,6 @@
 	help
 	  Add several files to the debugfs to test spinlock speed.
 
-if CPU_MIPSR6
-
-choice
-	prompt "Compact branch policy"
-	default MIPS_COMPACT_BRANCHES_OPTIMAL
-
-config MIPS_COMPACT_BRANCHES_NEVER
-	bool "Never (force delay slot branches)"
-	help
-	  Pass the -mcompact-branches=never flag to the compiler in order to
-	  force it to always emit branches with delay slots, and make no use
-	  of the compact branch instructions introduced by MIPSr6. This is
-	  useful if you suspect there may be an issue with compact branches in
-	  either the compiler or the CPU.
-
-config MIPS_COMPACT_BRANCHES_OPTIMAL
-	bool "Optimal (use where beneficial)"
-	help
-	  Pass the -mcompact-branches=optimal flag to the compiler in order for
-	  it to make use of compact branch instructions where it deems them
-	  beneficial, and use branches with delay slots elsewhere. This is the
-	  default compiler behaviour, and should be used unless you have a
-	  reason to choose otherwise.
-
-config MIPS_COMPACT_BRANCHES_ALWAYS
-	bool "Always (force compact branches)"
-	help
-	  Pass the -mcompact-branches=always flag to the compiler in order to
-	  force it to always emit compact branches, making no use of branch
-	  instructions with delay slots. This can result in more compact code
-	  which may be beneficial in some scenarios.
-
-endchoice
-
-endif # CPU_MIPSR6
-
 config SCACHE_DEBUGFS
 	bool "L2 cache debugfs entries"
 	depends on DEBUG_FS
--- linux-4.4.0.orig/arch/mips/Makefile
+++ linux-4.4.0/arch/mips/Makefile
@@ -204,10 +204,6 @@
 cflags-$(toolchain-msa)			+= -DTOOLCHAIN_SUPPORTS_MSA
 endif
 
-cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_NEVER)	+= -mcompact-branches=never
-cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_OPTIMAL)	+= -mcompact-branches=optimal
-cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_ALWAYS)	+= -mcompact-branches=always
-
 #
 # Firmware support
 #
--- linux-4.4.0.orig/arch/mips/alchemy/common/clock.c
+++ linux-4.4.0/arch/mips/alchemy/common/clock.c
@@ -151,6 +151,7 @@
 {
 	struct clk_init_data id;
 	struct clk_hw *h;
+	struct clk *clk;
 
 	h = kzalloc(sizeof(*h), GFP_KERNEL);
 	if (!h)
@@ -163,7 +164,13 @@
 	id.ops = &alchemy_clkops_cpu;
 	h->init = &id;
 
-	return clk_register(NULL, h);
+	clk = clk_register(NULL, h);
+	if (IS_ERR(clk)) {
+		pr_err("failed to register clock\n");
+		kfree(h);
+	}
+
+	return clk;
 }
 
 /* AUXPLLs ************************************************************/
--- linux-4.4.0.orig/arch/mips/alchemy/devboards/db1000.c
+++ linux-4.4.0/arch/mips/alchemy/devboards/db1000.c
@@ -503,15 +503,15 @@
 	if (board == BCSR_WHOAMI_DB1500) {
 		c0 = AU1500_GPIO2_INT;
 		c1 = AU1500_GPIO5_INT;
-		d0 = AU1500_GPIO0_INT;
-		d1 = AU1500_GPIO3_INT;
+		d0 = 0;	/* GPIO number, NOT irq! */
+		d1 = 3; /* GPIO number, NOT irq! */
 		s0 = AU1500_GPIO1_INT;
 		s1 = AU1500_GPIO4_INT;
 	} else if (board == BCSR_WHOAMI_DB1100) {
 		c0 = AU1100_GPIO2_INT;
 		c1 = AU1100_GPIO5_INT;
-		d0 = AU1100_GPIO0_INT;
-		d1 = AU1100_GPIO3_INT;
+		d0 = 0; /* GPIO number, NOT irq! */
+		d1 = 3; /* GPIO number, NOT irq! */
 		s0 = AU1100_GPIO1_INT;
 		s1 = AU1100_GPIO4_INT;
 
@@ -545,15 +545,15 @@
 	} else if (board == BCSR_WHOAMI_DB1000) {
 		c0 = AU1000_GPIO2_INT;
 		c1 = AU1000_GPIO5_INT;
-		d0 = AU1000_GPIO0_INT;
-		d1 = AU1000_GPIO3_INT;
+		d0 = 0; /* GPIO number, NOT irq! */
+		d1 = 3; /* GPIO number, NOT irq! */
 		s0 = AU1000_GPIO1_INT;
 		s1 = AU1000_GPIO4_INT;
 		platform_add_devices(db1000_devs, ARRAY_SIZE(db1000_devs));
 	} else if ((board == BCSR_WHOAMI_PB1500) ||
 		   (board == BCSR_WHOAMI_PB1500R2)) {
 		c0 = AU1500_GPIO203_INT;
-		d0 = AU1500_GPIO201_INT;
+		d0 = 1; /* GPIO number, NOT irq! */
 		s0 = AU1500_GPIO202_INT;
 		twosocks = 0;
 		flashsize = 64;
@@ -566,7 +566,7 @@
 		 */
 	} else if (board == BCSR_WHOAMI_PB1100) {
 		c0 = AU1100_GPIO11_INT;
-		d0 = AU1100_GPIO9_INT;
+		d0 = 9; /* GPIO number, NOT irq! */
 		s0 = AU1100_GPIO10_INT;
 		twosocks = 0;
 		flashsize = 64;
@@ -583,7 +583,6 @@
 	} else
 		return 0; /* unknown board, no further dev setup to do */
 
-	irq_set_irq_type(d0, IRQ_TYPE_EDGE_BOTH);
 	irq_set_irq_type(c0, IRQ_TYPE_LEVEL_LOW);
 	irq_set_irq_type(s0, IRQ_TYPE_LEVEL_LOW);
 
@@ -597,7 +596,6 @@
 		c0, d0, /*s0*/0, 0, 0);
 
 	if (twosocks) {
-		irq_set_irq_type(d1, IRQ_TYPE_EDGE_BOTH);
 		irq_set_irq_type(c1, IRQ_TYPE_LEVEL_LOW);
 		irq_set_irq_type(s1, IRQ_TYPE_LEVEL_LOW);
 
--- linux-4.4.0.orig/arch/mips/alchemy/devboards/db1550.c
+++ linux-4.4.0/arch/mips/alchemy/devboards/db1550.c
@@ -514,7 +514,7 @@
 		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
 		AU1000_PCMCIA_IO_PHYS_ADDR,
 		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-		AU1550_GPIO3_INT, AU1550_GPIO0_INT,
+		AU1550_GPIO3_INT, 0,
 		/*AU1550_GPIO21_INT*/0, 0, 0);
 
 	db1x_register_pcmcia_socket(
@@ -524,7 +524,7 @@
 		AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
 		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004000000,
 		AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
-		AU1550_GPIO5_INT, AU1550_GPIO1_INT,
+		AU1550_GPIO5_INT, 1,
 		/*AU1550_GPIO22_INT*/0, 0, 1);
 
 	platform_device_register(&db1550_nand_dev);
--- linux-4.4.0.orig/arch/mips/ar7/platform.c
+++ linux-4.4.0/arch/mips/ar7/platform.c
@@ -576,6 +576,7 @@
 	uart_port.type		= PORT_AR7;
 	uart_port.uartclk	= clk_get_rate(bus_clk) / 2;
 	uart_port.iotype	= UPIO_MEM32;
+	uart_port.flags		= UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF;
 	uart_port.regshift	= 2;
 
 	uart_port.line		= 0;
@@ -654,6 +655,10 @@
 	u32 val;
 	int res;
 
+	res = ar7_gpio_init();
+	if (res)
+		pr_warn("unable to register gpios: %d\n", res);
+
 	res = ar7_register_uarts();
 	if (res)
 		pr_err("unable to setup uart(s): %d\n", res);
--- linux-4.4.0.orig/arch/mips/ar7/prom.c
+++ linux-4.4.0/arch/mips/ar7/prom.c
@@ -246,8 +246,6 @@
 	ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
 	ar7_init_env((struct env_var *)fw_arg2);
 	console_config();
-
-	ar7_gpio_init();
 }
 
 #define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
--- linux-4.4.0.orig/arch/mips/ath25/board.c
+++ linux-4.4.0/arch/mips/ath25/board.c
@@ -135,6 +135,8 @@
 	}
 
 	board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
+	if (!board_data)
+		goto error;
 	ath25_board.config = (struct ath25_boarddata *)board_data;
 	memcpy_fromio(board_data, bcfg, 0x100);
 	if (broken_boarddata) {
--- linux-4.4.0.orig/arch/mips/ath79/common.c
+++ linux-4.4.0/arch/mips/ath79/common.c
@@ -58,7 +58,7 @@
 
 void ath79_ddr_wb_flush(u32 reg)
 {
-	void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg;
+	void __iomem *flush_reg = ath79_ddr_wb_flush_base + (reg * 4);
 
 	/* Flush the DDR write buffer. */
 	__raw_writel(0x1, flush_reg);
@@ -76,14 +76,14 @@
 {
 	BUG_ON(!ath79_ddr_pci_win_base);
 
-	__raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0);
-	__raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 1);
-	__raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 2);
-	__raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 3);
-	__raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 4);
-	__raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 5);
-	__raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 6);
-	__raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 7);
+	__raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0x0);
+	__raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 0x4);
+	__raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 0x8);
+	__raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 0xc);
+	__raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 0x10);
+	__raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 0x14);
+	__raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 0x18);
+	__raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 0x1c);
 }
 EXPORT_SYMBOL_GPL(ath79_ddr_set_pci_windows);
 
--- linux-4.4.0.orig/arch/mips/ath79/early_printk.c
+++ linux-4.4.0/arch/mips/ath79/early_printk.c
@@ -31,13 +31,15 @@
 	} while (1);
 }
 
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
 static void prom_putchar_ar71xx(unsigned char ch)
 {
 	void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
 
-	prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
+	prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY);
 	__raw_writel(ch, base + UART_TX * 4);
-	prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
+	prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY);
 }
 
 static void prom_putchar_ar933x(unsigned char ch)
--- linux-4.4.0.orig/arch/mips/ath79/setup.c
+++ linux-4.4.0/arch/mips/ath79/setup.c
@@ -44,6 +44,7 @@
 
 static void ath79_restart(char *command)
 {
+	local_irq_disable();
 	ath79_device_reset_set(AR71XX_RESET_FULL_CHIP);
 	for (;;)
 		if (cpu_wait)
--- linux-4.4.0.orig/arch/mips/bcm47xx/Kconfig
+++ linux-4.4.0/arch/mips/bcm47xx/Kconfig
@@ -26,6 +26,7 @@
 	select BCMA
 	select BCMA_HOST_SOC
 	select BCMA_DRIVER_MIPS
+	select BCMA_DRIVER_PCI if PCI
 	select BCMA_DRIVER_PCI_HOSTMODE if PCI
 	select BCMA_DRIVER_GPIO
 	default y
--- linux-4.4.0.orig/arch/mips/bcm47xx/buttons.c
+++ linux-4.4.0/arch/mips/bcm47xx/buttons.c
@@ -17,6 +17,12 @@
 		.active_low	= 1,					\
 	}
 
+#define BCM47XX_GPIO_KEY_H(_gpio, _code)				\
+	{								\
+		.code		= _code,				\
+		.gpio		= _gpio,				\
+	}
+
 /* Asus */
 
 static const struct gpio_keys_button
@@ -79,8 +85,8 @@
 
 static const struct gpio_keys_button
 bcm47xx_buttons_asus_wl500w[] __initconst = {
-	BCM47XX_GPIO_KEY(6, KEY_RESTART),
-	BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON),
+	BCM47XX_GPIO_KEY_H(6, KEY_RESTART),
+	BCM47XX_GPIO_KEY_H(7, KEY_WPS_BUTTON),
 };
 
 static const struct gpio_keys_button
--- linux-4.4.0.orig/arch/mips/bcm47xx/leds.c
+++ linux-4.4.0/arch/mips/bcm47xx/leds.c
@@ -330,7 +330,7 @@
 /* Verified on: WRT54GS V1.0 */
 static const struct gpio_led
 bcm47xx_leds_linksys_wrt54g_type_0101[] __initconst = {
-	BCM47XX_GPIO_LED(0, "green", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+	BCM47XX_GPIO_LED(0, "green", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
 	BCM47XX_GPIO_LED(1, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON),
 	BCM47XX_GPIO_LED(7, "green", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
 };
--- linux-4.4.0.orig/arch/mips/bcm47xx/workarounds.c
+++ linux-4.4.0/arch/mips/bcm47xx/workarounds.c
@@ -4,9 +4,8 @@
 #include <bcm47xx_board.h>
 #include <bcm47xx.h>
 
-static void __init bcm47xx_workarounds_netgear_wnr3500l(void)
+static void __init bcm47xx_workarounds_enable_usb_power(int usb_power)
 {
-	const int usb_power = 12;
 	int err;
 
 	err = gpio_request_one(usb_power, GPIOF_OUT_INIT_HIGH, "usb_power");
@@ -22,7 +21,10 @@
 
 	switch (board) {
 	case BCM47XX_BOARD_NETGEAR_WNR3500L:
-		bcm47xx_workarounds_netgear_wnr3500l();
+		bcm47xx_workarounds_enable_usb_power(12);
+		break;
+	case BCM47XX_BOARD_NETGEAR_WNDR3400_V3:
+		bcm47xx_workarounds_enable_usb_power(21);
 		break;
 	default:
 		/* No workaround(s) needed */
--- linux-4.4.0.orig/arch/mips/bcm63xx/prom.c
+++ linux-4.4.0/arch/mips/bcm63xx/prom.c
@@ -84,7 +84,7 @@
 		 * Here we will start up CPU1 in the background and ask it to
 		 * reconfigure itself then go back to sleep.
 		 */
-		memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20);
+		memcpy((void *)0xa0000200, bmips_smp_movevec, 0x20);
 		__sync();
 		set_c0_cause(C_SW0);
 		cpumask_set_cpu(1, &bmips_booted_mask);
--- linux-4.4.0.orig/arch/mips/bcm63xx/reset.c
+++ linux-4.4.0/arch/mips/bcm63xx/reset.c
@@ -119,7 +119,7 @@
 #define BCM6368_RESET_DSL	0
 #define BCM6368_RESET_SAR	SOFTRESET_6368_SAR_MASK
 #define BCM6368_RESET_EPHY	SOFTRESET_6368_EPHY_MASK
-#define BCM6368_RESET_ENETSW	0
+#define BCM6368_RESET_ENETSW	SOFTRESET_6368_ENETSW_MASK
 #define BCM6368_RESET_PCM	SOFTRESET_6368_PCM_MASK
 #define BCM6368_RESET_MPI	SOFTRESET_6368_MPI_MASK
 #define BCM6368_RESET_PCIE	0
--- linux-4.4.0.orig/arch/mips/boot/compressed/Makefile
+++ linux-4.4.0/arch/mips/boot/compressed/Makefile
@@ -66,6 +66,8 @@
 $(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.bin.z FORCE
 	$(call if_changed,objcopy)
 
+HOSTCFLAGS_calc_vmlinuz_load_addr.o += $(LINUXINCLUDE)
+
 # Calculate the load address of the compressed kernel image
 hostprogs-y := calc_vmlinuz_load_addr
 
--- linux-4.4.0.orig/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c
+++ linux-4.4.0/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c
@@ -13,6 +13,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <linux/sizes.h>
 
 int main(int argc, char *argv[])
 {
@@ -45,11 +46,11 @@
 	vmlinuz_load_addr = vmlinux_load_addr + vmlinux_size;
 
 	/*
-	 * Align with 16 bytes: "greater than that used for any standard data
-	 * types by a MIPS compiler." -- See MIPS Run Linux (Second Edition).
+	 * Align with 64KB: KEXEC needs load sections to be aligned to PAGE_SIZE,
+	 * which may be as large as 64KB depending on the kernel configuration.
 	 */
 
-	vmlinuz_load_addr += (16 - vmlinux_size % 16);
+	vmlinuz_load_addr += (SZ_64K - vmlinux_size % SZ_64K);
 
 	printf("0x%llx\n", vmlinuz_load_addr);
 
--- linux-4.4.0.orig/arch/mips/boot/dts/brcm/bcm7435.dtsi
+++ linux-4.4.0/arch/mips/boot/dts/brcm/bcm7435.dtsi
@@ -7,7 +7,7 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		mips-hpt-frequency = <163125000>;
+		mips-hpt-frequency = <175625000>;
 
 		cpu@0 {
 			compatible = "brcm,bmips5200";
--- linux-4.4.0.orig/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
+++ linux-4.4.0/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
@@ -266,7 +266,7 @@
 		} else {
 			union cvmx_pko_mem_debug8 debug8;
 			debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8);
-			return debug8.cn58xx.doorbell;
+			return debug8.cn50xx.doorbell;
 		}
 	case CVMX_CMD_QUEUE_ZIP:
 	case CVMX_CMD_QUEUE_DFA:
--- linux-4.4.0.orig/arch/mips/cavium-octeon/executive/cvmx-helper.c
+++ linux-4.4.0/arch/mips/cavium-octeon/executive/cvmx-helper.c
@@ -67,7 +67,7 @@
 void (*cvmx_override_ipd_port_setup) (int ipd_port);
 
 /* Port count per interface */
-static int interface_port_count[5];
+static int interface_port_count[9];
 
 /* Port last configured link info index by IPD/PKO port */
 static cvmx_helper_link_info_t
--- linux-4.4.0.orig/arch/mips/cavium-octeon/octeon-irq.c
+++ linux-4.4.0/arch/mips/cavium-octeon/octeon-irq.c
@@ -1220,7 +1220,7 @@
 
 	line = (hw + gpiod->base_hwirq) >> 6;
 	bit = (hw + gpiod->base_hwirq) & 63;
-	if (line > ARRAY_SIZE(octeon_irq_ciu_to_irq) ||
+	if (line >= ARRAY_SIZE(octeon_irq_ciu_to_irq) ||
 		octeon_irq_ciu_to_irq[line][bit] != 0)
 		return -EINVAL;
 
@@ -2168,6 +2168,9 @@
 	}
 
 	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+	if (!cd)
+		return -ENOMEM;
+
 	cd->host_data = host_data;
 	cd->bit = hw;
 
@@ -2240,17 +2243,19 @@
 
 	parent_irq = irq_of_parse_and_map(ciu_node, 0);
 	if (!parent_irq) {
-		pr_err("ERROR: Couldn't acquire parent_irq for %s\n.",
+		pr_err("ERROR: Couldn't acquire parent_irq for %s\n",
 			ciu_node->name);
 		return -EINVAL;
 	}
 
 	host_data = kzalloc(sizeof(*host_data), GFP_KERNEL);
+	if (!host_data)
+		return -ENOMEM;
 	raw_spin_lock_init(&host_data->lock);
 
 	addr = of_get_address(ciu_node, 0, NULL, NULL);
 	if (!addr) {
-		pr_err("ERROR: Couldn't acquire reg(0) %s\n.", ciu_node->name);
+		pr_err("ERROR: Couldn't acquire reg(0) %s\n", ciu_node->name);
 		return -EINVAL;
 	}
 	host_data->raw_reg = (u64)phys_to_virt(
@@ -2258,7 +2263,7 @@
 
 	addr = of_get_address(ciu_node, 1, NULL, NULL);
 	if (!addr) {
-		pr_err("ERROR: Couldn't acquire reg(1) %s\n.", ciu_node->name);
+		pr_err("ERROR: Couldn't acquire reg(1) %s\n", ciu_node->name);
 		return -EINVAL;
 	}
 	host_data->en_reg = (u64)phys_to_virt(
@@ -2266,7 +2271,7 @@
 
 	r = of_property_read_u32(ciu_node, "cavium,max-bits", &val);
 	if (r) {
-		pr_err("ERROR: Couldn't read cavium,max-bits from %s\n.",
+		pr_err("ERROR: Couldn't read cavium,max-bits from %s\n",
 			ciu_node->name);
 		return r;
 	}
@@ -2276,7 +2281,7 @@
 					   &octeon_irq_domain_cib_ops,
 					   host_data);
 	if (!cib_domain) {
-		pr_err("ERROR: Couldn't irq_domain_add_linear()\n.");
+		pr_err("ERROR: Couldn't irq_domain_add_linear()\n");
 		return -ENOMEM;
 	}
 
--- linux-4.4.0.orig/arch/mips/cavium-octeon/octeon-memcpy.S
+++ linux-4.4.0/arch/mips/cavium-octeon/octeon-memcpy.S
@@ -208,18 +208,18 @@
 	ADD	src, src, 16*NBYTES
 EXC(	STORE	t3, UNIT(7)(dst),	s_exc_p9u)
 	ADD	dst, dst, 16*NBYTES
-EXC(	LOAD	t0, UNIT(-8)(src),	l_exc_copy)
-EXC(	LOAD	t1, UNIT(-7)(src),	l_exc_copy)
-EXC(	LOAD	t2, UNIT(-6)(src),	l_exc_copy)
-EXC(	LOAD	t3, UNIT(-5)(src),	l_exc_copy)
+EXC(	LOAD	t0, UNIT(-8)(src),	l_exc_copy_rewind16)
+EXC(	LOAD	t1, UNIT(-7)(src),	l_exc_copy_rewind16)
+EXC(	LOAD	t2, UNIT(-6)(src),	l_exc_copy_rewind16)
+EXC(	LOAD	t3, UNIT(-5)(src),	l_exc_copy_rewind16)
 EXC(	STORE	t0, UNIT(-8)(dst),	s_exc_p8u)
 EXC(	STORE	t1, UNIT(-7)(dst),	s_exc_p7u)
 EXC(	STORE	t2, UNIT(-6)(dst),	s_exc_p6u)
 EXC(	STORE	t3, UNIT(-5)(dst),	s_exc_p5u)
-EXC(	LOAD	t0, UNIT(-4)(src),	l_exc_copy)
-EXC(	LOAD	t1, UNIT(-3)(src),	l_exc_copy)
-EXC(	LOAD	t2, UNIT(-2)(src),	l_exc_copy)
-EXC(	LOAD	t3, UNIT(-1)(src),	l_exc_copy)
+EXC(	LOAD	t0, UNIT(-4)(src),	l_exc_copy_rewind16)
+EXC(	LOAD	t1, UNIT(-3)(src),	l_exc_copy_rewind16)
+EXC(	LOAD	t2, UNIT(-2)(src),	l_exc_copy_rewind16)
+EXC(	LOAD	t3, UNIT(-1)(src),	l_exc_copy_rewind16)
 EXC(	STORE	t0, UNIT(-4)(dst),	s_exc_p4u)
 EXC(	STORE	t1, UNIT(-3)(dst),	s_exc_p3u)
 EXC(	STORE	t2, UNIT(-2)(dst),	s_exc_p2u)
@@ -383,6 +383,10 @@
 	 nop
 	END(memcpy)
 
+l_exc_copy_rewind16:
+	/* Rewind src and dst by 16*NBYTES for l_exc_copy */
+	SUB	src, src, 16*NBYTES
+	SUB	dst, dst, 16*NBYTES
 l_exc_copy:
 	/*
 	 * Copy bytes from src until faulting load address (or until a
--- linux-4.4.0.orig/arch/mips/cavium-octeon/octeon-platform.c
+++ linux-4.4.0/arch/mips/cavium-octeon/octeon-platform.c
@@ -349,6 +349,7 @@
 		return 0;
 
 	pd = of_find_device_by_node(ehci_node);
+	of_node_put(ehci_node);
 	if (!pd)
 		return 0;
 
@@ -411,6 +412,7 @@
 		return 0;
 
 	pd = of_find_device_by_node(ohci_node);
+	of_node_put(ohci_node);
 	if (!pd)
 		return 0;
 
@@ -483,7 +485,7 @@
 	if (phy_addr >= 256 && alt_phy > 0) {
 		const struct fdt_property *phy_prop;
 		struct fdt_property *alt_prop;
-		u32 phy_handle_name;
+		fdt32_t phy_handle_name;
 
 		/* Use the alt phy node instead.*/
 		phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL);
--- linux-4.4.0.orig/arch/mips/cavium-octeon/setup.c
+++ linux-4.4.0/arch/mips/cavium-octeon/setup.c
@@ -251,6 +251,17 @@
 	default_machine_crash_shutdown(regs);
 }
 
+#ifdef CONFIG_SMP
+void octeon_crash_smp_send_stop(void)
+{
+	int cpu;
+
+	/* disable watchdogs */
+	for_each_online_cpu(cpu)
+		cvmx_write_csr(CVMX_CIU_WDOGX(cpu_logical_map(cpu)), 0);
+}
+#endif
+
 #endif /* CONFIG_KEXEC */
 
 #ifdef CONFIG_CAVIUM_RESERVE32
@@ -864,6 +875,9 @@
 	_machine_kexec_shutdown = octeon_shutdown;
 	_machine_crash_shutdown = octeon_crash_shutdown;
 	_machine_kexec_prepare = octeon_kexec_prepare;
+#ifdef CONFIG_SMP
+	_crash_smp_send_stop = octeon_crash_smp_send_stop;
+#endif
 #endif
 
 	octeon_user_io_init();
--- linux-4.4.0.orig/arch/mips/cavium-octeon/smp.c
+++ linux-4.4.0/arch/mips/cavium-octeon/smp.c
@@ -239,6 +239,7 @@
 		return -ENOTSUPP;
 
 	set_cpu_online(cpu, false);
+	calculate_cpu_foreign_map();
 	cpumask_clear_cpu(cpu, &cpu_callin_map);
 	octeon_fixup_irqs();
 
--- linux-4.4.0.orig/arch/mips/configs/ath79_defconfig
+++ linux-4.4.0/arch/mips/configs/ath79_defconfig
@@ -74,6 +74,7 @@
 # CONFIG_SERIAL_8250_PCI is not set
 CONFIG_SERIAL_8250_NR_UARTS=1
 CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_AR933X=y
 CONFIG_SERIAL_AR933X_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
--- linux-4.4.0.orig/arch/mips/configs/ip22_defconfig
+++ linux-4.4.0/arch/mips/configs/ip22_defconfig
@@ -68,8 +68,8 @@
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
--- linux-4.4.0.orig/arch/mips/configs/ip27_defconfig
+++ linux-4.4.0/arch/mips/configs/ip27_defconfig
@@ -134,7 +134,7 @@
 CONFIG_SCSI_QLOGIC_1280=y
 CONFIG_SCSI_PMCRAID=m
 CONFIG_SCSI_BFA_FC=m
-CONFIG_SCSI_DH=m
+CONFIG_SCSI_DH=y
 CONFIG_SCSI_DH_RDAC=m
 CONFIG_SCSI_DH_HP_SW=m
 CONFIG_SCSI_DH_EMC=m
@@ -206,7 +206,6 @@
 # CONFIG_MLX4_DEBUG is not set
 CONFIG_TEHUTI=m
 CONFIG_BNX2X=m
-CONFIG_QLGE=m
 CONFIG_SFC=m
 CONFIG_BE2NET=m
 CONFIG_LIBERTAS_THINFIRM=m
--- linux-4.4.0.orig/arch/mips/configs/lemote2f_defconfig
+++ linux-4.4.0/arch/mips/configs/lemote2f_defconfig
@@ -39,7 +39,7 @@
 CONFIG_PM_STD_PARTITION="/dev/hda3"
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_DEBUG=y
-CONFIG_CPU_FREQ_STAT=m
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_STAT_DETAILS=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
--- linux-4.4.0.orig/arch/mips/configs/malta_defconfig
+++ linux-4.4.0/arch/mips/configs/malta_defconfig
@@ -59,8 +59,8 @@
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
--- linux-4.4.0.orig/arch/mips/configs/malta_kvm_defconfig
+++ linux-4.4.0/arch/mips/configs/malta_kvm_defconfig
@@ -60,8 +60,8 @@
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
--- linux-4.4.0.orig/arch/mips/configs/malta_kvm_guest_defconfig
+++ linux-4.4.0/arch/mips/configs/malta_kvm_guest_defconfig
@@ -59,8 +59,8 @@
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
--- linux-4.4.0.orig/arch/mips/configs/maltaup_xpa_defconfig
+++ linux-4.4.0/arch/mips/configs/maltaup_xpa_defconfig
@@ -61,8 +61,8 @@
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
--- linux-4.4.0.orig/arch/mips/configs/mtx1_defconfig
+++ linux-4.4.0/arch/mips/configs/mtx1_defconfig
@@ -638,7 +638,6 @@
 CONFIG_USB_EMI62=m
 CONFIG_USB_EMI26=m
 CONFIG_USB_ADUTUX=m
-CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
 CONFIG_USB_LED=m
--- linux-4.4.0.orig/arch/mips/configs/nlm_xlp_defconfig
+++ linux-4.4.0/arch/mips/configs/nlm_xlp_defconfig
@@ -111,7 +111,7 @@
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
--- linux-4.4.0.orig/arch/mips/configs/nlm_xlr_defconfig
+++ linux-4.4.0/arch/mips/configs/nlm_xlr_defconfig
@@ -91,7 +91,7 @@
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
--- linux-4.4.0.orig/arch/mips/configs/rm200_defconfig
+++ linux-4.4.0/arch/mips/configs/rm200_defconfig
@@ -351,7 +351,6 @@
 CONFIG_USB_SERIAL_CYBERJACK=m
 CONFIG_USB_SERIAL_XIRCOM=m
 CONFIG_USB_SERIAL_OMNINET=m
-CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
 CONFIG_USB_LED=m
--- linux-4.4.0.orig/arch/mips/dec/int-handler.S
+++ linux-4.4.0/arch/mips/dec/int-handler.S
@@ -146,7 +146,14 @@
 		/*
 		 * Find irq with highest priority
 		 */
-		 PTR_LA	t1,cpu_mask_nr_tbl
+		# open coded PTR_LA t1, cpu_mask_nr_tbl
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+		# open coded la t1, cpu_mask_nr_tbl
+		lui	t1, %hi(cpu_mask_nr_tbl)
+		addiu	t1, %lo(cpu_mask_nr_tbl)
+#else
+#error GCC `-msym32' option required for 64-bit DECstation builds
+#endif
 1:		lw	t2,(t1)
 		nop
 		and	t2,t0
@@ -195,7 +202,14 @@
 		/*
 		 * Find irq with highest priority
 		 */
-		 PTR_LA	t1,asic_mask_nr_tbl
+		# open coded PTR_LA t1,asic_mask_nr_tbl
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+		# open coded la t1, asic_mask_nr_tbl
+		lui	t1, %hi(asic_mask_nr_tbl)
+		addiu	t1, %lo(asic_mask_nr_tbl)
+#else
+#error GCC `-msym32' option required for 64-bit DECstation builds
+#endif
 2:		lw	t2,(t1)
 		nop
 		and	t2,t0
--- linux-4.4.0.orig/arch/mips/fw/sni/sniprom.c
+++ linux-4.4.0/arch/mips/fw/sni/sniprom.c
@@ -42,7 +42,7 @@
 
 /* O32 stack has to be 8-byte aligned. */
 static u64 o32_stk[4096];
-#define O32_STK	  &o32_stk[sizeof(o32_stk)]
+#define O32_STK	  (&o32_stk[ARRAY_SIZE(o32_stk)])
 
 #define __PROM_O32(fun, arg) fun arg __asm__(#fun); \
 				     __asm__(#fun " = call_o32")
--- linux-4.4.0.orig/arch/mips/include/asm/asm.h
+++ linux-4.4.0/arch/mips/include/asm/asm.h
@@ -54,7 +54,8 @@
 		.align	2;				\
 		.type	symbol, @function;		\
 		.ent	symbol, 0;			\
-symbol:		.frame	sp, 0, ra
+symbol:		.frame	sp, 0, ra;			\
+		.insn
 
 /*
  * NESTED - declare nested routine entry point
@@ -63,8 +64,9 @@
 		.globl	symbol;				\
 		.align	2;				\
 		.type	symbol, @function;		\
-		.ent	symbol, 0;			 \
-symbol:		.frame	sp, framesize, rpc
+		.ent	symbol, 0;			\
+symbol:		.frame	sp, framesize, rpc;		\
+		.insn
 
 /*
  * END - mark end of function
@@ -86,7 +88,7 @@
 #define FEXPORT(symbol)					\
 		.globl	symbol;				\
 		.type	symbol, @function;		\
-symbol:
+symbol:		.insn
 
 /*
  * ABS - export absolute symbol
--- linux-4.4.0.orig/arch/mips/include/asm/asmmacro.h
+++ linux-4.4.0/arch/mips/include/asm/asmmacro.h
@@ -135,6 +135,7 @@
 	ldc1	$f28, THREAD_FPR28(\thread)
 	ldc1	$f30, THREAD_FPR30(\thread)
 	ctc1	\tmp, fcr31
+	.set	pop
 	.endm
 
 	.macro	fpu_restore_16odd thread
@@ -298,21 +299,21 @@
 	.set	pop
 	.endm
 
-	.macro	copy_u_w	ws, n
+	.macro	copy_s_w	ws, n
 	.set	push
 	.set	mips32r2
 	.set	fp=64
 	.set	msa
-	copy_u.w $1, $w\ws[\n]
+	copy_s.w $1, $w\ws[\n]
 	.set	pop
 	.endm
 
-	.macro	copy_u_d	ws, n
+	.macro	copy_s_d	ws, n
 	.set	push
 	.set	mips64r2
 	.set	fp=64
 	.set	msa
-	copy_u.d $1, $w\ws[\n]
+	copy_s.d $1, $w\ws[\n]
 	.set	pop
 	.endm
 
@@ -346,8 +347,8 @@
 #define STH_MSA_INSN		0x5800081f
 #define STW_MSA_INSN		0x5800082f
 #define STD_MSA_INSN		0x5800083f
-#define COPY_UW_MSA_INSN	0x58f00056
-#define COPY_UD_MSA_INSN	0x58f80056
+#define COPY_SW_MSA_INSN	0x58b00056
+#define COPY_SD_MSA_INSN	0x58b80056
 #define INSERT_W_MSA_INSN	0x59300816
 #define INSERT_D_MSA_INSN	0x59380816
 #else
@@ -361,8 +362,8 @@
 #define STH_MSA_INSN		0x78000825
 #define STW_MSA_INSN		0x78000826
 #define STD_MSA_INSN		0x78000827
-#define COPY_UW_MSA_INSN	0x78f00059
-#define COPY_UD_MSA_INSN	0x78f80059
+#define COPY_SW_MSA_INSN	0x78b00059
+#define COPY_SD_MSA_INSN	0x78b80059
 #define INSERT_W_MSA_INSN	0x79300819
 #define INSERT_D_MSA_INSN	0x79380819
 #endif
@@ -393,7 +394,7 @@
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
-	addu	$1, \base, \off
+	PTR_ADDU $1, \base, \off
 	.word	LDB_MSA_INSN | (\wd << 6)
 	.set	pop
 	.endm
@@ -402,7 +403,7 @@
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
-	addu	$1, \base, \off
+	PTR_ADDU $1, \base, \off
 	.word	LDH_MSA_INSN | (\wd << 6)
 	.set	pop
 	.endm
@@ -411,7 +412,7 @@
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
-	addu	$1, \base, \off
+	PTR_ADDU $1, \base, \off
 	.word	LDW_MSA_INSN | (\wd << 6)
 	.set	pop
 	.endm
@@ -420,7 +421,7 @@
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
-	addu	$1, \base, \off
+	PTR_ADDU $1, \base, \off
 	.word	LDD_MSA_INSN | (\wd << 6)
 	.set	pop
 	.endm
@@ -429,7 +430,7 @@
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
-	addu	$1, \base, \off
+	PTR_ADDU $1, \base, \off
 	.word	STB_MSA_INSN | (\wd << 6)
 	.set	pop
 	.endm
@@ -438,7 +439,7 @@
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
-	addu	$1, \base, \off
+	PTR_ADDU $1, \base, \off
 	.word	STH_MSA_INSN | (\wd << 6)
 	.set	pop
 	.endm
@@ -447,7 +448,7 @@
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
-	addu	$1, \base, \off
+	PTR_ADDU $1, \base, \off
 	.word	STW_MSA_INSN | (\wd << 6)
 	.set	pop
 	.endm
@@ -456,26 +457,26 @@
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
-	addu	$1, \base, \off
+	PTR_ADDU $1, \base, \off
 	.word	STD_MSA_INSN | (\wd << 6)
 	.set	pop
 	.endm
 
-	.macro	copy_u_w	ws, n
+	.macro	copy_s_w	ws, n
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
 	.insn
-	.word	COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11)
+	.word	COPY_SW_MSA_INSN | (\n << 16) | (\ws << 11)
 	.set	pop
 	.endm
 
-	.macro	copy_u_d	ws, n
+	.macro	copy_s_d	ws, n
 	.set	push
 	.set	noat
 	SET_HARDFLOAT
 	.insn
-	.word	COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11)
+	.word	COPY_SD_MSA_INSN | (\n << 16) | (\ws << 11)
 	.set	pop
 	.endm
 
--- linux-4.4.0.orig/arch/mips/include/asm/bmips.h
+++ linux-4.4.0/arch/mips/include/asm/bmips.h
@@ -75,11 +75,11 @@
 #endif
 }
 
-extern char bmips_reset_nmi_vec;
-extern char bmips_reset_nmi_vec_end;
-extern char bmips_smp_movevec;
-extern char bmips_smp_int_vec;
-extern char bmips_smp_int_vec_end;
+extern char bmips_reset_nmi_vec[];
+extern char bmips_reset_nmi_vec_end[];
+extern char bmips_smp_movevec[];
+extern char bmips_smp_int_vec[];
+extern char bmips_smp_int_vec_end[];
 
 extern int bmips_smp_enabled;
 extern int bmips_cpu_offset;
--- linux-4.4.0.orig/arch/mips/include/asm/branch.h
+++ linux-4.4.0/arch/mips/include/asm/branch.h
@@ -74,10 +74,7 @@
 			return __microMIPS_compute_return_epc(regs);
 		if (cpu_has_mips16)
 			return __MIPS16e_compute_return_epc(regs);
-		return regs->cp0_epc;
-	}
-
-	if (!delay_slot(regs)) {
+	} else if (!delay_slot(regs)) {
 		regs->cp0_epc += 4;
 		return 0;
 	}
--- linux-4.4.0.orig/arch/mips/include/asm/cacheflush.h
+++ linux-4.4.0/arch/mips/include/asm/cacheflush.h
@@ -51,7 +51,6 @@
 	unsigned long start, unsigned long end);
 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
 extern void __flush_dcache_page(struct page *page);
-extern void __flush_icache_page(struct vm_area_struct *vma, struct page *page);
 
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 static inline void flush_dcache_page(struct page *page)
@@ -77,11 +76,6 @@
 static inline void flush_icache_page(struct vm_area_struct *vma,
 	struct page *page)
 {
-	if (!cpu_has_ic_fills_f_dc && (vma->vm_flags & VM_EXEC) &&
-	    Page_dcache_dirty(page)) {
-		__flush_icache_page(vma, page);
-		ClearPageDcacheDirty(page);
-	}
 }
 
 extern void (*flush_icache_range)(unsigned long start, unsigned long end);
--- linux-4.4.0.orig/arch/mips/include/asm/checksum.h
+++ linux-4.4.0/arch/mips/include/asm/checksum.h
@@ -186,7 +186,9 @@
 	"	daddu	%0, %4		\n"
 	"	dsll32	$1, %0, 0	\n"
 	"	daddu	%0, $1		\n"
+	"	sltu	$1, %0, $1	\n"
 	"	dsra32	%0, %0, 0	\n"
+	"	addu	%0, $1		\n"
 #endif
 	"	.set	pop"
 	: "=r" (sum)
--- linux-4.4.0.orig/arch/mips/include/asm/compiler.h
+++ linux-4.4.0/arch/mips/include/asm/compiler.h
@@ -8,6 +8,41 @@
 #ifndef _ASM_COMPILER_H
 #define _ASM_COMPILER_H
 
+/*
+ * With GCC 4.5 onwards we can use __builtin_unreachable to indicate to the
+ * compiler that a particular code path will never be hit. This allows it to be
+ * optimised out of the generated binary.
+ *
+ * Unfortunately at least GCC 4.6.3 through 7.3.0 inclusive suffer from a bug
+ * that can lead to instructions from beyond an unreachable statement being
+ * incorrectly reordered into earlier delay slots if the unreachable statement
+ * is the only content of a case in a switch statement. This can lead to
+ * seemingly random behaviour, such as invalid memory accesses from incorrectly
+ * reordered loads or stores. See this potential GCC fix for details:
+ *
+ *   https://gcc.gnu.org/ml/gcc-patches/2015-09/msg00360.html
+ *
+ * It is unclear whether GCC 8 onwards suffer from the same issue - nothing
+ * relevant is mentioned in GCC 8 release notes and nothing obviously relevant
+ * stands out in GCC commit logs, but these newer GCC versions generate very
+ * different code for the testcase which doesn't exhibit the bug.
+ *
+ * GCC also handles stack allocation suboptimally when calling noreturn
+ * functions or calling __builtin_unreachable():
+ *
+ *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365
+ *
+ * We work around both of these issues by placing a volatile asm statement,
+ * which GCC is prevented from reordering past, prior to __builtin_unreachable
+ * calls.
+ *
+ * The .insn statement is required to ensure that any branches to the
+ * statement, which sadly must be kept due to the asm statement, are known to
+ * be branches to code and satisfy linker requirements for microMIPS kernels.
+ */
+#undef barrier_before_unreachable
+#define barrier_before_unreachable() asm volatile(".insn")
+
 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 #define GCC_IMM_ASM() "n"
 #define GCC_REG_ACCUM "$0"
--- linux-4.4.0.orig/arch/mips/include/asm/cpu-type.h
+++ linux-4.4.0/arch/mips/include/asm/cpu-type.h
@@ -46,6 +46,7 @@
 	case CPU_34K:
 	case CPU_1004K:
 	case CPU_74K:
+	case CPU_1074K:
 	case CPU_M14KC:
 	case CPU_M14KEC:
 	case CPU_INTERAPTIV:
--- linux-4.4.0.orig/arch/mips/include/asm/elf.h
+++ linux-4.4.0/arch/mips/include/asm/elf.h
@@ -420,6 +420,7 @@
 #define ELF_ET_DYN_BASE		(TASK_SIZE / 3 * 2)
 #endif
 
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
 #define ARCH_DLINFO							\
 do {									\
 	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
--- linux-4.4.0.orig/arch/mips/include/asm/fpu_emulator.h
+++ linux-4.4.0/arch/mips/include/asm/fpu_emulator.h
@@ -66,6 +66,8 @@
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
 				    struct mips_fpu_struct *ctx, int has_fpu,
 				    void *__user *fault_addr);
+void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
+		     struct task_struct *tsk);
 int process_fpemu_return(int sig, void __user *fault_addr,
 			 unsigned long fcr31);
 int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
@@ -92,4 +94,15 @@
 		set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
 }
 
+/*
+ * Mask the FCSR Cause bits according to the Enable bits, observing
+ * that Unimplemented is always enabled.
+ */
+static inline unsigned long mask_fcr31_x(unsigned long fcr31)
+{
+	return fcr31 & (FPU_CSR_UNI_X |
+			((fcr31 & FPU_CSR_ALL_E) <<
+			 (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E))));
+}
+
 #endif /* _ASM_FPU_EMULATOR_H */
--- linux-4.4.0.orig/arch/mips/include/asm/futex.h
+++ linux-4.4.0/arch/mips/include/asm/futex.h
@@ -83,18 +83,9 @@
 }
 
 static inline int
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -125,17 +116,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/mips/include/asm/io.h
+++ linux-4.4.0/arch/mips/include/asm/io.h
@@ -60,21 +60,11 @@
  * instruction, so the lower 16 bits must be zero.  Should be true on
  * on any sane architecture; generic code does not use this assumption.
  */
-extern const unsigned long mips_io_port_base;
+extern unsigned long mips_io_port_base;
 
-/*
- * Gcc will generate code to load the value of mips_io_port_base after each
- * function call which may be fairly wasteful in some cases.  So we don't
- * play quite by the book.  We tell gcc mips_io_port_base is a long variable
- * which solves the code generation issue.  Now we need to violate the
- * aliasing rules a little to make initialization possible and finally we
- * will need the barrier() to fight side effects of the aliasing chat.
- * This trickery will eventually collapse under gcc's optimizer.  Oh well.
- */
 static inline void set_io_port_base(unsigned long base)
 {
-	* (unsigned long *) &mips_io_port_base = base;
-	barrier();
+	mips_io_port_base = base;
 }
 
 /*
@@ -141,14 +131,14 @@
 /*
  * ISA I/O bus memory addresses are 1:1 with the physical address.
  */
-static inline unsigned long isa_virt_to_bus(volatile void * address)
+static inline unsigned long isa_virt_to_bus(volatile void *address)
 {
-	return (unsigned long)address - PAGE_OFFSET;
+	return virt_to_phys(address);
 }
 
-static inline void * isa_bus_to_virt(unsigned long address)
+static inline void *isa_bus_to_virt(unsigned long address)
 {
-	return (void *)(address + PAGE_OFFSET);
+	return phys_to_virt(address);
 }
 
 #define isa_page_to_bus page_to_phys
@@ -411,6 +401,8 @@
 	__val = *__addr;						\
 	slow;								\
 									\
+	/* prevent prefetching of coherent DMA data prematurely */	\
+	rmb();								\
 	return pfx##ioswab##bwlq(__addr, __val);			\
 }
 
--- linux-4.4.0.orig/arch/mips/include/asm/irq.h
+++ linux-4.4.0/arch/mips/include/asm/irq.h
@@ -17,6 +17,33 @@
 
 #include <irq.h>
 
+#define IRQ_STACK_SIZE			THREAD_SIZE
+#define IRQ_STACK_START			(IRQ_STACK_SIZE - 16)
+
+extern void *irq_stack[NR_CPUS];
+
+/*
+ * The highest address on the IRQ stack contains a dummy frame put down in
+ * genex.S (handle_int & except_vec_vi_handler) which is structured as follows:
+ *
+ *   top ------------
+ *       | task sp  | <- irq_stack[cpu] + IRQ_STACK_START
+ *       ------------
+ *       |          | <- First frame of IRQ context
+ *       ------------
+ *
+ * task sp holds a copy of the task stack pointer where the struct pt_regs
+ * from exception entry can be found.
+ */
+
+static inline bool on_irq_stack(int cpu, unsigned long sp)
+{
+	unsigned long low = (unsigned long)irq_stack[cpu];
+	unsigned long high = low + IRQ_STACK_SIZE;
+
+	return (low <= sp && sp <= high);
+}
+
 #ifdef CONFIG_I8259
 static inline int irq_canonicalize(int irq)
 {
--- linux-4.4.0.orig/arch/mips/include/asm/jump_label.h
+++ linux-4.4.0/arch/mips/include/asm/jump_label.h
@@ -21,15 +21,15 @@
 #endif
 
 #ifdef CONFIG_CPU_MICROMIPS
-#define NOP_INSN "nop32"
+#define B_INSN "b32"
 #else
-#define NOP_INSN "nop"
+#define B_INSN "b"
 #endif
 
 static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
 {
-	asm_volatile_goto("1:\t" NOP_INSN "\n\t"
-		"nop\n\t"
+	asm_volatile_goto("1:\t" B_INSN " 2f\n\t"
+		"2:\tnop\n\t"
 		".pushsection __jump_table,  \"aw\"\n\t"
 		WORD_INSN " 1b, %l[l_yes], %0\n\t"
 		".popsection\n\t"
--- linux-4.4.0.orig/arch/mips/include/asm/kexec.h
+++ linux-4.4.0/arch/mips/include/asm/kexec.h
@@ -12,11 +12,11 @@
 #include <asm/stacktrace.h>
 
 /* Maximum physical address we can use pages from */
-#define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000)
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
 /* Maximum address we can reach in physical address mode */
-#define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000)
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
  /* Maximum address we can use for the control code buffer */
-#define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000)
+#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
 /* Reserve 3*4096 bytes for board-specific info */
 #define KEXEC_CONTROL_PAGE_SIZE (4096 + 3*4096)
 
@@ -45,6 +45,7 @@
 extern unsigned long secondary_kexec_args[4];
 extern void (*relocated_kexec_smp_wait) (void *);
 extern atomic_t kexec_ready_to_reboot;
+extern void (*_crash_smp_send_stop)(void);
 #endif
 #endif
 
--- linux-4.4.0.orig/arch/mips/include/asm/kprobes.h
+++ linux-4.4.0/arch/mips/include/asm/kprobes.h
@@ -40,7 +40,8 @@
 
 #define flush_insn_slot(p)						\
 do {									\
-	flush_icache_range((unsigned long)p->addr,			\
+	if (p->addr)							\
+		flush_icache_range((unsigned long)p->addr,		\
 			   (unsigned long)p->addr +			\
 			   (MAX_INSN_SIZE * sizeof(kprobe_opcode_t)));	\
 } while (0)
--- linux-4.4.0.orig/arch/mips/include/asm/kvm_host.h
+++ linux-4.4.0/arch/mips/include/asm/kvm_host.h
@@ -372,6 +372,7 @@
 #define KVM_MIPS_GUEST_TLB_SIZE	64
 struct kvm_vcpu_arch {
 	void *host_ebase, *guest_ebase;
+	int (*vcpu_run)(struct kvm_run *run, struct kvm_vcpu *vcpu);
 	unsigned long host_stack;
 	unsigned long host_gp;
 
@@ -399,7 +400,10 @@
 	/* Host KSEG0 address of the EI/DI offset */
 	void *kseg0_commpage;
 
-	u32 io_gpr;		/* GPR used as IO source/target */
+	/* Resume PC after MMIO completion */
+	unsigned long io_pc;
+	/* GPR used as IO source/target */
+	u32 io_gpr;
 
 	struct hrtimer comparecount_timer;
 	/* Count timer control KVM register */
@@ -421,8 +425,6 @@
 	/* Bitmask of pending exceptions to be cleared */
 	unsigned long pending_exceptions_clr;
 
-	unsigned long pending_load_cause;
-
 	/* Save/Restore the entryhi register when are are preempted/scheduled back in */
 	unsigned long preempt_entryhi;
 
@@ -784,7 +786,7 @@
 
 uint32_t kvm_mips_read_count(struct kvm_vcpu *vcpu);
 void kvm_mips_write_count(struct kvm_vcpu *vcpu, uint32_t count);
-void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare);
+void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare, bool ack);
 void kvm_mips_init_count(struct kvm_vcpu *vcpu);
 int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl);
 int kvm_mips_set_count_resume(struct kvm_vcpu *vcpu, s64 count_resume);
--- linux-4.4.0.orig/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ linux-4.4.0/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -167,7 +167,7 @@
 #define AR71XX_AHB_DIV_MASK		0x7
 
 #define AR724X_PLL_REG_CPU_CONFIG	0x00
-#define AR724X_PLL_REG_PCIE_CONFIG	0x18
+#define AR724X_PLL_REG_PCIE_CONFIG	0x10
 
 #define AR724X_PLL_FB_SHIFT		0
 #define AR724X_PLL_FB_MASK		0x3ff
--- linux-4.4.0.orig/arch/mips/include/asm/mach-ath79/ar933x_uart.h
+++ linux-4.4.0/arch/mips/include/asm/mach-ath79/ar933x_uart.h
@@ -27,8 +27,8 @@
 #define AR933X_UART_CS_PARITY_S		0
 #define AR933X_UART_CS_PARITY_M		0x3
 #define	  AR933X_UART_CS_PARITY_NONE	0
-#define	  AR933X_UART_CS_PARITY_ODD	1
-#define	  AR933X_UART_CS_PARITY_EVEN	2
+#define	  AR933X_UART_CS_PARITY_ODD	2
+#define	  AR933X_UART_CS_PARITY_EVEN	3
 #define AR933X_UART_CS_IF_MODE_S	2
 #define AR933X_UART_CS_IF_MODE_M	0x3
 #define	  AR933X_UART_CS_IF_MODE_NONE	0
--- linux-4.4.0.orig/arch/mips/include/asm/mach-ath79/ath79.h
+++ linux-4.4.0/arch/mips/include/asm/mach-ath79/ath79.h
@@ -133,6 +133,7 @@
 static inline void ath79_reset_wr(unsigned reg, u32 val)
 {
 	__raw_writel(val, ath79_reset_base + reg);
+	(void) __raw_readl(ath79_reset_base + reg); /* flush */
 }
 
 static inline u32 ath79_reset_rr(unsigned reg)
--- linux-4.4.0.orig/arch/mips/include/asm/mach-loongson64/irq.h
+++ linux-4.4.0/arch/mips/include/asm/mach-loongson64/irq.h
@@ -9,7 +9,7 @@
 #define MIPS_CPU_IRQ_BASE 56
 
 #define LOONGSON_UART_IRQ   (MIPS_CPU_IRQ_BASE + 2) /* UART */
-#define LOONGSON_HT1_IRQ    (MIPS_CPU_IRQ_BASE + 3) /* HT1 */
+#define LOONGSON_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 3) /* CASCADE */
 #define LOONGSON_TIMER_IRQ  (MIPS_CPU_IRQ_BASE + 7) /* CPU Timer */
 
 #define LOONGSON_HT1_CFG_BASE		loongson_sysconf.ht_control_base
--- linux-4.4.0.orig/arch/mips/include/asm/mach-paravirt/kernel-entry-init.h
+++ linux-4.4.0/arch/mips/include/asm/mach-paravirt/kernel-entry-init.h
@@ -11,11 +11,13 @@
 #define CP0_EBASE $15, 1
 
 	.macro  kernel_entry_setup
+#ifdef CONFIG_SMP
 	mfc0	t0, CP0_EBASE
 	andi	t0, t0, 0x3ff		# CPUNum
 	beqz	t0, 1f
 	# CPUs other than zero goto smp_bootstrap
 	j	smp_bootstrap
+#endif /* CONFIG_SMP */
 
 1:
 	.endm
--- linux-4.4.0.orig/arch/mips/include/asm/mips-cm.h
+++ linux-4.4.0/arch/mips/include/asm/mips-cm.h
@@ -238,8 +238,8 @@
 #define CM_GCR_BASE_GCRBASE_MSK			(_ULCAST_(0x1ffff) << 15)
 #define CM_GCR_BASE_CMDEFTGT_SHF		0
 #define CM_GCR_BASE_CMDEFTGT_MSK		(_ULCAST_(0x3) << 0)
-#define  CM_GCR_BASE_CMDEFTGT_DISABLED		0
-#define  CM_GCR_BASE_CMDEFTGT_MEM		1
+#define  CM_GCR_BASE_CMDEFTGT_MEM		0
+#define  CM_GCR_BASE_CMDEFTGT_RESERVED		1
 #define  CM_GCR_BASE_CMDEFTGT_IOCU0		2
 #define  CM_GCR_BASE_CMDEFTGT_IOCU1		3
 
--- linux-4.4.0.orig/arch/mips/include/asm/msa.h
+++ linux-4.4.0/arch/mips/include/asm/msa.h
@@ -147,6 +147,19 @@
 		_restore_msa(t);
 }
 
+static inline void init_msa_upper(void)
+{
+	/*
+	 * Check cpu_has_msa only if it's a constant. This will allow the
+	 * compiler to optimise out code for CPUs without MSA without adding
+	 * an extra redundant check for CPUs with MSA.
+	 */
+	if (__builtin_constant_p(cpu_has_msa) && !cpu_has_msa)
+		return;
+
+	_init_msa_upper();
+}
+
 #ifdef TOOLCHAIN_SUPPORTS_MSA
 
 #define __BUILD_MSA_CTL_REG(name, cs)				\
--- linux-4.4.0.orig/arch/mips/include/asm/netlogic/xlr/fmn.h
+++ linux-4.4.0/arch/mips/include/asm/netlogic/xlr/fmn.h
@@ -301,8 +301,6 @@
 	for (i = 0; i < 8; i++) {
 		nlm_msgsnd(dest);
 		status = nlm_read_c2_status0();
-		if ((status & 0x2) == 1)
-			pr_info("Send pending fail!\n");
 		if ((status & 0x4) == 0)
 			return 0;
 	}
--- linux-4.4.0.orig/arch/mips/include/asm/octeon/cvmx-pko.h
+++ linux-4.4.0/arch/mips/include/asm/octeon/cvmx-pko.h
@@ -611,7 +611,7 @@
 		pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num);
 		cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
 		debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8);
-		status->doorbell = debug8.cn58xx.doorbell;
+		status->doorbell = debug8.cn50xx.doorbell;
 	}
 }
 
--- linux-4.4.0.orig/arch/mips/include/asm/page.h
+++ linux-4.4.0/arch/mips/include/asm/page.h
@@ -33,7 +33,7 @@
 #define PAGE_SHIFT	16
 #endif
 #define PAGE_SIZE	(_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK	(~(PAGE_SIZE - 1))
+#define PAGE_MASK	(~((1 << PAGE_SHIFT) - 1))
 
 /*
  * This is used for calculating the real page sizes
--- linux-4.4.0.orig/arch/mips/include/asm/pci.h
+++ linux-4.4.0/arch/mips/include/asm/pci.h
@@ -89,7 +89,7 @@
 	phys_addr_t size = resource_size(rsrc);
 
 	*start = fixup_bigphys_addr(rsrc->start, size);
-	*end = rsrc->start + size;
+	*end = rsrc->start + size - 1;
 }
 
 /*
--- linux-4.4.0.orig/arch/mips/include/asm/pgtable-32.h
+++ linux-4.4.0/arch/mips/include/asm/pgtable-32.h
@@ -18,6 +18,10 @@
 
 #include <asm-generic/pgtable-nopmd.h>
 
+#ifdef CONFIG_HIGHMEM
+#include <asm/highmem.h>
+#endif
+
 extern int temp_tlb_entry;
 
 /*
@@ -61,7 +65,8 @@
 
 #define VMALLOC_START	  MAP_BASE
 
-#define PKMAP_BASE		(0xfe000000UL)
+#define PKMAP_END	((FIXADDR_START) & ~((LAST_PKMAP << PAGE_SHIFT)-1))
+#define PKMAP_BASE	(PKMAP_END - PAGE_SIZE * LAST_PKMAP)
 
 #ifdef CONFIG_HIGHMEM
 # define VMALLOC_END	(PKMAP_BASE-2*PAGE_SIZE)
--- linux-4.4.0.orig/arch/mips/include/asm/pgtable-64.h
+++ linux-4.4.0/arch/mips/include/asm/pgtable-64.h
@@ -189,6 +189,11 @@
 
 static inline int pmd_present(pmd_t pmd)
 {
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
+	if (unlikely(pmd_val(pmd) & _PAGE_HUGE))
+		return pmd_val(pmd) & _PAGE_PRESENT;
+#endif
+
 	return pmd_val(pmd) != (unsigned long) invalid_pte_table;
 }
 
--- linux-4.4.0.orig/arch/mips/include/asm/pgtable.h
+++ linux-4.4.0/arch/mips/include/asm/pgtable.h
@@ -127,10 +127,14 @@
 	}								\
 } while(0)
 
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pteval);
+
 #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
 
 #define pte_none(pte)		(!(((pte).pte_high) & ~_PAGE_GLOBAL))
 #define pte_present(pte)	((pte).pte_low & _PAGE_PRESENT)
+#define pte_no_exec(pte)	((pte).pte_low & _PAGE_NO_EXEC)
 
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
@@ -148,7 +152,6 @@
 			buddy->pte_high |= _PAGE_GLOBAL;
 	}
 }
-#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
@@ -166,6 +169,7 @@
 
 #define pte_none(pte)		(!(pte_val(pte) & ~_PAGE_GLOBAL))
 #define pte_present(pte)	(pte_val(pte) & _PAGE_PRESENT)
+#define pte_no_exec(pte)	(pte_val(pte) & _PAGE_NO_EXEC)
 
 /*
  * Certain architectures need to do special things when pte's
@@ -218,7 +222,6 @@
 	}
 #endif
 }
-#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
@@ -234,6 +237,22 @@
 }
 #endif
 
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pteval)
+{
+	extern void __update_cache(unsigned long address, pte_t pte);
+
+	if (!pte_present(pteval))
+		goto cache_sync_done;
+
+	if (pte_present(*ptep) && (pte_pfn(*ptep) == pte_pfn(pteval)))
+		goto cache_sync_done;
+
+	__update_cache(addr, pteval);
+cache_sync_done:
+	set_pte(ptep, pteval);
+}
+
 /*
  * (pmds are folded into puds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
@@ -353,7 +372,7 @@
 static inline pte_t pte_mkyoung(pte_t pte)
 {
 	pte_val(pte) |= _PAGE_ACCESSED;
-#ifdef CONFIG_CPU_MIPSR2
+#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
 	if (!(pte_val(pte) & _PAGE_NO_READ))
 		pte_val(pte) |= _PAGE_SILENT_READ;
 	else
@@ -430,15 +449,12 @@
 
 extern void __update_tlb(struct vm_area_struct *vma, unsigned long address,
 	pte_t pte);
-extern void __update_cache(struct vm_area_struct *vma, unsigned long address,
-	pte_t pte);
 
 static inline void update_mmu_cache(struct vm_area_struct *vma,
 	unsigned long address, pte_t *ptep)
 {
 	pte_t pte = *ptep;
 	__update_tlb(vma, address, pte);
-	__update_cache(vma, address, pte);
 }
 
 static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
@@ -560,7 +576,7 @@
 {
 	pmd_val(pmd) |= _PAGE_ACCESSED;
 
-#ifdef CONFIG_CPU_MIPSR2
+#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
 	if (!(pmd_val(pmd) & _PAGE_NO_READ))
 		pmd_val(pmd) |= _PAGE_SILENT_READ;
 	else
--- linux-4.4.0.orig/arch/mips/include/asm/processor.h
+++ linux-4.4.0/arch/mips/include/asm/processor.h
@@ -45,7 +45,7 @@
  * User space process size: 2GB. This is hardcoded into a few places,
  * so don't change it unless you know what you are doing.
  */
-#define TASK_SIZE	0x7fff8000UL
+#define TASK_SIZE	0x80000000UL
 #endif
 
 #define STACK_TOP_MAX	TASK_SIZE
@@ -131,7 +131,7 @@
 
 #define NUM_DSP_REGS   6
 
-typedef __u32 dspreg_t;
+typedef unsigned long dspreg_t;
 
 struct mips_dsp_state {
 	dspreg_t	dspr[NUM_DSP_REGS];
--- linux-4.4.0.orig/arch/mips/include/asm/ptrace.h
+++ linux-4.4.0/arch/mips/include/asm/ptrace.h
@@ -152,7 +152,7 @@
 
 static inline long regs_return_value(struct pt_regs *regs)
 {
-	if (is_syscall_success(regs))
+	if (is_syscall_success(regs) || !user_mode(regs))
 		return regs->regs[2];
 	else
 		return -regs->regs[2];
--- linux-4.4.0.orig/arch/mips/include/asm/r4kcache.h
+++ linux-4.4.0/arch/mips/include/asm/r4kcache.h
@@ -210,7 +210,11 @@
 
 static inline void protected_writeback_scache_line(unsigned long addr)
 {
+#ifdef CONFIG_EVA
+	protected_cachee_op(Hit_Writeback_Inv_SD, addr);
+#else
 	protected_cache_op(Hit_Writeback_Inv_SD, addr);
+#endif
 }
 
 /*
--- linux-4.4.0.orig/arch/mips/include/asm/smp.h
+++ linux-4.4.0/arch/mips/include/asm/smp.h
@@ -25,7 +25,17 @@
 extern cpumask_t cpu_core_map[];
 extern cpumask_t cpu_foreign_map;
 
-#define raw_smp_processor_id() (current_thread_info()->cpu)
+static inline int raw_smp_processor_id(void)
+{
+#if defined(__VDSO__)
+	extern int vdso_smp_processor_id(void)
+		__compiletime_error("VDSO should not call smp_processor_id()");
+	return vdso_smp_processor_id();
+#else
+	return current_thread_info()->cpu;
+#endif
+}
+#define raw_smp_processor_id raw_smp_processor_id
 
 /* Map from cpu id to sequential logical cpu number.  This will only
    not be idempotent when cpus failed to come on-line.	*/
@@ -53,6 +63,8 @@
 
 extern void asmlinkage smp_bootstrap(void);
 
+extern void calculate_cpu_foreign_map(void);
+
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
--- linux-4.4.0.orig/arch/mips/include/asm/spinlock.h
+++ linux-4.4.0/arch/mips/include/asm/spinlock.h
@@ -112,7 +112,7 @@
 		"	andi	%[ticket], %[ticket], 0xffff		\n"
 		"	bne	%[ticket], %[my_ticket], 4f		\n"
 		"	 subu	%[ticket], %[my_ticket], %[ticket]	\n"
-		"2:							\n"
+		"2:	.insn						\n"
 		"	.subsection 2					\n"
 		"4:	andi	%[ticket], %[ticket], 0xffff		\n"
 		"	sll	%[ticket], 5				\n"
@@ -187,7 +187,7 @@
 		"	sc	%[ticket], %[ticket_ptr]		\n"
 		"	beqz	%[ticket], 1b				\n"
 		"	 li	%[ticket], 1				\n"
-		"2:							\n"
+		"2:	.insn						\n"
 		"	.subsection 2					\n"
 		"3:	b	2b					\n"
 		"	 li	%[ticket], 0				\n"
@@ -367,7 +367,7 @@
 		"	.set	reorder					\n"
 		__WEAK_LLSC_MB
 		"	li	%2, 1					\n"
-		"2:							\n"
+		"2:	.insn						\n"
 		: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
 		: GCC_OFF_SMALL_ASM() (rw->lock)
 		: "memory");
@@ -407,7 +407,7 @@
 			"	lui	%1, 0x8000			\n"
 			"	sc	%1, %0				\n"
 			"	li	%2, 1				\n"
-			"2:						\n"
+			"2:	.insn					\n"
 			: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp),
 			  "=&r" (ret)
 			: GCC_OFF_SMALL_ASM() (rw->lock)
--- linux-4.4.0.orig/arch/mips/include/asm/stackframe.h
+++ linux-4.4.0/arch/mips/include/asm/stackframe.h
@@ -216,12 +216,19 @@
 		LONG_S	$25, PT_R25(sp)
 		LONG_S	$28, PT_R28(sp)
 		LONG_S	$31, PT_R31(sp)
+
+		/* Set thread_info if we're coming from user mode */
+		mfc0	k0, CP0_STATUS
+		sll	k0, 3		/* extract cu0 bit */
+		bltz	k0, 9f
+
 		ori	$28, sp, _THREAD_MASK
 		xori	$28, _THREAD_MASK
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
 		.set    mips64
 		pref    0, 0($28)       /* Prefetch the current pointer */
 #endif
+9:
 		.set	pop
 		.endm
 
--- linux-4.4.0.orig/arch/mips/include/asm/switch_to.h
+++ linux-4.4.0/arch/mips/include/asm/switch_to.h
@@ -76,6 +76,22 @@
 } while (0)
 
 /*
+ * Check FCSR for any unmasked exceptions pending set with `ptrace',
+ * clear them and send a signal.
+ */
+#define __sanitize_fcr31(next)						\
+do {									\
+	unsigned long fcr31 = mask_fcr31_x(next->thread.fpu.fcr31);	\
+	void __user *pc;						\
+									\
+	if (unlikely(fcr31)) {						\
+		pc = (void __user *)task_pt_regs(next)->cp0_epc;	\
+		next->thread.fpu.fcr31 &= ~fcr31;			\
+		force_fcr31_sig(fcr31, pc, next);			\
+	}								\
+} while (0)
+
+/*
  * For newly created kernel threads switch_to() will return to
  * ret_from_kernel_thread, newly created user threads to ret_from_fork.
  * That is, everything following resume() will be skipped for new threads.
@@ -85,6 +101,8 @@
 do {									\
 	__mips_mt_fpaff_switch_to(prev);				\
 	lose_fpu_inatomic(1, prev);					\
+	if (tsk_used_math(next))					\
+		__sanitize_fcr31(next);					\
 	if (cpu_has_dsp) {						\
 		__save_dsp(prev);					\
 		__restore_dsp(next);					\
@@ -105,7 +123,7 @@
 	__clear_software_ll_bit();					\
 	if (cpu_has_userlocal)						\
 		write_c0_userlocal(task_thread_info(next)->tp_value);	\
-	__restore_watch();						\
+	__restore_watch(next);						\
 	(last) = resume(prev, next, task_thread_info(next));		\
 } while (0)
 
--- linux-4.4.0.orig/arch/mips/include/asm/syscall.h
+++ linux-4.4.0/arch/mips/include/asm/syscall.h
@@ -51,7 +51,7 @@
 #ifdef CONFIG_64BIT
 	case 4: case 5: case 6: case 7:
 #ifdef CONFIG_MIPS32_O32
-		if (test_thread_flag(TIF_32BIT_REGS))
+		if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
 			return get_user(*arg, (int *)usp + n);
 		else
 #endif
@@ -101,10 +101,8 @@
 	/* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
 	if ((config_enabled(CONFIG_32BIT) ||
 	    test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
-	    (regs->regs[2] == __NR_syscall)) {
+	    (regs->regs[2] == __NR_syscall))
 		i++;
-		n++;
-	}
 
 	while (n--)
 		ret |= mips_get_syscall_arg(args++, task, regs, i++);
--- linux-4.4.0.orig/arch/mips/include/asm/thread_info.h
+++ linux-4.4.0/arch/mips/include/asm/thread_info.h
@@ -52,8 +52,26 @@
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
-/* How to get the thread information struct from C.  */
+/*
+ * A pointer to the struct thread_info for the currently executing thread is
+ * held in register $28/$gp.
+ *
+ * We declare __current_thread_info as a global register variable rather than a
+ * local register variable within current_thread_info() because clang doesn't
+ * support explicit local register variables.
+ *
+ * When building the VDSO we take care not to declare the global register
+ * variable because this causes GCC to not preserve the value of $28/$gp in
+ * functions that change its value (which is common in the PIC VDSO when
+ * accessing the GOT). Since the VDSO shouldn't be accessing
+ * __current_thread_info anyway we declare it extern in order to cause a link
+ * failure if it's referenced.
+ */
+#ifdef __VDSO__
+extern struct thread_info *__current_thread_info;
+#else
 register struct thread_info *__current_thread_info __asm__("$28");
+#endif
 
 static inline struct thread_info *current_thread_info(void)
 {
--- linux-4.4.0.orig/arch/mips/include/asm/uaccess.h
+++ linux-4.4.0/arch/mips/include/asm/uaccess.h
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/thread_info.h>
+#include <linux/string.h>
 #include <asm/asm-eva.h>
 
 /*
@@ -1170,6 +1171,8 @@
 			__cu_len = __invoke_copy_from_user(__cu_to,	\
 							   __cu_from,	\
 							   __cu_len);   \
+		} else {						\
+			memset(__cu_to, 0, __cu_len);			\
 		}							\
 	}								\
 	__cu_len;							\
@@ -1235,6 +1238,13 @@
 {
 	__kernel_size_t res;
 
+#ifdef CONFIG_CPU_MICROMIPS
+/* micromips memset / bzero also clobbers t7 & t8 */
+#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$15", "$24", "$31"
+#else
+#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"
+#endif /* CONFIG_CPU_MICROMIPS */
+
 	if (eva_kernel_access()) {
 		__asm__ __volatile__(
 			"move\t$4, %1\n\t"
@@ -1244,7 +1254,7 @@
 			"move\t%0, $6"
 			: "=r" (res)
 			: "r" (addr), "r" (size)
-			: "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+			: bzero_clobbers);
 	} else {
 		might_fault();
 		__asm__ __volatile__(
@@ -1255,7 +1265,7 @@
 			"move\t%0, $6"
 			: "=r" (res)
 			: "r" (addr), "r" (size)
-			: "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+			: bzero_clobbers);
 	}
 
 	return res;
--- linux-4.4.0.orig/arch/mips/include/asm/uprobes.h
+++ linux-4.4.0/arch/mips/include/asm/uprobes.h
@@ -36,7 +36,6 @@
 	unsigned long	resume_epc;
 	u32	insn[2];
 	u32	ixol[2];
-	union	mips_instruction orig_inst[MAX_UINSN_BYTES / 4];
 };
 
 struct arch_uprobe_task {
--- linux-4.4.0.orig/arch/mips/include/asm/watch.h
+++ linux-4.4.0/arch/mips/include/asm/watch.h
@@ -12,21 +12,21 @@
 
 #include <asm/mipsregs.h>
 
-void mips_install_watch_registers(void);
+void mips_install_watch_registers(struct task_struct *t);
 void mips_read_watch_registers(void);
 void mips_clear_watch_registers(void);
 void mips_probe_watch_registers(struct cpuinfo_mips *c);
 
 #ifdef CONFIG_HARDWARE_WATCHPOINTS
-#define __restore_watch() do {						\
+#define __restore_watch(task) do {					\
 	if (unlikely(test_bit(TIF_LOAD_WATCH,				\
-			      &current_thread_info()->flags))) {	\
-		mips_install_watch_registers();				\
+			      &task_thread_info(task)->flags))) {	\
+		mips_install_watch_registers(task);			\
 	}								\
 } while (0)
 
 #else
-#define __restore_watch() do {} while (0)
+#define __restore_watch(task) do {} while (0)
 #endif
 
 #endif /* _ASM_WATCH_H */
--- linux-4.4.0.orig/arch/mips/include/uapi/asm/auxvec.h
+++ linux-4.4.0/arch/mips/include/uapi/asm/auxvec.h
@@ -14,4 +14,6 @@
 /* Location of VDSO image. */
 #define AT_SYSINFO_EHDR		33
 
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
 #endif /* __ASM_AUXVEC_H */
--- linux-4.4.0.orig/arch/mips/include/uapi/asm/inst.h
+++ linux-4.4.0/arch/mips/include/uapi/asm/inst.h
@@ -290,8 +290,8 @@
 	mm_ext_op = 0x02c,
 	mm_pool32axf_op = 0x03c,
 	mm_srl32_op = 0x040,
+	mm_srlv32_op = 0x050,
 	mm_sra_op = 0x080,
-	mm_srlv32_op = 0x090,
 	mm_rotr_op = 0x0c0,
 	mm_lwxs_op = 0x118,
 	mm_addu32_op = 0x150,
@@ -846,7 +846,7 @@
 struct mm16_r5_format {		/* Load/store from stack pointer format */
 	__BITFIELD_FIELD(unsigned int opcode : 6,
 	__BITFIELD_FIELD(unsigned int rt : 5,
-	__BITFIELD_FIELD(signed int simmediate : 5,
+	__BITFIELD_FIELD(unsigned int imm : 5,
 	__BITFIELD_FIELD(unsigned int : 16, /* Ignored */
 	;))))
 };
--- linux-4.4.0.orig/arch/mips/include/uapi/asm/sgidefs.h
+++ linux-4.4.0/arch/mips/include/uapi/asm/sgidefs.h
@@ -11,14 +11,6 @@
 #define __ASM_SGIDEFS_H
 
 /*
- * Using a Linux compiler for building Linux seems logic but not to
- * everybody.
- */
-#ifndef __linux__
-#error Use a Linux compiler or give up.
-#endif
-
-/*
  * Definitions for the ISA levels
  *
  * With the introduction of MIPS32 / MIPS64 instruction sets definitions
--- linux-4.4.0.orig/arch/mips/include/uapi/asm/siginfo.h
+++ linux-4.4.0/arch/mips/include/uapi/asm/siginfo.h
@@ -28,7 +28,7 @@
 
 #define __ARCH_SIGSYS
 
-#include <uapi/asm-generic/siginfo.h>
+#include <asm-generic/siginfo.h>
 
 /* We can't use generic siginfo_t, because our si_code and si_errno are swapped */
 typedef struct siginfo {
@@ -42,13 +42,13 @@
 
 		/* kill() */
 		struct {
-			pid_t _pid;		/* sender's pid */
+			__kernel_pid_t _pid;	/* sender's pid */
 			__ARCH_SI_UID_T _uid;	/* sender's uid */
 		} _kill;
 
 		/* POSIX.1b timers */
 		struct {
-			timer_t _tid;		/* timer id */
+			__kernel_timer_t _tid;	/* timer id */
 			int _overrun;		/* overrun count */
 			char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
 			sigval_t _sigval;	/* same as below */
@@ -57,26 +57,26 @@
 
 		/* POSIX.1b signals */
 		struct {
-			pid_t _pid;		/* sender's pid */
+			__kernel_pid_t _pid;	/* sender's pid */
 			__ARCH_SI_UID_T _uid;	/* sender's uid */
 			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
 		struct {
-			pid_t _pid;		/* which child */
+			__kernel_pid_t _pid;	/* which child */
 			__ARCH_SI_UID_T _uid;	/* sender's uid */
 			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
+			__kernel_clock_t _utime;
+			__kernel_clock_t _stime;
 		} _sigchld;
 
 		/* IRIX SIGCHLD */
 		struct {
-			pid_t _pid;		/* which child */
-			clock_t _utime;
+			__kernel_pid_t _pid;	/* which child */
+			__kernel_clock_t _utime;
 			int _status;		/* exit code */
-			clock_t _stime;
+			__kernel_clock_t _stime;
 		} _irix_sigchld;
 
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -118,6 +118,4 @@
 #define SI_TIMER __SI_CODE(__SI_TIMER, -3) /* sent by timer expiration */
 #define SI_MESGQ __SI_CODE(__SI_MESGQ, -4) /* sent by real time mesq state change */
 
-#include <asm-generic/siginfo.h>
-
 #endif /* _UAPI_ASM_SIGINFO_H */
--- linux-4.4.0.orig/arch/mips/jazz/jazzdma.c
+++ linux-4.4.0/arch/mips/jazz/jazzdma.c
@@ -71,14 +71,15 @@
 						    get_order(VDMA_PGTBL_SIZE));
 	BUG_ON(!pgtbl);
 	dma_cache_wback_inv((unsigned long)pgtbl, VDMA_PGTBL_SIZE);
-	pgtbl = (VDMA_PGTBL_ENTRY *)KSEG1ADDR(pgtbl);
+	pgtbl = (VDMA_PGTBL_ENTRY *)CKSEG1ADDR((unsigned long)pgtbl);
 
 	/*
 	 * Clear the R4030 translation table
 	 */
 	vdma_pgtbl_init();
 
-	r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE, CPHYSADDR(pgtbl));
+	r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE,
+			  CPHYSADDR((unsigned long)pgtbl));
 	r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM, VDMA_PGTBL_SIZE);
 	r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0);
 
--- linux-4.4.0.orig/arch/mips/jz4740/Platform
+++ linux-4.4.0/arch/mips/jz4740/Platform
@@ -1,4 +1,4 @@
 platform-$(CONFIG_MACH_INGENIC)	+= jz4740/
 cflags-$(CONFIG_MACH_INGENIC)	+= -I$(srctree)/arch/mips/include/asm/mach-jz4740
 load-$(CONFIG_MACH_INGENIC)	+= 0xffffffff80010000
-zload-$(CONFIG_MACH_INGENIC)	+= 0xffffffff80600000
+zload-$(CONFIG_MACH_INGENIC)	+= 0xffffffff81000000
--- linux-4.4.0.orig/arch/mips/kernel/asm-offsets.c
+++ linux-4.4.0/arch/mips/kernel/asm-offsets.c
@@ -101,6 +101,8 @@
 	OFFSET(TI_REGS, thread_info, regs);
 	DEFINE(_THREAD_SIZE, THREAD_SIZE);
 	DEFINE(_THREAD_MASK, THREAD_MASK);
+	DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE);
+	DEFINE(_IRQ_STACK_START, IRQ_STACK_START);
 	BLANK();
 }
 
--- linux-4.4.0.orig/arch/mips/kernel/bmips_vec.S
+++ linux-4.4.0/arch/mips/kernel/bmips_vec.S
@@ -93,7 +93,8 @@
 #if defined(CONFIG_CPU_BMIPS5000)
 	mfc0	k0, CP0_PRID
 	li	k1, PRID_IMP_BMIPS5000
-	andi	k0, 0xff00
+	/* mask with PRID_IMP_BMIPS5000 to cover both variants */
+	andi	k0, PRID_IMP_BMIPS5000
 	bne	k0, k1, 1f
 
 	/* if we're not on core 0, this must be the SMP boot signal */
@@ -166,10 +167,12 @@
 2:
 #endif /* CONFIG_CPU_BMIPS4350 || CONFIG_CPU_BMIPS4380 */
 #if defined(CONFIG_CPU_BMIPS5000)
-	/* set exception vector base */
+	/* mask with PRID_IMP_BMIPS5000 to cover both variants */
 	li	k1, PRID_IMP_BMIPS5000
+	andi	k0, PRID_IMP_BMIPS5000
 	bne	k0, k1, 3f
 
+	/* set exception vector base */
 	la	k0, ebase
 	lw	k0, 0(k0)
 	mtc0	k0, $15, 1
@@ -263,6 +266,8 @@
 #endif /* CONFIG_CPU_BMIPS4380 */
 #if defined(CONFIG_CPU_BMIPS5000)
 	li	t1, PRID_IMP_BMIPS5000
+	/* mask with PRID_IMP_BMIPS5000 to cover both variants */
+	andi	t2, PRID_IMP_BMIPS5000
 	bne	t2, t1, 2f
 
 	mfc0	t0, $22, 5
--- linux-4.4.0.orig/arch/mips/kernel/branch.c
+++ linux-4.4.0/arch/mips/kernel/branch.c
@@ -399,7 +399,7 @@
  *
  * @regs:	Pointer to pt_regs
  * @insn:	branch instruction to decode
- * @returns:	-EFAULT on error and forces SIGBUS, and on success
+ * @returns:	-EFAULT on error and forces SIGILL, and on success
  *		returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
  *		evaluating the branch.
  *
@@ -431,7 +431,7 @@
 			/* Fall through */
 		case jr_op:
 			if (NO_R6EMU && insn.r_format.func == jr_op)
-				goto sigill_r6;
+				goto sigill_r2r6;
 			regs->cp0_epc = regs->regs[insn.r_format.rs];
 			break;
 		}
@@ -446,7 +446,7 @@
 		switch (insn.i_format.rt) {
 		case bltzl_op:
 			if (NO_R6EMU)
-				goto sigill_r6;
+				goto sigill_r2r6;
 		case bltz_op:
 			if ((long)regs->regs[insn.i_format.rs] < 0) {
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -459,7 +459,7 @@
 
 		case bgezl_op:
 			if (NO_R6EMU)
-				goto sigill_r6;
+				goto sigill_r2r6;
 		case bgez_op:
 			if ((long)regs->regs[insn.i_format.rs] >= 0) {
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -473,10 +473,8 @@
 		case bltzal_op:
 		case bltzall_op:
 			if (NO_R6EMU && (insn.i_format.rs ||
-			    insn.i_format.rt == bltzall_op)) {
-				ret = -SIGILL;
-				break;
-			}
+			    insn.i_format.rt == bltzall_op))
+				goto sigill_r2r6;
 			regs->regs[31] = epc + 8;
 			/*
 			 * OK we are here either because we hit a NAL
@@ -507,10 +505,8 @@
 		case bgezal_op:
 		case bgezall_op:
 			if (NO_R6EMU && (insn.i_format.rs ||
-			    insn.i_format.rt == bgezall_op)) {
-				ret = -SIGILL;
-				break;
-			}
+			    insn.i_format.rt == bgezall_op))
+				goto sigill_r2r6;
 			regs->regs[31] = epc + 8;
 			/*
 			 * OK we are here either because we hit a BAL
@@ -556,6 +552,7 @@
 	/*
 	 * These are unconditional and in j_format.
 	 */
+	case jalx_op:
 	case jal_op:
 		regs->regs[31] = regs->cp0_epc + 8;
 	case j_op:
@@ -573,7 +570,7 @@
 	 */
 	case beql_op:
 		if (NO_R6EMU)
-			goto sigill_r6;
+			goto sigill_r2r6;
 	case beq_op:
 		if (regs->regs[insn.i_format.rs] ==
 		    regs->regs[insn.i_format.rt]) {
@@ -587,7 +584,7 @@
 
 	case bnel_op:
 		if (NO_R6EMU)
-			goto sigill_r6;
+			goto sigill_r2r6;
 	case bne_op:
 		if (regs->regs[insn.i_format.rs] !=
 		    regs->regs[insn.i_format.rt]) {
@@ -601,7 +598,7 @@
 
 	case blezl_op: /* not really i_format */
 		if (!insn.i_format.rt && NO_R6EMU)
-			goto sigill_r6;
+			goto sigill_r2r6;
 	case blez_op:
 		/*
 		 * Compact branches for R6 for the
@@ -636,7 +633,7 @@
 
 	case bgtzl_op:
 		if (!insn.i_format.rt && NO_R6EMU)
-			goto sigill_r6;
+			goto sigill_r2r6;
 	case bgtz_op:
 		/*
 		 * Compact branches for R6 for the
@@ -688,21 +685,9 @@
 			}
 			lose_fpu(1);    /* Save FPU state for the emulator. */
 			reg = insn.i_format.rt;
-			bit = 0;
-			switch (insn.i_format.rs) {
-			case bc1eqz_op:
-				/* Test bit 0 */
-				if (get_fpr32(&current->thread.fpu.fpr[reg], 0)
-				    & 0x1)
-					bit = 1;
-				break;
-			case bc1nez_op:
-				/* Test bit 0 */
-				if (!(get_fpr32(&current->thread.fpu.fpr[reg], 0)
-				      & 0x1))
-					bit = 1;
-				break;
-			}
+			bit = get_fpr32(&current->thread.fpu.fpr[reg], 0) & 0x1;
+			if (insn.i_format.rs == bc1eqz_op)
+				bit = !bit;
 			own_fpu(1);
 			if (bit)
 				epc = epc + 4 +
@@ -816,8 +801,10 @@
 			break;
 		}
 		/* Compact branch: BNEZC || JIALC */
-		if (insn.i_format.rs)
+		if (!insn.i_format.rs) {
+			/* JIALC: set $31/ra */
 			regs->regs[31] = epc + 4;
+		}
 		regs->cp0_epc += 8;
 		break;
 #endif
@@ -841,11 +828,12 @@
 	return ret;
 
 sigill_dsp:
-	printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
-	force_sig(SIGBUS, current);
+	pr_info("%s: DSP branch but not DSP ASE - sending SIGILL.\n",
+		current->comm);
+	force_sig(SIGILL, current);
 	return -EFAULT;
-sigill_r6:
-	pr_info("%s: R2 branch but r2-to-r6 emulator is not preset - sending SIGILL.\n",
+sigill_r2r6:
+	pr_info("%s: R2 branch but r2-to-r6 emulator is not present - sending SIGILL.\n",
 		current->comm);
 	force_sig(SIGILL, current);
 	return -EFAULT;
--- linux-4.4.0.orig/arch/mips/kernel/cps-vec.S
+++ linux-4.4.0/arch/mips/kernel/cps-vec.S
@@ -245,7 +245,6 @@
 
 .org 0x480
 LEAF(excep_ejtag)
-	DUMP_EXCEP("EJTAG")
 	PTR_LA	k0, ejtag_debug_handler
 	jr	k0
 	 nop
--- linux-4.4.0.orig/arch/mips/kernel/cpu-probe.c
+++ linux-4.4.0/arch/mips/kernel/cpu-probe.c
@@ -1284,7 +1284,10 @@
 	case PRID_IMP_BMIPS5000:
 	case PRID_IMP_BMIPS5200:
 		c->cputype = CPU_BMIPS5000;
-		__cpu_name[cpu] = "Broadcom BMIPS5000";
+		if ((c->processor_id & PRID_IMP_MASK) == PRID_IMP_BMIPS5200)
+			__cpu_name[cpu] = "Broadcom BMIPS5200";
+		else
+			__cpu_name[cpu] = "Broadcom BMIPS5000";
 		set_elf_platform(cpu, "bmips5000");
 		c->options |= MIPS_CPU_ULRI;
 		break;
--- linux-4.4.0.orig/arch/mips/kernel/crash.c
+++ linux-4.4.0/arch/mips/kernel/crash.c
@@ -14,16 +14,29 @@
 static cpumask_t cpus_in_crash = CPU_MASK_NONE;
 
 #ifdef CONFIG_SMP
-static void crash_shutdown_secondary(void *ignore)
+static void crash_shutdown_secondary(void *passed_regs)
 {
-	struct pt_regs *regs;
+	struct pt_regs *regs = passed_regs;
 	int cpu = smp_processor_id();
 
-	regs = task_pt_regs(current);
+	/*
+	 * If we are passed registers, use those.  Otherwise get the
+	 * regs from the last interrupt, which should be correct, as
+	 * we are in an interrupt.  But if the regs are not there,
+	 * pull them from the top of the stack.  They are probably
+	 * wrong, but we need something to keep from crashing again.
+	 */
+	if (!regs)
+		regs = get_irq_regs();
+	if (!regs)
+		regs = task_pt_regs(current);
 
 	if (!cpu_online(cpu))
 		return;
 
+	/* We won't be sent IPIs any more. */
+	set_cpu_online(cpu, false);
+
 	local_irq_disable();
 	if (!cpumask_test_cpu(cpu, &cpus_in_crash))
 		crash_save_cpu(regs, cpu);
@@ -37,9 +50,14 @@
 
 static void crash_kexec_prepare_cpus(void)
 {
+	static int cpus_stopped;
 	unsigned int msecs;
+	unsigned int ncpus;
+
+	if (cpus_stopped)
+		return;
 
-	unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
+	ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
 
 	dump_send_ipi(crash_shutdown_secondary);
 	smp_wmb();
@@ -54,6 +72,17 @@
 		cpu_relax();
 		mdelay(1);
 	}
+
+	cpus_stopped = 1;
+}
+
+/* Override the weak function in kernel/panic.c */
+void crash_smp_send_stop(void)
+{
+	if (_crash_smp_send_stop)
+		_crash_smp_send_stop();
+
+	crash_kexec_prepare_cpus();
 }
 
 #else /* !defined(CONFIG_SMP)  */
--- linux-4.4.0.orig/arch/mips/kernel/csrc-r4k.c
+++ linux-4.4.0/arch/mips/kernel/csrc-r4k.c
@@ -23,7 +23,7 @@
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static u64 notrace r4k_read_sched_clock(void)
+static u64 __maybe_unused notrace r4k_read_sched_clock(void)
 {
 	return read_c0_count();
 }
@@ -82,7 +82,9 @@
 
 	clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
 
+#ifndef CONFIG_CPU_FREQ
 	sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
+#endif
 
 	return 0;
 }
--- linux-4.4.0.orig/arch/mips/kernel/elf.c
+++ linux-4.4.0/arch/mips/kernel/elf.c
@@ -206,7 +206,7 @@
 	else if ((prog_req.fr1 && prog_req.frdefault) ||
 		 (prog_req.single && !prog_req.frdefault))
 		/* Make sure 64-bit MIPS III/IV/64R1 will not pick FR1 */
-		state->overall_fp_mode = ((current_cpu_data.fpu_id & MIPS_FPIR_F64) &&
+		state->overall_fp_mode = ((raw_current_cpu_data.fpu_id & MIPS_FPIR_F64) &&
 					  cpu_has_mips_r2_r6) ?
 					  FP_FR1 : FP_FR0;
 	else if (prog_req.fr1)
--- linux-4.4.0.orig/arch/mips/kernel/entry.S
+++ linux-4.4.0/arch/mips/kernel/entry.S
@@ -11,6 +11,7 @@
 #include <asm/asm.h>
 #include <asm/asmmacro.h>
 #include <asm/compiler.h>
+#include <asm/irqflags.h>
 #include <asm/regdef.h>
 #include <asm/mipsregs.h>
 #include <asm/stackframe.h>
@@ -137,6 +138,7 @@
 	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
 	beqz	t0, work_notifysig
 work_resched:
+	TRACE_IRQS_OFF
 	jal	schedule
 
 	local_irq_disable		# make sure need_resched and
@@ -173,6 +175,7 @@
 	beqz	t0, work_pending	# trace bit set?
 	local_irq_enable		# could let syscall_trace_leave()
 					# call schedule() instead
+	TRACE_IRQS_ON
 	move	a0, sp
 	jal	syscall_trace_leave
 	b	resume_userspace
--- linux-4.4.0.orig/arch/mips/kernel/genex.S
+++ linux-4.4.0/arch/mips/kernel/genex.S
@@ -142,9 +142,8 @@
 	PTR_LA	k1, __r4k_wait
 	ori	k0, 0x1f	/* 32 byte rollback region */
 	xori	k0, 0x1f
-	bne	k0, k1, 9f
+	bne	k0, k1, \handler
 	MTC0	k0, CP0_EPC
-9:
 	.set pop
 	.endm
 
@@ -188,9 +187,46 @@
 
 	LONG_L	s0, TI_REGS($28)
 	LONG_S	sp, TI_REGS($28)
-	PTR_LA	ra, ret_from_irq
-	PTR_LA  v0, plat_irq_dispatch
-	jr	v0
+
+	/*
+	 * SAVE_ALL ensures we are using a valid kernel stack for the thread.
+	 * Check if we are already using the IRQ stack.
+	 */
+	move	s1, sp # Preserve the sp
+
+	/* Get IRQ stack for this CPU */
+	ASM_CPUID_MFC0	k0, ASM_SMP_CPUID_REG
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+	lui	k1, %hi(irq_stack)
+#else
+	lui	k1, %highest(irq_stack)
+	daddiu	k1, %higher(irq_stack)
+	dsll	k1, 16
+	daddiu	k1, %hi(irq_stack)
+	dsll	k1, 16
+#endif
+	LONG_SRL	k0, SMP_CPUID_PTRSHIFT
+	LONG_ADDU	k1, k0
+	LONG_L	t0, %lo(irq_stack)(k1)
+
+	# Check if already on IRQ stack
+	PTR_LI	t1, ~(_THREAD_SIZE-1)
+	and	t1, t1, sp
+	beq	t0, t1, 2f
+
+	/* Switch to IRQ stack */
+	li	t1, _IRQ_STACK_START
+	PTR_ADD sp, t0, t1
+
+	/* Save task's sp on IRQ stack so that unwinding can follow it */
+	LONG_S	s1, 0(sp)
+2:
+	jal	plat_irq_dispatch
+
+	/* Restore sp */
+	move	sp, s1
+
+	j	ret_from_irq
 #ifdef CONFIG_CPU_MICROMIPS
 	nop
 #endif
@@ -263,8 +299,46 @@
 
 	LONG_L	s0, TI_REGS($28)
 	LONG_S	sp, TI_REGS($28)
-	PTR_LA	ra, ret_from_irq
-	jr	v0
+
+	/*
+	 * SAVE_ALL ensures we are using a valid kernel stack for the thread.
+	 * Check if we are already using the IRQ stack.
+	 */
+	move	s1, sp # Preserve the sp
+
+	/* Get IRQ stack for this CPU */
+	ASM_CPUID_MFC0	k0, ASM_SMP_CPUID_REG
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+	lui	k1, %hi(irq_stack)
+#else
+	lui	k1, %highest(irq_stack)
+	daddiu	k1, %higher(irq_stack)
+	dsll	k1, 16
+	daddiu	k1, %hi(irq_stack)
+	dsll	k1, 16
+#endif
+	LONG_SRL	k0, SMP_CPUID_PTRSHIFT
+	LONG_ADDU	k1, k0
+	LONG_L	t0, %lo(irq_stack)(k1)
+
+	# Check if already on IRQ stack
+	PTR_LI	t1, ~(_THREAD_SIZE-1)
+	and	t1, t1, sp
+	beq	t0, t1, 2f
+
+	/* Switch to IRQ stack */
+	li	t1, _IRQ_STACK_START
+	PTR_ADD sp, t0, t1
+
+	/* Save task's sp on IRQ stack so that unwinding can follow it */
+	LONG_S	s1, 0(sp)
+2:
+	jalr	v0
+
+	/* Restore sp */
+	move	sp, s1
+
+	j	ret_from_irq
 	END(except_vec_vi_handler)
 
 /*
@@ -355,20 +429,20 @@
 	.endm
 
 	.macro	__build_clear_fpe
+	CLI
+	TRACE_IRQS_OFF
 	.set	push
 	/* gas fails to assemble cfc1 for some archs (octeon).*/ \
 	.set	mips1
 	SET_HARDFLOAT
 	cfc1	a1, fcr31
 	.set	pop
-	CLI
-	TRACE_IRQS_OFF
 	.endm
 
 	.macro	__build_clear_msa_fpe
-	_cfcmsa	a1, MSA_CSR
 	CLI
 	TRACE_IRQS_OFF
+	_cfcmsa	a1, MSA_CSR
 	.endm
 
 	.macro	__build_clear_ade
--- linux-4.4.0.orig/arch/mips/kernel/i8253.c
+++ linux-4.4.0/arch/mips/kernel/i8253.c
@@ -31,7 +31,8 @@
 
 static int __init init_pit_clocksource(void)
 {
-	if (num_possible_cpus() > 1) /* PIT does not scale! */
+	if (num_possible_cpus() > 1 || /* PIT does not scale! */
+	    !clockevent_state_periodic(&i8253_clockevent))
 		return 0;
 
 	return clocksource_i8253_init();
--- linux-4.4.0.orig/arch/mips/kernel/irq.c
+++ linux-4.4.0/arch/mips/kernel/irq.c
@@ -25,6 +25,8 @@
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
 
+void *irq_stack[NR_CPUS];
+
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
@@ -50,11 +52,20 @@
 void __init init_IRQ(void)
 {
 	int i;
+	unsigned int order = get_order(IRQ_STACK_SIZE);
 
 	for (i = 0; i < NR_IRQS; i++)
 		irq_set_noprobe(i);
 
 	arch_init_irq();
+
+	for_each_possible_cpu(i) {
+		void *s = (void *)__get_free_pages(GFP_KERNEL, order);
+
+		irq_stack[i] = s;
+		pr_debug("CPU%d IRQ stack at 0x%p - 0x%p\n", i,
+			irq_stack[i], irq_stack[i] + IRQ_STACK_SIZE);
+	}
 }
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
--- linux-4.4.0.orig/arch/mips/kernel/kgdb.c
+++ linux-4.4.0/arch/mips/kernel/kgdb.c
@@ -244,9 +244,6 @@
 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 {
 	int reg;
-	struct thread_info *ti = task_thread_info(p);
-	unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32;
-	struct pt_regs *regs = (struct pt_regs *)ksp - 1;
 #if (KGDB_GDB_REG_SIZE == 32)
 	u32 *ptr = (u32 *)gdb_regs;
 #else
@@ -254,25 +251,46 @@
 #endif
 
 	for (reg = 0; reg < 16; reg++)
-		*(ptr++) = regs->regs[reg];
+		*(ptr++) = 0;
 
 	/* S0 - S7 */
-	for (reg = 16; reg < 24; reg++)
-		*(ptr++) = regs->regs[reg];
+	*(ptr++) = p->thread.reg16;
+	*(ptr++) = p->thread.reg17;
+	*(ptr++) = p->thread.reg18;
+	*(ptr++) = p->thread.reg19;
+	*(ptr++) = p->thread.reg20;
+	*(ptr++) = p->thread.reg21;
+	*(ptr++) = p->thread.reg22;
+	*(ptr++) = p->thread.reg23;
 
 	for (reg = 24; reg < 28; reg++)
 		*(ptr++) = 0;
 
 	/* GP, SP, FP, RA */
-	for (reg = 28; reg < 32; reg++)
-		*(ptr++) = regs->regs[reg];
-
-	*(ptr++) = regs->cp0_status;
-	*(ptr++) = regs->lo;
-	*(ptr++) = regs->hi;
-	*(ptr++) = regs->cp0_badvaddr;
-	*(ptr++) = regs->cp0_cause;
-	*(ptr++) = regs->cp0_epc;
+	*(ptr++) = (long)p;
+	*(ptr++) = p->thread.reg29;
+	*(ptr++) = p->thread.reg30;
+	*(ptr++) = p->thread.reg31;
+
+	*(ptr++) = p->thread.cp0_status;
+
+	/* lo, hi */
+	*(ptr++) = 0;
+	*(ptr++) = 0;
+
+	/*
+	 * BadVAddr, Cause
+	 * Ideally these would come from the last exception frame up the stack
+	 * but that requires unwinding, otherwise we can't know much for sure.
+	 */
+	*(ptr++) = 0;
+	*(ptr++) = 0;
+
+	/*
+	 * PC
+	 * use return address (RA), i.e. the moment after return from resume()
+	 */
+	*(ptr++) = p->thread.reg31;
 }
 
 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
--- linux-4.4.0.orig/arch/mips/kernel/machine_kexec.c
+++ linux-4.4.0/arch/mips/kernel/machine_kexec.c
@@ -25,6 +25,7 @@
 #ifdef CONFIG_SMP
 void (*relocated_kexec_smp_wait) (void *);
 atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
+void (*_crash_smp_send_stop)(void) = NULL;
 #endif
 
 int
@@ -95,6 +96,9 @@
 			*ptr = (unsigned long) phys_to_virt(*ptr);
 	}
 
+	/* Mark offline BEFORE disabling local irq. */
+	set_cpu_online(smp_processor_id(), false);
+
 	/*
 	 * we do not want to be bothered.
 	 */
--- linux-4.4.0.orig/arch/mips/kernel/mcount.S
+++ linux-4.4.0/arch/mips/kernel/mcount.S
@@ -116,10 +116,20 @@
 NESTED(_mcount, PT_SIZE, ra)
 	PTR_LA	t1, ftrace_stub
 	PTR_L	t2, ftrace_trace_function /* Prepare t2 for (1) */
-	bne	t1, t2, static_trace
+	beq	t1, t2, fgraph_trace
 	 nop
 
+	MCOUNT_SAVE_REGS
+
+	move	a0, ra		/* arg1: self return address */
+	jalr	t2		/* (1) call *ftrace_trace_function */
+	 move	a1, AT		/* arg2: parent's return address */
+
+	MCOUNT_RESTORE_REGS
+
+fgraph_trace:
 #ifdef	CONFIG_FUNCTION_GRAPH_TRACER
+	PTR_LA	t1, ftrace_stub
 	PTR_L	t3, ftrace_graph_return
 	bne	t1, t3, ftrace_graph_caller
 	 nop
@@ -128,24 +138,11 @@
 	bne	t1, t3, ftrace_graph_caller
 	 nop
 #endif
-	b	ftrace_stub
-#ifdef CONFIG_32BIT
-	 addiu sp, sp, 8
-#else
-	 nop
-#endif
-
-static_trace:
-	MCOUNT_SAVE_REGS
-
-	move	a0, ra		/* arg1: self return address */
-	jalr	t2		/* (1) call *ftrace_trace_function */
-	 move	a1, AT		/* arg2: parent's return address */
 
-	MCOUNT_RESTORE_REGS
 #ifdef CONFIG_32BIT
 	addiu sp, sp, 8
 #endif
+
 	.globl ftrace_stub
 ftrace_stub:
 	RETURN_BACK
--- linux-4.4.0.orig/arch/mips/kernel/mips-cm.c
+++ linux-4.4.0/arch/mips/kernel/mips-cm.c
@@ -123,9 +123,9 @@
 	"COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07",
 	"0x08", "0x09", "0x0a", "0x0b",
 	"0x0c", "0x0d", "0x0e", "0x0f",
-	"0x10", "0x11", "0x12", "0x13",
-	"0x14", "0x15", "0x16", "INTVN_WR_ERR",
-	"INTVN_RD_ERR", "0x19", "0x1a", "0x1b",
+	"0x10", "INTVN_WR_ERR", "INTVN_RD_ERR", "0x13",
+	"0x14", "0x15", "0x16", "0x17",
+	"0x18", "0x19", "0x1a", "0x1b",
 	"0x1c", "0x1d", "0x1e", "0x1f"
 };
 
@@ -424,5 +424,5 @@
 	}
 
 	/* reprime cause register */
-	write_gcr_error_cause(0);
+	write_gcr_error_cause(cm_error);
 }
--- linux-4.4.0.orig/arch/mips/kernel/mips-r2-to-r6-emul.c
+++ linux-4.4.0/arch/mips/kernel/mips-r2-to-r6-emul.c
@@ -28,6 +28,7 @@
 #include <asm/inst.h>
 #include <asm/mips-r2-to-r6-emul.h>
 #include <asm/local.h>
+#include <asm/mipsregs.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 
@@ -433,8 +434,8 @@
 	rs = regs->regs[MIPSInst_RS(ir)];
 	res = (u64)rt * (u64)rs;
 	rt = res;
-	regs->lo = (s64)rt;
-	regs->hi = (s64)(res >> 32);
+	regs->lo = (s64)(s32)rt;
+	regs->hi = (s64)(s32)(res >> 32);
 
 	MIPS_R2_STATS(muls);
 
@@ -670,9 +671,9 @@
 	res += ((((s64)rt) << 32) | (u32)rs);
 
 	rt = res;
-	regs->lo = (s64)rt;
+	regs->lo = (s64)(s32)rt;
 	rs = res >> 32;
-	regs->hi = (s64)rs;
+	regs->hi = (s64)(s32)rs;
 
 	MIPS_R2_STATS(dsps);
 
@@ -728,9 +729,9 @@
 	res = ((((s64)rt) << 32) | (u32)rs) - res;
 
 	rt = res;
-	regs->lo = (s64)rt;
+	regs->lo = (s64)(s32)rt;
 	rs = res >> 32;
-	regs->hi = (s64)rs;
+	regs->hi = (s64)(s32)rs;
 
 	MIPS_R2_STATS(dsps);
 
@@ -899,7 +900,7 @@
  * mipsr2_decoder: Decode and emulate a MIPS R2 instruction
  * @regs: Process register set
  * @inst: Instruction to decode and emulate
- * @fcr31: Floating Point Control and Status Register returned
+ * @fcr31: Floating Point Control and Status Register Cause bits returned
  */
 int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
 {
@@ -1096,10 +1097,20 @@
 		}
 		break;
 
-	case beql_op:
-	case bnel_op:
 	case blezl_op:
 	case bgtzl_op:
+		/*
+		 * For BLEZL and BGTZL, rt field must be set to 0. If this
+		 * is not the case, this may be an encoding of a MIPS R6
+		 * instruction, so return to CPU execution if this occurs
+		 */
+		if (MIPSInst_RT(inst)) {
+			err = SIGILL;
+			break;
+		}
+		/* fall through */
+	case beql_op:
+	case bnel_op:
 		if (delay_slot(regs)) {
 			err = SIGILL;
 			break;
@@ -1163,20 +1174,22 @@
 		regs->regs[31] = r31;
 		regs->cp0_epc = epc;
 		if (!used_math()) {     /* First time FPU user.  */
+			preempt_disable();
 			err = init_fpu();
+			preempt_enable();
 			set_used_math();
 		}
 		lose_fpu(1);    /* Save FPU state for the emulator. */
 
 		err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
 					       &fault_addr);
-		*fcr31 = current->thread.fpu.fcr31;
 
 		/*
-		 * We can't allow the emulated instruction to leave any of
-		 * the cause bits set in $fcr31.
+		 * We can't allow the emulated instruction to leave any
+		 * enabled Cause bits set in $fcr31.
 		 */
-		current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+		*fcr31 = res = mask_fcr31_x(current->thread.fpu.fcr31);
+		current->thread.fpu.fcr31 &= ~res;
 
 		/*
 		 * this is a tricky issue - lose_fpu() uses LL/SC atomics
@@ -1251,10 +1264,10 @@
 			"	j	10b\n"
 			"	.previous\n"
 			"	.section	__ex_table,\"a\"\n"
-			"	.word	1b,8b\n"
-			"	.word	2b,8b\n"
-			"	.word	3b,8b\n"
-			"	.word	4b,8b\n"
+			STR(PTR) " 1b,8b\n"
+			STR(PTR) " 2b,8b\n"
+			STR(PTR) " 3b,8b\n"
+			STR(PTR) " 4b,8b\n"
 			"	.previous\n"
 			"	.set	pop\n"
 			: "+&r"(rt), "=&r"(rs),
@@ -1326,10 +1339,10 @@
 			"	j	10b\n"
 			"       .previous\n"
 			"	.section	__ex_table,\"a\"\n"
-			"	.word	1b,8b\n"
-			"	.word	2b,8b\n"
-			"	.word	3b,8b\n"
-			"	.word	4b,8b\n"
+			STR(PTR) " 1b,8b\n"
+			STR(PTR) " 2b,8b\n"
+			STR(PTR) " 3b,8b\n"
+			STR(PTR) " 4b,8b\n"
 			"	.previous\n"
 			"	.set	pop\n"
 			: "+&r"(rt), "=&r"(rs),
@@ -1397,10 +1410,10 @@
 			"	j	9b\n"
 			"	.previous\n"
 			"	.section        __ex_table,\"a\"\n"
-			"	.word	1b,8b\n"
-			"	.word	2b,8b\n"
-			"	.word	3b,8b\n"
-			"	.word	4b,8b\n"
+			STR(PTR) " 1b,8b\n"
+			STR(PTR) " 2b,8b\n"
+			STR(PTR) " 3b,8b\n"
+			STR(PTR) " 4b,8b\n"
 			"	.previous\n"
 			"	.set	pop\n"
 			: "+&r"(rt), "=&r"(rs),
@@ -1467,10 +1480,10 @@
 			"	j	9b\n"
 			"	.previous\n"
 			"	.section        __ex_table,\"a\"\n"
-			"	.word	1b,8b\n"
-			"	.word	2b,8b\n"
-			"	.word	3b,8b\n"
-			"	.word	4b,8b\n"
+			STR(PTR) " 1b,8b\n"
+			STR(PTR) " 2b,8b\n"
+			STR(PTR) " 3b,8b\n"
+			STR(PTR) " 4b,8b\n"
 			"	.previous\n"
 			"	.set	pop\n"
 			: "+&r"(rt), "=&r"(rs),
@@ -1582,14 +1595,14 @@
 			"	j	9b\n"
 			"	.previous\n"
 			"	.section        __ex_table,\"a\"\n"
-			"	.word	1b,8b\n"
-			"	.word	2b,8b\n"
-			"	.word	3b,8b\n"
-			"	.word	4b,8b\n"
-			"	.word	5b,8b\n"
-			"	.word	6b,8b\n"
-			"	.word	7b,8b\n"
-			"	.word	0b,8b\n"
+			STR(PTR) " 1b,8b\n"
+			STR(PTR) " 2b,8b\n"
+			STR(PTR) " 3b,8b\n"
+			STR(PTR) " 4b,8b\n"
+			STR(PTR) " 5b,8b\n"
+			STR(PTR) " 6b,8b\n"
+			STR(PTR) " 7b,8b\n"
+			STR(PTR) " 0b,8b\n"
 			"	.previous\n"
 			"	.set	pop\n"
 			: "+&r"(rt), "=&r"(rs),
@@ -1701,14 +1714,14 @@
 			"	j      9b\n"
 			"	.previous\n"
 			"	.section        __ex_table,\"a\"\n"
-			"	.word  1b,8b\n"
-			"	.word  2b,8b\n"
-			"	.word  3b,8b\n"
-			"	.word  4b,8b\n"
-			"	.word  5b,8b\n"
-			"	.word  6b,8b\n"
-			"	.word  7b,8b\n"
-			"	.word  0b,8b\n"
+			STR(PTR) " 1b,8b\n"
+			STR(PTR) " 2b,8b\n"
+			STR(PTR) " 3b,8b\n"
+			STR(PTR) " 4b,8b\n"
+			STR(PTR) " 5b,8b\n"
+			STR(PTR) " 6b,8b\n"
+			STR(PTR) " 7b,8b\n"
+			STR(PTR) " 0b,8b\n"
 			"	.previous\n"
 			"	.set    pop\n"
 			: "+&r"(rt), "=&r"(rs),
@@ -1820,14 +1833,14 @@
 			"	j	9b\n"
 			"	.previous\n"
 			"	.section        __ex_table,\"a\"\n"
-			"	.word	1b,8b\n"
-			"	.word	2b,8b\n"
-			"	.word	3b,8b\n"
-			"	.word	4b,8b\n"
-			"	.word	5b,8b\n"
-			"	.word	6b,8b\n"
-			"	.word	7b,8b\n"
-			"	.word	0b,8b\n"
+			STR(PTR) " 1b,8b\n"
+			STR(PTR) " 2b,8b\n"
+			STR(PTR) " 3b,8b\n"
+			STR(PTR) " 4b,8b\n"
+			STR(PTR) " 5b,8b\n"
+			STR(PTR) " 6b,8b\n"
+			STR(PTR) " 7b,8b\n"
+			STR(PTR) " 0b,8b\n"
 			"	.previous\n"
 			"	.set	pop\n"
 			: "+&r"(rt), "=&r"(rs),
@@ -1938,14 +1951,14 @@
 			"       j	9b\n"
 			"       .previous\n"
 			"       .section        __ex_table,\"a\"\n"
-			"       .word	1b,8b\n"
-			"       .word	2b,8b\n"
-			"       .word	3b,8b\n"
-			"       .word	4b,8b\n"
-			"       .word	5b,8b\n"
-			"       .word	6b,8b\n"
-			"       .word	7b,8b\n"
-			"       .word	0b,8b\n"
+			STR(PTR) " 1b,8b\n"
+			STR(PTR) " 2b,8b\n"
+			STR(PTR) " 3b,8b\n"
+			STR(PTR) " 4b,8b\n"
+			STR(PTR) " 5b,8b\n"
+			STR(PTR) " 6b,8b\n"
+			STR(PTR) " 7b,8b\n"
+			STR(PTR) " 0b,8b\n"
 			"       .previous\n"
 			"       .set	pop\n"
 			: "+&r"(rt), "=&r"(rs),
@@ -2000,7 +2013,7 @@
 			"j	2b\n"
 			".previous\n"
 			".section        __ex_table,\"a\"\n"
-			".word  1b, 3b\n"
+			STR(PTR) " 1b,3b\n"
 			".previous\n"
 			: "=&r"(res), "+&r"(err)
 			: "r"(vaddr), "i"(SIGSEGV)
@@ -2058,7 +2071,7 @@
 			"j	2b\n"
 			".previous\n"
 			".section        __ex_table,\"a\"\n"
-			".word	1b, 3b\n"
+			STR(PTR) " 1b,3b\n"
 			".previous\n"
 			: "+&r"(res), "+&r"(err)
 			: "r"(vaddr), "i"(SIGSEGV));
@@ -2119,7 +2132,7 @@
 			"j	2b\n"
 			".previous\n"
 			".section        __ex_table,\"a\"\n"
-			".word  1b, 3b\n"
+			STR(PTR) " 1b,3b\n"
 			".previous\n"
 			: "=&r"(res), "+&r"(err)
 			: "r"(vaddr), "i"(SIGSEGV)
@@ -2182,7 +2195,7 @@
 			"j	2b\n"
 			".previous\n"
 			".section        __ex_table,\"a\"\n"
-			".word	1b, 3b\n"
+			STR(PTR) " 1b,3b\n"
 			".previous\n"
 			: "+&r"(res), "+&r"(err)
 			: "r"(vaddr), "i"(SIGSEGV));
@@ -2327,6 +2340,8 @@
 	__this_cpu_write((mipsr2bremustats).bgezl, 0);
 	__this_cpu_write((mipsr2bremustats).bltzll, 0);
 	__this_cpu_write((mipsr2bremustats).bgezll, 0);
+	__this_cpu_write((mipsr2bremustats).bltzall, 0);
+	__this_cpu_write((mipsr2bremustats).bgezall, 0);
 	__this_cpu_write((mipsr2bremustats).bltzal, 0);
 	__this_cpu_write((mipsr2bremustats).bgezal, 0);
 	__this_cpu_write((mipsr2bremustats).beql, 0);
--- linux-4.4.0.orig/arch/mips/kernel/perf_event_mipsxx.c
+++ linux-4.4.0/arch/mips/kernel/perf_event_mipsxx.c
@@ -825,6 +825,16 @@
 	[PERF_COUNT_HW_BRANCH_MISSES] = { 0x27, CNTR_ODD, T },
 };
 
+static const struct mips_perf_event i6400_event_map[PERF_COUNT_HW_MAX] = {
+	[PERF_COUNT_HW_CPU_CYCLES]          = { 0x00, CNTR_EVEN | CNTR_ODD },
+	[PERF_COUNT_HW_INSTRUCTIONS]        = { 0x01, CNTR_EVEN | CNTR_ODD },
+	/* These only count dcache, not icache */
+	[PERF_COUNT_HW_CACHE_REFERENCES]    = { 0x45, CNTR_EVEN | CNTR_ODD },
+	[PERF_COUNT_HW_CACHE_MISSES]        = { 0x48, CNTR_EVEN | CNTR_ODD },
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x15, CNTR_EVEN | CNTR_ODD },
+	[PERF_COUNT_HW_BRANCH_MISSES]       = { 0x16, CNTR_EVEN | CNTR_ODD },
+};
+
 static const struct mips_perf_event loongson3_event_map[PERF_COUNT_HW_MAX] = {
 	[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN },
 	[PERF_COUNT_HW_INSTRUCTIONS] = { 0x00, CNTR_ODD },
@@ -1015,6 +1025,46 @@
 },
 };
 
+static const struct mips_perf_event i6400_cache_map
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+[C(L1D)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x46, CNTR_EVEN | CNTR_ODD },
+		[C(RESULT_MISS)]	= { 0x49, CNTR_EVEN | CNTR_ODD },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x47, CNTR_EVEN | CNTR_ODD },
+		[C(RESULT_MISS)]	= { 0x4a, CNTR_EVEN | CNTR_ODD },
+	},
+},
+[C(L1I)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x84, CNTR_EVEN | CNTR_ODD },
+		[C(RESULT_MISS)]	= { 0x85, CNTR_EVEN | CNTR_ODD },
+	},
+},
+[C(DTLB)] = {
+	/* Can't distinguish read & write */
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x40, CNTR_EVEN | CNTR_ODD },
+		[C(RESULT_MISS)]	= { 0x41, CNTR_EVEN | CNTR_ODD },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x40, CNTR_EVEN | CNTR_ODD },
+		[C(RESULT_MISS)]	= { 0x41, CNTR_EVEN | CNTR_ODD },
+	},
+},
+[C(BPU)] = {
+	/* Conditional branches / mispredicted */
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x15, CNTR_EVEN | CNTR_ODD },
+		[C(RESULT_MISS)]	= { 0x16, CNTR_EVEN | CNTR_ODD },
+	},
+},
+};
+
 static const struct mips_perf_event loongson3_cache_map
 				[PERF_COUNT_HW_CACHE_MAX]
 				[PERF_COUNT_HW_CACHE_OP_MAX]
@@ -1556,7 +1606,6 @@
 #endif
 		break;
 	case CPU_P5600:
-	case CPU_I6400:
 		/* 8-bit event numbers */
 		raw_id = config & 0x1ff;
 		base_id = raw_id & 0xff;
@@ -1569,6 +1618,11 @@
 		raw_event.range = P;
 #endif
 		break;
+	case CPU_I6400:
+		/* 8-bit event numbers */
+		base_id = config & 0xff;
+		raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+		break;
 	case CPU_1004K:
 		if (IS_BOTH_COUNTERS_1004K_EVENT(base_id))
 			raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
@@ -1720,8 +1774,8 @@
 		break;
 	case CPU_I6400:
 		mipspmu.name = "mips/I6400";
-		mipspmu.general_event_map = &mipsxxcore_event_map2;
-		mipspmu.cache_event_map = &mipsxxcore_cache_map2;
+		mipspmu.general_event_map = &i6400_event_map;
+		mipspmu.cache_event_map = &i6400_cache_map;
 		break;
 	case CPU_1004K:
 		mipspmu.name = "mips/1004K";
--- linux-4.4.0.orig/arch/mips/kernel/pm-cps.c
+++ linux-4.4.0/arch/mips/kernel/pm-cps.c
@@ -55,7 +55,6 @@
  * state. Actually per-core rather than per-CPU.
  */
 static DEFINE_PER_CPU_ALIGNED(u32*, ready_count);
-static DEFINE_PER_CPU_ALIGNED(void*, ready_count_alloc);
 
 /* Indicates online CPUs coupled with the current CPU */
 static DEFINE_PER_CPU_ALIGNED(cpumask_t, online_coupled);
@@ -625,7 +624,6 @@
 {
 	enum cps_pm_state state;
 	unsigned core = cpu_data[cpu].core;
-	unsigned dlinesz = cpu_data[cpu].dcache.linesz;
 	void *entry_fn, *core_rc;
 
 	for (state = CPS_PM_NC_WAIT; state < CPS_PM_STATE_COUNT; state++) {
@@ -645,16 +643,11 @@
 	}
 
 	if (!per_cpu(ready_count, core)) {
-		core_rc = kmalloc(dlinesz * 2, GFP_KERNEL);
+		core_rc = kmalloc(sizeof(u32), GFP_KERNEL);
 		if (!core_rc) {
 			pr_err("Failed allocate core %u ready_count\n", core);
 			return -ENOMEM;
 		}
-		per_cpu(ready_count_alloc, core) = core_rc;
-
-		/* Ensure ready_count is aligned to a cacheline boundary */
-		core_rc += dlinesz - 1;
-		core_rc = (void *)((unsigned long)core_rc & ~(dlinesz - 1));
 		per_cpu(ready_count, core) = core_rc;
 	}
 
--- linux-4.4.0.orig/arch/mips/kernel/pm.c
+++ linux-4.4.0/arch/mips/kernel/pm.c
@@ -56,7 +56,7 @@
 		write_c0_userlocal(current_thread_info()->tp_value);
 
 	/* Restore watch registers */
-	__restore_watch();
+	__restore_watch(current);
 }
 
 /**
--- linux-4.4.0.orig/arch/mips/kernel/proc.c
+++ linux-4.4.0/arch/mips/kernel/proc.c
@@ -83,7 +83,7 @@
 	}
 
 	seq_printf(m, "isa\t\t\t:"); 
-	if (cpu_has_mips_r1)
+	if (cpu_has_mips_1)
 		seq_printf(m, " mips1");
 	if (cpu_has_mips_2)
 		seq_printf(m, "%s", " mips2");
--- linux-4.4.0.orig/arch/mips/kernel/process.c
+++ linux-4.4.0/arch/mips/kernel/process.c
@@ -32,6 +32,7 @@
 #include <asm/cpu.h>
 #include <asm/dsp.h>
 #include <asm/fpu.h>
+#include <asm/irq.h>
 #include <asm/msa.h>
 #include <asm/pgtable.h>
 #include <asm/mipsregs.h>
@@ -48,9 +49,7 @@
 #ifdef CONFIG_HOTPLUG_CPU
 void arch_cpu_idle_dead(void)
 {
-	/* What the heck is this check doing ? */
-	if (!cpumask_test_cpu(smp_processor_id(), &cpu_callin_map))
-		play_dead();
+	play_dead();
 }
 #endif
 
@@ -116,7 +115,6 @@
 	struct thread_info *ti = task_thread_info(p);
 	struct pt_regs *childregs, *regs = current_pt_regs();
 	unsigned long childksp;
-	p->set_child_tid = p->clear_child_tid = NULL;
 
 	childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32;
 
@@ -191,11 +189,9 @@
 #define J_TARGET(pc,target)	\
 		(((unsigned long)(pc) & 0xf0000000) | ((target) << 2))
 
-static inline int is_ra_save_ins(union mips_instruction *ip)
+static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
 {
 #ifdef CONFIG_CPU_MICROMIPS
-	union mips_instruction mmi;
-
 	/*
 	 * swsp ra,offset
 	 * swm16 reglist,offset(sp)
@@ -205,29 +201,71 @@
 	 *
 	 * microMIPS is way more fun...
 	 */
-	if (mm_insn_16bit(ip->halfword[0])) {
-		mmi.word = (ip->halfword[0] << 16);
-		return (mmi.mm16_r5_format.opcode == mm_swsp16_op &&
-			mmi.mm16_r5_format.rt == 31) ||
-		       (mmi.mm16_m_format.opcode == mm_pool16c_op &&
-			mmi.mm16_m_format.func == mm_swm16_op);
-	}
-	else {
-		mmi.halfword[0] = ip->halfword[1];
-		mmi.halfword[1] = ip->halfword[0];
-		return (mmi.mm_m_format.opcode == mm_pool32b_op &&
-			mmi.mm_m_format.rd > 9 &&
-			mmi.mm_m_format.base == 29 &&
-			mmi.mm_m_format.func == mm_swm32_func) ||
-		       (mmi.i_format.opcode == mm_sw32_op &&
-			mmi.i_format.rs == 29 &&
-			mmi.i_format.rt == 31);
+	if (mm_insn_16bit(ip->halfword[1])) {
+		switch (ip->mm16_r5_format.opcode) {
+		case mm_swsp16_op:
+			if (ip->mm16_r5_format.rt != 31)
+				return 0;
+
+			*poff = ip->mm16_r5_format.imm;
+			*poff = (*poff << 2) / sizeof(ulong);
+			return 1;
+
+		case mm_pool16c_op:
+			switch (ip->mm16_m_format.func) {
+			case mm_swm16_op:
+				*poff = ip->mm16_m_format.imm;
+				*poff += 1 + ip->mm16_m_format.rlist;
+				*poff = (*poff << 2) / sizeof(ulong);
+				return 1;
+
+			default:
+				return 0;
+			}
+
+		default:
+			return 0;
+		}
+	}
+
+	switch (ip->i_format.opcode) {
+	case mm_sw32_op:
+		if (ip->i_format.rs != 29)
+			return 0;
+		if (ip->i_format.rt != 31)
+			return 0;
+
+		*poff = ip->i_format.simmediate / sizeof(ulong);
+		return 1;
+
+	case mm_pool32b_op:
+		switch (ip->mm_m_format.func) {
+		case mm_swm32_func:
+			if (ip->mm_m_format.rd < 0x10)
+				return 0;
+			if (ip->mm_m_format.base != 29)
+				return 0;
+
+			*poff = ip->mm_m_format.simmediate;
+			*poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32);
+			*poff /= sizeof(ulong);
+			return 1;
+		default:
+			return 0;
+		}
+
+	default:
+		return 0;
 	}
 #else
 	/* sw / sd $ra, offset($sp) */
-	return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
-		ip->i_format.rs == 29 &&
-		ip->i_format.rt == 31;
+	if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
+		ip->i_format.rs == 29 && ip->i_format.rt == 31) {
+		*poff = ip->i_format.simmediate / sizeof(ulong);
+		return 1;
+	}
+
+	return 0;
 #endif
 }
 
@@ -242,13 +280,16 @@
 	 *
 	 * microMIPS is kind of more fun...
 	 */
-	union mips_instruction mmi;
-
-	mmi.word = (ip->halfword[0] << 16);
+	if (mm_insn_16bit(ip->halfword[1])) {
+		if ((ip->mm16_r5_format.opcode == mm_pool16c_op &&
+		    (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op))
+			return 1;
+		return 0;
+	}
 
-	if ((mmi.mm16_r5_format.opcode == mm_pool16c_op &&
-	    (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) ||
-	    ip->j_format.opcode == mm_jal32_op)
+	if (ip->j_format.opcode == mm_j32_op)
+		return 1;
+	if (ip->j_format.opcode == mm_jal32_op)
 		return 1;
 	if (ip->r_format.opcode != mm_pool32a_op ||
 			ip->r_format.func != mm_pool32axf_op)
@@ -276,15 +317,13 @@
 	 *
 	 * microMIPS is not more fun...
 	 */
-	if (mm_insn_16bit(ip->halfword[0])) {
-		union mips_instruction mmi;
-
-		mmi.word = (ip->halfword[0] << 16);
-		return (mmi.mm16_r3_format.opcode == mm_pool16d_op &&
-			mmi.mm16_r3_format.simmediate && mm_addiusp_func) ||
-		       (mmi.mm16_r5_format.opcode == mm_pool16d_op &&
-			mmi.mm16_r5_format.rt == 29);
+	if (mm_insn_16bit(ip->halfword[1])) {
+		return (ip->mm16_r3_format.opcode == mm_pool16d_op &&
+			ip->mm16_r3_format.simmediate && mm_addiusp_func) ||
+		       (ip->mm16_r5_format.opcode == mm_pool16d_op &&
+			ip->mm16_r5_format.rt == 29);
 	}
+
 	return ip->mm_i_format.opcode == mm_addiu32_op &&
 	       ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29;
 #else
@@ -299,30 +338,40 @@
 
 static int get_frame_info(struct mips_frame_info *info)
 {
-#ifdef CONFIG_CPU_MICROMIPS
-	union mips_instruction *ip = (void *) (((char *) info->func) - 1);
-#else
-	union mips_instruction *ip = info->func;
-#endif
-	unsigned max_insns = info->func_size / sizeof(union mips_instruction);
-	unsigned i;
+	bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS);
+	union mips_instruction insn, *ip;
+	const unsigned int max_insns = 128;
+	unsigned int last_insn_size = 0;
+	unsigned int i;
 
 	info->pc_offset = -1;
 	info->frame_size = 0;
 
+	ip = (void *)msk_isa16_mode((ulong)info->func);
 	if (!ip)
 		goto err;
 
-	if (max_insns == 0)
-		max_insns = 128U;	/* unknown function size */
-	max_insns = min(128U, max_insns);
+	for (i = 0; i < max_insns; i++) {
+		ip = (void *)ip + last_insn_size;
 
-	for (i = 0; i < max_insns; i++, ip++) {
+		if (is_mmips && mm_insn_16bit(ip->halfword[0])) {
+			insn.halfword[0] = 0;
+			insn.halfword[1] = ip->halfword[0];
+			last_insn_size = 2;
+		} else if (is_mmips) {
+			insn.halfword[0] = ip->halfword[1];
+			insn.halfword[1] = ip->halfword[0];
+			last_insn_size = 4;
+		} else {
+			insn.word = ip->word;
+			last_insn_size = 4;
+		}
 
-		if (is_jump_ins(ip))
+		if (is_jump_ins(&insn))
 			break;
+
 		if (!info->frame_size) {
-			if (is_sp_move_ins(ip))
+			if (is_sp_move_ins(&insn))
 			{
 #ifdef CONFIG_CPU_MICROMIPS
 				if (mm_insn_16bit(ip->halfword[0]))
@@ -337,19 +386,15 @@
 						tmp = (ip->halfword[0] >> 1);
 						info->frame_size = -(signed short)(tmp & 0xf);
 					}
-					ip = (void *) &ip->halfword[1];
-					ip--;
 				} else
 #endif
 				info->frame_size = - ip->i_format.simmediate;
 			}
 			continue;
 		}
-		if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
-			info->pc_offset =
-				ip->i_format.simmediate / sizeof(long);
+		if (info->pc_offset == -1 &&
+		    is_ra_save_ins(&insn, &info->pc_offset))
 			break;
-		}
 	}
 	if (info->frame_size && info->pc_offset >= 0) /* nested */
 		return 0;
@@ -437,31 +482,52 @@
 					      unsigned long pc,
 					      unsigned long *ra)
 {
+	unsigned long low, high, irq_stack_high;
 	struct mips_frame_info info;
 	unsigned long size, ofs;
+	struct pt_regs *regs;
 	int leaf;
-	extern void ret_from_irq(void);
-	extern void ret_from_exception(void);
 
 	if (!stack_page)
 		return 0;
 
 	/*
-	 * If we reached the bottom of interrupt context,
-	 * return saved pc in pt_regs.
+	 * IRQ stacks start at IRQ_STACK_START
+	 * task stacks at THREAD_SIZE - 32
 	 */
-	if (pc == (unsigned long)ret_from_irq ||
-	    pc == (unsigned long)ret_from_exception) {
-		struct pt_regs *regs;
-		if (*sp >= stack_page &&
-		    *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) {
-			regs = (struct pt_regs *)*sp;
-			pc = regs->cp0_epc;
-			if (__kernel_text_address(pc)) {
-				*sp = regs->regs[29];
-				*ra = regs->regs[31];
-				return pc;
-			}
+	low = stack_page;
+	if (!preemptible() && on_irq_stack(raw_smp_processor_id(), *sp)) {
+		high = stack_page + IRQ_STACK_START;
+		irq_stack_high = high;
+	} else {
+		high = stack_page + THREAD_SIZE - 32;
+		irq_stack_high = 0;
+	}
+
+	/*
+	 * If we reached the top of the interrupt stack, start unwinding
+	 * the interrupted task stack.
+	 */
+	if (unlikely(*sp == irq_stack_high)) {
+		unsigned long task_sp = *(unsigned long *)*sp;
+
+		/*
+		 * Check that the pointer saved in the IRQ stack head points to
+		 * something within the stack of the current task
+		 */
+		if (!object_is_on_stack((void *)task_sp))
+			return 0;
+
+		/*
+		 * Follow pointer to tasks kernel stack frame where interrupted
+		 * state was saved.
+		 */
+		regs = (struct pt_regs *)task_sp;
+		pc = regs->cp0_epc;
+		if (!user_mode(regs) && __kernel_text_address(pc)) {
+			*sp = regs->regs[29];
+			*ra = regs->regs[31];
+			return pc;
 		}
 		return 0;
 	}
@@ -482,8 +548,7 @@
 	if (leaf < 0)
 		return 0;
 
-	if (*sp < stack_page ||
-	    *sp + info.frame_size > stack_page + THREAD_SIZE - 32)
+	if (*sp < low || *sp + info.frame_size > high)
 		return 0;
 
 	if (leaf)
@@ -507,7 +572,19 @@
 unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
 			   unsigned long pc, unsigned long *ra)
 {
-	unsigned long stack_page = (unsigned long)task_stack_page(task);
+	unsigned long stack_page = 0;
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		if (on_irq_stack(cpu, *sp)) {
+			stack_page = (unsigned long)irq_stack[cpu];
+			break;
+		}
+	}
+
+	if (!stack_page)
+		stack_page = (unsigned long)task_stack_page(task);
+
 	return unwind_stack_by_address(stack_page, sp, pc, ra);
 }
 #endif
@@ -553,21 +630,48 @@
 	return sp & ALMASK;
 }
 
+static DEFINE_PER_CPU(struct call_single_data, backtrace_csd);
+static struct cpumask backtrace_csd_busy;
+
 static void arch_dump_stack(void *info)
 {
 	struct pt_regs *regs;
+	static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
 
+	arch_spin_lock(&lock);
 	regs = get_irq_regs();
 
 	if (regs)
 		show_regs(regs);
+	else
+		dump_stack();
+	arch_spin_unlock(&lock);
 
-	dump_stack();
+	cpumask_clear_cpu(smp_processor_id(), &backtrace_csd_busy);
 }
 
 void arch_trigger_all_cpu_backtrace(bool include_self)
 {
-	smp_call_function(arch_dump_stack, NULL, 1);
+	struct call_single_data *csd;
+	int cpu;
+
+	for_each_cpu(cpu, cpu_online_mask) {
+		/*
+		 * If we previously sent an IPI to the target CPU & it hasn't
+		 * cleared its bit in the busy cpumask then it didn't handle
+		 * our previous IPI & it's not safe for us to reuse the
+		 * call_single_data_t.
+		 */
+		if (cpumask_test_and_set_cpu(cpu, &backtrace_csd_busy)) {
+			pr_warn("Unable to send backtrace IPI to CPU%u - perhaps it hung?\n",
+				cpu);
+			continue;
+		}
+
+		csd = &per_cpu(backtrace_csd, cpu);
+		csd->func = arch_dump_stack;
+		smp_call_function_single_async(cpu, csd);
+	}
 }
 
 int mips_get_process_fp_mode(struct task_struct *task)
@@ -588,21 +692,40 @@
 	unsigned long switch_count;
 	struct task_struct *t;
 
+	/* If nothing to change, return right away, successfully.  */
+	if (value == mips_get_process_fp_mode(task))
+		return 0;
+
+	/* Only accept a mode change if 64-bit FP enabled for o32.  */
+	if (!IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT))
+		return -EOPNOTSUPP;
+
+	/* And only for o32 tasks.  */
+	if (IS_ENABLED(CONFIG_64BIT) && !test_thread_flag(TIF_32BIT_REGS))
+		return -EOPNOTSUPP;
+
 	/* Check the value is valid */
 	if (value & ~known_bits)
 		return -EOPNOTSUPP;
 
+	/* Setting FRE without FR is not supported.  */
+	if ((value & (PR_FP_MODE_FR | PR_FP_MODE_FRE)) == PR_FP_MODE_FRE)
+		return -EOPNOTSUPP;
+
 	/* Avoid inadvertently triggering emulation */
-	if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
-	    !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
+	if ((value & PR_FP_MODE_FR) && raw_cpu_has_fpu &&
+	    !(raw_current_cpu_data.fpu_id & MIPS_FPIR_F64))
 		return -EOPNOTSUPP;
-	if ((value & PR_FP_MODE_FRE) && cpu_has_fpu && !cpu_has_fre)
+	if ((value & PR_FP_MODE_FRE) && raw_cpu_has_fpu && !cpu_has_fre)
 		return -EOPNOTSUPP;
 
 	/* FR = 0 not supported in MIPS R6 */
-	if (!(value & PR_FP_MODE_FR) && cpu_has_fpu && cpu_has_mips_r6)
+	if (!(value & PR_FP_MODE_FR) && raw_cpu_has_fpu && cpu_has_mips_r6)
 		return -EOPNOTSUPP;
 
+	/* Proceed with the mode switch */
+	preempt_disable();
+
 	/* Save FP & vector context, then disable FPU & MSA */
 	if (task->signal == current->signal)
 		lose_fpu(1);
@@ -661,6 +784,7 @@
 
 	/* Allow threads to use FP again */
 	atomic_set(&task->mm->context.fp_mode_switching, 0);
+	preempt_enable();
 
 	return 0;
 }
--- linux-4.4.0.orig/arch/mips/kernel/ptrace.c
+++ linux-4.4.0/arch/mips/kernel/ptrace.c
@@ -57,8 +57,7 @@
 	/* Begin with data registers set to all 1s... */
 	memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr));
 
-	/* ...and FCSR zeroed */
-	target->thread.fpu.fcr31 = 0;
+	/* FCSR has been preset by `mips_set_personality_nan'.  */
 
 	/*
 	 * Record that the target has "used" math, such that the context
@@ -80,6 +79,21 @@
 }
 
 /*
+ * Poke at FCSR according to its mask.  Set the Cause bits even
+ * if a corresponding Enable bit is set.  This will be noticed at
+ * the time the thread is switched to and SIGFPE thrown accordingly.
+ */
+static void ptrace_setfcr31(struct task_struct *child, u32 value)
+{
+	u32 fcr31;
+	u32 mask;
+
+	fcr31 = child->thread.fpu.fcr31;
+	mask = boot_cpu_data.fpu_msk31;
+	child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
+}
+
+/*
  * Read a general register set.	 We always use the 64-bit format, even
  * for 32-bit kernels and for 32-bit processes on a 64-bit kernel.
  * Registers are sign extended to fill the available space.
@@ -159,9 +173,7 @@
 {
 	union fpureg *fregs;
 	u64 fpr_val;
-	u32 fcr31;
 	u32 value;
-	u32 mask;
 	int i;
 
 	if (!access_ok(VERIFY_READ, data, 33 * 8))
@@ -176,9 +188,7 @@
 	}
 
 	__get_user(value, data + 64);
-	fcr31 = child->thread.fpu.fcr31;
-	mask = boot_cpu_data.fpu_msk31;
-	child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
+	ptrace_setfcr31(child, value);
 
 	/* FIR may not be written.  */
 
@@ -428,62 +438,174 @@
 
 #endif /* CONFIG_64BIT */
 
+/*
+ * Copy the floating-point context to the supplied NT_PRFPREG buffer,
+ * !CONFIG_CPU_HAS_MSA variant.  FP context's general register slots
+ * correspond 1:1 to buffer slots.  Only general registers are copied.
+ */
+static int fpr_get_fpa(struct task_struct *target,
+		       unsigned int *pos, unsigned int *count,
+		       void **kbuf, void __user **ubuf)
+{
+	return user_regset_copyout(pos, count, kbuf, ubuf,
+				   &target->thread.fpu,
+				   0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
+}
+
+/*
+ * Copy the floating-point context to the supplied NT_PRFPREG buffer,
+ * CONFIG_CPU_HAS_MSA variant.  Only lower 64 bits of FP context's
+ * general register slots are copied to buffer slots.  Only general
+ * registers are copied.
+ */
+static int fpr_get_msa(struct task_struct *target,
+		       unsigned int *pos, unsigned int *count,
+		       void **kbuf, void __user **ubuf)
+{
+	unsigned int i;
+	u64 fpr_val;
+	int err;
+
+	BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
+	for (i = 0; i < NUM_FPU_REGS; i++) {
+		fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
+		err = user_regset_copyout(pos, count, kbuf, ubuf,
+					  &fpr_val, i * sizeof(elf_fpreg_t),
+					  (i + 1) * sizeof(elf_fpreg_t));
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/*
+ * Copy the floating-point context to the supplied NT_PRFPREG buffer.
+ * Choose the appropriate helper for general registers, and then copy
+ * the FCSR and FIR registers separately.
+ */
 static int fpr_get(struct task_struct *target,
 		   const struct user_regset *regset,
 		   unsigned int pos, unsigned int count,
 		   void *kbuf, void __user *ubuf)
 {
-	unsigned i;
+	const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
+	const int fir_pos = fcr31_pos + sizeof(u32);
 	int err;
-	u64 fpr_val;
 
-	/* XXX fcr31  */
+	if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
+		err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf);
+	else
+		err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf);
+	if (err)
+		return err;
 
-	if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
-		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-					   &target->thread.fpu,
-					   0, sizeof(elf_fpregset_t));
+	err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				  &target->thread.fpu.fcr31,
+				  fcr31_pos, fcr31_pos + sizeof(u32));
+	if (err)
+		return err;
 
-	for (i = 0; i < NUM_FPU_REGS; i++) {
-		fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
-		err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-					  &fpr_val, i * sizeof(elf_fpreg_t),
-					  (i + 1) * sizeof(elf_fpreg_t));
+	err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				  &boot_cpu_data.fpu_id,
+				  fir_pos, fir_pos + sizeof(u32));
+
+	return err;
+}
+
+/*
+ * Copy the supplied NT_PRFPREG buffer to the floating-point context,
+ * !CONFIG_CPU_HAS_MSA variant.   Buffer slots correspond 1:1 to FP
+ * context's general register slots.  Only general registers are copied.
+ */
+static int fpr_set_fpa(struct task_struct *target,
+		       unsigned int *pos, unsigned int *count,
+		       const void **kbuf, const void __user **ubuf)
+{
+	return user_regset_copyin(pos, count, kbuf, ubuf,
+				  &target->thread.fpu,
+				  0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
+}
+
+/*
+ * Copy the supplied NT_PRFPREG buffer to the floating-point context,
+ * CONFIG_CPU_HAS_MSA variant.  Buffer slots are copied to lower 64
+ * bits only of FP context's general register slots.  Only general
+ * registers are copied.
+ */
+static int fpr_set_msa(struct task_struct *target,
+		       unsigned int *pos, unsigned int *count,
+		       const void **kbuf, const void __user **ubuf)
+{
+	unsigned int i;
+	u64 fpr_val;
+	int err;
+
+	BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
+	for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) {
+		err = user_regset_copyin(pos, count, kbuf, ubuf,
+					 &fpr_val, i * sizeof(elf_fpreg_t),
+					 (i + 1) * sizeof(elf_fpreg_t));
 		if (err)
 			return err;
+		set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
 	}
 
 	return 0;
 }
 
+/*
+ * Copy the supplied NT_PRFPREG buffer to the floating-point context.
+ * Choose the appropriate helper for general registers, and then copy
+ * the FCSR register separately.  Ignore the incoming FIR register
+ * contents though, as the register is read-only.
+ *
+ * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0',
+ * which is supposed to have been guaranteed by the kernel before
+ * calling us, e.g. in `ptrace_regset'.  We enforce that requirement,
+ * so that we can safely avoid preinitializing temporaries for
+ * partial register writes.
+ */
 static int fpr_set(struct task_struct *target,
 		   const struct user_regset *regset,
 		   unsigned int pos, unsigned int count,
 		   const void *kbuf, const void __user *ubuf)
 {
-	unsigned i;
+	const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
+	const int fir_pos = fcr31_pos + sizeof(u32);
+	u32 fcr31;
 	int err;
-	u64 fpr_val;
 
-	/* XXX fcr31  */
+	BUG_ON(count % sizeof(elf_fpreg_t));
+
+	if (pos + count > sizeof(elf_fpregset_t))
+		return -EIO;
 
 	init_fp_ctx(target);
 
-	if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
-		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-					  &target->thread.fpu,
-					  0, sizeof(elf_fpregset_t));
+	if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
+		err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf);
+	else
+		err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf);
+	if (err)
+		return err;
 
-	for (i = 0; i < NUM_FPU_REGS; i++) {
+	if (count > 0) {
 		err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-					 &fpr_val, i * sizeof(elf_fpreg_t),
-					 (i + 1) * sizeof(elf_fpreg_t));
+					 &fcr31,
+					 fcr31_pos, fcr31_pos + sizeof(u32));
 		if (err)
 			return err;
-		set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
+
+		ptrace_setfcr31(target, fcr31);
 	}
 
-	return 0;
+	if (count > 0)
+		err = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+						fir_pos,
+						fir_pos + sizeof(u32));
+
+	return err;
 }
 
 enum mips_regset {
@@ -548,9 +670,6 @@
 	REG_OFFSET_NAME(c0_badvaddr, cp0_badvaddr),
 	REG_OFFSET_NAME(c0_cause, cp0_cause),
 	REG_OFFSET_NAME(c0_epc, cp0_epc),
-#ifdef CONFIG_MIPS_MT_SMTC
-	REG_OFFSET_NAME(c0_tcstatus, cp0_tcstatus),
-#endif
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
 	REG_OFFSET_NAME(mpl0, mpl[0]),
 	REG_OFFSET_NAME(mpl1, mpl[1]),
@@ -638,6 +757,19 @@
 	.n		= ARRAY_SIZE(mips64_regsets),
 };
 
+#ifdef CONFIG_MIPS32_N32
+
+static const struct user_regset_view user_mipsn32_view = {
+	.name		= "mipsn32",
+	.e_flags	= EF_MIPS_ABI2,
+	.e_machine	= ELF_ARCH,
+	.ei_osabi	= ELF_OSABI,
+	.regsets	= mips64_regsets,
+	.n		= ARRAY_SIZE(mips64_regsets),
+};
+
+#endif /* CONFIG_MIPS32_N32 */
+
 #endif /* CONFIG_64BIT */
 
 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
@@ -649,6 +781,10 @@
 	if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
 		return &user_mips_view;
 #endif
+#ifdef CONFIG_MIPS32_N32
+	if (test_tsk_thread_flag(task, TIF_32BIT_ADDR))
+		return &user_mipsn32_view;
+#endif
 	return &user_mips64_view;
 #endif
 }
@@ -690,7 +826,7 @@
 			fregs = get_fpu_regs(child);
 
 #ifdef CONFIG_32BIT
-			if (test_thread_flag(TIF_32BIT_FPREGS)) {
+			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
 				/*
 				 * The odd registers are actually the high
 				 * order bits of the values stored in the even
@@ -701,7 +837,7 @@
 				break;
 			}
 #endif
-			tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
+			tmp = get_fpr64(&fregs[addr - FPR_BASE], 0);
 			break;
 		case PC:
 			tmp = regs->cp0_epc;
@@ -739,7 +875,7 @@
 				goto out;
 			}
 			dregs = __get_dsp_regs(child);
-			tmp = (unsigned long) (dregs[addr - DSP_BASE]);
+			tmp = dregs[addr - DSP_BASE];
 			break;
 		}
 		case DSP_CONTROL:
@@ -779,7 +915,7 @@
 
 			init_fp_ctx(child);
 #ifdef CONFIG_32BIT
-			if (test_thread_flag(TIF_32BIT_FPREGS)) {
+			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
 				/*
 				 * The odd registers are actually the high
 				 * order bits of the values stored in the even
@@ -808,7 +944,7 @@
 			break;
 #endif
 		case FPC_CSR:
-			child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X;
+			ptrace_setfcr31(child, data);
 			break;
 		case DSP_BASE ... DSP_BASE + 5: {
 			dspreg_t *dregs;
@@ -915,7 +1051,7 @@
 	audit_syscall_exit(regs);
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
-		trace_sys_exit(regs, regs->regs[2]);
+		trace_sys_exit(regs, regs_return_value(regs));
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
 		tracehook_report_syscall_exit(regs, 0);
--- linux-4.4.0.orig/arch/mips/kernel/ptrace32.c
+++ linux-4.4.0/arch/mips/kernel/ptrace32.c
@@ -97,7 +97,7 @@
 				break;
 			}
 			fregs = get_fpu_regs(child);
-			if (test_thread_flag(TIF_32BIT_FPREGS)) {
+			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
 				/*
 				 * The odd registers are actually the high
 				 * order bits of the values stored in the even
@@ -107,7 +107,7 @@
 						addr & 1);
 				break;
 			}
-			tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
+			tmp = get_fpr64(&fregs[addr - FPR_BASE], 0);
 			break;
 		case PC:
 			tmp = regs->cp0_epc;
@@ -140,7 +140,7 @@
 				goto out;
 			}
 			dregs = __get_dsp_regs(child);
-			tmp = (unsigned long) (dregs[addr - DSP_BASE]);
+			tmp = dregs[addr - DSP_BASE];
 			break;
 		}
 		case DSP_CONTROL:
@@ -203,7 +203,7 @@
 				       sizeof(child->thread.fpu));
 				child->thread.fpu.fcr31 = 0;
 			}
-			if (test_thread_flag(TIF_32BIT_FPREGS)) {
+			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
 				/*
 				 * The odd registers are actually the high
 				 * order bits of the values stored in the even
--- linux-4.4.0.orig/arch/mips/kernel/r4k_fpu.S
+++ linux-4.4.0/arch/mips/kernel/r4k_fpu.S
@@ -244,17 +244,17 @@
 	.set	push
 	.set	noat
 #ifdef CONFIG_64BIT
-	copy_u_d \wr, 1
+	copy_s_d \wr, 1
 	EX sd	$1, \off(\base)
 #elif defined(CONFIG_CPU_LITTLE_ENDIAN)
-	copy_u_w \wr, 2
+	copy_s_w \wr, 2
 	EX sw	$1, \off(\base)
-	copy_u_w \wr, 3
+	copy_s_w \wr, 3
 	EX sw	$1, (\off+4)(\base)
 #else /* CONFIG_CPU_BIG_ENDIAN */
-	copy_u_w \wr, 2
+	copy_s_w \wr, 2
 	EX sw	$1, (\off+4)(\base)
-	copy_u_w \wr, 3
+	copy_s_w \wr, 3
 	EX sw	$1, \off(\base)
 #endif
 	.set	pop
--- linux-4.4.0.orig/arch/mips/kernel/scall32-o32.S
+++ linux-4.4.0/arch/mips/kernel/scall32-o32.S
@@ -35,7 +35,6 @@
 
 	lw	t1, PT_EPC(sp)		# skip syscall on return
 
-	subu	v0, v0, __NR_O32_Linux	# check syscall number
 	addiu	t1, 4			# skip to next instruction
 	sw	t1, PT_EPC(sp)
 
@@ -89,6 +88,7 @@
 	and	t0, t1
 	bnez	t0, syscall_trace_entry # -> yes
 syscall_common:
+	subu	v0, v0, __NR_O32_Linux	# check syscall number
 	sltiu	t0, v0, __NR_O32_Linux_syscalls + 1
 	beqz	t0, illegal_syscall
 
@@ -118,24 +118,23 @@
 
 syscall_trace_entry:
 	SAVE_STATIC
-	move	s0, v0
 	move	a0, sp
 
 	/*
 	 * syscall number is in v0 unless we called syscall(__NR_###)
 	 * where the real syscall number is in a0
 	 */
-	addiu	a1, v0,  __NR_O32_Linux
-	bnez	v0, 1f /* __NR_syscall at offset 0 */
+	move	a1, v0
+	subu	t2, v0,  __NR_O32_Linux
+	bnez	t2, 1f /* __NR_syscall at offset 0 */
 	lw	a1, PT_R4(sp)
 
 1:	jal	syscall_trace_enter
 
 	bltz	v0, 1f			# seccomp failed? Skip syscall
 
-	move	v0, s0			# restore syscall
-
 	RESTORE_STATIC
+	lw	v0, PT_R2(sp)		# Restore syscall (maybe modified)
 	lw	a0, PT_R4(sp)		# Restore argument registers
 	lw	a1, PT_R5(sp)
 	lw	a2, PT_R6(sp)
@@ -372,7 +371,7 @@
 	PTR	sys_writev
 	PTR	sys_cacheflush
 	PTR	sys_cachectl
-	PTR	sys_sysmips
+	PTR	__sys_sysmips
 	PTR	sys_ni_syscall			/* 4150 */
 	PTR	sys_getsid
 	PTR	sys_fdatasync
--- linux-4.4.0.orig/arch/mips/kernel/scall64-64.S
+++ linux-4.4.0/arch/mips/kernel/scall64-64.S
@@ -82,15 +82,14 @@
 
 syscall_trace_entry:
 	SAVE_STATIC
-	move	s0, v0
 	move	a0, sp
 	move	a1, v0
 	jal	syscall_trace_enter
 
 	bltz	v0, 1f			# seccomp failed? Skip syscall
 
-	move	v0, s0
 	RESTORE_STATIC
+	ld	v0, PT_R2(sp)		# Restore syscall (maybe modified)
 	ld	a0, PT_R4(sp)		# Restore argument registers
 	ld	a1, PT_R5(sp)
 	ld	a2, PT_R6(sp)
@@ -312,7 +311,7 @@
 	PTR	sys_sched_getaffinity
 	PTR	sys_cacheflush
 	PTR	sys_cachectl
-	PTR	sys_sysmips
+	PTR	__sys_sysmips
 	PTR	sys_io_setup			/* 5200 */
 	PTR	sys_io_destroy
 	PTR	sys_io_getevents
--- linux-4.4.0.orig/arch/mips/kernel/scall64-n32.S
+++ linux-4.4.0/arch/mips/kernel/scall64-n32.S
@@ -42,9 +42,6 @@
 #endif
 	beqz	t0, not_n32_scall
 
-	dsll	t0, v0, 3		# offset into table
-	ld	t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0)
-
 	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
 
 	li	t1, _TIF_WORK_SYSCALL_ENTRY
@@ -53,6 +50,9 @@
 	bnez	t0, n32_syscall_trace_entry
 
 syscall_common:
+	dsll	t0, v0, 3		# offset into table
+	ld	t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0)
+
 	jalr	t2			# Do The Real Thing (TM)
 
 	li	t0, -EMAXERRNO - 1	# error?
@@ -71,21 +71,25 @@
 
 n32_syscall_trace_entry:
 	SAVE_STATIC
-	move	s0, t2
 	move	a0, sp
 	move	a1, v0
 	jal	syscall_trace_enter
 
 	bltz	v0, 1f			# seccomp failed? Skip syscall
 
-	move	t2, s0
 	RESTORE_STATIC
+	ld	v0, PT_R2(sp)		# Restore syscall (maybe modified)
 	ld	a0, PT_R4(sp)		# Restore argument registers
 	ld	a1, PT_R5(sp)
 	ld	a2, PT_R6(sp)
 	ld	a3, PT_R7(sp)
 	ld	a4, PT_R8(sp)
 	ld	a5, PT_R9(sp)
+
+	dsubu	t2, v0, __NR_N32_Linux	# check (new) syscall number
+	sltiu   t0, t2, __NR_N32_Linux_syscalls + 1
+	beqz	t0, not_n32_scall
+
 	j	syscall_common
 
 1:	j	syscall_exit
@@ -298,7 +302,7 @@
 	PTR	compat_sys_sched_getaffinity
 	PTR	sys_cacheflush
 	PTR	sys_cachectl
-	PTR	sys_sysmips
+	PTR	__sys_sysmips
 	PTR	compat_sys_io_setup			/* 6200 */
 	PTR	sys_io_destroy
 	PTR	compat_sys_io_getevents
@@ -344,7 +348,7 @@
 	PTR	sys_ni_syscall			/* available, was setaltroot */
 	PTR	sys_add_key
 	PTR	sys_request_key
-	PTR	sys_keyctl			/* 6245 */
+	PTR	compat_sys_keyctl		/* 6245 */
 	PTR	sys_set_thread_area
 	PTR	sys_inotify_init
 	PTR	sys_inotify_add_watch
--- linux-4.4.0.orig/arch/mips/kernel/scall64-o32.S
+++ linux-4.4.0/arch/mips/kernel/scall64-o32.S
@@ -52,9 +52,6 @@
 	sll	a2, a2, 0
 	sll	a3, a3, 0
 
-	dsll	t0, v0, 3		# offset into table
-	ld	t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0)
-
 	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
 
 	/*
@@ -88,6 +85,9 @@
 	bnez	t0, trace_a_syscall
 
 syscall_common:
+	dsll	t0, v0, 3		# offset into table
+	ld	t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0)
+
 	jalr	t2			# Do The Real Thing (TM)
 
 	li	t0, -EMAXERRNO - 1	# error?
@@ -112,7 +112,6 @@
 	sd	a6, PT_R10(sp)
 	sd	a7, PT_R11(sp)		# For indirect syscalls
 
-	move	s0, t2			# Save syscall pointer
 	move	a0, sp
 	/*
 	 * absolute syscall number is in v0 unless we called syscall(__NR_###)
@@ -126,15 +125,15 @@
 	subu	t1, v0,  __NR_O32_Linux
 	move	a1, v0
 	bnez	t1, 1f /* __NR_syscall at offset 0 */
-	lw	a1, PT_R4(sp) /* Arg1 for __NR_syscall case */
+	ld	a1, PT_R4(sp) /* Arg1 for __NR_syscall case */
 	.set	pop
 
 1:	jal	syscall_trace_enter
 
 	bltz	v0, 1f			# seccomp failed? Skip syscall
 
-	move	t2, s0
 	RESTORE_STATIC
+	ld	v0, PT_R2(sp)		# Restore syscall (maybe modified)
 	ld	a0, PT_R4(sp)		# Restore argument registers
 	ld	a1, PT_R5(sp)
 	ld	a2, PT_R6(sp)
@@ -143,6 +142,11 @@
 	ld	a5, PT_R9(sp)
 	ld	a6, PT_R10(sp)
 	ld	a7, PT_R11(sp)		# For indirect syscalls
+
+	dsubu	t0, v0, __NR_O32_Linux	# check (new) syscall number
+	sltiu	t0, t0, __NR_O32_Linux_syscalls + 1
+	beqz	t0, not_o32_scall
+
 	j	syscall_common
 
 1:	j	syscall_exit
@@ -367,7 +371,7 @@
 	PTR	compat_sys_writev
 	PTR	sys_cacheflush
 	PTR	sys_cachectl
-	PTR	sys_sysmips
+	PTR	__sys_sysmips
 	PTR	sys_ni_syscall			/* 4150 */
 	PTR	sys_getsid
 	PTR	sys_fdatasync
@@ -500,7 +504,7 @@
 	PTR	sys_ni_syscall			/* available, was setaltroot */
 	PTR	sys_add_key			/* 4280 */
 	PTR	sys_request_key
-	PTR	sys_keyctl
+	PTR	compat_sys_keyctl
 	PTR	sys_set_thread_area
 	PTR	sys_inotify_init
 	PTR	sys_inotify_add_watch		/* 4285 */
--- linux-4.4.0.orig/arch/mips/kernel/setup.c
+++ linux-4.4.0/arch/mips/kernel/setup.c
@@ -80,7 +80,7 @@
  * mips_io_port_base is the begin of the address space to which x86 style
  * I/O ports are mapped.
  */
-const unsigned long mips_io_port_base = -1;
+unsigned long mips_io_port_base = -1;
 EXPORT_SYMBOL(mips_io_port_base);
 
 static struct resource code_resource = { .name = "Kernel code", };
@@ -152,6 +152,35 @@
 	add_memory_region(start, size, BOOT_MEM_RAM);
 }
 
+bool __init memory_region_available(phys_addr_t start, phys_addr_t size)
+{
+	int i;
+	bool in_ram = false, free = true;
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		phys_addr_t start_, end_;
+
+		start_ = boot_mem_map.map[i].addr;
+		end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size;
+
+		switch (boot_mem_map.map[i].type) {
+		case BOOT_MEM_RAM:
+			if (start >= start_ && start + size <= end_)
+				in_ram = true;
+			break;
+		case BOOT_MEM_RESERVED:
+			if ((start >= start_ && start < end_) ||
+			    (start < start_ && start + size >= start_))
+				free = false;
+			break;
+		default:
+			continue;
+		}
+	}
+
+	return in_ram && free;
+}
+
 static void __init print_memory_map(void)
 {
 	int i;
@@ -300,11 +329,19 @@
 
 #else  /* !CONFIG_SGI_IP27 */
 
+static unsigned long __init bootmap_bytes(unsigned long pages)
+{
+	unsigned long bytes = DIV_ROUND_UP(pages, 8);
+
+	return ALIGN(bytes, sizeof(long));
+}
+
 static void __init bootmem_init(void)
 {
 	unsigned long reserved_end;
 	unsigned long mapstart = ~0UL;
 	unsigned long bootmap_size;
+	bool bootmap_valid = false;
 	int i;
 
 	/*
@@ -385,11 +422,42 @@
 #endif
 
 	/*
-	 * Initialize the boot-time allocator with low memory only.
+	 * check that mapstart doesn't overlap with any of
+	 * memory regions that have been reserved through eg. DTB
 	 */
-	bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
-					 min_low_pfn, max_low_pfn);
+	bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn);
+
+	bootmap_valid = memory_region_available(PFN_PHYS(mapstart),
+						bootmap_size);
+	for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) {
+		unsigned long mapstart_addr;
+
+		switch (boot_mem_map.map[i].type) {
+		case BOOT_MEM_RESERVED:
+			mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr +
+						boot_mem_map.map[i].size);
+			if (PHYS_PFN(mapstart_addr) < mapstart)
+				break;
+
+			bootmap_valid = memory_region_available(mapstart_addr,
+								bootmap_size);
+			if (bootmap_valid)
+				mapstart = PHYS_PFN(mapstart_addr);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (!bootmap_valid)
+		panic("No memory area to place a bootmap bitmap");
 
+	/*
+	 * Initialize the boot-time allocator with low memory only.
+	 */
+	if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart,
+					 min_low_pfn, max_low_pfn))
+		panic("Unexpected memory size required for bootmap");
 
 	for (i = 0; i < boot_mem_map.nr_map; i++) {
 		unsigned long start, end;
@@ -438,6 +506,10 @@
 			continue;
 		default:
 			/* Not usable memory */
+			if (start > min_low_pfn && end < max_low_pfn)
+				reserve_bootmem(boot_mem_map.map[i].addr,
+						boot_mem_map.map[i].size,
+						BOOTMEM_DEFAULT);
 			continue;
 		}
 
@@ -623,7 +695,7 @@
 
 #define USE_PROM_CMDLINE	IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
 #define USE_DTB_CMDLINE		IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
-#define EXTEND_WITH_PROM	IS_ENABLED(CONFIG_MIPS_CMDLINE_EXTEND)
+#define EXTEND_WITH_PROM	IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
 
 static void __init arch_mem_init(char **cmdline_p)
 {
@@ -697,7 +769,17 @@
 				BOOTMEM_DEFAULT);
 #endif
 	device_tree_init();
+
+	/*
+	 * In order to reduce the possibility of kernel panic when failed to
+	 * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
+	 * low memory as small as possible before plat_swiotlb_setup(), so
+	 * make sparse_init() using top-down allocation.
+	 */
+	memblock_set_bottom_up(false);
 	sparse_init();
+	memblock_set_bottom_up(true);
+
 	plat_swiotlb_setup();
 	paging_init();
 
@@ -706,6 +788,9 @@
 	for_each_memblock(reserved, reg)
 		if (reg->size != 0)
 			reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+
+	reserve_bootmem_region(__pa_symbol(&__nosave_begin),
+			__pa_symbol(&__nosave_end)); /* Reserve for hibernation */
 }
 
 static void __init resource_init(void)
--- linux-4.4.0.orig/arch/mips/kernel/signal.c
+++ linux-4.4.0/arch/mips/kernel/signal.c
@@ -195,6 +195,9 @@
 	unsigned int csr;
 	int i, err;
 
+	if (!config_enabled(CONFIG_CPU_HAS_MSA))
+		return SIGSYS;
+
 	if (size != sizeof(*msa))
 		return -EINVAL;
 
@@ -398,8 +401,8 @@
 	}
 
 fp_done:
-	if (used & USED_EXTCONTEXT)
-		err |= restore_extcontext(sc_to_extcontext(sc));
+	if (!err && (used & USED_EXTCONTEXT))
+		err = restore_extcontext(sc_to_extcontext(sc));
 
 	return err ?: sig;
 }
@@ -767,15 +770,7 @@
 	sigset_t *oldset = sigmask_to_save();
 	int ret;
 	struct mips_abi *abi = current->thread.abi;
-#ifdef CONFIG_CPU_MICROMIPS
-	void *vdso;
-	unsigned long tmp = (unsigned long)current->mm->context.vdso;
-
-	set_isa16_mode(tmp);
-	vdso = (void *)tmp;
-#else
 	void *vdso = current->mm->context.vdso;
-#endif
 
 	if (regs->regs[0]) {
 		switch(regs->regs[2]) {
--- linux-4.4.0.orig/arch/mips/kernel/smp-bmips.c
+++ linux-4.4.0/arch/mips/kernel/smp-bmips.c
@@ -166,11 +166,11 @@
 		return;
 	}
 
-	if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU,
-			"smp_ipi0", NULL))
+	if (request_irq(IPI0_IRQ, bmips_ipi_interrupt,
+			IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi0", NULL))
 		panic("Can't request IPI0 interrupt");
-	if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, IRQF_PERCPU,
-			"smp_ipi1", NULL))
+	if (request_irq(IPI1_IRQ, bmips_ipi_interrupt,
+			IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi1", NULL))
 		panic("Can't request IPI1 interrupt");
 }
 
@@ -362,6 +362,7 @@
 	pr_info("SMP: CPU%d is offline\n", cpu);
 
 	set_cpu_online(cpu, false);
+	calculate_cpu_foreign_map();
 	cpumask_clear_cpu(cpu, &cpu_callin_map);
 	clear_c0_status(IE_IRQ5);
 
@@ -451,10 +452,10 @@
 
 static inline void bmips_nmi_handler_setup(void)
 {
-	bmips_wr_vec(BMIPS_NMI_RESET_VEC, &bmips_reset_nmi_vec,
-		&bmips_reset_nmi_vec_end);
-	bmips_wr_vec(BMIPS_WARM_RESTART_VEC, &bmips_smp_int_vec,
-		&bmips_smp_int_vec_end);
+	bmips_wr_vec(BMIPS_NMI_RESET_VEC, bmips_reset_nmi_vec,
+		bmips_reset_nmi_vec_end);
+	bmips_wr_vec(BMIPS_WARM_RESTART_VEC, bmips_smp_int_vec,
+		bmips_smp_int_vec_end);
 }
 
 struct reset_vec_info {
--- linux-4.4.0.orig/arch/mips/kernel/smp-cps.c
+++ linux-4.4.0/arch/mips/kernel/smp-cps.c
@@ -338,6 +338,7 @@
 	atomic_sub(1 << cpu_vpe_id(&current_cpu_data), &core_cfg->vpe_mask);
 	smp_mb__after_atomic();
 	set_cpu_online(cpu, false);
+	calculate_cpu_foreign_map();
 	cpumask_clear_cpu(cpu, &cpu_callin_map);
 
 	return 0;
--- linux-4.4.0.orig/arch/mips/kernel/smp.c
+++ linux-4.4.0/arch/mips/kernel/smp.c
@@ -64,6 +64,9 @@
 cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(cpu_core_map);
 
+static DECLARE_COMPLETION(cpu_starting);
+static DECLARE_COMPLETION(cpu_running);
+
 /*
  * A logcal cpu mask containing only one VPE per core to
  * reduce the number of IPIs on large MT systems.
@@ -115,12 +118,13 @@
  * Calculate a new cpu_foreign_map mask whenever a
  * new cpu appears or disappears.
  */
-static inline void calculate_cpu_foreign_map(void)
+void calculate_cpu_foreign_map(void)
 {
 	int i, k, core_present;
 	cpumask_t temp_foreign_map;
 
 	/* Re-calculate the mask */
+	cpumask_clear(&temp_foreign_map);
 	for_each_online_cpu(i) {
 		core_present = 0;
 		for_each_cpu(k, &temp_foreign_map)
@@ -173,6 +177,12 @@
 	cpumask_set_cpu(cpu, &cpu_coherent_mask);
 	notify_cpu_starting(cpu);
 
+	/* Notify boot CPU that we're starting & ready to sync counters */
+	complete(&cpu_starting);
+
+	synchronise_count_slave(cpu);
+
+	/* The CPU is running and counters synchronised, now mark it online */
 	set_cpu_online(cpu, true);
 
 	set_cpu_sibling_map(cpu);
@@ -180,9 +190,11 @@
 
 	calculate_cpu_foreign_map();
 
-	cpumask_set_cpu(cpu, &cpu_callin_map);
-
-	synchronise_count_slave(cpu);
+	/*
+	 * Notify boot CPU that we're up & online and it can safely return
+	 * from __cpu_up
+	 */
+	complete(&cpu_running);
 
 	/*
 	 * irq will be enabled in ->smp_finish(), enabling it too early
@@ -242,22 +254,23 @@
 {
 	set_cpu_possible(0, true);
 	set_cpu_online(0, true);
-	cpumask_set_cpu(0, &cpu_callin_map);
 }
 
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
 	mp_ops->boot_secondary(cpu, tidle);
 
-	/*
-	 * Trust is futile.  We should really have timeouts ...
-	 */
-	while (!cpumask_test_cpu(cpu, &cpu_callin_map)) {
-		udelay(100);
-		schedule();
+	/* Wait for CPU to start and be ready to sync counters */
+	if (!wait_for_completion_timeout(&cpu_starting,
+					 msecs_to_jiffies(1000))) {
+		pr_crit("CPU%u: failed to start\n", cpu);
+		return -EIO;
 	}
 
 	synchronise_count_master(cpu);
+
+	/* Wait for CPU to finish startup & mark itself online before return */
+	wait_for_completion(&cpu_running);
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/mips/kernel/syscall.c
+++ linux-4.4.0/arch/mips/kernel/syscall.c
@@ -28,6 +28,7 @@
 #include <linux/elf.h>
 
 #include <asm/asm.h>
+#include <asm/asm-eva.h>
 #include <asm/branch.h>
 #include <asm/cachectl.h>
 #include <asm/cacheflush.h>
@@ -138,10 +139,12 @@
 		__asm__ __volatile__ (
 		"	.set	"MIPS_ISA_ARCH_LEVEL"			\n"
 		"	li	%[err], 0				\n"
-		"1:	ll	%[old], (%[addr])			\n"
+		"1:							\n"
+		user_ll("%[old]", "(%[addr])")
 		"	move	%[tmp], %[new]				\n"
-		"2:	sc	%[tmp], (%[addr])			\n"
-		"	bnez	%[tmp], 4f				\n"
+		"2:							\n"
+		user_sc("%[tmp]", "(%[addr])")
+		"	beqz	%[tmp], 4f				\n"
 		"3:							\n"
 		"	.insn						\n"
 		"	.subsection 2					\n"
@@ -199,6 +202,12 @@
 	unreachable();
 }
 
+/*
+ * mips_atomic_set() normally returns directly via syscall_exit potentially
+ * clobbering static registers, so be sure to preserve them.
+ */
+save_static_function(sys_sysmips);
+
 SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2)
 {
 	switch (cmd) {
--- linux-4.4.0.orig/arch/mips/kernel/time.c
+++ linux-4.4.0/arch/mips/kernel/time.c
@@ -22,12 +22,77 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/export.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
 
 #include <asm/cpu-features.h>
 #include <asm/cpu-type.h>
 #include <asm/div64.h>
 #include <asm/time.h>
 
+#ifdef CONFIG_CPU_FREQ
+
+static DEFINE_PER_CPU(unsigned long, pcp_lpj_ref);
+static DEFINE_PER_CPU(unsigned long, pcp_lpj_ref_freq);
+static unsigned long glb_lpj_ref;
+static unsigned long glb_lpj_ref_freq;
+
+static int cpufreq_callback(struct notifier_block *nb,
+			    unsigned long val, void *data)
+{
+	int cpu;
+	struct cpufreq_freqs *freq = data;
+
+	/*
+	 * Skip lpj numbers adjustment if the CPU-freq transition is safe for
+	 * the loops delay. (Is this possible?)
+	 */
+	if (freq->flags & CPUFREQ_CONST_LOOPS)
+		return NOTIFY_OK;
+
+	/* Save the initial values of the lpjes for future scaling. */
+	if (!glb_lpj_ref) {
+		glb_lpj_ref = boot_cpu_data.udelay_val;
+		glb_lpj_ref_freq = freq->old;
+
+		for_each_online_cpu(cpu) {
+			per_cpu(pcp_lpj_ref, cpu) =
+				cpu_data[cpu].udelay_val;
+			per_cpu(pcp_lpj_ref_freq, cpu) = freq->old;
+		}
+	}
+
+	cpu = freq->cpu;
+	/*
+	 * Adjust global lpj variable and per-CPU udelay_val number in
+	 * accordance with the new CPU frequency.
+	 */
+	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
+		loops_per_jiffy = cpufreq_scale(glb_lpj_ref,
+						glb_lpj_ref_freq,
+						freq->new);
+
+		cpu_data[cpu].udelay_val = cpufreq_scale(per_cpu(pcp_lpj_ref, cpu),
+					   per_cpu(pcp_lpj_ref_freq, cpu), freq->new);
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpufreq_notifier = {
+	.notifier_call  = cpufreq_callback,
+};
+
+static int __init register_cpufreq_notifier(void)
+{
+	return cpufreq_register_notifier(&cpufreq_notifier,
+					 CPUFREQ_TRANSITION_NOTIFIER);
+}
+core_initcall(register_cpufreq_notifier);
+
+#endif /* CONFIG_CPU_FREQ */
+
 /*
  * forward reference
  */
--- linux-4.4.0.orig/arch/mips/kernel/topology.c
+++ linux-4.4.0/arch/mips/kernel/topology.c
@@ -19,7 +19,7 @@
 	for_each_present_cpu(i) {
 		struct cpu *c = &per_cpu(cpu_devices, i);
 
-		c->hotpluggable = 1;
+		c->hotpluggable = !!i;
 		ret = register_cpu(c, i);
 		if (ret)
 			printk(KERN_WARNING "topology_init: register_cpu %d "
--- linux-4.4.0.orig/arch/mips/kernel/traps.c
+++ linux-4.4.0/arch/mips/kernel/traps.c
@@ -144,7 +144,7 @@
 	if (!task)
 		task = current;
 
-	if (raw_show_trace || !__kernel_text_address(pc)) {
+	if (raw_show_trace || user_mode(regs) || !__kernel_text_address(pc)) {
 		show_raw_backtrace(sp);
 		return;
 	}
@@ -194,6 +194,8 @@
 {
 	struct pt_regs regs;
 	mm_segment_t old_fs = get_fs();
+
+	regs.cp0_status = KSU_KERNEL;
 	if (sp) {
 		regs.regs[29] = (unsigned long)sp;
 		regs.regs[31] = 0;
@@ -342,6 +344,7 @@
 void show_regs(struct pt_regs *regs)
 {
 	__show_regs((struct pt_regs *)regs);
+	dump_stack();
 }
 
 void show_registers(struct pt_regs *regs)
@@ -690,19 +693,45 @@
 asmlinkage void do_ov(struct pt_regs *regs)
 {
 	enum ctx_state prev_state;
-	siginfo_t info;
+	siginfo_t info = {
+		.si_signo = SIGFPE,
+		.si_code = FPE_INTOVF,
+		.si_addr = (void __user *)regs->cp0_epc,
+	};
 
 	prev_state = exception_enter();
 	die_if_kernel("Integer overflow", regs);
 
-	info.si_code = FPE_INTOVF;
-	info.si_signo = SIGFPE;
-	info.si_errno = 0;
-	info.si_addr = (void __user *) regs->cp0_epc;
 	force_sig_info(SIGFPE, &info, current);
 	exception_exit(prev_state);
 }
 
+/*
+ * Send SIGFPE according to FCSR Cause bits, which must have already
+ * been masked against Enable bits.  This is impotant as Inexact can
+ * happen together with Overflow or Underflow, and `ptrace' can set
+ * any bits.
+ */
+void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
+		     struct task_struct *tsk)
+{
+	struct siginfo si = { .si_addr = fault_addr, .si_signo = SIGFPE };
+
+	if (fcr31 & FPU_CSR_INV_X)
+		si.si_code = FPE_FLTINV;
+	else if (fcr31 & FPU_CSR_DIV_X)
+		si.si_code = FPE_FLTDIV;
+	else if (fcr31 & FPU_CSR_OVF_X)
+		si.si_code = FPE_FLTOVF;
+	else if (fcr31 & FPU_CSR_UDF_X)
+		si.si_code = FPE_FLTUND;
+	else if (fcr31 & FPU_CSR_INE_X)
+		si.si_code = FPE_FLTRES;
+	else
+		si.si_code = __SI_FAULT;
+	force_sig_info(SIGFPE, &si, tsk);
+}
+
 int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
 {
 	struct siginfo si = { 0 };
@@ -712,27 +741,7 @@
 		return 0;
 
 	case SIGFPE:
-		si.si_addr = fault_addr;
-		si.si_signo = sig;
-		/*
-		 * Inexact can happen together with Overflow or Underflow.
-		 * Respect the mask to deliver the correct exception.
-		 */
-		fcr31 &= (fcr31 & FPU_CSR_ALL_E) <<
-			 (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E));
-		if (fcr31 & FPU_CSR_INV_X)
-			si.si_code = FPE_FLTINV;
-		else if (fcr31 & FPU_CSR_DIV_X)
-			si.si_code = FPE_FLTDIV;
-		else if (fcr31 & FPU_CSR_OVF_X)
-			si.si_code = FPE_FLTOVF;
-		else if (fcr31 & FPU_CSR_UDF_X)
-			si.si_code = FPE_FLTUND;
-		else if (fcr31 & FPU_CSR_INE_X)
-			si.si_code = FPE_FLTRES;
-		else
-			si.si_code = __SI_FAULT;
-		force_sig_info(sig, &si, current);
+		force_fcr31_sig(fcr31, fault_addr, current);
 		return 1;
 
 	case SIGBUS:
@@ -795,13 +804,13 @@
 	/* Run the emulator */
 	sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
 				       &fault_addr);
-	fcr31 = current->thread.fpu.fcr31;
 
 	/*
-	 * We can't allow the emulated instruction to leave any of
-	 * the cause bits set in $fcr31.
+	 * We can't allow the emulated instruction to leave any
+	 * enabled Cause bits set in $fcr31.
 	 */
-	current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+	fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+	current->thread.fpu.fcr31 &= ~fcr31;
 
 	/* Restore the hardware register state */
 	own_fpu(1);
@@ -827,7 +836,7 @@
 		goto out;
 
 	/* Clear FCSR.Cause before enabling interrupts */
-	write_32bit_cp1_register(CP1_STATUS, fcr31 & ~FPU_CSR_ALL_X);
+	write_32bit_cp1_register(CP1_STATUS, fcr31 & ~mask_fcr31_x(fcr31));
 	local_irq_enable();
 
 	die_if_kernel("FP exception in kernel code", regs);
@@ -849,13 +858,13 @@
 		/* Run the emulator */
 		sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
 					       &fault_addr);
-		fcr31 = current->thread.fpu.fcr31;
 
 		/*
-		 * We can't allow the emulated instruction to leave any of
-		 * the cause bits set in $fcr31.
+		 * We can't allow the emulated instruction to leave any
+		 * enabled Cause bits set in $fcr31.
 		 */
-		current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+		fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+		current->thread.fpu.fcr31 &= ~fcr31;
 
 		/* Restore the hardware register state */
 		own_fpu(1);	/* Using the FPU again.	 */
@@ -874,7 +883,7 @@
 void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
 	const char *str)
 {
-	siginfo_t info;
+	siginfo_t info = { 0 };
 	char b[40];
 
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
@@ -903,7 +912,6 @@
 		else
 			info.si_code = FPE_INTOVF;
 		info.si_signo = SIGFPE;
-		info.si_errno = 0;
 		info.si_addr = (void __user *) regs->cp0_epc;
 		force_sig_info(SIGFPE, &info, current);
 		break;
@@ -1242,7 +1250,7 @@
 		err = init_fpu();
 		if (msa && !err) {
 			enable_msa();
-			_init_msa_upper();
+			init_msa_upper();
 			set_thread_flag(TIF_USEDMSA);
 			set_thread_flag(TIF_MSA_CTX_LIVE);
 		}
@@ -1305,7 +1313,7 @@
 	 */
 	prior_msa = test_and_set_thread_flag(TIF_MSA_CTX_LIVE);
 	if (!prior_msa && was_fpu_owner) {
-		_init_msa_upper();
+		init_msa_upper();
 
 		goto out;
 	}
@@ -1322,7 +1330,7 @@
 		 * of each vector register such that it cannot see data left
 		 * behind by another task.
 		 */
-		_init_msa_upper();
+		init_msa_upper();
 	} else {
 		/* We need to restore the vector context. */
 		restore_msa(current);
@@ -1429,13 +1437,13 @@
 
 		sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
 					       &fault_addr);
-		fcr31 = current->thread.fpu.fcr31;
 
 		/*
 		 * We can't allow the emulated instruction to leave
-		 * any of the cause bits set in $fcr31.
+		 * any enabled Cause bits set in $fcr31.
 		 */
-		current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+		fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+		current->thread.fpu.fcr31 &= ~fcr31;
 
 		/* Send a signal if required.  */
 		if (!process_fpemu_return(sig, fault_addr, fcr31) && !err)
@@ -2072,6 +2080,7 @@
 
 	change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
 			 status_set);
+	back_to_back_c0_hazard();
 }
 
 /* configure HWRENA register */
--- linux-4.4.0.orig/arch/mips/kernel/unaligned.c
+++ linux-4.4.0/arch/mips/kernel/unaligned.c
@@ -885,7 +885,7 @@
 {
 	union mips_instruction insn;
 	unsigned long value;
-	unsigned int res;
+	unsigned int res, preempted;
 	unsigned long origpc;
 	unsigned long orig31;
 	void __user *fault_addr = NULL;
@@ -1226,27 +1226,36 @@
 			if (!access_ok(VERIFY_READ, addr, sizeof(*fpr)))
 				goto sigbus;
 
-			/*
-			 * Disable preemption to avoid a race between copying
-			 * state from userland, migrating to another CPU and
-			 * updating the hardware vector register below.
-			 */
-			preempt_disable();
-
-			res = __copy_from_user_inatomic(fpr, addr,
-							sizeof(*fpr));
-			if (res)
-				goto fault;
-
-			/*
-			 * Update the hardware register if it is in use by the
-			 * task in this quantum, in order to avoid having to
-			 * save & restore the whole vector context.
-			 */
-			if (test_thread_flag(TIF_USEDMSA))
-				write_msa_wr(wd, fpr, df);
-
-			preempt_enable();
+			do {
+				/*
+				 * If we have live MSA context keep track of
+				 * whether we get preempted in order to avoid
+				 * the register context we load being clobbered
+				 * by the live context as it's saved during
+				 * preemption. If we don't have live context
+				 * then it can't be saved to clobber the value
+				 * we load.
+				 */
+				preempted = test_thread_flag(TIF_USEDMSA);
+
+				res = __copy_from_user_inatomic(fpr, addr,
+								sizeof(*fpr));
+				if (res)
+					goto fault;
+
+				/*
+				 * Update the hardware register if it is in use
+				 * by the task in this quantum, in order to
+				 * avoid having to save & restore the whole
+				 * vector context.
+				 */
+				preempt_disable();
+				if (test_thread_flag(TIF_USEDMSA)) {
+					write_msa_wr(wd, fpr, df);
+					preempted = 0;
+				}
+				preempt_enable();
+			} while (preempted);
 			break;
 
 		case msa_st_op:
--- linux-4.4.0.orig/arch/mips/kernel/uprobes.c
+++ linux-4.4.0/arch/mips/kernel/uprobes.c
@@ -157,7 +157,6 @@
 int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs)
 {
 	struct uprobe_task *utask = current->utask;
-	union mips_instruction insn;
 
 	/*
 	 * Now find the EPC where to resume after the breakpoint has been
@@ -165,13 +164,10 @@
 	 */
 	aup->resume_epc = regs->cp0_epc + 4;
 	if (insn_has_delay_slot((union mips_instruction) aup->insn[0])) {
-		unsigned long epc;
-
-		epc = regs->cp0_epc;
-		__compute_return_epc_for_insn(regs, insn);
+		__compute_return_epc_for_insn(regs,
+			(union mips_instruction) aup->insn[0]);
 		aup->resume_epc = regs->cp0_epc;
 	}
-
 	utask->autask.saved_trap_nr = current->thread.trap_nr;
 	current->thread.trap_nr = UPROBE_TRAP_NR;
 	regs->cp0_epc = current->utask->xol_vaddr;
@@ -257,7 +253,7 @@
 	ra = regs->regs[31];
 
 	/* Replace the return address with the trampoline address */
-	regs->regs[31] = ra;
+	regs->regs[31] = trampoline_vaddr;
 
 	return ra;
 }
@@ -280,24 +276,6 @@
 	return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN);
 }
 
-/**
- * set_orig_insn - Restore the original instruction.
- * @mm: the probed process address space.
- * @auprobe: arch specific probepoint information.
- * @vaddr: the virtual address to insert the opcode.
- *
- * For mm @mm, restore the original opcode (opcode) at @vaddr.
- * Return 0 (success) or a negative errno.
- *
- * This overrides the weak version in kernel/events/uprobes.c.
- */
-int set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
-		 unsigned long vaddr)
-{
-	return uprobe_write_opcode(mm, vaddr,
-			*(uprobe_opcode_t *)&auprobe->orig_inst[0].word);
-}
-
 void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
 				  void *src, unsigned long len)
 {
--- linux-4.4.0.orig/arch/mips/kernel/vdso.c
+++ linux-4.4.0/arch/mips/kernel/vdso.c
@@ -14,12 +14,14 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/irqchip/mips-gic.h>
+#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/timekeeper_internal.h>
 
 #include <asm/abi.h>
+#include <asm/page.h>
 #include <asm/vdso.h>
 
 /* Kernel-provided data used by the VDSO. */
@@ -39,16 +41,16 @@
 static void __init init_vdso_image(struct mips_vdso_image *image)
 {
 	unsigned long num_pages, i;
+	unsigned long data_pfn;
 
 	BUG_ON(!PAGE_ALIGNED(image->data));
 	BUG_ON(!PAGE_ALIGNED(image->size));
 
 	num_pages = image->size / PAGE_SIZE;
 
-	for (i = 0; i < num_pages; i++) {
-		image->mapping.pages[i] =
-			virt_to_page(image->data + (i * PAGE_SIZE));
-	}
+	data_pfn = __phys_to_pfn(__pa_symbol(image->data));
+	for (i = 0; i < num_pages; i++)
+		image->mapping.pages[i] = pfn_to_page(data_pfn + i);
 }
 
 static int __init init_vdso(void)
@@ -118,12 +120,30 @@
 	vvar_size = gic_size + PAGE_SIZE;
 	size = vvar_size + image->size;
 
+	/*
+	 * Find a region that's large enough for us to perform the
+	 * colour-matching alignment below.
+	 */
+	if (cpu_has_dc_aliases)
+		size += shm_align_mask + 1;
+
 	base = get_unmapped_area(NULL, 0, size, 0, 0);
 	if (IS_ERR_VALUE(base)) {
 		ret = base;
 		goto out;
 	}
 
+	/*
+	 * If we suffer from dcache aliasing, ensure that the VDSO data page
+	 * mapping is coloured the same as the kernel's mapping of that memory.
+	 * This ensures that when the kernel updates the VDSO data userland
+	 * will observe it without requiring cache invalidations.
+	 */
+	if (cpu_has_dc_aliases) {
+		base = __ALIGN_MASK(base, shm_align_mask);
+		base += ((unsigned long)&vdso_data - gic_size) & shm_align_mask;
+	}
+
 	data_addr = base + gic_size;
 	vdso_addr = data_addr + PAGE_SIZE;
 
--- linux-4.4.0.orig/arch/mips/kernel/vmlinux.lds.S
+++ linux-4.4.0/arch/mips/kernel/vmlinux.lds.S
@@ -90,6 +90,7 @@
 
 		INIT_TASK_DATA(THREAD_SIZE)
 		NOSAVE_DATA
+		PAGE_ALIGNED_DATA(PAGE_SIZE)
 		CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
 		READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
 		DATA_DATA
@@ -159,7 +160,7 @@
 	 * Force .bss to 64K alignment so that .bss..swapper_pg_dir
 	 * gets that alignment.	 .sbss should be empty, so there will be
 	 * no holes after __init_end. */
-	BSS_SECTION(0, 0x10000, 0)
+	BSS_SECTION(0, 0x10000, 8)
 
 	_end = . ;
 
--- linux-4.4.0.orig/arch/mips/kernel/vpe.c
+++ linux-4.4.0/arch/mips/kernel/vpe.c
@@ -134,7 +134,7 @@
 {
 	list_del(&v->list);
 	if (v->load_addr)
-		release_progmem(v);
+		release_progmem(v->load_addr);
 	kfree(v);
 }
 
@@ -205,11 +205,11 @@
 			    || s->sh_entsize != ~0UL)
 				continue;
 			s->sh_entsize =
-				get_offset((unsigned long *)&mod->core_size, s);
+				get_offset((unsigned long *)&mod->core_layout.size, s);
 		}
 
 		if (m == 0)
-			mod->core_text_size = mod->core_size;
+			mod->core_layout.text_size = mod->core_layout.size;
 
 	}
 }
@@ -641,7 +641,7 @@
 		layout_sections(&mod, hdr, sechdrs, secstrings);
 	}
 
-	v->load_addr = alloc_progmem(mod.core_size);
+	v->load_addr = alloc_progmem(mod.core_layout.size);
 	if (!v->load_addr)
 		return -ENOMEM;
 
--- linux-4.4.0.orig/arch/mips/kernel/watch.c
+++ linux-4.4.0/arch/mips/kernel/watch.c
@@ -15,10 +15,9 @@
  * Install the watch registers for the current thread.	A maximum of
  * four registers are installed although the machine may have more.
  */
-void mips_install_watch_registers(void)
+void mips_install_watch_registers(struct task_struct *t)
 {
-	struct mips3264_watch_reg_state *watches =
-		&current->thread.watch.mips3264;
+	struct mips3264_watch_reg_state *watches = &t->thread.watch.mips3264;
 	switch (current_cpu_data.watch_reg_use_cnt) {
 	default:
 		BUG();
--- linux-4.4.0.orig/arch/mips/kvm/dyntrans.c
+++ linux-4.4.0/arch/mips/kvm/dyntrans.c
@@ -82,7 +82,7 @@
 
 	if ((rd == MIPS_CP0_ERRCTL) && (sel == 0)) {
 		mfc0_inst = CLEAR_TEMPLATE;
-		mfc0_inst |= ((rt & 0x1f) << 16);
+		mfc0_inst |= ((rt & 0x1f) << 11);
 	} else {
 		mfc0_inst = LW_TEMPLATE;
 		mfc0_inst |= ((rt & 0x1f) << 16);
--- linux-4.4.0.orig/arch/mips/kvm/emulate.c
+++ linux-4.4.0/arch/mips/kvm/emulate.c
@@ -302,12 +302,31 @@
  */
 static uint32_t kvm_mips_read_count_running(struct kvm_vcpu *vcpu, ktime_t now)
 {
-	ktime_t expires;
+	struct mips_coproc *cop0 = vcpu->arch.cop0;
+	ktime_t expires, threshold;
+	uint32_t count, compare;
 	int running;
 
-	/* Is the hrtimer pending? */
+	/* Calculate the biased and scaled guest CP0_Count */
+	count = vcpu->arch.count_bias + kvm_mips_ktime_to_count(vcpu, now);
+	compare = kvm_read_c0_guest_compare(cop0);
+
+	/*
+	 * Find whether CP0_Count has reached the closest timer interrupt. If
+	 * not, we shouldn't inject it.
+	 */
+	if ((int32_t)(count - compare) < 0)
+		return count;
+
+	/*
+	 * The CP0_Count we're going to return has already reached the closest
+	 * timer interrupt. Quickly check if it really is a new interrupt by
+	 * looking at whether the interval until the hrtimer expiry time is
+	 * less than 1/4 of the timer period.
+	 */
 	expires = hrtimer_get_expires(&vcpu->arch.comparecount_timer);
-	if (ktime_compare(now, expires) >= 0) {
+	threshold = ktime_add_ns(now, vcpu->arch.count_period / 4);
+	if (ktime_before(expires, threshold)) {
 		/*
 		 * Cancel it while we handle it so there's no chance of
 		 * interference with the timeout handler.
@@ -329,8 +348,7 @@
 		}
 	}
 
-	/* Return the biased and scaled guest CP0_Count */
-	return vcpu->arch.count_bias + kvm_mips_ktime_to_count(vcpu, now);
+	return count;
 }
 
 /**
@@ -420,32 +438,6 @@
 }
 
 /**
- * kvm_mips_update_hrtimer() - Update next expiry time of hrtimer.
- * @vcpu:	Virtual CPU.
- *
- * Recalculates and updates the expiry time of the hrtimer. This can be used
- * after timer parameters have been altered which do not depend on the time that
- * the change occurs (in those cases kvm_mips_freeze_hrtimer() and
- * kvm_mips_resume_hrtimer() are used directly).
- *
- * It is guaranteed that no timer interrupts will be lost in the process.
- *
- * Assumes !kvm_mips_count_disabled(@vcpu) (guest CP0_Count timer is running).
- */
-static void kvm_mips_update_hrtimer(struct kvm_vcpu *vcpu)
-{
-	ktime_t now;
-	uint32_t count;
-
-	/*
-	 * freeze_hrtimer takes care of a timer interrupts <= count, and
-	 * resume_hrtimer the hrtimer takes care of a timer interrupts > count.
-	 */
-	now = kvm_mips_freeze_hrtimer(vcpu, &count);
-	kvm_mips_resume_hrtimer(vcpu, now, count);
-}
-
-/**
  * kvm_mips_write_count() - Modify the count and update timer.
  * @vcpu:	Virtual CPU.
  * @count:	Guest CP0_Count value to set.
@@ -540,23 +532,42 @@
  * kvm_mips_write_compare() - Modify compare and update timer.
  * @vcpu:	Virtual CPU.
  * @compare:	New CP0_Compare value.
+ * @ack:	Whether to acknowledge timer interrupt.
  *
  * Update CP0_Compare to a new value and update the timeout.
+ * If @ack, atomically acknowledge any pending timer interrupt, otherwise ensure
+ * any pending timer interrupt is preserved.
  */
-void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare)
+void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare, bool ack)
 {
 	struct mips_coproc *cop0 = vcpu->arch.cop0;
+	int dc;
+	u32 old_compare = kvm_read_c0_guest_compare(cop0);
+	ktime_t now;
+	uint32_t count;
 
 	/* if unchanged, must just be an ack */
-	if (kvm_read_c0_guest_compare(cop0) == compare)
+	if (old_compare == compare) {
+		if (!ack)
+			return;
+		kvm_mips_callbacks->dequeue_timer_int(vcpu);
+		kvm_write_c0_guest_compare(cop0, compare);
 		return;
+	}
+
+	/* freeze_hrtimer() takes care of timer interrupts <= count */
+	dc = kvm_mips_count_disabled(vcpu);
+	if (!dc)
+		now = kvm_mips_freeze_hrtimer(vcpu, &count);
+
+	if (ack)
+		kvm_mips_callbacks->dequeue_timer_int(vcpu);
 
-	/* Update compare */
 	kvm_write_c0_guest_compare(cop0, compare);
 
-	/* Update timeout if count enabled */
-	if (!kvm_mips_count_disabled(vcpu))
-		kvm_mips_update_hrtimer(vcpu);
+	/* resume_hrtimer() takes care of timer interrupts > count */
+	if (!dc)
+		kvm_mips_resume_hrtimer(vcpu, now, count);
 }
 
 /**
@@ -741,15 +752,15 @@
 	struct mips_coproc *cop0 = vcpu->arch.cop0;
 	enum emulation_result er = EMULATE_DONE;
 
-	if (kvm_read_c0_guest_status(cop0) & ST0_EXL) {
+	if (kvm_read_c0_guest_status(cop0) & ST0_ERL) {
+		kvm_clear_c0_guest_status(cop0, ST0_ERL);
+		vcpu->arch.pc = kvm_read_c0_guest_errorepc(cop0);
+	} else if (kvm_read_c0_guest_status(cop0) & ST0_EXL) {
 		kvm_debug("[%#lx] ERET to %#lx\n", vcpu->arch.pc,
 			  kvm_read_c0_guest_epc(cop0));
 		kvm_clear_c0_guest_status(cop0, ST0_EXL);
 		vcpu->arch.pc = kvm_read_c0_guest_epc(cop0);
 
-	} else if (kvm_read_c0_guest_status(cop0) & ST0_ERL) {
-		kvm_clear_c0_guest_status(cop0, ST0_ERL);
-		vcpu->arch.pc = kvm_read_c0_guest_errorepc(cop0);
 	} else {
 		kvm_err("[%#lx] ERET when MIPS_SR_EXL|MIPS_SR_ERL == 0\n",
 			vcpu->arch.pc);
@@ -796,6 +807,47 @@
 	return EMULATE_FAIL;
 }
 
+/**
+ * kvm_mips_invalidate_guest_tlb() - Indicates a change in guest MMU map.
+ * @vcpu:	VCPU with changed mappings.
+ * @tlb:	TLB entry being removed.
+ *
+ * This is called to indicate a single change in guest MMU mappings, so that we
+ * can arrange TLB flushes on this and other CPUs.
+ */
+static void kvm_mips_invalidate_guest_tlb(struct kvm_vcpu *vcpu,
+					  struct kvm_mips_tlb *tlb)
+{
+	int cpu, i;
+	bool user;
+
+	/* No need to flush for entries which are already invalid */
+	if (!((tlb->tlb_lo0 | tlb->tlb_lo1) & MIPS3_PG_V))
+		return;
+	/* User address space doesn't need flushing for KSeg2/3 changes */
+	user = tlb->tlb_hi < KVM_GUEST_KSEG0;
+
+	preempt_disable();
+
+	/*
+	 * Probe the shadow host TLB for the entry being overwritten, if one
+	 * matches, invalidate it
+	 */
+	kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
+
+	/* Invalidate the whole ASID on other CPUs */
+	cpu = smp_processor_id();
+	for_each_possible_cpu(i) {
+		if (i == cpu)
+			continue;
+		if (user)
+			vcpu->arch.guest_user_asid[i] = 0;
+		vcpu->arch.guest_kernel_asid[i] = 0;
+	}
+
+	preempt_enable();
+}
+
 /* Write Guest TLB Entry @ Index */
 enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu)
 {
@@ -815,11 +867,8 @@
 	}
 
 	tlb = &vcpu->arch.guest_tlb[index];
-	/*
-	 * Probe the shadow host TLB for the entry being overwritten, if one
-	 * matches, invalidate it
-	 */
-	kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
+
+	kvm_mips_invalidate_guest_tlb(vcpu, tlb);
 
 	tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0);
 	tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0);
@@ -848,11 +897,7 @@
 
 	tlb = &vcpu->arch.guest_tlb[index];
 
-	/*
-	 * Probe the shadow host TLB for the entry being overwritten, if one
-	 * matches, invalidate it
-	 */
-	kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
+	kvm_mips_invalidate_guest_tlb(vcpu, tlb);
 
 	tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0);
 	tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0);
@@ -971,6 +1016,7 @@
 	int32_t rt, rd, copz, sel, co_bit, op;
 	uint32_t pc = vcpu->arch.pc;
 	unsigned long curr_pc;
+	int cpu, i;
 
 	/*
 	 * Update PC and hold onto current PC in case there is
@@ -1078,8 +1124,16 @@
 						vcpu->arch.gprs[rt]
 						& ASID_MASK);
 
+					preempt_disable();
 					/* Blow away the shadow host TLBs */
 					kvm_mips_flush_host_tlb(1);
+					cpu = smp_processor_id();
+					for_each_possible_cpu(i)
+						if (i != cpu) {
+							vcpu->arch.guest_user_asid[i] = 0;
+							vcpu->arch.guest_kernel_asid[i] = 0;
+						}
+					preempt_enable();
 				}
 				kvm_write_c0_guest_entryhi(cop0,
 							   vcpu->arch.gprs[rt]);
@@ -1095,9 +1149,9 @@
 
 				/* If we are writing to COMPARE */
 				/* Clear pending timer interrupt, if any */
-				kvm_mips_callbacks->dequeue_timer_int(vcpu);
 				kvm_mips_write_compare(vcpu,
-						       vcpu->arch.gprs[rt]);
+						       vcpu->arch.gprs[rt],
+						       true);
 			} else if ((rd == MIPS_CP0_STATUS) && (sel == 0)) {
 				unsigned int old_val, val, change;
 
@@ -1419,6 +1473,7 @@
 					    struct kvm_vcpu *vcpu)
 {
 	enum emulation_result er = EMULATE_DO_MMIO;
+	unsigned long curr_pc;
 	int32_t op, base, rt, offset;
 	uint32_t bytes;
 
@@ -1427,7 +1482,18 @@
 	offset = inst & 0xffff;
 	op = (inst >> 26) & 0x3f;
 
-	vcpu->arch.pending_load_cause = cause;
+	/*
+	 * Find the resume PC now while we have safe and easy access to the
+	 * prior branch instruction, and save it for
+	 * kvm_mips_complete_mmio_load() to restore later.
+	 */
+	curr_pc = vcpu->arch.pc;
+	er = update_pc(vcpu, cause);
+	if (er == EMULATE_FAIL)
+		return er;
+	vcpu->arch.io_pc = vcpu->arch.pc;
+	vcpu->arch.pc = curr_pc;
+
 	vcpu->arch.io_gpr = rt;
 
 	switch (op) {
@@ -1618,8 +1684,14 @@
 
 	preempt_disable();
 	if (KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG0) {
-		if (kvm_mips_host_tlb_lookup(vcpu, va) < 0)
-			kvm_mips_handle_kseg0_tlb_fault(va, vcpu);
+		if (kvm_mips_host_tlb_lookup(vcpu, va) < 0 &&
+		    kvm_mips_handle_kseg0_tlb_fault(va, vcpu)) {
+			kvm_err("%s: handling mapped kseg0 tlb fault for %lx, vcpu: %p, ASID: %#lx\n",
+				__func__, va, vcpu, read_c0_entryhi());
+			er = EMULATE_FAIL;
+			preempt_enable();
+			goto done;
+		}
 	} else if ((KVM_GUEST_KSEGX(va) < KVM_GUEST_KSEG0) ||
 		   KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG23) {
 		int index;
@@ -1654,14 +1726,19 @@
 								run, vcpu);
 				preempt_enable();
 				goto dont_update_pc;
-			} else {
-				/*
-				 * We fault an entry from the guest tlb to the
-				 * shadow host TLB
-				 */
-				kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb,
-								     NULL,
-								     NULL);
+			}
+			/*
+			 * We fault an entry from the guest tlb to the
+			 * shadow host TLB
+			 */
+			if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb,
+								 NULL, NULL)) {
+				kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n",
+					__func__, va, index, vcpu,
+					read_c0_entryhi());
+				er = EMULATE_FAIL;
+				preempt_enable();
+				goto done;
 			}
 		}
 	} else {
@@ -2396,9 +2473,8 @@
 		goto done;
 	}
 
-	er = update_pc(vcpu, vcpu->arch.pending_load_cause);
-	if (er == EMULATE_FAIL)
-		return er;
+	/* Restore saved resume PC */
+	vcpu->arch.pc = vcpu->arch.io_pc;
 
 	switch (run->mmio.len) {
 	case 4:
@@ -2420,11 +2496,6 @@
 		break;
 	}
 
-	if (vcpu->arch.pending_load_cause & CAUSEF_BD)
-		kvm_debug("[%#lx] Completing %d byte BD Load to gpr %d (0x%08lx) type %d\n",
-			  vcpu->arch.pc, run->mmio.len, vcpu->arch.io_gpr, *gpr,
-			  vcpu->mmio_needed);
-
 done:
 	return er;
 }
@@ -2622,8 +2693,13 @@
 			 * OK we have a Guest TLB entry, now inject it into the
 			 * shadow host TLB
 			 */
-			kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb, NULL,
-							     NULL);
+			if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb,
+								 NULL, NULL)) {
+				kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n",
+					__func__, va, index, vcpu,
+					read_c0_entryhi());
+				er = EMULATE_FAIL;
+			}
 		}
 	}
 
--- linux-4.4.0.orig/arch/mips/kvm/interrupt.h
+++ linux-4.4.0/arch/mips/kvm/interrupt.h
@@ -28,6 +28,7 @@
 #define MIPS_EXC_MAX                12
 /* XXXSL More to follow */
 
+extern char __kvm_mips_vcpu_run_end[];
 extern char mips32_exception[], mips32_exceptionEnd[];
 extern char mips32_GuestException[], mips32_GuestExceptionEnd[];
 
--- linux-4.4.0.orig/arch/mips/kvm/locore.S
+++ linux-4.4.0/arch/mips/kvm/locore.S
@@ -227,6 +227,7 @@
 
 	/* Jump to guest */
 	eret
+EXPORT(__kvm_mips_vcpu_run_end)
 
 VECTOR(MIPSX(exception), unknown)
 /* Find out what mode we came from and jump to the proper handler. */
--- linux-4.4.0.orig/arch/mips/kvm/mips.c
+++ linux-4.4.0/arch/mips/kvm/mips.c
@@ -40,7 +40,7 @@
 	{ "cache",	  VCPU_STAT(cache_exits),	 KVM_STAT_VCPU },
 	{ "signal",	  VCPU_STAT(signal_exits),	 KVM_STAT_VCPU },
 	{ "interrupt",	  VCPU_STAT(int_exits),		 KVM_STAT_VCPU },
-	{ "cop_unsuable", VCPU_STAT(cop_unusable_exits), KVM_STAT_VCPU },
+	{ "cop_unusable", VCPU_STAT(cop_unusable_exits), KVM_STAT_VCPU },
 	{ "tlbmod",	  VCPU_STAT(tlbmod_exits),	 KVM_STAT_VCPU },
 	{ "tlbmiss_ld",	  VCPU_STAT(tlbmiss_ld_exits),	 KVM_STAT_VCPU },
 	{ "tlbmiss_st",	  VCPU_STAT(tlbmiss_st_exits),	 KVM_STAT_VCPU },
@@ -314,9 +314,18 @@
 	memcpy(gebase + offset, mips32_GuestException,
 	       mips32_GuestExceptionEnd - mips32_GuestException);
 
+#ifdef MODULE
+	offset += mips32_GuestExceptionEnd - mips32_GuestException;
+	memcpy(gebase + offset, (char *)__kvm_mips_vcpu_run,
+	       __kvm_mips_vcpu_run_end - (char *)__kvm_mips_vcpu_run);
+	vcpu->arch.vcpu_run = gebase + offset;
+#else
+	vcpu->arch.vcpu_run = __kvm_mips_vcpu_run;
+#endif
+
 	/* Invalidate the icache for these ranges */
-	local_flush_icache_range((unsigned long)gebase,
-				(unsigned long)gebase + ALIGN(size, PAGE_SIZE));
+	flush_icache_range((unsigned long)gebase,
+			   (unsigned long)gebase + ALIGN(size, PAGE_SIZE));
 
 	/*
 	 * Allocate comm page for guest kernel, a TLB will be reserved for
@@ -403,7 +412,7 @@
 	/* Disable hardware page table walking while in guest */
 	htw_stop();
 
-	r = __kvm_mips_vcpu_run(run, vcpu);
+	r = vcpu->arch.vcpu_run(run, vcpu);
 
 	/* Re-enable HTW before enabling interrupts */
 	htw_start();
@@ -702,7 +711,7 @@
 	} else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) {
 		void __user *uaddr = (void __user *)(long)reg->addr;
 
-		return copy_to_user(uaddr, vs, 16);
+		return copy_to_user(uaddr, vs, 16) ? -EFAULT : 0;
 	} else {
 		return -EINVAL;
 	}
@@ -732,7 +741,7 @@
 	} else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) {
 		void __user *uaddr = (void __user *)(long)reg->addr;
 
-		return copy_from_user(vs, uaddr, 16);
+		return copy_from_user(vs, uaddr, 16) ? -EFAULT : 0;
 	} else {
 		return -EINVAL;
 	}
--- linux-4.4.0.orig/arch/mips/kvm/tlb.c
+++ linux-4.4.0/arch/mips/kvm/tlb.c
@@ -152,7 +152,7 @@
 	srcu_idx = srcu_read_lock(&kvm->srcu);
 	pfn = kvm_mips_gfn_to_pfn(kvm, gfn);
 
-	if (kvm_mips_is_error_pfn(pfn)) {
+	if (is_error_noslot_pfn(pfn)) {
 		kvm_err("Couldn't get pfn for gfn %#" PRIx64 "!\n", gfn);
 		err = -EFAULT;
 		goto out;
@@ -276,7 +276,7 @@
 	}
 
 	gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT);
-	if (gfn >= kvm->arch.guest_pmap_npages) {
+	if ((gfn | 1) >= kvm->arch.guest_pmap_npages) {
 		kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__,
 			gfn, badvaddr);
 		kvm_mips_dump_host_tlbs();
@@ -361,25 +361,39 @@
 	unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
 	struct kvm *kvm = vcpu->kvm;
 	pfn_t pfn0, pfn1;
+	gfn_t gfn0, gfn1;
+	long tlb_lo[2];
 
-	if ((tlb->tlb_hi & VPN2_MASK) == 0) {
-		pfn0 = 0;
-		pfn1 = 0;
-	} else {
-		if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo0)
-					   >> PAGE_SHIFT) < 0)
-			return -1;
-
-		if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo1)
-					   >> PAGE_SHIFT) < 0)
-			return -1;
-
-		pfn0 = kvm->arch.guest_pmap[mips3_tlbpfn_to_paddr(tlb->tlb_lo0)
-					    >> PAGE_SHIFT];
-		pfn1 = kvm->arch.guest_pmap[mips3_tlbpfn_to_paddr(tlb->tlb_lo1)
-					    >> PAGE_SHIFT];
+	tlb_lo[0] = tlb->tlb_lo0;
+	tlb_lo[1] = tlb->tlb_lo1;
+
+	/*
+	 * The commpage address must not be mapped to anything else if the guest
+	 * TLB contains entries nearby, or commpage accesses will break.
+	 */
+	if (!((tlb->tlb_hi ^ KVM_GUEST_COMMPAGE_ADDR) &
+			VPN2_MASK & (PAGE_MASK << 1)))
+		tlb_lo[(KVM_GUEST_COMMPAGE_ADDR >> PAGE_SHIFT) & 1] = 0;
+
+	gfn0 = mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT;
+	gfn1 = mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT;
+	if (gfn0 >= kvm->arch.guest_pmap_npages ||
+	    gfn1 >= kvm->arch.guest_pmap_npages) {
+		kvm_err("%s: Invalid gfn: [%#llx, %#llx], EHi: %#lx\n",
+			__func__, gfn0, gfn1, tlb->tlb_hi);
+		kvm_mips_dump_guest_tlbs(vcpu);
+		return -1;
 	}
 
+	if (kvm_mips_map_page(kvm, gfn0) < 0)
+		return -1;
+
+	if (kvm_mips_map_page(kvm, gfn1) < 0)
+		return -1;
+
+	pfn0 = kvm->arch.guest_pmap[gfn0];
+	pfn1 = kvm->arch.guest_pmap[gfn1];
+
 	if (hpa0)
 		*hpa0 = pfn0 << PAGE_SHIFT;
 
@@ -391,9 +405,9 @@
 					       kvm_mips_get_kernel_asid(vcpu) :
 					       kvm_mips_get_user_asid(vcpu));
 	entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | (0x3 << 3) |
-		   (tlb->tlb_lo0 & MIPS3_PG_D) | (tlb->tlb_lo0 & MIPS3_PG_V);
+		   (tlb_lo[0] & MIPS3_PG_D) | (tlb_lo[0] & MIPS3_PG_V);
 	entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) | (0x3 << 3) |
-		   (tlb->tlb_lo1 & MIPS3_PG_D) | (tlb->tlb_lo1 & MIPS3_PG_V);
+		   (tlb_lo[1] & MIPS3_PG_D) | (tlb_lo[1] & MIPS3_PG_V);
 
 	kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc,
 		  tlb->tlb_lo0, tlb->tlb_lo1);
@@ -794,10 +808,16 @@
 				local_irq_restore(flags);
 				return KVM_INVALID_INST;
 			}
-			kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
-							     &vcpu->arch.
-							     guest_tlb[index],
-							     NULL, NULL);
+			if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
+						&vcpu->arch.guest_tlb[index],
+						NULL, NULL)) {
+				kvm_err("%s: handling mapped seg tlb fault failed for %p, index: %u, vcpu: %p, ASID: %#lx\n",
+					__func__, opc, index, vcpu,
+					read_c0_entryhi());
+				kvm_mips_dump_guest_tlbs(vcpu);
+				local_irq_restore(flags);
+				return KVM_INVALID_INST;
+			}
 			inst = *(opc);
 		}
 		local_irq_restore(flags);
--- linux-4.4.0.orig/arch/mips/kvm/trap_emul.c
+++ linux-4.4.0/arch/mips/kvm/trap_emul.c
@@ -547,7 +547,7 @@
 		kvm_mips_write_count(vcpu, v);
 		break;
 	case KVM_REG_MIPS_CP0_COMPARE:
-		kvm_mips_write_compare(vcpu, v);
+		kvm_mips_write_compare(vcpu, v, false);
 		break;
 	case KVM_REG_MIPS_CP0_CAUSE:
 		/*
--- linux-4.4.0.orig/arch/mips/lantiq/irq.c
+++ linux-4.4.0/arch/mips/lantiq/irq.c
@@ -160,8 +160,9 @@
 			if (edge)
 				irq_set_handler(d->hwirq, handle_edge_irq);
 
-			ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
-				(val << (i * 4)), LTQ_EIU_EXIN_C);
+			ltq_eiu_w32((ltq_eiu_r32(LTQ_EIU_EXIN_C) &
+				    (~(7 << (i * 4)))) | (val << (i * 4)),
+				    LTQ_EIU_EXIN_C);
 		}
 	}
 
@@ -244,7 +245,7 @@
 	do_IRQ((int)irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module));
 
 	/* if this is a EBU irq, we need to ack it or get a deadlock */
-	if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0) && LTQ_EBU_PCC_ISTAT)
+	if (irq == LTQ_ICU_EBU_IRQ && !module && LTQ_EBU_PCC_ISTAT != 0)
 		ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
 			LTQ_EBU_PCC_ISTAT);
 }
--- linux-4.4.0.orig/arch/mips/lantiq/xway/sysctrl.c
+++ linux-4.4.0/arch/mips/lantiq/xway/sysctrl.c
@@ -467,10 +467,10 @@
 
 		if (!np_xbar)
 			panic("Failed to load xbar nodes from devicetree");
-		if (of_address_to_resource(np_pmu, 0, &res_xbar))
+		if (of_address_to_resource(np_xbar, 0, &res_xbar))
 			panic("Failed to get xbar resources");
-		if (request_mem_region(res_xbar.start, resource_size(&res_xbar),
-			res_xbar.name) < 0)
+		if (!request_mem_region(res_xbar.start, resource_size(&res_xbar),
+			res_xbar.name))
 			panic("Failed to get xbar resources");
 
 		ltq_xbar_membase = ioremap_nocache(res_xbar.start,
@@ -545,7 +545,7 @@
 		clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI);
 		clkdev_add_pmu("1a800000.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI);
 		clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL);
-		clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH | PMU_PPE_DP);
+		clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP);
 		clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
 		clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
 	} else if (of_machine_is_compatible("lantiq,ar10")) {
@@ -553,7 +553,7 @@
 				  ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz());
 		clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
 		clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
-		clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH |
+		clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH |
 			       PMU_PPE_DP | PMU_PPE_TC);
 		clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
 		clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
@@ -575,11 +575,11 @@
 		clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
 
 		clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
-		clkdev_add_pmu("1e108000.eth", NULL, 1, 0,
+		clkdev_add_pmu("1e108000.eth", NULL, 0, 0,
 				PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
 				PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
 				PMU_PPE_QSB | PMU_PPE_TOP);
-		clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
+		clkdev_add_pmu("1f203000.rcu", "gphy", 0, 0, PMU_GPHY);
 		clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
 		clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
 		clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
--- linux-4.4.0.orig/arch/mips/lib/Makefile
+++ linux-4.4.0/arch/mips/lib/Makefile
@@ -15,4 +15,5 @@
 obj-$(CONFIG_CPU_TX39XX)	+= r3k_dump_tlb.o
 
 # libgcc-style stuff needed in the kernel
-obj-y += ashldi3.o ashrdi3.o bswapsi.o bswapdi.o cmpdi2.o lshrdi3.o ucmpdi2.o
+obj-y += ashldi3.o ashrdi3.o bswapsi.o bswapdi.o cmpdi2.o lshrdi3.o multi3.o \
+	 ucmpdi2.o
--- linux-4.4.0.orig/arch/mips/lib/ashldi3.c
+++ linux-4.4.0/arch/mips/lib/ashldi3.c
@@ -2,7 +2,7 @@
 
 #include "libgcc.h"
 
-long long __ashldi3(long long u, word_type b)
+long long notrace __ashldi3(long long u, word_type b)
 {
 	DWunion uu, w;
 	word_type bm;
--- linux-4.4.0.orig/arch/mips/lib/ashrdi3.c
+++ linux-4.4.0/arch/mips/lib/ashrdi3.c
@@ -2,7 +2,7 @@
 
 #include "libgcc.h"
 
-long long __ashrdi3(long long u, word_type b)
+long long notrace __ashrdi3(long long u, word_type b)
 {
 	DWunion uu, w;
 	word_type bm;
--- linux-4.4.0.orig/arch/mips/lib/bswapdi.c
+++ linux-4.4.0/arch/mips/lib/bswapdi.c
@@ -1,6 +1,6 @@
 #include <linux/module.h>
 
-unsigned long long __bswapdi2(unsigned long long u)
+unsigned long long notrace __bswapdi2(unsigned long long u)
 {
 	return (((u) & 0xff00000000000000ull) >> 56) |
 	       (((u) & 0x00ff000000000000ull) >> 40) |
--- linux-4.4.0.orig/arch/mips/lib/bswapsi.c
+++ linux-4.4.0/arch/mips/lib/bswapsi.c
@@ -1,6 +1,6 @@
 #include <linux/module.h>
 
-unsigned int __bswapsi2(unsigned int u)
+unsigned int notrace __bswapsi2(unsigned int u)
 {
 	return (((u) & 0xff000000) >> 24) |
 	       (((u) & 0x00ff0000) >>  8) |
--- linux-4.4.0.orig/arch/mips/lib/cmpdi2.c
+++ linux-4.4.0/arch/mips/lib/cmpdi2.c
@@ -2,7 +2,7 @@
 
 #include "libgcc.h"
 
-word_type __cmpdi2(long long a, long long b)
+word_type notrace __cmpdi2(long long a, long long b)
 {
 	const DWunion au = {
 		.ll = a
--- linux-4.4.0.orig/arch/mips/lib/libgcc.h
+++ linux-4.4.0/arch/mips/lib/libgcc.h
@@ -9,10 +9,18 @@
 struct DWstruct {
 	int high, low;
 };
+
+struct TWstruct {
+	long long high, low;
+};
 #elif defined(__LITTLE_ENDIAN)
 struct DWstruct {
 	int low, high;
 };
+
+struct TWstruct {
+	long long low, high;
+};
 #else
 #error I feel sick.
 #endif
@@ -22,4 +30,13 @@
 	long long ll;
 } DWunion;
 
+#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6)
+typedef int ti_type __attribute__((mode(TI)));
+
+typedef union {
+	struct TWstruct s;
+	ti_type ti;
+} TWunion;
+#endif
+
 #endif /* __ASM_LIBGCC_H */
--- linux-4.4.0.orig/arch/mips/lib/lshrdi3.c
+++ linux-4.4.0/arch/mips/lib/lshrdi3.c
@@ -2,7 +2,7 @@
 
 #include "libgcc.h"
 
-long long __lshrdi3(long long u, word_type b)
+long long notrace __lshrdi3(long long u, word_type b)
 {
 	DWunion uu, w;
 	word_type bm;
--- linux-4.4.0.orig/arch/mips/lib/memset.S
+++ linux-4.4.0/arch/mips/lib/memset.S
@@ -218,7 +218,7 @@
 1:	PTR_ADDIU	a0, 1			/* fill bytewise */
 	R10KCBARRIER(0(ra))
 	bne		t1, a0, 1b
-	sb		a1, -1(a0)
+	 EX(sb, a1, -1(a0), .Lsmall_fixup\@)
 
 2:	jr		ra			/* done */
 	move		a2, zero
@@ -249,13 +249,18 @@
 	PTR_L		t0, TI_TASK($28)
 	andi		a2, STORMASK
 	LONG_L		t0, THREAD_BUADDR(t0)
-	LONG_ADDU	a2, t1
+	LONG_ADDU	a2, a0
 	jr		ra
 	LONG_SUBU	a2, t0
 
 .Llast_fixup\@:
 	jr		ra
-	andi		v1, a2, STORMASK
+	 nop
+
+.Lsmall_fixup\@:
+	PTR_SUBU	a2, t1, a0
+	jr		ra
+	 PTR_ADDIU	a2, 1
 
 	.endm
 
--- linux-4.4.0.orig/arch/mips/lib/multi3.c
+++ linux-4.4.0/arch/mips/lib/multi3.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/export.h>
+
+#include "libgcc.h"
+
+/*
+ * GCC 7 & older can suboptimally generate __multi3 calls for mips64r6, so for
+ * that specific case only we implement that intrinsic here.
+ *
+ * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82981
+ */
+#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 8)
+
+/* multiply 64-bit values, low 64-bits returned */
+static inline long long notrace dmulu(long long a, long long b)
+{
+	long long res;
+
+	asm ("dmulu %0,%1,%2" : "=r" (res) : "r" (a), "r" (b));
+	return res;
+}
+
+/* multiply 64-bit unsigned values, high 64-bits of 128-bit result returned */
+static inline long long notrace dmuhu(long long a, long long b)
+{
+	long long res;
+
+	asm ("dmuhu %0,%1,%2" : "=r" (res) : "r" (a), "r" (b));
+	return res;
+}
+
+/* multiply 128-bit values, low 128-bits returned */
+ti_type notrace __multi3(ti_type a, ti_type b)
+{
+	TWunion res, aa, bb;
+
+	aa.ti = a;
+	bb.ti = b;
+
+	/*
+	 * a * b =           (a.lo * b.lo)
+	 *         + 2^64  * (a.hi * b.lo + a.lo * b.hi)
+	 *        [+ 2^128 * (a.hi * b.hi)]
+	 */
+	res.s.low = dmulu(aa.s.low, bb.s.low);
+	res.s.high = dmuhu(aa.s.low, bb.s.low);
+	res.s.high += dmulu(aa.s.high, bb.s.low);
+	res.s.high += dmulu(aa.s.low, bb.s.high);
+
+	return res.ti;
+}
+EXPORT_SYMBOL(__multi3);
+
+#endif /* 64BIT && CPU_MIPSR6 && GCC7 */
--- linux-4.4.0.orig/arch/mips/lib/ucmpdi2.c
+++ linux-4.4.0/arch/mips/lib/ucmpdi2.c
@@ -2,7 +2,7 @@
 
 #include "libgcc.h"
 
-word_type __ucmpdi2(unsigned long long a, unsigned long long b)
+word_type notrace __ucmpdi2(unsigned long long a, unsigned long long b)
 {
 	const DWunion au = {.ll = a};
 	const DWunion bu = {.ll = b};
--- linux-4.4.0.orig/arch/mips/loongson64/common/cs5536/cs5536_ohci.c
+++ linux-4.4.0/arch/mips/loongson64/common/cs5536/cs5536_ohci.c
@@ -138,7 +138,7 @@
 		break;
 	case PCI_OHCI_INT_REG:
 		_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
-		if ((lo & 0x00000f00) == CS5536_USB_INTR)
+		if (((lo >> PIC_YSEL_LOW_USB_SHIFT) & 0xf) == CS5536_USB_INTR)
 			conf_data = 1;
 		break;
 	default:
--- linux-4.4.0.orig/arch/mips/loongson64/common/serial.c
+++ linux-4.4.0/arch/mips/loongson64/common/serial.c
@@ -110,7 +110,7 @@
 }
 module_init(serial_init);
 
-static void __init serial_exit(void)
+static void __exit serial_exit(void)
 {
 	platform_device_unregister(&uart8250_device);
 }
--- linux-4.4.0.orig/arch/mips/loongson64/lemote-2f/irq.c
+++ linux-4.4.0/arch/mips/loongson64/lemote-2f/irq.c
@@ -102,7 +102,7 @@
 static struct irqaction cascade_irqaction = {
 	.handler = no_action,
 	.name = "cascade",
-	.flags = IRQF_NO_THREAD,
+	.flags = IRQF_NO_THREAD | IRQF_NO_SUSPEND,
 };
 
 void __init mach_init_irq(void)
--- linux-4.4.0.orig/arch/mips/loongson64/loongson-3/hpet.c
+++ linux-4.4.0/arch/mips/loongson64/loongson-3/hpet.c
@@ -13,6 +13,9 @@
 #define SMBUS_PCI_REG64		0x64
 #define SMBUS_PCI_REGB4		0xb4
 
+#define HPET_MIN_CYCLES		16
+#define HPET_MIN_PROG_DELTA	(HPET_MIN_CYCLES * 12)
+
 static DEFINE_SPINLOCK(hpet_lock);
 DEFINE_PER_CPU(struct clock_event_device, hpet_clockevent_device);
 
@@ -154,15 +157,16 @@
 static int hpet_next_event(unsigned long delta,
 		struct clock_event_device *evt)
 {
-	unsigned int cnt;
-	int res;
+	u32 cnt;
+	s32 res;
 
 	cnt = hpet_read(HPET_COUNTER);
-	cnt += delta;
+	cnt += (u32) delta;
 	hpet_write(HPET_T0_CMP, cnt);
 
-	res = ((int)(hpet_read(HPET_COUNTER) - cnt) > 0) ? -ETIME : 0;
-	return res;
+	res = (s32)(cnt - hpet_read(HPET_COUNTER));
+
+	return res < HPET_MIN_CYCLES ? -ETIME : 0;
 }
 
 static irqreturn_t hpet_irq_handler(int irq, void *data)
@@ -226,7 +230,7 @@
 
 	cd = &per_cpu(hpet_clockevent_device, cpu);
 	cd->name = "hpet";
-	cd->rating = 320;
+	cd->rating = 100;
 	cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 	cd->set_state_shutdown = hpet_set_state_shutdown;
 	cd->set_state_periodic = hpet_set_state_periodic;
@@ -237,7 +241,7 @@
 	cd->cpumask = cpumask_of(cpu);
 	clockevent_set_clock(cd, HPET_FREQ);
 	cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
-	cd->min_delta_ns = 5000;
+	cd->min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, cd);
 
 	clockevents_register_device(cd);
 	setup_irq(HPET_T0_IRQ, &hpet_irq);
--- linux-4.4.0.orig/arch/mips/loongson64/loongson-3/irq.c
+++ linux-4.4.0/arch/mips/loongson64/loongson-3/irq.c
@@ -42,51 +42,8 @@
 	}
 }
 
-static struct irqaction cascade_irqaction = {
-	.handler = no_action,
-	.flags = IRQF_NO_SUSPEND,
-	.name = "cascade",
-};
-
-static inline void mask_loongson_irq(struct irq_data *d)
-{
-	clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
-	irq_disable_hazard();
-
-	/* Workaround: UART IRQ may deliver to any core */
-	if (d->irq == LOONGSON_UART_IRQ) {
-		int cpu = smp_processor_id();
-		int node_id = cpu_logical_map(cpu) / loongson_sysconf.cores_per_node;
-		int core_id = cpu_logical_map(cpu) % loongson_sysconf.cores_per_node;
-		u64 intenclr_addr = smp_group[node_id] |
-			(u64)(&LOONGSON_INT_ROUTER_INTENCLR);
-		u64 introuter_lpc_addr = smp_group[node_id] |
-			(u64)(&LOONGSON_INT_ROUTER_LPC);
-
-		*(volatile u32 *)intenclr_addr = 1 << 10;
-		*(volatile u8 *)introuter_lpc_addr = 0x10 + (1<<core_id);
-	}
-}
-
-static inline void unmask_loongson_irq(struct irq_data *d)
-{
-	/* Workaround: UART IRQ may deliver to any core */
-	if (d->irq == LOONGSON_UART_IRQ) {
-		int cpu = smp_processor_id();
-		int node_id = cpu_logical_map(cpu) / loongson_sysconf.cores_per_node;
-		int core_id = cpu_logical_map(cpu) % loongson_sysconf.cores_per_node;
-		u64 intenset_addr = smp_group[node_id] |
-			(u64)(&LOONGSON_INT_ROUTER_INTENSET);
-		u64 introuter_lpc_addr = smp_group[node_id] |
-			(u64)(&LOONGSON_INT_ROUTER_LPC);
-
-		*(volatile u32 *)intenset_addr = 1 << 10;
-		*(volatile u8 *)introuter_lpc_addr = 0x10 + (1<<core_id);
-	}
-
-	set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
-	irq_enable_hazard();
-}
+static inline void mask_loongson_irq(struct irq_data *d) { }
+static inline void unmask_loongson_irq(struct irq_data *d) { }
 
  /* For MIPS IRQs which shared by all cores */
 static struct irq_chip loongson_irq_chip = {
@@ -124,12 +81,11 @@
 	mips_cpu_irq_init();
 	init_i8259_irqs();
 	irq_set_chip_and_handler(LOONGSON_UART_IRQ,
-			&loongson_irq_chip, handle_level_irq);
-
-	/* setup HT1 irq */
-	setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction);
+			&loongson_irq_chip, handle_percpu_irq);
+	irq_set_chip_and_handler(LOONGSON_BRIDGE_IRQ,
+			&loongson_irq_chip, handle_percpu_irq);
 
-	set_c0_status(STATUSF_IP2 | STATUSF_IP6);
+	set_c0_status(STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP6);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
--- linux-4.4.0.orig/arch/mips/loongson64/loongson-3/numa.c
+++ linux-4.4.0/arch/mips/loongson64/loongson-3/numa.c
@@ -213,10 +213,10 @@
 		BOOTMEM_DEFAULT);
 
 	if (node == 0 && node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) {
-		/* Reserve 0xff800000~0xffffffff for RS780E integrated GPU */
+		/* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */
 		reserve_bootmem_node(NODE_DATA(node),
-				(node_addrspace_offset | 0xff800000),
-				8 << 20, BOOTMEM_DEFAULT);
+				(node_addrspace_offset | 0xfe000000),
+				32 << 20, BOOTMEM_DEFAULT);
 	}
 
 	sparse_memory_present_with_active_regions(node);
--- linux-4.4.0.orig/arch/mips/loongson64/loongson-3/platform.c
+++ linux-4.4.0/arch/mips/loongson64/loongson-3/platform.c
@@ -31,6 +31,9 @@
 			continue;
 
 		pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+		if (!pdev)
+			return -ENOMEM;
+
 		pdev->name = loongson_sysconf.sensors[i].name;
 		pdev->id = loongson_sysconf.sensors[i].id;
 		pdev->dev.platform_data = &loongson_sysconf.sensors[i];
--- linux-4.4.0.orig/arch/mips/loongson64/loongson-3/smp.c
+++ linux-4.4.0/arch/mips/loongson64/loongson-3/smp.c
@@ -30,13 +30,13 @@
 #include "smp.h"
 
 DEFINE_PER_CPU(int, cpu_state);
-DEFINE_PER_CPU(uint32_t, core0_c0count);
 
 static void *ipi_set0_regs[16];
 static void *ipi_clear0_regs[16];
 static void *ipi_status0_regs[16];
 static void *ipi_en0_regs[16];
 static void *ipi_mailbox_buf[16];
+static uint32_t core0_c0count[NR_CPUS];
 
 /* read a 32bit value from ipi register */
 #define loongson3_ipi_read32(addr) readl(addr)
@@ -275,12 +275,14 @@
 	if (action & SMP_ASK_C0COUNT) {
 		BUG_ON(cpu != 0);
 		c0count = read_c0_count();
-		for (i = 1; i < num_possible_cpus(); i++)
-			per_cpu(core0_c0count, i) = c0count;
+		c0count = c0count ? c0count : 1;
+		for (i = 1; i < nr_cpu_ids; i++)
+			core0_c0count[i] = c0count;
+		__wbflush(); /* Let others see the result ASAP */
 	}
 }
 
-#define MAX_LOOPS 1111
+#define MAX_LOOPS 800
 /*
  * SMP init and finish on secondary CPUs
  */
@@ -305,16 +307,20 @@
 		cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
 
 	i = 0;
-	__this_cpu_write(core0_c0count, 0);
+	core0_c0count[cpu] = 0;
 	loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
-	while (!__this_cpu_read(core0_c0count)) {
+	while (!core0_c0count[cpu]) {
 		i++;
 		cpu_relax();
 	}
 
 	if (i > MAX_LOOPS)
 		i = MAX_LOOPS;
-	initcount = __this_cpu_read(core0_c0count) + i;
+	if (cpu_data[cpu].package)
+		initcount = core0_c0count[cpu] + i;
+	else /* Local access is faster for loops */
+		initcount = core0_c0count[cpu] + i/2;
+
 	write_c0_count(initcount);
 }
 
@@ -411,6 +417,7 @@
 		return -EBUSY;
 
 	set_cpu_online(cpu, false);
+	calculate_cpu_foreign_map();
 	cpumask_clear_cpu(cpu, &cpu_callin_map);
 	local_irq_save(flags);
 	fixup_irqs();
--- linux-4.4.0.orig/arch/mips/math-emu/cp1emu.c
+++ linux-4.4.0/arch/mips/math-emu/cp1emu.c
@@ -445,9 +445,11 @@
 	case spec_op:
 		switch (insn.r_format.func) {
 		case jalr_op:
-			regs->regs[insn.r_format.rd] =
-				regs->cp0_epc + dec_insn.pc_inc +
-				dec_insn.next_pc_inc;
+			if (insn.r_format.rd != 0) {
+				regs->regs[insn.r_format.rd] =
+					regs->cp0_epc + dec_insn.pc_inc +
+					dec_insn.next_pc_inc;
+			}
 			/* Fall through */
 		case jr_op:
 			/* For R6, JR already emulated in jalr_op */
@@ -827,12 +829,12 @@
 } while (0)
 
 #define DIFROMREG(di, x)						\
-	((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0))
+	((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) ^ 1)], 0))
 
 #define DITOREG(di, x)							\
 do {									\
 	unsigned fpr, i;						\
-	fpr = (x) & ~(cop1_64bit(xcp) == 0);				\
+	fpr = (x) & ~(cop1_64bit(xcp) ^ 1);				\
 	set_fpr64(&ctx->fpr[fpr], 0, di);				\
 	for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++)		\
 		set_fpr64(&ctx->fpr[fpr], i, 0);			\
@@ -973,9 +975,10 @@
 		struct mm_decoded_insn dec_insn, void *__user *fault_addr)
 {
 	unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc;
-	unsigned int cond, cbit;
+	unsigned int cond, cbit, bit0;
 	mips_instruction ir;
 	int likely, pc_inc;
+	union fpureg *fpr;
 	u32 __user *wva;
 	u64 __user *dva;
 	u32 wval;
@@ -1187,14 +1190,14 @@
 				return SIGILL;
 
 			cond = likely = 0;
+			fpr = &current->thread.fpu.fpr[MIPSInst_RT(ir)];
+			bit0 = get_fpr32(fpr, 0) & 0x1;
 			switch (MIPSInst_RS(ir)) {
 			case bc1eqz_op:
-				if (get_fpr32(&current->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)
-				    cond = 1;
+				cond = bit0 == 0;
 				break;
 			case bc1nez_op:
-				if (!(get_fpr32(&current->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1))
-				    cond = 1;
+				cond = bit0 != 0;
 				break;
 			}
 			goto branch_common;
@@ -1775,7 +1778,7 @@
 			SPFROMREG(fs, MIPSInst_FS(ir));
 			SPFROMREG(fd, MIPSInst_FD(ir));
 			rv.s = ieee754sp_maddf(fd, fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fmsubf_op: {
@@ -1788,7 +1791,7 @@
 			SPFROMREG(fs, MIPSInst_FS(ir));
 			SPFROMREG(fd, MIPSInst_FD(ir));
 			rv.s = ieee754sp_msubf(fd, fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case frint_op: {
@@ -1812,7 +1815,7 @@
 			SPFROMREG(fs, MIPSInst_FS(ir));
 			rv.w = ieee754sp_2008class(fs);
 			rfmt = w_fmt;
-			break;
+			goto copcsr;
 		}
 
 		case fmin_op: {
@@ -1824,7 +1827,7 @@
 			SPFROMREG(ft, MIPSInst_FT(ir));
 			SPFROMREG(fs, MIPSInst_FS(ir));
 			rv.s = ieee754sp_fmin(fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fmina_op: {
@@ -1836,7 +1839,7 @@
 			SPFROMREG(ft, MIPSInst_FT(ir));
 			SPFROMREG(fs, MIPSInst_FS(ir));
 			rv.s = ieee754sp_fmina(fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fmax_op: {
@@ -1848,7 +1851,7 @@
 			SPFROMREG(ft, MIPSInst_FT(ir));
 			SPFROMREG(fs, MIPSInst_FS(ir));
 			rv.s = ieee754sp_fmax(fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fmaxa_op: {
@@ -1860,7 +1863,7 @@
 			SPFROMREG(ft, MIPSInst_FT(ir));
 			SPFROMREG(fs, MIPSInst_FS(ir));
 			rv.s = ieee754sp_fmaxa(fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fabs_op:
@@ -2093,7 +2096,7 @@
 			DPFROMREG(fs, MIPSInst_FS(ir));
 			DPFROMREG(fd, MIPSInst_FD(ir));
 			rv.d = ieee754dp_maddf(fd, fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fmsubf_op: {
@@ -2106,7 +2109,7 @@
 			DPFROMREG(fs, MIPSInst_FS(ir));
 			DPFROMREG(fd, MIPSInst_FD(ir));
 			rv.d = ieee754dp_msubf(fd, fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case frint_op: {
@@ -2130,7 +2133,7 @@
 			DPFROMREG(fs, MIPSInst_FS(ir));
 			rv.w = ieee754dp_2008class(fs);
 			rfmt = w_fmt;
-			break;
+			goto copcsr;
 		}
 
 		case fmin_op: {
@@ -2142,7 +2145,7 @@
 			DPFROMREG(ft, MIPSInst_FT(ir));
 			DPFROMREG(fs, MIPSInst_FS(ir));
 			rv.d = ieee754dp_fmin(fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fmina_op: {
@@ -2154,7 +2157,7 @@
 			DPFROMREG(ft, MIPSInst_FT(ir));
 			DPFROMREG(fs, MIPSInst_FS(ir));
 			rv.d = ieee754dp_fmina(fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fmax_op: {
@@ -2166,7 +2169,7 @@
 			DPFROMREG(ft, MIPSInst_FT(ir));
 			DPFROMREG(fs, MIPSInst_FS(ir));
 			rv.d = ieee754dp_fmax(fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fmaxa_op: {
@@ -2178,7 +2181,7 @@
 			DPFROMREG(ft, MIPSInst_FT(ir));
 			DPFROMREG(fs, MIPSInst_FS(ir));
 			rv.d = ieee754dp_fmaxa(fs, ft);
-			break;
+			goto copcsr;
 		}
 
 		case fabs_op:
@@ -2358,7 +2361,6 @@
 					break;
 				default:
 					/* Reserved R6 ops */
-					pr_err("Reserved MIPS R6 CMP.condn.S operation\n");
 					return SIGILL;
 				}
 			}
@@ -2432,7 +2434,6 @@
 					break;
 				default:
 					/* Reserved R6 ops */
-					pr_err("Reserved MIPS R6 CMP.condn.D operation\n");
 					return SIGILL;
 				}
 			}
@@ -2494,6 +2495,35 @@
 	return 0;
 }
 
+/*
+ * Emulate FPU instructions.
+ *
+ * If we use FPU hardware, then we have been typically called to handle
+ * an unimplemented operation, such as where an operand is a NaN or
+ * denormalized.  In that case exit the emulation loop after a single
+ * iteration so as to let hardware execute any subsequent instructions.
+ *
+ * If we have no FPU hardware or it has been disabled, then continue
+ * emulating floating-point instructions until one of these conditions
+ * has occurred:
+ *
+ * - a non-FPU instruction has been encountered,
+ *
+ * - an attempt to emulate has ended with a signal,
+ *
+ * - the ISA mode has been switched.
+ *
+ * We need to terminate the emulation loop if we got switched to the
+ * MIPS16 mode, whether supported or not, so that we do not attempt
+ * to emulate a MIPS16 instruction as a regular MIPS FPU instruction.
+ * Similarly if we got switched to the microMIPS mode and only the
+ * regular MIPS mode is supported, so that we do not attempt to emulate
+ * a microMIPS instruction as a regular MIPS FPU instruction.  Or if
+ * we got switched to the regular MIPS mode and only the microMIPS mode
+ * is supported, so that we do not attempt to emulate a regular MIPS
+ * instruction that should cause an Address Error exception instead.
+ * For simplicity we always terminate upon an ISA mode switch.
+ */
 int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 	int has_fpu, void *__user *fault_addr)
 {
@@ -2579,6 +2609,15 @@
 			break;
 		if (sig)
 			break;
+		/*
+		 * We have to check for the ISA bit explicitly here,
+		 * because `get_isa16_mode' may return 0 if support
+		 * for code compression has been globally disabled,
+		 * or otherwise we may produce the wrong signal or
+		 * even proceed successfully where we must not.
+		 */
+		if ((xcp->cp0_epc ^ prevepc) & 0x1)
+			break;
 
 		cond_resched();
 	} while (xcp->cp0_epc > prevepc);
--- linux-4.4.0.orig/arch/mips/math-emu/dp_fmax.c
+++ linux-4.4.0/arch/mips/math-emu/dp_fmax.c
@@ -47,14 +47,26 @@
 	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
 		return ieee754dp_nanxcpt(x);
 
-	/* numbers are preferred to NaNs */
+	/*
+	 * Quiet NaN handling
+	 */
+
+	/*
+	 *    The case of both inputs quiet NaNs
+	 */
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return x;
+
+	/*
+	 *    The cases of exactly one input quiet NaN (numbers
+	 *    are here preferred as returned values to NaNs)
+	 */
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
@@ -80,9 +92,7 @@
 		return ys ? x : y;
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		return ieee754dp_zero(1);
+		return ieee754dp_zero(xs & ys);
 
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
 		DPDNORMX;
@@ -106,16 +116,32 @@
 	else if (xs < ys)
 		return x;
 
-	/* Compare exponent */
-	if (xe > ye)
-		return x;
-	else if (xe < ye)
-		return y;
+	/* Signs of inputs are equal, let's compare exponents */
+	if (xs == 0) {
+		/* Inputs are both positive */
+		if (xe > ye)
+			return x;
+		else if (xe < ye)
+			return y;
+	} else {
+		/* Inputs are both negative */
+		if (xe > ye)
+			return y;
+		else if (xe < ye)
+			return x;
+	}
 
-	/* Compare mantissa */
+	/* Signs and exponents of inputs are equal, let's compare mantissas */
+	if (xs == 0) {
+		/* Inputs are both positive, with equal signs and exponents */
+		if (xm <= ym)
+			return y;
+		return x;
+	}
+	/* Inputs are both negative, with equal signs and exponents */
 	if (xm <= ym)
-		return y;
-	return x;
+		return x;
+	return y;
 }
 
 union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
@@ -147,14 +173,26 @@
 	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
 		return ieee754dp_nanxcpt(x);
 
-	/* numbers are preferred to NaNs */
+	/*
+	 * Quiet NaN handling
+	 */
+
+	/*
+	 *    The case of both inputs quiet NaNs
+	 */
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return x;
+
+	/*
+	 *    The cases of exactly one input quiet NaN (numbers
+	 *    are here preferred as returned values to NaNs)
+	 */
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
@@ -164,6 +202,9 @@
 	/*
 	 * Infinity and zero handling
 	 */
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		return ieee754dp_inf(xs & ys);
+
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
@@ -171,7 +212,6 @@
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
@@ -180,9 +220,7 @@
 		return y;
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		return ieee754dp_zero(1);
+		return ieee754dp_zero(xs & ys);
 
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
 		DPDNORMX;
@@ -207,7 +245,11 @@
 		return y;
 
 	/* Compare mantissa */
-	if (xm <= ym)
+	if (xm < ym)
 		return y;
-	return x;
+	else if (xm > ym)
+		return x;
+	else if (xs == 0)
+		return x;
+	return y;
 }
--- linux-4.4.0.orig/arch/mips/math-emu/dp_fmin.c
+++ linux-4.4.0/arch/mips/math-emu/dp_fmin.c
@@ -47,14 +47,26 @@
 	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
 		return ieee754dp_nanxcpt(x);
 
-	/* numbers are preferred to NaNs */
+	/*
+	 * Quiet NaN handling
+	 */
+
+	/*
+	 *    The case of both inputs quiet NaNs
+	 */
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return x;
+
+	/*
+	 *    The cases of exactly one input quiet NaN (numbers
+	 *    are here preferred as returned values to NaNs)
+	 */
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
@@ -80,9 +92,7 @@
 		return ys ? y : x;
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		return ieee754dp_zero(1);
+		return ieee754dp_zero(xs | ys);
 
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
 		DPDNORMX;
@@ -106,16 +116,32 @@
 	else if (xs < ys)
 		return y;
 
-	/* Compare exponent */
-	if (xe > ye)
-		return y;
-	else if (xe < ye)
-		return x;
+	/* Signs of inputs are the same, let's compare exponents */
+	if (xs == 0) {
+		/* Inputs are both positive */
+		if (xe > ye)
+			return y;
+		else if (xe < ye)
+			return x;
+	} else {
+		/* Inputs are both negative */
+		if (xe > ye)
+			return x;
+		else if (xe < ye)
+			return y;
+	}
 
-	/* Compare mantissa */
+	/* Signs and exponents of inputs are equal, let's compare mantissas */
+	if (xs == 0) {
+		/* Inputs are both positive, with equal signs and exponents */
+		if (xm <= ym)
+			return x;
+		return y;
+	}
+	/* Inputs are both negative, with equal signs and exponents */
 	if (xm <= ym)
-		return x;
-	return y;
+		return y;
+	return x;
 }
 
 union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
@@ -147,14 +173,26 @@
 	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
 		return ieee754dp_nanxcpt(x);
 
-	/* numbers are preferred to NaNs */
+	/*
+	 * Quiet NaN handling
+	 */
+
+	/*
+	 *    The case of both inputs quiet NaNs
+	 */
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return x;
+
+	/*
+	 *    The cases of exactly one input quiet NaN (numbers
+	 *    are here preferred as returned values to NaNs)
+	 */
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
@@ -164,25 +202,25 @@
 	/*
 	 * Infinity and zero handling
 	 */
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		return ieee754dp_inf(xs | ys);
+
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		return x;
+		return y;
 
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-		return y;
+		return x;
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		return ieee754dp_zero(1);
+		return ieee754dp_zero(xs | ys);
 
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
 		DPDNORMX;
@@ -207,7 +245,11 @@
 		return x;
 
 	/* Compare mantissa */
-	if (xm <= ym)
+	if (xm < ym)
+		return x;
+	else if (xm > ym)
+		return y;
+	else if (xs == 1)
 		return x;
 	return y;
 }
--- linux-4.4.0.orig/arch/mips/math-emu/sp_fmax.c
+++ linux-4.4.0/arch/mips/math-emu/sp_fmax.c
@@ -47,14 +47,26 @@
 	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
 		return ieee754sp_nanxcpt(x);
 
-	/* numbers are preferred to NaNs */
+	/*
+	 * Quiet NaN handling
+	 */
+
+	/*
+	 *    The case of both inputs quiet NaNs
+	 */
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return x;
+
+	/*
+	 *    The cases of exactly one input quiet NaN (numbers
+	 *    are here preferred as returned values to NaNs)
+	 */
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
@@ -80,9 +92,7 @@
 		return ys ? x : y;
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		return ieee754sp_zero(1);
+		return ieee754sp_zero(xs & ys);
 
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
 		SPDNORMX;
@@ -106,16 +116,32 @@
 	else if (xs < ys)
 		return x;
 
-	/* Compare exponent */
-	if (xe > ye)
-		return x;
-	else if (xe < ye)
-		return y;
+	/* Signs of inputs are equal, let's compare exponents */
+	if (xs == 0) {
+		/* Inputs are both positive */
+		if (xe > ye)
+			return x;
+		else if (xe < ye)
+			return y;
+	} else {
+		/* Inputs are both negative */
+		if (xe > ye)
+			return y;
+		else if (xe < ye)
+			return x;
+	}
 
-	/* Compare mantissa */
+	/* Signs and exponents of inputs are equal, let's compare mantissas */
+	if (xs == 0) {
+		/* Inputs are both positive, with equal signs and exponents */
+		if (xm <= ym)
+			return y;
+		return x;
+	}
+	/* Inputs are both negative, with equal signs and exponents */
 	if (xm <= ym)
-		return y;
-	return x;
+		return x;
+	return y;
 }
 
 union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
@@ -147,14 +173,26 @@
 	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
 		return ieee754sp_nanxcpt(x);
 
-	/* numbers are preferred to NaNs */
+	/*
+	 * Quiet NaN handling
+	 */
+
+	/*
+	 *    The case of both inputs quiet NaNs
+	 */
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return x;
+
+	/*
+	 *    The cases of exactly one input quiet NaN (numbers
+	 *    are here preferred as returned values to NaNs)
+	 */
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
@@ -164,6 +202,9 @@
 	/*
 	 * Infinity and zero handling
 	 */
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		return ieee754sp_inf(xs & ys);
+
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
@@ -171,7 +212,6 @@
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
@@ -180,9 +220,7 @@
 		return y;
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		return ieee754sp_zero(1);
+		return ieee754sp_zero(xs & ys);
 
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
 		SPDNORMX;
@@ -207,7 +245,11 @@
 		return y;
 
 	/* Compare mantissa */
-	if (xm <= ym)
+	if (xm < ym)
 		return y;
-	return x;
+	else if (xm > ym)
+		return x;
+	else if (xs == 0)
+		return x;
+	return y;
 }
--- linux-4.4.0.orig/arch/mips/math-emu/sp_fmin.c
+++ linux-4.4.0/arch/mips/math-emu/sp_fmin.c
@@ -47,14 +47,26 @@
 	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
 		return ieee754sp_nanxcpt(x);
 
-	/* numbers are preferred to NaNs */
+	/*
+	 * Quiet NaN handling
+	 */
+
+	/*
+	 *    The case of both inputs quiet NaNs
+	 */
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return x;
+
+	/*
+	 *    The cases of exactly one input quiet NaN (numbers
+	 *    are here preferred as returned values to NaNs)
+	 */
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
@@ -80,9 +92,7 @@
 		return ys ? y : x;
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		return ieee754sp_zero(1);
+		return ieee754sp_zero(xs | ys);
 
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
 		SPDNORMX;
@@ -106,16 +116,32 @@
 	else if (xs < ys)
 		return y;
 
-	/* Compare exponent */
-	if (xe > ye)
-		return y;
-	else if (xe < ye)
-		return x;
+	/* Signs of inputs are the same, let's compare exponents */
+	if (xs == 0) {
+		/* Inputs are both positive */
+		if (xe > ye)
+			return y;
+		else if (xe < ye)
+			return x;
+	} else {
+		/* Inputs are both negative */
+		if (xe > ye)
+			return x;
+		else if (xe < ye)
+			return y;
+	}
 
-	/* Compare mantissa */
+	/* Signs and exponents of inputs are equal, let's compare mantissas */
+	if (xs == 0) {
+		/* Inputs are both positive, with equal signs and exponents */
+		if (xm <= ym)
+			return x;
+		return y;
+	}
+	/* Inputs are both negative, with equal signs and exponents */
 	if (xm <= ym)
-		return x;
-	return y;
+		return y;
+	return x;
 }
 
 union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
@@ -147,14 +173,26 @@
 	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
 		return ieee754sp_nanxcpt(x);
 
-	/* numbers are preferred to NaNs */
+	/*
+	 * Quiet NaN handling
+	 */
+
+	/*
+	 *    The case of both inputs quiet NaNs
+	 */
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return x;
+
+	/*
+	 *    The cases of exactly one input quiet NaN (numbers
+	 *    are here preferred as returned values to NaNs)
+	 */
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
 		return x;
 
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
@@ -164,25 +202,25 @@
 	/*
 	 * Infinity and zero handling
 	 */
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		return ieee754sp_inf(xs | ys);
+
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		return x;
+		return y;
 
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-		return y;
+		return x;
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		return ieee754sp_zero(1);
+		return ieee754sp_zero(xs | ys);
 
 	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
 		SPDNORMX;
@@ -207,7 +245,11 @@
 		return x;
 
 	/* Compare mantissa */
-	if (xm <= ym)
+	if (xm < ym)
+		return x;
+	else if (xm > ym)
+		return y;
+	else if (xs == 1)
 		return x;
 	return y;
 }
--- linux-4.4.0.orig/arch/mips/mm/c-r4k.c
+++ linux-4.4.0/arch/mips/mm/c-r4k.c
@@ -447,6 +447,11 @@
 		r4k_blast_scache();
 		break;
 
+	case CPU_BMIPS5000:
+		r4k_blast_scache();
+		__sync();
+		break;
+
 	default:
 		r4k_blast_dcache();
 		r4k_blast_icache();
@@ -712,7 +717,8 @@
 static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
 {
 	/* Catch bad driver code */
-	BUG_ON(size == 0);
+	if (WARN_ON(size == 0))
+		return;
 
 	preempt_disable();
 	if (cpu_has_inclusive_pcaches) {
@@ -745,7 +751,8 @@
 static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
 {
 	/* Catch bad driver code */
-	BUG_ON(size == 0);
+	if (WARN_ON(size == 0))
+		return;
 
 	preempt_disable();
 	if (cpu_has_inclusive_pcaches) {
@@ -1306,6 +1313,12 @@
 		c->icache.flags |= MIPS_CACHE_IC_F_DC;
 		break;
 
+	case CPU_BMIPS5000:
+		c->icache.flags |= MIPS_CACHE_IC_F_DC;
+		/* Cache aliases are handled in hardware; allow HIGHMEM */
+		c->dcache.flags &= ~MIPS_CACHE_ALIASES;
+		break;
+
 	case CPU_LOONGSON2:
 		/*
 		 * LOONGSON2 has 4 way icache, but when using indexed cache op,
@@ -1388,7 +1401,7 @@
 	return 1;
 }
 
-static void __init loongson2_sc_init(void)
+static void loongson2_sc_init(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 
@@ -1743,8 +1756,6 @@
 		flush_icache_range = (void *)b5k_instruction_hazard;
 		local_flush_icache_range = (void *)b5k_instruction_hazard;
 
-		/* Cache aliases are handled in hardware; allow HIGHMEM */
-		current_cpu_data.dcache.flags &= ~MIPS_CACHE_ALIASES;
 
 		/* Optimization: an L2 flush implicitly flushes the L1 */
 		current_cpu_data.options |= MIPS_CPU_INCLUSIVE_CACHES;
--- linux-4.4.0.orig/arch/mips/mm/cache.c
+++ linux-4.4.0/arch/mips/mm/cache.c
@@ -16,6 +16,7 @@
 #include <linux/mm.h>
 
 #include <asm/cacheflush.h>
+#include <asm/highmem.h>
 #include <asm/processor.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
@@ -83,8 +84,6 @@
 	struct address_space *mapping = page_mapping(page);
 	unsigned long addr;
 
-	if (PageHighMem(page))
-		return;
 	if (mapping && !mapping_mapped(mapping)) {
 		SetPageDcacheDirty(page);
 		return;
@@ -95,8 +94,15 @@
 	 * case is for exec env/arg pages and those are %99 certainly going to
 	 * get faulted into the tlb (and thus flushed) anyways.
 	 */
-	addr = (unsigned long) page_address(page);
+	if (PageHighMem(page))
+		addr = (unsigned long)kmap_atomic(page);
+	else
+		addr = (unsigned long)page_address(page);
+
 	flush_data_cache_page(addr);
+
+	if (PageHighMem(page))
+		__kunmap_atomic((void *)addr);
 }
 
 EXPORT_SYMBOL(__flush_dcache_page);
@@ -119,33 +125,28 @@
 
 EXPORT_SYMBOL(__flush_anon_page);
 
-void __flush_icache_page(struct vm_area_struct *vma, struct page *page)
-{
-	unsigned long addr;
-
-	if (PageHighMem(page))
-		return;
-
-	addr = (unsigned long) page_address(page);
-	flush_data_cache_page(addr);
-}
-EXPORT_SYMBOL_GPL(__flush_icache_page);
-
-void __update_cache(struct vm_area_struct *vma, unsigned long address,
-	pte_t pte)
+void __update_cache(unsigned long address, pte_t pte)
 {
 	struct page *page;
 	unsigned long pfn, addr;
-	int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
+	int exec = !pte_no_exec(pte) && !cpu_has_ic_fills_f_dc;
 
 	pfn = pte_pfn(pte);
 	if (unlikely(!pfn_valid(pfn)))
 		return;
 	page = pfn_to_page(pfn);
-	if (page_mapping(page) && Page_dcache_dirty(page)) {
-		addr = (unsigned long) page_address(page);
+	if (Page_dcache_dirty(page)) {
+		if (PageHighMem(page))
+			addr = (unsigned long)kmap_atomic(page);
+		else
+			addr = (unsigned long)page_address(page);
+
 		if (exec || pages_do_alias(addr, address & PAGE_MASK))
 			flush_data_cache_page(addr);
+
+		if (PageHighMem(page))
+			__kunmap_atomic((void *)addr);
+
 		ClearPageDcacheDirty(page);
 	}
 }
--- linux-4.4.0.orig/arch/mips/mm/gup.c
+++ linux-4.4.0/arch/mips/mm/gup.c
@@ -303,7 +303,7 @@
 
 	ret = get_user_pages_unlocked(current, mm, start,
 				      (end - start) >> PAGE_SHIFT,
-				      write, 0, pages);
+				      pages, write ? FOLL_WRITE : 0);
 
 	/* Have to be a bit careful with return values */
 	if (nr > 0) {
--- linux-4.4.0.orig/arch/mips/mm/ioremap.c
+++ linux-4.4.0/arch/mips/mm/ioremap.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <asm/addrspace.h>
 #include <asm/byteorder.h>
+#include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -97,6 +98,20 @@
 	return error;
 }
 
+static int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages,
+			       void *arg)
+{
+	unsigned long i;
+
+	for (i = 0; i < nr_pages; i++) {
+		if (pfn_valid(start_pfn + i) &&
+		    !PageReserved(pfn_to_page(start_pfn + i)))
+			return 1;
+	}
+
+	return 0;
+}
+
 /*
  * Generic mapping function (not visible outside):
  */
@@ -115,8 +130,8 @@
 
 void __iomem * __ioremap(phys_addr_t phys_addr, phys_addr_t size, unsigned long flags)
 {
+	unsigned long offset, pfn, last_pfn;
 	struct vm_struct * area;
-	unsigned long offset;
 	phys_addr_t last_addr;
 	void * addr;
 
@@ -136,18 +151,16 @@
 		return (void __iomem *) CKSEG1ADDR(phys_addr);
 
 	/*
-	 * Don't allow anybody to remap normal RAM that we're using..
+	 * Don't allow anybody to remap RAM that may be allocated by the page
+	 * allocator, since that could lead to races & data clobbering.
 	 */
-	if (phys_addr < virt_to_phys(high_memory)) {
-		char *t_addr, *t_end;
-		struct page *page;
-
-		t_addr = __va(phys_addr);
-		t_end = t_addr + (size - 1);
-
-		for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
-			if(!PageReserved(page))
-				return NULL;
+	pfn = PFN_DOWN(phys_addr);
+	last_pfn = PFN_DOWN(last_addr);
+	if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
+				  __ioremap_check_ram) == 1) {
+		WARN_ONCE(1, "ioremap on RAM at %pa - %pa\n",
+			  &phys_addr, &last_addr);
+		return NULL;
 	}
 
 	/*
--- linux-4.4.0.orig/arch/mips/mm/mmap.c
+++ linux-4.4.0/arch/mips/mm/mmap.c
@@ -92,7 +92,7 @@
 
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
--- linux-4.4.0.orig/arch/mips/mm/pgtable-32.c
+++ linux-4.4.0/arch/mips/mm/pgtable-32.c
@@ -51,15 +51,15 @@
 	/*
 	 * Fixed mappings:
 	 */
-	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
-	fixrange_init(vaddr, vaddr + FIXADDR_SIZE, pgd_base);
+	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1);
+	fixrange_init(vaddr & PMD_MASK, vaddr + FIXADDR_SIZE, pgd_base);
 
 #ifdef CONFIG_HIGHMEM
 	/*
 	 * Permanent kmaps:
 	 */
 	vaddr = PKMAP_BASE;
-	fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
+	fixrange_init(vaddr & PMD_MASK, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
 
 	pgd = swapper_pg_dir + __pgd_offset(vaddr);
 	pud = pud_offset(pgd, vaddr);
--- linux-4.4.0.orig/arch/mips/mm/sc-ip22.c
+++ linux-4.4.0/arch/mips/mm/sc-ip22.c
@@ -31,26 +31,40 @@
 	unsigned long tmp;
 
 	__asm__ __volatile__(
-	".set\tpush\t\t\t# indy_sc_wipe\n\t"
-	".set\tnoreorder\n\t"
-	".set\tmips3\n\t"
-	".set\tnoat\n\t"
-	"mfc0\t%2, $12\n\t"
-	"li\t$1, 0x80\t\t\t# Go 64 bit\n\t"
-	"mtc0\t$1, $12\n\t"
-
-	"dli\t$1, 0x9000000080000000\n\t"
-	"or\t%0, $1\t\t\t# first line to flush\n\t"
-	"or\t%1, $1\t\t\t# last line to flush\n\t"
-	".set\tat\n\t"
-
-	"1:\tsw\t$0, 0(%0)\n\t"
-	"bne\t%0, %1, 1b\n\t"
-	" daddu\t%0, 32\n\t"
-
-	"mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t"
-	"nop; nop; nop; nop;\n\t"
-	".set\tpop"
+	"	.set	push			# indy_sc_wipe		\n"
+	"	.set	noreorder					\n"
+	"	.set	mips3						\n"
+	"	.set	noat						\n"
+	"	mfc0	%2, $12						\n"
+	"	li	$1, 0x80		# Go 64 bit		\n"
+	"	mtc0	$1, $12						\n"
+	"								\n"
+	"	#							\n"
+	"	# Open code a dli $1, 0x9000000080000000		\n"
+	"	#							\n"
+	"	# Required because binutils 2.25 will happily accept	\n"
+	"	# 64 bit instructions in .set mips3 mode but puke on	\n"
+	"	# 64 bit constants when generating 32 bit ELF		\n"
+	"	#							\n"
+	"	lui	$1,0x9000					\n"
+	"	dsll	$1,$1,0x10					\n"
+	"	ori	$1,$1,0x8000					\n"
+	"	dsll	$1,$1,0x10					\n"
+	"								\n"
+	"	or	%0, $1			# first line to flush	\n"
+	"	or	%1, $1			# last line to flush	\n"
+	"	.set	at						\n"
+	"								\n"
+	"1:	sw	$0, 0(%0)					\n"
+	"	bne	%0, %1, 1b					\n"
+	"	 daddu	%0, 32						\n"
+	"								\n"
+	"	mtc0	%2, $12			# Back to 32 bit	\n"
+	"	nop				# pipeline hazard	\n"
+	"	nop							\n"
+	"	nop							\n"
+	"	nop							\n"
+	"	.set	pop						\n"
 	: "=r" (first), "=r" (last), "=&r" (tmp)
 	: "0" (first), "1" (last));
 }
--- linux-4.4.0.orig/arch/mips/mm/sc-mips.c
+++ linux-4.4.0/arch/mips/mm/sc-mips.c
@@ -164,11 +164,13 @@
 
 	sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE_MSK;
 	sets >>= CM_GCR_L2_CONFIG_SET_SIZE_SHF;
-	c->scache.sets = 64 << sets;
+	if (sets)
+		c->scache.sets = 64 << sets;
 
 	line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE_MSK;
 	line_sz >>= CM_GCR_L2_CONFIG_LINE_SIZE_SHF;
-	c->scache.linesz = 2 << line_sz;
+	if (line_sz)
+		c->scache.linesz = 2 << line_sz;
 
 	assoc = cfg & CM_GCR_L2_CONFIG_ASSOC_MSK;
 	assoc >>= CM_GCR_L2_CONFIG_ASSOC_SHF;
@@ -176,9 +178,12 @@
 	c->scache.waysize = c->scache.sets * c->scache.linesz;
 	c->scache.waybit = __ffs(c->scache.waysize);
 
-	c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+	if (c->scache.linesz) {
+		c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+		return 1;
+	}
 
-	return 1;
+	return 0;
 }
 
 void __weak platform_early_l2_init(void)
--- linux-4.4.0.orig/arch/mips/mm/sc-rm7k.c
+++ linux-4.4.0/arch/mips/mm/sc-rm7k.c
@@ -161,7 +161,7 @@
 	local_irq_save(flags);
 	blast_rm7k_tcache();
 	clear_c0_config(RM7K_CONF_TE);
-	local_irq_save(flags);
+	local_irq_restore(flags);
 }
 
 static void rm7k_sc_disable(void)
--- linux-4.4.0.orig/arch/mips/mm/tlbex.c
+++ linux-4.4.0/arch/mips/mm/tlbex.c
@@ -242,7 +242,7 @@
 	pr_define("_PAGE_HUGE_SHIFT %d\n", _PAGE_HUGE_SHIFT);
 	pr_define("_PAGE_SPLITTING_SHIFT %d\n", _PAGE_SPLITTING_SHIFT);
 #endif
-#ifdef CONFIG_CPU_MIPSR2
+#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
 	if (cpu_has_rixi) {
 #ifdef _PAGE_NO_EXEC_SHIFT
 		pr_define("_PAGE_NO_EXEC_SHIFT %d\n", _PAGE_NO_EXEC_SHIFT);
@@ -757,7 +757,8 @@
 static void build_huge_handler_tail(u32 **p, struct uasm_reloc **r,
 				    struct uasm_label **l,
 				    unsigned int pte,
-				    unsigned int ptr)
+				    unsigned int ptr,
+				    unsigned int flush)
 {
 #ifdef CONFIG_SMP
 	UASM_i_SC(p, pte, 0, ptr);
@@ -766,6 +767,22 @@
 #else
 	UASM_i_SW(p, pte, 0, ptr);
 #endif
+	if (cpu_has_ftlb && flush) {
+		BUG_ON(!cpu_has_tlbinv);
+
+		UASM_i_MFC0(p, ptr, C0_ENTRYHI);
+		uasm_i_ori(p, ptr, ptr, MIPS_ENTRYHI_EHINV);
+		UASM_i_MTC0(p, ptr, C0_ENTRYHI);
+		build_tlb_write_entry(p, l, r, tlb_indexed);
+
+		uasm_i_xori(p, ptr, ptr, MIPS_ENTRYHI_EHINV);
+		UASM_i_MTC0(p, ptr, C0_ENTRYHI);
+		build_huge_update_entries(p, pte, ptr);
+		build_huge_tlb_write_entry(p, l, r, pte, tlb_random, 0);
+
+		return;
+	}
+
 	build_huge_update_entries(p, pte, ptr);
 	build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed, 0);
 }
@@ -2082,7 +2099,7 @@
 		uasm_l_tlbl_goaround2(&l, p);
 	}
 	uasm_i_ori(&p, wr.r1, wr.r1, (_PAGE_ACCESSED | _PAGE_VALID));
-	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2, 1);
 #endif
 
 	uasm_l_nopage_tlbl(&l, p);
@@ -2137,7 +2154,7 @@
 	build_tlb_probe_entry(&p);
 	uasm_i_ori(&p, wr.r1, wr.r1,
 		   _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
-	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2, 1);
 #endif
 
 	uasm_l_nopage_tlbs(&l, p);
@@ -2193,7 +2210,7 @@
 	build_tlb_probe_entry(&p);
 	uasm_i_ori(&p, wr.r1, wr.r1,
 		   _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
-	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
+	build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2, 0);
 #endif
 
 	uasm_l_nopage_tlbm(&l, p);
@@ -2312,9 +2329,7 @@
 	if (CONFIG_PGTABLE_LEVELS >= 3)
 		pwsize |= ilog2(PTRS_PER_PMD) << MIPS_PWSIZE_MDW_SHIFT;
 
-	/* If XPA has been enabled, PTEs are 64-bit in size. */
-	if (config_enabled(CONFIG_64BITS) || (read_c0_pagegrain() & PG_ELPA))
-		pwsize |= 1;
+	pwsize |= ilog2(sizeof(pte_t)/4) << MIPS_PWSIZE_PTEW_SHIFT;
 
 	write_c0_pwsize(pwsize);
 
--- linux-4.4.0.orig/arch/mips/mm/uasm-micromips.c
+++ linux-4.4.0/arch/mips/mm/uasm-micromips.c
@@ -75,7 +75,7 @@
 	{ insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS },
 	{ insn_lb, M(mm_lb32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
 	{ insn_ld, 0, 0 },
-	{ insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM },
+	{ insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
 	{ insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM },
 	{ insn_lld, 0, 0 },
 	{ insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM },
--- linux-4.4.0.orig/arch/mips/mm/uasm-mips.c
+++ linux-4.4.0/arch/mips/mm/uasm-mips.c
@@ -65,7 +65,7 @@
 #ifndef CONFIG_CPU_MIPSR6
 	{ insn_cache,  M(cache_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 #else
-	{ insn_cache,  M6(cache_op, 0, 0, 0, cache6_op),  RS | RT | SIMM9 },
+	{ insn_cache,  M6(spec3_op, 0, 0, 0, cache6_op),  RS | RT | SIMM9 },
 #endif
 	{ 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 },
--- linux-4.4.0.orig/arch/mips/mti-malta/malta-setup.c
+++ linux-4.4.0/arch/mips/mti-malta/malta-setup.c
@@ -39,6 +39,9 @@
 #include <linux/console.h>
 #endif
 
+#define ROCIT_CONFIG_GEN0		0x1f403000
+#define  ROCIT_CONFIG_GEN0_PCI_IOCU	BIT(7)
+
 extern void malta_be_init(void);
 extern int malta_be_handler(struct pt_regs *regs, int is_fixup);
 
@@ -107,6 +110,8 @@
 static int __init plat_enable_iocoherency(void)
 {
 	int supported = 0;
+	u32 cfg;
+
 	if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) {
 		if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) {
 			BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN;
@@ -129,7 +134,8 @@
 	} else if (mips_cm_numiocu() != 0) {
 		/* Nothing special needs to be done to enable coherency */
 		pr_info("CMP IOCU detected\n");
-		if ((*(unsigned int *)0xbf403000 & 0x81) != 0x81) {
+		cfg = __raw_readl((u32 *)CKSEG1ADDR(ROCIT_CONFIG_GEN0));
+		if (!(cfg & ROCIT_CONFIG_GEN0_PCI_IOCU)) {
 			pr_crit("IOCU OPERATION DISABLED BY SWITCH - DEFAULTING TO SW IO COHERENCY\n");
 			return 0;
 		}
--- linux-4.4.0.orig/arch/mips/net/bpf_jit.c
+++ linux-4.4.0/arch/mips/net/bpf_jit.c
@@ -527,7 +527,8 @@
 	u32 sflags, tmp_flags;
 
 	/* Adjust the stack pointer */
-	emit_stack_offset(-align_sp(offset), ctx);
+	if (offset)
+		emit_stack_offset(-align_sp(offset), ctx);
 
 	tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT;
 	/* sflags is essentially a bitmap */
@@ -579,7 +580,8 @@
 		emit_load_stack_reg(r_ra, r_sp, real_off, ctx);
 
 	/* Restore the sp and discard the scrach memory */
-	emit_stack_offset(align_sp(offset), ctx);
+	if (offset)
+		emit_stack_offset(align_sp(offset), ctx);
 }
 
 static unsigned int get_stack_depth(struct jit_ctx *ctx)
@@ -626,8 +628,14 @@
 	if (ctx->flags & SEEN_X)
 		emit_jit_reg_move(r_X, r_zero, ctx);
 
-	/* Do not leak kernel data to userspace */
-	if (bpf_needs_clear_a(&ctx->skf->insns[0]))
+	/*
+	 * Do not leak kernel data to userspace, we only need to clear
+	 * r_A if it is ever used.  In fact if it is never used, we
+	 * will not save/restore it, so clearing it in this case would
+	 * corrupt the state of the caller.
+	 */
+	if (bpf_needs_clear_a(&ctx->skf->insns[0]) &&
+	    (ctx->flags & SEEN_A))
 		emit_jit_reg_move(r_A, r_zero, ctx);
 }
 
@@ -1199,7 +1207,7 @@
 
 	memset(&ctx, 0, sizeof(ctx));
 
-	ctx.offsets = kcalloc(fp->len, sizeof(*ctx.offsets), GFP_KERNEL);
+	ctx.offsets = kcalloc(fp->len + 1, sizeof(*ctx.offsets), GFP_KERNEL);
 	if (ctx.offsets == NULL)
 		return;
 
--- linux-4.4.0.orig/arch/mips/net/bpf_jit_asm.S
+++ linux-4.4.0/arch/mips/net/bpf_jit_asm.S
@@ -90,18 +90,14 @@
 	is_offset_in_header(2, half)
 	/* Offset within header boundaries */
 	PTR_ADDU t1, $r_skb_data, offset
-	.set	reorder
-	lh	$r_A, 0(t1)
-	.set	noreorder
+	lhu	$r_A, 0(t1)
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
 # if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
-	wsbh	t0, $r_A
-	seh	$r_A, t0
+	wsbh	$r_A, $r_A
 # else
-	sll	t0, $r_A, 24
-	andi	t1, $r_A, 0xff00
-	sra	t0, t0, 16
-	srl	t1, t1, 8
+	sll	t0, $r_A, 8
+	srl	t1, $r_A, 8
+	andi	t0, t0, 0xff00
 	or	$r_A, t0, t1
 # endif
 #endif
@@ -115,7 +111,7 @@
 	is_offset_in_header(1, byte)
 	/* Offset within header boundaries */
 	PTR_ADDU t1, $r_skb_data, offset
-	lb	$r_A, 0(t1)
+	lbu	$r_A, 0(t1)
 	jr	$r_ra
 	 move	$r_ret, zero
 	END(sk_load_byte)
@@ -139,6 +135,11 @@
  * (void *to) is returned in r_s0
  *
  */
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#define DS_OFFSET(SIZE) (4 * SZREG)
+#else
+#define DS_OFFSET(SIZE) ((4 * SZREG) + (4 - SIZE))
+#endif
 #define bpf_slow_path_common(SIZE)				\
 	/* Quick check. Are we within reasonable boundaries? */ \
 	LONG_ADDIU	$r_s1, $r_skb_len, -SIZE;		\
@@ -150,7 +151,7 @@
 	PTR_LA		t0, skb_copy_bits;			\
 	PTR_S		$r_ra, (5 * SZREG)($r_sp);		\
 	/* Assign low slot to a2 */				\
-	move		a2, $r_sp;				\
+	PTR_ADDIU	a2, $r_sp, DS_OFFSET(SIZE);		\
 	jalr		t0;					\
 	/* Reset our destination slot (DS but it's ok) */	\
 	 INT_S		zero, (4 * SZREG)($r_sp);		\
--- linux-4.4.0.orig/arch/mips/netlogic/common/irq.c
+++ linux-4.4.0/arch/mips/netlogic/common/irq.c
@@ -275,7 +275,7 @@
 	do_IRQ(nlm_irq_to_xirq(node, i));
 }
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_CPU_XLP
 static const struct irq_domain_ops xlp_pic_irq_domain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
@@ -348,7 +348,7 @@
 #if defined(CONFIG_CPU_XLR)
 	nlm_setup_fmn_irq();
 #endif
-#if defined(CONFIG_OF)
+#ifdef CONFIG_CPU_XLP
 	of_irq_init(xlp_pic_irq_ids);
 #endif
 }
--- linux-4.4.0.orig/arch/mips/netlogic/common/reset.S
+++ linux-4.4.0/arch/mips/netlogic/common/reset.S
@@ -50,7 +50,6 @@
 #include <asm/netlogic/xlp-hal/sys.h>
 #include <asm/netlogic/xlp-hal/cpucontrol.h>
 
-#define CP0_EBASE	$15
 #define SYS_CPU_COHERENT_BASE	CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \
 			XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \
 			SYS_CPU_NONCOHERENT_MODE * 4
@@ -92,7 +91,7 @@
  * registers. On XLPII CPUs, usual cache instructions work.
  */
 .macro	xlp_flush_l1_dcache
-	mfc0	t0, CP0_EBASE, 0
+	mfc0	t0, CP0_PRID
 	andi	t0, t0, PRID_IMP_MASK
 	slt	t1, t0, 0x1200
 	beqz	t1, 15f
@@ -171,7 +170,7 @@
 	nop
 
 1:	/* Entry point on core wakeup */
-	mfc0	t0, CP0_EBASE, 0	/* processor ID */
+	mfc0	t0, CP0_PRID		/* processor ID */
 	andi	t0, PRID_IMP_MASK
 	li	t1, 0x1500		/* XLP 9xx */
 	beq	t0, t1, 2f		/* does not need to set coherent */
@@ -182,8 +181,8 @@
 	nop
 
 	/* set bit in SYS coherent register for the core */
-	mfc0	t0, CP0_EBASE, 1
-	mfc0	t1, CP0_EBASE, 1
+	mfc0	t0, CP0_EBASE
+	mfc0	t1, CP0_EBASE
 	srl	t1, 5
 	andi	t1, 0x3			/* t1 <- node */
 	li	t2, 0x40000
@@ -232,7 +231,7 @@
 
 	 * NOTE: All GPR contents are lost after the mtcr above!
 	 */
-	mfc0	v0, CP0_EBASE, 1
+	mfc0	v0, CP0_EBASE
 	andi	v0, 0x3ff		/* v0 <- node/core */
 
 	/*
--- linux-4.4.0.orig/arch/mips/netlogic/common/smpboot.S
+++ linux-4.4.0/arch/mips/netlogic/common/smpboot.S
@@ -48,8 +48,6 @@
 #include <asm/netlogic/xlp-hal/sys.h>
 #include <asm/netlogic/xlp-hal/cpucontrol.h>
 
-#define CP0_EBASE	$15
-
 	.set	noreorder
 	.set	noat
 	.set	arch=xlr		/* for mfcr/mtcr, XLR is sufficient */
@@ -86,7 +84,7 @@
 	PTR_L	gp, 0(t1)
 
 	/* a0 has the processor id */
-	mfc0	a0, CP0_EBASE, 1
+	mfc0	a0, CP0_EBASE
 	andi	a0, 0x3ff		/* a0 <- node/core */
 	PTR_LA	t0, nlm_early_init_secondary
 	jalr	t0
--- linux-4.4.0.orig/arch/mips/pci/msi-octeon.c
+++ linux-4.4.0/arch/mips/pci/msi-octeon.c
@@ -369,7 +369,9 @@
 	int irq;
 	struct irq_chip *msi;
 
-	if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE) {
+	if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_INVALID) {
+		return 0;
+	} else if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE) {
 		msi_rcv_reg[0] = CVMX_PEXP_NPEI_MSI_RCV0;
 		msi_rcv_reg[1] = CVMX_PEXP_NPEI_MSI_RCV1;
 		msi_rcv_reg[2] = CVMX_PEXP_NPEI_MSI_RCV2;
--- linux-4.4.0.orig/arch/mips/pci/pci-octeon.c
+++ linux-4.4.0/arch/mips/pci/pci-octeon.c
@@ -571,6 +571,11 @@
 	if (octeon_has_feature(OCTEON_FEATURE_PCIE))
 		return 0;
 
+	if (!octeon_is_pci_host()) {
+		pr_notice("Not in host mode, PCI Controller not initialized\n");
+		return 0;
+	}
+
 	/* Point pcibios_map_irq() to the PCI version of it */
 	octeon_pcibios_map_irq = octeon_pci_pcibios_map_irq;
 
@@ -582,11 +587,6 @@
 	else
 		octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_BIG;
 
-	if (!octeon_is_pci_host()) {
-		pr_notice("Not in host mode, PCI Controller not initialized\n");
-		return 0;
-	}
-
 	/* PCI I/O and PCI MEM values */
 	set_io_port_base(OCTEON_PCI_IOSPACE_BASE);
 	ioport_resource.start = 0;
--- linux-4.4.0.orig/arch/mips/pistachio/Platform
+++ linux-4.4.0/arch/mips/pistachio/Platform
@@ -6,3 +6,4 @@
 		-I$(srctree)/arch/mips/include/asm/mach-pistachio
 load-$(CONFIG_MACH_PISTACHIO)		+= 0xffffffff80400000
 zload-$(CONFIG_MACH_PISTACHIO)		+= 0xffffffff81000000
+all-$(CONFIG_MACH_PISTACHIO)		:= uImage.gz
--- linux-4.4.0.orig/arch/mips/ralink/mt7620.c
+++ linux-4.4.0/arch/mips/ralink/mt7620.c
@@ -81,7 +81,7 @@
 };
 static struct rt2880_pmx_func nd_sd_grp[] = {
 	FUNC("nand", MT7620_GPIO_MODE_NAND, 45, 15),
-	FUNC("sd", MT7620_GPIO_MODE_SD, 45, 15)
+	FUNC("sd", MT7620_GPIO_MODE_SD, 47, 13)
 };
 
 static struct rt2880_pmx_group mt7620a_pinmux_data[] = {
@@ -107,31 +107,31 @@
 };
 
 static struct rt2880_pmx_func pwm1_grp_mt7628[] = {
-	FUNC("sdcx", 3, 19, 1),
+	FUNC("sdxc d6", 3, 19, 1),
 	FUNC("utif", 2, 19, 1),
 	FUNC("gpio", 1, 19, 1),
-	FUNC("pwm", 0, 19, 1),
+	FUNC("pwm1", 0, 19, 1),
 };
 
 static struct rt2880_pmx_func pwm0_grp_mt7628[] = {
-	FUNC("sdcx", 3, 18, 1),
+	FUNC("sdxc d7", 3, 18, 1),
 	FUNC("utif", 2, 18, 1),
 	FUNC("gpio", 1, 18, 1),
-	FUNC("pwm", 0, 18, 1),
+	FUNC("pwm0", 0, 18, 1),
 };
 
 static struct rt2880_pmx_func uart2_grp_mt7628[] = {
-	FUNC("sdcx", 3, 20, 2),
+	FUNC("sdxc d5 d4", 3, 20, 2),
 	FUNC("pwm", 2, 20, 2),
 	FUNC("gpio", 1, 20, 2),
-	FUNC("uart", 0, 20, 2),
+	FUNC("uart2", 0, 20, 2),
 };
 
 static struct rt2880_pmx_func uart1_grp_mt7628[] = {
-	FUNC("sdcx", 3, 45, 2),
+	FUNC("sw_r", 3, 45, 2),
 	FUNC("pwm", 2, 45, 2),
 	FUNC("gpio", 1, 45, 2),
-	FUNC("uart", 0, 45, 2),
+	FUNC("uart1", 0, 45, 2),
 };
 
 static struct rt2880_pmx_func i2c_grp_mt7628[] = {
@@ -141,23 +141,23 @@
 	FUNC("i2c", 0, 4, 2),
 };
 
-static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("reclk", 0, 36, 1) };
-static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 37, 1) };
-static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 15, 38) };
+static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("refclk", 0, 37, 1) };
+static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 36, 1) };
+static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 38, 1) };
 static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) };
 
 static struct rt2880_pmx_func sd_mode_grp_mt7628[] = {
 	FUNC("jtag", 3, 22, 8),
 	FUNC("utif", 2, 22, 8),
 	FUNC("gpio", 1, 22, 8),
-	FUNC("sdcx", 0, 22, 8),
+	FUNC("sdxc", 0, 22, 8),
 };
 
 static struct rt2880_pmx_func uart0_grp_mt7628[] = {
 	FUNC("-", 3, 12, 2),
 	FUNC("-", 2, 12, 2),
 	FUNC("gpio", 1, 12, 2),
-	FUNC("uart", 0, 12, 2),
+	FUNC("uart0", 0, 12, 2),
 };
 
 static struct rt2880_pmx_func i2s_grp_mt7628[] = {
@@ -171,7 +171,7 @@
 	FUNC("-", 3, 6, 1),
 	FUNC("refclk", 2, 6, 1),
 	FUNC("gpio", 1, 6, 1),
-	FUNC("spi", 0, 6, 1),
+	FUNC("spi cs1", 0, 6, 1),
 };
 
 static struct rt2880_pmx_func spis_grp_mt7628[] = {
@@ -188,28 +188,44 @@
 	FUNC("gpio", 0, 11, 1),
 };
 
-#define MT7628_GPIO_MODE_MASK	0x3
-
-#define MT7628_GPIO_MODE_PWM1	30
-#define MT7628_GPIO_MODE_PWM0	28
-#define MT7628_GPIO_MODE_UART2	26
-#define MT7628_GPIO_MODE_UART1	24
-#define MT7628_GPIO_MODE_I2C	20
-#define MT7628_GPIO_MODE_REFCLK	18
-#define MT7628_GPIO_MODE_PERST	16
-#define MT7628_GPIO_MODE_WDT	14
-#define MT7628_GPIO_MODE_SPI	12
-#define MT7628_GPIO_MODE_SDMODE	10
-#define MT7628_GPIO_MODE_UART0	8
-#define MT7628_GPIO_MODE_I2S	6
-#define MT7628_GPIO_MODE_CS1	4
-#define MT7628_GPIO_MODE_SPIS	2
-#define MT7628_GPIO_MODE_GPIO	0
+static struct rt2880_pmx_func wled_kn_grp_mt7628[] = {
+	FUNC("rsvd", 3, 35, 1),
+	FUNC("rsvd", 2, 35, 1),
+	FUNC("gpio", 1, 35, 1),
+	FUNC("wled_kn", 0, 35, 1),
+};
+
+static struct rt2880_pmx_func wled_an_grp_mt7628[] = {
+	FUNC("rsvd", 3, 44, 1),
+	FUNC("rsvd", 2, 44, 1),
+	FUNC("gpio", 1, 44, 1),
+	FUNC("wled_an", 0, 44, 1),
+};
+
+#define MT7628_GPIO_MODE_MASK		0x3
+
+#define MT7628_GPIO_MODE_WLED_KN	48
+#define MT7628_GPIO_MODE_WLED_AN	32
+#define MT7628_GPIO_MODE_PWM1		30
+#define MT7628_GPIO_MODE_PWM0		28
+#define MT7628_GPIO_MODE_UART2		26
+#define MT7628_GPIO_MODE_UART1		24
+#define MT7628_GPIO_MODE_I2C		20
+#define MT7628_GPIO_MODE_REFCLK		18
+#define MT7628_GPIO_MODE_PERST		16
+#define MT7628_GPIO_MODE_WDT		14
+#define MT7628_GPIO_MODE_SPI		12
+#define MT7628_GPIO_MODE_SDMODE		10
+#define MT7628_GPIO_MODE_UART0		8
+#define MT7628_GPIO_MODE_I2S		6
+#define MT7628_GPIO_MODE_CS1		4
+#define MT7628_GPIO_MODE_SPIS		2
+#define MT7628_GPIO_MODE_GPIO		0
 
 static struct rt2880_pmx_group mt7628an_pinmux_data[] = {
-	GRP_G("pmw1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK,
+	GRP_G("pwm1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK,
 				1, MT7628_GPIO_MODE_PWM1),
-	GRP_G("pmw1", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK,
+	GRP_G("pwm0", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK,
 				1, MT7628_GPIO_MODE_PWM0),
 	GRP_G("uart2", uart2_grp_mt7628, MT7628_GPIO_MODE_MASK,
 				1, MT7628_GPIO_MODE_UART2),
@@ -233,6 +249,10 @@
 				1, MT7628_GPIO_MODE_SPIS),
 	GRP_G("gpio", gpio_grp_mt7628, MT7628_GPIO_MODE_MASK,
 				1, MT7628_GPIO_MODE_GPIO),
+	GRP_G("wled_an", wled_an_grp_mt7628, MT7628_GPIO_MODE_MASK,
+				1, MT7628_GPIO_MODE_WLED_AN),
+	GRP_G("wled_kn", wled_kn_grp_mt7628, MT7628_GPIO_MODE_MASK,
+				1, MT7628_GPIO_MODE_WLED_KN),
 	{ 0 }
 };
 
@@ -439,7 +459,7 @@
 	ralink_clk_add("10000c00.uartlite", periph_rate);
 	ralink_clk_add("10180000.wmac", xtal_rate);
 
-	if (IS_ENABLED(CONFIG_USB) && is_mt76x8()) {
+	if (IS_ENABLED(CONFIG_USB) && !is_mt76x8()) {
 		/*
 		 * When the CPU goes into sleep mode, the BUS clock will be
 		 * too low for USB to function properly. Adjust the busses
--- linux-4.4.0.orig/arch/mips/ralink/prom.c
+++ linux-4.4.0/arch/mips/ralink/prom.c
@@ -30,8 +30,10 @@
 	return soc_info.sys_type;
 }
 
-static __init void prom_init_cmdline(int argc, char **argv)
+static __init void prom_init_cmdline(void)
 {
+	int argc;
+	char **argv;
 	int i;
 
 	pr_debug("prom: fw_arg0=%08x fw_arg1=%08x fw_arg2=%08x fw_arg3=%08x\n",
@@ -60,14 +62,11 @@
 
 void __init prom_init(void)
 {
-	int argc;
-	char **argv;
-
 	prom_soc_init(&soc_info);
 
 	pr_info("SoC Type: %s\n", get_system_type());
 
-	prom_init_cmdline(argc, argv);
+	prom_init_cmdline();
 }
 
 void __init prom_free_prom_memory(void)
--- linux-4.4.0.orig/arch/mips/ralink/reset.c
+++ linux-4.4.0/arch/mips/ralink/reset.c
@@ -96,16 +96,9 @@
 	unreachable();
 }
 
-static void ralink_halt(void)
-{
-	local_irq_disable();
-	unreachable();
-}
-
 static int __init mips_reboot_setup(void)
 {
 	_machine_restart = ralink_restart;
-	_machine_halt = ralink_halt;
 
 	return 0;
 }
--- linux-4.4.0.orig/arch/mips/ralink/rt288x.c
+++ linux-4.4.0/arch/mips/ralink/rt288x.c
@@ -40,16 +40,6 @@
 	{ 0 }
 };
 
-static void rt288x_wdt_reset(void)
-{
-	u32 t;
-
-	/* enable WDT reset output on pin SRAM_CS_N */
-	t = rt_sysc_r32(SYSC_REG_CLKCFG);
-	t |= CLKCFG_SRAM_CS_N_WDT;
-	rt_sysc_w32(t, SYSC_REG_CLKCFG);
-}
-
 void __init ralink_clk_init(void)
 {
 	unsigned long cpu_rate, wmac_rate = 40000000;
@@ -119,5 +109,5 @@
 	soc_info->mem_size_max = RT2880_MEM_SIZE_MAX;
 
 	rt2880_pinmux_data = rt2880_pinmux_data_act;
-	ralink_soc == RT2880_SOC;
+	ralink_soc = RT2880_SOC;
 }
--- linux-4.4.0.orig/arch/mips/ralink/rt305x.c
+++ linux-4.4.0/arch/mips/ralink/rt305x.c
@@ -89,17 +89,6 @@
 	{ 0 }
 };
 
-static void rt305x_wdt_reset(void)
-{
-	u32 t;
-
-	/* enable WDT reset output on pin SRAM_CS_N */
-	t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG);
-	t |= RT305X_SYSCFG_SRAM_CS0_MODE_WDT <<
-		RT305X_SYSCFG_SRAM_CS0_MODE_SHIFT;
-	rt_sysc_w32(t, SYSC_REG_SYSTEM_CONFIG);
-}
-
 static unsigned long rt5350_get_mem_size(void)
 {
 	void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE);
--- linux-4.4.0.orig/arch/mips/ralink/rt3883.c
+++ linux-4.4.0/arch/mips/ralink/rt3883.c
@@ -36,7 +36,7 @@
 static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) };
 static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) };
 static struct rt2880_pmx_func lna_a_func[] = { FUNC("lna a", 0, 32, 3) };
-static struct rt2880_pmx_func lna_g_func[] = { FUNC("lna a", 0, 35, 3) };
+static struct rt2880_pmx_func lna_g_func[] = { FUNC("lna g", 0, 35, 3) };
 static struct rt2880_pmx_func pci_func[] = {
 	FUNC("pci-dev", 0, 40, 32),
 	FUNC("pci-host2", 1, 40, 32),
@@ -44,7 +44,7 @@
 	FUNC("pci-fnc", 3, 40, 32)
 };
 static struct rt2880_pmx_func ge1_func[] = { FUNC("ge1", 0, 72, 12) };
-static struct rt2880_pmx_func ge2_func[] = { FUNC("ge1", 0, 84, 12) };
+static struct rt2880_pmx_func ge2_func[] = { FUNC("ge2", 0, 84, 12) };
 
 static struct rt2880_pmx_group rt3883_pinmux_data[] = {
 	GRP("i2c", i2c_func, 1, RT3883_GPIO_MODE_I2C),
@@ -63,16 +63,6 @@
 	{ 0 }
 };
 
-static void rt3883_wdt_reset(void)
-{
-	u32 t;
-
-	/* enable WDT reset output on GPIO 2 */
-	t = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1);
-	t |= RT3883_SYSCFG1_GPIO2_AS_WDT_OUT;
-	rt_sysc_w32(t, RT3883_SYSC_REG_SYSCFG1);
-}
-
 void __init ralink_clk_init(void)
 {
 	unsigned long cpu_rate, sys_rate;
@@ -154,5 +144,5 @@
 
 	rt2880_pinmux_data = rt3883_pinmux_data;
 
-	ralink_soc == RT3883_SOC;
+	ralink_soc = RT3883_SOC;
 }
--- linux-4.4.0.orig/arch/mips/sgi-ip22/Platform
+++ linux-4.4.0/arch/mips/sgi-ip22/Platform
@@ -25,7 +25,7 @@
 # Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
 #
 ifdef CONFIG_SGI_IP28
-  ifeq ($(call cc-option-yn,-mr10k-cache-barrier=store), n)
+  ifeq ($(call cc-option-yn,-march=r10000 -mr10k-cache-barrier=store), n)
       $(error gcc doesn't support needed option -mr10k-cache-barrier=store)
   endif
 endif
--- linux-4.4.0.orig/arch/mips/sni/a20r.c
+++ linux-4.4.0/arch/mips/sni/a20r.c
@@ -143,7 +143,10 @@
 	},
 };
 
-static u32 a20r_ack_hwint(void)
+/*
+ * Trigger chipset to update CPU's CAUSE IP field
+ */
+static u32 a20r_update_cause_ip(void)
 {
 	u32 status = read_c0_status();
 
@@ -205,12 +208,14 @@
 	int irq;
 
 	clear_c0_status(IE_IRQ0);
-	status = a20r_ack_hwint();
+	status = a20r_update_cause_ip();
 	cause = read_c0_cause();
 
 	irq = ffs(((cause & status) >> 8) & 0xf8);
 	if (likely(irq > 0))
 		do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
+
+	a20r_update_cause_ip();
 	set_c0_status(IE_IRQ0);
 }
 
--- linux-4.4.0.orig/arch/mips/txx9/generic/setup.c
+++ linux-4.4.0/arch/mips/txx9/generic/setup.c
@@ -961,12 +961,11 @@
 		goto exit_put;
 	err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr);
 	if (err) {
-		device_unregister(&dev->dev);
 		iounmap(dev->base);
-		kfree(dev);
+		device_unregister(&dev->dev);
 	}
 	return;
 exit_put:
+	iounmap(dev->base);
 	put_device(&dev->dev);
-	return;
 }
--- linux-4.4.0.orig/arch/mips/txx9/rbtx4939/setup.c
+++ linux-4.4.0/arch/mips/txx9/rbtx4939/setup.c
@@ -186,7 +186,7 @@
 
 #define RBTX4939_MAX_7SEGLEDS	8
 
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
+#if IS_BUILTIN(CONFIG_LEDS_CLASS)
 static u8 led_val[RBTX4939_MAX_7SEGLEDS];
 struct rbtx4939_led_data {
 	struct led_classdev cdev;
@@ -261,7 +261,7 @@
 
 static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
 {
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
+#if IS_BUILTIN(CONFIG_LEDS_CLASS)
 	unsigned long flags;
 	local_irq_save(flags);
 	/* bit7: reserved for LED class */
--- linux-4.4.0.orig/arch/mips/vdso/Makefile
+++ linux-4.4.0/arch/mips/vdso/Makefile
@@ -5,10 +5,14 @@
 ccflags-vdso := \
 	$(filter -I%,$(KBUILD_CFLAGS)) \
 	$(filter -E%,$(KBUILD_CFLAGS)) \
-	$(filter -march=%,$(KBUILD_CFLAGS))
+	$(filter -mmicromips,$(KBUILD_CFLAGS)) \
+	$(filter -march=%,$(KBUILD_CFLAGS)) \
+	$(filter -m%-float,$(KBUILD_CFLAGS)) \
+	-D__VDSO__
 cflags-vdso := $(ccflags-vdso) \
 	$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
-	-O2 -g -fPIC -fno-common -fno-builtin -G 0 -DDISABLE_BRANCH_PROFILING \
+	-O2 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \
+	-DDISABLE_BRANCH_PROFILING \
 	$(call cc-option, -fno-stack-protector)
 aflags-vdso := $(ccflags-vdso) \
 	$(filter -I%,$(KBUILD_CFLAGS)) \
@@ -73,7 +77,7 @@
 $(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi)
 $(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi)
 
-$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi)
+$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi)
 
 $(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
 	$(call if_changed,vdsold)
@@ -105,7 +109,7 @@
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 
-$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := -mabi=32
+$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) -mabi=32
 $(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
 	$(call if_changed_dep,cpp_lds_S)
 
@@ -141,7 +145,7 @@
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 
-$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := -mabi=n32
+$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) -mabi=n32
 $(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
 	$(call if_changed_dep,cpp_lds_S)
 
--- linux-4.4.0.orig/arch/mips/vdso/genvdso.c
+++ linux-4.4.0/arch/mips/vdso/genvdso.c
@@ -126,6 +126,7 @@
 	if (fstat(fd, &stat) != 0) {
 		fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name,
 			path, strerror(errno));
+		close(fd);
 		return NULL;
 	}
 
@@ -134,6 +135,7 @@
 	if (addr == MAP_FAILED) {
 		fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name,
 			path, strerror(errno));
+		close(fd);
 		return NULL;
 	}
 
@@ -143,6 +145,7 @@
 	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
 		fprintf(stderr, "%s: '%s' is not an ELF file\n", program_name,
 			path);
+		close(fd);
 		return NULL;
 	}
 
@@ -154,6 +157,7 @@
 	default:
 		fprintf(stderr, "%s: '%s' has invalid ELF class\n",
 			program_name, path);
+		close(fd);
 		return NULL;
 	}
 
@@ -165,6 +169,7 @@
 	default:
 		fprintf(stderr, "%s: '%s' has invalid ELF data order\n",
 			program_name, path);
+		close(fd);
 		return NULL;
 	}
 
@@ -172,15 +177,18 @@
 		fprintf(stderr,
 			"%s: '%s' has invalid ELF machine (expected EM_MIPS)\n",
 			program_name, path);
+		close(fd);
 		return NULL;
 	} else if (swap_uint16(ehdr->e_type) != ET_DYN) {
 		fprintf(stderr,
 			"%s: '%s' has invalid ELF type (expected ET_DYN)\n",
 			program_name, path);
+		close(fd);
 		return NULL;
 	}
 
 	*_size = stat.st_size;
+	close(fd);
 	return addr;
 }
 
@@ -284,10 +292,12 @@
 	/* Calculate and write symbol offsets to <output file> */
 	if (!get_symbols(dbg_vdso_path, dbg_vdso)) {
 		unlink(out_path);
+		fclose(out_file);
 		return EXIT_FAILURE;
 	}
 
 	fprintf(out_file, "};\n");
+	fclose(out_file);
 
 	return EXIT_SUCCESS;
 }
--- linux-4.4.0.orig/arch/mn10300/include/asm/uaccess.h
+++ linux-4.4.0/arch/mn10300/include/asm/uaccess.h
@@ -181,6 +181,7 @@
 		"2:\n"						\
 		"	.section	.fixup,\"ax\"\n"	\
 		"3:\n\t"					\
+		"	mov		0,%1\n"			\
 		"	mov		%3,%0\n"		\
 		"	jmp		2b\n"			\
 		"	.previous\n"				\
--- linux-4.4.0.orig/arch/mn10300/lib/usercopy.c
+++ linux-4.4.0/arch/mn10300/lib/usercopy.c
@@ -9,7 +9,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the Licence, or (at your option) any later version.
  */
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 unsigned long
 __generic_copy_to_user(void *to, const void *from, unsigned long n)
@@ -24,6 +24,8 @@
 {
 	if (access_ok(VERIFY_READ, from, n))
 		__copy_user_zeroing(to, from, n);
+	else
+		memset(to, 0, n);
 	return n;
 }
 
--- linux-4.4.0.orig/arch/mn10300/mm/misalignment.c
+++ linux-4.4.0/arch/mn10300/mm/misalignment.c
@@ -437,7 +437,7 @@
 
 	info.si_signo	= SIGSEGV;
 	info.si_errno	= 0;
-	info.si_code	= 0;
+	info.si_code	= SEGV_MAPERR;
 	info.si_addr	= (void *) regs->pc;
 	force_sig_info(SIGSEGV, &info, current);
 	return;
--- linux-4.4.0.orig/arch/nios2/include/asm/uaccess.h
+++ linux-4.4.0/arch/nios2/include/asm/uaccess.h
@@ -102,9 +102,12 @@
 static inline long copy_from_user(void *to, const void __user *from,
 				unsigned long n)
 {
-	if (!access_ok(VERIFY_READ, from, n))
-		return n;
-	return __copy_from_user(to, from, n);
+	unsigned long res = n;
+	if (access_ok(VERIFY_READ, from, n))
+		res = __copy_from_user(to, from, n);
+	if (unlikely(res))
+		memset(to + (n - res), 0, res);
+	return res;
 }
 
 static inline long copy_to_user(void __user *to, const void *from,
@@ -139,7 +142,7 @@
 
 #define __get_user_unknown(val, size, ptr, err) do {			\
 	err = 0;							\
-	if (copy_from_user(&(val), ptr, size)) {			\
+	if (__copy_from_user(&(val), ptr, size)) {			\
 		err = -EFAULT;						\
 	}								\
 	} while (0)
@@ -166,7 +169,7 @@
 	({								\
 	long __gu_err = -EFAULT;					\
 	const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);		\
-	unsigned long __gu_val;						\
+	unsigned long __gu_val = 0;					\
 	__get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\
 	(x) = (__force __typeof__(x))__gu_val;				\
 	__gu_err;							\
--- linux-4.4.0.orig/arch/nios2/kernel/nios2_ksyms.c
+++ linux-4.4.0/arch/nios2/kernel/nios2_ksyms.c
@@ -9,12 +9,20 @@
 #include <linux/export.h>
 #include <linux/string.h>
 
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+
 /* string functions */
 
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memmove);
 
+/* memory management */
+
+EXPORT_SYMBOL(empty_zero_page);
+EXPORT_SYMBOL(flush_icache_range);
+
 /*
  * libgcc functions - functions that are used internally by the
  * compiler...  (prototypes are not correct though, but that
@@ -31,3 +39,7 @@
 DECLARE_EXPORT(__umoddi3);
 DECLARE_EXPORT(__umodsi3);
 DECLARE_EXPORT(__muldi3);
+DECLARE_EXPORT(__ucmpdi2);
+DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__ashrdi3);
--- linux-4.4.0.orig/arch/nios2/kernel/prom.c
+++ linux-4.4.0/arch/nios2/kernel/prom.c
@@ -48,6 +48,13 @@
 	return alloc_bootmem_align(size, align);
 }
 
+int __init early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size,
+					     bool nomap)
+{
+	reserve_bootmem(base, size, BOOTMEM_DEFAULT);
+	return 0;
+}
+
 void __init early_init_devtree(void *params)
 {
 	__be32 *dtb = (u32 *)__dtb_start;
--- linux-4.4.0.orig/arch/nios2/kernel/setup.c
+++ linux-4.4.0/arch/nios2/kernel/setup.c
@@ -195,6 +195,9 @@
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
 
+	early_init_fdt_reserve_self();
+	early_init_fdt_scan_reserved_mem();
+
 	unflatten_and_copy_device_tree();
 
 	setup_cpuinfo();
--- linux-4.4.0.orig/arch/openrisc/include/asm/uaccess.h
+++ linux-4.4.0/arch/openrisc/include/asm/uaccess.h
@@ -215,7 +215,7 @@
 	case 1: __get_user_asm(x, ptr, retval, "l.lbz"); break;		\
 	case 2: __get_user_asm(x, ptr, retval, "l.lhz"); break;		\
 	case 4: __get_user_asm(x, ptr, retval, "l.lwz"); break;		\
-	case 8: __get_user_asm2(x, ptr, retval);			\
+	case 8: __get_user_asm2(x, ptr, retval); break;			\
 	default: (x) = __get_user_bad();				\
 	}								\
 } while (0)
@@ -273,28 +273,20 @@
 static inline unsigned long
 copy_from_user(void *to, const void *from, unsigned long n)
 {
-	unsigned long over;
+	unsigned long res = n;
 
-	if (access_ok(VERIFY_READ, from, n))
-		return __copy_tofrom_user(to, from, n);
-	if ((unsigned long)from < TASK_SIZE) {
-		over = (unsigned long)from + n - TASK_SIZE;
-		return __copy_tofrom_user(to, from, n - over) + over;
-	}
-	return n;
+	if (likely(access_ok(VERIFY_READ, from, n)))
+		res = __copy_tofrom_user(to, from, n);
+	if (unlikely(res))
+		memset(to + (n - res), 0, res);
+	return res;
 }
 
 static inline unsigned long
 copy_to_user(void *to, const void *from, unsigned long n)
 {
-	unsigned long over;
-
-	if (access_ok(VERIFY_WRITE, to, n))
-		return __copy_tofrom_user(to, from, n);
-	if ((unsigned long)to < TASK_SIZE) {
-		over = (unsigned long)to + n - TASK_SIZE;
-		return __copy_tofrom_user(to, from, n - over) + over;
-	}
+	if (likely(access_ok(VERIFY_WRITE, to, n)))
+		n = __copy_tofrom_user(to, from, n);
 	return n;
 }
 
@@ -303,13 +295,8 @@
 static inline __must_check unsigned long
 clear_user(void *addr, unsigned long size)
 {
-
-	if (access_ok(VERIFY_WRITE, addr, size))
-		return __clear_user(addr, size);
-	if ((unsigned long)addr < TASK_SIZE) {
-		unsigned long over = (unsigned long)addr + size - TASK_SIZE;
-		return __clear_user(addr, size - over) + over;
-	}
+	if (likely(access_ok(VERIFY_WRITE, addr, size)))
+		size = __clear_user(addr, size);
 	return size;
 }
 
--- linux-4.4.0.orig/arch/openrisc/kernel/entry.S
+++ linux-4.4.0/arch/openrisc/kernel/entry.S
@@ -179,7 +179,7 @@
  *	 occured. in fact they never do. if you need them use
  *	 values saved on stack (for SPR_EPC, SPR_ESR) or content
  *       of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE()
- *       in 'arch/or32/kernel/head.S'
+ *       in 'arch/openrisc/kernel/head.S'
  */
 
 /* =====================================================[ exceptions] === */
@@ -1092,13 +1092,13 @@
 	l.movhi	r29,hi(sys_clone)
 	l.ori	r29,r29,lo(sys_clone)
 	l.j	_fork_save_extra_regs_and_call
-	 l.addi	r7,r1,0
+	 l.nop
 
 ENTRY(__sys_fork)
 	l.movhi	r29,hi(sys_fork)
 	l.ori	r29,r29,lo(sys_fork)
 	l.j	_fork_save_extra_regs_and_call
-	 l.addi	r3,r1,0
+	 l.nop
 
 ENTRY(sys_rt_sigreturn)
 	l.j	_sys_rt_sigreturn
--- linux-4.4.0.orig/arch/openrisc/kernel/head.S
+++ linux-4.4.0/arch/openrisc/kernel/head.S
@@ -1596,7 +1596,7 @@
 
 /*
  * .data section should be page aligned
- *	(look into arch/or32/kernel/vmlinux.lds)
+ *	(look into arch/openrisc/kernel/vmlinux.lds.S)
  */
 	.section .data,"aw"
 	.align	8192
--- linux-4.4.0.orig/arch/openrisc/kernel/process.c
+++ linux-4.4.0/arch/openrisc/kernel/process.c
@@ -152,8 +152,6 @@
 
 	top_of_kernel_stack = sp;
 
-	p->set_child_tid = p->clear_child_tid = NULL;
-
 	/* Locate userspace context on stack... */
 	sp -= STACK_FRAME_OVERHEAD;	/* redzone */
 	sp -= sizeof(struct pt_regs);
--- linux-4.4.0.orig/arch/openrisc/kernel/traps.c
+++ linux-4.4.0/arch/openrisc/kernel/traps.c
@@ -302,12 +302,12 @@
 	siginfo_t info;
 
 	if (user_mode(regs)) {
-		/* Send a SIGSEGV */
-		info.si_signo = SIGSEGV;
+		/* Send a SIGBUS */
+		info.si_signo = SIGBUS;
 		info.si_errno = 0;
-		/* info.si_code has been set above */
-		info.si_addr = (void *)address;
-		force_sig_info(SIGSEGV, &info, current);
+		info.si_code = BUS_ADRALN;
+		info.si_addr = (void __user *)address;
+		force_sig_info(SIGBUS, &info, current);
 	} else {
 		printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
 		show_registers(regs);
--- linux-4.4.0.orig/arch/openrisc/kernel/vmlinux.lds.S
+++ linux-4.4.0/arch/openrisc/kernel/vmlinux.lds.S
@@ -38,6 +38,8 @@
         /* Read-only sections, merged into text segment: */
         . = LOAD_BASE ;
 
+	_text = .;
+
 	/* _s_kernel_ro must be page aligned */
 	. = ALIGN(PAGE_SIZE);
 	_s_kernel_ro = .;
--- linux-4.4.0.orig/arch/parisc/Kconfig
+++ linux-4.4.0/arch/parisc/Kconfig
@@ -177,7 +177,7 @@
 
 config MLONGCALLS
 	bool "Enable the -mlong-calls compiler option for big kernels"
-	def_bool y if (!MODULES)
+	default y
 	depends on PA8X00
 	help
 	  If you configure the kernel to include many drivers built-in instead
--- linux-4.4.0.orig/arch/parisc/include/asm/atomic.h
+++ linux-4.4.0/arch/parisc/include/asm/atomic.h
@@ -208,6 +208,8 @@
 	_atomic_spin_unlock_irqrestore(v, flags);
 }
 
+#define atomic64_set_release(v, i)	atomic64_set((v), (i))
+
 static __inline__ s64
 atomic64_read(const atomic64_t *v)
 {
--- linux-4.4.0.orig/arch/parisc/include/asm/barrier.h
+++ linux-4.4.0/arch/parisc/include/asm/barrier.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_BARRIER_H
+#define __ASM_BARRIER_H
+
+#ifndef __ASSEMBLY__
+
+/* The synchronize caches instruction executes as a nop on systems in
+   which all memory references are performed in order. */
+#define synchronize_caches() __asm__ __volatile__ ("sync" : : : "memory")
+
+#if defined(CONFIG_SMP)
+#define mb()		do { synchronize_caches(); } while (0)
+#define rmb()		mb()
+#define wmb()		mb()
+#define dma_rmb()	mb()
+#define dma_wmb()	mb()
+#else
+#define mb()		barrier()
+#define rmb()		barrier()
+#define wmb()		barrier()
+#define dma_rmb()	barrier()
+#define dma_wmb()	barrier()
+#endif
+
+#define __smp_mb()	mb()
+#define __smp_rmb()	mb()
+#define __smp_wmb()	mb()
+
+#include <asm-generic/barrier.h>
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_BARRIER_H */
--- linux-4.4.0.orig/arch/parisc/include/asm/bitops.h
+++ linux-4.4.0/arch/parisc/include/asm/bitops.h
@@ -6,7 +6,7 @@
 #endif
 
 #include <linux/compiler.h>
-#include <asm/types.h>		/* for BITS_PER_LONG/SHIFT_PER_LONG */
+#include <asm/types.h>
 #include <asm/byteorder.h>
 #include <asm/barrier.h>
 #include <linux/atomic.h>
@@ -17,6 +17,12 @@
  * to include/asm-i386/bitops.h or kerneldoc
  */
 
+#if __BITS_PER_LONG == 64
+#define SHIFT_PER_LONG 6
+#else
+#define SHIFT_PER_LONG 5
+#endif
+
 #define CHOP_SHIFTCOUNT(x) (((unsigned long) (x)) & (BITS_PER_LONG - 1))
 
 
--- linux-4.4.0.orig/arch/parisc/include/asm/cache.h
+++ linux-4.4.0/arch/parisc/include/asm/cache.h
@@ -22,6 +22,9 @@
 
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
+/* Read-only memory is marked before mark_rodata_ro() is called. */
+#define __ro_after_init	__read_mostly
+
 void parisc_cache_init(void);	/* initializes cache-flushing */
 void disable_sr_hashing_asm(int); /* low level support for above */
 void disable_sr_hashing(void);   /* turns off space register hashing */
--- linux-4.4.0.orig/arch/parisc/include/asm/cmpxchg.h
+++ linux-4.4.0/arch/parisc/include/asm/cmpxchg.h
@@ -43,8 +43,14 @@
 **		if (((unsigned long)p & 0xf) == 0)
 **			return __ldcw(p);
 */
-#define xchg(ptr, x) \
-	((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+#define xchg(ptr, x)							\
+({									\
+	__typeof__(*(ptr)) __ret;					\
+	__typeof__(*(ptr)) _x_ = (x);					\
+	__ret = (__typeof__(*(ptr)))					\
+		__xchg((unsigned long)_x_, (ptr), sizeof(*(ptr)));	\
+	__ret;								\
+})
 
 /* bug catcher for when unsupported size is used - won't link */
 extern void __cmpxchg_called_with_bad_pointer(void);
--- linux-4.4.0.orig/arch/parisc/include/asm/dma-mapping.h
+++ linux-4.4.0/arch/parisc/include/asm/dma-mapping.h
@@ -39,6 +39,8 @@
 ** flush/purge and allocate "regular" cacheable pages for everything.
 */
 
+#define DMA_ERROR_CODE	(~(dma_addr_t)0)
+
 #ifdef CONFIG_PA11
 extern struct hppa_dma_ops pcxl_dma_ops;
 extern struct hppa_dma_ops pcx_dma_ops;
@@ -209,12 +211,13 @@
 			break;
 		}
 	}
-	BUG_ON(!dev->platform_data);
 	return dev->platform_data;
 }
-		
-#define GET_IOC(dev) (HBA_DATA(parisc_walk_tree(dev))->iommu)
-	
+
+#define GET_IOC(dev) ({					\
+	void *__pdata = parisc_walk_tree(dev);		\
+	__pdata ? HBA_DATA(__pdata)->iommu : NULL;	\
+})
 
 #ifdef CONFIG_IOMMU_CCIO
 struct parisc_device;
--- linux-4.4.0.orig/arch/parisc/include/asm/futex.h
+++ linux-4.4.0/arch/parisc/include/asm/futex.h
@@ -32,20 +32,11 @@
 }
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
 	unsigned long int flags;
 	u32 val;
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -98,17 +89,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/parisc/include/asm/hugetlb.h
+++ linux-4.4.0/arch/parisc/include/asm/hugetlb.h
@@ -54,24 +54,12 @@
 	return pte_wrprotect(pte);
 }
 
-static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
-					   unsigned long addr, pte_t *ptep)
-{
-	pte_t old_pte = *ptep;
-	set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
-}
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+					   unsigned long addr, pte_t *ptep);
 
-static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
 					     unsigned long addr, pte_t *ptep,
-					     pte_t pte, int dirty)
-{
-	int changed = !pte_same(*ptep, pte);
-	if (changed) {
-		set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
-		flush_tlb_page(vma, addr);
-	}
-	return changed;
-}
+					     pte_t pte, int dirty);
 
 static inline pte_t huge_ptep_get(pte_t *ptep)
 {
--- linux-4.4.0.orig/arch/parisc/include/asm/ldcw.h
+++ linux-4.4.0/arch/parisc/include/asm/ldcw.h
@@ -11,6 +11,7 @@
    for the semaphore.  */
 
 #define __PA_LDCW_ALIGNMENT	16
+#define __PA_LDCW_ALIGN_ORDER	4
 #define __ldcw_align(a) ({					\
 	unsigned long __ret = (unsigned long) &(a)->lock[0];	\
 	__ret = (__ret + __PA_LDCW_ALIGNMENT - 1)		\
@@ -28,6 +29,7 @@
    ldcd). */
 
 #define __PA_LDCW_ALIGNMENT	4
+#define __PA_LDCW_ALIGN_ORDER	2
 #define __ldcw_align(a) (&(a)->slock)
 #define __LDCW	"ldcw,co"
 
--- linux-4.4.0.orig/arch/parisc/include/asm/mmu_context.h
+++ linux-4.4.0/arch/parisc/include/asm/mmu_context.h
@@ -49,15 +49,26 @@
 	mtctl(__space_to_prot(context), 8);
 }
 
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
+static inline void switch_mm_irqs_off(struct mm_struct *prev,
+		struct mm_struct *next, struct task_struct *tsk)
 {
-
 	if (prev != next) {
 		mtctl(__pa(next->pgd), 25);
 		load_context(next->context);
 	}
 }
 
+static inline void switch_mm(struct mm_struct *prev,
+		struct mm_struct *next, struct task_struct *tsk)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	switch_mm_irqs_off(prev, next, tsk);
+	local_irq_restore(flags);
+}
+#define switch_mm_irqs_off switch_mm_irqs_off
+
 #define deactivate_mm(tsk,mm)	do { } while (0)
 
 static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
--- linux-4.4.0.orig/arch/parisc/include/asm/pgtable.h
+++ linux-4.4.0/arch/parisc/include/asm/pgtable.h
@@ -65,9 +65,9 @@
 		unsigned long flags;				\
 		spin_lock_irqsave(&pa_tlb_lock, flags);		\
 		old_pte = *ptep;				\
-		set_pte(ptep, pteval);				\
 		if (pte_inserted(old_pte))			\
 			purge_tlb_entries(mm, addr);		\
+		set_pte(ptep, pteval);				\
 		spin_unlock_irqrestore(&pa_tlb_lock, flags);	\
 	} while (0)
 
@@ -83,10 +83,10 @@
 	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
 
 /* This is the size of the initially mapped kernel memory */
-#ifdef CONFIG_64BIT
-#define KERNEL_INITIAL_ORDER	25	/* 1<<25 = 32MB */
+#if defined(CONFIG_64BIT)
+#define KERNEL_INITIAL_ORDER	26	/* 1<<26 = 64MB */
 #else
-#define KERNEL_INITIAL_ORDER	24	/* 1<<24 = 16MB */
+#define KERNEL_INITIAL_ORDER	25	/* 1<<25 = 32MB */
 #endif
 #define KERNEL_INITIAL_SIZE	(1 << KERNEL_INITIAL_ORDER)
 
@@ -478,8 +478,8 @@
 		spin_unlock_irqrestore(&pa_tlb_lock, flags);
 		return 0;
 	}
-	set_pte(ptep, pte_mkold(pte));
 	purge_tlb_entries(vma->vm_mm, addr);
+	set_pte(ptep, pte_mkold(pte));
 	spin_unlock_irqrestore(&pa_tlb_lock, flags);
 	return 1;
 }
@@ -492,9 +492,9 @@
 
 	spin_lock_irqsave(&pa_tlb_lock, flags);
 	old_pte = *ptep;
-	set_pte(ptep, __pte(0));
 	if (pte_inserted(old_pte))
 		purge_tlb_entries(mm, addr);
+	set_pte(ptep, __pte(0));
 	spin_unlock_irqrestore(&pa_tlb_lock, flags);
 
 	return old_pte;
@@ -504,8 +504,8 @@
 {
 	unsigned long flags;
 	spin_lock_irqsave(&pa_tlb_lock, flags);
-	set_pte(ptep, pte_wrprotect(*ptep));
 	purge_tlb_entries(mm, addr);
+	set_pte(ptep, pte_wrprotect(*ptep));
 	spin_unlock_irqrestore(&pa_tlb_lock, flags);
 }
 
--- linux-4.4.0.orig/arch/parisc/include/asm/spinlock.h
+++ linux-4.4.0/arch/parisc/include/asm/spinlock.h
@@ -21,7 +21,6 @@
 {
 	volatile unsigned int *a;
 
-	mb();
 	a = __ldcw_align(x);
 	while (__ldcw(a) == 0)
 		while (*a == 0)
@@ -31,16 +30,15 @@
 				local_irq_disable();
 			} else
 				cpu_relax();
-	mb();
 }
 
 static inline void arch_spin_unlock(arch_spinlock_t *x)
 {
 	volatile unsigned int *a;
-	mb();
+
 	a = __ldcw_align(x);
-	*a = 1;
 	mb();
+	*a = 1;
 }
 
 static inline int arch_spin_trylock(arch_spinlock_t *x)
@@ -48,10 +46,8 @@
 	volatile unsigned int *a;
 	int ret;
 
-	mb();
 	a = __ldcw_align(x);
         ret = __ldcw(a) != 0;
-	mb();
 
 	return ret;
 }
--- linux-4.4.0.orig/arch/parisc/include/asm/uaccess.h
+++ linux-4.4.0/arch/parisc/include/asm/uaccess.h
@@ -10,6 +10,7 @@
 #include <asm-generic/uaccess-unaligned.h>
 
 #include <linux/bug.h>
+#include <linux/string.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
@@ -76,6 +77,7 @@
  */
 struct exception_data {
 	unsigned long fault_ip;
+	unsigned long fault_gp;
 	unsigned long fault_space;
 	unsigned long fault_addr;
 };
@@ -244,13 +246,14 @@
                                           unsigned long n)
 {
         int sz = __compiletime_object_size(to);
-        int ret = -EFAULT;
+        unsigned long ret = n;
 
         if (likely(sz == -1 || !__builtin_constant_p(n) || sz >= n))
                 ret = __copy_from_user(to, from, n);
         else
                 copy_from_user_overflow();
-
+	if (unlikely(ret))
+		memset(to + (n - ret), 0, ret);
         return ret;
 }
 
--- linux-4.4.0.orig/arch/parisc/include/uapi/asm/bitsperlong.h
+++ linux-4.4.0/arch/parisc/include/uapi/asm/bitsperlong.h
@@ -3,10 +3,8 @@
 
 #if defined(__LP64__)
 #define __BITS_PER_LONG 64
-#define SHIFT_PER_LONG 6
 #else
 #define __BITS_PER_LONG 32
-#define SHIFT_PER_LONG 5
 #endif
 
 #include <asm-generic/bitsperlong.h>
--- linux-4.4.0.orig/arch/parisc/include/uapi/asm/errno.h
+++ linux-4.4.0/arch/parisc/include/uapi/asm/errno.h
@@ -97,10 +97,10 @@
 #define	ENOTCONN	235	/* Transport endpoint is not connected */
 #define	ESHUTDOWN	236	/* Cannot send after transport endpoint shutdown */
 #define	ETOOMANYREFS	237	/* Too many references: cannot splice */
-#define EREFUSED	ECONNREFUSED	/* for HP's NFS apparently */
 #define	ETIMEDOUT	238	/* Connection timed out */
 #define	ECONNREFUSED	239	/* Connection refused */
-#define EREMOTERELEASE	240	/* Remote peer released connection */
+#define	EREFUSED	ECONNREFUSED	/* for HP's NFS apparently */
+#define	EREMOTERELEASE	240	/* Remote peer released connection */
 #define	EHOSTDOWN	241	/* Host is down */
 #define	EHOSTUNREACH	242	/* No route to host */
 
--- linux-4.4.0.orig/arch/parisc/include/uapi/asm/siginfo.h
+++ linux-4.4.0/arch/parisc/include/uapi/asm/siginfo.h
@@ -1,6 +1,10 @@
 #ifndef _PARISC_SIGINFO_H
 #define _PARISC_SIGINFO_H
 
+#if defined(__LP64__)
+#define __ARCH_SI_PREAMBLE_SIZE   (4 * sizeof(int))
+#endif
+
 #include <asm-generic/siginfo.h>
 
 #undef NSIGTRAP
--- linux-4.4.0.orig/arch/parisc/include/uapi/asm/swab.h
+++ linux-4.4.0/arch/parisc/include/uapi/asm/swab.h
@@ -1,6 +1,7 @@
 #ifndef _PARISC_SWAB_H
 #define _PARISC_SWAB_H
 
+#include <asm/bitsperlong.h>
 #include <linux/types.h>
 #include <linux/compiler.h>
 
@@ -38,7 +39,7 @@
 }
 #define __arch_swab32 __arch_swab32
 
-#if BITS_PER_LONG > 32
+#if __BITS_PER_LONG > 32
 /*
 ** From "PA-RISC 2.0 Architecture", HP Professional Books.
 ** See Appendix I page 8 , "Endian Byte Swapping".
@@ -61,6 +62,6 @@
 	return x;
 }
 #define __arch_swab64 __arch_swab64
-#endif /* BITS_PER_LONG > 32 */
+#endif /* __BITS_PER_LONG > 32 */
 
 #endif /* _PARISC_SWAB_H */
--- linux-4.4.0.orig/arch/parisc/kernel/asm-offsets.c
+++ linux-4.4.0/arch/parisc/kernel/asm-offsets.c
@@ -299,6 +299,7 @@
 #endif
 	BLANK();
 	DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip));
+	DEFINE(EXCDATA_GP, offsetof(struct exception_data, fault_gp));
 	DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space));
 	DEFINE(EXCDATA_ADDR, offsetof(struct exception_data, fault_addr));
 	BLANK();
--- linux-4.4.0.orig/arch/parisc/kernel/cache.c
+++ linux-4.4.0/arch/parisc/kernel/cache.c
@@ -351,6 +351,7 @@
 {
 	unsigned long rangetime, alltime;
 	unsigned long size, start;
+	unsigned long threshold;
 
 	alltime = mfctl(16);
 	flush_data_cache();
@@ -364,26 +365,30 @@
 	printk(KERN_DEBUG "Whole cache flush %lu cycles, flushing %lu bytes %lu cycles\n",
 		alltime, size, rangetime);
 
-	/* Racy, but if we see an intermediate value, it's ok too... */
-	parisc_cache_flush_threshold = size * alltime / rangetime;
-
-	parisc_cache_flush_threshold = L1_CACHE_ALIGN(parisc_cache_flush_threshold);
-	if (!parisc_cache_flush_threshold)
-		parisc_cache_flush_threshold = FLUSH_THRESHOLD;
-
-	if (parisc_cache_flush_threshold > cache_info.dc_size)
-		parisc_cache_flush_threshold = cache_info.dc_size;
-
-	printk(KERN_INFO "Setting cache flush threshold to %lu kB\n",
+	threshold = L1_CACHE_ALIGN(size * alltime / rangetime);
+	if (threshold > cache_info.dc_size)
+		threshold = cache_info.dc_size;
+	if (threshold)
+		parisc_cache_flush_threshold = threshold;
+	printk(KERN_INFO "Cache flush threshold set to %lu KiB\n",
 		parisc_cache_flush_threshold/1024);
 
 	/* calculate TLB flush threshold */
 
+	/* On SMP machines, skip the TLB measure of kernel text which
+	 * has been mapped as huge pages. */
+	if (num_online_cpus() > 1 && !parisc_requires_coherency()) {
+		threshold = max(cache_info.it_size, cache_info.dt_size);
+		threshold *= PAGE_SIZE;
+		threshold /= num_online_cpus();
+		goto set_tlb_threshold;
+	}
+
 	alltime = mfctl(16);
 	flush_tlb_all();
 	alltime = mfctl(16) - alltime;
 
-	size = PAGE_SIZE;
+	size = 0;
 	start = (unsigned long) _text;
 	rangetime = mfctl(16);
 	while (start < (unsigned long) _end) {
@@ -396,13 +401,12 @@
 	printk(KERN_DEBUG "Whole TLB flush %lu cycles, flushing %lu bytes %lu cycles\n",
 		alltime, size, rangetime);
 
-	parisc_tlb_flush_threshold = size * alltime / rangetime;
-	parisc_tlb_flush_threshold *= num_online_cpus();
-	parisc_tlb_flush_threshold = PAGE_ALIGN(parisc_tlb_flush_threshold);
-	if (!parisc_tlb_flush_threshold)
-		parisc_tlb_flush_threshold = FLUSH_TLB_THRESHOLD;
+	threshold = PAGE_ALIGN(num_online_cpus() * size * alltime / rangetime);
 
-	printk(KERN_INFO "Setting TLB flush threshold to %lu kB\n",
+set_tlb_threshold:
+	if (threshold)
+		parisc_tlb_flush_threshold = threshold;
+	printk(KERN_INFO "TLB flush threshold set to %lu KiB\n",
 		parisc_tlb_flush_threshold/1024);
 }
 
--- linux-4.4.0.orig/arch/parisc/kernel/drivers.c
+++ linux-4.4.0/arch/parisc/kernel/drivers.c
@@ -648,6 +648,10 @@
 					(modpath->mod == PCI_FUNC(devfn)));
 	}
 
+	/* index might be out of bounds for bc[] */
+	if (index >= 6)
+		return 0;
+
 	id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5);
 	return (modpath->bc[index] == id);
 }
--- linux-4.4.0.orig/arch/parisc/kernel/entry.S
+++ linux-4.4.0/arch/parisc/kernel/entry.S
@@ -35,6 +35,7 @@
 #include <asm/pgtable.h>
 #include <asm/signal.h>
 #include <asm/unistd.h>
+#include <asm/ldcw.h>
 #include <asm/thread_info.h>
 
 #include <linux/linkage.h>
@@ -46,6 +47,14 @@
 #endif
 
 	.import		pa_tlb_lock,data
+	.macro  load_pa_tlb_lock reg
+#if __PA_LDCW_ALIGNMENT > 4
+	load32	PA(pa_tlb_lock) + __PA_LDCW_ALIGNMENT-1, \reg
+	depi	0,31,__PA_LDCW_ALIGN_ORDER, \reg
+#else
+	load32	PA(pa_tlb_lock), \reg
+#endif
+	.endm
 
 	/* space_to_prot macro creates a prot id from a space id */
 
@@ -176,7 +185,7 @@
 	bv,n	0(%r3)
 	nop
 	.word	0		/* checksum (will be patched) */
-	.word	PA(os_hpmc)	/* address of handler */
+	.word	0		/* address of handler */
 	.word	0		/* length of handler */
 	.endm
 
@@ -457,7 +466,7 @@
 	.macro		tlb_lock	spc,ptp,pte,tmp,tmp1,fault
 #ifdef CONFIG_SMP
 	cmpib,COND(=),n	0,\spc,2f
-	load32		PA(pa_tlb_lock),\tmp
+	load_pa_tlb_lock \tmp
 1:	LDCW		0(\tmp),\tmp1
 	cmpib,COND(=)	0,\tmp1,1b
 	nop
@@ -473,6 +482,8 @@
 	.macro		tlb_unlock0	spc,tmp
 #ifdef CONFIG_SMP
 	or,COND(=)	%r0,\spc,%r0
+	sync
+	or,COND(=)	%r0,\spc,%r0
 	stw             \spc,0(\tmp)
 #endif
 	.endm
@@ -480,7 +491,7 @@
 	/* Release pa_tlb_lock lock. */
 	.macro		tlb_unlock1	spc,tmp
 #ifdef CONFIG_SMP
-	load32		PA(pa_tlb_lock),\tmp
+	load_pa_tlb_lock \tmp
 	tlb_unlock0	\spc,\tmp
 #endif
 	.endm
--- linux-4.4.0.orig/arch/parisc/kernel/module.c
+++ linux-4.4.0/arch/parisc/kernel/module.c
@@ -42,9 +42,9 @@
  *      We are not doing SEGREL32 handling correctly. According to the ABI, we
  *      should do a value offset, like this:
  *			if (in_init(me, (void *)val))
- *				val -= (uint32_t)me->module_init;
+ *				val -= (uint32_t)me->init_layout.base;
  *			else
- *				val -= (uint32_t)me->module_core;
+ *				val -= (uint32_t)me->core_layout.base;
  *	However, SEGREL32 is used only for PARISC unwind entries, and we want
  *	those entries to have an absolute address, and not just an offset.
  *
@@ -100,14 +100,14 @@
  * or init pieces the location is */
 static inline int in_init(struct module *me, void *loc)
 {
-	return (loc >= me->module_init &&
-		loc <= (me->module_init + me->init_size));
+	return (loc >= me->init_layout.base &&
+		loc <= (me->init_layout.base + me->init_layout.size));
 }
 
 static inline int in_core(struct module *me, void *loc)
 {
-	return (loc >= me->module_core &&
-		loc <= (me->module_core + me->core_size));
+	return (loc >= me->core_layout.base &&
+		loc <= (me->core_layout.base + me->core_layout.size));
 }
 
 static inline int in_local(struct module *me, void *loc)
@@ -367,13 +367,13 @@
 	}
 
 	/* align things a bit */
-	me->core_size = ALIGN(me->core_size, 16);
-	me->arch.got_offset = me->core_size;
-	me->core_size += gots * sizeof(struct got_entry);
-
-	me->core_size = ALIGN(me->core_size, 16);
-	me->arch.fdesc_offset = me->core_size;
-	me->core_size += fdescs * sizeof(Elf_Fdesc);
+	me->core_layout.size = ALIGN(me->core_layout.size, 16);
+	me->arch.got_offset = me->core_layout.size;
+	me->core_layout.size += gots * sizeof(struct got_entry);
+
+	me->core_layout.size = ALIGN(me->core_layout.size, 16);
+	me->arch.fdesc_offset = me->core_layout.size;
+	me->core_layout.size += fdescs * sizeof(Elf_Fdesc);
 
 	me->arch.got_max = gots;
 	me->arch.fdesc_max = fdescs;
@@ -391,7 +391,7 @@
 
 	BUG_ON(value == 0);
 
-	got = me->module_core + me->arch.got_offset;
+	got = me->core_layout.base + me->arch.got_offset;
 	for (i = 0; got[i].addr; i++)
 		if (got[i].addr == value)
 			goto out;
@@ -409,7 +409,7 @@
 #ifdef CONFIG_64BIT
 static Elf_Addr get_fdesc(struct module *me, unsigned long value)
 {
-	Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset;
+	Elf_Fdesc *fdesc = me->core_layout.base + me->arch.fdesc_offset;
 
 	if (!value) {
 		printk(KERN_ERR "%s: zero OPD requested!\n", me->name);
@@ -427,7 +427,7 @@
 
 	/* Create new one */
 	fdesc->addr = value;
-	fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset;
+	fdesc->gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset;
 	return (Elf_Addr)fdesc;
 }
 #endif /* CONFIG_64BIT */
@@ -839,7 +839,7 @@
 
 	table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr;
 	end = table + sechdrs[me->arch.unwind_section].sh_size;
-	gp = (Elf_Addr)me->module_core + me->arch.got_offset;
+	gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset;
 
 	DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n",
 	       me->arch.unwind_section, table, end, gp);
--- linux-4.4.0.orig/arch/parisc/kernel/pacache.S
+++ linux-4.4.0/arch/parisc/kernel/pacache.S
@@ -36,6 +36,7 @@
 #include <asm/assembly.h>
 #include <asm/pgtable.h>
 #include <asm/cache.h>
+#include <asm/ldcw.h>
 #include <linux/linkage.h>
 
 	.text
@@ -96,7 +97,7 @@
 
 fitmanymiddle:					/* Loop if LOOP >= 2 */
 	addib,COND(>)		-1, %r31, fitmanymiddle	/* Adjusted inner loop decr */
-	pitlbe		0(%sr1, %r28)
+	pitlbe		%r0(%sr1, %r28)
 	pitlbe,m	%arg1(%sr1, %r28)	/* Last pitlbe and addr adjust */
 	addib,COND(>)		-1, %r29, fitmanymiddle	/* Middle loop decr */
 	copy		%arg3, %r31		/* Re-init inner loop count */
@@ -139,7 +140,7 @@
 
 fdtmanymiddle:					/* Loop if LOOP >= 2 */
 	addib,COND(>)		-1, %r31, fdtmanymiddle	/* Adjusted inner loop decr */
-	pdtlbe		0(%sr1, %r28)
+	pdtlbe		%r0(%sr1, %r28)
 	pdtlbe,m	%arg1(%sr1, %r28)	/* Last pdtlbe and addr adjust */
 	addib,COND(>)		-1, %r29, fdtmanymiddle	/* Middle loop decr */
 	copy		%arg3, %r31		/* Re-init inner loop count */
@@ -333,8 +334,12 @@
 
 	.macro	tlb_lock	la,flags,tmp
 #ifdef CONFIG_SMP
-	ldil		L%pa_tlb_lock,%r1
-	ldo		R%pa_tlb_lock(%r1),\la
+#if __PA_LDCW_ALIGNMENT > 4
+	load32		pa_tlb_lock + __PA_LDCW_ALIGNMENT-1, \la
+	depi		0,31,__PA_LDCW_ALIGN_ORDER, \la
+#else
+	load32		pa_tlb_lock, \la
+#endif
 	rsm		PSW_SM_I,\flags
 1:	LDCW		0(\la),\tmp
 	cmpib,<>,n	0,\tmp,3f
@@ -349,6 +354,7 @@
 	.macro	tlb_unlock	la,flags,tmp
 #ifdef CONFIG_SMP
 	ldi		1,\tmp
+	sync
 	stw		\tmp,0(\la)
 	mtsm		\flags
 #endif
@@ -620,12 +626,12 @@
 	/* Purge any old translations */
 
 #ifdef CONFIG_PA20
-	pdtlb,l		0(%r28)
-	pdtlb,l		0(%r29)
+	pdtlb,l		%r0(%r28)
+	pdtlb,l		%r0(%r29)
 #else
 	tlb_lock	%r20,%r21,%r22
-	pdtlb		0(%r28)
-	pdtlb		0(%r29)
+	pdtlb		%r0(%r28)
+	pdtlb		%r0(%r29)
 	tlb_unlock	%r20,%r21,%r22
 #endif
 
@@ -768,10 +774,10 @@
 	/* Purge any old translation */
 
 #ifdef CONFIG_PA20
-	pdtlb,l		0(%r28)
+	pdtlb,l		%r0(%r28)
 #else
 	tlb_lock	%r20,%r21,%r22
-	pdtlb		0(%r28)
+	pdtlb		%r0(%r28)
 	tlb_unlock	%r20,%r21,%r22
 #endif
 
@@ -852,10 +858,10 @@
 	/* Purge any old translation */
 
 #ifdef CONFIG_PA20
-	pdtlb,l		0(%r28)
+	pdtlb,l		%r0(%r28)
 #else
 	tlb_lock	%r20,%r21,%r22
-	pdtlb		0(%r28)
+	pdtlb		%r0(%r28)
 	tlb_unlock	%r20,%r21,%r22
 #endif
 
@@ -886,19 +892,10 @@
 	fdc,m		r31(%r28)
 	fdc,m		r31(%r28)
 	fdc,m		r31(%r28)
-	cmpb,COND(<<)		%r28, %r25,1b
+	cmpb,COND(<<)	%r28, %r25,1b
 	fdc,m		r31(%r28)
 
 	sync
-
-#ifdef CONFIG_PA20
-	pdtlb,l		0(%r25)
-#else
-	tlb_lock	%r20,%r21,%r22
-	pdtlb		0(%r25)
-	tlb_unlock	%r20,%r21,%r22
-#endif
-
 	bv		%r0(%r2)
 	nop
 	.exit
@@ -925,13 +922,18 @@
 	depwi		0, 31,PAGE_SHIFT, %r28	/* Clear any offset bits */
 #endif
 
-	/* Purge any old translation */
+	/* Purge any old translation.  Note that the FIC instruction
+	 * may use either the instruction or data TLB.  Given that we
+	 * have a flat address space, it's not clear which TLB will be
+	 * used.  So, we purge both entries.  */
 
 #ifdef CONFIG_PA20
+	pdtlb,l		%r0(%r28)
 	pitlb,l         %r0(%sr4,%r28)
 #else
 	tlb_lock        %r20,%r21,%r22
-	pitlb           (%sr4,%r28)
+	pdtlb		%r0(%r28)
+	pitlb           %r0(%sr4,%r28)
 	tlb_unlock      %r20,%r21,%r22
 #endif
 
@@ -968,15 +970,6 @@
 	fic,m		%r31(%sr4,%r28)
 
 	sync
-
-#ifdef CONFIG_PA20
-	pitlb,l         %r0(%sr4,%r25)
-#else
-	tlb_lock        %r20,%r21,%r22
-	pitlb           (%sr4,%r25)
-	tlb_unlock      %r20,%r21,%r22
-#endif
-
 	bv		%r0(%r2)
 	nop
 	.exit
--- linux-4.4.0.orig/arch/parisc/kernel/parisc_ksyms.c
+++ linux-4.4.0/arch/parisc/kernel/parisc_ksyms.c
@@ -47,11 +47,11 @@
 EXPORT_SYMBOL(lclear_user);
 EXPORT_SYMBOL(lstrnlen_user);
 
-/* Global fixups */
-extern void fixup_get_user_skip_1(void);
-extern void fixup_get_user_skip_2(void);
-extern void fixup_put_user_skip_1(void);
-extern void fixup_put_user_skip_2(void);
+/* Global fixups - defined as int to avoid creation of function pointers */
+extern int fixup_get_user_skip_1;
+extern int fixup_get_user_skip_2;
+extern int fixup_put_user_skip_1;
+extern int fixup_put_user_skip_2;
 EXPORT_SYMBOL(fixup_get_user_skip_1);
 EXPORT_SYMBOL(fixup_get_user_skip_2);
 EXPORT_SYMBOL(fixup_put_user_skip_1);
--- linux-4.4.0.orig/arch/parisc/kernel/pci-dma.c
+++ linux-4.4.0/arch/parisc/kernel/pci-dma.c
@@ -95,8 +95,8 @@
 
 		if (!pte_none(*pte))
 			printk(KERN_ERR "map_pte_uncached: page already exists\n");
-		set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
 		purge_tlb_start(flags);
+		set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
 		pdtlb_kernel(orig_vaddr);
 		purge_tlb_end(flags);
 		vaddr += PAGE_SIZE;
--- linux-4.4.0.orig/arch/parisc/kernel/perf.c
+++ linux-4.4.0/arch/parisc/kernel/perf.c
@@ -39,7 +39,7 @@
  *  the PDC INTRIGUE calls.  This is done to eliminate bugs introduced
  *  in various PDC revisions.  The code is much more maintainable
  *  and reliable this way vs having to debug on every version of PDC
- *  on every box. 
+ *  on every box.
  */
 
 #include <linux/capability.h>
@@ -195,8 +195,8 @@
 static int perf_release(struct inode *inode, struct file *file);
 static int perf_open(struct inode *inode, struct file *file);
 static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos);
-static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, 
-	loff_t *ppos);
+static ssize_t perf_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *ppos);
 static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static void perf_start_counters(void);
 static int perf_stop_counters(uint32_t *raddr);
@@ -222,7 +222,7 @@
 /*
  * configure:
  *
- * Configure the cpu with a given data image.  First turn off the counters, 
+ * Configure the cpu with a given data image.  First turn off the counters,
  * then download the image, then turn the counters back on.
  */
 static int perf_config(uint32_t *image_ptr)
@@ -234,7 +234,7 @@
 	error = perf_stop_counters(raddr);
 	if (error != 0) {
 		printk("perf_config: perf_stop_counters = %ld\n", error);
-		return -EINVAL; 
+		return -EINVAL;
 	}
 
 printk("Preparing to write image\n");
@@ -242,7 +242,7 @@
 	error = perf_write_image((uint64_t *)image_ptr);
 	if (error != 0) {
 		printk("perf_config: DOWNLOAD = %ld\n", error);
-		return -EINVAL; 
+		return -EINVAL;
 	}
 
 printk("Preparing to start counters\n");
@@ -254,7 +254,7 @@
 }
 
 /*
- * Open the device and initialize all of its memory.  The device is only 
+ * Open the device and initialize all of its memory.  The device is only
  * opened once, but can be "queried" by multiple processes that know its
  * file descriptor.
  */
@@ -298,8 +298,8 @@
  * called on the processor that the download should happen
  * on.
  */
-static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, 
-	loff_t *ppos)
+static ssize_t perf_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *ppos)
 {
 	int err;
 	size_t image_size;
@@ -307,11 +307,11 @@
 	uint32_t interface_type;
 	uint32_t test;
 
-	if (perf_processor_interface == ONYX_INTF) 
+	if (perf_processor_interface == ONYX_INTF)
 		image_size = PCXU_IMAGE_SIZE;
-	else if (perf_processor_interface == CUDA_INTF) 
+	else if (perf_processor_interface == CUDA_INTF)
 		image_size = PCXW_IMAGE_SIZE;
-	else 
+	else
 		return -EFAULT;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -331,22 +331,22 @@
 
 	/* First check the machine type is correct for
 	   the requested image */
-        if (((perf_processor_interface == CUDA_INTF) &&
-		       (interface_type != CUDA_INTF)) ||
-	    ((perf_processor_interface == ONYX_INTF) &&
-	               (interface_type != ONYX_INTF))) 
+	if (((perf_processor_interface == CUDA_INTF) &&
+			(interface_type != CUDA_INTF)) ||
+		((perf_processor_interface == ONYX_INTF) &&
+			(interface_type != ONYX_INTF)))
 		return -EINVAL;
 
 	/* Next check to make sure the requested image
 	   is valid */
-	if (((interface_type == CUDA_INTF) && 
+	if (((interface_type == CUDA_INTF) &&
 		       (test >= MAX_CUDA_IMAGES)) ||
-	    ((interface_type == ONYX_INTF) && 
-		       (test >= MAX_ONYX_IMAGES))) 
+	    ((interface_type == ONYX_INTF) &&
+		       (test >= MAX_ONYX_IMAGES)))
 		return -EINVAL;
 
 	/* Copy the image into the processor */
-	if (interface_type == CUDA_INTF) 
+	if (interface_type == CUDA_INTF)
 		return perf_config(cuda_images[test]);
 	else
 		return perf_config(onyx_images[test]);
@@ -360,7 +360,7 @@
 static void perf_patch_images(void)
 {
 #if 0 /* FIXME!! */
-/* 
+/*
  * NOTE:  this routine is VERY specific to the current TLB image.
  * If the image is changed, this routine might also need to be changed.
  */
@@ -368,9 +368,9 @@
 	extern void $i_dtlb_miss_2_0();
 	extern void PA2_0_iva();
 
-	/* 
+	/*
 	 * We can only use the lower 32-bits, the upper 32-bits should be 0
-	 * anyway given this is in the kernel 
+	 * anyway given this is in the kernel
 	 */
 	uint32_t itlb_addr  = (uint32_t)&($i_itlb_miss_2_0);
 	uint32_t dtlb_addr  = (uint32_t)&($i_dtlb_miss_2_0);
@@ -378,21 +378,21 @@
 
 	if (perf_processor_interface == ONYX_INTF) {
 		/* clear last 2 bytes */
-		onyx_images[TLBMISS][15] &= 0xffffff00;  
+		onyx_images[TLBMISS][15] &= 0xffffff00;
 		/* set 2 bytes */
 		onyx_images[TLBMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
 		onyx_images[TLBMISS][16] = (dtlb_addr << 8)&0xffffff00;
 		onyx_images[TLBMISS][17] = itlb_addr;
 
 		/* clear last 2 bytes */
-		onyx_images[TLBHANDMISS][15] &= 0xffffff00;  
+		onyx_images[TLBHANDMISS][15] &= 0xffffff00;
 		/* set 2 bytes */
 		onyx_images[TLBHANDMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
 		onyx_images[TLBHANDMISS][16] = (dtlb_addr << 8)&0xffffff00;
 		onyx_images[TLBHANDMISS][17] = itlb_addr;
 
 		/* clear last 2 bytes */
-		onyx_images[BIG_CPI][15] &= 0xffffff00;  
+		onyx_images[BIG_CPI][15] &= 0xffffff00;
 		/* set 2 bytes */
 		onyx_images[BIG_CPI][15] |= (0x000000ff&((dtlb_addr) >> 24));
 		onyx_images[BIG_CPI][16] = (dtlb_addr << 8)&0xffffff00;
@@ -405,24 +405,24 @@
 
 	} else if (perf_processor_interface == CUDA_INTF) {
 		/* Cuda interface */
-		cuda_images[TLBMISS][16] =  
+		cuda_images[TLBMISS][16] =
 			(cuda_images[TLBMISS][16]&0xffff0000) |
 			((dtlb_addr >> 8)&0x0000ffff);
-		cuda_images[TLBMISS][17] = 
+		cuda_images[TLBMISS][17] =
 			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
 		cuda_images[TLBMISS][18] = (itlb_addr << 16)&0xffff0000;
 
-		cuda_images[TLBHANDMISS][16] = 
+		cuda_images[TLBHANDMISS][16] =
 			(cuda_images[TLBHANDMISS][16]&0xffff0000) |
 			((dtlb_addr >> 8)&0x0000ffff);
-		cuda_images[TLBHANDMISS][17] = 
+		cuda_images[TLBHANDMISS][17] =
 			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
 		cuda_images[TLBHANDMISS][18] = (itlb_addr << 16)&0xffff0000;
 
-		cuda_images[BIG_CPI][16] = 
+		cuda_images[BIG_CPI][16] =
 			(cuda_images[BIG_CPI][16]&0xffff0000) |
 			((dtlb_addr >> 8)&0x0000ffff);
-		cuda_images[BIG_CPI][17] = 
+		cuda_images[BIG_CPI][17] =
 			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
 		cuda_images[BIG_CPI][18] = (itlb_addr << 16)&0xffff0000;
 	} else {
@@ -434,7 +434,7 @@
 
 /*
  * ioctl routine
- * All routines effect the processor that they are executed on.  Thus you 
+ * All routines effect the processor that they are executed on.  Thus you
  * must be running on the processor that you wish to change.
  */
 
@@ -460,7 +460,7 @@
 			}
 
 			/* copy out the Counters */
-			if (copy_to_user((void __user *)arg, raddr, 
+			if (copy_to_user((void __user *)arg, raddr,
 					sizeof (raddr)) != 0) {
 				error =  -EFAULT;
 				break;
@@ -488,7 +488,7 @@
 	.open = perf_open,
 	.release = perf_release
 };
-	
+
 static struct miscdevice perf_dev = {
 	MISC_DYNAMIC_MINOR,
 	PA_PERF_DEV,
@@ -596,7 +596,7 @@
 		/* OR sticky2 (bit 1496) to counter2 bit 32 */
 		tmp64 |= (userbuf[23] >> 8) & 0x0000000080000000;
 		raddr[2] = (uint32_t)tmp64;
-		
+
 		/* Counter3 is bits 1497 to 1528 */
 		tmp64 =  (userbuf[23] >> 7) & 0x00000000ffffffff;
 		/* OR sticky3 (bit 1529) to counter3 bit 32 */
@@ -618,7 +618,7 @@
 		userbuf[22] = 0;
 		userbuf[23] = 0;
 
-		/* 
+		/*
 		 * Write back the zeroed bytes + the image given
 		 * the read was destructive.
 		 */
@@ -626,13 +626,13 @@
 	} else {
 
 		/*
-		 * Read RDR-15 which contains the counters and sticky bits 
+		 * Read RDR-15 which contains the counters and sticky bits
 		 */
 		if (!perf_rdr_read_ubuf(15, userbuf)) {
 			return -13;
 		}
 
-		/* 
+		/*
 		 * Clear out the counters
 		 */
 		perf_rdr_clear(15);
@@ -645,7 +645,7 @@
 		raddr[2] = (uint32_t)((userbuf[1] >> 32) & 0x00000000ffffffffUL);
 		raddr[3] = (uint32_t)(userbuf[1] & 0x00000000ffffffffUL);
 	}
- 
+
 	return 0;
 }
 
@@ -683,7 +683,7 @@
 	i = tentry->num_words;
 	while (i--) {
 		buffer[i] = 0;
-	}	
+	}
 
 	/* Check for bits an even number of 64 */
 	if ((xbits = width & 0x03f) != 0) {
@@ -809,18 +809,22 @@
 	}
 
 	runway = ioremap_nocache(cpu_device->hpa.start, 4096);
+	if (!runway) {
+		pr_err("perf_write_image: ioremap failed!\n");
+		return -ENOMEM;
+	}
 
 	/* Merge intrigue bits into Runway STATUS 0 */
 	tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful;
-	__raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), 
+	__raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul),
 		     runway + RUNWAY_STATUS);
-	
+
 	/* Write RUNWAY DEBUG registers */
 	for (i = 0; i < 8; i++) {
 		__raw_writeq(*memaddr++, runway + RUNWAY_DEBUG);
 	}
 
-	return 0; 
+	return 0;
 }
 
 /*
@@ -844,7 +848,7 @@
 			perf_rdr_shift_out_U(rdr_num, buffer[i]);
 		} else {
 			perf_rdr_shift_out_W(rdr_num, buffer[i]);
-		}	
+		}
 	}
 printk("perf_rdr_write done\n");
 }
--- linux-4.4.0.orig/arch/parisc/kernel/ptrace.c
+++ linux-4.4.0/arch/parisc/kernel/ptrace.c
@@ -156,6 +156,9 @@
 		if ((addr & (sizeof(unsigned long)-1)) ||
 		     addr >= sizeof(struct pt_regs))
 			break;
+		if (addr == PT_IAOQ0 || addr == PT_IAOQ1) {
+			data |= 3; /* ensure userspace privilege */
+		}
 		if ((addr >= PT_GR1 && addr <= PT_GR31) ||
 				addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
 				(addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
@@ -189,16 +192,18 @@
 
 static compat_ulong_t translate_usr_offset(compat_ulong_t offset)
 {
-	if (offset < 0)
-		return sizeof(struct pt_regs);
-	else if (offset <= 32*4)	/* gr[0..31] */
-		return offset * 2 + 4;
-	else if (offset <= 32*4+32*8)	/* gr[0..31] + fr[0..31] */
-		return offset + 32*4;
-	else if (offset < sizeof(struct pt_regs)/2 + 32*4)
-		return offset * 2 + 4 - 32*8;
+	compat_ulong_t pos;
+
+	if (offset < 32*4)	/* gr[0..31] */
+		pos = offset * 2 + 4;
+	else if (offset < 32*4+32*8)	/* fr[0] ... fr[31] */
+		pos = (offset - 32*4) + PT_FR0;
+	else if (offset < sizeof(struct pt_regs)/2 + 32*4) /* sr[0] ... ipsw */
+		pos = (offset - 32*4 - 32*8) * 2 + PT_SR0 + 4;
 	else
-		return sizeof(struct pt_regs);
+		pos = sizeof(struct pt_regs);
+
+	return pos;
 }
 
 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
@@ -242,9 +247,12 @@
 			addr = translate_usr_offset(addr);
 			if (addr >= sizeof(struct pt_regs))
 				break;
+			if (addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4) {
+				data |= 3; /* ensure userspace privilege */
+			}
 			if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
 				/* Special case, fp regs are 64 bits anyway */
-				*(__u64 *) ((char *) task_regs(child) + addr) = data;
+				*(__u32 *) ((char *) task_regs(child) + addr) = data;
 				ret = 0;
 			}
 			else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
@@ -269,14 +277,19 @@
 
 long do_syscall_trace_enter(struct pt_regs *regs)
 {
-	long ret = 0;
-
 	/* Do the secure computing check first. */
 	secure_computing_strict(regs->gr[20]);
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    tracehook_report_syscall_entry(regs))
-		ret = -1L;
+	    tracehook_report_syscall_entry(regs)) {
+		/*
+		 * Tracing decided this syscall should not happen or the
+		 * debugger stored an invalid system call number. Skip
+		 * the system call and the system call restart handling.
+		 */
+		regs->gr[20] = -1UL;
+		goto out;
+	}
 
 #ifdef CONFIG_64BIT
 	if (!is_compat_task())
@@ -290,7 +303,8 @@
 			regs->gr[24] & 0xffffffff,
 			regs->gr[23] & 0xffffffff);
 
-	return ret ? : regs->gr[20];
+out:
+	return regs->gr[20];
 }
 
 void do_syscall_trace_exit(struct pt_regs *regs)
--- linux-4.4.0.orig/arch/parisc/kernel/setup.c
+++ linux-4.4.0/arch/parisc/kernel/setup.c
@@ -38,6 +38,7 @@
 #include <linux/export.h>
 
 #include <asm/processor.h>
+#include <asm/sections.h>
 #include <asm/pdc.h>
 #include <asm/led.h>
 #include <asm/machdep.h>	/* for pa7300lc_init() proto */
@@ -140,6 +141,13 @@
 #endif
 	printk(KERN_CONT ".\n");
 
+	/*
+	 * Check if initial kernel page mappings are sufficient.
+	 * panic early if not, else we may access kernel functions
+	 * and variables which can't be reached.
+	 */
+	if (__pa((unsigned long) &_end) >= KERNEL_INITIAL_SIZE)
+		panic("KERNEL_INITIAL_ORDER too small!");
 
 	pdc_console_init();
 
@@ -326,6 +334,10 @@
 	/* tell PDC we're Linux. Nevermind failure. */
 	pdc_stable_write(0x40, &osid, sizeof(osid));
 	
+	/* start with known state */
+	flush_cache_all_local();
+	flush_tlb_all_local(NULL);
+
 	processor_init();
 #ifdef CONFIG_SMP
 	pr_info("CPU(s): %d out of %d %s at %d.%06d MHz online\n",
--- linux-4.4.0.orig/arch/parisc/kernel/sys_parisc.c
+++ linux-4.4.0/arch/parisc/kernel/sys_parisc.c
@@ -88,7 +88,7 @@
 		unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
+	struct vm_area_struct *vma, *prev;
 	unsigned long task_size = TASK_SIZE;
 	int do_color_align, last_mmap;
 	struct vm_unmapped_area_info info;
@@ -115,9 +115,10 @@
 		else
 			addr = PAGE_ALIGN(addr);
 
-		vma = find_vma(mm, addr);
+		vma = find_vma_prev(mm, addr, &prev);
 		if (task_size - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)) &&
+		    (!prev || addr >= vm_end_gap(prev)))
 			goto found_addr;
 	}
 
@@ -141,7 +142,7 @@
 			  const unsigned long len, const unsigned long pgoff,
 			  const unsigned long flags)
 {
-	struct vm_area_struct *vma;
+	struct vm_area_struct *vma, *prev;
 	struct mm_struct *mm = current->mm;
 	unsigned long addr = addr0;
 	int do_color_align, last_mmap;
@@ -175,9 +176,11 @@
 			addr = COLOR_ALIGN(addr, last_mmap, pgoff);
 		else
 			addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
+
+		vma = find_vma_prev(mm, addr, &prev);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)) &&
+		    (!prev || addr >= vm_end_gap(prev)))
 			goto found_addr;
 	}
 
--- linux-4.4.0.orig/arch/parisc/kernel/syscall.S
+++ linux-4.4.0/arch/parisc/kernel/syscall.S
@@ -106,8 +106,6 @@
 	mtsp	%r0,%sr4			/* get kernel space into sr4 */
 	mtsp	%r0,%sr5			/* get kernel space into sr5 */
 	mtsp	%r0,%sr6			/* get kernel space into sr6 */
-	mfsp    %sr7,%r1                        /* save user sr7 */
-	mtsp    %r1,%sr3                        /* and store it in sr3 */
 
 #ifdef CONFIG_64BIT
 	/* for now we can *always* set the W bit on entry to the syscall
@@ -133,6 +131,14 @@
 	depdi	0, 31, 32, %r21
 1:	
 #endif
+
+	/* We use a rsm/ssm pair to prevent sr3 from being clobbered
+	 * by external interrupts.
+	 */
+	mfsp    %sr7,%r1                        /* save user sr7 */
+	rsm	PSW_SM_I, %r0			/* disable interrupts */
+	mtsp    %r1,%sr3                        /* and store it in sr3 */
+
 	mfctl   %cr30,%r1
 	xor     %r1,%r30,%r30                   /* ye olde xor trick */
 	xor     %r1,%r30,%r1
@@ -147,6 +153,7 @@
 	 */
 
 	mtsp	%r0,%sr7			/* get kernel space into sr7 */
+	ssm	PSW_SM_I, %r0			/* enable interrupts */
 	STREGM	%r1,FRAME_SIZE(%r30)		/* save r1 (usp) here for now */
 	mfctl	%cr30,%r1			/* get task ptr in %r1 */
 	LDREG	TI_TASK(%r1),%r1
@@ -343,7 +350,7 @@
 #endif
 
 	comiclr,>>=	__NR_Linux_syscalls, %r20, %r0
-	b,n	.Lsyscall_nosys
+	b,n	.Ltracesys_nosys
 
 	LDREGX  %r20(%r19), %r19
 
@@ -359,6 +366,9 @@
 	be      0(%sr7,%r19)
 	ldo	R%tracesys_exit(%r2),%r2
 
+.Ltracesys_nosys:
+	ldo	-ENOSYS(%r0),%r28		/* set errno */
+
 	/* Do *not* call this function on the gateway page, because it
 	makes a direct call to syscall_trace. */
 	
@@ -469,11 +479,6 @@
 	comiclr,>>	__NR_lws_entries, %r20, %r0
 	b,n	lws_exit_nosys
 
-	/* WARNING: Trashing sr2 and sr3 */
-	mfsp	%sr7,%r1			/* get userspace into sr3 */
-	mtsp	%r1,%sr3
-	mtsp	%r0,%sr2			/* get kernel space into sr2 */
-
 	/* Load table start */
 	ldil	L%lws_table, %r1
 	ldo	R%lws_table(%r1), %r28	/* Scratch use of r28 */
@@ -622,11 +627,12 @@
 	stw	%r1, 4(%sr2,%r20)
 #endif
 	/* The load and store could fail */
-1:	ldw,ma	0(%sr3,%r26), %r28
+1:	ldw	0(%r26), %r28
 	sub,<>	%r28, %r25, %r0
-2:	stw,ma	%r24, 0(%sr3,%r26)
+2:	stw	%r24, 0(%r26)
 	/* Free lock */
-	stw,ma	%r20, 0(%sr2,%r20)
+	sync
+	stw	%r20, 0(%sr2,%r20)
 #if ENABLE_LWS_DEBUG
 	/* Clear thread register indicator */
 	stw	%r0, 4(%sr2,%r20)
@@ -640,6 +646,7 @@
 3:		
 	/* Error occurred on load or store */
 	/* Free lock */
+	sync
 	stw	%r20, 0(%sr2,%r20)
 #if ENABLE_LWS_DEBUG
 	stw	%r0, 4(%sr2,%r20)
@@ -683,15 +690,15 @@
 	/* ELF32 Process entry path */
 lws_compare_and_swap_2:
 #ifdef CONFIG_64BIT
-	/* Clip the input registers */
+	/* Clip the input registers. We don't need to clip %r23 as we
+	   only use it for word operations */
 	depdi	0, 31, 32, %r26
 	depdi	0, 31, 32, %r25
 	depdi	0, 31, 32, %r24
-	depdi	0, 31, 32, %r23
 #endif
 
 	/* Check the validity of the size pointer */
-	subi,>>= 4, %r23, %r0
+	subi,>>= 3, %r23, %r0
 	b,n	lws_exit_nosys
 
 	/* Jump to the functions which will load the old and new values into
@@ -701,9 +708,9 @@
 	nop
 
 	/* 8bit load */
-4:	ldb	0(%sr3,%r25), %r25
+4:	ldb	0(%r25), %r25
 	b	cas2_lock_start
-5:	ldb	0(%sr3,%r24), %r24
+5:	ldb	0(%r24), %r24
 	nop
 	nop
 	nop
@@ -711,9 +718,9 @@
 	nop
 
 	/* 16bit load */
-6:	ldh	0(%sr3,%r25), %r25
+6:	ldh	0(%r25), %r25
 	b	cas2_lock_start
-7:	ldh	0(%sr3,%r24), %r24
+7:	ldh	0(%r24), %r24
 	nop
 	nop
 	nop
@@ -721,9 +728,9 @@
 	nop
 
 	/* 32bit load */
-8:	ldw	0(%sr3,%r25), %r25
+8:	ldw	0(%r25), %r25
 	b	cas2_lock_start
-9:	ldw	0(%sr3,%r24), %r24
+9:	ldw	0(%r24), %r24
 	nop
 	nop
 	nop
@@ -732,14 +739,14 @@
 
 	/* 64bit load */
 #ifdef CONFIG_64BIT
-10:	ldd	0(%sr3,%r25), %r25
-11:	ldd	0(%sr3,%r24), %r24
+10:	ldd	0(%r25), %r25
+11:	ldd	0(%r24), %r24
 #else
-	/* Load new value into r22/r23 - high/low */
-10:	ldw	0(%sr3,%r25), %r22
-11:	ldw	4(%sr3,%r25), %r23
+	/* Load old value into r22/r23 - high/low */
+10:	ldw	0(%r25), %r22
+11:	ldw	4(%r25), %r23
 	/* Load new value into fr4 for atomic store later */
-12:	flddx	0(%sr3,%r24), %fr4
+12:	flddx	0(%r24), %fr4
 #endif
 
 cas2_lock_start:
@@ -789,30 +796,30 @@
 	ldo	1(%r0),%r28
 
 	/* 8bit CAS */
-13:	ldb,ma	0(%sr3,%r26), %r29
+13:	ldb	0(%r26), %r29
 	sub,=	%r29, %r25, %r0
 	b,n	cas2_end
-14:	stb,ma	%r24, 0(%sr3,%r26)
+14:	stb	%r24, 0(%r26)
 	b	cas2_end
 	copy	%r0, %r28
 	nop
 	nop
 
 	/* 16bit CAS */
-15:	ldh,ma	0(%sr3,%r26), %r29
+15:	ldh	0(%r26), %r29
 	sub,=	%r29, %r25, %r0
 	b,n	cas2_end
-16:	sth,ma	%r24, 0(%sr3,%r26)
+16:	sth	%r24, 0(%r26)
 	b	cas2_end
 	copy	%r0, %r28
 	nop
 	nop
 
 	/* 32bit CAS */
-17:	ldw,ma	0(%sr3,%r26), %r29
+17:	ldw	0(%r26), %r29
 	sub,=	%r29, %r25, %r0
 	b,n	cas2_end
-18:	stw,ma	%r24, 0(%sr3,%r26)
+18:	stw	%r24, 0(%r26)
 	b	cas2_end
 	copy	%r0, %r28
 	nop
@@ -820,28 +827,29 @@
 
 	/* 64bit CAS */
 #ifdef CONFIG_64BIT
-19:	ldd,ma	0(%sr3,%r26), %r29
+19:	ldd	0(%r26), %r29
 	sub,*=	%r29, %r25, %r0
 	b,n	cas2_end
-20:	std,ma	%r24, 0(%sr3,%r26)
+20:	std	%r24, 0(%r26)
 	copy	%r0, %r28
 #else
 	/* Compare first word */
-19:	ldw,ma	0(%sr3,%r26), %r29
+19:	ldw	0(%r26), %r29
 	sub,=	%r29, %r22, %r0
 	b,n	cas2_end
 	/* Compare second word */
-20:	ldw,ma	4(%sr3,%r26), %r29
+20:	ldw	4(%r26), %r29
 	sub,=	%r29, %r23, %r0
 	b,n	cas2_end
 	/* Perform the store */
-21:	fstdx	%fr4, 0(%sr3,%r26)
+21:	fstdx	%fr4, 0(%r26)
 	copy	%r0, %r28
 #endif
 
 cas2_end:
 	/* Free lock */
-	stw,ma	%r20, 0(%sr2,%r20)
+	sync
+	stw	%r20, 0(%sr2,%r20)
 	/* Enable interrupts */
 	ssm	PSW_SM_I, %r0
 	/* Return to userspace, set no error */
@@ -851,6 +859,7 @@
 22:
 	/* Error occurred on load or store */
 	/* Free lock */
+	sync
 	stw	%r20, 0(%sr2,%r20)
 	ssm	PSW_SM_I, %r0
 	ldo	1(%r0),%r28
--- linux-4.4.0.orig/arch/parisc/kernel/syscall_table.S
+++ linux-4.4.0/arch/parisc/kernel/syscall_table.S
@@ -361,7 +361,7 @@
 	ENTRY_SAME(ni_syscall)	/* 263: reserved for vserver */
 	ENTRY_SAME(add_key)
 	ENTRY_SAME(request_key)		/* 265 */
-	ENTRY_SAME(keyctl)
+	ENTRY_COMP(keyctl)
 	ENTRY_SAME(ioprio_set)
 	ENTRY_SAME(ioprio_get)
 	ENTRY_SAME(inotify_init)
--- linux-4.4.0.orig/arch/parisc/kernel/traps.c
+++ linux-4.4.0/arch/parisc/kernel/traps.c
@@ -798,6 +798,9 @@
 
 	    if (fault_space == 0 && !faulthandler_disabled())
 	    {
+		/* Clean up and return if in exception table. */
+		if (fixup_exception(regs))
+			return;
 		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
 		parisc_terminate("Kernel Fault", regs, code, fault_address);
 	    }
@@ -826,7 +829,8 @@
 	for (i = 0; i < 8; i++)
 	    *ivap++ = 0;
 
-	/* Compute Checksum for HPMC handler */
+	/* Setup IVA and compute checksum for HPMC handler */
+	ivap[6] = (u32)__pa(os_hpmc);
 	length = os_hpmc_size;
 	ivap[7] = length;
 
--- linux-4.4.0.orig/arch/parisc/kernel/unaligned.c
+++ linux-4.4.0/arch/parisc/kernel/unaligned.c
@@ -666,7 +666,7 @@
 		break;
 	}
 
-	if (modify && R1(regs->iir))
+	if (ret == 0 && modify && R1(regs->iir))
 		regs->gr[R1(regs->iir)] = newbase;
 
 
@@ -677,6 +677,14 @@
 
 	if (ret)
 	{
+		/*
+		 * The unaligned handler failed.
+		 * If we were called by __get_user() or __put_user() jump
+		 * to it's exception fixup handler instead of crashing.
+		 */
+		if (!user_mode(regs) && fixup_exception(regs))
+			return;
+
 		printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
 		die_if_kernel("Unaligned data reference", regs, 28);
 
--- linux-4.4.0.orig/arch/parisc/kernel/vmlinux.lds.S
+++ linux-4.4.0/arch/parisc/kernel/vmlinux.lds.S
@@ -88,8 +88,9 @@
 	/* Start of data section */
 	_sdata = .;
 
-	RO_DATA_SECTION(8)
-
+	/* Architecturally we need to keep __gp below 0x1000000 and thus
+	 * in front of RO_DATA_SECTION() which stores lots of tracepoint
+	 * and ftrace symbols. */
 #ifdef CONFIG_64BIT
 	. = ALIGN(16);
 	/* Linkage tables */
@@ -104,6 +105,8 @@
 	}
 #endif
 
+	RO_DATA_SECTION(8)
+
 	/* unwind info */
 	.PARISC.unwind : {
 		__start___unwind = .;
--- linux-4.4.0.orig/arch/parisc/lib/fixup.S
+++ linux-4.4.0/arch/parisc/lib/fixup.S
@@ -26,6 +26,7 @@
 
 #ifdef CONFIG_SMP
 	.macro  get_fault_ip t1 t2
+	loadgp
 	addil LT%__per_cpu_offset,%r27
 	LDREG RT%__per_cpu_offset(%r1),\t1
 	/* t2 = smp_processor_id() */
@@ -40,14 +41,19 @@
 	LDREG RT%exception_data(%r1),\t1
 	/* t1 = this_cpu_ptr(&exception_data) */
 	add,l \t1,\t2,\t1
+	/* %r27 = t1->fault_gp - restore gp */
+	LDREG EXCDATA_GP(\t1), %r27
 	/* t1 = t1->fault_ip */
 	LDREG EXCDATA_IP(\t1), \t1
 	.endm
 #else
 	.macro  get_fault_ip t1 t2
+	loadgp
 	/* t1 = this_cpu_ptr(&exception_data) */
 	addil LT%exception_data,%r27
 	LDREG RT%exception_data(%r1),\t2
+	/* %r27 = t2->fault_gp - restore gp */
+	LDREG EXCDATA_GP(\t2), %r27
 	/* t1 = t2->fault_ip */
 	LDREG EXCDATA_IP(\t2), \t1
 	.endm
--- linux-4.4.0.orig/arch/parisc/math-emu/cnv_float.h
+++ linux-4.4.0/arch/parisc/math-emu/cnv_float.h
@@ -60,19 +60,19 @@
     ((exponent < (SGL_P - 1)) ?				\
      (Sall(sgl_value) << (SGL_EXP_LENGTH + 1 + exponent)) : FALSE)
 
-#define Int_isinexact_to_sgl(int_value)	(int_value << 33 - SGL_EXP_LENGTH)
+#define Int_isinexact_to_sgl(int_value)	((int_value << 33 - SGL_EXP_LENGTH) != 0)
 
 #define Sgl_roundnearest_from_int(int_value,sgl_value)			\
     if (int_value & 1<<(SGL_EXP_LENGTH - 2))   /* round bit */		\
-    	if ((int_value << 34 - SGL_EXP_LENGTH) || Slow(sgl_value))	\
+	if (((int_value << 34 - SGL_EXP_LENGTH) != 0) || Slow(sgl_value)) \
 		Sall(sgl_value)++
 
 #define Dint_isinexact_to_sgl(dint_valueA,dint_valueB)		\
-    ((Dintp1(dint_valueA) << 33 - SGL_EXP_LENGTH) || Dintp2(dint_valueB))
+    (((Dintp1(dint_valueA) << 33 - SGL_EXP_LENGTH) != 0) || Dintp2(dint_valueB))
 
 #define Sgl_roundnearest_from_dint(dint_valueA,dint_valueB,sgl_value)	\
     if (Dintp1(dint_valueA) & 1<<(SGL_EXP_LENGTH - 2)) 			\
-    	if ((Dintp1(dint_valueA) << 34 - SGL_EXP_LENGTH) ||		\
+	if (((Dintp1(dint_valueA) << 34 - SGL_EXP_LENGTH) != 0) ||	\
     	Dintp2(dint_valueB) || Slow(sgl_value)) Sall(sgl_value)++
 
 #define Dint_isinexact_to_dbl(dint_value) 	\
--- linux-4.4.0.orig/arch/parisc/mm/fault.c
+++ linux-4.4.0/arch/parisc/mm/fault.c
@@ -151,6 +151,7 @@
 		struct exception_data *d;
 		d = this_cpu_ptr(&exception_data);
 		d->fault_ip = regs->iaoq[0];
+		d->fault_gp = regs->gr[27];
 		d->fault_space = regs->isr;
 		d->fault_addr = regs->ior;
 
@@ -302,7 +303,7 @@
 		case 15:	/* Data TLB miss fault/Data page fault */
 			/* send SIGSEGV when outside of vma */
 			if (!vma ||
-			    address < vma->vm_start || address > vma->vm_end) {
+			    address < vma->vm_start || address >= vma->vm_end) {
 				si.si_signo = SIGSEGV;
 				si.si_code = SEGV_MAPERR;
 				break;
--- linux-4.4.0.orig/arch/parisc/mm/hugetlbpage.c
+++ linux-4.4.0/arch/parisc/mm/hugetlbpage.c
@@ -105,15 +105,13 @@
 	addr |= _HUGE_PAGE_SIZE_ENCODING_DEFAULT;
 
 	for (i = 0; i < (1 << (HPAGE_SHIFT-REAL_HPAGE_SHIFT)); i++) {
-		mtsp(mm->context, 1);
-		pdtlb(addr);
-		if (unlikely(split_tlb))
-			pitlb(addr);
+		purge_tlb_entries(mm, addr);
 		addr += (1UL << REAL_HPAGE_SHIFT);
 	}
 }
 
-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+/* __set_huge_pte_at() must be called holding the pa_tlb_lock. */
+static void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
 		     pte_t *ptep, pte_t entry)
 {
 	unsigned long addr_start;
@@ -123,14 +121,9 @@
 	addr_start = addr;
 
 	for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
-		/* Directly write pte entry.  We could call set_pte_at(mm, addr, ptep, entry)
-		 * instead, but then we get double locking on pa_tlb_lock. */
-		*ptep = entry;
+		set_pte(ptep, entry);
 		ptep++;
 
-		/* Drop the PAGE_SIZE/non-huge tlb entry */
-		purge_tlb_entries(mm, addr);
-
 		addr += PAGE_SIZE;
 		pte_val(entry) += PAGE_SIZE;
 	}
@@ -138,18 +131,61 @@
 	purge_tlb_entries_huge(mm, addr_start);
 }
 
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+		     pte_t *ptep, pte_t entry)
+{
+	unsigned long flags;
+
+	purge_tlb_start(flags);
+	__set_huge_pte_at(mm, addr, ptep, entry);
+	purge_tlb_end(flags);
+}
+
 
 pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep)
 {
+	unsigned long flags;
 	pte_t entry;
 
+	purge_tlb_start(flags);
 	entry = *ptep;
-	set_huge_pte_at(mm, addr, ptep, __pte(0));
+	__set_huge_pte_at(mm, addr, ptep, __pte(0));
+	purge_tlb_end(flags);
 
 	return entry;
 }
 
+
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+				unsigned long addr, pte_t *ptep)
+{
+	unsigned long flags;
+	pte_t old_pte;
+
+	purge_tlb_start(flags);
+	old_pte = *ptep;
+	__set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+	purge_tlb_end(flags);
+}
+
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep,
+				pte_t pte, int dirty)
+{
+	unsigned long flags;
+	int changed;
+
+	purge_tlb_start(flags);
+	changed = !pte_same(*ptep, pte);
+	if (changed) {
+		__set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+	}
+	purge_tlb_end(flags);
+	return changed;
+}
+
+
 int pmd_huge(pmd_t pmd)
 {
 	return 0;
--- linux-4.4.0.orig/arch/parisc/mm/init.c
+++ linux-4.4.0/arch/parisc/mm/init.c
@@ -491,12 +491,8 @@
 						pte = pte_mkhuge(pte);
 				}
 
-				if (address >= end_paddr) {
-					if (force)
-						break;
-					else
-						pte_val(pte) = 0;
-				}
+				if (address >= end_paddr)
+					break;
 
 				set_pte(pg_table, pte);
 
@@ -608,7 +604,7 @@
 			> BITS_PER_LONG);
 
 	high_memory = __va((max_pfn << PAGE_SHIFT));
-	set_max_mapnr(page_to_pfn(virt_to_page(high_memory - 1)) + 1);
+	set_max_mapnr(max_low_pfn);
 	free_all_bootmem();
 
 #ifdef CONFIG_PA11
--- linux-4.4.0.orig/arch/parisc/mm/ioremap.c
+++ linux-4.4.0/arch/parisc/mm/ioremap.c
@@ -2,7 +2,7 @@
  * arch/parisc/mm/ioremap.c
  *
  * (C) Copyright 1995 1996 Linus Torvalds
- * (C) Copyright 2001-2006 Helge Deller <deller@gmx.de>
+ * (C) Copyright 2001-2019 Helge Deller <deller@gmx.de>
  * (C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org>
  */
 
@@ -83,7 +83,7 @@
 	addr = (void __iomem *) area->addr;
 	if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
 			       phys_addr, pgprot)) {
-		vfree(addr);
+		vunmap(addr);
 		return NULL;
 	}
 
@@ -91,9 +91,11 @@
 }
 EXPORT_SYMBOL(__ioremap);
 
-void iounmap(const volatile void __iomem *addr)
+void iounmap(const volatile void __iomem *io_addr)
 {
-	if (addr > high_memory)
-		return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
+	unsigned long addr = (unsigned long)io_addr & PAGE_MASK;
+
+	if (is_vmalloc_addr((void *)addr))
+		vunmap((void *)addr);
 }
 EXPORT_SYMBOL(iounmap);
--- linux-4.4.0.orig/arch/powerpc/Kconfig
+++ linux-4.4.0/arch/powerpc/Kconfig
@@ -93,6 +93,7 @@
 	select BINFMT_ELF
 	select ARCH_HAS_ELF_RANDOMIZE
 	select OF
+	select OF_DMA_DEFAULT_COHERENT		if !NOT_COHERENT_CACHE
 	select OF_EARLY_FLATTREE
 	select OF_RESERVED_MEM
 	select HAVE_FTRACE_MCOUNT_RECORD
@@ -129,13 +130,14 @@
 	select IRQ_FORCED_THREADING
 	select HAVE_RCU_TABLE_FREE if SMP
 	select HAVE_SYSCALL_TRACEPOINTS
-	select HAVE_BPF_JIT
+	select HAVE_BPF_JIT if CPU_BIG_ENDIAN
 	select HAVE_ARCH_JUMP_LABEL
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select GENERIC_SMP_IDLE_THREAD
 	select GENERIC_CMOS_UPDATE
 	select GENERIC_TIME_VSYSCALL_OLD
+	select GENERIC_CPU_VULNERABILITIES	if PPC_BARRIER_NOSPEC
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
@@ -160,6 +162,12 @@
 	select EDAC_ATOMIC_SCRUB
 	select ARCH_HAS_DMA_SET_COHERENT_MASK
 	select HAVE_ARCH_SECCOMP_FILTER
+	select GENERIC_CPU_AUTOPROBE
+
+config PPC_BARRIER_NOSPEC
+	bool
+	default y
+	depends on PPC_BOOK3S_64 || PPC_FSL_BOOK3E
 
 config GENERIC_CSUM
 	def_bool CPU_LITTLE_ENDIAN
@@ -570,7 +578,7 @@
 
 config PPC_256K_PAGES
 	bool "256k page size"
-	depends on 44x && !STDBINUTILS
+	depends on 44x && !STDBINUTILS && !PPC_47x
 	help
 	  Make the page size 256k.
 
@@ -698,6 +706,19 @@
 
 	  If unsure, say Y. Only embedded should say N here.
 
+config PPC_RTAS_FILTER
+	bool "Enable filtering of RTAS syscalls"
+	default y
+	depends on PPC_RTAS
+	help
+	  The RTAS syscall API has security issues that could be used to
+	  compromise system integrity. This option enforces restrictions on the
+	  RTAS calls and arguments passed by userspace programs to mitigate
+	  these issues.
+
+	  Say Y unless you know what you are doing and the filter is causing
+	  problems for you.
+
 endmenu
 
 config ISA_DMA_API
@@ -1072,6 +1093,8 @@
 
 source "drivers/Kconfig"
 
+source "ubuntu/Kconfig"
+
 source "fs/Kconfig"
 
 source "arch/powerpc/sysdev/qe_lib/Kconfig"
@@ -1082,11 +1105,6 @@
 
 source "security/Kconfig"
 
-config KEYS_COMPAT
-	bool
-	depends on COMPAT && KEYS
-	default y
-
 source "crypto/Kconfig"
 
 config PPC_LIB_RHEAP
--- linux-4.4.0.orig/arch/powerpc/Makefile
+++ linux-4.4.0/arch/powerpc/Makefile
@@ -66,29 +66,35 @@
 UTS_MACHINE := $(OLDARCH)
 
 ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
-override CC	+= -mlittle-endian
-ifneq ($(cc-name),clang)
-override CC	+= -mno-strict-align
-endif
-override AS	+= -mlittle-endian
 override LD	+= -EL
-override CROSS32CC += -mlittle-endian
 override CROSS32AS += -mlittle-endian
 LDEMULATION	:= lppc
 GNUTARGET	:= powerpcle
 MULTIPLEWORD	:= -mno-multiple
 KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-save-toc-indirect)
 else
-ifeq ($(call cc-option-yn,-mbig-endian),y)
-override CC	+= -mbig-endian
-override AS	+= -mbig-endian
-endif
 override LD	+= -EB
 LDEMULATION	:= ppc
 GNUTARGET	:= powerpc
 MULTIPLEWORD	:= -mmultiple
 endif
 
+ifdef CONFIG_PPC64
+cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= $(call cc-option,-mabi=elfv1)
+cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= $(call cc-option,-mcall-aixdesc)
+aflags-$(CONFIG_CPU_BIG_ENDIAN)		+= $(call cc-option,-mabi=elfv1)
+aflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -mabi=elfv2
+endif
+
+cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -mlittle-endian
+cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= $(call cc-option,-mbig-endian)
+ifneq ($(cc-name),clang)
+  cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -mno-strict-align
+endif
+
+aflags-$(CONFIG_CPU_BIG_ENDIAN)		+= $(call cc-option,-mbig-endian)
+aflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -mlittle-endian
+
 ifeq ($(HAS_BIARCH),y)
 override AS	+= -a$(CONFIG_WORD_SIZE)
 override LD	+= -m elf$(CONFIG_WORD_SIZE)$(LDEMULATION)
@@ -121,7 +127,9 @@
 CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mabi=elfv2,$(call cc-option,-mcall-aixdesc))
 AFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mabi=elfv2)
 else
+CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mabi=elfv1)
 CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mcall-aixdesc)
+AFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mabi=elfv1)
 endif
 CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mcmodel=medium,$(call cc-option,-mminimal-toc))
 CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mno-pointers-to-nested-functions)
@@ -212,6 +220,9 @@
 KBUILD_AFLAGS += $(cpu-as-y)
 KBUILD_CFLAGS += $(cpu-as-y)
 
+KBUILD_AFLAGS += $(aflags-y)
+KBUILD_CFLAGS += $(cflags-y)
+
 head-y				:= arch/powerpc/kernel/head_$(CONFIG_WORD_SIZE).o
 head-$(CONFIG_8xx)		:= arch/powerpc/kernel/head_8xx.o
 head-$(CONFIG_40x)		:= arch/powerpc/kernel/head_40x.o
@@ -241,7 +252,7 @@
 all: zImage
 
 # With make 3.82 we cannot mix normal and wildcard targets
-BOOT_TARGETS1 := zImage zImage.initrd uImage
+BOOT_TARGETS1 := zImage zImage.initrd uImage vmlinux.strip
 BOOT_TARGETS2 := zImage% dtbImage% treeImage.% cuImage.% simpleImage.% uImage.%
 
 PHONY += $(BOOT_TARGETS1) $(BOOT_TARGETS2)
@@ -339,7 +350,9 @@
 ifeq ($(CONFIG_PPC64),y)
 	$(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@
 endif
+ifdef CONFIG_VDSO32
 	$(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso32 $@
+endif
 
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
--- linux-4.4.0.orig/arch/powerpc/boot/4xx.c
+++ linux-4.4.0/arch/powerpc/boot/4xx.c
@@ -232,7 +232,7 @@
 		dpath = 8; /* 64 bits */
 
 	/* get address pins (rows) */
- 	val = SDRAM0_READ(DDR0_42);
+	val = SDRAM0_READ(DDR0_42);
 
 	row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT);
 	if (row > max_row)
--- linux-4.4.0.orig/arch/powerpc/boot/Makefile
+++ linux-4.4.0/arch/powerpc/boot/Makefile
@@ -70,7 +70,8 @@
 libfdt       := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
 libfdtheader := fdt.h libfdt.h libfdt_internal.h
 
-$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o): \
+$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o \
+	treeboot-akebono.o treeboot-currituck.o treeboot-iss4xx.o): \
 	$(addprefix $(obj)/,$(libfdtheader))
 
 src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \
--- linux-4.4.0.orig/arch/powerpc/boot/addnote.c
+++ linux-4.4.0/arch/powerpc/boot/addnote.c
@@ -223,7 +223,11 @@
 	PUT_16(E_PHNUM, np + 2);
 
 	/* write back */
-	lseek(fd, (long) 0, SEEK_SET);
+	i = lseek(fd, (long) 0, SEEK_SET);
+	if (i < 0) {
+		perror("lseek");
+		exit(1);
+	}
 	i = write(fd, buf, n);
 	if (i < 0) {
 		perror("write");
--- linux-4.4.0.orig/arch/powerpc/boot/crt0.S
+++ linux-4.4.0/arch/powerpc/boot/crt0.S
@@ -15,7 +15,7 @@
 RELA = 7
 RELACOUNT = 0x6ffffff9
 
-	.text
+	.data
 	/* A procedure descriptor used when booting this as a COFF file.
 	 * When making COFF, this comes first in the link and we're
 	 * linked at 0x500000.
@@ -23,6 +23,8 @@
 	.globl	_zimage_start_opd
 _zimage_start_opd:
 	.long	0x500000, 0, 0, 0
+	.text
+	b	_zimage_start
 
 #ifdef __powerpc64__
 .balign 8
@@ -47,8 +49,10 @@
 p_pstack:	.long	_platform_stack_top
 #endif
 
-	.weak	_zimage_start
 	.globl	_zimage_start
+	/* Clang appears to require the .weak directive to be after the symbol
+	 * is defined. See https://bugs.llvm.org/show_bug.cgi?id=38921  */
+	.weak	_zimage_start
 _zimage_start:
 	.globl	_zimage_start_lib
 _zimage_start_lib:
--- linux-4.4.0.orig/arch/powerpc/boot/dts/bamboo.dts
+++ linux-4.4.0/arch/powerpc/boot/dts/bamboo.dts
@@ -268,8 +268,10 @@
 			/* Outbound ranges, one memory and one IO,
 			 * later cannot be changed. Chip supports a second
 			 * IO range but we don't use it for now
+			 * The chip also supports a larger memory range but
+			 * it's not naturally aligned, so our code will break
 			 */
-			ranges = <0x02000000 0x00000000 0xa0000000 0x00000000 0xa0000000 0x00000000 0x40000000
+			ranges = <0x02000000 0x00000000 0xa0000000 0x00000000 0xa0000000 0x00000000 0x20000000
 				  0x02000000 0x00000000 0x00000000 0x00000000 0xe0000000 0x00000000 0x00100000
 				  0x01000000 0x00000000 0x00000000 0x00000000 0xe8000000 0x00000000 0x00010000>;
 
--- linux-4.4.0.orig/arch/powerpc/boot/dts/fsl/kmcoge4.dts
+++ linux-4.4.0/arch/powerpc/boot/dts/fsl/kmcoge4.dts
@@ -83,6 +83,10 @@
 			};
 		};
 
+		sdhc@114000 {
+			status = "disabled";
+		};
+
 		i2c@119000 {
 			status = "disabled";
 		};
--- linux-4.4.0.orig/arch/powerpc/boot/libfdt_env.h
+++ linux-4.4.0/arch/powerpc/boot/libfdt_env.h
@@ -4,6 +4,10 @@
 #include <types.h>
 #include <string.h>
 
+#define INT_MAX			((int)(~0U>>1))
+#define UINT32_MAX		((u32)~0U)
+#define INT32_MAX		((s32)(UINT32_MAX >> 1))
+
 #include "of.h"
 
 typedef u32 uint32_t;
--- linux-4.4.0.orig/arch/powerpc/boot/ps3-head.S
+++ linux-4.4.0/arch/powerpc/boot/ps3-head.S
@@ -57,11 +57,6 @@
 	bctr
 
 1:
-	/* Save the value at addr zero for a null pointer write check later. */
-
-	li	r4, 0
-	lwz	r3, 0(r4)
-
 	/* Primary delays then goes to _zimage_start in wrapper. */
 
 	or	31, 31, 31 /* db16cyc */
--- linux-4.4.0.orig/arch/powerpc/boot/ps3.c
+++ linux-4.4.0/arch/powerpc/boot/ps3.c
@@ -119,13 +119,12 @@
 	flush_cache((void *)0x100, 512);
 }
 
-void platform_init(unsigned long null_check)
+void platform_init(void)
 {
 	const u32 heapsize = 0x1000000 - (u32)_end; /* 16MiB */
 	void *chosen;
 	unsigned long ft_addr;
 	u64 rm_size;
-	unsigned long val;
 
 	console_ops.write = ps3_console_write;
 	platform_ops.exit = ps3_exit;
@@ -153,11 +152,6 @@
 
 	printf(" flat tree at 0x%lx\n\r", ft_addr);
 
-	val = *(unsigned long *)0;
-
-	if (val != null_check)
-		printf("null check failed: %lx != %lx\n\r", val, null_check);
-
 	((kernel_entry_t)0)(ft_addr, 0, NULL);
 
 	ps3_exit();
--- linux-4.4.0.orig/arch/powerpc/boot/wrapper
+++ linux-4.4.0/arch/powerpc/boot/wrapper
@@ -161,6 +161,28 @@
     elf32-powerpc)	format=elf32ppc	;;
 esac
 
+ld_version()
+{
+    # Poached from scripts/ld-version.sh, but we don't want to call that because
+    # this script (wrapper) is distributed separately from the kernel source.
+    # Extract linker version number from stdin and turn into single number.
+    awk '{
+	gsub(".*\\)", "");
+	gsub(".*version ", "");
+	gsub("-.*", "");
+	split($1,a, ".");
+	print a[1]*100000000 + a[2]*1000000 + a[3]*10000;
+	exit
+    }'
+}
+
+# Do not include PT_INTERP segment when linking pie. Non-pie linking
+# just ignores this option.
+LD_VERSION=$(${CROSS}ld --version | ld_version)
+LD_NO_DL_MIN_VERSION=$(echo 2.26 | ld_version)
+if [ "$LD_VERSION" -ge "$LD_NO_DL_MIN_VERSION" ] ; then
+	nodl="--no-dynamic-linker"
+fi
 
 platformo=$object/"$platform".o
 lds=$object/zImage.lds
@@ -412,7 +434,7 @@
     if [ -n "$link_address" ] ; then
         text_start="-Ttext $link_address"
     fi
-    ${CROSS}ld -m $format -T $lds $text_start $pie -o "$ofile" \
+    ${CROSS}ld -m $format -T $lds $text_start $pie $nodl -o "$ofile" \
 	$platformo $tmp $object/wrapper.a
     rm $tmp
 fi
--- linux-4.4.0.orig/arch/powerpc/boot/zImage.lds.S
+++ linux-4.4.0/arch/powerpc/boot/zImage.lds.S
@@ -68,6 +68,7 @@
   }
 
 #ifdef CONFIG_PPC64_BOOT_WRAPPER
+  . = ALIGN(256);
   .got :
   {
     __toc_start = .;
--- linux-4.4.0.orig/arch/powerpc/configs/pasemi_defconfig
+++ linux-4.4.0/arch/powerpc/configs/pasemi_defconfig
@@ -115,7 +115,6 @@
 CONFIG_FB_NVIDIA_I2C=y
 CONFIG_FB_RADEON=y
 # CONFIG_LCD_CLASS_DEVICE is not set
-CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
--- linux-4.4.0.orig/arch/powerpc/configs/ppc6xx_defconfig
+++ linux-4.4.0/arch/powerpc/configs/ppc6xx_defconfig
@@ -797,7 +797,6 @@
 CONFIG_FB_SM501=m
 CONFIG_FB_IBM_GXT4500=y
 CONFIG_LCD_PLATFORM=m
-CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_LOGO=y
--- linux-4.4.0.orig/arch/powerpc/crypto/aes-spe-glue.c
+++ linux-4.4.0/arch/powerpc/crypto/aes-spe-glue.c
@@ -22,6 +22,7 @@
 #include <asm/byteorder.h>
 #include <asm/switch_to.h>
 #include <crypto/algapi.h>
+#include <crypto/xts.h>
 
 /*
  * MAX_BYTES defines the number of bytes that are allowed to be processed
@@ -85,6 +86,7 @@
 
 static void spe_end(void)
 {
+	disable_kernel_spe();
 	/* reenable preemption */
 	preempt_enable();
 }
@@ -125,6 +127,11 @@
 		   unsigned int key_len)
 {
 	struct ppc_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+	int err;
+
+	err = xts_check_key(tfm, in_key, key_len);
+	if (err)
+		return err;
 
 	key_len >>= 1;
 
--- linux-4.4.0.orig/arch/powerpc/crypto/sha1-powerpc-asm.S
+++ linux-4.4.0/arch/powerpc/crypto/sha1-powerpc-asm.S
@@ -7,6 +7,15 @@
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 
+#ifdef __BIG_ENDIAN__
+#define LWZ(rt, d, ra)	\
+	lwz	rt,d(ra)
+#else
+#define LWZ(rt, d, ra)	\
+	li	rt,d;	\
+	lwbrx	rt,rt,ra
+#endif
+
 /*
  * We roll the registers for T, A, B, C, D, E around on each
  * iteration; T on iteration t is A on iteration t+1, and so on.
@@ -23,7 +32,7 @@
 #define W(t)	(((t)%16)+16)
 
 #define LOADW(t)				\
-	lwz	W(t),(t)*4(r4)
+	LWZ(W(t),(t)*4,r4)
 
 #define STEPD0_LOAD(t)				\
 	andc	r0,RD(t),RB(t);		\
@@ -33,7 +42,7 @@
 	add	r0,RE(t),r15;			\
 	add	RT(t),RT(t),r6;		\
 	add	r14,r0,W(t);			\
-	lwz	W((t)+4),((t)+4)*4(r4);	\
+	LWZ(W((t)+4),((t)+4)*4,r4);	\
 	rotlwi	RB(t),RB(t),30;			\
 	add	RT(t),RT(t),r14
 
--- linux-4.4.0.orig/arch/powerpc/crypto/sha1-spe-glue.c
+++ linux-4.4.0/arch/powerpc/crypto/sha1-spe-glue.c
@@ -46,6 +46,7 @@
 
 static void spe_end(void)
 {
+	disable_kernel_spe();
 	/* reenable preemption */
 	preempt_enable();
 }
--- linux-4.4.0.orig/arch/powerpc/crypto/sha256-spe-glue.c
+++ linux-4.4.0/arch/powerpc/crypto/sha256-spe-glue.c
@@ -47,6 +47,7 @@
 
 static void spe_end(void)
 {
+	disable_kernel_spe();
 	/* reenable preemption */
 	preempt_enable();
 }
--- linux-4.4.0.orig/arch/powerpc/include/asm/archrandom.h
+++ linux-4.4.0/arch/powerpc/include/asm/archrandom.h
@@ -27,7 +27,7 @@
 	unsigned long val;
 	int rc;
 
-	rc = arch_get_random_long(&val);
+	rc = arch_get_random_seed_long(&val);
 	if (rc)
 		*v = val;
 
--- linux-4.4.0.orig/arch/powerpc/include/asm/asm-prototypes.h
+++ linux-4.4.0/arch/powerpc/include/asm/asm-prototypes.h
@@ -0,0 +1,24 @@
+#ifndef _ASM_POWERPC_ASM_PROTOTYPES_H
+#define _ASM_POWERPC_ASM_PROTOTYPES_H
+/*
+ * This file is for prototypes of C functions that are only called
+ * from asm, and any associated variables.
+ *
+ * Copyright 2016, Daniel Axtens, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+/* Patch sites */
+extern s32 patch__call_flush_count_cache;
+extern s32 patch__flush_count_cache_return;
+extern s32 patch__flush_link_stack_return;
+extern s32 patch__call_kvm_flush_link_stack;
+
+extern long flush_count_cache;
+extern long kvm_flush_link_stack;
+
+#endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/atomic.h
+++ linux-4.4.0/arch/powerpc/include/asm/atomic.h
@@ -12,6 +12,24 @@
 
 #define ATOMIC_INIT(i)		{ (i) }
 
+/*
+ * Since *_return_relaxed and {cmp}xchg_relaxed are implemented with
+ * a "bne-" instruction at the end, so an isync is enough as a acquire barrier
+ * on the platform without lwsync.
+ */
+#define __atomic_op_acquire(op, args...)				\
+({									\
+	typeof(op##_relaxed(args)) __ret  = op##_relaxed(args);		\
+	__asm__ __volatile__(PPC_ACQUIRE_BARRIER "" : : : "memory");	\
+	__ret;								\
+})
+
+#define __atomic_op_release(op, args...)				\
+({									\
+	__asm__ __volatile__(PPC_RELEASE_BARRIER "" : : : "memory");	\
+	op##_relaxed(args);						\
+})
+
 static __inline__ int atomic_read(const atomic_t *v)
 {
 	int t;
@@ -42,27 +60,27 @@
 	: "cc");							\
 }									\
 
-#define ATOMIC_OP_RETURN(op, asm_op)					\
-static __inline__ int atomic_##op##_return(int a, atomic_t *v)		\
+#define ATOMIC_OP_RETURN_RELAXED(op, asm_op)				\
+static inline int atomic_##op##_return_relaxed(int a, atomic_t *v)	\
 {									\
 	int t;								\
 									\
 	__asm__ __volatile__(						\
-	PPC_ATOMIC_ENTRY_BARRIER					\
-"1:	lwarx	%0,0,%2		# atomic_" #op "_return\n"		\
-	#asm_op " %0,%1,%0\n"						\
-	PPC405_ERR77(0,%2)						\
-"	stwcx.	%0,0,%2 \n"						\
+"1:	lwarx	%0,0,%3		# atomic_" #op "_return_relaxed\n"	\
+	#asm_op " %0,%2,%0\n"						\
+	PPC405_ERR77(0, %3)						\
+"	stwcx.	%0,0,%3\n"						\
 "	bne-	1b\n"							\
-	PPC_ATOMIC_EXIT_BARRIER						\
-	: "=&r" (t)							\
+	: "=&r" (t), "+m" (v->counter)					\
 	: "r" (a), "r" (&v->counter)					\
-	: "cc", "memory");						\
+	: "cc");							\
 									\
 	return t;							\
 }
 
-#define ATOMIC_OPS(op, asm_op) ATOMIC_OP(op, asm_op) ATOMIC_OP_RETURN(op, asm_op)
+#define ATOMIC_OPS(op, asm_op)						\
+	ATOMIC_OP(op, asm_op)						\
+	ATOMIC_OP_RETURN_RELAXED(op, asm_op)
 
 ATOMIC_OPS(add, add)
 ATOMIC_OPS(sub, subf)
@@ -71,8 +89,11 @@
 ATOMIC_OP(or, or)
 ATOMIC_OP(xor, xor)
 
+#define atomic_add_return_relaxed atomic_add_return_relaxed
+#define atomic_sub_return_relaxed atomic_sub_return_relaxed
+
 #undef ATOMIC_OPS
-#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP_RETURN_RELAXED
 #undef ATOMIC_OP
 
 #define atomic_add_negative(a, v)	(atomic_add_return((a), (v)) < 0)
@@ -92,21 +113,19 @@
 	: "cc", "xer");
 }
 
-static __inline__ int atomic_inc_return(atomic_t *v)
+static __inline__ int atomic_inc_return_relaxed(atomic_t *v)
 {
 	int t;
 
 	__asm__ __volatile__(
-	PPC_ATOMIC_ENTRY_BARRIER
-"1:	lwarx	%0,0,%1		# atomic_inc_return\n\
-	addic	%0,%0,1\n"
-	PPC405_ERR77(0,%1)
-"	stwcx.	%0,0,%1 \n\
-	bne-	1b"
-	PPC_ATOMIC_EXIT_BARRIER
-	: "=&r" (t)
+"1:	lwarx	%0,0,%2		# atomic_inc_return_relaxed\n"
+"	addic	%0,%0,1\n"
+	PPC405_ERR77(0, %2)
+"	stwcx.	%0,0,%2\n"
+"	bne-	1b"
+	: "=&r" (t), "+m" (v->counter)
 	: "r" (&v->counter)
-	: "cc", "xer", "memory");
+	: "cc", "xer");
 
 	return t;
 }
@@ -136,27 +155,34 @@
 	: "cc", "xer");
 }
 
-static __inline__ int atomic_dec_return(atomic_t *v)
+static __inline__ int atomic_dec_return_relaxed(atomic_t *v)
 {
 	int t;
 
 	__asm__ __volatile__(
-	PPC_ATOMIC_ENTRY_BARRIER
-"1:	lwarx	%0,0,%1		# atomic_dec_return\n\
-	addic	%0,%0,-1\n"
-	PPC405_ERR77(0,%1)
-"	stwcx.	%0,0,%1\n\
-	bne-	1b"
-	PPC_ATOMIC_EXIT_BARRIER
-	: "=&r" (t)
+"1:	lwarx	%0,0,%2		# atomic_dec_return_relaxed\n"
+"	addic	%0,%0,-1\n"
+	PPC405_ERR77(0, %2)
+"	stwcx.	%0,0,%2\n"
+"	bne-	1b"
+	: "=&r" (t), "+m" (v->counter)
 	: "r" (&v->counter)
-	: "cc", "xer", "memory");
+	: "cc", "xer");
 
 	return t;
 }
 
+#define atomic_inc_return_relaxed atomic_inc_return_relaxed
+#define atomic_dec_return_relaxed atomic_dec_return_relaxed
+
 #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg_relaxed(v, o, n) \
+	cmpxchg_relaxed(&((v)->counter), (o), (n))
+#define atomic_cmpxchg_acquire(v, o, n) \
+	cmpxchg_acquire(&((v)->counter), (o), (n))
+
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new))
 
 /**
  * __atomic_add_unless - add unless the number is a given value
@@ -285,26 +311,27 @@
 	: "cc");							\
 }
 
-#define ATOMIC64_OP_RETURN(op, asm_op)					\
-static __inline__ long atomic64_##op##_return(long a, atomic64_t *v)	\
+#define ATOMIC64_OP_RETURN_RELAXED(op, asm_op)				\
+static inline long							\
+atomic64_##op##_return_relaxed(long a, atomic64_t *v)			\
 {									\
 	long t;								\
 									\
 	__asm__ __volatile__(						\
-	PPC_ATOMIC_ENTRY_BARRIER					\
-"1:	ldarx	%0,0,%2		# atomic64_" #op "_return\n"		\
-	#asm_op " %0,%1,%0\n"						\
-"	stdcx.	%0,0,%2 \n"						\
+"1:	ldarx	%0,0,%3		# atomic64_" #op "_return_relaxed\n"	\
+	#asm_op " %0,%2,%0\n"						\
+"	stdcx.	%0,0,%3\n"						\
 "	bne-	1b\n"							\
-	PPC_ATOMIC_EXIT_BARRIER						\
-	: "=&r" (t)							\
+	: "=&r" (t), "+m" (v->counter)					\
 	: "r" (a), "r" (&v->counter)					\
-	: "cc", "memory");						\
+	: "cc");							\
 									\
 	return t;							\
 }
 
-#define ATOMIC64_OPS(op, asm_op) ATOMIC64_OP(op, asm_op) ATOMIC64_OP_RETURN(op, asm_op)
+#define ATOMIC64_OPS(op, asm_op)					\
+	ATOMIC64_OP(op, asm_op)						\
+	ATOMIC64_OP_RETURN_RELAXED(op, asm_op)
 
 ATOMIC64_OPS(add, add)
 ATOMIC64_OPS(sub, subf)
@@ -312,8 +339,11 @@
 ATOMIC64_OP(or, or)
 ATOMIC64_OP(xor, xor)
 
-#undef ATOMIC64_OPS
-#undef ATOMIC64_OP_RETURN
+#define atomic64_add_return_relaxed atomic64_add_return_relaxed
+#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed
+
+#undef ATOPIC64_OPS
+#undef ATOMIC64_OP_RETURN_RELAXED
 #undef ATOMIC64_OP
 
 #define atomic64_add_negative(a, v)	(atomic64_add_return((a), (v)) < 0)
@@ -332,20 +362,18 @@
 	: "cc", "xer");
 }
 
-static __inline__ long atomic64_inc_return(atomic64_t *v)
+static __inline__ long atomic64_inc_return_relaxed(atomic64_t *v)
 {
 	long t;
 
 	__asm__ __volatile__(
-	PPC_ATOMIC_ENTRY_BARRIER
-"1:	ldarx	%0,0,%1		# atomic64_inc_return\n\
-	addic	%0,%0,1\n\
-	stdcx.	%0,0,%1 \n\
-	bne-	1b"
-	PPC_ATOMIC_EXIT_BARRIER
-	: "=&r" (t)
+"1:	ldarx	%0,0,%2		# atomic64_inc_return_relaxed\n"
+"	addic	%0,%0,1\n"
+"	stdcx.	%0,0,%2\n"
+"	bne-	1b"
+	: "=&r" (t), "+m" (v->counter)
 	: "r" (&v->counter)
-	: "cc", "xer", "memory");
+	: "cc", "xer");
 
 	return t;
 }
@@ -374,24 +402,25 @@
 	: "cc", "xer");
 }
 
-static __inline__ long atomic64_dec_return(atomic64_t *v)
+static __inline__ long atomic64_dec_return_relaxed(atomic64_t *v)
 {
 	long t;
 
 	__asm__ __volatile__(
-	PPC_ATOMIC_ENTRY_BARRIER
-"1:	ldarx	%0,0,%1		# atomic64_dec_return\n\
-	addic	%0,%0,-1\n\
-	stdcx.	%0,0,%1\n\
-	bne-	1b"
-	PPC_ATOMIC_EXIT_BARRIER
-	: "=&r" (t)
+"1:	ldarx	%0,0,%2		# atomic64_dec_return_relaxed\n"
+"	addic	%0,%0,-1\n"
+"	stdcx.	%0,0,%2\n"
+"	bne-	1b"
+	: "=&r" (t), "+m" (v->counter)
 	: "r" (&v->counter)
-	: "cc", "xer", "memory");
+	: "cc", "xer");
 
 	return t;
 }
 
+#define atomic64_inc_return_relaxed atomic64_inc_return_relaxed
+#define atomic64_dec_return_relaxed atomic64_dec_return_relaxed
+
 #define atomic64_sub_and_test(a, v)	(atomic64_sub_return((a), (v)) == 0)
 #define atomic64_dec_and_test(v)	(atomic64_dec_return((v)) == 0)
 
@@ -420,7 +449,13 @@
 }
 
 #define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_cmpxchg_relaxed(v, o, n) \
+	cmpxchg_relaxed(&((v)->counter), (o), (n))
+#define atomic64_cmpxchg_acquire(v, o, n) \
+	cmpxchg_acquire(&((v)->counter), (o), (n))
+
 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic64_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new))
 
 /**
  * atomic64_add_unless - add unless the number is a given value
@@ -460,7 +495,7 @@
  * Atomically increments @v by 1, so long as @v is non-zero.
  * Returns non-zero if @v was non-zero, and zero otherwise.
  */
-static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
+static __inline__ int atomic64_inc_not_zero(atomic64_t *v)
 {
 	long t1, t2;
 
@@ -479,7 +514,7 @@
 	: "r" (&v->counter)
 	: "cc", "xer", "memory");
 
-	return t1;
+	return t1 != 0;
 }
 
 #endif /* __powerpc64__ */
--- linux-4.4.0.orig/arch/powerpc/include/asm/barrier.h
+++ linux-4.4.0/arch/powerpc/include/asm/barrier.h
@@ -34,9 +34,10 @@
 #define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
 #define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
 
-#define smp_store_mb(var, value)	do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
-#ifdef __SUBARCH_HAS_LWSYNC
+/* The sub-arch has lwsync */
+#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
 #    define SMPWMB      LWSYNC
 #else
 #    define SMPWMB      eieio
@@ -91,4 +92,25 @@
 #define smp_mb__after_atomic()      smp_mb()
 #define smp_mb__before_spinlock()   smp_mb()
 
+#ifdef CONFIG_PPC_BOOK3S_64
+#define NOSPEC_BARRIER_SLOT   nop
+#elif defined(CONFIG_PPC_FSL_BOOK3E)
+#define NOSPEC_BARRIER_SLOT   nop; nop
+#endif
+
+#ifdef CONFIG_PPC_BARRIER_NOSPEC
+/*
+ * Prevent execution of subsequent instructions until preceding branches have
+ * been fully resolved and are no longer executing speculatively.
+ */
+#define barrier_nospec_asm NOSPEC_BARRIER_FIXUP_SECTION; NOSPEC_BARRIER_SLOT
+
+// This also acts as a compiler barrier due to the memory clobber.
+#define barrier_nospec() asm (stringify_in_c(barrier_nospec_asm) ::: "memory")
+
+#else /* !CONFIG_PPC_BARRIER_NOSPEC */
+#define barrier_nospec_asm
+#define barrier_nospec()
+#endif /* CONFIG_PPC_BARRIER_NOSPEC */
+
 #endif /* _ASM_POWERPC_BARRIER_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/book3s/64/kup-radix.h
+++ linux-4.4.0/arch/powerpc/include/asm/book3s/64/kup-radix.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
+#define _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
+#include <linux/jump_label.h>
+
+DECLARE_STATIC_KEY_FALSE(uaccess_flush_key);
+
+/* Prototype for function defined in exceptions-64s.S */
+void do_uaccess_flush(void);
+
+static __always_inline void allow_user_access(void __user *to, const void __user *from,
+					      unsigned long size)
+{
+}
+
+static inline void prevent_user_access(void __user *to, const void __user *from,
+				       unsigned long size)
+{
+	if (static_branch_unlikely(&uaccess_flush_key))
+		do_uaccess_flush();
+}
+
+#endif /* _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/cmpxchg.h
+++ linux-4.4.0/arch/powerpc/include/asm/cmpxchg.h
@@ -9,21 +9,20 @@
 /*
  * Atomic exchange
  *
- * Changes the memory location '*ptr' to be val and returns
+ * Changes the memory location '*p' to be val and returns
  * the previous value stored there.
  */
+
 static __always_inline unsigned long
-__xchg_u32(volatile void *p, unsigned long val)
+__xchg_u32_local(volatile void *p, unsigned long val)
 {
 	unsigned long prev;
 
 	__asm__ __volatile__(
-	PPC_RELEASE_BARRIER
 "1:	lwarx	%0,0,%2 \n"
 	PPC405_ERR77(0,%2)
 "	stwcx.	%3,0,%2 \n\
 	bne-	1b"
-	PPC_ACQUIRE_BARRIER
 	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
 	: "r" (p), "r" (val)
 	: "cc", "memory");
@@ -31,42 +30,34 @@
 	return prev;
 }
 
-/*
- * Atomic exchange
- *
- * Changes the memory location '*ptr' to be val and returns
- * the previous value stored there.
- */
 static __always_inline unsigned long
-__xchg_u32_local(volatile void *p, unsigned long val)
+__xchg_u32_relaxed(u32 *p, unsigned long val)
 {
 	unsigned long prev;
 
 	__asm__ __volatile__(
-"1:	lwarx	%0,0,%2 \n"
-	PPC405_ERR77(0,%2)
-"	stwcx.	%3,0,%2 \n\
-	bne-	1b"
-	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
+"1:	lwarx	%0,0,%2\n"
+	PPC405_ERR77(0, %2)
+"	stwcx.	%3,0,%2\n"
+"	bne-	1b"
+	: "=&r" (prev), "+m" (*p)
 	: "r" (p), "r" (val)
-	: "cc", "memory");
+	: "cc");
 
 	return prev;
 }
 
 #ifdef CONFIG_PPC64
 static __always_inline unsigned long
-__xchg_u64(volatile void *p, unsigned long val)
+__xchg_u64_local(volatile void *p, unsigned long val)
 {
 	unsigned long prev;
 
 	__asm__ __volatile__(
-	PPC_RELEASE_BARRIER
 "1:	ldarx	%0,0,%2 \n"
 	PPC405_ERR77(0,%2)
 "	stdcx.	%3,0,%2 \n\
 	bne-	1b"
-	PPC_ACQUIRE_BARRIER
 	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
 	: "r" (p), "r" (val)
 	: "cc", "memory");
@@ -75,18 +66,18 @@
 }
 
 static __always_inline unsigned long
-__xchg_u64_local(volatile void *p, unsigned long val)
+__xchg_u64_relaxed(u64 *p, unsigned long val)
 {
 	unsigned long prev;
 
 	__asm__ __volatile__(
-"1:	ldarx	%0,0,%2 \n"
-	PPC405_ERR77(0,%2)
-"	stdcx.	%3,0,%2 \n\
-	bne-	1b"
-	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
+"1:	ldarx	%0,0,%2\n"
+	PPC405_ERR77(0, %2)
+"	stdcx.	%3,0,%2\n"
+"	bne-	1b"
+	: "=&r" (prev), "+m" (*p)
 	: "r" (p), "r" (val)
-	: "cc", "memory");
+	: "cc");
 
 	return prev;
 }
@@ -99,14 +90,14 @@
 extern void __xchg_called_with_bad_pointer(void);
 
 static __always_inline unsigned long
-__xchg(volatile void *ptr, unsigned long x, unsigned int size)
+__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
 {
 	switch (size) {
 	case 4:
-		return __xchg_u32(ptr, x);
+		return __xchg_u32_local(ptr, x);
 #ifdef CONFIG_PPC64
 	case 8:
-		return __xchg_u64(ptr, x);
+		return __xchg_u64_local(ptr, x);
 #endif
 	}
 	__xchg_called_with_bad_pointer();
@@ -114,25 +105,19 @@
 }
 
 static __always_inline unsigned long
-__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
+__xchg_relaxed(void *ptr, unsigned long x, unsigned int size)
 {
 	switch (size) {
 	case 4:
-		return __xchg_u32_local(ptr, x);
+		return __xchg_u32_relaxed(ptr, x);
 #ifdef CONFIG_PPC64
 	case 8:
-		return __xchg_u64_local(ptr, x);
+		return __xchg_u64_relaxed(ptr, x);
 #endif
 	}
 	__xchg_called_with_bad_pointer();
 	return x;
 }
-#define xchg(ptr,x)							     \
-  ({									     \
-     __typeof__(*(ptr)) _x_ = (x);					     \
-     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
-  })
-
 #define xchg_local(ptr,x)						     \
   ({									     \
      __typeof__(*(ptr)) _x_ = (x);					     \
@@ -140,6 +125,12 @@
      		(unsigned long)_x_, sizeof(*(ptr))); 			     \
   })
 
+#define xchg_relaxed(ptr, x)						\
+({									\
+	__typeof__(*(ptr)) _x_ = (x);					\
+	(__typeof__(*(ptr))) __xchg_relaxed((ptr),			\
+			(unsigned long)_x_, sizeof(*(ptr)));		\
+})
 /*
  * Compare and exchange - if *p == old, set it to new,
  * and return the old value of *p.
@@ -151,14 +142,14 @@
 	unsigned int prev;
 
 	__asm__ __volatile__ (
-	PPC_RELEASE_BARRIER
+	PPC_ATOMIC_ENTRY_BARRIER
 "1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
 	cmpw	0,%0,%3\n\
 	bne-	2f\n"
 	PPC405_ERR77(0,%2)
 "	stwcx.	%4,0,%2\n\
 	bne-	1b"
-	PPC_ACQUIRE_BARRIER
+	PPC_ATOMIC_EXIT_BARRIER
 	"\n\
 2:"
 	: "=&r" (prev), "+m" (*p)
@@ -190,6 +181,56 @@
 	return prev;
 }
 
+static __always_inline unsigned long
+__cmpxchg_u32_relaxed(u32 *p, unsigned long old, unsigned long new)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__ (
+"1:	lwarx	%0,0,%2		# __cmpxchg_u32_relaxed\n"
+"	cmpw	0,%0,%3\n"
+"	bne-	2f\n"
+	PPC405_ERR77(0, %2)
+"	stwcx.	%4,0,%2\n"
+"	bne-	1b\n"
+"2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc");
+
+	return prev;
+}
+
+/*
+ * cmpxchg family don't have order guarantee if cmp part fails, therefore we
+ * can avoid superfluous barriers if we use assembly code to implement
+ * cmpxchg() and cmpxchg_acquire(), however we don't do the similar for
+ * cmpxchg_release() because that will result in putting a barrier in the
+ * middle of a ll/sc loop, which is probably a bad idea. For example, this
+ * might cause the conditional store more likely to fail.
+ */
+static __always_inline unsigned long
+__cmpxchg_u32_acquire(u32 *p, unsigned long old, unsigned long new)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__ (
+"1:	lwarx	%0,0,%2		# __cmpxchg_u32_acquire\n"
+"	cmpw	0,%0,%3\n"
+"	bne-	2f\n"
+	PPC405_ERR77(0, %2)
+"	stwcx.	%4,0,%2\n"
+"	bne-	1b\n"
+	PPC_ACQUIRE_BARRIER
+	"\n"
+"2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
+
 #ifdef CONFIG_PPC64
 static __always_inline unsigned long
 __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
@@ -197,13 +238,13 @@
 	unsigned long prev;
 
 	__asm__ __volatile__ (
-	PPC_RELEASE_BARRIER
+	PPC_ATOMIC_ENTRY_BARRIER
 "1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
 	cmpd	0,%0,%3\n\
 	bne-	2f\n\
 	stdcx.	%4,0,%2\n\
 	bne-	1b"
-	PPC_ACQUIRE_BARRIER
+	PPC_ATOMIC_EXIT_BARRIER
 	"\n\
 2:"
 	: "=&r" (prev), "+m" (*p)
@@ -233,6 +274,46 @@
 
 	return prev;
 }
+
+static __always_inline unsigned long
+__cmpxchg_u64_relaxed(u64 *p, unsigned long old, unsigned long new)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__ (
+"1:	ldarx	%0,0,%2		# __cmpxchg_u64_relaxed\n"
+"	cmpd	0,%0,%3\n"
+"	bne-	2f\n"
+"	stdcx.	%4,0,%2\n"
+"	bne-	1b\n"
+"2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc");
+
+	return prev;
+}
+
+static __always_inline unsigned long
+__cmpxchg_u64_acquire(u64 *p, unsigned long old, unsigned long new)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__ (
+"1:	ldarx	%0,0,%2		# __cmpxchg_u64_acquire\n"
+"	cmpd	0,%0,%3\n"
+"	bne-	2f\n"
+"	stdcx.	%4,0,%2\n"
+"	bne-	1b\n"
+	PPC_ACQUIRE_BARRIER
+	"\n"
+"2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
 #endif
 
 /* This function doesn't exist, so you'll get a linker error
@@ -271,6 +352,37 @@
 	return old;
 }
 
+static __always_inline unsigned long
+__cmpxchg_relaxed(void *ptr, unsigned long old, unsigned long new,
+		  unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32_relaxed(ptr, old, new);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __cmpxchg_u64_relaxed(ptr, old, new);
+#endif
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+static __always_inline unsigned long
+__cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
+		  unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32_acquire(ptr, old, new);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __cmpxchg_u64_acquire(ptr, old, new);
+#endif
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
 #define cmpxchg(ptr, o, n)						 \
   ({									 \
      __typeof__(*(ptr)) _o_ = (o);					 \
@@ -288,6 +400,23 @@
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+#define cmpxchg_relaxed(ptr, o, n)					\
+({									\
+	__typeof__(*(ptr)) _o_ = (o);					\
+	__typeof__(*(ptr)) _n_ = (n);					\
+	(__typeof__(*(ptr))) __cmpxchg_relaxed((ptr),			\
+			(unsigned long)_o_, (unsigned long)_n_,		\
+			sizeof(*(ptr)));				\
+})
+
+#define cmpxchg_acquire(ptr, o, n)					\
+({									\
+	__typeof__(*(ptr)) _o_ = (o);					\
+	__typeof__(*(ptr)) _n_ = (n);					\
+	(__typeof__(*(ptr))) __cmpxchg_acquire((ptr),			\
+			(unsigned long)_o_, (unsigned long)_n_,		\
+			sizeof(*(ptr)));				\
+})
 #ifdef CONFIG_PPC64
 #define cmpxchg64(ptr, o, n)						\
   ({									\
@@ -299,7 +428,16 @@
 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
 	cmpxchg_local((ptr), (o), (n));					\
   })
-#define cmpxchg64_relaxed	cmpxchg64_local
+#define cmpxchg64_relaxed(ptr, o, n)					\
+({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
+	cmpxchg_relaxed((ptr), (o), (n));				\
+})
+#define cmpxchg64_acquire(ptr, o, n)					\
+({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
+	cmpxchg_acquire((ptr), (o), (n));				\
+})
 #else
 #include <asm-generic/cmpxchg-local.h>
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
--- linux-4.4.0.orig/arch/powerpc/include/asm/code-patching-asm.h
+++ linux-4.4.0/arch/powerpc/include/asm/code-patching-asm.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018, Michael Ellerman, IBM Corporation.
+ */
+#ifndef _ASM_POWERPC_CODE_PATCHING_ASM_H
+#define _ASM_POWERPC_CODE_PATCHING_ASM_H
+
+/* Define a "site" that can be patched */
+.macro patch_site label name
+	.pushsection ".rodata"
+	.balign 4
+	.global \name
+\name:
+	.4byte	\label - .
+	.popsection
+.endm
+
+#endif /* _ASM_POWERPC_CODE_PATCHING_ASM_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/code-patching.h
+++ linux-4.4.0/arch/powerpc/include/asm/code-patching.h
@@ -28,6 +28,8 @@
 				unsigned long target, int flags);
 int patch_branch(unsigned int *addr, unsigned long target, int flags);
 int patch_instruction(unsigned int *addr, unsigned int instr);
+int patch_instruction_site(s32 *addr, unsigned int instr);
+int patch_branch_site(s32 *site, unsigned long target, int flags);
 
 int instr_is_relative_branch(unsigned int instr);
 int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr);
@@ -43,7 +45,7 @@
 #endif
 
 #define OP_RT_RA_MASK	0xffff0000UL
-#define LIS_R2		0x3c020000UL
+#define LIS_R2		0x3c400000UL
 #define ADDIS_R2_R12	0x3c4c0000UL
 #define ADDI_R2_R2	0x38420000UL
 
--- linux-4.4.0.orig/arch/powerpc/include/asm/cpufeature.h
+++ linux-4.4.0/arch/powerpc/include/asm/cpufeature.h
@@ -0,0 +1,40 @@
+/*
+ * CPU feature definitions for module loading, used by
+ * module_cpu_feature_match(), see asm/cputable.h for powerpc CPU features.
+ *
+ * Copyright 2016 Alastair D'Silva, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __ASM_POWERPC_CPUFEATURE_H
+#define __ASM_POWERPC_CPUFEATURE_H
+
+#include <asm/cputable.h>
+
+/* Keep these in step with powerpc/include/asm/cputable.h */
+#define MAX_CPU_FEATURES (2 * 32)
+
+/*
+ * Currently we don't have a need for any of the feature bits defined in
+ * cpu_user_features. When we do, they should be defined such as:
+ *
+ * #define PPC_MODULE_FEATURE_32 (ilog2(PPC_FEATURE_32))
+ */
+
+#define PPC_MODULE_FEATURE_VEC_CRYPTO			(32 + ilog2(PPC_FEATURE2_VEC_CRYPTO))
+
+#define cpu_feature(x)		(x)
+
+static inline bool cpu_have_feature(unsigned int num)
+{
+	if (num < 32)
+		return !!(cur_cpu_spec->cpu_user_features & 1UL << num);
+	else
+		return !!(cur_cpu_spec->cpu_user_features2 & 1UL << (num - 32));
+}
+
+#endif /* __ASM_POWERPC_CPUFEATURE_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/cputable.h
+++ linux-4.4.0/arch/powerpc/include/asm/cputable.h
@@ -400,7 +400,6 @@
 	    CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
 	    CPU_FTR_DEBUG_LVL_EXC | CPU_FTR_EMB_HV | CPU_FTR_ALTIVEC_COMP | \
 	    CPU_FTR_CELL_TB_BUG | CPU_FTR_SMT)
-#define CPU_FTRS_GENERIC_32	(CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 
 /* 64-bit CPUs */
 #define CPU_FTRS_POWER4	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
@@ -479,8 +478,6 @@
 	    CPU_FTRS_7447 | CPU_FTRS_7447A | CPU_FTRS_82XX |
 	    CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_E300C2 |
 	    CPU_FTRS_CLASSIC32 |
-#else
-	    CPU_FTRS_GENERIC_32 |
 #endif
 #ifdef CONFIG_8xx
 	    CPU_FTRS_8XX |
@@ -530,8 +527,6 @@
 	    CPU_FTRS_7447 & CPU_FTRS_7447A & CPU_FTRS_82XX &
 	    CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_E300C2 &
 	    CPU_FTRS_CLASSIC32 &
-#else
-	    CPU_FTRS_GENERIC_32 &
 #endif
 #ifdef CONFIG_8xx
 	    CPU_FTRS_8XX &
--- linux-4.4.0.orig/arch/powerpc/include/asm/eeh.h
+++ linux-4.4.0/arch/powerpc/include/asm/eeh.h
@@ -81,6 +81,7 @@
 #define EEH_PE_KEEP		(1 << 8)	/* Keep PE on hotplug	*/
 #define EEH_PE_CFG_RESTRICTED	(1 << 9)	/* Block config on error */
 #define EEH_PE_REMOVED		(1 << 10)	/* Removed permanently	*/
+#define EEH_PE_PRI_BUS		(1 << 11)	/* Cached primary bus   */
 
 struct eeh_pe {
 	int type;			/* PE type: PHB/Bus/Device	*/
--- linux-4.4.0.orig/arch/powerpc/include/asm/elf.h
+++ linux-4.4.0/arch/powerpc/include/asm/elf.h
@@ -23,12 +23,13 @@
 #define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE	PAGE_SIZE
 
-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
-   use of this is to invoke "./ld.so someprog" to test out a new version of
-   the loader.  We need to make sure that it is out of the way of the program
-   that it will "exec", and that there is sufficient room for the brk.  */
-
-#define ELF_ET_DYN_BASE	0x20000000
+/*
+ * This is the base location for PIE (ET_DYN with INTERP) loads. On
+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * space open for things that want to use the area for 32-bit pointers.
+ */
+#define ELF_ET_DYN_BASE		(is_32bit_task() ? 0x000400000UL : \
+						   0x100000000UL)
 
 #define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)
 
--- linux-4.4.0.orig/arch/powerpc/include/asm/epapr_hcalls.h
+++ linux-4.4.0/arch/powerpc/include/asm/epapr_hcalls.h
@@ -508,7 +508,7 @@
 
 static inline long epapr_hypercall0_1(unsigned int nr, unsigned long *r2)
 {
-	unsigned long in[8];
+	unsigned long in[8] = {0};
 	unsigned long out[8];
 	unsigned long r;
 
@@ -520,7 +520,7 @@
 
 static inline long epapr_hypercall0(unsigned int nr)
 {
-	unsigned long in[8];
+	unsigned long in[8] = {0};
 	unsigned long out[8];
 
 	return epapr_hypercall(in, out, nr);
@@ -528,7 +528,7 @@
 
 static inline long epapr_hypercall1(unsigned int nr, unsigned long p1)
 {
-	unsigned long in[8];
+	unsigned long in[8] = {0};
 	unsigned long out[8];
 
 	in[0] = p1;
@@ -538,7 +538,7 @@
 static inline long epapr_hypercall2(unsigned int nr, unsigned long p1,
 				    unsigned long p2)
 {
-	unsigned long in[8];
+	unsigned long in[8] = {0};
 	unsigned long out[8];
 
 	in[0] = p1;
@@ -549,7 +549,7 @@
 static inline long epapr_hypercall3(unsigned int nr, unsigned long p1,
 				    unsigned long p2, unsigned long p3)
 {
-	unsigned long in[8];
+	unsigned long in[8] = {0};
 	unsigned long out[8];
 
 	in[0] = p1;
@@ -562,7 +562,7 @@
 				    unsigned long p2, unsigned long p3,
 				    unsigned long p4)
 {
-	unsigned long in[8];
+	unsigned long in[8] = {0};
 	unsigned long out[8];
 
 	in[0] = p1;
--- linux-4.4.0.orig/arch/powerpc/include/asm/exception-64e.h
+++ linux-4.4.0/arch/powerpc/include/asm/exception-64e.h
@@ -209,5 +209,11 @@
 	ori	r3,r3,vector_offset@l;		\
 	mtspr	SPRN_IVOR##vector_number,r3;
 
+#define RFI_TO_KERNEL							\
+	rfi
+
+#define RFI_TO_USER							\
+	rfi
+
 #endif /* _ASM_POWERPC_EXCEPTION_64E_H */
 
--- linux-4.4.0.orig/arch/powerpc/include/asm/exception-64s.h
+++ linux-4.4.0/arch/powerpc/include/asm/exception-64s.h
@@ -50,6 +50,94 @@
 #define EX_PPR		88	/* SMT thread status register (priority) */
 #define EX_CTR		96
 
+#define STF_ENTRY_BARRIER_SLOT						\
+	STF_ENTRY_BARRIER_FIXUP_SECTION;				\
+	nop;								\
+	nop;								\
+	nop
+
+#define STF_EXIT_BARRIER_SLOT						\
+	STF_EXIT_BARRIER_FIXUP_SECTION;					\
+	nop;								\
+	nop;								\
+	nop;								\
+	nop;								\
+	nop;								\
+	nop
+
+#define ENTRY_FLUSH_SLOT						\
+	ENTRY_FLUSH_FIXUP_SECTION;					\
+	nop;								\
+	nop;								\
+	nop;
+
+/*
+ * r10 must be free to use, r13 must be paca
+ */
+#define INTERRUPT_TO_KERNEL						\
+	STF_ENTRY_BARRIER_SLOT;						\
+	ENTRY_FLUSH_SLOT
+
+/*
+ * Macros for annotating the expected destination of (h)rfid
+ *
+ * The nop instructions allow us to insert one or more instructions to flush the
+ * L1-D cache when returning to userspace or a guest.
+ */
+#define RFI_FLUSH_SLOT							\
+	RFI_FLUSH_FIXUP_SECTION;					\
+	nop;								\
+	nop;								\
+	nop
+
+#define RFI_TO_KERNEL							\
+	rfid
+
+#define RFI_TO_USER							\
+	STF_EXIT_BARRIER_SLOT;						\
+	RFI_FLUSH_SLOT;							\
+	rfid;								\
+	b	rfi_flush_fallback
+
+#define RFI_TO_USER_OR_KERNEL						\
+	STF_EXIT_BARRIER_SLOT;						\
+	RFI_FLUSH_SLOT;							\
+	rfid;								\
+	b	rfi_flush_fallback
+
+#define RFI_TO_GUEST							\
+	STF_EXIT_BARRIER_SLOT;						\
+	RFI_FLUSH_SLOT;							\
+	rfid;								\
+	b	rfi_flush_fallback
+
+#define HRFI_TO_KERNEL							\
+	hrfid
+
+#define HRFI_TO_USER							\
+	STF_EXIT_BARRIER_SLOT;						\
+	RFI_FLUSH_SLOT;							\
+	hrfid;								\
+	b	hrfi_flush_fallback
+
+#define HRFI_TO_USER_OR_KERNEL						\
+	STF_EXIT_BARRIER_SLOT;						\
+	RFI_FLUSH_SLOT;							\
+	hrfid;								\
+	b	hrfi_flush_fallback
+
+#define HRFI_TO_GUEST							\
+	STF_EXIT_BARRIER_SLOT;						\
+	RFI_FLUSH_SLOT;							\
+	hrfid;								\
+	b	hrfi_flush_fallback
+
+#define HRFI_TO_UNKNOWN							\
+	STF_EXIT_BARRIER_SLOT;						\
+	RFI_FLUSH_SLOT;							\
+	hrfid;								\
+	b	hrfi_flush_fallback
+
 #ifdef CONFIG_RELOCATABLE
 #define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)			\
 	ld	r12,PACAKBASE(r13);	/* get high part of &label */	\
@@ -173,6 +261,7 @@
 #define __EXCEPTION_PROLOG_1(area, extra, vec)				\
 	OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR);		\
 	OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR);		\
+	INTERRUPT_TO_KERNEL;						\
 	SAVE_CTR(r10, area);						\
 	mfcr	r9;							\
 	extra(vec);							\
@@ -191,7 +280,7 @@
 	mtspr	SPRN_##h##SRR0,r12;					\
 	mfspr	r12,SPRN_##h##SRR1;	/* and SRR1 */			\
 	mtspr	SPRN_##h##SRR1,r10;					\
-	h##rfid;							\
+	h##RFI_TO_KERNEL;						\
 	b	.	/* prevent speculative execution */
 #define EXCEPTION_PROLOG_PSERIES_1(label, h)				\
 	__EXCEPTION_PROLOG_PSERIES_1(label, h)
@@ -459,6 +548,12 @@
 #define _MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)		\
 	__MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)
 
+#define MASKABLE_EXCEPTION_OOL(vec, label)				\
+	.globl label##_ool;						\
+label##_ool:								\
+	EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_PR, vec);		\
+	EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD);
+
 #define MASKABLE_EXCEPTION_PSERIES(loc, vec, label)			\
 	. = loc;							\
 	.globl label##_pSeries;						\
@@ -509,6 +604,12 @@
 	EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_NOTEST_HV, vec);		\
 	EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV);
 
+#define MASKABLE_RELON_EXCEPTION_PSERIES_OOL(vec, label)               \
+       .globl label##_relon_pSeries;                                   \
+label##_relon_pSeries:                                                 \
+       EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_NOTEST_PR, vec);          \
+       EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD)
+
 /*
  * Our exception common code can be passed various "additions"
  * to specify the behaviour of interrupts, whether to kick the
--- linux-4.4.0.orig/arch/powerpc/include/asm/fadump.h
+++ linux-4.4.0/arch/powerpc/include/asm/fadump.h
@@ -194,9 +194,6 @@
 	struct cpumask	cpu_online_mask;
 };
 
-/* Crash memory ranges */
-#define INIT_CRASHMEM_RANGES	(INIT_MEMBLOCK_REGIONS + 2)
-
 struct fad_crash_memory_ranges {
 	unsigned long long	base;
 	unsigned long long	size;
--- linux-4.4.0.orig/arch/powerpc/include/asm/feature-fixups.h
+++ linux-4.4.0/arch/powerpc/include/asm/feature-fixups.h
@@ -184,4 +184,78 @@
 	FTR_ENTRY_OFFSET label##1b-label##3b;		\
 	.popsection;
 
+#define STF_ENTRY_BARRIER_FIXUP_SECTION			\
+953:							\
+	.pushsection __stf_entry_barrier_fixup,"a";	\
+	.align 2;					\
+954:							\
+	FTR_ENTRY_OFFSET 953b-954b;			\
+	.popsection;
+
+#define STF_EXIT_BARRIER_FIXUP_SECTION			\
+955:							\
+	.pushsection __stf_exit_barrier_fixup,"a";	\
+	.align 2;					\
+956:							\
+	FTR_ENTRY_OFFSET 955b-956b;			\
+	.popsection;
+
+#define UACCESS_FLUSH_FIXUP_SECTION			\
+959:							\
+	.pushsection __uaccess_flush_fixup,"a";		\
+	.align 2;					\
+960:							\
+	FTR_ENTRY_OFFSET 959b-960b;			\
+	.popsection;
+
+#define ENTRY_FLUSH_FIXUP_SECTION			\
+957:							\
+	.pushsection __entry_flush_fixup,"a";		\
+	.align 2;					\
+958:							\
+	FTR_ENTRY_OFFSET 957b-958b;			\
+	.popsection;
+
+#define RFI_FLUSH_FIXUP_SECTION				\
+951:							\
+	.pushsection __rfi_flush_fixup,"a";		\
+	.align 2;					\
+952:							\
+	FTR_ENTRY_OFFSET 951b-952b;			\
+	.popsection;
+
+#define NOSPEC_BARRIER_FIXUP_SECTION			\
+953:							\
+	.pushsection __barrier_nospec_fixup,"a";	\
+	.align 2;					\
+954:							\
+	FTR_ENTRY_OFFSET 953b-954b;			\
+	.popsection;
+
+#define START_BTB_FLUSH_SECTION			\
+955:							\
+
+#define END_BTB_FLUSH_SECTION			\
+956:							\
+	.pushsection __btb_flush_fixup,"a";	\
+	.align 2;							\
+957:						\
+	FTR_ENTRY_OFFSET 955b-957b;			\
+	FTR_ENTRY_OFFSET 956b-957b;			\
+	.popsection;
+
+#ifndef __ASSEMBLY__
+
+extern long stf_barrier_fallback;
+extern long entry_flush_fallback;
+extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup;
+extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup;
+extern long __start___uaccess_flush_fixup, __stop___uaccess_flush_fixup;
+extern long __start___entry_flush_fixup, __stop___entry_flush_fixup;
+extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
+extern long __start___barrier_nospec_fixup, __stop___barrier_nospec_fixup;
+extern long __start__btb_flush_fixup, __stop__btb_flush_fixup;
+
+#endif
+
 #endif /* __ASM_POWERPC_FEATURE_FIXUPS_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/firmware.h
+++ linux-4.4.0/arch/powerpc/include/asm/firmware.h
@@ -47,12 +47,10 @@
 #define FW_FEATURE_VPHN		ASM_CONST(0x0000000004000000)
 #define FW_FEATURE_XCMO		ASM_CONST(0x0000000008000000)
 #define FW_FEATURE_OPAL		ASM_CONST(0x0000000010000000)
-#define FW_FEATURE_OPALv2	ASM_CONST(0x0000000020000000)
 #define FW_FEATURE_SET_MODE	ASM_CONST(0x0000000040000000)
 #define FW_FEATURE_BEST_ENERGY	ASM_CONST(0x0000000080000000)
 #define FW_FEATURE_TYPE1_AFFINITY ASM_CONST(0x0000000100000000)
 #define FW_FEATURE_PRRN		ASM_CONST(0x0000000200000000)
-#define FW_FEATURE_OPALv3	ASM_CONST(0x0000000400000000)
 
 #ifndef __ASSEMBLY__
 
@@ -70,8 +68,7 @@
 		FW_FEATURE_SET_MODE | FW_FEATURE_BEST_ENERGY |
 		FW_FEATURE_TYPE1_AFFINITY | FW_FEATURE_PRRN,
 	FW_FEATURE_PSERIES_ALWAYS = 0,
-	FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2 |
-		FW_FEATURE_OPALv3,
+	FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL,
 	FW_FEATURE_POWERNV_ALWAYS = 0,
 	FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
 	FW_FEATURE_PS3_ALWAYS = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
--- linux-4.4.0.orig/arch/powerpc/include/asm/futex.h
+++ linux-4.4.0/arch/powerpc/include/asm/futex.h
@@ -31,19 +31,12 @@
 	: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
 	: "cr0", "memory")
 
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
+	allow_write_to_user(uaddr, sizeof(*uaddr));
 	pagefault_disable();
 
 	switch (op) {
@@ -68,17 +61,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	*oval = oldval;
+
+	prevent_write_to_user(uaddr, sizeof(*uaddr));
 	return ret;
 }
 
@@ -92,6 +77,7 @@
 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
 
+	allow_write_to_user(uaddr, sizeof(*uaddr));
         __asm__ __volatile__ (
         PPC_ATOMIC_ENTRY_BARRIER
 "1:     lwarx   %1,0,%3         # futex_atomic_cmpxchg_inatomic\n\
@@ -114,6 +100,7 @@
         : "cc", "memory");
 
 	*uval = prev;
+	prevent_write_to_user(uaddr, sizeof(*uaddr));
         return ret;
 }
 
--- linux-4.4.0.orig/arch/powerpc/include/asm/hmi.h
+++ linux-4.4.0/arch/powerpc/include/asm/hmi.h
@@ -0,0 +1,45 @@
+/*
+ * Hypervisor Maintenance Interrupt header file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ *
+ * Copyright 2015 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#ifndef __ASM_PPC64_HMI_H__
+#define __ASM_PPC64_HMI_H__
+
+#ifdef CONFIG_PPC_BOOK3S_64
+
+#define	CORE_TB_RESYNC_REQ_BIT		63
+#define MAX_SUBCORE_PER_CORE		4
+
+/*
+ * sibling_subcore_state structure is used to co-ordinate all threads
+ * during HMI to avoid TB corruption. This structure is allocated once
+ * per each core and shared by all threads on that core.
+ */
+struct sibling_subcore_state {
+	unsigned long	flags;
+	u8		in_guest[MAX_SUBCORE_PER_CORE];
+};
+
+extern void wait_for_subcore_guest_exit(void);
+extern void wait_for_tb_resync(void);
+#else
+static inline void wait_for_subcore_guest_exit(void) { }
+static inline void wait_for_tb_resync(void) { }
+#endif
+#endif /* __ASM_PPC64_HMI_H__ */
--- linux-4.4.0.orig/arch/powerpc/include/asm/hvcall.h
+++ linux-4.4.0/arch/powerpc/include/asm/hvcall.h
@@ -94,6 +94,7 @@
 #define H_SG_LIST	-72
 #define H_OP_MODE	-73
 #define H_COP_HW	-74
+#define H_STATE		-75
 #define H_UNSUPPORTED_FLAG_START	-256
 #define H_UNSUPPORTED_FLAG_END		-511
 #define H_MULTI_THREADS_ACTIVE	-9005
@@ -239,6 +240,7 @@
 #define H_GET_HCA_INFO          0x1B8
 #define H_GET_PERF_COUNT        0x1BC
 #define H_MANAGE_TRACE          0x1C0
+#define H_GET_CPU_CHARACTERISTICS 0x1C8
 #define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
 #define H_QUERY_INT_STATE       0x1E4
 #define H_POLL_PENDING		0x1D8
@@ -258,11 +260,16 @@
 #define H_DEL_CONN		0x288
 #define H_JOIN			0x298
 #define H_VASI_STATE            0x2A4
+#define H_VIOCTL		0x2A8
 #define H_ENABLE_CRQ		0x2B0
 #define H_GET_EM_PARMS		0x2B8
 #define H_SET_MPP		0x2D0
 #define H_GET_MPP		0x2D4
+#define H_REG_SUB_CRQ		0x2DC
 #define H_HOME_NODE_ASSOCIATIVITY 0x2EC
+#define H_FREE_SUB_CRQ		0x2E0
+#define H_SEND_SUB_CRQ		0x2E4
+#define H_SEND_SUB_CRQ_INDIRECT	0x2E8
 #define H_BEST_ENERGY		0x2F4
 #define H_XIRR_X		0x2FC
 #define H_RANDOM		0x300
@@ -271,6 +278,21 @@
 #define H_SET_MODE		0x31C
 #define MAX_HCALL_OPCODE	H_SET_MODE
 
+/* H_VIOCTL functions */
+#define H_GET_VIOA_DUMP_SIZE	0x01
+#define H_GET_VIOA_DUMP		0x02
+#define H_GET_ILLAN_NUM_VLAN_IDS 0x03
+#define H_GET_ILLAN_VLAN_ID_LIST 0x04
+#define H_GET_ILLAN_SWITCH_ID	0x05
+#define H_DISABLE_MIGRATION	0x06
+#define H_ENABLE_MIGRATION	0x07
+#define H_GET_PARTNER_INFO	0x08
+#define H_GET_PARTNER_WWPN_LIST	0x09
+#define H_DISABLE_ALL_VIO_INTS	0x0A
+#define H_DISABLE_VIO_INTERRUPT	0x0B
+#define H_ENABLE_VIO_INTERRUPT	0x0C
+
+
 /* Platform specific hcalls, used by KVM */
 #define H_RTAS			0xf000
 
@@ -285,7 +307,24 @@
 #define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE	3
 #define H_SET_MODE_RESOURCE_LE			4
 
+/* H_GET_CPU_CHARACTERISTICS return values */
+#define H_CPU_CHAR_SPEC_BAR_ORI31	(1ull << 63) // IBM bit 0
+#define H_CPU_CHAR_BCCTRL_SERIALISED	(1ull << 62) // IBM bit 1
+#define H_CPU_CHAR_L1D_FLUSH_ORI30	(1ull << 61) // IBM bit 2
+#define H_CPU_CHAR_L1D_FLUSH_TRIG2	(1ull << 60) // IBM bit 3
+#define H_CPU_CHAR_L1D_THREAD_PRIV	(1ull << 59) // IBM bit 4
+#define H_CPU_CHAR_BRANCH_HINTS_HONORED	(1ull << 58) // IBM bit 5
+#define H_CPU_CHAR_THREAD_RECONFIG_CTRL	(1ull << 57) // IBM bit 6
+#define H_CPU_CHAR_COUNT_CACHE_DISABLED	(1ull << 56) // IBM bit 7
+#define H_CPU_CHAR_BCCTR_FLUSH_ASSIST	(1ull << 54) // IBM bit 9
+
+#define H_CPU_BEHAV_FAVOUR_SECURITY	(1ull << 63) // IBM bit 0
+#define H_CPU_BEHAV_L1D_FLUSH_PR	(1ull << 62) // IBM bit 1
+#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR	(1ull << 61) // IBM bit 2
+#define H_CPU_BEHAV_FLUSH_COUNT_CACHE	(1ull << 58) // IBM bit 5
+
 #ifndef __ASSEMBLY__
+#include <linux/types.h>
 
 /**
  * plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments
@@ -423,6 +462,11 @@
 
 #endif /* CONFIG_PPC_PSERIES */
 
+struct h_cpu_char_result {
+	u64 character;
+	u64 behaviour;
+};
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HVCALL_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/icswx.h
+++ linux-4.4.0/arch/powerpc/include/asm/icswx.h
@@ -164,6 +164,7 @@
 #define ICSWX_INITIATED		(0x8)
 #define ICSWX_BUSY		(0x4)
 #define ICSWX_REJECTED		(0x2)
+#define ICSWX_XERS0		(0x1)	/* undefined or set from XERSO. */
 
 static inline int icswx(__be32 ccw, struct coprocessor_request_block *crb)
 {
--- linux-4.4.0.orig/arch/powerpc/include/asm/io.h
+++ linux-4.4.0/arch/powerpc/include/asm/io.h
@@ -385,6 +385,17 @@
 {
 	*(volatile unsigned long __force *)PCI_FIX_ADDR(addr) = v;
 }
+
+/*
+ * Real mode version of the above. stdcix is only supposed to be used
+ * in hypervisor real mode as per the architecture spec.
+ */
+static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
+{
+	__asm__ __volatile__("stdcix %0,0,%1"
+		: : "r" (val), "r" (paddr) : "memory");
+}
+
 #endif /* __powerpc64__ */
 
 /*
--- linux-4.4.0.orig/arch/powerpc/include/asm/irq_work.h
+++ linux-4.4.0/arch/powerpc/include/asm/irq_work.h
@@ -5,5 +5,6 @@
 {
 	return true;
 }
+extern void arch_irq_work_raise(void);
 
 #endif /* _ASM_POWERPC_IRQ_WORK_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/kprobes.h
+++ linux-4.4.0/arch/powerpc/include/asm/kprobes.h
@@ -29,6 +29,7 @@
 #include <linux/types.h>
 #include <linux/ptrace.h>
 #include <linux/percpu.h>
+#include <linux/module.h>
 #include <asm/probes.h>
 #include <asm/code-patching.h>
 
@@ -61,7 +62,7 @@
 #define kprobe_lookup_name(name, addr)					\
 {									\
 	char dot_name[MODULE_NAME_LEN + 1 + KSYM_NAME_LEN];		\
-	char *modsym;							\
+	const char *modsym;							\
 	bool dot_appended = false;					\
 	if ((modsym = strchr(name, ':')) != NULL) {			\
 		modsym++;						\
--- linux-4.4.0.orig/arch/powerpc/include/asm/kup.h
+++ linux-4.4.0/arch/powerpc/include/asm/kup.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_KUP_H_
+#define _ASM_POWERPC_KUP_H_
+
+#ifndef __ASSEMBLY__
+
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_PPC_BOOK3S_64
+#include <asm/book3s/64/kup-radix.h>
+#else
+static inline void allow_user_access(void __user *to, const void __user *from,
+				     unsigned long size) { }
+static inline void prevent_user_access(void __user *to, const void __user *from,
+				       unsigned long size) { }
+#endif /* CONFIG_PPC64 */
+
+static inline void allow_read_from_user(const void __user *from, unsigned long size)
+{
+	allow_user_access(NULL, from, size);
+}
+
+static inline void allow_write_to_user(void __user *to, unsigned long size)
+{
+	allow_user_access(to, NULL, size);
+}
+
+static inline void prevent_read_from_user(const void __user *from, unsigned long size)
+{
+	prevent_user_access(NULL, from, size);
+}
+
+static inline void prevent_write_to_user(void __user *to, unsigned long size)
+{
+	prevent_user_access(to, NULL, size);
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_KUP_H_ */
--- linux-4.4.0.orig/arch/powerpc/include/asm/kvm_book3s.h
+++ linux-4.4.0/arch/powerpc/include/asm/kvm_book3s.h
@@ -83,6 +83,7 @@
 	u64 sdr1;
 	u64 hior;
 	u64 msr_mask;
+	u64 vtb;
 #ifdef CONFIG_PPC_BOOK3S_32
 	u32 vsid_pool[VSID_POOL_SIZE];
 	u32 vsid_next;
--- linux-4.4.0.orig/arch/powerpc/include/asm/kvm_booke.h
+++ linux-4.4.0/arch/powerpc/include/asm/kvm_booke.h
@@ -100,6 +100,11 @@
 	return vcpu->arch.pc;
 }
 
+static inline bool kvmppc_is_bigendian(struct kvm_vcpu *vcpu)
+{
+	return 1;
+}
+
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
 {
 	return vcpu->arch.fault_dear;
--- linux-4.4.0.orig/arch/powerpc/include/asm/kvm_host.h
+++ linux-4.4.0/arch/powerpc/include/asm/kvm_host.h
@@ -250,6 +250,7 @@
 #ifdef CONFIG_PPC_BOOK3S_64
 	struct list_head spapr_tce_tables;
 	struct list_head rtas_tokens;
+	struct mutex rtas_token_lock;
 	DECLARE_BITMAP(enabled_hcalls, MAX_HCALL_OPCODE/4 + 1);
 #endif
 #ifdef CONFIG_KVM_MPIC
@@ -297,6 +298,7 @@
 	u32 arch_compat;
 	ulong pcr;
 	ulong dpdes;		/* doorbell state (POWER8) */
+	ulong vtb;		/* virtual timebase */
 	ulong conferring_threads;
 };
 
@@ -473,7 +475,6 @@
 	ulong purr;
 	ulong spurr;
 	ulong ic;
-	ulong vtb;
 	ulong dscr;
 	ulong amr;
 	ulong uamor;
@@ -545,6 +546,7 @@
 	u64 tfiar;
 
 	u32 cr_tm;
+	u64 xer_tm;
 	u64 lr_tm;
 	u64 ctr_tm;
 	u64 amr_tm;
--- linux-4.4.0.orig/arch/powerpc/include/asm/machdep.h
+++ linux-4.4.0/arch/powerpc/include/asm/machdep.h
@@ -113,7 +113,6 @@
 
 	void		(*restart)(char *cmd);
 	void		(*halt)(void);
-	void		(*panic)(char *str);
 	void		(*cpu_die)(void);
 
 	long		(*time_init)(void); /* Optional, may be NULL */
--- linux-4.4.0.orig/arch/powerpc/include/asm/mmu_context.h
+++ linux-4.4.0/arch/powerpc/include/asm/mmu_context.h
@@ -18,6 +18,7 @@
 #ifdef CONFIG_SPAPR_TCE_IOMMU
 struct mm_iommu_table_group_mem_t;
 
+extern int isolate_lru_page(struct page *page);	/* from internal.h */
 extern bool mm_iommu_preregistered(void);
 extern long mm_iommu_get(unsigned long ua, unsigned long entries,
 		struct mm_iommu_table_group_mem_t **pmem);
--- linux-4.4.0.orig/arch/powerpc/include/asm/mpic.h
+++ linux-4.4.0/arch/powerpc/include/asm/mpic.h
@@ -392,7 +392,14 @@
 #define	MPIC_REGSET_TSI108		MPIC_REGSET(1)	/* Tsi108/109 PIC */
 
 /* Get the version of primary MPIC */
+#ifdef CONFIG_MPIC
 extern u32 fsl_mpic_primary_get_version(void);
+#else
+static inline u32 fsl_mpic_primary_get_version(void)
+{
+	return 0;
+}
+#endif
 
 /* Allocate the controller structure and setup the linux irq descs
  * for the range if interrupts passed in. No HW initialization is
--- linux-4.4.0.orig/arch/powerpc/include/asm/opal-api.h
+++ linux-4.4.0/arch/powerpc/include/asm/opal-api.h
@@ -157,7 +157,8 @@
 #define OPAL_LEDS_GET_INDICATOR			114
 #define OPAL_LEDS_SET_INDICATOR			115
 #define OPAL_CEC_REBOOT2			116
-#define OPAL_LAST				116
+#define OPAL_CONSOLE_FLUSH			117
+#define OPAL_LAST				117
 
 /* Device tree flags */
 
--- linux-4.4.0.orig/arch/powerpc/include/asm/opal.h
+++ linux-4.4.0/arch/powerpc/include/asm/opal.h
@@ -21,6 +21,9 @@
 /* We calculate number of sg entries based on PAGE_SIZE */
 #define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry))
 
+/* Default time to sleep or delay between OPAL_BUSY/OPAL_BUSY_EVENT loops */
+#define OPAL_BUSY_DELAY_MS	10
+
 /* /sys/firmware/opal */
 extern struct kobject *opal_kobj;
 
@@ -35,6 +38,7 @@
 			  uint8_t *buffer);
 int64_t opal_console_write_buffer_space(int64_t term_number,
 					__be64 *length);
+int64_t opal_console_flush(int64_t term_number);
 int64_t opal_rtc_read(__be32 *year_month_day,
 		      __be64 *hour_minute_second_millisecond);
 int64_t opal_rtc_write(uint32_t year_month_day,
@@ -262,6 +266,8 @@
 
 extern void opal_lpc_init(void);
 
+extern void opal_kmsg_init(void);
+
 extern int opal_event_request(unsigned int opal_event_nr);
 
 struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
--- linux-4.4.0.orig/arch/powerpc/include/asm/paca.h
+++ linux-4.4.0/arch/powerpc/include/asm/paca.h
@@ -24,6 +24,7 @@
 #ifdef CONFIG_KVM_BOOK3S_64_HANDLER
 #include <asm/kvm_book3s_asm.h>
 #endif
+#include <asm/hmi.h>
 
 register struct paca_struct *local_paca asm("r13");
 
@@ -41,6 +42,9 @@
 #define get_lppaca()	(get_paca()->lppaca_ptr)
 #define get_slb_shadow()	(get_paca()->slb_shadow_ptr)
 
+/* Maximum number of threads per core. */
+#define	MAX_SMT		8
+
 struct task_struct;
 
 /*
@@ -171,6 +175,11 @@
 	 */
 	u16 in_mce;
 	u8 hmi_event_available;		 /* HMI event is available */
+	/*
+	 * Bitmap for sibling subcore status. See kvm/book3s_hv_ras.c for
+	 * more details
+	 */
+	struct sibling_subcore_state *sibling_subcore_state;
 #endif
 
 	/* Stuff for accurate time accounting */
@@ -192,6 +201,15 @@
 #endif
 	struct kvmppc_host_state kvm_hstate;
 #endif
+#ifdef CONFIG_PPC_BOOK3S_64
+	/*
+	 * rfi fallback flush must be in its own cacheline to prevent
+	 * other paca data leaking into the L1d
+	 */
+	u64 exrfi[13] __aligned(0x80);
+	void *rfi_flush_fallback_area;
+	u64 l1d_flush_size;
+#endif
 };
 
 extern struct paca_struct *paca;
--- linux-4.4.0.orig/arch/powerpc/include/asm/page.h
+++ linux-4.4.0/arch/powerpc/include/asm/page.h
@@ -132,7 +132,19 @@
 #define virt_to_pfn(kaddr)	(__pa(kaddr) >> PAGE_SHIFT)
 #define virt_to_page(kaddr)	pfn_to_page(virt_to_pfn(kaddr))
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
+
+#ifdef CONFIG_PPC_BOOK3S_64
+/*
+ * On hash the vmalloc and other regions alias to the kernel region when passed
+ * through __pa(), which virt_to_pfn() uses. That means virt_addr_valid() can
+ * return true for some vmalloc addresses, which is incorrect. So explicitly
+ * check that the address is in the kernel region.
+ */
+#define virt_addr_valid(kaddr) (REGION_ID(kaddr) == KERNEL_REGION_ID && \
+				pfn_valid(virt_to_pfn(kaddr)))
+#else
 #define virt_addr_valid(kaddr)	pfn_valid(virt_to_pfn(kaddr))
+#endif
 
 /*
  * On Book-E parts we need __va to parse the device tree and we can't
--- linux-4.4.0.orig/arch/powerpc/include/asm/pci-bridge.h
+++ linux-4.4.0/arch/powerpc/include/asm/pci-bridge.h
@@ -205,6 +205,7 @@
 
 	int	pci_ext_config_space;	/* for pci devices */
 
+	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 #ifdef CONFIG_EEH
 	struct eeh_dev *edev;		/* eeh device */
 #endif
@@ -295,6 +296,7 @@
 /* Allocate & free a PCI host bridge structure */
 extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
 extern void pcibios_free_controller(struct pci_controller *phb);
+extern void pcibios_free_controller_deferred(struct pci_host_bridge *bridge);
 
 #ifdef CONFIG_PCI
 extern int pcibios_vaddr_is_ioport(void __iomem *address);
--- linux-4.4.0.orig/arch/powerpc/include/asm/pci.h
+++ linux-4.4.0/arch/powerpc/include/asm/pci.h
@@ -149,4 +149,8 @@
 extern void pcibios_scan_phb(struct pci_controller *hose);
 
 #endif	/* __KERNEL__ */
+
+extern struct pci_dev *pnv_pci_get_gpu_dev(struct pci_dev *npdev);
+extern struct pci_dev *pnv_pci_get_npu_dev(struct pci_dev *gpdev, int index);
+
 #endif /* __ASM_POWERPC_PCI_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/percpu.h
+++ linux-4.4.0/arch/powerpc/include/asm/percpu.h
@@ -9,8 +9,6 @@
 
 #ifdef CONFIG_SMP
 
-#include <asm/paca.h>
-
 #define __my_cpu_offset local_paca->data_offset
 
 #endif /* CONFIG_SMP */
@@ -18,4 +16,6 @@
 
 #include <asm-generic/percpu.h>
 
+#include <asm/paca.h>
+
 #endif /* _ASM_POWERPC_PERCPU_H_ */
--- linux-4.4.0.orig/arch/powerpc/include/asm/perf_event_server.h
+++ linux-4.4.0/arch/powerpc/include/asm/perf_event_server.h
@@ -136,16 +136,24 @@
  * event 'cpu-cycles' can have two entries in sysfs: 'cpu-cycles' and
  * 'PM_CYC' where the latter is the name by which the event is known in
  * POWER CPU specification.
+ *
+ * Similarly, some hardware and cache events use the same event code. Eg.
+ * on POWER8, both "cache-references" and "L1-dcache-loads" events refer
+ * to the same event, PM_LD_REF_L1.  The suffix, allows us to have two
+ * sysfs objects for the same event and thus two entries/aliases in sysfs.
  */
 #define	EVENT_VAR(_id, _suffix)		event_attr_##_id##_suffix
 #define	EVENT_PTR(_id, _suffix)		&EVENT_VAR(_id, _suffix).attr.attr
 
 #define	EVENT_ATTR(_name, _id, _suffix)					\
-	PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_##_id,	\
+	PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), _id,		\
 			power_events_sysfs_show)
 
 #define	GENERIC_EVENT_ATTR(_name, _id)	EVENT_ATTR(_name, _id, _g)
 #define	GENERIC_EVENT_PTR(_id)		EVENT_PTR(_id, _g)
 
+#define	CACHE_EVENT_ATTR(_name, _id)	EVENT_ATTR(_name, _id, _c)
+#define	CACHE_EVENT_PTR(_id)		EVENT_PTR(_id, _c)
+
 #define	POWER_EVENT_ATTR(_name, _id)	EVENT_ATTR(_name, _id, _p)
 #define	POWER_EVENT_PTR(_id)		EVENT_PTR(_id, _p)
--- linux-4.4.0.orig/arch/powerpc/include/asm/pgtable.h
+++ linux-4.4.0/arch/powerpc/include/asm/pgtable.h
@@ -149,9 +149,9 @@
 		flush_hash_entry(mm, ptep, addr);
 #endif
 	__asm__ __volatile__("\
-		stw%U0%X0 %2,%0\n\
+		stw%X0 %2,%0\n\
 		eieio\n\
-		stw%U0%X0 %L2,%1"
+		stw%X1 %L2,%1"
 	: "=m" (*ptep), "=m" (*((unsigned char *)ptep+4))
 	: "r" (pte) : "memory");
 
--- linux-4.4.0.orig/arch/powerpc/include/asm/plpar_wrappers.h
+++ linux-4.4.0/arch/powerpc/include/asm/plpar_wrappers.h
@@ -323,4 +323,18 @@
 	return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR, dawr0, dawrx0);
 }
 
+static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p)
+{
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+	long rc;
+
+	rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf);
+	if (rc == H_SUCCESS) {
+		p->character = retbuf[0];
+		p->behaviour = retbuf[1];
+	}
+
+	return rc;
+}
+
 #endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/ppc-opcode.h
+++ linux-4.4.0/arch/powerpc/include/asm/ppc-opcode.h
@@ -147,6 +147,7 @@
 #define PPC_INST_LWSYNC			0x7c2004ac
 #define PPC_INST_SYNC			0x7c0004ac
 #define PPC_INST_SYNC_MASK		0xfc0007fe
+#define PPC_INST_ISYNC			0x4c00012c
 #define PPC_INST_LXVD2X			0x7c000698
 #define PPC_INST_MCRXR			0x7c000400
 #define PPC_INST_MCRXR_MASK		0xfc0007fe
--- linux-4.4.0.orig/arch/powerpc/include/asm/ppc_asm.h
+++ linux-4.4.0/arch/powerpc/include/asm/ppc_asm.h
@@ -224,6 +224,16 @@
 	.globl name; \
 name:
 
+#define _KPROBE_TOC(name)			\
+	.section ".kprobes.text","a";		\
+	.align 2 ;				\
+	.type name,@function;			\
+	.globl name;				\
+name:						\
+0:	addis r2,r12,(.TOC.-0b)@ha;		\
+	addi r2,r2,(.TOC.-0b)@l;		\
+	.localentry name,.-name
+
 #define DOTSYM(a)	a
 
 #else
@@ -261,6 +271,8 @@
 	.type GLUE(.,name),@function; \
 GLUE(.,name):
 
+#define _KPROBE_TOC(n)	_KPROBE(n)
+
 #define DOTSYM(a)	GLUE(.,a)
 
 #endif
@@ -809,4 +821,15 @@
 	.long 0x2400004c  /* rfid				*/
 #endif /* !CONFIG_PPC_BOOK3E */
 #endif /*  __ASSEMBLY__ */
+
+#ifdef CONFIG_PPC_FSL_BOOK3E
+#define BTB_FLUSH(reg)			\
+	lis reg,BUCSR_INIT@h;		\
+	ori reg,reg,BUCSR_INIT@l;	\
+	mtspr SPRN_BUCSR,reg;		\
+	isync;
+#else
+#define BTB_FLUSH(reg)
+#endif /* CONFIG_PPC_FSL_BOOK3E */
+
 #endif /* _ASM_POWERPC_PPC_ASM_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/reg.h
+++ linux-4.4.0/arch/powerpc/include/asm/reg.h
@@ -647,7 +647,7 @@
 #define THRM1_TIN	(1 << 31)
 #define THRM1_TIV	(1 << 30)
 #define THRM1_THRES(x)	((x&0x7f)<<23)
-#define THRM3_SITV(x)	((x&0x3fff)<<1)
+#define THRM3_SITV(x)	((x & 0x1fff) << 1)
 #define THRM1_TID	(1<<2)
 #define THRM1_TIE	(1<<1)
 #define THRM1_V		(1<<0)
@@ -707,7 +707,8 @@
 #define   MMCR0_FCWAIT	0x00000002UL /* freeze counter in WAIT state */
 #define   MMCR0_FCHV	0x00000001UL /* freeze conditions in hypervisor mode */
 #define SPRN_MMCR1	798
-#define SPRN_MMCR2	769
+#define SPRN_MMCR2	785
+#define SPRN_UMMCR2	769
 #define SPRN_MMCRA	0x312
 #define   MMCRA_SDSYNC	0x80000000UL /* SDAR synced with SIAR */
 #define   MMCRA_SDAR_DCACHE_MISS 0x40000000UL
@@ -744,13 +745,13 @@
 #define SPRN_PMC6	792
 #define SPRN_PMC7	793
 #define SPRN_PMC8	794
-#define SPRN_SIAR	780
-#define SPRN_SDAR	781
 #define SPRN_SIER	784
 #define   SIER_SIPR		0x2000000	/* Sampled MSR_PR */
 #define   SIER_SIHV		0x1000000	/* Sampled MSR_HV */
 #define   SIER_SIAR_VALID	0x0400000	/* SIAR contents valid */
 #define   SIER_SDAR_VALID	0x0200000	/* SDAR contents valid */
+#define SPRN_SIAR	796
+#define SPRN_SDAR	797
 #define SPRN_TACR	888
 #define SPRN_TCSCR	889
 #define SPRN_CSIGR	890
@@ -1174,6 +1175,7 @@
 #define PVR_970GX	0x0045
 #define PVR_POWER7p	0x004A
 #define PVR_POWER8E	0x004B
+#define PVR_POWER8NVL	0x004C
 #define PVR_POWER8	0x004D
 #define PVR_BE		0x0070
 #define PVR_PA6T	0x0090
@@ -1235,7 +1237,7 @@
 				"	.llong 0\n"			\
 				".previous"				\
 			: "=r" (rval) \
-			: "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL)); \
+			: "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL) : "cr0"); \
 			rval;})
 #else
 #define mftb()		({unsigned long rval;	\
--- linux-4.4.0.orig/arch/powerpc/include/asm/reg_booke.h
+++ linux-4.4.0/arch/powerpc/include/asm/reg_booke.h
@@ -41,7 +41,7 @@
 #if defined(CONFIG_PPC_BOOK3E_64)
 #define MSR_64BIT	MSR_CM
 
-#define MSR_		(MSR_ME | MSR_CE)
+#define MSR_		(MSR_ME | MSR_RI | MSR_CE)
 #define MSR_KERNEL	(MSR_ | MSR_64BIT)
 #define MSR_USER32	(MSR_ | MSR_PR | MSR_EE)
 #define MSR_USER64	(MSR_USER32 | MSR_64BIT)
--- linux-4.4.0.orig/arch/powerpc/include/asm/security_features.h
+++ linux-4.4.0/arch/powerpc/include/asm/security_features.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Security related feature bit definitions.
+ *
+ * Copyright 2018, Michael Ellerman, IBM Corporation.
+ */
+
+#ifndef _ASM_POWERPC_SECURITY_FEATURES_H
+#define _ASM_POWERPC_SECURITY_FEATURES_H
+
+
+extern unsigned long powerpc_security_features;
+extern bool rfi_flush;
+
+/* These are bit flags */
+enum stf_barrier_type {
+	STF_BARRIER_NONE	= 0x1,
+	STF_BARRIER_FALLBACK	= 0x2,
+	STF_BARRIER_EIEIO	= 0x4,
+	STF_BARRIER_SYNC_ORI	= 0x8,
+};
+
+void setup_stf_barrier(void);
+void do_stf_barrier_fixups(enum stf_barrier_type types);
+void setup_count_cache_flush(void);
+
+static inline void security_ftr_set(unsigned long feature)
+{
+	powerpc_security_features |= feature;
+}
+
+static inline void security_ftr_clear(unsigned long feature)
+{
+	powerpc_security_features &= ~feature;
+}
+
+static inline bool security_ftr_enabled(unsigned long feature)
+{
+	return !!(powerpc_security_features & feature);
+}
+
+
+// Features indicating support for Spectre/Meltdown mitigations
+
+// The L1-D cache can be flushed with ori r30,r30,0
+#define SEC_FTR_L1D_FLUSH_ORI30		0x0000000000000001ull
+
+// The L1-D cache can be flushed with mtspr 882,r0 (aka SPRN_TRIG2)
+#define SEC_FTR_L1D_FLUSH_TRIG2		0x0000000000000002ull
+
+// ori r31,r31,0 acts as a speculation barrier
+#define SEC_FTR_SPEC_BAR_ORI31		0x0000000000000004ull
+
+// Speculation past bctr is disabled
+#define SEC_FTR_BCCTRL_SERIALISED	0x0000000000000008ull
+
+// Entries in L1-D are private to a SMT thread
+#define SEC_FTR_L1D_THREAD_PRIV		0x0000000000000010ull
+
+// Indirect branch prediction cache disabled
+#define SEC_FTR_COUNT_CACHE_DISABLED	0x0000000000000020ull
+
+// bcctr 2,0,0 triggers a hardware assisted count cache flush
+#define SEC_FTR_BCCTR_FLUSH_ASSIST	0x0000000000000800ull
+
+
+// Features indicating need for Spectre/Meltdown mitigations
+
+// The L1-D cache should be flushed on MSR[HV] 1->0 transition (hypervisor to guest)
+#define SEC_FTR_L1D_FLUSH_HV		0x0000000000000040ull
+
+// The L1-D cache should be flushed on MSR[PR] 0->1 transition (kernel to userspace)
+#define SEC_FTR_L1D_FLUSH_PR		0x0000000000000080ull
+
+// A speculation barrier should be used for bounds checks (Spectre variant 1)
+#define SEC_FTR_BNDS_CHK_SPEC_BAR	0x0000000000000100ull
+
+// Firmware configuration indicates user favours security over performance
+#define SEC_FTR_FAVOUR_SECURITY		0x0000000000000200ull
+
+// Software required to flush count cache on context switch
+#define SEC_FTR_FLUSH_COUNT_CACHE	0x0000000000000400ull
+
+// Software required to flush link stack on context switch
+#define SEC_FTR_FLUSH_LINK_STACK	0x0000000000001000ull
+
+// The L1-D cache should be flushed when entering the kernel
+#define SEC_FTR_L1D_FLUSH_ENTRY		0x0000000000004000ull
+
+// The L1-D cache should be flushed after user accesses from the kernel
+#define SEC_FTR_L1D_FLUSH_UACCESS	0x0000000000008000ull
+
+// Features enabled by default
+#define SEC_FTR_DEFAULT \
+	(SEC_FTR_L1D_FLUSH_HV | \
+	 SEC_FTR_L1D_FLUSH_PR | \
+	 SEC_FTR_BNDS_CHK_SPEC_BAR | \
+	 SEC_FTR_L1D_FLUSH_ENTRY | \
+	 SEC_FTR_L1D_FLUSH_UACCESS | \
+	 SEC_FTR_FAVOUR_SECURITY)
+
+#endif /* _ASM_POWERPC_SECURITY_FEATURES_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/setup.h
+++ linux-4.4.0/arch/powerpc/include/asm/setup.h
@@ -8,6 +8,7 @@
 
 extern unsigned int rtas_data;
 extern unsigned long long memory_limit;
+extern bool init_mem_is_free;
 extern unsigned long klimit;
 extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
 
@@ -23,9 +24,45 @@
 
 void check_for_initrd(void);
 void initmem_init(void);
-void setup_panic(void);
 #define ARCH_PANIC_TIMEOUT 180
 
+void rfi_flush_enable(bool enable);
+
+/* These are bit flags */
+enum l1d_flush_type {
+	L1D_FLUSH_NONE		= 0x1,
+	L1D_FLUSH_FALLBACK	= 0x2,
+	L1D_FLUSH_ORI		= 0x4,
+	L1D_FLUSH_MTTRIG	= 0x8,
+};
+
+void setup_rfi_flush(enum l1d_flush_type, bool enable);
+void setup_entry_flush(bool enable);
+void setup_uaccess_flush(bool enable);
+void do_rfi_flush_fixups(enum l1d_flush_type types);
+#ifdef CONFIG_PPC_BARRIER_NOSPEC
+void setup_barrier_nospec(void);
+#else
+static inline void setup_barrier_nospec(void) { };
+#endif
+void do_uaccess_flush_fixups(enum l1d_flush_type types);
+void do_entry_flush_fixups(enum l1d_flush_type types);
+void do_barrier_nospec_fixups(bool enable);
+extern bool barrier_nospec_enabled;
+
+#ifdef CONFIG_PPC_BARRIER_NOSPEC
+void do_barrier_nospec_fixups_range(bool enable, void *start, void *end);
+#else
+static inline void do_barrier_nospec_fixups_range(bool enable, void *start, void *end) { };
+#endif
+
+#ifdef CONFIG_PPC_FSL_BOOK3E
+void setup_spectre_v2(void);
+#else
+static inline void setup_spectre_v2(void) {};
+#endif
+void do_btb_flush_fixups(void);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif	/* _ASM_POWERPC_SETUP_H */
--- linux-4.4.0.orig/arch/powerpc/include/asm/sfp-machine.h
+++ linux-4.4.0/arch/powerpc/include/asm/sfp-machine.h
@@ -213,30 +213,18 @@
  * respectively.  The result is placed in HIGH_SUM and LOW_SUM.  Overflow
  * (i.e. carry out) is not stored anywhere, and is lost.
  */
-#define add_ssaaaa(sh, sl, ah, al, bh, bl)				\
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
   do {									\
     if (__builtin_constant_p (bh) && (bh) == 0)				\
-      __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2"		\
-	     : "=r" ((USItype)(sh)),					\
-	       "=&r" ((USItype)(sl))					\
-	     : "%r" ((USItype)(ah)),					\
-	       "%r" ((USItype)(al)),					\
-	       "rI" ((USItype)(bl)));					\
-    else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0)		\
-      __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2"		\
-	     : "=r" ((USItype)(sh)),					\
-	       "=&r" ((USItype)(sl))					\
-	     : "%r" ((USItype)(ah)),					\
-	       "%r" ((USItype)(al)),					\
-	       "rI" ((USItype)(bl)));					\
+      __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2"		\
+	     : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
+    else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0)		\
+      __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2"		\
+	     : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
     else								\
-      __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3"		\
-	     : "=r" ((USItype)(sh)),					\
-	       "=&r" ((USItype)(sl))					\
-	     : "%r" ((USItype)(ah)),					\
-	       "r" ((USItype)(bh)),					\
-	       "%r" ((USItype)(al)),					\
-	       "rI" ((USItype)(bl)));					\
+      __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3"		\
+	     : "=r" (sh), "=&r" (sl)					\
+	     : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl));		\
   } while (0)
 
 /* sub_ddmmss is used in op-2.h and udivmodti4.c and should be equivalent to
@@ -248,44 +236,24 @@
  * and LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
  * and is lost.
  */
-#define sub_ddmmss(sh, sl, ah, al, bh, bl)				\
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
   do {									\
     if (__builtin_constant_p (ah) && (ah) == 0)				\
-      __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2"	\
-	       : "=r" ((USItype)(sh)),					\
-		 "=&r" ((USItype)(sl))					\
-	       : "r" ((USItype)(bh)),					\
-		 "rI" ((USItype)(al)),					\
-		 "r" ((USItype)(bl)));					\
-    else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0)		\
-      __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2"	\
-	       : "=r" ((USItype)(sh)),					\
-		 "=&r" ((USItype)(sl))					\
-	       : "r" ((USItype)(bh)),					\
-		 "rI" ((USItype)(al)),					\
-		 "r" ((USItype)(bl)));					\
+      __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2"	\
+	       : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
+    else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0)		\
+      __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2"	\
+	       : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
     else if (__builtin_constant_p (bh) && (bh) == 0)			\
-      __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2"		\
-	       : "=r" ((USItype)(sh)),					\
-		 "=&r" ((USItype)(sl))					\
-	       : "r" ((USItype)(ah)),					\
-		 "rI" ((USItype)(al)),					\
-		 "r" ((USItype)(bl)));					\
-    else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0)		\
-      __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2"		\
-	       : "=r" ((USItype)(sh)),					\
-		 "=&r" ((USItype)(sl))					\
-	       : "r" ((USItype)(ah)),					\
-		 "rI" ((USItype)(al)),					\
-		 "r" ((USItype)(bl)));					\
+      __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2"		\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
+    else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0)		\
+      __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2"		\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
     else								\
-      __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2"	\
-	       : "=r" ((USItype)(sh)),					\
-		 "=&r" ((USItype)(sl))					\
-	       : "r" ((USItype)(ah)),					\
-		 "r" ((USItype)(bh)),					\
-		 "rI" ((USItype)(al)),					\
-		 "r" ((USItype)(bl)));					\
+      __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2"	\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "r" (bh), "rI" (al), "r" (bl));		\
   } while (0)
 
 /* asm fragments for mul and div */
@@ -294,13 +262,10 @@
  * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
  * word product in HIGH_PROD and LOW_PROD.
  */
-#define umul_ppmm(ph, pl, m0, m1)					\
+#define umul_ppmm(ph, pl, m0, m1) \
   do {									\
     USItype __m0 = (m0), __m1 = (m1);					\
-    __asm__ ("mulhwu %0,%1,%2"						\
-	     : "=r" ((USItype)(ph))					\
-	     : "%r" (__m0),						\
-               "r" (__m1));						\
+    __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1));	\
     (pl) = __m0 * __m1;							\
   } while (0)
 
@@ -312,9 +277,10 @@
  * significant bit of DENOMINATOR must be 1, then the pre-processor symbol
  * UDIV_NEEDS_NORMALIZATION is defined to 1.
  */
-#define udiv_qrnnd(q, r, n1, n0, d)					\
+#define udiv_qrnnd(q, r, n1, n0, d) \
   do {									\
-    UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m;			\
+    UWtype __d1, __d0, __q1, __q0;					\
+    UWtype __r1, __r0, __m;						\
     __d1 = __ll_highpart (d);						\
     __d0 = __ll_lowpart (d);						\
 									\
@@ -325,7 +291,7 @@
     if (__r1 < __m)							\
       {									\
 	__q1--, __r1 += (d);						\
-	if (__r1 >= (d)) /* we didn't get carry when adding to __r1 */	\
+	if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
 	  if (__r1 < __m)						\
 	    __q1--, __r1 += (d);					\
       }									\
--- linux-4.4.0.orig/arch/powerpc/include/asm/smp.h
+++ linux-4.4.0/arch/powerpc/include/asm/smp.h
@@ -30,6 +30,7 @@
 #include <asm/percpu.h>
 
 extern int boot_cpuid;
+extern int boot_hw_cpuid;
 extern int spinning_secondaries;
 
 extern void cpu_die(void);
--- linux-4.4.0.orig/arch/powerpc/include/asm/switch_to.h
+++ linux-4.4.0/arch/powerpc/include/asm/switch_to.h
@@ -46,6 +46,11 @@
 }
 #endif
 
+static inline void disable_kernel_fp(void) { }
+static inline void disable_kernel_altivec(void) { }
+static inline void disable_kernel_spe(void) { }
+static inline void disable_kernel_vsx(void) { }
+
 #ifdef CONFIG_PPC_FPU
 extern void flush_fp_to_thread(struct task_struct *);
 extern void giveup_fpu(struct task_struct *);
--- linux-4.4.0.orig/arch/powerpc/include/asm/synch.h
+++ linux-4.4.0/arch/powerpc/include/asm/synch.h
@@ -5,10 +5,6 @@
 #include <linux/stringify.h>
 #include <asm/feature-fixups.h>
 
-#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
-#define __SUBARCH_HAS_LWSYNC
-#endif
-
 #ifndef __ASSEMBLY__
 extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
 extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
@@ -44,7 +40,7 @@
 	MAKE_LWSYNC_SECTION_ENTRY(97, __lwsync_fixup);
 #define PPC_ACQUIRE_BARRIER	 "\n" stringify_in_c(__PPC_ACQUIRE_BARRIER)
 #define PPC_RELEASE_BARRIER	 stringify_in_c(LWSYNC) "\n"
-#define PPC_ATOMIC_ENTRY_BARRIER "\n" stringify_in_c(LWSYNC) "\n"
+#define PPC_ATOMIC_ENTRY_BARRIER "\n" stringify_in_c(sync) "\n"
 #define PPC_ATOMIC_EXIT_BARRIER	 "\n" stringify_in_c(sync) "\n"
 #else
 #define PPC_ACQUIRE_BARRIER
--- linux-4.4.0.orig/arch/powerpc/include/asm/uaccess.h
+++ linux-4.4.0/arch/powerpc/include/asm/uaccess.h
@@ -9,6 +9,7 @@
 #include <asm/asm-compat.h>
 #include <asm/processor.h>
 #include <asm/page.h>
+#include <asm/kup.h>
 
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
@@ -59,7 +60,7 @@
 #endif
 
 #define access_ok(type, addr, size)		\
-	(__chk_user_ptr(addr),			\
+	(__chk_user_ptr(addr), (void)(type),		\
 	 __access_ok((__force unsigned long)(addr), (size), get_fs()))
 
 /*
@@ -105,9 +106,14 @@
 	__put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
 
 #define __get_user(x, ptr) \
-	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
+	__get_user_nocheck((x), (ptr), sizeof(*(ptr)), true)
 #define __put_user(x, ptr) \
-	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), true)
+
+#define __get_user_allowed(x, ptr) \
+	__get_user_nocheck((x), (ptr), sizeof(*(ptr)), false)
+#define __put_user_allowed(x, ptr) \
+	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), false)
 
 #define __get_user_inatomic(x, ptr) \
 	__get_user_nosleep((x), (ptr), sizeof(*(ptr)))
@@ -161,7 +167,7 @@
 		: "r" (x), "b" (addr), "i" (-EFAULT), "0" (err))
 #endif /* __powerpc64__ */
 
-#define __put_user_size(x, ptr, size, retval)			\
+#define __put_user_size_allowed(x, ptr, size, retval)		\
 do {								\
 	retval = 0;						\
 	switch (size) {						\
@@ -173,14 +179,28 @@
 	}							\
 } while (0)
 
-#define __put_user_nocheck(x, ptr, size)			\
+#define __put_user_size(x, ptr, size, retval)			\
+do {								\
+	allow_write_to_user(ptr, size);				\
+	__put_user_size_allowed(x, ptr, size, retval);		\
+	prevent_write_to_user(ptr, size);			\
+} while (0)
+
+#define __put_user_nocheck(x, ptr, size, do_allow)			\
 ({								\
 	long __pu_err;						\
 	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
+	__typeof__(*(ptr)) __pu_val = (x);			\
+	__typeof__(size) __pu_size = (size);			\
+								\
 	if (!is_kernel_addr((unsigned long)__pu_addr))		\
 		might_fault();					\
-	__chk_user_ptr(ptr);					\
-	__put_user_size((x), __pu_addr, (size), __pu_err);	\
+	__chk_user_ptr(__pu_addr);				\
+	if (do_allow)								\
+		__put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err);	\
+	else									\
+		__put_user_size_allowed(__pu_val, __pu_addr, __pu_size, __pu_err); \
+								\
 	__pu_err;						\
 })
 
@@ -188,9 +208,13 @@
 ({									\
 	long __pu_err = -EFAULT;					\
 	__typeof__(*(ptr)) __user *__pu_addr = (ptr);			\
+	__typeof__(*(ptr)) __pu_val = (x);				\
+	__typeof__(size) __pu_size = (size);				\
+									\
 	might_fault();							\
-	if (access_ok(VERIFY_WRITE, __pu_addr, size))			\
-		__put_user_size((x), __pu_addr, (size), __pu_err);	\
+	if (access_ok(VERIFY_WRITE, __pu_addr, __pu_size))			\
+		__put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err); \
+									\
 	__pu_err;							\
 })
 
@@ -198,8 +222,12 @@
 ({								\
 	long __pu_err;						\
 	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
-	__chk_user_ptr(ptr);					\
-	__put_user_size((x), __pu_addr, (size), __pu_err);	\
+	__typeof__(*(ptr)) __pu_val = (x);			\
+	__typeof__(size) __pu_size = (size);			\
+								\
+	__chk_user_ptr(__pu_addr);				\
+	__put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err); \
+								\
 	__pu_err;						\
 })
 
@@ -246,7 +274,7 @@
 		: "b" (addr), "i" (-EFAULT), "0" (err))
 #endif /* __powerpc64__ */
 
-#define __get_user_size(x, ptr, size, retval)			\
+#define __get_user_size_allowed(x, ptr, size, retval)		\
 do {								\
 	retval = 0;						\
 	__chk_user_ptr(ptr);					\
@@ -261,16 +289,30 @@
 	}							\
 } while (0)
 
-#define __get_user_nocheck(x, ptr, size)			\
+#define __get_user_size(x, ptr, size, retval)			\
+do {								\
+	allow_read_from_user(ptr, size);			\
+	__get_user_size_allowed(x, ptr, size, retval);		\
+	prevent_read_from_user(ptr, size);			\
+} while (0)
+
+#define __get_user_nocheck(x, ptr, size, do_allow)			\
 ({								\
 	long __gu_err;						\
 	unsigned long __gu_val;					\
 	__typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
-	__chk_user_ptr(ptr);					\
+	__typeof__(size) __gu_size = (size);			\
+								\
+	__chk_user_ptr(__gu_addr);				\
 	if (!is_kernel_addr((unsigned long)__gu_addr))		\
 		might_fault();					\
-	__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
+	barrier_nospec();					\
+	if (do_allow)								\
+		__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err);	\
+	else									\
+		__get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \
 	(x) = (__typeof__(*(ptr)))__gu_val;			\
+								\
 	__gu_err;						\
 })
 
@@ -283,6 +325,7 @@
 	__chk_user_ptr(ptr);					\
 	if (!is_kernel_addr((unsigned long)__gu_addr))		\
 		might_fault();					\
+	barrier_nospec();					\
 	__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
 	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
 	__gu_err;						\
@@ -294,10 +337,15 @@
 	long __gu_err = -EFAULT;					\
 	unsigned long  __gu_val = 0;					\
 	__typeof__(*(ptr)) __user *__gu_addr = (ptr);		\
+	__typeof__(size) __gu_size = (size);				\
+									\
 	might_fault();							\
-	if (access_ok(VERIFY_READ, __gu_addr, (size)))			\
-		__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
+	if (access_ok(VERIFY_READ, __gu_addr, __gu_size)) {		\
+		barrier_nospec();					\
+		__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \
+	}								\
 	(x) = (__force __typeof__(*(ptr)))__gu_val;				\
+									\
 	__gu_err;							\
 })
 
@@ -306,9 +354,13 @@
 	long __gu_err;						\
 	unsigned long __gu_val;					\
 	__typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
-	__chk_user_ptr(ptr);					\
-	__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
+	__typeof__(size) __gu_size = (size);			\
+								\
+	__chk_user_ptr(__gu_addr);				\
+	barrier_nospec();					\
+	__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \
 	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
+								\
 	__gu_err;						\
 })
 
@@ -323,30 +375,24 @@
 static inline unsigned long copy_from_user(void *to,
 		const void __user *from, unsigned long n)
 {
-	unsigned long over;
+	unsigned long ret;
 
-	if (access_ok(VERIFY_READ, from, n))
-		return __copy_tofrom_user((__force void __user *)to, from, n);
-	if ((unsigned long)from < TASK_SIZE) {
-		over = (unsigned long)from + n - TASK_SIZE;
-		return __copy_tofrom_user((__force void __user *)to, from,
-				n - over) + over;
+	if (likely(access_ok(VERIFY_READ, from, n))) {
+		allow_user_access(to, from, n);
+		barrier_nospec();
+		ret = __copy_tofrom_user((__force void __user *)to, from, n);
+		prevent_user_access(to, from, n);
+		return ret;
 	}
+	memset(to, 0, n);
 	return n;
 }
 
 static inline unsigned long copy_to_user(void __user *to,
 		const void *from, unsigned long n)
 {
-	unsigned long over;
-
 	if (access_ok(VERIFY_WRITE, to, n))
 		return __copy_tofrom_user(to, (__force void __user *)from, n);
-	if ((unsigned long)to < TASK_SIZE) {
-		over = (unsigned long)to + n - TASK_SIZE;
-		return __copy_tofrom_user(to, (__force void __user *)from,
-				n - over) + over;
-	}
 	return n;
 }
 
@@ -367,53 +413,69 @@
 static inline unsigned long __copy_from_user_inatomic(void *to,
 		const void __user *from, unsigned long n)
 {
+	unsigned long ret;
 	if (__builtin_constant_p(n) && (n <= 8)) {
-		unsigned long ret = 1;
+		ret = 1;
 
 		switch (n) {
 		case 1:
+			barrier_nospec();
 			__get_user_size(*(u8 *)to, from, 1, ret);
 			break;
 		case 2:
+			barrier_nospec();
 			__get_user_size(*(u16 *)to, from, 2, ret);
 			break;
 		case 4:
+			barrier_nospec();
 			__get_user_size(*(u32 *)to, from, 4, ret);
 			break;
 		case 8:
+			barrier_nospec();
 			__get_user_size(*(u64 *)to, from, 8, ret);
 			break;
 		}
 		if (ret == 0)
 			return 0;
 	}
-	return __copy_tofrom_user((__force void __user *)to, from, n);
+
+	barrier_nospec();
+	allow_read_from_user(from, n);
+	ret = __copy_tofrom_user((__force void __user *)to, from, n);
+	prevent_read_from_user(from, n);
+	return ret;
 }
 
 static inline unsigned long __copy_to_user_inatomic(void __user *to,
 		const void *from, unsigned long n)
 {
+	unsigned long ret;
+
 	if (__builtin_constant_p(n) && (n <= 8)) {
-		unsigned long ret = 1;
+		ret = 1;
 
 		switch (n) {
 		case 1:
-			__put_user_size(*(u8 *)from, (u8 __user *)to, 1, ret);
+			__put_user_size_allowed(*(u8 *)from, (u8 __user *)to, 1, ret);
 			break;
 		case 2:
-			__put_user_size(*(u16 *)from, (u16 __user *)to, 2, ret);
+			__put_user_size_allowed(*(u16 *)from, (u16 __user *)to, 2, ret);
 			break;
 		case 4:
-			__put_user_size(*(u32 *)from, (u32 __user *)to, 4, ret);
+			__put_user_size_allowed(*(u32 *)from, (u32 __user *)to, 4, ret);
 			break;
 		case 8:
-			__put_user_size(*(u64 *)from, (u64 __user *)to, 8, ret);
+			__put_user_size_allowed(*(u64 *)from, (u64 __user *)to, 8, ret);
 			break;
 		}
 		if (ret == 0)
 			return 0;
 	}
-	return __copy_tofrom_user(to, (__force const void __user *)from, n);
+
+	allow_write_to_user(to, n);
+	ret = __copy_tofrom_user(to, (__force const void __user *)from, n);
+	prevent_write_to_user(to, n);
+	return ret;
 }
 
 static inline unsigned long __copy_from_user(void *to,
@@ -430,24 +492,39 @@
 	return __copy_to_user_inatomic(to, from, size);
 }
 
-extern unsigned long __clear_user(void __user *addr, unsigned long size);
+unsigned long __arch_clear_user(void __user *addr, unsigned long size);
 
 static inline unsigned long clear_user(void __user *addr, unsigned long size)
 {
+	unsigned long ret = size;
 	might_fault();
-	if (likely(access_ok(VERIFY_WRITE, addr, size)))
-		return __clear_user(addr, size);
-	if ((unsigned long)addr < TASK_SIZE) {
-		unsigned long over = (unsigned long)addr + size - TASK_SIZE;
-		return __clear_user(addr, size - over) + over;
+	if (likely(access_ok(VERIFY_WRITE, addr, size))) {
+		allow_write_to_user(addr, size);
+		ret = __arch_clear_user(addr, size);
+		prevent_write_to_user(addr, size);
 	}
-	return size;
+	return ret;
+}
+
+static inline unsigned long __clear_user(void __user *addr, unsigned long size)
+{
+	return clear_user(addr, size);
 }
 
 extern long strncpy_from_user(char *dst, const char __user *src, long count);
 extern __must_check long strlen_user(const char __user *str);
 extern __must_check long strnlen_user(const char __user *str, long n);
 
+
+#define user_access_begin()	do { } while (0)
+#define user_access_end()	prevent_user_access(NULL, NULL, ~0ul)
+
+#define unsafe_op_wrap(op, err) do { if (unlikely(op)) goto err; } while (0)
+#define unsafe_get_user(x, p, e) unsafe_op_wrap(__get_user_allowed(x, p), e)
+#define unsafe_put_user(x, p, e) unsafe_op_wrap(__put_user_allowed(x, p), e)
+#define unsafe_copy_to_user(d, s, l, e) \
+	unsafe_op_wrap(__copy_to_user_inatomic(d, s, l), e)
+
 #endif  /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 
--- linux-4.4.0.orig/arch/powerpc/include/asm/vdso_datapage.h
+++ linux-4.4.0/arch/powerpc/include/asm/vdso_datapage.h
@@ -86,6 +86,7 @@
 	__s32 wtom_clock_nsec;
 	struct timespec stamp_xtime;	/* xtime as at tb_orig_stamp */
 	__u32 stamp_sec_fraction;	/* fractional seconds of stamp_xtime */
+	__u32 hrtimer_res;			/* hrtimer resolution */
    	__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls  */
    	__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
 };
@@ -107,6 +108,7 @@
 	__s32 wtom_clock_nsec;
 	struct timespec stamp_xtime;	/* xtime as at tb_orig_stamp */
 	__u32 stamp_sec_fraction;	/* fractional seconds of stamp_xtime */
+	__u32 hrtimer_res;		/* hrtimer resolution */
    	__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
 	__u32 dcache_block_size;	/* L1 d-cache block size     */
 	__u32 icache_block_size;	/* L1 i-cache block size     */
--- linux-4.4.0.orig/arch/powerpc/include/asm/word-at-a-time.h
+++ linux-4.4.0/arch/powerpc/include/asm/word-at-a-time.h
@@ -82,7 +82,7 @@
 	    "andc	%1,%1,%2\n\t"
 	    "popcntd	%0,%1"
 		: "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask)
-		: "r" (bits));
+		: "b" (bits));
 
 	return leading_zero_bits;
 }
--- linux-4.4.0.orig/arch/powerpc/include/uapi/asm/cputable.h
+++ linux-4.4.0/arch/powerpc/include/uapi/asm/cputable.h
@@ -31,6 +31,7 @@
 #define PPC_FEATURE_PSERIES_PERFMON_COMPAT \
 					0x00000040
 
+/* Reserved - do not use		0x00000004 */
 #define PPC_FEATURE_TRUE_LE		0x00000002
 #define PPC_FEATURE_PPC_LE		0x00000001
 
--- linux-4.4.0.orig/arch/powerpc/include/uapi/asm/elf.h
+++ linux-4.4.0/arch/powerpc/include/uapi/asm/elf.h
@@ -295,6 +295,8 @@
 #define R_PPC64_TLSLD		108
 #define R_PPC64_TOCSAVE		109
 
+#define R_PPC64_ENTRY		118
+
 #define R_PPC64_REL16		249
 #define R_PPC64_REL16_LO	250
 #define R_PPC64_REL16_HI	251
--- linux-4.4.0.orig/arch/powerpc/include/uapi/asm/kvm.h
+++ linux-4.4.0/arch/powerpc/include/uapi/asm/kvm.h
@@ -587,6 +587,7 @@
 #define KVM_REG_PPC_TM_VSCR	(KVM_REG_PPC_TM | KVM_REG_SIZE_U32 | 0x67)
 #define KVM_REG_PPC_TM_DSCR	(KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x68)
 #define KVM_REG_PPC_TM_TAR	(KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x69)
+#define KVM_REG_PPC_TM_XER	(KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x6a)
 
 /* PPC64 eXternal Interrupt Controller Specification */
 #define KVM_DEV_XICS_GRP_SOURCES	1	/* 64-bit source attributes */
--- linux-4.4.0.orig/arch/powerpc/kernel/Makefile
+++ linux-4.4.0/arch/powerpc/kernel/Makefile
@@ -41,9 +41,10 @@
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_ppc970.o cpu_setup_pa6t.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_power.o
-obj-$(CONFIG_PPC_BOOK3S_64)	+= mce.o mce_power.o
+obj-$(CONFIG_PPC_BOOK3S_64)	+= mce.o mce_power.o hmi.o
 obj64-$(CONFIG_RELOCATABLE)	+= reloc_64.o
 obj-$(CONFIG_PPC_BOOK3E_64)	+= exceptions-64e.o idle_book3e.o
+obj-$(CONFIG_PPC_BARRIER_NOSPEC) += security.o
 obj-$(CONFIG_PPC64)		+= vdso64/
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o
 obj-$(CONFIG_PPC_970_NAP)	+= idle_power4.o
--- linux-4.4.0.orig/arch/powerpc/kernel/align.c
+++ linux-4.4.0/arch/powerpc/kernel/align.c
@@ -236,6 +236,28 @@
 
 #define SWIZ_PTR(p)		((unsigned char __user *)((p) ^ swiz))
 
+#define __get_user_or_set_dar(_regs, _dest, _addr)		\
+	({							\
+		int rc = 0;					\
+		typeof(_addr) __addr = (_addr);			\
+		if (__get_user_inatomic(_dest, __addr)) {	\
+			_regs->dar = (unsigned long)__addr;	\
+			rc = -EFAULT;				\
+		}						\
+		rc;						\
+	})
+
+#define __put_user_or_set_dar(_regs, _src, _addr)		\
+	({							\
+		int rc = 0;					\
+		typeof(_addr) __addr = (_addr);			\
+		if (__put_user_inatomic(_src, __addr)) {	\
+			_regs->dar = (unsigned long)__addr;	\
+			rc = -EFAULT;				\
+		}						\
+		rc;						\
+	})
+
 static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
 			    unsigned int reg, unsigned int nb,
 			    unsigned int flags, unsigned int instr,
@@ -264,9 +286,10 @@
 		} else {
 			unsigned long pc = regs->nip ^ (swiz & 4);
 
-			if (__get_user_inatomic(instr,
-						(unsigned int __user *)pc))
+			if (__get_user_or_set_dar(regs, instr,
+						  (unsigned int __user *)pc))
 				return -EFAULT;
+
 			if (swiz == 0 && (flags & SW))
 				instr = cpu_to_le32(instr);
 			nb = (instr >> 11) & 0x1f;
@@ -310,31 +333,31 @@
 			       ((nb0 + 3) / 4) * sizeof(unsigned long));
 
 		for (i = 0; i < nb; ++i, ++p)
-			if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
-						SWIZ_PTR(p)))
+			if (__get_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz),
+						  SWIZ_PTR(p)))
 				return -EFAULT;
 		if (nb0 > 0) {
 			rptr = &regs->gpr[0];
 			addr += nb;
 			for (i = 0; i < nb0; ++i, ++p)
-				if (__get_user_inatomic(REG_BYTE(rptr,
-								 i ^ bswiz),
-							SWIZ_PTR(p)))
+				if (__get_user_or_set_dar(regs,
+							  REG_BYTE(rptr, i ^ bswiz),
+							  SWIZ_PTR(p)))
 					return -EFAULT;
 		}
 
 	} else {
 		for (i = 0; i < nb; ++i, ++p)
-			if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
-						SWIZ_PTR(p)))
+			if (__put_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz),
+						  SWIZ_PTR(p)))
 				return -EFAULT;
 		if (nb0 > 0) {
 			rptr = &regs->gpr[0];
 			addr += nb;
 			for (i = 0; i < nb0; ++i, ++p)
-				if (__put_user_inatomic(REG_BYTE(rptr,
-								 i ^ bswiz),
-							SWIZ_PTR(p)))
+				if (__put_user_or_set_dar(regs,
+							  REG_BYTE(rptr, i ^ bswiz),
+							  SWIZ_PTR(p)))
 					return -EFAULT;
 		}
 	}
@@ -346,29 +369,32 @@
  * Only POWER6 has these instructions, and it does true little-endian,
  * so we don't need the address swizzling.
  */
-static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
-			   unsigned int flags)
+static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr,
+			   unsigned int reg, unsigned int flags)
 {
 	char *ptr0 = (char *) &current->thread.TS_FPR(reg);
 	char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
-	int i, ret, sw = 0;
+	int i, sw = 0;
 
 	if (reg & 1)
 		return 0;	/* invalid form: FRS/FRT must be even */
 	if (flags & SW)
 		sw = 7;
-	ret = 0;
+
 	for (i = 0; i < 8; ++i) {
 		if (!(flags & ST)) {
-			ret |= __get_user(ptr0[i^sw], addr + i);
-			ret |= __get_user(ptr1[i^sw], addr + i + 8);
+			if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i))
+				return -EFAULT;
+			if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
+				return -EFAULT;
 		} else {
-			ret |= __put_user(ptr0[i^sw], addr + i);
-			ret |= __put_user(ptr1[i^sw], addr + i + 8);
+			if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i))
+				return -EFAULT;
+			if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
+				return -EFAULT;
 		}
 	}
-	if (ret)
-		return -EFAULT;
+
 	return 1;	/* exception handled and fixed up */
 }
 
@@ -378,24 +404,27 @@
 {
 	char *ptr0 = (char *)&regs->gpr[reg];
 	char *ptr1 = (char *)&regs->gpr[reg+1];
-	int i, ret, sw = 0;
+	int i, sw = 0;
 
 	if (reg & 1)
 		return 0;	/* invalid form: GPR must be even */
 	if (flags & SW)
 		sw = 7;
-	ret = 0;
+
 	for (i = 0; i < 8; ++i) {
 		if (!(flags & ST)) {
-			ret |= __get_user(ptr0[i^sw], addr + i);
-			ret |= __get_user(ptr1[i^sw], addr + i + 8);
+			if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i))
+				return -EFAULT;
+			if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
+				return -EFAULT;
 		} else {
-			ret |= __put_user(ptr0[i^sw], addr + i);
-			ret |= __put_user(ptr1[i^sw], addr + i + 8);
+			if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i))
+				return -EFAULT;
+			if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
+				return -EFAULT;
 		}
 	}
-	if (ret)
-		return -EFAULT;
+
 	return 1;	/* exception handled and fixed up */
 }
 #endif /* CONFIG_PPC64 */
@@ -688,9 +717,14 @@
 	for (j = 0; j < length; j += elsize) {
 		for (i = 0; i < elsize; ++i) {
 			if (flags & ST)
-				ret |= __put_user(ptr[i^sw], addr + i);
+				ret = __put_user_or_set_dar(regs, ptr[i^sw],
+							    addr + i);
 			else
-				ret |= __get_user(ptr[i^sw], addr + i);
+				ret = __get_user_or_set_dar(regs, ptr[i^sw],
+							    addr + i);
+
+			if (ret)
+				return ret;
 		}
 		ptr  += elsize;
 #ifdef __LITTLE_ENDIAN__
@@ -740,7 +774,7 @@
 	unsigned int dsisr;
 	unsigned char __user *addr;
 	unsigned long p, swiz;
-	int ret, i;
+	int i;
 	union data {
 		u64 ll;
 		double dd;
@@ -808,14 +842,25 @@
 	nb = aligninfo[instr].len;
 	flags = aligninfo[instr].flags;
 
-	/* ldbrx/stdbrx overlap lfs/stfs in the DSISR unfortunately */
-	if (IS_XFORM(instruction) && ((instruction >> 1) & 0x3ff) == 532) {
-		nb = 8;
-		flags = LD+SW;
-	} else if (IS_XFORM(instruction) &&
-		   ((instruction >> 1) & 0x3ff) == 660) {
-		nb = 8;
-		flags = ST+SW;
+	/*
+	 * Handle some cases which give overlaps in the DSISR values.
+	 */
+	if (IS_XFORM(instruction)) {
+		switch (get_xop(instruction)) {
+		case 532:	/* ldbrx */
+			nb = 8;
+			flags = LD+SW;
+			break;
+		case 660:	/* stdbrx */
+			nb = 8;
+			flags = ST+SW;
+			break;
+		case 20:	/* lwarx */
+		case 84:	/* ldarx */
+		case 116:	/* lharx */
+		case 276:	/* lqarx */
+			return 0;	/* not emulated ever */
+		}
 	}
 
 	/* Byteswap little endian loads and stores */
@@ -912,7 +957,7 @@
 		if (flags & F) {
 			/* Special case for 16-byte FP loads and stores */
 			PPC_WARN_ALIGNMENT(fp_pair, regs);
-			return emulate_fp_pair(addr, reg, flags);
+			return emulate_fp_pair(regs, addr, reg, flags);
 		} else {
 #ifdef CONFIG_PPC64
 			/* Special case for 16-byte loads and stores */
@@ -942,15 +987,12 @@
 		}
 
 		data.ll = 0;
-		ret = 0;
 		p = (unsigned long)addr;
 
 		for (i = 0; i < nb; i++)
-			ret |= __get_user_inatomic(data.v[start + i],
-						   SWIZ_PTR(p++));
-
-		if (unlikely(ret))
-			return -EFAULT;
+			if (__get_user_or_set_dar(regs, data.v[start + i],
+						  SWIZ_PTR(p++)))
+				return -EFAULT;
 
 	} else if (flags & F) {
 		data.ll = current->thread.TS_FPR(reg);
@@ -960,6 +1002,7 @@
 			preempt_disable();
 			enable_kernel_fp();
 			cvt_df(&data.dd, (float *)&data.x32.low32);
+			disable_kernel_fp();
 			preempt_enable();
 #else
 			return 0;
@@ -1000,6 +1043,7 @@
 		preempt_disable();
 		enable_kernel_fp();
 		cvt_fd((float *)&data.x32.low32, &data.dd);
+		disable_kernel_fp();
 		preempt_enable();
 #else
 		return 0;
@@ -1020,15 +1064,13 @@
 			break;
 		}
 
-		ret = 0;
 		p = (unsigned long)addr;
 
 		for (i = 0; i < nb; i++)
-			ret |= __put_user_inatomic(data.v[start + i],
-						   SWIZ_PTR(p++));
+			if (__put_user_or_set_dar(regs, data.v[start + i],
+						  SWIZ_PTR(p++)))
+				return -EFAULT;
 
-		if (unlikely(ret))
-			return -EFAULT;
 	} else if (flags & F)
 		current->thread.TS_FPR(reg) = data.ll;
 	else
--- linux-4.4.0.orig/arch/powerpc/kernel/asm-offsets.c
+++ linux-4.4.0/arch/powerpc/kernel/asm-offsets.c
@@ -243,6 +243,9 @@
 #ifdef CONFIG_PPC_BOOK3S_64
 	DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp));
 	DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce));
+	DEFINE(PACA_RFI_FLUSH_FALLBACK_AREA, offsetof(struct paca_struct, rfi_flush_fallback_area));
+	DEFINE(PACA_EXRFI, offsetof(struct paca_struct, exrfi));
+	DEFINE(PACA_L1D_FLUSH_SIZE, offsetof(struct paca_struct, l1d_flush_size));
 #endif
 	DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
 	DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
@@ -395,6 +398,7 @@
 	DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
 	DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime));
 	DEFINE(STAMP_SEC_FRAC, offsetof(struct vdso_data, stamp_sec_fraction));
+	DEFINE(CLOCK_HRTIMER_RES, offsetof(struct vdso_data, hrtimer_res));
 	DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size));
 	DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size));
 	DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size));
@@ -423,7 +427,6 @@
 	DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
 	DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
 	DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
-	DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
 
 #ifdef CONFIG_BUG
 	DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
@@ -519,7 +522,6 @@
 	DEFINE(VCPU_PURR, offsetof(struct kvm_vcpu, arch.purr));
 	DEFINE(VCPU_SPURR, offsetof(struct kvm_vcpu, arch.spurr));
 	DEFINE(VCPU_IC, offsetof(struct kvm_vcpu, arch.ic));
-	DEFINE(VCPU_VTB, offsetof(struct kvm_vcpu, arch.vtb));
 	DEFINE(VCPU_DSCR, offsetof(struct kvm_vcpu, arch.dscr));
 	DEFINE(VCPU_AMR, offsetof(struct kvm_vcpu, arch.amr));
 	DEFINE(VCPU_UAMOR, offsetof(struct kvm_vcpu, arch.uamor));
@@ -572,6 +574,7 @@
 	DEFINE(VCORE_LPCR, offsetof(struct kvmppc_vcore, lpcr));
 	DEFINE(VCORE_PCR, offsetof(struct kvmppc_vcore, pcr));
 	DEFINE(VCORE_DPDES, offsetof(struct kvmppc_vcore, dpdes));
+	DEFINE(VCORE_VTB, offsetof(struct kvmppc_vcore, vtb));
 	DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
 	DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv));
 	DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb));
@@ -584,6 +587,7 @@
 	DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr));
 	DEFINE(VCPU_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm));
 	DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_tm));
+	DEFINE(VCPU_XER_TM, offsetof(struct kvm_vcpu, arch.xer_tm));
 	DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm));
 	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
 	DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
--- linux-4.4.0.orig/arch/powerpc/kernel/cacheinfo.c
+++ linux-4.4.0/arch/powerpc/kernel/cacheinfo.c
@@ -867,4 +867,21 @@
 	if (cache)
 		cache_cpu_clear(cache, cpu_id);
 }
+
+void cacheinfo_teardown(void)
+{
+	unsigned int cpu;
+
+	for_each_online_cpu(cpu)
+		cacheinfo_cpu_offline(cpu);
+}
+
+void cacheinfo_rebuild(void)
+{
+	unsigned int cpu;
+
+	for_each_online_cpu(cpu)
+		cacheinfo_cpu_online(cpu);
+}
+
 #endif /* (CONFIG_PPC_PSERIES && CONFIG_SUSPEND) || CONFIG_HOTPLUG_CPU */
--- linux-4.4.0.orig/arch/powerpc/kernel/cacheinfo.h
+++ linux-4.4.0/arch/powerpc/kernel/cacheinfo.h
@@ -5,4 +5,8 @@
 extern void cacheinfo_cpu_online(unsigned int cpu_id);
 extern void cacheinfo_cpu_offline(unsigned int cpu_id);
 
+/* Allow migration/suspend to tear down and rebuild the hierarchy. */
+extern void cacheinfo_teardown(void);
+extern void cacheinfo_rebuild(void);
+
 #endif /* _PPC_CACHEINFO_H */
--- linux-4.4.0.orig/arch/powerpc/kernel/cpu_setup_power.S
+++ linux-4.4.0/arch/powerpc/kernel/cpu_setup_power.S
@@ -27,6 +27,7 @@
 	beqlr
 	li	r0,0
 	mtspr	SPRN_LPID,r0
+	mtspr	SPRN_PCR,r0
 	mfspr	r3,SPRN_LPCR
 	bl	__init_LPCR
 	bl	__init_tlb_power7
@@ -40,6 +41,7 @@
 	beqlr
 	li	r0,0
 	mtspr	SPRN_LPID,r0
+	mtspr	SPRN_PCR,r0
 	mfspr	r3,SPRN_LPCR
 	bl	__init_LPCR
 	bl	__init_tlb_power7
@@ -55,6 +57,7 @@
 	beqlr
 	li	r0,0
 	mtspr	SPRN_LPID,r0
+	mtspr	SPRN_PCR,r0
 	mfspr	r3,SPRN_LPCR
 	ori	r3, r3, LPCR_PECEDH
 	bl	__init_LPCR
@@ -74,6 +77,7 @@
 	beqlr
 	li	r0,0
 	mtspr	SPRN_LPID,r0
+	mtspr	SPRN_PCR,r0
 	mfspr   r3,SPRN_LPCR
 	ori	r3, r3, LPCR_PECEDH
 	bl	__init_LPCR
--- linux-4.4.0.orig/arch/powerpc/kernel/cputable.c
+++ linux-4.4.0/arch/powerpc/kernel/cputable.c
@@ -2147,11 +2147,13 @@
 		 * oprofile_cpu_type already has a value, then we are
 		 * possibly overriding a real PVR with a logical one,
 		 * and, in that case, keep the current value for
-		 * oprofile_cpu_type.
+		 * oprofile_cpu_type. Futhermore, let's ensure that the
+		 * fix for the PMAO bug is enabled on compatibility mode.
 		 */
 		if (old.oprofile_cpu_type != NULL) {
 			t->oprofile_cpu_type = old.oprofile_cpu_type;
 			t->oprofile_type = old.oprofile_type;
+			t->cpu_features |= old.cpu_features & CPU_FTR_PMAO_BUG;
 		}
 	}
 
--- linux-4.4.0.orig/arch/powerpc/kernel/dma-iommu.c
+++ linux-4.4.0/arch/powerpc/kernel/dma-iommu.c
@@ -99,7 +99,8 @@
 	if (!tbl)
 		return 0;
 
-	mask = 1ULL < (fls_long(tbl->it_offset + tbl->it_size) - 1);
+	mask = 1ULL << (fls_long(tbl->it_offset + tbl->it_size) +
+			tbl->it_page_shift - 1);
 	mask += mask - 1;
 
 	return mask;
--- linux-4.4.0.orig/arch/powerpc/kernel/eeh.c
+++ linux-4.4.0/arch/powerpc/kernel/eeh.c
@@ -304,9 +304,17 @@
 	 *
 	 * For pHyp, we have to enable IO for log retrieval. Otherwise,
 	 * 0xFF's is always returned from PCI config space.
+	 *
+	 * When the @severity is EEH_LOG_PERM, the PE is going to be
+	 * removed. Prior to that, the drivers for devices included in
+	 * the PE will be closed. The drivers rely on working IO path
+	 * to bring the devices to quiet state. Otherwise, PCI traffic
+	 * from those devices after they are removed is like to cause
+	 * another unexpected EEH error.
 	 */
 	if (!(pe->type & EEH_PE_PHB)) {
-		if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG))
+		if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG) ||
+		    severity == EEH_LOG_PERM)
 			eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
 
 		/*
@@ -355,10 +363,19 @@
 					   NULL, &hugepage_shift);
 	if (!ptep)
 		return token;
-	WARN_ON(hugepage_shift);
-	pa = pte_pfn(*ptep) << PAGE_SHIFT;
 
-	return pa | (token & (PAGE_SIZE-1));
+	pa = pte_pfn(*ptep);
+
+	/* On radix we can do hugepage mappings for io, so handle that */
+	if (hugepage_shift) {
+		pa <<= hugepage_shift;
+		pa |= token & ((1ul << hugepage_shift) - 1);
+	} else {
+		pa <<= PAGE_SHIFT;
+		pa |= token & (PAGE_SIZE - 1);
+	}
+
+	return pa;
 }
 
 /*
@@ -677,7 +694,7 @@
 	/* Check if the request is finished successfully */
 	if (active_flag) {
 		rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
-		if (rc <= 0)
+		if (rc < 0)
 			return rc;
 
 		if (rc & active_flag)
@@ -1072,7 +1089,7 @@
 	struct pci_controller *phb;
 	struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
 
-	if (!edev || !eeh_enabled())
+	if (!edev)
 		return;
 
 	if (!eeh_has_flag(EEH_PROBE_MODE_DEVTREE))
--- linux-4.4.0.orig/arch/powerpc/kernel/eeh_driver.c
+++ linux-4.4.0/arch/powerpc/kernel/eeh_driver.c
@@ -166,6 +166,16 @@
 	if (!edev)
 		return NULL;
 
+	/*
+	 * We cannot access the config space on some adapters.
+	 * Otherwise, it will cause fenced PHB. We don't save
+	 * the content in their config space and will restore
+	 * from the initial config space saved when the EEH
+	 * device is created.
+	 */
+	if (edev->pe && (edev->pe->state & EEH_PE_CFG_RESTRICTED))
+		return NULL;
+
 	pdev = eeh_dev_to_pci_dev(edev);
 	if (!pdev)
 		return NULL;
@@ -305,6 +315,19 @@
 	if (!edev)
 		return NULL;
 
+	/*
+	 * The content in the config space isn't saved because
+	 * the blocked config space on some adapters. We have
+	 * to restore the initial saved config space when the
+	 * EEH device is created.
+	 */
+	if (edev->pe && (edev->pe->state & EEH_PE_CFG_RESTRICTED)) {
+		if (list_is_last(&edev->list, &edev->pe->edevs))
+			eeh_pe_restore_bars(edev->pe);
+
+		return NULL;
+	}
+
 	pdev = eeh_dev_to_pci_dev(edev);
 	if (!pdev)
 		return NULL;
@@ -418,8 +441,7 @@
 		eeh_pcid_put(dev);
 		if (driver->err_handler &&
 		    driver->err_handler->error_detected &&
-		    driver->err_handler->slot_reset &&
-		    driver->err_handler->resume)
+		    driver->err_handler->slot_reset)
 			return NULL;
 	}
 
@@ -463,7 +485,7 @@
 static void *__eeh_clear_pe_frozen_state(void *data, void *flag)
 {
 	struct eeh_pe *pe = (struct eeh_pe *)data;
-	bool *clear_sw_state = flag;
+	bool clear_sw_state = *(bool *)flag;
 	int i, rc = 1;
 
 	for (i = 0; rc && i < 3; i++)
@@ -505,9 +527,6 @@
 	/* Save states */
 	eeh_pe_dev_traverse(pe, eeh_dev_save_state, NULL);
 
-	/* Report error */
-	eeh_pe_dev_traverse(pe, eeh_report_error, &result);
-
 	/* Issue reset */
 	ret = eeh_reset_pe(pe);
 	if (ret) {
@@ -592,8 +611,10 @@
 
 	/* Clear frozen state */
 	rc = eeh_clear_pe_frozen_state(pe, false);
-	if (rc)
+	if (rc) {
+		pci_unlock_rescan_remove();
 		return rc;
+	}
 
 	/* Give the system 5 seconds to finish running the user-space
 	 * hotplug shutdown scripts, e.g. ifdown for ethernet.  Yes,
@@ -611,6 +632,7 @@
 		 * rebuilt when adding PCI devices.
 		 */
 		eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL);
+		eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
 		pcibios_add_pci_devices(bus);
 	} else if (frozen_bus && removed) {
 		pr_info("EEH: Sleep 5s ahead of partial hotplug\n");
@@ -633,7 +655,7 @@
  */
 #define MAX_WAIT_FOR_RECOVERY 300
 
-static void eeh_handle_normal_event(struct eeh_pe *pe)
+static bool eeh_handle_normal_event(struct eeh_pe *pe)
 {
 	struct pci_bus *frozen_bus;
 	int rc = 0;
@@ -643,7 +665,7 @@
 	if (!frozen_bus) {
 		pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n",
 			__func__, pe->phb->global_number, pe->addr);
-		return;
+		return false;
 	}
 
 	eeh_pe_update_time_stamp(pe);
@@ -768,7 +790,7 @@
 	pr_info("EEH: Notify device driver to resume\n");
 	eeh_pe_dev_traverse(pe, eeh_report_resume, NULL);
 
-	return;
+	return false;
 
 excess_failures:
 	/*
@@ -803,12 +825,17 @@
 	 * the their PCI config any more.
 	 */
 	if (frozen_bus) {
+		eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
 		eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
 
 		pci_lock_rescan_remove();
 		pcibios_remove_pci_devices(frozen_bus);
 		pci_unlock_rescan_remove();
+
+		/* The passed PE should no longer be used */
+		return true;
 	}
+	return false;
 }
 
 static void eeh_handle_special_event(void)
@@ -874,7 +901,14 @@
 		 */
 		if (rc == EEH_NEXT_ERR_FROZEN_PE ||
 		    rc == EEH_NEXT_ERR_FENCED_PHB) {
-			eeh_handle_normal_event(pe);
+			/*
+			 * eeh_handle_normal_event() can make the PE stale if it
+			 * determines that the PE cannot possibly be recovered.
+			 * Don't modify the PE state if that's the case.
+			 */
+			if (eeh_handle_normal_event(pe))
+				continue;
+
 			eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
 		} else {
 			pci_lock_rescan_remove();
@@ -886,7 +920,16 @@
 					continue;
 
 				/* Notify all devices to be down */
+				eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
 				bus = eeh_pe_bus_get(phb_pe);
+				if (!bus) {
+					pr_err("%s: Cannot find PCI bus for "
+					       "PHB#%d-PE#%x\n",
+					       __func__,
+					       pe->phb->global_number,
+					       pe->addr);
+					break;
+				}
 				eeh_pe_dev_traverse(pe,
 					eeh_report_failure, NULL);
 				pcibios_remove_pci_devices(bus);
--- linux-4.4.0.orig/arch/powerpc/kernel/eeh_pe.c
+++ linux-4.4.0/arch/powerpc/kernel/eeh_pe.c
@@ -367,7 +367,7 @@
 		while (parent) {
 			if (!(parent->type & EEH_PE_INVALID))
 				break;
-			parent->type &= ~(EEH_PE_INVALID | EEH_PE_KEEP);
+			parent->type &= ~EEH_PE_INVALID;
 			parent = parent->parent;
 		}
 
@@ -788,7 +788,8 @@
 	eeh_ops->write_config(pdn, 15*4, 4, edev->config_space[15]);
 
 	/* PCI Command: 0x4 */
-	eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1]);
+	eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1] |
+			      PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
 
 	/* Check the PCIe link is ready */
 	eeh_bridge_check_link(edev);
@@ -883,32 +884,29 @@
 const char *eeh_pe_loc_get(struct eeh_pe *pe)
 {
 	struct pci_bus *bus = eeh_pe_bus_get(pe);
-	struct device_node *dn = pci_bus_to_OF_node(bus);
+	struct device_node *dn;
 	const char *loc = NULL;
 
-	if (!dn)
-		goto out;
+	while (bus) {
+		dn = pci_bus_to_OF_node(bus);
+		if (!dn) {
+			bus = bus->parent;
+			continue;
+		}
 
-	/* PHB PE or root PE ? */
-	if (pci_is_root_bus(bus)) {
-		loc = of_get_property(dn, "ibm,loc-code", NULL);
-		if (!loc)
+		if (pci_is_root_bus(bus))
 			loc = of_get_property(dn, "ibm,io-base-loc-code", NULL);
+		else
+			loc = of_get_property(dn, "ibm,slot-location-code",
+					      NULL);
+
 		if (loc)
-			goto out;
+			return loc;
 
-		/* Check the root port */
-		dn = dn->child;
-		if (!dn)
-			goto out;
+		bus = bus->parent;
 	}
 
-	loc = of_get_property(dn, "ibm,loc-code", NULL);
-	if (!loc)
-		loc = of_get_property(dn, "ibm,slot-location-code", NULL);
-
-out:
-	return loc ? loc : "N/A";
+	return "N/A";
 }
 
 /**
@@ -931,15 +929,17 @@
 		bus = pe->phb->bus;
 	} else if (pe->type & EEH_PE_BUS ||
 		   pe->type & EEH_PE_DEVICE) {
-		if (pe->bus) {
+		if (pe->state & EEH_PE_PRI_BUS) {
 			bus = pe->bus;
 			goto out;
 		}
 
 		edev = list_first_entry(&pe->edevs, struct eeh_dev, list);
+		pci_lock_rescan_remove();
 		pdev = eeh_dev_to_pci_dev(edev);
 		if (pdev)
 			bus = pdev->bus;
+		pci_unlock_rescan_remove();
 	}
 
 out:
--- linux-4.4.0.orig/arch/powerpc/kernel/entry_32.S
+++ linux-4.4.0/arch/powerpc/kernel/entry_32.S
@@ -33,6 +33,7 @@
 #include <asm/unistd.h>
 #include <asm/ftrace.h>
 #include <asm/ptrace.h>
+#include <asm/barrier.h>
 
 /*
  * MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE.
@@ -340,6 +341,15 @@
 	ori	r10,r10,sys_call_table@l
 	slwi	r0,r0,2
 	bge-	66f
+
+	barrier_nospec_asm
+	/*
+	 * Prevent the load of the handler below (based on the user-passed
+	 * system call number) being speculatively executed until the test
+	 * against NR_syscalls and branch to .66f above has
+	 * committed.
+	 */
+
 	lwzx	r10,r10,r0	/* Fetch system call handler [ptr] */
 	mtlr	r10
 	addi	r9,r1,STACK_FRAME_OVERHEAD
@@ -685,6 +695,9 @@
 	mtcr	r10
 	lwz	r10,_LINK(r11)
 	mtlr	r10
+	/* Clear the exception_marker on the stack to avoid confusing stacktrace */
+	li	r10, 0
+	stw	r10, 8(r11)
 	REST_GPR(10, r11)
 	mtspr	SPRN_SRR1,r9
 	mtspr	SPRN_SRR0,r12
@@ -915,6 +928,9 @@
 	mtcrf	0xFF,r10
 	mtlr	r11
 
+	/* Clear the exception_marker on the stack to avoid confusing stacktrace */
+	li	r10, 0
+	stw	r10, 8(r1)
 	/*
 	 * Once we put values in SRR0 and SRR1, we are in a state
 	 * where exceptions are not recoverable, since taking an
@@ -952,6 +968,9 @@
 	mtlr	r11
 	lwz	r10,_CCR(r1)
 	mtcrf	0xff,r10
+	/* Clear the exception_marker on the stack to avoid confusing stacktrace */
+	li	r10, 0
+	stw	r10, 8(r1)
 	REST_2GPRS(9, r1)
 	.globl exc_exit_restart
 exc_exit_restart:
--- linux-4.4.0.orig/arch/powerpc/kernel/entry_64.S
+++ linux-4.4.0/arch/powerpc/kernel/entry_64.S
@@ -25,6 +25,7 @@
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/thread_info.h>
+#include <asm/code-patching-asm.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/cputable.h>
@@ -36,6 +37,12 @@
 #include <asm/hw_irq.h>
 #include <asm/context_tracking.h>
 #include <asm/tm.h>
+#include <asm/barrier.h>
+#ifdef CONFIG_PPC_BOOK3S
+#include <asm/exception-64s.h>
+#else
+#include <asm/exception-64e.h>
+#endif
 
 /*
  * System calls.
@@ -70,6 +77,11 @@
 	std	r0,GPR0(r1)
 	std	r10,GPR1(r1)
 	beq	2f			/* if from kernel mode */
+#ifdef CONFIG_PPC_FSL_BOOK3E
+START_BTB_FLUSH_SECTION
+	BTB_FLUSH(r10)
+END_BTB_FLUSH_SECTION
+#endif
 	ACCOUNT_CPU_USER_ENTRY(r10, r11)
 2:	std	r2,GPR2(r1)
 	std	r3,GPR3(r1)
@@ -172,6 +184,15 @@
 	clrldi	r8,r8,32
 15:
 	slwi	r0,r0,4
+
+	barrier_nospec_asm
+	/*
+	 * Prevent the load of the handler below (based on the user-passed
+	 * system call number) being speculatively executed until the test
+	 * against NR_syscalls and branch to .Lsyscall_enosys above has
+	 * committed.
+	 */
+
 	ldx	r12,r11,r0	/* Fetch system call handler [ptr] */
 	mtctr   r12
 	bctrl			/* Call handler */
@@ -225,13 +246,23 @@
 	ACCOUNT_CPU_USER_EXIT(r11, r12)
 	HMT_MEDIUM_LOW_HAS_PPR
 	ld	r13,GPR13(r1)	/* only restore r13 if returning to usermode */
+	ld	r2,GPR2(r1)
+	ld	r1,GPR1(r1)
+	mtlr	r4
+	mtcr	r5
+	mtspr	SPRN_SRR0,r7
+	mtspr	SPRN_SRR1,r8
+	RFI_TO_USER
+	b	.	/* prevent speculative execution */
+
+	/* exit to kernel */
 1:	ld	r2,GPR2(r1)
 	ld	r1,GPR1(r1)
 	mtlr	r4
 	mtcr	r5
 	mtspr	SPRN_SRR0,r7
 	mtspr	SPRN_SRR1,r8
-	RFI
+	RFI_TO_KERNEL
 	b	.	/* prevent speculative execution */
 
 syscall_error:	
@@ -334,13 +365,13 @@
 tabort_syscall:
 	/* Firstly we need to enable TM in the kernel */
 	mfmsr	r10
-	li	r13, 1
-	rldimi	r10, r13, MSR_TM_LG, 63-MSR_TM_LG
+	li	r9, 1
+	rldimi	r10, r9, MSR_TM_LG, 63-MSR_TM_LG
 	mtmsrd	r10, 0
 
 	/* tabort, this dooms the transaction, nothing else */
-	li	r13, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
-	TABORT(R13)
+	li	r9, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
+	TABORT(R9)
 
 	/*
 	 * Return directly to userspace. We have corrupted user register state,
@@ -348,13 +379,12 @@
 	 * resume after the tbegin of the aborted transaction with the
 	 * checkpointed register state.
 	 */
-	li	r13, MSR_RI
-	andc	r10, r10, r13
+	li	r9, MSR_RI
+	andc	r10, r10, r9
 	mtmsrd	r10, 1
 	mtspr	SPRN_SRR0, r11
 	mtspr	SPRN_SRR1, r12
-
-	rfid
+	RFI_TO_USER
 	b	.	/* prevent speculative execution */
 #endif
 
@@ -426,6 +456,63 @@
 	li	r3,0
 	b	.Lsyscall_exit
 
+#ifdef CONFIG_PPC_BOOK3S_64
+
+#define FLUSH_COUNT_CACHE	\
+1:	nop;			\
+	patch_site 1b, patch__call_flush_count_cache
+
+
+#define BCCTR_FLUSH	.long 0x4c400420
+
+.macro nops number
+	.rept \number
+	nop
+	.endr
+.endm
+
+.balign 32
+.global flush_count_cache
+flush_count_cache:
+	/* Save LR into r9 */
+	mflr	r9
+
+	// Flush the link stack
+	.rept 64
+	bl	.+4
+	.endr
+	b	1f
+	nops	6
+
+	.balign 32
+	/* Restore LR */
+1:	mtlr	r9
+
+	// If we're just flushing the link stack, return here
+3:	nop
+	patch_site 3b patch__flush_link_stack_return
+
+	li	r9,0x7fff
+	mtctr	r9
+
+	BCCTR_FLUSH
+
+2:	nop
+	patch_site 2b patch__flush_count_cache_return
+
+	nops	3
+
+	.rept 278
+	.balign 32
+	BCCTR_FLUSH
+	nops	7
+	.endr
+
+	blr
+#else
+#define FLUSH_COUNT_CACHE
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
 /*
  * This routine switches between two different tasks.  The process
  * state of one is saved on its kernel stack.  Then the state
@@ -489,6 +576,8 @@
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 #endif
 
+	FLUSH_COUNT_CACHE
+
 #ifdef CONFIG_SMP
 	/* We need a sync somewhere here to make sure that if the
 	 * previous task gets rescheduled on another CPU, it sees all
@@ -560,6 +649,7 @@
 	 * actually hit this code path.
 	 */
 
+	isync
 	slbie	r6
 	slbie	r6		/* Workaround POWER5 < DD2.1 issue */
 	slbmte	r7,r0
@@ -716,7 +806,7 @@
 
 	addi	r8,r1,INT_FRAME_SIZE	/* Get the kprobed function entry */
 
-	lwz	r3,GPR1(r1)
+	ld	r3,GPR1(r1)
 	subi	r3,r3,INT_FRAME_SIZE	/* dst: Allocate a trampoline exception frame */
 	mr	r4,r1			/* src:  current exception frame */
 	mr	r1,r3			/* Reroute the trampoline frame to r1 */
@@ -730,8 +820,8 @@
 	addi	r6,r6,8
 	bdnz	2b
 
-	/* Do real store operation to complete stwu */
-	lwz	r5,GPR1(r1)
+	/* Do real store operation to complete stdu */
+	ld	r5,GPR1(r1)
 	std	r8,0(r5)
 
 	/* Clear _TIF_EMULATE_STACK_STORE flag */
@@ -887,7 +977,7 @@
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 	ACCOUNT_CPU_USER_EXIT(r2, r4)
 	REST_GPR(13, r1)
-1:
+
 	mtspr	SPRN_SRR1,r3
 
 	ld	r2,_CCR(r1)
@@ -900,8 +990,22 @@
 	ld	r3,GPR3(r1)
 	ld	r4,GPR4(r1)
 	ld	r1,GPR1(r1)
+	RFI_TO_USER
+	b	.	/* prevent speculative execution */
 
-	rfid
+1:	mtspr	SPRN_SRR1,r3
+
+	ld	r2,_CCR(r1)
+	mtcrf	0xFF,r2
+	ld	r2,_NIP(r1)
+	mtspr	SPRN_SRR0,r2
+
+	ld	r0,GPR0(r1)
+	ld	r2,GPR2(r1)
+	ld	r3,GPR3(r1)
+	ld	r4,GPR4(r1)
+	ld	r1,GPR1(r1)
+	RFI_TO_KERNEL
 	b	.	/* prevent speculative execution */
 
 #endif /* CONFIG_PPC_BOOK3E */
@@ -1077,7 +1181,7 @@
 	
 	mtspr	SPRN_SRR0,r5
 	mtspr	SPRN_SRR1,r6
-	rfid
+	RFI_TO_KERNEL
 	b	.	/* prevent speculative execution */
 
 rtas_return_loc:
@@ -1102,7 +1206,7 @@
 
 	mtspr	SPRN_SRR0,r3
 	mtspr	SPRN_SRR1,r4
-	rfid
+	RFI_TO_KERNEL
 	b	.	/* prevent speculative execution */
 
 	.align	3
@@ -1173,7 +1277,7 @@
 	LOAD_REG_IMMEDIATE(r12, MSR_SF | MSR_ISF | MSR_LE)
 	andc	r11,r11,r12
 	mtsrr1	r11
-	rfid
+	RFI_TO_KERNEL
 #endif /* CONFIG_PPC_BOOK3E */
 
 1:	/* Return from OF */
--- linux-4.4.0.orig/arch/powerpc/kernel/exceptions-64e.S
+++ linux-4.4.0/arch/powerpc/kernel/exceptions-64e.S
@@ -295,7 +295,8 @@
 	andi.	r10,r11,MSR_PR;		/* save stack pointer */	    \
 	beq	1f;			/* branch around if supervisor */   \
 	ld	r1,PACAKSAVE(r13);	/* get kernel stack coming from usr */\
-1:	cmpdi	cr1,r1,0;		/* check if SP makes sense */	    \
+1:	type##_BTB_FLUSH		\
+	cmpdi	cr1,r1,0;		/* check if SP makes sense */	    \
 	bge-	cr1,exc_##n##_bad_stack;/* bad stack (TODO: out of line) */ \
 	mfspr	r10,SPRN_##type##_SRR0;	/* read SRR0 before touching stack */
 
@@ -327,6 +328,30 @@
 #define SPRN_MC_SRR0	SPRN_MCSRR0
 #define SPRN_MC_SRR1	SPRN_MCSRR1
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+#define GEN_BTB_FLUSH			\
+	START_BTB_FLUSH_SECTION		\
+		beq 1f;			\
+		BTB_FLUSH(r10)			\
+		1:		\
+	END_BTB_FLUSH_SECTION
+
+#define CRIT_BTB_FLUSH			\
+	START_BTB_FLUSH_SECTION		\
+		BTB_FLUSH(r10)		\
+	END_BTB_FLUSH_SECTION
+
+#define DBG_BTB_FLUSH CRIT_BTB_FLUSH
+#define MC_BTB_FLUSH CRIT_BTB_FLUSH
+#define GDBELL_BTB_FLUSH GEN_BTB_FLUSH
+#else
+#define GEN_BTB_FLUSH
+#define CRIT_BTB_FLUSH
+#define DBG_BTB_FLUSH
+#define MC_BTB_FLUSH
+#define GDBELL_BTB_FLUSH
+#endif
+
 #define NORMAL_EXCEPTION_PROLOG(n, intnum, addition)			    \
 	EXCEPTION_PROLOG(n, intnum, GEN, addition##_GEN(n))
 
@@ -735,8 +760,14 @@
 	andis.	r15,r14,(DBSR_IC|DBSR_BT)@h
 	beq+	1f
 
+#ifdef CONFIG_RELOCATABLE
+	ld	r15,PACATOC(r13)
+	ld	r14,interrupt_base_book3e@got(r15)
+	ld	r15,__end_interrupts@got(r15)
+#else
 	LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)
 	LOAD_REG_IMMEDIATE(r15,__end_interrupts)
+#endif
 	cmpld	cr0,r10,r14
 	cmpld	cr1,r10,r15
 	blt+	cr0,1f
@@ -799,8 +830,14 @@
 	andis.	r15,r14,(DBSR_IC|DBSR_BT)@h
 	beq+	1f
 
+#ifdef CONFIG_RELOCATABLE
+	ld	r15,PACATOC(r13)
+	ld	r14,interrupt_base_book3e@got(r15)
+	ld	r15,__end_interrupts@got(r15)
+#else
 	LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)
 	LOAD_REG_IMMEDIATE(r15,__end_interrupts)
+#endif
 	cmpld	cr0,r10,r14
 	cmpld	cr1,r10,r15
 	blt+	cr0,1f
--- linux-4.4.0.orig/arch/powerpc/kernel/exceptions-64s.S
+++ linux-4.4.0/arch/powerpc/kernel/exceptions-64s.S
@@ -36,6 +36,7 @@
 END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)				\
 	mr	r9,r13 ;					\
 	GET_PACA(r13) ;						\
+	INTERRUPT_TO_KERNEL ;					\
 	mfspr	r11,SPRN_SRR0 ;					\
 0:
 
@@ -46,7 +47,7 @@
 	mtspr	SPRN_SRR0,r10 ; 				\
 	ld	r10,PACAKMSR(r13) ;				\
 	mtspr	SPRN_SRR1,r10 ; 				\
-	rfid ; 							\
+	RFI_TO_KERNEL ; 							\
 	b	. ;	/* prevent speculative execution */
 
 #define SYSCALL_PSERIES_3					\
@@ -54,7 +55,7 @@
 1:	mfspr	r12,SPRN_SRR1 ;					\
 	xori	r12,r12,MSR_LE ;				\
 	mtspr	SPRN_SRR1,r12 ;					\
-	rfid ;		/* return to userspace */		\
+	RFI_TO_USER ;		/* return to userspace */		\
 	b	. ;	/* prevent speculative execution */
 
 #if defined(CONFIG_RELOCATABLE)
@@ -201,8 +202,8 @@
 data_access_pSeries:
 	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
-	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
-				 KVMTEST, 0x300)
+	EXCEPTION_PROLOG_0(PACA_EXGEN)
+	b data_access_pSeries_ool
 
 	. = 0x380
 	.globl data_access_slb_pSeries
@@ -210,31 +211,15 @@
 	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 	EXCEPTION_PROLOG_0(PACA_EXSLB)
-	EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
-	std	r3,PACA_EXSLB+EX_R3(r13)
-	mfspr	r3,SPRN_DAR
-#ifdef __DISABLED__
-	/* Keep that around for when we re-implement dynamic VSIDs */
-	cmpdi	r3,0
-	bge	slb_miss_user_pseries
-#endif /* __DISABLED__ */
-	mfspr	r12,SPRN_SRR1
-#ifndef CONFIG_RELOCATABLE
-	b	slb_miss_realmode
-#else
-	/*
-	 * We can't just use a direct branch to slb_miss_realmode
-	 * because the distance from here to there depends on where
-	 * the kernel ends up being put.
-	 */
-	mfctr	r11
-	ld	r10,PACAKBASE(r13)
-	LOAD_HANDLER(r10, slb_miss_realmode)
-	mtctr	r10
-	bctr
-#endif
+	b data_access_slb_pSeries_ool
 
-	STD_EXCEPTION_PSERIES(0x400, 0x400, instruction_access)
+	. = 0x400
+	.globl instruction_access_pSeries
+instruction_access_pSeries:
+	HMT_MEDIUM_PPR_DISCARD
+	SET_SCRATCH0(r13)
+	EXCEPTION_PROLOG_0(PACA_EXGEN)
+	b instruction_access_pSeries_ool
 
 	. = 0x480
 	.globl instruction_access_slb_pSeries
@@ -242,24 +227,7 @@
 	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 	EXCEPTION_PROLOG_0(PACA_EXSLB)
-	EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480)
-	std	r3,PACA_EXSLB+EX_R3(r13)
-	mfspr	r3,SPRN_SRR0		/* SRR0 is faulting address */
-#ifdef __DISABLED__
-	/* Keep that around for when we re-implement dynamic VSIDs */
-	cmpdi	r3,0
-	bge	slb_miss_user_pseries
-#endif /* __DISABLED__ */
-	mfspr	r12,SPRN_SRR1
-#ifndef CONFIG_RELOCATABLE
-	b	slb_miss_realmode
-#else
-	mfctr	r11
-	ld	r10,PACAKBASE(r13)
-	LOAD_HANDLER(r10, slb_miss_realmode)
-	mtctr	r10
-	bctr
-#endif
+	b instruction_access_slb_pSeries_ool
 
 	/* We open code these as we can't have a ". = x" (even with
 	 * x = "." within a feature section
@@ -290,11 +258,19 @@
 	KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x800)
 
 	. = 0x900
-	.globl decrementer_pSeries
-decrementer_pSeries:
-	_MASKABLE_EXCEPTION_PSERIES(0x900, decrementer, EXC_STD, SOFTEN_TEST_PR)
+	.globl decrementer_trampoline
+decrementer_trampoline:
+	SET_SCRATCH0(r13)
+	EXCEPTION_PROLOG_0(PACA_EXGEN)
+	b	decrementer_ool
 
-	STD_EXCEPTION_HV(0x980, 0x982, hdecrementer)
+	. = 0x980
+	.globl hdecrementer_trampoline
+hdecrementer_trampoline:
+	HMT_MEDIUM_PPR_DISCARD;
+	SET_SCRATCH0(r13);
+	EXCEPTION_PROLOG_0(PACA_EXGEN)
+	b hdecrementer_hv
 
 	MASKABLE_EXCEPTION_PSERIES(0xa00, 0xa00, doorbell_super)
 	KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xa00)
@@ -319,6 +295,7 @@
 	OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);
 	HMT_MEDIUM;
 	std	r10,PACA_EXGEN+EX_R10(r13)
+	INTERRUPT_TO_KERNEL
 	OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR);
 	mfcr	r9
 	KVMTEST(0xc00)
@@ -507,7 +484,7 @@
 	LOAD_HANDLER(r12, machine_check_handle_early)
 1:	mtspr	SPRN_SRR0,r12
 	mtspr	SPRN_SRR1,r11
-	rfid
+	RFI_TO_KERNEL
 	b	.	/* prevent speculative execution */
 2:
 	/* Stack overflow. Stay on emergency stack and panic.
@@ -541,6 +518,64 @@
 	KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x900)
 	KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982)
 
+/* moved from 0x300 */
+	.globl data_access_pSeries_ool
+data_access_pSeries_ool:
+	EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, 0x300)
+	EXCEPTION_PROLOG_PSERIES_1(data_access_common, EXC_STD)
+
+	.globl data_access_slb_pSeries_ool
+data_access_slb_pSeries_ool:
+	EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
+	std	r3,PACA_EXSLB+EX_R3(r13)
+	mfspr	r3,SPRN_DAR
+#ifdef __DISABLED__
+	/* Keep that around for when we re-implement dynamic VSIDs */
+	cmpdi	r3,0
+	bge	slb_miss_user_pseries
+#endif /* __DISABLED__ */
+	mfspr	r12,SPRN_SRR1
+#ifndef CONFIG_RELOCATABLE
+	b	slb_miss_realmode
+#else
+	/*
+	 * We can't just use a direct branch to slb_miss_realmode
+	 * because the distance from here to there depends on where
+	 * the kernel ends up being put.
+	 */
+	mfctr	r11
+	ld	r10,PACAKBASE(r13)
+	LOAD_HANDLER(r10, slb_miss_realmode)
+	mtctr	r10
+	bctr
+#endif
+
+	.globl instruction_access_pSeries_ool
+instruction_access_pSeries_ool:
+	EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, 0x400)
+	EXCEPTION_PROLOG_PSERIES_1(instruction_access_common, EXC_STD)
+
+	.globl instruction_access_slb_pSeries_ool
+instruction_access_slb_pSeries_ool:
+	EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480)
+	std	r3,PACA_EXSLB+EX_R3(r13)
+	mfspr	r3,SPRN_SRR0		/* SRR0 is faulting address */
+#ifdef __DISABLED__
+	/* Keep that around for when we re-implement dynamic VSIDs */
+	cmpdi	r3,0
+	bge	slb_miss_user_pseries
+#endif /* __DISABLED__ */
+	mfspr	r12,SPRN_SRR1
+#ifndef CONFIG_RELOCATABLE
+	b	slb_miss_realmode
+#else
+	mfctr	r11
+	ld	r10,PACAKBASE(r13)
+	LOAD_HANDLER(r10, slb_miss_realmode)
+	mtctr	r10
+	bctr
+#endif
+
 #ifdef CONFIG_PPC_DENORMALISATION
 denorm_assist:
 BEGIN_FTR_SECTION
@@ -601,12 +636,14 @@
 	ld	r11,PACA_EXGEN+EX_R11(r13)
 	ld	r12,PACA_EXGEN+EX_R12(r13)
 	ld	r13,PACA_EXGEN+EX_R13(r13)
-	HRFID
+	HRFI_TO_UNKNOWN
 	b	.
 #endif
 
 	.align	7
 	/* moved from 0xe00 */
+	MASKABLE_EXCEPTION_OOL(0x900, decrementer)
+	STD_EXCEPTION_HV_OOL(0x982, hdecrementer)
 	STD_EXCEPTION_HV_OOL(0xe02, h_data_storage)
 	KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0xe02)
 	STD_EXCEPTION_HV_OOL(0xe22, h_instr_storage)
@@ -666,7 +703,7 @@
 	ld	r10,PACA_EXGEN+EX_R10(r13);		\
 	ld	r11,PACA_EXGEN+EX_R11(r13);		\
 	GET_SCRATCH0(r13);				\
-	##_H##rfid;					\
+	##_H##RFI_TO_KERNEL;				\
 	b	.
 	
 	MASKED_INTERRUPT()
@@ -698,6 +735,8 @@
 BEGIN_FTR_SECTION
 	cmpwi	r3,0xe80
 	beq	h_doorbell_common
+	cmpwi	r3,0xe60
+	beq	hmi_exception_common
 FTR_SECTION_ELSE
 	cmpwi	r3,0xa00
 	beq	doorbell_super_common
@@ -756,7 +795,7 @@
 	addi	r13, r13, 4
 	mtspr	SPRN_SRR0, r13
 	GET_SCRATCH0(r13)
-	rfid
+	RFI_TO_KERNEL
 	b	.
 
 kvmppc_skip_Hinterrupt:
@@ -768,7 +807,7 @@
 	addi	r13, r13, 4
 	mtspr	SPRN_HSRR0, r13
 	GET_SCRATCH0(r13)
-	hrfid
+	HRFI_TO_KERNEL
 	b	.
 #endif
 
@@ -889,7 +928,15 @@
 	STD_RELON_EXCEPTION_PSERIES(0x4600, 0x600, alignment)
 	STD_RELON_EXCEPTION_PSERIES(0x4700, 0x700, program_check)
 	STD_RELON_EXCEPTION_PSERIES(0x4800, 0x800, fp_unavailable)
-	MASKABLE_RELON_EXCEPTION_PSERIES(0x4900, 0x900, decrementer)
+
+	. = 0x4900
+	.globl decrementer_relon_trampoline
+decrementer_relon_trampoline:
+	HMT_MEDIUM_PPR_DISCARD
+	SET_SCRATCH0(r13)
+	EXCEPTION_PROLOG_0(PACA_EXGEN)
+	b decrementer_relon_pSeries
+
 	STD_RELON_EXCEPTION_HV(0x4980, 0x982, hdecrementer)
 	MASKABLE_RELON_EXCEPTION_PSERIES(0x4a00, 0xa00, doorbell_super)
 	STD_RELON_EXCEPTION_PSERIES(0x4b00, 0xb00, trap_0b)
@@ -962,11 +1009,6 @@
 #endif
 	STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist)
 
-	/* Other future vectors */
-	.align	7
-	.globl	__end_interrupts
-__end_interrupts:
-
 	.align	7
 system_call_entry:
 	b	system_call_common
@@ -1244,6 +1286,8 @@
 __end_handlers:
 
 	/* Equivalents to the above handlers for relocation-on interrupt vectors */
+	MASKABLE_RELON_EXCEPTION_PSERIES_OOL(0x900, decrementer)
+
 	STD_RELON_EXCEPTION_HV_OOL(0xe40, emulation_assist)
 	MASKABLE_RELON_EXCEPTION_HV_OOL(0xe80, h_doorbell)
 
@@ -1253,6 +1297,17 @@
 	STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
 	STD_RELON_EXCEPTION_HV_OOL(0xf80, hv_facility_unavailable)
 
+	/*
+	 * The __end_interrupts marker must be past the out-of-line (OOL)
+	 * handlers, so that they are copied to real address 0x100 when running
+	 * a relocatable kernel. This ensures they can be reached from the short
+	 * trampoline handlers (like 0x4f00, 0x4f20, etc.) which branch
+	 * directly, without using LOAD_HANDLER().
+	 */
+	.align	7
+	.globl	__end_interrupts
+__end_interrupts:
+
 #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
 /*
  * Data area reserved for FWNMI option.
@@ -1270,7 +1325,7 @@
 
 	.globl hmi_exception_early
 hmi_exception_early:
-	EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0xe60)
+	EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, 0xe62)
 	mr	r10,r1			/* Save r1			*/
 	ld	r1,PACAEMERGSP(r13)	/* Use emergency stack		*/
 	subi	r1,r1,INT_FRAME_SIZE	/* alloc stack frame		*/
@@ -1433,7 +1488,7 @@
 	li	r3,MSR_ME
 	andc	r10,r10,r3		/* Turn off MSR_ME */
 	mtspr	SPRN_SRR1,r10
-	rfid
+	RFI_TO_KERNEL
 	b	.
 2:
 	/*
@@ -1451,9 +1506,13 @@
 	 */
 	bl	machine_check_queue_event
 	MACHINE_CHECK_HANDLER_WINDUP
-	rfid
+	RFI_TO_USER_OR_KERNEL
 9:
 	/* Deliver the machine check to host kernel in V mode. */
+BEGIN_FTR_SECTION
+	ld	r10,ORIG_GPR3(r1)
+	mtspr	SPRN_CFAR,r10
+END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
 	MACHINE_CHECK_HANDLER_WINDUP
 	b	machine_check_pSeries
 
@@ -1497,6 +1556,8 @@
 
 	andi.	r10,r12,MSR_RI	/* check for unrecoverable exception */
 	beq-	2f
+	andi.	r10,r12,MSR_PR	/* check for user mode (PR != 0) */
+	bne	1f
 
 .machine	push
 .machine	"power4"
@@ -1510,7 +1571,23 @@
 	ld	r11,PACA_EXSLB+EX_R11(r13)
 	ld	r12,PACA_EXSLB+EX_R12(r13)
 	ld	r13,PACA_EXSLB+EX_R13(r13)
-	rfid
+	RFI_TO_KERNEL
+	b	.	/* prevent speculative execution */
+
+1:
+.machine	push
+.machine	"power4"
+	mtcrf	0x80,r9
+	mtcrf	0x01,r9		/* slb_allocate uses cr0 and cr7 */
+.machine	pop
+
+	RESTORE_PPR_PACA(PACA_EXSLB, r9)
+	ld	r9,PACA_EXSLB+EX_R9(r13)
+	ld	r10,PACA_EXSLB+EX_R10(r13)
+	ld	r11,PACA_EXSLB+EX_R11(r13)
+	ld	r12,PACA_EXSLB+EX_R12(r13)
+	ld	r13,PACA_EXSLB+EX_R13(r13)
+	RFI_TO_USER
 	b	.	/* prevent speculative execution */
 
 2:	mfspr	r11,SPRN_SRR0
@@ -1519,7 +1596,7 @@
 	mtspr	SPRN_SRR0,r10
 	ld	r10,PACAKMSR(r13)
 	mtspr	SPRN_SRR1,r10
-	rfid
+	RFI_TO_KERNEL
 	b	.
 
 unrecov_slb:
@@ -1540,6 +1617,98 @@
 	blr
 #endif
 
+	.balign 16
+	.globl stf_barrier_fallback
+stf_barrier_fallback:
+	std	r9,PACA_EXRFI+EX_R9(r13)
+	std	r10,PACA_EXRFI+EX_R10(r13)
+	sync
+	ld	r9,PACA_EXRFI+EX_R9(r13)
+	ld	r10,PACA_EXRFI+EX_R10(r13)
+	ori	31,31,0
+	.rept 14
+	b	1f
+1:
+	.endr
+	blr
+
+
+/* Clobbers r10, r11, ctr */
+.macro L1D_DISPLACEMENT_FLUSH
+	ld	r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
+	ld	r11,PACA_L1D_FLUSH_SIZE(r13)
+	srdi	r11,r11,(7 + 3) /* 128 byte lines, unrolled 8x */
+	mtctr	r11
+	DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
+
+	/* order ld/st prior to dcbt stop all streams with flushing */
+	sync
+
+	/*
+	 * The load addresses are at staggered offsets within cachelines,
+	 * which suits some pipelines better (on others it should not
+	 * hurt).
+	 */
+1:
+	ld	r11,(0x80 + 8)*0(r10)
+	ld	r11,(0x80 + 8)*1(r10)
+	ld	r11,(0x80 + 8)*2(r10)
+	ld	r11,(0x80 + 8)*3(r10)
+	ld	r11,(0x80 + 8)*4(r10)
+	ld	r11,(0x80 + 8)*5(r10)
+	ld	r11,(0x80 + 8)*6(r10)
+	ld	r11,(0x80 + 8)*7(r10)
+	addi	r10,r10,0x80*8
+	bdnz	1b
+.endm
+
+
+	.globl rfi_flush_fallback
+rfi_flush_fallback:
+	SET_SCRATCH0(r13);
+	GET_PACA(r13);
+	std	r9,PACA_EXRFI+EX_R9(r13)
+	std	r10,PACA_EXRFI+EX_R10(r13)
+	std	r11,PACA_EXRFI+EX_R11(r13)
+	mfctr	r9
+	L1D_DISPLACEMENT_FLUSH
+	mtctr	r9
+	ld	r9,PACA_EXRFI+EX_R9(r13)
+	ld	r10,PACA_EXRFI+EX_R10(r13)
+	ld	r11,PACA_EXRFI+EX_R11(r13)
+	GET_SCRATCH0(r13);
+	rfid
+
+	.globl hrfi_flush_fallback
+hrfi_flush_fallback:
+	SET_SCRATCH0(r13);
+	GET_PACA(r13);
+	std	r9,PACA_EXRFI+EX_R9(r13)
+	std	r10,PACA_EXRFI+EX_R10(r13)
+	std	r11,PACA_EXRFI+EX_R11(r13)
+	mfctr	r9
+	L1D_DISPLACEMENT_FLUSH
+	mtctr	r9
+	ld	r9,PACA_EXRFI+EX_R9(r13)
+	ld	r10,PACA_EXRFI+EX_R10(r13)
+	ld	r11,PACA_EXRFI+EX_R11(r13)
+	GET_SCRATCH0(r13);
+	hrfid
+
+	.globl entry_flush_fallback
+entry_flush_fallback:
+	std	r9,PACA_EXRFI+EX_R9(r13)
+	std	r10,PACA_EXRFI+EX_R10(r13)
+	std	r11,PACA_EXRFI+EX_R11(r13)
+	mfctr	r9
+	L1D_DISPLACEMENT_FLUSH
+	mtctr	r9
+	ld	r9,PACA_EXRFI+EX_R9(r13)
+	ld	r10,PACA_EXRFI+EX_R10(r13)
+	ld	r11,PACA_EXRFI+EX_R11(r13)
+	blr
+
+
 /*
  * Hash table stuff
  */
@@ -1593,7 +1762,7 @@
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	do_page_fault
 	cmpdi	r3,0
-	beq+	12f
+	beq+	ret_from_except_lite
 	bl	save_nvgprs
 	mr	r5,r3
 	addi	r3,r1,STACK_FRAME_OVERHEAD
@@ -1608,7 +1777,12 @@
 	ld      r5,_DSISR(r1)
 	addi    r3,r1,STACK_FRAME_OVERHEAD
 	bl      do_break
-12:	b       ret_from_except_lite
+	/*
+	 * do_break() may have changed the NV GPRS while handling a breakpoint.
+	 * If so, we need to restore them with their updated values. Don't use
+	 * ret_from_except_lite here.
+	 */
+	b       ret_from_except
 
 
 /* We have a page fault that hash_page could handle but HV refused
@@ -1694,3 +1868,12 @@
 1:	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	kernel_bad_stack
 	b	1b
+
+_KPROBE(do_uaccess_flush)
+	UACCESS_FLUSH_FIXUP_SECTION
+	nop
+	nop
+	nop
+	blr
+	L1D_DISPLACEMENT_FLUSH
+	blr
--- linux-4.4.0.orig/arch/powerpc/kernel/fadump.c
+++ linux-4.4.0/arch/powerpc/kernel/fadump.c
@@ -35,6 +35,7 @@
 #include <linux/crash_dump.h>
 #include <linux/kobject.h>
 #include <linux/sysfs.h>
+#include <linux/slab.h>
 
 #include <asm/page.h>
 #include <asm/prom.h>
@@ -48,8 +49,10 @@
 static const struct fadump_mem_struct *fdm_active;
 
 static DEFINE_MUTEX(fadump_mutex);
-struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES];
+struct fad_crash_memory_ranges *crash_memory_ranges;
+int crash_memory_ranges_size;
 int crash_mem_ranges;
+int max_crash_mem_ranges;
 
 /* Scan the Firmware Assisted dump configuration details. */
 int __init early_init_dt_scan_fw_dump(unsigned long node,
@@ -357,9 +360,9 @@
 }
 early_param("fadump_reserve_mem", early_fadump_reserve_mem);
 
-static void register_fw_dump(struct fadump_mem_struct *fdm)
+static int register_fw_dump(struct fadump_mem_struct *fdm)
 {
-	int rc;
+	int rc, err;
 	unsigned int wait_time;
 
 	pr_debug("Registering for firmware-assisted kernel dump...\n");
@@ -376,7 +379,11 @@
 
 	} while (wait_time);
 
+	err = -EIO;
 	switch (rc) {
+	default:
+		pr_err("Failed to register. Unknown Error(%d).\n", rc);
+		break;
 	case -1:
 		printk(KERN_ERR "Failed to register firmware-assisted kernel"
 			" dump. Hardware Error(%d).\n", rc);
@@ -384,18 +391,22 @@
 	case -3:
 		printk(KERN_ERR "Failed to register firmware-assisted kernel"
 			" dump. Parameter Error(%d).\n", rc);
+		err = -EINVAL;
 		break;
 	case -9:
 		printk(KERN_ERR "firmware-assisted kernel dump is already "
 			" registered.");
 		fw_dump.dump_registered = 1;
+		err = -EEXIST;
 		break;
 	case 0:
 		printk(KERN_INFO "firmware-assisted kernel dump registration"
 			" is successful\n");
 		fw_dump.dump_registered = 1;
+		err = 0;
 		break;
 	}
+	return err;
 }
 
 void crash_fadump(struct pt_regs *regs, const char *str)
@@ -726,38 +737,88 @@
 	return 0;
 }
 
-static inline void fadump_add_crash_memory(unsigned long long base,
-					unsigned long long end)
+static void free_crash_memory_ranges(void)
+{
+	kfree(crash_memory_ranges);
+	crash_memory_ranges = NULL;
+	crash_memory_ranges_size = 0;
+	max_crash_mem_ranges = 0;
+}
+
+/*
+ * Allocate or reallocate crash memory ranges array in incremental units
+ * of PAGE_SIZE.
+ */
+static int allocate_crash_memory_ranges(void)
+{
+	struct fad_crash_memory_ranges *new_array;
+	u64 new_size;
+
+	new_size = crash_memory_ranges_size + PAGE_SIZE;
+	pr_debug("Allocating %llu bytes of memory for crash memory ranges\n",
+		 new_size);
+
+	new_array = krealloc(crash_memory_ranges, new_size, GFP_KERNEL);
+	if (new_array == NULL) {
+		pr_err("Insufficient memory for setting up crash memory ranges\n");
+		free_crash_memory_ranges();
+		return -ENOMEM;
+	}
+
+	crash_memory_ranges = new_array;
+	crash_memory_ranges_size = new_size;
+	max_crash_mem_ranges = (new_size /
+				sizeof(struct fad_crash_memory_ranges));
+	return 0;
+}
+
+static inline int fadump_add_crash_memory(unsigned long long base,
+					  unsigned long long end)
 {
 	if (base == end)
-		return;
+		return 0;
+
+	if (crash_mem_ranges == max_crash_mem_ranges) {
+		int ret;
+
+		ret = allocate_crash_memory_ranges();
+		if (ret)
+			return ret;
+	}
 
 	pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n",
 		crash_mem_ranges, base, end - 1, (end - base));
 	crash_memory_ranges[crash_mem_ranges].base = base;
 	crash_memory_ranges[crash_mem_ranges].size = end - base;
 	crash_mem_ranges++;
+	return 0;
 }
 
-static void fadump_exclude_reserved_area(unsigned long long start,
+static int fadump_exclude_reserved_area(unsigned long long start,
 					unsigned long long end)
 {
 	unsigned long long ra_start, ra_end;
+	int ret = 0;
 
 	ra_start = fw_dump.reserve_dump_area_start;
 	ra_end = ra_start + fw_dump.reserve_dump_area_size;
 
 	if ((ra_start < end) && (ra_end > start)) {
 		if ((start < ra_start) && (end > ra_end)) {
-			fadump_add_crash_memory(start, ra_start);
-			fadump_add_crash_memory(ra_end, end);
+			ret = fadump_add_crash_memory(start, ra_start);
+			if (ret)
+				return ret;
+
+			ret = fadump_add_crash_memory(ra_end, end);
 		} else if (start < ra_start) {
-			fadump_add_crash_memory(start, ra_start);
+			ret = fadump_add_crash_memory(start, ra_start);
 		} else if (ra_end < end) {
-			fadump_add_crash_memory(ra_end, end);
+			ret = fadump_add_crash_memory(ra_end, end);
 		}
 	} else
-		fadump_add_crash_memory(start, end);
+		ret = fadump_add_crash_memory(start, end);
+
+	return ret;
 }
 
 static int fadump_init_elfcore_header(char *bufp)
@@ -793,10 +854,11 @@
  * Traverse through memblock structure and setup crash memory ranges. These
  * ranges will be used create PT_LOAD program headers in elfcore header.
  */
-static void fadump_setup_crash_memory_ranges(void)
+static int fadump_setup_crash_memory_ranges(void)
 {
 	struct memblock_region *reg;
 	unsigned long long start, end;
+	int ret;
 
 	pr_debug("Setup crash memory ranges.\n");
 	crash_mem_ranges = 0;
@@ -807,7 +869,9 @@
 	 * specified during fadump registration. We need to create a separate
 	 * program header for this chunk with the correct offset.
 	 */
-	fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size);
+	ret = fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size);
+	if (ret)
+		return ret;
 
 	for_each_memblock(memory, reg) {
 		start = (unsigned long long)reg->base;
@@ -816,8 +880,12 @@
 			start = fw_dump.boot_memory_size;
 
 		/* add this range excluding the reserved dump area. */
-		fadump_exclude_reserved_area(start, end);
+		ret = fadump_exclude_reserved_area(start, end);
+		if (ret)
+			return ret;
 	}
+
+	return 0;
 }
 
 /*
@@ -937,19 +1005,22 @@
 	return addr;
 }
 
-static void register_fadump(void)
+static int register_fadump(void)
 {
 	unsigned long addr;
 	void *vaddr;
+	int ret;
 
 	/*
 	 * If no memory is reserved then we can not register for firmware-
 	 * assisted dump.
 	 */
 	if (!fw_dump.reserve_dump_area_size)
-		return;
+		return -ENODEV;
 
-	fadump_setup_crash_memory_ranges();
+	ret = fadump_setup_crash_memory_ranges();
+	if (ret)
+		return ret;
 
 	addr = be64_to_cpu(fdm.rmr_region.destination_address) + be64_to_cpu(fdm.rmr_region.source_len);
 	/* Initialize fadump crash info header. */
@@ -960,7 +1031,7 @@
 	fadump_create_elfcore_headers(vaddr);
 
 	/* register the future kernel dump with firmware. */
-	register_fw_dump(&fdm);
+	return register_fw_dump(&fdm);
 }
 
 static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
@@ -1025,6 +1096,10 @@
 		init_fadump_mem_struct(&fdm,
 			be64_to_cpu(fdm_active->cpu_state_data.destination_address));
 		fadump_invalidate_dump(&fdm);
+	} else if (fw_dump.dump_registered) {
+		/* Un-register Firmware-assisted dump if it was registered. */
+		fadump_unregister_dump(&fdm);
+		free_crash_memory_ranges();
 	}
 }
 
@@ -1141,7 +1216,6 @@
 	switch (buf[0]) {
 	case '0':
 		if (fw_dump.dump_registered == 0) {
-			ret = -EINVAL;
 			goto unlock_out;
 		}
 		/* Un-register Firmware-assisted dump */
@@ -1149,11 +1223,11 @@
 		break;
 	case '1':
 		if (fw_dump.dump_registered == 1) {
-			ret = -EINVAL;
+			ret = -EEXIST;
 			goto unlock_out;
 		}
 		/* Register Firmware-assisted dump */
-		register_fadump();
+		ret = register_fadump();
 		break;
 	default:
 		ret = -EINVAL;
@@ -1279,6 +1353,25 @@
 	return;
 }
 
+static int fadump_panic_event(struct notifier_block *this,
+			      unsigned long event, void *ptr)
+{
+	/*
+	 * If firmware-assisted dump has been registered then trigger
+	 * firmware-assisted dump and let firmware handle everything
+	 * else. If this returns, then fadump was not registered, so
+	 * go through the rest of the panic path.
+	 */
+	crash_fadump(NULL, ptr);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block fadump_panic_block = {
+	.notifier_call = fadump_panic_event,
+	.priority = INT_MIN /* may not return; must be done last */
+};
+
 /*
  * Prepare for firmware-assisted dump.
  */
@@ -1311,6 +1404,9 @@
 		init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
 	fadump_init_files();
 
+	atomic_notifier_chain_register(&panic_notifier_list,
+					&fadump_panic_block);
+
 	return 1;
 }
 subsys_initcall(setup_fadump);
--- linux-4.4.0.orig/arch/powerpc/kernel/head_8xx.S
+++ linux-4.4.0/arch/powerpc/kernel/head_8xx.S
@@ -361,11 +361,9 @@
 	/* Load the MI_TWC with the attributes for this "segment." */
 	MTSPR_CPU6(SPRN_MI_TWC, r11, r3)	/* Set segment attributes */
 
-#ifdef CONFIG_SWAP
-	rlwinm	r11, r10, 32-5, _PAGE_PRESENT
+	rlwinm	r11, r10, 32-11, _PAGE_PRESENT
 	and	r11, r11, r10
 	rlwimi	r10, r11, 0, _PAGE_PRESENT
-#endif
 	li	r11, RPN_PATTERN
 	/* The Linux PTE won't go exactly into the MMU TLB.
 	 * Software indicator bits 20-23 and 28 must be clear.
@@ -436,11 +434,9 @@
 	 * r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5));
 	 * r10 = (r10 & ~PRESENT) | r11;
 	 */
-#ifdef CONFIG_SWAP
-	rlwinm	r11, r10, 32-5, _PAGE_PRESENT
+	rlwinm	r11, r10, 32-11, _PAGE_PRESENT
 	and	r11, r11, r10
 	rlwimi	r10, r11, 0, _PAGE_PRESENT
-#endif
 	/* The Linux PTE won't go exactly into the MMU TLB.
 	 * Software indicator bits 22 and 28 must be clear.
 	 * Software indicator bits 24, 25, 26, and 27 must be
@@ -720,7 +716,7 @@
 	tovirt(r6,r6)
 	lis	r5, abatron_pteptrs@h
 	ori	r5, r5, abatron_pteptrs@l
-	stw	r5, 0xf0(r0)	/* Must match your Abatron config file */
+	stw	r5, 0xf0(0)	/* Must match your Abatron config file */
 	tophys(r5,r5)
 	stw	r6, 0(r5)
 
--- linux-4.4.0.orig/arch/powerpc/kernel/head_booke.h
+++ linux-4.4.0/arch/powerpc/kernel/head_booke.h
@@ -31,6 +31,16 @@
  */
 #define THREAD_NORMSAVE(offset)	(THREAD_NORMSAVES + (offset * 4))
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+#define BOOKE_CLEAR_BTB(reg)									\
+START_BTB_FLUSH_SECTION								\
+	BTB_FLUSH(reg)									\
+END_BTB_FLUSH_SECTION
+#else
+#define BOOKE_CLEAR_BTB(reg)
+#endif
+
+
 #define NORMAL_EXCEPTION_PROLOG(intno)						     \
 	mtspr	SPRN_SPRG_WSCRATCH0, r10;	/* save one register */	     \
 	mfspr	r10, SPRN_SPRG_THREAD;					     \
@@ -42,6 +52,7 @@
 	andi.	r11, r11, MSR_PR;	/* check whether user or kernel    */\
 	mr	r11, r1;						     \
 	beq	1f;							     \
+	BOOKE_CLEAR_BTB(r11)						\
 	/* if from user, start at top of this thread's kernel stack */       \
 	lwz	r11, THREAD_INFO-THREAD(r10);				     \
 	ALLOC_STACK_FRAME(r11, THREAD_SIZE);				     \
@@ -127,6 +138,7 @@
 	stw	r9,_CCR(r8);		/* save CR on stack		   */\
 	mfspr	r11,exc_level_srr1;	/* check whether user or kernel    */\
 	DO_KVM	BOOKE_INTERRUPT_##intno exc_level_srr1;		             \
+	BOOKE_CLEAR_BTB(r10)						\
 	andi.	r11,r11,MSR_PR;						     \
 	mfspr	r11,SPRN_SPRG_THREAD;	/* if from user, start at top of   */\
 	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
--- linux-4.4.0.orig/arch/powerpc/kernel/head_fsl_booke.S
+++ linux-4.4.0/arch/powerpc/kernel/head_fsl_booke.S
@@ -451,6 +451,13 @@
 	mfcr	r13
 	stw	r13, THREAD_NORMSAVE(3)(r10)
 	DO_KVM	BOOKE_INTERRUPT_DTLB_MISS SPRN_SRR1
+START_BTB_FLUSH_SECTION
+	mfspr r11, SPRN_SRR1
+	andi. r10,r11,MSR_PR
+	beq 1f
+	BTB_FLUSH(r10)
+1:
+END_BTB_FLUSH_SECTION
 	mfspr	r10, SPRN_DEAR		/* Get faulting address */
 
 	/* If we are faulting a kernel address, we have to use the
@@ -545,6 +552,14 @@
 	mfcr	r13
 	stw	r13, THREAD_NORMSAVE(3)(r10)
 	DO_KVM	BOOKE_INTERRUPT_ITLB_MISS SPRN_SRR1
+START_BTB_FLUSH_SECTION
+	mfspr r11, SPRN_SRR1
+	andi. r10,r11,MSR_PR
+	beq 1f
+	BTB_FLUSH(r10)
+1:
+END_BTB_FLUSH_SECTION
+
 	mfspr	r10, SPRN_SRR0		/* Get faulting address */
 
 	/* If we are faulting a kernel address, we have to use the
--- linux-4.4.0.orig/arch/powerpc/kernel/hmi.c
+++ linux-4.4.0/arch/powerpc/kernel/hmi.c
@@ -0,0 +1,56 @@
+/*
+ * Hypervisor Maintenance Interrupt (HMI) handling.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ *
+ * Copyright 2015 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <asm/paca.h>
+#include <asm/hmi.h>
+
+void wait_for_subcore_guest_exit(void)
+{
+	int i;
+
+	/*
+	 * NULL bitmap pointer indicates that KVM module hasn't
+	 * been loaded yet and hence no guests are running.
+	 * If no KVM is in use, no need to co-ordinate among threads
+	 * as all of them will always be in host and no one is going
+	 * to modify TB other than the opal hmi handler.
+	 * Hence, just return from here.
+	 */
+	if (!local_paca->sibling_subcore_state)
+		return;
+
+	for (i = 0; i < MAX_SUBCORE_PER_CORE; i++)
+		while (local_paca->sibling_subcore_state->in_guest[i])
+			cpu_relax();
+}
+
+void wait_for_tb_resync(void)
+{
+	if (!local_paca->sibling_subcore_state)
+		return;
+
+	while (test_bit(CORE_TB_RESYNC_REQ_BIT,
+				&local_paca->sibling_subcore_state->flags))
+		cpu_relax();
+}
--- linux-4.4.0.orig/arch/powerpc/kernel/hw_breakpoint.c
+++ linux-4.4.0/arch/powerpc/kernel/hw_breakpoint.c
@@ -174,8 +174,8 @@
 	if (cpu_has_feature(CPU_FTR_DAWR)) {
 		length_max = 512 ; /* 64 doublewords */
 		/* DAWR region can't cross 512 boundary */
-		if ((bp->attr.bp_addr >> 10) != 
-		    ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 10))
+		if ((bp->attr.bp_addr >> 9) !=
+		    ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 9))
 			return -EINVAL;
 	}
 	if (info->len >
@@ -227,8 +227,10 @@
 	rcu_read_lock();
 
 	bp = __this_cpu_read(bp_per_reg);
-	if (!bp)
+	if (!bp) {
+		rc = NOTIFY_DONE;
 		goto out;
+	}
 	info = counter_arch_bp(bp);
 
 	/*
--- linux-4.4.0.orig/arch/powerpc/kernel/ibmebus.c
+++ linux-4.4.0/arch/powerpc/kernel/ibmebus.c
@@ -180,6 +180,7 @@
 static int ibmebus_create_devices(const struct of_device_id *matches)
 {
 	struct device_node *root, *child;
+	struct device *dev;
 	int ret = 0;
 
 	root = of_find_node_by_path("/");
@@ -188,9 +189,12 @@
 		if (!of_match_node(matches, child))
 			continue;
 
-		if (bus_find_device(&ibmebus_bus_type, NULL, child,
-				    ibmebus_match_node))
+		dev = bus_find_device(&ibmebus_bus_type, NULL, child,
+				      ibmebus_match_node);
+		if (dev) {
+			put_device(dev);
 			continue;
+		}
 
 		ret = ibmebus_create_device(child);
 		if (ret) {
@@ -262,6 +266,7 @@
 				   const char *buf, size_t count)
 {
 	struct device_node *dn = NULL;
+	struct device *dev;
 	char *path;
 	ssize_t rc = 0;
 
@@ -269,8 +274,10 @@
 	if (!path)
 		return -ENOMEM;
 
-	if (bus_find_device(&ibmebus_bus_type, NULL, path,
-			    ibmebus_match_path)) {
+	dev = bus_find_device(&ibmebus_bus_type, NULL, path,
+			      ibmebus_match_path);
+	if (dev) {
+		put_device(dev);
 		printk(KERN_WARNING "%s: %s has already been probed\n",
 		       __func__, path);
 		rc = -EEXIST;
@@ -307,6 +314,7 @@
 	if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
 				   ibmebus_match_path))) {
 		of_device_unregister(to_platform_device(dev));
+		put_device(dev);
 
 		kfree(path);
 		return count;
--- linux-4.4.0.orig/arch/powerpc/kernel/idle_power7.S
+++ linux-4.4.0/arch/powerpc/kernel/idle_power7.S
@@ -44,7 +44,7 @@
 	std	r0,0(r1);					\
 	ptesync;						\
 	ld	r0,0(r1);					\
-1:	cmp	cr0,r0,r0;					\
+1:	cmpd	cr0,r0,r0;					\
 	bne	1b;						\
 	IDLE_INST;						\
 	b	.
@@ -277,8 +277,9 @@
 	ld	r2,PACATOC(r13);					\
 	ld	r1,PACAR1(r13);						\
 	std	r3,ORIG_GPR3(r1);	/* Save original r3 */		\
-	li	r0,OPAL_HANDLE_HMI;	/* Pass opal token argument*/	\
-	bl	opal_call_realmode;					\
+	li	r3,0;			/* NULL argument */		\
+	bl	hmi_exception_realmode;					\
+	nop;								\
 	ld	r3,ORIG_GPR3(r1);	/* Restore original r3 */	\
 20:	nop;
 
--- linux-4.4.0.orig/arch/powerpc/kernel/iommu.c
+++ linux-4.4.0/arch/powerpc/kernel/iommu.c
@@ -479,7 +479,8 @@
 
 		/* Handle failure */
 		if (unlikely(entry == DMA_ERROR_CODE)) {
-			if (printk_ratelimit())
+			if (unlikely(!dma_get_attr(DMA_ATTR_NO_WARN, attrs)) &&
+			    printk_ratelimit())
 				dev_info(dev, "iommu_alloc failed, tbl %p "
 					 "vaddr %lx npages %lu\n", tbl, vaddr,
 					 npages);
@@ -764,9 +765,9 @@
 
 	vaddr = page_address(page) + offset;
 	uaddr = (unsigned long)vaddr;
-	npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl));
 
 	if (tbl) {
+		npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl));
 		align = 0;
 		if (tbl->it_page_shift < PAGE_SHIFT && size >= PAGE_SIZE &&
 		    ((unsigned long)vaddr & ~PAGE_MASK) == 0)
@@ -776,7 +777,8 @@
 					 mask >> tbl->it_page_shift, align,
 					 attrs);
 		if (dma_handle == DMA_ERROR_CODE) {
-			if (printk_ratelimit())  {
+			if (unlikely(!dma_get_attr(DMA_ATTR_NO_WARN, attrs)) &&
+			    printk_ratelimit())  {
 				dev_info(dev, "iommu_alloc failed, tbl %p "
 					 "vaddr %p npages %d\n", tbl, vaddr,
 					 npages);
--- linux-4.4.0.orig/arch/powerpc/kernel/irq.c
+++ linux-4.4.0/arch/powerpc/kernel/irq.c
@@ -484,8 +484,6 @@
 
 	trace_irq_entry(regs);
 
-	check_stack_overflow();
-
 	/*
 	 * Query the platform PIC for the interrupt & ack it.
 	 *
@@ -517,6 +515,8 @@
 	irqtp = hardirq_ctx[raw_smp_processor_id()];
 	sirqtp = softirq_ctx[raw_smp_processor_id()];
 
+	check_stack_overflow();
+
 	/* Already there ? */
 	if (unlikely(curtp == irqtp || curtp == sirqtp)) {
 		__do_irq(regs);
--- linux-4.4.0.orig/arch/powerpc/kernel/kprobes.c
+++ linux-4.4.0/arch/powerpc/kernel/kprobes.c
@@ -514,6 +514,15 @@
 #endif
 #endif
 
+	/*
+	 * jprobes use jprobe_return() which skips the normal return
+	 * path of the function, and this messes up the accounting of the
+	 * function graph tracer.
+	 *
+	 * Pause function graph tracing while performing the jprobe function.
+	 */
+	pause_graph_tracing();
+
 	return 1;
 }
 
@@ -536,6 +545,8 @@
 	 * saved regs...
 	 */
 	memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs));
+	/* It's OK to start function graph tracing again */
+	unpause_graph_tracing();
 	preempt_enable_no_resched();
 	return 1;
 }
--- linux-4.4.0.orig/arch/powerpc/kernel/machine_kexec.c
+++ linux-4.4.0/arch/powerpc/kernel/machine_kexec.c
@@ -113,11 +113,12 @@
 
 void __init reserve_crashkernel(void)
 {
-	unsigned long long crash_size, crash_base;
+	unsigned long long crash_size, crash_base, total_mem_sz;
 	int ret;
 
+	total_mem_sz = memory_limit ? memory_limit : memblock_phys_mem_size();
 	/* use common parsing */
-	ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
+	ret = parse_crashkernel(boot_command_line, total_mem_sz,
 			&crash_size, &crash_base);
 	if (ret == 0 && crash_size > 0) {
 		crashk_res.start = crash_base;
@@ -176,6 +177,7 @@
 	/* Crash kernel trumps memory limit */
 	if (memory_limit && memory_limit <= crashk_res.end) {
 		memory_limit = crashk_res.end + 1;
+		total_mem_sz = memory_limit;
 		printk("Adjusted memory limit for crashkernel, now 0x%llx\n",
 		       memory_limit);
 	}
@@ -184,9 +186,14 @@
 			"for crashkernel (System RAM: %ldMB)\n",
 			(unsigned long)(crash_size >> 20),
 			(unsigned long)(crashk_res.start >> 20),
-			(unsigned long)(memblock_phys_mem_size() >> 20));
+			(unsigned long)(total_mem_sz >> 20));
 
-	memblock_reserve(crashk_res.start, crash_size);
+	if (!memblock_is_region_memory(crashk_res.start, crash_size) ||
+	    memblock_reserve(crashk_res.start, crash_size)) {
+		pr_err("Failed to reserve memory for crashkernel!\n");
+		crashk_res.start = crashk_res.end = 0;
+		return;
+	}
 }
 
 int overlaps_crashkernel(unsigned long start, unsigned long size)
--- linux-4.4.0.orig/arch/powerpc/kernel/mce.c
+++ linux-4.4.0/arch/powerpc/kernel/mce.c
@@ -92,7 +92,8 @@
 	mce->in_use = 1;
 
 	mce->initiator = MCE_INITIATOR_CPU;
-	if (handled)
+	/* Mark it recovered if we have handled it and MSR(RI=1). */
+	if (handled && (regs->msr & MSR_RI))
 		mce->disposition = MCE_DISPOSITION_RECOVERED;
 	else
 		mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
@@ -204,6 +205,8 @@
 {
 	int index;
 
+	add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
+
 	/*
 	 * For now just print it to console.
 	 * TODO: log this error event to FSP or nvram.
--- linux-4.4.0.orig/arch/powerpc/kernel/misc_32.S
+++ linux-4.4.0/arch/powerpc/kernel/misc_32.S
@@ -313,7 +313,7 @@
 	lis	r3, KERNELBASE@h
 	iccci	0,r3
 #endif
-#elif CONFIG_FSL_BOOKE
+#elif defined(CONFIG_FSL_BOOKE)
 BEGIN_FTR_SECTION
 	mfspr   r3,SPRN_L1CSR0
 	ori     r3,r3,L1CSR0_CFI|L1CSR0_CLFC
--- linux-4.4.0.orig/arch/powerpc/kernel/misc_64.S
+++ linux-4.4.0/arch/powerpc/kernel/misc_64.S
@@ -66,7 +66,7 @@
  *   flush all bytes from start through stop-1 inclusive
  */
 
-_KPROBE(flush_icache_range)
+_KPROBE_TOC(flush_icache_range)
 BEGIN_FTR_SECTION
 	PURGE_PREFETCHED_INS
 	blr
@@ -117,7 +117,7 @@
  *
  *    flush all bytes from start to stop-1 inclusive
  */
-_GLOBAL(flush_dcache_range)
+_GLOBAL_TOC(flush_dcache_range)
 
 /*
  * Flush the data cache to memory 
@@ -701,31 +701,3 @@
 	li	r5,0
 	blr	/* image->start(physid, image->start, 0); */
 #endif /* CONFIG_KEXEC */
-
-#ifdef CONFIG_MODULES
-#if defined(_CALL_ELF) && _CALL_ELF == 2
-
-#ifdef CONFIG_MODVERSIONS
-.weak __crc_TOC.
-.section "___kcrctab+TOC.","a"
-.globl __kcrctab_TOC.
-__kcrctab_TOC.:
-	.llong	__crc_TOC.
-#endif
-
-/*
- * Export a fake .TOC. since both modpost and depmod will complain otherwise.
- * Both modpost and depmod strip the leading . so we do the same here.
- */
-.section "__ksymtab_strings","a"
-__kstrtab_TOC.:
-	.asciz "TOC."
-
-.section "___ksymtab+TOC.","a"
-/* This symbol name is important: it's used by modpost to find exported syms */
-.globl __ksymtab_TOC.
-__ksymtab_TOC.:
-	.llong 0 /* .value */
-	.llong __kstrtab_TOC.
-#endif /* ELFv2 */
-#endif /* MODULES */
--- linux-4.4.0.orig/arch/powerpc/kernel/module.c
+++ linux-4.4.0/arch/powerpc/kernel/module.c
@@ -67,7 +67,15 @@
 		do_feature_fixups(powerpc_firmware_features,
 				  (void *)sect->sh_addr,
 				  (void *)sect->sh_addr + sect->sh_size);
-#endif
+#endif /* CONFIG_PPC64 */
+
+#ifdef CONFIG_PPC_BARRIER_NOSPEC
+	sect = find_section(hdr, sechdrs, "__spec_barrier_fixup");
+	if (sect != NULL)
+		do_barrier_nospec_fixups_range(barrier_nospec_enabled,
+				  (void *)sect->sh_addr,
+				  (void *)sect->sh_addr + sect->sh_size);
+#endif /* CONFIG_PPC_BARRIER_NOSPEC */
 
 	sect = find_section(hdr, sechdrs, "__lwsync_fixup");
 	if (sect != NULL)
--- linux-4.4.0.orig/arch/powerpc/kernel/module_32.c
+++ linux-4.4.0/arch/powerpc/kernel/module_32.c
@@ -188,8 +188,8 @@
 
 	pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
 	/* Init, or core PLT? */
-	if (location >= mod->module_core
-	    && location < mod->module_core + mod->core_size)
+	if (location >= mod->core_layout.base
+	    && location < mod->core_layout.base + mod->core_layout.size)
 		entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
 	else
 		entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
@@ -296,7 +296,7 @@
 	}
 #ifdef CONFIG_DYNAMIC_FTRACE
 	module->arch.tramp =
-		do_plt_call(module->module_core,
+		do_plt_call(module->core_layout.base,
 			    (unsigned long)ftrace_caller,
 			    sechdrs, module);
 #endif
--- linux-4.4.0.orig/arch/powerpc/kernel/module_64.c
+++ linux-4.4.0/arch/powerpc/kernel/module_64.c
@@ -326,7 +326,10 @@
 		}
 }
 
-/* Undefined symbols which refer to .funcname, hack to funcname (or .TOC.) */
+/*
+ * Undefined symbols which refer to .funcname, hack to funcname. Make .TOC.
+ * seem to be defined (value set later).
+ */
 static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
 {
 	unsigned int i;
@@ -334,8 +337,11 @@
 	for (i = 1; i < numsyms; i++) {
 		if (syms[i].st_shndx == SHN_UNDEF) {
 			char *name = strtab + syms[i].st_name;
-			if (name[0] == '.')
-				memmove(name, name+1, strlen(name));
+			if (name[0] == '.') {
+				if (strcmp(name+1, "TOC.") == 0)
+					syms[i].st_shndx = SHN_ABS;
+				syms[i].st_name++;
+			}
 		}
 	}
 }
@@ -351,7 +357,7 @@
 	numsyms = sechdrs[symindex].sh_size / sizeof(Elf64_Sym);
 
 	for (i = 1; i < numsyms; i++) {
-		if (syms[i].st_shndx == SHN_UNDEF
+		if (syms[i].st_shndx == SHN_ABS
 		    && strcmp(strtab + syms[i].st_name, "TOC.") == 0)
 			return &syms[i];
 	}
@@ -635,6 +641,33 @@
 			 */
 			break;
 
+		case R_PPC64_ENTRY:
+			/*
+			 * Optimize ELFv2 large code model entry point if
+			 * the TOC is within 2GB range of current location.
+			 */
+			value = my_r2(sechdrs, me) - (unsigned long)location;
+			if (value + 0x80008000 > 0xffffffff)
+				break;
+			/*
+			 * Check for the large code model prolog sequence:
+		         *	ld r2, ...(r12)
+			 *	add r2, r2, r12
+			 */
+			if ((((uint32_t *)location)[0] & ~0xfffc)
+			    != 0xe84c0000)
+				break;
+			if (((uint32_t *)location)[1] != 0x7c426214)
+				break;
+			/*
+			 * If found, replace it with:
+			 *	addis r2, r12, (.TOC.-func)@ha
+			 *	addi r2, r12, (.TOC.-func)@l
+			 */
+			((uint32_t *)location)[0] = 0x3c4c0000 + PPC_HA(value);
+			((uint32_t *)location)[1] = 0x38420000 + PPC_LO(value);
+			break;
+
 		case R_PPC64_REL16_HA:
 			/* Subtract location pointer */
 			value -= (unsigned long)location;
--- linux-4.4.0.orig/arch/powerpc/kernel/msi.c
+++ linux-4.4.0/arch/powerpc/kernel/msi.c
@@ -34,5 +34,10 @@
 {
 	struct pci_controller *phb = pci_bus_to_host(dev->bus);
 
-	phb->controller_ops.teardown_msi_irqs(dev);
+	/*
+	 * We can be called even when arch_setup_msi_irqs() returns -ENOSYS,
+	 * so check the pointer again.
+	 */
+	if (phb->controller_ops.teardown_msi_irqs)
+		phb->controller_ops.teardown_msi_irqs(dev);
 }
--- linux-4.4.0.orig/arch/powerpc/kernel/nvram_64.c
+++ linux-4.4.0/arch/powerpc/kernel/nvram_64.c
@@ -969,7 +969,7 @@
 
 		/* Make partition a free partition */
 		part->header.signature = NVRAM_SIG_FREE;
-		strncpy(part->header.name, "wwwwwwwwwwww", 12);
+		memset(part->header.name, 'w', 12);
 		part->header.checksum = nvram_checksum(&part->header);
 		rc = nvram_write_header(part);
 		if (rc <= 0) {
@@ -987,8 +987,8 @@
 		}
 		if (prev) {
 			prev->header.length += part->header.length;
-			prev->header.checksum = nvram_checksum(&part->header);
-			rc = nvram_write_header(part);
+			prev->header.checksum = nvram_checksum(&prev->header);
+			rc = nvram_write_header(prev);
 			if (rc <= 0) {
 				printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc);
 				return rc;
--- linux-4.4.0.orig/arch/powerpc/kernel/paca.c
+++ linux-4.4.0/arch/powerpc/kernel/paca.c
@@ -206,6 +206,7 @@
 {
 	u64 limit;
 	int cpu;
+	int nr_cpus;
 
 	limit = ppc64_rma_size;
 
@@ -218,20 +219,32 @@
 	limit = min(0x10000000ULL, limit);
 #endif
 
-	paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids);
+	/*
+	 * Always align up the nr_cpu_ids to SMT threads and allocate
+	 * the paca. This will help us to prepare for a situation where
+	 * boot cpu id > nr_cpus_id. We will use the last nthreads
+	 * slots (nthreads == threads per core) to accommodate a core
+	 * that contains boot cpu thread.
+	 *
+	 * Do not change nr_cpu_ids value here. Let us do that in
+	 * early_init_dt_scan_cpus() where we know exact value
+	 * of threads per core.
+	 */
+	nr_cpus = _ALIGN_UP(nr_cpu_ids, MAX_SMT);
+	paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpus);
 
 	paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit));
 	memset(paca, 0, paca_size);
 
 	printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
-		paca_size, nr_cpu_ids, paca);
+		paca_size, nr_cpus, paca);
 
-	allocate_lppacas(nr_cpu_ids, limit);
+	allocate_lppacas(nr_cpus, limit);
 
-	allocate_slb_shadows(nr_cpu_ids, limit);
+	allocate_slb_shadows(nr_cpus, limit);
 
 	/* Can't use for_each_*_cpu, as they aren't functional yet */
-	for (cpu = 0; cpu < nr_cpu_ids; cpu++)
+	for (cpu = 0; cpu < nr_cpus; cpu++)
 		initialise_paca(&paca[cpu], cpu);
 }
 
--- linux-4.4.0.orig/arch/powerpc/kernel/pci-common.c
+++ linux-4.4.0/arch/powerpc/kernel/pci-common.c
@@ -41,11 +41,18 @@
 #include <asm/ppc-pci.h>
 #include <asm/eeh.h>
 
+/* hose_spinlock protects accesses to the the phb_bitmap. */
 static DEFINE_SPINLOCK(hose_spinlock);
 LIST_HEAD(hose_list);
 
-/* XXX kill that some day ... */
-static int global_phb_number;		/* Global phb counter */
+/* For dynamic PHB numbering on get_phb_number(): max number of PHBs. */
+#define MAX_PHBS 0x10000
+
+/*
+ * For dynamic PHB numbering: used/free PHBs tracking bitmap.
+ * Accesses to this bitmap should be protected by hose_spinlock.
+ */
+static DECLARE_BITMAP(phb_bitmap, MAX_PHBS);
 
 /* ISA Memory physical address */
 resource_size_t isa_mem_base;
@@ -64,6 +71,42 @@
 }
 EXPORT_SYMBOL(get_pci_dma_ops);
 
+/*
+ * This function should run under locking protection, specifically
+ * hose_spinlock.
+ */
+static int get_phb_number(struct device_node *dn)
+{
+	int ret, phb_id = -1;
+	u64 prop;
+
+	/*
+	 * Try fixed PHB numbering first, by checking archs and reading
+	 * the respective device-tree properties. Firstly, try powernv by
+	 * reading "ibm,opal-phbid", only present in OPAL environment.
+	 */
+	ret = of_property_read_u64(dn, "ibm,opal-phbid", &prop);
+	if (ret)
+		ret = of_property_read_u32_index(dn, "reg", 1, (u32 *)&prop);
+
+	if (!ret)
+		phb_id = (int)(prop & (MAX_PHBS - 1));
+
+	/* We need to be sure to not use the same PHB number twice. */
+	if ((phb_id >= 0) && !test_and_set_bit(phb_id, phb_bitmap))
+		return phb_id;
+
+	/*
+	 * If not pseries nor powernv, or if fixed PHB numbering tried to add
+	 * the same PHB number twice, then fallback to dynamic PHB numbering.
+	 */
+	phb_id = find_first_zero_bit(phb_bitmap, MAX_PHBS);
+	BUG_ON(phb_id >= MAX_PHBS);
+	set_bit(phb_id, phb_bitmap);
+
+	return phb_id;
+}
+
 struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
 {
 	struct pci_controller *phb;
@@ -72,7 +115,7 @@
 	if (phb == NULL)
 		return NULL;
 	spin_lock(&hose_spinlock);
-	phb->global_number = global_phb_number++;
+	phb->global_number = get_phb_number(dev);
 	list_add_tail(&phb->list_node, &hose_list);
 	spin_unlock(&hose_spinlock);
 	phb->dn = dev;
@@ -94,6 +137,11 @@
 void pcibios_free_controller(struct pci_controller *phb)
 {
 	spin_lock(&hose_spinlock);
+
+	/* Clear bit of phb_bitmap to allow reuse of this PHB number. */
+	if (phb->global_number < MAX_PHBS)
+		clear_bit(phb->global_number, phb_bitmap);
+
 	list_del(&phb->list_node);
 	spin_unlock(&hose_spinlock);
 
@@ -103,6 +151,42 @@
 EXPORT_SYMBOL_GPL(pcibios_free_controller);
 
 /*
+ * This function is used to call pcibios_free_controller()
+ * in a deferred manner: a callback from the PCI subsystem.
+ *
+ * _*DO NOT*_ call pcibios_free_controller() explicitly if
+ * this is used (or it may access an invalid *phb pointer).
+ *
+ * The callback occurs when all references to the root bus
+ * are dropped (e.g., child buses/devices and their users).
+ *
+ * It's called as .release_fn() of 'struct pci_host_bridge'
+ * which is associated with the 'struct pci_controller.bus'
+ * (root bus) - it expects .release_data to hold a pointer
+ * to 'struct pci_controller'.
+ *
+ * In order to use it, register .release_fn()/release_data
+ * like this:
+ *
+ * pci_set_host_bridge_release(bridge,
+ *                             pcibios_free_controller_deferred
+ *                             (void *) phb);
+ *
+ * e.g. in the pcibios_root_bridge_prepare() callback from
+ * pci_create_root_bus().
+ */
+void pcibios_free_controller_deferred(struct pci_host_bridge *bridge)
+{
+	struct pci_controller *phb = (struct pci_controller *)
+					 bridge->release_data;
+
+	pr_debug("domain %d, dynamic %d\n", phb->global_number, phb->is_dynamic);
+
+	pcibios_free_controller(phb);
+}
+EXPORT_SYMBOL_GPL(pcibios_free_controller_deferred);
+
+/*
  * The function is used to return the minimal alignment
  * for memory or I/O windows of the associated P2P bridge.
  * By default, 4KiB alignment for I/O windows and 1MiB for
@@ -226,6 +310,7 @@
 	}
 	return NULL;
 }
+EXPORT_SYMBOL(pci_find_hose_for_OF_device);
 
 /*
  * Reads the interrupt pin to determine if interrupt is use by card.
@@ -1469,9 +1554,15 @@
 		phb->controller_ops.disable_device(dev);
 }
 
+/* Before assuming too much here, take care to realize that we need sign
+ * extension from 32-bit pointers to 64-bit resource addresses to work.
+ */
 resource_size_t pcibios_io_space_offset(struct pci_controller *hose)
 {
-	return (unsigned long) hose->io_base_virt - _IO_BASE;
+	long vbase = (long)hose->io_base_virt;
+	long io_base = _IO_BASE;
+
+	return (resource_size_t)(vbase - io_base);
 }
 
 static void pcibios_setup_phb_resources(struct pci_controller *hose,
@@ -1585,6 +1676,7 @@
 {
 	return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
 }
+EXPORT_SYMBOL_GPL(early_find_capability);
 
 struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
 {
--- linux-4.4.0.orig/arch/powerpc/kernel/pci_32.c
+++ linux-4.4.0/arch/powerpc/kernel/pci_32.c
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/bootmem.h>
+#include <linux/syscalls.h>
 #include <linux/irq.h>
 #include <linux/list.h>
 #include <linux/of.h>
--- linux-4.4.0.orig/arch/powerpc/kernel/pci_of_scan.c
+++ linux-4.4.0/arch/powerpc/kernel/pci_of_scan.c
@@ -45,6 +45,8 @@
 	if (addr0 & 0x02000000) {
 		flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;
 		flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64;
+		if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
+			flags |= IORESOURCE_MEM_64;
 		flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M;
 		if (addr0 & 0x40000000)
 			flags |= IORESOURCE_PREFETCH
@@ -80,10 +82,16 @@
 	const __be32 *addrs;
 	u32 i;
 	int proplen;
+	bool mark_unset = false;
 
 	addrs = of_get_property(node, "assigned-addresses", &proplen);
-	if (!addrs)
-		return;
+	if (!addrs || !proplen) {
+		addrs = of_get_property(node, "reg", &proplen);
+		if (!addrs || !proplen)
+			return;
+		mark_unset = true;
+	}
+
 	pr_debug("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
 	for (; proplen >= 20; proplen -= 20, addrs += 5) {
 		flags = pci_parse_of_flags(of_read_number(addrs, 1), 0);
@@ -108,6 +116,8 @@
 			continue;
 		}
 		res->flags = flags;
+		if (mark_unset)
+			res->flags |= IORESOURCE_UNSET;
 		res->name = pci_name(dev);
 		region.start = base;
 		region.end = base + size - 1;
--- linux-4.4.0.orig/arch/powerpc/kernel/ppc_ksyms.c
+++ linux-4.4.0/arch/powerpc/kernel/ppc_ksyms.c
@@ -5,6 +5,10 @@
 #include <asm/switch_to.h>
 #include <asm/cacheflush.h>
 #include <asm/epapr_hcalls.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_BOOK3S_64
+#include <asm/book3s/64/kup-radix.h>
+#endif
 
 EXPORT_SYMBOL(flush_dcache_range);
 EXPORT_SYMBOL(flush_icache_range);
@@ -43,3 +47,9 @@
 #endif
 
 EXPORT_SYMBOL(current_stack_pointer);
+
+EXPORT_SYMBOL(__arch_clear_user);
+
+#ifdef CONFIG_PPC_BOOK3S_64
+EXPORT_SYMBOL(do_uaccess_flush);
+#endif
--- linux-4.4.0.orig/arch/powerpc/kernel/process.c
+++ linux-4.4.0/arch/powerpc/kernel/process.c
@@ -209,7 +209,8 @@
 	WARN_ON(preemptible());
 
 #ifdef CONFIG_SMP
-	if (current->thread.regs && (current->thread.regs->msr & MSR_VSX))
+	if (current->thread.regs &&
+	    (current->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)))
 		giveup_vsx(current);
 	else
 		giveup_vsx(NULL);	/* just enable vsx for kernel - force */
@@ -231,7 +232,7 @@
 {
 	if (tsk->thread.regs) {
 		preempt_disable();
-		if (tsk->thread.regs->msr & MSR_VSX) {
+		if (tsk->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)) {
 #ifdef CONFIG_SMP
 			BUG_ON(tsk != current);
 #endif
@@ -1239,6 +1240,16 @@
 		current->thread.regs = regs - 1;
 	}
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	/*
+	 * Clear any transactional state, we're exec()ing. The cause is
+	 * not important as there will never be a recheckpoint so it's not
+	 * user visible.
+	 */
+	if (MSR_TM_SUSPENDED(mfmsr()))
+		tm_reclaim_current(0);
+#endif
+
 	memset(regs->gpr, 0, sizeof(regs->gpr));
 	regs->ctr = 0;
 	regs->link = 0;
--- linux-4.4.0.orig/arch/powerpc/kernel/prom.c
+++ linux-4.4.0/arch/powerpc/kernel/prom.c
@@ -125,7 +125,7 @@
 		p = __va(memblock_alloc(size, PAGE_SIZE));
 		memcpy(p, initial_boot_params, size);
 		initial_boot_params = p;
-		DBG("Moved device tree to 0x%p\n", p);
+		DBG("Moved device tree to 0x%px\n", p);
 	}
 
 	DBG("<- move_device_tree\n");
@@ -148,23 +148,25 @@
 	unsigned long	cpu_features;	/* CPU_FTR_xxx bit */
 	unsigned long	mmu_features;	/* MMU_FTR_xxx bit */
 	unsigned int	cpu_user_ftrs;	/* PPC_FEATURE_xxx bit */
+	unsigned int	cpu_user_ftrs2;	/* PPC_FEATURE2_xxx bit */
 	unsigned char	pabyte;		/* byte number in ibm,pa-features */
 	unsigned char	pabit;		/* bit number (big-endian) */
 	unsigned char	invert;		/* if 1, pa bit set => clear feature */
 } ibm_pa_features[] __initdata = {
-	{0, 0, PPC_FEATURE_HAS_MMU,	0, 0, 0},
-	{0, 0, PPC_FEATURE_HAS_FPU,	0, 1, 0},
-	{CPU_FTR_CTRL, 0, 0,		0, 3, 0},
-	{CPU_FTR_NOEXECUTE, 0, 0,	0, 6, 0},
-	{CPU_FTR_NODSISRALIGN, 0, 0,	1, 1, 1},
-	{0, MMU_FTR_CI_LARGE_PAGE, 0,	1, 2, 0},
-	{CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
+	{0, 0, PPC_FEATURE_HAS_MMU, 0,		0, 0, 0},
+	{0, 0, PPC_FEATURE_HAS_FPU, 0,		0, 1, 0},
+	{CPU_FTR_CTRL, 0, 0, 0,			0, 3, 0},
+	{CPU_FTR_NOEXECUTE, 0, 0, 0,		0, 6, 0},
+	{CPU_FTR_NODSISRALIGN, 0, 0, 0,		1, 1, 1},
+	{0, MMU_FTR_CI_LARGE_PAGE, 0, 0,		1, 2, 0},
+	{CPU_FTR_REAL_LE, 0, PPC_FEATURE_TRUE_LE, 0, 5, 0, 0},
 	/*
-	 * If the kernel doesn't support TM (ie. CONFIG_PPC_TRANSACTIONAL_MEM=n),
-	 * we don't want to turn on CPU_FTR_TM here, so we use CPU_FTR_TM_COMP
-	 * which is 0 if the kernel doesn't support TM.
+	 * If the kernel doesn't support TM (ie CONFIG_PPC_TRANSACTIONAL_MEM=n),
+	 * we don't want to turn on TM here, so we use the *_COMP versions
+	 * which are 0 if the kernel doesn't support TM.
 	 */
-	{CPU_FTR_TM_COMP, 0, 0,		22, 0, 0},
+	{CPU_FTR_TM_COMP, 0, 0,
+	 PPC_FEATURE2_HTM_COMP|PPC_FEATURE2_HTM_NOSC_COMP, 22, 0, 0},
 };
 
 static void __init scan_features(unsigned long node, const unsigned char *ftrs,
@@ -195,10 +197,12 @@
 		if (bit ^ fp->invert) {
 			cur_cpu_spec->cpu_features |= fp->cpu_features;
 			cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs;
+			cur_cpu_spec->cpu_user_features2 |= fp->cpu_user_ftrs2;
 			cur_cpu_spec->mmu_features |= fp->mmu_features;
 		} else {
 			cur_cpu_spec->cpu_features &= ~fp->cpu_features;
 			cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs;
+			cur_cpu_spec->cpu_user_features2 &= ~fp->cpu_user_ftrs2;
 			cur_cpu_spec->mmu_features &= ~fp->mmu_features;
 		}
 	}
@@ -291,6 +295,29 @@
 	}
 }
 
+/*
+ * Adjust the logical id of a boot cpu to fall under nr_cpu_ids. Map it to
+ * last core slot in the allocated paca array.
+ *
+ * e.g. on SMT=8 system, kernel booted with nr_cpus=1 and boot cpu = 33,
+ * align nr_cpu_ids to MAX_SMT value 8. Allocate paca array to hold up-to
+ * MAX_SMT=8 cpus. Since boot cpu 33 is greater than nr_cpus (8), adjust
+ * its logical id so that new id becomes less than nr_cpu_ids. Make sure
+ * that boot cpu's new logical id is aligned to its thread id and falls
+ * under last nthreads slots available in paca array. In this case the
+ * boot cpu 33 is adjusted to new boot cpu id 1.
+ *
+ */
+static inline void adjust_boot_cpuid(int nthreads, int phys_id)
+{
+	boot_hw_cpuid = phys_id;
+	if (boot_cpuid >= nr_cpu_ids) {
+		boot_cpuid = (boot_cpuid % nthreads) + (nr_cpu_ids - nthreads);
+		pr_info("Adjusted logical boot cpu id: logical %d physical %d\n",
+			boot_cpuid, phys_id);
+	}
+}
+
 static int __init early_init_dt_scan_cpus(unsigned long node,
 					  const char *uname, int depth,
 					  void *data)
@@ -314,6 +341,18 @@
 
 	nthreads = len / sizeof(int);
 
+#ifdef CONFIG_SMP
+	/*
+	 * Now that we know threads per core lets align nr_cpu_ids to
+	 * correct SMT value.
+	 */
+	if (nr_cpu_ids % nthreads) {
+		nr_cpu_ids = _ALIGN_UP(nr_cpu_ids, nthreads);
+		pr_info("Aligned nr_cpus to SMT=%d, nr_cpu_ids = %d\n",
+				 nthreads, nr_cpu_ids);
+	}
+#endif
+
 	/*
 	 * Now see if any of these threads match our boot cpu.
 	 * NOTE: This must match the parsing done in smp_setup_cpu_maps.
@@ -352,7 +391,9 @@
 	DBG("boot cpu: logical %d physical %d\n", found,
 	    be32_to_cpu(intserv[found_thread]));
 	boot_cpuid = found;
-	set_hard_smp_processor_id(found, be32_to_cpu(intserv[found_thread]));
+	adjust_boot_cpuid(nthreads, be32_to_cpu(intserv[found_thread]));
+	set_hard_smp_processor_id(boot_cpuid,
+					be32_to_cpu(intserv[found_thread]));
 
 	/*
 	 * PAPR defines "logical" PVR values for cpus that
@@ -643,7 +684,7 @@
 {
 	phys_addr_t limit;
 
-	DBG(" -> early_init_devtree(%p)\n", params);
+	DBG(" -> early_init_devtree(%px)\n", params);
 
 	/* Too early to BUG_ON(), do it by hand */
 	if (!early_init_dt_verify(params))
@@ -703,7 +744,7 @@
 	memblock_allow_resize();
 	memblock_dump_all();
 
-	DBG("Phys. mem: %llx\n", memblock_phys_mem_size());
+	DBG("Phys. mem: %llx\n", (unsigned long long)memblock_phys_mem_size());
 
 	/* We may need to relocate the flat tree, do it now.
 	 * FIXME .. and the initrd too? */
--- linux-4.4.0.orig/arch/powerpc/kernel/prom_init.c
+++ linux-4.4.0/arch/powerpc/kernel/prom_init.c
@@ -655,6 +655,7 @@
 	W(0xffff0000), W(0x003e0000),	/* POWER6 */
 	W(0xffff0000), W(0x003f0000),	/* POWER7 */
 	W(0xffff0000), W(0x004b0000),	/* POWER8E */
+	W(0xffff0000), W(0x004c0000),   /* POWER8NVL */
 	W(0xffff0000), W(0x004d0000),	/* POWER8 */
 	W(0xffffffff), W(0x0f000004),	/* all 2.07-compliant */
 	W(0xffffffff), W(0x0f000003),	/* all 2.06-compliant */
@@ -677,7 +678,7 @@
 	W(0xffffffff),			/* virt_base */
 	W(0xffffffff),			/* virt_size */
 	W(0xffffffff),			/* load_base */
-	W(256),				/* 256MB min RMA */
+	W(512),				/* 512MB min RMA */
 	W(0xffffffff),			/* full client load */
 	0,				/* min RMA percentage of total RAM */
 	48,				/* max log_2(hash table size) */
@@ -693,7 +694,7 @@
 	OV4_MIN_ENT_CAP,		/* minimum VP entitled capacity */
 
 	/* option vector 5: PAPR/OF options */
-	VECTOR_LENGTH(18),		/* length */
+	VECTOR_LENGTH(21),		/* length */
 	0,				/* don't ignore, don't halt */
 	OV5_FEAT(OV5_LPAR) | OV5_FEAT(OV5_SPLPAR) | OV5_FEAT(OV5_LARGE_PAGES) |
 	OV5_FEAT(OV5_DRCONF_MEMORY) | OV5_FEAT(OV5_DONATE_DEDICATE_CPU) |
@@ -717,15 +718,18 @@
 	 * must match by the macro below. Update the definition if
 	 * the structure layout changes.
 	 */
-#define IBM_ARCH_VEC_NRCORES_OFFSET	125
+#define IBM_ARCH_VEC_NRCORES_OFFSET	133
 	W(NR_CPUS),			/* number of cores supported */
 	0,
 	0,
 	0,
 	0,
 	OV5_FEAT(OV5_PFO_HW_RNG) | OV5_FEAT(OV5_PFO_HW_ENCR) |
-	OV5_FEAT(OV5_PFO_HW_842),
-	OV5_FEAT(OV5_SUB_PROCESSORS),
+	OV5_FEAT(OV5_PFO_HW_842),				/* Byte 17 */
+	0,							/* Byte 18 */
+	0,							/* Byte 19 */
+	0,							/* Byte 20 */
+	OV5_FEAT(OV5_SUB_PROCESSORS),				/* Byte 21 */
 
 	/* option vector 6: IBM PAPR hints */
 	VECTOR_LENGTH(3),		/* length */
@@ -2660,6 +2664,9 @@
 
 	cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
 
+	if (!PHANDLE_VALID(cpu_pkg))
+		return;
+
 	prom_getprop(cpu_pkg, "reg", &rval, sizeof(rval));
 	prom.cpu = be32_to_cpu(rval);
 
--- linux-4.4.0.orig/arch/powerpc/kernel/ptrace.c
+++ linux-4.4.0/arch/powerpc/kernel/ptrace.c
@@ -33,6 +33,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/perf_event.h>
 #include <linux/context_tracking.h>
+#include <linux/nospec.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -220,6 +221,8 @@
  */
 int ptrace_get_reg(struct task_struct *task, int regno, unsigned long *data)
 {
+	unsigned int regs_max;
+
 	if ((task->thread.regs == NULL) || !data)
 		return -EIO;
 
@@ -231,7 +234,9 @@
 	if (regno == PT_DSCR)
 		return get_user_dscr(task, data);
 
-	if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) {
+	regs_max = sizeof(struct pt_regs) / sizeof(unsigned long);
+	if (regno < regs_max) {
+		regno = array_index_nospec(regno, regs_max);
 		*data = ((unsigned long *)task->thread.regs)[regno];
 		return 0;
 	}
@@ -255,6 +260,7 @@
 		return set_user_dscr(task, data);
 
 	if (regno <= PT_MAX_PUT_REG) {
+		regno = array_index_nospec(regno, PT_MAX_PUT_REG + 1);
 		((unsigned long *)task->thread.regs)[regno] = data;
 		return 0;
 	}
@@ -376,7 +382,7 @@
 
 #else
 	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
-		     offsetof(struct thread_fp_state, fpr[32][0]));
+		     offsetof(struct thread_fp_state, fpr[32]));
 
 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 				   &target->thread.fp_state, 0, -1);
@@ -404,7 +410,7 @@
 	return 0;
 #else
 	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
-		     offsetof(struct thread_fp_state, fpr[32][0]));
+		     offsetof(struct thread_fp_state, fpr[32]));
 
 	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 				  &target->thread.fp_state, 0, -1);
@@ -1004,6 +1010,7 @@
 	/* Create a new breakpoint request if one doesn't exist already */
 	hw_breakpoint_init(&attr);
 	attr.bp_addr = hw_brk.address;
+	attr.bp_len = 8;
 	arch_bp_generic_fields(hw_brk.type,
 			       &attr.bp_type);
 
--- linux-4.4.0.orig/arch/powerpc/kernel/rtas.c
+++ linux-4.4.0/arch/powerpc/kernel/rtas.c
@@ -857,15 +857,17 @@
 		return 0;
 
 	for_each_cpu(cpu, cpus) {
+		struct device *dev = get_cpu_device(cpu);
+
 		switch (state) {
 		case DOWN:
-			cpuret = cpu_down(cpu);
+			cpuret = device_offline(dev);
 			break;
 		case UP:
-			cpuret = cpu_up(cpu);
+			cpuret = device_online(dev);
 			break;
 		}
-		if (cpuret) {
+		if (cpuret < 0) {
 			pr_debug("%s: cpu_%s for cpu#%d returned %d.\n",
 					__func__,
 					((state == UP) ? "up" : "down"),
@@ -954,6 +956,8 @@
 	data.token = rtas_token("ibm,suspend-me");
 	data.complete = &done;
 
+	lock_device_hotplug();
+
 	/* All present CPUs must be online */
 	cpumask_andnot(offline_mask, cpu_present_mask, cpu_online_mask);
 	cpuret = rtas_online_cpus_mask(offline_mask);
@@ -963,6 +967,7 @@
 		goto out;
 	}
 
+	cpu_hotplug_disable();
 	stop_topology_update();
 
 	/* Call function on all CPUs.  One of us will make the
@@ -977,6 +982,7 @@
 		printk(KERN_ERR "Error doing global join\n");
 
 	start_topology_update();
+	cpu_hotplug_enable();
 
 	/* Take down CPUs not online prior to suspend */
 	cpuret = rtas_offline_cpus_mask(offline_mask);
@@ -985,6 +991,7 @@
 				__func__);
 
 out:
+	unlock_device_hotplug();
 	free_cpumask_var(offline_mask);
 	return atomic_read(&data.error);
 }
@@ -1032,6 +1039,147 @@
 	return NULL;
 }
 
+#ifdef CONFIG_PPC_RTAS_FILTER
+
+/*
+ * The sys_rtas syscall, as originally designed, allows root to pass
+ * arbitrary physical addresses to RTAS calls. A number of RTAS calls
+ * can be abused to write to arbitrary memory and do other things that
+ * are potentially harmful to system integrity, and thus should only
+ * be used inside the kernel and not exposed to userspace.
+ *
+ * All known legitimate users of the sys_rtas syscall will only ever
+ * pass addresses that fall within the RMO buffer, and use a known
+ * subset of RTAS calls.
+ *
+ * Accordingly, we filter RTAS requests to check that the call is
+ * permitted, and that provided pointers fall within the RMO buffer.
+ * The rtas_filters list contains an entry for each permitted call,
+ * with the indexes of the parameters which are expected to contain
+ * addresses and sizes of buffers allocated inside the RMO buffer.
+ */
+struct rtas_filter {
+	const char *name;
+	int token;
+	/* Indexes into the args buffer, -1 if not used */
+	int buf_idx1;
+	int size_idx1;
+	int buf_idx2;
+	int size_idx2;
+
+	int fixed_size;
+};
+
+static struct rtas_filter rtas_filters[] __ro_after_init = {
+	{ "ibm,activate-firmware", -1, -1, -1, -1, -1 },
+	{ "ibm,configure-connector", -1, 0, -1, 1, -1, 4096 },	/* Special cased */
+	{ "display-character", -1, -1, -1, -1, -1 },
+	{ "ibm,display-message", -1, 0, -1, -1, -1 },
+	{ "ibm,errinjct", -1, 2, -1, -1, -1, 1024 },
+	{ "ibm,close-errinjct", -1, -1, -1, -1, -1 },
+	{ "ibm,open-errinjct", -1, -1, -1, -1, -1 },
+	{ "ibm,get-config-addr-info2", -1, -1, -1, -1, -1 },
+	{ "ibm,get-dynamic-sensor-state", -1, 1, -1, -1, -1 },
+	{ "ibm,get-indices", -1, 2, 3, -1, -1 },
+	{ "get-power-level", -1, -1, -1, -1, -1 },
+	{ "get-sensor-state", -1, -1, -1, -1, -1 },
+	{ "ibm,get-system-parameter", -1, 1, 2, -1, -1 },
+	{ "get-time-of-day", -1, -1, -1, -1, -1 },
+	{ "ibm,get-vpd", -1, 0, -1, 1, 2 },
+	{ "ibm,lpar-perftools", -1, 2, 3, -1, -1 },
+	{ "ibm,platform-dump", -1, 4, 5, -1, -1 },
+	{ "ibm,read-slot-reset-state", -1, -1, -1, -1, -1 },
+	{ "ibm,scan-log-dump", -1, 0, 1, -1, -1 },
+	{ "ibm,set-dynamic-indicator", -1, 2, -1, -1, -1 },
+	{ "ibm,set-eeh-option", -1, -1, -1, -1, -1 },
+	{ "set-indicator", -1, -1, -1, -1, -1 },
+	{ "set-power-level", -1, -1, -1, -1, -1 },
+	{ "set-time-for-power-on", -1, -1, -1, -1, -1 },
+	{ "ibm,set-system-parameter", -1, 1, -1, -1, -1 },
+	{ "set-time-of-day", -1, -1, -1, -1, -1 },
+	{ "ibm,suspend-me", -1, -1, -1, -1, -1 },
+	{ "ibm,update-nodes", -1, 0, -1, -1, -1, 4096 },
+	{ "ibm,update-properties", -1, 0, -1, -1, -1, 4096 },
+	{ "ibm,physical-attestation", -1, 0, 1, -1, -1 },
+};
+
+static bool in_rmo_buf(u32 base, u32 end)
+{
+	return base >= rtas_rmo_buf &&
+		base < (rtas_rmo_buf + RTAS_RMOBUF_MAX) &&
+		base <= end &&
+		end >= rtas_rmo_buf &&
+		end < (rtas_rmo_buf + RTAS_RMOBUF_MAX);
+}
+
+static bool block_rtas_call(int token, int nargs,
+			    struct rtas_args *args)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rtas_filters); i++) {
+		struct rtas_filter *f = &rtas_filters[i];
+		u32 base, size, end;
+
+		if (token != f->token)
+			continue;
+
+		if (f->buf_idx1 != -1) {
+			base = be32_to_cpu(args->args[f->buf_idx1]);
+			if (f->size_idx1 != -1)
+				size = be32_to_cpu(args->args[f->size_idx1]);
+			else if (f->fixed_size)
+				size = f->fixed_size;
+			else
+				size = 1;
+
+			end = base + size - 1;
+			if (!in_rmo_buf(base, end))
+				goto err;
+		}
+
+		if (f->buf_idx2 != -1) {
+			base = be32_to_cpu(args->args[f->buf_idx2]);
+			if (f->size_idx2 != -1)
+				size = be32_to_cpu(args->args[f->size_idx2]);
+			else if (f->fixed_size)
+				size = f->fixed_size;
+			else
+				size = 1;
+			end = base + size - 1;
+
+			/*
+			 * Special case for ibm,configure-connector where the
+			 * address can be 0
+			 */
+			if (!strcmp(f->name, "ibm,configure-connector") &&
+			    base == 0)
+				return false;
+
+			if (!in_rmo_buf(base, end))
+				goto err;
+		}
+
+		return false;
+	}
+
+err:
+	pr_err_ratelimited("sys_rtas: RTAS call blocked - exploit attempt?\n");
+	pr_err_ratelimited("sys_rtas: token=0x%x, nargs=%d (called by %s)\n",
+			   token, nargs, current->comm);
+	return true;
+}
+
+#else
+
+static bool block_rtas_call(int token, int nargs,
+			    struct rtas_args *args)
+{
+	return false;
+}
+
+#endif /* CONFIG_PPC_RTAS_FILTER */
+
 /* We assume to be passed big endian arguments */
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 {
@@ -1069,6 +1217,9 @@
 	args.rets = &args.args[nargs];
 	memset(args.rets, 0, nret * sizeof(rtas_arg_t));
 
+	if (block_rtas_call(token, nargs, &args))
+		return -EINVAL;
+
 	/* Need to handle ibm,suspend_me call specially */
 	if (token == ibm_suspend_me_token) {
 
@@ -1128,6 +1279,9 @@
 void __init rtas_initialize(void)
 {
 	unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
+#ifdef CONFIG_PPC_RTAS_FILTER
+	int i;
+#endif
 
 	/* Get RTAS dev node and fill up our "rtas" structure with infos
 	 * about it.
@@ -1167,6 +1321,12 @@
 #ifdef CONFIG_RTAS_ERROR_LOGGING
 	rtas_last_error_token = rtas_token("rtas-last-error");
 #endif
+
+#ifdef CONFIG_PPC_RTAS_FILTER
+	for (i = 0; i < ARRAY_SIZE(rtas_filters); i++) {
+		rtas_filters[i].token = rtas_token(rtas_filters[i].name);
+	}
+#endif
 }
 
 int __init early_init_dt_scan_rtas(unsigned long node,
--- linux-4.4.0.orig/arch/powerpc/kernel/security.c
+++ linux-4.4.0/arch/powerpc/kernel/security.c
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Security related flags and so on.
+//
+// Copyright 2018, Michael Ellerman, IBM Corporation.
+
+#include <linux/cpu.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/seq_buf.h>
+
+#include <asm/debug.h>
+#include <asm/asm-prototypes.h>
+#include <asm/code-patching.h>
+#include <asm/security_features.h>
+#include <asm/setup.h>
+
+
+unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT;
+
+enum count_cache_flush_type {
+	COUNT_CACHE_FLUSH_NONE	= 0x1,
+	COUNT_CACHE_FLUSH_SW	= 0x2,
+	COUNT_CACHE_FLUSH_HW	= 0x4,
+};
+static enum count_cache_flush_type count_cache_flush_type = COUNT_CACHE_FLUSH_NONE;
+static bool link_stack_flush_enabled;
+
+bool barrier_nospec_enabled;
+static bool no_nospec;
+static bool btb_flush_enabled;
+#if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64)
+static bool no_spectrev2;
+#endif
+
+static void enable_barrier_nospec(bool enable)
+{
+	barrier_nospec_enabled = enable;
+	do_barrier_nospec_fixups(enable);
+}
+
+void setup_barrier_nospec(void)
+{
+	bool enable;
+
+	/*
+	 * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well.
+	 * But there's a good reason not to. The two flags we check below are
+	 * both are enabled by default in the kernel, so if the hcall is not
+	 * functional they will be enabled.
+	 * On a system where the host firmware has been updated (so the ori
+	 * functions as a barrier), but on which the hypervisor (KVM/Qemu) has
+	 * not been updated, we would like to enable the barrier. Dropping the
+	 * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is
+	 * we potentially enable the barrier on systems where the host firmware
+	 * is not updated, but that's harmless as it's a no-op.
+	 */
+	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
+		 security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR);
+
+	if (!no_nospec && !cpu_mitigations_off())
+		enable_barrier_nospec(enable);
+}
+
+static int __init handle_nospectre_v1(char *p)
+{
+	no_nospec = true;
+
+	return 0;
+}
+early_param("nospectre_v1", handle_nospectre_v1);
+
+#ifdef CONFIG_DEBUG_FS
+static int barrier_nospec_set(void *data, u64 val)
+{
+	switch (val) {
+	case 0:
+	case 1:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!!val == !!barrier_nospec_enabled)
+		return 0;
+
+	enable_barrier_nospec(!!val);
+
+	return 0;
+}
+
+static int barrier_nospec_get(void *data, u64 *val)
+{
+	*val = barrier_nospec_enabled ? 1 : 0;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_barrier_nospec,
+			barrier_nospec_get, barrier_nospec_set, "%llu\n");
+
+static __init int barrier_nospec_debugfs_init(void)
+{
+	debugfs_create_file("barrier_nospec", 0600, powerpc_debugfs_root, NULL,
+			    &fops_barrier_nospec);
+	return 0;
+}
+device_initcall(barrier_nospec_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
+
+#if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3S_64)
+static int __init handle_nospectre_v2(char *p)
+{
+	no_spectrev2 = true;
+
+	return 0;
+}
+early_param("nospectre_v2", handle_nospectre_v2);
+#endif /* CONFIG_PPC_FSL_BOOK3E || CONFIG_PPC_BOOK3S_64 */
+
+#ifdef CONFIG_PPC_FSL_BOOK3E
+void setup_spectre_v2(void)
+{
+	if (no_spectrev2 || cpu_mitigations_off())
+		do_btb_flush_fixups();
+	else
+		btb_flush_enabled = true;
+}
+#endif /* CONFIG_PPC_FSL_BOOK3E */
+
+#ifdef CONFIG_PPC_BOOK3S_64
+ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	bool thread_priv;
+
+	thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV);
+
+	if (rfi_flush) {
+		struct seq_buf s;
+		seq_buf_init(&s, buf, PAGE_SIZE - 1);
+
+		seq_buf_printf(&s, "Mitigation: RFI Flush");
+		if (thread_priv)
+			seq_buf_printf(&s, ", L1D private per thread");
+
+		seq_buf_printf(&s, "\n");
+
+		return s.len;
+	}
+
+	if (thread_priv)
+		return sprintf(buf, "Vulnerable: L1D private per thread\n");
+
+	if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) &&
+	    !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR))
+		return sprintf(buf, "Not affected\n");
+
+	return sprintf(buf, "Vulnerable\n");
+}
+
+ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_meltdown(dev, attr, buf);
+}
+#endif
+
+ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct seq_buf s;
+
+	seq_buf_init(&s, buf, PAGE_SIZE - 1);
+
+	if (security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) {
+		if (barrier_nospec_enabled)
+			seq_buf_printf(&s, "Mitigation: __user pointer sanitization");
+		else
+			seq_buf_printf(&s, "Vulnerable");
+
+		if (security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31))
+			seq_buf_printf(&s, ", ori31 speculation barrier enabled");
+
+		seq_buf_printf(&s, "\n");
+	} else
+		seq_buf_printf(&s, "Not affected\n");
+
+	return s.len;
+}
+
+ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct seq_buf s;
+	bool bcs, ccd;
+
+	seq_buf_init(&s, buf, PAGE_SIZE - 1);
+
+	bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED);
+	ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED);
+
+	if (bcs || ccd) {
+		seq_buf_printf(&s, "Mitigation: ");
+
+		if (bcs)
+			seq_buf_printf(&s, "Indirect branch serialisation (kernel only)");
+
+		if (bcs && ccd)
+			seq_buf_printf(&s, ", ");
+
+		if (ccd)
+			seq_buf_printf(&s, "Indirect branch cache disabled");
+
+		if (link_stack_flush_enabled)
+			seq_buf_printf(&s, ", Software link stack flush");
+
+	} else if (count_cache_flush_type != COUNT_CACHE_FLUSH_NONE) {
+		seq_buf_printf(&s, "Mitigation: Software count cache flush");
+
+		if (count_cache_flush_type == COUNT_CACHE_FLUSH_HW)
+			seq_buf_printf(&s, " (hardware accelerated)");
+
+		if (link_stack_flush_enabled)
+			seq_buf_printf(&s, ", Software link stack flush");
+
+	} else if (btb_flush_enabled) {
+		seq_buf_printf(&s, "Mitigation: Branch predictor state flush");
+	} else {
+		seq_buf_printf(&s, "Vulnerable");
+	}
+
+	seq_buf_printf(&s, "\n");
+
+	return s.len;
+}
+
+#ifdef CONFIG_PPC_BOOK3S_64
+/*
+ * Store-forwarding barrier support.
+ */
+
+static enum stf_barrier_type stf_enabled_flush_types;
+static bool no_stf_barrier;
+bool stf_barrier;
+
+static int __init handle_no_stf_barrier(char *p)
+{
+	pr_info("stf-barrier: disabled on command line.");
+	no_stf_barrier = true;
+	return 0;
+}
+
+early_param("no_stf_barrier", handle_no_stf_barrier);
+
+/* This is the generic flag used by other architectures */
+static int __init handle_ssbd(char *p)
+{
+	if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) {
+		/* Until firmware tells us, we have the barrier with auto */
+		return 0;
+	} else if (strncmp(p, "off", 3) == 0) {
+		handle_no_stf_barrier(NULL);
+		return 0;
+	} else
+		return 1;
+
+	return 0;
+}
+early_param("spec_store_bypass_disable", handle_ssbd);
+
+/* This is the generic flag used by other architectures */
+static int __init handle_no_ssbd(char *p)
+{
+	handle_no_stf_barrier(NULL);
+	return 0;
+}
+early_param("nospec_store_bypass_disable", handle_no_ssbd);
+
+static void stf_barrier_enable(bool enable)
+{
+	if (enable)
+		do_stf_barrier_fixups(stf_enabled_flush_types);
+	else
+		do_stf_barrier_fixups(STF_BARRIER_NONE);
+
+	stf_barrier = enable;
+}
+
+void setup_stf_barrier(void)
+{
+	enum stf_barrier_type type;
+	bool enable, hv;
+
+	hv = cpu_has_feature(CPU_FTR_HVMODE);
+
+	/* Default to fallback in case fw-features are not available */
+	if (cpu_has_feature(CPU_FTR_ARCH_207S))
+		type = STF_BARRIER_SYNC_ORI;
+	else if (cpu_has_feature(CPU_FTR_ARCH_206))
+		type = STF_BARRIER_FALLBACK;
+	else
+		type = STF_BARRIER_NONE;
+
+	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
+		(security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) ||
+		 (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv));
+
+	if (type == STF_BARRIER_FALLBACK) {
+		pr_info("stf-barrier: fallback barrier available\n");
+	} else if (type == STF_BARRIER_SYNC_ORI) {
+		pr_info("stf-barrier: hwsync barrier available\n");
+	} else if (type == STF_BARRIER_EIEIO) {
+		pr_info("stf-barrier: eieio barrier available\n");
+	}
+
+	stf_enabled_flush_types = type;
+
+	if (!no_stf_barrier && !cpu_mitigations_off())
+		stf_barrier_enable(enable);
+}
+
+ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) {
+		const char *type;
+		switch (stf_enabled_flush_types) {
+		case STF_BARRIER_EIEIO:
+			type = "eieio";
+			break;
+		case STF_BARRIER_SYNC_ORI:
+			type = "hwsync";
+			break;
+		case STF_BARRIER_FALLBACK:
+			type = "fallback";
+			break;
+		default:
+			type = "unknown";
+		}
+		return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type);
+	}
+
+	if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) &&
+	    !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR))
+		return sprintf(buf, "Not affected\n");
+
+	return sprintf(buf, "Vulnerable\n");
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int stf_barrier_set(void *data, u64 val)
+{
+	bool enable;
+
+	if (val == 1)
+		enable = true;
+	else if (val == 0)
+		enable = false;
+	else
+		return -EINVAL;
+
+	/* Only do anything if we're changing state */
+	if (enable != stf_barrier)
+		stf_barrier_enable(enable);
+
+	return 0;
+}
+
+static int stf_barrier_get(void *data, u64 *val)
+{
+	*val = stf_barrier ? 1 : 0;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n");
+
+static __init int stf_barrier_debugfs_init(void)
+{
+	debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier);
+	return 0;
+}
+device_initcall(stf_barrier_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
+
+static void no_count_cache_flush(void)
+{
+	count_cache_flush_type = COUNT_CACHE_FLUSH_NONE;
+	pr_info("count-cache-flush: software flush disabled.\n");
+}
+
+static void toggle_count_cache_flush(bool enable)
+{
+	if (!security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE) &&
+	    !security_ftr_enabled(SEC_FTR_FLUSH_LINK_STACK))
+		enable = false;
+
+	if (!enable) {
+		patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP);
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+		patch_instruction_site(&patch__call_kvm_flush_link_stack, PPC_INST_NOP);
+#endif
+		pr_info("link-stack-flush: software flush disabled.\n");
+		link_stack_flush_enabled = false;
+		no_count_cache_flush();
+		return;
+	}
+
+	// This enables the branch from _switch to flush_count_cache
+	patch_branch_site(&patch__call_flush_count_cache,
+			  (u64)&flush_count_cache, BRANCH_SET_LINK);
+
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+	// This enables the branch from guest_exit_cont to kvm_flush_link_stack
+	patch_branch_site(&patch__call_kvm_flush_link_stack,
+			  (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
+#endif
+
+	pr_info("link-stack-flush: software flush enabled.\n");
+	link_stack_flush_enabled = true;
+
+	// If we just need to flush the link stack, patch an early return
+	if (!security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) {
+		patch_instruction_site(&patch__flush_link_stack_return, PPC_INST_BLR);
+		no_count_cache_flush();
+		return;
+	}
+
+	if (!security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) {
+		count_cache_flush_type = COUNT_CACHE_FLUSH_SW;
+		pr_info("count-cache-flush: full software flush sequence enabled.\n");
+		return;
+	}
+
+	patch_instruction_site(&patch__flush_count_cache_return, PPC_INST_BLR);
+	count_cache_flush_type = COUNT_CACHE_FLUSH_HW;
+	pr_info("count-cache-flush: hardware assisted flush sequence enabled\n");
+}
+
+void setup_count_cache_flush(void)
+{
+	bool enable = true;
+
+	if (no_spectrev2 || cpu_mitigations_off()) {
+		if (security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED) ||
+		    security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED))
+			pr_warn("Spectre v2 mitigations not fully under software control, can't disable\n");
+
+		enable = false;
+	}
+
+	/*
+	 * There's no firmware feature flag/hypervisor bit to tell us we need to
+	 * flush the link stack on context switch. So we set it here if we see
+	 * either of the Spectre v2 mitigations that aim to protect userspace.
+	 */
+	if (security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED) ||
+	    security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE))
+		security_ftr_set(SEC_FTR_FLUSH_LINK_STACK);
+
+	toggle_count_cache_flush(enable);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int count_cache_flush_set(void *data, u64 val)
+{
+	bool enable;
+
+	if (val == 1)
+		enable = true;
+	else if (val == 0)
+		enable = false;
+	else
+		return -EINVAL;
+
+	toggle_count_cache_flush(enable);
+
+	return 0;
+}
+
+static int count_cache_flush_get(void *data, u64 *val)
+{
+	if (count_cache_flush_type == COUNT_CACHE_FLUSH_NONE)
+		*val = 0;
+	else
+		*val = 1;
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_count_cache_flush, count_cache_flush_get,
+			count_cache_flush_set, "%llu\n");
+
+static __init int count_cache_flush_debugfs_init(void)
+{
+	debugfs_create_file("count_cache_flush", 0600, powerpc_debugfs_root,
+			    NULL, &fops_count_cache_flush);
+	return 0;
+}
+device_initcall(count_cache_flush_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
+#endif /* CONFIG_PPC_BOOK3S_64 */
--- linux-4.4.0.orig/arch/powerpc/kernel/setup-common.c
+++ linux-4.4.0/arch/powerpc/kernel/setup-common.c
@@ -77,6 +77,7 @@
 EXPORT_SYMBOL(machine_id);
 
 int boot_cpuid = -1;
+int boot_hw_cpuid = -1;
 EXPORT_SYMBOL_GPL(boot_cpuid);
 
 unsigned long klimit = (unsigned long) _end;
@@ -217,14 +218,6 @@
 	unsigned short maj;
 	unsigned short min;
 
-	/* We only show online cpus: disable preempt (overzealous, I
-	 * knew) to prevent cpu going down. */
-	preempt_disable();
-	if (!cpu_online(cpu_id)) {
-		preempt_enable();
-		return 0;
-	}
-
 #ifdef CONFIG_SMP
 	pvr = per_cpu(cpu_pvr, cpu_id);
 #else
@@ -329,9 +322,6 @@
 #ifdef CONFIG_SMP
 	seq_printf(m, "\n");
 #endif
-
-	preempt_enable();
-
 	/* If this is the last cpu, print the summary */
 	if (cpumask_next(cpu_id, cpu_online_mask) >= nr_cpu_ids)
 		show_cpuinfo_summary(m);
@@ -444,6 +434,7 @@
 	struct device_node *dn = NULL;
 	int cpu = 0;
 	int nthreads = 1;
+	bool boot_cpu_added = false;
 
 	DBG("smp_setup_cpu_maps()\n");
 
@@ -470,6 +461,24 @@
 		}
 
 		nthreads = len / sizeof(int);
+		/*
+		 * If boot cpu hasn't been added to paca and there are only
+		 * last nthreads slots available in paca array then wait
+		 * for boot cpu to show up.
+		 */
+		if (!boot_cpu_added && (cpu + nthreads) >= nr_cpu_ids) {
+			int found = 0;
+
+			DBG("Holding last nthreads paca slots for boot cpu\n");
+			for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) {
+				if (boot_hw_cpuid == be32_to_cpu(intserv[j])) {
+					found = 1;
+					break;
+				}
+			}
+			if (!found)
+				continue;
+		}
 
 		for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) {
 			bool avail;
@@ -485,6 +494,11 @@
 			set_cpu_present(cpu, avail);
 			set_hard_smp_processor_id(cpu, be32_to_cpu(intserv[j]));
 			set_cpu_possible(cpu, true);
+			if (boot_hw_cpuid == be32_to_cpu(intserv[j])) {
+				DBG("Boot cpu %d (hard id %d) added to paca\n",
+				    cpu, be32_to_cpu(intserv[j]));
+				boot_cpu_added = true;
+			}
 			cpu++;
 		}
 	}
@@ -663,28 +677,6 @@
 }
 EXPORT_SYMBOL(check_legacy_ioport);
 
-static int ppc_panic_event(struct notifier_block *this,
-                             unsigned long event, void *ptr)
-{
-	/*
-	 * If firmware-assisted dump has been registered then trigger
-	 * firmware-assisted dump and let firmware handle everything else.
-	 */
-	crash_fadump(NULL, ptr);
-	ppc_md.panic(ptr);  /* May not return */
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block ppc_panic_block = {
-	.notifier_call = ppc_panic_event,
-	.priority = INT_MIN /* may not return; must be done last */
-};
-
-void __init setup_panic(void)
-{
-	atomic_notifier_chain_register(&panic_notifier_list, &ppc_panic_block);
-}
-
 #ifdef CONFIG_CHECK_CACHE_COHERENCY
 /*
  * For platforms that have configurable cache-coherency.  This function
--- linux-4.4.0.orig/arch/powerpc/kernel/setup_32.c
+++ linux-4.4.0/arch/powerpc/kernel/setup_32.c
@@ -299,9 +299,6 @@
 	if (cpu_has_feature(CPU_FTR_UNIFIED_ID_CACHE))
 		ucache_bsize = icache_bsize = dcache_bsize;
 
-	if (ppc_md.panic)
-		setup_panic();
-
 	init_mm.start_code = (unsigned long)_stext;
 	init_mm.end_code = (unsigned long) _etext;
 	init_mm.end_data = (unsigned long) _edata;
@@ -322,6 +319,9 @@
 		ppc_md.setup_arch();
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
+	setup_barrier_nospec();
+	setup_spectre_v2();
+
 	paging_init();
 
 	/* Initialize the MMU context management stuff */
--- linux-4.4.0.orig/arch/powerpc/kernel/setup_64.c
+++ linux-4.4.0/arch/powerpc/kernel/setup_64.c
@@ -38,6 +38,8 @@
 #include <linux/hugetlb.h>
 #include <linux/memory.h>
 #include <linux/nmi.h>
+#include <linux/debugfs.h>
+#include <linux/cpu.h>
 
 #include <asm/io.h>
 #include <asm/kdump.h>
@@ -220,6 +222,15 @@
 		unsigned long lpcr = mfspr(SPRN_LPCR);
 		mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
 	}
+
+	/*
+	 * Fixup HFSCR:TM based on CPU features. The bit is set by our
+	 * early asm init because at that point we haven't updated our
+	 * CPU features from firmware and device-tree. Here we have,
+	 * so let's do it.
+	 */
+	if (cpu_has_feature(CPU_FTR_HVMODE) && !cpu_has_feature(CPU_FTR_TM_COMP))
+		mtspr(SPRN_HFSCR, mfspr(SPRN_HFSCR) & ~HFSCR_TM);
 }
 
 /*
@@ -700,9 +711,6 @@
 	dcache_bsize = ppc64_caches.dline_size;
 	icache_bsize = ppc64_caches.iline_size;
 
-	if (ppc_md.panic)
-		setup_panic();
-
 	init_mm.start_code = (unsigned long)_stext;
 	init_mm.end_code = (unsigned long) _etext;
 	init_mm.end_data = (unsigned long) _edata;
@@ -726,6 +734,9 @@
 	if (ppc_md.setup_arch)
 		ppc_md.setup_arch();
 
+	setup_barrier_nospec();
+	setup_spectre_v2();
+
 	paging_init();
 
 	/* Initialize the MMU context management stuff */
@@ -826,3 +837,281 @@
 }
 early_initcall(disable_hardlockup_detector);
 #endif
+
+#ifdef CONFIG_PPC_BOOK3S_64
+static enum l1d_flush_type enabled_flush_types;
+static void *l1d_flush_fallback_area;
+static bool no_rfi_flush;
+static bool no_entry_flush;
+static bool no_uaccess_flush;
+bool rfi_flush;
+bool entry_flush;
+bool uaccess_flush;
+DEFINE_STATIC_KEY_FALSE(uaccess_flush_key);
+EXPORT_SYMBOL(uaccess_flush_key);
+
+static int __init handle_no_rfi_flush(char *p)
+{
+	pr_info("rfi-flush: disabled on command line.");
+	no_rfi_flush = true;
+	return 0;
+}
+early_param("no_rfi_flush", handle_no_rfi_flush);
+
+static int __init handle_no_entry_flush(char *p)
+{
+	pr_info("entry-flush: disabled on command line.");
+	no_entry_flush = true;
+	return 0;
+}
+early_param("no_entry_flush", handle_no_entry_flush);
+
+static int __init handle_no_uaccess_flush(char *p)
+{
+	pr_info("uaccess-flush: disabled on command line.");
+	no_uaccess_flush = true;
+	return 0;
+}
+early_param("no_uaccess_flush", handle_no_uaccess_flush);
+
+/*
+ * The RFI flush is not KPTI, but because users will see doco that says to use
+ * nopti we hijack that option here to also disable the RFI flush.
+ */
+static int __init handle_no_pti(char *p)
+{
+	pr_info("rfi-flush: disabling due to 'nopti' on command line.\n");
+	handle_no_rfi_flush(NULL);
+	return 0;
+}
+early_param("nopti", handle_no_pti);
+
+static void do_nothing(void *unused)
+{
+	/*
+	 * We don't need to do the flush explicitly, just enter+exit kernel is
+	 * sufficient, the RFI exit handlers will do the right thing.
+	 */
+}
+
+void rfi_flush_enable(bool enable)
+{
+	if (enable) {
+		do_rfi_flush_fixups(enabled_flush_types);
+		on_each_cpu(do_nothing, NULL, 1);
+	} else
+		do_rfi_flush_fixups(L1D_FLUSH_NONE);
+
+	rfi_flush = enable;
+}
+
+void entry_flush_enable(bool enable)
+{
+	if (enable) {
+		do_entry_flush_fixups(enabled_flush_types);
+		on_each_cpu(do_nothing, NULL, 1);
+	} else {
+		do_entry_flush_fixups(L1D_FLUSH_NONE);
+	}
+
+	entry_flush = enable;
+}
+
+void uaccess_flush_enable(bool enable)
+{
+	if (enable) {
+		do_uaccess_flush_fixups(enabled_flush_types);
+		if (static_key_initialized)
+			static_branch_enable(&uaccess_flush_key);
+		else
+			printk(KERN_DEBUG "uaccess-flush: deferring static key until after static key initialization\n");
+		on_each_cpu(do_nothing, NULL, 1);
+	} else {
+		static_branch_disable(&uaccess_flush_key);
+		do_uaccess_flush_fixups(L1D_FLUSH_NONE);
+	}
+
+	uaccess_flush = enable;
+}
+
+static bool __ref init_fallback_flush(void)
+{
+	u64 l1d_size, limit;
+	int cpu;
+
+	/* Only allocate the fallback flush area once (at boot time). */
+	if (l1d_flush_fallback_area)
+		return true;
+
+	/*
+	 * Once the slab allocator is up it's too late to allocate the fallback
+	 * flush area, so return an error. This could happen if we migrated from
+	 * a patched machine to an unpatched machine.
+	 */
+	if (slab_is_available())
+		return false;
+
+	l1d_size = ppc64_caches.dsize;
+	limit = min(safe_stack_limit(), ppc64_rma_size);
+
+	/*
+	 * Align to L1d size, and size it at 2x L1d size, to catch possible
+	 * hardware prefetch runoff. We don't have a recipe for load patterns to
+	 * reliably avoid the prefetcher.
+	 */
+	l1d_flush_fallback_area = __va(memblock_alloc_base(l1d_size * 2, l1d_size, limit));
+	memset(l1d_flush_fallback_area, 0, l1d_size * 2);
+
+	for_each_possible_cpu(cpu) {
+		paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area;
+		paca[cpu].l1d_flush_size = l1d_size;
+	}
+
+	return true;
+}
+
+void setup_rfi_flush(enum l1d_flush_type types, bool enable)
+{
+	if (types & L1D_FLUSH_FALLBACK) {
+		if (init_fallback_flush())
+			pr_info("rfi-flush: Using fallback displacement flush\n");
+		else {
+			pr_warn("rfi-flush: Error unable to use fallback displacement flush!\n");
+			types &= ~L1D_FLUSH_FALLBACK;
+		}
+	}
+
+	if (types & L1D_FLUSH_ORI)
+		pr_info("rfi-flush: ori type flush available\n");
+
+	if (types & L1D_FLUSH_MTTRIG)
+		pr_info("rfi-flush: mttrig type flush available\n");
+
+	enabled_flush_types = types;
+
+	if (!no_rfi_flush && !cpu_mitigations_off())
+		rfi_flush_enable(enable);
+}
+
+void setup_entry_flush(bool enable)
+{
+	if (cpu_mitigations_off())
+		return;
+
+	if (!no_entry_flush)
+		entry_flush_enable(enable);
+}
+
+void setup_uaccess_flush(bool enable)
+{
+	if (cpu_mitigations_off())
+		return;
+
+	if (!no_uaccess_flush)
+		uaccess_flush_enable(enable);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int rfi_flush_set(void *data, u64 val)
+{
+	bool enable;
+
+	if (val == 1)
+		enable = true;
+	else if (val == 0)
+		enable = false;
+	else
+		return -EINVAL;
+
+	/* Only do anything if we're changing state */
+	if (enable != rfi_flush)
+		rfi_flush_enable(enable);
+
+	return 0;
+}
+
+static int rfi_flush_get(void *data, u64 *val)
+{
+	*val = rfi_flush ? 1 : 0;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_rfi_flush, rfi_flush_get, rfi_flush_set, "%llu\n");
+
+static int entry_flush_set(void *data, u64 val)
+{
+	bool enable;
+
+	if (val == 1)
+		enable = true;
+	else if (val == 0)
+		enable = false;
+	else
+		return -EINVAL;
+
+	/* Only do anything if we're changing state */
+	if (enable != entry_flush)
+		entry_flush_enable(enable);
+
+	return 0;
+}
+
+static int entry_flush_get(void *data, u64 *val)
+{
+	*val = entry_flush ? 1 : 0;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_entry_flush, entry_flush_get, entry_flush_set, "%llu\n");
+
+static int uaccess_flush_set(void *data, u64 val)
+{
+	bool enable;
+
+	if (val == 1)
+		enable = true;
+	else if (val == 0)
+		enable = false;
+	else
+		return -EINVAL;
+
+	/* Only do anything if we're changing state */
+	if (enable != uaccess_flush)
+		uaccess_flush_enable(enable);
+
+	return 0;
+}
+
+static int uaccess_flush_get(void *data, u64 *val)
+{
+	*val = uaccess_flush ? 1 : 0;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_uaccess_flush, uaccess_flush_get, uaccess_flush_set, "%llu\n");
+
+
+static __init int rfi_flush_debugfs_init(void)
+{
+	debugfs_create_file("rfi_flush", 0600, powerpc_debugfs_root, NULL, &fops_rfi_flush);
+	debugfs_create_file("entry_flush", 0600, powerpc_debugfs_root, NULL, &fops_entry_flush);
+	debugfs_create_file("uaccess_flush", 0600, powerpc_debugfs_root, NULL, &fops_uaccess_flush);
+	return 0;
+}
+device_initcall(rfi_flush_debugfs_init);
+#endif
+
+/*
+ * setup_uaccess_flush runs before jump_label_init, so we can't do the setup
+ * there. Do it now instead.
+ */
+static __init int uaccess_flush_static_key_init(void)
+{
+	if (uaccess_flush) {
+		printk(KERN_DEBUG "uaccess-flush: switching on static key\n");
+		static_branch_enable(&uaccess_flush_key);
+	}
+	return 0;
+}
+early_initcall(uaccess_flush_static_key_init);
+#endif /* CONFIG_PPC_BOOK3S_64 */
--- linux-4.4.0.orig/arch/powerpc/kernel/signal.c
+++ linux-4.4.0/arch/powerpc/kernel/signal.c
@@ -102,7 +102,7 @@
 static void do_signal(struct pt_regs *regs)
 {
 	sigset_t *oldset = sigmask_to_save();
-	struct ksignal ksig;
+	struct ksignal ksig = { .sig = 0 };
 	int ret;
 	int is32 = is_32bit_task();
 
--- linux-4.4.0.orig/arch/powerpc/kernel/signal_32.c
+++ linux-4.4.0/arch/powerpc/kernel/signal_32.c
@@ -1244,7 +1244,21 @@
 		(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);
 	if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf)))
 		goto bad;
+
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	/*
+	 * If there is a transactional state then throw it away.
+	 * The purpose of a sigreturn is to destroy all traces of the
+	 * signal frame, this includes any transactional state created
+	 * within in. We only check for suspended as we can never be
+	 * active in the kernel, we are active, there is nothing better to
+	 * do than go ahead and Bad Thing later.
+	 * The cause is not important as there will never be a
+	 * recheckpoint so it's not user visible.
+	 */
+	if (MSR_TM_SUSPENDED(mfmsr()))
+		tm_reclaim_current(0);
+
 	if (__get_user(tmp, &rt_sf->uc.uc_link))
 		goto bad;
 	uc_transact = (struct ucontext __user *)(uintptr_t)tmp;
@@ -1261,6 +1275,9 @@
 			goto bad;
 
 		if (MSR_TM_ACTIVE(msr_hi<<32)) {
+			/* Trying to start TM on non TM system */
+			if (!cpu_has_feature(CPU_FTR_TM))
+				goto bad;
 			/* We only recheckpoint on return if we're
 			 * transaction.
 			 */
--- linux-4.4.0.orig/arch/powerpc/kernel/signal_64.c
+++ linux-4.4.0/arch/powerpc/kernel/signal_64.c
@@ -462,8 +462,10 @@
 	err |= __get_user(current->thread.ckpt_regs.ccr,
 			  &sc->gp_regs[PT_CCR]);
 
+	/* Don't allow userspace to set the trap value */
+	regs->trap = 0;
+
 	/* These regs are not checkpointed; they can go in 'regs'. */
-	err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]);
 	err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]);
 	err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]);
 	err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]);
@@ -689,12 +691,31 @@
 	if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
 		goto badframe;
 	set_current_blocked(&set);
+
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	/*
+	 * If there is a transactional state then throw it away.
+	 * The purpose of a sigreturn is to destroy all traces of the
+	 * signal frame, this includes any transactional state created
+	 * within in. We only check for suspended as we can never be
+	 * active in the kernel, we are active, there is nothing better to
+	 * do than go ahead and Bad Thing later.
+	 * The cause is not important as there will never be a
+	 * recheckpoint so it's not user visible.
+	 */
+	if (MSR_TM_SUSPENDED(mfmsr()))
+		tm_reclaim_current(0);
+
 	if (__get_user(msr, &uc->uc_mcontext.gp_regs[PT_MSR]))
 		goto badframe;
 	if (MSR_TM_ACTIVE(msr)) {
 		/* We recheckpoint on return. */
 		struct ucontext __user *uc_transact;
+
+		/* Trying to start TM on non TM system */
+		if (!cpu_has_feature(CPU_FTR_TM))
+			goto badframe;
+
 		if (__get_user(uc_transact, &uc->uc_link))
 			goto badframe;
 		if (restore_tm_sigcontexts(regs, &uc->uc_mcontext,
--- linux-4.4.0.orig/arch/powerpc/kernel/swsusp_32.S
+++ linux-4.4.0/arch/powerpc/kernel/swsusp_32.S
@@ -23,11 +23,19 @@
 #define SL_IBAT2	0x48
 #define SL_DBAT3	0x50
 #define SL_IBAT3	0x58
-#define SL_TB		0x60
-#define SL_R2		0x68
-#define SL_CR		0x6c
-#define SL_LR		0x70
-#define SL_R12		0x74	/* r12 to r31 */
+#define SL_DBAT4	0x60
+#define SL_IBAT4	0x68
+#define SL_DBAT5	0x70
+#define SL_IBAT5	0x78
+#define SL_DBAT6	0x80
+#define SL_IBAT6	0x88
+#define SL_DBAT7	0x90
+#define SL_IBAT7	0x98
+#define SL_TB		0xa0
+#define SL_R2		0xa8
+#define SL_CR		0xac
+#define SL_LR		0xb0
+#define SL_R12		0xb4	/* r12 to r31 */
 #define SL_SIZE		(SL_R12 + 80)
 
 	.section .data
@@ -112,6 +120,41 @@
 	mfibatl	r4,3
 	stw	r4,SL_IBAT3+4(r11)
 
+BEGIN_MMU_FTR_SECTION
+	mfspr	r4,SPRN_DBAT4U
+	stw	r4,SL_DBAT4(r11)
+	mfspr	r4,SPRN_DBAT4L
+	stw	r4,SL_DBAT4+4(r11)
+	mfspr	r4,SPRN_DBAT5U
+	stw	r4,SL_DBAT5(r11)
+	mfspr	r4,SPRN_DBAT5L
+	stw	r4,SL_DBAT5+4(r11)
+	mfspr	r4,SPRN_DBAT6U
+	stw	r4,SL_DBAT6(r11)
+	mfspr	r4,SPRN_DBAT6L
+	stw	r4,SL_DBAT6+4(r11)
+	mfspr	r4,SPRN_DBAT7U
+	stw	r4,SL_DBAT7(r11)
+	mfspr	r4,SPRN_DBAT7L
+	stw	r4,SL_DBAT7+4(r11)
+	mfspr	r4,SPRN_IBAT4U
+	stw	r4,SL_IBAT4(r11)
+	mfspr	r4,SPRN_IBAT4L
+	stw	r4,SL_IBAT4+4(r11)
+	mfspr	r4,SPRN_IBAT5U
+	stw	r4,SL_IBAT5(r11)
+	mfspr	r4,SPRN_IBAT5L
+	stw	r4,SL_IBAT5+4(r11)
+	mfspr	r4,SPRN_IBAT6U
+	stw	r4,SL_IBAT6(r11)
+	mfspr	r4,SPRN_IBAT6L
+	stw	r4,SL_IBAT6+4(r11)
+	mfspr	r4,SPRN_IBAT7U
+	stw	r4,SL_IBAT7(r11)
+	mfspr	r4,SPRN_IBAT7L
+	stw	r4,SL_IBAT7+4(r11)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+
 #if  0
 	/* Backup various CPU config stuffs */
 	bl	__save_cpu_setup
@@ -277,27 +320,41 @@
 	mtibatu	3,r4
 	lwz	r4,SL_IBAT3+4(r11)
 	mtibatl	3,r4
-#endif
-
 BEGIN_MMU_FTR_SECTION
-	li	r4,0
+	lwz	r4,SL_DBAT4(r11)
 	mtspr	SPRN_DBAT4U,r4
+	lwz	r4,SL_DBAT4+4(r11)
 	mtspr	SPRN_DBAT4L,r4
+	lwz	r4,SL_DBAT5(r11)
 	mtspr	SPRN_DBAT5U,r4
+	lwz	r4,SL_DBAT5+4(r11)
 	mtspr	SPRN_DBAT5L,r4
+	lwz	r4,SL_DBAT6(r11)
 	mtspr	SPRN_DBAT6U,r4
+	lwz	r4,SL_DBAT6+4(r11)
 	mtspr	SPRN_DBAT6L,r4
+	lwz	r4,SL_DBAT7(r11)
 	mtspr	SPRN_DBAT7U,r4
+	lwz	r4,SL_DBAT7+4(r11)
 	mtspr	SPRN_DBAT7L,r4
+	lwz	r4,SL_IBAT4(r11)
 	mtspr	SPRN_IBAT4U,r4
+	lwz	r4,SL_IBAT4+4(r11)
 	mtspr	SPRN_IBAT4L,r4
+	lwz	r4,SL_IBAT5(r11)
 	mtspr	SPRN_IBAT5U,r4
+	lwz	r4,SL_IBAT5+4(r11)
 	mtspr	SPRN_IBAT5L,r4
+	lwz	r4,SL_IBAT6(r11)
 	mtspr	SPRN_IBAT6U,r4
+	lwz	r4,SL_IBAT6+4(r11)
 	mtspr	SPRN_IBAT6L,r4
+	lwz	r4,SL_IBAT7(r11)
 	mtspr	SPRN_IBAT7U,r4
+	lwz	r4,SL_IBAT7+4(r11)
 	mtspr	SPRN_IBAT7L,r4
 END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+#endif
 
 	/* Flush all TLBs */
 	lis	r4,0x1000
--- linux-4.4.0.orig/arch/powerpc/kernel/tau_6xx.c
+++ linux-4.4.0/arch/powerpc/kernel/tau_6xx.c
@@ -37,8 +37,6 @@
 
 struct timer_list tau_timer;
 
-#undef DEBUG
-
 /* TODO: put these in a /proc interface, with some sanity checks, and maybe
  * dynamic adjustment to minimize # of interrupts */
 /* configurable values for step size and how much to expand the window when
@@ -71,47 +69,33 @@
 
 void TAUupdate(int cpu)
 {
-	unsigned thrm;
-
-#ifdef DEBUG
-	printk("TAUupdate ");
-#endif
+	u32 thrm;
+	u32 bits = THRM1_TIV | THRM1_TIN | THRM1_V;
 
 	/* if both thresholds are crossed, the step_sizes cancel out
 	 * and the window winds up getting expanded twice. */
-	if((thrm = mfspr(SPRN_THRM1)) & THRM1_TIV){ /* is valid? */
-		if(thrm & THRM1_TIN){ /* crossed low threshold */
-			if (tau[cpu].low >= step_size){
-				tau[cpu].low -= step_size;
-				tau[cpu].high -= (step_size - window_expand);
-			}
-			tau[cpu].grew = 1;
-#ifdef DEBUG
-			printk("low threshold crossed ");
-#endif
+	thrm = mfspr(SPRN_THRM1);
+	if ((thrm & bits) == bits) {
+		mtspr(SPRN_THRM1, 0);
+
+		if (tau[cpu].low >= step_size) {
+			tau[cpu].low -= step_size;
+			tau[cpu].high -= (step_size - window_expand);
 		}
+		tau[cpu].grew = 1;
+		pr_debug("%s: low threshold crossed\n", __func__);
 	}
-	if((thrm = mfspr(SPRN_THRM2)) & THRM1_TIV){ /* is valid? */
-		if(thrm & THRM1_TIN){ /* crossed high threshold */
-			if (tau[cpu].high <= 127-step_size){
-				tau[cpu].low += (step_size - window_expand);
-				tau[cpu].high += step_size;
-			}
-			tau[cpu].grew = 1;
-#ifdef DEBUG
-			printk("high threshold crossed ");
-#endif
+	thrm = mfspr(SPRN_THRM2);
+	if ((thrm & bits) == bits) {
+		mtspr(SPRN_THRM2, 0);
+
+		if (tau[cpu].high <= 127 - step_size) {
+			tau[cpu].low += (step_size - window_expand);
+			tau[cpu].high += step_size;
 		}
+		tau[cpu].grew = 1;
+		pr_debug("%s: high threshold crossed\n", __func__);
 	}
-
-#ifdef DEBUG
-	printk("grew = %d\n", tau[cpu].grew);
-#endif
-
-#ifndef CONFIG_TAU_INT /* tau_timeout will do this if not using interrupts */
-	set_thresholds(cpu);
-#endif
-
 }
 
 #ifdef CONFIG_TAU_INT
@@ -136,18 +120,18 @@
 static void tau_timeout(void * info)
 {
 	int cpu;
-	unsigned long flags;
 	int size;
 	int shrink;
 
-	/* disabling interrupts *should* be okay */
-	local_irq_save(flags);
 	cpu = smp_processor_id();
 
 #ifndef CONFIG_TAU_INT
 	TAUupdate(cpu);
 #endif
 
+	/* Stop thermal sensor comparisons and interrupts */
+	mtspr(SPRN_THRM3, 0);
+
 	size = tau[cpu].high - tau[cpu].low;
 	if (size > min_window && ! tau[cpu].grew) {
 		/* do an exponential shrink of half the amount currently over size */
@@ -169,22 +153,12 @@
 
 	set_thresholds(cpu);
 
-	/*
-	 * Do the enable every time, since otherwise a bunch of (relatively)
-	 * complex sleep code needs to be added. One mtspr every time
-	 * tau_timeout is called is probably not a big deal.
-	 *
-	 * Enable thermal sensor and set up sample interval timer
-	 * need 20 us to do the compare.. until a nice 'cpu_speed' function
-	 * call is implemented, just assume a 500 mhz clock. It doesn't really
-	 * matter if we take too long for a compare since it's all interrupt
-	 * driven anyway.
-	 *
-	 * use a extra long time.. (60 us @ 500 mhz)
+	/* Restart thermal sensor comparisons and interrupts.
+	 * The "PowerPC 740 and PowerPC 750 Microprocessor Datasheet"
+	 * recommends that "the maximum value be set in THRM3 under all
+	 * conditions."
 	 */
-	mtspr(SPRN_THRM3, THRM3_SITV(500*60) | THRM3_E);
-
-	local_irq_restore(flags);
+	mtspr(SPRN_THRM3, THRM3_SITV(0x1fff) | THRM3_E);
 }
 
 static void tau_timeout_smp(unsigned long unused)
--- linux-4.4.0.orig/arch/powerpc/kernel/time.c
+++ linux-4.4.0/arch/powerpc/kernel/time.c
@@ -245,7 +245,7 @@
  * Accumulate stolen time by scanning the dispatch trace log.
  * Called on entry from user mode.
  */
-void accumulate_stolen_time(void)
+void notrace accumulate_stolen_time(void)
 {
 	u64 sst, ust;
 
@@ -686,12 +686,20 @@
 static void start_cpu_decrementer(void)
 {
 #if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+	unsigned int tcr;
+
 	/* Clear any pending timer interrupts */
 	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
 
-	/* Enable decrementer interrupt */
-	mtspr(SPRN_TCR, TCR_DIE);
-#endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */
+	tcr = mfspr(SPRN_TCR);
+	/*
+	 * The watchdog may have already been enabled by u-boot. So leave
+	 * TRC[WP] (Watchdog Period) alone.
+	 */
+	tcr &= TCR_WP_MASK;	/* Clear all bits except for TCR[WP] */
+	tcr |= TCR_DIE;		/* Enable decrementer */
+	mtspr(SPRN_TCR, tcr);
+#endif
 }
 
 void __init generic_calibrate_decr(void)
@@ -821,6 +829,7 @@
 	vdso_data->wtom_clock_nsec = wtm->tv_nsec;
 	vdso_data->stamp_xtime = *wall_time;
 	vdso_data->stamp_sec_fraction = frac_sec;
+	vdso_data->hrtimer_res = hrtimer_resolution;
 	smp_wmb();
 	++(vdso_data->tb_update_count);
 }
--- linux-4.4.0.orig/arch/powerpc/kernel/tm.S
+++ linux-4.4.0/arch/powerpc/kernel/tm.S
@@ -110,17 +110,11 @@
 	std	r3, STK_PARAM(R3)(r1)
 	SAVE_NVGPRS(r1)
 
-	/* We need to setup MSR for VSX register save instructions.  Here we
-	 * also clear the MSR RI since when we do the treclaim, we won't have a
-	 * valid kernel pointer for a while.  We clear RI here as it avoids
-	 * adding another mtmsr closer to the treclaim.  This makes the region
-	 * maked as non-recoverable wider than it needs to be but it saves on
-	 * inserting another mtmsrd later.
-	 */
+	/* We need to setup MSR for VSX register save instructions. */
 	mfmsr	r14
 	mr	r15, r14
 	ori	r15, r15, MSR_FP
-	li	r16, MSR_RI
+	li	r16, 0
 	ori	r16, r16, MSR_EE /* IRQs hard off */
 	andc	r15, r15, r16
 	oris	r15, r15, MSR_VEC@h
@@ -176,7 +170,17 @@
 1:	tdeqi   r6, 0
 	EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0
 
-	/* The moment we treclaim, ALL of our GPRs will switch
+	/* Clear MSR RI since we are about to change r1, EE is already off. */
+	li	r4, 0
+	mtmsrd	r4, 1
+
+	/*
+	 * BE CAREFUL HERE:
+	 * At this point we can't take an SLB miss since we have MSR_RI
+	 * off. Load only to/from the stack/paca which are in SLB bolted regions
+	 * until we turn MSR RI back on.
+	 *
+	 * The moment we treclaim, ALL of our GPRs will switch
 	 * to user register state.  (FPRs, CCR etc. also!)
 	 * Use an sprg and a tm_scratch in the PACA to shuffle.
 	 */
@@ -195,8 +199,27 @@
 	std	r1, PACATMSCRATCH(r13)
 	ld	r1, PACAR1(r13)
 
-	/* Store the PPR in r11 and reset to decent value */
 	std	r11, GPR11(r1)			/* Temporary stash */
+
+	/*
+	 * Move the saved user r1 to the kernel stack in case PACATMSCRATCH is
+	 * clobbered by an exception once we turn on MSR_RI below.
+	 */
+	ld	r11, PACATMSCRATCH(r13)
+	std	r11, GPR1(r1)
+
+	/*
+	 * Store r13 away so we can free up the scratch SPR for the SLB fault
+	 * handler (needed once we start accessing the thread_struct).
+	 */
+	GET_SCRATCH0(r11)
+	std	r11, GPR13(r1)
+
+	/* Reset MSR RI so we can take SLB faults again */
+	li	r11, MSR_RI
+	mtmsrd	r11, 1
+
+	/* Store the PPR in r11 and reset to decent value */
 	mfspr	r11, SPRN_PPR
 	HMT_MEDIUM
 
@@ -221,11 +244,11 @@
 	SAVE_GPR(8, r7)				/* user r8 */
 	SAVE_GPR(9, r7)				/* user r9 */
 	SAVE_GPR(10, r7)			/* user r10 */
-	ld	r3, PACATMSCRATCH(r13)		/* user r1 */
+	ld	r3, GPR1(r1)			/* user r1 */
 	ld	r4, GPR7(r1)			/* user r7 */
 	ld	r5, GPR11(r1)			/* user r11 */
 	ld	r6, GPR12(r1)			/* user r12 */
-	GET_SCRATCH0(8)				/* user r13 */
+	ld	r8, GPR13(r1)			/* user r13 */
 	std	r3, GPR1(r7)
 	std	r4, GPR7(r7)
 	std	r5, GPR11(r7)
@@ -329,8 +352,6 @@
 	 */
 	subi	r7, r7, STACK_FRAME_OVERHEAD
 
-	SET_SCRATCH0(r1)
-
 	mfmsr	r6
 	/* R4 = original MSR to indicate whether thread used FP/Vector etc. */
 
@@ -397,11 +418,6 @@
 	ld	r5, THREAD_TM_DSCR(r3)
 	ld	r6, THREAD_TM_PPR(r3)
 
-	/* Clear the MSR RI since we are about to change R1.  EE is already off
-	 */
-	li	r4, 0
-	mtmsrd	r4, 1
-
 	REST_GPR(0, r7)				/* GPR0 */
 	REST_2GPRS(2, r7)			/* GPR2-3 */
 	REST_GPR(4, r7)				/* GPR4 */
@@ -439,10 +455,34 @@
 	ld	r6, _CCR(r7)
 	mtcr    r6
 
-	REST_GPR(1, r7)				/* GPR1 */
-	REST_GPR(5, r7)				/* GPR5-7 */
 	REST_GPR(6, r7)
-	ld	r7, GPR7(r7)
+
+	/*
+	 * Store r1 and r5 on the stack so that we can access them
+	 * after we clear MSR RI.
+	 */
+
+	REST_GPR(5, r7)
+	std	r5, -8(r1)
+	ld	r5, GPR1(r7)
+	std	r5, -16(r1)
+
+	REST_GPR(7, r7)
+
+	/* Clear MSR RI since we are about to change r1. EE is already off */
+	li	r5, 0
+	mtmsrd	r5, 1
+
+	/*
+	 * BE CAREFUL HERE:
+	 * At this point we can't take an SLB miss since we have MSR_RI
+	 * off. Load only to/from the stack/paca which are in SLB bolted regions
+	 * until we turn MSR RI back on.
+	 */
+
+	SET_SCRATCH0(r1)
+	ld	r5, -8(r1)
+	ld	r1, -16(r1)
 
 	/* Commit register state as checkpointed state: */
 	TRECHKPT
--- linux-4.4.0.orig/arch/powerpc/kernel/traps.c
+++ linux-4.4.0/arch/powerpc/kernel/traps.c
@@ -60,6 +60,7 @@
 #include <asm/switch_to.h>
 #include <asm/tm.h>
 #include <asm/debug.h>
+#include <asm/hmi.h>
 #include <sysdev/fsl_pci.h>
 
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
@@ -297,8 +298,6 @@
 
 	__this_cpu_inc(irq_stat.mce_exceptions);
 
-	add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
-
 	if (cur_cpu_spec && cur_cpu_spec->machine_check_early)
 		handled = cur_cpu_spec->machine_check_early(regs);
 	return handled;
@@ -308,9 +307,13 @@
 {
 	__this_cpu_inc(irq_stat.hmi_exceptions);
 
+	wait_for_subcore_guest_exit();
+
 	if (ppc_md.hmi_exception_early)
 		ppc_md.hmi_exception_early(regs);
 
+	wait_for_tb_resync();
+
 	return 0;
 }
 
@@ -704,6 +707,8 @@
 
 	__this_cpu_inc(irq_stat.mce_exceptions);
 
+	add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
+
 	/* See if any machine dependent calls. In theory, we would want
 	 * to call the CPU first, and call the ppc_md. one if the CPU
 	 * one returns a positive number. However there is existing code
--- linux-4.4.0.orig/arch/powerpc/kernel/vdso.c
+++ linux-4.4.0/arch/powerpc/kernel/vdso.c
@@ -702,7 +702,7 @@
 	node = cpu_to_node(cpu);
 	WARN_ON_ONCE(node > 0xffff);
 
-	val = (cpu & 0xfff) | ((node & 0xffff) << 16);
+	val = (cpu & 0xffff) | ((node & 0xffff) << 16);
 	mtspr(SPRN_SPRG_VDSO_WRITE, val);
 	get_paca()->sprg_vdso = val;
 
--- linux-4.4.0.orig/arch/powerpc/kernel/vdso32/datapage.S
+++ linux-4.4.0/arch/powerpc/kernel/vdso32/datapage.S
@@ -37,6 +37,7 @@
 	mtlr	r0
 	addi	r3, r3, __kernel_datapage_offset-data_page_branch
 	lwz	r0,0(r3)
+  .cfi_restore lr
 	add	r3,r0,r3
 	blr
   .cfi_endproc
--- linux-4.4.0.orig/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ linux-4.4.0/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -139,6 +139,7 @@
 	 */
 99:
 	li	r0,__NR_clock_gettime
+  .cfi_restore lr
 	sc
 	blr
   .cfi_endproc
@@ -159,12 +160,15 @@
 	cror	cr0*4+eq,cr0*4+eq,cr1*4+eq
 	bne	cr0,99f
 
+	mflr	r12
+  .cfi_register lr,r12
+	bl	__get_datapage@local	/* get data page */
+	lwz	r5, CLOCK_HRTIMER_RES(r3)
+	mtlr	r12
 	li	r3,0
 	cmpli	cr0,r4,0
 	crclr	cr0*4+so
 	beqlr
-	lis	r5,CLOCK_REALTIME_RES@h
-	ori	r5,r5,CLOCK_REALTIME_RES@l
 	stw	r3,TSPC32_TV_SEC(r4)
 	stw	r5,TSPC32_TV_NSEC(r4)
 	blr
--- linux-4.4.0.orig/arch/powerpc/kernel/vdso64/cacheflush.S
+++ linux-4.4.0/arch/powerpc/kernel/vdso64/cacheflush.S
@@ -39,7 +39,7 @@
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
 	lwz	r9,CFG_DCACHE_LOGBLOCKSZ(r10)
-	srw.	r8,r8,r9		/* compute line count */
+	srd.	r8,r8,r9		/* compute line count */
 	crclr	cr0*4+so
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -56,7 +56,7 @@
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5
 	lwz	r9,CFG_ICACHE_LOGBLOCKSZ(r10)
-	srw.	r8,r8,r9		/* compute line count */
+	srd.	r8,r8,r9		/* compute line count */
 	crclr	cr0*4+so
 	beqlr				/* nothing to do? */
 	mtctr	r8
--- linux-4.4.0.orig/arch/powerpc/kernel/vdso64/datapage.S
+++ linux-4.4.0/arch/powerpc/kernel/vdso64/datapage.S
@@ -37,6 +37,7 @@
 	mtlr	r0
 	addi	r3, r3, __kernel_datapage_offset-data_page_branch
 	lwz	r0,0(r3)
+  .cfi_restore lr
 	add	r3,r0,r3
 	blr
   .cfi_endproc
@@ -59,7 +60,7 @@
 	bl	V_LOCAL_FUNC(__get_datapage)
 	mtlr	r12
 	addi	r3,r3,CFG_SYSCALL_MAP64
-	cmpli	cr0,r4,0
+	cmpldi	cr0,r4,0
 	crclr	cr0*4+so
 	beqlr
 	li	r0,__NR_syscalls
--- linux-4.4.0.orig/arch/powerpc/kernel/vdso64/gettimeofday.S
+++ linux-4.4.0/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -124,6 +124,7 @@
 	 */
 99:
 	li	r0,__NR_clock_gettime
+  .cfi_restore lr
 	sc
 	blr
   .cfi_endproc
@@ -144,12 +145,15 @@
 	cror	cr0*4+eq,cr0*4+eq,cr1*4+eq
 	bne	cr0,99f
 
+	mflr	r12
+  .cfi_register lr,r12
+	bl	V_LOCAL_FUNC(__get_datapage)
+	lwz	r5, CLOCK_HRTIMER_RES(r3)
+	mtlr	r12
 	li	r3,0
-	cmpli	cr0,r4,0
+	cmpldi	cr0,r4,0
 	crclr	cr0*4+so
 	beqlr
-	lis	r5,CLOCK_REALTIME_RES@h
-	ori	r5,r5,CLOCK_REALTIME_RES@l
 	std	r3,TSPC64_TV_SEC(r4)
 	std	r5,TSPC64_TV_NSEC(r4)
 	blr
--- linux-4.4.0.orig/arch/powerpc/kernel/vmlinux.lds.S
+++ linux-4.4.0/arch/powerpc/kernel/vmlinux.lds.S
@@ -72,6 +72,60 @@
 	/* Read-only data */
 	RODATA
 
+#ifdef CONFIG_PPC64
+	. = ALIGN(8);
+	__stf_entry_barrier_fixup : AT(ADDR(__stf_entry_barrier_fixup) - LOAD_OFFSET) {
+		__start___stf_entry_barrier_fixup = .;
+		*(__stf_entry_barrier_fixup)
+		__stop___stf_entry_barrier_fixup = .;
+	}
+
+	. = ALIGN(8);
+	__uaccess_flush_fixup : AT(ADDR(__uaccess_flush_fixup) - LOAD_OFFSET) {
+		__start___uaccess_flush_fixup = .;
+		*(__uaccess_flush_fixup)
+		__stop___uaccess_flush_fixup = .;
+	}
+
+	. = ALIGN(8);
+	__entry_flush_fixup : AT(ADDR(__entry_flush_fixup) - LOAD_OFFSET) {
+		__start___entry_flush_fixup = .;
+		*(__entry_flush_fixup)
+		__stop___entry_flush_fixup = .;
+	}
+
+	. = ALIGN(8);
+	__stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) {
+		__start___stf_exit_barrier_fixup = .;
+		*(__stf_exit_barrier_fixup)
+		__stop___stf_exit_barrier_fixup = .;
+	}
+
+	. = ALIGN(8);
+	__rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) {
+		__start___rfi_flush_fixup = .;
+		*(__rfi_flush_fixup)
+		__stop___rfi_flush_fixup = .;
+	}
+#endif /* CONFIG_PPC64 */
+
+#ifdef CONFIG_PPC_BARRIER_NOSPEC
+	. = ALIGN(8);
+	__spec_barrier_fixup : AT(ADDR(__spec_barrier_fixup) - LOAD_OFFSET) {
+		__start___barrier_nospec_fixup = .;
+		*(__barrier_nospec_fixup)
+		__stop___barrier_nospec_fixup = .;
+	}
+#endif /* CONFIG_PPC_BARRIER_NOSPEC */
+
+#ifdef CONFIG_PPC_FSL_BOOK3E
+	. = ALIGN(8);
+	__spec_btb_flush_fixup : AT(ADDR(__spec_btb_flush_fixup) - LOAD_OFFSET) {
+		__start__btb_flush_fixup = .;
+		*(__btb_flush_fixup)
+		__stop__btb_flush_fixup = .;
+	}
+#endif
 	EXCEPTION_TABLE(0)
 
 	NOTES :kernel :notes
@@ -215,6 +269,12 @@
 		*(.branch_lt)
 	}
 
+#ifdef CONFIG_DEBUG_INFO_BTF
+	.BTF : AT(ADDR(.BTF) - LOAD_OFFSET) {
+		*(.BTF)
+	}
+#endif
+
 	.opd : AT(ADDR(.opd) - LOAD_OFFSET) {
 		*(.opd)
 	}
--- linux-4.4.0.orig/arch/powerpc/kvm/Kconfig
+++ linux-4.4.0/arch/powerpc/kvm/Kconfig
@@ -22,6 +22,7 @@
 	select ANON_INODES
 	select HAVE_KVM_EVENTFD
 	select SRCU
+	select KVM_VFIO
 
 config KVM_BOOK3S_HANDLER
 	bool
--- linux-4.4.0.orig/arch/powerpc/kvm/Makefile
+++ linux-4.4.0/arch/powerpc/kvm/Makefile
@@ -7,15 +7,16 @@
 ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm
 KVM := ../../../virt/kvm
 
-common-objs-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \
-		$(KVM)/eventfd.o
+common-objs-y = $(KVM)/kvm_main.o $(KVM)/eventfd.o
+common-objs-$(CONFIG_KVM_VFIO) += $(KVM)/vfio.o
+common-objs-$(CONFIG_KVM_MMIO) += $(KVM)/coalesced_mmio.o
 
 CFLAGS_e500_mmu.o := -I.
 CFLAGS_e500_mmu_host.o := -I.
 CFLAGS_emulate.o  := -I.
 CFLAGS_emulate_loadstore.o  := -I.
 
-common-objs-y += powerpc.o emulate.o emulate_loadstore.o
+common-objs-y += powerpc.o emulate_loadstore.o
 obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o
 obj-$(CONFIG_KVM_BOOK3S_HANDLER) += book3s_exports.o
 
@@ -23,6 +24,7 @@
 
 kvm-e500-objs := \
 	$(common-objs-y) \
+	emulate.o \
 	booke.o \
 	booke_emulate.o \
 	booke_interrupts.o \
@@ -34,6 +36,7 @@
 
 kvm-e500mc-objs := \
 	$(common-objs-y) \
+	emulate.o \
 	booke.o \
 	booke_emulate.o \
 	bookehv_interrupts.o \
@@ -60,9 +63,6 @@
 	book3s_32_mmu.o
 
 ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
-kvm-book3s_64-module-objs := \
-	$(KVM)/coalesced_mmio.o
-
 kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
 	book3s_rmhandlers.o
 endif
@@ -87,11 +87,8 @@
 kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
 	book3s_xics.o
 
-kvm-book3s_64-module-objs += \
-	$(KVM)/kvm_main.o \
-	$(KVM)/eventfd.o \
-	powerpc.o \
-	emulate_loadstore.o \
+kvm-book3s_64-module-objs := \
+	$(common-objs-y) \
 	book3s.o \
 	book3s_64_vio.o \
 	book3s_rtas.o \
@@ -101,6 +98,7 @@
 
 kvm-book3s_32-objs := \
 	$(common-objs-y) \
+	emulate.o \
 	fpu.o \
 	book3s_paired_singles.o \
 	book3s.o \
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s.c
@@ -70,8 +70,11 @@
 {
 	if (vcpu->arch.hflags & BOOK3S_HFLAG_SPLIT_HACK) {
 		ulong pc = kvmppc_get_pc(vcpu);
+		ulong lr = kvmppc_get_lr(vcpu);
 		if ((pc & SPLIT_HACK_MASK) == SPLIT_HACK_OFFS)
 			kvmppc_set_pc(vcpu, pc & ~SPLIT_HACK_MASK);
+		if ((lr & SPLIT_HACK_MASK) == SPLIT_HACK_OFFS)
+			kvmppc_set_lr(vcpu, lr & ~SPLIT_HACK_MASK);
 		vcpu->arch.hflags &= ~BOOK3S_HFLAG_SPLIT_HACK;
 	}
 }
@@ -591,9 +594,6 @@
 		case KVM_REG_PPC_BESCR:
 			*val = get_reg_val(id, vcpu->arch.bescr);
 			break;
-		case KVM_REG_PPC_VTB:
-			*val = get_reg_val(id, vcpu->arch.vtb);
-			break;
 		case KVM_REG_PPC_IC:
 			*val = get_reg_val(id, vcpu->arch.ic);
 			break;
@@ -665,9 +665,6 @@
 		case KVM_REG_PPC_BESCR:
 			vcpu->arch.bescr = set_reg_val(id, *val);
 			break;
-		case KVM_REG_PPC_VTB:
-			vcpu->arch.vtb = set_reg_val(id, *val);
-			break;
 		case KVM_REG_PPC_IC:
 			vcpu->arch.ic = set_reg_val(id, *val);
 			break;
@@ -809,6 +806,7 @@
 #ifdef CONFIG_PPC64
 	INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
 	INIT_LIST_HEAD(&kvm->arch.rtas_tokens);
+	mutex_init(&kvm->arch.rtas_token_lock);
 #endif
 
 	return kvm->arch.kvm_ops->init_vm(kvm);
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -177,12 +177,15 @@
 	ret = ppc_md.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags,
 				 hpsize, hpsize, MMU_SEGSIZE_256M);
 
-	if (ret < 0) {
+	if (ret == -1) {
 		/* If we couldn't map a primary PTE, try a secondary */
 		hash = ~hash;
 		vflags ^= HPTE_V_SECONDARY;
 		attempt++;
 		goto map_again;
+	} else if (ret < 0) {
+		r = -EIO;
+		goto out_unlock;
 	} else {
 		trace_kvm_book3s_64_mmu_map(rflags, hpteg,
 					    vpn, hpaddr, orig_pte);
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -314,7 +314,7 @@
 	unsigned long pp, key;
 	unsigned long v, gr;
 	__be64 *hptep;
-	int index;
+	long int index;
 	int virtmode = vcpu->arch.shregs.msr & (data ? MSR_DR : MSR_IR);
 
 	/* Get SLB entry */
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_64_vio.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_64_vio.c
@@ -101,22 +101,17 @@
 				   struct kvm_create_spapr_tce *args)
 {
 	struct kvmppc_spapr_tce_table *stt = NULL;
+	struct kvmppc_spapr_tce_table *siter;
 	long npages;
 	int ret = -ENOMEM;
 	int i;
 
-	/* Check this LIOBN hasn't been previously allocated */
-	list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
-		if (stt->liobn == args->liobn)
-			return -EBUSY;
-	}
-
 	npages = kvmppc_stt_npages(args->window_size);
 
 	stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *),
 		      GFP_KERNEL);
 	if (!stt)
-		goto fail;
+		return ret;
 
 	stt->liobn = args->liobn;
 	stt->window_size = args->window_size;
@@ -128,23 +123,36 @@
 			goto fail;
 	}
 
-	kvm_get_kvm(kvm);
-
 	mutex_lock(&kvm->lock);
-	list_add(&stt->list, &kvm->arch.spapr_tce_tables);
+
+	/* Check this LIOBN hasn't been previously allocated */
+	ret = 0;
+	list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) {
+		if (siter->liobn == args->liobn) {
+			ret = -EBUSY;
+			break;
+		}
+	}
+
+	if (!ret)
+		ret = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
+				       stt, O_RDWR | O_CLOEXEC);
+
+	if (ret >= 0) {
+		list_add(&stt->list, &kvm->arch.spapr_tce_tables);
+		kvm_get_kvm(kvm);
+	}
 
 	mutex_unlock(&kvm->lock);
 
-	return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
-				stt, O_RDWR | O_CLOEXEC);
+	if (ret >= 0)
+		return ret;
 
-fail:
-	if (stt) {
-		for (i = 0; i < npages; i++)
-			if (stt->pages[i])
-				__free_page(stt->pages[i]);
+ fail:
+	for (i = 0; i < npages; i++)
+		if (stt->pages[i])
+			__free_page(stt->pages[i]);
 
-		kfree(stt);
-	}
+	kfree(stt);
 	return ret;
 }
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_emulate.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_emulate.c
@@ -498,6 +498,7 @@
 	case SPRN_MMCR0:
 	case SPRN_MMCR1:
 	case SPRN_MMCR2:
+	case SPRN_UMMCR2:
 #endif
 		break;
 unprivileged:
@@ -579,7 +580,7 @@
 		*spr_val = vcpu->arch.spurr;
 		break;
 	case SPRN_VTB:
-		*spr_val = vcpu->arch.vtb;
+		*spr_val = to_book3s(vcpu)->vtb;
 		break;
 	case SPRN_IC:
 		*spr_val = vcpu->arch.ic;
@@ -640,6 +641,7 @@
 	case SPRN_MMCR0:
 	case SPRN_MMCR1:
 	case SPRN_MMCR2:
+	case SPRN_UMMCR2:
 	case SPRN_TIR:
 #endif
 		*spr_val = 0;
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_hv.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_hv.c
@@ -51,6 +51,7 @@
 #include <asm/switch_to.h>
 #include <asm/smp.h>
 #include <asm/dbell.h>
+#include <asm/hmi.h>
 #include <linux/gfp.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
@@ -1100,6 +1101,9 @@
 	case KVM_REG_PPC_DPDES:
 		*val = get_reg_val(id, vcpu->arch.vcore->dpdes);
 		break;
+	case KVM_REG_PPC_VTB:
+		*val = get_reg_val(id, vcpu->arch.vcore->vtb);
+		break;
 	case KVM_REG_PPC_DAWR:
 		*val = get_reg_val(id, vcpu->arch.dawr);
 		break;
@@ -1186,6 +1190,9 @@
 	case KVM_REG_PPC_TM_CR:
 		*val = get_reg_val(id, vcpu->arch.cr_tm);
 		break;
+	case KVM_REG_PPC_TM_XER:
+		*val = get_reg_val(id, vcpu->arch.xer_tm);
+		break;
 	case KVM_REG_PPC_TM_LR:
 		*val = get_reg_val(id, vcpu->arch.lr_tm);
 		break;
@@ -1292,6 +1299,9 @@
 	case KVM_REG_PPC_DPDES:
 		vcpu->arch.vcore->dpdes = set_reg_val(id, *val);
 		break;
+	case KVM_REG_PPC_VTB:
+		vcpu->arch.vcore->vtb = set_reg_val(id, *val);
+		break;
 	case KVM_REG_PPC_DAWR:
 		vcpu->arch.dawr = set_reg_val(id, *val);
 		break;
@@ -1393,6 +1403,9 @@
 	case KVM_REG_PPC_TM_CR:
 		vcpu->arch.cr_tm = set_reg_val(id, *val);
 		break;
+	case KVM_REG_PPC_TM_XER:
+		vcpu->arch.xer_tm = set_reg_val(id, *val);
+		break;
 	case KVM_REG_PPC_TM_LR:
 		vcpu->arch.lr_tm = set_reg_val(id, *val);
 		break;
@@ -1663,7 +1676,7 @@
 	mutex_unlock(&kvm->lock);
 
 	if (!vcore)
-		goto free_vcpu;
+		goto uninit_vcpu;
 
 	spin_lock(&vcore->lock);
 	++vcore->num_threads;
@@ -1679,6 +1692,8 @@
 
 	return vcpu;
 
+uninit_vcpu:
+	kvm_vcpu_uninit(vcpu);
 free_vcpu:
 	kmem_cache_free(kvm_vcpu_cache, vcpu);
 out:
@@ -2115,9 +2130,11 @@
 	    pvc->lpcr != vc->lpcr)
 		return false;
 
-	/* P8 guest with > 1 thread per core would see wrong TIR value */
-	if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
-	    (vc->num_threads > 1 || pvc->num_threads > 1))
+	/*
+	 * P8 guests can't do piggybacking, because then the
+	 * VTB would be shared between the vcpus.
+	 */
+	if (cpu_has_feature(CPU_FTR_ARCH_207S))
 		return false;
 
 	n_thr = cip->subcore_threads[sub] + pvc->num_threads;
@@ -2681,12 +2698,38 @@
 {
 	int r;
 	int srcu_idx;
+	unsigned long ebb_regs[3] = {};	/* shut up GCC */
+	unsigned long user_tar = 0;
+	unsigned long proc_fscr = 0;
+	unsigned int user_vrsave;
 
 	if (!vcpu->arch.sane) {
 		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
 		return -EINVAL;
 	}
 
+	/*
+	 * Don't allow entry with a suspended transaction, because
+	 * the guest entry/exit code will lose it.
+	 * If the guest has TM enabled, save away their TM-related SPRs
+	 * (they will get restored by the TM unavailable interrupt).
+	 */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	if (cpu_has_feature(CPU_FTR_TM) && current->thread.regs &&
+	    (current->thread.regs->msr & MSR_TM)) {
+		if (MSR_TM_ACTIVE(current->thread.regs->msr)) {
+			run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+			run->fail_entry.hardware_entry_failure_reason = 0;
+			return -EINVAL;
+		}
+		/* Enable TM so we can read the TM SPRs */
+		mtmsr(mfmsr() | MSR_TM);
+		current->thread.tm_tfhar = mfspr(SPRN_TFHAR);
+		current->thread.tm_tfiar = mfspr(SPRN_TFIAR);
+		current->thread.tm_texasr = mfspr(SPRN_TEXASR);
+	}
+#endif
+
 	kvmppc_core_prepare_to_enter(vcpu);
 
 	/* No need to go into the guest when all we'll do is come back out */
@@ -2709,6 +2752,17 @@
 	flush_fp_to_thread(current);
 	flush_altivec_to_thread(current);
 	flush_vsx_to_thread(current);
+
+	/* Save userspace EBB and other register values */
+	if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
+		ebb_regs[0] = mfspr(SPRN_EBBHR);
+		ebb_regs[1] = mfspr(SPRN_EBBRR);
+		ebb_regs[2] = mfspr(SPRN_BESCR);
+		user_tar = mfspr(SPRN_TAR);
+		proc_fscr = mfspr(SPRN_FSCR);
+	}
+	user_vrsave = mfspr(SPRN_VRSAVE);
+
 	vcpu->arch.wqp = &vcpu->arch.vcore->wq;
 	vcpu->arch.pgdir = current->mm->pgd;
 	vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
@@ -2730,6 +2784,29 @@
 		}
 	} while (is_kvmppc_resume_guest(r));
 
+	/* Restore userspace EBB and other register values */
+	if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
+		mtspr(SPRN_EBBHR, ebb_regs[0]);
+		mtspr(SPRN_EBBRR, ebb_regs[1]);
+		mtspr(SPRN_BESCR, ebb_regs[2]);
+		mtspr(SPRN_TAR, user_tar);
+		mtspr(SPRN_FSCR, proc_fscr);
+	}
+	mtspr(SPRN_VRSAVE, user_vrsave);
+
+	/*
+	 * Since we don't do lazy TM reload, we need to reload
+	 * the TM registers here.
+	 */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	if (cpu_has_feature(CPU_FTR_TM) && current->thread.regs &&
+	    (current->thread.regs->msr & MSR_TM)) {
+		mtspr(SPRN_TFHAR, current->thread.tm_tfhar);
+		mtspr(SPRN_TFIAR, current->thread.tm_tfiar);
+		mtspr(SPRN_TEXASR, current->thread.tm_texasr);
+	}
+#endif
+
  out:
 	vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
 	atomic_dec(&vcpu->kvm->arch.vcpus_running);
@@ -2936,15 +3013,17 @@
 		goto up_out;
 
 	psize = vma_kernel_pagesize(vma);
-	porder = __ilog2(psize);
 
 	up_read(&current->mm->mmap_sem);
 
 	/* We can handle 4k, 64k or 16M pages in the VRMA */
-	err = -EINVAL;
-	if (!(psize == 0x1000 || psize == 0x10000 ||
-	      psize == 0x1000000))
-		goto out_srcu;
+	if (psize >= 0x1000000)
+		psize = 0x1000000;
+	else if (psize >= 0x10000)
+		psize = 0x10000;
+	else
+		psize = 0x1000;
+	porder = __ilog2(psize);
 
 	/* Update VRMASD field in the LPCR */
 	senc = slb_pgsize_encoding(psize);
@@ -3195,6 +3274,38 @@
 	.hcall_implemented = kvmppc_hcall_impl_hv,
 };
 
+static int kvm_init_subcore_bitmap(void)
+{
+	int i, j;
+	int nr_cores = cpu_nr_cores();
+	struct sibling_subcore_state *sibling_subcore_state;
+
+	for (i = 0; i < nr_cores; i++) {
+		int first_cpu = i * threads_per_core;
+		int node = cpu_to_node(first_cpu);
+
+		/* Ignore if it is already allocated. */
+		if (paca[first_cpu].sibling_subcore_state)
+			continue;
+
+		sibling_subcore_state =
+			kmalloc_node(sizeof(struct sibling_subcore_state),
+							GFP_KERNEL, node);
+		if (!sibling_subcore_state)
+			return -ENOMEM;
+
+		memset(sibling_subcore_state, 0,
+				sizeof(struct sibling_subcore_state));
+
+		for (j = 0; j < threads_per_core; j++) {
+			int cpu = first_cpu + j;
+
+			paca[cpu].sibling_subcore_state = sibling_subcore_state;
+		}
+	}
+	return 0;
+}
+
 static int kvmppc_book3s_init_hv(void)
 {
 	int r;
@@ -3205,6 +3316,10 @@
 	if (r < 0)
 		return -ENODEV;
 
+	r = kvm_init_subcore_bitmap();
+	if (r)
+		return r;
+
 	kvm_ops_hv.owner = THIS_MODULE;
 	kvmppc_hv_ops = &kvm_ops_hv;
 
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_hv_ras.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_hv_ras.c
@@ -13,6 +13,9 @@
 #include <linux/kernel.h>
 #include <asm/opal.h>
 #include <asm/mce.h>
+#include <asm/machdep.h>
+#include <asm/cputhreads.h>
+#include <asm/hmi.h>
 
 /* SRR1 bits for machine check on POWER7 */
 #define SRR1_MC_LDSTERR		(1ul << (63-42))
@@ -140,3 +143,176 @@
 {
 	return kvmppc_realmode_mc_power7(vcpu);
 }
+
+/* Check if dynamic split is in force and return subcore size accordingly. */
+static inline int kvmppc_cur_subcore_size(void)
+{
+	if (local_paca->kvm_hstate.kvm_split_mode)
+		return local_paca->kvm_hstate.kvm_split_mode->subcore_size;
+
+	return threads_per_subcore;
+}
+
+void kvmppc_subcore_enter_guest(void)
+{
+	int thread_id, subcore_id;
+
+	thread_id = cpu_thread_in_core(local_paca->paca_index);
+	subcore_id = thread_id / kvmppc_cur_subcore_size();
+
+	local_paca->sibling_subcore_state->in_guest[subcore_id] = 1;
+}
+
+void kvmppc_subcore_exit_guest(void)
+{
+	int thread_id, subcore_id;
+
+	thread_id = cpu_thread_in_core(local_paca->paca_index);
+	subcore_id = thread_id / kvmppc_cur_subcore_size();
+
+	local_paca->sibling_subcore_state->in_guest[subcore_id] = 0;
+}
+
+static bool kvmppc_tb_resync_required(void)
+{
+	if (test_and_set_bit(CORE_TB_RESYNC_REQ_BIT,
+				&local_paca->sibling_subcore_state->flags))
+		return false;
+
+	return true;
+}
+
+static void kvmppc_tb_resync_done(void)
+{
+	clear_bit(CORE_TB_RESYNC_REQ_BIT,
+			&local_paca->sibling_subcore_state->flags);
+}
+
+/*
+ * kvmppc_realmode_hmi_handler() is called only by primary thread during
+ * guest exit path.
+ *
+ * There are multiple reasons why HMI could occur, one of them is
+ * Timebase (TB) error. If this HMI is due to TB error, then TB would
+ * have been in stopped state. The opal hmi handler Will fix it and
+ * restore the TB value with host timebase value. For HMI caused due
+ * to non-TB errors, opal hmi handler will not touch/restore TB register
+ * and hence there won't be any change in TB value.
+ *
+ * Since we are not sure about the cause of this HMI, we can't be sure
+ * about the content of TB register whether it holds guest or host timebase
+ * value. Hence the idea is to resync the TB on every HMI, so that we
+ * know about the exact state of the TB value. Resync TB call will
+ * restore TB to host timebase.
+ *
+ * Things to consider:
+ * - On TB error, HMI interrupt is reported on all the threads of the core
+ *   that has encountered TB error irrespective of split-core mode.
+ * - The very first thread on the core that get chance to fix TB error
+ *   would rsync the TB with local chipTOD value.
+ * - The resync TB is a core level action i.e. it will sync all the TBs
+ *   in that core independent of split-core mode. This means if we trigger
+ *   TB sync from a thread from one subcore, it would affect TB values of
+ *   sibling subcores of the same core.
+ *
+ * All threads need to co-ordinate before making opal hmi handler.
+ * All threads will use sibling_subcore_state->in_guest[] (shared by all
+ * threads in the core) in paca which holds information about whether
+ * sibling subcores are in Guest mode or host mode. The in_guest[] array
+ * is of size MAX_SUBCORE_PER_CORE=4, indexed using subcore id to set/unset
+ * subcore status. Only primary threads from each subcore is responsible
+ * to set/unset its designated array element while entering/exiting the
+ * guset.
+ *
+ * After invoking opal hmi handler call, one of the thread (of entire core)
+ * will need to resync the TB. Bit 63 from subcore state bitmap flags
+ * (sibling_subcore_state->flags) will be used to co-ordinate between
+ * primary threads to decide who takes up the responsibility.
+ *
+ * This is what we do:
+ * - Primary thread from each subcore tries to set resync required bit[63]
+ *   of paca->sibling_subcore_state->flags.
+ * - The first primary thread that is able to set the flag takes the
+ *   responsibility of TB resync. (Let us call it as thread leader)
+ * - All other threads which are in host will call
+ *   wait_for_subcore_guest_exit() and wait for in_guest[0-3] from
+ *   paca->sibling_subcore_state to get cleared.
+ * - All the primary thread will clear its subcore status from subcore
+ *   state in_guest[] array respectively.
+ * - Once all primary threads clear in_guest[0-3], all of them will invoke
+ *   opal hmi handler.
+ * - Now all threads will wait for TB resync to complete by invoking
+ *   wait_for_tb_resync() except the thread leader.
+ * - Thread leader will do a TB resync by invoking opal_resync_timebase()
+ *   call and the it will clear the resync required bit.
+ * - All other threads will now come out of resync wait loop and proceed
+ *   with individual execution.
+ * - On return of this function, primary thread will signal all
+ *   secondary threads to proceed.
+ * - All secondary threads will eventually call opal hmi handler on
+ *   their exit path.
+ */
+
+long kvmppc_realmode_hmi_handler(struct kvm_vcpu *vcpu)
+{
+	int ptid = local_paca->kvm_hstate.ptid;
+	bool resync_req;
+
+	/* This is only called on primary thread. */
+	BUG_ON(ptid != 0);
+	__this_cpu_inc(irq_stat.hmi_exceptions);
+
+	/*
+	 * By now primary thread has already completed guest->host
+	 * partition switch but haven't signaled secondaries yet.
+	 * All the secondary threads on this subcore is waiting
+	 * for primary thread to signal them to go ahead.
+	 *
+	 * For threads from subcore which isn't in guest, they all will
+	 * wait until all other subcores on this core exit the guest.
+	 *
+	 * Now set the resync required bit. If you are the first to
+	 * set this bit then kvmppc_tb_resync_required() function will
+	 * return true. For rest all other subcores
+	 * kvmppc_tb_resync_required() will return false.
+	 *
+	 * If resync_req == true, then this thread is responsible to
+	 * initiate TB resync after hmi handler has completed.
+	 * All other threads on this core will wait until this thread
+	 * clears the resync required bit flag.
+	 */
+	resync_req = kvmppc_tb_resync_required();
+
+	/* Reset the subcore status to indicate it has exited guest */
+	kvmppc_subcore_exit_guest();
+
+	/*
+	 * Wait for other subcores on this core to exit the guest.
+	 * All the primary threads and threads from subcore that are
+	 * not in guest will wait here until all subcores are out
+	 * of guest context.
+	 */
+	wait_for_subcore_guest_exit();
+
+	/*
+	 * At this point we are sure that primary threads from each
+	 * subcore on this core have completed guest->host partition
+	 * switch. Now it is safe to call HMI handler.
+	 */
+	if (ppc_md.hmi_exception_early)
+		ppc_md.hmi_exception_early(NULL);
+
+	/*
+	 * Check if this thread is responsible to resync TB.
+	 * All other threads will wait until this thread completes the
+	 * TB resync.
+	 */
+	if (resync_req) {
+		opal_resync_timebase();
+		/* Reset TB resync req bit */
+		kvmppc_tb_resync_done();
+	} else {
+		wait_for_tb_resync();
+	}
+	return 0;
+}
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -653,6 +653,8 @@
 					      HPTE_V_ABSENT);
 			do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags),
 				  true);
+			/* Don't lose R/C bit updates done by hardware */
+			r |= be64_to_cpu(hpte[1]) & (HPTE_R_R | HPTE_R_C);
 			hpte[1] = cpu_to_be64(r);
 		}
 	}
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_hv_rm_xics.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -280,6 +280,7 @@
 		 */
 		if (reject && reject != XICS_IPI) {
 			arch_spin_unlock(&ics->lock);
+			icp->n_reject++;
 			new_irq = reject;
 			goto again;
 		}
@@ -611,10 +612,8 @@
 	state = &ics->irq_state[src];
 
 	/* Still asserted, resend it */
-	if (state->asserted) {
-		icp->n_reject++;
+	if (state->asserted)
 		icp_rm_deliver_irq(xics, icp, irq);
-	}
 
 	if (!hlist_empty(&vcpu->kvm->irq_ack_notifier_list)) {
 		icp->rm_action |= XICS_RM_NOTIFY_EOI;
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ linux-4.4.0/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -18,6 +18,7 @@
  */
 
 #include <asm/ppc_asm.h>
+#include <asm/code-patching-asm.h>
 #include <asm/kvm_asm.h>
 #include <asm/reg.h>
 #include <asm/mmu.h>
@@ -29,6 +30,7 @@
 #include <asm/kvm_book3s_asm.h>
 #include <asm/mmu-hash64.h>
 #include <asm/tm.h>
+#include <asm/opal.h>
 
 #define VCPU_GPRS_TM(reg) (((reg) * ULONG_SIZE) + VCPU_GPR_TM)
 
@@ -36,6 +38,13 @@
 #define NAPPING_CEDE	1
 #define NAPPING_NOVCPU	2
 
+/* Stack frame offsets for kvmppc_hv_entry */
+#define SFS			112
+#define STACK_SLOT_TRAP		(SFS-4)
+#define STACK_SLOT_CIABR	(SFS-16)
+#define STACK_SLOT_DAWR		(SFS-24)
+#define STACK_SLOT_DAWRX	(SFS-32)
+
 /*
  * Call kvmppc_hv_entry in real mode.
  * Must be called with interrupts hard-disabled.
@@ -57,7 +66,7 @@
 	mtmsrd	r0,1		/* clear RI in MSR */
 	mtsrr0	r5
 	mtsrr1	r6
-	RFI
+	RFI_TO_KERNEL
 
 kvmppc_call_hv_entry:
 	ld	r4, HSTATE_KVM_VCPU(r13)
@@ -163,7 +172,7 @@
 	mtsrr0	r8
 	mtsrr1	r7
 	beq	cr1, 13f		/* machine check */
-	RFI
+	RFI_TO_KERNEL
 
 	/* On POWER7, we have external interrupts set to use HSRR0/1 */
 11:	mtspr	SPRN_HSRR0, r8
@@ -274,10 +283,10 @@
 	bl	kvmhv_accumulate_time
 #endif
 13:	mr	r3, r12
-	stw	r12, 112-4(r1)
+	stw	r12, STACK_SLOT_TRAP(r1)
 	bl	kvmhv_commence_exit
 	nop
-	lwz	r12, 112-4(r1)
+	lwz	r12, STACK_SLOT_TRAP(r1)
 	b	kvmhv_switch_to_host
 
 /*
@@ -373,6 +382,18 @@
 	lwsync
 	std	r0, HSTATE_KVM_VCORE(r13)
 
+	/*
+	 * All secondaries exiting guest will fall through this path.
+	 * Before proceeding, just check for HMI interrupt and
+	 * invoke opal hmi handler. By now we are sure that the
+	 * primary thread on this core/subcore has already made partition
+	 * switch/TB resync and we are good to call opal hmi handler.
+	 */
+	cmpwi	r12, BOOK3S_INTERRUPT_HMI
+	bne	kvm_no_guest
+
+	li	r3,0			/* NULL argument */
+	bl	hmi_exception_realmode
 /*
  * At this point we have finished executing in the guest.
  * We need to wait for hwthread_req to become zero, since
@@ -427,6 +448,12 @@
  * whole-core mode, so we need to nap.
  */
 kvm_unsplit_nap:
+	/* Before we head down to nap, check if HMI is pending and handle it */
+	cmpwi	r12, BOOK3S_INTERRUPT_HMI
+	bne	55f
+	li	r3, 0			/* NULL argument */
+	bl	hmi_exception_realmode
+55:
 	/*
 	 * Ensure that secondary doesn't nap when it has
 	 * its vcore pointer set.
@@ -489,7 +516,7 @@
 	 */
 	mflr	r0
 	std	r0, PPC_LR_STKOFF(r1)
-	stdu	r1, -112(r1)
+	stdu	r1, -SFS(r1)
 
 	/* Save R1 in the PACA */
 	std	r1, HSTATE_HOST_R1(r13)
@@ -596,11 +623,18 @@
 38:
 
 BEGIN_FTR_SECTION
-	/* DPDES is shared between threads */
+	/* DPDES and VTB are shared between threads */
 	ld	r8, VCORE_DPDES(r5)
+	ld	r7, VCORE_VTB(r5)
 	mtspr	SPRN_DPDES, r8
+	mtspr	SPRN_VTB, r7
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
+	/* Mark the subcore state as inside guest */
+	bl	kvmppc_subcore_enter_guest
+	nop
+	ld	r5, HSTATE_KVM_VCORE(r13)
+	ld	r4, HSTATE_KVM_VCPU(r13)
 	li	r0,1
 	stb	r0,VCORE_IN_GUEST(r5)	/* signal secondaries to continue */
 
@@ -643,6 +677,16 @@
 	mtspr	SPRN_PURR,r7
 	mtspr	SPRN_SPURR,r8
 
+	/* Save host values of some registers */
+BEGIN_FTR_SECTION
+	mfspr	r5, SPRN_CIABR
+	mfspr	r6, SPRN_DAWR
+	mfspr	r7, SPRN_DAWRX
+	std	r5, STACK_SLOT_CIABR(r1)
+	std	r6, STACK_SLOT_DAWR(r1)
+	std	r7, STACK_SLOT_DAWRX(r1)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+
 BEGIN_FTR_SECTION
 	/* Set partition DABR */
 	/* Do this before re-enabling PMU to avoid P7 DABR corruption bug */
@@ -655,112 +699,8 @@
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 BEGIN_FTR_SECTION
-	b	skip_tm
-END_FTR_SECTION_IFCLR(CPU_FTR_TM)
-
-	/* Turn on TM/FP/VSX/VMX so we can restore them. */
-	mfmsr	r5
-	li	r6, MSR_TM >> 32
-	sldi	r6, r6, 32
-	or	r5, r5, r6
-	ori	r5, r5, MSR_FP
-	oris	r5, r5, (MSR_VEC | MSR_VSX)@h
-	mtmsrd	r5
-
-	/*
-	 * The user may change these outside of a transaction, so they must
-	 * always be context switched.
-	 */
-	ld	r5, VCPU_TFHAR(r4)
-	ld	r6, VCPU_TFIAR(r4)
-	ld	r7, VCPU_TEXASR(r4)
-	mtspr	SPRN_TFHAR, r5
-	mtspr	SPRN_TFIAR, r6
-	mtspr	SPRN_TEXASR, r7
-
-	ld	r5, VCPU_MSR(r4)
-	rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
-	beq	skip_tm	/* TM not active in guest */
-
-	/* Make sure the failure summary is set, otherwise we'll program check
-	 * when we trechkpt.  It's possible that this might have been not set
-	 * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
-	 * host.
-	 */
-	oris	r7, r7, (TEXASR_FS)@h
-	mtspr	SPRN_TEXASR, r7
-
-	/*
-	 * We need to load up the checkpointed state for the guest.
-	 * We need to do this early as it will blow away any GPRs, VSRs and
-	 * some SPRs.
-	 */
-
-	mr	r31, r4
-	addi	r3, r31, VCPU_FPRS_TM
-	bl	load_fp_state
-	addi	r3, r31, VCPU_VRS_TM
-	bl	load_vr_state
-	mr	r4, r31
-	lwz	r7, VCPU_VRSAVE_TM(r4)
-	mtspr	SPRN_VRSAVE, r7
-
-	ld	r5, VCPU_LR_TM(r4)
-	lwz	r6, VCPU_CR_TM(r4)
-	ld	r7, VCPU_CTR_TM(r4)
-	ld	r8, VCPU_AMR_TM(r4)
-	ld	r9, VCPU_TAR_TM(r4)
-	mtlr	r5
-	mtcr	r6
-	mtctr	r7
-	mtspr	SPRN_AMR, r8
-	mtspr	SPRN_TAR, r9
-
-	/*
-	 * Load up PPR and DSCR values but don't put them in the actual SPRs
-	 * till the last moment to avoid running with userspace PPR and DSCR for
-	 * too long.
-	 */
-	ld	r29, VCPU_DSCR_TM(r4)
-	ld	r30, VCPU_PPR_TM(r4)
-
-	std	r2, PACATMSCRATCH(r13) /* Save TOC */
-
-	/* Clear the MSR RI since r1, r13 are all going to be foobar. */
-	li	r5, 0
-	mtmsrd	r5, 1
-
-	/* Load GPRs r0-r28 */
-	reg = 0
-	.rept	29
-	ld	reg, VCPU_GPRS_TM(reg)(r31)
-	reg = reg + 1
-	.endr
-
-	mtspr	SPRN_DSCR, r29
-	mtspr	SPRN_PPR, r30
-
-	/* Load final GPRs */
-	ld	29, VCPU_GPRS_TM(29)(r31)
-	ld	30, VCPU_GPRS_TM(30)(r31)
-	ld	31, VCPU_GPRS_TM(31)(r31)
-
-	/* TM checkpointed state is now setup.  All GPRs are now volatile. */
-	TRECHKPT
-
-	/* Now let's get back the state we need. */
-	HMT_MEDIUM
-	GET_PACA(r13)
-	ld	r29, HSTATE_DSCR(r13)
-	mtspr	SPRN_DSCR, r29
-	ld	r4, HSTATE_KVM_VCPU(r13)
-	ld	r1, HSTATE_HOST_R1(r13)
-	ld	r2, PACATMSCRATCH(r13)
-
-	/* Set the MSR RI since we have our registers back. */
-	li	r5, MSR_RI
-	mtmsrd	r5, 1
-skip_tm:
+	bl	kvmppc_restore_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
 #endif
 
 	/* Load guest PMU registers */
@@ -841,12 +781,6 @@
 	/* Skip next section on POWER7 */
 	b	8f
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
-	/* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
-	mfmsr	r8
-	li	r0, 1
-	rldimi	r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-	mtmsrd	r8
-
 	/* Load up POWER8-specific registers */
 	ld	r5, VCPU_IAMR(r4)
 	lwz	r6, VCPU_PSPB(r4)
@@ -863,10 +797,8 @@
 	mtspr	SPRN_CIABR, r7
 	mtspr	SPRN_TAR, r8
 	ld	r5, VCPU_IC(r4)
-	ld	r6, VCPU_VTB(r4)
-	mtspr	SPRN_IC, r5
-	mtspr	SPRN_VTB, r6
 	ld	r8, VCPU_EBBHR(r4)
+	mtspr	SPRN_IC, r5
 	mtspr	SPRN_EBBHR, r8
 	ld	r5, VCPU_EBBRR(r4)
 	ld	r6, VCPU_BESCR(r4)
@@ -1058,8 +990,7 @@
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 	ld	r0, VCPU_GPR(R0)(r4)
 	ld	r4, VCPU_GPR(R4)(r4)
-
-	hrfid
+	HRFI_TO_GUEST
 	b	.
 
 secondary_too_late:
@@ -1263,6 +1194,10 @@
 	bl	kvmhv_accumulate_time
 #endif
 
+	/* Possibly flush the link stack here. */
+1:	nop
+	patch_site 1b patch__call_kvm_flush_link_stack
+
 	mr 	r3, r12
 	/* Increment exit count, poke other threads to exit */
 	bl	kvmhv_commence_exit
@@ -1347,10 +1282,8 @@
 	stw	r6, VCPU_PSPB(r9)
 	std	r7, VCPU_FSCR(r9)
 	mfspr	r5, SPRN_IC
-	mfspr	r6, SPRN_VTB
 	mfspr	r7, SPRN_TAR
 	std	r5, VCPU_IC(r9)
-	std	r6, VCPU_VTB(r9)
 	std	r7, VCPU_TAR(r9)
 	mfspr	r8, SPRN_EBBHR
 	std	r8, VCPU_EBBHR(r9)
@@ -1370,6 +1303,19 @@
 	std	r6, VCPU_ACOP(r9)
 	stw	r7, VCPU_GUEST_PID(r9)
 	std	r8, VCPU_WORT(r9)
+	/*
+	 * Restore various registers to 0, where non-zero values
+	 * set by the guest could disrupt the host.
+	 */
+	li	r0, 0
+	mtspr	SPRN_IAMR, r0
+	mtspr	SPRN_PSPB, r0
+	mtspr	SPRN_TCSCR, r0
+	mtspr	SPRN_WORT, r0
+	/* Set MMCRS to 1<<31 to freeze and disable the SPMC counters */
+	li	r0, 1
+	sldi	r0, r0, 31
+	mtspr	SPRN_MMCRS, r0
 8:
 
 	/* Save and reset AMR and UAMOR before turning on the MMU */
@@ -1379,6 +1325,7 @@
 	std	r6,VCPU_UAMOR(r9)
 	li	r6,0
 	mtspr	SPRN_AMR,r6
+	mtspr	SPRN_UAMOR, r6
 
 	/* Switch DSCR back to host value */
 	mfspr	r8, SPRN_DSCR
@@ -1422,106 +1369,8 @@
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 BEGIN_FTR_SECTION
-	b	2f
-END_FTR_SECTION_IFCLR(CPU_FTR_TM)
-	/* Turn on TM. */
-	mfmsr	r8
-	li	r0, 1
-	rldimi	r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-	mtmsrd	r8
-
-	ld	r5, VCPU_MSR(r9)
-	rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
-	beq	1f	/* TM not active in guest. */
-
-	li	r3, TM_CAUSE_KVM_RESCHED
-
-	/* Clear the MSR RI since r1, r13 are all going to be foobar. */
-	li	r5, 0
-	mtmsrd	r5, 1
-
-	/* All GPRs are volatile at this point. */
-	TRECLAIM(R3)
-
-	/* Temporarily store r13 and r9 so we have some regs to play with */
-	SET_SCRATCH0(r13)
-	GET_PACA(r13)
-	std	r9, PACATMSCRATCH(r13)
-	ld	r9, HSTATE_KVM_VCPU(r13)
-
-	/* Get a few more GPRs free. */
-	std	r29, VCPU_GPRS_TM(29)(r9)
-	std	r30, VCPU_GPRS_TM(30)(r9)
-	std	r31, VCPU_GPRS_TM(31)(r9)
-
-	/* Save away PPR and DSCR soon so don't run with user values. */
-	mfspr	r31, SPRN_PPR
-	HMT_MEDIUM
-	mfspr	r30, SPRN_DSCR
-	ld	r29, HSTATE_DSCR(r13)
-	mtspr	SPRN_DSCR, r29
-
-	/* Save all but r9, r13 & r29-r31 */
-	reg = 0
-	.rept	29
-	.if (reg != 9) && (reg != 13)
-	std	reg, VCPU_GPRS_TM(reg)(r9)
-	.endif
-	reg = reg + 1
-	.endr
-	/* ... now save r13 */
-	GET_SCRATCH0(r4)
-	std	r4, VCPU_GPRS_TM(13)(r9)
-	/* ... and save r9 */
-	ld	r4, PACATMSCRATCH(r13)
-	std	r4, VCPU_GPRS_TM(9)(r9)
-
-	/* Reload stack pointer and TOC. */
-	ld	r1, HSTATE_HOST_R1(r13)
-	ld	r2, PACATOC(r13)
-
-	/* Set MSR RI now we have r1 and r13 back. */
-	li	r5, MSR_RI
-	mtmsrd	r5, 1
-
-	/* Save away checkpinted SPRs. */
-	std	r31, VCPU_PPR_TM(r9)
-	std	r30, VCPU_DSCR_TM(r9)
-	mflr	r5
-	mfcr	r6
-	mfctr	r7
-	mfspr	r8, SPRN_AMR
-	mfspr	r10, SPRN_TAR
-	std	r5, VCPU_LR_TM(r9)
-	stw	r6, VCPU_CR_TM(r9)
-	std	r7, VCPU_CTR_TM(r9)
-	std	r8, VCPU_AMR_TM(r9)
-	std	r10, VCPU_TAR_TM(r9)
-
-	/* Restore r12 as trap number. */
-	lwz	r12, VCPU_TRAP(r9)
-
-	/* Save FP/VSX. */
-	addi	r3, r9, VCPU_FPRS_TM
-	bl	store_fp_state
-	addi	r3, r9, VCPU_VRS_TM
-	bl	store_vr_state
-	mfspr	r6, SPRN_VRSAVE
-	stw	r6, VCPU_VRSAVE_TM(r9)
-1:
-	/*
-	 * We need to save these SPRs after the treclaim so that the software
-	 * error code is recorded correctly in the TEXASR.  Also the user may
-	 * change these outside of a transaction, so they must always be
-	 * context switched.
-	 */
-	mfspr	r5, SPRN_TFHAR
-	mfspr	r6, SPRN_TFIAR
-	mfspr	r7, SPRN_TEXASR
-	std	r5, VCPU_TFHAR(r9)
-	std	r6, VCPU_TFIAR(r9)
-	std	r7, VCPU_TEXASR(r9)
-2:
+	bl	kvmppc_save_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
 #endif
 
 	/* Increment yield count if they have a VPA */
@@ -1618,6 +1467,16 @@
 	slbia
 	ptesync
 
+	/* Restore host values of some registers */
+BEGIN_FTR_SECTION
+	ld	r5, STACK_SLOT_CIABR(r1)
+	ld	r6, STACK_SLOT_DAWR(r1)
+	ld	r7, STACK_SLOT_DAWRX(r1)
+	mtspr	SPRN_CIABR, r5
+	mtspr	SPRN_DAWR, r6
+	mtspr	SPRN_DAWRX, r7
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+
 	/*
 	 * POWER7/POWER8 guest -> host partition switch code.
 	 * We don't have to lock against tlbies but we do
@@ -1661,14 +1520,34 @@
 	isync
 
 BEGIN_FTR_SECTION
-	/* DPDES is shared between threads */
+	/* DPDES and VTB are shared between threads */
 	mfspr	r7, SPRN_DPDES
+	mfspr	r8, SPRN_VTB
 	std	r7, VCORE_DPDES(r5)
+	std	r8, VCORE_VTB(r5)
 	/* clear DPDES so we don't get guest doorbells in the host */
 	li	r8, 0
 	mtspr	SPRN_DPDES, r8
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
+	/* If HMI, call kvmppc_realmode_hmi_handler() */
+	cmpwi	r12, BOOK3S_INTERRUPT_HMI
+	bne	27f
+	mr	r3, r9		/* get vcpu pointer */
+	bl	kvmppc_realmode_hmi_handler
+	nop
+	li	r12, BOOK3S_INTERRUPT_HMI
+	/*
+	 * At this point kvmppc_realmode_hmi_handler would have resync-ed
+	 * the TB. Hence it is not required to subtract guest timebase
+	 * offset from timebase. So, skip it.
+	 *
+	 * Also, do not call kvmppc_subcore_exit_guest() because it has
+	 * been invoked as part of kvmppc_realmode_hmi_handler().
+	 */
+	b	30f
+
+27:
 	/* Subtract timebase offset from timebase */
 	ld	r8,VCORE_TB_OFFSET(r5)
 	cmpdi	r8,0
@@ -1684,8 +1563,13 @@
 	addis	r8,r8,0x100		/* if so, increment upper 40 bits */
 	mtspr	SPRN_TBU40,r8
 
+17:	bl	kvmppc_subcore_exit_guest
+	nop
+30:	ld	r5,HSTATE_KVM_VCORE(r13)
+	ld	r4,VCORE_KVM(r5)	/* pointer to struct kvm */
+
 	/* Reset PCR */
-17:	ld	r0, VCORE_PCR(r5)
+	ld	r0, VCORE_PCR(r5)
 	cmpdi	r0, 0
 	beq	18f
 	li	r0, 0
@@ -1727,8 +1611,23 @@
 	li	r0, KVM_GUEST_MODE_NONE
 	stb	r0, HSTATE_IN_GUEST(r13)
 
-	ld	r0, 112+PPC_LR_STKOFF(r1)
-	addi	r1, r1, 112
+	ld	r0, SFS+PPC_LR_STKOFF(r1)
+	addi	r1, r1, SFS
+	mtlr	r0
+	blr
+
+.balign 32
+.global kvm_flush_link_stack
+kvm_flush_link_stack:
+	/* Save LR into r0 */
+	mflr	r0
+
+	/* Flush the link stack. On Power8 it's up to 32 entries in size. */
+	.rept 32
+	bl	.+4
+	.endr
+
+	/* Restore LR */
 	mtlr	r0
 	blr
 
@@ -2153,7 +2052,7 @@
 
 	/* Emulate H_SET_DABR/X on P8 for the sake of compat mode guests */
 2:	rlwimi	r5, r4, 5, DAWRX_DR | DAWRX_DW
-	rlwimi	r5, r4, 1, DAWRX_WT
+	rlwimi	r5, r4, 2, DAWRX_WT
 	clrrdi	r4, r4, 3
 	std	r4, VCPU_DAWR(r3)
 	std	r5, VCPU_DAWRX(r3)
@@ -2231,6 +2130,13 @@
 	/* save FP state */
 	bl	kvmppc_save_fp
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+	ld	r9, HSTATE_KVM_VCPU(r13)
+	bl	kvmppc_save_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+
 	/*
 	 * Set DEC to the smaller of DEC and HDEC, so that we wake
 	 * no later than the end of our timeslice (HDEC interrupts
@@ -2307,6 +2213,12 @@
 	bl	kvmhv_accumulate_time
 #endif
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+	bl	kvmppc_restore_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+
 	/* load up FP state */
 	bl	kvmppc_load_fp
 
@@ -2445,6 +2357,8 @@
 	cmpwi	r6, 3			/* hypervisor doorbell? */
 	beq	3f
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+	cmpwi	r6, 0xa			/* Hypervisor maintenance ? */
+	beq	4f
 	li	r3, 1			/* anything else, return 1 */
 0:	blr
 
@@ -2466,6 +2380,11 @@
 	li	r3, -1
 	blr
 
+	/* Woken up due to Hypervisor maintenance interrupt */
+4:	li	r12, BOOK3S_INTERRUPT_HMI
+	li	r3, 1
+	blr
+
 /*
  * Determine what sort of external interrupt is pending (if any).
  * Returns:
@@ -2615,6 +2534,243 @@
 	mr	r4,r31
 	blr
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Save transactional state and TM-related registers.
+ * Called with r9 pointing to the vcpu struct.
+ * This can modify all checkpointed registers, but
+ * restores r1, r2 and r9 (vcpu pointer) before exit.
+ */
+kvmppc_save_tm:
+	mflr	r0
+	std	r0, PPC_LR_STKOFF(r1)
+
+	/* Turn on TM. */
+	mfmsr	r8
+	li	r0, 1
+	rldimi	r8, r0, MSR_TM_LG, 63-MSR_TM_LG
+	mtmsrd	r8
+
+	ld	r5, VCPU_MSR(r9)
+	rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+	beq	1f	/* TM not active in guest. */
+
+	std	r1, HSTATE_HOST_R1(r13)
+	li	r3, TM_CAUSE_KVM_RESCHED
+
+	/* Clear the MSR RI since r1, r13 are all going to be foobar. */
+	li	r5, 0
+	mtmsrd	r5, 1
+
+	/* All GPRs are volatile at this point. */
+	TRECLAIM(R3)
+
+	/* Temporarily store r13 and r9 so we have some regs to play with */
+	SET_SCRATCH0(r13)
+	GET_PACA(r13)
+	std	r9, PACATMSCRATCH(r13)
+	ld	r9, HSTATE_KVM_VCPU(r13)
+
+	/* Get a few more GPRs free. */
+	std	r29, VCPU_GPRS_TM(29)(r9)
+	std	r30, VCPU_GPRS_TM(30)(r9)
+	std	r31, VCPU_GPRS_TM(31)(r9)
+
+	/* Save away PPR and DSCR soon so don't run with user values. */
+	mfspr	r31, SPRN_PPR
+	HMT_MEDIUM
+	mfspr	r30, SPRN_DSCR
+	ld	r29, HSTATE_DSCR(r13)
+	mtspr	SPRN_DSCR, r29
+
+	/* Save all but r9, r13 & r29-r31 */
+	reg = 0
+	.rept	29
+	.if (reg != 9) && (reg != 13)
+	std	reg, VCPU_GPRS_TM(reg)(r9)
+	.endif
+	reg = reg + 1
+	.endr
+	/* ... now save r13 */
+	GET_SCRATCH0(r4)
+	std	r4, VCPU_GPRS_TM(13)(r9)
+	/* ... and save r9 */
+	ld	r4, PACATMSCRATCH(r13)
+	std	r4, VCPU_GPRS_TM(9)(r9)
+
+	/* Reload stack pointer and TOC. */
+	ld	r1, HSTATE_HOST_R1(r13)
+	ld	r2, PACATOC(r13)
+
+	/* Set MSR RI now we have r1 and r13 back. */
+	li	r5, MSR_RI
+	mtmsrd	r5, 1
+
+	/* Save away checkpinted SPRs. */
+	std	r31, VCPU_PPR_TM(r9)
+	std	r30, VCPU_DSCR_TM(r9)
+	mflr	r5
+	mfcr	r6
+	mfctr	r7
+	mfspr	r8, SPRN_AMR
+	mfspr	r10, SPRN_TAR
+	mfxer	r11
+	std	r5, VCPU_LR_TM(r9)
+	stw	r6, VCPU_CR_TM(r9)
+	std	r7, VCPU_CTR_TM(r9)
+	std	r8, VCPU_AMR_TM(r9)
+	std	r10, VCPU_TAR_TM(r9)
+	std	r11, VCPU_XER_TM(r9)
+
+	/* Restore r12 as trap number. */
+	lwz	r12, VCPU_TRAP(r9)
+
+	/* Save FP/VSX. */
+	addi	r3, r9, VCPU_FPRS_TM
+	bl	store_fp_state
+	addi	r3, r9, VCPU_VRS_TM
+	bl	store_vr_state
+	mfspr	r6, SPRN_VRSAVE
+	stw	r6, VCPU_VRSAVE_TM(r9)
+1:
+	/*
+	 * We need to save these SPRs after the treclaim so that the software
+	 * error code is recorded correctly in the TEXASR.  Also the user may
+	 * change these outside of a transaction, so they must always be
+	 * context switched.
+	 */
+	mfspr	r5, SPRN_TFHAR
+	mfspr	r6, SPRN_TFIAR
+	mfspr	r7, SPRN_TEXASR
+	std	r5, VCPU_TFHAR(r9)
+	std	r6, VCPU_TFIAR(r9)
+	std	r7, VCPU_TEXASR(r9)
+
+	ld	r0, PPC_LR_STKOFF(r1)
+	mtlr	r0
+	blr
+
+/*
+ * Restore transactional state and TM-related registers.
+ * Called with r4 pointing to the vcpu struct.
+ * This potentially modifies all checkpointed registers.
+ * It restores r1, r2, r4 from the PACA.
+ */
+kvmppc_restore_tm:
+	mflr	r0
+	std	r0, PPC_LR_STKOFF(r1)
+
+	/* Turn on TM/FP/VSX/VMX so we can restore them. */
+	mfmsr	r5
+	li	r6, MSR_TM >> 32
+	sldi	r6, r6, 32
+	or	r5, r5, r6
+	ori	r5, r5, MSR_FP
+	oris	r5, r5, (MSR_VEC | MSR_VSX)@h
+	mtmsrd	r5
+
+	/*
+	 * The user may change these outside of a transaction, so they must
+	 * always be context switched.
+	 */
+	ld	r5, VCPU_TFHAR(r4)
+	ld	r6, VCPU_TFIAR(r4)
+	ld	r7, VCPU_TEXASR(r4)
+	mtspr	SPRN_TFHAR, r5
+	mtspr	SPRN_TFIAR, r6
+	mtspr	SPRN_TEXASR, r7
+
+	ld	r5, VCPU_MSR(r4)
+	rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+	beqlr		/* TM not active in guest */
+	std	r1, HSTATE_HOST_R1(r13)
+
+	/* Make sure the failure summary is set, otherwise we'll program check
+	 * when we trechkpt.  It's possible that this might have been not set
+	 * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
+	 * host.
+	 */
+	oris	r7, r7, (TEXASR_FS)@h
+	mtspr	SPRN_TEXASR, r7
+
+	/*
+	 * We need to load up the checkpointed state for the guest.
+	 * We need to do this early as it will blow away any GPRs, VSRs and
+	 * some SPRs.
+	 */
+
+	mr	r31, r4
+	addi	r3, r31, VCPU_FPRS_TM
+	bl	load_fp_state
+	addi	r3, r31, VCPU_VRS_TM
+	bl	load_vr_state
+	mr	r4, r31
+	lwz	r7, VCPU_VRSAVE_TM(r4)
+	mtspr	SPRN_VRSAVE, r7
+
+	ld	r5, VCPU_LR_TM(r4)
+	lwz	r6, VCPU_CR_TM(r4)
+	ld	r7, VCPU_CTR_TM(r4)
+	ld	r8, VCPU_AMR_TM(r4)
+	ld	r9, VCPU_TAR_TM(r4)
+	ld	r10, VCPU_XER_TM(r4)
+	mtlr	r5
+	mtcr	r6
+	mtctr	r7
+	mtspr	SPRN_AMR, r8
+	mtspr	SPRN_TAR, r9
+	mtxer	r10
+
+	/*
+	 * Load up PPR and DSCR values but don't put them in the actual SPRs
+	 * till the last moment to avoid running with userspace PPR and DSCR for
+	 * too long.
+	 */
+	ld	r29, VCPU_DSCR_TM(r4)
+	ld	r30, VCPU_PPR_TM(r4)
+
+	std	r2, PACATMSCRATCH(r13) /* Save TOC */
+
+	/* Clear the MSR RI since r1, r13 are all going to be foobar. */
+	li	r5, 0
+	mtmsrd	r5, 1
+
+	/* Load GPRs r0-r28 */
+	reg = 0
+	.rept	29
+	ld	reg, VCPU_GPRS_TM(reg)(r31)
+	reg = reg + 1
+	.endr
+
+	mtspr	SPRN_DSCR, r29
+	mtspr	SPRN_PPR, r30
+
+	/* Load final GPRs */
+	ld	29, VCPU_GPRS_TM(29)(r31)
+	ld	30, VCPU_GPRS_TM(30)(r31)
+	ld	31, VCPU_GPRS_TM(31)(r31)
+
+	/* TM checkpointed state is now setup.  All GPRs are now volatile. */
+	TRECHKPT
+
+	/* Now let's get back the state we need. */
+	HMT_MEDIUM
+	GET_PACA(r13)
+	ld	r29, HSTATE_DSCR(r13)
+	mtspr	SPRN_DSCR, r29
+	ld	r4, HSTATE_KVM_VCPU(r13)
+	ld	r1, HSTATE_HOST_R1(r13)
+	ld	r2, PACATMSCRATCH(r13)
+
+	/* Set the MSR RI since we have our registers back. */
+	li	r5, MSR_RI
+	mtmsrd	r5, 1
+
+	ld	r0, PPC_LR_STKOFF(r1)
+	mtlr	r0
+	blr
+#endif
+
 /*
  * We come here if we get any exception or interrupt while we are
  * executing host real mode code while in guest MMU context.
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_paired_singles.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_paired_singles.c
@@ -1265,6 +1265,7 @@
 	if (rcomp)
 		kvmppc_set_cr(vcpu, cr);
 
+	disable_kernel_fp();
 	preempt_enable();
 
 	return emulated;
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_pr.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_pr.c
@@ -226,7 +226,7 @@
 	 */
 	vcpu->arch.purr += get_tb() - vcpu->arch.entry_tb;
 	vcpu->arch.spurr += get_tb() - vcpu->arch.entry_tb;
-	vcpu->arch.vtb += get_vtb() - vcpu->arch.entry_vtb;
+	to_book3s(vcpu)->vtb += get_vtb() - vcpu->arch.entry_vtb;
 	if (cpu_has_feature(CPU_FTR_ARCH_207S))
 		vcpu->arch.ic += mfspr(SPRN_IC) - vcpu->arch.entry_ic;
 	svcpu->in_use = false;
@@ -625,7 +625,11 @@
 			kvmppc_mmu_unmap_page(vcpu, &pte);
 		}
 		/* The guest's PTE is not mapped yet. Map on the host */
-		kvmppc_mmu_map_page(vcpu, &pte, iswrite);
+		if (kvmppc_mmu_map_page(vcpu, &pte, iswrite) == -EIO) {
+			/* Exit KVM if mapping failed */
+			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+			return RESUME_HOST;
+		}
 		if (data)
 			vcpu->stat.sp_storage++;
 		else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
@@ -751,6 +755,7 @@
 		preempt_disable();
 		enable_kernel_fp();
 		load_fp_state(&vcpu->arch.fp);
+		disable_kernel_fp();
 		t->fp_save_area = &vcpu->arch.fp;
 		preempt_enable();
 	}
@@ -760,6 +765,7 @@
 		preempt_disable();
 		enable_kernel_altivec();
 		load_vr_state(&vcpu->arch.vr);
+		disable_kernel_altivec();
 		t->vr_save_area = &vcpu->arch.vr;
 		preempt_enable();
 #endif
@@ -788,6 +794,7 @@
 		preempt_disable();
 		enable_kernel_fp();
 		load_fp_state(&vcpu->arch.fp);
+		disable_kernel_fp();
 		preempt_enable();
 	}
 #ifdef CONFIG_ALTIVEC
@@ -795,6 +802,7 @@
 		preempt_disable();
 		enable_kernel_altivec();
 		load_vr_state(&vcpu->arch.vr);
+		disable_kernel_altivec();
 		preempt_enable();
 	}
 #endif
@@ -1321,6 +1329,9 @@
 	case KVM_REG_PPC_HIOR:
 		*val = get_reg_val(id, to_book3s(vcpu)->hior);
 		break;
+	case KVM_REG_PPC_VTB:
+		*val = get_reg_val(id, to_book3s(vcpu)->vtb);
+		break;
 	case KVM_REG_PPC_LPCR:
 	case KVM_REG_PPC_LPCR_64:
 		/*
@@ -1357,6 +1368,9 @@
 		to_book3s(vcpu)->hior = set_reg_val(id, *val);
 		to_book3s(vcpu)->hior_explicit = true;
 		break;
+	case KVM_REG_PPC_VTB:
+		to_book3s(vcpu)->vtb = set_reg_val(id, *val);
+		break;
 	case KVM_REG_PPC_LPCR:
 	case KVM_REG_PPC_LPCR_64:
 		kvmppc_set_lpcr_pr(vcpu, set_reg_val(id, *val));
@@ -1430,10 +1444,12 @@
 
 	err = kvmppc_mmu_init(vcpu);
 	if (err < 0)
-		goto uninit_vcpu;
+		goto free_shared_page;
 
 	return vcpu;
 
+free_shared_page:
+	free_page((unsigned long)vcpu->arch.shared);
 uninit_vcpu:
 	kvm_vcpu_uninit(vcpu);
 free_shadow_vcpu:
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_pr_papr.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_pr_papr.c
@@ -50,7 +50,9 @@
 	pteg_addr = get_pteg_addr(vcpu, pte_index);
 
 	mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-	copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
+	ret = H_FUNCTION;
+	if (copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)))
+		goto done;
 	hpte = pteg;
 
 	ret = H_PTEG_FULL;
@@ -71,7 +73,9 @@
 	hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6));
 	hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7));
 	pteg_addr += i * HPTE_SIZE;
-	copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE);
+	ret = H_FUNCTION;
+	if (copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE))
+		goto done;
 	kvmppc_set_gpr(vcpu, 4, pte_index | i);
 	ret = H_SUCCESS;
 
@@ -93,7 +97,9 @@
 
 	pteg = get_pteg_addr(vcpu, pte_index);
 	mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-	copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+	ret = H_FUNCTION;
+	if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
+		goto done;
 	pte[0] = be64_to_cpu((__force __be64)pte[0]);
 	pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -103,7 +109,9 @@
 	    ((flags & H_ANDCOND) && (pte[0] & avpn) != 0))
 		goto done;
 
-	copy_to_user((void __user *)pteg, &v, sizeof(v));
+	ret = H_FUNCTION;
+	if (copy_to_user((void __user *)pteg, &v, sizeof(v)))
+		goto done;
 
 	rb = compute_tlbie_rb(pte[0], pte[1], pte_index);
 	vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
@@ -171,7 +179,10 @@
 		}
 
 		pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
-		copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+		if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) {
+			ret = H_FUNCTION;
+			break;
+		}
 		pte[0] = be64_to_cpu((__force __be64)pte[0]);
 		pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -184,7 +195,10 @@
 			tsh |= H_BULK_REMOVE_NOT_FOUND;
 		} else {
 			/* Splat the pteg in (userland) hpt */
-			copy_to_user((void __user *)pteg, &v, sizeof(v));
+			if (copy_to_user((void __user *)pteg, &v, sizeof(v))) {
+				ret = H_FUNCTION;
+				break;
+			}
 
 			rb = compute_tlbie_rb(pte[0], pte[1],
 					      tsh & H_BULK_REMOVE_PTEX);
@@ -211,7 +225,9 @@
 
 	pteg = get_pteg_addr(vcpu, pte_index);
 	mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-	copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+	ret = H_FUNCTION;
+	if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
+		goto done;
 	pte[0] = be64_to_cpu((__force __be64)pte[0]);
 	pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -234,7 +250,9 @@
 	vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
 	pte[0] = (__force u64)cpu_to_be64(pte[0]);
 	pte[1] = (__force u64)cpu_to_be64(pte[1]);
-	copy_to_user((void __user *)pteg, pte, sizeof(pte));
+	ret = H_FUNCTION;
+	if (copy_to_user((void __user *)pteg, pte, sizeof(pte)))
+		goto done;
 	ret = H_SUCCESS;
 
  done:
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_rmhandlers.S
+++ linux-4.4.0/arch/powerpc/kvm/book3s_rmhandlers.S
@@ -46,6 +46,9 @@
 
 #define FUNC(name)		name
 
+#define RFI_TO_KERNEL	RFI
+#define RFI_TO_GUEST	RFI
+
 .macro INTERRUPT_TRAMPOLINE intno
 
 .global kvmppc_trampoline_\intno
@@ -141,7 +144,7 @@
 	GET_SCRATCH0(r13)
 
 	/* And get back into the code */
-	RFI
+	RFI_TO_KERNEL
 #endif
 
 /*
@@ -164,6 +167,6 @@
 	ori	r5, r5, MSR_EE
 	mtsrr0	r7
 	mtsrr1	r6
-	RFI
+	RFI_TO_KERNEL
 
 #include "book3s_segment.S"
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_rtas.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_rtas.c
@@ -133,7 +133,7 @@
 {
 	struct rtas_token_definition *d, *tmp;
 
-	lockdep_assert_held(&kvm->lock);
+	lockdep_assert_held(&kvm->arch.rtas_token_lock);
 
 	list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) {
 		if (rtas_name_matches(d->handler->name, name)) {
@@ -154,7 +154,7 @@
 	bool found;
 	int i;
 
-	lockdep_assert_held(&kvm->lock);
+	lockdep_assert_held(&kvm->arch.rtas_token_lock);
 
 	list_for_each_entry(d, &kvm->arch.rtas_tokens, list) {
 		if (d->token == token)
@@ -193,14 +193,14 @@
 	if (copy_from_user(&args, argp, sizeof(args)))
 		return -EFAULT;
 
-	mutex_lock(&kvm->lock);
+	mutex_lock(&kvm->arch.rtas_token_lock);
 
 	if (args.token)
 		rc = rtas_token_define(kvm, args.name, args.token);
 	else
 		rc = rtas_token_undefine(kvm, args.name);
 
-	mutex_unlock(&kvm->lock);
+	mutex_unlock(&kvm->arch.rtas_token_lock);
 
 	return rc;
 }
@@ -232,7 +232,7 @@
 	orig_rets = args.rets;
 	args.rets = &args.args[be32_to_cpu(args.nargs)];
 
-	mutex_lock(&vcpu->kvm->lock);
+	mutex_lock(&vcpu->kvm->arch.rtas_token_lock);
 
 	rc = -ENOENT;
 	list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) {
@@ -243,7 +243,7 @@
 		}
 	}
 
-	mutex_unlock(&vcpu->kvm->lock);
+	mutex_unlock(&vcpu->kvm->arch.rtas_token_lock);
 
 	if (rc == 0) {
 		args.rets = orig_rets;
@@ -269,8 +269,6 @@
 {
 	struct rtas_token_definition *d, *tmp;
 
-	lockdep_assert_held(&kvm->lock);
-
 	list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) {
 		list_del(&d->list);
 		kfree(d);
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_segment.S
+++ linux-4.4.0/arch/powerpc/kvm/book3s_segment.S
@@ -156,7 +156,7 @@
 	PPC_LL	r9, SVCPU_R9(r3)
 	PPC_LL	r3, (SVCPU_R3)(r3)
 
-	RFI
+	RFI_TO_GUEST
 kvmppc_handler_trampoline_enter_end:
 
 
@@ -389,5 +389,5 @@
 	cmpwi	r12, BOOK3S_INTERRUPT_DOORBELL
 	beqa	BOOK3S_INTERRUPT_DOORBELL
 
-	RFI
+	RFI_TO_KERNEL
 kvmppc_handler_trampoline_exit_end:
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_xics.c
+++ linux-4.4.0/arch/powerpc/kvm/book3s_xics.c
@@ -92,7 +92,7 @@
 	 * we are the only setter, thus concurrent access is undefined
 	 * to begin with.
 	 */
-	if (level == 1 || level == KVM_INTERRUPT_SET_LEVEL)
+	if ((level == 1 && state->lsi) || level == KVM_INTERRUPT_SET_LEVEL)
 		state->asserted = 1;
 	else if (level == 0 || level == KVM_INTERRUPT_UNSET) {
 		state->asserted = 0;
@@ -1174,9 +1174,11 @@
 			prio = irqp->saved_priority;
 		}
 		val |= prio << KVM_XICS_PRIORITY_SHIFT;
-		if (irqp->asserted)
-			val |= KVM_XICS_LEVEL_SENSITIVE | KVM_XICS_PENDING;
-		else if (irqp->masked_pending || irqp->resend)
+		if (irqp->lsi) {
+			val |= KVM_XICS_LEVEL_SENSITIVE;
+			if (irqp->asserted)
+				val |= KVM_XICS_PENDING;
+		} else if (irqp->masked_pending || irqp->resend)
 			val |= KVM_XICS_PENDING;
 		ret = 0;
 	}
@@ -1228,9 +1230,13 @@
 	irqp->priority = prio;
 	irqp->resend = 0;
 	irqp->masked_pending = 0;
+	irqp->lsi = 0;
 	irqp->asserted = 0;
-	if ((val & KVM_XICS_PENDING) && (val & KVM_XICS_LEVEL_SENSITIVE))
-		irqp->asserted = 1;
+	if (val & KVM_XICS_LEVEL_SENSITIVE) {
+		irqp->lsi = 1;
+		if (val & KVM_XICS_PENDING)
+			irqp->asserted = 1;
+	}
 	irqp->exists = 1;
 	arch_spin_unlock(&ics->lock);
 	local_irq_restore(flags);
@@ -1249,11 +1255,10 @@
 	return ics_deliver_irq(xics, irq, level);
 }
 
-int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm,
-		int irq_source_id, int level, bool line_status)
+int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *irq_entry,
+			      struct kvm *kvm, int irq_source_id,
+			      int level, bool line_status)
 {
-	if (!level)
-		return -1;
 	return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi,
 			   level, line_status);
 }
--- linux-4.4.0.orig/arch/powerpc/kvm/book3s_xics.h
+++ linux-4.4.0/arch/powerpc/kvm/book3s_xics.h
@@ -39,6 +39,7 @@
 	u8  saved_priority;
 	u8  resend;
 	u8  masked_pending;
+	u8  lsi;		/* level-sensitive interrupt */
 	u8  asserted; /* Only for LSI */
 	u8  exists;
 };
--- linux-4.4.0.orig/arch/powerpc/kvm/booke.c
+++ linux-4.4.0/arch/powerpc/kvm/booke.c
@@ -98,6 +98,7 @@
 	preempt_disable();
 	enable_kernel_spe();
 	kvmppc_save_guest_spe(vcpu);
+	disable_kernel_spe();
 	vcpu->arch.shadow_msr &= ~MSR_SPE;
 	preempt_enable();
 }
@@ -107,6 +108,7 @@
 	preempt_disable();
 	enable_kernel_spe();
 	kvmppc_load_guest_spe(vcpu);
+	disable_kernel_spe();
 	vcpu->arch.shadow_msr |= MSR_SPE;
 	preempt_enable();
 }
@@ -141,6 +143,7 @@
 	if (!(current->thread.regs->msr & MSR_FP)) {
 		enable_kernel_fp();
 		load_fp_state(&vcpu->arch.fp);
+		disable_kernel_fp();
 		current->thread.fp_save_area = &vcpu->arch.fp;
 		current->thread.regs->msr |= MSR_FP;
 	}
@@ -182,6 +185,7 @@
 		if (!(current->thread.regs->msr & MSR_VEC)) {
 			enable_kernel_altivec();
 			load_vr_state(&vcpu->arch.vr);
+			disable_kernel_altivec();
 			current->thread.vr_save_area = &vcpu->arch.vr;
 			current->thread.regs->msr |= MSR_VEC;
 		}
@@ -2033,7 +2037,7 @@
 		if (type == KVMPPC_DEBUG_NONE)
 			continue;
 
-		if (type & !(KVMPPC_DEBUG_WATCH_READ |
+		if (type & ~(KVMPPC_DEBUG_WATCH_READ |
 			     KVMPPC_DEBUG_WATCH_WRITE |
 			     KVMPPC_DEBUG_BREAKPOINT))
 			return -EINVAL;
--- linux-4.4.0.orig/arch/powerpc/kvm/bookehv_interrupts.S
+++ linux-4.4.0/arch/powerpc/kvm/bookehv_interrupts.S
@@ -75,6 +75,10 @@
 	PPC_LL	r1, VCPU_HOST_STACK(r4)
 	PPC_LL	r2, HOST_R2(r1)
 
+START_BTB_FLUSH_SECTION
+	BTB_FLUSH(r10)
+END_BTB_FLUSH_SECTION
+
 	mfspr	r10, SPRN_PID
 	lwz	r8, VCPU_HOST_PID(r4)
 	PPC_LL	r11, VCPU_SHARED(r4)
--- linux-4.4.0.orig/arch/powerpc/kvm/e500_emulate.c
+++ linux-4.4.0/arch/powerpc/kvm/e500_emulate.c
@@ -277,6 +277,13 @@
 		vcpu->arch.pwrmgtcr0 = spr_val;
 		break;
 
+	case SPRN_BUCSR:
+		/*
+		 * If we are here, it means that we have already flushed the
+		 * branch predictor, so just return to guest.
+		 */
+		break;
+
 	/* extra exceptions */
 #ifdef CONFIG_SPE_POSSIBLE
 	case SPRN_IVOR32:
--- linux-4.4.0.orig/arch/powerpc/kvm/emulate.c
+++ linux-4.4.0/arch/powerpc/kvm/emulate.c
@@ -302,7 +302,6 @@
 			advance = 0;
 			printk(KERN_ERR "Couldn't emulate instruction 0x%08x "
 			       "(op %d xop %d)\n", inst, get_op(inst), get_xop(inst));
-			kvmppc_core_queue_program(vcpu, 0);
 		}
 	}
 
--- linux-4.4.0.orig/arch/powerpc/kvm/powerpc.c
+++ linux-4.4.0/arch/powerpc/kvm/powerpc.c
@@ -919,21 +919,17 @@
 				r = -ENXIO;
 				break;
 			}
-			vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval;
+			val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0];
 			break;
 		case KVM_REG_PPC_VSCR:
 			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
 				r = -ENXIO;
 				break;
 			}
-			vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val);
+			val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]);
 			break;
 		case KVM_REG_PPC_VRSAVE:
-			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
-				r = -ENXIO;
-				break;
-			}
-			vcpu->arch.vrsave = set_reg_val(reg->id, val);
+			val = get_reg_val(reg->id, vcpu->arch.vrsave);
 			break;
 #endif /* CONFIG_ALTIVEC */
 		default:
@@ -974,17 +970,21 @@
 				r = -ENXIO;
 				break;
 			}
-			val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0];
+			vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval;
 			break;
 		case KVM_REG_PPC_VSCR:
 			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
 				r = -ENXIO;
 				break;
 			}
-			val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]);
+			vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val);
 			break;
 		case KVM_REG_PPC_VRSAVE:
-			val = get_reg_val(reg->id, vcpu->arch.vrsave);
+			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+				r = -ENXIO;
+				break;
+			}
+			vcpu->arch.vrsave = set_reg_val(reg->id, val);
 			break;
 #endif /* CONFIG_ALTIVEC */
 		default:
--- linux-4.4.0.orig/arch/powerpc/kvm/trace.h
+++ linux-4.4.0/arch/powerpc/kvm/trace.h
@@ -5,8 +5,6 @@
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE trace
 
 /*
  * Tracepoint for guest mode entry.
@@ -119,4 +117,10 @@
 #endif /* _TRACE_KVM_H */
 
 /* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace
+
 #include <trace/define_trace.h>
--- linux-4.4.0.orig/arch/powerpc/kvm/trace_booke.h
+++ linux-4.4.0/arch/powerpc/kvm/trace_booke.h
@@ -5,8 +5,6 @@
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm_booke
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE trace_booke
 
 #define kvm_trace_symbol_exit \
 	{0, "CRITICAL"}, \
@@ -217,4 +215,11 @@
 #endif
 
 /* This part must be outside protection */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_booke
+
 #include <trace/define_trace.h>
--- linux-4.4.0.orig/arch/powerpc/kvm/trace_hv.h
+++ linux-4.4.0/arch/powerpc/kvm/trace_hv.h
@@ -8,8 +8,6 @@
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm_hv
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE trace_hv
 
 #define kvm_trace_symbol_hcall \
 	{H_REMOVE,			"H_REMOVE"}, \
@@ -474,4 +472,11 @@
 #endif /* _TRACE_KVM_HV_H */
 
 /* This part must be outside protection */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_hv
+
 #include <trace/define_trace.h>
--- linux-4.4.0.orig/arch/powerpc/kvm/trace_pr.h
+++ linux-4.4.0/arch/powerpc/kvm/trace_pr.h
@@ -7,8 +7,6 @@
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm_pr
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE trace_pr
 
 TRACE_EVENT(kvm_book3s_reenter,
 	TP_PROTO(int r, struct kvm_vcpu *vcpu),
@@ -271,4 +269,11 @@
 #endif /* _TRACE_KVM_H */
 
 /* This part must be outside protection */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_pr
+
 #include <trace/define_trace.h>
--- linux-4.4.0.orig/arch/powerpc/lib/checksum_wrappers_64.c
+++ linux-4.4.0/arch/powerpc/lib/checksum_wrappers_64.c
@@ -29,6 +29,7 @@
 	unsigned int csum;
 
 	might_sleep();
+	allow_read_from_user(src, len);
 
 	*err_ptr = 0;
 
@@ -60,6 +61,7 @@
 	}
 
 out:
+	prevent_read_from_user(src, len);
 	return (__force __wsum)csum;
 }
 EXPORT_SYMBOL(csum_and_copy_from_user);
@@ -70,6 +72,7 @@
 	unsigned int csum;
 
 	might_sleep();
+	allow_write_to_user(dst, len);
 
 	*err_ptr = 0;
 
@@ -97,6 +100,7 @@
 	}
 
 out:
+	prevent_write_to_user(dst, len);
 	return (__force __wsum)csum;
 }
 EXPORT_SYMBOL(csum_and_copy_to_user);
--- linux-4.4.0.orig/arch/powerpc/lib/code-patching.c
+++ linux-4.4.0/arch/powerpc/lib/code-patching.c
@@ -14,12 +14,25 @@
 #include <asm/page.h>
 #include <asm/code-patching.h>
 #include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/sections.h>
 
 
+static inline bool is_init(unsigned int *addr)
+{
+	return addr >= (unsigned int *)__init_begin && addr < (unsigned int *)__init_end;
+}
+
 int patch_instruction(unsigned int *addr, unsigned int instr)
 {
 	int err;
 
+	/* Make sure we aren't patching a freed init section */
+	if (*PTRRELOC(&init_mem_is_free) && is_init(addr)) {
+		pr_debug("Skipping init section patching addr: 0x%px\n", addr);
+		return 0;
+	}
+
 	__put_user_size(instr, addr, 4, err);
 	if (err)
 		return err;
@@ -32,6 +45,22 @@
 	return patch_instruction(addr, create_branch(addr, target, flags));
 }
 
+int patch_branch_site(s32 *site, unsigned long target, int flags)
+{
+	unsigned int *addr;
+
+	addr = (unsigned int *)((unsigned long)site + *site);
+	return patch_instruction(addr, create_branch(addr, target, flags));
+}
+
+int patch_instruction_site(s32 *site, unsigned int instr)
+{
+	unsigned int *addr;
+
+	addr = (unsigned int *)((unsigned long)site + *site);
+	return patch_instruction(addr, instr);
+}
+
 unsigned int create_branch(const unsigned int *addr,
 			   unsigned long target, int flags)
 {
--- linux-4.4.0.orig/arch/powerpc/lib/copyuser_64.S
+++ linux-4.4.0/arch/powerpc/lib/copyuser_64.S
@@ -359,6 +359,7 @@
 	addi	r3,r3,8
 171:
 177:
+179:
 	addi	r3,r3,8
 370:
 372:
@@ -373,7 +374,6 @@
 173:
 174:
 175:
-179:
 181:
 184:
 186:
--- linux-4.4.0.orig/arch/powerpc/lib/feature-fixups.c
+++ linux-4.4.0/arch/powerpc/lib/feature-fixups.c
@@ -20,7 +20,8 @@
 #include <asm/code-patching.h>
 #include <asm/page.h>
 #include <asm/sections.h>
-
+#include <asm/setup.h>
+#include <asm/security_features.h>
 
 struct fixup_entry {
 	unsigned long	mask;
@@ -52,7 +53,7 @@
 		unsigned int *target = (unsigned int *)branch_target(src);
 
 		/* Branch within the section doesn't need translating */
-		if (target < alt_start || target >= alt_end) {
+		if (target < alt_start || target > alt_end) {
 			instr = translate_branch(dest, src);
 			if (!instr)
 				return 1;
@@ -113,6 +114,379 @@
 	}
 }
 
+#ifdef CONFIG_PPC_BOOK3S_64
+void do_stf_entry_barrier_fixups(enum stf_barrier_type types)
+{
+	unsigned int instrs[3], *dest;
+	long *start, *end;
+	int i;
+
+	start = PTRRELOC(&__start___stf_entry_barrier_fixup),
+	end = PTRRELOC(&__stop___stf_entry_barrier_fixup);
+
+	instrs[0] = 0x60000000; /* nop */
+	instrs[1] = 0x60000000; /* nop */
+	instrs[2] = 0x60000000; /* nop */
+
+	i = 0;
+	if (types & STF_BARRIER_FALLBACK) {
+		instrs[i++] = 0x7d4802a6; /* mflr r10		*/
+		instrs[i++] = 0x60000000; /* branch patched below */
+		instrs[i++] = 0x7d4803a6; /* mtlr r10		*/
+	} else if (types & STF_BARRIER_EIEIO) {
+		instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */
+	} else if (types & STF_BARRIER_SYNC_ORI) {
+		instrs[i++] = 0x7c0004ac; /* hwsync		*/
+		instrs[i++] = 0xe94d0000; /* ld r10,0(r13)	*/
+		instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+	}
+
+	for (i = 0; start < end; start++, i++) {
+		dest = (void *)start + *start;
+
+		pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+		patch_instruction(dest, instrs[0]);
+
+		if (types & STF_BARRIER_FALLBACK)
+			patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback,
+				     BRANCH_SET_LINK);
+		else
+			patch_instruction(dest + 1, instrs[1]);
+
+		patch_instruction(dest + 2, instrs[2]);
+	}
+
+	printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i,
+		(types == STF_BARRIER_NONE)                  ? "no" :
+		(types == STF_BARRIER_FALLBACK)              ? "fallback" :
+		(types == STF_BARRIER_EIEIO)                 ? "eieio" :
+		(types == (STF_BARRIER_SYNC_ORI))            ? "hwsync"
+		                                           : "unknown");
+}
+
+void do_stf_exit_barrier_fixups(enum stf_barrier_type types)
+{
+	unsigned int instrs[6], *dest;
+	long *start, *end;
+	int i;
+
+	start = PTRRELOC(&__start___stf_exit_barrier_fixup),
+	end = PTRRELOC(&__stop___stf_exit_barrier_fixup);
+
+	instrs[0] = 0x60000000; /* nop */
+	instrs[1] = 0x60000000; /* nop */
+	instrs[2] = 0x60000000; /* nop */
+	instrs[3] = 0x60000000; /* nop */
+	instrs[4] = 0x60000000; /* nop */
+	instrs[5] = 0x60000000; /* nop */
+
+	i = 0;
+	if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) {
+		if (cpu_has_feature(CPU_FTR_HVMODE)) {
+			instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */
+			instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */
+		} else {
+			instrs[i++] = 0x7db243a6; /* mtsprg 2,r13	*/
+			instrs[i++] = 0x7db142a6; /* mfsprg r13,1    */
+	        }
+		instrs[i++] = 0x7c0004ac; /* hwsync		*/
+		instrs[i++] = 0xe9ad0000; /* ld r13,0(r13)	*/
+		instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+		if (cpu_has_feature(CPU_FTR_HVMODE)) {
+			instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */
+		} else {
+			instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */
+		}
+	} else if (types & STF_BARRIER_EIEIO) {
+		instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */
+	}
+
+	for (i = 0; start < end; start++, i++) {
+		dest = (void *)start + *start;
+
+		pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+		patch_instruction(dest, instrs[0]);
+		patch_instruction(dest + 1, instrs[1]);
+		patch_instruction(dest + 2, instrs[2]);
+		patch_instruction(dest + 3, instrs[3]);
+		patch_instruction(dest + 4, instrs[4]);
+		patch_instruction(dest + 5, instrs[5]);
+	}
+	printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i,
+		(types == STF_BARRIER_NONE)                  ? "no" :
+		(types == STF_BARRIER_FALLBACK)              ? "fallback" :
+		(types == STF_BARRIER_EIEIO)                 ? "eieio" :
+		(types == (STF_BARRIER_SYNC_ORI))            ? "hwsync"
+		                                           : "unknown");
+}
+
+
+void do_stf_barrier_fixups(enum stf_barrier_type types)
+{
+	do_stf_entry_barrier_fixups(types);
+	do_stf_exit_barrier_fixups(types);
+}
+
+void do_uaccess_flush_fixups(enum l1d_flush_type types)
+{
+	unsigned int instrs[4], *dest;
+	long *start, *end;
+	int i;
+
+	start = PTRRELOC(&__start___uaccess_flush_fixup);
+	end = PTRRELOC(&__stop___uaccess_flush_fixup);
+
+	instrs[0] = 0x60000000; /* nop */
+	instrs[1] = 0x60000000; /* nop */
+	instrs[2] = 0x60000000; /* nop */
+	instrs[3] = 0x4e800020; /* blr */
+
+	i = 0;
+	if (types == L1D_FLUSH_FALLBACK) {
+		instrs[3] = 0x60000000; /* nop */
+		/* fallthrough to fallback flush */
+	}
+
+	if (types & L1D_FLUSH_ORI) {
+		instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+		instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
+	}
+
+	if (types & L1D_FLUSH_MTTRIG)
+		instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
+
+	for (i = 0; start < end; start++, i++) {
+		dest = (void *)start + *start;
+
+		pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+		patch_instruction(dest, instrs[0]);
+
+		patch_instruction((dest + 1), instrs[1]);
+		patch_instruction((dest + 2), instrs[2]);
+		patch_instruction((dest + 3), instrs[3]);
+	}
+
+	printk(KERN_DEBUG "uaccess-flush: patched %d locations (%s flush)\n", i,
+		(types == L1D_FLUSH_NONE)       ? "no" :
+		(types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
+		(types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
+							? "ori+mttrig type"
+							: "ori type" :
+		(types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
+						: "unknown");
+}
+
+static int __do_entry_flush_fixups(void *data)
+{
+	enum l1d_flush_type types = *(enum l1d_flush_type *)data;
+	unsigned int instrs[3], *dest;
+	long *start, *end;
+	int i;
+
+	start = PTRRELOC(&__start___entry_flush_fixup);
+	end = PTRRELOC(&__stop___entry_flush_fixup);
+
+	instrs[0] = 0x60000000; /* nop */
+	instrs[1] = 0x60000000; /* nop */
+	instrs[2] = 0x60000000; /* nop */
+
+	i = 0;
+	if (types == L1D_FLUSH_FALLBACK) {
+		instrs[i++] = 0x7d4802a6; /* mflr r10		*/
+		instrs[i++] = 0x60000000; /* branch patched below */
+		instrs[i++] = 0x7d4803a6; /* mtlr r10		*/
+	}
+
+	if (types & L1D_FLUSH_ORI) {
+		instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+		instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
+	}
+
+	if (types & L1D_FLUSH_MTTRIG)
+		instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
+
+	for (i = 0; start < end; start++, i++) {
+		dest = (void *)start + *start;
+
+		pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+		patch_instruction(dest, instrs[0]);
+
+		if (types == L1D_FLUSH_FALLBACK)
+			patch_branch((dest + 1), (unsigned long)&entry_flush_fallback,
+				     BRANCH_SET_LINK);
+		else
+			patch_instruction((dest + 1), instrs[1]);
+
+		patch_instruction((dest + 2), instrs[2]);
+	}
+
+	printk(KERN_DEBUG "entry-flush: patched %d locations (%s flush)\n", i,
+		(types == L1D_FLUSH_NONE)       ? "no" :
+		(types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
+		(types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
+							? "ori+mttrig type"
+							: "ori type" :
+		(types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
+						: "unknown");
+
+	return 0;
+}
+
+void do_entry_flush_fixups(enum l1d_flush_type types)
+{
+	/*
+	 * The call to the fallback flush can not be safely patched in/out while
+	 * other CPUs are executing it. So call __do_entry_flush_fixups() on one
+	 * CPU while all other CPUs spin in the stop machine core with interrupts
+	 * hard disabled.
+	 */
+	stop_machine(__do_entry_flush_fixups, &types, NULL);
+}
+
+void do_rfi_flush_fixups(enum l1d_flush_type types)
+{
+	unsigned int instrs[3], *dest;
+	long *start, *end;
+	int i;
+
+	start = PTRRELOC(&__start___rfi_flush_fixup),
+	end = PTRRELOC(&__stop___rfi_flush_fixup);
+
+	instrs[0] = 0x60000000; /* nop */
+	instrs[1] = 0x60000000; /* nop */
+	instrs[2] = 0x60000000; /* nop */
+
+	if (types & L1D_FLUSH_FALLBACK)
+		/* b .+16 to fallback flush */
+		instrs[0] = 0x48000010;
+
+	i = 0;
+	if (types & L1D_FLUSH_ORI) {
+		instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+		instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
+	}
+
+	if (types & L1D_FLUSH_MTTRIG)
+		instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
+
+	for (i = 0; start < end; start++, i++) {
+		dest = (void *)start + *start;
+
+		pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+		patch_instruction(dest, instrs[0]);
+		patch_instruction(dest + 1, instrs[1]);
+		patch_instruction(dest + 2, instrs[2]);
+	}
+
+	printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
+		(types == L1D_FLUSH_NONE)       ? "no" :
+		(types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
+		(types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
+							? "ori+mttrig type"
+							: "ori type" :
+		(types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
+						: "unknown");
+}
+
+void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
+{
+	unsigned int instr, *dest;
+	long *start, *end;
+	int i;
+
+	start = fixup_start;
+	end = fixup_end;
+
+	instr = 0x60000000; /* nop */
+
+	if (enable) {
+		pr_info("barrier-nospec: using ORI speculation barrier\n");
+		instr = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+	}
+
+	for (i = 0; start < end; start++, i++) {
+		dest = (void *)start + *start;
+
+		pr_devel("patching dest %lx\n", (unsigned long)dest);
+		patch_instruction(dest, instr);
+	}
+
+	printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
+}
+
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
+#ifdef CONFIG_PPC_BARRIER_NOSPEC
+void do_barrier_nospec_fixups(bool enable)
+{
+	void *start, *end;
+
+	start = PTRRELOC(&__start___barrier_nospec_fixup),
+	end = PTRRELOC(&__stop___barrier_nospec_fixup);
+
+	do_barrier_nospec_fixups_range(enable, start, end);
+}
+#endif /* CONFIG_PPC_BARRIER_NOSPEC */
+
+#ifdef CONFIG_PPC_FSL_BOOK3E
+void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
+{
+	unsigned int instr[2], *dest;
+	long *start, *end;
+	int i;
+
+	start = fixup_start;
+	end = fixup_end;
+
+	instr[0] = PPC_INST_NOP;
+	instr[1] = PPC_INST_NOP;
+
+	if (enable) {
+		pr_info("barrier-nospec: using isync; sync as speculation barrier\n");
+		instr[0] = PPC_INST_ISYNC;
+		instr[1] = PPC_INST_SYNC;
+	}
+
+	for (i = 0; start < end; start++, i++) {
+		dest = (void *)start + *start;
+
+		pr_devel("patching dest %lx\n", (unsigned long)dest);
+		patch_instruction(dest, instr[0]);
+		patch_instruction(dest + 1, instr[1]);
+	}
+
+	printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
+}
+
+static void patch_btb_flush_section(long *curr)
+{
+	unsigned int *start, *end;
+
+	start = (void *)curr + *curr;
+	end = (void *)curr + *(curr + 1);
+	for (; start < end; start++) {
+		pr_devel("patching dest %lx\n", (unsigned long)start);
+		patch_instruction(start, PPC_INST_NOP);
+	}
+}
+
+void do_btb_flush_fixups(void)
+{
+	long *start, *end;
+
+	start = PTRRELOC(&__start__btb_flush_fixup);
+	end = PTRRELOC(&__stop__btb_flush_fixup);
+
+	for (; start < end; start += 2)
+		patch_btb_flush_section(start);
+}
+#endif /* CONFIG_PPC_FSL_BOOK3E */
+
 void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
 {
 	long *start, *end;
--- linux-4.4.0.orig/arch/powerpc/lib/ppc_ksyms.c
+++ linux-4.4.0/arch/powerpc/lib/ppc_ksyms.c
@@ -24,7 +24,6 @@
 #endif
 
 EXPORT_SYMBOL(__copy_tofrom_user);
-EXPORT_SYMBOL(__clear_user);
 EXPORT_SYMBOL(copy_page);
 
 #ifdef CONFIG_PPC64
--- linux-4.4.0.orig/arch/powerpc/lib/sstep.c
+++ linux-4.4.0/arch/powerpc/lib/sstep.c
@@ -687,8 +687,10 @@
 	case 19:
 		switch ((instr >> 1) & 0x3ff) {
 		case 0:		/* mcrf */
-			rd = (instr >> 21) & 0x1c;
-			ra = (instr >> 16) & 0x1c;
+			rd = 7 - ((instr >> 23) & 0x7);
+			ra = 7 - ((instr >> 18) & 0x7);
+			rd *= 4;
+			ra *= 4;
 			val = (regs->ccr >> ra) & 0xf;
 			regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
 			goto instr_done;
@@ -967,6 +969,19 @@
 #endif
 
 		case 19:	/* mfcr */
+			if ((instr >> 20) & 1) {
+				imm = 0xf0000000UL;
+				for (sh = 0; sh < 8; ++sh) {
+					if (instr & (0x80000 >> sh)) {
+						regs->gpr[rd] = regs->ccr & imm;
+						break;
+					}
+					imm >>= 4;
+				}
+
+				goto instr_done;
+			}
+
 			regs->gpr[rd] = regs->ccr;
 			regs->gpr[rd] &= 0xffffffffUL;
 			goto instr_done;
@@ -1806,8 +1821,6 @@
 		goto instr_done;
 
 	case LARX:
-		if (regs->msr & MSR_LE)
-			return 0;
 		if (op.ea & (size - 1))
 			break;		/* can't handle misaligned */
 		err = -EFAULT;
@@ -1829,8 +1842,6 @@
 		goto ldst_done;
 
 	case STCX:
-		if (regs->msr & MSR_LE)
-			return 0;
 		if (op.ea & (size - 1))
 			break;		/* can't handle misaligned */
 		err = -EFAULT;
@@ -1854,8 +1865,6 @@
 		goto ldst_done;
 
 	case LOAD:
-		if (regs->msr & MSR_LE)
-			return 0;
 		err = read_mem(&regs->gpr[op.reg], op.ea, size, regs);
 		if (!err) {
 			if (op.type & SIGNEXT)
@@ -1867,8 +1876,6 @@
 
 #ifdef CONFIG_PPC_FPU
 	case LOAD_FP:
-		if (regs->msr & MSR_LE)
-			return 0;
 		if (size == 4)
 			err = do_fp_load(op.reg, do_lfs, op.ea, size, regs);
 		else
@@ -1877,15 +1884,11 @@
 #endif
 #ifdef CONFIG_ALTIVEC
 	case LOAD_VMX:
-		if (regs->msr & MSR_LE)
-			return 0;
 		err = do_vec_load(op.reg, do_lvx, op.ea & ~0xfUL, regs);
 		goto ldst_done;
 #endif
 #ifdef CONFIG_VSX
 	case LOAD_VSX:
-		if (regs->msr & MSR_LE)
-			return 0;
 		err = do_vsx_load(op.reg, do_lxvd2x, op.ea, regs);
 		goto ldst_done;
 #endif
@@ -1908,8 +1911,6 @@
 		goto instr_done;
 
 	case STORE:
-		if (regs->msr & MSR_LE)
-			return 0;
 		if ((op.type & UPDATE) && size == sizeof(long) &&
 		    op.reg == 1 && op.update_reg == 1 &&
 		    !(regs->msr & MSR_PR) &&
@@ -1922,8 +1923,6 @@
 
 #ifdef CONFIG_PPC_FPU
 	case STORE_FP:
-		if (regs->msr & MSR_LE)
-			return 0;
 		if (size == 4)
 			err = do_fp_store(op.reg, do_stfs, op.ea, size, regs);
 		else
@@ -1932,15 +1931,11 @@
 #endif
 #ifdef CONFIG_ALTIVEC
 	case STORE_VMX:
-		if (regs->msr & MSR_LE)
-			return 0;
 		err = do_vec_store(op.reg, do_stvx, op.ea & ~0xfUL, regs);
 		goto ldst_done;
 #endif
 #ifdef CONFIG_VSX
 	case STORE_VSX:
-		if (regs->msr & MSR_LE)
-			return 0;
 		err = do_vsx_store(op.reg, do_stxvd2x, op.ea, regs);
 		goto ldst_done;
 #endif
--- linux-4.4.0.orig/arch/powerpc/lib/string.S
+++ linux-4.4.0/arch/powerpc/lib/string.S
@@ -122,7 +122,7 @@
 	blr
 
 #ifdef CONFIG_PPC32
-_GLOBAL(__clear_user)
+_GLOBAL(__arch_clear_user)
 	addi	r6,r3,-4
 	li	r3,0
 	li	r5,0
--- linux-4.4.0.orig/arch/powerpc/lib/string_64.S
+++ linux-4.4.0/arch/powerpc/lib/string_64.S
@@ -27,7 +27,7 @@
 	.section	".text"
 
 /**
- * __clear_user: - Zero a block of memory in user space, with less checking.
+ * __arch_clear_user: - Zero a block of memory in user space, with less checking.
  * @to:   Destination address, in user space.
  * @n:    Number of bytes to zero.
  *
@@ -77,7 +77,7 @@
 	mr	r3,r4
 	blr
 
-_GLOBAL_TOC(__clear_user)
+_GLOBAL_TOC(__arch_clear_user)
 	cmpdi	r4,32
 	neg	r6,r3
 	li	r0,0
--- linux-4.4.0.orig/arch/powerpc/lib/vmx-helper.c
+++ linux-4.4.0/arch/powerpc/lib/vmx-helper.c
@@ -46,6 +46,7 @@
  */
 int exit_vmx_usercopy(void)
 {
+	disable_kernel_altivec();
 	pagefault_enable();
 	preempt_enable();
 	return 0;
@@ -70,6 +71,7 @@
  */
 void *exit_vmx_copy(void *dest)
 {
+	disable_kernel_altivec();
 	preempt_enable();
 	return dest;
 }
--- linux-4.4.0.orig/arch/powerpc/lib/xor_vmx.c
+++ linux-4.4.0/arch/powerpc/lib/xor_vmx.c
@@ -74,6 +74,7 @@
 		v2 += 4;
 	} while (--lines > 0);
 
+	disable_kernel_altivec();
 	preempt_enable();
 }
 EXPORT_SYMBOL(xor_altivec_2);
@@ -102,6 +103,7 @@
 		v3 += 4;
 	} while (--lines > 0);
 
+	disable_kernel_altivec();
 	preempt_enable();
 }
 EXPORT_SYMBOL(xor_altivec_3);
@@ -135,6 +137,7 @@
 		v4 += 4;
 	} while (--lines > 0);
 
+	disable_kernel_altivec();
 	preempt_enable();
 }
 EXPORT_SYMBOL(xor_altivec_4);
@@ -172,6 +175,7 @@
 		v5 += 4;
 	} while (--lines > 0);
 
+	disable_kernel_altivec();
 	preempt_enable();
 }
 EXPORT_SYMBOL(xor_altivec_5);
--- linux-4.4.0.orig/arch/powerpc/mm/copro_fault.c
+++ linux-4.4.0/arch/powerpc/mm/copro_fault.c
@@ -106,6 +106,8 @@
 	switch (REGION_ID(ea)) {
 	case USER_REGION_ID:
 		pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea);
+		if (mm == NULL)
+			return 1;
 		psize = get_slice_psize(mm, ea);
 		ssize = user_segment_size(ea);
 		vsid = get_vsid(mm->context.id, ea, ssize);
--- linux-4.4.0.orig/arch/powerpc/mm/fault.c
+++ linux-4.4.0/arch/powerpc/mm/fault.c
@@ -192,6 +192,9 @@
 	return MM_FAULT_CONTINUE;
 }
 
+// This comes from 64-bit struct rt_sigframe + __SIGNAL_FRAMESIZE
+#define SIGFRAME_MAX_SIZE	(4096 + 128)
+
 /*
  * For 600- and 800-family processors, the error_code parameter is DSISR
  * for a data fault, SRR1 for an instruction fault. For 400-family processors
@@ -294,7 +297,7 @@
 	 * can result in fault, which will cause a deadlock when called with
 	 * mmap_sem held
 	 */
-	if (user_mode(regs))
+	if (!is_exec && user_mode(regs))
 		store_update_sp = store_updates_sp(regs);
 
 	if (user_mode(regs))
@@ -341,7 +344,7 @@
 	/*
 	 * N.B. The POWER/Open ABI allows programs to access up to
 	 * 288 bytes below the stack pointer.
-	 * The kernel signal delivery code writes up to about 1.5kB
+	 * The kernel signal delivery code writes up to about 4kB
 	 * below the stack pointer (r1) before decrementing it.
 	 * The exec code can write slightly over 640kB to the stack
 	 * before setting the user r1.  Thus we allow the stack to
@@ -365,7 +368,7 @@
 		 * between the last mapped region and the stack will
 		 * expand the stack rather than segfaulting.
 		 */
-		if (address + 2048 < uregs->gpr[1] && !store_update_sp)
+		if (address + SIGFRAME_MAX_SIZE < uregs->gpr[1] && !store_update_sp)
 			goto bad_area;
 	}
 	if (expand_stack(vma, address))
@@ -521,21 +524,22 @@
 	switch (regs->trap) {
 	case 0x300:
 	case 0x380:
-		printk(KERN_ALERT "Unable to handle kernel paging request for "
-			"data at address 0x%08lx\n", regs->dar);
+		pr_alert("BUG: %s at 0x%08lx\n",
+			 regs->dar < PAGE_SIZE ? "Kernel NULL pointer dereference" :
+			 "Unable to handle kernel data access", regs->dar);
 		break;
 	case 0x400:
 	case 0x480:
-		printk(KERN_ALERT "Unable to handle kernel paging request for "
-			"instruction fetch\n");
+		pr_alert("BUG: Unable to handle kernel instruction fetch%s",
+			 regs->nip < PAGE_SIZE ? " (NULL pointer?)\n" : "\n");
 		break;
 	case 0x600:
-		printk(KERN_ALERT "Unable to handle kernel paging request for "
-			"unaligned access at address 0x%08lx\n", regs->dar);
+		pr_alert("BUG: Unable to handle kernel unaligned access at 0x%08lx\n",
+			 regs->dar);
 		break;
 	default:
-		printk(KERN_ALERT "Unable to handle kernel paging request for "
-			"unknown fault\n");
+		pr_alert("BUG: Unable to handle unknown paging fault at 0x%08lx\n",
+			 regs->dar);
 		break;
 	}
 	printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n",
--- linux-4.4.0.orig/arch/powerpc/mm/hash_native_64.c
+++ linux-4.4.0/arch/powerpc/mm/hash_native_64.c
@@ -645,6 +645,10 @@
 	unsigned long psize = batch->psize;
 	int ssize = batch->ssize;
 	int i;
+	unsigned int use_local;
+
+	use_local = local && mmu_has_feature(MMU_FTR_TLBIEL) &&
+		mmu_psize_defs[psize].tlbiel && !cxl_ctx_in_use();
 
 	local_irq_save(flags);
 
@@ -671,8 +675,7 @@
 		} pte_iterate_hashed_end();
 	}
 
-	if (mmu_has_feature(MMU_FTR_TLBIEL) &&
-	    mmu_psize_defs[psize].tlbiel && local) {
+	if (use_local) {
 		asm volatile("ptesync":::"memory");
 		for (i = 0; i < number; i++) {
 			vpn = batch->vpn[i];
--- linux-4.4.0.orig/arch/powerpc/mm/hugetlbpage.c
+++ linux-4.4.0/arch/powerpc/mm/hugetlbpage.c
@@ -486,13 +486,13 @@
 {
 	struct hugepd_freelist **batchp;
 
-	batchp = this_cpu_ptr(&hugepd_freelist_cur);
+	batchp = &get_cpu_var(hugepd_freelist_cur);
 
 	if (atomic_read(&tlb->mm->mm_users) < 2 ||
 	    cpumask_equal(mm_cpumask(tlb->mm),
 			  cpumask_of(smp_processor_id()))) {
 		kmem_cache_free(hugepte_cache, hugepte);
-        put_cpu_var(hugepd_freelist_cur);
+		put_cpu_var(hugepd_freelist_cur);
 		return;
 	}
 
--- linux-4.4.0.orig/arch/powerpc/mm/mem.c
+++ linux-4.4.0/arch/powerpc/mm/mem.c
@@ -62,6 +62,7 @@
 #endif
 
 unsigned long long memory_limit;
+bool init_mem_is_free;
 
 #ifdef CONFIG_HIGHMEM
 pte_t *kmap_pte;
@@ -329,6 +330,14 @@
 	BUILD_BUG_ON(MMU_PAGE_COUNT > 16);
 
 #ifdef CONFIG_SWIOTLB
+	/*
+	 * Some platforms (e.g. 85xx) limit DMA-able memory way below
+	 * 4G. We force memblock to bottom-up mode to ensure that the
+	 * memory allocated in swiotlb_init() is DMA-able.
+	 * As it's the last memblock allocation, no need to reset it
+	 * back to to-down.
+	 */
+	memblock_set_bottom_up(true);
 	swiotlb_init(0);
 #endif
 
@@ -381,6 +390,7 @@
 void free_initmem(void)
 {
 	ppc_md.progress = ppc_printk_progress;
+	init_mem_is_free = true;
 	free_initmem_default(POISON_FREE_INITMEM);
 }
 
--- linux-4.4.0.orig/arch/powerpc/mm/mmu_context_iommu.c
+++ linux-4.4.0/arch/powerpc/mm/mmu_context_iommu.c
@@ -15,6 +15,9 @@
 #include <linux/rculist.h>
 #include <linux/vmalloc.h>
 #include <linux/mutex.h>
+#include <linux/migrate.h>
+#include <linux/hugetlb.h>
+#include <linux/swap.h>
 #include <asm/mmu_context.h>
 
 static DEFINE_MUTEX(mem_list_mutex);
@@ -72,6 +75,55 @@
 }
 EXPORT_SYMBOL_GPL(mm_iommu_preregistered);
 
+/*
+ * Taken from alloc_migrate_target with changes to remove CMA allocations
+ */
+struct page *new_iommu_non_cma_page(struct page *page, unsigned long private,
+					int **resultp)
+{
+	gfp_t gfp_mask = GFP_USER;
+	struct page *new_page;
+
+	if (PageHuge(page) || PageTransHuge(page) || PageCompound(page))
+		return NULL;
+
+	if (PageHighMem(page))
+		gfp_mask |= __GFP_HIGHMEM;
+
+	/*
+	 * We don't want the allocation to force an OOM if possibe
+	 */
+	new_page = alloc_page(gfp_mask | __GFP_NORETRY | __GFP_NOWARN);
+	return new_page;
+}
+
+static int mm_iommu_move_page_from_cma(struct page *page)
+{
+	int ret = 0;
+	LIST_HEAD(cma_migrate_pages);
+
+	/* Ignore huge pages for now */
+	if (PageHuge(page) || PageTransHuge(page) || PageCompound(page))
+		return -EBUSY;
+
+	lru_add_drain();
+	ret = isolate_lru_page(page);
+	if (ret)
+		return ret;
+
+	list_add(&page->lru, &cma_migrate_pages);
+	put_page(page); /* Drop the gup reference */
+
+	ret = migrate_pages(&cma_migrate_pages, new_iommu_non_cma_page,
+				NULL, 0, MIGRATE_SYNC, MR_CMA);
+	if (ret) {
+		if (!list_empty(&cma_migrate_pages))
+			putback_movable_pages(&cma_migrate_pages);
+	}
+
+	return 0;
+}
+
 long mm_iommu_get(unsigned long ua, unsigned long entries,
 		struct mm_iommu_table_group_mem_t **pmem)
 {
@@ -124,15 +176,36 @@
 	for (i = 0; i < entries; ++i) {
 		if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT),
 					1/* pages */, 1/* iswrite */, &page)) {
+			ret = -EFAULT;
 			for (j = 0; j < i; ++j)
-				put_page(pfn_to_page(
-						mem->hpas[j] >> PAGE_SHIFT));
+				put_page(pfn_to_page(mem->hpas[j] >>
+						PAGE_SHIFT));
 			vfree(mem->hpas);
 			kfree(mem);
-			ret = -EFAULT;
 			goto unlock_exit;
 		}
-
+		/*
+		 * If we get a page from the CMA zone, since we are going to
+		 * be pinning these entries, we might as well move them out
+		 * of the CMA zone if possible. NOTE: faulting in + migration
+		 * can be expensive. Batching can be considered later
+		 */
+		if (get_pageblock_migratetype(page) == MIGRATE_CMA) {
+			if (mm_iommu_move_page_from_cma(page))
+				goto populate;
+			if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT),
+						1/* pages */, 1/* iswrite */,
+						&page)) {
+				ret = -EFAULT;
+				for (j = 0; j < i; ++j)
+					put_page(pfn_to_page(mem->hpas[j] >>
+								PAGE_SHIFT));
+				vfree(mem->hpas);
+				kfree(mem);
+				goto unlock_exit;
+			}
+		}
+populate:
 		mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT;
 	}
 
--- linux-4.4.0.orig/arch/powerpc/mm/numa.c
+++ linux-4.4.0/arch/powerpc/mm/numa.c
@@ -551,7 +551,7 @@
 	nid = of_node_to_nid_single(cpu);
 
 out_present:
-	if (nid < 0 || !node_online(nid))
+	if (nid < 0 || !node_possible(nid))
 		nid = first_online_node;
 
 	map_cpu_to_node(lcpu, nid);
@@ -951,6 +951,32 @@
 	NODE_DATA(nid)->node_spanned_pages = spanned_pages;
 }
 
+static void __init find_possible_nodes(void)
+{
+	struct device_node *rtas;
+	u32 numnodes, i;
+
+	if (min_common_depth <= 0)
+		return;
+
+	rtas = of_find_node_by_path("/rtas");
+	if (!rtas)
+		return;
+
+	if (of_property_read_u32_index(rtas,
+				"ibm,max-associativity-domains",
+				min_common_depth, &numnodes))
+		goto out;
+
+	for (i = 0; i < numnodes; i++) {
+		if (!node_possible(i))
+			node_set(i, node_possible_map);
+	}
+
+out:
+	of_node_put(rtas);
+}
+
 void __init initmem_init(void)
 {
 	int nid, cpu;
@@ -966,12 +992,15 @@
 	memblock_dump_all();
 
 	/*
-	 * Reduce the possible NUMA nodes to the online NUMA nodes,
-	 * since we do not support node hotplug. This ensures that  we
-	 * lower the maximum NUMA node ID to what is actually present.
+	 * Modify the set of possible NUMA nodes to reflect information
+	 * available about the set of online nodes, and the set of nodes
+	 * that we expect to make use of for this platform's affinity
+	 * calculations.
 	 */
 	nodes_and(node_possible_map, node_possible_map, node_online_map);
 
+	find_possible_nodes();
+
 	for_each_online_node(nid) {
 		unsigned long start_pfn, end_pfn;
 
@@ -1290,7 +1319,7 @@
 
 	switch (rc) {
 	case H_FUNCTION:
-		printk(KERN_INFO
+		printk_once(KERN_INFO
 			"VPHN is not supported. Disabling polling...\n");
 		stop_topology_update();
 		break;
@@ -1304,6 +1333,40 @@
 	return rc;
 }
 
+static inline int find_and_online_cpu_nid(int cpu)
+{
+	__be32 associativity[VPHN_ASSOC_BUFSIZE] = {0};
+	int new_nid;
+
+	/* Use associativity from first thread for all siblings */
+	vphn_get_associativity(cpu, associativity);
+	new_nid = associativity_to_nid(associativity);
+	if (new_nid < 0 || !node_possible(new_nid))
+		new_nid = first_online_node;
+
+	if (NODE_DATA(new_nid) == NULL) {
+#ifdef CONFIG_MEMORY_HOTPLUG
+		/*
+		 * Need to ensure that NODE_DATA is initialized for a node from
+		 * available memory (see memblock_alloc_try_nid). If unable to
+		 * init the node, then default to nearest node that has memory
+		 * installed.
+		 */
+		if (try_online_node(new_nid))
+			new_nid = first_online_node;
+#else
+		/*
+		 * Default to using the nearest node that has memory installed.
+		 * Otherwise, it would be necessary to patch the kernel MM code
+		 * to deal with more memoryless-node error conditions.
+		 */
+		new_nid = first_online_node;
+#endif
+	}
+
+	return new_nid;
+}
+
 /*
  * Update the CPU maps and sysfs entries for a single CPU when its NUMA
  * characteristics change. This function doesn't perform any locking and is
@@ -1369,7 +1432,6 @@
 {
 	unsigned int cpu, sibling, changed = 0;
 	struct topology_update_data *updates, *ud;
-	__be32 associativity[VPHN_ASSOC_BUFSIZE] = {0};
 	cpumask_t updated_cpus;
 	struct device *dev;
 	int weight, new_nid, i = 0;
@@ -1404,11 +1466,7 @@
 			continue;
 		}
 
-		/* Use associativity from first thread for all siblings */
-		vphn_get_associativity(cpu, associativity);
-		new_nid = associativity_to_nid(associativity);
-		if (new_nid < 0 || !node_online(new_nid))
-			new_nid = first_online_node;
+		new_nid = find_and_online_cpu_nid(cpu);
 
 		if (new_nid == numa_cpu_lookup_table[cpu]) {
 			cpumask_andnot(&cpu_associativity_changes_mask,
@@ -1553,6 +1611,9 @@
 {
 	int rc = 0;
 
+	if (!topology_updates_enabled)
+		return 0;
+
 	if (firmware_has_feature(FW_FEATURE_PRRN)) {
 		if (!prrn_enabled) {
 			prrn_enabled = 1;
@@ -1582,6 +1643,9 @@
 {
 	int rc = 0;
 
+	if (!topology_updates_enabled)
+		return 0;
+
 	if (prrn_enabled) {
 		prrn_enabled = 0;
 #ifdef CONFIG_SMP
@@ -1627,11 +1691,13 @@
 
 	kbuf[read_len] = '\0';
 
-	if (!strncmp(kbuf, "on", 2))
+	if (!strncmp(kbuf, "on", 2)) {
+		topology_updates_enabled = true;
 		start_topology_update();
-	else if (!strncmp(kbuf, "off", 3))
+	} else if (!strncmp(kbuf, "off", 3)) {
 		stop_topology_update();
-	else
+		topology_updates_enabled = false;
+	} else
 		return -EINVAL;
 
 	return count;
@@ -1646,9 +1712,7 @@
 
 static int topology_update_init(void)
 {
-	/* Do not poll for changes if disabled at boot */
-	if (topology_updates_enabled)
-		start_topology_update();
+	start_topology_update();
 
 	if (!proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops))
 		return -ENOMEM;
--- linux-4.4.0.orig/arch/powerpc/mm/ppc_mmu_32.c
+++ linux-4.4.0/arch/powerpc/mm/ppc_mmu_32.c
@@ -52,7 +52,7 @@
 phys_addr_t v_mapped_by_bats(unsigned long va)
 {
 	int b;
-	for (b = 0; b < 4; ++b)
+	for (b = 0; b < ARRAY_SIZE(bat_addrs); ++b)
 		if (va >= bat_addrs[b].start && va < bat_addrs[b].limit)
 			return bat_addrs[b].phys + (va - bat_addrs[b].start);
 	return 0;
@@ -64,7 +64,7 @@
 unsigned long p_mapped_by_bats(phys_addr_t pa)
 {
 	int b;
-	for (b = 0; b < 4; ++b)
+	for (b = 0; b < ARRAY_SIZE(bat_addrs); ++b)
 		if (pa >= bat_addrs[b].phys
 	    	    && pa < (bat_addrs[b].limit-bat_addrs[b].start)
 		              +bat_addrs[b].phys)
--- linux-4.4.0.orig/arch/powerpc/mm/slb.c
+++ linux-4.4.0/arch/powerpc/mm/slb.c
@@ -69,14 +69,14 @@
 	 * updating it.  No write barriers are needed here, provided
 	 * we only update the current CPU's SLB shadow buffer.
 	 */
-	p->save_area[index].esid = 0;
-	p->save_area[index].vsid = cpu_to_be64(mk_vsid_data(ea, ssize, flags));
-	p->save_area[index].esid = cpu_to_be64(mk_esid_data(ea, ssize, index));
+	WRITE_ONCE(p->save_area[index].esid, 0);
+	WRITE_ONCE(p->save_area[index].vsid, cpu_to_be64(mk_vsid_data(ea, ssize, flags)));
+	WRITE_ONCE(p->save_area[index].esid, cpu_to_be64(mk_esid_data(ea, ssize, index)));
 }
 
 static inline void slb_shadow_clear(enum slb_index index)
 {
-	get_slb_shadow()->save_area[index].esid = 0;
+	WRITE_ONCE(get_slb_shadow()->save_area[index].esid, 0);
 }
 
 static inline void create_shadowed_slbe(unsigned long ea, int ssize,
@@ -322,7 +322,7 @@
 #endif
 	}
 
-	get_paca()->stab_rr = SLB_NUM_BOLTED;
+	get_paca()->stab_rr = SLB_NUM_BOLTED - 1;
 
 	lflags = SLB_VSID_KERNEL | linear_llp;
 	vflags = SLB_VSID_KERNEL | vmalloc_llp;
--- linux-4.4.0.orig/arch/powerpc/mm/slb_low.S
+++ linux-4.4.0/arch/powerpc/mm/slb_low.S
@@ -113,7 +113,12 @@
 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
 	b	slb_finish_load_1T
 
-0:
+0:	/*
+	 * For userspace addresses, make sure this is region 0.
+	 */
+	cmpdi	r9, 0
+	bne	8f
+
 	/* when using slices, we extract the psize off the slice bitmaps
 	 * and then we need to get the sllp encoding off the mmu_psize_defs
 	 * array.
@@ -174,6 +179,16 @@
 	b	slb_finish_load
 
 8:	/* invalid EA */
+	/*
+	 * It's possible the bad EA is too large to fit in the SLB cache, which
+	 * would mean we'd fail to invalidate it on context switch. So mark the
+	 * SLB cache as full so we force a full flush. We also set cr7+eq to
+	 * mark the address as a kernel address, so slb_finish_load() skips
+	 * trying to insert it into the SLB cache.
+	 */
+	li	r9,SLB_CACHE_ENTRIES + 1
+	sth	r9,PACASLBCACHEPTR(r13)
+	crset	4*cr7+eq
 	li	r10,0			/* BAD_VSID */
 	li	r9,0			/* BAD_VSID */
 	li	r11,SLB_VSID_USER	/* flags don't much matter */
--- linux-4.4.0.orig/arch/powerpc/mm/slice.c
+++ linux-4.4.0/arch/powerpc/mm/slice.c
@@ -105,7 +105,7 @@
 	if ((mm->task_size - len) < addr)
 		return 0;
 	vma = find_vma(mm, addr);
-	return (!vma || (addr + len) <= vma->vm_start);
+	return (!vma || (addr + len) <= vm_start_gap(vma));
 }
 
 static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice)
--- linux-4.4.0.orig/arch/powerpc/mm/tlb_low_64e.S
+++ linux-4.4.0/arch/powerpc/mm/tlb_low_64e.S
@@ -69,6 +69,13 @@
 	std	r15,EX_TLB_R15(r12)
 	std	r10,EX_TLB_CR(r12)
 #ifdef CONFIG_PPC_FSL_BOOK3E
+START_BTB_FLUSH_SECTION
+	mfspr r11, SPRN_SRR1
+	andi. r10,r11,MSR_PR
+	beq 1f
+	BTB_FLUSH(r10)
+1:
+END_BTB_FLUSH_SECTION
 	std	r7,EX_TLB_R7(r12)
 #endif
 	TLB_MISS_PROLOG_STATS
--- linux-4.4.0.orig/arch/powerpc/mm/tlb_nohash.c
+++ linux-4.4.0/arch/powerpc/mm/tlb_nohash.c
@@ -487,6 +487,9 @@
 		for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
 			struct mmu_psize_def *def = &mmu_psize_defs[psize];
 
+			if (!def->shift)
+				continue;
+
 			if (tlb1ps & (1U << (def->shift - 10))) {
 				def->flags |= MMU_PAGE_SIZE_DIRECT;
 
--- linux-4.4.0.orig/arch/powerpc/mm/tlb_nohash_low.S
+++ linux-4.4.0/arch/powerpc/mm/tlb_nohash_low.S
@@ -400,7 +400,7 @@
  * extern void loadcam_entry(unsigned int index)
  *
  * Load TLBCAM[index] entry in to the L2 CAM MMU
- * Must preserve r7, r8, r9, and r10
+ * Must preserve r7, r8, r9, r10 and r11
  */
 _GLOBAL(loadcam_entry)
 	mflr	r5
@@ -436,6 +436,10 @@
  */
 _GLOBAL(loadcam_multi)
 	mflr	r8
+	/* Don't switch to AS=1 if already there */
+	mfmsr	r11
+	andi.	r11,r11,MSR_IS
+	bne	10f
 
 	/*
 	 * Set up temporary TLB entry that is the same as what we're
@@ -461,6 +465,7 @@
 	mtmsr	r6
 	isync
 
+10:
 	mr	r9,r3
 	add	r10,r3,r4
 2:	bl	loadcam_entry
@@ -469,6 +474,10 @@
 	mr	r3,r9
 	blt	2b
 
+	/* Don't return to AS=0 if we were in AS=1 at function start */
+	andi.	r11,r11,MSR_IS
+	bne	3f
+
 	/* Return to AS=0 and clear the temporary entry */
 	mfmsr	r6
 	rlwinm.	r6,r6,0,~(MSR_IS|MSR_DS)
@@ -484,6 +493,7 @@
 	tlbwe
 	isync
 
+3:
 	mtlr	r8
 	blr
 #endif
--- linux-4.4.0.orig/arch/powerpc/net/bpf_jit_comp.c
+++ linux-4.4.0/arch/powerpc/net/bpf_jit_comp.c
@@ -329,6 +329,9 @@
 			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
 			PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len));
 			break;
+		case BPF_LDX | BPF_W | BPF_ABS: /* A = *((u32 *)(seccomp_data + K)); */
+			PPC_LWZ_OFFS(r_A, r_skb, K);
+			break;
 		case BPF_LDX | BPF_W | BPF_LEN: /* X = skb->len; */
 			PPC_LWZ_OFFS(r_X, r_skb, offsetof(struct sk_buff, len));
 			break;
--- linux-4.4.0.orig/arch/powerpc/perf/core-book3s.c
+++ linux-4.4.0/arch/powerpc/perf/core-book3s.c
@@ -401,8 +401,12 @@
 	int ret;
 	__u64 target;
 
-	if (is_kernel_addr(addr))
-		return branch_target((unsigned int *)addr);
+	if (is_kernel_addr(addr)) {
+		if (probe_kernel_read(&instr, (void *)addr, sizeof(instr)))
+			return 0;
+
+		return branch_target(&instr);
+	}
 
 	/* Userspace: need copy instruction here then translate it */
 	pagefault_disable();
@@ -444,6 +448,16 @@
 				/* invalid entry */
 				continue;
 
+			/*
+			 * BHRB rolling buffer could very much contain the kernel
+			 * addresses at this point. Check the privileges before
+			 * exporting it to userspace (avoid exposure of regions
+			 * where we could have speculative execution)
+			 */
+			if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN) &&
+				is_kernel_addr(addr))
+				continue;
+
 			/* Branches are read most recent first (ie. mfbhrb 0 is
 			 * the most recent branch).
 			 * There are two types of valid entries:
@@ -1184,6 +1198,7 @@
 		 */
 		write_mmcr0(cpuhw, val);
 		mb();
+		isync();
 
 		/*
 		 * Disable instruction sampling if it was enabled
@@ -1192,12 +1207,26 @@
 			mtspr(SPRN_MMCRA,
 			      cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
 			mb();
+			isync();
 		}
 
 		cpuhw->disabled = 1;
 		cpuhw->n_added = 0;
 
 		ebb_switch_out(mmcr0);
+
+#ifdef CONFIG_PPC64
+		/*
+		 * These are readable by userspace, may contain kernel
+		 * addresses and are not switched by context switch, so clear
+		 * them now to avoid leaking anything to userspace in general
+		 * including to another process.
+		 */
+		if (ppmu->flags & PPMU_ARCH_207S) {
+			mtspr(SPRN_SDAR, 0);
+			mtspr(SPRN_SIAR, 0);
+		}
+#endif
 	}
 
 	local_irq_restore(flags);
@@ -1377,7 +1406,7 @@
 	int n = 0;
 	struct perf_event *event;
 
-	if (!is_software_event(group)) {
+	if (group->pmu->task_ctx_nr == perf_hw_context) {
 		if (n >= max_count)
 			return -1;
 		ctrs[n] = group;
@@ -1385,7 +1414,7 @@
 		events[n++] = group->hw.config;
 	}
 	list_for_each_entry(event, &group->sibling_list, group_entry) {
-		if (!is_software_event(event) &&
+		if (event->pmu->task_ctx_nr == perf_hw_context &&
 		    event->state != PERF_EVENT_STATE_OFF) {
 			if (n >= max_count)
 				return -1;
@@ -1979,7 +2008,17 @@
 			left += period;
 			if (left <= 0)
 				left = period;
-			record = siar_valid(regs);
+
+			/*
+			 * If address is not requested in the sample via
+			 * PERF_SAMPLE_IP, just record that sample irrespective
+			 * of SIAR valid check.
+			 */
+			if (event->attr.sample_type & PERF_SAMPLE_IP)
+				record = siar_valid(regs);
+			else
+				record = 1;
+
 			event->hw.last_period = event->hw.sample_period;
 		}
 		if (left < 0x80000000LL)
@@ -1992,6 +2031,17 @@
 	perf_event_update_userpage(event);
 
 	/*
+	 * Due to hardware limitation, sometimes SIAR could sample a kernel
+	 * address even when freeze on supervisor state (kernel) is set in
+	 * MMCR2. Check attr.exclude_kernel and address to drop the sample in
+	 * these cases.
+	 */
+	if (event->attr.exclude_kernel &&
+	    (event->attr.sample_type & PERF_SAMPLE_IP) &&
+	    is_kernel_addr(mfspr(SPRN_SIAR)))
+		record = 0;
+
+	/*
 	 * Finally record data if requested.
 	 */
 	if (record) {
--- linux-4.4.0.orig/arch/powerpc/perf/hv-24x7.c
+++ linux-4.4.0/arch/powerpc/perf/hv-24x7.c
@@ -27,20 +27,6 @@
 #include "hv-24x7-catalog.h"
 #include "hv-common.h"
 
-static const char *event_domain_suffix(unsigned domain)
-{
-	switch (domain) {
-#define DOMAIN(n, v, x, c)		\
-	case HV_PERF_DOMAIN_##n:	\
-		return "__" #n;
-#include "hv-24x7-domains.h"
-#undef DOMAIN
-	default:
-		WARN(1, "unknown domain %d\n", domain);
-		return "__UNKNOWN_DOMAIN_SUFFIX";
-	}
-}
-
 static bool domain_is_valid(unsigned domain)
 {
 	switch (domain) {
@@ -68,6 +54,24 @@
 	}
 }
 
+static const char *domain_name(unsigned domain)
+{
+	if (!domain_is_valid(domain))
+		return NULL;
+
+	switch (domain) {
+	case HV_PERF_DOMAIN_PHYS_CHIP:		return "Physical Chip";
+	case HV_PERF_DOMAIN_PHYS_CORE:		return "Physical Core";
+	case HV_PERF_DOMAIN_VCPU_HOME_CORE:	return "VCPU Home Core";
+	case HV_PERF_DOMAIN_VCPU_HOME_CHIP:	return "VCPU Home Chip";
+	case HV_PERF_DOMAIN_VCPU_HOME_NODE:	return "VCPU Home Node";
+	case HV_PERF_DOMAIN_VCPU_REMOTE_NODE:	return "VCPU Remote Node";
+	}
+
+	WARN_ON_ONCE(domain);
+	return NULL;
+}
+
 static bool catalog_entry_domain_is_valid(unsigned domain)
 {
 	return is_physical_domain(domain);
@@ -101,6 +105,7 @@
 EVENT_DEFINE_RANGE_FORMAT(domain, config, 0, 3);
 /* u16 */
 EVENT_DEFINE_RANGE_FORMAT(core, config, 16, 31);
+EVENT_DEFINE_RANGE_FORMAT(chip, config, 16, 31);
 EVENT_DEFINE_RANGE_FORMAT(vcpu, config, 16, 31);
 /* u32, see "data_offset" */
 EVENT_DEFINE_RANGE_FORMAT(offset, config, 32, 63);
@@ -115,6 +120,7 @@
 	&format_attr_domain.attr,
 	&format_attr_offset.attr,
 	&format_attr_core.attr,
+	&format_attr_chip.attr,
 	&format_attr_vcpu.attr,
 	&format_attr_lpar.attr,
 	NULL,
@@ -274,32 +280,70 @@
 					version, index);
 }
 
-static unsigned core_domains[] = {
-	HV_PERF_DOMAIN_PHYS_CORE,
-	HV_PERF_DOMAIN_VCPU_HOME_CORE,
-	HV_PERF_DOMAIN_VCPU_HOME_CHIP,
-	HV_PERF_DOMAIN_VCPU_HOME_NODE,
-	HV_PERF_DOMAIN_VCPU_REMOTE_NODE,
-};
-/* chip event data always yeilds a single event, core yeilds multiple */
-#define MAX_EVENTS_PER_EVENT_DATA ARRAY_SIZE(core_domains)
-
+/*
+ * Each event we find in the catalog, will have a sysfs entry. Format the
+ * data for this sysfs entry based on the event's domain.
+ *
+ * Events belonging to the Chip domain can only be monitored in that domain.
+ * i.e the domain for these events is a fixed/knwon value.
+ *
+ * Events belonging to the Core domain can be monitored either in the physical
+ * core or in one of the virtual CPU domains. So the domain value for these
+ * events must be specified by the user (i.e is a required parameter). Format
+ * the Core events with 'domain=?' so the perf-tool can error check required
+ * parameters.
+ *
+ * NOTE: For the Core domain events, rather than making domain a required
+ *	 parameter we could default it to PHYS_CORE and allowe users to
+ *	 override the domain to one of the VCPU domains.
+ *
+ *	 However, this can make the interface a little inconsistent.
+ *
+ *	 If we set domain=2 (PHYS_CHIP) and allow user to override this field
+ *	 the user may be tempted to also modify the "offset=x" field in which
+ *	 can lead to confusing usage. Consider the HPM_PCYC (offset=0x18) and
+ *	 HPM_INST (offset=0x20) events. With:
+ *
+ *		perf stat -e hv_24x7/HPM_PCYC,offset=0x20/
+ *
+ *	we end up monitoring HPM_INST, while the command line has HPM_PCYC.
+ *
+ *	By not assigning a default value to the domain for the Core events,
+ *	we can have simple guidelines:
+ *
+ *		- Specifying values for parameters with "=?" is required.
+ *
+ *		- Specifying (i.e overriding) values for other parameters
+ *		  is undefined.
+ */
 static char *event_fmt(struct hv_24x7_event_data *event, unsigned domain)
 {
 	const char *sindex;
 	const char *lpar;
+	const char *domain_str;
+	char buf[8];
 
-	if (is_physical_domain(domain)) {
+	switch (domain) {
+	case HV_PERF_DOMAIN_PHYS_CHIP:
+		snprintf(buf, sizeof(buf), "%d", domain);
+		domain_str = buf;
+		lpar = "0x0";
+		sindex = "chip";
+		break;
+	case HV_PERF_DOMAIN_PHYS_CORE:
+		domain_str = "?";
 		lpar = "0x0";
 		sindex = "core";
-	} else {
+		break;
+	default:
+		domain_str = "?";
 		lpar = "?";
 		sindex = "vcpu";
 	}
 
 	return kasprintf(GFP_KERNEL,
-			"domain=0x%x,offset=0x%x,%s=?,lpar=%s",
-			domain,
+			"domain=%s,offset=0x%x,%s=?,lpar=%s",
+			domain_str,
 			be16_to_cpu(event->event_counter_offs) +
 				be16_to_cpu(event->event_group_record_offs),
 			sindex,
@@ -339,6 +383,15 @@
 	return &attr->attr.attr;
 }
 
+/*
+ * Allocate and initialize strings representing event attributes.
+ *
+ * NOTE: The strings allocated here are never destroyed and continue to
+ *	 exist till shutdown. This is to allow us to create as many events
+ *	 from the catalog as possible, even if we encounter errors with some.
+ *	 In case of changes to error paths in future, these may need to be
+ *	 freed by the caller.
+ */
 static struct attribute *device_str_attr_create(char *name, int name_max,
 						int name_nonce,
 						char *str, size_t str_max)
@@ -370,16 +423,6 @@
 	return NULL;
 }
 
-static void device_str_attr_destroy(struct attribute *attr)
-{
-	struct dev_ext_attribute *d;
-
-	d = container_of(attr, struct dev_ext_attribute, attr.attr);
-	kfree(d->var);
-	kfree(d->attr.attr.name);
-	kfree(d);
-}
-
 static struct attribute *event_to_attr(unsigned ix,
 				       struct hv_24x7_event_data *event,
 				       unsigned domain,
@@ -387,7 +430,6 @@
 {
 	int event_name_len;
 	char *ev_name, *a_ev_name, *val;
-	const char *ev_suffix;
 	struct attribute *attr;
 
 	if (!domain_is_valid(domain)) {
@@ -400,14 +442,13 @@
 	if (!val)
 		return NULL;
 
-	ev_suffix = event_domain_suffix(domain);
 	ev_name = event_name(event, &event_name_len);
 	if (!nonce)
-		a_ev_name = kasprintf(GFP_KERNEL, "%.*s%s",
-				(int)event_name_len, ev_name, ev_suffix);
+		a_ev_name = kasprintf(GFP_KERNEL, "%.*s",
+				(int)event_name_len, ev_name);
 	else
-		a_ev_name = kasprintf(GFP_KERNEL, "%.*s%s__%d",
-				(int)event_name_len, ev_name, ev_suffix, nonce);
+		a_ev_name = kasprintf(GFP_KERNEL, "%.*s__%d",
+				(int)event_name_len, ev_name, nonce);
 
 	if (!a_ev_name)
 		goto out_val;
@@ -452,45 +493,14 @@
 	return device_str_attr_create(name, nl, nonce, desc, dl);
 }
 
-static ssize_t event_data_to_attrs(unsigned ix, struct attribute **attrs,
+static int event_data_to_attrs(unsigned ix, struct attribute **attrs,
 				   struct hv_24x7_event_data *event, int nonce)
 {
-	unsigned i;
-
-	switch (event->domain) {
-	case HV_PERF_DOMAIN_PHYS_CHIP:
-		*attrs = event_to_attr(ix, event, event->domain, nonce);
-		return 1;
-	case HV_PERF_DOMAIN_PHYS_CORE:
-		for (i = 0; i < ARRAY_SIZE(core_domains); i++) {
-			attrs[i] = event_to_attr(ix, event, core_domains[i],
-						nonce);
-			if (!attrs[i]) {
-				pr_warn("catalog event %u: individual attr %u "
-					"creation failure\n", ix, i);
-				for (; i; i--)
-					device_str_attr_destroy(attrs[i - 1]);
-				return -1;
-			}
-		}
-		return i;
-	default:
-		pr_warn("catalog event %u: domain %u is not allowed in the "
-				"catalog\n", ix, event->domain);
+	*attrs = event_to_attr(ix, event, event->domain, nonce);
+	if (!*attrs)
 		return -1;
-	}
-}
 
-static size_t event_to_attr_ct(struct hv_24x7_event_data *event)
-{
-	switch (event->domain) {
-	case HV_PERF_DOMAIN_PHYS_CHIP:
-		return 1;
-	case HV_PERF_DOMAIN_PHYS_CORE:
-		return ARRAY_SIZE(core_domains);
-	default:
-		return 0;
-	}
+	return 0;
 }
 
 static unsigned long vmalloc_to_phys(void *v)
@@ -514,7 +524,7 @@
 {
 	if (s1 < s2)
 		return 1;
-	if (s2 > s1)
+	if (s1 > s2)
 		return -1;
 
 	return memcmp(d1, d2, s1);
@@ -726,9 +736,8 @@
 		goto e_free;
 	}
 
-	if (SIZE_MAX / MAX_EVENTS_PER_EVENT_DATA - 1 < event_entry_count) {
-		pr_err("event_entry_count %zu is invalid\n",
-				event_entry_count);
+	if (SIZE_MAX - 1 < event_entry_count) {
+		pr_err("event_entry_count %zu is invalid\n", event_entry_count);
 		ret = -EIO;
 		goto e_free;
 	}
@@ -801,7 +810,7 @@
 			continue;
 		}
 
-		attr_max += event_to_attr_ct(event);
+		attr_max++;
 	}
 
 	event_idx_last = event_idx;
@@ -851,12 +860,12 @@
 		nonce = event_uniq_add(&ev_uniq, name, nl, event->domain);
 		ct    = event_data_to_attrs(event_idx, events + event_attr_ct,
 					    event, nonce);
-		if (ct <= 0) {
+		if (ct < 0) {
 			pr_warn("event %zu (%.*s) creation failure, skipping\n",
 				event_idx, nl, name);
 			junk_events++;
 		} else {
-			event_attr_ct += ct;
+			event_attr_ct++;
 			event_descs[desc_ct] = event_to_desc_attr(event, nonce);
 			if (event_descs[desc_ct])
 				desc_ct++;
@@ -961,6 +970,27 @@
 	return ret;
 }
 
+static ssize_t domains_show(struct device *dev, struct device_attribute *attr,
+			    char *page)
+{
+	int d, n, count = 0;
+	const char *str;
+
+	for (d = 0; d < HV_PERF_DOMAIN_MAX; d++) {
+		str = domain_name(d);
+		if (!str)
+			continue;
+
+		n = sprintf(page, "%d: %s\n", d, str);
+		if (n < 0)
+			break;
+
+		count += n;
+		page += n;
+	}
+	return count;
+}
+
 #define PAGE_0_ATTR(_name, _fmt, _expr)				\
 static ssize_t _name##_show(struct device *dev,			\
 			    struct device_attribute *dev_attr,	\
@@ -989,6 +1019,7 @@
 PAGE_0_ATTR(catalog_len, "%lld\n",
 		(unsigned long long)be32_to_cpu(page_0->length) * 4096);
 static BIN_ATTR_RO(catalog, 0/* real length varies */);
+static DEVICE_ATTR_RO(domains);
 
 static struct bin_attribute *if_bin_attrs[] = {
 	&bin_attr_catalog,
@@ -998,6 +1029,7 @@
 static struct attribute *if_attrs[] = {
 	&dev_attr_catalog_len.attr,
 	&dev_attr_catalog_version.attr,
+	&dev_attr_domains.attr,
 	NULL,
 };
 
@@ -1089,10 +1121,16 @@
 		return -EINVAL;
 	}
 
-	if (is_physical_domain(event_get_domain(event)))
+	switch (event_get_domain(event)) {
+	case HV_PERF_DOMAIN_PHYS_CHIP:
+		idx = event_get_chip(event);
+		break;
+	case HV_PERF_DOMAIN_PHYS_CORE:
 		idx = event_get_core(event);
-	else
+		break;
+	default:
 		idx = event_get_vcpu(event);
+	}
 
 	i = request_buffer->num_requests++;
 	req = &request_buffer->requests[i];
@@ -1208,11 +1246,12 @@
 		return -EACCES;
 	}
 
-	/* see if the event complains */
+	/* Get the initial value of the counter for this event */
 	if (single_24x7_request(event, &ct)) {
 		pr_devel("test hcall failed\n");
 		return -EIO;
 	}
+	(void)local64_xchg(&event->hw.prev_count, ct);
 
 	return 0;
 }
@@ -1275,6 +1314,16 @@
 			h24x7hw = &get_cpu_var(hv_24x7_hw);
 			h24x7hw->events[i] = event;
 			put_cpu_var(h24x7hw);
+			/*
+			 * Clear the event count so we can compute the _change_
+			 * in the 24x7 raw counter value at the end of the txn.
+			 *
+			 * Note that we could alternatively read the 24x7 value
+			 * now and save its value in event->hw.prev_count. But
+			 * that would require issuing a hcall, which would then
+			 * defeat the purpose of using the txn interface.
+			 */
+			local64_set(&event->count, 0);
 		}
 
 		put_cpu_var(hv_24x7_reqb);
--- linux-4.4.0.orig/arch/powerpc/perf/hv-24x7.h
+++ linux-4.4.0/arch/powerpc/perf/hv-24x7.h
@@ -7,6 +7,7 @@
 #define DOMAIN(n, v, x, c) HV_PERF_DOMAIN_##n = v,
 #include "hv-24x7-domains.h"
 #undef DOMAIN
+	HV_PERF_DOMAIN_MAX,
 };
 
 struct hv_24x7_request {
--- linux-4.4.0.orig/arch/powerpc/perf/hv-gpci-requests.h
+++ linux-4.4.0/arch/powerpc/perf/hv-gpci-requests.h
@@ -94,7 +94,7 @@
 
 #define REQUEST_NAME system_performance_capabilities
 #define REQUEST_NUM 0x40
-#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff"
+#define REQUEST_IDX_KIND "starting_index=0xffffffff"
 #include I(REQUEST_BEGIN)
 REQUEST(__field(0,	1,	perf_collect_privileged)
 	__field(0x1,	1,	capability_mask)
@@ -222,7 +222,7 @@
 
 #define REQUEST_NAME system_hypervisor_times
 #define REQUEST_NUM 0xF0
-#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff"
+#define REQUEST_IDX_KIND "starting_index=0xffffffff"
 #include I(REQUEST_BEGIN)
 REQUEST(__count(0,	8,	time_spent_to_dispatch_virtual_processors)
 	__count(0x8,	8,	time_spent_processing_virtual_processor_timers)
@@ -233,7 +233,7 @@
 
 #define REQUEST_NAME system_tlbie_count_and_time
 #define REQUEST_NUM 0xF4
-#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff"
+#define REQUEST_IDX_KIND "starting_index=0xffffffff"
 #include I(REQUEST_BEGIN)
 REQUEST(__count(0,	8,	tlbie_instructions_issued)
 	/*
--- linux-4.4.0.orig/arch/powerpc/perf/power7-pmu.c
+++ linux-4.4.0/arch/powerpc/perf/power7-pmu.c
@@ -54,7 +54,7 @@
  * Power7 event codes.
  */
 #define EVENT(_name, _code) \
-	PME_##_name = _code,
+	_name = _code,
 
 enum {
 #include "power7-events-list.h"
@@ -318,14 +318,14 @@
 }
 
 static int power7_generic_events[] = {
-	[PERF_COUNT_HW_CPU_CYCLES] =			PME_PM_CYC,
-	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =	PME_PM_GCT_NOSLOT_CYC,
-	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =	PME_PM_CMPLU_STALL,
-	[PERF_COUNT_HW_INSTRUCTIONS] =			PME_PM_INST_CMPL,
-	[PERF_COUNT_HW_CACHE_REFERENCES] =		PME_PM_LD_REF_L1,
-	[PERF_COUNT_HW_CACHE_MISSES] =			PME_PM_LD_MISS_L1,
-	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =		PME_PM_BRU_FIN,
-	[PERF_COUNT_HW_BRANCH_MISSES] =			PME_PM_BR_MPRED,
+	[PERF_COUNT_HW_CPU_CYCLES] =			PM_CYC,
+	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =	PM_GCT_NOSLOT_CYC,
+	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =	PM_CMPLU_STALL,
+	[PERF_COUNT_HW_INSTRUCTIONS] =			PM_INST_CMPL,
+	[PERF_COUNT_HW_CACHE_REFERENCES] =		PM_LD_REF_L1,
+	[PERF_COUNT_HW_CACHE_MISSES] =			PM_LD_MISS_L1,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =		PM_BRU_FIN,
+	[PERF_COUNT_HW_BRANCH_MISSES] =			PM_BR_MPRED,
 };
 
 #define C(x)	PERF_COUNT_HW_CACHE_##x
--- linux-4.4.0.orig/arch/powerpc/perf/power8-events-list.h
+++ linux-4.4.0/arch/powerpc/perf/power8-events-list.h
@@ -0,0 +1,51 @@
+/*
+ * Performance counter support for POWER8 processors.
+ *
+ * Copyright 2014 Sukadev Bhattiprolu, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Power8 event codes.
+ */
+EVENT(PM_CYC,					0x0001e)
+EVENT(PM_GCT_NOSLOT_CYC,			0x100f8)
+EVENT(PM_CMPLU_STALL,				0x4000a)
+EVENT(PM_INST_CMPL,				0x00002)
+EVENT(PM_BRU_FIN,				0x10068)
+EVENT(PM_BR_MPRED_CMPL,				0x400f6)
+
+/* All L1 D cache load references counted at finish, gated by reject */
+EVENT(PM_LD_REF_L1,				0x100ee)
+/* Load Missed L1 */
+EVENT(PM_LD_MISS_L1,				0x3e054)
+/* Store Missed L1 */
+EVENT(PM_ST_MISS_L1,				0x300f0)
+/* L1 cache data prefetches */
+EVENT(PM_L1_PREF,				0x0d8b8)
+/* Instruction fetches from L1 */
+EVENT(PM_INST_FROM_L1,				0x04080)
+/* Demand iCache Miss */
+EVENT(PM_L1_ICACHE_MISS,			0x200fd)
+/* Instruction Demand sectors wriittent into IL1 */
+EVENT(PM_L1_DEMAND_WRITE,			0x0408c)
+/* Instruction prefetch written into IL1 */
+EVENT(PM_IC_PREF_WRITE,				0x0408e)
+/* The data cache was reloaded from local core's L3 due to a demand load */
+EVENT(PM_DATA_FROM_L3,				0x4c042)
+/* Demand LD - L3 Miss (not L2 hit and not L3 hit) */
+EVENT(PM_DATA_FROM_L3MISS,			0x300fe)
+/* All successful D-side store dispatches for this thread */
+EVENT(PM_L2_ST,					0x17080)
+/* All successful D-side store dispatches for this thread that were L2 Miss */
+EVENT(PM_L2_ST_MISS,				0x17082)
+/* Total HW L3 prefetches(Load+store) */
+EVENT(PM_L3_PREF_ALL,				0x4e052)
+/* Data PTEG reload */
+EVENT(PM_DTLB_MISS,				0x300fc)
+/* ITLB Reloaded */
+EVENT(PM_ITLB_MISS,				0x400fc)
--- linux-4.4.0.orig/arch/powerpc/perf/power8-pmu.c
+++ linux-4.4.0/arch/powerpc/perf/power8-pmu.c
@@ -17,48 +17,16 @@
 #include <asm/firmware.h>
 #include <asm/cputable.h>
 
-
 /*
  * Some power8 event codes.
  */
-#define PM_CYC				0x0001e
-#define PM_GCT_NOSLOT_CYC		0x100f8
-#define PM_CMPLU_STALL			0x4000a
-#define PM_INST_CMPL			0x00002
-#define PM_BRU_FIN			0x10068
-#define PM_BR_MPRED_CMPL		0x400f6
-
-/* All L1 D cache load references counted at finish, gated by reject */
-#define PM_LD_REF_L1			0x100ee
-/* Load Missed L1 */
-#define PM_LD_MISS_L1			0x3e054
-/* Store Missed L1 */
-#define PM_ST_MISS_L1			0x300f0
-/* L1 cache data prefetches */
-#define PM_L1_PREF			0x0d8b8
-/* Instruction fetches from L1 */
-#define PM_INST_FROM_L1			0x04080
-/* Demand iCache Miss */
-#define PM_L1_ICACHE_MISS		0x200fd
-/* Instruction Demand sectors wriittent into IL1 */
-#define PM_L1_DEMAND_WRITE		0x0408c
-/* Instruction prefetch written into IL1 */
-#define PM_IC_PREF_WRITE		0x0408e
-/* The data cache was reloaded from local core's L3 due to a demand load */
-#define PM_DATA_FROM_L3			0x4c042
-/* Demand LD - L3 Miss (not L2 hit and not L3 hit) */
-#define PM_DATA_FROM_L3MISS		0x300fe
-/* All successful D-side store dispatches for this thread */
-#define PM_L2_ST			0x17080
-/* All successful D-side store dispatches for this thread that were L2 Miss */
-#define PM_L2_ST_MISS			0x17082
-/* Total HW L3 prefetches(Load+store) */
-#define PM_L3_PREF_ALL			0x4e052
-/* Data PTEG reload */
-#define PM_DTLB_MISS			0x300fc
-/* ITLB Reloaded */
-#define PM_ITLB_MISS			0x400fc
+#define EVENT(_name, _code)	_name = _code,
+
+enum {
+#include "power8-events-list.h"
+};
 
+#undef EVENT
 
 /*
  * Raw event encoding for POWER8:
@@ -604,6 +572,71 @@
 		mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SHIFT(pmc + 1));
 }
 
+GENERIC_EVENT_ATTR(cpu-cycles,			PM_CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-frontend,	PM_GCT_NOSLOT_CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-backend,	PM_CMPLU_STALL);
+GENERIC_EVENT_ATTR(instructions,		PM_INST_CMPL);
+GENERIC_EVENT_ATTR(branch-instructions,		PM_BRU_FIN);
+GENERIC_EVENT_ATTR(branch-misses,		PM_BR_MPRED_CMPL);
+GENERIC_EVENT_ATTR(cache-references,		PM_LD_REF_L1);
+GENERIC_EVENT_ATTR(cache-misses,		PM_LD_MISS_L1);
+
+CACHE_EVENT_ATTR(L1-dcache-load-misses,		PM_LD_MISS_L1);
+CACHE_EVENT_ATTR(L1-dcache-loads,		PM_LD_REF_L1);
+
+CACHE_EVENT_ATTR(L1-dcache-prefetches,		PM_L1_PREF);
+CACHE_EVENT_ATTR(L1-dcache-store-misses,	PM_ST_MISS_L1);
+CACHE_EVENT_ATTR(L1-icache-load-misses,		PM_L1_ICACHE_MISS);
+CACHE_EVENT_ATTR(L1-icache-loads,		PM_INST_FROM_L1);
+CACHE_EVENT_ATTR(L1-icache-prefetches,		PM_IC_PREF_WRITE);
+
+CACHE_EVENT_ATTR(LLC-load-misses,		PM_DATA_FROM_L3MISS);
+CACHE_EVENT_ATTR(LLC-loads,			PM_DATA_FROM_L3);
+CACHE_EVENT_ATTR(LLC-prefetches,		PM_L3_PREF_ALL);
+CACHE_EVENT_ATTR(LLC-store-misses,		PM_L2_ST_MISS);
+CACHE_EVENT_ATTR(LLC-stores,			PM_L2_ST);
+
+CACHE_EVENT_ATTR(branch-load-misses,		PM_BR_MPRED_CMPL);
+CACHE_EVENT_ATTR(branch-loads,			PM_BRU_FIN);
+CACHE_EVENT_ATTR(dTLB-load-misses,		PM_DTLB_MISS);
+CACHE_EVENT_ATTR(iTLB-load-misses,		PM_ITLB_MISS);
+
+static struct attribute *power8_events_attr[] = {
+	GENERIC_EVENT_PTR(PM_CYC),
+	GENERIC_EVENT_PTR(PM_GCT_NOSLOT_CYC),
+	GENERIC_EVENT_PTR(PM_CMPLU_STALL),
+	GENERIC_EVENT_PTR(PM_INST_CMPL),
+	GENERIC_EVENT_PTR(PM_BRU_FIN),
+	GENERIC_EVENT_PTR(PM_BR_MPRED_CMPL),
+	GENERIC_EVENT_PTR(PM_LD_REF_L1),
+	GENERIC_EVENT_PTR(PM_LD_MISS_L1),
+
+	CACHE_EVENT_PTR(PM_LD_MISS_L1),
+	CACHE_EVENT_PTR(PM_LD_REF_L1),
+	CACHE_EVENT_PTR(PM_L1_PREF),
+	CACHE_EVENT_PTR(PM_ST_MISS_L1),
+	CACHE_EVENT_PTR(PM_L1_ICACHE_MISS),
+	CACHE_EVENT_PTR(PM_INST_FROM_L1),
+	CACHE_EVENT_PTR(PM_IC_PREF_WRITE),
+	CACHE_EVENT_PTR(PM_DATA_FROM_L3MISS),
+	CACHE_EVENT_PTR(PM_DATA_FROM_L3),
+	CACHE_EVENT_PTR(PM_L3_PREF_ALL),
+	CACHE_EVENT_PTR(PM_L2_ST_MISS),
+	CACHE_EVENT_PTR(PM_L2_ST),
+
+	CACHE_EVENT_PTR(PM_BR_MPRED_CMPL),
+	CACHE_EVENT_PTR(PM_BRU_FIN),
+
+	CACHE_EVENT_PTR(PM_DTLB_MISS),
+	CACHE_EVENT_PTR(PM_ITLB_MISS),
+	NULL
+};
+
+static struct attribute_group power8_pmu_events_group = {
+	.name = "events",
+	.attrs = power8_events_attr,
+};
+
 PMU_FORMAT_ATTR(event,		"config:0-49");
 PMU_FORMAT_ATTR(pmcxsel,	"config:0-7");
 PMU_FORMAT_ATTR(mark,		"config:8");
@@ -640,6 +673,7 @@
 
 static const struct attribute_group *power8_pmu_attr_groups[] = {
 	&power8_pmu_format_group,
+	&power8_pmu_events_group,
 	NULL,
 };
 
@@ -816,7 +850,7 @@
 	.get_constraint		= power8_get_constraint,
 	.get_alternatives	= power8_get_alternatives,
 	.disable_pmc		= power8_disable_pmc,
-	.flags			= PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_ARCH_207S,
+	.flags			= PPMU_HAS_SIER | PPMU_ARCH_207S,
 	.n_generic		= ARRAY_SIZE(power8_generic_events),
 	.generic_events		= power8_generic_events,
 	.cache_events		= &power8_cache_events,
--- linux-4.4.0.orig/arch/powerpc/platforms/83xx/suspend-asm.S
+++ linux-4.4.0/arch/powerpc/platforms/83xx/suspend-asm.S
@@ -26,13 +26,13 @@
 #define SS_MSR		0x74
 #define SS_SDR1		0x78
 #define SS_LR		0x7c
-#define SS_SPRG		0x80 /* 4 SPRGs */
-#define SS_DBAT		0x90 /* 8 DBATs */
-#define SS_IBAT		0xd0 /* 8 IBATs */
-#define SS_TB		0x110
-#define SS_CR		0x118
-#define SS_GPREG	0x11c /* r12-r31 */
-#define STATE_SAVE_SIZE 0x16c
+#define SS_SPRG		0x80 /* 8 SPRGs */
+#define SS_DBAT		0xa0 /* 8 DBATs */
+#define SS_IBAT		0xe0 /* 8 IBATs */
+#define SS_TB		0x120
+#define SS_CR		0x128
+#define SS_GPREG	0x12c /* r12-r31 */
+#define STATE_SAVE_SIZE 0x17c
 
 	.section .data
 	.align	5
@@ -103,6 +103,16 @@
 	stw	r7, SS_SPRG+12(r3)
 	stw	r8, SS_SDR1(r3)
 
+	mfspr	r4, SPRN_SPRG4
+	mfspr	r5, SPRN_SPRG5
+	mfspr	r6, SPRN_SPRG6
+	mfspr	r7, SPRN_SPRG7
+
+	stw	r4, SS_SPRG+16(r3)
+	stw	r5, SS_SPRG+20(r3)
+	stw	r6, SS_SPRG+24(r3)
+	stw	r7, SS_SPRG+28(r3)
+
 	mfspr	r4, SPRN_DBAT0U
 	mfspr	r5, SPRN_DBAT0L
 	mfspr	r6, SPRN_DBAT1U
@@ -493,6 +503,16 @@
 	mtspr	SPRN_IBAT7U, r6
 	mtspr	SPRN_IBAT7L, r7
 
+	lwz	r4, SS_SPRG+16(r3)
+	lwz	r5, SS_SPRG+20(r3)
+	lwz	r6, SS_SPRG+24(r3)
+	lwz	r7, SS_SPRG+28(r3)
+
+	mtspr	SPRN_SPRG4, r4
+	mtspr	SPRN_SPRG5, r5
+	mtspr	SPRN_SPRG6, r6
+	mtspr	SPRN_SPRG7, r7
+
 	lwz	r4, SS_SPRG+0(r3)
 	lwz	r5, SS_SPRG+4(r3)
 	lwz	r6, SS_SPRG+8(r3)
--- linux-4.4.0.orig/arch/powerpc/platforms/Kconfig
+++ linux-4.4.0/arch/powerpc/platforms/Kconfig
@@ -242,7 +242,7 @@
 	  temp is actually what /proc/cpuinfo says it is.
 
 config TAU_INT
-	bool "Interrupt driven TAU driver (DANGEROUS)"
+	bool "Interrupt driven TAU driver (EXPERIMENTAL)"
 	depends on TAU
 	---help---
 	  The TAU supports an interrupt driven mode which causes an interrupt
@@ -250,12 +250,7 @@
 	  to get notified the temp has exceeded a range. With this option off,
 	  a timer is used to re-check the temperature periodically.
 
-	  However, on some cpus it appears that the TAU interrupt hardware
-	  is buggy and can cause a situation which would lead unexplained hard
-	  lockups.
-
-	  Unless you are extending the TAU driver, or enjoy kernel/hardware
-	  debugging, leave this option off.
+	  If in doubt, say N here.
 
 config TAU_AVERAGE
 	bool "Average high and low temp"
--- linux-4.4.0.orig/arch/powerpc/platforms/cell/Kconfig
+++ linux-4.4.0/arch/powerpc/platforms/cell/Kconfig
@@ -50,6 +50,7 @@
 	tristate "SPU file system"
 	default m
 	depends on PPC_CELL
+	depends on COREDUMP
 	select SPU_BASE
 	select MEMORY_HOTPLUG
 	help
--- linux-4.4.0.orig/arch/powerpc/platforms/cell/spufs/coredump.c
+++ linux-4.4.0/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -174,6 +174,8 @@
 	if (!dump_skip(cprm,
 		       roundup(cprm->written - total + sz, 4) - cprm->written))
 		goto Eio;
+
+	rc = 0;
 out:
 	free_page((unsigned long)buf);
 	return rc;
--- linux-4.4.0.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-4.4.0/arch/powerpc/platforms/cell/spufs/file.c
@@ -2044,8 +2044,9 @@
 static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
 				   size_t len, loff_t *pos)
 {
-	int ret;
 	struct spu_context *ctx = file->private_data;
+	u32 stat, data;
+	int ret;
 
 	if (!access_ok(VERIFY_WRITE, buf, len))
 		return -EFAULT;
@@ -2054,11 +2055,16 @@
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
+	stat = ctx->csa.prob.mb_stat_R;
+	data = ctx->csa.prob.pu_mb_R;
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	/* EOF if there's no entry in the mbox */
+	if (!(stat & 0x0000ff))
+		return 0;
+
+	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
 }
 
 static const struct file_operations spufs_mbox_info_fops = {
@@ -2085,6 +2091,7 @@
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	u32 stat, data;
 	int ret;
 
 	if (!access_ok(VERIFY_WRITE, buf, len))
@@ -2094,11 +2101,16 @@
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
+	stat = ctx->csa.prob.mb_stat_R;
+	data = ctx->csa.priv2.puint_mb_R;
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	/* EOF if there's no entry in the ibox */
+	if (!(stat & 0xff0000))
+		return 0;
+
+	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
 }
 
 static const struct file_operations spufs_ibox_info_fops = {
@@ -2107,6 +2119,11 @@
 	.llseek  = generic_file_llseek,
 };
 
+static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
+{
+	return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
+}
+
 static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
 			char __user *buf, size_t len, loff_t *pos)
 {
@@ -2115,7 +2132,7 @@
 	u32 wbox_stat;
 
 	wbox_stat = ctx->csa.prob.mb_stat_R;
-	cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
+	cnt = spufs_wbox_info_cnt(ctx);
 	for (i = 0; i < cnt; i++) {
 		data[i] = ctx->csa.spu_mailbox_data[i];
 	}
@@ -2128,7 +2145,8 @@
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
-	int ret;
+	u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
+	int ret, count;
 
 	if (!access_ok(VERIFY_WRITE, buf, len))
 		return -EFAULT;
@@ -2137,11 +2155,13 @@
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
+	count = spufs_wbox_info_cnt(ctx);
+	memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	return simple_read_from_buffer(buf, len, pos, &data,
+				count * sizeof(u32));
 }
 
 static const struct file_operations spufs_wbox_info_fops = {
@@ -2150,27 +2170,33 @@
 	.llseek  = generic_file_llseek,
 };
 
-static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
-			char __user *buf, size_t len, loff_t *pos)
+static void spufs_get_dma_info(struct spu_context *ctx,
+		struct spu_dma_info *info)
 {
-	struct spu_dma_info info;
-	struct mfc_cq_sr *qp, *spuqp;
 	int i;
 
-	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
-	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
-	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
-	info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
-	info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
+	info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
+	info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
+	info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
+	info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
+	info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
 	for (i = 0; i < 16; i++) {
-		qp = &info.dma_info_command_data[i];
-		spuqp = &ctx->csa.priv2.spuq[i];
+		struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
+		struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
 
 		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
 		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
 		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
 		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
 	}
+}
+
+static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
+			char __user *buf, size_t len, loff_t *pos)
+{
+	struct spu_dma_info info;
+
+	spufs_get_dma_info(ctx, &info);
 
 	return simple_read_from_buffer(buf, len, pos, &info,
 				sizeof info);
@@ -2180,6 +2206,7 @@
 			      size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	struct spu_dma_info info;
 	int ret;
 
 	if (!access_ok(VERIFY_WRITE, buf, len))
@@ -2189,11 +2216,12 @@
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_dma_info_read(ctx, buf, len, pos);
+	spufs_get_dma_info(ctx, &info);
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	return simple_read_from_buffer(buf, len, pos, &info,
+				sizeof(info));
 }
 
 static const struct file_operations spufs_dma_info_fops = {
@@ -2202,13 +2230,31 @@
 	.llseek = no_llseek,
 };
 
+static void spufs_get_proxydma_info(struct spu_context *ctx,
+		struct spu_proxydma_info *info)
+{
+	int i;
+
+	info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
+	info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
+	info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
+
+	for (i = 0; i < 8; i++) {
+		struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
+		struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
+
+		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
+		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
+		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
+		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
+	}
+}
+
 static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
 			char __user *buf, size_t len, loff_t *pos)
 {
 	struct spu_proxydma_info info;
-	struct mfc_cq_sr *qp, *puqp;
 	int ret = sizeof info;
-	int i;
 
 	if (len < ret)
 		return -EINVAL;
@@ -2216,18 +2262,7 @@
 	if (!access_ok(VERIFY_WRITE, buf, len))
 		return -EFAULT;
 
-	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
-	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
-	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
-	for (i = 0; i < 8; i++) {
-		qp = &info.proxydma_info_command_data[i];
-		puqp = &ctx->csa.priv2.puq[i];
-
-		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
-		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
-		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
-		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
-	}
+	spufs_get_proxydma_info(ctx, &info);
 
 	return simple_read_from_buffer(buf, len, pos, &info,
 				sizeof info);
@@ -2237,17 +2272,19 @@
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	struct spu_proxydma_info info;
 	int ret;
 
 	ret = spu_acquire_saved(ctx);
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
+	spufs_get_proxydma_info(ctx, &info);
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	return simple_read_from_buffer(buf, len, pos, &info,
+				sizeof(info));
 }
 
 static const struct file_operations spufs_proxydma_info_fops = {
--- linux-4.4.0.orig/arch/powerpc/platforms/chrp/time.c
+++ linux-4.4.0/arch/powerpc/platforms/chrp/time.c
@@ -27,6 +27,8 @@
 #include <asm/sections.h>
 #include <asm/time.h>
 
+#include <platforms/chrp/chrp.h>
+
 extern spinlock_t rtc_lock;
 
 #define NVRAM_AS0  0x74
@@ -62,7 +64,7 @@
 	return 0;
 }
 
-int chrp_cmos_clock_read(int addr)
+static int chrp_cmos_clock_read(int addr)
 {
 	if (nvram_as1 != 0)
 		outb(addr>>8, nvram_as1);
@@ -70,7 +72,7 @@
 	return (inb(nvram_data));
 }
 
-void chrp_cmos_clock_write(unsigned long val, int addr)
+static void chrp_cmos_clock_write(unsigned long val, int addr)
 {
 	if (nvram_as1 != 0)
 		outb(addr>>8, nvram_as1);
--- linux-4.4.0.orig/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+++ linux-4.4.0/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
@@ -35,6 +35,8 @@
  */
 #define HW_BROADWAY_ICR		0x00
 #define HW_BROADWAY_IMR		0x04
+#define HW_STARLET_ICR		0x08
+#define HW_STARLET_IMR		0x0c
 
 
 /*
@@ -74,6 +76,9 @@
 	void __iomem *io_base = irq_data_get_irq_chip_data(d);
 
 	setbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
+
+	/* Make sure the ARM (aka. Starlet) doesn't handle this interrupt. */
+	clrbits32(io_base + HW_STARLET_IMR, 1 << irq);
 }
 
 
--- linux-4.4.0.orig/arch/powerpc/platforms/embedded6xx/wii.c
+++ linux-4.4.0/arch/powerpc/platforms/embedded6xx/wii.c
@@ -104,6 +104,10 @@
 	/* MEM2 64MB@0x10000000 */
 	delta = wii_hole_start + wii_hole_size;
 	size = top - delta;
+
+	if (__map_without_bats)
+		return delta;
+
 	for (bl = 128<<10; bl < max_size; bl <<= 1) {
 		if (bl * 2 > size)
 			break;
--- linux-4.4.0.orig/arch/powerpc/platforms/powermac/bootx_init.c
+++ linux-4.4.0/arch/powerpc/platforms/powermac/bootx_init.c
@@ -467,7 +467,7 @@
 	boot_infos_t *bi = (boot_infos_t *) r4;
 	unsigned long hdr;
 	unsigned long space;
-	unsigned long ptr, x;
+	unsigned long ptr;
 	char *model;
 	unsigned long offset = reloc_offset();
 
@@ -561,6 +561,8 @@
 	 * MMU switched OFF, so this should not be useful anymore.
 	 */
 	if (bi->version < 4) {
+		unsigned long x __maybe_unused;
+
 		bootx_printf("Touching pages...\n");
 
 		/*
--- linux-4.4.0.orig/arch/powerpc/platforms/powermac/setup.c
+++ linux-4.4.0/arch/powerpc/platforms/powermac/setup.c
@@ -359,6 +359,7 @@
 }
 machine_late_initcall(powermac, pmac_late_init);
 
+void note_bootable_part(dev_t dev, int part, int goodness);
 /*
  * This is __init_refok because we check for "initializing" before
  * touching any of the __init sensitive things and "initializing"
--- linux-4.4.0.orig/arch/powerpc/platforms/powermac/sleep.S
+++ linux-4.4.0/arch/powerpc/platforms/powermac/sleep.S
@@ -37,10 +37,18 @@
 #define SL_IBAT2	0x48
 #define SL_DBAT3	0x50
 #define SL_IBAT3	0x58
-#define SL_TB		0x60
-#define SL_R2		0x68
-#define SL_CR		0x6c
-#define SL_R12		0x70	/* r12 to r31 */
+#define SL_DBAT4	0x60
+#define SL_IBAT4	0x68
+#define SL_DBAT5	0x70
+#define SL_IBAT5	0x78
+#define SL_DBAT6	0x80
+#define SL_IBAT6	0x88
+#define SL_DBAT7	0x90
+#define SL_IBAT7	0x98
+#define SL_TB		0xa0
+#define SL_R2		0xa8
+#define SL_CR		0xac
+#define SL_R12		0xb0	/* r12 to r31 */
 #define SL_SIZE		(SL_R12 + 80)
 
 	.section .text
@@ -125,6 +133,41 @@
 	mfibatl	r4,3
 	stw	r4,SL_IBAT3+4(r1)
 
+BEGIN_MMU_FTR_SECTION
+	mfspr	r4,SPRN_DBAT4U
+	stw	r4,SL_DBAT4(r1)
+	mfspr	r4,SPRN_DBAT4L
+	stw	r4,SL_DBAT4+4(r1)
+	mfspr	r4,SPRN_DBAT5U
+	stw	r4,SL_DBAT5(r1)
+	mfspr	r4,SPRN_DBAT5L
+	stw	r4,SL_DBAT5+4(r1)
+	mfspr	r4,SPRN_DBAT6U
+	stw	r4,SL_DBAT6(r1)
+	mfspr	r4,SPRN_DBAT6L
+	stw	r4,SL_DBAT6+4(r1)
+	mfspr	r4,SPRN_DBAT7U
+	stw	r4,SL_DBAT7(r1)
+	mfspr	r4,SPRN_DBAT7L
+	stw	r4,SL_DBAT7+4(r1)
+	mfspr	r4,SPRN_IBAT4U
+	stw	r4,SL_IBAT4(r1)
+	mfspr	r4,SPRN_IBAT4L
+	stw	r4,SL_IBAT4+4(r1)
+	mfspr	r4,SPRN_IBAT5U
+	stw	r4,SL_IBAT5(r1)
+	mfspr	r4,SPRN_IBAT5L
+	stw	r4,SL_IBAT5+4(r1)
+	mfspr	r4,SPRN_IBAT6U
+	stw	r4,SL_IBAT6(r1)
+	mfspr	r4,SPRN_IBAT6L
+	stw	r4,SL_IBAT6+4(r1)
+	mfspr	r4,SPRN_IBAT7U
+	stw	r4,SL_IBAT7(r1)
+	mfspr	r4,SPRN_IBAT7L
+	stw	r4,SL_IBAT7+4(r1)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+
 	/* Backup various CPU config stuffs */
 	bl	__save_cpu_setup
 
@@ -325,22 +368,37 @@
 	mtibatl	3,r4
 
 BEGIN_MMU_FTR_SECTION
-	li	r4,0
+	lwz	r4,SL_DBAT4(r1)
 	mtspr	SPRN_DBAT4U,r4
+	lwz	r4,SL_DBAT4+4(r1)
 	mtspr	SPRN_DBAT4L,r4
+	lwz	r4,SL_DBAT5(r1)
 	mtspr	SPRN_DBAT5U,r4
+	lwz	r4,SL_DBAT5+4(r1)
 	mtspr	SPRN_DBAT5L,r4
+	lwz	r4,SL_DBAT6(r1)
 	mtspr	SPRN_DBAT6U,r4
+	lwz	r4,SL_DBAT6+4(r1)
 	mtspr	SPRN_DBAT6L,r4
+	lwz	r4,SL_DBAT7(r1)
 	mtspr	SPRN_DBAT7U,r4
+	lwz	r4,SL_DBAT7+4(r1)
 	mtspr	SPRN_DBAT7L,r4
+	lwz	r4,SL_IBAT4(r1)
 	mtspr	SPRN_IBAT4U,r4
+	lwz	r4,SL_IBAT4+4(r1)
 	mtspr	SPRN_IBAT4L,r4
+	lwz	r4,SL_IBAT5(r1)
 	mtspr	SPRN_IBAT5U,r4
+	lwz	r4,SL_IBAT5+4(r1)
 	mtspr	SPRN_IBAT5L,r4
+	lwz	r4,SL_IBAT6(r1)
 	mtspr	SPRN_IBAT6U,r4
+	lwz	r4,SL_IBAT6+4(r1)
 	mtspr	SPRN_IBAT6L,r4
+	lwz	r4,SL_IBAT7(r1)
 	mtspr	SPRN_IBAT7U,r4
+	lwz	r4,SL_IBAT7+4(r1)
 	mtspr	SPRN_IBAT7L,r4
 END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
 
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/Makefile
+++ linux-4.4.0/arch/powerpc/platforms/powernv/Makefile
@@ -2,9 +2,10 @@
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 obj-y			+= opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
+obj-y			+= opal-kmsg.o
 
 obj-$(CONFIG_SMP)	+= smp.o subcore.o subcore-asm.o
-obj-$(CONFIG_PCI)	+= pci.o pci-p5ioc2.o pci-ioda.o
+obj-$(CONFIG_PCI)	+= pci.o pci-p5ioc2.o pci-ioda.o npu-dma.o
 obj-$(CONFIG_EEH)	+= eeh-powernv.o
 obj-$(CONFIG_PPC_SCOM)	+= opal-xscom.o
 obj-$(CONFIG_MEMORY_FAILURE)	+= opal-memory-errors.o
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -48,8 +48,8 @@
 	struct pci_controller *hose;
 	struct pnv_phb *phb;
 
-	if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
-		pr_warn("%s: OPALv3 is required !\n",
+	if (!firmware_has_feature(FW_FEATURE_OPAL)) {
+		pr_warn("%s: OPAL is required !\n",
 			__func__);
 		return -EINVAL;
 	}
@@ -444,9 +444,12 @@
 	 * PCI devices of the PE are expected to be removed prior
 	 * to PE reset.
 	 */
-	if (!edev->pe->bus)
+	if (!(edev->pe->state & EEH_PE_PRI_BUS)) {
 		edev->pe->bus = pci_find_bus(hose->global_number,
 					     pdn->busno);
+		if (edev->pe->bus)
+			edev->pe->state |= EEH_PE_PRI_BUS;
+	}
 
 	/*
 	 * Enable EEH explicitly so that we will do EEH check
@@ -774,7 +777,8 @@
 	 * reset followed by hot reset on root bus. So we also
 	 * need the PCI bus settlement delay.
 	 */
-	rc = pnv_eeh_phb_poll(phb);
+	if (rc > 0)
+		rc = pnv_eeh_phb_poll(phb);
 	if (option == EEH_RESET_DEACTIVATE) {
 		if (system_state < SYSTEM_RUNNING)
 			udelay(1000 * EEH_PE_RST_SETTLE_TIME);
@@ -817,7 +821,8 @@
 		goto out;
 
 	/* Poll state of the PHB until the request is done */
-	rc = pnv_eeh_phb_poll(phb);
+	if (rc > 0)
+		rc = pnv_eeh_phb_poll(phb);
 	if (option == EEH_RESET_DEACTIVATE)
 		msleep(EEH_PE_RST_SETTLE_TIME);
 out:
@@ -953,6 +958,11 @@
 		}
 
 		bus = eeh_pe_bus_get(pe);
+		if (!bus) {
+			pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n",
+			       __func__, pe->phb->global_number, pe->addr);
+			return -EIO;
+		}
 		if (pci_is_root_bus(bus) ||
 			pci_is_root_bus(bus->parent))
 			ret = pnv_eeh_root_reset(hose, option);
@@ -1160,7 +1170,7 @@
 		return;
 	}
 
-	switch (data->type) {
+	switch (be16_to_cpu(data->type)) {
 	case OPAL_P7IOC_DIAG_TYPE_RGC:
 		pr_info("P7IOC diag-data for RGC\n\n");
 		pnv_eeh_dump_hub_diag_common(data);
@@ -1392,7 +1402,7 @@
 
 				/* Try best to clear it */
 				opal_pci_eeh_freeze_clear(phb->opal_id,
-					frozen_pe_no,
+					be64_to_cpu(frozen_pe_no),
 					OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
 				ret = EEH_NEXT_ERR_NONE;
 			} else if ((*pe)->state & EEH_PE_ISOLATED ||
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/idle.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/idle.c
@@ -242,7 +242,7 @@
 	if (cpuidle_disable != IDLE_NO_OVERRIDE)
 		goto out;
 
-	if (!firmware_has_feature(FW_FEATURE_OPALv3))
+	if (!firmware_has_feature(FW_FEATURE_OPAL))
 		goto out;
 
 	power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/npu-dma.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/npu-dma.c
@@ -0,0 +1,348 @@
+/*
+ * This file implements the DMA operations for NVLink devices. The NPU
+ * devices all point to the same iommu table as the parent PCI device.
+ *
+ * Copyright Alistair Popple, IBM Corporation 2015.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+
+#include <linux/export.h>
+#include <linux/pci.h>
+#include <linux/memblock.h>
+
+#include <asm/iommu.h>
+#include <asm/pnv-pci.h>
+#include <asm/msi_bitmap.h>
+#include <asm/opal.h>
+
+#include "powernv.h"
+#include "pci.h"
+
+/*
+ * Other types of TCE cache invalidation are not functional in the
+ * hardware.
+ */
+#define TCE_KILL_INVAL_ALL PPC_BIT(0)
+
+static struct pci_dev *get_pci_dev(struct device_node *dn)
+{
+	return PCI_DN(dn)->pcidev;
+}
+
+/* Given a NPU device get the associated PCI device. */
+struct pci_dev *pnv_pci_get_gpu_dev(struct pci_dev *npdev)
+{
+	struct device_node *dn;
+	struct pci_dev *gpdev;
+
+	/* Get assoicated PCI device */
+	dn = of_parse_phandle(npdev->dev.of_node, "ibm,gpu", 0);
+	if (!dn)
+		return NULL;
+
+	gpdev = get_pci_dev(dn);
+	of_node_put(dn);
+
+	return gpdev;
+}
+EXPORT_SYMBOL(pnv_pci_get_gpu_dev);
+
+/* Given the real PCI device get a linked NPU device. */
+struct pci_dev *pnv_pci_get_npu_dev(struct pci_dev *gpdev, int index)
+{
+	struct device_node *dn;
+	struct pci_dev *npdev;
+
+	/* Get assoicated PCI device */
+	dn = of_parse_phandle(gpdev->dev.of_node, "ibm,npu", index);
+	if (!dn)
+		return NULL;
+
+	npdev = get_pci_dev(dn);
+	of_node_put(dn);
+
+	return npdev;
+}
+EXPORT_SYMBOL(pnv_pci_get_npu_dev);
+
+#define NPU_DMA_OP_UNSUPPORTED()					\
+	dev_err_once(dev, "%s operation unsupported for NVLink devices\n", \
+		__func__)
+
+static void *dma_npu_alloc(struct device *dev, size_t size,
+			   dma_addr_t *dma_handle, gfp_t flag,
+			   struct dma_attrs *attrs)
+{
+	NPU_DMA_OP_UNSUPPORTED();
+	return NULL;
+}
+
+static void dma_npu_free(struct device *dev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle,
+			 struct dma_attrs *attrs)
+{
+	NPU_DMA_OP_UNSUPPORTED();
+}
+
+static dma_addr_t dma_npu_map_page(struct device *dev, struct page *page,
+				   unsigned long offset, size_t size,
+				   enum dma_data_direction direction,
+				   struct dma_attrs *attrs)
+{
+	NPU_DMA_OP_UNSUPPORTED();
+	return 0;
+}
+
+static int dma_npu_map_sg(struct device *dev, struct scatterlist *sglist,
+			  int nelems, enum dma_data_direction direction,
+			  struct dma_attrs *attrs)
+{
+	NPU_DMA_OP_UNSUPPORTED();
+	return 0;
+}
+
+static int dma_npu_dma_supported(struct device *dev, u64 mask)
+{
+	NPU_DMA_OP_UNSUPPORTED();
+	return 0;
+}
+
+static u64 dma_npu_get_required_mask(struct device *dev)
+{
+	NPU_DMA_OP_UNSUPPORTED();
+	return 0;
+}
+
+struct dma_map_ops dma_npu_ops = {
+	.map_page		= dma_npu_map_page,
+	.map_sg			= dma_npu_map_sg,
+	.alloc			= dma_npu_alloc,
+	.free			= dma_npu_free,
+	.dma_supported		= dma_npu_dma_supported,
+	.get_required_mask	= dma_npu_get_required_mask,
+};
+
+/*
+ * Returns the PE assoicated with the PCI device of the given
+ * NPU. Returns the linked pci device if pci_dev != NULL.
+ */
+static struct pnv_ioda_pe *get_gpu_pci_dev_and_pe(struct pnv_ioda_pe *npe,
+						  struct pci_dev **gpdev)
+{
+	struct pnv_phb *phb;
+	struct pci_controller *hose;
+	struct pci_dev *pdev;
+	struct pnv_ioda_pe *pe;
+	struct pci_dn *pdn;
+
+	if (npe->flags & PNV_IODA_PE_PEER) {
+		pe = npe->peers[0];
+		pdev = pe->pdev;
+	} else {
+		pdev = pnv_pci_get_gpu_dev(npe->pdev);
+		if (!pdev)
+			return NULL;
+
+		pdn = pci_get_pdn(pdev);
+		if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
+			return NULL;
+
+		hose = pci_bus_to_host(pdev->bus);
+		phb = hose->private_data;
+		pe = &phb->ioda.pe_array[pdn->pe_number];
+	}
+
+	if (gpdev)
+		*gpdev = pdev;
+
+	return pe;
+}
+
+void pnv_npu_tce_invalidate_entire(struct pnv_ioda_pe *npe)
+{
+	struct pnv_phb *phb = npe->phb;
+
+	if (WARN_ON(phb->type != PNV_PHB_NPU ||
+		    !phb->ioda.tce_inval_reg ||
+		    !(npe->flags & PNV_IODA_PE_DEV)))
+		return;
+
+	mb(); /* Ensure previous TCE table stores are visible */
+	__raw_writeq(cpu_to_be64(TCE_KILL_INVAL_ALL),
+		phb->ioda.tce_inval_reg);
+}
+
+void pnv_npu_tce_invalidate(struct pnv_ioda_pe *npe,
+				struct iommu_table *tbl,
+				unsigned long index,
+				unsigned long npages,
+				bool rm)
+{
+	struct pnv_phb *phb = npe->phb;
+
+	/* We can only invalidate the whole cache on NPU */
+	unsigned long val = TCE_KILL_INVAL_ALL;
+
+	if (WARN_ON(phb->type != PNV_PHB_NPU ||
+		    !phb->ioda.tce_inval_reg ||
+		    !(npe->flags & PNV_IODA_PE_DEV)))
+		return;
+
+	mb(); /* Ensure previous TCE table stores are visible */
+	if (rm)
+		__raw_rm_writeq(cpu_to_be64(val),
+		  (__be64 __iomem *) phb->ioda.tce_inval_reg_phys);
+	else
+		__raw_writeq(cpu_to_be64(val),
+			phb->ioda.tce_inval_reg);
+}
+
+void pnv_npu_init_dma_pe(struct pnv_ioda_pe *npe)
+{
+	struct pnv_ioda_pe *gpe;
+	struct pci_dev *gpdev;
+	int i, avail = -1;
+
+	if (!npe->pdev || !(npe->flags & PNV_IODA_PE_DEV))
+		return;
+
+	gpe = get_gpu_pci_dev_and_pe(npe, &gpdev);
+	if (!gpe)
+		return;
+
+	for (i = 0; i < PNV_IODA_MAX_PEER_PES; i++) {
+		/* Nothing to do if the PE is already connected. */
+		if (gpe->peers[i] == npe)
+			return;
+
+		if (!gpe->peers[i])
+			avail = i;
+	}
+
+	if (WARN_ON(avail < 0))
+		return;
+
+	gpe->peers[avail] = npe;
+	gpe->flags |= PNV_IODA_PE_PEER;
+
+	/*
+	 * We assume that the NPU devices only have a single peer PE
+	 * (the GPU PCIe device PE).
+	 */
+	npe->peers[0] = gpe;
+	npe->flags |= PNV_IODA_PE_PEER;
+}
+
+/*
+ * For the NPU we want to point the TCE table at the same table as the
+ * real PCI device.
+ */
+static void pnv_npu_disable_bypass(struct pnv_ioda_pe *npe)
+{
+	struct pnv_phb *phb = npe->phb;
+	struct pci_dev *gpdev;
+	struct pnv_ioda_pe *gpe;
+	void *addr;
+	unsigned int size;
+	int64_t rc;
+
+	/*
+	 * Find the assoicated PCI devices and get the dma window
+	 * information from there.
+	 */
+	if (!npe->pdev || !(npe->flags & PNV_IODA_PE_DEV))
+		return;
+
+	gpe = get_gpu_pci_dev_and_pe(npe, &gpdev);
+	if (!gpe)
+		return;
+
+	addr = (void *)gpe->table_group.tables[0]->it_base;
+	size = gpe->table_group.tables[0]->it_size << 3;
+	rc = opal_pci_map_pe_dma_window(phb->opal_id, npe->pe_number,
+					npe->pe_number, 1, __pa(addr),
+					size, 0x1000);
+	if (rc != OPAL_SUCCESS)
+		pr_warn("%s: Error %lld setting DMA window on PHB#%d-PE#%d\n",
+			__func__, rc, phb->hose->global_number, npe->pe_number);
+
+	/*
+	 * We don't initialise npu_pe->tce32_table as we always use
+	 * dma_npu_ops which are nops.
+	 */
+	set_dma_ops(&npe->pdev->dev, &dma_npu_ops);
+}
+
+/*
+ * Enable/disable bypass mode on the NPU. The NPU only supports one
+ * window per link, so bypass needs to be explicity enabled or
+ * disabled. Unlike for a PHB3 bypass and non-bypass modes can't be
+ * active at the same time.
+ */
+int pnv_npu_dma_set_bypass(struct pnv_ioda_pe *npe, bool enable)
+{
+	struct pnv_phb *phb = npe->phb;
+	int64_t rc = 0;
+
+	if (phb->type != PNV_PHB_NPU || !npe->pdev)
+		return -EINVAL;
+
+	if (enable) {
+		/* Enable the bypass window */
+		phys_addr_t top = memblock_end_of_DRAM();
+
+		npe->tce_bypass_base = 0;
+		top = roundup_pow_of_two(top);
+		dev_info(&npe->pdev->dev, "Enabling bypass for PE %d\n",
+			 npe->pe_number);
+		rc = opal_pci_map_pe_dma_window_real(phb->opal_id,
+					npe->pe_number, npe->pe_number,
+					npe->tce_bypass_base, top);
+	} else {
+		/*
+		 * Disable the bypass window by replacing it with the
+		 * TCE32 window.
+		 */
+		pnv_npu_disable_bypass(npe);
+	}
+
+	return rc;
+}
+
+int pnv_npu_dma_set_mask(struct pci_dev *npdev, u64 dma_mask)
+{
+	struct pci_controller *hose = pci_bus_to_host(npdev->bus);
+	struct pnv_phb *phb = hose->private_data;
+	struct pci_dn *pdn = pci_get_pdn(npdev);
+	struct pnv_ioda_pe *npe, *gpe;
+	struct pci_dev *gpdev;
+	uint64_t top;
+	bool bypass = false;
+
+	if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
+		return -ENXIO;
+
+	/* We only do bypass if it's enabled on the linked device */
+	npe = &phb->ioda.pe_array[pdn->pe_number];
+	gpe = get_gpu_pci_dev_and_pe(npe, &gpdev);
+	if (!gpe)
+		return -ENODEV;
+
+	if (gpe->tce_bypass_enabled) {
+		top = gpe->tce_bypass_base + memblock_end_of_DRAM() - 1;
+		bypass = (dma_mask >= top);
+	}
+
+	if (bypass)
+		dev_info(&npdev->dev, "Using 64-bit DMA iommu bypass\n");
+	else
+		dev_info(&npdev->dev, "Using 32-bit DMA via iommu\n");
+
+	pnv_npu_dma_set_bypass(npe, bypass);
+	*npdev->dev.dma_mask = dma_mask;
+
+	return 0;
+}
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal-async.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal-async.c
@@ -39,18 +39,18 @@
 	int token;
 
 	spin_lock_irqsave(&opal_async_comp_lock, flags);
-	token = find_first_bit(opal_async_complete_map, opal_max_async_tokens);
+	token = find_first_zero_bit(opal_async_token_map, opal_max_async_tokens);
 	if (token >= opal_max_async_tokens) {
 		token = -EBUSY;
 		goto out;
 	}
 
-	if (__test_and_set_bit(token, opal_async_token_map)) {
+	if (!__test_and_clear_bit(token, opal_async_complete_map)) {
 		token = -EBUSY;
 		goto out;
 	}
 
-	__clear_bit(token, opal_async_complete_map);
+	__set_bit(token, opal_async_token_map);
 
 out:
 	spin_unlock_irqrestore(&opal_async_comp_lock, flags);
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal-dump.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal-dump.c
@@ -319,15 +319,14 @@
 	return count;
 }
 
-static struct dump_obj *create_dump_obj(uint32_t id, size_t size,
-					uint32_t type)
+static void create_dump_obj(uint32_t id, size_t size, uint32_t type)
 {
 	struct dump_obj *dump;
 	int rc;
 
 	dump = kzalloc(sizeof(*dump), GFP_KERNEL);
 	if (!dump)
-		return NULL;
+		return;
 
 	dump->kobj.kset = dump_kset;
 
@@ -347,33 +346,51 @@
 	rc = kobject_add(&dump->kobj, NULL, "0x%x-0x%x", type, id);
 	if (rc) {
 		kobject_put(&dump->kobj);
-		return NULL;
+		return;
 	}
 
+	/*
+	 * As soon as the sysfs file for this dump is created/activated there is
+	 * a chance the opal_errd daemon (or any userspace) might read and
+	 * acknowledge the dump before kobject_uevent() is called. If that
+	 * happens then there is a potential race between
+	 * dump_ack_store->kobject_put() and kobject_uevent() which leads to a
+	 * use-after-free of a kernfs object resulting in a kernel crash.
+	 *
+	 * To avoid that, we need to take a reference on behalf of the bin file,
+	 * so that our reference remains valid while we call kobject_uevent().
+	 * We then drop our reference before exiting the function, leaving the
+	 * bin file to drop the last reference (if it hasn't already).
+	 */
+
+	/* Take a reference for the bin file */
+	kobject_get(&dump->kobj);
 	rc = sysfs_create_bin_file(&dump->kobj, &dump->dump_attr);
-	if (rc) {
+	if (rc == 0) {
+		kobject_uevent(&dump->kobj, KOBJ_ADD);
+
+		pr_info("%s: New platform dump. ID = 0x%x Size %u\n",
+			__func__, dump->id, dump->size);
+	} else {
+		/* Drop reference count taken for bin file */
 		kobject_put(&dump->kobj);
-		return NULL;
 	}
 
-	pr_info("%s: New platform dump. ID = 0x%x Size %u\n",
-		__func__, dump->id, dump->size);
-
-	kobject_uevent(&dump->kobj, KOBJ_ADD);
-
-	return dump;
+	/* Drop our reference */
+	kobject_put(&dump->kobj);
+	return;
 }
 
 static irqreturn_t process_dump(int irq, void *data)
 {
 	int rc;
 	uint32_t dump_id, dump_size, dump_type;
-	struct dump_obj *dump;
 	char name[22];
+	struct kobject *kobj;
 
 	rc = dump_read_info(&dump_id, &dump_size, &dump_type);
 	if (rc != OPAL_SUCCESS)
-		return rc;
+		return IRQ_HANDLED;
 
 	sprintf(name, "0x%x-0x%x", dump_type, dump_id);
 
@@ -381,12 +398,14 @@
 	 * that gracefully and not create two conflicting
 	 * entries.
 	 */
-	if (kset_find_obj(dump_kset, name))
-		return 0;
+	kobj = kset_find_obj(dump_kset, name);
+	if (kobj) {
+		/* Drop reference added by kset_find_obj() */
+		kobject_put(kobj);
+		return IRQ_HANDLED;
+	}
 
-	dump = create_dump_obj(dump_id, dump_size, dump_type);
-	if (!dump)
-		return -1;
+	create_dump_obj(dump_id, dump_size, dump_type);
 
 	return IRQ_HANDLED;
 }
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal-elog.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal-elog.c
@@ -183,14 +183,14 @@
 	return count;
 }
 
-static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
+static void create_elog_obj(uint64_t id, size_t size, uint64_t type)
 {
 	struct elog_obj *elog;
 	int rc;
 
 	elog = kzalloc(sizeof(*elog), GFP_KERNEL);
 	if (!elog)
-		return NULL;
+		return;
 
 	elog->kobj.kset = elog_kset;
 
@@ -223,18 +223,37 @@
 	rc = kobject_add(&elog->kobj, NULL, "0x%llx", id);
 	if (rc) {
 		kobject_put(&elog->kobj);
-		return NULL;
+		return;
 	}
 
+	/*
+	 * As soon as the sysfs file for this elog is created/activated there is
+	 * a chance the opal_errd daemon (or any userspace) might read and
+	 * acknowledge the elog before kobject_uevent() is called. If that
+	 * happens then there is a potential race between
+	 * elog_ack_store->kobject_put() and kobject_uevent() which leads to a
+	 * use-after-free of a kernfs object resulting in a kernel crash.
+	 *
+	 * To avoid that, we need to take a reference on behalf of the bin file,
+	 * so that our reference remains valid while we call kobject_uevent().
+	 * We then drop our reference before exiting the function, leaving the
+	 * bin file to drop the last reference (if it hasn't already).
+	 */
+
+	/* Take a reference for the bin file */
+	kobject_get(&elog->kobj);
 	rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr);
-	if (rc) {
+	if (rc == 0) {
+		kobject_uevent(&elog->kobj, KOBJ_ADD);
+	} else {
+		/* Drop the reference taken for the bin file */
 		kobject_put(&elog->kobj);
-		return NULL;
 	}
 
-	kobject_uevent(&elog->kobj, KOBJ_ADD);
+	/* Drop our reference */
+	kobject_put(&elog->kobj);
 
-	return elog;
+	return;
 }
 
 static irqreturn_t elog_event(int irq, void *data)
@@ -247,6 +266,7 @@
 	uint64_t elog_type;
 	int rc;
 	char name[2+16+1];
+	struct kobject *kobj;
 
 	rc = opal_get_elog_size(&id, &size, &type);
 	if (rc != OPAL_SUCCESS) {
@@ -269,8 +289,12 @@
 	 * that gracefully and not create two conflicting
 	 * entries.
 	 */
-	if (kset_find_obj(elog_kset, name))
+	kobj = kset_find_obj(elog_kset, name);
+	if (kobj) {
+		/* Drop reference added by kset_find_obj() */
+		kobject_put(kobj);
 		return IRQ_HANDLED;
+	}
 
 	create_elog_obj(log_id, elog_size, elog_type);
 
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal-kmsg.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal-kmsg.c
@@ -0,0 +1,75 @@
+/*
+ * kmsg dumper that ensures the OPAL console fully flushes panic messages
+ *
+ * Author: Russell Currey <ruscur@russell.cc>
+ *
+ * Copyright 2015 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kmsg_dump.h>
+
+#include <asm/opal.h>
+#include <asm/opal-api.h>
+
+/*
+ * Console output is controlled by OPAL firmware.  The kernel regularly calls
+ * OPAL_POLL_EVENTS, which flushes some console output.  In a panic state,
+ * however, the kernel no longer calls OPAL_POLL_EVENTS and the panic message
+ * may not be completely printed.  This function does not actually dump the
+ * message, it just ensures that OPAL completely flushes the console buffer.
+ */
+static void force_opal_console_flush(struct kmsg_dumper *dumper,
+				     enum kmsg_dump_reason reason)
+{
+	int i;
+	int64_t ret;
+
+	/*
+	 * Outside of a panic context the pollers will continue to run,
+	 * so we don't need to do any special flushing.
+	 */
+	if (reason != KMSG_DUMP_PANIC)
+		return;
+
+	if (opal_check_token(OPAL_CONSOLE_FLUSH)) {
+		ret = opal_console_flush(0);
+
+		if (ret == OPAL_UNSUPPORTED || ret == OPAL_PARAMETER)
+			return;
+
+		/* Incrementally flush until there's nothing left */
+		while (opal_console_flush(0) != OPAL_SUCCESS);
+	} else {
+		/*
+		 * If OPAL_CONSOLE_FLUSH is not implemented in the firmware,
+		 * the console can still be flushed by calling the polling
+		 * function enough times to flush the buffer.  We don't know
+		 * how much output still needs to be flushed, but we can be
+		 * generous since the kernel is in panic and doesn't need
+		 * to do much else.
+		 */
+		printk(KERN_NOTICE "opal: OPAL_CONSOLE_FLUSH missing.\n");
+		for (i = 0; i < 1024; i++) {
+			opal_poll_events(NULL);
+		}
+	}
+}
+
+static struct kmsg_dumper opal_kmsg_dumper = {
+	.dump = force_opal_console_flush
+};
+
+void __init opal_kmsg_init(void)
+{
+	int rc;
+
+	/* Add our dumper to the list */
+	rc = kmsg_dump_register(&opal_kmsg_dumper);
+	if (rc != 0)
+		pr_err("opal: kmsg_dump_register failed; returned %d\n", rc);
+}
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal-msglog.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal-msglog.c
@@ -92,7 +92,7 @@
 }
 
 static struct bin_attribute opal_msglog_attr = {
-	.attr = {.name = "msglog", .mode = 0444},
+	.attr = {.name = "msglog", .mode = 0400},
 	.read = opal_msglog_read
 };
 
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal-nvram.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal-nvram.c
@@ -11,6 +11,7 @@
 
 #define DEBUG
 
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/of.h>
@@ -43,6 +44,10 @@
 	return count;
 }
 
+/*
+ * This can be called in the panic path with interrupts off, so use
+ * mdelay in that case.
+ */
 static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index)
 {
 	s64 rc = OPAL_BUSY;
@@ -56,9 +61,23 @@
 
 	while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
 		rc = opal_write_nvram(__pa(buf), count, off);
-		if (rc == OPAL_BUSY_EVENT)
+		if (rc == OPAL_BUSY_EVENT) {
+			if (in_interrupt() || irqs_disabled())
+				mdelay(OPAL_BUSY_DELAY_MS);
+			else
+				msleep(OPAL_BUSY_DELAY_MS);
 			opal_poll_events(NULL);
+		} else if (rc == OPAL_BUSY) {
+			if (in_interrupt() || irqs_disabled())
+				mdelay(OPAL_BUSY_DELAY_MS);
+			else
+				msleep(OPAL_BUSY_DELAY_MS);
+		}
 	}
+
+	if (rc)
+		return -EIO;
+
 	*index += count;
 	return count;
 }
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -64,7 +64,6 @@
 	OPAL_BRANCH(opal_tracepoint_entry) \
 	mfcr	r12;			\
 	stw	r12,8(r1);		\
-	std	r1,PACAR1(r13);		\
 	li	r11,0;			\
 	mfmsr	r12;			\
 	ori	r11,r11,MSR_EE;		\
@@ -127,7 +126,6 @@
 	mfcr	r12
 	std	r11,16(r1)
 	stw	r12,8(r1)
-	std	r1,PACAR1(r13)
 	li	r11,0
 	mfmsr	r12
 	ori	r11,r11,MSR_EE
@@ -148,7 +146,7 @@
 opal_tracepoint_return:
 	std	r3,STK_REG(R31)(r1)
 	mr	r4,r3
-	ld	r0,STK_REG(R23)(r1)
+	ld	r3,STK_REG(R23)(r1)
 	bl	__trace_opal_exit
 	ld	r3,STK_REG(R31)(r1)
 	addi	r1,r1,STACKFRAMESIZE
@@ -301,3 +299,4 @@
 OPAL_CALL(opal_prd_msg,				OPAL_PRD_MSG);
 OPAL_CALL(opal_leds_get_ind,			OPAL_LEDS_GET_INDICATOR);
 OPAL_CALL(opal_leds_set_ind,			OPAL_LEDS_SET_INDICATOR);
+OPAL_CALL(opal_console_flush,			OPAL_CONSOLE_FLUSH);
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal-xscom.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal-xscom.c
@@ -126,7 +126,7 @@
 
 static int opal_xscom_init(void)
 {
-	if (firmware_has_feature(FW_FEATURE_OPALv3))
+	if (firmware_has_feature(FW_FEATURE_OPAL))
 		scom_init(&opal_scom_controller);
 	return 0;
 }
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/opal.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/opal.c
@@ -98,16 +98,11 @@
 	pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%d)\n",
 		 opal.size, sizep, runtimesz);
 
-	powerpc_firmware_features |= FW_FEATURE_OPAL;
 	if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
-		powerpc_firmware_features |= FW_FEATURE_OPALv2;
-		powerpc_firmware_features |= FW_FEATURE_OPALv3;
-		pr_info("OPAL V3 detected !\n");
-	} else if (of_flat_dt_is_compatible(node, "ibm,opal-v2")) {
-		powerpc_firmware_features |= FW_FEATURE_OPALv2;
-		pr_info("OPAL V2 detected !\n");
+		powerpc_firmware_features |= FW_FEATURE_OPAL;
+		pr_info("OPAL detected !\n");
 	} else {
-		pr_info("OPAL V1 detected !\n");
+		panic("OPAL != V3 detected, no longer supported.\n");
 	}
 
 	/* Reinit all cores with the right endian */
@@ -352,17 +347,15 @@
 	 * enough room and be done with it
 	 */
 	spin_lock_irqsave(&opal_write_lock, flags);
-	if (firmware_has_feature(FW_FEATURE_OPALv2)) {
-		rc = opal_console_write_buffer_space(vtermno, &olen);
-		len = be64_to_cpu(olen);
-		if (rc || len < total_len) {
-			spin_unlock_irqrestore(&opal_write_lock, flags);
-			/* Closed -> drop characters */
-			if (rc)
-				return total_len;
-			opal_poll_events(NULL);
-			return -EAGAIN;
-		}
+	rc = opal_console_write_buffer_space(vtermno, &olen);
+	len = be64_to_cpu(olen);
+	if (rc || len < total_len) {
+		spin_unlock_irqrestore(&opal_write_lock, flags);
+		/* Closed -> drop characters */
+		if (rc)
+			return total_len;
+		opal_poll_events(NULL);
+		return -EAGAIN;
 	}
 
 	/* We still try to handle partial completions, though they
@@ -378,7 +371,7 @@
 		/* Closed or other error drop */
 		if (rc != OPAL_SUCCESS && rc != OPAL_BUSY &&
 		    rc != OPAL_BUSY_EVENT) {
-			written = total_len;
+			written += total_len;
 			break;
 		}
 		if (rc == OPAL_SUCCESS) {
@@ -408,6 +401,7 @@
 
 	if (!(regs->msr & MSR_RI)) {
 		/* If MSR_RI isn't set, we cannot recover */
+		pr_err("Machine check interrupt unrecoverable: MSR(RI=0)\n");
 		recovered = 0;
 	} else if (evt->disposition == MCE_DISPOSITION_RECOVERED) {
 		/* Platform corrected itself */
@@ -587,7 +581,10 @@
 				       bin_attr->size);
 }
 
-static BIN_ATTR_RO(symbol_map, 0);
+static struct bin_attribute symbol_map_attr = {
+	.attr = {.name = "symbol_map", .mode = 0400},
+	.read = symbol_map_read
+};
 
 static void opal_export_symmap(void)
 {
@@ -604,10 +601,10 @@
 		return;
 
 	/* Setup attributes */
-	bin_attr_symbol_map.private = __va(be64_to_cpu(syms[0]));
-	bin_attr_symbol_map.size = be64_to_cpu(syms[1]);
+	symbol_map_attr.private = __va(be64_to_cpu(syms[0]));
+	symbol_map_attr.size = be64_to_cpu(syms[1]);
 
-	rc = sysfs_create_bin_file(opal_kobj, &bin_attr_symbol_map);
+	rc = sysfs_create_bin_file(opal_kobj, &symbol_map_attr);
 	if (rc)
 		pr_warn("Error %d creating OPAL symbols file\n", rc);
 }
@@ -696,10 +693,7 @@
 	}
 
 	/* Register OPAL consoles if any ports */
-	if (firmware_has_feature(FW_FEATURE_OPALv2))
-		consoles = of_find_node_by_path("/ibm,opal/consoles");
-	else
-		consoles = of_node_get(opal_node);
+	consoles = of_find_node_by_path("/ibm,opal/consoles");
 	if (consoles) {
 		for_each_child_of_node(consoles, np) {
 			if (strcmp(np->name, "serial"))
@@ -758,6 +752,9 @@
 	opal_pdev_init(opal_node, "ibm,opal-flash");
 	opal_pdev_init(opal_node, "ibm,opal-prd");
 
+	/* Initialise OPAL kmsg dumper for flushing console on panic */
+	opal_kmsg_init();
+
 	return 0;
 }
 machine_subsys_initcall(powernv, opal_init);
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/pci-ioda.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -116,16 +116,6 @@
 }
 early_param("iommu", iommu_setup);
 
-/*
- * stdcix is only supposed to be used in hypervisor real mode as per
- * the architecture spec
- */
-static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
-{
-	__asm__ __volatile__("stdcix %0,0,%1"
-		: : "r" (val), "r" (paddr) : "memory");
-}
-
 static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)
 {
 	return ((flags & (IORESOURCE_MEM_64 | IORESOURCE_PREFETCH)) ==
@@ -344,7 +334,7 @@
 		return;
 	}
 
-	if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
+	if (!firmware_has_feature(FW_FEATURE_OPAL)) {
 		pr_info("  Firmware too old to support M64 window\n");
 		return;
 	}
@@ -780,8 +770,12 @@
 		return -ENXIO;
 	}
 
-	/* Configure PELTV */
-	pnv_ioda_set_peltv(phb, pe, true);
+	/*
+	 * Configure PELTV. NPUs don't have a PELTV table so skip
+	 * configuration on them.
+	 */
+	if (phb->type != PNV_PHB_NPU)
+		pnv_ioda_set_peltv(phb, pe, true);
 
 	/* Setup reverse map */
 	for (rid = pe->rid; rid < rid_end; rid++)
@@ -924,7 +918,6 @@
 }
 #endif /* CONFIG_PCI_IOV */
 
-#if 0
 static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)
 {
 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
@@ -941,11 +934,7 @@
 	if (pdn->pe_number != IODA_INVALID_PE)
 		return NULL;
 
-	/* PE#0 has been pre-set */
-	if (dev->bus->number == 0)
-		pe_num = 0;
-	else
-		pe_num = pnv_ioda_alloc_pe(phb);
+	pe_num = pnv_ioda_alloc_pe(phb);
 	if (pe_num == IODA_INVALID_PE) {
 		pr_warning("%s: Not enough PE# available, disabling device\n",
 			   pci_name(dev));
@@ -963,6 +952,7 @@
 	pci_dev_get(dev);
 	pdn->pcidev = dev;
 	pdn->pe_number = pe_num;
+	pe->flags = PNV_IODA_PE_DEV;
 	pe->pdev = dev;
 	pe->pbus = NULL;
 	pe->tce32_seg = -1;
@@ -993,7 +983,6 @@
 
 	return pe;
 }
-#endif /* Useful for SRIOV case */
 
 static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)
 {
@@ -1007,6 +996,7 @@
 				pci_name(dev));
 			continue;
 		}
+		pdn->pcidev = dev;
 		pdn->pe_number = pe->pe_number;
 		pe->dma_weight += pnv_ioda_dma_weight(dev);
 		if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate)
@@ -1083,6 +1073,77 @@
 	pnv_ioda_link_pe_by_weight(phb, pe);
 }
 
+static struct pnv_ioda_pe *pnv_ioda_setup_npu_PE(struct pci_dev *npu_pdev)
+{
+	int pe_num, found_pe = false, rc;
+	long rid;
+	struct pnv_ioda_pe *pe;
+	struct pci_dev *gpu_pdev;
+	struct pci_dn *npu_pdn;
+	struct pci_controller *hose = pci_bus_to_host(npu_pdev->bus);
+	struct pnv_phb *phb = hose->private_data;
+
+	/*
+	 * Due to a hardware errata PE#0 on the NPU is reserved for
+	 * error handling. This means we only have three PEs remaining
+	 * which need to be assigned to four links, implying some
+	 * links must share PEs.
+	 *
+	 * To achieve this we assign PEs such that NPUs linking the
+	 * same GPU get assigned the same PE.
+	 */
+	gpu_pdev = pnv_pci_get_gpu_dev(npu_pdev);
+	for (pe_num = 0; pe_num < phb->ioda.total_pe; pe_num++) {
+		pe = &phb->ioda.pe_array[pe_num];
+		if (!pe->pdev)
+			continue;
+
+		if (pnv_pci_get_gpu_dev(pe->pdev) == gpu_pdev) {
+			/*
+			 * This device has the same peer GPU so should
+			 * be assigned the same PE as the existing
+			 * peer NPU.
+			 */
+			dev_info(&npu_pdev->dev,
+				"Associating to existing PE %d\n", pe_num);
+			pci_dev_get(npu_pdev);
+			npu_pdn = pci_get_pdn(npu_pdev);
+			rid = npu_pdev->bus->number << 8 | npu_pdn->devfn;
+			npu_pdn->pcidev = npu_pdev;
+			npu_pdn->pe_number = pe_num;
+			pe->dma_weight += pnv_ioda_dma_weight(npu_pdev);
+			phb->ioda.pe_rmap[rid] = pe->pe_number;
+
+			/* Map the PE to this link */
+			rc = opal_pci_set_pe(phb->opal_id, pe_num, rid,
+					OpalPciBusAll,
+					OPAL_COMPARE_RID_DEVICE_NUMBER,
+					OPAL_COMPARE_RID_FUNCTION_NUMBER,
+					OPAL_MAP_PE);
+			WARN_ON(rc != OPAL_SUCCESS);
+			found_pe = true;
+			break;
+		}
+	}
+
+	if (!found_pe)
+		/*
+		 * Could not find an existing PE so allocate a new
+		 * one.
+		 */
+		return pnv_ioda_setup_dev_PE(npu_pdev);
+	else
+		return pe;
+}
+
+static void pnv_ioda_setup_npu_PEs(struct pci_bus *bus)
+{
+	struct pci_dev *pdev;
+
+	list_for_each_entry(pdev, &bus->devices, bus_list)
+		pnv_ioda_setup_npu_PE(pdev);
+}
+
 static void pnv_ioda_setup_PEs(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
@@ -1119,7 +1180,17 @@
 		if (phb->reserve_m64_pe)
 			phb->reserve_m64_pe(hose->bus, NULL, true);
 
-		pnv_ioda_setup_PEs(hose->bus);
+		/*
+		 * On NPU PHB, we expect separate PEs for individual PCI
+		 * functions. PCI bus dependent PEs are required for the
+		 * remaining types of PHBs.
+		 */
+		if (phb->type == PNV_PHB_NPU) {
+			/* PE#0 is needed for error reporting */
+			pnv_ioda_reserve_pe(phb, 0);
+			pnv_ioda_setup_npu_PEs(hose->bus);
+		} else
+			pnv_ioda_setup_PEs(hose->bus);
 	}
 }
 
@@ -1578,6 +1649,8 @@
 	struct pnv_ioda_pe *pe;
 	uint64_t top;
 	bool bypass = false;
+	struct pci_dev *linked_npu_dev;
+	int i;
 
 	if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
 		return -ENODEV;;
@@ -1596,6 +1669,18 @@
 		set_dma_ops(&pdev->dev, &dma_iommu_ops);
 	}
 	*pdev->dev.dma_mask = dma_mask;
+
+	/* Update peer npu devices */
+	if (pe->flags & PNV_IODA_PE_PEER)
+		for (i = 0; i < PNV_IODA_MAX_PEER_PES; i++) {
+			if (!pe->peers[i])
+				continue;
+
+			linked_npu_dev = pe->peers[i]->pdev;
+			if (dma_get_mask(&linked_npu_dev->dev) != dma_mask)
+				dma_set_mask(&linked_npu_dev->dev, dma_mask);
+		}
+
 	return 0;
 }
 
@@ -1740,12 +1825,23 @@
 	/* 01xb - invalidate TCEs that match the specified PE# */
 	unsigned long val = (0x4ull << 60) | (pe->pe_number & 0xFF);
 	struct pnv_phb *phb = pe->phb;
+	struct pnv_ioda_pe *npe;
+	int i;
 
 	if (!phb->ioda.tce_inval_reg)
 		return;
 
 	mb(); /* Ensure above stores are visible */
 	__raw_writeq(cpu_to_be64(val), phb->ioda.tce_inval_reg);
+
+	if (pe->flags & PNV_IODA_PE_PEER)
+		for (i = 0; i < PNV_IODA_MAX_PEER_PES; i++) {
+			npe = pe->peers[i];
+			if (!npe || npe->phb->type != PNV_PHB_NPU)
+				continue;
+
+			pnv_npu_tce_invalidate_entire(npe);
+		}
 }
 
 static void pnv_pci_ioda2_do_tce_invalidate(unsigned pe_number, bool rm,
@@ -1780,15 +1876,28 @@
 	struct iommu_table_group_link *tgl;
 
 	list_for_each_entry_rcu(tgl, &tbl->it_group_list, next) {
+		struct pnv_ioda_pe *npe;
 		struct pnv_ioda_pe *pe = container_of(tgl->table_group,
 				struct pnv_ioda_pe, table_group);
 		__be64 __iomem *invalidate = rm ?
 			(__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys :
 			pe->phb->ioda.tce_inval_reg;
+		int i;
 
 		pnv_pci_ioda2_do_tce_invalidate(pe->pe_number, rm,
 			invalidate, tbl->it_page_shift,
 			index, npages);
+
+		if (pe->flags & PNV_IODA_PE_PEER)
+			/* Invalidate PEs using the same TCE table */
+			for (i = 0; i < PNV_IODA_MAX_PEER_PES; i++) {
+				npe = pe->peers[i];
+				if (!npe || npe->phb->type != PNV_PHB_NPU)
+					continue;
+
+				pnv_npu_tce_invalidate(npe, tbl, index,
+							npages, rm);
+			}
 	}
 }
 
@@ -2270,6 +2379,9 @@
 	level_shift = entries_shift + 3;
 	level_shift = max_t(unsigned, level_shift, PAGE_SHIFT);
 
+	if ((level_shift - 3) * levels + page_shift >= 55)
+		return -EINVAL;
+
 	/* Allocate TCE table */
 	addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift,
 			levels, tce_table_size, &offset, &total_allocated);
@@ -2436,10 +2548,17 @@
 			pe_info(pe, "DMA weight %d, assigned %d DMA32 segments\n",
 				pe->dma_weight, segs);
 			pnv_pci_ioda_setup_dma_pe(phb, pe, base, segs);
-		} else {
+		} else if (phb->type == PNV_PHB_IODA2) {
 			pe_info(pe, "Assign DMA32 space\n");
 			segs = 0;
 			pnv_pci_ioda2_setup_dma_pe(phb, pe);
+		} else if (phb->type == PNV_PHB_NPU) {
+			/*
+			 * We initialise the DMA space for an NPU PHB
+			 * after setup of the PHB is complete as we
+			 * point the NPU TVT to the the same location
+			 * as the PHB3 TVT.
+			 */
 		}
 
 		remaining -= segs;
@@ -2881,6 +3000,11 @@
 
 	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
 		phb = hose->private_data;
+
+		/* NPU PHB does not support IO or MMIO segmentation */
+		if (phb->type == PNV_PHB_NPU)
+			continue;
+
 		list_for_each_entry(pe, &phb->ioda.pe_list, list) {
 			pnv_ioda_setup_pe_seg(hose, pe);
 		}
@@ -2920,6 +3044,27 @@
 #endif /* CONFIG_DEBUG_FS */
 }
 
+static void pnv_npu_ioda_fixup(void)
+{
+	bool enable_bypass;
+	struct pci_controller *hose, *tmp;
+	struct pnv_phb *phb;
+	struct pnv_ioda_pe *pe;
+
+	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+		phb = hose->private_data;
+		if (phb->type != PNV_PHB_NPU)
+			continue;
+
+		list_for_each_entry(pe, &phb->ioda.pe_dma_list, dma_link) {
+			enable_bypass = dma_get_mask(&pe->pdev->dev) ==
+				DMA_BIT_MASK(64);
+			pnv_npu_init_dma_pe(pe);
+			pnv_npu_dma_set_bypass(pe, enable_bypass);
+		}
+	}
+}
+
 static void pnv_pci_ioda_fixup(void)
 {
 	pnv_pci_ioda_setup_PEs();
@@ -2932,6 +3077,9 @@
 	eeh_init();
 	eeh_addr_cache_build();
 #endif
+
+	/* Link NPU IODA tables to their PCI devices. */
+	pnv_npu_ioda_fixup();
 }
 
 /*
@@ -3034,6 +3182,7 @@
 
 static const struct pci_controller_ops pnv_pci_ioda_controller_ops = {
        .dma_dev_setup = pnv_pci_dma_dev_setup,
+       .dma_bus_setup = pnv_pci_dma_bus_setup,
 #ifdef CONFIG_PCI_MSI
        .setup_msi_irqs = pnv_setup_msi_irqs,
        .teardown_msi_irqs = pnv_teardown_msi_irqs,
@@ -3046,6 +3195,19 @@
        .shutdown = pnv_pci_ioda_shutdown,
 };
 
+static const struct pci_controller_ops pnv_npu_ioda_controller_ops = {
+	.dma_dev_setup = pnv_pci_dma_dev_setup,
+#ifdef CONFIG_PCI_MSI
+	.setup_msi_irqs = pnv_setup_msi_irqs,
+	.teardown_msi_irqs = pnv_teardown_msi_irqs,
+#endif
+	.enable_device_hook = pnv_pci_enable_device_hook,
+	.window_alignment = pnv_pci_window_alignment,
+	.reset_secondary_bus = pnv_pci_reset_secondary_bus,
+	.dma_set_mask = pnv_npu_dma_set_mask,
+	.shutdown = pnv_pci_ioda_shutdown,
+};
+
 static void __init pnv_pci_init_ioda_phb(struct device_node *np,
 					 u64 hub_id, int ioda_type)
 {
@@ -3101,6 +3263,8 @@
 		phb->model = PNV_PHB_MODEL_P7IOC;
 	else if (of_device_is_compatible(np, "ibm,power8-pciex"))
 		phb->model = PNV_PHB_MODEL_PHB3;
+	else if (of_device_is_compatible(np, "ibm,power8-npu-pciex"))
+		phb->model = PNV_PHB_MODEL_NPU;
 	else
 		phb->model = PNV_PHB_MODEL_UNKNOWN;
 
@@ -3201,7 +3365,11 @@
 	 * the child P2P bridges) can form individual PE.
 	 */
 	ppc_md.pcibios_fixup = pnv_pci_ioda_fixup;
-	hose->controller_ops = pnv_pci_ioda_controller_ops;
+
+	if (phb->type == PNV_PHB_NPU)
+		hose->controller_ops = pnv_npu_ioda_controller_ops;
+	else
+		hose->controller_ops = pnv_pci_ioda_controller_ops;
 
 #ifdef CONFIG_PCI_IOV
 	ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov_resources;
@@ -3236,6 +3404,11 @@
 	pnv_pci_init_ioda_phb(np, 0, PNV_PHB_IODA2);
 }
 
+void __init pnv_pci_init_npu_phb(struct device_node *np)
+{
+	pnv_pci_init_ioda_phb(np, 0, PNV_PHB_NPU);
+}
+
 void __init pnv_pci_init_ioda_hub(struct device_node *np)
 {
 	struct device_node *phbn;
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/pci.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/pci.c
@@ -197,8 +197,8 @@
 			be64_to_cpu(data->dma1ErrorLog1));
 
 	for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
-		if ((data->pestA[i] >> 63) == 0 &&
-		    (data->pestB[i] >> 63) == 0)
+		if ((be64_to_cpu(data->pestA[i]) >> 63) == 0 &&
+		    (be64_to_cpu(data->pestB[i]) >> 63) == 0)
 			continue;
 
 		pr_info("PE[%3d] A/B: %016llx %016llx\n",
@@ -601,6 +601,9 @@
 	u64 rpn = __pa(uaddr) >> tbl->it_page_shift;
 	long i;
 
+	if (proto_tce & TCE_PCI_WRITE)
+		proto_tce |= TCE_PCI_READ;
+
 	for (i = 0; i < npages; i++) {
 		unsigned long newtce = proto_tce |
 			((rpn + i) << tbl->it_page_shift);
@@ -622,6 +625,9 @@
 
 	BUG_ON(*hpa & ~IOMMU_PAGE_MASK(tbl));
 
+	if (newtce & TCE_PCI_WRITE)
+		newtce |= TCE_PCI_READ;
+
 	oldtce = xchg(pnv_tce(tbl, idx), cpu_to_be64(newtce));
 	*hpa = be64_to_cpu(oldtce) & ~(TCE_PCI_READ | TCE_PCI_WRITE);
 	*direction = iommu_tce_direction(oldtce);
@@ -762,6 +768,26 @@
 		phb->dma_dev_setup(phb, pdev);
 }
 
+void pnv_pci_dma_bus_setup(struct pci_bus *bus)
+{
+	struct pci_controller *hose = bus->sysdata;
+	struct pnv_phb *phb = hose->private_data;
+	struct pnv_ioda_pe *pe;
+
+	list_for_each_entry(pe, &phb->ioda.pe_list, list) {
+		if (!(pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)))
+			continue;
+
+		if (!pe->pbus)
+			continue;
+
+		if (bus->number == ((pe->rid >> 8) & 0xFF)) {
+			pe->pbus = bus;
+			break;
+		}
+	}
+}
+
 void pnv_pci_shutdown(void)
 {
 	struct pci_controller *hose;
@@ -807,6 +833,10 @@
 	for_each_compatible_node(np, NULL, "ibm,ioda2-phb")
 		pnv_pci_init_ioda2_phb(np);
 
+	/* Look for NPU PHBs */
+	for_each_compatible_node(np, NULL, "ibm,ioda2-npu-phb")
+		pnv_pci_init_npu_phb(np);
+
 	/* Setup the linkage between OF nodes and PHBs */
 	pci_devs_phb_init();
 
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/pci.h
+++ linux-4.4.0/arch/powerpc/platforms/powernv/pci.h
@@ -7,6 +7,7 @@
 	PNV_PHB_P5IOC2	= 0,
 	PNV_PHB_IODA1	= 1,
 	PNV_PHB_IODA2	= 2,
+	PNV_PHB_NPU	= 3,
 };
 
 /* Precise PHB model for error management */
@@ -15,6 +16,7 @@
 	PNV_PHB_MODEL_P5IOC2,
 	PNV_PHB_MODEL_P7IOC,
 	PNV_PHB_MODEL_PHB3,
+	PNV_PHB_MODEL_NPU,
 };
 
 #define PNV_PCI_DIAG_BUF_SIZE	8192
@@ -24,6 +26,7 @@
 #define PNV_IODA_PE_MASTER	(1 << 3)	/* Master PE in compound case	*/
 #define PNV_IODA_PE_SLAVE	(1 << 4)	/* Slave PE in compound case	*/
 #define PNV_IODA_PE_VF		(1 << 5)	/* PE for one VF 		*/
+#define PNV_IODA_PE_PEER	(1 << 6)	/* PE has peers			*/
 
 /* Data associated with a PE, including IOMMU tracking etc.. */
 struct pnv_phb;
@@ -31,6 +34,9 @@
 	unsigned long		flags;
 	struct pnv_phb		*phb;
 
+#define PNV_IODA_MAX_PEER_PES	8
+	struct pnv_ioda_pe	*peers[PNV_IODA_MAX_PEER_PES];
+
 	/* A PE can be associated with a single device or an
 	 * entire bus (& children). In the former case, pdev
 	 * is populated, in the later case, pbus is.
@@ -229,13 +235,27 @@
 extern void pnv_pci_init_p5ioc2_hub(struct device_node *np);
 extern void pnv_pci_init_ioda_hub(struct device_node *np);
 extern void pnv_pci_init_ioda2_phb(struct device_node *np);
+extern void pnv_pci_init_npu_phb(struct device_node *np);
 extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
 					__be64 *startp, __be64 *endp, bool rm);
 extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev);
 extern int pnv_eeh_phb_reset(struct pci_controller *hose, int option);
 
 extern void pnv_pci_dma_dev_setup(struct pci_dev *pdev);
+extern void pnv_pci_dma_bus_setup(struct pci_bus *bus);
 extern int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type);
 extern void pnv_teardown_msi_irqs(struct pci_dev *pdev);
 
+/* Nvlink functions */
+extern void pnv_npu_tce_invalidate_entire(struct pnv_ioda_pe *npe);
+extern void pnv_npu_tce_invalidate(struct pnv_ioda_pe *npe,
+				       struct iommu_table *tbl,
+				       unsigned long index,
+				       unsigned long npages,
+				       bool rm);
+extern void pnv_npu_init_dma_pe(struct pnv_ioda_pe *npe);
+extern void pnv_npu_setup_dma_pe(struct pnv_ioda_pe *npe);
+extern int pnv_npu_dma_set_bypass(struct pnv_ioda_pe *npe, bool enabled);
+extern int pnv_npu_dma_set_mask(struct pci_dev *npdev, u64 dma_mask);
+
 #endif /* __POWERNV_PCI_H */
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/setup.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/setup.c
@@ -35,13 +35,125 @@
 #include <asm/opal.h>
 #include <asm/kexec.h>
 #include <asm/smp.h>
+#include <asm/tm.h>
+#include <asm/setup.h>
+#include <asm/security_features.h>
 
 #include "powernv.h"
 
+
+static bool fw_feature_is(const char *state, const char *name,
+			  struct device_node *fw_features)
+{
+	struct device_node *np;
+	bool rc = false;
+
+	np = of_get_child_by_name(fw_features, name);
+	if (np) {
+		rc = of_property_read_bool(np, state);
+		of_node_put(np);
+	}
+
+	return rc;
+}
+
+static void init_fw_feat_flags(struct device_node *np)
+{
+	if (fw_feature_is("enabled", "inst-spec-barrier-ori31,31,0", np))
+		security_ftr_set(SEC_FTR_SPEC_BAR_ORI31);
+
+	if (fw_feature_is("enabled", "fw-bcctrl-serialized", np))
+		security_ftr_set(SEC_FTR_BCCTRL_SERIALISED);
+
+	if (fw_feature_is("enabled", "inst-l1d-flush-ori30,30,0", np))
+		security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30);
+
+	if (fw_feature_is("enabled", "inst-l1d-flush-trig2", np))
+		security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2);
+
+	if (fw_feature_is("enabled", "fw-l1d-thread-split", np))
+		security_ftr_set(SEC_FTR_L1D_THREAD_PRIV);
+
+	if (fw_feature_is("enabled", "fw-count-cache-disabled", np))
+		security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED);
+
+	if (fw_feature_is("enabled", "fw-count-cache-flush-bcctr2,0,0", np))
+		security_ftr_set(SEC_FTR_BCCTR_FLUSH_ASSIST);
+
+	if (fw_feature_is("enabled", "needs-count-cache-flush-on-context-switch", np))
+		security_ftr_set(SEC_FTR_FLUSH_COUNT_CACHE);
+
+	/*
+	 * The features below are enabled by default, so we instead look to see
+	 * if firmware has *disabled* them, and clear them if so.
+	 */
+	if (fw_feature_is("disabled", "speculation-policy-favor-security", np))
+		security_ftr_clear(SEC_FTR_FAVOUR_SECURITY);
+
+	if (fw_feature_is("disabled", "needs-l1d-flush-msr-pr-0-to-1", np))
+		security_ftr_clear(SEC_FTR_L1D_FLUSH_PR);
+
+	if (fw_feature_is("disabled", "needs-l1d-flush-msr-hv-1-to-0", np))
+		security_ftr_clear(SEC_FTR_L1D_FLUSH_HV);
+
+	if (fw_feature_is("disabled", "needs-spec-barrier-for-bound-checks", np))
+		security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR);
+}
+
+static void pnv_setup_rfi_flush(void)
+{
+	struct device_node *np, *fw_features;
+	enum l1d_flush_type type;
+	bool enable;
+
+	/* Default to fallback in case fw-features are not available */
+	type = L1D_FLUSH_FALLBACK;
+
+	np = of_find_node_by_name(NULL, "ibm,opal");
+	fw_features = of_get_child_by_name(np, "fw-features");
+	of_node_put(np);
+
+	if (fw_features) {
+		init_fw_feat_flags(fw_features);
+		of_node_put(fw_features);
+
+		if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2))
+			type = L1D_FLUSH_MTTRIG;
+
+		if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30))
+			type = L1D_FLUSH_ORI;
+	}
+
+	/*
+	 * Xenial does not support Power9 bare metal, so it cannot be
+	 * vulnerable if booted in PowerNV: the vulnerability is P9 specific
+	 */
+	security_ftr_clear(SEC_FTR_L1D_FLUSH_ENTRY);
+	security_ftr_clear(SEC_FTR_L1D_FLUSH_UACCESS);
+
+	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \
+		 (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)   || \
+		  security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV));
+
+	setup_rfi_flush(type, enable);
+	setup_count_cache_flush();
+
+	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
+		 security_ftr_enabled(SEC_FTR_L1D_FLUSH_ENTRY);
+	setup_entry_flush(enable);
+
+	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
+		 security_ftr_enabled(SEC_FTR_L1D_FLUSH_UACCESS);
+	setup_uaccess_flush(enable);
+}
+
 static void __init pnv_setup_arch(void)
 {
 	set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
 
+	pnv_setup_rfi_flush();
+	setup_stf_barrier();
+
 	/* Initialize SMP */
 	pnv_smp_init();
 
@@ -90,12 +202,8 @@
 	if (root)
 		model = of_get_property(root, "model", NULL);
 	seq_printf(m, "machine\t\t: PowerNV %s\n", model);
-	if (firmware_has_feature(FW_FEATURE_OPALv3))
-		seq_printf(m, "firmware\t: OPAL v3\n");
-	else if (firmware_has_feature(FW_FEATURE_OPALv2))
-		seq_printf(m, "firmware\t: OPAL v2\n");
-	else if (firmware_has_feature(FW_FEATURE_OPAL))
-		seq_printf(m, "firmware\t: OPAL v1\n");
+	if (firmware_has_feature(FW_FEATURE_OPAL))
+		seq_printf(m, "firmware\t: OPAL\n");
 	else
 		seq_printf(m, "firmware\t: BML\n");
 	of_node_put(root);
@@ -224,9 +332,9 @@
 {
 	xics_kexec_teardown_cpu(secondary);
 
-	/* On OPAL v3, we return all CPUs to firmware */
+	/* On OPAL, we return all CPUs to firmware */
 
-	if (!firmware_has_feature(FW_FEATURE_OPALv3))
+	if (!firmware_has_feature(FW_FEATURE_OPAL))
 		return;
 
 	if (secondary) {
@@ -295,7 +403,7 @@
 {
 	unsigned long ret_freq;
 
-	ret_freq = cpufreq_quick_get(cpu) * 1000ul;
+	ret_freq = cpufreq_get(cpu) * 1000ul;
 
 	/*
 	 * If the backend cpufreq driver does not exist,
--- linux-4.4.0.orig/arch/powerpc/platforms/powernv/smp.c
+++ linux-4.4.0/arch/powerpc/platforms/powernv/smp.c
@@ -41,7 +41,7 @@
 #include <asm/udbg.h>
 #define DBG(fmt...) udbg_printf(fmt)
 #else
-#define DBG(fmt...)
+#define DBG(fmt...) do { } while (0)
 #endif
 
 static void pnv_smp_setup_cpu(int cpu)
@@ -61,14 +61,15 @@
 	unsigned long start_here =
 			__pa(ppc_function_entry(generic_secondary_smp_init));
 	long rc;
+	uint8_t status;
 
 	BUG_ON(nr < 0 || nr >= NR_CPUS);
 
 	/*
-	 * If we already started or OPALv2 is not supported, we just
+	 * If we already started or OPAL is not supported, we just
 	 * kick the CPU via the PACA
 	 */
-	if (paca[nr].cpu_start || !firmware_has_feature(FW_FEATURE_OPALv2))
+	if (paca[nr].cpu_start || !firmware_has_feature(FW_FEATURE_OPAL))
 		goto kick;
 
 	/*
@@ -77,55 +78,42 @@
 	 * first time. OPAL v3 allows us to query OPAL to know if it
 	 * has the CPUs, so we do that
 	 */
-	if (firmware_has_feature(FW_FEATURE_OPALv3)) {
-		uint8_t status;
-
-		rc = opal_query_cpu_status(pcpu, &status);
-		if (rc != OPAL_SUCCESS) {
-			pr_warn("OPAL Error %ld querying CPU %d state\n",
-				rc, nr);
-			return -ENODEV;
-		}
+	rc = opal_query_cpu_status(pcpu, &status);
+	if (rc != OPAL_SUCCESS) {
+		pr_warn("OPAL Error %ld querying CPU %d state\n", rc, nr);
+		return -ENODEV;
+	}
 
-		/*
-		 * Already started, just kick it, probably coming from
-		 * kexec and spinning
-		 */
-		if (status == OPAL_THREAD_STARTED)
-			goto kick;
+	/*
+	 * Already started, just kick it, probably coming from
+	 * kexec and spinning
+	 */
+	if (status == OPAL_THREAD_STARTED)
+		goto kick;
 
-		/*
-		 * Available/inactive, let's kick it
-		 */
-		if (status == OPAL_THREAD_INACTIVE) {
-			pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n",
-				 nr, pcpu);
-			rc = opal_start_cpu(pcpu, start_here);
-			if (rc != OPAL_SUCCESS) {
-				pr_warn("OPAL Error %ld starting CPU %d\n",
-					rc, nr);
-				return -ENODEV;
-			}
-		} else {
-			/*
-			 * An unavailable CPU (or any other unknown status)
-			 * shouldn't be started. It should also
-			 * not be in the possible map but currently it can
-			 * happen
-			 */
-			pr_devel("OPAL: CPU %d (HW 0x%x) is unavailable"
-				 " (status %d)...\n", nr, pcpu, status);
+	/*
+	 * Available/inactive, let's kick it
+	 */
+	if (status == OPAL_THREAD_INACTIVE) {
+		pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n", nr, pcpu);
+		rc = opal_start_cpu(pcpu, start_here);
+		if (rc != OPAL_SUCCESS) {
+			pr_warn("OPAL Error %ld starting CPU %d\n", rc, nr);
 			return -ENODEV;
 		}
 	} else {
 		/*
-		 * On OPAL v2, we just kick it and hope for the best,
-		 * we must not test the error from opal_start_cpu() or
-		 * we would fail to get CPUs from kexec.
+		 * An unavailable CPU (or any other unknown status)
+		 * shouldn't be started. It should also
+		 * not be in the possible map but currently it can
+		 * happen
 		 */
-		opal_start_cpu(pcpu, start_here);
+		pr_devel("OPAL: CPU %d (HW 0x%x) is unavailable"
+			 " (status %d)...\n", nr, pcpu, status);
+		return -ENODEV;
 	}
- kick:
+
+kick:
 	return smp_generic_kick_cpu(nr);
 }
 
--- linux-4.4.0.orig/arch/powerpc/platforms/ps3/mm.c
+++ linux-4.4.0/arch/powerpc/platforms/ps3/mm.c
@@ -212,13 +212,14 @@
 {
 	int result;
 
-	DBG("%s:%d: map.vas_id    = %llu\n", __func__, __LINE__, map.vas_id);
-
 	if (map.vas_id) {
 		result = lv1_select_virtual_address_space(0);
-		BUG_ON(result);
-		result = lv1_destruct_virtual_address_space(map.vas_id);
-		BUG_ON(result);
+		result += lv1_destruct_virtual_address_space(map.vas_id);
+
+		if (result) {
+			lv1_panic(0);
+		}
+
 		map.vas_id = 0;
 	}
 }
@@ -316,19 +317,20 @@
 	int result;
 
 	if (!r->destroy) {
-		pr_info("%s:%d: Not destroying high region: %llxh %llxh\n",
-			__func__, __LINE__, r->base, r->size);
 		return;
 	}
 
-	DBG("%s:%d: r->base = %llxh\n", __func__, __LINE__, r->base);
-
 	if (r->base) {
 		result = lv1_release_memory(r->base);
-		BUG_ON(result);
+
+		if (result) {
+			lv1_panic(0);
+		}
+
 		r->size = r->base = r->offset = 0;
 		map.total = map.rm.size;
 	}
+
 	ps3_mm_set_repository_highmem(NULL);
 }
 
--- linux-4.4.0.orig/arch/powerpc/platforms/ps3/os-area.c
+++ linux-4.4.0/arch/powerpc/platforms/ps3/os-area.c
@@ -664,7 +664,7 @@
 	db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
 
 	count = os_area_flash_write(db, sizeof(struct os_area_db), pos);
-	if (count < sizeof(struct os_area_db)) {
+	if (count < 0 || count < sizeof(struct os_area_db)) {
 		pr_debug("%s: os_area_flash_write failed %zd\n", __func__,
 			 count);
 		error = count < 0 ? count : -EIO;
--- linux-4.4.0.orig/arch/powerpc/platforms/ps3/setup.c
+++ linux-4.4.0/arch/powerpc/platforms/ps3/setup.c
@@ -104,20 +104,6 @@
 	ps3_sys_manager_halt(); /* never returns */
 }
 
-static void ps3_panic(char *str)
-{
-	DBG("%s:%d %s\n", __func__, __LINE__, str);
-
-	smp_send_stop();
-	printk("\n");
-	printk("   System does not reboot automatically.\n");
-	printk("   Please press POWER button.\n");
-	printk("\n");
-
-	while(1)
-		lv1_pause(1);
-}
-
 #if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) || \
     defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
 static void __init prealloc(struct ps3_prealloc *p)
@@ -268,7 +254,6 @@
 	.probe				= ps3_probe,
 	.setup_arch			= ps3_setup_arch,
 	.init_IRQ			= ps3_init_IRQ,
-	.panic				= ps3_panic,
 	.get_boot_time			= ps3_get_boot_time,
 	.set_dabr			= ps3_set_dabr,
 	.calibrate_decr			= ps3_calibrate_decr,
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/cmm.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/cmm.c
@@ -391,6 +391,10 @@
 	.dev_name = "cmm",
 };
 
+static void cmm_release_device(struct device *dev)
+{
+}
+
 /**
  * cmm_sysfs_register - Register with sysfs
  *
@@ -406,6 +410,7 @@
 
 	dev->id = 0;
 	dev->bus = &cmm_subsys;
+	dev->release = cmm_release_device;
 
 	if ((rc = device_register(dev)))
 		goto subsys_unregister;
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/dlpar.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/dlpar.c
@@ -55,6 +55,10 @@
 
 	name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
 	prop->name = kstrdup(name, GFP_KERNEL);
+	if (!prop->name) {
+		dlpar_free_cc_property(prop);
+		return NULL;
+	}
 
 	prop->length = be32_to_cpu(ccwa->prop_length);
 	value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
@@ -127,7 +131,6 @@
 #define NEXT_PROPERTY   3
 #define PREV_PARENT     4
 #define MORE_MEMORY     5
-#define CALL_AGAIN	-2
 #define ERR_CFG_USE     -9003
 
 struct device_node *dlpar_configure_connector(__be32 drc_index,
@@ -169,6 +172,9 @@
 
 		spin_unlock(&rtas_data_buf_lock);
 
+		if (rtas_busy_delay(rc))
+			continue;
+
 		switch (rc) {
 		case COMPLETE:
 			break;
@@ -221,9 +227,6 @@
 			parent_path = last_dn->parent->full_name;
 			break;
 
-		case CALL_AGAIN:
-			break;
-
 		case MORE_MEMORY:
 		case ERR_CFG_USE:
 		default:
@@ -280,7 +283,8 @@
 	if (rc)
 		return rc;
 
-	of_node_put(dn); /* Must decrement the refcount */
+	of_node_put(dn);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/dtl.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/dtl.c
@@ -150,7 +150,7 @@
 
 	/* Register our dtl buffer with the hypervisor. The HV expects the
 	 * buffer size to be passed in the second word of the buffer */
-	((u32 *)dtl->buf)[1] = DISPATCH_LOG_BYTES;
+	((u32 *)dtl->buf)[1] = cpu_to_be32(DISPATCH_LOG_BYTES);
 
 	hwcpu = get_hard_smp_processor_id(dtl->cpu);
 	addr = __pa(dtl->buf);
@@ -185,7 +185,7 @@
 
 static u64 dtl_current_index(struct dtl *dtl)
 {
-	return lppaca_of(dtl->cpu).dtl_idx;
+	return be64_to_cpu(lppaca_of(dtl->cpu).dtl_idx);
 }
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -615,29 +615,50 @@
 {
 	int config_addr;
 	int ret;
+	/* Waiting 0.2s maximum before skipping configuration */
+	int max_wait = 200;
 
 	/* Figure out the PE address */
 	config_addr = pe->config_addr;
 	if (pe->addr)
 		config_addr = pe->addr;
 
-	/* Use new configure-pe function, if supported */
-	if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) {
-		ret = rtas_call(ibm_configure_pe, 3, 1, NULL,
-				config_addr, BUID_HI(pe->phb->buid),
-				BUID_LO(pe->phb->buid));
-	} else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) {
-		ret = rtas_call(ibm_configure_bridge, 3, 1, NULL,
-				config_addr, BUID_HI(pe->phb->buid),
-				BUID_LO(pe->phb->buid));
-	} else {
-		return -EFAULT;
-	}
+	while (max_wait > 0) {
+		/* Use new configure-pe function, if supported */
+		if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) {
+			ret = rtas_call(ibm_configure_pe, 3, 1, NULL,
+					config_addr, BUID_HI(pe->phb->buid),
+					BUID_LO(pe->phb->buid));
+		} else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) {
+			ret = rtas_call(ibm_configure_bridge, 3, 1, NULL,
+					config_addr, BUID_HI(pe->phb->buid),
+					BUID_LO(pe->phb->buid));
+		} else {
+			return -EFAULT;
+		}
+
+		if (!ret)
+			return ret;
+
+		/*
+		 * If RTAS returns a delay value that's above 100ms, cut it
+		 * down to 100ms in case firmware made a mistake.  For more
+		 * on how these delay values work see rtas_busy_delay_time
+		 */
+		if (ret > RTAS_EXTENDED_DELAY_MIN+2 &&
+		    ret <= RTAS_EXTENDED_DELAY_MAX)
+			ret = RTAS_EXTENDED_DELAY_MIN+2;
 
-	if (ret)
-		pr_warn("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n",
-			__func__, pe->phb->global_number, pe->addr, ret);
+		max_wait -= rtas_busy_delay_time(ret);
+
+		if (max_wait < 0)
+			break;
+
+		rtas_busy_delay(ret);
+	}
 
+	pr_warn("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n",
+		__func__, pe->phb->global_number, pe->addr, ret);
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -29,7 +29,7 @@
 unsigned long pseries_memory_block_size(void)
 {
 	struct device_node *np;
-	unsigned int memblock_size = MIN_MEMORY_BLOCK_SIZE;
+	u64 memblock_size = MIN_MEMORY_BLOCK_SIZE;
 	struct resource r;
 
 	np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
@@ -110,6 +110,7 @@
 	for (i = 0; i < num_lmbs; i++) {
 		lmbs[i].base_addr = be64_to_cpu(lmbs[i].base_addr);
 		lmbs[i].drc_index = be32_to_cpu(lmbs[i].drc_index);
+		lmbs[i].aa_index = be32_to_cpu(lmbs[i].aa_index);
 		lmbs[i].flags = be32_to_cpu(lmbs[i].flags);
 	}
 
@@ -204,8 +205,10 @@
 
 	for (i = 0; i < scns_per_block; i++) {
 		pfn = PFN_DOWN(phys_addr);
-		if (!pfn_present(pfn))
+		if (!pfn_present(pfn)) {
+			phys_addr += MIN_MEMORY_BLOCK_SIZE;
 			continue;
+		}
 
 		rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
 		phys_addr += MIN_MEMORY_BLOCK_SIZE;
@@ -342,14 +345,15 @@
 		}
 	}
 
-	if (!lmb_found)
+	if (!lmb_found) {
+		pr_debug("Failed to look up LMB for drc index %x\n", drc_index);
 		rc = -EINVAL;
-
-	if (rc)
+	} else if (rc) {
 		pr_info("Failed to hot-remove memory at %llx\n",
 			lmbs[i].base_addr);
-	else
+	} else {
 		pr_info("Memory at %llx was hot-removed\n", lmbs[i].base_addr);
+	}
 
 	return rc;
 }
@@ -553,6 +557,7 @@
 	for (i = 0; i < num_lmbs; i++) {
 		lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr);
 		lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index);
+		lmbs[i].aa_index = cpu_to_be32(lmbs[i].aa_index);
 		lmbs[i].flags = cpu_to_be32(lmbs[i].flags);
 	}
 
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/hvconsole.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/hvconsole.c
@@ -62,7 +62,7 @@
  * @vtermno: The vtermno or unit_address of the adapter from which the data
  *	originated.
  * @buf: The character buffer that contains the character data to send to
- *	firmware.
+ *	firmware. Must be at least 16 bytes, even if count is less than 16.
  * @count: Send this number of characters.
  */
 int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/iommu.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/iommu.c
@@ -202,10 +202,10 @@
 	return be64_to_cpu(*tcep);
 }
 
-static void tce_free_pSeriesLP(struct iommu_table*, long, long);
+static void tce_free_pSeriesLP(unsigned long liobn, long, long);
 static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long);
 
-static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
+static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
 				long npages, unsigned long uaddr,
 				enum dma_data_direction direction,
 				struct dma_attrs *attrs)
@@ -216,25 +216,25 @@
 	int ret = 0;
 	long tcenum_start = tcenum, npages_start = npages;
 
-	rpn = __pa(uaddr) >> TCE_SHIFT;
+	rpn = __pa(uaddr) >> tceshift;
 	proto_tce = TCE_PCI_READ;
 	if (direction != DMA_TO_DEVICE)
 		proto_tce |= TCE_PCI_WRITE;
 
 	while (npages--) {
-		tce = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
-		rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, tce);
+		tce = proto_tce | (rpn & TCE_RPN_MASK) << tceshift;
+		rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, tce);
 
 		if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) {
 			ret = (int)rc;
-			tce_free_pSeriesLP(tbl, tcenum_start,
+			tce_free_pSeriesLP(liobn, tcenum_start,
 			                   (npages_start - (npages + 1)));
 			break;
 		}
 
 		if (rc && printk_ratelimit()) {
 			printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc);
-			printk("\tindex   = 0x%llx\n", (u64)tbl->it_index);
+			printk("\tindex   = 0x%llx\n", (u64)liobn);
 			printk("\ttcenum  = 0x%llx\n", (u64)tcenum);
 			printk("\ttce val = 0x%llx\n", tce );
 			dump_stack();
@@ -263,7 +263,8 @@
 	unsigned long flags;
 
 	if ((npages == 1) || !firmware_has_feature(FW_FEATURE_MULTITCE)) {
-		return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
+		return tce_build_pSeriesLP(tbl->it_index, tcenum,
+					   tbl->it_page_shift, npages, uaddr,
 		                           direction, attrs);
 	}
 
@@ -279,8 +280,9 @@
 		/* If allocation fails, fall back to the loop implementation */
 		if (!tcep) {
 			local_irq_restore(flags);
-			return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
-					    direction, attrs);
+			return tce_build_pSeriesLP(tbl->it_index, tcenum,
+					tbl->it_page_shift,
+					npages, uaddr, direction, attrs);
 		}
 		__this_cpu_write(tce_page, tcep);
 	}
@@ -331,16 +333,16 @@
 	return ret;
 }
 
-static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages)
+static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long npages)
 {
 	u64 rc;
 
 	while (npages--) {
-		rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0);
+		rc = plpar_tce_put((u64)liobn, (u64)tcenum << 12, 0);
 
 		if (rc && printk_ratelimit()) {
 			printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc);
-			printk("\tindex   = 0x%llx\n", (u64)tbl->it_index);
+			printk("\tindex   = 0x%llx\n", (u64)liobn);
 			printk("\ttcenum  = 0x%llx\n", (u64)tcenum);
 			dump_stack();
 		}
@@ -355,7 +357,7 @@
 	u64 rc;
 
 	if (!firmware_has_feature(FW_FEATURE_MULTITCE))
-		return tce_free_pSeriesLP(tbl, tcenum, npages);
+		return tce_free_pSeriesLP(tbl->it_index, tcenum, npages);
 
 	rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
 
@@ -470,6 +472,19 @@
 	u64 rc = 0;
 	long l, limit;
 
+	if (!firmware_has_feature(FW_FEATURE_MULTITCE)) {
+		unsigned long tceshift = be32_to_cpu(maprange->tce_shift);
+		unsigned long dmastart = (start_pfn << PAGE_SHIFT) +
+				be64_to_cpu(maprange->dma_base);
+		unsigned long tcenum = dmastart >> tceshift;
+		unsigned long npages = num_pfn << PAGE_SHIFT >> tceshift;
+		void *uaddr = __va(start_pfn << PAGE_SHIFT);
+
+		return tce_build_pSeriesLP(be32_to_cpu(maprange->liobn),
+				tcenum, tceshift, npages, (unsigned long) uaddr,
+				DMA_BIDIRECTIONAL, 0);
+	}
+
 	local_irq_disable();	/* to protect tcep and the page behind it */
 	tcep = __this_cpu_read(tce_page);
 
@@ -912,7 +927,8 @@
 static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,
 			struct ddw_query_response *query)
 {
-	struct eeh_dev *edev;
+	struct device_node *dn;
+	struct pci_dn *pdn;
 	u32 cfg_addr;
 	u64 buid;
 	int ret;
@@ -923,11 +939,10 @@
 	 * Retrieve them from the pci device, not the node with the
 	 * dma-window property
 	 */
-	edev = pci_dev_to_eeh_dev(dev);
-	cfg_addr = edev->config_addr;
-	if (edev->pe_config_addr)
-		cfg_addr = edev->pe_config_addr;
-	buid = edev->phb->buid;
+	dn = pci_device_to_OF_node(dev);
+	pdn = PCI_DN(dn);
+	buid = pdn->phb->buid;
+	cfg_addr = ((pdn->busno << 16) | (pdn->devfn << 8));
 
 	ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query,
 		  cfg_addr, BUID_HI(buid), BUID_LO(buid));
@@ -941,7 +956,8 @@
 			struct ddw_create_response *create, int page_shift,
 			int window_shift)
 {
-	struct eeh_dev *edev;
+	struct device_node *dn;
+	struct pci_dn *pdn;
 	u32 cfg_addr;
 	u64 buid;
 	int ret;
@@ -952,11 +968,10 @@
 	 * Retrieve them from the pci device, not the node with the
 	 * dma-window property
 	 */
-	edev = pci_dev_to_eeh_dev(dev);
-	cfg_addr = edev->config_addr;
-	if (edev->pe_config_addr)
-		cfg_addr = edev->pe_config_addr;
-	buid = edev->phb->buid;
+	dn = pci_device_to_OF_node(dev);
+	pdn = PCI_DN(dn);
+	buid = pdn->phb->buid;
+	cfg_addr = ((pdn->busno << 16) | (pdn->devfn << 8));
 
 	do {
 		/* extra outputs are LIOBN and dma-addr (hi, lo) */
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/lpar.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/lpar.c
@@ -406,7 +406,7 @@
 					     unsigned long *vpn, int count,
 					     int psize, int ssize)
 {
-	unsigned long param[8];
+	unsigned long param[PLPAR_HCALL9_BUFSIZE];
 	int i = 0, pix = 0, rc;
 	unsigned long flags = 0;
 	int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
@@ -523,7 +523,7 @@
 	unsigned long flags = 0;
 	struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch);
 	int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
-	unsigned long param[9];
+	unsigned long param[PLPAR_HCALL9_BUFSIZE];
 	unsigned long hash, index, shift, hidx, slot;
 	real_pte_t pte;
 	int psize, ssize;
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/mobility.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/mobility.c
@@ -11,6 +11,7 @@
 
 #include <linux/kernel.h>
 #include <linux/kobject.h>
+#include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/stat.h>
 #include <linux/completion.h>
@@ -206,7 +207,11 @@
 
 				prop_data += vd;
 			}
+
+			cond_resched();
 		}
+
+		cond_resched();
 	} while (rtas_rc == 1);
 
 	of_node_put(dn);
@@ -225,8 +230,10 @@
 		return -ENOENT;
 
 	dn = dlpar_configure_connector(drc_index, parent_dn);
-	if (!dn)
+	if (!dn) {
+		of_node_put(parent_dn);
 		return -ENOENT;
+	}
 
 	rc = dlpar_attach_node(dn);
 	if (rc)
@@ -280,8 +287,12 @@
 					add_dt_node(phandle, drc_index);
 					break;
 				}
+
+				cond_resched();
 			}
 		}
+
+		cond_resched();
 	} while (rc == 1);
 
 	kfree(rtas_buf);
@@ -312,6 +323,9 @@
 		printk(KERN_ERR "Post-mobility device tree update "
 			"failed: %d\n", rc);
 
+	/* Possibly switch to a new RFI flush type */
+	pseries_setup_rfi_flush();
+
 	return;
 }
 
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/pci.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/pci.c
@@ -119,6 +119,10 @@
 
 	bus = bridge->bus;
 
+	/* Rely on the pcibios_free_controller_deferred() callback. */
+	pci_set_host_bridge_release(bridge, pcibios_free_controller_deferred,
+					(void *) pci_bus_to_host(bus));
+
 	dn = pcibios_get_phb_of_node(bus);
 	if (!dn)
 		return 0;
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -138,8 +138,11 @@
 		release_resource(res);
 	}
 
-	/* Free pci_controller data structure */
-	pcibios_free_controller(phb);
+	/*
+	 * The pci_controller data structure is freed by
+	 * the pcibios_free_controller_deferred() callback;
+	 * see pseries_root_bridge_prepare().
+	 */
 
 	return 0;
 }
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/pseries.h
+++ linux-4.4.0/arch/powerpc/platforms/pseries/pseries.h
@@ -81,4 +81,6 @@
 
 unsigned long pseries_memory_block_size(void);
 
+void pseries_setup_rfi_flush(void);
+
 #endif /* _PSERIES_PSERIES_H */
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/ras.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/ras.c
@@ -40,6 +40,9 @@
 #define EPOW_SENSOR_TOKEN	9
 #define EPOW_SENSOR_INDEX	0
 
+/* EPOW events counter variable */
+static int num_epow_events;
+
 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
 static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
 
@@ -82,32 +85,29 @@
 {
 	switch (event_modifier) {
 	case EPOW_SHUTDOWN_NORMAL:
-		pr_emerg("Firmware initiated power off");
+		pr_emerg("Power off requested\n");
 		orderly_poweroff(true);
 		break;
 
 	case EPOW_SHUTDOWN_ON_UPS:
-		pr_emerg("Loss of power reported by firmware, system is "
-			"running on UPS/battery");
-		pr_emerg("Check RTAS error log for details");
-		orderly_poweroff(true);
+		pr_emerg("Loss of system power detected. System is running on"
+			 " UPS/battery. Check RTAS error log for details\n");
 		break;
 
 	case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS:
-		pr_emerg("Loss of system critical functions reported by "
-			"firmware");
-		pr_emerg("Check RTAS error log for details");
+		pr_emerg("Loss of system critical functions detected. Check"
+			 " RTAS error log for details\n");
 		orderly_poweroff(true);
 		break;
 
 	case EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH:
-		pr_emerg("Ambient temperature too high reported by firmware");
-		pr_emerg("Check RTAS error log for details");
+		pr_emerg("High ambient temperature detected. Check RTAS"
+			 " error log for details\n");
 		orderly_poweroff(true);
 		break;
 
 	default:
-		pr_err("Unknown power/cooling shutdown event (modifier %d)",
+		pr_err("Unknown power/cooling shutdown event (modifier = %d)\n",
 			event_modifier);
 	}
 }
@@ -145,17 +145,20 @@
 
 	switch (action_code) {
 	case EPOW_RESET:
-		pr_err("Non critical power or cooling issue cleared");
+		if (num_epow_events) {
+			pr_info("Non critical power/cooling issue cleared\n");
+			num_epow_events--;
+		}
 		break;
 
 	case EPOW_WARN_COOLING:
-		pr_err("Non critical cooling issue reported by firmware");
-		pr_err("Check RTAS error log for details");
+		pr_info("Non-critical cooling issue detected. Check RTAS error"
+			" log for details\n");
 		break;
 
 	case EPOW_WARN_POWER:
-		pr_err("Non critical power issue reported by firmware");
-		pr_err("Check RTAS error log for details");
+		pr_info("Non-critical power issue detected. Check RTAS error"
+			" log for details\n");
 		break;
 
 	case EPOW_SYSTEM_SHUTDOWN:
@@ -163,23 +166,27 @@
 		break;
 
 	case EPOW_SYSTEM_HALT:
-		pr_emerg("Firmware initiated power off");
+		pr_emerg("Critical power/cooling issue detected. Check RTAS"
+			 " error log for details. Powering off.\n");
 		orderly_poweroff(true);
 		break;
 
 	case EPOW_MAIN_ENCLOSURE:
 	case EPOW_POWER_OFF:
-		pr_emerg("Critical power/cooling issue reported by firmware");
-		pr_emerg("Check RTAS error log for details");
-		pr_emerg("Immediate power off");
+		pr_emerg("System about to lose power. Check RTAS error log "
+			 " for details. Powering off immediately.\n");
 		emergency_sync();
 		kernel_power_off();
 		break;
 
 	default:
-		pr_err("Unknown power/cooling event (action code %d)",
+		pr_err("Unknown power/cooling event (action code  = %d)\n",
 			action_code);
 	}
+
+	/* Increment epow events counter variable */
+	if (action_code != EPOW_RESET)
+		num_epow_events++;
 }
 
 /* Handle environmental and power warning (EPOW) interrupts. */
@@ -249,13 +256,12 @@
 	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);
 
 	if (fatal) {
-		pr_emerg("Fatal hardware error reported by firmware");
-		pr_emerg("Check RTAS error log for details");
-		pr_emerg("Immediate power off");
+		pr_emerg("Fatal hardware error detected. Check RTAS error"
+			 " log for details. Powering off immediately\n");
 		emergency_sync();
 		kernel_power_off();
 	} else {
-		pr_err("Recoverable hardware error reported by firmware");
+		pr_err("Recoverable hardware error detected\n");
 	}
 
 	spin_unlock(&ras_log_buf_lock);
@@ -265,10 +271,11 @@
 /*
  * Some versions of FWNMI place the buffer inside the 4kB page starting at
  * 0x7000. Other versions place it inside the rtas buffer. We check both.
+ * Minimum size of the buffer is 16 bytes.
  */
 #define VALID_FWNMI_BUFFER(A) \
-	((((A) >= 0x7000) && ((A) < 0x7ff0)) || \
-	(((A) >= rtas.base) && ((A) < (rtas.base + rtas.size - 16))))
+	((((A) >= 0x7000) && ((A) <= 0x8000 - 16)) || \
+	(((A) >= rtas.base) && ((A) <= (rtas.base + rtas.size - 16))))
 
 /*
  * Get the error information for errors coming through the
@@ -300,7 +307,7 @@
 	}
 
 	savep = __va(regs->gpr[3]);
-	regs->gpr[3] = savep[0];	/* restore original r3 */
+	regs->gpr[3] = be64_to_cpu(savep[0]);	/* restore original r3 */
 
 	/* If it isn't an extended log we can use the per cpu 64bit buffer */
 	h = (struct rtas_error_log *)&savep[1];
@@ -311,7 +318,7 @@
 		int len, error_log_length;
 
 		error_log_length = 8 + rtas_error_extended_log_length(h);
-		len = max_t(int, error_log_length, RTAS_ERROR_LOG_MAX);
+		len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX);
 		memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
 		memcpy(global_mce_data_buf, h, len);
 		errhdr = (struct rtas_error_log *)global_mce_data_buf;
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/reconfig.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/reconfig.c
@@ -82,7 +82,6 @@
 
 	of_detach_node(np);
 	of_node_put(parent);
-	of_node_put(np); /* Must decrement the refcount */
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/rng.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/rng.c
@@ -40,6 +40,7 @@
 
 	ppc_md.get_random_seed = pseries_get_random_long;
 
+	of_node_put(dn);
 	return 0;
 }
 machine_subsys_initcall(pseries, rng_init);
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/setup.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/setup.c
@@ -67,6 +67,7 @@
 #include <asm/eeh.h>
 #include <asm/reg.h>
 #include <asm/plpar_wrappers.h>
+#include <asm/security_features.h>
 
 #include "pseries.h"
 
@@ -368,6 +369,9 @@
 	 * low power mode by cedeing processor to hypervisor
 	 */
 
+	if (!prep_irq_for_idle())
+		return;
+
 	/* Indicate to hypervisor that we are idle. */
 	get_lppaca()->idle = 1;
 
@@ -499,6 +503,97 @@
 	of_pci_check_probe_only();
 }
 
+static void init_cpu_char_feature_flags(struct h_cpu_char_result *result)
+{
+	/*
+	 * The features below are disabled by default, so we instead look to see
+	 * if firmware has *enabled* them, and set them if so.
+	 */
+	if (result->character & H_CPU_CHAR_SPEC_BAR_ORI31)
+		security_ftr_set(SEC_FTR_SPEC_BAR_ORI31);
+
+	if (result->character & H_CPU_CHAR_BCCTRL_SERIALISED)
+		security_ftr_set(SEC_FTR_BCCTRL_SERIALISED);
+
+	if (result->character & H_CPU_CHAR_L1D_FLUSH_ORI30)
+		security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30);
+
+	if (result->character & H_CPU_CHAR_L1D_FLUSH_TRIG2)
+		security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2);
+
+	if (result->character & H_CPU_CHAR_L1D_THREAD_PRIV)
+		security_ftr_set(SEC_FTR_L1D_THREAD_PRIV);
+
+	if (result->character & H_CPU_CHAR_COUNT_CACHE_DISABLED)
+		security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED);
+
+	if (result->character & H_CPU_CHAR_BCCTR_FLUSH_ASSIST)
+		security_ftr_set(SEC_FTR_BCCTR_FLUSH_ASSIST);
+
+	if (result->behaviour & H_CPU_BEHAV_FLUSH_COUNT_CACHE)
+		security_ftr_set(SEC_FTR_FLUSH_COUNT_CACHE);
+
+	/*
+	 * The features below are enabled by default, so we instead look to see
+	 * if firmware has *disabled* them, and clear them if so.
+	 */
+	if (!(result->behaviour & H_CPU_BEHAV_FAVOUR_SECURITY))
+		security_ftr_clear(SEC_FTR_FAVOUR_SECURITY);
+
+	if (!(result->behaviour & H_CPU_BEHAV_L1D_FLUSH_PR))
+		security_ftr_clear(SEC_FTR_L1D_FLUSH_PR);
+
+	if (!(result->behaviour & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR))
+		security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR);
+}
+
+void pseries_setup_rfi_flush(void)
+{
+	struct h_cpu_char_result result;
+	enum l1d_flush_type types;
+	bool enable;
+	long rc;
+
+	/*
+	 * Set features to the defaults assumed by init_cpu_char_feature_flags()
+	 * so it can set/clear again any features that might have changed after
+	 * migration, and in case the hypercall fails and it is not even called.
+	 */
+	powerpc_security_features = SEC_FTR_DEFAULT;
+
+	rc = plpar_get_cpu_characteristics(&result);
+	if (rc == H_SUCCESS)
+		init_cpu_char_feature_flags(&result);
+
+	/*
+	 * We're the guest so this doesn't apply to us, clear it to simplify
+	 * handling of it elsewhere.
+	 */
+	security_ftr_clear(SEC_FTR_L1D_FLUSH_HV);
+
+	types = L1D_FLUSH_FALLBACK;
+
+	if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2))
+		types |= L1D_FLUSH_MTTRIG;
+
+	if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30))
+		types |= L1D_FLUSH_ORI;
+
+	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \
+		 security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR);
+
+	setup_rfi_flush(types, enable);
+	setup_count_cache_flush();
+
+	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
+		 security_ftr_enabled(SEC_FTR_L1D_FLUSH_ENTRY);
+	setup_entry_flush(enable);
+
+	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
+		 security_ftr_enabled(SEC_FTR_L1D_FLUSH_UACCESS);
+	setup_uaccess_flush(enable);
+}
+
 static void __init pSeries_setup_arch(void)
 {
 	set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
@@ -515,7 +610,10 @@
 
 	fwnmi_init();
 
-	/* By default, only probe PCI (can be overriden by rtas_pci) */
+	pseries_setup_rfi_flush();
+	setup_stf_barrier();
+
+	/* By default, only probe PCI (can be overridden by rtas_pci) */
 	pci_add_flags(PCI_PROBE_ONLY);
 
 	/* Find and initialize PCI host bridges */
@@ -841,7 +939,6 @@
 	.pcibios_fixup		= pSeries_final_fixup,
 	.restart		= rtas_restart,
 	.halt			= rtas_halt,
-	.panic			= rtas_os_term,
 	.get_boot_time		= rtas_get_boot_time,
 	.get_rtc_time		= rtas_get_rtc_time,
 	.set_rtc_time		= rtas_set_rtc_time,
--- linux-4.4.0.orig/arch/powerpc/platforms/pseries/suspend.c
+++ linux-4.4.0/arch/powerpc/platforms/pseries/suspend.c
@@ -224,7 +224,6 @@
 
 static const struct platform_suspend_ops pseries_suspend_ops = {
 	.valid		= suspend_valid_only_mem,
-	.begin		= pseries_suspend_begin,
 	.prepare_late	= pseries_prepare_late,
 	.enter		= pseries_suspend_enter,
 };
--- linux-4.4.0.orig/arch/powerpc/sysdev/axonram.c
+++ linux-4.4.0/arch/powerpc/sysdev/axonram.c
@@ -276,7 +276,9 @@
 			if (bank->disk->major > 0)
 				unregister_blkdev(bank->disk->major,
 						bank->disk->disk_name);
-			del_gendisk(bank->disk);
+			if (bank->disk->flags & GENHD_FL_UP)
+				del_gendisk(bank->disk);
+			put_disk(bank->disk);
 		}
 		device->dev.platform_data = NULL;
 		if (bank->io_addr != 0)
@@ -301,6 +303,7 @@
 	device_remove_file(&device->dev, &dev_attr_ecc);
 	free_irq(bank->irq_id, device);
 	del_gendisk(bank->disk);
+	put_disk(bank->disk);
 	iounmap((void __iomem *) bank->io_addr);
 	kfree(bank);
 
--- linux-4.4.0.orig/arch/powerpc/sysdev/ipic.c
+++ linux-4.4.0/arch/powerpc/sysdev/ipic.c
@@ -845,12 +845,12 @@
 
 u32 ipic_get_mcp_status(void)
 {
-	return ipic_read(primary_ipic->regs, IPIC_SERMR);
+	return ipic_read(primary_ipic->regs, IPIC_SERSR);
 }
 
 void ipic_clear_mcp_status(u32 mask)
 {
-	ipic_write(primary_ipic->regs, IPIC_SERMR, mask);
+	ipic_write(primary_ipic->regs, IPIC_SERSR, mask);
 }
 
 /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
--- linux-4.4.0.orig/arch/powerpc/sysdev/mpic.c
+++ linux-4.4.0/arch/powerpc/sysdev/mpic.c
@@ -626,7 +626,7 @@
 	int i;
 	u32 mask = 0;
 
-	for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1)
+	for (i = 0; i < min(32, NR_CPUS) && cpu_possible(i); ++i, cpumask >>= 1)
 		mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
 	return mask;
 }
--- linux-4.4.0.orig/arch/powerpc/sysdev/mpic_msgr.c
+++ linux-4.4.0/arch/powerpc/sysdev/mpic_msgr.c
@@ -196,7 +196,7 @@
 
 	/* IO map the message register block. */
 	of_address_to_resource(np, 0, &rsrc);
-	msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start);
+	msgr_block_addr = devm_ioremap(&dev->dev, rsrc.start, resource_size(&rsrc));
 	if (!msgr_block_addr) {
 		dev_err(&dev->dev, "Failed to iomap MPIC message registers");
 		return -EFAULT;
--- linux-4.4.0.orig/arch/powerpc/sysdev/qe_lib/gpio.c
+++ linux-4.4.0/arch/powerpc/sysdev/qe_lib/gpio.c
@@ -155,8 +155,10 @@
 	if (err < 0)
 		goto err0;
 	gc = gpio_to_chip(err);
-	if (WARN_ON(!gc))
+	if (WARN_ON(!gc)) {
+		err = -ENODEV;
 		goto err0;
+	}
 
 	if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) {
 		pr_debug("%s: tried to get a non-qe pin\n", __func__);
--- linux-4.4.0.orig/arch/powerpc/sysdev/uic.c
+++ linux-4.4.0/arch/powerpc/sysdev/uic.c
@@ -158,6 +158,7 @@
 
 	mtdcr(uic->dcrbase + UIC_PR, pr);
 	mtdcr(uic->dcrbase + UIC_TR, tr);
+	mtdcr(uic->dcrbase + UIC_SR, ~mask);
 
 	raw_spin_unlock_irqrestore(&uic->lock, flags);
 
--- linux-4.4.0.orig/arch/powerpc/sysdev/xics/icp-hv.c
+++ linux-4.4.0/arch/powerpc/sysdev/xics/icp-hv.c
@@ -179,6 +179,7 @@
 
 	icp_ops = &icp_hv_ops;
 
+	of_node_put(np);
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/powerpc/xmon/xmon.c
+++ linux-4.4.0/arch/powerpc/xmon/xmon.c
@@ -150,6 +150,7 @@
 static void csum(void);
 static void bootcmds(void);
 static void proccall(void);
+static void show_tasks(void);
 void dump_segments(void);
 static void symbol_lookup(void);
 static void xmon_show_stack(unsigned long sp, unsigned long lr,
@@ -221,6 +222,7 @@
   mz	zero a block of memory\n\
   mi	show information about memory allocation\n\
   p 	call a procedure\n\
+  P 	list processes/tasks\n\
   r	print registers\n\
   s	single step\n"
 #ifdef CONFIG_SPU_BASE
@@ -954,6 +956,9 @@
 		case 'p':
 			proccall();
 			break;
+		case 'P':
+			show_tasks();
+			break;
 #ifdef CONFIG_PPC_STD_MMU
 		case 'u':
 			dump_segments();
@@ -2144,6 +2149,8 @@
 	DUMP(p, slb_cache_ptr, "x");
 	for (i = 0; i < SLB_CACHE_ENTRIES; i++)
 		printf(" slb_cache[%d]:        = 0x%016lx\n", i, p->slb_cache[i]);
+
+	DUMP(p, rfi_flush_fallback_area, "px");
 #endif
 	DUMP(p, dscr_default, "llx");
 #ifdef CONFIG_PPC_BOOK3E
@@ -2510,6 +2517,61 @@
 		printf("%.8x\n", a - mskip);
 }
 
+static void show_task(struct task_struct *tsk)
+{
+	char state;
+
+	/*
+	 * Cloned from kdb_task_state_char(), which is not entirely
+	 * appropriate for calling from xmon. This could be moved
+	 * to a common, generic, routine used by both.
+	 */
+	state = (tsk->state == 0) ? 'R' :
+		(tsk->state < 0) ? 'U' :
+		(tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
+		(tsk->state & TASK_STOPPED) ? 'T' :
+		(tsk->state & TASK_TRACED) ? 'C' :
+		(tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
+		(tsk->exit_state & EXIT_DEAD) ? 'E' :
+		(tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
+
+	printf("%p %016lx %6d %6d %c %2d %s\n", tsk,
+		tsk->thread.ksp,
+		tsk->pid, tsk->parent->pid,
+		state, task_thread_info(tsk)->cpu,
+		tsk->comm);
+}
+
+static void show_tasks(void)
+{
+	unsigned long tskv;
+	struct task_struct *tsk = NULL;
+
+	printf("     task_struct     ->thread.ksp    PID   PPID S  P CMD\n");
+
+	if (scanhex(&tskv))
+		tsk = (struct task_struct *)tskv;
+
+	if (setjmp(bus_error_jmp) != 0) {
+		catch_memory_errors = 0;
+		printf("*** Error dumping task %p\n", tsk);
+		return;
+	}
+
+	catch_memory_errors = 1;
+	sync();
+
+	if (tsk)
+		show_task(tsk);
+	else
+		for_each_process(tsk)
+			show_task(tsk);
+
+	sync();
+	__delay(200);
+	catch_memory_errors = 0;
+}
+
 static void proccall(void)
 {
 	unsigned long args[8];
@@ -2838,7 +2900,7 @@
 
 	printf("sr0-15 =");
 	for (i = 0; i < 16; ++i)
-		printf(" %x", mfsrin(i));
+		printf(" %x", mfsrin(i << 28));
 	printf("\n");
 }
 #endif
--- linux-4.4.0.orig/arch/s390/Kconfig
+++ linux-4.4.0/arch/s390/Kconfig
@@ -111,6 +111,7 @@
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CPU_AUTOPROBE
 	select GENERIC_CPU_DEVICES if !SMP
+	select GENERIC_CPU_VULNERABILITIES
 	select GENERIC_FIND_FIRST_BIT
 	select GENERIC_SMP_IDLE_THREAD
 	select GENERIC_TIME_VSYSCALL
@@ -123,6 +124,7 @@
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
 	select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
+	select HAVE_EBPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
 	select HAVE_CMPXCHG_DOUBLE
 	select HAVE_CMPXCHG_LOCAL
 	select HAVE_DEBUG_KMEMLEAK
@@ -346,9 +348,6 @@
 config SYSVIPC_COMPAT
 	def_bool y if COMPAT && SYSVIPC
 
-config KEYS_COMPAT
-	def_bool y if COMPAT && KEYS
-
 config SMP
 	def_bool y
 	prompt "Symmetric multi-processing support"
@@ -707,6 +706,51 @@
 
 	  If unsure, say Y.
 
+config KERNEL_NOBP
+	def_bool n
+	prompt "Enable modified branch prediction for the kernel by default"
+	help
+	  If this option is selected the kernel will switch to a modified
+	  branch prediction mode if the firmware interface is available.
+	  The modified branch prediction mode improves the behaviour in
+	  regard to speculative execution.
+
+	  With the option enabled the kernel parameter "nobp=0" or "nospec"
+	  can be used to run the kernel in the normal branch prediction mode.
+
+	  With the option disabled the modified branch prediction mode is
+	  enabled with the "nobp=1" kernel parameter.
+
+	  If unsure, say N.
+
+config EXPOLINE
+	def_bool n
+	prompt "Avoid speculative indirect branches in the kernel"
+	help
+	  Compile the kernel with the expoline compiler options to guard
+	  against kernel-to-user data leaks by avoiding speculative indirect
+	  branches.
+	  Requires a compiler with -mindirect-branch=thunk support for full
+	  protection. The kernel may run slower.
+
+	  If unsure, say N.
+
+choice
+	prompt "Expoline default"
+	depends on EXPOLINE
+	default EXPOLINE_FULL
+
+config EXPOLINE_OFF
+	bool "spectre_v2=off"
+
+config EXPOLINE_AUTO
+	bool "spectre_v2=auto"
+
+config EXPOLINE_FULL
+	bool "spectre_v2=on"
+
+endchoice
+
 endmenu
 
 menu "Power Management"
@@ -756,6 +800,7 @@
 config SHARED_KERNEL
 	bool "VM shared kernel support"
 	depends on !JUMP_LABEL
+	depends on !ALTERNATIVES
 	help
 	  Select this option, if you want to share the text segment of the
 	  Linux kernel between different VM guests. This reduces memory
--- linux-4.4.0.orig/arch/s390/Makefile
+++ linux-4.4.0/arch/s390/Makefile
@@ -77,6 +77,16 @@
 cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
 endif
 
+ifdef CONFIG_EXPOLINE
+  ifeq ($(call cc-option-yn,$(CC_FLAGS_MARCH) -mindirect-branch=thunk),y)
+    CC_FLAGS_EXPOLINE := -mindirect-branch=thunk
+    CC_FLAGS_EXPOLINE += -mfunction-return=thunk
+    CC_FLAGS_EXPOLINE += -mindirect-branch-table
+    export CC_FLAGS_EXPOLINE
+    cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE
+  endif
+endif
+
 ifdef CONFIG_FUNCTION_TRACER
 # make use of hotpatch feature if the compiler supports it
 cc_hotpatch	:= -mhotpatch=0,3
--- linux-4.4.0.orig/arch/s390/boot/compressed/misc.c
+++ linux-4.4.0/arch/s390/boot/compressed/misc.c
@@ -141,31 +141,34 @@
 
 unsigned long decompress_kernel(void)
 {
-	unsigned long output_addr;
-	unsigned char *output;
+	void *output, *kernel_end;
 
-	output_addr = ((unsigned long) &_end + HEAP_SIZE + 4095UL) & -4096UL;
-	check_ipl_parmblock((void *) 0, output_addr + SZ__bss_start);
-	memset(&_bss, 0, &_ebss - &_bss);
-	free_mem_ptr = (unsigned long)&_end;
-	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
-	output = (unsigned char *) output_addr;
+	output = (void *) ALIGN((unsigned long) &_end + HEAP_SIZE, PAGE_SIZE);
+	kernel_end = output + SZ__bss_start;
+	check_ipl_parmblock((void *) 0, (unsigned long) kernel_end);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	/*
 	 * Move the initrd right behind the end of the decompressed
-	 * kernel image.
+	 * kernel image. This also prevents initrd corruption caused by
+	 * bss clearing since kernel_end will always be located behind the
+	 * current bss section..
 	 */
-	if (INITRD_START && INITRD_SIZE &&
-	    INITRD_START < (unsigned long) output + SZ__bss_start) {
-		check_ipl_parmblock(output + SZ__bss_start,
-				    INITRD_START + INITRD_SIZE);
-		memmove(output + SZ__bss_start,
-			(void *) INITRD_START, INITRD_SIZE);
-		INITRD_START = (unsigned long) output + SZ__bss_start;
+	if (INITRD_START && INITRD_SIZE && kernel_end > (void *) INITRD_START) {
+		check_ipl_parmblock(kernel_end, INITRD_SIZE);
+		memmove(kernel_end, (void *) INITRD_START, INITRD_SIZE);
+		INITRD_START = (unsigned long) kernel_end;
 	}
 #endif
 
+	/*
+	 * Clear bss section. free_mem_ptr and free_mem_end_ptr need to be
+	 * initialized afterwards since they reside in bss.
+	 */
+	memset(&_bss, 0, &_ebss - &_bss);
+	free_mem_ptr = (unsigned long) &_end;
+	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
 	puts("Uncompressing Linux... ");
 	__decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error);
 	puts("Ok, booting the kernel.\n");
--- linux-4.4.0.orig/arch/s390/crypto/aes_s390.c
+++ linux-4.4.0/arch/s390/crypto/aes_s390.c
@@ -27,6 +27,7 @@
 #include <linux/cpufeature.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <crypto/xts.h>
 #include "crypt_s390.h"
 
 #define AES_KEYLEN_128		1
@@ -587,6 +588,11 @@
 {
 	struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm);
 	u32 *flags = &tfm->crt_flags;
+	int err;
+
+	err = xts_check_key(tfm, in_key, key_len);
+	if (err)
+		return err;
 
 	switch (key_len) {
 	case 32:
--- linux-4.4.0.orig/arch/s390/crypto/prng.c
+++ linux-4.4.0/arch/s390/crypto/prng.c
@@ -565,8 +565,10 @@
 		prng_data->prngws.byte_counter += n;
 		prng_data->prngws.reseed_counter += n;
 
-		if (copy_to_user(ubuf, prng_data->buf, chunk))
-			return -EFAULT;
+		if (copy_to_user(ubuf, prng_data->buf, chunk)) {
+			ret = -EFAULT;
+			break;
+		}
 
 		nbytes -= chunk;
 		ret += chunk;
@@ -669,11 +671,13 @@
 static struct miscdevice prng_sha512_dev = {
 	.name	= "prandom",
 	.minor	= MISC_DYNAMIC_MINOR,
+	.mode	= 0644,
 	.fops	= &prng_sha512_fops,
 };
 static struct miscdevice prng_tdes_dev = {
 	.name	= "prandom",
 	.minor	= MISC_DYNAMIC_MINOR,
+	.mode	= 0644,
 	.fops	= &prng_tdes_fops,
 };
 
--- linux-4.4.0.orig/arch/s390/hypfs/hypfs_diag.c
+++ linux-4.4.0/arch/s390/hypfs/hypfs_diag.c
@@ -525,11 +525,11 @@
 static int diag224_get_name_table(void)
 {
 	/* memory must be below 2GB */
-	diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+	diag224_cpu_names = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
 	if (!diag224_cpu_names)
 		return -ENOMEM;
 	if (diag224(diag224_cpu_names)) {
-		kfree(diag224_cpu_names);
+		free_page((unsigned long) diag224_cpu_names);
 		return -EOPNOTSUPP;
 	}
 	EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
@@ -538,7 +538,7 @@
 
 static void diag224_delete_name_table(void)
 {
-	kfree(diag224_cpu_names);
+	free_page((unsigned long) diag224_cpu_names);
 }
 
 static int diag224_idx2name(int index, char *name)
--- linux-4.4.0.orig/arch/s390/hypfs/inode.c
+++ linux-4.4.0/arch/s390/hypfs/inode.c
@@ -267,7 +267,7 @@
 static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *root_inode;
-	struct dentry *root_dentry;
+	struct dentry *root_dentry, *update_file;
 	int rc = 0;
 	struct hypfs_sb_info *sbi;
 
@@ -298,9 +298,10 @@
 		rc = hypfs_diag_create_files(root_dentry);
 	if (rc)
 		return rc;
-	sbi->update_file = hypfs_create_update_file(root_dentry);
-	if (IS_ERR(sbi->update_file))
-		return PTR_ERR(sbi->update_file);
+	update_file = hypfs_create_update_file(root_dentry);
+	if (IS_ERR(update_file))
+		return PTR_ERR(update_file);
+	sbi->update_file = update_file;
 	hypfs_update_update(sb);
 	pr_info("Hypervisor filesystem mounted\n");
 	return 0;
@@ -318,7 +319,7 @@
 
 	if (sb->s_root)
 		hypfs_delete_tree(sb->s_root);
-	if (sb_info->update_file)
+	if (sb_info && sb_info->update_file)
 		hypfs_remove(sb_info->update_file);
 	kfree(sb->s_fs_info);
 	sb->s_fs_info = NULL;
--- linux-4.4.0.orig/arch/s390/include/asm/alternative-asm.h
+++ linux-4.4.0/arch/s390/include/asm/alternative-asm.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_ALTERNATIVE_ASM_H
+#define _ASM_S390_ALTERNATIVE_ASM_H
+
+#ifdef __ASSEMBLY__
+
+/*
+ * Check the length of an instruction sequence. The length may not be larger
+ * than 254 bytes and it has to be divisible by 2.
+ */
+.macro alt_len_check start,end
+	.if ( \end - \start ) > 254
+	.error "cpu alternatives does not support instructions blocks > 254 bytes\n"
+	.endif
+	.if ( \end - \start ) % 2
+	.error "cpu alternatives instructions length is odd\n"
+	.endif
+.endm
+
+/*
+ * Issue one struct alt_instr descriptor entry (need to put it into
+ * the section .altinstructions, see below). This entry contains
+ * enough information for the alternatives patching code to patch an
+ * instruction. See apply_alternatives().
+ */
+.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature
+	.long	\orig_start - .
+	.long	\alt_start - .
+	.word	\feature
+	.byte	\orig_end - \orig_start
+	.byte	\alt_end - \alt_start
+.endm
+
+/*
+ * Fill up @bytes with nops. The macro emits 6-byte nop instructions
+ * for the bulk of the area, possibly followed by a 4-byte and/or
+ * a 2-byte nop if the size of the area is not divisible by 6.
+ */
+.macro alt_pad_fill bytes
+	.fill	( \bytes ) / 6, 6, 0xc0040000
+	.fill	( \bytes ) % 6 / 4, 4, 0x47000000
+	.fill	( \bytes ) % 6 % 4 / 2, 2, 0x0700
+.endm
+
+/*
+ * Fill up @bytes with nops. If the number of bytes is larger
+ * than 6, emit a jg instruction to branch over all nops, then
+ * fill an area of size (@bytes - 6) with nop instructions.
+ */
+.macro alt_pad bytes
+	.if ( \bytes > 0 )
+	.if ( \bytes > 6 )
+	jg	. + \bytes
+	alt_pad_fill \bytes - 6
+	.else
+	alt_pad_fill \bytes
+	.endif
+	.endif
+.endm
+
+/*
+ * Define an alternative between two instructions. If @feature is
+ * present, early code in apply_alternatives() replaces @oldinstr with
+ * @newinstr. ".skip" directive takes care of proper instruction padding
+ * in case @newinstr is longer than @oldinstr.
+ */
+.macro ALTERNATIVE oldinstr, newinstr, feature
+	.pushsection .altinstr_replacement,"ax"
+770:	\newinstr
+771:	.popsection
+772:	\oldinstr
+773:	alt_len_check 770b, 771b
+	alt_len_check 772b, 773b
+	alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) )
+774:	.pushsection .altinstructions,"a"
+	alt_entry 772b, 774b, 770b, 771b, \feature
+	.popsection
+.endm
+
+/*
+ * Define an alternative between two instructions. If @feature is
+ * present, early code in apply_alternatives() replaces @oldinstr with
+ * @newinstr. ".skip" directive takes care of proper instruction padding
+ * in case @newinstr is longer than @oldinstr.
+ */
+.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
+	.pushsection .altinstr_replacement,"ax"
+770:	\newinstr1
+771:	\newinstr2
+772:	.popsection
+773:	\oldinstr
+774:	alt_len_check 770b, 771b
+	alt_len_check 771b, 772b
+	alt_len_check 773b, 774b
+	.if ( 771b - 770b > 772b - 771b )
+	alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) )
+	.else
+	alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) )
+	.endif
+775:	.pushsection .altinstructions,"a"
+	alt_entry 773b, 775b, 770b, 771b,\feature1
+	alt_entry 773b, 775b, 771b, 772b,\feature2
+	.popsection
+.endm
+
+#endif	/*  __ASSEMBLY__  */
+
+#endif /* _ASM_S390_ALTERNATIVE_ASM_H */
--- linux-4.4.0.orig/arch/s390/include/asm/alternative.h
+++ linux-4.4.0/arch/s390/include/asm/alternative.h
@@ -0,0 +1,149 @@
+#ifndef _ASM_S390_ALTERNATIVE_H
+#define _ASM_S390_ALTERNATIVE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/stringify.h>
+
+struct alt_instr {
+	s32 instr_offset;	/* original instruction */
+	s32 repl_offset;	/* offset to replacement instruction */
+	u16 facility;		/* facility bit set for replacement */
+	u8  instrlen;		/* length of original instruction */
+	u8  replacementlen;	/* length of new instruction */
+} __packed;
+
+void apply_alternative_instructions(void);
+void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
+
+/*
+ * |661:       |662:	  |6620      |663:
+ * +-----------+---------------------+
+ * | oldinstr  | oldinstr_padding    |
+ * |	       +----------+----------+
+ * |	       |	  |	     |
+ * |	       | >6 bytes |6/4/2 nops|
+ * |	       |6 bytes jg----------->
+ * +-----------+---------------------+
+ *		 ^^ static padding ^^
+ *
+ * .altinstr_replacement section
+ * +---------------------+-----------+
+ * |6641:			     |6651:
+ * | alternative instr 1	     |
+ * +-----------+---------+- - - - - -+
+ * |6642:		 |6652:      |
+ * | alternative instr 2 | padding
+ * +---------------------+- - - - - -+
+ *			  ^ runtime ^
+ *
+ * .altinstructions section
+ * +---------------------------------+
+ * | alt_instr entries for each      |
+ * | alternative instr		     |
+ * +---------------------------------+
+ */
+
+#define b_altinstr(num)	"664"#num
+#define e_altinstr(num)	"665"#num
+
+#define e_oldinstr_pad_end	"663"
+#define oldinstr_len		"662b-661b"
+#define oldinstr_total_len	e_oldinstr_pad_end"b-661b"
+#define altinstr_len(num)	e_altinstr(num)"b-"b_altinstr(num)"b"
+#define oldinstr_pad_len(num) \
+	"-(((" altinstr_len(num) ")-(" oldinstr_len ")) > 0) * " \
+	"((" altinstr_len(num) ")-(" oldinstr_len "))"
+
+#define INSTR_LEN_SANITY_CHECK(len)					\
+	".if " len " > 254\n"						\
+	"\t.error \"cpu alternatives does not support instructions "	\
+		"blocks > 254 bytes\"\n"				\
+	".endif\n"							\
+	".if (" len ") %% 2\n"						\
+	"\t.error \"cpu alternatives instructions length is odd\"\n"	\
+	".endif\n"
+
+#define OLDINSTR_PADDING(oldinstr, num)					\
+	".if " oldinstr_pad_len(num) " > 6\n"				\
+	"\tjg " e_oldinstr_pad_end "f\n"				\
+	"6620:\n"							\
+	"\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \
+	".else\n"							\
+	"\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n"	\
+	"\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n"	\
+	"\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n"	\
+	".endif\n"
+
+#define OLDINSTR(oldinstr, num)						\
+	"661:\n\t" oldinstr "\n662:\n"					\
+	OLDINSTR_PADDING(oldinstr, num)					\
+	e_oldinstr_pad_end ":\n"					\
+	INSTR_LEN_SANITY_CHECK(oldinstr_len)
+
+#define OLDINSTR_2(oldinstr, num1, num2)				\
+	"661:\n\t" oldinstr "\n662:\n"					\
+	".if " altinstr_len(num1) " < " altinstr_len(num2) "\n"		\
+	OLDINSTR_PADDING(oldinstr, num2)				\
+	".else\n"							\
+	OLDINSTR_PADDING(oldinstr, num1)				\
+	".endif\n"							\
+	e_oldinstr_pad_end ":\n"					\
+	INSTR_LEN_SANITY_CHECK(oldinstr_len)
+
+#define ALTINSTR_ENTRY(facility, num)					\
+	"\t.long 661b - .\n"			/* old instruction */	\
+	"\t.long " b_altinstr(num)"b - .\n"	/* alt instruction */	\
+	"\t.word " __stringify(facility) "\n"	/* facility bit    */	\
+	"\t.byte " oldinstr_total_len "\n"	/* source len	   */	\
+	"\t.byte " altinstr_len(num) "\n"	/* alt instruction len */
+
+#define ALTINSTR_REPLACEMENT(altinstr, num)	/* replacement */	\
+	b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n"	\
+	INSTR_LEN_SANITY_CHECK(altinstr_len(num))
+
+/* alternative assembly primitive: */
+#define ALTERNATIVE(oldinstr, altinstr, facility) \
+	".pushsection .altinstr_replacement, \"ax\"\n"			\
+	ALTINSTR_REPLACEMENT(altinstr, 1)				\
+	".popsection\n"							\
+	OLDINSTR(oldinstr, 1)						\
+	".pushsection .altinstructions,\"a\"\n"				\
+	ALTINSTR_ENTRY(facility, 1)					\
+	".popsection\n"
+
+#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\
+	".pushsection .altinstr_replacement, \"ax\"\n"			\
+	ALTINSTR_REPLACEMENT(altinstr1, 1)				\
+	ALTINSTR_REPLACEMENT(altinstr2, 2)				\
+	".popsection\n"							\
+	OLDINSTR_2(oldinstr, 1, 2)					\
+	".pushsection .altinstructions,\"a\"\n"				\
+	ALTINSTR_ENTRY(facility1, 1)					\
+	ALTINSTR_ENTRY(facility2, 2)					\
+	".popsection\n"
+
+/*
+ * Alternative instructions for different CPU types or capabilities.
+ *
+ * This allows to use optimized instructions even on generic binary
+ * kernels.
+ *
+ * oldinstr is padded with jump and nops at compile time if altinstr is
+ * longer. altinstr is padded with jump and nops at run-time during patching.
+ *
+ * For non barrier like inlines please define new variants
+ * without volatile and memory clobber.
+ */
+#define alternative(oldinstr, altinstr, facility)			\
+	asm volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory")
+
+#define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \
+	asm volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1,	    \
+				   altinstr2, facility2) ::: "memory")
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_S390_ALTERNATIVE_H */
--- linux-4.4.0.orig/arch/s390/include/asm/barrier.h
+++ linux-4.4.0/arch/s390/include/asm/barrier.h
@@ -7,6 +7,8 @@
 #ifndef __ASM_BARRIER_H
 #define __ASM_BARRIER_H
 
+#include <asm/alternative.h>
+
 /*
  * Force strict CPU ordering.
  * And yes, this is required on UP too when we're talking
@@ -22,6 +24,13 @@
 
 #define mb() do {  asm volatile(__ASM_BARRIER : : : "memory"); } while (0)
 
+/* Prevent speculative execution past this barrier. */
+#define barrier_nospec()						\
+	do {								\
+		asm volatile(ALTERNATIVE("", ".long 0xb2e8f000", 81)	\
+			     : : : "memory");				\
+	} while (0)
+
 #define rmb()				barrier()
 #define wmb()				barrier()
 #define dma_rmb()			mb()
@@ -36,7 +45,7 @@
 #define smp_mb__before_atomic()		smp_mb()
 #define smp_mb__after_atomic()		smp_mb()
 
-#define smp_store_mb(var, value)		do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value)	do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
 #define smp_store_release(p, v)						\
 do {									\
@@ -53,4 +62,28 @@
 	___p1;								\
 })
 
+/**
+ * array_index_mask_nospec - generate a mask for array_idx() that is
+ * ~0UL when the bounds check succeeds and 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ */
+#define array_index_mask_nospec array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+						    unsigned long size)
+{
+	unsigned long mask;
+
+	if (__builtin_constant_p(size) && size > 0) {
+		asm("	clgr	%2,%1\n"
+		    "	slbgr	%0,%0\n"
+		    :"=d" (mask) : "d" (size-1), "d" (index) :"cc");
+		return mask;
+	}
+	asm("	clgr	%1,%2\n"
+	    "	slbgr	%0,%0\n"
+	    :"=d" (mask) : "d" (size), "d" (index) :"cc");
+	return ~mask;
+}
+
 #endif /* __ASM_BARRIER_H */
--- linux-4.4.0.orig/arch/s390/include/asm/bitops.h
+++ linux-4.4.0/arch/s390/include/asm/bitops.h
@@ -301,6 +301,11 @@
 unsigned long find_next_bit_inv(const unsigned long *addr, unsigned long size,
 				unsigned long offset);
 
+#define for_each_set_bit_inv(bit, addr, size)				\
+	for ((bit) = find_first_bit_inv((addr), (size));		\
+	     (bit) < (size);						\
+	     (bit) = find_next_bit_inv((addr), (size), (bit) + 1))
+
 static inline void set_bit_inv(unsigned long nr, volatile unsigned long *ptr)
 {
 	return set_bit(nr ^ (BITS_PER_LONG - 1), ptr);
--- linux-4.4.0.orig/arch/s390/include/asm/cio.h
+++ linux-4.4.0/arch/s390/include/asm/cio.h
@@ -320,7 +320,7 @@
 extern int cio_get_iplinfo(struct cio_iplinfo *iplinfo);
 
 /* Function from drivers/s390/cio/chsc.c */
-int chsc_sstpc(void *page, unsigned int op, u16 ctrl);
+int chsc_sstpc(void *page, unsigned int op, u16 ctrl, u64 *clock_delta);
 int chsc_sstpi(void *page, void *result, size_t size);
 
 #endif
--- linux-4.4.0.orig/arch/s390/include/asm/clp.h
+++ linux-4.4.0/arch/s390/include/asm/clp.h
@@ -4,14 +4,23 @@
 /* CLP common request & response block size */
 #define CLP_BLK_SIZE			PAGE_SIZE
 
+#define CLP_LPS_BASE	0
+#define CLP_LPS_PCI	2
+
 struct clp_req_hdr {
 	u16 len;
 	u16 cmd;
+	u32 fmt		: 4;
+	u32 reserved1	: 28;
+	u64 reserved2;
 } __packed;
 
 struct clp_rsp_hdr {
 	u16 len;
 	u16 rsp;
+	u32 fmt		: 4;
+	u32 reserved1	: 28;
+	u64 reserved2;
 } __packed;
 
 /* CLP Response Codes */
@@ -25,4 +34,22 @@
 #define CLP_RC_NODATA			0x0080	/* No data available */
 #define CLP_RC_FC_UNKNOWN		0x0100	/* Function code not recognized */
 
+/* Store logical-processor characteristics request */
+struct clp_req_slpc {
+	struct clp_req_hdr hdr;
+} __packed;
+
+struct clp_rsp_slpc {
+	struct clp_rsp_hdr hdr;
+	u32 reserved2[4];
+	u32 lpif[8];
+	u32 reserved3[8];
+	u32 lpic[8];
+} __packed;
+
+struct clp_req_rsp_slpc {
+	struct clp_req_slpc request;
+	struct clp_rsp_slpc response;
+} __packed;
+
 #endif
--- linux-4.4.0.orig/arch/s390/include/asm/cpu_mf.h
+++ linux-4.4.0/arch/s390/include/asm/cpu_mf.h
@@ -113,7 +113,7 @@
 
 struct hws_diag_entry {
 	unsigned int def:16;	    /* 0-15  Data Entry Format		 */
-	unsigned int R:14;	    /* 16-19 and 20-30 reserved		 */
+	unsigned int R:15;	    /* 16-19 and 20-30 reserved		 */
 	unsigned int I:1;	    /* 31 entry valid or invalid	 */
 	u8	     data[];	    /* Machine-dependent sample data	 */
 } __packed;
@@ -129,7 +129,9 @@
 			unsigned int f:1;	/* 0 - Block Full Indicator   */
 			unsigned int a:1;	/* 1 - Alert request control  */
 			unsigned int t:1;	/* 2 - Timestamp format	      */
-			unsigned long long:61;	/* 3 - 63: Reserved	      */
+			unsigned int :29;	/* 3 - 31: Reserved	      */
+			unsigned int bsdes:16;	/* 32-47: size of basic SDE   */
+			unsigned int dsdes:16;	/* 48-63: size of diagnostic SDE */
 		};
 		unsigned long long flags;	/* 0 - 63: All indicators     */
 	};
--- linux-4.4.0.orig/arch/s390/include/asm/ctl_reg.h
+++ linux-4.4.0/arch/s390/include/asm/ctl_reg.h
@@ -15,7 +15,9 @@
 	BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\
 	asm volatile(							\
 		"	lctlg	%1,%2,%0\n"				\
-		: : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high));\
+		:							\
+		: "Q" (*(addrtype *)(&array)), "i" (low), "i" (high)	\
+		: "memory");						\
 }
 
 #define __ctl_store(array, low, high) {					\
--- linux-4.4.0.orig/arch/s390/include/asm/elf.h
+++ linux-4.4.0/arch/s390/include/asm/elf.h
@@ -154,14 +154,13 @@
 #define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE	4096
 
-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
-   use of this is to invoke "./ld.so someprog" to test out a new version of
-   the loader.  We need to make sure that it is out of the way of the program
-   that it will "exec", and that there is sufficient room for the brk. 64-bit
-   tasks are aligned to 4GB. */
-#define ELF_ET_DYN_BASE (is_32bit_task() ? \
-				(STACK_TOP / 3 * 2) : \
-				(STACK_TOP / 3 * 2) & ~((1UL << 32) - 1))
+/*
+ * This is the base location for PIE (ET_DYN with INTERP) loads. On
+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * space open for things that want to use the area for 32-bit pointers.
+ */
+#define ELF_ET_DYN_BASE		(is_compat_task() ? 0x000400000UL : \
+						    0x100000000UL)
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports. */
--- linux-4.4.0.orig/arch/s390/include/asm/etr.h
+++ linux-4.4.0/arch/s390/include/asm/etr.h
@@ -129,14 +129,6 @@
 	unsigned int _pad2	: 18;
 } __attribute__ ((packed));
 
-/* Query TOD offset result */
-struct etr_ptff_qto {
-	unsigned long long physical_clock;
-	unsigned long long tod_offset;
-	unsigned long long logical_tod_offset;
-	unsigned long long tod_epoch_difference;
-} __attribute__ ((packed));
-
 /* Inline assembly helper functions */
 static inline int etr_setr(struct etr_eacr *ctrl)
 {
@@ -186,30 +178,6 @@
 #define ETR_STEAI_PORT_0		0x12
 #define ETR_STEAI_PORT_1		0x13
 
-static inline int etr_ptff(void *ptff_block, unsigned int func)
-{
-	register unsigned int reg0 asm("0") = func;
-	register unsigned long reg1 asm("1") = (unsigned long) ptff_block;
-	int rc = -EOPNOTSUPP;
-
-	asm volatile(
-		"	.word	0x0104\n"
-		"	ipm	%0\n"
-		"	srl	%0,28\n"
-		: "=d" (rc), "=m" (ptff_block)
-		: "d" (reg0), "d" (reg1), "m" (ptff_block) : "cc");
-	return rc;
-}
-
-/* Function codes for the ptff instruction. */
-#define ETR_PTFF_QAF	0x00	/* query available functions */
-#define ETR_PTFF_QTO	0x01	/* query tod offset */
-#define ETR_PTFF_QSI	0x02	/* query steering information */
-#define ETR_PTFF_ATO	0x40	/* adjust tod offset */
-#define ETR_PTFF_STO	0x41	/* set tod offset */
-#define ETR_PTFF_SFS	0x42	/* set fine steering rate */
-#define ETR_PTFF_SGS	0x43	/* set gross steering rate */
-
 /* Functions needed by the machine check handler */
 int etr_switch_to_local(void);
 int etr_sync_check(void);
--- linux-4.4.0.orig/arch/s390/include/asm/facility.h
+++ linux-4.4.0/arch/s390/include/asm/facility.h
@@ -13,6 +13,24 @@
 
 #define MAX_FACILITY_BIT (256*8)	/* stfle_fac_list has 256 bytes */
 
+static inline void __set_facility(unsigned long nr, void *facilities)
+{
+	unsigned char *ptr = (unsigned char *) facilities;
+
+	if (nr >= MAX_FACILITY_BIT)
+		return;
+	ptr[nr >> 3] |= 0x80 >> (nr & 7);
+}
+
+static inline void __clear_facility(unsigned long nr, void *facilities)
+{
+	unsigned char *ptr = (unsigned char *) facilities;
+
+	if (nr >= MAX_FACILITY_BIT)
+		return;
+	ptr[nr >> 3] &= ~(0x80 >> (nr & 7));
+}
+
 static inline int __test_facility(unsigned long nr, void *facilities)
 {
 	unsigned char *ptr;
@@ -33,6 +51,18 @@
 	return __test_facility(nr, &S390_lowcore.stfle_fac_list);
 }
 
+static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size)
+{
+	register unsigned long reg0 asm("0") = size - 1;
+
+	asm volatile(
+		".insn s,0xb2b00000,0(%1)" /* stfle */
+		: "+d" (reg0)
+		: "a" (stfle_fac_list)
+		: "memory", "cc");
+	return reg0;
+}
+
 /**
  * stfle - Store facility list extended
  * @stfle_fac_list: array where facility list can be stored
@@ -44,21 +74,14 @@
 
 	preempt_disable();
 	asm volatile(
-		"	.insn s,0xb2b10000,0(0)\n" /* stfl */
-		"0:\n"
-		EX_TABLE(0b, 0b)
-		: "+m" (S390_lowcore.stfl_fac_list));
+		"	stfl	0(0)\n"
+		: "=m" (S390_lowcore.stfl_fac_list));
 	nr = 4; /* bytes stored by stfl */
 	memcpy(stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
 	if (S390_lowcore.stfl_fac_list & 0x01000000) {
 		/* More facility bits available with stfle */
-		register unsigned long reg0 asm("0") = size - 1;
-
-		asm volatile(".insn s,0xb2b00000,0(%1)" /* stfle */
-			     : "+d" (reg0)
-			     : "a" (stfle_fac_list)
-			     : "memory", "cc");
-		nr = (reg0 + 1) * 8; /* # bytes stored by stfle */
+		nr = __stfle_asm(stfle_fac_list, size);
+		nr = min_t(unsigned long, (nr + 1) * 8, size * 8);
 	}
 	memset((char *) stfle_fac_list + nr, 0, size * 8 - nr);
 	preempt_enable();
--- linux-4.4.0.orig/arch/s390/include/asm/fpu/api.h
+++ linux-4.4.0/arch/s390/include/asm/fpu/api.h
@@ -22,7 +22,7 @@
 		"	la	%0,0\n"
 		"1:\n"
 		EX_TABLE(0b,1b)
-		: "=d" (rc), "=d" (orig_fpc)
+		: "=d" (rc), "=&d" (orig_fpc)
 		: "d" (fpc), "0" (-EINVAL));
 	return rc;
 }
--- linux-4.4.0.orig/arch/s390/include/asm/fpu/internal.h
+++ linux-4.4.0/arch/s390/include/asm/fpu/internal.h
@@ -48,6 +48,7 @@
 static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu)
 {
 	fpregs->pad = 0;
+	fpregs->fpc = fpu->fpc;
 	if (MACHINE_HAS_VX)
 		convert_vx_to_fp((freg_t *)&fpregs->fprs, fpu->vxrs);
 	else
@@ -57,6 +58,7 @@
 
 static inline void fpregs_load(_s390_fp_regs *fpregs, struct fpu *fpu)
 {
+	fpu->fpc = fpregs->fpc;
 	if (MACHINE_HAS_VX)
 		convert_fp_to_vx(fpu->vxrs, (freg_t *)&fpregs->fprs);
 	else
--- linux-4.4.0.orig/arch/s390/include/asm/futex.h
+++ linux-4.4.0/arch/s390/include/asm/futex.h
@@ -21,17 +21,12 @@
 		: "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
 		  "m" (*uaddr) : "cc");
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, newval, ret;
 
 	load_kernel_asce();
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
 
 	pagefault_disable();
 	switch (op) {
@@ -60,17 +55,9 @@
 	}
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/s390/include/asm/kvm_host.h
+++ linux-4.4.0/arch/s390/include/asm/kvm_host.h
@@ -29,12 +29,12 @@
 #define KVM_USER_MEM_SLOTS 32
 
 /*
- * These seem to be used for allocating ->chip in the routing table,
- * which we don't use. 4096 is an out-of-thin-air value. If we need
- * to look at ->chip later on, we'll need to revisit this.
+ * These seem to be used for allocating ->chip in the routing table, which we
+ * don't use. 1 is as small as we can get to reduce the needed memory. If we
+ * need to look at ->chip later on, we'll need to revisit this.
  */
 #define KVM_NR_IRQCHIPS 1
-#define KVM_IRQCHIP_NUM_PINS 4096
+#define KVM_IRQCHIP_NUM_PINS 1
 #define KVM_HALT_POLL_NS_DEFAULT 0
 
 #define SIGP_CTRL_C		0x80
@@ -136,7 +136,8 @@
 	__u16	ipa;			/* 0x0056 */
 	__u32	ipb;			/* 0x0058 */
 	__u32	scaoh;			/* 0x005c */
-	__u8	reserved60;		/* 0x0060 */
+#define FPF_BPBC 	0x20
+	__u8	fpf;			/* 0x0060 */
 	__u8	ecb;			/* 0x0061 */
 	__u8    ecb2;                   /* 0x0062 */
 #define ECB3_AES 0x04
@@ -506,7 +507,6 @@
 	struct kvm_s390_sie_block *sie_block;
 	unsigned int      host_acrs[NUM_ACRS];
 	struct fpu	  host_fpregs;
-	struct fpu	  guest_fpregs;
 	struct kvm_s390_local_interrupt local_int;
 	struct hrtimer    ckc_timer;
 	struct kvm_s390_pgm_info pgm;
--- linux-4.4.0.orig/arch/s390/include/asm/lowcore.h
+++ linux-4.4.0/arch/s390/include/asm/lowcore.h
@@ -155,7 +155,9 @@
 	/* Per cpu primary space access list */
 	__u32	paste[16];			/* 0x0400 */
 
-	__u8	pad_0x04c0[0x0e00-0x0440];	/* 0x0440 */
+	/* br %r1 trampoline */
+	__u16	br_r1_trampoline;		/* 0x0440 */
+	__u8	pad_0x0442[0x0e00-0x0442];	/* 0x0442 */
 
 	/*
 	 * 0xe00 contains the address of the IPL Parameter Information
@@ -170,7 +172,8 @@
 	__u8	pad_0x0e20[0x0f00-0x0e20];	/* 0x0e20 */
 
 	/* Extended facility list */
-	__u64	stfle_fac_list[32];		/* 0x0f00 */
+	__u64	stfle_fac_list[16];		/* 0x0f00 */
+	__u64	alt_stfle_fac_list[16];		/* 0x0f80 */
 	__u8	pad_0x1000[0x11b0-0x1000];	/* 0x1000 */
 
 	/* Pointer to vector register save area */
--- linux-4.4.0.orig/arch/s390/include/asm/mmu.h
+++ linux-4.4.0/arch/s390/include/asm/mmu.h
@@ -5,13 +5,14 @@
 #include <linux/errno.h>
 
 typedef struct {
+	spinlock_t lock;
 	cpumask_t cpu_attach_mask;
 	atomic_t attach_count;
 	unsigned int flush_mm;
 	spinlock_t list_lock;
 	struct list_head pgtable_list;
 	struct list_head gmap_list;
-	unsigned long asce_bits;
+	unsigned long asce;
 	unsigned long asce_limit;
 	unsigned long vdso_base;
 	/* The mmu context allocates 4K page tables. */
@@ -23,6 +24,7 @@
 } mm_context_t;
 
 #define INIT_MM_CONTEXT(name)						      \
+	.context.lock = __SPIN_LOCK_UNLOCKED(name.context.lock),	      \
 	.context.list_lock    = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \
 	.context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list),    \
 	.context.gmap_list = LIST_HEAD_INIT(name.context.gmap_list),
--- linux-4.4.0.orig/arch/s390/include/asm/mmu_context.h
+++ linux-4.4.0/arch/s390/include/asm/mmu_context.h
@@ -15,17 +15,42 @@
 static inline int init_new_context(struct task_struct *tsk,
 				   struct mm_struct *mm)
 {
+	spin_lock_init(&mm->context.lock);
+	spin_lock_init(&mm->context.list_lock);
+	INIT_LIST_HEAD(&mm->context.pgtable_list);
+	INIT_LIST_HEAD(&mm->context.gmap_list);
 	cpumask_clear(&mm->context.cpu_attach_mask);
 	atomic_set(&mm->context.attach_count, 0);
 	mm->context.flush_mm = 0;
-	mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
-	mm->context.asce_bits |= _ASCE_TYPE_REGION3;
 #ifdef CONFIG_PGSTE
 	mm->context.alloc_pgste = page_table_allocate_pgste;
 	mm->context.has_pgste = 0;
 	mm->context.use_skey = 0;
 #endif
-	mm->context.asce_limit = STACK_TOP_MAX;
+	switch (mm->context.asce_limit) {
+	case 1UL << 42:
+		/*
+		 * forked 3-level task, fall through to set new asce with new
+		 * mm->pgd
+		 */
+	case 0:
+		/* context created by exec, set asce limit to 4TB */
+		mm->context.asce_limit = STACK_TOP_MAX;
+		mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
+				   _ASCE_USER_BITS | _ASCE_TYPE_REGION3;
+		break;
+	case 1UL << 53:
+		/* forked 4-level task, set new asce with new mm->pgd */
+		mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
+				   _ASCE_USER_BITS | _ASCE_TYPE_REGION2;
+		break;
+	case 1UL << 31:
+		/* forked 2-level compat task, set new asce with new mm->pgd */
+		mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
+				   _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT;
+		/* pgd_alloc() did not increase mm->nr_pmds */
+		mm_inc_nr_pmds(mm);
+	}
 	crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
 	return 0;
 }
@@ -34,7 +59,7 @@
 
 static inline void set_user_asce(struct mm_struct *mm)
 {
-	S390_lowcore.user_asce = mm->context.asce_bits | __pa(mm->pgd);
+	S390_lowcore.user_asce = mm->context.asce;
 	if (current->thread.mm_segment.ar4)
 		__ctl_load(S390_lowcore.user_asce, 7, 7);
 	set_cpu_flag(CIF_ASCE);
@@ -63,7 +88,7 @@
 {
 	int cpu = smp_processor_id();
 
-	S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd);
+	S390_lowcore.user_asce = next->context.asce;
 	if (prev == next)
 		return;
 	if (MACHINE_HAS_TLB_LC)
@@ -90,8 +115,7 @@
 			cpu_relax();
 
 		cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
-		if (mm->context.flush_mm)
-			__tlb_flush_mm(mm);
+		__tlb_flush_mm_lazy(mm);
 		preempt_enable();
 	}
 	set_fs(current->thread.mm_segment);
@@ -111,8 +135,6 @@
 static inline void arch_dup_mmap(struct mm_struct *oldmm,
 				 struct mm_struct *mm)
 {
-	if (oldmm->context.asce_limit < mm->context.asce_limit)
-		crst_table_downgrade(mm, oldmm->context.asce_limit);
 }
 
 static inline void arch_exit_mmap(struct mm_struct *mm)
--- linux-4.4.0.orig/arch/s390/include/asm/nospec-branch.h
+++ linux-4.4.0/arch/s390/include/asm/nospec-branch.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_EXPOLINE_H
+#define _ASM_S390_EXPOLINE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+extern int nospec_disable;
+
+void nospec_init_branches(void);
+void nospec_auto_detect(void);
+void nospec_revert(s32 *start, s32 *end);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_S390_EXPOLINE_H */
--- linux-4.4.0.orig/arch/s390/include/asm/nospec-insn.h
+++ linux-4.4.0/arch/s390/include/asm/nospec-insn.h
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_NOSPEC_ASM_H
+#define _ASM_S390_NOSPEC_ASM_H
+
+#include <asm/alternative-asm.h>
+#include <asm/asm-offsets.h>
+
+#ifdef __ASSEMBLY__
+
+#ifdef CONFIG_EXPOLINE
+
+_LC_BR_R1 = __LC_BR_R1
+
+/*
+ * The expoline macros are used to create thunks in the same format
+ * as gcc generates them. The 'comdat' section flag makes sure that
+ * the various thunks are merged into a single copy.
+ */
+	.macro __THUNK_PROLOG_NAME name
+	.pushsection .text.\name,"axG",@progbits,\name,comdat
+	.globl \name
+	.hidden \name
+	.type \name,@function
+\name:
+	.cfi_startproc
+	.endm
+
+	.macro __THUNK_EPILOG
+	.cfi_endproc
+	.popsection
+	.endm
+
+	.macro __THUNK_PROLOG_BR r1,r2
+	__THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1
+	.endm
+
+	.macro __THUNK_PROLOG_BC d0,r1,r2
+	__THUNK_PROLOG_NAME __s390x_indirect_branch_\d0\()_\r2\()use_\r1
+	.endm
+
+	.macro __THUNK_BR r1,r2
+	jg	__s390x_indirect_jump_r\r2\()use_r\r1
+	.endm
+
+	.macro __THUNK_BC d0,r1,r2
+	jg	__s390x_indirect_branch_\d0\()_\r2\()use_\r1
+	.endm
+
+	.macro __THUNK_BRASL r1,r2,r3
+	brasl	\r1,__s390x_indirect_jump_r\r3\()use_r\r2
+	.endm
+
+	.macro	__DECODE_RR expand,reg,ruse
+	.set __decode_fail,1
+	.irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	.ifc \reg,%r\r1
+	.irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	.ifc \ruse,%r\r2
+	\expand \r1,\r2
+	.set __decode_fail,0
+	.endif
+	.endr
+	.endif
+	.endr
+	.if __decode_fail == 1
+	.error "__DECODE_RR failed"
+	.endif
+	.endm
+
+	.macro	__DECODE_RRR expand,rsave,rtarget,ruse
+	.set __decode_fail,1
+	.irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	.ifc \rsave,%r\r1
+	.irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	.ifc \rtarget,%r\r2
+	.irp r3,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	.ifc \ruse,%r\r3
+	\expand \r1,\r2,\r3
+	.set __decode_fail,0
+	.endif
+	.endr
+	.endif
+	.endr
+	.endif
+	.endr
+	.if __decode_fail == 1
+	.error "__DECODE_RRR failed"
+	.endif
+	.endm
+
+	.macro	__DECODE_DRR expand,disp,reg,ruse
+	.set __decode_fail,1
+	.irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	.ifc \reg,%r\r1
+	.irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	.ifc \ruse,%r\r2
+	\expand \disp,\r1,\r2
+	.set __decode_fail,0
+	.endif
+	.endr
+	.endif
+	.endr
+	.if __decode_fail == 1
+	.error "__DECODE_DRR failed"
+	.endif
+	.endm
+
+	.macro __THUNK_EX_BR reg,ruse
+	# Be very careful when adding instructions to this macro!
+	# The ALTERNATIVE replacement code has a .+10 which targets
+	# the "br \reg" after the code has been patched.
+#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+	exrl	0,555f
+	j	.
+#else
+	.ifc \reg,%r1
+	ALTERNATIVE "ex %r0,_LC_BR_R1", ".insn ril,0xc60000000000,0,.+10", 35
+	j	.
+	.else
+	larl	\ruse,555f
+	ex	0,0(\ruse)
+	j	.
+	.endif
+#endif
+555:	br	\reg
+	.endm
+
+	.macro __THUNK_EX_BC disp,reg,ruse
+#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+	exrl	0,556f
+	j	.
+#else
+	larl	\ruse,556f
+	ex	0,0(\ruse)
+	j	.
+#endif
+556:	b	\disp(\reg)
+	.endm
+
+	.macro GEN_BR_THUNK reg,ruse=%r1
+	__DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse
+	__THUNK_EX_BR \reg,\ruse
+	__THUNK_EPILOG
+	.endm
+
+	.macro GEN_B_THUNK disp,reg,ruse=%r1
+	__DECODE_DRR __THUNK_PROLOG_BC,\disp,\reg,\ruse
+	__THUNK_EX_BC \disp,\reg,\ruse
+	__THUNK_EPILOG
+	.endm
+
+	.macro BR_EX reg,ruse=%r1
+557:	__DECODE_RR __THUNK_BR,\reg,\ruse
+	.pushsection .s390_indirect_branches,"a",@progbits
+	.long	557b-.
+	.popsection
+	.endm
+
+	 .macro B_EX disp,reg,ruse=%r1
+558:	__DECODE_DRR __THUNK_BC,\disp,\reg,\ruse
+	.pushsection .s390_indirect_branches,"a",@progbits
+	.long	558b-.
+	.popsection
+	.endm
+
+	.macro BASR_EX rsave,rtarget,ruse=%r1
+559:	__DECODE_RRR __THUNK_BRASL,\rsave,\rtarget,\ruse
+	.pushsection .s390_indirect_branches,"a",@progbits
+	.long	559b-.
+	.popsection
+	.endm
+
+#else
+	.macro GEN_BR_THUNK reg,ruse=%r1
+	.endm
+
+	.macro GEN_B_THUNK disp,reg,ruse=%r1
+	.endm
+
+	 .macro BR_EX reg,ruse=%r1
+	br	\reg
+	.endm
+
+	 .macro B_EX disp,reg,ruse=%r1
+	b	\disp(\reg)
+	.endm
+
+	.macro BASR_EX rsave,rtarget,ruse=%r1
+	basr	\rsave,\rtarget
+	.endm
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_S390_NOSPEC_ASM_H */
--- linux-4.4.0.orig/arch/s390/include/asm/pci.h
+++ linux-4.4.0/arch/s390/include/asm/pci.h
@@ -45,7 +45,8 @@
 	u64 rpcit_ops;
 	u64 dma_rbytes;
 	u64 dma_wbytes;
-} __packed __aligned(16);
+	u64 pad[2];
+} __packed __aligned(128);
 
 enum zpci_state {
 	ZPCI_FN_STATE_RESERVED,
@@ -66,7 +67,6 @@
 
 /* Private data per function */
 struct zpci_dev {
-	struct pci_dev	*pdev;
 	struct pci_bus	*bus;
 	struct list_head entry;		/* list of all zpci_devices, needed for hotplug, etc. */
 
@@ -192,7 +192,7 @@
 /* Debug */
 int zpci_debug_init(void);
 void zpci_debug_exit(void);
-void zpci_debug_init_device(struct zpci_dev *);
+void zpci_debug_init_device(struct zpci_dev *, const char *);
 void zpci_debug_exit_device(struct zpci_dev *);
 void zpci_debug_info(struct zpci_dev *, struct seq_file *);
 
--- linux-4.4.0.orig/arch/s390/include/asm/pci_clp.h
+++ linux-4.4.0/arch/s390/include/asm/pci_clp.h
@@ -49,9 +49,6 @@
 /* List PCI functions request */
 struct clp_req_list_pci {
 	struct clp_req_hdr hdr;
-	u32 fmt			:  4;	/* cmd request block format */
-	u32			: 28;
-	u64 reserved1;
 	u64 resume_token;
 	u64 reserved2;
 } __packed;
@@ -59,9 +56,6 @@
 /* List PCI functions response */
 struct clp_rsp_list_pci {
 	struct clp_rsp_hdr hdr;
-	u32 fmt			:  4;	/* cmd request block format */
-	u32			: 28;
-	u64 reserved1;
 	u64 resume_token;
 	u32 reserved2;
 	u16 max_fn;
@@ -73,9 +67,6 @@
 /* Query PCI function request */
 struct clp_req_query_pci {
 	struct clp_req_hdr hdr;
-	u32 fmt			:  4;	/* cmd request block format */
-	u32			: 28;
-	u64 reserved1;
 	u32 fh;				/* function handle */
 	u32 reserved2;
 	u64 reserved3;
@@ -84,9 +75,6 @@
 /* Query PCI function response */
 struct clp_rsp_query_pci {
 	struct clp_rsp_hdr hdr;
-	u32 fmt			:  4;	/* cmd request block format */
-	u32			: 28;
-	u64			: 64;
 	u16 vfn;			/* virtual fn number */
 	u16			:  7;
 	u16 util_str_avail	:  1;	/* utility string available? */
@@ -108,21 +96,15 @@
 /* Query PCI function group request */
 struct clp_req_query_pci_grp {
 	struct clp_req_hdr hdr;
-	u32 fmt			:  4;	/* cmd request block format */
-	u32			: 28;
-	u64 reserved1;
-	u32			: 24;
+	u32 reserved2		: 24;
 	u32 pfgid		:  8;	/* function group id */
-	u32 reserved2;
-	u64 reserved3;
+	u32 reserved3;
+	u64 reserved4;
 } __packed;
 
 /* Query PCI function group response */
 struct clp_rsp_query_pci_grp {
 	struct clp_rsp_hdr hdr;
-	u32 fmt			:  4;	/* cmd request block format */
-	u32			: 28;
-	u64 reserved1;
 	u16			:  4;
 	u16 noi			: 12;	/* number of interrupts */
 	u8 version;
@@ -141,9 +123,6 @@
 /* Set PCI function request */
 struct clp_req_set_pci {
 	struct clp_req_hdr hdr;
-	u32 fmt			:  4;	/* cmd request block format */
-	u32			: 28;
-	u64 reserved1;
 	u32 fh;				/* function handle */
 	u16 reserved2;
 	u8 oc;				/* operation controls */
@@ -154,9 +133,6 @@
 /* Set PCI function response */
 struct clp_rsp_set_pci {
 	struct clp_rsp_hdr hdr;
-	u32 fmt			:  4;	/* cmd request block format */
-	u32			: 28;
-	u64 reserved1;
 	u32 fh;				/* function handle */
 	u32 reserved3;
 	u64 reserved4;
--- linux-4.4.0.orig/arch/s390/include/asm/pci_dma.h
+++ linux-4.4.0/arch/s390/include/asm/pci_dma.h
@@ -23,6 +23,8 @@
 #define ZPCI_IOTA_FS_2G			2
 #define ZPCI_KEY			(PAGE_DEFAULT_KEY << 5)
 
+#define ZPCI_TABLE_SIZE_RT	(1UL << 42)
+
 #define ZPCI_IOTA_STO_FLAG	(ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST)
 #define ZPCI_IOTA_RTTO_FLAG	(ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT)
 #define ZPCI_IOTA_RSTO_FLAG	(ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RS)
--- linux-4.4.0.orig/arch/s390/include/asm/pci_insn.h
+++ linux-4.4.0/arch/s390/include/asm/pci_insn.h
@@ -81,6 +81,6 @@
 int zpci_load(u64 *data, u64 req, u64 offset);
 int zpci_store(u64 data, u64 req, u64 offset);
 int zpci_store_block(const u64 *data, u64 req, u64 offset);
-void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc);
+int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc);
 
 #endif
--- linux-4.4.0.orig/arch/s390/include/asm/pci_io.h
+++ linux-4.4.0/arch/s390/include/asm/pci_io.h
@@ -8,10 +8,13 @@
 #include <asm/pci_insn.h>
 
 /* I/O Map */
-#define ZPCI_IOMAP_MAX_ENTRIES		0x7fff
-#define ZPCI_IOMAP_ADDR_BASE		0x8000000000000000ULL
-#define ZPCI_IOMAP_ADDR_IDX_MASK	0x7fff000000000000ULL
-#define ZPCI_IOMAP_ADDR_OFF_MASK	0x0000ffffffffffffULL
+#define ZPCI_IOMAP_SHIFT		48
+#define ZPCI_IOMAP_ADDR_BASE		0x8000000000000000UL
+#define ZPCI_IOMAP_ADDR_OFF_MASK	((1UL << ZPCI_IOMAP_SHIFT) - 1)
+#define ZPCI_IOMAP_MAX_ENTRIES							\
+	((ULONG_MAX - ZPCI_IOMAP_ADDR_BASE + 1) / (1UL << ZPCI_IOMAP_SHIFT))
+#define ZPCI_IOMAP_ADDR_IDX_MASK						\
+	(~ZPCI_IOMAP_ADDR_OFF_MASK - ZPCI_IOMAP_ADDR_BASE)
 
 struct zpci_iomap_entry {
 	u32 fh;
@@ -21,8 +24,9 @@
 
 extern struct zpci_iomap_entry *zpci_iomap_start;
 
+#define ZPCI_ADDR(idx) (ZPCI_IOMAP_ADDR_BASE | ((u64) idx << ZPCI_IOMAP_SHIFT))
 #define ZPCI_IDX(addr)								\
-	(((__force u64) addr & ZPCI_IOMAP_ADDR_IDX_MASK) >> 48)
+	(((__force u64) addr & ZPCI_IOMAP_ADDR_IDX_MASK) >> ZPCI_IOMAP_SHIFT)
 #define ZPCI_OFFSET(addr)							\
 	((__force u64) addr & ZPCI_IOMAP_ADDR_OFF_MASK)
 
--- linux-4.4.0.orig/arch/s390/include/asm/percpu.h
+++ linux-4.4.0/arch/s390/include/asm/percpu.h
@@ -28,7 +28,7 @@
 	typedef typeof(pcp) pcp_op_T__;					\
 	pcp_op_T__ old__, new__, prev__;				\
 	pcp_op_T__ *ptr__;						\
-	preempt_disable();						\
+	preempt_disable_notrace();					\
 	ptr__ = raw_cpu_ptr(&(pcp));					\
 	prev__ = *ptr__;						\
 	do {								\
@@ -36,7 +36,7 @@
 		new__ = old__ op (val);					\
 		prev__ = cmpxchg(ptr__, old__, new__);			\
 	} while (prev__ != old__);					\
-	preempt_enable();						\
+	preempt_enable_notrace();					\
 	new__;								\
 })
 
@@ -67,7 +67,7 @@
 	typedef typeof(pcp) pcp_op_T__; 				\
 	pcp_op_T__ val__ = (val);					\
 	pcp_op_T__ old__, *ptr__;					\
-	preempt_disable();						\
+	preempt_disable_notrace();					\
 	ptr__ = raw_cpu_ptr(&(pcp)); 				\
 	if (__builtin_constant_p(val__) &&				\
 	    ((szcast)val__ > -129) && ((szcast)val__ < 128)) {		\
@@ -83,7 +83,7 @@
 			: [val__] "d" (val__)				\
 			: "cc");					\
 	}								\
-	preempt_enable();						\
+	preempt_enable_notrace();					\
 }
 
 #define this_cpu_add_4(pcp, val) arch_this_cpu_add(pcp, val, "laa", "asi", int)
@@ -94,14 +94,14 @@
 	typedef typeof(pcp) pcp_op_T__; 				\
 	pcp_op_T__ val__ = (val);					\
 	pcp_op_T__ old__, *ptr__;					\
-	preempt_disable();						\
+	preempt_disable_notrace();					\
 	ptr__ = raw_cpu_ptr(&(pcp));	 				\
 	asm volatile(							\
 		op "    %[old__],%[val__],%[ptr__]\n"			\
 		: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)		\
 		: [val__] "d" (val__)					\
 		: "cc");						\
-	preempt_enable();						\
+	preempt_enable_notrace();						\
 	old__ + val__;							\
 })
 
@@ -113,14 +113,14 @@
 	typedef typeof(pcp) pcp_op_T__; 				\
 	pcp_op_T__ val__ = (val);					\
 	pcp_op_T__ old__, *ptr__;					\
-	preempt_disable();						\
+	preempt_disable_notrace();					\
 	ptr__ = raw_cpu_ptr(&(pcp));	 				\
 	asm volatile(							\
 		op "    %[old__],%[val__],%[ptr__]\n"			\
 		: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)		\
 		: [val__] "d" (val__)					\
 		: "cc");						\
-	preempt_enable();						\
+	preempt_enable_notrace();					\
 }
 
 #define this_cpu_and_4(pcp, val)	arch_this_cpu_to_op(pcp, val, "lan")
@@ -135,10 +135,10 @@
 	typedef typeof(pcp) pcp_op_T__;					\
 	pcp_op_T__ ret__;						\
 	pcp_op_T__ *ptr__;						\
-	preempt_disable();						\
+	preempt_disable_notrace();					\
 	ptr__ = raw_cpu_ptr(&(pcp));					\
 	ret__ = cmpxchg(ptr__, oval, nval);				\
-	preempt_enable();						\
+	preempt_enable_notrace();					\
 	ret__;								\
 })
 
@@ -151,10 +151,10 @@
 ({									\
 	typeof(pcp) *ptr__;						\
 	typeof(pcp) ret__;						\
-	preempt_disable();						\
+	preempt_disable_notrace();					\
 	ptr__ = raw_cpu_ptr(&(pcp));					\
 	ret__ = xchg(ptr__, nval);					\
-	preempt_enable();						\
+	preempt_enable_notrace();					\
 	ret__;								\
 })
 
@@ -170,11 +170,11 @@
 	typeof(pcp1) *p1__;						\
 	typeof(pcp2) *p2__;						\
 	int ret__;							\
-	preempt_disable();						\
+	preempt_disable_notrace();					\
 	p1__ = raw_cpu_ptr(&(pcp1));					\
 	p2__ = raw_cpu_ptr(&(pcp2));					\
 	ret__ = __cmpxchg_double(p1__, p2__, o1__, o2__, n1__, n2__);	\
-	preempt_enable();						\
+	preempt_enable_notrace();					\
 	ret__;								\
 })
 
--- linux-4.4.0.orig/arch/s390/include/asm/pgalloc.h
+++ linux-4.4.0/arch/s390/include/asm/pgalloc.h
@@ -56,8 +56,8 @@
 	return _REGION2_ENTRY_EMPTY;
 }
 
-int crst_table_upgrade(struct mm_struct *, unsigned long limit);
-void crst_table_downgrade(struct mm_struct *, unsigned long limit);
+int crst_table_upgrade(struct mm_struct *);
+void crst_table_downgrade(struct mm_struct *);
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
 {
@@ -100,12 +100,26 @@
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-	spin_lock_init(&mm->context.list_lock);
-	INIT_LIST_HEAD(&mm->context.pgtable_list);
-	INIT_LIST_HEAD(&mm->context.gmap_list);
-	return (pgd_t *) crst_table_alloc(mm);
+	unsigned long *table = crst_table_alloc(mm);
+
+	if (!table)
+		return NULL;
+	if (mm->context.asce_limit == (1UL << 31)) {
+		/* Forking a compat process with 2 page table levels */
+		if (!pgtable_pmd_page_ctor(virt_to_page(table))) {
+			crst_table_free(mm, table);
+			return NULL;
+		}
+	}
+	return (pgd_t *) table;
+}
+
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+	if (mm->context.asce_limit == (1UL << 31))
+		pgtable_pmd_page_dtor(virt_to_page(pgd));
+	crst_table_free(mm, (unsigned long *) pgd);
 }
-#define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)
 
 static inline void pmd_populate(struct mm_struct *mm,
 				pmd_t *pmd, pgtable_t pte)
--- linux-4.4.0.orig/arch/s390/include/asm/pgtable.h
+++ linux-4.4.0/arch/s390/include/asm/pgtable.h
@@ -829,6 +829,8 @@
 {
 	pgste_t pgste;
 
+	if (pte_present(entry))
+		pte_val(entry) &= ~_PAGE_UNUSED;
 	if (mm_has_pgste(mm)) {
 		pgste = pgste_get_lock(ptep);
 		pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
--- linux-4.4.0.orig/arch/s390/include/asm/processor.h
+++ linux-4.4.0/arch/s390/include/asm/processor.h
@@ -69,12 +69,14 @@
 extern const struct seq_operations cpuinfo_op;
 extern int sysctl_ieee_emulation_warnings;
 extern void execve_tail(void);
+extern void __bpon(void);
 
 /*
  * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.
  */
 
-#define TASK_SIZE_OF(tsk)	((tsk)->mm->context.asce_limit)
+#define TASK_SIZE_OF(tsk)	((tsk)->mm ? \
+				 (tsk)->mm->context.asce_limit : TASK_MAX_SIZE)
 #define TASK_UNMAPPED_BASE	(test_thread_flag(TIF_31BIT) ? \
 					(1UL << 30) : (1UL << 41))
 #define TASK_SIZE		TASK_SIZE_OF(current)
@@ -163,7 +165,7 @@
 	regs->psw.mask	= PSW_USER_BITS | PSW_MASK_BA;			\
 	regs->psw.addr	= new_psw | PSW_ADDR_AMODE;			\
 	regs->gprs[15]	= new_stackp;					\
-	crst_table_downgrade(current->mm, 1UL << 31);			\
+	crst_table_downgrade(current->mm);				\
 	execve_tail();							\
 } while (0)
 
@@ -314,6 +316,9 @@
 	memcpy_absolute(&(dest), &__tmp, sizeof(__tmp));	\
 }
 
+extern int s390_isolate_bp(void);
+extern int s390_isolate_bp_guest(void);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_S390_PROCESSOR_H */
--- linux-4.4.0.orig/arch/s390/include/asm/qdio.h
+++ linux-4.4.0/arch/s390/include/asm/qdio.h
@@ -261,7 +261,6 @@
 	void *user;
 };
 
-#define QDIO_OUTBUF_STATE_FLAG_NONE	0x00
 #define QDIO_OUTBUF_STATE_FLAG_PENDING	0x01
 
 #define CHSC_AC1_INITIATE_INPUTQ	0x80
--- linux-4.4.0.orig/arch/s390/include/asm/runtime_instr.h
+++ linux-4.4.0/arch/s390/include/asm/runtime_instr.h
@@ -85,6 +85,8 @@
 		load_runtime_instr_cb(&runtime_instr_empty_cb);
 }
 
-void exit_thread_runtime_instr(void);
+struct task_struct;
+
+void runtime_instr_release(struct task_struct *tsk);
 
 #endif /* _RUNTIME_INSTR_H */
--- linux-4.4.0.orig/arch/s390/include/asm/switch_to.h
+++ linux-4.4.0/arch/s390/include/asm/switch_to.h
@@ -29,17 +29,16 @@
 }
 
 #define switch_to(prev,next,last) do {					\
-	if (prev->mm) {							\
-		save_fpu_regs();					\
-		save_access_regs(&prev->thread.acrs[0]);		\
-		save_ri_cb(prev->thread.ri_cb);				\
-	}								\
-	if (next->mm) {							\
-		update_cr_regs(next);					\
-		set_cpu_flag(CIF_FPU);					\
-		restore_access_regs(&next->thread.acrs[0]);		\
-		restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);	\
-	}								\
+	/* save_fpu_regs() sets the CIF_FPU flag, which enforces	\
+	 * a restore of the floating point / vector registers as	\
+	 * soon as the next task returns to user space			\
+	 */								\
+	save_fpu_regs();						\
+	save_access_regs(&prev->thread.acrs[0]);			\
+	save_ri_cb(prev->thread.ri_cb);					\
+	update_cr_regs(next);						\
+	restore_access_regs(&next->thread.acrs[0]);			\
+	restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);		\
 	prev = __switch_to(prev,next);					\
 } while (0)
 
--- linux-4.4.0.orig/arch/s390/include/asm/syscall.h
+++ linux-4.4.0/arch/s390/include/asm/syscall.h
@@ -41,7 +41,17 @@
 static inline long syscall_get_error(struct task_struct *task,
 				     struct pt_regs *regs)
 {
-	return IS_ERR_VALUE(regs->gprs[2]) ? regs->gprs[2] : 0;
+	unsigned long error = regs->gprs[2];
+#ifdef CONFIG_COMPAT
+	if (test_tsk_thread_flag(task, TIF_31BIT)) {
+		/*
+		 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
+		 * and will match correctly in comparisons.
+		 */
+		error = (long)(int)error;
+	}
+#endif
+	return IS_ERR_VALUE(error) ? error : 0;
 }
 
 static inline long syscall_get_return_value(struct task_struct *task,
@@ -64,6 +74,12 @@
 {
 	unsigned long mask = -1UL;
 
+	/*
+	 * No arguments for this syscall, there's nothing to do.
+	 */
+	if (!n)
+		return;
+
 	BUG_ON(i + n > 6);
 #ifdef CONFIG_COMPAT
 	if (test_tsk_thread_flag(task, TIF_31BIT))
--- linux-4.4.0.orig/arch/s390/include/asm/thread_info.h
+++ linux-4.4.0/arch/s390/include/asm/thread_info.h
@@ -78,6 +78,8 @@
 #define TIF_SECCOMP		5	/* secure computing */
 #define TIF_SYSCALL_TRACEPOINT	6	/* syscall tracepoint instrumentation */
 #define TIF_UPROBE		7	/* breakpointed or single-stepping */
+#define TIF_ISOLATE_BP		8	/* Run process with isolated BP */
+#define TIF_ISOLATE_BP_GUEST	9	/* Run KVM guests with isolated BP */
 #define TIF_31BIT		16	/* 32bit process */
 #define TIF_MEMDIE		17	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	18	/* restore signal mask in do_signal() */
@@ -93,6 +95,8 @@
 #define _TIF_SECCOMP		_BITUL(TIF_SECCOMP)
 #define _TIF_SYSCALL_TRACEPOINT	_BITUL(TIF_SYSCALL_TRACEPOINT)
 #define _TIF_UPROBE		_BITUL(TIF_UPROBE)
+#define _TIF_ISOLATE_BP		_BITUL(TIF_ISOLATE_BP)
+#define _TIF_ISOLATE_BP_GUEST	_BITUL(TIF_ISOLATE_BP_GUEST)
 #define _TIF_31BIT		_BITUL(TIF_31BIT)
 #define _TIF_SINGLE_STEP	_BITUL(TIF_SINGLE_STEP)
 
--- linux-4.4.0.orig/arch/s390/include/asm/timex.h
+++ linux-4.4.0/arch/s390/include/asm/timex.h
@@ -52,6 +52,52 @@
 
 void clock_comparator_work(void);
 
+void __init ptff_init(void);
+
+extern unsigned char ptff_function_mask[16];
+extern unsigned long lpar_offset;
+
+/* Function codes for the ptff instruction. */
+#define PTFF_QAF	0x00	/* query available functions */
+#define PTFF_QTO	0x01	/* query tod offset */
+#define PTFF_QSI	0x02	/* query steering information */
+#define PTFF_ATO	0x40	/* adjust tod offset */
+#define PTFF_STO	0x41	/* set tod offset */
+#define PTFF_SFS	0x42	/* set fine steering rate */
+#define PTFF_SGS	0x43	/* set gross steering rate */
+
+/* Query TOD offset result */
+struct ptff_qto {
+	unsigned long long physical_clock;
+	unsigned long long tod_offset;
+	unsigned long long logical_tod_offset;
+	unsigned long long tod_epoch_difference;
+} __packed;
+
+static inline int ptff_query(unsigned int nr)
+{
+	unsigned char *ptr;
+
+	ptr = ptff_function_mask + (nr >> 3);
+	return (*ptr & (0x80 >> (nr & 7))) != 0;
+}
+
+static inline int ptff(void *ptff_block, size_t len, unsigned int func)
+{
+	typedef struct { char _[len]; } addrtype;
+	register unsigned int reg0 asm("0") = func;
+	register unsigned long reg1 asm("1") = (unsigned long) ptff_block;
+	int rc;
+
+	asm volatile(
+		"	.word	0x0104\n"
+		"	ipm	%0\n"
+		"	srl	%0,28\n"
+		: "=d" (rc), "+m" (*(addrtype *) ptff_block)
+		: "d" (reg0), "d" (reg1) : "cc");
+	return rc;
+}
+
 static inline unsigned long long local_tick_disable(void)
 {
 	unsigned long long old;
@@ -82,7 +128,7 @@
 
 static inline unsigned long long get_tod_clock(void)
 {
-	unsigned char clk[STORE_CLOCK_EXT_SIZE];
+	char clk[STORE_CLOCK_EXT_SIZE];
 
 	get_tod_clock_ext(clk);
 	return *((unsigned long long *)&clk[1]);
@@ -105,7 +151,7 @@
 	return (cycles_t) get_tod_clock() >> 2;
 }
 
-int get_sync_clock(unsigned long long *clock);
+int get_phys_clock(unsigned long long *clock);
 void init_cpu_timer(void);
 unsigned long long monotonic_clock(void);
 
--- linux-4.4.0.orig/arch/s390/include/asm/tlb.h
+++ linux-4.4.0/arch/s390/include/asm/tlb.h
@@ -97,6 +97,19 @@
 {
 	free_page_and_swap_cache(page);
 }
+static inline void tlb_flush_pmd_range(struct mmu_gather *tlb,
+				unsigned long address, unsigned long size)
+{
+	/*
+	 * the range might exceed the original range that was provided to
+	 * tlb_gather_mmu(), so we need to update it despite the fact it is
+	 * usually not updated.
+	 */
+	if (tlb->start > address)
+		tlb->start = address;
+	if (tlb->end < address + size)
+		tlb->end = address + size;
+}
 
 /*
  * pte_free_tlb frees a pte table and clears the CRSTE for the
--- linux-4.4.0.orig/arch/s390/include/asm/tlbflush.h
+++ linux-4.4.0/arch/s390/include/asm/tlbflush.h
@@ -25,17 +25,6 @@
 		: : "a" (2048), "a" (asce) : "cc");
 }
 
-/*
- * Flush TLB entries for a specific ASCE on the local CPU
- */
-static inline void __tlb_flush_idte_local(unsigned long asce)
-{
-	/* Local TLB flush for the mm */
-	asm volatile(
-		"	.insn	rrf,0xb98e0000,0,%0,%1,1"
-		: : "a" (2048), "a" (asce) : "cc");
-}
-
 #ifdef CONFIG_SMP
 void smp_ptlb_all(void);
 
@@ -58,50 +47,26 @@
 }
 
 /*
- * Flush TLB entries for a specific mm on all CPUs (in case gmap is used
- * this implicates multiple ASCEs!).
+ * Flush TLB entries for a specific ASCE on all CPUs.
  */
-static inline void __tlb_flush_full(struct mm_struct *mm)
+static inline void __tlb_flush_mm(struct mm_struct * mm)
 {
+	/*
+	 * If the machine has IDTE we prefer to do a per mm flush
+	 * on all cpus instead of doing a local flush if the mm
+	 * only ran on the local cpu.
+	 */
 	preempt_disable();
 	atomic_add(0x10000, &mm->context.attach_count);
-	if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
-		/* Local TLB flush */
-		__tlb_flush_local();
+	/* Reset TLB flush mask */
+	if (MACHINE_HAS_TLB_LC)
+		cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask);
+	barrier();
+	if (MACHINE_HAS_IDTE && list_empty(&mm->context.gmap_list)) {
+		__tlb_flush_idte(mm->context.asce);
 	} else {
 		/* Global TLB flush */
 		__tlb_flush_global();
-		/* Reset TLB flush mask */
-		if (MACHINE_HAS_TLB_LC)
-			cpumask_copy(mm_cpumask(mm),
-				     &mm->context.cpu_attach_mask);
-	}
-	atomic_sub(0x10000, &mm->context.attach_count);
-	preempt_enable();
-}
-
-/*
- * Flush TLB entries for a specific ASCE on all CPUs.
- */
-static inline void __tlb_flush_asce(struct mm_struct *mm, unsigned long asce)
-{
-	int active, count;
-
-	preempt_disable();
-	active = (mm == current->active_mm) ? 1 : 0;
-	count = atomic_add_return(0x10000, &mm->context.attach_count);
-	if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active &&
-	    cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
-		__tlb_flush_idte_local(asce);
-	} else {
-		if (MACHINE_HAS_IDTE)
-			__tlb_flush_idte(asce);
-		else
-			__tlb_flush_global();
-		/* Reset TLB flush mask */
-		if (MACHINE_HAS_TLB_LC)
-			cpumask_copy(mm_cpumask(mm),
-				     &mm->context.cpu_attach_mask);
 	}
 	atomic_sub(0x10000, &mm->context.attach_count);
 	preempt_enable();
@@ -110,56 +75,41 @@
 static inline void __tlb_flush_kernel(void)
 {
 	if (MACHINE_HAS_IDTE)
-		__tlb_flush_idte((unsigned long) init_mm.pgd |
-				 init_mm.context.asce_bits);
+		__tlb_flush_idte(init_mm.context.asce);
 	else
 		__tlb_flush_global();
 }
 #else
 #define __tlb_flush_global()	__tlb_flush_local()
-#define __tlb_flush_full(mm)	__tlb_flush_local()
 
 /*
  * Flush TLB entries for a specific ASCE on all CPUs.
  */
 static inline void __tlb_flush_asce(struct mm_struct *mm, unsigned long asce)
 {
-	if (MACHINE_HAS_TLB_LC)
-		__tlb_flush_idte_local(asce);
-	else
-		__tlb_flush_local();
+	__tlb_flush_local();
 }
 
 static inline void __tlb_flush_kernel(void)
 {
-	if (MACHINE_HAS_TLB_LC)
-		__tlb_flush_idte_local((unsigned long) init_mm.pgd |
-				       init_mm.context.asce_bits);
-	else
-		__tlb_flush_local();
+	__tlb_flush_local();
 }
-#endif
 
 static inline void __tlb_flush_mm(struct mm_struct * mm)
 {
-	/*
-	 * If the machine has IDTE we prefer to do a per mm flush
-	 * on all cpus instead of doing a local flush if the mm
-	 * only ran on the local cpu.
-	 */
-	if (MACHINE_HAS_IDTE && list_empty(&mm->context.gmap_list))
-		__tlb_flush_asce(mm, (unsigned long) mm->pgd |
-				 mm->context.asce_bits);
-	else
-		__tlb_flush_full(mm);
+	__tlb_flush_local();
 }
 
+#endif
+
 static inline void __tlb_flush_mm_lazy(struct mm_struct * mm)
 {
+	spin_lock(&mm->context.lock);
 	if (mm->context.flush_mm) {
-		__tlb_flush_mm(mm);
 		mm->context.flush_mm = 0;
+		__tlb_flush_mm(mm);
 	}
+	spin_unlock(&mm->context.lock);
 }
 
 /*
--- linux-4.4.0.orig/arch/s390/include/asm/uaccess.h
+++ linux-4.4.0/arch/s390/include/asm/uaccess.h
@@ -150,7 +150,7 @@
 		"	jg	2b\n"				\
 		".popsection\n"					\
 		EX_TABLE(0b,3b) EX_TABLE(1b,3b)			\
-		: "=d" (__rc), "=Q" (*(to))			\
+		: "=d" (__rc), "+Q" (*(to))			\
 		: "d" (size), "Q" (*(from)),			\
 		  "d" (__reg0), "K" (-EFAULT)			\
 		: "cc");					\
@@ -215,28 +215,28 @@
 	__chk_user_ptr(ptr);					\
 	switch (sizeof(*(ptr))) {				\
 	case 1: {						\
-		unsigned char __x;				\
+		unsigned char __x = 0;				\
 		__gu_err = __get_user_fn(&__x, ptr,		\
 					 sizeof(*(ptr)));	\
 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
 		break;						\
 	};							\
 	case 2: {						\
-		unsigned short __x;				\
+		unsigned short __x = 0;				\
 		__gu_err = __get_user_fn(&__x, ptr,		\
 					 sizeof(*(ptr)));	\
 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
 		break;						\
 	};							\
 	case 4: {						\
-		unsigned int __x;				\
+		unsigned int __x = 0;				\
 		__gu_err = __get_user_fn(&__x, ptr,		\
 					 sizeof(*(ptr)));	\
 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
 		break;						\
 	};							\
 	case 8: {						\
-		unsigned long long __x;				\
+		unsigned long long __x = 0;			\
 		__gu_err = __get_user_fn(&__x, ptr,		\
 					 sizeof(*(ptr)));	\
 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
--- linux-4.4.0.orig/arch/s390/include/uapi/asm/clp.h
+++ linux-4.4.0/arch/s390/include/uapi/asm/clp.h
@@ -0,0 +1,28 @@
+/*
+ * ioctl interface for /dev/clp
+ *
+ * Copyright IBM Corp. 2016
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef _ASM_CLP_H
+#define _ASM_CLP_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+struct clp_req {
+	unsigned int c : 1;
+	unsigned int r : 1;
+	unsigned int lps : 6;
+	unsigned int cmd : 8;
+	unsigned int : 16;
+	unsigned int reserved;
+	__u64 data_p;
+};
+
+#define CLP_IOCTL_MAGIC 'c'
+
+#define CLP_SYNC _IOWR(CLP_IOCTL_MAGIC, 0xC1, struct clp_req)
+
+#endif
--- linux-4.4.0.orig/arch/s390/include/uapi/asm/kvm.h
+++ linux-4.4.0/arch/s390/include/uapi/asm/kvm.h
@@ -151,6 +151,7 @@
 #define KVM_SYNC_ARCH0  (1UL << 4)
 #define KVM_SYNC_PFAULT (1UL << 5)
 #define KVM_SYNC_VRS    (1UL << 6)
+#define KVM_SYNC_BPBC   (1UL << 10)
 /* definition of registers in kvm_run */
 struct kvm_sync_regs {
 	__u64 prefix;	/* prefix register */
@@ -168,6 +169,8 @@
 	__u64 vrs[32][2];	/* vector registers */
 	__u8  reserved[512];	/* for future vector expansion */
 	__u32 fpc;	/* only valid with vector registers */
+	__u8 bpbc : 1;		/* bp mode */
+	__u8 reserved2 : 7;
 };
 
 #define KVM_REG_S390_TODPR	(KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1)
--- linux-4.4.0.orig/arch/s390/kernel/Makefile
+++ linux-4.4.0/arch/s390/kernel/Makefile
@@ -44,10 +44,14 @@
 obj-y	+= debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o
 obj-y	+= sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
 obj-y	+= runtime_instr.o cache.o dumpstack.o
-obj-y	+= entry.o reipl.o relocate_kernel.o
+obj-y	+= entry.o reipl.o relocate_kernel.o alternative.o
+obj-y	+= nospec-branch.o
 
 extra-y				+= head.o head64.o vmlinux.lds
 
+obj-$(CONFIG_SYSFS)		+= nospec-sysfs.o
+CFLAGS_REMOVE_nospec-branch.o	+= $(CC_FLAGS_EXPOLINE)
+
 obj-$(CONFIG_MODULES)		+= s390_ksyms.o module.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SCHED_BOOK)	+= topology.o
--- linux-4.4.0.orig/arch/s390/kernel/alternative.c
+++ linux-4.4.0/arch/s390/kernel/alternative.c
@@ -0,0 +1,125 @@
+#include <linux/module.h>
+#include <asm/alternative.h>
+#include <asm/facility.h>
+#include <asm/nospec-branch.h>
+
+#define MAX_PATCH_LEN (255 - 1)
+
+static int __initdata_or_module alt_instr_disabled;
+
+static int __init disable_alternative_instructions(char *str)
+{
+	alt_instr_disabled = 1;
+	return 0;
+}
+
+early_param("noaltinstr", disable_alternative_instructions);
+
+static int __init nogmb_setup_early(char *str)
+{
+	__clear_facility(81, S390_lowcore.alt_stfle_fac_list);
+	return 0;
+}
+early_param("nogmb", nogmb_setup_early);
+
+struct brcl_insn {
+	u16 opc;
+	s32 disp;
+} __packed;
+
+static u16 __initdata_or_module nop16 = 0x0700;
+static u32 __initdata_or_module nop32 = 0x47000000;
+static struct brcl_insn __initdata_or_module nop48 = {
+	0xc004, 0
+};
+
+static const void *nops[] __initdata_or_module = {
+	&nop16,
+	&nop32,
+	&nop48
+};
+
+static void __init_or_module add_jump_padding(void *insns, unsigned int len)
+{
+	struct brcl_insn brcl = {
+		0xc0f4,
+		len / 2
+	};
+
+	memcpy(insns, &brcl, sizeof(brcl));
+	insns += sizeof(brcl);
+	len -= sizeof(brcl);
+
+	while (len > 0) {
+		memcpy(insns, &nop16, 2);
+		insns += 2;
+		len -= 2;
+	}
+}
+
+static void __init_or_module add_padding(void *insns, unsigned int len)
+{
+	if (len > 6)
+		add_jump_padding(insns, len);
+	else if (len >= 2)
+		memcpy(insns, nops[len / 2 - 1], len);
+}
+
+static void __init_or_module __apply_alternatives(struct alt_instr *start,
+						  struct alt_instr *end)
+{
+	struct alt_instr *a;
+	u8 *instr, *replacement;
+	u8 insnbuf[MAX_PATCH_LEN];
+
+	/*
+	 * The scan order should be from start to end. A later scanned
+	 * alternative code can overwrite previously scanned alternative code.
+	 */
+	for (a = start; a < end; a++) {
+		int insnbuf_sz = 0;
+
+		instr = (u8 *)&a->instr_offset + a->instr_offset;
+		replacement = (u8 *)&a->repl_offset + a->repl_offset;
+
+		if (!__test_facility(a->facility,
+				     S390_lowcore.alt_stfle_fac_list))
+			continue;
+
+		if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) {
+			WARN_ONCE(1, "cpu alternatives instructions length is "
+				     "odd, skipping patching\n");
+			continue;
+		}
+
+		memcpy(insnbuf, replacement, a->replacementlen);
+		insnbuf_sz = a->replacementlen;
+
+		if (a->instrlen > a->replacementlen) {
+			add_padding(insnbuf + a->replacementlen,
+				    a->instrlen - a->replacementlen);
+			insnbuf_sz += a->instrlen - a->replacementlen;
+		}
+
+		s390_kernel_write(instr, insnbuf, insnbuf_sz);
+	}
+}
+
+void __init_or_module apply_alternatives(struct alt_instr *start,
+					 struct alt_instr *end)
+{
+	if (!alt_instr_disabled)
+		__apply_alternatives(start, end);
+}
+
+extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
+void __init apply_alternative_instructions(void)
+{
+	pr_info("gmb %s",
+		(__test_facility(81, S390_lowcore.alt_stfle_fac_list)) ?
+		"enabled" : "disabled");
+	pr_info("nobp %s",
+		(__test_facility(82, S390_lowcore.alt_stfle_fac_list)) ?
+		"enabled" : "disabled");
+	apply_alternatives(__alt_instructions, __alt_instructions_end);
+}
--- linux-4.4.0.orig/arch/s390/kernel/asm-offsets.c
+++ linux-4.4.0/arch/s390/kernel/asm-offsets.c
@@ -120,6 +120,7 @@
 	OFFSET(__LC_IO_INT_PARM, _lowcore, io_int_parm);
 	OFFSET(__LC_IO_INT_WORD, _lowcore, io_int_word);
 	OFFSET(__LC_STFL_FAC_LIST, _lowcore, stfl_fac_list);
+	OFFSET(__LC_STFLE_FAC_LIST, _lowcore, stfle_fac_list);
 	OFFSET(__LC_MCCK_CODE, _lowcore, mcck_interruption_code);
 	OFFSET(__LC_MCCK_FAIL_STOR_ADDR, _lowcore, failing_storage_address);
 	OFFSET(__LC_LAST_BREAK, _lowcore, breaking_event_addr);
@@ -170,6 +171,7 @@
 	OFFSET(__LC_MACHINE_FLAGS, _lowcore, machine_flags);
 	OFFSET(__LC_GMAP, _lowcore, gmap);
 	OFFSET(__LC_PASTE, _lowcore, paste);
+	OFFSET(__LC_BR_R1, _lowcore, br_r1_trampoline);
 	/* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */
 	OFFSET(__LC_DUMP_REIPL, _lowcore, ipib);
 	/* hardware defined lowcore locations 0x1000 - 0x18ff */
@@ -181,6 +183,7 @@
 	OFFSET(__LC_PSW_SAVE_AREA, _lowcore, psw_save_area);
 	OFFSET(__LC_PREFIX_SAVE_AREA, _lowcore, prefixreg_save_area);
 	OFFSET(__LC_FP_CREG_SAVE_AREA, _lowcore, fpt_creg_save_area);
+	OFFSET(__LC_TOD_PROGREG_SAVE_AREA, _lowcore, tod_progreg_save_area);
 	OFFSET(__LC_CPU_TIMER_SAVE_AREA, _lowcore, cpu_timer_save_area);
 	OFFSET(__LC_CLOCK_COMP_SAVE_AREA, _lowcore, clock_comp_save_area);
 	OFFSET(__LC_AREGS_SAVE_AREA, _lowcore, access_regs_save_area);
--- linux-4.4.0.orig/arch/s390/kernel/base.S
+++ linux-4.4.0/arch/s390/kernel/base.S
@@ -8,18 +8,22 @@
 
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
+#include <asm/nospec-insn.h>
 #include <asm/ptrace.h>
 #include <asm/sigp.h>
 
+	GEN_BR_THUNK %r9
+	GEN_BR_THUNK %r14
+
 ENTRY(s390_base_mcck_handler)
 	basr	%r13,0
 0:	lg	%r15,__LC_PANIC_STACK	# load panic stack
 	aghi	%r15,-STACK_FRAME_OVERHEAD
 	larl	%r1,s390_base_mcck_handler_fn
-	lg	%r1,0(%r1)
-	ltgr	%r1,%r1
+	lg	%r9,0(%r1)
+	ltgr	%r9,%r9
 	jz	1f
-	basr	%r14,%r1
+	BASR_EX	%r14,%r9
 1:	la	%r1,4095
 	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
 	lpswe	__LC_MCK_OLD_PSW
@@ -36,10 +40,10 @@
 	basr	%r13,0
 0:	aghi	%r15,-STACK_FRAME_OVERHEAD
 	larl	%r1,s390_base_ext_handler_fn
-	lg	%r1,0(%r1)
-	ltgr	%r1,%r1
+	lg	%r9,0(%r1)
+	ltgr	%r9,%r9
 	jz	1f
-	basr	%r14,%r1
+	BASR_EX	%r14,%r9
 1:	lmg	%r0,%r15,__LC_SAVE_AREA_ASYNC
 	ni	__LC_EXT_OLD_PSW+1,0xfd	# clear wait state bit
 	lpswe	__LC_EXT_OLD_PSW
@@ -56,10 +60,10 @@
 	basr	%r13,0
 0:	aghi	%r15,-STACK_FRAME_OVERHEAD
 	larl	%r1,s390_base_pgm_handler_fn
-	lg	%r1,0(%r1)
-	ltgr	%r1,%r1
+	lg	%r9,0(%r1)
+	ltgr	%r9,%r9
 	jz	1f
-	basr	%r14,%r1
+	BASR_EX	%r14,%r9
 	lmg	%r0,%r15,__LC_SAVE_AREA_SYNC
 	lpswe	__LC_PGM_OLD_PSW
 1:	lpswe	disabled_wait_psw-0b(%r13)
@@ -116,7 +120,7 @@
 	larl	%r4,.Lcontinue_psw	# Restore PSW flags
 	lpswe	0(%r4)
 .Lcontinue:
-	br	%r14
+	BR_EX	%r14
 .align 16
 .Lrestart_psw:
 	.long	0x00080000,0x80000000 + .Lrestart_part2
--- linux-4.4.0.orig/arch/s390/kernel/compat_linux.c
+++ linux-4.4.0/arch/s390/kernel/compat_linux.c
@@ -110,7 +110,7 @@
 
 COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid)
 {
-	return sys_setgid((gid_t)gid);
+	return sys_setgid(low2highgid(gid));
 }
 
 COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
@@ -120,7 +120,7 @@
 
 COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid)
 {
-	return sys_setuid((uid_t)uid);
+	return sys_setuid(low2highuid(uid));
 }
 
 COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid)
@@ -173,12 +173,12 @@
 
 COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid)
 {
-	return sys_setfsuid((uid_t)uid);
+	return sys_setfsuid(low2highuid(uid));
 }
 
 COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid)
 {
-	return sys_setfsgid((gid_t)gid);
+	return sys_setfsgid(low2highgid(gid));
 }
 
 static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
@@ -263,6 +263,7 @@
 		return retval;
 	}
 
+	groups_sort(group_info);
 	retval = set_current_groups(group_info);
 	put_group_info(group_info);
 
--- linux-4.4.0.orig/arch/s390/kernel/compat_signal.c
+++ linux-4.4.0/arch/s390/kernel/compat_signal.c
@@ -271,7 +271,7 @@
 
 	/* Restore high gprs from signal stack */
 	if (__copy_from_user(&gprs_high, &sregs_ext->gprs_high,
-			     sizeof(&sregs_ext->gprs_high)))
+			     sizeof(sregs_ext->gprs_high)))
 		return -EFAULT;
 	for (i = 0; i < NUM_GPRS; i++)
 		*(__u32 *)&regs->gprs[i] = gprs_high[i];
--- linux-4.4.0.orig/arch/s390/kernel/crash_dump.c
+++ linux-4.4.0/arch/s390/kernel/crash_dump.c
@@ -23,6 +23,8 @@
 #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
 #define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
 
+#define LINUX_NOTE_NAME "LINUX"
+
 static struct memblock_region oldmem_region;
 
 static struct memblock_type oldmem_type = {
@@ -312,7 +314,7 @@
 static void *nt_s390_timer(void *ptr, struct save_area *sa)
 {
 	return nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer),
-			 KEXEC_CORE_NOTE_NAME);
+			 LINUX_NOTE_NAME);
 }
 
 /*
@@ -321,7 +323,7 @@
 static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa)
 {
 	return nt_init(ptr, NT_S390_TODCMP, &sa->clk_cmp,
-		       sizeof(sa->clk_cmp), KEXEC_CORE_NOTE_NAME);
+		       sizeof(sa->clk_cmp), LINUX_NOTE_NAME);
 }
 
 /*
@@ -330,7 +332,7 @@
 static void *nt_s390_tod_preg(void *ptr, struct save_area *sa)
 {
 	return nt_init(ptr, NT_S390_TODPREG, &sa->tod_reg,
-		       sizeof(sa->tod_reg), KEXEC_CORE_NOTE_NAME);
+		       sizeof(sa->tod_reg), LINUX_NOTE_NAME);
 }
 
 /*
@@ -339,7 +341,7 @@
 static void *nt_s390_ctrs(void *ptr, struct save_area *sa)
 {
 	return nt_init(ptr, NT_S390_CTRS, &sa->ctrl_regs,
-		       sizeof(sa->ctrl_regs), KEXEC_CORE_NOTE_NAME);
+		       sizeof(sa->ctrl_regs), LINUX_NOTE_NAME);
 }
 
 /*
@@ -348,7 +350,7 @@
 static void *nt_s390_prefix(void *ptr, struct save_area *sa)
 {
 	return nt_init(ptr, NT_S390_PREFIX, &sa->pref_reg,
-			 sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME);
+			 sizeof(sa->pref_reg), LINUX_NOTE_NAME);
 }
 
 /*
@@ -357,7 +359,7 @@
 static void *nt_s390_vx_high(void *ptr, __vector128 *vx_regs)
 {
 	return nt_init(ptr, NT_S390_VXRS_HIGH, &vx_regs[16],
-		       16 * sizeof(__vector128), KEXEC_CORE_NOTE_NAME);
+		       16 * sizeof(__vector128), LINUX_NOTE_NAME);
 }
 
 /*
@@ -370,12 +372,12 @@
 	int i;
 
 	note = (Elf64_Nhdr *)ptr;
-	note->n_namesz = strlen(KEXEC_CORE_NOTE_NAME) + 1;
+	note->n_namesz = strlen(LINUX_NOTE_NAME) + 1;
 	note->n_descsz = 16 * 8;
 	note->n_type = NT_S390_VXRS_LOW;
 	len = sizeof(Elf64_Nhdr);
 
-	memcpy(ptr + len, KEXEC_CORE_NOTE_NAME, note->n_namesz);
+	memcpy(ptr + len, LINUX_NOTE_NAME, note->n_namesz);
 	len = roundup(len + note->n_namesz, 4);
 
 	ptr += len;
@@ -462,6 +464,20 @@
 }
 
 /*
+ * Initialize final note (needed for /proc/vmcore code)
+ */
+static void *nt_final(void *ptr)
+{
+	Elf64_Nhdr *note;
+
+	note = (Elf64_Nhdr *) ptr;
+	note->n_namesz = 0;
+	note->n_descsz = 0;
+	note->n_type = 0;
+	return PTR_ADD(ptr, sizeof(Elf64_Nhdr));
+}
+
+/*
  * Initialize ELF header (new kernel)
  */
 static void *ehdr_init(Elf64_Ehdr *ehdr, int mem_chunk_cnt)
@@ -551,6 +567,7 @@
 		ptr = fill_cpu_elf_notes(ptr, &sa_ext->sa, sa_ext->vx_regs);
 	}
 	ptr = nt_vmcoreinfo(ptr);
+	ptr = nt_final(ptr);
 	memset(phdr, 0, sizeof(*phdr));
 	phdr->p_type = PT_NOTE;
 	phdr->p_offset = notes_offset;
--- linux-4.4.0.orig/arch/s390/kernel/diag.c
+++ linux-4.4.0/arch/s390/kernel/diag.c
@@ -76,7 +76,7 @@
 
 static void *show_diag_stat_start(struct seq_file *m, loff_t *pos)
 {
-	return *pos <= nr_cpu_ids ? (void *)((unsigned long) *pos + 1) : NULL;
+	return *pos <= NR_DIAG_STAT ? (void *)((unsigned long) *pos + 1) : NULL;
 }
 
 static void *show_diag_stat_next(struct seq_file *m, void *v, loff_t *pos)
--- linux-4.4.0.orig/arch/s390/kernel/dis.c
+++ linux-4.4.0/arch/s390/kernel/dis.c
@@ -1549,6 +1549,7 @@
 	{ "vfsq", 0xce, INSTR_VRR_VV000MM },
 	{ "vfs", 0xe2, INSTR_VRR_VVV00MM },
 	{ "vftci", 0x4a, INSTR_VRI_VVIMM },
+	{ "", 0, INSTR_INVALID }
 };
 
 static struct s390_insn opcode_eb[] = {
@@ -1961,7 +1962,7 @@
 {
 	char *mode = user_mode(regs) ? "User" : "Krnl";
 	unsigned char code[64];
-	char buffer[64], *ptr;
+	char buffer[128], *ptr;
 	mm_segment_t old_fs;
 	unsigned long addr;
 	int start, end, opsize, hops, i;
@@ -2024,7 +2025,7 @@
 		start += opsize;
 		printk(buffer);
 		ptr = buffer;
-		ptr += sprintf(ptr, "\n          ");
+		ptr += sprintf(ptr, "\n\t  ");
 		hops++;
 	}
 	printk("\n");
--- linux-4.4.0.orig/arch/s390/kernel/early.c
+++ linux-4.4.0/arch/s390/kernel/early.c
@@ -224,10 +224,10 @@
 	if (stsi(vmms, 3, 2, 2) || !vmms->count)
 		return;
 
-	/* Running under KVM? If not we assume z/VM */
+	/* Detect known hypervisors */
 	if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_KVM;
-	else
+	else if (!memcmp(vmms->vm[0].cpi, "\xa9\x61\xe5\xd4", 4))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_VM;
 }
 
@@ -279,6 +279,11 @@
 {
 	stfle(S390_lowcore.stfle_fac_list,
 	      ARRAY_SIZE(S390_lowcore.stfle_fac_list));
+	memcpy(S390_lowcore.alt_stfle_fac_list,
+	       S390_lowcore.stfle_fac_list,
+	       sizeof(S390_lowcore.alt_stfle_fac_list));
+	if (!IS_ENABLED(CONFIG_KERNEL_NOBP))
+		__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
 }
 
 static __init void detect_diag9c(void)
@@ -325,8 +330,10 @@
 		S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
 	if (test_facility(40))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
-	if (test_facility(50) && test_facility(73))
+	if (test_facility(50) && test_facility(73)) {
 		S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
+		__ctl_set_bit(0, 55);
+	}
 	if (test_facility(51))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
 	if (test_facility(129)) {
@@ -439,6 +446,7 @@
 	ipl_save_parameters();
 	rescue_initrd();
 	clear_bss_section();
+	ptff_init();
 	init_kernel_storage_key();
 	lockdep_init();
 	lockdep_off();
--- linux-4.4.0.orig/arch/s390/kernel/entry.S
+++ linux-4.4.0/arch/s390/kernel/entry.S
@@ -23,6 +23,7 @@
 #include <asm/vx-insn.h>
 #include <asm/setup.h>
 #include <asm/nmi.h>
+#include <asm/nospec-insn.h>
 
 __PT_R0      =	__PT_GPRS
 __PT_R1      =	__PT_GPRS + 8
@@ -104,6 +105,7 @@
 	j	3f
 1:	LAST_BREAK %r14
 	UPDATE_VTIME %r14,%r15,\timer
+	BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
 2:	lg	%r15,__LC_ASYNC_STACK	# load async stack
 3:	la	%r11,STACK_FRAME_OVERHEAD(%r15)
 	.endm
@@ -162,8 +164,79 @@
 		tm	off+\addr, \mask
 	.endm
 
+	.macro BPOFF
+	.pushsection .altinstr_replacement, "ax"
+660:	.long	0xb2e8c000
+	.popsection
+661:	.long	0x47000000
+	.pushsection .altinstructions, "a"
+	.long 661b - .
+	.long 660b - .
+	.word 82
+	.byte 4
+	.byte 4
+	.popsection
+	.endm
+
+	.macro BPON
+	.pushsection .altinstr_replacement, "ax"
+662:	.long	0xb2e8d000
+	.popsection
+663:	.long	0x47000000
+	.pushsection .altinstructions, "a"
+	.long 663b - .
+	.long 662b - .
+	.word 82
+	.byte 4
+	.byte 4
+	.popsection
+	.endm
+
+	.macro BPENTER tif_ptr,tif_mask
+	.pushsection .altinstr_replacement, "ax"
+662:	.word	0xc004, 0x0000, 0x0000	# 6 byte nop
+	.word	0xc004, 0x0000, 0x0000	# 6 byte nop
+	.popsection
+664:	TSTMSK	\tif_ptr,\tif_mask
+	jz	. + 8
+	.long	0xb2e8d000
+	.pushsection .altinstructions, "a"
+	.long 664b - .
+	.long 662b - .
+	.word 82
+	.byte 12
+	.byte 12
+	.popsection
+	.endm
+
+	.macro BPEXIT tif_ptr,tif_mask
+	TSTMSK	\tif_ptr,\tif_mask
+	.pushsection .altinstr_replacement, "ax"
+662:	jnz	. + 8
+	.long	0xb2e8d000
+	.popsection
+664:	jz	. + 8
+	.long	0xb2e8c000
+	.pushsection .altinstructions, "a"
+	.long 664b - .
+	.long 662b - .
+	.word 82
+	.byte 8
+	.byte 8
+	.popsection
+	.endm
+
+	GEN_BR_THUNK %r9
+	GEN_BR_THUNK %r14
+	GEN_BR_THUNK %r14,%r11
+
 	.section .kprobes.text, "ax"
 
+ENTRY(__bpon)
+	.globl __bpon
+	BPON
+	BR_EX	%r14
+
 /*
  * Scheduler resume function, called by switch_to
  *  gpr2 = (task_struct *) prev
@@ -190,9 +263,9 @@
 	mvc	__LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
 	lmg	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
-	bzr	%r14
+	jz	0f
 	.insn	s,0xb2800000,__LC_LPP		# set program parameter
-	br	%r14
+0:	BR_EX	%r14
 
 .L__critical_start:
 
@@ -204,9 +277,11 @@
  */
 ENTRY(sie64a)
 	stmg	%r6,%r14,__SF_GPRS(%r15)	# save kernel registers
+	lg	%r12,__LC_CURRENT
 	stg	%r2,__SF_EMPTY(%r15)		# save control block pointer
 	stg	%r3,__SF_EMPTY+8(%r15)		# save guest register save area
 	xc	__SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # reason code = 0
+	mvc	__SF_EMPTY+24(8,%r15),__TI_flags(%r12) # copy thread flags
 	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU		# load guest fp/vx registers ?
 	jno	.Lsie_load_guest_gprs
 	brasl	%r14,load_fpu_regs		# load guest fp/vx regs
@@ -223,31 +298,48 @@
 	jnz	.Lsie_skip
 	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
 	jo	.Lsie_skip			# exit if fp/vx regs changed
+	BPEXIT	__SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
 	sie	0(%r14)
+.Lsie_exit:
+	BPOFF
+	BPENTER	__SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
 .Lsie_skip:
 	ni	__SIE_PROG0C+3(%r14),0xfe	# no longer in SIE
 	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
 .Lsie_done:
 # some program checks are suppressing. C code (e.g. do_protection_exception)
-# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
-# instructions between sie64a and .Lsie_done should not cause program
-# interrupts. So lets use a nop (47 00 00 00) as a landing pad.
+# will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There
+# are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable.
+# Other instructions between sie64a and .Lsie_done should not cause program
+# interrupts. So lets use 3 nops as a landing pad for all possible rewinds.
 # See also .Lcleanup_sie
-.Lrewind_pad:
-	nop	0
+.Lrewind_pad6:
+	nopr	7
+.Lrewind_pad4:
+	nopr	7
+.Lrewind_pad2:
+	nopr	7
 	.globl sie_exit
 sie_exit:
 	lg	%r14,__SF_EMPTY+8(%r15)		# load guest register save area
 	stmg	%r0,%r13,0(%r14)		# save guest gprs 0-13
+	xgr	%r0,%r0				# clear guest registers to
+	xgr	%r1,%r1				# prevent speculative use
+	xgr	%r2,%r2
+	xgr	%r3,%r3
+	xgr	%r4,%r4
+	xgr	%r5,%r5
 	lmg	%r6,%r14,__SF_GPRS(%r15)	# restore kernel registers
 	lg	%r2,__SF_EMPTY+16(%r15)		# return exit reason code
-	br	%r14
+	BR_EX	%r14
 .Lsie_fault:
 	lghi	%r14,-EFAULT
 	stg	%r14,__SF_EMPTY+16(%r15)	# set exit reason code
 	j	sie_exit
 
-	EX_TABLE(.Lrewind_pad,.Lsie_fault)
+	EX_TABLE(.Lrewind_pad6,.Lsie_fault)
+	EX_TABLE(.Lrewind_pad4,.Lsie_fault)
+	EX_TABLE(.Lrewind_pad2,.Lsie_fault)
 	EX_TABLE(sie_exit,.Lsie_fault)
 #endif
 
@@ -260,6 +352,7 @@
 	stpt	__LC_SYNC_ENTER_TIMER
 .Lsysc_stmg:
 	stmg	%r8,%r15,__LC_SAVE_AREA_SYNC
+	BPOFF
 	lg	%r10,__LC_LAST_BREAK
 	lg	%r12,__LC_THREAD_INFO
 	lghi	%r14,_PIF_SYSCALL
@@ -269,12 +362,15 @@
 	LAST_BREAK %r13
 .Lsysc_vtime:
 	UPDATE_VTIME %r10,%r13,__LC_SYNC_ENTER_TIMER
+	BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
 	stmg	%r0,%r7,__PT_R0(%r11)
 	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
 	mvc	__PT_PSW(16,%r11),__LC_SVC_OLD_PSW
 	mvc	__PT_INT_CODE(4,%r11),__LC_SVC_ILC
 	stg	%r14,__PT_FLAGS(%r11)
 .Lsysc_do_svc:
+	# clear user controlled register to prevent speculative use
+	xgr	%r0,%r0
 	lg	%r10,__TI_sysc_table(%r12)	# address of system call table
 	llgh	%r8,__PT_INT_CODE+2(%r11)
 	slag	%r8,%r8,2			# shift and test for svc 0
@@ -292,7 +388,7 @@
 	lgf	%r9,0(%r8,%r10)			# get system call add.
 	TSTMSK	__TI_flags(%r12),_TIF_TRACE
 	jnz	.Lsysc_tracesys
-	basr	%r14,%r9			# call sys_xxxx
+	BASR_EX	%r14,%r9			# call sys_xxxx
 	stg	%r2,__PT_R2(%r11)		# store return value
 
 .Lsysc_return:
@@ -304,10 +400,12 @@
 	jnz	.Lsysc_work			# check for work
 	TSTMSK	__LC_CPU_FLAGS,_CIF_WORK
 	jnz	.Lsysc_work
+	BPEXIT	__TI_flags(%r12),_TIF_ISOLATE_BP
 .Lsysc_restore:
 	lg	%r14,__LC_VDSO_PER_CPU
 	lmg	%r0,%r10,__PT_R0(%r11)
 	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r11)
+.Lsysc_exit_timer:
 	stpt	__LC_EXIT_TIMER
 	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
 	lmg	%r11,%r15,__PT_R11(%r11)
@@ -430,7 +528,7 @@
 	lmg	%r3,%r7,__PT_R3(%r11)
 	stg	%r7,STACK_FRAME_OVERHEAD(%r15)
 	lg	%r2,__PT_ORIG_GPR2(%r11)
-	basr	%r14,%r9		# call sys_xxx
+	BASR_EX	%r14,%r9		# call sys_xxx
 	stg	%r2,__PT_R2(%r11)	# store return value
 .Lsysc_tracenogo:
 	TSTMSK	__TI_flags(%r12),_TIF_TRACE
@@ -454,7 +552,7 @@
 	lmg	%r9,%r10,__PT_R9(%r11)	# load gprs
 ENTRY(kernel_thread_starter)
 	la	%r2,0(%r10)
-	basr	%r14,%r9
+	BASR_EX	%r14,%r9
 	j	.Lsysc_tracenogo
 
 /*
@@ -463,6 +561,7 @@
 
 ENTRY(pgm_check_handler)
 	stpt	__LC_SYNC_ENTER_TIMER
+	BPOFF
 	stmg	%r8,%r15,__LC_SAVE_AREA_SYNC
 	lg	%r10,__LC_LAST_BREAK
 	lg	%r12,__LC_THREAD_INFO
@@ -487,6 +586,7 @@
 	j	3f
 2:	LAST_BREAK %r14
 	UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
+	BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
 	lg	%r15,__LC_KERNEL_STACK
 	lg	%r14,__TI_task(%r12)
 	aghi	%r14,__TASK_thread	# pointer to thread_struct
@@ -496,6 +596,15 @@
 	mvc	__THREAD_trap_tdb(256,%r14),0(%r13)
 3:	la	%r11,STACK_FRAME_OVERHEAD(%r15)
 	stmg	%r0,%r7,__PT_R0(%r11)
+	# clear user controlled registers to prevent speculative use
+	xgr	%r0,%r0
+	xgr	%r1,%r1
+	xgr	%r2,%r2
+	xgr	%r3,%r3
+	xgr	%r4,%r4
+	xgr	%r5,%r5
+	xgr	%r6,%r6
+	xgr	%r7,%r7
 	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
 	stmg	%r8,%r9,__PT_PSW(%r11)
 	mvc	__PT_INT_CODE(4,%r11),__LC_PGM_ILC
@@ -517,9 +626,9 @@
 	nill	%r10,0x007f
 	sll	%r10,2
 	je	.Lpgm_return
-	lgf	%r1,0(%r10,%r1)		# load address of handler routine
+	lgf	%r9,0(%r10,%r1)		# load address of handler routine
 	lgr	%r2,%r11		# pass pointer to pt_regs
-	basr	%r14,%r1		# branch to interrupt-handler
+	BASR_EX	%r14,%r9		# branch to interrupt-handler
 .Lpgm_return:
 	LOCKDEP_SYS_EXIT
 	tm	__PT_PSW+1(%r11),0x01	# returning to user ?
@@ -552,6 +661,7 @@
 ENTRY(io_int_handler)
 	STCK	__LC_INT_CLOCK
 	stpt	__LC_ASYNC_ENTER_TIMER
+	BPOFF
 	stmg	%r8,%r15,__LC_SAVE_AREA_ASYNC
 	lg	%r10,__LC_LAST_BREAK
 	lg	%r12,__LC_THREAD_INFO
@@ -559,6 +669,16 @@
 	lmg	%r8,%r9,__LC_IO_OLD_PSW
 	SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
 	stmg	%r0,%r7,__PT_R0(%r11)
+	# clear user controlled registers to prevent speculative use
+	xgr	%r0,%r0
+	xgr	%r1,%r1
+	xgr	%r2,%r2
+	xgr	%r3,%r3
+	xgr	%r4,%r4
+	xgr	%r5,%r5
+	xgr	%r6,%r6
+	xgr	%r7,%r7
+	xgr	%r10,%r10
 	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
 	stmg	%r8,%r9,__PT_PSW(%r11)
 	mvc	__PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
@@ -593,8 +713,13 @@
 	lg	%r14,__LC_VDSO_PER_CPU
 	lmg	%r0,%r10,__PT_R0(%r11)
 	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r11)
+	tm	__PT_PSW+1(%r11),0x01	# returning to user ?
+	jno	.Lio_exit_kernel
+	BPEXIT	__TI_flags(%r12),_TIF_ISOLATE_BP
+.Lio_exit_timer:
 	stpt	__LC_EXIT_TIMER
 	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
+.Lio_exit_kernel:
 	lmg	%r11,%r15,__PT_R11(%r11)
 	lpswe	__LC_RETURN_PSW
 .Lio_done:
@@ -726,6 +851,7 @@
 ENTRY(ext_int_handler)
 	STCK	__LC_INT_CLOCK
 	stpt	__LC_ASYNC_ENTER_TIMER
+	BPOFF
 	stmg	%r8,%r15,__LC_SAVE_AREA_ASYNC
 	lg	%r10,__LC_LAST_BREAK
 	lg	%r12,__LC_THREAD_INFO
@@ -733,6 +859,16 @@
 	lmg	%r8,%r9,__LC_EXT_OLD_PSW
 	SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
 	stmg	%r0,%r7,__PT_R0(%r11)
+	# clear user controlled registers to prevent speculative use
+	xgr	%r0,%r0
+	xgr	%r1,%r1
+	xgr	%r2,%r2
+	xgr	%r3,%r3
+	xgr	%r4,%r4
+	xgr	%r5,%r5
+	xgr	%r6,%r6
+	xgr	%r7,%r7
+	xgr	%r10,%r10
 	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
 	stmg	%r8,%r9,__PT_PSW(%r11)
 	lghi	%r1,__LC_EXT_PARAMS2
@@ -764,11 +900,12 @@
 	.insn	rsy,0xeb0000000017,%r1,5,__SF_EMPTY+16(%r15)
 .Lpsw_idle_stcctm:
 #endif
+	BPON
 	STCK	__CLOCK_IDLE_ENTER(%r2)
 	stpt	__TIMER_IDLE_ENTER(%r2)
 .Lpsw_idle_lpsw:
 	lpswe	__SF_EMPTY(%r15)
-	br	%r14
+	BR_EX	%r14
 .Lpsw_idle_end:
 
 /*
@@ -782,7 +919,7 @@
 	lg	%r2,__LC_CURRENT
 	aghi	%r2,__TASK_thread
 	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
-	bor	%r14
+	jo	.Lsave_fpu_regs_exit
 	stfpc	__THREAD_FPU_fpc(%r2)
 .Lsave_fpu_regs_fpc_end:
 	lg	%r3,__THREAD_FPU_regs(%r2)
@@ -812,7 +949,8 @@
 	std	15,120(%r3)
 .Lsave_fpu_regs_done:
 	oi	__LC_CPU_FLAGS+7,_CIF_FPU
-	br	%r14
+.Lsave_fpu_regs_exit:
+	BR_EX	%r14
 .Lsave_fpu_regs_end:
 
 /*
@@ -829,7 +967,7 @@
 	lg	%r4,__LC_CURRENT
 	aghi	%r4,__TASK_thread
 	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
-	bnor	%r14
+	jno	.Lload_fpu_regs_exit
 	lfpc	__THREAD_FPU_fpc(%r4)
 	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
 	lg	%r4,__THREAD_FPU_regs(%r4)	# %r4 <- reg save area
@@ -858,7 +996,8 @@
 	ld	15,120(%r4)
 .Lload_fpu_regs_done:
 	ni	__LC_CPU_FLAGS+7,255-_CIF_FPU
-	br	%r14
+.Lload_fpu_regs_exit:
+	BR_EX	%r14
 .Lload_fpu_regs_end:
 
 .L__critical_end:
@@ -868,6 +1007,7 @@
  */
 ENTRY(mcck_int_handler)
 	STCK	__LC_MCCK_CLOCK
+	BPOFF
 	la	%r1,4095		# revalidate r1
 	spt	__LC_CPU_TIMER_SAVE_AREA-4095(%r1)	# revalidate cpu timer
 	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
@@ -899,6 +1039,16 @@
 .Lmcck_skip:
 	lghi	%r14,__LC_GPREGS_SAVE_AREA+64
 	stmg	%r0,%r7,__PT_R0(%r11)
+	# clear user controlled registers to prevent speculative use
+	xgr	%r0,%r0
+	xgr	%r1,%r1
+	xgr	%r2,%r2
+	xgr	%r3,%r3
+	xgr	%r4,%r4
+	xgr	%r5,%r5
+	xgr	%r6,%r6
+	xgr	%r7,%r7
+	xgr	%r10,%r10
 	mvc	__PT_R8(64,%r11),0(%r14)
 	stmg	%r8,%r9,__PT_PSW(%r11)
 	xc	__PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
@@ -924,6 +1074,7 @@
 	mvc	__LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
 	tm	__LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
 	jno	0f
+	BPEXIT	__TI_flags(%r12),_TIF_ISOLATE_BP
 	stpt	__LC_EXIT_TIMER
 	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
 0:	lmg	%r11,%r15,__PT_R11(%r11)
@@ -1019,7 +1170,7 @@
 	jl	0f
 	clg	%r9,BASED(.Lcleanup_table+104)	# .Lload_fpu_regs_end
 	jl	.Lcleanup_load_fpu_regs
-0:	br	%r14
+0:	BR_EX	%r14,%r11
 
 	.align	8
 .Lcleanup_table:
@@ -1044,11 +1195,12 @@
 	.quad	.Lsie_done
 
 .Lcleanup_sie:
+	BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
 	lg	%r9,__SF_EMPTY(%r15)		# get control block pointer
 	ni	__SIE_PROG0C+3(%r9),0xfe	# no longer in SIE
 	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
 	larl	%r9,sie_exit			# skip forward to sie_exit
-	br	%r14
+	BR_EX	%r14,%r11
 #endif
 
 .Lcleanup_system_call:
@@ -1090,7 +1242,8 @@
 	srag	%r9,%r9,23
 	jz	0f
 	mvc	__TI_last_break(8,%r12),16(%r11)
-0:	# set up saved register r11
+0:	BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
+	# set up saved register r11
 	lg	%r15,__LC_KERNEL_STACK
 	la	%r9,STACK_FRAME_OVERHEAD(%r15)
 	stg	%r9,24(%r11)		# r11 pt_regs pointer
@@ -1105,7 +1258,7 @@
 	stg	%r15,56(%r11)		# r15 stack pointer
 	# set new psw address and exit
 	larl	%r9,.Lsysc_do_svc
-	br	%r14
+	BR_EX	%r14,%r11
 .Lcleanup_system_call_insn:
 	.quad	system_call
 	.quad	.Lsysc_stmg
@@ -1115,34 +1268,47 @@
 
 .Lcleanup_sysc_tif:
 	larl	%r9,.Lsysc_tif
-	br	%r14
+	BR_EX	%r14,%r11
 
 .Lcleanup_sysc_restore:
+	# check if stpt has been executed
 	clg	%r9,BASED(.Lcleanup_sysc_restore_insn)
+	jh	0f
+	mvc	__LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+	cghi	%r11,__LC_SAVE_AREA_ASYNC
 	je	0f
+	mvc	__LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER
+0:	clg	%r9,BASED(.Lcleanup_sysc_restore_insn+8)
+	je	1f
 	lg	%r9,24(%r11)		# get saved pointer to pt_regs
 	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r9)
 	mvc	0(64,%r11),__PT_R8(%r9)
 	lmg	%r0,%r7,__PT_R0(%r9)
-0:	lmg	%r8,%r9,__LC_RETURN_PSW
-	br	%r14
+1:	lmg	%r8,%r9,__LC_RETURN_PSW
+	BR_EX	%r14,%r11
 .Lcleanup_sysc_restore_insn:
+	.quad	.Lsysc_exit_timer
 	.quad	.Lsysc_done - 4
 
 .Lcleanup_io_tif:
 	larl	%r9,.Lio_tif
-	br	%r14
+	BR_EX	%r14,%r11
 
 .Lcleanup_io_restore:
+	# check if stpt has been executed
 	clg	%r9,BASED(.Lcleanup_io_restore_insn)
-	je	0f
+	jh	0f
+	mvc	__LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER
+0:	clg	%r9,BASED(.Lcleanup_io_restore_insn+8)
+	je	1f
 	lg	%r9,24(%r11)		# get saved r11 pointer to pt_regs
 	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r9)
 	mvc	0(64,%r11),__PT_R8(%r9)
 	lmg	%r0,%r7,__PT_R0(%r9)
-0:	lmg	%r8,%r9,__LC_RETURN_PSW
-	br	%r14
+1:	lmg	%r8,%r9,__LC_RETURN_PSW
+	BR_EX	%r14,%r11
 .Lcleanup_io_restore_insn:
+	.quad	.Lio_exit_timer
 	.quad	.Lio_done - 4
 
 .Lcleanup_idle:
@@ -1192,119 +1358,17 @@
 	# prepare return psw
 	nihh	%r8,0xfcfd		# clear irq & wait state bits
 	lg	%r9,48(%r11)		# return from psw_idle
-	br	%r14
+	BR_EX	%r14,%r11
 .Lcleanup_idle_insn:
 	.quad	.Lpsw_idle_lpsw
 
 .Lcleanup_save_fpu_regs:
-	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
-	bor	%r14
-	clg	%r9,BASED(.Lcleanup_save_fpu_regs_done)
-	jhe	5f
-	clg	%r9,BASED(.Lcleanup_save_fpu_regs_fp)
-	jhe	4f
-	clg	%r9,BASED(.Lcleanup_save_fpu_regs_vx_high)
-	jhe	3f
-	clg	%r9,BASED(.Lcleanup_save_fpu_regs_vx_low)
-	jhe	2f
-	clg	%r9,BASED(.Lcleanup_save_fpu_fpc_end)
-	jhe	1f
-	lg	%r2,__LC_CURRENT
-	aghi	%r2,__TASK_thread
-0:	# Store floating-point controls
-	stfpc	__THREAD_FPU_fpc(%r2)
-1:	# Load register save area and check if VX is active
-	lg	%r3,__THREAD_FPU_regs(%r2)
-	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
-	jz	4f			  # no VX -> store FP regs
-2:	# Store vector registers (V0-V15)
-	VSTM	%v0,%v15,0,%r3		  # vstm 0,15,0(3)
-3:	# Store vector registers (V16-V31)
-	VSTM	%v16,%v31,256,%r3	  # vstm 16,31,256(3)
-	j	5f			  # -> done, set CIF_FPU flag
-4:	# Store floating-point registers
-	std	0,0(%r3)
-	std	1,8(%r3)
-	std	2,16(%r3)
-	std	3,24(%r3)
-	std	4,32(%r3)
-	std	5,40(%r3)
-	std	6,48(%r3)
-	std	7,56(%r3)
-	std	8,64(%r3)
-	std	9,72(%r3)
-	std	10,80(%r3)
-	std	11,88(%r3)
-	std	12,96(%r3)
-	std	13,104(%r3)
-	std	14,112(%r3)
-	std	15,120(%r3)
-5:	# Set CIF_FPU flag
-	oi	__LC_CPU_FLAGS+7,_CIF_FPU
-	lg	%r9,48(%r11)		# return from save_fpu_regs
-	br	%r14
-.Lcleanup_save_fpu_fpc_end:
-	.quad	.Lsave_fpu_regs_fpc_end
-.Lcleanup_save_fpu_regs_vx_low:
-	.quad	.Lsave_fpu_regs_vx_low
-.Lcleanup_save_fpu_regs_vx_high:
-	.quad	.Lsave_fpu_regs_vx_high
-.Lcleanup_save_fpu_regs_fp:
-	.quad	.Lsave_fpu_regs_fp
-.Lcleanup_save_fpu_regs_done:
-	.quad	.Lsave_fpu_regs_done
+	larl	%r9,save_fpu_regs
+	BR_EX	%r14,%r11
 
 .Lcleanup_load_fpu_regs:
-	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
-	bnor	%r14
-	clg	%r9,BASED(.Lcleanup_load_fpu_regs_done)
-	jhe	1f
-	clg	%r9,BASED(.Lcleanup_load_fpu_regs_fp)
-	jhe	2f
-	clg	%r9,BASED(.Lcleanup_load_fpu_regs_vx_high)
-	jhe	3f
-	clg	%r9,BASED(.Lcleanup_load_fpu_regs_vx)
-	jhe	4f
-	lg	%r4,__LC_CURRENT
-	aghi	%r4,__TASK_thread
-	lfpc	__THREAD_FPU_fpc(%r4)
-	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
-	lg	%r4,__THREAD_FPU_regs(%r4)	# %r4 <- reg save area
-	jz	2f				# -> no VX, load FP regs
-4:	# Load V0 ..V15 registers
-	VLM	%v0,%v15,0,%r4
-3:	# Load V16..V31 registers
-	VLM	%v16,%v31,256,%r4
-	j	1f
-2:	# Load floating-point registers
-	ld	0,0(%r4)
-	ld	1,8(%r4)
-	ld	2,16(%r4)
-	ld	3,24(%r4)
-	ld	4,32(%r4)
-	ld	5,40(%r4)
-	ld	6,48(%r4)
-	ld	7,56(%r4)
-	ld	8,64(%r4)
-	ld	9,72(%r4)
-	ld	10,80(%r4)
-	ld	11,88(%r4)
-	ld	12,96(%r4)
-	ld	13,104(%r4)
-	ld	14,112(%r4)
-	ld	15,120(%r4)
-1:	# Clear CIF_FPU bit
-	ni	__LC_CPU_FLAGS+7,255-_CIF_FPU
-	lg	%r9,48(%r11)		# return from load_fpu_regs
-	br	%r14
-.Lcleanup_load_fpu_regs_vx:
-	.quad	.Lload_fpu_regs_vx
-.Lcleanup_load_fpu_regs_vx_high:
-	.quad	.Lload_fpu_regs_vx_high
-.Lcleanup_load_fpu_regs_fp:
-	.quad	.Lload_fpu_regs_fp
-.Lcleanup_load_fpu_regs_done:
-	.quad	.Lload_fpu_regs_done
+	larl	%r9,load_fpu_regs
+	BR_EX	%r14,%r11
 
 /*
  * Integer constants
@@ -1320,7 +1384,6 @@
 .Lsie_critical_length:
 	.quad	.Lsie_done - .Lsie_gmap
 #endif
-
 	.section .rodata, "a"
 #define SYSCALL(esame,emu)	.long esame
 	.globl	sys_call_table
--- linux-4.4.0.orig/arch/s390/kernel/head.S
+++ linux-4.4.0/arch/s390/kernel/head.S
@@ -300,19 +300,19 @@
 	xc	0x200(256),0x200	# partially clear lowcore
 	xc	0x300(256),0x300
 	xc	0xe00(256),0xe00
+	xc	0xf00(256),0xf00
 	lctlg	%c0,%c15,0x200(%r0)	# initialize control registers
 	stck	__LC_LAST_UPDATE_CLOCK
 	spt	6f-.LPG0(%r13)
 	mvc	__LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13)
-	xc	__LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST
-	# check capabilities against MARCH_{G5,Z900,Z990,Z9_109,Z10}
-	.insn	s,0xb2b10000,0		# store facilities @ __LC_STFL_FAC_LIST
-	tm	__LC_STFL_FAC_LIST,0x01	# stfle available ?
+	stfl	0(%r0)			# store facilities @ __LC_STFL_FAC_LIST
+	mvc	__LC_STFLE_FAC_LIST(4),__LC_STFL_FAC_LIST
+	tm	__LC_STFLE_FAC_LIST,0x01	# stfle available ?
 	jz	0f
 	la	%r0,1
-	.insn	s,0xb2b00000,__LC_STFL_FAC_LIST	# store facility list extended
+	.insn	s,0xb2b00000,__LC_STFLE_FAC_LIST # store facility list extended
 	# verify if all required facilities are supported by the machine
-0:	la	%r1,__LC_STFL_FAC_LIST
+0:	la	%r1,__LC_STFLE_FAC_LIST
 	la	%r2,3f+8-.LPG0(%r13)
 	l	%r3,0(%r2)
 1:	l	%r0,0(%r1)
--- linux-4.4.0.orig/arch/s390/kernel/head64.S
+++ linux-4.4.0/arch/s390/kernel/head64.S
@@ -16,7 +16,7 @@
 
 __HEAD
 ENTRY(startup_continue)
-	tm	__LC_STFL_FAC_LIST+6,0x80	# LPP available ?
+	tm	__LC_STFLE_FAC_LIST+5,0x80	# LPP available ?
 	jz	0f
 	xc	__LC_LPP+1(7,0),__LC_LPP+1	# clear lpp and current_pid
 	mvi	__LC_LPP,0x80			#   and set LPP_MAGIC
--- linux-4.4.0.orig/arch/s390/kernel/ipl.c
+++ linux-4.4.0/arch/s390/kernel/ipl.c
@@ -563,6 +563,7 @@
 
 static void __ipl_run(void *unused)
 {
+	__bpon();
 	diag308(DIAG308_IPL, NULL);
 	if (MACHINE_IS_VM)
 		__cpcmd("IPL", NULL, 0, NULL);
@@ -798,6 +799,7 @@
 	/* copy and convert to ebcdic */
 	memcpy(ipb->hdr.loadparm, buf, lp_len);
 	ASCEBC(ipb->hdr.loadparm, LOADPARM_LEN);
+	ipb->hdr.flags |= DIAG308_FLAGS_LP_VALID;
 	return len;
 }
 
@@ -2070,13 +2072,6 @@
 	S390_lowcore.program_new_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
 
-	/*
-	 * Clear subchannel ID and number to signal new kernel that no CCW or
-	 * SCSI IPL has been done (for kexec and kdump)
-	 */
-	S390_lowcore.subchannel_id = 0;
-	S390_lowcore.subchannel_nr = 0;
-
 	/* Store status at absolute zero */
 	store_status();
 
--- linux-4.4.0.orig/arch/s390/kernel/irq.c
+++ linux-4.4.0/arch/s390/kernel/irq.c
@@ -173,10 +173,9 @@
 		new -= STACK_FRAME_OVERHEAD;
 		((struct stack_frame *) new)->back_chain = old;
 		asm volatile("   la    15,0(%0)\n"
-			     "   basr  14,%2\n"
+			     "   brasl 14,__do_softirq\n"
 			     "   la    15,0(%1)\n"
-			     : : "a" (new), "a" (old),
-			         "a" (__do_softirq)
+			     : : "a" (new), "a" (old)
 			     : "0", "1", "2", "3", "4", "5", "14",
 			       "cc", "memory" );
 	} else {
--- linux-4.4.0.orig/arch/s390/kernel/mcount.S
+++ linux-4.4.0/arch/s390/kernel/mcount.S
@@ -8,31 +8,49 @@
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/ftrace.h>
+#include <asm/nospec-insn.h>
 #include <asm/ptrace.h>
 
+	GEN_BR_THUNK %r1
+	GEN_BR_THUNK %r14
+
 	.section .kprobes.text, "ax"
 
 ENTRY(ftrace_stub)
-	br	%r14
+	BR_EX	%r14
 
 #define STACK_FRAME_SIZE  (STACK_FRAME_OVERHEAD + __PT_SIZE)
 #define STACK_PTREGS	  (STACK_FRAME_OVERHEAD)
 #define STACK_PTREGS_GPRS (STACK_PTREGS + __PT_GPRS)
 #define STACK_PTREGS_PSW  (STACK_PTREGS + __PT_PSW)
+#ifdef __PACK_STACK
+/* allocate just enough for r14, r15 and backchain */
+#define TRACED_FUNC_FRAME_SIZE	24
+#else
+#define TRACED_FUNC_FRAME_SIZE	STACK_FRAME_OVERHEAD
+#endif
 
 ENTRY(_mcount)
-	br	%r14
+	BR_EX	%r14
 
 ENTRY(ftrace_caller)
 	.globl	ftrace_regs_caller
 	.set	ftrace_regs_caller,ftrace_caller
+	stg	%r14,(__SF_GPRS+8*8)(%r15)	# save traced function caller
 	lgr	%r1,%r15
 #ifndef CC_USING_HOTPATCH
 	aghi	%r0,MCOUNT_RETURN_FIXUP
 #endif
-	aghi	%r15,-STACK_FRAME_SIZE
+	# allocate stack frame for ftrace_caller to contain traced function
+	aghi	%r15,-TRACED_FUNC_FRAME_SIZE
 	stg	%r1,__SF_BACKCHAIN(%r15)
+	stg	%r0,(__SF_GPRS+8*8)(%r15)
+	stg	%r15,(__SF_GPRS+9*8)(%r15)
+	# allocate pt_regs and stack frame for ftrace_trace_function
+	aghi	%r15,-STACK_FRAME_SIZE
 	stg	%r1,(STACK_PTREGS_GPRS+15*8)(%r15)
+	aghi	%r1,-TRACED_FUNC_FRAME_SIZE
+	stg	%r1,__SF_BACKCHAIN(%r15)
 	stg	%r0,(STACK_PTREGS_PSW+8)(%r15)
 	stmg	%r2,%r14,(STACK_PTREGS_GPRS+2*8)(%r15)
 #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
@@ -49,7 +67,7 @@
 #endif
 	lgr	%r3,%r14
 	la	%r5,STACK_PTREGS(%r15)
-	basr	%r14,%r1
+	BASR_EX	%r14,%r1
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 # The j instruction gets runtime patched to a nop instruction.
 # See ftrace_enable_ftrace_graph_caller.
@@ -64,7 +82,7 @@
 #endif
 	lg	%r1,(STACK_PTREGS_PSW+8)(%r15)
 	lmg	%r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15)
-	br	%r1
+	BR_EX	%r1
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
@@ -77,6 +95,6 @@
 	aghi	%r15,STACK_FRAME_OVERHEAD
 	lgr	%r14,%r2
 	lmg	%r2,%r5,32(%r15)
-	br	%r14
+	BR_EX	%r14
 
 #endif
--- linux-4.4.0.orig/arch/s390/kernel/module.c
+++ linux-4.4.0/arch/s390/kernel/module.c
@@ -31,6 +31,9 @@
 #include <linux/kernel.h>
 #include <linux/moduleloader.h>
 #include <linux/bug.h>
+#include <asm/alternative.h>
+#include <asm/nospec-branch.h>
+#include <asm/facility.h>
 
 #if 0
 #define DEBUGP printk
@@ -159,11 +162,15 @@
 
 	/* Increase core size by size of got & plt and set start
 	   offsets for got and plt. */
-	me->core_size = ALIGN(me->core_size, 4);
-	me->arch.got_offset = me->core_size;
-	me->core_size += me->arch.got_size;
-	me->arch.plt_offset = me->core_size;
-	me->core_size += me->arch.plt_size;
+	me->core_layout.size = ALIGN(me->core_layout.size, 4);
+	me->arch.got_offset = me->core_layout.size;
+	me->core_layout.size += me->arch.got_size;
+	me->arch.plt_offset = me->core_layout.size;
+	if (me->arch.plt_size) {
+		if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable)
+			me->arch.plt_size += PLT_ENTRY_SIZE;
+		me->core_layout.size += me->arch.plt_size;
+	}
 	return 0;
 }
 
@@ -279,7 +286,7 @@
 		if (info->got_initialized == 0) {
 			Elf_Addr *gotent;
 
-			gotent = me->module_core + me->arch.got_offset +
+			gotent = me->core_layout.base + me->arch.got_offset +
 				info->got_offset;
 			*gotent = val;
 			info->got_initialized = 1;
@@ -302,7 +309,7 @@
 			rc = apply_rela_bits(loc, val, 0, 64, 0);
 		else if (r_type == R_390_GOTENT ||
 			 r_type == R_390_GOTPLTENT) {
-			val += (Elf_Addr) me->module_core - loc;
+			val += (Elf_Addr) me->core_layout.base - loc;
 			rc = apply_rela_bits(loc, val, 1, 32, 1);
 		}
 		break;
@@ -315,11 +322,22 @@
 	case R_390_PLTOFF64:	/* 16 bit offset from GOT to PLT. */
 		if (info->plt_initialized == 0) {
 			unsigned int *ip;
-			ip = me->module_core + me->arch.plt_offset +
+			ip = me->core_layout.base + me->arch.plt_offset +
 				info->plt_offset;
-			ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
-			ip[1] = 0x100a0004;
-			ip[2] = 0x07f10000;
+			ip[0] = 0x0d10e310;	/* basr 1,0  */
+			ip[1] = 0x100a0004;	/* lg	1,10(1) */
+			if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
+				unsigned int *ij;
+				ij = me->core_layout.base +
+					me->arch.plt_offset +
+					me->arch.plt_size - PLT_ENTRY_SIZE;
+				ip[2] = 0xa7f40000 +	/* j __jump_r1 */
+					(unsigned int)(u16)
+					(((unsigned long) ij - 8 -
+					  (unsigned long) ip) / 2);
+			} else {
+				ip[2] = 0x07f10000;	/* br %r1 */
+			}
 			ip[3] = (unsigned int) (val >> 32);
 			ip[4] = (unsigned int) val;
 			info->plt_initialized = 1;
@@ -334,7 +352,7 @@
 			       val - loc + 0xffffUL < 0x1ffffeUL) ||
 			      (r_type == R_390_PLT32DBL &&
 			       val - loc + 0xffffffffULL < 0x1fffffffeULL)))
-				val = (Elf_Addr) me->module_core +
+				val = (Elf_Addr) me->core_layout.base +
 					me->arch.plt_offset +
 					info->plt_offset;
 			val += rela->r_addend - loc;
@@ -356,7 +374,7 @@
 	case R_390_GOTOFF32:	/* 32 bit offset to GOT.  */
 	case R_390_GOTOFF64:	/* 64 bit offset to GOT. */
 		val = val + rela->r_addend -
-			((Elf_Addr) me->module_core + me->arch.got_offset);
+			((Elf_Addr) me->core_layout.base + me->arch.got_offset);
 		if (r_type == R_390_GOTOFF16)
 			rc = apply_rela_bits(loc, val, 0, 16, 0);
 		else if (r_type == R_390_GOTOFF32)
@@ -366,7 +384,7 @@
 		break;
 	case R_390_GOTPC:	/* 32 bit PC relative offset to GOT. */
 	case R_390_GOTPCDBL:	/* 32 bit PC rel. off. to GOT shifted by 1. */
-		val = (Elf_Addr) me->module_core + me->arch.got_offset +
+		val = (Elf_Addr) me->core_layout.base + me->arch.got_offset +
 			rela->r_addend - loc;
 		if (r_type == R_390_GOTPC)
 			rc = apply_rela_bits(loc, val, 1, 32, 0);
@@ -424,6 +442,45 @@
 		    const Elf_Shdr *sechdrs,
 		    struct module *me)
 {
+	const Elf_Shdr *s;
+	char *secstrings, *secname;
+	void *aseg;
+
+	if (IS_ENABLED(CONFIG_EXPOLINE) &&
+	    !nospec_disable && me->arch.plt_size) {
+		unsigned int *ij;
+
+		ij = me->core_layout.base + me->arch.plt_offset +
+			me->arch.plt_size - PLT_ENTRY_SIZE;
+		if (test_facility(35)) {
+			ij[0] = 0xc6000000;	/* exrl	%r0,.+10	*/
+			ij[1] = 0x0005a7f4;	/* j	.		*/
+			ij[2] = 0x000007f1;	/* br	%r1		*/
+		} else {
+			ij[0] = 0x44000000 | (unsigned int)
+				offsetof(struct _lowcore, br_r1_trampoline);
+			ij[1] = 0xa7f40000;	/* j	.		*/
+		}
+	}
+
+	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+		aseg = (void *) s->sh_addr;
+		secname = secstrings + s->sh_name;
+
+		if (!strcmp(".altinstructions", secname))
+			/* patch .altinstructions */
+			apply_alternatives(aseg, aseg + s->sh_size);
+
+		if (IS_ENABLED(CONFIG_EXPOLINE) &&
+		    (!strncmp(".s390_indirect", secname, 14)))
+			nospec_revert(aseg, aseg + s->sh_size);
+
+		if (IS_ENABLED(CONFIG_EXPOLINE) &&
+		    (!strncmp(".s390_return", secname, 12)))
+			nospec_revert(aseg, aseg + s->sh_size);
+	}
+
 	jump_label_apply_nops(me);
 	vfree(me->arch.syminfo);
 	me->arch.syminfo = NULL;
--- linux-4.4.0.orig/arch/s390/kernel/nospec-branch.c
+++ linux-4.4.0/arch/s390/kernel/nospec-branch.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/cpu.h>
+#include <asm/facility.h>
+#include <asm/nospec-branch.h>
+
+static int __init nobp_setup_early(char *str)
+{
+	bool enabled;
+	int rc;
+
+	rc = kstrtobool(str, &enabled);
+	if (rc)
+		return rc;
+	if (enabled && test_facility(82)) {
+		/*
+		 * The user explicitely requested nobp=1, enable it and
+		 * disable the expoline support.
+		 */
+		__set_facility(82, S390_lowcore.alt_stfle_fac_list);
+		if (IS_ENABLED(CONFIG_EXPOLINE))
+			nospec_disable = 1;
+	} else {
+		__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+	}
+	return 0;
+}
+early_param("nobp", nobp_setup_early);
+
+static int __init nospec_setup_early(char *str)
+{
+	__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+	return 0;
+}
+early_param("nospec", nospec_setup_early);
+
+static int __init nospec_report(void)
+{
+	if (test_facility(156))
+		pr_info("Spectre V2 mitigation: etokens\n");
+	if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable)
+		pr_info("Spectre V2 mitigation: execute trampolines.\n");
+	if (__test_facility(82, S390_lowcore.alt_stfle_fac_list))
+		pr_info("Spectre V2 mitigation: limited branch prediction.\n");
+	return 0;
+}
+arch_initcall(nospec_report);
+
+#ifdef CONFIG_EXPOLINE
+
+int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);
+
+static int __init nospectre_v2_setup_early(char *str)
+{
+	nospec_disable = 1;
+	return 0;
+}
+early_param("nospectre_v2", nospectre_v2_setup_early);
+
+void __init nospec_auto_detect(void)
+{
+	if (test_facility(156) || cpu_mitigations_off()) {
+		/*
+		 * The machine supports etokens.
+		 * Disable expolines and disable nobp.
+		 */
+		if (IS_ENABLED(CC_USING_EXPOLINE))
+			nospec_disable = 1;
+		__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+	} else if (IS_ENABLED(CC_USING_EXPOLINE)) {
+		/*
+		 * The kernel has been compiled with expolines.
+		 * Keep expolines enabled and disable nobp.
+		 */
+		nospec_disable = 0;
+		__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+	}
+	/*
+	 * If the kernel has not been compiled with expolines the
+	 * nobp setting decides what is done, this depends on the
+	 * CONFIG_KERNEL_NP option and the nobp/nospec parameters.
+	 */
+}
+
+static int __init spectre_v2_setup_early(char *str)
+{
+	if (str && !strncmp(str, "on", 2)) {
+		nospec_disable = 0;
+		__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+	}
+	if (str && !strncmp(str, "off", 3))
+		nospec_disable = 1;
+	if (str && !strncmp(str, "auto", 4))
+		nospec_auto_detect();
+	return 0;
+}
+early_param("spectre_v2", spectre_v2_setup_early);
+
+static void __init_or_module __nospec_revert(s32 *start, s32 *end)
+{
+	enum { BRCL_EXPOLINE, BRASL_EXPOLINE } type;
+	u8 *instr, *thunk, *br;
+	u8 insnbuf[6];
+	s32 *epo;
+
+	/* Second part of the instruction replace is always a nop */
+	for (epo = start; epo < end; epo++) {
+		instr = (u8 *) epo + *epo;
+		if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04)
+			type = BRCL_EXPOLINE;	/* brcl instruction */
+		else if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x05)
+			type = BRASL_EXPOLINE;	/* brasl instruction */
+		else
+			continue;
+		thunk = instr + (*(int *)(instr + 2)) * 2;
+		if (thunk[0] == 0xc6 && thunk[1] == 0x00)
+			/* exrl %r0,<target-br> */
+			br = thunk + (*(int *)(thunk + 2)) * 2;
+		else if (thunk[0] == 0xc0 && (thunk[1] & 0x0f) == 0x00 &&
+			 thunk[6] == 0x44 && thunk[7] == 0x00 &&
+			 (thunk[8] & 0x0f) == 0x00 && thunk[9] == 0x00 &&
+			 (thunk[1] & 0xf0) == (thunk[8] & 0xf0))
+			/* larl %rx,<target br> + ex %r0,0(%rx) */
+			br = thunk + (*(int *)(thunk + 2)) * 2;
+		else
+			continue;
+		/* Check for unconditional branch 0x07f? or 0x47f???? */
+		if ((br[0] & 0xbf) != 0x07 || (br[1] & 0xf0) != 0xf0)
+			continue;
+
+		memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x07, 0x00 }, 4);
+		switch (type) {
+		case BRCL_EXPOLINE:
+			insnbuf[0] = br[0];
+			insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
+			if (br[0] == 0x47) {
+				/* brcl to b, replace with bc + nopr */
+				insnbuf[2] = br[2];
+				insnbuf[3] = br[3];
+			} else {
+				/* brcl to br, replace with bcr + nop */
+			}
+			break;
+		case BRASL_EXPOLINE:
+			insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
+			if (br[0] == 0x47) {
+				/* brasl to b, replace with bas + nopr */
+				insnbuf[0] = 0x4d;
+				insnbuf[2] = br[2];
+				insnbuf[3] = br[3];
+			} else {
+				/* brasl to br, replace with basr + nop */
+				insnbuf[0] = 0x0d;
+			}
+			break;
+		}
+
+		s390_kernel_write(instr, insnbuf, 6);
+	}
+}
+
+void __init_or_module nospec_revert(s32 *start, s32 *end)
+{
+	if (nospec_disable)
+		__nospec_revert(start, end);
+}
+
+extern s32 __nospec_call_start[], __nospec_call_end[];
+extern s32 __nospec_return_start[], __nospec_return_end[];
+void __init nospec_init_branches(void)
+{
+	nospec_revert(__nospec_call_start, __nospec_call_end);
+	nospec_revert(__nospec_return_start, __nospec_return_end);
+}
+
+#endif /* CONFIG_EXPOLINE */
--- linux-4.4.0.orig/arch/s390/kernel/nospec-sysfs.c
+++ linux-4.4.0/arch/s390/kernel/nospec-sysfs.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/device.h>
+#include <linux/cpu.h>
+#include <asm/facility.h>
+#include <asm/nospec-branch.h>
+
+ssize_t cpu_show_spectre_v1(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Mitigation: __user pointer sanitization\n");
+}
+
+ssize_t cpu_show_spectre_v2(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	if (test_facility(156))
+		return sprintf(buf, "Mitigation: etokens\n");
+	if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable)
+		return sprintf(buf, "Mitigation: execute trampolines\n");
+	if (__test_facility(82, S390_lowcore.alt_stfle_fac_list))
+		return sprintf(buf, "Mitigation: limited branch prediction\n");
+	return sprintf(buf, "Vulnerable\n");
+}
--- linux-4.4.0.orig/arch/s390/kernel/perf_cpum_cf.c
+++ linux-4.4.0/arch/s390/kernel/perf_cpum_cf.c
@@ -344,6 +344,8 @@
 		break;
 
 	case PERF_TYPE_HARDWARE:
+		if (is_sampling_event(event))	/* No sampling support */
+			return -ENOENT;
 		ev = attr->config;
 		/* Count user space (problem-state) only */
 		if (!attr->exclude_user && attr->exclude_kernel) {
--- linux-4.4.0.orig/arch/s390/kernel/perf_cpum_sf.c
+++ linux-4.4.0/arch/s390/kernel/perf_cpum_sf.c
@@ -185,7 +185,7 @@
 				   unsigned long num_sdb, gfp_t gfp_flags)
 {
 	int i, rc;
-	unsigned long *new, *tail;
+	unsigned long *new, *tail, *tail_prev = NULL;
 
 	if (!sfb->sdbt || !sfb->tail)
 		return -EINVAL;
@@ -224,6 +224,7 @@
 			sfb->num_sdbt++;
 			/* Link current page to tail of chain */
 			*tail = (unsigned long)(void *) new + 1;
+			tail_prev = tail;
 			tail = new;
 		}
 
@@ -233,10 +234,22 @@
 		 * issue, a new realloc call (if required) might succeed.
 		 */
 		rc = alloc_sample_data_block(tail, gfp_flags);
-		if (rc)
+		if (rc) {
+			/* Undo last SDBT. An SDBT with no SDB at its first
+			 * entry but with an SDBT entry instead can not be
+			 * handled by the interrupt handler code.
+			 * Avoid this situation.
+			 */
+			if (tail_prev) {
+				sfb->num_sdbt--;
+				free_page((unsigned long) new);
+				tail = tail_prev;
+			}
 			break;
+		}
 		sfb->num_sdb++;
 		tail++;
+		tail_prev = new = NULL;	/* Allocated at least one SBD */
 	}
 
 	/* Link sampling buffer to its origin */
@@ -744,6 +757,10 @@
 	 */
 	rate = 0;
 	if (attr->freq) {
+		if (!attr->sample_freq) {
+			err = -EINVAL;
+			goto out;
+		}
 		rate = freq_to_sample_rate(&si, attr->sample_freq);
 		rate = hw_limit_rate(&si, rate);
 		attr->freq = 0;
@@ -1277,18 +1294,28 @@
 		 */
 		if (flush_all && done)
 			break;
-
-		/* If an event overflow happened, discard samples by
-		 * processing any remaining sample-data-blocks.
-		 */
-		if (event_overflow)
-			flush_all = 1;
 	}
 
 	/* Account sample overflows in the event hardware structure */
 	if (sampl_overflow)
 		OVERFLOW_REG(hwc) = DIV_ROUND_UP(OVERFLOW_REG(hwc) +
 						 sampl_overflow, 1 + num_sdb);
+
+	/* Perf_event_overflow() and perf_event_account_interrupt() limit
+	 * the interrupt rate to an upper limit. Roughly 1000 samples per
+	 * task tick.
+	 * Hitting this limit results in a large number
+	 * of throttled REF_REPORT_THROTTLE entries and the samples
+	 * are dropped.
+	 * Slightly increase the interval to avoid hitting this limit.
+	 */
+	if (event_overflow) {
+		SAMPL_RATE(hwc) += DIV_ROUND_UP(SAMPL_RATE(hwc), 10);
+		debug_sprintf_event(sfdbg, 1, "%s: rate adjustment %ld\n",
+				    __func__,
+				    DIV_ROUND_UP(SAMPL_RATE(hwc), 10));
+	}
+
 	if (sampl_overflow || event_overflow)
 		debug_sprintf_event(sfdbg, 4, "hw_perf_event_update: "
 				    "overflow stats: sample=%llu event=%llu\n",
@@ -1612,14 +1639,17 @@
 	}
 
 	sfdbg = debug_register(KMSG_COMPONENT, 2, 1, 80);
-	if (!sfdbg)
+	if (!sfdbg) {
 		pr_err("Registering for s390dbf failed\n");
+		return -ENOMEM;
+	}
 	debug_register_view(sfdbg, &debug_sprintf_view);
 
 	err = register_external_irq(EXT_IRQ_MEASURE_ALERT,
 				    cpumf_measurement_alert);
 	if (err) {
 		pr_cpumsf_err(RS_INIT_FAILURE_ALRT);
+		debug_unregister(sfdbg);
 		goto out;
 	}
 
@@ -1628,6 +1658,7 @@
 		pr_cpumsf_err(RS_INIT_FAILURE_PERF);
 		unregister_external_irq(EXT_IRQ_MEASURE_ALERT,
 					cpumf_measurement_alert);
+		debug_unregister(sfdbg);
 		goto out;
 	}
 	perf_cpu_notifier(cpumf_pmu_notifier);
@@ -1635,4 +1666,4 @@
 	return err;
 }
 arch_initcall(init_cpum_sampling_pmu);
-core_param(cpum_sfb_size, CPUM_SF_MAX_SDB, sfb_size, 0640);
+core_param(cpum_sfb_size, CPUM_SF_MAX_SDB, sfb_size, 0644);
--- linux-4.4.0.orig/arch/s390/kernel/process.c
+++ linux-4.4.0/arch/s390/kernel/process.c
@@ -72,7 +72,6 @@
  */
 void exit_thread(void)
 {
-	exit_thread_runtime_instr();
 }
 
 void flush_thread(void)
@@ -87,6 +86,7 @@
 {
 	/* Free either the floating-point or the vector register save area */
 	kfree(tsk->thread.fpu.regs);
+	runtime_instr_release(tsk);
 }
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
@@ -137,6 +137,7 @@
 	memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
 	memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
 	clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
+	p->thread.per_flags = 0;
 	/* Initialize per thread user and system timer values */
 	ti = task_thread_info(p);
 	ti->user_timer = 0;
--- linux-4.4.0.orig/arch/s390/kernel/processor.c
+++ linux-4.4.0/arch/s390/kernel/processor.c
@@ -6,6 +6,7 @@
 #define KMSG_COMPONENT "cpu"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/bitops.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
@@ -13,6 +14,7 @@
 #include <linux/cpu.h>
 #include <asm/diag.h>
 #include <asm/elf.h>
+#include <asm/facility.h>
 #include <asm/lowcore.h>
 #include <asm/param.h>
 #include <asm/smp.h>
@@ -52,6 +54,18 @@
 }
 EXPORT_SYMBOL(cpu_have_feature);
 
+static void show_facilities(struct seq_file *m)
+{
+	unsigned int bit;
+	long *facilities;
+
+	facilities = (long *)&S390_lowcore.stfle_fac_list;
+	seq_puts(m, "facilities      :");
+	for_each_set_bit_inv(bit, facilities, MAX_FACILITY_BIT)
+		seq_printf(m, " %d", bit);
+	seq_putc(m, '\n');
+}
+
 /*
  * show_cpuinfo - Get information on one CPU for use by procfs.
  */
@@ -76,6 +90,7 @@
 			if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
 				seq_printf(m, "%s ", hwcap_str[i]);
 		seq_puts(m, "\n");
+		show_facilities(m);
 		show_cacheinfo(m);
 	}
 	get_online_cpus();
@@ -113,3 +128,20 @@
 	.show	= show_cpuinfo,
 };
 
+int s390_isolate_bp(void)
+{
+	if (!test_facility(82))
+		return -EOPNOTSUPP;
+	set_thread_flag(TIF_ISOLATE_BP);
+	return 0;
+}
+EXPORT_SYMBOL(s390_isolate_bp);
+
+int s390_isolate_bp_guest(void)
+{
+	if (!test_facility(82))
+		return -EOPNOTSUPP;
+	set_thread_flag(TIF_ISOLATE_BP_GUEST);
+	return 0;
+}
+EXPORT_SYMBOL(s390_isolate_bp_guest);
--- linux-4.4.0.orig/arch/s390/kernel/ptrace.c
+++ linux-4.4.0/arch/s390/kernel/ptrace.c
@@ -963,6 +963,11 @@
 	if (target == current)
 		save_fpu_regs();
 
+	if (MACHINE_HAS_VX)
+		convert_vx_to_fp(fprs, target->thread.fpu.vxrs);
+	else
+		memcpy(&fprs, target->thread.fpu.fprs, sizeof(fprs));
+
 	/* If setting FPC, must validate it first. */
 	if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) {
 		u32 ufpc[2] = { target->thread.fpu.fpc, 0 };
@@ -1067,6 +1072,9 @@
 	if (target == current)
 		save_fpu_regs();
 
+	for (i = 0; i < __NUM_VXRS_LOW; i++)
+		vxrs[i] = *((__u64 *)(target->thread.fpu.vxrs + i) + 1);
+
 	rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
 	if (rc == 0)
 		for (i = 0; i < __NUM_VXRS_LOW; i++)
--- linux-4.4.0.orig/arch/s390/kernel/reipl.S
+++ linux-4.4.0/arch/s390/kernel/reipl.S
@@ -6,8 +6,11 @@
 
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
+#include <asm/nospec-insn.h>
 #include <asm/sigp.h>
 
+	GEN_BR_THUNK %r14
+
 #
 # store_status
 #
@@ -62,7 +65,7 @@
 	st	%r3,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 4(%r1)
 	larl	%r2,store_status
 	stg	%r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 8(%r1)
-	br	%r14
+	BR_EX	%r14
 
 	.section .bss
 	.align	8
--- linux-4.4.0.orig/arch/s390/kernel/runtime_instr.c
+++ linux-4.4.0/arch/s390/kernel/runtime_instr.c
@@ -18,11 +18,24 @@
 /* empty control block to disable RI by loading it */
 struct runtime_instr_cb runtime_instr_empty_cb;
 
+void runtime_instr_release(struct task_struct *tsk)
+{
+	kfree(tsk->thread.ri_cb);
+}
+
 static void disable_runtime_instr(void)
 {
-	struct pt_regs *regs = task_pt_regs(current);
+	struct task_struct *task = current;
+	struct pt_regs *regs;
 
+	if (!task->thread.ri_cb)
+		return;
+	regs = task_pt_regs(task);
+	preempt_disable();
 	load_runtime_instr_cb(&runtime_instr_empty_cb);
+	kfree(task->thread.ri_cb);
+	task->thread.ri_cb = NULL;
+	preempt_enable();
 
 	/*
 	 * Make sure the RI bit is deleted from the PSW. If the user did not
@@ -43,17 +56,6 @@
 	cb->valid = 1;
 }
 
-void exit_thread_runtime_instr(void)
-{
-	struct task_struct *task = current;
-
-	if (!task->thread.ri_cb)
-		return;
-	disable_runtime_instr();
-	kfree(task->thread.ri_cb);
-	task->thread.ri_cb = NULL;
-}
-
 SYSCALL_DEFINE1(s390_runtime_instr, int, command)
 {
 	struct runtime_instr_cb *cb;
@@ -62,9 +64,7 @@
 		return -EOPNOTSUPP;
 
 	if (command == S390_RUNTIME_INSTR_STOP) {
-		preempt_disable();
-		exit_thread_runtime_instr();
-		preempt_enable();
+		disable_runtime_instr();
 		return 0;
 	}
 
--- linux-4.4.0.orig/arch/s390/kernel/setup.c
+++ linux-4.4.0/arch/s390/kernel/setup.c
@@ -63,6 +63,8 @@
 #include <asm/sclp.h>
 #include <asm/sysinfo.h>
 #include <asm/numa.h>
+#include <asm/alternative.h>
+#include <asm/nospec-branch.h>
 #include "entry.h"
 
 /*
@@ -329,10 +331,13 @@
 		+ PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
 	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
 	lc->thread_info = (unsigned long) &init_thread_union;
+	lc->lpp = LPP_MAGIC;
 	lc->machine_flags = S390_lowcore.machine_flags;
 	lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
 	memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
-	       MAX_FACILITY_BIT/8);
+	       sizeof(lc->stfle_fac_list));
+	memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
+	       sizeof(lc->alt_stfle_fac_list));
 	if (MACHINE_HAS_VX)
 		lc->vector_save_area_addr =
 			(unsigned long) &lc->vector_save_area;
@@ -369,6 +374,7 @@
 #ifdef CONFIG_SMP
 	lc->spinlock_lockval = arch_spin_lockval(0);
 #endif
+	lc->br_r1_trampoline = 0x07f1;	/* br %r1 */
 
 	set_prefix((u32)(unsigned long) lc);
 	lowcore_ptr[0] = lc;
@@ -507,7 +513,7 @@
 /*
  * Make sure that the area behind memory_end is protected
  */
-static void reserve_memory_end(void)
+static void __init reserve_memory_end(void)
 {
 #ifdef CONFIG_CRASH_DUMP
 	if (ipl_info.type == IPL_TYPE_FCP_DUMP &&
@@ -525,7 +531,7 @@
 /*
  * Make sure that oldmem, where the dump is stored, is protected
  */
-static void reserve_oldmem(void)
+static void __init reserve_oldmem(void)
 {
 #ifdef CONFIG_CRASH_DUMP
 	if (OLDMEM_BASE)
@@ -537,7 +543,7 @@
 /*
  * Make sure that oldmem, where the dump is stored, is protected
  */
-static void remove_oldmem(void)
+static void __init remove_oldmem(void)
 {
 #ifdef CONFIG_CRASH_DUMP
 	if (OLDMEM_BASE)
@@ -804,10 +810,10 @@
 {
 	struct sysinfo_3_2_2 *vmms;
 
-	vmms = (struct sysinfo_3_2_2 *) alloc_page(GFP_KERNEL);
-	if (vmms && stsi(vmms, 3, 2, 2) == 0 && vmms->count)
-		add_device_randomness(&vmms, vmms->count);
-	free_page((unsigned long) vmms);
+	vmms = (struct sysinfo_3_2_2 *) memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+	if (stsi(vmms, 3, 2, 2) == 0 && vmms->count)
+		add_device_randomness(&vmms->vm, sizeof(vmms->vm[0]) * vmms->count);
+	memblock_free((unsigned long) vmms, PAGE_SIZE);
 }
 
 /*
@@ -827,6 +833,8 @@
 		pr_info("Linux is running under KVM in 64-bit mode\n");
 	else if (MACHINE_IS_LPAR)
 		pr_info("Linux is running natively in 64-bit mode\n");
+	else
+		pr_info("Linux is running as a guest in 64-bit mode\n");
 
 	/* Have one command line that is parsed and saved in /proc/cmdline */
 	/* boot_command_line has been already set up in early.c */
@@ -840,6 +848,9 @@
 	init_mm.end_data = (unsigned long) &_edata;
 	init_mm.brk = (unsigned long) &_end;
 
+	if (IS_ENABLED(CONFIG_EXPOLINE_AUTO))
+		nospec_auto_detect();
+
 	parse_early_param();
 	os_info_init();
 	setup_ipl();
@@ -892,6 +903,10 @@
 	conmode_default();
 	set_preferred_console();
 
+	apply_alternative_instructions();
+	if (IS_ENABLED(CONFIG_EXPOLINE))
+		nospec_init_branches();
+
 	/* Setup zfcpdump support */
 	setup_zfcpdump();
 
--- linux-4.4.0.orig/arch/s390/kernel/smp.c
+++ linux-4.4.0/arch/s390/kernel/smp.c
@@ -200,6 +200,7 @@
 	lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET;
 	lc->cpu_nr = cpu;
 	lc->spinlock_lockval = arch_spin_lockval(cpu);
+	lc->br_r1_trampoline = 0x07f1;	/* br %r1 */
 	if (MACHINE_HAS_VX)
 		lc->vector_save_area_addr =
 			(unsigned long) &lc->vector_save_area;
@@ -250,7 +251,9 @@
 	__ctl_store(lc->cregs_save_area, 0, 15);
 	save_access_regs((unsigned int *) lc->access_regs_save_area);
 	memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
-	       MAX_FACILITY_BIT/8);
+	       sizeof(lc->stfle_fac_list));
+	memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
+	       sizeof(lc->alt_stfle_fac_list));
 }
 
 static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
@@ -299,6 +302,7 @@
 	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);
+	__bpon();
 	asm volatile(
 		"0:	sigp	0,%0,%2	# sigp restart to target cpu\n"
 		"	brc	2,0b	# busy, try again\n"
@@ -356,9 +360,13 @@
  */
 void smp_call_ipl_cpu(void (*func)(void *), void *data)
 {
+	struct _lowcore *lc = pcpu_devices->lowcore;
+
+	if (pcpu_devices[0].address == stap())
+		lc = &S390_lowcore;
+
 	pcpu_delegate(&pcpu_devices[0], func, data,
-		      pcpu_devices->lowcore->panic_stack -
-		      PANIC_FRAME_OFFSET + PAGE_SIZE);
+		      lc->panic_stack - PANIC_FRAME_OFFSET + PAGE_SIZE);
 }
 
 int smp_find_processor_id(u16 address)
@@ -694,39 +702,67 @@
 
 static int smp_add_present_cpu(int cpu);
 
-static int __smp_rescan_cpus(struct sclp_core_info *info, int sysfs_add)
+static int smp_add_core(struct sclp_core_entry *core, cpumask_t *avail,
+			bool configured, bool early)
 {
 	struct pcpu *pcpu;
-	cpumask_t avail;
-	int cpu, nr, i, j;
+	int cpu, nr, i;
 	u16 address;
 
 	nr = 0;
-	cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
-	cpu = cpumask_first(&avail);
-	for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) {
-		if (sclp.has_core_type && info->core[i].type != boot_core_type)
+	if (sclp.has_core_type && core->type != boot_core_type)
+		return nr;
+	cpu = cpumask_first(avail);
+	address = core->core_id << smp_cpu_mt_shift;
+	for (i = 0; (i <= smp_cpu_mtid) && (cpu < nr_cpu_ids); i++) {
+		if (pcpu_find_address(cpu_present_mask, address + i))
 			continue;
-		address = info->core[i].core_id << smp_cpu_mt_shift;
-		for (j = 0; j <= smp_cpu_mtid; j++) {
-			if (pcpu_find_address(cpu_present_mask, address + j))
-				continue;
-			pcpu = pcpu_devices + cpu;
-			pcpu->address = address + j;
-			pcpu->state =
-				(cpu >= info->configured*(smp_cpu_mtid + 1)) ?
-				CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
-			smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
-			set_cpu_present(cpu, true);
-			if (sysfs_add && smp_add_present_cpu(cpu) != 0)
-				set_cpu_present(cpu, false);
-			else
-				nr++;
-			cpu = cpumask_next(cpu, &avail);
-			if (cpu >= nr_cpu_ids)
+		pcpu = pcpu_devices + cpu;
+		pcpu->address = address + i;
+		if (configured)
+			pcpu->state = CPU_STATE_CONFIGURED;
+		else
+			pcpu->state = CPU_STATE_STANDBY;
+		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+		set_cpu_present(cpu, true);
+		if (!early && smp_add_present_cpu(cpu) != 0)
+			set_cpu_present(cpu, false);
+		else
+			nr++;
+		cpumask_clear_cpu(cpu, avail);
+		cpu = cpumask_next(cpu, avail);
+	}
+	return nr;
+}
+
+static int __smp_rescan_cpus(struct sclp_core_info *info, bool early)
+{
+	struct sclp_core_entry *core;
+	static cpumask_t avail;
+	bool configured;
+	u16 core_id;
+	int nr, i;
+
+	nr = 0;
+	cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
+	/*
+	 * Add IPL core first (which got logical CPU number 0) to make sure
+	 * that all SMT threads get subsequent logical CPU numbers.
+	 */
+	if (early) {
+		core_id = pcpu_devices[0].address >> smp_cpu_mt_shift;
+		for (i = 0; i < info->configured; i++) {
+			core = &info->core[i];
+			if (core->core_id == core_id) {
+				nr += smp_add_core(core, &avail, true, early);
 				break;
+			}
 		}
 	}
+	for (i = 0; i < info->combined; i++) {
+		configured = i < info->configured;
+		nr += smp_add_core(&info->core[i], &avail, configured, early);
+	}
 	return nr;
 }
 
@@ -774,7 +810,7 @@
 
 	/* Add CPUs present at boot */
 	get_online_cpus();
-	__smp_rescan_cpus(info, 0);
+	__smp_rescan_cpus(info, true);
 	put_online_cpus();
 	kfree(info);
 }
@@ -888,6 +924,7 @@
 void __noreturn cpu_die(void)
 {
 	idle_task_exit();
+	__bpon();
 	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
 	for (;;) ;
 }
@@ -1131,7 +1168,7 @@
 		return -ENOMEM;
 	get_online_cpus();
 	mutex_lock(&smp_cpu_state_mutex);
-	nr = __smp_rescan_cpus(info, 1);
+	nr = __smp_rescan_cpus(info, false);
 	mutex_unlock(&smp_cpu_state_mutex);
 	put_online_cpus();
 	kfree(info);
@@ -1147,7 +1184,11 @@
 {
 	int rc;
 
+	rc = lock_device_hotplug_sysfs();
+	if (rc)
+		return rc;
 	rc = smp_rescan_cpus();
+	unlock_device_hotplug();
 	return rc ? rc : count;
 }
 static DEVICE_ATTR(rescan, 0200, NULL, rescan_store);
--- linux-4.4.0.orig/arch/s390/kernel/swsusp.S
+++ linux-4.4.0/arch/s390/kernel/swsusp.S
@@ -12,6 +12,7 @@
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
+#include <asm/nospec-insn.h>
 #include <asm/sigp.h>
 
 /*
@@ -23,6 +24,8 @@
  * (see below) in the resume process.
  * This function runs with disabled interrupts.
  */
+	GEN_BR_THUNK %r14
+
 	.section .text
 ENTRY(swsusp_arch_suspend)
 	stmg	%r6,%r15,__SF_GPRS(%r15)
@@ -102,7 +105,7 @@
 	spx	0x318(%r1)
 	lmg	%r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
 	lghi	%r2,0
-	br	%r14
+	BR_EX	%r14
 
 /*
  * Restore saved memory image to correct place and restore register context.
@@ -196,11 +199,10 @@
 	larl	%r15,init_thread_union
 	ahi	%r15,1<<(PAGE_SHIFT+THREAD_ORDER)
 	larl	%r2,.Lpanic_string
-	larl	%r3,_sclp_print_early
 	lghi	%r1,0
 	sam31
 	sigp	%r1,%r0,SIGP_SET_ARCHITECTURE
-	basr	%r14,%r3
+	brasl	%r14,_sclp_print_early
 	larl	%r3,.Ldisabled_wait_31
 	lpsw	0(%r3)
 4:
@@ -266,7 +268,7 @@
 	/* Return 0 */
 	lmg	%r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
 	lghi	%r2,0
-	br	%r14
+	BR_EX	%r14
 
 	.section .data..nosave,"aw",@progbits
 	.align	8
--- linux-4.4.0.orig/arch/s390/kernel/syscalls.S
+++ linux-4.4.0/arch/s390/kernel/syscalls.S
@@ -369,10 +369,10 @@
 SYSCALL(sys_sendmmsg,compat_sys_sendmmsg)
 SYSCALL(sys_socket,sys_socket)
 SYSCALL(sys_socketpair,compat_sys_socketpair)		/* 360 */
-SYSCALL(sys_bind,sys_bind)
-SYSCALL(sys_connect,sys_connect)
+SYSCALL(sys_bind,compat_sys_bind)
+SYSCALL(sys_connect,compat_sys_connect)
 SYSCALL(sys_listen,sys_listen)
-SYSCALL(sys_accept4,sys_accept4)
+SYSCALL(sys_accept4,compat_sys_accept4)
 SYSCALL(sys_getsockopt,compat_sys_getsockopt)		/* 365 */
 SYSCALL(sys_setsockopt,compat_sys_setsockopt)
 SYSCALL(sys_getsockname,compat_sys_getsockname)
--- linux-4.4.0.orig/arch/s390/kernel/time.c
+++ linux-4.4.0/arch/s390/kernel/time.c
@@ -39,6 +39,7 @@
 #include <linux/gfp.h>
 #include <linux/kprobes.h>
 #include <asm/uaccess.h>
+#include <asm/facility.h>
 #include <asm/delay.h>
 #include <asm/div64.h>
 #include <asm/vdso.h>
@@ -61,6 +62,25 @@
 ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier);
 EXPORT_SYMBOL(s390_epoch_delta_notifier);
 
+unsigned char ptff_function_mask[16];
+unsigned long lpar_offset;
+
+/*
+ * Get time offsets with PTFF
+ */
+void __init ptff_init(void)
+{
+	struct ptff_qto qto;
+
+	if (!test_facility(28))
+		return;
+	ptff(&ptff_function_mask, sizeof(ptff_function_mask), PTFF_QAF);
+
+	/* get LPAR offset */
+	if (ptff_query(PTFF_QTO) && ptff(&qto, sizeof(qto), PTFF_QTO) == 0)
+		lpar_offset = qto.tod_epoch_difference;
+}
+
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
@@ -337,20 +357,20 @@
 #define CLOCK_SYNC_STP		3
 
 /*
- * The synchronous get_clock function. It will write the current clock
- * value to the clock pointer and return 0 if the clock is in sync with
- * the external time source. If the clock mode is local it will return
- * -EOPNOTSUPP and -EAGAIN if the clock is not in sync with the external
- * reference.
+ * The get_clock function for the physical clock. It will get the current
+ * TOD clock, subtract the LPAR offset and write the result to *clock.
+ * The function returns 0 if the clock is in sync with the external time
+ * source. If the clock mode is local it will return -EOPNOTSUPP and
+ * -EAGAIN if the clock is not in sync with the external reference.
  */
-int get_sync_clock(unsigned long long *clock)
+int get_phys_clock(unsigned long long *clock)
 {
 	atomic_t *sw_ptr;
 	unsigned int sw0, sw1;
 
 	sw_ptr = &get_cpu_var(clock_sync_word);
 	sw0 = atomic_read(sw_ptr);
-	*clock = get_tod_clock();
+	*clock = get_tod_clock() - lpar_offset;
 	sw1 = atomic_read(sw_ptr);
 	put_cpu_var(clock_sync_word);
 	if (sw0 == sw1 && (sw0 & 0x80000000U))
@@ -364,7 +384,7 @@
 		return -EACCES;
 	return -EAGAIN;
 }
-EXPORT_SYMBOL(get_sync_clock);
+EXPORT_SYMBOL(get_phys_clock);
 
 /*
  * Make get_sync_clock return -EAGAIN.
@@ -759,6 +779,7 @@
 	unsigned long long clock, old_clock, clock_delta, delay, delta;
 	struct clock_sync_data *etr_sync;
 	struct etr_aib *sync_port, *aib;
+	struct ptff_qto qto;
 	int port;
 	int rc;
 
@@ -805,6 +826,10 @@
 			etr_sync->in_sync = -EAGAIN;
 			rc = -EAGAIN;
 		} else {
+			if (ptff_query(PTFF_QTO) &&
+			    ptff(&qto, sizeof(qto), PTFF_QTO) == 0)
+				/* Update LPAR offset */
+				lpar_offset = qto.tod_epoch_difference;
 			etr_sync->in_sync = 1;
 			rc = 0;
 		}
@@ -1460,7 +1485,7 @@
 	int rc;
 
 	stp_page = (void *) get_zeroed_page(GFP_ATOMIC);
-	rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
+	rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000, NULL);
 	if (rc == 0)
 		set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags);
 	else if (stp_online) {
@@ -1539,6 +1564,7 @@
 	static int first;
 	unsigned long long old_clock, delta, new_clock, clock_delta;
 	struct clock_sync_data *stp_sync;
+	struct ptff_qto qto;
 	int rc;
 
 	stp_sync = data;
@@ -1560,11 +1586,14 @@
 	    stp_info.todoff[2] || stp_info.todoff[3] ||
 	    stp_info.tmd != 2) {
 		old_clock = get_tod_clock();
-		rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0);
+		rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0, &clock_delta);
 		if (rc == 0) {
-			new_clock = get_tod_clock();
+			new_clock = old_clock + clock_delta;
 			delta = adjust_time(old_clock, new_clock, 0);
-			clock_delta = new_clock - old_clock;
+			if (ptff_query(PTFF_QTO) &&
+			    ptff(&qto, sizeof(qto), PTFF_QTO) == 0)
+				/* Update LPAR offset */
+				lpar_offset = qto.tod_epoch_difference;
 			atomic_notifier_call_chain(&s390_epoch_delta_notifier,
 						   0, &clock_delta);
 			fixup_clock_comparator(delta);
@@ -1596,12 +1625,12 @@
 	mutex_lock(&stp_work_mutex);
 
 	if (!stp_online) {
-		chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
+		chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000, NULL);
 		del_timer_sync(&stp_timer);
 		goto out_unlock;
 	}
 
-	rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0);
+	rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0, NULL);
 	if (rc)
 		goto out_unlock;
 
--- linux-4.4.0.orig/arch/s390/kernel/topology.c
+++ linux-4.4.0/arch/s390/kernel/topology.c
@@ -291,7 +291,8 @@
 		topology_update_polarization_simple();
 	for_each_online_cpu(cpu) {
 		dev = get_cpu_device(cpu);
-		kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+		if (dev)
+			kobject_uevent(&dev->kobj, KOBJ_CHANGE);
 	}
 	return rc;
 }
--- linux-4.4.0.orig/arch/s390/kernel/uprobes.c
+++ linux-4.4.0/arch/s390/kernel/uprobes.c
@@ -147,6 +147,15 @@
 	return orig;
 }
 
+bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
+			     struct pt_regs *regs)
+{
+	if (ctx == RP_CHECK_CHAIN_CALL)
+		return user_stack_pointer(regs) <= ret->stack;
+	else
+		return user_stack_pointer(regs) < ret->stack;
+}
+
 /* Instruction Emulation */
 
 static void adjust_psw_addr(psw_t *psw, unsigned long len)
--- linux-4.4.0.orig/arch/s390/kernel/vdso32/Makefile
+++ linux-4.4.0/arch/s390/kernel/vdso32/Makefile
@@ -29,7 +29,7 @@
 $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
 
 # link rule for the .so file, .lds has to be first
-$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32)
+$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) FORCE
 	$(call if_changed,vdso32ld)
 
 # strip rule for the .so file
@@ -38,12 +38,12 @@
 	$(call if_changed,objcopy)
 
 # assembly rules for the .S files
-$(obj-vdso32): %.o: %.S
+$(obj-vdso32): %.o: %.S FORCE
 	$(call if_changed_dep,vdso32as)
 
 # actual build commands
 quiet_cmd_vdso32ld = VDSO32L $@
-      cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@
+      cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $(filter %.lds %.o,$^) -o $@
 quiet_cmd_vdso32as = VDSO32A $@
       cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $<
 
--- linux-4.4.0.orig/arch/s390/kernel/vdso64/Makefile
+++ linux-4.4.0/arch/s390/kernel/vdso64/Makefile
@@ -29,7 +29,7 @@
 $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so
 
 # link rule for the .so file, .lds has to be first
-$(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64)
+$(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64) FORCE
 	$(call if_changed,vdso64ld)
 
 # strip rule for the .so file
@@ -38,12 +38,12 @@
 	$(call if_changed,objcopy)
 
 # assembly rules for the .S files
-$(obj-vdso64): %.o: %.S
+$(obj-vdso64): %.o: %.S FORCE
 	$(call if_changed_dep,vdso64as)
 
 # actual build commands
 quiet_cmd_vdso64ld = VDSO64L $@
-      cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@
+      cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $(filter %.lds %.o,$^) -o $@
 quiet_cmd_vdso64as = VDSO64A $@
       cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $<
 
--- linux-4.4.0.orig/arch/s390/kernel/vmlinux.lds.S
+++ linux-4.4.0/arch/s390/kernel/vmlinux.lds.S
@@ -21,8 +21,14 @@
 {
 	. = 0x00000000;
 	.text : {
-	_text = .;		/* Text and read-only data */
+		/* Text and read-only data */
 		HEAD_TEXT
+		/*
+		 * E.g. perf doesn't like symbols starting at address zero,
+		 * therefore skip the initial PSW and channel program located
+		 * at address zero and let _text start at 0x200.
+		 */
+	_text = 0x200;
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
@@ -72,6 +78,43 @@
 		EXIT_DATA
 	}
 
+	/*
+	 * struct alt_inst entries. From the header (alternative.h):
+	 * "Alternative instructions for different CPU types or capabilities"
+	 * Think locking instructions on spinlocks.
+	 * Note, that it is a part of __init region.
+	 */
+	. = ALIGN(8);
+	.altinstructions : {
+		__alt_instructions = .;
+		*(.altinstructions)
+		__alt_instructions_end = .;
+	}
+
+	/*
+	 * And here are the replacement instructions. The linker sticks
+	 * them as binary blobs. The .altinstructions has enough data to
+	 * get the address and the length of them to patch the kernel safely.
+	 * Note, that it is a part of __init region.
+	 */
+	.altinstr_replacement : {
+		*(.altinstr_replacement)
+	}
+
+	/*
+	 * Table with the patch locations to undo expolines
+	*/
+	.nospec_call_table : {
+		__nospec_call_start = . ;
+		*(.s390_indirect*)
+		__nospec_call_end = . ;
+	}
+	.nospec_return_table : {
+		__nospec_return_start = . ;
+		*(.s390_return*)
+		__nospec_return_end = . ;
+	}
+
 	/* early.c uses stsi, which requires page aligned data. */
 	. = ALIGN(PAGE_SIZE);
 	INIT_DATA_SECTION(0x100)
--- linux-4.4.0.orig/arch/s390/kvm/interrupt.c
+++ linux-4.4.0/arch/s390/kvm/interrupt.c
@@ -1487,6 +1487,16 @@
 	case KVM_S390_MCHK:
 		irq->u.mchk.mcic = s390int->parm64;
 		break;
+	case KVM_S390_INT_PFAULT_INIT:
+		irq->u.ext.ext_params = s390int->parm;
+		irq->u.ext.ext_params2 = s390int->parm64;
+		break;
+	case KVM_S390_RESTART:
+	case KVM_S390_INT_CLOCK_COMP:
+	case KVM_S390_INT_CPU_TIMER:
+		break;
+	default:
+		return -EINVAL;
 	}
 	return 0;
 }
--- linux-4.4.0.orig/arch/s390/kvm/kvm-s390.c
+++ linux-4.4.0/arch/s390/kvm/kvm-s390.c
@@ -118,8 +118,8 @@
 
 /* upper facilities limit for kvm */
 unsigned long kvm_s390_fac_list_mask[] = {
-	0xffe6fffbfcfdfc40UL,
-	0x005e800000000000UL,
+	0xffe6ffffffffffffUL,
+	0x005effffffffffffUL,
 };
 
 unsigned long kvm_s390_fac_list_mask_size(void)
@@ -185,17 +185,28 @@
 
 int kvm_arch_init(void *opaque)
 {
+	int rc;
+
 	kvm_s390_dbf = debug_register("kvm-trace", 32, 1, 7 * sizeof(long));
 	if (!kvm_s390_dbf)
 		return -ENOMEM;
 
 	if (debug_register_view(kvm_s390_dbf, &debug_sprintf_view)) {
-		debug_unregister(kvm_s390_dbf);
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto out_debug_unreg;
 	}
 
 	/* Register floating interrupt controller interface. */
-	return kvm_register_device_ops(&kvm_flic_ops, KVM_DEV_TYPE_FLIC);
+	rc = kvm_register_device_ops(&kvm_flic_ops, KVM_DEV_TYPE_FLIC);
+	if (rc) {
+		pr_err("Failed to register FLIC rc=%d\n", rc);
+		goto out_debug_unreg;
+	}
+	return 0;
+
+out_debug_unreg:
+	debug_unregister(kvm_s390_dbf);
+	return rc;
 }
 
 void kvm_arch_exit(void)
@@ -257,6 +268,9 @@
 	case KVM_CAP_S390_VECTOR_REGISTERS:
 		r = MACHINE_HAS_VX;
 		break;
+	case KVM_CAP_S390_BPB:
+		r = test_facility(82);
+		break;
 	default:
 		r = 0;
 	}
@@ -295,6 +309,9 @@
 	struct kvm_memory_slot *memslot;
 	int is_dirty = 0;
 
+	if (kvm_is_ucontrol(kvm))
+		return -EINVAL;
+
 	mutex_lock(&kvm->slots_lock);
 
 	r = -EINVAL;
@@ -1101,12 +1118,12 @@
 	kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
 	if (!kvm->arch.sca)
 		goto out_err;
-	spin_lock(&kvm_lock);
+	mutex_lock(&kvm_lock);
 	sca_offset += 16;
 	if (sca_offset + sizeof(struct sca_block) > PAGE_SIZE)
 		sca_offset = 0;
 	kvm->arch.sca = (struct sca_block *) ((char *) kvm->arch.sca + sca_offset);
-	spin_unlock(&kvm_lock);
+	mutex_unlock(&kvm_lock);
 
 	sprintf(debug_name, "kvm-%u", current->pid);
 
@@ -1261,6 +1278,8 @@
 				    KVM_SYNC_PFAULT;
 	if (test_kvm_facility(vcpu->kvm, 129))
 		vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS;
+	if (test_kvm_facility(vcpu->kvm, 82))
+		vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC;
 
 	if (kvm_is_ucontrol(vcpu->kvm))
 		return __kvm_ucontrol_vcpu_init(vcpu);
@@ -1268,44 +1287,18 @@
 	return 0;
 }
 
-/*
- * Backs up the current FP/VX register save area on a particular
- * destination.  Used to switch between different register save
- * areas.
- */
-static inline void save_fpu_to(struct fpu *dst)
-{
-	dst->fpc = current->thread.fpu.fpc;
-	dst->regs = current->thread.fpu.regs;
-}
-
-/*
- * Switches the FP/VX register save area from which to lazy
- * restore register contents.
- */
-static inline void load_fpu_from(struct fpu *from)
-{
-	current->thread.fpu.fpc = from->fpc;
-	current->thread.fpu.regs = from->regs;
-}
-
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	/* Save host register state */
 	save_fpu_regs();
-	save_fpu_to(&vcpu->arch.host_fpregs);
-
-	if (test_kvm_facility(vcpu->kvm, 129)) {
-		current->thread.fpu.fpc = vcpu->run->s.regs.fpc;
-		/*
-		 * Use the register save area in the SIE-control block
-		 * for register restore and save in kvm_arch_vcpu_put()
-		 */
-		current->thread.fpu.vxrs =
-			(__vector128 *)&vcpu->run->s.regs.vrs;
-	} else
-		load_fpu_from(&vcpu->arch.guest_fpregs);
+	vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc;
+	vcpu->arch.host_fpregs.regs = current->thread.fpu.regs;
 
+	/* Depending on MACHINE_HAS_VX, data stored to vrs either
+	 * has vector register or floating point register format.
+	 */
+	current->thread.fpu.regs = vcpu->run->s.regs.vrs;
+	current->thread.fpu.fpc = vcpu->run->s.regs.fpc;
 	if (test_fp_ctl(current->thread.fpu.fpc))
 		/* User space provided an invalid FPC, let's clear it */
 		current->thread.fpu.fpc = 0;
@@ -1321,19 +1314,13 @@
 	atomic_andnot(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
 	gmap_disable(vcpu->arch.gmap);
 
+	/* Save guest register state */
 	save_fpu_regs();
+	vcpu->run->s.regs.fpc = current->thread.fpu.fpc;
 
-	if (test_kvm_facility(vcpu->kvm, 129))
-		/*
-		 * kvm_arch_vcpu_load() set up the register save area to
-		 * the &vcpu->run->s.regs.vrs and, thus, the vector registers
-		 * are already saved.  Only the floating-point control must be
-		 * copied.
-		 */
-		vcpu->run->s.regs.fpc = current->thread.fpu.fpc;
-	else
-		save_fpu_to(&vcpu->arch.guest_fpregs);
-	load_fpu_from(&vcpu->arch.host_fpregs);
+	/* Restore host register state */
+	current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc;
+	current->thread.fpu.regs = vcpu->arch.host_fpregs.regs;
 
 	save_access_regs(vcpu->run->s.regs.acrs);
 	restore_access_regs(vcpu->arch.host_acrs);
@@ -1351,10 +1338,12 @@
 	memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
 	vcpu->arch.sie_block->gcr[0]  = 0xE0UL;
 	vcpu->arch.sie_block->gcr[14] = 0xC2000000UL;
-	vcpu->arch.guest_fpregs.fpc = 0;
-	asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc));
+	/* make sure the new fpc will be lazily loaded */
+	save_fpu_regs();
+	current->thread.fpu.fpc = 0;
 	vcpu->arch.sie_block->gbea = 1;
 	vcpu->arch.sie_block->pp = 0;
+	vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
 	vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
 	kvm_clear_async_pf_completion_queue(vcpu);
 	if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
@@ -1501,19 +1490,6 @@
 	vcpu->arch.local_int.wq = &vcpu->wq;
 	vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
 
-	/*
-	 * Allocate a save area for floating-point registers.  If the vector
-	 * extension is available, register contents are saved in the SIE
-	 * control block.  The allocated save area is still required in
-	 * particular places, for example, in kvm_s390_vcpu_store_status().
-	 */
-	vcpu->arch.guest_fpregs.fprs = kzalloc(sizeof(freg_t) * __NUM_FPRS,
-					       GFP_KERNEL);
-	if (!vcpu->arch.guest_fpregs.fprs) {
-		rc = -ENOMEM;
-		goto out_free_sie_block;
-	}
-
 	rc = kvm_vcpu_init(vcpu, kvm, id);
 	if (rc)
 		goto out_free_sie_block;
@@ -1734,19 +1710,27 @@
 
 int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
+	/* make sure the new values will be lazily loaded */
+	save_fpu_regs();
 	if (test_fp_ctl(fpu->fpc))
 		return -EINVAL;
-	memcpy(vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
-	vcpu->arch.guest_fpregs.fpc = fpu->fpc;
-	save_fpu_regs();
-	load_fpu_from(&vcpu->arch.guest_fpregs);
+	current->thread.fpu.fpc = fpu->fpc;
+	if (MACHINE_HAS_VX)
+		convert_fp_to_vx(current->thread.fpu.vxrs, (freg_t *)fpu->fprs);
+	else
+		memcpy(current->thread.fpu.fprs, &fpu->fprs, sizeof(fpu->fprs));
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-	memcpy(&fpu->fprs, vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs));
-	fpu->fpc = vcpu->arch.guest_fpregs.fpc;
+	/* make sure we have the latest values */
+	save_fpu_regs();
+	if (MACHINE_HAS_VX)
+		convert_vx_to_fp((freg_t *)fpu->fprs, current->thread.fpu.vxrs);
+	else
+		memcpy(fpu->fprs, current->thread.fpu.fprs, sizeof(fpu->fprs));
+	fpu->fpc = current->thread.fpu.fpc;
 	return 0;
 }
 
@@ -2178,6 +2162,11 @@
 		if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
 			kvm_clear_async_pf_completion_queue(vcpu);
 	}
+	if ((kvm_run->kvm_dirty_regs & KVM_SYNC_BPBC) &&
+	    test_kvm_facility(vcpu->kvm, 82)) {
+		vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
+		vcpu->arch.sie_block->fpf |= kvm_run->s.regs.bpbc ? FPF_BPBC : 0;
+	}
 	kvm_run->kvm_dirty_regs = 0;
 }
 
@@ -2195,6 +2184,7 @@
 	kvm_run->s.regs.pft = vcpu->arch.pfault_token;
 	kvm_run->s.regs.pfs = vcpu->arch.pfault_select;
 	kvm_run->s.regs.pfc = vcpu->arch.pfault_compare;
+	kvm_run->s.regs.bpbc = (vcpu->arch.sie_block->fpf & FPF_BPBC) == FPF_BPBC;
 }
 
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -2266,41 +2256,50 @@
 int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa)
 {
 	unsigned char archmode = 1;
+	freg_t fprs[NUM_FPRS];
 	unsigned int px;
 	u64 clkcomp;
 	int rc;
 
+	px = kvm_s390_get_prefix(vcpu);
 	if (gpa == KVM_S390_STORE_STATUS_NOADDR) {
 		if (write_guest_abs(vcpu, 163, &archmode, 1))
 			return -EFAULT;
-		gpa = SAVE_AREA_BASE;
+		gpa = 0;
 	} else if (gpa == KVM_S390_STORE_STATUS_PREFIXED) {
 		if (write_guest_real(vcpu, 163, &archmode, 1))
 			return -EFAULT;
-		gpa = kvm_s390_real_to_abs(vcpu, SAVE_AREA_BASE);
+		gpa = px;
+	} else
+		gpa -= __LC_FPREGS_SAVE_AREA;
+
+	/* manually convert vector registers if necessary */
+	if (MACHINE_HAS_VX) {
+		convert_vx_to_fp(fprs, (__vector128 *) vcpu->run->s.regs.vrs);
+		rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA,
+				     fprs, 128);
+	} else {
+		rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA,
+				     vcpu->run->s.regs.vrs, 128);
 	}
-	rc = write_guest_abs(vcpu, gpa + offsetof(struct save_area, fp_regs),
-			     vcpu->arch.guest_fpregs.fprs, 128);
-	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, gp_regs),
+	rc |= write_guest_abs(vcpu, gpa + __LC_GPREGS_SAVE_AREA,
 			      vcpu->run->s.regs.gprs, 128);
-	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, psw),
+	rc |= write_guest_abs(vcpu, gpa + __LC_PSW_SAVE_AREA,
 			      &vcpu->arch.sie_block->gpsw, 16);
-	px = kvm_s390_get_prefix(vcpu);
-	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, pref_reg),
+	rc |= write_guest_abs(vcpu, gpa + __LC_PREFIX_SAVE_AREA,
 			      &px, 4);
-	rc |= write_guest_abs(vcpu,
-			      gpa + offsetof(struct save_area, fp_ctrl_reg),
-			      &vcpu->arch.guest_fpregs.fpc, 4);
-	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, tod_reg),
+	rc |= write_guest_abs(vcpu, gpa + __LC_FP_CREG_SAVE_AREA,
+			      &vcpu->run->s.regs.fpc, 4);
+	rc |= write_guest_abs(vcpu, gpa + __LC_TOD_PROGREG_SAVE_AREA,
 			      &vcpu->arch.sie_block->todpr, 4);
-	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, timer),
+	rc |= write_guest_abs(vcpu, gpa + __LC_CPU_TIMER_SAVE_AREA,
 			      &vcpu->arch.sie_block->cputm, 8);
 	clkcomp = vcpu->arch.sie_block->ckc >> 8;
-	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, clk_cmp),
+	rc |= write_guest_abs(vcpu, gpa + __LC_CLOCK_COMP_SAVE_AREA,
 			      &clkcomp, 8);
-	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, acc_regs),
+	rc |= write_guest_abs(vcpu, gpa + __LC_AREGS_SAVE_AREA,
 			      &vcpu->run->s.regs.acrs, 64);
-	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, ctrl_regs),
+	rc |= write_guest_abs(vcpu, gpa + __LC_CREGS_SAVE_AREA,
 			      &vcpu->arch.sie_block->gcr, 128);
 	return rc ? -EFAULT : 0;
 }
@@ -2313,19 +2312,7 @@
 	 * it into the save area
 	 */
 	save_fpu_regs();
-	if (test_kvm_facility(vcpu->kvm, 129)) {
-		/*
-		 * If the vector extension is available, the vector registers
-		 * which overlaps with floating-point registers are saved in
-		 * the SIE-control block.  Hence, extract the floating-point
-		 * registers and the FPC value and store them in the
-		 * guest_fpregs structure.
-		 */
-		vcpu->arch.guest_fpregs.fpc = current->thread.fpu.fpc;
-		convert_vx_to_fp(vcpu->arch.guest_fpregs.fprs,
-				 current->thread.fpu.vxrs);
-	} else
-		save_fpu_to(&vcpu->arch.guest_fpregs);
+	vcpu->run->s.regs.fpc = current->thread.fpu.fpc;
 	save_access_regs(vcpu->run->s.regs.acrs);
 
 	return kvm_s390_store_status_unloaded(vcpu, addr);
@@ -2495,7 +2482,7 @@
 	const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION
 				    | KVM_S390_MEMOP_F_CHECK_ONLY;
 
-	if (mop->flags & ~supported_flags)
+	if (mop->flags & ~supported_flags || mop->ar >= NUM_ACRS || !mop->size)
 		return -EINVAL;
 
 	if (mop->size > MEM_OP_MAX_SIZE)
@@ -2565,7 +2552,7 @@
 	}
 	case KVM_S390_INTERRUPT: {
 		struct kvm_s390_interrupt s390int;
-		struct kvm_s390_irq s390irq;
+		struct kvm_s390_irq s390irq = {};
 
 		r = -EFAULT;
 		if (copy_from_user(&s390int, argp, sizeof(s390int)))
@@ -2745,21 +2732,28 @@
 				const struct kvm_memory_slot *new,
 				enum kvm_mr_change change)
 {
-	int rc;
-
-	/* If the basics of the memslot do not change, we do not want
-	 * to update the gmap. Every update causes several unnecessary
-	 * segment translation exceptions. This is usually handled just
-	 * fine by the normal fault handler + gmap, but it will also
-	 * cause faults on the prefix page of running guest CPUs.
-	 */
-	if (old->userspace_addr == mem->userspace_addr &&
-	    old->base_gfn * PAGE_SIZE == mem->guest_phys_addr &&
-	    old->npages * PAGE_SIZE == mem->memory_size)
-		return;
+	int rc = 0;
 
-	rc = gmap_map_segment(kvm->arch.gmap, mem->userspace_addr,
-		mem->guest_phys_addr, mem->memory_size);
+	switch (change) {
+	case KVM_MR_DELETE:
+		rc = gmap_unmap_segment(kvm->arch.gmap, old->base_gfn * PAGE_SIZE,
+					old->npages * PAGE_SIZE);
+		break;
+	case KVM_MR_MOVE:
+		rc = gmap_unmap_segment(kvm->arch.gmap, old->base_gfn * PAGE_SIZE,
+					old->npages * PAGE_SIZE);
+		if (rc)
+			break;
+		/* FALLTHROUGH */
+	case KVM_MR_CREATE:
+		rc = gmap_map_segment(kvm->arch.gmap, mem->userspace_addr,
+				      mem->guest_phys_addr, mem->memory_size);
+		break;
+	case KVM_MR_FLAGS_ONLY:
+		break;
+	default:
+		WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
+	}
 	if (rc)
 		pr_warn("failed to commit memory region\n");
 	return;
--- linux-4.4.0.orig/arch/s390/lib/mem.S
+++ linux-4.4.0/arch/s390/lib/mem.S
@@ -5,6 +5,9 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/nospec-insn.h>
+
+	GEN_BR_THUNK %r14
 
 /*
  * memset implementation
@@ -23,7 +26,7 @@
  */
 ENTRY(memset)
 	ltgr	%r4,%r4
-	bzr	%r14
+	jz	.Lmemset_exit
 	ltgr	%r3,%r3
 	jnz	.Lmemset_fill
 	aghi	%r4,-1
@@ -38,12 +41,13 @@
 .Lmemset_clear_rest:
 	larl	%r3,.Lmemset_xc
 	ex	%r4,0(%r3)
-	br	%r14
+.Lmemset_exit:
+	BR_EX	%r14
 .Lmemset_fill:
 	stc	%r3,0(%r2)
 	cghi	%r4,1
 	lgr	%r1,%r2
-	ber	%r14
+	je	.Lmemset_fill_exit
 	aghi	%r4,-2
 	srlg	%r3,%r4,8
 	ltgr	%r3,%r3
@@ -55,7 +59,8 @@
 .Lmemset_fill_rest:
 	larl	%r3,.Lmemset_mvc
 	ex	%r4,0(%r3)
-	br	%r14
+.Lmemset_fill_exit:
+	BR_EX	%r14
 .Lmemset_xc:
 	xc	0(1,%r1),0(%r1)
 .Lmemset_mvc:
@@ -68,7 +73,7 @@
  */
 ENTRY(memcpy)
 	ltgr	%r4,%r4
-	bzr	%r14
+	jz	.Lmemcpy_exit
 	aghi	%r4,-1
 	srlg	%r5,%r4,8
 	ltgr	%r5,%r5
@@ -77,7 +82,8 @@
 .Lmemcpy_rest:
 	larl	%r5,.Lmemcpy_mvc
 	ex	%r4,0(%r5)
-	br	%r14
+.Lmemcpy_exit:
+	BR_EX	%r14
 .Lmemcpy_loop:
 	mvc	0(256,%r1),0(%r3)
 	la	%r1,256(%r1)
--- linux-4.4.0.orig/arch/s390/lib/spinlock.c
+++ linux-4.4.0/arch/s390/lib/spinlock.c
@@ -182,42 +182,18 @@
 EXPORT_SYMBOL(_raw_read_trylock_retry);
 
 #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
-
 void _raw_write_lock_wait(arch_rwlock_t *rw, unsigned int prev)
-{
-	unsigned int owner, old;
-	int count = spin_retry;
-
-	owner = 0;
-	while (1) {
-		if (count-- <= 0) {
-			if (owner && !smp_vcpu_scheduled(~owner))
-				smp_yield_cpu(~owner);
-			count = spin_retry;
-		}
-		old = ACCESS_ONCE(rw->lock);
-		owner = ACCESS_ONCE(rw->owner);
-		smp_mb();
-		if ((int) old >= 0) {
-			prev = __RAW_LOCK(&rw->lock, 0x80000000, __RAW_OP_OR);
-			old = prev;
-		}
-		if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
-			break;
-		if (MACHINE_HAS_CAD)
-			_raw_compare_and_delay(&rw->lock, old);
-	}
-}
-EXPORT_SYMBOL(_raw_write_lock_wait);
-
-#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
-
+#else
 void _raw_write_lock_wait(arch_rwlock_t *rw)
+#endif
 {
-	unsigned int owner, old, prev;
+	unsigned int owner, old;
 	int count = spin_retry;
 
-	prev = 0x80000000;
+#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
+	if ((int) prev > 0)
+		__RAW_UNLOCK(&rw->lock, 0x7fffffff, __RAW_OP_AND);
+#endif
 	owner = 0;
 	while (1) {
 		if (count-- <= 0) {
@@ -227,12 +203,8 @@
 		}
 		old = ACCESS_ONCE(rw->lock);
 		owner = ACCESS_ONCE(rw->owner);
-		if ((int) old >= 0 &&
-		    _raw_compare_and_swap(&rw->lock, old, old | 0x80000000))
-			prev = old;
-		else
-			smp_mb();
-		if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
+		if (old == 0 &&
+		    _raw_compare_and_swap(&rw->lock, 0, 0x80000000))
 			break;
 		if (MACHINE_HAS_CAD)
 			_raw_compare_and_delay(&rw->lock, old);
@@ -240,8 +212,6 @@
 }
 EXPORT_SYMBOL(_raw_write_lock_wait);
 
-#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
-
 int _raw_write_trylock_retry(arch_rwlock_t *rw)
 {
 	unsigned int old;
--- linux-4.4.0.orig/arch/s390/mm/cmm.c
+++ linux-4.4.0/arch/s390/mm/cmm.c
@@ -306,16 +306,16 @@
 	}
 
 	if (write) {
-		len = *lenp;
-		if (copy_from_user(buf, buffer,
-				   len > sizeof(buf) ? sizeof(buf) : len))
+		len = min(*lenp, sizeof(buf));
+		if (copy_from_user(buf, buffer, len))
 			return -EFAULT;
-		buf[sizeof(buf) - 1] = '\0';
+		buf[len - 1] = '\0';
 		cmm_skip_blanks(buf, &p);
 		nr = simple_strtoul(p, &p, 0);
 		cmm_skip_blanks(p, &p);
 		seconds = simple_strtoul(p, &p, 0);
 		cmm_set_timeout(nr, seconds);
+		*ppos += *lenp;
 	} else {
 		len = sprintf(buf, "%ld %ld\n",
 			      cmm_timeout_pages, cmm_timeout_seconds);
@@ -323,9 +323,9 @@
 			len = *lenp;
 		if (copy_to_user(buffer, buf, len))
 			return -EFAULT;
+		*lenp = len;
+		*ppos += len;
 	}
-	*lenp = len;
-	*ppos += len;
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/s390/mm/extable.c
+++ linux-4.4.0/arch/s390/mm/extable.c
@@ -52,12 +52,16 @@
 	int i;
 
 	/* Normalize entries to being relative to the start of the section */
-	for (p = start, i = 0; p < finish; p++, i += 8)
+	for (p = start, i = 0; p < finish; p++, i += 8) {
 		p->insn += i;
+		p->fixup += i + 4;
+	}
 	sort(start, finish - start, sizeof(*start), cmp_ex, NULL);
 	/* Denormalize all entries */
-	for (p = start, i = 0; p < finish; p++, i += 8)
+	for (p = start, i = 0; p < finish; p++, i += 8) {
 		p->insn -= i;
+		p->fixup -= i + 4;
+	}
 }
 
 #ifdef CONFIG_MODULES
--- linux-4.4.0.orig/arch/s390/mm/extmem.c
+++ linux-4.4.0/arch/s390/mm/extmem.c
@@ -79,7 +79,7 @@
 struct dcss_segment {
 	struct list_head list;
 	char dcss_name[8];
-	char res_name[15];
+	char res_name[16];
 	unsigned long start_addr;
 	unsigned long end;
 	atomic_t ref_count;
@@ -434,7 +434,7 @@
 	memcpy(&seg->res_name, seg->dcss_name, 8);
 	EBCASC(seg->res_name, 8);
 	seg->res_name[8] = '\0';
-	strncat(seg->res_name, " (DCSS)", 7);
+	strlcat(seg->res_name, " (DCSS)", sizeof(seg->res_name));
 	seg->res->name = seg->res_name;
 	rc = seg->vm_segtype;
 	if (rc == SEG_TYPE_SC ||
--- linux-4.4.0.orig/arch/s390/mm/fault.c
+++ linux-4.4.0/arch/s390/mm/fault.c
@@ -459,6 +459,8 @@
 	/* No reason to continue if interrupted by SIGKILL. */
 	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
 		fault = VM_FAULT_SIGNAL;
+		if (flags & FAULT_FLAG_RETRY_NOWAIT)
+			goto out_up;
 		goto out;
 	}
 	if (unlikely(fault & VM_FAULT_ERROR))
--- linux-4.4.0.orig/arch/s390/mm/gup.c
+++ linux-4.4.0/arch/s390/mm/gup.c
@@ -54,13 +54,12 @@
 static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
 		unsigned long end, int write, struct page **pages, int *nr)
 {
-	unsigned long mask, result;
 	struct page *head, *page, *tail;
+	unsigned long mask;
 	int refs;
 
-	result = write ? 0 : _SEGMENT_ENTRY_PROTECT;
-	mask = result | _SEGMENT_ENTRY_INVALID;
-	if ((pmd_val(pmd) & mask) != result)
+	mask = (write ? _SEGMENT_ENTRY_PROTECT : 0) | _SEGMENT_ENTRY_INVALID;
+	if ((pmd_val(pmd) & mask) != 0)
 		return 0;
 	VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));
 
@@ -233,8 +232,15 @@
 	struct mm_struct *mm = current->mm;
 	int nr, ret;
 
+	/*
+	 * The FAST_GUP case requires FOLL_WRITE even for pure reads,
+	 * because get_user_pages() may need to cause an early COW in
+	 * order to avoid confusing the normal COW routines. So only
+	 * targets that are already writable are safe to do by just
+	 * looking at the page tables.
+	 */
 	start &= PAGE_MASK;
-	nr = __get_user_pages_fast(start, nr_pages, write, pages);
+	nr = __get_user_pages_fast(start, nr_pages, 1, pages);
 	if (nr == nr_pages)
 		return nr;
 
@@ -242,7 +248,7 @@
 	start += nr << PAGE_SHIFT;
 	pages += nr;
 	ret = get_user_pages_unlocked(current, mm, start,
-			     nr_pages - nr, write, 0, pages);
+			     nr_pages - nr, pages, write ? FOLL_WRITE : 0);
 	/* Have to be a bit careful with return values */
 	if (nr > 0)
 		ret = (ret < 0) ? nr : ret + nr;
--- linux-4.4.0.orig/arch/s390/mm/init.c
+++ linux-4.4.0/arch/s390/mm/init.c
@@ -89,7 +89,8 @@
 		asce_bits = _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH;
 		pgd_type = _REGION3_ENTRY_EMPTY;
 	}
-	S390_lowcore.kernel_asce = (__pa(init_mm.pgd) & PAGE_MASK) | asce_bits;
+	init_mm.context.asce = (__pa(init_mm.pgd) & PAGE_MASK) | asce_bits;
+	S390_lowcore.kernel_asce = init_mm.context.asce;
 	clear_table((unsigned long *) init_mm.pgd, pgd_type,
 		    sizeof(unsigned long)*2048);
 	vmem_map_init();
--- linux-4.4.0.orig/arch/s390/mm/mmap.c
+++ linux-4.4.0/arch/s390/mm/mmap.c
@@ -97,7 +97,7 @@
 		addr = PAGE_ALIGN(addr);
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
@@ -135,7 +135,7 @@
 		addr = PAGE_ALIGN(addr);
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
-				(!vma || addr + len <= vma->vm_start))
+				(!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
@@ -174,7 +174,7 @@
 	if (!(flags & MAP_FIXED))
 		addr = 0;
 	if ((addr + len) >= TASK_SIZE)
-		return crst_table_upgrade(current->mm, 1UL << 53);
+		return crst_table_upgrade(current->mm);
 	return 0;
 }
 
@@ -191,7 +191,7 @@
 		return area;
 	if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) {
 		/* Upgrade the page table to 4 levels and retry. */
-		rc = crst_table_upgrade(mm, 1UL << 53);
+		rc = crst_table_upgrade(mm);
 		if (rc)
 			return (unsigned long) rc;
 		area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
@@ -213,7 +213,7 @@
 		return area;
 	if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) {
 		/* Upgrade the page table to 4 levels and retry. */
-		rc = crst_table_upgrade(mm, 1UL << 53);
+		rc = crst_table_upgrade(mm);
 		if (rc)
 			return (unsigned long) rc;
 		area = arch_get_unmapped_area_topdown(filp, addr, len,
--- linux-4.4.0.orig/arch/s390/mm/pgtable.c
+++ linux-4.4.0/arch/s390/mm/pgtable.c
@@ -49,81 +49,52 @@
 	__tlb_flush_local();
 }
 
-int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
+int crst_table_upgrade(struct mm_struct *mm)
 {
 	unsigned long *table, *pgd;
-	unsigned long entry;
-	int flush;
 
-	BUG_ON(limit > (1UL << 53));
-	flush = 0;
-repeat:
+	/* upgrade should only happen from 3 to 4 levels */
+	BUG_ON(mm->context.asce_limit != (1UL << 42));
+
 	table = crst_table_alloc(mm);
 	if (!table)
 		return -ENOMEM;
+
 	spin_lock_bh(&mm->page_table_lock);
-	if (mm->context.asce_limit < limit) {
-		pgd = (unsigned long *) mm->pgd;
-		if (mm->context.asce_limit <= (1UL << 31)) {
-			entry = _REGION3_ENTRY_EMPTY;
-			mm->context.asce_limit = 1UL << 42;
-			mm->context.asce_bits = _ASCE_TABLE_LENGTH |
-						_ASCE_USER_BITS |
-						_ASCE_TYPE_REGION3;
-		} else {
-			entry = _REGION2_ENTRY_EMPTY;
-			mm->context.asce_limit = 1UL << 53;
-			mm->context.asce_bits = _ASCE_TABLE_LENGTH |
-						_ASCE_USER_BITS |
-						_ASCE_TYPE_REGION2;
-		}
-		crst_table_init(table, entry);
-		pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd);
-		mm->pgd = (pgd_t *) table;
-		mm->task_size = mm->context.asce_limit;
-		table = NULL;
-		flush = 1;
-	}
+	pgd = (unsigned long *) mm->pgd;
+	crst_table_init(table, _REGION2_ENTRY_EMPTY);
+	pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd);
+	mm->pgd = (pgd_t *) table;
+	mm->context.asce_limit = 1UL << 53;
+	mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
+			   _ASCE_USER_BITS | _ASCE_TYPE_REGION2;
+	mm->task_size = mm->context.asce_limit;
 	spin_unlock_bh(&mm->page_table_lock);
-	if (table)
-		crst_table_free(mm, table);
-	if (mm->context.asce_limit < limit)
-		goto repeat;
-	if (flush)
-		on_each_cpu(__crst_table_upgrade, mm, 0);
+
+	on_each_cpu(__crst_table_upgrade, mm, 0);
 	return 0;
 }
 
-void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
+void crst_table_downgrade(struct mm_struct *mm)
 {
 	pgd_t *pgd;
 
+	/* downgrade should only happen from 3 to 2 levels (compat only) */
+	BUG_ON(mm->context.asce_limit != (1UL << 42));
+
 	if (current->active_mm == mm) {
 		clear_user_asce();
 		__tlb_flush_mm(mm);
 	}
-	while (mm->context.asce_limit > limit) {
-		pgd = mm->pgd;
-		switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) {
-		case _REGION_ENTRY_TYPE_R2:
-			mm->context.asce_limit = 1UL << 42;
-			mm->context.asce_bits = _ASCE_TABLE_LENGTH |
-						_ASCE_USER_BITS |
-						_ASCE_TYPE_REGION3;
-			break;
-		case _REGION_ENTRY_TYPE_R3:
-			mm->context.asce_limit = 1UL << 31;
-			mm->context.asce_bits = _ASCE_TABLE_LENGTH |
-						_ASCE_USER_BITS |
-						_ASCE_TYPE_SEGMENT;
-			break;
-		default:
-			BUG();
-		}
-		mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN);
-		mm->task_size = mm->context.asce_limit;
-		crst_table_free(mm, (unsigned long *) pgd);
-	}
+
+	pgd = mm->pgd;
+	mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN);
+	mm->context.asce_limit = 1UL << 31;
+	mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
+			   _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT;
+	mm->task_size = mm->context.asce_limit;
+	crst_table_free(mm, (unsigned long *) pgd);
+
 	if (current->active_mm == mm)
 		set_user_asce(mm);
 }
@@ -195,7 +166,7 @@
 static void gmap_flush_tlb(struct gmap *gmap)
 {
 	if (MACHINE_HAS_IDTE)
-		__tlb_flush_asce(gmap->mm, gmap->asce);
+		__tlb_flush_idte(gmap->asce);
 	else
 		__tlb_flush_global();
 }
@@ -234,7 +205,7 @@
 
 	/* Flush tlb. */
 	if (MACHINE_HAS_IDTE)
-		__tlb_flush_asce(gmap->mm, gmap->asce);
+		__tlb_flush_idte(gmap->asce);
 	else
 		__tlb_flush_global();
 
@@ -666,6 +637,8 @@
 		vmaddr |= gaddr & ~PMD_MASK;
 		/* Find vma in the parent mm */
 		vma = find_vma(gmap->mm, vmaddr);
+		if (!vma)
+			continue;
 		size = min(to - gaddr, PMD_SIZE - (gaddr & ~PMD_MASK));
 		zap_page_range(vma, vmaddr, size, NULL);
 	}
@@ -1266,11 +1239,28 @@
  */
 bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap)
 {
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
 	pte_t *pte;
 	spinlock_t *ptl;
 	bool dirty = false;
 
-	pte = get_locked_pte(gmap->mm, address, &ptl);
+	pgd = pgd_offset(gmap->mm, address);
+	pud = pud_alloc(gmap->mm, pgd, address);
+	if (!pud)
+		return false;
+	pmd = pmd_alloc(gmap->mm, pud, address);
+	if (!pmd)
+		return false;
+	/* We can't run guests backed by huge pages, but userspace can
+	 * still set them up and then try to migrate them without any
+	 * migration support.
+	 */
+	if (pmd_large(*pmd))
+		return true;
+
+	pte = pte_alloc_map_lock(gmap->mm, pmd, address, &ptl);
 	if (unlikely(!pte))
 		return false;
 
--- linux-4.4.0.orig/arch/s390/mm/vmem.c
+++ linux-4.4.0/arch/s390/mm/vmem.c
@@ -372,7 +372,7 @@
 	ro_end = (unsigned long)&_eshared & PAGE_MASK;
 	for_each_memblock(memory, reg) {
 		start = reg->base;
-		end = reg->base + reg->size - 1;
+		end = reg->base + reg->size;
 		if (start >= ro_end || end <= ro_start)
 			vmem_add_mem(start, end - start, 0);
 		else if (start >= ro_start && end <= ro_end)
--- linux-4.4.0.orig/arch/s390/net/bpf_jit.S
+++ linux-4.4.0/arch/s390/net/bpf_jit.S
@@ -8,6 +8,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/nospec-insn.h>
 #include "bpf_jit.h"
 
 /*
@@ -53,7 +54,7 @@
 	clg	%r3,STK_OFF_HLEN(%r15);	/* Offset + SIZE > hlen? */	\
 	jh	sk_load_##NAME##_slow;					\
 	LOAD	%r14,-SIZE(%r3,%r12);	/* Get data from skb */		\
-	b	OFF_OK(%r6);		/* Return */			\
+	B_EX	OFF_OK,%r6;		/* Return */			\
 									\
 sk_load_##NAME##_slow:;							\
 	lgr	%r2,%r7;		/* Arg1 = skb pointer */	\
@@ -63,11 +64,14 @@
 	brasl	%r14,skb_copy_bits;	/* Get data from skb */		\
 	LOAD	%r14,STK_OFF_TMP(%r15);	/* Load from temp bufffer */	\
 	ltgr	%r2,%r2;		/* Set cc to (%r2 != 0) */	\
-	br	%r6;			/* Return */
+	BR_EX	%r6;			/* Return */
 
 sk_load_common(word, 4, llgf)	/* r14 = *(u32 *) (skb->data+offset) */
 sk_load_common(half, 2, llgh)	/* r14 = *(u16 *) (skb->data+offset) */
 
+	GEN_BR_THUNK %r6
+	GEN_B_THUNK OFF_OK,%r6
+
 /*
  * Load 1 byte from SKB (optimized version)
  */
@@ -79,7 +83,7 @@
 	clg	%r3,STK_OFF_HLEN(%r15)	# Offset >= hlen?
 	jnl	sk_load_byte_slow
 	llgc	%r14,0(%r3,%r12)	# Get byte from skb
-	b	OFF_OK(%r6)		# Return OK
+	B_EX	OFF_OK,%r6		# Return OK
 
 sk_load_byte_slow:
 	lgr	%r2,%r7			# Arg1 = skb pointer
@@ -89,7 +93,7 @@
 	brasl	%r14,skb_copy_bits	# Get data from skb
 	llgc	%r14,STK_OFF_TMP(%r15)	# Load result from temp buffer
 	ltgr	%r2,%r2			# Set cc to (%r2 != 0)
-	br	%r6			# Return cc
+	BR_EX	%r6			# Return cc
 
 #define sk_negative_common(NAME, SIZE, LOAD)				\
 sk_load_##NAME##_slow_neg:;						\
@@ -103,7 +107,7 @@
 	jz	bpf_error;						\
 	LOAD	%r14,0(%r2);		/* Get data from pointer */	\
 	xr	%r3,%r3;		/* Set cc to zero */		\
-	br	%r6;			/* Return cc */
+	BR_EX	%r6;			/* Return cc */
 
 sk_negative_common(word, 4, llgf)
 sk_negative_common(half, 2, llgh)
@@ -112,4 +116,4 @@
 bpf_error:
 # force a return 0 from jit handler
 	ltgr	%r15,%r15	# Set condition code
-	br	%r6
+	BR_EX	%r6
--- linux-4.4.0.orig/arch/s390/net/bpf_jit.h
+++ linux-4.4.0/arch/s390/net/bpf_jit.h
@@ -37,7 +37,7 @@
  *	      |		      |     |
  *	      +---------------+     |
  *	      | 8 byte skbp   |     |
- * R15+170 -> +---------------+     |
+ * R15+176 -> +---------------+     |
  *	      | 8 byte hlen   |     |
  * R15+168 -> +---------------+     |
  *	      | 4 byte align  |     |
@@ -58,7 +58,7 @@
 #define STK_OFF		(STK_SPACE - STK_160_UNUSED)
 #define STK_OFF_TMP	160	/* Offset of tmp buffer on stack */
 #define STK_OFF_HLEN	168	/* Offset of SKB header length on stack */
-#define STK_OFF_SKBP	170	/* Offset of SKB pointer on stack */
+#define STK_OFF_SKBP	176	/* Offset of SKB pointer on stack */
 
 #define STK_OFF_R6	(160 - 11 * 8)	/* Offset of r6 on stack */
 #define STK_OFF_TCCNT	(160 - 12 * 8)	/* Offset of tail_call_cnt on stack */
--- linux-4.4.0.orig/arch/s390/net/bpf_jit_comp.c
+++ linux-4.4.0/arch/s390/net/bpf_jit_comp.c
@@ -24,6 +24,8 @@
 #include <linux/bpf.h>
 #include <asm/cacheflush.h>
 #include <asm/dis.h>
+#include <asm/facility.h>
+#include <asm/nospec-branch.h>
 #include "bpf_jit.h"
 
 int bpf_jit_enable __read_mostly;
@@ -41,11 +43,13 @@
 	int base_ip;		/* Base address for literal pool */
 	int ret0_ip;		/* Address of return 0 */
 	int exit_ip;		/* Address of exit */
+	int r1_thunk_ip;	/* Address of expoline thunk for 'br %r1' */
+	int r14_thunk_ip;	/* Address of expoline thunk for 'br %r14' */
 	int tail_call_start;	/* Tail call start offset */
 	int labels[1];		/* Labels for local jumps */
 };
 
-#define BPF_SIZE_MAX	0x7ffff	/* Max size for program (20 bit signed displ) */
+#define BPF_SIZE_MAX	0xffff	/* Max size for program (16 bit branches) */
 
 #define SEEN_SKB	1	/* skb access */
 #define SEEN_MEM	2	/* use mem[] for temporary storage */
@@ -248,6 +252,19 @@
 	REG_SET_SEEN(b2);					\
 })
 
+#define EMIT6_PCREL_RILB(op, b, target)				\
+({								\
+	int rel = (target - jit->prg) / 2;			\
+	_EMIT6(op | reg_high(b) << 16 | rel >> 16, rel & 0xffff);	\
+	REG_SET_SEEN(b);					\
+})
+
+#define EMIT6_PCREL_RIL(op, target)				\
+({								\
+	int rel = (target - jit->prg) / 2;			\
+	_EMIT6(op | rel >> 16, rel & 0xffff);			\
+})
+
 #define _EMIT6_IMM(op, imm)					\
 ({								\
 	unsigned int __imm = (imm);				\
@@ -446,7 +463,7 @@
 		emit_load_skb_data_hlen(jit);
 	if (jit->seen & SEEN_SKB_CHANGE)
 		/* stg %b1,ST_OFF_SKBP(%r0,%r15) */
-		EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, REG_15,
+		EMIT6_DISP_LH(0xe3000000, 0x0024, BPF_REG_1, REG_0, REG_15,
 			      STK_OFF_SKBP);
 	/* Clear A (%b0) and X (%b7) registers for converted BPF programs */
 	if (is_classic) {
@@ -475,8 +492,43 @@
 	EMIT4(0xb9040000, REG_2, BPF_REG_0);
 	/* Restore registers */
 	save_restore_regs(jit, REGS_RESTORE);
+	if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) {
+		jit->r14_thunk_ip = jit->prg;
+		/* Generate __s390_indirect_jump_r14 thunk */
+		if (test_facility(35)) {
+			/* exrl %r0,.+10 */
+			EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10);
+		} else {
+			/* larl %r1,.+14 */
+			EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14);
+			/* ex 0,0(%r1) */
+			EMIT4_DISP(0x44000000, REG_0, REG_1, 0);
+		}
+		/* j . */
+		EMIT4_PCREL(0xa7f40000, 0);
+	}
 	/* br %r14 */
 	_EMIT2(0x07fe);
+
+	if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable &&
+	    (jit->seen & SEEN_FUNC)) {
+		jit->r1_thunk_ip = jit->prg;
+		/* Generate __s390_indirect_jump_r1 thunk */
+		if (test_facility(35)) {
+			/* exrl %r0,.+10 */
+			EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10);
+			/* j . */
+			EMIT4_PCREL(0xa7f40000, 0);
+			/* br %r1 */
+			_EMIT2(0x07f1);
+		} else {
+			/* ex 0,S390_lowcore.br_r1_tampoline */
+			EMIT4_DISP(0x44000000, REG_0, REG_0,
+				   offsetof(struct _lowcore, br_r1_trampoline));
+			/* j . */
+			EMIT4_PCREL(0xa7f40000, 0);
+		}
+	}
 }
 
 /*
@@ -544,10 +596,10 @@
 		EMIT4(0xb9080000, dst_reg, src_reg);
 		break;
 	case BPF_ALU | BPF_ADD | BPF_K: /* dst = (u32) dst + (u32) imm */
-		if (!imm)
-			break;
-		/* alfi %dst,imm */
-		EMIT6_IMM(0xc20b0000, dst_reg, imm);
+		if (imm != 0) {
+			/* alfi %dst,imm */
+			EMIT6_IMM(0xc20b0000, dst_reg, imm);
+		}
 		EMIT_ZERO(dst_reg);
 		break;
 	case BPF_ALU64 | BPF_ADD | BPF_K: /* dst = dst + imm */
@@ -569,17 +621,22 @@
 		EMIT4(0xb9090000, dst_reg, src_reg);
 		break;
 	case BPF_ALU | BPF_SUB | BPF_K: /* dst = (u32) dst - (u32) imm */
-		if (!imm)
-			break;
-		/* alfi %dst,-imm */
-		EMIT6_IMM(0xc20b0000, dst_reg, -imm);
+		if (imm != 0) {
+			/* alfi %dst,-imm */
+			EMIT6_IMM(0xc20b0000, dst_reg, -imm);
+		}
 		EMIT_ZERO(dst_reg);
 		break;
 	case BPF_ALU64 | BPF_SUB | BPF_K: /* dst = dst - imm */
 		if (!imm)
 			break;
-		/* agfi %dst,-imm */
-		EMIT6_IMM(0xc2080000, dst_reg, -imm);
+		if (imm == -0x80000000) {
+			/* algfi %dst,0x80000000 */
+			EMIT6_IMM(0xc20a0000, dst_reg, 0x80000000);
+		} else {
+			/* agfi %dst,-imm */
+			EMIT6_IMM(0xc2080000, dst_reg, -imm);
+		}
 		break;
 	/*
 	 * BPF_MUL
@@ -594,10 +651,10 @@
 		EMIT4(0xb90c0000, dst_reg, src_reg);
 		break;
 	case BPF_ALU | BPF_MUL | BPF_K: /* dst = (u32) dst * (u32) imm */
-		if (imm == 1)
-			break;
-		/* msfi %r5,imm */
-		EMIT6_IMM(0xc2010000, dst_reg, imm);
+		if (imm != 1) {
+			/* msfi %r5,imm */
+			EMIT6_IMM(0xc2010000, dst_reg, imm);
+		}
 		EMIT_ZERO(dst_reg);
 		break;
 	case BPF_ALU64 | BPF_MUL | BPF_K: /* dst = dst * imm */
@@ -658,6 +715,8 @@
 			if (BPF_OP(insn->code) == BPF_MOD)
 				/* lhgi %dst,0 */
 				EMIT4_IMM(0xa7090000, dst_reg, 0);
+			else
+				EMIT_ZERO(dst_reg);
 			break;
 		}
 		/* lhi %w0,0 */
@@ -750,10 +809,10 @@
 		EMIT4(0xb9820000, dst_reg, src_reg);
 		break;
 	case BPF_ALU | BPF_XOR | BPF_K: /* dst = (u32) dst ^ (u32) imm */
-		if (!imm)
-			break;
-		/* xilf %dst,imm */
-		EMIT6_IMM(0xc0070000, dst_reg, imm);
+		if (imm != 0) {
+			/* xilf %dst,imm */
+			EMIT6_IMM(0xc0070000, dst_reg, imm);
+		}
 		EMIT_ZERO(dst_reg);
 		break;
 	case BPF_ALU64 | BPF_XOR | BPF_K: /* dst = dst ^ imm */
@@ -774,10 +833,10 @@
 		EMIT6_DISP_LH(0xeb000000, 0x000d, dst_reg, dst_reg, src_reg, 0);
 		break;
 	case BPF_ALU | BPF_LSH | BPF_K: /* dst = (u32) dst << (u32) imm */
-		if (imm == 0)
-			break;
-		/* sll %dst,imm(%r0) */
-		EMIT4_DISP(0x89000000, dst_reg, REG_0, imm);
+		if (imm != 0) {
+			/* sll %dst,imm(%r0) */
+			EMIT4_DISP(0x89000000, dst_reg, REG_0, imm);
+		}
 		EMIT_ZERO(dst_reg);
 		break;
 	case BPF_ALU64 | BPF_LSH | BPF_K: /* dst = dst << imm */
@@ -799,10 +858,10 @@
 		EMIT6_DISP_LH(0xeb000000, 0x000c, dst_reg, dst_reg, src_reg, 0);
 		break;
 	case BPF_ALU | BPF_RSH | BPF_K: /* dst = (u32) dst >> (u32) imm */
-		if (imm == 0)
-			break;
-		/* srl %dst,imm(%r0) */
-		EMIT4_DISP(0x88000000, dst_reg, REG_0, imm);
+		if (imm != 0) {
+			/* srl %dst,imm(%r0) */
+			EMIT4_DISP(0x88000000, dst_reg, REG_0, imm);
+		}
 		EMIT_ZERO(dst_reg);
 		break;
 	case BPF_ALU64 | BPF_RSH | BPF_K: /* dst = dst >> imm */
@@ -834,7 +893,7 @@
 		break;
 	case BPF_ALU64 | BPF_NEG: /* dst = -dst */
 		/* lcgr %dst,%dst */
-		EMIT4(0xb9130000, dst_reg, dst_reg);
+		EMIT4(0xb9030000, dst_reg, dst_reg);
 		break;
 	/*
 	 * BPF_FROM_BE/LE
@@ -980,8 +1039,13 @@
 		/* lg %w1,<d(imm)>(%l) */
 		EMIT6_DISP_LH(0xe3000000, 0x0004, REG_W1, REG_0, REG_L,
 			      EMIT_CONST_U64(func));
-		/* basr %r14,%w1 */
-		EMIT2(0x0d00, REG_14, REG_W1);
+		if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) {
+			/* brasl %r14,__s390_indirect_jump_r1 */
+			EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip);
+		} else {
+			/* basr %r14,%w1 */
+			EMIT2(0x0d00, REG_14, REG_W1);
+		}
 		/* lgr %b0,%r2: load return value into %b0 */
 		EMIT4(0xb9040000, BPF_REG_0, REG_2);
 		if (bpf_helper_changes_skb_data((void *)func)) {
@@ -1010,8 +1074,8 @@
 		/* llgf %w1,map.max_entries(%b2) */
 		EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2,
 			      offsetof(struct bpf_array, map.max_entries));
-		/* clgrj %b3,%w1,0xa,label0: if %b3 >= %w1 goto out */
-		EMIT6_PCREL_LABEL(0xec000000, 0x0065, BPF_REG_3,
+		/* clrj %b3,%w1,0xa,label0: if (u32)%b3 >= (u32)%w1 goto out */
+		EMIT6_PCREL_LABEL(0xec000000, 0x0077, BPF_REG_3,
 				  REG_W1, 0, 0xa);
 
 		/*
@@ -1037,8 +1101,10 @@
 		 *         goto out;
 		 */
 
-		/* sllg %r1,%b3,3: %r1 = index * 8 */
-		EMIT6_DISP_LH(0xeb000000, 0x000d, REG_1, BPF_REG_3, REG_0, 3);
+		/* llgfr %r1,%b3: %r1 = (u32) index */
+		EMIT4(0xb9160000, REG_1, BPF_REG_3);
+		/* sllg %r1,%r1,3: %r1 *= 8 */
+		EMIT6_DISP_LH(0xeb000000, 0x000d, REG_1, REG_1, REG_0, 3);
 		/* lg %r1,prog(%b2,%r1) */
 		EMIT6_DISP_LH(0xe3000000, 0x0004, REG_1, BPF_REG_2,
 			      REG_1, offsetof(struct bpf_array, ptrs));
@@ -1218,8 +1284,13 @@
 			/* agfr %b2,%src (%src is s32 here) */
 			EMIT4(0xb9180000, BPF_REG_2, src_reg);
 
-		/* basr %b5,%w1 (%b5 is call saved) */
-		EMIT2(0x0d00, BPF_REG_5, REG_W1);
+		if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) {
+			/* brasl %r5,__s390_indirect_jump_r1 */
+			EMIT6_PCREL_RILB(0xc0050000, BPF_REG_5, jit->r1_thunk_ip);
+		} else {
+			/* basr %b5,%w1 (%b5 is call saved) */
+			EMIT2(0x0d00, BPF_REG_5, REG_W1);
+		}
 
 		/*
 		 * Note: For fast access we jump directly after the
@@ -1250,7 +1321,8 @@
 		insn_count = bpf_jit_insn(jit, fp, i);
 		if (insn_count < 0)
 			return -1;
-		jit->addrs[i + 1] = jit->prg; /* Next instruction address */
+		/* Next instruction address */
+		jit->addrs[i + insn_count] = jit->prg;
 	}
 	bpf_jit_epilogue(jit);
 
@@ -1271,18 +1343,19 @@
 /*
  * Compile eBPF program "fp"
  */
-void bpf_int_jit_compile(struct bpf_prog *fp)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
 {
 	struct bpf_binary_header *header;
 	struct bpf_jit jit;
 	int pass;
 
 	if (!bpf_jit_enable)
-		return;
+		return fp;
+
 	memset(&jit, 0, sizeof(jit));
 	jit.addrs = kcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
 	if (jit.addrs == NULL)
-		return;
+		return fp;
 	/*
 	 * Three initial passes:
 	 *   - 1/2: Determine clobbered registers
@@ -1314,6 +1387,7 @@
 	}
 free_addrs:
 	kfree(jit.addrs);
+	return fp;
 }
 
 /*
--- linux-4.4.0.orig/arch/s390/numa/numa.c
+++ linux-4.4.0/arch/s390/numa/numa.c
@@ -47,6 +47,7 @@
 {
 	return mode->distance ? mode->distance(a, b) : 0;
 }
+EXPORT_SYMBOL(__node_distance);
 
 int numa_debug_enabled;
 
--- linux-4.4.0.orig/arch/s390/pci/pci.c
+++ linux-4.4.0/arch/s390/pci/pci.c
@@ -68,9 +68,12 @@
 	.isc = PCI_ISC,
 };
 
-/* I/O Map */
+#define ZPCI_IOMAP_ENTRIES						\
+	min(((unsigned long) CONFIG_PCI_NR_FUNCTIONS * PCI_BAR_COUNT),	\
+	    ZPCI_IOMAP_MAX_ENTRIES)
+
 static DEFINE_SPINLOCK(zpci_iomap_lock);
-static DECLARE_BITMAP(zpci_iomap, ZPCI_IOMAP_MAX_ENTRIES);
+static unsigned long *zpci_iomap_bitmap;
 struct zpci_iomap_entry *zpci_iomap_start;
 EXPORT_SYMBOL_GPL(zpci_iomap_start);
 
@@ -265,27 +268,20 @@
 			      unsigned long max)
 {
 	struct zpci_dev *zdev =	to_zpci(pdev);
-	u64 addr;
 	int idx;
 
-	if ((bar & 7) != bar)
+	if (!pci_resource_len(pdev, bar))
 		return NULL;
 
 	idx = zdev->bars[bar].map_idx;
 	spin_lock(&zpci_iomap_lock);
-	if (zpci_iomap_start[idx].count++) {
-		BUG_ON(zpci_iomap_start[idx].fh != zdev->fh ||
-		       zpci_iomap_start[idx].bar != bar);
-	} else {
-		zpci_iomap_start[idx].fh = zdev->fh;
-		zpci_iomap_start[idx].bar = bar;
-	}
 	/* Detect overrun */
-	BUG_ON(!zpci_iomap_start[idx].count);
+	WARN_ON(!++zpci_iomap_start[idx].count);
+	zpci_iomap_start[idx].fh = zdev->fh;
+	zpci_iomap_start[idx].bar = bar;
 	spin_unlock(&zpci_iomap_lock);
 
-	addr = ZPCI_IOMAP_ADDR_BASE | ((u64) idx << 48);
-	return (void __iomem *) addr + offset;
+	return (void __iomem *) ZPCI_ADDR(idx) + offset;
 }
 EXPORT_SYMBOL(pci_iomap_range);
 
@@ -297,12 +293,11 @@
 
 void pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
 {
-	unsigned int idx;
+	unsigned int idx = ZPCI_IDX(addr);
 
-	idx = (((__force u64) addr) & ~ZPCI_IOMAP_ADDR_BASE) >> 48;
 	spin_lock(&zpci_iomap_lock);
 	/* Detect underrun */
-	BUG_ON(!zpci_iomap_start[idx].count);
+	WARN_ON(!zpci_iomap_start[idx].count);
 	if (!--zpci_iomap_start[idx].count) {
 		zpci_iomap_start[idx].fh = 0;
 		zpci_iomap_start[idx].bar = 0;
@@ -359,7 +354,8 @@
 				/* End of second scan with interrupts on. */
 				break;
 			/* First scan complete, reenable interrupts. */
-			zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+			if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC))
+				break;
 			si = 0;
 			continue;
 		}
@@ -411,6 +407,8 @@
 	hwirq = 0;
 	for_each_pci_msi_entry(msi, pdev) {
 		rc = -EIO;
+		if (hwirq >= msi_vecs)
+			break;
 		irq = irq_alloc_desc(0);	/* Alloc irq on node 0 */
 		if (irq < 0)
 			goto out_msi;
@@ -544,15 +542,15 @@
 
 static int zpci_alloc_iomap(struct zpci_dev *zdev)
 {
-	int entry;
+	unsigned long entry;
 
 	spin_lock(&zpci_iomap_lock);
-	entry = find_first_zero_bit(zpci_iomap, ZPCI_IOMAP_MAX_ENTRIES);
-	if (entry == ZPCI_IOMAP_MAX_ENTRIES) {
+	entry = find_first_zero_bit(zpci_iomap_bitmap, ZPCI_IOMAP_ENTRIES);
+	if (entry == ZPCI_IOMAP_ENTRIES) {
 		spin_unlock(&zpci_iomap_lock);
 		return -ENOSPC;
 	}
-	set_bit(entry, zpci_iomap);
+	set_bit(entry, zpci_iomap_bitmap);
 	spin_unlock(&zpci_iomap_lock);
 	return entry;
 }
@@ -561,7 +559,7 @@
 {
 	spin_lock(&zpci_iomap_lock);
 	memset(&zpci_iomap_start[entry], 0, sizeof(struct zpci_iomap_entry));
-	clear_bit(entry, zpci_iomap);
+	clear_bit(entry, zpci_iomap_bitmap);
 	spin_unlock(&zpci_iomap_lock);
 }
 
@@ -611,8 +609,7 @@
 		if (zdev->bars[i].val & 4)
 			flags |= IORESOURCE_MEM_64;
 
-		addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48);
-
+		addr = ZPCI_ADDR(entry);
 		size = 1UL << zdev->bars[i].size;
 
 		res = __alloc_res(zdev, addr, size, flags);
@@ -643,11 +640,9 @@
 
 int pcibios_add_device(struct pci_dev *pdev)
 {
-	struct zpci_dev *zdev = to_zpci(pdev);
 	struct resource *res;
 	int i;
 
-	zdev->pdev = pdev;
 	pdev->dev.groups = zpci_attr_groups;
 	zpci_map_resources(pdev);
 
@@ -670,8 +665,7 @@
 {
 	struct zpci_dev *zdev = to_zpci(pdev);
 
-	zdev->pdev = pdev;
-	zpci_debug_init_device(zdev);
+	zpci_debug_init_device(zdev, dev_name(&pdev->dev));
 	zpci_fmb_enable_device(zdev);
 
 	return pci_enable_resources(pdev, mask);
@@ -683,7 +677,6 @@
 
 	zpci_fmb_disable_device(zdev);
 	zpci_debug_exit_device(zdev);
-	zdev->pdev = NULL;
 }
 
 #ifdef CONFIG_HIBERNATE_CALLBACKS
@@ -701,8 +694,7 @@
 		goto out;
 
 	zpci_map_resources(pdev);
-	zpci_register_ioat(zdev, 0, zdev->start_dma + PAGE_OFFSET,
-			   zdev->start_dma + zdev->iommu_size - 1,
+	zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
 			   (u64) zdev->dma_table);
 
 out:
@@ -871,26 +863,36 @@
 
 static int zpci_mem_init(void)
 {
+	BUILD_BUG_ON(!is_power_of_2(__alignof__(struct zpci_fmb)) ||
+		     __alignof__(struct zpci_fmb) < sizeof(struct zpci_fmb));
+
 	zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
-				16, 0, NULL);
+					   __alignof__(struct zpci_fmb), 0, NULL);
 	if (!zdev_fmb_cache)
-		goto error_zdev;
+		goto error_fmb;
 
-	/* TODO: use realloc */
-	zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start),
-				   GFP_KERNEL);
+	zpci_iomap_start = kcalloc(ZPCI_IOMAP_ENTRIES,
+				   sizeof(*zpci_iomap_start), GFP_KERNEL);
 	if (!zpci_iomap_start)
 		goto error_iomap;
-	return 0;
 
+	zpci_iomap_bitmap = kcalloc(BITS_TO_LONGS(ZPCI_IOMAP_ENTRIES),
+				    sizeof(*zpci_iomap_bitmap), GFP_KERNEL);
+	if (!zpci_iomap_bitmap)
+		goto error_iomap_bitmap;
+
+	return 0;
+error_iomap_bitmap:
+	kfree(zpci_iomap_start);
 error_iomap:
 	kmem_cache_destroy(zdev_fmb_cache);
-error_zdev:
+error_fmb:
 	return -ENOMEM;
 }
 
 static void zpci_mem_exit(void)
 {
+	kfree(zpci_iomap_bitmap);
 	kfree(zpci_iomap_start);
 	kmem_cache_destroy(zdev_fmb_cache);
 }
@@ -919,7 +921,7 @@
 	if (!s390_pci_probe)
 		return 0;
 
-	if (!test_facility(69) || !test_facility(71) || !test_facility(72))
+	if (!test_facility(69) || !test_facility(71))
 		return 0;
 
 	rc = zpci_debug_init();
--- linux-4.4.0.orig/arch/s390/pci/pci_clp.c
+++ linux-4.4.0/arch/s390/pci/pci_clp.c
@@ -8,13 +8,19 @@
 #define KMSG_COMPONENT "zpci"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/compat.h>
 #include <linux/kernel.h>
+#include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <linux/uaccess.h>
 #include <asm/pci_debug.h>
 #include <asm/pci_clp.h>
+#include <asm/compat.h>
+#include <asm/clp.h>
+#include <uapi/asm/clp.h>
 
 static inline void zpci_err_clp(unsigned int rsp, int rc)
 {
@@ -27,21 +33,43 @@
 }
 
 /*
- * Call Logical Processor
- * Retry logic is handled by the caller.
+ * Call Logical Processor with c=1, lps=0 and command 1
+ * to get the bit mask of installed logical processors
  */
-static inline u8 clp_instr(void *data)
+static inline int clp_get_ilp(unsigned long *ilp)
+{
+	unsigned long mask;
+	int cc = 3;
+
+	asm volatile (
+		"	.insn	rrf,0xb9a00000,%[mask],%[cmd],8,0\n"
+		"0:	ipm	%[cc]\n"
+		"	srl	%[cc],28\n"
+		"1:\n"
+		EX_TABLE(0b, 1b)
+		: [cc] "+d" (cc), [mask] "=d" (mask) : [cmd] "a" (1)
+		: "cc");
+	*ilp = mask;
+	return cc;
+}
+
+/*
+ * Call Logical Processor with c=0, the give constant lps and an lpcb request.
+ */
+static inline int clp_req(void *data, unsigned int lps)
 {
 	struct { u8 _[CLP_BLK_SIZE]; } *req = data;
 	u64 ignored;
-	u8 cc;
+	int cc = 3;
 
 	asm volatile (
-		"	.insn	rrf,0xb9a00000,%[ign],%[req],0x0,0x2\n"
-		"	ipm	%[cc]\n"
+		"	.insn	rrf,0xb9a00000,%[ign],%[req],0,%[lps]\n"
+		"0:	ipm	%[cc]\n"
 		"	srl	%[cc],28\n"
-		: [cc] "=d" (cc), [ign] "=d" (ignored), "+m" (*req)
-		: [req] "a" (req)
+		"1:\n"
+		EX_TABLE(0b, 1b)
+		: [cc] "+d" (cc), [ign] "=d" (ignored), "+m" (*req)
+		: [req] "a" (req), [lps] "i" (lps)
 		: "cc");
 	return cc;
 }
@@ -90,7 +118,7 @@
 	rrb->response.hdr.len = sizeof(rrb->response);
 	rrb->request.pfgid = pfgid;
 
-	rc = clp_instr(rrb);
+	rc = clp_req(rrb, CLP_LPS_PCI);
 	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
 		clp_store_query_pci_fngrp(zdev, &rrb->response);
 	else {
@@ -143,7 +171,7 @@
 	rrb->response.hdr.len = sizeof(rrb->response);
 	rrb->request.fh = fh;
 
-	rc = clp_instr(rrb);
+	rc = clp_req(rrb, CLP_LPS_PCI);
 	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
 		rc = clp_store_query_pci_fn(zdev, &rrb->response);
 		if (rc)
@@ -214,7 +242,7 @@
 		rrb->request.oc = command;
 		rrb->request.ndas = nr_dma_as;
 
-		rc = clp_instr(rrb);
+		rc = clp_req(rrb, CLP_LPS_PCI);
 		if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) {
 			retries--;
 			if (retries < 0)
@@ -280,7 +308,7 @@
 		rrb->request.resume_token = resume_token;
 
 		/* Get PCI function handle list */
-		rc = clp_instr(rrb);
+		rc = clp_req(rrb, CLP_LPS_PCI);
 		if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
 			zpci_err("List PCI FN:\n");
 			zpci_err_clp(rrb->response.hdr.rsp, rc);
@@ -391,3 +419,198 @@
 	clp_free_block(rrb);
 	return rc;
 }
+
+static int clp_base_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb)
+{
+	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
+
+	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
+	    lpcb->response.hdr.len > limit)
+		return -EINVAL;
+	return clp_req(lpcb, CLP_LPS_BASE) ? -EOPNOTSUPP : 0;
+}
+
+static int clp_base_command(struct clp_req *req, struct clp_req_hdr *lpcb)
+{
+	switch (lpcb->cmd) {
+	case 0x0001: /* store logical-processor characteristics */
+		return clp_base_slpc(req, (void *) lpcb);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int clp_pci_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb)
+{
+	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
+
+	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
+	    lpcb->response.hdr.len > limit)
+		return -EINVAL;
+	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
+}
+
+static int clp_pci_list(struct clp_req *req, struct clp_req_rsp_list_pci *lpcb)
+{
+	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
+
+	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
+	    lpcb->response.hdr.len > limit)
+		return -EINVAL;
+	if (lpcb->request.reserved2 != 0)
+		return -EINVAL;
+	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
+}
+
+static int clp_pci_query(struct clp_req *req,
+			 struct clp_req_rsp_query_pci *lpcb)
+{
+	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
+
+	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
+	    lpcb->response.hdr.len > limit)
+		return -EINVAL;
+	if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0)
+		return -EINVAL;
+	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
+}
+
+static int clp_pci_query_grp(struct clp_req *req,
+			     struct clp_req_rsp_query_pci_grp *lpcb)
+{
+	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
+
+	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
+	    lpcb->response.hdr.len > limit)
+		return -EINVAL;
+	if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0 ||
+	    lpcb->request.reserved4 != 0)
+		return -EINVAL;
+	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
+}
+
+static int clp_pci_command(struct clp_req *req, struct clp_req_hdr *lpcb)
+{
+	switch (lpcb->cmd) {
+	case 0x0001: /* store logical-processor characteristics */
+		return clp_pci_slpc(req, (void *) lpcb);
+	case 0x0002: /* list PCI functions */
+		return clp_pci_list(req, (void *) lpcb);
+	case 0x0003: /* query PCI function */
+		return clp_pci_query(req, (void *) lpcb);
+	case 0x0004: /* query PCI function group */
+		return clp_pci_query_grp(req, (void *) lpcb);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int clp_normal_command(struct clp_req *req)
+{
+	struct clp_req_hdr *lpcb;
+	void __user *uptr;
+	int rc;
+
+	rc = -EINVAL;
+	if (req->lps != 0 && req->lps != 2)
+		goto out;
+
+	rc = -ENOMEM;
+	lpcb = clp_alloc_block(GFP_KERNEL);
+	if (!lpcb)
+		goto out;
+
+	rc = -EFAULT;
+	uptr = (void __force __user *)(unsigned long) req->data_p;
+	if (copy_from_user(lpcb, uptr, PAGE_SIZE) != 0)
+		goto out_free;
+
+	rc = -EINVAL;
+	if (lpcb->fmt != 0 || lpcb->reserved1 != 0 || lpcb->reserved2 != 0)
+		goto out_free;
+
+	switch (req->lps) {
+	case 0:
+		rc = clp_base_command(req, lpcb);
+		break;
+	case 2:
+		rc = clp_pci_command(req, lpcb);
+		break;
+	}
+	if (rc)
+		goto out_free;
+
+	rc = -EFAULT;
+	if (copy_to_user(uptr, lpcb, PAGE_SIZE) != 0)
+		goto out_free;
+
+	rc = 0;
+
+out_free:
+	clp_free_block(lpcb);
+out:
+	return rc;
+}
+
+static int clp_immediate_command(struct clp_req *req)
+{
+	void __user *uptr;
+	unsigned long ilp;
+	int exists;
+
+	if (req->cmd > 1 || clp_get_ilp(&ilp) != 0)
+		return -EINVAL;
+
+	uptr = (void __force __user *)(unsigned long) req->data_p;
+	if (req->cmd == 0) {
+		/* Command code 0: test for a specific processor */
+		exists = test_bit_inv(req->lps, &ilp);
+		return put_user(exists, (int __user *) uptr);
+	}
+	/* Command code 1: return bit mask of installed processors */
+	return put_user(ilp, (unsigned long __user *) uptr);
+}
+
+static long clp_misc_ioctl(struct file *filp, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct clp_req req;
+	void __user *argp;
+
+	if (cmd != CLP_SYNC)
+		return -EINVAL;
+
+	argp = is_compat_task() ? compat_ptr(arg) : (void __user *) arg;
+	if (copy_from_user(&req, argp, sizeof(req)))
+		return -EFAULT;
+	if (req.r != 0)
+		return -EINVAL;
+	return req.c ? clp_immediate_command(&req) : clp_normal_command(&req);
+}
+
+static int clp_misc_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+static const struct file_operations clp_misc_fops = {
+	.owner = THIS_MODULE,
+	.open = nonseekable_open,
+	.release = clp_misc_release,
+	.unlocked_ioctl = clp_misc_ioctl,
+	.compat_ioctl = clp_misc_ioctl,
+	.llseek = no_llseek,
+};
+
+static struct miscdevice clp_misc_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "clp",
+	.fops = &clp_misc_fops,
+};
+
+static int __init clp_misc_init(void)
+{
+	return misc_register(&clp_misc_device);
+}
+
+device_initcall(clp_misc_init);
--- linux-4.4.0.orig/arch/s390/pci/pci_debug.c
+++ linux-4.4.0/arch/s390/pci/pci_debug.c
@@ -128,10 +128,9 @@
 	.release = single_release,
 };
 
-void zpci_debug_init_device(struct zpci_dev *zdev)
+void zpci_debug_init_device(struct zpci_dev *zdev, const char *name)
 {
-	zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev),
-					       debugfs_root);
+	zdev->debugfs_dev = debugfs_create_dir(name, debugfs_root);
 	if (IS_ERR(zdev->debugfs_dev))
 		zdev->debugfs_dev = NULL;
 
--- linux-4.4.0.orig/arch/s390/pci/pci_dma.c
+++ linux-4.4.0/arch/s390/pci/pci_dma.c
@@ -217,27 +217,29 @@
 	dma_free_cpu_table(table);
 }
 
-static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev,
+static unsigned long __dma_alloc_iommu(struct device *dev,
 				       unsigned long start, int size)
 {
+	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
 	unsigned long boundary_size;
 
-	boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1,
+	boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
 			      PAGE_SIZE) >> PAGE_SHIFT;
 	return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages,
 				start, size, 0, boundary_size, 0);
 }
 
-static unsigned long dma_alloc_iommu(struct zpci_dev *zdev, int size)
+static unsigned long dma_alloc_iommu(struct device *dev, int size)
 {
+	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
 	unsigned long offset, flags;
 	int wrap = 0;
 
 	spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
-	offset = __dma_alloc_iommu(zdev, zdev->next_bit, size);
+	offset = __dma_alloc_iommu(dev, zdev->next_bit, size);
 	if (offset == -1) {
 		/* wrap-around */
-		offset = __dma_alloc_iommu(zdev, 0, size);
+		offset = __dma_alloc_iommu(dev, 0, size);
 		wrap = 1;
 	}
 
@@ -251,8 +253,9 @@
 	return offset;
 }
 
-static void dma_free_iommu(struct zpci_dev *zdev, unsigned long offset, int size)
+static void dma_free_iommu(struct device *dev, unsigned long offset, int size)
 {
+	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
 	unsigned long flags;
 
 	spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
@@ -293,7 +296,7 @@
 
 	/* This rounds up number of pages based on size and offset */
 	nr_pages = iommu_num_pages(pa, size, PAGE_SIZE);
-	iommu_page_index = dma_alloc_iommu(zdev, nr_pages);
+	iommu_page_index = dma_alloc_iommu(dev, nr_pages);
 	if (iommu_page_index == -1) {
 		ret = -ENOSPC;
 		goto out_err;
@@ -319,7 +322,7 @@
 	return dma_addr + (offset & ~PAGE_MASK);
 
 out_free:
-	dma_free_iommu(zdev, iommu_page_index, nr_pages);
+	dma_free_iommu(dev, iommu_page_index, nr_pages);
 out_err:
 	zpci_err("map error:\n");
 	zpci_err_dma(ret, pa);
@@ -346,7 +349,7 @@
 
 	atomic64_add(npages, &zdev->unmapped_pages);
 	iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT;
-	dma_free_iommu(zdev, iommu_page_index, npages);
+	dma_free_iommu(dev, iommu_page_index, npages);
 }
 
 static void *s390_dma_alloc(struct device *dev, size_t size,
@@ -366,8 +369,7 @@
 	pa = page_to_phys(page);
 	memset((void *) pa, 0, size);
 
-	map = s390_dma_map_pages(dev, page, pa % PAGE_SIZE,
-				 size, DMA_BIDIRECTIONAL, NULL);
+	map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, NULL);
 	if (dma_mapping_error(dev, map)) {
 		free_pages(pa, get_order(size));
 		return NULL;
@@ -455,29 +457,42 @@
 	zdev->dma_table = dma_alloc_cpu_table();
 	if (!zdev->dma_table) {
 		rc = -ENOMEM;
-		goto out_clean;
+		goto out;
 	}
 
-	zdev->iommu_size = (unsigned long) high_memory - PAGE_OFFSET;
+	/*
+	 * Restrict the iommu bitmap size to the minimum of the following:
+	 * - main memory size
+	 * - 3-level pagetable address limit minus start_dma offset
+	 * - DMA address range allowed by the hardware (clp query pci fn)
+	 *
+	 * Also set zdev->end_dma to the actual end address of the usable
+	 * range, instead of the theoretical maximum as reported by hardware.
+	 */
+	zdev->iommu_size = min3((u64) high_memory,
+				ZPCI_TABLE_SIZE_RT - zdev->start_dma,
+				zdev->end_dma - zdev->start_dma + 1);
+	zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1;
 	zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT;
 	zdev->iommu_bitmap = vzalloc(zdev->iommu_pages / 8);
 	if (!zdev->iommu_bitmap) {
 		rc = -ENOMEM;
-		goto out_reg;
+		goto free_dma_table;
 	}
 
-	rc = zpci_register_ioat(zdev,
-				0,
-				zdev->start_dma + PAGE_OFFSET,
-				zdev->start_dma + zdev->iommu_size - 1,
+	rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
 				(u64) zdev->dma_table);
 	if (rc)
-		goto out_reg;
-	return 0;
+		goto free_bitmap;
 
-out_reg:
+	return 0;
+free_bitmap:
+	vfree(zdev->iommu_bitmap);
+	zdev->iommu_bitmap = NULL;
+free_dma_table:
 	dma_free_cpu_table(zdev->dma_table);
-out_clean:
+	zdev->dma_table = NULL;
+out:
 	return rc;
 }
 
--- linux-4.4.0.orig/arch/s390/pci/pci_event.c
+++ linux-4.4.0/arch/s390/pci/pci_event.c
@@ -46,13 +46,22 @@
 static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
 {
 	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
-	struct pci_dev *pdev = zdev ? zdev->pdev : NULL;
+	struct pci_dev *pdev = NULL;
 
 	zpci_err("error CCDF:\n");
 	zpci_err_hex(ccdf, sizeof(*ccdf));
 
+	if (zdev)
+		pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN);
+
 	pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n",
 	       pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
+
+	if (!pdev)
+		return;
+
+	pdev->error_state = pci_channel_io_perm_failure;
+	pci_dev_put(pdev);
 }
 
 void zpci_event_error(void *data)
@@ -64,9 +73,12 @@
 static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
 {
 	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
-	struct pci_dev *pdev = zdev ? zdev->pdev : NULL;
+	struct pci_dev *pdev = NULL;
 	int ret;
 
+	if (zdev)
+		pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN);
+
 	pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n",
 		pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
 	zpci_err("avail CCDF:\n");
@@ -133,6 +145,8 @@
 	default:
 		break;
 	}
+	if (pdev)
+		pci_dev_put(pdev);
 }
 
 void zpci_event_availability(void *data)
--- linux-4.4.0.orig/arch/s390/pci/pci_insn.c
+++ linux-4.4.0/arch/s390/pci/pci_insn.c
@@ -7,6 +7,7 @@
 #include <linux/export.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <asm/facility.h>
 #include <asm/pci_insn.h>
 #include <asm/pci_debug.h>
 #include <asm/processor.h>
@@ -91,11 +92,14 @@
 }
 
 /* Set Interruption Controls */
-void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
+int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
 {
+	if (!test_facility(72))
+		return -EIO;
 	asm volatile (
 		"	.insn	rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
 		: : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
+	return 0;
 }
 
 /* PCI Load */
--- linux-4.4.0.orig/arch/score/include/asm/uaccess.h
+++ linux-4.4.0/arch/score/include/asm/uaccess.h
@@ -163,7 +163,7 @@
 		__get_user_asm(val, "lw", ptr);				\
 		 break;							\
 	case 8: 							\
-		if ((copy_from_user((void *)&val, ptr, 8)) == 0)	\
+		if (__copy_from_user((void *)&val, ptr, 8) == 0)	\
 			__gu_err = 0;					\
 		else							\
 			__gu_err = -EFAULT;				\
@@ -188,6 +188,8 @@
 									\
 	if (likely(access_ok(VERIFY_READ, __gu_ptr, size)))		\
 		__get_user_common((x), size, __gu_ptr);			\
+	else								\
+		(x) = 0;						\
 									\
 	__gu_err;							\
 })
@@ -201,6 +203,7 @@
 		"2:\n"							\
 		".section .fixup,\"ax\"\n"				\
 		"3:li	%0, %4\n"					\
+		"li	%1, 0\n"					\
 		"j	2b\n"						\
 		".previous\n"						\
 		".section __ex_table,\"a\"\n"				\
@@ -298,35 +301,34 @@
 static inline unsigned long
 copy_from_user(void *to, const void *from, unsigned long len)
 {
-	unsigned long over;
+	unsigned long res = len;
 
-	if (access_ok(VERIFY_READ, from, len))
-		return __copy_tofrom_user(to, from, len);
+	if (likely(access_ok(VERIFY_READ, from, len)))
+		res = __copy_tofrom_user(to, from, len);
 
-	if ((unsigned long)from < TASK_SIZE) {
-		over = (unsigned long)from + len - TASK_SIZE;
-		return __copy_tofrom_user(to, from, len - over) + over;
-	}
-	return len;
+	if (unlikely(res))
+		memset(to + (len - res), 0, res);
+
+	return res;
 }
 
 static inline unsigned long
 copy_to_user(void *to, const void *from, unsigned long len)
 {
-	unsigned long over;
-
-	if (access_ok(VERIFY_WRITE, to, len))
-		return __copy_tofrom_user(to, from, len);
+	if (likely(access_ok(VERIFY_WRITE, to, len)))
+		len = __copy_tofrom_user(to, from, len);
 
-	if ((unsigned long)to < TASK_SIZE) {
-		over = (unsigned long)to + len - TASK_SIZE;
-		return __copy_tofrom_user(to, from, len - over) + over;
-	}
 	return len;
 }
 
-#define __copy_from_user(to, from, len)	\
-		__copy_tofrom_user((to), (from), (len))
+static inline unsigned long
+__copy_from_user(void *to, const void *from, unsigned long len)
+{
+	unsigned long left = __copy_tofrom_user(to, from, len);
+	if (unlikely(left))
+		memset(to + (len - left), 0, left);
+	return left;
+}
 
 #define __copy_to_user(to, from, len)		\
 		__copy_tofrom_user((to), (from), (len))
@@ -340,17 +342,17 @@
 static inline unsigned long
 __copy_from_user_inatomic(void *to, const void *from, unsigned long len)
 {
-	return __copy_from_user(to, from, len);
+	return __copy_tofrom_user(to, from, len);
 }
 
-#define __copy_in_user(to, from, len)	__copy_from_user(to, from, len)
+#define __copy_in_user(to, from, len)	__copy_tofrom_user(to, from, len)
 
 static inline unsigned long
 copy_in_user(void *to, const void *from, unsigned long len)
 {
 	if (access_ok(VERIFY_READ, from, len) &&
 		      access_ok(VERFITY_WRITE, to, len))
-		return copy_from_user(to, from, len);
+		return __copy_tofrom_user(to, from, len);
 }
 
 /*
--- linux-4.4.0.orig/arch/sh/boards/mach-landisk/setup.c
+++ linux-4.4.0/arch/sh/boards/mach-landisk/setup.c
@@ -85,6 +85,9 @@
 
 static void __init landisk_setup(char **cmdline_p)
 {
+	/* I/O port identity mapping */
+	__set_io_port_base(0);
+
 	/* LED ON */
 	__raw_writeb(__raw_readb(PA_LED) | 0x03, PA_LED);
 
--- linux-4.4.0.orig/arch/sh/boards/mach-se/770x/setup.c
+++ linux-4.4.0/arch/sh/boards/mach-se/770x/setup.c
@@ -8,6 +8,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/sh_eth.h>
 #include <mach-se/mach/se.h>
 #include <mach-se/mach/mrshpc.h>
 #include <asm/machvec.h>
@@ -114,6 +115,11 @@
 #if defined(CONFIG_CPU_SUBTYPE_SH7710) ||\
 	defined(CONFIG_CPU_SUBTYPE_SH7712)
 /* SH771X Ethernet driver */
+static struct sh_eth_plat_data sh_eth_plat = {
+	.phy = PHY_ID,
+	.phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
 static struct resource sh_eth0_resources[] = {
 	[0] = {
 		.start = SH_ETH0_BASE,
@@ -131,7 +137,7 @@
 	.name = "sh771x-ether",
 	.id = 0,
 	.dev = {
-		.platform_data = PHY_ID,
+		.platform_data = &sh_eth_plat,
 	},
 	.num_resources = ARRAY_SIZE(sh_eth0_resources),
 	.resource = sh_eth0_resources,
@@ -154,7 +160,7 @@
 	.name = "sh771x-ether",
 	.id = 1,
 	.dev = {
-		.platform_data = PHY_ID,
+		.platform_data = &sh_eth_plat,
 	},
 	.num_resources = ARRAY_SIZE(sh_eth1_resources),
 	.resource = sh_eth1_resources,
--- linux-4.4.0.orig/arch/sh/drivers/dma/Kconfig
+++ linux-4.4.0/arch/sh/drivers/dma/Kconfig
@@ -62,8 +62,7 @@
 
 config G2_DMA
 	tristate "G2 Bus DMA support"
-	depends on SH_DREAMCAST
-	select SH_DMA_API
+	depends on SH_DREAMCAST && SH_DMA_API
 	help
 	  This enables support for the DMA controller for the Dreamcast's
 	  G2 bus. Drivers that want this will generally enable this on
--- linux-4.4.0.orig/arch/sh/drivers/push-switch.c
+++ linux-4.4.0/arch/sh/drivers/push-switch.c
@@ -107,8 +107,8 @@
 		device_remove_file(&pdev->dev, &dev_attr_switch);
 
 	platform_set_drvdata(pdev, NULL);
-	flush_work(&psw->work);
 	del_timer_sync(&psw->debounce);
+	flush_work(&psw->work);
 	free_irq(irq, pdev);
 
 	kfree(psw);
--- linux-4.4.0.orig/arch/sh/include/asm/futex.h
+++ linux-4.4.0/arch/sh/include/asm/futex.h
@@ -10,20 +10,11 @@
 /* XXX: UP variants, fix for SH-4A and SMP.. */
 #include <asm/futex-irq.h>
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 
 	switch (op) {
@@ -49,17 +40,8 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
 
 	return ret;
 }
--- linux-4.4.0.orig/arch/sh/include/asm/io.h
+++ linux-4.4.0/arch/sh/include/asm/io.h
@@ -370,7 +370,11 @@
 
 #define ioremap_nocache	ioremap
 #define ioremap_uc	ioremap
-#define iounmap		__iounmap
+
+static inline void iounmap(void __iomem *addr)
+{
+	__iounmap(addr);
+}
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
--- linux-4.4.0.orig/arch/sh/include/asm/tlb.h
+++ linux-4.4.0/arch/sh/include/asm/tlb.h
@@ -65,6 +65,16 @@
 		tlb->end = address + PAGE_SIZE;
 }
 
+static inline void
+tlb_flush_pmd_range(struct mmu_gather *tlb, unsigned long address,
+		    unsigned long size)
+{
+	if (tlb->start > address)
+		tlb->start = address;
+	if (tlb->end < address + size)
+		tlb->end = address + size;
+}
+
 /*
  * In the case of tlb vma handling, we can optimise these away in the
  * case where we're doing a full MM flush.  When we're doing a munmap,
--- linux-4.4.0.orig/arch/sh/include/asm/uaccess.h
+++ linux-4.4.0/arch/sh/include/asm/uaccess.h
@@ -151,7 +151,10 @@
 	__kernel_size_t __copy_size = (__kernel_size_t) n;
 
 	if (__copy_size && __access_ok(__copy_from, __copy_size))
-		return __copy_user(to, from, __copy_size);
+		__copy_size = __copy_user(to, from, __copy_size);
+
+	if (unlikely(__copy_size))
+		memset(to + (n - __copy_size), 0, __copy_size);
 
 	return __copy_size;
 }
--- linux-4.4.0.orig/arch/sh/include/asm/uaccess_64.h
+++ linux-4.4.0/arch/sh/include/asm/uaccess_64.h
@@ -24,6 +24,7 @@
 #define __get_user_size(x,ptr,size,retval)			\
 do {								\
 	retval = 0;						\
+	x = 0;							\
 	switch (size) {						\
 	case 1:							\
 		retval = __get_user_asm_b((void *)&x,		\
--- linux-4.4.0.orig/arch/sh/include/cpu-sh2a/cpu/sh7269.h
+++ linux-4.4.0/arch/sh/include/cpu-sh2a/cpu/sh7269.h
@@ -79,8 +79,15 @@
 	GPIO_FN_WDTOVF,
 
 	/* CAN */
-	GPIO_FN_CTX1, GPIO_FN_CRX1, GPIO_FN_CTX0, GPIO_FN_CTX0_CTX1,
-	GPIO_FN_CRX0, GPIO_FN_CRX0_CRX1, GPIO_FN_CRX0_CRX1_CRX2,
+	GPIO_FN_CTX2, GPIO_FN_CRX2,
+	GPIO_FN_CTX1, GPIO_FN_CRX1,
+	GPIO_FN_CTX0, GPIO_FN_CRX0,
+	GPIO_FN_CTX0_CTX1, GPIO_FN_CRX0_CRX1,
+	GPIO_FN_CTX0_CTX1_CTX2, GPIO_FN_CRX0_CRX1_CRX2,
+	GPIO_FN_CTX2_PJ21, GPIO_FN_CRX2_PJ20,
+	GPIO_FN_CTX1_PJ23, GPIO_FN_CRX1_PJ22,
+	GPIO_FN_CTX0_CTX1_PJ23, GPIO_FN_CRX0_CRX1_PJ22,
+	GPIO_FN_CTX0_CTX1_CTX2_PJ21, GPIO_FN_CRX0_CRX1_CRX2_PJ20,
 
 	/* DMAC */
 	GPIO_FN_TEND0, GPIO_FN_DACK0, GPIO_FN_DREQ0,
--- linux-4.4.0.orig/arch/sh/include/cpu-sh4/cpu/sh7734.h
+++ linux-4.4.0/arch/sh/include/cpu-sh4/cpu/sh7734.h
@@ -133,7 +133,7 @@
 	GPIO_FN_EX_WAIT1, GPIO_FN_SD1_DAT0_A, GPIO_FN_DREQ2, GPIO_FN_CAN1_TX_C,
 		GPIO_FN_ET0_LINK_C, GPIO_FN_ET0_ETXD5_A,
 	GPIO_FN_EX_WAIT0, GPIO_FN_TCLK1_B,
-	GPIO_FN_RD_WR, GPIO_FN_TCLK0,
+	GPIO_FN_RD_WR, GPIO_FN_TCLK0, GPIO_FN_CAN_CLK_B, GPIO_FN_ET0_ETXD4,
 	GPIO_FN_EX_CS5, GPIO_FN_SD1_CMD_A, GPIO_FN_ATADIR, GPIO_FN_QSSL_B,
 		GPIO_FN_ET0_ETXD3_A,
 	GPIO_FN_EX_CS4, GPIO_FN_SD1_WP_A, GPIO_FN_ATAWR, GPIO_FN_QMI_QIO1_B,
--- linux-4.4.0.orig/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+++ linux-4.4.0/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -165,7 +165,6 @@
 	.scscr		= SCSCR_TE | SCSCR_RE,
 	.type		= PORT_IRDA,
 	.ops		= &sh770x_sci_port_ops,
-	.regshift	= 1,
 };
 
 static struct resource scif2_resources[] = {
--- linux-4.4.0.orig/arch/sh/kernel/entry-common.S
+++ linux-4.4.0/arch/sh/kernel/entry-common.S
@@ -203,7 +203,7 @@
 	mov.l	@(OFF_R7,r15), r7   ! arg3
 	mov.l	@(OFF_R3,r15), r3   ! syscall_nr
 	!
-	mov.l	2f, r10			! Number of syscalls
+	mov.l	6f, r10			! Number of syscalls
 	cmp/hs	r10, r3
 	bf	syscall_call
 	mov	#-ENOSYS, r0
@@ -255,7 +255,7 @@
 	mov.l	@r8, r8
 	jsr	@r8
 	 nop
-	bra	__restore_all
+	bra	ret_from_exception
 	 nop
 	CFI_ENDPROC
 
@@ -348,7 +348,7 @@
 	tst	r9, r8
 	bf	syscall_trace_entry
 	!
-	mov.l	2f, r8			! Number of syscalls
+	mov.l	6f, r8			! Number of syscalls
 	cmp/hs	r8, r3
 	bt	syscall_badsys
 	!
@@ -387,7 +387,7 @@
 #if !defined(CONFIG_CPU_SH2)
 1:	.long	TRA
 #endif
-2:	.long	NR_syscalls
+6:	.long	NR_syscalls
 3:	.long	sys_call_table
 7:	.long	do_syscall_trace_enter
 8:	.long	do_syscall_trace_leave
--- linux-4.4.0.orig/arch/sh/kernel/hw_breakpoint.c
+++ linux-4.4.0/arch/sh/kernel/hw_breakpoint.c
@@ -160,6 +160,7 @@
 	switch (sh_type) {
 	case SH_BREAKPOINT_READ:
 		*gen_type = HW_BREAKPOINT_R;
+		break;
 	case SH_BREAKPOINT_WRITE:
 		*gen_type = HW_BREAKPOINT_W;
 		break;
--- linux-4.4.0.orig/arch/sh/kernel/sh_ksyms_32.c
+++ linux-4.4.0/arch/sh/kernel/sh_ksyms_32.c
@@ -34,6 +34,9 @@
 DECLARE_EXPORT(__lshrsi3);
 DECLARE_EXPORT(__ashrsi3);
 DECLARE_EXPORT(__ashlsi3);
+DECLARE_EXPORT(__lshrsi3_r0);
+DECLARE_EXPORT(__ashrsi3_r0);
+DECLARE_EXPORT(__ashlsi3_r0);
 DECLARE_EXPORT(__ashiftrt_r4_6);
 DECLARE_EXPORT(__ashiftrt_r4_7);
 DECLARE_EXPORT(__ashiftrt_r4_8);
--- linux-4.4.0.orig/arch/sh/kernel/traps_32.c
+++ linux-4.4.0/arch/sh/kernel/traps_32.c
@@ -607,7 +607,8 @@
 		break;
 	}
 
-	force_sig_info(SIGFPE, &info, current);
+	info.si_signo = SIGFPE;
+	force_sig_info(info.si_signo, &info, current);
 }
 #endif
 
--- linux-4.4.0.orig/arch/sh/lib/ashlsi3.S
+++ linux-4.4.0/arch/sh/lib/ashlsi3.S
@@ -54,21 +54,38 @@
 !
 ! (none)
 !
+! __ashlsi3_r0
+!
+! Entry:
+!
+! r4: Value to shift
+! r0: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
+
+
 	.global	__ashlsi3
+	.global	__ashlsi3_r0
 	
 	.align	2
 __ashlsi3:
-	mov	#31,r0
-	and	r0,r5
+	mov	r5,r0
+	.align	2
+__ashlsi3_r0:
+	and	#31,r0
+	mov.l	r4,@-r15
+	mov	r0,r4
 	mova	ashlsi3_table,r0
-	mov.b	@(r0,r5),r5
-#ifdef __sh1__
-	add	r5,r0
+	mov.b	@(r0,r4),r4
+	add	r4,r0
 	jmp	@r0
-#else
-	braf	r5
-#endif
-	mov	r4,r0
+	mov.l	@r15+,r0
 
 	.align	2
 ashlsi3_table:
--- linux-4.4.0.orig/arch/sh/lib/ashrsi3.S
+++ linux-4.4.0/arch/sh/lib/ashrsi3.S
@@ -54,22 +54,37 @@
 !
 ! (none)
 !
+! __ashrsi3_r0
+!
+! Entry:
+!
+! r4: Value to shift
+! r0: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
 
 	.global	__ashrsi3
+	.global	__ashrsi3_r0
 	
 	.align	2
 __ashrsi3:
-	mov	#31,r0
-	and	r0,r5
+	mov	r5,r0
+	.align	2
+__ashrsi3_r0:
+	and	#31,r0
+	mov.l	r4,@-r15
+	mov	r0,r4
 	mova	ashrsi3_table,r0
-	mov.b	@(r0,r5),r5
-#ifdef __sh1__
-	add	r5,r0
+	mov.b	@(r0,r4),r4
+	add	r4,r0
 	jmp	@r0
-#else
-	braf	r5
-#endif
-	mov	r4,r0
+	mov.l	@r15+,r0
 
 	.align	2
 ashrsi3_table:
--- linux-4.4.0.orig/arch/sh/lib/lshrsi3.S
+++ linux-4.4.0/arch/sh/lib/lshrsi3.S
@@ -54,21 +54,37 @@
 !
 ! (none)
 !
+! __lshrsi3_r0
+!
+! Entry:
+!
+! r0: Value to shift
+! r5: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
+!
 	.global	__lshrsi3
+	.global	__lshrsi3_r0
 	
 	.align	2
 __lshrsi3:
-	mov	#31,r0
-	and	r0,r5
+	mov	r5,r0
+	.align	2
+__lshrsi3_r0:
+	and	#31,r0
+	mov.l	r4,@-r15
+	mov	r0,r4
 	mova	lshrsi3_table,r0
-	mov.b	@(r0,r5),r5
-#ifdef __sh1__
-	add	r5,r0
+	mov.b	@(r0,r4),r4
+	add	r4,r0
 	jmp	@r0
-#else
-	braf	r5
-#endif
-	mov	r4,r0
+	mov.l	@r15+,r0
 
 	.align	2
 lshrsi3_table:
--- linux-4.4.0.orig/arch/sh/mm/gup.c
+++ linux-4.4.0/arch/sh/mm/gup.c
@@ -258,7 +258,8 @@
 		pages += nr;
 
 		ret = get_user_pages_unlocked(current, mm, start,
-			(end - start) >> PAGE_SHIFT, write, 0, pages);
+			(end - start) >> PAGE_SHIFT, pages,
+			write ? FOLL_WRITE : 0);
 
 		/* Have to be a bit careful with return values */
 		if (nr > 0) {
--- linux-4.4.0.orig/arch/sh/mm/kmap.c
+++ linux-4.4.0/arch/sh/mm/kmap.c
@@ -36,6 +36,7 @@
 
 	BUG_ON(!test_bit(PG_dcache_clean, &page->flags));
 
+	preempt_disable();
 	pagefault_disable();
 
 	idx = FIX_CMAP_END -
@@ -64,4 +65,5 @@
 	}
 
 	pagefault_enable();
+	preempt_enable();
 }
--- linux-4.4.0.orig/arch/sh/mm/mmap.c
+++ linux-4.4.0/arch/sh/mm/mmap.c
@@ -63,7 +63,7 @@
 
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
@@ -113,7 +113,7 @@
 
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
--- linux-4.4.0.orig/arch/sparc/Kconfig
+++ linux-4.4.0/arch/sparc/Kconfig
@@ -182,9 +182,9 @@
 	int "Maximum number of CPUs"
 	depends on SMP
 	range 2 32 if SPARC32
-	range 2 1024 if SPARC64
+	range 2 4096 if SPARC64
 	default 32 if SPARC32
-	default 64 if SPARC64
+	default 4096 if SPARC64
 
 source kernel/Kconfig.hz
 
@@ -539,7 +539,7 @@
 	bool
 	depends on SPARC64
 	default y
-	select COMPAT_BINFMT_ELF
+	select COMPAT_BINFMT_ELF if BINFMT_ELF
 	select HAVE_UID16
 	select ARCH_WANT_OLD_COMPAT_IPC
 	select COMPAT_OLD_SIGACTION
@@ -549,9 +549,6 @@
 	depends on COMPAT && SYSVIPC
 	default y
 
-config KEYS_COMPAT
-	def_bool y if COMPAT && KEYS
-
 endmenu
 
 source "net/Kconfig"
--- linux-4.4.0.orig/arch/sparc/include/asm/atomic_64.h
+++ linux-4.4.0/arch/sparc/include/asm/atomic_64.h
@@ -74,7 +74,11 @@
 #define atomic64_add_negative(i, v) (atomic64_add_return(i, v) < 0)
 
 #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+static inline int atomic_xchg(atomic_t *v, int new)
+{
+	return xchg(&v->counter, new);
+}
 
 static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 {
--- linux-4.4.0.orig/arch/sparc/include/asm/bug.h
+++ linux-4.4.0/arch/sparc/include/asm/bug.h
@@ -8,10 +8,14 @@
 void do_BUG(const char *file, int line);
 #define BUG() do {					\
 	do_BUG(__FILE__, __LINE__);			\
+	barrier_before_unreachable();			\
 	__builtin_trap();				\
 } while (0)
 #else
-#define BUG()		__builtin_trap()
+#define BUG() do {					\
+	barrier_before_unreachable();			\
+	__builtin_trap();				\
+} while (0)
 #endif
 
 #define HAVE_ARCH_BUG
--- linux-4.4.0.orig/arch/sparc/include/asm/cmpxchg_64.h
+++ linux-4.4.0/arch/sparc/include/asm/cmpxchg_64.h
@@ -40,7 +40,12 @@
 	return val;
 }
 
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define xchg(ptr,x)							\
+({	__typeof__(*(ptr)) __ret;					\
+	__ret = (__typeof__(*(ptr)))					\
+		__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)));	\
+	__ret;								\
+})
 
 void __xchg_called_with_bad_pointer(void);
 
--- linux-4.4.0.orig/arch/sparc/include/asm/futex_64.h
+++ linux-4.4.0/arch/sparc/include/asm/futex_64.h
@@ -29,22 +29,14 @@
 	: "r" (uaddr), "r" (oparg), "i" (-EFAULT)	\
 	: "memory")
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret, tem;
 
-	if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
-		return -EFAULT;
 	if (unlikely((((unsigned long) uaddr) & 0x3UL)))
 		return -EINVAL;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
 	pagefault_disable();
 
 	switch (op) {
@@ -69,17 +61,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/sparc/include/asm/head_64.h
+++ linux-4.4.0/arch/sparc/include/asm/head_64.h
@@ -15,6 +15,10 @@
 
 #define	PTREGS_OFF	(STACK_BIAS + STACKFRAME_SZ)
 
+#define	RTRAP_PSTATE		(PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
+#define	RTRAP_PSTATE_IRQOFF	(PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV)
+#define RTRAP_PSTATE_AG_IRQOFF	(PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
+
 #define __CHEETAH_ID	0x003e0014
 #define __JALAPENO_ID	0x003e0016
 #define __SERRANO_ID	0x003e0022
--- linux-4.4.0.orig/arch/sparc/include/asm/mmu_64.h
+++ linux-4.4.0/arch/sparc/include/asm/mmu_64.h
@@ -52,7 +52,7 @@
 #define CTX_NR_MASK		TAG_CONTEXT_BITS
 #define CTX_HW_MASK		(CTX_NR_MASK | CTX_PGSZ_MASK)
 
-#define CTX_FIRST_VERSION	((_AC(1,UL) << CTX_VERSION_SHIFT) + _AC(1,UL))
+#define CTX_FIRST_VERSION	BIT(CTX_VERSION_SHIFT)
 #define CTX_VALID(__ctx)	\
 	 (!(((__ctx.sparc64_ctx_val) ^ tlb_context_cache) & CTX_VERSION_MASK))
 #define CTX_HWBITS(__ctx)	((__ctx.sparc64_ctx_val) & CTX_HW_MASK)
@@ -92,7 +92,8 @@
 typedef struct {
 	spinlock_t		lock;
 	unsigned long		sparc64_ctx_val;
-	unsigned long		huge_pte_count;
+	unsigned long		hugetlb_pte_count;
+	unsigned long		thp_pte_count;
 	struct tsb_config	tsb_block[MM_NUM_TSBS];
 	struct hv_tsb_descr	tsb_descr[MM_NUM_TSBS];
 } mm_context_t;
--- linux-4.4.0.orig/arch/sparc/include/asm/mmu_context_64.h
+++ linux-4.4.0/arch/sparc/include/asm/mmu_context_64.h
@@ -17,22 +17,19 @@
 extern unsigned long tlb_context_cache;
 extern unsigned long mmu_context_bmap[];
 
+DECLARE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm);
 void get_new_mmu_context(struct mm_struct *mm);
-#ifdef CONFIG_SMP
-void smp_new_mmu_context_version(void);
-#else
-#define smp_new_mmu_context_version() do { } while (0)
-#endif
-
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
 void destroy_context(struct mm_struct *mm);
 
 void __tsb_context_switch(unsigned long pgd_pa,
 			  struct tsb_config *tsb_base,
 			  struct tsb_config *tsb_huge,
-			  unsigned long tsb_descr_pa);
+			  unsigned long tsb_descr_pa,
+			  unsigned long secondary_ctx);
 
-static inline void tsb_context_switch(struct mm_struct *mm)
+static inline void tsb_context_switch_ctx(struct mm_struct *mm,
+					  unsigned long ctx)
 {
 	__tsb_context_switch(__pa(mm->pgd),
 			     &mm->context.tsb_block[0],
@@ -43,9 +40,12 @@
 #else
 			     NULL
 #endif
-			     , __pa(&mm->context.tsb_descr[0]));
+			     , __pa(&mm->context.tsb_descr[0]),
+			     ctx);
 }
 
+#define tsb_context_switch(X) tsb_context_switch_ctx(X, 0)
+
 void tsb_grow(struct mm_struct *mm,
 	      unsigned long tsb_index,
 	      unsigned long mm_rss);
@@ -74,8 +74,9 @@
 static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk)
 {
 	unsigned long ctx_valid, flags;
-	int cpu;
+	int cpu = smp_processor_id();
 
+	per_cpu(per_cpu_secondary_mm, cpu) = mm;
 	if (unlikely(mm == &init_mm))
 		return;
 
@@ -114,14 +115,12 @@
 	 * cpu0 to update it's TSB because at that point the cpu_vm_mask
 	 * only had cpu1 set in it.
 	 */
-	load_secondary_context(mm);
-	tsb_context_switch(mm);
+	tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
 
 	/* Any time a processor runs a context on an address space
 	 * for the first time, we must flush that context out of the
 	 * local TLB.
 	 */
-	cpu = smp_processor_id();
 	if (!ctx_valid || !cpumask_test_cpu(cpu, mm_cpumask(mm))) {
 		cpumask_set_cpu(cpu, mm_cpumask(mm));
 		__flush_tlb_mm(CTX_HWBITS(mm->context),
@@ -131,26 +130,7 @@
 }
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
-
-/* Activate a new MM instance for the current task. */
-static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
-{
-	unsigned long flags;
-	int cpu;
-
-	spin_lock_irqsave(&mm->context.lock, flags);
-	if (!CTX_VALID(mm->context))
-		get_new_mmu_context(mm);
-	cpu = smp_processor_id();
-	if (!cpumask_test_cpu(cpu, mm_cpumask(mm)))
-		cpumask_set_cpu(cpu, mm_cpumask(mm));
-
-	load_secondary_context(mm);
-	__flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT);
-	tsb_context_switch(mm);
-	spin_unlock_irqrestore(&mm->context.lock, flags);
-}
-
+#define activate_mm(active_mm, mm) switch_mm(active_mm, mm, NULL)
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC64_MMU_CONTEXT_H) */
--- linux-4.4.0.orig/arch/sparc/include/asm/page_64.h
+++ linux-4.4.0/arch/sparc/include/asm/page_64.h
@@ -25,6 +25,7 @@
 #define HPAGE_MASK		(~(HPAGE_SIZE - 1UL))
 #define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT - PAGE_SHIFT)
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+#define REAL_HPAGE_PER_HPAGE	(_AC(1,UL) << (HPAGE_SHIFT - REAL_HPAGE_SHIFT))
 #endif
 
 #ifndef __ASSEMBLY__
--- linux-4.4.0.orig/arch/sparc/include/asm/parport.h
+++ linux-4.4.0/arch/sparc/include/asm/parport.h
@@ -20,6 +20,7 @@
  */
 #define HAS_DMA
 
+#ifdef CONFIG_PARPORT_PC_FIFO
 static DEFINE_SPINLOCK(dma_spin_lock);
 
 #define claim_dma_lock() \
@@ -30,6 +31,7 @@
 
 #define release_dma_lock(__flags) \
 	spin_unlock_irqrestore(&dma_spin_lock, __flags);
+#endif
 
 static struct sparc_ebus_info {
 	struct ebus_dma_info info;
--- linux-4.4.0.orig/arch/sparc/include/asm/pgtable_32.h
+++ linux-4.4.0/arch/sparc/include/asm/pgtable_32.h
@@ -91,9 +91,9 @@
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-extern unsigned long empty_zero_page;
+extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 
-#define ZERO_PAGE(vaddr) (virt_to_page(&empty_zero_page))
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 
 /*
  * In general all page table modifications should use the V8 atomic
--- linux-4.4.0.orig/arch/sparc/include/asm/pgtable_64.h
+++ linux-4.4.0/arch/sparc/include/asm/pgtable_64.h
@@ -375,7 +375,7 @@
 #define pgprot_noncached pgprot_noncached
 
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-static inline pte_t pte_mkhuge(pte_t pte)
+static inline unsigned long __pte_huge_mask(void)
 {
 	unsigned long mask;
 
@@ -390,8 +390,19 @@
 	: "=r" (mask)
 	: "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V));
 
-	return __pte(pte_val(pte) | mask);
+	return mask;
+}
+
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+	return __pte(pte_val(pte) | __pte_huge_mask());
 }
+
+static inline bool is_hugetlb_pte(pte_t pte)
+{
+	return !!(pte_val(pte) & __pte_huge_mask());
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 static inline pmd_t pmd_mkhuge(pmd_t pmd)
 {
@@ -403,6 +414,11 @@
 	return __pmd(pte_val(pte));
 }
 #endif
+#else
+static inline bool is_hugetlb_pte(pte_t pte)
+{
+	return false;
+}
 #endif
 
 static inline pte_t pte_mkdirty(pte_t pte)
@@ -652,26 +668,27 @@
 	return pte_pfn(pte);
 }
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static inline unsigned long pmd_dirty(pmd_t pmd)
+#define __HAVE_ARCH_PMD_WRITE
+static inline unsigned long pmd_write(pmd_t pmd)
 {
 	pte_t pte = __pte(pmd_val(pmd));
 
-	return pte_dirty(pte);
+	return pte_write(pte);
 }
 
-static inline unsigned long pmd_young(pmd_t pmd)
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static inline unsigned long pmd_dirty(pmd_t pmd)
 {
 	pte_t pte = __pte(pmd_val(pmd));
 
-	return pte_young(pte);
+	return pte_dirty(pte);
 }
 
-static inline unsigned long pmd_write(pmd_t pmd)
+static inline unsigned long pmd_young(pmd_t pmd)
 {
 	pte_t pte = __pte(pmd_val(pmd));
 
-	return pte_write(pte);
+	return pte_young(pte);
 }
 
 static inline unsigned long pmd_trans_huge(pmd_t pmd)
@@ -865,6 +882,19 @@
 void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
 		   pte_t *ptep, pte_t orig, int fullmm);
 
+static void maybe_tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
+				pte_t *ptep, pte_t orig, int fullmm)
+{
+	/* It is more efficient to let flush_tlb_kernel_range()
+	 * handle init_mm tlb flushes.
+	 *
+	 * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U
+	 *             and SUN4V pte layout, so this inline test is fine.
+	 */
+	if (likely(mm != &init_mm) && pte_accessible(mm, orig))
+		tlb_batch_add(mm, vaddr, ptep, orig, fullmm);
+}
+
 #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
 static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 					    unsigned long addr,
@@ -881,15 +911,7 @@
 	pte_t orig = *ptep;
 
 	*ptep = pte;
-
-	/* It is more efficient to let flush_tlb_kernel_range()
-	 * handle init_mm tlb flushes.
-	 *
-	 * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U
-	 *             and SUN4V pte layout, so this inline test is fine.
-	 */
-	if (likely(mm != &init_mm) && pte_accessible(mm, orig))
-		tlb_batch_add(mm, addr, ptep, orig, fullmm);
+	maybe_tlb_batch_add(mm, addr, ptep, orig, fullmm);
 }
 
 #define set_pte_at(mm,addr,ptep,pte)	\
--- linux-4.4.0.orig/arch/sparc/include/asm/pil.h
+++ linux-4.4.0/arch/sparc/include/asm/pil.h
@@ -20,7 +20,6 @@
 #define PIL_SMP_CALL_FUNC	1
 #define PIL_SMP_RECEIVE_SIGNAL	2
 #define PIL_SMP_CAPTURE		3
-#define PIL_SMP_CTX_NEW_VERSION	4
 #define PIL_DEVICE_IRQ		5
 #define PIL_SMP_CALL_FUNC_SNGL	6
 #define PIL_DEFERRED_PCR_WORK	7
--- linux-4.4.0.orig/arch/sparc/include/asm/setup.h
+++ linux-4.4.0/arch/sparc/include/asm/setup.h
@@ -16,7 +16,7 @@
  */
 extern unsigned char boot_cpu_id;
 
-extern unsigned long empty_zero_page;
+extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 
 extern int serial_console;
 static inline int con_is_present(void)
@@ -59,8 +59,11 @@
 extern atomic_t dcpage_flushes_xcall;
 
 extern int sysctl_tsb_ratio;
-#endif
 
+#ifdef CONFIG_SERIAL_SUNHV
+void sunhv_migrate_hvcons_irq(int cpu);
+#endif
+#endif
 void sun_do_break(void);
 extern int stop_a_enabled;
 extern int scons_pwroff;
--- linux-4.4.0.orig/arch/sparc/include/asm/tlbflush_64.h
+++ linux-4.4.0/arch/sparc/include/asm/tlbflush_64.h
@@ -8,6 +8,7 @@
 #define TLB_BATCH_NR	192
 
 struct tlb_batch {
+	bool huge;
 	struct mm_struct *mm;
 	unsigned long tlb_nr;
 	unsigned long active;
@@ -16,7 +17,7 @@
 
 void flush_tsb_kernel_range(unsigned long start, unsigned long end);
 void flush_tsb_user(struct tlb_batch *tb);
-void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr);
+void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, bool huge);
 
 /* TLB flush operations. */
 
--- linux-4.4.0.orig/arch/sparc/include/asm/trap_block.h
+++ linux-4.4.0/arch/sparc/include/asm/trap_block.h
@@ -54,6 +54,7 @@
 void init_cur_cpu_trap(struct thread_info *);
 void setup_tba(void);
 extern int ncpus_probed;
+extern u64 cpu_mondo_counter[NR_CPUS];
 
 unsigned long real_hard_smp_processor_id(void);
 
--- linux-4.4.0.orig/arch/sparc/include/asm/ttable.h
+++ linux-4.4.0/arch/sparc/include/asm/ttable.h
@@ -589,8 +589,8 @@
 	 restored;					\
 	nop; nop; nop; nop; nop; nop;			\
 	nop; nop; nop; nop; nop;			\
-	ba,a,pt	%xcc, user_rtt_fill_fixup;		\
-	ba,a,pt	%xcc, user_rtt_fill_fixup;		\
+	ba,a,pt	%xcc, user_rtt_fill_fixup_dax;		\
+	ba,a,pt	%xcc, user_rtt_fill_fixup_mna;		\
 	ba,a,pt	%xcc, user_rtt_fill_fixup;
 
 
@@ -652,8 +652,8 @@
 	 restored;					\
 	nop; nop; nop; nop; nop;			\
 	nop; nop; nop;					\
-	ba,a,pt	%xcc, user_rtt_fill_fixup;		\
-	ba,a,pt	%xcc, user_rtt_fill_fixup;		\
+	ba,a,pt	%xcc, user_rtt_fill_fixup_dax;		\
+	ba,a,pt	%xcc, user_rtt_fill_fixup_mna;		\
 	ba,a,pt	%xcc, user_rtt_fill_fixup;
 
 
--- linux-4.4.0.orig/arch/sparc/include/asm/uaccess_32.h
+++ linux-4.4.0/arch/sparc/include/asm/uaccess_32.h
@@ -328,8 +328,10 @@
 {
 	if (n && __access_ok((unsigned long) from, n))
 		return __copy_user((__force void __user *) to, from, n);
-	else
+	else {
+		memset(to, 0, n);
 		return n;
+	}
 }
 
 static inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
--- linux-4.4.0.orig/arch/sparc/include/asm/uaccess_64.h
+++ linux-4.4.0/arch/sparc/include/asm/uaccess_64.h
@@ -98,7 +98,6 @@
         unsigned int insn, fixup;
 };
 
-void __ret_efault(void);
 void __retl_efault(void);
 
 /* Uh, these should become the main single-value transfer routines..
@@ -179,20 +178,6 @@
 	 __gu_ret;							     \
 })
 
-#define __get_user_nocheck_ret(data, addr, size, type, retval) ({	\
-	register unsigned long __gu_val __asm__ ("l1");			\
-	switch (size) {							\
-	case 1: __get_user_asm_ret(__gu_val, ub, addr, retval); break;	\
-	case 2: __get_user_asm_ret(__gu_val, uh, addr, retval); break;	\
-	case 4: __get_user_asm_ret(__gu_val, uw, addr, retval); break;	\
-	case 8: __get_user_asm_ret(__gu_val, x, addr, retval); break;	\
-	default:							\
-		if (__get_user_bad())					\
-			return retval;					\
-	}								\
-	data = (__force type) __gu_val;					\
-})
-
 #define __get_user_asm(x, size, addr, ret)				\
 __asm__ __volatile__(							\
 		"/* Get user asm, inline. */\n"				\
@@ -214,80 +199,35 @@
 	       : "=r" (ret), "=r" (x) : "r" (__m(addr)),		\
 		 "i" (-EFAULT))
 
-#define __get_user_asm_ret(x, size, addr, retval)			\
-if (__builtin_constant_p(retval) && retval == -EFAULT)			\
-	__asm__ __volatile__(						\
-		"/* Get user asm ret, inline. */\n"			\
-	"1:\t"	"ld"#size "a [%1] %%asi, %0\n\n\t"			\
-		".section __ex_table,\"a\"\n\t"				\
-		".align	4\n\t"						\
-		".word	1b,__ret_efault\n\n\t"				\
-		".previous\n\t"						\
-	       : "=r" (x) : "r" (__m(addr)));				\
-else									\
-	__asm__ __volatile__(						\
-		"/* Get user asm ret, inline. */\n"			\
-	"1:\t"	"ld"#size "a [%1] %%asi, %0\n\n\t"			\
-		".section .fixup,#alloc,#execinstr\n\t"			\
-		".align	4\n"						\
-	"3:\n\t"							\
-		"ret\n\t"						\
-		" restore %%g0, %2, %%o0\n\n\t"				\
-		".previous\n\t"						\
-		".section __ex_table,\"a\"\n\t"				\
-		".align	4\n\t"						\
-		".word	1b, 3b\n\n\t"					\
-		".previous\n\t"						\
-	       : "=r" (x) : "r" (__m(addr)), "i" (retval))
-
 int __get_user_bad(void);
 
 unsigned long __must_check ___copy_from_user(void *to,
 					     const void __user *from,
 					     unsigned long size);
-unsigned long copy_from_user_fixup(void *to, const void __user *from,
-				   unsigned long size);
 static inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long size)
 {
-	unsigned long ret = ___copy_from_user(to, from, size);
-
-	if (unlikely(ret))
-		ret = copy_from_user_fixup(to, from, size);
-
-	return ret;
+	return ___copy_from_user(to, from, size);
 }
 #define __copy_from_user copy_from_user
 
 unsigned long __must_check ___copy_to_user(void __user *to,
 					   const void *from,
 					   unsigned long size);
-unsigned long copy_to_user_fixup(void __user *to, const void *from,
-				 unsigned long size);
 static inline unsigned long __must_check
 copy_to_user(void __user *to, const void *from, unsigned long size)
 {
-	unsigned long ret = ___copy_to_user(to, from, size);
-
-	if (unlikely(ret))
-		ret = copy_to_user_fixup(to, from, size);
-	return ret;
+	return ___copy_to_user(to, from, size);
 }
 #define __copy_to_user copy_to_user
 
 unsigned long __must_check ___copy_in_user(void __user *to,
 					   const void __user *from,
 					   unsigned long size);
-unsigned long copy_in_user_fixup(void __user *to, void __user *from,
-				 unsigned long size);
 static inline unsigned long __must_check
 copy_in_user(void __user *to, void __user *from, unsigned long size)
 {
-	unsigned long ret = ___copy_in_user(to, from, size);
-
-	if (unlikely(ret))
-		ret = copy_in_user_fixup(to, from, size);
-	return ret;
+	return ___copy_in_user(to, from, size);
 }
 #define __copy_in_user copy_in_user
 
--- linux-4.4.0.orig/arch/sparc/include/asm/vio.h
+++ linux-4.4.0/arch/sparc/include/asm/vio.h
@@ -327,6 +327,7 @@
 	int			compat_len;
 
 	u64			dev_no;
+	u64			id;
 
 	unsigned long		channel_id;
 
--- linux-4.4.0.orig/arch/sparc/include/uapi/asm/ipcbuf.h
+++ linux-4.4.0/arch/sparc/include/uapi/asm/ipcbuf.h
@@ -14,19 +14,19 @@
 
 struct ipc64_perm
 {
-	__kernel_key_t	key;
-	__kernel_uid_t	uid;
-	__kernel_gid_t	gid;
-	__kernel_uid_t	cuid;
-	__kernel_gid_t	cgid;
+	__kernel_key_t		key;
+	__kernel_uid32_t	uid;
+	__kernel_gid32_t	gid;
+	__kernel_uid32_t	cuid;
+	__kernel_gid32_t	cgid;
 #ifndef __arch64__
-	unsigned short	__pad0;
+	unsigned short		__pad0;
 #endif
-	__kernel_mode_t	mode;
-	unsigned short	__pad1;
-	unsigned short	seq;
-	unsigned long long __unused1;
-	unsigned long long __unused2;
+	__kernel_mode_t		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned long long	__unused1;
+	unsigned long long	__unused2;
 };
 
 #endif /* __SPARC_IPCBUF_H */
--- linux-4.4.0.orig/arch/sparc/kernel/Makefile
+++ linux-4.4.0/arch/sparc/kernel/Makefile
@@ -21,6 +21,7 @@
 CFLAGS_REMOVE_pcr.o := -pg
 endif
 
+obj-$(CONFIG_SPARC64)   += urtt_fill.o
 obj-$(CONFIG_SPARC32)   += entry.o wof.o wuf.o
 obj-$(CONFIG_SPARC32)   += etrap_32.o
 obj-$(CONFIG_SPARC32)   += rtrap_32.o
--- linux-4.4.0.orig/arch/sparc/kernel/cherrs.S
+++ linux-4.4.0/arch/sparc/kernel/cherrs.S
@@ -214,8 +214,7 @@
 	subcc		%g1, %g2, %g1		! Next cacheline
 	bge,pt		%icc, 1b
 	 nop
-	ba,pt		%xcc, dcpe_icpe_tl1_common
-	 nop
+	ba,a,pt		%xcc, dcpe_icpe_tl1_common
 
 do_dcpe_tl1_fatal:
 	sethi		%hi(1f), %g7
@@ -224,8 +223,7 @@
 	mov		0x2, %o0
 	call		cheetah_plus_parity_error
 	 add		%sp, PTREGS_OFF, %o1
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		do_dcpe_tl1,.-do_dcpe_tl1
 
 	.globl		do_icpe_tl1
@@ -259,8 +257,7 @@
 	subcc		%g1, %g2, %g1
 	bge,pt		%icc, 1b
 	 nop
-	ba,pt		%xcc, dcpe_icpe_tl1_common
-	 nop
+	ba,a,pt		%xcc, dcpe_icpe_tl1_common
 
 do_icpe_tl1_fatal:
 	sethi		%hi(1f), %g7
@@ -269,8 +266,7 @@
 	mov		0x3, %o0
 	call		cheetah_plus_parity_error
 	 add		%sp, PTREGS_OFF, %o1
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		do_icpe_tl1,.-do_icpe_tl1
 	
 	.type		dcpe_icpe_tl1_common,#function
@@ -456,7 +452,7 @@
 	 cmp		%g2, 0x63
 	be		c_cee
 	 nop
-	ba,pt		%xcc, c_deferred
+	ba,a,pt		%xcc, c_deferred
 	.size		__cheetah_log_error,.-__cheetah_log_error
 
 	/* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
--- linux-4.4.0.orig/arch/sparc/kernel/ds.c
+++ linux-4.4.0/arch/sparc/kernel/ds.c
@@ -908,7 +908,7 @@
 		pbuf.req.handle = cp->handle;
 		pbuf.req.major = 1;
 		pbuf.req.minor = 0;
-		strcpy(pbuf.req.svc_id, cp->service_id);
+		strcpy(pbuf.id_buf, cp->service_id);
 
 		err = __ds_send(lp, &pbuf, msg_len);
 		if (err > 0)
--- linux-4.4.0.orig/arch/sparc/kernel/dtlb_prot.S
+++ linux-4.4.0/arch/sparc/kernel/dtlb_prot.S
@@ -25,13 +25,13 @@
 
 /* PROT ** ICACHE line 2: More real fault processing */
 	ldxa		[%g4] ASI_DMMU, %g5		! Put tagaccess in %g5
+	srlx		%g5, PAGE_SHIFT, %g5
+	sllx		%g5, PAGE_SHIFT, %g5		! Clear context ID bits
 	bgu,pn		%xcc, winfix_trampoline		! Yes, perform winfixup
 	 mov		FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
 	ba,pt		%xcc, sparc64_realfault_common	! Nope, normal fault
 	 nop
 	nop
-	nop
-	nop
 
 /* PROT ** ICACHE line 3: Unused...	*/
 	nop
--- linux-4.4.0.orig/arch/sparc/kernel/entry.S
+++ linux-4.4.0/arch/sparc/kernel/entry.S
@@ -948,7 +948,24 @@
 	cmp	%o0, 0
 	bne	3f
 	 mov	-ENOSYS, %o0
+
+	/* Syscall tracing can modify the registers.  */
+	ld	[%sp + STACKFRAME_SZ + PT_G1], %g1
+	sethi	%hi(sys_call_table), %l7
+	ld	[%sp + STACKFRAME_SZ + PT_I0], %i0
+	or	%l7, %lo(sys_call_table), %l7
+	ld	[%sp + STACKFRAME_SZ + PT_I1], %i1
+	ld	[%sp + STACKFRAME_SZ + PT_I2], %i2
+	ld	[%sp + STACKFRAME_SZ + PT_I3], %i3
+	ld	[%sp + STACKFRAME_SZ + PT_I4], %i4
+	ld	[%sp + STACKFRAME_SZ + PT_I5], %i5
+	cmp	%g1, NR_syscalls
+	bgeu	3f
+	 mov	-ENOSYS, %o0
+
+	sll	%g1, 2, %l4
 	mov	%i0, %o0
+	ld	[%l7 + %l4], %l7
 	mov	%i1, %o1
 	mov	%i2, %o2
 	mov	%i3, %o3
--- linux-4.4.0.orig/arch/sparc/kernel/fpu_traps.S
+++ linux-4.4.0/arch/sparc/kernel/fpu_traps.S
@@ -100,8 +100,8 @@
 	fmuld		%f0, %f2, %f26
 	faddd		%f0, %f2, %f28
 	fmuld		%f0, %f2, %f30
-	b,pt		%xcc, fpdis_exit
-	 nop
+	ba,a,pt		%xcc, fpdis_exit
+
 2:	andcc		%g5, FPRS_DU, %g0
 	bne,pt		%icc, 3f
 	 fzero		%f32
@@ -144,8 +144,8 @@
 	fmuld		%f32, %f34, %f58
 	faddd		%f32, %f34, %f60
 	fmuld		%f32, %f34, %f62
-	ba,pt		%xcc, fpdis_exit
-	 nop
+	ba,a,pt		%xcc, fpdis_exit
+
 3:	mov		SECONDARY_CONTEXT, %g3
 	add		%g6, TI_FPREGS, %g1
 
@@ -197,8 +197,7 @@
 fp_other_bounce:
 	call		do_fpother
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		fp_other_bounce,.-fp_other_bounce
 
 	.align		32
--- linux-4.4.0.orig/arch/sparc/kernel/head_64.S
+++ linux-4.4.0/arch/sparc/kernel/head_64.S
@@ -461,9 +461,8 @@
 	subcc	%g3, 1, %g3
 	bne,pt	%xcc, 41b
 	add	%g1, 1, %g1
-	mov	SUN4V_CHIP_SPARC64X, %g4
 	ba,pt	%xcc, 5f
-	nop
+	 mov	SUN4V_CHIP_SPARC64X, %g4
 
 49:
 	mov	SUN4V_CHIP_UNKNOWN, %g4
@@ -548,8 +547,7 @@
 	stxa		%g0, [%g7] ASI_DMMU
 	membar	#Sync
 
-	ba,pt		%xcc, sun4u_continue
-	 nop
+	ba,a,pt		%xcc, sun4u_continue
 
 sun4v_init:
 	/* Set ctx 0 */
@@ -560,14 +558,12 @@
 	mov		SECONDARY_CONTEXT, %g7
 	stxa		%g0, [%g7] ASI_MMU
 	membar		#Sync
-	ba,pt		%xcc, niagara_tlb_fixup
-	 nop
+	ba,a,pt		%xcc, niagara_tlb_fixup
 
 sun4u_continue:
 	BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup)
 
-	ba,pt	%xcc, spitfire_tlb_fixup
-	 nop
+	ba,a,pt	%xcc, spitfire_tlb_fixup
 
 niagara_tlb_fixup:
 	mov	3, %g2		/* Set TLB type to hypervisor. */
@@ -639,8 +635,7 @@
 	call	hypervisor_patch_cachetlbops
 	 nop
 
-	ba,pt	%xcc, tlb_fixup_done
-	 nop
+	ba,a,pt	%xcc, tlb_fixup_done
 
 cheetah_tlb_fixup:
 	mov	2, %g2		/* Set TLB type to cheetah+. */
@@ -659,8 +654,7 @@
 	call	cheetah_patch_cachetlbops
 	 nop
 
-	ba,pt	%xcc, tlb_fixup_done
-	 nop
+	ba,a,pt	%xcc, tlb_fixup_done
 
 spitfire_tlb_fixup:
 	/* Set TLB type to spitfire. */
@@ -782,8 +776,7 @@
 	call	%o1
 	 add	%sp, (2047 + 128), %o0
 
-	ba,pt	%xcc, 2f
-	 nop
+	ba,a,pt	%xcc, 2f
 
 1:	sethi	%hi(sparc64_ttable_tl0), %o0
 	set	prom_set_trap_table_name, %g2
@@ -822,8 +815,7 @@
 
 	BRANCH_IF_ANY_CHEETAH(o2, o3, 1f)
 
-	ba,pt	%xcc, 2f
-	 nop
+	ba,a,pt	%xcc, 2f
 
 	/* Disable STICK_INT interrupts. */
 1:
@@ -930,47 +922,11 @@
 tlb_type:	.word	0	/* Must NOT end up in BSS */
 	.section	".fixup",#alloc,#execinstr
 
-	.globl	__ret_efault, __retl_efault, __ret_one, __retl_one
-ENTRY(__ret_efault)
-	ret
-	 restore %g0, -EFAULT, %o0
-ENDPROC(__ret_efault)
-
 ENTRY(__retl_efault)
 	retl
 	 mov	-EFAULT, %o0
 ENDPROC(__retl_efault)
 
-ENTRY(__retl_one)
-	retl
-	 mov	1, %o0
-ENDPROC(__retl_one)
-
-ENTRY(__retl_one_fp)
-	VISExitHalf
-	retl
-	 mov	1, %o0
-ENDPROC(__retl_one_fp)
-
-ENTRY(__ret_one_asi)
-	wr	%g0, ASI_AIUS, %asi
-	ret
-	 restore %g0, 1, %o0
-ENDPROC(__ret_one_asi)
-
-ENTRY(__retl_one_asi)
-	wr	%g0, ASI_AIUS, %asi
-	retl
-	 mov	1, %o0
-ENDPROC(__retl_one_asi)
-
-ENTRY(__retl_one_asi_fp)
-	wr	%g0, ASI_AIUS, %asi
-	VISExitHalf
-	retl
-	 mov	1, %o0
-ENDPROC(__retl_one_asi_fp)
-
 ENTRY(__retl_o1)
 	retl
 	 mov	%o1, %o0
--- linux-4.4.0.orig/arch/sparc/kernel/idprom.c
+++ linux-4.4.0/arch/sparc/kernel/idprom.c
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/export.h>
+#include <linux/etherdevice.h>
 
 #include <asm/oplib.h>
 #include <asm/idprom.h>
@@ -60,6 +61,12 @@
 {
 }
 #endif
+
+unsigned char *arch_get_platform_mac_address(void)
+{
+	return idprom->id_ethaddr;
+}
+
 /* Calculate the IDPROM checksum (xor of the data bytes). */
 static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
 {
--- linux-4.4.0.orig/arch/sparc/kernel/irq_64.c
+++ linux-4.4.0/arch/sparc/kernel/irq_64.c
@@ -1034,17 +1034,26 @@
 {
 #ifdef CONFIG_SMP
 	unsigned long page;
+	void *mondo, *p;
 
-	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
+	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > PAGE_SIZE);
+
+	/* Make sure mondo block is 64byte aligned */
+	p = kzalloc(127, GFP_KERNEL);
+	if (!p) {
+		prom_printf("SUN4V: Error, cannot allocate mondo block.\n");
+		prom_halt();
+	}
+	mondo = (void *)(((unsigned long)p + 63) & ~0x3f);
+	tb->cpu_mondo_block_pa = __pa(mondo);
 
 	page = get_zeroed_page(GFP_KERNEL);
 	if (!page) {
-		prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
+		prom_printf("SUN4V: Error, cannot allocate cpu list page.\n");
 		prom_halt();
 	}
 
-	tb->cpu_mondo_block_pa = __pa(page);
-	tb->cpu_list_pa = __pa(page + 64);
+	tb->cpu_list_pa = __pa(page);
 #endif
 }
 
--- linux-4.4.0.orig/arch/sparc/kernel/jump_label.c
+++ linux-4.4.0/arch/sparc/kernel/jump_label.c
@@ -13,19 +13,30 @@
 void arch_jump_label_transform(struct jump_entry *entry,
 			       enum jump_label_type type)
 {
-	u32 val;
 	u32 *insn = (u32 *) (unsigned long) entry->code;
+	u32 val;
 
 	if (type == JUMP_LABEL_JMP) {
 		s32 off = (s32)entry->target - (s32)entry->code;
+		bool use_v9_branch = false;
+
+		BUG_ON(off & 3);
 
 #ifdef CONFIG_SPARC64
-		/* ba,pt %xcc, . + (off << 2) */
-		val = 0x10680000 | ((u32) off >> 2);
-#else
-		/* ba . + (off << 2) */
-		val = 0x10800000 | ((u32) off >> 2);
+		if (off <= 0xfffff && off >= -0x100000)
+			use_v9_branch = true;
 #endif
+		if (use_v9_branch) {
+			/* WDISP19 - target is . + immed << 2 */
+			/* ba,pt %xcc, . + off */
+			val = 0x10680000 | (((u32) off >> 2) & 0x7ffff);
+		} else {
+			/* WDISP22 - target is . + immed << 2 */
+			BUG_ON(off > 0x7fffff);
+			BUG_ON(off < -0x800000);
+			/* ba . + off */
+			val = 0x10800000 | (((u32) off >> 2) & 0x3fffff);
+		}
 	} else {
 		val = 0x01000000;
 	}
--- linux-4.4.0.orig/arch/sparc/kernel/kernel.h
+++ linux-4.4.0/arch/sparc/kernel/kernel.h
@@ -37,7 +37,6 @@
 /* smp_64.c */
 void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs);
 void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs);
-void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs);
 void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs);
 void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs);
 
--- linux-4.4.0.orig/arch/sparc/kernel/ktlb.S
+++ linux-4.4.0/arch/sparc/kernel/ktlb.S
@@ -20,6 +20,10 @@
 	mov		TLB_TAG_ACCESS, %g4
 	ldxa		[%g4] ASI_IMMU, %g4
 
+	/* The kernel executes in context zero, therefore we do not
+	 * need to clear the context ID bits out of %g4 here.
+	 */
+
 	/* sun4v_itlb_miss branches here with the missing virtual
 	 * address already loaded into %g4
 	 */
@@ -128,6 +132,10 @@
 	mov		TLB_TAG_ACCESS, %g4
 	ldxa		[%g4] ASI_DMMU, %g4
 
+	/* The kernel executes in context zero, therefore we do not
+	 * need to clear the context ID bits out of %g4 here.
+	 */
+
 	/* sun4v_dtlb_miss branches here with the missing virtual
 	 * address already loaded into %g4
 	 */
@@ -251,6 +259,10 @@
 	nop
 	.previous
 
+	/* The kernel executes in context zero, therefore we do not
+	 * need to clear the context ID bits out of %g5 here.
+	 */
+
 	be,pt	%xcc, sparc64_realfault_common
 	 mov	FAULT_CODE_DTLB, %g4
 	ba,pt	%xcc, winfix_trampoline
--- linux-4.4.0.orig/arch/sparc/kernel/ldc.c
+++ linux-4.4.0/arch/sparc/kernel/ldc.c
@@ -1733,9 +1733,14 @@
 
 		lp->rcv_nxt = p->seqid;
 
+		/*
+		 * If this is a control-only packet, there is nothing
+		 * else to do but advance the rx queue since the packet
+		 * was already processed above.
+		 */
 		if (!(p->type & LDC_DATA)) {
 			new = rx_advance(lp, new);
-			goto no_data;
+			break;
 		}
 		if (p->stype & (LDC_ACK | LDC_NACK)) {
 			err = data_ack_nack(lp, p);
--- linux-4.4.0.orig/arch/sparc/kernel/misctrap.S
+++ linux-4.4.0/arch/sparc/kernel/misctrap.S
@@ -18,8 +18,7 @@
 109:	or		%g7, %lo(109b), %g7
 	call		do_privact
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		__do_privact,.-__do_privact
 
 	.type		do_mna,#function
@@ -46,8 +45,7 @@
 	mov		%l5, %o2
 	call		mem_address_unaligned
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		do_mna,.-do_mna
 
 	.type		do_lddfmna,#function
@@ -65,8 +63,7 @@
 	mov		%l5, %o2
 	call		handle_lddfmna
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		do_lddfmna,.-do_lddfmna
 
 	.type		do_stdfmna,#function
@@ -84,8 +81,7 @@
 	mov		%l5, %o2
 	call		handle_stdfmna
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		do_stdfmna,.-do_stdfmna
 
 	.type		breakpoint_trap,#function
--- linux-4.4.0.orig/arch/sparc/kernel/pci.c
+++ linux-4.4.0/arch/sparc/kernel/pci.c
@@ -245,6 +245,18 @@
 	}
 }
 
+static void pci_init_dev_archdata(struct dev_archdata *sd, void *iommu,
+				  void *stc, void *host_controller,
+				  struct platform_device  *op,
+				  int numa_node)
+{
+	sd->iommu = iommu;
+	sd->stc = stc;
+	sd->host_controller = host_controller;
+	sd->op = op;
+	sd->numa_node = numa_node;
+}
+
 static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
 					 struct device_node *node,
 					 struct pci_bus *bus, int devfn)
@@ -259,13 +271,10 @@
 	if (!dev)
 		return NULL;
 
+	op = of_find_device_by_node(node);
 	sd = &dev->dev.archdata;
-	sd->iommu = pbm->iommu;
-	sd->stc = &pbm->stc;
-	sd->host_controller = pbm;
-	sd->op = op = of_find_device_by_node(node);
-	sd->numa_node = pbm->numa_node;
-
+	pci_init_dev_archdata(sd, pbm->iommu, &pbm->stc, pbm, op,
+			      pbm->numa_node);
 	sd = &op->dev.archdata;
 	sd->iommu = pbm->iommu;
 	sd->stc = &pbm->stc;
@@ -994,6 +1003,27 @@
 	/* No special bus mastering setup handling */
 }
 
+#ifdef CONFIG_PCI_IOV
+int pcibios_add_device(struct pci_dev *dev)
+{
+	struct pci_dev *pdev;
+
+	/* Add sriov arch specific initialization here.
+	 * Copy dev_archdata from PF to VF
+	 */
+	if (dev->is_virtfn) {
+		struct dev_archdata *psd;
+
+		pdev = dev->physfn;
+		psd = &pdev->dev.archdata;
+		pci_init_dev_archdata(&dev->dev.archdata, psd->iommu,
+				      psd->stc, psd->host_controller, NULL,
+				      psd->numa_node);
+	}
+	return 0;
+}
+#endif /* CONFIG_PCI_IOV */
+
 static int __init pcibios_init(void)
 {
 	pci_dfl_cache_line_size = 64 >> 2;
--- linux-4.4.0.orig/arch/sparc/kernel/perf_event.c
+++ linux-4.4.0/arch/sparc/kernel/perf_event.c
@@ -889,6 +889,10 @@
 	s64 period = hwc->sample_period;
 	int ret = 0;
 
+	/* The period may have been changed by PERF_EVENT_IOC_PERIOD */
+	if (unlikely(period != hwc->last_period))
+		left = period - (hwc->last_period - left);
+
 	if (unlikely(left <= -period)) {
 		left = period;
 		local64_set(&hwc->period_left, left);
@@ -926,6 +930,8 @@
 			sparc_perf_event_update(cp, &cp->hw,
 						cpuc->current_idx[i]);
 			cpuc->current_idx[i] = PIC_NO_INDEX;
+			if (cp->hw.state & PERF_HES_STOPPED)
+				cp->hw.state |= PERF_HES_ARCH;
 		}
 	}
 }
@@ -958,10 +964,12 @@
 
 		enc = perf_event_get_enc(cpuc->events[i]);
 		cpuc->pcr[0] &= ~mask_for_index(idx);
-		if (hwc->state & PERF_HES_STOPPED)
+		if (hwc->state & PERF_HES_ARCH) {
 			cpuc->pcr[0] |= nop_for_index(idx);
-		else
+		} else {
 			cpuc->pcr[0] |= event_encoding(enc, idx);
+			hwc->state = 0;
+		}
 	}
 out:
 	cpuc->pcr[0] |= cpuc->event[0]->hw.config_base;
@@ -987,6 +995,9 @@
 
 		cpuc->current_idx[i] = idx;
 
+		if (cp->hw.state & PERF_HES_ARCH)
+			continue;
+
 		sparc_pmu_start(cp, PERF_EF_RELOAD);
 	}
 out:
@@ -1078,6 +1089,8 @@
 	event->hw.state = 0;
 
 	sparc_pmu_enable_event(cpuc, &event->hw, idx);
+
+	perf_event_update_userpage(event);
 }
 
 static void sparc_pmu_stop(struct perf_event *event, int flags)
@@ -1370,9 +1383,9 @@
 	cpuc->events[n0] = event->hw.event_base;
 	cpuc->current_idx[n0] = PIC_NO_INDEX;
 
-	event->hw.state = PERF_HES_UPTODATE;
+	event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
 	if (!(ef_flags & PERF_EF_START))
-		event->hw.state |= PERF_HES_STOPPED;
+		event->hw.state |= PERF_HES_ARCH;
 
 	/*
 	 * If group events scheduling transaction was started,
--- linux-4.4.0.orig/arch/sparc/kernel/ptrace_32.c
+++ linux-4.4.0/arch/sparc/kernel/ptrace_32.c
@@ -45,82 +45,79 @@
 	REGSET_FP,
 };
 
+static int regwindow32_get(struct task_struct *target,
+			   const struct pt_regs *regs,
+			   u32 *uregs)
+{
+	unsigned long reg_window = regs->u_regs[UREG_I6];
+	int size = 16 * sizeof(u32);
+
+	if (target == current) {
+		if (copy_from_user(uregs, (void __user *)reg_window, size))
+			return -EFAULT;
+	} else {
+		if (access_process_vm(target, reg_window, uregs, size,
+				      FOLL_FORCE) != size)
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static int regwindow32_set(struct task_struct *target,
+			   const struct pt_regs *regs,
+			   u32 *uregs)
+{
+	unsigned long reg_window = regs->u_regs[UREG_I6];
+	int size = 16 * sizeof(u32);
+
+	if (target == current) {
+		if (copy_to_user((void __user *)reg_window, uregs, size))
+			return -EFAULT;
+	} else {
+		if (access_process_vm(target, reg_window, uregs, size,
+				      FOLL_FORCE | FOLL_WRITE) != size)
+			return -EFAULT;
+	}
+	return 0;
+}
+
 static int genregs32_get(struct task_struct *target,
 			 const struct user_regset *regset,
 			 unsigned int pos, unsigned int count,
 			 void *kbuf, void __user *ubuf)
 {
 	const struct pt_regs *regs = target->thread.kregs;
-	unsigned long __user *reg_window;
-	unsigned long *k = kbuf;
-	unsigned long __user *u = ubuf;
-	unsigned long reg;
+	u32 uregs[16];
+	int ret;
 
 	if (target == current)
 		flush_user_windows();
 
-	pos /= sizeof(reg);
-	count /= sizeof(reg);
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				  regs->u_regs,
+				  0, 16 * sizeof(u32));
+	if (ret || !count)
+		return ret;
 
-	if (kbuf) {
-		for (; count > 0 && pos < 16; count--)
-			*k++ = regs->u_regs[pos++];
-
-		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-		reg_window -= 16;
-		for (; count > 0 && pos < 32; count--) {
-			if (get_user(*k++, &reg_window[pos++]))
-				return -EFAULT;
-		}
-	} else {
-		for (; count > 0 && pos < 16; count--) {
-			if (put_user(regs->u_regs[pos++], u++))
-				return -EFAULT;
-		}
-
-		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-		reg_window -= 16;
-		for (; count > 0 && pos < 32; count--) {
-			if (get_user(reg, &reg_window[pos++]) ||
-			    put_user(reg, u++))
-				return -EFAULT;
-		}
-	}
-	while (count > 0) {
-		switch (pos) {
-		case 32: /* PSR */
-			reg = regs->psr;
-			break;
-		case 33: /* PC */
-			reg = regs->pc;
-			break;
-		case 34: /* NPC */
-			reg = regs->npc;
-			break;
-		case 35: /* Y */
-			reg = regs->y;
-			break;
-		case 36: /* WIM */
-		case 37: /* TBR */
-			reg = 0;
-			break;
-		default:
-			goto finish;
-		}
-
-		if (kbuf)
-			*k++ = reg;
-		else if (put_user(reg, u++))
+	if (pos < 32 * sizeof(u32)) {
+		if (regwindow32_get(target, regs, uregs))
 			return -EFAULT;
-		pos++;
-		count--;
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					  uregs,
+					  16 * sizeof(u32), 32 * sizeof(u32));
+		if (ret || !count)
+			return ret;
 	}
-finish:
-	pos *= sizeof(reg);
-	count *= sizeof(reg);
 
-	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
-					38 * sizeof(reg), -1);
+	uregs[0] = regs->psr;
+	uregs[1] = regs->pc;
+	uregs[2] = regs->npc;
+	uregs[3] = regs->y;
+	uregs[4] = 0;	/* WIM */
+	uregs[5] = 0;	/* TBR */
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				  uregs,
+				  32 * sizeof(u32), 38 * sizeof(u32));
 }
 
 static int genregs32_set(struct task_struct *target,
@@ -129,82 +126,58 @@
 			 const void *kbuf, const void __user *ubuf)
 {
 	struct pt_regs *regs = target->thread.kregs;
-	unsigned long __user *reg_window;
-	const unsigned long *k = kbuf;
-	const unsigned long __user *u = ubuf;
-	unsigned long reg;
+	u32 uregs[16];
+	u32 psr;
+	int ret;
 
 	if (target == current)
 		flush_user_windows();
 
-	pos /= sizeof(reg);
-	count /= sizeof(reg);
-
-	if (kbuf) {
-		for (; count > 0 && pos < 16; count--)
-			regs->u_regs[pos++] = *k++;
-
-		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-		reg_window -= 16;
-		for (; count > 0 && pos < 32; count--) {
-			if (put_user(*k++, &reg_window[pos++]))
-				return -EFAULT;
-		}
-	} else {
-		for (; count > 0 && pos < 16; count--) {
-			if (get_user(reg, u++))
-				return -EFAULT;
-			regs->u_regs[pos++] = reg;
-		}
-
-		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-		reg_window -= 16;
-		for (; count > 0 && pos < 32; count--) {
-			if (get_user(reg, u++) ||
-			    put_user(reg, &reg_window[pos++]))
-				return -EFAULT;
-		}
-	}
-	while (count > 0) {
-		unsigned long psr;
-
-		if (kbuf)
-			reg = *k++;
-		else if (get_user(reg, u++))
-			return -EFAULT;
-
-		switch (pos) {
-		case 32: /* PSR */
-			psr = regs->psr;
-			psr &= ~(PSR_ICC | PSR_SYSCALL);
-			psr |= (reg & (PSR_ICC | PSR_SYSCALL));
-			regs->psr = psr;
-			break;
-		case 33: /* PC */
-			regs->pc = reg;
-			break;
-		case 34: /* NPC */
-			regs->npc = reg;
-			break;
-		case 35: /* Y */
-			regs->y = reg;
-			break;
-		case 36: /* WIM */
-		case 37: /* TBR */
-			break;
-		default:
-			goto finish;
-		}
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 regs->u_regs,
+				 0, 16 * sizeof(u32));
+	if (ret || !count)
+		return ret;
 
-		pos++;
-		count--;
+	if (pos < 32 * sizeof(u32)) {
+		if (regwindow32_get(target, regs, uregs))
+			return -EFAULT;
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					 uregs,
+					 16 * sizeof(u32), 32 * sizeof(u32));
+		if (ret)
+			return ret;
+		if (regwindow32_set(target, regs, uregs))
+			return -EFAULT;
+		if (!count)
+			return 0;
 	}
-finish:
-	pos *= sizeof(reg);
-	count *= sizeof(reg);
-
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 &psr,
+				 32 * sizeof(u32), 33 * sizeof(u32));
+	if (ret)
+		return ret;
+	regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
+		    (psr & (PSR_ICC | PSR_SYSCALL));
+	if (!count)
+		return 0;
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 &regs->pc,
+				 33 * sizeof(u32), 34 * sizeof(u32));
+	if (ret || !count)
+		return ret;
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 &regs->npc,
+				 34 * sizeof(u32), 35 * sizeof(u32));
+	if (ret || !count)
+		return ret;
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 &regs->y,
+				 35 * sizeof(u32), 36 * sizeof(u32));
+	if (ret || !count)
+		return ret;
 	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-					 38 * sizeof(reg), -1);
+					 36 * sizeof(u32), 38 * sizeof(u32));
 }
 
 static int fpregs32_get(struct task_struct *target,
--- linux-4.4.0.orig/arch/sparc/kernel/ptrace_64.c
+++ linux-4.4.0/arch/sparc/kernel/ptrace_64.c
@@ -311,7 +311,7 @@
 	}
 
 	if (!ret) {
-		unsigned long y;
+		unsigned long y = regs->y;
 
 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 					 &y,
@@ -534,13 +534,8 @@
 						      &reg, sizeof(reg), 0)
 				    != sizeof(reg))
 					return -EFAULT;
-				if (access_process_vm(target,
-						      (unsigned long) u,
-						      &reg, sizeof(reg), 1)
-				    != sizeof(reg))
+				if (put_user(reg, u++))
 					return -EFAULT;
-				pos++;
-				u++;
 			}
 		}
 	}
@@ -639,11 +634,7 @@
 			}
 		} else {
 			for (; count > 0 && pos < 32; count--) {
-				if (access_process_vm(target,
-						      (unsigned long)
-						      u,
-						      &reg, sizeof(reg), 0)
-				    != sizeof(reg))
+				if (get_user(reg, u++))
 					return -EFAULT;
 				if (access_process_vm(target,
 						      (unsigned long)
--- linux-4.4.0.orig/arch/sparc/kernel/rtrap_64.S
+++ linux-4.4.0/arch/sparc/kernel/rtrap_64.S
@@ -14,10 +14,6 @@
 #include <asm/visasm.h>
 #include <asm/processor.h>
 
-#define		RTRAP_PSTATE		(PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
-#define		RTRAP_PSTATE_IRQOFF	(PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV)
-#define		RTRAP_PSTATE_AG_IRQOFF	(PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
-
 #ifdef CONFIG_CONTEXT_TRACKING
 # define SCHEDULE_USER schedule_user
 #else
@@ -242,52 +238,17 @@
 		 wrpr			%g1, %cwp
 		ba,a,pt			%xcc, user_rtt_fill_64bit
 
-user_rtt_fill_fixup:
-		rdpr	%cwp, %g1
-		add	%g1, 1, %g1
-		wrpr	%g1, 0x0, %cwp
-
-		rdpr	%wstate, %g2
-		sll	%g2, 3, %g2
-		wrpr	%g2, 0x0, %wstate
-
-		/* We know %canrestore and %otherwin are both zero.  */
-
-		sethi	%hi(sparc64_kern_pri_context), %g2
-		ldx	[%g2 + %lo(sparc64_kern_pri_context)], %g2
-		mov	PRIMARY_CONTEXT, %g1
-
-661:		stxa	%g2, [%g1] ASI_DMMU
-		.section .sun4v_1insn_patch, "ax"
-		.word	661b
-		stxa	%g2, [%g1] ASI_MMU
-		.previous
-
-		sethi	%hi(KERNBASE), %g1
-		flush	%g1
+user_rtt_fill_fixup_dax:
+		ba,pt	%xcc, user_rtt_fill_fixup_common
+		 mov	1, %g3
+
+user_rtt_fill_fixup_mna:
+		ba,pt	%xcc, user_rtt_fill_fixup_common
+		 mov	2, %g3
 
-		or	%g4, FAULT_CODE_WINFIXUP, %g4
-		stb	%g4, [%g6 + TI_FAULT_CODE]
-		stx	%g5, [%g6 + TI_FAULT_ADDR]
-
-		mov	%g6, %l1
-		wrpr	%g0, 0x0, %tl
-
-661:		nop
-		.section		.sun4v_1insn_patch, "ax"
-		.word			661b
-		SET_GL(0)
-		.previous
-
-		wrpr	%g0, RTRAP_PSTATE, %pstate
-
-		mov	%l1, %g6
-		ldx	[%g6 + TI_TASK], %g4
-		LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3)
-		call	do_sparc64_fault
-		 add	%sp, PTREGS_OFF, %o0
-		ba,pt	%xcc, rtrap
-		 nop
+user_rtt_fill_fixup:
+		ba,pt	%xcc, user_rtt_fill_fixup_common
+		 clr	%g3
 
 user_rtt_pre_restore:
 		add			%g1, 1, %g1
--- linux-4.4.0.orig/arch/sparc/kernel/signal32.c
+++ linux-4.4.0/arch/sparc/kernel/signal32.c
@@ -138,12 +138,24 @@
 	return 0;
 }
 
+/* Checks if the fp is valid.  We always build signal frames which are
+ * 16-byte aligned, therefore we can always enforce that the restore
+ * frame has that property as well.
+ */
+static bool invalid_frame_pointer(void __user *fp, int fplen)
+{
+	if ((((unsigned long) fp) & 15) ||
+	    ((unsigned long)fp) > 0x100000000ULL - fplen)
+		return true;
+	return false;
+}
+
 void do_sigreturn32(struct pt_regs *regs)
 {
 	struct signal_frame32 __user *sf;
 	compat_uptr_t fpu_save;
 	compat_uptr_t rwin_save;
-	unsigned int psr;
+	unsigned int psr, ufp;
 	unsigned pc, npc;
 	sigset_t set;
 	compat_sigset_t seta;
@@ -158,11 +170,16 @@
 	sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
-	    (((unsigned long) sf) & 3))
+	if (invalid_frame_pointer(sf, sizeof(*sf)))
+		goto segv;
+
+	if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
+		goto segv;
+
+	if (ufp & 0x7)
 		goto segv;
 
-	if (get_user(pc, &sf->info.si_regs.pc) ||
+	if (__get_user(pc, &sf->info.si_regs.pc) ||
 	    __get_user(npc, &sf->info.si_regs.npc))
 		goto segv;
 
@@ -227,7 +244,7 @@
 asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
 {
 	struct rt_signal_frame32 __user *sf;
-	unsigned int psr, pc, npc;
+	unsigned int psr, pc, npc, ufp;
 	compat_uptr_t fpu_save;
 	compat_uptr_t rwin_save;
 	sigset_t set;
@@ -242,11 +259,16 @@
 	sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
-	    (((unsigned long) sf) & 3))
+	if (invalid_frame_pointer(sf, sizeof(*sf)))
 		goto segv;
 
-	if (get_user(pc, &sf->regs.pc) || 
+	if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
+		goto segv;
+
+	if (ufp & 0x7)
+		goto segv;
+
+	if (__get_user(pc, &sf->regs.pc) ||
 	    __get_user(npc, &sf->regs.npc))
 		goto segv;
 
@@ -307,14 +329,6 @@
 	force_sig(SIGSEGV, current);
 }
 
-/* Checks if the fp is valid */
-static int invalid_frame_pointer(void __user *fp, int fplen)
-{
-	if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
-		return 1;
-	return 0;
-}
-
 static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
 {
 	unsigned long sp;
--- linux-4.4.0.orig/arch/sparc/kernel/signal_32.c
+++ linux-4.4.0/arch/sparc/kernel/signal_32.c
@@ -60,10 +60,22 @@
 #define SF_ALIGNEDSZ  (((sizeof(struct signal_frame) + 7) & (~7)))
 #define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame) + 7) & (~7)))
 
+/* Checks if the fp is valid.  We always build signal frames which are
+ * 16-byte aligned, therefore we can always enforce that the restore
+ * frame has that property as well.
+ */
+static inline bool invalid_frame_pointer(void __user *fp, int fplen)
+{
+	if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen))
+		return true;
+
+	return false;
+}
+
 asmlinkage void do_sigreturn(struct pt_regs *regs)
 {
+	unsigned long up_psr, pc, npc, ufp;
 	struct signal_frame __user *sf;
-	unsigned long up_psr, pc, npc;
 	sigset_t set;
 	__siginfo_fpu_t __user *fpu_save;
 	__siginfo_rwin_t __user *rwin_save;
@@ -77,10 +89,13 @@
 	sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
+	if (invalid_frame_pointer(sf, sizeof(*sf)))
 		goto segv_and_exit;
 
-	if (((unsigned long) sf) & 3)
+	if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
+		goto segv_and_exit;
+
+	if (ufp & 0x7)
 		goto segv_and_exit;
 
 	err = __get_user(pc,  &sf->info.si_regs.pc);
@@ -127,7 +142,7 @@
 asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
 {
 	struct rt_signal_frame __user *sf;
-	unsigned int psr, pc, npc;
+	unsigned int psr, pc, npc, ufp;
 	__siginfo_fpu_t __user *fpu_save;
 	__siginfo_rwin_t __user *rwin_save;
 	sigset_t set;
@@ -135,8 +150,13 @@
 
 	synchronize_user_stack();
 	sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
-	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
-	    (((unsigned long) sf) & 0x03))
+	if (invalid_frame_pointer(sf, sizeof(*sf)))
+		goto segv;
+
+	if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
+		goto segv;
+
+	if (ufp & 0x7)
 		goto segv;
 
 	err = __get_user(pc, &sf->regs.pc);
@@ -178,15 +198,6 @@
 	force_sig(SIGSEGV, current);
 }
 
-/* Checks if the fp is valid */
-static inline int invalid_frame_pointer(void __user *fp, int fplen)
-{
-	if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen))
-		return 1;
-
-	return 0;
-}
-
 static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
 {
 	unsigned long sp = regs->u_regs[UREG_FP];
--- linux-4.4.0.orig/arch/sparc/kernel/signal_64.c
+++ linux-4.4.0/arch/sparc/kernel/signal_64.c
@@ -52,7 +52,7 @@
 	unsigned char fenab;
 	int err;
 
-	flush_user_windows();
+	synchronize_user_stack();
 	if (get_thread_wsaved()					||
 	    (((unsigned long)ucp) & (sizeof(unsigned long)-1))	||
 	    (!__access_ok(ucp, sizeof(*ucp))))
@@ -234,6 +234,17 @@
 	goto out;
 }
 
+/* Checks if the fp is valid.  We always build rt signal frames which
+ * are 16-byte aligned, therefore we can always enforce that the
+ * restore frame has that property as well.
+ */
+static bool invalid_frame_pointer(void __user *fp)
+{
+	if (((unsigned long) fp) & 15)
+		return true;
+	return false;
+}
+
 struct rt_signal_frame {
 	struct sparc_stackf	ss;
 	siginfo_t		info;
@@ -246,8 +257,8 @@
 
 void do_rt_sigreturn(struct pt_regs *regs)
 {
+	unsigned long tpc, tnpc, tstate, ufp;
 	struct rt_signal_frame __user *sf;
-	unsigned long tpc, tnpc, tstate;
 	__siginfo_fpu_t __user *fpu_save;
 	__siginfo_rwin_t __user *rwin_save;
 	sigset_t set;
@@ -261,10 +272,16 @@
 		(regs->u_regs [UREG_FP] + STACK_BIAS);
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (((unsigned long) sf) & 3)
+	if (invalid_frame_pointer(sf))
+		goto segv;
+
+	if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
 		goto segv;
 
-	err = get_user(tpc, &sf->regs.tpc);
+	if ((ufp + STACK_BIAS) & 0x7)
+		goto segv;
+
+	err = __get_user(tpc, &sf->regs.tpc);
 	err |= __get_user(tnpc, &sf->regs.tnpc);
 	if (test_thread_flag(TIF_32BIT)) {
 		tpc &= 0xffffffff;
@@ -308,14 +325,6 @@
 	force_sig(SIGSEGV, current);
 }
 
-/* Checks if the fp is valid */
-static int invalid_frame_pointer(void __user *fp)
-{
-	if (((unsigned long) fp) & 15)
-		return 1;
-	return 0;
-}
-
 static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
 {
 	unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
--- linux-4.4.0.orig/arch/sparc/kernel/sigutil_32.c
+++ linux-4.4.0/arch/sparc/kernel/sigutil_32.c
@@ -48,6 +48,10 @@
 int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
 {
 	int err;
+
+	if (((unsigned long) fpu) & 3)
+		return -EFAULT;
+
 #ifdef CONFIG_SMP
 	if (test_tsk_thread_flag(current, TIF_USEDFPU))
 		regs->psr &= ~PSR_EF;
@@ -97,7 +101,10 @@
 	struct thread_info *t = current_thread_info();
 	int i, wsaved, err;
 
-	__get_user(wsaved, &rp->wsaved);
+	if (((unsigned long) rp) & 3)
+		return -EFAULT;
+
+	get_user(wsaved, &rp->wsaved);
 	if (wsaved > NSWINS)
 		return -EFAULT;
 
--- linux-4.4.0.orig/arch/sparc/kernel/sigutil_64.c
+++ linux-4.4.0/arch/sparc/kernel/sigutil_64.c
@@ -37,7 +37,10 @@
 	unsigned long fprs;
 	int err;
 
-	err = __get_user(fprs, &fpu->si_fprs);
+	if (((unsigned long) fpu) & 7)
+		return -EFAULT;
+
+	err = get_user(fprs, &fpu->si_fprs);
 	fprs_write(0);
 	regs->tstate &= ~TSTATE_PEF;
 	if (fprs & FPRS_DL)
@@ -72,7 +75,10 @@
 	struct thread_info *t = current_thread_info();
 	int i, wsaved, err;
 
-	__get_user(wsaved, &rp->wsaved);
+	if (((unsigned long) rp) & 7)
+		return -EFAULT;
+
+	get_user(wsaved, &rp->wsaved);
 	if (wsaved > NSWINS)
 		return -EFAULT;
 
--- linux-4.4.0.orig/arch/sparc/kernel/smp_64.c
+++ linux-4.4.0/arch/sparc/kernel/smp_64.c
@@ -617,22 +617,48 @@
 	}
 }
 
-/* Multi-cpu list version.  */
+#define	CPU_MONDO_COUNTER(cpuid)	(cpu_mondo_counter[cpuid])
+#define	MONDO_USEC_WAIT_MIN		2
+#define	MONDO_USEC_WAIT_MAX		100
+#define	MONDO_RETRY_LIMIT		500000
+
+/* Multi-cpu list version.
+ *
+ * Deliver xcalls to 'cnt' number of cpus in 'cpu_list'.
+ * Sometimes not all cpus receive the mondo, requiring us to re-send
+ * the mondo until all cpus have received, or cpus are truly stuck
+ * unable to receive mondo, and we timeout.
+ * Occasionally a target cpu strand is borrowed briefly by hypervisor to
+ * perform guest service, such as PCIe error handling. Consider the
+ * service time, 1 second overall wait is reasonable for 1 cpu.
+ * Here two in-between mondo check wait time are defined: 2 usec for
+ * single cpu quick turn around and up to 100usec for large cpu count.
+ * Deliver mondo to large number of cpus could take longer, we adjusts
+ * the retry count as long as target cpus are making forward progress.
+ */
 static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt)
 {
-	int retries, this_cpu, prev_sent, i, saw_cpu_error;
+	int this_cpu, tot_cpus, prev_sent, i, rem;
+	int usec_wait, retries, tot_retries;
+	u16 first_cpu = 0xffff;
+	unsigned long xc_rcvd = 0;
 	unsigned long status;
+	int ecpuerror_id = 0;
+	int enocpu_id = 0;
 	u16 *cpu_list;
+	u16 cpu;
 
 	this_cpu = smp_processor_id();
-
 	cpu_list = __va(tb->cpu_list_pa);
-
-	saw_cpu_error = 0;
-	retries = 0;
+	usec_wait = cnt * MONDO_USEC_WAIT_MIN;
+	if (usec_wait > MONDO_USEC_WAIT_MAX)
+		usec_wait = MONDO_USEC_WAIT_MAX;
+	retries = tot_retries = 0;
+	tot_cpus = cnt;
 	prev_sent = 0;
+
 	do {
-		int forward_progress, n_sent;
+		int n_sent, mondo_delivered, target_cpu_busy;
 
 		status = sun4v_cpu_mondo_send(cnt,
 					      tb->cpu_list_pa,
@@ -640,94 +666,113 @@
 
 		/* HV_EOK means all cpus received the xcall, we're done.  */
 		if (likely(status == HV_EOK))
-			break;
+			goto xcall_done;
+
+		/* If not these non-fatal errors, panic */
+		if (unlikely((status != HV_EWOULDBLOCK) &&
+			(status != HV_ECPUERROR) &&
+			(status != HV_ENOCPU)))
+			goto fatal_errors;
 
 		/* First, see if we made any forward progress.
 		 *
+		 * Go through the cpu_list, count the target cpus that have
+		 * received our mondo (n_sent), and those that did not (rem).
+		 * Re-pack cpu_list with the cpus remain to be retried in the
+		 * front - this simplifies tracking the truly stalled cpus.
+		 *
 		 * The hypervisor indicates successful sends by setting
 		 * cpu list entries to the value 0xffff.
+		 *
+		 * EWOULDBLOCK means some target cpus did not receive the
+		 * mondo and retry usually helps.
+		 *
+		 * ECPUERROR means at least one target cpu is in error state,
+		 * it's usually safe to skip the faulty cpu and retry.
+		 *
+		 * ENOCPU means one of the target cpu doesn't belong to the
+		 * domain, perhaps offlined which is unexpected, but not
+		 * fatal and it's okay to skip the offlined cpu.
 		 */
+		rem = 0;
 		n_sent = 0;
 		for (i = 0; i < cnt; i++) {
-			if (likely(cpu_list[i] == 0xffff))
+			cpu = cpu_list[i];
+			if (likely(cpu == 0xffff)) {
 				n_sent++;
+			} else if ((status == HV_ECPUERROR) &&
+				(sun4v_cpu_state(cpu) == HV_CPU_STATE_ERROR)) {
+				ecpuerror_id = cpu + 1;
+			} else if (status == HV_ENOCPU && !cpu_online(cpu)) {
+				enocpu_id = cpu + 1;
+			} else {
+				cpu_list[rem++] = cpu;
+			}
 		}
 
-		forward_progress = 0;
-		if (n_sent > prev_sent)
-			forward_progress = 1;
+		/* No cpu remained, we're done. */
+		if (rem == 0)
+			break;
+
+		/* Otherwise, update the cpu count for retry. */
+		cnt = rem;
 
+		/* Record the overall number of mondos received by the
+		 * first of the remaining cpus.
+		 */
+		if (first_cpu != cpu_list[0]) {
+			first_cpu = cpu_list[0];
+			xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
+		}
+
+		/* Was any mondo delivered successfully? */
+		mondo_delivered = (n_sent > prev_sent);
 		prev_sent = n_sent;
 
-		/* If we get a HV_ECPUERROR, then one or more of the cpus
-		 * in the list are in error state.  Use the cpu_state()
-		 * hypervisor call to find out which cpus are in error state.
+		/* or, was any target cpu busy processing other mondos? */
+		target_cpu_busy = (xc_rcvd < CPU_MONDO_COUNTER(first_cpu));
+		xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
+
+		/* Retry count is for no progress. If we're making progress,
+		 * reset the retry count.
 		 */
-		if (unlikely(status == HV_ECPUERROR)) {
-			for (i = 0; i < cnt; i++) {
-				long err;
-				u16 cpu;
-
-				cpu = cpu_list[i];
-				if (cpu == 0xffff)
-					continue;
-
-				err = sun4v_cpu_state(cpu);
-				if (err == HV_CPU_STATE_ERROR) {
-					saw_cpu_error = (cpu + 1);
-					cpu_list[i] = 0xffff;
-				}
-			}
-		} else if (unlikely(status != HV_EWOULDBLOCK))
-			goto fatal_mondo_error;
+		if (likely(mondo_delivered || target_cpu_busy)) {
+			tot_retries += retries;
+			retries = 0;
+		} else if (unlikely(retries > MONDO_RETRY_LIMIT)) {
+			goto fatal_mondo_timeout;
+		}
 
-		/* Don't bother rewriting the CPU list, just leave the
-		 * 0xffff and non-0xffff entries in there and the
-		 * hypervisor will do the right thing.
-		 *
-		 * Only advance timeout state if we didn't make any
-		 * forward progress.
+		/* Delay a little bit to let other cpus catch up on
+		 * their cpu mondo queue work.
 		 */
-		if (unlikely(!forward_progress)) {
-			if (unlikely(++retries > 10000))
-				goto fatal_mondo_timeout;
+		if (!mondo_delivered)
+			udelay(usec_wait);
 
-			/* Delay a little bit to let other cpus catch up
-			 * on their cpu mondo queue work.
-			 */
-			udelay(2 * cnt);
-		}
+		retries++;
 	} while (1);
 
-	if (unlikely(saw_cpu_error))
-		goto fatal_mondo_cpu_error;
-
+xcall_done:
+	if (unlikely(ecpuerror_id > 0)) {
+		pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) was in error state\n",
+		       this_cpu, ecpuerror_id - 1);
+	} else if (unlikely(enocpu_id > 0)) {
+		pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) does not belong to the domain\n",
+		       this_cpu, enocpu_id - 1);
+	}
 	return;
 
-fatal_mondo_cpu_error:
-	printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus "
-	       "(including %d) were in error state\n",
-	       this_cpu, saw_cpu_error - 1);
-	return;
+fatal_errors:
+	/* fatal errors include bad alignment, etc */
+	pr_crit("CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) mondo_block_pa(%lx)\n",
+	       this_cpu, tot_cpus, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
+	panic("Unexpected SUN4V mondo error %lu\n", status);
 
 fatal_mondo_timeout:
-	printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward "
-	       " progress after %d retries.\n",
-	       this_cpu, retries);
-	goto dump_cpu_list_and_out;
-
-fatal_mondo_error:
-	printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n",
-	       this_cpu, status);
-	printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) "
-	       "mondo_block_pa(%lx)\n",
-	       this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
-
-dump_cpu_list_and_out:
-	printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu);
-	for (i = 0; i < cnt; i++)
-		printk("%u ", cpu_list[i]);
-	printk("]\n");
+	/* some cpus being non-responsive to the cpu mondo */
+	pr_crit("CPU[%d]: SUN4V mondo timeout, cpu(%d) made no forward progress after %d retries. Total target cpus(%d).\n",
+	       this_cpu, first_cpu, (tot_retries + retries), tot_cpus);
+	panic("SUN4V mondo timeout panic\n");
 }
 
 static void (*xcall_deliver_impl)(struct trap_per_cpu *, int);
@@ -959,37 +1004,6 @@
 	preempt_enable();
 }
 
-void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
-{
-	struct mm_struct *mm;
-	unsigned long flags;
-
-	clear_softint(1 << irq);
-
-	/* See if we need to allocate a new TLB context because
-	 * the version of the one we are using is now out of date.
-	 */
-	mm = current->active_mm;
-	if (unlikely(!mm || (mm == &init_mm)))
-		return;
-
-	spin_lock_irqsave(&mm->context.lock, flags);
-
-	if (unlikely(!CTX_VALID(mm->context)))
-		get_new_mmu_context(mm);
-
-	spin_unlock_irqrestore(&mm->context.lock, flags);
-
-	load_secondary_context(mm);
-	__flush_tlb_mm(CTX_HWBITS(mm->context),
-		       SECONDARY_CONTEXT);
-}
-
-void smp_new_mmu_context_version(void)
-{
-	smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0);
-}
-
 #ifdef CONFIG_KGDB
 void kgdb_roundup_cpus(unsigned long flags)
 {
@@ -1016,38 +1030,9 @@
  * are flush_tlb_*() routines, and these run after flush_cache_*()
  * which performs the flushw.
  *
- * The SMP TLB coherency scheme we use works as follows:
- *
- * 1) mm->cpu_vm_mask is a bit mask of which cpus an address
- *    space has (potentially) executed on, this is the heuristic
- *    we use to avoid doing cross calls.
- *
- *    Also, for flushing from kswapd and also for clones, we
- *    use cpu_vm_mask as the list of cpus to make run the TLB.
- *
- * 2) TLB context numbers are shared globally across all processors
- *    in the system, this allows us to play several games to avoid
- *    cross calls.
- *
- *    One invariant is that when a cpu switches to a process, and
- *    that processes tsk->active_mm->cpu_vm_mask does not have the
- *    current cpu's bit set, that tlb context is flushed locally.
- *
- *    If the address space is non-shared (ie. mm->count == 1) we avoid
- *    cross calls when we want to flush the currently running process's
- *    tlb state.  This is done by clearing all cpu bits except the current
- *    processor's in current->mm->cpu_vm_mask and performing the
- *    flush locally only.  This will force any subsequent cpus which run
- *    this task to flush the context from the local tlb if the process
- *    migrates to another cpu (again).
- *
- * 3) For shared address spaces (threads) and swapping we bite the
- *    bullet for most cases and perform the cross call (but only to
- *    the cpus listed in cpu_vm_mask).
- *
- *    The performance gain from "optimizing" away the cross call for threads is
- *    questionable (in theory the big win for threads is the massive sharing of
- *    address space state across processors).
+ * mm->cpu_vm_mask is a bit mask of which cpus an address
+ * space has (potentially) executed on, this is the heuristic
+ * we use to limit cross calls.
  */
 
 /* This currently is only used by the hugetlb arch pre-fault
@@ -1057,18 +1042,13 @@
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
 	u32 ctx = CTX_HWBITS(mm->context);
-	int cpu = get_cpu();
 
-	if (atomic_read(&mm->mm_users) == 1) {
-		cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
-		goto local_flush_and_out;
-	}
+	get_cpu();
 
 	smp_cross_call_masked(&xcall_flush_tlb_mm,
 			      ctx, 0, 0,
 			      mm_cpumask(mm));
 
-local_flush_and_out:
 	__flush_tlb_mm(ctx, SECONDARY_CONTEXT);
 
 	put_cpu();
@@ -1091,17 +1071,15 @@
 {
 	u32 ctx = CTX_HWBITS(mm->context);
 	struct tlb_pending_info info;
-	int cpu = get_cpu();
+
+	get_cpu();
 
 	info.ctx = ctx;
 	info.nr = nr;
 	info.vaddrs = vaddrs;
 
-	if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
-		cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
-	else
-		smp_call_function_many(mm_cpumask(mm), tlb_pending_func,
-				       &info, 1);
+	smp_call_function_many(mm_cpumask(mm), tlb_pending_func,
+			       &info, 1);
 
 	__flush_tlb_pending(ctx, nr, vaddrs);
 
@@ -1111,14 +1089,13 @@
 void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
 {
 	unsigned long context = CTX_HWBITS(mm->context);
-	int cpu = get_cpu();
 
-	if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
-		cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
-	else
-		smp_cross_call_masked(&xcall_flush_tlb_page,
-				      context, vaddr, 0,
-				      mm_cpumask(mm));
+	get_cpu();
+
+	smp_cross_call_masked(&xcall_flush_tlb_page,
+			      context, vaddr, 0,
+			      mm_cpumask(mm));
+
 	__flush_tlb_page(context, vaddr);
 
 	put_cpu();
@@ -1429,8 +1406,12 @@
 	int cpu;
 
 	if (tlb_type == hypervisor) {
+		int this_cpu = smp_processor_id();
+#ifdef CONFIG_SERIAL_SUNHV
+		sunhv_migrate_hvcons_irq(this_cpu);
+#endif
 		for_each_online_cpu(cpu) {
-			if (cpu == smp_processor_id())
+			if (cpu == this_cpu)
 				continue;
 #ifdef CONFIG_SUN_LDOMS
 			if (ldom_domaining_enabled) {
--- linux-4.4.0.orig/arch/sparc/kernel/sparc_ksyms_64.c
+++ linux-4.4.0/arch/sparc/kernel/sparc_ksyms_64.c
@@ -27,7 +27,6 @@
 EXPORT_SYMBOL_GPL(real_hard_smp_processor_id);
 
 /* from head_64.S */
-EXPORT_SYMBOL(__ret_efault);
 EXPORT_SYMBOL(tlb_type);
 EXPORT_SYMBOL(sun4v_chip_type);
 EXPORT_SYMBOL(prom_root_node);
--- linux-4.4.0.orig/arch/sparc/kernel/spiterrs.S
+++ linux-4.4.0/arch/sparc/kernel/spiterrs.S
@@ -85,8 +85,7 @@
 	ba,pt		%xcc, etraptl1
 	 rd		%pc, %g7
 
-	ba,pt		%xcc, 2f
-	 nop
+	ba,a,pt		%xcc, 2f
 
 1:	ba,pt		%xcc, etrap_irq
 	 rd		%pc, %g7
@@ -100,8 +99,7 @@
 	mov		%l5, %o2
 	call		spitfire_access_error
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		__spitfire_access_error,.-__spitfire_access_error
 
 	/* This is the trap handler entry point for ECC correctable
@@ -179,8 +177,7 @@
 	mov		%l5, %o2
 	call		spitfire_data_access_exception_tl1
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		__spitfire_data_access_exception_tl1,.-__spitfire_data_access_exception_tl1
 
 	.type		__spitfire_data_access_exception,#function
@@ -200,8 +197,7 @@
 	mov		%l5, %o2
 	call		spitfire_data_access_exception
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		__spitfire_data_access_exception,.-__spitfire_data_access_exception
 
 	.type		__spitfire_insn_access_exception_tl1,#function
@@ -220,8 +216,7 @@
 	mov		%l5, %o2
 	call		spitfire_insn_access_exception_tl1
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		__spitfire_insn_access_exception_tl1,.-__spitfire_insn_access_exception_tl1
 
 	.type		__spitfire_insn_access_exception,#function
@@ -240,6 +235,5 @@
 	mov		%l5, %o2
 	call		spitfire_insn_access_exception
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 	.size		__spitfire_insn_access_exception,.-__spitfire_insn_access_exception
--- linux-4.4.0.orig/arch/sparc/kernel/sun4v_ivec.S
+++ linux-4.4.0/arch/sparc/kernel/sun4v_ivec.S
@@ -26,6 +26,21 @@
 	ldxa	[%g0] ASI_SCRATCHPAD, %g4
 	sub	%g4, TRAP_PER_CPU_FAULT_INFO, %g4
 
+	/* Get smp_processor_id() into %g3 */
+	sethi	%hi(trap_block), %g5
+	or	%g5, %lo(trap_block), %g5
+	sub	%g4, %g5, %g3
+	srlx	%g3, TRAP_BLOCK_SZ_SHIFT, %g3
+
+	/* Increment cpu_mondo_counter[smp_processor_id()] */
+	sethi	%hi(cpu_mondo_counter), %g5
+	or	%g5, %lo(cpu_mondo_counter), %g5
+	sllx	%g3, 3, %g3
+	add	%g5, %g3, %g5
+	ldx	[%g5], %g3
+	add	%g3, 1, %g3
+	stx	%g3, [%g5]
+
 	/* Get CPU mondo queue base phys address into %g7.  */
 	ldx	[%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
 
--- linux-4.4.0.orig/arch/sparc/kernel/sys_sparc_32.c
+++ linux-4.4.0/arch/sparc/kernel/sys_sparc_32.c
@@ -201,23 +201,27 @@
 
 asmlinkage long sys_getdomainname(char __user *name, int len)
 {
- 	int nlen, err;
- 	
+	int nlen, err;
+	char tmp[__NEW_UTS_LEN + 1];
+
 	if (len < 0)
 		return -EINVAL;
 
- 	down_read(&uts_sem);
- 	
+	down_read(&uts_sem);
+
 	nlen = strlen(utsname()->domainname) + 1;
 	err = -EINVAL;
 	if (nlen > len)
-		goto out;
+		goto out_unlock;
+	memcpy(tmp, utsname()->domainname, nlen);
+
+	up_read(&uts_sem);
 
-	err = -EFAULT;
-	if (!copy_to_user(name, utsname()->domainname, nlen))
-		err = 0;
+	if (copy_to_user(name, tmp, nlen))
+		return -EFAULT;
+	return 0;
 
-out:
+out_unlock:
 	up_read(&uts_sem);
 	return err;
 }
--- linux-4.4.0.orig/arch/sparc/kernel/sys_sparc_64.c
+++ linux-4.4.0/arch/sparc/kernel/sys_sparc_64.c
@@ -118,7 +118,7 @@
 
 		vma = find_vma(mm, addr);
 		if (task_size - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
@@ -181,7 +181,7 @@
 
 		vma = find_vma(mm, addr);
 		if (task_size - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
@@ -413,7 +413,7 @@
 
 SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality)
 {
-	int ret;
+	long ret;
 
 	if (personality(current->personality) == PER_LINUX32 &&
 	    personality(personality) == PER_LINUX)
@@ -524,23 +524,27 @@
 
 SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len)
 {
-        int nlen, err;
+	int nlen, err;
+	char tmp[__NEW_UTS_LEN + 1];
 
 	if (len < 0)
 		return -EINVAL;
 
- 	down_read(&uts_sem);
- 	
+	down_read(&uts_sem);
+
 	nlen = strlen(utsname()->domainname) + 1;
 	err = -EINVAL;
 	if (nlen > len)
-		goto out;
+		goto out_unlock;
+	memcpy(tmp, utsname()->domainname, nlen);
+
+	up_read(&uts_sem);
 
-	err = -EFAULT;
-	if (!copy_to_user(name, utsname()->domainname, nlen))
-		err = 0;
+	if (copy_to_user(name, tmp, nlen))
+		return -EFAULT;
+	return 0;
 
-out:
+out_unlock:
 	up_read(&uts_sem);
 	return err;
 }
--- linux-4.4.0.orig/arch/sparc/kernel/syscalls.S
+++ linux-4.4.0/arch/sparc/kernel/syscalls.S
@@ -158,7 +158,25 @@
 	 add	%sp, PTREGS_OFF, %o0
 	brnz,pn	%o0, 3f
 	 mov	-ENOSYS, %o0
+
+	/* Syscall tracing can modify the registers.  */
+	ldx	[%sp + PTREGS_OFF + PT_V9_G1], %g1
+	sethi	%hi(sys_call_table32), %l7
+	ldx	[%sp + PTREGS_OFF + PT_V9_I0], %i0
+	or	%l7, %lo(sys_call_table32), %l7
+	ldx	[%sp + PTREGS_OFF + PT_V9_I1], %i1
+	ldx	[%sp + PTREGS_OFF + PT_V9_I2], %i2
+	ldx	[%sp + PTREGS_OFF + PT_V9_I3], %i3
+	ldx	[%sp + PTREGS_OFF + PT_V9_I4], %i4
+	ldx	[%sp + PTREGS_OFF + PT_V9_I5], %i5
+
+	cmp	%g1, NR_syscalls
+	bgeu,pn	%xcc, 3f
+	 mov	-ENOSYS, %o0
+
+	sll	%g1, 2, %l4
 	srl	%i0, 0, %o0
+	lduw	[%l7 + %l4], %l7
 	srl	%i4, 0, %o4
 	srl	%i1, 0, %o1
 	srl	%i2, 0, %o2
@@ -170,7 +188,25 @@
 	 add	%sp, PTREGS_OFF, %o0
 	brnz,pn	%o0, 3f
 	 mov	-ENOSYS, %o0
+
+	/* Syscall tracing can modify the registers.  */
+	ldx	[%sp + PTREGS_OFF + PT_V9_G1], %g1
+	sethi	%hi(sys_call_table64), %l7
+	ldx	[%sp + PTREGS_OFF + PT_V9_I0], %i0
+	or	%l7, %lo(sys_call_table64), %l7
+	ldx	[%sp + PTREGS_OFF + PT_V9_I1], %i1
+	ldx	[%sp + PTREGS_OFF + PT_V9_I2], %i2
+	ldx	[%sp + PTREGS_OFF + PT_V9_I3], %i3
+	ldx	[%sp + PTREGS_OFF + PT_V9_I4], %i4
+	ldx	[%sp + PTREGS_OFF + PT_V9_I5], %i5
+
+	cmp	%g1, NR_syscalls
+	bgeu,pn	%xcc, 3f
+	 mov	-ENOSYS, %o0
+
+	sll	%g1, 2, %l4
 	mov	%i0, %o0
+	lduw	[%l7 + %l4], %l7
 	mov	%i1, %o1
 	mov	%i2, %o2
 	mov	%i3, %o3
--- linux-4.4.0.orig/arch/sparc/kernel/traps_64.c
+++ linux-4.4.0/arch/sparc/kernel/traps_64.c
@@ -85,7 +85,7 @@
 
 void bad_trap(struct pt_regs *regs, long lvl)
 {
-	char buffer[32];
+	char buffer[36];
 	siginfo_t info;
 
 	if (notify_die(DIE_TRAP, "bad trap", regs,
@@ -116,7 +116,7 @@
 
 void bad_trap_tl1(struct pt_regs *regs, long lvl)
 {
-	char buffer[32];
+	char buffer[36];
 	
 	if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs,
 		       0, lvl, SIGTRAP) == NOTIFY_STOP)
@@ -2659,6 +2659,7 @@
 	}
 }
 
+u64 cpu_mondo_counter[NR_CPUS] = {0};
 struct trap_per_cpu trap_block[NR_CPUS];
 EXPORT_SYMBOL(trap_block);
 
--- linux-4.4.0.orig/arch/sparc/kernel/tsb.S
+++ linux-4.4.0/arch/sparc/kernel/tsb.S
@@ -29,13 +29,17 @@
 	 */
 tsb_miss_dtlb:
 	mov		TLB_TAG_ACCESS, %g4
+	ldxa		[%g4] ASI_DMMU, %g4
+	srlx		%g4, PAGE_SHIFT, %g4
 	ba,pt		%xcc, tsb_miss_page_table_walk
-	 ldxa		[%g4] ASI_DMMU, %g4
+	 sllx		%g4, PAGE_SHIFT, %g4
 
 tsb_miss_itlb:
 	mov		TLB_TAG_ACCESS, %g4
+	ldxa		[%g4] ASI_IMMU, %g4
+	srlx		%g4, PAGE_SHIFT, %g4
 	ba,pt		%xcc, tsb_miss_page_table_walk
-	 ldxa		[%g4] ASI_IMMU, %g4
+	 sllx		%g4, PAGE_SHIFT, %g4
 
 	/* At this point we have:
 	 * %g1 --	PAGE_SIZE TSB entry address
@@ -284,6 +288,10 @@
 	nop
 	.previous
 
+	/* Clear context ID bits.  */
+	srlx		%g5, PAGE_SHIFT, %g5
+	sllx		%g5, PAGE_SHIFT, %g5
+
 	be,pt	%xcc, sparc64_realfault_common
 	 mov	FAULT_CODE_DTLB, %g4
 	ba,pt	%xcc, winfix_trampoline
@@ -367,6 +375,7 @@
 	 * %o1:	TSB base config pointer
 	 * %o2:	TSB huge config pointer, or NULL if none
 	 * %o3:	Hypervisor TSB descriptor physical address
+	 * %o4: Secondary context to load, if non-zero
 	 *
 	 * We have to run this whole thing with interrupts
 	 * disabled so that the current cpu doesn't change
@@ -379,6 +388,17 @@
 	rdpr	%pstate, %g1
 	wrpr	%g1, PSTATE_IE, %pstate
 
+	brz,pn	%o4, 1f
+	 mov	SECONDARY_CONTEXT, %o5
+
+661:	stxa	%o4, [%o5] ASI_DMMU
+	.section .sun4v_1insn_patch, "ax"
+	.word	661b
+	stxa	%o4, [%o5] ASI_MMU
+	.previous
+	flush	%g6
+
+1:
 	TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
 
 	stx	%o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
@@ -462,13 +482,16 @@
 	.type	copy_tsb,#function
 copy_tsb:		/* %o0=old_tsb_base, %o1=old_tsb_size
 			 * %o2=new_tsb_base, %o3=new_tsb_size
+			 * %o4=page_size_shift
 			 */
 	sethi		%uhi(TSB_PASS_BITS), %g7
 	srlx		%o3, 4, %o3
-	add		%o0, %o1, %g1	/* end of old tsb */
+	add		%o0, %o1, %o1	/* end of old tsb */
 	sllx		%g7, 32, %g7
 	sub		%o3, 1, %o3	/* %o3 == new tsb hash mask */
 
+	mov		%o4, %g1	/* page_size_shift */
+
 661:	prefetcha	[%o0] ASI_N, #one_read
 	.section	.tsb_phys_patch, "ax"
 	.word		661b
@@ -493,9 +516,9 @@
 	/* This can definitely be computed faster... */
 	srlx		%o0, 4, %o5	/* Build index */
 	and		%o5, 511, %o5	/* Mask index */
-	sllx		%o5, PAGE_SHIFT, %o5 /* Put into vaddr position */
+	sllx		%o5, %g1, %o5	/* Put into vaddr position */
 	or		%o4, %o5, %o4	/* Full VADDR. */
-	srlx		%o4, PAGE_SHIFT, %o4 /* Shift down to create index */
+	srlx		%o4, %g1, %o4	/* Shift down to create index */
 	and		%o4, %o3, %o4	/* Mask with new_tsb_nents-1 */
 	sllx		%o4, 4, %o4	/* Shift back up into tsb ent offset */
 	TSB_STORE(%o2 + %o4, %g2)	/* Store TAG */
@@ -503,7 +526,7 @@
 	TSB_STORE(%o2 + %o4, %g3)	/* Store TTE */
 
 80:	add		%o0, 16, %o0
-	cmp		%o0, %g1
+	cmp		%o0, %o1
 	bne,pt		%xcc, 90b
 	 nop
 
--- linux-4.4.0.orig/arch/sparc/kernel/ttable_64.S
+++ linux-4.4.0/arch/sparc/kernel/ttable_64.S
@@ -50,7 +50,7 @@
 tl0_irq1:	TRAP_IRQ(smp_call_function_client, 1)
 tl0_irq2:	TRAP_IRQ(smp_receive_signal_client, 2)
 tl0_irq3:	TRAP_IRQ(smp_penguin_jailcell, 3)
-tl0_irq4:	TRAP_IRQ(smp_new_mmu_context_version_client, 4)
+tl0_irq4:       BTRAP(0x44)
 #else
 tl0_irq1:	BTRAP(0x41)
 tl0_irq2:	BTRAP(0x42)
--- linux-4.4.0.orig/arch/sparc/kernel/urtt_fill.S
+++ linux-4.4.0/arch/sparc/kernel/urtt_fill.S
@@ -0,0 +1,98 @@
+#include <asm/thread_info.h>
+#include <asm/trap_block.h>
+#include <asm/spitfire.h>
+#include <asm/ptrace.h>
+#include <asm/head.h>
+
+		.text
+		.align	8
+		.globl	user_rtt_fill_fixup_common
+user_rtt_fill_fixup_common:
+		rdpr	%cwp, %g1
+		add	%g1, 1, %g1
+		wrpr	%g1, 0x0, %cwp
+
+		rdpr	%wstate, %g2
+		sll	%g2, 3, %g2
+		wrpr	%g2, 0x0, %wstate
+
+		/* We know %canrestore and %otherwin are both zero.  */
+
+		sethi	%hi(sparc64_kern_pri_context), %g2
+		ldx	[%g2 + %lo(sparc64_kern_pri_context)], %g2
+		mov	PRIMARY_CONTEXT, %g1
+
+661:		stxa	%g2, [%g1] ASI_DMMU
+		.section .sun4v_1insn_patch, "ax"
+		.word	661b
+		stxa	%g2, [%g1] ASI_MMU
+		.previous
+
+		sethi	%hi(KERNBASE), %g1
+		flush	%g1
+
+		mov	%g4, %l4
+		mov	%g5, %l5
+		brnz,pn	%g3, 1f
+		 mov	%g3, %l3
+
+		or	%g4, FAULT_CODE_WINFIXUP, %g4
+		stb	%g4, [%g6 + TI_FAULT_CODE]
+		stx	%g5, [%g6 + TI_FAULT_ADDR]
+1:
+		mov	%g6, %l1
+		wrpr	%g0, 0x0, %tl
+
+661:		nop
+		.section		.sun4v_1insn_patch, "ax"
+		.word			661b
+		SET_GL(0)
+		.previous
+
+		wrpr	%g0, RTRAP_PSTATE, %pstate
+
+		mov	%l1, %g6
+		ldx	[%g6 + TI_TASK], %g4
+		LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3)
+
+		brnz,pn	%l3, 1f
+		 nop
+
+		call	do_sparc64_fault
+		 add	%sp, PTREGS_OFF, %o0
+		ba,pt	%xcc, rtrap
+		 nop
+
+1:		cmp	%g3, 2
+		bne,pn	%xcc, 2f
+		 nop
+
+		sethi	%hi(tlb_type), %g1
+		lduw	[%g1 + %lo(tlb_type)], %g1
+		cmp	%g1, 3
+		bne,pt	%icc, 1f
+		 add	%sp, PTREGS_OFF, %o0
+		mov	%l4, %o2
+		call	sun4v_do_mna
+		 mov	%l5, %o1
+		ba,a,pt	%xcc, rtrap
+1:		mov	%l4, %o1
+		mov	%l5, %o2
+		call	mem_address_unaligned
+		 nop
+		ba,a,pt	%xcc, rtrap
+
+2:		sethi	%hi(tlb_type), %g1
+		mov	%l4, %o1
+		lduw	[%g1 + %lo(tlb_type)], %g1
+		mov	%l5, %o2
+		cmp	%g1, 3
+		bne,pt	%icc, 1f
+		 add	%sp, PTREGS_OFF, %o0
+		call	sun4v_data_access_exception
+		 nop
+		ba,a,pt	%xcc, rtrap
+
+1:		call	spitfire_data_access_exception
+		 nop
+		ba,a,pt	%xcc, rtrap
--- linux-4.4.0.orig/arch/sparc/kernel/utrap.S
+++ linux-4.4.0/arch/sparc/kernel/utrap.S
@@ -11,8 +11,7 @@
 	mov		%l4, %o1
         call		bad_trap
 	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop
+	ba,a,pt		%xcc, rtrap
 
 invoke_utrap:
 	sllx		%g3, 3, %g3
--- linux-4.4.0.orig/arch/sparc/kernel/vio.c
+++ linux-4.4.0/arch/sparc/kernel/vio.c
@@ -284,13 +284,16 @@
 	if (!id) {
 		dev_set_name(&vdev->dev, "%s", bus_id_name);
 		vdev->dev_no = ~(u64)0;
+		vdev->id = ~(u64)0;
 	} else if (!cfg_handle) {
 		dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id);
 		vdev->dev_no = *id;
+		vdev->id = ~(u64)0;
 	} else {
 		dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name,
 			     *cfg_handle, *id);
 		vdev->dev_no = *cfg_handle;
+		vdev->id = *id;
 	}
 
 	vdev->dev.parent = parent;
@@ -333,27 +336,84 @@
 	(void) vio_create_one(hp, node, &root_vdev->dev);
 }
 
+struct vio_md_node_query {
+	const char *type;
+	u64 dev_no;
+	u64 id;
+};
+
 static int vio_md_node_match(struct device *dev, void *arg)
 {
+	struct vio_md_node_query *query = (struct vio_md_node_query *) arg;
 	struct vio_dev *vdev = to_vio_dev(dev);
 
-	if (vdev->mp == (u64) arg)
-		return 1;
+	if (vdev->dev_no != query->dev_no)
+		return 0;
+	if (vdev->id != query->id)
+		return 0;
+	if (strcmp(vdev->type, query->type))
+		return 0;
 
-	return 0;
+	return 1;
 }
 
 static void vio_remove(struct mdesc_handle *hp, u64 node)
 {
+	const char *type;
+	const u64 *id, *cfg_handle;
+	u64 a;
+	struct vio_md_node_query query;
 	struct device *dev;
 
-	dev = device_find_child(&root_vdev->dev, (void *) node,
+	type = mdesc_get_property(hp, node, "device-type", NULL);
+	if (!type) {
+		type = mdesc_get_property(hp, node, "name", NULL);
+		if (!type)
+			type = mdesc_node_name(hp, node);
+	}
+
+	query.type = type;
+
+	id = mdesc_get_property(hp, node, "id", NULL);
+	cfg_handle = NULL;
+	mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+		u64 target;
+
+		target = mdesc_arc_target(hp, a);
+		cfg_handle = mdesc_get_property(hp, target,
+						"cfg-handle", NULL);
+		if (cfg_handle)
+			break;
+	}
+
+	if (!id) {
+		query.dev_no = ~(u64)0;
+		query.id = ~(u64)0;
+	} else if (!cfg_handle) {
+		query.dev_no = *id;
+		query.id = ~(u64)0;
+	} else {
+		query.dev_no = *cfg_handle;
+		query.id = *id;
+	}
+
+	dev = device_find_child(&root_vdev->dev, &query,
 				vio_md_node_match);
 	if (dev) {
 		printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));
 
 		device_unregister(dev);
 		put_device(dev);
+	} else {
+		if (!id)
+			printk(KERN_ERR "VIO: Removed unknown %s node.\n",
+			       type);
+		else if (!cfg_handle)
+			printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n",
+			       type, *id);
+		else
+			printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n",
+			       type, *cfg_handle, *id);
 	}
 }
 
--- linux-4.4.0.orig/arch/sparc/kernel/vmlinux.lds.S
+++ linux-4.4.0/arch/sparc/kernel/vmlinux.lds.S
@@ -33,6 +33,10 @@
 jiffies = jiffies_64;
 #endif
 
+#ifdef CONFIG_SPARC64
+ASSERT((swapper_tsb == 0x0000000000408000), "Error: sparc64 early assembler too large")
+#endif
+
 SECTIONS
 {
 #ifdef CONFIG_SPARC64
--- linux-4.4.0.orig/arch/sparc/kernel/winfixup.S
+++ linux-4.4.0/arch/sparc/kernel/winfixup.S
@@ -32,8 +32,7 @@
 	 rd	%pc, %g7
 	call	do_sparc64_fault
 	 add	%sp, PTREGS_OFF, %o0
-	ba,pt	%xcc, rtrap
-	 nop
+	ba,a,pt	%xcc, rtrap
 
 	/* Be very careful about usage of the trap globals here.
 	 * You cannot touch %g5 as that has the fault information.
--- linux-4.4.0.orig/arch/sparc/lib/GENcopy_from_user.S
+++ linux-4.4.0/arch/sparc/lib/GENcopy_from_user.S
@@ -3,11 +3,11 @@
  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_LD(x)		\
+#define EX_LD(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one;	\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/GENcopy_to_user.S
+++ linux-4.4.0/arch/sparc/lib/GENcopy_to_user.S
@@ -3,11 +3,11 @@
  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_ST(x)		\
+#define EX_ST(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one;	\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/GENmemcpy.S
+++ linux-4.4.0/arch/sparc/lib/GENmemcpy.S
@@ -4,21 +4,18 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #define GLOBAL_SPARE	%g7
 #else
 #define GLOBAL_SPARE	%g5
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)	x
+#define EX_LD(x,y)	x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)	x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)	x
+#define EX_ST(x,y)	x
 #endif
 
 #ifndef LOAD
@@ -45,6 +42,29 @@
 	.register	%g3,#scratch
 
 	.text
+
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)	x
+ENTRY(GEN_retl_o4_1)
+	add	%o4, %o2, %o4
+	retl
+	 add	%o4, 1, %o0
+ENDPROC(GEN_retl_o4_1)
+ENTRY(GEN_retl_g1_8)
+	add	%g1, %o2, %g1
+	retl
+	 add	%g1, 8, %o0
+ENDPROC(GEN_retl_g1_8)
+ENTRY(GEN_retl_o2_4)
+	retl
+	 add	%o2, 4, %o0
+ENDPROC(GEN_retl_o2_4)
+ENTRY(GEN_retl_o2_1)
+	retl
+	 add	%o2, 1, %o0
+ENDPROC(GEN_retl_o2_1)
+#endif
+
 	.align		64
 
 	.globl	FUNC_NAME
@@ -73,8 +93,8 @@
 	sub		%g0, %o4, %o4
 	sub		%o2, %o4, %o2
 1:	subcc		%o4, 1, %o4
-	EX_LD(LOAD(ldub, %o1, %g1))
-	EX_ST(STORE(stb, %g1, %o0))
+	EX_LD(LOAD(ldub, %o1, %g1),GEN_retl_o4_1)
+	EX_ST(STORE(stb, %g1, %o0),GEN_retl_o4_1)
 	add		%o1, 1, %o1
 	bne,pt		%XCC, 1b
 	add		%o0, 1, %o0
@@ -82,8 +102,8 @@
 	andn		%o2, 0x7, %g1
 	sub		%o2, %g1, %o2
 1:	subcc		%g1, 0x8, %g1
-	EX_LD(LOAD(ldx, %o1, %g2))
-	EX_ST(STORE(stx, %g2, %o0))
+	EX_LD(LOAD(ldx, %o1, %g2),GEN_retl_g1_8)
+	EX_ST(STORE(stx, %g2, %o0),GEN_retl_g1_8)
 	add		%o1, 0x8, %o1
 	bne,pt		%XCC, 1b
 	 add		%o0, 0x8, %o0
@@ -100,8 +120,8 @@
 
 1:
 	subcc		%o2, 4, %o2
-	EX_LD(LOAD(lduw, %o1, %g1))
-	EX_ST(STORE(stw, %g1, %o1 + %o3))
+	EX_LD(LOAD(lduw, %o1, %g1),GEN_retl_o2_4)
+	EX_ST(STORE(stw, %g1, %o1 + %o3),GEN_retl_o2_4)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 4, %o1
 
@@ -111,8 +131,8 @@
 	.align		32
 90:
 	subcc		%o2, 1, %o2
-	EX_LD(LOAD(ldub, %o1, %g1))
-	EX_ST(STORE(stb, %g1, %o1 + %o3))
+	EX_LD(LOAD(ldub, %o1, %g1),GEN_retl_o2_1)
+	EX_ST(STORE(stb, %g1, %o1 + %o3),GEN_retl_o2_1)
 	bgu,pt		%XCC, 90b
 	 add		%o1, 1, %o1
 	retl
--- linux-4.4.0.orig/arch/sparc/lib/Makefile
+++ linux-4.4.0/arch/sparc/lib/Makefile
@@ -38,7 +38,7 @@
 lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o
 lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
 
-lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o
+lib-$(CONFIG_SPARC64) += copy_in_user.o memmove.o
 lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o
 
 obj-$(CONFIG_SPARC64) += iomap.o
--- linux-4.4.0.orig/arch/sparc/lib/NG2copy_from_user.S
+++ linux-4.4.0/arch/sparc/lib/NG2copy_from_user.S
@@ -3,19 +3,19 @@
  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_LD(x)		\
+#define EX_LD(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_asi;\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
-#define EX_LD_FP(x)		\
+#define EX_LD_FP(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_asi_fp;\
+	.word 98b, y##_fp;	\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/NG2copy_to_user.S
+++ linux-4.4.0/arch/sparc/lib/NG2copy_to_user.S
@@ -3,19 +3,19 @@
  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_ST(x)		\
+#define EX_ST(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_asi;\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
-#define EX_ST_FP(x)		\
+#define EX_ST_FP(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_asi_fp;\
+	.word 98b, y##_fp;	\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/NG2memcpy.S
+++ linux-4.4.0/arch/sparc/lib/NG2memcpy.S
@@ -4,6 +4,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #define GLOBAL_SPARE	%g7
@@ -32,21 +33,17 @@
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)	x
+#define EX_LD(x,y)	x
 #endif
 #ifndef EX_LD_FP
-#define EX_LD_FP(x)	x
+#define EX_LD_FP(x,y)	x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)	x
+#define EX_ST(x,y)	x
 #endif
 #ifndef EX_ST_FP
-#define EX_ST_FP(x)	x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)	x
+#define EX_ST_FP(x,y)	x
 #endif
 
 #ifndef LOAD
@@ -140,45 +137,110 @@
 	fsrc2		%x6, %f12; \
 	fsrc2		%x7, %f14;
 #define FREG_LOAD_1(base, x0) \
-	EX_LD_FP(LOAD(ldd, base + 0x00, %x0))
+	EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1)
 #define FREG_LOAD_2(base, x0, x1) \
-	EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-	EX_LD_FP(LOAD(ldd, base + 0x08, %x1));
+	EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_3(base, x0, x1, x2) \
-	EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-	EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-	EX_LD_FP(LOAD(ldd, base + 0x10, %x2));
+	EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_4(base, x0, x1, x2, x3) \
-	EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-	EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-	EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
-	EX_LD_FP(LOAD(ldd, base + 0x18, %x3));
+	EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x18, %x3), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_5(base, x0, x1, x2, x3, x4) \
-	EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-	EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-	EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
-	EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
-	EX_LD_FP(LOAD(ldd, base + 0x20, %x4));
+	EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x18, %x3), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x20, %x4), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_6(base, x0, x1, x2, x3, x4, x5) \
-	EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-	EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-	EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
-	EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
-	EX_LD_FP(LOAD(ldd, base + 0x20, %x4)); \
-	EX_LD_FP(LOAD(ldd, base + 0x28, %x5));
+	EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x18, %x3), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x20, %x4), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x28, %x5), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_7(base, x0, x1, x2, x3, x4, x5, x6) \
-	EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-	EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-	EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
-	EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
-	EX_LD_FP(LOAD(ldd, base + 0x20, %x4)); \
-	EX_LD_FP(LOAD(ldd, base + 0x28, %x5)); \
-	EX_LD_FP(LOAD(ldd, base + 0x30, %x6));
+	EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x18, %x3), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x20, %x4), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x28, %x5), NG2_retl_o2_plus_g1); \
+	EX_LD_FP(LOAD(ldd, base + 0x30, %x6), NG2_retl_o2_plus_g1);
 
 	.register	%g2,#scratch
 	.register	%g3,#scratch
 
 	.text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)	x
+__restore_fp:
+	VISExitHalf
+__restore_asi:
+	retl
+	 wr	%g0, ASI_AIUS, %asi
+ENTRY(NG2_retl_o2)
+	ba,pt	%xcc, __restore_asi
+	 mov	%o2, %o0
+ENDPROC(NG2_retl_o2)
+ENTRY(NG2_retl_o2_plus_1)
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, 1, %o0
+ENDPROC(NG2_retl_o2_plus_1)
+ENTRY(NG2_retl_o2_plus_4)
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, 4, %o0
+ENDPROC(NG2_retl_o2_plus_4)
+ENTRY(NG2_retl_o2_plus_8)
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, 8, %o0
+ENDPROC(NG2_retl_o2_plus_8)
+ENTRY(NG2_retl_o2_plus_o4_plus_1)
+	add	%o4, 1, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG2_retl_o2_plus_o4_plus_1)
+ENTRY(NG2_retl_o2_plus_o4_plus_8)
+	add	%o4, 8, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG2_retl_o2_plus_o4_plus_8)
+ENTRY(NG2_retl_o2_plus_o4_plus_16)
+	add	%o4, 16, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG2_retl_o2_plus_o4_plus_16)
+ENTRY(NG2_retl_o2_plus_g1_fp)
+	ba,pt	%xcc, __restore_fp
+	 add	%o2, %g1, %o0
+ENDPROC(NG2_retl_o2_plus_g1_fp)
+ENTRY(NG2_retl_o2_plus_g1_plus_64_fp)
+	add	%g1, 64, %g1
+	ba,pt	%xcc, __restore_fp
+	 add	%o2, %g1, %o0
+ENDPROC(NG2_retl_o2_plus_g1_plus_64_fp)
+ENTRY(NG2_retl_o2_plus_g1_plus_1)
+	add	%g1, 1, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %g1, %o0
+ENDPROC(NG2_retl_o2_plus_g1_plus_1)
+ENTRY(NG2_retl_o2_and_7_plus_o4)
+	and	%o2, 7, %o2
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG2_retl_o2_and_7_plus_o4)
+ENTRY(NG2_retl_o2_and_7_plus_o4_plus_8)
+	and	%o2, 7, %o2
+	add	%o4, 8, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG2_retl_o2_and_7_plus_o4_plus_8)
+#endif
+
 	.align		64
 
 	.globl	FUNC_NAME
@@ -230,8 +292,8 @@
 	sub		%g0, %o4, %o4	! bytes to align dst
 	sub		%o2, %o4, %o2
 1:	subcc		%o4, 1, %o4
-	EX_LD(LOAD(ldub, %o1, %g1))
-	EX_ST(STORE(stb, %g1, %o0))
+	EX_LD(LOAD(ldub, %o1, %g1), NG2_retl_o2_plus_o4_plus_1)
+	EX_ST(STORE(stb, %g1, %o0), NG2_retl_o2_plus_o4_plus_1)
 	add		%o1, 1, %o1
 	bne,pt		%XCC, 1b
 	add		%o0, 1, %o0
@@ -281,11 +343,11 @@
 	 nop
 	/* fall through for 0 < low bits < 8 */
 110:	sub		%o4, 64, %g2
-	EX_LD_FP(LOAD_BLK(%g2, %f0))
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-	EX_LD_FP(LOAD_BLK(%o4, %f16))
+	EX_LD_FP(LOAD_BLK(%g2, %f0), NG2_retl_o2_plus_g1)
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+	EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
 	FREG_FROB(f0, f2, f4, f6, f8, f10, f12, f14, f16)
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	FREG_MOVE_8(f16, f18, f20, f22, f24, f26, f28, f30)
 	subcc		%g1, 64, %g1
 	add		%o4, 64, %o4
@@ -296,10 +358,10 @@
 
 120:	sub		%o4, 56, %g2
 	FREG_LOAD_7(%g2, f0, f2, f4, f6, f8, f10, f12)
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-	EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+	EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
 	FREG_FROB(f0, f2, f4, f6, f8, f10, f12, f16, f18)
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	FREG_MOVE_7(f18, f20, f22, f24, f26, f28, f30)
 	subcc		%g1, 64, %g1
 	add		%o4, 64, %o4
@@ -310,10 +372,10 @@
 
 130:	sub		%o4, 48, %g2
 	FREG_LOAD_6(%g2, f0, f2, f4, f6, f8, f10)
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-	EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+	EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
 	FREG_FROB(f0, f2, f4, f6, f8, f10, f16, f18, f20)
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	FREG_MOVE_6(f20, f22, f24, f26, f28, f30)
 	subcc		%g1, 64, %g1
 	add		%o4, 64, %o4
@@ -324,10 +386,10 @@
 
 140:	sub		%o4, 40, %g2
 	FREG_LOAD_5(%g2, f0, f2, f4, f6, f8)
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-	EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+	EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
 	FREG_FROB(f0, f2, f4, f6, f8, f16, f18, f20, f22)
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	FREG_MOVE_5(f22, f24, f26, f28, f30)
 	subcc		%g1, 64, %g1
 	add		%o4, 64, %o4
@@ -338,10 +400,10 @@
 
 150:	sub		%o4, 32, %g2
 	FREG_LOAD_4(%g2, f0, f2, f4, f6)
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-	EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+	EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
 	FREG_FROB(f0, f2, f4, f6, f16, f18, f20, f22, f24)
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	FREG_MOVE_4(f24, f26, f28, f30)
 	subcc		%g1, 64, %g1
 	add		%o4, 64, %o4
@@ -352,10 +414,10 @@
 
 160:	sub		%o4, 24, %g2
 	FREG_LOAD_3(%g2, f0, f2, f4)
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-	EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+	EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
 	FREG_FROB(f0, f2, f4, f16, f18, f20, f22, f24, f26)
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	FREG_MOVE_3(f26, f28, f30)
 	subcc		%g1, 64, %g1
 	add		%o4, 64, %o4
@@ -366,10 +428,10 @@
 
 170:	sub		%o4, 16, %g2
 	FREG_LOAD_2(%g2, f0, f2)
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-	EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+	EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
 	FREG_FROB(f0, f2, f16, f18, f20, f22, f24, f26, f28)
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	FREG_MOVE_2(f28, f30)
 	subcc		%g1, 64, %g1
 	add		%o4, 64, %o4
@@ -380,10 +442,10 @@
 
 180:	sub		%o4, 8, %g2
 	FREG_LOAD_1(%g2, f0)
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-	EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+	EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
 	FREG_FROB(f0, f16, f18, f20, f22, f24, f26, f28, f30)
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	FREG_MOVE_1(f30)
 	subcc		%g1, 64, %g1
 	add		%o4, 64, %o4
@@ -393,10 +455,10 @@
 	 nop
 
 190:
-1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+1:	EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
 	subcc		%g1, 64, %g1
-	EX_LD_FP(LOAD_BLK(%o4, %f0))
-	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+	EX_LD_FP(LOAD_BLK(%o4, %f0), NG2_retl_o2_plus_g1_plus_64)
+	EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1_plus_64)
 	add		%o4, 64, %o4
 	bne,pt		%xcc, 1b
 	 LOAD(prefetch, %o4 + 64, #one_read)
@@ -423,28 +485,28 @@
 	andn		%o2, 0xf, %o4
 	and		%o2, 0xf, %o2
 1:	subcc		%o4, 0x10, %o4
-	EX_LD(LOAD(ldx, %o1, %o5))
+	EX_LD(LOAD(ldx, %o1, %o5), NG2_retl_o2_plus_o4_plus_16)
 	add		%o1, 0x08, %o1
-	EX_LD(LOAD(ldx, %o1, %g1))
+	EX_LD(LOAD(ldx, %o1, %g1), NG2_retl_o2_plus_o4_plus_16)
 	sub		%o1, 0x08, %o1
-	EX_ST(STORE(stx, %o5, %o1 + GLOBAL_SPARE))
+	EX_ST(STORE(stx, %o5, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_o4_plus_16)
 	add		%o1, 0x8, %o1
-	EX_ST(STORE(stx, %g1, %o1 + GLOBAL_SPARE))
+	EX_ST(STORE(stx, %g1, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_o4_plus_8)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 0x8, %o1
 73:	andcc		%o2, 0x8, %g0
 	be,pt		%XCC, 1f
 	 nop
 	sub		%o2, 0x8, %o2
-	EX_LD(LOAD(ldx, %o1, %o5))
-	EX_ST(STORE(stx, %o5, %o1 + GLOBAL_SPARE))
+	EX_LD(LOAD(ldx, %o1, %o5), NG2_retl_o2_plus_8)
+	EX_ST(STORE(stx, %o5, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_8)
 	add		%o1, 0x8, %o1
 1:	andcc		%o2, 0x4, %g0
 	be,pt		%XCC, 1f
 	 nop
 	sub		%o2, 0x4, %o2
-	EX_LD(LOAD(lduw, %o1, %o5))
-	EX_ST(STORE(stw, %o5, %o1 + GLOBAL_SPARE))
+	EX_LD(LOAD(lduw, %o1, %o5), NG2_retl_o2_plus_4)
+	EX_ST(STORE(stw, %o5, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_4)
 	add		%o1, 0x4, %o1
 1:	cmp		%o2, 0
 	be,pt		%XCC, 85f
@@ -460,8 +522,8 @@
 	sub		%o2, %g1, %o2
 
 1:	subcc		%g1, 1, %g1
-	EX_LD(LOAD(ldub, %o1, %o5))
-	EX_ST(STORE(stb, %o5, %o1 + GLOBAL_SPARE))
+	EX_LD(LOAD(ldub, %o1, %o5), NG2_retl_o2_plus_g1_plus_1)
+	EX_ST(STORE(stb, %o5, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_g1_plus_1)
 	bgu,pt		%icc, 1b
 	 add		%o1, 1, %o1
 
@@ -477,16 +539,16 @@
 
 8:	mov		64, GLOBAL_SPARE
 	andn		%o1, 0x7, %o1
-	EX_LD(LOAD(ldx, %o1, %g2))
+	EX_LD(LOAD(ldx, %o1, %g2), NG2_retl_o2)
 	sub		GLOBAL_SPARE, %g1, GLOBAL_SPARE
 	andn		%o2, 0x7, %o4
 	sllx		%g2, %g1, %g2
 1:	add		%o1, 0x8, %o1
-	EX_LD(LOAD(ldx, %o1, %g3))
+	EX_LD(LOAD(ldx, %o1, %g3), NG2_retl_o2_and_7_plus_o4)
 	subcc		%o4, 0x8, %o4
 	srlx		%g3, GLOBAL_SPARE, %o5
 	or		%o5, %g2, %o5
-	EX_ST(STORE(stx, %o5, %o0))
+	EX_ST(STORE(stx, %o5, %o0), NG2_retl_o2_and_7_plus_o4_plus_8)
 	add		%o0, 0x8, %o0
 	bgu,pt		%icc, 1b
 	 sllx		%g3, %g1, %g2
@@ -506,8 +568,8 @@
 
 1:
 	subcc		%o2, 4, %o2
-	EX_LD(LOAD(lduw, %o1, %g1))
-	EX_ST(STORE(stw, %g1, %o1 + GLOBAL_SPARE))
+	EX_LD(LOAD(lduw, %o1, %g1), NG2_retl_o2_plus_4)
+	EX_ST(STORE(stw, %g1, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_4)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 4, %o1
 
@@ -517,8 +579,8 @@
 	.align		32
 90:
 	subcc		%o2, 1, %o2
-	EX_LD(LOAD(ldub, %o1, %g1))
-	EX_ST(STORE(stb, %g1, %o1 + GLOBAL_SPARE))
+	EX_LD(LOAD(ldub, %o1, %g1), NG2_retl_o2_plus_1)
+	EX_ST(STORE(stb, %g1, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_1)
 	bgu,pt		%XCC, 90b
 	 add		%o1, 1, %o1
 	retl
--- linux-4.4.0.orig/arch/sparc/lib/NG4copy_from_user.S
+++ linux-4.4.0/arch/sparc/lib/NG4copy_from_user.S
@@ -3,19 +3,19 @@
  * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_LD(x)		\
+#define EX_LD(x, y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_asi;\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
-#define EX_LD_FP(x)		\
+#define EX_LD_FP(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_asi_fp;\
+	.word 98b, y##_fp;	\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/NG4copy_to_user.S
+++ linux-4.4.0/arch/sparc/lib/NG4copy_to_user.S
@@ -3,19 +3,19 @@
  * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_ST(x)		\
+#define EX_ST(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_asi;\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
-#define EX_ST_FP(x)		\
+#define EX_ST_FP(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_asi_fp;\
+	.word 98b, y##_fp;	\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/NG4memcpy.S
+++ linux-4.4.0/arch/sparc/lib/NG4memcpy.S
@@ -4,6 +4,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #define GLOBAL_SPARE	%g7
@@ -46,22 +47,19 @@
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)	x
+#define EX_LD(x,y)	x
 #endif
 #ifndef EX_LD_FP
-#define EX_LD_FP(x)	x
+#define EX_LD_FP(x,y)	x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)	x
+#define EX_ST(x,y)	x
 #endif
 #ifndef EX_ST_FP
-#define EX_ST_FP(x)	x
+#define EX_ST_FP(x,y)	x
 #endif
 
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)	x
-#endif
 
 #ifndef LOAD
 #define LOAD(type,addr,dest)	type [addr], dest
@@ -94,6 +92,158 @@
 	.register	%g3,#scratch
 
 	.text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)	x
+__restore_asi_fp:
+	VISExitHalf
+__restore_asi:
+	retl
+	 wr	%g0, ASI_AIUS, %asi
+
+ENTRY(NG4_retl_o2)
+	ba,pt	%xcc, __restore_asi
+	 mov	%o2, %o0
+ENDPROC(NG4_retl_o2)
+ENTRY(NG4_retl_o2_plus_1)
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, 1, %o0
+ENDPROC(NG4_retl_o2_plus_1)
+ENTRY(NG4_retl_o2_plus_4)
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, 4, %o0
+ENDPROC(NG4_retl_o2_plus_4)
+ENTRY(NG4_retl_o2_plus_o5)
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5)
+ENTRY(NG4_retl_o2_plus_o5_plus_4)
+	add	%o5, 4, %o5
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_4)
+ENTRY(NG4_retl_o2_plus_o5_plus_8)
+	add	%o5, 8, %o5
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_8)
+ENTRY(NG4_retl_o2_plus_o5_plus_16)
+	add	%o5, 16, %o5
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_16)
+ENTRY(NG4_retl_o2_plus_o5_plus_24)
+	add	%o5, 24, %o5
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_24)
+ENTRY(NG4_retl_o2_plus_o5_plus_32)
+	add	%o5, 32, %o5
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_32)
+ENTRY(NG4_retl_o2_plus_g1)
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %g1, %o0
+ENDPROC(NG4_retl_o2_plus_g1)
+ENTRY(NG4_retl_o2_plus_g1_plus_1)
+	add	%g1, 1, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %g1, %o0
+ENDPROC(NG4_retl_o2_plus_g1_plus_1)
+ENTRY(NG4_retl_o2_plus_g1_plus_8)
+	add	%g1, 8, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %g1, %o0
+ENDPROC(NG4_retl_o2_plus_g1_plus_8)
+ENTRY(NG4_retl_o2_plus_o4)
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4)
+ENTRY(NG4_retl_o2_plus_o4_plus_8)
+	add	%o4, 8, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_8)
+ENTRY(NG4_retl_o2_plus_o4_plus_16)
+	add	%o4, 16, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_16)
+ENTRY(NG4_retl_o2_plus_o4_plus_24)
+	add	%o4, 24, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_24)
+ENTRY(NG4_retl_o2_plus_o4_plus_32)
+	add	%o4, 32, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_32)
+ENTRY(NG4_retl_o2_plus_o4_plus_40)
+	add	%o4, 40, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_40)
+ENTRY(NG4_retl_o2_plus_o4_plus_48)
+	add	%o4, 48, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_48)
+ENTRY(NG4_retl_o2_plus_o4_plus_56)
+	add	%o4, 56, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_56)
+ENTRY(NG4_retl_o2_plus_o4_plus_64)
+	add	%o4, 64, %o4
+	ba,pt	%xcc, __restore_asi
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_64)
+ENTRY(NG4_retl_o2_plus_o4_fp)
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_8_fp)
+	add	%o4, 8, %o4
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_8_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_16_fp)
+	add	%o4, 16, %o4
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_16_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_24_fp)
+	add	%o4, 24, %o4
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_24_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_32_fp)
+	add	%o4, 32, %o4
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_32_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_40_fp)
+	add	%o4, 40, %o4
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_40_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_48_fp)
+	add	%o4, 48, %o4
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_48_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_56_fp)
+	add	%o4, 56, %o4
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_56_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_64_fp)
+	add	%o4, 64, %o4
+	ba,pt	%xcc, __restore_asi_fp
+	 add	%o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_64_fp)
+#endif
 	.align		64
 
 	.globl	FUNC_NAME
@@ -124,12 +274,13 @@
 	brz,pt		%g1, 51f
 	 sub		%o2, %g1, %o2
 
-1:	EX_LD(LOAD(ldub, %o1 + 0x00, %g2))
+
+1:	EX_LD(LOAD(ldub, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
 	add		%o1, 1, %o1
 	subcc		%g1, 1, %g1
 	add		%o0, 1, %o0
 	bne,pt		%icc, 1b
-	 EX_ST(STORE(stb, %g2, %o0 - 0x01))
+	 EX_ST(STORE(stb, %g2, %o0 - 0x01), NG4_retl_o2_plus_g1_plus_1)
 
 51:	LOAD(prefetch, %o1 + 0x040, #n_reads_strong)
 	LOAD(prefetch, %o1 + 0x080, #n_reads_strong)
@@ -154,43 +305,43 @@
 	brz,pt		%g1, .Llarge_aligned
 	 sub		%o2, %g1, %o2
 
-1:	EX_LD(LOAD(ldx, %o1 + 0x00, %g2))
+1:	EX_LD(LOAD(ldx, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
 	add		%o1, 8, %o1
 	subcc		%g1, 8, %g1
 	add		%o0, 8, %o0
 	bne,pt		%icc, 1b
-	 EX_ST(STORE(stx, %g2, %o0 - 0x08))
+	 EX_ST(STORE(stx, %g2, %o0 - 0x08), NG4_retl_o2_plus_g1_plus_8)
 
 .Llarge_aligned:
 	/* len >= 0x80 && src 8-byte aligned && dest 8-byte aligned */
 	andn		%o2, 0x3f, %o4
 	sub		%o2, %o4, %o2
 
-1:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1))
+1:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o4)
 	add		%o1, 0x40, %o1
-	EX_LD(LOAD(ldx, %o1 - 0x38, %g2))
+	EX_LD(LOAD(ldx, %o1 - 0x38, %g2), NG4_retl_o2_plus_o4)
 	subcc		%o4, 0x40, %o4
-	EX_LD(LOAD(ldx, %o1 - 0x30, %g3))
-	EX_LD(LOAD(ldx, %o1 - 0x28, GLOBAL_SPARE))
-	EX_LD(LOAD(ldx, %o1 - 0x20, %o5))
-	EX_ST(STORE_INIT(%g1, %o0))
+	EX_LD(LOAD(ldx, %o1 - 0x30, %g3), NG4_retl_o2_plus_o4_plus_64)
+	EX_LD(LOAD(ldx, %o1 - 0x28, GLOBAL_SPARE), NG4_retl_o2_plus_o4_plus_64)
+	EX_LD(LOAD(ldx, %o1 - 0x20, %o5), NG4_retl_o2_plus_o4_plus_64)
+	EX_ST(STORE_INIT(%g1, %o0), NG4_retl_o2_plus_o4_plus_64)
 	add		%o0, 0x08, %o0
-	EX_ST(STORE_INIT(%g2, %o0))
+	EX_ST(STORE_INIT(%g2, %o0), NG4_retl_o2_plus_o4_plus_56)
 	add		%o0, 0x08, %o0
-	EX_LD(LOAD(ldx, %o1 - 0x18, %g2))
-	EX_ST(STORE_INIT(%g3, %o0))
+	EX_LD(LOAD(ldx, %o1 - 0x18, %g2), NG4_retl_o2_plus_o4_plus_48)
+	EX_ST(STORE_INIT(%g3, %o0), NG4_retl_o2_plus_o4_plus_48)
 	add		%o0, 0x08, %o0
-	EX_LD(LOAD(ldx, %o1 - 0x10, %g3))
-	EX_ST(STORE_INIT(GLOBAL_SPARE, %o0))
+	EX_LD(LOAD(ldx, %o1 - 0x10, %g3), NG4_retl_o2_plus_o4_plus_40)
+	EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), NG4_retl_o2_plus_o4_plus_40)
 	add		%o0, 0x08, %o0
-	EX_LD(LOAD(ldx, %o1 - 0x08, GLOBAL_SPARE))
-	EX_ST(STORE_INIT(%o5, %o0))
+	EX_LD(LOAD(ldx, %o1 - 0x08, GLOBAL_SPARE), NG4_retl_o2_plus_o4_plus_32)
+	EX_ST(STORE_INIT(%o5, %o0), NG4_retl_o2_plus_o4_plus_32)
 	add		%o0, 0x08, %o0
-	EX_ST(STORE_INIT(%g2, %o0))
+	EX_ST(STORE_INIT(%g2, %o0), NG4_retl_o2_plus_o4_plus_24)
 	add		%o0, 0x08, %o0
-	EX_ST(STORE_INIT(%g3, %o0))
+	EX_ST(STORE_INIT(%g3, %o0), NG4_retl_o2_plus_o4_plus_16)
 	add		%o0, 0x08, %o0
-	EX_ST(STORE_INIT(GLOBAL_SPARE, %o0))
+	EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), NG4_retl_o2_plus_o4_plus_8)
 	add		%o0, 0x08, %o0
 	bne,pt		%icc, 1b
 	 LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
@@ -216,17 +367,17 @@
 	sub		%o2, %o4, %o2
 	alignaddr	%o1, %g0, %g1
 	add		%o1, %o4, %o1
-	EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0))
-1:	EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2))
+	EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0), NG4_retl_o2_plus_o4)
+1:	EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2), NG4_retl_o2_plus_o4)
 	subcc		%o4, 0x40, %o4
-	EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4))
-	EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6))
-	EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8))
-	EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10))
-	EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12))
-	EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14))
+	EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4), NG4_retl_o2_plus_o4_plus_64)
+	EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6), NG4_retl_o2_plus_o4_plus_64)
+	EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8), NG4_retl_o2_plus_o4_plus_64)
+	EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10), NG4_retl_o2_plus_o4_plus_64)
+	EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12), NG4_retl_o2_plus_o4_plus_64)
+	EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14), NG4_retl_o2_plus_o4_plus_64)
 	faligndata	%f0, %f2, %f16
-	EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0))
+	EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0), NG4_retl_o2_plus_o4_plus_64)
 	faligndata	%f2, %f4, %f18
 	add		%g1, 0x40, %g1
 	faligndata	%f4, %f6, %f20
@@ -235,14 +386,14 @@
 	faligndata	%f10, %f12, %f26
 	faligndata	%f12, %f14, %f28
 	faligndata	%f14, %f0, %f30
-	EX_ST_FP(STORE(std, %f16, %o0 + 0x00))
-	EX_ST_FP(STORE(std, %f18, %o0 + 0x08))
-	EX_ST_FP(STORE(std, %f20, %o0 + 0x10))
-	EX_ST_FP(STORE(std, %f22, %o0 + 0x18))
-	EX_ST_FP(STORE(std, %f24, %o0 + 0x20))
-	EX_ST_FP(STORE(std, %f26, %o0 + 0x28))
-	EX_ST_FP(STORE(std, %f28, %o0 + 0x30))
-	EX_ST_FP(STORE(std, %f30, %o0 + 0x38))
+	EX_ST_FP(STORE(std, %f16, %o0 + 0x00), NG4_retl_o2_plus_o4_plus_64)
+	EX_ST_FP(STORE(std, %f18, %o0 + 0x08), NG4_retl_o2_plus_o4_plus_56)
+	EX_ST_FP(STORE(std, %f20, %o0 + 0x10), NG4_retl_o2_plus_o4_plus_48)
+	EX_ST_FP(STORE(std, %f22, %o0 + 0x18), NG4_retl_o2_plus_o4_plus_40)
+	EX_ST_FP(STORE(std, %f24, %o0 + 0x20), NG4_retl_o2_plus_o4_plus_32)
+	EX_ST_FP(STORE(std, %f26, %o0 + 0x28), NG4_retl_o2_plus_o4_plus_24)
+	EX_ST_FP(STORE(std, %f28, %o0 + 0x30), NG4_retl_o2_plus_o4_plus_16)
+	EX_ST_FP(STORE(std, %f30, %o0 + 0x38), NG4_retl_o2_plus_o4_plus_8)
 	add		%o0, 0x40, %o0
 	bne,pt		%icc, 1b
 	 LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
@@ -270,37 +421,38 @@
 	andncc		%o2, 0x20 - 1, %o5
 	be,pn		%icc, 2f
 	 sub		%o2, %o5, %o2
-1:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1))
-	EX_LD(LOAD(ldx, %o1 + 0x08, %g2))
-	EX_LD(LOAD(ldx, %o1 + 0x10, GLOBAL_SPARE))
-	EX_LD(LOAD(ldx, %o1 + 0x18, %o4))
+1:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
+	EX_LD(LOAD(ldx, %o1 + 0x08, %g2), NG4_retl_o2_plus_o5)
+	EX_LD(LOAD(ldx, %o1 + 0x10, GLOBAL_SPARE), NG4_retl_o2_plus_o5)
+	EX_LD(LOAD(ldx, %o1 + 0x18, %o4), NG4_retl_o2_plus_o5)
 	add		%o1, 0x20, %o1
 	subcc		%o5, 0x20, %o5
-	EX_ST(STORE(stx, %g1, %o0 + 0x00))
-	EX_ST(STORE(stx, %g2, %o0 + 0x08))
-	EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10))
-	EX_ST(STORE(stx, %o4, %o0 + 0x18))
+	EX_ST(STORE(stx, %g1, %o0 + 0x00), NG4_retl_o2_plus_o5_plus_32)
+	EX_ST(STORE(stx, %g2, %o0 + 0x08), NG4_retl_o2_plus_o5_plus_24)
+	EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10), NG4_retl_o2_plus_o5_plus_24)
+	EX_ST(STORE(stx, %o4, %o0 + 0x18), NG4_retl_o2_plus_o5_plus_8)
 	bne,pt		%icc, 1b
 	 add		%o0, 0x20, %o0
 2:	andcc		%o2, 0x18, %o5
 	be,pt		%icc, 3f
 	 sub		%o2, %o5, %o2
-1:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1))
+
+1:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
 	add		%o1, 0x08, %o1
 	add		%o0, 0x08, %o0
 	subcc		%o5, 0x08, %o5
 	bne,pt		%icc, 1b
-	 EX_ST(STORE(stx, %g1, %o0 - 0x08))
+	 EX_ST(STORE(stx, %g1, %o0 - 0x08), NG4_retl_o2_plus_o5_plus_8)
 3:	brz,pt		%o2, .Lexit
 	 cmp		%o2, 0x04
 	bl,pn		%icc, .Ltiny
 	 nop
-	EX_LD(LOAD(lduw, %o1 + 0x00, %g1))
+	EX_LD(LOAD(lduw, %o1 + 0x00, %g1), NG4_retl_o2)
 	add		%o1, 0x04, %o1
 	add		%o0, 0x04, %o0
 	subcc		%o2, 0x04, %o2
 	bne,pn		%icc, .Ltiny
-	 EX_ST(STORE(stw, %g1, %o0 - 0x04))
+	 EX_ST(STORE(stw, %g1, %o0 - 0x04), NG4_retl_o2_plus_4)
 	ba,a,pt		%icc, .Lexit
 .Lmedium_unaligned:
 	/* First get dest 8 byte aligned.  */
@@ -309,12 +461,12 @@
 	brz,pt		%g1, 2f
 	 sub		%o2, %g1, %o2
 
-1:	EX_LD(LOAD(ldub, %o1 + 0x00, %g2))
+1:	EX_LD(LOAD(ldub, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
 	add		%o1, 1, %o1
 	subcc		%g1, 1, %g1
 	add		%o0, 1, %o0
 	bne,pt		%icc, 1b
-	 EX_ST(STORE(stb, %g2, %o0 - 0x01))
+	 EX_ST(STORE(stb, %g2, %o0 - 0x01), NG4_retl_o2_plus_g1_plus_1)
 2:
 	and		%o1, 0x7, %g1
 	brz,pn		%g1, .Lmedium_noprefetch
@@ -322,16 +474,16 @@
 	mov		64, %g2
 	sub		%g2, %g1, %g2
 	andn		%o1, 0x7, %o1
-	EX_LD(LOAD(ldx, %o1 + 0x00, %o4))
+	EX_LD(LOAD(ldx, %o1 + 0x00, %o4), NG4_retl_o2)
 	sllx		%o4, %g1, %o4
 	andn		%o2, 0x08 - 1, %o5
 	sub		%o2, %o5, %o2
-1:	EX_LD(LOAD(ldx, %o1 + 0x08, %g3))
+1:	EX_LD(LOAD(ldx, %o1 + 0x08, %g3), NG4_retl_o2_plus_o5)
 	add		%o1, 0x08, %o1
 	subcc		%o5, 0x08, %o5
 	srlx		%g3, %g2, GLOBAL_SPARE
 	or		GLOBAL_SPARE, %o4, GLOBAL_SPARE
-	EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x00))
+	EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x00), NG4_retl_o2_plus_o5_plus_8)
 	add		%o0, 0x08, %o0
 	bne,pt		%icc, 1b
 	 sllx		%g3, %g1, %o4
@@ -342,17 +494,17 @@
 	ba,pt		%icc, .Lsmall_unaligned
 
 .Ltiny:
-	EX_LD(LOAD(ldub, %o1 + 0x00, %g1))
+	EX_LD(LOAD(ldub, %o1 + 0x00, %g1), NG4_retl_o2)
 	subcc		%o2, 1, %o2
 	be,pn		%icc, .Lexit
-	 EX_ST(STORE(stb, %g1, %o0 + 0x00))
-	EX_LD(LOAD(ldub, %o1 + 0x01, %g1))
+	 EX_ST(STORE(stb, %g1, %o0 + 0x00), NG4_retl_o2_plus_1)
+	EX_LD(LOAD(ldub, %o1 + 0x01, %g1), NG4_retl_o2)
 	subcc		%o2, 1, %o2
 	be,pn		%icc, .Lexit
-	 EX_ST(STORE(stb, %g1, %o0 + 0x01))
-	EX_LD(LOAD(ldub, %o1 + 0x02, %g1))
+	 EX_ST(STORE(stb, %g1, %o0 + 0x01), NG4_retl_o2_plus_1)
+	EX_LD(LOAD(ldub, %o1 + 0x02, %g1), NG4_retl_o2)
 	ba,pt		%icc, .Lexit
-	 EX_ST(STORE(stb, %g1, %o0 + 0x02))
+	 EX_ST(STORE(stb, %g1, %o0 + 0x02), NG4_retl_o2)
 
 .Lsmall:
 	andcc		%g2, 0x3, %g0
@@ -360,22 +512,22 @@
 	 andn		%o2, 0x4 - 1, %o5
 	sub		%o2, %o5, %o2
 1:
-	EX_LD(LOAD(lduw, %o1 + 0x00, %g1))
+	EX_LD(LOAD(lduw, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
 	add		%o1, 0x04, %o1
 	subcc		%o5, 0x04, %o5
 	add		%o0, 0x04, %o0
 	bne,pt		%icc, 1b
-	 EX_ST(STORE(stw, %g1, %o0 - 0x04))
+	 EX_ST(STORE(stw, %g1, %o0 - 0x04), NG4_retl_o2_plus_o5_plus_4)
 	brz,pt		%o2, .Lexit
 	 nop
 	ba,a,pt		%icc, .Ltiny
 
 .Lsmall_unaligned:
-1:	EX_LD(LOAD(ldub, %o1 + 0x00, %g1))
+1:	EX_LD(LOAD(ldub, %o1 + 0x00, %g1), NG4_retl_o2)
 	add		%o1, 1, %o1
 	add		%o0, 1, %o0
 	subcc		%o2, 1, %o2
 	bne,pt		%icc, 1b
-	 EX_ST(STORE(stb, %g1, %o0 - 0x01))
+	 EX_ST(STORE(stb, %g1, %o0 - 0x01), NG4_retl_o2_plus_1)
 	ba,a,pt		%icc, .Lexit
 	.size		FUNC_NAME, .-FUNC_NAME
--- linux-4.4.0.orig/arch/sparc/lib/NGcopy_from_user.S
+++ linux-4.4.0/arch/sparc/lib/NGcopy_from_user.S
@@ -3,11 +3,11 @@
  * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_LD(x)		\
+#define EX_LD(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __ret_one_asi;\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/NGcopy_to_user.S
+++ linux-4.4.0/arch/sparc/lib/NGcopy_to_user.S
@@ -3,11 +3,11 @@
  * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_ST(x)		\
+#define EX_ST(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __ret_one_asi;\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/NGmemcpy.S
+++ linux-4.4.0/arch/sparc/lib/NGmemcpy.S
@@ -4,6 +4,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/asi.h>
 #include <asm/thread_info.h>
 #define GLOBAL_SPARE	%g7
@@ -27,15 +28,11 @@
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)	x
+#define EX_LD(x,y)	x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)	x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)	x
+#define EX_ST(x,y)	x
 #endif
 
 #ifndef LOAD
@@ -79,6 +76,92 @@
 	.register	%g3,#scratch
 
 	.text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)	x
+__restore_asi:
+	ret
+	wr	%g0, ASI_AIUS, %asi
+	 restore
+ENTRY(NG_ret_i2_plus_i4_plus_1)
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %i5, %i0
+ENDPROC(NG_ret_i2_plus_i4_plus_1)
+ENTRY(NG_ret_i2_plus_g1)
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1)
+ENTRY(NG_ret_i2_plus_g1_minus_8)
+	sub	%g1, 8, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_8)
+ENTRY(NG_ret_i2_plus_g1_minus_16)
+	sub	%g1, 16, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_16)
+ENTRY(NG_ret_i2_plus_g1_minus_24)
+	sub	%g1, 24, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_24)
+ENTRY(NG_ret_i2_plus_g1_minus_32)
+	sub	%g1, 32, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_32)
+ENTRY(NG_ret_i2_plus_g1_minus_40)
+	sub	%g1, 40, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_40)
+ENTRY(NG_ret_i2_plus_g1_minus_48)
+	sub	%g1, 48, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_48)
+ENTRY(NG_ret_i2_plus_g1_minus_56)
+	sub	%g1, 56, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_56)
+ENTRY(NG_ret_i2_plus_i4)
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %i4, %i0
+ENDPROC(NG_ret_i2_plus_i4)
+ENTRY(NG_ret_i2_plus_i4_minus_8)
+	sub	%i4, 8, %i4
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %i4, %i0
+ENDPROC(NG_ret_i2_plus_i4_minus_8)
+ENTRY(NG_ret_i2_plus_8)
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, 8, %i0
+ENDPROC(NG_ret_i2_plus_8)
+ENTRY(NG_ret_i2_plus_4)
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, 4, %i0
+ENDPROC(NG_ret_i2_plus_4)
+ENTRY(NG_ret_i2_plus_1)
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, 1, %i0
+ENDPROC(NG_ret_i2_plus_1)
+ENTRY(NG_ret_i2_plus_g1_plus_1)
+	add	%g1, 1, %g1
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_plus_1)
+ENTRY(NG_ret_i2)
+	ba,pt	%xcc, __restore_asi
+	 mov	%i2, %i0
+ENDPROC(NG_ret_i2)
+ENTRY(NG_ret_i2_and_7_plus_i4)
+	and	%i2, 7, %i2
+	ba,pt	%xcc, __restore_asi
+	 add	%i2, %i4, %i0
+ENDPROC(NG_ret_i2_and_7_plus_i4)
+#endif
+
 	.align		64
 
 	.globl	FUNC_NAME
@@ -126,8 +209,8 @@
 	sub		%g0, %i4, %i4	! bytes to align dst
 	sub		%i2, %i4, %i2
 1:	subcc		%i4, 1, %i4
-	EX_LD(LOAD(ldub, %i1, %g1))
-	EX_ST(STORE(stb, %g1, %o0))
+	EX_LD(LOAD(ldub, %i1, %g1), NG_ret_i2_plus_i4_plus_1)
+	EX_ST(STORE(stb, %g1, %o0), NG_ret_i2_plus_i4_plus_1)
 	add		%i1, 1, %i1
 	bne,pt		%XCC, 1b
 	add		%o0, 1, %o0
@@ -160,7 +243,7 @@
 	and		%i4, 0x7, GLOBAL_SPARE
 	sll		GLOBAL_SPARE, 3, GLOBAL_SPARE
 	mov		64, %i5
-	EX_LD(LOAD_TWIN(%i1, %g2, %g3))
+	EX_LD(LOAD_TWIN(%i1, %g2, %g3), NG_ret_i2_plus_g1)
 	sub		%i5, GLOBAL_SPARE, %i5
 	mov		16, %o4
 	mov		32, %o5
@@ -178,31 +261,31 @@
 	srlx		WORD3, PRE_SHIFT, TMP; \
 	or		WORD2, TMP, WORD2;
 
-8:	EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3))
+8:	EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3), NG_ret_i2_plus_g1)
 	MIX_THREE_WORDS(%g2, %g3, %o2, %i5, GLOBAL_SPARE, %o1)
 	LOAD(prefetch, %i1 + %i3, #one_read)
 
-	EX_ST(STORE_INIT(%g2, %o0 + 0x00))
-	EX_ST(STORE_INIT(%g3, %o0 + 0x08))
+	EX_ST(STORE_INIT(%g2, %o0 + 0x00), NG_ret_i2_plus_g1)
+	EX_ST(STORE_INIT(%g3, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
 
-	EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3))
+	EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3), NG_ret_i2_plus_g1_minus_16)
 	MIX_THREE_WORDS(%o2, %o3, %g2, %i5, GLOBAL_SPARE, %o1)
 
-	EX_ST(STORE_INIT(%o2, %o0 + 0x10))
-	EX_ST(STORE_INIT(%o3, %o0 + 0x18))
+	EX_ST(STORE_INIT(%o2, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
+	EX_ST(STORE_INIT(%o3, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
 
-	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3))
+	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
 	MIX_THREE_WORDS(%g2, %g3, %o2, %i5, GLOBAL_SPARE, %o1)
 
-	EX_ST(STORE_INIT(%g2, %o0 + 0x20))
-	EX_ST(STORE_INIT(%g3, %o0 + 0x28))
+	EX_ST(STORE_INIT(%g2, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
+	EX_ST(STORE_INIT(%g3, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
 
-	EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3))
+	EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3), NG_ret_i2_plus_g1_minus_48)
 	add		%i1, 64, %i1
 	MIX_THREE_WORDS(%o2, %o3, %g2, %i5, GLOBAL_SPARE, %o1)
 
-	EX_ST(STORE_INIT(%o2, %o0 + 0x30))
-	EX_ST(STORE_INIT(%o3, %o0 + 0x38))
+	EX_ST(STORE_INIT(%o2, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
+	EX_ST(STORE_INIT(%o3, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
 
 	subcc		%g1, 64, %g1
 	bne,pt		%XCC, 8b
@@ -211,31 +294,31 @@
 	ba,pt		%XCC, 60f
 	 add		%i1, %i4, %i1
 
-9:	EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3))
+9:	EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3), NG_ret_i2_plus_g1)
 	MIX_THREE_WORDS(%g3, %o2, %o3, %i5, GLOBAL_SPARE, %o1)
 	LOAD(prefetch, %i1 + %i3, #one_read)
 
-	EX_ST(STORE_INIT(%g3, %o0 + 0x00))
-	EX_ST(STORE_INIT(%o2, %o0 + 0x08))
+	EX_ST(STORE_INIT(%g3, %o0 + 0x00), NG_ret_i2_plus_g1)
+	EX_ST(STORE_INIT(%o2, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
 
-	EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3))
+	EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3), NG_ret_i2_plus_g1_minus_16)
 	MIX_THREE_WORDS(%o3, %g2, %g3, %i5, GLOBAL_SPARE, %o1)
 
-	EX_ST(STORE_INIT(%o3, %o0 + 0x10))
-	EX_ST(STORE_INIT(%g2, %o0 + 0x18))
+	EX_ST(STORE_INIT(%o3, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
+	EX_ST(STORE_INIT(%g2, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
 
-	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3))
+	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
 	MIX_THREE_WORDS(%g3, %o2, %o3, %i5, GLOBAL_SPARE, %o1)
 
-	EX_ST(STORE_INIT(%g3, %o0 + 0x20))
-	EX_ST(STORE_INIT(%o2, %o0 + 0x28))
+	EX_ST(STORE_INIT(%g3, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
+	EX_ST(STORE_INIT(%o2, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
 
-	EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3))
+	EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3), NG_ret_i2_plus_g1_minus_48)
 	add		%i1, 64, %i1
 	MIX_THREE_WORDS(%o3, %g2, %g3, %i5, GLOBAL_SPARE, %o1)
 
-	EX_ST(STORE_INIT(%o3, %o0 + 0x30))
-	EX_ST(STORE_INIT(%g2, %o0 + 0x38))
+	EX_ST(STORE_INIT(%o3, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
+	EX_ST(STORE_INIT(%g2, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
 
 	subcc		%g1, 64, %g1
 	bne,pt		%XCC, 9b
@@ -249,25 +332,25 @@
 	 * one twin load ahead, then add 8 back into source when
 	 * we finish the loop.
 	 */
-	EX_LD(LOAD_TWIN(%i1, %o4, %o5))
+	EX_LD(LOAD_TWIN(%i1, %o4, %o5), NG_ret_i2_plus_g1)
 	mov	16, %o7
 	mov	32, %g2
 	mov	48, %g3
 	mov	64, %o1
-1:	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3))
+1:	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1)
 	LOAD(prefetch, %i1 + %o1, #one_read)
-	EX_ST(STORE_INIT(%o5, %o0 + 0x00))	! initializes cache line
-	EX_ST(STORE_INIT(%o2, %o0 + 0x08))
-	EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5))
-	EX_ST(STORE_INIT(%o3, %o0 + 0x10))
-	EX_ST(STORE_INIT(%o4, %o0 + 0x18))
-	EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3))
-	EX_ST(STORE_INIT(%o5, %o0 + 0x20))
-	EX_ST(STORE_INIT(%o2, %o0 + 0x28))
-	EX_LD(LOAD_TWIN(%i1 + %o1, %o4, %o5))
+	EX_ST(STORE_INIT(%o5, %o0 + 0x00), NG_ret_i2_plus_g1)	! initializes cache line
+	EX_ST(STORE_INIT(%o2, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
+	EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5), NG_ret_i2_plus_g1_minus_16)
+	EX_ST(STORE_INIT(%o3, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
+	EX_ST(STORE_INIT(%o4, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
+	EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
+	EX_ST(STORE_INIT(%o5, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
+	EX_ST(STORE_INIT(%o2, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
+	EX_LD(LOAD_TWIN(%i1 + %o1, %o4, %o5), NG_ret_i2_plus_g1_minus_48)
 	add		%i1, 64, %i1
-	EX_ST(STORE_INIT(%o3, %o0 + 0x30))
-	EX_ST(STORE_INIT(%o4, %o0 + 0x38))
+	EX_ST(STORE_INIT(%o3, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
+	EX_ST(STORE_INIT(%o4, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
 	subcc		%g1, 64, %g1
 	bne,pt		%XCC, 1b
 	 add		%o0, 64, %o0
@@ -282,20 +365,20 @@
 	mov	32, %g2
 	mov	48, %g3
 	mov	64, %o1
-1:	EX_LD(LOAD_TWIN(%i1 + %g0, %o4, %o5))
-	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3))
+1:	EX_LD(LOAD_TWIN(%i1 + %g0, %o4, %o5), NG_ret_i2_plus_g1)
+	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1)
 	LOAD(prefetch, %i1 + %o1, #one_read)
-	EX_ST(STORE_INIT(%o4, %o0 + 0x00))	! initializes cache line
-	EX_ST(STORE_INIT(%o5, %o0 + 0x08))
-	EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5))
-	EX_ST(STORE_INIT(%o2, %o0 + 0x10))
-	EX_ST(STORE_INIT(%o3, %o0 + 0x18))
-	EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3))
+	EX_ST(STORE_INIT(%o4, %o0 + 0x00), NG_ret_i2_plus_g1)	! initializes cache line
+	EX_ST(STORE_INIT(%o5, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
+	EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5), NG_ret_i2_plus_g1_minus_16)
+	EX_ST(STORE_INIT(%o2, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
+	EX_ST(STORE_INIT(%o3, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
+	EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
 	add	%i1, 64, %i1
-	EX_ST(STORE_INIT(%o4, %o0 + 0x20))
-	EX_ST(STORE_INIT(%o5, %o0 + 0x28))
-	EX_ST(STORE_INIT(%o2, %o0 + 0x30))
-	EX_ST(STORE_INIT(%o3, %o0 + 0x38))
+	EX_ST(STORE_INIT(%o4, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
+	EX_ST(STORE_INIT(%o5, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
+	EX_ST(STORE_INIT(%o2, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
+	EX_ST(STORE_INIT(%o3, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
 	subcc	%g1, 64, %g1
 	bne,pt	%XCC, 1b
 	 add	%o0, 64, %o0
@@ -321,28 +404,28 @@
 	andn		%i2, 0xf, %i4
 	and		%i2, 0xf, %i2
 1:	subcc		%i4, 0x10, %i4
-	EX_LD(LOAD(ldx, %i1, %o4))
+	EX_LD(LOAD(ldx, %i1, %o4), NG_ret_i2_plus_i4)
 	add		%i1, 0x08, %i1
-	EX_LD(LOAD(ldx, %i1, %g1))
+	EX_LD(LOAD(ldx, %i1, %g1), NG_ret_i2_plus_i4)
 	sub		%i1, 0x08, %i1
-	EX_ST(STORE(stx, %o4, %i1 + %i3))
+	EX_ST(STORE(stx, %o4, %i1 + %i3), NG_ret_i2_plus_i4)
 	add		%i1, 0x8, %i1
-	EX_ST(STORE(stx, %g1, %i1 + %i3))
+	EX_ST(STORE(stx, %g1, %i1 + %i3), NG_ret_i2_plus_i4_minus_8)
 	bgu,pt		%XCC, 1b
 	 add		%i1, 0x8, %i1
 73:	andcc		%i2, 0x8, %g0
 	be,pt		%XCC, 1f
 	 nop
 	sub		%i2, 0x8, %i2
-	EX_LD(LOAD(ldx, %i1, %o4))
-	EX_ST(STORE(stx, %o4, %i1 + %i3))
+	EX_LD(LOAD(ldx, %i1, %o4), NG_ret_i2_plus_8)
+	EX_ST(STORE(stx, %o4, %i1 + %i3), NG_ret_i2_plus_8)
 	add		%i1, 0x8, %i1
 1:	andcc		%i2, 0x4, %g0
 	be,pt		%XCC, 1f
 	 nop
 	sub		%i2, 0x4, %i2
-	EX_LD(LOAD(lduw, %i1, %i5))
-	EX_ST(STORE(stw, %i5, %i1 + %i3))
+	EX_LD(LOAD(lduw, %i1, %i5), NG_ret_i2_plus_4)
+	EX_ST(STORE(stw, %i5, %i1 + %i3), NG_ret_i2_plus_4)
 	add		%i1, 0x4, %i1
 1:	cmp		%i2, 0
 	be,pt		%XCC, 85f
@@ -358,8 +441,8 @@
 	sub		%i2, %g1, %i2
 
 1:	subcc		%g1, 1, %g1
-	EX_LD(LOAD(ldub, %i1, %i5))
-	EX_ST(STORE(stb, %i5, %i1 + %i3))
+	EX_LD(LOAD(ldub, %i1, %i5), NG_ret_i2_plus_g1_plus_1)
+	EX_ST(STORE(stb, %i5, %i1 + %i3), NG_ret_i2_plus_g1_plus_1)
 	bgu,pt		%icc, 1b
 	 add		%i1, 1, %i1
 
@@ -375,16 +458,16 @@
 
 8:	mov		64, %i3
 	andn		%i1, 0x7, %i1
-	EX_LD(LOAD(ldx, %i1, %g2))
+	EX_LD(LOAD(ldx, %i1, %g2), NG_ret_i2)
 	sub		%i3, %g1, %i3
 	andn		%i2, 0x7, %i4
 	sllx		%g2, %g1, %g2
 1:	add		%i1, 0x8, %i1
-	EX_LD(LOAD(ldx, %i1, %g3))
+	EX_LD(LOAD(ldx, %i1, %g3), NG_ret_i2_and_7_plus_i4)
 	subcc		%i4, 0x8, %i4
 	srlx		%g3, %i3, %i5
 	or		%i5, %g2, %i5
-	EX_ST(STORE(stx, %i5, %o0))
+	EX_ST(STORE(stx, %i5, %o0), NG_ret_i2_and_7_plus_i4)
 	add		%o0, 0x8, %o0
 	bgu,pt		%icc, 1b
 	 sllx		%g3, %g1, %g2
@@ -404,8 +487,8 @@
 
 1:
 	subcc		%i2, 4, %i2
-	EX_LD(LOAD(lduw, %i1, %g1))
-	EX_ST(STORE(stw, %g1, %i1 + %i3))
+	EX_LD(LOAD(lduw, %i1, %g1), NG_ret_i2_plus_4)
+	EX_ST(STORE(stw, %g1, %i1 + %i3), NG_ret_i2_plus_4)
 	bgu,pt		%XCC, 1b
 	 add		%i1, 4, %i1
 
@@ -415,8 +498,8 @@
 	.align		32
 90:
 	subcc		%i2, 1, %i2
-	EX_LD(LOAD(ldub, %i1, %g1))
-	EX_ST(STORE(stb, %g1, %i1 + %i3))
+	EX_LD(LOAD(ldub, %i1, %g1), NG_ret_i2_plus_1)
+	EX_ST(STORE(stb, %g1, %i1 + %i3), NG_ret_i2_plus_1)
 	bgu,pt		%XCC, 90b
 	 add		%i1, 1, %i1
 	ret
--- linux-4.4.0.orig/arch/sparc/lib/U1copy_from_user.S
+++ linux-4.4.0/arch/sparc/lib/U1copy_from_user.S
@@ -3,19 +3,19 @@
  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#define EX_LD(x)		\
+#define EX_LD(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one;	\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
-#define EX_LD_FP(x)		\
+#define EX_LD_FP(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_fp;\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/U1copy_to_user.S
+++ linux-4.4.0/arch/sparc/lib/U1copy_to_user.S
@@ -3,19 +3,19 @@
  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#define EX_ST(x)		\
+#define EX_ST(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one;	\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
-#define EX_ST_FP(x)		\
+#define EX_ST_FP(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_fp;\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/U1memcpy.S
+++ linux-4.4.0/arch/sparc/lib/U1memcpy.S
@@ -5,6 +5,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #define GLOBAL_SPARE	g7
@@ -23,21 +24,17 @@
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)	x
+#define EX_LD(x,y)	x
 #endif
 #ifndef EX_LD_FP
-#define EX_LD_FP(x)	x
+#define EX_LD_FP(x,y)	x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)	x
+#define EX_ST(x,y)	x
 #endif
 #ifndef EX_ST_FP
-#define EX_ST_FP(x)	x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)	x
+#define EX_ST_FP(x,y)	x
 #endif
 
 #ifndef LOAD
@@ -78,53 +75,169 @@
 	faligndata		%f7, %f8, %f60;			\
 	faligndata		%f8, %f9, %f62;
 
-#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt)	\
-	EX_LD_FP(LOAD_BLK(%src, %fdest));				\
-	EX_ST_FP(STORE_BLK(%fsrc, %dest));				\
-	add			%src, 0x40, %src;		\
-	subcc			%len, 0x40, %len;		\
-	be,pn			%xcc, jmptgt;			\
-	 add			%dest, 0x40, %dest;		\
-
-#define LOOP_CHUNK1(src, dest, len, branch_dest)		\
-	MAIN_LOOP_CHUNK(src, dest, f0,  f48, len, branch_dest)
-#define LOOP_CHUNK2(src, dest, len, branch_dest)		\
-	MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest)
-#define LOOP_CHUNK3(src, dest, len, branch_dest)		\
-	MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
+#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, jmptgt)			\
+	EX_LD_FP(LOAD_BLK(%src, %fdest), U1_gs_80_fp);			\
+	EX_ST_FP(STORE_BLK(%fsrc, %dest), U1_gs_80_fp);			\
+	add			%src, 0x40, %src;			\
+	subcc			%GLOBAL_SPARE, 0x40, %GLOBAL_SPARE;	\
+	be,pn			%xcc, jmptgt;				\
+	 add			%dest, 0x40, %dest;			\
+
+#define LOOP_CHUNK1(src, dest, branch_dest)		\
+	MAIN_LOOP_CHUNK(src, dest, f0,  f48, branch_dest)
+#define LOOP_CHUNK2(src, dest, branch_dest)		\
+	MAIN_LOOP_CHUNK(src, dest, f16, f48, branch_dest)
+#define LOOP_CHUNK3(src, dest, branch_dest)		\
+	MAIN_LOOP_CHUNK(src, dest, f32, f48, branch_dest)
 
 #define DO_SYNC			membar	#Sync;
 #define STORE_SYNC(dest, fsrc)				\
-	EX_ST_FP(STORE_BLK(%fsrc, %dest));			\
+	EX_ST_FP(STORE_BLK(%fsrc, %dest), U1_gs_80_fp);	\
 	add			%dest, 0x40, %dest;	\
 	DO_SYNC
 
 #define STORE_JUMP(dest, fsrc, target)			\
-	EX_ST_FP(STORE_BLK(%fsrc, %dest));			\
+	EX_ST_FP(STORE_BLK(%fsrc, %dest), U1_gs_40_fp);	\
 	add			%dest, 0x40, %dest;	\
 	ba,pt			%xcc, target;		\
 	 nop;
 
-#define FINISH_VISCHUNK(dest, f0, f1, left)	\
-	subcc			%left, 8, %left;\
-	bl,pn			%xcc, 95f;	\
-	 faligndata		%f0, %f1, %f48;	\
-	EX_ST_FP(STORE(std, %f48, %dest));		\
+#define FINISH_VISCHUNK(dest, f0, f1)			\
+	subcc			%g3, 8, %g3;		\
+	bl,pn			%xcc, 95f;		\
+	 faligndata		%f0, %f1, %f48;		\
+	EX_ST_FP(STORE(std, %f48, %dest), U1_g3_8_fp);	\
 	add			%dest, 8, %dest;
 
-#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left)	\
-	subcc			%left, 8, %left;	\
-	bl,pn			%xcc, 95f;		\
+#define UNEVEN_VISCHUNK_LAST(dest, f0, f1)	\
+	subcc			%g3, 8, %g3;	\
+	bl,pn			%xcc, 95f;	\
 	 fsrc2			%f0, %f1;
 
-#define UNEVEN_VISCHUNK(dest, f0, f1, left)		\
-	UNEVEN_VISCHUNK_LAST(dest, f0, f1, left)	\
+#define UNEVEN_VISCHUNK(dest, f0, f1)		\
+	UNEVEN_VISCHUNK_LAST(dest, f0, f1)	\
 	ba,a,pt			%xcc, 93f;
 
 	.register	%g2,#scratch
 	.register	%g3,#scratch
 
 	.text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)	x
+ENTRY(U1_g1_1_fp)
+	VISExitHalf
+	add		%g1, 1, %g1
+	add		%g1, %g2, %g1
+	retl
+	 add		%g1, %o2, %o0
+ENDPROC(U1_g1_1_fp)
+ENTRY(U1_g2_0_fp)
+	VISExitHalf
+	retl
+	 add		%g2, %o2, %o0
+ENDPROC(U1_g2_0_fp)
+ENTRY(U1_g2_8_fp)
+	VISExitHalf
+	add		%g2, 8, %g2
+	retl
+	 add		%g2, %o2, %o0
+ENDPROC(U1_g2_8_fp)
+ENTRY(U1_gs_0_fp)
+	VISExitHalf
+	add		%GLOBAL_SPARE, %g3, %o0
+	retl
+	 add		%o0, %o2, %o0
+ENDPROC(U1_gs_0_fp)
+ENTRY(U1_gs_80_fp)
+	VISExitHalf
+	add		%GLOBAL_SPARE, 0x80, %GLOBAL_SPARE
+	add		%GLOBAL_SPARE, %g3, %o0
+	retl
+	 add		%o0, %o2, %o0
+ENDPROC(U1_gs_80_fp)
+ENTRY(U1_gs_40_fp)
+	VISExitHalf
+	add		%GLOBAL_SPARE, 0x40, %GLOBAL_SPARE
+	add		%GLOBAL_SPARE, %g3, %o0
+	retl
+	 add		%o0, %o2, %o0
+ENDPROC(U1_gs_40_fp)
+ENTRY(U1_g3_0_fp)
+	VISExitHalf
+	retl
+	 add		%g3, %o2, %o0
+ENDPROC(U1_g3_0_fp)
+ENTRY(U1_g3_8_fp)
+	VISExitHalf
+	add		%g3, 8, %g3
+	retl
+	 add		%g3, %o2, %o0
+ENDPROC(U1_g3_8_fp)
+ENTRY(U1_o2_0_fp)
+	VISExitHalf
+	retl
+	 mov		%o2, %o0
+ENDPROC(U1_o2_0_fp)
+ENTRY(U1_o2_1_fp)
+	VISExitHalf
+	retl
+	 add		%o2, 1, %o0
+ENDPROC(U1_o2_1_fp)
+ENTRY(U1_gs_0)
+	VISExitHalf
+	retl
+	 add		%GLOBAL_SPARE, %o2, %o0
+ENDPROC(U1_gs_0)
+ENTRY(U1_gs_8)
+	VISExitHalf
+	add		%GLOBAL_SPARE, %o2, %GLOBAL_SPARE
+	retl
+	 add		%GLOBAL_SPARE, 0x8, %o0
+ENDPROC(U1_gs_8)
+ENTRY(U1_gs_10)
+	VISExitHalf
+	add		%GLOBAL_SPARE, %o2, %GLOBAL_SPARE
+	retl
+	 add		%GLOBAL_SPARE, 0x10, %o0
+ENDPROC(U1_gs_10)
+ENTRY(U1_o2_0)
+	retl
+	 mov		%o2, %o0
+ENDPROC(U1_o2_0)
+ENTRY(U1_o2_8)
+	retl
+	 add		%o2, 8, %o0
+ENDPROC(U1_o2_8)
+ENTRY(U1_o2_4)
+	retl
+	 add		%o2, 4, %o0
+ENDPROC(U1_o2_4)
+ENTRY(U1_o2_1)
+	retl
+	 add		%o2, 1, %o0
+ENDPROC(U1_o2_1)
+ENTRY(U1_g1_0)
+	retl
+	 add		%g1, %o2, %o0
+ENDPROC(U1_g1_0)
+ENTRY(U1_g1_1)
+	add		%g1, 1, %g1
+	retl
+	 add		%g1, %o2, %o0
+ENDPROC(U1_g1_1)
+ENTRY(U1_gs_0_o2_adj)
+	and		%o2, 7, %o2
+	retl
+	 add		%GLOBAL_SPARE, %o2, %o0
+ENDPROC(U1_gs_0_o2_adj)
+ENTRY(U1_gs_8_o2_adj)
+	and		%o2, 7, %o2
+	add		%GLOBAL_SPARE, 8, %GLOBAL_SPARE
+	retl
+	 add		%GLOBAL_SPARE, %o2, %o0
+ENDPROC(U1_gs_8_o2_adj)
+#endif
+
 	.align		64
 
 	.globl		FUNC_NAME
@@ -166,8 +279,8 @@
 	 and		%g2, 0x38, %g2
 
 1:	subcc		%g1, 0x1, %g1
-	EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
-	EX_ST_FP(STORE(stb, %o3, %o1 + %GLOBAL_SPARE))
+	EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3), U1_g1_1_fp)
+	EX_ST_FP(STORE(stb, %o3, %o1 + %GLOBAL_SPARE), U1_g1_1_fp)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 0x1, %o1
 
@@ -178,20 +291,20 @@
 	be,pt		%icc, 3f
 	 alignaddr	%o1, %g0, %o1
 
-	EX_LD_FP(LOAD(ldd, %o1, %f4))
-1:	EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
+	EX_LD_FP(LOAD(ldd, %o1, %f4), U1_g2_0_fp)
+1:	EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6), U1_g2_0_fp)
 	add		%o1, 0x8, %o1
 	subcc		%g2, 0x8, %g2
 	faligndata	%f4, %f6, %f0
-	EX_ST_FP(STORE(std, %f0, %o0))
+	EX_ST_FP(STORE(std, %f0, %o0), U1_g2_8_fp)
 	be,pn		%icc, 3f
 	 add		%o0, 0x8, %o0
 
-	EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4), U1_g2_0_fp)
 	add		%o1, 0x8, %o1
 	subcc		%g2, 0x8, %g2
 	faligndata	%f6, %f4, %f0
-	EX_ST_FP(STORE(std, %f0, %o0))
+	EX_ST_FP(STORE(std, %f0, %o0), U1_g2_8_fp)
 	bne,pt		%icc, 1b
 	 add		%o0, 0x8, %o0
 
@@ -214,13 +327,13 @@
 	add		%g1, %GLOBAL_SPARE, %g1
 	subcc		%o2, %g3, %o2
 
-	EX_LD_FP(LOAD_BLK(%o1, %f0))
+	EX_LD_FP(LOAD_BLK(%o1, %f0), U1_gs_0_fp)
 	add		%o1, 0x40, %o1
 	add		%g1, %g3, %g1
-	EX_LD_FP(LOAD_BLK(%o1, %f16))
+	EX_LD_FP(LOAD_BLK(%o1, %f16), U1_gs_0_fp)
 	add		%o1, 0x40, %o1
 	sub		%GLOBAL_SPARE, 0x80, %GLOBAL_SPARE
-	EX_LD_FP(LOAD_BLK(%o1, %f32))
+	EX_LD_FP(LOAD_BLK(%o1, %f32), U1_gs_80_fp)
 	add		%o1, 0x40, %o1
 
 	/* There are 8 instances of the unrolled loop,
@@ -240,11 +353,11 @@
 
 	.align		64
 1:	FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
-	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+	LOOP_CHUNK1(o1, o0, 1f)
 	FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+	LOOP_CHUNK2(o1, o0, 2f)
 	FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
-	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+	LOOP_CHUNK3(o1, o0, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f0, %f2, %f48
 1:	FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
@@ -261,11 +374,11 @@
 	STORE_JUMP(o0, f48, 56f)
 
 1:	FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
-	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+	LOOP_CHUNK1(o1, o0, 1f)
 	FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
-	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+	LOOP_CHUNK2(o1, o0, 2f)
 	FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
-	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+	LOOP_CHUNK3(o1, o0, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f2, %f4, %f48
 1:	FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
@@ -282,11 +395,11 @@
 	STORE_JUMP(o0, f48, 57f)
 
 1:	FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
-	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+	LOOP_CHUNK1(o1, o0, 1f)
 	FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
-	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+	LOOP_CHUNK2(o1, o0, 2f)
 	FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
-	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+	LOOP_CHUNK3(o1, o0, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f4, %f6, %f48
 1:	FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
@@ -303,11 +416,11 @@
 	STORE_JUMP(o0, f48, 58f)
 
 1:	FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
-	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+	LOOP_CHUNK1(o1, o0, 1f)
 	FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
-	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+	LOOP_CHUNK2(o1, o0, 2f)
 	FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) 
-	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+	LOOP_CHUNK3(o1, o0, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f6, %f8, %f48
 1:	FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
@@ -324,11 +437,11 @@
 	STORE_JUMP(o0, f48, 59f)
 
 1:	FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
-	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+	LOOP_CHUNK1(o1, o0, 1f)
 	FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
-	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+	LOOP_CHUNK2(o1, o0, 2f)
 	FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
-	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+	LOOP_CHUNK3(o1, o0, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f8, %f10, %f48
 1:	FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
@@ -345,11 +458,11 @@
 	STORE_JUMP(o0, f48, 60f)
 
 1:	FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
-	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+	LOOP_CHUNK1(o1, o0, 1f)
 	FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
-	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+	LOOP_CHUNK2(o1, o0, 2f)
 	FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
-	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+	LOOP_CHUNK3(o1, o0, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f10, %f12, %f48
 1:	FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
@@ -366,11 +479,11 @@
 	STORE_JUMP(o0, f48, 61f)
 
 1:	FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
-	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+	LOOP_CHUNK1(o1, o0, 1f)
 	FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
-	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+	LOOP_CHUNK2(o1, o0, 2f)
 	FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
-	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+	LOOP_CHUNK3(o1, o0, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f12, %f14, %f48
 1:	FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
@@ -387,11 +500,11 @@
 	STORE_JUMP(o0, f48, 62f)
 
 1:	FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
-	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+	LOOP_CHUNK1(o1, o0, 1f)
 	FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
-	LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+	LOOP_CHUNK2(o1, o0, 2f)
 	FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
-	LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+	LOOP_CHUNK3(o1, o0, 3f)
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f14, %f16, %f48
 1:	FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
@@ -407,53 +520,53 @@
 	FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
 	STORE_JUMP(o0, f48, 63f)
 
-40:	FINISH_VISCHUNK(o0, f0,  f2,  g3)
-41:	FINISH_VISCHUNK(o0, f2,  f4,  g3)
-42:	FINISH_VISCHUNK(o0, f4,  f6,  g3)
-43:	FINISH_VISCHUNK(o0, f6,  f8,  g3)
-44:	FINISH_VISCHUNK(o0, f8,  f10, g3)
-45:	FINISH_VISCHUNK(o0, f10, f12, g3)
-46:	FINISH_VISCHUNK(o0, f12, f14, g3)
-47:	UNEVEN_VISCHUNK(o0, f14, f0,  g3)
-48:	FINISH_VISCHUNK(o0, f16, f18, g3)
-49:	FINISH_VISCHUNK(o0, f18, f20, g3)
-50:	FINISH_VISCHUNK(o0, f20, f22, g3)
-51:	FINISH_VISCHUNK(o0, f22, f24, g3)
-52:	FINISH_VISCHUNK(o0, f24, f26, g3)
-53:	FINISH_VISCHUNK(o0, f26, f28, g3)
-54:	FINISH_VISCHUNK(o0, f28, f30, g3)
-55:	UNEVEN_VISCHUNK(o0, f30, f0,  g3)
-56:	FINISH_VISCHUNK(o0, f32, f34, g3)
-57:	FINISH_VISCHUNK(o0, f34, f36, g3)
-58:	FINISH_VISCHUNK(o0, f36, f38, g3)
-59:	FINISH_VISCHUNK(o0, f38, f40, g3)
-60:	FINISH_VISCHUNK(o0, f40, f42, g3)
-61:	FINISH_VISCHUNK(o0, f42, f44, g3)
-62:	FINISH_VISCHUNK(o0, f44, f46, g3)
-63:	UNEVEN_VISCHUNK_LAST(o0, f46, f0,  g3)
+40:	FINISH_VISCHUNK(o0, f0,  f2)
+41:	FINISH_VISCHUNK(o0, f2,  f4)
+42:	FINISH_VISCHUNK(o0, f4,  f6)
+43:	FINISH_VISCHUNK(o0, f6,  f8)
+44:	FINISH_VISCHUNK(o0, f8,  f10)
+45:	FINISH_VISCHUNK(o0, f10, f12)
+46:	FINISH_VISCHUNK(o0, f12, f14)
+47:	UNEVEN_VISCHUNK(o0, f14, f0)
+48:	FINISH_VISCHUNK(o0, f16, f18)
+49:	FINISH_VISCHUNK(o0, f18, f20)
+50:	FINISH_VISCHUNK(o0, f20, f22)
+51:	FINISH_VISCHUNK(o0, f22, f24)
+52:	FINISH_VISCHUNK(o0, f24, f26)
+53:	FINISH_VISCHUNK(o0, f26, f28)
+54:	FINISH_VISCHUNK(o0, f28, f30)
+55:	UNEVEN_VISCHUNK(o0, f30, f0)
+56:	FINISH_VISCHUNK(o0, f32, f34)
+57:	FINISH_VISCHUNK(o0, f34, f36)
+58:	FINISH_VISCHUNK(o0, f36, f38)
+59:	FINISH_VISCHUNK(o0, f38, f40)
+60:	FINISH_VISCHUNK(o0, f40, f42)
+61:	FINISH_VISCHUNK(o0, f42, f44)
+62:	FINISH_VISCHUNK(o0, f44, f46)
+63:	UNEVEN_VISCHUNK_LAST(o0, f46, f0)
 
-93:	EX_LD_FP(LOAD(ldd, %o1, %f2))
+93:	EX_LD_FP(LOAD(ldd, %o1, %f2), U1_g3_0_fp)
 	add		%o1, 8, %o1
 	subcc		%g3, 8, %g3
 	faligndata	%f0, %f2, %f8
-	EX_ST_FP(STORE(std, %f8, %o0))
+	EX_ST_FP(STORE(std, %f8, %o0), U1_g3_8_fp)
 	bl,pn		%xcc, 95f
 	 add		%o0, 8, %o0
-	EX_LD_FP(LOAD(ldd, %o1, %f0))
+	EX_LD_FP(LOAD(ldd, %o1, %f0), U1_g3_0_fp)
 	add		%o1, 8, %o1
 	subcc		%g3, 8, %g3
 	faligndata	%f2, %f0, %f8
-	EX_ST_FP(STORE(std, %f8, %o0))
+	EX_ST_FP(STORE(std, %f8, %o0), U1_g3_8_fp)
 	bge,pt		%xcc, 93b
 	 add		%o0, 8, %o0
 
 95:	brz,pt		%o2, 2f
 	 mov		%g1, %o1
 
-1:	EX_LD_FP(LOAD(ldub, %o1, %o3))
+1:	EX_LD_FP(LOAD(ldub, %o1, %o3), U1_o2_0_fp)
 	add		%o1, 1, %o1
 	subcc		%o2, 1, %o2
-	EX_ST_FP(STORE(stb, %o3, %o0))
+	EX_ST_FP(STORE(stb, %o3, %o0), U1_o2_1_fp)
 	bne,pt		%xcc, 1b
 	 add		%o0, 1, %o0
 
@@ -469,27 +582,27 @@
 
 72:	andn		%o2, 0xf, %GLOBAL_SPARE
 	and		%o2, 0xf, %o2
-1:	EX_LD(LOAD(ldx, %o1 + 0x00, %o5))
-	EX_LD(LOAD(ldx, %o1 + 0x08, %g1))
+1:	EX_LD(LOAD(ldx, %o1 + 0x00, %o5), U1_gs_0)
+	EX_LD(LOAD(ldx, %o1 + 0x08, %g1), U1_gs_0)
 	subcc		%GLOBAL_SPARE, 0x10, %GLOBAL_SPARE
-	EX_ST(STORE(stx, %o5, %o1 + %o3))
+	EX_ST(STORE(stx, %o5, %o1 + %o3), U1_gs_10)
 	add		%o1, 0x8, %o1
-	EX_ST(STORE(stx, %g1, %o1 + %o3))
+	EX_ST(STORE(stx, %g1, %o1 + %o3), U1_gs_8)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 0x8, %o1
 73:	andcc		%o2, 0x8, %g0
 	be,pt		%XCC, 1f
 	 nop
-	EX_LD(LOAD(ldx, %o1, %o5))
+	EX_LD(LOAD(ldx, %o1, %o5), U1_o2_0)
 	sub		%o2, 0x8, %o2
-	EX_ST(STORE(stx, %o5, %o1 + %o3))
+	EX_ST(STORE(stx, %o5, %o1 + %o3), U1_o2_8)
 	add		%o1, 0x8, %o1
 1:	andcc		%o2, 0x4, %g0
 	be,pt		%XCC, 1f
 	 nop
-	EX_LD(LOAD(lduw, %o1, %o5))
+	EX_LD(LOAD(lduw, %o1, %o5), U1_o2_0)
 	sub		%o2, 0x4, %o2
-	EX_ST(STORE(stw, %o5, %o1 + %o3))
+	EX_ST(STORE(stw, %o5, %o1 + %o3), U1_o2_4)
 	add		%o1, 0x4, %o1
 1:	cmp		%o2, 0
 	be,pt		%XCC, 85f
@@ -503,9 +616,9 @@
 	 sub		%g0, %g1, %g1
 	sub		%o2, %g1, %o2
 
-1:	EX_LD(LOAD(ldub, %o1, %o5))
+1:	EX_LD(LOAD(ldub, %o1, %o5), U1_g1_0)
 	subcc		%g1, 1, %g1
-	EX_ST(STORE(stb, %o5, %o1 + %o3))
+	EX_ST(STORE(stb, %o5, %o1 + %o3), U1_g1_1)
 	bgu,pt		%icc, 1b
 	 add		%o1, 1, %o1
 
@@ -521,16 +634,16 @@
 
 8:	mov		64, %o3
 	andn		%o1, 0x7, %o1
-	EX_LD(LOAD(ldx, %o1, %g2))
+	EX_LD(LOAD(ldx, %o1, %g2), U1_o2_0)
 	sub		%o3, %g1, %o3
 	andn		%o2, 0x7, %GLOBAL_SPARE
 	sllx		%g2, %g1, %g2
-1:	EX_LD(LOAD(ldx, %o1 + 0x8, %g3))
+1:	EX_LD(LOAD(ldx, %o1 + 0x8, %g3), U1_gs_0_o2_adj)
 	subcc		%GLOBAL_SPARE, 0x8, %GLOBAL_SPARE
 	add		%o1, 0x8, %o1
 	srlx		%g3, %o3, %o5
 	or		%o5, %g2, %o5
-	EX_ST(STORE(stx, %o5, %o0))
+	EX_ST(STORE(stx, %o5, %o0), U1_gs_8_o2_adj)
 	add		%o0, 0x8, %o0
 	bgu,pt		%icc, 1b
 	 sllx		%g3, %g1, %g2
@@ -548,9 +661,9 @@
 	bne,pn		%XCC, 90f
 	 sub		%o0, %o1, %o3
 
-1:	EX_LD(LOAD(lduw, %o1, %g1))
+1:	EX_LD(LOAD(lduw, %o1, %g1), U1_o2_0)
 	subcc		%o2, 4, %o2
-	EX_ST(STORE(stw, %g1, %o1 + %o3))
+	EX_ST(STORE(stw, %g1, %o1 + %o3), U1_o2_4)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 4, %o1
 
@@ -558,9 +671,9 @@
 	 mov		EX_RETVAL(%o4), %o0
 
 	.align		32
-90:	EX_LD(LOAD(ldub, %o1, %g1))
+90:	EX_LD(LOAD(ldub, %o1, %g1), U1_o2_0)
 	subcc		%o2, 1, %o2
-	EX_ST(STORE(stb, %g1, %o1 + %o3))
+	EX_ST(STORE(stb, %g1, %o1 + %o3), U1_o2_1)
 	bgu,pt		%XCC, 90b
 	 add		%o1, 1, %o1
 	retl
--- linux-4.4.0.orig/arch/sparc/lib/U3copy_from_user.S
+++ linux-4.4.0/arch/sparc/lib/U3copy_from_user.S
@@ -3,19 +3,19 @@
  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#define EX_LD(x)		\
+#define EX_LD(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one;	\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
-#define EX_LD_FP(x)		\
+#define EX_LD_FP(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_fp;\
+	.word 98b, y##_fp;	\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/U3copy_to_user.S
+++ linux-4.4.0/arch/sparc/lib/U3copy_to_user.S
@@ -3,19 +3,19 @@
  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#define EX_ST(x)		\
+#define EX_ST(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one;	\
+	.word 98b, y;		\
 	.text;			\
 	.align 4;
 
-#define EX_ST_FP(x)		\
+#define EX_ST_FP(x,y)		\
 98:	x;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one_fp;\
+	.word 98b, y##_fp;	\
 	.text;			\
 	.align 4;
 
--- linux-4.4.0.orig/arch/sparc/lib/U3memcpy.S
+++ linux-4.4.0/arch/sparc/lib/U3memcpy.S
@@ -4,6 +4,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #define GLOBAL_SPARE	%g7
@@ -22,21 +23,17 @@
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)	x
+#define EX_LD(x,y)	x
 #endif
 #ifndef EX_LD_FP
-#define EX_LD_FP(x)	x
+#define EX_LD_FP(x,y)	x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)	x
+#define EX_ST(x,y)	x
 #endif
 #ifndef EX_ST_FP
-#define EX_ST_FP(x)	x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)	x
+#define EX_ST_FP(x,y)	x
 #endif
 
 #ifndef LOAD
@@ -77,6 +74,87 @@
 	 */
 
 	.text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)	x
+__restore_fp:
+	VISExitHalf
+	retl
+	 nop
+ENTRY(U3_retl_o2_plus_g2_plus_g1_plus_1_fp)
+	add	%g1, 1, %g1
+	add	%g2, %g1, %g2
+	ba,pt	%xcc, __restore_fp
+	 add	%o2, %g2, %o0
+ENDPROC(U3_retl_o2_plus_g2_plus_g1_plus_1_fp)
+ENTRY(U3_retl_o2_plus_g2_fp)
+	ba,pt	%xcc, __restore_fp
+	 add	%o2, %g2, %o0
+ENDPROC(U3_retl_o2_plus_g2_fp)
+ENTRY(U3_retl_o2_plus_g2_plus_8_fp)
+	add	%g2, 8, %g2
+	ba,pt	%xcc, __restore_fp
+	 add	%o2, %g2, %o0
+ENDPROC(U3_retl_o2_plus_g2_plus_8_fp)
+ENTRY(U3_retl_o2)
+	retl
+	 mov	%o2, %o0
+ENDPROC(U3_retl_o2)
+ENTRY(U3_retl_o2_plus_1)
+	retl
+	 add	%o2, 1, %o0
+ENDPROC(U3_retl_o2_plus_1)
+ENTRY(U3_retl_o2_plus_4)
+	retl
+	 add	%o2, 4, %o0
+ENDPROC(U3_retl_o2_plus_4)
+ENTRY(U3_retl_o2_plus_8)
+	retl
+	 add	%o2, 8, %o0
+ENDPROC(U3_retl_o2_plus_8)
+ENTRY(U3_retl_o2_plus_g1_plus_1)
+	add	%g1, 1, %g1
+	retl
+	 add	%o2, %g1, %o0
+ENDPROC(U3_retl_o2_plus_g1_plus_1)
+ENTRY(U3_retl_o2_fp)
+	ba,pt	%xcc, __restore_fp
+	 mov	%o2, %o0
+ENDPROC(U3_retl_o2_fp)
+ENTRY(U3_retl_o2_plus_o3_sll_6_plus_0x80_fp)
+	sll	%o3, 6, %o3
+	add	%o3, 0x80, %o3
+	ba,pt	%xcc, __restore_fp
+	 add	%o2, %o3, %o0
+ENDPROC(U3_retl_o2_plus_o3_sll_6_plus_0x80_fp)
+ENTRY(U3_retl_o2_plus_o3_sll_6_plus_0x40_fp)
+	sll	%o3, 6, %o3
+	add	%o3, 0x40, %o3
+	ba,pt	%xcc, __restore_fp
+	 add	%o2, %o3, %o0
+ENDPROC(U3_retl_o2_plus_o3_sll_6_plus_0x40_fp)
+ENTRY(U3_retl_o2_plus_GS_plus_0x10)
+	add	GLOBAL_SPARE, 0x10, GLOBAL_SPARE
+	retl
+	 add	%o2, GLOBAL_SPARE, %o0
+ENDPROC(U3_retl_o2_plus_GS_plus_0x10)
+ENTRY(U3_retl_o2_plus_GS_plus_0x08)
+	add	GLOBAL_SPARE, 0x08, GLOBAL_SPARE
+	retl
+	 add	%o2, GLOBAL_SPARE, %o0
+ENDPROC(U3_retl_o2_plus_GS_plus_0x08)
+ENTRY(U3_retl_o2_and_7_plus_GS)
+	and	%o2, 7, %o2
+	retl
+	 add	%o2, GLOBAL_SPARE, %o0
+ENDPROC(U3_retl_o2_and_7_plus_GS)
+ENTRY(U3_retl_o2_and_7_plus_GS_plus_8)
+	add	GLOBAL_SPARE, 8, GLOBAL_SPARE
+	and	%o2, 7, %o2
+	retl
+	 add	%o2, GLOBAL_SPARE, %o0
+ENDPROC(U3_retl_o2_and_7_plus_GS_plus_8)
+#endif
+
 	.align		64
 
 	/* The cheetah's flexible spine, oversized liver, enlarged heart,
@@ -126,8 +204,8 @@
 	 and		%g2, 0x38, %g2
 
 1:	subcc		%g1, 0x1, %g1
-	EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
-	EX_ST_FP(STORE(stb, %o3, %o1 + GLOBAL_SPARE))
+	EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3), U3_retl_o2_plus_g2_plus_g1_plus_1)
+	EX_ST_FP(STORE(stb, %o3, %o1 + GLOBAL_SPARE), U3_retl_o2_plus_g2_plus_g1_plus_1)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 0x1, %o1
 
@@ -138,20 +216,20 @@
 	be,pt		%icc, 3f
 	 alignaddr	%o1, %g0, %o1
 
-	EX_LD_FP(LOAD(ldd, %o1, %f4))
-1:	EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
+	EX_LD_FP(LOAD(ldd, %o1, %f4), U3_retl_o2_plus_g2)
+1:	EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6), U3_retl_o2_plus_g2)
 	add		%o1, 0x8, %o1
 	subcc		%g2, 0x8, %g2
 	faligndata	%f4, %f6, %f0
-	EX_ST_FP(STORE(std, %f0, %o0))
+	EX_ST_FP(STORE(std, %f0, %o0), U3_retl_o2_plus_g2_plus_8)
 	be,pn		%icc, 3f
 	 add		%o0, 0x8, %o0
 
-	EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4), U3_retl_o2_plus_g2)
 	add		%o1, 0x8, %o1
 	subcc		%g2, 0x8, %g2
 	faligndata	%f6, %f4, %f2
-	EX_ST_FP(STORE(std, %f2, %o0))
+	EX_ST_FP(STORE(std, %f2, %o0), U3_retl_o2_plus_g2_plus_8)
 	bne,pt		%icc, 1b
 	 add		%o0, 0x8, %o0
 
@@ -161,25 +239,25 @@
 	LOAD(prefetch, %o1 + 0x080, #one_read)
 	LOAD(prefetch, %o1 + 0x0c0, #one_read)
 	LOAD(prefetch, %o1 + 0x100, #one_read)
-	EX_LD_FP(LOAD(ldd, %o1 + 0x000, %f0))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x000, %f0), U3_retl_o2)
 	LOAD(prefetch, %o1 + 0x140, #one_read)
-	EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2), U3_retl_o2)
 	LOAD(prefetch, %o1 + 0x180, #one_read)
-	EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4), U3_retl_o2)
 	LOAD(prefetch, %o1 + 0x1c0, #one_read)
 	faligndata	%f0, %f2, %f16
-	EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6), U3_retl_o2)
 	faligndata	%f2, %f4, %f18
-	EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8), U3_retl_o2)
 	faligndata	%f4, %f6, %f20
-	EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10), U3_retl_o2)
 	faligndata	%f6, %f8, %f22
 
-	EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12), U3_retl_o2)
 	faligndata	%f8, %f10, %f24
-	EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14), U3_retl_o2)
 	faligndata	%f10, %f12, %f26
-	EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0), U3_retl_o2)
 
 	subcc		GLOBAL_SPARE, 0x80, GLOBAL_SPARE
 	add		%o1, 0x40, %o1
@@ -190,26 +268,26 @@
 
 	.align		64
 1:
-	EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2), U3_retl_o2_plus_o3_sll_6_plus_0x80)
 	faligndata	%f12, %f14, %f28
-	EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4), U3_retl_o2_plus_o3_sll_6_plus_0x80)
 	faligndata	%f14, %f0, %f30
-	EX_ST_FP(STORE_BLK(%f16, %o0))
-	EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
+	EX_ST_FP(STORE_BLK(%f16, %o0), U3_retl_o2_plus_o3_sll_6_plus_0x80)
+	EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	faligndata	%f0, %f2, %f16
 	add		%o0, 0x40, %o0
 
-	EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	faligndata	%f2, %f4, %f18
-	EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	faligndata	%f4, %f6, %f20
-	EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	subcc		%o3, 0x01, %o3
 	faligndata	%f6, %f8, %f22
-	EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14), U3_retl_o2_plus_o3_sll_6_plus_0x80)
 
 	faligndata	%f8, %f10, %f24
-	EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0), U3_retl_o2_plus_o3_sll_6_plus_0x80)
 	LOAD(prefetch, %o1 + 0x1c0, #one_read)
 	faligndata	%f10, %f12, %f26
 	bg,pt		%XCC, 1b
@@ -217,29 +295,29 @@
 
 	/* Finally we copy the last full 64-byte block. */
 2:
-	EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2), U3_retl_o2_plus_o3_sll_6_plus_0x80)
 	faligndata	%f12, %f14, %f28
-	EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4), U3_retl_o2_plus_o3_sll_6_plus_0x80)
 	faligndata	%f14, %f0, %f30
-	EX_ST_FP(STORE_BLK(%f16, %o0))
-	EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
+	EX_ST_FP(STORE_BLK(%f16, %o0), U3_retl_o2_plus_o3_sll_6_plus_0x80)
+	EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	faligndata	%f0, %f2, %f16
-	EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	faligndata	%f2, %f4, %f18
-	EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	faligndata	%f4, %f6, %f20
-	EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	faligndata	%f6, %f8, %f22
-	EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	faligndata	%f8, %f10, %f24
 	cmp		%g1, 0
 	be,pt		%XCC, 1f
 	 add		%o0, 0x40, %o0
-	EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 1:	faligndata	%f10, %f12, %f26
 	faligndata	%f12, %f14, %f28
 	faligndata	%f14, %f0, %f30
-	EX_ST_FP(STORE_BLK(%f16, %o0))
+	EX_ST_FP(STORE_BLK(%f16, %o0), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 	add		%o0, 0x40, %o0
 	add		%o1, 0x40, %o1
 	membar		#Sync
@@ -259,20 +337,20 @@
 
 	sub		%o2, %g2, %o2
 	be,a,pt		%XCC, 1f
-	 EX_LD_FP(LOAD(ldd, %o1 + 0x00, %f0))
+	 EX_LD_FP(LOAD(ldd, %o1 + 0x00, %f0), U3_retl_o2_plus_g2)
 
-1:	EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f2))
+1:	EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f2), U3_retl_o2_plus_g2)
 	add		%o1, 0x8, %o1
 	subcc		%g2, 0x8, %g2
 	faligndata	%f0, %f2, %f8
-	EX_ST_FP(STORE(std, %f8, %o0))
+	EX_ST_FP(STORE(std, %f8, %o0), U3_retl_o2_plus_g2_plus_8)
 	be,pn		%XCC, 2f
 	 add		%o0, 0x8, %o0
-	EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f0))
+	EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f0), U3_retl_o2_plus_g2)
 	add		%o1, 0x8, %o1
 	subcc		%g2, 0x8, %g2
 	faligndata	%f2, %f0, %f8
-	EX_ST_FP(STORE(std, %f8, %o0))
+	EX_ST_FP(STORE(std, %f8, %o0), U3_retl_o2_plus_g2_plus_8)
 	bne,pn		%XCC, 1b
 	 add		%o0, 0x8, %o0
 
@@ -292,30 +370,33 @@
 	 andcc		%o2, 0x8, %g0
 	be,pt		%icc, 1f
 	 nop
-	EX_LD(LOAD(ldx, %o1, %o5))
-	EX_ST(STORE(stx, %o5, %o1 + %o3))
+	EX_LD(LOAD(ldx, %o1, %o5), U3_retl_o2)
+	EX_ST(STORE(stx, %o5, %o1 + %o3), U3_retl_o2)
 	add		%o1, 0x8, %o1
+	sub		%o2, 8, %o2
 
 1:	andcc		%o2, 0x4, %g0
 	be,pt		%icc, 1f
 	 nop
-	EX_LD(LOAD(lduw, %o1, %o5))
-	EX_ST(STORE(stw, %o5, %o1 + %o3))
+	EX_LD(LOAD(lduw, %o1, %o5), U3_retl_o2)
+	EX_ST(STORE(stw, %o5, %o1 + %o3), U3_retl_o2)
 	add		%o1, 0x4, %o1
+	sub		%o2, 4, %o2
 
 1:	andcc		%o2, 0x2, %g0
 	be,pt		%icc, 1f
 	 nop
-	EX_LD(LOAD(lduh, %o1, %o5))
-	EX_ST(STORE(sth, %o5, %o1 + %o3))
+	EX_LD(LOAD(lduh, %o1, %o5), U3_retl_o2)
+	EX_ST(STORE(sth, %o5, %o1 + %o3), U3_retl_o2)
 	add		%o1, 0x2, %o1
+	sub		%o2, 2, %o2
 
 1:	andcc		%o2, 0x1, %g0
 	be,pt		%icc, 85f
 	 nop
-	EX_LD(LOAD(ldub, %o1, %o5))
+	EX_LD(LOAD(ldub, %o1, %o5), U3_retl_o2)
 	ba,pt		%xcc, 85f
-	 EX_ST(STORE(stb, %o5, %o1 + %o3))
+	 EX_ST(STORE(stb, %o5, %o1 + %o3), U3_retl_o2)
 
 	.align		64
 70: /* 16 < len <= 64 */
@@ -326,26 +407,26 @@
 	andn		%o2, 0xf, GLOBAL_SPARE
 	and		%o2, 0xf, %o2
 1:	subcc		GLOBAL_SPARE, 0x10, GLOBAL_SPARE
-	EX_LD(LOAD(ldx, %o1 + 0x00, %o5))
-	EX_LD(LOAD(ldx, %o1 + 0x08, %g1))
-	EX_ST(STORE(stx, %o5, %o1 + %o3))
+	EX_LD(LOAD(ldx, %o1 + 0x00, %o5), U3_retl_o2_plus_GS_plus_0x10)
+	EX_LD(LOAD(ldx, %o1 + 0x08, %g1), U3_retl_o2_plus_GS_plus_0x10)
+	EX_ST(STORE(stx, %o5, %o1 + %o3), U3_retl_o2_plus_GS_plus_0x10)
 	add		%o1, 0x8, %o1
-	EX_ST(STORE(stx, %g1, %o1 + %o3))
+	EX_ST(STORE(stx, %g1, %o1 + %o3), U3_retl_o2_plus_GS_plus_0x08)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 0x8, %o1
 73:	andcc		%o2, 0x8, %g0
 	be,pt		%XCC, 1f
 	 nop
 	sub		%o2, 0x8, %o2
-	EX_LD(LOAD(ldx, %o1, %o5))
-	EX_ST(STORE(stx, %o5, %o1 + %o3))
+	EX_LD(LOAD(ldx, %o1, %o5), U3_retl_o2_plus_8)
+	EX_ST(STORE(stx, %o5, %o1 + %o3), U3_retl_o2_plus_8)
 	add		%o1, 0x8, %o1
 1:	andcc		%o2, 0x4, %g0
 	be,pt		%XCC, 1f
 	 nop
 	sub		%o2, 0x4, %o2
-	EX_LD(LOAD(lduw, %o1, %o5))
-	EX_ST(STORE(stw, %o5, %o1 + %o3))
+	EX_LD(LOAD(lduw, %o1, %o5), U3_retl_o2_plus_4)
+	EX_ST(STORE(stw, %o5, %o1 + %o3), U3_retl_o2_plus_4)
 	add		%o1, 0x4, %o1
 1:	cmp		%o2, 0
 	be,pt		%XCC, 85f
@@ -361,8 +442,8 @@
 	sub		%o2, %g1, %o2
 
 1:	subcc		%g1, 1, %g1
-	EX_LD(LOAD(ldub, %o1, %o5))
-	EX_ST(STORE(stb, %o5, %o1 + %o3))
+	EX_LD(LOAD(ldub, %o1, %o5), U3_retl_o2_plus_g1_plus_1)
+	EX_ST(STORE(stb, %o5, %o1 + %o3), U3_retl_o2_plus_g1_plus_1)
 	bgu,pt		%icc, 1b
 	 add		%o1, 1, %o1
 
@@ -378,16 +459,16 @@
 
 8:	mov		64, %o3
 	andn		%o1, 0x7, %o1
-	EX_LD(LOAD(ldx, %o1, %g2))
+	EX_LD(LOAD(ldx, %o1, %g2), U3_retl_o2)
 	sub		%o3, %g1, %o3
 	andn		%o2, 0x7, GLOBAL_SPARE
 	sllx		%g2, %g1, %g2
-1:	EX_LD(LOAD(ldx, %o1 + 0x8, %g3))
+1:	EX_LD(LOAD(ldx, %o1 + 0x8, %g3), U3_retl_o2_and_7_plus_GS)
 	subcc		GLOBAL_SPARE, 0x8, GLOBAL_SPARE
 	add		%o1, 0x8, %o1
 	srlx		%g3, %o3, %o5
 	or		%o5, %g2, %o5
-	EX_ST(STORE(stx, %o5, %o0))
+	EX_ST(STORE(stx, %o5, %o0), U3_retl_o2_and_7_plus_GS_plus_8)
 	add		%o0, 0x8, %o0
 	bgu,pt		%icc, 1b
 	 sllx		%g3, %g1, %g2
@@ -407,8 +488,8 @@
 
 1:
 	subcc		%o2, 4, %o2
-	EX_LD(LOAD(lduw, %o1, %g1))
-	EX_ST(STORE(stw, %g1, %o1 + %o3))
+	EX_LD(LOAD(lduw, %o1, %g1), U3_retl_o2_plus_4)
+	EX_ST(STORE(stw, %g1, %o1 + %o3), U3_retl_o2_plus_4)
 	bgu,pt		%XCC, 1b
 	 add		%o1, 4, %o1
 
@@ -418,8 +499,8 @@
 	.align		32
 90:
 	subcc		%o2, 1, %o2
-	EX_LD(LOAD(ldub, %o1, %g1))
-	EX_ST(STORE(stb, %g1, %o1 + %o3))
+	EX_LD(LOAD(ldub, %o1, %g1), U3_retl_o2_plus_1)
+	EX_ST(STORE(stb, %g1, %o1 + %o3), U3_retl_o2_plus_1)
 	bgu,pt		%XCC, 90b
 	 add		%o1, 1, %o1
 	retl
--- linux-4.4.0.orig/arch/sparc/lib/copy_in_user.S
+++ linux-4.4.0/arch/sparc/lib/copy_in_user.S
@@ -8,18 +8,33 @@
 
 #define XCC xcc
 
-#define EX(x,y)			\
+#define EX(x,y,z)		\
 98:	x,y;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_one;	\
+	.word 98b, z;		\
 	.text;			\
 	.align 4;
 
+#define EX_O4(x,y) EX(x,y,__retl_o4_plus_8)
+#define EX_O2_4(x,y) EX(x,y,__retl_o2_plus_4)
+#define EX_O2_1(x,y) EX(x,y,__retl_o2_plus_1)
+
 	.register	%g2,#scratch
 	.register	%g3,#scratch
 
 	.text
+__retl_o4_plus_8:
+	add	%o4, %o2, %o4
+	retl
+	 add	%o4, 8, %o0
+__retl_o2_plus_4:
+	retl
+	 add	%o2, 4, %o0
+__retl_o2_plus_1:
+	retl
+	 add	%o2, 1, %o0
+
 	.align	32
 
 	/* Don't try to get too fancy here, just nice and
@@ -44,8 +59,8 @@
 	andn		%o2, 0x7, %o4
 	and		%o2, 0x7, %o2
 1:	subcc		%o4, 0x8, %o4
-	EX(ldxa [%o1] %asi, %o5)
-	EX(stxa %o5, [%o0] %asi)
+	EX_O4(ldxa [%o1] %asi, %o5)
+	EX_O4(stxa %o5, [%o0] %asi)
 	add		%o1, 0x8, %o1
 	bgu,pt		%XCC, 1b
 	 add		%o0, 0x8, %o0
@@ -53,8 +68,8 @@
 	be,pt		%XCC, 1f
 	 nop
 	sub		%o2, 0x4, %o2
-	EX(lduwa [%o1] %asi, %o5)
-	EX(stwa %o5, [%o0] %asi)
+	EX_O2_4(lduwa [%o1] %asi, %o5)
+	EX_O2_4(stwa %o5, [%o0] %asi)
 	add		%o1, 0x4, %o1
 	add		%o0, 0x4, %o0
 1:	cmp		%o2, 0
@@ -70,8 +85,8 @@
 
 82:
 	subcc		%o2, 4, %o2
-	EX(lduwa [%o1] %asi, %g1)
-	EX(stwa %g1, [%o0] %asi)
+	EX_O2_4(lduwa [%o1] %asi, %g1)
+	EX_O2_4(stwa %g1, [%o0] %asi)
 	add		%o1, 4, %o1
 	bgu,pt		%XCC, 82b
 	 add		%o0, 4, %o0
@@ -82,8 +97,8 @@
 	.align	32
 90:
 	subcc		%o2, 1, %o2
-	EX(lduba [%o1] %asi, %g1)
-	EX(stba %g1, [%o0] %asi)
+	EX_O2_1(lduba [%o1] %asi, %g1)
+	EX_O2_1(stba %g1, [%o0] %asi)
 	add		%o1, 1, %o1
 	bgu,pt		%XCC, 90b
 	 add		%o0, 1, %o0
--- linux-4.4.0.orig/arch/sparc/lib/memset.S
+++ linux-4.4.0/arch/sparc/lib/memset.S
@@ -137,6 +137,7 @@
 	ZERO_LAST_BLOCKS(%o0, 0x48, %g2)
 	ZERO_LAST_BLOCKS(%o0, 0x08, %g2)
 13:
+	EXT(12b, 13b, 21f)
 	be	8f
 	 andcc	%o1, 4, %g0
 
--- linux-4.4.0.orig/arch/sparc/mm/fault_64.c
+++ linux-4.4.0/arch/sparc/mm/fault_64.c
@@ -479,14 +479,15 @@
 	up_read(&mm->mmap_sem);
 
 	mm_rss = get_mm_rss(mm);
-#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-	mm_rss -= (mm->context.huge_pte_count * (HPAGE_SIZE / PAGE_SIZE));
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE)
+	mm_rss -= (mm->context.thp_pte_count * (HPAGE_SIZE / PAGE_SIZE));
 #endif
 	if (unlikely(mm_rss >
 		     mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit))
 		tsb_grow(mm, MM_TSB_BASE, mm_rss);
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-	mm_rss = mm->context.huge_pte_count;
+	mm_rss = mm->context.hugetlb_pte_count + mm->context.thp_pte_count;
+	mm_rss *= REAL_HPAGE_PER_HPAGE;
 	if (unlikely(mm_rss >
 		     mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) {
 		if (mm->context.tsb_block[MM_TSB_HUGE].tsb)
--- linux-4.4.0.orig/arch/sparc/mm/gup.c
+++ linux-4.4.0/arch/sparc/mm/gup.c
@@ -250,7 +250,8 @@
 		pages += nr;
 
 		ret = get_user_pages_unlocked(current, mm, start,
-			(end - start) >> PAGE_SHIFT, write, 0, pages);
+			(end - start) >> PAGE_SHIFT, pages,
+			write ? FOLL_WRITE : 0);
 
 		/* Have to be a bit careful with return values */
 		if (nr > 0) {
--- linux-4.4.0.orig/arch/sparc/mm/hugetlbpage.c
+++ linux-4.4.0/arch/sparc/mm/hugetlbpage.c
@@ -115,7 +115,7 @@
 		addr = ALIGN(addr, HPAGE_SIZE);
 		vma = find_vma(mm, addr);
 		if (task_size - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 	if (mm->get_unmapped_area == arch_get_unmapped_area)
@@ -176,17 +176,31 @@
 		     pte_t *ptep, pte_t entry)
 {
 	int i;
+	pte_t orig[2];
+	unsigned long nptes;
 
 	if (!pte_present(*ptep) && pte_present(entry))
-		mm->context.huge_pte_count++;
+		mm->context.hugetlb_pte_count++;
 
 	addr &= HPAGE_MASK;
-	for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
-		set_pte_at(mm, addr, ptep, entry);
+
+	nptes = 1 << HUGETLB_PAGE_ORDER;
+	orig[0] = *ptep;
+	orig[1] = *(ptep + nptes / 2);
+	for (i = 0; i < nptes; i++) {
+		*ptep = entry;
 		ptep++;
 		addr += PAGE_SIZE;
 		pte_val(entry) += PAGE_SIZE;
 	}
+
+	/* Issue TLB flush at REAL_HPAGE_SIZE boundaries */
+	addr -= REAL_HPAGE_SIZE;
+	ptep -= nptes / 2;
+	maybe_tlb_batch_add(mm, addr, ptep, orig[1], 0);
+	addr -= REAL_HPAGE_SIZE;
+	ptep -= nptes / 2;
+	maybe_tlb_batch_add(mm, addr, ptep, orig[0], 0);
 }
 
 pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
@@ -194,19 +208,28 @@
 {
 	pte_t entry;
 	int i;
+	unsigned long nptes;
 
 	entry = *ptep;
 	if (pte_present(entry))
-		mm->context.huge_pte_count--;
+		mm->context.hugetlb_pte_count--;
 
 	addr &= HPAGE_MASK;
-
-	for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
-		pte_clear(mm, addr, ptep);
+	nptes = 1 << HUGETLB_PAGE_ORDER;
+	for (i = 0; i < nptes; i++) {
+		*ptep = __pte(0UL);
 		addr += PAGE_SIZE;
 		ptep++;
 	}
 
+	/* Issue TLB flush at REAL_HPAGE_SIZE boundaries */
+	addr -= REAL_HPAGE_SIZE;
+	ptep -= nptes / 2;
+	maybe_tlb_batch_add(mm, addr, ptep, entry, 0);
+	addr -= REAL_HPAGE_SIZE;
+	ptep -= nptes / 2;
+	maybe_tlb_batch_add(mm, addr, ptep, entry, 0);
+
 	return entry;
 }
 
--- linux-4.4.0.orig/arch/sparc/mm/init_32.c
+++ linux-4.4.0/arch/sparc/mm/init_32.c
@@ -301,7 +301,7 @@
 
 
 	/* Saves us work later. */
-	memset((void *)&empty_zero_page, 0, PAGE_SIZE);
+	memset((void *)empty_zero_page, 0, PAGE_SIZE);
 
 	i = last_valid_pfn >> ((20 - PAGE_SHIFT) + 5);
 	i += 1;
--- linux-4.4.0.orig/arch/sparc/mm/init_64.c
+++ linux-4.4.0/arch/sparc/mm/init_64.c
@@ -324,18 +324,6 @@
 	tsb_insert(tsb, tag, tte);
 }
 
-#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-static inline bool is_hugetlb_pte(pte_t pte)
-{
-	if ((tlb_type == hypervisor &&
-	     (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) ||
-	    (tlb_type != hypervisor &&
-	     (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U))
-		return true;
-	return false;
-}
-#endif
-
 void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
 	struct mm_struct *mm;
@@ -358,7 +346,8 @@
 	spin_lock_irqsave(&mm->context.lock, flags);
 
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-	if (mm->context.huge_pte_count && is_hugetlb_pte(pte))
+	if ((mm->context.hugetlb_pte_count || mm->context.thp_pte_count) &&
+	    is_hugetlb_pte(pte))
 		__update_mmu_tsb_insert(mm, MM_TSB_HUGE, REAL_HPAGE_SHIFT,
 					address, pte_val(pte));
 	else
@@ -667,10 +656,58 @@
 
 /* get_new_mmu_context() uses "cache + 1".  */
 DEFINE_SPINLOCK(ctx_alloc_lock);
-unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
+unsigned long tlb_context_cache = CTX_FIRST_VERSION;
 #define MAX_CTX_NR	(1UL << CTX_NR_BITS)
 #define CTX_BMAP_SLOTS	BITS_TO_LONGS(MAX_CTX_NR)
 DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR);
+DEFINE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm) = {0};
+
+static void mmu_context_wrap(void)
+{
+	unsigned long old_ver = tlb_context_cache & CTX_VERSION_MASK;
+	unsigned long new_ver, new_ctx, old_ctx;
+	struct mm_struct *mm;
+	int cpu;
+
+	bitmap_zero(mmu_context_bmap, 1 << CTX_NR_BITS);
+
+	/* Reserve kernel context */
+	set_bit(0, mmu_context_bmap);
+
+	new_ver = (tlb_context_cache & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
+	if (unlikely(new_ver == 0))
+		new_ver = CTX_FIRST_VERSION;
+	tlb_context_cache = new_ver;
+
+	/*
+	 * Make sure that any new mm that are added into per_cpu_secondary_mm,
+	 * are going to go through get_new_mmu_context() path.
+	 */
+	mb();
+
+	/*
+	 * Updated versions to current on those CPUs that had valid secondary
+	 * contexts
+	 */
+	for_each_online_cpu(cpu) {
+		/*
+		 * If a new mm is stored after we took this mm from the array,
+		 * it will go into get_new_mmu_context() path, because we
+		 * already bumped the version in tlb_context_cache.
+		 */
+		mm = per_cpu(per_cpu_secondary_mm, cpu);
+
+		if (unlikely(!mm || mm == &init_mm))
+			continue;
+
+		old_ctx = mm->context.sparc64_ctx_val;
+		if (likely((old_ctx & CTX_VERSION_MASK) == old_ver)) {
+			new_ctx = (old_ctx & ~CTX_VERSION_MASK) | new_ver;
+			set_bit(new_ctx & CTX_NR_MASK, mmu_context_bmap);
+			mm->context.sparc64_ctx_val = new_ctx;
+		}
+	}
+}
 
 /* Caller does TLB context flushing on local CPU if necessary.
  * The caller also ensures that CTX_VALID(mm->context) is false.
@@ -686,48 +723,30 @@
 {
 	unsigned long ctx, new_ctx;
 	unsigned long orig_pgsz_bits;
-	int new_version;
 
 	spin_lock(&ctx_alloc_lock);
+retry:
+	/* wrap might have happened, test again if our context became valid */
+	if (unlikely(CTX_VALID(mm->context)))
+		goto out;
 	orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK);
 	ctx = (tlb_context_cache + 1) & CTX_NR_MASK;
 	new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx);
-	new_version = 0;
 	if (new_ctx >= (1 << CTX_NR_BITS)) {
 		new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
 		if (new_ctx >= ctx) {
-			int i;
-			new_ctx = (tlb_context_cache & CTX_VERSION_MASK) +
-				CTX_FIRST_VERSION;
-			if (new_ctx == 1)
-				new_ctx = CTX_FIRST_VERSION;
-
-			/* Don't call memset, for 16 entries that's just
-			 * plain silly...
-			 */
-			mmu_context_bmap[0] = 3;
-			mmu_context_bmap[1] = 0;
-			mmu_context_bmap[2] = 0;
-			mmu_context_bmap[3] = 0;
-			for (i = 4; i < CTX_BMAP_SLOTS; i += 4) {
-				mmu_context_bmap[i + 0] = 0;
-				mmu_context_bmap[i + 1] = 0;
-				mmu_context_bmap[i + 2] = 0;
-				mmu_context_bmap[i + 3] = 0;
-			}
-			new_version = 1;
-			goto out;
+			mmu_context_wrap();
+			goto retry;
 		}
 	}
+	if (mm->context.sparc64_ctx_val)
+		cpumask_clear(mm_cpumask(mm));
 	mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63));
 	new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
-out:
 	tlb_context_cache = new_ctx;
 	mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits;
+out:
 	spin_unlock(&ctx_alloc_lock);
-
-	if (unlikely(new_version))
-		smp_new_mmu_context_version();
 }
 
 static int numa_enabled = 1;
@@ -811,8 +830,10 @@
 };
 static struct mdesc_mblock *mblocks;
 static int num_mblocks;
+static int find_numa_node_for_addr(unsigned long pa,
+				   struct node_mem_mask *pnode_mask);
 
-static unsigned long ra_to_pa(unsigned long addr)
+static unsigned long __init ra_to_pa(unsigned long addr)
 {
 	int i;
 
@@ -828,8 +849,11 @@
 	return addr;
 }
 
-static int find_node(unsigned long addr)
+static int __init find_node(unsigned long addr)
 {
+	static bool search_mdesc = true;
+	static struct node_mem_mask last_mem_mask = { ~0UL, ~0UL };
+	static int last_index;
 	int i;
 
 	addr = ra_to_pa(addr);
@@ -839,13 +863,30 @@
 		if ((addr & p->mask) == p->val)
 			return i;
 	}
-	/* The following condition has been observed on LDOM guests.*/
-	WARN_ONCE(1, "find_node: A physical address doesn't match a NUMA node"
-		" rule. Some physical memory will be owned by node 0.");
-	return 0;
+	/* The following condition has been observed on LDOM guests because
+	 * node_masks only contains the best latency mask and value.
+	 * LDOM guest's mdesc can contain a single latency group to
+	 * cover multiple address range. Print warning message only if the
+	 * address cannot be found in node_masks nor mdesc.
+	 */
+	if ((search_mdesc) &&
+	    ((addr & last_mem_mask.mask) != last_mem_mask.val)) {
+		/* find the available node in the mdesc */
+		last_index = find_numa_node_for_addr(addr, &last_mem_mask);
+		numadbg("find_node: latency group for address 0x%lx is %d\n",
+			addr, last_index);
+		if ((last_index < 0) || (last_index >= num_node_masks)) {
+			/* WARN_ONCE() and use default group 0 */
+			WARN_ONCE(1, "find_node: A physical address doesn't match a NUMA node rule. Some physical memory will be owned by node 0.");
+			search_mdesc = false;
+			last_index = 0;
+		}
+	}
+
+	return last_index;
 }
 
-static u64 memblock_nid_range(u64 start, u64 end, int *nid)
+static u64 __init memblock_nid_range(u64 start, u64 end, int *nid)
 {
 	*nid = find_node(start);
 	start += PAGE_SIZE;
@@ -1169,6 +1210,41 @@
 	return numa_latency[from][to];
 }
 
+static int find_numa_node_for_addr(unsigned long pa,
+				   struct node_mem_mask *pnode_mask)
+{
+	struct mdesc_handle *md = mdesc_grab();
+	u64 node, arc;
+	int i = 0;
+
+	node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups");
+	if (node == MDESC_NODE_NULL)
+		goto out;
+
+	mdesc_for_each_node_by_name(md, node, "group") {
+		mdesc_for_each_arc(arc, md, node, MDESC_ARC_TYPE_FWD) {
+			u64 target = mdesc_arc_target(md, arc);
+			struct mdesc_mlgroup *m = find_mlgroup(target);
+
+			if (!m)
+				continue;
+			if ((pa & m->mask) == m->match) {
+				if (pnode_mask) {
+					pnode_mask->mask = m->mask;
+					pnode_mask->val = m->match;
+				}
+				mdesc_release(md);
+				return i;
+			}
+		}
+		i++;
+	}
+
+out:
+	mdesc_release(md);
+	return -1;
+}
+
 static int find_best_numa_node_for_mlgroup(struct mdesc_mlgroup *grp)
 {
 	int i;
@@ -1267,13 +1343,6 @@
 	int i, j, err, count;
 	u64 node;
 
-	/* Some sane defaults for numa latency values */
-	for (i = 0; i < MAX_NUMNODES; i++) {
-		for (j = 0; j < MAX_NUMNODES; j++)
-			numa_latency[i][j] = (i == j) ?
-				LOCAL_DISTANCE : REMOTE_DISTANCE;
-	}
-
 	node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups");
 	if (node == MDESC_NODE_NULL) {
 		mdesc_release(md);
@@ -1369,10 +1438,18 @@
 
 static int __init bootmem_init_numa(void)
 {
+	int i, j;
 	int err = -1;
 
 	numadbg("bootmem_init_numa()\n");
 
+	/* Some sane defaults for numa latency values */
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		for (j = 0; j < MAX_NUMNODES; j++)
+			numa_latency[i][j] = (i == j) ?
+				LOCAL_DISTANCE : REMOTE_DISTANCE;
+	}
+
 	if (numa_enabled) {
 		if (tlb_type == hypervisor)
 			err = numa_parse_mdesc();
@@ -1446,7 +1523,7 @@
 	if ((long)addr < 0L) {
 		unsigned long pa = __pa(addr);
 
-		if ((addr >> max_phys_bits) != 0UL)
+		if ((pa >> max_phys_bits) != 0UL)
 			return false;
 
 		return pfn_valid(pa >> PAGE_SHIFT);
@@ -2325,10 +2402,17 @@
 {
 	high_memory = __va(last_valid_pfn << PAGE_SHIFT);
 
-	register_page_bootmem_info();
 	free_all_bootmem();
 
 	/*
+	 * Must be done after boot memory is put on freelist, because here we
+	 * might set fields in deferred struct pages that have not yet been
+	 * initialized, and free_all_bootmem() initializes all the reserved
+	 * deferred pages for us.
+	 */
+	register_page_bootmem_info();
+
+	/*
 	 * Set up the zero page, mark it reserved, so that page count
 	 * is not manipulated when freeing the page from user ptes.
 	 */
@@ -2832,9 +2916,10 @@
 	 * the Data-TLB for huge pages.
 	 */
 	if (tlb_type == cheetah_plus) {
+		bool need_context_reload = false;
 		unsigned long ctx;
 
-		spin_lock(&ctx_alloc_lock);
+		spin_lock_irq(&ctx_alloc_lock);
 		ctx = mm->context.sparc64_ctx_val;
 		ctx &= ~CTX_PGSZ_MASK;
 		ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT;
@@ -2853,9 +2938,12 @@
 			 * also executing in this address space.
 			 */
 			mm->context.sparc64_ctx_val = ctx;
-			on_each_cpu(context_reload, mm, 0);
+			need_context_reload = true;
 		}
-		spin_unlock(&ctx_alloc_lock);
+		spin_unlock_irq(&ctx_alloc_lock);
+
+		if (need_context_reload)
+			on_each_cpu(context_reload, mm, 0);
 	}
 }
 #endif
--- linux-4.4.0.orig/arch/sparc/mm/tlb.c
+++ linux-4.4.0/arch/sparc/mm/tlb.c
@@ -67,7 +67,7 @@
 }
 
 static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
-			      bool exec)
+			      bool exec, bool huge)
 {
 	struct tlb_batch *tb = &get_cpu_var(tlb_batch);
 	unsigned long nr;
@@ -84,13 +84,21 @@
 	}
 
 	if (!tb->active) {
-		flush_tsb_user_page(mm, vaddr);
+		flush_tsb_user_page(mm, vaddr, huge);
 		global_flush_tlb_page(mm, vaddr);
 		goto out;
 	}
 
-	if (nr == 0)
+	if (nr == 0) {
 		tb->mm = mm;
+		tb->huge = huge;
+	}
+
+	if (tb->huge != huge) {
+		flush_tlb_pending();
+		tb->huge = huge;
+		nr = 0;
+	}
 
 	tb->vaddrs[nr] = vaddr;
 	tb->tlb_nr = ++nr;
@@ -104,6 +112,8 @@
 void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
 		   pte_t *ptep, pte_t orig, int fullmm)
 {
+	bool huge = is_hugetlb_pte(orig);
+
 	if (tlb_type != hypervisor &&
 	    pte_dirty(orig)) {
 		unsigned long paddr, pfn = pte_pfn(orig);
@@ -129,7 +139,7 @@
 
 no_cache_flush:
 	if (!fullmm)
-		tlb_batch_add_one(mm, vaddr, pte_exec(orig));
+		tlb_batch_add_one(mm, vaddr, pte_exec(orig), huge);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -145,7 +155,7 @@
 		if (pte_val(*pte) & _PAGE_VALID) {
 			bool exec = pte_exec(*pte);
 
-			tlb_batch_add_one(mm, vaddr, exec);
+			tlb_batch_add_one(mm, vaddr, exec, false);
 		}
 		pte++;
 		vaddr += PAGE_SIZE;
@@ -164,10 +174,25 @@
 		return;
 
 	if ((pmd_val(pmd) ^ pmd_val(orig)) & _PAGE_PMD_HUGE) {
-		if (pmd_val(pmd) & _PAGE_PMD_HUGE)
-			mm->context.huge_pte_count++;
-		else
-			mm->context.huge_pte_count--;
+		/*
+		 * Note that this routine only sets pmds for THP pages.
+		 * Hugetlb pages are handled elsewhere.  We need to check
+		 * for huge zero page.  Huge zero pages are like hugetlb
+		 * pages in that there is no RSS, but there is the need
+		 * for TSB entries.  So, huge zero page counts go into
+		 * hugetlb_pte_count.
+		 */
+		if (pmd_val(pmd) & _PAGE_PMD_HUGE) {
+			if (is_huge_zero_page(pmd_page(pmd)))
+				mm->context.hugetlb_pte_count++;
+			else
+				mm->context.thp_pte_count++;
+		} else {
+			if (is_huge_zero_page(pmd_page(orig)))
+				mm->context.hugetlb_pte_count--;
+			else
+				mm->context.thp_pte_count--;
+		}
 
 		/* Do not try to allocate the TSB hash table if we
 		 * don't have one already.  We have various locks held
@@ -185,14 +210,18 @@
 			pte_t orig_pte = __pte(pmd_val(orig));
 			bool exec = pte_exec(orig_pte);
 
-			tlb_batch_add_one(mm, addr, exec);
-			tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec);
+			tlb_batch_add_one(mm, addr, exec, true);
+			tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec,
+					true);
 		} else {
 			tlb_batch_pmd_scan(mm, addr, orig);
 		}
 	}
 }
 
+/*
+ * This routine is only called when splitting a THP
+ */
 void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
 		     pmd_t *pmdp)
 {
@@ -202,6 +231,15 @@
 
 	set_pmd_at(vma->vm_mm, address, pmdp, entry);
 	flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
+
+	/*
+	 * set_pmd_at() will not be called in a way to decrement
+	 * thp_pte_count when splitting a THP, so do it now.
+	 * Sanity check pmd before doing the actual decrement.
+	 */
+	if ((pmd_val(entry) & _PAGE_PMD_HUGE) &&
+	    !is_huge_zero_page(pmd_page(entry)))
+		(vma->vm_mm)->context.thp_pte_count--;
 }
 
 void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
--- linux-4.4.0.orig/arch/sparc/mm/tsb.c
+++ linux-4.4.0/arch/sparc/mm/tsb.c
@@ -27,6 +27,20 @@
 	return (tag == (vaddr >> 22));
 }
 
+static void flush_tsb_kernel_range_scan(unsigned long start, unsigned long end)
+{
+	unsigned long idx;
+
+	for (idx = 0; idx < KERNEL_TSB_NENTRIES; idx++) {
+		struct tsb *ent = &swapper_tsb[idx];
+		unsigned long match = idx << 13;
+
+		match |= (ent->tag << 22);
+		if (match >= start && match < end)
+			ent->tag = (1UL << TSB_TAG_INVALID_BIT);
+	}
+}
+
 /* TSB flushes need only occur on the processor initiating the address
  * space modification, not on each cpu the address space has run on.
  * Only the TLB flush needs that treatment.
@@ -36,6 +50,9 @@
 {
 	unsigned long v;
 
+	if ((end - start) >> PAGE_SHIFT >= 2 * KERNEL_TSB_NENTRIES)
+		return flush_tsb_kernel_range_scan(start, end);
+
 	for (v = start; v < end; v += PAGE_SIZE) {
 		unsigned long hash = tsb_hash(v, PAGE_SHIFT,
 					      KERNEL_TSB_NENTRIES);
@@ -76,14 +93,15 @@
 
 	spin_lock_irqsave(&mm->context.lock, flags);
 
-	base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb;
-	nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
-	if (tlb_type == cheetah_plus || tlb_type == hypervisor)
-		base = __pa(base);
-	__flush_tsb_one(tb, PAGE_SHIFT, base, nentries);
-
+	if (!tb->huge) {
+		base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb;
+		nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
+		if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+			base = __pa(base);
+		__flush_tsb_one(tb, PAGE_SHIFT, base, nentries);
+	}
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-	if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
+	if (tb->huge && mm->context.tsb_block[MM_TSB_HUGE].tsb) {
 		base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb;
 		nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
 		if (tlb_type == cheetah_plus || tlb_type == hypervisor)
@@ -94,20 +112,21 @@
 	spin_unlock_irqrestore(&mm->context.lock, flags);
 }
 
-void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr)
+void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, bool huge)
 {
 	unsigned long nentries, base, flags;
 
 	spin_lock_irqsave(&mm->context.lock, flags);
 
-	base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb;
-	nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
-	if (tlb_type == cheetah_plus || tlb_type == hypervisor)
-		base = __pa(base);
-	__flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries);
-
+	if (!huge) {
+		base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb;
+		nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
+		if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+			base = __pa(base);
+		__flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries);
+	}
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-	if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
+	if (huge && mm->context.tsb_block[MM_TSB_HUGE].tsb) {
 		base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb;
 		nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
 		if (tlb_type == cheetah_plus || tlb_type == hypervisor)
@@ -432,7 +451,8 @@
 		extern void copy_tsb(unsigned long old_tsb_base,
 				     unsigned long old_tsb_size,
 				     unsigned long new_tsb_base,
-				     unsigned long new_tsb_size);
+				     unsigned long new_tsb_size,
+				     unsigned long page_size_shift);
 		unsigned long old_tsb_base = (unsigned long) old_tsb;
 		unsigned long new_tsb_base = (unsigned long) new_tsb;
 
@@ -440,7 +460,9 @@
 			old_tsb_base = __pa(old_tsb_base);
 			new_tsb_base = __pa(new_tsb_base);
 		}
-		copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size);
+		copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size,
+			tsb_index == MM_TSB_BASE ?
+			PAGE_SHIFT : REAL_HPAGE_SHIFT);
 	}
 
 	mm->context.tsb_block[tsb_index].tsb = new_tsb;
@@ -467,8 +489,10 @@
 
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
+	unsigned long mm_rss = get_mm_rss(mm);
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-	unsigned long huge_pte_count;
+	unsigned long saved_hugetlb_pte_count;
+	unsigned long saved_thp_pte_count;
 #endif
 	unsigned int i;
 
@@ -477,12 +501,16 @@
 	mm->context.sparc64_ctx_val = 0UL;
 
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-	/* We reset it to zero because the fork() page copying
+	/* We reset them to zero because the fork() page copying
 	 * will re-increment the counters as the parent PTEs are
 	 * copied into the child address space.
 	 */
-	huge_pte_count = mm->context.huge_pte_count;
-	mm->context.huge_pte_count = 0;
+	saved_hugetlb_pte_count = mm->context.hugetlb_pte_count;
+	saved_thp_pte_count = mm->context.thp_pte_count;
+	mm->context.hugetlb_pte_count = 0;
+	mm->context.thp_pte_count = 0;
+
+	mm_rss -= saved_thp_pte_count * (HPAGE_SIZE / PAGE_SIZE);
 #endif
 
 	/* copy_mm() copies over the parent's mm_struct before calling
@@ -495,11 +523,13 @@
 	/* If this is fork, inherit the parent's TSB size.  We would
 	 * grow it to that size on the first page fault anyways.
 	 */
-	tsb_grow(mm, MM_TSB_BASE, get_mm_rss(mm));
+	tsb_grow(mm, MM_TSB_BASE, mm_rss);
 
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-	if (unlikely(huge_pte_count))
-		tsb_grow(mm, MM_TSB_HUGE, huge_pte_count);
+	if (unlikely(saved_hugetlb_pte_count + saved_thp_pte_count))
+		tsb_grow(mm, MM_TSB_HUGE,
+			 (saved_hugetlb_pte_count + saved_thp_pte_count) *
+			 REAL_HPAGE_PER_HPAGE);
 #endif
 
 	if (unlikely(!mm->context.tsb_block[MM_TSB_BASE].tsb))
--- linux-4.4.0.orig/arch/sparc/mm/ultra.S
+++ linux-4.4.0/arch/sparc/mm/ultra.S
@@ -30,7 +30,7 @@
 	.text
 	.align		32
 	.globl		__flush_tlb_mm
-__flush_tlb_mm:		/* 18 insns */
+__flush_tlb_mm:		/* 19 insns */
 	/* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
 	ldxa		[%o1] ASI_DMMU, %g2
 	cmp		%g2, %o0
@@ -81,7 +81,7 @@
 
 	.align		32
 	.globl		__flush_tlb_pending
-__flush_tlb_pending:	/* 26 insns */
+__flush_tlb_pending:	/* 27 insns */
 	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
 	rdpr		%pstate, %g7
 	sllx		%o1, 3, %o1
@@ -113,12 +113,14 @@
 
 	.align		32
 	.globl		__flush_tlb_kernel_range
-__flush_tlb_kernel_range:	/* 16 insns */
+__flush_tlb_kernel_range:	/* 31 insns */
 	/* %o0=start, %o1=end */
 	cmp		%o0, %o1
 	be,pn		%xcc, 2f
+	 sub		%o1, %o0, %o3
+	srlx		%o3, 18, %o4
+	brnz,pn		%o4, __spitfire_flush_tlb_kernel_range_slow
 	 sethi		%hi(PAGE_SIZE), %o4
-	sub		%o1, %o0, %o3
 	sub		%o3, %o4, %o3
 	or		%o0, 0x20, %o0		! Nucleus
 1:	stxa		%g0, [%o0 + %o3] ASI_DMMU_DEMAP
@@ -131,6 +133,41 @@
 	retl
 	 nop
 	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+__spitfire_flush_tlb_kernel_range_slow:
+	mov		63 * 8, %o4
+1:	ldxa		[%o4] ASI_ITLB_DATA_ACCESS, %o3
+	andcc		%o3, 0x40, %g0			/* _PAGE_L_4U */
+	bne,pn		%xcc, 2f
+	 mov		TLB_TAG_ACCESS, %o3
+	stxa		%g0, [%o3] ASI_IMMU
+	stxa		%g0, [%o4] ASI_ITLB_DATA_ACCESS
+	membar		#Sync
+2:	ldxa		[%o4] ASI_DTLB_DATA_ACCESS, %o3
+	andcc		%o3, 0x40, %g0
+	bne,pn		%xcc, 2f
+	 mov		TLB_TAG_ACCESS, %o3
+	stxa		%g0, [%o3] ASI_DMMU
+	stxa		%g0, [%o4] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
+2:	sub		%o4, 8, %o4
+	brgez,pt	%o4, 1b
+	 nop
+	retl
+	 nop
 
 __spitfire_flush_tlb_mm_slow:
 	rdpr		%pstate, %g1
@@ -285,6 +322,40 @@
 	retl
 	 wrpr		%g7, 0x0, %pstate
 
+__cheetah_flush_tlb_kernel_range:	/* 31 insns */
+	/* %o0=start, %o1=end */
+	cmp		%o0, %o1
+	be,pn		%xcc, 2f
+	 sub		%o1, %o0, %o3
+	srlx		%o3, 18, %o4
+	brnz,pn		%o4, 3f
+	 sethi		%hi(PAGE_SIZE), %o4
+	sub		%o3, %o4, %o3
+	or		%o0, 0x20, %o0		! Nucleus
+1:	stxa		%g0, [%o0 + %o3] ASI_DMMU_DEMAP
+	stxa		%g0, [%o0 + %o3] ASI_IMMU_DEMAP
+	membar		#Sync
+	brnz,pt		%o3, 1b
+	 sub		%o3, %o4, %o3
+2:	sethi		%hi(KERNBASE), %o3
+	flush		%o3
+	retl
+	 nop
+3:	mov		0x80, %o4
+	stxa		%g0, [%o4] ASI_DMMU_DEMAP
+	membar		#Sync
+	stxa		%g0, [%o4] ASI_IMMU_DEMAP
+	membar		#Sync
+	retl
+	 nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 #ifdef DCACHE_ALIASING_POSSIBLE
 __cheetah_flush_dcache_page: /* 11 insns */
 	sethi		%hi(PAGE_OFFSET), %g1
@@ -309,19 +380,28 @@
 	ret
 	 restore
 
-__hypervisor_flush_tlb_mm: /* 10 insns */
+__hypervisor_flush_tlb_mm: /* 19 insns */
 	mov		%o0, %o2	/* ARG2: mmu context */
 	mov		0, %o0		/* ARG0: CPU lists unimplemented */
 	mov		0, %o1		/* ARG1: CPU lists unimplemented */
 	mov		HV_MMU_ALL, %o3	/* ARG3: flags */
 	mov		HV_FAST_MMU_DEMAP_CTX, %o5
 	ta		HV_FAST_TRAP
-	brnz,pn		%o0, __hypervisor_tlb_tl0_error
+	brnz,pn		%o0, 1f
 	 mov		HV_FAST_MMU_DEMAP_CTX, %o1
 	retl
 	 nop
+1:	sethi		%hi(__hypervisor_tlb_tl0_error), %o5
+	jmpl		%o5 + %lo(__hypervisor_tlb_tl0_error), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
 
-__hypervisor_flush_tlb_page: /* 11 insns */
+__hypervisor_flush_tlb_page: /* 22 insns */
 	/* %o0 = context, %o1 = vaddr */
 	mov		%o0, %g2
 	mov		%o1, %o0              /* ARG0: vaddr + IMMU-bit */
@@ -330,12 +410,23 @@
 	srlx		%o0, PAGE_SHIFT, %o0
 	sllx		%o0, PAGE_SHIFT, %o0
 	ta		HV_MMU_UNMAP_ADDR_TRAP
-	brnz,pn		%o0, __hypervisor_tlb_tl0_error
+	brnz,pn		%o0, 1f
 	 mov		HV_MMU_UNMAP_ADDR_TRAP, %o1
 	retl
 	 nop
+1:	sethi		%hi(__hypervisor_tlb_tl0_error), %o2
+	jmpl		%o2 + %lo(__hypervisor_tlb_tl0_error), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
 
-__hypervisor_flush_tlb_pending: /* 16 insns */
+__hypervisor_flush_tlb_pending: /* 27 insns */
 	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
 	sllx		%o1, 3, %g1
 	mov		%o2, %g2
@@ -347,31 +438,57 @@
 	srlx		%o0, PAGE_SHIFT, %o0
 	sllx		%o0, PAGE_SHIFT, %o0
 	ta		HV_MMU_UNMAP_ADDR_TRAP
-	brnz,pn		%o0, __hypervisor_tlb_tl0_error
+	brnz,pn		%o0, 1f
 	 mov		HV_MMU_UNMAP_ADDR_TRAP, %o1
 	brnz,pt		%g1, 1b
 	 nop
 	retl
 	 nop
+1:	sethi		%hi(__hypervisor_tlb_tl0_error), %o2
+	jmpl		%o2 + %lo(__hypervisor_tlb_tl0_error), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
 
-__hypervisor_flush_tlb_kernel_range: /* 16 insns */
+__hypervisor_flush_tlb_kernel_range: /* 31 insns */
 	/* %o0=start, %o1=end */
 	cmp		%o0, %o1
 	be,pn		%xcc, 2f
-	 sethi		%hi(PAGE_SIZE), %g3
-	mov		%o0, %g1
-	sub		%o1, %g1, %g2
+	 sub		%o1, %o0, %g2
+	srlx		%g2, 18, %g3
+	brnz,pn		%g3, 4f
+	 mov		%o0, %g1
+	sethi		%hi(PAGE_SIZE), %g3
 	sub		%g2, %g3, %g2
 1:	add		%g1, %g2, %o0	/* ARG0: virtual address */
 	mov		0, %o1		/* ARG1: mmu context */
 	mov		HV_MMU_ALL, %o2	/* ARG2: flags */
 	ta		HV_MMU_UNMAP_ADDR_TRAP
-	brnz,pn		%o0, __hypervisor_tlb_tl0_error
+	brnz,pn		%o0, 3f
 	 mov		HV_MMU_UNMAP_ADDR_TRAP, %o1
 	brnz,pt		%g2, 1b
 	 sub		%g2, %g3, %g2
 2:	retl
 	 nop
+3:	sethi		%hi(__hypervisor_tlb_tl0_error), %o2
+	jmpl		%o2 + %lo(__hypervisor_tlb_tl0_error), %g0
+	 nop
+4:	mov		0, %o0		/* ARG0: CPU lists unimplemented */
+	mov		0, %o1		/* ARG1: CPU lists unimplemented */
+	mov		0, %o2		/* ARG2: mmu context == nucleus */
+	mov		HV_MMU_ALL, %o3	/* ARG3: flags */
+	mov		HV_FAST_MMU_DEMAP_CTX, %o5
+	ta		HV_FAST_TRAP
+	brnz,pn		%o0, 3b
+	 mov		HV_FAST_MMU_DEMAP_CTX, %o1
+	retl
+	 nop
 
 #ifdef DCACHE_ALIASING_POSSIBLE
 	/* XXX Niagara and friends have an 8K cache, so no aliasing is
@@ -394,43 +511,6 @@
 	retl
 	 nop
 
-	.globl		cheetah_patch_cachetlbops
-cheetah_patch_cachetlbops:
-	save		%sp, -128, %sp
-
-	sethi		%hi(__flush_tlb_mm), %o0
-	or		%o0, %lo(__flush_tlb_mm), %o0
-	sethi		%hi(__cheetah_flush_tlb_mm), %o1
-	or		%o1, %lo(__cheetah_flush_tlb_mm), %o1
-	call		tlb_patch_one
-	 mov		19, %o2
-
-	sethi		%hi(__flush_tlb_page), %o0
-	or		%o0, %lo(__flush_tlb_page), %o0
-	sethi		%hi(__cheetah_flush_tlb_page), %o1
-	or		%o1, %lo(__cheetah_flush_tlb_page), %o1
-	call		tlb_patch_one
-	 mov		22, %o2
-
-	sethi		%hi(__flush_tlb_pending), %o0
-	or		%o0, %lo(__flush_tlb_pending), %o0
-	sethi		%hi(__cheetah_flush_tlb_pending), %o1
-	or		%o1, %lo(__cheetah_flush_tlb_pending), %o1
-	call		tlb_patch_one
-	 mov		27, %o2
-
-#ifdef DCACHE_ALIASING_POSSIBLE
-	sethi		%hi(__flush_dcache_page), %o0
-	or		%o0, %lo(__flush_dcache_page), %o0
-	sethi		%hi(__cheetah_flush_dcache_page), %o1
-	or		%o1, %lo(__cheetah_flush_dcache_page), %o1
-	call		tlb_patch_one
-	 mov		11, %o2
-#endif /* DCACHE_ALIASING_POSSIBLE */
-
-	ret
-	 restore
-
 #ifdef CONFIG_SMP
 	/* These are all called by the slaves of a cross call, at
 	 * trap level 1, with interrupts fully disabled.
@@ -447,7 +527,7 @@
 	 */
 	.align		32
 	.globl		xcall_flush_tlb_mm
-xcall_flush_tlb_mm:	/* 21 insns */
+xcall_flush_tlb_mm:	/* 24 insns */
 	mov		PRIMARY_CONTEXT, %g2
 	ldxa		[%g2] ASI_DMMU, %g3
 	srlx		%g3, CTX_PGSZ1_NUC_SHIFT, %g4
@@ -469,9 +549,12 @@
 	nop
 	nop
 	nop
+	nop
+	nop
+	nop
 
 	.globl		xcall_flush_tlb_page
-xcall_flush_tlb_page:	/* 17 insns */
+xcall_flush_tlb_page:	/* 20 insns */
 	/* %g5=context, %g1=vaddr */
 	mov		PRIMARY_CONTEXT, %g4
 	ldxa		[%g4] ASI_DMMU, %g2
@@ -490,15 +573,20 @@
 	retry
 	nop
 	nop
+	nop
+	nop
+	nop
 
 	.globl		xcall_flush_tlb_kernel_range
-xcall_flush_tlb_kernel_range:	/* 25 insns */
+xcall_flush_tlb_kernel_range:	/* 44 insns */
 	sethi		%hi(PAGE_SIZE - 1), %g2
 	or		%g2, %lo(PAGE_SIZE - 1), %g2
 	andn		%g1, %g2, %g1
 	andn		%g7, %g2, %g7
 	sub		%g7, %g1, %g3
-	add		%g2, 1, %g2
+	srlx		%g3, 18, %g2
+	brnz,pn		%g2, 2f
+	 sethi		%hi(PAGE_SIZE), %g2
 	sub		%g3, %g2, %g3
 	or		%g1, 0x20, %g1		! Nucleus
 1:	stxa		%g0, [%g1 + %g3] ASI_DMMU_DEMAP
@@ -507,8 +595,25 @@
 	brnz,pt		%g3, 1b
 	 sub		%g3, %g2, %g3
 	retry
-	nop
-	nop
+2:	mov		63 * 8, %g1
+1:	ldxa		[%g1] ASI_ITLB_DATA_ACCESS, %g2
+	andcc		%g2, 0x40, %g0			/* _PAGE_L_4U */
+	bne,pn		%xcc, 2f
+	 mov		TLB_TAG_ACCESS, %g2
+	stxa		%g0, [%g2] ASI_IMMU
+	stxa		%g0, [%g1] ASI_ITLB_DATA_ACCESS
+	membar		#Sync
+2:	ldxa		[%g1] ASI_DTLB_DATA_ACCESS, %g2
+	andcc		%g2, 0x40, %g0
+	bne,pn		%xcc, 2f
+	 mov		TLB_TAG_ACCESS, %g2
+	stxa		%g0, [%g2] ASI_DMMU
+	stxa		%g0, [%g1] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
+2:	sub		%g1, 8, %g1
+	brgez,pt	%g1, 1b
+	 nop
+	retry
 	nop
 	nop
 	nop
@@ -637,6 +742,52 @@
 
 	retry
 
+__cheetah_xcall_flush_tlb_kernel_range:	/* 44 insns */
+	sethi		%hi(PAGE_SIZE - 1), %g2
+	or		%g2, %lo(PAGE_SIZE - 1), %g2
+	andn		%g1, %g2, %g1
+	andn		%g7, %g2, %g7
+	sub		%g7, %g1, %g3
+	srlx		%g3, 18, %g2
+	brnz,pn		%g2, 2f
+	 sethi		%hi(PAGE_SIZE), %g2
+	sub		%g3, %g2, %g3
+	or		%g1, 0x20, %g1		! Nucleus
+1:	stxa		%g0, [%g1 + %g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g1 + %g3] ASI_IMMU_DEMAP
+	membar		#Sync
+	brnz,pt		%g3, 1b
+	 sub		%g3, %g2, %g3
+	retry
+2:	mov		0x80, %g2
+	stxa		%g0, [%g2] ASI_DMMU_DEMAP
+	membar		#Sync
+	stxa		%g0, [%g2] ASI_IMMU_DEMAP
+	membar		#Sync
+	retry
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 #ifdef DCACHE_ALIASING_POSSIBLE
 	.align		32
 	.globl		xcall_flush_dcache_page_cheetah
@@ -700,7 +851,7 @@
 	ba,a,pt	%xcc, rtrap
 
 	.globl		__hypervisor_xcall_flush_tlb_mm
-__hypervisor_xcall_flush_tlb_mm: /* 21 insns */
+__hypervisor_xcall_flush_tlb_mm: /* 24 insns */
 	/* %g5=ctx, g1,g2,g3,g4,g7=scratch, %g6=unusable */
 	mov		%o0, %g2
 	mov		%o1, %g3
@@ -714,7 +865,7 @@
 	mov		HV_FAST_MMU_DEMAP_CTX, %o5
 	ta		HV_FAST_TRAP
 	mov		HV_FAST_MMU_DEMAP_CTX, %g6
-	brnz,pn		%o0, __hypervisor_tlb_xcall_error
+	brnz,pn		%o0, 1f
 	 mov		%o0, %g5
 	mov		%g2, %o0
 	mov		%g3, %o1
@@ -723,9 +874,12 @@
 	mov		%g7, %o5
 	membar		#Sync
 	retry
+1:	sethi		%hi(__hypervisor_tlb_xcall_error), %g4
+	jmpl		%g4 + %lo(__hypervisor_tlb_xcall_error), %g0
+	 nop
 
 	.globl		__hypervisor_xcall_flush_tlb_page
-__hypervisor_xcall_flush_tlb_page: /* 17 insns */
+__hypervisor_xcall_flush_tlb_page: /* 20 insns */
 	/* %g5=ctx, %g1=vaddr */
 	mov		%o0, %g2
 	mov		%o1, %g3
@@ -737,42 +891,64 @@
 	sllx		%o0, PAGE_SHIFT, %o0
 	ta		HV_MMU_UNMAP_ADDR_TRAP
 	mov		HV_MMU_UNMAP_ADDR_TRAP, %g6
-	brnz,a,pn	%o0, __hypervisor_tlb_xcall_error
+	brnz,a,pn	%o0, 1f
 	 mov		%o0, %g5
 	mov		%g2, %o0
 	mov		%g3, %o1
 	mov		%g4, %o2
 	membar		#Sync
 	retry
+1:	sethi		%hi(__hypervisor_tlb_xcall_error), %g4
+	jmpl		%g4 + %lo(__hypervisor_tlb_xcall_error), %g0
+	 nop
 
 	.globl		__hypervisor_xcall_flush_tlb_kernel_range
-__hypervisor_xcall_flush_tlb_kernel_range: /* 25 insns */
+__hypervisor_xcall_flush_tlb_kernel_range: /* 44 insns */
 	/* %g1=start, %g7=end, g2,g3,g4,g5,g6=scratch */
 	sethi		%hi(PAGE_SIZE - 1), %g2
 	or		%g2, %lo(PAGE_SIZE - 1), %g2
 	andn		%g1, %g2, %g1
 	andn		%g7, %g2, %g7
 	sub		%g7, %g1, %g3
+	srlx		%g3, 18, %g7
 	add		%g2, 1, %g2
 	sub		%g3, %g2, %g3
 	mov		%o0, %g2
 	mov		%o1, %g4
-	mov		%o2, %g7
+	brnz,pn		%g7, 2f
+	 mov		%o2, %g7
 1:	add		%g1, %g3, %o0	/* ARG0: virtual address */
 	mov		0, %o1		/* ARG1: mmu context */
 	mov		HV_MMU_ALL, %o2	/* ARG2: flags */
 	ta		HV_MMU_UNMAP_ADDR_TRAP
 	mov		HV_MMU_UNMAP_ADDR_TRAP, %g6
-	brnz,pn		%o0, __hypervisor_tlb_xcall_error
+	brnz,pn		%o0, 1f
 	 mov		%o0, %g5
 	sethi		%hi(PAGE_SIZE), %o2
 	brnz,pt		%g3, 1b
 	 sub		%g3, %o2, %g3
-	mov		%g2, %o0
+5:	mov		%g2, %o0
 	mov		%g4, %o1
 	mov		%g7, %o2
 	membar		#Sync
 	retry
+1:	sethi		%hi(__hypervisor_tlb_xcall_error), %g4
+	jmpl		%g4 + %lo(__hypervisor_tlb_xcall_error), %g0
+	 nop
+2:	mov		%o3, %g1
+	mov		%o5, %g3
+	mov		0, %o0		/* ARG0: CPU lists unimplemented */
+	mov		0, %o1		/* ARG1: CPU lists unimplemented */
+	mov		0, %o2		/* ARG2: mmu context == nucleus */
+	mov		HV_MMU_ALL, %o3	/* ARG3: flags */
+	mov		HV_FAST_MMU_DEMAP_CTX, %o5
+	ta		HV_FAST_TRAP
+	mov		%g1, %o3
+	brz,pt		%o0, 5b
+	 mov		%g3, %o5
+	mov		HV_FAST_MMU_DEMAP_CTX, %g6
+	ba,pt		%xcc, 1b
+	 clr		%g5
 
 	/* These just get rescheduled to PIL vectors. */
 	.globl		xcall_call_function
@@ -795,11 +971,6 @@
 	wr		%g0, (1 << PIL_SMP_CAPTURE), %set_softint
 	retry
 
-	.globl		xcall_new_mmu_context_version
-xcall_new_mmu_context_version:
-	wr		%g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint
-	retry
-
 #ifdef CONFIG_KGDB
 	.globl		xcall_kgdb_capture
 xcall_kgdb_capture:
@@ -809,6 +980,58 @@
 
 #endif /* CONFIG_SMP */
 
+	.globl		cheetah_patch_cachetlbops
+cheetah_patch_cachetlbops:
+	save		%sp, -128, %sp
+
+	sethi		%hi(__flush_tlb_mm), %o0
+	or		%o0, %lo(__flush_tlb_mm), %o0
+	sethi		%hi(__cheetah_flush_tlb_mm), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_mm), %o1
+	call		tlb_patch_one
+	 mov		19, %o2
+
+	sethi		%hi(__flush_tlb_page), %o0
+	or		%o0, %lo(__flush_tlb_page), %o0
+	sethi		%hi(__cheetah_flush_tlb_page), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_page), %o1
+	call		tlb_patch_one
+	 mov		22, %o2
+
+	sethi		%hi(__flush_tlb_pending), %o0
+	or		%o0, %lo(__flush_tlb_pending), %o0
+	sethi		%hi(__cheetah_flush_tlb_pending), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_pending), %o1
+	call		tlb_patch_one
+	 mov		27, %o2
+
+	sethi		%hi(__flush_tlb_kernel_range), %o0
+	or		%o0, %lo(__flush_tlb_kernel_range), %o0
+	sethi		%hi(__cheetah_flush_tlb_kernel_range), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_kernel_range), %o1
+	call		tlb_patch_one
+	 mov		31, %o2
+
+#ifdef DCACHE_ALIASING_POSSIBLE
+	sethi		%hi(__flush_dcache_page), %o0
+	or		%o0, %lo(__flush_dcache_page), %o0
+	sethi		%hi(__cheetah_flush_dcache_page), %o1
+	or		%o1, %lo(__cheetah_flush_dcache_page), %o1
+	call		tlb_patch_one
+	 mov		11, %o2
+#endif /* DCACHE_ALIASING_POSSIBLE */
+
+#ifdef CONFIG_SMP
+	sethi		%hi(xcall_flush_tlb_kernel_range), %o0
+	or		%o0, %lo(xcall_flush_tlb_kernel_range), %o0
+	sethi		%hi(__cheetah_xcall_flush_tlb_kernel_range), %o1
+	or		%o1, %lo(__cheetah_xcall_flush_tlb_kernel_range), %o1
+	call		tlb_patch_one
+	 mov		44, %o2
+#endif /* CONFIG_SMP */
+
+	ret
+	 restore
 
 	.globl		hypervisor_patch_cachetlbops
 hypervisor_patch_cachetlbops:
@@ -819,28 +1042,28 @@
 	sethi		%hi(__hypervisor_flush_tlb_mm), %o1
 	or		%o1, %lo(__hypervisor_flush_tlb_mm), %o1
 	call		tlb_patch_one
-	 mov		10, %o2
+	 mov		19, %o2
 
 	sethi		%hi(__flush_tlb_page), %o0
 	or		%o0, %lo(__flush_tlb_page), %o0
 	sethi		%hi(__hypervisor_flush_tlb_page), %o1
 	or		%o1, %lo(__hypervisor_flush_tlb_page), %o1
 	call		tlb_patch_one
-	 mov		11, %o2
+	 mov		22, %o2
 
 	sethi		%hi(__flush_tlb_pending), %o0
 	or		%o0, %lo(__flush_tlb_pending), %o0
 	sethi		%hi(__hypervisor_flush_tlb_pending), %o1
 	or		%o1, %lo(__hypervisor_flush_tlb_pending), %o1
 	call		tlb_patch_one
-	 mov		16, %o2
+	 mov		27, %o2
 
 	sethi		%hi(__flush_tlb_kernel_range), %o0
 	or		%o0, %lo(__flush_tlb_kernel_range), %o0
 	sethi		%hi(__hypervisor_flush_tlb_kernel_range), %o1
 	or		%o1, %lo(__hypervisor_flush_tlb_kernel_range), %o1
 	call		tlb_patch_one
-	 mov		16, %o2
+	 mov		31, %o2
 
 #ifdef DCACHE_ALIASING_POSSIBLE
 	sethi		%hi(__flush_dcache_page), %o0
@@ -857,21 +1080,21 @@
 	sethi		%hi(__hypervisor_xcall_flush_tlb_mm), %o1
 	or		%o1, %lo(__hypervisor_xcall_flush_tlb_mm), %o1
 	call		tlb_patch_one
-	 mov		21, %o2
+	 mov		24, %o2
 
 	sethi		%hi(xcall_flush_tlb_page), %o0
 	or		%o0, %lo(xcall_flush_tlb_page), %o0
 	sethi		%hi(__hypervisor_xcall_flush_tlb_page), %o1
 	or		%o1, %lo(__hypervisor_xcall_flush_tlb_page), %o1
 	call		tlb_patch_one
-	 mov		17, %o2
+	 mov		20, %o2
 
 	sethi		%hi(xcall_flush_tlb_kernel_range), %o0
 	or		%o0, %lo(xcall_flush_tlb_kernel_range), %o0
 	sethi		%hi(__hypervisor_xcall_flush_tlb_kernel_range), %o1
 	or		%o1, %lo(__hypervisor_xcall_flush_tlb_kernel_range), %o1
 	call		tlb_patch_one
-	 mov		25, %o2
+	 mov		44, %o2
 #endif /* CONFIG_SMP */
 
 	ret
--- linux-4.4.0.orig/arch/sparc/power/hibernate.c
+++ linux-4.4.0/arch/sparc/power/hibernate.c
@@ -35,6 +35,5 @@
 {
 	struct mm_struct *mm = current->active_mm;
 
-	load_secondary_context(mm);
-	tsb_context_switch(mm);
+	tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
 }
--- linux-4.4.0.orig/arch/tile/include/asm/elf.h
+++ linux-4.4.0/arch/tile/include/asm/elf.h
@@ -129,6 +129,7 @@
 struct linux_binprm;
 extern int arch_setup_additional_pages(struct linux_binprm *bprm,
 				       int executable_stack);
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
 #define ARCH_DLINFO \
 do { \
 	NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \
--- linux-4.4.0.orig/arch/tile/include/asm/futex.h
+++ linux-4.4.0/arch/tile/include/asm/futex.h
@@ -106,12 +106,9 @@
 	lock = __atomic_hashed_lock((int __force *)uaddr)
 #endif
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int uninitialized_var(val), ret;
 
 	__futex_prolog();
@@ -119,12 +116,6 @@
 	/* The 32-bit futex code makes this assumption, so validate it here. */
 	BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 	switch (op) {
 	case FUTEX_OP_SET:
@@ -148,30 +139,9 @@
 	}
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (val == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (val != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (val < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (val >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (val <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (val > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = val;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/tile/include/uapi/asm/auxvec.h
+++ linux-4.4.0/arch/tile/include/uapi/asm/auxvec.h
@@ -18,4 +18,6 @@
 /* The vDSO location. */
 #define AT_SYSINFO_EHDR         33
 
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
 #endif /* _ASM_TILE_AUXVEC_H */
--- linux-4.4.0.orig/arch/tile/kernel/ptrace.c
+++ linux-4.4.0/arch/tile/kernel/ptrace.c
@@ -111,7 +111,7 @@
 			  const void *kbuf, const void __user *ubuf)
 {
 	int ret;
-	struct pt_regs regs;
+	struct pt_regs regs = *task_pt_regs(target);
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &regs, 0,
 				 sizeof(regs));
--- linux-4.4.0.orig/arch/tile/kernel/time.c
+++ linux-4.4.0/arch/tile/kernel/time.c
@@ -218,8 +218,8 @@
  */
 unsigned long long sched_clock(void)
 {
-	return clocksource_cyc2ns(get_cycles(),
-				  sched_clock_mult, SCHED_CLOCK_SHIFT);
+	return mult_frac(get_cycles(),
+			 sched_clock_mult, 1ULL << SCHED_CLOCK_SHIFT);
 }
 
 int setup_profiling_timer(unsigned int multiplier)
--- linux-4.4.0.orig/arch/tile/lib/atomic_asm_32.S
+++ linux-4.4.0/arch/tile/lib/atomic_asm_32.S
@@ -24,8 +24,7 @@
  * has an opportunity to return -EFAULT to the user if needed.
  * The 64-bit routines just return a "long long" with the value,
  * since they are only used from kernel space and don't expect to fault.
- * Support for 16-bit ops is included in the framework but we don't provide
- * any (x86_64 has an atomic_inc_short(), so we might want to some day).
+ * Support for 16-bit ops is included in the framework but we don't provide any.
  *
  * Note that the caller is advised to issue a suitable L1 or L2
  * prefetch on the address being manipulated to avoid extra stalls.
--- linux-4.4.0.orig/arch/tile/mm/hugetlbpage.c
+++ linux-4.4.0/arch/tile/mm/hugetlbpage.c
@@ -232,7 +232,7 @@
 		addr = ALIGN(addr, huge_page_size(h));
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 	if (current->mm->get_unmapped_area == arch_get_unmapped_area)
--- linux-4.4.0.orig/arch/um/Kconfig.common
+++ linux-4.4.0/arch/um/Kconfig.common
@@ -1,6 +1,7 @@
 config UML
 	bool
 	default y
+	select ARCH_HAS_CPU_FINALIZE_INIT
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_UID16
 	select HAVE_FUTEX_CMPXCHG if FUTEX
--- linux-4.4.0.orig/arch/um/Kconfig.debug
+++ linux-4.4.0/arch/um/Kconfig.debug
@@ -18,6 +18,7 @@
 config GCOV
 	bool "Enable gcov support"
 	depends on DEBUG_INFO
+	depends on !KCOV
 	help
 	  This option allows developers to retrieve coverage data from a UML
 	  session.
--- linux-4.4.0.orig/arch/um/Makefile
+++ linux-4.4.0/arch/um/Makefile
@@ -59,10 +59,14 @@
 # Same things for in6addr_loopback and mktime - found in libc. For these two we
 # only get link-time error, luckily.
 #
+# -Dlongjmp=kernel_longjmp prevents anything from referencing the libpthread.a
+# embedded copy of longjmp, same thing for setjmp.
+#
 # These apply to USER_CFLAGS to.
 
 KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \
 	$(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap	\
+	-Dlongjmp=kernel_longjmp -Dsetjmp=kernel_setjmp \
 	-Din6addr_loopback=kernel_in6addr_loopback \
 	-Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr
 
@@ -117,7 +121,7 @@
 archprepare: include/generated/user_constants.h
 
 LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
-LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib
+LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib $(call cc-option, -no-pie)
 
 CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \
 	$(call cc-option, -fno-stack-protector,) \
--- linux-4.4.0.orig/arch/um/drivers/line.c
+++ linux-4.4.0/arch/um/drivers/line.c
@@ -260,7 +260,7 @@
 	if (err == 0) {
 		spin_unlock(&line->lock);
 		return IRQ_NONE;
-	} else if (err < 0) {
+	} else if ((err < 0) && (err != -EAGAIN)) {
 		line->head = line->buffer;
 		line->tail = line->buffer;
 	}
@@ -682,24 +682,26 @@
 		goto cleanup;
 	}
 
-	*winch = ((struct winch) { .list  	= LIST_HEAD_INIT(winch->list),
-				   .fd  	= fd,
+	*winch = ((struct winch) { .fd  	= fd,
 				   .tty_fd 	= tty_fd,
 				   .pid  	= pid,
 				   .port 	= port,
 				   .stack	= stack });
 
+	spin_lock(&winch_handler_lock);
+	list_add(&winch->list, &winch_handlers);
+	spin_unlock(&winch_handler_lock);
+
 	if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
 			   IRQF_SHARED, "winch", winch) < 0) {
 		printk(KERN_ERR "register_winch_irq - failed to register "
 		       "IRQ\n");
+		spin_lock(&winch_handler_lock);
+		list_del(&winch->list);
+		spin_unlock(&winch_handler_lock);
 		goto out_free;
 	}
 
-	spin_lock(&winch_handler_lock);
-	list_add(&winch->list, &winch_handlers);
-	spin_unlock(&winch_handler_lock);
-
 	return;
 
  out_free:
--- linux-4.4.0.orig/arch/um/drivers/mconsole_kern.c
+++ linux-4.4.0/arch/um/drivers/mconsole_kern.c
@@ -133,7 +133,7 @@
 	ptr += strlen("proc");
 	ptr = skip_spaces(ptr);
 
-	file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY);
+	file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY, 0);
 	if (IS_ERR(file)) {
 		mconsole_reply(req, "Failed to open file", 1, 0);
 		printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file));
--- linux-4.4.0.orig/arch/um/drivers/xterm.c
+++ linux-4.4.0/arch/um/drivers/xterm.c
@@ -18,6 +18,7 @@
 struct xterm_chan {
 	int pid;
 	int helper_pid;
+	int chan_fd;
 	char *title;
 	int device;
 	int raw;
@@ -33,6 +34,7 @@
 		return NULL;
 	*data = ((struct xterm_chan) { .pid 		= -1,
 				       .helper_pid 	= -1,
+				       .chan_fd		= -1,
 				       .device 		= device,
 				       .title 		= opts->xterm_title,
 				       .raw  		= opts->raw } );
@@ -149,6 +151,7 @@
 		goto out_kill;
 	}
 
+	data->chan_fd = fd;
 	new = xterm_fd(fd, &data->helper_pid);
 	if (new < 0) {
 		err = new;
@@ -206,6 +209,8 @@
 		os_kill_process(data->helper_pid, 0);
 	data->helper_pid = -1;
 
+	if (data->chan_fd != -1)
+		os_close_file(data->chan_fd);
 	os_close_file(fd);
 }
 
--- linux-4.4.0.orig/arch/um/include/asm/common.lds.S
+++ linux-4.4.0/arch/um/include/asm/common.lds.S
@@ -81,7 +81,7 @@
   .altinstr_replacement : { *(.altinstr_replacement) }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
-  .exit.text : { *(.exit.text) }
+  .exit.text : { EXIT_TEXT }
   .exit.data : { *(.exit.data) }
 
   .preinit_array : {
--- linux-4.4.0.orig/arch/um/include/asm/mmu_context.h
+++ linux-4.4.0/arch/um/include/asm/mmu_context.h
@@ -42,7 +42,7 @@
 	 * when the new ->mm is used for the first time.
 	 */
 	__switch_mm(&new->context.id);
-	down_write(&new->mmap_sem);
+	down_write_nested(&new->mmap_sem, 1);
 	uml_setup_stubs(new);
 	up_write(&new->mmap_sem);
 }
--- linux-4.4.0.orig/arch/um/include/asm/pgtable.h
+++ linux-4.4.0/arch/um/include/asm/pgtable.h
@@ -197,12 +197,17 @@
 
 static inline pte_t pte_wrprotect(pte_t pte)
 { 
-	pte_clear_bits(pte, _PAGE_RW);
+	if (likely(pte_get_bits(pte, _PAGE_RW)))
+		pte_clear_bits(pte, _PAGE_RW);
+	else
+		return pte;
 	return(pte_mknewprot(pte)); 
 }
 
 static inline pte_t pte_mkread(pte_t pte)
 { 
+	if (unlikely(pte_get_bits(pte, _PAGE_USER)))
+		return pte;
 	pte_set_bits(pte, _PAGE_USER);
 	return(pte_mknewprot(pte)); 
 }
@@ -221,6 +226,8 @@
 
 static inline pte_t pte_mkwrite(pte_t pte)	
 {
+	if (unlikely(pte_get_bits(pte,  _PAGE_RW)))
+		return pte;
 	pte_set_bits(pte, _PAGE_RW);
 	return(pte_mknewprot(pte)); 
 }
--- linux-4.4.0.orig/arch/um/include/asm/tlb.h
+++ linux-4.4.0/arch/um/include/asm/tlb.h
@@ -110,6 +110,18 @@
 	__tlb_remove_page(tlb, page);
 }
 
+static inline void
+tlb_flush_pmd_range(struct mmu_gather *tlb, unsigned long address,
+		    unsigned long size)
+{
+	tlb->need_flush = 1;
+
+	if (tlb->start > address)
+		tlb->start = address;
+	if (tlb->end < address + size)
+		tlb->end = address + size;
+}
+
 /**
  * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation.
  *
--- linux-4.4.0.orig/arch/um/kernel/sigio.c
+++ linux-4.4.0/arch/um/kernel/sigio.c
@@ -36,14 +36,14 @@
 }
 
 /* These are called from os-Linux/sigio.c to protect its pollfds arrays. */
-static DEFINE_SPINLOCK(sigio_spinlock);
+static DEFINE_MUTEX(sigio_mutex);
 
 void sigio_lock(void)
 {
-	spin_lock(&sigio_spinlock);
+	mutex_lock(&sigio_mutex);
 }
 
 void sigio_unlock(void)
 {
-	spin_unlock(&sigio_spinlock);
+	mutex_unlock(&sigio_mutex);
 }
--- linux-4.4.0.orig/arch/um/kernel/time.c
+++ linux-4.4.0/arch/um/kernel/time.c
@@ -96,7 +96,7 @@
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init timer_setup(void)
+static void __init um_timer_setup(void)
 {
 	int err;
 
@@ -130,5 +130,5 @@
 void __init time_init(void)
 {
 	timer_set_signal_handler();
-	late_time_init = timer_setup;
+	late_time_init = um_timer_setup;
 }
--- linux-4.4.0.orig/arch/um/kernel/um_arch.c
+++ linux-4.4.0/arch/um/kernel/um_arch.c
@@ -3,6 +3,7 @@
  * Licensed under the GPL
  */
 
+#include <linux/cpu.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/mm.h>
@@ -348,7 +349,7 @@
 	setup_hostinfo(host_info, sizeof host_info);
 }
 
-void __init check_bugs(void)
+void __init arch_cpu_finalize_init(void)
 {
 	arch_check_bugs();
 	os_check_bugs();
--- linux-4.4.0.orig/arch/um/os-Linux/file.c
+++ linux-4.4.0/arch/um/os-Linux/file.c
@@ -12,6 +12,7 @@
 #include <sys/mount.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/un.h>
 #include <sys/types.h>
 #include <os.h>
--- linux-4.4.0.orig/arch/um/os-Linux/signal.c
+++ linux-4.4.0/arch/um/os-Linux/signal.c
@@ -14,7 +14,9 @@
 #include <as-layout.h>
 #include <kern_util.h>
 #include <os.h>
+#include <sys/ucontext.h>
 #include <sysdep/mcontext.h>
+#include <um_malloc.h>
 
 void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
 	[SIGTRAP]	= relay_signal,
@@ -140,7 +142,7 @@
 
 static void hard_handler(int sig, siginfo_t *si, void *p)
 {
-	struct ucontext *uc = p;
+	ucontext_t *uc = p;
 	mcontext_t *mc = &uc->uc_mcontext;
 	unsigned long pending = 1UL << sig;
 
--- linux-4.4.0.orig/arch/um/os-Linux/skas/process.c
+++ linux-4.4.0/arch/um/os-Linux/skas/process.c
@@ -585,6 +585,11 @@
 		fatal_sigsegv();
 	}
 	longjmp(*switch_buf, 1);
+
+	/* unreachable */
+	printk(UM_KERN_ERR "impossible long jump!");
+	fatal_sigsegv();
+	return 0;
 }
 
 void initial_thread_cb_skas(void (*proc)(void *), void *arg)
--- linux-4.4.0.orig/arch/um/os-Linux/start_up.c
+++ linux-4.4.0/arch/um/os-Linux/start_up.c
@@ -94,6 +94,8 @@
 {
 	int pid, n, status;
 
+	fflush(stdout);
+
 	pid = fork();
 	if (pid == 0)
 		ptrace_child();
--- linux-4.4.0.orig/arch/x86/Kbuild
+++ linux-4.4.0/arch/x86/Kbuild
@@ -1,6 +1,7 @@
-
 obj-y += entry/
 
+obj-$(CONFIG_PERF_EVENTS) += events/
+
 obj-$(CONFIG_KVM) += kvm/
 
 # Xen paravirtualization support
--- linux-4.4.0.orig/arch/x86/Kconfig
+++ linux-4.4.0/arch/x86/Kconfig
@@ -24,6 +24,7 @@
 	select ARCH_DISCARD_MEMBLOCK
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 	select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_HAS_ELF_RANDOMIZE
 	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_GCOV_PROFILE_ALL
@@ -41,8 +42,7 @@
 	select ARCH_USE_BUILTIN_BSWAP
 	select ARCH_USE_CMPXCHG_LOCKREF		if X86_64
 	select ARCH_USE_QUEUED_RWLOCKS
-	select ARCH_USE_QUEUED_SPINLOCKS
-	select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if SMP
+	select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
 	select ARCH_WANTS_DYNAMIC_TASK_STRUCT
 	select ARCH_WANT_FRAME_POINTERS
 	select ARCH_WANT_IPC_PARSE_VERSION	if X86_32
@@ -62,6 +62,7 @@
 	select GENERIC_CLOCKEVENTS_MIN_ADJUST
 	select GENERIC_CMOS_UPDATE
 	select GENERIC_CPU_AUTOPROBE
+	select GENERIC_CPU_VULNERABILITIES
 	select GENERIC_EARLY_IOREMAP
 	select GENERIC_FIND_FIRST_BIT
 	select GENERIC_IOMAP
@@ -87,6 +88,7 @@
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
 	select HAVE_BPF_JIT			if X86_64
+	select HAVE_EBPF_JIT			if X86_64
 	select HAVE_CC_STACKPROTECTOR
 	select HAVE_CMPXCHG_DOUBLE
 	select HAVE_CMPXCHG_LOCAL
@@ -138,6 +140,7 @@
 	select HAVE_UID16			if X86_32 || IA32_EMULATION
 	select HAVE_UNSTABLE_SCHED_CLOCK
 	select HAVE_USER_RETURN_NOTIFIER
+	select HOTPLUG_SMT			if SMP
 	select IRQ_FORCED_THREADING
 	select MODULES_USE_ELF_RELA		if X86_64
 	select MODULES_USE_ELF_REL		if X86_32
@@ -278,11 +281,6 @@
 	def_bool y
 	depends on X86_32 && !CC_STACKPROTECTOR
 
-config ARCH_HWEIGHT_CFLAGS
-	string
-	default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
-	default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
-
 config ARCH_SUPPORTS_UPROBES
 	def_bool y
 
@@ -349,6 +347,17 @@
 
 	  If in doubt, say Y.
 
+config X86_FAST_FEATURE_TESTS
+	bool "Fast CPU feature tests" if EMBEDDED
+	default y
+	---help---
+	  Some fast-paths in the kernel depend on the capabilities of the CPU.
+	  Say Y here for the kernel to patch in the appropriate code at runtime
+	  based on the capabilities of the CPU. The infrastructure for patching
+	  code at runtime takes up some additional space; space-constrained
+	  embedded systems may wish to say N here to produce smaller, slightly
+	  slower code.
+
 config X86_X2APIC
 	bool "Support x2apic"
 	depends on X86_LOCAL_APIC && X86_64 && (IRQ_REMAP || HYPERVISOR_GUEST)
@@ -378,6 +387,19 @@
        def_bool y
        depends on X86_GOLDFISH
 
+config RETPOLINE
+	bool "Avoid speculative indirect branches in kernel"
+	default y
+	---help---
+	  Compile kernel with the retpoline compiler options to guard against
+	  kernel-to-user data leaks by avoiding speculative indirect
+	  branches. Requires a compiler with -mindirect-branch=thunk-extern
+	  support for full protection. The kernel may run slower.
+
+	  Without compiler support, at least indirect branches in assembler
+	  code are eliminated. Since this includes the syscall entry path,
+	  it is not entirely pointless.
+
 if X86_32
 config X86_EXTENDED_PLATFORM
 	bool "Support for extended (non-PC) x86 platforms"
@@ -523,9 +545,10 @@
 
 config X86_INTEL_LPSS
 	bool "Intel Low Power Subsystem Support"
-	depends on ACPI
+	depends on X86 && ACPI
 	select COMMON_CLK
 	select PINCTRL
+	select IOSF_MBI
 	---help---
 	  Select to build support for Intel Low Power Subsystem such as
 	  found on Intel Lynxpoint PCH. Selecting this option enables
@@ -873,13 +896,7 @@
 	  approximately eight kilobytes to the kernel image.
 
 config SCHED_SMT
-	bool "SMT (Hyperthreading) scheduler support"
-	depends on SMP
-	---help---
-	  SMT scheduler support improves the CPU scheduler's decision making
-	  when dealing with Intel Pentium 4 chips with HyperThreading at a
-	  cost of slightly increased overhead in some places. If unsure say
-	  N here.
+	def_bool y if SMP
 
 config SCHED_MC
 	def_bool y
@@ -994,7 +1011,7 @@
 	def_bool y
 
 config X86_MCE_INJECT
-	depends on X86_MCE
+	depends on X86_MCE && X86_LOCAL_APIC
 	tristate "Machine check injector support"
 	---help---
 	  Provide support for injecting machine checks for testing purposes.
@@ -1126,22 +1143,23 @@
 	bool "CPU microcode loading support"
 	default y
 	depends on CPU_SUP_AMD || CPU_SUP_INTEL
-	depends on BLK_DEV_INITRD
 	select FW_LOADER
 	---help---
-
 	  If you say Y here, you will be able to update the microcode on
-	  certain Intel and AMD processors. The Intel support is for the
-	  IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4,
-	  Xeon etc. The AMD support is for families 0x10 and later. You will
-	  obviously need the actual microcode binary data itself which is not
-	  shipped with the Linux kernel.
-
-	  This option selects the general module only, you need to select
-	  at least one vendor specific module as well.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called microcode.
+	  Intel and AMD processors. The Intel support is for the IA32 family,
+	  e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4, Xeon etc. The
+	  AMD support is for families 0x10 and later. You will obviously need
+	  the actual microcode binary data itself which is not shipped with
+	  the Linux kernel.
+
+	  The preferred method to load microcode from a detached initrd is described
+	  in Documentation/x86/early-microcode.txt. For that you need to enable
+	  CONFIG_BLK_DEV_INITRD in order for the loader to be able to scan the
+	  initrd for microcode blobs.
+
+	  In addition, you can build-in the microcode into the kernel. For that you
+	  need to enable FIRMWARE_IN_KERNEL and add the vendor-supplied microcode
+	  to the CONFIG_EXTRA_FIRMWARE config option.
 
 config MICROCODE_INTEL
 	bool "Intel microcode loading support"
@@ -1680,6 +1698,51 @@
 
 	  If unsure, say N.
 
+choice
+	prompt "TSX enable mode"
+	depends on CPU_SUP_INTEL
+	default X86_INTEL_TSX_MODE_OFF
+	help
+	  Intel's TSX (Transactional Synchronization Extensions) feature
+	  allows to optimize locking protocols through lock elision which
+	  can lead to a noticeable performance boost.
+
+	  On the other hand it has been shown that TSX can be exploited
+	  to form side channel attacks (e.g. TAA) and chances are there
+	  will be more of those attacks discovered in the future.
+
+	  Therefore TSX is not enabled by default (aka tsx=off). An admin
+	  might override this decision by tsx=on the command line parameter.
+	  Even with TSX enabled, the kernel will attempt to enable the best
+	  possible TAA mitigation setting depending on the microcode available
+	  for the particular machine.
+
+	  This option allows to set the default tsx mode between tsx=on, =off
+	  and =auto. See Documentation/admin-guide/kernel-parameters.txt for more
+	  details.
+
+	  Say off if not sure, auto if TSX is in use but it should be used on safe
+	  platforms or on if TSX is in use and the security aspect of tsx is not
+	  relevant.
+
+config X86_INTEL_TSX_MODE_OFF
+	bool "off"
+	help
+	  TSX is disabled if possible - equals to tsx=off command line parameter.
+
+config X86_INTEL_TSX_MODE_ON
+	bool "on"
+	help
+	  TSX is always enabled on TSX capable HW - equals the tsx=on command
+	  line parameter.
+
+config X86_INTEL_TSX_MODE_AUTO
+	bool "auto"
+	help
+	  TSX is enabled on TSX capable HW that is believed to be safe against
+	  side channel attacks- equals the tsx=auto command line parameter.
+endchoice
+
 config EFI
 	bool "EFI runtime service support"
 	depends on ACPI
@@ -1720,6 +1783,17 @@
 
 	   If unsure, say N.
 
+config EFI_SECURE_BOOT_SIG_ENFORCE
+	def_bool n
+	depends on EFI
+	prompt "Force module signing when UEFI Secure Boot is enabled"
+	---help---
+	  UEFI Secure Boot provides a mechanism for ensuring that the
+	  firmware will only load signed bootloaders and kernels. Certain
+	  use cases may also require that all kernel modules also be signed.
+	  Say Y here to automatically enable module signature enforcement
+	  when a system boots with UEFI Secure Boot enabled.
+
 config SECCOMP
 	def_bool y
 	prompt "Enable seccomp to safely compute untrusted bytecode"
@@ -1949,14 +2023,8 @@
 	  Don't change this unless you know what you are doing.
 
 config HOTPLUG_CPU
-	bool "Support for hot-pluggable CPUs"
+	def_bool y
 	depends on SMP
-	---help---
-	  Say Y here to allow turning CPUs off and on. CPUs can be
-	  controlled through /sys/devices/system/cpu.
-	  ( Note: power management support will enable this option
-	    automatically on SMP systems. )
-	  Say N if you want to disable CPU hotplug.
 
 config BOOTPARAM_HOTPLUG_CPU0
 	bool "Set default setting of cpu0_hotpluggable"
@@ -2135,6 +2203,15 @@
 
 	  Saying 'N' here may make sense for embedded or server kernels.
 
+config MITIGATION_VMSCAPE
+	bool "Mitigate VMSCAPE"
+	depends on KVM
+	default y
+	---help---
+	  Enable mitigation for VMSCAPE attacks. VMSCAPE is a hardware security
+	  vulnerability on Intel and AMD CPUs that may allow a guest to do
+	  Spectre v2 style attacks on userspace hypervisors.
+
 source "kernel/livepatch/Kconfig"
 
 endmenu
@@ -2159,6 +2236,31 @@
 	def_bool y
 	depends on X86_64 && HUGETLB_PAGE && MIGRATION
 
+choice
+	prompt "Clear branch history"
+	depends on CPU_SUP_INTEL
+	default SPECTRE_BHI_AUTO
+	help
+	  Enable BHI mitigations. BHI attacks are a form of Spectre V2 attacks
+	  where the branch history buffer is poisoned to speculatively steer
+	  indirect branches.
+	  See <file:Documentation/admin-guide/hw-vuln/spectre.rst>
+
+config SPECTRE_BHI_ON
+	bool "on"
+	help
+	  Equivalent to setting spectre_bhi=on command line parameter.
+config SPECTRE_BHI_OFF
+	bool "off"
+	help
+	  Equivalent to setting spectre_bhi=off command line parameter.
+config SPECTRE_BHI_AUTO
+	bool "auto"
+	help
+	  Equivalent to setting spectre_bhi=auto command line parameter.
+
+endchoice
+
 menu "Power management and ACPI options"
 
 config ARCH_HIBERNATION_HEADER
@@ -2472,8 +2574,7 @@
 
 config OLPC_XO1_PM
 	bool "OLPC XO-1 Power Management"
-	depends on OLPC && MFD_CS5535 && PM_SLEEP
-	select MFD_CORE
+	depends on OLPC && MFD_CS5535=y && PM_SLEEP
 	---help---
 	  Add support for poweroff and suspend of the OLPC XO-1 laptop.
 
@@ -2640,10 +2741,6 @@
 config SYSVIPC_COMPAT
 	def_bool y
 	depends on SYSVIPC
-
-config KEYS_COMPAT
-	def_bool y
-	depends on KEYS
 endif
 
 endmenu
@@ -2669,6 +2766,8 @@
 
 source "drivers/Kconfig"
 
+source "ubuntu/Kconfig"
+
 source "drivers/firmware/Kconfig"
 
 source "fs/Kconfig"
--- linux-4.4.0.orig/arch/x86/Kconfig.debug
+++ linux-4.4.0/arch/x86/Kconfig.debug
@@ -221,7 +221,7 @@
 
 config X86_DECODER_SELFTEST
 	bool "x86 instruction decoder selftest"
-	depends on DEBUG_KERNEL && KPROBES
+	depends on DEBUG_KERNEL && INSTRUCTION_DECODER
 	depends on !COMPILE_TEST
 	---help---
 	 Perform x86 instruction decoder selftests at build time.
@@ -367,16 +367,6 @@
 
 	  If unsure say N here.
 
-config X86_DEBUG_STATIC_CPU_HAS
-	bool "Debug alternatives"
-	depends on DEBUG_KERNEL
-	---help---
-	  This option causes additional code to be generated which
-	  fails if static_cpu_has() is used before alternatives have
-	  run.
-
-	  If unsure, say N.
-
 config X86_DEBUG_FPU
 	bool "Debug the x86 FPU code"
 	depends on DEBUG_KERNEL
@@ -391,6 +381,7 @@
 
 config PUNIT_ATOM_DEBUG
 	tristate "ATOM Punit debug driver"
+	depends on PCI
 	select DEBUG_FS
 	select IOSF_MBI
 	---help---
--- linux-4.4.0.orig/arch/x86/Makefile
+++ linux-4.4.0/arch/x86/Makefile
@@ -11,6 +11,16 @@
         KBUILD_DEFCONFIG := $(ARCH)_defconfig
 endif
 
+# For gcc stack alignment is specified with -mpreferred-stack-boundary,
+# clang has the option -mstack-alignment for that purpose.
+ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
+      cc_stack_align4 := -mpreferred-stack-boundary=2
+      cc_stack_align8 := -mpreferred-stack-boundary=3
+else ifneq ($(call cc-option, -mstack-alignment=16),)
+      cc_stack_align4 := -mstack-alignment=4
+      cc_stack_align8 := -mstack-alignment=8
+endif
+
 # How to compile the 16-bit code.  Note we always compile for -march=i386;
 # that way we can complain to the user if the CPU is insufficient.
 #
@@ -24,10 +34,12 @@
 		   -DDISABLE_BRANCH_PROFILING \
 		   -Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
 		   -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
-		   -mno-mmx -mno-sse \
-		   $(call cc-option, -ffreestanding) \
-		   $(call cc-option, -fno-stack-protector) \
-		   $(call cc-option, -mpreferred-stack-boundary=2)
+		   -mno-mmx -mno-sse
+
+REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -ffreestanding)
+REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -fno-stack-protector)
+REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -Wno-address-of-packed-member)
+REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), $(cc_stack_align4))
 export REALMODE_CFLAGS
 
 # BITS is used as extension for files which are available in a 32 bit
@@ -36,7 +48,7 @@
 export BITS
 
 ifdef CONFIG_X86_NEED_RELOCS
-        LDFLAGS_vmlinux := --emit-relocs
+        LDFLAGS_vmlinux := --emit-relocs --discard-none
 endif
 
 #
@@ -49,6 +61,9 @@
 KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow
 KBUILD_CFLAGS += $(call cc-option,-mno-avx,)
 
+# Intel CET isn't enabled in the kernel
+KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
+
 ifeq ($(CONFIG_X86_32),y)
         BITS := 32
         UTS_MACHINE := i386
@@ -64,8 +79,10 @@
         # with nonstandard options
         KBUILD_CFLAGS += -fno-pic
 
-        # prevent gcc from keeping the stack 16 byte aligned
-        KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
+        # Align the stack to the register width instead of using the default
+        # alignment of 16 bytes. This reduces stack usage and the number of
+        # alignment instructions.
+        KBUILD_CFLAGS += $(call cc-option,$(cc_stack_align4))
 
         # Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
         # a lot more stack due to the lack of sharing of stacklots:
@@ -88,17 +105,23 @@
         KBUILD_CFLAGS += -m64
 
         # Align jump targets to 1 byte, not the default 16 bytes:
-        KBUILD_CFLAGS += -falign-jumps=1
+        KBUILD_CFLAGS += $(call cc-option,-falign-jumps=1)
 
         # Pack loops tightly as well:
-        KBUILD_CFLAGS += -falign-loops=1
+        KBUILD_CFLAGS += $(call cc-option,-falign-loops=1)
 
         # Don't autogenerate traditional x87 instructions
         KBUILD_CFLAGS += $(call cc-option,-mno-80387)
         KBUILD_CFLAGS += $(call cc-option,-mno-fp-ret-in-387)
 
-	# Use -mpreferred-stack-boundary=3 if supported.
-	KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
+        # By default gcc and clang use a stack alignment of 16 bytes for x86.
+        # However the standard kernel entry on x86-64 leaves the stack on an
+        # 8-byte boundary. If the compiler isn't informed about the actual
+        # alignment it will generate extra alignment instructions for the
+        # default alignment which keep the stack *mis*aligned.
+        # Furthermore an alignment to the register width reduces stack usage
+        # and the number of alignment instructions.
+        KBUILD_CFLAGS += $(call cc-option,$(cc_stack_align8))
 
 	# Use -mskip-rax-setup if supported.
 	KBUILD_CFLAGS += $(call cc-option,-mskip-rax-setup)
@@ -179,6 +202,15 @@
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
 
+#
+# The 64-bit kernel must be aligned to 2MB.  Pass -z max-page-size=0x200000 to
+# the linker to force 2MB page size regardless of the default page size used
+# by the linker.
+#
+ifdef CONFIG_X86_64
+LDFLAGS += $(call ld-option, -z max-page-size=0x200000)
+endif
+
 # Speed up the build
 KBUILD_CFLAGS += -pipe
 # Workaround for a gcc prelease that unfortunately was shipped in a suse release
@@ -189,6 +221,14 @@
 KBUILD_CFLAGS += $(mflags-y)
 KBUILD_AFLAGS += $(mflags-y)
 
+# Avoid indirect branches in kernel to deal with Spectre
+ifdef CONFIG_RETPOLINE
+    RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register)
+    ifneq ($(RETPOLINE_CFLAGS),)
+        KBUILD_CFLAGS += $(RETPOLINE_CFLAGS) -DRETPOLINE
+    endif
+endif
+
 archscripts: scripts_basic
 	$(Q)$(MAKE) $(build)=arch/x86/tools relocs
 
--- linux-4.4.0.orig/arch/x86/boot/Makefile
+++ linux-4.4.0/arch/x86/boot/Makefile
@@ -64,12 +64,13 @@
 $(obj)/bzImage: asflags-y  := $(SVGA_MODE)
 
 quiet_cmd_image = BUILD   $@
+silent_redirect_image = >/dev/null
 cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
-			       $(obj)/zoffset.h $@
+			       $(obj)/zoffset.h $@ $($(quiet)redirect_image)
 
 $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
 	$(call if_changed,image)
-	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
+	@$(kecho) 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
 $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
@@ -99,7 +100,7 @@
 AFLAGS_header.o += -I$(obj)
 $(obj)/header.o: $(obj)/voffset.h $(obj)/zoffset.h
 
-LDFLAGS_setup.elf	:= -T
+LDFLAGS_setup.elf	:= -m elf_i386 -T
 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
 	$(call if_changed,ld)
 
@@ -162,6 +163,9 @@
 	for i in lib lib64 share end ; do \
 		if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \
 			cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \
+			if [ -f /usr/$$i/syslinux/ldlinux.c32 ]; then \
+				cp /usr/$$i/syslinux/ldlinux.c32 $(obj)/isoimage ; \
+			fi ; \
 			break ; \
 		fi ; \
 		if [ $$i = end ] ; then exit 1 ; fi ; \
--- linux-4.4.0.orig/arch/x86/boot/boot.h
+++ linux-4.4.0/arch/x86/boot/boot.h
@@ -16,7 +16,7 @@
 #ifndef BOOT_BOOT_H
 #define BOOT_BOOT_H
 
-#define STACK_SIZE	512	/* Minimum number of bytes for stack */
+#define STACK_SIZE	1024	/* Minimum number of bytes for stack */
 
 #ifndef __ASSEMBLY__
 
--- linux-4.4.0.orig/arch/x86/boot/compressed/Makefile
+++ linux-4.4.0/arch/x86/boot/compressed/Makefile
@@ -22,7 +22,7 @@
 	vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
 
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
-KBUILD_CFLAGS += -fno-strict-aliasing -fPIC
+KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC)
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
 cflags-$(CONFIG_X86_32) := -march=i386
 cflags-$(CONFIG_X86_64) := -mcmodel=small
@@ -30,11 +30,26 @@
 KBUILD_CFLAGS += -mno-mmx -mno-sse
 KBUILD_CFLAGS += $(call cc-option,-ffreestanding)
 KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
+KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
+# Disable relocation relaxation in case the link is not PIE.
+KBUILD_CFLAGS += $(call as-option,-Wa$(comma)-mrelax-relocations=no)
 
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 GCOV_PROFILE := n
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
+ifeq ($(CONFIG_RELOCATABLE),y)
+# If kernel is relocatable, build compressed kernel as PIE.
+ifeq ($(CONFIG_X86_32),y)
+LDFLAGS += $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker)
+else
+# To build 64-bit compressed kernel as PIE, we disable relocation
+# overflow check to avoid relocation overflow error with a new linker
+# command-line option, -z noreloc-overflow.
+LDFLAGS += $(shell $(LD) --help 2>&1 | grep -q "\-z noreloc-overflow" \
+	&& echo "-z noreloc-overflow -pie --no-dynamic-linker")
+endif
+endif
 LDFLAGS_vmlinux := -T
 
 hostprogs-y	:= mkpiggy
--- linux-4.4.0.orig/arch/x86/boot/compressed/aslr.c
+++ linux-4.4.0/arch/x86/boot/compressed/aslr.c
@@ -1,5 +1,6 @@
 #include "misc.h"
 
+#include <asm/asm.h>
 #include <asm/msr.h>
 #include <asm/archrandom.h>
 #include <asm/e820.h>
@@ -24,8 +25,8 @@
 	u16 status, timer;
 
 	do {
-		outb(I8254_PORT_CONTROL,
-		     I8254_CMD_READBACK | I8254_SELECT_COUNTER0);
+		outb(I8254_CMD_READBACK | I8254_SELECT_COUNTER0,
+		     I8254_PORT_CONTROL);
 		status = inb(I8254_PORT_COUNTER0);
 		timer  = inb(I8254_PORT_COUNTER0);
 		timer |= inb(I8254_PORT_COUNTER0) << 8;
@@ -94,7 +95,7 @@
 	}
 
 	/* Circular multiply for better bit diffusion */
-	asm("mul %3"
+	asm(_ASM_MUL "%3"
 	    : "=a" (random), "=d" (raw)
 	    : "a" (random), "rm" (mix_const));
 	random += raw;
--- linux-4.4.0.orig/arch/x86/boot/compressed/eboot.c
+++ linux-4.4.0/arch/x86/boot/compressed/eboot.c
@@ -12,6 +12,7 @@
 #include <asm/efi.h>
 #include <asm/setup.h>
 #include <asm/desc.h>
+#include <asm/bootparam_utils.h>
 
 #include "../string.h"
 #include "eboot.h"
@@ -364,7 +365,8 @@
 	if (status != EFI_SUCCESS)
 		goto free_struct;
 
-	memcpy(rom->romdata, pci->romimage, pci->romsize);
+	memcpy(rom->romdata, (void *)(unsigned long)pci->romimage,
+	       pci->romsize);
 	return status;
 
 free_struct:
@@ -470,7 +472,8 @@
 	if (status != EFI_SUCCESS)
 		goto free_struct;
 
-	memcpy(rom->romdata, pci->romimage, pci->romsize);
+	memcpy(rom->romdata, (void *)(unsigned long)pci->romimage,
+	       pci->romsize);
 	return status;
 
 free_struct:
@@ -847,6 +850,56 @@
 	return status;
 }
 
+static int get_secure_boot(void)
+{
+	u8 sb, setup, moksbstate;
+	unsigned long datasize = sizeof(sb);
+	u32 attr;
+	efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
+	efi_status_t status;
+
+	status = efi_early->call((unsigned long)sys_table->runtime->get_variable,
+				L"SecureBoot", &var_guid, NULL, &datasize, &sb);
+
+	if (status != EFI_SUCCESS)
+		return 0;
+
+	if (sb == 0)
+		return 0;
+
+
+	status = efi_early->call((unsigned long)sys_table->runtime->get_variable,
+				L"SetupMode", &var_guid, NULL, &datasize,
+				&setup);
+
+	if (status != EFI_SUCCESS)
+		return 0;
+
+	if (setup == 1)
+		return 0;
+
+	/* See if a user has put shim into insecure_mode.  If so, and the variable
+	 * doesn't have the runtime attribute set, we might as well honor that.
+	 */
+	var_guid = EFI_SHIM_LOCK_GUID;
+	status = efi_early->call((unsigned long)sys_table->runtime->get_variable,
+				L"MokSBState", &var_guid, &attr, &datasize,
+				&moksbstate);
+
+	/* If it fails, we don't care why.  Default to secure */
+	if (status != EFI_SUCCESS)
+		return EFI_SECURE_BOOT;
+
+	if (!(attr & EFI_VARIABLE_RUNTIME_ACCESS)) {
+		if (moksbstate == 1) {
+			return EFI_MOKSBSTATE_DISABLED;
+		}
+	}
+
+	return EFI_SECURE_BOOT;
+}
+
+
 /*
  * See if we have Graphics Output Protocol
  */
@@ -1432,6 +1485,10 @@
 	else
 		setup_boot_services32(efi_early);
 
+	sanitize_boot_params(boot_params);
+
+	boot_params->secure_boot = get_secure_boot();
+
 	setup_graphics(boot_params);
 
 	setup_efi_pci(boot_params);
--- linux-4.4.0.orig/arch/x86/boot/compressed/head_32.S
+++ linux-4.4.0/arch/x86/boot/compressed/head_32.S
@@ -31,6 +31,34 @@
 #include <asm/asm-offsets.h>
 #include <asm/bootparam.h>
 
+/*
+ * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
+ * relocation to get the symbol address in PIC.  When the compressed x86
+ * kernel isn't built as PIC, the linker optimizes R_386_GOT32X
+ * relocations to their fixed symbol addresses.  However, when the
+ * compressed x86 kernel is loaded at a different address, it leads
+ * to the following load failure:
+ *
+ *   Failed to allocate space for phdrs
+ *
+ * during the decompression stage.
+ *
+ * If the compressed x86 kernel is relocatable at run-time, it should be
+ * compiled with -fPIE, instead of -fPIC, if possible and should be built as
+ * Position Independent Executable (PIE) so that linker won't optimize
+ * R_386_GOT32X relocation to its fixed symbol address.  Older
+ * linkers generate R_386_32 relocations against locally defined symbols,
+ * _bss, _ebss, _got and _egot, in PIE.  It isn't wrong, just less
+ * optimal than R_386_RELATIVE.  But the x86 kernel fails to properly handle
+ * R_386_32 relocations when relocating the kernel.  To generate
+ * R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
+ * hidden:
+ */
+	.hidden _bss
+	.hidden _ebss
+	.hidden _got
+	.hidden _egot
+
 	__HEAD
 ENTRY(startup_32)
 #ifdef CONFIG_EFI_STUB
@@ -142,7 +170,7 @@
 	notl	%eax
 	andl    %eax, %ebx
 	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
-	jge	1f
+	jae	1f
 #endif
 	movl	$LOAD_PHYSICAL_ADDR, %ebx
 1:
--- linux-4.4.0.orig/arch/x86/boot/compressed/head_64.S
+++ linux-4.4.0/arch/x86/boot/compressed/head_64.S
@@ -33,6 +33,14 @@
 #include <asm/asm-offsets.h>
 #include <asm/bootparam.h>
 
+/*
+ * Locally defined symbols should be marked hidden:
+ */
+	.hidden _bss
+	.hidden _ebss
+	.hidden _got
+	.hidden _egot
+
 	__HEAD
 	.code32
 ENTRY(startup_32)
@@ -96,7 +104,7 @@
 	notl	%eax
 	andl	%eax, %ebx
 	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
-	jge	1f
+	jae	1f
 #endif
 	movl	$LOAD_PHYSICAL_ADDR, %ebx
 1:
@@ -217,6 +225,11 @@
 	leal	efi32_config(%ebp), %eax
 	movl	%eax, efi_config(%ebp)
 
+	/* Disable paging */
+	movl	%cr0, %eax
+	btrl	$X86_CR0_PG_BIT, %eax
+	movl	%eax, %cr0
+
 	jmp	startup_32
 ENDPROC(efi32_stub_entry)
 #endif
@@ -324,7 +337,7 @@
 	notq	%rax
 	andq	%rax, %rbp
 	cmpq	$LOAD_PHYSICAL_ADDR, %rbp
-	jge	1f
+	jae	1f
 #endif
 	movq	$LOAD_PHYSICAL_ADDR, %rbp
 1:
--- linux-4.4.0.orig/arch/x86/boot/compressed/misc.c
+++ linux-4.4.0/arch/x86/boot/compressed/misc.c
@@ -11,6 +11,7 @@
 
 #include "misc.h"
 #include "../string.h"
+#include <asm/bootparam_utils.h>
 
 /* WARNING!!
  * This code is compiled with -fPIC and it is relocated dynamically
@@ -366,6 +367,10 @@
 
 		switch (phdr->p_type) {
 		case PT_LOAD:
+#ifdef CONFIG_X86_64
+			if ((phdr->p_align % 0x200000) != 0)
+				error("Alignment of LOAD segment isn't multiple of 2MB");
+#endif
 #ifdef CONFIG_RELOCATABLE
 			dest = output;
 			dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR);
--- linux-4.4.0.orig/arch/x86/boot/compressed/misc.h
+++ linux-4.4.0/arch/x86/boot/compressed/misc.h
@@ -9,6 +9,7 @@
  */
 #undef CONFIG_PARAVIRT
 #undef CONFIG_PARAVIRT_SPINLOCKS
+#undef CONFIG_PAGE_TABLE_ISOLATION
 #undef CONFIG_KASAN
 
 #include <linux/linkage.h>
@@ -18,7 +19,6 @@
 #include <asm/page.h>
 #include <asm/boot.h>
 #include <asm/bootparam.h>
-#include <asm/bootparam_utils.h>
 
 #define BOOT_BOOT_H
 #include "../ctype.h"
--- linux-4.4.0.orig/arch/x86/boot/cpuflags.h
+++ linux-4.4.0/arch/x86/boot/cpuflags.h
@@ -1,7 +1,7 @@
 #ifndef BOOT_CPUFLAGS_H
 #define BOOT_CPUFLAGS_H
 
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/processor-flags.h>
 
 struct cpu_features {
--- linux-4.4.0.orig/arch/x86/boot/mkcpustr.c
+++ linux-4.4.0/arch/x86/boot/mkcpustr.c
@@ -17,7 +17,7 @@
 
 #include "../include/asm/required-features.h"
 #include "../include/asm/disabled-features.h"
-#include "../include/asm/cpufeature.h"
+#include "../include/asm/cpufeatures.h"
 #include "../kernel/cpu/capflags.c"
 
 int main(void)
--- linux-4.4.0.orig/arch/x86/boot/string.c
+++ linux-4.4.0/arch/x86/boot/string.c
@@ -14,6 +14,16 @@
 
 #include <linux/types.h>
 #include "ctype.h"
+#include "string.h"
+
+/*
+ * Undef these macros so that the functions that we provide
+ * here will have the correct names regardless of how string.h
+ * may have chosen to #define them.
+ */
+#undef memcpy
+#undef memset
+#undef memcmp
 
 int memcmp(const void *s1, const void *s2, size_t len)
 {
--- linux-4.4.0.orig/arch/x86/boot/string.h
+++ linux-4.4.0/arch/x86/boot/string.h
@@ -18,4 +18,13 @@
 #define memset(d,c,l) __builtin_memset(d,c,l)
 #define memcmp	__builtin_memcmp
 
+extern int strcmp(const char *str1, const char *str2);
+extern int strncmp(const char *cs, const char *ct, size_t count);
+extern size_t strlen(const char *s);
+extern char *strstr(const char *s1, const char *s2);
+extern size_t strnlen(const char *s, size_t maxlen);
+extern unsigned int atou(const char *s);
+extern unsigned long long simple_strtoull(const char *cp, char **endp,
+					  unsigned int base);
+
 #endif /* BOOT_STRING_H */
--- linux-4.4.0.orig/arch/x86/boot/tools/build.c
+++ linux-4.4.0/arch/x86/boot/tools/build.c
@@ -391,6 +391,13 @@
 		die("Unable to mmap '%s': %m", argv[2]);
 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
 	sys_size = (sz + 15 + 4) / 16;
+#ifdef CONFIG_EFI_STUB
+	/*
+	 * COFF requires minimum 32-byte alignment of sections, and
+	 * adding a signature is problematic without that alignment.
+	 */
+	sys_size = (sys_size + 1) & ~1;
+#endif
 
 	/* Patch the setup code with the appropriate size parameters */
 	buf[0x1f1] = setup_sectors-1;
--- linux-4.4.0.orig/arch/x86/boot/video-vga.c
+++ linux-4.4.0/arch/x86/boot/video-vga.c
@@ -190,7 +190,7 @@
 	vga_set_vertical_end(60*8);
 }
 
-static int vga_set_mode(struct mode_info *mode)
+static int __attribute__((optimize("no-jump-tables"))) vga_set_mode(struct mode_info *mode)
 {
 	/* Set the basic mode */
 	vga_set_basic_mode();
--- linux-4.4.0.orig/arch/x86/configs/i386_defconfig
+++ linux-4.4.0/arch/x86/configs/i386_defconfig
@@ -218,7 +218,6 @@
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_EFI=y
 # CONFIG_LCD_CLASS_DEVICE is not set
-CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
@@ -248,6 +247,7 @@
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_TT_NEWSCHED=y
 CONFIG_USB_OHCI_HCD=y
--- linux-4.4.0.orig/arch/x86/configs/tiny.config
+++ linux-4.4.0/arch/x86/configs/tiny.config
@@ -1 +1,3 @@
 CONFIG_NOHIGHMEM=y
+# CONFIG_HIGHMEM4G is not set
+# CONFIG_HIGHMEM64G is not set
--- linux-4.4.0.orig/arch/x86/configs/x86_64_defconfig
+++ linux-4.4.0/arch/x86/configs/x86_64_defconfig
@@ -212,7 +212,6 @@
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_EFI=y
 # CONFIG_LCD_CLASS_DEVICE is not set
-CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
@@ -242,6 +241,7 @@
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_TT_NEWSCHED=y
 CONFIG_USB_OHCI_HCD=y
--- linux-4.4.0.orig/arch/x86/crypto/aes_ctrby8_avx-x86_64.S
+++ linux-4.4.0/arch/x86/crypto/aes_ctrby8_avx-x86_64.S
@@ -65,7 +65,6 @@
 #include <linux/linkage.h>
 #include <asm/inst.h>
 
-#define CONCAT(a,b)	a##b
 #define VMOVDQ		vmovdqu
 
 #define xdata0		%xmm0
@@ -92,8 +91,6 @@
 #define num_bytes	%r8
 
 #define tmp		%r10
-#define	DDQ(i)		CONCAT(ddq_add_,i)
-#define	XMM(i)		CONCAT(%xmm, i)
 #define	DDQ_DATA	0
 #define	XDATA		1
 #define KEY_128		1
@@ -131,12 +128,12 @@
 /* generate a unique variable for ddq_add_x */
 
 .macro setddq n
-	var_ddq_add = DDQ(\n)
+	var_ddq_add = ddq_add_\n
 .endm
 
 /* generate a unique variable for xmm register */
 .macro setxdata n
-	var_xdata = XMM(\n)
+	var_xdata = %xmm\n
 .endm
 
 /* club the numeric 'id' to the symbol 'name' */
--- linux-4.4.0.orig/arch/x86/crypto/aesni-intel_asm.S
+++ linux-4.4.0/arch/x86/crypto/aesni-intel_asm.S
@@ -31,6 +31,7 @@
 
 #include <linux/linkage.h>
 #include <asm/inst.h>
+#include <asm/nospec-branch.h>
 
 /*
  * The following macros are used to move an (un)aligned 16 byte value to/from
@@ -2714,7 +2715,7 @@
 	pxor INC, STATE4
 	movdqu IV, 0x30(OUTP)
 
-	call *%r11
+	CALL_NOSPEC %r11
 
 	movdqu 0x00(OUTP), INC
 	pxor INC, STATE1
@@ -2759,7 +2760,7 @@
 	_aesni_gf128mul_x_ble()
 	movups IV, (IVP)
 
-	call *%r11
+	CALL_NOSPEC %r11
 
 	movdqu 0x40(OUTP), INC
 	pxor INC, STATE1
--- linux-4.4.0.orig/arch/x86/crypto/aesni-intel_glue.c
+++ linux-4.4.0/arch/x86/crypto/aesni-intel_glue.c
@@ -639,16 +639,11 @@
 			    unsigned int keylen)
 {
 	struct aesni_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;
-	}
+	err = xts_check_key(tfm, key, keylen);
+	if (err)
+		return err;
 
 	/* first half of xts-key is for crypt */
 	err = aes_set_key_common(tfm, ctx->raw_crypt_ctx, key, keylen / 2);
@@ -965,7 +960,7 @@
 
 	if (sg_is_last(req->src) &&
 	    req->src->offset + req->src->length <= PAGE_SIZE &&
-	    sg_is_last(req->dst) &&
+	    sg_is_last(req->dst) && req->dst->length &&
 	    req->dst->offset + req->dst->length <= PAGE_SIZE) {
 		one_entry_in_sg = 1;
 		scatterwalk_start(&src_sg_walk, req->src);
--- linux-4.4.0.orig/arch/x86/crypto/camellia-aesni-avx-asm_64.S
+++ linux-4.4.0/arch/x86/crypto/camellia-aesni-avx-asm_64.S
@@ -16,6 +16,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/nospec-branch.h>
 
 #define CAMELLIA_TABLE_BYTE_LEN 272
 
@@ -1210,7 +1211,7 @@
 	vpxor 14 * 16(%rax), %xmm15, %xmm14;
 	vpxor 15 * 16(%rax), %xmm15, %xmm15;
 
-	call *%r9;
+	CALL_NOSPEC %r9;
 
 	addq $(16 * 16), %rsp;
 
--- linux-4.4.0.orig/arch/x86/crypto/camellia-aesni-avx2-asm_64.S
+++ linux-4.4.0/arch/x86/crypto/camellia-aesni-avx2-asm_64.S
@@ -11,6 +11,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/nospec-branch.h>
 
 #define CAMELLIA_TABLE_BYTE_LEN 272
 
@@ -1323,7 +1324,7 @@
 	vpxor 14 * 32(%rax), %ymm15, %ymm14;
 	vpxor 15 * 32(%rax), %ymm15, %ymm15;
 
-	call *%r9;
+	CALL_NOSPEC %r9;
 
 	addq $(16 * 32), %rsp;
 
--- linux-4.4.0.orig/arch/x86/crypto/camellia_glue.c
+++ linux-4.4.0/arch/x86/crypto/camellia_glue.c
@@ -1503,13 +1503,9 @@
 	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;
-	}
+	err = xts_check_key(tfm, key, keylen);
+	if (err)
+		return err;
 
 	/* first half of xts-key is for crypt */
 	err = __camellia_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
--- linux-4.4.0.orig/arch/x86/crypto/cast5_avx_glue.c
+++ linux-4.4.0/arch/x86/crypto/cast5_avx_glue.c
@@ -66,8 +66,6 @@
 	void (*fn)(struct cast5_ctx *ctx, u8 *dst, const u8 *src);
 	int err;
 
-	fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way;
-
 	err = blkcipher_walk_virt(desc, walk);
 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
@@ -79,6 +77,7 @@
 
 		/* Process multi-block batch */
 		if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+			fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way;
 			do {
 				fn(ctx, wdst, wsrc);
 
--- linux-4.4.0.orig/arch/x86/crypto/cast6_avx_glue.c
+++ linux-4.4.0/arch/x86/crypto/cast6_avx_glue.c
@@ -329,13 +329,9 @@
 	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;
-	}
+	err = xts_check_key(tfm, key, keylen);
+	if (err)
+		return err;
 
 	/* first half of xts-key is for crypt */
 	err = __cast6_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
--- linux-4.4.0.orig/arch/x86/crypto/chacha20-ssse3-x86_64.S
+++ linux-4.4.0/arch/x86/crypto/chacha20-ssse3-x86_64.S
@@ -157,7 +157,9 @@
 	# done with the slightly better performing SSSE3 byte shuffling,
 	# 7/12-bit word rotation uses traditional shift+OR.
 
-	sub		$0x40,%rsp
+	mov		%rsp,%r11
+	sub		$0x80,%rsp
+	and		$~63,%rsp
 
 	# x0..15[0-3] = s0..3[0..3]
 	movq		0x00(%rdi),%xmm1
@@ -620,6 +622,6 @@
 	pxor		%xmm1,%xmm15
 	movdqu		%xmm15,0xf0(%rsi)
 
-	add		$0x40,%rsp
+	mov		%r11,%rsp
 	ret
 ENDPROC(chacha20_4block_xor_ssse3)
--- linux-4.4.0.orig/arch/x86/crypto/chacha20_glue.c
+++ linux-4.4.0/arch/x86/crypto/chacha20_glue.c
@@ -77,6 +77,7 @@
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt_block(desc, &walk, CHACHA20_BLOCK_SIZE);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
 	crypto_chacha20_init(state, crypto_blkcipher_ctx(desc->tfm), walk.iv);
 
@@ -125,7 +126,7 @@
 
 static int __init chacha20_simd_mod_init(void)
 {
-	if (!cpu_has_ssse3)
+	if (!boot_cpu_has(X86_FEATURE_SSSE3))
 		return -ENODEV;
 
 #ifdef CONFIG_AS_AVX2
--- linux-4.4.0.orig/arch/x86/crypto/crc32-pclmul_glue.c
+++ linux-4.4.0/arch/x86/crypto/crc32-pclmul_glue.c
@@ -33,7 +33,7 @@
 #include <linux/crc32.h>
 #include <crypto/internal/hash.h>
 
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/cpu_device_id.h>
 #include <asm/fpu/api.h>
 
--- linux-4.4.0.orig/arch/x86/crypto/crc32c-intel_glue.c
+++ linux-4.4.0/arch/x86/crypto/crc32c-intel_glue.c
@@ -30,7 +30,7 @@
 #include <linux/kernel.h>
 #include <crypto/internal/hash.h>
 
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/cpu_device_id.h>
 #include <asm/fpu/internal.h>
 
@@ -48,26 +48,13 @@
 #ifdef CONFIG_X86_64
 /*
  * use carryless multiply version of crc32c when buffer
- * size is >= 512 (when eager fpu is enabled) or
- * >= 1024 (when eager fpu is disabled) to account
+ * size is >= 512 to account
  * for fpu state save/restore overhead.
  */
-#define CRC32C_PCL_BREAKEVEN_EAGERFPU	512
-#define CRC32C_PCL_BREAKEVEN_NOEAGERFPU	1024
+#define CRC32C_PCL_BREAKEVEN	512
 
 asmlinkage unsigned int crc_pcl(const u8 *buffer, int len,
 				unsigned int crc_init);
-static int crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_EAGERFPU;
-#if defined(X86_FEATURE_EAGER_FPU)
-#define set_pcl_breakeven_point()					\
-do {									\
-	if (!use_eager_fpu())						\
-		crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_NOEAGERFPU;	\
-} while (0)
-#else
-#define set_pcl_breakeven_point()					\
-	(crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_NOEAGERFPU)
-#endif
 #endif /* CONFIG_X86_64 */
 
 static u32 crc32c_intel_le_hw_byte(u32 crc, unsigned char const *data, size_t length)
@@ -190,7 +177,7 @@
 	 * use faster PCL version if datasize is large enough to
 	 * overcome kernel fpu state save/restore overhead
 	 */
-	if (len >= crc32c_pcl_breakeven && irq_fpu_usable()) {
+	if (len >= CRC32C_PCL_BREAKEVEN && irq_fpu_usable()) {
 		kernel_fpu_begin();
 		*crcp = crc_pcl(data, len, *crcp);
 		kernel_fpu_end();
@@ -202,7 +189,7 @@
 static int __crc32c_pcl_intel_finup(u32 *crcp, const u8 *data, unsigned int len,
 				u8 *out)
 {
-	if (len >= crc32c_pcl_breakeven && irq_fpu_usable()) {
+	if (len >= CRC32C_PCL_BREAKEVEN && irq_fpu_usable()) {
 		kernel_fpu_begin();
 		*(__le32 *)out = ~cpu_to_le32(crc_pcl(data, len, *crcp));
 		kernel_fpu_end();
@@ -257,11 +244,10 @@
 	if (!x86_match_cpu(crc32c_cpu_id))
 		return -ENODEV;
 #ifdef CONFIG_X86_64
-	if (cpu_has_pclmulqdq) {
+	if (boot_cpu_has(X86_FEATURE_PCLMULQDQ)) {
 		alg.update = crc32c_pcl_intel_update;
 		alg.finup = crc32c_pcl_intel_finup;
 		alg.digest = crc32c_pcl_intel_digest;
-		set_pcl_breakeven_point();
 	}
 #endif
 	return crypto_register_shash(&alg);
--- linux-4.4.0.orig/arch/x86/crypto/crc32c-pcl-intel-asm_64.S
+++ linux-4.4.0/arch/x86/crypto/crc32c-pcl-intel-asm_64.S
@@ -45,6 +45,7 @@
 
 #include <asm/inst.h>
 #include <linux/linkage.h>
+#include <asm/nospec-branch.h>
 
 ## ISCSI CRC 32 Implementation with crc32 and pclmulqdq Instruction
 
@@ -172,7 +173,7 @@
 	movzxw  (bufp, %rax, 2), len
 	offset=crc_array-jump_table
 	lea     offset(bufp, len, 1), bufp
-	jmp     *bufp
+	JMP_NOSPEC bufp
 
 	################################################################
 	## 2a) PROCESS FULL BLOCKS:
--- linux-4.4.0.orig/arch/x86/crypto/crct10dif-pclmul_glue.c
+++ linux-4.4.0/arch/x86/crypto/crct10dif-pclmul_glue.c
@@ -30,7 +30,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <asm/fpu/api.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/cpu_device_id.h>
 
 asmlinkage __u16 crc_t10dif_pcl(__u16 crc, const unsigned char *buf,
@@ -76,15 +76,14 @@
 	return 0;
 }
 
-static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
-			u8 *out)
+static int __chksum_finup(__u16 crc, const u8 *data, unsigned int len, u8 *out)
 {
 	if (irq_fpu_usable()) {
 		kernel_fpu_begin();
-		*(__u16 *)out = crc_t10dif_pcl(*crcp, data, len);
+		*(__u16 *)out = crc_t10dif_pcl(crc, data, len);
 		kernel_fpu_end();
 	} else
-		*(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
+		*(__u16 *)out = crc_t10dif_generic(crc, data, len);
 	return 0;
 }
 
@@ -93,15 +92,13 @@
 {
 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
-	return __chksum_finup(&ctx->crc, data, len, out);
+	return __chksum_finup(ctx->crc, data, len, out);
 }
 
 static int chksum_digest(struct shash_desc *desc, const u8 *data,
 			 unsigned int length, u8 *out)
 {
-	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-	return __chksum_finup(&ctx->crc, data, length, out);
+	return __chksum_finup(0, data, length, out);
 }
 
 static struct shash_alg alg = {
--- linux-4.4.0.orig/arch/x86/crypto/ghash-clmulni-intel_glue.c
+++ linux-4.4.0/arch/x86/crypto/ghash-clmulni-intel_glue.c
@@ -219,6 +219,29 @@
 	}
 }
 
+static int ghash_async_import(struct ahash_request *req, const void *in)
+{
+	struct ahash_request *cryptd_req = ahash_request_ctx(req);
+	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+	ghash_async_init(req);
+	memcpy(dctx, in, sizeof(*dctx));
+	return 0;
+
+}
+
+static int ghash_async_export(struct ahash_request *req, void *out)
+{
+	struct ahash_request *cryptd_req = ahash_request_ctx(req);
+	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+	memcpy(out, dctx, sizeof(*dctx));
+	return 0;
+
+}
+
 static int ghash_async_digest(struct ahash_request *req)
 {
 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
@@ -288,8 +311,11 @@
 	.final		= ghash_async_final,
 	.setkey		= ghash_async_setkey,
 	.digest		= ghash_async_digest,
+	.export		= ghash_async_export,
+	.import		= ghash_async_import,
 	.halg = {
 		.digestsize	= GHASH_DIGEST_SIZE,
+		.statesize = sizeof(struct ghash_desc_ctx),
 		.base = {
 			.cra_name		= "ghash",
 			.cra_driver_name	= "ghash-clmulni",
--- linux-4.4.0.orig/arch/x86/crypto/poly1305-avx2-x86_64.S
+++ linux-4.4.0/arch/x86/crypto/poly1305-avx2-x86_64.S
@@ -321,6 +321,12 @@
 	vpaddq		t2,t1,t1
 	vmovq		t1x,d4
 
+	# Now do a partial reduction mod (2^130)-5, carrying h0 -> h1 -> h2 ->
+	# h3 -> h4 -> h0 -> h1 to get h0,h2,h3,h4 < 2^26 and h1 < 2^26 + a small
+	# amount.  Careful: we must not assume the carry bits 'd0 >> 26',
+	# 'd1 >> 26', 'd2 >> 26', 'd3 >> 26', and '(d4 >> 26) * 5' fit in 32-bit
+	# integers.  It's true in a single-block implementation, but not here.
+
 	# d1 += d0 >> 26
 	mov		d0,%rax
 	shr		$26,%rax
@@ -359,16 +365,16 @@
 	# h0 += (d4 >> 26) * 5
 	mov		d4,%rax
 	shr		$26,%rax
-	lea		(%eax,%eax,4),%eax
-	add		%eax,%ebx
+	lea		(%rax,%rax,4),%rax
+	add		%rax,%rbx
 	# h4 = d4 & 0x3ffffff
 	mov		d4,%rax
 	and		$0x3ffffff,%eax
 	mov		%eax,h4
 
 	# h1 += h0 >> 26
-	mov		%ebx,%eax
-	shr		$26,%eax
+	mov		%rbx,%rax
+	shr		$26,%rax
 	add		%eax,h1
 	# h0 = h0 & 0x3ffffff
 	andl		$0x3ffffff,%ebx
--- linux-4.4.0.orig/arch/x86/crypto/poly1305-sse2-x86_64.S
+++ linux-4.4.0/arch/x86/crypto/poly1305-sse2-x86_64.S
@@ -251,16 +251,16 @@
 	# h0 += (d4 >> 26) * 5
 	mov		d4,%rax
 	shr		$26,%rax
-	lea		(%eax,%eax,4),%eax
-	add		%eax,%ebx
+	lea		(%rax,%rax,4),%rax
+	add		%rax,%rbx
 	# h4 = d4 & 0x3ffffff
 	mov		d4,%rax
 	and		$0x3ffffff,%eax
 	mov		%eax,h4
 
 	# h1 += h0 >> 26
-	mov		%ebx,%eax
-	shr		$26,%eax
+	mov		%rbx,%rax
+	shr		$26,%rax
 	add		%eax,h1
 	# h0 = h0 & 0x3ffffff
 	andl		$0x3ffffff,%ebx
@@ -518,6 +518,12 @@
 	paddq		t2,t1
 	movq		t1,d4
 
+	# Now do a partial reduction mod (2^130)-5, carrying h0 -> h1 -> h2 ->
+	# h3 -> h4 -> h0 -> h1 to get h0,h2,h3,h4 < 2^26 and h1 < 2^26 + a small
+	# amount.  Careful: we must not assume the carry bits 'd0 >> 26',
+	# 'd1 >> 26', 'd2 >> 26', 'd3 >> 26', and '(d4 >> 26) * 5' fit in 32-bit
+	# integers.  It's true in a single-block implementation, but not here.
+
 	# d1 += d0 >> 26
 	mov		d0,%rax
 	shr		$26,%rax
@@ -556,16 +562,16 @@
 	# h0 += (d4 >> 26) * 5
 	mov		d4,%rax
 	shr		$26,%rax
-	lea		(%eax,%eax,4),%eax
-	add		%eax,%ebx
+	lea		(%rax,%rax,4),%rax
+	add		%rax,%rbx
 	# h4 = d4 & 0x3ffffff
 	mov		d4,%rax
 	and		$0x3ffffff,%eax
 	mov		%eax,h4
 
 	# h1 += h0 >> 26
-	mov		%ebx,%eax
-	shr		$26,%eax
+	mov		%rbx,%rax
+	shr		$26,%rax
 	add		%eax,h1
 	# h0 = h0 & 0x3ffffff
 	andl		$0x3ffffff,%ebx
--- linux-4.4.0.orig/arch/x86/crypto/poly1305_glue.c
+++ linux-4.4.0/arch/x86/crypto/poly1305_glue.c
@@ -164,7 +164,6 @@
 	.init		= poly1305_simd_init,
 	.update		= poly1305_simd_update,
 	.final		= crypto_poly1305_final,
-	.setkey		= crypto_poly1305_setkey,
 	.descsize	= sizeof(struct poly1305_simd_desc_ctx),
 	.base		= {
 		.cra_name		= "poly1305",
--- linux-4.4.0.orig/arch/x86/crypto/salsa20_glue.c
+++ linux-4.4.0/arch/x86/crypto/salsa20_glue.c
@@ -59,13 +59,6 @@
 
 	salsa20_ivsetup(ctx, walk.iv);
 
-	if (likely(walk.nbytes == nbytes))
-	{
-		salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
-				      walk.dst.virt.addr, nbytes);
-		return blkcipher_walk_done(desc, &walk, 0);
-	}
-
 	while (walk.nbytes >= 64) {
 		salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
 				      walk.dst.virt.addr,
--- linux-4.4.0.orig/arch/x86/crypto/serpent_avx_glue.c
+++ linux-4.4.0/arch/x86/crypto/serpent_avx_glue.c
@@ -332,16 +332,11 @@
 		       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;
-	}
+	err = xts_check_key(tfm, key, keylen);
+	if (err)
+		return err;
 
 	/* first half of xts-key is for crypt */
 	err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
--- linux-4.4.0.orig/arch/x86/crypto/serpent_sse2_glue.c
+++ linux-4.4.0/arch/x86/crypto/serpent_sse2_glue.c
@@ -309,16 +309,11 @@
 			      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;
-	}
+	err = xts_check_key(tfm, key, keylen);
+	if (err)
+		return err;
 
 	/* first half of xts-key is for crypt */
 	err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
--- linux-4.4.0.orig/arch/x86/crypto/sha-mb/sha1_mb.c
+++ linux-4.4.0/arch/x86/crypto/sha-mb/sha1_mb.c
@@ -453,10 +453,10 @@
 
 			req = cast_mcryptd_ctx_to_req(req_ctx);
 			if (irqs_disabled())
-				rctx->complete(&req->base, ret);
+				req_ctx->complete(&req->base, ret);
 			else {
 				local_bh_disable();
-				rctx->complete(&req->base, ret);
+				req_ctx->complete(&req->base, ret);
 				local_bh_enable();
 			}
 		}
@@ -762,6 +762,38 @@
 	return crypto_ahash_digest(mcryptd_req);
 }
 
+static int sha1_mb_async_export(struct ahash_request *req, void *out)
+{
+	struct ahash_request *mcryptd_req = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm;
+
+	memcpy(mcryptd_req, req, sizeof(*req));
+	ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base);
+	return crypto_ahash_export(mcryptd_req, out);
+}
+
+static int sha1_mb_async_import(struct ahash_request *req, const void *in)
+{
+	struct ahash_request *mcryptd_req = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm;
+	struct crypto_shash *child = mcryptd_ahash_child(mcryptd_tfm);
+	struct mcryptd_hash_request_ctx *rctx;
+	struct shash_desc *desc;
+
+	memcpy(mcryptd_req, req, sizeof(*req));
+	ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base);
+	rctx = ahash_request_ctx(mcryptd_req);
+	desc = &rctx->desc;
+	desc->tfm = child;
+	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	return crypto_ahash_import(mcryptd_req, in);
+}
+
 static int sha1_mb_async_init_tfm(struct crypto_tfm *tfm)
 {
 	struct mcryptd_ahash *mcryptd_tfm;
@@ -796,8 +828,11 @@
 	.final          = sha1_mb_async_final,
 	.finup          = sha1_mb_async_finup,
 	.digest         = sha1_mb_async_digest,
+	.export		= sha1_mb_async_export,
+	.import		= sha1_mb_async_import,
 	.halg = {
 		.digestsize     = SHA1_DIGEST_SIZE,
+		.statesize	= sizeof(struct sha1_hash_ctx),
 		.base = {
 			.cra_name               = "sha1",
 			.cra_driver_name        = "sha1_mb",
--- linux-4.4.0.orig/arch/x86/crypto/sha-mb/sha1_mb_mgr_flush_avx2.S
+++ linux-4.4.0/arch/x86/crypto/sha-mb/sha1_mb_mgr_flush_avx2.S
@@ -174,8 +174,8 @@
 .endr
 
 	# Find min length
-	vmovdqa _lens+0*16(state), %xmm0
-	vmovdqa _lens+1*16(state), %xmm1
+	vmovdqu _lens+0*16(state), %xmm0
+	vmovdqu _lens+1*16(state), %xmm1
 
 	vpminud %xmm1, %xmm0, %xmm2     # xmm2 has {D,C,B,A}
 	vpalignr $8, %xmm2, %xmm3, %xmm3   # xmm3 has {x,x,D,C}
@@ -195,8 +195,8 @@
 	vpsubd  %xmm2, %xmm0, %xmm0
 	vpsubd  %xmm2, %xmm1, %xmm1
 
-	vmovdqa %xmm0, _lens+0*16(state)
-	vmovdqa %xmm1, _lens+1*16(state)
+	vmovdqu %xmm0, _lens+0*16(state)
+	vmovdqu %xmm1, _lens+1*16(state)
 
 	# "state" and "args" are the same address, arg1
 	# len is arg2
@@ -260,8 +260,8 @@
 	jc      .return_null
 
 	# Find min length
-	vmovdqa _lens(state), %xmm0
-	vmovdqa _lens+1*16(state), %xmm1
+	vmovdqu _lens(state), %xmm0
+	vmovdqu _lens+1*16(state), %xmm1
 
 	vpminud %xmm1, %xmm0, %xmm2        # xmm2 has {D,C,B,A}
 	vpalignr $8, %xmm2, %xmm3, %xmm3   # xmm3 has {x,x,D,C}
--- linux-4.4.0.orig/arch/x86/crypto/sha1_avx2_x86_64_asm.S
+++ linux-4.4.0/arch/x86/crypto/sha1_avx2_x86_64_asm.S
@@ -117,11 +117,10 @@
 	.set T1, REG_T1
 .endm
 
-#define K_BASE		%r8
 #define HASH_PTR	%r9
+#define BLOCKS_CTR	%r8
 #define BUFFER_PTR	%r10
 #define BUFFER_PTR2	%r13
-#define BUFFER_END	%r11
 
 #define PRECALC_BUF	%r14
 #define WK_BUF		%r15
@@ -205,14 +204,14 @@
 		 * blended AVX2 and ALU instruction scheduling
 		 * 1 vector iteration per 8 rounds
 		 */
-		vmovdqu ((i * 2) + PRECALC_OFFSET)(BUFFER_PTR), W_TMP
+		vmovdqu (i * 2)(BUFFER_PTR), W_TMP
 	.elseif ((i & 7) == 1)
-		vinsertf128 $1, (((i-1) * 2)+PRECALC_OFFSET)(BUFFER_PTR2),\
+		vinsertf128 $1, ((i-1) * 2)(BUFFER_PTR2),\
 			 WY_TMP, WY_TMP
 	.elseif ((i & 7) == 2)
 		vpshufb YMM_SHUFB_BSWAP, WY_TMP, WY
 	.elseif ((i & 7) == 4)
-		vpaddd  K_XMM(K_BASE), WY, WY_TMP
+		vpaddd  K_XMM + K_XMM_AR(%rip), WY, WY_TMP
 	.elseif ((i & 7) == 7)
 		vmovdqu  WY_TMP, PRECALC_WK(i&~7)
 
@@ -255,7 +254,7 @@
 		vpxor	WY, WY_TMP, WY_TMP
 	.elseif ((i & 7) == 7)
 		vpxor	WY_TMP2, WY_TMP, WY
-		vpaddd	K_XMM(K_BASE), WY, WY_TMP
+		vpaddd  K_XMM + K_XMM_AR(%rip), WY, WY_TMP
 		vmovdqu	WY_TMP, PRECALC_WK(i&~7)
 
 		PRECALC_ROTATE_WY
@@ -291,7 +290,7 @@
 		vpsrld	$30, WY, WY
 		vpor	WY, WY_TMP, WY
 	.elseif ((i & 7) == 7)
-		vpaddd	K_XMM(K_BASE), WY, WY_TMP
+		vpaddd  K_XMM + K_XMM_AR(%rip), WY, WY_TMP
 		vmovdqu	WY_TMP, PRECALC_WK(i&~7)
 
 		PRECALC_ROTATE_WY
@@ -446,6 +445,16 @@
 
 .endm
 
+/* Add constant only if (%2 > %3) condition met (uses RTA as temp)
+ * %1 + %2 >= %3 ? %4 : 0
+ */
+.macro ADD_IF_GE a, b, c, d
+	mov     \a, RTA
+	add     $\d, RTA
+	cmp     $\c, \b
+	cmovge  RTA, \a
+.endm
+
 /*
  * macro implements 80 rounds of SHA-1, for multiple blocks with s/w pipelining
  */
@@ -463,13 +472,16 @@
 	lea	(2*4*80+32)(%rsp), WK_BUF
 
 	# Precalc WK for first 2 blocks
-	PRECALC_OFFSET = 0
+	ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 2, 64
 	.set i, 0
 	.rept    160
 		PRECALC i
 		.set i, i + 1
 	.endr
-	PRECALC_OFFSET = 128
+
+	/* Go to next block if needed */
+	ADD_IF_GE BUFFER_PTR, BLOCKS_CTR, 3, 128
+	ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 4, 128
 	xchg	WK_BUF, PRECALC_BUF
 
 	.align 32
@@ -479,8 +491,8 @@
 	 * we use K_BASE value as a signal of a last block,
 	 * it is set below by: cmovae BUFFER_PTR, K_BASE
 	 */
-	cmp	K_BASE, BUFFER_PTR
-	jne	_begin
+	test BLOCKS_CTR, BLOCKS_CTR
+	jnz _begin
 	.align 32
 	jmp	_end
 	.align 32
@@ -512,10 +524,10 @@
 		.set j, j+2
 	.endr
 
-	add	$(2*64), BUFFER_PTR       /* move to next odd-64-byte block */
-	cmp	BUFFER_END, BUFFER_PTR    /* is current block the last one? */
-	cmovae	K_BASE, BUFFER_PTR	/* signal the last iteration smartly */
-
+	/* Update Counter */
+	sub $1, BLOCKS_CTR
+	/* Move to the next block only if needed*/
+	ADD_IF_GE BUFFER_PTR, BLOCKS_CTR, 4, 128
 	/*
 	 * rounds
 	 * 60,62,64,66,68
@@ -532,8 +544,8 @@
 	UPDATE_HASH	12(HASH_PTR), D
 	UPDATE_HASH	16(HASH_PTR), E
 
-	cmp	K_BASE, BUFFER_PTR	/* is current block the last one? */
-	je	_loop
+	test	BLOCKS_CTR, BLOCKS_CTR
+	jz	_loop
 
 	mov	TB, B
 
@@ -575,10 +587,10 @@
 		.set j, j+2
 	.endr
 
-	add	$(2*64), BUFFER_PTR2      /* move to next even-64-byte block */
-
-	cmp	BUFFER_END, BUFFER_PTR2   /* is current block the last one */
-	cmovae	K_BASE, BUFFER_PTR       /* signal the last iteration smartly */
+	/* update counter */
+	sub     $1, BLOCKS_CTR
+	/* Move to the next block only if needed*/
+	ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 4, 128
 
 	jmp	_loop3
 _loop3:
@@ -641,19 +653,12 @@
 
 	avx2_zeroupper
 
-	lea	K_XMM_AR(%rip), K_BASE
-
+	/* Setup initial values */
 	mov	CTX, HASH_PTR
 	mov	BUF, BUFFER_PTR
-	lea	64(BUF), BUFFER_PTR2
-
-	shl	$6, CNT			/* mul by 64 */
-	add	BUF, CNT
-	add	$64, CNT
-	mov	CNT, BUFFER_END
 
-	cmp	BUFFER_END, BUFFER_PTR2
-	cmovae	K_BASE, BUFFER_PTR2
+	mov	BUF, BUFFER_PTR2
+	mov	CNT, BLOCKS_CTR
 
 	xmm_mov	BSWAP_SHUFB_CTL(%rip), YMM_SHUFB_BSWAP
 
--- linux-4.4.0.orig/arch/x86/crypto/twofish-x86_64-asm_64-3way.S
+++ linux-4.4.0/arch/x86/crypto/twofish-x86_64-asm_64-3way.S
@@ -55,29 +55,31 @@
 #define RAB1bl %bl
 #define RAB2bl %cl
 
+#define CD0 0x0(%rsp)
+#define CD1 0x8(%rsp)
+#define CD2 0x10(%rsp)
+
+# used only before/after all rounds
 #define RCD0 %r8
 #define RCD1 %r9
 #define RCD2 %r10
 
-#define RCD0d %r8d
-#define RCD1d %r9d
-#define RCD2d %r10d
-
-#define RX0 %rbp
-#define RX1 %r11
-#define RX2 %r12
-
-#define RX0d %ebp
-#define RX1d %r11d
-#define RX2d %r12d
-
-#define RY0 %r13
-#define RY1 %r14
-#define RY2 %r15
-
-#define RY0d %r13d
-#define RY1d %r14d
-#define RY2d %r15d
+# used only during rounds
+#define RX0 %r8
+#define RX1 %r9
+#define RX2 %r10
+
+#define RX0d %r8d
+#define RX1d %r9d
+#define RX2d %r10d
+
+#define RY0 %r11
+#define RY1 %r12
+#define RY2 %r13
+
+#define RY0d %r11d
+#define RY1d %r12d
+#define RY2d %r13d
 
 #define RT0 %rdx
 #define RT1 %rsi
@@ -85,6 +87,8 @@
 #define RT0d %edx
 #define RT1d %esi
 
+#define RT1bl %sil
+
 #define do16bit_ror(rot, op1, op2, T0, T1, tmp1, tmp2, ab, dst) \
 	movzbl ab ## bl,		tmp2 ## d; \
 	movzbl ab ## bh,		tmp1 ## d; \
@@ -92,6 +96,11 @@
 	op1##l T0(CTX, tmp2, 4),	dst ## d; \
 	op2##l T1(CTX, tmp1, 4),	dst ## d;
 
+#define swap_ab_with_cd(ab, cd, tmp)	\
+	movq cd, tmp;			\
+	movq ab, cd;			\
+	movq tmp, ab;
+
 /*
  * Combined G1 & G2 function. Reordered with help of rotates to have moves
  * at begining.
@@ -110,15 +119,15 @@
 	/* G1,2 && G2,2 */ \
 	do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 0, x ## 0); \
 	do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 0, y ## 0); \
-	xchgq cd ## 0, ab ## 0; \
+	swap_ab_with_cd(ab ## 0, cd ## 0, RT0); \
 	\
 	do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 1, x ## 1); \
 	do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 1, y ## 1); \
-	xchgq cd ## 1, ab ## 1; \
+	swap_ab_with_cd(ab ## 1, cd ## 1, RT0); \
 	\
 	do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 2, x ## 2); \
 	do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 2, y ## 2); \
-	xchgq cd ## 2, ab ## 2;
+	swap_ab_with_cd(ab ## 2, cd ## 2, RT0);
 
 #define enc_round_end(ab, x, y, n) \
 	addl y ## d,			x ## d; \
@@ -168,6 +177,16 @@
 	decrypt_round3(ba, dc, (n*2)+1); \
 	decrypt_round3(ba, dc, (n*2));
 
+#define push_cd()	\
+	pushq RCD2;	\
+	pushq RCD1;	\
+	pushq RCD0;
+
+#define pop_cd()	\
+	popq RCD0;	\
+	popq RCD1;	\
+	popq RCD2;
+
 #define inpack3(in, n, xy, m) \
 	movq 4*(n)(in),			xy ## 0; \
 	xorq w+4*m(CTX),		xy ## 0; \
@@ -223,11 +242,8 @@
 	 *	%rdx: src, RIO
 	 *	%rcx: bool, if true: xor output
 	 */
-	pushq %r15;
-	pushq %r14;
 	pushq %r13;
 	pushq %r12;
-	pushq %rbp;
 	pushq %rbx;
 
 	pushq %rcx; /* bool xor */
@@ -235,40 +251,36 @@
 
 	inpack_enc3();
 
-	encrypt_cycle3(RAB, RCD, 0);
-	encrypt_cycle3(RAB, RCD, 1);
-	encrypt_cycle3(RAB, RCD, 2);
-	encrypt_cycle3(RAB, RCD, 3);
-	encrypt_cycle3(RAB, RCD, 4);
-	encrypt_cycle3(RAB, RCD, 5);
-	encrypt_cycle3(RAB, RCD, 6);
-	encrypt_cycle3(RAB, RCD, 7);
+	push_cd();
+	encrypt_cycle3(RAB, CD, 0);
+	encrypt_cycle3(RAB, CD, 1);
+	encrypt_cycle3(RAB, CD, 2);
+	encrypt_cycle3(RAB, CD, 3);
+	encrypt_cycle3(RAB, CD, 4);
+	encrypt_cycle3(RAB, CD, 5);
+	encrypt_cycle3(RAB, CD, 6);
+	encrypt_cycle3(RAB, CD, 7);
+	pop_cd();
 
 	popq RIO; /* dst */
-	popq %rbp; /* bool xor */
+	popq RT1; /* bool xor */
 
-	testb %bpl, %bpl;
+	testb RT1bl, RT1bl;
 	jnz .L__enc_xor3;
 
 	outunpack_enc3(mov);
 
 	popq %rbx;
-	popq %rbp;
 	popq %r12;
 	popq %r13;
-	popq %r14;
-	popq %r15;
 	ret;
 
 .L__enc_xor3:
 	outunpack_enc3(xor);
 
 	popq %rbx;
-	popq %rbp;
 	popq %r12;
 	popq %r13;
-	popq %r14;
-	popq %r15;
 	ret;
 ENDPROC(__twofish_enc_blk_3way)
 
@@ -278,35 +290,31 @@
 	 *	%rsi: dst
 	 *	%rdx: src, RIO
 	 */
-	pushq %r15;
-	pushq %r14;
 	pushq %r13;
 	pushq %r12;
-	pushq %rbp;
 	pushq %rbx;
 
 	pushq %rsi; /* dst */
 
 	inpack_dec3();
 
-	decrypt_cycle3(RAB, RCD, 7);
-	decrypt_cycle3(RAB, RCD, 6);
-	decrypt_cycle3(RAB, RCD, 5);
-	decrypt_cycle3(RAB, RCD, 4);
-	decrypt_cycle3(RAB, RCD, 3);
-	decrypt_cycle3(RAB, RCD, 2);
-	decrypt_cycle3(RAB, RCD, 1);
-	decrypt_cycle3(RAB, RCD, 0);
+	push_cd();
+	decrypt_cycle3(RAB, CD, 7);
+	decrypt_cycle3(RAB, CD, 6);
+	decrypt_cycle3(RAB, CD, 5);
+	decrypt_cycle3(RAB, CD, 4);
+	decrypt_cycle3(RAB, CD, 3);
+	decrypt_cycle3(RAB, CD, 2);
+	decrypt_cycle3(RAB, CD, 1);
+	decrypt_cycle3(RAB, CD, 0);
+	pop_cd();
 
 	popq RIO; /* dst */
 
 	outunpack_dec3();
 
 	popq %rbx;
-	popq %rbp;
 	popq %r12;
 	popq %r13;
-	popq %r14;
-	popq %r15;
 	ret;
 ENDPROC(twofish_dec_blk_3way)
--- linux-4.4.0.orig/arch/x86/crypto/twofish_glue_3way.c
+++ linux-4.4.0/arch/x86/crypto/twofish_glue_3way.c
@@ -277,13 +277,9 @@
 	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;
-	}
+	err = xts_check_key(tfm, key, keylen);
+	if (err)
+		return err;
 
 	/* first half of xts-key is for crypt */
 	err = __twofish_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
--- linux-4.4.0.orig/arch/x86/entry/calling.h
+++ linux-4.4.0/arch/x86/entry/calling.h
@@ -1,3 +1,6 @@
+#include <asm/msr.h>
+#include <asm/nospec-branch.h>
+
 /*
 
  x86 function call convention, 64-bit:
@@ -199,6 +202,92 @@
 	.byte 0xf1
 	.endm
 
+/*
+ * IBRS kernel mitigation for Spectre_v2.
+ *
+ * Assumes full context is established (PUSH_REGS, CR3 and GS) and it clobbers
+ * the regs it uses (AX, CX, DX). Must be called before the first RET
+ * instruction (NOTE! UNTRAIN_RET includes a RET instruction)
+ *
+ * The optional argument is used to save/restore the current value,
+ * which is used on the paranoid paths.
+ *
+ * Assumes x86_spec_ctrl_{base,current} to have SPEC_CTRL_IBRS set.
+ */
+.macro IBRS_ENTER save_reg
+	ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
+	pushq	%rax
+	pushq	%rcx
+	pushq	%rdx
+	movl	$MSR_IA32_SPEC_CTRL, %ecx
+
+.ifnb \save_reg
+	rdmsr
+	shl	$32, %rdx
+	or	%rdx, %rax
+	mov	%rax, \save_reg
+	test	$SPEC_CTRL_IBRS, %eax
+	jz	.Ldo_wrmsr_\@
+	lfence
+	jmp	.Lend2_\@
+.Ldo_wrmsr_\@:
+.endif
+
+	movq	PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+	movl	%edx, %eax
+	shr	$32, %rdx
+	wrmsr
+.Lend2_\@:
+	popq	%rdx
+	popq	%rcx
+	popq	%rax
+.Lend_\@:
+.endm
+
+/*
+ * Similar to IBRS_ENTER, requires KERNEL GS,CR3 and clobbers (AX, CX, DX)
+ * regs. Must be called after the last RET.
+ */
+.macro IBRS_EXIT save_reg
+	ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
+	pushq	%rax
+	pushq	%rcx
+	pushq	%rdx
+	movl	$MSR_IA32_SPEC_CTRL, %ecx
+
+.ifnb \save_reg
+	mov	\save_reg, %rdx
+.else
+	movq	PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+	andl	$(~SPEC_CTRL_IBRS), %edx
+.endif
+
+	movl	%edx, %eax
+	shr	$32, %rdx
+	wrmsr
+	popq	%rdx
+	popq	%rcx
+	popq	%rax
+.Lend_\@:
+.endm
+
+/*
+ * Mitigate Spectre v1 for conditional swapgs code paths.
+ *
+ * FENCE_SWAPGS_USER_ENTRY is used in the user entry swapgs code path, to
+ * prevent a speculative swapgs when coming from kernel space.
+ *
+ * FENCE_SWAPGS_KERNEL_ENTRY is used in the kernel entry non-swapgs code path,
+ * to prevent the swapgs from getting speculatively skipped when coming from
+ * user space.
+ */
+	.macro FENCE_SWAPGS_USER_ENTRY
+	ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_USER
+	.endm
+	.macro FENCE_SWAPGS_KERNEL_ENTRY
+	ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_KERNEL
+	.endm
+
 #else /* CONFIG_X86_64 */
 
 /*
--- linux-4.4.0.orig/arch/x86/entry/common.c
+++ linux-4.4.0/arch/x86/entry/common.c
@@ -20,12 +20,15 @@
 #include <linux/export.h>
 #include <linux/context_tracking.h>
 #include <linux/user-return-notifier.h>
+#include <linux/nospec.h>
 #include <linux/uprobes.h>
 
 #include <asm/desc.h>
 #include <asm/traps.h>
 #include <asm/vdso.h>
 #include <asm/uaccess.h>
+#include <asm/cpufeature.h>
+#include <asm/nospec-branch.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
@@ -268,6 +271,7 @@
 /* Called with IRQs disabled. */
 __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
 {
+	struct thread_info *ti = pt_regs_to_thread_info(regs);
 	u32 cached_flags;
 
 	if (IS_ENABLED(CONFIG_PROVE_LOCKING) && WARN_ON(!irqs_disabled()))
@@ -275,13 +279,33 @@
 
 	lockdep_sys_exit();
 
-	cached_flags =
-		READ_ONCE(pt_regs_to_thread_info(regs)->flags);
+	cached_flags = READ_ONCE(ti->flags);
 
 	if (unlikely(cached_flags & EXIT_TO_USERMODE_LOOP_FLAGS))
 		exit_to_usermode_loop(regs, cached_flags);
 
+#ifdef CONFIG_COMPAT
+	/*
+	 * Compat syscalls set TS_COMPAT.  Make sure we clear it before
+	 * returning to user mode.  We need to clear it *after* signal
+	 * handling, because syscall restart has a fixup for compat
+	 * syscalls.  The fixup is exercised by the ptrace_syscall_32
+	 * selftest.
+	 */
+	ti->status &= ~TS_COMPAT;
+#endif
+
 	user_enter();
+
+	/* Avoid unnecessary reads of 'x86_ibpb_exit_to_user' */
+	if (cpu_feature_enabled(X86_FEATURE_IBPB_EXIT_TO_USER) &&
+	    this_cpu_read(x86_ibpb_exit_to_user)) {
+		indirect_branch_prediction_barrier();
+		this_cpu_write(x86_ibpb_exit_to_user, false);
+	}
+
+	mds_user_clear_cpu_buffers();
+	amd_clear_divider();
 }
 
 #define SYSCALL_EXIT_WORK_FLAGS				\
@@ -332,14 +356,6 @@
 	if (unlikely(cached_flags & SYSCALL_EXIT_WORK_FLAGS))
 		syscall_slow_exit_work(regs, cached_flags);
 
-#ifdef CONFIG_COMPAT
-	/*
-	 * Compat syscalls set TS_COMPAT.  Make sure we clear it before
-	 * returning to user mode.
-	 */
-	ti->status &= ~TS_COMPAT;
-#endif
-
 	local_irq_disable();
 	prepare_exit_to_usermode(regs);
 }
@@ -378,6 +394,7 @@
 	}
 
 	if (likely(nr < IA32_NR_syscalls)) {
+		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		/*
 		 * It's possible that a 32-bit syscall implementation
 		 * takes a 64-bit parameter but nonetheless assumes that
--- linux-4.4.0.orig/arch/x86/entry/entry_32.S
+++ linux-4.4.0/arch/x86/entry/entry_32.S
@@ -40,10 +40,11 @@
 #include <asm/processor-flags.h>
 #include <asm/ftrace.h>
 #include <asm/irq_vectors.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative-asm.h>
 #include <asm/asm.h>
 #include <asm/smap.h>
+#include <asm/nospec-branch.h>
 
 	.section .entry.text, "ax"
 
@@ -226,7 +227,8 @@
 	pushl	$0x0202				# Reset kernel eflags
 	popfl
 	movl	PT_EBP(%esp), %eax
-	call	*PT_EBX(%esp)
+	movl	PT_EBX(%esp), %edx
+	CALL_NOSPEC %edx
 	movl	$0, PT_EAX(%esp)
 
 	/*
@@ -329,7 +331,8 @@
 	 * Return back to the vDSO, which will pop ecx and edx.
 	 * Don't bother with DS and ES (they already contain __USER_DS).
 	 */
-	ENABLE_INTERRUPTS_SYSEXIT
+	sti
+	sysexit
 
 .pushsection .fixup, "ax"
 2:	movl	$0, PT_FS(%esp)
@@ -552,11 +555,6 @@
 	iret
 	_ASM_EXTABLE(native_iret, iret_exc)
 END(native_iret)
-
-ENTRY(native_irq_enable_sysexit)
-	sti
-	sysexit
-END(native_irq_enable_sysexit)
 #endif
 
 ENTRY(overflow)
@@ -766,8 +764,8 @@
 	jmp	ftrace_stub
 #endif
 
-.globl ftrace_stub
-ftrace_stub:
+/* This is weak to keep gas from relaxing the jumps */
+WEAK(ftrace_stub)
 	ret
 END(ftrace_caller)
 
@@ -861,7 +859,8 @@
 	movl	0x4(%ebp), %edx
 	subl	$MCOUNT_INSN_SIZE, %eax
 
-	call	*ftrace_trace_function
+	movl    ftrace_trace_function, %ecx
+	CALL_NOSPEC %ecx
 
 	popl	%edx
 	popl	%ecx
@@ -896,7 +895,7 @@
 	movl	%eax, %ecx
 	popl	%edx
 	popl	%eax
-	jmp	*%ecx
+	JMP_NOSPEC %ecx
 #endif
 
 #ifdef CONFIG_TRACING
@@ -938,7 +937,7 @@
 	movl	%ecx, %es
 	TRACE_IRQS_OFF
 	movl	%esp, %eax			# pt_regs pointer
-	call	*%edi
+	CALL_NOSPEC %edi
 	jmp	ret_from_exception
 END(page_fault)
 
@@ -1068,6 +1067,7 @@
 END(int3)
 
 ENTRY(general_protection)
+	ASM_CLAC
 	pushl	$do_general_protection
 	jmp	error_code
 END(general_protection)
--- linux-4.4.0.orig/arch/x86/entry/entry_64.S
+++ linux-4.4.0/arch/x86/entry/entry_64.S
@@ -22,7 +22,6 @@
 #include <asm/segment.h>
 #include <asm/cache.h>
 #include <asm/errno.h>
-#include "calling.h"
 #include <asm/asm-offsets.h>
 #include <asm/msr.h>
 #include <asm/unistd.h>
@@ -35,6 +34,9 @@
 #include <asm/asm.h>
 #include <asm/smap.h>
 #include <asm/pgtable_types.h>
+#include <asm/kaiser.h>
+#include <asm/nospec-branch.h>
+#include <asm/spec_ctrl.h>
 #include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
@@ -43,6 +45,8 @@
 #define __AUDIT_ARCH_64BIT			0x80000000
 #define __AUDIT_ARCH_LE				0x40000000
 
+#include "calling.h"
+
 .code64
 .section .entry.text, "ax"
 
@@ -88,7 +92,7 @@
 .endm
 
 .macro TRACE_IRQS_IRETQ_DEBUG
-	bt	$9, EFLAGS(%rsp)		/* interrupts off? */
+	btl	$9, EFLAGS(%rsp)		/* interrupts off? */
 	jnc	1f
 	TRACE_IRQS_ON_DEBUG
 1:
@@ -135,6 +139,7 @@
 	 * it is too small to ever cause noticeable irq latency.
 	 */
 	SWAPGS_UNSAFE_STACK
+	SWITCH_KERNEL_CR3_NO_STACK
 	/*
 	 * A hypervisor implementation might want to use a label
 	 * after the swapgs, so that it can do the swapgs
@@ -171,18 +176,30 @@
 	pushq	%r11				/* pt_regs->r11 */
 	sub	$(6*8), %rsp			/* pt_regs->bp, bx, r12-15 not saved */
 
+	/* clobbers %rax, make sure it is after saving the syscall nr */
+	IBRS_ENTER
+	CLEAR_BRANCH_HISTORY
+
 	testl	$_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
 	jnz	tracesys
 entry_SYSCALL_64_fastpath:
 #if __SYSCALL_MASK == ~0
-	cmpq	$__NR_syscall_max, %rax
+	cmpq	$NR_syscalls, %rax
 #else
 	andl	$__SYSCALL_MASK, %eax
-	cmpl	$__NR_syscall_max, %eax
+	cmpl	$NR_syscalls, %eax
 #endif
-	ja	1f				/* return -ENOSYS (already in pt_regs->ax) */
+	jae	1f				/* return -ENOSYS (already in pt_regs->ax) */
+	sbb	%rcx, %rcx			/* array_index_mask_nospec() */
+	and	%rcx, %rax
 	movq	%r10, %rcx
+#ifdef CONFIG_RETPOLINE
+	movq	sys_call_table(, %rax, 8), %rax
+	call	__x86_indirect_thunk_rax
+#else
 	call	*sys_call_table(, %rax, 8)
+#endif
+
 	movq	%rax, RAX(%rsp)
 1:
 /*
@@ -207,9 +224,22 @@
 	testl	$_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
 	jnz	int_ret_from_sys_call_irqs_off	/* Go to the slow path */
 
-	RESTORE_C_REGS_EXCEPT_RCX_R11
+	call	mds_user_clear_buffers
+
+	IBRS_EXIT
+
 	movq	RIP(%rsp), %rcx
 	movq	EFLAGS(%rsp), %r11
+	RESTORE_C_REGS_EXCEPT_RCX_R11
+
+	/*
+	 * This opens a window where we have a user CR3, but are
+	 * running in the kernel.  This makes using the CS
+	 * register useless for telling whether or not we need to
+	 * switch CR3 in NMIs.  Normal interrupts are OK because
+	 * they are off here.
+	 */
+	SWITCH_USER_CR3
 	movq	RSP(%rsp), %rsp
 	/*
 	 * 64-bit SYSRET restores rip from rcx,
@@ -259,14 +289,21 @@
 	RESTORE_C_REGS_EXCEPT_RAX
 	RESTORE_EXTRA_REGS
 #if __SYSCALL_MASK == ~0
-	cmpq	$__NR_syscall_max, %rax
+	cmpq	$NR_syscalls, %rax
 #else
 	andl	$__SYSCALL_MASK, %eax
-	cmpl	$__NR_syscall_max, %eax
+	cmpl	$NR_syscalls, %eax
 #endif
-	ja	1f				/* return -ENOSYS (already in pt_regs->ax) */
+	jae	1f				/* return -ENOSYS (already in pt_regs->ax) */
+	sbb	%rcx, %rcx			/* array_index_mask_nospec() */
+	and	%rcx, %rax
 	movq	%r10, %rcx			/* fixup for C */
+#ifdef CONFIG_RETPOLINE
+	movq	sys_call_table(, %rax, 8), %rax
+	call	__x86_indirect_thunk_rax
+#else
 	call	*sys_call_table(, %rax, 8)
+#endif
 	movq	%rax, RAX(%rsp)
 1:
 	/* Use IRET because user could have changed pt_regs->foo */
@@ -345,12 +382,31 @@
 	 * perf profiles. Nothing jumps here.
 	 */
 syscall_return_via_sysret:
-	/* rcx and r11 are already restored (see code above) */
-	RESTORE_C_REGS_EXCEPT_RCX_R11
+	IBRS_EXIT
+
+	RESTORE_C_REGS
+
+	/*
+	 * This opens a window where we have a user CR3, but are
+	 * running in the kernel.  This makes using the CS
+	 * register useless for telling whether or not we need to
+	 * switch CR3 in NMIs.  Normal interrupts are OK because
+	 * they are off here.
+	 */
+	SWITCH_USER_CR3
 	movq	RSP(%rsp), %rsp
 	USERGS_SYSRET64
 
 opportunistic_sysret_failed:
+	IBRS_EXIT
+	/*
+	 * This opens a window where we have a user CR3, but are
+	 * running in the kernel.  This makes using the CS
+	 * register useless for telling whether or not we need to
+	 * switch CR3 in NMIs.  Normal interrupts are OK because
+	 * they are off here.
+	 */
+	SWITCH_USER_CR3
 	SWAPGS
 	jmp	restore_c_regs_and_iret
 END(entry_SYSCALL_64)
@@ -465,7 +521,7 @@
 	 * nb: we depend on RESTORE_EXTRA_REGS above
 	 */
 	movq	%rbp, %rdi
-	call	*%rbx
+	CALL_NOSPEC %rbx
 	movl	$0, RAX(%rsp)
 	RESTORE_EXTRA_REGS
 	jmp	int_ret_from_sys_call
@@ -509,6 +565,10 @@
 	 * tracking that we're in kernel mode.
 	 */
 	SWAPGS
+	FENCE_SWAPGS_USER_ENTRY
+	SWITCH_KERNEL_CR3
+
+	IBRS_ENTER
 
 	/*
 	 * We need to tell lockdep that IRQs are off.  We can't do this until
@@ -524,7 +584,10 @@
 	call enter_from_user_mode
 #endif
 
+	jmp	2f
 1:
+	FENCE_SWAPGS_KERNEL_ENTRY
+2:
 	/*
 	 * Save previous stack pointer, optionally switch to interrupt stack.
 	 * irq_count is used to check if a CPU is already on an interrupt stack
@@ -568,6 +631,8 @@
 	mov	%rsp,%rdi
 	call	prepare_exit_to_usermode
 	TRACE_IRQS_IRETQ
+	IBRS_EXIT
+	SWITCH_USER_CR3
 	SWAPGS
 	jmp	restore_regs_and_iret
 
@@ -576,7 +641,7 @@
 #ifdef CONFIG_PREEMPT
 	/* Interrupts are off */
 	/* Check if we need preemption */
-	bt	$9, EFLAGS(%rsp)		/* were interrupts off? */
+	btl	$9, EFLAGS(%rsp)		/* were interrupts off? */
 	jnc	1f
 0:	cmpl	$0, PER_CPU_VAR(__preempt_count)
 	jnz	1f
@@ -625,6 +690,7 @@
 	pushq	%rax
 	pushq	%rdi
 	SWAPGS
+	SWITCH_KERNEL_CR3
 	movq	PER_CPU_VAR(espfix_waddr), %rdi
 	movq	%rax, (0*8)(%rdi)		/* RAX */
 	movq	(2*8)(%rsp), %rax		/* RIP */
@@ -640,6 +706,7 @@
 	andl	$0xffff0000, %eax
 	popq	%rdi
 	orq	PER_CPU_VAR(espfix_stack), %rax
+	SWITCH_USER_CR3
 	SWAPGS
 	movq	%rax, %rsp
 	popq	%rax
@@ -810,7 +877,7 @@
 
 	call	\do_sym
 
-	jmp	error_exit			/* %ebx: no swapgs flag */
+	jmp	error_exit
 	.endif
 END(\sym)
 .endm
@@ -972,7 +1039,7 @@
 #endif /* CONFIG_HYPERV */
 
 idtentry debug			do_debug		has_error_code=0	paranoid=1 shift_ist=DEBUG_STACK
-idtentry int3			do_int3			has_error_code=0	paranoid=1 shift_ist=DEBUG_STACK
+idtentry int3			do_int3			has_error_code=0
 idtentry stack_segment		do_stack_segment	has_error_code=1
 
 #ifdef CONFIG_XEN
@@ -989,13 +1056,17 @@
 #endif
 
 #ifdef CONFIG_X86_MCE
-idtentry machine_check					has_error_code=0	paranoid=1 do_sym=*machine_check_vector(%rip)
+idtentry machine_check		do_mce			has_error_code=0	paranoid=1
 #endif
 
 /*
  * Save all registers in pt_regs, and switch gs if needed.
  * Use slow, but surefire "are we in kernel?" check.
- * Return: ebx=0: need swapgs on exit, ebx=1: otherwise
+ *
+ * Return: ebx=0: needs swapgs but not SWITCH_USER_CR3 in paranoid_exit
+ *         ebx=1: needs neither swapgs nor SWITCH_USER_CR3 in paranoid_exit
+ *         ebx=2: needs both swapgs and SWITCH_USER_CR3 in paranoid_exit
+ *         ebx=3: needs SWITCH_USER_CR3 but not swapgs in paranoid_exit
  */
 ENTRY(paranoid_entry)
 	cld
@@ -1008,7 +1079,39 @@
 	js	1f				/* negative -> in kernel */
 	SWAPGS
 	xorl	%ebx, %ebx
-1:	ret
+1:
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	/*
+	 * We might have come in between a swapgs and a SWITCH_KERNEL_CR3
+	 * on entry, or between a SWITCH_USER_CR3 and a swapgs on exit.
+	 * Do a conditional SWITCH_KERNEL_CR3: this could safely be done
+	 * unconditionally, but we need to find out whether the reverse
+	 * should be done on return (conveyed to paranoid_exit in %ebx).
+	 */
+	ALTERNATIVE "jmp 2f", "movq %cr3, %rax", X86_FEATURE_KAISER
+	testl	$KAISER_SHADOW_PGD_OFFSET, %eax
+	jz	2f
+	orl	$2, %ebx
+	andq	$(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax
+	/* If PCID enabled, set X86_CR3_PCID_NOFLUSH_BIT */
+	ALTERNATIVE "", "bts $63, %rax", X86_FEATURE_PCID
+	movq	%rax, %cr3
+2:
+#endif
+	/*
+	 * The above CR3 update sequence doesn't do an
+	 * unconditional CR3 write, even in the PTI case.  So do an lfence
+	 * to prevent GS speculation, regardless of whether PTI is enabled.
+	 */
+	FENCE_SWAPGS_KERNEL_ENTRY
+
+	/*
+	 * Once we have CR3 and %GS setup save and set SPEC_CTRL. Just like
+	 * CR3 above, keep the old value in a callee saved register.
+	 */
+	IBRS_ENTER save_reg=%r15
+
+	ret
 END(paranoid_entry)
 
 /*
@@ -1021,19 +1124,33 @@
  * be complicated.  Fortunately, we there's no good reason
  * to try to handle preemption here.
  *
- * On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it)
+ * On entry: ebx=0: needs swapgs but not SWITCH_USER_CR3
+ *           ebx=1: needs neither swapgs nor SWITCH_USER_CR3
+ *           ebx=2: needs both swapgs and SWITCH_USER_CR3
+ *           ebx=3: needs SWITCH_USER_CR3 but not swapgs
  */
 ENTRY(paranoid_exit)
+
+	/*
+	 * Must restore IBRS state before both CR3 and %GS since we need access
+	 * to the per-CPU x86_spec_ctrl_shadow variable.
+	 */
+	IBRS_EXIT save_reg=%r15
+
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF_DEBUG
-	testl	%ebx, %ebx			/* swapgs needed? */
+	TRACE_IRQS_IRETQ_DEBUG
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	/* No ALTERNATIVE for X86_FEATURE_KAISER: paranoid_entry sets %ebx */
+	testl	$2, %ebx			/* SWITCH_USER_CR3 needed? */
+	jz	paranoid_exit_no_switch
+	SWITCH_USER_CR3
+paranoid_exit_no_switch:
+#endif
+	testl	$1, %ebx			/* swapgs needed? */
 	jnz	paranoid_exit_no_swapgs
-	TRACE_IRQS_IRETQ
 	SWAPGS_UNSAFE_STACK
-	jmp	paranoid_exit_restore
 paranoid_exit_no_swapgs:
-	TRACE_IRQS_IRETQ_DEBUG
-paranoid_exit_restore:
 	RESTORE_EXTRA_REGS
 	RESTORE_C_REGS
 	REMOVE_PT_GPREGS_FROM_STACK 8
@@ -1042,22 +1159,28 @@
 
 /*
  * Save all registers in pt_regs, and switch gs if needed.
- * Return: EBX=0: came from user mode; EBX=1: otherwise
  */
 ENTRY(error_entry)
 	cld
 	SAVE_C_REGS 8
 	SAVE_EXTRA_REGS 8
-	xorl	%ebx, %ebx
+	/*
+	 * error_entry() always returns with a kernel gsbase and
+	 * CR3.  We must also have a kernel CR3/gsbase before
+	 * calling TRACE_IRQS_*.  Just unconditionally switch to
+	 * the kernel CR3 here.
+	 */
+	SWITCH_KERNEL_CR3
 	testb	$3, CS+8(%rsp)
 	jz	.Lerror_kernelspace
 
-.Lerror_entry_from_usermode_swapgs:
 	/*
 	 * We entered from user mode or we're pretending to have entered
 	 * from user mode due to an IRET fault.
 	 */
 	SWAPGS
+	FENCE_SWAPGS_USER_ENTRY
+	IBRS_ENTER
 
 .Lerror_entry_from_usermode_after_swapgs:
 	/*
@@ -1071,6 +1194,8 @@
 #endif
 	ret
 
+.Lerror_entry_done_lfence:
+	FENCE_SWAPGS_KERNEL_ENTRY
 .Lerror_entry_done:
 	TRACE_IRQS_OFF
 	ret
@@ -1082,7 +1207,6 @@
 	 * for these here too.
 	 */
 .Lerror_kernelspace:
-	incl	%ebx
 	leaq	native_irq_return_iret(%rip), %rcx
 	cmpq	%rcx, RIP+8(%rsp)
 	je	.Lerror_bad_iret
@@ -1090,14 +1214,15 @@
 	cmpq	%rax, RIP+8(%rsp)
 	je	.Lbstep_iret
 	cmpq	$gs_change, RIP+8(%rsp)
-	jne	.Lerror_entry_done
+	jne	.Lerror_entry_done_lfence
 
 	/*
 	 * hack: gs_change can fail with user gsbase.  If this happens, fix up
 	 * gsbase and proceed.  We'll fix up the exception and land in
 	 * gs_change's error handler with kernel gsbase.
 	 */
-	jmp	.Lerror_entry_from_usermode_swapgs
+	SWAPGS
+	jmp .Lerror_entry_done
 
 .Lbstep_iret:
 	/* Fix truncated RIP */
@@ -1110,31 +1235,24 @@
 	 * Switch to kernel gsbase:
 	 */
 	SWAPGS
+	FENCE_SWAPGS_USER_ENTRY
+	IBRS_ENTER
 
 	/*
 	 * Pretend that the exception came from user mode: set up pt_regs
-	 * as if we faulted immediately after IRET and clear EBX so that
-	 * error_exit knows that we will be returning to user mode.
+	 * as if we faulted immediately after IRET.
 	 */
 	mov	%rsp, %rdi
 	call	fixup_bad_iret
 	mov	%rax, %rsp
-	decl	%ebx
 	jmp	.Lerror_entry_from_usermode_after_swapgs
 END(error_entry)
 
-
-/*
- * On entry, EBS is a "return to kernel mode" flag:
- *   1: already in kernel mode, don't need SWAPGS
- *   0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode
- */
 ENTRY(error_exit)
-	movl	%ebx, %eax
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
-	testl	%eax, %eax
-	jnz	retint_kernel
+	testb	$3, CS(%rsp)
+	jz	retint_kernel
 	jmp	retint_user
 END(error_exit)
 
@@ -1190,6 +1308,8 @@
 	 * other IST entries.
 	 */
 
+	ASM_CLAC
+
 	/* Use %rdx as our temp variable throughout */
 	pushq	%rdx
 
@@ -1208,7 +1328,12 @@
 	 */
 
 	SWAPGS_UNSAFE_STACK
+	/*
+	 * percpu variables are mapped with user CR3, so no need
+	 * to switch CR3 here.
+	 */
 	cld
+	FENCE_SWAPGS_USER_ENTRY
 	movq	%rsp, %rdx
 	movq	PER_CPU_VAR(cpu_current_top_of_stack), %rsp
 	pushq	5*8(%rdx)	/* pt_regs->ss */
@@ -1241,12 +1366,39 @@
 
 	movq	%rsp, %rdi
 	movq	$-1, %rsi
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	/* Unconditionally use kernel CR3 for do_nmi() */
+	/* %rax is saved above, so OK to clobber here */
+	ALTERNATIVE "jmp 2f", "movq %cr3, %rax", X86_FEATURE_KAISER
+	/* If PCID enabled, NOFLUSH now and NOFLUSH on return */
+	ALTERNATIVE "", "bts $63, %rax", X86_FEATURE_PCID
+	pushq	%rax
+	/* mask off "user" bit of pgd address and 12 PCID bits: */
+	andq	$(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax
+	movq	%rax, %cr3
+2:
+#endif
+
+	IBRS_ENTER
+
 	call	do_nmi
 
+	IBRS_EXIT
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	/*
+	 * Unconditionally restore CR3.  I know we return to
+	 * kernel code that needs user CR3, but do we ever return
+	 * to "user mode" where we need the kernel CR3?
+	 */
+	ALTERNATIVE "", "popq %rax; movq %rax, %cr3", X86_FEATURE_KAISER
+#endif
+
 	/*
 	 * Return back to user mode.  We must *not* do the normal exit
-	 * work, because we don't want to enable interrupts.  Fortunately,
-	 * do_nmi doesn't modify pt_regs.
+	 * work, because we don't want to enable interrupts.  Do not
+	 * switch to user CR3: we might be going back to kernel code
+	 * that had a user CR3 set.
 	 */
 	SWAPGS
 	jmp	restore_c_regs_and_iret
@@ -1443,22 +1595,65 @@
 	ALLOC_PT_GPREGS_ON_STACK
 
 	/*
-	 * Use paranoid_entry to handle SWAPGS, but no need to use paranoid_exit
-	 * as we should not be calling schedule in NMI context.
-	 * Even with normal interrupts enabled. An NMI should not be
-	 * setting NEED_RESCHED or anything that normal interrupts and
-	 * exceptions might do.
+	 * Use the same approach as paranoid_entry to handle SWAPGS, but
+	 * without CR3 handling since we do that differently in NMIs.  No
+	 * need to use paranoid_exit as we should not be calling schedule
+	 * in NMI context.  Even with normal interrupts enabled. An NMI
+	 * should not be setting NEED_RESCHED or anything that normal
+	 * interrupts and exceptions might do.
 	 */
-	call	paranoid_entry
-
-	/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
+	cld
+	SAVE_C_REGS
+	SAVE_EXTRA_REGS
+	movl	$1, %ebx
+	movl	$MSR_GS_BASE, %ecx
+	rdmsr
+	testl	%edx, %edx
+	js	1f				/* negative -> in kernel */
+	SWAPGS
+	xorl	%ebx, %ebx
+1:
 	movq	%rsp, %rdi
 	movq	$-1, %rsi
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	/* Unconditionally use kernel CR3 for do_nmi() */
+	/* %rax is saved above, so OK to clobber here */
+	ALTERNATIVE "jmp 2f", "movq %cr3, %rax", X86_FEATURE_KAISER
+	/* If PCID enabled, NOFLUSH now and NOFLUSH on return */
+	ALTERNATIVE "", "bts $63, %rax", X86_FEATURE_PCID
+	pushq	%rax
+	/* mask off "user" bit of pgd address and 12 PCID bits: */
+	andq	$(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax
+	movq	%rax, %cr3
+2:
+#endif
+	/*
+	 * The above CR3 update sequence doesn't do a CR3 write in the non-PTI
+	 * case.  So do an lfence to prevent GS speculation.
+	 */
+	FENCE_SWAPGS_KERNEL_ENTRY
+
+	IBRS_ENTER save_reg=%r15
+
+	/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
 	call	do_nmi
 
+	/* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
+	IBRS_EXIT save_reg=%r15
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	/*
+	 * Unconditionally restore CR3.  We might be returning to
+	 * kernel code that needs user CR3, like just just before
+	 * a sysret.
+	 */
+	ALTERNATIVE "", "popq %rax; movq %rax, %cr3", X86_FEATURE_KAISER
+#endif
+
 	testl	%ebx, %ebx			/* swapgs needed? */
 	jnz	nmi_restore
 nmi_swapgs:
+	/* We fixed up CR3 above, so no need to switch it here */
 	SWAPGS_UNSAFE_STACK
 nmi_restore:
 	RESTORE_EXTRA_REGS
@@ -1490,3 +1685,63 @@
 	mov	$-ENOSYS, %eax
 	sysret
 END(ignore_sysret)
+
+/*
+ * This sequence executes branches in order to remove user branch information
+ * from the branch history tracker in the Branch Predictor, therefore removing
+ * user influence on subsequent BTB lookups.
+ *
+ * It should be used on parts prior to Alder Lake. Newer parts should use the
+ * BHI_DIS_S hardware control instead. If a pre-Alder Lake part is being
+ * virtualized on newer hardware the VMM should protect against BHI attacks by
+ * setting BHI_DIS_S for the guests.
+ *
+ * CALLs/RETs are necessary to prevent Loop Stream Detector(LSD) from engaging
+ * and not clearing the branch history. The call tree looks like:
+ *
+ * call 1
+ *    call 2
+ *      call 2
+ *        call 2
+ *          call 2
+ * 	      call 2
+ * 	      ret
+ * 	    ret
+ *        ret
+ *      ret
+ *    ret
+ * ret
+ *
+ * This means that the stack is non-constant and ORC can't unwind it with %rsp
+ * alone.  Therefore we unconditionally set up the frame pointer, which allows
+ * ORC to unwind properly.
+ *
+ * The alignment is for performance and not for safety, and may be safely
+ * refactored in the future if needed.
+ */
+ENTRY(clear_bhb_loop)
+	push	%rbp
+	mov	%rsp, %rbp
+	push	%rax
+	push	%rcx
+	movl	$5, %ecx
+	call	1f
+	jmp	5f
+	.align 64, 0xcc
+1:	call	2f
+	RET
+	.align 64, 0xcc
+2:	movl	$5, %eax
+3:	jmp	4f
+	nop
+4:	sub	$1, %eax
+	jnz	3b
+	sub	$1, %ecx
+	jnz	1b
+	RET
+5:	lfence
+	pop	%rcx
+	pop	%rax
+	pop	%rbp
+	RET
+ENDPROC(clear_bhb_loop)
--- linux-4.4.0.orig/arch/x86/entry/entry_64_compat.S
+++ linux-4.4.0/arch/x86/entry/entry_64_compat.S
@@ -3,7 +3,6 @@
  *
  * Copyright 2000-2002 Andi Kleen, SuSE Labs.
  */
-#include "calling.h"
 #include <asm/asm-offsets.h>
 #include <asm/current.h>
 #include <asm/errno.h>
@@ -13,9 +12,14 @@
 #include <asm/irqflags.h>
 #include <asm/asm.h>
 #include <asm/smap.h>
+#include <asm/pgtable_types.h>
+#include <asm/kaiser.h>
+#include <asm/spec_ctrl.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
+#include "calling.h"
+
 	.section .entry.text, "ax"
 
 #ifdef CONFIG_PARAVIRT
@@ -50,6 +54,7 @@
 ENTRY(entry_SYSENTER_compat)
 	/* Interrupts are off on entry. */
 	SWAPGS_UNSAFE_STACK
+	SWITCH_KERNEL_CR3_NO_STACK
 	movq	PER_CPU_VAR(cpu_current_top_of_stack), %rsp
 
 	/*
@@ -76,24 +81,33 @@
 	ASM_CLAC			/* Clear AC after saving FLAGS */
 
 	pushq	$__USER32_CS		/* pt_regs->cs */
-	xorq    %r8,%r8
-	pushq	%r8			/* pt_regs->ip = 0 (placeholder) */
+	pushq	$0			/* pt_regs->ip = 0 (placeholder) */
 	pushq	%rax			/* pt_regs->orig_ax */
 	pushq	%rdi			/* pt_regs->di */
 	pushq	%rsi			/* pt_regs->si */
 	pushq	%rdx			/* pt_regs->dx */
 	pushq	%rcx			/* pt_regs->cx */
 	pushq	$-ENOSYS		/* pt_regs->ax */
-	pushq   %r8                     /* pt_regs->r8  = 0 */
-	pushq   %r8                     /* pt_regs->r9  = 0 */
-	pushq   %r8                     /* pt_regs->r10 = 0 */
-	pushq   %r8                     /* pt_regs->r11 = 0 */
+	pushq   $0			/* pt_regs->r8  = 0 */
+	xorq	%r8, %r8		/* nospec   r8 */
+	pushq   $0			/* pt_regs->r9  = 0 */
+	xorq	%r9, %r9		/* nospec   r9 */
+	pushq   $0			/* pt_regs->r10 = 0 */
+	xorq	%r10, %r10		/* nospec   r10 */
+	pushq   $0			/* pt_regs->r11 = 0 */
+	xorq	%r11, %r11		/* nospec   r11 */
 	pushq   %rbx                    /* pt_regs->rbx */
+	xorl	%ebx, %ebx		/* nospec   rbx */
 	pushq   %rbp                    /* pt_regs->rbp (will be overwritten) */
-	pushq   %r8                     /* pt_regs->r12 = 0 */
-	pushq   %r8                     /* pt_regs->r13 = 0 */
-	pushq   %r8                     /* pt_regs->r14 = 0 */
-	pushq   %r8                     /* pt_regs->r15 = 0 */
+	xorl	%ebp, %ebp		/* nospec   rbp */
+	pushq   $0			/* pt_regs->r12 = 0 */
+	xorq	%r12, %r12		/* nospec   r12 */
+	pushq   $0			/* pt_regs->r13 = 0 */
+	xorq	%r13, %r13		/* nospec   r13 */
+	pushq   $0			/* pt_regs->r14 = 0 */
+	xorq	%r14, %r14		/* nospec   r14 */
+	pushq   $0			/* pt_regs->r15 = 0 */
+	xorq	%r15, %r15		/* nospec   r15 */
 	cld
 
 	/*
@@ -119,6 +133,15 @@
 	 */
 	TRACE_IRQS_OFF
 
+	/*
+	 * CPU bugs mitigations mechanisms can call other functions. They
+	 * should be invoked after making sure TF is cleared because
+	 * single-step is ignored only for instructions inside the
+	 * entry_SYSENTER_compat function.
+	 */
+	IBRS_ENTER
+	CLEAR_BRANCH_HISTORY
+
 	movq	%rsp, %rdi
 	call	do_fast_syscall_32
 	/* XEN PV guests always use IRET path */
@@ -161,6 +184,7 @@
 ENTRY(entry_SYSCALL_compat)
 	/* Interrupts are off on entry. */
 	SWAPGS_UNSAFE_STACK
+	SWITCH_KERNEL_CR3_NO_STACK
 
 	/* Stash user ESP and switch to the kernel stack. */
 	movl	%esp, %r8d
@@ -181,17 +205,26 @@
 	pushq	%rdx			/* pt_regs->dx */
 	pushq	%rbp			/* pt_regs->cx (stashed in bp) */
 	pushq	$-ENOSYS		/* pt_regs->ax */
-	xorq    %r8,%r8
-	pushq   %r8                     /* pt_regs->r8  = 0 */
-	pushq   %r8                     /* pt_regs->r9  = 0 */
-	pushq   %r8                     /* pt_regs->r10 = 0 */
-	pushq   %r8                     /* pt_regs->r11 = 0 */
+	pushq   $0			/* pt_regs->r8  = 0 */
+	xorq	%r8, %r8		/* nospec   r8 */
+	pushq   $0			/* pt_regs->r9  = 0 */
+	xorq	%r9, %r9		/* nospec   r9 */
+	pushq   $0			/* pt_regs->r10 = 0 */
+	xorq	%r10, %r10		/* nospec   r10 */
+	pushq   $0			/* pt_regs->r11 = 0 */
+	xorq	%r11, %r11		/* nospec   r11 */
 	pushq   %rbx                    /* pt_regs->rbx */
+	xorl	%ebx, %ebx		/* nospec   rbx */
 	pushq   %rbp                    /* pt_regs->rbp (will be overwritten) */
-	pushq   %r8                     /* pt_regs->r12 = 0 */
-	pushq   %r8                     /* pt_regs->r13 = 0 */
-	pushq   %r8                     /* pt_regs->r14 = 0 */
-	pushq   %r8                     /* pt_regs->r15 = 0 */
+	xorl	%ebp, %ebp		/* nospec   rbp */
+	pushq   $0			/* pt_regs->r12 = 0 */
+	xorq	%r12, %r12		/* nospec   r12 */
+	pushq   $0			/* pt_regs->r13 = 0 */
+	xorq	%r13, %r13		/* nospec   r13 */
+	pushq   $0			/* pt_regs->r14 = 0 */
+	xorq	%r14, %r14		/* nospec   r14 */
+	pushq   $0			/* pt_regs->r15 = 0 */
+	xorq	%r15, %r15		/* nospec   r15 */
 
 	/*
 	 * User mode is traced as though IRQs are on, and SYSENTER
@@ -199,6 +232,9 @@
 	 */
 	TRACE_IRQS_OFF
 
+	IBRS_ENTER
+	CLEAR_BRANCH_HISTORY
+
 	movq	%rsp, %rdi
 	call	do_fast_syscall_32
 	/* XEN PV guests always use IRET path */
@@ -208,6 +244,9 @@
 	/* Opportunistic SYSRET */
 sysret32_from_system_call:
 	TRACE_IRQS_ON			/* User mode traces as IRQs on. */
+	IBRS_EXIT
+	SWITCH_USER_CR3
+
 	movq	RBX(%rsp), %rbx		/* pt_regs->rbx */
 	movq	RBP(%rsp), %rbp		/* pt_regs->rbp */
 	movq	EFLAGS(%rsp), %r11	/* pt_regs->flags (in r11) */
@@ -267,7 +306,9 @@
 	 * Interrupts are off on entry.
 	 */
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
+	ASM_CLAC			/* Do this early to minimize exposure */
 	SWAPGS
+	SWITCH_KERNEL_CR3_NO_STACK
 
 	/*
 	 * User tracing code (ptrace or signal handlers) might assume that
@@ -285,17 +326,26 @@
 	pushq	%rdx			/* pt_regs->dx */
 	pushq	%rcx			/* pt_regs->cx */
 	pushq	$-ENOSYS		/* pt_regs->ax */
-	xorq    %r8,%r8
-	pushq   %r8                     /* pt_regs->r8  = 0 */
-	pushq   %r8                     /* pt_regs->r9  = 0 */
-	pushq   %r8                     /* pt_regs->r10 = 0 */
-	pushq   %r8                     /* pt_regs->r11 = 0 */
+	pushq   $0			/* pt_regs->r8  = 0 */
+	xorq	%r8, %r8		/* nospec   r8 */
+	pushq   $0			/* pt_regs->r9  = 0 */
+	xorq	%r9, %r9		/* nospec   r9 */
+	pushq   $0			/* pt_regs->r10 = 0 */
+	xorq	%r10, %r10		/* nospec   r10 */
+	pushq   $0			/* pt_regs->r11 = 0 */
+	xorq	%r11, %r11		/* nospec   r11 */
 	pushq   %rbx                    /* pt_regs->rbx */
+	xorl	%ebx, %ebx		/* nospec   rbx */
 	pushq   %rbp                    /* pt_regs->rbp */
+	xorl	%ebp, %ebp		/* nospec   rbp */
 	pushq   %r12                    /* pt_regs->r12 */
+	xorq	%r12, %r12		/* nospec   r12 */
 	pushq   %r13                    /* pt_regs->r13 */
+	xorq	%r13, %r13		/* nospec   r13 */
 	pushq   %r14                    /* pt_regs->r14 */
+	xorq	%r14, %r14		/* nospec   r14 */
 	pushq   %r15                    /* pt_regs->r15 */
+	xorq	%r15, %r15		/* nospec   r15 */
 	cld
 
 	/*
@@ -304,12 +354,16 @@
 	 */
 	TRACE_IRQS_OFF
 
+	IBRS_ENTER
+	CLEAR_BRANCH_HISTORY
+
 	movq	%rsp, %rdi
 	call	do_syscall_32_irqs_off
 .Lsyscall_32_done:
 
 	/* Go back to user mode. */
 	TRACE_IRQS_ON
+	SWITCH_USER_CR3
 	SWAPGS
 	jmp	restore_regs_and_iret
 END(entry_INT80_compat)
--- linux-4.4.0.orig/arch/x86/entry/syscalls/syscall_32.tbl
+++ linux-4.4.0/arch/x86/entry/syscalls/syscall_32.tbl
@@ -294,7 +294,7 @@
 # 285 sys_setaltroot
 286	i386	add_key			sys_add_key
 287	i386	request_key		sys_request_key
-288	i386	keyctl			sys_keyctl
+288	i386	keyctl			sys_keyctl			compat_sys_keyctl
 289	i386	ioprio_set		sys_ioprio_set
 290	i386	ioprio_get		sys_ioprio_get
 291	i386	inotify_init		sys_inotify_init
--- linux-4.4.0.orig/arch/x86/entry/vdso/Makefile
+++ linux-4.4.0/arch/x86/entry/vdso/Makefile
@@ -43,7 +43,7 @@
 
 VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
 			-Wl,--no-undefined \
-			-Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \
+			-Wl,-z,max-page-size=4096 \
 			$(DISABLE_LTO)
 
 $(obj)/vdso64.so.dbg: $(src)/vdso.lds $(vobjs) FORCE
@@ -92,8 +92,7 @@
 CPPFLAGS_vdsox32.lds = $(CPPFLAGS_vdso.lds)
 VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \
 			   -Wl,-soname=linux-vdso.so.1 \
-			   -Wl,-z,max-page-size=4096 \
-			   -Wl,-z,common-page-size=4096
+			   -Wl,-z,max-page-size=4096
 
 # 64-bit objects to re-brand as x32
 vobjs64-for-x32 := $(filter-out $(vobjs-nox32),$(vobjs-y))
--- linux-4.4.0.orig/arch/x86/entry/vdso/vclock_gettime.c
+++ linux-4.4.0/arch/x86/entry/vdso/vclock_gettime.c
@@ -13,7 +13,6 @@
 
 #include <uapi/linux/time.h>
 #include <asm/vgtod.h>
-#include <asm/hpet.h>
 #include <asm/vvar.h>
 #include <asm/unistd.h>
 #include <asm/msr.h>
@@ -26,14 +25,9 @@
 extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz);
 extern time_t __vdso_time(time_t *t);
 
-#ifdef CONFIG_HPET_TIMER
-extern u8 hpet_page
+#ifdef CONFIG_PARAVIRT_CLOCK
+extern u8 pvclock_page
 	__attribute__((visibility("hidden")));
-
-static notrace cycle_t vread_hpet(void)
-{
-	return *(const volatile u32 *)(&hpet_page + HPET_COUNTER);
-}
 #endif
 
 #ifndef BUILD_VDSO32
@@ -46,8 +40,9 @@
 notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
 {
 	long ret;
-	asm("syscall" : "=a" (ret) :
-	    "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory");
+	asm ("syscall" : "=a" (ret), "=m" (*ts) :
+	     "0" (__NR_clock_gettime), "D" (clock), "S" (ts) :
+	     "memory", "rcx", "r11");
 	return ret;
 }
 
@@ -55,70 +50,73 @@
 {
 	long ret;
 
-	asm("syscall" : "=a" (ret) :
-	    "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+	asm ("syscall" : "=a" (ret), "=m" (*tv), "=m" (*tz) :
+	     "0" (__NR_gettimeofday), "D" (tv), "S" (tz) :
+	     "memory", "rcx", "r11");
 	return ret;
 }
 
 #ifdef CONFIG_PARAVIRT_CLOCK
 
-static notrace const struct pvclock_vsyscall_time_info *get_pvti(int cpu)
+static notrace const struct pvclock_vsyscall_time_info *get_pvti0(void)
 {
-	const struct pvclock_vsyscall_time_info *pvti_base;
-	int idx = cpu / (PAGE_SIZE/PVTI_SIZE);
-	int offset = cpu % (PAGE_SIZE/PVTI_SIZE);
-
-	BUG_ON(PVCLOCK_FIXMAP_BEGIN + idx > PVCLOCK_FIXMAP_END);
-
-	pvti_base = (struct pvclock_vsyscall_time_info *)
-		    __fix_to_virt(PVCLOCK_FIXMAP_BEGIN+idx);
-
-	return &pvti_base[offset];
+	return (const struct pvclock_vsyscall_time_info *)&pvclock_page;
 }
 
 static notrace cycle_t vread_pvclock(int *mode)
 {
-	const struct pvclock_vsyscall_time_info *pvti;
+	const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti;
 	cycle_t ret;
-	u64 last;
-	u32 version;
-	u8 flags;
-	unsigned cpu, cpu1;
-
+	u64 tsc, pvti_tsc;
+	u64 last, delta, pvti_system_time;
+	u32 version, pvti_tsc_to_system_mul, pvti_tsc_shift;
 
 	/*
-	 * Note: hypervisor must guarantee that:
-	 * 1. cpu ID number maps 1:1 to per-CPU pvclock time info.
-	 * 2. that per-CPU pvclock time info is updated if the
-	 *    underlying CPU changes.
-	 * 3. that version is increased whenever underlying CPU
-	 *    changes.
+	 * Note: The kernel and hypervisor must guarantee that cpu ID
+	 * number maps 1:1 to per-CPU pvclock time info.
+	 *
+	 * Because the hypervisor is entirely unaware of guest userspace
+	 * preemption, it cannot guarantee that per-CPU pvclock time
+	 * info is updated if the underlying CPU changes or that that
+	 * version is increased whenever underlying CPU changes.
 	 *
+	 * On KVM, we are guaranteed that pvti updates for any vCPU are
+	 * atomic as seen by *all* vCPUs.  This is an even stronger
+	 * guarantee than we get with a normal seqlock.
+	 *
+	 * On Xen, we don't appear to have that guarantee, but Xen still
+	 * supplies a valid seqlock using the version field.
+
+	 * We only do pvclock vdso timing at all if
+	 * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to
+	 * mean that all vCPUs have matching pvti and that the TSC is
+	 * synced, so we can just look at vCPU 0's pvti.
 	 */
-	do {
-		cpu = __getcpu() & VGETCPU_CPU_MASK;
-		/* TODO: We can put vcpu id into higher bits of pvti.version.
-		 * This will save a couple of cycles by getting rid of
-		 * __getcpu() calls (Gleb).
-		 */
-
-		pvti = get_pvti(cpu);
-
-		version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags);
-
-		/*
-		 * Test we're still on the cpu as well as the version.
-		 * We could have been migrated just after the first
-		 * vgetcpu but before fetching the version, so we
-		 * wouldn't notice a version change.
-		 */
-		cpu1 = __getcpu() & VGETCPU_CPU_MASK;
-	} while (unlikely(cpu != cpu1 ||
-			  (pvti->pvti.version & 1) ||
-			  pvti->pvti.version != version));
 
-	if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT)))
+	if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) {
 		*mode = VCLOCK_NONE;
+		return 0;
+	}
+
+	do {
+		version = pvti->version;
+
+		/* This is also a read barrier, so we'll read version first. */
+		tsc = rdtsc_ordered();
+
+		pvti_tsc_to_system_mul = pvti->tsc_to_system_mul;
+		pvti_tsc_shift = pvti->tsc_shift;
+		pvti_system_time = pvti->system_time;
+		pvti_tsc = pvti->tsc_timestamp;
+
+		/* Make sure that the version double-check is last. */
+		smp_rmb();
+	} while (unlikely((version & 1) || version != pvti->version));
+
+	delta = tsc - pvti_tsc;
+	ret = pvti_system_time +
+		pvclock_scale_delta(delta, pvti_tsc_to_system_mul,
+				    pvti_tsc_shift);
 
 	/* refer to tsc.c read_tsc() comment for rationale */
 	last = gtod->cycle_last;
@@ -136,13 +134,13 @@
 {
 	long ret;
 
-	asm(
+	asm (
 		"mov %%ebx, %%edx \n"
-		"mov %2, %%ebx \n"
+		"mov %[clock], %%ebx \n"
 		"call __kernel_vsyscall \n"
 		"mov %%edx, %%ebx \n"
-		: "=a" (ret)
-		: "0" (__NR_clock_gettime), "g" (clock), "c" (ts)
+		: "=a" (ret), "=m" (*ts)
+		: "0" (__NR_clock_gettime), [clock] "g" (clock), "c" (ts)
 		: "memory", "edx");
 	return ret;
 }
@@ -151,13 +149,13 @@
 {
 	long ret;
 
-	asm(
+	asm (
 		"mov %%ebx, %%edx \n"
-		"mov %2, %%ebx \n"
+		"mov %[tv], %%ebx \n"
 		"call __kernel_vsyscall \n"
 		"mov %%edx, %%ebx \n"
-		: "=a" (ret)
-		: "0" (__NR_gettimeofday), "g" (tv), "c" (tz)
+		: "=a" (ret), "=m" (*tv), "=m" (*tz)
+		: "0" (__NR_gettimeofday), [tv] "g" (tv), "c" (tz)
 		: "memory", "edx");
 	return ret;
 }
@@ -200,10 +198,6 @@
 
 	if (gtod->vclock_mode == VCLOCK_TSC)
 		cycles = vread_tsc();
-#ifdef CONFIG_HPET_TIMER
-	else if (gtod->vclock_mode == VCLOCK_HPET)
-		cycles = vread_hpet();
-#endif
 #ifdef CONFIG_PARAVIRT_CLOCK
 	else if (gtod->vclock_mode == VCLOCK_PVCLOCK)
 		cycles = vread_pvclock(mode);
--- linux-4.4.0.orig/arch/x86/entry/vdso/vdso-layout.lds.S
+++ linux-4.4.0/arch/x86/entry/vdso/vdso-layout.lds.S
@@ -35,7 +35,7 @@
 #undef __VVAR_KERNEL_LDS
 #undef EMIT_VVAR
 
-	hpet_page = vvar_start + PAGE_SIZE;
+	pvclock_page = vvar_start + PAGE_SIZE;
 
 	. = SIZEOF_HEADERS;
 
--- linux-4.4.0.orig/arch/x86/entry/vdso/vdso2c.c
+++ linux-4.4.0/arch/x86/entry/vdso/vdso2c.c
@@ -73,6 +73,7 @@
 	sym_vvar_start,
 	sym_vvar_page,
 	sym_hpet_page,
+	sym_pvclock_page,
 	sym_VDSO_FAKE_SECTION_TABLE_START,
 	sym_VDSO_FAKE_SECTION_TABLE_END,
 };
@@ -80,6 +81,7 @@
 const int special_pages[] = {
 	sym_vvar_page,
 	sym_hpet_page,
+	sym_pvclock_page,
 };
 
 struct vdso_sym {
@@ -91,6 +93,7 @@
 	[sym_vvar_start] = {"vvar_start", true},
 	[sym_vvar_page] = {"vvar_page", true},
 	[sym_hpet_page] = {"hpet_page", true},
+	[sym_pvclock_page] = {"pvclock_page", true},
 	[sym_VDSO_FAKE_SECTION_TABLE_START] = {
 		"VDSO_FAKE_SECTION_TABLE_START", false
 	},
--- linux-4.4.0.orig/arch/x86/entry/vdso/vdso32-setup.c
+++ linux-4.4.0/arch/x86/entry/vdso/vdso32-setup.c
@@ -10,8 +10,8 @@
 #include <linux/smp.h>
 #include <linux/kernel.h>
 #include <linux/mm_types.h>
+#include <linux/elf.h>
 
-#include <asm/cpufeature.h>
 #include <asm/processor.h>
 #include <asm/vdso.h>
 
@@ -31,8 +31,10 @@
 {
 	vdso32_enabled = simple_strtoul(s, NULL, 0);
 
-	if (vdso32_enabled > 1)
+	if (vdso32_enabled > 1) {
 		pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");
+		vdso32_enabled = 0;
+	}
 
 	return 1;
 }
@@ -63,13 +65,18 @@
 /* Register vsyscall32 into the ABI table */
 #include <linux/sysctl.h>
 
+static const int zero;
+static const int one = 1;
+
 static struct ctl_table abi_table2[] = {
 	{
 		.procname	= "vsyscall32",
 		.data		= &vdso32_enabled,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= (int *)&zero,
+		.extra2		= (int *)&one,
 	},
 	{}
 };
--- linux-4.4.0.orig/arch/x86/entry/vdso/vdso32/system_call.S
+++ linux-4.4.0/arch/x86/entry/vdso/vdso32/system_call.S
@@ -3,7 +3,7 @@
 */
 
 #include <asm/dwarf2.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative-asm.h>
 
 /*
--- linux-4.4.0.orig/arch/x86/entry/vdso/vma.c
+++ linux-4.4.0/arch/x86/entry/vdso/vma.c
@@ -12,6 +12,7 @@
 #include <linux/random.h>
 #include <linux/elf.h>
 #include <linux/cpu.h>
+#include <asm/pvclock.h>
 #include <asm/vgtod.h>
 #include <asm/proto.h>
 #include <asm/vdso.h>
@@ -19,6 +20,7 @@
 #include <asm/page.h>
 #include <asm/hpet.h>
 #include <asm/desc.h>
+#include <asm/cpufeature.h>
 
 #if defined(CONFIG_X86_64)
 unsigned int __read_mostly vdso64_enabled = 1;
@@ -100,6 +102,7 @@
 		.name = "[vvar]",
 		.pages = no_pages,
 	};
+	struct pvclock_vsyscall_time_info *pvti;
 
 	if (calculate_addr) {
 		addr = vdso_addr(current->mm->start_stack,
@@ -169,6 +172,18 @@
 	}
 #endif
 
+	pvti = pvclock_pvti_cpu0_va();
+	if (pvti && image->sym_pvclock_page) {
+		ret = remap_pfn_range(vma,
+				      text_start + image->sym_pvclock_page,
+				      __pa(pvti) >> PAGE_SHIFT,
+				      PAGE_SIZE,
+				      PAGE_READONLY);
+
+		if (ret)
+			goto up_fail;
+	}
+
 up_fail:
 	if (ret)
 		current->mm->context.vdso = NULL;
@@ -240,7 +255,7 @@
 #ifdef CONFIG_NUMA
 	node = cpu_to_node(cpu);
 #endif
-	if (cpu_has(&cpu_data(cpu), X86_FEATURE_RDTSCP))
+	if (static_cpu_has(X86_FEATURE_RDTSCP))
 		write_rdtscp_aux((node << 12) | cpu);
 
 	/*
--- linux-4.4.0.orig/arch/x86/entry/vsyscall/vsyscall_64.c
+++ linux-4.4.0/arch/x86/entry/vsyscall/vsyscall_64.c
@@ -46,6 +46,7 @@
 #else
 	EMULATE;
 #endif
+unsigned long vsyscall_pgprot = __PAGE_KERNEL_VSYSCALL;
 
 static int __init vsyscall_setup(char *str)
 {
@@ -66,6 +67,11 @@
 }
 early_param("vsyscall", vsyscall_setup);
 
+bool vsyscall_enabled(void)
+{
+	return vsyscall_mode != NONE;
+}
+
 static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
 			      const char *message)
 {
@@ -331,11 +337,11 @@
 	extern char __vsyscall_page;
 	unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
 
+	if (vsyscall_mode != NATIVE)
+		vsyscall_pgprot = __PAGE_KERNEL_VVAR;
 	if (vsyscall_mode != NONE)
 		__set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
-			     vsyscall_mode == NATIVE
-			     ? PAGE_KERNEL_VSYSCALL
-			     : PAGE_KERNEL_VVAR);
+			     __pgprot(vsyscall_pgprot));
 
 	BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) !=
 		     (unsigned long)VSYSCALL_ADDR);
--- linux-4.4.0.orig/arch/x86/events/Makefile
+++ linux-4.4.0/arch/x86/events/Makefile
@@ -0,0 +1,13 @@
+obj-y			+= core.o
+
+obj-$(CONFIG_CPU_SUP_AMD)               += amd/core.o amd/uncore.o
+obj-$(CONFIG_X86_LOCAL_APIC)            += amd/ibs.o msr.o
+ifdef CONFIG_AMD_IOMMU
+obj-$(CONFIG_CPU_SUP_AMD)               += amd/iommu.o
+endif
+obj-$(CONFIG_CPU_SUP_INTEL)		+= intel/core.o intel/bts.o intel/cqm.o
+obj-$(CONFIG_CPU_SUP_INTEL)		+= intel/cstate.o intel/ds.o intel/knc.o 
+obj-$(CONFIG_CPU_SUP_INTEL)		+= intel/lbr.o intel/p4.o intel/p6.o intel/pt.o
+obj-$(CONFIG_CPU_SUP_INTEL)		+= intel/rapl.o msr.o
+obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE)	+= intel/uncore.o intel/uncore_nhmex.o
+obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE)	+= intel/uncore_snb.o intel/uncore_snbep.o
--- linux-4.4.0.orig/arch/x86/events/amd/core.c
+++ linux-4.4.0/arch/x86/events/amd/core.c
@@ -0,0 +1,731 @@
+#include <linux/perf_event.h>
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/apicdef.h>
+
+#include "../perf_event.h"
+
+static __initconst const u64 amd_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses        */
+		[ C(RESULT_MISS)   ] = 0x0141, /* Data Cache Misses          */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0267, /* Data Prefetcher :attempts  */
+		[ C(RESULT_MISS)   ] = 0x0167, /* Data Prefetcher :cancelled */
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0080, /* Instruction cache fetches  */
+		[ C(RESULT_MISS)   ] = 0x0081, /* Instruction cache misses   */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x014B, /* Prefetch Instructions :Load */
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x037D, /* Requests to L2 Cache :IC+DC */
+		[ C(RESULT_MISS)   ] = 0x037E, /* L2 Cache Misses : IC+DC     */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x017F, /* L2 Fill/Writeback           */
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses        */
+		[ C(RESULT_MISS)   ] = 0x0746, /* L1_DTLB_AND_L2_DLTB_MISS.ALL */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0080, /* Instruction fecthes        */
+		[ C(RESULT_MISS)   ] = 0x0385, /* L1_ITLB_AND_L2_ITLB_MISS.ALL */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c2, /* Retired Branch Instr.      */
+		[ C(RESULT_MISS)   ] = 0x00c3, /* Retired Mispredicted BI    */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0xb8e9, /* CPU Request to Memory, l+r */
+		[ C(RESULT_MISS)   ] = 0x98e9, /* CPU Request to Memory, r   */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+};
+
+/*
+ * AMD Performance Monitor K7 and later.
+ */
+static const u64 amd_perfmon_event_map[] =
+{
+  [PERF_COUNT_HW_CPU_CYCLES]			= 0x0076,
+  [PERF_COUNT_HW_INSTRUCTIONS]			= 0x00c0,
+  [PERF_COUNT_HW_CACHE_REFERENCES]		= 0x0080,
+  [PERF_COUNT_HW_CACHE_MISSES]			= 0x0081,
+  [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]		= 0x00c2,
+  [PERF_COUNT_HW_BRANCH_MISSES]			= 0x00c3,
+  [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND]	= 0x00d0, /* "Decoder empty" event */
+  [PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= 0x00d1, /* "Dispatch stalls" event */
+};
+
+static u64 amd_pmu_event_map(int hw_event)
+{
+	return amd_perfmon_event_map[hw_event];
+}
+
+/*
+ * Previously calculated offsets
+ */
+static unsigned int event_offsets[X86_PMC_IDX_MAX] __read_mostly;
+static unsigned int count_offsets[X86_PMC_IDX_MAX] __read_mostly;
+
+/*
+ * Legacy CPUs:
+ *   4 counters starting at 0xc0010000 each offset by 1
+ *
+ * CPUs with core performance counter extensions:
+ *   6 counters starting at 0xc0010200 each offset by 2
+ */
+static inline int amd_pmu_addr_offset(int index, bool eventsel)
+{
+	int offset;
+
+	if (!index)
+		return index;
+
+	if (eventsel)
+		offset = event_offsets[index];
+	else
+		offset = count_offsets[index];
+
+	if (offset)
+		return offset;
+
+	if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
+		offset = index;
+	else
+		offset = index << 1;
+
+	if (eventsel)
+		event_offsets[index] = offset;
+	else
+		count_offsets[index] = offset;
+
+	return offset;
+}
+
+static int amd_core_hw_config(struct perf_event *event)
+{
+	if (event->attr.exclude_host && event->attr.exclude_guest)
+		/*
+		 * When HO == GO == 1 the hardware treats that as GO == HO == 0
+		 * and will count in both modes. We don't want to count in that
+		 * case so we emulate no-counting by setting US = OS = 0.
+		 */
+		event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR |
+				      ARCH_PERFMON_EVENTSEL_OS);
+	else if (event->attr.exclude_host)
+		event->hw.config |= AMD64_EVENTSEL_GUESTONLY;
+	else if (event->attr.exclude_guest)
+		event->hw.config |= AMD64_EVENTSEL_HOSTONLY;
+
+	return 0;
+}
+
+/*
+ * AMD64 events are detected based on their event codes.
+ */
+static inline unsigned int amd_get_event_code(struct hw_perf_event *hwc)
+{
+	return ((hwc->config >> 24) & 0x0f00) | (hwc->config & 0x00ff);
+}
+
+static inline int amd_is_nb_event(struct hw_perf_event *hwc)
+{
+	return (hwc->config & 0xe0) == 0xe0;
+}
+
+static inline int amd_has_nb(struct cpu_hw_events *cpuc)
+{
+	struct amd_nb *nb = cpuc->amd_nb;
+
+	return nb && nb->nb_id != -1;
+}
+
+static int amd_pmu_hw_config(struct perf_event *event)
+{
+	int ret;
+
+	/* pass precise event sampling to ibs: */
+	if (event->attr.precise_ip && get_ibs_caps())
+		return -ENOENT;
+
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
+	ret = x86_pmu_hw_config(event);
+	if (ret)
+		return ret;
+
+	if (event->attr.type == PERF_TYPE_RAW)
+		event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK;
+
+	return amd_core_hw_config(event);
+}
+
+static void __amd_put_nb_event_constraints(struct cpu_hw_events *cpuc,
+					   struct perf_event *event)
+{
+	struct amd_nb *nb = cpuc->amd_nb;
+	int i;
+
+	/*
+	 * need to scan whole list because event may not have
+	 * been assigned during scheduling
+	 *
+	 * no race condition possible because event can only
+	 * be removed on one CPU at a time AND PMU is disabled
+	 * when we come here
+	 */
+	for (i = 0; i < x86_pmu.num_counters; i++) {
+		if (cmpxchg(nb->owners + i, event, NULL) == event)
+			break;
+	}
+}
+
+ /*
+  * AMD64 NorthBridge events need special treatment because
+  * counter access needs to be synchronized across all cores
+  * of a package. Refer to BKDG section 3.12
+  *
+  * NB events are events measuring L3 cache, Hypertransport
+  * traffic. They are identified by an event code >= 0xe00.
+  * They measure events on the NorthBride which is shared
+  * by all cores on a package. NB events are counted on a
+  * shared set of counters. When a NB event is programmed
+  * in a counter, the data actually comes from a shared
+  * counter. Thus, access to those counters needs to be
+  * synchronized.
+  *
+  * We implement the synchronization such that no two cores
+  * can be measuring NB events using the same counters. Thus,
+  * we maintain a per-NB allocation table. The available slot
+  * is propagated using the event_constraint structure.
+  *
+  * We provide only one choice for each NB event based on
+  * the fact that only NB events have restrictions. Consequently,
+  * if a counter is available, there is a guarantee the NB event
+  * will be assigned to it. If no slot is available, an empty
+  * constraint is returned and scheduling will eventually fail
+  * for this event.
+  *
+  * Note that all cores attached the same NB compete for the same
+  * counters to host NB events, this is why we use atomic ops. Some
+  * multi-chip CPUs may have more than one NB.
+  *
+  * Given that resources are allocated (cmpxchg), they must be
+  * eventually freed for others to use. This is accomplished by
+  * calling __amd_put_nb_event_constraints()
+  *
+  * Non NB events are not impacted by this restriction.
+  */
+static struct event_constraint *
+__amd_get_nb_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
+			       struct event_constraint *c)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct amd_nb *nb = cpuc->amd_nb;
+	struct perf_event *old;
+	int idx, new = -1;
+
+	if (!c)
+		c = &unconstrained;
+
+	if (cpuc->is_fake)
+		return c;
+
+	/*
+	 * detect if already present, if so reuse
+	 *
+	 * cannot merge with actual allocation
+	 * because of possible holes
+	 *
+	 * event can already be present yet not assigned (in hwc->idx)
+	 * because of successive calls to x86_schedule_events() from
+	 * hw_perf_group_sched_in() without hw_perf_enable()
+	 */
+	for_each_set_bit(idx, c->idxmsk, x86_pmu.num_counters) {
+		if (new == -1 || hwc->idx == idx)
+			/* assign free slot, prefer hwc->idx */
+			old = cmpxchg(nb->owners + idx, NULL, event);
+		else if (nb->owners[idx] == event)
+			/* event already present */
+			old = event;
+		else
+			continue;
+
+		if (old && old != event)
+			continue;
+
+		/* reassign to this slot */
+		if (new != -1)
+			cmpxchg(nb->owners + new, event, NULL);
+		new = idx;
+
+		/* already present, reuse */
+		if (old == event)
+			break;
+	}
+
+	if (new == -1)
+		return &emptyconstraint;
+
+	return &nb->event_constraints[new];
+}
+
+static struct amd_nb *amd_alloc_nb(int cpu)
+{
+	struct amd_nb *nb;
+	int i;
+
+	nb = kzalloc_node(sizeof(struct amd_nb), GFP_KERNEL, cpu_to_node(cpu));
+	if (!nb)
+		return NULL;
+
+	nb->nb_id = -1;
+
+	/*
+	 * initialize all possible NB constraints
+	 */
+	for (i = 0; i < x86_pmu.num_counters; i++) {
+		__set_bit(i, nb->event_constraints[i].idxmsk);
+		nb->event_constraints[i].weight = 1;
+	}
+	return nb;
+}
+
+static int amd_pmu_cpu_prepare(int cpu)
+{
+	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+
+	WARN_ON_ONCE(cpuc->amd_nb);
+
+	if (boot_cpu_data.x86_max_cores < 2)
+		return NOTIFY_OK;
+
+	cpuc->amd_nb = amd_alloc_nb(cpu);
+	if (!cpuc->amd_nb)
+		return NOTIFY_BAD;
+
+	return NOTIFY_OK;
+}
+
+static void amd_pmu_cpu_starting(int cpu)
+{
+	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+	void **onln = &cpuc->kfree_on_online[X86_PERF_KFREE_SHARED];
+	struct amd_nb *nb;
+	int i, nb_id;
+
+	cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY;
+
+	if (boot_cpu_data.x86_max_cores < 2)
+		return;
+
+	nb_id = amd_get_nb_id(cpu);
+	WARN_ON_ONCE(nb_id == BAD_APICID);
+
+	for_each_online_cpu(i) {
+		nb = per_cpu(cpu_hw_events, i).amd_nb;
+		if (WARN_ON_ONCE(!nb))
+			continue;
+
+		if (nb->nb_id == nb_id) {
+			*onln = cpuc->amd_nb;
+			cpuc->amd_nb = nb;
+			break;
+		}
+	}
+
+	cpuc->amd_nb->nb_id = nb_id;
+	cpuc->amd_nb->refcnt++;
+}
+
+static void amd_pmu_cpu_dead(int cpu)
+{
+	struct cpu_hw_events *cpuhw;
+
+	if (boot_cpu_data.x86_max_cores < 2)
+		return;
+
+	cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+	if (cpuhw->amd_nb) {
+		struct amd_nb *nb = cpuhw->amd_nb;
+
+		if (nb->nb_id == -1 || --nb->refcnt == 0)
+			kfree(nb);
+
+		cpuhw->amd_nb = NULL;
+	}
+}
+
+static struct event_constraint *
+amd_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
+			  struct perf_event *event)
+{
+	/*
+	 * if not NB event or no NB, then no constraints
+	 */
+	if (!(amd_has_nb(cpuc) && amd_is_nb_event(&event->hw)))
+		return &unconstrained;
+
+	return __amd_get_nb_event_constraints(cpuc, event, NULL);
+}
+
+static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
+				      struct perf_event *event)
+{
+	if (amd_has_nb(cpuc) && amd_is_nb_event(&event->hw))
+		__amd_put_nb_event_constraints(cpuc, event);
+}
+
+PMU_FORMAT_ATTR(event,	"config:0-7,32-35");
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *amd_format_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
+/* AMD Family 15h */
+
+#define AMD_EVENT_TYPE_MASK	0x000000F0ULL
+
+#define AMD_EVENT_FP		0x00000000ULL ... 0x00000010ULL
+#define AMD_EVENT_LS		0x00000020ULL ... 0x00000030ULL
+#define AMD_EVENT_DC		0x00000040ULL ... 0x00000050ULL
+#define AMD_EVENT_CU		0x00000060ULL ... 0x00000070ULL
+#define AMD_EVENT_IC_DE		0x00000080ULL ... 0x00000090ULL
+#define AMD_EVENT_EX_LS		0x000000C0ULL
+#define AMD_EVENT_DE		0x000000D0ULL
+#define AMD_EVENT_NB		0x000000E0ULL ... 0x000000F0ULL
+
+/*
+ * AMD family 15h event code/PMC mappings:
+ *
+ * type = event_code & 0x0F0:
+ *
+ * 0x000	FP	PERF_CTL[5:3]
+ * 0x010	FP	PERF_CTL[5:3]
+ * 0x020	LS	PERF_CTL[5:0]
+ * 0x030	LS	PERF_CTL[5:0]
+ * 0x040	DC	PERF_CTL[5:0]
+ * 0x050	DC	PERF_CTL[5:0]
+ * 0x060	CU	PERF_CTL[2:0]
+ * 0x070	CU	PERF_CTL[2:0]
+ * 0x080	IC/DE	PERF_CTL[2:0]
+ * 0x090	IC/DE	PERF_CTL[2:0]
+ * 0x0A0	---
+ * 0x0B0	---
+ * 0x0C0	EX/LS	PERF_CTL[5:0]
+ * 0x0D0	DE	PERF_CTL[2:0]
+ * 0x0E0	NB	NB_PERF_CTL[3:0]
+ * 0x0F0	NB	NB_PERF_CTL[3:0]
+ *
+ * Exceptions:
+ *
+ * 0x000	FP	PERF_CTL[3], PERF_CTL[5:3] (*)
+ * 0x003	FP	PERF_CTL[3]
+ * 0x004	FP	PERF_CTL[3], PERF_CTL[5:3] (*)
+ * 0x00B	FP	PERF_CTL[3]
+ * 0x00D	FP	PERF_CTL[3]
+ * 0x023	DE	PERF_CTL[2:0]
+ * 0x02D	LS	PERF_CTL[3]
+ * 0x02E	LS	PERF_CTL[3,0]
+ * 0x031	LS	PERF_CTL[2:0] (**)
+ * 0x043	CU	PERF_CTL[2:0]
+ * 0x045	CU	PERF_CTL[2:0]
+ * 0x046	CU	PERF_CTL[2:0]
+ * 0x054	CU	PERF_CTL[2:0]
+ * 0x055	CU	PERF_CTL[2:0]
+ * 0x08F	IC	PERF_CTL[0]
+ * 0x187	DE	PERF_CTL[0]
+ * 0x188	DE	PERF_CTL[0]
+ * 0x0DB	EX	PERF_CTL[5:0]
+ * 0x0DC	LS	PERF_CTL[5:0]
+ * 0x0DD	LS	PERF_CTL[5:0]
+ * 0x0DE	LS	PERF_CTL[5:0]
+ * 0x0DF	LS	PERF_CTL[5:0]
+ * 0x1C0	EX	PERF_CTL[5:3]
+ * 0x1D6	EX	PERF_CTL[5:0]
+ * 0x1D8	EX	PERF_CTL[5:0]
+ *
+ * (*)  depending on the umask all FPU counters may be used
+ * (**) only one unitmask enabled at a time
+ */
+
+static struct event_constraint amd_f15_PMC0  = EVENT_CONSTRAINT(0, 0x01, 0);
+static struct event_constraint amd_f15_PMC20 = EVENT_CONSTRAINT(0, 0x07, 0);
+static struct event_constraint amd_f15_PMC3  = EVENT_CONSTRAINT(0, 0x08, 0);
+static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT_OVERLAP(0, 0x09, 0);
+static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0);
+static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0);
+
+static struct event_constraint *
+amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, int idx,
+			       struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	unsigned int event_code = amd_get_event_code(hwc);
+
+	switch (event_code & AMD_EVENT_TYPE_MASK) {
+	case AMD_EVENT_FP:
+		switch (event_code) {
+		case 0x000:
+			if (!(hwc->config & 0x0000F000ULL))
+				break;
+			if (!(hwc->config & 0x00000F00ULL))
+				break;
+			return &amd_f15_PMC3;
+		case 0x004:
+			if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1)
+				break;
+			return &amd_f15_PMC3;
+		case 0x003:
+		case 0x00B:
+		case 0x00D:
+			return &amd_f15_PMC3;
+		}
+		return &amd_f15_PMC53;
+	case AMD_EVENT_LS:
+	case AMD_EVENT_DC:
+	case AMD_EVENT_EX_LS:
+		switch (event_code) {
+		case 0x023:
+		case 0x043:
+		case 0x045:
+		case 0x046:
+		case 0x054:
+		case 0x055:
+			return &amd_f15_PMC20;
+		case 0x02D:
+			return &amd_f15_PMC3;
+		case 0x02E:
+			return &amd_f15_PMC30;
+		case 0x031:
+			if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1)
+				return &amd_f15_PMC20;
+			return &emptyconstraint;
+		case 0x1C0:
+			return &amd_f15_PMC53;
+		default:
+			return &amd_f15_PMC50;
+		}
+	case AMD_EVENT_CU:
+	case AMD_EVENT_IC_DE:
+	case AMD_EVENT_DE:
+		switch (event_code) {
+		case 0x08F:
+		case 0x187:
+		case 0x188:
+			return &amd_f15_PMC0;
+		case 0x0DB ... 0x0DF:
+		case 0x1D6:
+		case 0x1D8:
+			return &amd_f15_PMC50;
+		default:
+			return &amd_f15_PMC20;
+		}
+	case AMD_EVENT_NB:
+		/* moved to perf_event_amd_uncore.c */
+		return &emptyconstraint;
+	default:
+		return &emptyconstraint;
+	}
+}
+
+static ssize_t amd_event_sysfs_show(char *page, u64 config)
+{
+	u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT) |
+		    (config & AMD64_EVENTSEL_EVENT) >> 24;
+
+	return x86_event_sysfs_show(page, config, event);
+}
+
+static __initconst const struct x86_pmu amd_pmu = {
+	.name			= "AMD",
+	.handle_irq		= x86_pmu_handle_irq,
+	.disable_all		= x86_pmu_disable_all,
+	.enable_all		= x86_pmu_enable_all,
+	.enable			= x86_pmu_enable_event,
+	.disable		= x86_pmu_disable_event,
+	.hw_config		= amd_pmu_hw_config,
+	.schedule_events	= x86_schedule_events,
+	.eventsel		= MSR_K7_EVNTSEL0,
+	.perfctr		= MSR_K7_PERFCTR0,
+	.addr_offset            = amd_pmu_addr_offset,
+	.event_map		= amd_pmu_event_map,
+	.max_events		= ARRAY_SIZE(amd_perfmon_event_map),
+	.num_counters		= AMD64_NUM_COUNTERS,
+	.cntval_bits		= 48,
+	.cntval_mask		= (1ULL << 48) - 1,
+	.apic			= 1,
+	/* use highest bit to detect overflow */
+	.max_period		= (1ULL << 47) - 1,
+	.get_event_constraints	= amd_get_event_constraints,
+	.put_event_constraints	= amd_put_event_constraints,
+
+	.format_attrs		= amd_format_attr,
+	.events_sysfs_show	= amd_event_sysfs_show,
+
+	.cpu_prepare		= amd_pmu_cpu_prepare,
+	.cpu_starting		= amd_pmu_cpu_starting,
+	.cpu_dead		= amd_pmu_cpu_dead,
+};
+
+static int __init amd_core_pmu_init(void)
+{
+	if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
+		return 0;
+
+	switch (boot_cpu_data.x86) {
+	case 0x15:
+		pr_cont("Fam15h ");
+		x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
+		break;
+
+	default:
+		pr_err("core perfctr but no constraints; unknown hardware!\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * If core performance counter extensions exists, we must use
+	 * MSR_F15H_PERF_CTL/MSR_F15H_PERF_CTR msrs. See also
+	 * amd_pmu_addr_offset().
+	 */
+	x86_pmu.eventsel	= MSR_F15H_PERF_CTL;
+	x86_pmu.perfctr		= MSR_F15H_PERF_CTR;
+	x86_pmu.num_counters	= AMD64_NUM_COUNTERS_CORE;
+
+	pr_cont("core perfctr, ");
+	return 0;
+}
+
+__init int amd_pmu_init(void)
+{
+	int ret;
+
+	/* Performance-monitoring supported from K7 and later: */
+	if (boot_cpu_data.x86 < 6)
+		return -ENODEV;
+
+	x86_pmu = amd_pmu;
+
+	ret = amd_core_pmu_init();
+	if (ret)
+		return ret;
+
+	/* Events are common for all AMDs */
+	memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
+	       sizeof(hw_cache_event_ids));
+
+	return 0;
+}
+
+void amd_pmu_enable_virt(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	cpuc->perf_ctr_virt_mask = 0;
+
+	/* Reload all events */
+	x86_pmu_disable_all();
+	x86_pmu_enable_all(0);
+}
+EXPORT_SYMBOL_GPL(amd_pmu_enable_virt);
+
+void amd_pmu_disable_virt(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	/*
+	 * We only mask out the Host-only bit so that host-only counting works
+	 * when SVM is disabled. If someone sets up a guest-only counter when
+	 * SVM is disabled the Guest-only bits still gets set and the counter
+	 * will not count anything.
+	 */
+	cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY;
+
+	/* Reload all events */
+	x86_pmu_disable_all();
+	x86_pmu_enable_all(0);
+}
+EXPORT_SYMBOL_GPL(amd_pmu_disable_virt);
--- linux-4.4.0.orig/arch/x86/events/amd/ibs.c
+++ linux-4.4.0/arch/x86/events/amd/ibs.c
@@ -0,0 +1,959 @@
+/*
+ * Performance events - AMD IBS
+ *
+ *  Copyright (C) 2011 Advanced Micro Devices, Inc., Robert Richter
+ *
+ *  For licencing details see kernel-base/COPYING
+ */
+
+#include <linux/perf_event.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ptrace.h>
+#include <linux/syscore_ops.h>
+
+#include <asm/apic.h>
+
+#include "../perf_event.h"
+
+static u32 ibs_caps;
+
+#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
+
+#include <linux/kprobes.h>
+#include <linux/hardirq.h>
+
+#include <asm/nmi.h>
+
+#define IBS_FETCH_CONFIG_MASK	(IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT)
+#define IBS_OP_CONFIG_MASK	IBS_OP_MAX_CNT
+
+enum ibs_states {
+	IBS_ENABLED	= 0,
+	IBS_STARTED	= 1,
+	IBS_STOPPING	= 2,
+
+	IBS_MAX_STATES,
+};
+
+struct cpu_perf_ibs {
+	struct perf_event	*event;
+	unsigned long		state[BITS_TO_LONGS(IBS_MAX_STATES)];
+};
+
+struct perf_ibs {
+	struct pmu			pmu;
+	unsigned int			msr;
+	u64				config_mask;
+	u64				cnt_mask;
+	u64				enable_mask;
+	u64				valid_mask;
+	u64				max_period;
+	unsigned long			offset_mask[1];
+	int				offset_max;
+	struct cpu_perf_ibs __percpu	*pcpu;
+
+	struct attribute		**format_attrs;
+	struct attribute_group		format_group;
+	const struct attribute_group	*attr_groups[2];
+
+	u64				(*get_count)(u64 config);
+};
+
+struct perf_ibs_data {
+	u32		size;
+	union {
+		u32	data[0];	/* data buffer starts here */
+		u32	caps;
+	};
+	u64		regs[MSR_AMD64_IBS_REG_COUNT_MAX];
+};
+
+static int
+perf_event_set_period(struct hw_perf_event *hwc, u64 min, u64 max, u64 *hw_period)
+{
+	s64 left = local64_read(&hwc->period_left);
+	s64 period = hwc->sample_period;
+	int overflow = 0;
+
+	/*
+	 * If we are way outside a reasonable range then just skip forward:
+	 */
+	if (unlikely(left <= -period)) {
+		left = period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		overflow = 1;
+	}
+
+	if (unlikely(left < (s64)min)) {
+		left += period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		overflow = 1;
+	}
+
+	/*
+	 * If the hw period that triggers the sw overflow is too short
+	 * we might hit the irq handler. This biases the results.
+	 * Thus we shorten the next-to-last period and set the last
+	 * period to the max period.
+	 */
+	if (left > max) {
+		left -= max;
+		if (left > max)
+			left = max;
+		else if (left < min)
+			left = min;
+	}
+
+	*hw_period = (u64)left;
+
+	return overflow;
+}
+
+static  int
+perf_event_try_update(struct perf_event *event, u64 new_raw_count, int width)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int shift = 64 - width;
+	u64 prev_raw_count;
+	u64 delta;
+
+	/*
+	 * Careful: an NMI might modify the previous event value.
+	 *
+	 * Our tactic to handle this is to first atomically read and
+	 * exchange a new raw count - then add that new-prev delta
+	 * count to the generic event atomically:
+	 */
+	prev_raw_count = local64_read(&hwc->prev_count);
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+					new_raw_count) != prev_raw_count)
+		return 0;
+
+	/*
+	 * Now we have the new raw value and have updated the prev
+	 * timestamp already. We can now calculate the elapsed delta
+	 * (event-)time and add that to the generic event.
+	 *
+	 * Careful, not all hw sign-extends above the physical width
+	 * of the count.
+	 */
+	delta = (new_raw_count << shift) - (prev_raw_count << shift);
+	delta >>= shift;
+
+	local64_add(delta, &event->count);
+	local64_sub(delta, &hwc->period_left);
+
+	return 1;
+}
+
+static struct perf_ibs perf_ibs_fetch;
+static struct perf_ibs perf_ibs_op;
+
+static struct perf_ibs *get_ibs_pmu(int type)
+{
+	if (perf_ibs_fetch.pmu.type == type)
+		return &perf_ibs_fetch;
+	if (perf_ibs_op.pmu.type == type)
+		return &perf_ibs_op;
+	return NULL;
+}
+
+/*
+ * Use IBS for precise event sampling:
+ *
+ *  perf record -a -e cpu-cycles:p ...    # use ibs op counting cycle count
+ *  perf record -a -e r076:p ...          # same as -e cpu-cycles:p
+ *  perf record -a -e r0C1:p ...          # use ibs op counting micro-ops
+ *
+ * IbsOpCntCtl (bit 19) of IBS Execution Control Register (IbsOpCtl,
+ * MSRC001_1033) is used to select either cycle or micro-ops counting
+ * mode.
+ *
+ * The rip of IBS samples has skid 0. Thus, IBS supports precise
+ * levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the
+ * rip is invalid when IBS was not able to record the rip correctly.
+ * We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then.
+ *
+ */
+static int perf_ibs_precise_event(struct perf_event *event, u64 *config)
+{
+	switch (event->attr.precise_ip) {
+	case 0:
+		return -ENOENT;
+	case 1:
+	case 2:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	switch (event->attr.type) {
+	case PERF_TYPE_HARDWARE:
+		switch (event->attr.config) {
+		case PERF_COUNT_HW_CPU_CYCLES:
+			*config = 0;
+			return 0;
+		}
+		break;
+	case PERF_TYPE_RAW:
+		switch (event->attr.config) {
+		case 0x0076:
+			*config = 0;
+			return 0;
+		case 0x00C1:
+			*config = IBS_OP_CNT_CTL;
+			return 0;
+		}
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static const struct perf_event_attr ibs_notsupp = {
+	.exclude_user	= 1,
+	.exclude_kernel	= 1,
+	.exclude_hv	= 1,
+	.exclude_idle	= 1,
+	.exclude_host	= 1,
+	.exclude_guest	= 1,
+};
+
+static int perf_ibs_init(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_ibs *perf_ibs;
+	u64 max_cnt, config;
+	int ret;
+
+	perf_ibs = get_ibs_pmu(event->attr.type);
+	if (perf_ibs) {
+		config = event->attr.config;
+	} else {
+		perf_ibs = &perf_ibs_op;
+		ret = perf_ibs_precise_event(event, &config);
+		if (ret)
+			return ret;
+	}
+
+	if (event->pmu != &perf_ibs->pmu)
+		return -ENOENT;
+
+	if (perf_flags(&event->attr) & perf_flags(&ibs_notsupp))
+		return -EINVAL;
+
+	if (config & ~perf_ibs->config_mask)
+		return -EINVAL;
+
+	if (hwc->sample_period) {
+		if (config & perf_ibs->cnt_mask)
+			/* raw max_cnt may not be set */
+			return -EINVAL;
+		if (!event->attr.sample_freq && hwc->sample_period & 0x0f)
+			/*
+			 * lower 4 bits can not be set in ibs max cnt,
+			 * but allowing it in case we adjust the
+			 * sample period to set a frequency.
+			 */
+			return -EINVAL;
+		hwc->sample_period &= ~0x0FULL;
+		if (!hwc->sample_period)
+			hwc->sample_period = 0x10;
+	} else {
+		max_cnt = config & perf_ibs->cnt_mask;
+		config &= ~perf_ibs->cnt_mask;
+		event->attr.sample_period = max_cnt << 4;
+		hwc->sample_period = event->attr.sample_period;
+	}
+
+	if (!hwc->sample_period)
+		return -EINVAL;
+
+	/*
+	 * If we modify hwc->sample_period, we also need to update
+	 * hwc->last_period and hwc->period_left.
+	 */
+	hwc->last_period = hwc->sample_period;
+	local64_set(&hwc->period_left, hwc->sample_period);
+
+	hwc->config_base = perf_ibs->msr;
+	hwc->config = config;
+
+	return 0;
+}
+
+static int perf_ibs_set_period(struct perf_ibs *perf_ibs,
+			       struct hw_perf_event *hwc, u64 *period)
+{
+	int overflow;
+
+	/* ignore lower 4 bits in min count: */
+	overflow = perf_event_set_period(hwc, 1<<4, perf_ibs->max_period, period);
+	local64_set(&hwc->prev_count, 0);
+
+	return overflow;
+}
+
+static u64 get_ibs_fetch_count(u64 config)
+{
+	return (config & IBS_FETCH_CNT) >> 12;
+}
+
+static u64 get_ibs_op_count(u64 config)
+{
+	u64 count = 0;
+
+	if (config & IBS_OP_VAL)
+		count += (config & IBS_OP_MAX_CNT) << 4; /* cnt rolled over */
+
+	if (ibs_caps & IBS_CAPS_RDWROPCNT)
+		count += (config & IBS_OP_CUR_CNT) >> 32;
+
+	return count;
+}
+
+static void
+perf_ibs_event_update(struct perf_ibs *perf_ibs, struct perf_event *event,
+		      u64 *config)
+{
+	u64 count = perf_ibs->get_count(*config);
+
+	/*
+	 * Set width to 64 since we do not overflow on max width but
+	 * instead on max count. In perf_ibs_set_period() we clear
+	 * prev count manually on overflow.
+	 */
+	while (!perf_event_try_update(event, count, 64)) {
+		rdmsrl(event->hw.config_base, *config);
+		count = perf_ibs->get_count(*config);
+	}
+}
+
+static inline void perf_ibs_enable_event(struct perf_ibs *perf_ibs,
+					 struct hw_perf_event *hwc, u64 config)
+{
+	wrmsrl(hwc->config_base, hwc->config | config | perf_ibs->enable_mask);
+}
+
+/*
+ * Erratum #420 Instruction-Based Sampling Engine May Generate
+ * Interrupt that Cannot Be Cleared:
+ *
+ * Must clear counter mask first, then clear the enable bit. See
+ * Revision Guide for AMD Family 10h Processors, Publication #41322.
+ */
+static inline void perf_ibs_disable_event(struct perf_ibs *perf_ibs,
+					  struct hw_perf_event *hwc, u64 config)
+{
+	config &= ~perf_ibs->cnt_mask;
+	wrmsrl(hwc->config_base, config);
+	config &= ~perf_ibs->enable_mask;
+	wrmsrl(hwc->config_base, config);
+}
+
+/*
+ * We cannot restore the ibs pmu state, so we always needs to update
+ * the event while stopping it and then reset the state when starting
+ * again. Thus, ignoring PERF_EF_RELOAD and PERF_EF_UPDATE flags in
+ * perf_ibs_start()/perf_ibs_stop() and instead always do it.
+ */
+static void perf_ibs_start(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+	u64 period;
+
+	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+		return;
+
+	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+	hwc->state = 0;
+
+	perf_ibs_set_period(perf_ibs, hwc, &period);
+	set_bit(IBS_STARTED, pcpu->state);
+	perf_ibs_enable_event(perf_ibs, hwc, period >> 4);
+
+	perf_event_update_userpage(event);
+}
+
+static void perf_ibs_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+	u64 config;
+	int stopping;
+
+	stopping = test_and_clear_bit(IBS_STARTED, pcpu->state);
+
+	if (!stopping && (hwc->state & PERF_HES_UPTODATE))
+		return;
+
+	rdmsrl(hwc->config_base, config);
+
+	if (stopping) {
+		set_bit(IBS_STOPPING, pcpu->state);
+		perf_ibs_disable_event(perf_ibs, hwc, config);
+		WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+		hwc->state |= PERF_HES_STOPPED;
+	}
+
+	if (hwc->state & PERF_HES_UPTODATE)
+		return;
+
+	/*
+	 * Clear valid bit to not count rollovers on update, rollovers
+	 * are only updated in the irq handler.
+	 */
+	config &= ~perf_ibs->valid_mask;
+
+	perf_ibs_event_update(perf_ibs, event, &config);
+	hwc->state |= PERF_HES_UPTODATE;
+}
+
+static int perf_ibs_add(struct perf_event *event, int flags)
+{
+	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+
+	if (test_and_set_bit(IBS_ENABLED, pcpu->state))
+		return -ENOSPC;
+
+	event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+	pcpu->event = event;
+
+	if (flags & PERF_EF_START)
+		perf_ibs_start(event, PERF_EF_RELOAD);
+
+	return 0;
+}
+
+static void perf_ibs_del(struct perf_event *event, int flags)
+{
+	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+
+	if (!test_and_clear_bit(IBS_ENABLED, pcpu->state))
+		return;
+
+	perf_ibs_stop(event, PERF_EF_UPDATE);
+
+	pcpu->event = NULL;
+
+	perf_event_update_userpage(event);
+}
+
+static void perf_ibs_read(struct perf_event *event) { }
+
+PMU_FORMAT_ATTR(rand_en,	"config:57");
+PMU_FORMAT_ATTR(cnt_ctl,	"config:19");
+
+static struct attribute *ibs_fetch_format_attrs[] = {
+	&format_attr_rand_en.attr,
+	NULL,
+};
+
+static struct attribute *ibs_op_format_attrs[] = {
+	NULL,	/* &format_attr_cnt_ctl.attr if IBS_CAPS_OPCNT */
+	NULL,
+};
+
+static struct perf_ibs perf_ibs_fetch = {
+	.pmu = {
+		.task_ctx_nr	= perf_invalid_context,
+
+		.event_init	= perf_ibs_init,
+		.add		= perf_ibs_add,
+		.del		= perf_ibs_del,
+		.start		= perf_ibs_start,
+		.stop		= perf_ibs_stop,
+		.read		= perf_ibs_read,
+	},
+	.msr			= MSR_AMD64_IBSFETCHCTL,
+	.config_mask		= IBS_FETCH_CONFIG_MASK,
+	.cnt_mask		= IBS_FETCH_MAX_CNT,
+	.enable_mask		= IBS_FETCH_ENABLE,
+	.valid_mask		= IBS_FETCH_VAL,
+	.max_period		= IBS_FETCH_MAX_CNT << 4,
+	.offset_mask		= { MSR_AMD64_IBSFETCH_REG_MASK },
+	.offset_max		= MSR_AMD64_IBSFETCH_REG_COUNT,
+	.format_attrs		= ibs_fetch_format_attrs,
+
+	.get_count		= get_ibs_fetch_count,
+};
+
+static struct perf_ibs perf_ibs_op = {
+	.pmu = {
+		.task_ctx_nr	= perf_invalid_context,
+
+		.event_init	= perf_ibs_init,
+		.add		= perf_ibs_add,
+		.del		= perf_ibs_del,
+		.start		= perf_ibs_start,
+		.stop		= perf_ibs_stop,
+		.read		= perf_ibs_read,
+	},
+	.msr			= MSR_AMD64_IBSOPCTL,
+	.config_mask		= IBS_OP_CONFIG_MASK,
+	.cnt_mask		= IBS_OP_MAX_CNT,
+	.enable_mask		= IBS_OP_ENABLE,
+	.valid_mask		= IBS_OP_VAL,
+	.max_period		= IBS_OP_MAX_CNT << 4,
+	.offset_mask		= { MSR_AMD64_IBSOP_REG_MASK },
+	.offset_max		= MSR_AMD64_IBSOP_REG_COUNT,
+	.format_attrs		= ibs_op_format_attrs,
+
+	.get_count		= get_ibs_op_count,
+};
+
+static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
+{
+	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+	struct perf_event *event = pcpu->event;
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_sample_data data;
+	struct perf_raw_record raw;
+	struct pt_regs regs;
+	struct perf_ibs_data ibs_data;
+	int offset, size, check_rip, offset_max, throttle = 0;
+	unsigned int msr;
+	u64 *buf, *config, period;
+
+	if (!test_bit(IBS_STARTED, pcpu->state)) {
+		/*
+		 * Catch spurious interrupts after stopping IBS: After
+		 * disabling IBS there could be still incoming NMIs
+		 * with samples that even have the valid bit cleared.
+		 * Mark all this NMIs as handled.
+		 */
+		return test_and_clear_bit(IBS_STOPPING, pcpu->state) ? 1 : 0;
+	}
+
+	msr = hwc->config_base;
+	buf = ibs_data.regs;
+	rdmsrl(msr, *buf);
+	if (!(*buf++ & perf_ibs->valid_mask))
+		return 0;
+
+	config = &ibs_data.regs[0];
+	perf_ibs_event_update(perf_ibs, event, config);
+	perf_sample_data_init(&data, 0, hwc->last_period);
+	if (!perf_ibs_set_period(perf_ibs, hwc, &period))
+		goto out;	/* no sw counter overflow */
+
+	ibs_data.caps = ibs_caps;
+	size = 1;
+	offset = 1;
+	check_rip = (perf_ibs == &perf_ibs_op && (ibs_caps & IBS_CAPS_RIPINVALIDCHK));
+	if (event->attr.sample_type & PERF_SAMPLE_RAW)
+		offset_max = perf_ibs->offset_max;
+	else if (check_rip)
+		offset_max = 3;
+	else
+		offset_max = 1;
+	do {
+		rdmsrl(msr + offset, *buf++);
+		size++;
+		offset = find_next_bit(perf_ibs->offset_mask,
+				       perf_ibs->offset_max,
+				       offset + 1);
+	} while (offset < offset_max);
+	if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+		/*
+		 * Read IbsBrTarget and IbsOpData4 separately
+		 * depending on their availability.
+		 * Can't add to offset_max as they are staggered
+		 */
+		if (ibs_caps & IBS_CAPS_BRNTRGT) {
+			rdmsrl(MSR_AMD64_IBSBRTARGET, *buf++);
+			size++;
+		}
+		if (ibs_caps & IBS_CAPS_OPDATA4) {
+			rdmsrl(MSR_AMD64_IBSOPDATA4, *buf++);
+			size++;
+		}
+	}
+	ibs_data.size = sizeof(u64) * size;
+
+	regs = *iregs;
+	if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
+		regs.flags &= ~PERF_EFLAGS_EXACT;
+	} else {
+		set_linear_ip(&regs, ibs_data.regs[1]);
+		regs.flags |= PERF_EFLAGS_EXACT;
+	}
+
+	if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+		raw.size = sizeof(u32) + ibs_data.size;
+		raw.data = ibs_data.data;
+		data.raw = &raw;
+	}
+
+	throttle = perf_event_overflow(event, &data, &regs);
+out:
+	if (throttle)
+		perf_ibs_disable_event(perf_ibs, hwc, *config);
+	else
+		perf_ibs_enable_event(perf_ibs, hwc, period >> 4);
+
+	perf_event_update_userpage(event);
+
+	return 1;
+}
+
+static int
+perf_ibs_nmi_handler(unsigned int cmd, struct pt_regs *regs)
+{
+	int handled = 0;
+
+	handled += perf_ibs_handle_irq(&perf_ibs_fetch, regs);
+	handled += perf_ibs_handle_irq(&perf_ibs_op, regs);
+
+	if (handled)
+		inc_irq_stat(apic_perf_irqs);
+
+	return handled;
+}
+NOKPROBE_SYMBOL(perf_ibs_nmi_handler);
+
+static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
+{
+	struct cpu_perf_ibs __percpu *pcpu;
+	int ret;
+
+	pcpu = alloc_percpu(struct cpu_perf_ibs);
+	if (!pcpu)
+		return -ENOMEM;
+
+	perf_ibs->pcpu = pcpu;
+
+	/* register attributes */
+	if (perf_ibs->format_attrs[0]) {
+		memset(&perf_ibs->format_group, 0, sizeof(perf_ibs->format_group));
+		perf_ibs->format_group.name	= "format";
+		perf_ibs->format_group.attrs	= perf_ibs->format_attrs;
+
+		memset(&perf_ibs->attr_groups, 0, sizeof(perf_ibs->attr_groups));
+		perf_ibs->attr_groups[0]	= &perf_ibs->format_group;
+		perf_ibs->pmu.attr_groups	= perf_ibs->attr_groups;
+	}
+
+	ret = perf_pmu_register(&perf_ibs->pmu, name, -1);
+	if (ret) {
+		perf_ibs->pcpu = NULL;
+		free_percpu(pcpu);
+	}
+
+	return ret;
+}
+
+static __init int perf_event_ibs_init(void)
+{
+	struct attribute **attr = ibs_op_format_attrs;
+
+	if (!ibs_caps)
+		return -ENODEV;	/* ibs not supported by the cpu */
+
+	perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
+
+	if (ibs_caps & IBS_CAPS_OPCNT) {
+		perf_ibs_op.config_mask |= IBS_OP_CNT_CTL;
+		*attr++ = &format_attr_cnt_ctl.attr;
+	}
+	perf_ibs_pmu_init(&perf_ibs_op, "ibs_op");
+
+	register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
+	printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps);
+
+	return 0;
+}
+
+#else /* defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) */
+
+static __init int perf_event_ibs_init(void) { return 0; }
+
+#endif
+
+/* IBS - apic initialization, for perf and oprofile */
+
+static __init u32 __get_ibs_caps(void)
+{
+	u32 caps;
+	unsigned int max_level;
+
+	if (!boot_cpu_has(X86_FEATURE_IBS))
+		return 0;
+
+	/* check IBS cpuid feature flags */
+	max_level = cpuid_eax(0x80000000);
+	if (max_level < IBS_CPUID_FEATURES)
+		return IBS_CAPS_DEFAULT;
+
+	caps = cpuid_eax(IBS_CPUID_FEATURES);
+	if (!(caps & IBS_CAPS_AVAIL))
+		/* cpuid flags not valid */
+		return IBS_CAPS_DEFAULT;
+
+	return caps;
+}
+
+u32 get_ibs_caps(void)
+{
+	return ibs_caps;
+}
+
+EXPORT_SYMBOL(get_ibs_caps);
+
+static inline int get_eilvt(int offset)
+{
+	return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);
+}
+
+static inline int put_eilvt(int offset)
+{
+	return !setup_APIC_eilvt(offset, 0, 0, 1);
+}
+
+/*
+ * Check and reserve APIC extended interrupt LVT offset for IBS if available.
+ */
+static inline int ibs_eilvt_valid(void)
+{
+	int offset;
+	u64 val;
+	int valid = 0;
+
+	preempt_disable();
+
+	rdmsrl(MSR_AMD64_IBSCTL, val);
+	offset = val & IBSCTL_LVT_OFFSET_MASK;
+
+	if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
+		pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
+		       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
+		goto out;
+	}
+
+	if (!get_eilvt(offset)) {
+		pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
+		       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
+		goto out;
+	}
+
+	valid = 1;
+out:
+	preempt_enable();
+
+	return valid;
+}
+
+static int setup_ibs_ctl(int ibs_eilvt_off)
+{
+	struct pci_dev *cpu_cfg;
+	int nodes;
+	u32 value = 0;
+
+	nodes = 0;
+	cpu_cfg = NULL;
+	do {
+		cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
+					 PCI_DEVICE_ID_AMD_10H_NB_MISC,
+					 cpu_cfg);
+		if (!cpu_cfg)
+			break;
+		++nodes;
+		pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
+				       | IBSCTL_LVT_OFFSET_VALID);
+		pci_read_config_dword(cpu_cfg, IBSCTL, &value);
+		if (value != (ibs_eilvt_off | IBSCTL_LVT_OFFSET_VALID)) {
+			pci_dev_put(cpu_cfg);
+			printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
+			       "IBSCTL = 0x%08x\n", value);
+			return -EINVAL;
+		}
+	} while (1);
+
+	if (!nodes) {
+		printk(KERN_DEBUG "No CPU node configured for IBS\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+ * This runs only on the current cpu. We try to find an LVT offset and
+ * setup the local APIC. For this we must disable preemption. On
+ * success we initialize all nodes with this offset. This updates then
+ * the offset in the IBS_CTL per-node msr. The per-core APIC setup of
+ * the IBS interrupt vector is handled by perf_ibs_cpu_notifier that
+ * is using the new offset.
+ */
+static void force_ibs_eilvt_setup(void)
+{
+	int offset;
+	int ret;
+
+	preempt_disable();
+	/* find the next free available EILVT entry, skip offset 0 */
+	for (offset = 1; offset < APIC_EILVT_NR_MAX; offset++) {
+		if (get_eilvt(offset))
+			break;
+	}
+	preempt_enable();
+
+	if (offset == APIC_EILVT_NR_MAX) {
+		printk(KERN_DEBUG "No EILVT entry available\n");
+		return;
+	}
+
+	ret = setup_ibs_ctl(offset);
+	if (ret)
+		goto out;
+
+	if (!ibs_eilvt_valid())
+		goto out;
+
+	pr_info("IBS: LVT offset %d assigned\n", offset);
+
+	return;
+out:
+	preempt_disable();
+	put_eilvt(offset);
+	preempt_enable();
+	return;
+}
+
+static void ibs_eilvt_setup(void)
+{
+	/*
+	 * Force LVT offset assignment for family 10h: The offsets are
+	 * not assigned by the BIOS for this family, so the OS is
+	 * responsible for doing it. If the OS assignment fails, fall
+	 * back to BIOS settings and try to setup this.
+	 */
+	if (boot_cpu_data.x86 == 0x10)
+		force_ibs_eilvt_setup();
+}
+
+static inline int get_ibs_lvt_offset(void)
+{
+	u64 val;
+
+	rdmsrl(MSR_AMD64_IBSCTL, val);
+	if (!(val & IBSCTL_LVT_OFFSET_VALID))
+		return -EINVAL;
+
+	return val & IBSCTL_LVT_OFFSET_MASK;
+}
+
+static void setup_APIC_ibs(void *dummy)
+{
+	int offset;
+
+	offset = get_ibs_lvt_offset();
+	if (offset < 0)
+		goto failed;
+
+	if (!setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 0))
+		return;
+failed:
+	pr_warn("perf: IBS APIC setup failed on cpu #%d\n",
+		smp_processor_id());
+}
+
+static void clear_APIC_ibs(void *dummy)
+{
+	int offset;
+
+	offset = get_ibs_lvt_offset();
+	if (offset >= 0)
+		setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
+}
+
+#ifdef CONFIG_PM
+
+static int perf_ibs_suspend(void)
+{
+	clear_APIC_ibs(NULL);
+	return 0;
+}
+
+static void perf_ibs_resume(void)
+{
+	ibs_eilvt_setup();
+	setup_APIC_ibs(NULL);
+}
+
+static struct syscore_ops perf_ibs_syscore_ops = {
+	.resume		= perf_ibs_resume,
+	.suspend	= perf_ibs_suspend,
+};
+
+static void perf_ibs_pm_init(void)
+{
+	register_syscore_ops(&perf_ibs_syscore_ops);
+}
+
+#else
+
+static inline void perf_ibs_pm_init(void) { }
+
+#endif
+
+static int
+perf_ibs_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		setup_APIC_ibs(NULL);
+		break;
+	case CPU_DYING:
+		clear_APIC_ibs(NULL);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static __init int amd_ibs_init(void)
+{
+	u32 caps;
+	int ret = -EINVAL;
+
+	caps = __get_ibs_caps();
+	if (!caps)
+		return -ENODEV;	/* ibs not supported by the cpu */
+
+	ibs_eilvt_setup();
+
+	if (!ibs_eilvt_valid())
+		goto out;
+
+	perf_ibs_pm_init();
+	cpu_notifier_register_begin();
+	ibs_caps = caps;
+	/* make ibs_caps visible to other cpus: */
+	smp_mb();
+	smp_call_function(setup_APIC_ibs, NULL, 1);
+	__perf_cpu_notifier(perf_ibs_cpu_notifier);
+	cpu_notifier_register_done();
+
+	ret = perf_event_ibs_init();
+out:
+	if (ret)
+		pr_err("Failed to setup IBS, %d\n", ret);
+	return ret;
+}
+
+/* Since we need the pci subsystem to init ibs we can't do this earlier: */
+device_initcall(amd_ibs_init);
--- linux-4.4.0.orig/arch/x86/events/amd/iommu.c
+++ linux-4.4.0/arch/x86/events/amd/iommu.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Steven Kinney <Steven.Kinney@amd.com>
+ * Author: Suravee Suthikulpanit <Suraveee.Suthikulpanit@amd.com>
+ *
+ * Perf: amd_iommu - AMD IOMMU Performance Counter PMU implementation
+ *
+ * This program is free software; you can 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/perf_event.h>
+#include <linux/module.h>
+#include <linux/cpumask.h>
+#include <linux/slab.h>
+
+#include "../perf_event.h"
+#include "iommu.h"
+
+#define COUNTER_SHIFT		16
+
+#define _GET_BANK(ev)       ((u8)(ev->hw.extra_reg.reg >> 8))
+#define _GET_CNTR(ev)       ((u8)(ev->hw.extra_reg.reg))
+
+/* iommu pmu config masks */
+#define _GET_CSOURCE(ev)    ((ev->hw.config & 0xFFULL))
+#define _GET_DEVID(ev)      ((ev->hw.config >> 8)  & 0xFFFFULL)
+#define _GET_PASID(ev)      ((ev->hw.config >> 24) & 0xFFFFULL)
+#define _GET_DOMID(ev)      ((ev->hw.config >> 40) & 0xFFFFULL)
+#define _GET_DEVID_MASK(ev) ((ev->hw.extra_reg.config)  & 0xFFFFULL)
+#define _GET_PASID_MASK(ev) ((ev->hw.extra_reg.config >> 16) & 0xFFFFULL)
+#define _GET_DOMID_MASK(ev) ((ev->hw.extra_reg.config >> 32) & 0xFFFFULL)
+
+static struct perf_amd_iommu __perf_iommu;
+
+struct perf_amd_iommu {
+	struct pmu pmu;
+	u8 max_banks;
+	u8 max_counters;
+	u64 cntr_assign_mask;
+	raw_spinlock_t lock;
+	const struct attribute_group *attr_groups[4];
+};
+
+#define format_group	attr_groups[0]
+#define cpumask_group	attr_groups[1]
+#define events_group	attr_groups[2]
+#define null_group	attr_groups[3]
+
+/*---------------------------------------------
+ * sysfs format attributes
+ *---------------------------------------------*/
+PMU_FORMAT_ATTR(csource,    "config:0-7");
+PMU_FORMAT_ATTR(devid,      "config:8-23");
+PMU_FORMAT_ATTR(pasid,      "config:24-39");
+PMU_FORMAT_ATTR(domid,      "config:40-55");
+PMU_FORMAT_ATTR(devid_mask, "config1:0-15");
+PMU_FORMAT_ATTR(pasid_mask, "config1:16-31");
+PMU_FORMAT_ATTR(domid_mask, "config1:32-47");
+
+static struct attribute *iommu_format_attrs[] = {
+	&format_attr_csource.attr,
+	&format_attr_devid.attr,
+	&format_attr_pasid.attr,
+	&format_attr_domid.attr,
+	&format_attr_devid_mask.attr,
+	&format_attr_pasid_mask.attr,
+	&format_attr_domid_mask.attr,
+	NULL,
+};
+
+static struct attribute_group amd_iommu_format_group = {
+	.name = "format",
+	.attrs = iommu_format_attrs,
+};
+
+/*---------------------------------------------
+ * sysfs events attributes
+ *---------------------------------------------*/
+struct amd_iommu_event_desc {
+	struct kobj_attribute attr;
+	const char *event;
+};
+
+static ssize_t _iommu_event_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
+{
+	struct amd_iommu_event_desc *event =
+		container_of(attr, struct amd_iommu_event_desc, attr);
+	return sprintf(buf, "%s\n", event->event);
+}
+
+#define AMD_IOMMU_EVENT_DESC(_name, _event)			\
+{								\
+	.attr  = __ATTR(_name, 0444, _iommu_event_show, NULL),	\
+	.event = _event,					\
+}
+
+static struct amd_iommu_event_desc amd_iommu_v2_event_descs[] = {
+	AMD_IOMMU_EVENT_DESC(mem_pass_untrans,        "csource=0x01"),
+	AMD_IOMMU_EVENT_DESC(mem_pass_pretrans,       "csource=0x02"),
+	AMD_IOMMU_EVENT_DESC(mem_pass_excl,           "csource=0x03"),
+	AMD_IOMMU_EVENT_DESC(mem_target_abort,        "csource=0x04"),
+	AMD_IOMMU_EVENT_DESC(mem_trans_total,         "csource=0x05"),
+	AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pte_hit,   "csource=0x06"),
+	AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pte_mis,   "csource=0x07"),
+	AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pde_hit,   "csource=0x08"),
+	AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pde_mis,   "csource=0x09"),
+	AMD_IOMMU_EVENT_DESC(mem_dte_hit,             "csource=0x0a"),
+	AMD_IOMMU_EVENT_DESC(mem_dte_mis,             "csource=0x0b"),
+	AMD_IOMMU_EVENT_DESC(page_tbl_read_tot,       "csource=0x0c"),
+	AMD_IOMMU_EVENT_DESC(page_tbl_read_nst,       "csource=0x0d"),
+	AMD_IOMMU_EVENT_DESC(page_tbl_read_gst,       "csource=0x0e"),
+	AMD_IOMMU_EVENT_DESC(int_dte_hit,             "csource=0x0f"),
+	AMD_IOMMU_EVENT_DESC(int_dte_mis,             "csource=0x10"),
+	AMD_IOMMU_EVENT_DESC(cmd_processed,           "csource=0x11"),
+	AMD_IOMMU_EVENT_DESC(cmd_processed_inv,       "csource=0x12"),
+	AMD_IOMMU_EVENT_DESC(tlb_inv,                 "csource=0x13"),
+	{ /* end: all zeroes */ },
+};
+
+/*---------------------------------------------
+ * sysfs cpumask attributes
+ *---------------------------------------------*/
+static cpumask_t iommu_cpumask;
+
+static ssize_t _iommu_cpumask_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return cpumap_print_to_pagebuf(true, buf, &iommu_cpumask);
+}
+static DEVICE_ATTR(cpumask, S_IRUGO, _iommu_cpumask_show, NULL);
+
+static struct attribute *iommu_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static struct attribute_group amd_iommu_cpumask_group = {
+	.attrs = iommu_cpumask_attrs,
+};
+
+/*---------------------------------------------*/
+
+static int get_next_avail_iommu_bnk_cntr(struct perf_amd_iommu *perf_iommu)
+{
+	unsigned long flags;
+	int shift, bank, cntr, retval;
+	int max_banks = perf_iommu->max_banks;
+	int max_cntrs = perf_iommu->max_counters;
+
+	raw_spin_lock_irqsave(&perf_iommu->lock, flags);
+
+	for (bank = 0, shift = 0; bank < max_banks; bank++) {
+		for (cntr = 0; cntr < max_cntrs; cntr++) {
+			shift = bank + (bank*3) + cntr;
+			if (perf_iommu->cntr_assign_mask & (1ULL<<shift)) {
+				continue;
+			} else {
+				perf_iommu->cntr_assign_mask |= (1ULL<<shift);
+				retval = ((u16)((u16)bank<<8) | (u8)(cntr));
+				goto out;
+			}
+		}
+	}
+	retval = -ENOSPC;
+out:
+	raw_spin_unlock_irqrestore(&perf_iommu->lock, flags);
+	return retval;
+}
+
+static int clear_avail_iommu_bnk_cntr(struct perf_amd_iommu *perf_iommu,
+					u8 bank, u8 cntr)
+{
+	unsigned long flags;
+	int max_banks, max_cntrs;
+	int shift = 0;
+
+	max_banks = perf_iommu->max_banks;
+	max_cntrs = perf_iommu->max_counters;
+
+	if ((bank > max_banks) || (cntr > max_cntrs))
+		return -EINVAL;
+
+	shift = bank + cntr + (bank*3);
+
+	raw_spin_lock_irqsave(&perf_iommu->lock, flags);
+	perf_iommu->cntr_assign_mask &= ~(1ULL<<shift);
+	raw_spin_unlock_irqrestore(&perf_iommu->lock, flags);
+
+	return 0;
+}
+
+static int perf_iommu_event_init(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct perf_amd_iommu *perf_iommu;
+	u64 config, config1;
+
+	/* test the event attr type check for PMU enumeration */
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/*
+	 * IOMMU counters are shared across all cores.
+	 * Therefore, it does not support per-process mode.
+	 * Also, it does not support event sampling mode.
+	 */
+	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+		return -EINVAL;
+
+	/* IOMMU counters do not have usr/os/guest/host bits */
+	if (event->attr.exclude_user || event->attr.exclude_kernel ||
+	    event->attr.exclude_host || event->attr.exclude_guest)
+		return -EINVAL;
+
+	if (event->cpu < 0)
+		return -EINVAL;
+
+	perf_iommu = &__perf_iommu;
+
+	if (event->pmu != &perf_iommu->pmu)
+		return -ENOENT;
+
+	if (perf_iommu) {
+		config = event->attr.config;
+		config1 = event->attr.config1;
+	} else {
+		return -EINVAL;
+	}
+
+	/* integrate with iommu base devid (0000), assume one iommu */
+	perf_iommu->max_banks =
+		amd_iommu_pc_get_max_banks(IOMMU_BASE_DEVID);
+	perf_iommu->max_counters =
+		amd_iommu_pc_get_max_counters(IOMMU_BASE_DEVID);
+	if ((perf_iommu->max_banks == 0) || (perf_iommu->max_counters == 0))
+		return -EINVAL;
+
+	/* update the hw_perf_event struct with the iommu config data */
+	hwc->config = config;
+	hwc->extra_reg.config = config1;
+
+	return 0;
+}
+
+static void perf_iommu_enable_event(struct perf_event *ev)
+{
+	u8 csource = _GET_CSOURCE(ev);
+	u16 devid = _GET_DEVID(ev);
+	u64 reg = 0ULL;
+
+	reg = csource;
+	amd_iommu_pc_get_set_reg_val(devid,
+			_GET_BANK(ev), _GET_CNTR(ev) ,
+			 IOMMU_PC_COUNTER_SRC_REG, &reg, true);
+
+	reg = 0ULL | devid | (_GET_DEVID_MASK(ev) << 32);
+	if (reg)
+		reg |= (1UL << 31);
+	amd_iommu_pc_get_set_reg_val(devid,
+			_GET_BANK(ev), _GET_CNTR(ev) ,
+			 IOMMU_PC_DEVID_MATCH_REG, &reg, true);
+
+	reg = 0ULL | _GET_PASID(ev) | (_GET_PASID_MASK(ev) << 32);
+	if (reg)
+		reg |= (1UL << 31);
+	amd_iommu_pc_get_set_reg_val(devid,
+			_GET_BANK(ev), _GET_CNTR(ev) ,
+			 IOMMU_PC_PASID_MATCH_REG, &reg, true);
+
+	reg = 0ULL | _GET_DOMID(ev) | (_GET_DOMID_MASK(ev) << 32);
+	if (reg)
+		reg |= (1UL << 31);
+	amd_iommu_pc_get_set_reg_val(devid,
+			_GET_BANK(ev), _GET_CNTR(ev) ,
+			 IOMMU_PC_DOMID_MATCH_REG, &reg, true);
+}
+
+static void perf_iommu_disable_event(struct perf_event *event)
+{
+	u64 reg = 0ULL;
+
+	amd_iommu_pc_get_set_reg_val(_GET_DEVID(event),
+			_GET_BANK(event), _GET_CNTR(event),
+			IOMMU_PC_COUNTER_SRC_REG, &reg, true);
+}
+
+static void perf_iommu_start(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	pr_debug("perf: amd_iommu:perf_iommu_start\n");
+	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+		return;
+
+	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+	hwc->state = 0;
+
+	if (flags & PERF_EF_RELOAD) {
+		u64 prev_raw_count =  local64_read(&hwc->prev_count);
+		amd_iommu_pc_get_set_reg_val(_GET_DEVID(event),
+				_GET_BANK(event), _GET_CNTR(event),
+				IOMMU_PC_COUNTER_REG, &prev_raw_count, true);
+	}
+
+	perf_iommu_enable_event(event);
+	perf_event_update_userpage(event);
+
+}
+
+static void perf_iommu_read(struct perf_event *event)
+{
+	u64 count = 0ULL;
+	u64 prev_raw_count = 0ULL;
+	u64 delta = 0ULL;
+	struct hw_perf_event *hwc = &event->hw;
+	pr_debug("perf: amd_iommu:perf_iommu_read\n");
+
+	amd_iommu_pc_get_set_reg_val(_GET_DEVID(event),
+				_GET_BANK(event), _GET_CNTR(event),
+				IOMMU_PC_COUNTER_REG, &count, false);
+
+	/* IOMMU pc counter register is only 48 bits */
+	count &= 0xFFFFFFFFFFFFULL;
+
+	prev_raw_count =  local64_read(&hwc->prev_count);
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+					count) != prev_raw_count)
+		return;
+
+	/* Handling 48-bit counter overflowing */
+	delta = (count << COUNTER_SHIFT) - (prev_raw_count << COUNTER_SHIFT);
+	delta >>= COUNTER_SHIFT;
+	local64_add(delta, &event->count);
+
+}
+
+static void perf_iommu_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 config;
+
+	pr_debug("perf: amd_iommu:perf_iommu_stop\n");
+
+	if (hwc->state & PERF_HES_UPTODATE)
+		return;
+
+	perf_iommu_disable_event(event);
+	WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+	hwc->state |= PERF_HES_STOPPED;
+
+	if (hwc->state & PERF_HES_UPTODATE)
+		return;
+
+	config = hwc->config;
+	perf_iommu_read(event);
+	hwc->state |= PERF_HES_UPTODATE;
+}
+
+static int perf_iommu_add(struct perf_event *event, int flags)
+{
+	int retval;
+	struct perf_amd_iommu *perf_iommu =
+			container_of(event->pmu, struct perf_amd_iommu, pmu);
+
+	pr_debug("perf: amd_iommu:perf_iommu_add\n");
+	event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+	/* request an iommu bank/counter */
+	retval = get_next_avail_iommu_bnk_cntr(perf_iommu);
+	if (retval != -ENOSPC)
+		event->hw.extra_reg.reg = (u16)retval;
+	else
+		return retval;
+
+	if (flags & PERF_EF_START)
+		perf_iommu_start(event, PERF_EF_RELOAD);
+
+	return 0;
+}
+
+static void perf_iommu_del(struct perf_event *event, int flags)
+{
+	struct perf_amd_iommu *perf_iommu =
+			container_of(event->pmu, struct perf_amd_iommu, pmu);
+
+	pr_debug("perf: amd_iommu:perf_iommu_del\n");
+	perf_iommu_stop(event, PERF_EF_UPDATE);
+
+	/* clear the assigned iommu bank/counter */
+	clear_avail_iommu_bnk_cntr(perf_iommu,
+				     _GET_BANK(event),
+				     _GET_CNTR(event));
+
+	perf_event_update_userpage(event);
+}
+
+static __init int _init_events_attrs(struct perf_amd_iommu *perf_iommu)
+{
+	struct attribute **attrs;
+	struct attribute_group *attr_group;
+	int i = 0, j;
+
+	while (amd_iommu_v2_event_descs[i].attr.attr.name)
+		i++;
+
+	attr_group = kzalloc(sizeof(struct attribute *)
+		* (i + 1) + sizeof(*attr_group), GFP_KERNEL);
+	if (!attr_group)
+		return -ENOMEM;
+
+	attrs = (struct attribute **)(attr_group + 1);
+	for (j = 0; j < i; j++)
+		attrs[j] = &amd_iommu_v2_event_descs[j].attr.attr;
+
+	attr_group->name = "events";
+	attr_group->attrs = attrs;
+	perf_iommu->events_group = attr_group;
+
+	return 0;
+}
+
+static __init void amd_iommu_pc_exit(void)
+{
+	if (__perf_iommu.events_group != NULL) {
+		kfree(__perf_iommu.events_group);
+		__perf_iommu.events_group = NULL;
+	}
+}
+
+static __init int _init_perf_amd_iommu(
+	struct perf_amd_iommu *perf_iommu, char *name)
+{
+	int ret;
+
+	raw_spin_lock_init(&perf_iommu->lock);
+
+	/* Init format attributes */
+	perf_iommu->format_group = &amd_iommu_format_group;
+
+	/* Init cpumask attributes to only core 0 */
+	cpumask_set_cpu(0, &iommu_cpumask);
+	perf_iommu->cpumask_group = &amd_iommu_cpumask_group;
+
+	/* Init events attributes */
+	if (_init_events_attrs(perf_iommu) != 0)
+		pr_err("perf: amd_iommu: Only support raw events.\n");
+
+	/* Init null attributes */
+	perf_iommu->null_group = NULL;
+	perf_iommu->pmu.attr_groups = perf_iommu->attr_groups;
+
+	ret = perf_pmu_register(&perf_iommu->pmu, name, -1);
+	if (ret) {
+		pr_err("perf: amd_iommu: Failed to initialized.\n");
+		amd_iommu_pc_exit();
+	} else {
+		pr_info("perf: amd_iommu: Detected. (%d banks, %d counters/bank)\n",
+			amd_iommu_pc_get_max_banks(IOMMU_BASE_DEVID),
+			amd_iommu_pc_get_max_counters(IOMMU_BASE_DEVID));
+	}
+
+	return ret;
+}
+
+static struct perf_amd_iommu __perf_iommu = {
+	.pmu = {
+		.event_init	= perf_iommu_event_init,
+		.add		= perf_iommu_add,
+		.del		= perf_iommu_del,
+		.start		= perf_iommu_start,
+		.stop		= perf_iommu_stop,
+		.read		= perf_iommu_read,
+	},
+	.max_banks		= 0x00,
+	.max_counters		= 0x00,
+	.cntr_assign_mask	= 0ULL,
+	.format_group		= NULL,
+	.cpumask_group		= NULL,
+	.events_group		= NULL,
+	.null_group		= NULL,
+};
+
+static __init int amd_iommu_pc_init(void)
+{
+	/* Make sure the IOMMU PC resource is available */
+	if (!amd_iommu_pc_supported())
+		return -ENODEV;
+
+	_init_perf_amd_iommu(&__perf_iommu, "amd_iommu");
+
+	return 0;
+}
+
+device_initcall(amd_iommu_pc_init);
--- linux-4.4.0.orig/arch/x86/events/amd/iommu.h
+++ linux-4.4.0/arch/x86/events/amd/iommu.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Steven Kinney <Steven.Kinney@amd.com>
+ * Author: Suravee Suthikulpanit <Suraveee.Suthikulpanit@amd.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 _PERF_EVENT_AMD_IOMMU_H_
+#define _PERF_EVENT_AMD_IOMMU_H_
+
+/* iommu pc mmio region register indexes */
+#define IOMMU_PC_COUNTER_REG			0x00
+#define IOMMU_PC_COUNTER_SRC_REG		0x08
+#define IOMMU_PC_PASID_MATCH_REG		0x10
+#define IOMMU_PC_DOMID_MATCH_REG		0x18
+#define IOMMU_PC_DEVID_MATCH_REG		0x20
+#define IOMMU_PC_COUNTER_REPORT_REG		0x28
+
+/* maximun specified bank/counters */
+#define PC_MAX_SPEC_BNKS			64
+#define PC_MAX_SPEC_CNTRS			16
+
+/* iommu pc reg masks*/
+#define IOMMU_BASE_DEVID			0x0000
+
+/* amd_iommu_init.c external support functions */
+extern bool amd_iommu_pc_supported(void);
+
+extern u8 amd_iommu_pc_get_max_banks(u16 devid);
+
+extern u8 amd_iommu_pc_get_max_counters(u16 devid);
+
+extern int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr,
+			u8 fxn, u64 *value, bool is_write);
+
+#endif /*_PERF_EVENT_AMD_IOMMU_H_*/
--- linux-4.4.0.orig/arch/x86/events/amd/uncore.c
+++ linux-4.4.0/arch/x86/events/amd/uncore.c
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Jacob Shin <jacob.shin@amd.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/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+
+#include <asm/cpufeature.h>
+#include <asm/perf_event.h>
+#include <asm/msr.h>
+
+#define NUM_COUNTERS_NB		4
+#define NUM_COUNTERS_L2		4
+#define MAX_COUNTERS		NUM_COUNTERS_NB
+
+#define RDPMC_BASE_NB		6
+#define RDPMC_BASE_L2		10
+
+#define COUNTER_SHIFT		16
+
+struct amd_uncore {
+	int id;
+	int refcnt;
+	int cpu;
+	int num_counters;
+	int rdpmc_base;
+	u32 msr_base;
+	cpumask_t *active_mask;
+	struct pmu *pmu;
+	struct perf_event *events[MAX_COUNTERS];
+	struct amd_uncore *free_when_cpu_online;
+};
+
+static struct amd_uncore * __percpu *amd_uncore_nb;
+static struct amd_uncore * __percpu *amd_uncore_l2;
+
+static struct pmu amd_nb_pmu;
+static struct pmu amd_l2_pmu;
+
+static cpumask_t amd_nb_active_mask;
+static cpumask_t amd_l2_active_mask;
+
+static bool is_nb_event(struct perf_event *event)
+{
+	return event->pmu->type == amd_nb_pmu.type;
+}
+
+static bool is_l2_event(struct perf_event *event)
+{
+	return event->pmu->type == amd_l2_pmu.type;
+}
+
+static struct amd_uncore *event_to_amd_uncore(struct perf_event *event)
+{
+	if (is_nb_event(event) && amd_uncore_nb)
+		return *per_cpu_ptr(amd_uncore_nb, event->cpu);
+	else if (is_l2_event(event) && amd_uncore_l2)
+		return *per_cpu_ptr(amd_uncore_l2, event->cpu);
+
+	return NULL;
+}
+
+static void amd_uncore_read(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 prev, new;
+	s64 delta;
+
+	/*
+	 * since we do not enable counter overflow interrupts,
+	 * we do not have to worry about prev_count changing on us
+	 */
+
+	prev = local64_read(&hwc->prev_count);
+	rdpmcl(hwc->event_base_rdpmc, new);
+	local64_set(&hwc->prev_count, new);
+	delta = (new << COUNTER_SHIFT) - (prev << COUNTER_SHIFT);
+	delta >>= COUNTER_SHIFT;
+	local64_add(delta, &event->count);
+}
+
+static void amd_uncore_start(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (flags & PERF_EF_RELOAD)
+		wrmsrl(hwc->event_base, (u64)local64_read(&hwc->prev_count));
+
+	hwc->state = 0;
+	wrmsrl(hwc->config_base, (hwc->config | ARCH_PERFMON_EVENTSEL_ENABLE));
+	perf_event_update_userpage(event);
+}
+
+static void amd_uncore_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	wrmsrl(hwc->config_base, hwc->config);
+	hwc->state |= PERF_HES_STOPPED;
+
+	if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		amd_uncore_read(event);
+		hwc->state |= PERF_HES_UPTODATE;
+	}
+}
+
+static int amd_uncore_add(struct perf_event *event, int flags)
+{
+	int i;
+	struct amd_uncore *uncore = event_to_amd_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+
+	/* are we already assigned? */
+	if (hwc->idx != -1 && uncore->events[hwc->idx] == event)
+		goto out;
+
+	for (i = 0; i < uncore->num_counters; i++) {
+		if (uncore->events[i] == event) {
+			hwc->idx = i;
+			goto out;
+		}
+	}
+
+	/* if not, take the first available counter */
+	hwc->idx = -1;
+	for (i = 0; i < uncore->num_counters; i++) {
+		if (cmpxchg(&uncore->events[i], NULL, event) == NULL) {
+			hwc->idx = i;
+			break;
+		}
+	}
+
+out:
+	if (hwc->idx == -1)
+		return -EBUSY;
+
+	hwc->config_base = uncore->msr_base + (2 * hwc->idx);
+	hwc->event_base = uncore->msr_base + 1 + (2 * hwc->idx);
+	hwc->event_base_rdpmc = uncore->rdpmc_base + hwc->idx;
+	hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+	if (flags & PERF_EF_START)
+		amd_uncore_start(event, PERF_EF_RELOAD);
+
+	return 0;
+}
+
+static void amd_uncore_del(struct perf_event *event, int flags)
+{
+	int i;
+	struct amd_uncore *uncore = event_to_amd_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+
+	amd_uncore_stop(event, PERF_EF_UPDATE);
+
+	for (i = 0; i < uncore->num_counters; i++) {
+		if (cmpxchg(&uncore->events[i], event, NULL) == event)
+			break;
+	}
+
+	hwc->idx = -1;
+}
+
+static int amd_uncore_event_init(struct perf_event *event)
+{
+	struct amd_uncore *uncore;
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/*
+	 * NB and Last level cache counters (MSRs) are shared across all cores
+	 * that share the same NB / Last level cache.  On family 16h and below,
+	 * Interrupts can be directed to a single target core, however, event
+	 * counts generated by processes running on other cores cannot be masked
+	 * out. So we do not support sampling and per-thread events via
+	 * CAP_NO_INTERRUPT, and we do not enable counter overflow interrupts:
+	 */
+
+	/* NB and L2 counters do not have usr/os/guest/host bits */
+	if (event->attr.exclude_user || event->attr.exclude_kernel ||
+	    event->attr.exclude_host || event->attr.exclude_guest)
+		return -EINVAL;
+
+	hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB;
+	hwc->idx = -1;
+
+	if (event->cpu < 0)
+		return -EINVAL;
+
+	uncore = event_to_amd_uncore(event);
+	if (!uncore)
+		return -ENODEV;
+
+	/*
+	 * since request can come in to any of the shared cores, we will remap
+	 * to a single common cpu.
+	 */
+	event->cpu = uncore->cpu;
+
+	return 0;
+}
+
+static ssize_t amd_uncore_attr_show_cpumask(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	cpumask_t *active_mask;
+	struct pmu *pmu = dev_get_drvdata(dev);
+
+	if (pmu->type == amd_nb_pmu.type)
+		active_mask = &amd_nb_active_mask;
+	else if (pmu->type == amd_l2_pmu.type)
+		active_mask = &amd_l2_active_mask;
+	else
+		return 0;
+
+	return cpumap_print_to_pagebuf(true, buf, active_mask);
+}
+static DEVICE_ATTR(cpumask, S_IRUGO, amd_uncore_attr_show_cpumask, NULL);
+
+static struct attribute *amd_uncore_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static struct attribute_group amd_uncore_attr_group = {
+	.attrs = amd_uncore_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-7,32-35");
+PMU_FORMAT_ATTR(umask, "config:8-15");
+
+static struct attribute *amd_uncore_format_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	NULL,
+};
+
+static struct attribute_group amd_uncore_format_group = {
+	.name = "format",
+	.attrs = amd_uncore_format_attr,
+};
+
+static const struct attribute_group *amd_uncore_attr_groups[] = {
+	&amd_uncore_attr_group,
+	&amd_uncore_format_group,
+	NULL,
+};
+
+static struct pmu amd_nb_pmu = {
+	.attr_groups	= amd_uncore_attr_groups,
+	.name		= "amd_nb",
+	.event_init	= amd_uncore_event_init,
+	.add		= amd_uncore_add,
+	.del		= amd_uncore_del,
+	.start		= amd_uncore_start,
+	.stop		= amd_uncore_stop,
+	.read		= amd_uncore_read,
+	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+};
+
+static struct pmu amd_l2_pmu = {
+	.attr_groups	= amd_uncore_attr_groups,
+	.name		= "amd_l2",
+	.event_init	= amd_uncore_event_init,
+	.add		= amd_uncore_add,
+	.del		= amd_uncore_del,
+	.start		= amd_uncore_start,
+	.stop		= amd_uncore_stop,
+	.read		= amd_uncore_read,
+	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+};
+
+static struct amd_uncore *amd_uncore_alloc(unsigned int cpu)
+{
+	return kzalloc_node(sizeof(struct amd_uncore), GFP_KERNEL,
+			cpu_to_node(cpu));
+}
+
+static int amd_uncore_cpu_up_prepare(unsigned int cpu)
+{
+	struct amd_uncore *uncore_nb = NULL, *uncore_l2;
+
+	if (amd_uncore_nb) {
+		uncore_nb = amd_uncore_alloc(cpu);
+		if (!uncore_nb)
+			goto fail;
+		uncore_nb->cpu = cpu;
+		uncore_nb->num_counters = NUM_COUNTERS_NB;
+		uncore_nb->rdpmc_base = RDPMC_BASE_NB;
+		uncore_nb->msr_base = MSR_F15H_NB_PERF_CTL;
+		uncore_nb->active_mask = &amd_nb_active_mask;
+		uncore_nb->pmu = &amd_nb_pmu;
+		*per_cpu_ptr(amd_uncore_nb, cpu) = uncore_nb;
+	}
+
+	if (amd_uncore_l2) {
+		uncore_l2 = amd_uncore_alloc(cpu);
+		if (!uncore_l2)
+			goto fail;
+		uncore_l2->cpu = cpu;
+		uncore_l2->num_counters = NUM_COUNTERS_L2;
+		uncore_l2->rdpmc_base = RDPMC_BASE_L2;
+		uncore_l2->msr_base = MSR_F16H_L2I_PERF_CTL;
+		uncore_l2->active_mask = &amd_l2_active_mask;
+		uncore_l2->pmu = &amd_l2_pmu;
+		*per_cpu_ptr(amd_uncore_l2, cpu) = uncore_l2;
+	}
+
+	return 0;
+
+fail:
+	kfree(uncore_nb);
+	return -ENOMEM;
+}
+
+static struct amd_uncore *
+amd_uncore_find_online_sibling(struct amd_uncore *this,
+			       struct amd_uncore * __percpu *uncores)
+{
+	unsigned int cpu;
+	struct amd_uncore *that;
+
+	for_each_online_cpu(cpu) {
+		that = *per_cpu_ptr(uncores, cpu);
+
+		if (!that)
+			continue;
+
+		if (this == that)
+			continue;
+
+		if (this->id == that->id) {
+			that->free_when_cpu_online = this;
+			this = that;
+			break;
+		}
+	}
+
+	this->refcnt++;
+	return this;
+}
+
+static void amd_uncore_cpu_starting(unsigned int cpu)
+{
+	unsigned int eax, ebx, ecx, edx;
+	struct amd_uncore *uncore;
+
+	if (amd_uncore_nb) {
+		uncore = *per_cpu_ptr(amd_uncore_nb, cpu);
+		cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
+		uncore->id = ecx & 0xff;
+
+		uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_nb);
+		*per_cpu_ptr(amd_uncore_nb, cpu) = uncore;
+	}
+
+	if (amd_uncore_l2) {
+		unsigned int apicid = cpu_data(cpu).apicid;
+		unsigned int nshared;
+
+		uncore = *per_cpu_ptr(amd_uncore_l2, cpu);
+		cpuid_count(0x8000001d, 2, &eax, &ebx, &ecx, &edx);
+		nshared = ((eax >> 14) & 0xfff) + 1;
+		uncore->id = apicid - (apicid % nshared);
+
+		uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_l2);
+		*per_cpu_ptr(amd_uncore_l2, cpu) = uncore;
+	}
+}
+
+static void uncore_online(unsigned int cpu,
+			  struct amd_uncore * __percpu *uncores)
+{
+	struct amd_uncore *uncore = *per_cpu_ptr(uncores, cpu);
+
+	kfree(uncore->free_when_cpu_online);
+	uncore->free_when_cpu_online = NULL;
+
+	if (cpu == uncore->cpu)
+		cpumask_set_cpu(cpu, uncore->active_mask);
+}
+
+static void amd_uncore_cpu_online(unsigned int cpu)
+{
+	if (amd_uncore_nb)
+		uncore_online(cpu, amd_uncore_nb);
+
+	if (amd_uncore_l2)
+		uncore_online(cpu, amd_uncore_l2);
+}
+
+static void uncore_down_prepare(unsigned int cpu,
+				struct amd_uncore * __percpu *uncores)
+{
+	unsigned int i;
+	struct amd_uncore *this = *per_cpu_ptr(uncores, cpu);
+
+	if (this->cpu != cpu)
+		return;
+
+	/* this cpu is going down, migrate to a shared sibling if possible */
+	for_each_online_cpu(i) {
+		struct amd_uncore *that = *per_cpu_ptr(uncores, i);
+
+		if (cpu == i)
+			continue;
+
+		if (this == that) {
+			perf_pmu_migrate_context(this->pmu, cpu, i);
+			cpumask_clear_cpu(cpu, that->active_mask);
+			cpumask_set_cpu(i, that->active_mask);
+			that->cpu = i;
+			break;
+		}
+	}
+}
+
+static void amd_uncore_cpu_down_prepare(unsigned int cpu)
+{
+	if (amd_uncore_nb)
+		uncore_down_prepare(cpu, amd_uncore_nb);
+
+	if (amd_uncore_l2)
+		uncore_down_prepare(cpu, amd_uncore_l2);
+}
+
+static void uncore_dead(unsigned int cpu, struct amd_uncore * __percpu *uncores)
+{
+	struct amd_uncore *uncore = *per_cpu_ptr(uncores, cpu);
+
+	if (cpu == uncore->cpu)
+		cpumask_clear_cpu(cpu, uncore->active_mask);
+
+	if (!--uncore->refcnt)
+		kfree(uncore);
+	*per_cpu_ptr(uncores, cpu) = NULL;
+}
+
+static void amd_uncore_cpu_dead(unsigned int cpu)
+{
+	if (amd_uncore_nb)
+		uncore_dead(cpu, amd_uncore_nb);
+
+	if (amd_uncore_l2)
+		uncore_dead(cpu, amd_uncore_l2);
+}
+
+static int
+amd_uncore_cpu_notifier(struct notifier_block *self, unsigned long action,
+			void *hcpu)
+{
+	unsigned int cpu = (long)hcpu;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		if (amd_uncore_cpu_up_prepare(cpu))
+			return notifier_from_errno(-ENOMEM);
+		break;
+
+	case CPU_STARTING:
+		amd_uncore_cpu_starting(cpu);
+		break;
+
+	case CPU_ONLINE:
+		amd_uncore_cpu_online(cpu);
+		break;
+
+	case CPU_DOWN_PREPARE:
+		amd_uncore_cpu_down_prepare(cpu);
+		break;
+
+	case CPU_UP_CANCELED:
+	case CPU_DEAD:
+		amd_uncore_cpu_dead(cpu);
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block amd_uncore_cpu_notifier_block = {
+	.notifier_call	= amd_uncore_cpu_notifier,
+	.priority	= CPU_PRI_PERF + 1,
+};
+
+static void __init init_cpu_already_online(void *dummy)
+{
+	unsigned int cpu = smp_processor_id();
+
+	amd_uncore_cpu_starting(cpu);
+	amd_uncore_cpu_online(cpu);
+}
+
+static void cleanup_cpu_online(void *dummy)
+{
+	unsigned int cpu = smp_processor_id();
+
+	amd_uncore_cpu_dead(cpu);
+}
+
+static int __init amd_uncore_init(void)
+{
+	unsigned int cpu, cpu2;
+	int ret = -ENODEV;
+
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+		goto fail_nodev;
+
+	if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
+		goto fail_nodev;
+
+	if (boot_cpu_has(X86_FEATURE_PERFCTR_NB)) {
+		amd_uncore_nb = alloc_percpu(struct amd_uncore *);
+		if (!amd_uncore_nb) {
+			ret = -ENOMEM;
+			goto fail_nb;
+		}
+		ret = perf_pmu_register(&amd_nb_pmu, amd_nb_pmu.name, -1);
+		if (ret)
+			goto fail_nb;
+
+		printk(KERN_INFO "perf: AMD NB counters detected\n");
+		ret = 0;
+	}
+
+	if (boot_cpu_has(X86_FEATURE_PERFCTR_L2)) {
+		amd_uncore_l2 = alloc_percpu(struct amd_uncore *);
+		if (!amd_uncore_l2) {
+			ret = -ENOMEM;
+			goto fail_l2;
+		}
+		ret = perf_pmu_register(&amd_l2_pmu, amd_l2_pmu.name, -1);
+		if (ret)
+			goto fail_l2;
+
+		printk(KERN_INFO "perf: AMD L2I counters detected\n");
+		ret = 0;
+	}
+
+	if (ret)
+		goto fail_nodev;
+
+	cpu_notifier_register_begin();
+
+	/* init cpus already online before registering for hotplug notifier */
+	for_each_online_cpu(cpu) {
+		ret = amd_uncore_cpu_up_prepare(cpu);
+		if (ret)
+			goto fail_online;
+		smp_call_function_single(cpu, init_cpu_already_online, NULL, 1);
+	}
+
+	__register_cpu_notifier(&amd_uncore_cpu_notifier_block);
+	cpu_notifier_register_done();
+
+	return 0;
+
+
+fail_online:
+	for_each_online_cpu(cpu2) {
+		if (cpu2 == cpu)
+			break;
+		smp_call_function_single(cpu, cleanup_cpu_online, NULL, 1);
+	}
+	cpu_notifier_register_done();
+
+	/* amd_uncore_nb/l2 should have been freed by cleanup_cpu_online */
+	amd_uncore_nb = amd_uncore_l2 = NULL;
+
+	if (boot_cpu_has(X86_FEATURE_PERFCTR_L2))
+		perf_pmu_unregister(&amd_l2_pmu);
+fail_l2:
+	if (boot_cpu_has(X86_FEATURE_PERFCTR_NB))
+		perf_pmu_unregister(&amd_nb_pmu);
+	if (amd_uncore_l2)
+		free_percpu(amd_uncore_l2);
+fail_nb:
+	if (amd_uncore_nb)
+		free_percpu(amd_uncore_nb);
+
+fail_nodev:
+	return ret;
+}
+device_initcall(amd_uncore_init);
--- linux-4.4.0.orig/arch/x86/events/core.c
+++ linux-4.4.0/arch/x86/events/core.c
@@ -0,0 +1,2428 @@
+/*
+ * Performance events x86 architecture code
+ *
+ *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
+ *  Copyright (C) 2009 Jaswinder Singh Rajput
+ *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
+ *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
+ *  Copyright (C) 2009 Google, Inc., Stephane Eranian
+ *
+ *  For licencing details see kernel-base/COPYING
+ */
+
+#include <linux/perf_event.h>
+#include <linux/capability.h>
+#include <linux/notifier.h>
+#include <linux/hardirq.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/kdebug.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/nospec.h>
+
+#include <asm/apic.h>
+#include <asm/stacktrace.h>
+#include <asm/nmi.h>
+#include <asm/smp.h>
+#include <asm/alternative.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/timer.h>
+#include <asm/desc.h>
+#include <asm/ldt.h>
+
+#include "perf_event.h"
+
+struct x86_pmu x86_pmu __read_mostly;
+
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
+	.enabled = 1,
+};
+
+struct static_key rdpmc_always_available = STATIC_KEY_INIT_FALSE;
+
+u64 __read_mostly hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX];
+u64 __read_mostly hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX];
+
+/*
+ * Propagate event elapsed time into the generic event.
+ * Can only be executed on the CPU where the event is active.
+ * Returns the delta events processed.
+ */
+u64 x86_perf_event_update(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int shift = 64 - x86_pmu.cntval_bits;
+	u64 prev_raw_count, new_raw_count;
+	int idx = hwc->idx;
+	u64 delta;
+
+	if (idx == INTEL_PMC_IDX_FIXED_BTS)
+		return 0;
+
+	/*
+	 * Careful: an NMI might modify the previous event value.
+	 *
+	 * Our tactic to handle this is to first atomically read and
+	 * exchange a new raw count - then add that new-prev delta
+	 * count to the generic event atomically:
+	 */
+again:
+	prev_raw_count = local64_read(&hwc->prev_count);
+	rdpmcl(hwc->event_base_rdpmc, new_raw_count);
+
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+					new_raw_count) != prev_raw_count)
+		goto again;
+
+	/*
+	 * Now we have the new raw value and have updated the prev
+	 * timestamp already. We can now calculate the elapsed delta
+	 * (event-)time and add that to the generic event.
+	 *
+	 * Careful, not all hw sign-extends above the physical width
+	 * of the count.
+	 */
+	delta = (new_raw_count << shift) - (prev_raw_count << shift);
+	delta >>= shift;
+
+	local64_add(delta, &event->count);
+	local64_sub(delta, &hwc->period_left);
+
+	return new_raw_count;
+}
+
+/*
+ * Find and validate any extra registers to set up.
+ */
+static int x86_pmu_extra_regs(u64 config, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg;
+	struct extra_reg *er;
+
+	reg = &event->hw.extra_reg;
+
+	if (!x86_pmu.extra_regs)
+		return 0;
+
+	for (er = x86_pmu.extra_regs; er->msr; er++) {
+		if (er->event != (config & er->config_mask))
+			continue;
+		if (event->attr.config1 & ~er->valid_mask)
+			return -EINVAL;
+		/* Check if the extra msrs can be safely accessed*/
+		if (!er->extra_msr_access)
+			return -ENXIO;
+
+		reg->idx = er->idx;
+		reg->config = event->attr.config1;
+		reg->reg = er->msr;
+		break;
+	}
+	return 0;
+}
+
+static atomic_t active_events;
+static atomic_t pmc_refcount;
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+static bool reserve_pmc_hardware(void)
+{
+	int i;
+
+	for (i = 0; i < x86_pmu.num_counters; i++) {
+		if (!reserve_perfctr_nmi(x86_pmu_event_addr(i)))
+			goto perfctr_fail;
+	}
+
+	for (i = 0; i < x86_pmu.num_counters; i++) {
+		if (!reserve_evntsel_nmi(x86_pmu_config_addr(i)))
+			goto eventsel_fail;
+	}
+
+	return true;
+
+eventsel_fail:
+	for (i--; i >= 0; i--)
+		release_evntsel_nmi(x86_pmu_config_addr(i));
+
+	i = x86_pmu.num_counters;
+
+perfctr_fail:
+	for (i--; i >= 0; i--)
+		release_perfctr_nmi(x86_pmu_event_addr(i));
+
+	return false;
+}
+
+static void release_pmc_hardware(void)
+{
+	int i;
+
+	for (i = 0; i < x86_pmu.num_counters; i++) {
+		release_perfctr_nmi(x86_pmu_event_addr(i));
+		release_evntsel_nmi(x86_pmu_config_addr(i));
+	}
+}
+
+#else
+
+static bool reserve_pmc_hardware(void) { return true; }
+static void release_pmc_hardware(void) {}
+
+#endif
+
+static bool check_hw_exists(void)
+{
+	u64 val, val_fail = -1, val_new= ~0;
+	int i, reg, reg_fail = -1, ret = 0;
+	int bios_fail = 0;
+	int reg_safe = -1;
+
+	/*
+	 * Check to see if the BIOS enabled any of the counters, if so
+	 * complain and bail.
+	 */
+	for (i = 0; i < x86_pmu.num_counters; i++) {
+		reg = x86_pmu_config_addr(i);
+		ret = rdmsrl_safe(reg, &val);
+		if (ret)
+			goto msr_fail;
+		if (val & ARCH_PERFMON_EVENTSEL_ENABLE) {
+			bios_fail = 1;
+			val_fail = val;
+			reg_fail = reg;
+		} else {
+			reg_safe = i;
+		}
+	}
+
+	if (x86_pmu.num_counters_fixed) {
+		reg = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
+		ret = rdmsrl_safe(reg, &val);
+		if (ret)
+			goto msr_fail;
+		for (i = 0; i < x86_pmu.num_counters_fixed; i++) {
+			if (val & (0x03 << i*4)) {
+				bios_fail = 1;
+				val_fail = val;
+				reg_fail = reg;
+			}
+		}
+	}
+
+	/*
+	 * If all the counters are enabled, the below test will always
+	 * fail.  The tools will also become useless in this scenario.
+	 * Just fail and disable the hardware counters.
+	 */
+
+	if (reg_safe == -1) {
+		reg = reg_safe;
+		goto msr_fail;
+	}
+
+	/*
+	 * Read the current value, change it and read it back to see if it
+	 * matches, this is needed to detect certain hardware emulators
+	 * (qemu/kvm) that don't trap on the MSR access and always return 0s.
+	 */
+	reg = x86_pmu_event_addr(reg_safe);
+	if (rdmsrl_safe(reg, &val))
+		goto msr_fail;
+	val ^= 0xffffUL;
+	ret = wrmsrl_safe(reg, val);
+	ret |= rdmsrl_safe(reg, &val_new);
+	if (ret || val != val_new)
+		goto msr_fail;
+
+	/*
+	 * We still allow the PMU driver to operate:
+	 */
+	if (bios_fail) {
+		printk(KERN_CONT "Broken BIOS detected, complain to your hardware vendor.\n");
+		printk(KERN_ERR FW_BUG "the BIOS has corrupted hw-PMU resources (MSR %x is %Lx)\n", reg_fail, val_fail);
+	}
+
+	return true;
+
+msr_fail:
+	printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n");
+	printk("%sFailed to access perfctr msr (MSR %x is %Lx)\n",
+		boot_cpu_has(X86_FEATURE_HYPERVISOR) ? KERN_INFO : KERN_ERR,
+		reg, val_new);
+
+	return false;
+}
+
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+	x86_release_hardware();
+	atomic_dec(&active_events);
+}
+
+void hw_perf_lbr_event_destroy(struct perf_event *event)
+{
+	hw_perf_event_destroy(event);
+
+	/* undo the lbr/bts event accounting */
+	x86_del_exclusive(x86_lbr_exclusive_lbr);
+}
+
+static inline int x86_pmu_initialized(void)
+{
+	return x86_pmu.handle_irq != NULL;
+}
+
+static inline int
+set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event *event)
+{
+	struct perf_event_attr *attr = &event->attr;
+	unsigned int cache_type, cache_op, cache_result;
+	u64 config, val;
+
+	config = attr->config;
+
+	cache_type = (config >> 0) & 0xff;
+	if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
+		return -EINVAL;
+	cache_type = array_index_nospec(cache_type, PERF_COUNT_HW_CACHE_MAX);
+
+	cache_op = (config >>  8) & 0xff;
+	if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
+		return -EINVAL;
+	cache_op = array_index_nospec(cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
+
+	cache_result = (config >> 16) & 0xff;
+	if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+		return -EINVAL;
+	cache_result = array_index_nospec(cache_result, PERF_COUNT_HW_CACHE_RESULT_MAX);
+
+	val = hw_cache_event_ids[cache_type][cache_op][cache_result];
+
+	if (val == 0)
+		return -ENOENT;
+
+	if (val == -1)
+		return -EINVAL;
+
+	hwc->config |= val;
+	attr->config1 = hw_cache_extra_regs[cache_type][cache_op][cache_result];
+	return x86_pmu_extra_regs(val, event);
+}
+
+int x86_reserve_hardware(void)
+{
+	int err = 0;
+
+	if (!atomic_inc_not_zero(&pmc_refcount)) {
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_read(&pmc_refcount) == 0) {
+			if (!reserve_pmc_hardware())
+				err = -EBUSY;
+			else
+				reserve_ds_buffers();
+		}
+		if (!err)
+			atomic_inc(&pmc_refcount);
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+
+	return err;
+}
+
+void x86_release_hardware(void)
+{
+	if (atomic_dec_and_mutex_lock(&pmc_refcount, &pmc_reserve_mutex)) {
+		release_pmc_hardware();
+		release_ds_buffers();
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+}
+
+/*
+ * Check if we can create event of a certain type (that no conflicting events
+ * are present).
+ */
+int x86_add_exclusive(unsigned int what)
+{
+	int i;
+
+	if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) {
+		mutex_lock(&pmc_reserve_mutex);
+		for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
+			if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i]))
+				goto fail_unlock;
+		}
+		atomic_inc(&x86_pmu.lbr_exclusive[what]);
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+
+	atomic_inc(&active_events);
+	return 0;
+
+fail_unlock:
+	mutex_unlock(&pmc_reserve_mutex);
+	return -EBUSY;
+}
+
+void x86_del_exclusive(unsigned int what)
+{
+	atomic_dec(&x86_pmu.lbr_exclusive[what]);
+	atomic_dec(&active_events);
+}
+
+int x86_setup_perfctr(struct perf_event *event)
+{
+	struct perf_event_attr *attr = &event->attr;
+	struct hw_perf_event *hwc = &event->hw;
+	u64 config;
+
+	if (!is_sampling_event(event)) {
+		hwc->sample_period = x86_pmu.max_period;
+		hwc->last_period = hwc->sample_period;
+		local64_set(&hwc->period_left, hwc->sample_period);
+	}
+
+	if (attr->type == PERF_TYPE_RAW)
+		return x86_pmu_extra_regs(event->attr.config, event);
+
+	if (attr->type == PERF_TYPE_HW_CACHE)
+		return set_ext_hw_attr(hwc, event);
+
+	if (attr->config >= x86_pmu.max_events)
+		return -EINVAL;
+
+	attr->config = array_index_nospec((unsigned long)attr->config, x86_pmu.max_events);
+
+	/*
+	 * The generic map:
+	 */
+	config = x86_pmu.event_map(attr->config);
+
+	if (config == 0)
+		return -ENOENT;
+
+	if (config == -1LL)
+		return -EINVAL;
+
+	/*
+	 * Branch tracing:
+	 */
+	if (attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS &&
+	    !attr->freq && hwc->sample_period == 1) {
+		/* BTS is not supported by this architecture. */
+		if (!x86_pmu.bts_active)
+			return -EOPNOTSUPP;
+
+		/* BTS is currently only allowed for user-mode. */
+		if (!attr->exclude_kernel)
+			return -EOPNOTSUPP;
+
+		/* disallow bts if conflicting events are present */
+		if (x86_add_exclusive(x86_lbr_exclusive_lbr))
+			return -EBUSY;
+
+		event->destroy = hw_perf_lbr_event_destroy;
+	}
+
+	hwc->config |= config;
+
+	return 0;
+}
+
+/*
+ * check that branch_sample_type is compatible with
+ * settings needed for precise_ip > 1 which implies
+ * using the LBR to capture ALL taken branches at the
+ * priv levels of the measurement
+ */
+static inline int precise_br_compat(struct perf_event *event)
+{
+	u64 m = event->attr.branch_sample_type;
+	u64 b = 0;
+
+	/* must capture all branches */
+	if (!(m & PERF_SAMPLE_BRANCH_ANY))
+		return 0;
+
+	m &= PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_USER;
+
+	if (!event->attr.exclude_user)
+		b |= PERF_SAMPLE_BRANCH_USER;
+
+	if (!event->attr.exclude_kernel)
+		b |= PERF_SAMPLE_BRANCH_KERNEL;
+
+	/*
+	 * ignore PERF_SAMPLE_BRANCH_HV, not supported on x86
+	 */
+
+	return m == b;
+}
+
+int x86_pmu_hw_config(struct perf_event *event)
+{
+	if (event->attr.precise_ip) {
+		int precise = 0;
+
+		/* Support for constant skid */
+		if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {
+			precise++;
+
+			/* Support for IP fixup */
+			if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2)
+				precise++;
+		}
+
+		if (event->attr.precise_ip > precise)
+			return -EOPNOTSUPP;
+	}
+	/*
+	 * check that PEBS LBR correction does not conflict with
+	 * whatever the user is asking with attr->branch_sample_type
+	 */
+	if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format < 2) {
+		u64 *br_type = &event->attr.branch_sample_type;
+
+		if (has_branch_stack(event)) {
+			if (!precise_br_compat(event))
+				return -EOPNOTSUPP;
+
+			/* branch_sample_type is compatible */
+
+		} else {
+			/*
+			 * user did not specify  branch_sample_type
+			 *
+			 * For PEBS fixups, we capture all
+			 * the branches at the priv level of the
+			 * event.
+			 */
+			*br_type = PERF_SAMPLE_BRANCH_ANY;
+
+			if (!event->attr.exclude_user)
+				*br_type |= PERF_SAMPLE_BRANCH_USER;
+
+			if (!event->attr.exclude_kernel)
+				*br_type |= PERF_SAMPLE_BRANCH_KERNEL;
+		}
+	}
+
+	if (event->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK)
+		event->attach_state |= PERF_ATTACH_TASK_DATA;
+
+	/*
+	 * Generate PMC IRQs:
+	 * (keep 'enabled' bit clear for now)
+	 */
+	event->hw.config = ARCH_PERFMON_EVENTSEL_INT;
+
+	/*
+	 * Count user and OS events unless requested not to
+	 */
+	if (!event->attr.exclude_user)
+		event->hw.config |= ARCH_PERFMON_EVENTSEL_USR;
+	if (!event->attr.exclude_kernel)
+		event->hw.config |= ARCH_PERFMON_EVENTSEL_OS;
+
+	if (event->attr.type == PERF_TYPE_RAW)
+		event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK;
+
+	if (event->attr.sample_period && x86_pmu.limit_period) {
+		if (x86_pmu.limit_period(event, event->attr.sample_period) >
+				event->attr.sample_period)
+			return -EINVAL;
+	}
+
+	return x86_setup_perfctr(event);
+}
+
+/*
+ * Setup the hardware configuration for a given attr_type
+ */
+static int __x86_pmu_event_init(struct perf_event *event)
+{
+	int err;
+
+	if (!x86_pmu_initialized())
+		return -ENODEV;
+
+	err = x86_reserve_hardware();
+	if (err)
+		return err;
+
+	atomic_inc(&active_events);
+	event->destroy = hw_perf_event_destroy;
+
+	event->hw.idx = -1;
+	event->hw.last_cpu = -1;
+	event->hw.last_tag = ~0ULL;
+
+	/* mark unused */
+	event->hw.extra_reg.idx = EXTRA_REG_NONE;
+	event->hw.branch_reg.idx = EXTRA_REG_NONE;
+
+	return x86_pmu.hw_config(event);
+}
+
+void x86_pmu_disable_all(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	int idx;
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		u64 val;
+
+		if (!test_bit(idx, cpuc->active_mask))
+			continue;
+		rdmsrl(x86_pmu_config_addr(idx), val);
+		if (!(val & ARCH_PERFMON_EVENTSEL_ENABLE))
+			continue;
+		val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
+		wrmsrl(x86_pmu_config_addr(idx), val);
+	}
+}
+
+/*
+ * There may be PMI landing after enabled=0. The PMI hitting could be before or
+ * after disable_all.
+ *
+ * If PMI hits before disable_all, the PMU will be disabled in the NMI handler.
+ * It will not be re-enabled in the NMI handler again, because enabled=0. After
+ * handling the NMI, disable_all will be called, which will not change the
+ * state either. If PMI hits after disable_all, the PMU is already disabled
+ * before entering NMI handler. The NMI handler will not change the state
+ * either.
+ *
+ * So either situation is harmless.
+ */
+static void x86_pmu_disable(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	if (!x86_pmu_initialized())
+		return;
+
+	if (!cpuc->enabled)
+		return;
+
+	cpuc->n_added = 0;
+	cpuc->enabled = 0;
+	barrier();
+
+	x86_pmu.disable_all();
+}
+
+void x86_pmu_enable_all(int added)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	int idx;
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		struct hw_perf_event *hwc = &cpuc->events[idx]->hw;
+
+		if (!test_bit(idx, cpuc->active_mask))
+			continue;
+
+		__x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
+	}
+}
+
+static struct pmu pmu;
+
+static inline int is_x86_event(struct perf_event *event)
+{
+	return event->pmu == &pmu;
+}
+
+/*
+ * Event scheduler state:
+ *
+ * Assign events iterating over all events and counters, beginning
+ * with events with least weights first. Keep the current iterator
+ * state in struct sched_state.
+ */
+struct sched_state {
+	int	weight;
+	int	event;		/* event index */
+	int	counter;	/* counter index */
+	int	unassigned;	/* number of events to be assigned left */
+	int	nr_gp;		/* number of GP counters used */
+	unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+};
+
+/* Total max is X86_PMC_IDX_MAX, but we are O(n!) limited */
+#define	SCHED_STATES_MAX	2
+
+struct perf_sched {
+	int			max_weight;
+	int			max_events;
+	int			max_gp;
+	int			saved_states;
+	struct event_constraint	**constraints;
+	struct sched_state	state;
+	struct sched_state	saved[SCHED_STATES_MAX];
+};
+
+/*
+ * Initialize interator that runs through all events and counters.
+ */
+static void perf_sched_init(struct perf_sched *sched, struct event_constraint **constraints,
+			    int num, int wmin, int wmax, int gpmax)
+{
+	int idx;
+
+	memset(sched, 0, sizeof(*sched));
+	sched->max_events	= num;
+	sched->max_weight	= wmax;
+	sched->max_gp		= gpmax;
+	sched->constraints	= constraints;
+
+	for (idx = 0; idx < num; idx++) {
+		if (constraints[idx]->weight == wmin)
+			break;
+	}
+
+	sched->state.event	= idx;		/* start with min weight */
+	sched->state.weight	= wmin;
+	sched->state.unassigned	= num;
+}
+
+static void perf_sched_save_state(struct perf_sched *sched)
+{
+	if (WARN_ON_ONCE(sched->saved_states >= SCHED_STATES_MAX))
+		return;
+
+	sched->saved[sched->saved_states] = sched->state;
+	sched->saved_states++;
+}
+
+static bool perf_sched_restore_state(struct perf_sched *sched)
+{
+	if (!sched->saved_states)
+		return false;
+
+	sched->saved_states--;
+	sched->state = sched->saved[sched->saved_states];
+
+	/* continue with next counter: */
+	clear_bit(sched->state.counter++, sched->state.used);
+
+	return true;
+}
+
+/*
+ * Select a counter for the current event to schedule. Return true on
+ * success.
+ */
+static bool __perf_sched_find_counter(struct perf_sched *sched)
+{
+	struct event_constraint *c;
+	int idx;
+
+	if (!sched->state.unassigned)
+		return false;
+
+	if (sched->state.event >= sched->max_events)
+		return false;
+
+	c = sched->constraints[sched->state.event];
+	/* Prefer fixed purpose counters */
+	if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) {
+		idx = INTEL_PMC_IDX_FIXED;
+		for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) {
+			if (!__test_and_set_bit(idx, sched->state.used))
+				goto done;
+		}
+	}
+
+	/* Grab the first unused counter starting with idx */
+	idx = sched->state.counter;
+	for_each_set_bit_from(idx, c->idxmsk, INTEL_PMC_IDX_FIXED) {
+		if (!__test_and_set_bit(idx, sched->state.used)) {
+			if (sched->state.nr_gp++ >= sched->max_gp)
+				return false;
+
+			goto done;
+		}
+	}
+
+	return false;
+
+done:
+	sched->state.counter = idx;
+
+	if (c->overlap)
+		perf_sched_save_state(sched);
+
+	return true;
+}
+
+static bool perf_sched_find_counter(struct perf_sched *sched)
+{
+	while (!__perf_sched_find_counter(sched)) {
+		if (!perf_sched_restore_state(sched))
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * Go through all unassigned events and find the next one to schedule.
+ * Take events with the least weight first. Return true on success.
+ */
+static bool perf_sched_next_event(struct perf_sched *sched)
+{
+	struct event_constraint *c;
+
+	if (!sched->state.unassigned || !--sched->state.unassigned)
+		return false;
+
+	do {
+		/* next event */
+		sched->state.event++;
+		if (sched->state.event >= sched->max_events) {
+			/* next weight */
+			sched->state.event = 0;
+			sched->state.weight++;
+			if (sched->state.weight > sched->max_weight)
+				return false;
+		}
+		c = sched->constraints[sched->state.event];
+	} while (c->weight != sched->state.weight);
+
+	sched->state.counter = 0;	/* start with first counter */
+
+	return true;
+}
+
+/*
+ * Assign a counter for each event.
+ */
+int perf_assign_events(struct event_constraint **constraints, int n,
+			int wmin, int wmax, int gpmax, int *assign)
+{
+	struct perf_sched sched;
+
+	perf_sched_init(&sched, constraints, n, wmin, wmax, gpmax);
+
+	do {
+		if (!perf_sched_find_counter(&sched))
+			break;	/* failed */
+		if (assign)
+			assign[sched.state.event] = sched.state.counter;
+	} while (perf_sched_next_event(&sched));
+
+	return sched.state.unassigned;
+}
+EXPORT_SYMBOL_GPL(perf_assign_events);
+
+int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
+{
+	struct event_constraint *c;
+	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	struct perf_event *e;
+	int i, wmin, wmax, unsched = 0;
+	struct hw_perf_event *hwc;
+
+	bitmap_zero(used_mask, X86_PMC_IDX_MAX);
+
+	if (x86_pmu.start_scheduling)
+		x86_pmu.start_scheduling(cpuc);
+
+	for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) {
+		cpuc->event_constraint[i] = NULL;
+		c = x86_pmu.get_event_constraints(cpuc, i, cpuc->event_list[i]);
+		cpuc->event_constraint[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 = &cpuc->event_list[i]->hw;
+		c = cpuc->event_constraint[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);
+		if (assign)
+			assign[i] = hwc->idx;
+	}
+
+	/* slow path */
+	if (i != n) {
+		int gpmax = x86_pmu.num_counters;
+
+		/*
+		 * Do not allow scheduling of more than half the available
+		 * generic counters.
+		 *
+		 * This helps avoid counter starvation of sibling thread by
+		 * ensuring at most half the counters cannot be in exclusive
+		 * mode. There is no designated counters for the limits. Any
+		 * N/2 counters can be used. This helps with events with
+		 * specific counter constraints.
+		 */
+		if (is_ht_workaround_enabled() && !cpuc->is_fake &&
+		    READ_ONCE(cpuc->excl_cntrs->exclusive_present))
+			gpmax /= 2;
+
+		unsched = perf_assign_events(cpuc->event_constraint, n, wmin,
+					     wmax, gpmax, assign);
+	}
+
+	/*
+	 * In case of success (unsched = 0), mark events as committed,
+	 * so we do not put_constraint() in case new events are added
+	 * and fail to be scheduled
+	 *
+	 * We invoke the lower level commit callback to lock the resource
+	 *
+	 * We do not need to do all of this in case we are called to
+	 * validate an event group (assign == NULL)
+	 */
+	if (!unsched && assign) {
+		for (i = 0; i < n; i++) {
+			e = cpuc->event_list[i];
+			e->hw.flags |= PERF_X86_EVENT_COMMITTED;
+			if (x86_pmu.commit_scheduling)
+				x86_pmu.commit_scheduling(cpuc, i, assign[i]);
+		}
+	} else {
+		for (i = 0; i < n; i++) {
+			e = cpuc->event_list[i];
+			/*
+			 * do not put_constraint() on comitted events,
+			 * because they are good to go
+			 */
+			if ((e->hw.flags & PERF_X86_EVENT_COMMITTED))
+				continue;
+
+			/*
+			 * release events that failed scheduling
+			 */
+			if (x86_pmu.put_event_constraints)
+				x86_pmu.put_event_constraints(cpuc, e);
+		}
+	}
+
+	if (x86_pmu.stop_scheduling)
+		x86_pmu.stop_scheduling(cpuc);
+
+	return unsched ? -EINVAL : 0;
+}
+
+/*
+ * dogrp: true if must collect siblings events (group)
+ * returns total number of events and error code
+ */
+static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, bool dogrp)
+{
+	struct perf_event *event;
+	int n, max_count;
+
+	max_count = x86_pmu.num_counters + x86_pmu.num_counters_fixed;
+
+	/* current number of events already accepted */
+	n = cpuc->n_events;
+
+	if (is_x86_event(leader)) {
+		if (n >= max_count)
+			return -EINVAL;
+		cpuc->event_list[n] = leader;
+		n++;
+	}
+	if (!dogrp)
+		return n;
+
+	list_for_each_entry(event, &leader->sibling_list, group_entry) {
+		if (!is_x86_event(event) ||
+		    event->state <= PERF_EVENT_STATE_OFF)
+			continue;
+
+		if (n >= max_count)
+			return -EINVAL;
+
+		cpuc->event_list[n] = event;
+		n++;
+	}
+	return n;
+}
+
+static inline void x86_assign_hw_event(struct perf_event *event,
+				struct cpu_hw_events *cpuc, int i)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	hwc->idx = cpuc->assign[i];
+	hwc->last_cpu = smp_processor_id();
+	hwc->last_tag = ++cpuc->tags[i];
+
+	if (hwc->idx == INTEL_PMC_IDX_FIXED_BTS) {
+		hwc->config_base = 0;
+		hwc->event_base	= 0;
+	} else if (hwc->idx >= INTEL_PMC_IDX_FIXED) {
+		hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
+		hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 + (hwc->idx - INTEL_PMC_IDX_FIXED);
+		hwc->event_base_rdpmc = (hwc->idx - INTEL_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 = x86_pmu_rdpmc_index(hwc->idx);
+	}
+}
+
+static inline int match_prev_assignment(struct hw_perf_event *hwc,
+					struct cpu_hw_events *cpuc,
+					int i)
+{
+	return hwc->idx == cpuc->assign[i] &&
+		hwc->last_cpu == smp_processor_id() &&
+		hwc->last_tag == cpuc->tags[i];
+}
+
+static void x86_pmu_start(struct perf_event *event, int flags);
+
+static void x86_pmu_enable(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct perf_event *event;
+	struct hw_perf_event *hwc;
+	int i, added = cpuc->n_added;
+
+	if (!x86_pmu_initialized())
+		return;
+
+	if (cpuc->enabled)
+		return;
+
+	if (cpuc->n_added) {
+		int n_running = cpuc->n_events - cpuc->n_added;
+		/*
+		 * apply assignment obtained either from
+		 * hw_perf_group_sched_in() or x86_pmu_enable()
+		 *
+		 * step1: save events moving to new counters
+		 */
+		for (i = 0; i < n_running; i++) {
+			event = cpuc->event_list[i];
+			hwc = &event->hw;
+
+			/*
+			 * we can avoid reprogramming counter if:
+			 * - assigned same counter as last time
+			 * - running on same CPU as last time
+			 * - no other event has used the counter since
+			 */
+			if (hwc->idx == -1 ||
+			    match_prev_assignment(hwc, cpuc, 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;
+
+			x86_pmu_stop(event, PERF_EF_UPDATE);
+		}
+
+		/*
+		 * step2: reprogram moved events into new counters
+		 */
+		for (i = 0; i < cpuc->n_events; i++) {
+			event = cpuc->event_list[i];
+			hwc = &event->hw;
+
+			if (!match_prev_assignment(hwc, cpuc, i))
+				x86_assign_hw_event(event, cpuc, i);
+			else if (i < n_running)
+				continue;
+
+			if (hwc->state & PERF_HES_ARCH)
+				continue;
+
+			x86_pmu_start(event, PERF_EF_RELOAD);
+		}
+		cpuc->n_added = 0;
+		perf_events_lapic_init();
+	}
+
+	cpuc->enabled = 1;
+	barrier();
+
+	x86_pmu.enable_all(added);
+}
+
+static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left);
+
+/*
+ * Set the next IRQ period, based on the hwc->period_left value.
+ * To be called with the event disabled in hw:
+ */
+int x86_perf_event_set_period(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	s64 left = local64_read(&hwc->period_left);
+	s64 period = hwc->sample_period;
+	int ret = 0, idx = hwc->idx;
+
+	if (idx == INTEL_PMC_IDX_FIXED_BTS)
+		return 0;
+
+	/*
+	 * If we are way outside a reasonable range then just skip forward:
+	 */
+	if (unlikely(left <= -period)) {
+		left = period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (unlikely(left <= 0)) {
+		left += period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+	/*
+	 * Quirk: certain CPUs dont like it if just 1 hw_event is left:
+	 */
+	if (unlikely(left < 2))
+		left = 2;
+
+	if (left > x86_pmu.max_period)
+		left = x86_pmu.max_period;
+
+	if (x86_pmu.limit_period)
+		left = x86_pmu.limit_period(event, left);
+
+	per_cpu(pmc_prev_left[idx], smp_processor_id()) = left;
+
+	if (!(hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) ||
+	    local64_read(&hwc->prev_count) != (u64)-left) {
+		/*
+		 * The hw event starts counting from this event offset,
+		 * mark it to be able to extra future deltas:
+		 */
+		local64_set(&hwc->prev_count, (u64)-left);
+
+		wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask);
+	}
+
+	/*
+	 * Due to erratum on certan cpu we need
+	 * a second write to be sure the register
+	 * is updated properly
+	 */
+	if (x86_pmu.perfctr_second_write) {
+		wrmsrl(hwc->event_base,
+			(u64)(-left) & x86_pmu.cntval_mask);
+	}
+
+	perf_event_update_userpage(event);
+
+	return ret;
+}
+
+void x86_pmu_enable_event(struct perf_event *event)
+{
+	if (__this_cpu_read(cpu_hw_events.enabled))
+		__x86_pmu_enable_event(&event->hw,
+				       ARCH_PERFMON_EVENTSEL_ENABLE);
+}
+
+/*
+ * Add a single event to the PMU.
+ *
+ * The event is added to the group of enabled events
+ * but only if it can be scehduled with existing events.
+ */
+static int x86_pmu_add(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct hw_perf_event *hwc;
+	int assign[X86_PMC_IDX_MAX];
+	int n, n0, ret;
+
+	hwc = &event->hw;
+
+	n0 = cpuc->n_events;
+	ret = n = collect_events(cpuc, event, false);
+	if (ret < 0)
+		goto out;
+
+	hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+	if (!(flags & PERF_EF_START))
+		hwc->state |= PERF_HES_ARCH;
+
+	/*
+	 * If group events scheduling transaction was started,
+	 * skip the schedulability test here, it will be performed
+	 * at commit time (->commit_txn) as a whole.
+	 */
+	if (cpuc->txn_flags & PERF_PMU_TXN_ADD)
+		goto done_collect;
+
+	ret = x86_pmu.schedule_events(cpuc, n, assign);
+	if (ret)
+		goto out;
+	/*
+	 * copy new assignment, now we know it is possible
+	 * will be used by hw_perf_enable()
+	 */
+	memcpy(cpuc->assign, assign, n*sizeof(int));
+
+done_collect:
+	/*
+	 * Commit the collect_events() state. See x86_pmu_del() and
+	 * x86_pmu_*_txn().
+	 */
+	cpuc->n_events = n;
+	cpuc->n_added += n - n0;
+	cpuc->n_txn += n - n0;
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static void x86_pmu_start(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	int idx = event->hw.idx;
+
+	if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+		return;
+
+	if (WARN_ON_ONCE(idx == -1))
+		return;
+
+	if (flags & PERF_EF_RELOAD) {
+		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+		x86_perf_event_set_period(event);
+	}
+
+	event->hw.state = 0;
+
+	cpuc->events[idx] = event;
+	__set_bit(idx, cpuc->active_mask);
+	__set_bit(idx, cpuc->running);
+	x86_pmu.enable(event);
+	perf_event_update_userpage(event);
+}
+
+void perf_event_print_debug(void)
+{
+	u64 ctrl, status, overflow, pmc_ctrl, pmc_count, prev_left, fixed;
+	u64 pebs, debugctl;
+	struct cpu_hw_events *cpuc;
+	unsigned long flags;
+	int cpu, idx;
+
+	if (!x86_pmu.num_counters)
+		return;
+
+	local_irq_save(flags);
+
+	cpu = smp_processor_id();
+	cpuc = &per_cpu(cpu_hw_events, cpu);
+
+	if (x86_pmu.version >= 2) {
+		rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
+		rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
+		rdmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, overflow);
+		rdmsrl(MSR_ARCH_PERFMON_FIXED_CTR_CTRL, fixed);
+
+		pr_info("\n");
+		pr_info("CPU#%d: ctrl:       %016llx\n", cpu, ctrl);
+		pr_info("CPU#%d: status:     %016llx\n", cpu, status);
+		pr_info("CPU#%d: overflow:   %016llx\n", cpu, overflow);
+		pr_info("CPU#%d: fixed:      %016llx\n", cpu, fixed);
+		if (x86_pmu.pebs_constraints) {
+			rdmsrl(MSR_IA32_PEBS_ENABLE, pebs);
+			pr_info("CPU#%d: pebs:       %016llx\n", cpu, pebs);
+		}
+		if (x86_pmu.lbr_nr) {
+			rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
+			pr_info("CPU#%d: debugctl:   %016llx\n", cpu, debugctl);
+		}
+	}
+	pr_info("CPU#%d: active:     %016llx\n", cpu, *(u64 *)cpuc->active_mask);
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		rdmsrl(x86_pmu_config_addr(idx), pmc_ctrl);
+		rdmsrl(x86_pmu_event_addr(idx), pmc_count);
+
+		prev_left = per_cpu(pmc_prev_left[idx], cpu);
+
+		pr_info("CPU#%d:   gen-PMC%d ctrl:  %016llx\n",
+			cpu, idx, pmc_ctrl);
+		pr_info("CPU#%d:   gen-PMC%d count: %016llx\n",
+			cpu, idx, pmc_count);
+		pr_info("CPU#%d:   gen-PMC%d left:  %016llx\n",
+			cpu, idx, prev_left);
+	}
+	for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) {
+		rdmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, pmc_count);
+
+		pr_info("CPU#%d: fixed-PMC%d count: %016llx\n",
+			cpu, idx, pmc_count);
+	}
+	local_irq_restore(flags);
+}
+
+void x86_pmu_stop(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (__test_and_clear_bit(hwc->idx, cpuc->active_mask)) {
+		x86_pmu.disable(event);
+		cpuc->events[hwc->idx] = NULL;
+		WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+		hwc->state |= PERF_HES_STOPPED;
+	}
+
+	if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		/*
+		 * Drain the remaining delta count out of a event
+		 * that we are disabling:
+		 */
+		x86_perf_event_update(event);
+		hwc->state |= PERF_HES_UPTODATE;
+	}
+}
+
+static void x86_pmu_del(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	int i;
+
+	/*
+	 * event is descheduled
+	 */
+	event->hw.flags &= ~PERF_X86_EVENT_COMMITTED;
+
+	/*
+	 * If we're called during a txn, we don't need to do anything.
+	 * The events never got scheduled and ->cancel_txn will truncate
+	 * the event_list.
+	 *
+	 * XXX assumes any ->del() called during a TXN will only be on
+	 * an event added during that same TXN.
+	 */
+	if (cpuc->txn_flags & PERF_PMU_TXN_ADD)
+		return;
+
+	/*
+	 * Not a TXN, therefore cleanup properly.
+	 */
+	x86_pmu_stop(event, PERF_EF_UPDATE);
+
+	for (i = 0; i < cpuc->n_events; i++) {
+		if (event == cpuc->event_list[i])
+			break;
+	}
+
+	if (WARN_ON_ONCE(i == cpuc->n_events)) /* called ->del() without ->add() ? */
+		return;
+
+	/* If we have a newly added event; make sure to decrease n_added. */
+	if (i >= cpuc->n_events - cpuc->n_added)
+		--cpuc->n_added;
+
+	if (x86_pmu.put_event_constraints)
+		x86_pmu.put_event_constraints(cpuc, event);
+
+	/* Delete the array entry. */
+	while (++i < cpuc->n_events) {
+		cpuc->event_list[i-1] = cpuc->event_list[i];
+		cpuc->event_constraint[i-1] = cpuc->event_constraint[i];
+	}
+	--cpuc->n_events;
+
+	perf_event_update_userpage(event);
+}
+
+int x86_pmu_handle_irq(struct pt_regs *regs)
+{
+	struct perf_sample_data data;
+	struct cpu_hw_events *cpuc;
+	struct perf_event *event;
+	int idx, handled = 0;
+	u64 val;
+
+	cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	/*
+	 * Some chipsets need to unmask the LVTPC in a particular spot
+	 * inside the nmi handler.  As a result, the unmasking was pushed
+	 * into all the nmi handlers.
+	 *
+	 * This generic handler doesn't seem to have any issues where the
+	 * unmasking occurs so it was left at the top.
+	 */
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		if (!test_bit(idx, cpuc->active_mask)) {
+			/*
+			 * Though we deactivated the counter some cpus
+			 * might still deliver spurious interrupts still
+			 * in flight. Catch them:
+			 */
+			if (__test_and_clear_bit(idx, cpuc->running))
+				handled++;
+			continue;
+		}
+
+		event = cpuc->events[idx];
+
+		val = x86_perf_event_update(event);
+		if (val & (1ULL << (x86_pmu.cntval_bits - 1)))
+			continue;
+
+		/*
+		 * event overflow
+		 */
+		handled++;
+		perf_sample_data_init(&data, 0, event->hw.last_period);
+
+		if (!x86_perf_event_set_period(event))
+			continue;
+
+		if (perf_event_overflow(event, &data, regs))
+			x86_pmu_stop(event, 0);
+	}
+
+	if (handled)
+		inc_irq_stat(apic_perf_irqs);
+
+	return handled;
+}
+
+void perf_events_lapic_init(void)
+{
+	if (!x86_pmu.apic || !x86_pmu_initialized())
+		return;
+
+	/*
+	 * Always use NMI for PMU
+	 */
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+}
+
+static int
+perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
+{
+	u64 start_clock;
+	u64 finish_clock;
+	int ret;
+
+	/*
+	 * All PMUs/events that share this PMI handler should make sure to
+	 * increment active_events for their events.
+	 */
+	if (!atomic_read(&active_events))
+		return NMI_DONE;
+
+	start_clock = sched_clock();
+	ret = x86_pmu.handle_irq(regs);
+	finish_clock = sched_clock();
+
+	perf_sample_event_took(finish_clock - start_clock);
+
+	return ret;
+}
+NOKPROBE_SYMBOL(perf_event_nmi_handler);
+
+struct event_constraint emptyconstraint;
+struct event_constraint unconstrained;
+
+static int
+x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (long)hcpu;
+	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+	int i, ret = NOTIFY_OK;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		for (i = 0 ; i < X86_PERF_KFREE_MAX; i++)
+			cpuc->kfree_on_online[i] = NULL;
+		if (x86_pmu.cpu_prepare)
+			ret = x86_pmu.cpu_prepare(cpu);
+		break;
+
+	case CPU_STARTING:
+		if (x86_pmu.cpu_starting)
+			x86_pmu.cpu_starting(cpu);
+		break;
+
+	case CPU_ONLINE:
+		for (i = 0 ; i < X86_PERF_KFREE_MAX; i++) {
+			kfree(cpuc->kfree_on_online[i]);
+			cpuc->kfree_on_online[i] = NULL;
+		}
+		break;
+
+	case CPU_DYING:
+		if (x86_pmu.cpu_dying)
+			x86_pmu.cpu_dying(cpu);
+		break;
+
+	case CPU_UP_CANCELED:
+	case CPU_DEAD:
+		if (x86_pmu.cpu_dead)
+			x86_pmu.cpu_dead(cpu);
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static void __init pmu_check_apic(void)
+{
+	if (cpu_has_apic)
+		return;
+
+	x86_pmu.apic = 0;
+	pr_info("no APIC, boot with the \"lapic\" boot parameter to force-enable it.\n");
+	pr_info("no hardware sampling interrupt available.\n");
+
+	/*
+	 * If we have a PMU initialized but no APIC
+	 * interrupts, we cannot sample hardware
+	 * events (user-space has to fall back and
+	 * sample via a hrtimer based software event):
+	 */
+	pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
+
+}
+
+static struct attribute_group x86_pmu_format_group = {
+	.name = "format",
+	.attrs = NULL,
+};
+
+/*
+ * Remove all undefined events (x86_pmu.event_map(id) == 0)
+ * out of events_attr attributes.
+ */
+static void __init filter_events(struct attribute **attrs)
+{
+	struct device_attribute *d;
+	struct perf_pmu_events_attr *pmu_attr;
+	int offset = 0;
+	int i, j;
+
+	for (i = 0; attrs[i]; i++) {
+		d = (struct device_attribute *)attrs[i];
+		pmu_attr = container_of(d, struct perf_pmu_events_attr, attr);
+		/* str trumps id */
+		if (pmu_attr->event_str)
+			continue;
+		if (x86_pmu.event_map(i + offset))
+			continue;
+
+		for (j = i; attrs[j]; j++)
+			attrs[j] = attrs[j + 1];
+
+		/* Check the shifted attr. */
+		i--;
+
+		/*
+		 * event_map() is index based, the attrs array is organized
+		 * by increasing event index. If we shift the events, then
+		 * we need to compensate for the event_map(), otherwise
+		 * we are looking up the wrong event in the map
+		 */
+		offset++;
+	}
+}
+
+/* Merge two pointer arrays */
+__init struct attribute **merge_attr(struct attribute **a, struct attribute **b)
+{
+	struct attribute **new;
+	int j, i;
+
+	for (j = 0; a[j]; j++)
+		;
+	for (i = 0; b[i]; i++)
+		j++;
+	j++;
+
+	new = kmalloc(sizeof(struct attribute *) * j, GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	j = 0;
+	for (i = 0; a[i]; i++)
+		new[j++] = a[i];
+	for (i = 0; b[i]; i++)
+		new[j++] = b[i];
+	new[j] = NULL;
+
+	return new;
+}
+
+ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
+			  char *page)
+{
+	struct perf_pmu_events_attr *pmu_attr = \
+		container_of(attr, struct perf_pmu_events_attr, attr);
+	u64 config = x86_pmu.event_map(pmu_attr->id);
+
+	/* string trumps id */
+	if (pmu_attr->event_str)
+		return sprintf(page, "%s", pmu_attr->event_str);
+
+	return x86_pmu.events_sysfs_show(page, config);
+}
+
+EVENT_ATTR(cpu-cycles,			CPU_CYCLES		);
+EVENT_ATTR(instructions,		INSTRUCTIONS		);
+EVENT_ATTR(cache-references,		CACHE_REFERENCES	);
+EVENT_ATTR(cache-misses, 		CACHE_MISSES		);
+EVENT_ATTR(branch-instructions,		BRANCH_INSTRUCTIONS	);
+EVENT_ATTR(branch-misses,		BRANCH_MISSES		);
+EVENT_ATTR(bus-cycles,			BUS_CYCLES		);
+EVENT_ATTR(stalled-cycles-frontend,	STALLED_CYCLES_FRONTEND	);
+EVENT_ATTR(stalled-cycles-backend,	STALLED_CYCLES_BACKEND	);
+EVENT_ATTR(ref-cycles,			REF_CPU_CYCLES		);
+
+static struct attribute *empty_attrs;
+
+static struct attribute *events_attr[] = {
+	EVENT_PTR(CPU_CYCLES),
+	EVENT_PTR(INSTRUCTIONS),
+	EVENT_PTR(CACHE_REFERENCES),
+	EVENT_PTR(CACHE_MISSES),
+	EVENT_PTR(BRANCH_INSTRUCTIONS),
+	EVENT_PTR(BRANCH_MISSES),
+	EVENT_PTR(BUS_CYCLES),
+	EVENT_PTR(STALLED_CYCLES_FRONTEND),
+	EVENT_PTR(STALLED_CYCLES_BACKEND),
+	EVENT_PTR(REF_CPU_CYCLES),
+	NULL,
+};
+
+static struct attribute_group x86_pmu_events_group = {
+	.name = "events",
+	.attrs = events_attr,
+};
+
+ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event)
+{
+	u64 umask  = (config & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
+	u64 cmask  = (config & ARCH_PERFMON_EVENTSEL_CMASK) >> 24;
+	bool edge  = (config & ARCH_PERFMON_EVENTSEL_EDGE);
+	bool pc    = (config & ARCH_PERFMON_EVENTSEL_PIN_CONTROL);
+	bool any   = (config & ARCH_PERFMON_EVENTSEL_ANY);
+	bool inv   = (config & ARCH_PERFMON_EVENTSEL_INV);
+	ssize_t ret;
+
+	/*
+	* We have whole page size to spend and just little data
+	* to write, so we can safely use sprintf.
+	*/
+	ret = sprintf(page, "event=0x%02llx", event);
+
+	if (umask)
+		ret += sprintf(page + ret, ",umask=0x%02llx", umask);
+
+	if (edge)
+		ret += sprintf(page + ret, ",edge");
+
+	if (pc)
+		ret += sprintf(page + ret, ",pc");
+
+	if (any)
+		ret += sprintf(page + ret, ",any");
+
+	if (inv)
+		ret += sprintf(page + ret, ",inv");
+
+	if (cmask)
+		ret += sprintf(page + ret, ",cmask=0x%02llx", cmask);
+
+	ret += sprintf(page + ret, "\n");
+
+	return ret;
+}
+
+static int __init init_hw_perf_events(void)
+{
+	struct x86_pmu_quirk *quirk;
+	int err;
+
+	pr_info("Performance Events: ");
+
+	switch (boot_cpu_data.x86_vendor) {
+	case X86_VENDOR_INTEL:
+		err = intel_pmu_init();
+		break;
+	case X86_VENDOR_AMD:
+		err = amd_pmu_init();
+		break;
+	default:
+		err = -ENOTSUPP;
+	}
+	if (err != 0) {
+		pr_cont("no PMU driver, software events only.\n");
+		return 0;
+	}
+
+	pmu_check_apic();
+
+	/* sanity check that the hardware exists or is emulated */
+	if (!check_hw_exists())
+		return 0;
+
+	pr_cont("%s PMU driver.\n", x86_pmu.name);
+
+	x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+
+	for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next)
+		quirk->func();
+
+	if (!x86_pmu.intel_ctrl)
+		x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
+
+	perf_events_lapic_init();
+	register_nmi_handler(NMI_LOCAL, perf_event_nmi_handler, 0, "PMI");
+
+	unconstrained = (struct event_constraint)
+		__EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1,
+				   0, x86_pmu.num_counters, 0, 0);
+
+	x86_pmu_format_group.attrs = x86_pmu.format_attrs;
+
+	if (x86_pmu.event_attrs)
+		x86_pmu_events_group.attrs = x86_pmu.event_attrs;
+
+	if (!x86_pmu.events_sysfs_show)
+		x86_pmu_events_group.attrs = &empty_attrs;
+	else
+		filter_events(x86_pmu_events_group.attrs);
+
+	if (x86_pmu.cpu_events) {
+		struct attribute **tmp;
+
+		tmp = merge_attr(x86_pmu_events_group.attrs, x86_pmu.cpu_events);
+		if (!WARN_ON(!tmp))
+			x86_pmu_events_group.attrs = tmp;
+	}
+
+	pr_info("... version:                %d\n",     x86_pmu.version);
+	pr_info("... bit width:              %d\n",     x86_pmu.cntval_bits);
+	pr_info("... generic registers:      %d\n",     x86_pmu.num_counters);
+	pr_info("... value mask:             %016Lx\n", x86_pmu.cntval_mask);
+	pr_info("... max period:             %016Lx\n", x86_pmu.max_period);
+	pr_info("... fixed-purpose events:   %d\n",     x86_pmu.num_counters_fixed);
+	pr_info("... event mask:             %016Lx\n", x86_pmu.intel_ctrl);
+
+	perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
+	perf_cpu_notifier(x86_pmu_notifier);
+
+	return 0;
+}
+early_initcall(init_hw_perf_events);
+
+static inline void x86_pmu_read(struct perf_event *event)
+{
+	x86_perf_event_update(event);
+}
+
+/*
+ * Start group events scheduling transaction
+ * Set the flag to make pmu::enable() not perform the
+ * schedulability test, it will be performed at commit time
+ *
+ * We only support PERF_PMU_TXN_ADD transactions. Save the
+ * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD
+ * transactions.
+ */
+static void x86_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	WARN_ON_ONCE(cpuc->txn_flags);		/* txn already in flight */
+
+	cpuc->txn_flags = txn_flags;
+	if (txn_flags & ~PERF_PMU_TXN_ADD)
+		return;
+
+	perf_pmu_disable(pmu);
+	__this_cpu_write(cpu_hw_events.n_txn, 0);
+}
+
+/*
+ * Stop group events scheduling transaction
+ * Clear the flag and pmu::enable() will perform the
+ * schedulability test.
+ */
+static void x86_pmu_cancel_txn(struct pmu *pmu)
+{
+	unsigned int txn_flags;
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	WARN_ON_ONCE(!cpuc->txn_flags);	/* no txn in flight */
+
+	txn_flags = cpuc->txn_flags;
+	cpuc->txn_flags = 0;
+	if (txn_flags & ~PERF_PMU_TXN_ADD)
+		return;
+
+	/*
+	 * Truncate collected array by the number of events added in this
+	 * transaction. See x86_pmu_add() and x86_pmu_*_txn().
+	 */
+	__this_cpu_sub(cpu_hw_events.n_added, __this_cpu_read(cpu_hw_events.n_txn));
+	__this_cpu_sub(cpu_hw_events.n_events, __this_cpu_read(cpu_hw_events.n_txn));
+	perf_pmu_enable(pmu);
+}
+
+/*
+ * Commit group events scheduling transaction
+ * Perform the group schedulability test as a whole
+ * Return 0 if success
+ *
+ * Does not cancel the transaction on failure; expects the caller to do this.
+ */
+static int x86_pmu_commit_txn(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	int assign[X86_PMC_IDX_MAX];
+	int n, ret;
+
+	WARN_ON_ONCE(!cpuc->txn_flags);	/* no txn in flight */
+
+	if (cpuc->txn_flags & ~PERF_PMU_TXN_ADD) {
+		cpuc->txn_flags = 0;
+		return 0;
+	}
+
+	n = cpuc->n_events;
+
+	if (!x86_pmu_initialized())
+		return -EAGAIN;
+
+	ret = x86_pmu.schedule_events(cpuc, n, assign);
+	if (ret)
+		return ret;
+
+	/*
+	 * copy new assignment, now we know it is possible
+	 * will be used by hw_perf_enable()
+	 */
+	memcpy(cpuc->assign, assign, n*sizeof(int));
+
+	cpuc->txn_flags = 0;
+	perf_pmu_enable(pmu);
+	return 0;
+}
+/*
+ * a fake_cpuc is used to validate event groups. Due to
+ * the extra reg logic, we need to also allocate a fake
+ * per_core and per_cpu structure. Otherwise, group events
+ * using extra reg may conflict without the kernel being
+ * able to catch this when the last event gets added to
+ * the group.
+ */
+static void free_fake_cpuc(struct cpu_hw_events *cpuc)
+{
+	kfree(cpuc->shared_regs);
+	kfree(cpuc);
+}
+
+static struct cpu_hw_events *allocate_fake_cpuc(void)
+{
+	struct cpu_hw_events *cpuc;
+	int cpu = raw_smp_processor_id();
+
+	cpuc = kzalloc(sizeof(*cpuc), GFP_KERNEL);
+	if (!cpuc)
+		return ERR_PTR(-ENOMEM);
+
+	/* only needed, if we have extra_regs */
+	if (x86_pmu.extra_regs) {
+		cpuc->shared_regs = allocate_shared_regs(cpu);
+		if (!cpuc->shared_regs)
+			goto error;
+	}
+	cpuc->is_fake = 1;
+	return cpuc;
+error:
+	free_fake_cpuc(cpuc);
+	return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * validate that we can schedule this event
+ */
+static int validate_event(struct perf_event *event)
+{
+	struct cpu_hw_events *fake_cpuc;
+	struct event_constraint *c;
+	int ret = 0;
+
+	fake_cpuc = allocate_fake_cpuc();
+	if (IS_ERR(fake_cpuc))
+		return PTR_ERR(fake_cpuc);
+
+	c = x86_pmu.get_event_constraints(fake_cpuc, -1, event);
+
+	if (!c || !c->weight)
+		ret = -EINVAL;
+
+	if (x86_pmu.put_event_constraints)
+		x86_pmu.put_event_constraints(fake_cpuc, event);
+
+	free_fake_cpuc(fake_cpuc);
+
+	return ret;
+}
+
+/*
+ * validate a single event group
+ *
+ * validation include:
+ *	- check events are compatible which each other
+ *	- events do not compete for the same counter
+ *	- number of events <= number of counters
+ *
+ * validation ensures the group can be loaded onto the
+ * PMU if it was the only group available.
+ */
+static int validate_group(struct perf_event *event)
+{
+	struct perf_event *leader = event->group_leader;
+	struct cpu_hw_events *fake_cpuc;
+	int ret = -EINVAL, n;
+
+	fake_cpuc = allocate_fake_cpuc();
+	if (IS_ERR(fake_cpuc))
+		return PTR_ERR(fake_cpuc);
+	/*
+	 * 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 = collect_events(fake_cpuc, leader, true);
+	if (n < 0)
+		goto out;
+
+	fake_cpuc->n_events = n;
+	n = collect_events(fake_cpuc, event, false);
+	if (n < 0)
+		goto out;
+
+	fake_cpuc->n_events = n;
+
+	ret = x86_pmu.schedule_events(fake_cpuc, n, NULL);
+
+out:
+	free_fake_cpuc(fake_cpuc);
+	return ret;
+}
+
+static int x86_pmu_event_init(struct perf_event *event)
+{
+	struct pmu *tmp;
+	int err;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_RAW:
+	case PERF_TYPE_HARDWARE:
+	case PERF_TYPE_HW_CACHE:
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
+	err = __x86_pmu_event_init(event);
+	if (!err) {
+		/*
+		 * we temporarily connect event to its pmu
+		 * such that validate_group() can classify
+		 * it as an x86 event using is_x86_event()
+		 */
+		tmp = event->pmu;
+		event->pmu = &pmu;
+
+		if (event->group_leader != event)
+			err = validate_group(event);
+		else
+			err = validate_event(event);
+
+		event->pmu = tmp;
+	}
+	if (err) {
+		if (event->destroy)
+			event->destroy(event);
+	}
+
+	if (ACCESS_ONCE(x86_pmu.attr_rdpmc))
+		event->hw.flags |= PERF_X86_EVENT_RDPMC_ALLOWED;
+
+	return err;
+}
+
+static void refresh_pce(void *ignored)
+{
+	if (current->active_mm)
+		load_mm_cr4(current->active_mm);
+}
+
+static void x86_pmu_event_mapped(struct perf_event *event)
+{
+	if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
+		return;
+
+	if (atomic_inc_return(&current->mm->context.perf_rdpmc_allowed) == 1)
+		on_each_cpu_mask(mm_cpumask(current->mm), refresh_pce, NULL, 1);
+}
+
+static void x86_pmu_event_unmapped(struct perf_event *event)
+{
+	if (!current->mm)
+		return;
+
+	if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
+		return;
+
+	if (atomic_dec_and_test(&current->mm->context.perf_rdpmc_allowed))
+		on_each_cpu_mask(mm_cpumask(current->mm), refresh_pce, NULL, 1);
+}
+
+static int x86_pmu_event_idx(struct perf_event *event)
+{
+	int idx = event->hw.idx;
+
+	if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
+		return 0;
+
+	if (x86_pmu.num_counters_fixed && idx >= INTEL_PMC_IDX_FIXED) {
+		idx -= INTEL_PMC_IDX_FIXED;
+		idx |= 1 << 30;
+	}
+
+	return idx + 1;
+}
+
+static ssize_t get_attr_rdpmc(struct device *cdev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc);
+}
+
+static ssize_t set_attr_rdpmc(struct device *cdev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	unsigned long val;
+	ssize_t ret;
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	if (val > 2)
+		return -EINVAL;
+
+	if (x86_pmu.attr_rdpmc_broken)
+		return -ENOTSUPP;
+
+	if ((val == 2) != (x86_pmu.attr_rdpmc == 2)) {
+		/*
+		 * Changing into or out of always available, aka
+		 * perf-event-bypassing mode.  This path is extremely slow,
+		 * but only root can trigger it, so it's okay.
+		 */
+		if (val == 2)
+			static_key_slow_inc(&rdpmc_always_available);
+		else
+			static_key_slow_dec(&rdpmc_always_available);
+		on_each_cpu(refresh_pce, NULL, 1);
+	}
+
+	x86_pmu.attr_rdpmc = val;
+
+	return count;
+}
+
+static DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc);
+
+static struct attribute *x86_pmu_attrs[] = {
+	&dev_attr_rdpmc.attr,
+	NULL,
+};
+
+static struct attribute_group x86_pmu_attr_group = {
+	.attrs = x86_pmu_attrs,
+};
+
+static const struct attribute_group *x86_pmu_attr_groups[] = {
+	&x86_pmu_attr_group,
+	&x86_pmu_format_group,
+	&x86_pmu_events_group,
+	NULL,
+};
+
+static void x86_pmu_sched_task(struct perf_event_context *ctx, bool sched_in)
+{
+	if (x86_pmu.sched_task)
+		x86_pmu.sched_task(ctx, sched_in);
+}
+
+void perf_check_microcode(void)
+{
+	if (x86_pmu.check_microcode)
+		x86_pmu.check_microcode();
+}
+EXPORT_SYMBOL_GPL(perf_check_microcode);
+
+static struct pmu pmu = {
+	.pmu_enable		= x86_pmu_enable,
+	.pmu_disable		= x86_pmu_disable,
+
+	.attr_groups		= x86_pmu_attr_groups,
+
+	.event_init		= x86_pmu_event_init,
+
+	.event_mapped		= x86_pmu_event_mapped,
+	.event_unmapped		= x86_pmu_event_unmapped,
+
+	.add			= x86_pmu_add,
+	.del			= x86_pmu_del,
+	.start			= x86_pmu_start,
+	.stop			= x86_pmu_stop,
+	.read			= x86_pmu_read,
+
+	.start_txn		= x86_pmu_start_txn,
+	.cancel_txn		= x86_pmu_cancel_txn,
+	.commit_txn		= x86_pmu_commit_txn,
+
+	.event_idx		= x86_pmu_event_idx,
+	.sched_task		= x86_pmu_sched_task,
+	.task_ctx_size          = sizeof(struct x86_perf_task_context),
+};
+
+void arch_perf_update_userpage(struct perf_event *event,
+			       struct perf_event_mmap_page *userpg, u64 now)
+{
+	struct cyc2ns_data *data;
+
+	userpg->cap_user_time = 0;
+	userpg->cap_user_time_zero = 0;
+	userpg->cap_user_rdpmc =
+		!!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED);
+	userpg->pmc_width = x86_pmu.cntval_bits;
+
+	if (!sched_clock_stable())
+		return;
+
+	data = cyc2ns_read_begin();
+
+	/*
+	 * Internal timekeeping for enabled/running/stopped times
+	 * is always in the local_clock domain.
+	 */
+	userpg->cap_user_time = 1;
+	userpg->time_mult = data->cyc2ns_mul;
+	userpg->time_shift = data->cyc2ns_shift;
+	userpg->time_offset = data->cyc2ns_offset - now;
+
+	/*
+	 * cap_user_time_zero doesn't make sense when we're using a different
+	 * time base for the records.
+	 */
+	if (event->clock == &local_clock) {
+		userpg->cap_user_time_zero = 1;
+		userpg->time_zero = data->cyc2ns_offset;
+	}
+
+	cyc2ns_read_end(data);
+}
+
+/*
+ * callchain support
+ */
+
+static int backtrace_stack(void *data, char *name)
+{
+	return 0;
+}
+
+static void backtrace_address(void *data, unsigned long addr, int reliable)
+{
+	struct perf_callchain_entry *entry = data;
+
+	perf_callchain_store(entry, addr);
+}
+
+static const struct stacktrace_ops backtrace_ops = {
+	.stack			= backtrace_stack,
+	.address		= backtrace_address,
+	.walk_stack		= print_context_stack_bp,
+};
+
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
+{
+	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+		/* TODO: We don't support guest os callchain now */
+		return;
+	}
+
+	perf_callchain_store(entry, regs->ip);
+
+	dump_trace(NULL, regs, NULL, 0, &backtrace_ops, entry);
+}
+
+static inline int
+valid_user_frame(const void __user *fp, unsigned long size)
+{
+	return (__range_not_ok(fp, size, TASK_SIZE) == 0);
+}
+
+static unsigned long get_segment_base(unsigned int segment)
+{
+	struct desc_struct *desc;
+	int idx = segment >> 3;
+
+	if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) {
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+		struct ldt_struct *ldt;
+
+		if (idx > LDT_ENTRIES)
+			return 0;
+
+		/* IRQs are off, so this synchronizes with smp_store_release */
+		ldt = lockless_dereference(current->active_mm->context.ldt);
+		if (!ldt || idx > ldt->size)
+			return 0;
+
+		desc = &ldt->entries[idx];
+#else
+		return 0;
+#endif
+	} else {
+		if (idx > GDT_ENTRIES)
+			return 0;
+
+		desc = raw_cpu_ptr(gdt_page.gdt) + idx;
+	}
+
+	return get_desc_base(desc);
+}
+
+#ifdef CONFIG_IA32_EMULATION
+
+#include <asm/compat.h>
+
+static inline int
+perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
+{
+	/* 32-bit process in 64-bit kernel. */
+	unsigned long ss_base, cs_base;
+	struct stack_frame_ia32 frame;
+	const void __user *fp;
+
+	if (!test_thread_flag(TIF_IA32))
+		return 0;
+
+	cs_base = get_segment_base(regs->cs);
+	ss_base = get_segment_base(regs->ss);
+
+	fp = compat_ptr(ss_base + regs->bp);
+	while (entry->nr < PERF_MAX_STACK_DEPTH) {
+		unsigned long bytes;
+		frame.next_frame     = 0;
+		frame.return_address = 0;
+
+		bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
+		if (bytes != 0)
+			break;
+
+		if (!valid_user_frame(fp, sizeof(frame)))
+			break;
+
+		perf_callchain_store(entry, cs_base + frame.return_address);
+		fp = compat_ptr(ss_base + frame.next_frame);
+	}
+	return 1;
+}
+#else
+static inline int
+perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
+{
+    return 0;
+}
+#endif
+
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
+{
+	struct stack_frame frame;
+	const void __user *fp;
+
+	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+		/* TODO: We don't support guest os callchain now */
+		return;
+	}
+
+	/*
+	 * We don't know what to do with VM86 stacks.. ignore them for now.
+	 */
+	if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM))
+		return;
+
+	fp = (void __user *)regs->bp;
+
+	perf_callchain_store(entry, regs->ip);
+
+	if (!current->mm)
+		return;
+
+	if (perf_callchain_user32(regs, entry))
+		return;
+
+	while (entry->nr < PERF_MAX_STACK_DEPTH) {
+		unsigned long bytes;
+		frame.next_frame	     = NULL;
+		frame.return_address = 0;
+
+		bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
+		if (bytes != 0)
+			break;
+
+		if (!valid_user_frame(fp, sizeof(frame)))
+			break;
+
+		perf_callchain_store(entry, frame.return_address);
+		fp = frame.next_frame;
+	}
+}
+
+/*
+ * Deal with code segment offsets for the various execution modes:
+ *
+ *   VM86 - the good olde 16 bit days, where the linear address is
+ *          20 bits and we use regs->ip + 0x10 * regs->cs.
+ *
+ *   IA32 - Where we need to look at GDT/LDT segment descriptor tables
+ *          to figure out what the 32bit base address is.
+ *
+ *    X32 - has TIF_X32 set, but is running in x86_64
+ *
+ * X86_64 - CS,DS,SS,ES are all zero based.
+ */
+static unsigned long code_segment_base(struct pt_regs *regs)
+{
+	/*
+	 * For IA32 we look at the GDT/LDT segment base to convert the
+	 * effective IP to a linear address.
+	 */
+
+#ifdef CONFIG_X86_32
+	/*
+	 * If we are in VM86 mode, add the segment offset to convert to a
+	 * linear address.
+	 */
+	if (regs->flags & X86_VM_MASK)
+		return 0x10 * regs->cs;
+
+	if (user_mode(regs) && regs->cs != __USER_CS)
+		return get_segment_base(regs->cs);
+#else
+	if (user_mode(regs) && !user_64bit_mode(regs) &&
+	    regs->cs != __USER32_CS)
+		return get_segment_base(regs->cs);
+#endif
+	return 0;
+}
+
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
+	if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
+		return perf_guest_cbs->get_guest_ip();
+
+	return regs->ip + code_segment_base(regs);
+}
+
+unsigned long perf_misc_flags(struct pt_regs *regs)
+{
+	int misc = 0;
+
+	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+		if (perf_guest_cbs->is_user_mode())
+			misc |= PERF_RECORD_MISC_GUEST_USER;
+		else
+			misc |= PERF_RECORD_MISC_GUEST_KERNEL;
+	} else {
+		if (user_mode(regs))
+			misc |= PERF_RECORD_MISC_USER;
+		else
+			misc |= PERF_RECORD_MISC_KERNEL;
+	}
+
+	if (regs->flags & PERF_EFLAGS_EXACT)
+		misc |= PERF_RECORD_MISC_EXACT_IP;
+
+	return misc;
+}
+
+void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
+{
+	cap->version		= x86_pmu.version;
+	cap->num_counters_gp	= x86_pmu.num_counters;
+	cap->num_counters_fixed	= x86_pmu.num_counters_fixed;
+	cap->bit_width_gp	= x86_pmu.cntval_bits;
+	cap->bit_width_fixed	= x86_pmu.cntval_bits;
+	cap->events_mask	= (unsigned int)x86_pmu.events_maskl;
+	cap->events_mask_len	= x86_pmu.events_mask_len;
+}
+EXPORT_SYMBOL_GPL(perf_get_x86_pmu_capability);
--- linux-4.4.0.orig/arch/x86/events/intel/bts.c
+++ linux-4.4.0/arch/x86/events/intel/bts.c
@@ -0,0 +1,566 @@
+/*
+ * BTS PMU driver for perf
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#undef DEBUG
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/coredump.h>
+#include <linux/kaiser.h>
+
+#include <asm-generic/sizes.h>
+#include <asm/perf_event.h>
+
+#include "../perf_event.h"
+
+struct bts_ctx {
+	struct perf_output_handle	handle;
+	struct debug_store		ds_back;
+	int				started;
+};
+
+static DEFINE_PER_CPU(struct bts_ctx, bts_ctx);
+
+#define BTS_RECORD_SIZE		24
+#define BTS_SAFETY_MARGIN	4080
+
+struct bts_phys {
+	struct page	*page;
+	unsigned long	size;
+	unsigned long	offset;
+	unsigned long	displacement;
+};
+
+struct bts_buffer {
+	size_t		real_size;	/* multiple of BTS_RECORD_SIZE */
+	unsigned int	nr_pages;
+	unsigned int	nr_bufs;
+	unsigned int	cur_buf;
+	bool		snapshot;
+	local_t		data_size;
+	local_t		lost;
+	local_t		head;
+	unsigned long	end;
+	void		**data_pages;
+	struct bts_phys	buf[0];
+};
+
+struct pmu bts_pmu;
+
+static size_t buf_size(struct page *page)
+{
+	return 1 << (PAGE_SHIFT + page_private(page));
+}
+
+static void bts_buffer_free_aux(void *data)
+{
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	struct bts_buffer *buf = data;
+	int nbuf;
+
+	for (nbuf = 0; nbuf < buf->nr_bufs; nbuf++) {
+		struct page *page = buf->buf[nbuf].page;
+		void *kaddr = page_address(page);
+		size_t page_size = buf_size(page);
+
+		kaiser_remove_mapping((unsigned long)kaddr, page_size);
+	}
+#endif
+	kfree(data);
+}
+
+static void *
+bts_buffer_setup_aux(int cpu, void **pages, int nr_pages, bool overwrite)
+{
+	struct bts_buffer *buf;
+	struct page *page;
+	int node = (cpu == -1) ? cpu : cpu_to_node(cpu);
+	unsigned long offset;
+	size_t size = nr_pages << PAGE_SHIFT;
+	int pg, nbuf, pad;
+
+	/* count all the high order buffers */
+	for (pg = 0, nbuf = 0; pg < nr_pages;) {
+		page = virt_to_page(pages[pg]);
+		if (WARN_ON_ONCE(!PagePrivate(page) && nr_pages > 1))
+			return NULL;
+		pg += 1 << page_private(page);
+		nbuf++;
+	}
+
+	/*
+	 * to avoid interrupts in overwrite mode, only allow one physical
+	 */
+	if (overwrite && nbuf > 1)
+		return NULL;
+
+	buf = kzalloc_node(offsetof(struct bts_buffer, buf[nbuf]), GFP_KERNEL, node);
+	if (!buf)
+		return NULL;
+
+	buf->nr_pages = nr_pages;
+	buf->nr_bufs = nbuf;
+	buf->snapshot = overwrite;
+	buf->data_pages = pages;
+	buf->real_size = size - size % BTS_RECORD_SIZE;
+
+	for (pg = 0, nbuf = 0, offset = 0, pad = 0; nbuf < buf->nr_bufs; nbuf++) {
+		void *kaddr = pages[pg];
+		size_t page_size;
+
+		page = virt_to_page(kaddr);
+		page_size = buf_size(page);
+
+		if (kaiser_add_mapping((unsigned long)kaddr,
+					page_size, __PAGE_KERNEL) < 0) {
+			buf->nr_bufs = nbuf;
+			bts_buffer_free_aux(buf);
+			return NULL;
+		}
+
+		buf->buf[nbuf].page = page;
+		buf->buf[nbuf].offset = offset;
+		buf->buf[nbuf].displacement = (pad ? BTS_RECORD_SIZE - pad : 0);
+		buf->buf[nbuf].size = page_size - buf->buf[nbuf].displacement;
+		pad = buf->buf[nbuf].size % BTS_RECORD_SIZE;
+		buf->buf[nbuf].size -= pad;
+
+		pg += page_size >> PAGE_SHIFT;
+		offset += page_size;
+	}
+
+	return buf;
+}
+
+static unsigned long bts_buffer_offset(struct bts_buffer *buf, unsigned int idx)
+{
+	return buf->buf[idx].offset + buf->buf[idx].displacement;
+}
+
+static void
+bts_config_buffer(struct bts_buffer *buf)
+{
+	int cpu = raw_smp_processor_id();
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+	struct bts_phys *phys = &buf->buf[buf->cur_buf];
+	unsigned long index, thresh = 0, end = phys->size;
+	struct page *page = phys->page;
+
+	index = local_read(&buf->head);
+
+	if (!buf->snapshot) {
+		if (buf->end < phys->offset + buf_size(page))
+			end = buf->end - phys->offset - phys->displacement;
+
+		index -= phys->offset + phys->displacement;
+
+		if (end - index > BTS_SAFETY_MARGIN)
+			thresh = end - BTS_SAFETY_MARGIN;
+		else if (end - index > BTS_RECORD_SIZE)
+			thresh = end - BTS_RECORD_SIZE;
+		else
+			thresh = end;
+	}
+
+	ds->bts_buffer_base = (u64)(long)page_address(page) + phys->displacement;
+	ds->bts_index = ds->bts_buffer_base + index;
+	ds->bts_absolute_maximum = ds->bts_buffer_base + end;
+	ds->bts_interrupt_threshold = !buf->snapshot
+		? ds->bts_buffer_base + thresh
+		: ds->bts_absolute_maximum + BTS_RECORD_SIZE;
+}
+
+static void bts_buffer_pad_out(struct bts_phys *phys, unsigned long head)
+{
+	unsigned long index = head - phys->offset;
+
+	memset(page_address(phys->page) + index, 0, phys->size - index);
+}
+
+static bool bts_buffer_is_full(struct bts_buffer *buf, struct bts_ctx *bts)
+{
+	if (buf->snapshot)
+		return false;
+
+	if (local_read(&buf->data_size) >= bts->handle.size ||
+	    bts->handle.size - local_read(&buf->data_size) < BTS_RECORD_SIZE)
+		return true;
+
+	return false;
+}
+
+static void bts_update(struct bts_ctx *bts)
+{
+	int cpu = raw_smp_processor_id();
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+	struct bts_buffer *buf = perf_get_aux(&bts->handle);
+	unsigned long index = ds->bts_index - ds->bts_buffer_base, old, head;
+
+	if (!buf)
+		return;
+
+	head = index + bts_buffer_offset(buf, buf->cur_buf);
+	old = local_xchg(&buf->head, head);
+
+	if (!buf->snapshot) {
+		if (old == head)
+			return;
+
+		if (ds->bts_index >= ds->bts_absolute_maximum)
+			local_inc(&buf->lost);
+
+		/*
+		 * old and head are always in the same physical buffer, so we
+		 * can subtract them to get the data size.
+		 */
+		local_add(head - old, &buf->data_size);
+	} else {
+		local_set(&buf->data_size, head);
+	}
+}
+
+static void __bts_event_start(struct perf_event *event)
+{
+	struct bts_ctx *bts = this_cpu_ptr(&bts_ctx);
+	struct bts_buffer *buf = perf_get_aux(&bts->handle);
+	u64 config = 0;
+
+	if (!buf || bts_buffer_is_full(buf, bts))
+		return;
+
+	event->hw.itrace_started = 1;
+	event->hw.state = 0;
+
+	if (!buf->snapshot)
+		config |= ARCH_PERFMON_EVENTSEL_INT;
+	if (!event->attr.exclude_kernel)
+		config |= ARCH_PERFMON_EVENTSEL_OS;
+	if (!event->attr.exclude_user)
+		config |= ARCH_PERFMON_EVENTSEL_USR;
+
+	bts_config_buffer(buf);
+
+	/*
+	 * local barrier to make sure that ds configuration made it
+	 * before we enable BTS
+	 */
+	wmb();
+
+	intel_pmu_enable_bts(config);
+}
+
+static void bts_event_start(struct perf_event *event, int flags)
+{
+	struct bts_ctx *bts = this_cpu_ptr(&bts_ctx);
+
+	__bts_event_start(event);
+
+	/* PMI handler: this counter is running and likely generating PMIs */
+	ACCESS_ONCE(bts->started) = 1;
+}
+
+static void __bts_event_stop(struct perf_event *event)
+{
+	/*
+	 * No extra synchronization is mandated by the documentation to have
+	 * BTS data stores globally visible.
+	 */
+	intel_pmu_disable_bts();
+
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
+	ACCESS_ONCE(event->hw.state) |= PERF_HES_STOPPED;
+}
+
+static void bts_event_stop(struct perf_event *event, int flags)
+{
+	struct bts_ctx *bts = this_cpu_ptr(&bts_ctx);
+
+	/* PMI handler: don't restart this counter */
+	ACCESS_ONCE(bts->started) = 0;
+
+	__bts_event_stop(event);
+
+	if (flags & PERF_EF_UPDATE)
+		bts_update(bts);
+}
+
+void intel_bts_enable_local(void)
+{
+	struct bts_ctx *bts = this_cpu_ptr(&bts_ctx);
+
+	if (bts->handle.event && bts->started)
+		__bts_event_start(bts->handle.event);
+}
+
+void intel_bts_disable_local(void)
+{
+	struct bts_ctx *bts = this_cpu_ptr(&bts_ctx);
+
+	if (bts->handle.event)
+		__bts_event_stop(bts->handle.event);
+}
+
+static int
+bts_buffer_reset(struct bts_buffer *buf, struct perf_output_handle *handle)
+{
+	unsigned long head, space, next_space, pad, gap, skip, wakeup;
+	unsigned int next_buf;
+	struct bts_phys *phys, *next_phys;
+	int ret;
+
+	if (buf->snapshot)
+		return 0;
+
+	head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
+	if (WARN_ON_ONCE(head != local_read(&buf->head)))
+		return -EINVAL;
+
+	phys = &buf->buf[buf->cur_buf];
+	space = phys->offset + phys->displacement + phys->size - head;
+	pad = space;
+	if (space > handle->size) {
+		space = handle->size;
+		space -= space % BTS_RECORD_SIZE;
+	}
+	if (space <= BTS_SAFETY_MARGIN) {
+		/* See if next phys buffer has more space */
+		next_buf = buf->cur_buf + 1;
+		if (next_buf >= buf->nr_bufs)
+			next_buf = 0;
+		next_phys = &buf->buf[next_buf];
+		gap = buf_size(phys->page) - phys->displacement - phys->size +
+		      next_phys->displacement;
+		skip = pad + gap;
+		if (handle->size >= skip) {
+			next_space = next_phys->size;
+			if (next_space + skip > handle->size) {
+				next_space = handle->size - skip;
+				next_space -= next_space % BTS_RECORD_SIZE;
+			}
+			if (next_space > space || !space) {
+				if (pad)
+					bts_buffer_pad_out(phys, head);
+				ret = perf_aux_output_skip(handle, skip);
+				if (ret)
+					return ret;
+				/* Advance to next phys buffer */
+				phys = next_phys;
+				space = next_space;
+				head = phys->offset + phys->displacement;
+				/*
+				 * After this, cur_buf and head won't match ds
+				 * anymore, so we must not be racing with
+				 * bts_update().
+				 */
+				buf->cur_buf = next_buf;
+				local_set(&buf->head, head);
+			}
+		}
+	}
+
+	/* Don't go far beyond wakeup watermark */
+	wakeup = BTS_SAFETY_MARGIN + BTS_RECORD_SIZE + handle->wakeup -
+		 handle->head;
+	if (space > wakeup) {
+		space = wakeup;
+		space -= space % BTS_RECORD_SIZE;
+	}
+
+	buf->end = head + space;
+
+	/*
+	 * If we have no space, the lost notification would have been sent when
+	 * we hit absolute_maximum - see bts_update()
+	 */
+	if (!space)
+		return -ENOSPC;
+
+	return 0;
+}
+
+int intel_bts_interrupt(void)
+{
+	struct bts_ctx *bts = this_cpu_ptr(&bts_ctx);
+	struct perf_event *event = bts->handle.event;
+	struct bts_buffer *buf;
+	s64 old_head;
+	int err;
+
+	if (!event || !bts->started)
+		return 0;
+
+	buf = perf_get_aux(&bts->handle);
+	/*
+	 * Skip snapshot counters: they don't use the interrupt, but
+	 * there's no other way of telling, because the pointer will
+	 * keep moving
+	 */
+	if (!buf || buf->snapshot)
+		return 0;
+
+	old_head = local_read(&buf->head);
+	bts_update(bts);
+
+	/* no new data */
+	if (old_head == local_read(&buf->head))
+		return 0;
+
+	perf_aux_output_end(&bts->handle, local_xchg(&buf->data_size, 0),
+			    !!local_xchg(&buf->lost, 0));
+
+	buf = perf_aux_output_begin(&bts->handle, event);
+	if (!buf)
+		return 1;
+
+	err = bts_buffer_reset(buf, &bts->handle);
+	if (err)
+		perf_aux_output_end(&bts->handle, 0, false);
+
+	return 1;
+}
+
+static void bts_event_del(struct perf_event *event, int mode)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct bts_ctx *bts = this_cpu_ptr(&bts_ctx);
+	struct bts_buffer *buf = perf_get_aux(&bts->handle);
+
+	bts_event_stop(event, PERF_EF_UPDATE);
+
+	if (buf) {
+		if (buf->snapshot)
+			bts->handle.head =
+				local_xchg(&buf->data_size,
+					   buf->nr_pages << PAGE_SHIFT);
+		perf_aux_output_end(&bts->handle, local_xchg(&buf->data_size, 0),
+				    !!local_xchg(&buf->lost, 0));
+	}
+
+	cpuc->ds->bts_index = bts->ds_back.bts_buffer_base;
+	cpuc->ds->bts_buffer_base = bts->ds_back.bts_buffer_base;
+	cpuc->ds->bts_absolute_maximum = bts->ds_back.bts_absolute_maximum;
+	cpuc->ds->bts_interrupt_threshold = bts->ds_back.bts_interrupt_threshold;
+}
+
+static int bts_event_add(struct perf_event *event, int mode)
+{
+	struct bts_buffer *buf;
+	struct bts_ctx *bts = this_cpu_ptr(&bts_ctx);
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+	int ret = -EBUSY;
+
+	event->hw.state = PERF_HES_STOPPED;
+
+	if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask))
+		return -EBUSY;
+
+	if (bts->handle.event)
+		return -EBUSY;
+
+	buf = perf_aux_output_begin(&bts->handle, event);
+	if (!buf)
+		return -EINVAL;
+
+	ret = bts_buffer_reset(buf, &bts->handle);
+	if (ret) {
+		perf_aux_output_end(&bts->handle, 0, false);
+		return ret;
+	}
+
+	bts->ds_back.bts_buffer_base = cpuc->ds->bts_buffer_base;
+	bts->ds_back.bts_absolute_maximum = cpuc->ds->bts_absolute_maximum;
+	bts->ds_back.bts_interrupt_threshold = cpuc->ds->bts_interrupt_threshold;
+
+	if (mode & PERF_EF_START) {
+		bts_event_start(event, 0);
+		if (hwc->state & PERF_HES_STOPPED) {
+			bts_event_del(event, 0);
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+static void bts_event_destroy(struct perf_event *event)
+{
+	x86_release_hardware();
+	x86_del_exclusive(x86_lbr_exclusive_bts);
+}
+
+static int bts_event_init(struct perf_event *event)
+{
+	int ret;
+
+	if (event->attr.type != bts_pmu.type)
+		return -ENOENT;
+
+	if (x86_add_exclusive(x86_lbr_exclusive_bts))
+		return -EBUSY;
+
+	/*
+	 * BTS leaks kernel addresses even when CPL0 tracing is
+	 * disabled, so disallow intel_bts driver for unprivileged
+	 * users on paranoid systems since it provides trace data
+	 * to the user in a zero-copy fashion.
+	 *
+	 * Note that the default paranoia setting permits unprivileged
+	 * users to profile the kernel.
+	 */
+	if (event->attr.exclude_kernel && perf_paranoid_kernel() &&
+	    !capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	ret = x86_reserve_hardware();
+	if (ret) {
+		x86_del_exclusive(x86_lbr_exclusive_bts);
+		return ret;
+	}
+
+	event->destroy = bts_event_destroy;
+
+	return 0;
+}
+
+static void bts_event_read(struct perf_event *event)
+{
+}
+
+static __init int bts_init(void)
+{
+	if (!boot_cpu_has(X86_FEATURE_DTES64) || !x86_pmu.bts)
+		return -ENODEV;
+
+	bts_pmu.capabilities	= PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_ITRACE;
+	bts_pmu.task_ctx_nr	= perf_sw_context;
+	bts_pmu.event_init	= bts_event_init;
+	bts_pmu.add		= bts_event_add;
+	bts_pmu.del		= bts_event_del;
+	bts_pmu.start		= bts_event_start;
+	bts_pmu.stop		= bts_event_stop;
+	bts_pmu.read		= bts_event_read;
+	bts_pmu.setup_aux	= bts_buffer_setup_aux;
+	bts_pmu.free_aux	= bts_buffer_free_aux;
+
+	return perf_pmu_register(&bts_pmu, "intel_bts", -1);
+}
+arch_initcall(bts_init);
--- linux-4.4.0.orig/arch/x86/events/intel/core.c
+++ linux-4.4.0/arch/x86/events/intel/core.c
@@ -0,0 +1,3762 @@
+/*
+ * Per core/cpu state
+ *
+ * Used to coordinate shared registers between HT threads or
+ * 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>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/nmi.h>
+
+#include <asm/cpufeature.h>
+#include <asm/hardirq.h>
+#include <asm/intel-family.h>
+#include <asm/apic.h>
+
+#include "../perf_event.h"
+
+/*
+ * Intel PerfMon, used on Core and later.
+ */
+static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly =
+{
+	[PERF_COUNT_HW_CPU_CYCLES]		= 0x003c,
+	[PERF_COUNT_HW_INSTRUCTIONS]		= 0x00c0,
+	[PERF_COUNT_HW_CACHE_REFERENCES]	= 0x4f2e,
+	[PERF_COUNT_HW_CACHE_MISSES]		= 0x412e,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x00c4,
+	[PERF_COUNT_HW_BRANCH_MISSES]		= 0x00c5,
+	[PERF_COUNT_HW_BUS_CYCLES]		= 0x013c,
+	[PERF_COUNT_HW_REF_CPU_CYCLES]		= 0x0300, /* pseudo-encoding */
+};
+
+static struct event_constraint intel_core_event_constraints[] __read_mostly =
+{
+	INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
+	INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
+	INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
+	INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
+	INTEL_EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */
+	INTEL_EVENT_CONSTRAINT(0xc1, 0x1), /* FP_COMP_INSTR_RET */
+	EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_core2_event_constraints[] __read_mostly =
+{
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
+	INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
+	INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
+	INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
+	INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
+	INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
+	INTEL_EVENT_CONSTRAINT(0x18, 0x1), /* IDLE_DURING_DIV */
+	INTEL_EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */
+	INTEL_EVENT_CONSTRAINT(0xa1, 0x1), /* RS_UOPS_DISPATCH_CYCLES */
+	INTEL_EVENT_CONSTRAINT(0xc9, 0x1), /* ITLB_MISS_RETIRED (T30-9) */
+	INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED */
+	EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_nehalem_event_constraints[] __read_mostly =
+{
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
+	INTEL_EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */
+	INTEL_EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */
+	INTEL_EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */
+	INTEL_EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */
+	INTEL_EVENT_CONSTRAINT(0x48, 0x3), /* L1D_PEND_MISS */
+	INTEL_EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */
+	INTEL_EVENT_CONSTRAINT(0x51, 0x3), /* L1D */
+	INTEL_EVENT_CONSTRAINT(0x63, 0x3), /* CACHE_LOCK_CYCLES */
+	EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg intel_nehalem_extra_regs[] __read_mostly =
+{
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0),
+	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x100b),
+	EVENT_EXTRA_END
+};
+
+static struct event_constraint intel_westmere_event_constraints[] __read_mostly =
+{
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
+	INTEL_EVENT_CONSTRAINT(0x51, 0x3), /* L1D */
+	INTEL_EVENT_CONSTRAINT(0x60, 0x1), /* OFFCORE_REQUESTS_OUTSTANDING */
+	INTEL_EVENT_CONSTRAINT(0x63, 0x3), /* CACHE_LOCK_CYCLES */
+	INTEL_EVENT_CONSTRAINT(0xb3, 0x1), /* SNOOPQ_REQUEST_OUTSTANDING */
+	EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_snb_event_constraints[] __read_mostly =
+{
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
+	INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_NO_DISPATCH */
+	INTEL_UEVENT_CONSTRAINT(0x05a3, 0xf), /* CYCLE_ACTIVITY.STALLS_L2_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x02a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x06a3, 0x4), /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */
+	INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
+	INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
+	INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_NO_DISPATCH */
+	INTEL_UEVENT_CONSTRAINT(0x02a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
+
+	INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf), /* MEM_UOPS_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd3, 0xf), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+
+	EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_ivb_event_constraints[] __read_mostly =
+{
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
+	INTEL_UEVENT_CONSTRAINT(0x0148, 0x4), /* L1D_PEND_MISS.PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x0279, 0xf), /* IDQ.EMTPY */
+	INTEL_UEVENT_CONSTRAINT(0x019c, 0xf), /* IDQ_UOPS_NOT_DELIVERED.CORE */
+	INTEL_UEVENT_CONSTRAINT(0x02a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_LDM_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */
+	INTEL_UEVENT_CONSTRAINT(0x05a3, 0xf), /* CYCLE_ACTIVITY.STALLS_L2_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x06a3, 0xf), /* CYCLE_ACTIVITY.STALLS_LDM_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4), /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
+
+	INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf), /* MEM_UOPS_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd3, 0xf), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+
+	EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg intel_westmere_extra_regs[] __read_mostly =
+{
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x01bb, MSR_OFFCORE_RSP_1, 0xffff, RSP_1),
+	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x100b),
+	EVENT_EXTRA_END
+};
+
+static struct event_constraint intel_v1_event_constraints[] __read_mostly =
+{
+	EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_gen_event_constraints[] __read_mostly =
+{
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
+	EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_slm_event_constraints[] __read_mostly =
+{
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* pseudo CPU_CLK_UNHALTED.REF */
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_skl_event_constraints[] = {
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0),	/* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1),	/* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2),	/* CPU_CLK_UNHALTED.REF */
+	INTEL_UEVENT_CONSTRAINT(0x1c0, 0x2),	/* INST_RETIRED.PREC_DIST */
+	EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg intel_knl_extra_regs[] __read_mostly = {
+	INTEL_UEVENT_EXTRA_REG(0x01b7,
+			       MSR_OFFCORE_RSP_0, 0x7f9ffbffffull, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x02b7,
+			       MSR_OFFCORE_RSP_1, 0x3f9ffbffffull, RSP_1),
+	EVENT_EXTRA_END
+};
+
+static struct extra_reg intel_snb_extra_regs[] __read_mostly = {
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x3f807f8fffull, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x01bb, MSR_OFFCORE_RSP_1, 0x3f807f8fffull, RSP_1),
+	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
+	EVENT_EXTRA_END
+};
+
+static struct extra_reg intel_snbep_extra_regs[] __read_mostly = {
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x3fffff8fffull, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x01bb, MSR_OFFCORE_RSP_1, 0x3fffff8fffull, RSP_1),
+	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
+	EVENT_EXTRA_END
+};
+
+static struct extra_reg intel_skl_extra_regs[] __read_mostly = {
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x3fffff8fffull, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x01bb, MSR_OFFCORE_RSP_1, 0x3fffff8fffull, RSP_1),
+	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
+	/*
+	 * Note the low 8 bits eventsel code is not a continuous field, containing
+	 * some #GPing bits. These are masked out.
+	 */
+	INTEL_UEVENT_EXTRA_REG(0x01c6, MSR_PEBS_FRONTEND, 0x7fff17, FE),
+	EVENT_EXTRA_END
+};
+
+EVENT_ATTR_STR(mem-loads,	mem_ld_nhm,	"event=0x0b,umask=0x10,ldlat=3");
+EVENT_ATTR_STR(mem-loads,	mem_ld_snb,	"event=0xcd,umask=0x1,ldlat=3");
+EVENT_ATTR_STR(mem-stores,	mem_st_snb,	"event=0xcd,umask=0x2");
+
+struct attribute *nhm_events_attrs[] = {
+	EVENT_PTR(mem_ld_nhm),
+	NULL,
+};
+
+struct attribute *snb_events_attrs[] = {
+	EVENT_PTR(mem_ld_snb),
+	EVENT_PTR(mem_st_snb),
+	NULL,
+};
+
+static struct event_constraint intel_hsw_event_constraints[] = {
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
+	INTEL_UEVENT_CONSTRAINT(0x148, 0x4),	/* L1D_PEND_MISS.PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
+	INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
+	/* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4),
+	/* CYCLE_ACTIVITY.STALLS_L1D_PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4),
+	/* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */
+	INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf),
+
+	INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf), /* MEM_UOPS_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd3, 0xf), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_bdw_event_constraints[] = {
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0),	/* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1),	/* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2),	/* CPU_CLK_UNHALTED.REF */
+	INTEL_UEVENT_CONSTRAINT(0x148, 0x4),	/* L1D_PEND_MISS.PENDING */
+	INTEL_UEVENT_CONSTRAINT(0x8a3, 0x4),	/* CYCLE_ACTIVITY.CYCLES_L1D_MISS */
+	EVENT_CONSTRAINT_END
+};
+
+static u64 intel_pmu_event_map(int hw_event)
+{
+	return intel_perfmon_event_map[hw_event];
+}
+
+/*
+ * Notes on the events:
+ * - data reads do not include code reads (comparable to earlier tables)
+ * - data counts include speculative execution (except L1 write, dtlb, bpu)
+ * - remote node access includes remote memory, remote cache, remote mmio.
+ * - prefetches are not included in the counts.
+ * - icache miss does not include decoded icache
+ */
+
+#define SKL_DEMAND_DATA_RD		BIT_ULL(0)
+#define SKL_DEMAND_RFO			BIT_ULL(1)
+#define SKL_ANY_RESPONSE		BIT_ULL(16)
+#define SKL_SUPPLIER_NONE		BIT_ULL(17)
+#define SKL_L3_MISS_LOCAL_DRAM		BIT_ULL(26)
+#define SKL_L3_MISS_REMOTE_HOP0_DRAM	BIT_ULL(27)
+#define SKL_L3_MISS_REMOTE_HOP1_DRAM	BIT_ULL(28)
+#define SKL_L3_MISS_REMOTE_HOP2P_DRAM	BIT_ULL(29)
+#define SKL_L3_MISS			(SKL_L3_MISS_LOCAL_DRAM| \
+					 SKL_L3_MISS_REMOTE_HOP0_DRAM| \
+					 SKL_L3_MISS_REMOTE_HOP1_DRAM| \
+					 SKL_L3_MISS_REMOTE_HOP2P_DRAM)
+#define SKL_SPL_HIT			BIT_ULL(30)
+#define SKL_SNOOP_NONE			BIT_ULL(31)
+#define SKL_SNOOP_NOT_NEEDED		BIT_ULL(32)
+#define SKL_SNOOP_MISS			BIT_ULL(33)
+#define SKL_SNOOP_HIT_NO_FWD		BIT_ULL(34)
+#define SKL_SNOOP_HIT_WITH_FWD		BIT_ULL(35)
+#define SKL_SNOOP_HITM			BIT_ULL(36)
+#define SKL_SNOOP_NON_DRAM		BIT_ULL(37)
+#define SKL_ANY_SNOOP			(SKL_SPL_HIT|SKL_SNOOP_NONE| \
+					 SKL_SNOOP_NOT_NEEDED|SKL_SNOOP_MISS| \
+					 SKL_SNOOP_HIT_NO_FWD|SKL_SNOOP_HIT_WITH_FWD| \
+					 SKL_SNOOP_HITM|SKL_SNOOP_NON_DRAM)
+#define SKL_DEMAND_READ			SKL_DEMAND_DATA_RD
+#define SKL_SNOOP_DRAM			(SKL_SNOOP_NONE| \
+					 SKL_SNOOP_NOT_NEEDED|SKL_SNOOP_MISS| \
+					 SKL_SNOOP_HIT_NO_FWD|SKL_SNOOP_HIT_WITH_FWD| \
+					 SKL_SNOOP_HITM|SKL_SPL_HIT)
+#define SKL_DEMAND_WRITE		SKL_DEMAND_RFO
+#define SKL_LLC_ACCESS			SKL_ANY_RESPONSE
+#define SKL_L3_MISS_REMOTE		(SKL_L3_MISS_REMOTE_HOP0_DRAM| \
+					 SKL_L3_MISS_REMOTE_HOP1_DRAM| \
+					 SKL_L3_MISS_REMOTE_HOP2P_DRAM)
+
+static __initconst const u64 skl_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x81d0,	/* MEM_INST_RETIRED.ALL_LOADS */
+		[ C(RESULT_MISS)   ] = 0x151,	/* L1D.REPLACEMENT */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x82d0,	/* MEM_INST_RETIRED.ALL_STORES */
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x283,	/* ICACHE_64B.MISS */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1b7,	/* OFFCORE_RESPONSE */
+		[ C(RESULT_MISS)   ] = 0x1b7,	/* OFFCORE_RESPONSE */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1b7,	/* OFFCORE_RESPONSE */
+		[ C(RESULT_MISS)   ] = 0x1b7,	/* OFFCORE_RESPONSE */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x81d0,	/* MEM_INST_RETIRED.ALL_LOADS */
+		[ C(RESULT_MISS)   ] = 0x608,	/* DTLB_LOAD_MISSES.WALK_COMPLETED */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x82d0,	/* MEM_INST_RETIRED.ALL_STORES */
+		[ C(RESULT_MISS)   ] = 0x649,	/* DTLB_STORE_MISSES.WALK_COMPLETED */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x2085,	/* ITLB_MISSES.STLB_HIT */
+		[ C(RESULT_MISS)   ] = 0xe85,	/* ITLB_MISSES.WALK_COMPLETED */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0xc4,	/* BR_INST_RETIRED.ALL_BRANCHES */
+		[ C(RESULT_MISS)   ] = 0xc5,	/* BR_MISP_RETIRED.ALL_BRANCHES */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1b7,	/* OFFCORE_RESPONSE */
+		[ C(RESULT_MISS)   ] = 0x1b7,	/* OFFCORE_RESPONSE */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1b7,	/* OFFCORE_RESPONSE */
+		[ C(RESULT_MISS)   ] = 0x1b7,	/* OFFCORE_RESPONSE */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+};
+
+static __initconst const u64 skl_hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = SKL_DEMAND_READ|
+				       SKL_LLC_ACCESS|SKL_ANY_SNOOP,
+		[ C(RESULT_MISS)   ] = SKL_DEMAND_READ|
+				       SKL_L3_MISS|SKL_ANY_SNOOP|
+				       SKL_SUPPLIER_NONE,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = SKL_DEMAND_WRITE|
+				       SKL_LLC_ACCESS|SKL_ANY_SNOOP,
+		[ C(RESULT_MISS)   ] = SKL_DEMAND_WRITE|
+				       SKL_L3_MISS|SKL_ANY_SNOOP|
+				       SKL_SUPPLIER_NONE,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = SKL_DEMAND_READ|
+				       SKL_L3_MISS_LOCAL_DRAM|SKL_SNOOP_DRAM,
+		[ C(RESULT_MISS)   ] = SKL_DEMAND_READ|
+				       SKL_L3_MISS_REMOTE|SKL_SNOOP_DRAM,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = SKL_DEMAND_WRITE|
+				       SKL_L3_MISS_LOCAL_DRAM|SKL_SNOOP_DRAM,
+		[ C(RESULT_MISS)   ] = SKL_DEMAND_WRITE|
+				       SKL_L3_MISS_REMOTE|SKL_SNOOP_DRAM,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+};
+
+#define SNB_DMND_DATA_RD	(1ULL << 0)
+#define SNB_DMND_RFO		(1ULL << 1)
+#define SNB_DMND_IFETCH		(1ULL << 2)
+#define SNB_DMND_WB		(1ULL << 3)
+#define SNB_PF_DATA_RD		(1ULL << 4)
+#define SNB_PF_RFO		(1ULL << 5)
+#define SNB_PF_IFETCH		(1ULL << 6)
+#define SNB_LLC_DATA_RD		(1ULL << 7)
+#define SNB_LLC_RFO		(1ULL << 8)
+#define SNB_LLC_IFETCH		(1ULL << 9)
+#define SNB_BUS_LOCKS		(1ULL << 10)
+#define SNB_STRM_ST		(1ULL << 11)
+#define SNB_OTHER		(1ULL << 15)
+#define SNB_RESP_ANY		(1ULL << 16)
+#define SNB_NO_SUPP		(1ULL << 17)
+#define SNB_LLC_HITM		(1ULL << 18)
+#define SNB_LLC_HITE		(1ULL << 19)
+#define SNB_LLC_HITS		(1ULL << 20)
+#define SNB_LLC_HITF		(1ULL << 21)
+#define SNB_LOCAL		(1ULL << 22)
+#define SNB_REMOTE		(0xffULL << 23)
+#define SNB_SNP_NONE		(1ULL << 31)
+#define SNB_SNP_NOT_NEEDED	(1ULL << 32)
+#define SNB_SNP_MISS		(1ULL << 33)
+#define SNB_NO_FWD		(1ULL << 34)
+#define SNB_SNP_FWD		(1ULL << 35)
+#define SNB_HITM		(1ULL << 36)
+#define SNB_NON_DRAM		(1ULL << 37)
+
+#define SNB_DMND_READ		(SNB_DMND_DATA_RD|SNB_LLC_DATA_RD)
+#define SNB_DMND_WRITE		(SNB_DMND_RFO|SNB_LLC_RFO)
+#define SNB_DMND_PREFETCH	(SNB_PF_DATA_RD|SNB_PF_RFO)
+
+#define SNB_SNP_ANY		(SNB_SNP_NONE|SNB_SNP_NOT_NEEDED| \
+				 SNB_SNP_MISS|SNB_NO_FWD|SNB_SNP_FWD| \
+				 SNB_HITM)
+
+#define SNB_DRAM_ANY		(SNB_LOCAL|SNB_REMOTE|SNB_SNP_ANY)
+#define SNB_DRAM_REMOTE		(SNB_REMOTE|SNB_SNP_ANY)
+
+#define SNB_L3_ACCESS		SNB_RESP_ANY
+#define SNB_L3_MISS		(SNB_DRAM_ANY|SNB_NON_DRAM)
+
+static __initconst const u64 snb_hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = SNB_DMND_READ|SNB_L3_ACCESS,
+		[ C(RESULT_MISS)   ] = SNB_DMND_READ|SNB_L3_MISS,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = SNB_DMND_WRITE|SNB_L3_ACCESS,
+		[ C(RESULT_MISS)   ] = SNB_DMND_WRITE|SNB_L3_MISS,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = SNB_DMND_PREFETCH|SNB_L3_ACCESS,
+		[ C(RESULT_MISS)   ] = SNB_DMND_PREFETCH|SNB_L3_MISS,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = SNB_DMND_READ|SNB_DRAM_ANY,
+		[ C(RESULT_MISS)   ] = SNB_DMND_READ|SNB_DRAM_REMOTE,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = SNB_DMND_WRITE|SNB_DRAM_ANY,
+		[ C(RESULT_MISS)   ] = SNB_DMND_WRITE|SNB_DRAM_REMOTE,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = SNB_DMND_PREFETCH|SNB_DRAM_ANY,
+		[ C(RESULT_MISS)   ] = SNB_DMND_PREFETCH|SNB_DRAM_REMOTE,
+	},
+ },
+};
+
+static __initconst const u64 snb_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0xf1d0, /* MEM_UOP_RETIRED.LOADS        */
+		[ C(RESULT_MISS)   ] = 0x0151, /* L1D.REPLACEMENT              */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0xf2d0, /* MEM_UOP_RETIRED.STORES       */
+		[ C(RESULT_MISS)   ] = 0x0851, /* L1D.ALL_M_REPLACEMENT        */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x024e, /* HW_PRE_REQ.DL1_MISS          */
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0280, /* ICACHE.MISSES */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		/* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_WRITE) ] = {
+		/* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_PREFETCH) ] = {
+		/* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x81d0, /* MEM_UOP_RETIRED.ALL_LOADS */
+		[ C(RESULT_MISS)   ] = 0x0108, /* DTLB_LOAD_MISSES.CAUSES_A_WALK */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x82d0, /* MEM_UOP_RETIRED.ALL_STORES */
+		[ C(RESULT_MISS)   ] = 0x0149, /* DTLB_STORE_MISSES.MISS_CAUSES_A_WALK */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1085, /* ITLB_MISSES.STLB_HIT         */
+		[ C(RESULT_MISS)   ] = 0x0185, /* ITLB_MISSES.CAUSES_A_WALK    */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */
+		[ C(RESULT_MISS)   ] = 0x00c5, /* BR_MISP_RETIRED.ALL_BRANCHES */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+ },
+
+};
+
+/*
+ * Notes on the events:
+ * - data reads do not include code reads (comparable to earlier tables)
+ * - data counts include speculative execution (except L1 write, dtlb, bpu)
+ * - remote node access includes remote memory, remote cache, remote mmio.
+ * - prefetches are not included in the counts because they are not
+ *   reliably counted.
+ */
+
+#define HSW_DEMAND_DATA_RD		BIT_ULL(0)
+#define HSW_DEMAND_RFO			BIT_ULL(1)
+#define HSW_ANY_RESPONSE		BIT_ULL(16)
+#define HSW_SUPPLIER_NONE		BIT_ULL(17)
+#define HSW_L3_MISS_LOCAL_DRAM		BIT_ULL(22)
+#define HSW_L3_MISS_REMOTE_HOP0		BIT_ULL(27)
+#define HSW_L3_MISS_REMOTE_HOP1		BIT_ULL(28)
+#define HSW_L3_MISS_REMOTE_HOP2P	BIT_ULL(29)
+#define HSW_L3_MISS			(HSW_L3_MISS_LOCAL_DRAM| \
+					 HSW_L3_MISS_REMOTE_HOP0|HSW_L3_MISS_REMOTE_HOP1| \
+					 HSW_L3_MISS_REMOTE_HOP2P)
+#define HSW_SNOOP_NONE			BIT_ULL(31)
+#define HSW_SNOOP_NOT_NEEDED		BIT_ULL(32)
+#define HSW_SNOOP_MISS			BIT_ULL(33)
+#define HSW_SNOOP_HIT_NO_FWD		BIT_ULL(34)
+#define HSW_SNOOP_HIT_WITH_FWD		BIT_ULL(35)
+#define HSW_SNOOP_HITM			BIT_ULL(36)
+#define HSW_SNOOP_NON_DRAM		BIT_ULL(37)
+#define HSW_ANY_SNOOP			(HSW_SNOOP_NONE| \
+					 HSW_SNOOP_NOT_NEEDED|HSW_SNOOP_MISS| \
+					 HSW_SNOOP_HIT_NO_FWD|HSW_SNOOP_HIT_WITH_FWD| \
+					 HSW_SNOOP_HITM|HSW_SNOOP_NON_DRAM)
+#define HSW_SNOOP_DRAM			(HSW_ANY_SNOOP & ~HSW_SNOOP_NON_DRAM)
+#define HSW_DEMAND_READ			HSW_DEMAND_DATA_RD
+#define HSW_DEMAND_WRITE		HSW_DEMAND_RFO
+#define HSW_L3_MISS_REMOTE		(HSW_L3_MISS_REMOTE_HOP0|\
+					 HSW_L3_MISS_REMOTE_HOP1|HSW_L3_MISS_REMOTE_HOP2P)
+#define HSW_LLC_ACCESS			HSW_ANY_RESPONSE
+
+#define BDW_L3_MISS_LOCAL		BIT(26)
+#define BDW_L3_MISS			(BDW_L3_MISS_LOCAL| \
+					 HSW_L3_MISS_REMOTE_HOP0|HSW_L3_MISS_REMOTE_HOP1| \
+					 HSW_L3_MISS_REMOTE_HOP2P)
+
+
+static __initconst const u64 hsw_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x81d0,	/* MEM_UOPS_RETIRED.ALL_LOADS */
+		[ C(RESULT_MISS)   ] = 0x151,	/* L1D.REPLACEMENT */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x82d0,	/* MEM_UOPS_RETIRED.ALL_STORES */
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x280,	/* ICACHE.MISSES */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1b7,	/* OFFCORE_RESPONSE */
+		[ C(RESULT_MISS)   ] = 0x1b7,	/* OFFCORE_RESPONSE */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1b7,	/* OFFCORE_RESPONSE */
+		[ C(RESULT_MISS)   ] = 0x1b7,	/* OFFCORE_RESPONSE */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x81d0,	/* MEM_UOPS_RETIRED.ALL_LOADS */
+		[ C(RESULT_MISS)   ] = 0x108,	/* DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x82d0,	/* MEM_UOPS_RETIRED.ALL_STORES */
+		[ C(RESULT_MISS)   ] = 0x149,	/* DTLB_STORE_MISSES.MISS_CAUSES_A_WALK */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x6085,	/* ITLB_MISSES.STLB_HIT */
+		[ C(RESULT_MISS)   ] = 0x185,	/* ITLB_MISSES.MISS_CAUSES_A_WALK */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0xc4,	/* BR_INST_RETIRED.ALL_BRANCHES */
+		[ C(RESULT_MISS)   ] = 0xc5,	/* BR_MISP_RETIRED.ALL_BRANCHES */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1b7,	/* OFFCORE_RESPONSE */
+		[ C(RESULT_MISS)   ] = 0x1b7,	/* OFFCORE_RESPONSE */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x1b7,	/* OFFCORE_RESPONSE */
+		[ C(RESULT_MISS)   ] = 0x1b7,	/* OFFCORE_RESPONSE */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+};
+
+static __initconst const u64 hsw_hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = HSW_DEMAND_READ|
+				       HSW_LLC_ACCESS,
+		[ C(RESULT_MISS)   ] = HSW_DEMAND_READ|
+				       HSW_L3_MISS|HSW_ANY_SNOOP,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = HSW_DEMAND_WRITE|
+				       HSW_LLC_ACCESS,
+		[ C(RESULT_MISS)   ] = HSW_DEMAND_WRITE|
+				       HSW_L3_MISS|HSW_ANY_SNOOP,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = HSW_DEMAND_READ|
+				       HSW_L3_MISS_LOCAL_DRAM|
+				       HSW_SNOOP_DRAM,
+		[ C(RESULT_MISS)   ] = HSW_DEMAND_READ|
+				       HSW_L3_MISS_REMOTE|
+				       HSW_SNOOP_DRAM,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = HSW_DEMAND_WRITE|
+				       HSW_L3_MISS_LOCAL_DRAM|
+				       HSW_SNOOP_DRAM,
+		[ C(RESULT_MISS)   ] = HSW_DEMAND_WRITE|
+				       HSW_L3_MISS_REMOTE|
+				       HSW_SNOOP_DRAM,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+};
+
+static __initconst const u64 westmere_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS       */
+		[ C(RESULT_MISS)   ] = 0x0151, /* L1D.REPL                     */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES      */
+		[ C(RESULT_MISS)   ] = 0x0251, /* L1D.M_REPL                   */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS        */
+		[ C(RESULT_MISS)   ] = 0x024e, /* L1D_PREFETCH.MISS            */
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0380, /* L1I.READS                    */
+		[ C(RESULT_MISS)   ] = 0x0280, /* L1I.MISSES                   */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		/* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	/*
+	 * Use RFO, not WRITEBACK, because a write miss would typically occur
+	 * on RFO.
+	 */
+	[ C(OP_WRITE) ] = {
+		/* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_PREFETCH) ] = {
+		/* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS       */
+		[ C(RESULT_MISS)   ] = 0x0108, /* DTLB_LOAD_MISSES.ANY         */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES      */
+		[ C(RESULT_MISS)   ] = 0x010c, /* MEM_STORE_RETIRED.DTLB_MISS  */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01c0, /* INST_RETIRED.ANY_P           */
+		[ C(RESULT_MISS)   ] = 0x0185, /* ITLB_MISSES.ANY              */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */
+		[ C(RESULT_MISS)   ] = 0x03e8, /* BPU_CLEARS.ANY               */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+ },
+};
+
+/*
+ * Nehalem/Westmere MSR_OFFCORE_RESPONSE bits;
+ * See IA32 SDM Vol 3B 30.6.1.3
+ */
+
+#define NHM_DMND_DATA_RD	(1 << 0)
+#define NHM_DMND_RFO		(1 << 1)
+#define NHM_DMND_IFETCH		(1 << 2)
+#define NHM_DMND_WB		(1 << 3)
+#define NHM_PF_DATA_RD		(1 << 4)
+#define NHM_PF_DATA_RFO		(1 << 5)
+#define NHM_PF_IFETCH		(1 << 6)
+#define NHM_OFFCORE_OTHER	(1 << 7)
+#define NHM_UNCORE_HIT		(1 << 8)
+#define NHM_OTHER_CORE_HIT_SNP	(1 << 9)
+#define NHM_OTHER_CORE_HITM	(1 << 10)
+        			/* reserved */
+#define NHM_REMOTE_CACHE_FWD	(1 << 12)
+#define NHM_REMOTE_DRAM		(1 << 13)
+#define NHM_LOCAL_DRAM		(1 << 14)
+#define NHM_NON_DRAM		(1 << 15)
+
+#define NHM_LOCAL		(NHM_LOCAL_DRAM|NHM_REMOTE_CACHE_FWD)
+#define NHM_REMOTE		(NHM_REMOTE_DRAM)
+
+#define NHM_DMND_READ		(NHM_DMND_DATA_RD)
+#define NHM_DMND_WRITE		(NHM_DMND_RFO|NHM_DMND_WB)
+#define NHM_DMND_PREFETCH	(NHM_PF_DATA_RD|NHM_PF_DATA_RFO)
+
+#define NHM_L3_HIT	(NHM_UNCORE_HIT|NHM_OTHER_CORE_HIT_SNP|NHM_OTHER_CORE_HITM)
+#define NHM_L3_MISS	(NHM_NON_DRAM|NHM_LOCAL_DRAM|NHM_REMOTE_DRAM|NHM_REMOTE_CACHE_FWD)
+#define NHM_L3_ACCESS	(NHM_L3_HIT|NHM_L3_MISS)
+
+static __initconst const u64 nehalem_hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_L3_ACCESS,
+		[ C(RESULT_MISS)   ] = NHM_DMND_READ|NHM_L3_MISS,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_L3_ACCESS,
+		[ C(RESULT_MISS)   ] = NHM_DMND_WRITE|NHM_L3_MISS,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_L3_ACCESS,
+		[ C(RESULT_MISS)   ] = NHM_DMND_PREFETCH|NHM_L3_MISS,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_LOCAL|NHM_REMOTE,
+		[ C(RESULT_MISS)   ] = NHM_DMND_READ|NHM_REMOTE,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_LOCAL|NHM_REMOTE,
+		[ C(RESULT_MISS)   ] = NHM_DMND_WRITE|NHM_REMOTE,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_LOCAL|NHM_REMOTE,
+		[ C(RESULT_MISS)   ] = NHM_DMND_PREFETCH|NHM_REMOTE,
+	},
+ },
+};
+
+static __initconst const u64 nehalem_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS       */
+		[ C(RESULT_MISS)   ] = 0x0151, /* L1D.REPL                     */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES      */
+		[ C(RESULT_MISS)   ] = 0x0251, /* L1D.M_REPL                   */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS        */
+		[ C(RESULT_MISS)   ] = 0x024e, /* L1D_PREFETCH.MISS            */
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0380, /* L1I.READS                    */
+		[ C(RESULT_MISS)   ] = 0x0280, /* L1I.MISSES                   */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		/* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	/*
+	 * Use RFO, not WRITEBACK, because a write miss would typically occur
+	 * on RFO.
+	 */
+	[ C(OP_WRITE) ] = {
+		/* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_PREFETCH) ] = {
+		/* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI   (alias)  */
+		[ C(RESULT_MISS)   ] = 0x0108, /* DTLB_LOAD_MISSES.ANY         */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI   (alias)  */
+		[ C(RESULT_MISS)   ] = 0x010c, /* MEM_STORE_RETIRED.DTLB_MISS  */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01c0, /* INST_RETIRED.ANY_P           */
+		[ C(RESULT_MISS)   ] = 0x20c8, /* ITLB_MISS_RETIRED            */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */
+		[ C(RESULT_MISS)   ] = 0x03e8, /* BPU_CLEARS.ANY               */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+ },
+};
+
+static __initconst const u64 core2_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI          */
+		[ C(RESULT_MISS)   ] = 0x0140, /* L1D_CACHE_LD.I_STATE       */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI          */
+		[ C(RESULT_MISS)   ] = 0x0141, /* L1D_CACHE_ST.I_STATE       */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x104e, /* L1D_PREFETCH.REQUESTS      */
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0080, /* L1I.READS                  */
+		[ C(RESULT_MISS)   ] = 0x0081, /* L1I.MISSES                 */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x4f29, /* L2_LD.MESI                 */
+		[ C(RESULT_MISS)   ] = 0x4129, /* L2_LD.ISTATE               */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x4f2A, /* L2_ST.MESI                 */
+		[ C(RESULT_MISS)   ] = 0x412A, /* L2_ST.ISTATE               */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI  (alias) */
+		[ C(RESULT_MISS)   ] = 0x0208, /* DTLB_MISSES.MISS_LD        */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI  (alias) */
+		[ C(RESULT_MISS)   ] = 0x0808, /* DTLB_MISSES.MISS_ST        */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c0, /* INST_RETIRED.ANY_P         */
+		[ C(RESULT_MISS)   ] = 0x1282, /* ITLBMISSES                 */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ANY        */
+		[ C(RESULT_MISS)   ] = 0x00c5, /* BP_INST_RETIRED.MISPRED    */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+};
+
+static __initconst const u64 atom_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x2140, /* L1D_CACHE.LD               */
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x2240, /* L1D_CACHE.ST               */
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0380, /* L1I.READS                  */
+		[ C(RESULT_MISS)   ] = 0x0280, /* L1I.MISSES                 */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x4f29, /* L2_LD.MESI                 */
+		[ C(RESULT_MISS)   ] = 0x4129, /* L2_LD.ISTATE               */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x4f2A, /* L2_ST.MESI                 */
+		[ C(RESULT_MISS)   ] = 0x412A, /* L2_ST.ISTATE               */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x2140, /* L1D_CACHE_LD.MESI  (alias) */
+		[ C(RESULT_MISS)   ] = 0x0508, /* DTLB_MISSES.MISS_LD        */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x2240, /* L1D_CACHE_ST.MESI  (alias) */
+		[ C(RESULT_MISS)   ] = 0x0608, /* DTLB_MISSES.MISS_ST        */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c0, /* INST_RETIRED.ANY_P         */
+		[ C(RESULT_MISS)   ] = 0x0282, /* ITLB.MISSES                */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ANY        */
+		[ C(RESULT_MISS)   ] = 0x00c5, /* BP_INST_RETIRED.MISPRED    */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+};
+
+static struct extra_reg intel_slm_extra_regs[] __read_mostly =
+{
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x768005ffffull, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0x368005ffffull, RSP_1),
+	EVENT_EXTRA_END
+};
+
+#define SLM_DMND_READ		SNB_DMND_DATA_RD
+#define SLM_DMND_WRITE		SNB_DMND_RFO
+#define SLM_DMND_PREFETCH	(SNB_PF_DATA_RD|SNB_PF_RFO)
+
+#define SLM_SNP_ANY		(SNB_SNP_NONE|SNB_SNP_MISS|SNB_NO_FWD|SNB_HITM)
+#define SLM_LLC_ACCESS		SNB_RESP_ANY
+#define SLM_LLC_MISS		(SLM_SNP_ANY|SNB_NON_DRAM)
+
+static __initconst const u64 slm_hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = SLM_DMND_READ|SLM_LLC_ACCESS,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = SLM_DMND_WRITE|SLM_LLC_ACCESS,
+		[ C(RESULT_MISS)   ] = SLM_DMND_WRITE|SLM_LLC_MISS,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = SLM_DMND_PREFETCH|SLM_LLC_ACCESS,
+		[ C(RESULT_MISS)   ] = SLM_DMND_PREFETCH|SLM_LLC_MISS,
+	},
+ },
+};
+
+static __initconst const u64 slm_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0x0104, /* LD_DCU_MISS */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0380, /* ICACHE.ACCESSES */
+		[ C(RESULT_MISS)   ] = 0x0280, /* ICACGE.MISSES */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		/* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_WRITE) ] = {
+		/* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_PREFETCH) ] = {
+		/* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0x0804, /* LD_DTLB_MISS */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c0, /* INST_RETIRED.ANY_P */
+		[ C(RESULT_MISS)   ] = 0x40205, /* PAGE_WALKS.I_SIDE_WALKS */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ANY */
+		[ C(RESULT_MISS)   ] = 0x00c5, /* BP_INST_RETIRED.MISPRED */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+};
+
+#define KNL_OT_L2_HITE		BIT_ULL(19) /* Other Tile L2 Hit */
+#define KNL_OT_L2_HITF		BIT_ULL(20) /* Other Tile L2 Hit */
+#define KNL_MCDRAM_LOCAL	BIT_ULL(21)
+#define KNL_MCDRAM_FAR		BIT_ULL(22)
+#define KNL_DDR_LOCAL		BIT_ULL(23)
+#define KNL_DDR_FAR		BIT_ULL(24)
+#define KNL_DRAM_ANY		(KNL_MCDRAM_LOCAL | KNL_MCDRAM_FAR | \
+				    KNL_DDR_LOCAL | KNL_DDR_FAR)
+#define KNL_L2_READ		SLM_DMND_READ
+#define KNL_L2_WRITE		SLM_DMND_WRITE
+#define KNL_L2_PREFETCH		SLM_DMND_PREFETCH
+#define KNL_L2_ACCESS		SLM_LLC_ACCESS
+#define KNL_L2_MISS		(KNL_OT_L2_HITE | KNL_OT_L2_HITF | \
+				   KNL_DRAM_ANY | SNB_SNP_ANY | \
+						  SNB_NON_DRAM)
+
+static __initconst const u64 knl_hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+	[C(LL)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)] = KNL_L2_READ | KNL_L2_ACCESS,
+			[C(RESULT_MISS)]   = 0,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)] = KNL_L2_WRITE | KNL_L2_ACCESS,
+			[C(RESULT_MISS)]   = KNL_L2_WRITE | KNL_L2_MISS,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)] = KNL_L2_PREFETCH | KNL_L2_ACCESS,
+			[C(RESULT_MISS)]   = KNL_L2_PREFETCH | KNL_L2_MISS,
+		},
+	},
+};
+
+/*
+ * Used from PMIs where the LBRs are already disabled.
+ *
+ * This function could be called consecutively. It is required to remain in
+ * disabled state if called consecutively.
+ *
+ * During consecutive calls, the same disable value will be written to related
+ * registers, so the PMU state remains unchanged. hw.state in
+ * intel_bts_disable_local will remain PERF_HES_STOPPED too in consecutive
+ * calls.
+ */
+static void __intel_pmu_disable_all(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
+
+	if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask))
+		intel_pmu_disable_bts();
+	else
+		intel_bts_disable_local();
+
+	intel_pmu_pebs_disable_all();
+}
+
+static void intel_pmu_disable_all(void)
+{
+	__intel_pmu_disable_all();
+	intel_pmu_lbr_disable_all();
+}
+
+static void __intel_pmu_enable_all(int added, bool pmi)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	intel_pmu_pebs_enable_all();
+	intel_pmu_lbr_enable_all(pmi);
+	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL,
+			x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask);
+
+	if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask)) {
+		struct perf_event *event =
+			cpuc->events[INTEL_PMC_IDX_FIXED_BTS];
+
+		if (WARN_ON_ONCE(!event))
+			return;
+
+		intel_pmu_enable_bts(event->hw.config);
+	} else
+		intel_bts_enable_local();
+}
+
+static void intel_pmu_enable_all(int added)
+{
+	__intel_pmu_enable_all(added, false);
+}
+
+/*
+ * Workaround for:
+ *   Intel Errata AAK100 (model 26)
+ *   Intel Errata AAP53  (model 30)
+ *   Intel Errata BD53   (model 44)
+ *
+ * The official story:
+ *   These chips need to be 'reset' when adding counters by programming the
+ *   magic three (non-counting) events 0x4300B5, 0x4300D2, and 0x4300B1 either
+ *   in sequence on the same PMC or on different PMCs.
+ *
+ * In practise it appears some of these events do in fact count, and
+ * we need to programm all 4 events.
+ */
+static void intel_pmu_nhm_workaround(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	static const unsigned long nhm_magic[4] = {
+		0x4300B5,
+		0x4300D2,
+		0x4300B1,
+		0x4300B1
+	};
+	struct perf_event *event;
+	int i;
+
+	/*
+	 * The Errata requires below steps:
+	 * 1) Clear MSR_IA32_PEBS_ENABLE and MSR_CORE_PERF_GLOBAL_CTRL;
+	 * 2) Configure 4 PERFEVTSELx with the magic events and clear
+	 *    the corresponding PMCx;
+	 * 3) set bit0~bit3 of MSR_CORE_PERF_GLOBAL_CTRL;
+	 * 4) Clear MSR_CORE_PERF_GLOBAL_CTRL;
+	 * 5) Clear 4 pairs of ERFEVTSELx and PMCx;
+	 */
+
+	/*
+	 * The real steps we choose are a little different from above.
+	 * A) To reduce MSR operations, we don't run step 1) as they
+	 *    are already cleared before this function is called;
+	 * B) Call x86_perf_event_update to save PMCx before configuring
+	 *    PERFEVTSELx with magic number;
+	 * C) With step 5), we do clear only when the PERFEVTSELx is
+	 *    not used currently.
+	 * D) Call x86_perf_event_set_period to restore PMCx;
+	 */
+
+	/* We always operate 4 pairs of PERF Counters */
+	for (i = 0; i < 4; i++) {
+		event = cpuc->events[i];
+		if (event)
+			x86_perf_event_update(event);
+	}
+
+	for (i = 0; i < 4; i++) {
+		wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + i, nhm_magic[i]);
+		wrmsrl(MSR_ARCH_PERFMON_PERFCTR0 + i, 0x0);
+	}
+
+	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0xf);
+	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x0);
+
+	for (i = 0; i < 4; i++) {
+		event = cpuc->events[i];
+
+		if (event) {
+			x86_perf_event_set_period(event);
+			__x86_pmu_enable_event(&event->hw,
+					ARCH_PERFMON_EVENTSEL_ENABLE);
+		} else
+			wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + i, 0x0);
+	}
+}
+
+static void intel_pmu_nhm_enable_all(int added)
+{
+	if (added)
+		intel_pmu_nhm_workaround();
+	intel_pmu_enable_all(added);
+}
+
+static inline u64 intel_pmu_get_status(void)
+{
+	u64 status;
+
+	rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
+
+	return status;
+}
+
+static inline void intel_pmu_ack_status(u64 ack)
+{
+	wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack);
+}
+
+static void intel_pmu_disable_fixed(struct hw_perf_event *hwc)
+{
+	int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
+	u64 ctrl_val, mask;
+
+	mask = 0xfULL << (idx * 4);
+
+	rdmsrl(hwc->config_base, ctrl_val);
+	ctrl_val &= ~mask;
+	wrmsrl(hwc->config_base, ctrl_val);
+}
+
+static inline bool event_is_checkpointed(struct perf_event *event)
+{
+	return (event->hw.config & HSW_IN_TX_CHECKPOINTED) != 0;
+}
+
+static void intel_pmu_disable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	if (unlikely(hwc->idx == INTEL_PMC_IDX_FIXED_BTS)) {
+		intel_pmu_disable_bts();
+		intel_pmu_drain_bts_buffer();
+		return;
+	}
+
+	cpuc->intel_ctrl_guest_mask &= ~(1ull << hwc->idx);
+	cpuc->intel_ctrl_host_mask &= ~(1ull << hwc->idx);
+	cpuc->intel_cp_status &= ~(1ull << hwc->idx);
+
+	/*
+	 * must disable before any actual event
+	 * because any event may be combined with LBR
+	 */
+	if (needs_branch_stack(event))
+		intel_pmu_lbr_disable(event);
+
+	if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
+		intel_pmu_disable_fixed(hwc);
+		return;
+	}
+
+	x86_pmu_disable_event(event);
+
+	if (unlikely(event->attr.precise_ip))
+		intel_pmu_pebs_disable(event);
+}
+
+static void intel_pmu_enable_fixed(struct hw_perf_event *hwc)
+{
+	int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
+	u64 ctrl_val, bits, mask;
+
+	/*
+	 * Enable IRQ generation (0x8),
+	 * and enable ring-3 counting (0x2) and ring-0 counting (0x1)
+	 * if requested:
+	 */
+	bits = 0x8ULL;
+	if (hwc->config & ARCH_PERFMON_EVENTSEL_USR)
+		bits |= 0x2;
+	if (hwc->config & ARCH_PERFMON_EVENTSEL_OS)
+		bits |= 0x1;
+
+	/*
+	 * ANY bit is supported in v3 and up
+	 */
+	if (x86_pmu.version > 2 && hwc->config & ARCH_PERFMON_EVENTSEL_ANY)
+		bits |= 0x4;
+
+	bits <<= (idx * 4);
+	mask = 0xfULL << (idx * 4);
+
+	rdmsrl(hwc->config_base, ctrl_val);
+	ctrl_val &= ~mask;
+	ctrl_val |= bits;
+	wrmsrl(hwc->config_base, ctrl_val);
+}
+
+static void intel_pmu_enable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	if (unlikely(hwc->idx == INTEL_PMC_IDX_FIXED_BTS)) {
+		if (!__this_cpu_read(cpu_hw_events.enabled))
+			return;
+
+		intel_pmu_enable_bts(hwc->config);
+		return;
+	}
+	/*
+	 * must enabled before any actual event
+	 * because any event may be combined with LBR
+	 */
+	if (needs_branch_stack(event))
+		intel_pmu_lbr_enable(event);
+
+	if (event->attr.exclude_host)
+		cpuc->intel_ctrl_guest_mask |= (1ull << hwc->idx);
+	if (event->attr.exclude_guest)
+		cpuc->intel_ctrl_host_mask |= (1ull << hwc->idx);
+
+	if (unlikely(event_is_checkpointed(event)))
+		cpuc->intel_cp_status |= (1ull << hwc->idx);
+
+	if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
+		intel_pmu_enable_fixed(hwc);
+		return;
+	}
+
+	if (unlikely(event->attr.precise_ip))
+		intel_pmu_pebs_enable(event);
+
+	__x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
+}
+
+/*
+ * Save and restart an expired event. Called by NMI contexts,
+ * so it has to be careful about preempting normal event ops:
+ */
+int intel_pmu_save_and_restart(struct perf_event *event)
+{
+	x86_perf_event_update(event);
+	/*
+	 * For a checkpointed counter always reset back to 0.  This
+	 * avoids a situation where the counter overflows, aborts the
+	 * transaction and is then set back to shortly before the
+	 * overflow, and overflows and aborts again.
+	 */
+	if (unlikely(event_is_checkpointed(event))) {
+		/* No race with NMIs because the counter should not be armed */
+		wrmsrl(event->hw.event_base, 0);
+		local64_set(&event->hw.prev_count, 0);
+	}
+	return x86_perf_event_set_period(event);
+}
+
+static void intel_pmu_reset(void)
+{
+	struct debug_store *ds = __this_cpu_read(cpu_hw_events.ds);
+	unsigned long flags;
+	int idx;
+
+	if (!x86_pmu.num_counters)
+		return;
+
+	local_irq_save(flags);
+
+	pr_info("clearing PMU state on CPU#%d\n", smp_processor_id());
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		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++)
+		wrmsrl_safe(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
+
+	if (ds)
+		ds->bts_index = ds->bts_buffer_base;
+
+	/* Ack all overflows and disable fixed counters */
+	if (x86_pmu.version >= 2) {
+		intel_pmu_ack_status(intel_pmu_get_status());
+		wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
+	}
+
+	/* Reset LBRs and LBR freezing */
+	if (x86_pmu.lbr_nr) {
+		update_debugctlmsr(get_debugctlmsr() &
+			~(DEBUGCTLMSR_FREEZE_LBRS_ON_PMI|DEBUGCTLMSR_LBR));
+	}
+
+	local_irq_restore(flags);
+}
+
+/*
+ * This handler is triggered by the local APIC, so the APIC IRQ handling
+ * rules apply:
+ */
+static int intel_pmu_handle_irq(struct pt_regs *regs)
+{
+	struct perf_sample_data data;
+	struct cpu_hw_events *cpuc;
+	int bit, loops;
+	u64 status;
+	int handled;
+
+	cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	/*
+	 * No known reason to not always do late ACK,
+	 * but just in case do it opt-in.
+	 */
+	if (!x86_pmu.late_ack)
+		apic_write(APIC_LVTPC, APIC_DM_NMI);
+	__intel_pmu_disable_all();
+	handled = intel_pmu_drain_bts_buffer();
+	handled += intel_bts_interrupt();
+	status = intel_pmu_get_status();
+	if (!status)
+		goto done;
+
+	loops = 0;
+again:
+	intel_pmu_lbr_read();
+	intel_pmu_ack_status(status);
+	if (++loops > 100) {
+		static bool warned = false;
+		if (!warned) {
+			WARN(1, "perfevents: irq loop stuck!\n");
+			perf_event_print_debug();
+			warned = true;
+		}
+		intel_pmu_reset();
+		goto done;
+	}
+
+	inc_irq_stat(apic_perf_irqs);
+
+
+	/*
+	 * Ignore a range of extra bits in status that do not indicate
+	 * overflow by themselves.
+	 */
+	status &= ~(GLOBAL_STATUS_COND_CHG |
+		    GLOBAL_STATUS_ASIF |
+		    GLOBAL_STATUS_LBRS_FROZEN);
+	if (!status)
+		goto done;
+
+	/*
+	 * PEBS overflow sets bit 62 in the global status register
+	 */
+	if (__test_and_clear_bit(62, (unsigned long *)&status)) {
+		handled++;
+		x86_pmu.drain_pebs(regs);
+		/*
+		 * There are cases where, even though, the PEBS ovfl bit is set
+		 * in GLOBAL_OVF_STATUS, the PEBS events may also have their
+		 * overflow bits set for their counters. We must clear them
+		 * here because they have been processed as exact samples in
+		 * the drain_pebs() routine. They must not be processed again
+		 * in the for_each_bit_set() loop for regular samples below.
+		 */
+		status &= ~cpuc->pebs_enabled;
+		status &= x86_pmu.intel_ctrl | GLOBAL_STATUS_TRACE_TOPAPMI;
+	}
+
+	/*
+	 * Intel PT
+	 */
+	if (__test_and_clear_bit(55, (unsigned long *)&status)) {
+		handled++;
+		intel_pt_interrupt();
+	}
+
+	/*
+	 * Checkpointed counters can lead to 'spurious' PMIs because the
+	 * rollback caused by the PMI will have cleared the overflow status
+	 * bit. Therefore always force probe these counters.
+	 */
+	status |= cpuc->intel_cp_status;
+
+	for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
+		struct perf_event *event = cpuc->events[bit];
+
+		handled++;
+
+		if (!test_bit(bit, cpuc->active_mask))
+			continue;
+
+		if (!intel_pmu_save_and_restart(event))
+			continue;
+
+		perf_sample_data_init(&data, 0, event->hw.last_period);
+
+		if (has_branch_stack(event))
+			data.br_stack = &cpuc->lbr_stack;
+
+		if (perf_event_overflow(event, &data, regs))
+			x86_pmu_stop(event, 0);
+	}
+
+	/*
+	 * Repeat if there is more work to be done:
+	 */
+	status = intel_pmu_get_status();
+	if (status)
+		goto again;
+
+done:
+	/* Only restore PMU state when it's active. See x86_pmu_disable(). */
+	if (cpuc->enabled)
+		__intel_pmu_enable_all(0, true);
+
+	/*
+	 * Only unmask the NMI after the overflow counters
+	 * have been reset. This avoids spurious NMIs on
+	 * Haswell CPUs.
+	 */
+	if (x86_pmu.late_ack)
+		apic_write(APIC_LVTPC, APIC_DM_NMI);
+	return handled;
+}
+
+static struct event_constraint *
+intel_bts_constraints(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	unsigned int hw_event, bts_event;
+
+	if (event->attr.freq)
+		return NULL;
+
+	hw_event = hwc->config & INTEL_ARCH_EVENT_MASK;
+	bts_event = x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
+
+	if (unlikely(hw_event == bts_event && hwc->sample_period == 1))
+		return &bts_constraint;
+
+	return NULL;
+}
+
+static int intel_alt_er(int idx, u64 config)
+{
+	int alt_idx = idx;
+
+	if (!(x86_pmu.flags & PMU_FL_HAS_RSP_1))
+		return idx;
+
+	if (idx == EXTRA_REG_RSP_0)
+		alt_idx = EXTRA_REG_RSP_1;
+
+	if (idx == EXTRA_REG_RSP_1)
+		alt_idx = EXTRA_REG_RSP_0;
+
+	if (config & ~x86_pmu.extra_regs[alt_idx].valid_mask)
+		return idx;
+
+	return alt_idx;
+}
+
+static void intel_fixup_er(struct perf_event *event, int idx)
+{
+	event->hw.extra_reg.idx = idx;
+
+	if (idx == EXTRA_REG_RSP_0) {
+		event->hw.config &= ~INTEL_ARCH_EVENT_MASK;
+		event->hw.config |= x86_pmu.extra_regs[EXTRA_REG_RSP_0].event;
+		event->hw.extra_reg.reg = MSR_OFFCORE_RSP_0;
+	} else if (idx == EXTRA_REG_RSP_1) {
+		event->hw.config &= ~INTEL_ARCH_EVENT_MASK;
+		event->hw.config |= x86_pmu.extra_regs[EXTRA_REG_RSP_1].event;
+		event->hw.extra_reg.reg = MSR_OFFCORE_RSP_1;
+	}
+}
+
+/*
+ * manage allocation of shared extra msr for certain events
+ *
+ * sharing can be:
+ * per-cpu: to be shared between the various events on a single PMU
+ * per-core: per-cpu + shared by HT threads
+ */
+static struct event_constraint *
+__intel_shared_reg_get_constraints(struct cpu_hw_events *cpuc,
+				   struct perf_event *event,
+				   struct hw_perf_event_extra *reg)
+{
+	struct event_constraint *c = &emptyconstraint;
+	struct er_account *era;
+	unsigned long flags;
+	int idx = reg->idx;
+
+	/*
+	 * reg->alloc can be set due to existing state, so for fake cpuc we
+	 * need to ignore this, otherwise we might fail to allocate proper fake
+	 * state for this extra reg constraint. Also see the comment below.
+	 */
+	if (reg->alloc && !cpuc->is_fake)
+		return NULL; /* call x86_get_event_constraint() */
+
+again:
+	era = &cpuc->shared_regs->regs[idx];
+	/*
+	 * we use spin_lock_irqsave() to avoid lockdep issues when
+	 * passing a fake cpuc
+	 */
+	raw_spin_lock_irqsave(&era->lock, flags);
+
+	if (!atomic_read(&era->ref) || era->config == reg->config) {
+
+		/*
+		 * If its a fake cpuc -- as per validate_{group,event}() we
+		 * shouldn't touch event state and we can avoid doing so
+		 * since both will only call get_event_constraints() once
+		 * on each event, this avoids the need for reg->alloc.
+		 *
+		 * Not doing the ER fixup will only result in era->reg being
+		 * wrong, but since we won't actually try and program hardware
+		 * this isn't a problem either.
+		 */
+		if (!cpuc->is_fake) {
+			if (idx != reg->idx)
+				intel_fixup_er(event, idx);
+
+			/*
+			 * x86_schedule_events() can call get_event_constraints()
+			 * multiple times on events in the case of incremental
+			 * scheduling(). reg->alloc ensures we only do the ER
+			 * allocation once.
+			 */
+			reg->alloc = 1;
+		}
+
+		/* lock in msr value */
+		era->config = reg->config;
+		era->reg = reg->reg;
+
+		/* one more user */
+		atomic_inc(&era->ref);
+
+		/*
+		 * need to call x86_get_event_constraint()
+		 * to check if associated event has constraints
+		 */
+		c = NULL;
+	} else {
+		idx = intel_alt_er(idx, reg->config);
+		if (idx != reg->idx) {
+			raw_spin_unlock_irqrestore(&era->lock, flags);
+			goto again;
+		}
+	}
+	raw_spin_unlock_irqrestore(&era->lock, flags);
+
+	return c;
+}
+
+static void
+__intel_shared_reg_put_constraints(struct cpu_hw_events *cpuc,
+				   struct hw_perf_event_extra *reg)
+{
+	struct er_account *era;
+
+	/*
+	 * Only put constraint if extra reg was actually allocated. Also takes
+	 * care of event which do not use an extra shared reg.
+	 *
+	 * Also, if this is a fake cpuc we shouldn't touch any event state
+	 * (reg->alloc) and we don't care about leaving inconsistent cpuc state
+	 * either since it'll be thrown out.
+	 */
+	if (!reg->alloc || cpuc->is_fake)
+		return;
+
+	era = &cpuc->shared_regs->regs[reg->idx];
+
+	/* one fewer user */
+	atomic_dec(&era->ref);
+
+	/* allocate again next time */
+	reg->alloc = 0;
+}
+
+static struct event_constraint *
+intel_shared_regs_constraints(struct cpu_hw_events *cpuc,
+			      struct perf_event *event)
+{
+	struct event_constraint *c = NULL, *d;
+	struct hw_perf_event_extra *xreg, *breg;
+
+	xreg = &event->hw.extra_reg;
+	if (xreg->idx != EXTRA_REG_NONE) {
+		c = __intel_shared_reg_get_constraints(cpuc, event, xreg);
+		if (c == &emptyconstraint)
+			return c;
+	}
+	breg = &event->hw.branch_reg;
+	if (breg->idx != EXTRA_REG_NONE) {
+		d = __intel_shared_reg_get_constraints(cpuc, event, breg);
+		if (d == &emptyconstraint) {
+			__intel_shared_reg_put_constraints(cpuc, xreg);
+			c = d;
+		}
+	}
+	return c;
+}
+
+struct event_constraint *
+x86_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
+			  struct perf_event *event)
+{
+	struct event_constraint *c;
+
+	if (x86_pmu.event_constraints) {
+		for_each_event_constraint(c, x86_pmu.event_constraints) {
+			if ((event->hw.config & c->cmask) == c->code) {
+				event->hw.flags |= c->flags;
+				return c;
+			}
+		}
+	}
+
+	return &unconstrained;
+}
+
+static struct event_constraint *
+__intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
+			    struct perf_event *event)
+{
+	struct event_constraint *c;
+
+	c = intel_bts_constraints(event);
+	if (c)
+		return c;
+
+	c = intel_shared_regs_constraints(cpuc, event);
+	if (c)
+		return c;
+
+	c = intel_pebs_constraints(event);
+	if (c)
+		return c;
+
+	return x86_get_event_constraints(cpuc, idx, event);
+}
+
+static void
+intel_start_scheduling(struct cpu_hw_events *cpuc)
+{
+	struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
+	struct intel_excl_states *xl;
+	int tid = cpuc->excl_thread_id;
+
+	/*
+	 * nothing needed if in group validation mode
+	 */
+	if (cpuc->is_fake || !is_ht_workaround_enabled())
+		return;
+
+	/*
+	 * no exclusion needed
+	 */
+	if (WARN_ON_ONCE(!excl_cntrs))
+		return;
+
+	xl = &excl_cntrs->states[tid];
+
+	xl->sched_started = true;
+	/*
+	 * lock shared state until we are done scheduling
+	 * in stop_event_scheduling()
+	 * makes scheduling appear as a transaction
+	 */
+	raw_spin_lock(&excl_cntrs->lock);
+}
+
+static void intel_commit_scheduling(struct cpu_hw_events *cpuc, int idx, int cntr)
+{
+	struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
+	struct event_constraint *c = cpuc->event_constraint[idx];
+	struct intel_excl_states *xl;
+	int tid = cpuc->excl_thread_id;
+
+	if (cpuc->is_fake || !is_ht_workaround_enabled())
+		return;
+
+	if (WARN_ON_ONCE(!excl_cntrs))
+		return;
+
+	if (!(c->flags & PERF_X86_EVENT_DYNAMIC))
+		return;
+
+	xl = &excl_cntrs->states[tid];
+
+	lockdep_assert_held(&excl_cntrs->lock);
+
+	if (c->flags & PERF_X86_EVENT_EXCL)
+		xl->state[cntr] = INTEL_EXCL_EXCLUSIVE;
+	else
+		xl->state[cntr] = INTEL_EXCL_SHARED;
+}
+
+static void
+intel_stop_scheduling(struct cpu_hw_events *cpuc)
+{
+	struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
+	struct intel_excl_states *xl;
+	int tid = cpuc->excl_thread_id;
+
+	/*
+	 * nothing needed if in group validation mode
+	 */
+	if (cpuc->is_fake || !is_ht_workaround_enabled())
+		return;
+	/*
+	 * no exclusion needed
+	 */
+	if (WARN_ON_ONCE(!excl_cntrs))
+		return;
+
+	xl = &excl_cntrs->states[tid];
+
+	xl->sched_started = false;
+	/*
+	 * release shared state lock (acquired in intel_start_scheduling())
+	 */
+	raw_spin_unlock(&excl_cntrs->lock);
+}
+
+static struct event_constraint *
+intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
+			   int idx, struct event_constraint *c)
+{
+	struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
+	struct intel_excl_states *xlo;
+	int tid = cpuc->excl_thread_id;
+	int is_excl, i;
+
+	/*
+	 * validating a group does not require
+	 * enforcing cross-thread  exclusion
+	 */
+	if (cpuc->is_fake || !is_ht_workaround_enabled())
+		return c;
+
+	/*
+	 * no exclusion needed
+	 */
+	if (WARN_ON_ONCE(!excl_cntrs))
+		return c;
+
+	/*
+	 * because we modify the constraint, we need
+	 * to make a copy. Static constraints come
+	 * from static const tables.
+	 *
+	 * only needed when constraint has not yet
+	 * been cloned (marked dynamic)
+	 */
+	if (!(c->flags & PERF_X86_EVENT_DYNAMIC)) {
+		struct event_constraint *cx;
+
+		/*
+		 * grab pre-allocated constraint entry
+		 */
+		cx = &cpuc->constraint_list[idx];
+
+		/*
+		 * initialize dynamic constraint
+		 * with static constraint
+		 */
+		*cx = *c;
+
+		/*
+		 * mark constraint as dynamic, so we
+		 * can free it later on
+		 */
+		cx->flags |= PERF_X86_EVENT_DYNAMIC;
+		c = cx;
+	}
+
+	/*
+	 * From here on, the constraint is dynamic.
+	 * Either it was just allocated above, or it
+	 * was allocated during a earlier invocation
+	 * of this function
+	 */
+
+	/*
+	 * state of sibling HT
+	 */
+	xlo = &excl_cntrs->states[tid ^ 1];
+
+	/*
+	 * event requires exclusive counter access
+	 * across HT threads
+	 */
+	is_excl = c->flags & PERF_X86_EVENT_EXCL;
+	if (is_excl && !(event->hw.flags & PERF_X86_EVENT_EXCL_ACCT)) {
+		event->hw.flags |= PERF_X86_EVENT_EXCL_ACCT;
+		if (!cpuc->n_excl++)
+			WRITE_ONCE(excl_cntrs->has_exclusive[tid], 1);
+	}
+
+	/*
+	 * Modify static constraint with current dynamic
+	 * state of thread
+	 *
+	 * EXCLUSIVE: sibling counter measuring exclusive event
+	 * SHARED   : sibling counter measuring non-exclusive event
+	 * UNUSED   : sibling counter unused
+	 */
+	for_each_set_bit(i, c->idxmsk, X86_PMC_IDX_MAX) {
+		/*
+		 * exclusive event in sibling counter
+		 * our corresponding counter cannot be used
+		 * regardless of our event
+		 */
+		if (xlo->state[i] == INTEL_EXCL_EXCLUSIVE)
+			__clear_bit(i, c->idxmsk);
+		/*
+		 * if measuring an exclusive event, sibling
+		 * measuring non-exclusive, then counter cannot
+		 * be used
+		 */
+		if (is_excl && xlo->state[i] == INTEL_EXCL_SHARED)
+			__clear_bit(i, c->idxmsk);
+	}
+
+	/*
+	 * recompute actual bit weight for scheduling algorithm
+	 */
+	c->weight = hweight64(c->idxmsk64);
+
+	/*
+	 * if we return an empty mask, then switch
+	 * back to static empty constraint to avoid
+	 * the cost of freeing later on
+	 */
+	if (c->weight == 0)
+		c = &emptyconstraint;
+
+	return c;
+}
+
+static struct event_constraint *
+intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
+			    struct perf_event *event)
+{
+	struct event_constraint *c1 = NULL;
+	struct event_constraint *c2;
+
+	if (idx >= 0) /* fake does < 0 */
+		c1 = cpuc->event_constraint[idx];
+
+	/*
+	 * first time only
+	 * - static constraint: no change across incremental scheduling calls
+	 * - dynamic constraint: handled by intel_get_excl_constraints()
+	 */
+	c2 = __intel_get_event_constraints(cpuc, idx, event);
+	if (c1 && (c1->flags & PERF_X86_EVENT_DYNAMIC)) {
+		bitmap_copy(c1->idxmsk, c2->idxmsk, X86_PMC_IDX_MAX);
+		c1->weight = c2->weight;
+		c2 = c1;
+	}
+
+	if (cpuc->excl_cntrs)
+		return intel_get_excl_constraints(cpuc, event, idx, c2);
+
+	return c2;
+}
+
+static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
+		struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
+	int tid = cpuc->excl_thread_id;
+	struct intel_excl_states *xl;
+
+	/*
+	 * nothing needed if in group validation mode
+	 */
+	if (cpuc->is_fake)
+		return;
+
+	if (WARN_ON_ONCE(!excl_cntrs))
+		return;
+
+	if (hwc->flags & PERF_X86_EVENT_EXCL_ACCT) {
+		hwc->flags &= ~PERF_X86_EVENT_EXCL_ACCT;
+		if (!--cpuc->n_excl)
+			WRITE_ONCE(excl_cntrs->has_exclusive[tid], 0);
+	}
+
+	/*
+	 * If event was actually assigned, then mark the counter state as
+	 * unused now.
+	 */
+	if (hwc->idx >= 0) {
+		xl = &excl_cntrs->states[tid];
+
+		/*
+		 * put_constraint may be called from x86_schedule_events()
+		 * which already has the lock held so here make locking
+		 * conditional.
+		 */
+		if (!xl->sched_started)
+			raw_spin_lock(&excl_cntrs->lock);
+
+		xl->state[hwc->idx] = INTEL_EXCL_UNUSED;
+
+		if (!xl->sched_started)
+			raw_spin_unlock(&excl_cntrs->lock);
+	}
+}
+
+static void
+intel_put_shared_regs_event_constraints(struct cpu_hw_events *cpuc,
+					struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg;
+
+	reg = &event->hw.extra_reg;
+	if (reg->idx != EXTRA_REG_NONE)
+		__intel_shared_reg_put_constraints(cpuc, reg);
+
+	reg = &event->hw.branch_reg;
+	if (reg->idx != EXTRA_REG_NONE)
+		__intel_shared_reg_put_constraints(cpuc, reg);
+}
+
+static void intel_put_event_constraints(struct cpu_hw_events *cpuc,
+					struct perf_event *event)
+{
+	intel_put_shared_regs_event_constraints(cpuc, event);
+
+	/*
+	 * is PMU has exclusive counter restrictions, then
+	 * all events are subject to and must call the
+	 * put_excl_constraints() routine
+	 */
+	if (cpuc->excl_cntrs)
+		intel_put_excl_constraints(cpuc, event);
+}
+
+static void intel_pebs_aliases_core2(struct perf_event *event)
+{
+	if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) {
+		/*
+		 * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P
+		 * (0x003c) so that we can use it with PEBS.
+		 *
+		 * The regular CPU_CLK_UNHALTED.THREAD_P event (0x003c) isn't
+		 * PEBS capable. However we can use INST_RETIRED.ANY_P
+		 * (0x00c0), which is a PEBS capable event, to get the same
+		 * count.
+		 *
+		 * INST_RETIRED.ANY_P counts the number of cycles that retires
+		 * CNTMASK instructions. By setting CNTMASK to a value (16)
+		 * larger than the maximum number of instructions that can be
+		 * retired per cycle (4) and then inverting the condition, we
+		 * count all cycles that retire 16 or less instructions, which
+		 * is every cycle.
+		 *
+		 * Thereby we gain a PEBS capable cycle counter.
+		 */
+		u64 alt_config = X86_CONFIG(.event=0xc0, .inv=1, .cmask=16);
+
+		alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK);
+		event->hw.config = alt_config;
+	}
+}
+
+static void intel_pebs_aliases_snb(struct perf_event *event)
+{
+	if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) {
+		/*
+		 * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P
+		 * (0x003c) so that we can use it with PEBS.
+		 *
+		 * The regular CPU_CLK_UNHALTED.THREAD_P event (0x003c) isn't
+		 * PEBS capable. However we can use UOPS_RETIRED.ALL
+		 * (0x01c2), which is a PEBS capable event, to get the same
+		 * count.
+		 *
+		 * UOPS_RETIRED.ALL counts the number of cycles that retires
+		 * CNTMASK micro-ops. By setting CNTMASK to a value (16)
+		 * larger than the maximum number of micro-ops that can be
+		 * retired per cycle (4) and then inverting the condition, we
+		 * count all cycles that retire 16 or less micro-ops, which
+		 * is every cycle.
+		 *
+		 * Thereby we gain a PEBS capable cycle counter.
+		 */
+		u64 alt_config = X86_CONFIG(.event=0xc2, .umask=0x01, .inv=1, .cmask=16);
+
+		alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK);
+		event->hw.config = alt_config;
+	}
+}
+
+static unsigned long intel_pmu_free_running_flags(struct perf_event *event)
+{
+	unsigned long flags = x86_pmu.free_running_flags;
+
+	if (event->attr.use_clockid)
+		flags &= ~PERF_SAMPLE_TIME;
+	return flags;
+}
+
+static int intel_pmu_hw_config(struct perf_event *event)
+{
+	int ret = x86_pmu_hw_config(event);
+
+	if (ret)
+		return ret;
+
+	if (event->attr.precise_ip) {
+		if (!(event->attr.freq || (event->attr.wakeup_events && !event->attr.watermark))) {
+
+			event->hw.flags |= PERF_X86_EVENT_AUTO_RELOAD;
+			if (!(event->attr.sample_type &
+			      ~intel_pmu_free_running_flags(event)))
+				event->hw.flags |= PERF_X86_EVENT_FREERUNNING;
+		}
+		if (x86_pmu.pebs_aliases)
+			x86_pmu.pebs_aliases(event);
+	}
+
+	if (needs_branch_stack(event)) {
+		ret = intel_pmu_setup_lbr_filter(event);
+		if (ret)
+			return ret;
+
+		/*
+		 * BTS is set up earlier in this path, so don't account twice
+		 */
+		if (!intel_pmu_has_bts(event)) {
+			/* disallow lbr if conflicting events are present */
+			if (x86_add_exclusive(x86_lbr_exclusive_lbr))
+				return -EBUSY;
+
+			event->destroy = hw_perf_lbr_event_destroy;
+		}
+	}
+
+	if (event->attr.type != PERF_TYPE_RAW)
+		return 0;
+
+	if (!(event->attr.config & ARCH_PERFMON_EVENTSEL_ANY))
+		return 0;
+
+	if (x86_pmu.version < 3)
+		return -EINVAL;
+
+	if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	event->hw.config |= ARCH_PERFMON_EVENTSEL_ANY;
+
+	return 0;
+}
+
+struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr)
+{
+	if (x86_pmu.guest_get_msrs)
+		return x86_pmu.guest_get_msrs(nr);
+	*nr = 0;
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(perf_guest_get_msrs);
+
+static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct perf_guest_switch_msr *arr = cpuc->guest_switch_msrs;
+
+	arr[0].msr = MSR_CORE_PERF_GLOBAL_CTRL;
+	arr[0].host = x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask;
+	arr[0].guest = x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_host_mask;
+	/*
+	 * If PMU counter has PEBS enabled it is not enough to disable counter
+	 * on a guest entry since PEBS memory write can overshoot guest entry
+	 * and corrupt guest memory. Disabling PEBS solves the problem.
+	 */
+	arr[1].msr = MSR_IA32_PEBS_ENABLE;
+	arr[1].host = cpuc->pebs_enabled;
+	arr[1].guest = 0;
+
+	*nr = 2;
+	return arr;
+}
+
+static struct perf_guest_switch_msr *core_guest_get_msrs(int *nr)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct perf_guest_switch_msr *arr = cpuc->guest_switch_msrs;
+	int idx;
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++)  {
+		struct perf_event *event = cpuc->events[idx];
+
+		arr[idx].msr = x86_pmu_config_addr(idx);
+		arr[idx].host = arr[idx].guest = 0;
+
+		if (!test_bit(idx, cpuc->active_mask))
+			continue;
+
+		arr[idx].host = arr[idx].guest =
+			event->hw.config | ARCH_PERFMON_EVENTSEL_ENABLE;
+
+		if (event->attr.exclude_host)
+			arr[idx].host &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
+		else if (event->attr.exclude_guest)
+			arr[idx].guest &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
+	}
+
+	*nr = x86_pmu.num_counters;
+	return arr;
+}
+
+static void core_pmu_enable_event(struct perf_event *event)
+{
+	if (!event->attr.exclude_host)
+		x86_pmu_enable_event(event);
+}
+
+static void core_pmu_enable_all(int added)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	int idx;
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		struct hw_perf_event *hwc = &cpuc->events[idx]->hw;
+
+		if (!test_bit(idx, cpuc->active_mask) ||
+				cpuc->events[idx]->attr.exclude_host)
+			continue;
+
+		__x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
+	}
+}
+
+static int hsw_hw_config(struct perf_event *event)
+{
+	int ret = intel_pmu_hw_config(event);
+
+	if (ret)
+		return ret;
+	if (!boot_cpu_has(X86_FEATURE_RTM) && !boot_cpu_has(X86_FEATURE_HLE))
+		return 0;
+	event->hw.config |= event->attr.config & (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED);
+
+	/*
+	 * IN_TX/IN_TX-CP filters are not supported by the Haswell PMU with
+	 * PEBS or in ANY thread mode. Since the results are non-sensical forbid
+	 * this combination.
+	 */
+	if ((event->hw.config & (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED)) &&
+	     ((event->hw.config & ARCH_PERFMON_EVENTSEL_ANY) ||
+	      event->attr.precise_ip > 0))
+		return -EOPNOTSUPP;
+
+	if (event_is_checkpointed(event)) {
+		/*
+		 * Sampling of checkpointed events can cause situations where
+		 * the CPU constantly aborts because of a overflow, which is
+		 * then checkpointed back and ignored. Forbid checkpointing
+		 * for sampling.
+		 *
+		 * But still allow a long sampling period, so that perf stat
+		 * from KVM works.
+		 */
+		if (event->attr.sample_period > 0 &&
+		    event->attr.sample_period < 0x7fffffff)
+			return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static struct event_constraint counter2_constraint =
+			EVENT_CONSTRAINT(0, 0x4, 0);
+
+static struct event_constraint *
+hsw_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
+			  struct perf_event *event)
+{
+	struct event_constraint *c;
+
+	c = intel_get_event_constraints(cpuc, idx, event);
+
+	/* Handle special quirk on in_tx_checkpointed only in counter 2 */
+	if (event->hw.config & HSW_IN_TX_CHECKPOINTED) {
+		if (c->idxmsk64 & (1U << 2))
+			return &counter2_constraint;
+		return &emptyconstraint;
+	}
+
+	return c;
+}
+
+/*
+ * Broadwell:
+ *
+ * The INST_RETIRED.ALL period always needs to have lowest 6 bits cleared
+ * (BDM55) and it must not use a period smaller than 100 (BDM11). We combine
+ * the two to enforce a minimum period of 128 (the smallest value that has bits
+ * 0-5 cleared and >= 100).
+ *
+ * Because of how the code in x86_perf_event_set_period() works, the truncation
+ * of the lower 6 bits is 'harmless' as we'll occasionally add a longer period
+ * to make up for the 'lost' events due to carrying the 'error' in period_left.
+ *
+ * Therefore the effective (average) period matches the requested period,
+ * despite coarser hardware granularity.
+ */
+static unsigned bdw_limit_period(struct perf_event *event, unsigned left)
+{
+	if ((event->hw.config & INTEL_ARCH_EVENT_MASK) ==
+			X86_CONFIG(.event=0xc0, .umask=0x01)) {
+		if (left < 128)
+			left = 128;
+		left &= ~0x3fULL;
+	}
+	return left;
+}
+
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(pc,	"config:19"	);
+PMU_FORMAT_ATTR(any,	"config:21"	); /* v3 + */
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+PMU_FORMAT_ATTR(in_tx,  "config:32");
+PMU_FORMAT_ATTR(in_tx_cp, "config:33");
+
+static struct attribute *intel_arch_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
+ssize_t intel_event_sysfs_show(char *page, u64 config)
+{
+	u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT);
+
+	return x86_event_sysfs_show(page, config, event);
+}
+
+struct intel_shared_regs *allocate_shared_regs(int cpu)
+{
+	struct intel_shared_regs *regs;
+	int i;
+
+	regs = kzalloc_node(sizeof(struct intel_shared_regs),
+			    GFP_KERNEL, cpu_to_node(cpu));
+	if (regs) {
+		/*
+		 * initialize the locks to keep lockdep happy
+		 */
+		for (i = 0; i < EXTRA_REG_MAX; i++)
+			raw_spin_lock_init(&regs->regs[i].lock);
+
+		regs->core_id = -1;
+	}
+	return regs;
+}
+
+static struct intel_excl_cntrs *allocate_excl_cntrs(int cpu)
+{
+	struct intel_excl_cntrs *c;
+
+	c = kzalloc_node(sizeof(struct intel_excl_cntrs),
+			 GFP_KERNEL, cpu_to_node(cpu));
+	if (c) {
+		raw_spin_lock_init(&c->lock);
+		c->core_id = -1;
+	}
+	return c;
+}
+
+static int intel_pmu_cpu_prepare(int cpu)
+{
+	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+
+	if (x86_pmu.extra_regs || x86_pmu.lbr_sel_map) {
+		cpuc->shared_regs = allocate_shared_regs(cpu);
+		if (!cpuc->shared_regs)
+			goto err;
+	}
+
+	if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
+		size_t sz = X86_PMC_IDX_MAX * sizeof(struct event_constraint);
+
+		cpuc->constraint_list = kzalloc(sz, GFP_KERNEL);
+		if (!cpuc->constraint_list)
+			goto err_shared_regs;
+
+		cpuc->excl_cntrs = allocate_excl_cntrs(cpu);
+		if (!cpuc->excl_cntrs)
+			goto err_constraint_list;
+
+		cpuc->excl_thread_id = 0;
+	}
+
+	return NOTIFY_OK;
+
+err_constraint_list:
+	kfree(cpuc->constraint_list);
+	cpuc->constraint_list = NULL;
+
+err_shared_regs:
+	kfree(cpuc->shared_regs);
+	cpuc->shared_regs = NULL;
+
+err:
+	return NOTIFY_BAD;
+}
+
+static void intel_pmu_cpu_starting(int cpu)
+{
+	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+	int core_id = topology_core_id(cpu);
+	int i;
+
+	init_debug_store_on_cpu(cpu);
+	/*
+	 * Deal with CPUs that don't clear their LBRs on power-up.
+	 */
+	intel_pmu_lbr_reset();
+
+	cpuc->lbr_sel = NULL;
+
+	if (!cpuc->shared_regs)
+		return;
+
+	if (!(x86_pmu.flags & PMU_FL_NO_HT_SHARING)) {
+		void **onln = &cpuc->kfree_on_online[X86_PERF_KFREE_SHARED];
+
+		for_each_cpu(i, topology_sibling_cpumask(cpu)) {
+			struct intel_shared_regs *pc;
+
+			pc = per_cpu(cpu_hw_events, i).shared_regs;
+			if (pc && pc->core_id == core_id) {
+				*onln = cpuc->shared_regs;
+				cpuc->shared_regs = pc;
+				break;
+			}
+		}
+		cpuc->shared_regs->core_id = core_id;
+		cpuc->shared_regs->refcnt++;
+	}
+
+	if (x86_pmu.lbr_sel_map)
+		cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR];
+
+	if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
+		for_each_cpu(i, topology_sibling_cpumask(cpu)) {
+			struct intel_excl_cntrs *c;
+
+			c = per_cpu(cpu_hw_events, i).excl_cntrs;
+			if (c && c->core_id == core_id) {
+				cpuc->kfree_on_online[1] = cpuc->excl_cntrs;
+				cpuc->excl_cntrs = c;
+				cpuc->excl_thread_id = 1;
+				break;
+			}
+		}
+		cpuc->excl_cntrs->core_id = core_id;
+		cpuc->excl_cntrs->refcnt++;
+	}
+}
+
+static void free_excl_cntrs(int cpu)
+{
+	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+	struct intel_excl_cntrs *c;
+
+	c = cpuc->excl_cntrs;
+	if (c) {
+		if (c->core_id == -1 || --c->refcnt == 0)
+			kfree(c);
+		cpuc->excl_cntrs = NULL;
+		kfree(cpuc->constraint_list);
+		cpuc->constraint_list = NULL;
+	}
+}
+
+static void intel_pmu_cpu_dying(int cpu)
+{
+	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+	struct intel_shared_regs *pc;
+
+	pc = cpuc->shared_regs;
+	if (pc) {
+		if (pc->core_id == -1 || --pc->refcnt == 0)
+			kfree(pc);
+		cpuc->shared_regs = NULL;
+	}
+
+	free_excl_cntrs(cpu);
+
+	fini_debug_store_on_cpu(cpu);
+}
+
+static void intel_pmu_sched_task(struct perf_event_context *ctx,
+				 bool sched_in)
+{
+	if (x86_pmu.pebs_active)
+		intel_pmu_pebs_sched_task(ctx, sched_in);
+	if (x86_pmu.lbr_nr)
+		intel_pmu_lbr_sched_task(ctx, sched_in);
+}
+
+PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
+
+PMU_FORMAT_ATTR(ldlat, "config1:0-15");
+
+PMU_FORMAT_ATTR(frontend, "config1:0-23");
+
+static struct attribute *intel_arch3_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_any.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	&format_attr_in_tx.attr,
+	&format_attr_in_tx_cp.attr,
+
+	&format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */
+	&format_attr_ldlat.attr, /* PEBS load latency */
+	NULL,
+};
+
+static struct attribute *skl_format_attr[] = {
+	&format_attr_frontend.attr,
+	NULL,
+};
+
+static __initconst const struct x86_pmu core_pmu = {
+	.name			= "core",
+	.handle_irq		= x86_pmu_handle_irq,
+	.disable_all		= x86_pmu_disable_all,
+	.enable_all		= core_pmu_enable_all,
+	.enable			= core_pmu_enable_event,
+	.disable		= x86_pmu_disable_event,
+	.hw_config		= x86_pmu_hw_config,
+	.schedule_events	= x86_schedule_events,
+	.eventsel		= MSR_ARCH_PERFMON_EVENTSEL0,
+	.perfctr		= MSR_ARCH_PERFMON_PERFCTR0,
+	.event_map		= intel_pmu_event_map,
+	.max_events		= ARRAY_SIZE(intel_perfmon_event_map),
+	.apic			= 1,
+	.free_running_flags	= PEBS_FREERUNNING_FLAGS,
+
+	/*
+	 * Intel PMCs cannot be accessed sanely above 32-bit width,
+	 * so we install an artificial 1<<31 period regardless of
+	 * the generic event period:
+	 */
+	.max_period		= (1ULL<<31) - 1,
+	.get_event_constraints	= intel_get_event_constraints,
+	.put_event_constraints	= intel_put_event_constraints,
+	.event_constraints	= intel_core_event_constraints,
+	.guest_get_msrs		= core_guest_get_msrs,
+	.format_attrs		= intel_arch_formats_attr,
+	.events_sysfs_show	= intel_event_sysfs_show,
+
+	/*
+	 * Virtual (or funny metal) CPU can define x86_pmu.extra_regs
+	 * together with PMU version 1 and thus be using core_pmu with
+	 * shared_regs. We need following callbacks here to allocate
+	 * it properly.
+	 */
+	.cpu_prepare		= intel_pmu_cpu_prepare,
+	.cpu_starting		= intel_pmu_cpu_starting,
+	.cpu_dying		= intel_pmu_cpu_dying,
+};
+
+static __initconst const struct x86_pmu intel_pmu = {
+	.name			= "Intel",
+	.handle_irq		= intel_pmu_handle_irq,
+	.disable_all		= intel_pmu_disable_all,
+	.enable_all		= intel_pmu_enable_all,
+	.enable			= intel_pmu_enable_event,
+	.disable		= intel_pmu_disable_event,
+	.hw_config		= intel_pmu_hw_config,
+	.schedule_events	= x86_schedule_events,
+	.eventsel		= MSR_ARCH_PERFMON_EVENTSEL0,
+	.perfctr		= MSR_ARCH_PERFMON_PERFCTR0,
+	.event_map		= intel_pmu_event_map,
+	.max_events		= ARRAY_SIZE(intel_perfmon_event_map),
+	.apic			= 1,
+	.free_running_flags	= PEBS_FREERUNNING_FLAGS,
+	/*
+	 * Intel PMCs cannot be accessed sanely above 32 bit width,
+	 * so we install an artificial 1<<31 period regardless of
+	 * the generic event period:
+	 */
+	.max_period		= (1ULL << 31) - 1,
+	.get_event_constraints	= intel_get_event_constraints,
+	.put_event_constraints	= intel_put_event_constraints,
+	.pebs_aliases		= intel_pebs_aliases_core2,
+
+	.format_attrs		= intel_arch3_formats_attr,
+	.events_sysfs_show	= intel_event_sysfs_show,
+
+	.cpu_prepare		= intel_pmu_cpu_prepare,
+	.cpu_starting		= intel_pmu_cpu_starting,
+	.cpu_dying		= intel_pmu_cpu_dying,
+	.guest_get_msrs		= intel_guest_get_msrs,
+	.sched_task		= intel_pmu_sched_task,
+};
+
+static __init void intel_clovertown_quirk(void)
+{
+	/*
+	 * PEBS is unreliable due to:
+	 *
+	 *   AJ67  - PEBS may experience CPL leaks
+	 *   AJ68  - PEBS PMI may be delayed by one event
+	 *   AJ69  - GLOBAL_STATUS[62] will only be set when DEBUGCTL[12]
+	 *   AJ106 - FREEZE_LBRS_ON_PMI doesn't work in combination with PEBS
+	 *
+	 * AJ67 could be worked around by restricting the OS/USR flags.
+	 * AJ69 could be worked around by setting PMU_FREEZE_ON_PMI.
+	 *
+	 * AJ106 could possibly be worked around by not allowing LBR
+	 *       usage from PEBS, including the fixup.
+	 * AJ68  could possibly be worked around by always programming
+	 *	 a pebs_event_reset[0] value and coping with the lost events.
+	 *
+	 * But taken together it might just make sense to not enable PEBS on
+	 * these chips.
+	 */
+	pr_warn("PEBS disabled due to CPU errata\n");
+	x86_pmu.pebs = 0;
+	x86_pmu.pebs_constraints = NULL;
+}
+
+static int intel_snb_pebs_broken(int cpu)
+{
+	u32 rev = UINT_MAX; /* default to broken for unknown models */
+
+	switch (cpu_data(cpu).x86_model) {
+	case INTEL_FAM6_SANDYBRIDGE:
+		rev = 0x28;
+		break;
+
+	case INTEL_FAM6_SANDYBRIDGE_X:
+		switch (cpu_data(cpu).x86_stepping) {
+		case 6: rev = 0x618; break;
+		case 7: rev = 0x70c; break;
+		}
+	}
+
+	return (cpu_data(cpu).microcode < rev);
+}
+
+static void intel_snb_check_microcode(void)
+{
+	int pebs_broken = 0;
+	int cpu;
+
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		if ((pebs_broken = intel_snb_pebs_broken(cpu)))
+			break;
+	}
+	put_online_cpus();
+
+	if (pebs_broken == x86_pmu.pebs_broken)
+		return;
+
+	/*
+	 * Serialized by the microcode lock..
+	 */
+	if (x86_pmu.pebs_broken) {
+		pr_info("PEBS enabled due to microcode update\n");
+		x86_pmu.pebs_broken = 0;
+	} else {
+		pr_info("PEBS disabled due to CPU errata, please upgrade microcode\n");
+		x86_pmu.pebs_broken = 1;
+	}
+}
+
+/*
+ * Under certain circumstances, access certain MSR may cause #GP.
+ * The function tests if the input MSR can be safely accessed.
+ */
+static bool check_msr(unsigned long msr, u64 mask)
+{
+	u64 val_old, val_new, val_tmp;
+
+	/*
+	 * Read the current value, change it and read it back to see if it
+	 * matches, this is needed to detect certain hardware emulators
+	 * (qemu/kvm) that don't trap on the MSR access and always return 0s.
+	 */
+	if (rdmsrl_safe(msr, &val_old))
+		return false;
+
+	/*
+	 * Only change the bits which can be updated by wrmsrl.
+	 */
+	val_tmp = val_old ^ mask;
+	if (wrmsrl_safe(msr, val_tmp) ||
+	    rdmsrl_safe(msr, &val_new))
+		return false;
+
+	if (val_new != val_tmp)
+		return false;
+
+	/* Here it's sure that the MSR can be safely accessed.
+	 * Restore the old value and return.
+	 */
+	wrmsrl(msr, val_old);
+
+	return true;
+}
+
+static __init void intel_sandybridge_quirk(void)
+{
+	x86_pmu.check_microcode = intel_snb_check_microcode;
+	intel_snb_check_microcode();
+}
+
+static const struct { int id; char *name; } intel_arch_events_map[] __initconst = {
+	{ PERF_COUNT_HW_CPU_CYCLES, "cpu cycles" },
+	{ PERF_COUNT_HW_INSTRUCTIONS, "instructions" },
+	{ PERF_COUNT_HW_BUS_CYCLES, "bus cycles" },
+	{ PERF_COUNT_HW_CACHE_REFERENCES, "cache references" },
+	{ PERF_COUNT_HW_CACHE_MISSES, "cache misses" },
+	{ PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branch instructions" },
+	{ PERF_COUNT_HW_BRANCH_MISSES, "branch misses" },
+};
+
+static __init void intel_arch_events_quirk(void)
+{
+	int bit;
+
+	/* 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;
+		pr_warn("CPUID marked event: \'%s\' unavailable\n",
+			intel_arch_events_map[bit].name);
+	}
+}
+
+static __init void intel_nehalem_quirk(void)
+{
+	union cpuid10_ebx ebx;
+
+	ebx.full = x86_pmu.events_maskl;
+	if (ebx.split.no_branch_misses_retired) {
+		/*
+		 * Erratum AAJ80 detected, we work it around by using
+		 * the BR_MISP_EXEC.ANY event. This will over-count
+		 * branch-misses, but it's still much better than the
+		 * architectural event which is often completely bogus:
+		 */
+		intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89;
+		ebx.split.no_branch_misses_retired = 0;
+		x86_pmu.events_maskl = ebx.full;
+		pr_info("CPU erratum AAJ80 worked around\n");
+	}
+}
+
+/*
+ * enable software workaround for errata:
+ * SNB: BJ122
+ * IVB: BV98
+ * HSW: HSD29
+ *
+ * Only needed when HT is enabled. However detecting
+ * if HT is enabled is difficult (model specific). So instead,
+ * we enable the workaround in the early boot, and verify if
+ * it is needed in a later initcall phase once we have valid
+ * topology information to check if HT is actually enabled
+ */
+static __init void intel_ht_bug(void)
+{
+	x86_pmu.flags |= PMU_FL_EXCL_CNTRS | PMU_FL_EXCL_ENABLED;
+
+	x86_pmu.start_scheduling = intel_start_scheduling;
+	x86_pmu.commit_scheduling = intel_commit_scheduling;
+	x86_pmu.stop_scheduling = intel_stop_scheduling;
+}
+
+EVENT_ATTR_STR(mem-loads,	mem_ld_hsw,	"event=0xcd,umask=0x1,ldlat=3");
+EVENT_ATTR_STR(mem-stores,	mem_st_hsw,	"event=0xd0,umask=0x82")
+
+/* Haswell special events */
+EVENT_ATTR_STR(tx-start,	tx_start,	"event=0xc9,umask=0x1");
+EVENT_ATTR_STR(tx-commit,	tx_commit,	"event=0xc9,umask=0x2");
+EVENT_ATTR_STR(tx-abort,	tx_abort,	"event=0xc9,umask=0x4");
+EVENT_ATTR_STR(tx-capacity,	tx_capacity,	"event=0x54,umask=0x2");
+EVENT_ATTR_STR(tx-conflict,	tx_conflict,	"event=0x54,umask=0x1");
+EVENT_ATTR_STR(el-start,	el_start,	"event=0xc8,umask=0x1");
+EVENT_ATTR_STR(el-commit,	el_commit,	"event=0xc8,umask=0x2");
+EVENT_ATTR_STR(el-abort,	el_abort,	"event=0xc8,umask=0x4");
+EVENT_ATTR_STR(el-capacity,	el_capacity,	"event=0x54,umask=0x2");
+EVENT_ATTR_STR(el-conflict,	el_conflict,	"event=0x54,umask=0x1");
+EVENT_ATTR_STR(cycles-t,	cycles_t,	"event=0x3c,in_tx=1");
+EVENT_ATTR_STR(cycles-ct,	cycles_ct,	"event=0x3c,in_tx=1,in_tx_cp=1");
+
+static struct attribute *hsw_events_attrs[] = {
+	EVENT_PTR(tx_start),
+	EVENT_PTR(tx_commit),
+	EVENT_PTR(tx_abort),
+	EVENT_PTR(tx_capacity),
+	EVENT_PTR(tx_conflict),
+	EVENT_PTR(el_start),
+	EVENT_PTR(el_commit),
+	EVENT_PTR(el_abort),
+	EVENT_PTR(el_capacity),
+	EVENT_PTR(el_conflict),
+	EVENT_PTR(cycles_t),
+	EVENT_PTR(cycles_ct),
+	EVENT_PTR(mem_ld_hsw),
+	EVENT_PTR(mem_st_hsw),
+	NULL
+};
+
+__init int intel_pmu_init(void)
+{
+	union cpuid10_edx edx;
+	union cpuid10_eax eax;
+	union cpuid10_ebx ebx;
+	struct event_constraint *c;
+	unsigned int unused;
+	struct extra_reg *er;
+	int version, i;
+
+	if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+		switch (boot_cpu_data.x86) {
+		case 0x6:
+			return p6_pmu_init();
+		case 0xb:
+			return knc_pmu_init();
+		case 0xf:
+			return p4_pmu_init();
+		}
+		return -ENODEV;
+	}
+
+	/*
+	 * Check whether the Architectural PerfMon supports
+	 * Branch Misses Retired hw_event or not.
+	 */
+	cpuid(10, &eax.full, &ebx.full, &unused, &edx.full);
+	if (eax.split.mask_length < ARCH_PERFMON_EVENTS_COUNT)
+		return -ENODEV;
+
+	version = eax.split.version_id;
+	if (version < 2)
+		x86_pmu = core_pmu;
+	else
+		x86_pmu = intel_pmu;
+
+	x86_pmu.version			= version;
+	x86_pmu.num_counters		= eax.split.num_counters;
+	x86_pmu.cntval_bits		= eax.split.bit_width;
+	x86_pmu.cntval_mask		= (1ULL << eax.split.bit_width) - 1;
+
+	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:
+	 */
+	if (version > 1)
+		x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3);
+
+	if (boot_cpu_has(X86_FEATURE_PDCM)) {
+		u64 capabilities;
+
+		rdmsrl(MSR_IA32_PERF_CAPABILITIES, capabilities);
+		x86_pmu.intel_cap.capabilities = capabilities;
+	}
+
+	intel_ds_init();
+
+	x86_add_quirk(intel_arch_events_quirk); /* Install first, so it runs last */
+
+	/*
+	 * Install the hw-cache-events table:
+	 */
+	switch (boot_cpu_data.x86_model) {
+	case INTEL_FAM6_CORE_YONAH:
+		pr_cont("Core events, ");
+		break;
+
+	case INTEL_FAM6_CORE2_MEROM:
+		x86_add_quirk(intel_clovertown_quirk);
+	case INTEL_FAM6_CORE2_MEROM_L:
+	case INTEL_FAM6_CORE2_PENRYN:
+	case INTEL_FAM6_CORE2_DUNNINGTON:
+		memcpy(hw_cache_event_ids, core2_hw_cache_event_ids,
+		       sizeof(hw_cache_event_ids));
+
+		intel_pmu_lbr_init_core();
+
+		x86_pmu.event_constraints = intel_core2_event_constraints;
+		x86_pmu.pebs_constraints = intel_core2_pebs_event_constraints;
+		pr_cont("Core2 events, ");
+		break;
+
+	case INTEL_FAM6_NEHALEM:
+	case INTEL_FAM6_NEHALEM_EP:
+	case INTEL_FAM6_NEHALEM_EX:
+		memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
+		       sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
+		       sizeof(hw_cache_extra_regs));
+
+		intel_pmu_lbr_init_nhm();
+
+		x86_pmu.event_constraints = intel_nehalem_event_constraints;
+		x86_pmu.pebs_constraints = intel_nehalem_pebs_event_constraints;
+		x86_pmu.enable_all = intel_pmu_nhm_enable_all;
+		x86_pmu.extra_regs = intel_nehalem_extra_regs;
+
+		x86_pmu.cpu_events = nhm_events_attrs;
+
+		/* UOPS_ISSUED.STALLED_CYCLES */
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+			X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
+		/* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
+			X86_CONFIG(.event=0xb1, .umask=0x3f, .inv=1, .cmask=1);
+
+		intel_pmu_pebs_data_source_nhm();
+		x86_add_quirk(intel_nehalem_quirk);
+
+		pr_cont("Nehalem events, ");
+		break;
+
+	case INTEL_FAM6_ATOM_BONNELL:
+	case INTEL_FAM6_ATOM_BONNELL_MID:
+	case INTEL_FAM6_ATOM_SALTWELL:
+	case INTEL_FAM6_ATOM_SALTWELL_MID:
+	case INTEL_FAM6_ATOM_SALTWELL_TABLET:
+		memcpy(hw_cache_event_ids, atom_hw_cache_event_ids,
+		       sizeof(hw_cache_event_ids));
+
+		intel_pmu_lbr_init_atom();
+
+		x86_pmu.event_constraints = intel_gen_event_constraints;
+		x86_pmu.pebs_constraints = intel_atom_pebs_event_constraints;
+		pr_cont("Atom events, ");
+		break;
+
+	case INTEL_FAM6_ATOM_SILVERMONT:
+	case INTEL_FAM6_ATOM_SILVERMONT_X:
+	case INTEL_FAM6_ATOM_SILVERMONT_MID:
+	case INTEL_FAM6_ATOM_AIRMONT:
+	case INTEL_FAM6_ATOM_AIRMONT_MID:
+		memcpy(hw_cache_event_ids, slm_hw_cache_event_ids,
+			sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs,
+		       sizeof(hw_cache_extra_regs));
+
+		intel_pmu_lbr_init_atom();
+
+		x86_pmu.event_constraints = intel_slm_event_constraints;
+		x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints;
+		x86_pmu.extra_regs = intel_slm_extra_regs;
+		x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+		pr_cont("Silvermont events, ");
+		break;
+
+	case INTEL_FAM6_WESTMERE:
+	case INTEL_FAM6_WESTMERE_EP:
+	case INTEL_FAM6_WESTMERE_EX:
+		memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids,
+		       sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
+		       sizeof(hw_cache_extra_regs));
+
+		intel_pmu_lbr_init_nhm();
+
+		x86_pmu.event_constraints = intel_westmere_event_constraints;
+		x86_pmu.enable_all = intel_pmu_nhm_enable_all;
+		x86_pmu.pebs_constraints = intel_westmere_pebs_event_constraints;
+		x86_pmu.extra_regs = intel_westmere_extra_regs;
+		x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+
+		x86_pmu.cpu_events = nhm_events_attrs;
+
+		/* UOPS_ISSUED.STALLED_CYCLES */
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+			X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
+		/* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
+			X86_CONFIG(.event=0xb1, .umask=0x3f, .inv=1, .cmask=1);
+
+		intel_pmu_pebs_data_source_nhm();
+		pr_cont("Westmere events, ");
+		break;
+
+	case INTEL_FAM6_SANDYBRIDGE:
+	case INTEL_FAM6_SANDYBRIDGE_X:
+		x86_add_quirk(intel_sandybridge_quirk);
+		x86_add_quirk(intel_ht_bug);
+		memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
+		       sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
+		       sizeof(hw_cache_extra_regs));
+
+		intel_pmu_lbr_init_snb();
+
+		x86_pmu.event_constraints = intel_snb_event_constraints;
+		x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints;
+		x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+		if (boot_cpu_data.x86_model == INTEL_FAM6_SANDYBRIDGE_X)
+			x86_pmu.extra_regs = intel_snbep_extra_regs;
+		else
+			x86_pmu.extra_regs = intel_snb_extra_regs;
+
+
+		/* all extra regs are per-cpu when HT is on */
+		x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+		x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
+
+		x86_pmu.cpu_events = snb_events_attrs;
+
+		/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+			X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
+		/* UOPS_DISPATCHED.THREAD,c=1,i=1 to count stall cycles*/
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
+			X86_CONFIG(.event=0xb1, .umask=0x01, .inv=1, .cmask=1);
+
+		pr_cont("SandyBridge events, ");
+		break;
+
+	case INTEL_FAM6_IVYBRIDGE:
+	case INTEL_FAM6_IVYBRIDGE_X:
+		x86_add_quirk(intel_ht_bug);
+		memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
+		       sizeof(hw_cache_event_ids));
+		/* dTLB-load-misses on IVB is different than SNB */
+		hw_cache_event_ids[C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = 0x8108; /* DTLB_LOAD_MISSES.DEMAND_LD_MISS_CAUSES_A_WALK */
+
+		memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
+		       sizeof(hw_cache_extra_regs));
+
+		intel_pmu_lbr_init_snb();
+
+		x86_pmu.event_constraints = intel_ivb_event_constraints;
+		x86_pmu.pebs_constraints = intel_ivb_pebs_event_constraints;
+		x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+		if (boot_cpu_data.x86_model == INTEL_FAM6_IVYBRIDGE_X)
+			x86_pmu.extra_regs = intel_snbep_extra_regs;
+		else
+			x86_pmu.extra_regs = intel_snb_extra_regs;
+		/* all extra regs are per-cpu when HT is on */
+		x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+		x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
+
+		x86_pmu.cpu_events = snb_events_attrs;
+
+		/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+			X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
+
+		pr_cont("IvyBridge events, ");
+		break;
+
+
+	case INTEL_FAM6_HASWELL_CORE:
+	case INTEL_FAM6_HASWELL_X:
+	case INTEL_FAM6_HASWELL_ULT:
+	case INTEL_FAM6_HASWELL_GT3E:
+		x86_add_quirk(intel_ht_bug);
+		x86_pmu.late_ack = true;
+		memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+
+		intel_pmu_lbr_init_hsw();
+
+		x86_pmu.event_constraints = intel_hsw_event_constraints;
+		x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
+		x86_pmu.extra_regs = intel_snbep_extra_regs;
+		x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+		/* all extra regs are per-cpu when HT is on */
+		x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+		x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
+
+		x86_pmu.hw_config = hsw_hw_config;
+		x86_pmu.get_event_constraints = hsw_get_event_constraints;
+		x86_pmu.cpu_events = hsw_events_attrs;
+		x86_pmu.lbr_double_abort = true;
+		pr_cont("Haswell events, ");
+		break;
+
+	case INTEL_FAM6_BROADWELL_CORE:
+	case INTEL_FAM6_BROADWELL_XEON_D:
+	case INTEL_FAM6_BROADWELL_GT3E:
+	case INTEL_FAM6_BROADWELL_X:
+		x86_pmu.late_ack = true;
+		memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+
+		/* L3_MISS_LOCAL_DRAM is BIT(26) in Broadwell */
+		hw_cache_extra_regs[C(LL)][C(OP_READ)][C(RESULT_MISS)] = HSW_DEMAND_READ |
+									 BDW_L3_MISS|HSW_SNOOP_DRAM;
+		hw_cache_extra_regs[C(LL)][C(OP_WRITE)][C(RESULT_MISS)] = HSW_DEMAND_WRITE|BDW_L3_MISS|
+									  HSW_SNOOP_DRAM;
+		hw_cache_extra_regs[C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = HSW_DEMAND_READ|
+									     BDW_L3_MISS_LOCAL|HSW_SNOOP_DRAM;
+		hw_cache_extra_regs[C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = HSW_DEMAND_WRITE|
+									      BDW_L3_MISS_LOCAL|HSW_SNOOP_DRAM;
+
+		intel_pmu_lbr_init_hsw();
+
+		x86_pmu.event_constraints = intel_bdw_event_constraints;
+		x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
+		x86_pmu.extra_regs = intel_snbep_extra_regs;
+		x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+		/* all extra regs are per-cpu when HT is on */
+		x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+		x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
+
+		x86_pmu.hw_config = hsw_hw_config;
+		x86_pmu.get_event_constraints = hsw_get_event_constraints;
+		x86_pmu.cpu_events = hsw_events_attrs;
+		x86_pmu.limit_period = bdw_limit_period;
+		pr_cont("Broadwell events, ");
+		break;
+
+	case INTEL_FAM6_XEON_PHI_KNL:
+		memcpy(hw_cache_event_ids,
+		       slm_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs,
+		       knl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+		intel_pmu_lbr_init_knl();
+
+		x86_pmu.event_constraints = intel_slm_event_constraints;
+		x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints;
+		x86_pmu.extra_regs = intel_knl_extra_regs;
+
+		/* all extra regs are per-cpu when HT is on */
+		x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+		x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
+
+		pr_cont("Knights Landing events, ");
+		break;
+
+	case INTEL_FAM6_SKYLAKE_MOBILE:
+	case INTEL_FAM6_SKYLAKE_DESKTOP:
+	case INTEL_FAM6_SKYLAKE_X:
+	case INTEL_FAM6_KABYLAKE_MOBILE:
+	case INTEL_FAM6_KABYLAKE_DESKTOP:
+		x86_pmu.late_ack = true;
+		memcpy(hw_cache_event_ids, skl_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, skl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+		intel_pmu_lbr_init_skl();
+
+		x86_pmu.event_constraints = intel_skl_event_constraints;
+		x86_pmu.pebs_constraints = intel_skl_pebs_event_constraints;
+		x86_pmu.extra_regs = intel_skl_extra_regs;
+		x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+		/* all extra regs are per-cpu when HT is on */
+		x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+		x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
+
+		x86_pmu.hw_config = hsw_hw_config;
+		x86_pmu.get_event_constraints = hsw_get_event_constraints;
+		x86_pmu.format_attrs = merge_attr(intel_arch3_formats_attr,
+						  skl_format_attr);
+		WARN_ON(!x86_pmu.format_attrs);
+		x86_pmu.cpu_events = hsw_events_attrs;
+		pr_cont("Skylake events, ");
+		break;
+
+	default:
+		switch (x86_pmu.version) {
+		case 1:
+			x86_pmu.event_constraints = intel_v1_event_constraints;
+			pr_cont("generic architected perfmon v1, ");
+			break;
+		default:
+			/*
+			 * default constraints for v2 and up
+			 */
+			x86_pmu.event_constraints = intel_gen_event_constraints;
+			pr_cont("generic architected perfmon, ");
+			break;
+		}
+	}
+
+	if (x86_pmu.num_counters > INTEL_PMC_MAX_GENERIC) {
+		WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!",
+		     x86_pmu.num_counters, INTEL_PMC_MAX_GENERIC);
+		x86_pmu.num_counters = INTEL_PMC_MAX_GENERIC;
+	}
+	x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
+
+	if (x86_pmu.num_counters_fixed > INTEL_PMC_MAX_FIXED) {
+		WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!",
+		     x86_pmu.num_counters_fixed, INTEL_PMC_MAX_FIXED);
+		x86_pmu.num_counters_fixed = INTEL_PMC_MAX_FIXED;
+	}
+
+	x86_pmu.intel_ctrl |=
+		((1LL << x86_pmu.num_counters_fixed)-1) << INTEL_PMC_IDX_FIXED;
+
+	if (x86_pmu.event_constraints) {
+		/*
+		 * event on fixed counter2 (REF_CYCLES) only works on this
+		 * counter, so do not extend mask to generic counters
+		 */
+		for_each_event_constraint(c, x86_pmu.event_constraints) {
+			if (c->cmask == FIXED_EVENT_FLAGS
+			    && c->idxmsk64 != INTEL_PMC_MSK_FIXED_REF_CYCLES) {
+				c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1;
+			}
+			c->idxmsk64 &=
+				~(~0ULL << (INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed));
+			c->weight = hweight64(c->idxmsk64);
+		}
+	}
+
+	/*
+	 * Access LBR MSR may cause #GP under certain circumstances.
+	 * E.g. KVM doesn't support LBR MSR
+	 * Check all LBT MSR here.
+	 * Disable LBR access if any LBR MSRs can not be accessed.
+	 */
+	if (x86_pmu.lbr_nr && !check_msr(x86_pmu.lbr_tos, 0x3UL))
+		x86_pmu.lbr_nr = 0;
+	for (i = 0; i < x86_pmu.lbr_nr; i++) {
+		if (!(check_msr(x86_pmu.lbr_from + i, 0xffffUL) &&
+		      check_msr(x86_pmu.lbr_to + i, 0xffffUL)))
+			x86_pmu.lbr_nr = 0;
+	}
+
+	/*
+	 * Access extra MSR may cause #GP under certain circumstances.
+	 * E.g. KVM doesn't support offcore event
+	 * Check all extra_regs here.
+	 */
+	if (x86_pmu.extra_regs) {
+		for (er = x86_pmu.extra_regs; er->msr; er++) {
+			er->extra_msr_access = check_msr(er->msr, 0x11UL);
+			/* Disable LBR select mapping */
+			if ((er->idx == EXTRA_REG_LBR) && !er->extra_msr_access)
+				x86_pmu.lbr_sel_map = NULL;
+		}
+	}
+
+	/* Support full width counters using alternative MSR range */
+	if (x86_pmu.intel_cap.full_width_write) {
+		x86_pmu.max_period = x86_pmu.cntval_mask >> 1;
+		x86_pmu.perfctr = MSR_IA32_PMC0;
+		pr_cont("full-width counters, ");
+	}
+
+	return 0;
+}
+
+/*
+ * HT bug: phase 2 init
+ * Called once we have valid topology information to check
+ * whether or not HT is enabled
+ * If HT is off, then we disable the workaround
+ */
+static __init int fixup_ht_bug(void)
+{
+	int cpu = smp_processor_id();
+	int w, c;
+	/*
+	 * problem not present on this CPU model, nothing to do
+	 */
+	if (!(x86_pmu.flags & PMU_FL_EXCL_ENABLED))
+		return 0;
+
+	w = cpumask_weight(topology_sibling_cpumask(cpu));
+	if (w > 1) {
+		pr_info("PMU erratum BJ122, BV98, HSD29 worked around, HT is on\n");
+		return 0;
+	}
+
+	if (lockup_detector_suspend() != 0) {
+		pr_debug("failed to disable PMU erratum BJ122, BV98, HSD29 workaround\n");
+		return 0;
+	}
+
+	x86_pmu.flags &= ~(PMU_FL_EXCL_CNTRS | PMU_FL_EXCL_ENABLED);
+
+	x86_pmu.start_scheduling = NULL;
+	x86_pmu.commit_scheduling = NULL;
+	x86_pmu.stop_scheduling = NULL;
+
+	lockup_detector_resume();
+
+	get_online_cpus();
+
+	for_each_online_cpu(c) {
+		free_excl_cntrs(c);
+	}
+
+	put_online_cpus();
+	pr_info("PMU erratum BJ122, BV98, HSD29 workaround disabled, HT off\n");
+	return 0;
+}
+subsys_initcall(fixup_ht_bug)
--- linux-4.4.0.orig/arch/x86/events/intel/cqm.c
+++ linux-4.4.0/arch/x86/events/intel/cqm.c
@@ -0,0 +1,1801 @@
+/*
+ * Intel Cache Quality-of-Service Monitoring (CQM) support.
+ *
+ * Based very, very heavily on work by Peter Zijlstra.
+ */
+
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+#include <asm/cpu_device_id.h>
+#include "../perf_event.h"
+
+#define MSR_IA32_PQR_ASSOC	0x0c8f
+#define MSR_IA32_QM_CTR		0x0c8e
+#define MSR_IA32_QM_EVTSEL	0x0c8d
+
+#define MBM_CNTR_WIDTH		24
+/*
+ * Guaranteed time in ms as per SDM where MBM counters will not overflow.
+ */
+#define MBM_CTR_OVERFLOW_TIME	1000
+
+static u32 cqm_max_rmid = -1;
+static unsigned int cqm_l3_scale; /* supposedly cacheline size */
+static bool cqm_enabled, mbm_enabled;
+unsigned int mbm_socket_max;
+
+/**
+ * struct intel_pqr_state - State cache for the PQR MSR
+ * @rmid:		The cached Resource Monitoring ID
+ * @closid:		The cached Class Of Service ID
+ * @rmid_usecnt:	The usage counter for rmid
+ *
+ * The upper 32 bits of MSR_IA32_PQR_ASSOC contain closid and the
+ * lower 10 bits rmid. The update to MSR_IA32_PQR_ASSOC always
+ * contains both parts, so we need to cache them.
+ *
+ * The cache also helps to avoid pointless updates if the value does
+ * not change.
+ */
+struct intel_pqr_state {
+	u32			rmid;
+	u32			closid;
+	int			rmid_usecnt;
+};
+
+/*
+ * The cached intel_pqr_state is strictly per CPU and can never be
+ * updated from a remote CPU. Both functions which modify the state
+ * (intel_cqm_event_start and intel_cqm_event_stop) are called with
+ * interrupts disabled, which is sufficient for the protection.
+ */
+static DEFINE_PER_CPU(struct intel_pqr_state, pqr_state);
+static struct hrtimer *mbm_timers;
+/**
+ * struct sample - mbm event's (local or total) data
+ * @total_bytes    #bytes since we began monitoring
+ * @prev_msr       previous value of MSR
+ */
+struct sample {
+	u64	total_bytes;
+	u64	prev_msr;
+};
+
+/*
+ * samples profiled for total memory bandwidth type events
+ */
+static struct sample *mbm_total;
+/*
+ * samples profiled for local memory bandwidth type events
+ */
+static struct sample *mbm_local;
+
+#define pkg_id	topology_physical_package_id(smp_processor_id())
+/*
+ * rmid_2_index returns the index for the rmid in mbm_local/mbm_total array.
+ * mbm_total[] and mbm_local[] are linearly indexed by socket# * max number of
+ * rmids per socket, an example is given below
+ * RMID1 of Socket0:  vrmid =  1
+ * RMID1 of Socket1:  vrmid =  1 * (cqm_max_rmid + 1) + 1
+ * RMID1 of Socket2:  vrmid =  2 * (cqm_max_rmid + 1) + 1
+ */
+#define rmid_2_index(rmid)  ((pkg_id * (cqm_max_rmid + 1)) + rmid)
+/*
+ * Protects cache_cgroups and cqm_rmid_free_lru and cqm_rmid_limbo_lru.
+ * Also protects event->hw.cqm_rmid
+ *
+ * Hold either for stability, both for modification of ->hw.cqm_rmid.
+ */
+static DEFINE_MUTEX(cache_mutex);
+static DEFINE_RAW_SPINLOCK(cache_lock);
+
+/*
+ * Groups of events that have the same target(s), one RMID per group.
+ */
+static LIST_HEAD(cache_groups);
+
+/*
+ * Mask of CPUs for reading CQM values. We only need one per-socket.
+ */
+static cpumask_t cqm_cpumask;
+
+#define RMID_VAL_ERROR		(1ULL << 63)
+#define RMID_VAL_UNAVAIL	(1ULL << 62)
+
+/*
+ * Event IDs are used to program IA32_QM_EVTSEL before reading event
+ * counter from IA32_QM_CTR
+ */
+#define QOS_L3_OCCUP_EVENT_ID	0x01
+#define QOS_MBM_TOTAL_EVENT_ID	0x02
+#define QOS_MBM_LOCAL_EVENT_ID	0x03
+
+/*
+ * This is central to the rotation algorithm in __intel_cqm_rmid_rotate().
+ *
+ * This rmid is always free and is guaranteed to have an associated
+ * near-zero occupancy value, i.e. no cachelines are tagged with this
+ * RMID, once __intel_cqm_rmid_rotate() returns.
+ */
+static u32 intel_cqm_rotation_rmid;
+
+#define INVALID_RMID		(-1)
+
+/*
+ * Is @rmid valid for programming the hardware?
+ *
+ * rmid 0 is reserved by the hardware for all non-monitored tasks, which
+ * means that we should never come across an rmid with that value.
+ * Likewise, an rmid value of -1 is used to indicate "no rmid currently
+ * assigned" and is used as part of the rotation code.
+ */
+static inline bool __rmid_valid(u32 rmid)
+{
+	if (!rmid || rmid == INVALID_RMID)
+		return false;
+
+	return true;
+}
+
+static u64 __rmid_read(u32 rmid)
+{
+	u64 val;
+
+	/*
+	 * Ignore the SDM, this thing is _NOTHING_ like a regular perfcnt,
+	 * it just says that to increase confusion.
+	 */
+	wrmsr(MSR_IA32_QM_EVTSEL, QOS_L3_OCCUP_EVENT_ID, rmid);
+	rdmsrl(MSR_IA32_QM_CTR, val);
+
+	/*
+	 * Aside from the ERROR and UNAVAIL bits, assume this thing returns
+	 * the number of cachelines tagged with @rmid.
+	 */
+	return val;
+}
+
+enum rmid_recycle_state {
+	RMID_YOUNG = 0,
+	RMID_AVAILABLE,
+	RMID_DIRTY,
+};
+
+struct cqm_rmid_entry {
+	u32 rmid;
+	enum rmid_recycle_state state;
+	struct list_head list;
+	unsigned long queue_time;
+};
+
+/*
+ * cqm_rmid_free_lru - A least recently used list of RMIDs.
+ *
+ * Oldest entry at the head, newest (most recently used) entry at the
+ * tail. This list is never traversed, it's only used to keep track of
+ * the lru order. That is, we only pick entries of the head or insert
+ * them on the tail.
+ *
+ * All entries on the list are 'free', and their RMIDs are not currently
+ * in use. To mark an RMID as in use, remove its entry from the lru
+ * list.
+ *
+ *
+ * cqm_rmid_limbo_lru - list of currently unused but (potentially) dirty RMIDs.
+ *
+ * This list is contains RMIDs that no one is currently using but that
+ * may have a non-zero occupancy value associated with them. The
+ * rotation worker moves RMIDs from the limbo list to the free list once
+ * the occupancy value drops below __intel_cqm_threshold.
+ *
+ * Both lists are protected by cache_mutex.
+ */
+static LIST_HEAD(cqm_rmid_free_lru);
+static LIST_HEAD(cqm_rmid_limbo_lru);
+
+/*
+ * We use a simple array of pointers so that we can lookup a struct
+ * cqm_rmid_entry in O(1). This alleviates the callers of __get_rmid()
+ * and __put_rmid() from having to worry about dealing with struct
+ * cqm_rmid_entry - they just deal with rmids, i.e. integers.
+ *
+ * Once this array is initialized it is read-only. No locks are required
+ * to access it.
+ *
+ * All entries for all RMIDs can be looked up in the this array at all
+ * times.
+ */
+static struct cqm_rmid_entry **cqm_rmid_ptrs;
+
+static inline struct cqm_rmid_entry *__rmid_entry(u32 rmid)
+{
+	struct cqm_rmid_entry *entry;
+
+	entry = cqm_rmid_ptrs[rmid];
+	WARN_ON(entry->rmid != rmid);
+
+	return entry;
+}
+
+/*
+ * Returns < 0 on fail.
+ *
+ * We expect to be called with cache_mutex held.
+ */
+static u32 __get_rmid(void)
+{
+	struct cqm_rmid_entry *entry;
+
+	lockdep_assert_held(&cache_mutex);
+
+	if (list_empty(&cqm_rmid_free_lru))
+		return INVALID_RMID;
+
+	entry = list_first_entry(&cqm_rmid_free_lru, struct cqm_rmid_entry, list);
+	list_del(&entry->list);
+
+	return entry->rmid;
+}
+
+static void __put_rmid(u32 rmid)
+{
+	struct cqm_rmid_entry *entry;
+
+	lockdep_assert_held(&cache_mutex);
+
+	WARN_ON(!__rmid_valid(rmid));
+	entry = __rmid_entry(rmid);
+
+	entry->queue_time = jiffies;
+	entry->state = RMID_YOUNG;
+
+	list_add_tail(&entry->list, &cqm_rmid_limbo_lru);
+}
+
+static void cqm_cleanup(void)
+{
+	int i;
+
+	if (!cqm_rmid_ptrs)
+		return;
+
+	for (i = 0; i < cqm_max_rmid; i++)
+		kfree(cqm_rmid_ptrs[i]);
+
+	kfree(cqm_rmid_ptrs);
+	cqm_rmid_ptrs = NULL;
+	cqm_enabled = false;
+}
+
+static int intel_cqm_setup_rmid_cache(void)
+{
+	struct cqm_rmid_entry *entry;
+	unsigned int nr_rmids;
+	int r = 0;
+
+	nr_rmids = cqm_max_rmid + 1;
+	cqm_rmid_ptrs = kzalloc(sizeof(struct cqm_rmid_entry *) *
+				nr_rmids, GFP_KERNEL);
+	if (!cqm_rmid_ptrs)
+		return -ENOMEM;
+
+	for (; r <= cqm_max_rmid; r++) {
+		struct cqm_rmid_entry *entry;
+
+		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+		if (!entry)
+			goto fail;
+
+		INIT_LIST_HEAD(&entry->list);
+		entry->rmid = r;
+		cqm_rmid_ptrs[r] = entry;
+
+		list_add_tail(&entry->list, &cqm_rmid_free_lru);
+	}
+
+	/*
+	 * RMID 0 is special and is always allocated. It's used for all
+	 * tasks that are not monitored.
+	 */
+	entry = __rmid_entry(0);
+	list_del(&entry->list);
+
+	mutex_lock(&cache_mutex);
+	intel_cqm_rotation_rmid = __get_rmid();
+	mutex_unlock(&cache_mutex);
+
+	return 0;
+
+fail:
+	cqm_cleanup();
+	return -ENOMEM;
+}
+
+/*
+ * Determine if @a and @b measure the same set of tasks.
+ *
+ * If @a and @b measure the same set of tasks then we want to share a
+ * single RMID.
+ */
+static bool __match_event(struct perf_event *a, struct perf_event *b)
+{
+	/* Per-cpu and task events don't mix */
+	if ((a->attach_state & PERF_ATTACH_TASK) !=
+	    (b->attach_state & PERF_ATTACH_TASK))
+		return false;
+
+#ifdef CONFIG_CGROUP_PERF
+	if (a->cgrp != b->cgrp)
+		return false;
+#endif
+
+	/* If not task event, we're machine wide */
+	if (!(b->attach_state & PERF_ATTACH_TASK))
+		return true;
+
+	/*
+	 * Events that target same task are placed into the same cache group.
+	 * Mark it as a multi event group, so that we update ->count
+	 * for every event rather than just the group leader later.
+	 */
+	if (a->hw.target == b->hw.target) {
+		b->hw.is_group_event = true;
+		return true;
+	}
+
+	/*
+	 * Are we an inherited event?
+	 */
+	if (b->parent == a)
+		return true;
+
+	return false;
+}
+
+#ifdef CONFIG_CGROUP_PERF
+static inline struct perf_cgroup *event_to_cgroup(struct perf_event *event)
+{
+	if (event->attach_state & PERF_ATTACH_TASK)
+		return perf_cgroup_from_task(event->hw.target, event->ctx);
+
+	return event->cgrp;
+}
+#endif
+
+/*
+ * Determine if @a's tasks intersect with @b's tasks
+ *
+ * There are combinations of events that we explicitly prohibit,
+ *
+ *		   PROHIBITS
+ *     system-wide    -> 	cgroup and task
+ *     cgroup 	      ->	system-wide
+ *     		      ->	task in cgroup
+ *     task 	      -> 	system-wide
+ *     		      ->	task in cgroup
+ *
+ * Call this function before allocating an RMID.
+ */
+static bool __conflict_event(struct perf_event *a, struct perf_event *b)
+{
+#ifdef CONFIG_CGROUP_PERF
+	/*
+	 * We can have any number of cgroups but only one system-wide
+	 * event at a time.
+	 */
+	if (a->cgrp && b->cgrp) {
+		struct perf_cgroup *ac = a->cgrp;
+		struct perf_cgroup *bc = b->cgrp;
+
+		/*
+		 * This condition should have been caught in
+		 * __match_event() and we should be sharing an RMID.
+		 */
+		WARN_ON_ONCE(ac == bc);
+
+		if (cgroup_is_descendant(ac->css.cgroup, bc->css.cgroup) ||
+		    cgroup_is_descendant(bc->css.cgroup, ac->css.cgroup))
+			return true;
+
+		return false;
+	}
+
+	if (a->cgrp || b->cgrp) {
+		struct perf_cgroup *ac, *bc;
+
+		/*
+		 * cgroup and system-wide events are mutually exclusive
+		 */
+		if ((a->cgrp && !(b->attach_state & PERF_ATTACH_TASK)) ||
+		    (b->cgrp && !(a->attach_state & PERF_ATTACH_TASK)))
+			return true;
+
+		/*
+		 * Ensure neither event is part of the other's cgroup
+		 */
+		ac = event_to_cgroup(a);
+		bc = event_to_cgroup(b);
+		if (ac == bc)
+			return true;
+
+		/*
+		 * Must have cgroup and non-intersecting task events.
+		 */
+		if (!ac || !bc)
+			return false;
+
+		/*
+		 * We have cgroup and task events, and the task belongs
+		 * to a cgroup. Check for for overlap.
+		 */
+		if (cgroup_is_descendant(ac->css.cgroup, bc->css.cgroup) ||
+		    cgroup_is_descendant(bc->css.cgroup, ac->css.cgroup))
+			return true;
+
+		return false;
+	}
+#endif
+	/*
+	 * If one of them is not a task, same story as above with cgroups.
+	 */
+	if (!(a->attach_state & PERF_ATTACH_TASK) ||
+	    !(b->attach_state & PERF_ATTACH_TASK))
+		return true;
+
+	/*
+	 * Must be non-overlapping.
+	 */
+	return false;
+}
+
+struct rmid_read {
+	u32 rmid;
+	u32 evt_type;
+	atomic64_t value;
+};
+
+static void __intel_cqm_event_count(void *info);
+static void init_mbm_sample(u32 rmid, u32 evt_type);
+static void __intel_mbm_event_count(void *info);
+
+static bool is_mbm_event(int e)
+{
+	return (e >= QOS_MBM_TOTAL_EVENT_ID && e <= QOS_MBM_LOCAL_EVENT_ID);
+}
+
+/*
+ * Exchange the RMID of a group of events.
+ */
+static u32 intel_cqm_xchg_rmid(struct perf_event *group, u32 rmid)
+{
+	struct perf_event *event;
+	struct list_head *head = &group->hw.cqm_group_entry;
+	u32 old_rmid = group->hw.cqm_rmid;
+
+	lockdep_assert_held(&cache_mutex);
+
+	/*
+	 * If our RMID is being deallocated, perform a read now.
+	 */
+	if (__rmid_valid(old_rmid) && !__rmid_valid(rmid)) {
+		struct rmid_read rr = {
+			.value = ATOMIC64_INIT(0),
+			.rmid = old_rmid,
+		};
+
+		if (is_mbm_event(group->attr.config)) {
+			rr.evt_type = group->attr.config;
+			on_each_cpu_mask(&cqm_cpumask, __intel_mbm_event_count,
+					 &rr, 1);
+		} else {
+			on_each_cpu_mask(&cqm_cpumask, __intel_cqm_event_count,
+					 &rr, 1);
+		}
+		local64_set(&group->count, atomic64_read(&rr.value));
+	}
+
+	raw_spin_lock_irq(&cache_lock);
+
+	group->hw.cqm_rmid = rmid;
+	list_for_each_entry(event, head, hw.cqm_group_entry)
+		event->hw.cqm_rmid = rmid;
+
+	raw_spin_unlock_irq(&cache_lock);
+
+	/*
+	 * If the allocation is for mbm, init the mbm stats.
+	 * Need to check if each event in the group is mbm event
+	 * because there could be multiple type of events in the same group.
+	 */
+	if (__rmid_valid(rmid)) {
+		event = group;
+		if (is_mbm_event(event->attr.config))
+			init_mbm_sample(rmid, event->attr.config);
+
+		list_for_each_entry(event, head, hw.cqm_group_entry) {
+			if (is_mbm_event(event->attr.config))
+				init_mbm_sample(rmid, event->attr.config);
+		}
+	}
+
+	return old_rmid;
+}
+
+/*
+ * If we fail to assign a new RMID for intel_cqm_rotation_rmid because
+ * cachelines are still tagged with RMIDs in limbo, we progressively
+ * increment the threshold until we find an RMID in limbo with <=
+ * __intel_cqm_threshold lines tagged. This is designed to mitigate the
+ * problem where cachelines tagged with an RMID are not steadily being
+ * evicted.
+ *
+ * On successful rotations we decrease the threshold back towards zero.
+ *
+ * __intel_cqm_max_threshold provides an upper bound on the threshold,
+ * and is measured in bytes because it's exposed to userland.
+ */
+static unsigned int __intel_cqm_threshold;
+static unsigned int __intel_cqm_max_threshold;
+
+/*
+ * Test whether an RMID has a zero occupancy value on this cpu.
+ */
+static void intel_cqm_stable(void *arg)
+{
+	struct cqm_rmid_entry *entry;
+
+	list_for_each_entry(entry, &cqm_rmid_limbo_lru, list) {
+		if (entry->state != RMID_AVAILABLE)
+			break;
+
+		if (__rmid_read(entry->rmid) > __intel_cqm_threshold)
+			entry->state = RMID_DIRTY;
+	}
+}
+
+/*
+ * If we have group events waiting for an RMID that don't conflict with
+ * events already running, assign @rmid.
+ */
+static bool intel_cqm_sched_in_event(u32 rmid)
+{
+	struct perf_event *leader, *event;
+
+	lockdep_assert_held(&cache_mutex);
+
+	leader = list_first_entry(&cache_groups, struct perf_event,
+				  hw.cqm_groups_entry);
+	event = leader;
+
+	list_for_each_entry_continue(event, &cache_groups,
+				     hw.cqm_groups_entry) {
+		if (__rmid_valid(event->hw.cqm_rmid))
+			continue;
+
+		if (__conflict_event(event, leader))
+			continue;
+
+		intel_cqm_xchg_rmid(event, rmid);
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * Initially use this constant for both the limbo queue time and the
+ * rotation timer interval, pmu::hrtimer_interval_ms.
+ *
+ * They don't need to be the same, but the two are related since if you
+ * rotate faster than you recycle RMIDs, you may run out of available
+ * RMIDs.
+ */
+#define RMID_DEFAULT_QUEUE_TIME 250	/* ms */
+
+static unsigned int __rmid_queue_time_ms = RMID_DEFAULT_QUEUE_TIME;
+
+/*
+ * intel_cqm_rmid_stabilize - move RMIDs from limbo to free list
+ * @nr_available: number of freeable RMIDs on the limbo list
+ *
+ * Quiescent state; wait for all 'freed' RMIDs to become unused, i.e. no
+ * cachelines are tagged with those RMIDs. After this we can reuse them
+ * and know that the current set of active RMIDs is stable.
+ *
+ * Return %true or %false depending on whether stabilization needs to be
+ * reattempted.
+ *
+ * If we return %true then @nr_available is updated to indicate the
+ * number of RMIDs on the limbo list that have been queued for the
+ * minimum queue time (RMID_AVAILABLE), but whose data occupancy values
+ * are above __intel_cqm_threshold.
+ */
+static bool intel_cqm_rmid_stabilize(unsigned int *available)
+{
+	struct cqm_rmid_entry *entry, *tmp;
+
+	lockdep_assert_held(&cache_mutex);
+
+	*available = 0;
+	list_for_each_entry(entry, &cqm_rmid_limbo_lru, list) {
+		unsigned long min_queue_time;
+		unsigned long now = jiffies;
+
+		/*
+		 * We hold RMIDs placed into limbo for a minimum queue
+		 * time. Before the minimum queue time has elapsed we do
+		 * not recycle RMIDs.
+		 *
+		 * The reasoning is that until a sufficient time has
+		 * passed since we stopped using an RMID, any RMID
+		 * placed onto the limbo list will likely still have
+		 * data tagged in the cache, which means we'll probably
+		 * fail to recycle it anyway.
+		 *
+		 * We can save ourselves an expensive IPI by skipping
+		 * any RMIDs that have not been queued for the minimum
+		 * time.
+		 */
+		min_queue_time = entry->queue_time +
+			msecs_to_jiffies(__rmid_queue_time_ms);
+
+		if (time_after(min_queue_time, now))
+			break;
+
+		entry->state = RMID_AVAILABLE;
+		(*available)++;
+	}
+
+	/*
+	 * Fast return if none of the RMIDs on the limbo list have been
+	 * sitting on the queue for the minimum queue time.
+	 */
+	if (!*available)
+		return false;
+
+	/*
+	 * Test whether an RMID is free for each package.
+	 */
+	on_each_cpu_mask(&cqm_cpumask, intel_cqm_stable, NULL, true);
+
+	list_for_each_entry_safe(entry, tmp, &cqm_rmid_limbo_lru, list) {
+		/*
+		 * Exhausted all RMIDs that have waited min queue time.
+		 */
+		if (entry->state == RMID_YOUNG)
+			break;
+
+		if (entry->state == RMID_DIRTY)
+			continue;
+
+		list_del(&entry->list);	/* remove from limbo */
+
+		/*
+		 * The rotation RMID gets priority if it's
+		 * currently invalid. In which case, skip adding
+		 * the RMID to the the free lru.
+		 */
+		if (!__rmid_valid(intel_cqm_rotation_rmid)) {
+			intel_cqm_rotation_rmid = entry->rmid;
+			continue;
+		}
+
+		/*
+		 * If we have groups waiting for RMIDs, hand
+		 * them one now provided they don't conflict.
+		 */
+		if (intel_cqm_sched_in_event(entry->rmid))
+			continue;
+
+		/*
+		 * Otherwise place it onto the free list.
+		 */
+		list_add_tail(&entry->list, &cqm_rmid_free_lru);
+	}
+
+
+	return __rmid_valid(intel_cqm_rotation_rmid);
+}
+
+/*
+ * Pick a victim group and move it to the tail of the group list.
+ * @next: The first group without an RMID
+ */
+static void __intel_cqm_pick_and_rotate(struct perf_event *next)
+{
+	struct perf_event *rotor;
+	u32 rmid;
+
+	lockdep_assert_held(&cache_mutex);
+
+	rotor = list_first_entry(&cache_groups, struct perf_event,
+				 hw.cqm_groups_entry);
+
+	/*
+	 * The group at the front of the list should always have a valid
+	 * RMID. If it doesn't then no groups have RMIDs assigned and we
+	 * don't need to rotate the list.
+	 */
+	if (next == rotor)
+		return;
+
+	rmid = intel_cqm_xchg_rmid(rotor, INVALID_RMID);
+	__put_rmid(rmid);
+
+	list_rotate_left(&cache_groups);
+}
+
+/*
+ * Deallocate the RMIDs from any events that conflict with @event, and
+ * place them on the back of the group list.
+ */
+static void intel_cqm_sched_out_conflicting_events(struct perf_event *event)
+{
+	struct perf_event *group, *g;
+	u32 rmid;
+
+	lockdep_assert_held(&cache_mutex);
+
+	list_for_each_entry_safe(group, g, &cache_groups, hw.cqm_groups_entry) {
+		if (group == event)
+			continue;
+
+		rmid = group->hw.cqm_rmid;
+
+		/*
+		 * Skip events that don't have a valid RMID.
+		 */
+		if (!__rmid_valid(rmid))
+			continue;
+
+		/*
+		 * No conflict? No problem! Leave the event alone.
+		 */
+		if (!__conflict_event(group, event))
+			continue;
+
+		intel_cqm_xchg_rmid(group, INVALID_RMID);
+		__put_rmid(rmid);
+	}
+}
+
+/*
+ * Attempt to rotate the groups and assign new RMIDs.
+ *
+ * We rotate for two reasons,
+ *   1. To handle the scheduling of conflicting events
+ *   2. To recycle RMIDs
+ *
+ * Rotating RMIDs is complicated because the hardware doesn't give us
+ * any clues.
+ *
+ * There's problems with the hardware interface; when you change the
+ * task:RMID map cachelines retain their 'old' tags, giving a skewed
+ * picture. In order to work around this, we must always keep one free
+ * RMID - intel_cqm_rotation_rmid.
+ *
+ * Rotation works by taking away an RMID from a group (the old RMID),
+ * and assigning the free RMID to another group (the new RMID). We must
+ * then wait for the old RMID to not be used (no cachelines tagged).
+ * This ensure that all cachelines are tagged with 'active' RMIDs. At
+ * this point we can start reading values for the new RMID and treat the
+ * old RMID as the free RMID for the next rotation.
+ *
+ * Return %true or %false depending on whether we did any rotating.
+ */
+static bool __intel_cqm_rmid_rotate(void)
+{
+	struct perf_event *group, *start = NULL;
+	unsigned int threshold_limit;
+	unsigned int nr_needed = 0;
+	unsigned int nr_available;
+	bool rotated = false;
+
+	mutex_lock(&cache_mutex);
+
+again:
+	/*
+	 * Fast path through this function if there are no groups and no
+	 * RMIDs that need cleaning.
+	 */
+	if (list_empty(&cache_groups) && list_empty(&cqm_rmid_limbo_lru))
+		goto out;
+
+	list_for_each_entry(group, &cache_groups, hw.cqm_groups_entry) {
+		if (!__rmid_valid(group->hw.cqm_rmid)) {
+			if (!start)
+				start = group;
+			nr_needed++;
+		}
+	}
+
+	/*
+	 * We have some event groups, but they all have RMIDs assigned
+	 * and no RMIDs need cleaning.
+	 */
+	if (!nr_needed && list_empty(&cqm_rmid_limbo_lru))
+		goto out;
+
+	if (!nr_needed)
+		goto stabilize;
+
+	/*
+	 * We have more event groups without RMIDs than available RMIDs,
+	 * or we have event groups that conflict with the ones currently
+	 * scheduled.
+	 *
+	 * We force deallocate the rmid of the group at the head of
+	 * cache_groups. The first event group without an RMID then gets
+	 * assigned intel_cqm_rotation_rmid. This ensures we always make
+	 * forward progress.
+	 *
+	 * Rotate the cache_groups list so the previous head is now the
+	 * tail.
+	 */
+	__intel_cqm_pick_and_rotate(start);
+
+	/*
+	 * If the rotation is going to succeed, reduce the threshold so
+	 * that we don't needlessly reuse dirty RMIDs.
+	 */
+	if (__rmid_valid(intel_cqm_rotation_rmid)) {
+		intel_cqm_xchg_rmid(start, intel_cqm_rotation_rmid);
+		intel_cqm_rotation_rmid = __get_rmid();
+
+		intel_cqm_sched_out_conflicting_events(start);
+
+		if (__intel_cqm_threshold)
+			__intel_cqm_threshold--;
+	}
+
+	rotated = true;
+
+stabilize:
+	/*
+	 * We now need to stablize the RMID we freed above (if any) to
+	 * ensure that the next time we rotate we have an RMID with zero
+	 * occupancy value.
+	 *
+	 * Alternatively, if we didn't need to perform any rotation,
+	 * we'll have a bunch of RMIDs in limbo that need stabilizing.
+	 */
+	threshold_limit = __intel_cqm_max_threshold / cqm_l3_scale;
+
+	while (intel_cqm_rmid_stabilize(&nr_available) &&
+	       __intel_cqm_threshold < threshold_limit) {
+		unsigned int steal_limit;
+
+		/*
+		 * Don't spin if nobody is actively waiting for an RMID,
+		 * the rotation worker will be kicked as soon as an
+		 * event needs an RMID anyway.
+		 */
+		if (!nr_needed)
+			break;
+
+		/* Allow max 25% of RMIDs to be in limbo. */
+		steal_limit = (cqm_max_rmid + 1) / 4;
+
+		/*
+		 * We failed to stabilize any RMIDs so our rotation
+		 * logic is now stuck. In order to make forward progress
+		 * we have a few options:
+		 *
+		 *   1. rotate ("steal") another RMID
+		 *   2. increase the threshold
+		 *   3. do nothing
+		 *
+		 * We do both of 1. and 2. until we hit the steal limit.
+		 *
+		 * The steal limit prevents all RMIDs ending up on the
+		 * limbo list. This can happen if every RMID has a
+		 * non-zero occupancy above threshold_limit, and the
+		 * occupancy values aren't dropping fast enough.
+		 *
+		 * Note that there is prioritisation at work here - we'd
+		 * rather increase the number of RMIDs on the limbo list
+		 * than increase the threshold, because increasing the
+		 * threshold skews the event data (because we reuse
+		 * dirty RMIDs) - threshold bumps are a last resort.
+		 */
+		if (nr_available < steal_limit)
+			goto again;
+
+		__intel_cqm_threshold++;
+	}
+
+out:
+	mutex_unlock(&cache_mutex);
+	return rotated;
+}
+
+static void intel_cqm_rmid_rotate(struct work_struct *work);
+
+static DECLARE_DELAYED_WORK(intel_cqm_rmid_work, intel_cqm_rmid_rotate);
+
+static struct pmu intel_cqm_pmu;
+
+static void intel_cqm_rmid_rotate(struct work_struct *work)
+{
+	unsigned long delay;
+
+	__intel_cqm_rmid_rotate();
+
+	delay = msecs_to_jiffies(intel_cqm_pmu.hrtimer_interval_ms);
+	schedule_delayed_work(&intel_cqm_rmid_work, delay);
+}
+
+static u64 update_sample(unsigned int rmid, u32 evt_type, int first)
+{
+	struct sample *mbm_current;
+	u32 vrmid = rmid_2_index(rmid);
+	u64 val, bytes, shift;
+	u32 eventid;
+
+	if (evt_type == QOS_MBM_LOCAL_EVENT_ID) {
+		mbm_current = &mbm_local[vrmid];
+		eventid     = QOS_MBM_LOCAL_EVENT_ID;
+	} else {
+		mbm_current = &mbm_total[vrmid];
+		eventid     = QOS_MBM_TOTAL_EVENT_ID;
+	}
+
+	wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
+	rdmsrl(MSR_IA32_QM_CTR, val);
+	if (val & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL))
+		return mbm_current->total_bytes;
+
+	if (first) {
+		mbm_current->prev_msr = val;
+		mbm_current->total_bytes = 0;
+		return mbm_current->total_bytes;
+	}
+
+	/*
+	 * The h/w guarantees that counters will not overflow
+	 * so long as we poll them at least once per second.
+	 */
+	shift = 64 - MBM_CNTR_WIDTH;
+	bytes = (val << shift) - (mbm_current->prev_msr << shift);
+	bytes >>= shift;
+
+	bytes *= cqm_l3_scale;
+
+	mbm_current->total_bytes += bytes;
+	mbm_current->prev_msr = val;
+
+	return mbm_current->total_bytes;
+}
+
+static u64 rmid_read_mbm(unsigned int rmid, u32 evt_type)
+{
+	return update_sample(rmid, evt_type, 0);
+}
+
+static void __intel_mbm_event_init(void *info)
+{
+	struct rmid_read *rr = info;
+
+	update_sample(rr->rmid, rr->evt_type, 1);
+}
+
+static void init_mbm_sample(u32 rmid, u32 evt_type)
+{
+	struct rmid_read rr = {
+		.rmid = rmid,
+		.evt_type = evt_type,
+		.value = ATOMIC64_INIT(0),
+	};
+
+	/* on each socket, init sample */
+	on_each_cpu_mask(&cqm_cpumask, __intel_mbm_event_init, &rr, 1);
+}
+
+/*
+ * Find a group and setup RMID.
+ *
+ * If we're part of a group, we use the group's RMID.
+ */
+static void intel_cqm_setup_event(struct perf_event *event,
+				  struct perf_event **group)
+{
+	struct perf_event *iter;
+	bool conflict = false;
+	u32 rmid;
+
+	event->hw.is_group_event = false;
+	list_for_each_entry(iter, &cache_groups, hw.cqm_groups_entry) {
+		rmid = iter->hw.cqm_rmid;
+
+		if (__match_event(iter, event)) {
+			/* All tasks in a group share an RMID */
+			event->hw.cqm_rmid = rmid;
+			*group = iter;
+			if (is_mbm_event(event->attr.config) && __rmid_valid(rmid))
+				init_mbm_sample(rmid, event->attr.config);
+			return;
+		}
+
+		/*
+		 * We only care about conflicts for events that are
+		 * actually scheduled in (and hence have a valid RMID).
+		 */
+		if (__conflict_event(iter, event) && __rmid_valid(rmid))
+			conflict = true;
+	}
+
+	if (conflict)
+		rmid = INVALID_RMID;
+	else
+		rmid = __get_rmid();
+
+	if (is_mbm_event(event->attr.config) && __rmid_valid(rmid))
+		init_mbm_sample(rmid, event->attr.config);
+
+	event->hw.cqm_rmid = rmid;
+}
+
+static void intel_cqm_event_read(struct perf_event *event)
+{
+	unsigned long flags;
+	u32 rmid;
+	u64 val;
+
+	/*
+	 * Task events are handled by intel_cqm_event_count().
+	 */
+	if (event->cpu == -1)
+		return;
+
+	raw_spin_lock_irqsave(&cache_lock, flags);
+	rmid = event->hw.cqm_rmid;
+
+	if (!__rmid_valid(rmid))
+		goto out;
+
+	if (is_mbm_event(event->attr.config))
+		val = rmid_read_mbm(rmid, event->attr.config);
+	else
+		val = __rmid_read(rmid);
+
+	/*
+	 * Ignore this reading on error states and do not update the value.
+	 */
+	if (val & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL))
+		goto out;
+
+	local64_set(&event->count, val);
+out:
+	raw_spin_unlock_irqrestore(&cache_lock, flags);
+}
+
+static void __intel_cqm_event_count(void *info)
+{
+	struct rmid_read *rr = info;
+	u64 val;
+
+	val = __rmid_read(rr->rmid);
+
+	if (val & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL))
+		return;
+
+	atomic64_add(val, &rr->value);
+}
+
+static inline bool cqm_group_leader(struct perf_event *event)
+{
+	return !list_empty(&event->hw.cqm_groups_entry);
+}
+
+static void __intel_mbm_event_count(void *info)
+{
+	struct rmid_read *rr = info;
+	u64 val;
+
+	val = rmid_read_mbm(rr->rmid, rr->evt_type);
+	if (val & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL))
+		return;
+	atomic64_add(val, &rr->value);
+}
+
+static enum hrtimer_restart mbm_hrtimer_handle(struct hrtimer *hrtimer)
+{
+	struct perf_event *iter, *iter1;
+	int ret = HRTIMER_RESTART;
+	struct list_head *head;
+	unsigned long flags;
+	u32 grp_rmid;
+
+	/*
+	 * Need to cache_lock as the timer Event Select MSR reads
+	 * can race with the mbm/cqm count() and mbm_init() reads.
+	 */
+	raw_spin_lock_irqsave(&cache_lock, flags);
+
+	if (list_empty(&cache_groups)) {
+		ret = HRTIMER_NORESTART;
+		goto out;
+	}
+
+	list_for_each_entry(iter, &cache_groups, hw.cqm_groups_entry) {
+		grp_rmid = iter->hw.cqm_rmid;
+		if (!__rmid_valid(grp_rmid))
+			continue;
+		if (is_mbm_event(iter->attr.config))
+			update_sample(grp_rmid, iter->attr.config, 0);
+
+		head = &iter->hw.cqm_group_entry;
+		if (list_empty(head))
+			continue;
+		list_for_each_entry(iter1, head, hw.cqm_group_entry) {
+			if (!iter1->hw.is_group_event)
+				break;
+			if (is_mbm_event(iter1->attr.config))
+				update_sample(iter1->hw.cqm_rmid,
+					      iter1->attr.config, 0);
+		}
+	}
+
+	hrtimer_forward_now(hrtimer, ms_to_ktime(MBM_CTR_OVERFLOW_TIME));
+out:
+	raw_spin_unlock_irqrestore(&cache_lock, flags);
+
+	return ret;
+}
+
+static void __mbm_start_timer(void *info)
+{
+	hrtimer_start(&mbm_timers[pkg_id], ms_to_ktime(MBM_CTR_OVERFLOW_TIME),
+			     HRTIMER_MODE_REL_PINNED);
+}
+
+static void __mbm_stop_timer(void *info)
+{
+	hrtimer_cancel(&mbm_timers[pkg_id]);
+}
+
+static void mbm_start_timers(void)
+{
+	on_each_cpu_mask(&cqm_cpumask, __mbm_start_timer, NULL, 1);
+}
+
+static void mbm_stop_timers(void)
+{
+	on_each_cpu_mask(&cqm_cpumask, __mbm_stop_timer, NULL, 1);
+}
+
+static void mbm_hrtimer_init(void)
+{
+	struct hrtimer *hr;
+	int i;
+
+	for (i = 0; i < mbm_socket_max; i++) {
+		hr = &mbm_timers[i];
+		hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		hr->function = mbm_hrtimer_handle;
+	}
+}
+
+static u64 intel_cqm_event_count(struct perf_event *event)
+{
+	unsigned long flags;
+	struct rmid_read rr = {
+		.value = ATOMIC64_INIT(0),
+	};
+
+	/*
+	 * We only need to worry about task events. System-wide events
+	 * are handled like usual, i.e. entirely with
+	 * intel_cqm_event_read().
+	 */
+	if (event->cpu != -1)
+		return __perf_event_count(event);
+
+	/*
+	 * Only the group leader gets to report values except in case of
+	 * multiple events in the same group, we still need to read the
+	 * other events.This stops us
+	 * reporting duplicate values to userspace, and gives us a clear
+	 * rule for which task gets to report the values.
+	 *
+	 * Note that it is impossible to attribute these values to
+	 * specific packages - we forfeit that ability when we create
+	 * task events.
+	 */
+	if (!cqm_group_leader(event) && !event->hw.is_group_event)
+		return 0;
+
+	/*
+	 * Getting up-to-date values requires an SMP IPI which is not
+	 * possible if we're being called in interrupt context. Return
+	 * the cached values instead.
+	 */
+	if (unlikely(in_interrupt()))
+		goto out;
+
+	/*
+	 * Notice that we don't perform the reading of an RMID
+	 * atomically, because we can't hold a spin lock across the
+	 * IPIs.
+	 *
+	 * Speculatively perform the read, since @event might be
+	 * assigned a different (possibly invalid) RMID while we're
+	 * busying performing the IPI calls. It's therefore necessary to
+	 * check @event's RMID afterwards, and if it has changed,
+	 * discard the result of the read.
+	 */
+	rr.rmid = ACCESS_ONCE(event->hw.cqm_rmid);
+
+	if (!__rmid_valid(rr.rmid))
+		goto out;
+
+	if (is_mbm_event(event->attr.config)) {
+		rr.evt_type = event->attr.config;
+		on_each_cpu_mask(&cqm_cpumask, __intel_mbm_event_count, &rr, 1);
+	} else {
+		on_each_cpu_mask(&cqm_cpumask, __intel_cqm_event_count, &rr, 1);
+	}
+
+	raw_spin_lock_irqsave(&cache_lock, flags);
+	if (event->hw.cqm_rmid == rr.rmid)
+		local64_set(&event->count, atomic64_read(&rr.value));
+	raw_spin_unlock_irqrestore(&cache_lock, flags);
+out:
+	return __perf_event_count(event);
+}
+
+static void intel_cqm_event_start(struct perf_event *event, int mode)
+{
+	struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
+	u32 rmid = event->hw.cqm_rmid;
+
+	if (!(event->hw.cqm_state & PERF_HES_STOPPED))
+		return;
+
+	event->hw.cqm_state &= ~PERF_HES_STOPPED;
+
+	if (state->rmid_usecnt++) {
+		if (!WARN_ON_ONCE(state->rmid != rmid))
+			return;
+	} else {
+		WARN_ON_ONCE(state->rmid);
+	}
+
+	state->rmid = rmid;
+	wrmsr(MSR_IA32_PQR_ASSOC, rmid, state->closid);
+}
+
+static void intel_cqm_event_stop(struct perf_event *event, int mode)
+{
+	struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
+
+	if (event->hw.cqm_state & PERF_HES_STOPPED)
+		return;
+
+	event->hw.cqm_state |= PERF_HES_STOPPED;
+
+	intel_cqm_event_read(event);
+
+	if (!--state->rmid_usecnt) {
+		state->rmid = 0;
+		wrmsr(MSR_IA32_PQR_ASSOC, 0, state->closid);
+	} else {
+		WARN_ON_ONCE(!state->rmid);
+	}
+}
+
+static int intel_cqm_event_add(struct perf_event *event, int mode)
+{
+	unsigned long flags;
+	u32 rmid;
+
+	raw_spin_lock_irqsave(&cache_lock, flags);
+
+	event->hw.cqm_state = PERF_HES_STOPPED;
+	rmid = event->hw.cqm_rmid;
+
+	if (__rmid_valid(rmid) && (mode & PERF_EF_START))
+		intel_cqm_event_start(event, mode);
+
+	raw_spin_unlock_irqrestore(&cache_lock, flags);
+
+	return 0;
+}
+
+static void intel_cqm_event_destroy(struct perf_event *event)
+{
+	struct perf_event *group_other = NULL;
+	unsigned long flags;
+
+	mutex_lock(&cache_mutex);
+	/*
+	* Hold the cache_lock as mbm timer handlers could be
+	* scanning the list of events.
+	*/
+	raw_spin_lock_irqsave(&cache_lock, flags);
+
+	/*
+	 * If there's another event in this group...
+	 */
+	if (!list_empty(&event->hw.cqm_group_entry)) {
+		group_other = list_first_entry(&event->hw.cqm_group_entry,
+					       struct perf_event,
+					       hw.cqm_group_entry);
+		list_del(&event->hw.cqm_group_entry);
+	}
+
+	/*
+	 * And we're the group leader..
+	 */
+	if (cqm_group_leader(event)) {
+		/*
+		 * If there was a group_other, make that leader, otherwise
+		 * destroy the group and return the RMID.
+		 */
+		if (group_other) {
+			list_replace(&event->hw.cqm_groups_entry,
+				     &group_other->hw.cqm_groups_entry);
+		} else {
+			u32 rmid = event->hw.cqm_rmid;
+
+			if (__rmid_valid(rmid))
+				__put_rmid(rmid);
+			list_del(&event->hw.cqm_groups_entry);
+		}
+	}
+
+	raw_spin_unlock_irqrestore(&cache_lock, flags);
+
+	/*
+	 * Stop the mbm overflow timers when the last event is destroyed.
+	*/
+	if (mbm_enabled && list_empty(&cache_groups))
+		mbm_stop_timers();
+
+	mutex_unlock(&cache_mutex);
+}
+
+static int intel_cqm_event_init(struct perf_event *event)
+{
+	struct perf_event *group = NULL;
+	bool rotate = false;
+	unsigned long flags;
+
+	if (event->attr.type != intel_cqm_pmu.type)
+		return -ENOENT;
+
+	if ((event->attr.config < QOS_L3_OCCUP_EVENT_ID) ||
+	     (event->attr.config > QOS_MBM_LOCAL_EVENT_ID))
+		return -EINVAL;
+
+	/* unsupported modes and filters */
+	if (event->attr.exclude_user   ||
+	    event->attr.exclude_kernel ||
+	    event->attr.exclude_hv     ||
+	    event->attr.exclude_idle   ||
+	    event->attr.exclude_host   ||
+	    event->attr.exclude_guest  ||
+	    event->attr.sample_period) /* no sampling */
+		return -EINVAL;
+
+	INIT_LIST_HEAD(&event->hw.cqm_group_entry);
+	INIT_LIST_HEAD(&event->hw.cqm_groups_entry);
+
+	event->destroy = intel_cqm_event_destroy;
+
+	mutex_lock(&cache_mutex);
+
+	/*
+	 * Start the mbm overflow timers when the first event is created.
+	*/
+	if (mbm_enabled && list_empty(&cache_groups))
+		mbm_start_timers();
+
+	/* Will also set rmid */
+	intel_cqm_setup_event(event, &group);
+
+	/*
+	* Hold the cache_lock as mbm timer handlers be
+	* scanning the list of events.
+	*/
+	raw_spin_lock_irqsave(&cache_lock, flags);
+
+	if (group) {
+		list_add_tail(&event->hw.cqm_group_entry,
+			      &group->hw.cqm_group_entry);
+	} else {
+		list_add_tail(&event->hw.cqm_groups_entry,
+			      &cache_groups);
+
+		/*
+		 * All RMIDs are either in use or have recently been
+		 * used. Kick the rotation worker to clean/free some.
+		 *
+		 * We only do this for the group leader, rather than for
+		 * every event in a group to save on needless work.
+		 */
+		if (!__rmid_valid(event->hw.cqm_rmid))
+			rotate = true;
+	}
+
+	raw_spin_unlock_irqrestore(&cache_lock, flags);
+	mutex_unlock(&cache_mutex);
+
+	if (rotate)
+		schedule_delayed_work(&intel_cqm_rmid_work, 0);
+
+	return 0;
+}
+
+EVENT_ATTR_STR(llc_occupancy, intel_cqm_llc, "event=0x01");
+EVENT_ATTR_STR(llc_occupancy.per-pkg, intel_cqm_llc_pkg, "1");
+EVENT_ATTR_STR(llc_occupancy.unit, intel_cqm_llc_unit, "Bytes");
+EVENT_ATTR_STR(llc_occupancy.scale, intel_cqm_llc_scale, NULL);
+EVENT_ATTR_STR(llc_occupancy.snapshot, intel_cqm_llc_snapshot, "1");
+
+EVENT_ATTR_STR(total_bytes, intel_cqm_total_bytes, "event=0x02");
+EVENT_ATTR_STR(total_bytes.per-pkg, intel_cqm_total_bytes_pkg, "1");
+EVENT_ATTR_STR(total_bytes.unit, intel_cqm_total_bytes_unit, "MB");
+EVENT_ATTR_STR(total_bytes.scale, intel_cqm_total_bytes_scale, "1e-6");
+
+EVENT_ATTR_STR(local_bytes, intel_cqm_local_bytes, "event=0x03");
+EVENT_ATTR_STR(local_bytes.per-pkg, intel_cqm_local_bytes_pkg, "1");
+EVENT_ATTR_STR(local_bytes.unit, intel_cqm_local_bytes_unit, "MB");
+EVENT_ATTR_STR(local_bytes.scale, intel_cqm_local_bytes_scale, "1e-6");
+
+static struct attribute *intel_cqm_events_attr[] = {
+	EVENT_PTR(intel_cqm_llc),
+	EVENT_PTR(intel_cqm_llc_pkg),
+	EVENT_PTR(intel_cqm_llc_unit),
+	EVENT_PTR(intel_cqm_llc_scale),
+	EVENT_PTR(intel_cqm_llc_snapshot),
+	NULL,
+};
+
+static struct attribute *intel_mbm_events_attr[] = {
+	EVENT_PTR(intel_cqm_total_bytes),
+	EVENT_PTR(intel_cqm_local_bytes),
+	EVENT_PTR(intel_cqm_total_bytes_pkg),
+	EVENT_PTR(intel_cqm_local_bytes_pkg),
+	EVENT_PTR(intel_cqm_total_bytes_unit),
+	EVENT_PTR(intel_cqm_local_bytes_unit),
+	EVENT_PTR(intel_cqm_total_bytes_scale),
+	EVENT_PTR(intel_cqm_local_bytes_scale),
+	NULL,
+};
+
+static struct attribute *intel_cmt_mbm_events_attr[] = {
+	EVENT_PTR(intel_cqm_llc),
+	EVENT_PTR(intel_cqm_total_bytes),
+	EVENT_PTR(intel_cqm_local_bytes),
+	EVENT_PTR(intel_cqm_llc_pkg),
+	EVENT_PTR(intel_cqm_total_bytes_pkg),
+	EVENT_PTR(intel_cqm_local_bytes_pkg),
+	EVENT_PTR(intel_cqm_llc_unit),
+	EVENT_PTR(intel_cqm_total_bytes_unit),
+	EVENT_PTR(intel_cqm_local_bytes_unit),
+	EVENT_PTR(intel_cqm_llc_scale),
+	EVENT_PTR(intel_cqm_total_bytes_scale),
+	EVENT_PTR(intel_cqm_local_bytes_scale),
+	EVENT_PTR(intel_cqm_llc_snapshot),
+	NULL,
+};
+
+static struct attribute_group intel_cqm_events_group = {
+	.name = "events",
+	.attrs = NULL,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-7");
+static struct attribute *intel_cqm_formats_attr[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group intel_cqm_format_group = {
+	.name = "format",
+	.attrs = intel_cqm_formats_attr,
+};
+
+static ssize_t
+max_recycle_threshold_show(struct device *dev, struct device_attribute *attr,
+			   char *page)
+{
+	ssize_t rv;
+
+	mutex_lock(&cache_mutex);
+	rv = snprintf(page, PAGE_SIZE-1, "%u\n", __intel_cqm_max_threshold);
+	mutex_unlock(&cache_mutex);
+
+	return rv;
+}
+
+static ssize_t
+max_recycle_threshold_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned int bytes, cachelines;
+	int ret;
+
+	ret = kstrtouint(buf, 0, &bytes);
+	if (ret)
+		return ret;
+
+	mutex_lock(&cache_mutex);
+
+	__intel_cqm_max_threshold = bytes;
+	cachelines = bytes / cqm_l3_scale;
+
+	/*
+	 * The new maximum takes effect immediately.
+	 */
+	if (__intel_cqm_threshold > cachelines)
+		__intel_cqm_threshold = cachelines;
+
+	mutex_unlock(&cache_mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(max_recycle_threshold);
+
+static struct attribute *intel_cqm_attrs[] = {
+	&dev_attr_max_recycle_threshold.attr,
+	NULL,
+};
+
+static const struct attribute_group intel_cqm_group = {
+	.attrs = intel_cqm_attrs,
+};
+
+static const struct attribute_group *intel_cqm_attr_groups[] = {
+	&intel_cqm_events_group,
+	&intel_cqm_format_group,
+	&intel_cqm_group,
+	NULL,
+};
+
+static struct pmu intel_cqm_pmu = {
+	.hrtimer_interval_ms = RMID_DEFAULT_QUEUE_TIME,
+	.attr_groups	     = intel_cqm_attr_groups,
+	.task_ctx_nr	     = perf_sw_context,
+	.event_init	     = intel_cqm_event_init,
+	.add		     = intel_cqm_event_add,
+	.del		     = intel_cqm_event_stop,
+	.start		     = intel_cqm_event_start,
+	.stop		     = intel_cqm_event_stop,
+	.read		     = intel_cqm_event_read,
+	.count		     = intel_cqm_event_count,
+};
+
+static inline void cqm_pick_event_reader(int cpu)
+{
+	int phys_id = topology_physical_package_id(cpu);
+	int i;
+
+	for_each_cpu(i, &cqm_cpumask) {
+		if (phys_id == topology_physical_package_id(i))
+			return;	/* already got reader for this socket */
+	}
+
+	cpumask_set_cpu(cpu, &cqm_cpumask);
+}
+
+static void intel_cqm_cpu_starting(unsigned int cpu)
+{
+	struct intel_pqr_state *state = &per_cpu(pqr_state, cpu);
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+	state->rmid = 0;
+	state->closid = 0;
+	state->rmid_usecnt = 0;
+
+	WARN_ON(c->x86_cache_max_rmid != cqm_max_rmid);
+	WARN_ON(c->x86_cache_occ_scale != cqm_l3_scale);
+}
+
+static void intel_cqm_cpu_exit(unsigned int cpu)
+{
+	int phys_id = topology_physical_package_id(cpu);
+	int i;
+
+	/*
+	 * Is @cpu a designated cqm reader?
+	 */
+	if (!cpumask_test_and_clear_cpu(cpu, &cqm_cpumask))
+		return;
+
+	for_each_online_cpu(i) {
+		if (i == cpu)
+			continue;
+
+		if (phys_id == topology_physical_package_id(i)) {
+			cpumask_set_cpu(i, &cqm_cpumask);
+			break;
+		}
+	}
+}
+
+static int intel_cqm_cpu_notifier(struct notifier_block *nb,
+				  unsigned long action, void *hcpu)
+{
+	unsigned int cpu  = (unsigned long)hcpu;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_DOWN_PREPARE:
+		intel_cqm_cpu_exit(cpu);
+		break;
+	case CPU_STARTING:
+		intel_cqm_cpu_starting(cpu);
+		cqm_pick_event_reader(cpu);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static const struct x86_cpu_id intel_cqm_match[] = {
+	{ .vendor = X86_VENDOR_INTEL, .feature = X86_FEATURE_CQM_OCCUP_LLC },
+	{}
+};
+
+static void mbm_cleanup(void)
+{
+	if (!mbm_enabled)
+		return;
+
+	kfree(mbm_local);
+	kfree(mbm_total);
+	mbm_enabled = false;
+}
+
+static const struct x86_cpu_id intel_mbm_local_match[] = {
+	{ .vendor = X86_VENDOR_INTEL, .feature = X86_FEATURE_CQM_MBM_LOCAL },
+	{}
+};
+
+static const struct x86_cpu_id intel_mbm_total_match[] = {
+	{ .vendor = X86_VENDOR_INTEL, .feature = X86_FEATURE_CQM_MBM_TOTAL },
+	{}
+};
+
+static int intel_mbm_init(void)
+{
+	int ret = 0, array_size, maxid = cqm_max_rmid + 1;
+
+	mbm_socket_max = topology_max_packages();
+	array_size = sizeof(struct sample) * maxid * mbm_socket_max;
+	mbm_local = kmalloc(array_size, GFP_KERNEL);
+	if (!mbm_local)
+		return -ENOMEM;
+
+	mbm_total = kmalloc(array_size, GFP_KERNEL);
+	if (!mbm_total) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	array_size = sizeof(struct hrtimer) * mbm_socket_max;
+	mbm_timers = kmalloc(array_size, GFP_KERNEL);
+	if (!mbm_timers) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	mbm_hrtimer_init();
+
+out:
+	if (ret)
+		mbm_cleanup();
+
+	return ret;
+}
+
+static int __init intel_cqm_init(void)
+{
+	char *str = NULL, scale[20];
+	int i, cpu, ret;
+
+	if (x86_match_cpu(intel_cqm_match))
+		cqm_enabled = true;
+
+	if (x86_match_cpu(intel_mbm_local_match) &&
+	     x86_match_cpu(intel_mbm_total_match))
+		mbm_enabled = true;
+
+	if (!cqm_enabled && !mbm_enabled)
+		return -ENODEV;
+
+	cqm_l3_scale = boot_cpu_data.x86_cache_occ_scale;
+
+	/*
+	 * It's possible that not all resources support the same number
+	 * of RMIDs. Instead of making scheduling much more complicated
+	 * (where we have to match a task's RMID to a cpu that supports
+	 * that many RMIDs) just find the minimum RMIDs supported across
+	 * all cpus.
+	 *
+	 * Also, check that the scales match on all cpus.
+	 */
+	cpu_notifier_register_begin();
+
+	for_each_online_cpu(cpu) {
+		struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+		if (c->x86_cache_max_rmid < cqm_max_rmid)
+			cqm_max_rmid = c->x86_cache_max_rmid;
+
+		if (c->x86_cache_occ_scale != cqm_l3_scale) {
+			pr_err("Multiple LLC scale values, disabling\n");
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	/*
+	 * A reasonable upper limit on the max threshold is the number
+	 * of lines tagged per RMID if all RMIDs have the same number of
+	 * lines tagged in the LLC.
+	 *
+	 * For a 35MB LLC and 56 RMIDs, this is ~1.8% of the LLC.
+	 */
+	__intel_cqm_max_threshold =
+		boot_cpu_data.x86_cache_size * 1024 / (cqm_max_rmid + 1);
+
+	snprintf(scale, sizeof(scale), "%u", cqm_l3_scale);
+	str = kstrdup(scale, GFP_KERNEL);
+	if (!str) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	event_attr_intel_cqm_llc_scale.event_str = str;
+
+	ret = intel_cqm_setup_rmid_cache();
+	if (ret)
+		goto out;
+
+	for_each_online_cpu(i) {
+		intel_cqm_cpu_starting(i);
+		cqm_pick_event_reader(i);
+	}
+
+	if (mbm_enabled)
+		ret = intel_mbm_init();
+	if (ret && !cqm_enabled)
+		goto out;
+
+	if (cqm_enabled && mbm_enabled)
+		intel_cqm_events_group.attrs = intel_cmt_mbm_events_attr;
+	else if (!cqm_enabled && mbm_enabled)
+		intel_cqm_events_group.attrs = intel_mbm_events_attr;
+	else if (cqm_enabled && !mbm_enabled)
+		intel_cqm_events_group.attrs = intel_cqm_events_attr;
+
+	ret = perf_pmu_register(&intel_cqm_pmu, "intel_cqm", -1);
+	if (ret) {
+		pr_err("Intel CQM perf registration failed: %d\n", ret);
+		goto out;
+	}
+
+	if (cqm_enabled)
+		pr_info("Intel CQM monitoring enabled\n");
+	if (mbm_enabled)
+		pr_info("Intel MBM enabled\n");
+
+	/*
+	 * Register the hot cpu notifier once we are sure cqm
+	 * is enabled to avoid notifier leak.
+	 */
+	__perf_cpu_notifier(intel_cqm_cpu_notifier);
+out:
+	cpu_notifier_register_done();
+	if (ret) {
+		kfree(str);
+		cqm_cleanup();
+		mbm_cleanup();
+	}
+
+	return ret;
+}
+device_initcall(intel_cqm_init);
--- linux-4.4.0.orig/arch/x86/events/intel/cstate.c
+++ linux-4.4.0/arch/x86/events/intel/cstate.c
@@ -0,0 +1,697 @@
+/*
+ * perf_event_intel_cstate.c: support cstate residency counters
+ *
+ * Copyright (C) 2015, Intel Corp.
+ * Author: Kan Liang (kan.liang@intel.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ */
+
+/*
+ * This file export cstate related free running (read-only) counters
+ * for perf. These counters may be use simultaneously by other tools,
+ * such as turbostat. However, it still make sense to implement them
+ * in perf. Because we can conveniently collect them together with
+ * other events, and allow to use them from tools without special MSR
+ * access code.
+ *
+ * The events only support system-wide mode counting. There is no
+ * sampling support because it is not supported by the hardware.
+ *
+ * According to counters' scope and category, two PMUs are registered
+ * with the perf_event core subsystem.
+ *  - 'cstate_core': The counter is available for each physical core.
+ *    The counters include CORE_C*_RESIDENCY.
+ *  - 'cstate_pkg': The counter is available for each physical package.
+ *    The counters include PKG_C*_RESIDENCY.
+ *
+ * All of these counters are specified in the Intel® 64 and IA-32
+ * Architectures Software Developer.s Manual Vol3b.
+ *
+ * Model specific counters:
+ *	MSR_CORE_C1_RES: CORE C1 Residency Counter
+ *			 perf code: 0x00
+ *			 Available model: SLM,AMT
+ *			 Scope: Core (each processor core has a MSR)
+ *	MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter
+ *			       perf code: 0x01
+ *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *			       Scope: Core
+ *	MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter
+ *			       perf code: 0x02
+ *			       Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *			       Scope: Core
+ *	MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
+ *			       perf code: 0x03
+ *			       Available model: SNB,IVB,HSW,BDW,SKL
+ *			       Scope: Core
+ *	MSR_PKG_C2_RESIDENCY:  Package C2 Residency Counter.
+ *			       perf code: 0x00
+ *			       Available model: SNB,IVB,HSW,BDW,SKL
+ *			       Scope: Package (physical package)
+ *	MSR_PKG_C3_RESIDENCY:  Package C3 Residency Counter.
+ *			       perf code: 0x01
+ *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *			       Scope: Package (physical package)
+ *	MSR_PKG_C6_RESIDENCY:  Package C6 Residency Counter.
+ *			       perf code: 0x02
+ *			       Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *			       Scope: Package (physical package)
+ *	MSR_PKG_C7_RESIDENCY:  Package C7 Residency Counter.
+ *			       perf code: 0x03
+ *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *			       Scope: Package (physical package)
+ *	MSR_PKG_C8_RESIDENCY:  Package C8 Residency Counter.
+ *			       perf code: 0x04
+ *			       Available model: HSW ULT only
+ *			       Scope: Package (physical package)
+ *	MSR_PKG_C9_RESIDENCY:  Package C9 Residency Counter.
+ *			       perf code: 0x05
+ *			       Available model: HSW ULT only
+ *			       Scope: Package (physical package)
+ *	MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter.
+ *			       perf code: 0x06
+ *			       Available model: HSW ULT only
+ *			       Scope: Package (physical package)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/perf_event.h>
+#include <linux/nospec.h>
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+#include "../perf_event.h"
+
+#define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format)		\
+static ssize_t __cstate_##_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, __cstate_##_var##_show, NULL)
+
+static ssize_t cstate_get_attr_cpumask(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf);
+
+struct perf_cstate_msr {
+	u64	msr;
+	struct	perf_pmu_events_attr *attr;
+	bool	(*test)(int idx);
+};
+
+
+/* cstate_core PMU */
+
+static struct pmu cstate_core_pmu;
+static bool has_cstate_core;
+
+enum perf_cstate_core_id {
+	/*
+	 * cstate_core events
+	 */
+	PERF_CSTATE_CORE_C1_RES = 0,
+	PERF_CSTATE_CORE_C3_RES,
+	PERF_CSTATE_CORE_C6_RES,
+	PERF_CSTATE_CORE_C7_RES,
+
+	PERF_CSTATE_CORE_EVENT_MAX,
+};
+
+bool test_core(int idx)
+{
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
+	    boot_cpu_data.x86 != 6)
+		return false;
+
+	switch (boot_cpu_data.x86_model) {
+	case INTEL_FAM6_NEHALEM:
+	case INTEL_FAM6_NEHALEM_EP:
+	case INTEL_FAM6_NEHALEM_EX:
+
+	case INTEL_FAM6_WESTMERE:
+	case INTEL_FAM6_WESTMERE_EP:
+	case INTEL_FAM6_WESTMERE_EX:
+		if (idx == PERF_CSTATE_CORE_C3_RES ||
+		    idx == PERF_CSTATE_CORE_C6_RES)
+			return true;
+		break;
+	case INTEL_FAM6_SANDYBRIDGE:
+	case INTEL_FAM6_SANDYBRIDGE_X:
+
+	case INTEL_FAM6_IVYBRIDGE:
+	case INTEL_FAM6_IVYBRIDGE_X:
+
+	case INTEL_FAM6_HASWELL_CORE:
+	case INTEL_FAM6_HASWELL_X:
+	case INTEL_FAM6_HASWELL_ULT:
+	case INTEL_FAM6_HASWELL_GT3E:
+
+	case INTEL_FAM6_BROADWELL_CORE:
+	case INTEL_FAM6_BROADWELL_XEON_D:
+	case INTEL_FAM6_BROADWELL_GT3E:
+	case INTEL_FAM6_BROADWELL_X:
+
+	case INTEL_FAM6_SKYLAKE_MOBILE:
+	case INTEL_FAM6_SKYLAKE_DESKTOP:
+		if (idx == PERF_CSTATE_CORE_C3_RES ||
+		    idx == PERF_CSTATE_CORE_C6_RES ||
+		    idx == PERF_CSTATE_CORE_C7_RES)
+			return true;
+		break;
+	case INTEL_FAM6_ATOM_SILVERMONT:
+	case INTEL_FAM6_ATOM_SILVERMONT_X:
+	case INTEL_FAM6_ATOM_AIRMONT:
+		if (idx == PERF_CSTATE_CORE_C1_RES ||
+		    idx == PERF_CSTATE_CORE_C6_RES)
+			return true;
+		break;
+	}
+
+	return false;
+}
+
+PMU_EVENT_ATTR_STRING(c1-residency, evattr_cstate_core_c1, "event=0x00");
+PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_core_c3, "event=0x01");
+PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_core_c6, "event=0x02");
+PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_core_c7, "event=0x03");
+
+static struct perf_cstate_msr core_msr[] = {
+	[PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES,		&evattr_cstate_core_c1,	test_core, },
+	[PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY,	&evattr_cstate_core_c3, test_core, },
+	[PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY,	&evattr_cstate_core_c6, test_core, },
+	[PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY,	&evattr_cstate_core_c7,	test_core, },
+};
+
+static struct attribute *core_events_attrs[PERF_CSTATE_CORE_EVENT_MAX + 1] = {
+	NULL,
+};
+
+static struct attribute_group core_events_attr_group = {
+	.name = "events",
+	.attrs = core_events_attrs,
+};
+
+DEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63");
+static struct attribute *core_format_attrs[] = {
+	&format_attr_core_event.attr,
+	NULL,
+};
+
+static struct attribute_group core_format_attr_group = {
+	.name = "format",
+	.attrs = core_format_attrs,
+};
+
+static cpumask_t cstate_core_cpu_mask;
+static DEVICE_ATTR(cpumask, S_IRUGO, cstate_get_attr_cpumask, NULL);
+
+static struct attribute *cstate_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static struct attribute_group cpumask_attr_group = {
+	.attrs = cstate_cpumask_attrs,
+};
+
+static const struct attribute_group *core_attr_groups[] = {
+	&core_events_attr_group,
+	&core_format_attr_group,
+	&cpumask_attr_group,
+	NULL,
+};
+
+/* cstate_core PMU end */
+
+
+/* cstate_pkg PMU */
+
+static struct pmu cstate_pkg_pmu;
+static bool has_cstate_pkg;
+
+enum perf_cstate_pkg_id {
+	/*
+	 * cstate_pkg events
+	 */
+	PERF_CSTATE_PKG_C2_RES = 0,
+	PERF_CSTATE_PKG_C3_RES,
+	PERF_CSTATE_PKG_C6_RES,
+	PERF_CSTATE_PKG_C7_RES,
+	PERF_CSTATE_PKG_C8_RES,
+	PERF_CSTATE_PKG_C9_RES,
+	PERF_CSTATE_PKG_C10_RES,
+
+	PERF_CSTATE_PKG_EVENT_MAX,
+};
+
+bool test_pkg(int idx)
+{
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
+	    boot_cpu_data.x86 != 6)
+		return false;
+
+	switch (boot_cpu_data.x86_model) {
+	case INTEL_FAM6_NEHALEM:
+	case INTEL_FAM6_NEHALEM_EP:
+	case INTEL_FAM6_NEHALEM_EX:
+
+	case INTEL_FAM6_WESTMERE:
+	case INTEL_FAM6_WESTMERE_EP:
+	case INTEL_FAM6_WESTMERE_EX:
+		if (idx == PERF_CSTATE_CORE_C3_RES ||
+		    idx == PERF_CSTATE_CORE_C6_RES ||
+		    idx == PERF_CSTATE_CORE_C7_RES)
+			return true;
+		break;
+	case INTEL_FAM6_SANDYBRIDGE:
+	case INTEL_FAM6_SANDYBRIDGE_X:
+
+	case INTEL_FAM6_IVYBRIDGE:
+	case INTEL_FAM6_IVYBRIDGE_X:
+
+	case INTEL_FAM6_HASWELL_CORE:
+	case INTEL_FAM6_HASWELL_X:
+	case INTEL_FAM6_HASWELL_GT3E:
+
+	case INTEL_FAM6_BROADWELL_CORE:
+	case INTEL_FAM6_BROADWELL_XEON_D:
+	case INTEL_FAM6_BROADWELL_GT3E:
+	case INTEL_FAM6_BROADWELL_X:
+
+	case INTEL_FAM6_SKYLAKE_MOBILE:
+	case INTEL_FAM6_SKYLAKE_DESKTOP:
+		if (idx == PERF_CSTATE_PKG_C2_RES ||
+		    idx == PERF_CSTATE_PKG_C3_RES ||
+		    idx == PERF_CSTATE_PKG_C6_RES ||
+		    idx == PERF_CSTATE_PKG_C7_RES)
+			return true;
+		break;
+	case INTEL_FAM6_ATOM_SILVERMONT:
+	case INTEL_FAM6_ATOM_SILVERMONT_X:
+	case INTEL_FAM6_ATOM_AIRMONT:
+		if (idx == PERF_CSTATE_CORE_C6_RES)
+			return true;
+		break;
+	case INTEL_FAM6_HASWELL_ULT:
+		if (idx == PERF_CSTATE_PKG_C2_RES ||
+		    idx == PERF_CSTATE_PKG_C3_RES ||
+		    idx == PERF_CSTATE_PKG_C6_RES ||
+		    idx == PERF_CSTATE_PKG_C7_RES ||
+		    idx == PERF_CSTATE_PKG_C8_RES ||
+		    idx == PERF_CSTATE_PKG_C9_RES ||
+		    idx == PERF_CSTATE_PKG_C10_RES)
+			return true;
+		break;
+	}
+
+	return false;
+}
+
+PMU_EVENT_ATTR_STRING(c2-residency, evattr_cstate_pkg_c2, "event=0x00");
+PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_pkg_c3, "event=0x01");
+PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_pkg_c6, "event=0x02");
+PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_pkg_c7, "event=0x03");
+PMU_EVENT_ATTR_STRING(c8-residency, evattr_cstate_pkg_c8, "event=0x04");
+PMU_EVENT_ATTR_STRING(c9-residency, evattr_cstate_pkg_c9, "event=0x05");
+PMU_EVENT_ATTR_STRING(c10-residency, evattr_cstate_pkg_c10, "event=0x06");
+
+static struct perf_cstate_msr pkg_msr[] = {
+	[PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY,	&evattr_cstate_pkg_c2,	test_pkg, },
+	[PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY,	&evattr_cstate_pkg_c3,	test_pkg, },
+	[PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY,	&evattr_cstate_pkg_c6,	test_pkg, },
+	[PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY,	&evattr_cstate_pkg_c7,	test_pkg, },
+	[PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY,	&evattr_cstate_pkg_c8,	test_pkg, },
+	[PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY,	&evattr_cstate_pkg_c9,	test_pkg, },
+	[PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY,	&evattr_cstate_pkg_c10,	test_pkg, },
+};
+
+static struct attribute *pkg_events_attrs[PERF_CSTATE_PKG_EVENT_MAX + 1] = {
+	NULL,
+};
+
+static struct attribute_group pkg_events_attr_group = {
+	.name = "events",
+	.attrs = pkg_events_attrs,
+};
+
+DEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63");
+static struct attribute *pkg_format_attrs[] = {
+	&format_attr_pkg_event.attr,
+	NULL,
+};
+static struct attribute_group pkg_format_attr_group = {
+	.name = "format",
+	.attrs = pkg_format_attrs,
+};
+
+static cpumask_t cstate_pkg_cpu_mask;
+
+static const struct attribute_group *pkg_attr_groups[] = {
+	&pkg_events_attr_group,
+	&pkg_format_attr_group,
+	&cpumask_attr_group,
+	NULL,
+};
+
+/* cstate_pkg PMU end*/
+
+static ssize_t cstate_get_attr_cpumask(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct pmu *pmu = dev_get_drvdata(dev);
+
+	if (pmu == &cstate_core_pmu)
+		return cpumap_print_to_pagebuf(true, buf, &cstate_core_cpu_mask);
+	else if (pmu == &cstate_pkg_pmu)
+		return cpumap_print_to_pagebuf(true, buf, &cstate_pkg_cpu_mask);
+	else
+		return 0;
+}
+
+static int cstate_pmu_event_init(struct perf_event *event)
+{
+	u64 cfg = event->attr.config;
+	int ret = 0;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/* unsupported modes and filters */
+	if (event->attr.exclude_user   ||
+	    event->attr.exclude_kernel ||
+	    event->attr.exclude_hv     ||
+	    event->attr.exclude_idle   ||
+	    event->attr.exclude_host   ||
+	    event->attr.exclude_guest  ||
+	    event->attr.sample_period) /* no sampling */
+		return -EINVAL;
+
+	if (event->pmu == &cstate_core_pmu) {
+		if (cfg >= PERF_CSTATE_CORE_EVENT_MAX)
+			return -EINVAL;
+		if (!core_msr[cfg].attr)
+			return -EINVAL;
+		event->hw.event_base = core_msr[cfg].msr;
+	} else if (event->pmu == &cstate_pkg_pmu) {
+		if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
+			return -EINVAL;
+		cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_PKG_EVENT_MAX);
+		if (!pkg_msr[cfg].attr)
+			return -EINVAL;
+		event->hw.event_base = pkg_msr[cfg].msr;
+	} else
+		return -ENOENT;
+
+	/* must be done before validate_group */
+	event->hw.config = cfg;
+	event->hw.idx = -1;
+
+	return ret;
+}
+
+static inline u64 cstate_pmu_read_counter(struct perf_event *event)
+{
+	u64 val;
+
+	rdmsrl(event->hw.event_base, val);
+	return val;
+}
+
+static void cstate_pmu_event_update(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 prev_raw_count, new_raw_count;
+
+again:
+	prev_raw_count = local64_read(&hwc->prev_count);
+	new_raw_count = cstate_pmu_read_counter(event);
+
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+			    new_raw_count) != prev_raw_count)
+		goto again;
+
+	local64_add(new_raw_count - prev_raw_count, &event->count);
+}
+
+static void cstate_pmu_event_start(struct perf_event *event, int mode)
+{
+	local64_set(&event->hw.prev_count, cstate_pmu_read_counter(event));
+}
+
+static void cstate_pmu_event_stop(struct perf_event *event, int mode)
+{
+	cstate_pmu_event_update(event);
+}
+
+static void cstate_pmu_event_del(struct perf_event *event, int mode)
+{
+	cstate_pmu_event_stop(event, PERF_EF_UPDATE);
+}
+
+static int cstate_pmu_event_add(struct perf_event *event, int mode)
+{
+	if (mode & PERF_EF_START)
+		cstate_pmu_event_start(event, mode);
+
+	return 0;
+}
+
+static void cstate_cpu_exit(int cpu)
+{
+	int i, id, target;
+
+	/* cpu exit for cstate core */
+	if (has_cstate_core) {
+		id = topology_core_id(cpu);
+		target = -1;
+
+		for_each_online_cpu(i) {
+			if (i == cpu)
+				continue;
+			if (id == topology_core_id(i)) {
+				target = i;
+				break;
+			}
+		}
+		if (cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask) && target >= 0)
+			cpumask_set_cpu(target, &cstate_core_cpu_mask);
+		WARN_ON(cpumask_empty(&cstate_core_cpu_mask));
+		if (target >= 0)
+			perf_pmu_migrate_context(&cstate_core_pmu, cpu, target);
+	}
+
+	/* cpu exit for cstate pkg */
+	if (has_cstate_pkg) {
+		id = topology_physical_package_id(cpu);
+		target = -1;
+
+		for_each_online_cpu(i) {
+			if (i == cpu)
+				continue;
+			if (id == topology_physical_package_id(i)) {
+				target = i;
+				break;
+			}
+		}
+		if (cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask) && target >= 0)
+			cpumask_set_cpu(target, &cstate_pkg_cpu_mask);
+		WARN_ON(cpumask_empty(&cstate_pkg_cpu_mask));
+		if (target >= 0)
+			perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target);
+	}
+}
+
+static void cstate_cpu_init(int cpu)
+{
+	int i, id;
+
+	/* cpu init for cstate core */
+	if (has_cstate_core) {
+		id = topology_core_id(cpu);
+		for_each_cpu(i, &cstate_core_cpu_mask) {
+			if (id == topology_core_id(i))
+				break;
+		}
+		if (i >= nr_cpu_ids)
+			cpumask_set_cpu(cpu, &cstate_core_cpu_mask);
+	}
+
+	/* cpu init for cstate pkg */
+	if (has_cstate_pkg) {
+		id = topology_physical_package_id(cpu);
+		for_each_cpu(i, &cstate_pkg_cpu_mask) {
+			if (id == topology_physical_package_id(i))
+				break;
+		}
+		if (i >= nr_cpu_ids)
+			cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
+	}
+}
+
+static int cstate_cpu_notifier(struct notifier_block *self,
+				  unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (long)hcpu;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		break;
+	case CPU_STARTING:
+		cstate_cpu_init(cpu);
+		break;
+	case CPU_UP_CANCELED:
+	case CPU_DYING:
+		break;
+	case CPU_ONLINE:
+	case CPU_DEAD:
+		break;
+	case CPU_DOWN_PREPARE:
+		cstate_cpu_exit(cpu);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+/*
+ * Probe the cstate events and insert the available one into sysfs attrs
+ * Return false if there is no available events.
+ */
+static bool cstate_probe_msr(struct perf_cstate_msr *msr,
+			     struct attribute	**events_attrs,
+			     int max_event_nr)
+{
+	int i, j = 0;
+	u64 val;
+
+	/* Probe the cstate events. */
+	for (i = 0; i < max_event_nr; i++) {
+		if (!msr[i].test(i) || rdmsrl_safe(msr[i].msr, &val))
+			msr[i].attr = NULL;
+	}
+
+	/* List remaining events in the sysfs attrs. */
+	for (i = 0; i < max_event_nr; i++) {
+		if (msr[i].attr)
+			events_attrs[j++] = &msr[i].attr->attr.attr;
+	}
+	events_attrs[j] = NULL;
+
+	return (j > 0) ? true : false;
+}
+
+static int __init cstate_init(void)
+{
+	/* SLM has different MSR for PKG C6 */
+	switch (boot_cpu_data.x86_model) {
+	case INTEL_FAM6_ATOM_SILVERMONT:
+	case INTEL_FAM6_ATOM_SILVERMONT_X:
+	case INTEL_FAM6_ATOM_AIRMONT:
+		pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY;
+	}
+
+	if (cstate_probe_msr(core_msr, core_events_attrs, PERF_CSTATE_CORE_EVENT_MAX))
+		has_cstate_core = true;
+
+	if (cstate_probe_msr(pkg_msr, pkg_events_attrs, PERF_CSTATE_PKG_EVENT_MAX))
+		has_cstate_pkg = true;
+
+	return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV;
+}
+
+static void __init cstate_cpumask_init(void)
+{
+	int cpu;
+
+	cpu_notifier_register_begin();
+
+	for_each_online_cpu(cpu)
+		cstate_cpu_init(cpu);
+
+	__perf_cpu_notifier(cstate_cpu_notifier);
+
+	cpu_notifier_register_done();
+}
+
+static struct pmu cstate_core_pmu = {
+	.attr_groups	= core_attr_groups,
+	.name		= "cstate_core",
+	.task_ctx_nr	= perf_invalid_context,
+	.event_init	= cstate_pmu_event_init,
+	.add		= cstate_pmu_event_add, /* must have */
+	.del		= cstate_pmu_event_del, /* must have */
+	.start		= cstate_pmu_event_start,
+	.stop		= cstate_pmu_event_stop,
+	.read		= cstate_pmu_event_update,
+	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+};
+
+static struct pmu cstate_pkg_pmu = {
+	.attr_groups	= pkg_attr_groups,
+	.name		= "cstate_pkg",
+	.task_ctx_nr	= perf_invalid_context,
+	.event_init	= cstate_pmu_event_init,
+	.add		= cstate_pmu_event_add, /* must have */
+	.del		= cstate_pmu_event_del, /* must have */
+	.start		= cstate_pmu_event_start,
+	.stop		= cstate_pmu_event_stop,
+	.read		= cstate_pmu_event_update,
+	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+};
+
+static void __init cstate_pmus_register(void)
+{
+	int err;
+
+	if (has_cstate_core) {
+		err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, -1);
+		if (WARN_ON(err))
+			pr_info("Failed to register PMU %s error %d\n",
+				cstate_core_pmu.name, err);
+	}
+
+	if (has_cstate_pkg) {
+		err = perf_pmu_register(&cstate_pkg_pmu, cstate_pkg_pmu.name, -1);
+		if (WARN_ON(err))
+			pr_info("Failed to register PMU %s error %d\n",
+				cstate_pkg_pmu.name, err);
+	}
+}
+
+static int __init cstate_pmu_init(void)
+{
+	int err;
+
+	if (cpu_has_hypervisor)
+		return -ENODEV;
+
+	err = cstate_init();
+	if (err)
+		return err;
+
+	cstate_cpumask_init();
+
+	cstate_pmus_register();
+
+	return 0;
+}
+
+device_initcall(cstate_pmu_init);
--- linux-4.4.0.orig/arch/x86/events/intel/ds.c
+++ linux-4.4.0/arch/x86/events/intel/ds.c
@@ -0,0 +1,1403 @@
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include <asm/kaiser.h>
+#include <asm/perf_event.h>
+#include <asm/insn.h>
+
+#include "../perf_event.h"
+
+static
+DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct debug_store, cpu_debug_store);
+
+/* The size of a BTS record in bytes: */
+#define BTS_RECORD_SIZE		24
+
+#define BTS_BUFFER_SIZE		(PAGE_SIZE << 4)
+#define PEBS_BUFFER_SIZE	(PAGE_SIZE << 4)
+#define PEBS_FIXUP_SIZE		PAGE_SIZE
+
+/*
+ * pebs_record_32 for p4 and core not supported
+
+struct pebs_record_32 {
+	u32 flags, ip;
+	u32 ax, bc, cx, dx;
+	u32 si, di, bp, sp;
+};
+
+ */
+
+union intel_x86_pebs_dse {
+	u64 val;
+	struct {
+		unsigned int ld_dse:4;
+		unsigned int ld_stlb_miss:1;
+		unsigned int ld_locked:1;
+		unsigned int ld_reserved:26;
+	};
+	struct {
+		unsigned int st_l1d_hit:1;
+		unsigned int st_reserved1:3;
+		unsigned int st_stlb_miss:1;
+		unsigned int st_locked:1;
+		unsigned int st_reserved2:26;
+	};
+};
+
+
+/*
+ * Map PEBS Load Latency Data Source encodings to generic
+ * memory data source information
+ */
+#define P(a, b) PERF_MEM_S(a, b)
+#define OP_LH (P(OP, LOAD) | P(LVL, HIT))
+#define SNOOP_NONE_MISS (P(SNOOP, NONE) | P(SNOOP, MISS))
+
+/* Version for Sandy Bridge and later */
+static u64 pebs_data_source[] = {
+	P(OP, LOAD) | P(LVL, MISS) | P(LVL, L3) | P(SNOOP, NA),/* 0x00:ukn L3 */
+	OP_LH | P(LVL, L1)  | P(SNOOP, NONE),	/* 0x01: L1 local */
+	OP_LH | P(LVL, LFB) | P(SNOOP, NONE),	/* 0x02: LFB hit */
+	OP_LH | P(LVL, L2)  | P(SNOOP, NONE),	/* 0x03: L2 hit */
+	OP_LH | P(LVL, L3)  | P(SNOOP, NONE),	/* 0x04: L3 hit */
+	OP_LH | P(LVL, L3)  | P(SNOOP, MISS),	/* 0x05: L3 hit, snoop miss */
+	OP_LH | P(LVL, L3)  | P(SNOOP, HIT),	/* 0x06: L3 hit, snoop hit */
+	OP_LH | P(LVL, L3)  | P(SNOOP, HITM),	/* 0x07: L3 hit, snoop hitm */
+	OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HIT),  /* 0x08: L3 miss snoop hit */
+	OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HITM), /* 0x09: L3 miss snoop hitm*/
+	OP_LH | P(LVL, LOC_RAM)  | P(SNOOP, HIT),  /* 0x0a: L3 miss, shared */
+	OP_LH | P(LVL, REM_RAM1) | P(SNOOP, HIT),  /* 0x0b: L3 miss, shared */
+	OP_LH | P(LVL, LOC_RAM)  | SNOOP_NONE_MISS,/* 0x0c: L3 miss, excl */
+	OP_LH | P(LVL, REM_RAM1) | SNOOP_NONE_MISS,/* 0x0d: L3 miss, excl */
+	OP_LH | P(LVL, IO)  | P(SNOOP, NONE), /* 0x0e: I/O */
+	OP_LH | P(LVL, UNC) | P(SNOOP, NONE), /* 0x0f: uncached */
+};
+
+/* Patch up minor differences in the bits */
+void __init intel_pmu_pebs_data_source_nhm(void)
+{
+	pebs_data_source[0x05] = OP_LH | P(LVL, L3)  | P(SNOOP, HIT);
+	pebs_data_source[0x06] = OP_LH | P(LVL, L3)  | P(SNOOP, HITM);
+	pebs_data_source[0x07] = OP_LH | P(LVL, L3)  | P(SNOOP, HITM);
+}
+
+static u64 precise_store_data(u64 status)
+{
+	union intel_x86_pebs_dse dse;
+	u64 val = P(OP, STORE) | P(SNOOP, NA) | P(LVL, L1) | P(TLB, L2);
+
+	dse.val = status;
+
+	/*
+	 * bit 4: TLB access
+	 * 1 = stored missed 2nd level TLB
+	 *
+	 * so it either hit the walker or the OS
+	 * otherwise hit 2nd level TLB
+	 */
+	if (dse.st_stlb_miss)
+		val |= P(TLB, MISS);
+	else
+		val |= P(TLB, HIT);
+
+	/*
+	 * bit 0: hit L1 data cache
+	 * if not set, then all we know is that
+	 * it missed L1D
+	 */
+	if (dse.st_l1d_hit)
+		val |= P(LVL, HIT);
+	else
+		val |= P(LVL, MISS);
+
+	/*
+	 * bit 5: Locked prefix
+	 */
+	if (dse.st_locked)
+		val |= P(LOCK, LOCKED);
+
+	return val;
+}
+
+static u64 precise_datala_hsw(struct perf_event *event, u64 status)
+{
+	union perf_mem_data_src dse;
+
+	dse.val = PERF_MEM_NA;
+
+	if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
+		dse.mem_op = PERF_MEM_OP_STORE;
+	else if (event->hw.flags & PERF_X86_EVENT_PEBS_LD_HSW)
+		dse.mem_op = PERF_MEM_OP_LOAD;
+
+	/*
+	 * L1 info only valid for following events:
+	 *
+	 * MEM_UOPS_RETIRED.STLB_MISS_STORES
+	 * MEM_UOPS_RETIRED.LOCK_STORES
+	 * MEM_UOPS_RETIRED.SPLIT_STORES
+	 * MEM_UOPS_RETIRED.ALL_STORES
+	 */
+	if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) {
+		if (status & 1)
+			dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
+		else
+			dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS;
+	}
+	return dse.val;
+}
+
+static u64 load_latency_data(u64 status)
+{
+	union intel_x86_pebs_dse dse;
+	u64 val;
+	int model = boot_cpu_data.x86_model;
+	int fam = boot_cpu_data.x86;
+
+	dse.val = status;
+
+	/*
+	 * use the mapping table for bit 0-3
+	 */
+	val = pebs_data_source[dse.ld_dse];
+
+	/*
+	 * Nehalem models do not support TLB, Lock infos
+	 */
+	if (fam == 0x6 && (model == 26 || model == 30
+	    || model == 31 || model == 46)) {
+		val |= P(TLB, NA) | P(LOCK, NA);
+		return val;
+	}
+	/*
+	 * bit 4: TLB access
+	 * 0 = did not miss 2nd level TLB
+	 * 1 = missed 2nd level TLB
+	 */
+	if (dse.ld_stlb_miss)
+		val |= P(TLB, MISS) | P(TLB, L2);
+	else
+		val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2);
+
+	/*
+	 * bit 5: locked prefix
+	 */
+	if (dse.ld_locked)
+		val |= P(LOCK, LOCKED);
+
+	return val;
+}
+
+struct pebs_record_core {
+	u64 flags, ip;
+	u64 ax, bx, cx, dx;
+	u64 si, di, bp, sp;
+	u64 r8,  r9,  r10, r11;
+	u64 r12, r13, r14, r15;
+};
+
+struct pebs_record_nhm {
+	u64 flags, ip;
+	u64 ax, bx, cx, dx;
+	u64 si, di, bp, sp;
+	u64 r8,  r9,  r10, r11;
+	u64 r12, r13, r14, r15;
+	u64 status, dla, dse, lat;
+};
+
+/*
+ * Same as pebs_record_nhm, with two additional fields.
+ */
+struct pebs_record_hsw {
+	u64 flags, ip;
+	u64 ax, bx, cx, dx;
+	u64 si, di, bp, sp;
+	u64 r8,  r9,  r10, r11;
+	u64 r12, r13, r14, r15;
+	u64 status, dla, dse, lat;
+	u64 real_ip, tsx_tuning;
+};
+
+union hsw_tsx_tuning {
+	struct {
+		u32 cycles_last_block     : 32,
+		    hle_abort		  : 1,
+		    rtm_abort		  : 1,
+		    instruction_abort     : 1,
+		    non_instruction_abort : 1,
+		    retry		  : 1,
+		    data_conflict	  : 1,
+		    capacity_writes	  : 1,
+		    capacity_reads	  : 1;
+	};
+	u64	    value;
+};
+
+#define PEBS_HSW_TSX_FLAGS	0xff00000000ULL
+
+/* Same as HSW, plus TSC */
+
+struct pebs_record_skl {
+	u64 flags, ip;
+	u64 ax, bx, cx, dx;
+	u64 si, di, bp, sp;
+	u64 r8,  r9,  r10, r11;
+	u64 r12, r13, r14, r15;
+	u64 status, dla, dse, lat;
+	u64 real_ip, tsx_tuning;
+	u64 tsc;
+};
+
+void init_debug_store_on_cpu(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+	if (!ds)
+		return;
+
+	wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA,
+		     (u32)((u64)(unsigned long)ds),
+		     (u32)((u64)(unsigned long)ds >> 32));
+}
+
+void fini_debug_store_on_cpu(int cpu)
+{
+	if (!per_cpu(cpu_hw_events, cpu).ds)
+		return;
+
+	wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
+}
+
+static DEFINE_PER_CPU(void *, insn_buffer);
+
+static void *dsalloc(size_t size, gfp_t flags, int node)
+{
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	unsigned int order = get_order(size);
+	struct page *page;
+	unsigned long addr;
+
+	page = __alloc_pages_node(node, flags | __GFP_ZERO, order);
+	if (!page)
+		return NULL;
+	addr = (unsigned long)page_address(page);
+	if (kaiser_add_mapping(addr, size, __PAGE_KERNEL) < 0) {
+		__free_pages(page, order);
+		addr = 0;
+	}
+	return (void *)addr;
+#else
+	return kmalloc_node(size, flags | __GFP_ZERO, node);
+#endif
+}
+
+static void dsfree(const void *buffer, size_t size)
+{
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	if (!buffer)
+		return;
+	kaiser_remove_mapping((unsigned long)buffer, size);
+	free_pages((unsigned long)buffer, get_order(size));
+#else
+	kfree(buffer);
+#endif
+}
+
+static int alloc_pebs_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+	int node = cpu_to_node(cpu);
+	int max;
+	void *buffer, *ibuffer;
+
+	if (!x86_pmu.pebs)
+		return 0;
+
+	buffer = dsalloc(x86_pmu.pebs_buffer_size, GFP_KERNEL, node);
+	if (unlikely(!buffer))
+		return -ENOMEM;
+
+	/*
+	 * HSW+ already provides us the eventing ip; no need to allocate this
+	 * buffer then.
+	 */
+	if (x86_pmu.intel_cap.pebs_format < 2) {
+		ibuffer = kzalloc_node(PEBS_FIXUP_SIZE, GFP_KERNEL, node);
+		if (!ibuffer) {
+			dsfree(buffer, x86_pmu.pebs_buffer_size);
+			return -ENOMEM;
+		}
+		per_cpu(insn_buffer, cpu) = ibuffer;
+	}
+
+	max = x86_pmu.pebs_buffer_size / x86_pmu.pebs_record_size;
+
+	ds->pebs_buffer_base = (u64)(unsigned long)buffer;
+	ds->pebs_index = ds->pebs_buffer_base;
+	ds->pebs_absolute_maximum = ds->pebs_buffer_base +
+		max * x86_pmu.pebs_record_size;
+
+	return 0;
+}
+
+static void release_pebs_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+	if (!ds || !x86_pmu.pebs)
+		return;
+
+	kfree(per_cpu(insn_buffer, cpu));
+	per_cpu(insn_buffer, cpu) = NULL;
+
+	dsfree((void *)(unsigned long)ds->pebs_buffer_base,
+			x86_pmu.pebs_buffer_size);
+	ds->pebs_buffer_base = 0;
+}
+
+static int alloc_bts_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+	int node = cpu_to_node(cpu);
+	int max, thresh;
+	void *buffer;
+
+	if (!x86_pmu.bts)
+		return 0;
+
+	buffer = dsalloc(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_NOWARN, node);
+	if (unlikely(!buffer)) {
+		WARN_ONCE(1, "%s: BTS buffer allocation failure\n", __func__);
+		return -ENOMEM;
+	}
+
+	max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
+	thresh = max / 16;
+
+	ds->bts_buffer_base = (u64)(unsigned long)buffer;
+	ds->bts_index = ds->bts_buffer_base;
+	ds->bts_absolute_maximum = ds->bts_buffer_base +
+		max * BTS_RECORD_SIZE;
+	ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
+		thresh * BTS_RECORD_SIZE;
+
+	return 0;
+}
+
+static void release_bts_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+	if (!ds || !x86_pmu.bts)
+		return;
+
+	dsfree((void *)(unsigned long)ds->bts_buffer_base, BTS_BUFFER_SIZE);
+	ds->bts_buffer_base = 0;
+}
+
+static int alloc_ds_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu_ptr(&cpu_debug_store, cpu);
+
+	memset(ds, 0, sizeof(*ds));
+	per_cpu(cpu_hw_events, cpu).ds = ds;
+
+	return 0;
+}
+
+static void release_ds_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+	if (!ds)
+		return;
+
+	per_cpu(cpu_hw_events, cpu).ds = NULL;
+}
+
+void release_ds_buffers(void)
+{
+	int cpu;
+
+	if (!x86_pmu.bts && !x86_pmu.pebs)
+		return;
+
+	get_online_cpus();
+	for_each_online_cpu(cpu)
+		fini_debug_store_on_cpu(cpu);
+
+	for_each_possible_cpu(cpu) {
+		release_pebs_buffer(cpu);
+		release_bts_buffer(cpu);
+		release_ds_buffer(cpu);
+	}
+	put_online_cpus();
+}
+
+void reserve_ds_buffers(void)
+{
+	int bts_err = 0, pebs_err = 0;
+	int cpu;
+
+	x86_pmu.bts_active = 0;
+	x86_pmu.pebs_active = 0;
+
+	if (!x86_pmu.bts && !x86_pmu.pebs)
+		return;
+
+	if (!x86_pmu.bts)
+		bts_err = 1;
+
+	if (!x86_pmu.pebs)
+		pebs_err = 1;
+
+	get_online_cpus();
+
+	for_each_possible_cpu(cpu) {
+		if (alloc_ds_buffer(cpu)) {
+			bts_err = 1;
+			pebs_err = 1;
+		}
+
+		if (!bts_err && alloc_bts_buffer(cpu))
+			bts_err = 1;
+
+		if (!pebs_err && alloc_pebs_buffer(cpu))
+			pebs_err = 1;
+
+		if (bts_err && pebs_err)
+			break;
+	}
+
+	if (bts_err) {
+		for_each_possible_cpu(cpu)
+			release_bts_buffer(cpu);
+	}
+
+	if (pebs_err) {
+		for_each_possible_cpu(cpu)
+			release_pebs_buffer(cpu);
+	}
+
+	if (bts_err && pebs_err) {
+		for_each_possible_cpu(cpu)
+			release_ds_buffer(cpu);
+	} else {
+		if (x86_pmu.bts && !bts_err)
+			x86_pmu.bts_active = 1;
+
+		if (x86_pmu.pebs && !pebs_err)
+			x86_pmu.pebs_active = 1;
+
+		for_each_online_cpu(cpu)
+			init_debug_store_on_cpu(cpu);
+	}
+
+	put_online_cpus();
+}
+
+/*
+ * BTS
+ */
+
+struct event_constraint bts_constraint =
+	EVENT_CONSTRAINT(0, 1ULL << INTEL_PMC_IDX_FIXED_BTS, 0);
+
+void intel_pmu_enable_bts(u64 config)
+{
+	unsigned long debugctlmsr;
+
+	debugctlmsr = get_debugctlmsr();
+
+	debugctlmsr |= DEBUGCTLMSR_TR;
+	debugctlmsr |= DEBUGCTLMSR_BTS;
+	if (config & ARCH_PERFMON_EVENTSEL_INT)
+		debugctlmsr |= DEBUGCTLMSR_BTINT;
+
+	if (!(config & ARCH_PERFMON_EVENTSEL_OS))
+		debugctlmsr |= DEBUGCTLMSR_BTS_OFF_OS;
+
+	if (!(config & ARCH_PERFMON_EVENTSEL_USR))
+		debugctlmsr |= DEBUGCTLMSR_BTS_OFF_USR;
+
+	update_debugctlmsr(debugctlmsr);
+}
+
+void intel_pmu_disable_bts(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	unsigned long debugctlmsr;
+
+	if (!cpuc->ds)
+		return;
+
+	debugctlmsr = get_debugctlmsr();
+
+	debugctlmsr &=
+		~(DEBUGCTLMSR_TR | DEBUGCTLMSR_BTS | DEBUGCTLMSR_BTINT |
+		  DEBUGCTLMSR_BTS_OFF_OS | DEBUGCTLMSR_BTS_OFF_USR);
+
+	update_debugctlmsr(debugctlmsr);
+}
+
+int intel_pmu_drain_bts_buffer(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct debug_store *ds = cpuc->ds;
+	struct bts_record {
+		u64	from;
+		u64	to;
+		u64	flags;
+	};
+	struct perf_event *event = cpuc->events[INTEL_PMC_IDX_FIXED_BTS];
+	struct bts_record *at, *base, *top;
+	struct perf_output_handle handle;
+	struct perf_event_header header;
+	struct perf_sample_data data;
+	unsigned long skip = 0;
+	struct pt_regs regs;
+
+	if (!event)
+		return 0;
+
+	if (!x86_pmu.bts_active)
+		return 0;
+
+	base = (struct bts_record *)(unsigned long)ds->bts_buffer_base;
+	top  = (struct bts_record *)(unsigned long)ds->bts_index;
+
+	if (top <= base)
+		return 0;
+
+	memset(&regs, 0, sizeof(regs));
+
+	ds->bts_index = ds->bts_buffer_base;
+
+	perf_sample_data_init(&data, 0, event->hw.last_period);
+
+	/*
+	 * BTS leaks kernel addresses in branches across the cpl boundary,
+	 * such as traps or system calls, so unless the user is asking for
+	 * kernel tracing (and right now it's not possible), we'd need to
+	 * filter them out. But first we need to count how many of those we
+	 * have in the current batch. This is an extra O(n) pass, however,
+	 * it's much faster than the other one especially considering that
+	 * n <= 2560 (BTS_BUFFER_SIZE / BTS_RECORD_SIZE * 15/16; see the
+	 * alloc_bts_buffer()).
+	 */
+	for (at = base; at < top; at++) {
+		/*
+		 * Note that right now *this* BTS code only works if
+		 * attr::exclude_kernel is set, but let's keep this extra
+		 * check here in case that changes.
+		 */
+		if (event->attr.exclude_kernel &&
+		    (kernel_ip(at->from) || kernel_ip(at->to)))
+			skip++;
+	}
+
+	/*
+	 * Prepare a generic sample, i.e. fill in the invariant fields.
+	 * We will overwrite the from and to address before we output
+	 * the sample.
+	 */
+	perf_prepare_sample(&header, &data, event, &regs);
+
+	if (perf_output_begin(&handle, event, header.size *
+			      (top - base - skip)))
+		return 1;
+
+	for (at = base; at < top; at++) {
+		/* Filter out any records that contain kernel addresses. */
+		if (event->attr.exclude_kernel &&
+		    (kernel_ip(at->from) || kernel_ip(at->to)))
+			continue;
+
+		data.ip		= at->from;
+		data.addr	= at->to;
+
+		perf_output_sample(&handle, &header, &data, event);
+	}
+
+	perf_output_end(&handle);
+
+	/* There's new data available. */
+	event->hw.interrupts++;
+	event->pending_kill = POLL_IN;
+	return 1;
+}
+
+static inline void intel_pmu_drain_pebs_buffer(void)
+{
+	struct pt_regs regs;
+
+	x86_pmu.drain_pebs(&regs);
+}
+
+void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in)
+{
+	if (!sched_in)
+		intel_pmu_drain_pebs_buffer();
+}
+
+/*
+ * PEBS
+ */
+struct event_constraint intel_core2_pebs_event_constraints[] = {
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */
+	/* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x01),
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_atom_pebs_event_constraints[] = {
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */
+	/* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x01),
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_slm_pebs_event_constraints[] = {
+	/* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x1),
+	/* Allow all events as PEBS with no flags */
+	INTEL_ALL_EVENT_CONSTRAINT(0, 0x1),
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_nehalem_pebs_event_constraints[] = {
+	INTEL_PLD_CONSTRAINT(0x100b, 0xf),      /* MEM_INST_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf),    /* MEM_UNCORE_RETIRED.* */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf),    /* INST_RETIRED.ANY */
+	INTEL_EVENT_CONSTRAINT(0xc2, 0xf),    /* UOPS_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf),    /* SSEX_UOPS_RETIRED.* */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf),    /* MEM_LOAD_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf),    /* FP_ASSIST.* */
+	/* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x0f),
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_westmere_pebs_event_constraints[] = {
+	INTEL_PLD_CONSTRAINT(0x100b, 0xf),      /* MEM_INST_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf),    /* MEM_UNCORE_RETIRED.* */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf),    /* INSTR_RETIRED.* */
+	INTEL_EVENT_CONSTRAINT(0xc2, 0xf),    /* UOPS_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xc5, 0xf),    /* BR_MISP_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf),    /* SSEX_UOPS_RETIRED.* */
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf),    /* MEM_LOAD_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf),    /* FP_ASSIST.* */
+	/* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x0f),
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_snb_pebs_event_constraints[] = {
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+	INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
+	INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
+	/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+        INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
+        INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
+        INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+        INTEL_EXCLEVT_CONSTRAINT(0xd3, 0xf),    /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+	/* Allow all events as PEBS with no flags */
+	INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_ivb_pebs_event_constraints[] = {
+        INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+        INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
+	INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
+	/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+	INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+	INTEL_EXCLEVT_CONSTRAINT(0xd3, 0xf),    /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+	/* Allow all events as PEBS with no flags */
+	INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
+        EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_hsw_pebs_event_constraints[] = {
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+	INTEL_PLD_CONSTRAINT(0x01cd, 0xf),    /* MEM_TRANS_RETIRED.* */
+	/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST(0x12d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_STORES */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST(0x42d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_STORES */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */
+	INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD(0xd2, 0xf),    /* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD(0xd3, 0xf),    /* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */
+	/* Allow all events as PEBS with no flags */
+	INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint intel_skl_pebs_event_constraints[] = {
+	INTEL_FLAGS_UEVENT_CONSTRAINT(0x1c0, 0x2),	/* INST_RETIRED.PREC_DIST */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
+	/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+	INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+	INTEL_PLD_CONSTRAINT(0x1cd, 0xf),		      /* MEM_TRANS_RETIRED.* */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_INST_RETIRED.LOCK_LOADS */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x22d0, 0xf), /* MEM_INST_RETIRED.LOCK_STORES */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_INST_RETIRED.SPLIT_LOADS */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_INST_RETIRED.SPLIT_STORES */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_INST_RETIRED.ALL_LOADS */
+	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_INST_RETIRED.ALL_STORES */
+	INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd1, 0xf),    /* MEM_LOAD_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd2, 0xf),    /* MEM_LOAD_L3_HIT_RETIRED.* */
+	INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd3, 0xf),    /* MEM_LOAD_L3_MISS_RETIRED.* */
+	/* Allow all events as PEBS with no flags */
+	INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
+	EVENT_CONSTRAINT_END
+};
+
+struct event_constraint *intel_pebs_constraints(struct perf_event *event)
+{
+	struct event_constraint *c;
+
+	if (!event->attr.precise_ip)
+		return NULL;
+
+	if (x86_pmu.pebs_constraints) {
+		for_each_event_constraint(c, x86_pmu.pebs_constraints) {
+			if ((event->hw.config & c->cmask) == c->code) {
+				event->hw.flags |= c->flags;
+				return c;
+			}
+		}
+	}
+
+	return &emptyconstraint;
+}
+
+static inline bool pebs_is_enabled(struct cpu_hw_events *cpuc)
+{
+	return (cpuc->pebs_enabled & ((1ULL << MAX_PEBS_EVENTS) - 1));
+}
+
+void intel_pmu_pebs_enable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+	struct debug_store *ds = cpuc->ds;
+	bool first_pebs;
+	u64 threshold;
+
+	hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT;
+
+	first_pebs = !pebs_is_enabled(cpuc);
+	cpuc->pebs_enabled |= 1ULL << hwc->idx;
+
+	if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT)
+		cpuc->pebs_enabled |= 1ULL << (hwc->idx + 32);
+	else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
+		cpuc->pebs_enabled |= 1ULL << 63;
+
+	/*
+	 * When the event is constrained enough we can use a larger
+	 * threshold and run the event with less frequent PMI.
+	 */
+	if (hwc->flags & PERF_X86_EVENT_FREERUNNING) {
+		threshold = ds->pebs_absolute_maximum -
+			x86_pmu.max_pebs_events * x86_pmu.pebs_record_size;
+
+		if (first_pebs)
+			perf_sched_cb_inc(event->ctx->pmu);
+	} else {
+		threshold = ds->pebs_buffer_base + x86_pmu.pebs_record_size;
+
+		/*
+		 * If not all events can use larger buffer,
+		 * roll back to threshold = 1
+		 */
+		if (!first_pebs &&
+		    (ds->pebs_interrupt_threshold > threshold))
+			perf_sched_cb_dec(event->ctx->pmu);
+	}
+
+	/* Use auto-reload if possible to save a MSR write in the PMI */
+	if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) {
+		ds->pebs_event_reset[hwc->idx] =
+			(u64)(-hwc->sample_period) & x86_pmu.cntval_mask;
+	}
+
+	if (first_pebs || ds->pebs_interrupt_threshold > threshold)
+		ds->pebs_interrupt_threshold = threshold;
+}
+
+void intel_pmu_pebs_disable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+	struct debug_store *ds = cpuc->ds;
+	bool large_pebs = ds->pebs_interrupt_threshold >
+		ds->pebs_buffer_base + x86_pmu.pebs_record_size;
+
+	if (large_pebs)
+		intel_pmu_drain_pebs_buffer();
+
+	cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
+
+	if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT)
+		cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32));
+	else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
+		cpuc->pebs_enabled &= ~(1ULL << 63);
+
+	if (large_pebs && !pebs_is_enabled(cpuc))
+		perf_sched_cb_dec(event->ctx->pmu);
+
+	if (cpuc->enabled)
+		wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
+
+	hwc->config |= ARCH_PERFMON_EVENTSEL_INT;
+}
+
+void intel_pmu_pebs_enable_all(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	if (cpuc->pebs_enabled)
+		wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
+}
+
+void intel_pmu_pebs_disable_all(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	if (cpuc->pebs_enabled)
+		wrmsrl(MSR_IA32_PEBS_ENABLE, 0);
+}
+
+static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	unsigned long from = cpuc->lbr_entries[0].from;
+	unsigned long old_to, to = cpuc->lbr_entries[0].to;
+	unsigned long ip = regs->ip;
+	int is_64bit = 0;
+	void *kaddr;
+	int size;
+
+	/*
+	 * We don't need to fixup if the PEBS assist is fault like
+	 */
+	if (!x86_pmu.intel_cap.pebs_trap)
+		return 1;
+
+	/*
+	 * No LBR entry, no basic block, no rewinding
+	 */
+	if (!cpuc->lbr_stack.nr || !from || !to)
+		return 0;
+
+	/*
+	 * Basic blocks should never cross user/kernel boundaries
+	 */
+	if (kernel_ip(ip) != kernel_ip(to))
+		return 0;
+
+	/*
+	 * unsigned math, either ip is before the start (impossible) or
+	 * the basic block is larger than 1 page (sanity)
+	 */
+	if ((ip - to) > PEBS_FIXUP_SIZE)
+		return 0;
+
+	/*
+	 * We sampled a branch insn, rewind using the LBR stack
+	 */
+	if (ip == to) {
+		set_linear_ip(regs, from);
+		return 1;
+	}
+
+	size = ip - to;
+	if (!kernel_ip(ip)) {
+		int bytes;
+		u8 *buf = this_cpu_read(insn_buffer);
+
+		/* 'size' must fit our buffer, see above */
+		bytes = copy_from_user_nmi(buf, (void __user *)to, size);
+		if (bytes != 0)
+			return 0;
+
+		kaddr = buf;
+	} else {
+		kaddr = (void *)to;
+	}
+
+	do {
+		struct insn insn;
+
+		old_to = to;
+
+#ifdef CONFIG_X86_64
+		is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32);
+#endif
+		insn_init(&insn, kaddr, size, is_64bit);
+		insn_get_length(&insn);
+		/*
+		 * Make sure there was not a problem decoding the
+		 * instruction and getting the length.  This is
+		 * doubly important because we have an infinite
+		 * loop if insn.length=0.
+		 */
+		if (!insn.length)
+			break;
+
+		to += insn.length;
+		kaddr += insn.length;
+		size -= insn.length;
+	} while (to < ip);
+
+	if (to == ip) {
+		set_linear_ip(regs, old_to);
+		return 1;
+	}
+
+	/*
+	 * Even though we decoded the basic block, the instruction stream
+	 * never matched the given IP, either the TO or the IP got corrupted.
+	 */
+	return 0;
+}
+
+static inline u64 intel_hsw_weight(struct pebs_record_skl *pebs)
+{
+	if (pebs->tsx_tuning) {
+		union hsw_tsx_tuning tsx = { .value = pebs->tsx_tuning };
+		return tsx.cycles_last_block;
+	}
+	return 0;
+}
+
+static inline u64 intel_hsw_transaction(struct pebs_record_skl *pebs)
+{
+	u64 txn = (pebs->tsx_tuning & PEBS_HSW_TSX_FLAGS) >> 32;
+
+	/* For RTM XABORTs also log the abort code from AX */
+	if ((txn & PERF_TXN_TRANSACTION) && (pebs->ax & 1))
+		txn |= ((pebs->ax >> 24) & 0xff) << PERF_TXN_ABORT_SHIFT;
+	return txn;
+}
+
+static void setup_pebs_sample_data(struct perf_event *event,
+				   struct pt_regs *iregs, void *__pebs,
+				   struct perf_sample_data *data,
+				   struct pt_regs *regs)
+{
+#define PERF_X86_EVENT_PEBS_HSW_PREC \
+		(PERF_X86_EVENT_PEBS_ST_HSW | \
+		 PERF_X86_EVENT_PEBS_LD_HSW | \
+		 PERF_X86_EVENT_PEBS_NA_HSW)
+	/*
+	 * We cast to the biggest pebs_record but are careful not to
+	 * unconditionally access the 'extra' entries.
+	 */
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct pebs_record_skl *pebs = __pebs;
+	u64 sample_type;
+	int fll, fst, dsrc;
+	int fl = event->hw.flags;
+
+	if (pebs == NULL)
+		return;
+
+	sample_type = event->attr.sample_type;
+	dsrc = sample_type & PERF_SAMPLE_DATA_SRC;
+
+	fll = fl & PERF_X86_EVENT_PEBS_LDLAT;
+	fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC);
+
+	perf_sample_data_init(data, 0, event->hw.last_period);
+
+	data->period = event->hw.last_period;
+
+	/*
+	 * Use latency for weight (only avail with PEBS-LL)
+	 */
+	if (fll && (sample_type & PERF_SAMPLE_WEIGHT))
+		data->weight = pebs->lat;
+
+	/*
+	 * data.data_src encodes the data source
+	 */
+	if (dsrc) {
+		u64 val = PERF_MEM_NA;
+		if (fll)
+			val = load_latency_data(pebs->dse);
+		else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC))
+			val = precise_datala_hsw(event, pebs->dse);
+		else if (fst)
+			val = precise_store_data(pebs->dse);
+		data->data_src.val = val;
+	}
+
+	/*
+	 * We use the interrupt regs as a base because the PEBS record
+	 * does not contain a full regs set, specifically it seems to
+	 * lack segment descriptors, which get used by things like
+	 * user_mode().
+	 *
+	 * In the simple case fix up only the IP and BP,SP regs, for
+	 * PERF_SAMPLE_IP and PERF_SAMPLE_CALLCHAIN to function properly.
+	 * A possible PERF_SAMPLE_REGS will have to transfer all regs.
+	 */
+	*regs = *iregs;
+	regs->flags = pebs->flags;
+	set_linear_ip(regs, pebs->ip);
+	regs->bp = pebs->bp;
+	regs->sp = pebs->sp;
+
+	if (sample_type & PERF_SAMPLE_REGS_INTR) {
+		regs->ax = pebs->ax;
+		regs->bx = pebs->bx;
+		regs->cx = pebs->cx;
+		regs->dx = pebs->dx;
+		regs->si = pebs->si;
+		regs->di = pebs->di;
+		regs->bp = pebs->bp;
+		regs->sp = pebs->sp;
+
+		regs->flags = pebs->flags;
+#ifndef CONFIG_X86_32
+		regs->r8 = pebs->r8;
+		regs->r9 = pebs->r9;
+		regs->r10 = pebs->r10;
+		regs->r11 = pebs->r11;
+		regs->r12 = pebs->r12;
+		regs->r13 = pebs->r13;
+		regs->r14 = pebs->r14;
+		regs->r15 = pebs->r15;
+#endif
+	}
+
+	if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) {
+		regs->ip = pebs->real_ip;
+		regs->flags |= PERF_EFLAGS_EXACT;
+	} else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(regs))
+		regs->flags |= PERF_EFLAGS_EXACT;
+	else
+		regs->flags &= ~PERF_EFLAGS_EXACT;
+
+	if ((sample_type & PERF_SAMPLE_ADDR) &&
+	    x86_pmu.intel_cap.pebs_format >= 1)
+		data->addr = pebs->dla;
+
+	if (x86_pmu.intel_cap.pebs_format >= 2) {
+		/* Only set the TSX weight when no memory weight. */
+		if ((sample_type & PERF_SAMPLE_WEIGHT) && !fll)
+			data->weight = intel_hsw_weight(pebs);
+
+		if (sample_type & PERF_SAMPLE_TRANSACTION)
+			data->txn = intel_hsw_transaction(pebs);
+	}
+
+	/*
+	 * v3 supplies an accurate time stamp, so we use that
+	 * for the time stamp.
+	 *
+	 * We can only do this for the default trace clock.
+	 */
+	if (x86_pmu.intel_cap.pebs_format >= 3 &&
+		event->attr.use_clockid == 0)
+		data->time = native_sched_clock_from_tsc(pebs->tsc);
+
+	if (has_branch_stack(event))
+		data->br_stack = &cpuc->lbr_stack;
+}
+
+static inline void *
+get_next_pebs_record_by_bit(void *base, void *top, int bit)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	void *at;
+	u64 pebs_status;
+
+	/*
+	 * fmt0 does not have a status bitfield (does not use
+	 * perf_record_nhm format)
+	 */
+	if (x86_pmu.intel_cap.pebs_format < 1)
+		return base;
+
+	if (base == NULL)
+		return NULL;
+
+	for (at = base; at < top; at += x86_pmu.pebs_record_size) {
+		struct pebs_record_nhm *p = at;
+
+		if (test_bit(bit, (unsigned long *)&p->status)) {
+			/* PEBS v3 has accurate status bits */
+			if (x86_pmu.intel_cap.pebs_format >= 3)
+				return at;
+
+			if (p->status == (1 << bit))
+				return at;
+
+			/* clear non-PEBS bit and re-check */
+			pebs_status = p->status & cpuc->pebs_enabled;
+			pebs_status &= (1ULL << MAX_PEBS_EVENTS) - 1;
+			if (pebs_status == (1 << bit))
+				return at;
+		}
+	}
+	return NULL;
+}
+
+static void __intel_pmu_pebs_event(struct perf_event *event,
+				   struct pt_regs *iregs,
+				   void *base, void *top,
+				   int bit, int count)
+{
+	struct perf_sample_data data;
+	struct pt_regs regs;
+	void *at = get_next_pebs_record_by_bit(base, top, bit);
+
+	if (!intel_pmu_save_and_restart(event) &&
+	    !(event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD))
+		return;
+
+	while (count > 1) {
+		setup_pebs_sample_data(event, iregs, at, &data, &regs);
+		perf_event_output(event, &data, &regs);
+		at += x86_pmu.pebs_record_size;
+		at = get_next_pebs_record_by_bit(at, top, bit);
+		count--;
+	}
+
+	setup_pebs_sample_data(event, iregs, at, &data, &regs);
+
+	/*
+	 * All but the last records are processed.
+	 * The last one is left to be able to call the overflow handler.
+	 */
+	if (perf_event_overflow(event, &data, &regs)) {
+		x86_pmu_stop(event, 0);
+		return;
+	}
+
+}
+
+static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct debug_store *ds = cpuc->ds;
+	struct perf_event *event = cpuc->events[0]; /* PMC0 only */
+	struct pebs_record_core *at, *top;
+	int n;
+
+	if (!x86_pmu.pebs_active)
+		return;
+
+	at  = (struct pebs_record_core *)(unsigned long)ds->pebs_buffer_base;
+	top = (struct pebs_record_core *)(unsigned long)ds->pebs_index;
+
+	/*
+	 * Whatever else happens, drain the thing
+	 */
+	ds->pebs_index = ds->pebs_buffer_base;
+
+	if (!test_bit(0, cpuc->active_mask))
+		return;
+
+	WARN_ON_ONCE(!event);
+
+	if (!event->attr.precise_ip)
+		return;
+
+	n = top - at;
+	if (n <= 0)
+		return;
+
+	__intel_pmu_pebs_event(event, iregs, at, top, 0, n);
+}
+
+static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct debug_store *ds = cpuc->ds;
+	struct perf_event *event;
+	void *base, *at, *top;
+	short counts[MAX_PEBS_EVENTS] = {};
+	short error[MAX_PEBS_EVENTS] = {};
+	int bit, i;
+
+	if (!x86_pmu.pebs_active)
+		return;
+
+	base = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
+	top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index;
+
+	ds->pebs_index = ds->pebs_buffer_base;
+
+	if (unlikely(base >= top))
+		return;
+
+	for (at = base; at < top; at += x86_pmu.pebs_record_size) {
+		struct pebs_record_nhm *p = at;
+		u64 pebs_status;
+
+		/* PEBS v3 has accurate status bits */
+		if (x86_pmu.intel_cap.pebs_format >= 3) {
+			for_each_set_bit(bit, (unsigned long *)&p->status,
+					 MAX_PEBS_EVENTS)
+				counts[bit]++;
+
+			continue;
+		}
+
+		pebs_status = p->status & cpuc->pebs_enabled;
+		pebs_status &= (1ULL << x86_pmu.max_pebs_events) - 1;
+
+		bit = find_first_bit((unsigned long *)&pebs_status,
+					x86_pmu.max_pebs_events);
+		if (WARN(bit >= x86_pmu.max_pebs_events,
+			 "PEBS record without PEBS event! status=%Lx pebs_enabled=%Lx active_mask=%Lx",
+			 (unsigned long long)p->status, (unsigned long long)cpuc->pebs_enabled,
+			 *(unsigned long long *)cpuc->active_mask))
+			continue;
+
+		/*
+		 * The PEBS hardware does not deal well with the situation
+		 * when events happen near to each other and multiple bits
+		 * are set. But it should happen rarely.
+		 *
+		 * If these events include one PEBS and multiple non-PEBS
+		 * events, it doesn't impact PEBS record. The record will
+		 * be handled normally. (slow path)
+		 *
+		 * If these events include two or more PEBS events, the
+		 * records for the events can be collapsed into a single
+		 * one, and it's not possible to reconstruct all events
+		 * that caused the PEBS record. It's called collision.
+		 * If collision happened, the record will be dropped.
+		 */
+		if (p->status != (1ULL << bit)) {
+			for_each_set_bit(i, (unsigned long *)&pebs_status,
+					 x86_pmu.max_pebs_events)
+				error[i]++;
+			continue;
+		}
+
+		counts[bit]++;
+	}
+
+	for (bit = 0; bit < x86_pmu.max_pebs_events; bit++) {
+		if ((counts[bit] == 0) && (error[bit] == 0))
+			continue;
+
+		event = cpuc->events[bit];
+		WARN_ON_ONCE(!event);
+		WARN_ON_ONCE(!event->attr.precise_ip);
+
+		/* log dropped samples number */
+		if (error[bit])
+			perf_log_lost_samples(event, error[bit]);
+
+		if (counts[bit]) {
+			__intel_pmu_pebs_event(event, iregs, base,
+					       top, bit, counts[bit]);
+		}
+	}
+}
+
+/*
+ * BTS, PEBS probe and setup
+ */
+
+void __init intel_ds_init(void)
+{
+	/*
+	 * No support for 32bit formats
+	 */
+	if (!boot_cpu_has(X86_FEATURE_DTES64))
+		return;
+
+	x86_pmu.bts  = boot_cpu_has(X86_FEATURE_BTS);
+	x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS);
+	x86_pmu.pebs_buffer_size = PEBS_BUFFER_SIZE;
+	if (x86_pmu.pebs) {
+		char pebs_type = x86_pmu.intel_cap.pebs_trap ?  '+' : '-';
+		int format = x86_pmu.intel_cap.pebs_format;
+
+		switch (format) {
+		case 0:
+			printk(KERN_CONT "PEBS fmt0%c, ", pebs_type);
+			x86_pmu.pebs_record_size = sizeof(struct pebs_record_core);
+			/*
+			 * Using >PAGE_SIZE buffers makes the WRMSR to
+			 * PERF_GLOBAL_CTRL in intel_pmu_enable_all()
+			 * mysteriously hang on Core2.
+			 *
+			 * As a workaround, we don't do this.
+			 */
+			x86_pmu.pebs_buffer_size = PAGE_SIZE;
+			x86_pmu.drain_pebs = intel_pmu_drain_pebs_core;
+			break;
+
+		case 1:
+			printk(KERN_CONT "PEBS fmt1%c, ", pebs_type);
+			x86_pmu.pebs_record_size = sizeof(struct pebs_record_nhm);
+			x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm;
+			break;
+
+		case 2:
+			pr_cont("PEBS fmt2%c, ", pebs_type);
+			x86_pmu.pebs_record_size = sizeof(struct pebs_record_hsw);
+			x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm;
+			break;
+
+		case 3:
+			pr_cont("PEBS fmt3%c, ", pebs_type);
+			x86_pmu.pebs_record_size =
+						sizeof(struct pebs_record_skl);
+			x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm;
+			x86_pmu.free_running_flags |= PERF_SAMPLE_TIME;
+			break;
+
+		default:
+			printk(KERN_CONT "no PEBS fmt%d%c, ", format, pebs_type);
+			x86_pmu.pebs = 0;
+		}
+	}
+}
+
+void perf_restore_debug_store(void)
+{
+	struct debug_store *ds = __this_cpu_read(cpu_hw_events.ds);
+
+	if (!x86_pmu.bts && !x86_pmu.pebs)
+		return;
+
+	wrmsrl(MSR_IA32_DS_AREA, (unsigned long)ds);
+}
--- linux-4.4.0.orig/arch/x86/events/intel/knc.c
+++ linux-4.4.0/arch/x86/events/intel/knc.c
@@ -0,0 +1,321 @@
+/* Driver for Intel Xeon Phi "Knights Corner" PMU */
+
+#include <linux/perf_event.h>
+#include <linux/types.h>
+
+#include <asm/hardirq.h>
+
+#include "../perf_event.h"
+
+static const u64 knc_perfmon_event_map[] =
+{
+  [PERF_COUNT_HW_CPU_CYCLES]		= 0x002a,
+  [PERF_COUNT_HW_INSTRUCTIONS]		= 0x0016,
+  [PERF_COUNT_HW_CACHE_REFERENCES]	= 0x0028,
+  [PERF_COUNT_HW_CACHE_MISSES]		= 0x0029,
+  [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x0012,
+  [PERF_COUNT_HW_BRANCH_MISSES]		= 0x002b,
+};
+
+static const u64 __initconst knc_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		/* On Xeon Phi event "0" is a valid DATA_READ          */
+		/*   (L1 Data Cache Reads) Instruction.                */
+		/* We code this as ARCH_PERFMON_EVENTSEL_INT as this   */
+		/* bit will always be set in x86_pmu_hw_config().      */
+		[ C(RESULT_ACCESS) ] = ARCH_PERFMON_EVENTSEL_INT,
+						/* DATA_READ           */
+		[ C(RESULT_MISS)   ] = 0x0003,	/* DATA_READ_MISS      */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0001,	/* DATA_WRITE          */
+		[ C(RESULT_MISS)   ] = 0x0004,	/* DATA_WRITE_MISS     */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0011,	/* L1_DATA_PF1         */
+		[ C(RESULT_MISS)   ] = 0x001c,	/* L1_DATA_PF1_MISS    */
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x000c,	/* CODE_READ          */
+		[ C(RESULT_MISS)   ] = 0x000e,	/* CODE_CACHE_MISS    */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0x10cb,	/* L2_READ_MISS */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x10cc,	/* L2_WRITE_HIT */
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x10fc,	/* L2_DATA_PF2      */
+		[ C(RESULT_MISS)   ] = 0x10fe,	/* L2_DATA_PF2_MISS */
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = ARCH_PERFMON_EVENTSEL_INT,
+						/* DATA_READ */
+						/* see note on L1 OP_READ */
+		[ C(RESULT_MISS)   ] = 0x0002,	/* DATA_PAGE_WALK */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0001,	/* DATA_WRITE */
+		[ C(RESULT_MISS)   ] = 0x0002,	/* DATA_PAGE_WALK */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = 0x0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x000c,	/* CODE_READ */
+		[ C(RESULT_MISS)   ] = 0x000d,	/* CODE_PAGE_WALK */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0012,	/* BRANCHES */
+		[ C(RESULT_MISS)   ] = 0x002b,	/* BRANCHES_MISPREDICTED */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+};
+
+
+static u64 knc_pmu_event_map(int hw_event)
+{
+	return knc_perfmon_event_map[hw_event];
+}
+
+static struct event_constraint knc_event_constraints[] =
+{
+	INTEL_EVENT_CONSTRAINT(0xc3, 0x1),	/* HWP_L2HIT */
+	INTEL_EVENT_CONSTRAINT(0xc4, 0x1),	/* HWP_L2MISS */
+	INTEL_EVENT_CONSTRAINT(0xc8, 0x1),	/* L2_READ_HIT_E */
+	INTEL_EVENT_CONSTRAINT(0xc9, 0x1),	/* L2_READ_HIT_M */
+	INTEL_EVENT_CONSTRAINT(0xca, 0x1),	/* L2_READ_HIT_S */
+	INTEL_EVENT_CONSTRAINT(0xcb, 0x1),	/* L2_READ_MISS */
+	INTEL_EVENT_CONSTRAINT(0xcc, 0x1),	/* L2_WRITE_HIT */
+	INTEL_EVENT_CONSTRAINT(0xce, 0x1),	/* L2_STRONGLY_ORDERED_STREAMING_VSTORES_MISS */
+	INTEL_EVENT_CONSTRAINT(0xcf, 0x1),	/* L2_WEAKLY_ORDERED_STREAMING_VSTORE_MISS */
+	INTEL_EVENT_CONSTRAINT(0xd7, 0x1),	/* L2_VICTIM_REQ_WITH_DATA */
+	INTEL_EVENT_CONSTRAINT(0xe3, 0x1),	/* SNP_HITM_BUNIT */
+	INTEL_EVENT_CONSTRAINT(0xe6, 0x1),	/* SNP_HIT_L2 */
+	INTEL_EVENT_CONSTRAINT(0xe7, 0x1),	/* SNP_HITM_L2 */
+	INTEL_EVENT_CONSTRAINT(0xf1, 0x1),	/* L2_DATA_READ_MISS_CACHE_FILL */
+	INTEL_EVENT_CONSTRAINT(0xf2, 0x1),	/* L2_DATA_WRITE_MISS_CACHE_FILL */
+	INTEL_EVENT_CONSTRAINT(0xf6, 0x1),	/* L2_DATA_READ_MISS_MEM_FILL */
+	INTEL_EVENT_CONSTRAINT(0xf7, 0x1),	/* L2_DATA_WRITE_MISS_MEM_FILL */
+	INTEL_EVENT_CONSTRAINT(0xfc, 0x1),	/* L2_DATA_PF2 */
+	INTEL_EVENT_CONSTRAINT(0xfd, 0x1),	/* L2_DATA_PF2_DROP */
+	INTEL_EVENT_CONSTRAINT(0xfe, 0x1),	/* L2_DATA_PF2_MISS */
+	INTEL_EVENT_CONSTRAINT(0xff, 0x1),	/* L2_DATA_HIT_INFLIGHT_PF2 */
+	EVENT_CONSTRAINT_END
+};
+
+#define MSR_KNC_IA32_PERF_GLOBAL_STATUS		0x0000002d
+#define MSR_KNC_IA32_PERF_GLOBAL_OVF_CONTROL	0x0000002e
+#define MSR_KNC_IA32_PERF_GLOBAL_CTRL		0x0000002f
+
+#define KNC_ENABLE_COUNTER0			0x00000001
+#define KNC_ENABLE_COUNTER1			0x00000002
+
+static void knc_pmu_disable_all(void)
+{
+	u64 val;
+
+	rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val);
+	val &= ~(KNC_ENABLE_COUNTER0|KNC_ENABLE_COUNTER1);
+	wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val);
+}
+
+static void knc_pmu_enable_all(int added)
+{
+	u64 val;
+
+	rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val);
+	val |= (KNC_ENABLE_COUNTER0|KNC_ENABLE_COUNTER1);
+	wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val);
+}
+
+static inline void
+knc_pmu_disable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 val;
+
+	val = hwc->config;
+	val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
+
+	(void)wrmsrl_safe(hwc->config_base + hwc->idx, val);
+}
+
+static void knc_pmu_enable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 val;
+
+	val = hwc->config;
+	val |= ARCH_PERFMON_EVENTSEL_ENABLE;
+
+	(void)wrmsrl_safe(hwc->config_base + hwc->idx, val);
+}
+
+static inline u64 knc_pmu_get_status(void)
+{
+	u64 status;
+
+	rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_STATUS, status);
+
+	return status;
+}
+
+static inline void knc_pmu_ack_status(u64 ack)
+{
+	wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_OVF_CONTROL, ack);
+}
+
+static int knc_pmu_handle_irq(struct pt_regs *regs)
+{
+	struct perf_sample_data data;
+	struct cpu_hw_events *cpuc;
+	int handled = 0;
+	int bit, loops;
+	u64 status;
+
+	cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	knc_pmu_disable_all();
+
+	status = knc_pmu_get_status();
+	if (!status) {
+		knc_pmu_enable_all(0);
+		return handled;
+	}
+
+	loops = 0;
+again:
+	knc_pmu_ack_status(status);
+	if (++loops > 100) {
+		WARN_ONCE(1, "perf: irq loop stuck!\n");
+		perf_event_print_debug();
+		goto done;
+	}
+
+	inc_irq_stat(apic_perf_irqs);
+
+	for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
+		struct perf_event *event = cpuc->events[bit];
+
+		handled++;
+
+		if (!test_bit(bit, cpuc->active_mask))
+			continue;
+
+		if (!intel_pmu_save_and_restart(event))
+			continue;
+
+		perf_sample_data_init(&data, 0, event->hw.last_period);
+
+		if (perf_event_overflow(event, &data, regs))
+			x86_pmu_stop(event, 0);
+	}
+
+	/*
+	 * Repeat if there is more work to be done:
+	 */
+	status = knc_pmu_get_status();
+	if (status)
+		goto again;
+
+done:
+	/* Only restore PMU state when it's active. See x86_pmu_disable(). */
+	if (cpuc->enabled)
+		knc_pmu_enable_all(0);
+
+	return handled;
+}
+
+
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *intel_knc_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
+static const struct x86_pmu knc_pmu __initconst = {
+	.name			= "knc",
+	.handle_irq		= knc_pmu_handle_irq,
+	.disable_all		= knc_pmu_disable_all,
+	.enable_all		= knc_pmu_enable_all,
+	.enable			= knc_pmu_enable_event,
+	.disable		= knc_pmu_disable_event,
+	.hw_config		= x86_pmu_hw_config,
+	.schedule_events	= x86_schedule_events,
+	.eventsel		= MSR_KNC_EVNTSEL0,
+	.perfctr		= MSR_KNC_PERFCTR0,
+	.event_map		= knc_pmu_event_map,
+	.max_events             = ARRAY_SIZE(knc_perfmon_event_map),
+	.apic			= 1,
+	.max_period		= (1ULL << 39) - 1,
+	.version		= 0,
+	.num_counters		= 2,
+	.cntval_bits		= 40,
+	.cntval_mask		= (1ULL << 40) - 1,
+	.get_event_constraints	= x86_get_event_constraints,
+	.event_constraints	= knc_event_constraints,
+	.format_attrs		= intel_knc_formats_attr,
+};
+
+__init int knc_pmu_init(void)
+{
+	x86_pmu = knc_pmu;
+
+	memcpy(hw_cache_event_ids, knc_hw_cache_event_ids, 
+		sizeof(hw_cache_event_ids));
+
+	return 0;
+}
--- linux-4.4.0.orig/arch/x86/events/intel/lbr.c
+++ linux-4.4.0/arch/x86/events/intel/lbr.c
@@ -0,0 +1,1049 @@
+#include <linux/perf_event.h>
+#include <linux/types.h>
+
+#include <asm/perf_event.h>
+#include <asm/msr.h>
+#include <asm/insn.h>
+
+#include "../perf_event.h"
+
+enum {
+	LBR_FORMAT_32		= 0x00,
+	LBR_FORMAT_LIP		= 0x01,
+	LBR_FORMAT_EIP		= 0x02,
+	LBR_FORMAT_EIP_FLAGS	= 0x03,
+	LBR_FORMAT_EIP_FLAGS2	= 0x04,
+	LBR_FORMAT_INFO		= 0x05,
+	LBR_FORMAT_MAX_KNOWN    = LBR_FORMAT_INFO,
+};
+
+static enum {
+	LBR_EIP_FLAGS		= 1,
+	LBR_TSX			= 2,
+} lbr_desc[LBR_FORMAT_MAX_KNOWN + 1] = {
+	[LBR_FORMAT_EIP_FLAGS]  = LBR_EIP_FLAGS,
+	[LBR_FORMAT_EIP_FLAGS2] = LBR_EIP_FLAGS | LBR_TSX,
+};
+
+/*
+ * Intel LBR_SELECT bits
+ * Intel Vol3a, April 2011, Section 16.7 Table 16-10
+ *
+ * Hardware branch filter (not available on all CPUs)
+ */
+#define LBR_KERNEL_BIT		0 /* do not capture at ring0 */
+#define LBR_USER_BIT		1 /* do not capture at ring > 0 */
+#define LBR_JCC_BIT		2 /* do not capture conditional branches */
+#define LBR_REL_CALL_BIT	3 /* do not capture relative calls */
+#define LBR_IND_CALL_BIT	4 /* do not capture indirect calls */
+#define LBR_RETURN_BIT		5 /* do not capture near returns */
+#define LBR_IND_JMP_BIT		6 /* do not capture indirect jumps */
+#define LBR_REL_JMP_BIT		7 /* do not capture relative jumps */
+#define LBR_FAR_BIT		8 /* do not capture far branches */
+#define LBR_CALL_STACK_BIT	9 /* enable call stack */
+
+#define LBR_KERNEL	(1 << LBR_KERNEL_BIT)
+#define LBR_USER	(1 << LBR_USER_BIT)
+#define LBR_JCC		(1 << LBR_JCC_BIT)
+#define LBR_REL_CALL	(1 << LBR_REL_CALL_BIT)
+#define LBR_IND_CALL	(1 << LBR_IND_CALL_BIT)
+#define LBR_RETURN	(1 << LBR_RETURN_BIT)
+#define LBR_REL_JMP	(1 << LBR_REL_JMP_BIT)
+#define LBR_IND_JMP	(1 << LBR_IND_JMP_BIT)
+#define LBR_FAR		(1 << LBR_FAR_BIT)
+#define LBR_CALL_STACK	(1 << LBR_CALL_STACK_BIT)
+
+#define LBR_PLM (LBR_KERNEL | LBR_USER)
+
+#define LBR_SEL_MASK	0x1ff	/* valid bits in LBR_SELECT */
+#define LBR_NOT_SUPP	-1	/* LBR filter not supported */
+#define LBR_IGN		0	/* ignored */
+
+#define LBR_ANY		 \
+	(LBR_JCC	|\
+	 LBR_REL_CALL	|\
+	 LBR_IND_CALL	|\
+	 LBR_RETURN	|\
+	 LBR_REL_JMP	|\
+	 LBR_IND_JMP	|\
+	 LBR_FAR)
+
+#define LBR_FROM_FLAG_MISPRED  (1ULL << 63)
+#define LBR_FROM_FLAG_IN_TX    (1ULL << 62)
+#define LBR_FROM_FLAG_ABORT    (1ULL << 61)
+
+/*
+ * x86control flow change classification
+ * x86control flow changes include branches, interrupts, traps, faults
+ */
+enum {
+	X86_BR_NONE		= 0,      /* unknown */
+
+	X86_BR_USER		= 1 << 0, /* branch target is user */
+	X86_BR_KERNEL		= 1 << 1, /* branch target is kernel */
+
+	X86_BR_CALL		= 1 << 2, /* call */
+	X86_BR_RET		= 1 << 3, /* return */
+	X86_BR_SYSCALL		= 1 << 4, /* syscall */
+	X86_BR_SYSRET		= 1 << 5, /* syscall return */
+	X86_BR_INT		= 1 << 6, /* sw interrupt */
+	X86_BR_IRET		= 1 << 7, /* return from interrupt */
+	X86_BR_JCC		= 1 << 8, /* conditional */
+	X86_BR_JMP		= 1 << 9, /* jump */
+	X86_BR_IRQ		= 1 << 10,/* hw interrupt or trap or fault */
+	X86_BR_IND_CALL		= 1 << 11,/* indirect calls */
+	X86_BR_ABORT		= 1 << 12,/* transaction abort */
+	X86_BR_IN_TX		= 1 << 13,/* in transaction */
+	X86_BR_NO_TX		= 1 << 14,/* not in transaction */
+	X86_BR_ZERO_CALL	= 1 << 15,/* zero length call */
+	X86_BR_CALL_STACK	= 1 << 16,/* call stack */
+	X86_BR_IND_JMP		= 1 << 17,/* indirect jump */
+};
+
+#define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL)
+#define X86_BR_ANYTX (X86_BR_NO_TX | X86_BR_IN_TX)
+
+#define X86_BR_ANY       \
+	(X86_BR_CALL    |\
+	 X86_BR_RET     |\
+	 X86_BR_SYSCALL |\
+	 X86_BR_SYSRET  |\
+	 X86_BR_INT     |\
+	 X86_BR_IRET    |\
+	 X86_BR_JCC     |\
+	 X86_BR_JMP	 |\
+	 X86_BR_IRQ	 |\
+	 X86_BR_ABORT	 |\
+	 X86_BR_IND_CALL |\
+	 X86_BR_IND_JMP  |\
+	 X86_BR_ZERO_CALL)
+
+#define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY)
+
+#define X86_BR_ANY_CALL		 \
+	(X86_BR_CALL		|\
+	 X86_BR_IND_CALL	|\
+	 X86_BR_ZERO_CALL	|\
+	 X86_BR_SYSCALL		|\
+	 X86_BR_IRQ		|\
+	 X86_BR_INT)
+
+static void intel_pmu_lbr_filter(struct cpu_hw_events *cpuc);
+
+/*
+ * We only support LBR implementations that have FREEZE_LBRS_ON_PMI
+ * otherwise it becomes near impossible to get a reliable stack.
+ */
+
+static void __intel_pmu_lbr_enable(bool pmi)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	u64 debugctl, lbr_select = 0, orig_debugctl;
+
+	/*
+	 * No need to unfreeze manually, as v4 can do that as part
+	 * of the GLOBAL_STATUS ack.
+	 */
+	if (pmi && x86_pmu.version >= 4)
+		return;
+
+	/*
+	 * No need to reprogram LBR_SELECT in a PMI, as it
+	 * did not change.
+	 */
+	if (cpuc->lbr_sel)
+		lbr_select = cpuc->lbr_sel->config;
+	if (!pmi && cpuc->lbr_sel)
+		wrmsrl(MSR_LBR_SELECT, lbr_select);
+
+	rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
+	orig_debugctl = debugctl;
+	debugctl |= DEBUGCTLMSR_LBR;
+	/*
+	 * LBR callstack does not work well with FREEZE_LBRS_ON_PMI.
+	 * If FREEZE_LBRS_ON_PMI is set, PMI near call/return instructions
+	 * may cause superfluous increase/decrease of LBR_TOS.
+	 */
+	if (!(lbr_select & LBR_CALL_STACK))
+		debugctl |= DEBUGCTLMSR_FREEZE_LBRS_ON_PMI;
+	if (orig_debugctl != debugctl)
+		wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
+}
+
+static void __intel_pmu_lbr_disable(void)
+{
+	u64 debugctl;
+
+	rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
+	debugctl &= ~(DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);
+	wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
+}
+
+static void intel_pmu_lbr_reset_32(void)
+{
+	int i;
+
+	for (i = 0; i < x86_pmu.lbr_nr; i++)
+		wrmsrl(x86_pmu.lbr_from + i, 0);
+}
+
+static void intel_pmu_lbr_reset_64(void)
+{
+	int i;
+
+	for (i = 0; i < x86_pmu.lbr_nr; i++) {
+		wrmsrl(x86_pmu.lbr_from + i, 0);
+		wrmsrl(x86_pmu.lbr_to   + i, 0);
+		if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
+			wrmsrl(MSR_LBR_INFO_0 + i, 0);
+	}
+}
+
+void intel_pmu_lbr_reset(void)
+{
+	if (!x86_pmu.lbr_nr)
+		return;
+
+	if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32)
+		intel_pmu_lbr_reset_32();
+	else
+		intel_pmu_lbr_reset_64();
+}
+
+/*
+ * TOS = most recently recorded branch
+ */
+static inline u64 intel_pmu_lbr_tos(void)
+{
+	u64 tos;
+
+	rdmsrl(x86_pmu.lbr_tos, tos);
+	return tos;
+}
+
+enum {
+	LBR_NONE,
+	LBR_VALID,
+};
+
+static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
+{
+	int i;
+	unsigned lbr_idx, mask;
+	u64 tos;
+
+	if (task_ctx->lbr_callstack_users == 0 ||
+	    task_ctx->lbr_stack_state == LBR_NONE) {
+		intel_pmu_lbr_reset();
+		return;
+	}
+
+	mask = x86_pmu.lbr_nr - 1;
+	tos = task_ctx->tos;
+	for (i = 0; i < tos; i++) {
+		lbr_idx = (tos - i) & mask;
+		wrmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]);
+		wrmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]);
+		if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
+			wrmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]);
+	}
+	wrmsrl(x86_pmu.lbr_tos, tos);
+	task_ctx->lbr_stack_state = LBR_NONE;
+}
+
+static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
+{
+	int i;
+	unsigned lbr_idx, mask;
+	u64 tos;
+
+	if (task_ctx->lbr_callstack_users == 0) {
+		task_ctx->lbr_stack_state = LBR_NONE;
+		return;
+	}
+
+	mask = x86_pmu.lbr_nr - 1;
+	tos = intel_pmu_lbr_tos();
+	for (i = 0; i < tos; i++) {
+		lbr_idx = (tos - i) & mask;
+		rdmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]);
+		rdmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]);
+		if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
+			rdmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]);
+	}
+	task_ctx->tos = tos;
+	task_ctx->lbr_stack_state = LBR_VALID;
+}
+
+void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct x86_perf_task_context *task_ctx;
+
+	/*
+	 * If LBR callstack feature is enabled and the stack was saved when
+	 * the task was scheduled out, restore the stack. Otherwise flush
+	 * the LBR stack.
+	 */
+	task_ctx = ctx ? ctx->task_ctx_data : NULL;
+	if (task_ctx) {
+		if (sched_in) {
+			__intel_pmu_lbr_restore(task_ctx);
+			cpuc->lbr_context = ctx;
+		} else {
+			__intel_pmu_lbr_save(task_ctx);
+		}
+		return;
+	}
+
+	/*
+	 * When sampling the branck stack in system-wide, it may be
+	 * necessary to flush the stack on context switch. This happens
+	 * when the branch stack does not tag its entries with the pid
+	 * of the current task. Otherwise it becomes impossible to
+	 * associate a branch entry with a task. This ambiguity is more
+	 * likely to appear when the branch stack supports priv level
+	 * filtering and the user sets it to monitor only at the user
+	 * level (which could be a useful measurement in system-wide
+	 * mode). In that case, the risk is high of having a branch
+	 * stack with branch from multiple tasks.
+ 	 */
+	if (sched_in) {
+		intel_pmu_lbr_reset();
+		cpuc->lbr_context = ctx;
+	}
+}
+
+static inline bool branch_user_callstack(unsigned br_sel)
+{
+	return (br_sel & X86_BR_USER) && (br_sel & X86_BR_CALL_STACK);
+}
+
+void intel_pmu_lbr_enable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct x86_perf_task_context *task_ctx;
+
+	if (!x86_pmu.lbr_nr)
+		return;
+
+	/*
+	 * Reset the LBR stack if we changed task context to
+	 * avoid data leaks.
+	 */
+	if (event->ctx->task && cpuc->lbr_context != event->ctx) {
+		intel_pmu_lbr_reset();
+		cpuc->lbr_context = event->ctx;
+	}
+	cpuc->br_sel = event->hw.branch_reg.reg;
+
+	if (branch_user_callstack(cpuc->br_sel) && event->ctx &&
+					event->ctx->task_ctx_data) {
+		task_ctx = event->ctx->task_ctx_data;
+		task_ctx->lbr_callstack_users++;
+	}
+
+	cpuc->lbr_users++;
+	perf_sched_cb_inc(event->ctx->pmu);
+}
+
+void intel_pmu_lbr_disable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct x86_perf_task_context *task_ctx;
+
+	if (!x86_pmu.lbr_nr)
+		return;
+
+	if (branch_user_callstack(cpuc->br_sel) && event->ctx &&
+					event->ctx->task_ctx_data) {
+		task_ctx = event->ctx->task_ctx_data;
+		task_ctx->lbr_callstack_users--;
+	}
+
+	cpuc->lbr_users--;
+	WARN_ON_ONCE(cpuc->lbr_users < 0);
+	perf_sched_cb_dec(event->ctx->pmu);
+
+	if (cpuc->enabled && !cpuc->lbr_users) {
+		__intel_pmu_lbr_disable();
+		/* avoid stale pointer */
+		cpuc->lbr_context = NULL;
+	}
+}
+
+void intel_pmu_lbr_enable_all(bool pmi)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	if (cpuc->lbr_users)
+		__intel_pmu_lbr_enable(pmi);
+}
+
+void intel_pmu_lbr_disable_all(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	if (cpuc->lbr_users)
+		__intel_pmu_lbr_disable();
+}
+
+static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
+{
+	unsigned long mask = x86_pmu.lbr_nr - 1;
+	u64 tos = intel_pmu_lbr_tos();
+	int i;
+
+	for (i = 0; i < x86_pmu.lbr_nr; i++) {
+		unsigned long lbr_idx = (tos - i) & mask;
+		union {
+			struct {
+				u32 from;
+				u32 to;
+			};
+			u64     lbr;
+		} msr_lastbranch;
+
+		rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr);
+
+		cpuc->lbr_entries[i].from	= msr_lastbranch.from;
+		cpuc->lbr_entries[i].to		= msr_lastbranch.to;
+		cpuc->lbr_entries[i].mispred	= 0;
+		cpuc->lbr_entries[i].predicted	= 0;
+		cpuc->lbr_entries[i].in_tx	= 0;
+		cpuc->lbr_entries[i].abort	= 0;
+		cpuc->lbr_entries[i].cycles	= 0;
+		cpuc->lbr_entries[i].reserved	= 0;
+	}
+	cpuc->lbr_stack.nr = i;
+}
+
+/*
+ * Due to lack of segmentation in Linux the effective address (offset)
+ * is the same as the linear address, allowing us to merge the LIP and EIP
+ * LBR formats.
+ */
+static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
+{
+	unsigned long mask = x86_pmu.lbr_nr - 1;
+	int lbr_format = x86_pmu.intel_cap.lbr_format;
+	u64 tos = intel_pmu_lbr_tos();
+	int i;
+	int out = 0;
+	int num = x86_pmu.lbr_nr;
+
+	if (cpuc->lbr_sel) {
+		if (cpuc->lbr_sel->config & LBR_CALL_STACK)
+			num = tos;
+	}
+
+	for (i = 0; i < num; i++) {
+		unsigned long lbr_idx = (tos - i) & mask;
+		u64 from, to, mis = 0, pred = 0, in_tx = 0, abort = 0;
+		int skip = 0;
+		u16 cycles = 0;
+		int lbr_flags = lbr_desc[lbr_format];
+
+		rdmsrl(x86_pmu.lbr_from + lbr_idx, from);
+		rdmsrl(x86_pmu.lbr_to   + lbr_idx, to);
+
+		if (lbr_format == LBR_FORMAT_INFO) {
+			u64 info;
+
+			rdmsrl(MSR_LBR_INFO_0 + lbr_idx, info);
+			mis = !!(info & LBR_INFO_MISPRED);
+			pred = !mis;
+			in_tx = !!(info & LBR_INFO_IN_TX);
+			abort = !!(info & LBR_INFO_ABORT);
+			cycles = (info & LBR_INFO_CYCLES);
+		}
+		if (lbr_flags & LBR_EIP_FLAGS) {
+			mis = !!(from & LBR_FROM_FLAG_MISPRED);
+			pred = !mis;
+			skip = 1;
+		}
+		if (lbr_flags & LBR_TSX) {
+			in_tx = !!(from & LBR_FROM_FLAG_IN_TX);
+			abort = !!(from & LBR_FROM_FLAG_ABORT);
+			skip = 3;
+		}
+		from = (u64)((((s64)from) << skip) >> skip);
+
+		/*
+		 * Some CPUs report duplicated abort records,
+		 * with the second entry not having an abort bit set.
+		 * Skip them here. This loop runs backwards,
+		 * so we need to undo the previous record.
+		 * If the abort just happened outside the window
+		 * the extra entry cannot be removed.
+		 */
+		if (abort && x86_pmu.lbr_double_abort && out > 0)
+			out--;
+
+		cpuc->lbr_entries[out].from	 = from;
+		cpuc->lbr_entries[out].to	 = to;
+		cpuc->lbr_entries[out].mispred	 = mis;
+		cpuc->lbr_entries[out].predicted = pred;
+		cpuc->lbr_entries[out].in_tx	 = in_tx;
+		cpuc->lbr_entries[out].abort	 = abort;
+		cpuc->lbr_entries[out].cycles	 = cycles;
+		cpuc->lbr_entries[out].reserved	 = 0;
+		out++;
+	}
+	cpuc->lbr_stack.nr = out;
+}
+
+void intel_pmu_lbr_read(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	if (!cpuc->lbr_users)
+		return;
+
+	if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32)
+		intel_pmu_lbr_read_32(cpuc);
+	else
+		intel_pmu_lbr_read_64(cpuc);
+
+	intel_pmu_lbr_filter(cpuc);
+}
+
+/*
+ * SW filter is used:
+ * - in case there is no HW filter
+ * - in case the HW filter has errata or limitations
+ */
+static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
+{
+	u64 br_type = event->attr.branch_sample_type;
+	int mask = 0;
+
+	if (br_type & PERF_SAMPLE_BRANCH_USER)
+		mask |= X86_BR_USER;
+
+	if (br_type & PERF_SAMPLE_BRANCH_KERNEL)
+		mask |= X86_BR_KERNEL;
+
+	/* we ignore BRANCH_HV here */
+
+	if (br_type & PERF_SAMPLE_BRANCH_ANY)
+		mask |= X86_BR_ANY;
+
+	if (br_type & PERF_SAMPLE_BRANCH_ANY_CALL)
+		mask |= X86_BR_ANY_CALL;
+
+	if (br_type & PERF_SAMPLE_BRANCH_ANY_RETURN)
+		mask |= X86_BR_RET | X86_BR_IRET | X86_BR_SYSRET;
+
+	if (br_type & PERF_SAMPLE_BRANCH_IND_CALL)
+		mask |= X86_BR_IND_CALL;
+
+	if (br_type & PERF_SAMPLE_BRANCH_ABORT_TX)
+		mask |= X86_BR_ABORT;
+
+	if (br_type & PERF_SAMPLE_BRANCH_IN_TX)
+		mask |= X86_BR_IN_TX;
+
+	if (br_type & PERF_SAMPLE_BRANCH_NO_TX)
+		mask |= X86_BR_NO_TX;
+
+	if (br_type & PERF_SAMPLE_BRANCH_COND)
+		mask |= X86_BR_JCC;
+
+	if (br_type & PERF_SAMPLE_BRANCH_CALL_STACK) {
+		if (!x86_pmu_has_lbr_callstack())
+			return -EOPNOTSUPP;
+		if (mask & ~(X86_BR_USER | X86_BR_KERNEL))
+			return -EINVAL;
+		mask |= X86_BR_CALL | X86_BR_IND_CALL | X86_BR_RET |
+			X86_BR_CALL_STACK;
+	}
+
+	if (br_type & PERF_SAMPLE_BRANCH_IND_JUMP)
+		mask |= X86_BR_IND_JMP;
+
+	if (br_type & PERF_SAMPLE_BRANCH_CALL)
+		mask |= X86_BR_CALL | X86_BR_ZERO_CALL;
+	/*
+	 * stash actual user request into reg, it may
+	 * be used by fixup code for some CPU
+	 */
+	event->hw.branch_reg.reg = mask;
+	return 0;
+}
+
+/*
+ * setup the HW LBR filter
+ * Used only when available, may not be enough to disambiguate
+ * all branches, may need the help of the SW filter
+ */
+static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg;
+	u64 br_type = event->attr.branch_sample_type;
+	u64 mask = 0, v;
+	int i;
+
+	for (i = 0; i < PERF_SAMPLE_BRANCH_MAX_SHIFT; i++) {
+		if (!(br_type & (1ULL << i)))
+			continue;
+
+		v = x86_pmu.lbr_sel_map[i];
+		if (v == LBR_NOT_SUPP)
+			return -EOPNOTSUPP;
+
+		if (v != LBR_IGN)
+			mask |= v;
+	}
+	reg = &event->hw.branch_reg;
+	reg->idx = EXTRA_REG_LBR;
+
+	/*
+	 * The first 9 bits (LBR_SEL_MASK) in LBR_SELECT operate
+	 * in suppress mode. So LBR_SELECT should be set to
+	 * (~mask & LBR_SEL_MASK) | (mask & ~LBR_SEL_MASK)
+	 */
+	reg->config = mask ^ x86_pmu.lbr_sel_mask;
+
+	return 0;
+}
+
+int intel_pmu_setup_lbr_filter(struct perf_event *event)
+{
+	int ret = 0;
+
+	/*
+	 * no LBR on this PMU
+	 */
+	if (!x86_pmu.lbr_nr)
+		return -EOPNOTSUPP;
+
+	/*
+	 * setup SW LBR filter
+	 */
+	ret = intel_pmu_setup_sw_lbr_filter(event);
+	if (ret)
+		return ret;
+
+	/*
+	 * setup HW LBR filter, if any
+	 */
+	if (x86_pmu.lbr_sel_map)
+		ret = intel_pmu_setup_hw_lbr_filter(event);
+
+	return ret;
+}
+
+/*
+ * return the type of control flow change at address "from"
+ * intruction is not necessarily a branch (in case of interrupt).
+ *
+ * The branch type returned also includes the priv level of the
+ * target of the control flow change (X86_BR_USER, X86_BR_KERNEL).
+ *
+ * If a branch type is unknown OR the instruction cannot be
+ * decoded (e.g., text page not present), then X86_BR_NONE is
+ * returned.
+ */
+static int branch_type(unsigned long from, unsigned long to, int abort)
+{
+	struct insn insn;
+	void *addr;
+	int bytes_read, bytes_left;
+	int ret = X86_BR_NONE;
+	int ext, to_plm, from_plm;
+	u8 buf[MAX_INSN_SIZE];
+	int is64 = 0;
+
+	to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER;
+	from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER;
+
+	/*
+	 * maybe zero if lbr did not fill up after a reset by the time
+	 * we get a PMU interrupt
+	 */
+	if (from == 0 || to == 0)
+		return X86_BR_NONE;
+
+	if (abort)
+		return X86_BR_ABORT | to_plm;
+
+	if (from_plm == X86_BR_USER) {
+		/*
+		 * can happen if measuring at the user level only
+		 * and we interrupt in a kernel thread, e.g., idle.
+		 */
+		if (!current->mm)
+			return X86_BR_NONE;
+
+		/* may fail if text not present */
+		bytes_left = copy_from_user_nmi(buf, (void __user *)from,
+						MAX_INSN_SIZE);
+		bytes_read = MAX_INSN_SIZE - bytes_left;
+		if (!bytes_read)
+			return X86_BR_NONE;
+
+		addr = buf;
+	} else {
+		/*
+		 * The LBR logs any address in the IP, even if the IP just
+		 * faulted. This means userspace can control the from address.
+		 * Ensure we don't blindy read any address by validating it is
+		 * a known text address.
+		 */
+		if (kernel_text_address(from)) {
+			addr = (void *)from;
+			/*
+			 * Assume we can get the maximum possible size
+			 * when grabbing kernel data.  This is not
+			 * _strictly_ true since we could possibly be
+			 * executing up next to a memory hole, but
+			 * it is very unlikely to be a problem.
+			 */
+			bytes_read = MAX_INSN_SIZE;
+		} else {
+			return X86_BR_NONE;
+		}
+	}
+
+	/*
+	 * decoder needs to know the ABI especially
+	 * on 64-bit systems running 32-bit apps
+	 */
+#ifdef CONFIG_X86_64
+	is64 = kernel_ip((unsigned long)addr) || !test_thread_flag(TIF_IA32);
+#endif
+	insn_init(&insn, addr, bytes_read, is64);
+	insn_get_opcode(&insn);
+	if (!insn.opcode.got)
+		return X86_BR_ABORT;
+
+	switch (insn.opcode.bytes[0]) {
+	case 0xf:
+		switch (insn.opcode.bytes[1]) {
+		case 0x05: /* syscall */
+		case 0x34: /* sysenter */
+			ret = X86_BR_SYSCALL;
+			break;
+		case 0x07: /* sysret */
+		case 0x35: /* sysexit */
+			ret = X86_BR_SYSRET;
+			break;
+		case 0x80 ... 0x8f: /* conditional */
+			ret = X86_BR_JCC;
+			break;
+		default:
+			ret = X86_BR_NONE;
+		}
+		break;
+	case 0x70 ... 0x7f: /* conditional */
+		ret = X86_BR_JCC;
+		break;
+	case 0xc2: /* near ret */
+	case 0xc3: /* near ret */
+	case 0xca: /* far ret */
+	case 0xcb: /* far ret */
+		ret = X86_BR_RET;
+		break;
+	case 0xcf: /* iret */
+		ret = X86_BR_IRET;
+		break;
+	case 0xcc ... 0xce: /* int */
+		ret = X86_BR_INT;
+		break;
+	case 0xe8: /* call near rel */
+		insn_get_immediate(&insn);
+		if (insn.immediate1.value == 0) {
+			/* zero length call */
+			ret = X86_BR_ZERO_CALL;
+			break;
+		}
+	case 0x9a: /* call far absolute */
+		ret = X86_BR_CALL;
+		break;
+	case 0xe0 ... 0xe3: /* loop jmp */
+		ret = X86_BR_JCC;
+		break;
+	case 0xe9 ... 0xeb: /* jmp */
+		ret = X86_BR_JMP;
+		break;
+	case 0xff: /* call near absolute, call far absolute ind */
+		insn_get_modrm(&insn);
+		ext = (insn.modrm.bytes[0] >> 3) & 0x7;
+		switch (ext) {
+		case 2: /* near ind call */
+		case 3: /* far ind call */
+			ret = X86_BR_IND_CALL;
+			break;
+		case 4:
+		case 5:
+			ret = X86_BR_IND_JMP;
+			break;
+		}
+		break;
+	default:
+		ret = X86_BR_NONE;
+	}
+	/*
+	 * interrupts, traps, faults (and thus ring transition) may
+	 * occur on any instructions. Thus, to classify them correctly,
+	 * we need to first look at the from and to priv levels. If they
+	 * are different and to is in the kernel, then it indicates
+	 * a ring transition. If the from instruction is not a ring
+	 * transition instr (syscall, systenter, int), then it means
+	 * it was a irq, trap or fault.
+	 *
+	 * we have no way of detecting kernel to kernel faults.
+	 */
+	if (from_plm == X86_BR_USER && to_plm == X86_BR_KERNEL
+	    && ret != X86_BR_SYSCALL && ret != X86_BR_INT)
+		ret = X86_BR_IRQ;
+
+	/*
+	 * branch priv level determined by target as
+	 * is done by HW when LBR_SELECT is implemented
+	 */
+	if (ret != X86_BR_NONE)
+		ret |= to_plm;
+
+	return ret;
+}
+
+/*
+ * implement actual branch filter based on user demand.
+ * Hardware may not exactly satisfy that request, thus
+ * we need to inspect opcodes. Mismatched branches are
+ * discarded. Therefore, the number of branches returned
+ * in PERF_SAMPLE_BRANCH_STACK sample may vary.
+ */
+static void
+intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
+{
+	u64 from, to;
+	int br_sel = cpuc->br_sel;
+	int i, j, type;
+	bool compress = false;
+
+	/* if sampling all branches, then nothing to filter */
+	if ((br_sel & X86_BR_ALL) == X86_BR_ALL)
+		return;
+
+	for (i = 0; i < cpuc->lbr_stack.nr; i++) {
+
+		from = cpuc->lbr_entries[i].from;
+		to = cpuc->lbr_entries[i].to;
+
+		type = branch_type(from, to, cpuc->lbr_entries[i].abort);
+		if (type != X86_BR_NONE && (br_sel & X86_BR_ANYTX)) {
+			if (cpuc->lbr_entries[i].in_tx)
+				type |= X86_BR_IN_TX;
+			else
+				type |= X86_BR_NO_TX;
+		}
+
+		/* if type does not correspond, then discard */
+		if (type == X86_BR_NONE || (br_sel & type) != type) {
+			cpuc->lbr_entries[i].from = 0;
+			compress = true;
+		}
+	}
+
+	if (!compress)
+		return;
+
+	/* remove all entries with from=0 */
+	for (i = 0; i < cpuc->lbr_stack.nr; ) {
+		if (!cpuc->lbr_entries[i].from) {
+			j = i;
+			while (++j < cpuc->lbr_stack.nr)
+				cpuc->lbr_entries[j-1] = cpuc->lbr_entries[j];
+			cpuc->lbr_stack.nr--;
+			if (!cpuc->lbr_entries[i].from)
+				continue;
+		}
+		i++;
+	}
+}
+
+/*
+ * Map interface branch filters onto LBR filters
+ */
+static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
+	[PERF_SAMPLE_BRANCH_ANY_SHIFT]		= LBR_ANY,
+	[PERF_SAMPLE_BRANCH_USER_SHIFT]		= LBR_USER,
+	[PERF_SAMPLE_BRANCH_KERNEL_SHIFT]	= LBR_KERNEL,
+	[PERF_SAMPLE_BRANCH_HV_SHIFT]		= LBR_IGN,
+	[PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT]	= LBR_RETURN | LBR_REL_JMP
+						| LBR_IND_JMP | LBR_FAR,
+	/*
+	 * NHM/WSM erratum: must include REL_JMP+IND_JMP to get CALL branches
+	 */
+	[PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] =
+	 LBR_REL_CALL | LBR_IND_CALL | LBR_REL_JMP | LBR_IND_JMP | LBR_FAR,
+	/*
+	 * NHM/WSM erratum: must include IND_JMP to capture IND_CALL
+	 */
+	[PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL | LBR_IND_JMP,
+	[PERF_SAMPLE_BRANCH_COND_SHIFT]     = LBR_JCC,
+	[PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP,
+};
+
+static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
+	[PERF_SAMPLE_BRANCH_ANY_SHIFT]		= LBR_ANY,
+	[PERF_SAMPLE_BRANCH_USER_SHIFT]		= LBR_USER,
+	[PERF_SAMPLE_BRANCH_KERNEL_SHIFT]	= LBR_KERNEL,
+	[PERF_SAMPLE_BRANCH_HV_SHIFT]		= LBR_IGN,
+	[PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT]	= LBR_RETURN | LBR_FAR,
+	[PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT]	= LBR_REL_CALL | LBR_IND_CALL
+						| LBR_FAR,
+	[PERF_SAMPLE_BRANCH_IND_CALL_SHIFT]	= LBR_IND_CALL,
+	[PERF_SAMPLE_BRANCH_COND_SHIFT]		= LBR_JCC,
+	[PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT]	= LBR_IND_JMP,
+	[PERF_SAMPLE_BRANCH_CALL_SHIFT]		= LBR_REL_CALL,
+};
+
+static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
+	[PERF_SAMPLE_BRANCH_ANY_SHIFT]		= LBR_ANY,
+	[PERF_SAMPLE_BRANCH_USER_SHIFT]		= LBR_USER,
+	[PERF_SAMPLE_BRANCH_KERNEL_SHIFT]	= LBR_KERNEL,
+	[PERF_SAMPLE_BRANCH_HV_SHIFT]		= LBR_IGN,
+	[PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT]	= LBR_RETURN | LBR_FAR,
+	[PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT]	= LBR_REL_CALL | LBR_IND_CALL
+						| LBR_FAR,
+	[PERF_SAMPLE_BRANCH_IND_CALL_SHIFT]	= LBR_IND_CALL,
+	[PERF_SAMPLE_BRANCH_COND_SHIFT]		= LBR_JCC,
+	[PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT]	= LBR_REL_CALL | LBR_IND_CALL
+						| LBR_RETURN | LBR_CALL_STACK,
+	[PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT]	= LBR_IND_JMP,
+	[PERF_SAMPLE_BRANCH_CALL_SHIFT]		= LBR_REL_CALL,
+};
+
+/* core */
+void __init intel_pmu_lbr_init_core(void)
+{
+	x86_pmu.lbr_nr     = 4;
+	x86_pmu.lbr_tos    = MSR_LBR_TOS;
+	x86_pmu.lbr_from   = MSR_LBR_CORE_FROM;
+	x86_pmu.lbr_to     = MSR_LBR_CORE_TO;
+
+	/*
+	 * SW branch filter usage:
+	 * - compensate for lack of HW filter
+	 */
+	pr_cont("4-deep LBR, ");
+}
+
+/* nehalem/westmere */
+void __init intel_pmu_lbr_init_nhm(void)
+{
+	x86_pmu.lbr_nr     = 16;
+	x86_pmu.lbr_tos    = MSR_LBR_TOS;
+	x86_pmu.lbr_from   = MSR_LBR_NHM_FROM;
+	x86_pmu.lbr_to     = MSR_LBR_NHM_TO;
+
+	x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+	x86_pmu.lbr_sel_map  = nhm_lbr_sel_map;
+
+	/*
+	 * SW branch filter usage:
+	 * - workaround LBR_SEL errata (see above)
+	 * - support syscall, sysret capture.
+	 *   That requires LBR_FAR but that means far
+	 *   jmp need to be filtered out
+	 */
+	pr_cont("16-deep LBR, ");
+}
+
+/* sandy bridge */
+void __init intel_pmu_lbr_init_snb(void)
+{
+	x86_pmu.lbr_nr	 = 16;
+	x86_pmu.lbr_tos	 = MSR_LBR_TOS;
+	x86_pmu.lbr_from = MSR_LBR_NHM_FROM;
+	x86_pmu.lbr_to   = MSR_LBR_NHM_TO;
+
+	x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+	x86_pmu.lbr_sel_map  = snb_lbr_sel_map;
+
+	/*
+	 * SW branch filter usage:
+	 * - support syscall, sysret capture.
+	 *   That requires LBR_FAR but that means far
+	 *   jmp need to be filtered out
+	 */
+	pr_cont("16-deep LBR, ");
+}
+
+/* haswell */
+void intel_pmu_lbr_init_hsw(void)
+{
+	x86_pmu.lbr_nr	 = 16;
+	x86_pmu.lbr_tos	 = MSR_LBR_TOS;
+	x86_pmu.lbr_from = MSR_LBR_NHM_FROM;
+	x86_pmu.lbr_to   = MSR_LBR_NHM_TO;
+
+	x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+	x86_pmu.lbr_sel_map  = hsw_lbr_sel_map;
+
+	pr_cont("16-deep LBR, ");
+}
+
+/* skylake */
+__init void intel_pmu_lbr_init_skl(void)
+{
+	x86_pmu.lbr_nr	 = 32;
+	x86_pmu.lbr_tos	 = MSR_LBR_TOS;
+	x86_pmu.lbr_from = MSR_LBR_NHM_FROM;
+	x86_pmu.lbr_to   = MSR_LBR_NHM_TO;
+
+	x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+	x86_pmu.lbr_sel_map  = hsw_lbr_sel_map;
+
+	/*
+	 * SW branch filter usage:
+	 * - support syscall, sysret capture.
+	 *   That requires LBR_FAR but that means far
+	 *   jmp need to be filtered out
+	 */
+	pr_cont("32-deep LBR, ");
+}
+
+/* atom */
+void __init intel_pmu_lbr_init_atom(void)
+{
+	/*
+	 * only models starting at stepping 10 seems
+	 * to have an operational LBR which can freeze
+	 * on PMU interrupt
+	 */
+	if (boot_cpu_data.x86_model == 28
+	    && boot_cpu_data.x86_stepping < 10) {
+		pr_cont("LBR disabled due to erratum");
+		return;
+	}
+
+	x86_pmu.lbr_nr	   = 8;
+	x86_pmu.lbr_tos    = MSR_LBR_TOS;
+	x86_pmu.lbr_from   = MSR_LBR_CORE_FROM;
+	x86_pmu.lbr_to     = MSR_LBR_CORE_TO;
+
+	/*
+	 * SW branch filter usage:
+	 * - compensate for lack of HW filter
+	 */
+	pr_cont("8-deep LBR, ");
+}
+
+/* Knights Landing */
+void intel_pmu_lbr_init_knl(void)
+{
+	x86_pmu.lbr_nr	   = 8;
+	x86_pmu.lbr_tos    = MSR_LBR_TOS;
+	x86_pmu.lbr_from   = MSR_LBR_NHM_FROM;
+	x86_pmu.lbr_to     = MSR_LBR_NHM_TO;
+
+	x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+	x86_pmu.lbr_sel_map  = snb_lbr_sel_map;
+
+	pr_cont("8-deep LBR, ");
+}
--- linux-4.4.0.orig/arch/x86/events/intel/p4.c
+++ linux-4.4.0/arch/x86/events/intel/p4.c
@@ -0,0 +1,1376 @@
+/*
+ * Netburst Performance Events (P4, old Xeon)
+ *
+ *  Copyright (C) 2010 Parallels, Inc., Cyrill Gorcunov <gorcunov@openvz.org>
+ *  Copyright (C) 2010 Intel Corporation, Lin Ming <ming.m.lin@intel.com>
+ *
+ *  For licencing details see kernel-base/COPYING
+ */
+
+#include <linux/perf_event.h>
+
+#include <asm/perf_event_p4.h>
+#include <asm/hardirq.h>
+#include <asm/apic.h>
+
+#include "../perf_event.h"
+
+#define P4_CNTR_LIMIT 3
+/*
+ * array indices: 0,1 - HT threads, used with HT enabled cpu
+ */
+struct p4_event_bind {
+	unsigned int opcode;			/* Event code and ESCR selector */
+	unsigned int escr_msr[2];		/* ESCR MSR for this event */
+	unsigned int escr_emask;		/* valid ESCR EventMask bits */
+	unsigned int shared;			/* event is shared across threads */
+	char cntr[2][P4_CNTR_LIMIT];		/* counter index (offset), -1 on abscence */
+};
+
+struct p4_pebs_bind {
+	unsigned int metric_pebs;
+	unsigned int metric_vert;
+};
+
+/* it sets P4_PEBS_ENABLE_UOP_TAG as well */
+#define P4_GEN_PEBS_BIND(name, pebs, vert)			\
+	[P4_PEBS_METRIC__##name] = {				\
+		.metric_pebs = pebs | P4_PEBS_ENABLE_UOP_TAG,	\
+		.metric_vert = vert,				\
+	}
+
+/*
+ * note we have P4_PEBS_ENABLE_UOP_TAG always set here
+ *
+ * it's needed for mapping P4_PEBS_CONFIG_METRIC_MASK bits of
+ * event configuration to find out which values are to be
+ * written into MSR_IA32_PEBS_ENABLE and MSR_P4_PEBS_MATRIX_VERT
+ * resgisters
+ */
+static struct p4_pebs_bind p4_pebs_bind_map[] = {
+	P4_GEN_PEBS_BIND(1stl_cache_load_miss_retired,	0x0000001, 0x0000001),
+	P4_GEN_PEBS_BIND(2ndl_cache_load_miss_retired,	0x0000002, 0x0000001),
+	P4_GEN_PEBS_BIND(dtlb_load_miss_retired,	0x0000004, 0x0000001),
+	P4_GEN_PEBS_BIND(dtlb_store_miss_retired,	0x0000004, 0x0000002),
+	P4_GEN_PEBS_BIND(dtlb_all_miss_retired,		0x0000004, 0x0000003),
+	P4_GEN_PEBS_BIND(tagged_mispred_branch,		0x0018000, 0x0000010),
+	P4_GEN_PEBS_BIND(mob_load_replay_retired,	0x0000200, 0x0000001),
+	P4_GEN_PEBS_BIND(split_load_retired,		0x0000400, 0x0000001),
+	P4_GEN_PEBS_BIND(split_store_retired,		0x0000400, 0x0000002),
+};
+
+/*
+ * Note that we don't use CCCR1 here, there is an
+ * exception for P4_BSQ_ALLOCATION but we just have
+ * no workaround
+ *
+ * consider this binding as resources which particular
+ * event may borrow, it doesn't contain EventMask,
+ * Tags and friends -- they are left to a caller
+ */
+static struct p4_event_bind p4_event_bind_map[] = {
+	[P4_EVENT_TC_DELIVER_MODE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_TC_DELIVER_MODE),
+		.escr_msr	= { MSR_P4_TC_ESCR0, MSR_P4_TC_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DD)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DB)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DI)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BD)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BB)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BI)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, ID),
+		.shared		= 1,
+		.cntr		= { {4, 5, -1}, {6, 7, -1} },
+	},
+	[P4_EVENT_BPU_FETCH_REQUEST] = {
+		.opcode		= P4_OPCODE(P4_EVENT_BPU_FETCH_REQUEST),
+		.escr_msr	= { MSR_P4_BPU_ESCR0, MSR_P4_BPU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BPU_FETCH_REQUEST, TCMISS),
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_ITLB_REFERENCE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_ITLB_REFERENCE),
+		.escr_msr	= { MSR_P4_ITLB_ESCR0, MSR_P4_ITLB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, HIT)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, MISS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, HIT_UK),
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_MEMORY_CANCEL] = {
+		.opcode		= P4_OPCODE(P4_EVENT_MEMORY_CANCEL),
+		.escr_msr	= { MSR_P4_DAC_ESCR0, MSR_P4_DAC_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_CANCEL, ST_RB_FULL)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_CANCEL, 64K_CONF),
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_MEMORY_COMPLETE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_MEMORY_COMPLETE),
+		.escr_msr	= { MSR_P4_SAAT_ESCR0 , MSR_P4_SAAT_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_COMPLETE, LSC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_COMPLETE, SSC),
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_LOAD_PORT_REPLAY] = {
+		.opcode		= P4_OPCODE(P4_EVENT_LOAD_PORT_REPLAY),
+		.escr_msr	= { MSR_P4_SAAT_ESCR0, MSR_P4_SAAT_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_LOAD_PORT_REPLAY, SPLIT_LD),
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_STORE_PORT_REPLAY] = {
+		.opcode		= P4_OPCODE(P4_EVENT_STORE_PORT_REPLAY),
+		.escr_msr	= { MSR_P4_SAAT_ESCR0 ,  MSR_P4_SAAT_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_STORE_PORT_REPLAY, SPLIT_ST),
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_MOB_LOAD_REPLAY] = {
+		.opcode		= P4_OPCODE(P4_EVENT_MOB_LOAD_REPLAY),
+		.escr_msr	= { MSR_P4_MOB_ESCR0, MSR_P4_MOB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, NO_STA)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, NO_STD)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, PARTIAL_DATA)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, UNALGN_ADDR),
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_PAGE_WALK_TYPE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_PAGE_WALK_TYPE),
+		.escr_msr	= { MSR_P4_PMH_ESCR0, MSR_P4_PMH_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_PAGE_WALK_TYPE, DTMISS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_PAGE_WALK_TYPE, ITMISS),
+		.shared		= 1,
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_BSQ_CACHE_REFERENCE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_BSQ_CACHE_REFERENCE),
+		.escr_msr	= { MSR_P4_BSU_ESCR0, MSR_P4_BSU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITS)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITM)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITS)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITM)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_MISS)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_MISS)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, WR_2ndL_MISS),
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_IOQ_ALLOCATION] = {
+		.opcode		= P4_OPCODE(P4_EVENT_IOQ_ALLOCATION),
+		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, DEFAULT)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, ALL_READ)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, ALL_WRITE)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_UC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WT)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WP)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WB)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, OWN)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, OTHER)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, PREFETCH),
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_IOQ_ACTIVE_ENTRIES] = {	/* shared ESCR */
+		.opcode		= P4_OPCODE(P4_EVENT_IOQ_ACTIVE_ENTRIES),
+		.escr_msr	= { MSR_P4_FSB_ESCR1,  MSR_P4_FSB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, DEFAULT)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, ALL_READ)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, ALL_WRITE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_UC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WT)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WP)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WB)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, OWN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, OTHER)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, PREFETCH),
+		.cntr		= { {2, -1, -1}, {3, -1, -1} },
+	},
+	[P4_EVENT_FSB_DATA_ACTIVITY] = {
+		.opcode		= P4_OPCODE(P4_EVENT_FSB_DATA_ACTIVITY),
+		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_DRV)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_OWN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_OTHER)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_DRV)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_OWN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_OTHER),
+		.shared		= 1,
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_BSQ_ALLOCATION] = {		/* shared ESCR, broken CCCR1 */
+		.opcode		= P4_OPCODE(P4_EVENT_BSQ_ALLOCATION),
+		.escr_msr	= { MSR_P4_BSU_ESCR0, MSR_P4_BSU_ESCR0 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_TYPE0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_TYPE1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LEN0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LEN1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_IO_TYPE)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LOCK_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_CACHE_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_SPLIT_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_DEM_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_ORD_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE2),
+		.cntr		= { {0, -1, -1}, {1, -1, -1} },
+	},
+	[P4_EVENT_BSQ_ACTIVE_ENTRIES] = {	/* shared ESCR */
+		.opcode		= P4_OPCODE(P4_EVENT_BSQ_ACTIVE_ENTRIES),
+		.escr_msr	= { MSR_P4_BSU_ESCR1 , MSR_P4_BSU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_TYPE0)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_TYPE1)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LEN0)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LEN1)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_IO_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LOCK_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_CACHE_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_SPLIT_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_DEM_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_ORD_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE0)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE1)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE2),
+		.cntr		= { {2, -1, -1}, {3, -1, -1} },
+	},
+	[P4_EVENT_SSE_INPUT_ASSIST] = {
+		.opcode		= P4_OPCODE(P4_EVENT_SSE_INPUT_ASSIST),
+		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_SSE_INPUT_ASSIST, ALL),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_PACKED_SP_UOP] = {
+		.opcode		= P4_OPCODE(P4_EVENT_PACKED_SP_UOP),
+		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_PACKED_SP_UOP, ALL),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_PACKED_DP_UOP] = {
+		.opcode		= P4_OPCODE(P4_EVENT_PACKED_DP_UOP),
+		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_PACKED_DP_UOP, ALL),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_SCALAR_SP_UOP] = {
+		.opcode		= P4_OPCODE(P4_EVENT_SCALAR_SP_UOP),
+		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_SCALAR_SP_UOP, ALL),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_SCALAR_DP_UOP] = {
+		.opcode		= P4_OPCODE(P4_EVENT_SCALAR_DP_UOP),
+		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_SCALAR_DP_UOP, ALL),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_64BIT_MMX_UOP] = {
+		.opcode		= P4_OPCODE(P4_EVENT_64BIT_MMX_UOP),
+		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_64BIT_MMX_UOP, ALL),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_128BIT_MMX_UOP] = {
+		.opcode		= P4_OPCODE(P4_EVENT_128BIT_MMX_UOP),
+		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_128BIT_MMX_UOP, ALL),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_X87_FP_UOP] = {
+		.opcode		= P4_OPCODE(P4_EVENT_X87_FP_UOP),
+		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_FP_UOP, ALL),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_TC_MISC] = {
+		.opcode		= P4_OPCODE(P4_EVENT_TC_MISC),
+		.escr_msr	= { MSR_P4_TC_ESCR0, MSR_P4_TC_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_MISC, FLUSH),
+		.cntr		= { {4, 5, -1}, {6, 7, -1} },
+	},
+	[P4_EVENT_GLOBAL_POWER_EVENTS] = {
+		.opcode		= P4_OPCODE(P4_EVENT_GLOBAL_POWER_EVENTS),
+		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_GLOBAL_POWER_EVENTS, RUNNING),
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_TC_MS_XFER] = {
+		.opcode		= P4_OPCODE(P4_EVENT_TC_MS_XFER),
+		.escr_msr	= { MSR_P4_MS_ESCR0, MSR_P4_MS_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_MS_XFER, CISC),
+		.cntr		= { {4, 5, -1}, {6, 7, -1} },
+	},
+	[P4_EVENT_UOP_QUEUE_WRITES] = {
+		.opcode		= P4_OPCODE(P4_EVENT_UOP_QUEUE_WRITES),
+		.escr_msr	= { MSR_P4_MS_ESCR0, MSR_P4_MS_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_TC_BUILD)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_TC_DELIVER)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_ROM),
+		.cntr		= { {4, 5, -1}, {6, 7, -1} },
+	},
+	[P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE),
+		.escr_msr	= { MSR_P4_TBPU_ESCR0 , MSR_P4_TBPU_ESCR0 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, CONDITIONAL)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, CALL)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, RETURN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, INDIRECT),
+		.cntr		= { {4, 5, -1}, {6, 7, -1} },
+	},
+	[P4_EVENT_RETIRED_BRANCH_TYPE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_RETIRED_BRANCH_TYPE),
+		.escr_msr	= { MSR_P4_TBPU_ESCR0 , MSR_P4_TBPU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, CONDITIONAL)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, CALL)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, RETURN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, INDIRECT),
+		.cntr		= { {4, 5, -1}, {6, 7, -1} },
+	},
+	[P4_EVENT_RESOURCE_STALL] = {
+		.opcode		= P4_OPCODE(P4_EVENT_RESOURCE_STALL),
+		.escr_msr	= { MSR_P4_ALF_ESCR0, MSR_P4_ALF_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_RESOURCE_STALL, SBFULL),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_WC_BUFFER] = {
+		.opcode		= P4_OPCODE(P4_EVENT_WC_BUFFER),
+		.escr_msr	= { MSR_P4_DAC_ESCR0, MSR_P4_DAC_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_WC_BUFFER, WCB_EVICTS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_WC_BUFFER, WCB_FULL_EVICTS),
+		.shared		= 1,
+		.cntr		= { {8, 9, -1}, {10, 11, -1} },
+	},
+	[P4_EVENT_B2B_CYCLES] = {
+		.opcode		= P4_OPCODE(P4_EVENT_B2B_CYCLES),
+		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	= 0,
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_BNR] = {
+		.opcode		= P4_OPCODE(P4_EVENT_BNR),
+		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	= 0,
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_SNOOP] = {
+		.opcode		= P4_OPCODE(P4_EVENT_SNOOP),
+		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	= 0,
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_RESPONSE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_RESPONSE),
+		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	= 0,
+		.cntr		= { {0, -1, -1}, {2, -1, -1} },
+	},
+	[P4_EVENT_FRONT_END_EVENT] = {
+		.opcode		= P4_OPCODE(P4_EVENT_FRONT_END_EVENT),
+		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_FRONT_END_EVENT, NBOGUS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FRONT_END_EVENT, BOGUS),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_EXECUTION_EVENT] = {
+		.opcode		= P4_OPCODE(P4_EVENT_EXECUTION_EVENT),
+		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS2)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS3)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS2)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS3),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_REPLAY_EVENT] = {
+		.opcode		= P4_OPCODE(P4_EVENT_REPLAY_EVENT),
+		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_REPLAY_EVENT, NBOGUS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_REPLAY_EVENT, BOGUS),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_INSTR_RETIRED] = {
+		.opcode		= P4_OPCODE(P4_EVENT_INSTR_RETIRED),
+		.escr_msr	= { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, NBOGUSNTAG)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, NBOGUSTAG)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, BOGUSNTAG)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, BOGUSTAG),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_UOPS_RETIRED] = {
+		.opcode		= P4_OPCODE(P4_EVENT_UOPS_RETIRED),
+		.escr_msr	= { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOPS_RETIRED, NBOGUS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOPS_RETIRED, BOGUS),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_UOP_TYPE] = {
+		.opcode		= P4_OPCODE(P4_EVENT_UOP_TYPE),
+		.escr_msr	= { MSR_P4_RAT_ESCR0, MSR_P4_RAT_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_TYPE, TAGLOADS)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_TYPE, TAGSTORES),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_BRANCH_RETIRED] = {
+		.opcode		= P4_OPCODE(P4_EVENT_BRANCH_RETIRED),
+		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMNP)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMNM)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMTP)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMTM),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_MISPRED_BRANCH_RETIRED] = {
+		.opcode		= P4_OPCODE(P4_EVENT_MISPRED_BRANCH_RETIRED),
+		.escr_msr	= { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_X87_ASSIST] = {
+		.opcode		= P4_OPCODE(P4_EVENT_X87_ASSIST),
+		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, FPSU)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, FPSO)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, POAO)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, POAU)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, PREA),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_MACHINE_CLEAR] = {
+		.opcode		= P4_OPCODE(P4_EVENT_MACHINE_CLEAR),
+		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, CLEAR)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, MOCLEAR)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, SMCLEAR),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+	[P4_EVENT_INSTR_COMPLETED] = {
+		.opcode		= P4_OPCODE(P4_EVENT_INSTR_COMPLETED),
+		.escr_msr	= { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_COMPLETED, NBOGUS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_COMPLETED, BOGUS),
+		.cntr		= { {12, 13, 16}, {14, 15, 17} },
+	},
+};
+
+#define P4_GEN_CACHE_EVENT(event, bit, metric)				  \
+	p4_config_pack_escr(P4_ESCR_EVENT(event)			| \
+			    P4_ESCR_EMASK_BIT(event, bit))		| \
+	p4_config_pack_cccr(metric					| \
+			    P4_CCCR_ESEL(P4_OPCODE_ESEL(P4_OPCODE(event))))
+
+static __initconst const u64 p4_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = P4_GEN_CACHE_EVENT(P4_EVENT_REPLAY_EVENT, NBOGUS,
+						P4_PEBS_METRIC__1stl_cache_load_miss_retired),
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = P4_GEN_CACHE_EVENT(P4_EVENT_REPLAY_EVENT, NBOGUS,
+						P4_PEBS_METRIC__2ndl_cache_load_miss_retired),
+	},
+},
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = P4_GEN_CACHE_EVENT(P4_EVENT_REPLAY_EVENT, NBOGUS,
+						P4_PEBS_METRIC__dtlb_load_miss_retired),
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0,
+		[ C(RESULT_MISS)   ] = P4_GEN_CACHE_EVENT(P4_EVENT_REPLAY_EVENT, NBOGUS,
+						P4_PEBS_METRIC__dtlb_store_miss_retired),
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = P4_GEN_CACHE_EVENT(P4_EVENT_ITLB_REFERENCE, HIT,
+						P4_PEBS_METRIC__none),
+		[ C(RESULT_MISS)   ] = P4_GEN_CACHE_EVENT(P4_EVENT_ITLB_REFERENCE, MISS,
+						P4_PEBS_METRIC__none),
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(NODE) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+};
+
+/*
+ * Because of Netburst being quite restricted in how many
+ * identical events may run simultaneously, we introduce event aliases,
+ * ie the different events which have the same functionality but
+ * utilize non-intersected resources (ESCR/CCCR/counter registers).
+ *
+ * This allow us to relax restrictions a bit and run two or more
+ * identical events together.
+ *
+ * Never set any custom internal bits such as P4_CONFIG_HT,
+ * P4_CONFIG_ALIASABLE or bits for P4_PEBS_METRIC, they are
+ * either up to date automatically or not applicable at all.
+ */
+struct p4_event_alias {
+	u64 original;
+	u64 alternative;
+} p4_event_aliases[] = {
+	{
+		/*
+		 * Non-halted cycles can be substituted with non-sleeping cycles (see
+		 * Intel SDM Vol3b for details). We need this alias to be able
+		 * to run nmi-watchdog and 'perf top' (or any other user space tool
+		 * which is interested in running PERF_COUNT_HW_CPU_CYCLES)
+		 * simultaneously.
+		 */
+	.original	=
+		p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_GLOBAL_POWER_EVENTS)		|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_GLOBAL_POWER_EVENTS, RUNNING)),
+	.alternative	=
+		p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_EXECUTION_EVENT)		|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS0)|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS1)|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS2)|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS3)|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS0)	|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS1)	|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS2)	|
+				    P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS3))|
+		p4_config_pack_cccr(P4_CCCR_THRESHOLD(15) | P4_CCCR_COMPLEMENT		|
+				    P4_CCCR_COMPARE),
+	},
+};
+
+static u64 p4_get_alias_event(u64 config)
+{
+	u64 config_match;
+	int i;
+
+	/*
+	 * Only event with special mark is allowed,
+	 * we're to be sure it didn't come as malformed
+	 * RAW event.
+	 */
+	if (!(config & P4_CONFIG_ALIASABLE))
+		return 0;
+
+	config_match = config & P4_CONFIG_EVENT_ALIAS_MASK;
+
+	for (i = 0; i < ARRAY_SIZE(p4_event_aliases); i++) {
+		if (config_match == p4_event_aliases[i].original) {
+			config_match = p4_event_aliases[i].alternative;
+			break;
+		} else if (config_match == p4_event_aliases[i].alternative) {
+			config_match = p4_event_aliases[i].original;
+			break;
+		}
+	}
+
+	if (i >= ARRAY_SIZE(p4_event_aliases))
+		return 0;
+
+	return config_match | (config & P4_CONFIG_EVENT_ALIAS_IMMUTABLE_BITS);
+}
+
+static u64 p4_general_events[PERF_COUNT_HW_MAX] = {
+  /* non-halted CPU clocks */
+  [PERF_COUNT_HW_CPU_CYCLES] =
+	p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_GLOBAL_POWER_EVENTS)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_GLOBAL_POWER_EVENTS, RUNNING))	|
+		P4_CONFIG_ALIASABLE,
+
+  /*
+   * retired instructions
+   * in a sake of simplicity we don't use the FSB tagging
+   */
+  [PERF_COUNT_HW_INSTRUCTIONS] =
+	p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_INSTR_RETIRED)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, NBOGUSNTAG)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, BOGUSNTAG)),
+
+  /* cache hits */
+  [PERF_COUNT_HW_CACHE_REFERENCES] =
+	p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_BSQ_CACHE_REFERENCE)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITS)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITE)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITM)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITS)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITE)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITM)),
+
+  /* cache misses */
+  [PERF_COUNT_HW_CACHE_MISSES] =
+	p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_BSQ_CACHE_REFERENCE)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_MISS)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_MISS)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, WR_2ndL_MISS)),
+
+  /* branch instructions retired */
+  [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =
+	p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_RETIRED_BRANCH_TYPE)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, CONDITIONAL)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, CALL)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, RETURN)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, INDIRECT)),
+
+  /* mispredicted branches retired */
+  [PERF_COUNT_HW_BRANCH_MISSES]	=
+	p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_MISPRED_BRANCH_RETIRED)	|
+		P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS)),
+
+  /* bus ready clocks (cpu is driving #DRDY_DRV\#DRDY_OWN):  */
+  [PERF_COUNT_HW_BUS_CYCLES] =
+	p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_FSB_DATA_ACTIVITY)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_DRV)		|
+		P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_OWN))	|
+	p4_config_pack_cccr(P4_CCCR_EDGE | P4_CCCR_COMPARE),
+};
+
+static struct p4_event_bind *p4_config_get_bind(u64 config)
+{
+	unsigned int evnt = p4_config_unpack_event(config);
+	struct p4_event_bind *bind = NULL;
+
+	if (evnt < ARRAY_SIZE(p4_event_bind_map))
+		bind = &p4_event_bind_map[evnt];
+
+	return bind;
+}
+
+static u64 p4_pmu_event_map(int hw_event)
+{
+	struct p4_event_bind *bind;
+	unsigned int esel;
+	u64 config;
+
+	config = p4_general_events[hw_event];
+	bind = p4_config_get_bind(config);
+	esel = P4_OPCODE_ESEL(bind->opcode);
+	config |= p4_config_pack_cccr(P4_CCCR_ESEL(esel));
+
+	return config;
+}
+
+/* check cpu model specifics */
+static bool p4_event_match_cpu_model(unsigned int event_idx)
+{
+	/* INSTR_COMPLETED event only exist for model 3, 4, 6 (Prescott) */
+	if (event_idx == P4_EVENT_INSTR_COMPLETED) {
+		if (boot_cpu_data.x86_model != 3 &&
+			boot_cpu_data.x86_model != 4 &&
+			boot_cpu_data.x86_model != 6)
+			return false;
+	}
+
+	/*
+	 * For info
+	 * - IQ_ESCR0, IQ_ESCR1 only for models 1 and 2
+	 */
+
+	return true;
+}
+
+static int p4_validate_raw_event(struct perf_event *event)
+{
+	unsigned int v, emask;
+
+	/* User data may have out-of-bound event index */
+	v = p4_config_unpack_event(event->attr.config);
+	if (v >= ARRAY_SIZE(p4_event_bind_map))
+		return -EINVAL;
+
+	/* It may be unsupported: */
+	if (!p4_event_match_cpu_model(v))
+		return -EINVAL;
+
+	/*
+	 * NOTE: P4_CCCR_THREAD_ANY has not the same meaning as
+	 * in Architectural Performance Monitoring, it means not
+	 * on _which_ logical cpu to count but rather _when_, ie it
+	 * depends on logical cpu state -- count event if one cpu active,
+	 * none, both or any, so we just allow user to pass any value
+	 * desired.
+	 *
+	 * In turn we always set Tx_OS/Tx_USR bits bound to logical
+	 * cpu without their propagation to another cpu
+	 */
+
+	/*
+	 * if an event is shared across the logical threads
+	 * the user needs special permissions to be able to use it
+	 */
+	if (p4_ht_active() && p4_event_bind_map[v].shared) {
+		if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
+			return -EACCES;
+	}
+
+	/* ESCR EventMask bits may be invalid */
+	emask = p4_config_unpack_escr(event->attr.config) & P4_ESCR_EVENTMASK_MASK;
+	if (emask & ~p4_event_bind_map[v].escr_emask)
+		return -EINVAL;
+
+	/*
+	 * it may have some invalid PEBS bits
+	 */
+	if (p4_config_pebs_has(event->attr.config, P4_PEBS_CONFIG_ENABLE))
+		return -EINVAL;
+
+	v = p4_config_unpack_metric(event->attr.config);
+	if (v >= ARRAY_SIZE(p4_pebs_bind_map))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int p4_hw_config(struct perf_event *event)
+{
+	int cpu = get_cpu();
+	int rc = 0;
+	u32 escr, cccr;
+
+	/*
+	 * the reason we use cpu that early is that: if we get scheduled
+	 * first time on the same cpu -- we will not need swap thread
+	 * specific flags in config (and will save some cpu cycles)
+	 */
+
+	cccr = p4_default_cccr_conf(cpu);
+	escr = p4_default_escr_conf(cpu, event->attr.exclude_kernel,
+					 event->attr.exclude_user);
+	event->hw.config = p4_config_pack_escr(escr) |
+			   p4_config_pack_cccr(cccr);
+
+	if (p4_ht_active() && p4_ht_thread(cpu))
+		event->hw.config = p4_set_ht_bit(event->hw.config);
+
+	if (event->attr.type == PERF_TYPE_RAW) {
+		struct p4_event_bind *bind;
+		unsigned int esel;
+		/*
+		 * Clear bits we reserve to be managed by kernel itself
+		 * and never allowed from a user space
+		 */
+		 event->attr.config &= P4_CONFIG_MASK;
+
+		rc = p4_validate_raw_event(event);
+		if (rc)
+			goto out;
+
+		/*
+		 * Note that for RAW events we allow user to use P4_CCCR_RESERVED
+		 * bits since we keep additional info here (for cache events and etc)
+		 */
+		event->hw.config |= event->attr.config;
+		bind = p4_config_get_bind(event->attr.config);
+		if (!bind) {
+			rc = -EINVAL;
+			goto out;
+		}
+		esel = P4_OPCODE_ESEL(bind->opcode);
+		event->hw.config |= p4_config_pack_cccr(P4_CCCR_ESEL(esel));
+	}
+
+	rc = x86_setup_perfctr(event);
+out:
+	put_cpu();
+	return rc;
+}
+
+static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
+{
+	u64 v;
+
+	/* an official way for overflow indication */
+	rdmsrl(hwc->config_base, v);
+	if (v & P4_CCCR_OVF) {
+		wrmsrl(hwc->config_base, v & ~P4_CCCR_OVF);
+		return 1;
+	}
+
+	/*
+	 * In some circumstances the overflow might issue an NMI but did
+	 * not set P4_CCCR_OVF bit. Because a counter holds a negative value
+	 * we simply check for high bit being set, if it's cleared it means
+	 * the counter has reached zero value and continued counting before
+	 * real NMI signal was received:
+	 */
+	rdmsrl(hwc->event_base, v);
+	if (!(v & ARCH_P4_UNFLAGGED_BIT))
+		return 1;
+
+	return 0;
+}
+
+static void p4_pmu_disable_pebs(void)
+{
+	/*
+	 * FIXME
+	 *
+	 * It's still allowed that two threads setup same cache
+	 * events so we can't simply clear metrics until we knew
+	 * no one is depending on us, so we need kind of counter
+	 * for "ReplayEvent" users.
+	 *
+	 * What is more complex -- RAW events, if user (for some
+	 * reason) will pass some cache event metric with improper
+	 * event opcode -- it's fine from hardware point of view
+	 * but completely nonsense from "meaning" of such action.
+	 *
+	 * So at moment let leave metrics turned on forever -- it's
+	 * ok for now but need to be revisited!
+	 *
+	 * (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, 0);
+	 * (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, 0);
+	 */
+}
+
+static inline void p4_pmu_disable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	/*
+	 * If event gets disabled while counter is in overflowed
+	 * state we need to clear P4_CCCR_OVF, otherwise interrupt get
+	 * asserted again and again
+	 */
+	(void)wrmsrl_safe(hwc->config_base,
+		p4_config_unpack_cccr(hwc->config) & ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED);
+}
+
+static void p4_pmu_disable_all(void)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	int idx;
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		struct perf_event *event = cpuc->events[idx];
+		if (!test_bit(idx, cpuc->active_mask))
+			continue;
+		p4_pmu_disable_event(event);
+	}
+
+	p4_pmu_disable_pebs();
+}
+
+/* configuration must be valid */
+static void p4_pmu_enable_pebs(u64 config)
+{
+	struct p4_pebs_bind *bind;
+	unsigned int idx;
+
+	BUILD_BUG_ON(P4_PEBS_METRIC__max > P4_PEBS_CONFIG_METRIC_MASK);
+
+	idx = p4_config_unpack_metric(config);
+	if (idx == P4_PEBS_METRIC__none)
+		return;
+
+	bind = &p4_pebs_bind_map[idx];
+
+	(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)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int thread = p4_ht_config_thread(hwc->config);
+	u64 escr_conf = p4_config_unpack_escr(p4_clear_ht_bit(hwc->config));
+	unsigned int idx = p4_config_unpack_event(hwc->config);
+	struct p4_event_bind *bind;
+	u64 escr_addr, cccr;
+
+	bind = &p4_event_bind_map[idx];
+	escr_addr = bind->escr_msr[thread];
+
+	/*
+	 * - we dont support cascaded counters yet
+	 * - and counter 1 is broken (erratum)
+	 */
+	WARN_ON_ONCE(p4_is_event_cascaded(hwc->config));
+	WARN_ON_ONCE(hwc->idx == 1);
+
+	/* we need a real Event value */
+	escr_conf &= ~P4_ESCR_EVENT_MASK;
+	escr_conf |= P4_ESCR_EVENT(P4_OPCODE_EVNT(bind->opcode));
+
+	cccr = p4_config_unpack_cccr(hwc->config);
+
+	/*
+	 * it could be Cache event so we need to write metrics
+	 * into additional MSRs
+	 */
+	p4_pmu_enable_pebs(hwc->config);
+
+	(void)wrmsrl_safe(escr_addr, escr_conf);
+	(void)wrmsrl_safe(hwc->config_base,
+				(cccr & ~P4_CCCR_RESERVED) | P4_CCCR_ENABLE);
+}
+
+static void p4_pmu_enable_all(int added)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	int idx;
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		struct perf_event *event = cpuc->events[idx];
+		if (!test_bit(idx, cpuc->active_mask))
+			continue;
+		p4_pmu_enable_event(event);
+	}
+}
+
+static int p4_pmu_handle_irq(struct pt_regs *regs)
+{
+	struct perf_sample_data data;
+	struct cpu_hw_events *cpuc;
+	struct perf_event *event;
+	struct hw_perf_event *hwc;
+	int idx, handled = 0;
+	u64 val;
+
+	cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		int overflow;
+
+		if (!test_bit(idx, cpuc->active_mask)) {
+			/* catch in-flight IRQs */
+			if (__test_and_clear_bit(idx, cpuc->running))
+				handled++;
+			continue;
+		}
+
+		event = cpuc->events[idx];
+		hwc = &event->hw;
+
+		WARN_ON_ONCE(hwc->idx != idx);
+
+		/* it might be unflagged overflow */
+		overflow = p4_pmu_clear_cccr_ovf(hwc);
+
+		val = x86_perf_event_update(event);
+		if (!overflow && (val & (1ULL << (x86_pmu.cntval_bits - 1))))
+			continue;
+
+		handled += overflow;
+
+		/* event overflow for sure */
+		perf_sample_data_init(&data, 0, hwc->last_period);
+
+		if (!x86_perf_event_set_period(event))
+			continue;
+
+
+		if (perf_event_overflow(event, &data, regs))
+			x86_pmu_stop(event, 0);
+	}
+
+	if (handled)
+		inc_irq_stat(apic_perf_irqs);
+
+	/*
+	 * When dealing with the unmasking of the LVTPC on P4 perf hw, it has
+	 * been observed that the OVF bit flag has to be cleared first _before_
+	 * the LVTPC can be unmasked.
+	 *
+	 * The reason is the NMI line will continue to be asserted while the OVF
+	 * bit is set.  This causes a second NMI to generate if the LVTPC is
+	 * unmasked before the OVF bit is cleared, leading to unknown NMI
+	 * messages.
+	 */
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+
+	return handled;
+}
+
+/*
+ * swap thread specific fields according to a thread
+ * we are going to run on
+ */
+static void p4_pmu_swap_config_ts(struct hw_perf_event *hwc, int cpu)
+{
+	u32 escr, cccr;
+
+	/*
+	 * we either lucky and continue on same cpu or no HT support
+	 */
+	if (!p4_should_swap_ts(hwc->config, cpu))
+		return;
+
+	/*
+	 * the event is migrated from an another logical
+	 * cpu, so we need to swap thread specific flags
+	 */
+
+	escr = p4_config_unpack_escr(hwc->config);
+	cccr = p4_config_unpack_cccr(hwc->config);
+
+	if (p4_ht_thread(cpu)) {
+		cccr &= ~P4_CCCR_OVF_PMI_T0;
+		cccr |= P4_CCCR_OVF_PMI_T1;
+		if (escr & P4_ESCR_T0_OS) {
+			escr &= ~P4_ESCR_T0_OS;
+			escr |= P4_ESCR_T1_OS;
+		}
+		if (escr & P4_ESCR_T0_USR) {
+			escr &= ~P4_ESCR_T0_USR;
+			escr |= P4_ESCR_T1_USR;
+		}
+		hwc->config  = p4_config_pack_escr(escr);
+		hwc->config |= p4_config_pack_cccr(cccr);
+		hwc->config |= P4_CONFIG_HT;
+	} else {
+		cccr &= ~P4_CCCR_OVF_PMI_T1;
+		cccr |= P4_CCCR_OVF_PMI_T0;
+		if (escr & P4_ESCR_T1_OS) {
+			escr &= ~P4_ESCR_T1_OS;
+			escr |= P4_ESCR_T0_OS;
+		}
+		if (escr & P4_ESCR_T1_USR) {
+			escr &= ~P4_ESCR_T1_USR;
+			escr |= P4_ESCR_T0_USR;
+		}
+		hwc->config  = p4_config_pack_escr(escr);
+		hwc->config |= p4_config_pack_cccr(cccr);
+		hwc->config &= ~P4_CONFIG_HT;
+	}
+}
+
+/*
+ * ESCR address hashing is tricky, ESCRs are not sequential
+ * in memory but all starts from MSR_P4_BSU_ESCR0 (0x03a0) and
+ * the metric between any ESCRs is laid in range [0xa0,0xe1]
+ *
+ * so we make ~70% filled hashtable
+ */
+
+#define P4_ESCR_MSR_BASE		0x000003a0
+#define P4_ESCR_MSR_MAX			0x000003e1
+#define P4_ESCR_MSR_TABLE_SIZE		(P4_ESCR_MSR_MAX - P4_ESCR_MSR_BASE + 1)
+#define P4_ESCR_MSR_IDX(msr)		(msr - P4_ESCR_MSR_BASE)
+#define P4_ESCR_MSR_TABLE_ENTRY(msr)	[P4_ESCR_MSR_IDX(msr)] = msr
+
+static const unsigned int p4_escr_table[P4_ESCR_MSR_TABLE_SIZE] = {
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_ALF_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_ALF_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_BPU_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_BPU_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_BSU_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_BSU_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_CRU_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_CRU_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_CRU_ESCR2),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_CRU_ESCR3),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_CRU_ESCR4),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_CRU_ESCR5),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_DAC_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_DAC_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_FIRM_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_FIRM_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_FLAME_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_FLAME_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_FSB_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_FSB_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_IQ_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_IQ_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_IS_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_IS_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_ITLB_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_ITLB_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_IX_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_IX_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_MOB_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_MOB_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_MS_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_MS_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_PMH_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_PMH_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_RAT_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_RAT_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_SAAT_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_SAAT_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_SSU_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_SSU_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_TBPU_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_TBPU_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_TC_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_TC_ESCR1),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_U2L_ESCR0),
+	P4_ESCR_MSR_TABLE_ENTRY(MSR_P4_U2L_ESCR1),
+};
+
+static int p4_get_escr_idx(unsigned int addr)
+{
+	unsigned int idx = P4_ESCR_MSR_IDX(addr);
+
+	if (unlikely(idx >= P4_ESCR_MSR_TABLE_SIZE	||
+			!p4_escr_table[idx]		||
+			p4_escr_table[idx] != addr)) {
+		WARN_ONCE(1, "P4 PMU: Wrong address passed: %x\n", addr);
+		return -1;
+	}
+
+	return idx;
+}
+
+static int p4_next_cntr(int thread, unsigned long *used_mask,
+			struct p4_event_bind *bind)
+{
+	int i, j;
+
+	for (i = 0; i < P4_CNTR_LIMIT; i++) {
+		j = bind->cntr[thread][i];
+		if (j != -1 && !test_bit(j, used_mask))
+			return j;
+	}
+
+	return -1;
+}
+
+static int p4_pmu_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
+{
+	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	unsigned long escr_mask[BITS_TO_LONGS(P4_ESCR_MSR_TABLE_SIZE)];
+	int cpu = smp_processor_id();
+	struct hw_perf_event *hwc;
+	struct p4_event_bind *bind;
+	unsigned int i, thread, num;
+	int cntr_idx, escr_idx;
+	u64 config_alias;
+	int pass;
+
+	bitmap_zero(used_mask, X86_PMC_IDX_MAX);
+	bitmap_zero(escr_mask, P4_ESCR_MSR_TABLE_SIZE);
+
+	for (i = 0, num = n; i < n; i++, num--) {
+
+		hwc = &cpuc->event_list[i]->hw;
+		thread = p4_ht_thread(cpu);
+		pass = 0;
+
+again:
+		/*
+		 * It's possible to hit a circular lock
+		 * between original and alternative events
+		 * if both are scheduled already.
+		 */
+		if (pass > 2)
+			goto done;
+
+		bind = p4_config_get_bind(hwc->config);
+		escr_idx = p4_get_escr_idx(bind->escr_msr[thread]);
+		if (unlikely(escr_idx == -1))
+			goto done;
+
+		if (hwc->idx != -1 && !p4_should_swap_ts(hwc->config, cpu)) {
+			cntr_idx = hwc->idx;
+			if (assign)
+				assign[i] = hwc->idx;
+			goto reserve;
+		}
+
+		cntr_idx = p4_next_cntr(thread, used_mask, bind);
+		if (cntr_idx == -1 || test_bit(escr_idx, escr_mask)) {
+			/*
+			 * Check whether an event alias is still available.
+			 */
+			config_alias = p4_get_alias_event(hwc->config);
+			if (!config_alias)
+				goto done;
+			hwc->config = config_alias;
+			pass++;
+			goto again;
+		}
+		/*
+		 * Perf does test runs to see if a whole group can be assigned
+		 * together succesfully.  There can be multiple rounds of this.
+		 * Unfortunately, p4_pmu_swap_config_ts touches the hwc->config
+		 * bits, such that the next round of group assignments will
+		 * cause the above p4_should_swap_ts to pass instead of fail.
+		 * This leads to counters exclusive to thread0 being used by
+		 * thread1.
+		 *
+		 * Solve this with a cheap hack, reset the idx back to -1 to
+		 * force a new lookup (p4_next_cntr) to get the right counter
+		 * for the right thread.
+		 *
+		 * This probably doesn't comply with the general spirit of how
+		 * perf wants to work, but P4 is special. :-(
+		 */
+		if (p4_should_swap_ts(hwc->config, cpu))
+			hwc->idx = -1;
+		p4_pmu_swap_config_ts(hwc, cpu);
+		if (assign)
+			assign[i] = cntr_idx;
+reserve:
+		set_bit(cntr_idx, used_mask);
+		set_bit(escr_idx, escr_mask);
+	}
+
+done:
+	return num ? -EINVAL : 0;
+}
+
+PMU_FORMAT_ATTR(cccr, "config:0-31" );
+PMU_FORMAT_ATTR(escr, "config:32-62");
+PMU_FORMAT_ATTR(ht,   "config:63"   );
+
+static struct attribute *intel_p4_formats_attr[] = {
+	&format_attr_cccr.attr,
+	&format_attr_escr.attr,
+	&format_attr_ht.attr,
+	NULL,
+};
+
+static __initconst const struct x86_pmu p4_pmu = {
+	.name			= "Netburst P4/Xeon",
+	.handle_irq		= p4_pmu_handle_irq,
+	.disable_all		= p4_pmu_disable_all,
+	.enable_all		= p4_pmu_enable_all,
+	.enable			= p4_pmu_enable_event,
+	.disable		= p4_pmu_disable_event,
+	.eventsel		= MSR_P4_BPU_CCCR0,
+	.perfctr		= MSR_P4_BPU_PERFCTR0,
+	.event_map		= p4_pmu_event_map,
+	.max_events		= ARRAY_SIZE(p4_general_events),
+	.get_event_constraints	= x86_get_event_constraints,
+	/*
+	 * IF HT disabled we may need to use all
+	 * ARCH_P4_MAX_CCCR counters simulaneously
+	 * though leave it restricted at moment assuming
+	 * HT is on
+	 */
+	.num_counters		= ARCH_P4_MAX_CCCR,
+	.apic			= 1,
+	.cntval_bits		= ARCH_P4_CNTRVAL_BITS,
+	.cntval_mask		= ARCH_P4_CNTRVAL_MASK,
+	.max_period		= (1ULL << (ARCH_P4_CNTRVAL_BITS - 1)) - 1,
+	.hw_config		= p4_hw_config,
+	.schedule_events	= p4_pmu_schedule_events,
+	/*
+	 * This handles erratum N15 in intel doc 249199-029,
+	 * the counter may not be updated correctly on write
+	 * so we need a second write operation to do the trick
+	 * (the official workaround didn't work)
+	 *
+	 * the former idea is taken from OProfile code
+	 */
+	.perfctr_second_write	= 1,
+
+	.format_attrs		= intel_p4_formats_attr,
+};
+
+__init int p4_pmu_init(void)
+{
+	unsigned int low, high;
+	int i, reg;
+
+	/* If we get stripped -- indexing fails */
+	BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC);
+
+	rdmsr(MSR_IA32_MISC_ENABLE, low, high);
+	if (!(low & (1 << 7))) {
+		pr_cont("unsupported Netburst CPU model %d ",
+			boot_cpu_data.x86_model);
+		return -ENODEV;
+	}
+
+	memcpy(hw_cache_event_ids, p4_hw_cache_event_ids,
+		sizeof(hw_cache_event_ids));
+
+	pr_cont("Netburst events, ");
+
+	x86_pmu = p4_pmu;
+
+	/*
+	 * Even though the counters are configured to interrupt a particular
+	 * logical processor when an overflow happens, testing has shown that
+	 * on kdump kernels (which uses a single cpu), thread1's counter
+	 * continues to run and will report an NMI on thread0.  Due to the
+	 * overflow bug, this leads to a stream of unknown NMIs.
+	 *
+	 * Solve this by zero'ing out the registers to mimic a reset.
+	 */
+	for (i = 0; i < x86_pmu.num_counters; i++) {
+		reg = x86_pmu_config_addr(i);
+		wrmsrl_safe(reg, 0ULL);
+	}
+
+	return 0;
+}
--- linux-4.4.0.orig/arch/x86/events/intel/p6.c
+++ linux-4.4.0/arch/x86/events/intel/p6.c
@@ -0,0 +1,279 @@
+#include <linux/perf_event.h>
+#include <linux/types.h>
+
+#include "../perf_event.h"
+
+/*
+ * Not sure about some of these
+ */
+static const u64 p6_perfmon_event_map[] =
+{
+  [PERF_COUNT_HW_CPU_CYCLES]		= 0x0079,	/* CPU_CLK_UNHALTED */
+  [PERF_COUNT_HW_INSTRUCTIONS]		= 0x00c0,	/* INST_RETIRED     */
+  [PERF_COUNT_HW_CACHE_REFERENCES]	= 0x0f2e,	/* L2_RQSTS:M:E:S:I */
+  [PERF_COUNT_HW_CACHE_MISSES]		= 0x012e,	/* L2_RQSTS:I       */
+  [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x00c4,	/* BR_INST_RETIRED  */
+  [PERF_COUNT_HW_BRANCH_MISSES]		= 0x00c5,	/* BR_MISS_PRED_RETIRED */
+  [PERF_COUNT_HW_BUS_CYCLES]		= 0x0062,	/* BUS_DRDY_CLOCKS  */
+  [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00a2,	/* RESOURCE_STALLS  */
+
+};
+
+static const u64 __initconst p6_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0043,	/* DATA_MEM_REFS       */
+                [ C(RESULT_MISS)   ] = 0x0045,	/* DCU_LINES_IN        */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0x0f29,	/* L2_LD:M:E:S:I       */
+	},
+        [ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+        },
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0080,	/* IFU_IFETCH         */
+		[ C(RESULT_MISS)   ] = 0x0f28,	/* L2_IFETCH:M:E:S:I  */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0x0025,	/* L2_M_LINES_INM     */
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0043,	/* DATA_MEM_REFS      */
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0080,	/* IFU_IFETCH         */
+		[ C(RESULT_MISS)   ] = 0x0085,	/* ITLB_MISS          */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c4,	/* BR_INST_RETIRED      */
+		[ C(RESULT_MISS)   ] = 0x00c5,	/* BR_MISS_PRED_RETIRED */
+        },
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+};
+
+static u64 p6_pmu_event_map(int hw_event)
+{
+	return p6_perfmon_event_map[hw_event];
+}
+
+/*
+ * Event setting that is specified not to count anything.
+ * We use this to effectively disable a counter.
+ *
+ * L2_RQSTS with 0 MESI unit mask.
+ */
+#define P6_NOP_EVENT			0x0000002EULL
+
+static struct event_constraint p6_event_constraints[] =
+{
+	INTEL_EVENT_CONSTRAINT(0xc1, 0x1),	/* FLOPS */
+	INTEL_EVENT_CONSTRAINT(0x10, 0x1),	/* FP_COMP_OPS_EXE */
+	INTEL_EVENT_CONSTRAINT(0x11, 0x2),	/* FP_ASSIST */
+	INTEL_EVENT_CONSTRAINT(0x12, 0x2),	/* MUL */
+	INTEL_EVENT_CONSTRAINT(0x13, 0x2),	/* DIV */
+	INTEL_EVENT_CONSTRAINT(0x14, 0x1),	/* CYCLES_DIV_BUSY */
+	EVENT_CONSTRAINT_END
+};
+
+static void p6_pmu_disable_all(void)
+{
+	u64 val;
+
+	/* p6 only has one enable register */
+	rdmsrl(MSR_P6_EVNTSEL0, val);
+	val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
+	wrmsrl(MSR_P6_EVNTSEL0, val);
+}
+
+static void p6_pmu_enable_all(int added)
+{
+	unsigned long val;
+
+	/* p6 only has one enable register */
+	rdmsrl(MSR_P6_EVNTSEL0, val);
+	val |= ARCH_PERFMON_EVENTSEL_ENABLE;
+	wrmsrl(MSR_P6_EVNTSEL0, val);
+}
+
+static inline void
+p6_pmu_disable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 val = P6_NOP_EVENT;
+
+	(void)wrmsrl_safe(hwc->config_base, val);
+}
+
+static void p6_pmu_enable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 val;
+
+	val = hwc->config;
+
+	/*
+	 * p6 only has a global event enable, set on PerfEvtSel0
+	 * We "disable" events by programming P6_NOP_EVENT
+	 * and we rely on p6_pmu_enable_all() being called
+	 * to actually enable the events.
+	 */
+
+	(void)wrmsrl_safe(hwc->config_base, val);
+}
+
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(pc,	"config:19"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *intel_p6_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
+static __initconst const struct x86_pmu p6_pmu = {
+	.name			= "p6",
+	.handle_irq		= x86_pmu_handle_irq,
+	.disable_all		= p6_pmu_disable_all,
+	.enable_all		= p6_pmu_enable_all,
+	.enable			= p6_pmu_enable_event,
+	.disable		= p6_pmu_disable_event,
+	.hw_config		= x86_pmu_hw_config,
+	.schedule_events	= x86_schedule_events,
+	.eventsel		= MSR_P6_EVNTSEL0,
+	.perfctr		= MSR_P6_PERFCTR0,
+	.event_map		= p6_pmu_event_map,
+	.max_events		= ARRAY_SIZE(p6_perfmon_event_map),
+	.apic			= 1,
+	.max_period		= (1ULL << 31) - 1,
+	.version		= 0,
+	.num_counters		= 2,
+	/*
+	 * Events have 40 bits implemented. However they are designed such
+	 * that bits [32-39] are sign extensions of bit 31. As such the
+	 * effective width of a event for P6-like PMU is 32 bits only.
+	 *
+	 * See IA-32 Intel Architecture Software developer manual Vol 3B
+	 */
+	.cntval_bits		= 32,
+	.cntval_mask		= (1ULL << 32) - 1,
+	.get_event_constraints	= x86_get_event_constraints,
+	.event_constraints	= p6_event_constraints,
+
+	.format_attrs		= intel_p6_formats_attr,
+	.events_sysfs_show	= intel_event_sysfs_show,
+
+};
+
+static __init void p6_pmu_rdpmc_quirk(void)
+{
+	if (boot_cpu_data.x86_stepping < 9) {
+		/*
+		 * PPro erratum 26; fixed in stepping 9 and above.
+		 */
+		pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n");
+		x86_pmu.attr_rdpmc_broken = 1;
+		x86_pmu.attr_rdpmc = 0;
+	}
+}
+
+__init int p6_pmu_init(void)
+{
+	x86_pmu = p6_pmu;
+
+	switch (boot_cpu_data.x86_model) {
+	case  1: /* Pentium Pro */
+		x86_add_quirk(p6_pmu_rdpmc_quirk);
+		break;
+
+	case  3: /* Pentium II - Klamath */
+	case  5: /* Pentium II - Deschutes */
+	case  6: /* Pentium II - Mendocino */
+		break;
+
+	case  7: /* Pentium III - Katmai */
+	case  8: /* Pentium III - Coppermine */
+	case 10: /* Pentium III Xeon */
+	case 11: /* Pentium III - Tualatin */
+		break;
+
+	case  9: /* Pentium M - Banias */
+	case 13: /* Pentium M - Dothan */
+		break;
+
+	default:
+		pr_cont("unsupported p6 CPU model %d ", boot_cpu_data.x86_model);
+		return -ENODEV;
+	}
+
+	memcpy(hw_cache_event_ids, p6_hw_cache_event_ids,
+		sizeof(hw_cache_event_ids));
+
+	return 0;
+}
--- linux-4.4.0.orig/arch/x86/events/intel/pt.c
+++ linux-4.4.0/arch/x86/events/intel/pt.c
@@ -0,0 +1,1181 @@
+/*
+ * Intel(R) Processor Trace PMU driver for perf
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * Intel PT is specified in the Intel Architecture Instruction Set Extensions
+ * Programming Reference:
+ * http://software.intel.com/en-us/intel-isa-extensions
+ */
+
+#undef DEBUG
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+
+#include <asm/perf_event.h>
+#include <asm/insn.h>
+#include <asm/io.h>
+
+#include "../perf_event.h"
+#include "pt.h"
+
+static DEFINE_PER_CPU(struct pt, pt_ctx);
+
+static struct pt_pmu pt_pmu;
+
+enum cpuid_regs {
+	CR_EAX = 0,
+	CR_ECX,
+	CR_EDX,
+	CR_EBX
+};
+
+/*
+ * Capabilities of Intel PT hardware, such as number of address bits or
+ * supported output schemes, are cached and exported to userspace as "caps"
+ * attribute group of pt pmu device
+ * (/sys/bus/event_source/devices/intel_pt/caps/) so that userspace can store
+ * relevant bits together with intel_pt traces.
+ *
+ * These are necessary for both trace decoding (payloads_lip, contains address
+ * width encoded in IP-related packets), and event configuration (bitmasks with
+ * permitted values for certain bit fields).
+ */
+#define PT_CAP(_n, _l, _r, _m)						\
+	[PT_CAP_ ## _n] = { .name = __stringify(_n), .leaf = _l,	\
+			    .reg = _r, .mask = _m }
+
+static struct pt_cap_desc {
+	const char	*name;
+	u32		leaf;
+	u8		reg;
+	u32		mask;
+} pt_caps[] = {
+	PT_CAP(max_subleaf,		0, CR_EAX, 0xffffffff),
+	PT_CAP(cr3_filtering,		0, CR_EBX, BIT(0)),
+	PT_CAP(psb_cyc,			0, CR_EBX, BIT(1)),
+	PT_CAP(mtc,			0, CR_EBX, BIT(3)),
+	PT_CAP(topa_output,		0, CR_ECX, BIT(0)),
+	PT_CAP(topa_multiple_entries,	0, CR_ECX, BIT(1)),
+	PT_CAP(single_range_output,	0, CR_ECX, BIT(2)),
+	PT_CAP(payloads_lip,		0, CR_ECX, BIT(31)),
+	PT_CAP(mtc_periods,		1, CR_EAX, 0xffff0000),
+	PT_CAP(cycle_thresholds,	1, CR_EBX, 0xffff),
+	PT_CAP(psb_periods,		1, CR_EBX, 0xffff0000),
+};
+
+static u32 pt_cap_get(enum pt_capabilities cap)
+{
+	struct pt_cap_desc *cd = &pt_caps[cap];
+	u32 c = pt_pmu.caps[cd->leaf * PT_CPUID_REGS_NUM + cd->reg];
+	unsigned int shift = __ffs(cd->mask);
+
+	return (c & cd->mask) >> shift;
+}
+
+static ssize_t pt_cap_show(struct device *cdev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct dev_ext_attribute *ea =
+		container_of(attr, struct dev_ext_attribute, attr);
+	enum pt_capabilities cap = (long)ea->var;
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", pt_cap_get(cap));
+}
+
+static struct attribute_group pt_cap_group = {
+	.name	= "caps",
+};
+
+PMU_FORMAT_ATTR(cyc,		"config:1"	);
+PMU_FORMAT_ATTR(mtc,		"config:9"	);
+PMU_FORMAT_ATTR(tsc,		"config:10"	);
+PMU_FORMAT_ATTR(noretcomp,	"config:11"	);
+PMU_FORMAT_ATTR(mtc_period,	"config:14-17"	);
+PMU_FORMAT_ATTR(cyc_thresh,	"config:19-22"	);
+PMU_FORMAT_ATTR(psb_period,	"config:24-27"	);
+
+static struct attribute *pt_formats_attr[] = {
+	&format_attr_cyc.attr,
+	&format_attr_mtc.attr,
+	&format_attr_tsc.attr,
+	&format_attr_noretcomp.attr,
+	&format_attr_mtc_period.attr,
+	&format_attr_cyc_thresh.attr,
+	&format_attr_psb_period.attr,
+	NULL,
+};
+
+static struct attribute_group pt_format_group = {
+	.name	= "format",
+	.attrs	= pt_formats_attr,
+};
+
+static const struct attribute_group *pt_attr_groups[] = {
+	&pt_cap_group,
+	&pt_format_group,
+	NULL,
+};
+
+static int __init pt_pmu_hw_init(void)
+{
+	struct dev_ext_attribute *de_attrs;
+	struct attribute **attrs;
+	size_t size;
+	int ret;
+	long i;
+
+	attrs = NULL;
+
+	for (i = 0; i < PT_CPUID_LEAVES; i++) {
+		cpuid_count(20, i,
+			    &pt_pmu.caps[CR_EAX + i*PT_CPUID_REGS_NUM],
+			    &pt_pmu.caps[CR_EBX + i*PT_CPUID_REGS_NUM],
+			    &pt_pmu.caps[CR_ECX + i*PT_CPUID_REGS_NUM],
+			    &pt_pmu.caps[CR_EDX + i*PT_CPUID_REGS_NUM]);
+	}
+
+	ret = -ENOMEM;
+	size = sizeof(struct attribute *) * (ARRAY_SIZE(pt_caps)+1);
+	attrs = kzalloc(size, GFP_KERNEL);
+	if (!attrs)
+		goto fail;
+
+	size = sizeof(struct dev_ext_attribute) * (ARRAY_SIZE(pt_caps)+1);
+	de_attrs = kzalloc(size, GFP_KERNEL);
+	if (!de_attrs)
+		goto fail;
+
+	for (i = 0; i < ARRAY_SIZE(pt_caps); i++) {
+		struct dev_ext_attribute *de_attr = de_attrs + i;
+
+		de_attr->attr.attr.name = pt_caps[i].name;
+
+		sysfs_attr_init(&de_attr->attr.attr);
+
+		de_attr->attr.attr.mode		= S_IRUGO;
+		de_attr->attr.show		= pt_cap_show;
+		de_attr->var			= (void *)i;
+
+		attrs[i] = &de_attr->attr.attr;
+	}
+
+	pt_cap_group.attrs = attrs;
+
+	return 0;
+
+fail:
+	kfree(attrs);
+
+	return ret;
+}
+
+#define RTIT_CTL_CYC_PSB (RTIT_CTL_CYCLEACC	| \
+			  RTIT_CTL_CYC_THRESH	| \
+			  RTIT_CTL_PSB_FREQ)
+
+#define RTIT_CTL_MTC	(RTIT_CTL_MTC_EN	| \
+			 RTIT_CTL_MTC_RANGE)
+
+#define PT_CONFIG_MASK (RTIT_CTL_TSC_EN		| \
+			RTIT_CTL_DISRETC	| \
+			RTIT_CTL_CYC_PSB	| \
+			RTIT_CTL_MTC)
+
+static bool pt_event_valid(struct perf_event *event)
+{
+	u64 config = event->attr.config;
+	u64 allowed, requested;
+
+	if ((config & PT_CONFIG_MASK) != config)
+		return false;
+
+	if (config & RTIT_CTL_CYC_PSB) {
+		if (!pt_cap_get(PT_CAP_psb_cyc))
+			return false;
+
+		allowed = pt_cap_get(PT_CAP_psb_periods);
+		requested = (config & RTIT_CTL_PSB_FREQ) >>
+			RTIT_CTL_PSB_FREQ_OFFSET;
+		if (requested && (!(allowed & BIT(requested))))
+			return false;
+
+		allowed = pt_cap_get(PT_CAP_cycle_thresholds);
+		requested = (config & RTIT_CTL_CYC_THRESH) >>
+			RTIT_CTL_CYC_THRESH_OFFSET;
+		if (requested && (!(allowed & BIT(requested))))
+			return false;
+	}
+
+	if (config & RTIT_CTL_MTC) {
+		/*
+		 * In the unlikely case that CPUID lists valid mtc periods,
+		 * but not the mtc capability, drop out here.
+		 *
+		 * Spec says that setting mtc period bits while mtc bit in
+		 * CPUID is 0 will #GP, so better safe than sorry.
+		 */
+		if (!pt_cap_get(PT_CAP_mtc))
+			return false;
+
+		allowed = pt_cap_get(PT_CAP_mtc_periods);
+		if (!allowed)
+			return false;
+
+		requested = (config & RTIT_CTL_MTC_RANGE) >>
+			RTIT_CTL_MTC_RANGE_OFFSET;
+
+		if (!(allowed & BIT(requested)))
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * PT configuration helpers
+ * These all are cpu affine and operate on a local PT
+ */
+
+static void pt_config(struct perf_event *event)
+{
+	u64 reg;
+
+	if (!event->hw.itrace_started) {
+		event->hw.itrace_started = 1;
+		wrmsrl(MSR_IA32_RTIT_STATUS, 0);
+	}
+
+	reg = RTIT_CTL_TOPA | RTIT_CTL_BRANCH_EN | RTIT_CTL_TRACEEN;
+
+	if (!event->attr.exclude_kernel)
+		reg |= RTIT_CTL_OS;
+	if (!event->attr.exclude_user)
+		reg |= RTIT_CTL_USR;
+
+	reg |= (event->attr.config & PT_CONFIG_MASK);
+
+	wrmsrl(MSR_IA32_RTIT_CTL, reg);
+}
+
+static void pt_config_start(bool start)
+{
+	u64 ctl;
+
+	rdmsrl(MSR_IA32_RTIT_CTL, ctl);
+	if (start)
+		ctl |= RTIT_CTL_TRACEEN;
+	else
+		ctl &= ~RTIT_CTL_TRACEEN;
+	wrmsrl(MSR_IA32_RTIT_CTL, ctl);
+
+	/*
+	 * A wrmsr that disables trace generation serializes other PT
+	 * registers and causes all data packets to be written to memory,
+	 * but a fence is required for the data to become globally visible.
+	 *
+	 * The below WMB, separating data store and aux_head store matches
+	 * the consumer's RMB that separates aux_head load and data load.
+	 */
+	if (!start)
+		wmb();
+}
+
+static void pt_config_buffer(void *buf, unsigned int topa_idx,
+			     unsigned int output_off)
+{
+	u64 reg;
+
+	wrmsrl(MSR_IA32_RTIT_OUTPUT_BASE, virt_to_phys(buf));
+
+	reg = 0x7f | ((u64)topa_idx << 7) | ((u64)output_off << 32);
+
+	wrmsrl(MSR_IA32_RTIT_OUTPUT_MASK, reg);
+}
+
+/*
+ * Keep ToPA table-related metadata on the same page as the actual table,
+ * taking up a few words from the top
+ */
+
+#define TENTS_PER_PAGE (((PAGE_SIZE - 40) / sizeof(struct topa_entry)) - 1)
+
+/**
+ * struct topa - page-sized ToPA table with metadata at the top
+ * @table:	actual ToPA table entries, as understood by PT hardware
+ * @list:	linkage to struct pt_buffer's list of tables
+ * @phys:	physical address of this page
+ * @offset:	offset of the first entry in this table in the buffer
+ * @size:	total size of all entries in this table
+ * @last:	index of the last initialized entry in this table
+ */
+struct topa {
+	struct topa_entry	table[TENTS_PER_PAGE];
+	struct list_head	list;
+	u64			phys;
+	u64			offset;
+	size_t			size;
+	int			last;
+};
+
+/* make -1 stand for the last table entry */
+#define TOPA_ENTRY(t, i) ((i) == -1 ? &(t)->table[(t)->last] : &(t)->table[(i)])
+
+/**
+ * topa_alloc() - allocate page-sized ToPA table
+ * @cpu:	CPU on which to allocate.
+ * @gfp:	Allocation flags.
+ *
+ * Return:	On success, return the pointer to ToPA table page.
+ */
+static struct topa *topa_alloc(int cpu, gfp_t gfp)
+{
+	int node = cpu_to_node(cpu);
+	struct topa *topa;
+	struct page *p;
+
+	p = alloc_pages_node(node, gfp | __GFP_ZERO, 0);
+	if (!p)
+		return NULL;
+
+	topa = page_address(p);
+	topa->last = 0;
+	topa->phys = page_to_phys(p);
+
+	/*
+	 * In case of singe-entry ToPA, always put the self-referencing END
+	 * link as the 2nd entry in the table
+	 */
+	if (!pt_cap_get(PT_CAP_topa_multiple_entries)) {
+		TOPA_ENTRY(topa, 1)->base = topa->phys >> TOPA_SHIFT;
+		TOPA_ENTRY(topa, 1)->end = 1;
+	}
+
+	return topa;
+}
+
+/**
+ * topa_free() - free a page-sized ToPA table
+ * @topa:	Table to deallocate.
+ */
+static void topa_free(struct topa *topa)
+{
+	free_page((unsigned long)topa);
+}
+
+/**
+ * topa_insert_table() - insert a ToPA table into a buffer
+ * @buf:	 PT buffer that's being extended.
+ * @topa:	 New topa table to be inserted.
+ *
+ * If it's the first table in this buffer, set up buffer's pointers
+ * accordingly; otherwise, add a END=1 link entry to @topa to the current
+ * "last" table and adjust the last table pointer to @topa.
+ */
+static void topa_insert_table(struct pt_buffer *buf, struct topa *topa)
+{
+	struct topa *last = buf->last;
+
+	list_add_tail(&topa->list, &buf->tables);
+
+	if (!buf->first) {
+		buf->first = buf->last = buf->cur = topa;
+		return;
+	}
+
+	topa->offset = last->offset + last->size;
+	buf->last = topa;
+
+	if (!pt_cap_get(PT_CAP_topa_multiple_entries))
+		return;
+
+	BUG_ON(last->last != TENTS_PER_PAGE - 1);
+
+	TOPA_ENTRY(last, -1)->base = topa->phys >> TOPA_SHIFT;
+	TOPA_ENTRY(last, -1)->end = 1;
+}
+
+/**
+ * topa_table_full() - check if a ToPA table is filled up
+ * @topa:	ToPA table.
+ */
+static bool topa_table_full(struct topa *topa)
+{
+	/* single-entry ToPA is a special case */
+	if (!pt_cap_get(PT_CAP_topa_multiple_entries))
+		return !!topa->last;
+
+	return topa->last == TENTS_PER_PAGE - 1;
+}
+
+/**
+ * topa_insert_pages() - create a list of ToPA tables
+ * @buf:	PT buffer being initialized.
+ * @gfp:	Allocation flags.
+ *
+ * This initializes a list of ToPA tables with entries from
+ * the data_pages provided by rb_alloc_aux().
+ *
+ * Return:	0 on success or error code.
+ */
+static int topa_insert_pages(struct pt_buffer *buf, gfp_t gfp)
+{
+	struct topa *topa = buf->last;
+	int order = 0;
+	struct page *p;
+
+	p = virt_to_page(buf->data_pages[buf->nr_pages]);
+	if (PagePrivate(p))
+		order = page_private(p);
+
+	if (topa_table_full(topa)) {
+		topa = topa_alloc(buf->cpu, gfp);
+		if (!topa)
+			return -ENOMEM;
+
+		topa_insert_table(buf, topa);
+	}
+
+	TOPA_ENTRY(topa, -1)->base = page_to_phys(p) >> TOPA_SHIFT;
+	TOPA_ENTRY(topa, -1)->size = order;
+	if (!buf->snapshot && !pt_cap_get(PT_CAP_topa_multiple_entries)) {
+		TOPA_ENTRY(topa, -1)->intr = 1;
+		TOPA_ENTRY(topa, -1)->stop = 1;
+	}
+
+	topa->last++;
+	topa->size += sizes(order);
+
+	buf->nr_pages += 1ul << order;
+
+	return 0;
+}
+
+/**
+ * pt_topa_dump() - print ToPA tables and their entries
+ * @buf:	PT buffer.
+ */
+static void pt_topa_dump(struct pt_buffer *buf)
+{
+	struct topa *topa;
+
+	list_for_each_entry(topa, &buf->tables, list) {
+		int i;
+
+		pr_debug("# table @%p (%016Lx), off %llx size %zx\n", topa->table,
+			 topa->phys, topa->offset, topa->size);
+		for (i = 0; i < TENTS_PER_PAGE; i++) {
+			pr_debug("# entry @%p (%lx sz %u %c%c%c) raw=%16llx\n",
+				 &topa->table[i],
+				 (unsigned long)topa->table[i].base << TOPA_SHIFT,
+				 sizes(topa->table[i].size),
+				 topa->table[i].end ?  'E' : ' ',
+				 topa->table[i].intr ? 'I' : ' ',
+				 topa->table[i].stop ? 'S' : ' ',
+				 *(u64 *)&topa->table[i]);
+			if ((pt_cap_get(PT_CAP_topa_multiple_entries) &&
+			     topa->table[i].stop) ||
+			    topa->table[i].end)
+				break;
+		}
+	}
+}
+
+/**
+ * pt_buffer_advance() - advance to the next output region
+ * @buf:	PT buffer.
+ *
+ * Advance the current pointers in the buffer to the next ToPA entry.
+ */
+static void pt_buffer_advance(struct pt_buffer *buf)
+{
+	buf->output_off = 0;
+	buf->cur_idx++;
+
+	if (buf->cur_idx == buf->cur->last) {
+		if (buf->cur == buf->last)
+			buf->cur = buf->first;
+		else
+			buf->cur = list_entry(buf->cur->list.next, struct topa,
+					      list);
+		buf->cur_idx = 0;
+	}
+}
+
+/**
+ * pt_update_head() - calculate current offsets and sizes
+ * @pt:		Per-cpu pt context.
+ *
+ * Update buffer's current write pointer position and data size.
+ */
+static void pt_update_head(struct pt *pt)
+{
+	struct pt_buffer *buf = perf_get_aux(&pt->handle);
+	u64 topa_idx, base, old;
+
+	/* offset of the first region in this table from the beginning of buf */
+	base = buf->cur->offset + buf->output_off;
+
+	/* offset of the current output region within this table */
+	for (topa_idx = 0; topa_idx < buf->cur_idx; topa_idx++)
+		base += sizes(buf->cur->table[topa_idx].size);
+
+	if (buf->snapshot) {
+		local_set(&buf->data_size, base);
+	} else {
+		old = (local64_xchg(&buf->head, base) &
+		       ((buf->nr_pages << PAGE_SHIFT) - 1));
+		if (base < old)
+			base += buf->nr_pages << PAGE_SHIFT;
+
+		local_add(base - old, &buf->data_size);
+	}
+}
+
+/**
+ * pt_buffer_region() - obtain current output region's address
+ * @buf:	PT buffer.
+ */
+static void *pt_buffer_region(struct pt_buffer *buf)
+{
+	return phys_to_virt(buf->cur->table[buf->cur_idx].base << TOPA_SHIFT);
+}
+
+/**
+ * pt_buffer_region_size() - obtain current output region's size
+ * @buf:	PT buffer.
+ */
+static size_t pt_buffer_region_size(struct pt_buffer *buf)
+{
+	return sizes(buf->cur->table[buf->cur_idx].size);
+}
+
+/**
+ * pt_handle_status() - take care of possible status conditions
+ * @pt:		Per-cpu pt context.
+ */
+static void pt_handle_status(struct pt *pt)
+{
+	struct pt_buffer *buf = perf_get_aux(&pt->handle);
+	int advance = 0;
+	u64 status;
+
+	rdmsrl(MSR_IA32_RTIT_STATUS, status);
+
+	if (status & RTIT_STATUS_ERROR) {
+		pr_err_ratelimited("ToPA ERROR encountered, trying to recover\n");
+		pt_topa_dump(buf);
+		status &= ~RTIT_STATUS_ERROR;
+	}
+
+	if (status & RTIT_STATUS_STOPPED) {
+		status &= ~RTIT_STATUS_STOPPED;
+
+		/*
+		 * On systems that only do single-entry ToPA, hitting STOP
+		 * means we are already losing data; need to let the decoder
+		 * know.
+		 */
+		if (!pt_cap_get(PT_CAP_topa_multiple_entries) ||
+		    buf->output_off == sizes(TOPA_ENTRY(buf->cur, buf->cur_idx)->size)) {
+			local_inc(&buf->lost);
+			advance++;
+		}
+	}
+
+	/*
+	 * Also on single-entry ToPA implementations, interrupt will come
+	 * before the output reaches its output region's boundary.
+	 */
+	if (!pt_cap_get(PT_CAP_topa_multiple_entries) && !buf->snapshot &&
+	    pt_buffer_region_size(buf) - buf->output_off <= TOPA_PMI_MARGIN) {
+		void *head = pt_buffer_region(buf);
+
+		/* everything within this margin needs to be zeroed out */
+		memset(head + buf->output_off, 0,
+		       pt_buffer_region_size(buf) -
+		       buf->output_off);
+		advance++;
+	}
+
+	if (advance)
+		pt_buffer_advance(buf);
+
+	wrmsrl(MSR_IA32_RTIT_STATUS, status);
+}
+
+/**
+ * pt_read_offset() - translate registers into buffer pointers
+ * @buf:	PT buffer.
+ *
+ * Set buffer's output pointers from MSR values.
+ */
+static void pt_read_offset(struct pt_buffer *buf)
+{
+	u64 offset, base_topa;
+
+	rdmsrl(MSR_IA32_RTIT_OUTPUT_BASE, base_topa);
+	buf->cur = phys_to_virt(base_topa);
+
+	rdmsrl(MSR_IA32_RTIT_OUTPUT_MASK, offset);
+	/* offset within current output region */
+	buf->output_off = offset >> 32;
+	/* index of current output region within this table */
+	buf->cur_idx = (offset & 0xffffff80) >> 7;
+}
+
+/**
+ * pt_topa_next_entry() - obtain index of the first page in the next ToPA entry
+ * @buf:	PT buffer.
+ * @pg:		Page offset in the buffer.
+ *
+ * When advancing to the next output region (ToPA entry), given a page offset
+ * into the buffer, we need to find the offset of the first page in the next
+ * region.
+ */
+static unsigned int pt_topa_next_entry(struct pt_buffer *buf, unsigned int pg)
+{
+	struct topa_entry *te = buf->topa_index[pg];
+
+	/* one region */
+	if (buf->first == buf->last && buf->first->last == 1)
+		return pg;
+
+	do {
+		pg++;
+		pg &= buf->nr_pages - 1;
+	} while (buf->topa_index[pg] == te);
+
+	return pg;
+}
+
+/**
+ * pt_buffer_reset_markers() - place interrupt and stop bits in the buffer
+ * @buf:	PT buffer.
+ * @handle:	Current output handle.
+ *
+ * Place INT and STOP marks to prevent overwriting old data that the consumer
+ * hasn't yet collected and waking up the consumer after a certain fraction of
+ * the buffer has filled up. Only needed and sensible for non-snapshot counters.
+ *
+ * This obviously relies on buf::head to figure out buffer markers, so it has
+ * to be called after pt_buffer_reset_offsets() and before the hardware tracing
+ * is enabled.
+ */
+static int pt_buffer_reset_markers(struct pt_buffer *buf,
+				   struct perf_output_handle *handle)
+
+{
+	unsigned long head = local64_read(&buf->head);
+	unsigned long idx, npages, wakeup;
+
+	/* can't stop in the middle of an output region */
+	if (buf->output_off + handle->size + 1 <
+	    sizes(TOPA_ENTRY(buf->cur, buf->cur_idx)->size))
+		return -EINVAL;
+
+
+	/* single entry ToPA is handled by marking all regions STOP=1 INT=1 */
+	if (!pt_cap_get(PT_CAP_topa_multiple_entries))
+		return 0;
+
+	/* clear STOP and INT from current entry */
+	buf->topa_index[buf->stop_pos]->stop = 0;
+	buf->topa_index[buf->stop_pos]->intr = 0;
+	buf->topa_index[buf->intr_pos]->intr = 0;
+
+	/* how many pages till the STOP marker */
+	npages = handle->size >> PAGE_SHIFT;
+
+	/* if it's on a page boundary, fill up one more page */
+	if (!offset_in_page(head + handle->size + 1))
+		npages++;
+
+	idx = (head >> PAGE_SHIFT) + npages;
+	idx &= buf->nr_pages - 1;
+	buf->stop_pos = idx;
+
+	wakeup = handle->wakeup >> PAGE_SHIFT;
+
+	/* in the worst case, wake up the consumer one page before hard stop */
+	idx = (head >> PAGE_SHIFT) + npages - 1;
+	if (idx > wakeup)
+		idx = wakeup;
+
+	idx &= buf->nr_pages - 1;
+	buf->intr_pos = idx;
+
+	buf->topa_index[buf->stop_pos]->stop = 1;
+	buf->topa_index[buf->stop_pos]->intr = 1;
+	buf->topa_index[buf->intr_pos]->intr = 1;
+
+	return 0;
+}
+
+/**
+ * pt_buffer_setup_topa_index() - build topa_index[] table of regions
+ * @buf:	PT buffer.
+ *
+ * topa_index[] references output regions indexed by offset into the
+ * buffer for purposes of quick reverse lookup.
+ */
+static void pt_buffer_setup_topa_index(struct pt_buffer *buf)
+{
+	struct topa *cur = buf->first, *prev = buf->last;
+	struct topa_entry *te_cur = TOPA_ENTRY(cur, 0),
+		*te_prev = TOPA_ENTRY(prev, prev->last - 1);
+	int pg = 0, idx = 0;
+
+	while (pg < buf->nr_pages) {
+		int tidx;
+
+		/* pages within one topa entry */
+		for (tidx = 0; tidx < 1 << te_cur->size; tidx++, pg++)
+			buf->topa_index[pg] = te_prev;
+
+		te_prev = te_cur;
+
+		if (idx == cur->last - 1) {
+			/* advance to next topa table */
+			idx = 0;
+			cur = list_entry(cur->list.next, struct topa, list);
+		} else {
+			idx++;
+		}
+		te_cur = TOPA_ENTRY(cur, idx);
+	}
+
+}
+
+/**
+ * pt_buffer_reset_offsets() - adjust buffer's write pointers from aux_head
+ * @buf:	PT buffer.
+ * @head:	Write pointer (aux_head) from AUX buffer.
+ *
+ * Find the ToPA table and entry corresponding to given @head and set buffer's
+ * "current" pointers accordingly. This is done after we have obtained the
+ * current aux_head position from a successful call to perf_aux_output_begin()
+ * to make sure the hardware is writing to the right place.
+ *
+ * This function modifies buf::{cur,cur_idx,output_off} that will be programmed
+ * into PT msrs when the tracing is enabled and buf::head and buf::data_size,
+ * which are used to determine INT and STOP markers' locations by a subsequent
+ * call to pt_buffer_reset_markers().
+ */
+static void pt_buffer_reset_offsets(struct pt_buffer *buf, unsigned long head)
+{
+	int pg;
+
+	if (buf->snapshot)
+		head &= (buf->nr_pages << PAGE_SHIFT) - 1;
+
+	pg = (head >> PAGE_SHIFT) & (buf->nr_pages - 1);
+	pg = pt_topa_next_entry(buf, pg);
+
+	buf->cur = (struct topa *)((unsigned long)buf->topa_index[pg] & PAGE_MASK);
+	buf->cur_idx = ((unsigned long)buf->topa_index[pg] -
+			(unsigned long)buf->cur) / sizeof(struct topa_entry);
+	buf->output_off = head & (sizes(buf->cur->table[buf->cur_idx].size) - 1);
+
+	local64_set(&buf->head, head);
+	local_set(&buf->data_size, 0);
+}
+
+/**
+ * pt_buffer_fini_topa() - deallocate ToPA structure of a buffer
+ * @buf:	PT buffer.
+ */
+static void pt_buffer_fini_topa(struct pt_buffer *buf)
+{
+	struct topa *topa, *iter;
+
+	list_for_each_entry_safe(topa, iter, &buf->tables, list) {
+		/*
+		 * right now, this is in free_aux() path only, so
+		 * no need to unlink this table from the list
+		 */
+		topa_free(topa);
+	}
+}
+
+/**
+ * pt_buffer_init_topa() - initialize ToPA table for pt buffer
+ * @buf:	PT buffer.
+ * @size:	Total size of all regions within this ToPA.
+ * @gfp:	Allocation flags.
+ */
+static int pt_buffer_init_topa(struct pt_buffer *buf, unsigned long nr_pages,
+			       gfp_t gfp)
+{
+	struct topa *topa;
+	int err;
+
+	topa = topa_alloc(buf->cpu, gfp);
+	if (!topa)
+		return -ENOMEM;
+
+	topa_insert_table(buf, topa);
+
+	while (buf->nr_pages < nr_pages) {
+		err = topa_insert_pages(buf, gfp);
+		if (err) {
+			pt_buffer_fini_topa(buf);
+			return -ENOMEM;
+		}
+	}
+
+	pt_buffer_setup_topa_index(buf);
+
+	/* link last table to the first one, unless we're double buffering */
+	if (pt_cap_get(PT_CAP_topa_multiple_entries)) {
+		TOPA_ENTRY(buf->last, -1)->base = buf->first->phys >> TOPA_SHIFT;
+		TOPA_ENTRY(buf->last, -1)->end = 1;
+	}
+
+	pt_topa_dump(buf);
+	return 0;
+}
+
+/**
+ * pt_buffer_setup_aux() - set up topa tables for a PT buffer
+ * @cpu:	Cpu on which to allocate, -1 means current.
+ * @pages:	Array of pointers to buffer pages passed from perf core.
+ * @nr_pages:	Number of pages in the buffer.
+ * @snapshot:	If this is a snapshot/overwrite counter.
+ *
+ * This is a pmu::setup_aux callback that sets up ToPA tables and all the
+ * bookkeeping for an AUX buffer.
+ *
+ * Return:	Our private PT buffer structure.
+ */
+static void *
+pt_buffer_setup_aux(int cpu, void **pages, int nr_pages, bool snapshot)
+{
+	struct pt_buffer *buf;
+	int node, ret;
+
+	if (!nr_pages)
+		return NULL;
+
+	if (cpu == -1)
+		cpu = raw_smp_processor_id();
+	node = cpu_to_node(cpu);
+
+	buf = kzalloc_node(offsetof(struct pt_buffer, topa_index[nr_pages]),
+			   GFP_KERNEL, node);
+	if (!buf)
+		return NULL;
+
+	buf->cpu = cpu;
+	buf->snapshot = snapshot;
+	buf->data_pages = pages;
+
+	INIT_LIST_HEAD(&buf->tables);
+
+	ret = pt_buffer_init_topa(buf, nr_pages, GFP_KERNEL);
+	if (ret) {
+		kfree(buf);
+		return NULL;
+	}
+
+	return buf;
+}
+
+/**
+ * pt_buffer_free_aux() - perf AUX deallocation path callback
+ * @data:	PT buffer.
+ */
+static void pt_buffer_free_aux(void *data)
+{
+	struct pt_buffer *buf = data;
+
+	pt_buffer_fini_topa(buf);
+	kfree(buf);
+}
+
+/**
+ * pt_buffer_is_full() - check if the buffer is full
+ * @buf:	PT buffer.
+ * @pt:		Per-cpu pt handle.
+ *
+ * If the user hasn't read data from the output region that aux_head
+ * points to, the buffer is considered full: the user needs to read at
+ * least this region and update aux_tail to point past it.
+ */
+static bool pt_buffer_is_full(struct pt_buffer *buf, struct pt *pt)
+{
+	if (buf->snapshot)
+		return false;
+
+	if (local_read(&buf->data_size) >= pt->handle.size)
+		return true;
+
+	return false;
+}
+
+/**
+ * intel_pt_interrupt() - PT PMI handler
+ */
+void intel_pt_interrupt(void)
+{
+	struct pt *pt = this_cpu_ptr(&pt_ctx);
+	struct pt_buffer *buf;
+	struct perf_event *event = pt->handle.event;
+
+	/*
+	 * There may be a dangling PT bit in the interrupt status register
+	 * after PT has been disabled by pt_event_stop(). Make sure we don't
+	 * do anything (particularly, re-enable) for this event here.
+	 */
+	if (!ACCESS_ONCE(pt->handle_nmi))
+		return;
+
+	pt_config_start(false);
+
+	if (!event)
+		return;
+
+	buf = perf_get_aux(&pt->handle);
+	if (!buf)
+		return;
+
+	pt_read_offset(buf);
+
+	pt_handle_status(pt);
+
+	pt_update_head(pt);
+
+	perf_aux_output_end(&pt->handle, local_xchg(&buf->data_size, 0),
+			    local_xchg(&buf->lost, 0));
+
+	if (!event->hw.state) {
+		int ret;
+
+		buf = perf_aux_output_begin(&pt->handle, event);
+		if (!buf) {
+			event->hw.state = PERF_HES_STOPPED;
+			return;
+		}
+
+		pt_buffer_reset_offsets(buf, pt->handle.head);
+		/* snapshot counters don't use PMI, so it's safe */
+		ret = pt_buffer_reset_markers(buf, &pt->handle);
+		if (ret) {
+			perf_aux_output_end(&pt->handle, 0, true);
+			return;
+		}
+
+		pt_config_buffer(buf->cur->table, buf->cur_idx,
+				 buf->output_off);
+		pt_config(event);
+	}
+}
+
+/*
+ * PMU callbacks
+ */
+
+static void pt_event_start(struct perf_event *event, int mode)
+{
+	struct pt *pt = this_cpu_ptr(&pt_ctx);
+	struct pt_buffer *buf = perf_get_aux(&pt->handle);
+
+	if (!buf || pt_buffer_is_full(buf, pt)) {
+		event->hw.state = PERF_HES_STOPPED;
+		return;
+	}
+
+	ACCESS_ONCE(pt->handle_nmi) = 1;
+	event->hw.state = 0;
+
+	pt_config_buffer(buf->cur->table, buf->cur_idx,
+			 buf->output_off);
+	pt_config(event);
+}
+
+static void pt_event_stop(struct perf_event *event, int mode)
+{
+	struct pt *pt = this_cpu_ptr(&pt_ctx);
+
+	/*
+	 * Protect against the PMI racing with disabling wrmsr,
+	 * see comment in intel_pt_interrupt().
+	 */
+	ACCESS_ONCE(pt->handle_nmi) = 0;
+	pt_config_start(false);
+
+	if (event->hw.state == PERF_HES_STOPPED)
+		return;
+
+	event->hw.state = PERF_HES_STOPPED;
+
+	if (mode & PERF_EF_UPDATE) {
+		struct pt_buffer *buf = perf_get_aux(&pt->handle);
+
+		if (!buf)
+			return;
+
+		if (WARN_ON_ONCE(pt->handle.event != event))
+			return;
+
+		pt_read_offset(buf);
+
+		pt_handle_status(pt);
+
+		pt_update_head(pt);
+	}
+}
+
+static void pt_event_del(struct perf_event *event, int mode)
+{
+	struct pt *pt = this_cpu_ptr(&pt_ctx);
+	struct pt_buffer *buf;
+
+	pt_event_stop(event, PERF_EF_UPDATE);
+
+	buf = perf_get_aux(&pt->handle);
+
+	if (buf) {
+		if (buf->snapshot)
+			pt->handle.head =
+				local_xchg(&buf->data_size,
+					   buf->nr_pages << PAGE_SHIFT);
+		perf_aux_output_end(&pt->handle, local_xchg(&buf->data_size, 0),
+				    local_xchg(&buf->lost, 0));
+	}
+}
+
+static int pt_event_add(struct perf_event *event, int mode)
+{
+	struct pt_buffer *buf;
+	struct pt *pt = this_cpu_ptr(&pt_ctx);
+	struct hw_perf_event *hwc = &event->hw;
+	int ret = -EBUSY;
+
+	if (pt->handle.event)
+		goto fail;
+
+	buf = perf_aux_output_begin(&pt->handle, event);
+	ret = -EINVAL;
+	if (!buf)
+		goto fail_stop;
+
+	pt_buffer_reset_offsets(buf, pt->handle.head);
+	if (!buf->snapshot) {
+		ret = pt_buffer_reset_markers(buf, &pt->handle);
+		if (ret)
+			goto fail_end_stop;
+	}
+
+	if (mode & PERF_EF_START) {
+		pt_event_start(event, 0);
+		ret = -EBUSY;
+		if (hwc->state == PERF_HES_STOPPED)
+			goto fail_end_stop;
+	} else {
+		hwc->state = PERF_HES_STOPPED;
+	}
+
+	return 0;
+
+fail_end_stop:
+	perf_aux_output_end(&pt->handle, 0, true);
+fail_stop:
+	hwc->state = PERF_HES_STOPPED;
+fail:
+	return ret;
+}
+
+static void pt_event_read(struct perf_event *event)
+{
+}
+
+static void pt_event_destroy(struct perf_event *event)
+{
+	x86_del_exclusive(x86_lbr_exclusive_pt);
+}
+
+static int pt_event_init(struct perf_event *event)
+{
+	if (event->attr.type != pt_pmu.pmu.type)
+		return -ENOENT;
+
+	if (!pt_event_valid(event))
+		return -EINVAL;
+
+	if (x86_add_exclusive(x86_lbr_exclusive_pt))
+		return -EBUSY;
+
+	event->destroy = pt_event_destroy;
+
+	return 0;
+}
+
+static __init int pt_init(void)
+{
+	int ret, cpu, prior_warn = 0;
+
+	BUILD_BUG_ON(sizeof(struct topa) > PAGE_SIZE);
+
+	if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_INTEL_PT))
+		return -ENODEV;
+
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		u64 ctl;
+
+		ret = rdmsrl_safe_on_cpu(cpu, MSR_IA32_RTIT_CTL, &ctl);
+		if (!ret && (ctl & RTIT_CTL_TRACEEN))
+			prior_warn++;
+	}
+	put_online_cpus();
+
+	if (prior_warn) {
+		x86_add_exclusive(x86_lbr_exclusive_pt);
+		pr_warn("PT is enabled at boot time, doing nothing\n");
+
+		return -EBUSY;
+	}
+
+	ret = pt_pmu_hw_init();
+	if (ret)
+		return ret;
+
+	if (!pt_cap_get(PT_CAP_topa_output)) {
+		pr_warn("ToPA output is not supported on this CPU\n");
+		return -ENODEV;
+	}
+
+	if (!pt_cap_get(PT_CAP_topa_multiple_entries))
+		pt_pmu.pmu.capabilities =
+			PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_SW_DOUBLEBUF;
+
+	pt_pmu.pmu.capabilities	|= PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE;
+	pt_pmu.pmu.attr_groups	= pt_attr_groups;
+	pt_pmu.pmu.task_ctx_nr	= perf_sw_context;
+	pt_pmu.pmu.event_init	= pt_event_init;
+	pt_pmu.pmu.add		= pt_event_add;
+	pt_pmu.pmu.del		= pt_event_del;
+	pt_pmu.pmu.start	= pt_event_start;
+	pt_pmu.pmu.stop		= pt_event_stop;
+	pt_pmu.pmu.read		= pt_event_read;
+	pt_pmu.pmu.setup_aux	= pt_buffer_setup_aux;
+	pt_pmu.pmu.free_aux	= pt_buffer_free_aux;
+	ret = perf_pmu_register(&pt_pmu.pmu, "intel_pt", -1);
+
+	return ret;
+}
+arch_initcall(pt_init);
--- linux-4.4.0.orig/arch/x86/events/intel/pt.h
+++ linux-4.4.0/arch/x86/events/intel/pt.h
@@ -0,0 +1,116 @@
+/*
+ * Intel(R) Processor Trace PMU driver for perf
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * Intel PT is specified in the Intel Architecture Instruction Set Extensions
+ * Programming Reference:
+ * http://software.intel.com/en-us/intel-isa-extensions
+ */
+
+#ifndef __INTEL_PT_H__
+#define __INTEL_PT_H__
+
+/*
+ * Single-entry ToPA: when this close to region boundary, switch
+ * buffers to avoid losing data.
+ */
+#define TOPA_PMI_MARGIN 512
+
+#define TOPA_SHIFT 12
+
+static inline unsigned int sizes(unsigned int tsz)
+{
+	return 1 << (tsz + TOPA_SHIFT);
+};
+
+struct topa_entry {
+	u64	end	: 1;
+	u64	rsvd0	: 1;
+	u64	intr	: 1;
+	u64	rsvd1	: 1;
+	u64	stop	: 1;
+	u64	rsvd2	: 1;
+	u64	size	: 4;
+	u64	rsvd3	: 2;
+	u64	base	: 36;
+	u64	rsvd4	: 16;
+};
+
+#define PT_CPUID_LEAVES		2
+#define PT_CPUID_REGS_NUM	4 /* number of regsters (eax, ebx, ecx, edx) */
+
+enum pt_capabilities {
+	PT_CAP_max_subleaf = 0,
+	PT_CAP_cr3_filtering,
+	PT_CAP_psb_cyc,
+	PT_CAP_mtc,
+	PT_CAP_topa_output,
+	PT_CAP_topa_multiple_entries,
+	PT_CAP_single_range_output,
+	PT_CAP_payloads_lip,
+	PT_CAP_mtc_periods,
+	PT_CAP_cycle_thresholds,
+	PT_CAP_psb_periods,
+};
+
+struct pt_pmu {
+	struct pmu		pmu;
+	u32			caps[PT_CPUID_REGS_NUM * PT_CPUID_LEAVES];
+};
+
+/**
+ * struct pt_buffer - buffer configuration; one buffer per task_struct or
+ *		cpu, depending on perf event configuration
+ * @cpu:	cpu for per-cpu allocation
+ * @tables:	list of ToPA tables in this buffer
+ * @first:	shorthand for first topa table
+ * @last:	shorthand for last topa table
+ * @cur:	current topa table
+ * @nr_pages:	buffer size in pages
+ * @cur_idx:	current output region's index within @cur table
+ * @output_off:	offset within the current output region
+ * @data_size:	running total of the amount of data in this buffer
+ * @lost:	if data was lost/truncated
+ * @head:	logical write offset inside the buffer
+ * @snapshot:	if this is for a snapshot/overwrite counter
+ * @stop_pos:	STOP topa entry in the buffer
+ * @intr_pos:	INT topa entry in the buffer
+ * @data_pages:	array of pages from perf
+ * @topa_index:	table of topa entries indexed by page offset
+ */
+struct pt_buffer {
+	int			cpu;
+	struct list_head	tables;
+	struct topa		*first, *last, *cur;
+	unsigned int		cur_idx;
+	size_t			output_off;
+	unsigned long		nr_pages;
+	local_t			data_size;
+	local_t			lost;
+	local64_t		head;
+	bool			snapshot;
+	unsigned long		stop_pos, intr_pos;
+	void			**data_pages;
+	struct topa_entry	*topa_index[0];
+};
+
+/**
+ * struct pt - per-cpu pt context
+ * @handle:	perf output handle
+ * @handle_nmi:	do handle PT PMI on this cpu, there's an active event
+ */
+struct pt {
+	struct perf_output_handle handle;
+	int			handle_nmi;
+};
+
+#endif /* __INTEL_PT_H__ */
--- linux-4.4.0.orig/arch/x86/events/intel/rapl.c
+++ linux-4.4.0/arch/x86/events/intel/rapl.c
@@ -0,0 +1,797 @@
+/*
+ * perf_event_intel_rapl.c: support Intel RAPL energy consumption counters
+ * Copyright (C) 2013 Google, Inc., Stephane Eranian
+ *
+ * Intel RAPL interface is specified in the IA-32 Manual Vol3b
+ * section 14.7.1 (September 2013)
+ *
+ * RAPL provides more controls than just reporting energy consumption
+ * however here we only expose the 3 energy consumption free running
+ * counters (pp0, pkg, dram).
+ *
+ * Each of those counters increments in a power unit defined by the
+ * RAPL_POWER_UNIT MSR. On SandyBridge, this unit is 1/(2^16) Joules
+ * but it can vary.
+ *
+ * Counter to rapl events mappings:
+ *
+ *  pp0 counter: consumption of all physical cores (power plane 0)
+ * 	  event: rapl_energy_cores
+ *    perf code: 0x1
+ *
+ *  pkg counter: consumption of the whole processor package
+ *	  event: rapl_energy_pkg
+ *    perf code: 0x2
+ *
+ * dram counter: consumption of the dram domain (servers only)
+ *	  event: rapl_energy_dram
+ *    perf code: 0x3
+ *
+ * dram counter: consumption of the builtin-gpu domain (client only)
+ *	  event: rapl_energy_gpu
+ *    perf code: 0x4
+ *
+ * We manage those counters as free running (read-only). They may be
+ * use simultaneously by other tools, such as turbostat.
+ *
+ * The events only support system-wide mode counting. There is no
+ * sampling support because it does not make sense and is not
+ * supported by the RAPL hardware.
+ *
+ * Because we want to avoid floating-point operations in the kernel,
+ * the events are all reported in fixed point arithmetic (32.32).
+ * Tools must adjust the counts to convert them to Watts using
+ * the duration of the measurement. Tools may use a function such as
+ * ldexp(raw_count, -32);
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/perf_event.h>
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+#include "../perf_event.h"
+
+/*
+ * RAPL energy status counters
+ */
+#define RAPL_IDX_PP0_NRG_STAT	0	/* all cores */
+#define INTEL_RAPL_PP0		0x1	/* pseudo-encoding */
+#define RAPL_IDX_PKG_NRG_STAT	1	/* entire package */
+#define INTEL_RAPL_PKG		0x2	/* pseudo-encoding */
+#define RAPL_IDX_RAM_NRG_STAT	2	/* DRAM */
+#define INTEL_RAPL_RAM		0x3	/* pseudo-encoding */
+#define RAPL_IDX_PP1_NRG_STAT	3	/* gpu */
+#define INTEL_RAPL_PP1		0x4	/* pseudo-encoding */
+
+#define NR_RAPL_DOMAINS         0x4
+static const char *rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
+	"pp0-core",
+	"package",
+	"dram",
+	"pp1-gpu",
+};
+
+/* Clients have PP0, PKG */
+#define RAPL_IDX_CLN	(1<<RAPL_IDX_PP0_NRG_STAT|\
+			 1<<RAPL_IDX_PKG_NRG_STAT|\
+			 1<<RAPL_IDX_PP1_NRG_STAT)
+
+/* Servers have PP0, PKG, RAM */
+#define RAPL_IDX_SRV	(1<<RAPL_IDX_PP0_NRG_STAT|\
+			 1<<RAPL_IDX_PKG_NRG_STAT|\
+			 1<<RAPL_IDX_RAM_NRG_STAT)
+
+/* Servers have PP0, PKG, RAM, PP1 */
+#define RAPL_IDX_HSW	(1<<RAPL_IDX_PP0_NRG_STAT|\
+			 1<<RAPL_IDX_PKG_NRG_STAT|\
+			 1<<RAPL_IDX_RAM_NRG_STAT|\
+			 1<<RAPL_IDX_PP1_NRG_STAT)
+
+/* Knights Landing has PKG, RAM */
+#define RAPL_IDX_KNL	(1<<RAPL_IDX_PKG_NRG_STAT|\
+			 1<<RAPL_IDX_RAM_NRG_STAT)
+
+/*
+ * event code: LSB 8 bits, passed in attr->config
+ * any other bit is reserved
+ */
+#define RAPL_EVENT_MASK	0xFFULL
+
+#define DEFINE_RAPL_FORMAT_ATTR(_var, _name, _format)		\
+static ssize_t __rapl_##_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, __rapl_##_var##_show, NULL)
+
+#define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */
+
+#define RAPL_EVENT_ATTR_STR(_name, v, str)				\
+static struct perf_pmu_events_attr event_attr_##v = {			\
+	.attr		= __ATTR(_name, 0444, rapl_sysfs_show, NULL),	\
+	.id		= 0,						\
+	.event_str	= str,						\
+};
+
+struct rapl_pmu {
+	spinlock_t	 lock;
+	int		 n_active; /* number of active events */
+	struct list_head active_list;
+	struct pmu	 *pmu; /* pointer to rapl_pmu_class */
+	ktime_t		 timer_interval; /* in ktime_t unit */
+	struct hrtimer   hrtimer;
+};
+
+static int rapl_hw_unit[NR_RAPL_DOMAINS] __read_mostly;  /* 1/2^hw_unit Joule */
+static struct pmu rapl_pmu_class;
+static cpumask_t rapl_cpu_mask;
+static int rapl_cntr_mask;
+
+static DEFINE_PER_CPU(struct rapl_pmu *, rapl_pmu);
+static DEFINE_PER_CPU(struct rapl_pmu *, rapl_pmu_to_free);
+
+static struct x86_pmu_quirk *rapl_quirks;
+static inline u64 rapl_read_counter(struct perf_event *event)
+{
+	u64 raw;
+	rdmsrl(event->hw.event_base, raw);
+	return raw;
+}
+
+#define rapl_add_quirk(func_)						\
+do {									\
+	static struct x86_pmu_quirk __quirk __initdata = {		\
+		.func = func_,						\
+	};								\
+	__quirk.next = rapl_quirks;					\
+	rapl_quirks = &__quirk;						\
+} while (0)
+
+static inline u64 rapl_scale(u64 v, int cfg)
+{
+	if (cfg > NR_RAPL_DOMAINS) {
+		pr_warn("invalid domain %d, failed to scale data\n", cfg);
+		return v;
+	}
+	/*
+	 * scale delta to smallest unit (1/2^32)
+	 * users must then scale back: count * 1/(1e9*2^32) to get Joules
+	 * or use ldexp(count, -32).
+	 * Watts = Joules/Time delta
+	 */
+	return v << (32 - rapl_hw_unit[cfg - 1]);
+}
+
+static u64 rapl_event_update(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 prev_raw_count, new_raw_count;
+	s64 delta, sdelta;
+	int shift = RAPL_CNTR_WIDTH;
+
+again:
+	prev_raw_count = local64_read(&hwc->prev_count);
+	rdmsrl(event->hw.event_base, new_raw_count);
+
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+			    new_raw_count) != prev_raw_count) {
+		cpu_relax();
+		goto again;
+	}
+
+	/*
+	 * Now we have the new raw value and have updated the prev
+	 * timestamp already. We can now calculate the elapsed delta
+	 * (event-)time and add that to the generic event.
+	 *
+	 * Careful, not all hw sign-extends above the physical width
+	 * of the count.
+	 */
+	delta = (new_raw_count << shift) - (prev_raw_count << shift);
+	delta >>= shift;
+
+	sdelta = rapl_scale(delta, event->hw.config);
+
+	local64_add(sdelta, &event->count);
+
+	return new_raw_count;
+}
+
+static void rapl_start_hrtimer(struct rapl_pmu *pmu)
+{
+       hrtimer_start(&pmu->hrtimer, pmu->timer_interval,
+		     HRTIMER_MODE_REL_PINNED);
+}
+
+static void rapl_stop_hrtimer(struct rapl_pmu *pmu)
+{
+	hrtimer_cancel(&pmu->hrtimer);
+}
+
+static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer)
+{
+	struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu);
+	struct perf_event *event;
+	unsigned long flags;
+
+	if (!pmu->n_active)
+		return HRTIMER_NORESTART;
+
+	spin_lock_irqsave(&pmu->lock, flags);
+
+	list_for_each_entry(event, &pmu->active_list, active_entry) {
+		rapl_event_update(event);
+	}
+
+	spin_unlock_irqrestore(&pmu->lock, flags);
+
+	hrtimer_forward_now(hrtimer, pmu->timer_interval);
+
+	return HRTIMER_RESTART;
+}
+
+static void rapl_hrtimer_init(struct rapl_pmu *pmu)
+{
+	struct hrtimer *hr = &pmu->hrtimer;
+
+	hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hr->function = rapl_hrtimer_handle;
+}
+
+static void __rapl_pmu_event_start(struct rapl_pmu *pmu,
+				   struct perf_event *event)
+{
+	if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+		return;
+
+	event->hw.state = 0;
+
+	list_add_tail(&event->active_entry, &pmu->active_list);
+
+	local64_set(&event->hw.prev_count, rapl_read_counter(event));
+
+	pmu->n_active++;
+	if (pmu->n_active == 1)
+		rapl_start_hrtimer(pmu);
+}
+
+static void rapl_pmu_event_start(struct perf_event *event, int mode)
+{
+	struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu);
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmu->lock, flags);
+	__rapl_pmu_event_start(pmu, event);
+	spin_unlock_irqrestore(&pmu->lock, flags);
+}
+
+static void rapl_pmu_event_stop(struct perf_event *event, int mode)
+{
+	struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmu->lock, flags);
+
+	/* mark event as deactivated and stopped */
+	if (!(hwc->state & PERF_HES_STOPPED)) {
+		WARN_ON_ONCE(pmu->n_active <= 0);
+		pmu->n_active--;
+		if (pmu->n_active == 0)
+			rapl_stop_hrtimer(pmu);
+
+		list_del(&event->active_entry);
+
+		WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+		hwc->state |= PERF_HES_STOPPED;
+	}
+
+	/* check if update of sw counter is necessary */
+	if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		/*
+		 * Drain the remaining delta count out of a event
+		 * that we are disabling:
+		 */
+		rapl_event_update(event);
+		hwc->state |= PERF_HES_UPTODATE;
+	}
+
+	spin_unlock_irqrestore(&pmu->lock, flags);
+}
+
+static int rapl_pmu_event_add(struct perf_event *event, int mode)
+{
+	struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmu->lock, flags);
+
+	hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+	if (mode & PERF_EF_START)
+		__rapl_pmu_event_start(pmu, event);
+
+	spin_unlock_irqrestore(&pmu->lock, flags);
+
+	return 0;
+}
+
+static void rapl_pmu_event_del(struct perf_event *event, int flags)
+{
+	rapl_pmu_event_stop(event, PERF_EF_UPDATE);
+}
+
+static int rapl_pmu_event_init(struct perf_event *event)
+{
+	u64 cfg = event->attr.config & RAPL_EVENT_MASK;
+	int bit, msr, ret = 0;
+
+	/* only look at RAPL events */
+	if (event->attr.type != rapl_pmu_class.type)
+		return -ENOENT;
+
+	/* check only supported bits are set */
+	if (event->attr.config & ~RAPL_EVENT_MASK)
+		return -EINVAL;
+
+	/*
+	 * check event is known (determines counter)
+	 */
+	switch (cfg) {
+	case INTEL_RAPL_PP0:
+		bit = RAPL_IDX_PP0_NRG_STAT;
+		msr = MSR_PP0_ENERGY_STATUS;
+		break;
+	case INTEL_RAPL_PKG:
+		bit = RAPL_IDX_PKG_NRG_STAT;
+		msr = MSR_PKG_ENERGY_STATUS;
+		break;
+	case INTEL_RAPL_RAM:
+		bit = RAPL_IDX_RAM_NRG_STAT;
+		msr = MSR_DRAM_ENERGY_STATUS;
+		break;
+	case INTEL_RAPL_PP1:
+		bit = RAPL_IDX_PP1_NRG_STAT;
+		msr = MSR_PP1_ENERGY_STATUS;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* check event supported */
+	if (!(rapl_cntr_mask & (1 << bit)))
+		return -EINVAL;
+
+	/* unsupported modes and filters */
+	if (event->attr.exclude_user   ||
+	    event->attr.exclude_kernel ||
+	    event->attr.exclude_hv     ||
+	    event->attr.exclude_idle   ||
+	    event->attr.exclude_host   ||
+	    event->attr.exclude_guest  ||
+	    event->attr.sample_period) /* no sampling */
+		return -EINVAL;
+
+	/* must be done before validate_group */
+	event->hw.event_base = msr;
+	event->hw.config = cfg;
+	event->hw.idx = bit;
+
+	return ret;
+}
+
+static void rapl_pmu_event_read(struct perf_event *event)
+{
+	rapl_event_update(event);
+}
+
+static ssize_t rapl_get_attr_cpumask(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return cpumap_print_to_pagebuf(true, buf, &rapl_cpu_mask);
+}
+
+static DEVICE_ATTR(cpumask, S_IRUGO, rapl_get_attr_cpumask, NULL);
+
+static struct attribute *rapl_pmu_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static struct attribute_group rapl_pmu_attr_group = {
+	.attrs = rapl_pmu_attrs,
+};
+
+static ssize_t rapl_sysfs_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *page)
+{
+	struct perf_pmu_events_attr *pmu_attr = \
+		container_of(attr, struct perf_pmu_events_attr, attr);
+
+	if (pmu_attr->event_str)
+		return sprintf(page, "%s", pmu_attr->event_str);
+
+	return 0;
+}
+
+RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01");
+RAPL_EVENT_ATTR_STR(energy-pkg  ,   rapl_pkg, "event=0x02");
+RAPL_EVENT_ATTR_STR(energy-ram  ,   rapl_ram, "event=0x03");
+RAPL_EVENT_ATTR_STR(energy-gpu  ,   rapl_gpu, "event=0x04");
+
+RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules");
+RAPL_EVENT_ATTR_STR(energy-pkg.unit  ,   rapl_pkg_unit, "Joules");
+RAPL_EVENT_ATTR_STR(energy-ram.unit  ,   rapl_ram_unit, "Joules");
+RAPL_EVENT_ATTR_STR(energy-gpu.unit  ,   rapl_gpu_unit, "Joules");
+
+/*
+ * we compute in 0.23 nJ increments regardless of MSR
+ */
+RAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-pkg.scale,     rapl_pkg_scale, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-ram.scale,     rapl_ram_scale, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-gpu.scale,     rapl_gpu_scale, "2.3283064365386962890625e-10");
+
+static struct attribute *rapl_events_srv_attr[] = {
+	EVENT_PTR(rapl_cores),
+	EVENT_PTR(rapl_pkg),
+	EVENT_PTR(rapl_ram),
+
+	EVENT_PTR(rapl_cores_unit),
+	EVENT_PTR(rapl_pkg_unit),
+	EVENT_PTR(rapl_ram_unit),
+
+	EVENT_PTR(rapl_cores_scale),
+	EVENT_PTR(rapl_pkg_scale),
+	EVENT_PTR(rapl_ram_scale),
+	NULL,
+};
+
+static struct attribute *rapl_events_cln_attr[] = {
+	EVENT_PTR(rapl_cores),
+	EVENT_PTR(rapl_pkg),
+	EVENT_PTR(rapl_gpu),
+
+	EVENT_PTR(rapl_cores_unit),
+	EVENT_PTR(rapl_pkg_unit),
+	EVENT_PTR(rapl_gpu_unit),
+
+	EVENT_PTR(rapl_cores_scale),
+	EVENT_PTR(rapl_pkg_scale),
+	EVENT_PTR(rapl_gpu_scale),
+	NULL,
+};
+
+static struct attribute *rapl_events_hsw_attr[] = {
+	EVENT_PTR(rapl_cores),
+	EVENT_PTR(rapl_pkg),
+	EVENT_PTR(rapl_gpu),
+	EVENT_PTR(rapl_ram),
+
+	EVENT_PTR(rapl_cores_unit),
+	EVENT_PTR(rapl_pkg_unit),
+	EVENT_PTR(rapl_gpu_unit),
+	EVENT_PTR(rapl_ram_unit),
+
+	EVENT_PTR(rapl_cores_scale),
+	EVENT_PTR(rapl_pkg_scale),
+	EVENT_PTR(rapl_gpu_scale),
+	EVENT_PTR(rapl_ram_scale),
+	NULL,
+};
+
+static struct attribute *rapl_events_knl_attr[] = {
+	EVENT_PTR(rapl_pkg),
+	EVENT_PTR(rapl_ram),
+
+	EVENT_PTR(rapl_pkg_unit),
+	EVENT_PTR(rapl_ram_unit),
+
+	EVENT_PTR(rapl_pkg_scale),
+	EVENT_PTR(rapl_ram_scale),
+	NULL,
+};
+
+static struct attribute_group rapl_pmu_events_group = {
+	.name = "events",
+	.attrs = NULL, /* patched at runtime */
+};
+
+DEFINE_RAPL_FORMAT_ATTR(event, event, "config:0-7");
+static struct attribute *rapl_formats_attr[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group rapl_pmu_format_group = {
+	.name = "format",
+	.attrs = rapl_formats_attr,
+};
+
+const struct attribute_group *rapl_attr_groups[] = {
+	&rapl_pmu_attr_group,
+	&rapl_pmu_format_group,
+	&rapl_pmu_events_group,
+	NULL,
+};
+
+static struct pmu rapl_pmu_class = {
+	.attr_groups	= rapl_attr_groups,
+	.task_ctx_nr	= perf_invalid_context, /* system-wide only */
+	.event_init	= rapl_pmu_event_init,
+	.add		= rapl_pmu_event_add, /* must have */
+	.del		= rapl_pmu_event_del, /* must have */
+	.start		= rapl_pmu_event_start,
+	.stop		= rapl_pmu_event_stop,
+	.read		= rapl_pmu_event_read,
+};
+
+static void rapl_cpu_exit(int cpu)
+{
+	struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu);
+	int i, phys_id = topology_physical_package_id(cpu);
+	int target = -1;
+
+	/* find a new cpu on same package */
+	for_each_online_cpu(i) {
+		if (i == cpu)
+			continue;
+		if (phys_id == topology_physical_package_id(i)) {
+			target = i;
+			break;
+		}
+	}
+	/*
+	 * clear cpu from cpumask
+	 * if was set in cpumask and still some cpu on package,
+	 * then move to new cpu
+	 */
+	if (cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask) && target >= 0)
+		cpumask_set_cpu(target, &rapl_cpu_mask);
+
+	WARN_ON(cpumask_empty(&rapl_cpu_mask));
+	/*
+	 * migrate events and context to new cpu
+	 */
+	if (target >= 0)
+		perf_pmu_migrate_context(pmu->pmu, cpu, target);
+
+	/* cancel overflow polling timer for CPU */
+	rapl_stop_hrtimer(pmu);
+}
+
+static void rapl_cpu_init(int cpu)
+{
+	int i, phys_id = topology_physical_package_id(cpu);
+
+	/* check if phys_is is already covered */
+	for_each_cpu(i, &rapl_cpu_mask) {
+		if (phys_id == topology_physical_package_id(i))
+			return;
+	}
+	/* was not found, so add it */
+	cpumask_set_cpu(cpu, &rapl_cpu_mask);
+}
+
+static __init void rapl_hsw_server_quirk(void)
+{
+	/*
+	 * DRAM domain on HSW server has fixed energy unit which can be
+	 * different than the unit from power unit MSR.
+	 * "Intel Xeon Processor E5-1600 and E5-2600 v3 Product Families, V2
+	 * of 2. Datasheet, September 2014, Reference Number: 330784-001 "
+	 */
+	rapl_hw_unit[RAPL_IDX_RAM_NRG_STAT] = 16;
+}
+
+static int rapl_cpu_prepare(int cpu)
+{
+	struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu);
+	int phys_id = topology_physical_package_id(cpu);
+	u64 ms;
+
+	if (pmu)
+		return 0;
+
+	if (phys_id < 0)
+		return -1;
+
+	pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
+	if (!pmu)
+		return -1;
+	spin_lock_init(&pmu->lock);
+
+	INIT_LIST_HEAD(&pmu->active_list);
+
+	pmu->pmu = &rapl_pmu_class;
+
+	/*
+	 * use reference of 200W for scaling the timeout
+	 * to avoid missing counter overflows.
+	 * 200W = 200 Joules/sec
+	 * divide interval by 2 to avoid lockstep (2 * 100)
+	 * if hw unit is 32, then we use 2 ms 1/200/2
+	 */
+	if (rapl_hw_unit[0] < 32)
+		ms = (1000 / (2 * 100)) * (1ULL << (32 - rapl_hw_unit[0] - 1));
+	else
+		ms = 2;
+
+	pmu->timer_interval = ms_to_ktime(ms);
+
+	rapl_hrtimer_init(pmu);
+
+	/* set RAPL pmu for this cpu for now */
+	per_cpu(rapl_pmu, cpu) = pmu;
+	per_cpu(rapl_pmu_to_free, cpu) = NULL;
+
+	return 0;
+}
+
+static void rapl_cpu_kfree(int cpu)
+{
+	struct rapl_pmu *pmu = per_cpu(rapl_pmu_to_free, cpu);
+
+	kfree(pmu);
+
+	per_cpu(rapl_pmu_to_free, cpu) = NULL;
+}
+
+static int rapl_cpu_dying(int cpu)
+{
+	struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu);
+
+	if (!pmu)
+		return 0;
+
+	per_cpu(rapl_pmu, cpu) = NULL;
+
+	per_cpu(rapl_pmu_to_free, cpu) = pmu;
+
+	return 0;
+}
+
+static int rapl_cpu_notifier(struct notifier_block *self,
+			     unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (long)hcpu;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		rapl_cpu_prepare(cpu);
+		break;
+	case CPU_STARTING:
+		rapl_cpu_init(cpu);
+		break;
+	case CPU_UP_CANCELED:
+	case CPU_DYING:
+		rapl_cpu_dying(cpu);
+		break;
+	case CPU_ONLINE:
+	case CPU_DEAD:
+		rapl_cpu_kfree(cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+		rapl_cpu_exit(cpu);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int rapl_check_hw_unit(void)
+{
+	u64 msr_rapl_power_unit_bits;
+	int i;
+
+	/* protect rdmsrl() to handle virtualization */
+	if (rdmsrl_safe(MSR_RAPL_POWER_UNIT, &msr_rapl_power_unit_bits))
+		return -1;
+	for (i = 0; i < NR_RAPL_DOMAINS; i++)
+		rapl_hw_unit[i] = (msr_rapl_power_unit_bits >> 8) & 0x1FULL;
+
+	return 0;
+}
+
+static const struct x86_cpu_id rapl_cpu_match[] = {
+	[0] = { .vendor = X86_VENDOR_INTEL, .family = 6 },
+	[1] = {},
+};
+
+static int __init rapl_pmu_init(void)
+{
+	struct rapl_pmu *pmu;
+	int cpu, ret;
+	struct x86_pmu_quirk *quirk;
+	int i;
+
+	/*
+	 * check for Intel processor family 6
+	 */
+	if (!x86_match_cpu(rapl_cpu_match))
+		return 0;
+
+	/* check supported CPU */
+	switch (boot_cpu_data.x86_model) {
+	case INTEL_FAM6_SANDYBRIDGE:
+	case INTEL_FAM6_IVYBRIDGE:
+		rapl_cntr_mask = RAPL_IDX_CLN;
+		rapl_pmu_events_group.attrs = rapl_events_cln_attr;
+		break;
+	case INTEL_FAM6_HASWELL_X:
+		rapl_add_quirk(rapl_hsw_server_quirk);
+		rapl_cntr_mask = RAPL_IDX_SRV;
+		rapl_pmu_events_group.attrs = rapl_events_srv_attr;
+		break;
+	case INTEL_FAM6_HASWELL_CORE:
+	case INTEL_FAM6_HASWELL_ULT:
+	case INTEL_FAM6_BROADWELL_CORE:
+		rapl_cntr_mask = RAPL_IDX_HSW;
+		rapl_pmu_events_group.attrs = rapl_events_hsw_attr;
+		break;
+	case INTEL_FAM6_SANDYBRIDGE_X:
+	case INTEL_FAM6_IVYBRIDGE_X:
+		rapl_cntr_mask = RAPL_IDX_SRV;
+		rapl_pmu_events_group.attrs = rapl_events_srv_attr;
+		break;
+	case INTEL_FAM6_XEON_PHI_KNL:
+		rapl_add_quirk(rapl_hsw_server_quirk);
+		rapl_cntr_mask = RAPL_IDX_KNL;
+		rapl_pmu_events_group.attrs = rapl_events_knl_attr;
+
+	default:
+		/* unsupported */
+		return 0;
+	}
+	ret = rapl_check_hw_unit();
+	if (ret)
+		return ret;
+
+	/* run cpu model quirks */
+	for (quirk = rapl_quirks; quirk; quirk = quirk->next)
+		quirk->func();
+	cpu_notifier_register_begin();
+
+	for_each_online_cpu(cpu) {
+		ret = rapl_cpu_prepare(cpu);
+		if (ret)
+			goto out;
+		rapl_cpu_init(cpu);
+	}
+
+	__perf_cpu_notifier(rapl_cpu_notifier);
+
+	ret = perf_pmu_register(&rapl_pmu_class, "power", -1);
+	if (WARN_ON(ret)) {
+		pr_info("RAPL PMU detected, registration failed (%d), RAPL PMU disabled\n", ret);
+		cpu_notifier_register_done();
+		return -1;
+	}
+
+	pmu = __this_cpu_read(rapl_pmu);
+
+	pr_info("RAPL PMU detected,"
+		" API unit is 2^-32 Joules,"
+		" %d fixed counters"
+		" %llu ms ovfl timer\n",
+		hweight32(rapl_cntr_mask),
+		ktime_to_ms(pmu->timer_interval));
+	for (i = 0; i < NR_RAPL_DOMAINS; i++) {
+		if (rapl_cntr_mask & (1 << i)) {
+			pr_info("hw unit of domain %s 2^-%d Joules\n",
+				rapl_domain_names[i], rapl_hw_unit[i]);
+		}
+	}
+out:
+	cpu_notifier_register_done();
+
+	return 0;
+}
+device_initcall(rapl_pmu_init);
--- linux-4.4.0.orig/arch/x86/events/intel/uncore.c
+++ linux-4.4.0/arch/x86/events/intel/uncore.c
@@ -0,0 +1,1398 @@
+#include "uncore.h"
+
+static struct intel_uncore_type *empty_uncore[] = { NULL, };
+struct intel_uncore_type **uncore_msr_uncores = empty_uncore;
+struct intel_uncore_type **uncore_pci_uncores = empty_uncore;
+
+static bool pcidrv_registered;
+struct pci_driver *uncore_pci_driver;
+/* pci bus to socket mapping */
+DEFINE_RAW_SPINLOCK(pci2phy_map_lock);
+struct list_head pci2phy_map_head = LIST_HEAD_INIT(pci2phy_map_head);
+struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
+
+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 uncore_constraint_fixed =
+	EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL);
+struct event_constraint uncore_constraint_empty =
+	EVENT_CONSTRAINT(0, 0, 0);
+
+int uncore_pcibus_to_physid(struct pci_bus *bus)
+{
+	struct pci2phy_map *map;
+	int phys_id = -1;
+
+	raw_spin_lock(&pci2phy_map_lock);
+	list_for_each_entry(map, &pci2phy_map_head, list) {
+		if (map->segment == pci_domain_nr(bus)) {
+			phys_id = map->pbus_to_physid[bus->number];
+			break;
+		}
+	}
+	raw_spin_unlock(&pci2phy_map_lock);
+
+	return phys_id;
+}
+
+struct pci2phy_map *__find_pci2phy_map(int segment)
+{
+	struct pci2phy_map *map, *alloc = NULL;
+	int i;
+
+	lockdep_assert_held(&pci2phy_map_lock);
+
+lookup:
+	list_for_each_entry(map, &pci2phy_map_head, list) {
+		if (map->segment == segment)
+			goto end;
+	}
+
+	if (!alloc) {
+		raw_spin_unlock(&pci2phy_map_lock);
+		alloc = kmalloc(sizeof(struct pci2phy_map), GFP_KERNEL);
+		raw_spin_lock(&pci2phy_map_lock);
+
+		if (!alloc)
+			return NULL;
+
+		goto lookup;
+	}
+
+	map = alloc;
+	alloc = NULL;
+	map->segment = segment;
+	for (i = 0; i < 256; i++)
+		map->pbus_to_physid[i] = -1;
+	list_add_tail(&map->list, &pci2phy_map_head);
+
+end:
+	kfree(alloc);
+	return map;
+}
+
+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);
+}
+
+struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
+{
+	return container_of(event->pmu, struct intel_uncore_pmu, pmu);
+}
+
+struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
+{
+	struct intel_uncore_box *box;
+
+	box = *per_cpu_ptr(pmu->box, cpu);
+	if (box)
+		return box;
+
+	raw_spin_lock(&uncore_box_lock);
+	/* Recheck in lock to handle races. */
+	if (*per_cpu_ptr(pmu->box, cpu))
+		goto out;
+	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;
+		}
+	}
+out:
+	raw_spin_unlock(&uncore_box_lock);
+
+	return *per_cpu_ptr(pmu->box, cpu);
+}
+
+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());
+}
+
+u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+	u64 count;
+
+	rdmsrl(event->hw.event_base, count);
+
+	return count;
+}
+
+/*
+ * generic get constraint function for shared match/mask registers.
+ */
+struct event_constraint *
+uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct intel_uncore_extra_reg *er;
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+	unsigned long flags;
+	bool ok = false;
+
+	/*
+	 * reg->alloc can be set due to existing state, so for fake box we
+	 * need to ignore this, otherwise we might fail to allocate proper
+	 * fake state for this extra reg constraint.
+	 */
+	if (reg1->idx == EXTRA_REG_NONE ||
+	    (!uncore_box_is_fake(box) && reg1->alloc))
+		return NULL;
+
+	er = &box->shared_regs[reg1->idx];
+	raw_spin_lock_irqsave(&er->lock, flags);
+	if (!atomic_read(&er->ref) ||
+	    (er->config1 == reg1->config && er->config2 == reg2->config)) {
+		atomic_inc(&er->ref);
+		er->config1 = reg1->config;
+		er->config2 = reg2->config;
+		ok = true;
+	}
+	raw_spin_unlock_irqrestore(&er->lock, flags);
+
+	if (ok) {
+		if (!uncore_box_is_fake(box))
+			reg1->alloc = 1;
+		return NULL;
+	}
+
+	return &uncore_constraint_empty;
+}
+
+void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct intel_uncore_extra_reg *er;
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+
+	/*
+	 * Only put constraint if extra reg was actually allocated. Also
+	 * takes care of event which do not use an extra shared reg.
+	 *
+	 * Also, if this is a fake box we shouldn't touch any event state
+	 * (reg->alloc) and we don't care about leaving inconsistent box
+	 * state either since it will be thrown out.
+	 */
+	if (uncore_box_is_fake(box) || !reg1->alloc)
+		return;
+
+	er = &box->shared_regs[reg1->idx];
+	atomic_dec(&er->ref);
+	reg1->alloc = 0;
+}
+
+u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx)
+{
+	struct intel_uncore_extra_reg *er;
+	unsigned long flags;
+	u64 config;
+
+	er = &box->shared_regs[idx];
+
+	raw_spin_lock_irqsave(&er->lock, flags);
+	config = er->config;
+	raw_spin_unlock_irqrestore(&er->lock, flags);
+
+	return config;
+}
+
+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);
+}
+
+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;
+	struct perf_event *event;
+	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);
+
+	/*
+	 * handle boxes with an active event list as opposed to active
+	 * counters
+	 */
+	list_for_each_entry(event, &box->active_list, active_entry) {
+		uncore_perf_event_update(box, event);
+	}
+
+	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(box->hrtimer_duration));
+	return HRTIMER_RESTART;
+}
+
+void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
+{
+	hrtimer_start(&box->hrtimer, ns_to_ktime(box->hrtimer_duration),
+		      HRTIMER_MODE_REL_PINNED);
+}
+
+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;
+}
+
+static struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type, int node)
+{
+	struct intel_uncore_box *box;
+	int i, size;
+
+	size = sizeof(*box) + type->num_shared_regs * sizeof(struct intel_uncore_extra_reg);
+
+	box = kzalloc_node(size, GFP_KERNEL, node);
+	if (!box)
+		return NULL;
+
+	for (i = 0; i < type->num_shared_regs; i++)
+		raw_spin_lock_init(&box->shared_regs[i].lock);
+
+	uncore_pmu_init_hrtimer(box);
+	atomic_set(&box->refcnt, 1);
+	box->cpu = -1;
+	box->phys_id = -1;
+
+	/* set default hrtimer timeout */
+	box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
+
+	INIT_LIST_HEAD(&box->active_list);
+
+	return box;
+}
+
+/*
+ * Using uncore_pmu_event_init pmu event_init callback
+ * as a detection point for uncore events.
+ */
+static int uncore_pmu_event_init(struct perf_event *event);
+
+static bool is_uncore_event(struct perf_event *event)
+{
+	return event->pmu->event_init == uncore_pmu_event_init;
+}
+
+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;
+
+	if (is_uncore_event(leader)) {
+		box->event_list[n] = leader;
+		n++;
+	}
+
+	if (!dogrp)
+		return n;
+
+	list_for_each_entry(event, &leader->sibling_list, group_entry) {
+		if (!is_uncore_event(event) ||
+		    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_get_event_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct intel_uncore_type *type = box->pmu->type;
+	struct event_constraint *c;
+
+	if (type->ops->get_constraint) {
+		c = type->ops->get_constraint(box, event);
+		if (c)
+			return c;
+	}
+
+	if (event->attr.config == UNCORE_FIXED_EVENT)
+		return &uncore_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 void uncore_put_event_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	if (box->pmu->type->ops->put_constraint)
+		box->pmu->type->ops->put_constraint(box, event);
+}
+
+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;
+	int i, wmin, wmax, ret = 0;
+	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_get_event_constraint(box, box->event_list[i]);
+		box->event_constraint[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 = box->event_constraint[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);
+		if (assign)
+			assign[i] = hwc->idx;
+	}
+	/* slow path */
+	if (i != n)
+		ret = perf_assign_events(box->event_constraint, n,
+					 wmin, wmax, n, assign);
+
+	if (!assign || ret) {
+		for (i = 0; i < n; i++)
+			uncore_put_event_constraint(box, box->event_list[i]);
+	}
+	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]) {
+			uncore_put_event_constraint(box, event);
+
+			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;
+}
+
+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 ret = -EINVAL, n;
+
+	fake_box = uncore_alloc_box(pmu->type, NUMA_NO_NODE);
+	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, NULL, n);
+out:
+	kfree(fake_box);
+	return ret;
+}
+
+static 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;
+
+	event->hw.idx = -1;
+	event->hw.last_tag = ~0ULL;
+	event->hw.extra_reg.idx = EXTRA_REG_NONE;
+	event->hw.branch_reg.idx = EXTRA_REG_NONE;
+
+	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;
+
+		/* fixed counters have event field hardcoded to zero */
+		hwc->config = 0ULL;
+	} else {
+		hwc->config = event->attr.config & pmu->type->event_mask;
+		if (pmu->type->ops->hw_config) {
+			ret = pmu->type->ops->hw_config(box, event);
+			if (ret)
+				return ret;
+		}
+	}
+
+	if (event->group_leader != event)
+		ret = uncore_validate_group(pmu, event);
+	else
+		ret = 0;
+
+	return ret;
+}
+
+static ssize_t uncore_get_attr_cpumask(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return cpumap_print_to_pagebuf(true, buf, &uncore_cpu_mask);
+}
+
+static DEVICE_ATTR(cpumask, S_IRUGO, uncore_get_attr_cpumask, NULL);
+
+static struct attribute *uncore_pmu_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static struct attribute_group uncore_pmu_attr_group = {
+	.attrs = uncore_pmu_attrs,
+};
+
+static int uncore_pmu_register(struct intel_uncore_pmu *pmu)
+{
+	int ret;
+
+	if (!pmu->type->pmu) {
+		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,
+		};
+	} else {
+		pmu->pmu = *pmu->type->pmu;
+		pmu->pmu.attr_groups = pmu->type->attr_groups;
+	}
+
+	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->events_group);
+	type->events_group = NULL;
+}
+
+static void __init 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 *attr_group;
+	struct attribute **attrs;
+	int i, j;
+
+	pmus = kzalloc(sizeof(*pmus) * type->num_boxes, GFP_KERNEL);
+	if (!pmus)
+		return -ENOMEM;
+
+	type->pmus = pmus;
+
+	type->unconstrainted = (struct event_constraint)
+		__EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
+				0, type->num_counters, 0, 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++;
+
+		attr_group = kzalloc(sizeof(struct attribute *) * (i + 1) +
+					sizeof(*attr_group), GFP_KERNEL);
+		if (!attr_group)
+			goto fail;
+
+		attrs = (struct attribute **)(attr_group + 1);
+		attr_group->name = "events";
+		attr_group->attrs = attrs;
+
+		for (j = 0; j < i; j++)
+			attrs[j] = &type->event_descs[j].attr.attr;
+
+		type->events_group = attr_group;
+	}
+
+	type->pmu_group = &uncore_pmu_attr_group;
+	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;
+}
+
+/*
+ * add a pci uncore device
+ */
+static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_box *box;
+	struct intel_uncore_type *type;
+	int phys_id;
+	bool first_box = false;
+
+	phys_id = uncore_pcibus_to_physid(pdev->bus);
+	if (phys_id < 0)
+		return -ENODEV;
+
+	if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
+		int idx = UNCORE_PCI_DEV_IDX(id->driver_data);
+		uncore_extra_pci_dev[phys_id][idx] = pdev;
+		pci_set_drvdata(pdev, NULL);
+		return 0;
+	}
+
+	type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
+	box = uncore_alloc_box(type, NUMA_NO_NODE);
+	if (!box)
+		return -ENOMEM;
+
+	/*
+	 * for performance monitoring unit with multiple boxes,
+	 * each box has a different function id.
+	 */
+	pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)];
+	/* Knights Landing uses a common PCI device ID for multiple instances of
+	 * an uncore PMU device type. There is only one entry per device type in
+	 * the knl_uncore_pci_ids table inspite of multiple devices present for
+	 * some device types. Hence PCI device idx would be 0 for all devices.
+	 * So increment pmu pointer to point to an unused array element.
+	 */
+	if (boot_cpu_data.x86_model == 87)
+		while (pmu->func_id >= 0)
+			pmu++;
+	if (pmu->func_id < 0)
+		pmu->func_id = pdev->devfn;
+	else
+		WARN_ON_ONCE(pmu->func_id != pdev->devfn);
+
+	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);
+	if (list_empty(&pmu->box_list))
+		first_box = true;
+	list_add_tail(&box->list, &pmu->box_list);
+	raw_spin_unlock(&uncore_box_lock);
+
+	if (first_box)
+		uncore_pmu_register(pmu);
+	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;
+	int i, cpu, phys_id;
+	bool last_box = false;
+
+	phys_id = uncore_pcibus_to_physid(pdev->bus);
+	box = pci_get_drvdata(pdev);
+	if (!box) {
+		for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) {
+			if (uncore_extra_pci_dev[phys_id][i] == pdev) {
+				uncore_extra_pci_dev[phys_id][i] = NULL;
+				break;
+			}
+		}
+		WARN_ON_ONCE(i >= UNCORE_EXTRA_PCI_DEV_MAX);
+		return;
+	}
+
+	pmu = box->pmu;
+	if (WARN_ON_ONCE(phys_id != box->phys_id))
+		return;
+
+	pci_set_drvdata(pdev, NULL);
+
+	raw_spin_lock(&uncore_box_lock);
+	list_del(&box->list);
+	if (list_empty(&pmu->box_list))
+		last_box = true;
+	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);
+
+	if (last_box)
+		perf_pmu_unregister(&pmu->pmu);
+}
+
+static int __init uncore_pci_init(void)
+{
+	int ret;
+
+	switch (boot_cpu_data.x86_model) {
+	case INTEL_FAM6_SANDYBRIDGE_X:
+		ret = snbep_uncore_pci_init();
+		break;
+	case INTEL_FAM6_IVYBRIDGE_X:
+		ret = ivbep_uncore_pci_init();
+		break;
+	case INTEL_FAM6_HASWELL_X:
+		ret = hswep_uncore_pci_init();
+		break;
+	case INTEL_FAM6_BROADWELL_X:
+	case INTEL_FAM6_BROADWELL_XEON_D:
+		ret = bdx_uncore_pci_init();
+		break;
+	case INTEL_FAM6_SANDYBRIDGE:
+		ret = snb_uncore_pci_init();
+		break;
+	case INTEL_FAM6_IVYBRIDGE:
+		ret = ivb_uncore_pci_init();
+		break;
+	case INTEL_FAM6_HASWELL_CORE:
+	case INTEL_FAM6_HASWELL_ULT:
+		ret = hsw_uncore_pci_init();
+		break;
+	case INTEL_FAM6_BROADWELL_CORE:
+		ret = bdw_uncore_pci_init();
+		break;
+	case INTEL_FAM6_XEON_PHI_KNL:
+		ret = knl_uncore_pci_init();
+		break;
+	default:
+		return 0;
+	}
+
+	if (ret)
+		return ret;
+
+	ret = uncore_types_init(uncore_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(uncore_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(uncore_pci_uncores);
+	}
+}
+
+/* CPU hot plug/unplug are serialized by cpu_add_remove_lock mutex */
+static LIST_HEAD(boxes_to_free);
+
+static void uncore_kfree_boxes(void)
+{
+	struct intel_uncore_box *box;
+
+	while (!list_empty(&boxes_to_free)) {
+		box = list_entry(boxes_to_free.next,
+				 struct intel_uncore_box, list);
+		list_del(&box->list);
+		kfree(box);
+	}
+}
+
+static void 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; uncore_msr_uncores[i]; i++) {
+		type = uncore_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))
+				list_add(&box->list, &boxes_to_free);
+		}
+	}
+}
+
+static int 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; uncore_msr_uncores[i]; i++) {
+		type = uncore_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;
+					if (box) {
+						list_add(&box->list,
+							 &boxes_to_free);
+						box = NULL;
+					}
+					break;
+				}
+			}
+
+			if (box) {
+				box->phys_id = phys_id;
+				uncore_box_init(box);
+			}
+		}
+	}
+	return 0;
+}
+
+static int 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; uncore_msr_uncores[i]; i++) {
+		type = uncore_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(type, cpu_to_node(cpu));
+			if (!box)
+				return -ENOMEM;
+
+			box->pmu = pmu;
+			box->phys_id = phys_id;
+			*per_cpu_ptr(pmu->box, cpu) = box;
+		}
+	}
+	return 0;
+}
+
+static void
+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 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(uncore_msr_uncores, cpu, target);
+	uncore_change_context(uncore_pci_uncores, cpu, target);
+}
+
+static void 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(uncore_msr_uncores, -1, cpu);
+	uncore_change_context(uncore_pci_uncores, -1, cpu);
+}
+
+static int 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;
+	case CPU_ONLINE:
+	case CPU_DEAD:
+		uncore_kfree_boxes();
+		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 = {
+	.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;
+
+	switch (boot_cpu_data.x86_model) {
+	case INTEL_FAM6_NEHALEM_EP:
+	case INTEL_FAM6_NEHALEM:
+	case INTEL_FAM6_WESTMERE:
+	case INTEL_FAM6_WESTMERE_EP:
+		nhm_uncore_cpu_init();
+		break;
+	case INTEL_FAM6_SANDYBRIDGE:
+	case INTEL_FAM6_IVYBRIDGE:
+	case INTEL_FAM6_HASWELL_CORE:
+	case INTEL_FAM6_HASWELL_ULT:
+	case INTEL_FAM6_HASWELL_GT3E:
+	case INTEL_FAM6_BROADWELL_CORE:
+	case INTEL_FAM6_BROADWELL_GT3E:
+		snb_uncore_cpu_init();
+		break;
+	case INTEL_FAM6_SANDYBRIDGE_X:
+		snbep_uncore_cpu_init();
+		break;
+	case INTEL_FAM6_NEHALEM_EX:
+	case INTEL_FAM6_WESTMERE_EX:
+		nhmex_uncore_cpu_init();
+		break;
+	case INTEL_FAM6_IVYBRIDGE_X:
+		ivbep_uncore_cpu_init();
+		break;
+	case INTEL_FAM6_HASWELL_X:
+		hswep_uncore_cpu_init();
+		break;
+	case INTEL_FAM6_BROADWELL_X:
+	case INTEL_FAM6_BROADWELL_XEON_D:
+		bdx_uncore_cpu_init();
+		break;
+	case INTEL_FAM6_XEON_PHI_KNL:
+		knl_uncore_cpu_init();
+		break;
+	default:
+		return 0;
+	}
+
+	ret = uncore_types_init(uncore_msr_uncores);
+	if (ret)
+		return ret;
+
+	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; uncore_msr_uncores[i]; i++) {
+		type = uncore_msr_uncores[i];
+		for (j = 0; j < type->num_boxes; j++) {
+			pmu = &type->pmus[j];
+			uncore_pmu_register(pmu);
+		}
+	}
+
+	return 0;
+}
+
+static void __init uncore_cpumask_init(void)
+{
+	int cpu;
+
+	/*
+	 * ony invoke once from msr or pci init code
+	 */
+	if (!cpumask_empty(&uncore_cpu_mask))
+		return;
+
+	cpu_notifier_register_begin();
+
+	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);
+
+	cpu_notifier_register_done();
+}
+
+
+static int __init intel_uncore_init(void)
+{
+	int ret;
+
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+		return -ENODEV;
+
+	if (cpu_has_hypervisor)
+		return -ENODEV;
+
+	ret = uncore_pci_init();
+	if (ret)
+		goto fail;
+	ret = uncore_cpu_init();
+	if (ret) {
+		uncore_pci_exit();
+		goto fail;
+	}
+	uncore_cpumask_init();
+
+	uncore_pmus_register();
+	return 0;
+fail:
+	return ret;
+}
+device_initcall(intel_uncore_init);
--- linux-4.4.0.orig/arch/x86/events/intel/uncore.h
+++ linux-4.4.0/arch/x86/events/intel/uncore.h
@@ -0,0 +1,357 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/perf_event.h>
+#include <asm/intel-family.h>
+#include "../perf_event.h"
+
+#define UNCORE_PMU_NAME_LEN		32
+#define UNCORE_PMU_HRTIMER_INTERVAL	(60LL * NSEC_PER_SEC)
+#define UNCORE_SNB_IMC_HRTIMER_INTERVAL (5ULL * NSEC_PER_SEC)
+
+#define UNCORE_FIXED_EVENT		0xff
+#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_PCI_DEV_DATA(type, idx)	((type << 8) | idx)
+#define UNCORE_PCI_DEV_TYPE(data)	((data >> 8) & 0xff)
+#define UNCORE_PCI_DEV_IDX(data)	(data & 0xff)
+#define UNCORE_EXTRA_PCI_DEV		0xff
+#define UNCORE_EXTRA_PCI_DEV_MAX	3
+
+/* support up to 8 sockets */
+#define UNCORE_SOCKET_MAX		8
+
+#define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff)
+
+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;
+	unsigned perf_ctr;
+	unsigned event_ctl;
+	unsigned event_mask;
+	unsigned fixed_ctr;
+	unsigned fixed_ctl;
+	unsigned box_ctl;
+	unsigned msr_offset;
+	unsigned num_shared_regs:8;
+	unsigned single_fixed:1;
+	unsigned pair_ctr_ctl:1;
+	unsigned *msr_offsets;
+	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[4];
+	struct pmu *pmu; /* for custom pmu ops */
+};
+
+#define pmu_group attr_groups[0]
+#define format_group attr_groups[1]
+#define events_group attr_groups[2]
+
+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 *);
+	int (*hw_config)(struct intel_uncore_box *, struct perf_event *);
+	struct event_constraint *(*get_constraint)(struct intel_uncore_box *,
+						   struct perf_event *);
+	void (*put_constraint)(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_extra_reg {
+	raw_spinlock_t lock;
+	u64 config, config1, config2;
+	atomic_t ref;
+};
+
+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];
+	struct event_constraint *event_constraint[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;
+	u64 hrtimer_duration; /* hrtimer timeout for this box */
+	struct hrtimer hrtimer;
+	struct list_head list;
+	struct list_head active_list;
+	void *io_addr;
+	struct intel_uncore_extra_reg shared_regs[0];
+};
+
+#define UNCORE_BOX_FLAG_INITIATED	0
+
+struct uncore_event_desc {
+	struct kobj_attribute attr;
+	const char *config;
+};
+
+struct pci2phy_map {
+	struct list_head list;
+	int segment;
+	int pbus_to_physid[256];
+};
+
+int uncore_pcibus_to_physid(struct pci_bus *bus);
+struct pci2phy_map *__find_pci2phy_map(int segment);
+
+ssize_t uncore_event_show(struct kobject *kobj,
+			  struct kobj_attribute *attr, char *buf);
+
+#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 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_offset(struct intel_uncore_box *box)
+{
+	struct intel_uncore_pmu *pmu = box->pmu;
+	return pmu->type->msr_offsets ?
+		pmu->type->msr_offsets[pmu->pmu_idx] :
+		pmu->type->msr_offset * pmu->pmu_idx;
+}
+
+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 + uncore_msr_box_offset(box);
+}
+
+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 + uncore_msr_box_offset(box);
+}
+
+static inline unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
+{
+	return box->pmu->type->fixed_ctr + uncore_msr_box_offset(box);
+}
+
+static inline
+unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx)
+{
+	return box->pmu->type->event_ctl +
+		(box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
+		uncore_msr_box_offset(box);
+}
+
+static inline
+unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
+{
+	return box->pmu->type->perf_ctr +
+		(box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
+		uncore_msr_box_offset(box);
+}
+
+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);
+	}
+}
+
+static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
+{
+	return (box->phys_id < 0);
+}
+
+struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event);
+struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu);
+struct intel_uncore_box *uncore_event_to_box(struct perf_event *event);
+u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event);
+void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
+void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
+void uncore_pmu_event_read(struct perf_event *event);
+void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
+struct event_constraint *
+uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event);
+void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event);
+u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx);
+
+extern struct intel_uncore_type **uncore_msr_uncores;
+extern struct intel_uncore_type **uncore_pci_uncores;
+extern struct pci_driver *uncore_pci_driver;
+extern raw_spinlock_t pci2phy_map_lock;
+extern struct list_head pci2phy_map_head;
+extern struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
+extern struct event_constraint uncore_constraint_empty;
+
+/* perf_event_intel_uncore_snb.c */
+int snb_uncore_pci_init(void);
+int ivb_uncore_pci_init(void);
+int hsw_uncore_pci_init(void);
+int bdw_uncore_pci_init(void);
+void snb_uncore_cpu_init(void);
+void nhm_uncore_cpu_init(void);
+int snb_pci2phy_map_init(int devid);
+
+/* perf_event_intel_uncore_snbep.c */
+int snbep_uncore_pci_init(void);
+void snbep_uncore_cpu_init(void);
+int ivbep_uncore_pci_init(void);
+void ivbep_uncore_cpu_init(void);
+int hswep_uncore_pci_init(void);
+void hswep_uncore_cpu_init(void);
+int bdx_uncore_pci_init(void);
+void bdx_uncore_cpu_init(void);
+int knl_uncore_pci_init(void);
+void knl_uncore_cpu_init(void);
+
+/* perf_event_intel_uncore_nhmex.c */
+void nhmex_uncore_cpu_init(void);
--- linux-4.4.0.orig/arch/x86/events/intel/uncore_nhmex.c
+++ linux-4.4.0/arch/x86/events/intel/uncore_nhmex.c
@@ -0,0 +1,1221 @@
+/* Nehalem-EX/Westmere-EX uncore support */
+#include "uncore.h"
+
+/* NHM-EX event control */
+#define NHMEX_PMON_CTL_EV_SEL_MASK	0x000000ff
+#define NHMEX_PMON_CTL_UMASK_MASK	0x0000ff00
+#define NHMEX_PMON_CTL_EN_BIT0		(1 << 0)
+#define NHMEX_PMON_CTL_EDGE_DET		(1 << 18)
+#define NHMEX_PMON_CTL_PMI_EN		(1 << 20)
+#define NHMEX_PMON_CTL_EN_BIT22		(1 << 22)
+#define NHMEX_PMON_CTL_INVERT		(1 << 23)
+#define NHMEX_PMON_CTL_TRESH_MASK	0xff000000
+#define NHMEX_PMON_RAW_EVENT_MASK	(NHMEX_PMON_CTL_EV_SEL_MASK | \
+					 NHMEX_PMON_CTL_UMASK_MASK | \
+					 NHMEX_PMON_CTL_EDGE_DET | \
+					 NHMEX_PMON_CTL_INVERT | \
+					 NHMEX_PMON_CTL_TRESH_MASK)
+
+/* NHM-EX Ubox */
+#define NHMEX_U_MSR_PMON_GLOBAL_CTL		0xc00
+#define NHMEX_U_MSR_PMON_CTR			0xc11
+#define NHMEX_U_MSR_PMON_EV_SEL			0xc10
+
+#define NHMEX_U_PMON_GLOBAL_EN			(1 << 0)
+#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL	0x0000001e
+#define NHMEX_U_PMON_GLOBAL_EN_ALL		(1 << 28)
+#define NHMEX_U_PMON_GLOBAL_RST_ALL		(1 << 29)
+#define NHMEX_U_PMON_GLOBAL_FRZ_ALL		(1 << 31)
+
+#define NHMEX_U_PMON_RAW_EVENT_MASK		\
+		(NHMEX_PMON_CTL_EV_SEL_MASK |	\
+		 NHMEX_PMON_CTL_EDGE_DET)
+
+/* NHM-EX Cbox */
+#define NHMEX_C0_MSR_PMON_GLOBAL_CTL		0xd00
+#define NHMEX_C0_MSR_PMON_CTR0			0xd11
+#define NHMEX_C0_MSR_PMON_EV_SEL0		0xd10
+#define NHMEX_C_MSR_OFFSET			0x20
+
+/* NHM-EX Bbox */
+#define NHMEX_B0_MSR_PMON_GLOBAL_CTL		0xc20
+#define NHMEX_B0_MSR_PMON_CTR0			0xc31
+#define NHMEX_B0_MSR_PMON_CTL0			0xc30
+#define NHMEX_B_MSR_OFFSET			0x40
+#define NHMEX_B0_MSR_MATCH			0xe45
+#define NHMEX_B0_MSR_MASK			0xe46
+#define NHMEX_B1_MSR_MATCH			0xe4d
+#define NHMEX_B1_MSR_MASK			0xe4e
+
+#define NHMEX_B_PMON_CTL_EN			(1 << 0)
+#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT		1
+#define NHMEX_B_PMON_CTL_EV_SEL_MASK		\
+		(0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT)
+#define NHMEX_B_PMON_CTR_SHIFT		6
+#define NHMEX_B_PMON_CTR_MASK		\
+		(0x3 << NHMEX_B_PMON_CTR_SHIFT)
+#define NHMEX_B_PMON_RAW_EVENT_MASK		\
+		(NHMEX_B_PMON_CTL_EV_SEL_MASK | \
+		 NHMEX_B_PMON_CTR_MASK)
+
+/* NHM-EX Sbox */
+#define NHMEX_S0_MSR_PMON_GLOBAL_CTL		0xc40
+#define NHMEX_S0_MSR_PMON_CTR0			0xc51
+#define NHMEX_S0_MSR_PMON_CTL0			0xc50
+#define NHMEX_S_MSR_OFFSET			0x80
+#define NHMEX_S0_MSR_MM_CFG			0xe48
+#define NHMEX_S0_MSR_MATCH			0xe49
+#define NHMEX_S0_MSR_MASK			0xe4a
+#define NHMEX_S1_MSR_MM_CFG			0xe58
+#define NHMEX_S1_MSR_MATCH			0xe59
+#define NHMEX_S1_MSR_MASK			0xe5a
+
+#define NHMEX_S_PMON_MM_CFG_EN			(0x1ULL << 63)
+#define NHMEX_S_EVENT_TO_R_PROG_EV		0
+
+/* NHM-EX Mbox */
+#define NHMEX_M0_MSR_GLOBAL_CTL			0xca0
+#define NHMEX_M0_MSR_PMU_DSP			0xca5
+#define NHMEX_M0_MSR_PMU_ISS			0xca6
+#define NHMEX_M0_MSR_PMU_MAP			0xca7
+#define NHMEX_M0_MSR_PMU_MSC_THR		0xca8
+#define NHMEX_M0_MSR_PMU_PGT			0xca9
+#define NHMEX_M0_MSR_PMU_PLD			0xcaa
+#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC		0xcab
+#define NHMEX_M0_MSR_PMU_CTL0			0xcb0
+#define NHMEX_M0_MSR_PMU_CNT0			0xcb1
+#define NHMEX_M_MSR_OFFSET			0x40
+#define NHMEX_M0_MSR_PMU_MM_CFG			0xe54
+#define NHMEX_M1_MSR_PMU_MM_CFG			0xe5c
+
+#define NHMEX_M_PMON_MM_CFG_EN			(1ULL << 63)
+#define NHMEX_M_PMON_ADDR_MATCH_MASK		0x3ffffffffULL
+#define NHMEX_M_PMON_ADDR_MASK_MASK		0x7ffffffULL
+#define NHMEX_M_PMON_ADDR_MASK_SHIFT		34
+
+#define NHMEX_M_PMON_CTL_EN			(1 << 0)
+#define NHMEX_M_PMON_CTL_PMI_EN			(1 << 1)
+#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT	2
+#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK	\
+	(0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT)
+#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT	4
+#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK	\
+	(0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT)
+#define NHMEX_M_PMON_CTL_WRAP_MODE		(1 << 6)
+#define NHMEX_M_PMON_CTL_FLAG_MODE		(1 << 7)
+#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT		9
+#define NHMEX_M_PMON_CTL_INC_SEL_MASK		\
+	(0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
+#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT	19
+#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK	\
+	(0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT)
+#define NHMEX_M_PMON_RAW_EVENT_MASK			\
+		(NHMEX_M_PMON_CTL_COUNT_MODE_MASK |	\
+		 NHMEX_M_PMON_CTL_STORAGE_MODE_MASK |	\
+		 NHMEX_M_PMON_CTL_WRAP_MODE |		\
+		 NHMEX_M_PMON_CTL_FLAG_MODE |		\
+		 NHMEX_M_PMON_CTL_INC_SEL_MASK |	\
+		 NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
+
+#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK		(((1 << 11) - 1) | (1 << 23))
+#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n)	(0x7ULL << (11 + 3 * (n)))
+
+#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK		(((1 << 12) - 1) | (1 << 24))
+#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n)	(0x7ULL << (12 + 3 * (n)))
+
+/*
+ * use the 9~13 bits to select event If the 7th bit is not set,
+ * otherwise use the 19~21 bits to select event.
+ */
+#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
+#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \
+				NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \
+			   NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \
+				NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_INC_SEL_EXTAR_REG(c, r) \
+		EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \
+				MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r)
+#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \
+		EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \
+				MBOX_SET_FLAG_SEL_MASK, \
+				(u64)-1, NHMEX_M_##r)
+
+/* NHM-EX Rbox */
+#define NHMEX_R_MSR_GLOBAL_CTL			0xe00
+#define NHMEX_R_MSR_PMON_CTL0			0xe10
+#define NHMEX_R_MSR_PMON_CNT0			0xe11
+#define NHMEX_R_MSR_OFFSET			0x20
+
+#define NHMEX_R_MSR_PORTN_QLX_CFG(n)		\
+		((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4))
+#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n)		(0xe04 + (n))
+#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n)		(0xe24 + (n))
+#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n)		\
+		(((n) < 4 ? 0 : 0x10) + (n) * 4)
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n)	\
+		(0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n)	\
+		(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1)
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n)	\
+		(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2)
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n)	\
+		(0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n)	\
+		(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1)
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n)	\
+		(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2)
+
+#define NHMEX_R_PMON_CTL_EN			(1 << 0)
+#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT		1
+#define NHMEX_R_PMON_CTL_EV_SEL_MASK		\
+		(0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT)
+#define NHMEX_R_PMON_CTL_PMI_EN			(1 << 6)
+#define NHMEX_R_PMON_RAW_EVENT_MASK		NHMEX_R_PMON_CTL_EV_SEL_MASK
+
+/* NHM-EX Wbox */
+#define NHMEX_W_MSR_GLOBAL_CTL			0xc80
+#define NHMEX_W_MSR_PMON_CNT0			0xc90
+#define NHMEX_W_MSR_PMON_EVT_SEL0		0xc91
+#define NHMEX_W_MSR_PMON_FIXED_CTR		0x394
+#define NHMEX_W_MSR_PMON_FIXED_CTL		0x395
+
+#define NHMEX_W_PMON_GLOBAL_FIXED_EN		(1ULL << 31)
+
+#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
+				((1ULL << (n)) - 1)))
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
+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(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
+DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
+
+static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+	wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL);
+}
+
+static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+	unsigned msr = uncore_msr_box_ctl(box);
+	u64 config;
+
+	if (msr) {
+		rdmsrl(msr, config);
+		config &= ~((1ULL << uncore_num_counters(box)) - 1);
+		/* WBox has a fixed counter */
+		if (uncore_msr_fixed_ctl(box))
+			config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN;
+		wrmsrl(msr, config);
+	}
+}
+
+static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+	unsigned msr = uncore_msr_box_ctl(box);
+	u64 config;
+
+	if (msr) {
+		rdmsrl(msr, config);
+		config |= (1ULL << uncore_num_counters(box)) - 1;
+		/* WBox has a fixed counter */
+		if (uncore_msr_fixed_ctl(box))
+			config |= NHMEX_W_PMON_GLOBAL_FIXED_EN;
+		wrmsrl(msr, config);
+	}
+}
+
+static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+	wrmsrl(event->hw.config_base, 0);
+}
+
+static void nhmex_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, NHMEX_PMON_CTL_EN_BIT0);
+	else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0)
+		wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
+	else
+		wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+}
+
+#define NHMEX_UNCORE_OPS_COMMON_INIT()				\
+	.init_box	= nhmex_uncore_msr_init_box,		\
+	.disable_box	= nhmex_uncore_msr_disable_box,		\
+	.enable_box	= nhmex_uncore_msr_enable_box,		\
+	.disable_event	= nhmex_uncore_msr_disable_event,	\
+	.read_counter	= uncore_msr_read_counter
+
+static struct intel_uncore_ops nhmex_uncore_ops = {
+	NHMEX_UNCORE_OPS_COMMON_INIT(),
+	.enable_event	= nhmex_uncore_msr_enable_event,
+};
+
+static struct attribute *nhmex_uncore_ubox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_edge.attr,
+	NULL,
+};
+
+static struct attribute_group nhmex_uncore_ubox_format_group = {
+	.name		= "format",
+	.attrs		= nhmex_uncore_ubox_formats_attr,
+};
+
+static struct intel_uncore_type nhmex_uncore_ubox = {
+	.name		= "ubox",
+	.num_counters	= 1,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 48,
+	.event_ctl	= NHMEX_U_MSR_PMON_EV_SEL,
+	.perf_ctr	= NHMEX_U_MSR_PMON_CTR,
+	.event_mask	= NHMEX_U_PMON_RAW_EVENT_MASK,
+	.box_ctl	= NHMEX_U_MSR_PMON_GLOBAL_CTL,
+	.ops		= &nhmex_uncore_ops,
+	.format_group	= &nhmex_uncore_ubox_format_group
+};
+
+static struct attribute *nhmex_uncore_cbox_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_group nhmex_uncore_cbox_format_group = {
+	.name = "format",
+	.attrs = nhmex_uncore_cbox_formats_attr,
+};
+
+/* msr offset for each instance of cbox */
+static unsigned nhmex_cbox_msr_offsets[] = {
+	0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0,
+};
+
+static struct intel_uncore_type nhmex_uncore_cbox = {
+	.name			= "cbox",
+	.num_counters		= 6,
+	.num_boxes		= 10,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= NHMEX_C0_MSR_PMON_EV_SEL0,
+	.perf_ctr		= NHMEX_C0_MSR_PMON_CTR0,
+	.event_mask		= NHMEX_PMON_RAW_EVENT_MASK,
+	.box_ctl		= NHMEX_C0_MSR_PMON_GLOBAL_CTL,
+	.msr_offsets		= nhmex_cbox_msr_offsets,
+	.pair_ctr_ctl		= 1,
+	.ops			= &nhmex_uncore_ops,
+	.format_group		= &nhmex_uncore_cbox_format_group
+};
+
+static struct uncore_event_desc nhmex_uncore_wbox_events[] = {
+	INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"),
+	{ /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type nhmex_uncore_wbox = {
+	.name			= "wbox",
+	.num_counters		= 4,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= NHMEX_W_MSR_PMON_CNT0,
+	.perf_ctr		= NHMEX_W_MSR_PMON_EVT_SEL0,
+	.fixed_ctr		= NHMEX_W_MSR_PMON_FIXED_CTR,
+	.fixed_ctl		= NHMEX_W_MSR_PMON_FIXED_CTL,
+	.event_mask		= NHMEX_PMON_RAW_EVENT_MASK,
+	.box_ctl		= NHMEX_W_MSR_GLOBAL_CTL,
+	.pair_ctr_ctl		= 1,
+	.event_descs		= nhmex_uncore_wbox_events,
+	.ops			= &nhmex_uncore_ops,
+	.format_group		= &nhmex_uncore_cbox_format_group
+};
+
+static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+	int ctr, ev_sel;
+
+	ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >>
+		NHMEX_B_PMON_CTR_SHIFT;
+	ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >>
+		  NHMEX_B_PMON_CTL_EV_SEL_SHIFT;
+
+	/* events that do not use the match/mask registers */
+	if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) ||
+	    (ctr == 2 && ev_sel != 0x4) || ctr == 3)
+		return 0;
+
+	if (box->pmu->pmu_idx == 0)
+		reg1->reg = NHMEX_B0_MSR_MATCH;
+	else
+		reg1->reg = NHMEX_B1_MSR_MATCH;
+	reg1->idx = 0;
+	reg1->config = event->attr.config1;
+	reg2->config = event->attr.config2;
+	return 0;
+}
+
+static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+	if (reg1->idx != EXTRA_REG_NONE) {
+		wrmsrl(reg1->reg, reg1->config);
+		wrmsrl(reg1->reg + 1, reg2->config);
+	}
+	wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
+		(hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK));
+}
+
+/*
+ * The Bbox has 4 counters, but each counter monitors different events.
+ * Use bits 6-7 in the event config to select counter.
+ */
+static struct event_constraint nhmex_uncore_bbox_constraints[] = {
+	EVENT_CONSTRAINT(0 , 1, 0xc0),
+	EVENT_CONSTRAINT(0x40, 2, 0xc0),
+	EVENT_CONSTRAINT(0x80, 4, 0xc0),
+	EVENT_CONSTRAINT(0xc0, 8, 0xc0),
+	EVENT_CONSTRAINT_END,
+};
+
+static struct attribute *nhmex_uncore_bbox_formats_attr[] = {
+	&format_attr_event5.attr,
+	&format_attr_counter.attr,
+	&format_attr_match.attr,
+	&format_attr_mask.attr,
+	NULL,
+};
+
+static struct attribute_group nhmex_uncore_bbox_format_group = {
+	.name = "format",
+	.attrs = nhmex_uncore_bbox_formats_attr,
+};
+
+static struct intel_uncore_ops nhmex_uncore_bbox_ops = {
+	NHMEX_UNCORE_OPS_COMMON_INIT(),
+	.enable_event		= nhmex_bbox_msr_enable_event,
+	.hw_config		= nhmex_bbox_hw_config,
+	.get_constraint		= uncore_get_constraint,
+	.put_constraint		= uncore_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_bbox = {
+	.name			= "bbox",
+	.num_counters		= 4,
+	.num_boxes		= 2,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= NHMEX_B0_MSR_PMON_CTL0,
+	.perf_ctr		= NHMEX_B0_MSR_PMON_CTR0,
+	.event_mask		= NHMEX_B_PMON_RAW_EVENT_MASK,
+	.box_ctl		= NHMEX_B0_MSR_PMON_GLOBAL_CTL,
+	.msr_offset		= NHMEX_B_MSR_OFFSET,
+	.pair_ctr_ctl		= 1,
+	.num_shared_regs	= 1,
+	.constraints		= nhmex_uncore_bbox_constraints,
+	.ops			= &nhmex_uncore_bbox_ops,
+	.format_group		= &nhmex_uncore_bbox_format_group
+};
+
+static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+	/* only TO_R_PROG_EV event uses the match/mask register */
+	if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) !=
+	    NHMEX_S_EVENT_TO_R_PROG_EV)
+		return 0;
+
+	if (box->pmu->pmu_idx == 0)
+		reg1->reg = NHMEX_S0_MSR_MM_CFG;
+	else
+		reg1->reg = NHMEX_S1_MSR_MM_CFG;
+	reg1->idx = 0;
+	reg1->config = event->attr.config1;
+	reg2->config = event->attr.config2;
+	return 0;
+}
+
+static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+	if (reg1->idx != EXTRA_REG_NONE) {
+		wrmsrl(reg1->reg, 0);
+		wrmsrl(reg1->reg + 1, reg1->config);
+		wrmsrl(reg1->reg + 2, reg2->config);
+		wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
+	}
+	wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
+}
+
+static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh8.attr,
+	&format_attr_match.attr,
+	&format_attr_mask.attr,
+	NULL,
+};
+
+static struct attribute_group nhmex_uncore_sbox_format_group = {
+	.name			= "format",
+	.attrs			= nhmex_uncore_sbox_formats_attr,
+};
+
+static struct intel_uncore_ops nhmex_uncore_sbox_ops = {
+	NHMEX_UNCORE_OPS_COMMON_INIT(),
+	.enable_event		= nhmex_sbox_msr_enable_event,
+	.hw_config		= nhmex_sbox_hw_config,
+	.get_constraint		= uncore_get_constraint,
+	.put_constraint		= uncore_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_sbox = {
+	.name			= "sbox",
+	.num_counters		= 4,
+	.num_boxes		= 2,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= NHMEX_S0_MSR_PMON_CTL0,
+	.perf_ctr		= NHMEX_S0_MSR_PMON_CTR0,
+	.event_mask		= NHMEX_PMON_RAW_EVENT_MASK,
+	.box_ctl		= NHMEX_S0_MSR_PMON_GLOBAL_CTL,
+	.msr_offset		= NHMEX_S_MSR_OFFSET,
+	.pair_ctr_ctl		= 1,
+	.num_shared_regs	= 1,
+	.ops			= &nhmex_uncore_sbox_ops,
+	.format_group		= &nhmex_uncore_sbox_format_group
+};
+
+enum {
+	EXTRA_REG_NHMEX_M_FILTER,
+	EXTRA_REG_NHMEX_M_DSP,
+	EXTRA_REG_NHMEX_M_ISS,
+	EXTRA_REG_NHMEX_M_MAP,
+	EXTRA_REG_NHMEX_M_MSC_THR,
+	EXTRA_REG_NHMEX_M_PGT,
+	EXTRA_REG_NHMEX_M_PLD,
+	EXTRA_REG_NHMEX_M_ZDP_CTL_FVC,
+};
+
+static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
+	MBOX_INC_SEL_EXTAR_REG(0x0, DSP),
+	MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR),
+	MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR),
+	MBOX_INC_SEL_EXTAR_REG(0x9, ISS),
+	/* event 0xa uses two extra registers */
+	MBOX_INC_SEL_EXTAR_REG(0xa, ISS),
+	MBOX_INC_SEL_EXTAR_REG(0xa, PLD),
+	MBOX_INC_SEL_EXTAR_REG(0xb, PLD),
+	/* events 0xd ~ 0x10 use the same extra register */
+	MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC),
+	MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC),
+	MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC),
+	MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC),
+	MBOX_INC_SEL_EXTAR_REG(0x16, PGT),
+	MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP),
+	MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS),
+	MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT),
+	MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP),
+	EVENT_EXTRA_END
+};
+
+/* Nehalem-EX or Westmere-EX ? */
+static bool uncore_nhmex;
+
+static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
+{
+	struct intel_uncore_extra_reg *er;
+	unsigned long flags;
+	bool ret = false;
+	u64 mask;
+
+	if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+		er = &box->shared_regs[idx];
+		raw_spin_lock_irqsave(&er->lock, flags);
+		if (!atomic_read(&er->ref) || er->config == config) {
+			atomic_inc(&er->ref);
+			er->config = config;
+			ret = true;
+		}
+		raw_spin_unlock_irqrestore(&er->lock, flags);
+
+		return ret;
+	}
+	/*
+	 * The ZDP_CTL_FVC MSR has 4 fields which are used to control
+	 * events 0xd ~ 0x10. Besides these 4 fields, there are additional
+	 * fields which are shared.
+	 */
+	idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+	if (WARN_ON_ONCE(idx >= 4))
+		return false;
+
+	/* mask of the shared fields */
+	if (uncore_nhmex)
+		mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
+	else
+		mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK;
+	er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+
+	raw_spin_lock_irqsave(&er->lock, flags);
+	/* add mask of the non-shared field if it's in use */
+	if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) {
+		if (uncore_nhmex)
+			mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+		else
+			mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+	}
+
+	if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
+		atomic_add(1 << (idx * 8), &er->ref);
+		if (uncore_nhmex)
+			mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
+				NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+		else
+			mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK |
+				WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+		er->config &= ~mask;
+		er->config |= (config & mask);
+		ret = true;
+	}
+	raw_spin_unlock_irqrestore(&er->lock, flags);
+
+	return ret;
+}
+
+static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx)
+{
+	struct intel_uncore_extra_reg *er;
+
+	if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+		er = &box->shared_regs[idx];
+		atomic_dec(&er->ref);
+		return;
+	}
+
+	idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+	er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+	atomic_sub(1 << (idx * 8), &er->ref);
+}
+
+static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
+	u64 config = reg1->config;
+
+	/* get the non-shared control bits and shift them */
+	idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+	if (uncore_nhmex)
+		config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+	else
+		config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+	if (new_idx > orig_idx) {
+		idx = new_idx - orig_idx;
+		config <<= 3 * idx;
+	} else {
+		idx = orig_idx - new_idx;
+		config >>= 3 * idx;
+	}
+
+	/* add the shared control bits back */
+	if (uncore_nhmex)
+		config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+	else
+		config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+	config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+	if (modify) {
+		/* adjust the main event selector */
+		if (new_idx > orig_idx)
+			hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
+		else
+			hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
+		reg1->config = config;
+		reg1->idx = ~0xff | new_idx;
+	}
+	return config;
+}
+
+static struct event_constraint *
+nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+	int i, idx[2], alloc = 0;
+	u64 config1 = reg1->config;
+
+	idx[0] = __BITS_VALUE(reg1->idx, 0, 8);
+	idx[1] = __BITS_VALUE(reg1->idx, 1, 8);
+again:
+	for (i = 0; i < 2; i++) {
+		if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
+			idx[i] = 0xff;
+
+		if (idx[i] == 0xff)
+			continue;
+
+		if (!nhmex_mbox_get_shared_reg(box, idx[i],
+				__BITS_VALUE(config1, i, 32)))
+			goto fail;
+		alloc |= (0x1 << i);
+	}
+
+	/* for the match/mask registers */
+	if (reg2->idx != EXTRA_REG_NONE &&
+	    (uncore_box_is_fake(box) || !reg2->alloc) &&
+	    !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
+		goto fail;
+
+	/*
+	 * If it's a fake box -- as per validate_{group,event}() we
+	 * shouldn't touch event state and we can avoid doing so
+	 * since both will only call get_event_constraints() once
+	 * on each event, this avoids the need for reg->alloc.
+	 */
+	if (!uncore_box_is_fake(box)) {
+		if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
+			nhmex_mbox_alter_er(event, idx[0], true);
+		reg1->alloc |= alloc;
+		if (reg2->idx != EXTRA_REG_NONE)
+			reg2->alloc = 1;
+	}
+	return NULL;
+fail:
+	if (idx[0] != 0xff && !(alloc & 0x1) &&
+	    idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+		/*
+		 * events 0xd ~ 0x10 are functional identical, but are
+		 * controlled by different fields in the ZDP_CTL_FVC
+		 * register. If we failed to take one field, try the
+		 * rest 3 choices.
+		 */
+		BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff);
+		idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+		idx[0] = (idx[0] + 1) % 4;
+		idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+		if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) {
+			config1 = nhmex_mbox_alter_er(event, idx[0], false);
+			goto again;
+		}
+	}
+
+	if (alloc & 0x1)
+		nhmex_mbox_put_shared_reg(box, idx[0]);
+	if (alloc & 0x2)
+		nhmex_mbox_put_shared_reg(box, idx[1]);
+	return &uncore_constraint_empty;
+}
+
+static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+
+	if (uncore_box_is_fake(box))
+		return;
+
+	if (reg1->alloc & 0x1)
+		nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8));
+	if (reg1->alloc & 0x2)
+		nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8));
+	reg1->alloc = 0;
+
+	if (reg2->alloc) {
+		nhmex_mbox_put_shared_reg(box, reg2->idx);
+		reg2->alloc = 0;
+	}
+}
+
+static int nhmex_mbox_extra_reg_idx(struct extra_reg *er)
+{
+	if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
+		return er->idx;
+	return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd;
+}
+
+static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct intel_uncore_type *type = box->pmu->type;
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+	struct extra_reg *er;
+	unsigned msr;
+	int reg_idx = 0;
+	/*
+	 * The mbox events may require 2 extra MSRs at the most. But only
+	 * the lower 32 bits in these MSRs are significant, so we can use
+	 * config1 to pass two MSRs' config.
+	 */
+	for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) {
+		if (er->event != (event->hw.config & er->config_mask))
+			continue;
+		if (event->attr.config1 & ~er->valid_mask)
+			return -EINVAL;
+
+		msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
+		if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
+			return -EINVAL;
+
+		/* always use the 32~63 bits to pass the PLD config */
+		if (er->idx == EXTRA_REG_NHMEX_M_PLD)
+			reg_idx = 1;
+		else if (WARN_ON_ONCE(reg_idx > 0))
+			return -EINVAL;
+
+		reg1->idx &= ~(0xff << (reg_idx * 8));
+		reg1->reg &= ~(0xffff << (reg_idx * 16));
+		reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8);
+		reg1->reg |= msr << (reg_idx * 16);
+		reg1->config = event->attr.config1;
+		reg_idx++;
+	}
+	/*
+	 * The mbox only provides ability to perform address matching
+	 * for the PLD events.
+	 */
+	if (reg_idx == 2) {
+		reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
+		if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
+			reg2->config = event->attr.config2;
+		else
+			reg2->config = ~0ULL;
+		if (box->pmu->pmu_idx == 0)
+			reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
+		else
+			reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
+	}
+	return 0;
+}
+
+static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx)
+{
+	struct intel_uncore_extra_reg *er;
+	unsigned long flags;
+	u64 config;
+
+	if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
+		return box->shared_regs[idx].config;
+
+	er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+	raw_spin_lock_irqsave(&er->lock, flags);
+	config = er->config;
+	raw_spin_unlock_irqrestore(&er->lock, flags);
+	return config;
+}
+
+static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+	int idx;
+
+	idx = __BITS_VALUE(reg1->idx, 0, 8);
+	if (idx != 0xff)
+		wrmsrl(__BITS_VALUE(reg1->reg, 0, 16),
+			nhmex_mbox_shared_reg_config(box, idx));
+	idx = __BITS_VALUE(reg1->idx, 1, 8);
+	if (idx != 0xff)
+		wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
+			nhmex_mbox_shared_reg_config(box, idx));
+
+	if (reg2->idx != EXTRA_REG_NONE) {
+		wrmsrl(reg2->reg, 0);
+		if (reg2->config != ~0ULL) {
+			wrmsrl(reg2->reg + 1,
+				reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
+			wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
+				(reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
+			wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
+		}
+	}
+
+	wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+}
+
+DEFINE_UNCORE_FORMAT_ATTR(count_mode,		count_mode,	"config:2-3");
+DEFINE_UNCORE_FORMAT_ATTR(storage_mode,		storage_mode,	"config:4-5");
+DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,		wrap_mode,	"config:6");
+DEFINE_UNCORE_FORMAT_ATTR(flag_mode,		flag_mode,	"config:7");
+DEFINE_UNCORE_FORMAT_ATTR(inc_sel,		inc_sel,	"config:9-13");
+DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,		set_flag_sel,	"config:19-21");
+DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en,	filter_cfg_en,	"config2:63");
+DEFINE_UNCORE_FORMAT_ATTR(filter_match,		filter_match,	"config2:0-33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_mask,		filter_mask,	"config2:34-61");
+DEFINE_UNCORE_FORMAT_ATTR(dsp,			dsp,		"config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(thr,			thr,		"config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(fvc,			fvc,		"config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pgt,			pgt,		"config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(map,			map,		"config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(iss,			iss,		"config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pld,			pld,		"config1:32-63");
+
+static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
+	&format_attr_count_mode.attr,
+	&format_attr_storage_mode.attr,
+	&format_attr_wrap_mode.attr,
+	&format_attr_flag_mode.attr,
+	&format_attr_inc_sel.attr,
+	&format_attr_set_flag_sel.attr,
+	&format_attr_filter_cfg_en.attr,
+	&format_attr_filter_match.attr,
+	&format_attr_filter_mask.attr,
+	&format_attr_dsp.attr,
+	&format_attr_thr.attr,
+	&format_attr_fvc.attr,
+	&format_attr_pgt.attr,
+	&format_attr_map.attr,
+	&format_attr_iss.attr,
+	&format_attr_pld.attr,
+	NULL,
+};
+
+static struct attribute_group nhmex_uncore_mbox_format_group = {
+	.name		= "format",
+	.attrs		= nhmex_uncore_mbox_formats_attr,
+};
+
+static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
+	INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"),
+	INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"),
+	{ /* end: all zeroes */ },
+};
+
+static struct uncore_event_desc wsmex_uncore_mbox_events[] = {
+	INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"),
+	INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"),
+	{ /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
+	NHMEX_UNCORE_OPS_COMMON_INIT(),
+	.enable_event	= nhmex_mbox_msr_enable_event,
+	.hw_config	= nhmex_mbox_hw_config,
+	.get_constraint	= nhmex_mbox_get_constraint,
+	.put_constraint	= nhmex_mbox_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_mbox = {
+	.name			= "mbox",
+	.num_counters		= 6,
+	.num_boxes		= 2,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= NHMEX_M0_MSR_PMU_CTL0,
+	.perf_ctr		= NHMEX_M0_MSR_PMU_CNT0,
+	.event_mask		= NHMEX_M_PMON_RAW_EVENT_MASK,
+	.box_ctl		= NHMEX_M0_MSR_GLOBAL_CTL,
+	.msr_offset		= NHMEX_M_MSR_OFFSET,
+	.pair_ctr_ctl		= 1,
+	.num_shared_regs	= 8,
+	.event_descs		= nhmex_uncore_mbox_events,
+	.ops			= &nhmex_uncore_mbox_ops,
+	.format_group		= &nhmex_uncore_mbox_format_group,
+};
+
+static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+	/* adjust the main event selector and extra register index */
+	if (reg1->idx % 2) {
+		reg1->idx--;
+		hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+	} else {
+		reg1->idx++;
+		hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+	}
+
+	/* adjust extra register config */
+	switch (reg1->idx % 6) {
+	case 2:
+		/* shift the 8~15 bits to the 0~7 bits */
+		reg1->config >>= 8;
+		break;
+	case 3:
+		/* shift the 0~7 bits to the 8~15 bits */
+		reg1->config <<= 8;
+		break;
+	}
+}
+
+/*
+ * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7.
+ * An event set consists of 6 events, the 3rd and 4th events in
+ * an event set use the same extra register. So an event set uses
+ * 5 extra registers.
+ */
+static struct event_constraint *
+nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+	struct intel_uncore_extra_reg *er;
+	unsigned long flags;
+	int idx, er_idx;
+	u64 config1;
+	bool ok = false;
+
+	if (!uncore_box_is_fake(box) && reg1->alloc)
+		return NULL;
+
+	idx = reg1->idx % 6;
+	config1 = reg1->config;
+again:
+	er_idx = idx;
+	/* the 3rd and 4th events use the same extra register */
+	if (er_idx > 2)
+		er_idx--;
+	er_idx += (reg1->idx / 6) * 5;
+
+	er = &box->shared_regs[er_idx];
+	raw_spin_lock_irqsave(&er->lock, flags);
+	if (idx < 2) {
+		if (!atomic_read(&er->ref) || er->config == reg1->config) {
+			atomic_inc(&er->ref);
+			er->config = reg1->config;
+			ok = true;
+		}
+	} else if (idx == 2 || idx == 3) {
+		/*
+		 * these two events use different fields in a extra register,
+		 * the 0~7 bits and the 8~15 bits respectively.
+		 */
+		u64 mask = 0xff << ((idx - 2) * 8);
+		if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) ||
+				!((er->config ^ config1) & mask)) {
+			atomic_add(1 << ((idx - 2) * 8), &er->ref);
+			er->config &= ~mask;
+			er->config |= config1 & mask;
+			ok = true;
+		}
+	} else {
+		if (!atomic_read(&er->ref) ||
+				(er->config == (hwc->config >> 32) &&
+				 er->config1 == reg1->config &&
+				 er->config2 == reg2->config)) {
+			atomic_inc(&er->ref);
+			er->config = (hwc->config >> 32);
+			er->config1 = reg1->config;
+			er->config2 = reg2->config;
+			ok = true;
+		}
+	}
+	raw_spin_unlock_irqrestore(&er->lock, flags);
+
+	if (!ok) {
+		/*
+		 * The Rbox events are always in pairs. The paired
+		 * events are functional identical, but use different
+		 * extra registers. If we failed to take an extra
+		 * register, try the alternative.
+		 */
+		idx ^= 1;
+		if (idx != reg1->idx % 6) {
+			if (idx == 2)
+				config1 >>= 8;
+			else if (idx == 3)
+				config1 <<= 8;
+			goto again;
+		}
+	} else {
+		if (!uncore_box_is_fake(box)) {
+			if (idx != reg1->idx % 6)
+				nhmex_rbox_alter_er(box, event);
+			reg1->alloc = 1;
+		}
+		return NULL;
+	}
+	return &uncore_constraint_empty;
+}
+
+static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct intel_uncore_extra_reg *er;
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	int idx, er_idx;
+
+	if (uncore_box_is_fake(box) || !reg1->alloc)
+		return;
+
+	idx = reg1->idx % 6;
+	er_idx = idx;
+	if (er_idx > 2)
+		er_idx--;
+	er_idx += (reg1->idx / 6) * 5;
+
+	er = &box->shared_regs[er_idx];
+	if (idx == 2 || idx == 3)
+		atomic_sub(1 << ((idx - 2) * 8), &er->ref);
+	else
+		atomic_dec(&er->ref);
+
+	reg1->alloc = 0;
+}
+
+static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+	int idx;
+
+	idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
+		NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+	if (idx >= 0x18)
+		return -EINVAL;
+
+	reg1->idx = idx;
+	reg1->config = event->attr.config1;
+
+	switch (idx % 6) {
+	case 4:
+	case 5:
+		hwc->config |= event->attr.config & (~0ULL << 32);
+		reg2->config = event->attr.config2;
+		break;
+	}
+	return 0;
+}
+
+static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+	int idx, port;
+
+	idx = reg1->idx;
+	port = idx / 6 + box->pmu->pmu_idx * 4;
+
+	switch (idx % 6) {
+	case 0:
+		wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config);
+		break;
+	case 1:
+		wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config);
+		break;
+	case 2:
+	case 3:
+		wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
+			uncore_shared_reg_config(box, 2 + (idx / 6) * 5));
+		break;
+	case 4:
+		wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
+			hwc->config >> 32);
+		wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config);
+		wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config);
+		break;
+	case 5:
+		wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port),
+			hwc->config >> 32);
+		wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config);
+		wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config);
+		break;
+	}
+
+	wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
+		(hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
+}
+
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
+DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
+
+static struct attribute *nhmex_uncore_rbox_formats_attr[] = {
+	&format_attr_event5.attr,
+	&format_attr_xbr_mm_cfg.attr,
+	&format_attr_xbr_match.attr,
+	&format_attr_xbr_mask.attr,
+	&format_attr_qlx_cfg.attr,
+	&format_attr_iperf_cfg.attr,
+	NULL,
+};
+
+static struct attribute_group nhmex_uncore_rbox_format_group = {
+	.name = "format",
+	.attrs = nhmex_uncore_rbox_formats_attr,
+};
+
+static struct uncore_event_desc nhmex_uncore_rbox_events[] = {
+	INTEL_UNCORE_EVENT_DESC(qpi0_flit_send,		"event=0x0,iperf_cfg=0x80000000"),
+	INTEL_UNCORE_EVENT_DESC(qpi1_filt_send,		"event=0x6,iperf_cfg=0x80000000"),
+	INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt,		"event=0x0,iperf_cfg=0x40000000"),
+	INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt,		"event=0x6,iperf_cfg=0x40000000"),
+	INTEL_UNCORE_EVENT_DESC(qpi0_date_response,	"event=0x0,iperf_cfg=0xc4"),
+	INTEL_UNCORE_EVENT_DESC(qpi1_date_response,	"event=0x6,iperf_cfg=0xc4"),
+	{ /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhmex_uncore_rbox_ops = {
+	NHMEX_UNCORE_OPS_COMMON_INIT(),
+	.enable_event		= nhmex_rbox_msr_enable_event,
+	.hw_config		= nhmex_rbox_hw_config,
+	.get_constraint		= nhmex_rbox_get_constraint,
+	.put_constraint		= nhmex_rbox_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_rbox = {
+	.name			= "rbox",
+	.num_counters		= 8,
+	.num_boxes		= 2,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= NHMEX_R_MSR_PMON_CTL0,
+	.perf_ctr		= NHMEX_R_MSR_PMON_CNT0,
+	.event_mask		= NHMEX_R_PMON_RAW_EVENT_MASK,
+	.box_ctl		= NHMEX_R_MSR_GLOBAL_CTL,
+	.msr_offset		= NHMEX_R_MSR_OFFSET,
+	.pair_ctr_ctl		= 1,
+	.num_shared_regs	= 20,
+	.event_descs		= nhmex_uncore_rbox_events,
+	.ops			= &nhmex_uncore_rbox_ops,
+	.format_group		= &nhmex_uncore_rbox_format_group
+};
+
+static struct intel_uncore_type *nhmex_msr_uncores[] = {
+	&nhmex_uncore_ubox,
+	&nhmex_uncore_cbox,
+	&nhmex_uncore_bbox,
+	&nhmex_uncore_sbox,
+	&nhmex_uncore_mbox,
+	&nhmex_uncore_rbox,
+	&nhmex_uncore_wbox,
+	NULL,
+};
+
+void nhmex_uncore_cpu_init(void)
+{
+	if (boot_cpu_data.x86_model == 46)
+		uncore_nhmex = true;
+	else
+		nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
+	if (nhmex_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+		nhmex_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+	uncore_msr_uncores = nhmex_msr_uncores;
+}
+/* end of Nehalem-EX uncore support */
--- linux-4.4.0.orig/arch/x86/events/intel/uncore_snb.c
+++ linux-4.4.0/arch/x86/events/intel/uncore_snb.c
@@ -0,0 +1,697 @@
+/* Nehalem/SandBridge/Haswell uncore support */
+#include "uncore.h"
+
+/* Uncore IMC PCI IDs */
+#define PCI_DEVICE_ID_INTEL_SNB_IMC	0x0100
+#define PCI_DEVICE_ID_INTEL_IVB_IMC	0x0154
+#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC	0x0150
+#define PCI_DEVICE_ID_INTEL_HSW_IMC	0x0c00
+#define PCI_DEVICE_ID_INTEL_HSW_U_IMC	0x0a04
+#define PCI_DEVICE_ID_INTEL_BDW_IMC	0x1604
+
+/* 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
+
+/* SNB ARB register */
+#define SNB_UNC_ARB_PER_CTR0			0x3b0
+#define SNB_UNC_ARB_PERFEVTSEL0			0x3b2
+#define SNB_UNC_ARB_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
+
+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");
+
+/* 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 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 uncore_event_desc snb_uncore_events[] = {
+	INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"),
+	{ /* end: all zeroes */ },
+};
+
+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	= uncore_msr_read_counter,
+};
+
+static struct event_constraint snb_uncore_arb_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,
+	.ops		= &snb_uncore_msr_ops,
+	.format_group	= &snb_uncore_format_group,
+	.event_descs	= snb_uncore_events,
+};
+
+static struct intel_uncore_type snb_uncore_arb = {
+	.name		= "arb",
+	.num_counters   = 2,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 44,
+	.perf_ctr	= SNB_UNC_ARB_PER_CTR0,
+	.event_ctl	= SNB_UNC_ARB_PERFEVTSEL0,
+	.event_mask	= SNB_UNC_RAW_EVENT_MASK,
+	.msr_offset	= SNB_UNC_ARB_MSR_OFFSET,
+	.constraints	= snb_uncore_arb_constraints,
+	.ops		= &snb_uncore_msr_ops,
+	.format_group	= &snb_uncore_format_group,
+};
+
+static struct intel_uncore_type *snb_msr_uncores[] = {
+	&snb_uncore_cbox,
+	&snb_uncore_arb,
+	NULL,
+};
+
+void snb_uncore_cpu_init(void)
+{
+	uncore_msr_uncores = snb_msr_uncores;
+	if (snb_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+		snb_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+}
+
+enum {
+	SNB_PCI_UNCORE_IMC,
+};
+
+static struct uncore_event_desc snb_uncore_imc_events[] = {
+	INTEL_UNCORE_EVENT_DESC(data_reads,  "event=0x01"),
+	INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
+	INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
+
+	INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
+	INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
+	INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
+
+	{ /* end: all zeroes */ },
+};
+
+#define SNB_UNCORE_PCI_IMC_EVENT_MASK		0xff
+#define SNB_UNCORE_PCI_IMC_BAR_OFFSET		0x48
+
+/* page size multiple covering all config regs */
+#define SNB_UNCORE_PCI_IMC_MAP_SIZE		0x6000
+
+#define SNB_UNCORE_PCI_IMC_DATA_READS		0x1
+#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE	0x5050
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES		0x2
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE	0x5054
+#define SNB_UNCORE_PCI_IMC_CTR_BASE		SNB_UNCORE_PCI_IMC_DATA_READS_BASE
+
+static struct attribute *snb_uncore_imc_formats_attr[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group snb_uncore_imc_format_group = {
+	.name = "format",
+	.attrs = snb_uncore_imc_formats_attr,
+};
+
+static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET;
+	resource_size_t addr;
+	u32 pci_dword;
+
+	pci_read_config_dword(pdev, where, &pci_dword);
+	addr = pci_dword;
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+	pci_read_config_dword(pdev, where + 4, &pci_dword);
+	addr |= ((resource_size_t)pci_dword << 32);
+#endif
+
+	addr &= ~(PAGE_SIZE - 1);
+
+	box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
+	box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
+}
+
+static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
+}
+
+/*
+ * custom event_init() function because we define our own fixed, free
+ * running counters, so we do not want to conflict with generic uncore
+ * logic. Also simplifies processing
+ */
+static int snb_uncore_imc_event_init(struct perf_event *event)
+{
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_box *box;
+	struct hw_perf_event *hwc = &event->hw;
+	u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
+	int idx, base;
+
+	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;
+
+	/* Sampling not supported yet */
+	if (hwc->sample_period)
+		return -EINVAL;
+
+	/* unsupported modes and filters */
+	if (event->attr.exclude_user   ||
+	    event->attr.exclude_kernel ||
+	    event->attr.exclude_hv     ||
+	    event->attr.exclude_idle   ||
+	    event->attr.exclude_host   ||
+	    event->attr.exclude_guest  ||
+	    event->attr.sample_period) /* no sampling */
+		return -EINVAL;
+
+	/*
+	 * Place all uncore events for a particular physical package
+	 * onto a single cpu
+	 */
+	if (event->cpu < 0)
+		return -EINVAL;
+
+	/* check only supported bits are set */
+	if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
+		return -EINVAL;
+
+	box = uncore_pmu_to_box(pmu, event->cpu);
+	if (!box || box->cpu < 0)
+		return -EINVAL;
+
+	event->cpu = box->cpu;
+
+	event->hw.idx = -1;
+	event->hw.last_tag = ~0ULL;
+	event->hw.extra_reg.idx = EXTRA_REG_NONE;
+	event->hw.branch_reg.idx = EXTRA_REG_NONE;
+	/*
+	 * check event is known (whitelist, determines counter)
+	 */
+	switch (cfg) {
+	case SNB_UNCORE_PCI_IMC_DATA_READS:
+		base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
+		idx = UNCORE_PMC_IDX_FIXED;
+		break;
+	case SNB_UNCORE_PCI_IMC_DATA_WRITES:
+		base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
+		idx = UNCORE_PMC_IDX_FIXED + 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* must be done before validate_group */
+	event->hw.event_base = base;
+	event->hw.config = cfg;
+	event->hw.idx = idx;
+
+	/* no group validation needed, we have free running counters */
+
+	return 0;
+}
+
+static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	return 0;
+}
+
+static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
+{
+	struct intel_uncore_box *box = uncore_event_to_box(event);
+	u64 count;
+
+	if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+		return;
+
+	event->hw.state = 0;
+	box->n_active++;
+
+	list_add_tail(&event->active_entry, &box->active_list);
+
+	count = snb_uncore_imc_read_counter(box, event);
+	local64_set(&event->hw.prev_count, count);
+
+	if (box->n_active == 1)
+		uncore_pmu_start_hrtimer(box);
+}
+
+static void snb_uncore_imc_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 (!(hwc->state & PERF_HES_STOPPED)) {
+		box->n_active--;
+
+		WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+		hwc->state |= PERF_HES_STOPPED;
+
+		list_del(&event->active_entry);
+
+		if (box->n_active == 0)
+			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 snb_uncore_imc_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;
+
+	if (!box)
+		return -ENODEV;
+
+	hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+	if (!(flags & PERF_EF_START))
+		hwc->state |= PERF_HES_ARCH;
+
+	snb_uncore_imc_event_start(event, 0);
+
+	box->n_events++;
+
+	return 0;
+}
+
+static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
+{
+	struct intel_uncore_box *box = uncore_event_to_box(event);
+	int i;
+
+	snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
+
+	for (i = 0; i < box->n_events; i++) {
+		if (event == box->event_list[i]) {
+			--box->n_events;
+			break;
+		}
+	}
+}
+
+int snb_pci2phy_map_init(int devid)
+{
+	struct pci_dev *dev = NULL;
+	struct pci2phy_map *map;
+	int bus, segment;
+
+	dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
+	if (!dev)
+		return -ENOTTY;
+
+	bus = dev->bus->number;
+	segment = pci_domain_nr(dev->bus);
+
+	raw_spin_lock(&pci2phy_map_lock);
+	map = __find_pci2phy_map(segment);
+	if (!map) {
+		raw_spin_unlock(&pci2phy_map_lock);
+		pci_dev_put(dev);
+		return -ENOMEM;
+	}
+	map->pbus_to_physid[bus] = 0;
+	raw_spin_unlock(&pci2phy_map_lock);
+
+	pci_dev_put(dev);
+
+	return 0;
+}
+
+static struct pmu snb_uncore_imc_pmu = {
+	.task_ctx_nr	= perf_invalid_context,
+	.event_init	= snb_uncore_imc_event_init,
+	.add		= snb_uncore_imc_event_add,
+	.del		= snb_uncore_imc_event_del,
+	.start		= snb_uncore_imc_event_start,
+	.stop		= snb_uncore_imc_event_stop,
+	.read		= uncore_pmu_event_read,
+};
+
+static struct intel_uncore_ops snb_uncore_imc_ops = {
+	.init_box	= snb_uncore_imc_init_box,
+	.enable_box	= snb_uncore_imc_enable_box,
+	.disable_box	= snb_uncore_imc_disable_box,
+	.disable_event	= snb_uncore_imc_disable_event,
+	.enable_event	= snb_uncore_imc_enable_event,
+	.hw_config	= snb_uncore_imc_hw_config,
+	.read_counter	= snb_uncore_imc_read_counter,
+};
+
+static struct intel_uncore_type snb_uncore_imc = {
+	.name		= "imc",
+	.num_counters   = 2,
+	.num_boxes	= 1,
+	.fixed_ctr_bits	= 32,
+	.fixed_ctr	= SNB_UNCORE_PCI_IMC_CTR_BASE,
+	.event_descs	= snb_uncore_imc_events,
+	.format_group	= &snb_uncore_imc_format_group,
+	.perf_ctr	= SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
+	.event_mask	= SNB_UNCORE_PCI_IMC_EVENT_MASK,
+	.ops		= &snb_uncore_imc_ops,
+	.pmu		= &snb_uncore_imc_pmu,
+};
+
+static struct intel_uncore_type *snb_pci_uncores[] = {
+	[SNB_PCI_UNCORE_IMC]	= &snb_uncore_imc,
+	NULL,
+};
+
+static const struct pci_device_id snb_uncore_pci_ids[] = {
+	{ /* IMC */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+	},
+	{ /* end: all zeroes */ },
+};
+
+static const struct pci_device_id ivb_uncore_pci_ids[] = {
+	{ /* IMC */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+	},
+	{ /* IMC */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_E3_IMC),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+	},
+	{ /* end: all zeroes */ },
+};
+
+static const struct pci_device_id hsw_uncore_pci_ids[] = {
+	{ /* IMC */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+	},
+	{ /* IMC */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_U_IMC),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+	},
+	{ /* end: all zeroes */ },
+};
+
+static const struct pci_device_id bdw_uncore_pci_ids[] = {
+	{ /* IMC */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_IMC),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+	},
+	{ /* end: all zeroes */ },
+};
+
+static struct pci_driver snb_uncore_pci_driver = {
+	.name		= "snb_uncore",
+	.id_table	= snb_uncore_pci_ids,
+};
+
+static struct pci_driver ivb_uncore_pci_driver = {
+	.name		= "ivb_uncore",
+	.id_table	= ivb_uncore_pci_ids,
+};
+
+static struct pci_driver hsw_uncore_pci_driver = {
+	.name		= "hsw_uncore",
+	.id_table	= hsw_uncore_pci_ids,
+};
+
+static struct pci_driver bdw_uncore_pci_driver = {
+	.name		= "bdw_uncore",
+	.id_table	= bdw_uncore_pci_ids,
+};
+
+struct imc_uncore_pci_dev {
+	__u32 pci_id;
+	struct pci_driver *driver;
+};
+#define IMC_DEV(a, d) \
+	{ .pci_id = PCI_DEVICE_ID_INTEL_##a, .driver = (d) }
+
+static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
+	IMC_DEV(SNB_IMC, &snb_uncore_pci_driver),
+	IMC_DEV(IVB_IMC, &ivb_uncore_pci_driver),    /* 3rd Gen Core processor */
+	IMC_DEV(IVB_E3_IMC, &ivb_uncore_pci_driver), /* Xeon E3-1200 v2/3rd Gen Core processor */
+	IMC_DEV(HSW_IMC, &hsw_uncore_pci_driver),    /* 4th Gen Core Processor */
+	IMC_DEV(HSW_U_IMC, &hsw_uncore_pci_driver),  /* 4th Gen Core ULT Mobile Processor */
+	IMC_DEV(BDW_IMC, &bdw_uncore_pci_driver),    /* 5th Gen Core U */
+	{  /* end marker */ }
+};
+
+
+#define for_each_imc_pci_id(x, t) \
+	for (x = (t); (x)->pci_id; x++)
+
+static struct pci_driver *imc_uncore_find_dev(void)
+{
+	const struct imc_uncore_pci_dev *p;
+	int ret;
+
+	for_each_imc_pci_id(p, desktop_imc_pci_ids) {
+		ret = snb_pci2phy_map_init(p->pci_id);
+		if (ret == 0)
+			return p->driver;
+	}
+	return NULL;
+}
+
+static int imc_uncore_pci_init(void)
+{
+	struct pci_driver *imc_drv = imc_uncore_find_dev();
+
+	if (!imc_drv)
+		return -ENODEV;
+
+	uncore_pci_uncores = snb_pci_uncores;
+	uncore_pci_driver = imc_drv;
+
+	return 0;
+}
+
+int snb_uncore_pci_init(void)
+{
+	return imc_uncore_pci_init();
+}
+
+int ivb_uncore_pci_init(void)
+{
+	return imc_uncore_pci_init();
+}
+int hsw_uncore_pci_init(void)
+{
+	return imc_uncore_pci_init();
+}
+
+int bdw_uncore_pci_init(void)
+{
+	return imc_uncore_pci_init();
+}
+
+/* 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=0x00"),
+	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	= 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,
+};
+
+void nhm_uncore_cpu_init(void)
+{
+	uncore_msr_uncores = nhm_msr_uncores;
+}
+
+/* end of Nehalem uncore support */
--- linux-4.4.0.orig/arch/x86/events/intel/uncore_snbep.c
+++ linux-4.4.0/arch/x86/events/intel/uncore_snbep.c
@@ -0,0 +1,3127 @@
+/* SandyBridge-EP/IvyTown uncore support */
+#include "uncore.h"
+
+/* 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)
+#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)
+
+#define SNBEP_CBO_PMON_CTL_TID_EN		(1 << 19)
+#define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK	(SNBEP_PMON_RAW_EVENT_MASK | \
+						 SNBEP_CBO_PMON_CTL_TID_EN)
+
+/* 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_EV_SEL_EXT | \
+				 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)
+
+#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK	\
+				(SNBEP_PMON_RAW_EVENT_MASK | \
+				 SNBEP_PMON_CTL_EV_SEL_EXT)
+
+/* 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_CTL		0xd04
+#define SNBEP_C0_MSR_PMON_BOX_FILTER		0xd14
+#define SNBEP_CBO_MSR_OFFSET			0x20
+
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID	0x1f
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID	0x3fc00
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE	0x7c0000
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC	0xff800000
+
+#define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) {	\
+	.event = (e),				\
+	.msr = SNBEP_C0_MSR_PMON_BOX_FILTER,	\
+	.config_mask = (m),			\
+	.idx = (i)				\
+}
+
+/* SNB-EP PCU register */
+#define SNBEP_PCU_MSR_PMON_CTR0			0xc36
+#define SNBEP_PCU_MSR_PMON_CTL0			0xc30
+#define SNBEP_PCU_MSR_PMON_BOX_CTL		0xc24
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER		0xc34
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK	0xffffffff
+#define SNBEP_PCU_MSR_CORE_C3_CTR		0x3fc
+#define SNBEP_PCU_MSR_CORE_C6_CTR		0x3fd
+
+/* IVBEP event control */
+#define IVBEP_PMON_BOX_CTL_INT		(SNBEP_PMON_BOX_CTL_RST_CTRL | \
+					 SNBEP_PMON_BOX_CTL_RST_CTRS)
+#define IVBEP_PMON_RAW_EVENT_MASK		(SNBEP_PMON_CTL_EV_SEL_MASK | \
+					 SNBEP_PMON_CTL_UMASK_MASK | \
+					 SNBEP_PMON_CTL_EDGE_DET | \
+					 SNBEP_PMON_CTL_TRESH_MASK)
+/* IVBEP Ubox */
+#define IVBEP_U_MSR_PMON_GLOBAL_CTL		0xc00
+#define IVBEP_U_PMON_GLOBAL_FRZ_ALL		(1 << 31)
+#define IVBEP_U_PMON_GLOBAL_UNFRZ_ALL		(1 << 29)
+
+#define IVBEP_U_MSR_PMON_RAW_EVENT_MASK	\
+				(SNBEP_PMON_CTL_EV_SEL_MASK | \
+				 SNBEP_PMON_CTL_UMASK_MASK | \
+				 SNBEP_PMON_CTL_EDGE_DET | \
+				 SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
+/* IVBEP Cbo */
+#define IVBEP_CBO_MSR_PMON_RAW_EVENT_MASK		(IVBEP_PMON_RAW_EVENT_MASK | \
+						 SNBEP_CBO_PMON_CTL_TID_EN)
+
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_TID		(0x1fULL << 0)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_LINK	(0xfULL << 5)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_STATE	(0x3fULL << 17)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_NID		(0xffffULL << 32)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_OPC		(0x1ffULL << 52)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_C6		(0x1ULL << 61)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_NC		(0x1ULL << 62)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_ISOC	(0x1ULL << 63)
+
+/* IVBEP home agent */
+#define IVBEP_HA_PCI_PMON_CTL_Q_OCC_RST		(1 << 16)
+#define IVBEP_HA_PCI_PMON_RAW_EVENT_MASK		\
+				(IVBEP_PMON_RAW_EVENT_MASK | \
+				 IVBEP_HA_PCI_PMON_CTL_Q_OCC_RST)
+/* IVBEP PCU */
+#define IVBEP_PCU_MSR_PMON_RAW_EVENT_MASK	\
+				(SNBEP_PMON_CTL_EV_SEL_MASK | \
+				 SNBEP_PMON_CTL_EV_SEL_EXT | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+				 SNBEP_PMON_CTL_EDGE_DET | \
+				 SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+/* IVBEP QPI */
+#define IVBEP_QPI_PCI_PMON_RAW_EVENT_MASK	\
+				(IVBEP_PMON_RAW_EVENT_MASK | \
+				 SNBEP_PMON_CTL_EV_SEL_EXT)
+
+#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
+				((1ULL << (n)) - 1)))
+
+/* Haswell-EP Ubox */
+#define HSWEP_U_MSR_PMON_CTR0			0x709
+#define HSWEP_U_MSR_PMON_CTL0			0x705
+#define HSWEP_U_MSR_PMON_FILTER			0x707
+
+#define HSWEP_U_MSR_PMON_UCLK_FIXED_CTL		0x703
+#define HSWEP_U_MSR_PMON_UCLK_FIXED_CTR		0x704
+
+#define HSWEP_U_MSR_PMON_BOX_FILTER_TID		(0x1 << 0)
+#define HSWEP_U_MSR_PMON_BOX_FILTER_CID		(0x1fULL << 1)
+#define HSWEP_U_MSR_PMON_BOX_FILTER_MASK \
+					(HSWEP_U_MSR_PMON_BOX_FILTER_TID | \
+					 HSWEP_U_MSR_PMON_BOX_FILTER_CID)
+
+/* Haswell-EP CBo */
+#define HSWEP_C0_MSR_PMON_CTR0			0xe08
+#define HSWEP_C0_MSR_PMON_CTL0			0xe01
+#define HSWEP_C0_MSR_PMON_BOX_CTL			0xe00
+#define HSWEP_C0_MSR_PMON_BOX_FILTER0		0xe05
+#define HSWEP_CBO_MSR_OFFSET			0x10
+
+
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_TID		(0x3fULL << 0)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_LINK	(0xfULL << 6)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_STATE	(0x7fULL << 17)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_NID		(0xffffULL << 32)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_OPC		(0x1ffULL << 52)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_C6		(0x1ULL << 61)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_NC		(0x1ULL << 62)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_ISOC	(0x1ULL << 63)
+
+
+/* Haswell-EP Sbox */
+#define HSWEP_S0_MSR_PMON_CTR0			0x726
+#define HSWEP_S0_MSR_PMON_CTL0			0x721
+#define HSWEP_S0_MSR_PMON_BOX_CTL			0x720
+#define HSWEP_SBOX_MSR_OFFSET			0xa
+#define HSWEP_S_MSR_PMON_RAW_EVENT_MASK		(SNBEP_PMON_RAW_EVENT_MASK | \
+						 SNBEP_CBO_PMON_CTL_TID_EN)
+
+/* Haswell-EP PCU */
+#define HSWEP_PCU_MSR_PMON_CTR0			0x717
+#define HSWEP_PCU_MSR_PMON_CTL0			0x711
+#define HSWEP_PCU_MSR_PMON_BOX_CTL		0x710
+#define HSWEP_PCU_MSR_PMON_BOX_FILTER		0x715
+
+/* KNL Ubox */
+#define KNL_U_MSR_PMON_RAW_EVENT_MASK \
+					(SNBEP_U_MSR_PMON_RAW_EVENT_MASK | \
+						SNBEP_CBO_PMON_CTL_TID_EN)
+/* KNL CHA */
+#define KNL_CHA_MSR_OFFSET			0xc
+#define KNL_CHA_MSR_PMON_CTL_QOR		(1 << 16)
+#define KNL_CHA_MSR_PMON_RAW_EVENT_MASK \
+					(SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK | \
+					 KNL_CHA_MSR_PMON_CTL_QOR)
+#define KNL_CHA_MSR_PMON_BOX_FILTER_TID		0x1ff
+#define KNL_CHA_MSR_PMON_BOX_FILTER_STATE	(7 << 18)
+#define KNL_CHA_MSR_PMON_BOX_FILTER_OP		(0xfffffe2aULL << 32)
+
+/* KNL EDC/MC UCLK */
+#define KNL_UCLK_MSR_PMON_CTR0_LOW		0x400
+#define KNL_UCLK_MSR_PMON_CTL0			0x420
+#define KNL_UCLK_MSR_PMON_BOX_CTL		0x430
+#define KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW	0x44c
+#define KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL	0x454
+#define KNL_PMON_FIXED_CTL_EN			0x1
+
+/* KNL EDC */
+#define KNL_EDC0_ECLK_MSR_PMON_CTR0_LOW		0xa00
+#define KNL_EDC0_ECLK_MSR_PMON_CTL0		0xa20
+#define KNL_EDC0_ECLK_MSR_PMON_BOX_CTL		0xa30
+#define KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_LOW	0xa3c
+#define KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_CTL	0xa44
+
+/* KNL MC */
+#define KNL_MC0_CH0_MSR_PMON_CTR0_LOW		0xb00
+#define KNL_MC0_CH0_MSR_PMON_CTL0		0xb20
+#define KNL_MC0_CH0_MSR_PMON_BOX_CTL		0xb30
+#define KNL_MC0_CH0_MSR_PMON_FIXED_LOW		0xb3c
+#define KNL_MC0_CH0_MSR_PMON_FIXED_CTL		0xb44
+
+/* KNL IRP */
+#define KNL_IRP_PCI_PMON_BOX_CTL		0xf0
+#define KNL_IRP_PCI_PMON_RAW_EVENT_MASK		(SNBEP_PMON_RAW_EVENT_MASK | \
+						 KNL_CHA_MSR_PMON_CTL_QOR)
+/* KNL PCU */
+#define KNL_PCU_PMON_CTL_EV_SEL_MASK		0x0000007f
+#define KNL_PCU_PMON_CTL_USE_OCC_CTR		(1 << 7)
+#define KNL_PCU_MSR_PMON_CTL_TRESH_MASK		0x3f000000
+#define KNL_PCU_MSR_PMON_RAW_EVENT_MASK	\
+				(KNL_PCU_PMON_CTL_EV_SEL_MASK | \
+				 KNL_PCU_PMON_CTL_USE_OCC_CTR | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+				 SNBEP_PMON_CTL_EDGE_DET | \
+				 SNBEP_CBO_PMON_CTL_TID_EN | \
+				 SNBEP_PMON_CTL_EV_SEL_EXT | \
+				 SNBEP_PMON_CTL_INVERT | \
+				 KNL_PCU_MSR_PMON_CTL_TRESH_MASK | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event2, event, "config:0-6");
+DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
+DEFINE_UNCORE_FORMAT_ATTR(use_occ_ctr, use_occ_ctr, "config:7");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh6, thresh, "config:24-29");
+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");
+DEFINE_UNCORE_FORMAT_ATTR(occ_edge_det, occ_edge_det, "config:31");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid2, filter_tid, "config1:0");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid3, filter_tid, "config1:0-5");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid4, filter_tid, "config1:0-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link3, filter_link, "config1:12");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state3, filter_state, "config1:17-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state4, filter_state, "config1:18-20");
+DEFINE_UNCORE_FORMAT_ATTR(filter_local, filter_local, "config1:33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_all_op, filter_all_op, "config1:35");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nnm, filter_nnm, "config1:37");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc3, filter_opc, "config1:41-60");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nc, filter_nc, "config1:62");
+DEFINE_UNCORE_FORMAT_ATTR(filter_c6, filter_c6, "config1:61");
+DEFINE_UNCORE_FORMAT_ATTR(filter_isoc, filter_isoc, "config1:63");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(match_rds, match_rds, "config1:48-51");
+DEFINE_UNCORE_FORMAT_ATTR(match_rnid30, match_rnid30, "config1:32-35");
+DEFINE_UNCORE_FORMAT_ATTR(match_rnid4, match_rnid4, "config1:31");
+DEFINE_UNCORE_FORMAT_ATTR(match_dnid, match_dnid, "config1:13-17");
+DEFINE_UNCORE_FORMAT_ATTR(match_mc, match_mc, "config1:9-12");
+DEFINE_UNCORE_FORMAT_ATTR(match_opc, match_opc, "config1:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(match_vnw, match_vnw, "config1:3-4");
+DEFINE_UNCORE_FORMAT_ATTR(match0, match0, "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(match1, match1, "config1:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rds, mask_rds, "config2:48-51");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rnid30, mask_rnid30, "config2:32-35");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rnid4, mask_rnid4, "config2:31");
+DEFINE_UNCORE_FORMAT_ATTR(mask_dnid, mask_dnid, "config2:13-17");
+DEFINE_UNCORE_FORMAT_ATTR(mask_mc, mask_mc, "config2:9-12");
+DEFINE_UNCORE_FORMAT_ATTR(mask_opc, mask_opc, "config2:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
+DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
+
+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 = 0;
+
+	if (!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 = 0;
+
+	if (!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 = 0;
+
+	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;
+	int box_ctl = uncore_pci_box_ctl(box);
+
+	pci_write_config_dword(pdev, 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);
+	}
+}
+
+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);
+	}
+}
+
+static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+	if (reg1->idx != EXTRA_REG_NONE)
+		wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0));
+
+	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 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_cbox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_tid_en.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh8.attr,
+	&format_attr_filter_tid.attr,
+	&format_attr_filter_nid.attr,
+	&format_attr_filter_state.attr,
+	&format_attr_filter_opc.attr,
+	NULL,
+};
+
+static struct attribute *snbep_uncore_pcu_formats_attr[] = {
+	&format_attr_event_ext.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,
+	&format_attr_filter_band0.attr,
+	&format_attr_filter_band1.attr,
+	&format_attr_filter_band2.attr,
+	&format_attr_filter_band3.attr,
+	NULL,
+};
+
+static struct attribute *snbep_uncore_qpi_formats_attr[] = {
+	&format_attr_event_ext.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh8.attr,
+	&format_attr_match_rds.attr,
+	&format_attr_match_rnid30.attr,
+	&format_attr_match_rnid4.attr,
+	&format_attr_match_dnid.attr,
+	&format_attr_match_mc.attr,
+	&format_attr_match_opc.attr,
+	&format_attr_match_vnw.attr,
+	&format_attr_match0.attr,
+	&format_attr_match1.attr,
+	&format_attr_mask_rds.attr,
+	&format_attr_mask_rnid30.attr,
+	&format_attr_mask_rnid4.attr,
+	&format_attr_mask_dnid.attr,
+	&format_attr_mask_mc.attr,
+	&format_attr_mask_opc.attr,
+	&format_attr_mask_vnw.attr,
+	&format_attr_mask0.attr,
+	&format_attr_mask1.attr,
+	NULL,
+};
+
+static struct uncore_event_desc snbep_uncore_imc_events[] = {
+	INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0xff,umask=0x00"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_read.scale, "6.103515625e-5"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_read.unit, "MiB"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_write.scale, "6.103515625e-5"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_write.unit, "MiB"),
+	{ /* 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=0x102,umask=0x08"),
+	INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x103,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_cbox_format_group = {
+	.name = "format",
+	.attrs = snbep_uncore_cbox_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_pcu_format_group = {
+	.name = "format",
+	.attrs = snbep_uncore_pcu_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_qpi_format_group = {
+	.name = "format",
+	.attrs = snbep_uncore_qpi_formats_attr,
+};
+
+#define __SNBEP_UNCORE_MSR_OPS_COMMON_INIT()			\
+	.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	= uncore_msr_read_counter
+
+#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT()			\
+	__SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),			\
+	.init_box	= snbep_uncore_msr_init_box		\
+
+static struct intel_uncore_ops snbep_uncore_msr_ops = {
+	SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+};
+
+#define SNBEP_UNCORE_PCI_OPS_COMMON_INIT()			\
+	.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,	\
+	.read_counter	= snbep_uncore_pci_read_counter
+
+static struct intel_uncore_ops snbep_uncore_pci_ops = {
+	SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
+	.enable_event	= snbep_uncore_pci_enable_event,	\
+};
+
+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(0x09, 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),
+	EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff),
+	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(0x28, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2a, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2f, 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),
+	UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x39, 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 extra_reg snbep_uncore_cbox_extra_regs[] = {
+	SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+				  SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xa),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xa),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xa),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xa),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2),
+	EVENT_EXTRA_END
+};
+
+static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+	int i;
+
+	if (uncore_box_is_fake(box))
+		return;
+
+	for (i = 0; i < 5; i++) {
+		if (reg1->alloc & (0x1 << i))
+			atomic_sub(1 << (i * 6), &er->ref);
+	}
+	reg1->alloc = 0;
+}
+
+static struct event_constraint *
+__snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event,
+			    u64 (*cbox_filter_mask)(int fields))
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+	int i, alloc = 0;
+	unsigned long flags;
+	u64 mask;
+
+	if (reg1->idx == EXTRA_REG_NONE)
+		return NULL;
+
+	raw_spin_lock_irqsave(&er->lock, flags);
+	for (i = 0; i < 5; i++) {
+		if (!(reg1->idx & (0x1 << i)))
+			continue;
+		if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
+			continue;
+
+		mask = cbox_filter_mask(0x1 << i);
+		if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) ||
+		    !((reg1->config ^ er->config) & mask)) {
+			atomic_add(1 << (i * 6), &er->ref);
+			er->config &= ~mask;
+			er->config |= reg1->config & mask;
+			alloc |= (0x1 << i);
+		} else {
+			break;
+		}
+	}
+	raw_spin_unlock_irqrestore(&er->lock, flags);
+	if (i < 5)
+		goto fail;
+
+	if (!uncore_box_is_fake(box))
+		reg1->alloc |= alloc;
+
+	return NULL;
+fail:
+	for (; i >= 0; i--) {
+		if (alloc & (0x1 << i))
+			atomic_sub(1 << (i * 6), &er->ref);
+	}
+	return &uncore_constraint_empty;
+}
+
+static u64 snbep_cbox_filter_mask(int fields)
+{
+	u64 mask = 0;
+
+	if (fields & 0x1)
+		mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID;
+	if (fields & 0x2)
+		mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID;
+	if (fields & 0x4)
+		mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+	if (fields & 0x8)
+		mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+
+	return mask;
+}
+
+static struct event_constraint *
+snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask);
+}
+
+static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct extra_reg *er;
+	int idx = 0;
+
+	for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) {
+		if (er->event != (event->hw.config & er->config_mask))
+			continue;
+		idx |= er->idx;
+	}
+
+	if (idx) {
+		reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+			SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+		reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx);
+		reg1->idx = idx;
+	}
+	return 0;
+}
+
+static struct intel_uncore_ops snbep_uncore_cbox_ops = {
+	SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+	.hw_config		= snbep_cbox_hw_config,
+	.get_constraint		= snbep_cbox_get_constraint,
+	.put_constraint		= snbep_cbox_put_constraint,
+};
+
+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_CBO_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_C0_MSR_PMON_BOX_CTL,
+	.msr_offset		= SNBEP_CBO_MSR_OFFSET,
+	.num_shared_regs	= 1,
+	.constraints		= snbep_uncore_cbox_constraints,
+	.ops			= &snbep_uncore_cbox_ops,
+	.format_group		= &snbep_uncore_cbox_format_group,
+};
+
+static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	u64 config = reg1->config;
+
+	if (new_idx > reg1->idx)
+		config <<= 8 * (new_idx - reg1->idx);
+	else
+		config >>= 8 * (reg1->idx - new_idx);
+
+	if (modify) {
+		hwc->config += new_idx - reg1->idx;
+		reg1->config = config;
+		reg1->idx = new_idx;
+	}
+	return config;
+}
+
+static struct event_constraint *
+snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+	unsigned long flags;
+	int idx = reg1->idx;
+	u64 mask, config1 = reg1->config;
+	bool ok = false;
+
+	if (reg1->idx == EXTRA_REG_NONE ||
+	    (!uncore_box_is_fake(box) && reg1->alloc))
+		return NULL;
+again:
+	mask = 0xffULL << (idx * 8);
+	raw_spin_lock_irqsave(&er->lock, flags);
+	if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) ||
+	    !((config1 ^ er->config) & mask)) {
+		atomic_add(1 << (idx * 8), &er->ref);
+		er->config &= ~mask;
+		er->config |= config1 & mask;
+		ok = true;
+	}
+	raw_spin_unlock_irqrestore(&er->lock, flags);
+
+	if (!ok) {
+		idx = (idx + 1) % 4;
+		if (idx != reg1->idx) {
+			config1 = snbep_pcu_alter_er(event, idx, false);
+			goto again;
+		}
+		return &uncore_constraint_empty;
+	}
+
+	if (!uncore_box_is_fake(box)) {
+		if (idx != reg1->idx)
+			snbep_pcu_alter_er(event, idx, true);
+		reg1->alloc = 1;
+	}
+	return NULL;
+}
+
+static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+
+	if (uncore_box_is_fake(box) || !reg1->alloc)
+		return;
+
+	atomic_sub(1 << (reg1->idx * 8), &er->ref);
+	reg1->alloc = 0;
+}
+
+static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
+
+	if (ev_sel >= 0xb && ev_sel <= 0xe) {
+		reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
+		reg1->idx = ev_sel - 0xb;
+		reg1->config = event->attr.config1 & (0xff << (reg1->idx * 8));
+	}
+	return 0;
+}
+
+static struct intel_uncore_ops snbep_uncore_pcu_ops = {
+	SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+	.hw_config		= snbep_pcu_hw_config,
+	.get_constraint		= snbep_pcu_get_constraint,
+	.put_constraint		= snbep_pcu_put_constraint,
+};
+
+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,
+	.num_shared_regs	= 1,
+	.ops			= &snbep_uncore_pcu_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,
+};
+
+void snbep_uncore_cpu_init(void)
+{
+	if (snbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+		snbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+	uncore_msr_uncores = snbep_msr_uncores;
+}
+
+enum {
+	SNBEP_PCI_QPI_PORT0_FILTER,
+	SNBEP_PCI_QPI_PORT1_FILTER,
+	HSWEP_PCI_PCU_3,
+};
+
+static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+	if ((hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK) == 0x38) {
+		reg1->idx = 0;
+		reg1->reg = SNBEP_Q_Py_PCI_PMON_PKT_MATCH0;
+		reg1->config = event->attr.config1;
+		reg2->reg = SNBEP_Q_Py_PCI_PMON_PKT_MASK0;
+		reg2->config = event->attr.config2;
+	}
+	return 0;
+}
+
+static void snbep_qpi_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;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+	if (reg1->idx != EXTRA_REG_NONE) {
+		int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
+		struct pci_dev *filter_pdev = uncore_extra_pci_dev[box->phys_id][idx];
+		if (filter_pdev) {
+			pci_write_config_dword(filter_pdev, reg1->reg,
+						(u32)reg1->config);
+			pci_write_config_dword(filter_pdev, reg1->reg + 4,
+						(u32)(reg1->config >> 32));
+			pci_write_config_dword(filter_pdev, reg2->reg,
+						(u32)reg2->config);
+			pci_write_config_dword(filter_pdev, reg2->reg + 4,
+						(u32)(reg2->config >> 32));
+		}
+	}
+
+	pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops snbep_uncore_qpi_ops = {
+	SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
+	.enable_event		= snbep_qpi_enable_event,
+	.hw_config		= snbep_qpi_hw_config,
+	.get_constraint		= uncore_get_constraint,
+	.put_constraint		= uncore_put_constraint,
+};
+
+#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,
+	.perf_ctr		= SNBEP_PCI_PMON_CTR0,
+	.event_ctl		= SNBEP_PCI_PMON_CTL0,
+	.event_mask		= SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCI_PMON_BOX_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &snbep_uncore_qpi_ops,
+	.event_descs		= snbep_uncore_qpi_events,
+	.format_group		= &snbep_uncore_qpi_format_group,
+};
+
+
+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(),
+};
+
+enum {
+	SNBEP_PCI_UNCORE_HA,
+	SNBEP_PCI_UNCORE_IMC,
+	SNBEP_PCI_UNCORE_QPI,
+	SNBEP_PCI_UNCORE_R2PCIE,
+	SNBEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *snbep_pci_uncores[] = {
+	[SNBEP_PCI_UNCORE_HA]		= &snbep_uncore_ha,
+	[SNBEP_PCI_UNCORE_IMC]		= &snbep_uncore_imc,
+	[SNBEP_PCI_UNCORE_QPI]		= &snbep_uncore_qpi,
+	[SNBEP_PCI_UNCORE_R2PCIE]	= &snbep_uncore_r2pcie,
+	[SNBEP_PCI_UNCORE_R3QPI]	= &snbep_uncore_r3qpi,
+	NULL,
+};
+
+static const struct pci_device_id snbep_uncore_pci_ids[] = {
+	{ /* Home Agent */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_HA, 0),
+	},
+	{ /* MC Channel 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 0),
+	},
+	{ /* MC Channel 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 1),
+	},
+	{ /* MC Channel 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 2),
+	},
+	{ /* MC Channel 3 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 3),
+	},
+	{ /* QPI Port 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 0),
+	},
+	{ /* QPI Port 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 1),
+	},
+	{ /* R2PCIe */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R2PCIE, 0),
+	},
+	{ /* R3QPI Link 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 0),
+	},
+	{ /* R3QPI Link 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 1),
+	},
+	{ /* QPI Port 0 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c86),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   SNBEP_PCI_QPI_PORT0_FILTER),
+	},
+	{ /* QPI Port 0 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c96),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   SNBEP_PCI_QPI_PORT1_FILTER),
+	},
+	{ /* end: all zeroes */ }
+};
+
+static struct pci_driver snbep_uncore_pci_driver = {
+	.name		= "snbep_uncore",
+	.id_table	= snbep_uncore_pci_ids,
+};
+
+#define NODE_ID_MASK	0x7
+
+/*
+ * build pci bus to socket mapping
+ */
+static int snbep_pci2phy_map_init(int devid)
+{
+	struct pci_dev *ubox_dev = NULL;
+	int i, bus, nodeid, segment;
+	struct pci2phy_map *map;
+	int err = 0;
+	u32 config = 0;
+
+	while (1) {
+		/* find the UBOX device */
+		ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev);
+		if (!ubox_dev)
+			break;
+		bus = ubox_dev->bus->number;
+		/* get the Node ID of the local register */
+		err = pci_read_config_dword(ubox_dev, 0x40, &config);
+		if (err)
+			break;
+		nodeid = config & NODE_ID_MASK;
+		/* get the Node ID mapping */
+		err = pci_read_config_dword(ubox_dev, 0x54, &config);
+		if (err)
+			break;
+
+		segment = pci_domain_nr(ubox_dev->bus);
+		raw_spin_lock(&pci2phy_map_lock);
+		map = __find_pci2phy_map(segment);
+		if (!map) {
+			raw_spin_unlock(&pci2phy_map_lock);
+			err = -ENOMEM;
+			break;
+		}
+
+		/*
+		 * 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)) {
+				map->pbus_to_physid[bus] = i;
+				break;
+			}
+		}
+		raw_spin_unlock(&pci2phy_map_lock);
+	}
+
+	if (!err) {
+		/*
+		 * For PCI bus with no UBOX device, find the next bus
+		 * that has UBOX device and use its mapping.
+		 */
+		raw_spin_lock(&pci2phy_map_lock);
+		list_for_each_entry(map, &pci2phy_map_head, list) {
+			i = -1;
+			for (bus = 255; bus >= 0; bus--) {
+				if (map->pbus_to_physid[bus] >= 0)
+					i = map->pbus_to_physid[bus];
+				else
+					map->pbus_to_physid[bus] = i;
+			}
+		}
+		raw_spin_unlock(&pci2phy_map_lock);
+	}
+
+	pci_dev_put(ubox_dev);
+
+	return err ? pcibios_err_to_errno(err) : 0;
+}
+
+int snbep_uncore_pci_init(void)
+{
+	int ret = snbep_pci2phy_map_init(0x3ce0);
+	if (ret)
+		return ret;
+	uncore_pci_uncores = snbep_pci_uncores;
+	uncore_pci_driver = &snbep_uncore_pci_driver;
+	return 0;
+}
+/* end of Sandy Bridge-EP uncore support */
+
+/* IvyTown uncore support */
+static void ivbep_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+	unsigned msr = uncore_msr_box_ctl(box);
+	if (msr)
+		wrmsrl(msr, IVBEP_PMON_BOX_CTL_INT);
+}
+
+static void ivbep_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, IVBEP_PMON_BOX_CTL_INT);
+}
+
+#define IVBEP_UNCORE_MSR_OPS_COMMON_INIT()			\
+	.init_box	= ivbep_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	= uncore_msr_read_counter
+
+static struct intel_uncore_ops ivbep_uncore_msr_ops = {
+	IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+};
+
+static struct intel_uncore_ops ivbep_uncore_pci_ops = {
+	.init_box	= ivbep_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,
+};
+
+#define IVBEP_UNCORE_PCI_COMMON_INIT()				\
+	.perf_ctr	= SNBEP_PCI_PMON_CTR0,			\
+	.event_ctl	= SNBEP_PCI_PMON_CTL0,			\
+	.event_mask	= IVBEP_PMON_RAW_EVENT_MASK,		\
+	.box_ctl	= SNBEP_PCI_PMON_BOX_CTL,		\
+	.ops		= &ivbep_uncore_pci_ops,			\
+	.format_group	= &ivbep_uncore_format_group
+
+static struct attribute *ivbep_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 *ivbep_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 *ivbep_uncore_cbox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_tid_en.attr,
+	&format_attr_thresh8.attr,
+	&format_attr_filter_tid.attr,
+	&format_attr_filter_link.attr,
+	&format_attr_filter_state2.attr,
+	&format_attr_filter_nid2.attr,
+	&format_attr_filter_opc2.attr,
+	&format_attr_filter_nc.attr,
+	&format_attr_filter_c6.attr,
+	&format_attr_filter_isoc.attr,
+	NULL,
+};
+
+static struct attribute *ivbep_uncore_pcu_formats_attr[] = {
+	&format_attr_event_ext.attr,
+	&format_attr_occ_sel.attr,
+	&format_attr_edge.attr,
+	&format_attr_thresh5.attr,
+	&format_attr_occ_invert.attr,
+	&format_attr_occ_edge.attr,
+	&format_attr_filter_band0.attr,
+	&format_attr_filter_band1.attr,
+	&format_attr_filter_band2.attr,
+	&format_attr_filter_band3.attr,
+	NULL,
+};
+
+static struct attribute *ivbep_uncore_qpi_formats_attr[] = {
+	&format_attr_event_ext.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_thresh8.attr,
+	&format_attr_match_rds.attr,
+	&format_attr_match_rnid30.attr,
+	&format_attr_match_rnid4.attr,
+	&format_attr_match_dnid.attr,
+	&format_attr_match_mc.attr,
+	&format_attr_match_opc.attr,
+	&format_attr_match_vnw.attr,
+	&format_attr_match0.attr,
+	&format_attr_match1.attr,
+	&format_attr_mask_rds.attr,
+	&format_attr_mask_rnid30.attr,
+	&format_attr_mask_rnid4.attr,
+	&format_attr_mask_dnid.attr,
+	&format_attr_mask_mc.attr,
+	&format_attr_mask_opc.attr,
+	&format_attr_mask_vnw.attr,
+	&format_attr_mask0.attr,
+	&format_attr_mask1.attr,
+	NULL,
+};
+
+static struct attribute_group ivbep_uncore_format_group = {
+	.name = "format",
+	.attrs = ivbep_uncore_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_ubox_format_group = {
+	.name = "format",
+	.attrs = ivbep_uncore_ubox_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_cbox_format_group = {
+	.name = "format",
+	.attrs = ivbep_uncore_cbox_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_pcu_format_group = {
+	.name = "format",
+	.attrs = ivbep_uncore_pcu_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_qpi_format_group = {
+	.name = "format",
+	.attrs = ivbep_uncore_qpi_formats_attr,
+};
+
+static struct intel_uncore_type ivbep_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	= IVBEP_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		= &ivbep_uncore_msr_ops,
+	.format_group	= &ivbep_uncore_ubox_format_group,
+};
+
+static struct extra_reg ivbep_uncore_cbox_extra_regs[] = {
+	SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+				  SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
+	EVENT_EXTRA_END
+};
+
+static u64 ivbep_cbox_filter_mask(int fields)
+{
+	u64 mask = 0;
+
+	if (fields & 0x1)
+		mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_TID;
+	if (fields & 0x2)
+		mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_LINK;
+	if (fields & 0x4)
+		mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+	if (fields & 0x8)
+		mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_NID;
+	if (fields & 0x10) {
+		mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+		mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_NC;
+		mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_C6;
+		mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_ISOC;
+	}
+
+	return mask;
+}
+
+static struct event_constraint *
+ivbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	return __snbep_cbox_get_constraint(box, event, ivbep_cbox_filter_mask);
+}
+
+static int ivbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct extra_reg *er;
+	int idx = 0;
+
+	for (er = ivbep_uncore_cbox_extra_regs; er->msr; er++) {
+		if (er->event != (event->hw.config & er->config_mask))
+			continue;
+		idx |= er->idx;
+	}
+
+	if (idx) {
+		reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+			SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+		reg1->config = event->attr.config1 & ivbep_cbox_filter_mask(idx);
+		reg1->idx = idx;
+	}
+	return 0;
+}
+
+static void ivbep_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+	if (reg1->idx != EXTRA_REG_NONE) {
+		u64 filter = uncore_shared_reg_config(box, 0);
+		wrmsrl(reg1->reg, filter & 0xffffffff);
+		wrmsrl(reg1->reg + 6, filter >> 32);
+	}
+
+	wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops ivbep_uncore_cbox_ops = {
+	.init_box		= ivbep_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		= ivbep_cbox_enable_event,
+	.read_counter		= uncore_msr_read_counter,
+	.hw_config		= ivbep_cbox_hw_config,
+	.get_constraint		= ivbep_cbox_get_constraint,
+	.put_constraint		= snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_uncore_cbox = {
+	.name			= "cbox",
+	.num_counters		= 4,
+	.num_boxes		= 15,
+	.perf_ctr_bits		= 44,
+	.event_ctl		= SNBEP_C0_MSR_PMON_CTL0,
+	.perf_ctr		= SNBEP_C0_MSR_PMON_CTR0,
+	.event_mask		= IVBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_C0_MSR_PMON_BOX_CTL,
+	.msr_offset		= SNBEP_CBO_MSR_OFFSET,
+	.num_shared_regs	= 1,
+	.constraints		= snbep_uncore_cbox_constraints,
+	.ops			= &ivbep_uncore_cbox_ops,
+	.format_group		= &ivbep_uncore_cbox_format_group,
+};
+
+static struct intel_uncore_ops ivbep_uncore_pcu_ops = {
+	IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+	.hw_config		= snbep_pcu_hw_config,
+	.get_constraint		= snbep_pcu_get_constraint,
+	.put_constraint		= snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_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		= IVBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCU_MSR_PMON_BOX_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &ivbep_uncore_pcu_ops,
+	.format_group		= &ivbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *ivbep_msr_uncores[] = {
+	&ivbep_uncore_ubox,
+	&ivbep_uncore_cbox,
+	&ivbep_uncore_pcu,
+	NULL,
+};
+
+void ivbep_uncore_cpu_init(void)
+{
+	if (ivbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+		ivbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+	uncore_msr_uncores = ivbep_msr_uncores;
+}
+
+static struct intel_uncore_type ivbep_uncore_ha = {
+	.name		= "ha",
+	.num_counters   = 4,
+	.num_boxes	= 2,
+	.perf_ctr_bits	= 48,
+	IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivbep_uncore_imc = {
+	.name		= "imc",
+	.num_counters   = 4,
+	.num_boxes	= 8,
+	.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,
+	IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+/* registers in IRP boxes are not properly aligned */
+static unsigned ivbep_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4};
+static unsigned ivbep_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0};
+
+static void ivbep_uncore_irp_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, ivbep_uncore_irp_ctls[hwc->idx],
+			       hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void ivbep_uncore_irp_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, ivbep_uncore_irp_ctls[hwc->idx], hwc->config);
+}
+
+static u64 ivbep_uncore_irp_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 = 0;
+
+	pci_read_config_dword(pdev, ivbep_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
+	pci_read_config_dword(pdev, ivbep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
+
+	return count;
+}
+
+static struct intel_uncore_ops ivbep_uncore_irp_ops = {
+	.init_box	= ivbep_uncore_pci_init_box,
+	.disable_box	= snbep_uncore_pci_disable_box,
+	.enable_box	= snbep_uncore_pci_enable_box,
+	.disable_event	= ivbep_uncore_irp_disable_event,
+	.enable_event	= ivbep_uncore_irp_enable_event,
+	.read_counter	= ivbep_uncore_irp_read_counter,
+};
+
+static struct intel_uncore_type ivbep_uncore_irp = {
+	.name			= "irp",
+	.num_counters		= 4,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.event_mask		= IVBEP_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCI_PMON_BOX_CTL,
+	.ops			= &ivbep_uncore_irp_ops,
+	.format_group		= &ivbep_uncore_format_group,
+};
+
+static struct intel_uncore_ops ivbep_uncore_qpi_ops = {
+	.init_box	= ivbep_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_qpi_enable_event,
+	.read_counter	= snbep_uncore_pci_read_counter,
+	.hw_config	= snbep_qpi_hw_config,
+	.get_constraint	= uncore_get_constraint,
+	.put_constraint	= uncore_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_uncore_qpi = {
+	.name			= "qpi",
+	.num_counters		= 4,
+	.num_boxes		= 3,
+	.perf_ctr_bits		= 48,
+	.perf_ctr		= SNBEP_PCI_PMON_CTR0,
+	.event_ctl		= SNBEP_PCI_PMON_CTL0,
+	.event_mask		= IVBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCI_PMON_BOX_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &ivbep_uncore_qpi_ops,
+	.format_group		= &ivbep_uncore_qpi_format_group,
+};
+
+static struct intel_uncore_type ivbep_uncore_r2pcie = {
+	.name		= "r2pcie",
+	.num_counters   = 4,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 44,
+	.constraints	= snbep_uncore_r2pcie_constraints,
+	IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivbep_uncore_r3qpi = {
+	.name		= "r3qpi",
+	.num_counters   = 3,
+	.num_boxes	= 2,
+	.perf_ctr_bits	= 44,
+	.constraints	= snbep_uncore_r3qpi_constraints,
+	IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+	IVBEP_PCI_UNCORE_HA,
+	IVBEP_PCI_UNCORE_IMC,
+	IVBEP_PCI_UNCORE_IRP,
+	IVBEP_PCI_UNCORE_QPI,
+	IVBEP_PCI_UNCORE_R2PCIE,
+	IVBEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *ivbep_pci_uncores[] = {
+	[IVBEP_PCI_UNCORE_HA]	= &ivbep_uncore_ha,
+	[IVBEP_PCI_UNCORE_IMC]	= &ivbep_uncore_imc,
+	[IVBEP_PCI_UNCORE_IRP]	= &ivbep_uncore_irp,
+	[IVBEP_PCI_UNCORE_QPI]	= &ivbep_uncore_qpi,
+	[IVBEP_PCI_UNCORE_R2PCIE]	= &ivbep_uncore_r2pcie,
+	[IVBEP_PCI_UNCORE_R3QPI]	= &ivbep_uncore_r3qpi,
+	NULL,
+};
+
+static const struct pci_device_id ivbep_uncore_pci_ids[] = {
+	{ /* Home Agent 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_HA, 0),
+	},
+	{ /* Home Agent 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_HA, 1),
+	},
+	{ /* MC0 Channel 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 0),
+	},
+	{ /* MC0 Channel 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 1),
+	},
+	{ /* MC0 Channel 3 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 2),
+	},
+	{ /* MC0 Channel 4 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 3),
+	},
+	{ /* MC1 Channel 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 4),
+	},
+	{ /* MC1 Channel 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 5),
+	},
+	{ /* MC1 Channel 3 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 6),
+	},
+	{ /* MC1 Channel 4 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 7),
+	},
+	{ /* IRP */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IRP, 0),
+	},
+	{ /* QPI0 Port 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 0),
+	},
+	{ /* QPI0 Port 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 1),
+	},
+	{ /* QPI1 Port 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 2),
+	},
+	{ /* R2PCIe */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R2PCIE, 0),
+	},
+	{ /* R3QPI0 Link 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 0),
+	},
+	{ /* R3QPI0 Link 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 1),
+	},
+	{ /* R3QPI1 Link 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e),
+		.driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 2),
+	},
+	{ /* QPI Port 0 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   SNBEP_PCI_QPI_PORT0_FILTER),
+	},
+	{ /* QPI Port 0 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe96),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   SNBEP_PCI_QPI_PORT1_FILTER),
+	},
+	{ /* end: all zeroes */ }
+};
+
+static struct pci_driver ivbep_uncore_pci_driver = {
+	.name		= "ivbep_uncore",
+	.id_table	= ivbep_uncore_pci_ids,
+};
+
+int ivbep_uncore_pci_init(void)
+{
+	int ret = snbep_pci2phy_map_init(0x0e1e);
+	if (ret)
+		return ret;
+	uncore_pci_uncores = ivbep_pci_uncores;
+	uncore_pci_driver = &ivbep_uncore_pci_driver;
+	return 0;
+}
+/* end of IvyTown uncore support */
+
+/* KNL uncore support */
+static struct attribute *knl_uncore_ubox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_tid_en.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh5.attr,
+	NULL,
+};
+
+static struct attribute_group knl_uncore_ubox_format_group = {
+	.name = "format",
+	.attrs = knl_uncore_ubox_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_ubox = {
+	.name			= "ubox",
+	.num_counters		= 2,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.fixed_ctr_bits		= 48,
+	.perf_ctr		= HSWEP_U_MSR_PMON_CTR0,
+	.event_ctl		= HSWEP_U_MSR_PMON_CTL0,
+	.event_mask		= KNL_U_MSR_PMON_RAW_EVENT_MASK,
+	.fixed_ctr		= HSWEP_U_MSR_PMON_UCLK_FIXED_CTR,
+	.fixed_ctl		= HSWEP_U_MSR_PMON_UCLK_FIXED_CTL,
+	.ops			= &snbep_uncore_msr_ops,
+	.format_group		= &knl_uncore_ubox_format_group,
+};
+
+static struct attribute *knl_uncore_cha_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_qor.attr,
+	&format_attr_edge.attr,
+	&format_attr_tid_en.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh8.attr,
+	&format_attr_filter_tid4.attr,
+	&format_attr_filter_link3.attr,
+	&format_attr_filter_state4.attr,
+	&format_attr_filter_local.attr,
+	&format_attr_filter_all_op.attr,
+	&format_attr_filter_nnm.attr,
+	&format_attr_filter_opc3.attr,
+	&format_attr_filter_nc.attr,
+	&format_attr_filter_isoc.attr,
+	NULL,
+};
+
+static struct attribute_group knl_uncore_cha_format_group = {
+	.name = "format",
+	.attrs = knl_uncore_cha_formats_attr,
+};
+
+static struct event_constraint knl_uncore_cha_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x1f, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+	EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg knl_uncore_cha_extra_regs[] = {
+	SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+				  SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x3d, 0xff, 0x2),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x35, 0xff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x36, 0xff, 0x4),
+	EVENT_EXTRA_END
+};
+
+static u64 knl_cha_filter_mask(int fields)
+{
+	u64 mask = 0;
+
+	if (fields & 0x1)
+		mask |= KNL_CHA_MSR_PMON_BOX_FILTER_TID;
+	if (fields & 0x2)
+		mask |= KNL_CHA_MSR_PMON_BOX_FILTER_STATE;
+	if (fields & 0x4)
+		mask |= KNL_CHA_MSR_PMON_BOX_FILTER_OP;
+	return mask;
+}
+
+static struct event_constraint *
+knl_cha_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	return __snbep_cbox_get_constraint(box, event, knl_cha_filter_mask);
+}
+
+static int knl_cha_hw_config(struct intel_uncore_box *box,
+			     struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct extra_reg *er;
+	int idx = 0;
+
+	for (er = knl_uncore_cha_extra_regs; er->msr; er++) {
+		if (er->event != (event->hw.config & er->config_mask))
+			continue;
+		idx |= er->idx;
+	}
+
+	if (idx) {
+		reg1->reg = HSWEP_C0_MSR_PMON_BOX_FILTER0 +
+			    KNL_CHA_MSR_OFFSET * box->pmu->pmu_idx;
+		reg1->config = event->attr.config1 & knl_cha_filter_mask(idx);
+		reg1->idx = idx;
+	}
+	return 0;
+}
+
+static void hswep_cbox_enable_event(struct intel_uncore_box *box,
+				    struct perf_event *event);
+
+static struct intel_uncore_ops knl_uncore_cha_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		= hswep_cbox_enable_event,
+	.read_counter		= uncore_msr_read_counter,
+	.hw_config		= knl_cha_hw_config,
+	.get_constraint		= knl_cha_get_constraint,
+	.put_constraint		= snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type knl_uncore_cha = {
+	.name			= "cha",
+	.num_counters		= 4,
+	.num_boxes		= 38,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= HSWEP_C0_MSR_PMON_CTL0,
+	.perf_ctr		= HSWEP_C0_MSR_PMON_CTR0,
+	.event_mask		= KNL_CHA_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= HSWEP_C0_MSR_PMON_BOX_CTL,
+	.msr_offset		= KNL_CHA_MSR_OFFSET,
+	.num_shared_regs	= 1,
+	.constraints		= knl_uncore_cha_constraints,
+	.ops			= &knl_uncore_cha_ops,
+	.format_group		= &knl_uncore_cha_format_group,
+};
+
+static struct attribute *knl_uncore_pcu_formats_attr[] = {
+	&format_attr_event2.attr,
+	&format_attr_use_occ_ctr.attr,
+	&format_attr_occ_sel.attr,
+	&format_attr_edge.attr,
+	&format_attr_tid_en.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh6.attr,
+	&format_attr_occ_invert.attr,
+	&format_attr_occ_edge_det.attr,
+	NULL,
+};
+
+static struct attribute_group knl_uncore_pcu_format_group = {
+	.name = "format",
+	.attrs = knl_uncore_pcu_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_pcu = {
+	.name			= "pcu",
+	.num_counters		= 4,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.perf_ctr		= HSWEP_PCU_MSR_PMON_CTR0,
+	.event_ctl		= HSWEP_PCU_MSR_PMON_CTL0,
+	.event_mask		= KNL_PCU_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= HSWEP_PCU_MSR_PMON_BOX_CTL,
+	.ops			= &snbep_uncore_msr_ops,
+	.format_group		= &knl_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *knl_msr_uncores[] = {
+	&knl_uncore_ubox,
+	&knl_uncore_cha,
+	&knl_uncore_pcu,
+	NULL,
+};
+
+void knl_uncore_cpu_init(void)
+{
+	uncore_msr_uncores = knl_msr_uncores;
+}
+
+static void knl_uncore_imc_enable_box(struct intel_uncore_box *box)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	int box_ctl = uncore_pci_box_ctl(box);
+
+	pci_write_config_dword(pdev, box_ctl, 0);
+}
+
+static void knl_uncore_imc_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;
+
+	if ((event->attr.config & SNBEP_PMON_CTL_EV_SEL_MASK)
+							== UNCORE_FIXED_EVENT)
+		pci_write_config_dword(pdev, hwc->config_base,
+				       hwc->config | KNL_PMON_FIXED_CTL_EN);
+	else
+		pci_write_config_dword(pdev, hwc->config_base,
+				       hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops knl_uncore_imc_ops = {
+	.init_box	= snbep_uncore_pci_init_box,
+	.disable_box	= snbep_uncore_pci_disable_box,
+	.enable_box	= knl_uncore_imc_enable_box,
+	.read_counter	= snbep_uncore_pci_read_counter,
+	.enable_event	= knl_uncore_imc_enable_event,
+	.disable_event	= snbep_uncore_pci_disable_event,
+};
+
+static struct intel_uncore_type knl_uncore_imc_uclk = {
+	.name			= "imc_uclk",
+	.num_counters		= 4,
+	.num_boxes		= 2,
+	.perf_ctr_bits		= 48,
+	.fixed_ctr_bits		= 48,
+	.perf_ctr		= KNL_UCLK_MSR_PMON_CTR0_LOW,
+	.event_ctl		= KNL_UCLK_MSR_PMON_CTL0,
+	.event_mask		= SNBEP_PMON_RAW_EVENT_MASK,
+	.fixed_ctr		= KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW,
+	.fixed_ctl		= KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL,
+	.box_ctl		= KNL_UCLK_MSR_PMON_BOX_CTL,
+	.ops			= &knl_uncore_imc_ops,
+	.format_group		= &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_imc_dclk = {
+	.name			= "imc",
+	.num_counters		= 4,
+	.num_boxes		= 6,
+	.perf_ctr_bits		= 48,
+	.fixed_ctr_bits		= 48,
+	.perf_ctr		= KNL_MC0_CH0_MSR_PMON_CTR0_LOW,
+	.event_ctl		= KNL_MC0_CH0_MSR_PMON_CTL0,
+	.event_mask		= SNBEP_PMON_RAW_EVENT_MASK,
+	.fixed_ctr		= KNL_MC0_CH0_MSR_PMON_FIXED_LOW,
+	.fixed_ctl		= KNL_MC0_CH0_MSR_PMON_FIXED_CTL,
+	.box_ctl		= KNL_MC0_CH0_MSR_PMON_BOX_CTL,
+	.ops			= &knl_uncore_imc_ops,
+	.format_group		= &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_edc_uclk = {
+	.name			= "edc_uclk",
+	.num_counters		= 4,
+	.num_boxes		= 8,
+	.perf_ctr_bits		= 48,
+	.fixed_ctr_bits		= 48,
+	.perf_ctr		= KNL_UCLK_MSR_PMON_CTR0_LOW,
+	.event_ctl		= KNL_UCLK_MSR_PMON_CTL0,
+	.event_mask		= SNBEP_PMON_RAW_EVENT_MASK,
+	.fixed_ctr		= KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW,
+	.fixed_ctl		= KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL,
+	.box_ctl		= KNL_UCLK_MSR_PMON_BOX_CTL,
+	.ops			= &knl_uncore_imc_ops,
+	.format_group		= &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_edc_eclk = {
+	.name			= "edc_eclk",
+	.num_counters		= 4,
+	.num_boxes		= 8,
+	.perf_ctr_bits		= 48,
+	.fixed_ctr_bits		= 48,
+	.perf_ctr		= KNL_EDC0_ECLK_MSR_PMON_CTR0_LOW,
+	.event_ctl		= KNL_EDC0_ECLK_MSR_PMON_CTL0,
+	.event_mask		= SNBEP_PMON_RAW_EVENT_MASK,
+	.fixed_ctr		= KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_LOW,
+	.fixed_ctl		= KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_CTL,
+	.box_ctl		= KNL_EDC0_ECLK_MSR_PMON_BOX_CTL,
+	.ops			= &knl_uncore_imc_ops,
+	.format_group		= &snbep_uncore_format_group,
+};
+
+static struct event_constraint knl_uncore_m2pcie_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+	EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type knl_uncore_m2pcie = {
+	.name		= "m2pcie",
+	.num_counters   = 4,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 48,
+	.constraints	= knl_uncore_m2pcie_constraints,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct attribute *knl_uncore_irp_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_qor.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh8.attr,
+	NULL,
+};
+
+static struct attribute_group knl_uncore_irp_format_group = {
+	.name = "format",
+	.attrs = knl_uncore_irp_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_irp = {
+	.name			= "irp",
+	.num_counters		= 2,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.perf_ctr		= SNBEP_PCI_PMON_CTR0,
+	.event_ctl		= SNBEP_PCI_PMON_CTL0,
+	.event_mask		= KNL_IRP_PCI_PMON_RAW_EVENT_MASK,
+	.box_ctl		= KNL_IRP_PCI_PMON_BOX_CTL,
+	.ops			= &snbep_uncore_pci_ops,
+	.format_group		= &knl_uncore_irp_format_group,
+};
+
+enum {
+	KNL_PCI_UNCORE_MC_UCLK,
+	KNL_PCI_UNCORE_MC_DCLK,
+	KNL_PCI_UNCORE_EDC_UCLK,
+	KNL_PCI_UNCORE_EDC_ECLK,
+	KNL_PCI_UNCORE_M2PCIE,
+	KNL_PCI_UNCORE_IRP,
+};
+
+static struct intel_uncore_type *knl_pci_uncores[] = {
+	[KNL_PCI_UNCORE_MC_UCLK]	= &knl_uncore_imc_uclk,
+	[KNL_PCI_UNCORE_MC_DCLK]	= &knl_uncore_imc_dclk,
+	[KNL_PCI_UNCORE_EDC_UCLK]	= &knl_uncore_edc_uclk,
+	[KNL_PCI_UNCORE_EDC_ECLK]	= &knl_uncore_edc_eclk,
+	[KNL_PCI_UNCORE_M2PCIE]		= &knl_uncore_m2pcie,
+	[KNL_PCI_UNCORE_IRP]		= &knl_uncore_irp,
+	NULL,
+};
+
+/*
+ * KNL uses a common PCI device ID for multiple instances of an Uncore PMU
+ * device type. prior to KNL, each instance of a PMU device type had a unique
+ * device ID.
+ *
+ *	PCI Device ID	Uncore PMU Devices
+ *	----------------------------------
+ *	0x7841		MC0 UClk, MC1 UClk
+ *	0x7843		MC0 DClk CH 0, MC0 DClk CH 1, MC0 DClk CH 2,
+ *			MC1 DClk CH 0, MC1 DClk CH 1, MC1 DClk CH 2
+ *	0x7833		EDC0 UClk, EDC1 UClk, EDC2 UClk, EDC3 UClk,
+ *			EDC4 UClk, EDC5 UClk, EDC6 UClk, EDC7 UClk
+ *	0x7835		EDC0 EClk, EDC1 EClk, EDC2 EClk, EDC3 EClk,
+ *			EDC4 EClk, EDC5 EClk, EDC6 EClk, EDC7 EClk
+ *	0x7817		M2PCIe
+ *	0x7814		IRP
+*/
+
+static const struct pci_device_id knl_uncore_pci_ids[] = {
+	{ /* MC UClk */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7841),
+		.driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_MC_UCLK, 0),
+	},
+	{ /* MC DClk Channel */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843),
+		.driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_MC_DCLK, 0),
+	},
+	{ /* EDC UClk */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833),
+		.driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_EDC_UCLK, 0),
+	},
+	{ /* EDC EClk */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835),
+		.driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_EDC_ECLK, 0),
+	},
+	{ /* M2PCIe */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7817),
+		.driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_M2PCIE, 0),
+	},
+	{ /* IRP */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7814),
+		.driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_IRP, 0),
+	},
+	{ /* end: all zeroes */ }
+};
+
+static struct pci_driver knl_uncore_pci_driver = {
+	.name		= "knl_uncore",
+	.id_table	= knl_uncore_pci_ids,
+};
+
+int knl_uncore_pci_init(void)
+{
+	int ret;
+
+	/* All KNL PCI based PMON units are on the same PCI bus except IRP */
+	ret = snb_pci2phy_map_init(0x7814); /* IRP */
+	if (ret)
+		return ret;
+	ret = snb_pci2phy_map_init(0x7817); /* M2PCIe */
+	if (ret)
+		return ret;
+	uncore_pci_uncores = knl_pci_uncores;
+	uncore_pci_driver = &knl_uncore_pci_driver;
+	return 0;
+}
+
+/* end of KNL uncore support */
+
+/* Haswell-EP uncore support */
+static struct attribute *hswep_uncore_ubox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh5.attr,
+	&format_attr_filter_tid2.attr,
+	&format_attr_filter_cid.attr,
+	NULL,
+};
+
+static struct attribute_group hswep_uncore_ubox_format_group = {
+	.name = "format",
+	.attrs = hswep_uncore_ubox_formats_attr,
+};
+
+static int hswep_ubox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	reg1->reg = HSWEP_U_MSR_PMON_FILTER;
+	reg1->config = event->attr.config1 & HSWEP_U_MSR_PMON_BOX_FILTER_MASK;
+	reg1->idx = 0;
+	return 0;
+}
+
+static struct intel_uncore_ops hswep_uncore_ubox_ops = {
+	SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+	.hw_config		= hswep_ubox_hw_config,
+	.get_constraint		= uncore_get_constraint,
+	.put_constraint		= uncore_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_ubox = {
+	.name			= "ubox",
+	.num_counters		= 2,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 44,
+	.fixed_ctr_bits		= 48,
+	.perf_ctr		= HSWEP_U_MSR_PMON_CTR0,
+	.event_ctl		= HSWEP_U_MSR_PMON_CTL0,
+	.event_mask		= SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+	.fixed_ctr		= HSWEP_U_MSR_PMON_UCLK_FIXED_CTR,
+	.fixed_ctl		= HSWEP_U_MSR_PMON_UCLK_FIXED_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &hswep_uncore_ubox_ops,
+	.format_group		= &hswep_uncore_ubox_format_group,
+};
+
+static struct attribute *hswep_uncore_cbox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_tid_en.attr,
+	&format_attr_thresh8.attr,
+	&format_attr_filter_tid3.attr,
+	&format_attr_filter_link2.attr,
+	&format_attr_filter_state3.attr,
+	&format_attr_filter_nid2.attr,
+	&format_attr_filter_opc2.attr,
+	&format_attr_filter_nc.attr,
+	&format_attr_filter_c6.attr,
+	&format_attr_filter_isoc.attr,
+	NULL,
+};
+
+static struct attribute_group hswep_uncore_cbox_format_group = {
+	.name = "format",
+	.attrs = hswep_uncore_cbox_formats_attr,
+};
+
+static struct event_constraint hswep_uncore_cbox_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x09, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x3e, 0x1),
+	EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg hswep_uncore_cbox_extra_regs[] = {
+	SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+				  SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2134, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x4),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4028, 0x40ff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4032, 0x40ff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4029, 0x40ff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4033, 0x40ff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x402A, 0x40ff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x12),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
+	SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
+	EVENT_EXTRA_END
+};
+
+static u64 hswep_cbox_filter_mask(int fields)
+{
+	u64 mask = 0;
+	if (fields & 0x1)
+		mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_TID;
+	if (fields & 0x2)
+		mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_LINK;
+	if (fields & 0x4)
+		mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+	if (fields & 0x8)
+		mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_NID;
+	if (fields & 0x10) {
+		mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+		mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_NC;
+		mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_C6;
+		mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_ISOC;
+	}
+	return mask;
+}
+
+static struct event_constraint *
+hswep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+	return __snbep_cbox_get_constraint(box, event, hswep_cbox_filter_mask);
+}
+
+static int hswep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+	struct extra_reg *er;
+	int idx = 0;
+
+	for (er = hswep_uncore_cbox_extra_regs; er->msr; er++) {
+		if (er->event != (event->hw.config & er->config_mask))
+			continue;
+		idx |= er->idx;
+	}
+
+	if (idx) {
+		reg1->reg = HSWEP_C0_MSR_PMON_BOX_FILTER0 +
+			    HSWEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+		reg1->config = event->attr.config1 & hswep_cbox_filter_mask(idx);
+		reg1->idx = idx;
+	}
+	return 0;
+}
+
+static void hswep_cbox_enable_event(struct intel_uncore_box *box,
+				  struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+	if (reg1->idx != EXTRA_REG_NONE) {
+		u64 filter = uncore_shared_reg_config(box, 0);
+		wrmsrl(reg1->reg, filter & 0xffffffff);
+		wrmsrl(reg1->reg + 1, filter >> 32);
+	}
+
+	wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops hswep_uncore_cbox_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		= hswep_cbox_enable_event,
+	.read_counter		= uncore_msr_read_counter,
+	.hw_config		= hswep_cbox_hw_config,
+	.get_constraint		= hswep_cbox_get_constraint,
+	.put_constraint		= snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_cbox = {
+	.name			= "cbox",
+	.num_counters		= 4,
+	.num_boxes		= 18,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= HSWEP_C0_MSR_PMON_CTL0,
+	.perf_ctr		= HSWEP_C0_MSR_PMON_CTR0,
+	.event_mask		= SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= HSWEP_C0_MSR_PMON_BOX_CTL,
+	.msr_offset		= HSWEP_CBO_MSR_OFFSET,
+	.num_shared_regs	= 1,
+	.constraints		= hswep_uncore_cbox_constraints,
+	.ops			= &hswep_uncore_cbox_ops,
+	.format_group		= &hswep_uncore_cbox_format_group,
+};
+
+/*
+ * Write SBOX Initialization register bit by bit to avoid spurious #GPs
+ */
+static void hswep_uncore_sbox_msr_init_box(struct intel_uncore_box *box)
+{
+	unsigned msr = uncore_msr_box_ctl(box);
+
+	if (msr) {
+		u64 init = SNBEP_PMON_BOX_CTL_INT;
+		u64 flags = 0;
+		int i;
+
+		for_each_set_bit(i, (unsigned long *)&init, 64) {
+			flags |= (1ULL << i);
+			wrmsrl(msr, flags);
+		}
+	}
+}
+
+static struct intel_uncore_ops hswep_uncore_sbox_msr_ops = {
+	__SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+	.init_box		= hswep_uncore_sbox_msr_init_box
+};
+
+static struct attribute *hswep_uncore_sbox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_tid_en.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh8.attr,
+	NULL,
+};
+
+static struct attribute_group hswep_uncore_sbox_format_group = {
+	.name = "format",
+	.attrs = hswep_uncore_sbox_formats_attr,
+};
+
+static struct intel_uncore_type hswep_uncore_sbox = {
+	.name			= "sbox",
+	.num_counters		= 4,
+	.num_boxes		= 4,
+	.perf_ctr_bits		= 44,
+	.event_ctl		= HSWEP_S0_MSR_PMON_CTL0,
+	.perf_ctr		= HSWEP_S0_MSR_PMON_CTR0,
+	.event_mask		= HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= HSWEP_S0_MSR_PMON_BOX_CTL,
+	.msr_offset		= HSWEP_SBOX_MSR_OFFSET,
+	.ops			= &hswep_uncore_sbox_msr_ops,
+	.format_group		= &hswep_uncore_sbox_format_group,
+};
+
+static int hswep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
+
+	if (ev_sel >= 0xb && ev_sel <= 0xe) {
+		reg1->reg = HSWEP_PCU_MSR_PMON_BOX_FILTER;
+		reg1->idx = ev_sel - 0xb;
+		reg1->config = event->attr.config1 & (0xff << reg1->idx);
+	}
+	return 0;
+}
+
+static struct intel_uncore_ops hswep_uncore_pcu_ops = {
+	SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+	.hw_config		= hswep_pcu_hw_config,
+	.get_constraint		= snbep_pcu_get_constraint,
+	.put_constraint		= snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_pcu = {
+	.name			= "pcu",
+	.num_counters		= 4,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.perf_ctr		= HSWEP_PCU_MSR_PMON_CTR0,
+	.event_ctl		= HSWEP_PCU_MSR_PMON_CTL0,
+	.event_mask		= SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= HSWEP_PCU_MSR_PMON_BOX_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &hswep_uncore_pcu_ops,
+	.format_group		= &snbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *hswep_msr_uncores[] = {
+	&hswep_uncore_ubox,
+	&hswep_uncore_cbox,
+	&hswep_uncore_sbox,
+	&hswep_uncore_pcu,
+	NULL,
+};
+
+void hswep_uncore_cpu_init(void)
+{
+	if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+		hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+
+	/* Detect 6-8 core systems with only two SBOXes */
+	if (uncore_extra_pci_dev[0][HSWEP_PCI_PCU_3]) {
+		u32 capid4;
+
+		pci_read_config_dword(uncore_extra_pci_dev[0][HSWEP_PCI_PCU_3],
+				      0x94, &capid4);
+		if (((capid4 >> 6) & 0x3) == 0)
+			hswep_uncore_sbox.num_boxes = 2;
+	}
+
+	uncore_msr_uncores = hswep_msr_uncores;
+}
+
+static struct intel_uncore_type hswep_uncore_ha = {
+	.name		= "ha",
+	.num_counters   = 5,
+	.num_boxes	= 2,
+	.perf_ctr_bits	= 48,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct uncore_event_desc hswep_uncore_imc_events[] = {
+	INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0x00,umask=0x00"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_read.scale, "6.103515625e-5"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_read.unit, "MiB"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_write.scale, "6.103515625e-5"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_write.unit, "MiB"),
+	{ /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type hswep_uncore_imc = {
+	.name		= "imc",
+	.num_counters   = 5,
+	.num_boxes	= 8,
+	.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	= hswep_uncore_imc_events,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static unsigned hswep_uncore_irp_ctrs[] = {0xa0, 0xa8, 0xb0, 0xb8};
+
+static u64 hswep_uncore_irp_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 = 0;
+
+	pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
+	pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
+
+	return count;
+}
+
+static struct intel_uncore_ops hswep_uncore_irp_ops = {
+	.init_box	= snbep_uncore_pci_init_box,
+	.disable_box	= snbep_uncore_pci_disable_box,
+	.enable_box	= snbep_uncore_pci_enable_box,
+	.disable_event	= ivbep_uncore_irp_disable_event,
+	.enable_event	= ivbep_uncore_irp_enable_event,
+	.read_counter	= hswep_uncore_irp_read_counter,
+};
+
+static struct intel_uncore_type hswep_uncore_irp = {
+	.name			= "irp",
+	.num_counters		= 4,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.event_mask		= SNBEP_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCI_PMON_BOX_CTL,
+	.ops			= &hswep_uncore_irp_ops,
+	.format_group		= &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type hswep_uncore_qpi = {
+	.name			= "qpi",
+	.num_counters		= 5,
+	.num_boxes		= 3,
+	.perf_ctr_bits		= 48,
+	.perf_ctr		= SNBEP_PCI_PMON_CTR0,
+	.event_ctl		= SNBEP_PCI_PMON_CTL0,
+	.event_mask		= SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCI_PMON_BOX_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &snbep_uncore_qpi_ops,
+	.format_group		= &snbep_uncore_qpi_format_group,
+};
+
+static struct event_constraint hswep_uncore_r2pcie_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x23, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x24, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x25, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x27, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2a, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
+	EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type hswep_uncore_r2pcie = {
+	.name		= "r2pcie",
+	.num_counters   = 4,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 48,
+	.constraints	= hswep_uncore_r2pcie_constraints,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct event_constraint hswep_uncore_r3qpi_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x01, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x07, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x08, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x09, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x0a, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x0e, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x14, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x15, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x1f, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2f, 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),
+	UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+	EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type hswep_uncore_r3qpi = {
+	.name		= "r3qpi",
+	.num_counters   = 4,
+	.num_boxes	= 3,
+	.perf_ctr_bits	= 44,
+	.constraints	= hswep_uncore_r3qpi_constraints,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+	HSWEP_PCI_UNCORE_HA,
+	HSWEP_PCI_UNCORE_IMC,
+	HSWEP_PCI_UNCORE_IRP,
+	HSWEP_PCI_UNCORE_QPI,
+	HSWEP_PCI_UNCORE_R2PCIE,
+	HSWEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *hswep_pci_uncores[] = {
+	[HSWEP_PCI_UNCORE_HA]	= &hswep_uncore_ha,
+	[HSWEP_PCI_UNCORE_IMC]	= &hswep_uncore_imc,
+	[HSWEP_PCI_UNCORE_IRP]	= &hswep_uncore_irp,
+	[HSWEP_PCI_UNCORE_QPI]	= &hswep_uncore_qpi,
+	[HSWEP_PCI_UNCORE_R2PCIE]	= &hswep_uncore_r2pcie,
+	[HSWEP_PCI_UNCORE_R3QPI]	= &hswep_uncore_r3qpi,
+	NULL,
+};
+
+static const struct pci_device_id hswep_uncore_pci_ids[] = {
+	{ /* Home Agent 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f30),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_HA, 0),
+	},
+	{ /* Home Agent 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f38),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_HA, 1),
+	},
+	{ /* MC0 Channel 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb0),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 0),
+	},
+	{ /* MC0 Channel 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb1),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 1),
+	},
+	{ /* MC0 Channel 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb4),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 2),
+	},
+	{ /* MC0 Channel 3 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb5),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 3),
+	},
+	{ /* MC1 Channel 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd0),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 4),
+	},
+	{ /* MC1 Channel 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd1),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 5),
+	},
+	{ /* MC1 Channel 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd4),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 6),
+	},
+	{ /* MC1 Channel 3 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd5),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 7),
+	},
+	{ /* IRP */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f39),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IRP, 0),
+	},
+	{ /* QPI0 Port 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f32),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 0),
+	},
+	{ /* QPI0 Port 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f33),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 1),
+	},
+	{ /* QPI1 Port 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f3a),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 2),
+	},
+	{ /* R2PCIe */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f34),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R2PCIE, 0),
+	},
+	{ /* R3QPI0 Link 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f36),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 0),
+	},
+	{ /* R3QPI0 Link 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f37),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 1),
+	},
+	{ /* R3QPI1 Link 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f3e),
+		.driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 2),
+	},
+	{ /* QPI Port 0 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f86),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   SNBEP_PCI_QPI_PORT0_FILTER),
+	},
+	{ /* QPI Port 1 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f96),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   SNBEP_PCI_QPI_PORT1_FILTER),
+	},
+	{ /* PCU.3 (for Capability registers) */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fc0),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   HSWEP_PCI_PCU_3),
+	},
+	{ /* end: all zeroes */ }
+};
+
+static struct pci_driver hswep_uncore_pci_driver = {
+	.name		= "hswep_uncore",
+	.id_table	= hswep_uncore_pci_ids,
+};
+
+int hswep_uncore_pci_init(void)
+{
+	int ret = snbep_pci2phy_map_init(0x2f1e);
+	if (ret)
+		return ret;
+	uncore_pci_uncores = hswep_pci_uncores;
+	uncore_pci_driver = &hswep_uncore_pci_driver;
+	return 0;
+}
+/* end of Haswell-EP uncore support */
+
+/* BDX uncore support */
+
+static struct intel_uncore_type bdx_uncore_ubox = {
+	.name			= "ubox",
+	.num_counters		= 2,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.fixed_ctr_bits		= 48,
+	.perf_ctr		= HSWEP_U_MSR_PMON_CTR0,
+	.event_ctl		= HSWEP_U_MSR_PMON_CTL0,
+	.event_mask		= SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+	.fixed_ctr		= HSWEP_U_MSR_PMON_UCLK_FIXED_CTR,
+	.fixed_ctl		= HSWEP_U_MSR_PMON_UCLK_FIXED_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &ivbep_uncore_msr_ops,
+	.format_group		= &ivbep_uncore_ubox_format_group,
+};
+
+static struct event_constraint bdx_uncore_cbox_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x09, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x3e, 0x1),
+	EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type bdx_uncore_cbox = {
+	.name			= "cbox",
+	.num_counters		= 4,
+	.num_boxes		= 24,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= HSWEP_C0_MSR_PMON_CTL0,
+	.perf_ctr		= HSWEP_C0_MSR_PMON_CTR0,
+	.event_mask		= SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= HSWEP_C0_MSR_PMON_BOX_CTL,
+	.msr_offset		= HSWEP_CBO_MSR_OFFSET,
+	.num_shared_regs	= 1,
+	.constraints		= bdx_uncore_cbox_constraints,
+	.ops			= &hswep_uncore_cbox_ops,
+	.format_group		= &hswep_uncore_cbox_format_group,
+};
+
+static struct intel_uncore_type bdx_uncore_sbox = {
+	.name			= "sbox",
+	.num_counters		= 4,
+	.num_boxes		= 4,
+	.perf_ctr_bits		= 48,
+	.event_ctl		= HSWEP_S0_MSR_PMON_CTL0,
+	.perf_ctr		= HSWEP_S0_MSR_PMON_CTR0,
+	.event_mask		= HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl		= HSWEP_S0_MSR_PMON_BOX_CTL,
+	.msr_offset		= HSWEP_SBOX_MSR_OFFSET,
+	.ops			= &hswep_uncore_sbox_msr_ops,
+	.format_group		= &hswep_uncore_sbox_format_group,
+};
+
+static struct intel_uncore_type *bdx_msr_uncores[] = {
+	&bdx_uncore_ubox,
+	&bdx_uncore_cbox,
+	&bdx_uncore_sbox,
+	&hswep_uncore_pcu,
+	NULL,
+};
+
+void bdx_uncore_cpu_init(void)
+{
+	if (bdx_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+		bdx_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+	uncore_msr_uncores = bdx_msr_uncores;
+}
+
+static struct intel_uncore_type bdx_uncore_ha = {
+	.name		= "ha",
+	.num_counters   = 4,
+	.num_boxes	= 2,
+	.perf_ctr_bits	= 48,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type bdx_uncore_imc = {
+	.name		= "imc",
+	.num_counters   = 5,
+	.num_boxes	= 8,
+	.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	= hswep_uncore_imc_events,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type bdx_uncore_irp = {
+	.name			= "irp",
+	.num_counters		= 4,
+	.num_boxes		= 1,
+	.perf_ctr_bits		= 48,
+	.event_mask		= SNBEP_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCI_PMON_BOX_CTL,
+	.ops			= &hswep_uncore_irp_ops,
+	.format_group		= &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type bdx_uncore_qpi = {
+	.name			= "qpi",
+	.num_counters		= 4,
+	.num_boxes		= 3,
+	.perf_ctr_bits		= 48,
+	.perf_ctr		= SNBEP_PCI_PMON_CTR0,
+	.event_ctl		= SNBEP_PCI_PMON_CTL0,
+	.event_mask		= SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCI_PMON_BOX_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &snbep_uncore_qpi_ops,
+	.format_group		= &snbep_uncore_qpi_format_group,
+};
+
+static struct event_constraint bdx_uncore_r2pcie_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x23, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x25, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+	EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type bdx_uncore_r2pcie = {
+	.name		= "r2pcie",
+	.num_counters   = 4,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 48,
+	.constraints	= bdx_uncore_r2pcie_constraints,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct event_constraint bdx_uncore_r3qpi_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x01, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x07, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x08, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x09, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x0a, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x0e, 0x7),
+	UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x14, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x15, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x1f, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+	EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type bdx_uncore_r3qpi = {
+	.name		= "r3qpi",
+	.num_counters   = 3,
+	.num_boxes	= 3,
+	.perf_ctr_bits	= 48,
+	.constraints	= bdx_uncore_r3qpi_constraints,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+	BDX_PCI_UNCORE_HA,
+	BDX_PCI_UNCORE_IMC,
+	BDX_PCI_UNCORE_IRP,
+	BDX_PCI_UNCORE_QPI,
+	BDX_PCI_UNCORE_R2PCIE,
+	BDX_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *bdx_pci_uncores[] = {
+	[BDX_PCI_UNCORE_HA]	= &bdx_uncore_ha,
+	[BDX_PCI_UNCORE_IMC]	= &bdx_uncore_imc,
+	[BDX_PCI_UNCORE_IRP]	= &bdx_uncore_irp,
+	[BDX_PCI_UNCORE_QPI]	= &bdx_uncore_qpi,
+	[BDX_PCI_UNCORE_R2PCIE]	= &bdx_uncore_r2pcie,
+	[BDX_PCI_UNCORE_R3QPI]	= &bdx_uncore_r3qpi,
+	NULL,
+};
+
+static const struct pci_device_id bdx_uncore_pci_ids[] = {
+	{ /* Home Agent 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f30),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_HA, 0),
+	},
+	{ /* Home Agent 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f38),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_HA, 1),
+	},
+	{ /* MC0 Channel 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb0),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 0),
+	},
+	{ /* MC0 Channel 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb1),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 1),
+	},
+	{ /* MC0 Channel 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb4),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 2),
+	},
+	{ /* MC0 Channel 3 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb5),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 3),
+	},
+	{ /* MC1 Channel 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd0),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 4),
+	},
+	{ /* MC1 Channel 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd1),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 5),
+	},
+	{ /* MC1 Channel 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd4),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 6),
+	},
+	{ /* MC1 Channel 3 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd5),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 7),
+	},
+	{ /* IRP */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f39),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IRP, 0),
+	},
+	{ /* QPI0 Port 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f32),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 0),
+	},
+	{ /* QPI0 Port 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f33),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 1),
+	},
+	{ /* QPI1 Port 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f3a),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 2),
+	},
+	{ /* R2PCIe */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f34),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R2PCIE, 0),
+	},
+	{ /* R3QPI0 Link 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f36),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 0),
+	},
+	{ /* R3QPI0 Link 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f37),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 1),
+	},
+	{ /* R3QPI1 Link 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f3e),
+		.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 2),
+	},
+	{ /* QPI Port 0 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f86),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 0),
+	},
+	{ /* QPI Port 1 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f96),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 1),
+	},
+	{ /* QPI Port 2 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f46),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 2),
+	},
+	{ /* end: all zeroes */ }
+};
+
+static struct pci_driver bdx_uncore_pci_driver = {
+	.name		= "bdx_uncore",
+	.id_table	= bdx_uncore_pci_ids,
+};
+
+int bdx_uncore_pci_init(void)
+{
+	int ret = snbep_pci2phy_map_init(0x6f1e);
+
+	if (ret)
+		return ret;
+	uncore_pci_uncores = bdx_pci_uncores;
+	uncore_pci_driver = &bdx_uncore_pci_driver;
+	return 0;
+}
+
+/* end of BDX uncore support */
--- linux-4.4.0.orig/arch/x86/events/msr.c
+++ linux-4.4.0/arch/x86/events/msr.c
@@ -0,0 +1,257 @@
+#include <linux/perf_event.h>
+#include <linux/nospec.h>
+#include <asm/intel-family.h>
+
+enum perf_msr_id {
+	PERF_MSR_TSC			= 0,
+	PERF_MSR_APERF			= 1,
+	PERF_MSR_MPERF			= 2,
+	PERF_MSR_PPERF			= 3,
+	PERF_MSR_SMI			= 4,
+
+	PERF_MSR_EVENT_MAX,
+};
+
+static bool test_aperfmperf(int idx)
+{
+	return boot_cpu_has(X86_FEATURE_APERFMPERF);
+}
+
+static bool test_intel(int idx)
+{
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
+	    boot_cpu_data.x86 != 6)
+		return false;
+
+	switch (boot_cpu_data.x86_model) {
+	case INTEL_FAM6_NEHALEM:
+	case INTEL_FAM6_NEHALEM_EP:
+	case INTEL_FAM6_NEHALEM_EX:
+
+	case INTEL_FAM6_WESTMERE:
+	case INTEL_FAM6_WESTMERE2:
+	case INTEL_FAM6_WESTMERE_EP:
+	case INTEL_FAM6_WESTMERE_EX:
+
+	case INTEL_FAM6_SANDYBRIDGE:
+	case INTEL_FAM6_SANDYBRIDGE_X:
+
+	case INTEL_FAM6_IVYBRIDGE:
+	case INTEL_FAM6_IVYBRIDGE_X:
+
+	case INTEL_FAM6_HASWELL_CORE:
+	case INTEL_FAM6_HASWELL_X:
+	case INTEL_FAM6_HASWELL_ULT:
+	case INTEL_FAM6_HASWELL_GT3E:
+
+	case INTEL_FAM6_BROADWELL_CORE:
+	case INTEL_FAM6_BROADWELL_XEON_D:
+	case INTEL_FAM6_BROADWELL_GT3E:
+	case INTEL_FAM6_BROADWELL_X:
+
+	case INTEL_FAM6_ATOM_SILVERMONT:
+	case INTEL_FAM6_ATOM_SILVERMONT_X:
+	case INTEL_FAM6_ATOM_AIRMONT:
+
+	case INTEL_FAM6_ATOM_GOLDMONT:
+	case INTEL_FAM6_ATOM_GOLDMONT_X:
+
+	case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
+
+	case INTEL_FAM6_XEON_PHI_KNL:
+	case INTEL_FAM6_XEON_PHI_KNM:
+		if (idx == PERF_MSR_SMI)
+			return true;
+		break;
+
+	case INTEL_FAM6_SKYLAKE_MOBILE:
+	case INTEL_FAM6_SKYLAKE_DESKTOP:
+	case INTEL_FAM6_SKYLAKE_X:
+	case INTEL_FAM6_KABYLAKE_MOBILE:
+	case INTEL_FAM6_KABYLAKE_DESKTOP:
+		if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF)
+			return true;
+		break;
+	}
+
+	return false;
+}
+
+struct perf_msr {
+	u64	msr;
+	struct	perf_pmu_events_attr *attr;
+	bool	(*test)(int idx);
+};
+
+PMU_EVENT_ATTR_STRING(tsc,   evattr_tsc,   "event=0x00");
+PMU_EVENT_ATTR_STRING(aperf, evattr_aperf, "event=0x01");
+PMU_EVENT_ATTR_STRING(mperf, evattr_mperf, "event=0x02");
+PMU_EVENT_ATTR_STRING(pperf, evattr_pperf, "event=0x03");
+PMU_EVENT_ATTR_STRING(smi,   evattr_smi,   "event=0x04");
+
+static struct perf_msr msr[] = {
+	[PERF_MSR_TSC]   = { 0,			&evattr_tsc,	NULL,		 },
+	[PERF_MSR_APERF] = { MSR_IA32_APERF,	&evattr_aperf,	test_aperfmperf, },
+	[PERF_MSR_MPERF] = { MSR_IA32_MPERF,	&evattr_mperf,	test_aperfmperf, },
+	[PERF_MSR_PPERF] = { MSR_PPERF,		&evattr_pperf,	test_intel,	 },
+	[PERF_MSR_SMI]   = { MSR_SMI_COUNT,	&evattr_smi,	test_intel,	 },
+};
+
+static struct attribute *events_attrs[PERF_MSR_EVENT_MAX + 1] = {
+	NULL,
+};
+
+static struct attribute_group events_attr_group = {
+	.name = "events",
+	.attrs = events_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-63");
+static struct attribute *format_attrs[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+static struct attribute_group format_attr_group = {
+	.name = "format",
+	.attrs = format_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+	&events_attr_group,
+	&format_attr_group,
+	NULL,
+};
+
+static int msr_event_init(struct perf_event *event)
+{
+	u64 cfg = event->attr.config;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/* unsupported modes and filters */
+	if (event->attr.exclude_user   ||
+	    event->attr.exclude_kernel ||
+	    event->attr.exclude_hv     ||
+	    event->attr.exclude_idle   ||
+	    event->attr.exclude_host   ||
+	    event->attr.exclude_guest  ||
+	    event->attr.sample_period) /* no sampling */
+		return -EINVAL;
+
+	if (cfg >= PERF_MSR_EVENT_MAX)
+		return -EINVAL;
+
+	cfg = array_index_nospec((unsigned long)cfg, PERF_MSR_EVENT_MAX);
+
+	if (!msr[cfg].attr)
+		return -EINVAL;
+
+	event->hw.idx = -1;
+	event->hw.event_base = msr[cfg].msr;
+	event->hw.config = cfg;
+
+	return 0;
+}
+
+static inline u64 msr_read_counter(struct perf_event *event)
+{
+	u64 now;
+
+	if (event->hw.event_base)
+		rdmsrl(event->hw.event_base, now);
+	else
+		rdtscll(now);
+
+	return now;
+}
+static void msr_event_update(struct perf_event *event)
+{
+	u64 prev, now;
+	s64 delta;
+
+	/* Careful, an NMI might modify the previous event value. */
+again:
+	prev = local64_read(&event->hw.prev_count);
+	now = msr_read_counter(event);
+
+	if (local64_cmpxchg(&event->hw.prev_count, prev, now) != prev)
+		goto again;
+
+	delta = now - prev;
+	if (unlikely(event->hw.event_base == MSR_SMI_COUNT))
+		delta = sign_extend64(delta, 31);
+
+	local64_add(now - prev, &event->count);
+}
+
+static void msr_event_start(struct perf_event *event, int flags)
+{
+	u64 now;
+
+	now = msr_read_counter(event);
+	local64_set(&event->hw.prev_count, now);
+}
+
+static void msr_event_stop(struct perf_event *event, int flags)
+{
+	msr_event_update(event);
+}
+
+static void msr_event_del(struct perf_event *event, int flags)
+{
+	msr_event_stop(event, PERF_EF_UPDATE);
+}
+
+static int msr_event_add(struct perf_event *event, int flags)
+{
+	if (flags & PERF_EF_START)
+		msr_event_start(event, flags);
+
+	return 0;
+}
+
+static struct pmu pmu_msr = {
+	.task_ctx_nr	= perf_sw_context,
+	.attr_groups	= attr_groups,
+	.event_init	= msr_event_init,
+	.add		= msr_event_add,
+	.del		= msr_event_del,
+	.start		= msr_event_start,
+	.stop		= msr_event_stop,
+	.read		= msr_event_update,
+	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+};
+
+static int __init msr_init(void)
+{
+	int i, j = 0;
+
+	if (!boot_cpu_has(X86_FEATURE_TSC)) {
+		pr_cont("no MSR PMU driver.\n");
+		return 0;
+	}
+
+	/* Probe the MSRs. */
+	for (i = PERF_MSR_TSC + 1; i < PERF_MSR_EVENT_MAX; i++) {
+		u64 val;
+
+		/*
+		 * Virt sucks arse; you cannot tell if a R/O MSR is present :/
+		 */
+		if (!msr[i].test(i) || rdmsrl_safe(msr[i].msr, &val))
+			msr[i].attr = NULL;
+	}
+
+	/* List remaining MSRs in the sysfs attrs. */
+	for (i = 0; i < PERF_MSR_EVENT_MAX; i++) {
+		if (msr[i].attr)
+			events_attrs[j++] = &msr[i].attr->attr.attr;
+	}
+	events_attrs[j] = NULL;
+
+	perf_pmu_register(&pmu_msr, "msr", -1);
+
+	return 0;
+}
+device_initcall(msr_init);
--- linux-4.4.0.orig/arch/x86/events/perf_event.h
+++ linux-4.4.0/arch/x86/events/perf_event.h
@@ -0,0 +1,963 @@
+/*
+ * Performance events x86 architecture header
+ *
+ *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
+ *  Copyright (C) 2009 Jaswinder Singh Rajput
+ *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
+ *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
+ *  Copyright (C) 2009 Google, Inc., Stephane Eranian
+ *
+ *  For licencing details see kernel-base/COPYING
+ */
+
+#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 -------------------------------
+ *          |  HT  | no HT |  HT  | no HT |
+ *-----------------------------------------
+ * offcore  | core | core  | cpu  | core  |
+ * lbr_sel  | core | core  | cpu  | core  |
+ * ld_lat   | cpu  | core  | cpu  | core  |
+ *-----------------------------------------
+ *
+ * Given that there is a small number of shared regs,
+ * we can pre-allocate their slot in the per-cpu
+ * per-core reg tables.
+ */
+enum extra_reg_type {
+	EXTRA_REG_NONE  = -1,	/* not used */
+
+	EXTRA_REG_RSP_0 = 0,	/* offcore_response_0 */
+	EXTRA_REG_RSP_1 = 1,	/* offcore_response_1 */
+	EXTRA_REG_LBR   = 2,	/* lbr_select */
+	EXTRA_REG_LDLAT = 3,	/* ld_lat_threshold */
+	EXTRA_REG_FE    = 4,    /* fe_* */
+
+	EXTRA_REG_MAX		/* number of entries needed */
+};
+
+struct event_constraint {
+	union {
+		unsigned long	idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+		u64		idxmsk64;
+	};
+	u64	code;
+	u64	cmask;
+	int	weight;
+	int	overlap;
+	int	flags;
+};
+/*
+ * struct hw_perf_event.flags flags
+ */
+#define PERF_X86_EVENT_PEBS_LDLAT	0x0001 /* ld+ldlat data address sampling */
+#define PERF_X86_EVENT_PEBS_ST		0x0002 /* st data address sampling */
+#define PERF_X86_EVENT_PEBS_ST_HSW	0x0004 /* haswell style datala, store */
+#define PERF_X86_EVENT_COMMITTED	0x0008 /* event passed commit_txn */
+#define PERF_X86_EVENT_PEBS_LD_HSW	0x0010 /* haswell style datala, load */
+#define PERF_X86_EVENT_PEBS_NA_HSW	0x0020 /* haswell style datala, unknown */
+#define PERF_X86_EVENT_EXCL		0x0040 /* HT exclusivity on counter */
+#define PERF_X86_EVENT_DYNAMIC		0x0080 /* dynamic alloc'd constraint */
+#define PERF_X86_EVENT_RDPMC_ALLOWED	0x0100 /* grant rdpmc permission */
+#define PERF_X86_EVENT_EXCL_ACCT	0x0200 /* accounted EXCL event */
+#define PERF_X86_EVENT_AUTO_RELOAD	0x0400 /* use PEBS auto-reload */
+#define PERF_X86_EVENT_FREERUNNING	0x0800 /* use freerunning PEBS */
+
+
+struct amd_nb {
+	int nb_id;  /* NorthBridge id */
+	int refcnt; /* reference count */
+	struct perf_event *owners[X86_PMC_IDX_MAX];
+	struct event_constraint event_constraints[X86_PMC_IDX_MAX];
+};
+
+/* The maximal number of PEBS events: */
+#define MAX_PEBS_EVENTS		8
+
+/*
+ * Flags PEBS can handle without an PMI.
+ *
+ * TID can only be handled by flushing at context switch.
+ *
+ */
+#define PEBS_FREERUNNING_FLAGS \
+	(PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR | \
+	PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID | \
+	PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | \
+	PERF_SAMPLE_TRANSACTION)
+
+/*
+ * A debug store configuration.
+ *
+ * We only support architectures that use 64bit fields.
+ */
+struct debug_store {
+	u64	bts_buffer_base;
+	u64	bts_index;
+	u64	bts_absolute_maximum;
+	u64	bts_interrupt_threshold;
+	u64	pebs_buffer_base;
+	u64	pebs_index;
+	u64	pebs_absolute_maximum;
+	u64	pebs_interrupt_threshold;
+	u64	pebs_event_reset[MAX_PEBS_EVENTS];
+};
+
+/*
+ * Per register state.
+ */
+struct er_account {
+	raw_spinlock_t		lock;	/* per-core: protect structure */
+	u64                 config;	/* extra MSR config */
+	u64                 reg;	/* extra MSR number */
+	atomic_t            ref;	/* reference count */
+};
+
+/*
+ * Per core/cpu state
+ *
+ * Used to coordinate shared registers between HT threads or
+ * among events on a single PMU.
+ */
+struct intel_shared_regs {
+	struct er_account       regs[EXTRA_REG_MAX];
+	int                     refcnt;		/* per-core: #HT threads */
+	unsigned                core_id;	/* per-core: core id */
+};
+
+enum intel_excl_state_type {
+	INTEL_EXCL_UNUSED    = 0, /* counter is unused */
+	INTEL_EXCL_SHARED    = 1, /* counter can be used by both threads */
+	INTEL_EXCL_EXCLUSIVE = 2, /* counter can be used by one thread only */
+};
+
+struct intel_excl_states {
+	enum intel_excl_state_type state[X86_PMC_IDX_MAX];
+	bool sched_started; /* true if scheduling has started */
+};
+
+struct intel_excl_cntrs {
+	raw_spinlock_t	lock;
+
+	struct intel_excl_states states[2];
+
+	union {
+		u16	has_exclusive[2];
+		u32	exclusive_present;
+	};
+
+	int		refcnt;		/* per-core: #HT threads */
+	unsigned	core_id;	/* per-core: core id */
+};
+
+#define MAX_LBR_ENTRIES		32
+
+enum {
+	X86_PERF_KFREE_SHARED = 0,
+	X86_PERF_KFREE_EXCL   = 1,
+	X86_PERF_KFREE_MAX
+};
+
+struct cpu_hw_events {
+	/*
+	 * Generic x86 PMC bits
+	 */
+	struct perf_event	*events[X86_PMC_IDX_MAX]; /* in counter order */
+	unsigned long		active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	unsigned long		running[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	int			enabled;
+
+	int			n_events; /* the # of events in the below arrays */
+	int			n_added;  /* the # last events in the below arrays;
+					     they've never been enabled yet */
+	int			n_txn;    /* the # last events in the below arrays;
+					     added in the current transaction */
+	int			assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
+	u64			tags[X86_PMC_IDX_MAX];
+
+	struct perf_event	*event_list[X86_PMC_IDX_MAX]; /* in enabled order */
+	struct event_constraint	*event_constraint[X86_PMC_IDX_MAX];
+
+	int			n_excl; /* the number of exclusive events */
+
+	unsigned int		txn_flags;
+	int			is_fake;
+
+	/*
+	 * Intel DebugStore bits
+	 */
+	struct debug_store	*ds;
+	u64			pebs_enabled;
+
+	/*
+	 * Intel LBR bits
+	 */
+	int				lbr_users;
+	void				*lbr_context;
+	struct perf_branch_stack	lbr_stack;
+	struct perf_branch_entry	lbr_entries[MAX_LBR_ENTRIES];
+	struct er_account		*lbr_sel;
+	u64				br_sel;
+
+	/*
+	 * Intel host/guest exclude bits
+	 */
+	u64				intel_ctrl_guest_mask;
+	u64				intel_ctrl_host_mask;
+	struct perf_guest_switch_msr	guest_switch_msrs[X86_PMC_IDX_MAX];
+
+	/*
+	 * Intel checkpoint mask
+	 */
+	u64				intel_cp_status;
+
+	/*
+	 * manage shared (per-core, per-cpu) registers
+	 * used on Intel NHM/WSM/SNB
+	 */
+	struct intel_shared_regs	*shared_regs;
+	/*
+	 * manage exclusive counter access between hyperthread
+	 */
+	struct event_constraint *constraint_list; /* in enable order */
+	struct intel_excl_cntrs		*excl_cntrs;
+	int excl_thread_id; /* 0 or 1 */
+
+	/*
+	 * AMD specific bits
+	 */
+	struct amd_nb			*amd_nb;
+	/* Inverted mask of bits to clear in the perf_ctr ctrl registers */
+	u64				perf_ctr_virt_mask;
+
+	void				*kfree_on_online[X86_PERF_KFREE_MAX];
+};
+
+#define __EVENT_CONSTRAINT(c, n, m, w, o, f) {\
+	{ .idxmsk64 = (n) },		\
+	.code = (c),			\
+	.cmask = (m),			\
+	.weight = (w),			\
+	.overlap = (o),			\
+	.flags = f,			\
+}
+
+#define EVENT_CONSTRAINT(c, n, m)	\
+	__EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0, 0)
+
+#define INTEL_EXCLEVT_CONSTRAINT(c, n)	\
+	__EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT, HWEIGHT(n),\
+			   0, PERF_X86_EVENT_EXCL)
+
+/*
+ * The overlap flag marks event constraints with overlapping counter
+ * masks. This is the case if the counter mask of such an event is not
+ * a subset of any other counter mask of a constraint with an equal or
+ * higher weight, e.g.:
+ *
+ *  c_overlaps = EVENT_CONSTRAINT_OVERLAP(0, 0x09, 0);
+ *  c_another1 = EVENT_CONSTRAINT(0, 0x07, 0);
+ *  c_another2 = EVENT_CONSTRAINT(0, 0x38, 0);
+ *
+ * The event scheduler may not select the correct counter in the first
+ * cycle because it needs to know which subsequent events will be
+ * scheduled. It may fail to schedule the events then. So we set the
+ * overlap flag for such constraints to give the scheduler a hint which
+ * events to select for counter rescheduling.
+ *
+ * Care must be taken as the rescheduling algorithm is O(n!) which
+ * will increase scheduling cycles for an over-commited system
+ * dramatically.  The number of such EVENT_CONSTRAINT_OVERLAP() macros
+ * and its counter masks must be kept at a minimum.
+ */
+#define EVENT_CONSTRAINT_OVERLAP(c, n, m)	\
+	__EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 1, 0)
+
+/*
+ * Constraint on the Event code.
+ */
+#define INTEL_EVENT_CONSTRAINT(c, n)	\
+	EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT)
+
+/*
+ * Constraint on the Event code + UMask + fixed-mask
+ *
+ * filter mask to validate fixed counter events.
+ * the following filters disqualify for fixed counters:
+ *  - inv
+ *  - edge
+ *  - cnt-mask
+ *  - in_tx
+ *  - in_tx_checkpointed
+ *  The other filters are supported by fixed counters.
+ *  The any-thread option is supported starting with v3.
+ */
+#define FIXED_EVENT_FLAGS (X86_RAW_EVENT_MASK|HSW_IN_TX|HSW_IN_TX_CHECKPOINTED)
+#define FIXED_EVENT_CONSTRAINT(c, n)	\
+	EVENT_CONSTRAINT(c, (1ULL << (32+n)), FIXED_EVENT_FLAGS)
+
+/*
+ * Constraint on the Event code + UMask
+ */
+#define INTEL_UEVENT_CONSTRAINT(c, n)	\
+	EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
+
+/* Like UEVENT_CONSTRAINT, but match flags too */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT(c, n)	\
+	EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
+
+#define INTEL_EXCLUEVT_CONSTRAINT(c, n)	\
+	__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+			   HWEIGHT(n), 0, PERF_X86_EVENT_EXCL)
+
+#define INTEL_PLD_CONSTRAINT(c, n)	\
+	__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+			   HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT)
+
+#define INTEL_PST_CONSTRAINT(c, n)	\
+	__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST)
+
+/* Event constraint, but match on all event flags too. */
+#define INTEL_FLAGS_EVENT_CONSTRAINT(c, n) \
+	EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
+
+/* Check only flags, but allow all event/umask */
+#define INTEL_ALL_EVENT_CONSTRAINT(code, n)	\
+	EVENT_CONSTRAINT(code, n, X86_ALL_EVENT_FLAGS)
+
+/* Check flags and event code, and set the HSW store flag */
+#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_ST(code, n) \
+	__EVENT_CONSTRAINT(code, n, 			\
+			  ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW)
+
+/* Check flags and event code, and set the HSW load flag */
+#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(code, n) \
+	__EVENT_CONSTRAINT(code, n,			\
+			  ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW)
+
+#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD(code, n) \
+	__EVENT_CONSTRAINT(code, n,			\
+			  ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, \
+			  PERF_X86_EVENT_PEBS_LD_HSW|PERF_X86_EVENT_EXCL)
+
+/* Check flags and event code/umask, and set the HSW store flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(code, n) \
+	__EVENT_CONSTRAINT(code, n, 			\
+			  INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW)
+
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST(code, n) \
+	__EVENT_CONSTRAINT(code, n,			\
+			  INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, \
+			  PERF_X86_EVENT_PEBS_ST_HSW|PERF_X86_EVENT_EXCL)
+
+/* Check flags and event code/umask, and set the HSW load flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(code, n) \
+	__EVENT_CONSTRAINT(code, n, 			\
+			  INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW)
+
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(code, n) \
+	__EVENT_CONSTRAINT(code, n,			\
+			  INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, \
+			  PERF_X86_EVENT_PEBS_LD_HSW|PERF_X86_EVENT_EXCL)
+
+/* Check flags and event code/umask, and set the HSW N/A flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(code, n) \
+	__EVENT_CONSTRAINT(code, n, 			\
+			  INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+			  HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_NA_HSW)
+
+
+/*
+ * We define the end marker as having a weight of -1
+ * to enable blacklisting of events using a counter bitmask
+ * of zero and thus a weight of zero.
+ * The end marker has a weight that cannot possibly be
+ * obtained from counting the bits in the bitmask.
+ */
+#define EVENT_CONSTRAINT_END { .weight = -1 }
+
+/*
+ * Check for end marker with weight == -1
+ */
+#define for_each_event_constraint(e, c)	\
+	for ((e) = (c); (e)->weight != -1; (e)++)
+
+/*
+ * Extra registers for specific events.
+ *
+ * Some events need large masks and require external MSRs.
+ * Those extra MSRs end up being shared for all events on
+ * a PMU and sometimes between PMU of sibling HT threads.
+ * In either case, the kernel needs to handle conflicting
+ * accesses to those extra, shared, regs. The data structure
+ * to manage those registers is stored in cpu_hw_event.
+ */
+struct extra_reg {
+	unsigned int		event;
+	unsigned int		msr;
+	u64			config_mask;
+	u64			valid_mask;
+	int			idx;  /* per_xxx->regs[] reg index */
+	bool			extra_msr_access;
+};
+
+#define EVENT_EXTRA_REG(e, ms, m, vm, i) {	\
+	.event = (e),			\
+	.msr = (ms),			\
+	.config_mask = (m),		\
+	.valid_mask = (vm),		\
+	.idx = EXTRA_REG_##i,		\
+	.extra_msr_access = true,	\
+	}
+
+#define INTEL_EVENT_EXTRA_REG(event, msr, vm, idx)	\
+	EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT, vm, idx)
+
+#define INTEL_UEVENT_EXTRA_REG(event, msr, vm, idx) \
+	EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT | \
+			ARCH_PERFMON_EVENTSEL_UMASK, vm, idx)
+
+#define INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(c) \
+	INTEL_UEVENT_EXTRA_REG(c, \
+			       MSR_PEBS_LD_LAT_THRESHOLD, \
+			       0xffff, \
+			       LDLAT)
+
+#define EVENT_EXTRA_END EVENT_EXTRA_REG(0, 0, 0, 0, RSP_0)
+
+union perf_capabilities {
+	struct {
+		u64	lbr_format:6;
+		u64	pebs_trap:1;
+		u64	pebs_arch_reg:1;
+		u64	pebs_format:4;
+		u64	smm_freeze:1;
+		/*
+		 * PMU supports separate counter range for writing
+		 * values > 32bit.
+		 */
+		u64	full_width_write:1;
+	};
+	u64	capabilities;
+};
+
+struct x86_pmu_quirk {
+	struct x86_pmu_quirk *next;
+	void (*func)(void);
+};
+
+union x86_pmu_config {
+	struct {
+		u64 event:8,
+		    umask:8,
+		    usr:1,
+		    os:1,
+		    edge:1,
+		    pc:1,
+		    interrupt:1,
+		    __reserved1:1,
+		    en:1,
+		    inv:1,
+		    cmask:8,
+		    event2:4,
+		    __reserved2:4,
+		    go:1,
+		    ho:1;
+	} bits;
+	u64 value;
+};
+
+#define X86_CONFIG(args...) ((union x86_pmu_config){.bits = {args}}).value
+
+enum {
+	x86_lbr_exclusive_lbr,
+	x86_lbr_exclusive_bts,
+	x86_lbr_exclusive_pt,
+	x86_lbr_exclusive_max,
+};
+
+/*
+ * struct x86_pmu - generic x86 pmu
+ */
+struct x86_pmu {
+	/*
+	 * Generic x86 PMC bits
+	 */
+	const char	*name;
+	int		version;
+	int		(*handle_irq)(struct pt_regs *);
+	void		(*disable_all)(void);
+	void		(*enable_all)(int added);
+	void		(*enable)(struct perf_event *);
+	void		(*disable)(struct perf_event *);
+	int		(*hw_config)(struct perf_event *event);
+	int		(*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign);
+	unsigned	eventsel;
+	unsigned	perfctr;
+	int		(*addr_offset)(int index, bool eventsel);
+	int		(*rdpmc_index)(int index);
+	u64		(*event_map)(int);
+	int		max_events;
+	int		num_counters;
+	int		num_counters_fixed;
+	int		cntval_bits;
+	u64		cntval_mask;
+	union {
+			unsigned long events_maskl;
+			unsigned long events_mask[BITS_TO_LONGS(ARCH_PERFMON_EVENTS_COUNT)];
+	};
+	int		events_mask_len;
+	int		apic;
+	u64		max_period;
+	struct event_constraint *
+			(*get_event_constraints)(struct cpu_hw_events *cpuc,
+						 int idx,
+						 struct perf_event *event);
+
+	void		(*put_event_constraints)(struct cpu_hw_events *cpuc,
+						 struct perf_event *event);
+
+	void		(*start_scheduling)(struct cpu_hw_events *cpuc);
+
+	void		(*commit_scheduling)(struct cpu_hw_events *cpuc, int idx, int cntr);
+
+	void		(*stop_scheduling)(struct cpu_hw_events *cpuc);
+
+	struct event_constraint *event_constraints;
+	struct x86_pmu_quirk *quirks;
+	int		perfctr_second_write;
+	bool		late_ack;
+	unsigned	(*limit_period)(struct perf_event *event, unsigned l);
+
+	/*
+	 * sysfs attrs
+	 */
+	int		attr_rdpmc_broken;
+	int		attr_rdpmc;
+	struct attribute **format_attrs;
+	struct attribute **event_attrs;
+
+	ssize_t		(*events_sysfs_show)(char *page, u64 config);
+	struct attribute **cpu_events;
+
+	/*
+	 * CPU Hotplug hooks
+	 */
+	int		(*cpu_prepare)(int cpu);
+	void		(*cpu_starting)(int cpu);
+	void		(*cpu_dying)(int cpu);
+	void		(*cpu_dead)(int cpu);
+
+	void		(*check_microcode)(void);
+	void		(*sched_task)(struct perf_event_context *ctx,
+				      bool sched_in);
+
+	/*
+	 * Intel Arch Perfmon v2+
+	 */
+	u64			intel_ctrl;
+	union perf_capabilities intel_cap;
+
+	/*
+	 * Intel DebugStore bits
+	 */
+	unsigned int	bts		:1,
+			bts_active	:1,
+			pebs		:1,
+			pebs_active	:1,
+			pebs_broken	:1;
+	int		pebs_record_size;
+	int		pebs_buffer_size;
+	void		(*drain_pebs)(struct pt_regs *regs);
+	struct event_constraint *pebs_constraints;
+	void		(*pebs_aliases)(struct perf_event *event);
+	int 		max_pebs_events;
+	unsigned long	free_running_flags;
+
+	/*
+	 * Intel LBR
+	 */
+	unsigned long	lbr_tos, lbr_from, lbr_to; /* MSR base regs       */
+	int		lbr_nr;			   /* hardware stack size */
+	u64		lbr_sel_mask;		   /* LBR_SELECT valid bits */
+	const int	*lbr_sel_map;		   /* lbr_select mappings */
+	bool		lbr_double_abort;	   /* duplicated lbr aborts */
+
+	/*
+	 * Intel PT/LBR/BTS are exclusive
+	 */
+	atomic_t	lbr_exclusive[x86_lbr_exclusive_max];
+
+	/*
+	 * Extra registers for events
+	 */
+	struct extra_reg *extra_regs;
+	unsigned int flags;
+
+	/*
+	 * Intel host/guest support (KVM)
+	 */
+	struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr);
+};
+
+struct x86_perf_task_context {
+	u64 lbr_from[MAX_LBR_ENTRIES];
+	u64 lbr_to[MAX_LBR_ENTRIES];
+	u64 lbr_info[MAX_LBR_ENTRIES];
+	int tos;
+	int lbr_callstack_users;
+	int lbr_stack_state;
+};
+
+#define x86_add_quirk(func_)						\
+do {									\
+	static struct x86_pmu_quirk __quirk __initdata = {		\
+		.func = func_,						\
+	};								\
+	__quirk.next = x86_pmu.quirks;					\
+	x86_pmu.quirks = &__quirk;					\
+} while (0)
+
+/*
+ * x86_pmu flags
+ */
+#define PMU_FL_NO_HT_SHARING	0x1 /* no hyper-threading resource sharing */
+#define PMU_FL_HAS_RSP_1	0x2 /* has 2 equivalent offcore_rsp regs   */
+#define PMU_FL_EXCL_CNTRS	0x4 /* has exclusive counter requirements  */
+#define PMU_FL_EXCL_ENABLED	0x8 /* exclusive counter active */
+
+#define EVENT_VAR(_id)  event_attr_##_id
+#define EVENT_PTR(_id) &event_attr_##_id.attr.attr
+
+#define EVENT_ATTR(_name, _id)						\
+static struct perf_pmu_events_attr EVENT_VAR(_id) = {			\
+	.attr		= __ATTR(_name, 0444, events_sysfs_show, NULL),	\
+	.id		= PERF_COUNT_HW_##_id,				\
+	.event_str	= NULL,						\
+};
+
+#define EVENT_ATTR_STR(_name, v, str)					\
+static struct perf_pmu_events_attr event_attr_##v = {			\
+	.attr		= __ATTR(_name, 0444, events_sysfs_show, NULL),	\
+	.id		= 0,						\
+	.event_str	= str,						\
+};
+
+extern struct x86_pmu x86_pmu __read_mostly;
+
+static inline bool x86_pmu_has_lbr_callstack(void)
+{
+	return  x86_pmu.lbr_sel_map &&
+		x86_pmu.lbr_sel_map[PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT] > 0;
+}
+
+DECLARE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+int x86_perf_event_set_period(struct perf_event *event);
+
+/*
+ * Generalized hw caching related hw_event table, filled
+ * in on a per model basis. A value of 0 means
+ * 'not supported', -1 means 'hw_event makes no sense on
+ * this CPU', any other value means the raw hw_event
+ * ID.
+ */
+
+#define C(x) PERF_COUNT_HW_CACHE_##x
+
+extern u64 __read_mostly hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX];
+extern u64 __read_mostly hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX];
+
+u64 x86_perf_event_update(struct perf_event *event);
+
+static inline unsigned int x86_pmu_config_addr(int index)
+{
+	return x86_pmu.eventsel + (x86_pmu.addr_offset ?
+				   x86_pmu.addr_offset(index, true) : index);
+}
+
+static inline unsigned int x86_pmu_event_addr(int index)
+{
+	return x86_pmu.perfctr + (x86_pmu.addr_offset ?
+				  x86_pmu.addr_offset(index, false) : index);
+}
+
+static inline int x86_pmu_rdpmc_index(int index)
+{
+	return x86_pmu.rdpmc_index ? x86_pmu.rdpmc_index(index) : index;
+}
+
+int x86_add_exclusive(unsigned int what);
+
+void x86_del_exclusive(unsigned int what);
+
+int x86_reserve_hardware(void);
+
+void x86_release_hardware(void);
+
+void hw_perf_lbr_event_destroy(struct perf_event *event);
+
+int x86_setup_perfctr(struct perf_event *event);
+
+int x86_pmu_hw_config(struct perf_event *event);
+
+void x86_pmu_disable_all(void);
+
+static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
+					  u64 enable_mask)
+{
+	u64 disable_mask = __this_cpu_read(cpu_hw_events.perf_ctr_virt_mask);
+
+	if (hwc->extra_reg.reg)
+		wrmsrl(hwc->extra_reg.reg, hwc->extra_reg.config);
+	wrmsrl(hwc->config_base, (hwc->config | enable_mask) & ~disable_mask);
+}
+
+void x86_pmu_enable_all(int added);
+
+int perf_assign_events(struct event_constraint **constraints, int n,
+			int wmin, int wmax, int gpmax, 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);
+
+static inline void x86_pmu_disable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	wrmsrl(hwc->config_base, hwc->config);
+}
+
+void x86_pmu_enable_event(struct perf_event *event);
+
+int x86_pmu_handle_irq(struct pt_regs *regs);
+
+extern struct event_constraint emptyconstraint;
+
+extern struct event_constraint unconstrained;
+
+static inline bool kernel_ip(unsigned long ip)
+{
+#ifdef CONFIG_X86_32
+	return ip > PAGE_OFFSET;
+#else
+	return (long)ip < 0;
+#endif
+}
+
+/*
+ * Not all PMUs provide the right context information to place the reported IP
+ * into full context. Specifically segment registers are typically not
+ * supplied.
+ *
+ * Assuming the address is a linear address (it is for IBS), we fake the CS and
+ * vm86 mode using the known zero-based code segment and 'fix up' the registers
+ * to reflect this.
+ *
+ * Intel PEBS/LBR appear to typically provide the effective address, nothing
+ * much we can do about that but pray and treat it like a linear address.
+ */
+static inline void set_linear_ip(struct pt_regs *regs, unsigned long ip)
+{
+	regs->cs = kernel_ip(ip) ? __KERNEL_CS : __USER_CS;
+	if (regs->flags & X86_VM_MASK)
+		regs->flags ^= (PERF_EFLAGS_VM | X86_VM_MASK);
+	regs->ip = ip;
+}
+
+ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event);
+ssize_t intel_event_sysfs_show(char *page, u64 config);
+
+struct attribute **merge_attr(struct attribute **a, struct attribute **b);
+
+#ifdef CONFIG_CPU_SUP_AMD
+
+int amd_pmu_init(void);
+
+#else /* CONFIG_CPU_SUP_AMD */
+
+static inline int amd_pmu_init(void)
+{
+	return 0;
+}
+
+#endif /* CONFIG_CPU_SUP_AMD */
+
+#ifdef CONFIG_CPU_SUP_INTEL
+
+static inline bool intel_pmu_has_bts(struct perf_event *event)
+{
+	if (event->attr.config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS &&
+	    !event->attr.freq && event->hw.sample_period == 1)
+		return true;
+
+	return false;
+}
+
+int intel_pmu_save_and_restart(struct perf_event *event);
+
+struct event_constraint *
+x86_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
+			  struct perf_event *event);
+
+struct intel_shared_regs *allocate_shared_regs(int cpu);
+
+int intel_pmu_init(void);
+
+void init_debug_store_on_cpu(int cpu);
+
+void fini_debug_store_on_cpu(int cpu);
+
+void release_ds_buffers(void);
+
+void reserve_ds_buffers(void);
+
+extern struct event_constraint bts_constraint;
+
+void intel_pmu_enable_bts(u64 config);
+
+void intel_pmu_disable_bts(void);
+
+int intel_pmu_drain_bts_buffer(void);
+
+extern struct event_constraint intel_core2_pebs_event_constraints[];
+
+extern struct event_constraint intel_atom_pebs_event_constraints[];
+
+extern struct event_constraint intel_slm_pebs_event_constraints[];
+
+extern struct event_constraint intel_nehalem_pebs_event_constraints[];
+
+extern struct event_constraint intel_westmere_pebs_event_constraints[];
+
+extern struct event_constraint intel_snb_pebs_event_constraints[];
+
+extern struct event_constraint intel_ivb_pebs_event_constraints[];
+
+extern struct event_constraint intel_hsw_pebs_event_constraints[];
+
+extern struct event_constraint intel_skl_pebs_event_constraints[];
+
+struct event_constraint *intel_pebs_constraints(struct perf_event *event);
+
+void intel_pmu_pebs_enable(struct perf_event *event);
+
+void intel_pmu_pebs_disable(struct perf_event *event);
+
+void intel_pmu_pebs_enable_all(void);
+
+void intel_pmu_pebs_disable_all(void);
+
+void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in);
+
+void intel_ds_init(void);
+
+void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in);
+
+void intel_pmu_lbr_reset(void);
+
+void intel_pmu_lbr_enable(struct perf_event *event);
+
+void intel_pmu_lbr_disable(struct perf_event *event);
+
+void intel_pmu_lbr_enable_all(bool pmi);
+
+void intel_pmu_lbr_disable_all(void);
+
+void intel_pmu_lbr_read(void);
+
+void intel_pmu_lbr_init_core(void);
+
+void intel_pmu_lbr_init_nhm(void);
+
+void intel_pmu_lbr_init_atom(void);
+
+void intel_pmu_lbr_init_snb(void);
+
+void intel_pmu_lbr_init_hsw(void);
+
+void intel_pmu_lbr_init_skl(void);
+
+void intel_pmu_lbr_init_knl(void);
+
+void intel_pmu_pebs_data_source_nhm(void);
+
+int intel_pmu_setup_lbr_filter(struct perf_event *event);
+
+void intel_pt_interrupt(void);
+
+int intel_bts_interrupt(void);
+
+void intel_bts_enable_local(void);
+
+void intel_bts_disable_local(void);
+
+int p4_pmu_init(void);
+
+int p6_pmu_init(void);
+
+int knc_pmu_init(void);
+
+ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
+			  char *page);
+
+static inline int is_ht_workaround_enabled(void)
+{
+	return !!(x86_pmu.flags & PMU_FL_EXCL_ENABLED);
+}
+
+#else /* CONFIG_CPU_SUP_INTEL */
+
+static inline void reserve_ds_buffers(void)
+{
+}
+
+static inline void release_ds_buffers(void)
+{
+}
+
+static inline int intel_pmu_init(void)
+{
+	return 0;
+}
+
+static inline struct intel_shared_regs *allocate_shared_regs(int cpu)
+{
+	return NULL;
+}
+
+static inline int is_ht_workaround_enabled(void)
+{
+	return 0;
+}
+#endif /* CONFIG_CPU_SUP_INTEL */
--- linux-4.4.0.orig/arch/x86/ia32/ia32_aout.c
+++ linux-4.4.0/arch/x86/ia32/ia32_aout.c
@@ -50,7 +50,7 @@
 /*
  * fill in the user structure for a core dump..
  */
-static void dump_thread32(struct pt_regs *regs, struct user32 *dump)
+static void fill_dump(struct pt_regs *regs, struct user32 *dump)
 {
 	u32 fs, gs;
 	memset(dump, 0, sizeof(*dump));
@@ -156,10 +156,12 @@
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	has_dumped = 1;
+
+	fill_dump(cprm->regs, &dump);
+
 	strncpy(dump.u_comm, current->comm, sizeof(current->comm));
 	dump.u_ar0 = offsetof(struct user32, regs);
 	dump.signal = cprm->siginfo->si_signo;
-	dump_thread32(cprm->regs, &dump);
 
 	/*
 	 * If the size of the dump file exceeds the rlimit, then see
--- linux-4.4.0.orig/arch/x86/ia32/ia32_signal.c
+++ linux-4.4.0/arch/x86/ia32/ia32_signal.c
@@ -60,9 +60,8 @@
 } while (0)
 
 #define RELOAD_SEG(seg)		{		\
-	unsigned int pre = GET_SEG(seg);	\
+	unsigned int pre = (seg) | 3;		\
 	unsigned int cur = get_user_seg(seg);	\
-	pre |= 3;				\
 	if (pre != cur)				\
 		set_user_seg(seg, pre);		\
 }
@@ -71,6 +70,7 @@
 				   struct sigcontext_32 __user *sc)
 {
 	unsigned int tmpflags, err = 0;
+	u16 gs, fs, es, ds;
 	void __user *buf;
 	u32 tmp;
 
@@ -78,16 +78,10 @@
 	current->restart_block.fn = do_no_restart_syscall;
 
 	get_user_try {
-		/*
-		 * Reload fs and gs if they have changed in the signal
-		 * handler.  This does not handle long fs/gs base changes in
-		 * the handler, but does not clobber them at least in the
-		 * normal case.
-		 */
-		RELOAD_SEG(gs);
-		RELOAD_SEG(fs);
-		RELOAD_SEG(ds);
-		RELOAD_SEG(es);
+		gs = GET_SEG(gs);
+		fs = GET_SEG(fs);
+		ds = GET_SEG(ds);
+		es = GET_SEG(es);
 
 		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 		COPY(dx); COPY(cx); COPY(ip); COPY(ax);
@@ -105,6 +99,17 @@
 		buf = compat_ptr(tmp);
 	} get_user_catch(err);
 
+	/*
+	 * Reload fs and gs if they have changed in the signal
+	 * handler.  This does not handle long fs/gs base changes in
+	 * the handler, but does not clobber them at least in the
+	 * normal case.
+	 */
+	RELOAD_SEG(gs);
+	RELOAD_SEG(fs);
+	RELOAD_SEG(ds);
+	RELOAD_SEG(es);
+
 	err |= fpu__restore_sig(buf, 1);
 
 	force_iret();
--- linux-4.4.0.orig/arch/x86/include/asm/acpi.h
+++ linux-4.4.0/arch/x86/include/asm/acpi.h
@@ -92,7 +92,7 @@
 	if (boot_cpu_data.x86 == 0x0F &&
 	    boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
 	    boot_cpu_data.x86_model <= 0x05 &&
-	    boot_cpu_data.x86_mask < 0x0A)
+	    boot_cpu_data.x86_stepping < 0x0A)
 		return 1;
 	else if (amd_e400_c1e_detected)
 		return 1;
--- linux-4.4.0.orig/arch/x86/include/asm/alternative-asm.h
+++ linux-4.4.0/arch/x86/include/asm/alternative-asm.h
@@ -62,8 +62,10 @@
 #define new_len2		145f-144f
 
 /*
- * max without conditionals. Idea adapted from:
+ * gas compatible max based on the idea from:
  * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
+ *
+ * The additional "-" is needed because gas uses a "true" value of -1.
  */
 #define alt_max_short(a, b)	((a) ^ (((a) ^ (b)) & -(-((a) < (b)))))
 
--- linux-4.4.0.orig/arch/x86/include/asm/alternative.h
+++ linux-4.4.0/arch/x86/include/asm/alternative.h
@@ -1,11 +1,12 @@
 #ifndef _ASM_X86_ALTERNATIVE_H
 #define _ASM_X86_ALTERNATIVE_H
 
+#ifndef __ASSEMBLY__
+
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/stringify.h>
 #include <asm/asm.h>
-#include <asm/ptrace.h>
 
 /*
  * Alternative inline assembly for SMP.
@@ -102,12 +103,12 @@
 	alt_end_marker ":\n"
 
 /*
- * max without conditionals. Idea adapted from:
+ * gas compatible max based on the idea from:
  * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
  *
- * The additional "-" is needed because gas works with s32s.
+ * The additional "-" is needed because gas uses a "true" value of -1.
  */
-#define alt_max_short(a, b)	"((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") - (" b ")))))"
+#define alt_max_short(a, b)	"((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") < (" b ")))))"
 
 /*
  * Pad the second replacement alternative with additional NOPs if it is
@@ -138,7 +139,7 @@
 	".popsection\n"							\
 	".pushsection .altinstr_replacement, \"ax\"\n"			\
 	ALTINSTR_REPLACEMENT(newinstr, feature, 1)			\
-	".popsection"
+	".popsection\n"
 
 #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
 	OLDINSTR_2(oldinstr, 1, 2)					\
@@ -149,13 +150,7 @@
 	".pushsection .altinstr_replacement, \"ax\"\n"			\
 	ALTINSTR_REPLACEMENT(newinstr1, feature1, 1)			\
 	ALTINSTR_REPLACEMENT(newinstr2, feature2, 2)			\
-	".popsection"
-
-/*
- * This must be included *after* the definition of ALTERNATIVE due to
- * <asm/arch_hweight.h>
- */
-#include <asm/cpufeature.h>
+	".popsection\n"
 
 /*
  * Alternative instructions for different CPU types or capabilities.
@@ -239,36 +234,6 @@
  */
 #define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr
 
-struct paravirt_patch_site;
-#ifdef CONFIG_PARAVIRT
-void apply_paravirt(struct paravirt_patch_site *start,
-		    struct paravirt_patch_site *end);
-#else
-static inline void apply_paravirt(struct paravirt_patch_site *start,
-				  struct paravirt_patch_site *end)
-{}
-#define __parainstructions	NULL
-#define __parainstructions_end	NULL
-#endif
-
-extern void *text_poke_early(void *addr, const void *opcode, size_t len);
-
-/*
- * Clear and restore the kernel write-protection flag on the local CPU.
- * Allows the kernel to edit read-only pages.
- * Side-effect: any interrupt handler running between save and restore will have
- * the ability to write to read-only pages.
- *
- * Warning:
- * Code patching in the UP case is safe if NMIs and MCE handlers are stopped and
- * no thread can be preempted in the instructions being modified (no iret to an
- * invalid instruction possible) or if the instructions are changed from a
- * consistent state to another consistent state atomically.
- * On the local CPU you need to be protected again NMI or MCE handlers seeing an
- * inconsistent instruction while you patch.
- */
-extern void *text_poke(void *addr, const void *opcode, size_t len);
-extern int poke_int3_handler(struct pt_regs *regs);
-extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler);
+#endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_X86_ALTERNATIVE_H */
--- linux-4.4.0.orig/arch/x86/include/asm/apic.h
+++ linux-4.4.0/arch/x86/include/asm/apic.h
@@ -6,12 +6,12 @@
 
 #include <asm/alternative.h>
 #include <asm/cpufeature.h>
-#include <asm/processor.h>
 #include <asm/apicdef.h>
 #include <linux/atomic.h>
 #include <asm/fixmap.h>
 #include <asm/mpspec.h>
 #include <asm/msr.h>
+#include <asm/hardirq.h>
 #include <asm/idle.h>
 
 #define ARCH_APICTIMER_STOPS_ON_C3	1
@@ -45,7 +45,7 @@
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
-extern unsigned int apic_verbosity;
+extern int apic_verbosity;
 extern int local_apic_timer_c2_ok;
 
 extern int disable_apic;
@@ -169,16 +169,6 @@
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_X2APIC
-/*
- * Make previous memory operations globally visible before
- * sending the IPI through x2apic wrmsr. We need a serializing instruction or
- * mfence for this.
- */
-static inline void x2apic_wrmsr_fence(void)
-{
-	asm volatile("mfence" : : : "memory");
-}
-
 static inline void native_apic_msr_write(u32 reg, u32 v)
 {
 	if (reg == APIC_DFR || reg == APIC_ID || reg == APIC_LDR ||
@@ -627,25 +617,34 @@
 #endif
 
 #endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_SMP
+bool apic_id_is_primary_thread(unsigned int id);
+#else
+static inline bool apic_id_is_primary_thread(unsigned int id) { return false; }
+#endif
+
 extern void irq_enter(void);
 extern void irq_exit(void);
 
 static inline void entering_irq(void)
 {
 	irq_enter();
+	kvm_set_cpu_l1tf_flush_l1d();
 	exit_idle();
 }
 
 static inline void entering_ack_irq(void)
 {
-	ack_APIC_irq();
 	entering_irq();
+	ack_APIC_irq();
 }
 
 static inline void ipi_entering_ack_irq(void)
 {
-	ack_APIC_irq();
 	irq_enter();
+	ack_APIC_irq();
+	kvm_set_cpu_l1tf_flush_l1d();
 }
 
 static inline void exiting_irq(void)
@@ -655,9 +654,8 @@
 
 static inline void exiting_ack_irq(void)
 {
-	irq_exit();
-	/* Ack only at the end to avoid potential reentry */
 	ack_APIC_irq();
+	irq_exit();
 }
 
 extern void ioapic_zap_locks(void);
--- linux-4.4.0.orig/arch/x86/include/asm/arch_hweight.h
+++ linux-4.4.0/arch/x86/include/asm/arch_hweight.h
@@ -1,9 +1,11 @@
 #ifndef _ASM_X86_HWEIGHT_H
 #define _ASM_X86_HWEIGHT_H
 
+#include <asm/cpufeatures.h>
+
 #ifdef CONFIG_64BIT
-/* popcnt %edi, %eax -- redundant REX prefix for alignment */
-#define POPCNT32 ".byte 0xf3,0x40,0x0f,0xb8,0xc7"
+/* popcnt %edi, %eax */
+#define POPCNT32 ".byte 0xf3,0x0f,0xb8,0xc7"
 /* popcnt %rdi, %rax */
 #define POPCNT64 ".byte 0xf3,0x48,0x0f,0xb8,0xc7"
 #define REG_IN "D"
@@ -15,19 +17,15 @@
 #define REG_OUT "a"
 #endif
 
-/*
- * __sw_hweightXX are called from within the alternatives below
- * and callee-clobbered registers need to be taken care of. See
- * ARCH_HWEIGHT_CFLAGS in <arch/x86/Kconfig> for the respective
- * compiler switches.
- */
+#define __HAVE_ARCH_SW_HWEIGHT
+
 static __always_inline unsigned int __arch_hweight32(unsigned int w)
 {
-	unsigned int res = 0;
+	unsigned int res;
 
 	asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT)
-		     : "="REG_OUT (res)
-		     : REG_IN (w));
+			 : "="REG_OUT (res)
+			 : REG_IN (w));
 
 	return res;
 }
@@ -51,11 +49,11 @@
 #else
 static __always_inline unsigned long __arch_hweight64(__u64 w)
 {
-	unsigned long res = 0;
+	unsigned long res;
 
 	asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT)
-		     : "="REG_OUT (res)
-		     : REG_IN (w));
+			 : "="REG_OUT (res)
+			 : REG_IN (w));
 
 	return res;
 }
--- linux-4.4.0.orig/arch/x86/include/asm/asm-prototypes.h
+++ linux-4.4.0/arch/x86/include/asm/asm-prototypes.h
@@ -0,0 +1,40 @@
+#include <asm/ftrace.h>
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/page.h>
+#include <asm/checksum.h>
+
+#include <asm-generic/asm-prototypes.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/special_insns.h>
+#include <asm/preempt.h>
+#include <asm/asm.h>
+
+#ifndef CONFIG_X86_CMPXCHG64
+extern void cmpxchg8b_emu(void);
+#endif
+
+#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_X86_32
+#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_e ## reg(void);
+#else
+#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_r ## reg(void);
+INDIRECT_THUNK(8)
+INDIRECT_THUNK(9)
+INDIRECT_THUNK(10)
+INDIRECT_THUNK(11)
+INDIRECT_THUNK(12)
+INDIRECT_THUNK(13)
+INDIRECT_THUNK(14)
+INDIRECT_THUNK(15)
+#endif
+INDIRECT_THUNK(ax)
+INDIRECT_THUNK(bx)
+INDIRECT_THUNK(cx)
+INDIRECT_THUNK(dx)
+INDIRECT_THUNK(si)
+INDIRECT_THUNK(di)
+INDIRECT_THUNK(bp)
+#endif /* CONFIG_RETPOLINE */
--- linux-4.4.0.orig/arch/x86/include/asm/asm.h
+++ linux-4.4.0/arch/x86/include/asm/asm.h
@@ -11,10 +11,12 @@
 # define __ASM_FORM_COMMA(x) " " #x ","
 #endif
 
-#ifdef CONFIG_X86_32
+#ifndef __x86_64__
+/* 32 bit */
 # define __ASM_SEL(a,b) __ASM_FORM(a)
 # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
 #else
+/* 64 bit */
 # define __ASM_SEL(a,b) __ASM_FORM(b)
 # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
 #endif
@@ -32,6 +34,7 @@
 #define _ASM_ADD	__ASM_SIZE(add)
 #define _ASM_SUB	__ASM_SIZE(sub)
 #define _ASM_XADD	__ASM_SIZE(xadd)
+#define _ASM_MUL	__ASM_SIZE(mul)
 
 #define _ASM_AX		__ASM_REG(ax)
 #define _ASM_BX		__ASM_REG(bx)
@@ -42,6 +45,65 @@
 #define _ASM_SI		__ASM_REG(si)
 #define _ASM_DI		__ASM_REG(di)
 
+#ifndef __x86_64__
+/* 32 bit */
+
+#define _ASM_ARG1	_ASM_AX
+#define _ASM_ARG2	_ASM_DX
+#define _ASM_ARG3	_ASM_CX
+
+#define _ASM_ARG1L	eax
+#define _ASM_ARG2L	edx
+#define _ASM_ARG3L	ecx
+
+#define _ASM_ARG1W	ax
+#define _ASM_ARG2W	dx
+#define _ASM_ARG3W	cx
+
+#define _ASM_ARG1B	al
+#define _ASM_ARG2B	dl
+#define _ASM_ARG3B	cl
+
+#else
+/* 64 bit */
+
+#define _ASM_ARG1	_ASM_DI
+#define _ASM_ARG2	_ASM_SI
+#define _ASM_ARG3	_ASM_DX
+#define _ASM_ARG4	_ASM_CX
+#define _ASM_ARG5	r8
+#define _ASM_ARG6	r9
+
+#define _ASM_ARG1Q	rdi
+#define _ASM_ARG2Q	rsi
+#define _ASM_ARG3Q	rdx
+#define _ASM_ARG4Q	rcx
+#define _ASM_ARG5Q	r8
+#define _ASM_ARG6Q	r9
+
+#define _ASM_ARG1L	edi
+#define _ASM_ARG2L	esi
+#define _ASM_ARG3L	edx
+#define _ASM_ARG4L	ecx
+#define _ASM_ARG5L	r8d
+#define _ASM_ARG6L	r9d
+
+#define _ASM_ARG1W	di
+#define _ASM_ARG2W	si
+#define _ASM_ARG3W	dx
+#define _ASM_ARG4W	cx
+#define _ASM_ARG5W	r8w
+#define _ASM_ARG6W	r9w
+
+#define _ASM_ARG1B	dil
+#define _ASM_ARG2B	sil
+#define _ASM_ARG3B	dl
+#define _ASM_ARG4B	cl
+#define _ASM_ARG5B	r8b
+#define _ASM_ARG6B	r9b
+
+#endif
+
 /* Exception table entry */
 #ifdef __ASSEMBLY__
 # define _ASM_EXTABLE(from,to)					\
@@ -105,4 +167,15 @@
 /* For C file, we already have NOKPROBE_SYMBOL macro */
 #endif
 
+#ifndef __ASSEMBLY__
+/*
+ * This output constraint should be used for any inline asm which has a "call"
+ * instruction.  Otherwise the asm may be inserted before the frame pointer
+ * gets set up by the containing function.  If you forget to do this, objtool
+ * may print a "call without frame pointer save/setup" warning.
+ */
+register unsigned long current_stack_pointer asm(_ASM_SP);
+#define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
+#endif
+
 #endif /* _ASM_X86_ASM_H */
--- linux-4.4.0.orig/arch/x86/include/asm/atomic.h
+++ linux-4.4.0/arch/x86/include/asm/atomic.h
@@ -3,7 +3,6 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <asm/processor.h>
 #include <asm/alternative.h>
 #include <asm/cmpxchg.h>
 #include <asm/rmwcc.h>
@@ -50,7 +49,7 @@
 {
 	asm volatile(LOCK_PREFIX "addl %1,%0"
 		     : "+m" (v->counter)
-		     : "ir" (i));
+		     : "ir" (i) : "memory");
 }
 
 /**
@@ -64,7 +63,7 @@
 {
 	asm volatile(LOCK_PREFIX "subl %1,%0"
 		     : "+m" (v->counter)
-		     : "ir" (i));
+		     : "ir" (i) : "memory");
 }
 
 /**
@@ -90,7 +89,7 @@
 static __always_inline void atomic_inc(atomic_t *v)
 {
 	asm volatile(LOCK_PREFIX "incl %0"
-		     : "+m" (v->counter));
+		     : "+m" (v->counter) :: "memory");
 }
 
 /**
@@ -102,7 +101,7 @@
 static __always_inline void atomic_dec(atomic_t *v)
 {
 	asm volatile(LOCK_PREFIX "decl %0"
-		     : "+m" (v->counter));
+		     : "+m" (v->counter) :: "memory");
 }
 
 /**
@@ -221,19 +220,6 @@
 	return c;
 }
 
-/**
- * atomic_inc_short - increment of a short integer
- * @v: pointer to type int
- *
- * Atomically adds 1 to @v
- * Returns the new value of @u
- */
-static __always_inline short int atomic_inc_short(short int *v)
-{
-	asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v));
-	return *v;
-}
-
 #ifdef CONFIG_X86_32
 # include <asm/atomic64_32.h>
 #else
--- linux-4.4.0.orig/arch/x86/include/asm/atomic64_32.h
+++ linux-4.4.0/arch/x86/include/asm/atomic64_32.h
@@ -3,7 +3,6 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <asm/processor.h>
 //#include <asm/cmpxchg.h>
 
 /* An 64bit atomic type */
--- linux-4.4.0.orig/arch/x86/include/asm/atomic64_64.h
+++ linux-4.4.0/arch/x86/include/asm/atomic64_64.h
@@ -44,7 +44,7 @@
 {
 	asm volatile(LOCK_PREFIX "addq %1,%0"
 		     : "=m" (v->counter)
-		     : "er" (i), "m" (v->counter));
+		     : "er" (i), "m" (v->counter) : "memory");
 }
 
 /**
@@ -58,7 +58,7 @@
 {
 	asm volatile(LOCK_PREFIX "subq %1,%0"
 		     : "=m" (v->counter)
-		     : "er" (i), "m" (v->counter));
+		     : "er" (i), "m" (v->counter) : "memory");
 }
 
 /**
@@ -85,7 +85,7 @@
 {
 	asm volatile(LOCK_PREFIX "incq %0"
 		     : "=m" (v->counter)
-		     : "m" (v->counter));
+		     : "m" (v->counter) : "memory");
 }
 
 /**
@@ -98,7 +98,7 @@
 {
 	asm volatile(LOCK_PREFIX "decq %0"
 		     : "=m" (v->counter)
-		     : "m" (v->counter));
+		     : "m" (v->counter) : "memory");
 }
 
 /**
--- linux-4.4.0.orig/arch/x86/include/asm/barrier.h
+++ linux-4.4.0/arch/x86/include/asm/barrier.h
@@ -24,6 +24,34 @@
 #define wmb()	asm volatile("sfence" ::: "memory")
 #endif
 
+/**
+ * array_index_mask_nospec() - generate a mask that is ~0UL when the
+ * 	bounds check succeeds and 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * Returns:
+ *     0 - (index < size)
+ */
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+		unsigned long size)
+{
+	unsigned long mask;
+
+	asm volatile ("cmp %1,%2; sbb %0,%0;"
+			:"=r" (mask)
+			:"g"(size),"r" (index)
+			:"cc");
+	return mask;
+}
+
+/* Override the default implementation from linux/nospec.h. */
+#define array_index_mask_nospec array_index_mask_nospec
+
+/* Prevent speculative execution past this barrier. */
+#define barrier_nospec() alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC, \
+					   "lfence", X86_FEATURE_LFENCE_RDTSC)
+
 #ifdef CONFIG_X86_PPRO_FENCE
 #define dma_rmb()	rmb()
 #else
@@ -31,20 +59,10 @@
 #endif
 #define dma_wmb()	barrier()
 
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	dma_rmb()
-#define smp_wmb()	barrier()
-#define smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
-#else /* !SMP */
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0)
-#endif /* SMP */
-
-#define read_barrier_depends()		do { } while (0)
-#define smp_read_barrier_depends()	do { } while (0)
+#define __smp_mb()	mb()
+#define __smp_rmb()	dma_rmb()
+#define __smp_wmb()	barrier()
+#define __smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
 
 #if defined(CONFIG_X86_PPRO_FENCE)
 
@@ -53,31 +71,31 @@
  * model and we should fall back to full barriers.
  */
 
-#define smp_store_release(p, v)						\
+#define __smp_store_release(p, v)					\
 do {									\
 	compiletime_assert_atomic_type(*p);				\
-	smp_mb();							\
+	__smp_mb();							\
 	WRITE_ONCE(*p, v);						\
 } while (0)
 
-#define smp_load_acquire(p)						\
+#define __smp_load_acquire(p)						\
 ({									\
 	typeof(*p) ___p1 = READ_ONCE(*p);				\
 	compiletime_assert_atomic_type(*p);				\
-	smp_mb();							\
+	__smp_mb();							\
 	___p1;								\
 })
 
 #else /* regular x86 TSO memory ordering */
 
-#define smp_store_release(p, v)						\
+#define __smp_store_release(p, v)					\
 do {									\
 	compiletime_assert_atomic_type(*p);				\
 	barrier();							\
 	WRITE_ONCE(*p, v);						\
 } while (0)
 
-#define smp_load_acquire(p)						\
+#define __smp_load_acquire(p)						\
 ({									\
 	typeof(*p) ___p1 = READ_ONCE(*p);				\
 	compiletime_assert_atomic_type(*p);				\
@@ -88,7 +106,27 @@
 #endif
 
 /* Atomic operations are already serializing on x86 */
-#define smp_mb__before_atomic()	barrier()
-#define smp_mb__after_atomic()	barrier()
+#define smp_mb__before_atomic()	do { } while (0)
+#define smp_mb__after_atomic()	do { } while (0)
+
+#include <asm-generic/barrier.h>
+
+/*
+ * Make previous memory operations globally visible before
+ * a WRMSR.
+ *
+ * MFENCE makes writes visible, but only affects load/store
+ * instructions.  WRMSR is unfortunately not a load/store
+ * instruction and is unaffected by MFENCE.  The LFENCE ensures
+ * that the WRMSR is not reordered.
+ *
+ * Most WRMSRs are full serializing instructions themselves and
+ * do not require this barrier.  This is only required for the
+ * IA32_TSC_DEADLINE and X2APIC MSRs.
+ */
+static inline void weak_wrmsr_fence(void)
+{
+	asm volatile("mfence; lfence" : : : "memory");
+}
 
 #endif /* _ASM_X86_BARRIER_H */
--- linux-4.4.0.orig/arch/x86/include/asm/boot.h
+++ linux-4.4.0/arch/x86/include/asm/boot.h
@@ -27,7 +27,7 @@
 #define BOOT_HEAP_SIZE             0x400000
 #else /* !CONFIG_KERNEL_BZIP2 */
 
-#define BOOT_HEAP_SIZE	0x8000
+#define BOOT_HEAP_SIZE	0x10000
 
 #endif /* !CONFIG_KERNEL_BZIP2 */
 
--- linux-4.4.0.orig/arch/x86/include/asm/bootparam_utils.h
+++ linux-4.4.0/arch/x86/include/asm/bootparam_utils.h
@@ -17,6 +17,20 @@
  * Note: efi_info is commonly left uninitialized, but that field has a
  * private magic, so it is better to leave it unchanged.
  */
+
+#define sizeof_mbr(type, member) ({ sizeof(((type *)0)->member); })
+
+#define BOOT_PARAM_PRESERVE(struct_member)				\
+	{								\
+		.start = offsetof(struct boot_params, struct_member),	\
+		.len   = sizeof_mbr(struct boot_params, struct_member),	\
+	}
+
+struct boot_params_to_save {
+	unsigned int start;
+	unsigned int len;
+};
+
 static void sanitize_boot_params(struct boot_params *boot_params)
 {
 	/* 
@@ -35,19 +49,40 @@
 	 */
 	if (boot_params->sentinel) {
 		/* fields in boot_params are left uninitialized, clear them */
-		memset(&boot_params->ext_ramdisk_image, 0,
-		       (char *)&boot_params->efi_info -
-			(char *)&boot_params->ext_ramdisk_image);
-		memset(&boot_params->kbd_status, 0,
-		       (char *)&boot_params->hdr -
-		       (char *)&boot_params->kbd_status);
-		memset(&boot_params->_pad7[0], 0,
-		       (char *)&boot_params->edd_mbr_sig_buffer[0] -
-			(char *)&boot_params->_pad7[0]);
-		memset(&boot_params->_pad8[0], 0,
-		       (char *)&boot_params->eddbuf[0] -
-			(char *)&boot_params->_pad8[0]);
-		memset(&boot_params->_pad9[0], 0, sizeof(boot_params->_pad9));
+		static struct boot_params scratch;
+		char *bp_base = (char *)boot_params;
+		char *save_base = (char *)&scratch;
+		int i;
+
+		const struct boot_params_to_save to_save[] = {
+			BOOT_PARAM_PRESERVE(screen_info),
+			BOOT_PARAM_PRESERVE(apm_bios_info),
+			BOOT_PARAM_PRESERVE(tboot_addr),
+			BOOT_PARAM_PRESERVE(ist_info),
+			BOOT_PARAM_PRESERVE(hd0_info),
+			BOOT_PARAM_PRESERVE(hd1_info),
+			BOOT_PARAM_PRESERVE(sys_desc_table),
+			BOOT_PARAM_PRESERVE(olpc_ofw_header),
+			BOOT_PARAM_PRESERVE(efi_info),
+			BOOT_PARAM_PRESERVE(alt_mem_k),
+			BOOT_PARAM_PRESERVE(scratch),
+			BOOT_PARAM_PRESERVE(e820_entries),
+			BOOT_PARAM_PRESERVE(eddbuf_entries),
+			BOOT_PARAM_PRESERVE(edd_mbr_sig_buf_entries),
+			BOOT_PARAM_PRESERVE(edd_mbr_sig_buffer),
+			BOOT_PARAM_PRESERVE(hdr),
+			BOOT_PARAM_PRESERVE(e820_map),
+			BOOT_PARAM_PRESERVE(eddbuf),
+		};
+
+		memset(&scratch, 0, sizeof(scratch));
+
+		for (i = 0; i < ARRAY_SIZE(to_save); i++) {
+			memcpy(save_base + to_save[i].start,
+			       bp_base + to_save[i].start, to_save[i].len);
+		}
+
+		memcpy(boot_params, save_base, sizeof(*boot_params));
 	}
 }
 
--- linux-4.4.0.orig/arch/x86/include/asm/bugs.h
+++ linux-4.4.0/arch/x86/include/asm/bugs.h
@@ -1,8 +1,6 @@
 #ifndef _ASM_X86_BUGS_H
 #define _ASM_X86_BUGS_H
 
-extern void check_bugs(void);
-
 #if defined(CONFIG_CPU_SUP_INTEL) && defined(CONFIG_X86_32)
 int ppro_with_ram_bug(void);
 #else
--- linux-4.4.0.orig/arch/x86/include/asm/clocksource.h
+++ linux-4.4.0/arch/x86/include/asm/clocksource.h
@@ -5,8 +5,7 @@
 
 #define VCLOCK_NONE 0  /* No vDSO clock available.	*/
 #define VCLOCK_TSC  1  /* vDSO should use vread_tsc.	*/
-#define VCLOCK_HPET 2  /* vDSO should use vread_hpet.	*/
-#define VCLOCK_PVCLOCK 3 /* vDSO should use vread_pvclock. */
+#define VCLOCK_PVCLOCK 2 /* vDSO should use vread_pvclock. */
 
 struct arch_clocksource_data {
 	int vclock_mode;
--- linux-4.4.0.orig/arch/x86/include/asm/cmdline.h
+++ linux-4.4.0/arch/x86/include/asm/cmdline.h
@@ -2,5 +2,7 @@
 #define _ASM_X86_CMDLINE_H
 
 int cmdline_find_option_bool(const char *cmdline_ptr, const char *option);
+int cmdline_find_option(const char *cmdline_ptr, const char *option,
+			char *buffer, int bufsize);
 
 #endif /* _ASM_X86_CMDLINE_H */
--- linux-4.4.0.orig/arch/x86/include/asm/cmpxchg.h
+++ linux-4.4.0/arch/x86/include/asm/cmpxchg.h
@@ -2,6 +2,7 @@
 #define ASM_X86_CMPXCHG_H
 
 #include <linux/compiler.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative.h> /* Provides LOCK_PREFIX */
 
 /*
--- linux-4.4.0.orig/arch/x86/include/asm/cmpxchg_32.h
+++ linux-4.4.0/arch/x86/include/asm/cmpxchg_32.h
@@ -109,6 +109,6 @@
 
 #endif
 
-#define system_has_cmpxchg_double() cpu_has_cx8
+#define system_has_cmpxchg_double() boot_cpu_has(X86_FEATURE_CX8)
 
 #endif /* _ASM_X86_CMPXCHG_32_H */
--- linux-4.4.0.orig/arch/x86/include/asm/cmpxchg_64.h
+++ linux-4.4.0/arch/x86/include/asm/cmpxchg_64.h
@@ -18,6 +18,6 @@
 	cmpxchg_local((ptr), (o), (n));					\
 })
 
-#define system_has_cmpxchg_double() cpu_has_cx16
+#define system_has_cmpxchg_double() boot_cpu_has(X86_FEATURE_CX16)
 
 #endif /* _ASM_X86_CMPXCHG_64_H */
--- linux-4.4.0.orig/arch/x86/include/asm/cpu_device_id.h
+++ linux-4.4.0/arch/x86/include/asm/cpu_device_id.h
@@ -1,13 +1,201 @@
-#ifndef _CPU_DEVICE_ID
-#define _CPU_DEVICE_ID 1
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_CPU_DEVICE_ID
+#define _ASM_X86_CPU_DEVICE_ID
 
 /*
  * Declare drivers belonging to specific x86 CPUs
  * Similar in spirit to pci_device_id and related PCI functions
+ *
+ * The wildcard initializers are in mod_devicetable.h because
+ * file2alias needs them. Sigh.
  */
-
 #include <linux/mod_devicetable.h>
+/* Get the INTEL_FAM* model defines */
+#include <asm/intel-family.h>
+/* And the X86_VENDOR_* ones */
+#include <asm/processor.h>
+
+/* Centaur FAM6 models */
+#define X86_CENTAUR_FAM6_C7_A		0xa
+#define X86_CENTAUR_FAM6_C7_D		0xd
+#define X86_CENTAUR_FAM6_NANO		0xf
+
+/**
+ * X86_MATCH_VENDOR_FAM_MODEL_FEATURE - Base macro for CPU matching
+ * @_vendor:	The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *		The name is expanded to X86_VENDOR_@_vendor
+ * @_family:	The family number or X86_FAMILY_ANY
+ * @_model:	The model number, model constant or X86_MODEL_ANY
+ * @_feature:	A X86_FEATURE bit or X86_FEATURE_ANY
+ * @_data:	Driver specific data or NULL. The internal storage
+ *		format is unsigned long. The supplied value, pointer
+ *		etc. is casted to unsigned long internally.
+ *
+ * Use only if you need all selectors. Otherwise use one of the shorter
+ * macros of the X86_MATCH_* family. If there is no matching shorthand
+ * macro, consider to add one. If you really need to wrap one of the macros
+ * into another macro at the usage site for good reasons, then please
+ * start this local macro with X86_MATCH to allow easy grepping.
+ */
+#define X86_MATCH_VENDOR_FAM_MODEL_FEATURE(_vendor, _family, _model,	\
+					   _feature, _data) {		\
+	.vendor		= X86_VENDOR_##_vendor,				\
+	.family		= _family,					\
+	.model		= _model,					\
+	.feature	= _feature,					\
+	.driver_data	= (unsigned long) _data				\
+}
+
+/**
+ * X86_MATCH_VENDOR_FAM_FEATURE - Macro for matching vendor, family and CPU feature
+ * @vendor:	The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *		The name is expanded to X86_VENDOR_@vendor
+ * @family:	The family number or X86_FAMILY_ANY
+ * @feature:	A X86_FEATURE bit
+ * @data:	Driver specific data or NULL. The internal storage
+ *		format is unsigned long. The supplied value, pointer
+ *		etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set to wildcards.
+ */
+#define X86_MATCH_VENDOR_FAM_FEATURE(vendor, family, feature, data)	\
+	X86_MATCH_VENDOR_FAM_MODEL_FEATURE(vendor, family,		\
+					   X86_MODEL_ANY, feature, data)
+
+/**
+ * X86_MATCH_VENDOR_FEATURE - Macro for matching vendor and CPU feature
+ * @vendor:	The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *		The name is expanded to X86_VENDOR_@vendor
+ * @feature:	A X86_FEATURE bit
+ * @data:	Driver specific data or NULL. The internal storage
+ *		format is unsigned long. The supplied value, pointer
+ *		etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set to wildcards.
+ */
+#define X86_MATCH_VENDOR_FEATURE(vendor, feature, data)			\
+	X86_MATCH_VENDOR_FAM_FEATURE(vendor, X86_FAMILY_ANY, feature, data)
+
+/**
+ * X86_MATCH_FEATURE - Macro for matching a CPU feature
+ * @feature:	A X86_FEATURE bit
+ * @data:	Driver specific data or NULL. The internal storage
+ *		format is unsigned long. The supplied value, pointer
+ *		etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set to wildcards.
+ */
+#define X86_MATCH_FEATURE(feature, data)				\
+	X86_MATCH_VENDOR_FEATURE(ANY, feature, data)
+
+/* Transitional to keep the existing code working */
+#define X86_FEATURE_MATCH(feature)	X86_MATCH_FEATURE(feature, NULL)
+
+/**
+ * X86_MATCH_VENDOR_FAM_MODEL - Match vendor, family and model
+ * @vendor:	The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *		The name is expanded to X86_VENDOR_@vendor
+ * @family:	The family number or X86_FAMILY_ANY
+ * @model:	The model number, model constant or X86_MODEL_ANY
+ * @data:	Driver specific data or NULL. The internal storage
+ *		format is unsigned long. The supplied value, pointer
+ *		etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set to wildcards.
+ */
+#define X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, data)		\
+	X86_MATCH_VENDOR_FAM_MODEL_FEATURE(vendor, family, model,	\
+					   X86_FEATURE_ANY, data)
+
+/**
+ * X86_MATCH_VENDOR_FAM - Match vendor and family
+ * @vendor:	The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *		The name is expanded to X86_VENDOR_@vendor
+ * @family:	The family number or X86_FAMILY_ANY
+ * @data:	Driver specific data or NULL. The internal storage
+ *		format is unsigned long. The supplied value, pointer
+ *		etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments to X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set of wildcards.
+ */
+#define X86_MATCH_VENDOR_FAM(vendor, family, data)			\
+	X86_MATCH_VENDOR_FAM_MODEL(vendor, family, X86_MODEL_ANY, data)
+
+/**
+ * X86_MATCH_INTEL_FAM6_MODEL - Match vendor INTEL, family 6 and model
+ * @model:	The model name without the INTEL_FAM6_ prefix or ANY
+ *		The model name is expanded to INTEL_FAM6_@model internally
+ * @data:	Driver specific data or NULL. The internal storage
+ *		format is unsigned long. The supplied value, pointer
+ *		etc. is casted to unsigned long internally.
+ *
+ * The vendor is set to INTEL, the family to 6 and all other missing
+ * arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are set to wildcards.
+ *
+ * See X86_MATCH_VENDOR_FAM_MODEL_FEATURE() for further information.
+ */
+#define X86_MATCH_INTEL_FAM6_MODEL(model, data)				\
+	X86_MATCH_VENDOR_FAM_MODEL(INTEL, 6, INTEL_FAM6_##model, data)
+
+/*
+ * Match specific microcode revisions.
+ *
+ * vendor/family/model/stepping must be all set.
+ *
+ * Only checks against the boot CPU.  When mixed-stepping configs are
+ * valid for a CPU model, add a quirk for every valid stepping and
+ * do the fine-tuning in the quirk handler.
+ */
+
+struct x86_cpu_desc {
+	u8	x86_family;
+	u8	x86_vendor;
+	u8	x86_model;
+	u8	x86_stepping;
+	u32	x86_microcode_rev;
+};
+
+#define INTEL_CPU_DESC(model, stepping, revision) {		\
+	.x86_family		= 6,				\
+	.x86_vendor		= X86_VENDOR_INTEL,		\
+	.x86_model		= (model),			\
+	.x86_stepping		= (stepping),			\
+	.x86_microcode_rev	= (revision),			\
+}
+
+#define X86_STEPPINGS(mins, maxs)    GENMASK(maxs, mins)
+
+/**
+ * X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE - Base macro for CPU matching
+ * @_vendor:	The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *		The name is expanded to X86_VENDOR_@_vendor
+ * @_family:	The family number or X86_FAMILY_ANY
+ * @_model:	The model number, model constant or X86_MODEL_ANY
+ * @_steppings:	Bitmask for steppings, stepping constant or X86_STEPPING_ANY
+ * @_feature:	A X86_FEATURE bit or X86_FEATURE_ANY
+ * @_data:	Driver specific data or NULL. The internal storage
+ *		format is unsigned long. The supplied value, pointer
+ *		etc. is casted to unsigned long internally.
+ *
+ * Backport version to keep the SRBDS pile consistant. No shorter variants
+ * required for this.
+ */
+#define X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(_vendor, _family, _model, \
+						    _steppings, _feature, _data) { \
+	.vendor		= X86_VENDOR_##_vendor,				\
+	.family		= _family,					\
+	.model		= _model,					\
+	.steppings	= _steppings,					\
+	.feature	= _feature,					\
+	.driver_data	= (unsigned long) _data				\
+}
 
 extern const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match);
+extern bool x86_cpu_has_min_microcode_rev(const struct x86_cpu_desc *table);
 
-#endif
+#endif /* _ASM_X86_CPU_DEVICE_ID */
--- linux-4.4.0.orig/arch/x86/include/asm/cpufeature.h
+++ linux-4.4.0/arch/x86/include/asm/cpufeature.h
@@ -1,284 +1,38 @@
-/*
- * Defines x86 CPU feature bits
- */
 #ifndef _ASM_X86_CPUFEATURE_H
 #define _ASM_X86_CPUFEATURE_H
 
-#ifndef _ASM_X86_REQUIRED_FEATURES_H
-#include <asm/required-features.h>
-#endif
-
-#ifndef _ASM_X86_DISABLED_FEATURES_H
-#include <asm/disabled-features.h>
-#endif
-
-#define NCAPINTS	14	/* N 32-bit words worth of info */
-#define NBUGINTS	1	/* N 32-bit bug flags */
-
-/*
- * Note: If the comment begins with a quoted string, that string is used
- * in /proc/cpuinfo instead of the macro name.  If the string is "",
- * this feature bit is not displayed in /proc/cpuinfo at all.
- */
-
-/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
-#define X86_FEATURE_FPU		( 0*32+ 0) /* Onboard FPU */
-#define X86_FEATURE_VME		( 0*32+ 1) /* Virtual Mode Extensions */
-#define X86_FEATURE_DE		( 0*32+ 2) /* Debugging Extensions */
-#define X86_FEATURE_PSE		( 0*32+ 3) /* Page Size Extensions */
-#define X86_FEATURE_TSC		( 0*32+ 4) /* Time Stamp Counter */
-#define X86_FEATURE_MSR		( 0*32+ 5) /* Model-Specific Registers */
-#define X86_FEATURE_PAE		( 0*32+ 6) /* Physical Address Extensions */
-#define X86_FEATURE_MCE		( 0*32+ 7) /* Machine Check Exception */
-#define X86_FEATURE_CX8		( 0*32+ 8) /* CMPXCHG8 instruction */
-#define X86_FEATURE_APIC	( 0*32+ 9) /* Onboard APIC */
-#define X86_FEATURE_SEP		( 0*32+11) /* SYSENTER/SYSEXIT */
-#define X86_FEATURE_MTRR	( 0*32+12) /* Memory Type Range Registers */
-#define X86_FEATURE_PGE		( 0*32+13) /* Page Global Enable */
-#define X86_FEATURE_MCA		( 0*32+14) /* Machine Check Architecture */
-#define X86_FEATURE_CMOV	( 0*32+15) /* CMOV instructions */
-					  /* (plus FCMOVcc, FCOMI with FPU) */
-#define X86_FEATURE_PAT		( 0*32+16) /* Page Attribute Table */
-#define X86_FEATURE_PSE36	( 0*32+17) /* 36-bit PSEs */
-#define X86_FEATURE_PN		( 0*32+18) /* Processor serial number */
-#define X86_FEATURE_CLFLUSH	( 0*32+19) /* CLFLUSH instruction */
-#define X86_FEATURE_DS		( 0*32+21) /* "dts" Debug Store */
-#define X86_FEATURE_ACPI	( 0*32+22) /* ACPI via MSR */
-#define X86_FEATURE_MMX		( 0*32+23) /* Multimedia Extensions */
-#define X86_FEATURE_FXSR	( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */
-#define X86_FEATURE_XMM		( 0*32+25) /* "sse" */
-#define X86_FEATURE_XMM2	( 0*32+26) /* "sse2" */
-#define X86_FEATURE_SELFSNOOP	( 0*32+27) /* "ss" CPU self snoop */
-#define X86_FEATURE_HT		( 0*32+28) /* Hyper-Threading */
-#define X86_FEATURE_ACC		( 0*32+29) /* "tm" Automatic clock control */
-#define X86_FEATURE_IA64	( 0*32+30) /* IA-64 processor */
-#define X86_FEATURE_PBE		( 0*32+31) /* Pending Break Enable */
-
-/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
-/* Don't duplicate feature flags which are redundant with Intel! */
-#define X86_FEATURE_SYSCALL	( 1*32+11) /* SYSCALL/SYSRET */
-#define X86_FEATURE_MP		( 1*32+19) /* MP Capable. */
-#define X86_FEATURE_NX		( 1*32+20) /* Execute Disable */
-#define X86_FEATURE_MMXEXT	( 1*32+22) /* AMD MMX extensions */
-#define X86_FEATURE_FXSR_OPT	( 1*32+25) /* FXSAVE/FXRSTOR optimizations */
-#define X86_FEATURE_GBPAGES	( 1*32+26) /* "pdpe1gb" GB pages */
-#define X86_FEATURE_RDTSCP	( 1*32+27) /* RDTSCP */
-#define X86_FEATURE_LM		( 1*32+29) /* Long Mode (x86-64) */
-#define X86_FEATURE_3DNOWEXT	( 1*32+30) /* AMD 3DNow! extensions */
-#define X86_FEATURE_3DNOW	( 1*32+31) /* 3DNow! */
-
-/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
-#define X86_FEATURE_RECOVERY	( 2*32+ 0) /* CPU in recovery mode */
-#define X86_FEATURE_LONGRUN	( 2*32+ 1) /* Longrun power control */
-#define X86_FEATURE_LRTI	( 2*32+ 3) /* LongRun table interface */
-
-/* Other features, Linux-defined mapping, word 3 */
-/* This range is used for feature bits which conflict or are synthesized */
-#define X86_FEATURE_CXMMX	( 3*32+ 0) /* Cyrix MMX extensions */
-#define X86_FEATURE_K6_MTRR	( 3*32+ 1) /* AMD K6 nonstandard MTRRs */
-#define X86_FEATURE_CYRIX_ARR	( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */
-#define X86_FEATURE_CENTAUR_MCR	( 3*32+ 3) /* Centaur MCRs (= MTRRs) */
-/* cpu types for specific tunings: */
-#define X86_FEATURE_K8		( 3*32+ 4) /* "" Opteron, Athlon64 */
-#define X86_FEATURE_K7		( 3*32+ 5) /* "" Athlon */
-#define X86_FEATURE_P3		( 3*32+ 6) /* "" P3 */
-#define X86_FEATURE_P4		( 3*32+ 7) /* "" P4 */
-#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */
-#define X86_FEATURE_UP		( 3*32+ 9) /* smp kernel running on up */
-/* free, was #define X86_FEATURE_FXSAVE_LEAK ( 3*32+10) * "" FXSAVE leaks FOP/FIP/FOP */
-#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */
-#define X86_FEATURE_PEBS	( 3*32+12) /* Precise-Event Based Sampling */
-#define X86_FEATURE_BTS		( 3*32+13) /* Branch Trace Store */
-#define X86_FEATURE_SYSCALL32	( 3*32+14) /* "" syscall in ia32 userspace */
-#define X86_FEATURE_SYSENTER32	( 3*32+15) /* "" sysenter in ia32 userspace */
-#define X86_FEATURE_REP_GOOD	( 3*32+16) /* rep microcode works well */
-#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" Mfence synchronizes RDTSC */
-#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" Lfence synchronizes RDTSC */
-/* free, was #define X86_FEATURE_11AP	( 3*32+19) * "" Bad local APIC aka 11AP */
-#define X86_FEATURE_NOPL	( 3*32+20) /* The NOPL (0F 1F) instructions */
-#define X86_FEATURE_ALWAYS	( 3*32+21) /* "" Always-present feature */
-#define X86_FEATURE_XTOPOLOGY	( 3*32+22) /* cpu topology enum extensions */
-#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */
-#define X86_FEATURE_NONSTOP_TSC	( 3*32+24) /* TSC does not stop in C states */
-/* free, was #define X86_FEATURE_CLFLUSH_MONITOR ( 3*32+25) * "" clflush reqd with monitor */
-#define X86_FEATURE_EXTD_APICID	( 3*32+26) /* has extended APICID (8 bits) */
-#define X86_FEATURE_AMD_DCM     ( 3*32+27) /* multi-node processor */
-#define X86_FEATURE_APERFMPERF	( 3*32+28) /* APERFMPERF */
-#define X86_FEATURE_EAGER_FPU	( 3*32+29) /* "eagerfpu" Non lazy FPU restore */
-#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
-
-/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
-#define X86_FEATURE_XMM3	( 4*32+ 0) /* "pni" SSE-3 */
-#define X86_FEATURE_PCLMULQDQ	( 4*32+ 1) /* PCLMULQDQ instruction */
-#define X86_FEATURE_DTES64	( 4*32+ 2) /* 64-bit Debug Store */
-#define X86_FEATURE_MWAIT	( 4*32+ 3) /* "monitor" Monitor/Mwait support */
-#define X86_FEATURE_DSCPL	( 4*32+ 4) /* "ds_cpl" CPL Qual. Debug Store */
-#define X86_FEATURE_VMX		( 4*32+ 5) /* Hardware virtualization */
-#define X86_FEATURE_SMX		( 4*32+ 6) /* Safer mode */
-#define X86_FEATURE_EST		( 4*32+ 7) /* Enhanced SpeedStep */
-#define X86_FEATURE_TM2		( 4*32+ 8) /* Thermal Monitor 2 */
-#define X86_FEATURE_SSSE3	( 4*32+ 9) /* Supplemental SSE-3 */
-#define X86_FEATURE_CID		( 4*32+10) /* Context ID */
-#define X86_FEATURE_SDBG	( 4*32+11) /* Silicon Debug */
-#define X86_FEATURE_FMA		( 4*32+12) /* Fused multiply-add */
-#define X86_FEATURE_CX16	( 4*32+13) /* CMPXCHG16B */
-#define X86_FEATURE_XTPR	( 4*32+14) /* Send Task Priority Messages */
-#define X86_FEATURE_PDCM	( 4*32+15) /* Performance Capabilities */
-#define X86_FEATURE_PCID	( 4*32+17) /* Process Context Identifiers */
-#define X86_FEATURE_DCA		( 4*32+18) /* Direct Cache Access */
-#define X86_FEATURE_XMM4_1	( 4*32+19) /* "sse4_1" SSE-4.1 */
-#define X86_FEATURE_XMM4_2	( 4*32+20) /* "sse4_2" SSE-4.2 */
-#define X86_FEATURE_X2APIC	( 4*32+21) /* x2APIC */
-#define X86_FEATURE_MOVBE	( 4*32+22) /* MOVBE instruction */
-#define X86_FEATURE_POPCNT      ( 4*32+23) /* POPCNT instruction */
-#define X86_FEATURE_TSC_DEADLINE_TIMER	( 4*32+24) /* Tsc deadline timer */
-#define X86_FEATURE_AES		( 4*32+25) /* AES instructions */
-#define X86_FEATURE_XSAVE	( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
-#define X86_FEATURE_OSXSAVE	( 4*32+27) /* "" XSAVE enabled in the OS */
-#define X86_FEATURE_AVX		( 4*32+28) /* Advanced Vector Extensions */
-#define X86_FEATURE_F16C	( 4*32+29) /* 16-bit fp conversions */
-#define X86_FEATURE_RDRAND	( 4*32+30) /* The RDRAND instruction */
-#define X86_FEATURE_HYPERVISOR	( 4*32+31) /* Running on a hypervisor */
-
-/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
-#define X86_FEATURE_XSTORE	( 5*32+ 2) /* "rng" RNG present (xstore) */
-#define X86_FEATURE_XSTORE_EN	( 5*32+ 3) /* "rng_en" RNG enabled */
-#define X86_FEATURE_XCRYPT	( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */
-#define X86_FEATURE_XCRYPT_EN	( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */
-#define X86_FEATURE_ACE2	( 5*32+ 8) /* Advanced Cryptography Engine v2 */
-#define X86_FEATURE_ACE2_EN	( 5*32+ 9) /* ACE v2 enabled */
-#define X86_FEATURE_PHE		( 5*32+10) /* PadLock Hash Engine */
-#define X86_FEATURE_PHE_EN	( 5*32+11) /* PHE enabled */
-#define X86_FEATURE_PMM		( 5*32+12) /* PadLock Montgomery Multiplier */
-#define X86_FEATURE_PMM_EN	( 5*32+13) /* PMM enabled */
-
-/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
-#define X86_FEATURE_LAHF_LM	( 6*32+ 0) /* LAHF/SAHF in long mode */
-#define X86_FEATURE_CMP_LEGACY	( 6*32+ 1) /* If yes HyperThreading not valid */
-#define X86_FEATURE_SVM		( 6*32+ 2) /* Secure virtual machine */
-#define X86_FEATURE_EXTAPIC	( 6*32+ 3) /* Extended APIC space */
-#define X86_FEATURE_CR8_LEGACY	( 6*32+ 4) /* CR8 in 32-bit mode */
-#define X86_FEATURE_ABM		( 6*32+ 5) /* Advanced bit manipulation */
-#define X86_FEATURE_SSE4A	( 6*32+ 6) /* SSE-4A */
-#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* Misaligned SSE mode */
-#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* 3DNow prefetch instructions */
-#define X86_FEATURE_OSVW	( 6*32+ 9) /* OS Visible Workaround */
-#define X86_FEATURE_IBS		( 6*32+10) /* Instruction Based Sampling */
-#define X86_FEATURE_XOP		( 6*32+11) /* extended AVX instructions */
-#define X86_FEATURE_SKINIT	( 6*32+12) /* SKINIT/STGI instructions */
-#define X86_FEATURE_WDT		( 6*32+13) /* Watchdog timer */
-#define X86_FEATURE_LWP		( 6*32+15) /* Light Weight Profiling */
-#define X86_FEATURE_FMA4	( 6*32+16) /* 4 operands MAC instructions */
-#define X86_FEATURE_TCE		( 6*32+17) /* translation cache extension */
-#define X86_FEATURE_NODEID_MSR	( 6*32+19) /* NodeId MSR */
-#define X86_FEATURE_TBM		( 6*32+21) /* trailing bit manipulations */
-#define X86_FEATURE_TOPOEXT	( 6*32+22) /* topology extensions CPUID leafs */
-#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */
-#define X86_FEATURE_PERFCTR_NB  ( 6*32+24) /* NB performance counter extensions */
-#define X86_FEATURE_BPEXT	(6*32+26) /* data breakpoint extension */
-#define X86_FEATURE_PERFCTR_L2	( 6*32+28) /* L2 performance counter extensions */
-#define X86_FEATURE_MWAITX	( 6*32+29) /* MWAIT extension (MONITORX/MWAITX) */
-
-/*
- * Auxiliary flags: Linux defined - For features scattered in various
- * CPUID levels like 0x6, 0xA etc, word 7
- */
-#define X86_FEATURE_IDA		( 7*32+ 0) /* Intel Dynamic Acceleration */
-#define X86_FEATURE_ARAT	( 7*32+ 1) /* Always Running APIC Timer */
-#define X86_FEATURE_CPB		( 7*32+ 2) /* AMD Core Performance Boost */
-#define X86_FEATURE_EPB		( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
-#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_DTHERM	( 7*32+ 7) /* Digital Thermal Sensor */
-#define X86_FEATURE_HW_PSTATE	( 7*32+ 8) /* AMD HW-PState */
-#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
-#define X86_FEATURE_HWP		( 7*32+ 10) /* "hwp" Intel HWP */
-#define X86_FEATURE_HWP_NOTIFY	( 7*32+ 11) /* Intel HWP_NOTIFY */
-#define X86_FEATURE_HWP_ACT_WINDOW ( 7*32+ 12) /* Intel HWP_ACT_WINDOW */
-#define X86_FEATURE_HWP_EPP	( 7*32+13) /* Intel HWP_EPP */
-#define X86_FEATURE_HWP_PKG_REQ ( 7*32+14) /* Intel HWP_PKG_REQ */
-#define X86_FEATURE_INTEL_PT	( 7*32+15) /* Intel Processor Trace */
-
-/* Virtualization flags: Linux defined, word 8 */
-#define X86_FEATURE_TPR_SHADOW  ( 8*32+ 0) /* Intel TPR Shadow */
-#define X86_FEATURE_VNMI        ( 8*32+ 1) /* Intel Virtual NMI */
-#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */
-#define X86_FEATURE_EPT         ( 8*32+ 3) /* Intel Extended Page Table */
-#define X86_FEATURE_VPID        ( 8*32+ 4) /* Intel Virtual Processor ID */
-#define X86_FEATURE_NPT		( 8*32+ 5) /* AMD Nested Page Table support */
-#define X86_FEATURE_LBRV	( 8*32+ 6) /* AMD LBR Virtualization support */
-#define X86_FEATURE_SVML	( 8*32+ 7) /* "svm_lock" AMD SVM locking MSR */
-#define X86_FEATURE_NRIPS	( 8*32+ 8) /* "nrip_save" AMD SVM next_rip save */
-#define X86_FEATURE_TSCRATEMSR  ( 8*32+ 9) /* "tsc_scale" AMD TSC scaling support */
-#define X86_FEATURE_VMCBCLEAN   ( 8*32+10) /* "vmcb_clean" AMD VMCB clean bits support */
-#define X86_FEATURE_FLUSHBYASID ( 8*32+11) /* AMD flush-by-ASID support */
-#define X86_FEATURE_DECODEASSISTS ( 8*32+12) /* AMD Decode Assists support */
-#define X86_FEATURE_PAUSEFILTER ( 8*32+13) /* AMD filtered pause intercept */
-#define X86_FEATURE_PFTHRESHOLD ( 8*32+14) /* AMD pause filter threshold */
-#define X86_FEATURE_VMMCALL     ( 8*32+15) /* Prefer vmmcall to vmcall */
-#define X86_FEATURE_XENPV       ( 8*32+16) /* "" Xen paravirtual guest */
-
-
-/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
-#define X86_FEATURE_FSGSBASE	( 9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
-#define X86_FEATURE_TSC_ADJUST	( 9*32+ 1) /* TSC adjustment MSR 0x3b */
-#define X86_FEATURE_BMI1	( 9*32+ 3) /* 1st group bit manipulation extensions */
-#define X86_FEATURE_HLE		( 9*32+ 4) /* Hardware Lock Elision */
-#define X86_FEATURE_AVX2	( 9*32+ 5) /* AVX2 instructions */
-#define X86_FEATURE_SMEP	( 9*32+ 7) /* Supervisor Mode Execution Protection */
-#define X86_FEATURE_BMI2	( 9*32+ 8) /* 2nd group bit manipulation extensions */
-#define X86_FEATURE_ERMS	( 9*32+ 9) /* Enhanced REP MOVSB/STOSB */
-#define X86_FEATURE_INVPCID	( 9*32+10) /* Invalidate Processor Context ID */
-#define X86_FEATURE_RTM		( 9*32+11) /* Restricted Transactional Memory */
-#define X86_FEATURE_CQM		( 9*32+12) /* Cache QoS Monitoring */
-#define X86_FEATURE_MPX		( 9*32+14) /* Memory Protection Extension */
-#define X86_FEATURE_AVX512F	( 9*32+16) /* AVX-512 Foundation */
-#define X86_FEATURE_RDSEED	( 9*32+18) /* The RDSEED instruction */
-#define X86_FEATURE_ADX		( 9*32+19) /* The ADCX and ADOX instructions */
-#define X86_FEATURE_SMAP	( 9*32+20) /* Supervisor Mode Access Prevention */
-#define X86_FEATURE_PCOMMIT	( 9*32+22) /* PCOMMIT instruction */
-#define X86_FEATURE_CLFLUSHOPT	( 9*32+23) /* CLFLUSHOPT instruction */
-#define X86_FEATURE_CLWB	( 9*32+24) /* CLWB instruction */
-#define X86_FEATURE_AVX512PF	( 9*32+26) /* AVX-512 Prefetch */
-#define X86_FEATURE_AVX512ER	( 9*32+27) /* AVX-512 Exponential and Reciprocal */
-#define X86_FEATURE_AVX512CD	( 9*32+28) /* AVX-512 Conflict Detection */
-#define X86_FEATURE_SHA_NI	( 9*32+29) /* SHA1/SHA256 Instruction Extensions */
-
-/* Extended state features, CPUID level 0x0000000d:1 (eax), word 10 */
-#define X86_FEATURE_XSAVEOPT	(10*32+ 0) /* XSAVEOPT */
-#define X86_FEATURE_XSAVEC	(10*32+ 1) /* XSAVEC */
-#define X86_FEATURE_XGETBV1	(10*32+ 2) /* XGETBV with ECX = 1 */
-#define X86_FEATURE_XSAVES	(10*32+ 3) /* XSAVES/XRSTORS */
-
-/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (edx), word 11 */
-#define X86_FEATURE_CQM_LLC	(11*32+ 1) /* LLC QoS if 1 */
-
-/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (edx), word 12 */
-#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring if 1 */
-
-/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
-#define X86_FEATURE_CLZERO	(13*32+0) /* CLZERO instruction */
-
-/*
- * BUG word(s)
- */
-#define X86_BUG(x)		(NCAPINTS*32 + (x))
-
-#define X86_BUG_F00F		X86_BUG(0) /* Intel F00F */
-#define X86_BUG_FDIV		X86_BUG(1) /* FPU FDIV */
-#define X86_BUG_COMA		X86_BUG(2) /* Cyrix 6x86 coma */
-#define X86_BUG_AMD_TLB_MMATCH	X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */
-#define X86_BUG_AMD_APIC_C1E	X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */
-#define X86_BUG_11AP		X86_BUG(5) /* Bad local APIC aka 11AP */
-#define X86_BUG_FXSAVE_LEAK	X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */
-#define X86_BUG_CLFLUSH_MONITOR	X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */
-#define X86_BUG_SYSRET_SS_ATTRS	X86_BUG(8) /* SYSRET doesn't fix up SS attrs */
+#include <asm/processor.h>
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
 #include <asm/asm.h>
 #include <linux/bitops.h>
 
+enum cpuid_leafs
+{
+	CPUID_1_EDX		= 0,
+	CPUID_8000_0001_EDX,
+	CPUID_8086_0001_EDX,
+	CPUID_LNX_1,
+	CPUID_1_ECX,
+	CPUID_C000_0001_EDX,
+	CPUID_8000_0001_ECX,
+	CPUID_LNX_2,
+	CPUID_LNX_3,
+	CPUID_7_0_EBX,
+	CPUID_D_1_EAX,
+	CPUID_LNX_4,
+	CPUID_DUMMY,
+	CPUID_8000_0008_EBX,
+	CPUID_6_EAX,
+	CPUID_8000_000A_EDX,
+	CPUID_7_ECX,
+	CPUID_8000_0007_EBX,
+	CPUID_7_EDX,
+	CPUID_LNX_5,
+	NR_CPUID_WORDS,
+};
+
 #ifdef CONFIG_X86_FEATURE_NAMES
 extern const char * const x86_cap_flags[NCAPINTS*32];
 extern const char * const x86_power_flags[32];
@@ -298,29 +52,63 @@
 #define test_cpu_cap(c, bit)						\
 	 test_bit(bit, (unsigned long *)((c)->x86_capability))
 
-#define REQUIRED_MASK_BIT_SET(bit)					\
-	 ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) ||	\
-	   (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) ||	\
-	   (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) ||	\
-	   (((bit)>>5)==3 && (1UL<<((bit)&31) & REQUIRED_MASK3)) ||	\
-	   (((bit)>>5)==4 && (1UL<<((bit)&31) & REQUIRED_MASK4)) ||	\
-	   (((bit)>>5)==5 && (1UL<<((bit)&31) & REQUIRED_MASK5)) ||	\
-	   (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) ||	\
-	   (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) ||	\
-	   (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) ||	\
-	   (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) )
-
-#define DISABLED_MASK_BIT_SET(bit)					\
-	 ( (((bit)>>5)==0 && (1UL<<((bit)&31) & DISABLED_MASK0)) ||	\
-	   (((bit)>>5)==1 && (1UL<<((bit)&31) & DISABLED_MASK1)) ||	\
-	   (((bit)>>5)==2 && (1UL<<((bit)&31) & DISABLED_MASK2)) ||	\
-	   (((bit)>>5)==3 && (1UL<<((bit)&31) & DISABLED_MASK3)) ||	\
-	   (((bit)>>5)==4 && (1UL<<((bit)&31) & DISABLED_MASK4)) ||	\
-	   (((bit)>>5)==5 && (1UL<<((bit)&31) & DISABLED_MASK5)) ||	\
-	   (((bit)>>5)==6 && (1UL<<((bit)&31) & DISABLED_MASK6)) ||	\
-	   (((bit)>>5)==7 && (1UL<<((bit)&31) & DISABLED_MASK7)) ||	\
-	   (((bit)>>5)==8 && (1UL<<((bit)&31) & DISABLED_MASK8)) ||	\
-	   (((bit)>>5)==9 && (1UL<<((bit)&31) & DISABLED_MASK9)) )
+/*
+ * There are 32 bits/features in each mask word.  The high bits
+ * (selected with (bit>>5) give us the word number and the low 5
+ * bits give us the bit/feature number inside the word.
+ * (1UL<<((bit)&31) gives us a mask for the feature_bit so we can
+ * see if it is set in the mask word.
+ */
+#define CHECK_BIT_IN_MASK_WORD(maskname, word, bit)    \
+	(((bit)>>5)==(word) && (1UL<<((bit)&31) & maskname##word ))
+
+#define REQUIRED_MASK_BIT_SET(feature_bit)		\
+	 ( CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  0, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  1, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  2, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  3, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  4, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  5, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  6, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  7, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  8, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  9, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 10, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 11, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 12, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 13, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 14, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 15, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 16, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 17, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 18, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 19, feature_bit) ||	\
+	   REQUIRED_MASK_CHECK					  ||	\
+	   BUILD_BUG_ON_ZERO(NCAPINTS != 20))
+
+#define DISABLED_MASK_BIT_SET(feature_bit)				\
+	 ( CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  0, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  1, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  2, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  3, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  4, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  5, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  6, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  7, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  8, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  9, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 10, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 11, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 12, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 13, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 14, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 15, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 16, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 17, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 18, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 19, feature_bit) ||	\
+	   DISABLED_MASK_CHECK					  ||	\
+	   BUILD_BUG_ON_ZERO(NCAPINTS != 20))
 
 #define cpu_has(c, bit)							\
 	(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :	\
@@ -339,8 +127,7 @@
  * is not relevant.
  */
 #define cpu_feature_enabled(bit)	\
-	(__builtin_constant_p(bit) && DISABLED_MASK_BIT_SET(bit) ? 0 :	\
-	 cpu_has(&boot_cpu_data, bit))
+	(__builtin_constant_p(bit) && DISABLED_MASK_BIT_SET(bit) ? 0 : static_cpu_has(bit))
 
 #define boot_cpu_has(bit)	cpu_has(&boot_cpu_data, bit)
 
@@ -355,156 +142,42 @@
 	set_bit(bit, (unsigned long *)cpu_caps_set);	\
 } while (0)
 
+#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)
+
 #define cpu_has_fpu		boot_cpu_has(X86_FEATURE_FPU)
-#define cpu_has_de		boot_cpu_has(X86_FEATURE_DE)
 #define cpu_has_pse		boot_cpu_has(X86_FEATURE_PSE)
 #define cpu_has_tsc		boot_cpu_has(X86_FEATURE_TSC)
 #define cpu_has_pge		boot_cpu_has(X86_FEATURE_PGE)
 #define cpu_has_apic		boot_cpu_has(X86_FEATURE_APIC)
-#define cpu_has_sep		boot_cpu_has(X86_FEATURE_SEP)
-#define cpu_has_mtrr		boot_cpu_has(X86_FEATURE_MTRR)
-#define cpu_has_mmx		boot_cpu_has(X86_FEATURE_MMX)
 #define cpu_has_fxsr		boot_cpu_has(X86_FEATURE_FXSR)
 #define cpu_has_xmm		boot_cpu_has(X86_FEATURE_XMM)
 #define cpu_has_xmm2		boot_cpu_has(X86_FEATURE_XMM2)
-#define cpu_has_xmm3		boot_cpu_has(X86_FEATURE_XMM3)
-#define cpu_has_ssse3		boot_cpu_has(X86_FEATURE_SSSE3)
 #define cpu_has_aes		boot_cpu_has(X86_FEATURE_AES)
 #define cpu_has_avx		boot_cpu_has(X86_FEATURE_AVX)
 #define cpu_has_avx2		boot_cpu_has(X86_FEATURE_AVX2)
-#define cpu_has_ht		boot_cpu_has(X86_FEATURE_HT)
-#define cpu_has_nx		boot_cpu_has(X86_FEATURE_NX)
-#define cpu_has_xstore		boot_cpu_has(X86_FEATURE_XSTORE)
-#define cpu_has_xstore_enabled	boot_cpu_has(X86_FEATURE_XSTORE_EN)
-#define cpu_has_xcrypt		boot_cpu_has(X86_FEATURE_XCRYPT)
-#define cpu_has_xcrypt_enabled	boot_cpu_has(X86_FEATURE_XCRYPT_EN)
-#define cpu_has_ace2		boot_cpu_has(X86_FEATURE_ACE2)
-#define cpu_has_ace2_enabled	boot_cpu_has(X86_FEATURE_ACE2_EN)
-#define cpu_has_phe		boot_cpu_has(X86_FEATURE_PHE)
-#define cpu_has_phe_enabled	boot_cpu_has(X86_FEATURE_PHE_EN)
-#define cpu_has_pmm		boot_cpu_has(X86_FEATURE_PMM)
-#define cpu_has_pmm_enabled	boot_cpu_has(X86_FEATURE_PMM_EN)
-#define cpu_has_ds		boot_cpu_has(X86_FEATURE_DS)
-#define cpu_has_pebs		boot_cpu_has(X86_FEATURE_PEBS)
 #define cpu_has_clflush		boot_cpu_has(X86_FEATURE_CLFLUSH)
-#define cpu_has_bts		boot_cpu_has(X86_FEATURE_BTS)
 #define cpu_has_gbpages		boot_cpu_has(X86_FEATURE_GBPAGES)
 #define cpu_has_arch_perfmon	boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
 #define cpu_has_pat		boot_cpu_has(X86_FEATURE_PAT)
-#define cpu_has_xmm4_1		boot_cpu_has(X86_FEATURE_XMM4_1)
-#define cpu_has_xmm4_2		boot_cpu_has(X86_FEATURE_XMM4_2)
 #define cpu_has_x2apic		boot_cpu_has(X86_FEATURE_X2APIC)
 #define cpu_has_xsave		boot_cpu_has(X86_FEATURE_XSAVE)
-#define cpu_has_xsaveopt	boot_cpu_has(X86_FEATURE_XSAVEOPT)
 #define cpu_has_xsaves		boot_cpu_has(X86_FEATURE_XSAVES)
 #define cpu_has_osxsave		boot_cpu_has(X86_FEATURE_OSXSAVE)
 #define cpu_has_hypervisor	boot_cpu_has(X86_FEATURE_HYPERVISOR)
-#define cpu_has_pclmulqdq	boot_cpu_has(X86_FEATURE_PCLMULQDQ)
-#define cpu_has_perfctr_core	boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
-#define cpu_has_perfctr_nb	boot_cpu_has(X86_FEATURE_PERFCTR_NB)
-#define cpu_has_perfctr_l2	boot_cpu_has(X86_FEATURE_PERFCTR_L2)
-#define cpu_has_cx8		boot_cpu_has(X86_FEATURE_CX8)
-#define cpu_has_cx16		boot_cpu_has(X86_FEATURE_CX16)
-#define cpu_has_eager_fpu	boot_cpu_has(X86_FEATURE_EAGER_FPU)
-#define cpu_has_topoext		boot_cpu_has(X86_FEATURE_TOPOEXT)
-#define cpu_has_bpext		boot_cpu_has(X86_FEATURE_BPEXT)
-
-#if __GNUC__ >= 4
-extern void warn_pre_alternatives(void);
-extern bool __static_cpu_has_safe(u16 bit);
+/*
+ * Do not add any more of those clumsy macros - use static_cpu_has() for
+ * fast paths and boot_cpu_has() otherwise!
+ */
 
+#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_X86_FAST_FEATURE_TESTS)
 /*
  * Static testing of CPU features.  Used the same as boot_cpu_has().
- * These are only valid after alternatives have run, but will statically
- * patch the target code for additional performance.
+ * These will statically patch the target code for additional
+ * performance.
  */
-static __always_inline __pure bool __static_cpu_has(u16 bit)
-{
-#ifdef CC_HAVE_ASM_GOTO
-
-#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
-
-		/*
-		 * Catch too early usage of this before alternatives
-		 * have run.
-		 */
-		asm_volatile_goto("1: jmp %l[t_warn]\n"
-			 "2:\n"
-			 ".section .altinstructions,\"a\"\n"
-			 " .long 1b - .\n"
-			 " .long 0\n"		/* no replacement */
-			 " .word %P0\n"		/* 1: do replace */
-			 " .byte 2b - 1b\n"	/* source len */
-			 " .byte 0\n"		/* replacement len */
-			 " .byte 0\n"		/* pad len */
-			 ".previous\n"
-			 /* skipping size check since replacement size = 0 */
-			 : : "i" (X86_FEATURE_ALWAYS) : : t_warn);
-
-#endif
-
-		asm_volatile_goto("1: jmp %l[t_no]\n"
-			 "2:\n"
-			 ".section .altinstructions,\"a\"\n"
-			 " .long 1b - .\n"
-			 " .long 0\n"		/* no replacement */
-			 " .word %P0\n"		/* feature bit */
-			 " .byte 2b - 1b\n"	/* source len */
-			 " .byte 0\n"		/* replacement len */
-			 " .byte 0\n"		/* pad len */
-			 ".previous\n"
-			 /* skipping size check since replacement size = 0 */
-			 : : "i" (bit) : : t_no);
-		return true;
-	t_no:
-		return false;
-
-#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
-	t_warn:
-		warn_pre_alternatives();
-		return false;
-#endif
-
-#else /* CC_HAVE_ASM_GOTO */
-
-		u8 flag;
-		/* Open-coded due to __stringify() in ALTERNATIVE() */
-		asm volatile("1: movb $0,%0\n"
-			     "2:\n"
-			     ".section .altinstructions,\"a\"\n"
-			     " .long 1b - .\n"
-			     " .long 3f - .\n"
-			     " .word %P1\n"		/* feature bit */
-			     " .byte 2b - 1b\n"		/* source len */
-			     " .byte 4f - 3f\n"		/* replacement len */
-			     " .byte 0\n"		/* pad len */
-			     ".previous\n"
-			     ".section .discard,\"aw\",@progbits\n"
-			     " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */
-			     ".previous\n"
-			     ".section .altinstr_replacement,\"ax\"\n"
-			     "3: movb $1,%0\n"
-			     "4:\n"
-			     ".previous\n"
-			     : "=qm" (flag) : "i" (bit));
-		return flag;
-
-#endif /* CC_HAVE_ASM_GOTO */
-}
-
-#define static_cpu_has(bit)					\
-(								\
-	__builtin_constant_p(boot_cpu_has(bit)) ?		\
-		boot_cpu_has(bit) :				\
-	__builtin_constant_p(bit) ?				\
-		__static_cpu_has(bit) :				\
-		boot_cpu_has(bit)				\
-)
-
-static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
+static __always_inline __pure bool _static_cpu_has(u16 bit)
 {
-#ifdef CC_HAVE_ASM_GOTO
-		asm_volatile_goto("1: jmp %l[t_dynamic]\n"
+		asm_volatile_goto("1: jmp 6f\n"
 			 "2:\n"
 			 ".skip -(((5f-4f) - (2b-1b)) > 0) * "
 			         "((5f-4f) - (2b-1b)),0x90\n"
@@ -529,66 +202,34 @@
 			 " .byte 0\n"			/* repl len */
 			 " .byte 0\n"			/* pad len */
 			 ".previous\n"
-			 : : "i" (bit), "i" (X86_FEATURE_ALWAYS)
-			 : : t_dynamic, t_no);
+			 ".section .altinstr_aux,\"ax\"\n"
+			 "6:\n"
+			 " testb %[bitnum],%[cap_byte]\n"
+			 " jnz %l[t_yes]\n"
+			 " jmp %l[t_no]\n"
+			 ".previous\n"
+			 : : "i" (bit), "i" (X86_FEATURE_ALWAYS),
+			     [bitnum] "i" (1 << (bit & 7)),
+			     [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3])
+			 : : t_yes, t_no);
+	t_yes:
 		return true;
 	t_no:
 		return false;
-	t_dynamic:
-		return __static_cpu_has_safe(bit);
-#else
-		u8 flag;
-		/* Open-coded due to __stringify() in ALTERNATIVE() */
-		asm volatile("1: movb $2,%0\n"
-			     "2:\n"
-			     ".section .altinstructions,\"a\"\n"
-			     " .long 1b - .\n"		/* src offset */
-			     " .long 3f - .\n"		/* repl offset */
-			     " .word %P2\n"		/* always replace */
-			     " .byte 2b - 1b\n"		/* source len */
-			     " .byte 4f - 3f\n"		/* replacement len */
-			     " .byte 0\n"		/* pad len */
-			     ".previous\n"
-			     ".section .discard,\"aw\",@progbits\n"
-			     " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */
-			     ".previous\n"
-			     ".section .altinstr_replacement,\"ax\"\n"
-			     "3: movb $0,%0\n"
-			     "4:\n"
-			     ".previous\n"
-			     ".section .altinstructions,\"a\"\n"
-			     " .long 1b - .\n"		/* src offset */
-			     " .long 5f - .\n"		/* repl offset */
-			     " .word %P1\n"		/* feature bit */
-			     " .byte 4b - 3b\n"		/* src len */
-			     " .byte 6f - 5f\n"		/* repl len */
-			     " .byte 0\n"		/* pad len */
-			     ".previous\n"
-			     ".section .discard,\"aw\",@progbits\n"
-			     " .byte 0xff + (6f-5f) - (4b-3b)\n" /* size check */
-			     ".previous\n"
-			     ".section .altinstr_replacement,\"ax\"\n"
-			     "5: movb $1,%0\n"
-			     "6:\n"
-			     ".previous\n"
-			     : "=qm" (flag)
-			     : "i" (bit), "i" (X86_FEATURE_ALWAYS));
-		return (flag == 2 ? __static_cpu_has_safe(bit) : flag);
-#endif /* CC_HAVE_ASM_GOTO */
 }
 
-#define static_cpu_has_safe(bit)				\
+#define static_cpu_has(bit)					\
 (								\
 	__builtin_constant_p(boot_cpu_has(bit)) ?		\
 		boot_cpu_has(bit) :				\
-		_static_cpu_has_safe(bit)			\
+		_static_cpu_has(bit)				\
 )
 #else
 /*
- * gcc 3.x is too stupid to do the static test; fall back to dynamic.
+ * Fall back to dynamic for gcc versions which don't support asm goto. Should be
+ * a minority now anyway.
  */
 #define static_cpu_has(bit)		boot_cpu_has(bit)
-#define static_cpu_has_safe(bit)	boot_cpu_has(bit)
 #endif
 
 #define cpu_has_bug(c, bit)		cpu_has(c, (bit))
@@ -596,7 +237,6 @@
 #define clear_cpu_bug(c, bit)		clear_cpu_cap(c, (bit))
 
 #define static_cpu_has_bug(bit)		static_cpu_has((bit))
-#define static_cpu_has_bug_safe(bit)	static_cpu_has_safe((bit))
 #define boot_cpu_has_bug(bit)		cpu_has_bug(&boot_cpu_data, (bit))
 
 #define MAX_CPU_FEATURES		(NCAPINTS * 32)
--- linux-4.4.0.orig/arch/x86/include/asm/cpufeatures.h
+++ linux-4.4.0/arch/x86/include/asm/cpufeatures.h
@@ -0,0 +1,388 @@
+#ifndef _ASM_X86_CPUFEATURES_H
+#define _ASM_X86_CPUFEATURES_H
+
+#ifndef _ASM_X86_REQUIRED_FEATURES_H
+#include <asm/required-features.h>
+#endif
+
+#ifndef _ASM_X86_DISABLED_FEATURES_H
+#include <asm/disabled-features.h>
+#endif
+
+/*
+ * Defines x86 CPU feature bits
+ */
+#define NCAPINTS	20	/* N 32-bit words worth of info */
+#define NBUGINTS	2	/* N 32-bit bug flags */
+
+/*
+ * Note: If the comment begins with a quoted string, that string is used
+ * in /proc/cpuinfo instead of the macro name.  If the string is "",
+ * this feature bit is not displayed in /proc/cpuinfo at all.
+ */
+
+/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
+#define X86_FEATURE_FPU		( 0*32+ 0) /* Onboard FPU */
+#define X86_FEATURE_VME		( 0*32+ 1) /* Virtual Mode Extensions */
+#define X86_FEATURE_DE		( 0*32+ 2) /* Debugging Extensions */
+#define X86_FEATURE_PSE		( 0*32+ 3) /* Page Size Extensions */
+#define X86_FEATURE_TSC		( 0*32+ 4) /* Time Stamp Counter */
+#define X86_FEATURE_MSR		( 0*32+ 5) /* Model-Specific Registers */
+#define X86_FEATURE_PAE		( 0*32+ 6) /* Physical Address Extensions */
+#define X86_FEATURE_MCE		( 0*32+ 7) /* Machine Check Exception */
+#define X86_FEATURE_CX8		( 0*32+ 8) /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC	( 0*32+ 9) /* Onboard APIC */
+#define X86_FEATURE_SEP		( 0*32+11) /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR	( 0*32+12) /* Memory Type Range Registers */
+#define X86_FEATURE_PGE		( 0*32+13) /* Page Global Enable */
+#define X86_FEATURE_MCA		( 0*32+14) /* Machine Check Architecture */
+#define X86_FEATURE_CMOV	( 0*32+15) /* CMOV instructions */
+					  /* (plus FCMOVcc, FCOMI with FPU) */
+#define X86_FEATURE_PAT		( 0*32+16) /* Page Attribute Table */
+#define X86_FEATURE_PSE36	( 0*32+17) /* 36-bit PSEs */
+#define X86_FEATURE_PN		( 0*32+18) /* Processor serial number */
+#define X86_FEATURE_CLFLUSH	( 0*32+19) /* CLFLUSH instruction */
+#define X86_FEATURE_DS		( 0*32+21) /* "dts" Debug Store */
+#define X86_FEATURE_ACPI	( 0*32+22) /* ACPI via MSR */
+#define X86_FEATURE_MMX		( 0*32+23) /* Multimedia Extensions */
+#define X86_FEATURE_FXSR	( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */
+#define X86_FEATURE_XMM		( 0*32+25) /* "sse" */
+#define X86_FEATURE_XMM2	( 0*32+26) /* "sse2" */
+#define X86_FEATURE_SELFSNOOP	( 0*32+27) /* "ss" CPU self snoop */
+#define X86_FEATURE_HT		( 0*32+28) /* Hyper-Threading */
+#define X86_FEATURE_ACC		( 0*32+29) /* "tm" Automatic clock control */
+#define X86_FEATURE_IA64	( 0*32+30) /* IA-64 processor */
+#define X86_FEATURE_PBE		( 0*32+31) /* Pending Break Enable */
+
+/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
+/* Don't duplicate feature flags which are redundant with Intel! */
+#define X86_FEATURE_SYSCALL	( 1*32+11) /* SYSCALL/SYSRET */
+#define X86_FEATURE_MP		( 1*32+19) /* MP Capable. */
+#define X86_FEATURE_NX		( 1*32+20) /* Execute Disable */
+#define X86_FEATURE_MMXEXT	( 1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_FXSR_OPT	( 1*32+25) /* FXSAVE/FXRSTOR optimizations */
+#define X86_FEATURE_GBPAGES	( 1*32+26) /* "pdpe1gb" GB pages */
+#define X86_FEATURE_RDTSCP	( 1*32+27) /* RDTSCP */
+#define X86_FEATURE_LM		( 1*32+29) /* Long Mode (x86-64) */
+#define X86_FEATURE_3DNOWEXT	( 1*32+30) /* AMD 3DNow! extensions */
+#define X86_FEATURE_3DNOW	( 1*32+31) /* 3DNow! */
+
+/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
+#define X86_FEATURE_RECOVERY	( 2*32+ 0) /* CPU in recovery mode */
+#define X86_FEATURE_LONGRUN	( 2*32+ 1) /* Longrun power control */
+#define X86_FEATURE_LRTI	( 2*32+ 3) /* LongRun table interface */
+
+/* Other features, Linux-defined mapping, word 3 */
+/* This range is used for feature bits which conflict or are synthesized */
+#define X86_FEATURE_CXMMX	( 3*32+ 0) /* Cyrix MMX extensions */
+#define X86_FEATURE_K6_MTRR	( 3*32+ 1) /* AMD K6 nonstandard MTRRs */
+#define X86_FEATURE_CYRIX_ARR	( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */
+#define X86_FEATURE_CENTAUR_MCR	( 3*32+ 3) /* Centaur MCRs (= MTRRs) */
+/* cpu types for specific tunings: */
+#define X86_FEATURE_K8		( 3*32+ 4) /* "" Opteron, Athlon64 */
+#define X86_FEATURE_K7		( 3*32+ 5) /* "" Athlon */
+#define X86_FEATURE_P3		( 3*32+ 6) /* "" P3 */
+#define X86_FEATURE_P4		( 3*32+ 7) /* "" P4 */
+#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */
+#define X86_FEATURE_UP		( 3*32+ 9) /* smp kernel running on up */
+#define X86_FEATURE_ART		( 3*32+10) /* Platform has always running timer (ART) */
+#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */
+#define X86_FEATURE_PEBS	( 3*32+12) /* Precise-Event Based Sampling */
+#define X86_FEATURE_BTS		( 3*32+13) /* Branch Trace Store */
+#define X86_FEATURE_SYSCALL32	( 3*32+14) /* "" syscall in ia32 userspace */
+#define X86_FEATURE_SYSENTER32	( 3*32+15) /* "" sysenter in ia32 userspace */
+#define X86_FEATURE_REP_GOOD	( 3*32+16) /* rep microcode works well */
+#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" Mfence synchronizes RDTSC */
+#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" Lfence synchronizes RDTSC */
+/* free, was #define X86_FEATURE_11AP	( 3*32+19) * "" Bad local APIC aka 11AP */
+#define X86_FEATURE_NOPL	( 3*32+20) /* The NOPL (0F 1F) instructions */
+#define X86_FEATURE_ALWAYS	( 3*32+21) /* "" Always-present feature */
+#define X86_FEATURE_XTOPOLOGY	( 3*32+22) /* cpu topology enum extensions */
+#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */
+#define X86_FEATURE_NONSTOP_TSC	( 3*32+24) /* TSC does not stop in C states */
+/* free, was #define X86_FEATURE_CLFLUSH_MONITOR ( 3*32+25) * "" clflush reqd with monitor */
+#define X86_FEATURE_EXTD_APICID	( 3*32+26) /* has extended APICID (8 bits) */
+#define X86_FEATURE_AMD_DCM     ( 3*32+27) /* multi-node processor */
+#define X86_FEATURE_APERFMPERF	( 3*32+28) /* APERFMPERF */
+#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
+#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* TSC has known frequency */
+
+/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
+#define X86_FEATURE_XMM3	( 4*32+ 0) /* "pni" SSE-3 */
+#define X86_FEATURE_PCLMULQDQ	( 4*32+ 1) /* PCLMULQDQ instruction */
+#define X86_FEATURE_DTES64	( 4*32+ 2) /* 64-bit Debug Store */
+#define X86_FEATURE_MWAIT	( 4*32+ 3) /* "monitor" Monitor/Mwait support */
+#define X86_FEATURE_DSCPL	( 4*32+ 4) /* "ds_cpl" CPL Qual. Debug Store */
+#define X86_FEATURE_VMX		( 4*32+ 5) /* Hardware virtualization */
+#define X86_FEATURE_SMX		( 4*32+ 6) /* Safer mode */
+#define X86_FEATURE_EST		( 4*32+ 7) /* Enhanced SpeedStep */
+#define X86_FEATURE_TM2		( 4*32+ 8) /* Thermal Monitor 2 */
+#define X86_FEATURE_SSSE3	( 4*32+ 9) /* Supplemental SSE-3 */
+#define X86_FEATURE_CID		( 4*32+10) /* Context ID */
+#define X86_FEATURE_SDBG	( 4*32+11) /* Silicon Debug */
+#define X86_FEATURE_FMA		( 4*32+12) /* Fused multiply-add */
+#define X86_FEATURE_CX16	( 4*32+13) /* CMPXCHG16B */
+#define X86_FEATURE_XTPR	( 4*32+14) /* Send Task Priority Messages */
+#define X86_FEATURE_PDCM	( 4*32+15) /* Performance Capabilities */
+#define X86_FEATURE_PCID	( 4*32+17) /* Process Context Identifiers */
+#define X86_FEATURE_DCA		( 4*32+18) /* Direct Cache Access */
+#define X86_FEATURE_XMM4_1	( 4*32+19) /* "sse4_1" SSE-4.1 */
+#define X86_FEATURE_XMM4_2	( 4*32+20) /* "sse4_2" SSE-4.2 */
+#define X86_FEATURE_X2APIC	( 4*32+21) /* x2APIC */
+#define X86_FEATURE_MOVBE	( 4*32+22) /* MOVBE instruction */
+#define X86_FEATURE_POPCNT      ( 4*32+23) /* POPCNT instruction */
+#define X86_FEATURE_TSC_DEADLINE_TIMER	( 4*32+24) /* Tsc deadline timer */
+#define X86_FEATURE_AES		( 4*32+25) /* AES instructions */
+#define X86_FEATURE_XSAVE	( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
+#define X86_FEATURE_OSXSAVE	( 4*32+27) /* "" XSAVE enabled in the OS */
+#define X86_FEATURE_AVX		( 4*32+28) /* Advanced Vector Extensions */
+#define X86_FEATURE_F16C	( 4*32+29) /* 16-bit fp conversions */
+#define X86_FEATURE_RDRAND	( 4*32+30) /* The RDRAND instruction */
+#define X86_FEATURE_HYPERVISOR	( 4*32+31) /* Running on a hypervisor */
+
+/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
+#define X86_FEATURE_XSTORE	( 5*32+ 2) /* "rng" RNG present (xstore) */
+#define X86_FEATURE_XSTORE_EN	( 5*32+ 3) /* "rng_en" RNG enabled */
+#define X86_FEATURE_XCRYPT	( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */
+#define X86_FEATURE_XCRYPT_EN	( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */
+#define X86_FEATURE_ACE2	( 5*32+ 8) /* Advanced Cryptography Engine v2 */
+#define X86_FEATURE_ACE2_EN	( 5*32+ 9) /* ACE v2 enabled */
+#define X86_FEATURE_PHE		( 5*32+10) /* PadLock Hash Engine */
+#define X86_FEATURE_PHE_EN	( 5*32+11) /* PHE enabled */
+#define X86_FEATURE_PMM		( 5*32+12) /* PadLock Montgomery Multiplier */
+#define X86_FEATURE_PMM_EN	( 5*32+13) /* PMM enabled */
+
+/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
+#define X86_FEATURE_LAHF_LM	( 6*32+ 0) /* LAHF/SAHF in long mode */
+#define X86_FEATURE_CMP_LEGACY	( 6*32+ 1) /* If yes HyperThreading not valid */
+#define X86_FEATURE_SVM		( 6*32+ 2) /* Secure virtual machine */
+#define X86_FEATURE_EXTAPIC	( 6*32+ 3) /* Extended APIC space */
+#define X86_FEATURE_CR8_LEGACY	( 6*32+ 4) /* CR8 in 32-bit mode */
+#define X86_FEATURE_ABM		( 6*32+ 5) /* Advanced bit manipulation */
+#define X86_FEATURE_SSE4A	( 6*32+ 6) /* SSE-4A */
+#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* Misaligned SSE mode */
+#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* 3DNow prefetch instructions */
+#define X86_FEATURE_OSVW	( 6*32+ 9) /* OS Visible Workaround */
+#define X86_FEATURE_IBS		( 6*32+10) /* Instruction Based Sampling */
+#define X86_FEATURE_XOP		( 6*32+11) /* extended AVX instructions */
+#define X86_FEATURE_SKINIT	( 6*32+12) /* SKINIT/STGI instructions */
+#define X86_FEATURE_WDT		( 6*32+13) /* Watchdog timer */
+#define X86_FEATURE_LWP		( 6*32+15) /* Light Weight Profiling */
+#define X86_FEATURE_FMA4	( 6*32+16) /* 4 operands MAC instructions */
+#define X86_FEATURE_TCE		( 6*32+17) /* translation cache extension */
+#define X86_FEATURE_NODEID_MSR	( 6*32+19) /* NodeId MSR */
+#define X86_FEATURE_TBM		( 6*32+21) /* trailing bit manipulations */
+#define X86_FEATURE_TOPOEXT	( 6*32+22) /* topology extensions CPUID leafs */
+#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */
+#define X86_FEATURE_PERFCTR_NB  ( 6*32+24) /* NB performance counter extensions */
+#define X86_FEATURE_BPEXT	(6*32+26) /* data breakpoint extension */
+#define X86_FEATURE_PERFCTR_L2	( 6*32+28) /* L2 performance counter extensions */
+#define X86_FEATURE_MWAITX	( 6*32+29) /* MWAIT extension (MONITORX/MWAITX) */
+
+/*
+ * Auxiliary flags: Linux defined - For features scattered in various
+ * CPUID levels like 0x6, 0xA etc, word 7.
+ *
+ * Reuse free bits when adding new feature flags!
+ */
+
+#define X86_FEATURE_CPB		( 7*32+ 2) /* AMD Core Performance Boost */
+#define X86_FEATURE_EPB		( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
+#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 4) /* Effectively INVPCID && CR4.PCIDE=1 */
+
+#define X86_FEATURE_HW_PSTATE	( 7*32+ 8) /* AMD HW-PState */
+#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
+
+#define X86_FEATURE_KERNEL_IBRS		( 7*32+12) /* "" Set/clear IBRS on kernel entry/exit */
+#define X86_FEATURE_RSB_VMEXIT		( 7*32+13) /* "" Fill RSB on VM-Exit */
+
+#define X86_FEATURE_INTEL_PT	( 7*32+15) /* Intel Processor Trace */
+#define X86_FEATURE_MSR_SPEC_CTRL	( 7*32+16) /* "" MSR SPEC_CTRL is implemented */
+#define X86_FEATURE_SSBD		( 7*32+17) /* Speculative Store Bypass Disable */
+
+#define X86_FEATURE_USE_IBPB	( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
+#define X86_FEATURE_USE_IBRS_FW		( 7*32+22) /* "" Use IBRS during runtime firmware calls */
+#define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE	( 7*32+23) /* "" Disable Speculative Store Bypass. */
+#define X86_FEATURE_LS_CFG_SSBD		( 7*32+24)  /* "" AMD SSBD implementation via LS_CFG MSR */
+#define X86_FEATURE_IBRS		( 7*32+25) /* Indirect Branch Restricted Speculation */
+#define X86_FEATURE_IBPB		( 7*32+26) /* Indirect Branch Prediction Barrier */
+#define X86_FEATURE_STIBP		( 7*32+27) /* Single Thread Indirect Branch Predictors */
+#define X86_FEATURE_ZEN			( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */
+#define X86_FEATURE_L1TF_PTEINV		( 7*32+29) /* "" L1TF workaround PTE inversion */
+#define X86_FEATURE_IBRS_ENHANCED	( 7*32+30) /* Enhanced IBRS */
+#define X86_FEATURE_KAISER     ( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */
+
+#define X86_FEATURE_RSB_CTXSW	( 7*32+19) /* "" Fill RSB on context switches */
+
+/* Virtualization flags: Linux defined, word 8 */
+#define X86_FEATURE_TPR_SHADOW  ( 8*32+ 0) /* Intel TPR Shadow */
+#define X86_FEATURE_VNMI        ( 8*32+ 1) /* Intel Virtual NMI */
+#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */
+#define X86_FEATURE_EPT         ( 8*32+ 3) /* Intel Extended Page Table */
+#define X86_FEATURE_VPID        ( 8*32+ 4) /* Intel Virtual Processor ID */
+
+#define X86_FEATURE_VMMCALL     ( 8*32+15) /* Prefer vmmcall to vmcall */
+#define X86_FEATURE_XENPV       ( 8*32+16) /* "" Xen paravirtual guest */
+
+
+
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
+#define X86_FEATURE_FSGSBASE	( 9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
+#define X86_FEATURE_TSC_ADJUST	( 9*32+ 1) /* TSC adjustment MSR 0x3b */
+#define X86_FEATURE_BMI1	( 9*32+ 3) /* 1st group bit manipulation extensions */
+#define X86_FEATURE_HLE		( 9*32+ 4) /* Hardware Lock Elision */
+#define X86_FEATURE_AVX2	( 9*32+ 5) /* AVX2 instructions */
+#define X86_FEATURE_SMEP	( 9*32+ 7) /* Supervisor Mode Execution Protection */
+#define X86_FEATURE_BMI2	( 9*32+ 8) /* 2nd group bit manipulation extensions */
+#define X86_FEATURE_ERMS	( 9*32+ 9) /* Enhanced REP MOVSB/STOSB */
+#define X86_FEATURE_INVPCID	( 9*32+10) /* Invalidate Processor Context ID */
+#define X86_FEATURE_RTM		( 9*32+11) /* Restricted Transactional Memory */
+#define X86_FEATURE_CQM		( 9*32+12) /* Cache QoS Monitoring */
+#define X86_FEATURE_MPX		( 9*32+14) /* Memory Protection Extension */
+#define X86_FEATURE_AVX512F	( 9*32+16) /* AVX-512 Foundation */
+#define X86_FEATURE_RDSEED	( 9*32+18) /* The RDSEED instruction */
+#define X86_FEATURE_ADX		( 9*32+19) /* The ADCX and ADOX instructions */
+#define X86_FEATURE_SMAP	( 9*32+20) /* Supervisor Mode Access Prevention */
+#define X86_FEATURE_PCOMMIT	( 9*32+22) /* PCOMMIT instruction */
+#define X86_FEATURE_CLFLUSHOPT	( 9*32+23) /* CLFLUSHOPT instruction */
+#define X86_FEATURE_CLWB	( 9*32+24) /* CLWB instruction */
+#define X86_FEATURE_AVX512PF	( 9*32+26) /* AVX-512 Prefetch */
+#define X86_FEATURE_AVX512ER	( 9*32+27) /* AVX-512 Exponential and Reciprocal */
+#define X86_FEATURE_AVX512CD	( 9*32+28) /* AVX-512 Conflict Detection */
+#define X86_FEATURE_SHA_NI	( 9*32+29) /* SHA1/SHA256 Instruction Extensions */
+
+/* Extended state features, CPUID level 0x0000000d:1 (eax), word 10 */
+#define X86_FEATURE_XSAVEOPT	(10*32+ 0) /* XSAVEOPT */
+#define X86_FEATURE_XSAVEC	(10*32+ 1) /* XSAVEC */
+#define X86_FEATURE_XGETBV1	(10*32+ 2) /* XGETBV with ECX = 1 */
+#define X86_FEATURE_XSAVES	(10*32+ 3) /* XSAVES/XRSTORS */
+
+/*
+ * Extended auxiliary flags: Linux defined - for features scattered in various
+ * CPUID levels like 0xf, etc.
+ *
+ * Reuse free bits when adding new feature flags!
+ */
+#define X86_FEATURE_CQM_LLC		(11*32+ 0) /* LLC QoS if 1 */
+#define X86_FEATURE_CQM_OCCUP_LLC	(11*32+ 1) /* LLC occupancy monitoring */
+#define X86_FEATURE_CQM_MBM_TOTAL	(11*32+ 2) /* LLC Total MBM monitoring */
+#define X86_FEATURE_CQM_MBM_LOCAL	(11*32+ 3) /* LLC Local MBM monitoring */
+#define X86_FEATURE_FENCE_SWAPGS_USER	(11*32+ 4) /* "" LFENCE in user entry SWAPGS path */
+#define X86_FEATURE_FENCE_SWAPGS_KERNEL	(11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
+/* FREE!				(11*32+ 6) */
+/* FREE!				(11*32+ 7) */
+/* FREE!				(11*32+ 8) */
+/* FREE!				(11*32+ 9) */
+/* FREE!				(11*32+10) */
+#define X86_FEATURE_RRSBA_CTRL		(11*32+11) /* "" RET prediction control */
+#define X86_FEATURE_RETPOLINE		(11*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_LFENCE	(11*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_RSB_VMEXIT_LITE	(11*32+17) /* "" Fill RSB on VM exit when EIBRS is enabled */
+
+/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
+#define X86_FEATURE_CLZERO	(13*32+0) /* CLZERO instruction */
+#define X86_FEATURE_AMD_IBPB	(13*32+12) /* "" Indirect Branch Prediction Barrier */
+#define X86_FEATURE_AMD_IBRS	(13*32+14) /* "" Indirect Branch Restricted Speculation */
+#define X86_FEATURE_AMD_STIBP	(13*32+15) /* "" Single Thread Indirect Branch Predictors */
+#define X86_FEATURE_AMD_STIBP_ALWAYS_ON	(13*32+17) /* "" Single Thread Indirect Branch Predictors always-on preferred */
+#define X86_FEATURE_AMD_SSBD	(13*32+24) /* "" Speculative Store Bypass Disable */
+#define X86_FEATURE_VIRT_SSBD	(13*32+25) /* Virtualized Speculative Store Bypass Disable */
+#define X86_FEATURE_AMD_SSB_NO	(13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
+#define X86_FEATURE_BTC_NO		(13*32+29) /* "" Not vulnerable to Branch Type Confusion */
+
+/* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */
+#define X86_FEATURE_DTHERM	(14*32+ 0) /* Digital Thermal Sensor */
+#define X86_FEATURE_IDA		(14*32+ 1) /* Intel Dynamic Acceleration */
+#define X86_FEATURE_ARAT	(14*32+ 2) /* Always Running APIC Timer */
+#define X86_FEATURE_PLN		(14*32+ 4) /* Intel Power Limit Notification */
+#define X86_FEATURE_PTS		(14*32+ 6) /* Intel Package Thermal Status */
+#define X86_FEATURE_HWP		(14*32+ 7) /* Intel Hardware P-states */
+#define X86_FEATURE_HWP_NOTIFY	(14*32+ 8) /* HWP Notification */
+#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */
+#define X86_FEATURE_HWP_EPP	(14*32+10) /* HWP Energy Perf. Preference */
+#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */
+
+/* AMD SVM Feature Identification, CPUID level 0x8000000a (edx), word 15 */
+#define X86_FEATURE_NPT		(15*32+ 0) /* Nested Page Table support */
+#define X86_FEATURE_LBRV	(15*32+ 1) /* LBR Virtualization support */
+#define X86_FEATURE_SVML	(15*32+ 2) /* "svm_lock" SVM locking MSR */
+#define X86_FEATURE_NRIPS	(15*32+ 3) /* "nrip_save" SVM next_rip save */
+#define X86_FEATURE_TSCRATEMSR  (15*32+ 4) /* "tsc_scale" TSC scaling support */
+#define X86_FEATURE_VMCBCLEAN   (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */
+#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */
+#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */
+#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */
+#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */
+#define X86_FEATURE_AVIC	(15*32+13) /* Virtual Interrupt Controller */
+
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */
+#define X86_FEATURE_PKU		(16*32+ 3) /* Protection Keys for Userspace */
+#define X86_FEATURE_OSPKE	(16*32+ 4) /* OS Protection Keys Enable */
+#define X86_FEATURE_RDPID	(16*32+ 22) /* RDPID instruction */
+
+/* AMD-defined CPU features, CPUID level 0x80000007 (ebx), word 17 */
+#define X86_FEATURE_OVERFLOW_RECOV (17*32+0) /* MCA overflow recovery support */
+#define X86_FEATURE_SUCCOR	(17*32+1) /* Uncorrectable error containment and recovery */
+#define X86_FEATURE_SMCA	(17*32+3) /* Scalable MCA */
+
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
+#define X86_FEATURE_AVX512_4VNNIW	(18*32+ 2) /* AVX-512 Neural Network Instructions */
+#define X86_FEATURE_AVX512_4FMAPS	(18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_SRBDS_CTRL		(18*32+ 9) /* "" SRBDS mitigation MSR available */
+#define X86_FEATURE_MD_CLEAR		(18*32+10) /* VERW clears CPU buffers */
+#define X86_FEATURE_SPEC_CTRL		(18*32+26) /* "" Speculation Control (IBRS + IBPB) */
+#define X86_FEATURE_INTEL_STIBP		(18*32+27) /* "" Single Thread Indirect Branch Predictors */
+#define X86_FEATURE_FLUSH_L1D		(18*32+28) /* Flush L1D cache */
+#define X86_FEATURE_ARCH_CAPABILITIES	(18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
+#define X86_FEATURE_SPEC_CTRL_SSBD	(18*32+31) /* "" Speculative Store Bypass Disable */
+
+/*
+ * Extended auxiliary flags: Linux defined - for features scattered in various
+ * CPUID levels like 0x80000022, etc and Linux defined features.
+ *
+ * Reuse free bits when adding new feature flags!
+ */
+#define X86_FEATURE_CLEAR_BHB_LOOP	(19*32+ 1) /* "" Clear branch history at syscall entry using SW loop */
+#define X86_FEATURE_BHI_CTRL		(19*32+ 2) /* "" BHI_DIS_S HW control available */
+#define X86_FEATURE_CLEAR_BHB_HW	(19*32+ 3) /* "" BHI_DIS_S HW control enabled */
+#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (19*32+ 4) /* "" Clear branch history at vmexit using SW loop */
+#define X86_FEATURE_IBPB_EXIT_TO_USER	(19*32+15) /* Use IBPB on exit-to-userspace, see VMSCAPE bug */
+
+/*
+ * BUG word(s)
+ */
+#define X86_BUG(x)		(NCAPINTS*32 + (x))
+
+#define X86_BUG_F00F		X86_BUG(0) /* Intel F00F */
+#define X86_BUG_FDIV		X86_BUG(1) /* FPU FDIV */
+#define X86_BUG_COMA		X86_BUG(2) /* Cyrix 6x86 coma */
+#define X86_BUG_AMD_TLB_MMATCH	X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */
+#define X86_BUG_AMD_APIC_C1E	X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */
+#define X86_BUG_11AP		X86_BUG(5) /* Bad local APIC aka 11AP */
+#define X86_BUG_FXSAVE_LEAK	X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */
+#define X86_BUG_CLFLUSH_MONITOR	X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */
+#define X86_BUG_SYSRET_SS_ATTRS	X86_BUG(8) /* SYSRET doesn't fix up SS attrs */
+
+#define X86_BUG_MONITOR		X86_BUG(12) /* IPI required to wake up remote CPU */
+#define X86_BUG_CPU_MELTDOWN		X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */
+#define X86_BUG_SPECTRE_V1		X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */
+#define X86_BUG_SPECTRE_V2		X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */
+#define X86_BUG_SPEC_STORE_BYPASS	X86_BUG(17) /* CPU is affected by speculative store bypass attack */
+#define X86_BUG_L1TF			X86_BUG(18) /* CPU is affected by L1 Terminal Fault */
+#define X86_BUG_MDS			X86_BUG(19) /* CPU is affected by Microarchitectural data sampling */
+#define X86_BUG_MSBDS_ONLY		X86_BUG(20) /* CPU is only affected by the  MSDBS variant of BUG_MDS */
+#define X86_BUG_SWAPGS			X86_BUG(21) /* CPU is affected by speculation through SWAPGS */
+#define X86_BUG_TAA			X86_BUG(22) /* CPU is affected by TSX Async Abort(TAA) */
+#define X86_BUG_ITLB_MULTIHIT		X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
+#define X86_BUG_SRBDS			X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
+#define X86_BUG_MMIO_STALE_DATA		X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
+#define X86_BUG_RETBLEED		X86_BUG(27) /* CPU is affected by RETBleed */
+#define X86_BUG_EIBRS_PBRSB		X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
+#define X86_BUG_SMT_RSB			X86_BUG(29) /* CPU is vulnerable to Cross-Thread Return Address Predictions */
+#define X86_BUG_GDS			X86_BUG(30) /* CPU is affected by Gather Data Sampling */
+
+/* BUG word 2 */
+#define X86_BUG_DIV0			X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */
+#define X86_BUG_BHI			X86_BUG(1*32 + 3) /* CPU is affected by Branch History Injection */
+#define X86_BUG_VMSCAPE			X86_BUG(1*32 + 10) /* CPU is affected by VMSCAPE attacks from guests */
+#endif /* _ASM_X86_CPUFEATURES_H */
--- linux-4.4.0.orig/arch/x86/include/asm/crash.h
+++ linux-4.4.0/arch/x86/include/asm/crash.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_CRASH_H
 #define _ASM_X86_CRASH_H
 
+struct kimage;
+
 int crash_load_segments(struct kimage *image);
 int crash_copy_backup_region(struct kimage *image);
 int crash_setup_memmap_entries(struct kimage *image,
--- linux-4.4.0.orig/arch/x86/include/asm/desc.h
+++ linux-4.4.0/arch/x86/include/asm/desc.h
@@ -43,7 +43,7 @@
 	struct desc_struct gdt[GDT_ENTRIES];
 } __attribute__((aligned(PAGE_SIZE)));
 
-DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page);
+DECLARE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(struct gdt_page, gdt_page);
 
 static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
 {
--- linux-4.4.0.orig/arch/x86/include/asm/disabled-features.h
+++ linux-4.4.0/arch/x86/include/asm/disabled-features.h
@@ -21,13 +21,29 @@
 # define DISABLE_K6_MTRR	(1<<(X86_FEATURE_K6_MTRR & 31))
 # define DISABLE_CYRIX_ARR	(1<<(X86_FEATURE_CYRIX_ARR & 31))
 # define DISABLE_CENTAUR_MCR	(1<<(X86_FEATURE_CENTAUR_MCR & 31))
+# define DISABLE_PCID		0
 #else
 # define DISABLE_VME		0
 # define DISABLE_K6_MTRR	0
 # define DISABLE_CYRIX_ARR	0
 # define DISABLE_CENTAUR_MCR	0
+# define DISABLE_PCID		(1<<(X86_FEATURE_PCID & 31))
 #endif /* CONFIG_X86_64 */
 
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+# define DISABLE_PKU		0
+# define DISABLE_OSPKE		0
+#else
+# define DISABLE_PKU		(1<<(X86_FEATURE_PKU & 31))
+# define DISABLE_OSPKE		(1<<(X86_FEATURE_OSPKE & 31))
+#endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+# define DISABLE_KAISER		0
+#else
+# define DISABLE_KAISER		(1 << (X86_FEATURE_KAISER & 31))
+#endif
+
 /*
  * Make sure to add features to the correct mask
  */
@@ -35,11 +51,22 @@
 #define DISABLED_MASK1	0
 #define DISABLED_MASK2	0
 #define DISABLED_MASK3	(DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR)
-#define DISABLED_MASK4	0
+#define DISABLED_MASK4	(DISABLE_PCID)
 #define DISABLED_MASK5	0
 #define DISABLED_MASK6	0
-#define DISABLED_MASK7	0
+#define DISABLED_MASK7	(DISABLE_KAISER)
 #define DISABLED_MASK8	0
 #define DISABLED_MASK9	(DISABLE_MPX)
+#define DISABLED_MASK10	0
+#define DISABLED_MASK11	0
+#define DISABLED_MASK12	0
+#define DISABLED_MASK13	0
+#define DISABLED_MASK14	0
+#define DISABLED_MASK15	0
+#define DISABLED_MASK16	0
+#define DISABLED_MASK17	0
+#define DISABLED_MASK18	0
+#define DISABLED_MASK19	0
+#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 20)
 
 #endif /* _ASM_X86_DISABLED_FEATURES_H */
--- linux-4.4.0.orig/arch/x86/include/asm/dma.h
+++ linux-4.4.0/arch/x86/include/asm/dma.h
@@ -73,7 +73,7 @@
 #define MAX_DMA_PFN   ((16UL * 1024 * 1024) >> PAGE_SHIFT)
 
 /* 4GB broken PCI/AGP hardware bus master zone */
-#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT)
+#define MAX_DMA32_PFN (1UL << (32 - PAGE_SHIFT))
 
 #ifdef CONFIG_X86_32
 /* The maximum address that we can perform a DMA transfer to on this platform */
--- linux-4.4.0.orig/arch/x86/include/asm/dmi.h
+++ linux-4.4.0/arch/x86/include/asm/dmi.h
@@ -3,8 +3,8 @@
 
 #include <linux/compiler.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/setup.h>
 
 static __always_inline __init void *dmi_alloc(unsigned len)
--- linux-4.4.0.orig/arch/x86/include/asm/efi.h
+++ linux-4.4.0/arch/x86/include/asm/efi.h
@@ -3,6 +3,7 @@
 
 #include <asm/fpu/api.h>
 #include <asm/pgtable.h>
+#include <asm/nospec-branch.h>
 
 /*
  * We map the EFI regions needed for runtime services non-contiguously,
@@ -39,8 +40,10 @@
 ({									\
 	efi_status_t __s;						\
 	kernel_fpu_begin();						\
+	firmware_restrict_branch_speculation_start();			\
 	__s = ((efi_##f##_t __attribute__((regparm(0)))*)		\
 		efi.systab->runtime->f)(args);				\
+	firmware_restrict_branch_speculation_end();			\
 	kernel_fpu_end();						\
 	__s;								\
 })
@@ -49,8 +52,10 @@
 #define __efi_call_virt(f, args...) \
 ({									\
 	kernel_fpu_begin();						\
+	firmware_restrict_branch_speculation_start();			\
 	((efi_##f##_t __attribute__((regparm(0)))*)			\
 		efi.systab->runtime->f)(args);				\
+	firmware_restrict_branch_speculation_end();			\
 	kernel_fpu_end();						\
 })
 
@@ -71,7 +76,9 @@
 	efi_sync_low_kernel_mappings();					\
 	preempt_disable();						\
 	__kernel_fpu_begin();						\
+	firmware_restrict_branch_speculation_start();			\
 	__s = efi_call((void *)efi.systab->runtime->f, __VA_ARGS__);	\
+	firmware_restrict_branch_speculation_end();			\
 	__kernel_fpu_end();						\
 	preempt_enable();						\
 	__s;								\
--- linux-4.4.0.orig/arch/x86/include/asm/elf.h
+++ linux-4.4.0/arch/x86/include/asm/elf.h
@@ -204,6 +204,7 @@
 
 #define ELF_CORE_COPY_REGS(pr_reg, regs)			\
 do {								\
+	unsigned long base;					\
 	unsigned v;						\
 	(pr_reg)[0] = (regs)->r15;				\
 	(pr_reg)[1] = (regs)->r14;				\
@@ -226,8 +227,8 @@
 	(pr_reg)[18] = (regs)->flags;				\
 	(pr_reg)[19] = (regs)->sp;				\
 	(pr_reg)[20] = (regs)->ss;				\
-	(pr_reg)[21] = current->thread.fs;			\
-	(pr_reg)[22] = current->thread.gs;			\
+	rdmsrl(MSR_FS_BASE, base); (pr_reg)[21] = base;		\
+	rdmsrl(MSR_KERNEL_GS_BASE, base); (pr_reg)[22] = base;	\
 	asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v;	\
 	asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v;	\
 	asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v;	\
@@ -245,12 +246,13 @@
 #define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE	4096
 
-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
-   use of this is to invoke "./ld.so someprog" to test out a new version of
-   the loader.  We need to make sure that it is out of the way of the program
-   that it will "exec", and that there is sufficient room for the brk.  */
-
-#define ELF_ET_DYN_BASE		(TASK_SIZE / 3 * 2)
+/*
+ * This is the base location for PIE (ET_DYN with INTERP) loads. On
+ * 64-bit, this is above 4GB to leave the entire 32-bit address
+ * space open for things that want to use the area for 32-bit pointers.
+ */
+#define ELF_ET_DYN_BASE		(mmap_is_ia32() ? 0x000400000UL : \
+						  (TASK_SIZE / 3 * 2))
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports.  This could be done in user space,
@@ -278,7 +280,7 @@
 
 #define	ARCH_DLINFO_IA32						\
 do {									\
-	if (vdso32_enabled) {						\
+	if (VDSO_CURRENT_BASE) {					\
 		NEW_AUX_ENT(AT_SYSINFO,	VDSO_ENTRY);			\
 		NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE);	\
 	}								\
--- linux-4.4.0.orig/arch/x86/include/asm/fixmap.h
+++ linux-4.4.0/arch/x86/include/asm/fixmap.h
@@ -147,7 +147,7 @@
 extern pte_t *pkmap_page_table;
 
 void __native_set_fixmap(enum fixed_addresses idx, pte_t pte);
-void native_set_fixmap(enum fixed_addresses idx,
+void native_set_fixmap(unsigned /* enum fixed_addresses */ idx,
 		       phys_addr_t phys, pgprot_t flags);
 
 #ifndef CONFIG_PARAVIRT
--- linux-4.4.0.orig/arch/x86/include/asm/fpu/internal.h
+++ linux-4.4.0/arch/x86/include/asm/fpu/internal.h
@@ -17,6 +17,7 @@
 #include <asm/user.h>
 #include <asm/fpu/api.h>
 #include <asm/fpu/xstate.h>
+#include <asm/cpufeature.h>
 
 /*
  * High level FPU state handling functions:
@@ -42,6 +43,7 @@
 extern void fpu__init_system(struct cpuinfo_x86 *c);
 extern void fpu__init_check_bugs(void);
 extern void fpu__resume_cpu(void);
+extern u64 fpu__get_supported_xfeatures_mask(void);
 
 /*
  * Debugging facility:
@@ -55,24 +57,19 @@
 /*
  * FPU related CPU feature flag helper routines:
  */
-static __always_inline __pure bool use_eager_fpu(void)
-{
-	return static_cpu_has_safe(X86_FEATURE_EAGER_FPU);
-}
-
 static __always_inline __pure bool use_xsaveopt(void)
 {
-	return static_cpu_has_safe(X86_FEATURE_XSAVEOPT);
+	return static_cpu_has(X86_FEATURE_XSAVEOPT);
 }
 
 static __always_inline __pure bool use_xsave(void)
 {
-	return static_cpu_has_safe(X86_FEATURE_XSAVE);
+	return static_cpu_has(X86_FEATURE_XSAVE);
 }
 
 static __always_inline __pure bool use_fxsr(void)
 {
-	return static_cpu_has_safe(X86_FEATURE_FXSR);
+	return static_cpu_has(X86_FEATURE_FXSR);
 }
 
 /*
@@ -97,6 +94,9 @@
 #define user_insn(insn, output, input...)				\
 ({									\
 	int err;							\
+									\
+	might_fault();							\
+									\
 	asm volatile(ASM_STAC "\n"					\
 		     "1:" #insn "\n\t"					\
 		     "2: " ASM_CLAC "\n"				\
@@ -224,18 +224,67 @@
 #define XRSTOR		".byte " REX_PREFIX "0x0f,0xae,0x2f"
 #define XRSTORS		".byte " REX_PREFIX "0x0f,0xc7,0x1f"
 
-/* xstate instruction fault handler: */
-#define xstate_fault(__err)		\
-					\
-	".section .fixup,\"ax\"\n"	\
-					\
-	"3:  movl $-2,%[_err]\n"	\
-	"    jmp  2b\n"			\
-					\
-	".previous\n"			\
-					\
-	_ASM_EXTABLE(1b, 3b)		\
-	: [_err] "=r" (__err)
+#define XSTATE_OP(op, st, lmask, hmask, err)				\
+	asm volatile("1:" op "\n\t"					\
+		     "xor %[err], %[err]\n"				\
+		     "2:\n\t"						\
+		     ".pushsection .fixup,\"ax\"\n\t"			\
+		     "3: movl $-2,%[err]\n\t"				\
+		     "jmp 2b\n\t"					\
+		     ".popsection\n\t"					\
+		     _ASM_EXTABLE(1b, 3b)				\
+		     : [err] "=r" (err)					\
+		     : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)	\
+		     : "memory")
+
+/*
+ * If XSAVES is enabled, it replaces XSAVEOPT because it supports a compact
+ * format and supervisor states in addition to modified optimization in
+ * XSAVEOPT.
+ *
+ * Otherwise, if XSAVEOPT is enabled, XSAVEOPT replaces XSAVE because XSAVEOPT
+ * supports modified optimization which is not supported by XSAVE.
+ *
+ * We use XSAVE as a fallback.
+ *
+ * The 661 label is defined in the ALTERNATIVE* macros as the address of the
+ * original instruction which gets replaced. We need to use it here as the
+ * address of the instruction where we might get an exception at.
+ */
+#define XSTATE_XSAVE(st, lmask, hmask, err)				\
+	asm volatile(ALTERNATIVE_2(XSAVE,				\
+				   XSAVEOPT, X86_FEATURE_XSAVEOPT,	\
+				   XSAVES,   X86_FEATURE_XSAVES)	\
+		     "\n"						\
+		     "xor %[err], %[err]\n"				\
+		     "3:\n"						\
+		     ".pushsection .fixup,\"ax\"\n"			\
+		     "4: movl $-2, %[err]\n"				\
+		     "jmp 3b\n"						\
+		     ".popsection\n"					\
+		     _ASM_EXTABLE(661b, 4b)				\
+		     : [err] "=r" (err)					\
+		     : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)	\
+		     : "memory")
+
+/*
+ * Use XRSTORS to restore context if it is enabled. XRSTORS supports compact
+ * XSAVE area format.
+ */
+#define XSTATE_XRESTORE(st, lmask, hmask, err)				\
+	asm volatile(ALTERNATIVE(XRSTOR,				\
+				 XRSTORS, X86_FEATURE_XSAVES)		\
+		     "\n"						\
+		     "xor %[err], %[err]\n"				\
+		     "3:\n"						\
+		     ".pushsection .fixup,\"ax\"\n"			\
+		     "4: movl $-2, %[err]\n"				\
+		     "jmp 3b\n"						\
+		     ".popsection\n"					\
+		     _ASM_EXTABLE(661b, 4b)				\
+		     : [err] "=r" (err)					\
+		     : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)	\
+		     : "memory")
 
 /*
  * This function is called only during boot time when x86 caps are not set
@@ -246,22 +295,14 @@
 	u64 mask = -1;
 	u32 lmask = mask;
 	u32 hmask = mask >> 32;
-	int err = 0;
+	int err;
 
 	WARN_ON(system_state != SYSTEM_BOOTING);
 
-	if (boot_cpu_has(X86_FEATURE_XSAVES))
-		asm volatile("1:"XSAVES"\n\t"
-			"2:\n\t"
-			     xstate_fault(err)
-			: "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
-			: "memory");
+	if (static_cpu_has(X86_FEATURE_XSAVES))
+		XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
 	else
-		asm volatile("1:"XSAVE"\n\t"
-			"2:\n\t"
-			     xstate_fault(err)
-			: "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
-			: "memory");
+		XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
 
 	/* We should never fault when copying to a kernel buffer: */
 	WARN_ON_FPU(err);
@@ -276,22 +317,14 @@
 	u64 mask = -1;
 	u32 lmask = mask;
 	u32 hmask = mask >> 32;
-	int err = 0;
+	int err;
 
 	WARN_ON(system_state != SYSTEM_BOOTING);
 
-	if (boot_cpu_has(X86_FEATURE_XSAVES))
-		asm volatile("1:"XRSTORS"\n\t"
-			"2:\n\t"
-			     xstate_fault(err)
-			: "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
-			: "memory");
+	if (static_cpu_has(X86_FEATURE_XSAVES))
+		XSTATE_OP(XRSTORS, xstate, lmask, hmask, err);
 	else
-		asm volatile("1:"XRSTOR"\n\t"
-			"2:\n\t"
-			     xstate_fault(err)
-			: "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
-			: "memory");
+		XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
 
 	/* We should never fault when copying from a kernel buffer: */
 	WARN_ON_FPU(err);
@@ -305,33 +338,11 @@
 	u64 mask = -1;
 	u32 lmask = mask;
 	u32 hmask = mask >> 32;
-	int err = 0;
+	int err;
 
 	WARN_ON(!alternatives_patched);
 
-	/*
-	 * If xsaves is enabled, xsaves replaces xsaveopt because
-	 * it supports compact format and supervisor states in addition to
-	 * modified optimization in xsaveopt.
-	 *
-	 * Otherwise, if xsaveopt is enabled, xsaveopt replaces xsave
-	 * because xsaveopt supports modified optimization which is not
-	 * supported by xsave.
-	 *
-	 * If none of xsaves and xsaveopt is enabled, use xsave.
-	 */
-	alternative_input_2(
-		"1:"XSAVE,
-		XSAVEOPT,
-		X86_FEATURE_XSAVEOPT,
-		XSAVES,
-		X86_FEATURE_XSAVES,
-		[xstate] "D" (xstate), "a" (lmask), "d" (hmask) :
-		"memory");
-	asm volatile("2:\n\t"
-		     xstate_fault(err)
-		     : "0" (err)
-		     : "memory");
+	XSTATE_XSAVE(xstate, lmask, hmask, err);
 
 	/* We should never fault when copying to a kernel buffer: */
 	WARN_ON_FPU(err);
@@ -344,23 +355,9 @@
 {
 	u32 lmask = mask;
 	u32 hmask = mask >> 32;
-	int err = 0;
+	int err;
 
-	/*
-	 * Use xrstors to restore context if it is enabled. xrstors supports
-	 * compacted format of xsave area which is not supported by xrstor.
-	 */
-	alternative_input(
-		"1: " XRSTOR,
-		XRSTORS,
-		X86_FEATURE_XSAVES,
-		"D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask)
-		: "memory");
-
-	asm volatile("2:\n"
-		     xstate_fault(err)
-		     : "0" (err)
-		     : "memory");
+	XSTATE_XRESTORE(xstate, lmask, hmask, err);
 
 	/* We should never fault when copying from a kernel buffer: */
 	WARN_ON_FPU(err);
@@ -388,12 +385,10 @@
 	if (unlikely(err))
 		return -EFAULT;
 
-	__asm__ __volatile__(ASM_STAC "\n"
-			     "1:"XSAVE"\n"
-			     "2: " ASM_CLAC "\n"
-			     xstate_fault(err)
-			     : "D" (buf), "a" (-1), "d" (-1), "0" (err)
-			     : "memory");
+	stac();
+	XSTATE_OP(XSAVE, buf, -1, -1, err);
+	clac();
+
 	return err;
 }
 
@@ -405,14 +400,12 @@
 	struct xregs_state *xstate = ((__force struct xregs_state *)buf);
 	u32 lmask = mask;
 	u32 hmask = mask >> 32;
-	int err = 0;
+	int err;
+
+	stac();
+	XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
+	clac();
 
-	__asm__ __volatile__(ASM_STAC "\n"
-			     "1:"XRSTOR"\n"
-			     "2: " ASM_CLAC "\n"
-			     xstate_fault(err)
-			     : "D" (xstate), "a" (lmask), "d" (hmask), "0" (err)
-			     : "memory");	/* memory required? */
 	return err;
 }
 
@@ -466,7 +459,7 @@
 	 * pending. Clear the x87 state here by setting it to fixed values.
 	 * "m" is a random variable that should be in L1.
 	 */
-	if (unlikely(static_cpu_has_bug_safe(X86_BUG_FXSAVE_LEAK))) {
+	if (unlikely(static_cpu_has_bug(X86_BUG_FXSAVE_LEAK))) {
 		asm volatile(
 			"fnclex\n\t"
 			"emms\n\t"
@@ -503,24 +496,6 @@
 }
 
 
-/*
- * Wrap lazy FPU TS handling in a 'hw fpregs activation/deactivation'
- * idiom, which is then paired with the sw-flag (fpregs_active) later on:
- */
-
-static inline void __fpregs_activate_hw(void)
-{
-	if (!use_eager_fpu())
-		clts();
-}
-
-static inline void __fpregs_deactivate_hw(void)
-{
-	if (!use_eager_fpu())
-		stts();
-}
-
-/* Must be paired with an 'stts' (fpregs_deactivate_hw()) after! */
 static inline void __fpregs_deactivate(struct fpu *fpu)
 {
 	WARN_ON_FPU(!fpu->fpregs_active);
@@ -529,7 +504,6 @@
 	this_cpu_write(fpu_fpregs_owner_ctx, NULL);
 }
 
-/* Must be paired with a 'clts' (fpregs_activate_hw()) before! */
 static inline void __fpregs_activate(struct fpu *fpu)
 {
 	WARN_ON_FPU(fpu->fpregs_active);
@@ -554,22 +528,17 @@
 }
 
 /*
- * Encapsulate the CR0.TS handling together with the
- * software flag.
- *
  * These generally need preemption protection to work,
  * do try to avoid using these on their own.
  */
 static inline void fpregs_activate(struct fpu *fpu)
 {
-	__fpregs_activate_hw();
 	__fpregs_activate(fpu);
 }
 
 static inline void fpregs_deactivate(struct fpu *fpu)
 {
 	__fpregs_deactivate(fpu);
-	__fpregs_deactivate_hw();
 }
 
 /*
@@ -595,8 +564,8 @@
 	 * If the task has used the math, pre-load the FPU on xsave processors
 	 * or if the past 5 consecutive context-switches used math.
 	 */
-	fpu.preload = new_fpu->fpstate_active &&
-		      (use_eager_fpu() || new_fpu->counter > 5);
+	fpu.preload = static_cpu_has(X86_FEATURE_FPU) &&
+		      new_fpu->fpstate_active;
 
 	if (old_fpu->fpregs_active) {
 		if (!copy_fpregs_to_fpstate(old_fpu))
@@ -609,17 +578,12 @@
 
 		/* Don't change CR0.TS if we just switch! */
 		if (fpu.preload) {
-			new_fpu->counter++;
 			__fpregs_activate(new_fpu);
 			prefetch(&new_fpu->state);
-		} else {
-			__fpregs_deactivate_hw();
 		}
 	} else {
-		old_fpu->counter = 0;
 		old_fpu->last_cpu = -1;
 		if (fpu.preload) {
-			new_fpu->counter++;
 			if (fpu_want_lazy_restore(new_fpu, cpu))
 				fpu.preload = 0;
 			else
--- linux-4.4.0.orig/arch/x86/include/asm/fpu/types.h
+++ linux-4.4.0/arch/x86/include/asm/fpu/types.h
@@ -303,17 +303,6 @@
 	unsigned char			fpregs_active;
 
 	/*
-	 * @counter:
-	 *
-	 * This counter contains the number of consecutive context switches
-	 * during which the FPU stays used. If this is over a threshold, the
-	 * lazy FPU restore logic becomes eager, to save the trap overhead.
-	 * This is an unsigned char so that after 256 iterations the counter
-	 * wraps and the context switch behavior turns lazy again; this is to
-	 * deal with bursty apps that only use the FPU for a short time:
-	 */
-	unsigned char			counter;
-	/*
 	 * @state:
 	 *
 	 * In-memory copy of all FPU registers that we save/restore
@@ -321,29 +310,6 @@
 	 * the registers in the FPU are more recent than this state
 	 * copy. If the task context-switches away then they get
 	 * saved here and represent the FPU state.
-	 *
-	 * After context switches there may be a (short) time period
-	 * during which the in-FPU hardware registers are unchanged
-	 * and still perfectly match this state, if the tasks
-	 * scheduled afterwards are not using the FPU.
-	 *
-	 * This is the 'lazy restore' window of optimization, which
-	 * we track though 'fpu_fpregs_owner_ctx' and 'fpu->last_cpu'.
-	 *
-	 * We detect whether a subsequent task uses the FPU via setting
-	 * CR0::TS to 1, which causes any FPU use to raise a #NM fault.
-	 *
-	 * During this window, if the task gets scheduled again, we
-	 * might be able to skip having to do a restore from this
-	 * memory buffer to the hardware registers - at the cost of
-	 * incurring the overhead of #NM fault traps.
-	 *
-	 * Note that on modern CPUs that support the XSAVEOPT (or other
-	 * optimized XSAVE instructions), we don't use #NM traps anymore,
-	 * as the hardware can track whether FPU registers need saving
-	 * or not. On such CPUs we activate the non-lazy ('eagerfpu')
-	 * logic, which unconditionally saves/restores all FPU state
-	 * across context switches. (if FPU state exists.)
 	 */
 	union fpregs_state		state;
 	/*
--- linux-4.4.0.orig/arch/x86/include/asm/fpu/xstate.h
+++ linux-4.4.0/arch/x86/include/asm/fpu/xstate.h
@@ -22,7 +22,7 @@
 #define XFEATURE_MASK_LAZY	(XFEATURE_MASK_FP | \
 				 XFEATURE_MASK_SSE | \
 				 XFEATURE_MASK_YMM | \
-				 XFEATURE_MASK_OPMASK |	\
+				 XFEATURE_MASK_OPMASK | \
 				 XFEATURE_MASK_ZMM_Hi256 | \
 				 XFEATURE_MASK_Hi16_ZMM)
 
--- linux-4.4.0.orig/arch/x86/include/asm/futex.h
+++ linux-4.4.0/arch/x86/include/asm/futex.h
@@ -41,20 +41,11 @@
 		       "+m" (*uaddr), "=&r" (tem)		\
 		     : "r" (oparg), "i" (-EFAULT), "1" (0))
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret, tem;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 
 	switch (op) {
@@ -80,30 +71,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (oldval == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (oldval != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (oldval < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (oldval >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (oldval <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (oldval > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/x86/include/asm/hardirq.h
+++ linux-4.4.0/arch/x86/include/asm/hardirq.h
@@ -2,10 +2,12 @@
 #define _ASM_X86_HARDIRQ_H
 
 #include <linux/threads.h>
-#include <linux/irq.h>
 
 typedef struct {
-	unsigned int __softirq_pending;
+	u16	     __softirq_pending;
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+	u8	     kvm_cpu_l1tf_flush_l1d;
+#endif
 	unsigned int __nmi_count;	/* arch dependent */
 #ifdef CONFIG_X86_LOCAL_APIC
 	unsigned int apic_timer_irqs;	/* arch dependent */
@@ -22,12 +24,8 @@
 #ifdef CONFIG_SMP
 	unsigned int irq_resched_count;
 	unsigned int irq_call_count;
-	/*
-	 * irq_tlb_count is double-counted in irq_call_count, so it must be
-	 * subtracted from irq_call_count when displaying irq_call_count
-	 */
-	unsigned int irq_tlb_count;
 #endif
+	unsigned int irq_tlb_count;
 #ifdef CONFIG_X86_THERMAL_VECTOR
 	unsigned int irq_thermal_count;
 #endif
@@ -64,4 +62,24 @@
 extern u64 arch_irq_stat(void);
 #define arch_irq_stat		arch_irq_stat
 
+
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+static inline void kvm_set_cpu_l1tf_flush_l1d(void)
+{
+	__this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1);
+}
+
+static inline void kvm_clear_cpu_l1tf_flush_l1d(void)
+{
+	__this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 0);
+}
+
+static inline bool kvm_get_cpu_l1tf_flush_l1d(void)
+{
+	return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d);
+}
+#else /* !IS_ENABLED(CONFIG_KVM_INTEL) */
+static inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
+#endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
+
 #endif /* _ASM_X86_HARDIRQ_H */
--- linux-4.4.0.orig/arch/x86/include/asm/hugetlb.h
+++ linux-4.4.0/arch/x86/include/asm/hugetlb.h
@@ -4,6 +4,7 @@
 #include <asm/page.h>
 #include <asm-generic/hugetlb.h>
 
+#define hugepages_supported() cpu_has_pse
 
 static inline int is_hugepage_only_range(struct mm_struct *mm,
 					 unsigned long addr,
--- linux-4.4.0.orig/arch/x86/include/asm/hw_irq.h
+++ linux-4.4.0/arch/x86/include/asm/hw_irq.h
@@ -136,6 +136,7 @@
 struct irq_cfg {
 	unsigned int		dest_apicid;
 	u8			vector;
+	u8			old_vector;
 };
 
 extern struct irq_cfg *irq_cfg(unsigned int irq);
@@ -186,7 +187,7 @@
 #define VECTOR_RETRIGGERED	((void *)~0UL)
 
 typedef struct irq_desc* vector_irq_t[NR_VECTORS];
-DECLARE_PER_CPU(vector_irq_t, vector_irq);
+DECLARE_PER_CPU_USER_MAPPED(vector_irq_t, vector_irq);
 
 #endif /* !ASSEMBLY_ */
 
--- linux-4.4.0.orig/arch/x86/include/asm/inat.h
+++ linux-4.4.0/arch/x86/include/asm/inat.h
@@ -48,6 +48,7 @@
 /* AVX VEX prefixes */
 #define INAT_PFX_VEX2	13	/* 2-bytes VEX prefix */
 #define INAT_PFX_VEX3	14	/* 3-bytes VEX prefix */
+#define INAT_PFX_EVEX	15	/* EVEX prefix */
 
 #define INAT_LSTPFX_MAX	3
 #define INAT_LGCPFX_MAX	11
@@ -89,6 +90,7 @@
 #define INAT_VARIANT	(1 << (INAT_FLAG_OFFS + 4))
 #define INAT_VEXOK	(1 << (INAT_FLAG_OFFS + 5))
 #define INAT_VEXONLY	(1 << (INAT_FLAG_OFFS + 6))
+#define INAT_EVEXONLY	(1 << (INAT_FLAG_OFFS + 7))
 /* Attribute making macros for attribute tables */
 #define INAT_MAKE_PREFIX(pfx)	(pfx << INAT_PFX_OFFS)
 #define INAT_MAKE_ESCAPE(esc)	(esc << INAT_ESC_OFFS)
@@ -141,7 +143,13 @@
 static inline int inat_is_vex_prefix(insn_attr_t attr)
 {
 	attr &= INAT_PFX_MASK;
-	return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3;
+	return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 ||
+	       attr == INAT_PFX_EVEX;
+}
+
+static inline int inat_is_evex_prefix(insn_attr_t attr)
+{
+	return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX;
 }
 
 static inline int inat_is_vex3_prefix(insn_attr_t attr)
@@ -216,6 +224,11 @@
 
 static inline int inat_must_vex(insn_attr_t attr)
 {
-	return attr & INAT_VEXONLY;
+	return attr & (INAT_VEXONLY | INAT_EVEXONLY);
+}
+
+static inline int inat_must_evex(insn_attr_t attr)
+{
+	return attr & INAT_EVEXONLY;
 }
 #endif
--- linux-4.4.0.orig/arch/x86/include/asm/init.h
+++ linux-4.4.0/arch/x86/include/asm/init.h
@@ -5,10 +5,10 @@
 	void *(*alloc_pgt_page)(void *); /* allocate buf for page table */
 	void *context;			 /* context for alloc_pgt_page */
 	unsigned long pmd_flag;		 /* page flag for PMD entry */
-	bool kernel_mapping;		 /* kernel mapping or ident mapping */
+	unsigned long offset;		 /* ident mapping offset */
 };
 
 int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
-				unsigned long addr, unsigned long end);
+				unsigned long pstart, unsigned long pend);
 
 #endif /* _ASM_X86_INIT_H */
--- linux-4.4.0.orig/arch/x86/include/asm/insn.h
+++ linux-4.4.0/arch/x86/include/asm/insn.h
@@ -91,6 +91,7 @@
 #define X86_VEX_B(vex)	((vex) & 0x20)	/* VEX3 Byte1 */
 #define X86_VEX_L(vex)	((vex) & 0x04)	/* VEX3 Byte2, VEX2 Byte1 */
 /* VEX bit fields */
+#define X86_EVEX_M(vex)	((vex) & 0x03)		/* EVEX Byte1 */
 #define X86_VEX3_M(vex)	((vex) & 0x1f)		/* VEX3 Byte1 */
 #define X86_VEX2_M	1			/* VEX2.M always 1 */
 #define X86_VEX_V(vex)	(((vex) & 0x78) >> 3)	/* VEX3 Byte2, VEX2 Byte1 */
@@ -133,6 +134,13 @@
 	return (insn->vex_prefix.value != 0);
 }
 
+static inline int insn_is_evex(struct insn *insn)
+{
+	if (!insn->prefixes.got)
+		insn_get_prefixes(insn);
+	return (insn->vex_prefix.nbytes == 4);
+}
+
 /* Ensure this instruction is decoded completely */
 static inline int insn_complete(struct insn *insn)
 {
@@ -144,8 +152,10 @@
 {
 	if (insn->vex_prefix.nbytes == 2)	/* 2 bytes VEX */
 		return X86_VEX2_M;
-	else
+	else if (insn->vex_prefix.nbytes == 3)	/* 3 bytes VEX */
 		return X86_VEX3_M(insn->vex_prefix.bytes[1]);
+	else					/* EVEX */
+		return X86_EVEX_M(insn->vex_prefix.bytes[1]);
 }
 
 static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
@@ -198,4 +208,37 @@
 	return insn_offset_displacement(insn) + insn->displacement.nbytes;
 }
 
+/**
+ * for_each_insn_prefix() -- Iterate prefixes in the instruction
+ * @insn: Pointer to struct insn.
+ * @idx:  Index storage.
+ * @prefix: Prefix byte.
+ *
+ * Iterate prefix bytes of given @insn. Each prefix byte is stored in @prefix
+ * and the index is stored in @idx (note that this @idx is just for a cursor,
+ * do not change it.)
+ * Since prefixes.nbytes can be bigger than 4 if some prefixes
+ * are repeated, it cannot be used for looping over the prefixes.
+ */
+#define for_each_insn_prefix(insn, idx, prefix)	\
+	for (idx = 0; idx < ARRAY_SIZE(insn->prefixes.bytes) && (prefix = insn->prefixes.bytes[idx]) != 0; idx++)
+
+#define POP_SS_OPCODE 0x1f
+#define MOV_SREG_OPCODE 0x8e
+
+/*
+ * Intel SDM Vol.3A 6.8.3 states;
+ * "Any single-step trap that would be delivered following the MOV to SS
+ * instruction or POP to SS instruction (because EFLAGS.TF is 1) is
+ * suppressed."
+ * This function returns true if @insn is MOV SS or POP SS. On these
+ * instructions, single stepping is suppressed.
+ */
+static inline int insn_masking_exception(struct insn *insn)
+{
+	return insn->opcode.bytes[0] == POP_SS_OPCODE ||
+		(insn->opcode.bytes[0] == MOV_SREG_OPCODE &&
+		 X86_MODRM_REG(insn->modrm.bytes[0]) == 2);
+}
+
 #endif /* _ASM_X86_INSN_H */
--- linux-4.4.0.orig/arch/x86/include/asm/intel-family.h
+++ linux-4.4.0/arch/x86/include/asm/intel-family.h
@@ -0,0 +1,109 @@
+#ifndef _ASM_X86_INTEL_FAMILY_H
+#define _ASM_X86_INTEL_FAMILY_H
+
+/*
+ * "Big Core" Processors (Branded as Core, Xeon, etc...)
+ *
+ * The "_X" parts are generally the EP and EX Xeons, or the
+ * "Extreme" ones, like Broadwell-E, or Atom microserver.
+ *
+ * Things ending in "2" are usually because we have no better
+ * name for them.  There's no processor called "WESTMERE2".
+ *
+ * While adding a new CPUID for a new microarchitecture, add a new
+ * group to keep logically sorted out in chronological order. Within
+ * that group keep the CPUID for the variants sorted by model number.
+ */
+
+/* Wildcard match for FAM6 so X86_MATCH_INTEL_FAM6_MODEL(ANY) works */
+#define INTEL_FAM6_ANY			X86_MODEL_ANY
+
+#define INTEL_FAM6_CORE_YONAH		0x0E
+#define INTEL_FAM6_CORE2_MEROM		0x0F
+#define INTEL_FAM6_CORE2_MEROM_L	0x16
+#define INTEL_FAM6_CORE2_PENRYN		0x17
+#define INTEL_FAM6_CORE2_DUNNINGTON	0x1D
+
+#define INTEL_FAM6_NEHALEM		0x1E
+#define INTEL_FAM6_NEHALEM_EP		0x1A
+#define INTEL_FAM6_NEHALEM_EX		0x2E
+#define INTEL_FAM6_WESTMERE		0x25
+#define INTEL_FAM6_WESTMERE2		0x1F
+#define INTEL_FAM6_WESTMERE_EP		0x2C
+#define INTEL_FAM6_WESTMERE_EX		0x2F
+
+#define INTEL_FAM6_SANDYBRIDGE		0x2A
+#define INTEL_FAM6_SANDYBRIDGE_X	0x2D
+#define INTEL_FAM6_IVYBRIDGE		0x3A
+#define INTEL_FAM6_IVYBRIDGE_X		0x3E
+
+#define INTEL_FAM6_HASWELL_CORE		0x3C
+#define INTEL_FAM6_HASWELL_X		0x3F
+#define INTEL_FAM6_HASWELL_ULT		0x45
+#define INTEL_FAM6_HASWELL_GT3E		0x46
+
+#define INTEL_FAM6_BROADWELL_CORE	0x3D
+#define INTEL_FAM6_BROADWELL_XEON_D	0x56
+#define INTEL_FAM6_BROADWELL_GT3E	0x47
+#define INTEL_FAM6_BROADWELL_X		0x4F
+
+#define INTEL_FAM6_SKYLAKE_MOBILE	0x4E
+#define INTEL_FAM6_SKYLAKE_DESKTOP	0x5E
+#define INTEL_FAM6_SKYLAKE_X		0x55
+#define INTEL_FAM6_KABYLAKE_MOBILE	0x8E
+#define INTEL_FAM6_KABYLAKE_DESKTOP	0x9E
+
+#define INTEL_FAM6_CANNONLAKE_MOBILE	0x66
+
+#define INTEL_FAM6_ICELAKE_X		0x6A
+#define INTEL_FAM6_ICELAKE_XEON_D	0x6C
+#define INTEL_FAM6_ICELAKE_DESKTOP	0x7D
+#define INTEL_FAM6_ICELAKE_MOBILE	0x7E
+
+#define INTEL_FAM6_COMETLAKE		0xA5
+#define INTEL_FAM6_COMETLAKE_L		0xA6
+
+#define INTEL_FAM6_ROCKETLAKE		0xA7
+
+/* Hybrid Core/Atom Processors */
+
+#define	INTEL_FAM6_LAKEFIELD		0x8A
+#define INTEL_FAM6_ALDERLAKE		0x97
+#define INTEL_FAM6_ALDERLAKE_L		0x9A
+
+#define INTEL_FAM6_TIGERLAKE_L		0x8C
+#define INTEL_FAM6_TIGERLAKE		0x8D
+
+/* "Small Core" Processors (Atom) */
+
+#define INTEL_FAM6_ATOM_BONNELL		0x1C /* Diamondville, Pineview */
+#define INTEL_FAM6_ATOM_BONNELL_MID	0x26 /* Silverthorne, Lincroft */
+
+#define INTEL_FAM6_ATOM_SALTWELL	0x36 /* Cedarview */
+#define INTEL_FAM6_ATOM_SALTWELL_MID	0x27 /* Penwell */
+#define INTEL_FAM6_ATOM_SALTWELL_TABLET	0x35 /* Cloverview */
+
+#define INTEL_FAM6_ATOM_SILVERMONT	0x37 /* Bay Trail, Valleyview */
+#define INTEL_FAM6_ATOM_SILVERMONT_X	0x4D /* Avaton, Rangely */
+#define INTEL_FAM6_ATOM_SILVERMONT_MID	0x4A /* Merriefield */
+
+#define INTEL_FAM6_ATOM_AIRMONT		0x4C /* Cherry Trail, Braswell */
+#define INTEL_FAM6_ATOM_AIRMONT_MID	0x5A /* Moorefield */
+
+#define INTEL_FAM6_ATOM_GOLDMONT	0x5C /* Apollo Lake */
+#define INTEL_FAM6_ATOM_GOLDMONT_X	0x5F /* Denverton */
+#define INTEL_FAM6_ATOM_GOLDMONT_PLUS	0x7A /* Gemini Lake */
+
+#define INTEL_FAM6_ATOM_TREMONT_X	0x86 /* Jacobsville */
+#define INTEL_FAM6_ATOM_TREMONT		0x96 /* Elkhart Lake */
+#define INTEL_FAM6_ATOM_TREMONT_L	0x9C /* Jasper Lake */
+
+/* Xeon Phi */
+
+#define INTEL_FAM6_XEON_PHI_KNL		0x57 /* Knights Landing */
+#define INTEL_FAM6_XEON_PHI_KNM		0x85 /* Knights Mill */
+
+/* Family 5 */
+#define INTEL_FAM5_QUARK_X1000		0x09 /* Quark X1000 SoC */
+
+#endif /* _ASM_X86_INTEL_FAMILY_H */
--- linux-4.4.0.orig/arch/x86/include/asm/intel_punit_ipc.h
+++ linux-4.4.0/arch/x86/include/asm/intel_punit_ipc.h
@@ -0,0 +1,101 @@
+#ifndef _ASM_X86_INTEL_PUNIT_IPC_H_
+#define  _ASM_X86_INTEL_PUNIT_IPC_H_
+
+/*
+ * Three types of 8bit P-Unit IPC commands are supported,
+ * bit[7:6]: [00]: BIOS; [01]: GTD; [10]: ISPD.
+ */
+typedef enum {
+	BIOS_IPC = 0,
+	GTDRIVER_IPC,
+	ISPDRIVER_IPC,
+	RESERVED_IPC,
+} IPC_TYPE;
+
+#define IPC_TYPE_OFFSET			6
+#define IPC_PUNIT_BIOS_CMD_BASE		(BIOS_IPC << IPC_TYPE_OFFSET)
+#define IPC_PUNIT_GTD_CMD_BASE		(GTDDRIVER_IPC << IPC_TYPE_OFFSET)
+#define IPC_PUNIT_ISPD_CMD_BASE		(ISPDRIVER_IPC << IPC_TYPE_OFFSET)
+#define IPC_PUNIT_CMD_TYPE_MASK		(RESERVED_IPC << IPC_TYPE_OFFSET)
+
+/* BIOS => Pcode commands */
+#define IPC_PUNIT_BIOS_ZERO			(IPC_PUNIT_BIOS_CMD_BASE | 0x00)
+#define IPC_PUNIT_BIOS_VR_INTERFACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x01)
+#define IPC_PUNIT_BIOS_READ_PCS			(IPC_PUNIT_BIOS_CMD_BASE | 0x02)
+#define IPC_PUNIT_BIOS_WRITE_PCS		(IPC_PUNIT_BIOS_CMD_BASE | 0x03)
+#define IPC_PUNIT_BIOS_READ_PCU_CONFIG		(IPC_PUNIT_BIOS_CMD_BASE | 0x04)
+#define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG		(IPC_PUNIT_BIOS_CMD_BASE | 0x05)
+#define IPC_PUNIT_BIOS_READ_PL1_SETTING		(IPC_PUNIT_BIOS_CMD_BASE | 0x06)
+#define IPC_PUNIT_BIOS_WRITE_PL1_SETTING	(IPC_PUNIT_BIOS_CMD_BASE | 0x07)
+#define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM		(IPC_PUNIT_BIOS_CMD_BASE | 0x08)
+#define IPC_PUNIT_BIOS_READ_TELE_INFO		(IPC_PUNIT_BIOS_CMD_BASE | 0x09)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0a)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0b)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0c)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0d)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x0e)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x0f)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT		(IPC_PUNIT_BIOS_CMD_BASE | 0x10)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT		(IPC_PUNIT_BIOS_CMD_BASE | 0x11)
+#define IPC_PUNIT_BIOS_READ_MODULE_TEMP		(IPC_PUNIT_BIOS_CMD_BASE | 0x12)
+#define IPC_PUNIT_BIOS_RESERVED			(IPC_PUNIT_BIOS_CMD_BASE | 0x13)
+#define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER	(IPC_PUNIT_BIOS_CMD_BASE | 0x14)
+#define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER	(IPC_PUNIT_BIOS_CMD_BASE | 0x15)
+#define IPC_PUNIT_BIOS_READ_RATIO_OVER		(IPC_PUNIT_BIOS_CMD_BASE | 0x16)
+#define IPC_PUNIT_BIOS_WRITE_RATIO_OVER		(IPC_PUNIT_BIOS_CMD_BASE | 0x17)
+#define IPC_PUNIT_BIOS_READ_VF_GL_CTRL		(IPC_PUNIT_BIOS_CMD_BASE | 0x18)
+#define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL		(IPC_PUNIT_BIOS_CMD_BASE | 0x19)
+#define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH	(IPC_PUNIT_BIOS_CMD_BASE | 0x1a)
+#define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH	(IPC_PUNIT_BIOS_CMD_BASE | 0x1b)
+
+/* GT Driver => Pcode commands */
+#define IPC_PUNIT_GTD_ZERO			(IPC_PUNIT_GTD_CMD_BASE | 0x00)
+#define IPC_PUNIT_GTD_CONFIG			(IPC_PUNIT_GTD_CMD_BASE | 0x01)
+#define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL	(IPC_PUNIT_GTD_CMD_BASE | 0x02)
+#define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL	(IPC_PUNIT_GTD_CMD_BASE | 0x03)
+#define IPC_PUNIT_GTD_GET_WM_VAL		(IPC_PUNIT_GTD_CMD_BASE | 0x06)
+#define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ	(IPC_PUNIT_GTD_CMD_BASE | 0x07)
+#define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE	(IPC_PUNIT_GTD_CMD_BASE | 0x16)
+#define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST	(IPC_PUNIT_GTD_CMD_BASE | 0x17)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL	(IPC_PUNIT_GTD_CMD_BASE | 0x1a)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING	(IPC_PUNIT_GTD_CMD_BASE | 0x1c)
+
+/* ISP Driver => Pcode commands */
+#define IPC_PUNIT_ISPD_ZERO			(IPC_PUNIT_ISPD_CMD_BASE | 0x00)
+#define IPC_PUNIT_ISPD_CONFIG			(IPC_PUNIT_ISPD_CMD_BASE | 0x01)
+#define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL		(IPC_PUNIT_ISPD_CMD_BASE | 0x02)
+#define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS	(IPC_PUNIT_ISPD_CMD_BASE | 0x03)
+#define IPC_PUNIT_ISPD_READ_CDYN_LEVEL		(IPC_PUNIT_ISPD_CMD_BASE | 0x04)
+#define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL		(IPC_PUNIT_ISPD_CMD_BASE | 0x05)
+
+/* Error codes */
+#define IPC_PUNIT_ERR_SUCCESS			0
+#define IPC_PUNIT_ERR_INVALID_CMD		1
+#define IPC_PUNIT_ERR_INVALID_PARAMETER		2
+#define IPC_PUNIT_ERR_CMD_TIMEOUT		3
+#define IPC_PUNIT_ERR_CMD_LOCKED		4
+#define IPC_PUNIT_ERR_INVALID_VR_ID		5
+#define IPC_PUNIT_ERR_VR_ERR			6
+
+#if IS_ENABLED(CONFIG_INTEL_PUNIT_IPC)
+
+int intel_punit_ipc_simple_command(int cmd, int para1, int para2);
+int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out);
+
+#else
+
+static inline int intel_punit_ipc_simple_command(int cmd,
+						  int para1, int para2)
+{
+	return -ENODEV;
+}
+
+static inline int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2,
+					  u32 *in, u32 *out)
+{
+	return -ENODEV;
+}
+
+#endif /* CONFIG_INTEL_PUNIT_IPC */
+
+#endif
--- linux-4.4.0.orig/arch/x86/include/asm/intel_telemetry.h
+++ linux-4.4.0/arch/x86/include/asm/intel_telemetry.h
@@ -0,0 +1,147 @@
+/*
+ * Intel SOC Telemetry Driver Header File
+ * Copyright (C) 2015, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+#ifndef INTEL_TELEMETRY_H
+#define INTEL_TELEMETRY_H
+
+#define TELEM_MAX_EVENTS_SRAM		28
+#define TELEM_MAX_OS_ALLOCATED_EVENTS	20
+
+enum telemetry_unit {
+	TELEM_PSS = 0,
+	TELEM_IOSS,
+	TELEM_UNIT_NONE
+};
+
+struct telemetry_evtlog {
+	u32 telem_evtid;
+	u64 telem_evtlog;
+};
+
+struct telemetry_evtconfig {
+	/* Array of Event-IDs to Enable */
+	u32 *evtmap;
+
+	/* Number of Events (<29) in evtmap */
+	u8 num_evts;
+
+	/* Sampling period */
+	u8 period;
+};
+
+struct telemetry_evtmap {
+	const char *name;
+	u32 evt_id;
+};
+
+struct telemetry_unit_config {
+	struct telemetry_evtmap *telem_evts;
+	void __iomem *regmap;
+	u32 ssram_base_addr;
+	u8 ssram_evts_used;
+	u8 curr_period;
+	u8 max_period;
+	u8 min_period;
+	u32 ssram_size;
+
+};
+
+struct telemetry_plt_config {
+	struct telemetry_unit_config pss_config;
+	struct telemetry_unit_config ioss_config;
+	struct mutex telem_trace_lock;
+	struct mutex telem_lock;
+	bool telem_in_use;
+};
+
+struct telemetry_core_ops {
+	int (*get_sampling_period)(u8 *pss_min_period, u8 *pss_max_period,
+				   u8 *ioss_min_period, u8 *ioss_max_period);
+
+	int (*get_eventconfig)(struct telemetry_evtconfig *pss_evtconfig,
+			       struct telemetry_evtconfig *ioss_evtconfig,
+			       int pss_len, int ioss_len);
+
+	int (*update_events)(struct telemetry_evtconfig pss_evtconfig,
+			     struct telemetry_evtconfig ioss_evtconfig);
+
+	int (*set_sampling_period)(u8 pss_period, u8 ioss_period);
+
+	int (*get_trace_verbosity)(enum telemetry_unit telem_unit,
+				   u32 *verbosity);
+
+	int (*set_trace_verbosity)(enum telemetry_unit telem_unit,
+				   u32 verbosity);
+
+	int (*raw_read_eventlog)(enum telemetry_unit telem_unit,
+				 struct telemetry_evtlog *evtlog,
+				 int len, int log_all_evts);
+
+	int (*read_eventlog)(enum telemetry_unit telem_unit,
+			     struct telemetry_evtlog *evtlog,
+			     int len, int log_all_evts);
+
+	int (*add_events)(u8 num_pss_evts, u8 num_ioss_evts,
+			  u32 *pss_evtmap, u32 *ioss_evtmap);
+
+	int (*reset_events)(void);
+};
+
+int telemetry_set_pltdata(struct telemetry_core_ops *ops,
+			  struct telemetry_plt_config *pltconfig);
+
+int telemetry_clear_pltdata(void);
+
+int telemetry_pltconfig_valid(void);
+
+int telemetry_get_evtname(enum telemetry_unit telem_unit,
+			  const char **name, int len);
+
+int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig,
+			    struct telemetry_evtconfig ioss_evtconfig);
+
+int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts,
+			 u32 *pss_evtmap, u32 *ioss_evtmap);
+
+int telemetry_reset_events(void);
+
+int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_config,
+			      struct telemetry_evtconfig *ioss_config,
+			      int pss_len, int ioss_len);
+
+int telemetry_read_events(enum telemetry_unit telem_unit,
+			  struct telemetry_evtlog *evtlog, int len);
+
+int telemetry_raw_read_events(enum telemetry_unit telem_unit,
+			      struct telemetry_evtlog *evtlog, int len);
+
+int telemetry_read_eventlog(enum telemetry_unit telem_unit,
+			    struct telemetry_evtlog *evtlog, int len);
+
+int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit,
+				struct telemetry_evtlog *evtlog, int len);
+
+int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period,
+				  u8 *ioss_min_period, u8 *ioss_max_period);
+
+int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period);
+
+int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit,
+				  u32 verbosity);
+
+int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit,
+				  u32 *verbosity);
+
+#endif /* INTEL_TELEMETRY_H */
--- linux-4.4.0.orig/arch/x86/include/asm/io.h
+++ linux-4.4.0/arch/x86/include/asm/io.h
@@ -304,13 +304,13 @@
 static inline void outs##bwl(int port, const void *addr, unsigned long count) \
 {									\
 	asm volatile("rep; outs" #bwl					\
-		     : "+S"(addr), "+c"(count) : "d"(port));		\
+		     : "+S"(addr), "+c"(count) : "d"(port) : "memory");	\
 }									\
 									\
 static inline void ins##bwl(int port, void *addr, unsigned long count)	\
 {									\
 	asm volatile("rep; ins" #bwl					\
-		     : "+D"(addr), "+c"(count) : "d"(port));		\
+		     : "+D"(addr), "+c"(count) : "d"(port) : "memory");	\
 }
 
 BUILDIO(b, b, char)
@@ -351,4 +351,10 @@
 #define arch_phys_wc_add arch_phys_wc_add
 #endif
 
+#ifdef CONFIG_X86_PAT
+extern int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size);
+extern void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size);
+#define arch_io_reserve_memtype_wc arch_io_reserve_memtype_wc
+#endif
+
 #endif /* _ASM_X86_IO_H */
--- linux-4.4.0.orig/arch/x86/include/asm/iosf_mbi.h
+++ linux-4.4.0/arch/x86/include/asm/iosf_mbi.h
@@ -16,6 +16,18 @@
 #define MBI_MASK_LO		0x000000FF
 #define MBI_ENABLE		0xF0
 
+/* IOSF SB read/write opcodes */
+#define MBI_MMIO_READ		0x00
+#define MBI_MMIO_WRITE		0x01
+#define MBI_CFG_READ		0x04
+#define MBI_CFG_WRITE		0x05
+#define MBI_CR_READ		0x06
+#define MBI_CR_WRITE		0x07
+#define MBI_REG_READ		0x10
+#define MBI_REG_WRITE		0x11
+#define MBI_ESRAM_READ		0x12
+#define MBI_ESRAM_WRITE		0x13
+
 /* Baytrail available units */
 #define BT_MBI_UNIT_AUNIT	0x00
 #define BT_MBI_UNIT_SMC		0x01
--- linux-4.4.0.orig/arch/x86/include/asm/irq.h
+++ linux-4.4.0/arch/x86/include/asm/irq.h
@@ -23,11 +23,13 @@
 
 #define __ARCH_HAS_DO_SOFTIRQ
 
+struct irq_desc;
+
 #ifdef CONFIG_HOTPLUG_CPU
 #include <linux/cpumask.h>
 extern int check_irq_vectors_for_cpu_disable(void);
 extern void fixup_irqs(void);
-extern void irq_force_complete_move(int);
+extern void irq_force_complete_move(struct irq_desc *desc);
 #endif
 
 #ifdef CONFIG_HAVE_KVM
@@ -37,7 +39,6 @@
 extern void (*x86_platform_ipi_callback)(void);
 extern void native_init_IRQ(void);
 
-struct irq_desc;
 extern bool handle_irq(struct irq_desc *desc, struct pt_regs *regs);
 
 extern __visible unsigned int do_IRQ(struct pt_regs *regs);
--- linux-4.4.0.orig/arch/x86/include/asm/irq_work.h
+++ linux-4.4.0/arch/x86/include/asm/irq_work.h
@@ -1,7 +1,7 @@
 #ifndef _ASM_IRQ_WORK_H
 #define _ASM_IRQ_WORK_H
 
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 
 static inline bool arch_irq_work_has_interrupt(void)
 {
--- linux-4.4.0.orig/arch/x86/include/asm/irqflags.h
+++ linux-4.4.0/arch/x86/include/asm/irqflags.h
@@ -4,11 +4,16 @@
 #include <asm/processor-flags.h>
 
 #ifndef __ASSEMBLY__
+
+#include <asm/nospec-branch.h>
+
 /*
  * Interrupt control:
  */
 
-static inline unsigned long native_save_fl(void)
+/* Declaration required for gcc < 4.9 to prevent -Werror=missing-prototypes */
+extern inline unsigned long native_save_fl(void);
+extern inline unsigned long native_save_fl(void)
 {
 	unsigned long flags;
 
@@ -26,7 +31,8 @@
 	return flags;
 }
 
-static inline void native_restore_fl(unsigned long flags)
+extern inline void native_restore_fl(unsigned long flags);
+extern inline void native_restore_fl(unsigned long flags)
 {
 	asm volatile("push %0 ; popf"
 		     : /* no output */
@@ -46,11 +52,13 @@
 
 static inline void native_safe_halt(void)
 {
+	mds_idle_clear_cpu_buffers();
 	asm volatile("sti; hlt": : :"memory");
 }
 
 static inline void native_halt(void)
 {
+	mds_idle_clear_cpu_buffers();
 	asm volatile("hlt": : :"memory");
 }
 
--- linux-4.4.0.orig/arch/x86/include/asm/kaiser.h
+++ linux-4.4.0/arch/x86/include/asm/kaiser.h
@@ -0,0 +1,151 @@
+#ifndef _ASM_X86_KAISER_H
+#define _ASM_X86_KAISER_H
+
+#include <uapi/asm/processor-flags.h> /* For PCID constants */
+
+/*
+ * This file includes the definitions for the KAISER feature.
+ * KAISER is a counter measure against x86_64 side channel attacks on
+ * the kernel virtual memory.  It has a shadow pgd for every process: the
+ * shadow pgd has a minimalistic kernel-set mapped, but includes the whole
+ * user memory. Within a kernel context switch, or when an interrupt is handled,
+ * the pgd is switched to the normal one. When the system switches to user mode,
+ * the shadow pgd is enabled. By this, the virtual memory caches are freed,
+ * and the user may not attack the whole kernel memory.
+ *
+ * A minimalistic kernel mapping holds the parts needed to be mapped in user
+ * mode, such as the entry/exit functions of the user space, or the stacks.
+ */
+
+#define KAISER_SHADOW_PGD_OFFSET 0x1000
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+/*
+ *  A page table address must have this alignment to stay the same when
+ *  KAISER_SHADOW_PGD_OFFSET mask is applied
+ */
+#define KAISER_KERNEL_PGD_ALIGNMENT (KAISER_SHADOW_PGD_OFFSET << 1)
+#else
+#define KAISER_KERNEL_PGD_ALIGNMENT PAGE_SIZE
+#endif
+
+#ifdef __ASSEMBLY__
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+
+.macro _SWITCH_TO_KERNEL_CR3 reg
+movq %cr3, \reg
+andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), \reg
+/* If PCID enabled, set X86_CR3_PCID_NOFLUSH_BIT */
+ALTERNATIVE "", "bts $63, \reg", X86_FEATURE_PCID
+movq \reg, %cr3
+.endm
+
+.macro _SWITCH_TO_USER_CR3 reg regb
+/*
+ * regb must be the low byte portion of reg: because we have arranged
+ * for the low byte of the user PCID to serve as the high byte of NOFLUSH
+ * (0x80 for each when PCID is enabled, or 0x00 when PCID and NOFLUSH are
+ * not enabled): so that the one register can update both memory and cr3.
+ */
+movq %cr3, \reg
+orq  PER_CPU_VAR(x86_cr3_pcid_user), \reg
+js   9f
+/* If PCID enabled, FLUSH this time, reset to NOFLUSH for next time */
+movb \regb, PER_CPU_VAR(x86_cr3_pcid_user+7)
+9:
+movq \reg, %cr3
+.endm
+
+.macro SWITCH_KERNEL_CR3
+ALTERNATIVE "jmp 8f", "pushq %rax", X86_FEATURE_KAISER
+_SWITCH_TO_KERNEL_CR3 %rax
+popq %rax
+8:
+.endm
+
+.macro SWITCH_USER_CR3
+ALTERNATIVE "jmp 8f", "pushq %rax", X86_FEATURE_KAISER
+_SWITCH_TO_USER_CR3 %rax %al
+popq %rax
+8:
+.endm
+
+.macro SWITCH_KERNEL_CR3_NO_STACK
+ALTERNATIVE "jmp 8f", \
+	__stringify(movq %rax, PER_CPU_VAR(unsafe_stack_register_backup)), \
+	X86_FEATURE_KAISER
+_SWITCH_TO_KERNEL_CR3 %rax
+movq PER_CPU_VAR(unsafe_stack_register_backup), %rax
+8:
+.endm
+
+#else /* CONFIG_PAGE_TABLE_ISOLATION */
+
+.macro SWITCH_KERNEL_CR3
+.endm
+.macro SWITCH_USER_CR3
+.endm
+.macro SWITCH_KERNEL_CR3_NO_STACK
+.endm
+
+#endif /* CONFIG_PAGE_TABLE_ISOLATION */
+
+#else /* __ASSEMBLY__ */
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+/*
+ * Upon kernel/user mode switch, it may happen that the address
+ * space has to be switched before the registers have been
+ * stored.  To change the address space, another register is
+ * needed.  A register therefore has to be stored/restored.
+*/
+DECLARE_PER_CPU_USER_MAPPED(unsigned long, unsafe_stack_register_backup);
+
+DECLARE_PER_CPU(unsigned long, x86_cr3_pcid_user);
+
+extern char __per_cpu_user_mapped_start[], __per_cpu_user_mapped_end[];
+
+extern int kaiser_enabled;
+extern void __init kaiser_check_boottime_disable(void);
+#else
+#define kaiser_enabled	0
+static inline void __init kaiser_check_boottime_disable(void) {}
+#endif /* CONFIG_PAGE_TABLE_ISOLATION */
+
+/*
+ * Kaiser function prototypes are needed even when CONFIG_PAGE_TABLE_ISOLATION is not set,
+ * so as to build with tests on kaiser_enabled instead of #ifdefs.
+ */
+
+/**
+ *  kaiser_add_mapping - map a virtual memory part to the shadow (user) mapping
+ *  @addr: the start address of the range
+ *  @size: the size of the range
+ *  @flags: The mapping flags of the pages
+ *
+ *  The mapping is done on a global scope, so no bigger
+ *  synchronization has to be done.  the pages have to be
+ *  manually unmapped again when they are not needed any longer.
+ */
+extern int kaiser_add_mapping(unsigned long addr, unsigned long size, unsigned long flags);
+
+/**
+ *  kaiser_remove_mapping - unmap a virtual memory part of the shadow mapping
+ *  @addr: the start address of the range
+ *  @size: the size of the range
+ */
+extern void kaiser_remove_mapping(unsigned long start, unsigned long size);
+
+/**
+ *  kaiser_init - Initialize the shadow mapping
+ *
+ *  Most parts of the shadow mapping can be mapped upon boot
+ *  time.  Only per-process things like the thread stacks
+ *  or a new LDT have to be mapped at runtime.  These boot-
+ *  time mappings are permanent and never unmapped.
+ */
+extern void kaiser_init(void);
+
+#endif /* __ASSEMBLY */
+
+#endif /* _ASM_X86_KAISER_H */
--- linux-4.4.0.orig/arch/x86/include/asm/kexec.h
+++ linux-4.4.0/arch/x86/include/asm/kexec.h
@@ -66,7 +66,7 @@
 
 /* Memory to backup during crash kdump */
 #define KEXEC_BACKUP_SRC_START	(0UL)
-#define KEXEC_BACKUP_SRC_END	(640 * 1024UL)	/* 640K */
+#define KEXEC_BACKUP_SRC_END	(640 * 1024UL - 1)	/* 640K */
 
 /*
  * CPU does not save ss and sp on stack if execution is already
--- linux-4.4.0.orig/arch/x86/include/asm/kgdb.h
+++ linux-4.4.0/arch/x86/include/asm/kgdb.h
@@ -6,6 +6,8 @@
  * Copyright (C) 2008 Wind River Systems, Inc.
  */
 
+#include <asm/ptrace.h>
+
 /*
  * BUFMAX defines the maximum number of characters in inbound/outbound
  * buffers at least NUMREGBYTES*2 are needed for register packets
--- linux-4.4.0.orig/arch/x86/include/asm/kvm_emulate.h
+++ linux-4.4.0/arch/x86/include/asm/kvm_emulate.h
@@ -105,11 +105,12 @@
 	 *  @addr:  [IN ] Linear address from which to read.
 	 *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
 	 *  @bytes: [IN ] Number of bytes to read from memory.
+	 *  @system:[IN ] Whether the access is forced to be at CPL0.
 	 */
 	int (*read_std)(struct x86_emulate_ctxt *ctxt,
 			unsigned long addr, void *val,
 			unsigned int bytes,
-			struct x86_exception *fault);
+			struct x86_exception *fault, bool system);
 
 	/*
 	 * read_phys: Read bytes of standard (non-emulated/special) memory.
@@ -127,10 +128,11 @@
 	 *  @addr:  [IN ] Linear address to which to write.
 	 *  @val:   [OUT] Value write to memory, zero-extended to 'u_long'.
 	 *  @bytes: [IN ] Number of bytes to write to memory.
+	 *  @system:[IN ] Whether the access is forced to be at CPL0.
 	 */
 	int (*write_std)(struct x86_emulate_ctxt *ctxt,
 			 unsigned long addr, void *val, unsigned int bytes,
-			 struct x86_exception *fault);
+			 struct x86_exception *fault, bool system);
 	/*
 	 * fetch: Read bytes of standard (non-emulated/special) memory.
 	 *        Used for instruction fetch.
@@ -221,6 +223,9 @@
 	void (*get_cpuid)(struct x86_emulate_ctxt *ctxt,
 			  u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
 	void (*set_nmi_mask)(struct x86_emulate_ctxt *ctxt, bool masked);
+
+	unsigned (*get_hflags)(struct x86_emulate_ctxt *ctxt);
+	void (*set_hflags)(struct x86_emulate_ctxt *ctxt, unsigned hflags);
 };
 
 typedef u32 __attribute__((vector_size(16))) sse128_t;
@@ -290,10 +295,10 @@
 
 	/* interruptibility state, as a result of execution of STI or MOV SS */
 	int interruptibility;
-	int emul_flags;
 
 	bool perm_ok; /* do not check permissions if true */
 	bool ud;	/* inject an #UD if host doesn't support insn */
+	bool tf;	/* TF value before instruction (after for syscall/sysret) */
 
 	bool have_exception;
 	struct x86_exception exception;
--- linux-4.4.0.orig/arch/x86/include/asm/kvm_host.h
+++ linux-4.4.0/arch/x86/include/asm/kvm_host.h
@@ -17,6 +17,7 @@
 #include <linux/tracepoint.h>
 #include <linux/cpumask.h>
 #include <linux/irq_work.h>
+#include <linux/irq.h>
 
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
@@ -25,6 +26,7 @@
 #include <linux/pvclock_gtod.h>
 #include <linux/clocksource.h>
 #include <linux/irqbypass.h>
+#include <linux/hyperv.h>
 
 #include <asm/pvclock-abi.h>
 #include <asm/desc.h>
@@ -41,7 +43,7 @@
 
 #define KVM_PIO_PAGE_OFFSET 1
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 2
-#define KVM_HALT_POLL_NS_DEFAULT 500000
+#define KVM_HALT_POLL_NS_DEFAULT 200000
 
 #define KVM_IRQCHIP_NUM_PINS  KVM_IOAPIC_NUM_PINS
 
@@ -213,9 +215,16 @@
 	};
 };
 
+struct kvm_rmap_head {
+	unsigned long val;
+};
+
 struct kvm_mmu_page {
 	struct list_head link;
 	struct hlist_node hash_link;
+	struct list_head lpage_disallowed_link;
+
+	bool lpage_disallowed; /* Can't be replaced by an equiv large page */
 
 	/*
 	 * The following two entries are used to key the shadow page in the
@@ -230,7 +239,7 @@
 	bool unsync;
 	int root_count;          /* Currently serving as active root */
 	unsigned int unsync_children;
-	unsigned long parent_ptes;	/* Reverse mapping for parent_pte */
+	struct kvm_rmap_head parent_ptes; /* rmap pointers to parent sptes */
 
 	/* The page is obsolete if mmu_valid_gen != kvm->arch.mmu_valid_gen.  */
 	unsigned long mmu_valid_gen;
@@ -374,10 +383,38 @@
 	struct list_head head;
 };
 
+/* Hyper-V SynIC timer */
+struct kvm_vcpu_hv_stimer {
+	struct hrtimer timer;
+	int index;
+	u64 config;
+	u64 count;
+	u64 exp_time;
+	struct hv_message msg;
+	bool msg_pending;
+};
+
+/* Hyper-V synthetic interrupt controller (SynIC)*/
+struct kvm_vcpu_hv_synic {
+	u64 version;
+	u64 control;
+	u64 msg_page;
+	u64 evt_page;
+	atomic64_t sint[HV_SYNIC_SINT_COUNT];
+	atomic_t sint_to_gsi[HV_SYNIC_SINT_COUNT];
+	DECLARE_BITMAP(auto_eoi_bitmap, 256);
+	DECLARE_BITMAP(vec_bitmap, 256);
+	bool active;
+};
+
 /* Hyper-V per vcpu emulation context */
 struct kvm_vcpu_hv {
 	u64 hv_vapic;
 	s64 runtime_offset;
+	struct kvm_vcpu_hv_synic synic;
+	struct kvm_hyperv_exit exit;
+	struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT];
+	DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
 };
 
 struct kvm_vcpu_arch {
@@ -400,7 +437,8 @@
 	u64 efer;
 	u64 apic_base;
 	struct kvm_lapic *apic;    /* kernel irqchip context */
-	u64 eoi_exit_bitmap[4];
+	bool apicv_active;
+	DECLARE_BITMAP(ioapic_handled_vectors, 256);
 	unsigned long apic_attention;
 	int32_t apic_arb_prio;
 	int mp_state;
@@ -408,6 +446,8 @@
 	u64 smbase;
 	bool tpr_access_reporting;
 	u64 ia32_xss;
+	u64 microcode_version;
+	u64 arch_capabilities;
 
 	/*
 	 * Paging state of the vcpu
@@ -439,7 +479,6 @@
 	struct kvm_mmu_memory_cache mmu_page_header_cache;
 
 	struct fpu guest_fpu;
-	bool eager_fpu;
 	u64 xcr0;
 	u64 guest_supported_xcr0;
 	u32 guest_xstate_size;
@@ -582,14 +621,17 @@
 
 	int pending_ioapic_eoi;
 	int pending_external_vector;
+
+	/* Flush the L1 Data cache for L1TF mitigation on VMENTER */
+	bool l1tf_flush_l1d;
 };
 
 struct kvm_lpage_info {
-	int write_count;
+	int disallow_lpage;
 };
 
 struct kvm_arch_memory_slot {
-	unsigned long *rmap[KVM_NR_PAGE_SIZES];
+	struct kvm_rmap_head *rmap[KVM_NR_PAGE_SIZES];
 	struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
 };
 
@@ -635,6 +677,7 @@
 	 */
 	struct list_head active_mmu_pages;
 	struct list_head zapped_obsolete_pages;
+	struct list_head lpage_disallowed_mmu_pages;
 
 	struct list_head assigned_dev_head;
 	struct iommu_domain *iommu_domain;
@@ -695,6 +738,8 @@
 
 	bool irqchip_split;
 	u8 nr_reserved_ioapic_pins;
+
+	struct task_struct *nx_lpage_recovery_thread;
 };
 
 struct kvm_vm_stat {
@@ -708,6 +753,7 @@
 	u32 mmu_unsync;
 	u32 remote_tlb_flush;
 	u32 lpages;
+	ulong nx_lpage_splits;
 };
 
 struct kvm_vcpu_stat {
@@ -722,6 +768,7 @@
 	u32 signal_exits;
 	u32 irq_window_exits;
 	u32 nmi_window_exits;
+	u32 l1d_flush;
 	u32 halt_exits;
 	u32 halt_successful_poll;
 	u32 halt_attempted_poll;
@@ -766,9 +813,12 @@
 	int (*hardware_setup)(void);               /* __init */
 	void (*hardware_unsetup)(void);            /* __exit */
 	bool (*cpu_has_accelerated_tpr)(void);
-	bool (*cpu_has_high_real_mode_segbase)(void);
+	bool (*has_emulated_msr)(int index);
 	void (*cpuid_update)(struct kvm_vcpu *vcpu);
 
+	int (*vm_init)(struct kvm *kvm);
+	void (*vm_destroy)(struct kvm *kvm);
+
 	/* Create, but do not attach this VCPU */
 	struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
 	void (*vcpu_free)(struct kvm_vcpu *vcpu);
@@ -831,10 +881,11 @@
 	void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
 	void (*enable_irq_window)(struct kvm_vcpu *vcpu);
 	void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
-	int (*cpu_uses_apicv)(struct kvm_vcpu *vcpu);
+	bool (*get_enable_apicv)(void);
+	void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
 	void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
 	void (*hwapic_isr_update)(struct kvm *kvm, int isr);
-	void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu);
+	void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
 	void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu, bool set);
 	void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa);
 	void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
@@ -911,6 +962,8 @@
 	void (*post_block)(struct kvm_vcpu *vcpu);
 	int (*update_pi_irte)(struct kvm *kvm, unsigned int host_irq,
 			      uint32_t guest_irq, bool set);
+
+	int (*get_msr_feature)(struct kvm_msr_entry *entry);
 };
 
 struct kvm_arch_async_pf {
@@ -998,7 +1051,8 @@
 static inline int emulate_instruction(struct kvm_vcpu *vcpu,
 			int emulation_type)
 {
-	return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0);
+	return x86_emulate_instruction(vcpu, 0,
+			emulation_type | EMULTYPE_NO_REEXECUTE, NULL, 0);
 }
 
 void kvm_enable_efer_bits(u64);
@@ -1086,6 +1140,8 @@
 gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
 				struct x86_exception *exception);
 
+void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu);
+
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
 
 int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code,
@@ -1184,25 +1240,29 @@
 #define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0)
 #define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm)
 
+asmlinkage void __noreturn kvm_spurious_fault(void);
+
 /*
  * Hardware virtualization extension instructions may fault if a
  * reboot turns off virtualization while processes are running.
- * Trap the fault and ignore the instruction if that happens.
+ * Usually after catching the fault we just panic; during reboot
+ * instead the instruction is ignored.
  */
-asmlinkage void kvm_spurious_fault(void);
-
-#define ____kvm_handle_fault_on_reboot(insn, cleanup_insn)	\
-	"666: " insn "\n\t" \
-	"668: \n\t"                           \
-	".pushsection .fixup, \"ax\" \n" \
-	"667: \n\t" \
-	cleanup_insn "\n\t"		      \
-	"cmpb $0, kvm_rebooting \n\t"	      \
-	"jne 668b \n\t"      		      \
-	__ASM_SIZE(push) " $666b \n\t"	      \
-	"call kvm_spurious_fault \n\t"	      \
-	".popsection \n\t" \
-	_ASM_EXTABLE(666b, 667b)
+#define ____kvm_handle_fault_on_reboot(insn, cleanup_insn)		\
+	"666: \n\t"							\
+	insn "\n\t"							\
+	"jmp	668f \n\t"						\
+	"667: \n\t"							\
+	"call	kvm_spurious_fault \n\t"				\
+	"668: \n\t"							\
+	".pushsection .fixup, \"ax\" \n\t"				\
+	"700: \n\t"							\
+	cleanup_insn "\n\t"						\
+	"cmpb	$0, kvm_rebooting\n\t"					\
+	"je	667b \n\t"						\
+	"jmp	668b \n\t"						\
+	".popsection \n\t"						\
+	_ASM_EXTABLE(666b, 700b)
 
 #define __kvm_handle_fault_on_reboot(insn)		\
 	____kvm_handle_fault_on_reboot(insn, "")
@@ -1222,6 +1282,7 @@
 void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
 					   unsigned long address);
 
+u64 kvm_get_arch_capabilities(void);
 void kvm_define_shared_msr(unsigned index, u32 msr);
 int kvm_set_shared_msr(unsigned index, u64 val, u64 mask);
 
--- linux-4.4.0.orig/arch/x86/include/asm/microcode.h
+++ linux-4.4.0/arch/x86/include/asm/microcode.h
@@ -2,6 +2,8 @@
 #define _ASM_X86_MICROCODE_H
 
 #include <linux/earlycpio.h>
+#include <linux/initrd.h>
+#include <asm/microcode_amd.h>
 
 #define native_rdmsr(msr, val1, val2)			\
 do {							\
@@ -158,14 +160,39 @@
 extern void __init load_ucode_bsp(void);
 extern void load_ucode_ap(void);
 extern int __init save_microcode_in_initrd(void);
-void reload_early_microcode(void);
+void reload_early_microcode(unsigned int cpu);
 extern bool get_builtin_firmware(struct cpio_data *cd, const char *name);
 #else
 static inline void __init load_ucode_bsp(void)			{ }
 static inline void load_ucode_ap(void)				{ }
 static inline int __init save_microcode_in_initrd(void)		{ return 0; }
-static inline void reload_early_microcode(void)			{ }
+static inline void reload_early_microcode(unsigned int cpu)	{ }
 static inline bool
 get_builtin_firmware(struct cpio_data *cd, const char *name)	{ return false; }
 #endif
+
+static inline unsigned long get_initrd_start(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+	return initrd_start;
+#else
+	return 0;
+#endif
+}
+
+static inline unsigned long get_initrd_start_addr(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+#ifdef CONFIG_X86_32
+	unsigned long *initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start);
+
+	return (unsigned long)__pa_nodebug(*initrd_start_p);
+#else
+	return get_initrd_start();
+#endif
+#else /* CONFIG_BLK_DEV_INITRD */
+	return 0;
+#endif
+}
+
 #endif /* _ASM_X86_MICROCODE_H */
--- linux-4.4.0.orig/arch/x86/include/asm/microcode_amd.h
+++ linux-4.4.0/arch/x86/include/asm/microcode_amd.h
@@ -59,7 +59,6 @@
 
 extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
 extern int apply_microcode_amd(int cpu);
-extern enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size);
 
 #define PATCH_MAX_SIZE PAGE_SIZE
 extern u8 amd_ucode_patch[PATCH_MAX_SIZE];
@@ -68,12 +67,14 @@
 extern void __init load_ucode_amd_bsp(unsigned int family);
 extern void load_ucode_amd_ap(void);
 extern int __init save_microcode_in_initrd_amd(void);
-void reload_ucode_amd(void);
+void reload_ucode_amd(unsigned int cpu);
+extern void amd_check_microcode(void);
 #else
 static inline void __init load_ucode_amd_bsp(unsigned int family) {}
 static inline void load_ucode_amd_ap(void) {}
 static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; }
-void reload_ucode_amd(void) {}
+static inline void reload_ucode_amd(unsigned int cpu) {}
+static inline void amd_check_microcode(void) {}
 #endif
 
 extern bool check_current_patch_level(u32 *rev, bool early);
--- linux-4.4.0.orig/arch/x86/include/asm/microcode_intel.h
+++ linux-4.4.0/arch/x86/include/asm/microcode_intel.h
@@ -53,6 +53,21 @@
 
 #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
 
+static inline u32 intel_get_microcode_revision(void)
+{
+	u32 rev, dummy;
+
+	native_wrmsrl(MSR_IA32_UCODE_REV, 0);
+
+	/* As documented in the SDM: Do a CPUID 1 here */
+	native_cpuid_eax(1);
+
+	/* get the current revision from MSR 0x8B */
+	native_rdmsr(MSR_IA32_UCODE_REV, dummy, rev);
+
+	return rev;
+}
+
 extern int has_newer_microcode(void *mc, unsigned int csig, int cpf, int rev);
 extern int microcode_sanity_check(void *mc, int print_err);
 extern int find_matching_signature(void *mc, unsigned int csig, int cpf);
--- linux-4.4.0.orig/arch/x86/include/asm/mmu.h
+++ linux-4.4.0/arch/x86/include/asm/mmu.h
@@ -3,12 +3,18 @@
 
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
+#include <linux/atomic.h>
 
 /*
- * The x86 doesn't have a mmu context, but
- * we put the segment information here.
+ * x86 has arch-specific MMU state beyond what lives in mm_struct.
  */
 typedef struct {
+	/*
+	 * ctx_id uniquely identifies this mm_struct.  A ctx_id will never
+	 * be reused, and zero is not a valid ctx_id.
+	 */
+	u64 ctx_id;
+
 #ifdef CONFIG_MODIFY_LDT_SYSCALL
 	struct ldt_struct *ldt;
 #endif
@@ -24,12 +30,11 @@
 	atomic_t perf_rdpmc_allowed;	/* nonzero if rdpmc is allowed */
 } mm_context_t;
 
-#ifdef CONFIG_SMP
+#define INIT_MM_CONTEXT(mm)						\
+	.context = {							\
+		.ctx_id = 1,						\
+	}
+
 void leave_mm(int cpu);
-#else
-static inline void leave_mm(int cpu)
-{
-}
-#endif
 
 #endif /* _ASM_X86_MMU_H */
--- linux-4.4.0.orig/arch/x86/include/asm/mmu_context.h
+++ linux-4.4.0/arch/x86/include/asm/mmu_context.h
@@ -11,6 +11,9 @@
 #include <asm/tlbflush.h>
 #include <asm/paravirt.h>
 #include <asm/mpx.h>
+
+extern atomic64_t last_mm_ctx_id;
+
 #ifndef CONFIG_PARAVIRT
 static inline void paravirt_activate_mm(struct mm_struct *prev,
 					struct mm_struct *next)
@@ -52,15 +55,15 @@
 /*
  * Used for LDT copy/destruction.
  */
-int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
-void destroy_context(struct mm_struct *mm);
+int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm);
+void destroy_context_ldt(struct mm_struct *mm);
 #else	/* CONFIG_MODIFY_LDT_SYSCALL */
-static inline int init_new_context(struct task_struct *tsk,
-				   struct mm_struct *mm)
+static inline int init_new_context_ldt(struct task_struct *tsk,
+				       struct mm_struct *mm)
 {
 	return 0;
 }
-static inline void destroy_context(struct mm_struct *mm) {}
+static inline void destroy_context_ldt(struct mm_struct *mm) {}
 #endif
 
 static inline void load_mm_ldt(struct mm_struct *mm)
@@ -98,77 +101,27 @@
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
-#ifdef CONFIG_SMP
 	if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
 		this_cpu_write(cpu_tlbstate.state, TLBSTATE_LAZY);
-#endif
 }
 
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-			     struct task_struct *tsk)
+static inline int init_new_context(struct task_struct *tsk,
+				   struct mm_struct *mm)
 {
-	unsigned cpu = smp_processor_id();
-
-	if (likely(prev != next)) {
-#ifdef CONFIG_SMP
-		this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
-		this_cpu_write(cpu_tlbstate.active_mm, next);
-#endif
-		cpumask_set_cpu(cpu, mm_cpumask(next));
-
-		/* Re-load page tables */
-		load_cr3(next->pgd);
-		trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
-
-		/* Stop flush ipis for the previous mm */
-		cpumask_clear_cpu(cpu, mm_cpumask(prev));
+	mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id);
+	return init_new_context_ldt(tsk, mm);
+}
+static inline void destroy_context(struct mm_struct *mm)
+{
+	destroy_context_ldt(mm);
+}
 
-		/* Load per-mm CR4 state */
-		load_mm_cr4(next);
+extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+		      struct task_struct *tsk);
 
-#ifdef CONFIG_MODIFY_LDT_SYSCALL
-		/*
-		 * Load the LDT, if the LDT is different.
-		 *
-		 * It's possible that prev->context.ldt doesn't match
-		 * the LDT register.  This can happen if leave_mm(prev)
-		 * was called and then modify_ldt changed
-		 * prev->context.ldt but suppressed an IPI to this CPU.
-		 * In this case, prev->context.ldt != NULL, because we
-		 * never set context.ldt to NULL while the mm still
-		 * exists.  That means that next->context.ldt !=
-		 * prev->context.ldt, because mms never share an LDT.
-		 */
-		if (unlikely(prev->context.ldt != next->context.ldt))
-			load_mm_ldt(next);
-#endif
-	}
-#ifdef CONFIG_SMP
-	  else {
-		this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
-		BUG_ON(this_cpu_read(cpu_tlbstate.active_mm) != next);
-
-		if (!cpumask_test_cpu(cpu, mm_cpumask(next))) {
-			/*
-			 * On established mms, the mm_cpumask is only changed
-			 * from irq context, from ptep_clear_flush() while in
-			 * lazy tlb mode, and here. Irqs are blocked during
-			 * schedule, protecting us from simultaneous changes.
-			 */
-			cpumask_set_cpu(cpu, mm_cpumask(next));
-			/*
-			 * We were in lazy tlb mode and leave_mm disabled
-			 * tlb flush IPI delivery. We must reload CR3
-			 * to make sure to use no freed page tables.
-			 */
-			load_cr3(next->pgd);
-			trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
-			load_mm_cr4(next);
-			load_mm_ldt(next);
-		}
-	}
-#endif
-}
+extern void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
+			       struct task_struct *tsk);
+#define switch_mm_irqs_off switch_mm_irqs_off
 
 #define activate_mm(prev, next)			\
 do {						\
--- linux-4.4.0.orig/arch/x86/include/asm/msi.h
+++ linux-4.4.0/arch/x86/include/asm/msi.h
@@ -1,7 +1,13 @@
 #ifndef _ASM_X86_MSI_H
 #define _ASM_X86_MSI_H
 #include <asm/hw_irq.h>
+#include <asm/irqdomain.h>
 
 typedef struct irq_alloc_info msi_alloc_info_t;
 
+int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
+		    msi_alloc_info_t *arg);
+
+void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc);
+
 #endif /* _ASM_X86_MSI_H */
--- linux-4.4.0.orig/arch/x86/include/asm/msr-index.h
+++ linux-4.4.0/arch/x86/include/asm/msr-index.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_MSR_INDEX_H
 #define _ASM_X86_MSR_INDEX_H
 
+#include <linux/bits.h>
+
 /* CPU model specific register (MSR) numbers */
 
 /* x86-64 specific MSRs */
@@ -32,6 +34,20 @@
 #define EFER_FFXSR		(1<<_EFER_FFXSR)
 
 /* Intel MSRs. Some also available on other CPUs */
+#define MSR_IA32_SPEC_CTRL		0x00000048 /* Speculation Control */
+#define SPEC_CTRL_IBRS			(1)	   /* Indirect Branch Restricted Speculation */
+#define SPEC_CTRL_STIBP_SHIFT		1	   /* Single Thread Indirect Branch Predictor (STIBP) bit */
+#define SPEC_CTRL_STIBP			BIT(SPEC_CTRL_STIBP_SHIFT)	/* STIBP mask */
+#define SPEC_CTRL_SSBD_SHIFT		2	   /* Speculative Store Bypass Disable bit */
+#define SPEC_CTRL_SSBD			BIT(SPEC_CTRL_SSBD_SHIFT)	/* Speculative Store Bypass Disable */
+#define SPEC_CTRL_RRSBA_DIS_S_SHIFT	6	   /* Disable RRSBA behavior */
+#define SPEC_CTRL_RRSBA_DIS_S		BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT)
+#define SPEC_CTRL_BHI_DIS_S_SHIFT	10	   /* Disable Branch History Injection behavior */
+#define SPEC_CTRL_BHI_DIS_S		BIT(SPEC_CTRL_BHI_DIS_S_SHIFT)
+
+#define MSR_IA32_PRED_CMD		0x00000049 /* Prediction Command */
+#define PRED_CMD_IBPB			BIT(0)	   /* Indirect Branch Prediction Barrier */
+
 #define MSR_IA32_PERFCTR0		0x000000c1
 #define MSR_IA32_PERFCTR1		0x000000c2
 #define MSR_FSB_FREQ			0x000000cd
@@ -45,9 +61,103 @@
 #define SNB_C3_AUTO_UNDEMOTE		(1UL << 28)
 
 #define MSR_MTRRcap			0x000000fe
+
+#define MSR_IA32_ARCH_CAPABILITIES	0x0000010a
+#define ARCH_CAP_RDCL_NO		BIT(0)	/* Not susceptible to Meltdown */
+#define ARCH_CAP_IBRS_ALL		BIT(1)	/* Enhanced IBRS support */
+#define ARCH_CAP_RSBA			BIT(2)	/* RET may use alternative branch predictors */
+#define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH	BIT(3)	/* Skip L1D flush on vmentry */
+#define ARCH_CAP_SSB_NO			BIT(4)	/*
+						 * Not susceptible to Speculative Store Bypass
+						 * attack, so no Speculative Store Bypass
+						 * control required.
+						 */
+#define ARCH_CAP_MDS_NO			BIT(5)   /*
+						  * Not susceptible to
+						  * Microarchitectural Data
+						  * Sampling (MDS) vulnerabilities.
+						  */
+#define ARCH_CAP_PSCHANGE_MC_NO		BIT(6)	 /*
+						  * The processor is not susceptible to a
+						  * machine check error due to modifying the
+						  * code page size along with either the
+						  * physical address or cache type
+						  * without TLB invalidation.
+						  */
+#define ARCH_CAP_TSX_CTRL_MSR		BIT(7)	/* MSR for TSX control is available. */
+#define ARCH_CAP_TAA_NO			BIT(8)	/*
+						 * Not susceptible to
+						 * TSX Async Abort (TAA) vulnerabilities.
+						 */
+#define ARCH_CAP_SBDR_SSDP_NO		BIT(13)	/*
+						 * Not susceptible to SBDR and SSDP
+						 * variants of Processor MMIO stale data
+						 * vulnerabilities.
+						 */
+#define ARCH_CAP_FBSDP_NO		BIT(14)	/*
+						 * Not susceptible to FBSDP variant of
+						 * Processor MMIO stale data
+						 * vulnerabilities.
+						 */
+#define ARCH_CAP_PSDP_NO		BIT(15)	/*
+						 * Not susceptible to PSDP variant of
+						 * Processor MMIO stale data
+						 * vulnerabilities.
+						 */
+#define ARCH_CAP_FB_CLEAR		BIT(17)	/*
+						 * VERW clears CPU fill buffer
+						 * even on MDS_NO CPUs.
+						 */
+#define ARCH_CAP_FB_CLEAR_CTRL		BIT(18)	/*
+						 * MSR_IA32_MCU_OPT_CTRL[FB_CLEAR_DIS]
+						 * bit available to control VERW
+						 * behavior.
+						 */
+#define ARCH_CAP_RRSBA			BIT(19)	/*
+						 * Indicates RET may use predictors
+						 * other than the RSB. With eIBRS
+						 * enabled predictions in kernel mode
+						 * are restricted to targets in
+						 * kernel.
+						 */
+#define ARCH_CAP_BHI_NO			BIT(20)	/*
+						 * CPU is not affected by Branch
+						 * History Injection.
+						 */
+#define ARCH_CAP_PBRSB_NO		BIT(24)	/*
+						 * Not susceptible to Post-Barrier
+						 * Return Stack Buffer Predictions.
+						 */
+#define ARCH_CAP_GDS_CTRL		BIT(25)	/*
+						 * CPU is vulnerable to Gather
+						 * Data Sampling (GDS) and
+						 * has controls for mitigation.
+						 */
+#define ARCH_CAP_GDS_NO			BIT(26)	/*
+						 * CPU is not vulnerable to Gather
+						 * Data Sampling (GDS).
+						 */
+
+#define MSR_IA32_FLUSH_CMD		0x0000010b
+#define L1D_FLUSH			BIT(0)	/*
+						 * Writeback and invalidate the
+						 * L1 data cache.
+						 */
+
 #define MSR_IA32_BBL_CR_CTL		0x00000119
 #define MSR_IA32_BBL_CR_CTL3		0x0000011e
 
+#define MSR_IA32_TSX_CTRL		0x00000122
+#define TSX_CTRL_RTM_DISABLE		BIT(0)	/* Disable RTM feature */
+#define TSX_CTRL_CPUID_CLEAR		BIT(1)	/* Disable TSX enumeration */
+
+/* SRBDS support */
+#define MSR_IA32_MCU_OPT_CTRL		0x00000123
+#define RNGDS_MITG_DIS			BIT(0)
+#define FB_CLEAR_DIS			BIT(3)	/* CPU Fill buffer clear disable */
+#define GDS_MITG_DIS			BIT(4)	/* Disable GDS mitigation */
+#define GDS_MITG_LOCKED			BIT(5)	/* GDS mitigation locked */
+
 #define MSR_IA32_SYSENTER_CS		0x00000174
 #define MSR_IA32_SYSENTER_ESP		0x00000175
 #define MSR_IA32_SYSENTER_EIP		0x00000176
@@ -132,6 +242,7 @@
 
 /* DEBUGCTLMSR bits (others vary by model): */
 #define DEBUGCTLMSR_LBR			(1UL <<  0) /* last branch recording */
+#define DEBUGCTLMSR_BTF_SHIFT		1
 #define DEBUGCTLMSR_BTF			(1UL <<  1) /* single-step on branches */
 #define DEBUGCTLMSR_TR			(1UL <<  6)
 #define DEBUGCTLMSR_BTS			(1UL <<  7)
@@ -162,6 +273,14 @@
 #define MSR_PKG_C9_RESIDENCY		0x00000631
 #define MSR_PKG_C10_RESIDENCY		0x00000632
 
+/* Interrupt Response Limit */
+#define MSR_PKGC3_IRTL			0x0000060a
+#define MSR_PKGC6_IRTL			0x0000060b
+#define MSR_PKGC7_IRTL			0x0000060c
+#define MSR_PKGC8_IRTL			0x00000633
+#define MSR_PKGC9_IRTL			0x00000634
+#define MSR_PKGC10_IRTL			0x00000635
+
 /* Run Time Average Power Limiting (RAPL) Interface */
 
 #define MSR_RAPL_POWER_UNIT		0x00000606
@@ -283,11 +402,18 @@
 #define MSR_AMD64_PATCH_LEVEL		0x0000008b
 #define MSR_AMD64_TSC_RATIO		0xc0000104
 #define MSR_AMD64_NB_CFG		0xc001001f
+#define MSR_AMD64_CPUID_FN_1		0xc0011004
 #define MSR_AMD64_PATCH_LOADER		0xc0010020
 #define MSR_AMD64_OSVW_ID_LENGTH	0xc0010140
 #define MSR_AMD64_OSVW_STATUS		0xc0010141
 #define MSR_AMD64_LS_CFG		0xc0011020
 #define MSR_AMD64_DC_CFG		0xc0011022
+
+#define MSR_AMD64_DE_CFG		0xc0011029
+#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT	 1
+#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE	BIT_ULL(MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT)
+#define MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT 9
+
 #define MSR_AMD64_BU_CFG2		0xc001102a
 #define MSR_AMD64_IBSFETCHCTL		0xc0011030
 #define MSR_AMD64_IBSFETCHLINAD		0xc0011031
@@ -308,6 +434,8 @@
 #define MSR_AMD64_IBSOPDATA4		0xc001103d
 #define MSR_AMD64_IBS_REG_COUNT_MAX	8 /* includes MSR_AMD64_IBSBRTARGET */
 
+#define MSR_AMD64_VIRT_SPEC_CTRL	0xc001011f
+
 /* Fam 16h MSRs */
 #define MSR_F16H_L2I_PERF_CTL		0xc0010230
 #define MSR_F16H_L2I_PERF_CTR		0xc0010231
@@ -321,6 +449,8 @@
 #define MSR_F15H_PERF_CTR		0xc0010201
 #define MSR_F15H_NB_PERF_CTL		0xc0010240
 #define MSR_F15H_NB_PERF_CTR		0xc0010241
+#define MSR_F15H_IC_CFG			0xc0011021
+#define MSR_F15H_IC_CFG_DIS_IND		BIT_ULL(14)
 
 /* Fam 10h MSRs */
 #define MSR_FAM10H_MMIO_CONF_BASE	0xc0010058
@@ -330,6 +460,9 @@
 #define FAM10H_MMIO_CONF_BASE_MASK	0xfffffffULL
 #define FAM10H_MMIO_CONF_BASE_SHIFT	20
 #define MSR_FAM10H_NODE_ID		0xc001100c
+#define MSR_F10H_DECFG			0xc0011029
+#define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT	1
+#define MSR_F10H_DECFG_LFENCE_SERIALIZE		BIT_ULL(MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT)
 
 /* K8 MSRs */
 #define MSR_K8_TOP_MEM1			0xc001001a
@@ -405,6 +538,8 @@
 #define MSR_IA32_TSC_ADJUST             0x0000003b
 #define MSR_IA32_BNDCFGS		0x00000d90
 
+#define MSR_IA32_BNDCFGS_RSVD		0x00000ffc
+
 #define MSR_IA32_XSS			0x00000da0
 
 #define FEATURE_CONTROL_LOCKED				(1<<0)
--- linux-4.4.0.orig/arch/x86/include/asm/msr.h
+++ linux-4.4.0/arch/x86/include/asm/msr.h
@@ -32,6 +32,16 @@
 	int err;
 };
 
+struct saved_msr {
+	bool valid;
+	struct msr_info info;
+};
+
+struct saved_msrs {
+	unsigned int num;
+	struct saved_msr *array;
+};
+
 static inline unsigned long long native_read_tscp(unsigned int *aux)
 {
 	unsigned long low, high;
@@ -147,8 +157,7 @@
 	 * that some other imaginary CPU is updating continuously with a
 	 * time stamp.
 	 */
-	alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC,
-			  "lfence", X86_FEATURE_LFENCE_RDTSC);
+	barrier_nospec();
 	return rdtsc();
 }
 
--- linux-4.4.0.orig/arch/x86/include/asm/mtrr.h
+++ linux-4.4.0/arch/x86/include/asm/mtrr.h
@@ -24,6 +24,7 @@
 #define _ASM_X86_MTRR_H
 
 #include <uapi/asm/mtrr.h>
+#include <asm/pat.h>
 
 
 /*
@@ -83,9 +84,12 @@
 static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
 {
 }
+static inline void mtrr_bp_init(void)
+{
+	pat_disable("MTRRs disabled, skipping PAT initialization too.");
+}
 
 #define mtrr_ap_init() do {} while (0)
-#define mtrr_bp_init() do {} while (0)
 #define set_mtrr_aps_delayed_init() do {} while (0)
 #define mtrr_aps_init() do {} while (0)
 #define mtrr_bp_restore() do {} while (0)
--- linux-4.4.0.orig/arch/x86/include/asm/mwait.h
+++ linux-4.4.0/arch/x86/include/asm/mwait.h
@@ -3,6 +3,11 @@
 
 #include <linux/sched.h>
 
+#include <asm/cpufeature.h>
+#include <asm/microcode.h>
+#include <asm/nospec-branch.h>
+#include <asm/spec_ctrl.h>
+
 #define MWAIT_SUBSTATE_MASK		0xf
 #define MWAIT_CSTATE_MASK		0xf
 #define MWAIT_SUBSTATE_SIZE		4
@@ -16,7 +21,7 @@
 #define MWAIT_ECX_INTERRUPT_BREAK	0x1
 #define MWAITX_ECX_TIMER_ENABLE		BIT(1)
 #define MWAITX_MAX_LOOPS		((u32)-1)
-#define MWAITX_DISABLE_CSTATES		0xf
+#define MWAITX_DISABLE_CSTATES		0xf0
 
 static inline void __monitor(const void *eax, unsigned long ecx,
 			     unsigned long edx)
@@ -36,6 +41,8 @@
 
 static inline void __mwait(unsigned long eax, unsigned long ecx)
 {
+	mds_idle_clear_cpu_buffers();
+
 	/* "mwait %eax, %ecx;" */
 	asm volatile(".byte 0x0f, 0x01, 0xc9;"
 		     :: "a" (eax), "c" (ecx));
@@ -70,6 +77,8 @@
 static inline void __mwaitx(unsigned long eax, unsigned long ebx,
 			    unsigned long ecx)
 {
+	/* No MDS buffer clear as this is AMD/HYGON only */
+
 	/* "mwaitx %eax, %ebx, %ecx;" */
 	asm volatile(".byte 0x0f, 0x01, 0xfb;"
 		     :: "a" (eax), "b" (ebx), "c" (ecx));
@@ -77,6 +86,8 @@
 
 static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 {
+	mds_idle_clear_cpu_buffers();
+
 	trace_hardirqs_on();
 	/* "mwait %eax, %ecx;" */
 	asm volatile("sti; .byte 0x0f, 0x01, 0xc9;"
@@ -95,16 +106,20 @@
  */
 static inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
 {
-	if (!current_set_polling_and_test()) {
+	if (static_cpu_has_bug(X86_BUG_MONITOR) || !current_set_polling_and_test()) {
 		if (static_cpu_has_bug(X86_BUG_CLFLUSH_MONITOR)) {
 			mb();
 			clflush((void *)&current_thread_info()->flags);
 			mb();
 		}
 
+		ubuntu_restrict_branch_speculation_end();
+
 		__monitor((void *)&current_thread_info()->flags, 0, 0);
 		if (!need_resched())
 			__mwait(eax, ecx);
+
+		ubuntu_restrict_branch_speculation_start();
 	}
 	current_clr_polling();
 }
--- linux-4.4.0.orig/arch/x86/include/asm/nospec-branch.h
+++ linux-4.4.0/arch/x86/include/asm/nospec-branch.h
@@ -0,0 +1,439 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_X86_NOSPEC_BRANCH_H_
+#define _ASM_X86_NOSPEC_BRANCH_H_
+
+#include <linux/static_key.h>
+
+#include <asm/alternative.h>
+#include <asm/alternative-asm.h>
+#include <asm/cpufeatures.h>
+#include <asm/msr-index.h>
+#include <asm/percpu.h>
+
+/*
+ * Fill the CPU return stack buffer.
+ *
+ * Each entry in the RSB, if used for a speculative 'ret', contains an
+ * infinite 'pause; lfence; jmp' loop to capture speculative execution.
+ *
+ * This is required in various cases for retpoline and IBRS-based
+ * mitigations for the Spectre variant 2 vulnerability. Sometimes to
+ * eliminate potentially bogus entries from the RSB, and sometimes
+ * purely to ensure that it doesn't get empty, which on some CPUs would
+ * allow predictions from other (unwanted!) sources to be used.
+ *
+ * We define a CPP macro such that it can be used from both .S files and
+ * inline assembly. It's possible to do a .macro and then include that
+ * from C via asm(".include <asm/nospec-branch.h>") but let's not go there.
+ */
+
+#define RSB_CLEAR_LOOPS		32	/* To forcibly overwrite all entries */
+#define RSB_FILL_LOOPS		16	/* To avoid underflow */
+
+/*
+ * Google experimented with loop-unrolling and this turned out to be
+ * the optimal version — two calls, each with their own speculation
+ * trap should their return address end up getting used, in a loop.
+ */
+#define __FILL_RETURN_BUFFER(reg, nr, sp)	\
+	mov	$(nr/2), reg;			\
+771:						\
+	call	772f;				\
+773:	/* speculation trap */			\
+	pause;					\
+	lfence;					\
+	jmp	773b;				\
+772:						\
+	call	774f;				\
+775:	/* speculation trap */			\
+	pause;					\
+	lfence;					\
+	jmp	775b;				\
+774:						\
+	add	$(BITS_PER_LONG/8) * 2, sp;	\
+	dec	reg;				\
+	jnz	771b;				\
+	/* barrier for jnz misprediction */	\
+	lfence;
+
+#define ISSUE_UNBALANCED_RET_GUARD(sp)		\
+	call 992f;				\
+	int3;					\
+992:						\
+	add $(BITS_PER_LONG/8), sp;		\
+	lfence;
+
+#ifdef __ASSEMBLY__
+
+/*
+ * This should be used immediately before an indirect jump/call. It tells
+ * objtool the subsequent indirect jump/call is vouched safe for retpoline
+ * builds.
+ */
+.macro ANNOTATE_RETPOLINE_SAFE
+	.Lannotate_\@:
+	.pushsection .discard.retpoline_safe
+	_ASM_PTR .Lannotate_\@
+	.popsection
+.endm
+
+/*
+ * These are the bare retpoline primitives for indirect jmp and call.
+ * Do not use these directly; they only exist to make the ALTERNATIVE
+ * invocation below less ugly.
+ */
+.macro RETPOLINE_JMP reg:req
+	call	.Ldo_rop_\@
+.Lspec_trap_\@:
+	pause
+	lfence
+	jmp	.Lspec_trap_\@
+.Ldo_rop_\@:
+	mov	\reg, (%_ASM_SP)
+	ret
+.endm
+
+/*
+ * This is a wrapper around RETPOLINE_JMP so the called function in reg
+ * returns to the instruction after the macro.
+ */
+.macro RETPOLINE_CALL reg:req
+	jmp	.Ldo_call_\@
+.Ldo_retpoline_jmp_\@:
+	RETPOLINE_JMP \reg
+.Ldo_call_\@:
+	call	.Ldo_retpoline_jmp_\@
+.endm
+
+/*
+ * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
+ * indirect jmp/call which may be susceptible to the Spectre variant 2
+ * attack.
+ */
+.macro JMP_NOSPEC reg:req
+#ifdef CONFIG_RETPOLINE
+	ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *\reg),	\
+		__stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE,	\
+		__stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *\reg), X86_FEATURE_RETPOLINE_LFENCE
+#else
+	jmp	*\reg
+#endif
+.endm
+
+.macro CALL_NOSPEC reg:req
+#ifdef CONFIG_RETPOLINE
+	ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *\reg),	\
+		__stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\
+		__stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *\reg), X86_FEATURE_RETPOLINE_LFENCE
+#else
+	call	*\reg
+#endif
+.endm
+
+ /*
+  * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
+  * monstrosity above, manually.
+  */
+.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
+	ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
+	__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
+.Lskip_rsb_\@:
+.endm
+
+#ifdef CONFIG_X86_64
+.macro CLEAR_BRANCH_HISTORY
+	ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP
+.endm
+
+.macro CLEAR_BRANCH_HISTORY_VMEXIT
+	ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT
+.endm
+#else
+#define CLEAR_BRANCH_HISTORY
+#define CLEAR_BRANCH_HISTORY_VMEXIT
+#endif
+
+#else /* __ASSEMBLY__ */
+
+#ifdef CONFIG_X86_64
+#define CLEAR_BRANCH_HISTORY_VMEXIT \
+	ALTERNATIVE("", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT)
+#else
+#define CLEAR_BRANCH_HISTORY_VMEXIT
+#endif
+
+#define ANNOTATE_RETPOLINE_SAFE					\
+	"999:\n\t"						\
+	".pushsection .discard.retpoline_safe\n\t"		\
+	_ASM_PTR " 999b\n\t"					\
+	".popsection\n\t"
+
+#ifdef CONFIG_X86_64
+extern void clear_bhb_loop(void);
+#endif
+
+#if defined(CONFIG_X86_64) && defined(RETPOLINE)
+
+/*
+ * Since the inline asm uses the %V modifier which is only in newer GCC,
+ * the 64-bit one is dependent on RETPOLINE not CONFIG_RETPOLINE.
+ */
+# define CALL_NOSPEC						\
+	ALTERNATIVE(						\
+	ANNOTATE_RETPOLINE_SAFE					\
+	"call *%[thunk_target]\n",				\
+	"call __x86_indirect_thunk_%V[thunk_target]\n",		\
+	X86_FEATURE_RETPOLINE)
+# define THUNK_TARGET(addr) [thunk_target] "r" (addr)
+
+#elif defined(CONFIG_X86_32) && defined(CONFIG_RETPOLINE)
+/*
+ * For i386 we use the original ret-equivalent retpoline, because
+ * otherwise we'll run out of registers. We don't care about CET
+ * here, anyway.
+ */
+# define CALL_NOSPEC 						\
+	ALTERNATIVE(						\
+	ANNOTATE_RETPOLINE_SAFE					\
+	"call *%[thunk_target]\n",				\
+	"       jmp    904f;\n"					\
+	"       .align 16\n"					\
+	"901:	call   903f;\n"					\
+	"902:	pause;\n"					\
+	"    	lfence;\n"					\
+	"       jmp    902b;\n"					\
+	"       .align 16\n"					\
+	"903:	lea    4(%%esp), %%esp;\n"			\
+	"       pushl  %[thunk_target];\n"			\
+	"       ret;\n"						\
+	"       .align 16\n"					\
+	"904:	call   901b;\n",				\
+	X86_FEATURE_RETPOLINE)
+
+# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
+#else /* No retpoline for C / inline asm */
+# define CALL_NOSPEC "call *%[thunk_target]\n"
+# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
+#endif
+
+/* The IBPB runtime control knob */
+extern unsigned int ibpb_enabled;
+int set_ibpb_enabled(unsigned int);
+
+/* The IBRS runtime control knob */
+extern unsigned int ibrs_enabled;
+int set_ibrs_enabled(unsigned int);
+
+/* The Spectre V2 mitigation variants */
+enum spectre_v2_mitigation {
+	SPECTRE_V2_NONE,
+	SPECTRE_V2_RETPOLINE,
+	SPECTRE_V2_LFENCE,
+	SPECTRE_V2_EIBRS,
+	SPECTRE_V2_EIBRS_RETPOLINE,
+	SPECTRE_V2_EIBRS_LFENCE,
+	SPECTRE_V2_IBRS,
+};
+
+/* The indirect branch speculation control variants */
+enum spectre_v2_user_mitigation {
+	SPECTRE_V2_USER_NONE,
+	SPECTRE_V2_USER_STRICT,
+	SPECTRE_V2_USER_STRICT_PREFERRED,
+	SPECTRE_V2_USER_PRCTL,
+	SPECTRE_V2_USER_SECCOMP,
+};
+
+/* The Speculative Store Bypass disable variants */
+enum ssb_mitigation {
+	SPEC_STORE_BYPASS_NONE,
+	SPEC_STORE_BYPASS_DISABLE,
+	SPEC_STORE_BYPASS_PRCTL,
+	SPEC_STORE_BYPASS_SECCOMP,
+};
+
+extern char __indirect_thunk_start[];
+extern char __indirect_thunk_end[];
+
+/*
+ * On VMEXIT we must ensure that no RSB predictions learned in the guest
+ * can be followed in the host, by overwriting the RSB completely. Both
+ * retpoline and IBRS mitigations for Spectre v2 need this; only on future
+ * CPUs with IBRS_ALL *might* it be avoided.
+ */
+static __always_inline void vmexit_fill_RSB(void)
+{
+	unsigned long loops;
+
+	asm volatile (
+		      ALTERNATIVE_2("jmp 910f", "", X86_FEATURE_RSB_VMEXIT,
+				    "jmp 911f", X86_FEATURE_RSB_VMEXIT_LITE)
+		      __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1))
+		      "911:"
+		      __stringify(ISSUE_UNBALANCED_RET_GUARD(%1))
+		      "910:"
+		      : "=r" (loops), ASM_CALL_CONSTRAINT
+		      : : "memory" );
+}
+
+static __always_inline
+void alternative_msr_write(unsigned int msr, u64 val, unsigned int feature)
+{
+	asm volatile(ALTERNATIVE("", "wrmsr", %c[feature])
+		: : "c" (msr),
+		    "a" ((u32)val),
+		    "d" ((u32)(val >> 32)),
+		    [feature] "i" (feature)
+		: "memory");
+}
+
+static inline void indirect_branch_prediction_barrier(void)
+{
+	u64 val = PRED_CMD_IBPB;
+
+	if (ibpb_enabled)
+		alternative_msr_write(MSR_IA32_PRED_CMD, val,
+				      X86_FEATURE_USE_IBPB);
+}
+
+/* The Intel SPEC CTRL MSR base value cache */
+extern u64 x86_spec_ctrl_base;
+DECLARE_PER_CPU(u64, x86_spec_ctrl_current);
+DECLARE_PER_CPU(bool, x86_ibpb_exit_to_user);
+extern void update_spec_ctrl_cond(u64 val);
+extern u64 spec_ctrl_current(void);
+
+/*
+ * With retpoline, we must use IBRS to restrict branch prediction
+ * before calling into firmware.
+ *
+ * (Implemented as CPP macros due to header hell.)
+ */
+#define firmware_restrict_branch_speculation_start()			\
+do {									\
+	preempt_disable();						\
+	alternative_msr_write(MSR_IA32_SPEC_CTRL,			\
+			      spec_ctrl_current() | SPEC_CTRL_IBRS,	\
+			      X86_FEATURE_USE_IBRS_FW);			\
+} while (0)
+
+#define firmware_restrict_branch_speculation_end()			\
+do {									\
+	alternative_msr_write(MSR_IA32_SPEC_CTRL,			\
+			      spec_ctrl_current(),			\
+			      X86_FEATURE_USE_IBRS_FW);			\
+	preempt_enable();						\
+} while (0)
+
+#define ubuntu_restrict_branch_speculation_start()			\
+do {									\
+	u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;			\
+									\
+	if (ibrs_enabled)						\
+		native_wrmsrl(MSR_IA32_SPEC_CTRL, val);			\
+} while (0)
+
+#define ubuntu_restrict_branch_speculation_end()			\
+do {									\
+	u64 val = x86_spec_ctrl_base;					\
+									\
+	if (ibrs_enabled)						\
+		native_wrmsrl(MSR_IA32_SPEC_CTRL, val);			\
+ } while (0)
+
+DECLARE_STATIC_KEY_FALSE(switch_to_cond_stibp);
+DECLARE_STATIC_KEY_FALSE(switch_mm_cond_ibpb);
+DECLARE_STATIC_KEY_FALSE(switch_mm_always_ibpb);
+
+DECLARE_STATIC_KEY_FALSE(mds_user_clear);
+DECLARE_STATIC_KEY_FALSE(mds_idle_clear);
+
+DECLARE_STATIC_KEY_FALSE(mmio_stale_data_clear);
+
+#include <asm/segment.h>
+
+/**
+ * mds_clear_cpu_buffers - Mitigation for MDS and TAA vulnerability
+ *
+ * This uses the otherwise unused and obsolete VERW instruction in
+ * combination with microcode which triggers a CPU buffer flush when the
+ * instruction is executed.
+ */
+static __always_inline void mds_clear_cpu_buffers(void)
+{
+	static const u16 ds = __KERNEL_DS;
+
+	/*
+	 * Has to be the memory-operand variant because only that
+	 * guarantees the CPU buffer flush functionality according to
+	 * documentation. The register-operand variant does not.
+	 * Works with any segment selector, but a valid writable
+	 * data segment is the fastest variant.
+	 *
+	 * "cc" clobber is required because VERW modifies ZF.
+	 */
+	asm volatile("verw %[ds]" : : [ds] "m" (ds) : "cc");
+}
+
+/**
+ * mds_user_clear_cpu_buffers - Mitigation for MDS and TAA vulnerability
+ *
+ * Clear CPU buffers if the corresponding static key is enabled
+ */
+static __always_inline void mds_user_clear_cpu_buffers(void)
+{
+	if (static_branch_likely(&mds_user_clear))
+		mds_clear_cpu_buffers();
+}
+
+/**
+ * mds_idle_clear_cpu_buffers - Mitigation for MDS vulnerability
+ *
+ * Clear CPU buffers if the corresponding static key is enabled
+ */
+static inline void mds_idle_clear_cpu_buffers(void)
+{
+	if (static_branch_likely(&mds_idle_clear))
+		mds_clear_cpu_buffers();
+}
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Below is used in the eBPF JIT compiler and emits the byte sequence
+ * for the following assembly:
+ *
+ * With retpolines configured:
+ *
+ *    callq do_rop
+ *  spec_trap:
+ *    pause
+ *    lfence
+ *    jmp spec_trap
+ *  do_rop:
+ *    mov %rax,(%rsp)
+ *    retq
+ *
+ * Without retpolines configured:
+ *
+ *    jmp *%rax
+ */
+#ifdef CONFIG_RETPOLINE
+# define RETPOLINE_RAX_BPF_JIT_SIZE	17
+# define RETPOLINE_RAX_BPF_JIT()				\
+	EMIT1_off32(0xE8, 7);	 /* callq do_rop */		\
+	/* spec_trap: */					\
+	EMIT2(0xF3, 0x90);       /* pause */			\
+	EMIT3(0x0F, 0xAE, 0xE8); /* lfence */			\
+	EMIT2(0xEB, 0xF9);       /* jmp spec_trap */		\
+	/* do_rop: */						\
+	EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */	\
+	EMIT1(0xC3);             /* retq */
+#else
+# define RETPOLINE_RAX_BPF_JIT_SIZE	2
+# define RETPOLINE_RAX_BPF_JIT()				\
+	EMIT2(0xFF, 0xE0);	 /* jmp *%rax */
+#endif
+
+#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
--- linux-4.4.0.orig/arch/x86/include/asm/page.h
+++ linux-4.4.0/arch/x86/include/asm/page.h
@@ -37,7 +37,10 @@
 	alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
 
+#ifndef __pa
 #define __pa(x)		__phys_addr((unsigned long)(x))
+#endif
+
 #define __pa_nodebug(x)	__phys_addr_nodebug((unsigned long)(x))
 /* __pa_symbol should be used for C visible symbols.
    This seems to be the official gcc blessed way to do such arithmetic. */
@@ -51,7 +54,9 @@
 #define __pa_symbol(x) \
 	__phys_addr_symbol(__phys_reloc_hide((unsigned long)(x)))
 
+#ifndef __va
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+#endif
 
 #define __boot_va(x)		__va(x)
 #define __boot_pa(x)		__pa(x)
--- linux-4.4.0.orig/arch/x86/include/asm/page_32_types.h
+++ linux-4.4.0/arch/x86/include/asm/page_32_types.h
@@ -27,8 +27,13 @@
 #define N_EXCEPTION_STACKS 1
 
 #ifdef CONFIG_X86_PAE
-/* 44=32+12, the limit we can fit into an unsigned long pfn */
-#define __PHYSICAL_MASK_SHIFT	44
+/*
+ * This is beyond the 44 bit limit imposed by the 32bit long pfns,
+ * but we need the full mask to make sure inverted PROT_NONE
+ * entries have all the host bits set in a guest.
+ * The real limit is still 44 bits.
+ */
+#define __PHYSICAL_MASK_SHIFT	52
 #define __VIRTUAL_MASK_SHIFT	32
 
 #else  /* !CONFIG_X86_PAE */
--- linux-4.4.0.orig/arch/x86/include/asm/page_64_types.h
+++ linux-4.4.0/arch/x86/include/asm/page_64_types.h
@@ -2,7 +2,11 @@
 #define _ASM_X86_PAGE_64_DEFS_H
 
 #ifdef CONFIG_KASAN
+#ifdef CONFIG_KASAN_EXTRA
+#define KASAN_STACK_ORDER 2
+#else
 #define KASAN_STACK_ORDER 1
+#endif
 #else
 #define KASAN_STACK_ORDER 0
 #endif
--- linux-4.4.0.orig/arch/x86/include/asm/paravirt.h
+++ linux-4.4.0/arch/x86/include/asm/paravirt.h
@@ -6,6 +6,7 @@
 #ifdef CONFIG_PARAVIRT
 #include <asm/pgtable_types.h>
 #include <asm/asm.h>
+#include <asm/nospec-branch.h>
 
 #include <asm/paravirt_types.h>
 
@@ -914,37 +915,35 @@
 
 #define INTERRUPT_RETURN						\
 	PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_iret), CLBR_NONE,	\
-		  jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_iret))
+		  ANNOTATE_RETPOLINE_SAFE;					\
+		  jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_iret);)
 
 #define DISABLE_INTERRUPTS(clobbers)					\
 	PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_disable), clobbers, \
 		  PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE);		\
+		  ANNOTATE_RETPOLINE_SAFE;					\
 		  call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_disable);	\
 		  PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);)
 
 #define ENABLE_INTERRUPTS(clobbers)					\
 	PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_enable), clobbers,	\
 		  PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE);		\
+		  ANNOTATE_RETPOLINE_SAFE;					\
 		  call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_enable);	\
 		  PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);)
 
 #define USERGS_SYSRET32							\
 	PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret32),	\
 		  CLBR_NONE,						\
+		  ANNOTATE_RETPOLINE_SAFE;					\
 		  jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret32))
 
 #ifdef CONFIG_X86_32
 #define GET_CR0_INTO_EAX				\
 	push %ecx; push %edx;				\
+	ANNOTATE_RETPOLINE_SAFE;				\
 	call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0);	\
 	pop %edx; pop %ecx
-
-#define ENABLE_INTERRUPTS_SYSEXIT					\
-	PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_sysexit),	\
-		  CLBR_NONE,						\
-		  jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_irq_enable_sysexit))
-
-
 #else	/* !CONFIG_X86_32 */
 
 /*
@@ -964,21 +963,25 @@
  */
 #define SWAPGS								\
 	PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_swapgs), CLBR_NONE,	\
-		  call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs)		\
+		  ANNOTATE_RETPOLINE_SAFE;					\
+		  call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs);		\
 		 )
 
 #define GET_CR2_INTO_RAX				\
-	call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2)
+	ANNOTATE_RETPOLINE_SAFE;				\
+	call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2);
 
 #define PARAVIRT_ADJUST_EXCEPTION_FRAME					\
 	PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \
 		  CLBR_NONE,						\
+		  ANNOTATE_RETPOLINE_SAFE;				\
 		  call PARA_INDIRECT(pv_irq_ops+PV_IRQ_adjust_exception_frame))
 
 #define USERGS_SYSRET64							\
 	PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64),	\
 		  CLBR_NONE,						\
-		  jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64))
+		  ANNOTATE_RETPOLINE_SAFE;					\
+		  jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64);)
 #endif	/* CONFIG_X86_32 */
 
 #endif /* __ASSEMBLY__ */
--- linux-4.4.0.orig/arch/x86/include/asm/paravirt_types.h
+++ linux-4.4.0/arch/x86/include/asm/paravirt_types.h
@@ -42,6 +42,7 @@
 #include <asm/desc_defs.h>
 #include <asm/kmap_types.h>
 #include <asm/pgtable_types.h>
+#include <asm/nospec-branch.h>
 
 struct page;
 struct thread_struct;
@@ -162,15 +163,6 @@
 
 	u64 (*read_pmc)(int counter);
 
-#ifdef CONFIG_X86_32
-	/*
-	 * Atomically enable interrupts and return to userspace.  This
-	 * is only used in 32-bit kernels.  64-bit kernels use
-	 * usergs_sysret32 instead.
-	 */
-	void (*irq_enable_sysexit)(void);
-#endif
-
 	/*
 	 * Switch to usermode gs and return to 64-bit usermode using
 	 * sysret.  Only used in 64-bit kernels to return to 64-bit
@@ -434,7 +426,9 @@
  * offset into the paravirt_patch_template structure, and can therefore be
  * freely converted back into a structure offset.
  */
-#define PARAVIRT_CALL	"call *%c[paravirt_opptr];"
+#define PARAVIRT_CALL					\
+	ANNOTATE_RETPOLINE_SAFE				\
+	"call *%c[paravirt_opptr];"
 
 /*
  * These macros are intended to wrap calls through one of the paravirt
--- linux-4.4.0.orig/arch/x86/include/asm/pat.h
+++ linux-4.4.0/arch/x86/include/asm/pat.h
@@ -5,8 +5,9 @@
 #include <asm/pgtable_types.h>
 
 bool pat_enabled(void);
+void pat_disable(const char *reason);
 extern void pat_init(void);
-void pat_init_cache_modes(u64);
+extern void init_cache_modes(void);
 
 extern int reserve_memtype(u64 start, u64 end,
 		enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm);
--- linux-4.4.0.orig/arch/x86/include/asm/pci-direct.h
+++ linux-4.4.0/arch/x86/include/asm/pci-direct.h
@@ -9,10 +9,12 @@
 extern u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset);
 extern u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset);
 extern u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset);
+extern u32 pci_early_find_cap(int bus, int slot, int func, int cap);
 extern void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, u32 val);
 extern void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val);
 extern void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 val);
 
+extern unsigned int pci_early_clear_msi;
 extern int early_pci_allowed(void);
 
 extern unsigned int pci_early_dump_regs;
--- linux-4.4.0.orig/arch/x86/include/asm/pci.h
+++ linux-4.4.0/arch/x86/include/asm/pci.h
@@ -20,6 +20,9 @@
 #ifdef CONFIG_X86_64
 	void		*iommu;		/* IOMMU private data */
 #endif
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+	void		*fwnode;	/* IRQ domain for MSI assignment */
+#endif
 };
 
 extern int pci_routeirq;
@@ -32,6 +35,7 @@
 static inline int pci_domain_nr(struct pci_bus *bus)
 {
 	struct pci_sysdata *sd = bus->sysdata;
+
 	return sd->domain;
 }
 
@@ -41,6 +45,17 @@
 }
 #endif
 
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+static inline void *_pci_root_bus_fwnode(struct pci_bus *bus)
+{
+	struct pci_sysdata *sd = bus->sysdata;
+
+	return sd->fwnode;
+}
+
+#define pci_root_bus_fwnode	_pci_root_bus_fwnode
+#endif
+
 /* Can be used to override the logic in pci_scan_bus for skipping
    already-configured bus numbers - to be used for buggy BIOSes
    or architectures with incomplete PCI setup by the loader */
--- linux-4.4.0.orig/arch/x86/include/asm/pci_x86.h
+++ linux-4.4.0/arch/x86/include/asm/pci_x86.h
@@ -93,6 +93,8 @@
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
 extern void (*pcibios_disable_irq)(struct pci_dev *dev);
 
+extern bool mp_should_keep_irq(struct device *dev);
+
 struct pci_raw_ops {
 	int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
 						int reg, int len, u32 *val);
--- linux-4.4.0.orig/arch/x86/include/asm/percpu.h
+++ linux-4.4.0/arch/x86/include/asm/percpu.h
@@ -184,22 +184,22 @@
 	typeof(var) pfo_ret__;				\
 	switch (sizeof(var)) {				\
 	case 1:						\
-		asm(op "b "__percpu_arg(1)",%0"		\
+		asm volatile(op "b "__percpu_arg(1)",%0"\
 		    : "=q" (pfo_ret__)			\
 		    : "m" (var));			\
 		break;					\
 	case 2:						\
-		asm(op "w "__percpu_arg(1)",%0"		\
+		asm volatile(op "w "__percpu_arg(1)",%0"\
 		    : "=r" (pfo_ret__)			\
 		    : "m" (var));			\
 		break;					\
 	case 4:						\
-		asm(op "l "__percpu_arg(1)",%0"		\
+		asm volatile(op "l "__percpu_arg(1)",%0"\
 		    : "=r" (pfo_ret__)			\
 		    : "m" (var));			\
 		break;					\
 	case 8:						\
-		asm(op "q "__percpu_arg(1)",%0"		\
+		asm volatile(op "q "__percpu_arg(1)",%0"\
 		    : "=r" (pfo_ret__)			\
 		    : "m" (var));			\
 		break;					\
--- linux-4.4.0.orig/arch/x86/include/asm/perf_event.h
+++ linux-4.4.0/arch/x86/include/asm/perf_event.h
@@ -165,6 +165,7 @@
 #define GLOBAL_STATUS_ASIF				BIT_ULL(60)
 #define GLOBAL_STATUS_COUNTERS_FROZEN			BIT_ULL(59)
 #define GLOBAL_STATUS_LBRS_FROZEN			BIT_ULL(58)
+#define GLOBAL_STATUS_TRACE_TOPAPMI			BIT_ULL(55)
 
 /*
  * IBS cpuid feature detection
--- linux-4.4.0.orig/arch/x86/include/asm/pgtable-2level.h
+++ linux-4.4.0/arch/x86/include/asm/pgtable-2level.h
@@ -77,4 +77,21 @@
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { (pte).pte_low })
 #define __swp_entry_to_pte(x)		((pte_t) { .pte = (x).val })
 
+/* No inverted PFNs on 2 level page tables */
+
+static inline u64 protnone_mask(u64 val)
+{
+	return 0;
+}
+
+static inline u64 flip_protnone_guard(u64 oldval, u64 val, u64 mask)
+{
+	return val;
+}
+
+static inline bool __pte_needs_invert(u64 val)
+{
+	return false;
+}
+
 #endif /* _ASM_X86_PGTABLE_2LEVEL_H */
--- linux-4.4.0.orig/arch/x86/include/asm/pgtable-3level.h
+++ linux-4.4.0/arch/x86/include/asm/pgtable-3level.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_PGTABLE_3LEVEL_H
 #define _ASM_X86_PGTABLE_3LEVEL_H
 
+#include <asm/atomic64_32.h>
+
 /*
  * Intel Physical Address Extension (PAE) Mode - three-level page
  * tables on PPro+ CPUs.
@@ -142,10 +144,7 @@
 {
 	pte_t res;
 
-	/* xchg acts as a barrier before the setting of the high bits */
-	res.pte_low = xchg(&ptep->pte_low, 0);
-	res.pte_high = ptep->pte_high;
-	ptep->pte_high = 0;
+	res.pte = (pteval_t)atomic64_xchg((atomic64_t *)ptep, 0);
 
 	return res;
 }
@@ -177,11 +176,44 @@
 #endif
 
 /* Encode and de-code a swap entry */
+#define SWP_TYPE_BITS		5
+
+#define SWP_OFFSET_FIRST_BIT	(_PAGE_BIT_PROTNONE + 1)
+
+/* We always extract/encode the offset by shifting it all the way up, and then down again */
+#define SWP_OFFSET_SHIFT	(SWP_OFFSET_FIRST_BIT + SWP_TYPE_BITS)
+
 #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > 5)
 #define __swp_type(x)			(((x).val) & 0x1f)
 #define __swp_offset(x)			((x).val >> 5)
 #define __swp_entry(type, offset)	((swp_entry_t){(type) | (offset) << 5})
-#define __pte_to_swp_entry(pte)		((swp_entry_t){ (pte).pte_high })
-#define __swp_entry_to_pte(x)		((pte_t){ { .pte_high = (x).val } })
+
+/*
+ * Normally, __swp_entry() converts from arch-independent swp_entry_t to
+ * arch-dependent swp_entry_t, and __swp_entry_to_pte() just stores the result
+ * to pte. But here we have 32bit swp_entry_t and 64bit pte, and need to use the
+ * whole 64 bits. Thus, we shift the "real" arch-dependent conversion to
+ * __swp_entry_to_pte() through the following helper macro based on 64bit
+ * __swp_entry().
+ */
+#define __swp_pteval_entry(type, offset) ((pteval_t) { \
+	(~(pteval_t)(offset) << SWP_OFFSET_SHIFT >> SWP_TYPE_BITS) \
+	| ((pteval_t)(type) << (64 - SWP_TYPE_BITS)) })
+
+#define __swp_entry_to_pte(x)	((pte_t){ .pte = \
+		__swp_pteval_entry(__swp_type(x), __swp_offset(x)) })
+/*
+ * Analogically, __pte_to_swp_entry() doesn't just extract the arch-dependent
+ * swp_entry_t, but also has to convert it from 64bit to the 32bit
+ * intermediate representation, using the following macros based on 64bit
+ * __swp_type() and __swp_offset().
+ */
+#define __pteval_swp_type(x) ((unsigned long)((x).pte >> (64 - SWP_TYPE_BITS)))
+#define __pteval_swp_offset(x) ((unsigned long)(~((x).pte) << SWP_TYPE_BITS >> SWP_OFFSET_SHIFT))
+
+#define __pte_to_swp_entry(pte)	(__swp_entry(__pteval_swp_type(pte), \
+					     __pteval_swp_offset(pte)))
+
+#include <asm/pgtable-invert.h>
 
 #endif /* _ASM_X86_PGTABLE_3LEVEL_H */
--- linux-4.4.0.orig/arch/x86/include/asm/pgtable-invert.h
+++ linux-4.4.0/arch/x86/include/asm/pgtable-invert.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PGTABLE_INVERT_H
+#define _ASM_PGTABLE_INVERT_H 1
+
+#ifndef __ASSEMBLY__
+
+/*
+ * A clear pte value is special, and doesn't get inverted.
+ *
+ * Note that even users that only pass a pgprot_t (rather
+ * than a full pte) won't trigger the special zero case,
+ * because even PAGE_NONE has _PAGE_PROTNONE | _PAGE_ACCESSED
+ * set. So the all zero case really is limited to just the
+ * cleared page table entry case.
+ */
+static inline bool __pte_needs_invert(u64 val)
+{
+	return val && !(val & _PAGE_PRESENT);
+}
+
+/* Get a mask to xor with the page table entry to get the correct pfn. */
+static inline u64 protnone_mask(u64 val)
+{
+	return __pte_needs_invert(val) ?  ~0ull : 0;
+}
+
+static inline u64 flip_protnone_guard(u64 oldval, u64 val, u64 mask)
+{
+	/*
+	 * When a PTE transitions from NONE to !NONE or vice-versa
+	 * invert the PFN part to stop speculation.
+	 * pte_pfn undoes this when needed.
+	 */
+	if (__pte_needs_invert(oldval) != __pte_needs_invert(val))
+		val = (val & ~mask) | (~val & mask);
+	return val;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif
--- linux-4.4.0.orig/arch/x86/include/asm/pgtable.h
+++ linux-4.4.0/arch/x86/include/asm/pgtable.h
@@ -18,6 +18,12 @@
 #ifndef __ASSEMBLY__
 #include <asm/x86_init.h>
 
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+extern int kaiser_enabled;
+#else
+#define kaiser_enabled 0
+#endif
+
 void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd);
 void ptdump_walk_pgd_level_checkwx(void);
 
@@ -142,19 +148,34 @@
 	return pte_flags(pte) & _PAGE_SPECIAL;
 }
 
+/* Entries that were set to PROT_NONE are inverted */
+
+static inline u64 protnone_mask(u64 val);
+
 static inline unsigned long pte_pfn(pte_t pte)
 {
-	return (pte_val(pte) & PTE_PFN_MASK) >> PAGE_SHIFT;
+	phys_addr_t pfn = pte_val(pte);
+	pfn ^= protnone_mask(pfn);
+	return (pfn & PTE_PFN_MASK) >> PAGE_SHIFT;
 }
 
 static inline unsigned long pmd_pfn(pmd_t pmd)
 {
-	return (pmd_val(pmd) & pmd_pfn_mask(pmd)) >> PAGE_SHIFT;
+	phys_addr_t pfn = pmd_val(pmd);
+	pfn ^= protnone_mask(pfn);
+	return (pfn & pmd_pfn_mask(pmd)) >> PAGE_SHIFT;
 }
 
 static inline unsigned long pud_pfn(pud_t pud)
 {
-	return (pud_val(pud) & pud_pfn_mask(pud)) >> PAGE_SHIFT;
+	phys_addr_t pfn = pud_val(pud);
+	pfn ^= protnone_mask(pfn);
+	return (pfn & pud_pfn_mask(pud)) >> PAGE_SHIFT;
+}
+
+static inline unsigned long pgd_pfn(pgd_t pgd)
+{
+	return (pgd_val(pgd) & PTE_PFN_MASK) >> PAGE_SHIFT;
 }
 
 #define pte_page(pte)	pfn_to_page(pte_pfn(pte))
@@ -299,11 +320,6 @@
 	return pmd_set_flags(pmd, _PAGE_RW);
 }
 
-static inline pmd_t pmd_mknotpresent(pmd_t pmd)
-{
-	return pmd_clear_flags(pmd, _PAGE_PRESENT | _PAGE_PROTNONE);
-}
-
 #ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY
 static inline int pte_soft_dirty(pte_t pte)
 {
@@ -353,19 +369,58 @@
 
 static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
 {
-	return __pte(((phys_addr_t)page_nr << PAGE_SHIFT) |
-		     massage_pgprot(pgprot));
+	phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT;
+	pfn ^= protnone_mask(pgprot_val(pgprot));
+	pfn &= PTE_PFN_MASK;
+	return __pte(pfn | massage_pgprot(pgprot));
 }
 
 static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
 {
-	return __pmd(((phys_addr_t)page_nr << PAGE_SHIFT) |
-		     massage_pgprot(pgprot));
+	phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT;
+	pfn ^= protnone_mask(pgprot_val(pgprot));
+	pfn &= PHYSICAL_PMD_PAGE_MASK;
+	return __pmd(pfn | massage_pgprot(pgprot));
+}
+
+static inline pud_t pfn_pud(unsigned long page_nr, pgprot_t pgprot)
+{
+	phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT;
+	pfn ^= protnone_mask(pgprot_val(pgprot));
+	pfn &= PHYSICAL_PUD_PAGE_MASK;
+	return __pud(pfn | massage_pgprot(pgprot));
+}
+
+static inline pmd_t pmd_mknotpresent(pmd_t pmd)
+{
+	return pfn_pmd(pmd_pfn(pmd),
+		       __pgprot(pmd_flags(pmd) & ~(_PAGE_PRESENT|_PAGE_PROTNONE)));
 }
 
+static inline pud_t pud_set_flags(pud_t pud, pudval_t set)
+{
+	pudval_t v = native_pud_val(pud);
+
+	return __pud(v | set);
+}
+
+static inline pud_t pud_clear_flags(pud_t pud, pudval_t clear)
+{
+	pudval_t v = native_pud_val(pud);
+
+	return __pud(v & ~clear);
+}
+
+static inline pud_t pud_mkhuge(pud_t pud)
+{
+	return pud_set_flags(pud, _PAGE_PSE);
+}
+
+static inline u64 flip_protnone_guard(u64 oldval, u64 val, u64 mask);
+
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-	pteval_t val = pte_val(pte);
+	pteval_t val = pte_val(pte), oldval = val;
 
 	/*
 	 * Chop off the NX bit (if present), and add the NX portion of
@@ -373,17 +428,17 @@
 	 */
 	val &= _PAGE_CHG_MASK;
 	val |= massage_pgprot(newprot) & ~_PAGE_CHG_MASK;
-
+	val = flip_protnone_guard(oldval, val, PTE_PFN_MASK);
 	return __pte(val);
 }
 
 static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
 {
-	pmdval_t val = pmd_val(pmd);
+	pmdval_t val = pmd_val(pmd), oldval = val;
 
 	val &= _HPAGE_CHG_MASK;
 	val |= massage_pgprot(newprot) & ~_HPAGE_CHG_MASK;
-
+	val = flip_protnone_guard(oldval, val, PHYSICAL_PMD_PAGE_MASK);
 	return __pmd(val);
 }
 
@@ -528,8 +583,7 @@
  * Currently stuck as a macro due to indirect forward reference to
  * linux/mmzone.h's __section_mem_map_addr() definition:
  */
-#define pmd_page(pmd)		\
-	pfn_to_page((pmd_val(pmd) & pmd_pfn_mask(pmd)) >> PAGE_SHIFT)
+#define pmd_page(pmd)	pfn_to_page(pmd_pfn(pmd))
 
 /*
  * the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD]
@@ -597,8 +651,7 @@
  * Currently stuck as a macro due to indirect forward reference to
  * linux/mmzone.h's __section_mem_map_addr() definition:
  */
-#define pud_page(pud)		\
-	pfn_to_page((pud_val(pud) & pud_pfn_mask(pud)) >> PAGE_SHIFT)
+#define pud_page(pud)	pfn_to_page(pud_pfn(pud))
 
 /* Find an entry in the second-level page table.. */
 static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
@@ -638,7 +691,7 @@
  * Currently stuck as a macro due to indirect forward reference to
  * linux/mmzone.h's __section_mem_map_addr() definition:
  */
-#define pgd_page(pgd)		pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT)
+#define pgd_page(pgd)		pfn_to_page(pgd_pfn(pgd))
 
 /* to find an entry in a page-table-directory. */
 static inline unsigned long pud_index(unsigned long address)
@@ -653,7 +706,17 @@
 
 static inline int pgd_bad(pgd_t pgd)
 {
-	return (pgd_flags(pgd) & ~_PAGE_USER) != _KERNPG_TABLE;
+	pgdval_t ignore_flags = _PAGE_USER;
+	/*
+	 * We set NX on KAISER pgds that map userspace memory so
+	 * that userspace can not meaningfully use the kernel
+	 * page table by accident; it will fault on the first
+	 * instruction it tries to run.  See native_set_pgd().
+	 */
+	if (kaiser_enabled)
+		ignore_flags |= _PAGE_NX;
+
+	return (pgd_flags(pgd) & ~ignore_flags) != _KERNPG_TABLE;
 }
 
 static inline int pgd_none(pgd_t pgd)
@@ -855,7 +918,15 @@
  */
 static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
 {
-       memcpy(dst, src, count * sizeof(pgd_t));
+	memcpy(dst, src, count * sizeof(pgd_t));
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	if (kaiser_enabled) {
+		/* Clone the shadow pgd part as well */
+		memcpy(native_get_shadow_pgd(dst),
+			native_get_shadow_pgd(src),
+			count * sizeof(pgd_t));
+	}
+#endif
 }
 
 #define PTE_SHIFT ilog2(PTRS_PER_PTE)
@@ -902,6 +973,14 @@
 }
 #endif
 
+#define __HAVE_ARCH_PFN_MODIFY_ALLOWED 1
+extern bool pfn_modify_allowed(unsigned long pfn, pgprot_t prot);
+
+static inline bool arch_has_pfn_modify_check(void)
+{
+	return boot_cpu_has_bug(X86_BUG_L1TF);
+}
+
 #include <asm-generic/pgtable.h>
 #endif	/* __ASSEMBLY__ */
 
--- linux-4.4.0.orig/arch/x86/include/asm/pgtable_64.h
+++ linux-4.4.0/arch/x86/include/asm/pgtable_64.h
@@ -44,15 +44,15 @@
 void set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte);
 
 
-static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr,
-				    pte_t *ptep)
+static inline void native_set_pte(pte_t *ptep, pte_t pte)
 {
-	*ptep = native_make_pte(0);
+	WRITE_ONCE(*ptep, pte);
 }
 
-static inline void native_set_pte(pte_t *ptep, pte_t pte)
+static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr,
+				    pte_t *ptep)
 {
-	*ptep = pte;
+	native_set_pte(ptep, native_make_pte(0));
 }
 
 static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
@@ -62,7 +62,7 @@
 
 static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
 {
-	*pmdp = pmd;
+	WRITE_ONCE(*pmdp, pmd);
 }
 
 static inline void native_pmd_clear(pmd_t *pmd)
@@ -98,7 +98,7 @@
 
 static inline void native_set_pud(pud_t *pudp, pud_t pud)
 {
-	*pudp = pud;
+	WRITE_ONCE(*pudp, pud);
 }
 
 static inline void native_pud_clear(pud_t *pud)
@@ -106,9 +106,32 @@
 	native_set_pud(pud, native_make_pud(0));
 }
 
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+extern pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd);
+
+static inline pgd_t *native_get_shadow_pgd(pgd_t *pgdp)
+{
+#ifdef CONFIG_DEBUG_VM
+	/* linux/mmdebug.h may not have been included at this point */
+	BUG_ON(!kaiser_enabled);
+#endif
+	return (pgd_t *)((unsigned long)pgdp | (unsigned long)PAGE_SIZE);
+}
+#else
+static inline pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd)
+{
+	return pgd;
+}
+static inline pgd_t *native_get_shadow_pgd(pgd_t *pgdp)
+{
+	BUILD_BUG_ON(1);
+	return NULL;
+}
+#endif /* CONFIG_PAGE_TABLE_ISOLATION */
+
 static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd)
 {
-	*pgdp = pgd;
+	WRITE_ONCE(*pgdp, kaiser_set_shadow_pgd(pgdp, pgd));
 }
 
 static inline void native_pgd_clear(pgd_t *pgd)
@@ -140,18 +163,52 @@
 #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
 #define pte_unmap(pte) ((void)(pte))/* NOP */
 
-/* Encode and de-code a swap entry */
-#define SWP_TYPE_BITS 5
-#define SWP_OFFSET_SHIFT (_PAGE_BIT_PROTNONE + 1)
+/*
+ * Encode and de-code a swap entry
+ *
+ * |     ...            | 11| 10|  9|8|7|6|5| 4| 3|2| 1|0| <- bit number
+ * |     ...            |SW3|SW2|SW1|G|L|D|A|CD|WT|U| W|P| <- bit names
+ * | TYPE (59-63) | ~OFFSET (9-58)  |0|0|X|X| X| X|X|SD|0| <- swp entry
+ *
+ * G (8) is aliased and used as a PROT_NONE indicator for
+ * !present ptes.  We need to start storing swap entries above
+ * there.  We also need to avoid using A and D because of an
+ * erratum where they can be incorrectly set by hardware on
+ * non-present PTEs.
+ *
+ * SD (1) in swp entry is used to store soft dirty bit, which helps us
+ * remember soft dirty over page migration
+ *
+ * Bit 7 in swp entry should be 0 because pmd_present checks not only P,
+ * but also L and G.
+ *
+ * The offset is inverted by a binary not operation to make the high
+ * physical bits set.
+ */
+#define SWP_TYPE_BITS		5
+
+#define SWP_OFFSET_FIRST_BIT	(_PAGE_BIT_PROTNONE + 1)
+
+/* We always extract/encode the offset by shifting it all the way up, and then down again */
+#define SWP_OFFSET_SHIFT	(SWP_OFFSET_FIRST_BIT+SWP_TYPE_BITS)
 
 #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS)
 
-#define __swp_type(x)			(((x).val >> (_PAGE_BIT_PRESENT + 1)) \
-					 & ((1U << SWP_TYPE_BITS) - 1))
-#define __swp_offset(x)			((x).val >> SWP_OFFSET_SHIFT)
-#define __swp_entry(type, offset)	((swp_entry_t) { \
-					 ((type) << (_PAGE_BIT_PRESENT + 1)) \
-					 | ((offset) << SWP_OFFSET_SHIFT) })
+/* Extract the high bits for type */
+#define __swp_type(x) ((x).val >> (64 - SWP_TYPE_BITS))
+
+/* Shift up (to get rid of type), then down to get value */
+#define __swp_offset(x) (~(x).val << SWP_TYPE_BITS >> SWP_OFFSET_SHIFT)
+
+/*
+ * Shift the offset up "too far" by TYPE bits, then down again
+ * The offset is inverted by a binary not operation to make the high
+ * physical bits set.
+ */
+#define __swp_entry(type, offset) ((swp_entry_t) { \
+	(~(unsigned long)(offset) << SWP_OFFSET_SHIFT >> SWP_TYPE_BITS) \
+	| ((unsigned long)(type) << (64-SWP_TYPE_BITS)) })
+
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val((pte)) })
 #define __swp_entry_to_pte(x)		((pte_t) { .pte = (x).val })
 
@@ -178,6 +235,8 @@
 extern void init_extra_mapping_uc(unsigned long phys, unsigned long size);
 extern void init_extra_mapping_wb(unsigned long phys, unsigned long size);
 
+#include <asm/pgtable-invert.h>
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_X86_PGTABLE_64_H */
--- linux-4.4.0.orig/arch/x86/include/asm/pgtable_types.h
+++ linux-4.4.0/arch/x86/include/asm/pgtable_types.h
@@ -70,15 +70,15 @@
 /*
  * Tracking soft dirty bit when a page goes to a swap is tricky.
  * We need a bit which can be stored in pte _and_ not conflict
- * with swap entry format. On x86 bits 6 and 7 are *not* involved
- * into swap entry computation, but bit 6 is used for nonlinear
- * file mapping, so we borrow bit 7 for soft dirty tracking.
+ * with swap entry format. On x86 bits 1-4 are *not* involved
+ * into swap entry computation, but bit 7 is used for thp migration,
+ * so we borrow bit 1 for soft dirty tracking.
  *
  * Please note that this bit must be treated as swap dirty page
- * mark if and only if the PTE has present bit clear!
+ * mark if and only if the PTE/PMD has present bit clear!
  */
 #ifdef CONFIG_MEM_SOFT_DIRTY
-#define _PAGE_SWP_SOFT_DIRTY	_PAGE_PSE
+#define _PAGE_SWP_SOFT_DIRTY	_PAGE_RW
 #else
 #define _PAGE_SWP_SOFT_DIRTY	(_AT(pteval_t, 0))
 #endif
@@ -89,7 +89,7 @@
 #define _PAGE_NX	(_AT(pteval_t, 0))
 #endif
 
-#define _PAGE_PROTNONE	(_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
+#define _PAGE_PROTNONE  (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER |	\
 			 _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -102,6 +102,33 @@
 			 _PAGE_SOFT_DIRTY)
 #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE)
 
+/* The ASID is the lower 12 bits of CR3 */
+#define X86_CR3_PCID_ASID_MASK  (_AC((1<<12)-1,UL))
+
+/* Mask for all the PCID-related bits in CR3: */
+#define X86_CR3_PCID_MASK       (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_MASK)
+#define X86_CR3_PCID_ASID_KERN  (_AC(0x0,UL))
+
+#if defined(CONFIG_PAGE_TABLE_ISOLATION) && defined(CONFIG_X86_64)
+/* Let X86_CR3_PCID_ASID_USER be usable for the X86_CR3_PCID_NOFLUSH bit */
+#define X86_CR3_PCID_ASID_USER	(_AC(0x80,UL))
+
+#define X86_CR3_PCID_KERN_FLUSH		(X86_CR3_PCID_ASID_KERN)
+#define X86_CR3_PCID_USER_FLUSH		(X86_CR3_PCID_ASID_USER)
+#define X86_CR3_PCID_KERN_NOFLUSH	(X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_KERN)
+#define X86_CR3_PCID_USER_NOFLUSH	(X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_USER)
+#else
+#define X86_CR3_PCID_ASID_USER  (_AC(0x0,UL))
+/*
+ * PCIDs are unsupported on 32-bit and none of these bits can be
+ * set in CR3:
+ */
+#define X86_CR3_PCID_KERN_FLUSH		(0)
+#define X86_CR3_PCID_USER_FLUSH		(0)
+#define X86_CR3_PCID_KERN_NOFLUSH	(0)
+#define X86_CR3_PCID_USER_NOFLUSH	(0)
+#endif
+
 /*
  * The cache modes defined here are used to translate between pure SW usage
  * and the HW defined cache mode bits and/or PAT entries.
@@ -363,20 +390,18 @@
 }
 static inline pgprot_t pgprot_4k_2_large(pgprot_t pgprot)
 {
+	pgprotval_t val = pgprot_val(pgprot);
 	pgprot_t new;
-	unsigned long val;
 
-	val = pgprot_val(pgprot);
 	pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) |
 		((val & _PAGE_PAT) << (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT));
 	return new;
 }
 static inline pgprot_t pgprot_large_2_4k(pgprot_t pgprot)
 {
+	pgprotval_t val = pgprot_val(pgprot);
 	pgprot_t new;
-	unsigned long val;
 
-	val = pgprot_val(pgprot);
 	pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) |
 			  ((val & _PAGE_PAT_LARGE) >>
 			   (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT));
--- linux-4.4.0.orig/arch/x86/include/asm/pmem.h
+++ linux-4.4.0/arch/x86/include/asm/pmem.h
@@ -72,8 +72,8 @@
  * @size:	number of bytes to write back
  *
  * Write back a cache range using the CLWB (cache line write back)
- * instruction.  This function requires explicit ordering with an
- * arch_wmb_pmem() call.  This API is internal to the x86 PMEM implementation.
+ * instruction. Note that @size is internally rounded up to be cache
+ * line size aligned.
  */
 static inline void __arch_wb_cache_pmem(void *vaddr, size_t size)
 {
@@ -87,15 +87,6 @@
 		clwb(p);
 }
 
-/*
- * copy_from_iter_nocache() on x86 only uses non-temporal stores for iovec
- * iterators, so for other types (bvec & kvec) we must do a cache write-back.
- */
-static inline bool __iter_needs_pmem_wb(struct iov_iter *i)
-{
-	return iter_is_iovec(i) == false;
-}
-
 /**
  * arch_copy_from_iter_pmem - copy data from an iterator to PMEM
  * @addr:	PMEM destination address
@@ -114,8 +105,36 @@
 	/* TODO: skip the write-back by always using non-temporal stores */
 	len = copy_from_iter_nocache(vaddr, bytes, i);
 
-	if (__iter_needs_pmem_wb(i))
-		__arch_wb_cache_pmem(vaddr, bytes);
+	/*
+	 * In the iovec case on x86_64 copy_from_iter_nocache() uses
+	 * non-temporal stores for the bulk of the transfer, but we need
+	 * to manually flush if the transfer is unaligned. A cached
+	 * memory copy is used when destination or size is not naturally
+	 * aligned. That is:
+	 *   - Require 8-byte alignment when size is 8 bytes or larger.
+	 *   - Require 4-byte alignment when size is 4 bytes.
+	 *
+	 * In the non-iovec case the entire destination needs to be
+	 * flushed.
+	 */
+	if (iter_is_iovec(i)) {
+		unsigned long flushed, dest = (unsigned long) addr;
+
+		if (bytes < 8) {
+			if (!IS_ALIGNED(dest, 4) || (bytes != 4))
+				__arch_wb_cache_pmem(addr, bytes);
+		} else {
+			if (!IS_ALIGNED(dest, 8)) {
+				dest = ALIGN(dest, boot_cpu_data.x86_clflush_size);
+				__arch_wb_cache_pmem(addr, 1);
+			}
+
+			flushed = dest - (unsigned long) addr;
+			if (bytes > flushed && !IS_ALIGNED(bytes - flushed, 8))
+				__arch_wb_cache_pmem(addr + bytes - 1, 1);
+		}
+	} else
+		__arch_wb_cache_pmem(addr, bytes);
 
 	return len;
 }
--- linux-4.4.0.orig/arch/x86/include/asm/processor.h
+++ linux-4.4.0/arch/x86/include/asm/processor.h
@@ -13,7 +13,7 @@
 #include <asm/types.h>
 #include <uapi/asm/sigcontext.h>
 #include <asm/current.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/page.h>
 #include <asm/pgtable_types.h>
 #include <asm/percpu.h>
@@ -24,7 +24,6 @@
 #include <asm/fpu/types.h>
 
 #include <linux/personality.h>
-#include <linux/cpumask.h>
 #include <linux/cache.h>
 #include <linux/threads.h>
 #include <linux/math64.h>
@@ -89,7 +88,7 @@
 	__u8			x86;		/* CPU family */
 	__u8			x86_vendor;	/* CPU vendor */
 	__u8			x86_model;
-	__u8			x86_mask;
+	__u8			x86_stepping;
 #ifdef CONFIG_X86_32
 	char			wp_works_ok;	/* It doesn't on 386's */
 
@@ -113,7 +112,7 @@
 	char			x86_vendor_id[16];
 	char			x86_model_id[64];
 	/* in KB - valid for CPUS which support this call: */
-	int			x86_cache_size;
+	unsigned int		x86_cache_size;
 	int			x86_cache_alignment;	/* In bytes */
 	/* Cache QoS architectural values: */
 	int			x86_cache_max_rmid;	/* max index */
@@ -129,6 +128,8 @@
 	u16			booted_cores;
 	/* Physical processor id: */
 	u16			phys_proc_id;
+	/* Logical processor id: */
+	u16			logical_proc_id;
 	/* Core id: */
 	u16			cpu_core_id;
 	/* Compute unit id */
@@ -136,6 +137,8 @@
 	/* Index into per_cpu list: */
 	u16			cpu_index;
 	u32			microcode;
+	/* Address space bits used by the cache internally */
+	u8			x86_cache_bits;
 };
 
 #define X86_VENDOR_INTEL	0
@@ -156,8 +159,8 @@
 extern struct cpuinfo_x86	new_cpu_data;
 
 extern struct tss_struct	doublefault_tss;
-extern __u32			cpu_caps_cleared[NCAPINTS];
-extern __u32			cpu_caps_set[NCAPINTS];
+extern __u32			cpu_caps_cleared[NCAPINTS + NBUGINTS];
+extern __u32			cpu_caps_set[NCAPINTS + NBUGINTS];
 
 #ifdef CONFIG_SMP
 DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
@@ -173,16 +176,25 @@
 
 extern void cpu_detect(struct cpuinfo_x86 *c);
 
+static inline unsigned long long l1tf_pfn_limit(void)
+{
+	return BIT_ULL(boot_cpu_data.x86_cache_bits - 1 - PAGE_SHIFT);
+}
+
 extern void early_cpu_init(void);
 extern void identify_boot_cpu(void);
 extern void identify_secondary_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
 void print_cpu_msr(struct cpuinfo_x86 *);
 extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c);
+extern u32 get_scattered_cpuid_leaf(unsigned int level,
+				    unsigned int sub_leaf,
+				    u8 reg);
 extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
 extern void init_amd_cacheinfo(struct cpuinfo_x86 *c);
-
-extern void detect_extended_topology(struct cpuinfo_x86 *c);
+extern int detect_extended_topology_early(struct cpuinfo_x86 *c);
+extern int detect_extended_topology(struct cpuinfo_x86 *c);
+extern int detect_ht_early(struct cpuinfo_x86 *c);
 extern void detect_ht(struct cpuinfo_x86 *c);
 
 #ifdef CONFIG_X86_32
@@ -206,6 +218,24 @@
 	    : "memory");
 }
 
+#define native_cpuid_reg(reg)					\
+static inline unsigned int native_cpuid_##reg(unsigned int op)	\
+{								\
+	unsigned int eax = op, ebx, ecx = 0, edx;		\
+								\
+	native_cpuid(&eax, &ebx, &ecx, &edx);			\
+								\
+	return reg;						\
+}
+
+/*
+ * Native CPUID functions returning a single datum.
+ */
+native_cpuid_reg(eax)
+native_cpuid_reg(ebx)
+native_cpuid_reg(ecx)
+native_cpuid_reg(edx)
+
 static inline void load_cr3(pgd_t *pgdir)
 {
 	write_cr3(__pa(pgdir));
@@ -305,7 +335,7 @@
 
 } ____cacheline_aligned;
 
-DECLARE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss);
+DECLARE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct tss_struct, cpu_tss);
 
 #ifdef CONFIG_X86_32
 DECLARE_PER_CPU(unsigned long, cpu_current_top_of_stack);
@@ -574,7 +604,7 @@
 {
 	int tmp;
 
-#ifdef CONFIG_M486
+#ifdef CONFIG_X86_32
 	/*
 	 * Do a CPUID if available, otherwise do a jump.  The jump
 	 * can conveniently enough be the jump around CPUID.
@@ -811,6 +841,7 @@
 
 extern u16 amd_get_nb_id(int cpu);
 extern u32 amd_get_nodes_per_socket(void);
+extern void amd_clear_divider(void);
 
 static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
 {
@@ -839,4 +870,29 @@
 
 void stop_this_cpu(void *dummy);
 void df_debug(struct pt_regs *regs, long error_code);
+
+enum l1tf_mitigations {
+	L1TF_MITIGATION_OFF,
+	L1TF_MITIGATION_FLUSH_NOWARN,
+	L1TF_MITIGATION_FLUSH,
+	L1TF_MITIGATION_FLUSH_NOSMT,
+	L1TF_MITIGATION_FULL,
+	L1TF_MITIGATION_FULL_FORCE
+};
+
+extern enum l1tf_mitigations l1tf_mitigation;
+
+enum mds_mitigations {
+	MDS_MITIGATION_OFF,
+	MDS_MITIGATION_FULL,
+	MDS_MITIGATION_VMWERV,
+};
+
+enum taa_mitigations {
+	TAA_MITIGATION_OFF,
+	TAA_MITIGATION_UCODE_NEEDED,
+	TAA_MITIGATION_VERW,
+	TAA_MITIGATION_TSX_DISABLED,
+};
+
 #endif /* _ASM_X86_PROCESSOR_H */
--- linux-4.4.0.orig/arch/x86/include/asm/ptrace.h
+++ linux-4.4.0/arch/x86/include/asm/ptrace.h
@@ -121,9 +121,9 @@
 #endif
 }
 
-#ifdef CONFIG_X86_64
 static inline bool user_64bit_mode(struct pt_regs *regs)
 {
+#ifdef CONFIG_X86_64
 #ifndef CONFIG_PARAVIRT
 	/*
 	 * On non-paravirt systems, this is the only long mode CPL 3
@@ -134,8 +134,12 @@
 	/* Headers are too twisted for this to go in paravirt.h. */
 	return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs;
 #endif
+#else /* !CONFIG_X86_64 */
+	return false;
+#endif
 }
 
+#ifdef CONFIG_X86_64
 #define current_user_stack_pointer()	current_pt_regs()->sp
 #define compat_user_stack_pointer()	current_pt_regs()->sp
 #endif
@@ -202,23 +206,51 @@
 }
 
 /**
+ * regs_get_kernel_stack_nth_addr() - get the address of the Nth entry on stack
+ * @regs:	pt_regs which contains kernel stack pointer.
+ * @n:		stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns the address of the @n th entry of the
+ * kernel stack which is specified by @regs. If the @n th entry is NOT in
+ * the kernel stack, this returns NULL.
+ */
+static inline unsigned long *regs_get_kernel_stack_nth_addr(struct pt_regs *regs, unsigned int n)
+{
+	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+
+	addr += n;
+	if (regs_within_kernel_stack(regs, (unsigned long)addr))
+		return addr;
+	else
+		return NULL;
+}
+
+/* To avoid include hell, we can't include uaccess.h */
+extern long probe_kernel_read(void *dst, const void *src, size_t size);
+
+/**
  * regs_get_kernel_stack_nth() - get Nth entry of the stack
  * @regs:	pt_regs which contains kernel stack pointer.
  * @n:		stack entry number.
  *
  * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
- * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack
  * this returns 0.
  */
 static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
 						      unsigned int n)
 {
-	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
-	addr += n;
-	if (regs_within_kernel_stack(regs, (unsigned long)addr))
-		return *addr;
-	else
-		return 0;
+	unsigned long *addr;
+	unsigned long val;
+	long ret;
+
+	addr = regs_get_kernel_stack_nth_addr(regs, n);
+	if (addr) {
+		ret = probe_kernel_read(&val, addr, sizeof(val));
+		if (!ret)
+			return val;
+	}
+	return 0;
 }
 
 #define arch_has_single_step()	(1)
--- linux-4.4.0.orig/arch/x86/include/asm/pvclock.h
+++ linux-4.4.0/arch/x86/include/asm/pvclock.h
@@ -4,6 +4,15 @@
 #include <linux/clocksource.h>
 #include <asm/pvclock-abi.h>
 
+#ifdef CONFIG_KVM_GUEST
+extern struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void);
+#else
+static inline struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
+{
+	return NULL;
+}
+#endif
+
 /* some helper functions for xen and kvm pv clock sources */
 cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src);
 u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src);
@@ -76,6 +85,8 @@
 	u8 ret_flags;
 
 	version = src->version;
+	/* Make the latest version visible */
+	smp_rmb();
 
 	offset = pvclock_get_nsec_offset(src);
 	ret = src->system_time + offset;
--- linux-4.4.0.orig/arch/x86/include/asm/required-features.h
+++ linux-4.4.0/arch/x86/include/asm/required-features.h
@@ -92,5 +92,16 @@
 #define REQUIRED_MASK7	0
 #define REQUIRED_MASK8	0
 #define REQUIRED_MASK9	0
+#define REQUIRED_MASK10	0
+#define REQUIRED_MASK11	0
+#define REQUIRED_MASK12	0
+#define REQUIRED_MASK13	0
+#define REQUIRED_MASK14	0
+#define REQUIRED_MASK15	0
+#define REQUIRED_MASK16	0
+#define REQUIRED_MASK17	0
+#define REQUIRED_MASK18	0
+#define REQUIRED_MASK19	0
+#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 20)
 
 #endif /* _ASM_X86_REQUIRED_FEATURES_H */
--- linux-4.4.0.orig/arch/x86/include/asm/setup.h
+++ linux-4.4.0/arch/x86/include/asm/setup.h
@@ -6,6 +6,7 @@
 #define COMMAND_LINE_SIZE 2048
 
 #include <linux/linkage.h>
+#include <asm/page_types.h>
 
 #ifdef __i386__
 
--- linux-4.4.0.orig/arch/x86/include/asm/smap.h
+++ linux-4.4.0/arch/x86/include/asm/smap.h
@@ -15,7 +15,7 @@
 
 #include <linux/stringify.h>
 #include <asm/nops.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 
 /* "Raw" instruction opcodes */
 #define __ASM_CLAC	.byte 0x0f,0x01,0xca
--- linux-4.4.0.orig/arch/x86/include/asm/smp.h
+++ linux-4.4.0/arch/x86/include/asm/smp.h
@@ -16,20 +16,10 @@
 #endif
 #include <asm/thread_info.h>
 #include <asm/cpumask.h>
-#include <asm/cpufeature.h>
 
 extern int smp_num_siblings;
 extern unsigned int num_processors;
 
-static inline bool cpu_has_ht_siblings(void)
-{
-	bool has_siblings = false;
-#ifdef CONFIG_SMP
-	has_siblings = cpu_has_ht && smp_num_siblings > 1;
-#endif
-	return has_siblings;
-}
-
 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: */
@@ -148,6 +138,7 @@
 int native_cpu_disable(void);
 int common_cpu_die(unsigned int cpu);
 void native_cpu_die(unsigned int cpu);
+void hlt_play_dead(void);
 void native_play_dead(void);
 void play_dead_common(void);
 void wbinvd_on_cpu(int cpu);
@@ -168,6 +159,7 @@
 	wbinvd();
 	return 0;
 }
+#define smp_num_siblings	1
 #endif /* CONFIG_SMP */
 
 extern unsigned disabled_cpus;
--- linux-4.4.0.orig/arch/x86/include/asm/spec-ctrl.h
+++ linux-4.4.0/arch/x86/include/asm/spec-ctrl.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_SPECCTRL_H_
+#define _ASM_X86_SPECCTRL_H_
+
+#include <linux/thread_info.h>
+#include <asm/nospec-branch.h>
+
+/*
+ * On VMENTER we must preserve whatever view of the SPEC_CTRL MSR
+ * the guest has, while on VMEXIT we restore the host view. This
+ * would be easier if SPEC_CTRL were architecturally maskable or
+ * shadowable for guests but this is not (currently) the case.
+ * Takes the guest view of SPEC_CTRL MSR as a parameter and also
+ * the guest's version of VIRT_SPEC_CTRL, if emulated.
+ */
+extern void x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool guest);
+
+/**
+ * x86_spec_ctrl_set_guest - Set speculation control registers for the guest
+ * @guest_spec_ctrl:		The guest content of MSR_SPEC_CTRL
+ * @guest_virt_spec_ctrl:	The guest controlled bits of MSR_VIRT_SPEC_CTRL
+ *				(may get translated to MSR_AMD64_LS_CFG bits)
+ *
+ * Avoids writing to the MSR if the content/bits are the same
+ */
+static inline
+void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl)
+{
+	x86_virt_spec_ctrl(guest_spec_ctrl, guest_virt_spec_ctrl, true);
+}
+
+/**
+ * x86_spec_ctrl_restore_host - Restore host speculation control registers
+ * @guest_spec_ctrl:		The guest content of MSR_SPEC_CTRL
+ * @guest_virt_spec_ctrl:	The guest controlled bits of MSR_VIRT_SPEC_CTRL
+ *				(may get translated to MSR_AMD64_LS_CFG bits)
+ *
+ * Avoids writing to the MSR if the content/bits are the same
+ */
+static inline
+void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl)
+{
+	x86_virt_spec_ctrl(guest_spec_ctrl, guest_virt_spec_ctrl, false);
+}
+
+/* AMD specific Speculative Store Bypass MSR data */
+extern u64 x86_amd_ls_cfg_base;
+extern u64 x86_amd_ls_cfg_ssbd_mask;
+
+static inline u64 ssbd_tif_to_spec_ctrl(u64 tifn)
+{
+	BUILD_BUG_ON(TIF_SSBD < SPEC_CTRL_SSBD_SHIFT);
+	return (tifn & _TIF_SSBD) >> (TIF_SSBD - SPEC_CTRL_SSBD_SHIFT);
+}
+
+static inline u64 stibp_tif_to_spec_ctrl(u64 tifn)
+{
+	BUILD_BUG_ON(TIF_SPEC_IB < SPEC_CTRL_STIBP_SHIFT);
+	return (tifn & _TIF_SPEC_IB) >> (TIF_SPEC_IB - SPEC_CTRL_STIBP_SHIFT);
+}
+
+static inline unsigned long ssbd_spec_ctrl_to_tif(u64 spec_ctrl)
+{
+	BUILD_BUG_ON(TIF_SSBD < SPEC_CTRL_SSBD_SHIFT);
+	return (spec_ctrl & SPEC_CTRL_SSBD) << (TIF_SSBD - SPEC_CTRL_SSBD_SHIFT);
+}
+
+static inline unsigned long stibp_spec_ctrl_to_tif(u64 spec_ctrl)
+{
+	BUILD_BUG_ON(TIF_SPEC_IB < SPEC_CTRL_STIBP_SHIFT);
+	return (spec_ctrl & SPEC_CTRL_STIBP) << (TIF_SPEC_IB - SPEC_CTRL_STIBP_SHIFT);
+}
+
+static inline u64 ssbd_tif_to_amd_ls_cfg(u64 tifn)
+{
+	return (tifn & _TIF_SSBD) ? x86_amd_ls_cfg_ssbd_mask : 0ULL;
+}
+
+#ifdef CONFIG_SMP
+extern void speculative_store_bypass_ht_init(void);
+#else
+static inline void speculative_store_bypass_ht_init(void) { }
+#endif
+
+extern void speculation_ctrl_update(unsigned long tif);
+extern void speculation_ctrl_update_current(void);
+
+extern void mds_user_clear_buffers(void);
+
+#endif
--- linux-4.4.0.orig/arch/x86/include/asm/spec_ctrl.h
+++ linux-4.4.0/arch/x86/include/asm/spec_ctrl.h
@@ -0,0 +1,79 @@
+#ifndef _ASM_X86_SPEC_CTRL_H
+#define _ASM_X86_SPEC_CTRL_H
+
+#include <linux/stringify.h>
+#include <asm/msr-index.h>
+#include <asm/cpufeatures.h>
+#include <asm/alternative-asm.h>
+
+#ifdef __ASSEMBLY__
+
+.extern ibrs_enabled
+.extern x86_spec_ctrl_base
+
+#define _SPEC_CTRL_IBRS (1 << SPEC_CTRL_IBRS_SHIFT)
+
+#define __ASM_ENABLE_IBRS			\
+	pushq %rax;				\
+	pushq %rcx;				\
+	pushq %rdx;				\
+	movl $MSR_IA32_SPEC_CTRL, %ecx;		\
+	movq x86_spec_ctrl_base, %rdx;		\
+	shr $32, %rdx;				\
+	movq x86_spec_ctrl_base, %rax;		\
+	orl $_SPEC_CTRL_IBRS, %eax;		\
+	wrmsr;					\
+	popq %rdx;				\
+	popq %rcx;				\
+	popq %rax
+
+#define __ASM_ENABLE_IBRS_CLOBBER		\
+	movl $MSR_IA32_SPEC_CTRL, %ecx;		\
+	movq x86_spec_ctrl_base, %rdx;		\
+	shr $32, %rdx;				\
+	movq x86_spec_ctrl_base, %rax;		\
+	orl $_SPEC_CTRL_IBRS, %eax;		\
+	wrmsr;
+
+#define __ASM_DISABLE_IBRS			\
+	pushq %rax;				\
+	pushq %rcx;				\
+	pushq %rdx;				\
+	movl $MSR_IA32_SPEC_CTRL, %ecx;		\
+	movq x86_spec_ctrl_base, %rdx;		\
+	shr $32, %rdx;				\
+	movq x86_spec_ctrl_base, %rax;		\
+	wrmsr;					\
+	popq %rdx;				\
+	popq %rcx;				\
+	popq %rax
+
+.macro ENABLE_IBRS
+	testl	$1, ibrs_enabled
+	jz	10f
+	__ASM_ENABLE_IBRS
+	jmp 20f
+10:
+	lfence
+20:
+.endm
+
+.macro ENABLE_IBRS_CLOBBER
+	testl	$1, ibrs_enabled
+	jz	11f
+	__ASM_ENABLE_IBRS_CLOBBER
+	jmp 21f
+11:
+	lfence
+21:
+.endm
+
+.macro DISABLE_IBRS
+	testl	$1, ibrs_enabled
+	jz	9f
+	__ASM_DISABLE_IBRS
+9:
+.endm
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_X86_SPEC_CTRL_H */
--- linux-4.4.0.orig/arch/x86/include/asm/stackprotector.h
+++ linux-4.4.0/arch/x86/include/asm/stackprotector.h
@@ -54,8 +54,13 @@
 /*
  * Initialize the stackprotector canary value.
  *
- * NOTE: this must only be called from functions that never return,
+ * NOTE: this must only be called from functions that never return
  * and it must always be inlined.
+ *
+ * In addition, it should be called from a compilation unit for which
+ * stack protector is disabled. Alternatively, the caller should not end
+ * with a function call which gets tail-call optimized as that would
+ * lead to checking a modified canary value.
  */
 static __always_inline void boot_init_stack_canary(void)
 {
--- linux-4.4.0.orig/arch/x86/include/asm/suspend_32.h
+++ linux-4.4.0/arch/x86/include/asm/suspend_32.h
@@ -15,6 +15,7 @@
 	unsigned long cr0, cr2, cr3, cr4;
 	u64 misc_enable;
 	bool misc_enable_saved;
+	struct saved_msrs saved_msrs;
 	struct desc_ptr gdt_desc;
 	struct desc_ptr idt;
 	u16 ldt;
--- linux-4.4.0.orig/arch/x86/include/asm/suspend_64.h
+++ linux-4.4.0/arch/x86/include/asm/suspend_64.h
@@ -24,6 +24,7 @@
 	unsigned long cr0, cr2, cr3, cr4, cr8;
 	u64 misc_enable;
 	bool misc_enable_saved;
+	struct saved_msrs saved_msrs;
 	unsigned long efer;
 	u16 gdt_pad; /* Unused */
 	struct desc_ptr gdt_desc;
--- linux-4.4.0.orig/arch/x86/include/asm/svm.h
+++ linux-4.4.0/arch/x86/include/asm/svm.h
@@ -108,6 +108,8 @@
 #define V_IGN_TPR_SHIFT 20
 #define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
 
+#define V_IRQ_INJECTION_BITS_MASK (V_IRQ_MASK | V_INTR_PRIO_MASK | V_IGN_TPR_MASK)
+
 #define V_INTR_MASKING_SHIFT 24
 #define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
 
--- linux-4.4.0.orig/arch/x86/include/asm/switch_to.h
+++ linux-4.4.0/arch/x86/include/asm/switch_to.h
@@ -1,12 +1,11 @@
 #ifndef _ASM_X86_SWITCH_TO_H
 #define _ASM_X86_SWITCH_TO_H
 
+#include <asm/nospec-branch.h>
+
 struct task_struct; /* one of the stranger aspects of C forward declarations */
 __visible struct task_struct *__switch_to(struct task_struct *prev,
 					   struct task_struct *next);
-struct tss_struct;
-void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
-		      struct tss_struct *tss);
 
 #ifdef CONFIG_X86_32
 
@@ -24,6 +23,23 @@
 #define __switch_canary_iparam
 #endif	/* CC_STACKPROTECTOR */
 
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * When switching from a shallower to a deeper call stack
+	 * the RSB may either underflow or use entries populated
+	 * with userspace addresses. On CPUs where those concerns
+	 * exist, overwrite the RSB with entries which capture
+	 * speculative execution to prevent attack.
+	 */
+#define __retpoline_fill_return_buffer					\
+	ALTERNATIVE("jmp 910f",						\
+		__stringify(__FILL_RETURN_BUFFER(%%ebx, RSB_CLEAR_LOOPS, %%esp)),\
+		X86_FEATURE_RSB_CTXSW)					\
+	"910:\n\t"
+#else
+#define __retpoline_fill_return_buffer
+#endif
+
 /*
  * Saving eflags is important. It switches not only IOPL between tasks,
  * it also protects other tasks from NT leaking through sysenter etc.
@@ -46,6 +62,7 @@
 		     "movl $1f,%[prev_ip]\n\t"	/* save    EIP   */	\
 		     "pushl %[next_ip]\n\t"	/* restore EIP   */	\
 		     __switch_canary					\
+		     __retpoline_fill_return_buffer			\
 		     "jmp __switch_to\n"	/* regparm call  */	\
 		     "1:\t"						\
 		     "popl %%ebp\n\t"		/* restore EBP   */	\
@@ -100,6 +117,23 @@
 #define __switch_canary_iparam
 #endif	/* CC_STACKPROTECTOR */
 
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * When switching from a shallower to a deeper call stack
+	 * the RSB may either underflow or use entries populated
+	 * with userspace addresses. On CPUs where those concerns
+	 * exist, overwrite the RSB with entries which capture
+	 * speculative execution to prevent attack.
+	 */
+#define __retpoline_fill_return_buffer					\
+	ALTERNATIVE("jmp 910f",						\
+		__stringify(__FILL_RETURN_BUFFER(%%r12, RSB_CLEAR_LOOPS, %%rsp)),\
+		X86_FEATURE_RSB_CTXSW)					\
+	"910:\n\t"
+#else
+#define __retpoline_fill_return_buffer
+#endif
+
 /*
  * There is no need to save or restore flags, because flags are always
  * clean in kernel mode, with the possible exception of IOPL.  Kernel IOPL
@@ -112,6 +146,7 @@
 	     "call __switch_to\n\t"					  \
 	     "movq "__percpu_arg([current_task])",%%rsi\n\t"		  \
 	     __switch_canary						  \
+	     __retpoline_fill_return_buffer				  \
 	     "movq %P[thread_info](%%rsi),%%r8\n\t"			  \
 	     "movq %%rax,%%rdi\n\t" 					  \
 	     "testl  %[_tif_fork],%P[ti_flags](%%r8)\n\t"		  \
--- linux-4.4.0.orig/arch/x86/include/asm/syscalls.h
+++ linux-4.4.0/arch/x86/include/asm/syscalls.h
@@ -21,7 +21,7 @@
 asmlinkage long sys_iopl(unsigned int);
 
 /* kernel/ldt.c */
-asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
+asmlinkage long sys_modify_ldt(int, void __user *, unsigned long);
 
 /* kernel/signal.c */
 asmlinkage long sys_rt_sigreturn(void);
--- linux-4.4.0.orig/arch/x86/include/asm/text-patching.h
+++ linux-4.4.0/arch/x86/include/asm/text-patching.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_X86_TEXT_PATCHING_H
+#define _ASM_X86_TEXT_PATCHING_H
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <asm/ptrace.h>
+
+struct paravirt_patch_site;
+#ifdef CONFIG_PARAVIRT
+void apply_paravirt(struct paravirt_patch_site *start,
+		    struct paravirt_patch_site *end);
+#else
+static inline void apply_paravirt(struct paravirt_patch_site *start,
+				  struct paravirt_patch_site *end)
+{}
+#define __parainstructions	NULL
+#define __parainstructions_end	NULL
+#endif
+
+extern void *text_poke_early(void *addr, const void *opcode, size_t len);
+
+/*
+ * Clear and restore the kernel write-protection flag on the local CPU.
+ * Allows the kernel to edit read-only pages.
+ * Side-effect: any interrupt handler running between save and restore will have
+ * the ability to write to read-only pages.
+ *
+ * Warning:
+ * Code patching in the UP case is safe if NMIs and MCE handlers are stopped and
+ * no thread can be preempted in the instructions being modified (no iret to an
+ * invalid instruction possible) or if the instructions are changed from a
+ * consistent state to another consistent state atomically.
+ * On the local CPU you need to be protected again NMI or MCE handlers seeing an
+ * inconsistent instruction while you patch.
+ */
+extern void *text_poke(void *addr, const void *opcode, size_t len);
+extern int poke_int3_handler(struct pt_regs *regs);
+extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler);
+
+#endif /* _ASM_X86_TEXT_PATCHING_H */
--- linux-4.4.0.orig/arch/x86/include/asm/thread_info.h
+++ linux-4.4.0/arch/x86/include/asm/thread_info.h
@@ -49,7 +49,7 @@
  */
 #ifndef __ASSEMBLY__
 struct task_struct;
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <linux/atomic.h>
 
 struct thread_info {
@@ -83,18 +83,18 @@
  * thread information flags
  * - these are process state flags that various assembly files
  *   may need to access
- * - pending work-to-be-done flags are in LSW
- * - other flags in MSW
- * Warning: layout of LSW is hardcoded in entry.S
  */
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_NOTIFY_RESUME	1	/* callback before returning to user */
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* reenable singlestep on user return*/
+#define TIF_SSBD		5	/* Speculative store bypass disable */
 #define TIF_SYSCALL_EMU		6	/* syscall emulation active */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_SECCOMP		8	/* secure computing */
+#define TIF_SPEC_IB		9	/* Indirect branch speculation mitigation */
+#define TIF_SPEC_FORCE_UPDATE	10	/* Force speculation MSR update in context switch */
 #define TIF_USER_RETURN_NOTIFY	11	/* notify kernel of userspace return */
 #define TIF_UPROBE		12	/* breakpointed or singlestepping */
 #define TIF_NOTSC		16	/* TSC is not accessible in userland */
@@ -114,11 +114,14 @@
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
-#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
+#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
+#define _TIF_SSBD		(1 << TIF_SSBD)
 #define _TIF_SYSCALL_EMU	(1 << TIF_SYSCALL_EMU)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
+#define _TIF_SPEC_IB		(1 << TIF_SPEC_IB)
+#define _TIF_SPEC_FORCE_UPDATE	(1 << TIF_SPEC_FORCE_UPDATE)
 #define _TIF_USER_RETURN_NOTIFY	(1 << TIF_USER_RETURN_NOTIFY)
 #define _TIF_UPROBE		(1 << TIF_UPROBE)
 #define _TIF_NOTSC		(1 << TIF_NOTSC)
@@ -142,12 +145,24 @@
 
 /* work to do on any return to user space */
 #define _TIF_ALLWORK_MASK						\
-	((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT |	\
-	_TIF_NOHZ)
+	(_TIF_SYSCALL_TRACE | _TIF_NOTIFY_RESUME | _TIF_SIGPENDING |	\
+	 _TIF_NEED_RESCHED | _TIF_SINGLESTEP | _TIF_SYSCALL_EMU |	\
+	 _TIF_SYSCALL_AUDIT | _TIF_USER_RETURN_NOTIFY | _TIF_UPROBE |	\
+	 _TIF_NOHZ | _TIF_SYSCALL_TRACEPOINT)
 
 /* flags to check in __switch_to() */
-#define _TIF_WORK_CTXSW							\
-	(_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP)
+#define _TIF_WORK_CTXSW_BASE						\
+	(_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP|			\
+	 _TIF_SSBD | _TIF_SPEC_FORCE_UPDATE)
+
+/*
+ * Avoid calls to __switch_to_xtra() on UP as STIBP is not evaluated.
+ */
+#ifdef CONFIG_SMP
+# define _TIF_WORK_CTXSW	(_TIF_WORK_CTXSW_BASE | _TIF_SPEC_IB)
+#else
+# define _TIF_WORK_CTXSW	(_TIF_WORK_CTXSW_BASE)
+#endif
 
 #define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
 #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
@@ -166,17 +181,6 @@
 	return (struct thread_info *)(current_top_of_stack() - THREAD_SIZE);
 }
 
-static inline unsigned long current_stack_pointer(void)
-{
-	unsigned long sp;
-#ifdef CONFIG_X86_64
-	asm("mov %%rsp,%0" : "=g" (sp));
-#else
-	asm("mov %%esp,%0" : "=g" (sp));
-#endif
-	return sp;
-}
-
 #else /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_X86_64
--- linux-4.4.0.orig/arch/x86/include/asm/tlbflush.h
+++ linux-4.4.0/arch/x86/include/asm/tlbflush.h
@@ -5,7 +5,57 @@
 #include <linux/sched.h>
 
 #include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <asm/special_insns.h>
+#include <asm/smp.h>
+
+static inline void __invpcid(unsigned long pcid, unsigned long addr,
+			     unsigned long type)
+{
+	struct { u64 d[2]; } desc = { { pcid, addr } };
+
+	/*
+	 * The memory clobber is because the whole point is to invalidate
+	 * stale TLB entries and, especially if we're flushing global
+	 * mappings, we don't want the compiler to reorder any subsequent
+	 * memory accesses before the TLB flush.
+	 *
+	 * The hex opcode is invpcid (%ecx), %eax in 32-bit mode and
+	 * invpcid (%rcx), %rax in long mode.
+	 */
+	asm volatile (".byte 0x66, 0x0f, 0x38, 0x82, 0x01"
+		      : : "m" (desc), "a" (type), "c" (&desc) : "memory");
+}
+
+#define INVPCID_TYPE_INDIV_ADDR		0
+#define INVPCID_TYPE_SINGLE_CTXT	1
+#define INVPCID_TYPE_ALL_INCL_GLOBAL	2
+#define INVPCID_TYPE_ALL_NON_GLOBAL	3
+
+/* Flush all mappings for a given pcid and addr, not including globals. */
+static inline void invpcid_flush_one(unsigned long pcid,
+				     unsigned long addr)
+{
+	__invpcid(pcid, addr, INVPCID_TYPE_INDIV_ADDR);
+}
+
+/* Flush all mappings for a given PCID, not including globals. */
+static inline void invpcid_flush_single_context(unsigned long pcid)
+{
+	__invpcid(pcid, 0, INVPCID_TYPE_SINGLE_CTXT);
+}
+
+/* Flush all mappings, including globals, for all PCIDs. */
+static inline void invpcid_flush_all(void)
+{
+	__invpcid(0, 0, INVPCID_TYPE_ALL_INCL_GLOBAL);
+}
+
+/* Flush all mappings for all PCIDs except globals. */
+static inline void invpcid_flush_all_nonglobals(void)
+{
+	__invpcid(0, 0, INVPCID_TYPE_ALL_NON_GLOBAL);
+}
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
@@ -16,10 +66,14 @@
 #endif
 
 struct tlb_state {
-#ifdef CONFIG_SMP
 	struct mm_struct *active_mm;
 	int state;
-#endif
+
+	/* Last user mm for optimizing IBPB */
+	union {
+		struct mm_struct	*last_user_mm;
+		unsigned long		last_user_mm_ibpb;
+	};
 
 	/*
 	 * Access to this CR4 shadow and to H/W CR4 is protected by
@@ -32,7 +86,7 @@
 /* Initialize cr4 shadow for this CPU. */
 static inline void cr4_init_shadow(void)
 {
-	this_cpu_write(cpu_tlbstate.cr4, __read_cr4());
+	this_cpu_write(cpu_tlbstate.cr4, __read_cr4_safe());
 }
 
 /* Set in this cpu's CR4. */
@@ -61,6 +115,16 @@
 	}
 }
 
+static inline void cr4_toggle_bits(unsigned long mask)
+{
+	unsigned long cr4;
+
+	cr4 = this_cpu_read(cpu_tlbstate.cr4);
+	cr4 ^= mask;
+	this_cpu_write(cpu_tlbstate.cr4, cr4);
+	__write_cr4(cr4);
+}
+
 /* Read the CR4 shadow. */
 static inline unsigned long cr4_read_shadow(void)
 {
@@ -84,9 +148,36 @@
 	cr4_set_bits(mask);
 }
 
+/*
+ * Declare a couple of kaiser interfaces here for convenience,
+ * to avoid the need for asm/kaiser.h in unexpected places.
+ */
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+extern int kaiser_enabled;
+extern void kaiser_setup_pcid(void);
+extern void kaiser_flush_tlb_on_return_to_user(void);
+#else
+#define kaiser_enabled 0
+static inline void kaiser_setup_pcid(void)
+{
+}
+static inline void kaiser_flush_tlb_on_return_to_user(void)
+{
+}
+#endif
+
 static inline void __native_flush_tlb(void)
 {
+	/*
+	 * If current->mm == NULL then we borrow a mm which may change during a
+	 * task switch and therefore we must not be preempted while we write CR3
+	 * back:
+	 */
+	preempt_disable();
+	if (kaiser_enabled)
+		kaiser_flush_tlb_on_return_to_user();
 	native_write_cr3(native_read_cr3());
+	preempt_enable();
 }
 
 static inline void __native_flush_tlb_global_irq_disabled(void)
@@ -94,39 +185,85 @@
 	unsigned long cr4;
 
 	cr4 = this_cpu_read(cpu_tlbstate.cr4);
-	/* clear PGE */
-	native_write_cr4(cr4 & ~X86_CR4_PGE);
-	/* write old PGE again and flush TLBs */
-	native_write_cr4(cr4);
+	if (cr4 & X86_CR4_PGE) {
+		/* clear PGE and flush TLB of all entries */
+		native_write_cr4(cr4 & ~X86_CR4_PGE);
+		/* restore PGE as it was before */
+		native_write_cr4(cr4);
+	} else {
+		/* do it with cr3, letting kaiser flush user PCID */
+		__native_flush_tlb();
+	}
 }
 
 static inline void __native_flush_tlb_global(void)
 {
 	unsigned long flags;
 
+	if (this_cpu_has(X86_FEATURE_INVPCID)) {
+		/*
+		 * Using INVPCID is considerably faster than a pair of writes
+		 * to CR4 sandwiched inside an IRQ flag save/restore.
+		 */
+		invpcid_flush_all();
+		return;
+	}
+
 	/*
 	 * Read-modify-write to CR4 - protect it from preemption and
 	 * from interrupts. (Use the raw variant because this code can
 	 * be called from deep inside debugging code.)
 	 */
 	raw_local_irq_save(flags);
-
 	__native_flush_tlb_global_irq_disabled();
-
 	raw_local_irq_restore(flags);
 }
 
 static inline void __native_flush_tlb_single(unsigned long addr)
 {
-	asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
+	/*
+	 * SIMICS #GP's if you run INVPCID with type 2/3
+	 * and X86_CR4_PCIDE clear.  Shame!
+	 *
+	 * The ASIDs used below are hard-coded.  But, we must not
+	 * call invpcid(type=1/2) before CR4.PCIDE=1.  Just call
+	 * invlpg in the case we are called early.
+	 */
+
+	if (!this_cpu_has(X86_FEATURE_INVPCID_SINGLE)) {
+		if (kaiser_enabled)
+			kaiser_flush_tlb_on_return_to_user();
+		asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
+		return;
+	}
+	/* Flush the address out of both PCIDs. */
+	/*
+	 * An optimization here might be to determine addresses
+	 * that are only kernel-mapped and only flush the kernel
+	 * ASID.  But, userspace flushes are probably much more
+	 * important performance-wise.
+	 *
+	 * In the KAISER disabled case, do an INVLPG to make sure
+	 * the mapping is flushed in case it is a global one.
+	 */
+	if (kaiser_enabled) {
+		invpcid_flush_one(X86_CR3_PCID_ASID_USER, addr);
+		invpcid_flush_one(X86_CR3_PCID_ASID_KERN, addr);
+	} else {
+		asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
+	}
 }
 
 static inline void __flush_tlb_all(void)
 {
-	if (cpu_has_pge)
-		__flush_tlb_global();
-	else
-		__flush_tlb();
+	__flush_tlb_global();
+	/*
+	 * Note: if we somehow had PCID but not PGE, then this wouldn't work --
+	 * we'd end up flushing kernel translations for the current ASID but
+	 * we might fail to flush kernel translations for other cached ASIDs.
+	 *
+	 * To avoid this issue, we force PCID off if PGE is off.
+	 */
 }
 
 static inline void __flush_tlb_one(unsigned long addr)
@@ -140,7 +277,6 @@
 /*
  * TLB flushing:
  *
- *  - flush_tlb() flushes the current mm struct TLBs
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
@@ -152,84 +288,6 @@
  * and page-granular flushes are available only on i486 and up.
  */
 
-#ifndef CONFIG_SMP
-
-/* "_up" is for UniProcessor.
- *
- * This is a helper for other header functions.  *Not* intended to be called
- * directly.  All global TLB flushes need to either call this, or to bump the
- * vm statistics themselves.
- */
-static inline void __flush_tlb_up(void)
-{
-	count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
-	__flush_tlb();
-}
-
-static inline void flush_tlb_all(void)
-{
-	count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
-	__flush_tlb_all();
-}
-
-static inline void flush_tlb(void)
-{
-	__flush_tlb_up();
-}
-
-static inline void local_flush_tlb(void)
-{
-	__flush_tlb_up();
-}
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
-	if (mm == current->active_mm)
-		__flush_tlb_up();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-				  unsigned long addr)
-{
-	if (vma->vm_mm == current->active_mm)
-		__flush_tlb_one(addr);
-}
-
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-				   unsigned long start, unsigned long end)
-{
-	if (vma->vm_mm == current->active_mm)
-		__flush_tlb_up();
-}
-
-static inline void flush_tlb_mm_range(struct mm_struct *mm,
-	   unsigned long start, unsigned long end, unsigned long vmflag)
-{
-	if (mm == current->active_mm)
-		__flush_tlb_up();
-}
-
-static inline void native_flush_tlb_others(const struct cpumask *cpumask,
-					   struct mm_struct *mm,
-					   unsigned long start,
-					   unsigned long end)
-{
-}
-
-static inline void reset_lazy_tlbstate(void)
-{
-}
-
-static inline void flush_tlb_kernel_range(unsigned long start,
-					  unsigned long end)
-{
-	flush_tlb_all();
-}
-
-#else  /* SMP */
-
-#include <asm/smp.h>
-
 #define local_flush_tlb() __flush_tlb()
 
 #define flush_tlb_mm(mm)	flush_tlb_mm_range(mm, 0UL, TLB_FLUSH_ALL, 0UL)
@@ -238,13 +296,14 @@
 		flush_tlb_mm_range(vma->vm_mm, start, end, vma->vm_flags)
 
 extern void flush_tlb_all(void);
-extern void flush_tlb_current_task(void);
-extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
 				unsigned long end, unsigned long vmflag);
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
-#define flush_tlb()	flush_tlb_current_task()
+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long a)
+{
+	flush_tlb_mm_range(vma->vm_mm, a, a + PAGE_SIZE, VM_NONE);
+}
 
 void native_flush_tlb_others(const struct cpumask *cpumask,
 				struct mm_struct *mm,
@@ -259,14 +318,6 @@
 	this_cpu_write(cpu_tlbstate.active_mm, &init_mm);
 }
 
-#endif	/* SMP */
-
-/* Not inlined due to inc_irq_stat not being defined yet */
-#define flush_tlb_local() {		\
-	inc_irq_stat(irq_tlb_count);	\
-	local_flush_tlb();		\
-}
-
 #ifndef CONFIG_PARAVIRT
 #define flush_tlb_others(mask, mm, start, end)	\
 	native_flush_tlb_others(mask, mm, start, end)
--- linux-4.4.0.orig/arch/x86/include/asm/topology.h
+++ linux-4.4.0/arch/x86/include/asm/topology.h
@@ -46,6 +46,7 @@
 #include <linux/cpumask.h>
 
 #include <asm/mpspec.h>
+#include <asm/percpu.h>
 
 /* Mappings between logical cpu number and node number */
 DECLARE_EARLY_PER_CPU(int, x86_cpu_to_node_map);
@@ -119,12 +120,36 @@
 
 extern const struct cpumask *cpu_coregroup_mask(int cpu);
 
+#define topology_logical_package_id(cpu)	(cpu_data(cpu).logical_proc_id)
 #define topology_physical_package_id(cpu)	(cpu_data(cpu).phys_proc_id)
 #define topology_core_id(cpu)			(cpu_data(cpu).cpu_core_id)
 
 #ifdef ENABLE_TOPO_DEFINES
 #define topology_core_cpumask(cpu)		(per_cpu(cpu_core_map, cpu))
 #define topology_sibling_cpumask(cpu)		(per_cpu(cpu_sibling_map, cpu))
+
+extern unsigned int __max_logical_packages;
+#define topology_max_packages()			(__max_logical_packages)
+
+extern int __max_smt_threads;
+
+static inline int topology_max_smt_threads(void)
+{
+	return __max_smt_threads;
+}
+
+int topology_update_package_map(unsigned int apicid, unsigned int cpu);
+int topology_phys_to_logical_pkg(unsigned int pkg);
+bool topology_is_primary_thread(unsigned int cpu);
+bool topology_smt_supported(void);
+#else
+#define topology_max_packages()			(1)
+static inline int
+topology_update_package_map(unsigned int apicid, unsigned int cpu) { return 0; }
+static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
+static inline int topology_max_smt_threads(void) { return 1; }
+static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
+static inline bool topology_smt_supported(void) { return false; }
 #endif
 
 static inline void arch_fix_phys_package_id(int num, u32 slot)
--- linux-4.4.0.orig/arch/x86/include/asm/traps.h
+++ linux-4.4.0/arch/x86/include/asm/traps.h
@@ -92,6 +92,7 @@
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *, long);
 #endif
+dotraplinkage void do_mce(struct pt_regs *, long);
 
 static inline int get_si_code(unsigned long condition)
 {
--- linux-4.4.0.orig/arch/x86/include/asm/tsc.h
+++ linux-4.4.0/arch/x86/include/asm/tsc.h
@@ -29,6 +29,8 @@
 	return rdtsc();
 }
 
+extern struct system_counterval_t convert_art_to_tsc(cycle_t art);
+
 extern void tsc_init(void);
 extern void mark_tsc_unstable(char *reason);
 extern int unsynchronized_tsc(void);
--- linux-4.4.0.orig/arch/x86/include/asm/uaccess.h
+++ linux-4.4.0/arch/x86/include/asm/uaccess.h
@@ -7,6 +7,7 @@
 #include <linux/compiler.h>
 #include <linux/thread_info.h>
 #include <linux/string.h>
+#include <linux/preempt.h>
 #include <asm/asm.h>
 #include <asm/page.h>
 #include <asm/smap.h>
@@ -66,6 +67,12 @@
 	__chk_range_not_ok((unsigned long __force)(addr), size, limit); \
 })
 
+#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
+# define WARN_ON_IN_IRQ()	WARN_ON_ONCE(!in_task())
+#else
+# define WARN_ON_IN_IRQ()
+#endif
+
 /**
  * access_ok: - Checks if a user space pointer is valid
  * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
@@ -86,8 +93,11 @@
  * checks that the pointer is in the user space range - after calling
  * this function, memory access functions may still return -EFAULT.
  */
-#define access_ok(type, addr, size) \
-	likely(!__range_not_ok(addr, size, user_addr_max()))
+#define access_ok(type, addr, size)					\
+({									\
+	WARN_ON_IN_IRQ();						\
+	likely(!__range_not_ok(addr, size, user_addr_max()));		\
+})
 
 /*
  * The exception table consists of pairs of addresses relative to the
@@ -134,6 +144,14 @@
 extern int __get_user_8(void);
 extern int __get_user_bad(void);
 
+#define __uaccess_begin() stac()
+#define __uaccess_end()   clac()
+#define __uaccess_begin_nospec()	\
+({					\
+	stac();				\
+	barrier_nospec();		\
+})
+
 /*
  * This is a type: either unsigned long, if the argument fits into
  * that type, or otherwise unsigned long long.
@@ -193,10 +211,10 @@
 
 #ifdef CONFIG_X86_32
 #define __put_user_asm_u64(x, addr, err, errret)			\
-	asm volatile(ASM_STAC "\n"					\
+	asm volatile("\n"						\
 		     "1:	movl %%eax,0(%2)\n"			\
 		     "2:	movl %%edx,4(%2)\n"			\
-		     "3: " ASM_CLAC "\n"				\
+		     "3:"						\
 		     ".section .fixup,\"ax\"\n"				\
 		     "4:	movl %3,%0\n"				\
 		     "	jmp 3b\n"					\
@@ -207,10 +225,10 @@
 		     : "A" (x), "r" (addr), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex_u64(x, addr)					\
-	asm volatile(ASM_STAC "\n"					\
+	asm volatile("\n"						\
 		     "1:	movl %%eax,0(%1)\n"			\
 		     "2:	movl %%edx,4(%1)\n"			\
-		     "3: " ASM_CLAC "\n"				\
+		     "3:"						\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     _ASM_EXTABLE_EX(2b, 3b)				\
 		     : : "A" (x), "r" (addr))
@@ -296,14 +314,17 @@
 		__put_user_asm(x, ptr, retval, "l", "k", "ir", errret);	\
 		break;							\
 	case 8:								\
-		__put_user_asm_u64((__typeof__(*ptr))(x), ptr, retval,	\
-				   errret);				\
+		__put_user_asm_u64(x, ptr, retval, errret);		\
 		break;							\
 	default:							\
 		__put_user_bad();					\
 	}								\
 } while (0)
 
+/*
+ * This doesn't do __uaccess_begin/end - the exception handling
+ * around it must do that.
+ */
 #define __put_user_size_ex(x, ptr, size)				\
 do {									\
 	__chk_user_ptr(ptr);						\
@@ -332,7 +353,7 @@
 #define __get_user_asm_u64(x, ptr, retval, errret) \
 	 __get_user_asm(x, ptr, retval, "q", "", "=r", errret)
 #define __get_user_asm_ex_u64(x, ptr) \
-	 __get_user_asm_ex(x, ptr, "q", "", "=r")
+	 __get_user_asm_ex(x, ptr, "q", "", "=&r")
 #endif
 
 #define __get_user_size(x, ptr, size, retval, errret)			\
@@ -358,9 +379,9 @@
 } while (0)
 
 #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile(ASM_STAC "\n"					\
+	asm volatile("\n"						\
 		     "1:	mov"itype" %2,%"rtype"1\n"		\
-		     "2: " ASM_CLAC "\n"				\
+		     "2:\n"						\
 		     ".section .fixup,\"ax\"\n"				\
 		     "3:	mov %3,%0\n"				\
 		     "	xor"itype" %"rtype"1,%"rtype"1\n"		\
@@ -370,18 +391,22 @@
 		     : "=r" (err), ltype(x)				\
 		     : "m" (__m(addr)), "i" (errret), "0" (err))
 
+/*
+ * This doesn't do __uaccess_begin/end - the exception handling
+ * around it must do that.
+ */
 #define __get_user_size_ex(x, ptr, size)				\
 do {									\
 	__chk_user_ptr(ptr);						\
 	switch (size) {							\
 	case 1:								\
-		__get_user_asm_ex(x, ptr, "b", "b", "=q");		\
+		__get_user_asm_ex(x, ptr, "b", "b", "=&q");		\
 		break;							\
 	case 2:								\
-		__get_user_asm_ex(x, ptr, "w", "w", "=r");		\
+		__get_user_asm_ex(x, ptr, "w", "w", "=&r");		\
 		break;							\
 	case 4:								\
-		__get_user_asm_ex(x, ptr, "l", "k", "=r");		\
+		__get_user_asm_ex(x, ptr, "l", "k", "=&r");		\
 		break;							\
 	case 8:								\
 		__get_user_asm_ex_u64(x, ptr);				\
@@ -395,12 +420,16 @@
 	asm volatile("1:	mov"itype" %1,%"rtype"0\n"		\
 		     "2:\n"						\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
-		     : ltype(x) : "m" (__m(addr)))
+		     : ltype(x) : "m" (__m(addr)), "0" (0))
 
 #define __put_user_nocheck(x, ptr, size)			\
 ({								\
 	int __pu_err;						\
-	__put_user_size((x), (ptr), (size), __pu_err, -EFAULT);	\
+	__typeof__(*(ptr)) __pu_val;				\
+	__pu_val = x;						\
+	__uaccess_begin();					\
+	__put_user_size(__pu_val, (ptr), (size), __pu_err, -EFAULT);\
+	__uaccess_end();					\
 	__builtin_expect(__pu_err, 0);				\
 })
 
@@ -408,7 +437,9 @@
 ({									\
 	int __gu_err;							\
 	unsigned long __gu_val;						\
+	__uaccess_begin_nospec();					\
 	__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);	\
+	__uaccess_end();						\
 	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
 	__builtin_expect(__gu_err, 0);					\
 })
@@ -423,9 +454,9 @@
  * aliasing issues.
  */
 #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile(ASM_STAC "\n"					\
+	asm volatile("\n"						\
 		     "1:	mov"itype" %"rtype"1,%2\n"		\
-		     "2: " ASM_CLAC "\n"				\
+		     "2:\n"						\
 		     ".section .fixup,\"ax\"\n"				\
 		     "3:	mov %3,%0\n"				\
 		     "	jmp 2b\n"					\
@@ -445,11 +476,15 @@
  */
 #define uaccess_try	do {						\
 	current_thread_info()->uaccess_err = 0;				\
-	stac();								\
+	__uaccess_begin();						\
 	barrier();
 
+#define uaccess_try_nospec do {						\
+	current_thread_info()->uaccess_err = 0;				\
+	__uaccess_begin_nospec();					\
+
 #define uaccess_catch(err)						\
-	clac();								\
+	__uaccess_end();						\
 	(err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0);	\
 } while (0)
 
@@ -512,7 +547,7 @@
  *	get_user_ex(...);
  * } get_user_catch(err)
  */
-#define get_user_try		uaccess_try
+#define get_user_try		uaccess_try_nospec
 #define get_user_catch(err)	uaccess_catch(err)
 
 #define get_user_ex(x, ptr)	do {					\
@@ -547,12 +582,13 @@
 	__typeof__(ptr) __uval = (uval);				\
 	__typeof__(*(ptr)) __old = (old);				\
 	__typeof__(*(ptr)) __new = (new);				\
+	__uaccess_begin_nospec();					\
 	switch (size) {							\
 	case 1:								\
 	{								\
-		asm volatile("\t" ASM_STAC "\n"				\
+		asm volatile("\n"					\
 			"1:\t" LOCK_PREFIX "cmpxchgb %4, %2\n"		\
-			"2:\t" ASM_CLAC "\n"				\
+			"2:\n"						\
 			"\t.section .fixup, \"ax\"\n"			\
 			"3:\tmov     %3, %0\n"				\
 			"\tjmp     2b\n"				\
@@ -566,9 +602,9 @@
 	}								\
 	case 2:								\
 	{								\
-		asm volatile("\t" ASM_STAC "\n"				\
+		asm volatile("\n"					\
 			"1:\t" LOCK_PREFIX "cmpxchgw %4, %2\n"		\
-			"2:\t" ASM_CLAC "\n"				\
+			"2:\n"						\
 			"\t.section .fixup, \"ax\"\n"			\
 			"3:\tmov     %3, %0\n"				\
 			"\tjmp     2b\n"				\
@@ -582,9 +618,9 @@
 	}								\
 	case 4:								\
 	{								\
-		asm volatile("\t" ASM_STAC "\n"				\
+		asm volatile("\n"					\
 			"1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"		\
-			"2:\t" ASM_CLAC "\n"				\
+			"2:\n"						\
 			"\t.section .fixup, \"ax\"\n"			\
 			"3:\tmov     %3, %0\n"				\
 			"\tjmp     2b\n"				\
@@ -601,9 +637,9 @@
 		if (!IS_ENABLED(CONFIG_X86_64))				\
 			__cmpxchg_wrong_size();				\
 									\
-		asm volatile("\t" ASM_STAC "\n"				\
+		asm volatile("\n"					\
 			"1:\t" LOCK_PREFIX "cmpxchgq %4, %2\n"		\
-			"2:\t" ASM_CLAC "\n"				\
+			"2:\n"						\
 			"\t.section .fixup, \"ax\"\n"			\
 			"3:\tmov     %3, %0\n"				\
 			"\tjmp     2b\n"				\
@@ -618,6 +654,7 @@
 	default:							\
 		__cmpxchg_wrong_size();					\
 	}								\
+	__uaccess_end();						\
 	*__uval = __old;						\
 	__ret;								\
 })
--- linux-4.4.0.orig/arch/x86/include/asm/uaccess_32.h
+++ linux-4.4.0/arch/x86/include/asm/uaccess_32.h
@@ -48,20 +48,28 @@
 
 		switch (n) {
 		case 1:
+			__uaccess_begin_nospec();
 			__put_user_size(*(u8 *)from, (u8 __user *)to,
 					1, ret, 1);
+			__uaccess_end();
 			return ret;
 		case 2:
+			__uaccess_begin_nospec();
 			__put_user_size(*(u16 *)from, (u16 __user *)to,
 					2, ret, 2);
+			__uaccess_end();
 			return ret;
 		case 4:
+			__uaccess_begin_nospec();
 			__put_user_size(*(u32 *)from, (u32 __user *)to,
 					4, ret, 4);
+			__uaccess_end();
 			return ret;
 		case 8:
+			__uaccess_begin_nospec();
 			__put_user_size(*(u64 *)from, (u64 __user *)to,
 					8, ret, 8);
+			__uaccess_end();
 			return ret;
 		}
 	}
@@ -103,13 +111,19 @@
 
 		switch (n) {
 		case 1:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u8 *)to, from, 1, ret, 1);
+			__uaccess_end();
 			return ret;
 		case 2:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u16 *)to, from, 2, ret, 2);
+			__uaccess_end();
 			return ret;
 		case 4:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u32 *)to, from, 4, ret, 4);
+			__uaccess_end();
 			return ret;
 		}
 	}
@@ -148,13 +162,19 @@
 
 		switch (n) {
 		case 1:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u8 *)to, from, 1, ret, 1);
+			__uaccess_end();
 			return ret;
 		case 2:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u16 *)to, from, 2, ret, 2);
+			__uaccess_end();
 			return ret;
 		case 4:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u32 *)to, from, 4, ret, 4);
+			__uaccess_end();
 			return ret;
 		}
 	}
@@ -170,13 +190,19 @@
 
 		switch (n) {
 		case 1:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u8 *)to, from, 1, ret, 1);
+			__uaccess_end();
 			return ret;
 		case 2:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u16 *)to, from, 2, ret, 2);
+			__uaccess_end();
 			return ret;
 		case 4:
+			__uaccess_begin_nospec();
 			__get_user_size(*(u32 *)to, from, 4, ret, 4);
+			__uaccess_end();
 			return ret;
 		}
 	}
--- linux-4.4.0.orig/arch/x86/include/asm/uaccess_64.h
+++ linux-4.4.0/arch/x86/include/asm/uaccess_64.h
@@ -8,7 +8,7 @@
 #include <linux/errno.h>
 #include <linux/lockdep.h>
 #include <asm/alternative.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/page.h>
 
 /*
@@ -56,35 +56,49 @@
 	if (!__builtin_constant_p(size))
 		return copy_user_generic(dst, (__force void *)src, size);
 	switch (size) {
-	case 1:__get_user_asm(*(u8 *)dst, (u8 __user *)src,
+	case 1:
+		__uaccess_begin_nospec();
+		__get_user_asm(*(u8 *)dst, (u8 __user *)src,
 			      ret, "b", "b", "=q", 1);
+		__uaccess_end();
 		return ret;
-	case 2:__get_user_asm(*(u16 *)dst, (u16 __user *)src,
+	case 2:
+		__uaccess_begin_nospec();
+		__get_user_asm(*(u16 *)dst, (u16 __user *)src,
 			      ret, "w", "w", "=r", 2);
+		__uaccess_end();
 		return ret;
-	case 4:__get_user_asm(*(u32 *)dst, (u32 __user *)src,
+	case 4:
+		__uaccess_begin_nospec();
+		__get_user_asm(*(u32 *)dst, (u32 __user *)src,
 			      ret, "l", "k", "=r", 4);
+		__uaccess_end();
 		return ret;
-	case 8:__get_user_asm(*(u64 *)dst, (u64 __user *)src,
+	case 8:
+		__uaccess_begin_nospec();
+		__get_user_asm(*(u64 *)dst, (u64 __user *)src,
 			      ret, "q", "", "=r", 8);
+		__uaccess_end();
 		return ret;
 	case 10:
+		__uaccess_begin_nospec();
 		__get_user_asm(*(u64 *)dst, (u64 __user *)src,
 			       ret, "q", "", "=r", 10);
-		if (unlikely(ret))
-			return ret;
-		__get_user_asm(*(u16 *)(8 + (char *)dst),
-			       (u16 __user *)(8 + (char __user *)src),
-			       ret, "w", "w", "=r", 2);
+		if (likely(!ret))
+			__get_user_asm(*(u16 *)(8 + (char *)dst),
+				       (u16 __user *)(8 + (char __user *)src),
+				       ret, "w", "w", "=r", 2);
+		__uaccess_end();
 		return ret;
 	case 16:
+		__uaccess_begin_nospec();
 		__get_user_asm(*(u64 *)dst, (u64 __user *)src,
 			       ret, "q", "", "=r", 16);
-		if (unlikely(ret))
-			return ret;
-		__get_user_asm(*(u64 *)(8 + (char *)dst),
-			       (u64 __user *)(8 + (char __user *)src),
-			       ret, "q", "", "=r", 8);
+		if (likely(!ret))
+			__get_user_asm(*(u64 *)(8 + (char *)dst),
+				       (u64 __user *)(8 + (char __user *)src),
+				       ret, "q", "", "=r", 8);
+		__uaccess_end();
 		return ret;
 	default:
 		return copy_user_generic(dst, (__force void *)src, size);
@@ -106,35 +120,51 @@
 	if (!__builtin_constant_p(size))
 		return copy_user_generic((__force void *)dst, src, size);
 	switch (size) {
-	case 1:__put_user_asm(*(u8 *)src, (u8 __user *)dst,
+	case 1:
+		__uaccess_begin();
+		__put_user_asm(*(u8 *)src, (u8 __user *)dst,
 			      ret, "b", "b", "iq", 1);
+		__uaccess_end();
 		return ret;
-	case 2:__put_user_asm(*(u16 *)src, (u16 __user *)dst,
+	case 2:
+		__uaccess_begin();
+		__put_user_asm(*(u16 *)src, (u16 __user *)dst,
 			      ret, "w", "w", "ir", 2);
+		__uaccess_end();
 		return ret;
-	case 4:__put_user_asm(*(u32 *)src, (u32 __user *)dst,
+	case 4:
+		__uaccess_begin();
+		__put_user_asm(*(u32 *)src, (u32 __user *)dst,
 			      ret, "l", "k", "ir", 4);
+		__uaccess_end();
 		return ret;
-	case 8:__put_user_asm(*(u64 *)src, (u64 __user *)dst,
+	case 8:
+		__uaccess_begin();
+		__put_user_asm(*(u64 *)src, (u64 __user *)dst,
 			      ret, "q", "", "er", 8);
+		__uaccess_end();
 		return ret;
 	case 10:
+		__uaccess_begin();
 		__put_user_asm(*(u64 *)src, (u64 __user *)dst,
 			       ret, "q", "", "er", 10);
-		if (unlikely(ret))
-			return ret;
-		asm("":::"memory");
-		__put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
-			       ret, "w", "w", "ir", 2);
+		if (likely(!ret)) {
+			asm("":::"memory");
+			__put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
+				       ret, "w", "w", "ir", 2);
+		}
+		__uaccess_end();
 		return ret;
 	case 16:
+		__uaccess_begin();
 		__put_user_asm(*(u64 *)src, (u64 __user *)dst,
 			       ret, "q", "", "er", 16);
-		if (unlikely(ret))
-			return ret;
-		asm("":::"memory");
-		__put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
-			       ret, "q", "", "er", 8);
+		if (likely(!ret)) {
+			asm("":::"memory");
+			__put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
+				       ret, "q", "", "er", 8);
+		}
+		__uaccess_end();
 		return ret;
 	default:
 		return copy_user_generic((__force void *)dst, src, size);
@@ -160,39 +190,47 @@
 	switch (size) {
 	case 1: {
 		u8 tmp;
+		__uaccess_begin_nospec();
 		__get_user_asm(tmp, (u8 __user *)src,
 			       ret, "b", "b", "=q", 1);
 		if (likely(!ret))
 			__put_user_asm(tmp, (u8 __user *)dst,
 				       ret, "b", "b", "iq", 1);
+		__uaccess_end();
 		return ret;
 	}
 	case 2: {
 		u16 tmp;
+		__uaccess_begin_nospec();
 		__get_user_asm(tmp, (u16 __user *)src,
 			       ret, "w", "w", "=r", 2);
 		if (likely(!ret))
 			__put_user_asm(tmp, (u16 __user *)dst,
 				       ret, "w", "w", "ir", 2);
+		__uaccess_end();
 		return ret;
 	}
 
 	case 4: {
 		u32 tmp;
+		__uaccess_begin_nospec();
 		__get_user_asm(tmp, (u32 __user *)src,
 			       ret, "l", "k", "=r", 4);
 		if (likely(!ret))
 			__put_user_asm(tmp, (u32 __user *)dst,
 				       ret, "l", "k", "ir", 4);
+		__uaccess_end();
 		return ret;
 	}
 	case 8: {
 		u64 tmp;
+		__uaccess_begin_nospec();
 		__get_user_asm(tmp, (u64 __user *)src,
 			       ret, "q", "", "=r", 8);
 		if (likely(!ret))
 			__put_user_asm(tmp, (u64 __user *)dst,
 				       ret, "q", "", "er", 8);
+		__uaccess_end();
 		return ret;
 	}
 	default:
--- linux-4.4.0.orig/arch/x86/include/asm/vdso.h
+++ linux-4.4.0/arch/x86/include/asm/vdso.h
@@ -22,6 +22,7 @@
 
 	long sym_vvar_page;
 	long sym_hpet_page;
+	long sym_pvclock_page;
 	long sym_VDSO32_NOTE_MASK;
 	long sym___kernel_sigreturn;
 	long sym___kernel_rt_sigreturn;
--- linux-4.4.0.orig/arch/x86/include/asm/vgtod.h
+++ linux-4.4.0/arch/x86/include/asm/vgtod.h
@@ -83,8 +83,13 @@
 	 * works on all CPUs.  This is volatile so that it orders
 	 * correctly wrt barrier() and to keep gcc from cleverly
 	 * hoisting it out of the calling function.
+	 *
+	 * If RDPID is available, use it.
 	 */
-	asm volatile ("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
+	alternative_io ("lsl %[seg],%[p]",
+			".byte 0xf3,0x0f,0xc7,0xf8", /* RDPID %eax/rax */
+			X86_FEATURE_RDPID,
+			[p] "=a" (p), [seg] "r" (__PER_CPU_SEG));
 
 	return p;
 }
--- linux-4.4.0.orig/arch/x86/include/asm/vmx.h
+++ linux-4.4.0/arch/x86/include/asm/vmx.h
@@ -310,6 +310,7 @@
 #define INTR_TYPE_NMI_INTR		(2 << 8) /* NMI */
 #define INTR_TYPE_HARD_EXCEPTION	(3 << 8) /* processor exception */
 #define INTR_TYPE_SOFT_INTR             (4 << 8) /* software interrupt */
+#define INTR_TYPE_PRIV_SW_EXCEPTION	(5 << 8) /* ICE breakpoint - undocumented */
 #define INTR_TYPE_SOFT_EXCEPTION	(6 << 8) /* software exception */
 
 /* GUEST_INTERRUPTIBILITY_INFO flags. */
@@ -400,10 +401,11 @@
 #define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT	(KVM_USER_MEM_SLOTS + 2)
 
 #define VMX_NR_VPIDS				(1 << 16)
+#define VMX_VPID_EXTENT_INDIVIDUAL_ADDR		0
 #define VMX_VPID_EXTENT_SINGLE_CONTEXT		1
 #define VMX_VPID_EXTENT_ALL_CONTEXT		2
+#define VMX_VPID_EXTENT_SINGLE_NON_GLOBAL	3
 
-#define VMX_EPT_EXTENT_INDIVIDUAL_ADDR		0
 #define VMX_EPT_EXTENT_CONTEXT			1
 #define VMX_EPT_EXTENT_GLOBAL			2
 #define VMX_EPT_EXTENT_SHIFT			24
@@ -420,8 +422,10 @@
 #define VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)
 
 #define VMX_VPID_INVVPID_BIT                    (1ull << 0) /* (32 - 32) */
+#define VMX_VPID_EXTENT_INDIVIDUAL_ADDR_BIT     (1ull << 8) /* (40 - 32) */
 #define VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT      (1ull << 9) /* (41 - 32) */
 #define VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT      (1ull << 10) /* (42 - 32) */
+#define VMX_VPID_EXTENT_SINGLE_NON_GLOBAL_BIT   (1ull << 11) /* (43 - 32) */
 
 #define VMX_EPT_DEFAULT_GAW			3
 #define VMX_EPT_MAX_GAW				0x4
@@ -496,4 +500,15 @@
 	VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28,
 };
 
+enum vmx_l1d_flush_state {
+	VMENTER_L1D_FLUSH_AUTO,
+	VMENTER_L1D_FLUSH_NEVER,
+	VMENTER_L1D_FLUSH_COND,
+	VMENTER_L1D_FLUSH_ALWAYS,
+	VMENTER_L1D_FLUSH_EPT_DISABLED,
+	VMENTER_L1D_FLUSH_NOT_REQUIRED,
+};
+
+extern enum vmx_l1d_flush_state l1tf_vmx_mitigation;
+
 #endif
--- linux-4.4.0.orig/arch/x86/include/asm/vsyscall.h
+++ linux-4.4.0/arch/x86/include/asm/vsyscall.h
@@ -12,12 +12,15 @@
  * Returns true if handled.
  */
 extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address);
+extern bool vsyscall_enabled(void);
 #else
 static inline void map_vsyscall(void) {}
 static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 {
 	return false;
 }
+static inline bool vsyscall_enabled(void) { return false; }
 #endif
+extern unsigned long vsyscall_pgprot;
 
 #endif /* _ASM_X86_VSYSCALL_H */
--- linux-4.4.0.orig/arch/x86/include/asm/xen/hypercall.h
+++ linux-4.4.0/arch/x86/include/asm/xen/hypercall.h
@@ -43,6 +43,8 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/smap.h>
+#include <asm/nospec-branch.h>
 
 #include <xen/interface/xen.h>
 #include <xen/interface/sched.h>
@@ -213,10 +215,15 @@
 	__HYPERCALL_DECLS;
 	__HYPERCALL_5ARG(a1, a2, a3, a4, a5);
 
-	asm volatile("call *%[call]"
+	if (call >= PAGE_SIZE / sizeof(hypercall_page[0]))
+		return -EINVAL;
+
+	stac();
+	asm volatile(CALL_NOSPEC
 		     : __HYPERCALL_5PARAM
-		     : [call] "a" (&hypercall_page[call])
+		     : [thunk_target] "a" (&hypercall_page[call])
 		     : __HYPERCALL_CLOBBER5);
+	clac();
 
 	return (long)__res;
 }
--- linux-4.4.0.orig/arch/x86/include/asm/xen/hypervisor.h
+++ linux-4.4.0/arch/x86/include/asm/xen/hypervisor.h
@@ -62,4 +62,6 @@
 void xen_arch_unregister_cpu(int num);
 #endif
 
+extern void xen_set_iopl_mask(unsigned mask);
+
 #endif /* _ASM_X86_XEN_HYPERVISOR_H */
--- linux-4.4.0.orig/arch/x86/include/asm/xor_32.h
+++ linux-4.4.0/arch/x86/include/asm/xor_32.h
@@ -553,7 +553,7 @@
 	if (cpu_has_xmm) {				\
 		xor_speed(&xor_block_pIII_sse);		\
 		xor_speed(&xor_block_sse_pf64);		\
-	} else if (cpu_has_mmx) {			\
+	} else if (boot_cpu_has(X86_FEATURE_MMX)) {	\
 		xor_speed(&xor_block_pII_mmx);		\
 		xor_speed(&xor_block_p5_mmx);		\
 	} else {					\
--- linux-4.4.0.orig/arch/x86/include/uapi/asm/Kbuild
+++ linux-4.4.0/arch/x86/include/uapi/asm/Kbuild
@@ -27,7 +27,6 @@
 header-y += mce.h
 header-y += mman.h
 header-y += msgbuf.h
-header-y += msr-index.h
 header-y += msr.h
 header-y += mtrr.h
 header-y += param.h
--- linux-4.4.0.orig/arch/x86/include/uapi/asm/bootparam.h
+++ linux-4.4.0/arch/x86/include/uapi/asm/bootparam.h
@@ -134,7 +134,8 @@
 	__u8  eddbuf_entries;				/* 0x1e9 */
 	__u8  edd_mbr_sig_buf_entries;			/* 0x1ea */
 	__u8  kbd_status;				/* 0x1eb */
-	__u8  _pad5[3];					/* 0x1ec */
+	__u8  secure_boot;				/* 0x1ec */
+	__u8  _pad5[2];					/* 0x1ed */
 	/*
 	 * The sentinel is set to a nonzero value (0xff) in header.S.
 	 *
--- linux-4.4.0.orig/arch/x86/include/uapi/asm/hyperv.h
+++ linux-4.4.0/arch/x86/include/uapi/asm/hyperv.h
@@ -226,7 +226,9 @@
 		(~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1))
 
 /* Declare the various hypercall operations. */
-#define HV_X64_HV_NOTIFY_LONG_SPIN_WAIT		0x0008
+#define HVCALL_NOTIFY_LONG_SPIN_WAIT		0x0008
+#define HVCALL_POST_MESSAGE			0x005c
+#define HVCALL_SIGNAL_EVENT			0x005d
 
 #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE		0x00000001
 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT	12
@@ -269,4 +271,96 @@
 #define HV_SYNIC_SINT_AUTO_EOI		(1ULL << 17)
 #define HV_SYNIC_SINT_VECTOR_MASK	(0xFF)
 
+#define HV_SYNIC_STIMER_COUNT		(4)
+
+/* Define synthetic interrupt controller message constants. */
+#define HV_MESSAGE_SIZE			(256)
+#define HV_MESSAGE_PAYLOAD_BYTE_COUNT	(240)
+#define HV_MESSAGE_PAYLOAD_QWORD_COUNT	(30)
+
+/* Define hypervisor message types. */
+enum hv_message_type {
+	HVMSG_NONE			= 0x00000000,
+
+	/* Memory access messages. */
+	HVMSG_UNMAPPED_GPA		= 0x80000000,
+	HVMSG_GPA_INTERCEPT		= 0x80000001,
+
+	/* Timer notification messages. */
+	HVMSG_TIMER_EXPIRED			= 0x80000010,
+
+	/* Error messages. */
+	HVMSG_INVALID_VP_REGISTER_VALUE	= 0x80000020,
+	HVMSG_UNRECOVERABLE_EXCEPTION	= 0x80000021,
+	HVMSG_UNSUPPORTED_FEATURE		= 0x80000022,
+
+	/* Trace buffer complete messages. */
+	HVMSG_EVENTLOG_BUFFERCOMPLETE	= 0x80000040,
+
+	/* Platform-specific processor intercept messages. */
+	HVMSG_X64_IOPORT_INTERCEPT		= 0x80010000,
+	HVMSG_X64_MSR_INTERCEPT		= 0x80010001,
+	HVMSG_X64_CPUID_INTERCEPT		= 0x80010002,
+	HVMSG_X64_EXCEPTION_INTERCEPT	= 0x80010003,
+	HVMSG_X64_APIC_EOI			= 0x80010004,
+	HVMSG_X64_LEGACY_FP_ERROR		= 0x80010005
+};
+
+/* Define synthetic interrupt controller message flags. */
+union hv_message_flags {
+	__u8 asu8;
+	struct {
+		__u8 msg_pending:1;
+		__u8 reserved:7;
+	};
+};
+
+/* Define port identifier type. */
+union hv_port_id {
+	__u32 asu32;
+	struct {
+		__u32 id:24;
+		__u32 reserved:8;
+	} u;
+};
+
+/* Define synthetic interrupt controller message header. */
+struct hv_message_header {
+	__u32 message_type;
+	__u8 payload_size;
+	union hv_message_flags message_flags;
+	__u8 reserved[2];
+	union {
+		__u64 sender;
+		union hv_port_id port;
+	};
+};
+
+/* Define synthetic interrupt controller message format. */
+struct hv_message {
+	struct hv_message_header header;
+	union {
+		__u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+	} u;
+};
+
+/* Define the synthetic interrupt message page layout. */
+struct hv_message_page {
+	struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
+};
+
+/* Define timer message payload structure. */
+struct hv_timer_message_payload {
+	__u32 timer_index;
+	__u32 reserved;
+	__u64 expiration_time;	/* When the timer expired */
+	__u64 delivery_time;	/* When the message was delivered */
+};
+
+#define HV_STIMER_ENABLE		(1ULL << 0)
+#define HV_STIMER_PERIODIC		(1ULL << 1)
+#define HV_STIMER_LAZY			(1ULL << 2)
+#define HV_STIMER_AUTOENABLE		(1ULL << 3)
+#define HV_STIMER_SINT(config)		(__u8)(((config) >> 16) & 0x0F)
+
 #endif
--- linux-4.4.0.orig/arch/x86/include/uapi/asm/mce.h
+++ linux-4.4.0/arch/x86/include/uapi/asm/mce.h
@@ -26,6 +26,10 @@
 	__u32 socketid;	/* CPU socket ID */
 	__u32 apicid;	/* CPU initial apic ID */
 	__u64 mcgcap;	/* MCGCAP MSR: machine check capabilities of CPU */
+	__u64 synd;	/* MCA_SYND MSR: only valid on SMCA systems */
+	__u64 ipid;	/* MCA_IPID MSR: only valid on SMCA systems */
+	__u64 ppin;	/* Protected Processor Inventory Number */
+	__u32 microcode;/* Microcode revision */
 };
 
 #define MCE_GET_RECORD_LEN   _IOR('M', 1, int)
--- linux-4.4.0.orig/arch/x86/include/uapi/asm/msgbuf.h
+++ linux-4.4.0/arch/x86/include/uapi/asm/msgbuf.h
@@ -1 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __ASM_X64_MSGBUF_H
+#define __ASM_X64_MSGBUF_H
+
+#if !defined(__x86_64__) || !defined(__ILP32__)
 #include <asm-generic/msgbuf.h>
+#else
+/*
+ * The msqid64_ds structure for x86 architecture with x32 ABI.
+ *
+ * On x86-32 and x86-64 we can just use the generic definition, but
+ * x32 uses the same binary layout as x86_64, which is differnet
+ * from other 32-bit architectures.
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	__kernel_time_t msg_ctime;	/* last change time */
+	__kernel_ulong_t msg_cbytes;	/* current number of bytes on queue */
+	__kernel_ulong_t msg_qnum;	/* number of messages in queue */
+	__kernel_ulong_t msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	__kernel_ulong_t __unused4;
+	__kernel_ulong_t __unused5;
+};
+
+#endif
+
+#endif /* __ASM_GENERIC_MSGBUF_H */
--- linux-4.4.0.orig/arch/x86/include/uapi/asm/processor-flags.h
+++ linux-4.4.0/arch/x86/include/uapi/asm/processor-flags.h
@@ -77,7 +77,8 @@
 #define X86_CR3_PWT		_BITUL(X86_CR3_PWT_BIT)
 #define X86_CR3_PCD_BIT		4 /* Page Cache Disable */
 #define X86_CR3_PCD		_BITUL(X86_CR3_PCD_BIT)
-#define X86_CR3_PCID_MASK	_AC(0x00000fff,UL) /* PCID Mask */
+#define X86_CR3_PCID_NOFLUSH_BIT 63 /* Preserve old PCID */
+#define X86_CR3_PCID_NOFLUSH    _BITULL(X86_CR3_PCID_NOFLUSH_BIT)
 
 /*
  * Intel CPU features in CR4
--- linux-4.4.0.orig/arch/x86/include/uapi/asm/shmbuf.h
+++ linux-4.4.0/arch/x86/include/uapi/asm/shmbuf.h
@@ -1 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __ASM_X86_SHMBUF_H
+#define __ASM_X86_SHMBUF_H
+
+#if !defined(__x86_64__) || !defined(__ILP32__)
 #include <asm-generic/shmbuf.h>
+#else
+/*
+ * The shmid64_ds structure for x86 architecture with x32 ABI.
+ *
+ * On x86-32 and x86-64 we can just use the generic definition, but
+ * x32 uses the same binary layout as x86_64, which is differnet
+ * from other 32-bit architectures.
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_time_t		shm_atime;	/* last attach time */
+	__kernel_time_t		shm_dtime;	/* last detach time */
+	__kernel_time_t		shm_ctime;	/* last change time */
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	__kernel_ulong_t	shm_nattch;	/* no. of current attaches */
+	__kernel_ulong_t	__unused4;
+	__kernel_ulong_t	__unused5;
+};
+
+struct shminfo64 {
+	__kernel_ulong_t	shmmax;
+	__kernel_ulong_t	shmmin;
+	__kernel_ulong_t	shmmni;
+	__kernel_ulong_t	shmseg;
+	__kernel_ulong_t	shmall;
+	__kernel_ulong_t	__unused1;
+	__kernel_ulong_t	__unused2;
+	__kernel_ulong_t	__unused3;
+	__kernel_ulong_t	__unused4;
+};
+
+#endif
+
+#endif /* __ASM_X86_SHMBUF_H */
--- linux-4.4.0.orig/arch/x86/kernel/Makefile
+++ linux-4.4.0/arch/x86/kernel/Makefile
@@ -41,6 +41,7 @@
 obj-y			+= tsc.o tsc_msr.o io_delay.o rtc.o
 obj-y			+= pci-iommu_table.o
 obj-y			+= resource.o
+obj-y			+= irqflags.o
 
 obj-y				+= process.o
 obj-y				+= fpu/
--- linux-4.4.0.orig/arch/x86/kernel/acpi/boot.c
+++ linux-4.4.0/arch/x86/kernel/acpi/boot.c
@@ -28,7 +28,7 @@
 #include <linux/acpi_pmtmr.h>
 #include <linux/efi.h>
 #include <linux/cpumask.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/dmi.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
@@ -321,20 +321,19 @@
 #ifdef CONFIG_X86_IO_APIC
 #define MP_ISA_BUS		0
 
+static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity,
+						u8 trigger, u32 gsi);
+
 static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
 					  u32 gsi)
 {
-	int ioapic;
-	int pin;
-	struct mpc_intsrc mp_irq;
-
 	/*
-	 * Convert 'gsi' to 'ioapic.pin'.
+	 * Check bus_irq boundary.
 	 */
-	ioapic = mp_find_ioapic(gsi);
-	if (ioapic < 0)
+	if (bus_irq >= NR_IRQS_LEGACY) {
+		pr_warn("Invalid bus_irq %u for legacy override\n", bus_irq);
 		return;
-	pin = mp_find_ioapic_pin(ioapic, gsi);
+	}
 
 	/*
 	 * TBD: This check is for faulty timer entries, where the override
@@ -344,16 +343,8 @@
 	if ((bus_irq == 0) && (trigger == 3))
 		trigger = 1;
 
-	mp_irq.type = MP_INTSRC;
-	mp_irq.irqtype = mp_INT;
-	mp_irq.irqflag = (trigger << 2) | polarity;
-	mp_irq.srcbus = MP_ISA_BUS;
-	mp_irq.srcbusirq = bus_irq;	/* IRQ */
-	mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */
-	mp_irq.dstirq = pin;	/* INTIN# */
-
-	mp_save_irq(&mp_irq);
-
+	if (mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi) < 0)
+		return;
 	/*
 	 * Reset default identity mapping if gsi is also an legacy IRQ,
 	 * otherwise there will be more than one entry with the same GSI
@@ -400,6 +391,34 @@
 	return 0;
 }
 
+static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity,
+						u8 trigger, u32 gsi)
+{
+	struct mpc_intsrc mp_irq;
+	int ioapic, pin;
+
+	/* Convert 'gsi' to 'ioapic.pin'(INTIN#) */
+	ioapic = mp_find_ioapic(gsi);
+	if (ioapic < 0) {
+		pr_warn("Failed to find ioapic for gsi : %u\n", gsi);
+		return ioapic;
+	}
+
+	pin = mp_find_ioapic_pin(ioapic, gsi);
+
+	mp_irq.type = MP_INTSRC;
+	mp_irq.irqtype = mp_INT;
+	mp_irq.irqflag = (trigger << 2) | polarity;
+	mp_irq.srcbus = MP_ISA_BUS;
+	mp_irq.srcbusirq = bus_irq;
+	mp_irq.dstapic = mpc_ioapic_id(ioapic);
+	mp_irq.dstirq = pin;
+
+	mp_save_irq(&mp_irq);
+
+	return 0;
+}
+
 static int __init
 acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
 {
@@ -444,7 +463,11 @@
 	if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
 		polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
 
-	mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
+	if (bus_irq < NR_IRQS_LEGACY)
+		mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
+	else
+		mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi);
+
 	acpi_penalize_sci_irq(bus_irq, trigger, polarity);
 
 	/*
@@ -1685,7 +1708,7 @@
 		new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
 		val = cmpxchg(lock, old, new);
 	} while (unlikely (val != old));
-	return (new < 3) ? -1 : 0;
+	return ((new & 0x3) < 3) ? -1 : 0;
 }
 
 int __acpi_release_global_lock(unsigned int *lock)
--- linux-4.4.0.orig/arch/x86/kernel/acpi/cstate.c
+++ linux-4.4.0/arch/x86/kernel/acpi/cstate.c
@@ -5,7 +5,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/cpu.h>
--- linux-4.4.0.orig/arch/x86/kernel/acpi/sleep.c
+++ linux-4.4.0/arch/x86/kernel/acpi/sleep.c
@@ -16,6 +16,7 @@
 #include <asm/cacheflush.h>
 #include <asm/realmode.h>
 
+#include <linux/ftrace.h>
 #include "../../realmode/rm/wakeup.h"
 #include "sleep.h"
 
@@ -107,7 +108,13 @@
        saved_magic = 0x123456789abcdef0L;
 #endif /* CONFIG_64BIT */
 
+	/*
+	 * Pause/unpause graph tracing around do_suspend_lowlevel as it has
+	 * inconsistent call/return info after it jumps to the wakeup vector.
+	 */
+	pause_graph_tracing();
 	do_suspend_lowlevel();
+	unpause_graph_tracing();
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/x86/kernel/acpi/wakeup_32.S
+++ linux-4.4.0/arch/x86/kernel/acpi/wakeup_32.S
@@ -2,6 +2,7 @@
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page_types.h>
+#include <asm/nospec-branch.h>
 
 # Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
 
@@ -37,6 +38,7 @@
 
 	# jump to place where we left off
 	movl	saved_eip, %eax
+	ANNOTATE_RETPOLINE_SAFE
 	jmp	*%eax
 
 bogus_magic:
--- linux-4.4.0.orig/arch/x86/kernel/acpi/wakeup_64.S
+++ linux-4.4.0/arch/x86/kernel/acpi/wakeup_64.S
@@ -5,6 +5,7 @@
 #include <asm/page_types.h>
 #include <asm/msr.h>
 #include <asm/asm-offsets.h>
+#include <asm/nospec-branch.h>
 
 # Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
 
@@ -32,6 +33,7 @@
 	movq	saved_rbp, %rbp
 
 	movq	saved_rip, %rax
+	ANNOTATE_RETPOLINE_SAFE
 	jmp	*%rax
 ENDPROC(wakeup_long64)
 
--- linux-4.4.0.orig/arch/x86/kernel/alternative.c
+++ linux-4.4.0/arch/x86/kernel/alternative.c
@@ -11,6 +11,7 @@
 #include <linux/stop_machine.h>
 #include <linux/slab.h>
 #include <linux/kdebug.h>
+#include <asm/text-patching.h>
 #include <asm/alternative.h>
 #include <asm/sections.h>
 #include <asm/pgtable.h>
@@ -45,17 +46,6 @@
 }
 __setup("noreplace-smp", setup_noreplace_smp);
 
-#ifdef CONFIG_PARAVIRT
-static int __initdata_or_module noreplace_paravirt = 0;
-
-static int __init setup_noreplace_paravirt(char *str)
-{
-	noreplace_paravirt = 1;
-	return 1;
-}
-__setup("noreplace-paravirt", setup_noreplace_paravirt);
-#endif
-
 #define DPRINTK(fmt, args...)						\
 do {									\
 	if (debug_alternative)						\
@@ -339,9 +329,12 @@
 static void __init_or_module optimize_nops(struct alt_instr *a, u8 *instr)
 {
 	unsigned long flags;
+	int i;
 
-	if (instr[0] != 0x90)
-		return;
+	for (i = 0; i < a->padlen; i++) {
+		if (instr[i] != 0x90)
+			return;
+	}
 
 	local_irq_save(flags);
 	add_nops(instr + (a->instrlen - a->padlen), a->padlen);
@@ -584,9 +577,6 @@
 	struct paravirt_patch_site *p;
 	char insnbuf[MAX_PATCH_LEN];
 
-	if (noreplace_paravirt)
-		return;
-
 	for (p = start; p < end; p++) {
 		unsigned int used;
 
--- linux-4.4.0.orig/arch/x86/kernel/amd_gart_64.c
+++ linux-4.4.0/arch/x86/kernel/amd_gart_64.c
@@ -20,7 +20,6 @@
 #include <linux/string.h>
 #include <linux/spinlock.h>
 #include <linux/pci.h>
-#include <linux/module.h>
 #include <linux/topology.h>
 #include <linux/interrupt.h>
 #include <linux/bitmap.h>
--- linux-4.4.0.orig/arch/x86/kernel/amd_nb.c
+++ linux-4.4.0/arch/x86/kernel/amd_nb.c
@@ -9,7 +9,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/errno.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <asm/amd_nb.h>
 
@@ -71,8 +71,8 @@
 	while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
 		i++;
 
-	if (i == 0)
-		return 0;
+	if (!i)
+		return -ENODEV;
 
 	nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
 	if (!nb)
@@ -105,7 +105,7 @@
 	if (boot_cpu_data.x86 == 0x10 &&
 	    boot_cpu_data.x86_model >= 0x8 &&
 	    (boot_cpu_data.x86_model > 0x9 ||
-	     boot_cpu_data.x86_mask >= 0x1))
+	     boot_cpu_data.x86_stepping >= 0x1))
 		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
 
 	if (boot_cpu_data.x86 == 0x15)
--- linux-4.4.0.orig/arch/x86/kernel/aperture_64.c
+++ linux-4.4.0/arch/x86/kernel/aperture_64.c
@@ -91,32 +91,6 @@
 }
 
 
-/* Find a PCI capability */
-static u32 __init find_cap(int bus, int slot, int func, int cap)
-{
-	int bytes;
-	u8 pos;
-
-	if (!(read_pci_config_16(bus, slot, func, PCI_STATUS) &
-						PCI_STATUS_CAP_LIST))
-		return 0;
-
-	pos = read_pci_config_byte(bus, slot, func, PCI_CAPABILITY_LIST);
-	for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
-		u8 id;
-
-		pos &= ~3;
-		id = read_pci_config_byte(bus, slot, func, pos+PCI_CAP_LIST_ID);
-		if (id == 0xff)
-			break;
-		if (id == cap)
-			return pos;
-		pos = read_pci_config_byte(bus, slot, func,
-						pos+PCI_CAP_LIST_NEXT);
-	}
-	return 0;
-}
-
 /* Read a standard AGPv3 bridge header */
 static u32 __init read_agp(int bus, int slot, int func, int cap, u32 *order)
 {
@@ -205,8 +179,8 @@
 				case PCI_CLASS_BRIDGE_HOST:
 				case PCI_CLASS_BRIDGE_OTHER: /* needed? */
 					/* AGP bridge? */
-					cap = find_cap(bus, slot, func,
-							PCI_CAP_ID_AGP);
+					cap = pci_early_find_cap(bus, slot,
+						 func, PCI_CAP_ID_AGP);
 					if (!cap)
 						break;
 					*valid_agp = 1;
--- linux-4.4.0.orig/arch/x86/kernel/apic/apic.c
+++ linux-4.4.0/arch/x86/kernel/apic/apic.c
@@ -23,7 +23,7 @@
 #include <linux/bootmem.h>
 #include <linux/ftrace.h>
 #include <linux/ioport.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscore_ops.h>
 #include <linux/delay.h>
 #include <linux/timex.h>
@@ -41,6 +41,7 @@
 #include <asm/x86_init.h>
 #include <asm/pgalloc.h>
 #include <linux/atomic.h>
+#include <asm/barrier.h>
 #include <asm/mpspec.h>
 #include <asm/i8259.h>
 #include <asm/proto.h>
@@ -55,6 +56,7 @@
 #include <asm/mce.h>
 #include <asm/tsc.h>
 #include <asm/hypervisor.h>
+#include <asm/irq_regs.h>
 
 unsigned int num_processors;
 
@@ -171,7 +173,7 @@
 /*
  * Debug level, exported for io_apic.c
  */
-unsigned int apic_verbosity;
+int apic_verbosity;
 
 int pic_mode;
 
@@ -464,6 +466,9 @@
 {
 	u64 tsc;
 
+	/* This MSR is special and need a special fence: */
+	weak_wrmsr_fence();
+
 	tsc = rdtsc();
 	wrmsrl(MSR_IA32_TSC_DEADLINE, tsc + (((u64) delta) * TSC_DIVISOR));
 	return 0;
@@ -593,7 +598,7 @@
 static __initdata unsigned long lapic_cal_j1, lapic_cal_j2;
 
 /*
- * Temporary interrupt handler.
+ * Temporary interrupt handler and polled calibration function.
  */
 static void __init lapic_cal_handler(struct clock_event_device *dev)
 {
@@ -677,7 +682,8 @@
 static int __init calibrate_APIC_clock(void)
 {
 	struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
-	void (*real_handler)(struct clock_event_device *dev);
+	u64 tsc_perj = 0, tsc_start = 0;
+	unsigned long jif_start;
 	unsigned long deltaj;
 	long delta, deltatsc;
 	int pm_referenced = 0;
@@ -706,28 +712,64 @@
 	apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
 		    "calibrating APIC timer ...\n");
 
+	/*
+	 * There are platforms w/o global clockevent devices. Instead of
+	 * making the calibration conditional on that, use a polling based
+	 * approach everywhere.
+	 */
 	local_irq_disable();
 
-	/* Replace the global interrupt handler */
-	real_handler = global_clock_event->event_handler;
-	global_clock_event->event_handler = lapic_cal_handler;
-
 	/*
 	 * Setup the APIC counter to maximum. There is no way the lapic
 	 * can underflow in the 100ms detection time frame
 	 */
 	__setup_APIC_LVTT(0xffffffff, 0, 0);
 
-	/* Let the interrupts run */
+	/*
+	 * Methods to terminate the calibration loop:
+	 *  1) Global clockevent if available (jiffies)
+	 *  2) TSC if available and frequency is known
+	 */
+	jif_start = READ_ONCE(jiffies);
+
+	if (tsc_khz) {
+		tsc_start = rdtsc();
+		tsc_perj = div_u64((u64)tsc_khz * 1000, HZ);
+	}
+
+	/*
+	 * Enable interrupts so the tick can fire, if a global
+	 * clockevent device is available
+	 */
 	local_irq_enable();
 
-	while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
-		cpu_relax();
+	while (lapic_cal_loops <= LAPIC_CAL_LOOPS) {
+		/* Wait for a tick to elapse */
+		while (1) {
+			if (tsc_khz) {
+				u64 tsc_now = rdtsc();
+				if ((tsc_now - tsc_start) >= tsc_perj) {
+					tsc_start += tsc_perj;
+					break;
+				}
+			} else {
+				unsigned long jif_now = READ_ONCE(jiffies);
 
-	local_irq_disable();
+				if (time_after(jif_now, jif_start)) {
+					jif_start = jif_now;
+					break;
+				}
+			}
+			cpu_relax();
+		}
+
+		/* Invoke the calibration routine */
+		local_irq_disable();
+		lapic_cal_handler(NULL);
+		local_irq_enable();
+	}
 
-	/* Restore the real event handler */
-	global_clock_event->event_handler = real_handler;
+	local_irq_disable();
 
 	/* Build delta t1-t2 as apic timer counts down */
 	delta = lapic_cal_t1 - lapic_cal_t2;
@@ -778,10 +820,11 @@
 	levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
 
 	/*
-	 * PM timer calibration failed or not turned on
-	 * so lets try APIC timer based calibration
+	 * PM timer calibration failed or not turned on so lets try APIC
+	 * timer based calibration, if a global clockevent device is
+	 * available.
 	 */
-	if (!pm_referenced) {
+	if (!pm_referenced && global_clock_event) {
 		apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
 
 		/*
@@ -1227,6 +1270,14 @@
 		return;
 	}
 
+	/*
+	 * If this comes from kexec/kcrash the APIC might be enabled in
+	 * SPIV. Soft disable it before doing further initialization.
+	 */
+	value = apic_read(APIC_SPIV);
+	value &= ~APIC_SPIV_APIC_ENABLED;
+	apic_write(APIC_SPIV, value);
+
 #ifdef CONFIG_X86_32
 	/* Pound the ESR really hard over the head with a big hammer - mbligh */
 	if (lapic_is_integrated() && apic->disable_esr) {
@@ -1252,16 +1303,21 @@
 	apic->init_apic_ldr();
 
 #ifdef CONFIG_X86_32
-	/*
-	 * APIC LDR is initialized.  If logical_apicid mapping was
-	 * initialized during get_smp_config(), make sure it matches the
-	 * actual value.
-	 */
-	i = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
-	WARN_ON(i != BAD_APICID && i != logical_smp_processor_id());
-	/* always use the value from LDR */
-	early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
-		logical_smp_processor_id();
+	if (apic->dest_logical) {
+		int logical_apicid, ldr_apicid;
+
+		/*
+		 * APIC LDR is initialized.  If logical_apicid mapping was
+		 * initialized during get_smp_config(), make sure it matches
+		 * the actual value.
+		 */
+		logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
+		ldr_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
+		if (logical_apicid != BAD_APICID)
+			WARN_ON(logical_apicid != ldr_apicid);
+		/* Always use the value from LDR. */
+		early_per_cpu(x86_cpu_to_logical_apicid, cpu) = ldr_apicid;
+	}
 #endif
 
 	/*
@@ -1368,7 +1424,7 @@
 	 * TODO: set up through-local-APIC from through-I/O-APIC? --macro
 	 */
 	value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
-	if (!cpu && (pic_mode || !value)) {
+	if (!cpu && (pic_mode || !value || skip_ioapic_setup)) {
 		value = APIC_DM_EXTINT;
 		apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", cpu);
 	} else {
@@ -1587,6 +1643,9 @@
 	unsigned long flags;
 	int ret, ir_stat;
 
+	if (skip_ioapic_setup)
+		return;
+
 	ir_stat = irq_remapping_prepare();
 	if (ir_stat < 0 && !x2apic_supported())
 		return;
@@ -1988,6 +2047,21 @@
 	apic_write(APIC_LVT1, value);
 }
 
+/**
+ * apic_id_is_primary_thread - Check whether APIC ID belongs to a primary thread
+ * @id:	APIC ID to check
+ */
+bool apic_id_is_primary_thread(unsigned int apicid)
+{
+	u32 mask;
+
+	if (smp_num_siblings == 1)
+		return true;
+	/* Isolate the SMT bit(s) in the APICID and check for 0 */
+	mask = (1U << (fls(smp_num_siblings) - 1)) - 1;
+	return !(apicid & mask);
+}
+
 int generic_processor_info(int apicid, int version)
 {
 	int cpu, max = nr_cpu_ids;
@@ -2068,6 +2142,20 @@
 		cpu = cpumask_next_zero(-1, cpu_present_mask);
 
 	/*
+	 * This can happen on physical hotplug. The sanity check at boot time
+	 * is done from native_smp_prepare_cpus() after num_possible_cpus() is
+	 * established.
+	 */
+	if (topology_update_package_map(apicid, cpu) < 0) {
+		int thiscpu = max + disabled_cpus;
+
+		pr_warning("ACPI: Package limit reached. Processor %d/0x%x ignored.\n",
+			   thiscpu, apicid);
+		disabled_cpus++;
+		return -ENOSPC;
+	}
+
+	/*
 	 * Validate version
 	 */
 	if (version == 0x0) {
--- linux-4.4.0.orig/arch/x86/kernel/apic/apic_flat_64.c
+++ linux-4.4.0/arch/x86/kernel/apic/apic_flat_64.c
@@ -15,7 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/hardirq.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/smp.h>
 #include <asm/apic.h>
 #include <asm/ipi.h>
--- linux-4.4.0.orig/arch/x86/kernel/apic/apic_noop.c
+++ linux-4.4.0/arch/x86/kernel/apic/apic_noop.c
@@ -11,7 +11,6 @@
 
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
--- linux-4.4.0.orig/arch/x86/kernel/apic/apic_numachip.c
+++ linux-4.4.0/arch/x86/kernel/apic/apic_numachip.c
@@ -30,7 +30,7 @@
 	unsigned long value;
 	unsigned int id = (x >> 24) & 0xff;
 
-	if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+	if (static_cpu_has(X86_FEATURE_NODEID_MSR)) {
 		rdmsrl(MSR_FAM10H_NODE_ID, value);
 		id |= (value << 2) & 0xff00;
 	}
@@ -178,7 +178,7 @@
 	this_cpu_write(cpu_llc_id, node);
 
 	/* Account for nodes per socket in multi-core-module processors */
-	if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+	if (static_cpu_has(X86_FEATURE_NODEID_MSR)) {
 		rdmsrl(MSR_FAM10H_NODE_ID, val);
 		nodes = ((val >> 3) & 7) + 1;
 	}
--- linux-4.4.0.orig/arch/x86/kernel/apic/bigsmp_32.c
+++ linux-4.4.0/arch/x86/kernel/apic/bigsmp_32.c
@@ -37,32 +37,12 @@
 	return early_per_cpu(x86_cpu_to_apicid, cpu);
 }
 
-static inline unsigned long calculate_ldr(int cpu)
-{
-	unsigned long val, id;
-
-	val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
-	id = per_cpu(x86_bios_cpu_apicid, cpu);
-	val |= SET_APIC_LOGICAL_ID(id);
-
-	return val;
-}
-
 /*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LDR and TPR before enabling
- * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116).  So here it goes...
+ * bigsmp enables physical destination mode
+ * and doesn't use LDR and DFR
  */
 static void bigsmp_init_apic_ldr(void)
 {
-	unsigned long val;
-	int cpu = smp_processor_id();
-
-	apic_write(APIC_DFR, APIC_DFR_FLAT);
-	val = calculate_ldr(cpu);
-	apic_write(APIC_LDR, val);
 }
 
 static void bigsmp_setup_apic_routing(void)
--- linux-4.4.0.orig/arch/x86/kernel/apic/htirq.c
+++ linux-4.4.0/arch/x86/kernel/apic/htirq.c
@@ -12,6 +12,7 @@
  */
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/pci.h>
--- linux-4.4.0.orig/arch/x86/kernel/apic/hw_nmi.c
+++ linux-4.4.0/arch/x86/kernel/apic/hw_nmi.c
@@ -16,7 +16,7 @@
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/nmi.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/seq_buf.h>
 
--- linux-4.4.0.orig/arch/x86/kernel/apic/io_apic.c
+++ linux-4.4.0/arch/x86/kernel/apic/io_apic.c
@@ -32,6 +32,7 @@
 
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
@@ -39,7 +40,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/compiler.h>
 #include <linux/acpi.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscore_ops.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
@@ -369,27 +370,26 @@
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static int __add_pin_to_irq_node(struct mp_chip_data *data,
-				 int node, int apic, int pin)
+static bool add_pin_to_irq_node(struct mp_chip_data *data, int node, int apic, int pin)
 {
 	struct irq_pin_list *entry;
 
-	/* don't allow duplicates */
-	for_each_irq_pin(entry, data->irq_2_pin)
+	/* Don't allow duplicates */
+	for_each_irq_pin(entry, data->irq_2_pin) {
 		if (entry->apic == apic && entry->pin == pin)
-			return 0;
+			return true;
+	}
 
 	entry = kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node);
 	if (!entry) {
-		pr_err("can not alloc irq_pin_list (%d,%d,%d)\n",
-		       node, apic, pin);
-		return -ENOMEM;
+		pr_err("Cannot allocate irq_pin_list (%d,%d,%d)\n", node, apic, pin);
+		return false;
 	}
+
 	entry->apic = apic;
 	entry->pin = pin;
 	list_add_tail(&entry->list, &data->irq_2_pin);
-
-	return 0;
+	return true;
 }
 
 static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
@@ -404,13 +404,6 @@
 		}
 }
 
-static void add_pin_to_irq_node(struct mp_chip_data *data,
-				int node, int apic, int pin)
-{
-	if (__add_pin_to_irq_node(data, node, apic, pin))
-		panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
-}
-
 /*
  * Reroute an IRQ to a different pin.
  */
@@ -1010,8 +1003,7 @@
 	if (irq_data && irq_data->parent_data) {
 		if (!mp_check_pin_attr(irq, info))
 			return -EBUSY;
-		if (__add_pin_to_irq_node(irq_data->chip_data, node, ioapic,
-					  info->ioapic_pin))
+		if (!add_pin_to_irq_node(irq_data->chip_data, node, ioapic, info->ioapic_pin))
 			return -ENOMEM;
 	} else {
 		irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true);
@@ -1710,9 +1702,10 @@
 
 static inline bool ioapic_irqd_mask(struct irq_data *data)
 {
-	/* If we are moving the irq we need to mask it */
+	/* If we are moving the IRQ we need to mask it */
 	if (unlikely(irqd_is_setaffinity_pending(data))) {
-		mask_ioapic_irq(data);
+		if (!irqd_irq_masked(data))
+			mask_ioapic_irq(data);
 		return true;
 	}
 	return false;
@@ -1749,7 +1742,9 @@
 		 */
 		if (!io_apic_level_ack_pending(data->chip_data))
 			irq_move_masked_irq(data);
-		unmask_ioapic_irq(data);
+		/* If the IRQ is masked in the core, leave it: */
+		if (!irqd_irq_masked(data))
+			unmask_ioapic_irq(data);
 	}
 }
 #else
@@ -1875,6 +1870,7 @@
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_eoi		= ioapic_ack_level,
 	.irq_set_affinity	= ioapic_set_affinity,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.flags			= IRQCHIP_SKIP_SET_WAKE,
 };
 
@@ -1886,6 +1882,7 @@
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_eoi		= ioapic_ir_ack_level,
 	.irq_set_affinity	= ioapic_set_affinity,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.flags			= IRQCHIP_SKIP_SET_WAKE,
 };
 
@@ -2113,8 +2110,9 @@
 			int idx;
 			idx = find_irq_entry(apic1, pin1, mp_INT);
 			if (idx != -1 && irq_trigger(idx))
-				unmask_ioapic_irq(irq_get_chip_data(0));
+				unmask_ioapic_irq(irq_get_irq_data(0));
 		}
+		irq_domain_deactivate_irq(irq_data);
 		irq_domain_activate_irq(irq_data);
 		if (timer_irq_works()) {
 			if (disable_timer_pin_1 > 0)
@@ -2136,6 +2134,7 @@
 		 * legacy devices should be connected to IO APIC #0
 		 */
 		replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
+		irq_domain_deactivate_irq(irq_data);
 		irq_domain_activate_irq(irq_data);
 		legacy_pic->unmask(0);
 		if (timer_irq_works()) {
@@ -2340,7 +2339,13 @@
 	 * dmar_alloc_hwirq() may be called before setup_IO_APIC(), so use
 	 * gsi_top if ioapic_dynirq_base hasn't been initialized yet.
 	 */
-	return ioapic_initialized ? ioapic_dynirq_base : gsi_top;
+	if (!ioapic_initialized)
+		return gsi_top;
+	/*
+	 * For DT enabled machines ioapic_dynirq_base is irrelevant and not
+	 * updated. So simply return @from if ioapic_dynirq_base == 0.
+	 */
+	return ioapic_dynirq_base ? : from;
 }
 
 #ifdef CONFIG_X86_32
@@ -2521,6 +2526,7 @@
 {
 	int pin, ioapic, irq, irq_entry;
 	const struct cpumask *mask;
+	struct irq_desc *desc;
 	struct irq_data *idata;
 	struct irq_chip *chip;
 
@@ -2536,7 +2542,9 @@
 		if (irq < 0 || !mp_init_irq_at_boot(ioapic, irq))
 			continue;
 
-		idata = irq_get_irq_data(irq);
+		desc = irq_to_desc(irq);
+		raw_spin_lock_irq(&desc->lock);
+		idata = irq_desc_get_irq_data(desc);
 
 		/*
 		 * Honour affinities which have been set in early boot
@@ -2550,6 +2558,7 @@
 		/* Might be lapic_chip for irq 0 */
 		if (chip->irq_set_affinity)
 			chip->irq_set_affinity(idata, mask, false);
+		raw_spin_unlock_irq(&desc->lock);
 	}
 }
 #endif
@@ -2584,8 +2593,8 @@
 		res[num].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 		snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);
 		mem += IOAPIC_RESOURCE_NAME_SIZE;
+		ioapics[i].iomem_res = &res[num];
 		num++;
-		ioapics[i].iomem_res = res;
 	}
 
 	ioapic_resources = res;
@@ -2928,10 +2937,8 @@
 
 	info->ioapic_entry = &data->entry;
 	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
-	if (ret < 0) {
-		kfree(data);
-		return ret;
-	}
+	if (ret < 0)
+		goto free_data;
 
 	INIT_LIST_HEAD(&data->irq_2_pin);
 	irq_data->hwirq = info->ioapic_pin;
@@ -2941,7 +2948,10 @@
 	mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
 
 	cfg = irqd_cfg(irq_data);
-	add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
+	if (!add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin)) {
+		ret = -ENOMEM;
+		goto free_irqs;
+	}
 
 	local_irq_save(flags);
 	if (info->ioapic_entry)
@@ -2957,6 +2967,12 @@
 		    virq, data->trigger, data->polarity, cfg->dest_apicid);
 
 	return 0;
+
+free_irqs:
+	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+free_data:
+	kfree(data);
+	return ret;
 }
 
 void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
--- linux-4.4.0.orig/arch/x86/kernel/apic/ipi.c
+++ linux-4.4.0/arch/x86/kernel/apic/ipi.c
@@ -8,7 +8,6 @@
 #include <linux/mc146818rtc.h>
 #include <linux/cache.h>
 #include <linux/cpu.h>
-#include <linux/module.h>
 
 #include <asm/smp.h>
 #include <asm/mtrr.h>
--- linux-4.4.0.orig/arch/x86/kernel/apic/msi.c
+++ linux-4.4.0/arch/x86/kernel/apic/msi.c
@@ -12,6 +12,7 @@
  */
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/dmar.h>
 #include <linux/hpet.h>
@@ -96,8 +97,8 @@
 	return arg->msi_hwirq;
 }
 
-static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
-			   int nvec, msi_alloc_info_t *arg)
+int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
+		    msi_alloc_info_t *arg)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct msi_desc *desc = first_pci_msi_entry(pdev);
@@ -113,11 +114,13 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(pci_msi_prepare);
 
-static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
 {
 	arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
 }
+EXPORT_SYMBOL_GPL(pci_msi_set_desc);
 
 static struct msi_domain_ops pci_msi_domain_ops = {
 	.get_hwirq	= pci_msi_get_hwirq,
--- linux-4.4.0.orig/arch/x86/kernel/apic/probe_32.c
+++ linux-4.4.0/arch/x86/kernel/apic/probe_32.c
@@ -8,7 +8,7 @@
  */
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
--- linux-4.4.0.orig/arch/x86/kernel/apic/probe_64.c
+++ linux-4.4.0/arch/x86/kernel/apic/probe_64.c
@@ -11,7 +11,7 @@
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/string.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/init.h>
--- linux-4.4.0.orig/arch/x86/kernel/apic/vector.c
+++ linux-4.4.0/arch/x86/kernel/apic/vector.c
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/init.h>
 #include <linux/compiler.h>
 #include <linux/slab.h>
@@ -29,8 +30,9 @@
 };
 
 struct irq_domain *x86_vector_domain;
+EXPORT_SYMBOL_GPL(x86_vector_domain);
 static DEFINE_RAW_SPINLOCK(vector_lock);
-static cpumask_var_t vector_cpumask;
+static cpumask_var_t vector_cpumask, vector_searchmask, searched_cpumask;
 static struct irq_chip lapic_controller;
 #ifdef	CONFIG_X86_IO_APIC
 static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
@@ -66,6 +68,7 @@
 
 	return data ? &data->cfg : NULL;
 }
+EXPORT_SYMBOL_GPL(irqd_cfg);
 
 struct irq_cfg *irq_cfg(unsigned int irq)
 {
@@ -91,8 +94,12 @@
 	return NULL;
 }
 
-static void free_apic_chip_data(struct apic_chip_data *data)
+static void free_apic_chip_data(unsigned int virq, struct apic_chip_data *data)
 {
+#ifdef	CONFIG_X86_IO_APIC
+	if (virq  < nr_legacy_irqs())
+		legacy_irq_data[virq] = NULL;
+#endif
 	if (data) {
 		free_cpumask_var(data->domain);
 		free_cpumask_var(data->old_domain);
@@ -116,35 +123,47 @@
 	 */
 	static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
 	static int current_offset = VECTOR_OFFSET_START % 16;
-	int cpu, err;
+	int cpu, vector;
 
-	if (d->move_in_progress)
+	/*
+	 * If there is still a move in progress or the previous move has not
+	 * been cleaned up completely, tell the caller to come back later.
+	 */
+	if (d->move_in_progress ||
+	    cpumask_intersects(d->old_domain, cpu_online_mask))
 		return -EBUSY;
 
 	/* Only try and allocate irqs on cpus that are present */
-	err = -ENOSPC;
 	cpumask_clear(d->old_domain);
+	cpumask_clear(searched_cpumask);
 	cpu = cpumask_first_and(mask, cpu_online_mask);
 	while (cpu < nr_cpu_ids) {
-		int new_cpu, vector, offset;
+		int new_cpu, offset;
 
+		/* Get the possible target cpus for @mask/@cpu from the apic */
 		apic->vector_allocation_domain(cpu, vector_cpumask, mask);
 
+		/*
+		 * Clear the offline cpus from @vector_cpumask for searching
+		 * and verify whether the result overlaps with @mask. If true,
+		 * then the call to apic->cpu_mask_to_apicid_and() will
+		 * succeed as well. If not, no point in trying to find a
+		 * vector in this mask.
+		 */
+		cpumask_and(vector_searchmask, vector_cpumask, cpu_online_mask);
+		if (!cpumask_intersects(vector_searchmask, mask))
+			goto next_cpu;
+
 		if (cpumask_subset(vector_cpumask, d->domain)) {
-			err = 0;
 			if (cpumask_equal(vector_cpumask, d->domain))
-				break;
+				goto success;
 			/*
-			 * New cpumask using the vector is a proper subset of
-			 * the current in use mask. So cleanup the vector
-			 * allocation for the members that are not used anymore.
+			 * Mark the cpus which are not longer in the mask for
+			 * cleanup.
 			 */
-			cpumask_andnot(d->old_domain, d->domain,
-				       vector_cpumask);
-			d->move_in_progress =
-			   cpumask_intersects(d->old_domain, cpu_online_mask);
-			cpumask_and(d->domain, d->domain, vector_cpumask);
-			break;
+			cpumask_andnot(d->old_domain, d->domain, vector_cpumask);
+			vector = d->cfg.vector;
+			goto update;
 		}
 
 		vector = current_vector;
@@ -156,45 +175,61 @@
 			vector = FIRST_EXTERNAL_VECTOR + offset;
 		}
 
-		if (unlikely(current_vector == vector)) {
-			cpumask_or(d->old_domain, d->old_domain,
-				   vector_cpumask);
-			cpumask_andnot(vector_cpumask, mask, d->old_domain);
-			cpu = cpumask_first_and(vector_cpumask,
-						cpu_online_mask);
-			continue;
-		}
+		/* If the search wrapped around, try the next cpu */
+		if (unlikely(current_vector == vector))
+			goto next_cpu;
 
 		if (test_bit(vector, used_vectors))
 			goto next;
 
-		for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) {
+		for_each_cpu(new_cpu, vector_searchmask) {
 			if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector]))
 				goto next;
 		}
 		/* Found one! */
 		current_vector = vector;
 		current_offset = offset;
-		if (d->cfg.vector) {
+		/* Schedule the old vector for cleanup on all cpus */
+		if (d->cfg.vector)
 			cpumask_copy(d->old_domain, d->domain);
-			d->move_in_progress =
-			   cpumask_intersects(d->old_domain, cpu_online_mask);
-		}
-		for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask)
+		for_each_cpu(new_cpu, vector_searchmask)
 			per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq);
-		d->cfg.vector = vector;
-		cpumask_copy(d->domain, vector_cpumask);
-		err = 0;
-		break;
-	}
+		goto update;
 
-	if (!err) {
-		/* cache destination APIC IDs into cfg->dest_apicid */
-		err = apic->cpu_mask_to_apicid_and(mask, d->domain,
-						   &d->cfg.dest_apicid);
+next_cpu:
+		/*
+		 * We exclude the current @vector_cpumask from the requested
+		 * @mask and try again with the next online cpu in the
+		 * result. We cannot modify @mask, so we use @vector_cpumask
+		 * as a temporary buffer here as it will be reassigned when
+		 * calling apic->vector_allocation_domain() above.
+		 */
+		cpumask_or(searched_cpumask, searched_cpumask, vector_cpumask);
+		cpumask_andnot(vector_cpumask, mask, searched_cpumask);
+		cpu = cpumask_first_and(vector_cpumask, cpu_online_mask);
+		continue;
 	}
+	return -ENOSPC;
 
-	return err;
+update:
+	/*
+	 * Exclude offline cpus from the cleanup mask and set the
+	 * move_in_progress flag when the result is not empty.
+	 */
+	cpumask_and(d->old_domain, d->old_domain, cpu_online_mask);
+	d->move_in_progress = !cpumask_empty(d->old_domain);
+	d->cfg.old_vector = d->move_in_progress ? d->cfg.vector : 0;
+	d->cfg.vector = vector;
+	cpumask_copy(d->domain, vector_cpumask);
+success:
+	/*
+	 * Cache destination APIC IDs into cfg->dest_apicid. This cannot fail
+	 * as we already established, that mask & d->domain & cpu_online_mask
+	 * is not empty.
+	 */
+	BUG_ON(apic->cpu_mask_to_apicid_and(mask, d->domain,
+					    &d->cfg.dest_apicid));
+	return 0;
 }
 
 static int assign_irq_vector(int irq, struct apic_chip_data *data,
@@ -224,11 +259,10 @@
 static void clear_irq_vector(int irq, struct apic_chip_data *data)
 {
 	struct irq_desc *desc;
-	unsigned long flags;
 	int cpu, vector;
 
-	raw_spin_lock_irqsave(&vector_lock, flags);
-	BUG_ON(!data->cfg.vector);
+	if (!data->cfg.vector)
+		return;
 
 	vector = data->cfg.vector;
 	for_each_cpu_and(cpu, data->domain, cpu_online_mask)
@@ -237,10 +271,13 @@
 	data->cfg.vector = 0;
 	cpumask_clear(data->domain);
 
-	if (likely(!data->move_in_progress)) {
-		raw_spin_unlock_irqrestore(&vector_lock, flags);
+	/*
+	 * If move is in progress or the old_domain mask is not empty,
+	 * i.e. the cleanup IPI has not been processed yet, we need to remove
+	 * the old references to desc from all cpus vector tables.
+	 */
+	if (!data->move_in_progress && cpumask_empty(data->old_domain))
 		return;
-	}
 
 	desc = irq_to_desc(irq);
 	for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
@@ -253,7 +290,6 @@
 		}
 	}
 	data->move_in_progress = 0;
-	raw_spin_unlock_irqrestore(&vector_lock, flags);
 }
 
 void init_irq_alloc_info(struct irq_alloc_info *info,
@@ -274,19 +310,20 @@
 static void x86_vector_free_irqs(struct irq_domain *domain,
 				 unsigned int virq, unsigned int nr_irqs)
 {
+	struct apic_chip_data *apic_data;
 	struct irq_data *irq_data;
+	unsigned long flags;
 	int i;
 
 	for (i = 0; i < nr_irqs; i++) {
 		irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i);
 		if (irq_data && irq_data->chip_data) {
+			raw_spin_lock_irqsave(&vector_lock, flags);
 			clear_irq_vector(virq + i, irq_data->chip_data);
-			free_apic_chip_data(irq_data->chip_data);
-#ifdef	CONFIG_X86_IO_APIC
-			if (virq + i < nr_legacy_irqs())
-				legacy_irq_data[virq + i] = NULL;
-#endif
+			apic_data = irq_data->chip_data;
 			irq_domain_reset_irq_data(irq_data);
+			raw_spin_unlock_irqrestore(&vector_lock, flags);
+			free_apic_chip_data(virq + i, apic_data);
 		}
 	}
 }
@@ -325,14 +362,17 @@
 		irq_data->chip_data = data;
 		irq_data->hwirq = virq + i;
 		err = assign_irq_vector_policy(virq + i, node, data, info);
-		if (err)
+		if (err) {
+			irq_data->chip_data = NULL;
+			free_apic_chip_data(virq + i, data);
 			goto error;
+		}
 	}
 
 	return 0;
 
 error:
-	x86_vector_free_irqs(domain, virq, i + 1);
+	x86_vector_free_irqs(domain, virq, i);
 	return err;
 }
 
@@ -404,6 +444,8 @@
 	arch_init_htirq_domain(x86_vector_domain);
 
 	BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL));
+	BUG_ON(!alloc_cpumask_var(&vector_searchmask, GFP_KERNEL));
+	BUG_ON(!alloc_cpumask_var(&searched_cpumask, GFP_KERNEL));
 
 	return arch_early_ioapic_init();
 }
@@ -492,14 +534,7 @@
 		return -EINVAL;
 
 	err = assign_irq_vector(irq, data, dest);
-	if (err) {
-		if (assign_irq_vector(irq, data,
-				      irq_data_get_affinity_mask(irq_data)))
-			pr_err("Failed to recover vector for irq %d\n", irq);
-		return err;
-	}
-
-	return IRQ_SET_MASK_OK;
+	return err ? err : IRQ_SET_MASK_OK;
 }
 
 static struct irq_chip lapic_controller = {
@@ -511,20 +546,12 @@
 #ifdef CONFIG_SMP
 static void __send_cleanup_vector(struct apic_chip_data *data)
 {
-	cpumask_var_t cleanup_mask;
-
-	if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
-		unsigned int i;
-
-		for_each_cpu_and(i, data->old_domain, cpu_online_mask)
-			apic->send_IPI_mask(cpumask_of(i),
-					    IRQ_MOVE_CLEANUP_VECTOR);
-	} else {
-		cpumask_and(cleanup_mask, data->old_domain, cpu_online_mask);
-		apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
-		free_cpumask_var(cleanup_mask);
-	}
+	raw_spin_lock(&vector_lock);
+	cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
 	data->move_in_progress = 0;
+	if (!cpumask_empty(data->old_domain))
+		apic->send_IPI_mask(data->old_domain, IRQ_MOVE_CLEANUP_VECTOR);
+	raw_spin_unlock(&vector_lock);
 }
 
 void send_cleanup_vector(struct irq_cfg *cfg)
@@ -568,12 +595,25 @@
 			goto unlock;
 
 		/*
-		 * Check if the irq migration is in progress. If so, we
-		 * haven't received the cleanup request yet for this irq.
+		 * Nothing to cleanup if irq migration is in progress
+		 * or this cpu is not set in the cleanup mask.
 		 */
-		if (data->move_in_progress)
+		if (data->move_in_progress ||
+		    !cpumask_test_cpu(me, data->old_domain))
 			goto unlock;
 
+		/*
+		 * We have two cases to handle here:
+		 * 1) vector is unchanged but the target mask got reduced
+		 * 2) vector and the target mask has changed
+		 *
+		 * #1 is obvious, but in #2 we have two vectors with the same
+		 * irq descriptor: the old and the new vector. So we need to
+		 * make sure that we only cleanup the old vector. The new
+		 * vector has the current @vector number in the config and
+		 * this cpu is part of the target mask. We better leave that
+		 * one alone.
+		 */
 		if (vector == data->cfg.vector &&
 		    cpumask_test_cpu(me, data->domain))
 			goto unlock;
@@ -591,6 +631,7 @@
 			goto unlock;
 		}
 		__this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
+		cpumask_clear_cpu(me, data->old_domain);
 unlock:
 		raw_spin_unlock(&desc->lock);
 	}
@@ -619,12 +660,116 @@
 	__irq_complete_move(cfg, ~get_irq_regs()->orig_ax);
 }
 
-void irq_force_complete_move(int irq)
+/*
+ * Called from fixup_irqs() with @desc->lock held and interrupts disabled.
+ */
+void irq_force_complete_move(struct irq_desc *desc)
 {
-	struct irq_cfg *cfg = irq_cfg(irq);
+	struct irq_data *irqdata;
+	struct apic_chip_data *data;
+	struct irq_cfg *cfg;
+	unsigned int cpu;
 
-	if (cfg)
-		__irq_complete_move(cfg, cfg->vector);
+	/*
+	 * The function is called for all descriptors regardless of which
+	 * irqdomain they belong to. For example if an IRQ is provided by
+	 * an irq_chip as part of a GPIO driver, the chip data for that
+	 * descriptor is specific to the irq_chip in question.
+	 *
+	 * Check first that the chip_data is what we expect
+	 * (apic_chip_data) before touching it any further.
+	 */
+	irqdata = irq_domain_get_irq_data(x86_vector_domain,
+					  irq_desc_get_irq(desc));
+	if (!irqdata)
+		return;
+
+	data = apic_chip_data(irqdata);
+	cfg = data ? &data->cfg : NULL;
+
+	if (!cfg)
+		return;
+
+	/*
+	 * This is tricky. If the cleanup of @data->old_domain has not been
+	 * done yet, then the following setaffinity call will fail with
+	 * -EBUSY. This can leave the interrupt in a stale state.
+	 *
+	 * All CPUs are stuck in stop machine with interrupts disabled so
+	 * calling __irq_complete_move() would be completely pointless.
+	 */
+	raw_spin_lock(&vector_lock);
+	/*
+	 * Clean out all offline cpus (including the outgoing one) from the
+	 * old_domain mask.
+	 */
+	cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
+
+	/*
+	 * If move_in_progress is cleared and the old_domain mask is empty,
+	 * then there is nothing to cleanup. fixup_irqs() will take care of
+	 * the stale vectors on the outgoing cpu.
+	 */
+	if (!data->move_in_progress && cpumask_empty(data->old_domain)) {
+		raw_spin_unlock(&vector_lock);
+		return;
+	}
+
+	/*
+	 * 1) The interrupt is in move_in_progress state. That means that we
+	 *    have not seen an interrupt since the io_apic was reprogrammed to
+	 *    the new vector.
+	 *
+	 * 2) The interrupt has fired on the new vector, but the cleanup IPIs
+	 *    have not been processed yet.
+	 */
+	if (data->move_in_progress) {
+		/*
+		 * In theory there is a race:
+		 *
+		 * set_ioapic(new_vector) <-- Interrupt is raised before update
+		 *			      is effective, i.e. it's raised on
+		 *			      the old vector.
+		 *
+		 * So if the target cpu cannot handle that interrupt before
+		 * the old vector is cleaned up, we get a spurious interrupt
+		 * and in the worst case the ioapic irq line becomes stale.
+		 *
+		 * But in case of cpu hotplug this should be a non issue
+		 * because if the affinity update happens right before all
+		 * cpus rendevouz in stop machine, there is no way that the
+		 * interrupt can be blocked on the target cpu because all cpus
+		 * loops first with interrupts enabled in stop machine, so the
+		 * old vector is not yet cleaned up when the interrupt fires.
+		 *
+		 * So the only way to run into this issue is if the delivery
+		 * of the interrupt on the apic/system bus would be delayed
+		 * beyond the point where the target cpu disables interrupts
+		 * in stop machine. I doubt that it can happen, but at least
+		 * there is a theroretical chance. Virtualization might be
+		 * able to expose this, but AFAICT the IOAPIC emulation is not
+		 * as stupid as the real hardware.
+		 *
+		 * Anyway, there is nothing we can do about that at this point
+		 * w/o refactoring the whole fixup_irq() business completely.
+		 * We print at least the irq number and the old vector number,
+		 * so we have the necessary information when a problem in that
+		 * area arises.
+		 */
+		pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n",
+			irqdata->irq, cfg->old_vector);
+	}
+	/*
+	 * If old_domain is not empty, then other cpus still have the irq
+	 * descriptor set in their vector array. Clean it up.
+	 */
+	for_each_cpu(cpu, data->old_domain)
+		per_cpu(vector_irq, cpu)[cfg->old_vector] = VECTOR_UNUSED;
+
+	/* Cleanup the left overs of the (half finished) move */
+	cpumask_clear(data->old_domain);
+	data->move_in_progress = 0;
+	raw_spin_unlock(&vector_lock);
 }
 #endif
 
--- linux-4.4.0.orig/arch/x86/kernel/apic/x2apic_cluster.c
+++ linux-4.4.0/arch/x86/kernel/apic/x2apic_cluster.c
@@ -32,7 +32,8 @@
 	unsigned long flags;
 	u32 dest;
 
-	x2apic_wrmsr_fence();
+	/* x2apic MSRs are special and need a special fence: */
+	weak_wrmsr_fence();
 
 	local_irq_save(flags);
 
--- linux-4.4.0.orig/arch/x86/kernel/apic/x2apic_phys.c
+++ linux-4.4.0/arch/x86/kernel/apic/x2apic_phys.c
@@ -43,7 +43,8 @@
 	unsigned long this_cpu;
 	unsigned long flags;
 
-	x2apic_wrmsr_fence();
+	/* x2apic MSRs are special and need a special fence: */
+	weak_wrmsr_fence();
 
 	local_irq_save(flags);
 
--- linux-4.4.0.orig/arch/x86/kernel/apic/x2apic_uv_x.c
+++ linux-4.4.0/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -12,7 +12,7 @@
 #include <linux/proc_fs.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/sched.h>
@@ -648,9 +648,9 @@
 				l = li;
 			}
 			addr1 = (base << shift) +
-				f * (unsigned long)(1 << m_io);
+				f * (1ULL << m_io);
 			addr2 = (base << shift) +
-				(l + 1) * (unsigned long)(1 << m_io);
+				(l + 1) * (1ULL << m_io);
 			pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx - 0x%016lx\n",
 				id, fi, li, lnasid, addr1, addr2);
 			if (max_io < l)
--- linux-4.4.0.orig/arch/x86/kernel/apm_32.c
+++ linux-4.4.0/arch/x86/kernel/apm_32.c
@@ -239,6 +239,7 @@
 #include <asm/olpc.h>
 #include <asm/paravirt.h>
 #include <asm/reboot.h>
+#include <asm/nospec-branch.h>
 
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 extern int (*console_blank_hook)(int);
@@ -613,11 +614,13 @@
 	gdt[0x40 / 8] = bad_bios_desc;
 
 	apm_irq_save(flags);
+	firmware_restrict_branch_speculation_start();
 	APM_DO_SAVE_SEGS;
 	apm_bios_call_asm(call->func, call->ebx, call->ecx,
 			  &call->eax, &call->ebx, &call->ecx, &call->edx,
 			  &call->esi);
 	APM_DO_RESTORE_SEGS;
+	firmware_restrict_branch_speculation_end();
 	apm_irq_restore(flags);
 	gdt[0x40 / 8] = save_desc_40;
 	put_cpu();
@@ -689,10 +692,12 @@
 	gdt[0x40 / 8] = bad_bios_desc;
 
 	apm_irq_save(flags);
+	firmware_restrict_branch_speculation_start();
 	APM_DO_SAVE_SEGS;
 	error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
 					 &call->eax);
 	APM_DO_RESTORE_SEGS;
+	firmware_restrict_branch_speculation_end();
 	apm_irq_restore(flags);
 	gdt[0x40 / 8] = save_desc_40;
 	put_cpu();
--- linux-4.4.0.orig/arch/x86/kernel/asm-offsets.c
+++ linux-4.4.0/arch/x86/kernel/asm-offsets.c
@@ -65,9 +65,6 @@
 	OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
 	OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
 	OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
-#ifdef CONFIG_X86_32
-	OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
-#endif
 	OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0);
 	OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
 #endif
--- linux-4.4.0.orig/arch/x86/kernel/asm-offsets_32.c
+++ linux-4.4.0/arch/x86/kernel/asm-offsets_32.c
@@ -20,7 +20,7 @@
 	OFFSET(CPUINFO_x86, cpuinfo_x86, x86);
 	OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor);
 	OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model);
-	OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask);
+	OFFSET(CPUINFO_x86_stepping, cpuinfo_x86, x86_stepping);
 	OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level);
 	OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability);
 	OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
--- linux-4.4.0.orig/arch/x86/kernel/check.c
+++ linux-4.4.0/arch/x86/kernel/check.c
@@ -30,6 +30,11 @@
 	ssize_t ret;
 	unsigned long val;
 
+	if (!arg) {
+		pr_err("memory_corruption_check config string not provided\n");
+		return -EINVAL;
+	}
+
 	ret = kstrtoul(arg, 10, &val);
 	if (ret)
 		return ret;
@@ -44,6 +49,11 @@
 	ssize_t ret;
 	unsigned long val;
 
+	if (!arg) {
+		pr_err("memory_corruption_check_period config string not provided\n");
+		return -EINVAL;
+	}
+
 	ret = kstrtoul(arg, 10, &val);
 	if (ret)
 		return ret;
@@ -58,6 +68,11 @@
 	char *end;
 	unsigned size;
 
+	if (!arg) {
+		pr_err("memory_corruption_check_size config string not provided\n");
+		return -EINVAL;
+	}
+
 	size = memparse(arg, &end);
 
 	if (*end == '\0')
--- linux-4.4.0.orig/arch/x86/kernel/cpu/Makefile
+++ linux-4.4.0/arch/x86/kernel/cpu/Makefile
@@ -16,47 +16,23 @@
 obj-y			+= common.o
 obj-y			+= rdrand.o
 obj-y			+= match.o
+obj-y			+= bugs.o
 
 obj-$(CONFIG_PROC_FS)	+= proc.o
 obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
 
-obj-$(CONFIG_X86_32)	+= bugs.o
-obj-$(CONFIG_X86_64)	+= bugs_64.o
-
-obj-$(CONFIG_CPU_SUP_INTEL)		+= intel.o
+obj-$(CONFIG_CPU_SUP_INTEL)		+= intel.o tsx.o
 obj-$(CONFIG_CPU_SUP_AMD)		+= amd.o
 obj-$(CONFIG_CPU_SUP_CYRIX_32)		+= cyrix.o
 obj-$(CONFIG_CPU_SUP_CENTAUR)		+= centaur.o
 obj-$(CONFIG_CPU_SUP_TRANSMETA_32)	+= transmeta.o
 obj-$(CONFIG_CPU_SUP_UMC_32)		+= umc.o
 
-obj-$(CONFIG_PERF_EVENTS)		+= perf_event.o
-
-ifdef CONFIG_PERF_EVENTS
-obj-$(CONFIG_CPU_SUP_AMD)		+= perf_event_amd.o perf_event_amd_uncore.o
-ifdef CONFIG_AMD_IOMMU
-obj-$(CONFIG_CPU_SUP_AMD)		+= perf_event_amd_iommu.o
-endif
-obj-$(CONFIG_CPU_SUP_INTEL)		+= perf_event_p6.o perf_event_knc.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_rapl.o perf_event_intel_cqm.o
-obj-$(CONFIG_CPU_SUP_INTEL)		+= perf_event_intel_pt.o perf_event_intel_bts.o
-obj-$(CONFIG_CPU_SUP_INTEL)		+= perf_event_intel_cstate.o
-
-obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE)	+= perf_event_intel_uncore.o \
-					   perf_event_intel_uncore_snb.o \
-					   perf_event_intel_uncore_snbep.o \
-					   perf_event_intel_uncore_nhmex.o
-obj-$(CONFIG_CPU_SUP_INTEL)		+= perf_event_msr.o
-obj-$(CONFIG_CPU_SUP_AMD)		+= perf_event_msr.o
-endif
-
-
 obj-$(CONFIG_X86_MCE)			+= mcheck/
 obj-$(CONFIG_MTRR)			+= mtrr/
 obj-$(CONFIG_MICROCODE)			+= microcode/
 
-obj-$(CONFIG_X86_LOCAL_APIC)		+= perfctr-watchdog.o perf_event_amd_ibs.o
+obj-$(CONFIG_X86_LOCAL_APIC)		+= perfctr-watchdog.o
 
 obj-$(CONFIG_HYPERVISOR_GUEST)		+= vmware.o hypervisor.o mshyperv.o
 
@@ -64,7 +40,7 @@
 quiet_cmd_mkcapflags = MKCAP   $@
       cmd_mkcapflags = $(CONFIG_SHELL) $(srctree)/$(src)/mkcapflags.sh $< $@
 
-cpufeature = $(src)/../../include/asm/cpufeature.h
+cpufeature = $(src)/../../include/asm/cpufeatures.h
 
 targets += capflags.c
 $(obj)/capflags.c: $(cpufeature) $(src)/mkcapflags.sh FORCE
--- linux-4.4.0.orig/arch/x86/kernel/cpu/amd.c
+++ linux-4.4.0/arch/x86/kernel/cpu/amd.c
@@ -9,6 +9,7 @@
 #include <asm/processor.h>
 #include <asm/apic.h>
 #include <asm/cpu.h>
+#include <asm/spec-ctrl.h>
 #include <asm/smp.h>
 #include <asm/pci-direct.h>
 #include <asm/delay.h>
@@ -20,6 +21,9 @@
 
 #include "cpu.h"
 
+/* "noibpb" commandline parameter present (1) or not (0) */
+extern unsigned int noibpb;
+
 /*
  * nodes_per_socket: Stores the number of nodes per socket.
  * Refer to Fam15h Models 00-0fh BKDG - CPUID Fn8000_001E_ECX
@@ -27,6 +31,78 @@
  */
 static u32 nodes_per_socket = 1;
 
+/*
+ * AMD errata checking
+ *
+ * Errata are defined as arrays of ints using the AMD_LEGACY_ERRATUM() or
+ * AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
+ * have an OSVW id assigned, which it takes as first argument. Both take a
+ * variable number of family-specific model-stepping ranges created by
+ * AMD_MODEL_RANGE().
+ *
+ * Example:
+ *
+ * const int amd_erratum_319[] =
+ *	AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2),
+ *			   AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0),
+ *			   AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
+ */
+
+#define AMD_LEGACY_ERRATUM(...)		{ -1, __VA_ARGS__, 0 }
+#define AMD_OSVW_ERRATUM(osvw_id, ...)	{ osvw_id, __VA_ARGS__, 0 }
+#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
+	((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
+#define AMD_MODEL_RANGE_FAMILY(range)	(((range) >> 24) & 0xff)
+#define AMD_MODEL_RANGE_START(range)	(((range) >> 12) & 0xfff)
+#define AMD_MODEL_RANGE_END(range)	((range) & 0xfff)
+
+static const int amd_erratum_400[] =
+	AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
+			    AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
+
+static const int amd_erratum_383[] =
+	AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
+
+static const int amd_zenbleed[] =
+	AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf),
+			   AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf),
+			   AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf));
+
+static const int amd_div0[] =
+	AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x00, 0x0, 0x2f, 0xf),
+			   AMD_MODEL_RANGE(0x17, 0x50, 0x0, 0x5f, 0xf));
+
+static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
+{
+	int osvw_id = *erratum++;
+	u32 range;
+	u32 ms;
+
+	if (osvw_id >= 0 && osvw_id < 65536 &&
+	    cpu_has(cpu, X86_FEATURE_OSVW)) {
+		u64 osvw_len;
+
+		rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, osvw_len);
+		if (osvw_id < osvw_len) {
+			u64 osvw_bits;
+
+			rdmsrl(MSR_AMD64_OSVW_STATUS + (osvw_id >> 6),
+			    osvw_bits);
+			return osvw_bits & (1ULL << (osvw_id & 0x3f));
+		}
+	}
+
+	/* OSVW unavailable or ID unknown, match family-model-stepping range */
+	ms = (cpu->x86_model << 4) | cpu->x86_stepping;
+	while ((range = *erratum++))
+		if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) &&
+		    (ms >= AMD_MODEL_RANGE_START(range)) &&
+		    (ms <= AMD_MODEL_RANGE_END(range)))
+			return true;
+
+	return false;
+}
+
 static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
 {
 	u32 gprs[8] = { 0 };
@@ -111,7 +187,7 @@
 		return;
 	}
 
-	if (c->x86_model == 6 && c->x86_mask == 1) {
+	if (c->x86_model == 6 && c->x86_stepping == 1) {
 		const int K6_BUG_LOOP = 1000000;
 		int n;
 		void (*f_vide)(void);
@@ -141,7 +217,7 @@
 
 	/* K6 with old style WHCR */
 	if (c->x86_model < 8 ||
-	   (c->x86_model == 8 && c->x86_mask < 8)) {
+	   (c->x86_model == 8 && c->x86_stepping < 8)) {
 		/* We can only write allocate on the low 508Mb */
 		if (mbytes > 508)
 			mbytes = 508;
@@ -160,7 +236,7 @@
 		return;
 	}
 
-	if ((c->x86_model == 8 && c->x86_mask > 7) ||
+	if ((c->x86_model == 8 && c->x86_stepping > 7) ||
 	     c->x86_model == 9 || c->x86_model == 13) {
 		/* The more serious chips .. */
 
@@ -213,7 +289,7 @@
 	 * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
 	 * As per AMD technical note 27212 0.2
 	 */
-	if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) {
+	if ((c->x86_model == 8 && c->x86_stepping >= 1) || (c->x86_model > 8)) {
 		rdmsr(MSR_K7_CLK_CTL, l, h);
 		if ((l & 0xfff00000) != 0x20000000) {
 			printk(KERN_INFO
@@ -223,8 +299,6 @@
 		}
 	}
 
-	set_cpu_cap(c, X86_FEATURE_K7);
-
 	/* calling is from identify_secondary_cpu() ? */
 	if (!c->cpu_index)
 		return;
@@ -234,12 +308,12 @@
 	 * but they are not certified as MP capable.
 	 */
 	/* Athlon 660/661 is valid. */
-	if ((c->x86_model == 6) && ((c->x86_mask == 0) ||
-	    (c->x86_mask == 1)))
+	if ((c->x86_model == 6) && ((c->x86_stepping == 0) ||
+	    (c->x86_stepping == 1)))
 		return;
 
 	/* Duron 670 is valid */
-	if ((c->x86_model == 7) && (c->x86_mask == 0))
+	if ((c->x86_model == 7) && (c->x86_stepping == 0))
 		return;
 
 	/*
@@ -249,8 +323,8 @@
 	 * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for
 	 * more.
 	 */
-	if (((c->x86_model == 6) && (c->x86_mask >= 2)) ||
-	    ((c->x86_model == 7) && (c->x86_mask >= 1)) ||
+	if (((c->x86_model == 6) && (c->x86_stepping >= 2)) ||
+	    ((c->x86_model == 7) && (c->x86_stepping >= 1)) ||
 	     (c->x86_model > 7))
 		if (cpu_has(c, X86_FEATURE_MP))
 			return;
@@ -290,6 +364,12 @@
 }
 #endif
 
+static void amd_get_topology_early(struct cpuinfo_x86 *c)
+{
+	if (cpu_has(c, X86_FEATURE_TOPOEXT))
+		smp_num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0x3) + 1;
+}
+
 /*
  * Fixup core topology information for
  * (1) AMD multi-node processors
@@ -304,7 +384,7 @@
 	int cpu = smp_processor_id();
 
 	/* get information required for multi-node processors */
-	if (cpu_has_topoext) {
+	if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
 		u32 eax, ebx, ecx, edx;
 
 		cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
@@ -312,9 +392,9 @@
 		node_id = ecx & 7;
 
 		/* get compute unit information */
-		smp_num_siblings = ((ebx >> 8) & 3) + 1;
+		cores_per_cu = smp_num_siblings;
+		c->x86_max_cores /= smp_num_siblings;
 		c->compute_unit_id = ebx & 0xff;
-		cores_per_cu += ((ebx >> 8) & 3);
 	} else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
 		u64 value;
 
@@ -330,8 +410,8 @@
 		u32 cus_per_node;
 
 		set_cpu_cap(c, X86_FEATURE_AMD_DCM);
-		cores_per_node = c->x86_max_cores / nodes_per_socket;
-		cus_per_node = cores_per_node / cores_per_cu;
+		cus_per_node = c->x86_max_cores / nodes_per_socket;
+		cores_per_node = cus_per_node * cores_per_cu;
 
 		/* store NodeID, use llc_shared_map to store sibling info */
 		per_cpu(cpu_llc_id, cpu) = node_id;
@@ -352,7 +432,6 @@
 #ifdef CONFIG_SMP
 	unsigned bits;
 	int cpu = smp_processor_id();
-	unsigned int socket_id, core_complex_id;
 
 	bits = c->x86_coreid_bits;
 	/* Low order bits define the core id (index of core in socket) */
@@ -370,10 +449,7 @@
 	 if (c->x86 != 0x17 || !cpuid_edx(0x80000006))
 		return;
 
-	socket_id	= (c->apicid >> bits) - 1;
-	core_complex_id	= (c->apicid & ((1 << bits) - 1)) >> 3;
-
-	per_cpu(cpu_llc_id, cpu) = (socket_id << 3) | core_complex_id;
+	per_cpu(cpu_llc_id, cpu) = c->apicid >> 3;
 #endif
 }
 
@@ -523,12 +599,42 @@
 
 	if (cpu_has(c, X86_FEATURE_MWAITX))
 		use_mwaitx_delay();
+
+	if (c->x86 >= 0x15 && c->x86 <= 0x17) {
+		unsigned int bit;
+
+		switch (c->x86) {
+		case 0x15: bit = 54; break;
+		case 0x16: bit = 33; break;
+		case 0x17: bit = 10; break;
+		default: return;
+		}
+		/*
+		 * Try to cache the base value so further operations can
+		 * avoid RMW. If that faults, do not enable SSBD.
+		 */
+		if (!rdmsrl_safe(MSR_AMD64_LS_CFG, &x86_amd_ls_cfg_base)) {
+			setup_force_cpu_cap(X86_FEATURE_LS_CFG_SSBD);
+			setup_force_cpu_cap(X86_FEATURE_SSBD);
+			x86_amd_ls_cfg_ssbd_mask = 1ULL << bit;
+		}
+	}
 }
 
 static void early_init_amd(struct cpuinfo_x86 *c)
 {
+	u64 value;
+
 	early_init_amd_mc(c);
 
+#ifdef CONFIG_X86_32
+	if (c->x86 == 6)
+		set_cpu_cap(c, X86_FEATURE_K7);
+#endif
+
+	if (c->x86 >= 0xf)
+		set_cpu_cap(c, X86_FEATURE_K8);
+
 	/*
 	 * c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate
 	 * with P/T states and does not stop in deep C-states
@@ -546,7 +652,7 @@
 	/*  Set MTRR capability flag if appropriate */
 	if (c->x86 == 5)
 		if (c->x86_model == 13 || c->x86_model == 9 ||
-		    (c->x86_model == 8 && c->x86_mask >= 8))
+		    (c->x86_model == 8 && c->x86_stepping >= 8))
 			set_cpu_cap(c, X86_FEATURE_K6_MTRR);
 #endif
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI)
@@ -577,6 +683,22 @@
 	/* F16h erratum 793, CVE-2013-6885 */
 	if (c->x86 == 0x16 && c->x86_model <= 0xf)
 		msr_set_bit(MSR_AMD64_LS_CFG, 15);
+
+	/* Re-enable TopologyExtensions if switched off by BIOS */
+	if (c->x86 == 0x15 &&
+	    (c->x86_model >= 0x10 && c->x86_model <= 0x6f) &&
+	    !cpu_has(c, X86_FEATURE_TOPOEXT)) {
+
+		if (msr_set_bit(0xc0011005, 54) > 0) {
+			rdmsrl(0xc0011005, value);
+			if (value & BIT_64(54)) {
+				set_cpu_cap(c, X86_FEATURE_TOPOEXT);
+				pr_info_once(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n");
+			}
+		}
+	}
+
+	amd_get_topology_early(c);
 }
 
 static const int amd_erratum_383[];
@@ -656,33 +778,158 @@
 		set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
 }
 
-static void init_amd_bd(struct cpuinfo_x86 *c)
+#define MSR_AMD64_DE_CFG	0xC0011029
+
+static void init_amd_ln(struct cpuinfo_x86 *c)
 {
-	u64 value;
+	/*
+	 * Apply erratum 665 fix unconditionally so machines without a BIOS
+	 * fix work.
+	 */
+	msr_set_bit(MSR_AMD64_DE_CFG, 31);
+}
 
-	/* re-enable TopologyExtensions if switched off by BIOS */
-	if ((c->x86_model >= 0x10) && (c->x86_model <= 0x1f) &&
-	    !cpu_has(c, X86_FEATURE_TOPOEXT)) {
+static bool rdrand_force;
 
-		if (msr_set_bit(0xc0011005, 54) > 0) {
-			rdmsrl(0xc0011005, value);
-			if (value & BIT_64(54)) {
-				set_cpu_cap(c, X86_FEATURE_TOPOEXT);
-				pr_info(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n");
-			}
-		}
+static int __init rdrand_cmdline(char *str)
+{
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "force"))
+		rdrand_force = true;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+early_param("rdrand", rdrand_cmdline);
+
+static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c)
+{
+	/*
+	 * Saving of the MSR used to hide the RDRAND support during
+	 * suspend/resume is done by arch/x86/power/cpu.c, which is
+	 * dependent on CONFIG_PM_SLEEP.
+	 */
+	if (!IS_ENABLED(CONFIG_PM_SLEEP))
+		return;
+
+	/*
+	 * The nordrand option can clear X86_FEATURE_RDRAND, so check for
+	 * RDRAND support using the CPUID function directly.
+	 */
+	if (!(cpuid_ecx(1) & BIT(30)) || rdrand_force)
+		return;
+
+	msr_clear_bit(MSR_AMD64_CPUID_FN_1, 62);
+
+	/*
+	 * Verify that the CPUID change has occurred in case the kernel is
+	 * running virtualized and the hypervisor doesn't support the MSR.
+	 */
+	if (cpuid_ecx(1) & BIT(30)) {
+		pr_info_once("BIOS may not properly restore RDRAND after suspend, but hypervisor does not support hiding RDRAND via CPUID.\n");
+		return;
 	}
 
+	clear_cpu_cap(c, X86_FEATURE_RDRAND);
+	pr_info_once("BIOS may not properly restore RDRAND after suspend, hiding RDRAND via CPUID. Use rdrand=force to reenable.\n");
+}
+
+static void init_amd_jg(struct cpuinfo_x86 *c)
+{
+	/*
+	 * Some BIOS implementations do not restore proper RDRAND support
+	 * across suspend and resume. Check on whether to hide the RDRAND
+	 * instruction support via CPUID.
+	 */
+	clear_rdrand_cpuid_bit(c);
+}
+
+static void init_amd_bd(struct cpuinfo_x86 *c)
+{
+	u64 value;
+
 	/*
 	 * The way access filter has a performance penalty on some workloads.
 	 * Disable it on the affected CPUs.
 	 */
 	if ((c->x86_model >= 0x02) && (c->x86_model < 0x20)) {
-		if (!rdmsrl_safe(0xc0011021, &value) && !(value & 0x1E)) {
+		if (!rdmsrl_safe(MSR_F15H_IC_CFG, &value) && !(value & 0x1E)) {
 			value |= 0x1E;
-			wrmsrl_safe(0xc0011021, value);
+			wrmsrl_safe(MSR_F15H_IC_CFG, value);
 		}
 	}
+
+	/*
+	 * Some BIOS implementations do not restore proper RDRAND support
+	 * across suspend and resume. Check on whether to hide the RDRAND
+	 * instruction support via CPUID.
+	 */
+	clear_rdrand_cpuid_bit(c);
+}
+
+static void init_amd_zn(struct cpuinfo_x86 *c)
+{
+	set_cpu_cap(c, X86_FEATURE_ZEN);
+
+	/* Fix up CPUID bits, but only if not virtualised. */
+	if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) {
+
+		/* Erratum 1076: CPB feature bit not being set in CPUID. */
+		if (!cpu_has(c, X86_FEATURE_CPB))
+			set_cpu_cap(c, X86_FEATURE_CPB);
+
+		/*
+		 * Zen3 (Fam19 model < 0x10) parts are not susceptible to
+		 * Branch Type Confusion, but predate the allocation of the
+		 * BTC_NO bit.
+		 */
+		if (c->x86 == 0x19 && !cpu_has(c, X86_FEATURE_BTC_NO))
+			set_cpu_cap(c, X86_FEATURE_BTC_NO);
+	}
+}
+
+static bool cpu_has_zenbleed_microcode(void)
+{
+	u32 good_rev = 0;
+
+	switch (boot_cpu_data.x86_model) {
+	case 0x30 ... 0x3f: good_rev = 0x0830107a; break;
+	case 0x60 ... 0x67: good_rev = 0x0860010b; break;
+	case 0x68 ... 0x6f: good_rev = 0x08608105; break;
+	case 0x70 ... 0x7f: good_rev = 0x08701032; break;
+	case 0xa0 ... 0xaf: good_rev = 0x08a00008; break;
+
+	default:
+		return false;
+		break;
+	}
+
+	if (boot_cpu_data.microcode < good_rev)
+		return false;
+
+	return true;
+}
+
+static void zenbleed_check(struct cpuinfo_x86 *c)
+{
+	if (!cpu_has_amd_erratum(c, amd_zenbleed))
+		return;
+
+	if (cpu_has(c, X86_FEATURE_HYPERVISOR))
+		return;
+
+	if (!cpu_has(c, X86_FEATURE_AVX))
+		return;
+
+	if (!cpu_has_zenbleed_microcode()) {
+		pr_notice_once("Zenbleed: please update your microcode for the most optimal fix\n");
+		msr_set_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT);
+	} else {
+		msr_clear_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT);
+	}
 }
 
 static void init_amd(struct cpuinfo_x86 *c)
@@ -713,7 +960,10 @@
 	case 6:	   init_amd_k7(c); break;
 	case 0xf:  init_amd_k8(c); break;
 	case 0x10: init_amd_gh(c); break;
+	case 0x12: init_amd_ln(c); break;
 	case 0x15: init_amd_bd(c); break;
+	case 0x16: init_amd_jg(c); break;
+	case 0x17: init_amd_zn(c); break;
 	}
 
 	/* Enable workaround for FXSAVE leak */
@@ -728,18 +978,35 @@
 		srat_detect_node(c);
 	}
 
-#ifdef CONFIG_X86_32
-	detect_ht(c);
-#endif
-
 	init_amd_cacheinfo(c);
 
-	if (c->x86 >= 0xf)
-		set_cpu_cap(c, X86_FEATURE_K8);
-
 	if (cpu_has_xmm2) {
-		/* MFENCE stops RDTSC speculation */
-		set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
+		unsigned long long val;
+		int ret;
+
+		/*
+		 * A serializing LFENCE has less overhead than MFENCE, so
+		 * use it for execution serialization.  On families which
+		 * don't have that MSR, LFENCE is already serializing.
+		 * msr_set_bit() uses the safe accessors, too, even if the MSR
+		 * is not present.
+		 */
+		msr_set_bit(MSR_F10H_DECFG,
+			    MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT);
+
+		/*
+		 * Verify that the MSR write was successful (could be running
+		 * under a hypervisor) and only then assume that LFENCE is
+		 * serializing.
+		 */
+		ret = rdmsrl_safe(MSR_F10H_DECFG, &val);
+		if (!ret && (val & MSR_F10H_DECFG_LFENCE_SERIALIZE)) {
+			/* A serializing LFENCE stops RDTSC speculation */
+			set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
+		} else {
+			/* MFENCE stops RDTSC speculation */
+			set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
+		}
 	}
 
 	/*
@@ -759,8 +1026,37 @@
 		if (cpu_has(c, X86_FEATURE_3DNOW) || cpu_has(c, X86_FEATURE_LM))
 			set_cpu_cap(c, X86_FEATURE_3DNOWPREFETCH);
 
-	/* AMD CPUs don't reset SS attributes on SYSRET */
-	set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS);
+	/* AMD CPUs don't reset SS attributes on SYSRET, Xen does. */
+	if (!cpu_has(c, X86_FEATURE_XENPV))
+		set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS);
+
+	/*
+	 * On AMD family 0x10, 0x12 and 0x16 processors that do not support the
+	 * speculative control features, IBPB type support can be achieved by
+	 * disabling indirect branch predictor support.
+	 */
+	if (!noibpb && !cpu_has(c, X86_FEATURE_SPEC_CTRL) &&
+	    !cpu_has(c, X86_FEATURE_IBPB)) {
+		u64 val;
+
+		switch (c->x86) {
+		case 0x10:
+		case 0x12:
+		case 0x16:
+			pr_info_once("Disabling Indirect Branch Predictor Support\n");
+			rdmsrl(MSR_F15H_IC_CFG, val);
+			val |= MSR_F15H_IC_CFG_DIS_IND;
+			wrmsrl(MSR_F15H_IC_CFG, val);
+			break;
+		}
+	}
+
+	zenbleed_check(c);
+
+	if (cpu_has_amd_erratum(c, amd_div0)) {
+		pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n");
+		setup_force_cpu_bug(X86_BUG_DIV0);
+	}
 }
 
 #ifdef CONFIG_X86_32
@@ -769,11 +1065,11 @@
 	/* AMD errata T13 (order #21922) */
 	if ((c->x86 == 6)) {
 		/* Duron Rev A0 */
-		if (c->x86_model == 3 && c->x86_mask == 0)
+		if (c->x86_model == 3 && c->x86_stepping == 0)
 			size = 64;
 		/* Tbird rev A1/A2 */
 		if (c->x86_model == 4 &&
-			(c->x86_mask == 0 || c->x86_mask == 1))
+			(c->x86_stepping == 0 || c->x86_stepping == 1))
 			size = 256;
 	}
 	return size;
@@ -856,73 +1152,9 @@
 
 cpu_dev_register(amd_cpu_dev);
 
-/*
- * AMD errata checking
- *
- * Errata are defined as arrays of ints using the AMD_LEGACY_ERRATUM() or
- * AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
- * have an OSVW id assigned, which it takes as first argument. Both take a
- * variable number of family-specific model-stepping ranges created by
- * AMD_MODEL_RANGE().
- *
- * Example:
- *
- * const int amd_erratum_319[] =
- *	AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2),
- *			   AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0),
- *			   AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
- */
-
-#define AMD_LEGACY_ERRATUM(...)		{ -1, __VA_ARGS__, 0 }
-#define AMD_OSVW_ERRATUM(osvw_id, ...)	{ osvw_id, __VA_ARGS__, 0 }
-#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
-	((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
-#define AMD_MODEL_RANGE_FAMILY(range)	(((range) >> 24) & 0xff)
-#define AMD_MODEL_RANGE_START(range)	(((range) >> 12) & 0xfff)
-#define AMD_MODEL_RANGE_END(range)	((range) & 0xfff)
-
-static const int amd_erratum_400[] =
-	AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
-			    AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
-
-static const int amd_erratum_383[] =
-	AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
-
-
-static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
-{
-	int osvw_id = *erratum++;
-	u32 range;
-	u32 ms;
-
-	if (osvw_id >= 0 && osvw_id < 65536 &&
-	    cpu_has(cpu, X86_FEATURE_OSVW)) {
-		u64 osvw_len;
-
-		rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, osvw_len);
-		if (osvw_id < osvw_len) {
-			u64 osvw_bits;
-
-			rdmsrl(MSR_AMD64_OSVW_STATUS + (osvw_id >> 6),
-			    osvw_bits);
-			return osvw_bits & (1ULL << (osvw_id & 0x3f));
-		}
-	}
-
-	/* OSVW unavailable or ID unknown, match family-model-stepping range */
-	ms = (cpu->x86_model << 4) | cpu->x86_mask;
-	while ((range = *erratum++))
-		if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) &&
-		    (ms >= AMD_MODEL_RANGE_START(range)) &&
-		    (ms <= AMD_MODEL_RANGE_END(range)))
-			return true;
-
-	return false;
-}
-
 void set_dr_addr_mask(unsigned long mask, int dr)
 {
-	if (!cpu_has_bpext)
+	if (!boot_cpu_has(X86_FEATURE_BPEXT))
 		return;
 
 	switch (dr) {
@@ -938,3 +1170,26 @@
 		break;
 	}
 }
+
+static void zenbleed_check_cpu(void *unused)
+{
+	struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
+
+	zenbleed_check(c);
+}
+
+void amd_check_microcode(void)
+{
+	on_each_cpu(zenbleed_check_cpu, NULL, 1);
+}
+
+/*
+ * Issue a DIV 0/1 insn to clear any division data from previous DIV
+ * operations.
+ */
+void amd_clear_divider(void)
+{
+	asm volatile(ALTERNATIVE("", "div %2\n\t", X86_BUG_DIV0)
+		     :: "a" (0), "d" (0), "r" (1));
+}
+EXPORT_SYMBOL_GPL(amd_clear_divider);
--- linux-4.4.0.orig/arch/x86/kernel/cpu/bugs.c
+++ linux-4.4.0/arch/x86/kernel/cpu/bugs.c
@@ -8,36 +8,2581 @@
  *	- Andrew D. Balsa (code cleanup).
  */
 #include <linux/init.h>
-#include <linux/utsname.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+#include <linux/nospec.h>
+#include <linux/prctl.h>
+#include <linux/sched/smt.h>
+
+#include <asm/spec-ctrl.h>
+#include <asm/cmdline.h>
 #include <asm/bugs.h>
 #include <asm/processor.h>
 #include <asm/processor-flags.h>
 #include <asm/fpu/internal.h>
 #include <asm/msr.h>
+#include <asm/vmx.h>
 #include <asm/paravirt.h>
-#include <asm/alternative.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#include <asm/intel-family.h>
+#include <asm/e820.h>
+#include <asm/hypervisor.h>
+
+#include "cpu.h"
 
-void __init check_bugs(void)
+unsigned int noibpb = 0;
+
+static int __init noibpb_handler(char *str)
 {
-	identify_boot_cpu();
-#ifndef CONFIG_SMP
-	pr_info("CPU: ");
-	print_cpu_info(&boot_cpu_data);
-#endif
+	noibpb = 1;
+	return 0;
+}
+
+early_param("noibpb", noibpb_handler);
+
+unsigned int noibrs = 0;
+
+static int __init noibrs_handler(char *str)
+{
+	noibrs = 1;
+	return 0;
+}
+
+early_param("noibrs", noibrs_handler);
+
+static void __init spectre_v1_select_mitigation(void);
+static void __init spectre_v2_select_mitigation(void);
+static void __init retbleed_select_mitigation(void);
+static void __init spectre_v2_user_select_mitigation(void);
+static void __init ssb_select_mitigation(void);
+static void __init l1tf_select_mitigation(void);
+static void __init mds_select_mitigation(void);
+static void __init md_clear_update_mitigation(void);
+static void __init md_clear_select_mitigation(void);
+static void __init taa_select_mitigation(void);
+static void __init mmio_select_mitigation(void);
+static void __init srbds_select_mitigation(void);
+static void __init gds_select_mitigation(void);
+static void __init vmscape_select_mitigation(void);
+
+/* The base value of the SPEC_CTRL MSR without task-specific bits set */
+u64 x86_spec_ctrl_base;
+EXPORT_SYMBOL_GPL(x86_spec_ctrl_base);
+
+/* The current value of the SPEC_CTRL MSR with task-specific bits set */
+DEFINE_PER_CPU(u64, x86_spec_ctrl_current);
+EXPORT_SYMBOL_GPL(x86_spec_ctrl_current);
+
+/*
+ * Set when the CPU has run a potentially malicious guest. An IBPB will
+ * be needed before running userspace to flush the branch predictor.
+ */
+DEFINE_PER_CPU(bool, x86_ibpb_exit_to_user);
+EXPORT_PER_CPU_SYMBOL_GPL(x86_ibpb_exit_to_user);
+
+static u64 __ro_after_init x86_arch_cap_msr;
+
+static DEFINE_MUTEX(spec_ctrl_mutex);
+
+/* Update SPEC_CTRL MSR and its cached copy unconditionally */
+static void update_spec_ctrl(u64 val)
+{
+	this_cpu_write(x86_spec_ctrl_current, val);
+	wrmsrl(MSR_IA32_SPEC_CTRL, val);
+}
+
+/*
+ * Keep track of the SPEC_CTRL MSR value for the current task, which may differ
+ * from x86_spec_ctrl_base due to STIBP/SSB in __speculation_ctrl_update().
+ */
+void update_spec_ctrl_cond(u64 val)
+{
+	if (this_cpu_read(x86_spec_ctrl_current) == val)
+		return;
+
+	this_cpu_write(x86_spec_ctrl_current, val);
+
+	/*
+	 * When KERNEL_IBRS this MSR is written on return-to-user, unless
+	 * forced the update can be delayed until that time.
+	 */
+	if (!cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS))
+		wrmsrl(MSR_IA32_SPEC_CTRL, val);
+}
+
+u64 spec_ctrl_current(void)
+{
+	return this_cpu_read(x86_spec_ctrl_current);
+}
+EXPORT_SYMBOL_GPL(spec_ctrl_current);
+
+/*
+ * AMD specific MSR info for Speculative Store Bypass control.
+ * x86_amd_ls_cfg_ssbd_mask is initialized in identify_boot_cpu().
+ */
+u64 __ro_after_init x86_amd_ls_cfg_base;
+u64 __ro_after_init x86_amd_ls_cfg_ssbd_mask;
+
+/* Control conditional STIBP in switch_to() */
+DEFINE_STATIC_KEY_FALSE(switch_to_cond_stibp);
+/* Control conditional IBPB in switch_mm() */
+DEFINE_STATIC_KEY_FALSE(switch_mm_cond_ibpb);
+/* Control unconditional IBPB in switch_mm() */
+DEFINE_STATIC_KEY_FALSE(switch_mm_always_ibpb);
+
+/* Control MDS CPU buffer clear before returning to user space */
+DEFINE_STATIC_KEY_FALSE(mds_user_clear);
+EXPORT_SYMBOL_GPL(mds_user_clear);
+/* Control MDS CPU buffer clear before idling (halt, mwait) */
+DEFINE_STATIC_KEY_FALSE(mds_idle_clear);
+EXPORT_SYMBOL_GPL(mds_idle_clear);
+
+/* Controls CPU Fill buffer clear before KVM guest MMIO accesses */
+DEFINE_STATIC_KEY_FALSE(mmio_stale_data_clear);
+EXPORT_SYMBOL_GPL(mmio_stale_data_clear);
+
+void __init cpu_select_mitigations(void)
+{
+	/*
+	 * Read the SPEC_CTRL MSR to account for reserved bits which may
+	 * have unknown values. AMD64_LS_CFG MSR is cached in the early AMD
+	 * init code as it is not enumerated and depends on the family.
+	 */
+	if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
+		rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+
+	x86_arch_cap_msr = x86_read_arch_cap_msr();
+
+	/* Select the proper CPU mitigations before patching alternatives: */
+	spectre_v1_select_mitigation();
+	spectre_v2_select_mitigation();
+	/*
+	 * retbleed_select_mitigation() relies on the state set by
+	 * spectre_v2_select_mitigation(); specifically it wants to know about
+	 * spectre_v2=ibrs.
+	 */
+	retbleed_select_mitigation();
+	/*
+	 * spectre_v2_user_select_mitigation() relies on the state set by
+	 * retbleed_select_mitigation(); specifically the STIBP selection is
+	 * forced for UNRET.
+	 */
+	spectre_v2_user_select_mitigation();
+	ssb_select_mitigation();
+	l1tf_select_mitigation();
+	md_clear_select_mitigation();
+	srbds_select_mitigation();
+	gds_select_mitigation();
+	vmscape_select_mitigation();
+}
+
+/*
+ * NOTE: For VMX, this function is not called in the vmexit path.
+ * It uses vmx_spec_ctrl_restore_host() instead.
+ */
+void
+x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest)
+{
+	u64 msrval, guestval = guest_spec_ctrl, hostval = spec_ctrl_current();
+	struct thread_info *ti = current_thread_info();
+
+	if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) {
+		if (hostval != guestval) {
+			msrval = setguest ? guestval : hostval;
+			wrmsrl(MSR_IA32_SPEC_CTRL, msrval);
+		}
+	}
+
+	/*
+	 * If SSBD is not handled in MSR_SPEC_CTRL on AMD, update
+	 * MSR_AMD64_L2_CFG or MSR_VIRT_SPEC_CTRL if supported.
+	 */
+	if (!static_cpu_has(X86_FEATURE_LS_CFG_SSBD) &&
+	    !static_cpu_has(X86_FEATURE_VIRT_SSBD))
+		return;
+
+	/*
+	 * If the host has SSBD mitigation enabled, force it in the host's
+	 * virtual MSR value. If its not permanently enabled, evaluate
+	 * current's TIF_SSBD thread flag.
+	 */
+	if (static_cpu_has(X86_FEATURE_SPEC_STORE_BYPASS_DISABLE))
+		hostval = SPEC_CTRL_SSBD;
+	else
+		hostval = ssbd_tif_to_spec_ctrl(ti->flags);
+
+	/* Sanitize the guest value */
+	guestval = guest_virt_spec_ctrl & SPEC_CTRL_SSBD;
+
+	if (hostval != guestval) {
+		unsigned long tif;
+
+		tif = setguest ? ssbd_spec_ctrl_to_tif(guestval) :
+				 ssbd_spec_ctrl_to_tif(hostval);
+
+		speculation_ctrl_update(tif);
+	}
+}
+EXPORT_SYMBOL_GPL(x86_virt_spec_ctrl);
+
+static void x86_amd_ssb_disable(void)
+{
+	u64 msrval = x86_amd_ls_cfg_base | x86_amd_ls_cfg_ssbd_mask;
+
+	if (boot_cpu_has(X86_FEATURE_VIRT_SSBD))
+		wrmsrl(MSR_AMD64_VIRT_SPEC_CTRL, SPEC_CTRL_SSBD);
+	else if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD))
+		wrmsrl(MSR_AMD64_LS_CFG, msrval);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"MDS: " fmt
+
+/* Default mitigation for MDS-affected CPUs */
+static enum mds_mitigations mds_mitigation __ro_after_init = MDS_MITIGATION_FULL;
+static bool mds_nosmt __ro_after_init = false;
+
+static const char * const mds_strings[] = {
+	[MDS_MITIGATION_OFF]	= "Vulnerable",
+	[MDS_MITIGATION_FULL]	= "Mitigation: Clear CPU buffers",
+	[MDS_MITIGATION_VMWERV]	= "Vulnerable: Clear CPU buffers attempted, no microcode",
+};
+
+static void __init mds_select_mitigation(void)
+{
+	if (!boot_cpu_has_bug(X86_BUG_MDS) || cpu_mitigations_off()) {
+		mds_mitigation = MDS_MITIGATION_OFF;
+		return;
+	}
+
+	if (mds_mitigation == MDS_MITIGATION_FULL) {
+		if (!boot_cpu_has(X86_FEATURE_MD_CLEAR))
+			mds_mitigation = MDS_MITIGATION_VMWERV;
+
+		static_branch_enable(&mds_user_clear);
+
+		if (!boot_cpu_has(X86_BUG_MSBDS_ONLY) &&
+		    (mds_nosmt || cpu_mitigations_auto_nosmt()))
+			cpu_smt_disable(false);
+	}
+}
+
+static int __init mds_cmdline(char *str)
+{
+	if (!boot_cpu_has_bug(X86_BUG_MDS))
+		return 0;
+
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "off"))
+		mds_mitigation = MDS_MITIGATION_OFF;
+	else if (!strcmp(str, "full"))
+		mds_mitigation = MDS_MITIGATION_FULL;
+	else if (!strcmp(str, "full,nosmt")) {
+		mds_mitigation = MDS_MITIGATION_FULL;
+		mds_nosmt = true;
+	}
+
+	return 0;
+}
+early_param("mds", mds_cmdline);
+
+void mds_user_clear_buffers(void)
+{
+	mds_user_clear_cpu_buffers();
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"TAA: " fmt
+
+/* Default mitigation for TAA-affected CPUs */
+static enum taa_mitigations taa_mitigation __ro_after_init = TAA_MITIGATION_VERW;
+static bool taa_nosmt __ro_after_init;
+
+static const char * const taa_strings[] = {
+	[TAA_MITIGATION_OFF]		= "Vulnerable",
+	[TAA_MITIGATION_UCODE_NEEDED]	= "Vulnerable: Clear CPU buffers attempted, no microcode",
+	[TAA_MITIGATION_VERW]		= "Mitigation: Clear CPU buffers",
+	[TAA_MITIGATION_TSX_DISABLED]	= "Mitigation: TSX disabled",
+};
+
+static void __init taa_select_mitigation(void)
+{
+	if (!boot_cpu_has_bug(X86_BUG_TAA)) {
+		taa_mitigation = TAA_MITIGATION_OFF;
+		return;
+	}
+
+	/* TSX previously disabled by tsx=off */
+	if (!boot_cpu_has(X86_FEATURE_RTM)) {
+		taa_mitigation = TAA_MITIGATION_TSX_DISABLED;
+		return;
+	}
+
+	if (cpu_mitigations_off()) {
+		taa_mitigation = TAA_MITIGATION_OFF;
+		return;
+	}
+
+	/*
+	 * TAA mitigation via VERW is turned off if both
+	 * tsx_async_abort=off and mds=off are specified.
+	 */
+	if (taa_mitigation == TAA_MITIGATION_OFF &&
+	    mds_mitigation == MDS_MITIGATION_OFF)
+		return;
+
+	if (boot_cpu_has(X86_FEATURE_MD_CLEAR))
+		taa_mitigation = TAA_MITIGATION_VERW;
+	else
+		taa_mitigation = TAA_MITIGATION_UCODE_NEEDED;
 
 	/*
-	 * Check whether we are able to run this kernel safely on SMP.
+	 * VERW doesn't clear the CPU buffers when MD_CLEAR=1 and MDS_NO=1.
+	 * A microcode update fixes this behavior to clear CPU buffers. It also
+	 * adds support for MSR_IA32_TSX_CTRL which is enumerated by the
+	 * ARCH_CAP_TSX_CTRL_MSR bit.
 	 *
-	 * - i386 is no longer supported.
-	 * - In order to run on anything without a TSC, we need to be
-	 *   compiled for a i486.
+	 * On MDS_NO=1 CPUs if ARCH_CAP_TSX_CTRL_MSR is not set, microcode
+	 * update is required.
+	 */
+	if ( (x86_arch_cap_msr & ARCH_CAP_MDS_NO) &&
+	    !(x86_arch_cap_msr & ARCH_CAP_TSX_CTRL_MSR))
+		taa_mitigation = TAA_MITIGATION_UCODE_NEEDED;
+
+	/*
+	 * TSX is enabled, select alternate mitigation for TAA which is
+	 * the same as MDS. Enable MDS static branch to clear CPU buffers.
+	 *
+	 * For guests that can't determine whether the correct microcode is
+	 * present on host, enable the mitigation for UCODE_NEEDED as well.
+	 */
+	static_branch_enable(&mds_user_clear);
+
+	if (taa_nosmt || cpu_mitigations_auto_nosmt())
+		cpu_smt_disable(false);
+}
+
+static int __init tsx_async_abort_parse_cmdline(char *str)
+{
+	if (!boot_cpu_has_bug(X86_BUG_TAA))
+		return 0;
+
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "off")) {
+		taa_mitigation = TAA_MITIGATION_OFF;
+	} else if (!strcmp(str, "full")) {
+		taa_mitigation = TAA_MITIGATION_VERW;
+	} else if (!strcmp(str, "full,nosmt")) {
+		taa_mitigation = TAA_MITIGATION_VERW;
+		taa_nosmt = true;
+	}
+
+	return 0;
+}
+early_param("tsx_async_abort", tsx_async_abort_parse_cmdline);
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"MMIO Stale Data: " fmt
+
+enum mmio_mitigations {
+	MMIO_MITIGATION_OFF,
+	MMIO_MITIGATION_UCODE_NEEDED,
+	MMIO_MITIGATION_VERW,
+};
+
+/* Default mitigation for Processor MMIO Stale Data vulnerabilities */
+static enum mmio_mitigations mmio_mitigation __ro_after_init = MMIO_MITIGATION_VERW;
+static bool mmio_nosmt __ro_after_init = false;
+
+static const char * const mmio_strings[] = {
+	[MMIO_MITIGATION_OFF]		= "Vulnerable",
+	[MMIO_MITIGATION_UCODE_NEEDED]	= "Vulnerable: Clear CPU buffers attempted, no microcode",
+	[MMIO_MITIGATION_VERW]		= "Mitigation: Clear CPU buffers",
+};
+
+static void __init mmio_select_mitigation(void)
+{
+	if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA) ||
+	    cpu_mitigations_off()) {
+		mmio_mitigation = MMIO_MITIGATION_OFF;
+		return;
+	}
+
+	if (mmio_mitigation == MMIO_MITIGATION_OFF)
+		return;
+
+	/*
+	 * Enable CPU buffer clear mitigation for host and VMM, if also affected
+	 * by MDS or TAA. Otherwise, enable mitigation for VMM only.
+	 */
+	if (boot_cpu_has_bug(X86_BUG_MDS) || (boot_cpu_has_bug(X86_BUG_TAA) &&
+					      boot_cpu_has(X86_FEATURE_RTM)))
+		static_branch_enable(&mds_user_clear);
+	else
+		static_branch_enable(&mmio_stale_data_clear);
+
+	/*
+	 * If Processor-MMIO-Stale-Data bug is present and Fill Buffer data can
+	 * be propagated to uncore buffers, clearing the Fill buffers on idle
+	 * is required irrespective of SMT state.
+	 */
+	if (!(x86_arch_cap_msr & ARCH_CAP_FBSDP_NO))
+		static_branch_enable(&mds_idle_clear);
+
+	/*
+	 * Check if the system has the right microcode.
+	 *
+	 * CPU Fill buffer clear mitigation is enumerated by either an explicit
+	 * FB_CLEAR or by the presence of both MD_CLEAR and L1D_FLUSH on MDS
+	 * affected systems.
+	 */
+	if ((x86_arch_cap_msr & ARCH_CAP_FB_CLEAR) ||
+	    (boot_cpu_has(X86_FEATURE_MD_CLEAR) &&
+	     boot_cpu_has(X86_FEATURE_FLUSH_L1D) &&
+	     !(x86_arch_cap_msr & ARCH_CAP_MDS_NO)))
+		mmio_mitigation = MMIO_MITIGATION_VERW;
+	else
+		mmio_mitigation = MMIO_MITIGATION_UCODE_NEEDED;
+
+	if (mmio_nosmt || cpu_mitigations_auto_nosmt())
+		cpu_smt_disable(false);
+}
+
+static int __init mmio_stale_data_parse_cmdline(char *str)
+{
+	if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
+		return 0;
+
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "off")) {
+		mmio_mitigation = MMIO_MITIGATION_OFF;
+	} else if (!strcmp(str, "full")) {
+		mmio_mitigation = MMIO_MITIGATION_VERW;
+	} else if (!strcmp(str, "full,nosmt")) {
+		mmio_mitigation = MMIO_MITIGATION_VERW;
+		mmio_nosmt = true;
+	}
+
+	return 0;
+}
+early_param("mmio_stale_data", mmio_stale_data_parse_cmdline);
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "" fmt
+
+static void __init md_clear_update_mitigation(void)
+{
+	if (cpu_mitigations_off())
+		return;
+
+	if (!static_key_enabled(&mds_user_clear))
+		goto out;
+
+	/*
+	 * mds_user_clear is now enabled. Update MDS, TAA and MMIO Stale Data
+	 * mitigation, if necessary.
+	 */
+	if (mds_mitigation == MDS_MITIGATION_OFF &&
+	    boot_cpu_has_bug(X86_BUG_MDS)) {
+		mds_mitigation = MDS_MITIGATION_FULL;
+		mds_select_mitigation();
+	}
+	if (taa_mitigation == TAA_MITIGATION_OFF &&
+	    boot_cpu_has_bug(X86_BUG_TAA)) {
+		taa_mitigation = TAA_MITIGATION_VERW;
+		taa_select_mitigation();
+	}
+	if (mmio_mitigation == MMIO_MITIGATION_OFF &&
+	    boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) {
+		mmio_mitigation = MMIO_MITIGATION_VERW;
+		mmio_select_mitigation();
+	}
+out:
+	if (boot_cpu_has_bug(X86_BUG_MDS))
+		pr_info("MDS: %s\n", mds_strings[mds_mitigation]);
+	if (boot_cpu_has_bug(X86_BUG_TAA))
+		pr_info("TAA: %s\n", taa_strings[taa_mitigation]);
+	if (boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
+		pr_info("MMIO Stale Data: %s\n", mmio_strings[mmio_mitigation]);
+}
+
+static void __init md_clear_select_mitigation(void)
+{
+	mds_select_mitigation();
+	taa_select_mitigation();
+	mmio_select_mitigation();
+
+	/*
+	 * As MDS, TAA and MMIO Stale Data mitigations are inter-related, update
+	 * and print their mitigation after MDS, TAA and MMIO Stale Data
+	 * mitigation selection is done.
+	 */
+	md_clear_update_mitigation();
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"SRBDS: " fmt
+
+enum srbds_mitigations {
+	SRBDS_MITIGATION_OFF,
+	SRBDS_MITIGATION_UCODE_NEEDED,
+	SRBDS_MITIGATION_FULL,
+	SRBDS_MITIGATION_TSX_OFF,
+	SRBDS_MITIGATION_HYPERVISOR,
+};
+
+static enum srbds_mitigations srbds_mitigation __ro_after_init = SRBDS_MITIGATION_FULL;
+
+static const char * const srbds_strings[] = {
+	[SRBDS_MITIGATION_OFF]		= "Vulnerable",
+	[SRBDS_MITIGATION_UCODE_NEEDED]	= "Vulnerable: No microcode",
+	[SRBDS_MITIGATION_FULL]		= "Mitigation: Microcode",
+	[SRBDS_MITIGATION_TSX_OFF]	= "Mitigation: TSX disabled",
+	[SRBDS_MITIGATION_HYPERVISOR]	= "Unknown: Dependent on hypervisor status",
+};
+
+static bool srbds_off;
+
+void update_srbds_msr(void)
+{
+	u64 mcu_ctrl;
+
+	if (!boot_cpu_has_bug(X86_BUG_SRBDS))
+		return;
+
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
+		return;
+
+	if (!boot_cpu_has(X86_FEATURE_SRBDS_CTRL))
+		return;
+
+	rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl);
+
+	switch (srbds_mitigation) {
+	case SRBDS_MITIGATION_OFF:
+	case SRBDS_MITIGATION_TSX_OFF:
+		mcu_ctrl |= RNGDS_MITG_DIS;
+		break;
+	case SRBDS_MITIGATION_FULL:
+		mcu_ctrl &= ~RNGDS_MITG_DIS;
+		break;
+	default:
+		break;
+	}
+
+	wrmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl);
+}
+
+static void __init srbds_select_mitigation(void)
+{
+	if (!boot_cpu_has_bug(X86_BUG_SRBDS))
+		return;
+
+	/*
+	 * Check to see if this is one of the MDS_NO systems supporting TSX that
+	 * are only exposed to SRBDS when TSX is enabled or when CPU is affected
+	 * by Processor MMIO Stale Data vulnerability.
+	 */
+	if ((x86_arch_cap_msr & ARCH_CAP_MDS_NO) && !boot_cpu_has(X86_FEATURE_RTM) &&
+	    !boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
+		srbds_mitigation = SRBDS_MITIGATION_TSX_OFF;
+	else if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
+		srbds_mitigation = SRBDS_MITIGATION_HYPERVISOR;
+	else if (!boot_cpu_has(X86_FEATURE_SRBDS_CTRL))
+		srbds_mitigation = SRBDS_MITIGATION_UCODE_NEEDED;
+	else if (cpu_mitigations_off() || srbds_off)
+		srbds_mitigation = SRBDS_MITIGATION_OFF;
+
+	update_srbds_msr();
+	pr_info("%s\n", srbds_strings[srbds_mitigation]);
+}
+
+static int __init srbds_parse_cmdline(char *str)
+{
+	if (!str)
+		return -EINVAL;
+
+	if (!boot_cpu_has_bug(X86_BUG_SRBDS))
+		return 0;
+
+	srbds_off = !strcmp(str, "off");
+	return 0;
+}
+early_param("srbds", srbds_parse_cmdline);
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"GDS: " fmt
+
+enum gds_mitigations {
+	GDS_MITIGATION_OFF,
+	GDS_MITIGATION_UCODE_NEEDED,
+	GDS_MITIGATION_FULL,
+	GDS_MITIGATION_FULL_LOCKED,
+	GDS_MITIGATION_HYPERVISOR,
+};
+
+static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FULL;
+
+static const char * const gds_strings[] = {
+	[GDS_MITIGATION_OFF]		= "Vulnerable",
+	[GDS_MITIGATION_UCODE_NEEDED]	= "Vulnerable: No microcode",
+	[GDS_MITIGATION_FULL]		= "Mitigation: Microcode",
+	[GDS_MITIGATION_FULL_LOCKED]	= "Mitigation: Microcode (locked)",
+	[GDS_MITIGATION_HYPERVISOR]	= "Unknown: Dependent on hypervisor status",
+};
+
+bool gds_ucode_mitigated(void)
+{
+	return (gds_mitigation == GDS_MITIGATION_FULL ||
+		gds_mitigation == GDS_MITIGATION_FULL_LOCKED);
+}
+EXPORT_SYMBOL_GPL(gds_ucode_mitigated);
+
+void update_gds_msr(void)
+{
+	u64 mcu_ctrl_after;
+	u64 mcu_ctrl;
+
+	switch (gds_mitigation) {
+	case GDS_MITIGATION_OFF:
+		rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl);
+		mcu_ctrl |= GDS_MITG_DIS;
+		break;
+	case GDS_MITIGATION_FULL_LOCKED:
+		/*
+		 * The LOCKED state comes from the boot CPU. APs might not have
+		 * the same state. Make sure the mitigation is enabled on all
+		 * CPUs.
+		 */
+	case GDS_MITIGATION_FULL:
+		rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl);
+		mcu_ctrl &= ~GDS_MITG_DIS;
+		break;
+	case GDS_MITIGATION_UCODE_NEEDED:
+	case GDS_MITIGATION_HYPERVISOR:
+		return;
+	};
+
+	wrmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl);
+
+	/*
+	 * Check to make sure that the WRMSR value was not ignored. Writes to
+	 * GDS_MITG_DIS will be ignored if this processor is locked but the boot
+	 * processor was not.
+	 */
+	rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl_after);
+	WARN_ON_ONCE(mcu_ctrl != mcu_ctrl_after);
+}
+
+static void __init gds_select_mitigation(void)
+{
+	u64 mcu_ctrl;
+
+	if (!boot_cpu_has_bug(X86_BUG_GDS))
+		return;
+
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
+		gds_mitigation = GDS_MITIGATION_HYPERVISOR;
+		goto out;
+	}
+
+	if (cpu_mitigations_off())
+		gds_mitigation = GDS_MITIGATION_OFF;
+	/* Will verify below that mitigation _can_ be disabled */
+
+	/* No microcode */
+	if (!(x86_arch_cap_msr & ARCH_CAP_GDS_CTRL)) {
+		gds_mitigation = GDS_MITIGATION_UCODE_NEEDED;
+		goto out;
+	}
+
+	rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl);
+	if (mcu_ctrl & GDS_MITG_LOCKED) {
+		if (gds_mitigation == GDS_MITIGATION_OFF)
+			pr_warn("Mitigation locked. Disable failed.\n");
+
+		/*
+		 * The mitigation is selected from the boot CPU. All other CPUs
+		 * _should_ have the same state. If the boot CPU isn't locked
+		 * but others are then update_gds_msr() will WARN() of the state
+		 * mismatch. If the boot CPU is locked update_gds_msr() will
+		 * ensure the other CPUs have the mitigation enabled.
+		 */
+		gds_mitigation = GDS_MITIGATION_FULL_LOCKED;
+	}
+
+	update_gds_msr();
+out:
+	pr_info("%s\n", gds_strings[gds_mitigation]);
+}
+
+static int __init gds_parse_cmdline(char *str)
+{
+	if (!str)
+		return -EINVAL;
+
+	if (!boot_cpu_has_bug(X86_BUG_GDS))
+		return 0;
+
+	if (!strcmp(str, "off"))
+		gds_mitigation = GDS_MITIGATION_OFF;
+
+	return 0;
+}
+early_param("gather_data_sampling", gds_parse_cmdline);
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"VMSCAPE: " fmt
+
+enum vmscape_mitigations {
+	VMSCAPE_MITIGATION_NONE,
+	VMSCAPE_MITIGATION_AUTO,
+	VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER,
+};
+
+static enum vmscape_mitigations vmscape_mitigation __ro_after_init =
+	IS_ENABLED(CONFIG_MITIGATION_VMSCAPE) ? VMSCAPE_MITIGATION_AUTO : VMSCAPE_MITIGATION_NONE;
+
+static const char * const vmscape_strings[] = {
+	[VMSCAPE_MITIGATION_NONE]		= "Vulnerable",
+	/* [VMSCAPE_MITIGATION_AUTO] */
+	[VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER]	= "Mitigation: IBPB before exit to userspace",
+};
+
+static int __init vmscape_parse_cmdline(char *str)
+{
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "off")) {
+		vmscape_mitigation = VMSCAPE_MITIGATION_NONE;
+	} else if (!strcmp(str, "ibpb")) {
+		vmscape_mitigation = VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER;
+	} else if (!strcmp(str, "force")) {
+		setup_force_cpu_bug(X86_BUG_VMSCAPE);
+		vmscape_mitigation = VMSCAPE_MITIGATION_AUTO;
+	} else {
+		pr_err("Ignoring unknown vmscape=%s option.\n", str);
+	}
+
+	return 0;
+}
+early_param("vmscape", vmscape_parse_cmdline);
+
+static void __init vmscape_select_mitigation(void)
+{
+	if (cpu_mitigations_off() ||
+	    !boot_cpu_has_bug(X86_BUG_VMSCAPE) ||
+	    !boot_cpu_has(X86_FEATURE_IBPB)) {
+		vmscape_mitigation = VMSCAPE_MITIGATION_NONE;
+		return;
+	}
+
+	if (vmscape_mitigation == VMSCAPE_MITIGATION_AUTO)
+		vmscape_mitigation = VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER;
+
+	if (vmscape_mitigation == VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER)
+		setup_force_cpu_cap(X86_FEATURE_IBPB_EXIT_TO_USER);
+
+	pr_info("%s\n", vmscape_strings[vmscape_mitigation]);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Spectre V1 : " fmt
+
+enum spectre_v1_mitigation {
+	SPECTRE_V1_MITIGATION_NONE,
+	SPECTRE_V1_MITIGATION_AUTO,
+};
+
+static enum spectre_v1_mitigation spectre_v1_mitigation __ro_after_init =
+	SPECTRE_V1_MITIGATION_AUTO;
+
+static const char * const spectre_v1_strings[] = {
+	[SPECTRE_V1_MITIGATION_NONE] = "Vulnerable: __user pointer sanitization and usercopy barriers only; no swapgs barriers",
+	[SPECTRE_V1_MITIGATION_AUTO] = "Mitigation: usercopy/swapgs barriers and __user pointer sanitization",
+};
+
+/*
+ * Does SMAP provide full mitigation against speculative kernel access to
+ * userspace?
+ */
+static bool smap_works_speculatively(void)
+{
+	if (!boot_cpu_has(X86_FEATURE_SMAP))
+		return false;
+
+	/*
+	 * On CPUs which are vulnerable to Meltdown, SMAP does not
+	 * prevent speculative access to user data in the L1 cache.
+	 * Consider SMAP to be non-functional as a mitigation on these
+	 * CPUs.
 	 */
-	if (boot_cpu_data.x86 < 4)
-		panic("Kernel requires i486+ for 'invlpg' and other features");
+	if (boot_cpu_has(X86_BUG_CPU_MELTDOWN))
+		return false;
+
+	return true;
+}
+
+static void __init spectre_v1_select_mitigation(void)
+{
+	if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1) || cpu_mitigations_off()) {
+		spectre_v1_mitigation = SPECTRE_V1_MITIGATION_NONE;
+		return;
+	}
+
+	if (spectre_v1_mitigation == SPECTRE_V1_MITIGATION_AUTO) {
+		/*
+		 * With Spectre v1, a user can speculatively control either
+		 * path of a conditional swapgs with a user-controlled GS
+		 * value.  The mitigation is to add lfences to both code paths.
+		 *
+		 * If FSGSBASE is enabled, the user can put a kernel address in
+		 * GS, in which case SMAP provides no protection.
+		 *
+		 * [ NOTE: Don't check for X86_FEATURE_FSGSBASE until the
+		 *	   FSGSBASE enablement patches have been merged. ]
+		 *
+		 * If FSGSBASE is disabled, the user can only put a user space
+		 * address in GS.  That makes an attack harder, but still
+		 * possible if there's no SMAP protection.
+		 */
+		if (!smap_works_speculatively()) {
+			/*
+			 * Mitigation can be provided from SWAPGS itself or
+			 * PTI as the CR3 write in the Meltdown mitigation
+			 * is serializing.
+			 *
+			 * If neither is there, mitigate with an LFENCE to
+			 * stop speculation through swapgs.
+			 */
+			if (boot_cpu_has_bug(X86_BUG_SWAPGS) &&
+			    !boot_cpu_has(X86_FEATURE_KAISER))
+				setup_force_cpu_cap(X86_FEATURE_FENCE_SWAPGS_USER);
+
+			/*
+			 * Enable lfences in the kernel entry (non-swapgs)
+			 * paths, to prevent user entry from speculatively
+			 * skipping swapgs.
+			 */
+			setup_force_cpu_cap(X86_FEATURE_FENCE_SWAPGS_KERNEL);
+		}
+	}
+
+	pr_info("%s\n", spectre_v1_strings[spectre_v1_mitigation]);
+}
+
+static int __init nospectre_v1_cmdline(char *str)
+{
+	spectre_v1_mitigation = SPECTRE_V1_MITIGATION_NONE;
+	return 0;
+}
+early_param("nospectre_v1", nospectre_v1_cmdline);
 
-	init_utsname()->machine[1] =
-		'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
-	alternative_instructions();
+static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
+	SPECTRE_V2_NONE;
 
-	fpu__init_check_bugs();
+#undef pr_fmt
+#define pr_fmt(fmt)     "RETBleed: " fmt
+
+enum retbleed_mitigation {
+	RETBLEED_MITIGATION_NONE,
+	RETBLEED_MITIGATION_IBRS,
+	RETBLEED_MITIGATION_EIBRS,
+};
+
+enum retbleed_mitigation_cmd {
+	RETBLEED_CMD_OFF,
+	RETBLEED_CMD_AUTO
+};
+
+const char * const retbleed_strings[] = {
+	[RETBLEED_MITIGATION_NONE]	= "Vulnerable",
+	[RETBLEED_MITIGATION_IBRS]	= "Mitigation: IBRS",
+	[RETBLEED_MITIGATION_EIBRS]	= "Mitigation: Enhanced IBRS",
+};
+
+static enum retbleed_mitigation retbleed_mitigation __ro_after_init =
+	RETBLEED_MITIGATION_NONE;
+static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init =
+	RETBLEED_CMD_AUTO;
+
+static int __init retbleed_parse_cmdline(char *str)
+{
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "off"))
+		retbleed_cmd = RETBLEED_CMD_OFF;
+	else if (!strcmp(str, "auto"))
+		retbleed_cmd = RETBLEED_CMD_AUTO;
+	else
+		pr_err("Unknown retbleed option (%s). Defaulting to 'auto'\n", str);
+
+	return 0;
 }
+early_param("retbleed", retbleed_parse_cmdline);
+
+#define RETBLEED_INTEL_MSG "WARNING: Spectre v2 mitigation leaves CPU vulnerable to RETBleed attacks, data leaks possible!\n"
+
+static void __init retbleed_select_mitigation(void)
+{
+	if (!boot_cpu_has_bug(X86_BUG_RETBLEED) || cpu_mitigations_off())
+		return;
+
+	switch (retbleed_cmd) {
+	case RETBLEED_CMD_OFF:
+		return;
+
+	case RETBLEED_CMD_AUTO:
+	default:
+		/*
+		 * The Intel mitigation (IBRS) was already selected in
+		 * spectre_v2_select_mitigation().
+		 */
+
+		break;
+	}
+
+	switch (retbleed_mitigation) {
+	default:
+		break;
+	}
+
+	/*
+	 * Let IBRS trump all on Intel without affecting the effects of the
+	 * retbleed= cmdline option.
+	 */
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+		switch (spectre_v2_enabled) {
+		case SPECTRE_V2_IBRS:
+			retbleed_mitigation = RETBLEED_MITIGATION_IBRS;
+			break;
+		case SPECTRE_V2_EIBRS:
+		case SPECTRE_V2_EIBRS_RETPOLINE:
+		case SPECTRE_V2_EIBRS_LFENCE:
+			retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
+			break;
+		default:
+			pr_err(RETBLEED_INTEL_MSG);
+		}
+	}
+
+	pr_info("%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Spectre V2 : " fmt
+
+static enum spectre_v2_user_mitigation spectre_v2_user_stibp __ro_after_init =
+	SPECTRE_V2_USER_NONE;
+static enum spectre_v2_user_mitigation spectre_v2_user_ibpb __ro_after_init =
+	SPECTRE_V2_USER_NONE;
+
+#ifdef RETPOLINE
+static bool spectre_v2_bad_module;
+
+bool retpoline_module_ok(bool has_retpoline)
+{
+	if (spectre_v2_enabled == SPECTRE_V2_NONE || has_retpoline)
+		return true;
+
+	pr_err("System may be vulnerable to spectre v2\n");
+	spectre_v2_bad_module = true;
+	return false;
+}
+
+static inline const char *spectre_v2_module_string(void)
+{
+	return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+}
+#else
+static inline const char *spectre_v2_module_string(void) { return ""; }
+#endif
+
+#define SPECTRE_V2_IBRS_PERF_MSG "WARNING: IBRS mitigation selected on Enhanced IBRS CPU, this may cause unnecessary performance loss\n"
+
+static inline bool match_option(const char *arg, int arglen, const char *opt)
+{
+	int len = strlen(opt);
+
+	return len == arglen && !strncmp(arg, opt, len);
+}
+
+/* The kernel command line selection for spectre v2 */
+enum spectre_v2_mitigation_cmd {
+	SPECTRE_V2_CMD_NONE,
+	SPECTRE_V2_CMD_AUTO,
+	SPECTRE_V2_CMD_FORCE,
+	SPECTRE_V2_CMD_RETPOLINE,
+	SPECTRE_V2_CMD_RETPOLINE_GENERIC,
+	SPECTRE_V2_CMD_RETPOLINE_LFENCE,
+	SPECTRE_V2_CMD_EIBRS,
+	SPECTRE_V2_CMD_EIBRS_RETPOLINE,
+	SPECTRE_V2_CMD_EIBRS_LFENCE,
+	SPECTRE_V2_CMD_IBRS,
+};
+
+enum spectre_v2_user_cmd {
+	SPECTRE_V2_USER_CMD_NONE,
+	SPECTRE_V2_USER_CMD_AUTO,
+	SPECTRE_V2_USER_CMD_FORCE,
+	SPECTRE_V2_USER_CMD_PRCTL,
+	SPECTRE_V2_USER_CMD_PRCTL_IBPB,
+	SPECTRE_V2_USER_CMD_SECCOMP,
+	SPECTRE_V2_USER_CMD_SECCOMP_IBPB,
+};
+
+static const char * const spectre_v2_user_strings[] = {
+	[SPECTRE_V2_USER_NONE]			= "User space: Vulnerable",
+	[SPECTRE_V2_USER_STRICT]		= "User space: Mitigation: STIBP protection",
+	[SPECTRE_V2_USER_STRICT_PREFERRED]	= "User space: Mitigation: STIBP always-on protection",
+	[SPECTRE_V2_USER_PRCTL]			= "User space: Mitigation: STIBP via prctl",
+	[SPECTRE_V2_USER_SECCOMP]		= "User space: Mitigation: STIBP via seccomp and prctl",
+};
+
+static const struct {
+	const char			*option;
+	enum spectre_v2_user_cmd	cmd;
+	bool				secure;
+} v2_user_options[] __initconst = {
+	{ "auto",		SPECTRE_V2_USER_CMD_AUTO,		false },
+	{ "off",		SPECTRE_V2_USER_CMD_NONE,		false },
+	{ "on",			SPECTRE_V2_USER_CMD_FORCE,		true  },
+	{ "prctl",		SPECTRE_V2_USER_CMD_PRCTL,		false },
+	{ "prctl,ibpb",		SPECTRE_V2_USER_CMD_PRCTL_IBPB,		false },
+	{ "seccomp",		SPECTRE_V2_USER_CMD_SECCOMP,		false },
+	{ "seccomp,ibpb",	SPECTRE_V2_USER_CMD_SECCOMP_IBPB,	false },
+};
+
+static void __init spec_v2_user_print_cond(const char *reason, bool secure)
+{
+	if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2) != secure)
+		pr_info("spectre_v2_user=%s forced on command line.\n", reason);
+}
+
+static __ro_after_init enum spectre_v2_mitigation_cmd spectre_v2_cmd;
+
+static enum spectre_v2_user_cmd __init
+spectre_v2_parse_user_cmdline(void)
+{
+	char arg[20];
+	int ret, i;
+
+	switch (spectre_v2_cmd) {
+	case SPECTRE_V2_CMD_NONE:
+		return SPECTRE_V2_USER_CMD_NONE;
+	case SPECTRE_V2_CMD_FORCE:
+		return SPECTRE_V2_USER_CMD_FORCE;
+	default:
+		break;
+	}
+
+	ret = cmdline_find_option(boot_command_line, "spectre_v2_user",
+				  arg, sizeof(arg));
+	if (ret < 0)
+		return SPECTRE_V2_USER_CMD_AUTO;
+
+	for (i = 0; i < ARRAY_SIZE(v2_user_options); i++) {
+		if (match_option(arg, ret, v2_user_options[i].option)) {
+			spec_v2_user_print_cond(v2_user_options[i].option,
+						v2_user_options[i].secure);
+			return v2_user_options[i].cmd;
+		}
+	}
+
+	pr_err("Unknown user space protection option (%s). Switching to AUTO select\n", arg);
+	return SPECTRE_V2_USER_CMD_AUTO;
+}
+
+static inline bool spectre_v2_in_eibrs_mode(enum spectre_v2_mitigation mode)
+{
+	return mode == SPECTRE_V2_EIBRS ||
+	       mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+	       mode == SPECTRE_V2_EIBRS_LFENCE;
+}
+
+static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
+{
+	return spectre_v2_in_eibrs_mode(mode) || mode == SPECTRE_V2_IBRS;
+}
+
+static void __init
+spectre_v2_user_select_mitigation(void)
+{
+	enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE;
+	bool smt_possible = IS_ENABLED(CONFIG_SMP);
+	enum spectre_v2_user_cmd cmd;
+
+	if (!boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_STIBP))
+		return;
+
+	if (cpu_smt_control == CPU_SMT_FORCE_DISABLED ||
+	    cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
+		smt_possible = false;
+
+	cmd = spectre_v2_parse_user_cmdline();
+	switch (cmd) {
+	case SPECTRE_V2_USER_CMD_NONE:
+		goto set_mode;
+	case SPECTRE_V2_USER_CMD_FORCE:
+		mode = SPECTRE_V2_USER_STRICT;
+		break;
+	case SPECTRE_V2_USER_CMD_PRCTL:
+	case SPECTRE_V2_USER_CMD_PRCTL_IBPB:
+		mode = SPECTRE_V2_USER_PRCTL;
+		break;
+	case SPECTRE_V2_USER_CMD_AUTO:
+	case SPECTRE_V2_USER_CMD_SECCOMP:
+	case SPECTRE_V2_USER_CMD_SECCOMP_IBPB:
+		if (IS_ENABLED(CONFIG_SECCOMP))
+			mode = SPECTRE_V2_USER_SECCOMP;
+		else
+			mode = SPECTRE_V2_USER_PRCTL;
+		break;
+	}
+
+	/* Initialize Indirect Branch Prediction Barrier */
+	if (boot_cpu_has(X86_FEATURE_IBPB)) {
+		setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
+
+		spectre_v2_user_ibpb = mode;
+		switch (cmd) {
+		case SPECTRE_V2_USER_CMD_FORCE:
+		case SPECTRE_V2_USER_CMD_PRCTL_IBPB:
+		case SPECTRE_V2_USER_CMD_SECCOMP_IBPB:
+			static_branch_enable(&switch_mm_always_ibpb);
+			spectre_v2_user_ibpb = SPECTRE_V2_USER_STRICT;
+			break;
+		case SPECTRE_V2_USER_CMD_PRCTL:
+		case SPECTRE_V2_USER_CMD_AUTO:
+		case SPECTRE_V2_USER_CMD_SECCOMP:
+			static_branch_enable(&switch_mm_cond_ibpb);
+			break;
+		default:
+			break;
+		}
+
+		pr_info("mitigation: Enabling %s Indirect Branch Prediction Barrier\n",
+			static_key_enabled(&switch_mm_always_ibpb) ?
+			"always-on" : "conditional");
+
+		if (!noibpb)
+			set_ibpb_enabled(1);   /* Enable IBPB */
+	}
+
+	/*
+	 * If no STIBP, enhanced IBRS is enabled, or SMT impossible, STIBP
+	 * is not required.
+	 *
+	 * Enhanced IBRS also protects against cross-thread branch target
+	 * injection in user-mode as the IBRS bit remains always set which
+	 * implicitly enables cross-thread protections.  However, in legacy IBRS
+	 * mode, the IBRS bit is set only on kernel entry and cleared on return
+	 * to userspace. This disables the implicit cross-thread protection,
+	 * so allow for STIBP to be selected in that case.
+	 */
+	if (!boot_cpu_has(X86_FEATURE_STIBP) ||
+	    !smt_possible ||
+	    spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+		return;
+
+	/*
+	 * At this point, an STIBP mode other than "off" has been set.
+	 * If STIBP support is not being forced, check if STIBP always-on
+	 * is preferred.
+	 */
+	if (mode != SPECTRE_V2_USER_STRICT &&
+	    boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
+		mode = SPECTRE_V2_USER_STRICT_PREFERRED;
+
+	spectre_v2_user_stibp = mode;
+
+set_mode:
+	pr_info("%s\n", spectre_v2_user_strings[mode]);
+}
+
+static const char * const spectre_v2_strings[] = {
+	[SPECTRE_V2_NONE]			= "Vulnerable",
+	[SPECTRE_V2_RETPOLINE]			= "Mitigation: Retpolines",
+	[SPECTRE_V2_LFENCE]			= "Mitigation: LFENCE",
+	[SPECTRE_V2_EIBRS]			= "Mitigation: Enhanced IBRS",
+	[SPECTRE_V2_EIBRS_LFENCE]		= "Mitigation: Enhanced IBRS + LFENCE",
+	[SPECTRE_V2_EIBRS_RETPOLINE]		= "Mitigation: Enhanced IBRS + Retpolines",
+	[SPECTRE_V2_IBRS]			= "Mitigation: IBRS",
+};
+
+static const struct {
+	const char *option;
+	enum spectre_v2_mitigation_cmd cmd;
+	bool secure;
+} mitigation_options[] __initconst = {
+	{ "off",		SPECTRE_V2_CMD_NONE,		  false },
+	{ "on",			SPECTRE_V2_CMD_FORCE,		  true  },
+	{ "retpoline",		SPECTRE_V2_CMD_RETPOLINE,	  false },
+	{ "retpoline,amd",	SPECTRE_V2_CMD_RETPOLINE_LFENCE,  false },
+	{ "retpoline,lfence",	SPECTRE_V2_CMD_RETPOLINE_LFENCE,  false },
+	{ "retpoline,generic",	SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
+	{ "eibrs",		SPECTRE_V2_CMD_EIBRS,		  false },
+	{ "eibrs,lfence",	SPECTRE_V2_CMD_EIBRS_LFENCE,	  false },
+	{ "eibrs,retpoline",	SPECTRE_V2_CMD_EIBRS_RETPOLINE,	  false },
+	{ "auto",		SPECTRE_V2_CMD_AUTO,		  false },
+	{ "ibrs",		SPECTRE_V2_CMD_IBRS,              false },
+};
+
+static void __init spec_v2_print_cond(const char *reason, bool secure)
+{
+	if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2) != secure)
+		pr_info("%s selected on command line.\n", reason);
+}
+
+static inline bool retp_compiler(void)
+{
+	return __is_defined(RETPOLINE);
+}
+
+static const char *spectre_v2_retp(enum spectre_v2_mitigation mode)
+{
+	switch (mode) {
+	case SPECTRE_V2_RETPOLINE:
+	case SPECTRE_V2_LFENCE:
+	case SPECTRE_V2_EIBRS_LFENCE:
+	case SPECTRE_V2_EIBRS_RETPOLINE:
+		if (!retp_compiler())
+			return " (minimal)";
+		/* fallthrough */
+	default:
+		return "";
+	}
+}
+
+static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
+{
+	enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO;
+	char arg[20];
+	int ret, i;
+
+	if (cmdline_find_option_bool(boot_command_line, "nospectre_v2") ||
+	    cpu_mitigations_off())
+		return SPECTRE_V2_CMD_NONE;
+
+	ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg));
+	if (ret < 0)
+		return SPECTRE_V2_CMD_AUTO;
+
+	for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) {
+		if (!match_option(arg, ret, mitigation_options[i].option))
+			continue;
+		cmd = mitigation_options[i].cmd;
+		break;
+	}
+
+	if (i >= ARRAY_SIZE(mitigation_options)) {
+		pr_err("unknown option (%s). Switching to AUTO select\n", arg);
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
+	     cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
+	     cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC ||
+	     cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
+	     cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
+	    !IS_ENABLED(CONFIG_RETPOLINE)) {
+		pr_err("%s selected but not compiled in. Switching to AUTO select\n",
+		       mitigation_options[i].option);
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if ((cmd == SPECTRE_V2_CMD_EIBRS ||
+	     cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
+	     cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
+	    !boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
+		pr_err("%s selected but CPU doesn't have eIBRS. Switching to AUTO select\n",
+		       mitigation_options[i].option);
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if ((cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
+	     cmd == SPECTRE_V2_CMD_EIBRS_LFENCE) &&
+	    !boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
+		pr_err("%s selected, but CPU doesn't have a serializing LFENCE. Switching to AUTO select\n",
+		       mitigation_options[i].option);
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
+		pr_err("%s selected but not Intel CPU. Switching to AUTO select\n",
+		       mitigation_options[i].option);
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if (cmd == SPECTRE_V2_CMD_IBRS && !boot_cpu_has(X86_FEATURE_IBRS)) {
+		pr_err("%s selected but CPU doesn't have IBRS. Switching to AUTO select\n",
+		       mitigation_options[i].option);
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_has(X86_FEATURE_XENPV)) {
+		pr_err("%s selected but running as XenPV guest. Switching to AUTO select\n",
+		       mitigation_options[i].option);
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	spec_v2_print_cond(mitigation_options[i].option,
+			   mitigation_options[i].secure);
+	return cmd;
+}
+
+static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
+{
+	if (!IS_ENABLED(CONFIG_RETPOLINE)) {
+		pr_err("Kernel not compiled with retpoline; no mitigation available!");
+		return SPECTRE_V2_NONE;
+	}
+
+	return SPECTRE_V2_RETPOLINE;
+}
+
+static bool __ro_after_init rrsba_disabled;
+
+/* Disable in-kernel use of non-RSB RET predictors */
+static void __init spec_ctrl_disable_kernel_rrsba(void)
+{
+	if (rrsba_disabled)
+		return;
+
+	if (!(x86_arch_cap_msr & ARCH_CAP_RRSBA)) {
+		rrsba_disabled = true;
+		return;
+	}
+
+	if (!boot_cpu_has(X86_FEATURE_RRSBA_CTRL))
+		return;
+
+	x86_spec_ctrl_base |= SPEC_CTRL_RRSBA_DIS_S;
+	update_spec_ctrl(x86_spec_ctrl_base);
+	rrsba_disabled = true;
+}
+
+static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_mitigation mode)
+{
+	/*
+	 * Similar to context switches, there are two types of RSB attacks
+	 * after VM exit:
+	 *
+	 * 1) RSB underflow
+	 *
+	 * 2) Poisoned RSB entry
+	 *
+	 * When retpoline is enabled, both are mitigated by filling/clearing
+	 * the RSB.
+	 *
+	 * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
+	 * prediction isolation protections, RSB still needs to be cleared
+	 * because of #2.  Note that SMEP provides no protection here, unlike
+	 * user-space-poisoned RSB entries.
+	 *
+	 * eIBRS should protect against RSB poisoning, but if the EIBRS_PBRSB
+	 * bug is present then a LITE version of RSB protection is required,
+	 * just a single call needs to retire before a RET is executed.
+	 */
+	switch (mode) {
+	case SPECTRE_V2_NONE:
+		return;
+
+	case SPECTRE_V2_EIBRS_LFENCE:
+	case SPECTRE_V2_EIBRS:
+		if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB) &&
+		    (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)) {
+			setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT_LITE);
+			pr_info("Spectre v2 / PBRSB-eIBRS: Retire a single CALL on VMEXIT\n");
+		}
+		return;
+
+	case SPECTRE_V2_EIBRS_RETPOLINE:
+	case SPECTRE_V2_RETPOLINE:
+	case SPECTRE_V2_LFENCE:
+	case SPECTRE_V2_IBRS:
+		setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+		pr_info("Spectre v2 / SpectreRSB : Filling RSB on VMEXIT\n");
+		return;
+	}
+
+	pr_warn_once("Unknown Spectre v2 mode, disabling RSB mitigation at VM exit");
+	dump_stack();
+}
+
+/*
+ * Set BHI_DIS_S to prevent indirect branches in kernel to be influenced by
+ * branch history in userspace. Not needed if BHI_NO is set.
+ */
+static bool __init spec_ctrl_bhi_dis(void)
+{
+	if (!boot_cpu_has(X86_FEATURE_BHI_CTRL))
+		return false;
+
+	x86_spec_ctrl_base |= SPEC_CTRL_BHI_DIS_S;
+	update_spec_ctrl(x86_spec_ctrl_base);
+	setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_HW);
+
+	return true;
+}
+
+enum bhi_mitigations {
+	BHI_MITIGATION_OFF,
+	BHI_MITIGATION_ON,
+	BHI_MITIGATION_AUTO,
+};
+
+static enum bhi_mitigations bhi_mitigation __ro_after_init =
+	IS_ENABLED(CONFIG_SPECTRE_BHI_ON)  ? BHI_MITIGATION_ON  :
+	IS_ENABLED(CONFIG_SPECTRE_BHI_OFF) ? BHI_MITIGATION_OFF :
+					     BHI_MITIGATION_AUTO;
+
+static int __init spectre_bhi_parse_cmdline(char *str)
+{
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "off"))
+		bhi_mitigation = BHI_MITIGATION_OFF;
+	else if (!strcmp(str, "on"))
+		bhi_mitigation = BHI_MITIGATION_ON;
+	else if (!strcmp(str, "auto"))
+		bhi_mitigation = BHI_MITIGATION_AUTO;
+	else
+		pr_err("Ignoring unknown spectre_bhi option (%s)", str);
+
+	return 0;
+}
+early_param("spectre_bhi", spectre_bhi_parse_cmdline);
+
+static void __init bhi_select_mitigation(void)
+{
+	if (bhi_mitigation == BHI_MITIGATION_OFF)
+		return;
+
+	/* Retpoline mitigates against BHI unless the CPU has RRSBA behavior */
+	if (boot_cpu_has(X86_FEATURE_RETPOLINE) &&
+	    !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) {
+		spec_ctrl_disable_kernel_rrsba();
+		if (rrsba_disabled)
+			return;
+	}
+
+	if (spec_ctrl_bhi_dis())
+		return;
+
+	if (!IS_ENABLED(CONFIG_X86_64))
+		return;
+
+	/* Mitigate KVM by default */
+	setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT);
+	pr_info("Spectre BHI mitigation: SW BHB clearing on vm exit\n");
+
+	if (bhi_mitigation == BHI_MITIGATION_AUTO)
+		return;
+
+	/* Mitigate syscalls when the mitigation is forced =on */
+	setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP);
+	pr_info("Spectre BHI mitigation: SW BHB clearing on syscall\n");
+}
+
+static void __init spectre_v2_select_mitigation(void)
+{
+	enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
+	enum spectre_v2_mitigation mode = SPECTRE_V2_NONE;
+
+	/*
+	 * If the CPU is not affected and the command line mode is NONE or AUTO
+	 * then nothing to do.
+	 */
+	if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) &&
+	    (cmd == SPECTRE_V2_CMD_NONE || cmd == SPECTRE_V2_CMD_AUTO))
+		return;
+
+	switch (cmd) {
+	case SPECTRE_V2_CMD_NONE:
+		return;
+
+	case SPECTRE_V2_CMD_FORCE:
+	case SPECTRE_V2_CMD_AUTO:
+		if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
+			mode = SPECTRE_V2_EIBRS;
+			break;
+		}
+
+		if (boot_cpu_has_bug(X86_BUG_RETBLEED) &&
+		    retbleed_cmd != RETBLEED_CMD_OFF &&
+		    boot_cpu_has(X86_FEATURE_IBRS) &&
+		    boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+			mode = SPECTRE_V2_IBRS;
+			break;
+		}
+
+		mode = spectre_v2_select_retpoline();
+		break;
+
+	case SPECTRE_V2_CMD_RETPOLINE_LFENCE:
+		mode = SPECTRE_V2_LFENCE;
+		break;
+
+	case SPECTRE_V2_CMD_RETPOLINE_GENERIC:
+		mode = SPECTRE_V2_RETPOLINE;
+		break;
+
+	case SPECTRE_V2_CMD_RETPOLINE:
+		mode = spectre_v2_select_retpoline();
+		break;
+
+	case SPECTRE_V2_CMD_IBRS:
+		mode = SPECTRE_V2_IBRS;
+		break;
+
+	case SPECTRE_V2_CMD_EIBRS:
+		mode = SPECTRE_V2_EIBRS;
+		break;
+
+	case SPECTRE_V2_CMD_EIBRS_LFENCE:
+		mode = SPECTRE_V2_EIBRS_LFENCE;
+		break;
+
+	case SPECTRE_V2_CMD_EIBRS_RETPOLINE:
+		mode = SPECTRE_V2_EIBRS_RETPOLINE;
+		break;
+	}
+
+	if (spectre_v2_in_ibrs_mode(mode)) {
+		x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
+		update_spec_ctrl(x86_spec_ctrl_base);
+	}
+
+	switch (mode) {
+	case SPECTRE_V2_NONE:
+	case SPECTRE_V2_EIBRS:
+		break;
+
+	case SPECTRE_V2_IBRS:
+		setup_force_cpu_cap(X86_FEATURE_KERNEL_IBRS);
+		if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED))
+			pr_warn(SPECTRE_V2_IBRS_PERF_MSG);
+		break;
+
+	case SPECTRE_V2_LFENCE:
+	case SPECTRE_V2_EIBRS_LFENCE:
+		setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
+		/* fallthrough */
+
+	case SPECTRE_V2_RETPOLINE:
+	case SPECTRE_V2_EIBRS_RETPOLINE:
+		setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
+		break;
+	}
+
+	/*
+	 * Disable alternate RSB predictions in kernel when indirect CALLs and
+	 * JMPs gets protection against BHI and Intramode-BTI, but RET
+	 * prediction from a non-RSB predictor is still a risk.
+	 */
+	if (mode == SPECTRE_V2_EIBRS_LFENCE ||
+	    mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+	    mode == SPECTRE_V2_RETPOLINE)
+		spec_ctrl_disable_kernel_rrsba();
+
+	if (boot_cpu_has(X86_BUG_BHI))
+		bhi_select_mitigation();
+
+	spectre_v2_enabled = mode;
+	pr_info("%s%s\n", spectre_v2_strings[mode], spectre_v2_retp(mode));
+
+	/*
+	 * If Spectre v2 protection has been enabled, fill the RSB during a
+	 * context switch.  In general there are two types of RSB attacks
+	 * across context switches, for which the CALLs/RETs may be unbalanced.
+	 *
+	 * 1) RSB underflow
+	 *
+	 *    Some Intel parts have "bottomless RSB".  When the RSB is empty,
+	 *    speculated return targets may come from the branch predictor,
+	 *    which could have a user-poisoned BTB or BHB entry.
+	 *
+	 *    AMD has it even worse: *all* returns are speculated from the BTB,
+	 *    regardless of the state of the RSB.
+	 *
+	 *    When IBRS or eIBRS is enabled, the "user -> kernel" attack
+	 *    scenario is mitigated by the IBRS branch prediction isolation
+	 *    properties, so the RSB buffer filling wouldn't be necessary to
+	 *    protect against this type of attack.
+	 *
+	 *    The "user -> user" attack scenario is mitigated by RSB filling.
+	 *
+	 * 2) Poisoned RSB entry
+	 *
+	 *    If the 'next' in-kernel return stack is shorter than 'prev',
+	 *    'next' could be tricked into speculating with a user-poisoned RSB
+	 *    entry.
+	 *
+	 *    The "user -> kernel" attack scenario is mitigated by SMEP and
+	 *    eIBRS.
+	 *
+	 *    The "user -> user" scenario, also known as SpectreBHB, requires
+	 *    RSB clearing.
+	 *
+	 * So to mitigate all cases, unconditionally fill RSB on context
+	 * switches.
+	 *
+	 * FIXME: Is this pointless for retbleed-affected AMD?
+	 */
+	setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
+	pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
+
+	spectre_v2_determine_rsb_fill_type_at_vmexit(mode);
+
+	/*
+	 * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
+	 * and Enhanced IBRS protect firmware too, so enable IBRS around
+	 * firmware calls only when IBRS / Enhanced IBRS aren't otherwise
+	 * enabled.
+	 *
+	 * Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
+	 * the user might select retpoline on the kernel command line and if
+	 * the CPU supports Enhanced IBRS, kernel might un-intentionally not
+	 * enable IBRS around firmware calls.
+	 */
+	if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_ibrs_mode(mode)) {
+		setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
+		pr_info("Enabling Restricted Speculation for firmware calls\n");
+
+		if (!noibrs &&
+		    mode != SPECTRE_V2_RETPOLINE &&
+		    mode != SPECTRE_V2_LFENCE)
+			set_ibrs_enabled(1);   /* Enable IBRS */
+	}
+
+	/* Set up IBPB and STIBP depending on the general spectre V2 command */
+	spectre_v2_cmd = cmd;
+}
+
+static void update_stibp_msr(void * __unused)
+{
+	u64 val = spec_ctrl_current() | (x86_spec_ctrl_base & SPEC_CTRL_STIBP);
+	update_spec_ctrl(val);
+}
+
+/* Update x86_spec_ctrl_base in case SMT state changed. */
+static void update_stibp_strict(void)
+{
+	u64 mask = x86_spec_ctrl_base & ~SPEC_CTRL_STIBP;
+
+	if (sched_smt_active())
+		mask |= SPEC_CTRL_STIBP;
+
+	if (mask == x86_spec_ctrl_base)
+		return;
+
+	pr_info("Update user space SMT mitigation: STIBP %s\n",
+		mask & SPEC_CTRL_STIBP ? "always-on" : "off");
+	x86_spec_ctrl_base = mask;
+	on_each_cpu(update_stibp_msr, NULL, 1);
+}
+
+/* Update the static key controlling the evaluation of TIF_SPEC_IB */
+static void update_indir_branch_cond(void)
+{
+	if (sched_smt_active())
+		static_branch_enable(&switch_to_cond_stibp);
+	else
+		static_branch_disable(&switch_to_cond_stibp);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt) fmt
+
+/* Update the static key controlling the MDS CPU buffer clear in idle */
+static void update_mds_branch_idle(void)
+{
+	/*
+	 * Enable the idle clearing if SMT is active on CPUs which are
+	 * affected only by MSBDS and not any other MDS variant.
+	 *
+	 * The other variants cannot be mitigated when SMT is enabled, so
+	 * clearing the buffers on idle just to prevent the Store Buffer
+	 * repartitioning leak would be a window dressing exercise.
+	 */
+	if (!boot_cpu_has_bug(X86_BUG_MSBDS_ONLY))
+		return;
+
+	if (sched_smt_active()) {
+		static_branch_enable(&mds_idle_clear);
+	} else if (mmio_mitigation == MMIO_MITIGATION_OFF ||
+		   (x86_arch_cap_msr & ARCH_CAP_FBSDP_NO)) {
+		static_branch_disable(&mds_idle_clear);
+	}
+}
+
+#define MDS_MSG_SMT "MDS CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html for more details.\n"
+#define TAA_MSG_SMT "TAA CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/tsx_async_abort.html for more details.\n"
+#define MMIO_MSG_SMT "MMIO Stale Data CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/processor_mmio_stale_data.html for more details.\n"
+#define VMSCAPE_MSG_SMT "VMSCAPE: SMT on, STIBP is required for full protection. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/vmscape.html for more details.\n"
+
+void arch_smt_update(void)
+{
+	mutex_lock(&spec_ctrl_mutex);
+
+	switch (spectre_v2_user_stibp) {
+	case SPECTRE_V2_USER_NONE:
+		break;
+	case SPECTRE_V2_USER_STRICT:
+	case SPECTRE_V2_USER_STRICT_PREFERRED:
+		update_stibp_strict();
+		break;
+	case SPECTRE_V2_USER_PRCTL:
+	case SPECTRE_V2_USER_SECCOMP:
+		update_indir_branch_cond();
+		break;
+	}
+
+	if (vmscape_mitigation == VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER &&
+	    sched_smt_active() &&
+	    spectre_v2_user_stibp != SPECTRE_V2_USER_STRICT &&
+	    spectre_v2_user_stibp != SPECTRE_V2_USER_STRICT_PREFERRED &&
+	    !spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+		pr_warn_once(VMSCAPE_MSG_SMT);
+
+	switch (mds_mitigation) {
+	case MDS_MITIGATION_FULL:
+	case MDS_MITIGATION_VMWERV:
+		if (sched_smt_active() && !boot_cpu_has(X86_BUG_MSBDS_ONLY))
+			pr_warn_once(MDS_MSG_SMT);
+		update_mds_branch_idle();
+		break;
+	case MDS_MITIGATION_OFF:
+		break;
+	}
+
+	switch (taa_mitigation) {
+	case TAA_MITIGATION_VERW:
+	case TAA_MITIGATION_UCODE_NEEDED:
+		if (sched_smt_active())
+			pr_warn_once(TAA_MSG_SMT);
+		break;
+	case TAA_MITIGATION_TSX_DISABLED:
+	case TAA_MITIGATION_OFF:
+		break;
+	}
+
+	switch (mmio_mitigation) {
+	case MMIO_MITIGATION_VERW:
+	case MMIO_MITIGATION_UCODE_NEEDED:
+		if (sched_smt_active())
+			pr_warn_once(MMIO_MSG_SMT);
+		break;
+	case MMIO_MITIGATION_OFF:
+		break;
+	}
+
+	mutex_unlock(&spec_ctrl_mutex);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"Speculative Store Bypass: " fmt
+
+static enum ssb_mitigation ssb_mode __ro_after_init = SPEC_STORE_BYPASS_NONE;
+
+/* The kernel command line selection */
+enum ssb_mitigation_cmd {
+	SPEC_STORE_BYPASS_CMD_NONE,
+	SPEC_STORE_BYPASS_CMD_AUTO,
+	SPEC_STORE_BYPASS_CMD_ON,
+	SPEC_STORE_BYPASS_CMD_PRCTL,
+	SPEC_STORE_BYPASS_CMD_SECCOMP,
+};
+
+static const char * const ssb_strings[] = {
+	[SPEC_STORE_BYPASS_NONE]	= "Vulnerable",
+	[SPEC_STORE_BYPASS_DISABLE]	= "Mitigation: Speculative Store Bypass disabled",
+	[SPEC_STORE_BYPASS_PRCTL]	= "Mitigation: Speculative Store Bypass disabled via prctl",
+	[SPEC_STORE_BYPASS_SECCOMP]	= "Mitigation: Speculative Store Bypass disabled via prctl and seccomp",
+};
+
+static const struct {
+	const char *option;
+	enum ssb_mitigation_cmd cmd;
+} ssb_mitigation_options[]  __initconst = {
+	{ "auto",	SPEC_STORE_BYPASS_CMD_AUTO },    /* Platform decides */
+	{ "on",		SPEC_STORE_BYPASS_CMD_ON },      /* Disable Speculative Store Bypass */
+	{ "off",	SPEC_STORE_BYPASS_CMD_NONE },    /* Don't touch Speculative Store Bypass */
+	{ "prctl",	SPEC_STORE_BYPASS_CMD_PRCTL },   /* Disable Speculative Store Bypass via prctl */
+	{ "seccomp",	SPEC_STORE_BYPASS_CMD_SECCOMP }, /* Disable Speculative Store Bypass via prctl and seccomp */
+};
+
+static enum ssb_mitigation_cmd __init ssb_parse_cmdline(void)
+{
+	enum ssb_mitigation_cmd cmd = SPEC_STORE_BYPASS_CMD_AUTO;
+	char arg[20];
+	int ret, i;
+
+	if (cmdline_find_option_bool(boot_command_line, "nospec_store_bypass_disable") ||
+	    cpu_mitigations_off()) {
+		return SPEC_STORE_BYPASS_CMD_NONE;
+	} else {
+		ret = cmdline_find_option(boot_command_line, "spec_store_bypass_disable",
+					  arg, sizeof(arg));
+		if (ret < 0)
+			return SPEC_STORE_BYPASS_CMD_AUTO;
+
+		for (i = 0; i < ARRAY_SIZE(ssb_mitigation_options); i++) {
+			if (!match_option(arg, ret, ssb_mitigation_options[i].option))
+				continue;
+
+			cmd = ssb_mitigation_options[i].cmd;
+			break;
+		}
+
+		if (i >= ARRAY_SIZE(ssb_mitigation_options)) {
+			pr_err("unknown option (%s). Switching to AUTO select\n", arg);
+			return SPEC_STORE_BYPASS_CMD_AUTO;
+		}
+	}
+
+	return cmd;
+}
+
+static enum ssb_mitigation __init __ssb_select_mitigation(void)
+{
+	enum ssb_mitigation mode = SPEC_STORE_BYPASS_NONE;
+	enum ssb_mitigation_cmd cmd;
+
+	if (!boot_cpu_has(X86_FEATURE_SSBD))
+		return mode;
+
+	cmd = ssb_parse_cmdline();
+	if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS) &&
+	    (cmd == SPEC_STORE_BYPASS_CMD_NONE ||
+	     cmd == SPEC_STORE_BYPASS_CMD_AUTO))
+		return mode;
+
+	switch (cmd) {
+	case SPEC_STORE_BYPASS_CMD_AUTO:
+	case SPEC_STORE_BYPASS_CMD_SECCOMP:
+		/*
+		 * Choose prctl+seccomp as the default mode if seccomp is
+		 * enabled.
+		 */
+		if (IS_ENABLED(CONFIG_SECCOMP))
+			mode = SPEC_STORE_BYPASS_SECCOMP;
+		else
+			mode = SPEC_STORE_BYPASS_PRCTL;
+		break;
+	case SPEC_STORE_BYPASS_CMD_ON:
+		mode = SPEC_STORE_BYPASS_DISABLE;
+		break;
+	case SPEC_STORE_BYPASS_CMD_PRCTL:
+		mode = SPEC_STORE_BYPASS_PRCTL;
+		break;
+	case SPEC_STORE_BYPASS_CMD_NONE:
+		break;
+	}
+
+	/*
+	 * We have three CPU feature flags that are in play here:
+	 *  - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible.
+	 *  - X86_FEATURE_SSBD - CPU is able to turn off speculative store bypass
+	 *  - X86_FEATURE_SPEC_STORE_BYPASS_DISABLE - engage the mitigation
+	 */
+	if (mode == SPEC_STORE_BYPASS_DISABLE) {
+		setup_force_cpu_cap(X86_FEATURE_SPEC_STORE_BYPASS_DISABLE);
+		/*
+		 * Intel uses the SPEC CTRL MSR Bit(2) for this, while AMD may
+		 * use a completely different MSR and bit dependent on family.
+		 */
+		if (!static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) &&
+		    !static_cpu_has(X86_FEATURE_AMD_SSBD)) {
+			x86_amd_ssb_disable();
+		} else {
+			x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
+			update_spec_ctrl(x86_spec_ctrl_base);
+		}
+	}
+
+	return mode;
+}
+
+static void ssb_select_mitigation(void)
+{
+	ssb_mode = __ssb_select_mitigation();
+
+	if (boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS))
+		pr_info("%s\n", ssb_strings[ssb_mode]);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Speculation prctl: " fmt
+
+static void task_update_spec_tif(struct task_struct *tsk)
+{
+	/* Force the update of the real TIF bits */
+	set_tsk_thread_flag(tsk, TIF_SPEC_FORCE_UPDATE);
+
+	/*
+	 * Immediately update the speculation control MSRs for the current
+	 * task, but for a non-current task delay setting the CPU
+	 * mitigation until it is scheduled next.
+	 *
+	 * This can only happen for SECCOMP mitigation. For PRCTL it's
+	 * always the current task.
+	 */
+	if (tsk == current)
+		speculation_ctrl_update_current();
+}
+
+static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
+{
+	if (ssb_mode != SPEC_STORE_BYPASS_PRCTL &&
+	    ssb_mode != SPEC_STORE_BYPASS_SECCOMP)
+		return -ENXIO;
+
+	switch (ctrl) {
+	case PR_SPEC_ENABLE:
+		/* If speculation is force disabled, enable is not allowed */
+		if (task_spec_ssb_force_disable(task))
+			return -EPERM;
+		task_clear_spec_ssb_disable(task);
+		task_update_spec_tif(task);
+		break;
+	case PR_SPEC_DISABLE:
+		task_set_spec_ssb_disable(task);
+		task_update_spec_tif(task);
+		break;
+	case PR_SPEC_FORCE_DISABLE:
+		task_set_spec_ssb_disable(task);
+		task_set_spec_ssb_force_disable(task);
+		task_update_spec_tif(task);
+		break;
+	default:
+		return -ERANGE;
+	}
+	return 0;
+}
+
+static bool is_spec_ib_user_controlled(void)
+{
+	return spectre_v2_user_ibpb == SPECTRE_V2_USER_PRCTL ||
+		spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
+		spectre_v2_user_stibp == SPECTRE_V2_USER_PRCTL ||
+		spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP;
+}
+
+static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
+{
+	switch (ctrl) {
+	case PR_SPEC_ENABLE:
+		if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+		    spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
+			return 0;
+		/*
+		 * With strict mode for both IBPB and STIBP, the instruction
+		 * code paths avoid checking this task flag and instead,
+		 * unconditionally run the instruction. However, STIBP and IBPB
+		 * are independent and either can be set to conditionally
+		 * enabled regardless of the mode of the other.
+		 *
+		 * If either is set to conditional, allow the task flag to be
+		 * updated, unless it was force-disabled by a previous prctl
+		 * call. Currently, this is possible on an AMD CPU which has the
+		 * feature X86_FEATURE_AMD_STIBP_ALWAYS_ON. In this case, if the
+		 * kernel is booted with 'spectre_v2_user=seccomp', then
+		 * spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP and
+		 * spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED.
+		 */
+		if (!is_spec_ib_user_controlled() ||
+		    task_spec_ib_force_disable(task))
+			return -EPERM;
+
+		task_clear_spec_ib_disable(task);
+		task_update_spec_tif(task);
+		break;
+	case PR_SPEC_DISABLE:
+	case PR_SPEC_FORCE_DISABLE:
+		/*
+		 * Indirect branch speculation is always allowed when
+		 * mitigation is force disabled.
+		 */
+		if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+		    spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
+			return -EPERM;
+
+		if (!is_spec_ib_user_controlled())
+			return 0;
+
+		task_set_spec_ib_disable(task);
+		if (ctrl == PR_SPEC_FORCE_DISABLE)
+			task_set_spec_ib_force_disable(task);
+		task_update_spec_tif(task);
+		if (task == current)
+			indirect_branch_prediction_barrier();
+		break;
+	default:
+		return -ERANGE;
+	}
+	return 0;
+}
+
+int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
+			     unsigned long ctrl)
+{
+	switch (which) {
+	case PR_SPEC_STORE_BYPASS:
+		return ssb_prctl_set(task, ctrl);
+	case PR_SPEC_INDIRECT_BRANCH:
+		return ib_prctl_set(task, ctrl);
+	default:
+		return -ENODEV;
+	}
+}
+
+#ifdef CONFIG_SECCOMP
+void arch_seccomp_spec_mitigate(struct task_struct *task)
+{
+	if (ssb_mode == SPEC_STORE_BYPASS_SECCOMP)
+		ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE);
+	if (spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
+	    spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP)
+		ib_prctl_set(task, PR_SPEC_FORCE_DISABLE);
+}
+#endif
+
+static int ssb_prctl_get(struct task_struct *task)
+{
+	switch (ssb_mode) {
+	case SPEC_STORE_BYPASS_DISABLE:
+		return PR_SPEC_DISABLE;
+	case SPEC_STORE_BYPASS_SECCOMP:
+	case SPEC_STORE_BYPASS_PRCTL:
+		if (task_spec_ssb_force_disable(task))
+			return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
+		if (task_spec_ssb_disable(task))
+			return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
+		return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
+	default:
+		if (boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS))
+			return PR_SPEC_ENABLE;
+		return PR_SPEC_NOT_AFFECTED;
+	}
+}
+
+static int ib_prctl_get(struct task_struct *task)
+{
+	if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
+		return PR_SPEC_NOT_AFFECTED;
+
+	if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+	    spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
+		return PR_SPEC_ENABLE;
+	else if (is_spec_ib_user_controlled()) {
+		if (task_spec_ib_force_disable(task))
+			return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
+		if (task_spec_ib_disable(task))
+			return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
+		return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
+	} else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
+	    spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
+	    spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
+		return PR_SPEC_DISABLE;
+	else
+		return PR_SPEC_NOT_AFFECTED;
+}
+
+int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
+{
+	switch (which) {
+	case PR_SPEC_STORE_BYPASS:
+		return ssb_prctl_get(task);
+	case PR_SPEC_INDIRECT_BRANCH:
+		return ib_prctl_get(task);
+	default:
+		return -ENODEV;
+	}
+}
+
+void x86_spec_ctrl_setup_ap(void)
+{
+	if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
+		update_spec_ctrl(x86_spec_ctrl_base);
+
+	if (ssb_mode == SPEC_STORE_BYPASS_DISABLE)
+		x86_amd_ssb_disable();
+}
+
+bool itlb_multihit_kvm_mitigation;
+EXPORT_SYMBOL_GPL(itlb_multihit_kvm_mitigation);
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"L1TF: " fmt
+
+/* Default mitigation for L1TF-affected CPUs */
+enum l1tf_mitigations l1tf_mitigation __ro_after_init = L1TF_MITIGATION_FLUSH;
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+EXPORT_SYMBOL_GPL(l1tf_mitigation);
+
+enum vmx_l1d_flush_state l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_AUTO;
+EXPORT_SYMBOL_GPL(l1tf_vmx_mitigation);
+#endif
+
+/*
+ * These CPUs all support 44bits physical address space internally in the
+ * cache but CPUID can report a smaller number of physical address bits.
+ *
+ * The L1TF mitigation uses the top most address bit for the inversion of
+ * non present PTEs. When the installed memory reaches into the top most
+ * address bit due to memory holes, which has been observed on machines
+ * which report 36bits physical address bits and have 32G RAM installed,
+ * then the mitigation range check in l1tf_select_mitigation() triggers.
+ * This is a false positive because the mitigation is still possible due to
+ * the fact that the cache uses 44bit internally. Use the cache bits
+ * instead of the reported physical bits and adjust them on the affected
+ * machines to 44bit if the reported bits are less than 44.
+ */
+static void override_cache_bits(struct cpuinfo_x86 *c)
+{
+	if (c->x86 != 6)
+		return;
+
+	switch (c->x86_model) {
+	case INTEL_FAM6_NEHALEM:
+	case INTEL_FAM6_WESTMERE:
+	case INTEL_FAM6_SANDYBRIDGE:
+	case INTEL_FAM6_IVYBRIDGE:
+	case INTEL_FAM6_HASWELL_CORE:
+	case INTEL_FAM6_HASWELL_ULT:
+	case INTEL_FAM6_HASWELL_GT3E:
+	case INTEL_FAM6_BROADWELL_CORE:
+	case INTEL_FAM6_BROADWELL_GT3E:
+	case INTEL_FAM6_SKYLAKE_MOBILE:
+	case INTEL_FAM6_SKYLAKE_DESKTOP:
+	case INTEL_FAM6_KABYLAKE_MOBILE:
+	case INTEL_FAM6_KABYLAKE_DESKTOP:
+		if (c->x86_cache_bits < 44)
+			c->x86_cache_bits = 44;
+		break;
+	}
+}
+
+static void __init l1tf_select_mitigation(void)
+{
+	u64 half_pa;
+
+	if (!boot_cpu_has_bug(X86_BUG_L1TF))
+		return;
+
+	if (cpu_mitigations_off())
+		l1tf_mitigation = L1TF_MITIGATION_OFF;
+	else if (cpu_mitigations_auto_nosmt())
+		l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOSMT;
+
+	override_cache_bits(&boot_cpu_data);
+
+	switch (l1tf_mitigation) {
+	case L1TF_MITIGATION_OFF:
+	case L1TF_MITIGATION_FLUSH_NOWARN:
+	case L1TF_MITIGATION_FLUSH:
+		break;
+	case L1TF_MITIGATION_FLUSH_NOSMT:
+	case L1TF_MITIGATION_FULL:
+		cpu_smt_disable(false);
+		break;
+	case L1TF_MITIGATION_FULL_FORCE:
+		cpu_smt_disable(true);
+		break;
+	}
+
+#if CONFIG_PGTABLE_LEVELS == 2
+	pr_warn("Kernel not compiled for PAE. No mitigation for L1TF\n");
+	return;
+#endif
+
+	half_pa = (u64)l1tf_pfn_limit() << PAGE_SHIFT;
+	if (e820_any_mapped(half_pa, ULLONG_MAX - half_pa, E820_RAM)) {
+		pr_warn("System has more than MAX_PA/2 memory. L1TF mitigation not effective.\n");
+		pr_info("You may make it effective by booting the kernel with mem=%llu parameter.\n",
+				half_pa);
+		pr_info("However, doing so will make a part of your RAM unusable.\n");
+		pr_info("Reading https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/l1tf.html might help you decide.\n");
+		return;
+	}
+
+	setup_force_cpu_cap(X86_FEATURE_L1TF_PTEINV);
+}
+
+static int __init l1tf_cmdline(char *str)
+{
+	if (!boot_cpu_has_bug(X86_BUG_L1TF))
+		return 0;
+
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "off"))
+		l1tf_mitigation = L1TF_MITIGATION_OFF;
+	else if (!strcmp(str, "flush,nowarn"))
+		l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOWARN;
+	else if (!strcmp(str, "flush"))
+		l1tf_mitigation = L1TF_MITIGATION_FLUSH;
+	else if (!strcmp(str, "flush,nosmt"))
+		l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOSMT;
+	else if (!strcmp(str, "full"))
+		l1tf_mitigation = L1TF_MITIGATION_FULL;
+	else if (!strcmp(str, "full,force"))
+		l1tf_mitigation = L1TF_MITIGATION_FULL_FORCE;
+
+	return 0;
+}
+early_param("l1tf", l1tf_cmdline);
+
+#undef pr_fmt
+#define pr_fmt(fmt) fmt
+
+#ifdef CONFIG_SYSFS
+
+#define L1TF_DEFAULT_MSG "Mitigation: PTE Inversion"
+
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+static const char *l1tf_vmx_states[] = {
+	[VMENTER_L1D_FLUSH_AUTO]		= "auto",
+	[VMENTER_L1D_FLUSH_NEVER]		= "vulnerable",
+	[VMENTER_L1D_FLUSH_COND]		= "conditional cache flushes",
+	[VMENTER_L1D_FLUSH_ALWAYS]		= "cache flushes",
+	[VMENTER_L1D_FLUSH_EPT_DISABLED]	= "EPT disabled",
+	[VMENTER_L1D_FLUSH_NOT_REQUIRED]	= "flush not necessary"
+};
+
+static ssize_t l1tf_show_state(char *buf)
+{
+	if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_AUTO)
+		return sprintf(buf, "%s\n", L1TF_DEFAULT_MSG);
+
+	if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_EPT_DISABLED ||
+	    (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_NEVER &&
+	     cpu_smt_control == CPU_SMT_ENABLED))
+		return sprintf(buf, "%s; VMX: %s\n", L1TF_DEFAULT_MSG,
+			       l1tf_vmx_states[l1tf_vmx_mitigation]);
+
+	return sprintf(buf, "%s; VMX: %s, SMT %s\n", L1TF_DEFAULT_MSG,
+		       l1tf_vmx_states[l1tf_vmx_mitigation],
+		       cpu_smt_control == CPU_SMT_ENABLED ? "vulnerable" : "disabled");
+}
+
+static ssize_t itlb_multihit_show_state(char *buf)
+{
+	if (itlb_multihit_kvm_mitigation)
+		return sprintf(buf, "KVM: Mitigation: Split huge pages\n");
+	else
+		return sprintf(buf, "KVM: Vulnerable\n");
+}
+#else
+static ssize_t l1tf_show_state(char *buf)
+{
+	return sprintf(buf, "%s\n", L1TF_DEFAULT_MSG);
+}
+
+static ssize_t itlb_multihit_show_state(char *buf)
+{
+	return sprintf(buf, "Processor vulnerable\n");
+}
+#endif
+
+static ssize_t mds_show_state(char *buf)
+{
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
+		return sprintf(buf, "%s; SMT Host state unknown\n",
+			       mds_strings[mds_mitigation]);
+	}
+
+	if (boot_cpu_has(X86_BUG_MSBDS_ONLY)) {
+		return sprintf(buf, "%s; SMT %s\n", mds_strings[mds_mitigation],
+			       (mds_mitigation == MDS_MITIGATION_OFF ? "vulnerable" :
+			        sched_smt_active() ? "mitigated" : "disabled"));
+	}
+
+	return sprintf(buf, "%s; SMT %s\n", mds_strings[mds_mitigation],
+		       sched_smt_active() ? "vulnerable" : "disabled");
+}
+
+static ssize_t tsx_async_abort_show_state(char *buf)
+{
+	if ((taa_mitigation == TAA_MITIGATION_TSX_DISABLED) ||
+	    (taa_mitigation == TAA_MITIGATION_OFF))
+		return sprintf(buf, "%s\n", taa_strings[taa_mitigation]);
+
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
+		return sprintf(buf, "%s; SMT Host state unknown\n",
+			       taa_strings[taa_mitigation]);
+	}
+
+	return sprintf(buf, "%s; SMT %s\n", taa_strings[taa_mitigation],
+		       sched_smt_active() ? "vulnerable" : "disabled");
+}
+
+static ssize_t mmio_stale_data_show_state(char *buf)
+{
+	if (mmio_mitigation == MMIO_MITIGATION_OFF)
+		return sysfs_emit(buf, "%s\n", mmio_strings[mmio_mitigation]);
+
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
+		return sysfs_emit(buf, "%s; SMT Host state unknown\n",
+				  mmio_strings[mmio_mitigation]);
+	}
+
+	return sysfs_emit(buf, "%s; SMT %s\n", mmio_strings[mmio_mitigation],
+			  sched_smt_active() ? "vulnerable" : "disabled");
+}
+
+static char *stibp_state(void)
+{
+	if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+		return "";
+
+	switch (spectre_v2_user_stibp) {
+	case SPECTRE_V2_USER_NONE:
+		return "; STIBP: disabled";
+	case SPECTRE_V2_USER_STRICT:
+		return "; STIBP: forced";
+	case SPECTRE_V2_USER_STRICT_PREFERRED:
+		return "; STIBP: always-on";
+	case SPECTRE_V2_USER_PRCTL:
+	case SPECTRE_V2_USER_SECCOMP:
+		if (static_key_enabled(&switch_to_cond_stibp))
+			return "; STIBP: conditional";
+	}
+	return "";
+}
+
+static char *ibpb_state(void)
+{
+	if (boot_cpu_has(X86_FEATURE_IBPB)) {
+		if (static_key_enabled(&switch_mm_always_ibpb))
+			return "; IBPB: always-on";
+		if (static_key_enabled(&switch_mm_cond_ibpb))
+			return "; IBPB: conditional";
+		return "; IBPB: disabled";
+	}
+	return "";
+}
+
+static char *pbrsb_eibrs_state(void)
+{
+	if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) {
+		if (boot_cpu_has(X86_FEATURE_RSB_VMEXIT_LITE) ||
+		    boot_cpu_has(X86_FEATURE_RSB_VMEXIT))
+			return "; PBRSB-eIBRS: SW sequence";
+		else
+			return "; PBRSB-eIBRS: Vulnerable";
+	} else {
+		return "; PBRSB-eIBRS: Not affected";
+	}
+}
+
+static char *ubuntu_ibpb_state(void)
+{
+	if (ibpb_enabled) {
+		/* This is the default behaviour so don't show anything */
+		return "";
+	} else {
+		/* IBPB in the kernel is disabled */
+		return ", IBPB: kernel-off";
+	}
+}
+
+static char *ubuntu_ibrs_state(void)
+{
+	if (ibrs_enabled == 2) {
+		/* IBRS is enabled in both kernel and user space */
+		return ", IBRS: kernel+user";
+	} else if (ibrs_enabled) {
+		/* IBRS is only enabled in the kernel */
+		return ", IBRS: kernel";
+	} else {
+		/* This is the default behaviour so don't show anything */
+		return "";
+	}
+}
+
+static ssize_t srbds_show_state(char *buf)
+{
+	return sprintf(buf, "%s\n", srbds_strings[srbds_mitigation]);
+}
+
+static ssize_t retbleed_show_state(char *buf)
+{
+	return sprintf(buf, "%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
+static ssize_t gds_show_state(char *buf)
+{
+	return sysfs_emit(buf, "%s\n", gds_strings[gds_mitigation]);
+}
+
+static ssize_t vmscape_show_state(char *buf)
+{
+	return sysfs_emit(buf, "%s\n", vmscape_strings[vmscape_mitigation]);
+}
+
+static const char * const spectre_bhi_state(void)
+{
+	if (!boot_cpu_has_bug(X86_BUG_BHI))
+		return "; BHI: Not affected";
+	else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_HW))
+		return "; BHI: BHI_DIS_S";
+	else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP))
+		return "; BHI: SW loop, KVM: SW loop";
+	else if (boot_cpu_has(X86_FEATURE_RETPOLINE) &&
+		 !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) &&
+		 rrsba_disabled)
+		return "; BHI: Retpoline";
+	else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT))
+		return "; BHI: Vulnerable, KVM: SW loop";
+
+	return "; BHI: Vulnerable";
+}
+
+static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr,
+			       char *buf, unsigned int bug)
+{
+	if (!boot_cpu_has_bug(bug))
+		return sprintf(buf, "Not affected\n");
+
+	switch (bug) {
+	case X86_BUG_CPU_MELTDOWN:
+		if (boot_cpu_has(X86_FEATURE_KAISER))
+			return sprintf(buf, "Mitigation: PTI\n");
+		break;
+
+	case X86_BUG_SPECTRE_V1:
+		return sprintf(buf, "%s\n", spectre_v1_strings[spectre_v1_mitigation]);
+
+	case X86_BUG_SPECTRE_V2:
+		return sprintf(buf, "%s%s%s%s%s%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
+			       spectre_v2_retp(spectre_v2_enabled),
+			       ubuntu_ibpb_state(),
+			       ibpb_state(),
+			       ubuntu_ibrs_state(),
+			       boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? "; IBRS_FW" : "",
+			       stibp_state(),
+			       boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? "; RSB filling" : "",
+			       pbrsb_eibrs_state(),
+			       spectre_bhi_state(),
+			       /* this should always be at the end */
+			       spectre_v2_module_string());
+
+	case X86_BUG_SPEC_STORE_BYPASS:
+		return sprintf(buf, "%s\n", ssb_strings[ssb_mode]);
+
+	case X86_BUG_L1TF:
+		if (boot_cpu_has(X86_FEATURE_L1TF_PTEINV))
+			return l1tf_show_state(buf);
+		break;
+
+	case X86_BUG_MDS:
+		return mds_show_state(buf);
+
+	case X86_BUG_TAA:
+		return tsx_async_abort_show_state(buf);
+
+	case X86_BUG_ITLB_MULTIHIT:
+		return itlb_multihit_show_state(buf);
+
+	case X86_BUG_SRBDS:
+		return srbds_show_state(buf);
+
+	case X86_BUG_MMIO_STALE_DATA:
+		return mmio_stale_data_show_state(buf);
+
+	case X86_BUG_RETBLEED:
+		return retbleed_show_state(buf);
+
+	case X86_BUG_GDS:
+		return gds_show_state(buf);
+
+	case X86_BUG_VMSCAPE:
+		return vmscape_show_state(buf);
+
+	default:
+		break;
+	}
+
+	return sprintf(buf, "Vulnerable\n");
+}
+
+ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_CPU_MELTDOWN);
+}
+
+ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_SPECTRE_V1);
+}
+
+ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_SPECTRE_V2);
+}
+
+ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_SPEC_STORE_BYPASS);
+}
+
+ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_L1TF);
+}
+
+ssize_t cpu_show_mds(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_MDS);
+}
+
+ssize_t cpu_show_tsx_async_abort(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_TAA);
+}
+
+ssize_t cpu_show_itlb_multihit(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_ITLB_MULTIHIT);
+}
+
+ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_SRBDS);
+}
+
+ssize_t cpu_show_mmio_stale_data(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
+}
+
+ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_RETBLEED);
+}
+
+ssize_t cpu_show_gds(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_GDS);
+}
+
+ssize_t cpu_show_vmscape(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpu_show_common(dev, attr, buf, X86_BUG_VMSCAPE);
+}
+#endif
--- linux-4.4.0.orig/arch/x86/kernel/cpu/centaur.c
+++ linux-4.4.0/arch/x86/kernel/cpu/centaur.c
@@ -1,7 +1,7 @@
 #include <linux/bitops.h>
 #include <linux/kernel.h>
 
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <asm/e820.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
@@ -43,7 +43,7 @@
 		/* store Centaur Extended Feature Flags as
 		 * word 5 of the CPU capability bit array
 		 */
-		c->x86_capability[5] = cpuid_edx(0xC0000001);
+		c->x86_capability[CPUID_C000_0001_EDX] = cpuid_edx(0xC0000001);
 	}
 #ifdef CONFIG_X86_32
 	/* Cyrix III family needs CX8 & PGE explicitly enabled. */
@@ -134,7 +134,7 @@
 			clear_cpu_cap(c, X86_FEATURE_TSC);
 			break;
 		case 8:
-			switch (c->x86_mask) {
+			switch (c->x86_stepping) {
 			default:
 			name = "2";
 				break;
@@ -209,7 +209,7 @@
 	 *  - Note, it seems this may only be in engineering samples.
 	 */
 	if ((c->x86 == 6) && (c->x86_model == 9) &&
-				(c->x86_mask == 1) && (size == 65))
+				(c->x86_stepping == 1) && (size == 65))
 		size -= 1;
 	return size;
 }
--- linux-4.4.0.orig/arch/x86/kernel/cpu/common.c
+++ linux-4.4.0/arch/x86/kernel/cpu/common.c
@@ -2,20 +2,25 @@
 #include <linux/linkage.h>
 #include <linux/bitops.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/percpu.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/sched/smt.h>
 #include <linux/init.h>
 #include <linux/kprobes.h>
 #include <linux/kgdb.h>
 #include <linux/smp.h>
+#include <linux/cpu.h>
 #include <linux/io.h>
 #include <linux/syscore_ops.h>
 
 #include <asm/stackprotector.h>
+#include <linux/utsname.h>
+
+#include <asm/alternative.h>
 #include <asm/perf_event.h>
 #include <asm/mmu_context.h>
 #include <asm/archrandom.h>
@@ -43,6 +48,8 @@
 #include <asm/pat.h>
 #include <asm/microcode.h>
 #include <asm/microcode_intel.h>
+#include <asm/intel-family.h>
+#include <asm/cpu_device_id.h>
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/uv/uv.h>
@@ -92,7 +99,7 @@
 
 static const struct cpu_dev *this_cpu = &default_cpu;
 
-DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
+DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(struct gdt_page, gdt_page) = { .gdt = {
 #ifdef CONFIG_X86_64
 	/*
 	 * We need valid kernel segments for data and code in long mode too
@@ -162,6 +169,40 @@
 }
 __setup("nompx", x86_mpx_setup);
 
+#ifdef CONFIG_X86_64
+static int __init x86_pcid_setup(char *s)
+{
+	/* require an exact match without trailing characters */
+	if (strlen(s))
+		return 0;
+
+	/* do not emit a message if the feature is not present */
+	if (!boot_cpu_has(X86_FEATURE_PCID))
+		return 1;
+
+	setup_clear_cpu_cap(X86_FEATURE_PCID);
+	pr_info("nopcid: PCID feature disabled\n");
+	return 1;
+}
+__setup("nopcid", x86_pcid_setup);
+#endif
+
+static int __init x86_noinvpcid_setup(char *s)
+{
+	/* noinvpcid doesn't accept parameters */
+	if (s)
+		return -EINVAL;
+
+	/* do not emit a message if the feature is not present */
+	if (!boot_cpu_has(X86_FEATURE_INVPCID))
+		return 0;
+
+	setup_clear_cpu_cap(X86_FEATURE_INVPCID);
+	pr_info("noinvpcid: INVPCID feature disabled\n");
+	return 0;
+}
+early_param("noinvpcid", x86_noinvpcid_setup);
+
 #ifdef CONFIG_X86_32
 static int cachesize_override = -1;
 static int disable_x86_serial_nr = 1;
@@ -287,6 +328,39 @@
 	}
 }
 
+static void setup_pcid(struct cpuinfo_x86 *c)
+{
+	if (cpu_has(c, X86_FEATURE_PCID)) {
+		if (cpu_has(c, X86_FEATURE_PGE) || kaiser_enabled) {
+			cr4_set_bits(X86_CR4_PCIDE);
+			/*
+			 * INVPCID has two "groups" of types:
+			 * 1/2: Invalidate an individual address
+			 * 3/4: Invalidate all contexts
+			 *
+			 * 1/2 take a PCID, but 3/4 do not.  So, 3/4
+			 * ignore the PCID argument in the descriptor.
+			 * But, we have to be careful not to call 1/2
+			 * with an actual non-zero PCID in them before
+			 * we do the above cr4_set_bits().
+			 */
+			if (cpu_has(c, X86_FEATURE_INVPCID))
+				set_cpu_cap(c, X86_FEATURE_INVPCID_SINGLE);
+		} else {
+			/*
+			 * flush_tlb_all(), as currently implemented, won't
+			 * work if PCID is on but PGE is not.  Since that
+			 * combination doesn't exist on real hardware, there's
+			 * no reason to try to fully support it, but it's
+			 * polite to avoid corrupting data if we're on
+			 * an improperly configured VM.
+			 */
+			clear_cpu_cap(c, X86_FEATURE_PCID);
+		}
+	}
+	kaiser_setup_pcid();
+}
+
 /*
  * Some CPU features depend on higher CPUID levels, which may not always
  * be available due to CPUID level capping or broken virtualization
@@ -365,8 +439,8 @@
 	return NULL;		/* Not found */
 }
 
-__u32 cpu_caps_cleared[NCAPINTS];
-__u32 cpu_caps_set[NCAPINTS];
+__u32 cpu_caps_cleared[NCAPINTS + NBUGINTS];
+__u32 cpu_caps_set[NCAPINTS + NBUGINTS];
 
 void load_percpu_segment(int cpu)
 {
@@ -489,33 +563,36 @@
 		tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]);
 }
 
-void detect_ht(struct cpuinfo_x86 *c)
+int detect_ht_early(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
 	u32 eax, ebx, ecx, edx;
-	int index_msb, core_bits;
-	static bool printed;
 
 	if (!cpu_has(c, X86_FEATURE_HT))
-		return;
+		return -1;
 
 	if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
-		goto out;
+		return -1;
 
 	if (cpu_has(c, X86_FEATURE_XTOPOLOGY))
-		return;
+		return -1;
 
 	cpuid(1, &eax, &ebx, &ecx, &edx);
 
 	smp_num_siblings = (ebx & 0xff0000) >> 16;
-
-	if (smp_num_siblings == 1) {
+	if (smp_num_siblings == 1)
 		printk_once(KERN_INFO "CPU0: Hyper-Threading is disabled\n");
-		goto out;
-	}
+#endif
+	return 0;
+}
 
-	if (smp_num_siblings <= 1)
-		goto out;
+void detect_ht(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+	int index_msb, core_bits;
+
+	if (detect_ht_early(c) < 0)
+		return;
 
 	index_msb = get_count_order(smp_num_siblings);
 	c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, index_msb);
@@ -528,15 +605,6 @@
 
 	c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, index_msb) &
 				       ((1 << core_bits) - 1);
-
-out:
-	if (!printed && (c->x86_max_cores * smp_num_siblings) > 1) {
-		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-		       c->phys_proc_id);
-		printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-		       c->cpu_core_id);
-		printed = 1;
-	}
 #endif
 }
 
@@ -583,7 +651,7 @@
 		cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
 		c->x86 = (tfms >> 8) & 0xf;
 		c->x86_model = (tfms >> 4) & 0xf;
-		c->x86_mask = tfms & 0xf;
+		c->x86_stepping	= tfms & 0xf;
 
 		if (c->x86 == 0xf)
 			c->x86 += (tfms >> 20) & 0xff;
@@ -597,89 +665,158 @@
 	}
 }
 
+static void apply_forced_caps(struct cpuinfo_x86 *c)
+{
+	int i;
+
+	for (i = 0; i < NCAPINTS + NBUGINTS; i++) {
+		c->x86_capability[i] &= ~cpu_caps_cleared[i];
+		c->x86_capability[i] |= cpu_caps_set[i];
+	}
+}
+
+static void init_speculation_control(struct cpuinfo_x86 *c)
+{
+	/*
+	 * The Intel SPEC_CTRL CPUID bit implies IBRS and IBPB support,
+	 * and they also have a different bit for STIBP support. Also,
+	 * a hypervisor might have set the individual AMD bits even on
+	 * Intel CPUs, for finer-grained selection of what's available.
+	 */
+	if (cpu_has(c, X86_FEATURE_SPEC_CTRL)) {
+		set_cpu_cap(c, X86_FEATURE_IBRS);
+		set_cpu_cap(c, X86_FEATURE_IBPB);
+		set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL);
+	}
+
+	if (cpu_has(c, X86_FEATURE_INTEL_STIBP))
+		set_cpu_cap(c, X86_FEATURE_STIBP);
+
+	if (cpu_has(c, X86_FEATURE_SPEC_CTRL_SSBD) ||
+	    cpu_has(c, X86_FEATURE_VIRT_SSBD))
+		set_cpu_cap(c, X86_FEATURE_SSBD);
+
+	if (cpu_has(c, X86_FEATURE_AMD_IBRS)) {
+		set_cpu_cap(c, X86_FEATURE_IBRS);
+		set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL);
+	}
+
+	if (cpu_has(c, X86_FEATURE_AMD_IBPB))
+		set_cpu_cap(c, X86_FEATURE_IBPB);
+
+	if (cpu_has(c, X86_FEATURE_AMD_STIBP)) {
+		set_cpu_cap(c, X86_FEATURE_STIBP);
+		set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL);
+	}
+
+	if (cpu_has(c, X86_FEATURE_AMD_SSBD)) {
+		set_cpu_cap(c, X86_FEATURE_SSBD);
+		set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL);
+		clear_cpu_cap(c, X86_FEATURE_VIRT_SSBD);
+	}
+}
+
+static void init_cqm(struct cpuinfo_x86 *c)
+{
+	if (!cpu_has(c, X86_FEATURE_CQM_LLC)) {
+		c->x86_cache_max_rmid  = -1;
+		c->x86_cache_occ_scale = -1;
+		return;
+	}
+
+	/* will be overridden if occupancy monitoring exists */
+	c->x86_cache_max_rmid = cpuid_ebx(0xf);
+
+	if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC) ||
+	    cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL) ||
+	    cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)) {
+		u32 eax, ebx, ecx, edx;
+
+		/* QoS sub-leaf, EAX=0Fh, ECX=1 */
+		cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
+
+		c->x86_cache_max_rmid  = ecx;
+		c->x86_cache_occ_scale = ebx;
+	}
+}
+
 void get_cpu_cap(struct cpuinfo_x86 *c)
 {
-	u32 tfms, xlvl;
-	u32 ebx;
+	u32 eax, ebx, ecx, edx;
 
 	/* Intel-defined flags: level 0x00000001 */
 	if (c->cpuid_level >= 0x00000001) {
-		u32 capability, excap;
+		cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
 
-		cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
-		c->x86_capability[0] = capability;
-		c->x86_capability[4] = excap;
+		c->x86_capability[CPUID_1_ECX] = ecx;
+		c->x86_capability[CPUID_1_EDX] = edx;
 	}
 
+	/* Thermal and Power Management Leaf: level 0x00000006 (eax) */
+	if (c->cpuid_level >= 0x00000006)
+		c->x86_capability[CPUID_6_EAX] = cpuid_eax(0x00000006);
+
 	/* Additional Intel-defined flags: level 0x00000007 */
 	if (c->cpuid_level >= 0x00000007) {
-		u32 eax, ebx, ecx, edx;
-
 		cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx);
-
-		c->x86_capability[9] = ebx;
+		c->x86_capability[CPUID_7_0_EBX] = ebx;
+		c->x86_capability[CPUID_7_ECX] = ecx;
+		c->x86_capability[CPUID_7_EDX] = edx;
 	}
 
 	/* Extended state features: level 0x0000000d */
 	if (c->cpuid_level >= 0x0000000d) {
-		u32 eax, ebx, ecx, edx;
-
 		cpuid_count(0x0000000d, 1, &eax, &ebx, &ecx, &edx);
 
-		c->x86_capability[10] = eax;
+		c->x86_capability[CPUID_D_1_EAX] = eax;
 	}
 
-	/* Additional Intel-defined flags: level 0x0000000F */
-	if (c->cpuid_level >= 0x0000000F) {
-		u32 eax, ebx, ecx, edx;
+	/* AMD-defined flags: level 0x80000001 */
+	eax = cpuid_eax(0x80000000);
+	c->extended_cpuid_level = eax;
 
-		/* QoS sub-leaf, EAX=0Fh, ECX=0 */
-		cpuid_count(0x0000000F, 0, &eax, &ebx, &ecx, &edx);
-		c->x86_capability[11] = edx;
-		if (cpu_has(c, X86_FEATURE_CQM_LLC)) {
-			/* will be overridden if occupancy monitoring exists */
-			c->x86_cache_max_rmid = ebx;
-
-			/* QoS sub-leaf, EAX=0Fh, ECX=1 */
-			cpuid_count(0x0000000F, 1, &eax, &ebx, &ecx, &edx);
-			c->x86_capability[12] = edx;
-			if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC)) {
-				c->x86_cache_max_rmid = ecx;
-				c->x86_cache_occ_scale = ebx;
-			}
-		} else {
-			c->x86_cache_max_rmid = -1;
-			c->x86_cache_occ_scale = -1;
+	if ((eax & 0xffff0000) == 0x80000000) {
+		if (eax >= 0x80000001) {
+			cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+
+			c->x86_capability[CPUID_8000_0001_ECX] = ecx;
+			c->x86_capability[CPUID_8000_0001_EDX] = edx;
 		}
 	}
 
-	/* AMD-defined flags: level 0x80000001 */
-	xlvl = cpuid_eax(0x80000000);
-	c->extended_cpuid_level = xlvl;
+	if (c->extended_cpuid_level >= 0x80000007) {
+		cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
 
-	if ((xlvl & 0xffff0000) == 0x80000000) {
-		if (xlvl >= 0x80000001) {
-			c->x86_capability[1] = cpuid_edx(0x80000001);
-			c->x86_capability[6] = cpuid_ecx(0x80000001);
-		}
+		c->x86_capability[CPUID_8000_0007_EBX] = ebx;
+		c->x86_power = edx;
 	}
 
 	if (c->extended_cpuid_level >= 0x80000008) {
-		u32 eax = cpuid_eax(0x80000008);
+		cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
 
 		c->x86_virt_bits = (eax >> 8) & 0xff;
 		c->x86_phys_bits = eax & 0xff;
-		c->x86_capability[13] = cpuid_ebx(0x80000008);
+		c->x86_capability[CPUID_8000_0008_EBX] = ebx;
 	}
 #ifdef CONFIG_X86_32
 	else if (cpu_has(c, X86_FEATURE_PAE) || cpu_has(c, X86_FEATURE_PSE36))
 		c->x86_phys_bits = 36;
 #endif
+	c->x86_cache_bits = c->x86_phys_bits;
 
-	if (c->extended_cpuid_level >= 0x80000007)
-		c->x86_power = cpuid_edx(0x80000007);
+	if (c->extended_cpuid_level >= 0x8000000a)
+		c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
 
 	init_scattered_cpuid_features(c);
+	init_speculation_control(c);
+	init_cqm(c);
+
+	/*
+	 * Clear/Set all flags overridden by options, after probe.
+	 * This needs to happen each time we re-probe, which may happen
+	 * several times during CPU initialization.
+	 */
+	apply_forced_caps(c);
 }
 
 static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
@@ -708,6 +845,308 @@
 #endif
 }
 
+#define NO_SPECULATION		BIT(0)
+#define NO_MELTDOWN		BIT(1)
+#define NO_SSB			BIT(2)
+#define NO_L1TF			BIT(3)
+#define NO_MDS			BIT(4)
+#define MSBDS_ONLY		BIT(5)
+#define NO_SWAPGS		BIT(6)
+#define NO_ITLB_MULTIHIT	BIT(7)
+#define NO_EIBRS_PBRSB		BIT(9)
+#define NO_BHI			BIT(11)
+
+#define VULNWL(_vendor, _family, _model, _whitelist)	\
+	{ X86_VENDOR_##_vendor, _family, _model, X86_FEATURE_ANY, _whitelist }
+
+#define VULNWL_INTEL(model, whitelist)		\
+	VULNWL(INTEL, 6, INTEL_FAM6_##model, whitelist)
+
+#define VULNWL_AMD(family, whitelist)		\
+	VULNWL(AMD, family, X86_MODEL_ANY, whitelist)
+
+static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
+	VULNWL(ANY,	4, X86_MODEL_ANY,	NO_SPECULATION),
+	VULNWL(CENTAUR,	5, X86_MODEL_ANY,	NO_SPECULATION),
+	VULNWL(INTEL,	5, X86_MODEL_ANY,	NO_SPECULATION),
+	VULNWL(NSC,	5, X86_MODEL_ANY,	NO_SPECULATION),
+
+	/* Intel Family 6 */
+	VULNWL_INTEL(ATOM_SALTWELL,		NO_SPECULATION | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_SALTWELL_TABLET,	NO_SPECULATION | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_SALTWELL_MID,		NO_SPECULATION | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_BONNELL,		NO_SPECULATION | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_BONNELL_MID,		NO_SPECULATION | NO_ITLB_MULTIHIT),
+
+	VULNWL_INTEL(ATOM_SILVERMONT,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_SILVERMONT_X,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_SILVERMONT_MID,	NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_AIRMONT,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(XEON_PHI_KNL,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(XEON_PHI_KNM,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+
+	VULNWL_INTEL(CORE_YONAH,		NO_SSB),
+
+	VULNWL_INTEL(ATOM_AIRMONT_MID,		NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+
+	VULNWL_INTEL(ATOM_GOLDMONT,		NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_GOLDMONT_X,		NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_GOLDMONT_PLUS,	NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB),
+
+	/*
+	 * Technically, swapgs isn't serializing on AMD (despite it previously
+	 * being documented as such in the APM).  But according to AMD, %gs is
+	 * updated non-speculatively, and the issuing of %gs-relative memory
+	 * operands will be blocked until the %gs update completes, which is
+	 * good enough for our purposes.
+	 */
+
+	VULNWL_INTEL(ATOM_TREMONT,		NO_EIBRS_PBRSB),
+	VULNWL_INTEL(ATOM_TREMONT_L,		NO_EIBRS_PBRSB),
+	VULNWL_INTEL(ATOM_TREMONT_X,		NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB),
+
+	/* AMD Family 0xf - 0x12 */
+	VULNWL_AMD(0x0f,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_BHI),
+	VULNWL_AMD(0x10,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_BHI),
+	VULNWL_AMD(0x11,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_BHI),
+	VULNWL_AMD(0x12,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_BHI),
+
+	/* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
+	VULNWL_AMD(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_BHI),
+	{}
+};
+
+#define VULNBL(vendor, family, model, blacklist)	\
+	X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, blacklist)
+
+#define VULNBL_INTEL_STEPPINGS(model, steppings, issues)		   \
+	X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(INTEL, 6,		   \
+					    INTEL_FAM6_##model, steppings, \
+					    X86_FEATURE_ANY, issues)
+
+#define VULNBL_AMD(family, blacklist)		\
+	VULNBL(AMD, family, X86_MODEL_ANY, blacklist)
+
+#define SRBDS		BIT(0)
+/* CPU is affected by X86_BUG_MMIO_STALE_DATA */
+#define MMIO		BIT(1)
+/* CPU is affected by Shared Buffers Data Sampling (SBDS), a variant of X86_BUG_MMIO_STALE_DATA */
+#define MMIO_SBDS	BIT(2)
+/* CPU is affected by RETbleed, speculating where you would not expect it */
+#define RETBLEED	BIT(3)
+/* CPU is affected by SMT (cross-thread) return predictions */
+#define SMT_RSB		BIT(4)
+/* CPU is affected by GDS */
+#define GDS		BIT(5)
+/* CPU is affected by VMSCAPE */
+#define VMSCAPE		BIT(6)
+
+static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
+	VULNBL_INTEL_STEPPINGS(SANDYBRIDGE_X,	X86_STEPPING_ANY,		VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(SANDYBRIDGE,	X86_STEPPING_ANY,		VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(IVYBRIDGE_X,	X86_STEPPING_ANY,		VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(IVYBRIDGE,	X86_STEPPING_ANY,		SRBDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(HASWELL_CORE,	X86_STEPPING_ANY,		SRBDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(HASWELL_ULT,	X86_STEPPING_ANY,		SRBDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(HASWELL_GT3E,	X86_STEPPING_ANY,		SRBDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(HASWELL_X,	X86_STEPPING_ANY,		MMIO | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(BROADWELL_XEON_D,X86_STEPPING_ANY,		MMIO | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(BROADWELL_GT3E,	X86_STEPPING_ANY,		SRBDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(BROADWELL_X,	X86_STEPPING_ANY,		MMIO | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(BROADWELL_CORE,	X86_STEPPING_ANY,		SRBDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(SKYLAKE_MOBILE,	X86_STEPPING_ANY,		SRBDS | MMIO | RETBLEED | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(SKYLAKE_X,	X86_STEPPING_ANY,		MMIO | RETBLEED | GDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(SKYLAKE_DESKTOP,	X86_STEPPING_ANY,		SRBDS | MMIO | RETBLEED | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(KABYLAKE_MOBILE,	X86_STEPPING_ANY,		SRBDS | MMIO | RETBLEED | GDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(KABYLAKE_DESKTOP,X86_STEPPING_ANY,		SRBDS | MMIO | RETBLEED | GDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(CANNONLAKE_MOBILE,X86_STEPPING_ANY,		RETBLEED | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(ICELAKE_MOBILE,	X86_STEPPING_ANY,		MMIO | MMIO_SBDS | RETBLEED | GDS),
+	VULNBL_INTEL_STEPPINGS(ICELAKE_XEON_D,	X86_STEPPING_ANY,		MMIO | GDS),
+	VULNBL_INTEL_STEPPINGS(ICELAKE_X,	X86_STEPPING_ANY,		MMIO | GDS),
+	VULNBL_INTEL_STEPPINGS(COMETLAKE,	X86_STEPPING_ANY,		MMIO | MMIO_SBDS | RETBLEED | GDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(COMETLAKE_L,	X86_STEPPING_ANY,		MMIO | MMIO_SBDS | RETBLEED | GDS | VMSCAPE),
+	VULNBL_INTEL_STEPPINGS(TIGERLAKE_L,	X86_STEPPING_ANY,		GDS),
+	VULNBL_INTEL_STEPPINGS(TIGERLAKE,	X86_STEPPING_ANY,		GDS),
+	VULNBL_INTEL_STEPPINGS(LAKEFIELD,	X86_STEPPING_ANY,		MMIO | MMIO_SBDS | RETBLEED),
+	VULNBL_INTEL_STEPPINGS(ROCKETLAKE,	X86_STEPPING_ANY,		MMIO | RETBLEED | GDS),
+	VULNBL_INTEL_STEPPINGS(ATOM_TREMONT,	X86_STEPPING_ANY,		MMIO | MMIO_SBDS),
+	VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_X,	X86_STEPPING_ANY,		MMIO),
+	VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L,	X86_STEPPING_ANY,		MMIO | MMIO_SBDS),
+
+	VULNBL_AMD(0x15, RETBLEED),
+	VULNBL_AMD(0x16, RETBLEED),
+	VULNBL_AMD(0x17, RETBLEED | SMT_RSB | VMSCAPE),
+	VULNBL_AMD(0x19, VMSCAPE),
+	{}
+};
+
+static bool __init cpu_matches(const struct x86_cpu_id *table, unsigned long which)
+{
+	const struct x86_cpu_id *m = x86_match_cpu(table);
+
+	return m && !!(m->driver_data & which);
+}
+
+u64 x86_read_arch_cap_msr(void)
+{
+	u64 x86_arch_cap_msr = 0;
+
+	if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES))
+		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, x86_arch_cap_msr);
+
+	return x86_arch_cap_msr;
+}
+
+static bool arch_cap_mmio_immune(u64 x86_arch_cap_msr)
+{
+	return (x86_arch_cap_msr & ARCH_CAP_FBSDP_NO &&
+		x86_arch_cap_msr & ARCH_CAP_PSDP_NO &&
+		x86_arch_cap_msr & ARCH_CAP_SBDR_SSDP_NO);
+}
+
+static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
+{
+	u64 x86_arch_cap_msr = x86_read_arch_cap_msr();
+
+	/* Set ITLB_MULTIHIT bug if cpu is not in the whitelist and not mitigated */
+	if (!cpu_matches(cpu_vuln_whitelist, NO_ITLB_MULTIHIT) &&
+	    !(x86_arch_cap_msr & ARCH_CAP_PSCHANGE_MC_NO))
+		setup_force_cpu_bug(X86_BUG_ITLB_MULTIHIT);
+
+	if (cpu_matches(cpu_vuln_whitelist, NO_SPECULATION))
+		return;
+
+	setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
+	setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
+
+	if (!cpu_matches(cpu_vuln_whitelist, NO_SSB) &&
+	    !(x86_arch_cap_msr & ARCH_CAP_SSB_NO) &&
+	   !cpu_has(c, X86_FEATURE_AMD_SSB_NO))
+		setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS);
+
+	if (x86_arch_cap_msr & ARCH_CAP_IBRS_ALL)
+		setup_force_cpu_cap(X86_FEATURE_IBRS_ENHANCED);
+
+	if (!cpu_matches(cpu_vuln_whitelist, NO_MDS) &&
+	    !(x86_arch_cap_msr & ARCH_CAP_MDS_NO)) {
+		setup_force_cpu_bug(X86_BUG_MDS);
+		if (cpu_matches(cpu_vuln_whitelist, MSBDS_ONLY))
+			setup_force_cpu_bug(X86_BUG_MSBDS_ONLY);
+	}
+
+	if (!cpu_matches(cpu_vuln_whitelist, NO_SWAPGS))
+		setup_force_cpu_bug(X86_BUG_SWAPGS);
+
+	/*
+	 * When the CPU is not mitigated for TAA (TAA_NO=0) set TAA bug when:
+	 *	- TSX is supported or
+	 *	- TSX_CTRL is present
+	 *
+	 * TSX_CTRL check is needed for cases when TSX could be disabled before
+	 * the kernel boot e.g. kexec.
+	 * TSX_CTRL check alone is not sufficient for cases when the microcode
+	 * update is not present or running as guest that don't get TSX_CTRL.
+	 */
+	if (!(x86_arch_cap_msr & ARCH_CAP_TAA_NO) &&
+	    (cpu_has(c, X86_FEATURE_RTM) ||
+	     (x86_arch_cap_msr & ARCH_CAP_TSX_CTRL_MSR)))
+		setup_force_cpu_bug(X86_BUG_TAA);
+
+	/*
+	 * SRBDS affects CPUs which support RDRAND or RDSEED and are listed
+	 * in the vulnerability blacklist.
+	 *
+	 * Some of the implications and mitigation of Shared Buffers Data
+	 * Sampling (SBDS) are similar to SRBDS. Give SBDS same treatment as
+	 * SRBDS.
+	 */
+	if ((cpu_has(c, X86_FEATURE_RDRAND) ||
+	     cpu_has(c, X86_FEATURE_RDSEED)) &&
+	    cpu_matches(cpu_vuln_blacklist, SRBDS | MMIO_SBDS))
+		    setup_force_cpu_bug(X86_BUG_SRBDS);
+
+	/*
+	 * Processor MMIO Stale Data bug enumeration
+	 *
+	 * Affected CPU list is generally enough to enumerate the vulnerability,
+	 * but for virtualization case check for ARCH_CAP MSR bits also, VMM may
+	 * not want the guest to enumerate the bug.
+	 */
+	if (cpu_matches(cpu_vuln_blacklist, MMIO) &&
+	    !arch_cap_mmio_immune(x86_arch_cap_msr))
+		setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
+
+	if (!cpu_has(c, X86_FEATURE_BTC_NO)) {
+		if (cpu_matches(cpu_vuln_blacklist, RETBLEED) || (x86_arch_cap_msr & ARCH_CAP_RSBA))
+			setup_force_cpu_bug(X86_BUG_RETBLEED);
+	}
+
+	if (cpu_has(c, X86_FEATURE_IBRS_ENHANCED) &&
+	    !cpu_matches(cpu_vuln_whitelist, NO_EIBRS_PBRSB) &&
+	    !(x86_arch_cap_msr & ARCH_CAP_PBRSB_NO))
+		setup_force_cpu_bug(X86_BUG_EIBRS_PBRSB);
+
+	if (cpu_matches(cpu_vuln_blacklist, SMT_RSB))
+		setup_force_cpu_bug(X86_BUG_SMT_RSB);
+
+	/*
+	 * Check if CPU is vulnerable to GDS. If running in a virtual machine on
+	 * an affected processor, the VMM may have disabled the use of GATHER by
+	 * disabling AVX2. The only way to do this in HW is to clear XCR0[2],
+	 * which means that AVX will be disabled.
+	 */
+	if (cpu_matches(cpu_vuln_blacklist, GDS) && !(x86_arch_cap_msr & ARCH_CAP_GDS_NO) &&
+	    boot_cpu_has(X86_FEATURE_AVX))
+		setup_force_cpu_bug(X86_BUG_GDS);
+
+	/*
+	 * Set the bug only on bare-metal. A nested hypervisor should already be
+	 * deploying IBPB to isolate itself from nested guests.
+	 */
+	if (cpu_matches(cpu_vuln_blacklist, VMSCAPE) &&
+	    !boot_cpu_has(X86_FEATURE_HYPERVISOR))
+		setup_force_cpu_bug(X86_BUG_VMSCAPE);
+
+	/* When virtualized, eIBRS could be hidden, assume vulnerable */
+	if (!(x86_arch_cap_msr & ARCH_CAP_BHI_NO) &&
+	    !cpu_matches(cpu_vuln_whitelist, NO_BHI) &&
+	    (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED) ||
+	     boot_cpu_has(X86_FEATURE_HYPERVISOR)))
+		setup_force_cpu_bug(X86_BUG_BHI);
+
+	if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
+		return;
+
+	/* Rogue Data Cache Load? No! */
+	if (x86_arch_cap_msr & ARCH_CAP_RDCL_NO)
+		return;
+
+	setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
+
+	if (cpu_matches(cpu_vuln_whitelist, NO_L1TF))
+		return;
+
+	setup_force_cpu_bug(X86_BUG_L1TF);
+}
+
+/*
+ * The NOPL instruction is supposed to exist on all CPUs of family >= 6;
+ * unfortunately, that's not true in practice because of early VIA
+ * chips and (more importantly) broken virtualizers that are not easy
+ * to detect. In the latter case it doesn't even *fail* reliably, so
+ * probing for it doesn't even work. Disable it completely on 32-bit
+ * unless we can find a reliable way to detect all the broken cases.
+ * Enable it explicitly on 64-bit for non-constant inputs of cpu_has().
+ */
+static void detect_nopl(void)
+{
+#ifdef CONFIG_X86_32
+	setup_clear_cpu_cap(X86_FEATURE_NOPL);
+#else
+	setup_force_cpu_cap(X86_FEATURE_NOPL);
+#endif
+}
+
 /*
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
@@ -737,24 +1176,36 @@
 		identify_cpu_without_cpuid(c);
 
 	/* cyrix could have cpuid enabled via c_identify()*/
-	if (!have_cpuid_p())
-		return;
+	if (have_cpuid_p()) {
+		cpu_detect(c);
+		get_cpu_vendor(c);
+		get_cpu_cap(c);
 
-	cpu_detect(c);
-	get_cpu_vendor(c);
-	get_cpu_cap(c);
+		if (this_cpu->c_early_init)
+			this_cpu->c_early_init(c);
 
-	if (this_cpu->c_early_init)
-		this_cpu->c_early_init(c);
+		c->cpu_index = 0;
+		filter_cpuid_features(c, false);
 
-	c->cpu_index = 0;
-	filter_cpuid_features(c, false);
-
-	if (this_cpu->c_bsp_init)
-		this_cpu->c_bsp_init(c);
+		if (this_cpu->c_bsp_init)
+			this_cpu->c_bsp_init(c);
+	}
 
 	setup_force_cpu_cap(X86_FEATURE_ALWAYS);
+
+	cpu_set_bug_bits(c);
+
 	fpu__init_system(c);
+
+#ifdef CONFIG_X86_32
+	/*
+	 * Regardless of whether PCID is enumerated, the SDM says
+	 * that it can't be enabled in 32-bit mode.
+	 */
+	setup_clear_cpu_cap(X86_FEATURE_PCID);
+#endif
+
+	detect_nopl();
 }
 
 void __init early_cpu_init(void)
@@ -790,24 +1241,6 @@
 	early_identify_cpu(&boot_cpu_data);
 }
 
-/*
- * The NOPL instruction is supposed to exist on all CPUs of family >= 6;
- * unfortunately, that's not true in practice because of early VIA
- * chips and (more importantly) broken virtualizers that are not easy
- * to detect. In the latter case it doesn't even *fail* reliably, so
- * probing for it doesn't even work. Disable it completely on 32-bit
- * unless we can find a reliable way to detect all the broken cases.
- * Enable it explicitly on 64-bit for non-constant inputs of cpu_has().
- */
-static void detect_nopl(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_X86_32
-	clear_cpu_cap(c, X86_FEATURE_NOPL);
-#else
-	set_cpu_cap(c, X86_FEATURE_NOPL);
-#endif
-}
-
 static void generic_identify(struct cpuinfo_x86 *c)
 {
 	c->extended_cpuid_level = 0;
@@ -838,8 +1271,6 @@
 	}
 
 	get_model_name(c); /* Default name */
-
-	detect_nopl(c);
 }
 
 static void x86_init_cache_qos(struct cpuinfo_x86 *c)
@@ -864,9 +1295,9 @@
 	int i;
 
 	c->loops_per_jiffy = loops_per_jiffy;
-	c->x86_cache_size = -1;
+	c->x86_cache_size = 0;
 	c->x86_vendor = X86_VENDOR_UNKNOWN;
-	c->x86_model = c->x86_mask = 0;	/* So far unknown... */
+	c->x86_model = c->x86_stepping = 0;	/* So far unknown... */
 	c->x86_vendor_id[0] = '\0'; /* Unset */
 	c->x86_model_id[0] = '\0';  /* Unset */
 	c->x86_max_cores = 1;
@@ -889,11 +1320,8 @@
 	if (this_cpu->c_identify)
 		this_cpu->c_identify(c);
 
-	/* Clear/Set all flags overriden by options, after probe */
-	for (i = 0; i < NCAPINTS; i++) {
-		c->x86_capability[i] &= ~cpu_caps_cleared[i];
-		c->x86_capability[i] |= cpu_caps_set[i];
-	}
+ 	/* Clear/Set all flags overridden by options, after probe */
+	apply_forced_caps(c);
 
 #ifdef CONFIG_X86_64
 	c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
@@ -919,6 +1347,9 @@
 	setup_smep(c);
 	setup_smap(c);
 
+	/* Set up PCID */
+	setup_pcid(c);
+
 	/*
 	 * The vendor-specific functions might have changed features.
 	 * Now we do "generic changes."
@@ -951,10 +1382,7 @@
 	 * Clear/Set all flags overriden by options, need do it
 	 * before following smp all cpus cap AND.
 	 */
-	for (i = 0; i < NCAPINTS; i++) {
-		c->x86_capability[i] &= ~cpu_caps_cleared[i];
-		c->x86_capability[i] |= cpu_caps_set[i];
-	}
+	apply_forced_caps(c);
 
 	/*
 	 * On SMP, boot_cpu_data holds the common feature set between
@@ -980,6 +1408,8 @@
 #ifdef CONFIG_NUMA
 	numa_add_cpu(smp_processor_id());
 #endif
+	/* The boot/hotplug time assigment got cleared, restore it */
+	c->logical_proc_id = topology_phys_to_logical_pkg(c->phys_proc_id);
 }
 
 /*
@@ -1026,6 +1456,8 @@
 	enable_sep_cpu();
 #endif
 	cpu_detect_tlb(&boot_cpu_data);
+
+	tsx_init();
 }
 
 void identify_secondary_cpu(struct cpuinfo_x86 *c)
@@ -1036,6 +1468,10 @@
 	enable_sep_cpu();
 #endif
 	mtrr_ap_init();
+	x86_spec_ctrl_setup_ap();
+	update_srbds_msr();
+	if (boot_cpu_has_bug(X86_BUG_GDS))
+		update_gds_msr();
 }
 
 struct msr_range {
@@ -1112,8 +1548,8 @@
 
 	printk(KERN_CONT " (family: 0x%x, model: 0x%x", c->x86, c->x86_model);
 
-	if (c->x86_mask || c->cpuid_level >= 0)
-		printk(KERN_CONT ", stepping: 0x%x)\n", c->x86_mask);
+	if (c->x86_stepping || c->cpuid_level >= 0)
+		pr_cont(", stepping: 0x%x)\n", c->x86_stepping);
 	else
 		printk(KERN_CONT ")\n");
 
@@ -1130,7 +1566,7 @@
 {
 	int bit;
 
-	if (get_option(&arg, &bit) && bit < NCAPINTS*32)
+	if (get_option(&arg, &bit) && bit >= 0 && bit < NCAPINTS * 32)
 		setup_clear_cpu_cap(bit);
 	else
 		return 0;
@@ -1174,7 +1610,7 @@
 	  [DEBUG_STACK - 1]			= DEBUG_STKSZ
 };
 
-static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
+DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(char, exception_stacks
 	[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]);
 
 /* May not be marked __init: used by software suspend */
@@ -1337,6 +1773,14 @@
 	 * try to read it.
 	 */
 	cr4_init_shadow();
+	if (!kaiser_enabled) {
+		/*
+		 * secondary_startup_64() deferred setting PGE in cr4:
+		 * probe_page_size_mask() sets it on the boot cpu,
+		 * but it needs to be set on each secondary cpu.
+		 */
+		cr4_set_bits(X86_CR4_PGE);
+	}
 
 	/*
 	 * Load microcode on this cpu if a valid microcode is available.
@@ -1443,7 +1887,9 @@
 
 	printk(KERN_INFO "Initializing CPU#%d\n", cpu);
 
-	if (cpu_feature_enabled(X86_FEATURE_VME) || cpu_has_tsc || cpu_has_de)
+	if (cpu_feature_enabled(X86_FEATURE_VME) ||
+	    cpu_has_tsc ||
+	    boot_cpu_has(X86_FEATURE_DE))
 		cr4_clear_bits(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
 	load_current_idt();
@@ -1476,20 +1922,6 @@
 }
 #endif
 
-#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
-void warn_pre_alternatives(void)
-{
-	WARN(1, "You're using static_cpu_has before alternatives have run!\n");
-}
-EXPORT_SYMBOL_GPL(warn_pre_alternatives);
-#endif
-
-inline bool __static_cpu_has_safe(u16 bit)
-{
-	return boot_cpu_has(bit);
-}
-EXPORT_SYMBOL_GPL(__static_cpu_has_safe);
-
 static void bsp_resume(void)
 {
 	if (this_cpu->c_bsp_resume)
@@ -1506,3 +1938,54 @@
 	return 0;
 }
 core_initcall(init_cpu_syscore);
+
+void __init arch_cpu_finalize_init(void)
+{
+	identify_boot_cpu();
+
+	amd_check_microcode();
+
+	/*
+	 * identify_boot_cpu() initialized SMT support information, let the
+	 * core code know.
+	 */
+	cpu_smt_check_topology();
+
+	if (!IS_ENABLED(CONFIG_SMP)) {
+		pr_info("CPU: ");
+		print_cpu_info(&boot_cpu_data);
+	}
+
+	cpu_select_mitigations();
+
+	arch_smt_update();
+
+	if (IS_ENABLED(CONFIG_X86_32)) {
+		/*
+		 * Check whether this is a real i386 which is not longer
+		 * supported and fixup the utsname.
+		 */
+		if (boot_cpu_data.x86 < 4)
+			panic("Kernel requires i486+ for 'invlpg' and other features");
+
+		init_utsname()->machine[1] =
+			'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
+	}
+
+	alternative_instructions();
+
+	if (IS_ENABLED(CONFIG_X86_64)) {
+		/*
+		 * Make sure the first 2MB area is not mapped by huge pages
+		 * There are typically fixed size MTRRs in there and overlapping
+		 * MTRRs into large pages causes slow downs.
+		 *
+		 * Right now we don't do that with gbpages because there seems
+		 * very little benefit for that case.
+		 */
+		if (!direct_gbpages)
+			set_memory_4k((unsigned long)__va(0), 1);
+	} else {
+		fpu__init_check_bugs();
+	}
+}
--- linux-4.4.0.orig/arch/x86/kernel/cpu/cpu.h
+++ linux-4.4.0/arch/x86/kernel/cpu/cpu.h
@@ -44,6 +44,30 @@
 extern const struct cpu_dev *const __x86_cpu_dev_start[],
 			    *const __x86_cpu_dev_end[];
 
+#ifdef CONFIG_CPU_SUP_INTEL
+enum tsx_ctrl_states {
+	TSX_CTRL_ENABLE,
+	TSX_CTRL_DISABLE,
+	TSX_CTRL_NOT_SUPPORTED,
+};
+
+extern __ro_after_init enum tsx_ctrl_states tsx_ctrl_state;
+
+extern void __init tsx_init(void);
+extern void tsx_enable(void);
+extern void tsx_disable(void);
+#else
+static inline void tsx_init(void) { }
+#endif /* CONFIG_CPU_SUP_INTEL */
+
 extern void get_cpu_cap(struct cpuinfo_x86 *c);
 extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
+void cpu_select_mitigations(void);
+
+extern void x86_spec_ctrl_setup_ap(void);
+extern void update_srbds_msr(void);
+extern void update_gds_msr(void);
+
+extern u64 x86_read_arch_cap_msr(void);
+
 #endif /* ARCH_X86_CPU_H */
--- linux-4.4.0.orig/arch/x86/kernel/cpu/cyrix.c
+++ linux-4.4.0/arch/x86/kernel/cpu/cyrix.c
@@ -8,6 +8,7 @@
 #include <linux/timer.h>
 #include <asm/pci-direct.h>
 #include <asm/tsc.h>
+#include <asm/cpufeature.h>
 
 #include "cpu.h"
 
@@ -120,7 +121,7 @@
 	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
 
 	/* Load/Store Serialize to mem access disable (=reorder it) */
-	setCx86_old(CX86_PCR0, getCx86_old(CX86_PCR0) & ~0x80);
+	setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80);
 	/* set load/store serialize from 1GB to 4GB */
 	ccr3 |= 0xe0;
 	setCx86(CX86_CCR3, ccr3);
@@ -131,11 +132,11 @@
 	printk(KERN_INFO "Enable Memory-Write-back mode on Cyrix/NSC processor.\n");
 
 	/* CCR2 bit 2: unlock NW bit */
-	setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) & ~0x04);
+	setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04);
 	/* set 'Not Write-through' */
 	write_cr0(read_cr0() | X86_CR0_NW);
 	/* CCR2 bit 2: lock NW bit and set WT1 */
-	setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x14);
+	setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14);
 }
 
 /*
@@ -149,14 +150,14 @@
 	local_irq_save(flags);
 
 	/* Suspend on halt power saving and enable #SUSP pin */
-	setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x88);
+	setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
 
 	ccr3 = getCx86(CX86_CCR3);
 	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);	/* enable MAPEN */
 
 
 	/* FPU fast, DTE cache, Mem bypass */
-	setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x38);
+	setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x38);
 	setCx86(CX86_CCR3, ccr3);			/* disable MAPEN */
 
 	set_cx86_memwb();
@@ -211,7 +212,7 @@
 
 	/* common case step number/rev -- exceptions handled below */
 	c->x86_model = (dir1 >> 4) + 1;
-	c->x86_mask = dir1 & 0xf;
+	c->x86_stepping = dir1 & 0xf;
 
 	/* Now cook; the original recipe is by Channing Corn, from Cyrix.
 	 * We do the same thing for each generation: we work out
@@ -291,7 +292,7 @@
 		/* GXm supports extended cpuid levels 'ala' AMD */
 		if (c->cpuid_level == 2) {
 			/* Enable cxMMX extensions (GX1 Datasheet 54) */
-			setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7) | 1);
+			setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
 
 			/*
 			 * GXm : 0x30 ... 0x5f GXm  datasheet 51
@@ -314,7 +315,7 @@
 		if (dir1 > 7) {
 			dir0_msn++;  /* M II */
 			/* Enable MMX extensions (App note 108) */
-			setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7)|1);
+			setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
 		} else {
 			/* A 6x86MX - it has the bug. */
 			set_cpu_bug(c, X86_BUG_COMA);
@@ -432,7 +433,7 @@
 			/* enable MAPEN  */
 			setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
 			/* enable cpuid  */
-			setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x80);
+			setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);
 			/* disable MAPEN */
 			setCx86(CX86_CCR3, ccr3);
 			local_irq_restore(flags);
--- linux-4.4.0.orig/arch/x86/kernel/cpu/hypervisor.c
+++ linux-4.4.0/arch/x86/kernel/cpu/hypervisor.c
@@ -21,7 +21,8 @@
  *
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <asm/processor.h>
 #include <asm/hypervisor.h>
 
--- linux-4.4.0.orig/arch/x86/kernel/cpu/intel.c
+++ linux-4.4.0/arch/x86/kernel/cpu/intel.c
@@ -5,14 +5,16 @@
 #include <linux/smp.h>
 #include <linux/sched.h>
 #include <linux/thread_info.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/uaccess.h>
 
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <asm/pgtable.h>
 #include <asm/msr.h>
 #include <asm/bugs.h>
 #include <asm/cpu.h>
+#include <asm/intel-family.h>
+#include <asm/microcode_intel.h>
 
 #ifdef CONFIG_X86_64
 #include <linux/topology.h>
@@ -42,14 +44,8 @@
 		(c->x86 == 0x6 && c->x86_model >= 0x0e))
 		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
 
-	if (c->x86 >= 6 && !cpu_has(c, X86_FEATURE_IA64)) {
-		unsigned lower_word;
-
-		wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-		/* Required by the SDM */
-		sync_core();
-		rdmsr(MSR_IA32_UCODE_REV, lower_word, c->microcode);
-	}
+	if (c->x86 >= 6 && !cpu_has(c, X86_FEATURE_IA64))
+		c->microcode = intel_get_microcode_revision();
 
 	/*
 	 * Atom erratum AAE44/AAF40/AAG38/AAH41:
@@ -59,7 +55,7 @@
 	 * need the microcode to have already been loaded... so if it is
 	 * not, recommend a BIOS update and disable large pages.
 	 */
-	if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_mask <= 2 &&
+	if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_stepping <= 2 &&
 	    c->microcode < 0x20e) {
 		printk(KERN_WARNING "Atom PSE erratum detected, BIOS microcode update recommended\n");
 		clear_cpu_cap(c, X86_FEATURE_PSE);
@@ -75,7 +71,7 @@
 
 	/* CPUID workaround for 0F33/0F34 CPU */
 	if (c->x86 == 0xF && c->x86_model == 0x3
-	    && (c->x86_mask == 0x3 || c->x86_mask == 0x4))
+	    && (c->x86_stepping == 0x3 || c->x86_stepping == 0x4))
 		c->x86_phys_bits = 36;
 
 	/*
@@ -160,6 +156,26 @@
 		pr_info("Disabling PGE capability bit\n");
 		setup_clear_cpu_cap(X86_FEATURE_PGE);
 	}
+
+	if (c->cpuid_level >= 0x00000001) {
+		u32 eax, ebx, ecx, edx;
+
+		cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
+		/*
+		 * If HTT (EDX[28]) is set EBX[16:23] contain the number of
+		 * apicids which are reserved per package. Store the resulting
+		 * shift value for the package management code.
+		 */
+		if (edx & (1U << 28))
+			c->x86_coreid_bits = get_count_order((ebx >> 16) & 0xff);
+	}
+
+	/*
+	 * Get the number of SMT siblings early from the extended topology
+	 * leaf, if available. Otherwise try the legacy SMT detection.
+	 */
+	if (detect_extended_topology_early(c) < 0)
+		detect_ht_early(c);
 }
 
 #ifdef CONFIG_X86_32
@@ -175,8 +191,8 @@
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
 	    boot_cpu_data.x86 == 6 &&
 	    boot_cpu_data.x86_model == 1 &&
-	    boot_cpu_data.x86_mask < 8) {
-		printk(KERN_INFO "Pentium Pro with Errata#50 detected. Taking evasive action.\n");
+	    boot_cpu_data.x86_stepping < 8) {
+		pr_info("Pentium Pro with Errata#50 detected. Taking evasive action.\n");
 		return 1;
 	}
 	return 0;
@@ -192,7 +208,7 @@
 	 * Mask B, Pentium, but not Pentium MMX
 	 */
 	if (c->x86 == 5 &&
-	    c->x86_mask >= 1 && c->x86_mask <= 4 &&
+	    c->x86_stepping >= 1 && c->x86_stepping <= 4 &&
 	    c->x86_model <= 3) {
 		/*
 		 * Remember we have B step Pentia with bugs
@@ -235,7 +251,7 @@
 	 * SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until
 	 * model 3 mask 3
 	 */
-	if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
+	if ((c->x86<<8 | c->x86_model<<4 | c->x86_stepping) < 0x633)
 		clear_cpu_cap(c, X86_FEATURE_SEP);
 
 	/*
@@ -253,7 +269,7 @@
 	 * P4 Xeon errata 037 workaround.
 	 * Hardware prefetcher may cause stale data to be loaded into the cache.
 	 */
-	if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
+	if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_stepping == 1)) {
 		if (msr_set_bit(MSR_IA32_MISC_ENABLE,
 				MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT)
 		    > 0) {
@@ -269,7 +285,7 @@
 	 * Specification Update").
 	 */
 	if (cpu_has_apic && (c->x86<<8 | c->x86_model<<4) == 0x520 &&
-	    (c->x86_mask < 0x6 || c->x86_mask == 0xb))
+	    (c->x86_stepping < 0x6 || c->x86_stepping == 0xb))
 		set_cpu_bug(c, X86_BUG_11AP);
 
 
@@ -445,7 +461,8 @@
 
 	if (cpu_has_xmm2)
 		set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-	if (cpu_has_ds) {
+
+	if (boot_cpu_has(X86_FEATURE_DS)) {
 		unsigned int l1;
 		rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
 		if (!(l1 & (1<<11)))
@@ -458,6 +475,10 @@
 	    (c->x86_model == 29 || c->x86_model == 46 || c->x86_model == 47))
 		set_cpu_bug(c, X86_BUG_CLFLUSH_MONITOR);
 
+	if (c->x86 == 6 && boot_cpu_has(X86_FEATURE_MWAIT) &&
+		((c->x86_model == INTEL_FAM6_ATOM_GOLDMONT)))
+		set_cpu_bug(c, X86_BUG_MONITOR);
+
 #ifdef CONFIG_X86_64
 	if (c->x86 == 15)
 		c->x86_cache_alignment = c->x86_clflush_size * 2;
@@ -483,7 +504,7 @@
 		case 6:
 			if (l2 == 128)
 				p = "Celeron (Mendocino)";
-			else if (c->x86_mask == 0 || c->x86_mask == 5)
+			else if (c->x86_stepping == 0 || c->x86_stepping == 5)
 				p = "Celeron-A";
 			break;
 
@@ -510,6 +531,11 @@
 		detect_vmx_virtcap(c);
 
 	init_intel_energy_perf(c);
+
+	if (tsx_ctrl_state == TSX_CTRL_ENABLE)
+		tsx_enable();
+	if (tsx_ctrl_state == TSX_CTRL_DISABLE)
+		tsx_disable();
 }
 
 #ifdef CONFIG_X86_32
--- linux-4.4.0.orig/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ linux-4.4.0/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -14,7 +14,7 @@
 #include <linux/sysfs.h>
 #include <linux/pci.h>
 
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <asm/amd_nb.h>
 #include <asm/smp.h>
 
@@ -591,7 +591,7 @@
 	unsigned		edx;
 
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
-		if (cpu_has_topoext)
+		if (boot_cpu_has(X86_FEATURE_TOPOEXT))
 			cpuid_count(0x8000001d, index, &eax.full,
 				    &ebx.full, &ecx.full, &edx);
 		else
@@ -637,7 +637,7 @@
 void init_amd_cacheinfo(struct cpuinfo_x86 *c)
 {
 
-	if (cpu_has_topoext) {
+	if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
 		num_cache_leaves = find_num_cache_leaves(c);
 	} else if (c->extended_cpuid_level >= 0x80000006) {
 		if (cpuid_edx(0x80000006) & 0xf000)
@@ -809,7 +809,7 @@
 	struct cacheinfo *this_leaf;
 	int i, sibling;
 
-	if (cpu_has_topoext) {
+	if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
 		unsigned int apicid, nshared, first, last;
 
 		this_leaf = this_cpu_ci->info_list + index;
@@ -934,6 +934,8 @@
 		ci_leaf_init(this_leaf++, &id4_regs);
 		__cache_cpumap_setup(cpu, idx, &id4_regs);
 	}
+	this_cpu_ci->cpu_map_populated = true;
+
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/x86/kernel/cpu/match.c
+++ linux-4.4.0/arch/x86/kernel/cpu/match.c
@@ -1,7 +1,7 @@
 #include <asm/cpu_device_id.h>
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <linux/cpu.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 
 /**
@@ -15,12 +15,17 @@
  * respective wildcard entries.
  *
  * A typical table entry would be to match a specific CPU
- * { X86_VENDOR_INTEL, 6, 0x12 }
- * or to match a specific CPU feature
- * { X86_FEATURE_MATCH(X86_FEATURE_FOOBAR) }
+ *
+ * X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_BROADWELL,
+ *				      X86_FEATURE_ANY, NULL);
  *
  * Fields can be wildcarded with %X86_VENDOR_ANY, %X86_FAMILY_ANY,
- * %X86_MODEL_ANY, %X86_FEATURE_ANY or 0 (except for vendor)
+ * %X86_MODEL_ANY, %X86_FEATURE_ANY (except for vendor)
+ *
+ * asm/cpu_device_id.h contains a set of useful macros which are shortcuts
+ * for various common selections. The above can be shortened to:
+ *
+ * X86_MATCH_INTEL_FAM6_MODEL(BROADWELL, NULL);
  *
  * Arrays used to match for this should also be declared using
  * MODULE_DEVICE_TABLE(x86cpu, ...)
@@ -33,13 +38,18 @@
 	const struct x86_cpu_id *m;
 	struct cpuinfo_x86 *c = &boot_cpu_data;
 
-	for (m = match; m->vendor | m->family | m->model | m->feature; m++) {
+	for (m = match;
+	     m->vendor | m->family | m->model | m->steppings | m->feature;
+	     m++) {
 		if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor)
 			continue;
 		if (m->family != X86_FAMILY_ANY && c->x86 != m->family)
 			continue;
 		if (m->model != X86_MODEL_ANY && c->x86_model != m->model)
 			continue;
+		if (m->steppings != X86_STEPPING_ANY &&
+		    !(BIT(c->x86_stepping) & m->steppings))
+			continue;
 		if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature))
 			continue;
 		return m;
@@ -47,3 +57,34 @@
 	return NULL;
 }
 EXPORT_SYMBOL(x86_match_cpu);
+
+static const struct x86_cpu_desc *
+x86_match_cpu_with_stepping(const struct x86_cpu_desc *match)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+	const struct x86_cpu_desc *m;
+
+	for (m = match; m->x86_family | m->x86_model; m++) {
+		if (c->x86_vendor != m->x86_vendor)
+			continue;
+		if (c->x86 != m->x86_family)
+			continue;
+		if (c->x86_model != m->x86_model)
+			continue;
+		if (c->x86_stepping != m->x86_stepping)
+			continue;
+		return m;
+	}
+	return NULL;
+}
+
+bool x86_cpu_has_min_microcode_rev(const struct x86_cpu_desc *table)
+{
+	const struct x86_cpu_desc *res = x86_match_cpu_with_stepping(table);
+
+	if (!res || res->x86_microcode_rev > boot_cpu_data.microcode)
+		return false;
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(x86_cpu_has_min_microcode_rev);
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mcheck/mce-genpool.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mcheck/mce-genpool.c
@@ -29,7 +29,7 @@
 void mce_gen_pool_process(void)
 {
 	struct llist_node *head;
-	struct mce_evt_llist *node;
+	struct mce_evt_llist *node, *tmp;
 	struct mce *mce;
 
 	head = llist_del_all(&mce_event_llist);
@@ -37,7 +37,7 @@
 		return;
 
 	head = llist_reverse_order(head);
-	llist_for_each_entry(node, head, llnode) {
+	llist_for_each_entry_safe(node, tmp, head, llnode) {
 		mce = &node->mce;
 		atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
 		gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node));
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mcheck/mce-inject.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mcheck/mce-inject.c
@@ -152,7 +152,6 @@
 	if (context == MCJ_CTX_RANDOM)
 		return;
 
-#ifdef CONFIG_X86_LOCAL_APIC
 	if (m->inject_flags & (MCJ_IRQ_BROADCAST | MCJ_NMI_BROADCAST)) {
 		unsigned long start;
 		int cpu;
@@ -193,9 +192,7 @@
 		raise_local();
 		put_cpu();
 		put_online_cpus();
-	} else
-#endif
-	{
+	} else {
 		preempt_disable();
 		raise_local();
 		preempt_enable();
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mcheck/mce-severity.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mcheck/mce-severity.c
@@ -132,6 +132,11 @@
 		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR),
 		USER
 		),
+	MCESEV(
+		PANIC, "Instruction fetch error in kernel",
+		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR),
+		KERNEL
+		),
 #endif
 	MCESEV(
 		PANIC, "Action required: unknown MCACOD",
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mcheck/mce.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mcheck/mce.c
@@ -60,6 +60,9 @@
 	smp_load_acquire(&(p)); \
 })
 
+/* sysfs synchronization */
+static DEFINE_MUTEX(mce_sysfs_mutex);
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/mce.h>
 
@@ -135,6 +138,8 @@
 	m->socketid = cpu_data(m->extcpu).phys_proc_id;
 	m->apicid = cpu_data(m->extcpu).initial_apicid;
 	rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap);
+
+	m->microcode = boot_cpu_data.microcode;
 }
 
 DEFINE_PER_CPU(struct mce, injectm);
@@ -255,7 +260,7 @@
 	 */
 	pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
 		m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
-		cpu_data(m->extcpu).microcode);
+		m->microcode);
 
 	/*
 	 * Print out human-readable details about the MCE error,
@@ -667,6 +672,7 @@
 		}
 
 		if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
+			m->bank = i;
 			*msg = tmp;
 			ret = 1;
 		}
@@ -977,11 +983,12 @@
 	int i;
 	int worst = 0;
 	int severity;
+
 	/*
 	 * Establish sequential order between the CPUs entering the machine
 	 * check handler.
 	 */
-	int order;
+	int order = -1;
 	/*
 	 * If no_way_out gets set, there is no safe way to recover from this
 	 * MCE.  If mca_cfg.tolerant is cranked up, we'll try anyway.
@@ -997,7 +1004,12 @@
 	char *msg = "Unknown";
 	u64 recover_paddr = ~0ull;
 	int flags = MF_ACTION_REQUIRED;
-	int lmce = 0;
+
+	/*
+	 * MCEs are always local on AMD. Same is determined by MCG_STATUS_LMCES
+	 * on Intel.
+	 */
+	int lmce = 1;
 
 	/* If this CPU is offline, just bail out. */
 	if (cpu_is_offline(smp_processor_id())) {
@@ -1036,17 +1048,23 @@
 		kill_it = 1;
 
 	/*
-	 * Check if this MCE is signaled to only this logical processor
+	 * Check if this MCE is signaled to only this logical processor,
+	 * on Intel only.
 	 */
-	if (m.mcgstatus & MCG_STATUS_LMCES)
-		lmce = 1;
-	else {
-		/*
-		 * Go through all the banks in exclusion of the other CPUs.
-		 * This way we don't report duplicated events on shared banks
-		 * because the first one to see it will clear it.
-		 * If this is a Local MCE, then no need to perform rendezvous.
-		 */
+	if (m.cpuvendor == X86_VENDOR_INTEL)
+		lmce = m.mcgstatus & MCG_STATUS_LMCES;
+
+	/*
+	 * Local machine check may already know that we have to panic.
+	 * Broadcast machine check begins rendezvous in mce_start()
+	 * Go through all banks in exclusion of the other CPUs. This way we
+	 * don't report duplicated events on shared banks because the first one
+	 * to see it will clear it.
+	 */
+	if (lmce) {
+		if (no_way_out)
+			mce_panic("Fatal local machine check", &m, msg);
+	} else {
 		order = mce_start(&no_way_out);
 	}
 
@@ -1125,12 +1143,17 @@
 			no_way_out = worst >= MCE_PANIC_SEVERITY;
 	} else {
 		/*
-		 * Local MCE skipped calling mce_reign()
-		 * If we found a fatal error, we need to panic here.
-		 */
-		 if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3)
-			mce_panic("Machine check from unknown source",
-				NULL, NULL);
+		 * If there was a fatal machine check we should have
+		 * already called mce_panic earlier in this function.
+		 * Since we re-read the banks, we might have found
+		 * something new. Check again to see if we found a
+		 * fatal error. We call "mce_severity()" again to
+		 * make sure we have the right "msg".
+		 */
+		if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3) {
+			mce_severity(&m, cfg->tolerant, &msg, true);
+			mce_panic("Local fatal machine check!", &m, msg);
+		}
 	}
 
 	/*
@@ -1513,11 +1536,10 @@
 			mce_flags.overflow_recov = 1;
 
 		/*
-		 * Turn off MC4_MISC thresholding banks on those models since
+		 * Turn off MC4_MISC thresholding banks on all models since
 		 * they're not supported there.
 		 */
-		if (c->x86 == 0x15 &&
-		    (c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
+		if (c->x86 == 0x15) {
 			int i;
 			u64 hwcr;
 			bool need_toggle;
@@ -1672,6 +1694,14 @@
 void (*machine_check_vector)(struct pt_regs *, long error_code) =
 						unexpected_machine_check;
 
+dotraplinkage void do_mce(struct pt_regs *regs, long error_code)
+{
+	machine_check_vector(regs, error_code);
+}
+
+static struct notifier_block mce_cpu_notifier;
+static bool mce_cpu_notifier_registered = false;
+
 /*
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off:
@@ -1702,6 +1732,18 @@
 
 	__mcheck_cpu_init_generic();
 	__mcheck_cpu_init_vendor(c);
+
+	if (!mce_cpu_notifier_registered) {
+		/*
+		 * Register the CPU hotplug notifier early (and it will
+		 * not be unregistered (as before) to not leave timers
+		 * undeleted. This function is called with required locks
+		 * being hold.
+		 */
+		__register_hotcpu_notifier(&mce_cpu_notifier);
+		mce_cpu_notifier_registered = true;
+	}
+
 	__mcheck_cpu_init_timer();
 }
 
@@ -2215,6 +2257,7 @@
 	if (kstrtou64(buf, 0, &new) < 0)
 		return -EINVAL;
 
+	mutex_lock(&mce_sysfs_mutex);
 	if (mca_cfg.ignore_ce ^ !!new) {
 		if (new) {
 			/* disable ce features */
@@ -2227,6 +2270,8 @@
 			on_each_cpu(mce_enable_ce, (void *)1, 1);
 		}
 	}
+	mutex_unlock(&mce_sysfs_mutex);
+
 	return size;
 }
 
@@ -2239,6 +2284,7 @@
 	if (kstrtou64(buf, 0, &new) < 0)
 		return -EINVAL;
 
+	mutex_lock(&mce_sysfs_mutex);
 	if (mca_cfg.cmci_disabled ^ !!new) {
 		if (new) {
 			/* disable cmci */
@@ -2250,6 +2296,8 @@
 			on_each_cpu(mce_enable_ce, NULL, 1);
 		}
 	}
+	mutex_unlock(&mce_sysfs_mutex);
+
 	return size;
 }
 
@@ -2257,8 +2305,16 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
-	ssize_t ret = device_store_int(s, attr, buf, size);
+	unsigned long old_check_interval = check_interval;
+	ssize_t ret = device_store_ulong(s, attr, buf, size);
+
+	if (check_interval == old_check_interval)
+		return ret;
+
+	mutex_lock(&mce_sysfs_mutex);
 	mce_restart();
+	mutex_unlock(&mce_sysfs_mutex);
+
 	return ret;
 }
 
@@ -2293,6 +2349,7 @@
 	NULL
 };
 
+static bool mce_device_initdone = false;
 static cpumask_var_t mce_device_initialized;
 
 static void mce_device_release(struct device *dev)
@@ -2409,14 +2466,16 @@
 
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_ONLINE:
-		mce_device_create(cpu);
+		if (mce_device_initdone)
+			mce_device_create(cpu);
 		if (threshold_cpu_callback)
 			threshold_cpu_callback(action, cpu);
 		break;
 	case CPU_DEAD:
 		if (threshold_cpu_callback)
 			threshold_cpu_callback(action, cpu);
-		mce_device_remove(cpu);
+		if (mce_device_initdone)
+			mce_device_remove(cpu);
 		mce_intel_hcpu_update(cpu);
 
 		/* intentionally ignoring frozen here */
@@ -2479,23 +2538,15 @@
 	if (err)
 		goto err_out_mem;
 
-	cpu_notifier_register_begin();
+	cpu_maps_update_begin();
 	for_each_online_cpu(i) {
 		err = mce_device_create(i);
 		if (err) {
-			/*
-			 * Register notifier anyway (and do not unreg it) so
-			 * that we don't leave undeleted timers, see notifier
-			 * callback above.
-			 */
-			__register_hotcpu_notifier(&mce_cpu_notifier);
-			cpu_notifier_register_done();
+			cpu_maps_update_done();
 			goto err_device_create;
 		}
 	}
-
-	__register_hotcpu_notifier(&mce_cpu_notifier);
-	cpu_notifier_register_done();
+	cpu_maps_update_done();
 
 	register_syscore_ops(&mce_syscore_ops);
 
@@ -2504,6 +2555,8 @@
 	if (err)
 		goto err_register;
 
+	mce_device_initdone = true;
+
 	return 0;
 
 err_register:
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -53,7 +53,7 @@
 	"load_store",
 	"insn_fetch",
 	"combined_unit",
-	"",
+	"decode_unit",
 	"northbridge",
 	"execution_unit",
 };
@@ -560,9 +560,12 @@
 	.store			= store,
 };
 
+static void threshold_block_release(struct kobject *kobj);
+
 static struct kobj_type threshold_ktype = {
 	.sysfs_ops		= &threshold_ops,
 	.default_attrs		= default_attrs,
+	.release		= threshold_block_release,
 };
 
 static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank,
@@ -682,6 +685,9 @@
 	const char *name = th_names[bank];
 	int err = 0;
 
+	if (!dev)
+		return -ENODEV;
+
 	if (is_shared_bank(bank)) {
 		nb = node_to_amd_nb(amd_get_nb_id(cpu));
 
@@ -762,8 +768,12 @@
 	return err;
 }
 
-static void deallocate_threshold_block(unsigned int cpu,
-						 unsigned int bank)
+static void threshold_block_release(struct kobject *kobj)
+{
+	kfree(to_block(kobj));
+}
+
+static void deallocate_threshold_block(unsigned int cpu, unsigned int bank)
 {
 	struct threshold_block *pos = NULL;
 	struct threshold_block *tmp = NULL;
@@ -773,13 +783,11 @@
 		return;
 
 	list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) {
-		kobject_put(&pos->kobj);
 		list_del(&pos->miscj);
-		kfree(pos);
+		kobject_put(&pos->kobj);
 	}
 
-	kfree(per_cpu(threshold_banks, cpu)[bank]->blocks);
-	per_cpu(threshold_banks, cpu)[bank]->blocks = NULL;
+	kobject_put(&head->blocks->kobj);
 }
 
 static void __threshold_remove_blocks(struct threshold_bank *b)
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -385,6 +385,9 @@
 {
 	__u64 msr_val;
 
+	if (static_cpu_has(X86_FEATURE_HWP))
+		wrmsrl_safe(MSR_HWP_STATUS, 0);
+
 	rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
 
 	/* Check for violation of core thermal thresholds*/
--- linux-4.4.0.orig/arch/x86/kernel/cpu/microcode/amd.c
+++ linux-4.4.0/arch/x86/kernel/cpu/microcode/amd.c
@@ -131,6 +131,9 @@
 	return size;
 }
 
+static enum ucode_state
+load_microcode_amd(bool save, u8 family, const u8 *data, size_t size);
+
 /*
  * Early load occurs before we can vmalloc(). So we look for the microcode
  * patch container file in initrd, traverse equivalent cpu table, look for a
@@ -438,7 +441,7 @@
 	eax   = cpuid_eax(0x00000001);
 	eax   = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
 
-	ret = load_microcode_amd(smp_processor_id(), eax, container, container_size);
+	ret = load_microcode_amd(true, eax, container, container_size);
 	if (ret != UCODE_OK)
 		retval = -EINVAL;
 
@@ -452,7 +455,7 @@
 	return retval;
 }
 
-void reload_ucode_amd(void)
+void reload_ucode_amd(unsigned int cpu)
 {
 	struct microcode_amd *mc;
 	u32 rev;
@@ -580,6 +583,7 @@
 #define F14H_MPB_MAX_SIZE 1824
 #define F15H_MPB_MAX_SIZE 4096
 #define F16H_MPB_MAX_SIZE 3458
+#define F17H_MPB_MAX_SIZE 3200
 
 	switch (family) {
 	case 0x14:
@@ -591,6 +595,9 @@
 	case 0x16:
 		max_size = F16H_MPB_MAX_SIZE;
 		break;
+	case 0x17:
+		max_size = F17H_MPB_MAX_SIZE;
+		break;
 	default:
 		max_size = F1XH_MPB_MAX_SIZE;
 		break;
@@ -688,22 +695,26 @@
 		return -1;
 
 	/* need to apply patch? */
-	if (rev >= mc_amd->hdr.patch_id) {
-		c->microcode = rev;
-		uci->cpu_sig.rev = rev;
-		return 0;
-	}
+	if (rev >= mc_amd->hdr.patch_id)
+		goto out;
 
 	if (__apply_microcode_amd(mc_amd)) {
 		pr_err("CPU%d: update failed for patch_level=0x%08x\n",
 			cpu, mc_amd->hdr.patch_id);
 		return -1;
 	}
-	pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
-		mc_amd->hdr.patch_id);
 
-	uci->cpu_sig.rev = mc_amd->hdr.patch_id;
-	c->microcode = mc_amd->hdr.patch_id;
+	rev = mc_amd->hdr.patch_id;
+
+	pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev);
+
+out:
+	uci->cpu_sig.rev = rev;
+	c->microcode	 = rev;
+
+	/* Update boot_cpu_data's revision too, if we're on the BSP: */
+	if (c->cpu_index == boot_cpu_data.cpu_index)
+		boot_cpu_data.microcode = rev;
 
 	return 0;
 }
@@ -850,7 +861,8 @@
 	return UCODE_OK;
 }
 
-enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size)
+static enum ucode_state
+load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
 {
 	enum ucode_state ret;
 
@@ -864,8 +876,8 @@
 
 #ifdef CONFIG_X86_32
 	/* save BSP's matching patch for early load */
-	if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
-		struct ucode_patch *p = find_patch(cpu);
+	if (save) {
+		struct ucode_patch *p = find_patch(0);
 		if (p) {
 			memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
 			memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data),
@@ -897,11 +909,12 @@
 {
 	char fw_name[36] = "amd-ucode/microcode_amd.bin";
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	bool bsp = c->cpu_index == boot_cpu_data.cpu_index;
 	enum ucode_state ret = UCODE_NFOUND;
 	const struct firmware *fw;
 
 	/* reload ucode container only on the boot cpu */
-	if (!refresh_fw || c->cpu_index != boot_cpu_data.cpu_index)
+	if (!refresh_fw || !bsp)
 		return UCODE_OK;
 
 	if (c->x86 >= 0x15)
@@ -918,7 +931,7 @@
 		goto fw_release;
 	}
 
-	ret = load_microcode_amd(cpu, c->x86, fw->data, fw->size);
+	ret = load_microcode_amd(bsp, c->x86, fw->data, fw->size);
 
  fw_release:
 	release_firmware(fw);
--- linux-4.4.0.orig/arch/x86/kernel/cpu/microcode/core.c
+++ linux-4.4.0/arch/x86/kernel/cpu/microcode/core.c
@@ -44,7 +44,7 @@
 
 static struct microcode_ops	*microcode_ops;
 
-static bool dis_ucode_ldr;
+static bool dis_ucode_ldr = true;
 
 static int __init disable_loader(char *str)
 {
@@ -81,6 +81,7 @@
 
 static bool __init check_loader_disabled_bsp(void)
 {
+	u32 a, b, c, d;
 #ifdef CONFIG_X86_32
 	const char *cmdline = (const char *)__pa_nodebug(boot_command_line);
 	const char *opt	    = "dis_ucode_ldr";
@@ -93,8 +94,20 @@
 	bool *res = &dis_ucode_ldr;
 #endif
 
-	if (cmdline_find_option_bool(cmdline, option))
-		*res = true;
+	a = 1;
+	c = 0;
+	native_cpuid(&a, &b, &c, &d);
+
+	/*
+	 * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not
+	 * completely accurate as xen pv guests don't see that CPUID bit set but
+	 * that's good enough as they don't land on the BSP path anyway.
+	 */
+	if (c & BIT(31))
+		return *res;
+
+	if (cmdline_find_option_bool(cmdline, option) <= 0)
+		*res = false;
 
 	return *res;
 }
@@ -122,9 +135,7 @@
 {
 	int vendor;
 	unsigned int family;
-
-	if (check_loader_disabled_bsp())
-		return;
+	bool intel = true;
 
 	if (!have_cpuid_p())
 		return;
@@ -134,16 +145,27 @@
 
 	switch (vendor) {
 	case X86_VENDOR_INTEL:
-		if (family >= 6)
-			load_ucode_intel_bsp();
+		if (family < 6)
+			return;
 		break;
+
 	case X86_VENDOR_AMD:
-		if (family >= 0x10)
-			load_ucode_amd_bsp(family);
+		if (family < 0x10)
+			return;
+		intel = false;
 		break;
+
 	default:
-		break;
+		return;
 	}
+
+	if (check_loader_disabled_bsp())
+		return;
+
+	if (intel)
+		load_ucode_intel_bsp();
+	else
+		load_ucode_amd_bsp(family);
 }
 
 static bool check_loader_disabled_ap(void)
@@ -162,9 +184,6 @@
 	if (check_loader_disabled_ap())
 		return;
 
-	if (!have_cpuid_p())
-		return;
-
 	vendor = x86_vendor();
 	family = x86_family();
 
@@ -202,7 +221,7 @@
 	return 0;
 }
 
-void reload_early_microcode(void)
+void reload_early_microcode(unsigned int cpu)
 {
 	int vendor, family;
 
@@ -216,7 +235,7 @@
 		break;
 	case X86_VENDOR_AMD:
 		if (family >= 0x10)
-			reload_ucode_amd();
+			reload_ucode_amd(cpu);
 		break;
 	default:
 		break;
@@ -419,6 +438,7 @@
 	}
 	if (!ret)
 		perf_check_microcode();
+
 	mutex_unlock(&microcode_mutex);
 	put_online_cpus();
 
@@ -559,7 +579,7 @@
 	if (uci->valid && uci->mc)
 		microcode_ops->apply_microcode(cpu);
 	else if (!uci->mc)
-		reload_early_microcode();
+		reload_early_microcode(cpu);
 }
 
 static struct syscore_ops mc_syscore_ops = {
--- linux-4.4.0.orig/arch/x86/kernel/cpu/microcode/intel.c
+++ linux-4.4.0/arch/x86/kernel/cpu/microcode/intel.c
@@ -39,6 +39,9 @@
 #include <asm/setup.h>
 #include <asm/msr.h>
 
+/* last level cache size per core */
+static int llc_size_per_core;
+
 static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT];
 static struct mc_saved_data {
 	unsigned int mc_saved_count;
@@ -129,51 +132,6 @@
 	}
 }
 
-/*
- * Given CPU signature and a microcode patch, this function finds if the
- * microcode patch has matching family and model with the CPU.
- */
-static enum ucode_state
-matching_model_microcode(struct microcode_header_intel *mc_header,
-			unsigned long sig)
-{
-	unsigned int fam, model;
-	unsigned int fam_ucode, model_ucode;
-	struct extended_sigtable *ext_header;
-	unsigned long total_size = get_totalsize(mc_header);
-	unsigned long data_size = get_datasize(mc_header);
-	int ext_sigcount, i;
-	struct extended_signature *ext_sig;
-
-	fam   = __x86_family(sig);
-	model = x86_model(sig);
-
-	fam_ucode   = __x86_family(mc_header->sig);
-	model_ucode = x86_model(mc_header->sig);
-
-	if (fam == fam_ucode && model == model_ucode)
-		return UCODE_OK;
-
-	/* Look for ext. headers: */
-	if (total_size <= data_size + MC_HEADER_SIZE)
-		return UCODE_NFOUND;
-
-	ext_header   = (void *) mc_header + data_size + MC_HEADER_SIZE;
-	ext_sig      = (void *)ext_header + EXT_HEADER_SIZE;
-	ext_sigcount = ext_header->count;
-
-	for (i = 0; i < ext_sigcount; i++) {
-		fam_ucode   = __x86_family(ext_sig->sig);
-		model_ucode = x86_model(ext_sig->sig);
-
-		if (fam == fam_ucode && model == model_ucode)
-			return UCODE_OK;
-
-		ext_sig++;
-	}
-	return UCODE_NFOUND;
-}
-
 static int
 save_microcode(struct mc_saved_data *mc_saved_data,
 	       struct microcode_intel **mc_saved_src,
@@ -318,8 +276,8 @@
 		 * the platform, we need to find and save microcode patches
 		 * with the same family and model as the BSP.
 		 */
-		if (matching_model_microcode(mc_header, uci->cpu_sig.sig) !=
-			 UCODE_OK) {
+		if (!find_matching_signature(mc_header, uci->cpu_sig.sig,
+					     uci->cpu_sig.pf)) {
 			ucode_ptr += mc_size;
 			continue;
 		}
@@ -373,15 +331,8 @@
 		native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
 		csig.pf = 1 << ((val[1] >> 18) & 7);
 	}
-	native_wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-
-	/* As documented in the SDM: Do a CPUID 1 here */
-	sync_core();
 
-	/* get the current revision from MSR 0x8B */
-	native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-
-	csig.rev = val[1];
+	csig.rev = intel_get_microcode_revision();
 
 	uci->cpu_sig = csig;
 	uci->valid = 1;
@@ -555,10 +506,14 @@
 	cd.data = NULL;
 	cd.size = 0;
 
-	cd = find_cpio_data(p, (void *)start, size, &offset);
-	if (!cd.data) {
+	/* try built-in microcode if no initrd */
+	if (!size) {
 		if (!load_builtin_intel_microcode(&cd))
 			return UCODE_ERROR;
+	} else {
+		cd = find_cpio_data(p, (void *)start, size, &offset);
+		if (!cd.data)
+			return UCODE_ERROR;
 	}
 
 	return get_matching_model_microcode(0, start, cd.data, cd.size,
@@ -647,31 +602,37 @@
 static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
 {
 	struct microcode_intel *mc_intel;
-	unsigned int val[2];
+	u32 rev;
 
 	mc_intel = uci->mc;
 	if (mc_intel == NULL)
 		return 0;
 
+	/*
+	 * Save us the MSR write below - which is a particular expensive
+	 * operation - when the other hyperthread has updated the microcode
+	 * already.
+	 */
+	rev = intel_get_microcode_revision();
+	if (rev >= mc_intel->hdr.rev) {
+		uci->cpu_sig.rev = rev;
+		return 0;
+	}
+
 	/* write microcode via MSR 0x79 */
 	native_wrmsr(MSR_IA32_UCODE_WRITE,
 	      (unsigned long) mc_intel->bits,
 	      (unsigned long) mc_intel->bits >> 16 >> 16);
-	native_wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-
-	/* As documented in the SDM: Do a CPUID 1 here */
-	sync_core();
 
-	/* get the current revision from MSR 0x8B */
-	native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-	if (val[1] != mc_intel->hdr.rev)
+	rev = intel_get_microcode_revision();
+	if (rev != mc_intel->hdr.rev)
 		return -1;
 
 #ifdef CONFIG_X86_64
 	/* Flush global tlb. This is precaution. */
 	flush_tlb_early();
 #endif
-	uci->cpu_sig.rev = val[1];
+	uci->cpu_sig.rev = rev;
 
 	if (early)
 		print_ucode(uci);
@@ -694,7 +655,7 @@
 	if (count == 0)
 		return ret;
 
-	copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, initrd_start, count);
+	copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, get_initrd_start(), count);
 	ret = save_microcode(&mc_saved_data, mc_saved, count);
 	if (ret)
 		pr_err("Cannot save microcode patches from initrd.\n");
@@ -732,16 +693,20 @@
 	struct boot_params *p;
 
 	p	= (struct boot_params *)__pa_nodebug(&boot_params);
-	start	= p->hdr.ramdisk_image;
 	size	= p->hdr.ramdisk_size;
 
-	_load_ucode_intel_bsp(
-			(struct mc_saved_data *)__pa_nodebug(&mc_saved_data),
-			(unsigned long *)__pa_nodebug(&mc_saved_in_initrd),
-			start, size);
+	/*
+	 * Set start only if we have an initrd image. We cannot use initrd_start
+	 * because it is not set that early yet.
+	 */
+	start	= (size ? p->hdr.ramdisk_image : 0);
+
+	_load_ucode_intel_bsp((struct mc_saved_data *)__pa_nodebug(&mc_saved_data),
+			      (unsigned long *)__pa_nodebug(&mc_saved_in_initrd),
+			      start, size);
 #else
-	start	= boot_params.hdr.ramdisk_image + PAGE_OFFSET;
 	size	= boot_params.hdr.ramdisk_size;
+	start	= (size ? boot_params.hdr.ramdisk_image + PAGE_OFFSET : 0);
 
 	_load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, start, size);
 #endif
@@ -752,20 +717,14 @@
 	struct mc_saved_data *mc_saved_data_p;
 	struct ucode_cpu_info uci;
 	unsigned long *mc_saved_in_initrd_p;
-	unsigned long initrd_start_addr;
 	enum ucode_state ret;
 #ifdef CONFIG_X86_32
-	unsigned long *initrd_start_p;
 
-	mc_saved_in_initrd_p =
-		(unsigned long *)__pa_nodebug(mc_saved_in_initrd);
+	mc_saved_in_initrd_p = (unsigned long *)__pa_nodebug(mc_saved_in_initrd);
 	mc_saved_data_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data);
-	initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start);
-	initrd_start_addr = (unsigned long)__pa_nodebug(*initrd_start_p);
 #else
-	mc_saved_data_p = &mc_saved_data;
 	mc_saved_in_initrd_p = mc_saved_in_initrd;
-	initrd_start_addr = initrd_start;
+	mc_saved_data_p = &mc_saved_data;
 #endif
 
 	/*
@@ -777,7 +736,7 @@
 
 	collect_cpu_info_early(&uci);
 	ret = load_microcode(mc_saved_data_p, mc_saved_in_initrd_p,
-			     initrd_start_addr, &uci);
+			     get_initrd_start_addr(), &uci);
 
 	if (ret != UCODE_OK)
 		return;
@@ -847,7 +806,7 @@
 {
 	struct microcode_intel *mc_intel;
 	struct ucode_cpu_info *uci;
-	unsigned int val[2];
+	u32 rev;
 	int cpu_num = raw_smp_processor_id();
 	struct cpuinfo_x86 *c = &cpu_data(cpu_num);
 
@@ -868,31 +827,40 @@
 	if (get_matching_mc(mc_intel, cpu) == 0)
 		return 0;
 
+	/*
+	 * Save us the MSR write below - which is a particular expensive
+	 * operation - when the other hyperthread has updated the microcode
+	 * already.
+	 */
+	rev = intel_get_microcode_revision();
+	if (rev >= mc_intel->hdr.rev)
+		goto out;
+
 	/* write microcode via MSR 0x79 */
 	wrmsr(MSR_IA32_UCODE_WRITE,
 	      (unsigned long) mc_intel->bits,
 	      (unsigned long) mc_intel->bits >> 16 >> 16);
-	wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-
-	/* As documented in the SDM: Do a CPUID 1 here */
-	sync_core();
 
-	/* get the current revision from MSR 0x8B */
-	rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+	rev = intel_get_microcode_revision();
 
-	if (val[1] != mc_intel->hdr.rev) {
+	if (rev != mc_intel->hdr.rev) {
 		pr_err("CPU%d update to revision 0x%x failed\n",
 		       cpu_num, mc_intel->hdr.rev);
 		return -1;
 	}
 	pr_info("CPU%d updated to revision 0x%x, date = %04x-%02x-%02x\n",
-		cpu_num, val[1],
+		cpu_num, rev,
 		mc_intel->hdr.date & 0xffff,
 		mc_intel->hdr.date >> 24,
 		(mc_intel->hdr.date >> 16) & 0xff);
 
-	uci->cpu_sig.rev = val[1];
-	c->microcode = val[1];
+out:
+	uci->cpu_sig.rev = rev;
+	c->microcode	 = rev;
+
+	/* Update boot_cpu_data's revision too, if we're on the BSP: */
+	if (c->cpu_index == boot_cpu_data.cpu_index)
+		boot_cpu_data.microcode = rev;
 
 	return 0;
 }
@@ -988,6 +956,29 @@
 	return 0;
 }
 
+static bool is_blacklisted(unsigned int cpu)
+{
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+	/*
+	 * Late loading on model 79 with microcode revision less than 0x0b000021
+	 * and LLC size per core bigger than 2.5MB may result in a system hang.
+	 * This behavior is documented in item BDF90, #334165 (Intel Xeon
+	 * Processor E7-8800/4800 v4 Product Family).
+	 */
+	if (c->x86 == 6 &&
+	    c->x86_model == 79 &&
+	    c->x86_stepping == 0x01 &&
+	    llc_size_per_core > 2621440 &&
+	    c->microcode < 0x0b000021) {
+		pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode);
+		pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n");
+		return true;
+	}
+
+	return false;
+}
+
 static enum ucode_state request_microcode_fw(int cpu, struct device *device,
 					     bool refresh_fw)
 {
@@ -996,8 +987,11 @@
 	const struct firmware *firmware;
 	enum ucode_state ret;
 
+	if (is_blacklisted(cpu))
+		return UCODE_NFOUND;
+
 	sprintf(name, "intel-ucode/%02x-%02x-%02x",
-		c->x86, c->x86_model, c->x86_mask);
+		c->x86, c->x86_model, c->x86_stepping);
 
 	if (request_firmware_direct(&firmware, name, device)) {
 		pr_debug("data file %s load failed\n", name);
@@ -1020,6 +1014,9 @@
 static enum ucode_state
 request_microcode_user(int cpu, const void __user *buf, size_t size)
 {
+	if (is_blacklisted(cpu))
+		return UCODE_NFOUND;
+
 	return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user);
 }
 
@@ -1039,6 +1036,15 @@
 	.microcode_fini_cpu               = microcode_fini_cpu,
 };
 
+static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c)
+{
+	u64 llc_size = c->x86_cache_size * 1024ULL;
+
+	do_div(llc_size, c->x86_max_cores);
+
+	return (int)llc_size;
+}
+
 struct microcode_ops * __init init_intel_microcode(void)
 {
 	struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -1049,6 +1055,8 @@
 		return NULL;
 	}
 
+	llc_size_per_core = calc_llc_size_per_core(c);
+
 	return &microcode_intel_ops;
 }
 
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mkcapflags.sh
+++ linux-4.4.0/arch/x86/kernel/cpu/mkcapflags.sh
@@ -1,8 +1,10 @@
 #!/bin/sh
 #
-# Generate the x86_cap/bug_flags[] arrays from include/asm/cpufeature.h
+# Generate the x86_cap/bug_flags[] arrays from include/asm/cpufeatures.h
 #
 
+set -e
+
 IN=$1
 OUT=$2
 
@@ -49,8 +51,8 @@
 trap 'rm "$OUT"' EXIT
 
 (
-	echo "#ifndef _ASM_X86_CPUFEATURE_H"
-	echo "#include <asm/cpufeature.h>"
+	echo "#ifndef _ASM_X86_CPUFEATURES_H"
+	echo "#include <asm/cpufeatures.h>"
 	echo "#endif"
 	echo ""
 
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mshyperv.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mshyperv.c
@@ -13,7 +13,8 @@
 #include <linux/types.h>
 #include <linux/time.h>
 #include <linux/clocksource.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/hardirq.h>
 #include <linux/efi.h>
 #include <linux/interrupt.h>
@@ -30,6 +31,7 @@
 #include <asm/apic.h>
 #include <asm/timer.h>
 #include <asm/reboot.h>
+#include <asm/nmi.h>
 
 struct ms_hyperv_info ms_hyperv;
 EXPORT_SYMBOL_GPL(ms_hyperv);
@@ -132,25 +134,30 @@
 	return 0;
 }
 
-static cycle_t read_hv_clock(struct clocksource *arg)
+static unsigned char hv_get_nmi_reason(void)
 {
-	cycle_t current_tick;
-	/*
-	 * Read the partition counter to get the current tick count. This count
-	 * is set to 0 when the partition is created and is incremented in
-	 * 100 nanosecond units.
-	 */
-	rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
-	return current_tick;
+	return 0;
 }
 
-static struct clocksource hyperv_cs = {
-	.name		= "hyperv_clocksource",
-	.rating		= 400, /* use this when running on Hyperv*/
-	.read		= read_hv_clock,
-	.mask		= CLOCKSOURCE_MASK(64),
-	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
-};
+#ifdef CONFIG_X86_LOCAL_APIC
+/*
+ * Prior to WS2016 Debug-VM sends NMIs to all CPUs which makes
+ * it dificult to process CHANNELMSG_UNLOAD in case of crash. Handle
+ * unknown NMI on the first CPU which gets it.
+ */
+static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs)
+{
+	static atomic_t nmi_cpu = ATOMIC_INIT(-1);
+
+	if (!unknown_nmi_panic)
+		return NMI_DONE;
+
+	if (atomic_cmpxchg(&nmi_cpu, -1, raw_smp_processor_id()) != -1)
+		return NMI_HANDLED;
+
+	return NMI_DONE;
+}
+#endif
 
 static void __init ms_hyperv_init_platform(void)
 {
@@ -177,10 +184,10 @@
 		printk(KERN_INFO "HyperV: LAPIC Timer Frequency: %#x\n",
 				lapic_timer_frequency);
 	}
-#endif
 
-	if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
-		clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
+	register_nmi_handler(NMI_UNKNOWN, hv_nmi_unknown, NMI_FLAG_FIRST,
+			     "hv_nmi_unknown");
+#endif
 
 #ifdef CONFIG_X86_IO_APIC
 	no_timer_check = 1;
@@ -191,6 +198,13 @@
 	machine_ops.crash_shutdown = hv_machine_crash_shutdown;
 #endif
 	mark_tsc_unstable("running on Hyper-V");
+
+	/*
+	 * Generation 2 instances don't support reading the NMI status from
+	 * 0x61 port.
+	 */
+	if (efi_enabled(EFI_BOOT))
+		x86_platform.get_nmi_reason = hv_get_nmi_reason;
 }
 
 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mtrr/cleanup.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mtrr/cleanup.c
@@ -17,7 +17,6 @@
  * License along with this library; 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/pci.h>
 #include <linux/smp.h>
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mtrr/generic.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mtrr/generic.c
@@ -4,7 +4,7 @@
  */
 #define DEBUG
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/mm.h>
@@ -166,9 +166,6 @@
 	*repeat = 0;
 	*uniform = 1;
 
-	/* Make end inclusive instead of exclusive */
-	end--;
-
 	prev_match = MTRR_TYPE_INVALID;
 	for (i = 0; i < num_var_ranges; ++i) {
 		unsigned short start_state, end_state, inclusive;
@@ -260,6 +257,9 @@
 	int repeat;
 	u64 partial_end;
 
+	/* Make end inclusive instead of exclusive */
+	end--;
+
 	if (!mtrr_state_set)
 		return MTRR_TYPE_INVALID;
 
@@ -349,7 +349,7 @@
 
 void mtrr_save_fixed_ranges(void *info)
 {
-	if (cpu_has_mtrr)
+	if (boot_cpu_has(X86_FEATURE_MTRR))
 		get_fixed_ranges(mtrr_state.fixed_ranges);
 }
 
@@ -444,11 +444,24 @@
 		pr_debug("TOM2: %016llx aka %lldM\n", mtrr_tom2, mtrr_tom2>>20);
 }
 
+/* PAT setup for BP. We need to go through sync steps here */
+void __init mtrr_bp_pat_init(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	prepare_set();
+
+	pat_init();
+
+	post_set();
+	local_irq_restore(flags);
+}
+
 /* Grab all of the MTRR state for this CPU into *state */
 bool __init get_mtrr_state(void)
 {
 	struct mtrr_var_range *vrs;
-	unsigned long flags;
 	unsigned lo, dummy;
 	unsigned int i;
 
@@ -481,15 +494,6 @@
 
 	mtrr_state_set = 1;
 
-	/* PAT setup for BP. We need to go through sync steps here */
-	local_irq_save(flags);
-	prepare_set();
-
-	pat_init();
-
-	post_set();
-	local_irq_restore(flags);
-
 	return !!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED);
 }
 
@@ -856,7 +860,7 @@
 	 */
 	if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 &&
 	    boot_cpu_data.x86_model == 1 &&
-	    boot_cpu_data.x86_mask <= 7) {
+	    boot_cpu_data.x86_stepping <= 7) {
 		if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) {
 			pr_warning("mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
 			return -EINVAL;
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mtrr/if.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mtrr/if.c
@@ -173,6 +173,8 @@
 	struct mtrr_gentry gentry;
 	void __user *arg = (void __user *) __arg;
 
+	memset(&gentry, 0, sizeof(gentry));
+
 	switch (cmd) {
 	case MTRRIOC_ADD_ENTRY:
 	case MTRRIOC_SET_ENTRY:
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mtrr/main.c
+++ linux-4.4.0/arch/x86/kernel/cpu/mtrr/main.c
@@ -47,7 +47,7 @@
 #include <linux/smp.h>
 #include <linux/syscore_ops.h>
 
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <asm/e820.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
@@ -682,7 +682,7 @@
 
 	phys_addr = 32;
 
-	if (cpu_has_mtrr) {
+	if (boot_cpu_has(X86_FEATURE_MTRR)) {
 		mtrr_if = &generic_mtrr_ops;
 		size_or_mask = SIZE_OR_MASK_BITS(36);
 		size_and_mask = 0x00f00000;
@@ -699,8 +699,8 @@
 			if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
 			    boot_cpu_data.x86 == 0xF &&
 			    boot_cpu_data.x86_model == 0x3 &&
-			    (boot_cpu_data.x86_mask == 0x3 ||
-			     boot_cpu_data.x86_mask == 0x4))
+			    (boot_cpu_data.x86_stepping == 0x3 ||
+			     boot_cpu_data.x86_stepping == 0x4))
 				phys_addr = 36;
 
 			size_or_mask = SIZE_OR_MASK_BITS(phys_addr);
@@ -752,6 +752,9 @@
 			/* BIOS may override */
 			__mtrr_enabled = get_mtrr_state();
 
+			if (mtrr_enabled())
+				mtrr_bp_pat_init();
+
 			if (mtrr_cleanup(phys_addr)) {
 				changed_by_mtrr_cleanup = 1;
 				mtrr_if->set_all();
@@ -759,8 +762,16 @@
 		}
 	}
 
-	if (!mtrr_enabled())
+	if (!mtrr_enabled()) {
 		pr_info("MTRR: Disabled\n");
+
+		/*
+		 * PAT initialization relies on MTRR's rendezvous handler.
+		 * Skip PAT init until the handler can initialize both
+		 * features independently.
+		 */
+		pat_disable("MTRRs disabled, skipping PAT initialization too.");
+	}
 }
 
 void mtrr_ap_init(void)
--- linux-4.4.0.orig/arch/x86/kernel/cpu/mtrr/mtrr.h
+++ linux-4.4.0/arch/x86/kernel/cpu/mtrr/mtrr.h
@@ -52,6 +52,7 @@
 void fill_mtrr_var_range(unsigned int index,
 		u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
 bool get_mtrr_state(void);
+void mtrr_bp_pat_init(void);
 
 extern void set_mtrr_ops(const struct mtrr_ops *ops);
 
--- linux-4.4.0.orig/arch/x86/kernel/cpu/perfctr-watchdog.c
+++ linux-4.4.0/arch/x86/kernel/cpu/perfctr-watchdog.c
@@ -12,7 +12,7 @@
  */
 
 #include <linux/percpu.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/smp.h>
--- linux-4.4.0.orig/arch/x86/kernel/cpu/proc.c
+++ linux-4.4.0/arch/x86/kernel/cpu/proc.c
@@ -70,8 +70,8 @@
 		   c->x86_model,
 		   c->x86_model_id[0] ? c->x86_model_id : "unknown");
 
-	if (c->x86_mask || c->cpuid_level >= 0)
-		seq_printf(m, "stepping\t: %d\n", c->x86_mask);
+	if (c->x86_stepping || c->cpuid_level >= 0)
+		seq_printf(m, "stepping\t: %d\n", c->x86_stepping);
 	else
 		seq_puts(m, "stepping\t: unknown\n");
 	if (c->microcode)
@@ -87,8 +87,8 @@
 	}
 
 	/* Cache size */
-	if (c->x86_cache_size >= 0)
-		seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
+	if (c->x86_cache_size)
+		seq_printf(m, "cache size\t: %u KB\n", c->x86_cache_size);
 
 	show_cpuinfo_core(m, c, cpu);
 	show_cpuinfo_misc(m, c);
--- linux-4.4.0.orig/arch/x86/kernel/cpu/scattered.c
+++ linux-4.4.0/arch/x86/kernel/cpu/scattered.c
@@ -24,42 +24,29 @@
 	CR_EBX
 };
 
+/* Please keep the leaf sorted by cpuid_bit.level for faster search. */
+static const struct cpuid_bit cpuid_bits[] = {
+	{ X86_FEATURE_INTEL_PT,		CR_EBX,25, 0x00000007, 0 },
+	{ X86_FEATURE_APERFMPERF,	CR_ECX, 0, 0x00000006, 0 },
+	{ X86_FEATURE_EPB,		CR_ECX, 3, 0x00000006, 0 },
+	{ X86_FEATURE_RRSBA_CTRL,	CR_EDX, 2, 0x00000007, 2 },
+	{ X86_FEATURE_BHI_CTRL,		CR_EDX, 4, 0x00000007, 2 },
+	{ X86_FEATURE_CQM_LLC,		CR_EDX, 1, 0x0000000f, 0 },
+	{ X86_FEATURE_CQM_OCCUP_LLC,	CR_EDX, 0, 0x0000000f, 1 },
+	{ X86_FEATURE_CQM_MBM_TOTAL,	CR_EDX, 1, 0x0000000f, 1 },
+	{ X86_FEATURE_CQM_MBM_LOCAL,	CR_EDX, 2, 0x0000000f, 1 },
+	{ X86_FEATURE_HW_PSTATE,	CR_EDX, 7, 0x80000007, 0 },
+	{ X86_FEATURE_CPB,		CR_EDX, 9, 0x80000007, 0 },
+	{ X86_FEATURE_PROC_FEEDBACK,	CR_EDX,11, 0x80000007, 0 },
+	{ 0, 0, 0, 0, 0 }
+};
+
 void init_scattered_cpuid_features(struct cpuinfo_x86 *c)
 {
 	u32 max_level;
 	u32 regs[4];
 	const struct cpuid_bit *cb;
 
-	static const struct cpuid_bit cpuid_bits[] = {
-		{ 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 },
-		{ X86_FEATURE_PTS,		CR_EAX, 6, 0x00000006, 0 },
-		{ X86_FEATURE_HWP,		CR_EAX, 7, 0x00000006, 0 },
-		{ X86_FEATURE_HWP_NOTIFY,	CR_EAX, 8, 0x00000006, 0 },
-		{ X86_FEATURE_HWP_ACT_WINDOW,	CR_EAX, 9, 0x00000006, 0 },
-		{ X86_FEATURE_HWP_EPP,		CR_EAX,10, 0x00000006, 0 },
-		{ X86_FEATURE_HWP_PKG_REQ,	CR_EAX,11, 0x00000006, 0 },
-		{ X86_FEATURE_INTEL_PT,		CR_EBX,25, 0x00000007, 0 },
-		{ X86_FEATURE_APERFMPERF,	CR_ECX, 0, 0x00000006, 0 },
-		{ X86_FEATURE_EPB,		CR_ECX, 3, 0x00000006, 0 },
-		{ X86_FEATURE_HW_PSTATE,	CR_EDX, 7, 0x80000007, 0 },
-		{ X86_FEATURE_CPB,		CR_EDX, 9, 0x80000007, 0 },
-		{ X86_FEATURE_PROC_FEEDBACK,	CR_EDX,11, 0x80000007, 0 },
-		{ X86_FEATURE_NPT,		CR_EDX, 0, 0x8000000a, 0 },
-		{ X86_FEATURE_LBRV,		CR_EDX, 1, 0x8000000a, 0 },
-		{ X86_FEATURE_SVML,		CR_EDX, 2, 0x8000000a, 0 },
-		{ X86_FEATURE_NRIPS,		CR_EDX, 3, 0x8000000a, 0 },
-		{ X86_FEATURE_TSCRATEMSR,	CR_EDX, 4, 0x8000000a, 0 },
-		{ X86_FEATURE_VMCBCLEAN,	CR_EDX, 5, 0x8000000a, 0 },
-		{ X86_FEATURE_FLUSHBYASID,	CR_EDX, 6, 0x8000000a, 0 },
-		{ X86_FEATURE_DECODEASSISTS,	CR_EDX, 7, 0x8000000a, 0 },
-		{ X86_FEATURE_PAUSEFILTER,	CR_EDX,10, 0x8000000a, 0 },
-		{ X86_FEATURE_PFTHRESHOLD,	CR_EDX,12, 0x8000000a, 0 },
-		{ 0, 0, 0, 0, 0 }
-	};
-
 	for (cb = cpuid_bits; cb->feature; cb++) {
 
 		/* Verify that the level is valid */
@@ -75,3 +62,26 @@
 			set_cpu_cap(c, cb->feature);
 	}
 }
+
+u32 get_scattered_cpuid_leaf(unsigned int level, unsigned int sub_leaf, u8 reg)
+{
+	const struct cpuid_bit *cb;
+	u32 cpuid_val = 0;
+
+	for (cb = cpuid_bits; cb->feature; cb++) {
+
+		if (level > cb->level)
+			continue;
+
+		if (level < cb->level)
+			break;
+
+		if (reg == cb->reg && sub_leaf == cb->sub_leaf) {
+			if (cpu_has(&boot_cpu_data, cb->feature))
+				cpuid_val |= BIT(cb->bit);
+		}
+	}
+
+	return cpuid_val;
+}
+EXPORT_SYMBOL_GPL(get_scattered_cpuid_leaf);
--- linux-4.4.0.orig/arch/x86/kernel/cpu/topology.c
+++ linux-4.4.0/arch/x86/kernel/cpu/topology.c
@@ -21,21 +21,13 @@
 #define BITS_SHIFT_NEXT_LEVEL(eax)	((eax) & 0x1f)
 #define LEVEL_MAX_SIBLINGS(ebx)		((ebx) & 0xffff)
 
-/*
- * Check for extended topology enumeration cpuid leaf 0xb and if it
- * exists, use it for populating initial_apicid and cpu topology
- * detection.
- */
-void detect_extended_topology(struct cpuinfo_x86 *c)
+int detect_extended_topology_early(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
-	unsigned int eax, ebx, ecx, edx, sub_index;
-	unsigned int ht_mask_width, core_plus_mask_width;
-	unsigned int core_select_mask, core_level_siblings;
-	static bool printed;
+	unsigned int eax, ebx, ecx, edx;
 
 	if (c->cpuid_level < 0xb)
-		return;
+		return -1;
 
 	cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
 
@@ -43,7 +35,7 @@
 	 * check if the cpuid leaf 0xb is actually implemented.
 	 */
 	if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
-		return;
+		return -1;
 
 	set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
 
@@ -51,10 +43,30 @@
 	 * initial apic id, which also represents 32-bit extended x2apic id.
 	 */
 	c->initial_apicid = edx;
+	smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
+#endif
+	return 0;
+}
+
+/*
+ * Check for extended topology enumeration cpuid leaf 0xb and if it
+ * exists, use it for populating initial_apicid and cpu topology
+ * detection.
+ */
+int detect_extended_topology(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+	unsigned int eax, ebx, ecx, edx, sub_index;
+	unsigned int ht_mask_width, core_plus_mask_width;
+	unsigned int core_select_mask, core_level_siblings;
+
+	if (detect_extended_topology_early(c) < 0)
+		return -1;
 
 	/*
 	 * Populate HT related information from sub-leaf level 0.
 	 */
+	cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
 	core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
 	core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 
@@ -85,15 +97,6 @@
 	c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
 
 	c->x86_max_cores = (core_level_siblings / smp_num_siblings);
-
-	if (!printed) {
-		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-		       c->phys_proc_id);
-		if (c->x86_max_cores > 1)
-			printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-			       c->cpu_core_id);
-		printed = 1;
-	}
-	return;
 #endif
+	return 0;
 }
--- linux-4.4.0.orig/arch/x86/kernel/cpu/transmeta.c
+++ linux-4.4.0/arch/x86/kernel/cpu/transmeta.c
@@ -1,6 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <asm/msr.h>
 #include "cpu.h"
 
@@ -12,7 +12,7 @@
 	xlvl = cpuid_eax(0x80860000);
 	if ((xlvl & 0xffff0000) == 0x80860000) {
 		if (xlvl >= 0x80860001)
-			c->x86_capability[2] = cpuid_edx(0x80860001);
+			c->x86_capability[CPUID_8086_0001_EDX] = cpuid_edx(0x80860001);
 	}
 }
 
@@ -82,7 +82,7 @@
 	/* Unhide possibly hidden capability flags */
 	rdmsr(0x80860004, cap_mask, uk);
 	wrmsr(0x80860004, ~0, uk);
-	c->x86_capability[0] = cpuid_edx(0x00000001);
+	c->x86_capability[CPUID_1_EDX] = cpuid_edx(0x00000001);
 	wrmsr(0x80860004, cap_mask, uk);
 
 	/* All Transmeta CPUs have a constant TSC */
--- linux-4.4.0.orig/arch/x86/kernel/cpu/tsx.c
+++ linux-4.4.0/arch/x86/kernel/cpu/tsx.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Transactional Synchronization Extensions (TSX) control.
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * Author:
+ *	Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+ */
+
+#include <linux/cpufeature.h>
+
+#include <asm/cmdline.h>
+
+#include "cpu.h"
+
+enum tsx_ctrl_states tsx_ctrl_state __ro_after_init = TSX_CTRL_NOT_SUPPORTED;
+
+void tsx_disable(void)
+{
+	u64 tsx;
+
+	rdmsrl(MSR_IA32_TSX_CTRL, tsx);
+
+	/* Force all transactions to immediately abort */
+	tsx |= TSX_CTRL_RTM_DISABLE;
+
+	/*
+	 * Ensure TSX support is not enumerated in CPUID.
+	 * This is visible to userspace and will ensure they
+	 * do not waste resources trying TSX transactions that
+	 * will always abort.
+	 */
+	tsx |= TSX_CTRL_CPUID_CLEAR;
+
+	wrmsrl(MSR_IA32_TSX_CTRL, tsx);
+}
+
+void tsx_enable(void)
+{
+	u64 tsx;
+
+	rdmsrl(MSR_IA32_TSX_CTRL, tsx);
+
+	/* Enable the RTM feature in the cpu */
+	tsx &= ~TSX_CTRL_RTM_DISABLE;
+
+	/*
+	 * Ensure TSX support is enumerated in CPUID.
+	 * This is visible to userspace and will ensure they
+	 * can enumerate and use the TSX feature.
+	 */
+	tsx &= ~TSX_CTRL_CPUID_CLEAR;
+
+	wrmsrl(MSR_IA32_TSX_CTRL, tsx);
+}
+
+static bool __init tsx_ctrl_is_supported(void)
+{
+	u64 ia32_cap = x86_read_arch_cap_msr();
+
+	/*
+	 * TSX is controlled via MSR_IA32_TSX_CTRL.  However, support for this
+	 * MSR is enumerated by ARCH_CAP_TSX_MSR bit in MSR_IA32_ARCH_CAPABILITIES.
+	 *
+	 * TSX control (aka MSR_IA32_TSX_CTRL) is only available after a
+	 * microcode update on CPUs that have their MSR_IA32_ARCH_CAPABILITIES
+	 * bit MDS_NO=1. CPUs with MDS_NO=0 are not planned to get
+	 * MSR_IA32_TSX_CTRL support even after a microcode update. Thus,
+	 * tsx= cmdline requests will do nothing on CPUs without
+	 * MSR_IA32_TSX_CTRL support.
+	 */
+	return !!(ia32_cap & ARCH_CAP_TSX_CTRL_MSR);
+}
+
+static enum tsx_ctrl_states x86_get_tsx_auto_mode(void)
+{
+	if (boot_cpu_has_bug(X86_BUG_TAA))
+		return TSX_CTRL_DISABLE;
+
+	return TSX_CTRL_ENABLE;
+}
+
+void __init tsx_init(void)
+{
+	char arg[5] = {};
+	int ret;
+
+	if (!tsx_ctrl_is_supported())
+		return;
+
+	ret = cmdline_find_option(boot_command_line, "tsx", arg, sizeof(arg));
+	if (ret >= 0) {
+		if (!strcmp(arg, "on")) {
+			tsx_ctrl_state = TSX_CTRL_ENABLE;
+		} else if (!strcmp(arg, "off")) {
+			tsx_ctrl_state = TSX_CTRL_DISABLE;
+		} else if (!strcmp(arg, "auto")) {
+			tsx_ctrl_state = x86_get_tsx_auto_mode();
+		} else {
+			tsx_ctrl_state = TSX_CTRL_DISABLE;
+			pr_err("tsx: invalid option, defaulting to off\n");
+		}
+	} else {
+		/* tsx= not provided */
+		if (IS_ENABLED(CONFIG_X86_INTEL_TSX_MODE_AUTO))
+			tsx_ctrl_state = x86_get_tsx_auto_mode();
+		else if (IS_ENABLED(CONFIG_X86_INTEL_TSX_MODE_OFF))
+			tsx_ctrl_state = TSX_CTRL_DISABLE;
+		else
+			tsx_ctrl_state = TSX_CTRL_ENABLE;
+	}
+
+	if (tsx_ctrl_state == TSX_CTRL_DISABLE) {
+		tsx_disable();
+
+		/*
+		 * tsx_disable() will change the state of the RTM and HLE CPUID
+		 * bits. Clear them here since they are now expected to be not
+		 * set.
+		 */
+		setup_clear_cpu_cap(X86_FEATURE_RTM);
+		setup_clear_cpu_cap(X86_FEATURE_HLE);
+	} else if (tsx_ctrl_state == TSX_CTRL_ENABLE) {
+
+		/*
+		 * HW defaults TSX to be enabled at bootup.
+		 * We may still need the TSX enable support
+		 * during init for special cases like
+		 * kexec after TSX is disabled.
+		 */
+		tsx_enable();
+
+		/*
+		 * tsx_enable() will change the state of the RTM and HLE CPUID
+		 * bits. Force them here since they are now expected to be set.
+		 */
+		setup_force_cpu_cap(X86_FEATURE_RTM);
+		setup_force_cpu_cap(X86_FEATURE_HLE);
+	}
+}
--- linux-4.4.0.orig/arch/x86/kernel/cpu/vmware.c
+++ linux-4.4.0/arch/x86/kernel/cpu/vmware.c
@@ -22,7 +22,8 @@
  */
 
 #include <linux/dmi.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <asm/div64.h>
 #include <asm/x86_init.h>
 #include <asm/hypervisor.h>
--- linux-4.4.0.orig/arch/x86/kernel/crash.c
+++ linux-4.4.0/arch/x86/kernel/crash.c
@@ -20,7 +20,7 @@
 #include <linux/delay.h>
 #include <linux/elf.h>
 #include <linux/elfcore.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 
--- linux-4.4.0.orig/arch/x86/kernel/devicetree.c
+++ linux-4.4.0/arch/x86/kernel/devicetree.c
@@ -11,6 +11,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/of_irq.h>
+#include <linux/libfdt.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/of_pci.h>
@@ -199,19 +200,22 @@
 static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
 			      unsigned int nr_irqs, void *arg)
 {
-	struct of_phandle_args *irq_data = (void *)arg;
+	struct irq_fwspec *fwspec = (struct irq_fwspec *)arg;
 	struct of_ioapic_type *it;
 	struct irq_alloc_info tmp;
+	int type_index;
 
-	if (WARN_ON(irq_data->args_count < 2))
+	if (WARN_ON(fwspec->param_count < 2))
 		return -EINVAL;
-	if (irq_data->args[1] >= ARRAY_SIZE(of_ioapic_type))
+
+	type_index = fwspec->param[1];
+	if (type_index >= ARRAY_SIZE(of_ioapic_type))
 		return -EINVAL;
 
-	it = &of_ioapic_type[irq_data->args[1]];
+	it = &of_ioapic_type[type_index];
 	ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity);
 	tmp.ioapic_id = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
-	tmp.ioapic_pin = irq_data->args[0];
+	tmp.ioapic_pin = fwspec->param[0];
 
 	return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp);
 }
@@ -276,14 +280,15 @@
 
 	map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128);
 
-	initial_boot_params = dt = early_memremap(initial_dtb, map_len);
-	size = of_get_flat_dt_size();
+	dt = early_memremap(initial_dtb, map_len);
+	size = fdt_totalsize(dt);
 	if (map_len < size) {
 		early_memunmap(dt, map_len);
-		initial_boot_params = dt = early_memremap(initial_dtb, size);
+		dt = early_memremap(initial_dtb, size);
 		map_len = size;
 	}
 
+	early_init_dt_verify(dt);
 	unflatten_and_copy_device_tree();
 	early_memunmap(dt, map_len);
 }
--- linux-4.4.0.orig/arch/x86/kernel/dumpstack_32.c
+++ linux-4.4.0/arch/x86/kernel/dumpstack_32.c
@@ -7,7 +7,7 @@
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
 #include <linux/kdebug.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/ptrace.h>
 #include <linux/kexec.h>
 #include <linux/sysfs.h>
--- linux-4.4.0.orig/arch/x86/kernel/dumpstack_64.c
+++ linux-4.4.0/arch/x86/kernel/dumpstack_64.c
@@ -7,7 +7,7 @@
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
 #include <linux/kdebug.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/ptrace.h>
 #include <linux/kexec.h>
 #include <linux/sysfs.h>
--- linux-4.4.0.orig/arch/x86/kernel/e820.c
+++ linux-4.4.0/arch/x86/kernel/e820.c
@@ -24,6 +24,7 @@
 #include <asm/e820.h>
 #include <asm/proto.h>
 #include <asm/setup.h>
+#include <asm/cpufeature.h>
 
 /*
  * The e820 map is the map that gets modified e.g. with command line parameters
@@ -753,7 +754,7 @@
 /*
  * Find the highest page frame number we have available
  */
-static unsigned long __init e820_end_pfn(unsigned long limit_pfn)
+static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
 {
 	int i;
 	unsigned long last_pfn = 0;
@@ -764,11 +765,7 @@
 		unsigned long start_pfn;
 		unsigned long end_pfn;
 
-		/*
-		 * Persistent memory is accounted as ram for purposes of
-		 * establishing max_pfn and mem_map.
-		 */
-		if (ei->type != E820_RAM && ei->type != E820_PRAM)
+		if (ei->type != type)
 			continue;
 
 		start_pfn = ei->addr >> PAGE_SHIFT;
@@ -793,12 +790,12 @@
 }
 unsigned long __init e820_end_of_ram_pfn(void)
 {
-	return e820_end_pfn(MAX_ARCH_PFN);
+	return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
 }
 
 unsigned long __init e820_end_of_low_ram_pfn(void)
 {
-	return e820_end_pfn(1UL << (32-PAGE_SHIFT));
+	return e820_end_pfn(1UL << (32 - PAGE_SHIFT), E820_RAM);
 }
 
 static void early_panic(char *msg)
--- linux-4.4.0.orig/arch/x86/kernel/early-quirks.c
+++ linux-4.4.0/arch/x86/kernel/early-quirks.c
@@ -11,7 +11,11 @@
 
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
 #include <linux/pci_ids.h>
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_regs.h>
 #include <drm/i915_drm.h>
 #include <asm/pci-direct.h>
 #include <asm/dma.h>
@@ -21,6 +25,40 @@
 #include <asm/iommu.h>
 #include <asm/gart.h>
 #include <asm/irq_remapping.h>
+#include <asm/early_ioremap.h>
+
+static void __init early_pci_clear_msi(int bus, int slot, int func)
+{
+	int pos;
+	u16 ctrl;
+
+	if (likely(!pci_early_clear_msi))
+		return;
+
+	pr_info_once("Clearing MSI/MSI-X enable bits early in boot (quirk)\n");
+
+	pos = pci_early_find_cap(bus, slot, func, PCI_CAP_ID_MSI);
+	if (pos) {
+		ctrl = read_pci_config_16(bus, slot, func, pos + PCI_MSI_FLAGS);
+		ctrl &= ~PCI_MSI_FLAGS_ENABLE;
+		write_pci_config_16(bus, slot, func, pos + PCI_MSI_FLAGS, ctrl);
+
+		/* Read again to flush previous write */
+		ctrl = read_pci_config_16(bus, slot, func, pos + PCI_MSI_FLAGS);
+	}
+
+	pos = pci_early_find_cap(bus, slot, func, PCI_CAP_ID_MSIX);
+	if (pos) {
+		ctrl = read_pci_config_16(bus, slot, func, pos + PCI_MSIX_FLAGS);
+		ctrl &= ~PCI_MSIX_FLAGS_ENABLE;
+		write_pci_config_16(bus, slot, func, pos + PCI_MSIX_FLAGS, ctrl);
+
+		/* Read again to flush previous write */
+		ctrl = read_pci_config_16(bus, slot, func, pos + PCI_MSIX_FLAGS);
+	}
+}
+
+#define dev_err(msg)  pr_err("pci 0000:%02x:%02x.%d: %s", bus, slot, func, msg)
 
 static void __init fix_hypertransport_config(int num, int slot, int func)
 {
@@ -76,6 +114,13 @@
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_X86_IO_APIC
 	/*
+	 * Only applies to Nvidia root ports (bus 0) and not to
+	 * Nvidia graphics cards with PCI ports on secondary buses.
+	 */
+	if (num)
+		return;
+
+	/*
 	 * All timer overrides on Nvidia are
 	 * wrong unless HPET is enabled.
 	 * Unfortunately that's not true on many Asus boards.
@@ -317,12 +362,11 @@
 
 static u32 __init i865_stolen_base(int num, int slot, int func, size_t stolen_size)
 {
-	/*
-	 * FIXME is the graphics stolen memory region
-	 * always at TOUD? Ie. is it always the last
-	 * one to be allocated by the BIOS?
-	 */
-	return read_pci_config_16(0, 0, 0, I865_TOUD) << 16;
+	u16 toud = 0;
+
+	toud = read_pci_config_16(0, 0, 0, I865_TOUD);
+
+	return (phys_addr_t)(toud << 16) + i845_tseg_size();
 }
 
 static size_t __init i830_stolen_size(int num, int slot, int func)
@@ -589,6 +633,61 @@
 #endif
 }
 
+#define BCM4331_MMIO_SIZE	16384
+#define BCM4331_PM_CAP		0x40
+#define bcma_aread32(reg)	ioread32(mmio + 1 * BCMA_CORE_SIZE + reg)
+#define bcma_awrite32(reg, val)	iowrite32(val, mmio + 1 * BCMA_CORE_SIZE + reg)
+
+static void __init apple_airport_reset(int bus, int slot, int func)
+{
+	void __iomem *mmio;
+	u16 pmcsr;
+	u64 addr;
+	int i;
+
+	if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc."))
+		return;
+
+	/* Card may have been put into PCI_D3hot by grub quirk */
+	pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL);
+
+	if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) {
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		write_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL, pmcsr);
+		mdelay(10);
+
+		pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL);
+		if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) {
+			dev_err("Cannot power up Apple AirPort card\n");
+			return;
+		}
+	}
+
+	addr  =      read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+	addr |= (u64)read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_1) << 32;
+	addr &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	mmio = early_ioremap(addr, BCM4331_MMIO_SIZE);
+	if (!mmio) {
+		dev_err("Cannot iomap Apple AirPort card\n");
+		return;
+	}
+
+	pr_info("Resetting Apple AirPort card (left enabled by EFI)\n");
+
+	for (i = 0; bcma_aread32(BCMA_RESET_ST) && i < 30; i++)
+		udelay(10);
+
+	bcma_awrite32(BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
+	bcma_aread32(BCMA_RESET_CTL);
+	udelay(1);
+
+	bcma_awrite32(BCMA_RESET_CTL, 0);
+	bcma_aread32(BCMA_RESET_CTL);
+	udelay(10);
+
+	early_iounmap(mmio, BCM4331_MMIO_SIZE);
+}
 
 #define QFLAG_APPLY_ONCE 	0x1
 #define QFLAG_APPLIED		0x2
@@ -602,12 +701,6 @@
 	void (*f)(int num, int slot, int func);
 };
 
-/*
- * Only works for devices on the root bus. If you add any devices
- * not on bus 0 readd another loop level in early_quirks(). But
- * be careful because at least the Nvidia quirk here relies on
- * only matching on bus 0.
- */
 static struct chipset early_qrk[] __initdata = {
 	{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
 	  PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs },
@@ -637,9 +730,14 @@
 	 */
 	{ PCI_VENDOR_ID_INTEL, 0x0f00,
 		PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
+	{ PCI_VENDOR_ID_BROADCOM, 0x4331,
+	  PCI_CLASS_NETWORK_OTHER, PCI_ANY_ID, 0, apple_airport_reset},
+	{ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, early_pci_clear_msi},
 	{}
 };
 
+static void __init early_pci_scan_bus(int bus);
+
 /**
  * check_dev_quirk - apply early quirks to a given PCI device
  * @num: bus number
@@ -648,7 +746,7 @@
  *
  * Check the vendor & device ID against the early quirks table.
  *
- * If the device is single function, let early_quirks() know so we don't
+ * If the device is single function, let early_pci_scan_bus() know so we don't
  * poke at this device again.
  */
 static int __init check_dev_quirk(int num, int slot, int func)
@@ -657,6 +755,7 @@
 	u16 vendor;
 	u16 device;
 	u8 type;
+	u8 sec;
 	int i;
 
 	class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE);
@@ -684,25 +783,45 @@
 
 	type = read_pci_config_byte(num, slot, func,
 				    PCI_HEADER_TYPE);
+
+	if ((type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
+		/* pci_early_clear_msi scans the buses differently. */
+		if (pci_early_clear_msi)
+			return -1;
+
+		sec = read_pci_config_byte(num, slot, func, PCI_SECONDARY_BUS);
+		if (sec > num)
+			early_pci_scan_bus(sec);
+	}
+
 	if (!(type & 0x80))
 		return -1;
 
 	return 0;
 }
 
-void __init early_quirks(void)
+static void __init early_pci_scan_bus(int bus)
 {
 	int slot, func;
 
-	if (!early_pci_allowed())
-		return;
-
 	/* Poor man's PCI discovery */
-	/* Only scan the root bus */
 	for (slot = 0; slot < 32; slot++)
 		for (func = 0; func < 8; func++) {
 			/* Only probe function 0 on single fn devices */
-			if (check_dev_quirk(0, slot, func))
+			if (check_dev_quirk(bus, slot, func))
 				break;
 		}
 }
+
+void __init early_quirks(void)
+{
+	int bus;
+
+	if (!early_pci_allowed())
+		return;
+
+	early_pci_scan_bus(0);
+	/* pci_early_clear_msi scans more buses. */
+	for (bus = 1; pci_early_clear_msi && bus < 256; bus++)
+		early_pci_scan_bus(bus);
+}
--- linux-4.4.0.orig/arch/x86/kernel/espfix_64.c
+++ linux-4.4.0/arch/x86/kernel/espfix_64.c
@@ -41,6 +41,7 @@
 #include <asm/pgalloc.h>
 #include <asm/setup.h>
 #include <asm/espfix.h>
+#include <asm/kaiser.h>
 
 /*
  * Note: we only need 6*8 = 48 bytes for the espfix stack, but round
@@ -126,6 +127,15 @@
 	/* Install the espfix pud into the kernel page directory */
 	pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)];
 	pgd_populate(&init_mm, pgd_p, (pud_t *)espfix_pud_page);
+	/*
+	 * Just copy the top-level PGD that is mapping the espfix
+	 * area to ensure it is mapped into the shadow user page
+	 * tables.
+	 */
+	if (kaiser_enabled) {
+		set_pgd(native_get_shadow_pgd(pgd_p),
+			__pgd(_KERNPG_TABLE | __pa((pud_t *)espfix_pud_page)));
+	}
 
 	/* Randomize the locations */
 	init_espfix_random();
--- linux-4.4.0.orig/arch/x86/kernel/fpu/core.c
+++ linux-4.4.0/arch/x86/kernel/fpu/core.c
@@ -9,6 +9,7 @@
 #include <asm/fpu/regset.h>
 #include <asm/fpu/signal.h>
 #include <asm/traps.h>
+#include <asm/irq_regs.h>
 
 #include <linux/hardirq.h>
 
@@ -53,27 +54,9 @@
 	return this_cpu_read(in_kernel_fpu);
 }
 
-/*
- * Were we in an interrupt that interrupted kernel mode?
- *
- * On others, we can do a kernel_fpu_begin/end() pair *ONLY* if that
- * pair does nothing at all: the thread must not have fpu (so
- * that we don't try to save the FPU state), and TS must
- * be set (so that the clts/stts pair does nothing that is
- * visible in the interrupted kernel thread).
- *
- * Except for the eagerfpu case when we return true; in the likely case
- * the thread has FPU but we are not going to set/clear TS.
- */
 static bool interrupted_kernel_fpu_idle(void)
 {
-	if (kernel_fpu_disabled())
-		return false;
-
-	if (use_eager_fpu())
-		return true;
-
-	return !current->thread.fpu.fpregs_active && (read_cr0() & X86_CR0_TS);
+	return !kernel_fpu_disabled();
 }
 
 /*
@@ -114,10 +97,13 @@
 	kernel_fpu_disable();
 
 	if (fpu->fpregs_active) {
+		/*
+		 * Ignore return value -- we don't care if reg state
+		 * is clobbered.
+		 */
 		copy_fpregs_to_fpstate(fpu);
 	} else {
 		this_cpu_write(fpu_fpregs_owner_ctx, NULL);
-		__fpregs_activate_hw();
 	}
 }
 EXPORT_SYMBOL(__kernel_fpu_begin);
@@ -128,8 +114,6 @@
 
 	if (fpu->fpregs_active)
 		copy_kernel_to_fpregs(&fpu->state);
-	else
-		__fpregs_deactivate_hw();
 
 	kernel_fpu_enable();
 }
@@ -189,8 +173,9 @@
 
 	preempt_disable();
 	if (fpu->fpregs_active) {
-		if (!copy_fpregs_to_fpstate(fpu))
-			fpregs_deactivate(fpu);
+		if (!copy_fpregs_to_fpstate(fpu)) {
+			copy_kernel_to_fpregs(&fpu->state);
+		}
 	}
 	preempt_enable();
 }
@@ -237,8 +222,7 @@
 	 * Don't let 'init optimized' areas of the XSAVE area
 	 * leak into the child task:
 	 */
-	if (use_eager_fpu())
-		memset(&dst_fpu->state.xsave, 0, xstate_size);
+	memset(&dst_fpu->state.xsave, 0, xstate_size);
 
 	/*
 	 * Save current FPU registers directly into the child
@@ -259,14 +243,14 @@
 	preempt_disable();
 	if (!copy_fpregs_to_fpstate(dst_fpu)) {
 		memcpy(&src_fpu->state, &dst_fpu->state, xstate_size);
-		fpregs_deactivate(src_fpu);
+
+		copy_kernel_to_fpregs(&src_fpu->state);
 	}
 	preempt_enable();
 }
 
 int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
 {
-	dst_fpu->counter = 0;
 	dst_fpu->fpregs_active = 0;
 	dst_fpu->last_cpu = -1;
 
@@ -369,7 +353,6 @@
 	kernel_fpu_disable();
 	fpregs_activate(fpu);
 	copy_kernel_to_fpregs(&fpu->state);
-	fpu->counter++;
 	kernel_fpu_enable();
 }
 EXPORT_SYMBOL_GPL(fpu__restore);
@@ -386,7 +369,6 @@
 void fpu__drop(struct fpu *fpu)
 {
 	preempt_disable();
-	fpu->counter = 0;
 
 	if (fpu->fpregs_active) {
 		/* Ignore delayed exceptions from user space */
@@ -409,8 +391,10 @@
 {
 	if (use_xsave())
 		copy_kernel_to_xregs(&init_fpstate.xsave, -1);
-	else
+	else if (static_cpu_has(X86_FEATURE_FXSR))
 		copy_kernel_to_fxregs(&init_fpstate.fxsave);
+	else
+		copy_kernel_to_fregs(&init_fpstate.fsave);
 }
 
 /*
@@ -423,7 +407,7 @@
 {
 	WARN_ON_FPU(fpu != &current->thread.fpu); /* Almost certainly an anomaly */
 
-	if (!use_eager_fpu()) {
+	if (!static_cpu_has(X86_FEATURE_FPU)) {
 		/* FPU state will be reallocated lazily at the first use. */
 		fpu__drop(fpu);
 	} else {
--- linux-4.4.0.orig/arch/x86/kernel/fpu/init.c
+++ linux-4.4.0/arch/x86/kernel/fpu/init.c
@@ -3,8 +3,11 @@
  */
 #include <asm/fpu/internal.h>
 #include <asm/tlbflush.h>
+#include <asm/setup.h>
+#include <asm/cmdline.h>
 
 #include <linux/sched.h>
+#include <linux/init.h>
 
 /*
  * Initialize the TS bit in CR0 according to the style of context-switches
@@ -12,10 +15,7 @@
  */
 static void fpu__init_cpu_ctx_switch(void)
 {
-	if (!cpu_has_eager_fpu)
-		stts();
-	else
-		clts();
+	clts();
 }
 
 /*
@@ -75,13 +75,15 @@
 	cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
 	write_cr0(cr0);
 
-	asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
-		     : "+m" (fsw), "+m" (fcw));
+	if (!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
+		asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
+			     : "+m" (fsw), "+m" (fcw));
 
-	if (fsw == 0 && (fcw & 0x103f) == 0x003f)
-		set_cpu_cap(c, X86_FEATURE_FPU);
-	else
-		clear_cpu_cap(c, X86_FEATURE_FPU);
+		if (fsw == 0 && (fcw & 0x103f) == 0x003f)
+			set_cpu_cap(c, X86_FEATURE_FPU);
+		else
+			clear_cpu_cap(c, X86_FEATURE_FPU);
+	}
 
 #ifndef CONFIG_MATH_EMULATION
 	if (!cpu_has_fpu) {
@@ -96,6 +98,7 @@
  * Boot time FPU feature detection code:
  */
 unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
+EXPORT_SYMBOL_GPL(mxcsr_feature_mask);
 
 static void __init fpu__init_system_mxcsr(void)
 {
@@ -129,7 +132,7 @@
 	 * Set up the legacy init FPU context. (xstate init might overwrite this
 	 * with a more modern format, if the CPU supports it.)
 	 */
-	fpstate_init_fxstate(&init_fpstate.fxsave);
+	fpstate_init(&init_fpstate);
 
 	fpu__init_system_mxcsr();
 }
@@ -229,53 +232,16 @@
 }
 
 /*
- * FPU context switching strategies:
- *
- * Against popular belief, we don't do lazy FPU saves, due to the
- * task migration complications it brings on SMP - we only do
- * lazy FPU restores.
- *
- * 'lazy' is the traditional strategy, which is based on setting
- * CR0::TS to 1 during context-switch (instead of doing a full
- * restore of the FPU state), which causes the first FPU instruction
- * after the context switch (whenever it is executed) to fault - at
- * which point we lazily restore the FPU state into FPU registers.
- *
- * Tasks are of course under no obligation to execute FPU instructions,
- * so it can easily happen that another context-switch occurs without
- * a single FPU instruction being executed. If we eventually switch
- * back to the original task (that still owns the FPU) then we have
- * not only saved the restores along the way, but we also have the
- * FPU ready to be used for the original task.
- *
- * 'eager' switching is used on modern CPUs, there we switch the FPU
- * state during every context switch, regardless of whether the task
- * has used FPU instructions in that time slice or not. This is done
- * because modern FPU context saving instructions are able to optimize
- * state saving and restoration in hardware: they can detect both
- * unused and untouched FPU state and optimize accordingly.
- *
- * [ Note that even in 'lazy' mode we might optimize context switches
- *   to use 'eager' restores, if we detect that a task is using the FPU
- *   frequently. See the fpu->counter logic in fpu/internal.h for that. ]
+ * Find supported xfeatures based on cpu features and command-line input.
+ * This must be called after fpu__init_parse_early_param() is called and
+ * xfeatures_mask is enumerated.
  */
-static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
-
-static int __init eager_fpu_setup(char *s)
+u64 __init fpu__get_supported_xfeatures_mask(void)
 {
-	if (!strcmp(s, "on"))
-		eagerfpu = ENABLE;
-	else if (!strcmp(s, "off"))
-		eagerfpu = DISABLE;
-	else if (!strcmp(s, "auto"))
-		eagerfpu = AUTO;
-	return 1;
+	return XCNTXT_MASK;
 }
-__setup("eagerfpu=", eager_fpu_setup);
 
-/*
- * Pick the FPU context switching strategy:
- */
+/* Legacy code to initialize eager fpu mode. */
 static void __init fpu__init_system_ctx_switch(void)
 {
 	static bool on_boot_cpu = 1;
@@ -285,25 +251,31 @@
 
 	WARN_ON_FPU(current->thread.fpu.fpstate_active);
 	current_thread_info()->status = 0;
+}
 
-	/* Auto enable eagerfpu for xsaveopt */
-	if (cpu_has_xsaveopt && eagerfpu != DISABLE)
-		eagerfpu = ENABLE;
-
-	if (xfeatures_mask & XFEATURE_MASK_EAGER) {
-		if (eagerfpu == DISABLE) {
-			pr_err("x86/fpu: eagerfpu switching disabled, disabling the following xstate features: 0x%llx.\n",
-			       xfeatures_mask & XFEATURE_MASK_EAGER);
-			xfeatures_mask &= ~XFEATURE_MASK_EAGER;
-		} else {
-			eagerfpu = ENABLE;
-		}
+/*
+ * We parse fpu parameters early because fpu__init_system() is executed
+ * before parse_early_param().
+ */
+static void __init fpu__init_parse_early_param(void)
+{
+	if (cmdline_find_option_bool(boot_command_line, "no387"))
+		setup_clear_cpu_cap(X86_FEATURE_FPU);
+
+	if (cmdline_find_option_bool(boot_command_line, "nofxsr")) {
+		setup_clear_cpu_cap(X86_FEATURE_FXSR);
+		setup_clear_cpu_cap(X86_FEATURE_FXSR_OPT);
+		setup_clear_cpu_cap(X86_FEATURE_XMM);
 	}
 
-	if (eagerfpu == ENABLE)
-		setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
+	if (cmdline_find_option_bool(boot_command_line, "noxsave"))
+		fpu__xstate_clear_all_cpu_caps();
+
+	if (cmdline_find_option_bool(boot_command_line, "noxsaveopt"))
+		setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
 
-	printk(KERN_INFO "x86/fpu: Using '%s' FPU context switches.\n", eagerfpu == ENABLE ? "eager" : "lazy");
+	if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
+		setup_clear_cpu_cap(X86_FEATURE_XSAVES);
 }
 
 /*
@@ -312,6 +284,7 @@
  */
 void __init fpu__init_system(struct cpuinfo_x86 *c)
 {
+	fpu__init_parse_early_param();
 	fpu__init_system_early_generic(c);
 
 	/*
@@ -335,62 +308,3 @@
 
 	fpu__init_system_ctx_switch();
 }
-
-/*
- * Boot parameter to turn off FPU support and fall back to math-emu:
- */
-static int __init no_387(char *s)
-{
-	setup_clear_cpu_cap(X86_FEATURE_FPU);
-	return 1;
-}
-__setup("no387", no_387);
-
-/*
- * Disable all xstate CPU features:
- */
-static int __init x86_noxsave_setup(char *s)
-{
-	if (strlen(s))
-		return 0;
-
-	fpu__xstate_clear_all_cpu_caps();
-
-	return 1;
-}
-__setup("noxsave", x86_noxsave_setup);
-
-/*
- * Disable the XSAVEOPT instruction specifically:
- */
-static int __init x86_noxsaveopt_setup(char *s)
-{
-	setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
-
-	return 1;
-}
-__setup("noxsaveopt", x86_noxsaveopt_setup);
-
-/*
- * Disable the XSAVES instruction:
- */
-static int __init x86_noxsaves_setup(char *s)
-{
-	setup_clear_cpu_cap(X86_FEATURE_XSAVES);
-
-	return 1;
-}
-__setup("noxsaves", x86_noxsaves_setup);
-
-/*
- * Disable FX save/restore and SSE support:
- */
-static int __init x86_nofxsr_setup(char *s)
-{
-	setup_clear_cpu_cap(X86_FEATURE_FXSR);
-	setup_clear_cpu_cap(X86_FEATURE_FXSR_OPT);
-	setup_clear_cpu_cap(X86_FEATURE_XMM);
-
-	return 1;
-}
-__setup("nofxsr", x86_nofxsr_setup);
--- linux-4.4.0.orig/arch/x86/kernel/fpu/regset.c
+++ linux-4.4.0/arch/x86/kernel/fpu/regset.c
@@ -116,6 +116,11 @@
 	xsave = &fpu->state.xsave;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
+
+	/* xcomp_bv must be 0 when using uncompacted format */
+	if (!ret && xsave->header.xcomp_bv)
+		ret = -EINVAL;
+
 	/*
 	 * mxcsr reserved bits must be masked to zero for security reasons.
 	 */
@@ -126,6 +131,12 @@
 	 */
 	memset(&xsave->header.reserved, 0, 48);
 
+	/*
+	 * In case of failure, mark all states as init:
+	 */
+	if (ret)
+		fpstate_init(&fpu->state);
+
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/x86/kernel/fpu/signal.c
+++ linux-4.4.0/arch/x86/kernel/fpu/signal.c
@@ -294,7 +294,6 @@
 		 * thread's fpu state, reconstruct fxstate from the fsave
 		 * header. Sanitize the copied state etc.
 		 */
-		struct fpu *fpu = &tsk->thread.fpu;
 		struct user_i387_ia32_struct env;
 		int err = 0;
 
@@ -309,19 +308,19 @@
 		fpu__drop(fpu);
 
 		if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) ||
-		    __copy_from_user(&env, buf, sizeof(env))) {
+		    __copy_from_user(&env, buf, sizeof(env)) ||
+		    (state_size > offsetof(struct xregs_state, header) &&
+		     fpu->state.xsave.header.xcomp_bv)) {
 			fpstate_init(&fpu->state);
 			err = -1;
 		} else {
 			sanitize_restored_xstate(tsk, &env, xfeatures, fx_only);
 		}
 
+		local_bh_disable();
 		fpu->fpstate_active = 1;
-		if (use_eager_fpu()) {
-			preempt_disable();
-			fpu__restore(fpu);
-			preempt_enable();
-		}
+		fpu__restore(fpu);
+		local_bh_enable();
 
 		return err;
 	} else {
--- linux-4.4.0.orig/arch/x86/kernel/fpu/xstate.c
+++ linux-4.4.0/arch/x86/kernel/fpu/xstate.c
@@ -632,8 +632,7 @@
 		BUG();
 	}
 
-	/* Support only the state known to the OS: */
-	xfeatures_mask = xfeatures_mask & XCNTXT_MASK;
+	xfeatures_mask &= fpu__get_supported_xfeatures_mask();
 
 	/* Enable xstate instructions to be able to continue with initialization: */
 	fpu__init_cpu_xstate();
--- linux-4.4.0.orig/arch/x86/kernel/ftrace.c
+++ linux-4.4.0/arch/x86/kernel/ftrace.c
@@ -28,6 +28,7 @@
 #include <asm/kprobes.h>
 #include <asm/ftrace.h>
 #include <asm/nops.h>
+#include <asm/sections.h>
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
@@ -977,6 +978,18 @@
 	unsigned long return_hooker = (unsigned long)
 				&return_to_handler;
 
+	/*
+	 * When resuming from suspend-to-ram, this function can be indirectly
+	 * called from early CPU startup code while the CPU is in real mode,
+	 * which would fail miserably.  Make sure the stack pointer is a
+	 * virtual address.
+	 *
+	 * This check isn't as accurate as virt_addr_valid(), but it should be
+	 * good enough for this purpose, and it's fast.
+	 */
+	if (unlikely((long)__builtin_frame_address(0) >= 0))
+		return;
+
 	if (unlikely(ftrace_graph_is_dead()))
 		return;
 
--- linux-4.4.0.orig/arch/x86/kernel/head64.c
+++ linux-4.4.0/arch/x86/kernel/head64.c
@@ -4,6 +4,7 @@
  *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
  */
 
+#define DISABLE_BRANCH_PROFILING
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
--- linux-4.4.0.orig/arch/x86/kernel/head_32.S
+++ linux-4.4.0/arch/x86/kernel/head_32.S
@@ -19,10 +19,11 @@
 #include <asm/setup.h>
 #include <asm/processor-flags.h>
 #include <asm/msr-index.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/percpu.h>
 #include <asm/nops.h>
 #include <asm/bootparam.h>
+#include <asm/nospec-branch.h>
 
 /* Physical address */
 #define pa(X) ((X) - __PAGE_OFFSET)
@@ -34,7 +35,7 @@
 #define X86		new_cpu_data+CPUINFO_x86
 #define X86_VENDOR	new_cpu_data+CPUINFO_x86_vendor
 #define X86_MODEL	new_cpu_data+CPUINFO_x86_model
-#define X86_MASK	new_cpu_data+CPUINFO_x86_mask
+#define X86_STEPPING	new_cpu_data+CPUINFO_x86_stepping
 #define X86_HARD_MATH	new_cpu_data+CPUINFO_hard_math
 #define X86_CPUID	new_cpu_data+CPUINFO_cpuid_level
 #define X86_CAPABILITY	new_cpu_data+CPUINFO_x86_capability
@@ -257,6 +258,7 @@
 
 	movl pa(subarch_entries)(,%eax,4), %eax
 	subl $__PAGE_OFFSET, %eax
+	ANNOTATE_RETPOLINE_SAFE
 	jmp *%eax
 
 bad_subarch:
@@ -410,6 +412,7 @@
 	movl setup_once_ref,%eax
 	andl %eax,%eax
 	jz 1f				# Did we do this already?
+	ANNOTATE_RETPOLINE_SAFE
 	call *%eax
 1:
 
@@ -440,7 +443,7 @@
 	shrb $4,%al
 	movb %al,X86_MODEL
 	andb $0x0f,%cl		# mask mask revision
-	movb %cl,X86_MASK
+	movb %cl,X86_STEPPING
 	movl %edx,X86_CAPABILITY
 
 is486:
@@ -571,7 +574,7 @@
 	movl %eax,%ds
 	movl %eax,%es
 
-	cmpl $(__KERNEL_CS),32(%esp)
+	cmpw $(__KERNEL_CS),32(%esp)
 	jne 10f
 
 	leal 28(%esp),%eax	# Pointer to %eip
@@ -669,14 +672,17 @@
 initial_pg_pmd:
 	.fill 1024*KPMDS,4,0
 #else
-ENTRY(initial_page_table)
+.globl initial_page_table
+initial_page_table:
 	.fill 1024,4,0
 #endif
 initial_pg_fixmap:
 	.fill 1024,4,0
-ENTRY(empty_zero_page)
+.globl empty_zero_page
+empty_zero_page:
 	.fill 4096,1,0
-ENTRY(swapper_pg_dir)
+.globl swapper_pg_dir
+swapper_pg_dir:
 	.fill 1024,4,0
 
 /*
--- linux-4.4.0.orig/arch/x86/kernel/head_64.S
+++ linux-4.4.0/arch/x86/kernel/head_64.S
@@ -20,6 +20,7 @@
 #include <asm/processor-flags.h>
 #include <asm/percpu.h>
 #include <asm/nops.h>
+#include <asm/nospec-branch.h>
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/asm-offsets.h>
@@ -76,9 +77,7 @@
 	subq	$_text - __START_KERNEL_map, %rbp
 
 	/* Is the address not 2M aligned? */
-	movq	%rbp, %rax
-	andl	$~PMD_PAGE_MASK, %eax
-	testl	%eax, %eax
+	testl	$~PMD_PAGE_MASK, %ebp
 	jnz	bad_address
 
 	/*
@@ -183,8 +182,8 @@
 	movq	$(init_level4_pgt - __START_KERNEL_map), %rax
 1:
 
-	/* Enable PAE mode and PGE */
-	movl	$(X86_CR4_PAE | X86_CR4_PGE), %ecx
+	/* Enable PAE and PSE, but defer PGE until kaiser_enabled is decided */
+	movl	$(X86_CR4_PAE | X86_CR4_PSE), %ecx
 	movq	%rcx, %cr4
 
 	/* Setup early boot stage 4 level pagetables. */
@@ -193,6 +192,7 @@
 
 	/* Ensure I am executing from virtual addresses */
 	movq	$1f, %rax
+	ANNOTATE_RETPOLINE_SAFE
 	jmp	*%rax
 1:
 
@@ -441,6 +441,27 @@
 	.balign	PAGE_SIZE; \
 GLOBAL(name)
 
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+/*
+ * Each PGD needs to be 8k long and 8k aligned.  We do not
+ * ever go out to userspace with these, so we do not
+ * strictly *need* the second page, but this allows us to
+ * have a single set_pgd() implementation that does not
+ * need to worry about whether it has 4k or 8k to work
+ * with.
+ *
+ * This ensures PGDs are 8k long:
+ */
+#define KAISER_USER_PGD_FILL	512
+/* This ensures they are 8k-aligned: */
+#define NEXT_PGD_PAGE(name) \
+	.balign 2 * PAGE_SIZE; \
+GLOBAL(name)
+#else
+#define NEXT_PGD_PAGE(name) NEXT_PAGE(name)
+#define KAISER_USER_PGD_FILL	0
+#endif
+
 /* Automate the creation of 1 to 1 mapping pmd entries */
 #define PMDS(START, PERM, COUNT)			\
 	i = 0 ;						\
@@ -450,9 +471,10 @@
 	.endr
 
 	__INITDATA
-NEXT_PAGE(early_level4_pgt)
+NEXT_PGD_PAGE(early_level4_pgt)
 	.fill	511,8,0
 	.quad	level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
+	.fill	KAISER_USER_PGD_FILL,8,0
 
 NEXT_PAGE(early_dynamic_pgts)
 	.fill	512*EARLY_DYNAMIC_PAGE_TABLES,8,0
@@ -460,16 +482,18 @@
 	.data
 
 #ifndef CONFIG_XEN
-NEXT_PAGE(init_level4_pgt)
+NEXT_PGD_PAGE(init_level4_pgt)
 	.fill	512,8,0
+	.fill	KAISER_USER_PGD_FILL,8,0
 #else
-NEXT_PAGE(init_level4_pgt)
+NEXT_PGD_PAGE(init_level4_pgt)
 	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
 	.org    init_level4_pgt + L4_PAGE_OFFSET*8, 0
 	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
 	.org    init_level4_pgt + L4_START_KERNEL*8, 0
 	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
 	.quad   level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
+	.fill	KAISER_USER_PGD_FILL,8,0
 
 NEXT_PAGE(level3_ident_pgt)
 	.quad	level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
@@ -480,6 +504,7 @@
 	 */
 	PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
 #endif
+	.fill	KAISER_USER_PGD_FILL,8,0
 
 NEXT_PAGE(level3_kernel_pgt)
 	.fill	L3_START_KERNEL,8,0
--- linux-4.4.0.orig/arch/x86/kernel/hpet.c
+++ linux-4.4.0/arch/x86/kernel/hpet.c
@@ -1,6 +1,7 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/export.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -12,6 +13,7 @@
 #include <linux/pm.h>
 #include <linux/io.h>
 
+#include <asm/cpufeature.h>
 #include <asm/irqdomain.h>
 #include <asm/fixmap.h>
 #include <asm/hpet.h>
@@ -351,8 +353,9 @@
 	} else {
 		struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
 
+		irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq));
 		irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
-		disable_irq(hdev->irq);
+		disable_hardirq(hdev->irq);
 		irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
 		enable_irq(hdev->irq);
 	}
@@ -772,7 +775,6 @@
 	.mask		= HPET_MASK,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 	.resume		= hpet_resume_counter,
-	.archdata	= { .vclock_mode = VCLOCK_HPET },
 };
 
 static int hpet_clocksource_register(void)
@@ -823,6 +825,8 @@
 		return 0;
 
 	hpet_set_mapping();
+	if (!hpet_virt_address)
+		return 0;
 
 	/*
 	 * Read the period and check for a sane value:
--- linux-4.4.0.orig/arch/x86/kernel/hw_breakpoint.c
+++ linux-4.4.0/arch/x86/kernel/hw_breakpoint.c
@@ -36,13 +36,14 @@
 #include <linux/percpu.h>
 #include <linux/kdebug.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 
 #include <asm/hw_breakpoint.h>
 #include <asm/processor.h>
 #include <asm/debugreg.h>
+#include <asm/user.h>
 
 /* Per cpu debug control register value */
 DEFINE_PER_CPU(unsigned long, cpu_dr7);
@@ -300,6 +301,10 @@
 			return -EINVAL;
 		if (bp->attr.bp_addr & (bp->attr.bp_len - 1))
 			return -EINVAL;
+
+		if (!boot_cpu_has(X86_FEATURE_BPEXT))
+			return -EOPNOTSUPP;
+
 		/*
 		 * It's impossible to use a range breakpoint to fake out
 		 * user vs kernel detection because bp_len - 1 can't
@@ -307,8 +312,6 @@
 		 * breakpoints, then we'll have to check for kprobe-blacklisted
 		 * addresses anywhere in the range.
 		 */
-		if (!cpu_has_bpext)
-			return -EOPNOTSUPP;
 		info->mask = bp->attr.bp_len - 1;
 		info->len = X86_BREAKPOINT_LEN_1;
 	}
@@ -349,6 +352,7 @@
 #endif
 	default:
 		WARN_ON_ONCE(1);
+		return -EINVAL;
 	}
 
 	/*
--- linux-4.4.0.orig/arch/x86/kernel/i386_ksyms_32.c
+++ linux-4.4.0/arch/x86/kernel/i386_ksyms_32.c
@@ -1,4 +1,5 @@
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/spinlock_types.h>
 
 #include <asm/checksum.h>
 #include <asm/pgtable.h>
@@ -42,3 +43,5 @@
 EXPORT_SYMBOL(___preempt_schedule);
 EXPORT_SYMBOL(___preempt_schedule_notrace);
 #endif
+
+EXPORT_SYMBOL(__sw_hweight32);
--- linux-4.4.0.orig/arch/x86/kernel/i8253.c
+++ linux-4.4.0/arch/x86/kernel/i8253.c
@@ -3,7 +3,7 @@
  *
  */
 #include <linux/clockchips.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/timex.h>
 #include <linux/i8253.h>
 
--- linux-4.4.0.orig/arch/x86/kernel/i8259.c
+++ linux-4.4.0/arch/x86/kernel/i8259.c
@@ -4,6 +4,7 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/timex.h>
 #include <linux/random.h>
 #include <linux/init.h>
@@ -204,7 +205,7 @@
 		 * lets ACK and report it. [once per IRQ]
 		 */
 		if (!(spurious_irq_mask & irqmask)) {
-			printk(KERN_DEBUG
+			printk_deferred(KERN_DEBUG
 			       "spurious 8259A interrupt: IRQ%d.\n", irq);
 			spurious_irq_mask |= irqmask;
 		}
@@ -418,6 +419,7 @@
 };
 
 struct legacy_pic *legacy_pic = &default_legacy_pic;
+EXPORT_SYMBOL(legacy_pic);
 
 static int __init i8259A_init_ops(void)
 {
--- linux-4.4.0.orig/arch/x86/kernel/io_delay.c
+++ linux-4.4.0/arch/x86/kernel/io_delay.c
@@ -6,7 +6,7 @@
  * outb_p/inb_p API uses.
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
--- linux-4.4.0.orig/arch/x86/kernel/ioport.c
+++ linux-4.4.0/arch/x86/kernel/ioport.c
@@ -15,6 +15,7 @@
 #include <linux/thread_info.h>
 #include <linux/syscalls.h>
 #include <linux/bitmap.h>
+#include <linux/module.h>
 #include <asm/syscalls.h>
 
 /*
@@ -28,7 +29,7 @@
 
 	if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
 		return -EINVAL;
-	if (turn_on && !capable(CAP_SYS_RAWIO))
+	if (turn_on && (!capable(CAP_SYS_RAWIO) || secure_modules()))
 		return -EPERM;
 
 	/*
@@ -96,18 +97,24 @@
 SYSCALL_DEFINE1(iopl, unsigned int, level)
 {
 	struct pt_regs *regs = current_pt_regs();
-	unsigned int old = (regs->flags >> 12) & 3;
 	struct thread_struct *t = &current->thread;
 
+	/*
+	 * Careful: the IOPL bits in regs->flags are undefined under Xen PV
+	 * and changing them has no effect.
+	 */
+	unsigned int old = t->iopl >> X86_EFLAGS_IOPL_BIT;
+
 	if (level > 3)
 		return -EINVAL;
 	/* Trying to gain more privileges? */
 	if (level > old) {
-		if (!capable(CAP_SYS_RAWIO))
+		if (!capable(CAP_SYS_RAWIO) || secure_modules())
 			return -EPERM;
 	}
-	regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12);
-	t->iopl = level << 12;
+	regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) |
+		(level << X86_EFLAGS_IOPL_BIT);
+	t->iopl = level << X86_EFLAGS_IOPL_BIT;
 	set_iopl_mask(t->iopl);
 
 	return 0;
--- linux-4.4.0.orig/arch/x86/kernel/irq.c
+++ linux-4.4.0/arch/x86/kernel/irq.c
@@ -10,6 +10,7 @@
 #include <linux/ftrace.h>
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/irq.h>
 
 #include <asm/apic.h>
 #include <asm/io_apic.h>
@@ -102,8 +103,7 @@
 	seq_puts(p, "  Rescheduling interrupts\n");
 	seq_printf(p, "%*s: ", prec, "CAL");
 	for_each_online_cpu(j)
-		seq_printf(p, "%10u ", irq_stats(j)->irq_call_count -
-					irq_stats(j)->irq_tlb_count);
+		seq_printf(p, "%10u ", irq_stats(j)->irq_call_count);
 	seq_puts(p, "  Function call interrupts\n");
 	seq_printf(p, "%*s: ", prec, "TLB");
 	for_each_online_cpu(j)
@@ -462,7 +462,7 @@
 		 * non intr-remapping case, we can't wait till this interrupt
 		 * arrives at this cpu before completing the irq move.
 		 */
-		irq_force_complete_move(irq);
+		irq_force_complete_move(desc);
 
 		if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
 			break_affinity = 1;
@@ -470,6 +470,15 @@
 		}
 
 		chip = irq_data_get_irq_chip(data);
+		/*
+		 * The interrupt descriptor might have been cleaned up
+		 * already, but it is not yet removed from the radix tree
+		 */
+		if (!chip) {
+			raw_spin_unlock(&desc->lock);
+			continue;
+		}
+
 		if (!irqd_can_move_in_process_context(data) && chip->irq_mask)
 			chip->irq_mask(data);
 
--- linux-4.4.0.orig/arch/x86/kernel/irq_32.c
+++ linux-4.4.0/arch/x86/kernel/irq_32.c
@@ -8,9 +8,9 @@
  * io_apic.c.)
  */
 
-#include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel_stat.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 
 #include <asm/apic.h>
+#include <asm/nospec-branch.h>
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 
@@ -55,17 +56,17 @@
 static void call_on_stack(void *func, void *stack)
 {
 	asm volatile("xchgl	%%ebx,%%esp	\n"
-		     "call	*%%edi		\n"
+		     CALL_NOSPEC
 		     "movl	%%ebx,%%esp	\n"
 		     : "=b" (stack)
 		     : "0" (stack),
-		       "D"(func)
+		       [thunk_target] "D"(func)
 		     : "memory", "cc", "edx", "ecx", "eax");
 }
 
 static inline void *current_stack(void)
 {
-	return (void *)(current_stack_pointer() & ~(THREAD_SIZE - 1));
+	return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1));
 }
 
 static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc)
@@ -89,17 +90,17 @@
 
 	/* Save the next esp at the bottom of the stack */
 	prev_esp = (u32 *)irqstk;
-	*prev_esp = current_stack_pointer();
+	*prev_esp = current_stack_pointer;
 
 	if (unlikely(overflow))
 		call_on_stack(print_stack_overflow, isp);
 
 	asm volatile("xchgl	%%ebx,%%esp	\n"
-		     "call	*%%edi		\n"
+		     CALL_NOSPEC
 		     "movl	%%ebx,%%esp	\n"
 		     : "=a" (arg1), "=b" (isp)
 		     :  "0" (desc),   "1" (isp),
-			"D" (desc->handle_irq)
+			[thunk_target] "D" (desc->handle_irq)
 		     : "memory", "cc", "ecx");
 	return 1;
 }
@@ -142,7 +143,7 @@
 
 	/* Push the previous esp onto the stack */
 	prev_esp = (u32 *)irqstk;
-	*prev_esp = current_stack_pointer();
+	*prev_esp = current_stack_pointer;
 
 	call_on_stack(__do_softirq, isp);
 }
--- linux-4.4.0.orig/arch/x86/kernel/irq_64.c
+++ linux-4.4.0/arch/x86/kernel/irq_64.c
@@ -10,8 +10,8 @@
 
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/seq_file.h>
-#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
@@ -25,9 +25,18 @@
 /*
  * Probabilistic stack overflow check:
  *
- * Only check the stack in process context, because everything else
- * runs on the big interrupt stacks. Checking reliably is too expensive,
- * so we just check from interrupts.
+ * Regular device interrupts can enter on the following stacks:
+ *
+ * - User stack
+ *
+ * - Kernel task stack
+ *
+ * - Interrupt stack if a device driver reenables interrupts
+ *   which should only happen in really old drivers.
+ *
+ * - Debug IST stack
+ *
+ * All other contexts are invalid.
  */
 static inline void stack_overflow_check(struct pt_regs *regs)
 {
@@ -53,8 +62,8 @@
 		return;
 
 	oist = this_cpu_ptr(&orig_ist);
-	estack_top = (u64)oist->ist[0] - EXCEPTION_STKSZ + STACK_TOP_MARGIN;
-	estack_bottom = (u64)oist->ist[N_EXCEPTION_STACKS - 1];
+	estack_bottom = (u64)oist->ist[DEBUG_STACK];
+	estack_top = estack_bottom - DEBUG_STKSZ + STACK_TOP_MARGIN;
 	if (regs->sp >= estack_top && regs->sp <= estack_bottom)
 		return;
 
--- linux-4.4.0.orig/arch/x86/kernel/irqflags.S
+++ linux-4.4.0/arch/x86/kernel/irqflags.S
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <asm/asm.h>
+#include <asm-generic/export.h>
+#include <linux/linkage.h>
+
+/*
+ * unsigned long native_save_fl(void)
+ */
+ENTRY(native_save_fl)
+	pushf
+	pop %_ASM_AX
+	ret
+ENDPROC(native_save_fl)
+EXPORT_SYMBOL(native_save_fl)
+
+/*
+ * void native_restore_fl(unsigned long flags)
+ * %eax/%rdi: flags
+ */
+ENTRY(native_restore_fl)
+	push %_ASM_ARG1
+	popf
+	ret
+ENDPROC(native_restore_fl)
+EXPORT_SYMBOL(native_restore_fl)
--- linux-4.4.0.orig/arch/x86/kernel/irqinit.c
+++ linux-4.4.0/arch/x86/kernel/irqinit.c
@@ -4,6 +4,7 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/timex.h>
 #include <linux/random.h>
 #include <linux/kprobes.h>
@@ -51,7 +52,7 @@
 	.flags = IRQF_NO_THREAD,
 };
 
-DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
+DEFINE_PER_CPU_USER_MAPPED(vector_irq_t, vector_irq) = {
 	[0 ... NR_VECTORS - 1] = VECTOR_UNUSED,
 };
 
--- linux-4.4.0.orig/arch/x86/kernel/jump_label.c
+++ linux-4.4.0/arch/x86/kernel/jump_label.c
@@ -13,6 +13,7 @@
 #include <linux/cpu.h>
 #include <asm/kprobes.h>
 #include <asm/alternative.h>
+#include <asm/text-patching.h>
 
 #ifdef HAVE_JUMP_LABEL
 
--- linux-4.4.0.orig/arch/x86/kernel/kdebugfs.c
+++ linux-4.4.0/arch/x86/kernel/kdebugfs.c
@@ -8,7 +8,7 @@
  */
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/stat.h>
--- linux-4.4.0.orig/arch/x86/kernel/kexec-bzimage64.c
+++ linux-4.4.0/arch/x86/kernel/kexec-bzimage64.c
@@ -168,6 +168,9 @@
 	struct efi_info *current_ei = &boot_params.efi_info;
 	struct efi_info *ei = &params->efi_info;
 
+	if (!efi_enabled(EFI_RUNTIME_SERVICES))
+		return 0;
+
 	if (!current_ei->efi_memmap_size)
 		return 0;
 
@@ -180,6 +183,7 @@
 	if (efi_enabled(EFI_OLD_MEMMAP))
 		return 0;
 
+	params->secure_boot = boot_params.secure_boot;
 	ei->efi_loader_signature = current_ei->efi_loader_signature;
 	ei->efi_systab = current_ei->efi_systab;
 	ei->efi_systab_hi = current_ei->efi_systab_hi;
@@ -209,8 +213,7 @@
 	params->hdr.hardware_subarch = boot_params.hdr.hardware_subarch;
 
 	/* Copying screen_info will do? */
-	memcpy(&params->screen_info, &boot_params.screen_info,
-				sizeof(struct screen_info));
+	memcpy(&params->screen_info, &screen_info, sizeof(struct screen_info));
 
 	/* Fill in memsize later */
 	params->screen_info.ext_mem_k = 0;
--- linux-4.4.0.orig/arch/x86/kernel/kgdb.c
+++ linux-4.4.0/arch/x86/kernel/kgdb.c
@@ -45,6 +45,7 @@
 #include <linux/uaccess.h>
 #include <linux/memory.h>
 
+#include <asm/text-patching.h>
 #include <asm/debugreg.h>
 #include <asm/apicdef.h>
 #include <asm/apic.h>
@@ -437,7 +438,7 @@
  */
 void kgdb_roundup_cpus(unsigned long flags)
 {
-	apic->send_IPI_allbutself(APIC_DM_NMI);
+	apic->send_IPI_allbutself(NMI_VECTOR);
 }
 #endif
 
--- linux-4.4.0.orig/arch/x86/kernel/kprobes/common.h
+++ linux-4.4.0/arch/x86/kernel/kprobes/common.h
@@ -67,7 +67,7 @@
 #endif
 
 /* Ensure if the instruction can be boostable */
-extern int can_boost(kprobe_opcode_t *instruction);
+extern int can_boost(kprobe_opcode_t *instruction, void *addr);
 /* Recover instruction if given address is probed */
 extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf,
 					 unsigned long addr);
--- linux-4.4.0.orig/arch/x86/kernel/kprobes/core.c
+++ linux-4.4.0/arch/x86/kernel/kprobes/core.c
@@ -49,7 +49,9 @@
 #include <linux/kdebug.h>
 #include <linux/kallsyms.h>
 #include <linux/ftrace.h>
+#include <linux/moduleloader.h>
 
+#include <asm/text-patching.h>
 #include <asm/cacheflush.h>
 #include <asm/desc.h>
 #include <asm/pgtable.h>
@@ -57,6 +59,7 @@
 #include <asm/alternative.h>
 #include <asm/insn.h>
 #include <asm/debugreg.h>
+#include <asm/sections.h>
 
 #include "common.h"
 
@@ -163,12 +166,12 @@
  * Returns non-zero if opcode is boostable.
  * RIP relative instructions are adjusted at copying time in 64 bits mode
  */
-int can_boost(kprobe_opcode_t *opcodes)
+int can_boost(kprobe_opcode_t *opcodes, void *addr)
 {
 	kprobe_opcode_t opcode;
 	kprobe_opcode_t *orig_opcodes = opcodes;
 
-	if (search_exception_tables((unsigned long)opcodes))
+	if (search_exception_tables((unsigned long)addr))
 		return 0;	/* Page fault may occur on this address. */
 
 retry:
@@ -196,6 +199,8 @@
 		return (opcode != 0x62 && opcode != 0x67);
 	case 0x70:
 		return 0; /* can't boost conditional jump */
+	case 0x90:
+		return opcode != 0x9a;	/* can't boost call far */
 	case 0xc0:
 		/* can't boost software-interruptions */
 		return (0xc1 < opcode && opcode < 0xcc) || opcode == 0xcf;
@@ -369,6 +374,10 @@
 		return 0;
 	memcpy(dest, insn.kaddr, length);
 
+	/* We should not singlestep on the exception masking instructions */
+	if (insn_masking_exception(&insn))
+		return 0;
+
 #ifdef CONFIG_X86_64
 	if (insn_rip_relative(&insn)) {
 		s64 newdisp;
@@ -390,7 +399,6 @@
 		newdisp = (u8 *) src + (s64) insn.displacement.value - (u8 *) dest;
 		if ((s64) (s32) newdisp != newdisp) {
 			pr_err("Kprobes error: new displacement does not fit into s32 (%llx)\n", newdisp);
-			pr_err("\tSrc: %p, Dest: %p, old disp: %x\n", src, dest, insn.displacement.value);
 			return 0;
 		}
 		disp = (u8 *) dest + insn_offset_displacement(&insn);
@@ -400,23 +408,48 @@
 	return length;
 }
 
+/* Recover page to RW mode before releasing it */
+void free_insn_page(void *page)
+{
+	set_memory_nx((unsigned long)page & PAGE_MASK, 1);
+	set_memory_rw((unsigned long)page & PAGE_MASK, 1);
+	module_memfree(page);
+}
+
+/* Prepare reljump right after instruction to boost */
+static void prepare_boost(struct kprobe *p, int length)
+{
+	if (can_boost(p->ainsn.insn, p->addr) &&
+	    MAX_INSN_SIZE - length >= RELATIVEJUMP_SIZE) {
+		/*
+		 * These instructions can be executed directly if it
+		 * jumps back to correct address.
+		 */
+		synthesize_reljump(p->ainsn.insn + length, p->addr + length);
+		p->ainsn.boostable = 1;
+	} else {
+		p->ainsn.boostable = -1;
+	}
+}
+
 static int arch_copy_kprobe(struct kprobe *p)
 {
-	int ret;
+	int len;
+
+	set_memory_rw((unsigned long)p->ainsn.insn & PAGE_MASK, 1);
 
 	/* Copy an instruction with recovering if other optprobe modifies it.*/
-	ret = __copy_instruction(p->ainsn.insn, p->addr);
-	if (!ret)
+	len = __copy_instruction(p->ainsn.insn, p->addr);
+	if (!len)
 		return -EINVAL;
 
 	/*
 	 * __copy_instruction can modify the displacement of the instruction,
 	 * but it doesn't affect boostable check.
 	 */
-	if (can_boost(p->ainsn.insn))
-		p->ainsn.boostable = 0;
-	else
-		p->ainsn.boostable = -1;
+	prepare_boost(p, len);
+
+	set_memory_ro((unsigned long)p->ainsn.insn & PAGE_MASK, 1);
 
 	/* Check whether the instruction modifies Interrupt Flag or not */
 	p->ainsn.if_modifier = is_IF_modifier(p->ainsn.insn);
@@ -514,6 +547,7 @@
 	unsigned long *sara = stack_addr(regs);
 
 	ri->ret_addr = (kprobe_opcode_t *) *sara;
+	ri->fp = sara;
 
 	/* Replace the return addr with trampoline addr */
 	*sara = (unsigned long) &kretprobe_trampoline;
@@ -581,8 +615,7 @@
 		 * Raise a BUG or we'll continue in an endless reentering loop
 		 * and eventually a stack overflow.
 		 */
-		printk(KERN_WARNING "Unrecoverable kprobe detected at %p.\n",
-		       p->addr);
+		pr_err("Unrecoverable kprobe detected.\n");
 		dump_kprobe(p);
 		BUG();
 	default:
@@ -716,15 +749,28 @@
 	unsigned long flags, orig_ret_address = 0;
 	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
 	kprobe_opcode_t *correct_ret_addr = NULL;
+	void *frame_pointer;
+	bool skipped = false;
+
+	/*
+	 * Set a dummy kprobe for avoiding kretprobe recursion.
+	 * Since kretprobe never run in kprobe handler, kprobe must not
+	 * be running at this point.
+	 */
+	kprobe_busy_begin();
 
 	INIT_HLIST_HEAD(&empty_rp);
 	kretprobe_hash_lock(current, &head, &flags);
 	/* fixup registers */
 #ifdef CONFIG_X86_64
 	regs->cs = __KERNEL_CS;
+	/* On x86-64, we use pt_regs->sp for return address holder. */
+	frame_pointer = &regs->sp;
 #else
 	regs->cs = __KERNEL_CS | get_kernel_rpl();
 	regs->gs = 0;
+	/* On x86-32, we use pt_regs->flags for return address holder. */
+	frame_pointer = &regs->flags;
 #endif
 	regs->ip = trampoline_address;
 	regs->orig_ax = ~0UL;
@@ -746,8 +792,25 @@
 		if (ri->task != current)
 			/* another task is sharing our hash bucket */
 			continue;
+		/*
+		 * Return probes must be pushed on this hash list correct
+		 * order (same as return order) so that it can be poped
+		 * correctly. However, if we find it is pushed it incorrect
+		 * order, this means we find a function which should not be
+		 * probed, because the wrong order entry is pushed on the
+		 * path of processing other kretprobe itself.
+		 */
+		if (ri->fp != frame_pointer) {
+			if (!skipped)
+				pr_warn("kretprobe is stacked incorrectly. Trying to fixup.\n");
+			skipped = true;
+			continue;
+		}
 
 		orig_ret_address = (unsigned long)ri->ret_addr;
+		if (skipped)
+			pr_warn("%ps must be blacklisted because of incorrect kretprobe order\n",
+				ri->rp->kp.addr);
 
 		if (orig_ret_address != trampoline_address)
 			/*
@@ -765,14 +828,15 @@
 		if (ri->task != current)
 			/* another task is sharing our hash bucket */
 			continue;
+		if (ri->fp != frame_pointer)
+			continue;
 
 		orig_ret_address = (unsigned long)ri->ret_addr;
 		if (ri->rp && ri->rp->handler) {
 			__this_cpu_write(current_kprobe, &ri->rp->kp);
-			get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
 			ri->ret_addr = correct_ret_addr;
 			ri->rp->handler(ri, regs);
-			__this_cpu_write(current_kprobe, NULL);
+			__this_cpu_write(current_kprobe, &kprobe_busy);
 		}
 
 		recycle_rp_inst(ri, &empty_rp);
@@ -788,6 +852,8 @@
 
 	kretprobe_hash_unlock(current, &flags);
 
+	kprobe_busy_end();
+
 	hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
 		hlist_del(&ri->hlist);
 		kfree(ri);
@@ -879,21 +945,6 @@
 		break;
 	}
 
-	if (p->ainsn.boostable == 0) {
-		if ((regs->ip > copy_ip) &&
-		    (regs->ip - copy_ip) + 5 < MAX_INSN_SIZE) {
-			/*
-			 * These instructions can be executed directly if it
-			 * jumps back to correct address.
-			 */
-			synthesize_reljump((void *)regs->ip,
-				(void *)orig_ip + (regs->ip - copy_ip));
-			p->ainsn.boostable = 1;
-		} else {
-			p->ainsn.boostable = -1;
-		}
-	}
-
 	regs->ip += orig_ip - copy_ip;
 
 no_change:
@@ -959,7 +1010,24 @@
 		 * normal page fault.
 		 */
 		regs->ip = (unsigned long)cur->addr;
+		/*
+		 * Trap flag (TF) has been set here because this fault
+		 * happened where the single stepping will be done.
+		 * So clear it by resetting the current kprobe:
+		 */
+		regs->flags &= ~X86_EFLAGS_TF;
+		/*
+		 * Since the single step (trap) has been cancelled,
+		 * we need to restore BTF here.
+		 */
+		restore_btf();
+
+		/*
+		 * If the TF flag was set before the kprobe hit,
+		 * don't touch it:
+		 */
 		regs->flags |= kcb->kprobe_old_flags;
+
 		if (kcb->kprobe_status == KPROBE_REENTER)
 			restore_previous_kprobe(kcb);
 		else
--- linux-4.4.0.orig/arch/x86/kernel/kprobes/ftrace.c
+++ linux-4.4.0/arch/x86/kernel/kprobes/ftrace.c
@@ -26,7 +26,7 @@
 #include "common.h"
 
 static nokprobe_inline
-int __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+void __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
 		      struct kprobe_ctlblk *kcb, unsigned long orig_ip)
 {
 	/*
@@ -41,20 +41,21 @@
 	__this_cpu_write(current_kprobe, NULL);
 	if (orig_ip)
 		regs->ip = orig_ip;
-	return 1;
 }
 
 int skip_singlestep(struct kprobe *p, struct pt_regs *regs,
 		    struct kprobe_ctlblk *kcb)
 {
-	if (kprobe_ftrace(p))
-		return __skip_singlestep(p, regs, kcb, 0);
-	else
-		return 0;
+	if (kprobe_ftrace(p)) {
+		__skip_singlestep(p, regs, kcb, 0);
+		preempt_enable_no_resched();
+		return 1;
+	}
+	return 0;
 }
 NOKPROBE_SYMBOL(skip_singlestep);
 
-/* Ftrace callback handler for kprobes */
+/* Ftrace callback handler for kprobes -- called under preepmt disabed */
 void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
 			   struct ftrace_ops *ops, struct pt_regs *regs)
 {
@@ -77,13 +78,17 @@
 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
 		regs->ip = ip + sizeof(kprobe_opcode_t);
 
+		/* To emulate trap based kprobes, preempt_disable here */
+		preempt_disable();
 		__this_cpu_write(current_kprobe, p);
 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-		if (!p->pre_handler || !p->pre_handler(p, regs))
+		if (!p->pre_handler || !p->pre_handler(p, regs)) {
 			__skip_singlestep(p, regs, kcb, orig_ip);
+			preempt_enable_no_resched();
+		}
 		/*
 		 * If pre_handler returns !0, it sets regs->ip and
-		 * resets current kprobe.
+		 * resets current kprobe, and keep preempt count +1.
 		 */
 	}
 end:
--- linux-4.4.0.orig/arch/x86/kernel/kprobes/opt.c
+++ linux-4.4.0/arch/x86/kernel/kprobes/opt.c
@@ -29,6 +29,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ftrace.h>
 
+#include <asm/text-patching.h>
 #include <asm/cacheflush.h>
 #include <asm/desc.h>
 #include <asm/pgtable.h>
@@ -36,6 +37,8 @@
 #include <asm/alternative.h>
 #include <asm/insn.h>
 #include <asm/debugreg.h>
+#include <asm/nospec-branch.h>
+#include <asm/sections.h>
 
 #include "common.h"
 
@@ -177,7 +180,7 @@
 
 	while (len < RELATIVEJUMP_SIZE) {
 		ret = __copy_instruction(dest + len, src + len);
-		if (!ret || !can_boost(dest + len))
+		if (!ret || !can_boost(dest + len, src + len))
 			return -EINVAL;
 		len += ret;
 	}
@@ -191,7 +194,7 @@
 }
 
 /* Check whether insn is indirect jump */
-static int insn_is_indirect_jump(struct insn *insn)
+static int __insn_is_indirect_jump(struct insn *insn)
 {
 	return ((insn->opcode.bytes[0] == 0xff &&
 		(X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
@@ -225,6 +228,26 @@
 	return (start <= target && target <= start + len);
 }
 
+static int insn_is_indirect_jump(struct insn *insn)
+{
+	int ret = __insn_is_indirect_jump(insn);
+
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * Jump to x86_indirect_thunk_* is treated as an indirect jump.
+	 * Note that even with CONFIG_RETPOLINE=y, the kernel compiled with
+	 * older gcc may use indirect jump. So we add this check instead of
+	 * replace indirect-jump check.
+	 */
+	if (!ret)
+		ret = insn_jump_into_range(insn,
+				(unsigned long)__indirect_thunk_start,
+				(unsigned long)__indirect_thunk_end -
+				(unsigned long)__indirect_thunk_start);
+#endif
+	return ret;
+}
+
 /* Decode whole function to ensure any instructions don't jump into target */
 static int can_optimize(unsigned long paddr)
 {
@@ -349,6 +372,7 @@
 	}
 
 	buf = (u8 *)op->optinsn.insn;
+	set_memory_rw((unsigned long)buf & PAGE_MASK, 1);
 
 	/* Copy instructions into the out-of-line buffer */
 	ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr);
@@ -371,6 +395,8 @@
 	synthesize_reljump(buf + TMPL_END_IDX + op->optinsn.size,
 			   (u8 *)op->kp.addr + op->optinsn.size);
 
+	set_memory_ro((unsigned long)buf & PAGE_MASK, 1);
+
 	flush_icache_range((unsigned long) buf,
 			   (unsigned long) buf + TMPL_END_IDX +
 			   op->optinsn.size + RELATIVEJUMP_SIZE);
--- linux-4.4.0.orig/arch/x86/kernel/kvm.c
+++ linux-4.4.0/arch/x86/kernel/kvm.c
@@ -21,7 +21,7 @@
  */
 
 #include <linux/context_tracking.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kvm_para.h>
 #include <linux/cpu.h>
@@ -151,6 +151,8 @@
 		if (hlist_unhashed(&n.link))
 			break;
 
+		rcu_irq_exit();
+
 		if (!n.halted) {
 			local_irq_enable();
 			schedule();
@@ -159,11 +161,11 @@
 			/*
 			 * We cannot reschedule. So halt.
 			 */
-			rcu_irq_exit();
 			native_safe_halt();
-			rcu_irq_enter();
 			local_irq_disable();
 		}
+
+		rcu_irq_enter();
 	}
 	if (!n.halted)
 		finish_wait(&n.wq, &wait);
--- linux-4.4.0.orig/arch/x86/kernel/kvmclock.c
+++ linux-4.4.0/arch/x86/kernel/kvmclock.c
@@ -45,6 +45,11 @@
 static struct pvclock_vsyscall_time_info *hv_clock;
 static struct pvclock_wall_clock wall_clock;
 
+struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
+{
+	return hv_clock;
+}
+
 /*
  * The wallclock is the time of day when we booted. Since then, some time may
  * have elapsed since the hypervisor wrote the data. So we try to account for
@@ -135,6 +140,7 @@
 	src = &hv_clock[cpu].pvti;
 	tsc_khz = pvclock_tsc_khz(src);
 	put_cpu();
+	setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
 	return tsc_khz;
 }
 
--- linux-4.4.0.orig/arch/x86/kernel/ldt.c
+++ linux-4.4.0/arch/x86/kernel/ldt.c
@@ -12,9 +12,11 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/syscalls.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
+#include <linux/kaiser.h>
 
 #include <asm/ldt.h>
 #include <asm/desc.h>
@@ -33,11 +35,21 @@
 	set_ldt(pc->ldt->entries, pc->ldt->size);
 }
 
+static void __free_ldt_struct(struct ldt_struct *ldt)
+{
+	if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE)
+		vfree(ldt->entries);
+	else
+		free_page((unsigned long)ldt->entries);
+	kfree(ldt);
+}
+
 /* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */
 static struct ldt_struct *alloc_ldt_struct(int size)
 {
 	struct ldt_struct *new_ldt;
 	int alloc_size;
+	int ret;
 
 	if (size > LDT_ENTRIES)
 		return NULL;
@@ -65,7 +77,13 @@
 		return NULL;
 	}
 
+	ret = kaiser_add_mapping((unsigned long)new_ldt->entries, alloc_size,
+				 __PAGE_KERNEL);
 	new_ldt->size = size;
+	if (ret) {
+		__free_ldt_struct(new_ldt);
+		return NULL;
+	}
 	return new_ldt;
 }
 
@@ -91,19 +109,17 @@
 	if (likely(!ldt))
 		return;
 
+	kaiser_remove_mapping((unsigned long)ldt->entries,
+			      ldt->size * LDT_ENTRY_SIZE);
 	paravirt_free_ldt(ldt->entries, ldt->size);
-	if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE)
-		vfree(ldt->entries);
-	else
-		free_page((unsigned long)ldt->entries);
-	kfree(ldt);
+	__free_ldt_struct(ldt);
 }
 
 /*
  * we do not have to muck with descriptors here, that is
  * done in switch_mm() as needed.
  */
-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm)
 {
 	struct ldt_struct *new_ldt;
 	struct mm_struct *old_mm;
@@ -144,7 +160,7 @@
  *
  * 64bit: Don't touch the LDT register - we're already in the next thread.
  */
-void destroy_context(struct mm_struct *mm)
+void destroy_context_ldt(struct mm_struct *mm)
 {
 	free_ldt_struct(mm->context.ldt);
 	mm->context.ldt = NULL;
@@ -271,8 +287,8 @@
 	return error;
 }
 
-asmlinkage int sys_modify_ldt(int func, void __user *ptr,
-			      unsigned long bytecount)
+SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr ,
+		unsigned long , bytecount)
 {
 	int ret = -ENOSYS;
 
@@ -290,5 +306,14 @@
 		ret = write_ldt(ptr, bytecount, 0);
 		break;
 	}
-	return ret;
+	/*
+	 * The SYSCALL_DEFINE() macros give us an 'unsigned long'
+	 * return type, but tht ABI for sys_modify_ldt() expects
+	 * 'int'.  This cast gives us an int-sized value in %rax
+	 * for the return code.  The 'unsigned' is necessary so
+	 * the compiler does not try to sign-extend the negative
+	 * return codes into the high half of the register when
+	 * taking the value from int->long.
+	 */
+	return (unsigned int)ret;
 }
--- linux-4.4.0.orig/arch/x86/kernel/livepatch.c
+++ linux-4.4.0/arch/x86/kernel/livepatch.c
@@ -20,8 +20,6 @@
 
 #include <linux/module.h>
 #include <linux/uaccess.h>
-#include <asm/cacheflush.h>
-#include <asm/page_types.h>
 #include <asm/elf.h>
 #include <asm/livepatch.h>
 
@@ -38,11 +36,10 @@
 int klp_write_module_reloc(struct module *mod, unsigned long type,
 			   unsigned long loc, unsigned long value)
 {
-	int ret, numpages, size = 4;
-	bool readonly;
+	size_t size = 4;
 	unsigned long val;
-	unsigned long core = (unsigned long)mod->module_core;
-	unsigned long core_size = mod->core_size;
+	unsigned long core = (unsigned long)mod->core_layout.base;
+	unsigned long core_size = mod->core_layout.size;
 
 	switch (type) {
 	case R_X86_64_NONE:
@@ -58,6 +55,7 @@
 		val = (s32)value;
 		break;
 	case R_X86_64_PC32:
+	case R_X86_64_PLT32:
 		val = (u32)(value - loc);
 		break;
 	default:
@@ -69,23 +67,5 @@
 		/* loc does not point to any symbol inside the module */
 		return -EINVAL;
 
-	readonly = false;
-
-#ifdef CONFIG_DEBUG_SET_MODULE_RONX
-	if (loc < core + mod->core_ro_size)
-		readonly = true;
-#endif
-
-	/* determine if the relocation spans a page boundary */
-	numpages = ((loc & PAGE_MASK) == ((loc + size) & PAGE_MASK)) ? 1 : 2;
-
-	if (readonly)
-		set_memory_rw(loc & PAGE_MASK, numpages);
-
-	ret = probe_kernel_write((void *)loc, &val, size);
-
-	if (readonly)
-		set_memory_ro(loc & PAGE_MASK, numpages);
-
-	return ret;
+	return probe_kernel_write((void *)loc, &val, size);
 }
--- linux-4.4.0.orig/arch/x86/kernel/machine_kexec_32.c
+++ linux-4.4.0/arch/x86/kernel/machine_kexec_32.c
@@ -71,12 +71,17 @@
 static void machine_kexec_free_page_tables(struct kimage *image)
 {
 	free_page((unsigned long)image->arch.pgd);
+	image->arch.pgd = NULL;
 #ifdef CONFIG_X86_PAE
 	free_page((unsigned long)image->arch.pmd0);
+	image->arch.pmd0 = NULL;
 	free_page((unsigned long)image->arch.pmd1);
+	image->arch.pmd1 = NULL;
 #endif
 	free_page((unsigned long)image->arch.pte0);
+	image->arch.pte0 = NULL;
 	free_page((unsigned long)image->arch.pte1);
+	image->arch.pte1 = NULL;
 }
 
 static int machine_kexec_alloc_page_tables(struct kimage *image)
@@ -93,7 +98,6 @@
 	    !image->arch.pmd0 || !image->arch.pmd1 ||
 #endif
 	    !image->arch.pte0 || !image->arch.pte1) {
-		machine_kexec_free_page_tables(image);
 		return -ENOMEM;
 	}
 	return 0;
--- linux-4.4.0.orig/arch/x86/kernel/machine_kexec_64.c
+++ linux-4.4.0/arch/x86/kernel/machine_kexec_64.c
@@ -37,8 +37,11 @@
 static void free_transition_pgtable(struct kimage *image)
 {
 	free_page((unsigned long)image->arch.pud);
+	image->arch.pud = NULL;
 	free_page((unsigned long)image->arch.pmd);
+	image->arch.pmd = NULL;
 	free_page((unsigned long)image->arch.pte);
+	image->arch.pte = NULL;
 }
 
 static int init_transition_pgtable(struct kimage *image, pgd_t *pgd)
@@ -79,7 +82,6 @@
 	set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC));
 	return 0;
 err:
-	free_transition_pgtable(image);
 	return result;
 }
 
@@ -519,6 +521,7 @@
 				goto overflow;
 			break;
 		case R_X86_64_PC32:
+		case R_X86_64_PLT32:
 			value -= (u64)address;
 			*(u32 *)location = value;
 			break;
--- linux-4.4.0.orig/arch/x86/kernel/mcount_64.S
+++ linux-4.4.0/arch/x86/kernel/mcount_64.S
@@ -7,7 +7,7 @@
 #include <linux/linkage.h>
 #include <asm/ptrace.h>
 #include <asm/ftrace.h>
-
+#include <asm/nospec-branch.h>
 
 	.code64
 	.section .entry.text, "ax"
@@ -180,7 +180,8 @@
 	jmp ftrace_stub
 #endif
 
-GLOBAL(ftrace_stub)
+/* This is weak to keep gas from relaxing the jumps */
+WEAK(ftrace_stub)
 	retq
 END(ftrace_caller)
 
@@ -284,8 +285,9 @@
 	 * ip and parent ip are used and the list function is called when
 	 * function tracing is enabled.
 	 */
-	call   *ftrace_trace_function
 
+	movq ftrace_trace_function, %r8
+	CALL_NOSPEC %r8
 	restore_mcount_regs
 
 	jmp fgraph_trace
@@ -328,5 +330,5 @@
 	movq 8(%rsp), %rdx
 	movq (%rsp), %rax
 	addq $24, %rsp
-	jmp *%rdi
+	JMP_NOSPEC %rdi
 #endif
--- linux-4.4.0.orig/arch/x86/kernel/module.c
+++ linux-4.4.0/arch/x86/kernel/module.c
@@ -31,6 +31,7 @@
 #include <linux/jump_label.h>
 #include <linux/random.h>
 
+#include <asm/text-patching.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/setup.h>
@@ -124,6 +125,7 @@
 			*location += sym->st_value;
 			break;
 		case R_386_PC32:
+		case R_386_PLT32:
 			/* Add the value, subtract its position */
 			*location += sym->st_value - (uint32_t)location;
 			break;
@@ -170,19 +172,28 @@
 		case R_X86_64_NONE:
 			break;
 		case R_X86_64_64:
+			if (*(u64 *)loc != 0)
+				goto invalid_relocation;
 			*(u64 *)loc = val;
 			break;
 		case R_X86_64_32:
+			if (*(u32 *)loc != 0)
+				goto invalid_relocation;
 			*(u32 *)loc = val;
 			if (val != *(u32 *)loc)
 				goto overflow;
 			break;
 		case R_X86_64_32S:
+			if (*(s32 *)loc != 0)
+				goto invalid_relocation;
 			*(s32 *)loc = val;
 			if ((s64)val != *(s32 *)loc)
 				goto overflow;
 			break;
 		case R_X86_64_PC32:
+		case R_X86_64_PLT32:
+			if (*(u32 *)loc != 0)
+				goto invalid_relocation;
 			val -= (u64)loc;
 			*(u32 *)loc = val;
 #if 0
@@ -198,6 +209,11 @@
 	}
 	return 0;
 
+invalid_relocation:
+	pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
+	       (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
+	return -ENOEXEC;
+
 overflow:
 	pr_err("overflow in relocation type %d val %Lx\n",
 	       (int)ELF64_R_TYPE(rel[i].r_info), val);
--- linux-4.4.0.orig/arch/x86/kernel/mpparse.c
+++ linux-4.4.0/arch/x86/kernel/mpparse.c
@@ -16,7 +16,6 @@
 #include <linux/mc146818rtc.h>
 #include <linux/bitops.h>
 #include <linux/acpi.h>
-#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/pci.h>
 
@@ -407,7 +406,7 @@
 	processor.apicver = mpc_default_type > 4 ? 0x10 : 0x01;
 	processor.cpuflag = CPU_ENABLED;
 	processor.cpufeature = (boot_cpu_data.x86 << 8) |
-	    (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
+	    (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_stepping;
 	processor.featureflag = boot_cpu_data.x86_capability[0];
 	processor.reserved[0] = 0;
 	processor.reserved[1] = 0;
--- linux-4.4.0.orig/arch/x86/kernel/msr.c
+++ linux-4.4.0/arch/x86/kernel/msr.c
@@ -40,7 +40,7 @@
 #include <linux/uaccess.h>
 #include <linux/gfp.h>
 
-#include <asm/processor.h>
+#include <asm/cpufeature.h>
 #include <asm/msr.h>
 
 static struct class *msr_class;
@@ -105,6 +105,9 @@
 	int err = 0;
 	ssize_t bytes = 0;
 
+	if (secure_modules())
+		return -EPERM;
+
 	if (count % 8)
 		return -EINVAL;	/* Invalid chunk size */
 
@@ -152,6 +155,10 @@
 			err = -EBADF;
 			break;
 		}
+		if (secure_modules()) {
+			err = -EPERM;
+			break;
+		}
 		if (copy_from_user(&regs, uregs, sizeof regs)) {
 			err = -EFAULT;
 			break;
--- linux-4.4.0.orig/arch/x86/kernel/nmi.c
+++ linux-4.4.0/arch/x86/kernel/nmi.c
@@ -29,6 +29,7 @@
 #include <asm/mach_traps.h>
 #include <asm/nmi.h>
 #include <asm/x86_init.h>
+#include <asm/nospec-branch.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/nmi.h>
@@ -522,6 +523,9 @@
 		write_cr2(this_cpu_read(nmi_cr2));
 	if (this_cpu_dec_return(nmi_state))
 		goto nmi_restart;
+
+	if (user_mode(regs))
+		mds_user_clear_cpu_buffers();
 }
 NOKPROBE_SYMBOL(do_nmi);
 
--- linux-4.4.0.orig/arch/x86/kernel/paravirt-spinlocks.c
+++ linux-4.4.0/arch/x86/kernel/paravirt-spinlocks.c
@@ -3,7 +3,7 @@
  * compiled in a FTRACE-compatible way.
  */
 #include <linux/spinlock.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/jump_label.h>
 
 #include <asm/paravirt.h>
--- linux-4.4.0.orig/arch/x86/kernel/paravirt.c
+++ linux-4.4.0/arch/x86/kernel/paravirt.c
@@ -19,7 +19,8 @@
 */
 
 #include <linux/errno.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/efi.h>
 #include <linux/bcd.h>
 #include <linux/highmem.h>
@@ -55,12 +56,12 @@
      ".popsection");
 
 /* identity function, which can be inlined */
-u32 _paravirt_ident_32(u32 x)
+u32 notrace _paravirt_ident_32(u32 x)
 {
 	return x;
 }
 
-u64 _paravirt_ident_64(u64 x)
+u64 notrace _paravirt_ident_64(u64 x)
 {
 	return x;
 }
@@ -97,10 +98,12 @@
 	struct branch *b = insnbuf;
 	unsigned long delta = (unsigned long)target - (addr+5);
 
-	if (tgt_clobbers & ~site_clobbers)
-		return len;	/* target would clobber too much for this site */
-	if (len < 5)
+	if (len < 5) {
+#ifdef CONFIG_RETPOLINE
+		WARN_ONCE("Failing to patch indirect CALL in %ps\n", (void *)addr);
+#endif
 		return len;	/* call too long for patch site */
+	}
 
 	b->opcode = 0xe8; /* call */
 	b->delta = delta;
@@ -115,8 +118,12 @@
 	struct branch *b = insnbuf;
 	unsigned long delta = (unsigned long)target - (addr+5);
 
-	if (len < 5)
+	if (len < 5) {
+#ifdef CONFIG_RETPOLINE
+		WARN_ONCE("Failing to patch indirect JMP in %ps\n", (void *)addr);
+#endif
 		return len;	/* call too long for patch site */
+	}
 
 	b->opcode = 0xe9;	/* jmp */
 	b->delta = delta;
@@ -162,9 +169,6 @@
 		ret = paravirt_patch_ident_64(insnbuf, len);
 
 	else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
-#ifdef CONFIG_X86_32
-		 type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
-#endif
 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
 		/* If operation requires a jmp, then jmp */
@@ -220,7 +224,6 @@
 
 /* These are in entry.S */
 extern void native_iret(void);
-extern void native_irq_enable_sysexit(void);
 extern void native_usergs_sysret32(void);
 extern void native_usergs_sysret64(void);
 
@@ -379,9 +382,6 @@
 
 	.load_sp0 = native_load_sp0,
 
-#if defined(CONFIG_X86_32)
-	.irq_enable_sysexit = native_irq_enable_sysexit,
-#endif
 #ifdef CONFIG_X86_64
 #ifdef CONFIG_IA32_EMULATION
 	.usergs_sysret32 = native_usergs_sysret32,
--- linux-4.4.0.orig/arch/x86/kernel/paravirt_patch_32.c
+++ linux-4.4.0/arch/x86/kernel/paravirt_patch_32.c
@@ -5,7 +5,6 @@
 DEF_NATIVE(pv_irq_ops, restore_fl, "push %eax; popf");
 DEF_NATIVE(pv_irq_ops, save_fl, "pushf; pop %eax");
 DEF_NATIVE(pv_cpu_ops, iret, "iret");
-DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "sti; sysexit");
 DEF_NATIVE(pv_mmu_ops, read_cr2, "mov %cr2, %eax");
 DEF_NATIVE(pv_mmu_ops, write_cr3, "mov %eax, %cr3");
 DEF_NATIVE(pv_mmu_ops, read_cr3, "mov %cr3, %eax");
@@ -46,7 +45,6 @@
 		PATCH_SITE(pv_irq_ops, restore_fl);
 		PATCH_SITE(pv_irq_ops, save_fl);
 		PATCH_SITE(pv_cpu_ops, iret);
-		PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
 		PATCH_SITE(pv_mmu_ops, read_cr2);
 		PATCH_SITE(pv_mmu_ops, read_cr3);
 		PATCH_SITE(pv_mmu_ops, write_cr3);
--- linux-4.4.0.orig/arch/x86/kernel/paravirt_patch_64.c
+++ linux-4.4.0/arch/x86/kernel/paravirt_patch_64.c
@@ -9,11 +9,9 @@
 DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax");
 DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax");
 DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3");
-DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)");
 DEF_NATIVE(pv_cpu_ops, clts, "clts");
 DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd");
 
-DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "swapgs; sti; sysexit");
 DEF_NATIVE(pv_cpu_ops, usergs_sysret64, "swapgs; sysretq");
 DEF_NATIVE(pv_cpu_ops, usergs_sysret32, "swapgs; sysretl");
 DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");
@@ -62,7 +60,6 @@
 		PATCH_SITE(pv_mmu_ops, read_cr3);
 		PATCH_SITE(pv_mmu_ops, write_cr3);
 		PATCH_SITE(pv_cpu_ops, clts);
-		PATCH_SITE(pv_mmu_ops, flush_tlb_single);
 		PATCH_SITE(pv_cpu_ops, wbinvd);
 #if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
 		case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock):
--- linux-4.4.0.orig/arch/x86/kernel/pci-calgary_64.c
+++ linux-4.4.0/arch/x86/kernel/pci-calgary_64.c
@@ -296,7 +296,7 @@
 
 	/* were we called with bad_dma_address? */
 	badend = DMA_ERROR_CODE + (EMERGENCY_PAGES * PAGE_SIZE);
-	if (unlikely((dma_addr >= DMA_ERROR_CODE) && (dma_addr < badend))) {
+	if (unlikely(dma_addr < badend)) {
 		WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA "
 		       "address 0x%Lx\n", dma_addr);
 		return;
--- linux-4.4.0.orig/arch/x86/kernel/pci-swiotlb.c
+++ linux-4.4.0/arch/x86/kernel/pci-swiotlb.c
@@ -2,7 +2,7 @@
 
 #include <linux/pci.h>
 #include <linux/cache.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/swiotlb.h>
 #include <linux/bootmem.h>
 #include <linux/dma-mapping.h>
--- linux-4.4.0.orig/arch/x86/kernel/pmem.c
+++ linux-4.4.0/arch/x86/kernel/pmem.c
@@ -3,7 +3,7 @@
  * Copyright (c) 2015, Intel Corporation.
  */
 #include <linux/platform_device.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/ioport.h>
 
 static int found(u64 start, u64 end, void *data)
--- linux-4.4.0.orig/arch/x86/kernel/process.c
+++ linux-4.4.0/arch/x86/kernel/process.c
@@ -7,7 +7,8 @@
 #include <linux/prctl.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/pm.h>
 #include <linux/tick.h>
 #include <linux/random.h>
@@ -31,6 +32,9 @@
 #include <asm/tlbflush.h>
 #include <asm/mce.h>
 #include <asm/vm86.h>
+#include <asm/spec-ctrl.h>
+
+#include "process.h"
 
 /*
  * per-CPU TSS segments. Threads are completely 'soft' on Linux,
@@ -39,7 +43,7 @@
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */
-__visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = {
+__visible DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct tss_struct, cpu_tss) = {
 	.x86_tss = {
 		.sp0 = TOP_OF_INIT_STACK,
 #ifdef CONFIG_X86_32
@@ -130,11 +134,6 @@
 	fpu__clear(&tsk->thread.fpu);
 }
 
-static void hard_disable_TSC(void)
-{
-	cr4_set_bits(X86_CR4_TSD);
-}
-
 void disable_TSC(void)
 {
 	preempt_disable();
@@ -143,15 +142,10 @@
 		 * Must flip the CPU state synchronously with
 		 * TIF_NOTSC in the current running context.
 		 */
-		hard_disable_TSC();
+		cr4_set_bits(X86_CR4_TSD);
 	preempt_enable();
 }
 
-static void hard_enable_TSC(void)
-{
-	cr4_clear_bits(X86_CR4_TSD);
-}
-
 static void enable_TSC(void)
 {
 	preempt_disable();
@@ -160,7 +154,7 @@
 		 * Must flip the CPU state synchronously with
 		 * TIF_NOTSC in the current running context.
 		 */
-		hard_enable_TSC();
+		cr4_clear_bits(X86_CR4_TSD);
 	preempt_enable();
 }
 
@@ -188,48 +182,252 @@
 	return 0;
 }
 
-void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
-		      struct tss_struct *tss)
+static inline void switch_to_bitmap(struct thread_struct *prev,
+				    struct thread_struct *next,
+				    unsigned long tifp, unsigned long tifn)
 {
-	struct thread_struct *prev, *next;
-
-	prev = &prev_p->thread;
-	next = &next_p->thread;
-
-	if (test_tsk_thread_flag(prev_p, TIF_BLOCKSTEP) ^
-	    test_tsk_thread_flag(next_p, TIF_BLOCKSTEP)) {
-		unsigned long debugctl = get_debugctlmsr();
-
-		debugctl &= ~DEBUGCTLMSR_BTF;
-		if (test_tsk_thread_flag(next_p, TIF_BLOCKSTEP))
-			debugctl |= DEBUGCTLMSR_BTF;
-
-		update_debugctlmsr(debugctl);
-	}
-
-	if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^
-	    test_tsk_thread_flag(next_p, TIF_NOTSC)) {
-		/* prev and next are different */
-		if (test_tsk_thread_flag(next_p, TIF_NOTSC))
-			hard_disable_TSC();
-		else
-			hard_enable_TSC();
-	}
+	struct tss_struct *tss = this_cpu_ptr(&cpu_tss);
 
-	if (test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
+	if (tifn & _TIF_IO_BITMAP) {
 		/*
 		 * Copy the relevant range of the IO bitmap.
 		 * Normally this is 128 bytes or less:
 		 */
 		memcpy(tss->io_bitmap, next->io_bitmap_ptr,
 		       max(prev->io_bitmap_max, next->io_bitmap_max));
-	} else if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) {
+	} else if (tifp & _TIF_IO_BITMAP) {
 		/*
 		 * Clear any possible leftover bits:
 		 */
 		memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
 	}
+}
+
+#ifdef CONFIG_SMP
+
+struct ssb_state {
+	struct ssb_state	*shared_state;
+	raw_spinlock_t		lock;
+	unsigned int		disable_state;
+	unsigned long		local_state;
+};
+
+#define LSTATE_SSB	0
+
+static DEFINE_PER_CPU(struct ssb_state, ssb_state);
+
+void speculative_store_bypass_ht_init(void)
+{
+	struct ssb_state *st = this_cpu_ptr(&ssb_state);
+	unsigned int this_cpu = smp_processor_id();
+	unsigned int cpu;
+
+	st->local_state = 0;
+
+	/*
+	 * Shared state setup happens once on the first bringup
+	 * of the CPU. It's not destroyed on CPU hotunplug.
+	 */
+	if (st->shared_state)
+		return;
+
+	raw_spin_lock_init(&st->lock);
+
+	/*
+	 * Go over HT siblings and check whether one of them has set up the
+	 * shared state pointer already.
+	 */
+	for_each_cpu(cpu, topology_sibling_cpumask(this_cpu)) {
+		if (cpu == this_cpu)
+			continue;
+
+		if (!per_cpu(ssb_state, cpu).shared_state)
+			continue;
+
+		/* Link it to the state of the sibling: */
+		st->shared_state = per_cpu(ssb_state, cpu).shared_state;
+		return;
+	}
+
+	/*
+	 * First HT sibling to come up on the core.  Link shared state of
+	 * the first HT sibling to itself. The siblings on the same core
+	 * which come up later will see the shared state pointer and link
+	 * themself to the state of this CPU.
+	 */
+	st->shared_state = st;
+}
+
+/*
+ * Logic is: First HT sibling enables SSBD for both siblings in the core
+ * and last sibling to disable it, disables it for the whole core. This how
+ * MSR_SPEC_CTRL works in "hardware":
+ *
+ *  CORE_SPEC_CTRL = THREAD0_SPEC_CTRL | THREAD1_SPEC_CTRL
+ */
+static __always_inline void amd_set_core_ssb_state(unsigned long tifn)
+{
+	struct ssb_state *st = this_cpu_ptr(&ssb_state);
+	u64 msr = x86_amd_ls_cfg_base;
+
+	if (!static_cpu_has(X86_FEATURE_ZEN)) {
+		msr |= ssbd_tif_to_amd_ls_cfg(tifn);
+		wrmsrl(MSR_AMD64_LS_CFG, msr);
+		return;
+	}
+
+	if (tifn & _TIF_SSBD) {
+		/*
+		 * Since this can race with prctl(), block reentry on the
+		 * same CPU.
+		 */
+		if (__test_and_set_bit(LSTATE_SSB, &st->local_state))
+			return;
+
+		msr |= x86_amd_ls_cfg_ssbd_mask;
+
+		raw_spin_lock(&st->shared_state->lock);
+		/* First sibling enables SSBD: */
+		if (!st->shared_state->disable_state)
+			wrmsrl(MSR_AMD64_LS_CFG, msr);
+		st->shared_state->disable_state++;
+		raw_spin_unlock(&st->shared_state->lock);
+	} else {
+		if (!__test_and_clear_bit(LSTATE_SSB, &st->local_state))
+			return;
+
+		raw_spin_lock(&st->shared_state->lock);
+		st->shared_state->disable_state--;
+		if (!st->shared_state->disable_state)
+			wrmsrl(MSR_AMD64_LS_CFG, msr);
+		raw_spin_unlock(&st->shared_state->lock);
+	}
+}
+#else
+static __always_inline void amd_set_core_ssb_state(unsigned long tifn)
+{
+	u64 msr = x86_amd_ls_cfg_base | ssbd_tif_to_amd_ls_cfg(tifn);
+
+	wrmsrl(MSR_AMD64_LS_CFG, msr);
+}
+#endif
+
+static __always_inline void amd_set_ssb_virt_state(unsigned long tifn)
+{
+	/*
+	 * SSBD has the same definition in SPEC_CTRL and VIRT_SPEC_CTRL,
+	 * so ssbd_tif_to_spec_ctrl() just works.
+	 */
+	wrmsrl(MSR_AMD64_VIRT_SPEC_CTRL, ssbd_tif_to_spec_ctrl(tifn));
+}
+
+/*
+ * Update the MSRs managing speculation control, during context switch.
+ *
+ * tifp: Previous task's thread flags
+ * tifn: Next task's thread flags
+ */
+static __always_inline void __speculation_ctrl_update(unsigned long tifp,
+						      unsigned long tifn)
+{
+	unsigned long tif_diff = tifp ^ tifn;
+	u64 msr = x86_spec_ctrl_base;
+	bool updmsr = false;
+
+	/* Handle change of TIF_SSBD depending on the mitigation method. */
+	if (static_cpu_has(X86_FEATURE_VIRT_SSBD)) {
+		if (tif_diff & _TIF_SSBD)
+			amd_set_ssb_virt_state(tifn);
+	} else if (static_cpu_has(X86_FEATURE_LS_CFG_SSBD)) {
+		if (tif_diff & _TIF_SSBD)
+			amd_set_core_ssb_state(tifn);
+	} else if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
+		   static_cpu_has(X86_FEATURE_AMD_SSBD)) {
+		updmsr |= !!(tif_diff & _TIF_SSBD);
+		msr |= ssbd_tif_to_spec_ctrl(tifn);
+	}
+
+	/* Only evaluate TIF_SPEC_IB if conditional STIBP is enabled. */
+	if (IS_ENABLED(CONFIG_SMP) &&
+	    static_branch_unlikely(&switch_to_cond_stibp)) {
+		updmsr |= !!(tif_diff & _TIF_SPEC_IB);
+		msr |= stibp_tif_to_spec_ctrl(tifn);
+	}
+
+	if (updmsr)
+		update_spec_ctrl_cond(msr);
+}
+
+static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk)
+{
+	if (test_and_clear_tsk_thread_flag(tsk, TIF_SPEC_FORCE_UPDATE)) {
+		if (task_spec_ssb_disable(tsk))
+			set_tsk_thread_flag(tsk, TIF_SSBD);
+		else
+			clear_tsk_thread_flag(tsk, TIF_SSBD);
+
+		if (task_spec_ib_disable(tsk))
+			set_tsk_thread_flag(tsk, TIF_SPEC_IB);
+		else
+			clear_tsk_thread_flag(tsk, TIF_SPEC_IB);
+	}
+	/* Return the updated threadinfo flags*/
+	return task_thread_info(tsk)->flags;
+}
+
+void speculation_ctrl_update(unsigned long tif)
+{
+	/* Forced update. Make sure all relevant TIF flags are different */
+	preempt_disable();
+	__speculation_ctrl_update(~tif, tif);
+	preempt_enable();
+}
+
+/* Called from seccomp/prctl update */
+void speculation_ctrl_update_current(void)
+{
+	preempt_disable();
+	speculation_ctrl_update(speculation_ctrl_update_tif(current));
+	preempt_enable();
+}
+
+void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p)
+{
+	struct thread_struct *prev, *next;
+	unsigned long tifp, tifn;
+
+	prev = &prev_p->thread;
+	next = &next_p->thread;
+
+	tifn = READ_ONCE(task_thread_info(next_p)->flags);
+	tifp = READ_ONCE(task_thread_info(prev_p)->flags);
+	switch_to_bitmap(prev, next, tifp, tifn);
+
 	propagate_user_return_notify(prev_p, next_p);
+
+	if ((tifp & _TIF_BLOCKSTEP || tifn & _TIF_BLOCKSTEP) &&
+	    arch_has_block_step()) {
+		unsigned long debugctl, msk;
+
+		rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
+		debugctl &= ~DEBUGCTLMSR_BTF;
+		msk = tifn & _TIF_BLOCKSTEP;
+		debugctl |= (msk >> TIF_BLOCKSTEP) << DEBUGCTLMSR_BTF_SHIFT;
+		wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
+	}
+
+	if ((tifp ^ tifn) & _TIF_NOTSC)
+		cr4_toggle_bits(X86_CR4_TSD);
+
+	if (likely(!((tifp | tifn) & _TIF_SPEC_FORCE_UPDATE))) {
+		__speculation_ctrl_update(tifp, tifn);
+	} else {
+		speculation_ctrl_update_tif(prev_p);
+		tifn = speculation_ctrl_update_tif(next_p);
+
+		/* Enforce MSR update to ensure consistent state */
+		__speculation_ctrl_update(~tifn, tifn);
+	}
 }
 
 /*
@@ -402,7 +600,7 @@
 	if (c->x86_vendor != X86_VENDOR_INTEL)
 		return 0;
 
-	if (!cpu_has(c, X86_FEATURE_MWAIT))
+	if (!cpu_has(c, X86_FEATURE_MWAIT) || static_cpu_has_bug(X86_BUG_MONITOR))
 		return 0;
 
 	return 1;
@@ -423,11 +621,17 @@
 			smp_mb(); /* quirk */
 		}
 
+		ubuntu_restrict_branch_speculation_end();
+
 		__monitor((void *)&current_thread_info()->flags, 0, 0);
-		if (!need_resched())
+
+		if (!need_resched()) {
 			__sti_mwait(0, 0);
-		else
+			ubuntu_restrict_branch_speculation_start();
+		} else {
+			ubuntu_restrict_branch_speculation_start();
 			local_irq_enable();
+		}
 		trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 	} else {
 		local_irq_enable();
--- linux-4.4.0.orig/arch/x86/kernel/process.h
+++ linux-4.4.0/arch/x86/kernel/process.h
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Code shared between 32 and 64 bit
+
+#include <asm/spec-ctrl.h>
+
+void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p);
+
+/*
+ * This needs to be inline to optimize for the common case where no extra
+ * work needs to be done.
+ */
+static inline void switch_to_extra(struct task_struct *prev,
+				   struct task_struct *next)
+{
+	unsigned long next_tif = task_thread_info(next)->flags;
+	unsigned long prev_tif = task_thread_info(prev)->flags;
+
+	if (IS_ENABLED(CONFIG_SMP)) {
+		/*
+		 * Avoid __switch_to_xtra() invocation when conditional
+		 * STIBP is disabled and the only different bit is
+		 * TIF_SPEC_IB. For CONFIG_SMP=n TIF_SPEC_IB is not
+		 * in the TIF_WORK_CTXSW masks.
+		 */
+		if (!static_branch_likely(&switch_to_cond_stibp)) {
+			prev_tif &= ~_TIF_SPEC_IB;
+			next_tif &= ~_TIF_SPEC_IB;
+		}
+	}
+
+	/*
+	 * __switch_to_xtra() handles debug registers, i/o bitmaps,
+	 * speculation mitigations etc.
+	 */
+	if (unlikely(next_tif & _TIF_WORK_CTXSW_NEXT ||
+		     prev_tif & _TIF_WORK_CTXSW_PREV))
+		__switch_to_xtra(prev, next);
+}
--- linux-4.4.0.orig/arch/x86/kernel/process_32.c
+++ linux-4.4.0/arch/x86/kernel/process_32.c
@@ -25,7 +25,7 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/mc146818rtc.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/personality.h>
@@ -55,6 +55,8 @@
 #include <asm/switch_to.h>
 #include <asm/vm86.h>
 
+#include "process.h"
+
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
 
@@ -279,12 +281,7 @@
 	if (get_kernel_rpl() && unlikely(prev->iopl != next->iopl))
 		set_iopl_mask(next->iopl);
 
-	/*
-	 * Now maybe handle debug registers and/or IO bitmaps
-	 */
-	if (unlikely(task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV ||
-		     task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT))
-		__switch_to_xtra(prev_p, next_p, tss);
+	switch_to_extra(prev_p, next_p);
 
 	/*
 	 * Leave lazy mode, flushing any hypercalls made here.
--- linux-4.4.0.orig/arch/x86/kernel/process_64.c
+++ linux-4.4.0/arch/x86/kernel/process_64.c
@@ -26,7 +26,7 @@
 #include <linux/user.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/ptrace.h>
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
@@ -48,6 +48,9 @@
 #include <asm/syscalls.h>
 #include <asm/debugreg.h>
 #include <asm/switch_to.h>
+#include <asm/xen/hypervisor.h>
+
+#include "process.h"
 
 asmlinkage extern void ret_from_fork(void);
 
@@ -125,7 +128,7 @@
 		if (dead_task->mm->context.ldt) {
 			pr_warn("WARNING: dead process %s still has LDT? <%p/%d>\n",
 				dead_task->comm,
-				dead_task->mm->context.ldt,
+				dead_task->mm->context.ldt->entries,
 				dead_task->mm->context.ldt->size);
 			BUG();
 		}
@@ -249,6 +252,7 @@
 	start_thread_common(regs, new_ip, new_sp,
 			    __USER_CS, __USER_DS, 0);
 }
+EXPORT_SYMBOL_GPL(start_thread);
 
 #ifdef CONFIG_COMPAT
 void compat_start_thread(struct pt_regs *regs, u32 new_ip, u32 new_sp)
@@ -404,12 +408,18 @@
 	/* Reload esp0 and ss1.  This changes current_thread_info(). */
 	load_sp0(tss, next);
 
+	switch_to_extra(prev_p, next_p);
+
+#ifdef CONFIG_XEN
 	/*
-	 * Now maybe reload the debug registers and handle I/O bitmaps
+	 * On Xen PV, IOPL bits in pt_regs->flags have no effect, and
+	 * current_pt_regs()->flags may not match the current task's
+	 * intended IOPL.  We need to switch it manually.
 	 */
-	if (unlikely(task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT ||
-		     task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV))
-		__switch_to_xtra(prev_p, next_p, tss);
+	if (unlikely(static_cpu_has(X86_FEATURE_XENPV) &&
+		     prev->iopl != next->iopl))
+		xen_set_iopl_mask(next->iopl);
+#endif
 
 	if (static_cpu_has_bug(X86_BUG_SYSRET_SS_ATTRS)) {
 		/*
--- linux-4.4.0.orig/arch/x86/kernel/ptrace.c
+++ linux-4.4.0/arch/x86/kernel/ptrace.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/export.h>
 #include <linux/context_tracking.h>
+#include <linux/nospec.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -188,8 +189,8 @@
 		return sp;
 
 	prev_esp = (u32 *)(context);
-	if (prev_esp)
-		return (unsigned long)prev_esp;
+	if (*prev_esp)
+		return (unsigned long)*prev_esp;
 
 	return (unsigned long)regs;
 }
@@ -699,7 +700,8 @@
 	unsigned long val = 0;
 
 	if (n < HBP_NUM) {
-		struct perf_event *bp = thread->ptrace_bps[n];
+		int index = array_index_nospec(n, HBP_NUM);
+		struct perf_event *bp = thread->ptrace_bps[index];
 
 		if (bp)
 			val = bp->hw.info.address;
--- linux-4.4.0.orig/arch/x86/kernel/pvclock.c
+++ linux-4.4.0/arch/x86/kernel/pvclock.c
@@ -66,6 +66,8 @@
 
 	do {
 		version = __pvclock_read_cycles(src, &ret, &flags);
+		/* Make sure that the version double-check is last. */
+		smp_rmb();
 	} while ((src->version & 1) || version != src->version);
 
 	return flags & valid_flags;
@@ -80,6 +82,8 @@
 
 	do {
 		version = __pvclock_read_cycles(src, &ret, &flags);
+		/* Make sure that the version double-check is last. */
+		smp_rmb();
 	} while ((src->version & 1) || version != src->version);
 
 	if (unlikely((flags & PVCLOCK_GUEST_STOPPED) != 0)) {
--- linux-4.4.0.orig/arch/x86/kernel/reboot.c
+++ linux-4.4.0/arch/x86/kernel/reboot.c
@@ -1,6 +1,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/pm.h>
@@ -30,6 +30,7 @@
 #include <asm/realmode.h>
 #include <asm/x86_init.h>
 #include <asm/efi.h>
+#include <asm/nospec-branch.h>
 
 /*
  * Power off function, if any
@@ -55,6 +56,19 @@
  */
 
 /*
+ * Some machines require the "reboot=a" commandline options
+ */
+static int __init set_acpi_reboot(const struct dmi_system_id *d)
+{
+	if (reboot_type != BOOT_ACPI) {
+		reboot_type = BOOT_ACPI;
+		pr_info("%s series board detected. Selecting %s-method for reboots.\n",
+			d->ident, "ACPI");
+	}
+	return 0;
+}
+
+/*
  * Some machines require the "reboot=b" or "reboot=k"  commandline options,
  * this quirk makes that automatic.
  */
@@ -93,15 +107,19 @@
 	load_cr3(initial_page_table);
 #else
 	write_cr3(real_mode_header->trampoline_pgd);
+
+	/* Exiting long mode will fail if CR4.PCIDE is set. */
+	if (static_cpu_has(X86_FEATURE_PCID))
+		cr4_clear_bits(X86_CR4_PCIDE);
 #endif
 
 	/* Jump to the identity-mapped low memory code */
 #ifdef CONFIG_X86_32
-	asm volatile("jmpl *%0" : :
+	asm volatile(ANNOTATE_RETPOLINE_SAFE "jmpl *%0" : :
 		     "rm" (real_mode_header->machine_real_restart_asm),
 		     "a" (type));
 #else
-	asm volatile("ljmpl *%0" : :
+	asm volatile(ANNOTATE_RETPOLINE_SAFE "ljmpl *%0" : :
 		     "m" (real_mode_header->machine_real_restart_asm),
 		     "D" (type));
 #endif
@@ -158,6 +176,14 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
 		},
 	},
+	{	/* Handle problems with rebooting on Apple MacBook6,1 */
+		.callback = set_pci_reboot,
+		.ident = "Apple MacBook6,1",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"),
+		},
+	},
 	{	/* Handle problems with rebooting on Apple MacBookPro5 */
 		.callback = set_pci_reboot,
 		.ident = "Apple MacBookPro5",
@@ -182,6 +208,14 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
 		},
 	},
+	{	/* Handle problems with rebooting on the iMac10,1. */
+		.callback = set_pci_reboot,
+		.ident = "Apple iMac10,1",
+		.matches = {
+		    DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+		    DMI_MATCH(DMI_PRODUCT_NAME, "iMac10,1"),
+		},
+	},
 
 	/* ASRock */
 	{	/* Handle problems with rebooting on ASRock Q1900DC-ITX */
@@ -387,6 +421,14 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
 		},
 	},
+	{	/* Handle problems with rebooting on Dell Optiplex 7450 AIO */
+		.callback = set_acpi_reboot,
+		.ident = "Dell OptiPlex 7450 AIO",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 7450 AIO"),
+		},
+	},
 
 	/* Hewlett-Packard */
 	{	/* Handle problems with rebooting on HP laptops */
@@ -398,6 +440,15 @@
 		},
 	},
 
+	{	/* PCIe Wifi card isn't detected after reboot otherwise */
+		.callback = set_pci_reboot,
+		.ident = "Zotac ZBOX CI327 nano",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "NA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ZBOX-CI327NANO-GS-01"),
+		},
+	},
+
 	/* Sony */
 	{	/* Handle problems with rebooting on Sony VGN-Z540N */
 		.callback = set_bios_reboot,
@@ -407,7 +458,46 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
 		},
 	},
-
+	{	/* Handle problems with rebooting on the Latitude E6520. */
+		.callback = set_pci_reboot,
+		.ident = "Dell Latitude E6520",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6520"),
+		},
+	},
+	{       /* Handle problems with rebooting on the OptiPlex 790. */
+		.callback = set_pci_reboot,
+		.ident = "Dell OptiPlex 790",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 790"),
+		},
+	},
+	{	/* Handle problems with rebooting on the OptiPlex 990. */
+		.callback = set_pci_reboot,
+		.ident = "Dell OptiPlex 990",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
+		},
+	},
+	{       /* Handle problems with rebooting on the Latitude E6220. */
+		.callback = set_pci_reboot,
+		.ident = "Dell Latitude E6220",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6220"),
+		},
+	},
+	{	/* Handle problems with rebooting on the OptiPlex 390. */
+		.callback = set_pci_reboot,
+		.ident = "Dell OptiPlex 390",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 390"),
+		},
+	},
 	{ }
 };
 
@@ -459,29 +549,20 @@
 	local_irq_disable();
 
 	/*
-	 * We need to disable VMX on all CPUs before rebooting, otherwise
-	 * we risk hanging up the machine, because the CPU ignore INIT
-	 * signals when VMX is enabled.
-	 *
-	 * We can't take any locks and we may be on an inconsistent
-	 * state, so we use NMIs as IPIs to tell the other CPUs to disable
-	 * VMX and halt.
+	 * Disable VMX on all CPUs before rebooting, otherwise we risk hanging
+	 * the machine, because the CPU blocks INIT when it's in VMX root.
 	 *
-	 * For safety, we will avoid running the nmi_shootdown_cpus()
-	 * stuff unnecessarily, but we don't have a way to check
-	 * if other CPUs have VMX enabled. So we will call it only if the
-	 * CPU we are running on has VMX enabled.
+	 * We can't take any locks and we may be on an inconsistent state, so
+	 * use NMIs as IPIs to tell the other CPUs to exit VMX root and halt.
 	 *
-	 * We will miss cases where VMX is not enabled on all CPUs. This
-	 * shouldn't do much harm because KVM always enable VMX on all
-	 * CPUs anyway. But we can miss it on the small window where KVM
-	 * is still enabling VMX.
+	 * Do the NMI shootdown even if VMX if off on _this_ CPU, as that
+	 * doesn't prevent a different CPU from being in VMX root operation.
 	 */
-	if (cpu_has_vmx() && cpu_vmx_enabled()) {
-		/* Disable VMX on this CPU. */
-		cpu_vmxoff();
+	if (cpu_has_vmx()) {
+		/* Safely force _this_ CPU out of VMX root operation. */
+		__cpu_emergency_vmxoff();
 
-		/* Halt and disable VMX on the other CPUs */
+		/* Halt and exit VMX root operation on the other CPUs. */
 		nmi_shootdown_cpus(vmxoff_nmi);
 
 	}
--- linux-4.4.0.orig/arch/x86/kernel/relocate_kernel_32.S
+++ linux-4.4.0/arch/x86/kernel/relocate_kernel_32.S
@@ -10,6 +10,7 @@
 #include <asm/page_types.h>
 #include <asm/kexec.h>
 #include <asm/processor-flags.h>
+#include <asm/nospec-branch.h>
 
 /*
  * Must be relocatable PIC code callable as a C function
@@ -167,6 +168,7 @@
 	movl	CP_PA_SWAP_PAGE(%edi), %esp
 	addl	$PAGE_SIZE, %esp
 2:
+	ANNOTATE_RETPOLINE_SAFE
 	call	*%edx
 
 	/* get the re-entry point of the peer system */
--- linux-4.4.0.orig/arch/x86/kernel/relocate_kernel_64.S
+++ linux-4.4.0/arch/x86/kernel/relocate_kernel_64.S
@@ -11,6 +11,7 @@
 #include <asm/kexec.h>
 #include <asm/processor-flags.h>
 #include <asm/pgtable_types.h>
+#include <asm/nospec-branch.h>
 
 /*
  * Must be relocatable PIC code callable as a C function
@@ -172,6 +173,7 @@
 1:
 	popq	%rdx
 	leaq	PAGE_SIZE(%r10), %rsp
+	ANNOTATE_RETPOLINE_SAFE
 	call	*%rdx
 
 	/* get the re-entry point of the peer system */
--- linux-4.4.0.orig/arch/x86/kernel/setup.c
+++ linux-4.4.0/arch/x86/kernel/setup.c
@@ -36,7 +36,7 @@
 #include <linux/console.h>
 #include <linux/root_dev.h>
 #include <linux/highmem.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/efi.h>
 #include <linux/init.h>
 #include <linux/edd.h>
@@ -112,6 +112,7 @@
 #include <asm/alternative.h>
 #include <asm/prom.h>
 #include <asm/microcode.h>
+#include <asm/kaiser.h>
 
 /*
  * max_low_pfn_mapped: highest direct mapped pfn under 4GB
@@ -850,6 +851,12 @@
 	memblock_reserve(__pa_symbol(_text),
 			 (unsigned long)__bss_stop - (unsigned long)_text);
 
+	/*
+	 * Make sure page 0 is always reserved because on systems with
+	 * L1TF its contents can be leaked to user processes.
+	 */
+	memblock_reserve(0, PAGE_SIZE);
+
 	early_reserve_initrd();
 
 	/*
@@ -892,6 +899,8 @@
 
 	early_trap_init();
 	early_cpu_init();
+	arch_init_ideal_nops();
+	jump_label_init();
 	early_ioremap_init();
 
 	setup_olpc_ofw_pgd();
@@ -1016,6 +1025,12 @@
 	 */
 	init_hypervisor_platform();
 
+	/*
+	 * This needs to happen right after XENPV is set on xen and
+	 * kaiser_enabled is checked below in cleanup_highmap().
+	 */
+	kaiser_check_boottime_disable();
+
 	x86_init.resources.probe_roms();
 
 	/* after parse_early_param, so could debug it */
@@ -1048,6 +1063,13 @@
 	if (mtrr_trim_uncached_memory(max_pfn))
 		max_pfn = e820_end_of_ram_pfn();
 
+	/*
+	 * This call is required when the CPU does not support PAT. If
+	 * mtrr_bp_init() invoked it already via pat_init() the call has no
+	 * effect.
+	 */
+	init_cache_modes();
+
 #ifdef CONFIG_X86_32
 	/* max_low_pfn get updated here */
 	find_low_pfn_range();
@@ -1143,6 +1165,19 @@
 
 	io_delay_init();
 
+#ifdef CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE
+	if (boot_params.secure_boot == EFI_SECURE_BOOT) {
+		set_bit(EFI_SECURE_BOOT, &efi.flags);
+		enforce_signed_modules();
+		pr_info("Secure boot enabled\n");
+	}
+	else if (boot_params.secure_boot == EFI_MOKSBSTATE_DISABLED) {
+		set_bit(EFI_MOKSBSTATE_DISABLED, &efi.flags);
+		boot_params.secure_boot = 0;
+		pr_info("Secure boot MOKSBState disabled\n");
+    }
+#endif
+
 	/*
 	 * Parse the ACPI tables for possible boot-time SMP configuration.
 	 */
@@ -1242,8 +1277,6 @@
 
 	mcheck_init();
 
-	arch_init_ideal_nops();
-
 	register_refined_jiffies(CLOCK_TICK_RATE);
 
 #ifdef CONFIG_EFI
--- linux-4.4.0.orig/arch/x86/kernel/smp.c
+++ linux-4.4.0/arch/x86/kernel/smp.c
@@ -176,6 +176,12 @@
 	irq_exit();
 }
 
+static int register_stop_handler(void)
+{
+	return register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
+				    NMI_FLAG_FIRST, "smp_stop");
+}
+
 static void native_stop_other_cpus(int wait)
 {
 	unsigned long flags;
@@ -209,39 +215,41 @@
 		apic->send_IPI_allbutself(REBOOT_VECTOR);
 
 		/*
-		 * Don't wait longer than a second if the caller
-		 * didn't ask us to wait.
+		 * Don't wait longer than a second for IPI completion. The
+		 * wait request is not checked here because that would
+		 * prevent an NMI shutdown attempt in case that not all
+		 * CPUs reach shutdown state.
 		 */
 		timeout = USEC_PER_SEC;
-		while (num_online_cpus() > 1 && (wait || timeout--))
+		while (num_online_cpus() > 1 && timeout--)
 			udelay(1);
 	}
-	
-	/* if the REBOOT_VECTOR didn't work, try with the NMI */
-	if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi))  {
-		if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
-					 NMI_FLAG_FIRST, "smp_stop"))
-			/* Note: we ignore failures here */
-			/* Hope the REBOOT_IRQ is good enough */
-			goto finish;
-
-		/* sync above data before sending IRQ */
-		wmb();
 
-		pr_emerg("Shutting down cpus with NMI\n");
+	/* if the REBOOT_VECTOR didn't work, try with the NMI */
+	if (num_online_cpus() > 1) {
+		/*
+		 * If NMI IPI is enabled, try to register the stop handler
+		 * and send the IPI. In any case try to wait for the other
+		 * CPUs to stop.
+		 */
+		if (!smp_no_nmi_ipi && !register_stop_handler()) {
+			/* Sync above data before sending IRQ */
+			wmb();
 
-		apic->send_IPI_allbutself(NMI_VECTOR);
+			pr_emerg("Shutting down cpus with NMI\n");
 
+			apic->send_IPI_allbutself(NMI_VECTOR);
+		}
 		/*
-		 * Don't wait longer than a 10 ms if the caller
-		 * didn't ask us to wait.
+		 * Don't wait longer than 10 ms if the caller didn't
+		 * reqeust it. If wait is true, the machine hangs here if
+		 * one or more CPUs do not reach shutdown state.
 		 */
 		timeout = USEC_PER_MSEC * 10;
 		while (num_online_cpus() > 1 && (wait || timeout--))
 			udelay(1);
 	}
 
-finish:
 	local_irq_save(flags);
 	disable_local_APIC();
 	mcheck_cpu_clear(this_cpu_ptr(&cpu_info));
@@ -261,6 +269,7 @@
 {
 	ack_APIC_irq();
 	__smp_reschedule_interrupt();
+	kvm_set_cpu_l1tf_flush_l1d();
 	/*
 	 * KVM uses this interrupt to force a cpu out of guest mode
 	 */
--- linux-4.4.0.orig/arch/x86/kernel/smpboot.c
+++ linux-4.4.0/arch/x86/kernel/smpboot.c
@@ -43,7 +43,7 @@
 
 #include <linux/init.h>
 #include <linux/smp.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/percpu.h>
 #include <linux/bootmem.h>
@@ -53,6 +53,7 @@
 #include <linux/stackprotector.h>
 #include <linux/gfp.h>
 #include <linux/cpuidle.h>
+#include <linux/irq.h>
 
 #include <asm/acpi.h>
 #include <asm/desc.h>
@@ -75,6 +76,10 @@
 #include <asm/i8259.h>
 #include <asm/realmode.h>
 #include <asm/misc.h>
+#include <asm/intel-family.h>
+#include <asm/cpu_device_id.h>
+#include <asm/spec-ctrl.h>
+#include <asm/microcode.h>
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
@@ -97,6 +102,18 @@
 DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
 EXPORT_PER_CPU_SYMBOL(cpu_info);
 
+/* Logical package management. We might want to allocate that dynamically */
+static int *physical_to_logical_pkg __read_mostly;
+static unsigned long *physical_package_map __read_mostly;;
+static unsigned int max_physical_pkg_id __read_mostly;
+unsigned int __max_logical_packages __read_mostly;
+EXPORT_SYMBOL(__max_logical_packages);
+static unsigned int logical_packages __read_mostly;
+static bool logical_packages_frozen __read_mostly;
+
+/* Maximum number of SMT threads on any online core */
+int __max_smt_threads __read_mostly;
+
 static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
 {
 	unsigned long flags;
@@ -104,14 +121,10 @@
 	spin_lock_irqsave(&rtc_lock, flags);
 	CMOS_WRITE(0xa, 0xf);
 	spin_unlock_irqrestore(&rtc_lock, flags);
-	local_flush_tlb();
-	pr_debug("1.\n");
 	*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) =
 							start_eip >> 4;
-	pr_debug("2.\n");
 	*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) =
 							start_eip & 0xf;
-	pr_debug("3.\n");
 }
 
 static inline void smpboot_restore_warm_reset_vector(void)
@@ -119,11 +132,6 @@
 	unsigned long flags;
 
 	/*
-	 * Install writable page 0 entry to set BIOS data area.
-	 */
-	local_flush_tlb();
-
-	/*
 	 * Paranoid:  Set warm reset code and vector here back
 	 * to default values.
 	 */
@@ -226,6 +234,8 @@
 	 */
 	check_tsc_sync_target();
 
+	speculative_store_bypass_ht_init();
+
 	/*
 	 * Lock vector_lock and initialize the vectors on this cpu
 	 * before setting the cpu online. We must set it online with
@@ -249,6 +259,146 @@
 
 	wmb();
 	cpu_startup_entry(CPUHP_ONLINE);
+
+	/*
+	 * Prevent tail call to cpu_startup_entry() because the stack protector
+	 * guard has been changed a couple of function calls up, in
+	 * boot_init_stack_canary() and must not be checked before tail calling
+	 * another function.
+	 */
+	prevent_tail_call_optimization();
+}
+
+int topology_update_package_map(unsigned int apicid, unsigned int cpu)
+{
+	unsigned int new, pkg = apicid >> boot_cpu_data.x86_coreid_bits;
+
+	/* Called from early boot ? */
+	if (!physical_package_map)
+		return 0;
+
+	if (pkg >= max_physical_pkg_id)
+		return -EINVAL;
+
+	/* Set the logical package id */
+	if (test_and_set_bit(pkg, physical_package_map))
+		goto found;
+
+	if (logical_packages_frozen) {
+		physical_to_logical_pkg[pkg] = -1;
+		pr_warn("APIC(%x) Package %u exceeds logical package max\n",
+			apicid, pkg);
+		return -ENOSPC;
+	}
+
+	new = logical_packages++;
+	pr_info("APIC(%x) Converting physical %u to logical package %u\n",
+		apicid, pkg, new);
+	physical_to_logical_pkg[pkg] = new;
+
+found:
+	cpu_data(cpu).logical_proc_id = physical_to_logical_pkg[pkg];
+	return 0;
+}
+
+/**
+ * topology_is_primary_thread - Check whether CPU is the primary SMT thread
+ * @cpu:	CPU to check
+ */
+bool topology_is_primary_thread(unsigned int cpu)
+{
+	return apic_id_is_primary_thread(per_cpu(x86_cpu_to_apicid, cpu));
+}
+
+/**
+ * topology_smt_supported - Check whether SMT is supported by the CPUs
+ */
+bool topology_smt_supported(void)
+{
+	return smp_num_siblings > 1;
+}
+
+/**
+ * topology_phys_to_logical_pkg - Map a physical package id to a logical
+ *
+ * Returns logical package id or -1 if not found
+ */
+int topology_phys_to_logical_pkg(unsigned int phys_pkg)
+{
+	if (phys_pkg >= max_physical_pkg_id)
+		return -1;
+	return physical_to_logical_pkg[phys_pkg];
+}
+EXPORT_SYMBOL(topology_phys_to_logical_pkg);
+
+static void __init smp_init_package_map(void)
+{
+	unsigned int ncpus, cpu;
+	size_t size;
+
+	/*
+	 * Today neither Intel nor AMD support heterogenous systems. That
+	 * might change in the future....
+	 *
+	 * While ideally we'd want '* smp_num_siblings' in the below @ncpus
+	 * computation, this won't actually work since some Intel BIOSes
+	 * report inconsistent HT data when they disable HT.
+	 *
+	 * In particular, they reduce the APIC-IDs to only include the cores,
+	 * but leave the CPUID topology to say there are (2) siblings.
+	 * This means we don't know how many threads there will be until
+	 * after the APIC enumeration.
+	 *
+	 * By not including this we'll sometimes over-estimate the number of
+	 * logical packages by the amount of !present siblings, but this is
+	 * still better than MAX_LOCAL_APIC.
+	 *
+	 * We use total_cpus not nr_cpu_ids because nr_cpu_ids can be limited
+	 * on the command line leading to a similar issue as the HT disable
+	 * problem because the hyperthreads are usually enumerated after the
+	 * primary cores.
+	 */
+	ncpus = boot_cpu_data.x86_max_cores;
+	if (!ncpus) {
+		pr_warn("x86_max_cores == zero !?!?");
+		ncpus = 1;
+	}
+
+	__max_logical_packages = DIV_ROUND_UP(total_cpus, ncpus);
+	logical_packages = 0;
+
+	/*
+	 * Possibly larger than what we need as the number of apic ids per
+	 * package can be smaller than the actual used apic ids.
+	 */
+	max_physical_pkg_id = DIV_ROUND_UP(MAX_LOCAL_APIC, ncpus);
+	size = max_physical_pkg_id * sizeof(unsigned int);
+	physical_to_logical_pkg = kmalloc(size, GFP_KERNEL);
+	memset(physical_to_logical_pkg, 0xff, size);
+	size = BITS_TO_LONGS(max_physical_pkg_id) * sizeof(unsigned long);
+	physical_package_map = kzalloc(size, GFP_KERNEL);
+
+	for_each_present_cpu(cpu) {
+		unsigned int apicid = apic->cpu_present_to_apicid(cpu);
+
+		if (apicid == BAD_APICID || !apic->apic_id_valid(apicid))
+			continue;
+		if (!topology_update_package_map(apicid, cpu))
+			continue;
+		pr_warn("CPU %u APICId %x disabled\n", cpu, apicid);
+		per_cpu(x86_bios_cpu_apicid, cpu) = BAD_APICID;
+		set_cpu_possible(cpu, false);
+		set_cpu_present(cpu, false);
+	}
+
+	if (logical_packages > __max_logical_packages) {
+		pr_warn("Detected more packages (%u), then computed by BIOS data (%u).\n",
+			logical_packages, __max_logical_packages);
+		logical_packages_frozen = true;
+		__max_logical_packages  = logical_packages;
+	}
+
+	pr_info("Max logical packages: %u\n", __max_logical_packages);
 }
 
 void __init smp_store_boot_cpu_info(void)
@@ -258,6 +408,7 @@
 
 	*c = boot_cpu_data;
 	c->cpu_index = id;
+	smp_init_package_map();
 }
 
 /*
@@ -304,7 +455,7 @@
 
 static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
 {
-	if (cpu_has_topoext) {
+	if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
 		int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
 
 		if (c->phys_proc_id == o->phys_proc_id &&
@@ -320,15 +471,47 @@
 	return false;
 }
 
+/*
+ * Define snc_cpu[] for SNC (Sub-NUMA Cluster) CPUs.
+ *
+ * These are Intel CPUs that enumerate an LLC that is shared by
+ * multiple NUMA nodes. The LLC on these systems is shared for
+ * off-package data access but private to the NUMA node (half
+ * of the package) for on-package access.
+ *
+ * CPUID (the source of the information about the LLC) can only
+ * enumerate the cache as being shared *or* unshared, but not
+ * this particular configuration. The CPU in this case enumerates
+ * the cache to be shared across the entire package (spanning both
+ * NUMA nodes).
+ */
+
+static const struct x86_cpu_id snc_cpu[] = {
+	{ X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_X },
+	{}
+};
+
 static bool match_llc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
 {
 	int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
 
-	if (per_cpu(cpu_llc_id, cpu1) != BAD_APICID &&
-	    per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2))
-		return topology_sane(c, o, "llc");
+	/* Do not match if we do not have a valid APICID for cpu: */
+	if (per_cpu(cpu_llc_id, cpu1) == BAD_APICID)
+		return false;
 
-	return false;
+	/* Do not match if LLC id does not match: */
+	if (per_cpu(cpu_llc_id, cpu1) != per_cpu(cpu_llc_id, cpu2))
+		return false;
+
+	/*
+	 * Allow the SNC topology without warning. Return of false
+	 * means 'c' does not share the LLC of 'o'. This will be
+	 * reflected to userspace.
+	 */
+	if (!topology_same_node(c, o) && x86_match_cpu(snc_cpu))
+		return false;
+
+	return topology_sane(c, o, "llc");
 }
 
 /*
@@ -375,7 +558,7 @@
 	bool has_mp = has_smt || boot_cpu_data.x86_max_cores > 1;
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
 	struct cpuinfo_x86 *o;
-	int i;
+	int i, threads;
 
 	cpumask_set_cpu(cpu, cpu_sibling_setup_mask);
 
@@ -432,6 +615,10 @@
 		if (match_die(c, o) && !topology_same_node(c, o))
 			primarily_use_numa_for_topology();
 	}
+
+	threads = cpumask_weight(topology_sibling_cpumask(cpu));
+	if (threads > __max_smt_threads)
+		__max_smt_threads = threads;
 }
 
 /* maps the cpu to the sched domain representing multi-core */
@@ -1218,6 +1405,8 @@
 	set_mtrr_aps_delayed_init();
 
 	smp_quirk_init_udelay();
+
+	speculative_store_bypass_ht_init();
 }
 
 void arch_enable_nonboot_cpus_begin(void)
@@ -1330,6 +1519,21 @@
 
 #ifdef CONFIG_HOTPLUG_CPU
 
+/* Recompute SMT state for all CPUs on offline */
+static void recompute_smt_state(void)
+{
+	int max_threads, cpu;
+
+	max_threads = 0;
+	for_each_online_cpu (cpu) {
+		int threads = cpumask_weight(topology_sibling_cpumask(cpu));
+
+		if (threads > max_threads)
+			max_threads = threads;
+	}
+	__max_smt_threads = max_threads;
+}
+
 static void remove_siblinginfo(int cpu)
 {
 	int sibling;
@@ -1353,7 +1557,9 @@
 	cpumask_clear(topology_core_cpumask(cpu));
 	c->phys_proc_id = 0;
 	c->cpu_core_id = 0;
+	c->booted_cores = 0;
 	cpumask_clear_cpu(cpu, cpu_sibling_setup_mask);
+	recompute_smt_state();
 }
 
 static void remove_cpu_from_maps(int cpu)
@@ -1451,6 +1657,8 @@
 	void *mwait_ptr;
 	int i;
 
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+		return;
 	if (!this_cpu_has(X86_FEATURE_MWAIT))
 		return;
 	if (!this_cpu_has(X86_FEATURE_CLFLUSH))
@@ -1511,7 +1719,7 @@
 	}
 }
 
-static inline void hlt_play_dead(void)
+void hlt_play_dead(void)
 {
 	if (__this_cpu_read(cpu_info.x86) >= 4)
 		wbinvd();
@@ -1531,9 +1739,13 @@
 	play_dead_common();
 	tboot_shutdown(TB_SHUTDOWN_WFS);
 
+	ubuntu_restrict_branch_speculation_end();
+
 	mwait_play_dead();	/* Only returns on failure */
 	if (cpuidle_play_dead())
 		hlt_play_dead();
+
+	ubuntu_restrict_branch_speculation_start();
 }
 
 #else /* ... !CONFIG_HOTPLUG_CPU */
--- linux-4.4.0.orig/arch/x86/kernel/stacktrace.c
+++ linux-4.4.0/arch/x86/kernel/stacktrace.c
@@ -5,7 +5,7 @@
  */
 #include <linux/sched.h>
 #include <linux/stacktrace.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/uaccess.h>
 #include <asm/stacktrace.h>
 
--- linux-4.4.0.orig/arch/x86/kernel/sys_x86_64.c
+++ linux-4.4.0/arch/x86/kernel/sys_x86_64.c
@@ -143,7 +143,7 @@
 		addr = PAGE_ALIGN(addr);
 		vma = find_vma(mm, addr);
 		if (end - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
@@ -186,7 +186,7 @@
 		addr = PAGE_ALIGN(addr);
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-				(!vma || addr + len <= vma->vm_start))
+				(!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
--- linux-4.4.0.orig/arch/x86/kernel/sysfb_efi.c
+++ linux-4.4.0/arch/x86/kernel/sysfb_efi.c
@@ -106,14 +106,24 @@
 					continue;
 				for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 					resource_size_t start, end;
+					unsigned long flags;
+
+					flags = pci_resource_flags(dev, i);
+					if (!(flags & IORESOURCE_MEM))
+						continue;
+
+					if (flags & IORESOURCE_UNSET)
+						continue;
+
+					if (pci_resource_len(dev, i) == 0)
+						continue;
 
 					start = pci_resource_start(dev, i);
-					if (start == 0)
-						break;
 					end = pci_resource_end(dev, i);
 					if (screen_info.lfb_base >= start &&
 					    screen_info.lfb_base < end) {
 						found_bar = 1;
+						break;
 					}
 				}
 			}
@@ -206,9 +216,55 @@
 	{},
 };
 
+/*
+ * Some devices have a portrait LCD but advertise a landscape resolution (and
+ * pitch). We simply swap width and height for these devices so that we can
+ * correctly deal with some of them coming with multiple resolutions.
+ */
+static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
+	{
+		/*
+		 * Lenovo MIIX310-10ICR, only some batches have the troublesome
+		 * 800x1280 portrait screen. Luckily the portrait version has
+		 * its own BIOS version, so we match on that.
+		 */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"),
+			DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1HCN44WW"),
+		},
+	},
+	{
+		/* Lenovo MIIX 320-10ICR with 800x1280 portrait screen */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
+					"Lenovo MIIX 320-10ICR"),
+		},
+	},
+	{
+		/* Lenovo D330 with 800x1280 or 1200x1920 portrait screen */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
+					"Lenovo ideapad D330-10IGM"),
+		},
+	},
+	{},
+};
+
 __init void sysfb_apply_efi_quirks(void)
 {
 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
 	    !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
 		dmi_check_system(efifb_dmi_system_table);
+
+	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI &&
+	    dmi_check_system(efifb_dmi_swap_width_height)) {
+		u16 temp = screen_info.lfb_width;
+
+		screen_info.lfb_width = screen_info.lfb_height;
+		screen_info.lfb_height = temp;
+		screen_info.lfb_linelength = 4 * screen_info.lfb_width;
+	}
 }
--- linux-4.4.0.orig/arch/x86/kernel/tboot.c
+++ linux-4.4.0/arch/x86/kernel/tboot.c
@@ -140,6 +140,16 @@
 		return -1;
 	set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot));
 	pte_unmap(pte);
+
+	/*
+	 * PTI poisons low addresses in the kernel page tables in the
+	 * name of making them unusable for userspace.  To execute
+	 * code at such a low address, the poison must be cleared.
+	 *
+	 * Note: 'pgd' actually gets set in pud_alloc().
+	 */
+	pgd->pgd &= ~_PAGE_NX;
+
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/x86/kernel/time.c
+++ linux-4.4.0/arch/x86/kernel/time.c
@@ -11,6 +11,7 @@
 
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/i8253.h>
 #include <linux/time.h>
 #include <linux/export.h>
@@ -22,10 +23,6 @@
 #include <asm/hpet.h>
 #include <asm/time.h>
 
-#ifdef CONFIG_X86_64
-__visible volatile unsigned long jiffies __cacheline_aligned = INITIAL_JIFFIES;
-#endif
-
 unsigned long profile_pc(struct pt_regs *regs)
 {
 	unsigned long pc = instruction_pointer(regs);
--- linux-4.4.0.orig/arch/x86/kernel/tls.c
+++ linux-4.4.0/arch/x86/kernel/tls.c
@@ -4,6 +4,7 @@
 #include <linux/user.h>
 #include <linux/regset.h>
 #include <linux/syscalls.h>
+#include <linux/nospec.h>
 
 #include <asm/uaccess.h>
 #include <asm/desc.h>
@@ -177,6 +178,7 @@
 		       struct user_desc __user *u_info)
 {
 	struct user_desc info;
+	int index;
 
 	if (idx == -1 && get_user(idx, &u_info->entry_number))
 		return -EFAULT;
@@ -184,8 +186,11 @@
 	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
 		return -EINVAL;
 
-	fill_user_desc(&info, idx,
-		       &p->thread.tls_array[idx - GDT_ENTRY_TLS_MIN]);
+	index = idx - GDT_ENTRY_TLS_MIN;
+	index = array_index_nospec(index,
+			GDT_ENTRY_TLS_MAX - GDT_ENTRY_TLS_MIN + 1);
+
+	fill_user_desc(&info, idx, &p->thread.tls_array[index]);
 
 	if (copy_to_user(u_info, &info, sizeof(info)))
 		return -EFAULT;
--- linux-4.4.0.orig/arch/x86/kernel/tracepoint.c
+++ linux-4.4.0/arch/x86/kernel/tracepoint.c
@@ -9,10 +9,12 @@
 #include <linux/atomic.h>
 
 atomic_t trace_idt_ctr = ATOMIC_INIT(0);
+__aligned(PAGE_SIZE)
 struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1,
 				(unsigned long) trace_idt_table };
 
 /* No need to be aligned, but done to keep all IDTs defined the same way. */
+__aligned(PAGE_SIZE)
 gate_desc trace_idt_table[NR_VECTORS] __page_aligned_bss;
 
 static int trace_irq_vector_refcount;
--- linux-4.4.0.orig/arch/x86/kernel/traps.c
+++ linux-4.4.0/arch/x86/kernel/traps.c
@@ -21,7 +21,7 @@
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/ptrace.h>
 #include <linux/uprobes.h>
 #include <linux/string.h>
@@ -51,6 +51,7 @@
 #include <asm/processor.h>
 #include <asm/debugreg.h>
 #include <linux/atomic.h>
+#include <asm/text-patching.h>
 #include <asm/ftrace.h>
 #include <asm/traps.h>
 #include <asm/desc.h>
@@ -109,6 +110,12 @@
 	preempt_count_dec();
 }
 
+/*
+ * In IST context, we explicitly disable preemption.  This serves two
+ * purposes: it makes it much less likely that we would accidentally
+ * schedule in IST context and it will force a warning if we somehow
+ * manage to schedule by accident.
+ */
 void ist_enter(struct pt_regs *regs)
 {
 	if (user_mode(regs)) {
@@ -123,13 +130,7 @@
 		rcu_nmi_enter();
 	}
 
-	/*
-	 * We are atomic because we're on the IST stack; or we're on
-	 * x86_32, in which case we still shouldn't schedule; or we're
-	 * on x86_64 and entered from user mode, in which case we're
-	 * still atomic unless ist_begin_non_atomic is called.
-	 */
-	preempt_count_add(HARDIRQ_OFFSET);
+	preempt_disable();
 
 	/* This code is a bit fragile.  Test it. */
 	RCU_LOCKDEP_WARN(!rcu_is_watching(), "ist_enter didn't work");
@@ -137,7 +138,7 @@
 
 void ist_exit(struct pt_regs *regs)
 {
-	preempt_count_sub(HARDIRQ_OFFSET);
+	preempt_enable_no_resched();
 
 	if (!user_mode(regs))
 		rcu_nmi_exit();
@@ -166,9 +167,9 @@
 	 * from double_fault.
 	 */
 	BUG_ON((unsigned long)(current_top_of_stack() -
-			       current_stack_pointer()) >= THREAD_SIZE);
+			       current_stack_pointer) >= THREAD_SIZE);
 
-	preempt_count_sub(HARDIRQ_OFFSET);
+	preempt_enable_no_resched();
 }
 
 /**
@@ -178,7 +179,7 @@
  */
 void ist_end_non_atomic(void)
 {
-	preempt_count_add(HARDIRQ_OFFSET);
+	preempt_disable();
 }
 
 static nokprobe_inline int
@@ -480,7 +481,6 @@
 }
 NOKPROBE_SYMBOL(do_general_protection);
 
-/* May run on IST stack. */
 dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
 {
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -495,6 +495,13 @@
 	if (poke_int3_handler(regs))
 		return;
 
+	/*
+	 * Use ist_enter despite the fact that we don't use an IST stack.
+	 * We can be called from a kprobe in non-CONTEXT_KERNEL kernel
+	 * mode or even during context tracking state changes.
+	 *
+	 * This means that we can't schedule.  That's okay.
+	 */
 	ist_enter(regs);
 	RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
@@ -512,15 +519,10 @@
 			SIGTRAP) == NOTIFY_STOP)
 		goto exit;
 
-	/*
-	 * Let others (NMI) know that the debug stack is in use
-	 * as we may switch to the interrupt stack.
-	 */
-	debug_stack_usage_inc();
 	preempt_conditional_sti(regs);
 	do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
 	preempt_conditional_cli(regs);
-	debug_stack_usage_dec();
+
 exit:
 	ist_exit(regs);
 }
@@ -750,7 +752,6 @@
 do_device_not_available(struct pt_regs *regs, long error_code)
 {
 	RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
-	BUG_ON(use_eager_fpu());
 
 #ifdef CONFIG_MATH_EMULATION
 	if (read_cr0() & X86_CR0_EM) {
@@ -891,14 +892,11 @@
 	 * cpu_init() loads TSS. See comments in early_trap_init().
 	 */
 	set_intr_gate_ist(X86_TRAP_DB, &debug, DEBUG_STACK);
-	/* int3 can be called from all */
-	set_system_intr_gate_ist(X86_TRAP_BP, &int3, DEBUG_STACK);
 
 	x86_init.irqs.trap_init();
 
 #ifdef CONFIG_X86_64
 	memcpy(&debug_idt_table, &idt_table, IDT_ENTRIES * 16);
 	set_nmi_gate(X86_TRAP_DB, &debug);
-	set_nmi_gate(X86_TRAP_BP, &int3);
 #endif
 }
--- linux-4.4.0.orig/arch/x86/kernel/tsc.c
+++ linux-4.4.0/arch/x86/kernel/tsc.c
@@ -3,7 +3,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/timer.h>
 #include <linux/acpi_pmtmr.h>
 #include <linux/cpufreq.h>
@@ -43,6 +43,11 @@
 
 int tsc_clocksource_reliable;
 
+static u32 art_to_tsc_numerator;
+static u32 art_to_tsc_denominator;
+static u64 art_to_tsc_offset;
+struct clocksource *art_related_clocksource;
+
 /*
  * Use a ring-buffer like data structure, where a writer advances the head by
  * writing a new data entry and a reader advances the tail when it observes a
@@ -365,20 +370,23 @@
 		tsc_clocksource_reliable = 1;
 	if (!strncmp(str, "noirqtime", 9))
 		no_sched_irq_time = 1;
+	if (!strcmp(str, "unstable"))
+		mark_tsc_unstable("boot parameter");
 	return 1;
 }
 
 __setup("tsc=", tsc_setup);
 
-#define MAX_RETRIES     5
-#define SMI_TRESHOLD    50000
+#define MAX_RETRIES		5
+#define TSC_DEFAULT_THRESHOLD	0x20000
 
 /*
- * Read TSC and the reference counters. Take care of SMI disturbance
+ * Read TSC and the reference counters. Take care of any disturbances
  */
 static u64 tsc_read_refs(u64 *p, int hpet)
 {
 	u64 t1, t2;
+	u64 thresh = tsc_khz ? tsc_khz >> 5 : TSC_DEFAULT_THRESHOLD;
 	int i;
 
 	for (i = 0; i < MAX_RETRIES; i++) {
@@ -388,7 +396,7 @@
 		else
 			*p = acpi_pm_read_early();
 		t2 = get_cycles();
-		if ((t2 - t1) < SMI_TRESHOLD)
+		if ((t2 - t1) < thresh)
 			return t2;
 	}
 	return ULLONG_MAX;
@@ -406,7 +414,7 @@
 	hpet2 -= hpet1;
 	tmp = ((u64)hpet2 * hpet_readl(HPET_PERIOD));
 	do_div(tmp, 1000000);
-	do_div(deltatsc, tmp);
+	deltatsc = div64_u64(deltatsc, tmp);
 
 	return (unsigned long) deltatsc;
 }
@@ -693,15 +701,15 @@
 	 * zero. In each wait loop iteration we read the TSC and check
 	 * the delta to the previous read. We keep track of the min
 	 * and max values of that delta. The delta is mostly defined
-	 * by the IO time of the PIT access, so we can detect when a
-	 * SMI/SMM disturbance happened between the two reads. If the
+	 * by the IO time of the PIT access, so we can detect when
+	 * any disturbance happened between the two reads. If the
 	 * maximum time is significantly larger than the minimum time,
 	 * then we discard the result and have another try.
 	 *
 	 * 2) Reference counter. If available we use the HPET or the
 	 * PMTIMER as a reference to check the sanity of that value.
 	 * We use separate TSC readouts and check inside of the
-	 * reference read for a SMI/SMM disturbance. We dicard
+	 * reference read for any possible disturbance. We dicard
 	 * disturbed values here as well. We do that around the PIT
 	 * calibration delay loop as we have to wait for a certain
 	 * amount of time anyway.
@@ -734,7 +742,7 @@
 		if (ref1 == ref2)
 			continue;
 
-		/* Check, whether the sampling was disturbed by an SMI */
+		/* Check, whether the sampling was disturbed */
 		if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX)
 			continue;
 
@@ -964,6 +972,37 @@
 
 #endif /* CONFIG_CPU_FREQ */
 
+#define ART_CPUID_LEAF (0x15)
+#define ART_MIN_DENOMINATOR (1)
+
+
+/*
+ * If ART is present detect the numerator:denominator to convert to TSC
+ */
+static void detect_art(void)
+{
+	unsigned int unused[2];
+
+	if (boot_cpu_data.cpuid_level < ART_CPUID_LEAF)
+		return;
+
+	cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
+	      &art_to_tsc_numerator, unused, unused+1);
+
+	/* Don't enable ART in a VM, non-stop TSC required */
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR) ||
+	    !boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ||
+	    art_to_tsc_denominator < ART_MIN_DENOMINATOR)
+		return;
+
+	if (rdmsrl_safe(MSR_IA32_TSC_ADJUST, &art_to_tsc_offset))
+		return;
+
+	/* Make this sticky over multiple CPU init calls */
+	setup_force_cpu_cap(X86_FEATURE_ART);
+}
+
+
 /* clocksource code */
 
 static struct clocksource clocksource_tsc;
@@ -1071,6 +1110,25 @@
 	return 0;
 }
 
+/*
+ * Convert ART to TSC given numerator/denominator found in detect_art()
+ */
+struct system_counterval_t convert_art_to_tsc(cycle_t art)
+{
+	u64 tmp, res, rem;
+
+	rem = do_div(art, art_to_tsc_denominator);
+
+	res = art * art_to_tsc_numerator;
+	tmp = rem * art_to_tsc_numerator;
+
+	do_div(tmp, art_to_tsc_denominator);
+	res += tmp + art_to_tsc_offset;
+
+	return (struct system_counterval_t) {.cs = art_related_clocksource,
+			.cycles = res};
+}
+EXPORT_SYMBOL(convert_art_to_tsc);
 
 static void tsc_refine_calibration_work(struct work_struct *work);
 static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work);
@@ -1090,7 +1148,7 @@
  */
 static void tsc_refine_calibration_work(struct work_struct *work)
 {
-	static u64 tsc_start = -1, ref_start;
+	static u64 tsc_start = ULLONG_MAX, ref_start;
 	static int hpet;
 	u64 tsc_stop, ref_stop, delta;
 	unsigned long freq;
@@ -1104,14 +1162,15 @@
 	 * delayed the first time we expire. So set the workqueue
 	 * again once we know timers are working.
 	 */
-	if (tsc_start == -1) {
+	if (tsc_start == ULLONG_MAX) {
+restart:
 		/*
 		 * Only set hpet once, to avoid mixing hardware
 		 * if the hpet becomes enabled later.
 		 */
 		hpet = is_hpet_enabled();
-		schedule_delayed_work(&tsc_irqwork, HZ);
 		tsc_start = tsc_read_refs(&ref_start, hpet);
+		schedule_delayed_work(&tsc_irqwork, HZ);
 		return;
 	}
 
@@ -1121,9 +1180,9 @@
 	if (ref_start == ref_stop)
 		goto out;
 
-	/* Check, whether the sampling was disturbed by an SMI */
-	if (tsc_start == ULLONG_MAX || tsc_stop == ULLONG_MAX)
-		goto out;
+	/* Check, whether the sampling was disturbed */
+	if (tsc_stop == ULLONG_MAX)
+		goto restart;
 
 	delta = tsc_stop - tsc_start;
 	delta *= 1000000LL;
@@ -1142,6 +1201,8 @@
 		(unsigned long)tsc_khz % 1000);
 
 out:
+	if (boot_cpu_has(X86_FEATURE_ART))
+		art_related_clocksource = &clocksource_tsc;
 	clocksource_register_khz(&clocksource_tsc, tsc_khz);
 }
 
@@ -1163,10 +1224,15 @@
 		clocksource_tsc.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
 
 	/*
-	 * Trust the results of the earlier calibration on systems
-	 * exporting a reliable TSC.
+	 * When TSC frequency is known (retrieved via MSR or CPUID), we skip
+	 * the refined calibration and directly register it as a clocksource.
+	 *
+	 * We still keep the TSC_RELIABLE flag here to avoid regressions -
+	 * it will be removed after all the conversion for other code paths
+	 * connected to this flag is done.
 	 */
-	if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) {
+	if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE) ||
+		boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ)) {
 		clocksource_register_khz(&clocksource_tsc, tsc_khz);
 		return 0;
 	}
@@ -1237,6 +1303,8 @@
 		mark_tsc_unstable("TSCs unsynchronized");
 
 	check_system_tsc_reliable();
+
+	detect_art();
 }
 
 #ifdef CONFIG_SMP
--- linux-4.4.0.orig/arch/x86/kernel/tsc_msr.c
+++ linux-4.4.0/arch/x86/kernel/tsc_msr.c
@@ -21,6 +21,7 @@
 #include <asm/setup.h>
 #include <asm/apic.h>
 #include <asm/param.h>
+#include <asm/tsc.h>
 
 /* CPU reference clock frequency: in KHz */
 #define FREQ_83		83200
@@ -92,7 +93,7 @@
 
 	if (freq_desc_tables[cpu_index].msr_plat) {
 		rdmsr(MSR_PLATFORM_INFO, lo, hi);
-		ratio = (lo >> 8) & 0x1f;
+		ratio = (lo >> 8) & 0xff;
 	} else {
 		rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 		ratio = (hi >> 8) & 0x1f;
--- linux-4.4.0.orig/arch/x86/kernel/uprobes.c
+++ linux-4.4.0/arch/x86/kernel/uprobes.c
@@ -268,10 +268,11 @@
 
 static bool is_prefix_bad(struct insn *insn)
 {
+	insn_byte_t p;
 	int i;
 
-	for (i = 0; i < insn->prefixes.nbytes; i++) {
-		switch (insn->prefixes.bytes[i]) {
+	for_each_insn_prefix(insn, i, p) {
+		switch (p) {
 		case 0x26:	/* INAT_PFX_ES   */
 		case 0x2E:	/* INAT_PFX_CS   */
 		case 0x36:	/* INAT_PFX_DS   */
@@ -290,12 +291,16 @@
 	insn_init(insn, auprobe->insn, sizeof(auprobe->insn), x86_64);
 	/* has the side-effect of processing the entire instruction */
 	insn_get_length(insn);
-	if (WARN_ON_ONCE(!insn_complete(insn)))
+	if (!insn_complete(insn))
 		return -ENOEXEC;
 
 	if (is_prefix_bad(insn))
 		return -ENOTSUPP;
 
+	/* We should not singlestep on the exception masking instructions */
+	if (insn_masking_exception(insn))
+		return -ENOTSUPP;
+
 	if (x86_64)
 		good_insns = good_insns_64;
 	else
@@ -357,20 +362,22 @@
 		*cursor &= 0xfe;
 	}
 	/*
-	 * Similar treatment for VEX3 prefix.
-	 * TODO: add XOP/EVEX treatment when insn decoder supports them
+	 * Similar treatment for VEX3/EVEX prefix.
+	 * TODO: add XOP treatment when insn decoder supports them
 	 */
-	if (insn->vex_prefix.nbytes == 3) {
+	if (insn->vex_prefix.nbytes >= 3) {
 		/*
 		 * vex2:     c5    rvvvvLpp   (has no b bit)
 		 * vex3/xop: c4/8f rxbmmmmm wvvvvLpp
 		 * evex:     62    rxbR00mm wvvvv1pp zllBVaaa
-		 *   (evex will need setting of both b and x since
-		 *   in non-sib encoding evex.x is 4th bit of MODRM.rm)
-		 * Setting VEX3.b (setting because it has inverted meaning):
+		 * Setting VEX3.b (setting because it has inverted meaning).
+		 * Setting EVEX.x since (in non-SIB encoding) EVEX.x
+		 * is the 4th bit of MODRM.rm, and needs the same treatment.
+		 * For VEX3-encoded insns, VEX3.x value has no effect in
+		 * non-SIB encoding, the change is superfluous but harmless.
 		 */
 		cursor = auprobe->insn + insn_offset_vex_prefix(insn) + 1;
-		*cursor |= 0x20;
+		*cursor |= 0x60;
 	}
 
 	/*
@@ -415,12 +422,10 @@
 
 	reg = MODRM_REG(insn);	/* Fetch modrm.reg */
 	reg2 = 0xff;		/* Fetch vex.vvvv */
-	if (insn->vex_prefix.nbytes == 2)
-		reg2 = insn->vex_prefix.bytes[1];
-	else if (insn->vex_prefix.nbytes == 3)
+	if (insn->vex_prefix.nbytes)
 		reg2 = insn->vex_prefix.bytes[2];
 	/*
-	 * TODO: add XOP, EXEV vvvv reading.
+	 * TODO: add XOP vvvv reading.
 	 *
 	 * vex.vvvv field is in bits 6-3, bits are inverted.
 	 * But in 32-bit mode, high-order bit may be ignored.
@@ -514,9 +519,12 @@
 	void	(*abort)(struct arch_uprobe *, struct pt_regs *);
 };
 
-static inline int sizeof_long(void)
+static inline int sizeof_long(struct pt_regs *regs)
 {
-	return is_ia32_task() ? 4 : 8;
+	/*
+	 * Check registers for mode as in_xxx_syscall() does not apply here.
+	 */
+	return user_64bit_mode(regs) ? 8 : 4;
 }
 
 static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
@@ -527,9 +535,9 @@
 
 static int push_ret_address(struct pt_regs *regs, unsigned long ip)
 {
-	unsigned long new_sp = regs->sp - sizeof_long();
+	unsigned long new_sp = regs->sp - sizeof_long(regs);
 
-	if (copy_to_user((void __user *)new_sp, &ip, sizeof_long()))
+	if (copy_to_user((void __user *)new_sp, &ip, sizeof_long(regs)))
 		return -EFAULT;
 
 	regs->sp = new_sp;
@@ -562,7 +570,7 @@
 		long correction = utask->vaddr - utask->xol_vaddr;
 		regs->ip += correction;
 	} else if (auprobe->defparam.fixups & UPROBE_FIX_CALL) {
-		regs->sp += sizeof_long(); /* Pop incorrect return address */
+		regs->sp += sizeof_long(regs); /* Pop incorrect return address */
 		if (push_ret_address(regs, utask->vaddr + auprobe->defparam.ilen))
 			return -ERESTART;
 	}
@@ -671,7 +679,7 @@
 	 * "call" insn was executed out-of-line. Just restore ->sp and restart.
 	 * We could also restore ->ip and try to call branch_emulate_op() again.
 	 */
-	regs->sp += sizeof_long();
+	regs->sp += sizeof_long(regs);
 	return -ERESTART;
 }
 
@@ -704,6 +712,7 @@
 static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
 {
 	u8 opc1 = OPCODE1(insn);
+	insn_byte_t p;
 	int i;
 
 	switch (opc1) {
@@ -734,8 +743,8 @@
 	 * Intel and AMD behavior differ in 64-bit mode: Intel ignores 66 prefix.
 	 * No one uses these insns, reject any branch insns with such prefix.
 	 */
-	for (i = 0; i < insn->prefixes.nbytes; i++) {
-		if (insn->prefixes.bytes[i] == 0x66)
+	for_each_insn_prefix(insn, i, p) {
+		if (p == 0x66)
 			return -ENOTSUPP;
 	}
 
@@ -962,7 +971,7 @@
 unsigned long
 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
 {
-	int rasize = sizeof_long(), nleft;
+	int rasize = sizeof_long(regs), nleft;
 	unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */
 
 	if (copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize))
@@ -980,7 +989,7 @@
 		pr_err("uprobe: return address clobbered: pid=%d, %%sp=%#lx, "
 			"%%ip=%#lx\n", current->pid, regs->sp, regs->ip);
 
-		force_sig_info(SIGSEGV, SEND_SIG_FORCED, current);
+		force_sig(SIGSEGV, current);
 	}
 
 	return -1;
--- linux-4.4.0.orig/arch/x86/kernel/verify_cpu.S
+++ linux-4.4.0/arch/x86/kernel/verify_cpu.S
@@ -30,7 +30,7 @@
  * 	appropriately. Either display a message or halt.
  */
 
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/msr-index.h>
 
 verify_cpu:
--- linux-4.4.0.orig/arch/x86/kernel/vm86_32.c
+++ linux-4.4.0/arch/x86/kernel/vm86_32.c
@@ -187,7 +187,7 @@
 	pte_unmap_unlock(pte, ptl);
 out:
 	up_write(&mm->mmap_sem);
-	flush_tlb();
+	flush_tlb_mm_range(mm, 0xA0000, 0xA0000 + 32*PAGE_SIZE, 0UL);
 }
 
 
@@ -357,8 +357,10 @@
 	tss = &per_cpu(cpu_tss, get_cpu());
 	/* make room for real-mode segments */
 	tsk->thread.sp0 += 16;
-	if (cpu_has_sep)
+
+	if (static_cpu_has(X86_FEATURE_SEP))
 		tsk->thread.sysenter_cs = 0;
+
 	load_sp0(tss, &tsk->thread);
 	put_cpu();
 
@@ -715,7 +717,8 @@
 	return;
 
 check_vip:
-	if (VEFLAGS & X86_EFLAGS_VIP) {
+	if ((VEFLAGS & (X86_EFLAGS_VIP | X86_EFLAGS_VIF)) ==
+	    (X86_EFLAGS_VIP | X86_EFLAGS_VIF)) {
 		save_v86_state(regs, VM86_STI);
 		return;
 	}
--- linux-4.4.0.orig/arch/x86/kernel/vmlinux.lds.S
+++ linux-4.4.0/arch/x86/kernel/vmlinux.lds.S
@@ -34,13 +34,13 @@
 #ifdef CONFIG_X86_32
 OUTPUT_ARCH(i386)
 ENTRY(phys_startup_32)
-jiffies = jiffies_64;
 #else
 OUTPUT_ARCH(i386:x86-64)
 ENTRY(phys_startup_64)
-jiffies_64 = jiffies;
 #endif
 
+jiffies = jiffies_64;
+
 #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
 /*
  * On 64-bit, align RODATA to 2MB so that even with CONFIG_DEBUG_RODATA
@@ -104,6 +104,13 @@
 		IRQENTRY_TEXT
 		*(.fixup)
 		*(.gnu.warning)
+
+#ifdef CONFIG_RETPOLINE
+		__indirect_thunk_start = .;
+		*(.text.__x86.indirect_thunk)
+		__indirect_thunk_end = .;
+#endif
+
 		/* End of text section */
 		_etext = .;
 	} :text = 0x9090
@@ -195,6 +202,17 @@
 	:init
 #endif
 
+	/*
+	 * Section for code used exclusively before alternatives are run. All
+	 * references to such code must be patched out by alternatives, normally
+	 * by using X86_FEATURE_ALWAYS CPU feature bit.
+	 *
+	 * See static_cpu_has() for an example.
+	 */
+	.altinstr_aux : AT(ADDR(.altinstr_aux) - LOAD_OFFSET) {
+		*(.altinstr_aux)
+	}
+
 	INIT_DATA_SECTION(16)
 
 	.x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
@@ -347,7 +365,7 @@
  * Per-cpu symbols which need to be offset from __per_cpu_load
  * for the boot processor.
  */
-#define INIT_PER_CPU(x) init_per_cpu__##x = x + __per_cpu_load
+#define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x) + __per_cpu_load
 INIT_PER_CPU(gdt_page);
 INIT_PER_CPU(irq_stack_union);
 
--- linux-4.4.0.orig/arch/x86/kernel/x8664_ksyms_64.c
+++ linux-4.4.0/arch/x86/kernel/x8664_ksyms_64.c
@@ -1,7 +1,7 @@
 /* Exports for assembly files.
    All C exports should go in the respective C files. */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/smp.h>
 
 #include <net/checksum.h>
@@ -42,6 +42,9 @@
 
 EXPORT_SYMBOL(csum_partial);
 
+EXPORT_SYMBOL(__sw_hweight32);
+EXPORT_SYMBOL(__sw_hweight64);
+
 /*
  * Export string functions. We normally rely on gcc builtin for most of these,
  * but gcc sometimes decides not to inline them.
@@ -77,3 +80,5 @@
 EXPORT_SYMBOL(___preempt_schedule);
 EXPORT_SYMBOL(___preempt_schedule_notrace);
 #endif
+
+EXPORT_SYMBOL_GPL(clear_bhb_loop);
--- linux-4.4.0.orig/arch/x86/kernel/x86_init.c
+++ linux-4.4.0/arch/x86/kernel/x86_init.c
@@ -5,7 +5,7 @@
  */
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/pci.h>
 
 #include <asm/bios_ebda.h>
--- linux-4.4.0.orig/arch/x86/kvm/Kconfig
+++ linux-4.4.0/arch/x86/kvm/Kconfig
@@ -22,7 +22,8 @@
 	depends on HAVE_KVM
 	depends on HIGH_RES_TIMERS
 	# for TASKSTATS/TASK_DELAY_ACCT:
-	depends on NET
+	depends on NET && MULTIUSER
+	depends on X86_LOCAL_APIC
 	select PREEMPT_NOTIFIERS
 	select MMU_NOTIFIER
 	select ANON_INODES
--- linux-4.4.0.orig/arch/x86/kvm/cpuid.c
+++ linux-4.4.0/arch/x86/kvm/cpuid.c
@@ -16,7 +16,6 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
-#include <asm/fpu/internal.h> /* For use_eager_fpu.  Ugh! */
 #include <asm/user.h>
 #include <asm/fpu/xstate.h>
 #include "cpuid.h"
@@ -46,11 +45,18 @@
 	return ret;
 }
 
+bool kvm_mpx_supported(void)
+{
+	return ((host_xcr0 & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR))
+		 && kvm_x86_ops->mpx_supported());
+}
+EXPORT_SYMBOL_GPL(kvm_mpx_supported);
+
 u64 kvm_supported_xcr0(void)
 {
 	u64 xcr0 = KVM_SUPPORTED_XCR0 & host_xcr0;
 
-	if (!kvm_x86_ops->mpx_supported())
+	if (!kvm_mpx_supported())
 		xcr0 &= ~(XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR);
 
 	return xcr0;
@@ -97,9 +103,7 @@
 	if (best && (best->eax & (F(XSAVES) | F(XSAVEC))))
 		best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
 
-	vcpu->arch.eager_fpu = use_eager_fpu() || guest_cpuid_has_mpx(vcpu);
-	if (vcpu->arch.eager_fpu)
-		kvm_x86_ops->fpu_activate(vcpu);
+	kvm_x86_ops->fpu_activate(vcpu);
 
 	/*
 	 * The existing code assumes virtual address is 48-bit in the canonical
@@ -165,19 +169,22 @@
 			     struct kvm_cpuid_entry __user *entries)
 {
 	int r, i;
-	struct kvm_cpuid_entry *cpuid_entries;
+	struct kvm_cpuid_entry *cpuid_entries = NULL;
 
 	r = -E2BIG;
 	if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
 		goto out;
 	r = -ENOMEM;
-	cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry) * cpuid->nent);
-	if (!cpuid_entries)
-		goto out;
-	r = -EFAULT;
-	if (copy_from_user(cpuid_entries, entries,
-			   cpuid->nent * sizeof(struct kvm_cpuid_entry)))
-		goto out_free;
+	if (cpuid->nent) {
+		cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry) *
+					cpuid->nent);
+		if (!cpuid_entries)
+			goto out;
+		r = -EFAULT;
+		if (copy_from_user(cpuid_entries, entries,
+				   cpuid->nent * sizeof(struct kvm_cpuid_entry)))
+			goto out;
+	}
 	for (i = 0; i < cpuid->nent; i++) {
 		vcpu->arch.cpuid_entries[i].function = cpuid_entries[i].function;
 		vcpu->arch.cpuid_entries[i].eax = cpuid_entries[i].eax;
@@ -196,9 +203,8 @@
 	kvm_x86_ops->cpuid_update(vcpu);
 	r = kvm_update_cpuid(vcpu);
 
-out_free:
-	vfree(cpuid_entries);
 out:
+	vfree(cpuid_entries);
 	return r;
 }
 
@@ -263,13 +269,18 @@
 {
 	switch (func) {
 	case 0:
-		entry->eax = 1;		/* only one leaf currently */
+		entry->eax = 7;
 		++*nent;
 		break;
 	case 1:
 		entry->ecx = F(MOVBE);
 		++*nent;
 		break;
+	case 7:
+		entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+		if (index == 0)
+			entry->ecx = F(RDPID);
+		++*nent;
 	default:
 		break;
 	}
@@ -295,11 +306,11 @@
 #endif
 	unsigned f_rdtscp = kvm_x86_ops->rdtscp_supported() ? F(RDTSCP) : 0;
 	unsigned f_invpcid = kvm_x86_ops->invpcid_supported() ? F(INVPCID) : 0;
-	unsigned f_mpx = kvm_x86_ops->mpx_supported() ? F(MPX) : 0;
+	unsigned f_mpx = kvm_mpx_supported() ? F(MPX) : 0;
 	unsigned f_xsaves = kvm_x86_ops->xsaves_supported() ? F(XSAVES) : 0;
 
 	/* cpuid 1.edx */
-	const u32 kvm_supported_word0_x86_features =
+	const u32 kvm_cpuid_1_edx_x86_features =
 		F(FPU) | F(VME) | F(DE) | F(PSE) |
 		F(TSC) | F(MSR) | F(PAE) | F(MCE) |
 		F(CX8) | F(APIC) | 0 /* Reserved */ | F(SEP) |
@@ -309,7 +320,7 @@
 		F(FXSR) | F(XMM) | F(XMM2) | F(SELFSNOOP) |
 		0 /* HTT, TM, Reserved, PBE */;
 	/* cpuid 0x80000001.edx */
-	const u32 kvm_supported_word1_x86_features =
+	const u32 kvm_cpuid_8000_0001_edx_x86_features =
 		F(FPU) | F(VME) | F(DE) | F(PSE) |
 		F(TSC) | F(MSR) | F(PAE) | F(MCE) |
 		F(CX8) | F(APIC) | 0 /* Reserved */ | F(SYSCALL) |
@@ -319,7 +330,7 @@
 		F(FXSR) | F(FXSR_OPT) | f_gbpages | f_rdtscp |
 		0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW);
 	/* cpuid 1.ecx */
-	const u32 kvm_supported_word4_x86_features =
+	const u32 kvm_cpuid_1_ecx_x86_features =
 		/* NOTE: MONITOR (and MWAIT) are emulated as NOP,
 		 * but *not* advertised to guests via CPUID ! */
 		F(XMM3) | F(PCLMULQDQ) | 0 /* DTES64, MONITOR */ |
@@ -331,35 +342,45 @@
 		0 /* Reserved*/ | F(AES) | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX) |
 		F(F16C) | F(RDRAND);
 	/* cpuid 0x80000001.ecx */
-	const u32 kvm_supported_word6_x86_features =
+	const u32 kvm_cpuid_8000_0001_ecx_x86_features =
 		F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ |
 		F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) |
 		F(3DNOWPREFETCH) | F(OSVW) | 0 /* IBS */ | F(XOP) |
 		0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
 
+	/* cpuid 0x80000008.ebx */
+	const u32 kvm_cpuid_8000_0008_ebx_x86_features =
+		F(AMD_IBPB) | F(AMD_IBRS) | F(AMD_SSBD) | F(VIRT_SSBD) |
+		F(AMD_STIBP) | F(AMD_SSB_NO);
+
 	/* cpuid 0xC0000001.edx */
-	const u32 kvm_supported_word5_x86_features =
+	const u32 kvm_cpuid_C000_0001_edx_x86_features =
 		F(XSTORE) | F(XSTORE_EN) | F(XCRYPT) | F(XCRYPT_EN) |
 		F(ACE2) | F(ACE2_EN) | F(PHE) | F(PHE_EN) |
 		F(PMM) | F(PMM_EN);
 
 	/* cpuid 7.0.ebx */
-	const u32 kvm_supported_word9_x86_features =
+	const u32 kvm_cpuid_7_0_ebx_x86_features =
 		F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
 		F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
 		F(ADX) | F(SMAP) | F(AVX512F) | F(AVX512PF) | F(AVX512ER) |
 		F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(PCOMMIT);
 
 	/* cpuid 0xD.1.eax */
-	const u32 kvm_supported_word10_x86_features =
+	const u32 kvm_cpuid_D_1_eax_x86_features =
 		F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | f_xsaves;
 
+	/* cpuid 7.0.edx*/
+	const u32 kvm_cpuid_7_0_edx_x86_features =
+		F(SPEC_CTRL) | F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) |
+		F(INTEL_STIBP) | F(MD_CLEAR);
+
 	/* all calls to cpuid_count() should be made on the same cpu */
 	get_cpu();
 
 	r = -E2BIG;
 
-	if (*nent >= maxnent)
+	if (WARN_ON(*nent >= maxnent))
 		goto out;
 
 	do_cpuid_1_ent(entry, function, index);
@@ -370,10 +391,10 @@
 		entry->eax = min(entry->eax, (u32)0xd);
 		break;
 	case 1:
-		entry->edx &= kvm_supported_word0_x86_features;
-		cpuid_mask(&entry->edx, 0);
-		entry->ecx &= kvm_supported_word4_x86_features;
-		cpuid_mask(&entry->ecx, 4);
+		entry->edx &= kvm_cpuid_1_edx_x86_features;
+		cpuid_mask(&entry->edx, CPUID_1_EDX);
+		entry->ecx &= kvm_cpuid_1_ecx_x86_features;
+		cpuid_mask(&entry->ecx, CPUID_1_ECX);
 		/* we support x2apic emulation even if host does not support
 		 * it since we emulate x2apic in software */
 		entry->ecx |= F(X2APIC);
@@ -427,15 +448,30 @@
 		entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
 		/* Mask ebx against host capability word 9 */
 		if (index == 0) {
-			entry->ebx &= kvm_supported_word9_x86_features;
-			cpuid_mask(&entry->ebx, 9);
+			entry->ebx &= kvm_cpuid_7_0_ebx_x86_features;
+			cpuid_mask(&entry->ebx, CPUID_7_0_EBX);
 			// TSC_ADJUST is emulated
 			entry->ebx |= F(TSC_ADJUST);
-		} else
+			entry->edx &= kvm_cpuid_7_0_edx_x86_features;
+			cpuid_mask(&entry->edx, CPUID_7_EDX);
+			if (boot_cpu_has(X86_FEATURE_IBPB) && boot_cpu_has(X86_FEATURE_IBRS))
+				entry->edx |= F(SPEC_CTRL);
+			if (boot_cpu_has(X86_FEATURE_STIBP))
+				entry->edx |= F(INTEL_STIBP);
+			if (boot_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
+			    boot_cpu_has(X86_FEATURE_AMD_SSBD))
+				entry->edx |= F(SPEC_CTRL_SSBD);
+			/*
+			 * We emulate ARCH_CAPABILITIES in software even
+			 * if the host doesn't support it.
+			 */
+			entry->edx |= F(ARCH_CAPABILITIES);
+		} else {
 			entry->ebx = 0;
+			entry->edx = 0;
+		}
 		entry->eax = 0;
 		entry->ecx = 0;
-		entry->edx = 0;
 		break;
 	}
 	case 9:
@@ -508,7 +544,8 @@
 
 			do_cpuid_1_ent(&entry[i], function, idx);
 			if (idx == 1) {
-				entry[i].eax &= kvm_supported_word10_x86_features;
+				entry[i].eax &= kvm_cpuid_D_1_eax_x86_features;
+				cpuid_mask(&entry[i].eax, CPUID_D_1_EAX);
 				entry[i].ebx = 0;
 				if (entry[i].eax & (F(XSAVES)|F(XSAVEC)))
 					entry[i].ebx =
@@ -558,10 +595,10 @@
 		entry->eax = min(entry->eax, 0x8000001a);
 		break;
 	case 0x80000001:
-		entry->edx &= kvm_supported_word1_x86_features;
-		cpuid_mask(&entry->edx, 1);
-		entry->ecx &= kvm_supported_word6_x86_features;
-		cpuid_mask(&entry->ecx, 6);
+		entry->edx &= kvm_cpuid_8000_0001_edx_x86_features;
+		cpuid_mask(&entry->edx, CPUID_8000_0001_EDX);
+		entry->ecx &= kvm_cpuid_8000_0001_ecx_x86_features;
+		cpuid_mask(&entry->ecx, CPUID_8000_0001_ECX);
 		break;
 	case 0x80000007: /* Advanced power management */
 		/* invariant TSC is CPUID.80000007H:EDX[8] */
@@ -578,7 +615,26 @@
 		if (!g_phys_as)
 			g_phys_as = phys_as;
 		entry->eax = g_phys_as | (virt_as << 8);
-		entry->ebx = entry->edx = 0;
+		entry->edx = 0;
+		/*
+		 * IBRS, IBPB and VIRT_SSBD aren't necessarily present in
+		 * hardware cpuid
+		 */
+		if (boot_cpu_has(X86_FEATURE_AMD_IBPB))
+			entry->ebx |= F(AMD_IBPB);
+		if (boot_cpu_has(X86_FEATURE_AMD_IBRS))
+			entry->ebx |= F(AMD_IBRS);
+		if (boot_cpu_has(X86_FEATURE_VIRT_SSBD))
+			entry->ebx |= F(VIRT_SSBD);
+		entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features;
+		cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX);
+		/*
+		 * The preference is to use SPEC CTRL MSR instead of the
+		 * VIRT_SPEC MSR.
+		 */
+		if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD) &&
+		    !boot_cpu_has(X86_FEATURE_AMD_SSBD))
+			entry->ebx |= F(VIRT_SSBD);
 		break;
 	}
 	case 0x80000019:
@@ -594,8 +650,8 @@
 		entry->eax = min(entry->eax, 0xC0000004);
 		break;
 	case 0xC0000001:
-		entry->edx &= kvm_supported_word5_x86_features;
-		cpuid_mask(&entry->edx, 5);
+		entry->edx &= kvm_cpuid_C000_0001_edx_x86_features;
+		cpuid_mask(&entry->edx, CPUID_C000_0001_EDX);
 		break;
 	case 3: /* Processor serial number */
 	case 5: /* MONITOR/MWAIT */
@@ -620,6 +676,9 @@
 static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 func,
 			u32 idx, int *nent, int maxnent, unsigned int type)
 {
+	if (*nent >= maxnent)
+		return -E2BIG;
+
 	if (type == KVM_GET_EMULATED_CPUID)
 		return __do_cpuid_ent_emulated(entry, func, idx, nent, maxnent);
 
@@ -736,18 +795,20 @@
 static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
 {
 	struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
-	int j, nent = vcpu->arch.cpuid_nent;
+	struct kvm_cpuid_entry2 *ej;
+	int j = i;
+	int nent = vcpu->arch.cpuid_nent;
 
 	e->flags &= ~KVM_CPUID_FLAG_STATE_READ_NEXT;
 	/* when no next entry is found, the current entry[i] is reselected */
-	for (j = i + 1; ; j = (j + 1) % nent) {
-		struct kvm_cpuid_entry2 *ej = &vcpu->arch.cpuid_entries[j];
-		if (ej->function == e->function) {
-			ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
-			return j;
-		}
-	}
-	return 0; /* silence gcc, even though control never reaches here */
+	do {
+		j = (j + 1) % nent;
+		ej = &vcpu->arch.cpuid_entries[j];
+	} while (ej->function != e->function);
+
+	ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
+
+	return j;
 }
 
 /* find an entry with matching function, matching index (if needed), and that
@@ -817,12 +878,6 @@
 	if (!best)
 		best = check_cpuid_limit(vcpu, function, index);
 
-	/*
-	 * Perfmon not yet supported for L2 guest.
-	 */
-	if (is_guest_mode(vcpu) && function == 0xa)
-		best = NULL;
-
 	if (best) {
 		*eax = best->eax;
 		*ebx = best->ebx;
--- linux-4.4.0.orig/arch/x86/kvm/cpuid.h
+++ linux-4.4.0/arch/x86/kvm/cpuid.h
@@ -1,9 +1,12 @@
 #ifndef ARCH_X86_KVM_CPUID_H
 #define ARCH_X86_KVM_CPUID_H
 
+#include <asm/microcode.h>
+
 #include "x86.h"
 
 int kvm_update_cpuid(struct kvm_vcpu *vcpu);
+bool kvm_mpx_supported(void);
 struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
 					      u32 function, u32 index);
 int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid,
@@ -134,20 +137,20 @@
 	return best && (best->ebx & bit(X86_FEATURE_RTM));
 }
 
-static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu)
+static inline bool guest_cpuid_has_pcommit(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpuid_entry2 *best;
 
 	best = kvm_find_cpuid_entry(vcpu, 7, 0);
-	return best && (best->ebx & bit(X86_FEATURE_MPX));
+	return best && (best->ebx & bit(X86_FEATURE_PCOMMIT));
 }
 
-static inline bool guest_cpuid_has_pcommit(struct kvm_vcpu *vcpu)
+static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpuid_entry2 *best;
 
 	best = kvm_find_cpuid_entry(vcpu, 7, 0);
-	return best && (best->ebx & bit(X86_FEATURE_PCOMMIT));
+	return best && (best->ebx & bit(X86_FEATURE_MPX));
 }
 
 static inline bool guest_cpuid_has_rdtscp(struct kvm_vcpu *vcpu)
@@ -158,6 +161,46 @@
 	return best && (best->edx & bit(X86_FEATURE_RDTSCP));
 }
 
+static inline bool guest_cpuid_has_ibpb(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
+	if (best && (best->ebx & bit(X86_FEATURE_AMD_IBPB)))
+		return true;
+	best = kvm_find_cpuid_entry(vcpu, 7, 0);
+	return best && (best->edx & bit(X86_FEATURE_SPEC_CTRL));
+}
+
+static inline bool guest_cpuid_has_spec_ctrl(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
+	if (best && (best->ebx & (bit(X86_FEATURE_AMD_IBRS | bit(X86_FEATURE_AMD_SSBD)))))
+		return true;
+	best = kvm_find_cpuid_entry(vcpu, 7, 0);
+	return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SPEC_CTRL_SSBD)));
+}
+
+static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 7, 0);
+	return best && (best->edx & bit(X86_FEATURE_ARCH_CAPABILITIES));
+}
+
+static inline bool guest_cpuid_has_virt_ssbd(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
+	return best && (best->ebx & bit(X86_FEATURE_VIRT_SSBD));
+}
+
+
+
 /*
  * NRIPS is provided through cpuidfn 0x8000000a.edx bit 3
  */
@@ -178,4 +221,26 @@
 }
 #undef BIT_NRIPS
 
+static inline int guest_cpuid_family(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+	if (!best)
+		return -1;
+
+	return __x86_family(best->eax);
+}
+
+static inline int guest_cpuid_model(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+	if (!best)
+		return -1;
+
+	return x86_model(best->eax);
+}
+
 #endif
--- linux-4.4.0.orig/arch/x86/kvm/emulate.c
+++ linux-4.4.0/arch/x86/kvm/emulate.c
@@ -23,9 +23,11 @@
 #include <linux/kvm_host.h>
 #include "kvm_cache_regs.h"
 #include <linux/module.h>
+#include <linux/nospec.h>
 #include <asm/kvm_emulate.h>
 #include <linux/stringify.h>
 #include <asm/debugreg.h>
+#include <asm/nospec-branch.h>
 
 #include "x86.h"
 #include "tss.h"
@@ -172,6 +174,7 @@
 #define NearBranch  ((u64)1 << 52)  /* Near branches */
 #define No16	    ((u64)1 << 53)  /* No 16 bit operand */
 #define IncSP       ((u64)1 << 54)  /* SP is incremented before ModRM calc */
+#define Aligned16   ((u64)1 << 55)  /* Aligned to 16 byte boundary (e.g. FXSAVE) */
 
 #define DstXacc     (DstAccLo | SrcAccHi | SrcWrite)
 
@@ -434,6 +437,26 @@
 FOP_START(salc) "pushf; sbb %al, %al; popf \n\t" FOP_RET
 FOP_END;
 
+/*
+ * XXX: inoutclob user must know where the argument is being expanded.
+ *      Relying on CC_HAVE_ASM_GOTO would allow us to remove _fault.
+ */
+#define asm_safe(insn, inoutclob...) \
+({ \
+	int _fault = 0; \
+ \
+	asm volatile("1:" insn "\n" \
+	             "2:\n" \
+	             ".pushsection .fixup, \"ax\"\n" \
+	             "3: movl $1, %[_fault]\n" \
+	             "   jmp  2b\n" \
+	             ".popsection\n" \
+	             _ASM_EXTABLE(1b, 3b) \
+	             : [_fault] "+qm"(_fault) inoutclob ); \
+ \
+	_fault ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE; \
+})
+
 static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
 				    enum x86_intercept intercept,
 				    enum x86_intercept_stage stage)
@@ -620,21 +643,24 @@
  * depending on whether they're AVX encoded or not.
  *
  * Also included is CMPXCHG16B which is not a vector instruction, yet it is
- * subject to the same check.
+ * subject to the same check.  FXSAVE and FXRSTOR are checked here too as their
+ * 512 bytes of data must be aligned to a 16 byte boundary.
  */
-static bool insn_aligned(struct x86_emulate_ctxt *ctxt, unsigned size)
+static unsigned insn_alignment(struct x86_emulate_ctxt *ctxt, unsigned size)
 {
 	if (likely(size < 16))
-		return false;
+		return 1;
 
 	if (ctxt->d & Aligned)
-		return true;
+		return size;
 	else if (ctxt->d & Unaligned)
-		return false;
+		return 1;
 	else if (ctxt->d & Avx)
-		return false;
+		return 1;
+	else if (ctxt->d & Aligned16)
+		return 16;
 	else
-		return true;
+		return size;
 }
 
 static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt,
@@ -650,10 +676,10 @@
 	u16 sel;
 
 	la = seg_base(ctxt, addr.seg) + addr.ea;
-	*linear = la;
 	*max_size = 0;
 	switch (mode) {
 	case X86EMUL_MODE_PROT64:
+		*linear = la;
 		if (is_noncanonical_address(la))
 			goto bad;
 
@@ -662,6 +688,7 @@
 			goto bad;
 		break;
 	default:
+		*linear = la = (u32)la;
 		usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL,
 						addr.seg);
 		if (!usable)
@@ -689,10 +716,9 @@
 			if (size > *max_size)
 				goto bad;
 		}
-		la &= (u32)-1;
 		break;
 	}
-	if (insn_aligned(ctxt, size) && ((la & (size - 1)) != 0))
+	if (la & (insn_alignment(ctxt, size) - 1))
 		return emulate_gp(ctxt, 0);
 	return X86EMUL_CONTINUE;
 bad:
@@ -765,6 +791,19 @@
 	return assign_eip_near(ctxt, ctxt->_eip + rel);
 }
 
+static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear,
+			      void *data, unsigned size)
+{
+	return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, true);
+}
+
+static int linear_write_system(struct x86_emulate_ctxt *ctxt,
+			       ulong linear, void *data,
+			       unsigned int size)
+{
+	return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, true);
+}
+
 static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
 			      struct segmented_address addr,
 			      void *data,
@@ -776,7 +815,21 @@
 	rc = linearize(ctxt, addr, size, false, &linear);
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
-	return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception);
+	return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, false);
+}
+
+static int segmented_write_std(struct x86_emulate_ctxt *ctxt,
+			       struct segmented_address addr,
+			       void *data,
+			       unsigned int size)
+{
+	int rc;
+	ulong linear;
+
+	rc = linearize(ctxt, addr, size, true, &linear);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+	return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, false);
 }
 
 /*
@@ -962,8 +1015,8 @@
 	void (*fop)(void) = (void *)em_setcc + 4 * (condition & 0xf);
 
 	flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF;
-	asm("push %[flags]; popf; call *%[fastop]"
-	    : "=a"(rc) : [fastop]"r"(fop), [flags]"r"(flags));
+	asm("push %[flags]; popf; " CALL_NOSPEC
+	    : "=a"(rc) : [thunk_target]"r"(fop), [flags]"r"(flags));
 	return rc;
 }
 
@@ -1449,8 +1502,7 @@
 		return emulate_gp(ctxt, index << 3 | 0x2);
 
 	addr = dt.address + index * 8;
-	return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc,
-				   &ctxt->exception);
+	return linear_read_system(ctxt, addr, desc, sizeof *desc);
 }
 
 static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
@@ -1513,8 +1565,7 @@
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
-	return ctxt->ops->read_std(ctxt, *desc_addr_p, desc, sizeof(*desc),
-				   &ctxt->exception);
+	return linear_read_system(ctxt, *desc_addr_p, desc, sizeof(*desc));
 }
 
 /* allowed just for 8 bytes segments */
@@ -1528,11 +1579,9 @@
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
-	return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc,
-				    &ctxt->exception);
+	return linear_write_system(ctxt, addr, desc, sizeof *desc);
 }
 
-/* Does not support long mode */
 static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
 				     u16 selector, int seg, u8 cpl,
 				     enum x86_transfer_type transfer,
@@ -1569,20 +1618,34 @@
 
 	rpl = selector & 3;
 
-	/* NULL selector is not valid for TR, CS and SS (except for long mode) */
-	if ((seg == VCPU_SREG_CS
-	     || (seg == VCPU_SREG_SS
-		 && (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl))
-	     || seg == VCPU_SREG_TR)
-	    && null_selector)
-		goto exception;
-
 	/* TR should be in GDT only */
 	if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
 		goto exception;
 
-	if (null_selector) /* for NULL selector skip all following checks */
+	/* NULL selector is not valid for TR, CS and (except for long mode) SS */
+	if (null_selector) {
+		if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR)
+			goto exception;
+
+		if (seg == VCPU_SREG_SS) {
+			if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)
+				goto exception;
+
+			/*
+			 * ctxt->ops->set_segment expects the CPL to be in
+			 * SS.DPL, so fake an expand-up 32-bit data segment.
+			 */
+			seg_desc.type = 3;
+			seg_desc.p = 1;
+			seg_desc.s = 1;
+			seg_desc.dpl = cpl;
+			seg_desc.d = 1;
+			seg_desc.g = 1;
+		}
+
+		/* Skip all following checks */
 		goto load;
+	}
 
 	ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr);
 	if (ret != X86EMUL_CONTINUE)
@@ -1677,8 +1740,7 @@
 				return ret;
 		}
 	} else if (ctxt->mode == X86EMUL_MODE_PROT64) {
-		ret = ctxt->ops->read_std(ctxt, desc_addr+8, &base3,
-				sizeof(base3), &ctxt->exception);
+		ret = linear_read_system(ctxt, desc_addr+8, &base3, sizeof(base3));
 		if (ret != X86EMUL_CONTINUE)
 			return ret;
 		if (is_noncanonical_address(get_desc_base(&seg_desc) |
@@ -1698,6 +1760,21 @@
 				   u16 selector, int seg)
 {
 	u8 cpl = ctxt->ops->cpl(ctxt);
+
+	/*
+	 * None of MOV, POP and LSS can load a NULL selector in CPL=3, but
+	 * they can load it at CPL<3 (Intel's manual says only LSS can,
+	 * but it's wrong).
+	 *
+	 * However, the Intel manual says that putting IST=1/DPL=3 in
+	 * an interrupt gate will result in SS=3 (the AMD manual instead
+	 * says it doesn't), so allow SS=3 in __load_segment_descriptor
+	 * and only forbid it here.
+	 */
+	if (seg == VCPU_SREG_SS && selector == 3 &&
+	    ctxt->mode == X86EMUL_MODE_PROT64)
+		return emulate_exception(ctxt, GP_VECTOR, 0, true);
+
 	return __load_segment_descriptor(ctxt, selector, seg, cpl,
 					 X86_TRANSFER_NONE, NULL);
 }
@@ -1976,11 +2053,11 @@
 	eip_addr = dt.address + (irq << 2);
 	cs_addr = dt.address + (irq << 2) + 2;
 
-	rc = ops->read_std(ctxt, cs_addr, &cs, 2, &ctxt->exception);
+	rc = linear_read_system(ctxt, cs_addr, &cs, 2);
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
-	rc = ops->read_std(ctxt, eip_addr, &eip, 2, &ctxt->exception);
+	rc = linear_read_system(ctxt, eip_addr, &eip, 2);
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
@@ -2093,16 +2170,10 @@
 static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
 {
 	int rc;
-	unsigned short sel, old_sel;
-	struct desc_struct old_desc, new_desc;
-	const struct x86_emulate_ops *ops = ctxt->ops;
+	unsigned short sel;
+	struct desc_struct new_desc;
 	u8 cpl = ctxt->ops->cpl(ctxt);
 
-	/* Assignment of RIP may only fail in 64-bit mode */
-	if (ctxt->mode == X86EMUL_MODE_PROT64)
-		ops->get_segment(ctxt, &old_sel, &old_desc, NULL,
-				 VCPU_SREG_CS);
-
 	memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2);
 
 	rc = __load_segment_descriptor(ctxt, sel, VCPU_SREG_CS, cpl,
@@ -2112,12 +2183,10 @@
 		return rc;
 
 	rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
-	if (rc != X86EMUL_CONTINUE) {
-		WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
-		/* assigning eip failed; restore the old cs */
-		ops->set_segment(ctxt, old_sel, &old_desc, 0, VCPU_SREG_CS);
-		return rc;
-	}
+	/* Error handling is not implemented. */
+	if (rc != X86EMUL_CONTINUE)
+		return X86EMUL_UNHANDLEABLE;
+
 	return rc;
 }
 
@@ -2177,14 +2246,8 @@
 {
 	int rc;
 	unsigned long eip, cs;
-	u16 old_cs;
 	int cpl = ctxt->ops->cpl(ctxt);
-	struct desc_struct old_desc, new_desc;
-	const struct x86_emulate_ops *ops = ctxt->ops;
-
-	if (ctxt->mode == X86EMUL_MODE_PROT64)
-		ops->get_segment(ctxt, &old_cs, &old_desc, NULL,
-				 VCPU_SREG_CS);
+	struct desc_struct new_desc;
 
 	rc = emulate_pop(ctxt, &eip, ctxt->op_bytes);
 	if (rc != X86EMUL_CONTINUE)
@@ -2201,10 +2264,10 @@
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 	rc = assign_eip_far(ctxt, eip, &new_desc);
-	if (rc != X86EMUL_CONTINUE) {
-		WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
-		ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
-	}
+	/* Error handling is not implemented. */
+	if (rc != X86EMUL_CONTINUE)
+		return X86EMUL_UNHANDLEABLE;
+
 	return rc;
 }
 
@@ -2331,9 +2394,21 @@
 }
 
 static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt,
-				     u64 cr0, u64 cr4)
+				    u64 cr0, u64 cr3, u64 cr4)
 {
 	int bad;
+	u64 pcid;
+
+	/* In order to later set CR4.PCIDE, CR3[11:0] must be zero.  */
+	pcid = 0;
+	if (cr4 & X86_CR4_PCIDE) {
+		pcid = cr3 & 0xfff;
+		cr3 &= ~0xfff;
+	}
+
+	bad = ctxt->ops->set_cr(ctxt, 3, cr3);
+	if (bad)
+		return X86EMUL_UNHANDLEABLE;
 
 	/*
 	 * First enable PAE, long mode needs it before CR0.PG = 1 is set.
@@ -2352,6 +2427,12 @@
 		bad = ctxt->ops->set_cr(ctxt, 4, cr4);
 		if (bad)
 			return X86EMUL_UNHANDLEABLE;
+		if (pcid) {
+			bad = ctxt->ops->set_cr(ctxt, 3, cr3 | pcid);
+			if (bad)
+				return X86EMUL_UNHANDLEABLE;
+		}
+
 	}
 
 	return X86EMUL_CONTINUE;
@@ -2362,11 +2443,11 @@
 	struct desc_struct desc;
 	struct desc_ptr dt;
 	u16 selector;
-	u32 val, cr0, cr4;
+	u32 val, cr0, cr3, cr4;
 	int i;
 
 	cr0 =                      GET_SMSTATE(u32, smbase, 0x7ffc);
-	ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u32, smbase, 0x7ff8));
+	cr3 =                      GET_SMSTATE(u32, smbase, 0x7ff8);
 	ctxt->eflags =             GET_SMSTATE(u32, smbase, 0x7ff4) | X86_EFLAGS_FIXED;
 	ctxt->_eip =               GET_SMSTATE(u32, smbase, 0x7ff0);
 
@@ -2408,14 +2489,14 @@
 
 	ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7ef8));
 
-	return rsm_enter_protected_mode(ctxt, cr0, cr4);
+	return rsm_enter_protected_mode(ctxt, cr0, cr3, cr4);
 }
 
 static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
 {
 	struct desc_struct desc;
 	struct desc_ptr dt;
-	u64 val, cr0, cr4;
+	u64 val, cr0, cr3, cr4;
 	u32 base3;
 	u16 selector;
 	int i, r;
@@ -2432,7 +2513,7 @@
 	ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1);
 
 	cr0 =                       GET_SMSTATE(u64, smbase, 0x7f58);
-	ctxt->ops->set_cr(ctxt, 3,  GET_SMSTATE(u64, smbase, 0x7f50));
+	cr3 =                       GET_SMSTATE(u64, smbase, 0x7f50);
 	cr4 =                       GET_SMSTATE(u64, smbase, 0x7f48);
 	ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7f00));
 	val =                       GET_SMSTATE(u64, smbase, 0x7ed0);
@@ -2460,7 +2541,7 @@
 	dt.address =                GET_SMSTATE(u64, smbase, 0x7e68);
 	ctxt->ops->set_gdt(ctxt, &dt);
 
-	r = rsm_enter_protected_mode(ctxt, cr0, cr4);
+	r = rsm_enter_protected_mode(ctxt, cr0, cr3, cr4);
 	if (r != X86EMUL_CONTINUE)
 		return r;
 
@@ -2479,7 +2560,7 @@
 	u64 smbase;
 	int ret;
 
-	if ((ctxt->emul_flags & X86EMUL_SMM_MASK) == 0)
+	if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_MASK) == 0)
 		return emulate_ud(ctxt);
 
 	/*
@@ -2487,15 +2568,13 @@
 	 * CR0/CR3/CR4/EFER.  It's all a bit more complicated if the vCPU
 	 * supports long mode.
 	 */
-	cr4 = ctxt->ops->get_cr(ctxt, 4);
 	if (emulator_has_longmode(ctxt)) {
 		struct desc_struct cs_desc;
 
 		/* Zero CR4.PCIDE before CR0.PG.  */
-		if (cr4 & X86_CR4_PCIDE) {
+		cr4 = ctxt->ops->get_cr(ctxt, 4);
+		if (cr4 & X86_CR4_PCIDE)
 			ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PCIDE);
-			cr4 &= ~X86_CR4_PCIDE;
-		}
 
 		/* A 32-bit code segment is required to clear EFER.LMA.  */
 		memset(&cs_desc, 0, sizeof(cs_desc));
@@ -2509,13 +2588,16 @@
 	if (cr0 & X86_CR0_PE)
 		ctxt->ops->set_cr(ctxt, 0, cr0 & ~(X86_CR0_PG | X86_CR0_PE));
 
-	/* Now clear CR4.PAE (which must be done before clearing EFER.LME).  */
-	if (cr4 & X86_CR4_PAE)
-		ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PAE);
-
-	/* And finally go back to 32-bit mode.  */
-	efer = 0;
-	ctxt->ops->set_msr(ctxt, MSR_EFER, efer);
+	if (emulator_has_longmode(ctxt)) {
+		/* Clear CR4.PAE before clearing EFER.LME. */
+		cr4 = ctxt->ops->get_cr(ctxt, 4);
+		if (cr4 & X86_CR4_PAE)
+			ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PAE);
+
+		/* And finally go back to 32-bit mode.  */
+		efer = 0;
+		ctxt->ops->set_msr(ctxt, MSR_EFER, efer);
+	}
 
 	smbase = ctxt->ops->get_smbase(ctxt);
 	if (emulator_has_longmode(ctxt))
@@ -2528,11 +2610,11 @@
 		return X86EMUL_UNHANDLEABLE;
 	}
 
-	if ((ctxt->emul_flags & X86EMUL_SMM_INSIDE_NMI_MASK) == 0)
+	if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_INSIDE_NMI_MASK) == 0)
 		ctxt->ops->set_nmi_mask(ctxt, false);
 
-	ctxt->emul_flags &= ~X86EMUL_SMM_INSIDE_NMI_MASK;
-	ctxt->emul_flags &= ~X86EMUL_SMM_MASK;
+	ctxt->ops->set_hflags(ctxt, ctxt->ops->get_hflags(ctxt) &
+		~(X86EMUL_SMM_INSIDE_NMI_MASK | X86EMUL_SMM_MASK));
 	return X86EMUL_CONTINUE;
 }
 
@@ -2674,6 +2756,7 @@
 		ctxt->eflags &= ~(X86_EFLAGS_VM | X86_EFLAGS_IF);
 	}
 
+	ctxt->tf = (ctxt->eflags & X86_EFLAGS_TF) != 0;
 	return X86EMUL_CONTINUE;
 }
 
@@ -2819,12 +2902,12 @@
 #ifdef CONFIG_X86_64
 	base |= ((u64)base3) << 32;
 #endif
-	r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL);
+	r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true);
 	if (r != X86EMUL_CONTINUE)
 		return false;
 	if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))
 		return false;
-	r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL);
+	r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, true);
 	if (r != X86EMUL_CONTINUE)
 		return false;
 	if ((perm >> bit_idx) & mask)
@@ -2953,35 +3036,30 @@
 			  u16 tss_selector, u16 old_tss_sel,
 			  ulong old_tss_base, struct desc_struct *new_desc)
 {
-	const struct x86_emulate_ops *ops = ctxt->ops;
 	struct tss_segment_16 tss_seg;
 	int ret;
 	u32 new_tss_base = get_desc_base(new_desc);
 
-	ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg,
-			    &ctxt->exception);
+	ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg);
 	if (ret != X86EMUL_CONTINUE)
 		return ret;
 
 	save_state_to_tss16(ctxt, &tss_seg);
 
-	ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg,
-			     &ctxt->exception);
+	ret = linear_write_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg);
 	if (ret != X86EMUL_CONTINUE)
 		return ret;
 
-	ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg,
-			    &ctxt->exception);
+	ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg);
 	if (ret != X86EMUL_CONTINUE)
 		return ret;
 
 	if (old_tss_sel != 0xffff) {
 		tss_seg.prev_task_link = old_tss_sel;
 
-		ret = ops->write_std(ctxt, new_tss_base,
-				     &tss_seg.prev_task_link,
-				     sizeof tss_seg.prev_task_link,
-				     &ctxt->exception);
+		ret = linear_write_system(ctxt, new_tss_base,
+					  &tss_seg.prev_task_link,
+					  sizeof tss_seg.prev_task_link);
 		if (ret != X86EMUL_CONTINUE)
 			return ret;
 	}
@@ -3097,38 +3175,34 @@
 			  u16 tss_selector, u16 old_tss_sel,
 			  ulong old_tss_base, struct desc_struct *new_desc)
 {
-	const struct x86_emulate_ops *ops = ctxt->ops;
 	struct tss_segment_32 tss_seg;
 	int ret;
 	u32 new_tss_base = get_desc_base(new_desc);
 	u32 eip_offset = offsetof(struct tss_segment_32, eip);
 	u32 ldt_sel_offset = offsetof(struct tss_segment_32, ldt_selector);
 
-	ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg,
-			    &ctxt->exception);
+	ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg);
 	if (ret != X86EMUL_CONTINUE)
 		return ret;
 
 	save_state_to_tss32(ctxt, &tss_seg);
 
 	/* Only GP registers and segment selectors are saved */
-	ret = ops->write_std(ctxt, old_tss_base + eip_offset, &tss_seg.eip,
-			     ldt_sel_offset - eip_offset, &ctxt->exception);
+	ret = linear_write_system(ctxt, old_tss_base + eip_offset, &tss_seg.eip,
+				  ldt_sel_offset - eip_offset);
 	if (ret != X86EMUL_CONTINUE)
 		return ret;
 
-	ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg,
-			    &ctxt->exception);
+	ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg);
 	if (ret != X86EMUL_CONTINUE)
 		return ret;
 
 	if (old_tss_sel != 0xffff) {
 		tss_seg.prev_task_link = old_tss_sel;
 
-		ret = ops->write_std(ctxt, new_tss_base,
-				     &tss_seg.prev_task_link,
-				     sizeof tss_seg.prev_task_link,
-				     &ctxt->exception);
+		ret = linear_write_system(ctxt, new_tss_base,
+					  &tss_seg.prev_task_link,
+					  sizeof tss_seg.prev_task_link);
 		if (ret != X86EMUL_CONTINUE)
 			return ret;
 	}
@@ -3445,6 +3519,16 @@
 	return X86EMUL_CONTINUE;
 }
 
+static int em_rdpid(struct x86_emulate_ctxt *ctxt)
+{
+	u64 tsc_aux = 0;
+
+	if (ctxt->ops->get_msr(ctxt, MSR_TSC_AUX, &tsc_aux))
+		return emulate_ud(ctxt);
+	ctxt->dst.val = tsc_aux;
+	return X86EMUL_CONTINUE;
+}
+
 static int em_rdtsc(struct x86_emulate_ctxt *ctxt)
 {
 	u64 tsc = 0;
@@ -3660,8 +3744,8 @@
 	}
 	/* Disable writeback. */
 	ctxt->dst.type = OP_NONE;
-	return segmented_write(ctxt, ctxt->dst.addr.mem,
-			       &desc_ptr, 2 + ctxt->op_bytes);
+	return segmented_write_std(ctxt, ctxt->dst.addr.mem,
+				   &desc_ptr, 2 + ctxt->op_bytes);
 }
 
 static int em_sgdt(struct x86_emulate_ctxt *ctxt)
@@ -3838,12 +3922,143 @@
 	return X86EMUL_CONTINUE;
 }
 
+static int em_clflushopt(struct x86_emulate_ctxt *ctxt)
+{
+	/* emulating clflushopt regardless of cpuid */
+	return X86EMUL_CONTINUE;
+}
+
 static int em_movsxd(struct x86_emulate_ctxt *ctxt)
 {
 	ctxt->dst.val = (s32) ctxt->src.val;
 	return X86EMUL_CONTINUE;
 }
 
+static int check_fxsr(struct x86_emulate_ctxt *ctxt)
+{
+	u32 eax = 1, ebx, ecx = 0, edx;
+
+	ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+	if (!(edx & FFL(FXSR)))
+		return emulate_ud(ctxt);
+
+	if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
+		return emulate_nm(ctxt);
+
+	/*
+	 * Don't emulate a case that should never be hit, instead of working
+	 * around a lack of fxsave64/fxrstor64 on old compilers.
+	 */
+	if (ctxt->mode >= X86EMUL_MODE_PROT64)
+		return X86EMUL_UNHANDLEABLE;
+
+	return X86EMUL_CONTINUE;
+}
+
+/*
+ * FXSAVE and FXRSTOR have 4 different formats depending on execution mode,
+ *  1) 16 bit mode
+ *  2) 32 bit mode
+ *     - like (1), but FIP and FDP (foo) are only 16 bit.  At least Intel CPUs
+ *       preserve whole 32 bit values, though, so (1) and (2) are the same wrt.
+ *       save and restore
+ *  3) 64-bit mode with REX.W prefix
+ *     - like (2), but XMM 8-15 are being saved and restored
+ *  4) 64-bit mode without REX.W prefix
+ *     - like (3), but FIP and FDP are 64 bit
+ *
+ * Emulation uses (3) for (1) and (2) and preserves XMM 8-15 to reach the
+ * desired result.  (4) is not emulated.
+ *
+ * Note: Guest and host CPUID.(EAX=07H,ECX=0H):EBX[bit 13] (deprecate FPU CS
+ * and FPU DS) should match.
+ */
+static int em_fxsave(struct x86_emulate_ctxt *ctxt)
+{
+	struct fxregs_state fx_state;
+	size_t size;
+	int rc;
+
+	rc = check_fxsr(ctxt);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	ctxt->ops->get_fpu(ctxt);
+
+	rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_state));
+
+	ctxt->ops->put_fpu(ctxt);
+
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	if (ctxt->ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR)
+		size = offsetof(struct fxregs_state, xmm_space[8 * 16/4]);
+	else
+		size = offsetof(struct fxregs_state, xmm_space[0]);
+
+	return segmented_write_std(ctxt, ctxt->memop.addr.mem, &fx_state, size);
+}
+
+static int fxrstor_fixup(struct x86_emulate_ctxt *ctxt,
+		struct fxregs_state *new)
+{
+	int rc = X86EMUL_CONTINUE;
+	struct fxregs_state old;
+
+	rc = asm_safe("fxsave %[fx]", , [fx] "+m"(old));
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	/*
+	 * 64 bit host will restore XMM 8-15, which is not correct on non-64
+	 * bit guests.  Load the current values in order to preserve 64 bit
+	 * XMMs after fxrstor.
+	 */
+#ifdef CONFIG_X86_64
+	/* XXX: accessing XMM 8-15 very awkwardly */
+	memcpy(&new->xmm_space[8 * 16/4], &old.xmm_space[8 * 16/4], 8 * 16);
+#endif
+
+	/*
+	 * Hardware doesn't save and restore XMM 0-7 without CR4.OSFXSR, but
+	 * does save and restore MXCSR.
+	 */
+	if (!(ctxt->ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))
+		memcpy(new->xmm_space, old.xmm_space, 8 * 16);
+
+	return rc;
+}
+
+static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
+{
+	struct fxregs_state fx_state;
+	int rc;
+
+	rc = check_fxsr(ctxt);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	rc = segmented_read_std(ctxt, ctxt->memop.addr.mem, &fx_state, 512);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	if (fx_state.mxcsr >> 16)
+		return emulate_gp(ctxt, 0);
+
+	ctxt->ops->get_fpu(ctxt);
+
+	if (ctxt->mode < X86EMUL_MODE_PROT64)
+		rc = fxrstor_fixup(ctxt, &fx_state);
+
+	if (rc == X86EMUL_CONTINUE)
+		rc = asm_safe("fxrstor %[fx]", : [fx] "m"(fx_state));
+
+	ctxt->ops->put_fpu(ctxt);
+
+	return rc;
+}
+
 static bool valid_cr(int nr)
 {
 	switch (nr) {
@@ -4180,10 +4395,20 @@
 	F(DstMem | SrcImmByte | Lock | PageTable,	em_btc),
 };
 
+/*
+ * The "memory" destination is actually always a register, since we come
+ * from the register case of group9.
+ */
+static const struct gprefix pfx_0f_c7_7 = {
+	N, N, N, II(DstMem | ModRM | Op3264 | EmulateOnUD, em_rdpid, rdtscp),
+};
+
+
 static const struct group_dual group9 = { {
 	N, I(DstMem64 | Lock | PageTable, em_cmpxchg8b), N, N, N, N, N, N,
 }, {
-	N, N, N, N, N, N, N, N,
+	N, N, N, N, N, N, N,
+	GP(0, &pfx_0f_c7_7),
 } };
 
 static const struct opcode group11[] = {
@@ -4192,11 +4417,13 @@
 };
 
 static const struct gprefix pfx_0f_ae_7 = {
-	I(SrcMem | ByteOp, em_clflush), N, N, N,
+	I(SrcMem | ByteOp, em_clflush), I(SrcMem | ByteOp, em_clflushopt), N, N,
 };
 
 static const struct group_dual group15 = { {
-	N, N, N, N, N, N, N, GP(0, &pfx_0f_ae_7),
+	I(ModRM | Aligned16, em_fxsave),
+	I(ModRM | Aligned16, em_fxrstor),
+	N, N, N, N, N, GP(0, &pfx_0f_ae_7),
 }, {
 	N, N, N, N, N, N, N, N,
 } };
@@ -4780,6 +5007,8 @@
 	bool op_prefix = false;
 	bool has_seg_override = false;
 	struct opcode opcode;
+	u16 dummy;
+	struct desc_struct desc;
 
 	ctxt->memop.type = OP_NONE;
 	ctxt->memopp = NULL;
@@ -4787,6 +5016,7 @@
 	ctxt->fetch.ptr = ctxt->fetch.data;
 	ctxt->fetch.end = ctxt->fetch.data + insn_len;
 	ctxt->opcode_len = 1;
+	ctxt->intercept = x86_intercept_none;
 	if (insn_len > 0)
 		memcpy(ctxt->fetch.data, insn, insn_len);
 	else {
@@ -4798,6 +5028,11 @@
 	switch (mode) {
 	case X86EMUL_MODE_REAL:
 	case X86EMUL_MODE_VM86:
+		def_op_bytes = def_ad_bytes = 2;
+		ctxt->ops->get_segment(ctxt, &dummy, &desc, NULL, VCPU_SREG_CS);
+		if (desc.d)
+			def_op_bytes = def_ad_bytes = 4;
+		break;
 	case X86EMUL_MODE_PROT16:
 		def_op_bytes = def_ad_bytes = 2;
 		break;
@@ -4834,16 +5069,28 @@
 				ctxt->ad_bytes = def_ad_bytes ^ 6;
 			break;
 		case 0x26:	/* ES override */
+			has_seg_override = true;
+			ctxt->seg_override = VCPU_SREG_ES;
+			break;
 		case 0x2e:	/* CS override */
+			has_seg_override = true;
+			ctxt->seg_override = VCPU_SREG_CS;
+			break;
 		case 0x36:	/* SS override */
+			has_seg_override = true;
+			ctxt->seg_override = VCPU_SREG_SS;
+			break;
 		case 0x3e:	/* DS override */
 			has_seg_override = true;
-			ctxt->seg_override = (ctxt->b >> 3) & 3;
+			ctxt->seg_override = VCPU_SREG_DS;
 			break;
 		case 0x64:	/* FS override */
+			has_seg_override = true;
+			ctxt->seg_override = VCPU_SREG_FS;
+			break;
 		case 0x65:	/* GS override */
 			has_seg_override = true;
-			ctxt->seg_override = ctxt->b & 7;
+			ctxt->seg_override = VCPU_SREG_GS;
 			break;
 		case 0x40 ... 0x4f: /* REX */
 			if (mode != X86EMUL_MODE_PROT64)
@@ -4927,10 +5174,15 @@
 			}
 			break;
 		case Escape:
-			if (ctxt->modrm > 0xbf)
-				opcode = opcode.u.esc->high[ctxt->modrm - 0xc0];
-			else
+			if (ctxt->modrm > 0xbf) {
+				size_t size = ARRAY_SIZE(opcode.u.esc->high);
+				u32 index = array_index_nospec(
+					ctxt->modrm - 0xc0, size);
+
+				opcode = opcode.u.esc->high[index];
+			} else {
 				opcode = opcode.u.esc->op[(ctxt->modrm >> 3) & 7];
+			}
 			break;
 		case InstrDual:
 			if ((ctxt->modrm >> 6) == 3)
@@ -5033,11 +5285,13 @@
 	/* Decode and fetch the destination operand: register or memory. */
 	rc = decode_operand(ctxt, &ctxt->dst, (ctxt->d >> DstShift) & OpMask);
 
-	if (ctxt->rip_relative)
+	if (ctxt->rip_relative && likely(ctxt->memopp))
 		ctxt->memopp->addr.mem.ea = address_mask(ctxt,
 					ctxt->memopp->addr.mem.ea + ctxt->_eip);
 
 done:
+	if (rc == X86EMUL_PROPAGATE_FAULT)
+		ctxt->have_exception = true;
 	return (rc != X86EMUL_CONTINUE) ? EMULATION_FAILED : EMULATION_OK;
 }
 
@@ -5068,21 +5322,13 @@
 
 static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt)
 {
-	bool fault = false;
+	int rc;
 
 	ctxt->ops->get_fpu(ctxt);
-	asm volatile("1: fwait \n\t"
-		     "2: \n\t"
-		     ".pushsection .fixup,\"ax\" \n\t"
-		     "3: \n\t"
-		     "movb $1, %[fault] \n\t"
-		     "jmp 2b \n\t"
-		     ".popsection \n\t"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [fault]"+qm"(fault));
+	rc = asm_safe("fwait");
 	ctxt->ops->put_fpu(ctxt);
 
-	if (unlikely(fault))
+	if (unlikely(rc != X86EMUL_CONTINUE))
 		return emulate_exception(ctxt, MF_VECTOR, 0, false);
 
 	return X86EMUL_CONTINUE;
@@ -5100,9 +5346,9 @@
 	ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
 	if (!(ctxt->d & ByteOp))
 		fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
-	asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
+	asm("push %[flags]; popf; " CALL_NOSPEC " ; pushf; pop %[flags]\n"
 	    : "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags),
-	      [fastop]"+S"(fop)
+	      [thunk_target]"+S"(fop)
 	    : "c"(ctxt->src2.val));
 	ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);
 	if (!fop) /* exception is returned in fop variable */
@@ -5125,6 +5371,7 @@
 	const struct x86_emulate_ops *ops = ctxt->ops;
 	int rc = X86EMUL_CONTINUE;
 	int saved_dst_type = ctxt->dst.type;
+	unsigned emul_flags;
 
 	ctxt->mem_read.pos = 0;
 
@@ -5139,6 +5386,7 @@
 		goto done;
 	}
 
+	emul_flags = ctxt->ops->get_hflags(ctxt);
 	if (unlikely(ctxt->d &
 		     (No64|Undefined|Sse|Mmx|Intercept|CheckPerm|Priv|Prot|String))) {
 		if ((ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) ||
@@ -5172,7 +5420,7 @@
 				fetch_possible_mmx_operand(ctxt, &ctxt->dst);
 		}
 
-		if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) {
+		if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) {
 			rc = emulator_check_intercept(ctxt, ctxt->intercept,
 						      X86_ICPT_PRE_EXCEPT);
 			if (rc != X86EMUL_CONTINUE)
@@ -5201,7 +5449,7 @@
 				goto done;
 		}
 
-		if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) {
+		if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) {
 			rc = emulator_check_intercept(ctxt, ctxt->intercept,
 						      X86_ICPT_POST_EXCEPT);
 			if (rc != X86EMUL_CONTINUE)
@@ -5255,7 +5503,7 @@
 
 special_insn:
 
-	if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) {
+	if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) {
 		rc = emulator_check_intercept(ctxt, ctxt->intercept,
 					      X86_ICPT_POST_MEMACCESS);
 		if (rc != X86EMUL_CONTINUE)
--- linux-4.4.0.orig/arch/x86/kvm/hyperv.c
+++ linux-4.4.0/arch/x86/kvm/hyperv.c
@@ -23,13 +23,647 @@
 
 #include "x86.h"
 #include "lapic.h"
+#include "ioapic.h"
 #include "hyperv.h"
 
 #include <linux/kvm_host.h>
+#include <linux/highmem.h>
+#include <asm/apicdef.h>
+#include <linux/nospec.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
 
+static inline u64 synic_read_sint(struct kvm_vcpu_hv_synic *synic, int sint)
+{
+	return atomic64_read(&synic->sint[sint]);
+}
+
+static inline int synic_get_sint_vector(u64 sint_value)
+{
+	if (sint_value & HV_SYNIC_SINT_MASKED)
+		return -1;
+	return sint_value & HV_SYNIC_SINT_VECTOR_MASK;
+}
+
+static bool synic_has_vector_connected(struct kvm_vcpu_hv_synic *synic,
+				      int vector)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+		if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector)
+			return true;
+	}
+	return false;
+}
+
+static bool synic_has_vector_auto_eoi(struct kvm_vcpu_hv_synic *synic,
+				     int vector)
+{
+	int i;
+	u64 sint_value;
+
+	for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+		sint_value = synic_read_sint(synic, i);
+		if (synic_get_sint_vector(sint_value) == vector &&
+		    sint_value & HV_SYNIC_SINT_AUTO_EOI)
+			return true;
+	}
+	return false;
+}
+
+static int synic_set_sint(struct kvm_vcpu_hv_synic *synic, int sint, u64 data)
+{
+	int vector;
+
+	vector = data & HV_SYNIC_SINT_VECTOR_MASK;
+	if (vector < 16)
+		return 1;
+	/*
+	 * Guest may configure multiple SINTs to use the same vector, so
+	 * we maintain a bitmap of vectors handled by synic, and a
+	 * bitmap of vectors with auto-eoi behavior.  The bitmaps are
+	 * updated here, and atomically queried on fast paths.
+	 */
+
+	atomic64_set(&synic->sint[sint], data);
+
+	if (synic_has_vector_connected(synic, vector))
+		__set_bit(vector, synic->vec_bitmap);
+	else
+		__clear_bit(vector, synic->vec_bitmap);
+
+	if (synic_has_vector_auto_eoi(synic, vector))
+		__set_bit(vector, synic->auto_eoi_bitmap);
+	else
+		__clear_bit(vector, synic->auto_eoi_bitmap);
+
+	/* Load SynIC vectors into EOI exit bitmap */
+	kvm_make_request(KVM_REQ_SCAN_IOAPIC, synic_to_vcpu(synic));
+	return 0;
+}
+
+static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vcpu_id)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vcpu_hv_synic *synic;
+
+	if (vcpu_id >= atomic_read(&kvm->online_vcpus))
+		return NULL;
+	vcpu = kvm_get_vcpu(kvm, vcpu_id);
+	if (!vcpu)
+		return NULL;
+	synic = vcpu_to_synic(vcpu);
+	return (synic->active) ? synic : NULL;
+}
+
+static void synic_clear_sint_msg_pending(struct kvm_vcpu_hv_synic *synic,
+					u32 sint)
+{
+	struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+	struct page *page;
+	gpa_t gpa;
+	struct hv_message *msg;
+	struct hv_message_page *msg_page;
+
+	gpa = synic->msg_page & PAGE_MASK;
+	page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT);
+	if (is_error_page(page)) {
+		vcpu_err(vcpu, "Hyper-V SynIC can't get msg page, gpa 0x%llx\n",
+			 gpa);
+		return;
+	}
+	msg_page = kmap_atomic(page);
+
+	msg = &msg_page->sint_message[sint];
+	msg->header.message_flags.msg_pending = 0;
+
+	kunmap_atomic(msg_page);
+	kvm_release_page_dirty(page);
+	kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
+}
+
+static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+	struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+	struct kvm_vcpu_hv_stimer *stimer;
+	int gsi, idx, stimers_pending;
+
+	vcpu_debug(vcpu, "Hyper-V SynIC acked sint %d\n", sint);
+
+	if (synic->msg_page & HV_SYNIC_SIMP_ENABLE)
+		synic_clear_sint_msg_pending(synic, sint);
+
+	/* Try to deliver pending Hyper-V SynIC timers messages */
+	stimers_pending = 0;
+	for (idx = 0; idx < ARRAY_SIZE(hv_vcpu->stimer); idx++) {
+		stimer = &hv_vcpu->stimer[idx];
+		if (stimer->msg_pending &&
+		    (stimer->config & HV_STIMER_ENABLE) &&
+		    HV_STIMER_SINT(stimer->config) == sint) {
+			set_bit(stimer->index,
+				hv_vcpu->stimer_pending_bitmap);
+			stimers_pending++;
+		}
+	}
+	if (stimers_pending)
+		kvm_make_request(KVM_REQ_HV_STIMER, vcpu);
+
+	idx = srcu_read_lock(&kvm->irq_srcu);
+	gsi = atomic_read(&synic->sint_to_gsi[sint]);
+	if (gsi != -1)
+		kvm_notify_acked_gsi(kvm, gsi);
+	srcu_read_unlock(&kvm->irq_srcu, idx);
+}
+
+static void synic_exit(struct kvm_vcpu_hv_synic *synic, u32 msr)
+{
+	struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+	struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv;
+
+	hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNIC;
+	hv_vcpu->exit.u.synic.msr = msr;
+	hv_vcpu->exit.u.synic.control = synic->control;
+	hv_vcpu->exit.u.synic.evt_page = synic->evt_page;
+	hv_vcpu->exit.u.synic.msg_page = synic->msg_page;
+
+	kvm_make_request(KVM_REQ_HV_EXIT, vcpu);
+}
+
+static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
+			 u32 msr, u64 data, bool host)
+{
+	struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+	int ret;
+
+	if (!synic->active)
+		return 1;
+
+	vcpu_debug(vcpu, "Hyper-V SynIC set msr 0x%x 0x%llx host %d\n",
+		   msr, data, host);
+	ret = 0;
+	switch (msr) {
+	case HV_X64_MSR_SCONTROL:
+		synic->control = data;
+		if (!host)
+			synic_exit(synic, msr);
+		break;
+	case HV_X64_MSR_SVERSION:
+		if (!host) {
+			ret = 1;
+			break;
+		}
+		synic->version = data;
+		break;
+	case HV_X64_MSR_SIEFP:
+		if (data & HV_SYNIC_SIEFP_ENABLE)
+			if (kvm_clear_guest(vcpu->kvm,
+					    data & PAGE_MASK, PAGE_SIZE)) {
+				ret = 1;
+				break;
+			}
+		synic->evt_page = data;
+		if (!host)
+			synic_exit(synic, msr);
+		break;
+	case HV_X64_MSR_SIMP:
+		if (data & HV_SYNIC_SIMP_ENABLE)
+			if (kvm_clear_guest(vcpu->kvm,
+					    data & PAGE_MASK, PAGE_SIZE)) {
+				ret = 1;
+				break;
+			}
+		synic->msg_page = data;
+		if (!host)
+			synic_exit(synic, msr);
+		break;
+	case HV_X64_MSR_EOM: {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(synic->sint); i++)
+			kvm_hv_notify_acked_sint(vcpu, i);
+		break;
+	}
+	case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+		ret = synic_set_sint(synic, msr - HV_X64_MSR_SINT0, data);
+		break;
+	default:
+		ret = 1;
+		break;
+	}
+	return ret;
+}
+
+static int synic_get_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 *pdata)
+{
+	int ret;
+
+	if (!synic->active)
+		return 1;
+
+	ret = 0;
+	switch (msr) {
+	case HV_X64_MSR_SCONTROL:
+		*pdata = synic->control;
+		break;
+	case HV_X64_MSR_SVERSION:
+		*pdata = synic->version;
+		break;
+	case HV_X64_MSR_SIEFP:
+		*pdata = synic->evt_page;
+		break;
+	case HV_X64_MSR_SIMP:
+		*pdata = synic->msg_page;
+		break;
+	case HV_X64_MSR_EOM:
+		*pdata = 0;
+		break;
+	case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+		*pdata = atomic64_read(&synic->sint[msr - HV_X64_MSR_SINT0]);
+		break;
+	default:
+		ret = 1;
+		break;
+	}
+	return ret;
+}
+
+int synic_set_irq(struct kvm_vcpu_hv_synic *synic, u32 sint)
+{
+	struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+	struct kvm_lapic_irq irq;
+	int ret, vector;
+
+	if (sint >= ARRAY_SIZE(synic->sint))
+		return -EINVAL;
+
+	vector = synic_get_sint_vector(synic_read_sint(synic, sint));
+	if (vector < 0)
+		return -ENOENT;
+
+	memset(&irq, 0, sizeof(irq));
+	irq.dest_id = kvm_apic_id(vcpu->arch.apic);
+	irq.dest_mode = APIC_DEST_PHYSICAL;
+	irq.delivery_mode = APIC_DM_FIXED;
+	irq.vector = vector;
+	irq.level = 1;
+
+	ret = kvm_irq_delivery_to_apic(vcpu->kvm, NULL, &irq, NULL);
+	vcpu_debug(vcpu, "Hyper-V SynIC set irq ret %d\n", ret);
+	return ret;
+}
+
+int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint)
+{
+	struct kvm_vcpu_hv_synic *synic;
+
+	synic = synic_get(kvm, vcpu_id);
+	if (!synic)
+		return -EINVAL;
+
+	return synic_set_irq(synic, sint);
+}
+
+void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector)
+{
+	struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+	int i;
+
+	vcpu_debug(vcpu, "Hyper-V SynIC send eoi vec %d\n", vector);
+
+	for (i = 0; i < ARRAY_SIZE(synic->sint); i++)
+		if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector)
+			kvm_hv_notify_acked_sint(vcpu, i);
+}
+
+static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vcpu_id, u32 sint, int gsi)
+{
+	struct kvm_vcpu_hv_synic *synic;
+
+	synic = synic_get(kvm, vcpu_id);
+	if (!synic)
+		return -EINVAL;
+
+	if (sint >= ARRAY_SIZE(synic->sint_to_gsi))
+		return -EINVAL;
+
+	atomic_set(&synic->sint_to_gsi[sint], gsi);
+	return 0;
+}
+
+void kvm_hv_irq_routing_update(struct kvm *kvm)
+{
+	struct kvm_irq_routing_table *irq_rt;
+	struct kvm_kernel_irq_routing_entry *e;
+	u32 gsi;
+
+	irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu,
+					lockdep_is_held(&kvm->irq_lock));
+
+	for (gsi = 0; gsi < irq_rt->nr_rt_entries; gsi++) {
+		hlist_for_each_entry(e, &irq_rt->map[gsi], link) {
+			if (e->type == KVM_IRQ_ROUTING_HV_SINT)
+				kvm_hv_set_sint_gsi(kvm, e->hv_sint.vcpu,
+						    e->hv_sint.sint, gsi);
+		}
+	}
+}
+
+static void synic_init(struct kvm_vcpu_hv_synic *synic)
+{
+	int i;
+
+	memset(synic, 0, sizeof(*synic));
+	synic->version = HV_SYNIC_VERSION_1;
+	for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+		atomic64_set(&synic->sint[i], HV_SYNIC_SINT_MASKED);
+		atomic_set(&synic->sint_to_gsi[i], -1);
+	}
+}
+
+static u64 get_time_ref_counter(struct kvm *kvm)
+{
+	return div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100);
+}
+
+static void stimer_mark_expired(struct kvm_vcpu_hv_stimer *stimer,
+				bool vcpu_kick)
+{
+	struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+
+	set_bit(stimer->index,
+		vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+	kvm_make_request(KVM_REQ_HV_STIMER, vcpu);
+	if (vcpu_kick)
+		kvm_vcpu_kick(vcpu);
+}
+
+static void stimer_stop(struct kvm_vcpu_hv_stimer *stimer)
+{
+	hrtimer_cancel(&stimer->timer);
+}
+
+static void stimer_cleanup(struct kvm_vcpu_hv_stimer *stimer)
+{
+	struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+
+	stimer_stop(stimer);
+	clear_bit(stimer->index,
+		  vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+	stimer->msg_pending = false;
+}
+
+static enum hrtimer_restart stimer_timer_callback(struct hrtimer *timer)
+{
+	struct kvm_vcpu_hv_stimer *stimer;
+
+	stimer = container_of(timer, struct kvm_vcpu_hv_stimer, timer);
+	stimer_mark_expired(stimer, true);
+
+	return HRTIMER_NORESTART;
+}
+
+static void stimer_restart(struct kvm_vcpu_hv_stimer *stimer)
+{
+	u64 time_now;
+	ktime_t ktime_now;
+	u64 remainder;
+
+	time_now = get_time_ref_counter(stimer_to_vcpu(stimer)->kvm);
+	ktime_now = ktime_get();
+
+	div64_u64_rem(time_now - stimer->exp_time, stimer->count, &remainder);
+	stimer->exp_time = time_now + (stimer->count - remainder);
+
+	hrtimer_start(&stimer->timer,
+		      ktime_add_ns(ktime_now,
+				   100 * (stimer->exp_time - time_now)),
+		      HRTIMER_MODE_ABS);
+}
+
+static int stimer_start(struct kvm_vcpu_hv_stimer *stimer)
+{
+	u64 time_now;
+	ktime_t ktime_now;
+
+	time_now = get_time_ref_counter(stimer_to_vcpu(stimer)->kvm);
+	ktime_now = ktime_get();
+
+	if (stimer->config & HV_STIMER_PERIODIC) {
+		if (stimer->count == 0)
+			return -EINVAL;
+
+		stimer->exp_time = time_now + stimer->count;
+		hrtimer_start(&stimer->timer,
+			      ktime_add_ns(ktime_now, 100 * stimer->count),
+			      HRTIMER_MODE_ABS);
+		return 0;
+	}
+	stimer->exp_time = stimer->count;
+	if (time_now >= stimer->count) {
+		/*
+		 * Expire timer according to Hypervisor Top-Level Functional
+		 * specification v4(15.3.1):
+		 * "If a one shot is enabled and the specified count is in
+		 * the past, it will expire immediately."
+		 */
+		stimer_mark_expired(stimer, false);
+		return 0;
+	}
+
+	hrtimer_start(&stimer->timer,
+		      ktime_add_ns(ktime_now, 100 * (stimer->count - time_now)),
+		      HRTIMER_MODE_ABS);
+	return 0;
+}
+
+static int stimer_set_config(struct kvm_vcpu_hv_stimer *stimer, u64 config,
+			     bool host)
+{
+	if (stimer->count == 0 || HV_STIMER_SINT(config) == 0)
+		config &= ~HV_STIMER_ENABLE;
+	stimer->config = config;
+	stimer_cleanup(stimer);
+	if (stimer->config & HV_STIMER_ENABLE)
+		if (stimer_start(stimer))
+			return 1;
+	return 0;
+}
+
+static int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count,
+			    bool host)
+{
+	stimer->count = count;
+
+	stimer_cleanup(stimer);
+	if (stimer->count == 0)
+		stimer->config &= ~HV_STIMER_ENABLE;
+	else if (stimer->config & HV_STIMER_AUTOENABLE) {
+		stimer->config |= HV_STIMER_ENABLE;
+		if (stimer_start(stimer))
+			return 1;
+	}
+
+	return 0;
+}
+
+static int stimer_get_config(struct kvm_vcpu_hv_stimer *stimer, u64 *pconfig)
+{
+	*pconfig = stimer->config;
+	return 0;
+}
+
+static int stimer_get_count(struct kvm_vcpu_hv_stimer *stimer, u64 *pcount)
+{
+	*pcount = stimer->count;
+	return 0;
+}
+
+static int synic_deliver_msg(struct kvm_vcpu_hv_synic *synic, u32 sint,
+			     struct hv_message *src_msg)
+{
+	struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+	struct page *page;
+	gpa_t gpa;
+	struct hv_message *dst_msg;
+	int r;
+	struct hv_message_page *msg_page;
+
+	if (!(synic->msg_page & HV_SYNIC_SIMP_ENABLE))
+		return -ENOENT;
+
+	gpa = synic->msg_page & PAGE_MASK;
+	page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT);
+	if (is_error_page(page))
+		return -EFAULT;
+
+	msg_page = kmap_atomic(page);
+	dst_msg = &msg_page->sint_message[sint];
+	if (sync_cmpxchg(&dst_msg->header.message_type, HVMSG_NONE,
+			 src_msg->header.message_type) != HVMSG_NONE) {
+		dst_msg->header.message_flags.msg_pending = 1;
+		r = -EAGAIN;
+	} else {
+		memcpy(&dst_msg->u.payload, &src_msg->u.payload,
+		       src_msg->header.payload_size);
+		dst_msg->header.message_type = src_msg->header.message_type;
+		dst_msg->header.payload_size = src_msg->header.payload_size;
+		r = synic_set_irq(synic, sint);
+		if (r >= 1)
+			r = 0;
+		else if (r == 0)
+			r = -EFAULT;
+	}
+	kunmap_atomic(msg_page);
+	kvm_release_page_dirty(page);
+	kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
+	return r;
+}
+
+static void stimer_send_msg(struct kvm_vcpu_hv_stimer *stimer)
+{
+	struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+	struct hv_message *msg = &stimer->msg;
+	struct hv_timer_message_payload *payload =
+			(struct hv_timer_message_payload *)&msg->u.payload;
+	int r;
+
+	stimer->msg_pending = true;
+	payload->expiration_time = stimer->exp_time;
+	payload->delivery_time = get_time_ref_counter(vcpu->kvm);
+	r = synic_deliver_msg(vcpu_to_synic(vcpu),
+			      HV_STIMER_SINT(stimer->config), msg);
+	if (!r)
+		stimer->msg_pending = false;
+}
+
+static void stimer_expiration(struct kvm_vcpu_hv_stimer *stimer)
+{
+	stimer_send_msg(stimer);
+	if (!(stimer->config & HV_STIMER_PERIODIC))
+		stimer->config |= ~HV_STIMER_ENABLE;
+	else
+		stimer_restart(stimer);
+}
+
+void kvm_hv_process_stimers(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+	struct kvm_vcpu_hv_stimer *stimer;
+	u64 time_now;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+		if (test_and_clear_bit(i, hv_vcpu->stimer_pending_bitmap)) {
+			stimer = &hv_vcpu->stimer[i];
+			stimer_stop(stimer);
+			if (stimer->config & HV_STIMER_ENABLE) {
+				time_now = get_time_ref_counter(vcpu->kvm);
+				if (time_now >= stimer->exp_time)
+					stimer_expiration(stimer);
+			}
+		}
+}
+
+void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+		stimer_cleanup(&hv_vcpu->stimer[i]);
+}
+
+static void stimer_prepare_msg(struct kvm_vcpu_hv_stimer *stimer)
+{
+	struct hv_message *msg = &stimer->msg;
+	struct hv_timer_message_payload *payload =
+			(struct hv_timer_message_payload *)&msg->u.payload;
+
+	memset(&msg->header, 0, sizeof(msg->header));
+	msg->header.message_type = HVMSG_TIMER_EXPIRED;
+	msg->header.payload_size = sizeof(*payload);
+
+	payload->timer_index = stimer->index;
+	payload->expiration_time = 0;
+	payload->delivery_time = 0;
+}
+
+static void stimer_init(struct kvm_vcpu_hv_stimer *stimer, int timer_index)
+{
+	memset(stimer, 0, sizeof(*stimer));
+	stimer->index = timer_index;
+	hrtimer_init(&stimer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	stimer->timer.function = stimer_timer_callback;
+	stimer_prepare_msg(stimer);
+}
+
+void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+	int i;
+
+	synic_init(&hv_vcpu->synic);
+
+	bitmap_zero(hv_vcpu->stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
+	for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+		stimer_init(&hv_vcpu->stimer[i], i);
+}
+
+int kvm_hv_activate_synic(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * Hyper-V SynIC auto EOI SINT's are
+	 * not compatible with APICV, so deactivate APICV
+	 */
+	kvm_vcpu_deactivate_apicv(vcpu);
+	vcpu_to_synic(vcpu)->active = true;
+	return 0;
+}
+
 static bool kvm_hv_msr_partition_wide(u32 msr)
 {
 	bool r = false;
@@ -53,11 +687,12 @@
 				     u32 index, u64 *pdata)
 {
 	struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
+	size_t size = ARRAY_SIZE(hv->hv_crash_param);
 
-	if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
+	if (WARN_ON_ONCE(index >= size))
 		return -EINVAL;
 
-	*pdata = hv->hv_crash_param[index];
+	*pdata = hv->hv_crash_param[array_index_nospec(index, size)];
 	return 0;
 }
 
@@ -96,11 +731,12 @@
 				     u32 index, u64 data)
 {
 	struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
+	size_t size = ARRAY_SIZE(hv->hv_crash_param);
 
-	if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
+	if (WARN_ON_ONCE(index >= size))
 		return -EINVAL;
 
-	hv->hv_crash_param[index] = data;
+	hv->hv_crash_param[array_index_nospec(index, size)] = data;
 	return 0;
 }
 
@@ -226,6 +862,31 @@
 			return 1;
 		hv->runtime_offset = data - current_task_runtime_100ns();
 		break;
+	case HV_X64_MSR_SCONTROL:
+	case HV_X64_MSR_SVERSION:
+	case HV_X64_MSR_SIEFP:
+	case HV_X64_MSR_SIMP:
+	case HV_X64_MSR_EOM:
+	case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+		return synic_set_msr(vcpu_to_synic(vcpu), msr, data, host);
+	case HV_X64_MSR_STIMER0_CONFIG:
+	case HV_X64_MSR_STIMER1_CONFIG:
+	case HV_X64_MSR_STIMER2_CONFIG:
+	case HV_X64_MSR_STIMER3_CONFIG: {
+		int timer_index = (msr - HV_X64_MSR_STIMER0_CONFIG)/2;
+
+		return stimer_set_config(vcpu_to_stimer(vcpu, timer_index),
+					 data, host);
+	}
+	case HV_X64_MSR_STIMER0_COUNT:
+	case HV_X64_MSR_STIMER1_COUNT:
+	case HV_X64_MSR_STIMER2_COUNT:
+	case HV_X64_MSR_STIMER3_COUNT: {
+		int timer_index = (msr - HV_X64_MSR_STIMER0_COUNT)/2;
+
+		return stimer_set_count(vcpu_to_stimer(vcpu, timer_index),
+					data, host);
+	}
 	default:
 		vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n",
 			    msr, data);
@@ -248,11 +909,9 @@
 	case HV_X64_MSR_HYPERCALL:
 		data = hv->hv_hypercall;
 		break;
-	case HV_X64_MSR_TIME_REF_COUNT: {
-		data =
-		     div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100);
+	case HV_X64_MSR_TIME_REF_COUNT:
+		data = get_time_ref_counter(kvm);
 		break;
-	}
 	case HV_X64_MSR_REFERENCE_TSC:
 		data = hv->hv_tsc_page;
 		break;
@@ -304,6 +963,31 @@
 	case HV_X64_MSR_VP_RUNTIME:
 		data = current_task_runtime_100ns() + hv->runtime_offset;
 		break;
+	case HV_X64_MSR_SCONTROL:
+	case HV_X64_MSR_SVERSION:
+	case HV_X64_MSR_SIEFP:
+	case HV_X64_MSR_SIMP:
+	case HV_X64_MSR_EOM:
+	case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+		return synic_get_msr(vcpu_to_synic(vcpu), msr, pdata);
+	case HV_X64_MSR_STIMER0_CONFIG:
+	case HV_X64_MSR_STIMER1_CONFIG:
+	case HV_X64_MSR_STIMER2_CONFIG:
+	case HV_X64_MSR_STIMER3_CONFIG: {
+		int timer_index = (msr - HV_X64_MSR_STIMER0_CONFIG)/2;
+
+		return stimer_get_config(vcpu_to_stimer(vcpu, timer_index),
+					 pdata);
+	}
+	case HV_X64_MSR_STIMER0_COUNT:
+	case HV_X64_MSR_STIMER1_COUNT:
+	case HV_X64_MSR_STIMER2_COUNT:
+	case HV_X64_MSR_STIMER3_COUNT: {
+		int timer_index = (msr - HV_X64_MSR_STIMER0_COUNT)/2;
+
+		return stimer_get_count(vcpu_to_stimer(vcpu, timer_index),
+					pdata);
+	}
 	default:
 		vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
 		return 1;
@@ -384,7 +1068,7 @@
 	trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa);
 
 	switch (code) {
-	case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT:
+	case HVCALL_NOTIFY_LONG_SPIN_WAIT:
 		kvm_vcpu_on_spin(vcpu);
 		break;
 	default:
--- linux-4.4.0.orig/arch/x86/kvm/hyperv.h
+++ linux-4.4.0/arch/x86/kvm/hyperv.h
@@ -24,9 +24,64 @@
 #ifndef __ARCH_X86_KVM_HYPERV_H__
 #define __ARCH_X86_KVM_HYPERV_H__
 
+static inline struct kvm_vcpu_hv *vcpu_to_hv_vcpu(struct kvm_vcpu *vcpu)
+{
+	return &vcpu->arch.hyperv;
+}
+
+static inline struct kvm_vcpu *hv_vcpu_to_vcpu(struct kvm_vcpu_hv *hv_vcpu)
+{
+	struct kvm_vcpu_arch *arch;
+
+	arch = container_of(hv_vcpu, struct kvm_vcpu_arch, hyperv);
+	return container_of(arch, struct kvm_vcpu, arch);
+}
+
+static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu)
+{
+	return &vcpu->arch.hyperv.synic;
+}
+
+static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic)
+{
+	return hv_vcpu_to_vcpu(container_of(synic, struct kvm_vcpu_hv, synic));
+}
+
 int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host);
 int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
+
 bool kvm_hv_hypercall_enabled(struct kvm *kvm);
 int kvm_hv_hypercall(struct kvm_vcpu *vcpu);
 
+void kvm_hv_irq_routing_update(struct kvm *kvm);
+int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
+void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
+int kvm_hv_activate_synic(struct kvm_vcpu *vcpu);
+
+void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu);
+void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
+
+static inline struct kvm_vcpu_hv_stimer *vcpu_to_stimer(struct kvm_vcpu *vcpu,
+							int timer_index)
+{
+	return &vcpu_to_hv_vcpu(vcpu)->stimer[timer_index];
+}
+
+static inline struct kvm_vcpu *stimer_to_vcpu(struct kvm_vcpu_hv_stimer *stimer)
+{
+	struct kvm_vcpu_hv *hv_vcpu;
+
+	hv_vcpu = container_of(stimer - stimer->index, struct kvm_vcpu_hv,
+			       stimer[0]);
+	return hv_vcpu_to_vcpu(hv_vcpu);
+}
+
+static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu)
+{
+	return !bitmap_empty(vcpu->arch.hyperv.stimer_pending_bitmap,
+			     HV_SYNIC_STIMER_COUNT);
+}
+
+void kvm_hv_process_stimers(struct kvm_vcpu *vcpu);
+
 #endif
--- linux-4.4.0.orig/arch/x86/kvm/i8254.c
+++ linux-4.4.0/arch/x86/kvm/i8254.c
@@ -245,7 +245,7 @@
 		 * PIC is being reset.  Handle it gracefully here
 		 */
 		atomic_inc(&ps->pending);
-	else if (value > 0)
+	else if (value > 0 && ps->reinject)
 		/* in this case, we had multiple outstanding pit interrupts
 		 * that we needed to inject.  Reinject
 		 */
@@ -288,7 +288,9 @@
 	 * last one has been acked.
 	 */
 	spin_lock(&ps->inject_lock);
-	if (ps->irq_ack) {
+	if (!ps->reinject)
+		inject = 1;
+	else if (ps->irq_ack) {
 		ps->irq_ack = 0;
 		inject = 1;
 	}
@@ -317,10 +319,10 @@
 	struct kvm_kpit_state *ps = container_of(data, struct kvm_kpit_state, timer);
 	struct kvm_pit *pt = ps->kvm->arch.vpit;
 
-	if (ps->reinject || !atomic_read(&ps->pending)) {
+	if (ps->reinject)
 		atomic_inc(&ps->pending);
-		queue_kthread_work(&pt->worker, &pt->expired);
-	}
+
+	queue_kthread_work(&pt->worker, &pt->expired);
 
 	if (ps->is_periodic) {
 		hrtimer_add_expires_ns(&ps->timer, ps->period);
@@ -676,7 +678,6 @@
 	.write    = speaker_ioport_write,
 };
 
-/* Caller must hold slots_lock */
 struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 {
 	struct kvm_pit *pit;
@@ -731,6 +732,7 @@
 	pit->mask_notifier.func = pit_mask_notifer;
 	kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
 
+	mutex_lock(&kvm->slots_lock);
 	kvm_iodevice_init(&pit->dev, &pit_dev_ops);
 	ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, KVM_PIT_BASE_ADDRESS,
 				      KVM_PIT_MEM_LENGTH, &pit->dev);
@@ -745,13 +747,14 @@
 		if (ret < 0)
 			goto fail_unregister;
 	}
+	mutex_unlock(&kvm->slots_lock);
 
 	return pit;
 
 fail_unregister:
 	kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &pit->dev);
-
 fail:
+	mutex_unlock(&kvm->slots_lock);
 	kvm_unregister_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
 	kvm_unregister_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier);
 	kvm_free_irq_source_id(kvm, pit->irq_source_id);
--- linux-4.4.0.orig/arch/x86/kvm/i8259.c
+++ linux-4.4.0/arch/x86/kvm/i8259.c
@@ -456,46 +456,37 @@
 	return s->elcr;
 }
 
-static int picdev_in_range(gpa_t addr)
-{
-	switch (addr) {
-	case 0x20:
-	case 0x21:
-	case 0xa0:
-	case 0xa1:
-	case 0x4d0:
-	case 0x4d1:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
 static int picdev_write(struct kvm_pic *s,
 			 gpa_t addr, int len, const void *val)
 {
 	unsigned char data = *(unsigned char *)val;
-	if (!picdev_in_range(addr))
-		return -EOPNOTSUPP;
 
 	if (len != 1) {
 		pr_pic_unimpl("non byte write\n");
 		return 0;
 	}
-	pic_lock(s);
 	switch (addr) {
 	case 0x20:
 	case 0x21:
+		pic_lock(s);
+		pic_ioport_write(&s->pics[0], addr, data);
+		pic_unlock(s);
+		break;
 	case 0xa0:
 	case 0xa1:
-		pic_ioport_write(&s->pics[addr >> 7], addr, data);
+		pic_lock(s);
+		pic_ioport_write(&s->pics[1], addr, data);
+		pic_unlock(s);
 		break;
 	case 0x4d0:
 	case 0x4d1:
+		pic_lock(s);
 		elcr_ioport_write(&s->pics[addr & 1], addr, data);
+		pic_unlock(s);
 		break;
+	default:
+		return -EOPNOTSUPP;
 	}
-	pic_unlock(s);
 	return 0;
 }
 
@@ -503,29 +494,31 @@
 		       gpa_t addr, int len, void *val)
 {
 	unsigned char data = 0;
-	if (!picdev_in_range(addr))
-		return -EOPNOTSUPP;
 
 	if (len != 1) {
 		memset(val, 0, len);
 		pr_pic_unimpl("non byte read\n");
 		return 0;
 	}
-	pic_lock(s);
 	switch (addr) {
 	case 0x20:
 	case 0x21:
 	case 0xa0:
 	case 0xa1:
+		pic_lock(s);
 		data = pic_ioport_read(&s->pics[addr >> 7], addr);
+		pic_unlock(s);
 		break;
 	case 0x4d0:
 	case 0x4d1:
+		pic_lock(s);
 		data = elcr_ioport_read(&s->pics[addr & 1], addr);
+		pic_unlock(s);
 		break;
+	default:
+		return -EOPNOTSUPP;
 	}
 	*(unsigned char *)val = data;
-	pic_unlock(s);
 	return 0;
 }
 
--- linux-4.4.0.orig/arch/x86/kvm/ioapic.c
+++ linux-4.4.0/arch/x86/kvm/ioapic.c
@@ -36,6 +36,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/nospec.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/current.h>
@@ -73,13 +74,14 @@
 	default:
 		{
 			u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
-			u64 redir_content;
+			u64 redir_content = ~0ULL;
 
-			if (redir_index < IOAPIC_NUM_PINS)
-				redir_content =
-					ioapic->redirtbl[redir_index].bits;
-			else
-				redir_content = ~0ULL;
+			if (redir_index < IOAPIC_NUM_PINS) {
+				u32 index = array_index_nospec(
+					redir_index, IOAPIC_NUM_PINS);
+
+				redir_content = ioapic->redirtbl[index].bits;
+			}
 
 			result = (ioapic->ioregsel & 0x1) ?
 			    (redir_content >> 32) & 0xffffffff :
@@ -94,7 +96,7 @@
 static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)
 {
 	ioapic->rtc_status.pending_eoi = 0;
-	bitmap_zero(ioapic->rtc_status.dest_map, KVM_MAX_VCPUS);
+	bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPUS);
 }
 
 static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic);
@@ -109,6 +111,7 @@
 {
 	bool new_val, old_val;
 	struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
+	struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
 	union kvm_ioapic_redirect_entry *e;
 
 	e = &ioapic->redirtbl[RTC_GSI];
@@ -117,16 +120,17 @@
 		return;
 
 	new_val = kvm_apic_pending_eoi(vcpu, e->fields.vector);
-	old_val = test_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);
+	old_val = test_bit(vcpu->vcpu_id, dest_map->map);
 
 	if (new_val == old_val)
 		return;
 
 	if (new_val) {
-		__set_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);
+		__set_bit(vcpu->vcpu_id, dest_map->map);
+		dest_map->vectors[vcpu->vcpu_id] = e->fields.vector;
 		ioapic->rtc_status.pending_eoi++;
 	} else {
-		__clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);
+		__clear_bit(vcpu->vcpu_id, dest_map->map);
 		ioapic->rtc_status.pending_eoi--;
 		rtc_status_pending_eoi_check_valid(ioapic);
 	}
@@ -156,7 +160,8 @@
 
 static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu)
 {
-	if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map)) {
+	if (test_and_clear_bit(vcpu->vcpu_id,
+			       ioapic->rtc_status.dest_map.map)) {
 		--ioapic->rtc_status.pending_eoi;
 		rtc_status_pending_eoi_check_valid(ioapic);
 	}
@@ -233,13 +238,20 @@
 }
 
 
-void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, ulong *ioapic_handled_vectors)
 {
 	struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
+	struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
 	union kvm_ioapic_redirect_entry *e;
 	int index;
 
 	spin_lock(&ioapic->lock);
+
+	/* Make sure we see any missing RTC EOI */
+	if (test_bit(vcpu->vcpu_id, dest_map->map))
+		__set_bit(dest_map->vectors[vcpu->vcpu_id],
+			  ioapic_handled_vectors);
+
 	for (index = 0; index < IOAPIC_NUM_PINS; index++) {
 		e = &ioapic->redirtbl[index];
 		if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG ||
@@ -247,10 +259,9 @@
 		    index == RTC_GSI) {
 			if (kvm_apic_match_dest(vcpu, NULL, 0,
 			             e->fields.dest_id, e->fields.dest_mode) ||
-			    (e->fields.trig_mode == IOAPIC_EDGE_TRIG &&
-			     kvm_apic_pending_eoi(vcpu, e->fields.vector)))
+			    kvm_apic_pending_eoi(vcpu, e->fields.vector))
 				__set_bit(e->fields.vector,
-					(unsigned long *)eoi_exit_bitmap);
+					  ioapic_handled_vectors);
 		}
 	}
 	spin_unlock(&ioapic->lock);
@@ -269,6 +280,7 @@
 {
 	unsigned index;
 	bool mask_before, mask_after;
+	int old_remote_irr, old_delivery_status;
 	union kvm_ioapic_redirect_entry *e;
 
 	switch (ioapic->ioregsel) {
@@ -289,16 +301,31 @@
 		ioapic_debug("change redir index %x val %x\n", index, val);
 		if (index >= IOAPIC_NUM_PINS)
 			return;
+		index = array_index_nospec(index, IOAPIC_NUM_PINS);
 		e = &ioapic->redirtbl[index];
 		mask_before = e->fields.mask;
+		/* Preserve read-only fields */
+		old_remote_irr = e->fields.remote_irr;
+		old_delivery_status = e->fields.delivery_status;
 		if (ioapic->ioregsel & 1) {
 			e->bits &= 0xffffffff;
 			e->bits |= (u64) val << 32;
 		} else {
 			e->bits &= ~0xffffffffULL;
 			e->bits |= (u32) val;
-			e->fields.remote_irr = 0;
 		}
+		e->fields.remote_irr = old_remote_irr;
+		e->fields.delivery_status = old_delivery_status;
+
+		/*
+		 * Some OSes (Linux, Xen) assume that Remote IRR bit will
+		 * be cleared by IOAPIC hardware when the entry is configured
+		 * as edge-triggered. This behavior is used to simulate an
+		 * explicit EOI on IOAPICs that don't have the EOI register.
+		 */
+		if (e->fields.trig_mode == IOAPIC_EDGE_TRIG)
+			e->fields.remote_irr = 0;
+
 		mask_after = e->fields.mask;
 		if (mask_before != mask_after)
 			kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
@@ -346,7 +373,7 @@
 		 */
 		BUG_ON(ioapic->rtc_status.pending_eoi != 0);
 		ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
-				ioapic->rtc_status.dest_map);
+					       &ioapic->rtc_status.dest_map);
 		ioapic->rtc_status.pending_eoi = (ret < 0 ? 0 : ret);
 	} else
 		ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL);
@@ -407,8 +434,14 @@
 static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
 			struct kvm_ioapic *ioapic, int vector, int trigger_mode)
 {
-	int i;
+	struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
 	struct kvm_lapic *apic = vcpu->arch.apic;
+	int i;
+
+	/* RTC special handling */
+	if (test_bit(vcpu->vcpu_id, dest_map->map) &&
+	    vector == dest_map->vectors[vcpu->vcpu_id])
+		rtc_irq_eoi(ioapic, vcpu);
 
 	for (i = 0; i < IOAPIC_NUM_PINS; i++) {
 		union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
@@ -416,8 +449,6 @@
 		if (ent->fields.vector != vector)
 			continue;
 
-		if (i == RTC_GSI)
-			rtc_irq_eoi(ioapic, vcpu);
 		/*
 		 * We are dropping lock while calling ack notifiers because ack
 		 * notifier callbacks for assigned devices call into IOAPIC
@@ -580,7 +611,7 @@
 	ioapic->irr = 0;
 	ioapic->irr_delivered = 0;
 	ioapic->id = 0;
-	memset(ioapic->irq_eoi, 0x00, IOAPIC_NUM_PINS);
+	memset(ioapic->irq_eoi, 0x00, sizeof(ioapic->irq_eoi));
 	rtc_irq_eoi_tracking_reset(ioapic);
 }
 
--- linux-4.4.0.orig/arch/x86/kvm/ioapic.h
+++ linux-4.4.0/arch/x86/kvm/ioapic.h
@@ -40,9 +40,21 @@
 #define RTC_GSI -1U
 #endif
 
+struct dest_map {
+	/* vcpu bitmap where IRQ has been sent */
+	DECLARE_BITMAP(map, KVM_MAX_VCPUS);
+
+	/*
+	 * Vector sent to a given vcpu, only valid when
+	 * the vcpu's bit in map is set
+	 */
+	u8 vectors[KVM_MAX_VCPUS];
+};
+
+
 struct rtc_status {
 	int pending_eoi;
-	DECLARE_BITMAP(dest_map, KVM_MAX_VCPUS);
+	struct dest_map dest_map;
 };
 
 union kvm_ioapic_redirect_entry {
@@ -118,10 +130,12 @@
 		       int level, bool line_status);
 void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id);
 int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
-		struct kvm_lapic_irq *irq, unsigned long *dest_map);
+			     struct kvm_lapic_irq *irq,
+			     struct dest_map *dest_map);
 int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
 int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
-void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
-void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
-
+void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu,
+			   ulong *ioapic_handled_vectors);
+void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
+			    ulong *ioapic_handled_vectors);
 #endif
--- linux-4.4.0.orig/arch/x86/kvm/irq.c
+++ linux-4.4.0/arch/x86/kvm/irq.c
@@ -76,7 +76,7 @@
 	if (kvm_cpu_has_extint(v))
 		return 1;
 
-	if (kvm_vcpu_apic_vid_enabled(v))
+	if (kvm_vcpu_apicv_active(v))
 		return 0;
 
 	return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
--- linux-4.4.0.orig/arch/x86/kvm/irq_comm.c
+++ linux-4.4.0/arch/x86/kvm/irq_comm.c
@@ -33,11 +33,22 @@
 
 #include "lapic.h"
 
+#include "hyperv.h"
+
 static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
 			   struct kvm *kvm, int irq_source_id, int level,
 			   bool line_status)
 {
 	struct kvm_pic *pic = pic_irqchip(kvm);
+
+	/*
+	 * XXX: rejecting pic routes when pic isn't in use would be better,
+	 * but the default routing table is installed while kvm->arch.vpic is
+	 * NULL and KVM_CREATE_IRQCHIP can race with KVM_IRQ_LINE.
+	 */
+	if (!pic)
+		return -1;
+
 	return kvm_pic_set_irq(pic, e->irqchip.pin, irq_source_id, level);
 }
 
@@ -46,12 +57,16 @@
 			      bool line_status)
 {
 	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
+
+	if (!ioapic)
+		return -1;
+
 	return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, irq_source_id, level,
 				line_status);
 }
 
 int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
-		struct kvm_lapic_irq *irq, unsigned long *dest_map)
+		struct kvm_lapic_irq *irq, struct dest_map *dest_map)
 {
 	int i, r = -1;
 	struct kvm_vcpu *vcpu, *lowest = NULL;
@@ -219,6 +234,16 @@
 	srcu_read_unlock(&kvm->irq_srcu, idx);
 }
 
+static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
+		    struct kvm *kvm, int irq_source_id, int level,
+		    bool line_status)
+{
+	if (!level)
+		return -1;
+
+	return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
+}
+
 int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
 			  const struct kvm_irq_routing_entry *ue)
 {
@@ -257,6 +282,11 @@
 		e->msi.address_hi = ue->u.msi.address_hi;
 		e->msi.data = ue->u.msi.data;
 		break;
+	case KVM_IRQ_ROUTING_HV_SINT:
+		e->set = kvm_hv_set_sint;
+		e->hv_sint.vcpu = ue->u.hv_sint.vcpu;
+		e->hv_sint.sint = ue->u.hv_sint.sint;
+		break;
 	default:
 		goto out;
 	}
@@ -332,14 +362,15 @@
 	return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
 }
 
-void kvm_arch_irq_routing_update(struct kvm *kvm)
+void kvm_arch_post_irq_routing_update(struct kvm *kvm)
 {
 	if (ioapic_in_kernel(kvm) || !irqchip_in_kernel(kvm))
 		return;
 	kvm_make_scan_ioapic_request(kvm);
 }
 
-void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
+			    ulong *ioapic_handled_vectors)
 {
 	struct kvm *kvm = vcpu->kvm;
 	struct kvm_kernel_irq_routing_entry *entry;
@@ -369,9 +400,26 @@
 				u32 vector = entry->msi.data & 0xff;
 
 				__set_bit(vector,
-					  (unsigned long *) eoi_exit_bitmap);
+					  ioapic_handled_vectors);
 			}
 		}
 	}
 	srcu_read_unlock(&kvm->irq_srcu, idx);
 }
+
+int kvm_arch_set_irq(struct kvm_kernel_irq_routing_entry *irq, struct kvm *kvm,
+		     int irq_source_id, int level, bool line_status)
+{
+	switch (irq->type) {
+	case KVM_IRQ_ROUTING_HV_SINT:
+		return kvm_hv_set_sint(irq, kvm, irq_source_id, level,
+				       line_status);
+	default:
+		return -EWOULDBLOCK;
+	}
+}
+
+void kvm_arch_irq_routing_update(struct kvm *kvm)
+{
+	kvm_hv_irq_routing_update(kvm);
+}
--- linux-4.4.0.orig/arch/x86/kvm/lapic.c
+++ linux-4.4.0/arch/x86/kvm/lapic.c
@@ -36,11 +36,13 @@
 #include <asm/delay.h>
 #include <linux/atomic.h>
 #include <linux/jump_label.h>
+#include <linux/nospec.h>
 #include "kvm_cache_regs.h"
 #include "irq.h"
 #include "trace.h"
 #include "x86.h"
 #include "cpuid.h"
+#include "hyperv.h"
 
 #ifndef CONFIG_X86_64
 #define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
@@ -56,7 +58,7 @@
 #define APIC_BUS_CYCLE_NS 1
 
 /* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
-#define apic_debug(fmt, arg...)
+#define apic_debug(fmt, arg...) do {} while (0)
 
 #define APIC_LVT_NUM			6
 /* 14 is the version for Xeon and Pentium 8.4.8*/
@@ -128,11 +130,6 @@
 	(LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
 	 APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
 
-static inline int kvm_apic_id(struct kvm_lapic *apic)
-{
-	return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
-}
-
 /* The logical map is definitely wrong if we have multiple
  * modes at the same time.  (Physical map is always right.)
  */
@@ -288,8 +285,16 @@
 	if (!kvm_vcpu_has_lapic(vcpu))
 		return;
 
+	/*
+	 * KVM emulates 82093AA datasheet (with in-kernel IOAPIC implementation)
+	 * which doesn't have EOI register; Some buggy OSes (e.g. Windows with
+	 * Hyper-V role) disable EOI broadcast in lapic not checking for IOAPIC
+	 * version first and level-triggered interrupts never get EOIed in
+	 * IOAPIC.
+	 */
 	feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0);
-	if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31))))
+	if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31))) &&
+	    !ioapic_in_kernel(vcpu->kvm))
 		v |= APIC_LVR_DIRECTED_EOI;
 	apic_set_reg(apic, APIC_LVR, v);
 }
@@ -379,7 +384,8 @@
 	if (!apic->irr_pending)
 		return -1;
 
-	kvm_x86_ops->sync_pir_to_irr(apic->vcpu);
+	if (apic->vcpu->arch.apicv_active)
+		kvm_x86_ops->sync_pir_to_irr(apic->vcpu);
 	result = apic_search_irr(apic);
 	ASSERT(result == -1 || result >= 16);
 
@@ -392,7 +398,7 @@
 
 	vcpu = apic->vcpu;
 
-	if (unlikely(kvm_vcpu_apic_vid_enabled(vcpu))) {
+	if (unlikely(vcpu->arch.apicv_active)) {
 		/* try to update RVI */
 		apic_clear_vector(vec, apic->regs + APIC_IRR);
 		kvm_make_request(KVM_REQ_EVENT, vcpu);
@@ -418,7 +424,7 @@
 	 * because the processor can modify ISR under the hood.  Instead
 	 * just set SVI.
 	 */
-	if (unlikely(kvm_x86_ops->hwapic_isr_update))
+	if (unlikely(vcpu->arch.apicv_active))
 		kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec);
 	else {
 		++apic->isr_count;
@@ -466,7 +472,7 @@
 	 * on the other hand isr_count and highest_isr_cache are unused
 	 * and must be left alone.
 	 */
-	if (unlikely(kvm_x86_ops->hwapic_isr_update))
+	if (unlikely(vcpu->arch.apicv_active))
 		kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
 					       apic_find_highest_isr(apic));
 	else {
@@ -494,10 +500,10 @@
 
 static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
 			     int vector, int level, int trig_mode,
-			     unsigned long *dest_map);
+			     struct dest_map *dest_map);
 
 int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq,
-		unsigned long *dest_map)
+		     struct dest_map *dest_map)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
 
@@ -527,9 +533,11 @@
 static bool pv_eoi_get_pending(struct kvm_vcpu *vcpu)
 {
 	u8 val;
-	if (pv_eoi_get_user(vcpu, &val) < 0)
+	if (pv_eoi_get_user(vcpu, &val) < 0) {
 		apic_debug("Can't read EOI MSR value: 0x%llx\n",
 			   (unsigned long long)vcpu->arch.pv_eoi.msr_val);
+		return false;
+	}
 	return val & 0x1;
 }
 
@@ -679,7 +687,7 @@
 }
 
 bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
-		struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map)
+		struct kvm_lapic_irq *irq, int *r, struct dest_map *dest_map)
 {
 	struct kvm_apic_map *map;
 	unsigned long bitmap = 1;
@@ -822,7 +830,7 @@
  */
 static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
 			     int vector, int level, int trig_mode,
-			     unsigned long *dest_map)
+			     struct dest_map *dest_map)
 {
 	int result = 0;
 	struct kvm_vcpu *vcpu = apic->vcpu;
@@ -842,8 +850,10 @@
 
 		result = 1;
 
-		if (dest_map)
-			__set_bit(vcpu->vcpu_id, dest_map);
+		if (dest_map) {
+			__set_bit(vcpu->vcpu_id, dest_map->map);
+			dest_map->vectors[vcpu->vcpu_id] = vector;
+		}
 
 		if (apic_test_vector(vector, apic->regs + APIC_TMR) != !!trig_mode) {
 			if (trig_mode)
@@ -852,7 +862,7 @@
 				apic_clear_vector(vector, apic->regs + APIC_TMR);
 		}
 
-		if (kvm_x86_ops->deliver_posted_interrupt)
+		if (vcpu->arch.apicv_active)
 			kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
 		else {
 			apic_set_irr(vector, apic);
@@ -932,7 +942,7 @@
 
 static bool kvm_ioapic_handles_vector(struct kvm_lapic *apic, int vector)
 {
-	return test_bit(vector, (ulong *)apic->vcpu->arch.eoi_exit_bitmap);
+	return test_bit(vector, apic->vcpu->arch.ioapic_handled_vectors);
 }
 
 static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
@@ -974,6 +984,9 @@
 	apic_clear_isr(vector, apic);
 	apic_update_ppr(apic);
 
+	if (test_bit(vector, vcpu_to_synic(apic->vcpu)->vec_bitmap))
+		kvm_hv_synic_send_eoi(apic->vcpu, vector);
+
 	kvm_ioapic_send_eoi(apic, vector);
 	kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
 	return vector;
@@ -1225,7 +1238,7 @@
 		int vec = reg & APIC_VECTOR_MASK;
 		void *bitmap = apic->regs + APIC_ISR;
 
-		if (kvm_x86_ops->deliver_posted_interrupt)
+		if (vcpu->arch.apicv_active)
 			bitmap = apic->regs + APIC_IRR;
 
 		if (apic_test_vector(vec, bitmap))
@@ -1255,7 +1268,8 @@
 
 	/* __delay is delay_tsc whenever the hardware has TSC, thus always.  */
 	if (guest_tsc < tsc_deadline)
-		__delay(tsc_deadline - guest_tsc);
+		__delay(min(tsc_deadline - guest_tsc,
+			nsec_to_cycles(vcpu, lapic_timer_advance_ns)));
 }
 
 static void start_apic_timer(struct kvm_lapic *apic)
@@ -1424,15 +1438,21 @@
 	case APIC_LVTTHMR:
 	case APIC_LVTPC:
 	case APIC_LVT1:
-	case APIC_LVTERR:
+	case APIC_LVTERR: {
 		/* TODO: Check vector */
+		size_t size;
+		u32 index;
+
 		if (!kvm_apic_sw_enabled(apic))
 			val |= APIC_LVT_MASKED;
 
-		val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4];
+		size = ARRAY_SIZE(apic_lvt_mask);
+		index = array_index_nospec(
+				(reg - APIC_LVTT) >> 4, size);
+		val &= apic_lvt_mask[index];
 		apic_set_reg(apic, reg, val);
-
 		break;
+	}
 
 	case APIC_LVTT:
 		if (!kvm_apic_sw_enabled(apic))
@@ -1693,8 +1713,8 @@
 		apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
 		apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
 	}
-	apic->irr_pending = kvm_vcpu_apic_vid_enabled(vcpu);
-	apic->isr_count = kvm_x86_ops->hwapic_isr_update ? 1 : 0;
+	apic->irr_pending = vcpu->arch.apicv_active;
+	apic->isr_count = vcpu->arch.apicv_active ? 1 : 0;
 	apic->highest_isr_cache = -1;
 	update_divide_count(apic);
 	atomic_set(&apic->lapic_timer.pending, 0);
@@ -1883,6 +1903,12 @@
 	apic_set_isr(vector, apic);
 	apic_update_ppr(apic);
 	apic_clear_irr(vector, apic);
+
+	if (test_bit(vector, vcpu_to_synic(vcpu)->auto_eoi_bitmap)) {
+		apic_clear_isr(vector, apic);
+		apic_update_ppr(apic);
+	}
+
 	return vector;
 }
 
@@ -1906,15 +1932,15 @@
 	update_divide_count(apic);
 	start_apic_timer(apic);
 	apic->irr_pending = true;
-	apic->isr_count = kvm_x86_ops->hwapic_isr_update ?
+	apic->isr_count = vcpu->arch.apicv_active ?
 				1 : count_vectors(apic->regs + APIC_ISR);
 	apic->highest_isr_cache = -1;
-	if (kvm_x86_ops->hwapic_irr_update)
+	if (vcpu->arch.apicv_active) {
 		kvm_x86_ops->hwapic_irr_update(vcpu,
 				apic_find_highest_irr(apic));
-	if (unlikely(kvm_x86_ops->hwapic_isr_update))
 		kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
 				apic_find_highest_isr(apic));
+	}
 	kvm_make_request(KVM_REQ_EVENT, vcpu);
 	if (ioapic_in_kernel(vcpu->kvm))
 		kvm_rtc_eoi_tracking_restore_one(vcpu);
@@ -2187,3 +2213,9 @@
 	jump_label_rate_limit(&apic_hw_disabled, HZ);
 	jump_label_rate_limit(&apic_sw_disabled, HZ);
 }
+
+void kvm_lapic_exit(void)
+{
+	static_key_deferred_flush(&apic_hw_disabled);
+	static_key_deferred_flush(&apic_sw_disabled);
+}
--- linux-4.4.0.orig/arch/x86/kvm/lapic.h
+++ linux-4.4.0/arch/x86/kvm/lapic.h
@@ -42,6 +42,9 @@
 	unsigned long pending_events;
 	unsigned int sipi_vector;
 };
+
+struct dest_map;
+
 int kvm_create_lapic(struct kvm_vcpu *vcpu);
 void kvm_free_lapic(struct kvm_vcpu *vcpu);
 
@@ -60,11 +63,11 @@
 void __kvm_apic_update_irr(u32 *pir, void *regs);
 void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir);
 int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq,
-		unsigned long *dest_map);
+		     struct dest_map *dest_map);
 int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type);
 
 bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
-		struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map);
+		struct kvm_lapic_irq *irq, int *r, struct dest_map *dest_map);
 
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
 int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
@@ -95,6 +98,7 @@
 
 int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data);
 void kvm_lapic_init(void);
+void kvm_lapic_exit(void);
 
 static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off)
 {
@@ -143,9 +147,9 @@
 	return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
 }
 
-static inline bool kvm_vcpu_apic_vid_enabled(struct kvm_vcpu *vcpu)
+static inline bool kvm_vcpu_apicv_active(struct kvm_vcpu *vcpu)
 {
-	return kvm_x86_ops->cpu_uses_apicv(vcpu);
+	return vcpu->arch.apic && vcpu->arch.apicv_active;
 }
 
 static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu)
@@ -164,6 +168,11 @@
 	return kvm_vcpu_has_lapic(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
 }
 
+static inline int kvm_apic_id(struct kvm_lapic *apic)
+{
+	return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+}
+
 bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
 
 void wait_lapic_expire(struct kvm_vcpu *vcpu);
--- linux-4.4.0.orig/arch/x86/kvm/mmu.c
+++ linux-4.4.0/arch/x86/kvm/mmu.c
@@ -36,12 +36,37 @@
 #include <linux/srcu.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/kthread.h>
 
 #include <asm/page.h>
 #include <asm/cmpxchg.h>
 #include <asm/io.h>
 #include <asm/vmx.h>
 
+extern bool itlb_multihit_kvm_mitigation;
+
+static int __read_mostly nx_huge_pages = -1;
+static uint __read_mostly nx_huge_pages_recovery_ratio = 60;
+
+static int set_nx_huge_pages(const char *val, const struct kernel_param *kp);
+static int set_nx_huge_pages_recovery_ratio(const char *val, const struct kernel_param *kp);
+
+static struct kernel_param_ops nx_huge_pages_ops = {
+	.set = set_nx_huge_pages,
+	.get = param_get_bool,
+};
+
+static struct kernel_param_ops nx_huge_pages_recovery_ratio_ops = {
+	.set = set_nx_huge_pages_recovery_ratio,
+	.get = param_get_uint,
+};
+
+module_param_cb(nx_huge_pages, &nx_huge_pages_ops, &nx_huge_pages, 0644);
+__MODULE_PARM_TYPE(nx_huge_pages, "bool");
+module_param_cb(nx_huge_pages_recovery_ratio, &nx_huge_pages_recovery_ratio_ops,
+		&nx_huge_pages_recovery_ratio, 0644);
+__MODULE_PARM_TYPE(nx_huge_pages_recovery_ratio, "uint");
+
 /*
  * When setting this variable to true it enables Two-Dimensional-Paging
  * where the hardware walks 2 page tables:
@@ -129,9 +154,6 @@
 
 #include <trace/events/kvm.h>
 
-#define CREATE_TRACE_POINTS
-#include "mmutrace.h"
-
 #define SPTE_HOST_WRITEABLE	(1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
 #define SPTE_MMU_WRITEABLE	(1ULL << (PT_FIRST_AVAIL_BITS_SHIFT + 1))
 
@@ -140,6 +162,20 @@
 /* make pte_list_desc fit well in cache line */
 #define PTE_LIST_EXT 3
 
+/*
+ * Return values of handle_mmio_page_fault and mmu.page_fault:
+ * RET_PF_RETRY: let CPU fault again on the address.
+ * RET_PF_EMULATE: mmio page fault, emulate the instruction directly.
+ *
+ * For handle_mmio_page_fault only:
+ * RET_PF_INVALID: the spte is invalid, let the real page fault path update it.
+ */
+enum {
+	RET_PF_RETRY = 0,
+	RET_PF_EMULATE = 1,
+	RET_PF_INVALID = 2,
+};
+
 struct pte_list_desc {
 	u64 *sptes[PTE_LIST_EXT];
 	struct pte_list_desc *more;
@@ -178,12 +214,21 @@
 static void mmu_spte_set(u64 *sptep, u64 spte);
 static void mmu_free_roots(struct kvm_vcpu *vcpu);
 
+#define CREATE_TRACE_POINTS
+#include "mmutrace.h"
+
+
 void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask)
 {
 	shadow_mmio_mask = mmio_mask;
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_set_mmio_spte_mask);
 
+static bool is_nx_huge_page_enabled(void)
+{
+	return READ_ONCE(nx_huge_pages);
+}
+
 /*
  * the low bit of the generation number is always presumed to be zero.
  * This disables mmio caching during memslot updates.  The concept is
@@ -761,10 +806,16 @@
 
 static void kvm_mmu_page_set_gfn(struct kvm_mmu_page *sp, int index, gfn_t gfn)
 {
-	if (sp->role.direct)
-		BUG_ON(gfn != kvm_mmu_page_get_gfn(sp, index));
-	else
+	if (!sp->role.direct) {
 		sp->gfns[index] = gfn;
+		return;
+	}
+
+	if (WARN_ON(gfn != kvm_mmu_page_get_gfn(sp, index)))
+		pr_err_ratelimited("gfn mismatch under direct page %llx "
+				   "(expected %llx, got %llx)\n",
+				   sp->gfn,
+				   kvm_mmu_page_get_gfn(sp, index), gfn);
 }
 
 /*
@@ -781,62 +832,93 @@
 	return &slot->arch.lpage_info[level - 2][idx];
 }
 
+static void update_gfn_disallow_lpage_count(struct kvm_memory_slot *slot,
+					    gfn_t gfn, int count)
+{
+	struct kvm_lpage_info *linfo;
+	int i;
+
+	for (i = PT_DIRECTORY_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
+		linfo = lpage_info_slot(gfn, slot, i);
+		linfo->disallow_lpage += count;
+		WARN_ON(linfo->disallow_lpage < 0);
+	}
+}
+
+void kvm_mmu_gfn_disallow_lpage(struct kvm_memory_slot *slot, gfn_t gfn)
+{
+	update_gfn_disallow_lpage_count(slot, gfn, 1);
+}
+
+void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn)
+{
+	update_gfn_disallow_lpage_count(slot, gfn, -1);
+}
+
 static void account_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
 	struct kvm_memslots *slots;
 	struct kvm_memory_slot *slot;
-	struct kvm_lpage_info *linfo;
 	gfn_t gfn;
-	int i;
 
 	gfn = sp->gfn;
 	slots = kvm_memslots_for_spte_role(kvm, sp->role);
 	slot = __gfn_to_memslot(slots, gfn);
-	for (i = PT_DIRECTORY_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
-		linfo = lpage_info_slot(gfn, slot, i);
-		linfo->write_count += 1;
-	}
+	kvm_mmu_gfn_disallow_lpage(slot, gfn);
 	kvm->arch.indirect_shadow_pages++;
 }
 
+static void account_huge_nx_page(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+	if (sp->lpage_disallowed)
+		return;
+
+	++kvm->stat.nx_lpage_splits;
+	list_add_tail(&sp->lpage_disallowed_link,
+		      &kvm->arch.lpage_disallowed_mmu_pages);
+	sp->lpage_disallowed = true;
+}
+
 static void unaccount_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
 	struct kvm_memslots *slots;
 	struct kvm_memory_slot *slot;
-	struct kvm_lpage_info *linfo;
 	gfn_t gfn;
-	int i;
 
 	gfn = sp->gfn;
 	slots = kvm_memslots_for_spte_role(kvm, sp->role);
 	slot = __gfn_to_memslot(slots, gfn);
-	for (i = PT_DIRECTORY_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
-		linfo = lpage_info_slot(gfn, slot, i);
-		linfo->write_count -= 1;
-		WARN_ON(linfo->write_count < 0);
-	}
+	kvm_mmu_gfn_allow_lpage(slot, gfn);
 	kvm->arch.indirect_shadow_pages--;
 }
 
-static int __has_wrprotected_page(gfn_t gfn, int level,
-				  struct kvm_memory_slot *slot)
+static void unaccount_huge_nx_page(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+	--kvm->stat.nx_lpage_splits;
+	sp->lpage_disallowed = false;
+	list_del(&sp->lpage_disallowed_link);
+}
+
+static bool __mmu_gfn_lpage_is_disallowed(gfn_t gfn, int level,
+					  struct kvm_memory_slot *slot)
 {
 	struct kvm_lpage_info *linfo;
 
 	if (slot) {
 		linfo = lpage_info_slot(gfn, slot, level);
-		return linfo->write_count;
+		return !!linfo->disallow_lpage;
 	}
 
-	return 1;
+	return true;
 }
 
-static int has_wrprotected_page(struct kvm_vcpu *vcpu, gfn_t gfn, int level)
+static bool mmu_gfn_lpage_is_disallowed(struct kvm_vcpu *vcpu, gfn_t gfn,
+					int level)
 {
 	struct kvm_memory_slot *slot;
 
 	slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
-	return __has_wrprotected_page(gfn, level, slot);
+	return __mmu_gfn_lpage_is_disallowed(gfn, level, slot);
 }
 
 static int host_mapping_level(struct kvm *kvm, gfn_t gfn)
@@ -902,43 +984,42 @@
 	max_level = min(kvm_x86_ops->get_lpage_level(), host_level);
 
 	for (level = PT_DIRECTORY_LEVEL; level <= max_level; ++level)
-		if (__has_wrprotected_page(large_gfn, level, slot))
+		if (__mmu_gfn_lpage_is_disallowed(large_gfn, level, slot))
 			break;
 
 	return level - 1;
 }
 
 /*
- * Pte mapping structures:
- *
- * If pte_list bit zero is zero, then pte_list point to the spte.
+ * About rmap_head encoding:
  *
- * If pte_list bit zero is one, (then pte_list & ~1) points to a struct
+ * If the bit zero of rmap_head->val is clear, then it points to the only spte
+ * in this rmap chain. Otherwise, (rmap_head->val & ~1) points to a struct
  * pte_list_desc containing more mappings.
- *
- * Returns the number of pte entries before the spte was added or zero if
- * the spte was not added.
- *
+ */
+
+/*
+ * Returns the number of pointers in the rmap chain, not counting the new one.
  */
 static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte,
-			unsigned long *pte_list)
+			struct kvm_rmap_head *rmap_head)
 {
 	struct pte_list_desc *desc;
 	int i, count = 0;
 
-	if (!*pte_list) {
+	if (!rmap_head->val) {
 		rmap_printk("pte_list_add: %p %llx 0->1\n", spte, *spte);
-		*pte_list = (unsigned long)spte;
-	} else if (!(*pte_list & 1)) {
+		rmap_head->val = (unsigned long)spte;
+	} else if (!(rmap_head->val & 1)) {
 		rmap_printk("pte_list_add: %p %llx 1->many\n", spte, *spte);
 		desc = mmu_alloc_pte_list_desc(vcpu);
-		desc->sptes[0] = (u64 *)*pte_list;
+		desc->sptes[0] = (u64 *)rmap_head->val;
 		desc->sptes[1] = spte;
-		*pte_list = (unsigned long)desc | 1;
+		rmap_head->val = (unsigned long)desc | 1;
 		++count;
 	} else {
 		rmap_printk("pte_list_add: %p %llx many->many\n", spte, *spte);
-		desc = (struct pte_list_desc *)(*pte_list & ~1ul);
+		desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
 		while (desc->sptes[PTE_LIST_EXT-1] && desc->more) {
 			desc = desc->more;
 			count += PTE_LIST_EXT;
@@ -955,8 +1036,9 @@
 }
 
 static void
-pte_list_desc_remove_entry(unsigned long *pte_list, struct pte_list_desc *desc,
-			   int i, struct pte_list_desc *prev_desc)
+pte_list_desc_remove_entry(struct kvm_rmap_head *rmap_head,
+			   struct pte_list_desc *desc, int i,
+			   struct pte_list_desc *prev_desc)
 {
 	int j;
 
@@ -967,43 +1049,43 @@
 	if (j != 0)
 		return;
 	if (!prev_desc && !desc->more)
-		*pte_list = (unsigned long)desc->sptes[0];
+		rmap_head->val = (unsigned long)desc->sptes[0];
 	else
 		if (prev_desc)
 			prev_desc->more = desc->more;
 		else
-			*pte_list = (unsigned long)desc->more | 1;
+			rmap_head->val = (unsigned long)desc->more | 1;
 	mmu_free_pte_list_desc(desc);
 }
 
-static void pte_list_remove(u64 *spte, unsigned long *pte_list)
+static void pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head)
 {
 	struct pte_list_desc *desc;
 	struct pte_list_desc *prev_desc;
 	int i;
 
-	if (!*pte_list) {
+	if (!rmap_head->val) {
 		printk(KERN_ERR "pte_list_remove: %p 0->BUG\n", spte);
 		BUG();
-	} else if (!(*pte_list & 1)) {
+	} else if (!(rmap_head->val & 1)) {
 		rmap_printk("pte_list_remove:  %p 1->0\n", spte);
-		if ((u64 *)*pte_list != spte) {
+		if ((u64 *)rmap_head->val != spte) {
 			printk(KERN_ERR "pte_list_remove:  %p 1->BUG\n", spte);
 			BUG();
 		}
-		*pte_list = 0;
+		rmap_head->val = 0;
 	} else {
 		rmap_printk("pte_list_remove:  %p many->many\n", spte);
-		desc = (struct pte_list_desc *)(*pte_list & ~1ul);
+		desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
 		prev_desc = NULL;
 		while (desc) {
-			for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i)
+			for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) {
 				if (desc->sptes[i] == spte) {
-					pte_list_desc_remove_entry(pte_list,
-							       desc, i,
-							       prev_desc);
+					pte_list_desc_remove_entry(rmap_head,
+							desc, i, prev_desc);
 					return;
 				}
+			}
 			prev_desc = desc;
 			desc = desc->more;
 		}
@@ -1013,18 +1095,18 @@
 }
 
 typedef void (*pte_list_walk_fn) (u64 *spte);
-static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn)
+static void pte_list_walk(struct kvm_rmap_head *rmap_head, pte_list_walk_fn fn)
 {
 	struct pte_list_desc *desc;
 	int i;
 
-	if (!*pte_list)
+	if (!rmap_head->val)
 		return;
 
-	if (!(*pte_list & 1))
-		return fn((u64 *)*pte_list);
+	if (!(rmap_head->val & 1))
+		return fn((u64 *)rmap_head->val);
 
-	desc = (struct pte_list_desc *)(*pte_list & ~1ul);
+	desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
 	while (desc) {
 		for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i)
 			fn(desc->sptes[i]);
@@ -1032,8 +1114,8 @@
 	}
 }
 
-static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
-				    struct kvm_memory_slot *slot)
+static struct kvm_rmap_head *__gfn_to_rmap(gfn_t gfn, int level,
+					   struct kvm_memory_slot *slot)
 {
 	unsigned long idx;
 
@@ -1041,10 +1123,8 @@
 	return &slot->arch.rmap[level - PT_PAGE_TABLE_LEVEL][idx];
 }
 
-/*
- * Take gfn and return the reverse mapping to it.
- */
-static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, struct kvm_mmu_page *sp)
+static struct kvm_rmap_head *gfn_to_rmap(struct kvm *kvm, gfn_t gfn,
+					 struct kvm_mmu_page *sp)
 {
 	struct kvm_memslots *slots;
 	struct kvm_memory_slot *slot;
@@ -1065,24 +1145,24 @@
 static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
 {
 	struct kvm_mmu_page *sp;
-	unsigned long *rmapp;
+	struct kvm_rmap_head *rmap_head;
 
 	sp = page_header(__pa(spte));
 	kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn);
-	rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp);
-	return pte_list_add(vcpu, spte, rmapp);
+	rmap_head = gfn_to_rmap(vcpu->kvm, gfn, sp);
+	return pte_list_add(vcpu, spte, rmap_head);
 }
 
 static void rmap_remove(struct kvm *kvm, u64 *spte)
 {
 	struct kvm_mmu_page *sp;
 	gfn_t gfn;
-	unsigned long *rmapp;
+	struct kvm_rmap_head *rmap_head;
 
 	sp = page_header(__pa(spte));
 	gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt);
-	rmapp = gfn_to_rmap(kvm, gfn, sp);
-	pte_list_remove(spte, rmapp);
+	rmap_head = gfn_to_rmap(kvm, gfn, sp);
+	pte_list_remove(spte, rmap_head);
 }
 
 /*
@@ -1102,17 +1182,18 @@
  *
  * Returns sptep if found, NULL otherwise.
  */
-static u64 *rmap_get_first(unsigned long rmap, struct rmap_iterator *iter)
+static u64 *rmap_get_first(struct kvm_rmap_head *rmap_head,
+			   struct rmap_iterator *iter)
 {
-	if (!rmap)
+	if (!rmap_head->val)
 		return NULL;
 
-	if (!(rmap & 1)) {
+	if (!(rmap_head->val & 1)) {
 		iter->desc = NULL;
-		return (u64 *)rmap;
+		return (u64 *)rmap_head->val;
 	}
 
-	iter->desc = (struct pte_list_desc *)(rmap & ~1ul);
+	iter->desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
 	iter->pos = 0;
 	return iter->desc->sptes[iter->pos];
 }
@@ -1146,10 +1227,10 @@
 	return NULL;
 }
 
-#define for_each_rmap_spte(_rmap_, _iter_, _spte_)			    \
-	   for (_spte_ = rmap_get_first(*_rmap_, _iter_);		    \
-		_spte_ && ({BUG_ON(!is_shadow_present_pte(*_spte_)); 1;});  \
-			_spte_ = rmap_get_next(_iter_))
+#define for_each_rmap_spte(_rmap_head_, _iter_, _spte_)			\
+	for (_spte_ = rmap_get_first(_rmap_head_, _iter_);		\
+	     _spte_ && ({BUG_ON(!is_shadow_present_pte(*_spte_)); 1;});	\
+	     _spte_ = rmap_get_next(_iter_))
 
 static void drop_spte(struct kvm *kvm, u64 *sptep)
 {
@@ -1207,14 +1288,15 @@
 	return mmu_spte_update(sptep, spte);
 }
 
-static bool __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp,
+static bool __rmap_write_protect(struct kvm *kvm,
+				 struct kvm_rmap_head *rmap_head,
 				 bool pt_protect)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
 	bool flush = false;
 
-	for_each_rmap_spte(rmapp, &iter, sptep)
+	for_each_rmap_spte(rmap_head, &iter, sptep)
 		flush |= spte_write_protect(kvm, sptep, pt_protect);
 
 	return flush;
@@ -1231,13 +1313,13 @@
 	return mmu_spte_update(sptep, spte);
 }
 
-static bool __rmap_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
+static bool __rmap_clear_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
 	bool flush = false;
 
-	for_each_rmap_spte(rmapp, &iter, sptep)
+	for_each_rmap_spte(rmap_head, &iter, sptep)
 		flush |= spte_clear_dirty(kvm, sptep);
 
 	return flush;
@@ -1254,13 +1336,13 @@
 	return mmu_spte_update(sptep, spte);
 }
 
-static bool __rmap_set_dirty(struct kvm *kvm, unsigned long *rmapp)
+static bool __rmap_set_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
 	bool flush = false;
 
-	for_each_rmap_spte(rmapp, &iter, sptep)
+	for_each_rmap_spte(rmap_head, &iter, sptep)
 		flush |= spte_set_dirty(kvm, sptep);
 
 	return flush;
@@ -1280,12 +1362,12 @@
 				     struct kvm_memory_slot *slot,
 				     gfn_t gfn_offset, unsigned long mask)
 {
-	unsigned long *rmapp;
+	struct kvm_rmap_head *rmap_head;
 
 	while (mask) {
-		rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
-				      PT_PAGE_TABLE_LEVEL, slot);
-		__rmap_write_protect(kvm, rmapp, false);
+		rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
+					  PT_PAGE_TABLE_LEVEL, slot);
+		__rmap_write_protect(kvm, rmap_head, false);
 
 		/* clear the first set bit */
 		mask &= mask - 1;
@@ -1305,12 +1387,12 @@
 				     struct kvm_memory_slot *slot,
 				     gfn_t gfn_offset, unsigned long mask)
 {
-	unsigned long *rmapp;
+	struct kvm_rmap_head *rmap_head;
 
 	while (mask) {
-		rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
-				      PT_PAGE_TABLE_LEVEL, slot);
-		__rmap_clear_dirty(kvm, rmapp);
+		rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
+					  PT_PAGE_TABLE_LEVEL, slot);
+		__rmap_clear_dirty(kvm, rmap_head);
 
 		/* clear the first set bit */
 		mask &= mask - 1;
@@ -1342,27 +1424,27 @@
 static bool rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
 {
 	struct kvm_memory_slot *slot;
-	unsigned long *rmapp;
+	struct kvm_rmap_head *rmap_head;
 	int i;
 	bool write_protected = false;
 
 	slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
 
 	for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
-		rmapp = __gfn_to_rmap(gfn, i, slot);
-		write_protected |= __rmap_write_protect(vcpu->kvm, rmapp, true);
+		rmap_head = __gfn_to_rmap(gfn, i, slot);
+		write_protected |= __rmap_write_protect(vcpu->kvm, rmap_head, true);
 	}
 
 	return write_protected;
 }
 
-static bool kvm_zap_rmapp(struct kvm *kvm, unsigned long *rmapp)
+static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
 	bool flush = false;
 
-	while ((sptep = rmap_get_first(*rmapp, &iter))) {
+	while ((sptep = rmap_get_first(rmap_head, &iter))) {
 		BUG_ON(!(*sptep & PT_PRESENT_MASK));
 		rmap_printk("%s: spte %p %llx.\n", __func__, sptep, *sptep);
 
@@ -1373,14 +1455,14 @@
 	return flush;
 }
 
-static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_unmap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
 			   struct kvm_memory_slot *slot, gfn_t gfn, int level,
 			   unsigned long data)
 {
-	return kvm_zap_rmapp(kvm, rmapp);
+	return kvm_zap_rmapp(kvm, rmap_head);
 }
 
-static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
 			     struct kvm_memory_slot *slot, gfn_t gfn, int level,
 			     unsigned long data)
 {
@@ -1395,7 +1477,7 @@
 	new_pfn = pte_pfn(*ptep);
 
 restart:
-	for_each_rmap_spte(rmapp, &iter, sptep) {
+	for_each_rmap_spte(rmap_head, &iter, sptep) {
 		rmap_printk("kvm_set_pte_rmapp: spte %p %llx gfn %llx (%d)\n",
 			     sptep, *sptep, gfn, level);
 
@@ -1433,11 +1515,11 @@
 
 	/* output fields. */
 	gfn_t gfn;
-	unsigned long *rmap;
+	struct kvm_rmap_head *rmap;
 	int level;
 
 	/* private field. */
-	unsigned long *end_rmap;
+	struct kvm_rmap_head *end_rmap;
 };
 
 static void
@@ -1496,7 +1578,7 @@
 				unsigned long end,
 				unsigned long data,
 				int (*handler)(struct kvm *kvm,
-					       unsigned long *rmapp,
+					       struct kvm_rmap_head *rmap_head,
 					       struct kvm_memory_slot *slot,
 					       gfn_t gfn,
 					       int level,
@@ -1540,7 +1622,8 @@
 
 static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
 			  unsigned long data,
-			  int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+			  int (*handler)(struct kvm *kvm,
+					 struct kvm_rmap_head *rmap_head,
 					 struct kvm_memory_slot *slot,
 					 gfn_t gfn, int level,
 					 unsigned long data))
@@ -1563,7 +1646,7 @@
 	kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
 }
 
-static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
 			 struct kvm_memory_slot *slot, gfn_t gfn, int level,
 			 unsigned long data)
 {
@@ -1573,18 +1656,19 @@
 
 	BUG_ON(!shadow_accessed_mask);
 
-	for_each_rmap_spte(rmapp, &iter, sptep)
+	for_each_rmap_spte(rmap_head, &iter, sptep) {
 		if (*sptep & shadow_accessed_mask) {
 			young = 1;
 			clear_bit((ffs(shadow_accessed_mask) - 1),
 				 (unsigned long *)sptep);
 		}
+	}
 
 	trace_kvm_age_page(gfn, level, slot, young);
 	return young;
 }
 
-static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
 			      struct kvm_memory_slot *slot, gfn_t gfn,
 			      int level, unsigned long data)
 {
@@ -1600,11 +1684,12 @@
 	if (!shadow_accessed_mask)
 		goto out;
 
-	for_each_rmap_spte(rmapp, &iter, sptep)
+	for_each_rmap_spte(rmap_head, &iter, sptep) {
 		if (*sptep & shadow_accessed_mask) {
 			young = 1;
 			break;
 		}
+	}
 out:
 	return young;
 }
@@ -1613,14 +1698,14 @@
 
 static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
 {
-	unsigned long *rmapp;
+	struct kvm_rmap_head *rmap_head;
 	struct kvm_mmu_page *sp;
 
 	sp = page_header(__pa(spte));
 
-	rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp);
+	rmap_head = gfn_to_rmap(vcpu->kvm, gfn, sp);
 
-	kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, gfn, sp->role.level, 0);
+	kvm_unmap_rmapp(vcpu->kvm, rmap_head, NULL, gfn, sp->role.level, 0);
 	kvm_flush_remote_tlbs(vcpu->kvm);
 }
 
@@ -1720,8 +1805,7 @@
 	mmu_spte_clear_no_track(parent_pte);
 }
 
-static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
-					       u64 *parent_pte, int direct)
+static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, int direct)
 {
 	struct kvm_mmu_page *sp;
 
@@ -1737,8 +1821,6 @@
 	 * this feature. See the comments in kvm_zap_obsolete_pages().
 	 */
 	list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
-	sp->parent_ptes = 0;
-	mmu_page_add_parent_pte(vcpu, sp, parent_pte);
 	kvm_mod_used_mmu_pages(vcpu->kvm, +1);
 	return sp;
 }
@@ -2083,8 +2165,7 @@
 					     gva_t gaddr,
 					     unsigned level,
 					     int direct,
-					     unsigned access,
-					     u64 *parent_pte)
+					     unsigned access)
 {
 	union kvm_mmu_page_role role;
 	unsigned quadrant;
@@ -2116,21 +2197,18 @@
 		if (sp->unsync && kvm_sync_page_transient(vcpu, sp))
 			break;
 
-		mmu_page_add_parent_pte(vcpu, sp, parent_pte);
-		if (sp->unsync_children) {
+		if (sp->unsync_children)
 			kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
-			kvm_mmu_mark_parents_unsync(sp);
-		} else if (sp->unsync)
-			kvm_mmu_mark_parents_unsync(sp);
 
 		__clear_sp_write_flooding_count(sp);
 		trace_kvm_mmu_get_page(sp, false);
 		return sp;
 	}
+
 	++vcpu->kvm->stat.mmu_cache_miss;
-	sp = kvm_mmu_alloc_page(vcpu, parent_pte, direct);
-	if (!sp)
-		return sp;
+
+	sp = kvm_mmu_alloc_page(vcpu, direct);
+
 	sp->gfn = gfn;
 	sp->role = role;
 	hlist_add_head(&sp->hash_link,
@@ -2198,7 +2276,8 @@
 	return __shadow_walk_next(iterator, *iterator->sptep);
 }
 
-static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp, bool accessed)
+static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep,
+			     struct kvm_mmu_page *sp)
 {
 	u64 spte;
 
@@ -2206,12 +2285,14 @@
 			VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
 
 	spte = __pa(sp->spt) | PT_PRESENT_MASK | PT_WRITABLE_MASK |
-	       shadow_user_mask | shadow_x_mask;
-
-	if (accessed)
-		spte |= shadow_accessed_mask;
+	       shadow_user_mask | shadow_x_mask | shadow_accessed_mask;
 
 	mmu_spte_set(sptep, spte);
+
+	mmu_page_add_parent_pte(vcpu, sp, sptep);
+
+	if (sp->unsync_children || sp->unsync)
+		mark_unsync(sptep);
 }
 
 static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep,
@@ -2270,17 +2351,12 @@
 		mmu_page_zap_pte(kvm, sp, sp->spt + i);
 }
 
-static void kvm_mmu_put_page(struct kvm_mmu_page *sp, u64 *parent_pte)
-{
-	mmu_page_remove_parent_pte(sp, parent_pte);
-}
-
 static void kvm_mmu_unlink_parents(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
 
-	while ((sptep = rmap_get_first(sp->parent_ptes, &iter)))
+	while ((sptep = rmap_get_first(&sp->parent_ptes, &iter)))
 		drop_parent_pte(sp, sptep);
 }
 
@@ -2342,6 +2418,9 @@
 			kvm_reload_remote_mmus(kvm);
 	}
 
+	if (sp->lpage_disallowed)
+		unaccount_huge_nx_page(kvm, sp);
+
 	sp->role.invalid = 1;
 	return ret;
 }
@@ -2499,6 +2578,11 @@
 	if (!speculative)
 		spte |= shadow_accessed_mask;
 
+	if (level > PT_PAGE_TABLE_LEVEL && (pte_access & ACC_EXEC_MASK) &&
+	    is_nx_huge_page_enabled()) {
+		pte_access &= ~ACC_EXEC_MASK;
+	}
+
 	if (pte_access & ACC_EXEC_MASK)
 		spte |= shadow_x_mask;
 	else
@@ -2529,7 +2613,7 @@
 		 * be fixed if guest refault.
 		 */
 		if (level > PT_PAGE_TABLE_LEVEL &&
-		    has_wrprotected_page(vcpu, gfn, level))
+		    mmu_gfn_lpage_is_disallowed(vcpu, gfn, level))
 			goto done;
 
 		spte |= PT_WRITABLE_MASK | SPTE_MMU_WRITEABLE;
@@ -2564,13 +2648,13 @@
 	return ret;
 }
 
-static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
-			 unsigned pte_access, int write_fault, int *emulate,
-			 int level, gfn_t gfn, pfn_t pfn, bool speculative,
-			 bool host_writable)
+static int mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
+			int write_fault, int level, gfn_t gfn, pfn_t pfn,
+			bool speculative, bool host_writable)
 {
 	int was_rmapped = 0;
 	int rmap_count;
+	int ret = RET_PF_RETRY;
 
 	pgprintk("%s: spte %llx write_fault %d gfn %llx\n", __func__,
 		 *sptep, write_fault, gfn);
@@ -2600,18 +2684,15 @@
 	if (set_spte(vcpu, sptep, pte_access, level, gfn, pfn, speculative,
 	      true, host_writable)) {
 		if (write_fault)
-			*emulate = 1;
+			ret = RET_PF_EMULATE;
 		kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
 	}
 
-	if (unlikely(is_mmio_spte(*sptep) && emulate))
-		*emulate = 1;
+	if (unlikely(is_mmio_spte(*sptep)))
+		ret = RET_PF_EMULATE;
 
 	pgprintk("%s: setting spte %llx\n", __func__, *sptep);
-	pgprintk("instantiating %s PTE (%s) at %llx (%llx) addr %p\n",
-		 is_large_pte(*sptep)? "2MB" : "4kB",
-		 *sptep & PT_PRESENT_MASK ?"RW":"R", gfn,
-		 *sptep, sptep);
+	trace_kvm_mmu_set_spte(level, gfn, sptep);
 	if (!was_rmapped && is_large_pte(*sptep))
 		++vcpu->kvm->stat.lpages;
 
@@ -2623,7 +2704,7 @@
 		}
 	}
 
-	kvm_release_pfn_clean(pfn);
+	return ret;
 }
 
 static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
@@ -2657,10 +2738,11 @@
 	if (ret <= 0)
 		return -1;
 
-	for (i = 0; i < ret; i++, gfn++, start++)
-		mmu_set_spte(vcpu, start, access, 0, NULL,
-			     sp->role.level, gfn, page_to_pfn(pages[i]),
-			     true, true);
+	for (i = 0; i < ret; i++, gfn++, start++) {
+		mmu_set_spte(vcpu, start, access, 0, sp->role.level, gfn,
+			     page_to_pfn(pages[i]), true, true);
+		put_page(pages[i]);
+	}
 
 	return 0;
 }
@@ -2708,42 +2790,71 @@
 	__direct_pte_prefetch(vcpu, sp, sptep);
 }
 
-static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
-			int map_writable, int level, gfn_t gfn, pfn_t pfn,
-			bool prefault)
+static void disallowed_hugepage_adjust(struct kvm_shadow_walk_iterator it,
+				       gfn_t gfn, pfn_t *pfnp, int *levelp)
 {
-	struct kvm_shadow_walk_iterator iterator;
+	int level = *levelp;
+	u64 spte = *it.sptep;
+
+	if (it.level == level && level > PT_PAGE_TABLE_LEVEL &&
+	    is_nx_huge_page_enabled() &&
+	    is_shadow_present_pte(spte) &&
+	    !is_large_pte(spte)) {
+		/*
+		 * A small SPTE exists for this pfn, but FNAME(fetch)
+		 * and __direct_map would like to create a large PTE
+		 * instead: just force them to go down another level,
+		 * patching back for them into pfn the next 9 bits of
+		 * the address.
+		 */
+		u64 page_mask = KVM_PAGES_PER_HPAGE(level) - KVM_PAGES_PER_HPAGE(level - 1);
+		*pfnp |= gfn & page_mask;
+		(*levelp)--;
+	}
+}
+
+static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, int write,
+			int map_writable, int level, pfn_t pfn,
+			bool prefault, bool lpage_disallowed)
+{
+	struct kvm_shadow_walk_iterator it;
 	struct kvm_mmu_page *sp;
-	int emulate = 0;
-	gfn_t pseudo_gfn;
+	int ret;
+	gfn_t gfn = gpa >> PAGE_SHIFT;
+	gfn_t base_gfn = gfn;
 
 	if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
-		return 0;
-
-	for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) {
-		if (iterator.level == level) {
-			mmu_set_spte(vcpu, iterator.sptep, ACC_ALL,
-				     write, &emulate, level, gfn, pfn,
-				     prefault, map_writable);
-			direct_pte_prefetch(vcpu, iterator.sptep);
-			++vcpu->stat.pf_fixed;
-			break;
-		}
+		return RET_PF_RETRY;
 
-		drop_large_spte(vcpu, iterator.sptep);
-		if (!is_shadow_present_pte(*iterator.sptep)) {
-			u64 base_addr = iterator.addr;
+	trace_kvm_mmu_spte_requested(gpa, level, pfn);
+	for_each_shadow_entry(vcpu, gpa, it) {
+		/*
+		 * We cannot overwrite existing page tables with an NX
+		 * large page, as the leaf could be executable.
+		 */
+		disallowed_hugepage_adjust(it, gfn, &pfn, &level);
 
-			base_addr &= PT64_LVL_ADDR_MASK(iterator.level);
-			pseudo_gfn = base_addr >> PAGE_SHIFT;
-			sp = kvm_mmu_get_page(vcpu, pseudo_gfn, iterator.addr,
-					      iterator.level - 1,
-					      1, ACC_ALL, iterator.sptep);
+		base_gfn = gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
+		if (it.level == level)
+			break;
 
-			link_shadow_page(iterator.sptep, sp, true);
+		drop_large_spte(vcpu, it.sptep);
+		if (!is_shadow_present_pte(*it.sptep)) {
+			sp = kvm_mmu_get_page(vcpu, base_gfn, it.addr,
+					      it.level - 1, true, ACC_ALL);
+
+			link_shadow_page(vcpu, it.sptep, sp);
+			if (lpage_disallowed)
+				account_huge_nx_page(vcpu->kvm, sp);
 		}
 	}
-	return emulate;
+
+	ret = mmu_set_spte(vcpu, it.sptep, ACC_ALL,
+			   write, level, base_gfn, pfn, prefault,
+			   map_writable);
+	direct_pte_prefetch(vcpu, it.sptep);
+	++vcpu->stat.pf_fixed;
+	return ret;
 }
 
 static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *tsk)
@@ -2765,24 +2876,22 @@
 	 * Do not cache the mmio info caused by writing the readonly gfn
 	 * into the spte otherwise read access on readonly gfn also can
 	 * caused mmio page fault and treat it as mmio access.
-	 * Return 1 to tell kvm to emulate it.
 	 */
 	if (pfn == KVM_PFN_ERR_RO_FAULT)
-		return 1;
+		return RET_PF_EMULATE;
 
 	if (pfn == KVM_PFN_ERR_HWPOISON) {
 		kvm_send_hwpoison_signal(kvm_vcpu_gfn_to_hva(vcpu, gfn), current);
-		return 0;
+		return RET_PF_RETRY;
 	}
 
 	return -EFAULT;
 }
 
 static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
-					gfn_t *gfnp, pfn_t *pfnp, int *levelp)
+					gfn_t gfn, pfn_t *pfnp, int *levelp)
 {
 	pfn_t pfn = *pfnp;
-	gfn_t gfn = *gfnp;
 	int level = *levelp;
 
 	/*
@@ -2794,7 +2903,7 @@
 	if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) &&
 	    level == PT_PAGE_TABLE_LEVEL &&
 	    PageTransCompound(pfn_to_page(pfn)) &&
-	    !has_wrprotected_page(vcpu, gfn, PT_DIRECTORY_LEVEL)) {
+	    !mmu_gfn_lpage_is_disallowed(vcpu, gfn, PT_DIRECTORY_LEVEL)) {
 		unsigned long mask;
 		/*
 		 * mmu_notifier_retry was successful and we hold the
@@ -2809,8 +2918,6 @@
 		mask = KVM_PAGES_PER_HPAGE(level) - 1;
 		VM_BUG_ON((gfn & mask) != (pfn & mask));
 		if (pfn & mask) {
-			gfn &= ~mask;
-			*gfnp = gfn;
 			kvm_release_pfn_clean(pfn);
 			pfn &= ~mask;
 			kvm_get_pfn(pfn);
@@ -2982,11 +3089,14 @@
 {
 	int r;
 	int level;
-	bool force_pt_level = false;
+	bool force_pt_level;
 	pfn_t pfn;
 	unsigned long mmu_seq;
 	bool map_writable, write = error_code & PFERR_WRITE_MASK;
+	bool lpage_disallowed = (error_code & PFERR_FETCH_MASK) &&
+				is_nx_huge_page_enabled();
 
+	force_pt_level = lpage_disallowed;
 	level = mapping_level(vcpu, gfn, &force_pt_level);
 	if (likely(!force_pt_level)) {
 		/*
@@ -3001,34 +3111,30 @@
 	}
 
 	if (fast_page_fault(vcpu, v, level, error_code))
-		return 0;
+		return RET_PF_RETRY;
 
 	mmu_seq = vcpu->kvm->mmu_notifier_seq;
 	smp_rmb();
 
 	if (try_async_pf(vcpu, prefault, gfn, v, &pfn, write, &map_writable))
-		return 0;
+		return RET_PF_RETRY;
 
 	if (handle_abnormal_pfn(vcpu, v, gfn, pfn, ACC_ALL, &r))
 		return r;
 
+	r = RET_PF_RETRY;
 	spin_lock(&vcpu->kvm->mmu_lock);
 	if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
 		goto out_unlock;
 	make_mmu_pages_available(vcpu);
 	if (likely(!force_pt_level))
-		transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level);
-	r = __direct_map(vcpu, v, write, map_writable, level, gfn, pfn,
-			 prefault);
-	spin_unlock(&vcpu->kvm->mmu_lock);
-
-
-	return r;
-
+		transparent_hugepage_adjust(vcpu, gfn, &pfn, &level);
+	r = __direct_map(vcpu, v, write, map_writable, level, pfn,
+			 prefault, false);
 out_unlock:
 	spin_unlock(&vcpu->kvm->mmu_lock);
 	kvm_release_pfn_clean(pfn);
-	return 0;
+	return r;
 }
 
 
@@ -3097,8 +3203,7 @@
 	if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
 		spin_lock(&vcpu->kvm->mmu_lock);
 		make_mmu_pages_available(vcpu);
-		sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL,
-				      1, ACC_ALL, NULL);
+		sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL, 1, ACC_ALL);
 		++sp->root_count;
 		spin_unlock(&vcpu->kvm->mmu_lock);
 		vcpu->arch.mmu.root_hpa = __pa(sp->spt);
@@ -3110,9 +3215,7 @@
 			spin_lock(&vcpu->kvm->mmu_lock);
 			make_mmu_pages_available(vcpu);
 			sp = kvm_mmu_get_page(vcpu, i << (30 - PAGE_SHIFT),
-					      i << 30,
-					      PT32_ROOT_LEVEL, 1, ACC_ALL,
-					      NULL);
+					i << 30, PT32_ROOT_LEVEL, 1, ACC_ALL);
 			root = __pa(sp->spt);
 			++sp->root_count;
 			spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3149,7 +3252,7 @@
 		spin_lock(&vcpu->kvm->mmu_lock);
 		make_mmu_pages_available(vcpu);
 		sp = kvm_mmu_get_page(vcpu, root_gfn, 0, PT64_ROOT_LEVEL,
-				      0, ACC_ALL, NULL);
+				      0, ACC_ALL);
 		root = __pa(sp->spt);
 		++sp->root_count;
 		spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3182,9 +3285,8 @@
 		}
 		spin_lock(&vcpu->kvm->mmu_lock);
 		make_mmu_pages_available(vcpu);
-		sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
-				      PT32_ROOT_LEVEL, 0,
-				      ACC_ALL, NULL);
+		sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, PT32_ROOT_LEVEL,
+				      0, ACC_ALL);
 		root = __pa(sp->spt);
 		++sp->root_count;
 		spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3305,7 +3407,7 @@
 	return __is_rsvd_bits_set(&mmu->shadow_zero_check, spte, level);
 }
 
-static bool quickly_check_mmio_pf(struct kvm_vcpu *vcpu, u64 addr, bool direct)
+static bool mmio_info_in_cache(struct kvm_vcpu *vcpu, u64 addr, bool direct)
 {
 	if (direct)
 		return vcpu_match_mmio_gpa(vcpu, addr);
@@ -3359,38 +3461,38 @@
 	return reserved;
 }
 
-int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct)
+static int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct)
 {
 	u64 spte;
 	bool reserved;
 
-	if (quickly_check_mmio_pf(vcpu, addr, direct))
-		return RET_MMIO_PF_EMULATE;
+	if (mmio_info_in_cache(vcpu, addr, direct))
+		return RET_PF_EMULATE;
 
 	reserved = walk_shadow_page_get_mmio_spte(vcpu, addr, &spte);
 	if (WARN_ON(reserved))
-		return RET_MMIO_PF_BUG;
+		return -EINVAL;
 
 	if (is_mmio_spte(spte)) {
 		gfn_t gfn = get_mmio_spte_gfn(spte);
 		unsigned access = get_mmio_spte_access(spte);
 
 		if (!check_mmio_spte(vcpu, spte))
-			return RET_MMIO_PF_INVALID;
+			return RET_PF_INVALID;
 
 		if (direct)
 			addr = 0;
 
 		trace_handle_mmio_page_fault(addr, gfn, access);
 		vcpu_cache_mmio_info(vcpu, addr, gfn, access);
-		return RET_MMIO_PF_EMULATE;
+		return RET_PF_EMULATE;
 	}
 
 	/*
 	 * If the page table is zapped by other cpus, let CPU fault again on
 	 * the address.
 	 */
-	return RET_MMIO_PF_RETRY;
+	return RET_PF_RETRY;
 }
 EXPORT_SYMBOL_GPL(handle_mmio_page_fault);
 
@@ -3402,13 +3504,6 @@
 
 	pgprintk("%s: gva %lx error %x\n", __func__, gva, error_code);
 
-	if (unlikely(error_code & PFERR_RSVD_MASK)) {
-		r = handle_mmio_page_fault(vcpu, gva, true);
-
-		if (likely(r != RET_MMIO_PF_INVALID))
-			return r;
-	}
-
 	r = mmu_topup_memory_caches(vcpu);
 	if (r)
 		return r;
@@ -3421,11 +3516,22 @@
 			     error_code, gfn, prefault);
 }
 
+static u32 alloc_apf_token(struct kvm_vcpu *vcpu)
+{
+	/* make sure the token value is not 0 */
+	u32 id = vcpu->arch.apf.id;
+
+	if (id << 12 == 0)
+		vcpu->arch.apf.id = 1;
+
+	return (vcpu->arch.apf.id++ << 12) | vcpu->vcpu_id;
+}
+
 static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
 {
 	struct kvm_arch_async_pf arch;
 
-	arch.token = (vcpu->arch.apf.id++ << 12) | vcpu->vcpu_id;
+	arch.token = alloc_apf_token(vcpu);
 	arch.gfn = gfn;
 	arch.direct_map = vcpu->arch.mmu.direct_map;
 	arch.cr3 = vcpu->arch.mmu.get_cr3(vcpu);
@@ -3433,12 +3539,15 @@
 	return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch);
 }
 
-static bool can_do_async_pf(struct kvm_vcpu *vcpu)
+bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
 {
 	if (unlikely(!lapic_in_kernel(vcpu) ||
 		     kvm_event_needs_reinjection(vcpu)))
 		return false;
 
+	if (is_guest_mode(vcpu))
+		return false;
+
 	return kvm_x86_ops->interrupt_allowed(vcpu);
 }
 
@@ -3454,7 +3563,7 @@
 	if (!async)
 		return false; /* *pfn has correct page already */
 
-	if (!prefault && can_do_async_pf(vcpu)) {
+	if (!prefault && kvm_can_do_async_pf(vcpu)) {
 		trace_kvm_try_async_get_page(gva, gfn);
 		if (kvm_find_async_pf_gfn(vcpu, gfn)) {
 			trace_kvm_async_pf_doublefault(gva, gfn);
@@ -3489,22 +3598,18 @@
 	unsigned long mmu_seq;
 	int write = error_code & PFERR_WRITE_MASK;
 	bool map_writable;
+	bool lpage_disallowed = (error_code & PFERR_FETCH_MASK) &&
+				is_nx_huge_page_enabled();
 
 	MMU_WARN_ON(!VALID_PAGE(vcpu->arch.mmu.root_hpa));
 
-	if (unlikely(error_code & PFERR_RSVD_MASK)) {
-		r = handle_mmio_page_fault(vcpu, gpa, true);
-
-		if (likely(r != RET_MMIO_PF_INVALID))
-			return r;
-	}
-
 	r = mmu_topup_memory_caches(vcpu);
 	if (r)
 		return r;
 
-	force_pt_level = !check_hugepage_cache_consistency(vcpu, gfn,
-							   PT_DIRECTORY_LEVEL);
+	force_pt_level =
+		lpage_disallowed ||
+		!check_hugepage_cache_consistency(vcpu, gfn, PT_DIRECTORY_LEVEL);
 	level = mapping_level(vcpu, gfn, &force_pt_level);
 	if (likely(!force_pt_level)) {
 		if (level > PT_DIRECTORY_LEVEL &&
@@ -3514,33 +3619,30 @@
 	}
 
 	if (fast_page_fault(vcpu, gpa, level, error_code))
-		return 0;
+		return RET_PF_RETRY;
 
 	mmu_seq = vcpu->kvm->mmu_notifier_seq;
 	smp_rmb();
 
 	if (try_async_pf(vcpu, prefault, gfn, gpa, &pfn, write, &map_writable))
-		return 0;
+		return RET_PF_RETRY;
 
 	if (handle_abnormal_pfn(vcpu, 0, gfn, pfn, ACC_ALL, &r))
 		return r;
 
+	r = RET_PF_RETRY;
 	spin_lock(&vcpu->kvm->mmu_lock);
 	if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
 		goto out_unlock;
 	make_mmu_pages_available(vcpu);
 	if (likely(!force_pt_level))
-		transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level);
-	r = __direct_map(vcpu, gpa, write, map_writable,
-			 level, gfn, pfn, prefault);
-	spin_unlock(&vcpu->kvm->mmu_lock);
-
-	return r;
-
+		transparent_hugepage_adjust(vcpu, gfn, &pfn, &level);
+	r = __direct_map(vcpu, gpa, write, map_writable, level, pfn,
+			 prefault, lpage_disallowed);
 out_unlock:
 	spin_unlock(&vcpu->kvm->mmu_lock);
 	kvm_release_pfn_clean(pfn);
-	return 0;
+	return r;
 }
 
 static void nonpaging_init_context(struct kvm_vcpu *vcpu,
@@ -3676,7 +3778,7 @@
 			nonleaf_bit8_rsvd | rsvd_bits(7, 7) |
 			rsvd_bits(maxphyaddr, 51);
 		rsvd_check->rsvd_bits_mask[0][2] = exb_bit_rsvd |
-			nonleaf_bit8_rsvd | gbpages_bit_rsvd |
+			gbpages_bit_rsvd |
 			rsvd_bits(maxphyaddr, 51);
 		rsvd_check->rsvd_bits_mask[0][1] = exb_bit_rsvd |
 			rsvd_bits(maxphyaddr, 51);
@@ -3754,13 +3856,15 @@
 void
 reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
 {
+	bool uses_nx = context->nx || context->base_role.smep_andnot_wp;
+
 	/*
 	 * Passing "true" to the last argument is okay; it adds a check
 	 * on bit 8 of the SPTEs which KVM doesn't use anyway.
 	 */
 	__reset_rsvds_bits_mask(vcpu, &context->shadow_zero_check,
 				boot_cpu_data.x86_phys_bits,
-				context->shadow_root_level, context->nx,
+				context->shadow_root_level, uses_nx,
 				guest_cpuid_has_gbpages(vcpu), is_pse(vcpu),
 				true);
 }
@@ -4169,9 +4273,9 @@
 }
 
 static u64 mmu_pte_write_fetch_gpte(struct kvm_vcpu *vcpu, gpa_t *gpa,
-				    const u8 *new, int *bytes)
+				    int *bytes)
 {
-	u64 gentry;
+	u64 gentry = 0;
 	int r;
 
 	/*
@@ -4183,22 +4287,12 @@
 		/* Handle a 32-bit guest writing two halves of a 64-bit gpte */
 		*gpa &= ~(gpa_t)7;
 		*bytes = 8;
-		r = kvm_vcpu_read_guest(vcpu, *gpa, &gentry, 8);
-		if (r)
-			gentry = 0;
-		new = (const u8 *)&gentry;
 	}
 
-	switch (*bytes) {
-	case 4:
-		gentry = *(const u32 *)new;
-		break;
-	case 8:
-		gentry = *(const u64 *)new;
-		break;
-	default:
-		gentry = 0;
-		break;
+	if (*bytes == 4 || *bytes == 8) {
+		r = kvm_vcpu_read_guest_atomic(vcpu, *gpa, &gentry, *bytes);
+		if (r)
+			gentry = 0;
 	}
 
 	return gentry;
@@ -4308,8 +4402,6 @@
 
 	pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes);
 
-	gentry = mmu_pte_write_fetch_gpte(vcpu, &gpa, new, &bytes);
-
 	/*
 	 * No need to care whether allocation memory is successful
 	 * or not since pte prefetch is skiped if it does not have
@@ -4318,6 +4410,9 @@
 	mmu_topup_memory_caches(vcpu);
 
 	spin_lock(&vcpu->kvm->mmu_lock);
+
+	gentry = mmu_pte_write_fetch_gpte(vcpu, &gpa, &bytes);
+
 	++vcpu->kvm->stat.mmu_pte_write;
 	kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE);
 
@@ -4385,32 +4480,35 @@
 	kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
 }
 
-static bool is_mmio_page_fault(struct kvm_vcpu *vcpu, gva_t addr)
-{
-	if (vcpu->arch.mmu.direct_map || mmu_is_nested(vcpu))
-		return vcpu_match_mmio_gpa(vcpu, addr);
-
-	return vcpu_match_mmio_gva(vcpu, addr);
-}
-
 int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code,
 		       void *insn, int insn_len)
 {
 	int r, emulation_type = EMULTYPE_RETRY;
 	enum emulation_result er;
+	bool direct = vcpu->arch.mmu.direct_map || mmu_is_nested(vcpu);
 
-	r = vcpu->arch.mmu.page_fault(vcpu, cr2, error_code, false);
-	if (r < 0)
-		goto out;
+	r = RET_PF_INVALID;
+	if (unlikely(error_code & PFERR_RSVD_MASK)) {
+		r = handle_mmio_page_fault(vcpu, cr2, direct);
+		if (r == RET_PF_EMULATE) {
+			emulation_type = 0;
+			goto emulate;
+		}
+	}
 
-	if (!r) {
-		r = 1;
-		goto out;
+	if (r == RET_PF_INVALID) {
+		r = vcpu->arch.mmu.page_fault(vcpu, cr2, error_code, false);
+		WARN_ON(r == RET_PF_INVALID);
 	}
 
-	if (is_mmio_page_fault(vcpu, cr2))
-		emulation_type = 0;
+	if (r == RET_PF_RETRY)
+		return 1;
+	if (r < 0)
+		return r;
 
+	if (mmio_info_in_cache(vcpu, cr2, direct))
+		emulation_type = 0;
+emulate:
 	er = x86_emulate_instruction(vcpu, cr2, emulation_type, insn, insn_len);
 
 	switch (er) {
@@ -4424,8 +4522,6 @@
 	default:
 		BUG();
 	}
-out:
-	return r;
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_page_fault);
 
@@ -4495,10 +4591,10 @@
 }
 
 /* The return value indicates if tlb flush on all vcpus is needed. */
-typedef bool (*slot_level_handler) (struct kvm *kvm, unsigned long *rmap);
+typedef bool (*slot_level_handler) (struct kvm *kvm, struct kvm_rmap_head *rmap_head);
 
 /* The caller should hold mmu-lock before calling this function. */
-static bool
+static __always_inline bool
 slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot,
 			slot_level_handler fn, int start_level, int end_level,
 			gfn_t start_gfn, gfn_t end_gfn, bool lock_flush_tlb)
@@ -4528,7 +4624,7 @@
 	return flush;
 }
 
-static bool
+static __always_inline bool
 slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
 		  slot_level_handler fn, int start_level, int end_level,
 		  bool lock_flush_tlb)
@@ -4539,7 +4635,7 @@
 			lock_flush_tlb);
 }
 
-static bool
+static __always_inline bool
 slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
 		      slot_level_handler fn, bool lock_flush_tlb)
 {
@@ -4547,7 +4643,7 @@
 				 PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb);
 }
 
-static bool
+static __always_inline bool
 slot_handle_large_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
 			slot_level_handler fn, bool lock_flush_tlb)
 {
@@ -4555,7 +4651,7 @@
 				 PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb);
 }
 
-static bool
+static __always_inline bool
 slot_handle_leaf(struct kvm *kvm, struct kvm_memory_slot *memslot,
 		 slot_level_handler fn, bool lock_flush_tlb)
 {
@@ -4589,9 +4685,10 @@
 	spin_unlock(&kvm->mmu_lock);
 }
 
-static bool slot_rmap_write_protect(struct kvm *kvm, unsigned long *rmapp)
+static bool slot_rmap_write_protect(struct kvm *kvm,
+				    struct kvm_rmap_head *rmap_head)
 {
-	return __rmap_write_protect(kvm, rmapp, false);
+	return __rmap_write_protect(kvm, rmap_head, false);
 }
 
 void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
@@ -4627,7 +4724,7 @@
 }
 
 static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
-		unsigned long *rmapp)
+					 struct kvm_rmap_head *rmap_head)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
@@ -4636,7 +4733,7 @@
 	struct kvm_mmu_page *sp;
 
 restart:
-	for_each_rmap_spte(rmapp, &iter, sptep) {
+	for_each_rmap_spte(rmap_head, &iter, sptep) {
 		sp = page_header(__pa(sptep));
 		pfn = spte_to_pfn(*sptep);
 
@@ -4831,7 +4928,7 @@
 	int nr_to_scan = sc->nr_to_scan;
 	unsigned long freed = 0;
 
-	spin_lock(&kvm_lock);
+	mutex_lock(&kvm_lock);
 
 	list_for_each_entry(kvm, &vm_list, vm_list) {
 		int idx;
@@ -4881,7 +4978,7 @@
 		break;
 	}
 
-	spin_unlock(&kvm_lock);
+	mutex_unlock(&kvm_lock);
 	return freed;
 }
 
@@ -4905,8 +5002,58 @@
 		kmem_cache_destroy(mmu_page_header_cache);
 }
 
+static bool get_nx_auto_mode(void)
+{
+	/* Return true when CPU has the bug, and mitigations are ON */
+	return boot_cpu_has_bug(X86_BUG_ITLB_MULTIHIT) && !cpu_mitigations_off();
+}
+
+static void __set_nx_huge_pages(bool val)
+{
+	nx_huge_pages = itlb_multihit_kvm_mitigation = val;
+}
+
+static int set_nx_huge_pages(const char *val, const struct kernel_param *kp)
+{
+	bool old_val = nx_huge_pages;
+	bool new_val;
+
+	/* In "auto" mode deploy workaround only if CPU has the bug. */
+	if (sysfs_streq(val, "off"))
+		new_val = 0;
+	else if (sysfs_streq(val, "force"))
+		new_val = 1;
+	else if (sysfs_streq(val, "auto"))
+		new_val = get_nx_auto_mode();
+	else if (strtobool(val, &new_val) < 0)
+		return -EINVAL;
+
+	__set_nx_huge_pages(new_val);
+
+	if (new_val != old_val) {
+		struct kvm *kvm;
+		int idx;
+
+		mutex_lock(&kvm_lock);
+
+		list_for_each_entry(kvm, &vm_list, vm_list) {
+			idx = srcu_read_lock(&kvm->srcu);
+			kvm_mmu_invalidate_zap_all_pages(kvm);
+			srcu_read_unlock(&kvm->srcu, idx);
+
+			wake_up_process(kvm->arch.nx_lpage_recovery_thread);
+		}
+		mutex_unlock(&kvm_lock);
+	}
+
+	return 0;
+}
+
 int kvm_mmu_module_init(void)
 {
+	if (nx_huge_pages == -1)
+		__set_nx_huge_pages(get_nx_auto_mode());
+
 	pte_list_desc_cache = kmem_cache_create("pte_list_desc",
 					    sizeof(struct pte_list_desc),
 					    0, 0, NULL);
@@ -4970,3 +5117,116 @@
 	unregister_shrinker(&mmu_shrinker);
 	mmu_audit_disable();
 }
+
+static int set_nx_huge_pages_recovery_ratio(const char *val, const struct kernel_param *kp)
+{
+	unsigned int old_val;
+	int err;
+
+	old_val = nx_huge_pages_recovery_ratio;
+	err = param_set_uint(val, kp);
+	if (err)
+		return err;
+
+	if (READ_ONCE(nx_huge_pages) &&
+	    !old_val && nx_huge_pages_recovery_ratio) {
+		struct kvm *kvm;
+
+		mutex_lock(&kvm_lock);
+
+		list_for_each_entry(kvm, &vm_list, vm_list)
+			wake_up_process(kvm->arch.nx_lpage_recovery_thread);
+
+		mutex_unlock(&kvm_lock);
+	}
+
+	return err;
+}
+
+static void kvm_recover_nx_lpages(struct kvm *kvm)
+{
+	int rcu_idx;
+	struct kvm_mmu_page *sp;
+	unsigned int ratio;
+	LIST_HEAD(invalid_list);
+	ulong to_zap;
+
+	rcu_idx = srcu_read_lock(&kvm->srcu);
+	spin_lock(&kvm->mmu_lock);
+
+	ratio = READ_ONCE(nx_huge_pages_recovery_ratio);
+	to_zap = ratio ? DIV_ROUND_UP(kvm->stat.nx_lpage_splits, ratio) : 0;
+	while (to_zap && !list_empty(&kvm->arch.lpage_disallowed_mmu_pages)) {
+		/*
+		 * We use a separate list instead of just using active_mmu_pages
+		 * because the number of lpage_disallowed pages is expected to
+		 * be relatively small compared to the total.
+		 */
+		sp = list_first_entry(&kvm->arch.lpage_disallowed_mmu_pages,
+				      struct kvm_mmu_page,
+				      lpage_disallowed_link);
+		WARN_ON_ONCE(!sp->lpage_disallowed);
+		kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
+		WARN_ON_ONCE(sp->lpage_disallowed);
+
+		if (!--to_zap || need_resched() || spin_needbreak(&kvm->mmu_lock)) {
+			kvm_mmu_commit_zap_page(kvm, &invalid_list);
+			if (to_zap)
+				cond_resched_lock(&kvm->mmu_lock);
+		}
+	}
+
+	spin_unlock(&kvm->mmu_lock);
+	srcu_read_unlock(&kvm->srcu, rcu_idx);
+}
+
+static long get_nx_lpage_recovery_timeout(u64 start_time)
+{
+	return READ_ONCE(nx_huge_pages) && READ_ONCE(nx_huge_pages_recovery_ratio)
+		? start_time + 60 * HZ - get_jiffies_64()
+		: MAX_SCHEDULE_TIMEOUT;
+}
+
+static int kvm_nx_lpage_recovery_worker(struct kvm *kvm, uintptr_t data)
+{
+	u64 start_time;
+	long remaining_time;
+
+	while (true) {
+		start_time = get_jiffies_64();
+		remaining_time = get_nx_lpage_recovery_timeout(start_time);
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		while (!kthread_should_stop() && remaining_time > 0) {
+			schedule_timeout(remaining_time);
+			remaining_time = get_nx_lpage_recovery_timeout(start_time);
+			set_current_state(TASK_INTERRUPTIBLE);
+		}
+
+		set_current_state(TASK_RUNNING);
+
+		if (kthread_should_stop())
+			return 0;
+
+		kvm_recover_nx_lpages(kvm);
+	}
+}
+
+int kvm_mmu_post_init_vm(struct kvm *kvm)
+{
+	int err;
+
+	err = kvm_vm_create_worker_thread(kvm, kvm_nx_lpage_recovery_worker, 0,
+					  "kvm-nx-lpage-recovery",
+					  &kvm->arch.nx_lpage_recovery_thread);
+	if (!err)
+		kthread_unpark(kvm->arch.nx_lpage_recovery_thread);
+
+	return err;
+}
+
+void kvm_mmu_pre_destroy_vm(struct kvm *kvm)
+{
+	if (kvm->arch.nx_lpage_recovery_thread)
+		kthread_stop(kvm->arch.nx_lpage_recovery_thread);
+}
--- linux-4.4.0.orig/arch/x86/kvm/mmu.h
+++ linux-4.4.0/arch/x86/kvm/mmu.h
@@ -55,25 +55,9 @@
 void
 reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
 
-/*
- * Return values of handle_mmio_page_fault:
- * RET_MMIO_PF_EMULATE: it is a real mmio page fault, emulate the instruction
- *			directly.
- * RET_MMIO_PF_INVALID: invalid spte is detected then let the real page
- *			fault path update the mmio spte.
- * RET_MMIO_PF_RETRY: let CPU fault again on the address.
- * RET_MMIO_PF_BUG: a bug was detected (and a WARN was printed).
- */
-enum {
-	RET_MMIO_PF_EMULATE = 1,
-	RET_MMIO_PF_INVALID = 2,
-	RET_MMIO_PF_RETRY = 0,
-	RET_MMIO_PF_BUG = -1
-};
-
-int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct);
 void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu);
 void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly);
+bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu);
 
 static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
 {
@@ -174,4 +158,11 @@
 
 void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
 void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end);
+
+void kvm_mmu_gfn_disallow_lpage(struct kvm_memory_slot *slot, gfn_t gfn);
+void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn);
+
+int kvm_mmu_post_init_vm(struct kvm *kvm);
+void kvm_mmu_pre_destroy_vm(struct kvm *kvm);
+
 #endif
--- linux-4.4.0.orig/arch/x86/kvm/mmu_audit.c
+++ linux-4.4.0/arch/x86/kvm/mmu_audit.c
@@ -129,7 +129,7 @@
 static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
 {
 	static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
-	unsigned long *rmapp;
+	struct kvm_rmap_head *rmap_head;
 	struct kvm_mmu_page *rev_sp;
 	struct kvm_memslots *slots;
 	struct kvm_memory_slot *slot;
@@ -150,8 +150,8 @@
 		return;
 	}
 
-	rmapp = __gfn_to_rmap(gfn, rev_sp->role.level, slot);
-	if (!*rmapp) {
+	rmap_head = __gfn_to_rmap(gfn, rev_sp->role.level, slot);
+	if (!rmap_head->val) {
 		if (!__ratelimit(&ratelimit_state))
 			return;
 		audit_printk(kvm, "no rmap for writable spte %llx\n",
@@ -192,7 +192,7 @@
 
 static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
-	unsigned long *rmapp;
+	struct kvm_rmap_head *rmap_head;
 	u64 *sptep;
 	struct rmap_iterator iter;
 	struct kvm_memslots *slots;
@@ -203,13 +203,14 @@
 
 	slots = kvm_memslots_for_spte_role(kvm, sp->role);
 	slot = __gfn_to_memslot(slots, sp->gfn);
-	rmapp = __gfn_to_rmap(sp->gfn, PT_PAGE_TABLE_LEVEL, slot);
+	rmap_head = __gfn_to_rmap(sp->gfn, PT_PAGE_TABLE_LEVEL, slot);
 
-	for_each_rmap_spte(rmapp, &iter, sptep)
+	for_each_rmap_spte(rmap_head, &iter, sptep) {
 		if (is_writable_pte(*sptep))
 			audit_printk(kvm, "shadow page has writable "
 				     "mappings: gfn %llx role %x\n",
 				     sp->gfn, sp->role.word);
+	}
 }
 
 static void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
--- linux-4.4.0.orig/arch/x86/kvm/mmutrace.h
+++ linux-4.4.0/arch/x86/kvm/mmutrace.h
@@ -322,6 +322,65 @@
 		  __entry->kvm_gen == __entry->spte_gen
 	)
 );
+
+TRACE_EVENT(
+	kvm_mmu_set_spte,
+	TP_PROTO(int level, gfn_t gfn, u64 *sptep),
+	TP_ARGS(level, gfn, sptep),
+
+	TP_STRUCT__entry(
+		__field(u64, gfn)
+		__field(u64, spte)
+		__field(u64, sptep)
+		__field(u8, level)
+		/* These depend on page entry type, so compute them now.  */
+		__field(bool, r)
+		__field(bool, x)
+		__field(u8, u)
+	),
+
+	TP_fast_assign(
+		__entry->gfn = gfn;
+		__entry->spte = *sptep;
+		__entry->sptep = virt_to_phys(sptep);
+		__entry->level = level;
+		__entry->r = __entry->spte & PT_PRESENT_MASK;
+		__entry->x = (__entry->spte & (shadow_x_mask | shadow_nx_mask)) == shadow_x_mask;
+		__entry->u = shadow_user_mask ? !!(__entry->spte & shadow_user_mask) : -1;
+	),
+
+	TP_printk("gfn %llx spte %llx (%s%s%s%s) level %d at %llx",
+		  __entry->gfn, __entry->spte,
+		  __entry->r ? "r" : "-",
+		  __entry->spte & PT_WRITABLE_MASK ? "w" : "-",
+		  __entry->x ? "x" : "-",
+		  __entry->u == -1 ? "" : (__entry->u ? "u" : "-"),
+		  __entry->level, __entry->sptep
+	)
+);
+
+TRACE_EVENT(
+	kvm_mmu_spte_requested,
+	TP_PROTO(gpa_t addr, int level, pfn_t pfn),
+	TP_ARGS(addr, level, pfn),
+
+	TP_STRUCT__entry(
+		__field(u64, gfn)
+		__field(u64, pfn)
+		__field(u8, level)
+	),
+
+	TP_fast_assign(
+		__entry->gfn = addr >> PAGE_SHIFT;
+		__entry->pfn = pfn | (__entry->gfn & (KVM_PAGES_PER_HPAGE(level) - 1));
+		__entry->level = level;
+	),
+
+	TP_printk("gfn %llx pfn %llx level %d",
+		  __entry->gfn, __entry->pfn, __entry->level
+	)
+);
+
 #endif /* _TRACE_KVMMMU_H */
 
 #undef TRACE_INCLUDE_PATH
--- linux-4.4.0.orig/arch/x86/kvm/mtrr.c
+++ linux-4.4.0/arch/x86/kvm/mtrr.c
@@ -17,6 +17,7 @@
  */
 
 #include <linux/kvm_host.h>
+#include <linux/nospec.h>
 #include <asm/mtrr.h>
 
 #include "cpuid.h"
@@ -44,8 +45,6 @@
 	case MSR_MTRRdefType:
 	case MSR_IA32_CR_PAT:
 		return true;
-	case 0x2f8:
-		return true;
 	}
 	return false;
 }
@@ -204,11 +203,15 @@
 		break;
 	case MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000:
 		*seg = 1;
-		*unit = msr - MSR_MTRRfix16K_80000;
+		*unit = array_index_nospec(
+			msr - MSR_MTRRfix16K_80000,
+			MSR_MTRRfix16K_A0000 - MSR_MTRRfix16K_80000 + 1);
 		break;
 	case MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000:
 		*seg = 2;
-		*unit = msr - MSR_MTRRfix4K_C0000;
+		*unit = array_index_nospec(
+			msr - MSR_MTRRfix4K_C0000,
+			MSR_MTRRfix4K_F8000 - MSR_MTRRfix4K_C0000 + 1);
 		break;
 	default:
 		return false;
@@ -541,6 +544,7 @@
 
 	iter->fixed = false;
 	iter->start_max = iter->start;
+	iter->range = NULL;
 	iter->range = list_prepare_entry(iter->range, &mtrr_state->head, node);
 
 	__mtrr_lookup_var_next(iter);
--- linux-4.4.0.orig/arch/x86/kvm/paging_tmpl.h
+++ linux-4.4.0/arch/x86/kvm/paging_tmpl.h
@@ -100,8 +100,8 @@
 	gpa_t pte_gpa[PT_MAX_FULL_LEVELS];
 	pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS];
 	bool pte_writable[PT_MAX_FULL_LEVELS];
-	unsigned pt_access;
-	unsigned pte_access;
+	unsigned int pt_access[PT_MAX_FULL_LEVELS];
+	unsigned int pte_access;
 	gfn_t gfn;
 	struct x86_exception fault;
 };
@@ -181,7 +181,7 @@
 	return true;
 }
 
-static inline unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, u64 gpte)
+static inline unsigned FNAME(gpte_access)(u64 gpte)
 {
 	unsigned access;
 #if PTTYPE == PTTYPE_EPT
@@ -249,7 +249,7 @@
 			return ret;
 
 		kvm_vcpu_mark_page_dirty(vcpu, table_gfn);
-		walker->ptes[level] = pte;
+		walker->ptes[level - 1] = pte;
 	}
 	return 0;
 }
@@ -265,9 +265,11 @@
 	pt_element_t pte;
 	pt_element_t __user *uninitialized_var(ptep_user);
 	gfn_t table_gfn;
-	unsigned index, pt_access, pte_access, accessed_dirty;
+	u64 pt_access, pte_access;
+	unsigned index, accessed_dirty;
 	gpa_t pte_gpa;
 	int offset;
+	u64 walk_nx_mask = 0;
 	const int write_fault = access & PFERR_WRITE_MASK;
 	const int user_fault  = access & PFERR_USER_MASK;
 	const int fetch_fault = access & PFERR_FETCH_MASK;
@@ -281,6 +283,7 @@
 	pte           = mmu->get_cr3(vcpu);
 
 #if PTTYPE == 64
+	walk_nx_mask = 1ULL << PT64_NX_SHIFT;
 	if (walker->level == PT32E_ROOT_LEVEL) {
 		pte = mmu->get_pdptr(vcpu, (addr >> 30) & 3);
 		trace_kvm_mmu_paging_element(pte, walker->level);
@@ -292,15 +295,14 @@
 	walker->max_level = walker->level;
 	ASSERT(!(is_long_mode(vcpu) && !is_pae(vcpu)));
 
-	accessed_dirty = PT_GUEST_ACCESSED_MASK;
-	pt_access = pte_access = ACC_ALL;
+	pte_access = ~0;
 	++walker->level;
 
 	do {
 		gfn_t real_gfn;
 		unsigned long host_addr;
 
-		pt_access &= pte_access;
+		pt_access = pte_access;
 		--walker->level;
 
 		index = PT_INDEX(addr, walker->level);
@@ -342,6 +344,12 @@
 
 		trace_kvm_mmu_paging_element(pte, walker->level);
 
+		/*
+		 * Inverting the NX it lets us AND it like other
+		 * permission bits.
+		 */
+		pte_access = pt_access & (pte ^ walk_nx_mask);
+
 		if (unlikely(!FNAME(is_present_gpte)(pte)))
 			goto error;
 
@@ -350,16 +358,19 @@
 			goto error;
 		}
 
-		accessed_dirty &= pte;
-		pte_access = pt_access & FNAME(gpte_access)(vcpu, pte);
-
 		walker->ptes[walker->level - 1] = pte;
+
+		/* Convert to ACC_*_MASK flags for struct guest_walker.  */
+		walker->pt_access[walker->level - 1] = FNAME(gpte_access)(pt_access ^ walk_nx_mask);
 	} while (!is_last_gpte(mmu, walker->level, pte));
 
-	if (unlikely(permission_fault(vcpu, mmu, pte_access, access))) {
-		errcode |= PFERR_PRESENT_MASK;
+	accessed_dirty = pte_access & PT_GUEST_ACCESSED_MASK;
+
+	/* Convert to ACC_*_MASK flags for struct guest_walker.  */
+	walker->pte_access = FNAME(gpte_access)(pte_access ^ walk_nx_mask);
+	errcode = permission_fault(vcpu, mmu, walker->pte_access, access);
+	if (unlikely(errcode))
 		goto error;
-	}
 
 	gfn = gpte_to_gfn_lvl(pte, walker->level);
 	gfn += (addr & PT_LVL_OFFSET_MASK(walker->level)) >> PAGE_SHIFT;
@@ -374,7 +385,7 @@
 	walker->gfn = real_gpa >> PAGE_SHIFT;
 
 	if (!write_fault)
-		FNAME(protect_clean_gpte)(&pte_access, pte);
+		FNAME(protect_clean_gpte)(&walker->pte_access, pte);
 	else
 		/*
 		 * On a write fault, fold the dirty bit into accessed_dirty.
@@ -392,10 +403,9 @@
 			goto retry_walk;
 	}
 
-	walker->pt_access = pt_access;
-	walker->pte_access = pte_access;
 	pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
-		 __func__, (u64)pte, pte_access, pt_access);
+		 __func__, (u64)pte, walker->pte_access,
+		 walker->pt_access[walker->level - 1]);
 	return 1;
 
 error:
@@ -423,7 +433,7 @@
 	 */
 	if (!(errcode & PFERR_RSVD_MASK)) {
 		vcpu->arch.exit_qualification &= 0x187;
-		vcpu->arch.exit_qualification |= ((pt_access & pte) & 0x7) << 3;
+		vcpu->arch.exit_qualification |= (pte_access & 0x7) << 3;
 	}
 #endif
 	walker->fault.address = addr;
@@ -464,7 +474,7 @@
 	pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
 
 	gfn = gpte_to_gfn(gpte);
-	pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
+	pte_access = sp->role.access & FNAME(gpte_access)(gpte);
 	FNAME(protect_clean_gpte)(&pte_access, gpte);
 	pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn,
 			no_dirty_log && (pte_access & ACC_WRITE_MASK));
@@ -475,9 +485,10 @@
 	 * we call mmu_set_spte() with host_writable = true because
 	 * pte_prefetch_gfn_to_pfn always gets a writable pfn.
 	 */
-	mmu_set_spte(vcpu, spte, pte_access, 0, NULL, PT_PAGE_TABLE_LEVEL,
-		     gfn, pfn, true, true);
+	mmu_set_spte(vcpu, spte, pte_access, 0, PT_PAGE_TABLE_LEVEL, gfn, pfn,
+		     true, true);
 
+	kvm_release_pfn_clean(pfn);
 	return true;
 }
 
@@ -551,12 +562,14 @@
 static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
 			 struct guest_walker *gw,
 			 int write_fault, int hlevel,
-			 pfn_t pfn, bool map_writable, bool prefault)
+			 pfn_t pfn, bool map_writable, bool prefault,
+			 bool lpage_disallowed)
 {
 	struct kvm_mmu_page *sp = NULL;
 	struct kvm_shadow_walk_iterator it;
-	unsigned direct_access, access = gw->pt_access;
-	int top_level, emulate = 0;
+	unsigned int direct_access, access;
+	int top_level, ret;
+	gfn_t gfn, base_gfn;
 
 	direct_access = gw->pte_access;
 
@@ -586,8 +599,9 @@
 		sp = NULL;
 		if (!is_shadow_present_pte(*it.sptep)) {
 			table_gfn = gw->table_gfn[it.level - 2];
+			access = gw->pt_access[it.level - 2];
 			sp = kvm_mmu_get_page(vcpu, table_gfn, addr, it.level-1,
-					      false, access, it.sptep);
+					      false, access);
 		}
 
 		/*
@@ -598,41 +612,52 @@
 			goto out_gpte_changed;
 
 		if (sp)
-			link_shadow_page(it.sptep, sp, PT_GUEST_ACCESSED_MASK);
+			link_shadow_page(vcpu, it.sptep, sp);
 	}
 
-	for (;
-	     shadow_walk_okay(&it) && it.level > hlevel;
-	     shadow_walk_next(&it)) {
-		gfn_t direct_gfn;
+	/*
+	 * FNAME(page_fault) might have clobbered the bottom bits of
+	 * gw->gfn, restore them from the virtual address.
+	 */
+	gfn = gw->gfn | ((addr & PT_LVL_OFFSET_MASK(gw->level)) >> PAGE_SHIFT);
+	base_gfn = gfn;
+
+	trace_kvm_mmu_spte_requested(addr, gw->level, pfn);
 
+	for (; shadow_walk_okay(&it); shadow_walk_next(&it)) {
 		clear_sp_write_flooding_count(it.sptep);
-		validate_direct_spte(vcpu, it.sptep, direct_access);
 
-		drop_large_spte(vcpu, it.sptep);
+		/*
+		 * We cannot overwrite existing page tables with an NX
+		 * large page, as the leaf could be executable.
+		 */
+		disallowed_hugepage_adjust(it, gfn, &pfn, &hlevel);
 
-		if (is_shadow_present_pte(*it.sptep))
-			continue;
+		base_gfn = gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
+		if (it.level == hlevel)
+			break;
 
-		direct_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
+		validate_direct_spte(vcpu, it.sptep, direct_access);
+
+		drop_large_spte(vcpu, it.sptep);
 
-		sp = kvm_mmu_get_page(vcpu, direct_gfn, addr, it.level-1,
-				      true, direct_access, it.sptep);
-		link_shadow_page(it.sptep, sp, PT_GUEST_ACCESSED_MASK);
+		if (!is_shadow_present_pte(*it.sptep)) {
+			sp = kvm_mmu_get_page(vcpu, base_gfn, addr,
+					      it.level - 1, true, direct_access);
+			link_shadow_page(vcpu, it.sptep, sp);
+			if (lpage_disallowed)
+				account_huge_nx_page(vcpu->kvm, sp);
+		}
 	}
 
-	clear_sp_write_flooding_count(it.sptep);
-	mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault, &emulate,
-		     it.level, gw->gfn, pfn, prefault, map_writable);
+	ret = mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault,
+			   it.level, base_gfn, pfn, prefault, map_writable);
 	FNAME(pte_prefetch)(vcpu, gw, it.sptep);
-
-	return emulate;
+	++vcpu->stat.pf_fixed;
+	return ret;
 
 out_gpte_changed:
-	if (sp)
-		kvm_mmu_put_page(sp, it.sptep);
-	kvm_release_pfn_clean(pfn);
-	return 0;
+	return RET_PF_RETRY;
 }
 
  /*
@@ -698,30 +723,25 @@
 	int r;
 	pfn_t pfn;
 	int level = PT_PAGE_TABLE_LEVEL;
-	bool force_pt_level = false;
 	unsigned long mmu_seq;
 	bool map_writable, is_self_change_mapping;
+	bool lpage_disallowed = (error_code & PFERR_FETCH_MASK) &&
+				is_nx_huge_page_enabled();
+	bool force_pt_level = lpage_disallowed;
 
 	pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
 
-	if (unlikely(error_code & PFERR_RSVD_MASK)) {
-		r = handle_mmio_page_fault(vcpu, addr, mmu_is_nested(vcpu));
-		if (likely(r != RET_MMIO_PF_INVALID))
-			return r;
-
-		/*
-		 * page fault with PFEC.RSVD  = 1 is caused by shadow
-		 * page fault, should not be used to walk guest page
-		 * table.
-		 */
-		error_code &= ~PFERR_RSVD_MASK;
-	};
-
 	r = mmu_topup_memory_caches(vcpu);
 	if (r)
 		return r;
 
 	/*
+	 * If PFEC.RSVD is set, this is a shadow page fault.
+	 * The bit needs to be cleared before walking guest page tables.
+	 */
+	error_code &= ~PFERR_RSVD_MASK;
+
+	/*
 	 * Look up the guest pte for the faulting address.
 	 */
 	r = FNAME(walk_addr)(&walker, vcpu, addr, error_code);
@@ -734,7 +754,7 @@
 		if (!prefault)
 			inject_page_fault(vcpu, &walker.fault);
 
-		return 0;
+		return RET_PF_RETRY;
 	}
 
 	vcpu->arch.write_fault_to_shadow_pgtable = false;
@@ -756,7 +776,7 @@
 
 	if (try_async_pf(vcpu, prefault, walker.gfn, addr, &pfn, write_fault,
 			 &map_writable))
-		return 0;
+		return RET_PF_RETRY;
 
 	if (handle_abnormal_pfn(vcpu, mmu_is_nested(vcpu) ? 0 : addr,
 				walker.gfn, pfn, walker.pte_access, &r))
@@ -782,6 +802,7 @@
 			walker.pte_access &= ~ACC_EXEC_MASK;
 	}
 
+	r = RET_PF_RETRY;
 	spin_lock(&vcpu->kvm->mmu_lock);
 	if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
 		goto out_unlock;
@@ -789,19 +810,15 @@
 	kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT);
 	make_mmu_pages_available(vcpu);
 	if (!force_pt_level)
-		transparent_hugepage_adjust(vcpu, &walker.gfn, &pfn, &level);
+		transparent_hugepage_adjust(vcpu, walker.gfn, &pfn, &level);
 	r = FNAME(fetch)(vcpu, addr, &walker, write_fault,
-			 level, pfn, map_writable, prefault);
-	++vcpu->stat.pf_fixed;
+			 level, pfn, map_writable, prefault, lpage_disallowed);
 	kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT);
-	spin_unlock(&vcpu->kvm->mmu_lock);
-
-	return r;
 
 out_unlock:
 	spin_unlock(&vcpu->kvm->mmu_lock);
 	kvm_release_pfn_clean(pfn);
-	return 0;
+	return r;
 }
 
 static gpa_t FNAME(get_level1_sp_gpa)(struct kvm_mmu_page *sp)
@@ -956,7 +973,7 @@
 
 		gfn = gpte_to_gfn(gpte);
 		pte_access = sp->role.access;
-		pte_access &= FNAME(gpte_access)(vcpu, gpte);
+		pte_access &= FNAME(gpte_access)(gpte);
 		FNAME(protect_clean_gpte)(&pte_access, gpte);
 
 		if (sync_mmio_spte(vcpu, &sp->spt[i], gfn, pte_access,
--- linux-4.4.0.orig/arch/x86/kvm/pmu.c
+++ linux-4.4.0/arch/x86/kvm/pmu.c
@@ -124,8 +124,8 @@
 						 intr ? kvm_perf_overflow_intr :
 						 kvm_perf_overflow, pmc);
 	if (IS_ERR(event)) {
-		printk_once("kvm_pmu: event creation failed %ld\n",
-			    PTR_ERR(event));
+		pr_debug_ratelimited("kvm_pmu: event creation failed %ld for pmc->idx = %d\n",
+			    PTR_ERR(event), pmc->idx);
 		return;
 	}
 
--- linux-4.4.0.orig/arch/x86/kvm/pmu.h
+++ linux-4.4.0/arch/x86/kvm/pmu.h
@@ -1,6 +1,8 @@
 #ifndef __KVM_X86_PMU_H
 #define __KVM_X86_PMU_H
 
+#include <linux/nospec.h>
+
 #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu)
 #define pmu_to_vcpu(pmu)  (container_of((pmu), struct kvm_vcpu, arch.pmu))
 #define pmc_to_pmu(pmc)   (&(pmc)->vcpu->arch.pmu)
@@ -80,8 +82,12 @@
 static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr,
 					 u32 base)
 {
-	if (msr >= base && msr < base + pmu->nr_arch_gp_counters)
-		return &pmu->gp_counters[msr - base];
+	if (msr >= base && msr < base + pmu->nr_arch_gp_counters) {
+		u32 index = array_index_nospec(msr - base,
+					       pmu->nr_arch_gp_counters);
+
+		return &pmu->gp_counters[index];
+	}
 
 	return NULL;
 }
@@ -91,8 +97,12 @@
 {
 	int base = MSR_CORE_PERF_FIXED_CTR0;
 
-	if (msr >= base && msr < base + pmu->nr_arch_fixed_counters)
-		return &pmu->fixed_counters[msr - base];
+	if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) {
+		u32 index = array_index_nospec(msr - base,
+					       pmu->nr_arch_fixed_counters);
+
+		return &pmu->fixed_counters[index];
+	}
 
 	return NULL;
 }
--- linux-4.4.0.orig/arch/x86/kvm/pmu_intel.c
+++ linux-4.4.0/arch/x86/kvm/pmu_intel.c
@@ -29,7 +29,7 @@
 	[4] = { 0x2e, 0x41, PERF_COUNT_HW_CACHE_MISSES },
 	[5] = { 0xc4, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
 	[6] = { 0xc5, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
-	[7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
+	[7] = { 0x00, 0x03, PERF_COUNT_HW_REF_CPU_CYCLES },
 };
 
 /* mapping between fixed pmc index and intel_arch_events array */
@@ -87,10 +87,14 @@
 
 static unsigned intel_find_fixed_event(int idx)
 {
-	if (idx >= ARRAY_SIZE(fixed_pmc_events))
+	u32 event;
+	size_t size = ARRAY_SIZE(fixed_pmc_events);
+
+	if (idx >= size)
 		return PERF_COUNT_HW_MAX;
 
-	return intel_arch_events[fixed_pmc_events[idx]].event_type;
+	event = fixed_pmc_events[array_index_nospec(idx, size)];
+	return intel_arch_events[event].event_type;
 }
 
 /* check if a PMC is enabled by comparising it with globl_ctrl bits. */
@@ -131,15 +135,19 @@
 	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
 	bool fixed = idx & (1u << 30);
 	struct kvm_pmc *counters;
+	unsigned int num_counters;
 
 	idx &= ~(3u << 30);
-	if (!fixed && idx >= pmu->nr_arch_gp_counters)
-		return NULL;
-	if (fixed && idx >= pmu->nr_arch_fixed_counters)
+	if (fixed) {
+		counters = pmu->fixed_counters;
+		num_counters = pmu->nr_arch_fixed_counters;
+	} else {
+		counters = pmu->gp_counters;
+		num_counters = pmu->nr_arch_gp_counters;
+	}
+	if (idx >= num_counters)
 		return NULL;
-	counters = fixed ? pmu->fixed_counters : pmu->gp_counters;
-
-	return &counters[idx];
+	return &counters[array_index_nospec(idx, num_counters)];
 }
 
 static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
@@ -235,11 +243,14 @@
 		}
 		break;
 	default:
-		if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
-		    (pmc = get_fixed_pmc(pmu, msr))) {
-			if (!msr_info->host_initiated)
-				data = (s64)(s32)data;
-			pmc->counter += data - pmc_read_counter(pmc);
+		if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0))) {
+			if (msr_info->host_initiated)
+				pmc->counter = data;
+			else
+				pmc->counter = (s32)data;
+			return 0;
+		} else if ((pmc = get_fixed_pmc(pmu, msr))) {
+			pmc->counter = data;
 			return 0;
 		} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
 			if (data == pmc->eventsel)
@@ -294,7 +305,7 @@
 			((u64)1 << edx.split.bit_width_fixed) - 1;
 	}
 
-	pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
+	pmu->global_ctrl = ((1ull << pmu->nr_arch_gp_counters) - 1) |
 		(((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
 	pmu->global_ctrl_mask = ~pmu->global_ctrl;
 
--- linux-4.4.0.orig/arch/x86/kvm/svm.c
+++ linux-4.4.0/arch/x86/kvm/svm.c
@@ -37,6 +37,9 @@
 #include <asm/desc.h>
 #include <asm/debugreg.h>
 #include <asm/kvm_para.h>
+#include <asm/microcode.h>
+#include <asm/spec-ctrl.h>
+#include <asm/cpu_device_id.h>
 
 #include <asm/virtext.h>
 #include "trace.h"
@@ -136,6 +139,8 @@
 	uint64_t sysenter_esp;
 	uint64_t sysenter_eip;
 
+	u64 msr_decfg;
+
 	u64 next_rip;
 
 	u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
@@ -146,6 +151,14 @@
 		u64 gs_base;
 	} host;
 
+	u64 spec_ctrl;
+	/*
+	 * Contains guest-controlled bits of VIRT_SPEC_CTRL, which will be
+	 * translated into the appropriate L2_CFG bits on the host to
+	 * perform speculative control.
+	 */
+	u64 virt_spec_ctrl;
+
 	u32 *msrpm;
 
 	ulong nmi_iret_rip;
@@ -181,6 +194,8 @@
 	{ .index = MSR_CSTAR,				.always = true  },
 	{ .index = MSR_SYSCALL_MASK,			.always = true  },
 #endif
+	{ .index = MSR_IA32_SPEC_CTRL,			.always = false },
+	{ .index = MSR_IA32_PRED_CMD,			.always = false },
 	{ .index = MSR_IA32_LASTBRANCHFROMIP,		.always = false },
 	{ .index = MSR_IA32_LASTBRANCHTOIP,		.always = false },
 	{ .index = MSR_IA32_LASTINTFROMIP,		.always = false },
@@ -410,6 +425,7 @@
 	struct kvm_ldttss_desc *tss_desc;
 
 	struct page *save_area;
+	struct vmcb *current_vmcb;
 };
 
 static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
@@ -475,8 +491,14 @@
 static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
 	vcpu->arch.efer = efer;
-	if (!npt_enabled && !(efer & EFER_LMA))
-		efer &= ~EFER_LME;
+
+	if (!npt_enabled) {
+		/* Shadow paging assumes NX to be available.  */
+		efer |= EFER_NX;
+
+		if (!(efer & EFER_LMA))
+			efer &= ~EFER_LME;
+	}
 
 	to_svm(vcpu)->vmcb->save.efer = efer | EFER_SVME;
 	mark_dirty(to_svm(vcpu)->vmcb, VMCB_CR);
@@ -761,6 +783,25 @@
 	return false;
 }
 
+static bool msr_write_intercepted(struct kvm_vcpu *vcpu, unsigned msr)
+{
+	u8 bit_write;
+	unsigned long tmp;
+	u32 offset;
+	u32 *msrpm;
+
+	msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm:
+				      to_svm(vcpu)->msrpm;
+
+	offset    = svm_msrpm_offset(msr);
+	bit_write = 2 * (msr & 0x0f) + 1;
+	tmp       = msrpm[offset];
+
+	BUG_ON(offset == MSR_INVALID);
+
+	return !!test_bit(bit_write,  &tmp);
+}
+
 static void set_msr_interception(u32 *msrpm, unsigned msr,
 				 int read, int write)
 {
@@ -1119,6 +1160,10 @@
 	u32 dummy;
 	u32 eax = 1;
 
+	vcpu->arch.microcode_version = 0x01000065;
+	svm->spec_ctrl = 0;
+	svm->virt_spec_ctrl = 0;
+
 	if (!init_event) {
 		svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
 					   MSR_IA32_APICBASE_ENABLE;
@@ -1199,10 +1244,25 @@
 	return ERR_PTR(err);
 }
 
+static void svm_clear_current_vmcb(struct vmcb *vmcb)
+{
+	int i;
+
+	for_each_online_cpu(i)
+		cmpxchg(&per_cpu(svm_data, i)->current_vmcb, vmcb, NULL);
+}
+
 static void svm_free_vcpu(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
+	/*
+	 * The vmcb page can be recycled, causing a false negative in
+	 * svm_vcpu_load(). So, ensure that no logical CPU has this
+	 * vmcb page recorded as its current vmcb.
+	 */
+	svm_clear_current_vmcb(svm->vmcb);
+
 	__free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
 	__free_pages(virt_to_page(svm->msrpm), MSRPM_ALLOC_ORDER);
 	__free_page(virt_to_page(svm->nested.hsave));
@@ -1214,6 +1274,7 @@
 static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
+	struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
 	int i;
 
 	if (unlikely(cpu != vcpu->cpu)) {
@@ -1238,6 +1299,11 @@
 			wrmsrl(MSR_AMD64_TSC_RATIO, tsc_ratio);
 		}
 	}
+
+	if (sd->current_vmcb != svm->vmcb) {
+		sd->current_vmcb = svm->vmcb;
+		indirect_branch_prediction_barrier();
+	}
 }
 
 static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1385,6 +1451,7 @@
 		 */
 		if (var->unusable)
 			var->db = 0;
+		/* This is symmetric with svm_set_segment() */
 		var->dpl = to_svm(vcpu)->vmcb->save.cpl;
 		break;
 	}
@@ -1530,18 +1597,14 @@
 	s->base = var->base;
 	s->limit = var->limit;
 	s->selector = var->selector;
-	if (var->unusable)
-		s->attrib = 0;
-	else {
-		s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
-		s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
-		s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
-		s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT;
-		s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
-		s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
-		s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
-		s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
-	}
+	s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
+	s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
+	s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
+	s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT;
+	s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
+	s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
+	s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
+	s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
 
 	/*
 	 * This is always accurate, except if SYSRET returned to a segment
@@ -1550,7 +1613,8 @@
 	 * would entail passing the CPL to userspace and back.
 	 */
 	if (seg == VCPU_SREG_SS)
-		svm->vmcb->save.cpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3;
+		/* This is symmetric with svm_get_segment() */
+		svm->vmcb->save.cpl = (var->dpl & 3);
 
 	mark_dirty(svm->vmcb, VMCB_SEG);
 }
@@ -1624,6 +1688,8 @@
 	u32 error_code;
 	int r = 1;
 
+	svm->vcpu.arch.l1tf_flush_l1d = true;
+
 	switch (svm->apf_reason) {
 	default:
 		error_code = svm->vmcb->control.exit_info_1;
@@ -1696,6 +1762,8 @@
 	int er;
 
 	er = emulate_instruction(&svm->vcpu, EMULTYPE_TRAP_UD);
+	if (er == EMULATE_USER_EXIT)
+		return 0;
 	if (er != EMULATE_DONE)
 		kvm_queue_exception(&svm->vcpu, UD_VECTOR);
 	return 1;
@@ -2205,7 +2273,7 @@
 	dst->iopm_base_pa         = from->iopm_base_pa;
 	dst->msrpm_base_pa        = from->msrpm_base_pa;
 	dst->tsc_offset           = from->tsc_offset;
-	dst->asid                 = from->asid;
+	/* asid not copied, it is handled manually for svm->vmcb.  */
 	dst->tlb_ctl              = from->tlb_ctl;
 	dst->int_ctl              = from->int_ctl;
 	dst->int_vector           = from->int_vector;
@@ -2343,6 +2411,14 @@
 	kvm_mmu_reset_context(&svm->vcpu);
 	kvm_mmu_load(&svm->vcpu);
 
+	/*
+	 * Drop what we picked up for L2 via svm_complete_interrupts() so it
+	 * doesn't end up in L1.
+	 */
+	svm->vcpu.arch.nmi_injected = false;
+	kvm_clear_exception_queue(&svm->vcpu);
+	kvm_clear_interrupt_queue(&svm->vcpu);
+
 	return 0;
 }
 
@@ -2511,7 +2587,11 @@
 	svm->nested.intercept            = nested_vmcb->control.intercept;
 
 	svm_flush_tlb(&svm->vcpu);
-	svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl | V_INTR_MASKING_MASK;
+	svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl &
+			(V_TPR_MASK | V_IRQ_INJECTION_BITS_MASK);
+
+	svm->vmcb->control.int_ctl |= V_INTR_MASKING_MASK;
+
 	if (nested_vmcb->control.int_ctl & V_INTR_MASKING_MASK)
 		svm->vcpu.arch.hflags |= HF_VINTR_MASK;
 	else
@@ -2987,6 +3067,22 @@
 	return vmcb->control.tsc_offset + host_tsc;
 }
 
+static int svm_get_msr_feature(struct kvm_msr_entry *msr)
+{
+	msr->data = 0;
+
+	switch (msr->index) {
+	case MSR_F10H_DECFG:
+		if (boot_cpu_has(X86_FEATURE_LFENCE_RDTSC))
+			msr->data |= MSR_F10H_DECFG_LFENCE_SERIALIZE;
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
 static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
@@ -3050,8 +3146,39 @@
 	case MSR_VM_CR:
 		msr_info->data = svm->nested.vm_cr_msr;
 		break;
-	case MSR_IA32_UCODE_REV:
-		msr_info->data = 0x01000065;
+	case MSR_IA32_SPEC_CTRL:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_spec_ctrl(vcpu))
+			return 1;
+
+		msr_info->data = svm->spec_ctrl;
+		break;
+	case MSR_AMD64_VIRT_SPEC_CTRL:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_virt_ssbd(vcpu))
+			return 1;
+
+		msr_info->data = svm->virt_spec_ctrl;
+		break;
+	case MSR_F15H_IC_CFG: {
+
+		int family, model;
+
+		family = guest_cpuid_family(vcpu);
+		model  = guest_cpuid_model(vcpu);
+
+		if (family < 0 || model < 0)
+			return kvm_get_msr_common(vcpu, msr_info);
+
+		msr_info->data = 0;
+
+		if (family == 0x15 &&
+		    (model >= 0x2 && model < 0x20))
+			msr_info->data = 0x1E;
+		}
+		break;
+	case MSR_F10H_DECFG:
+		msr_info->data = svm->msr_decfg;
 		break;
 	default:
 		return kvm_get_msr_common(vcpu, msr_info);
@@ -3114,9 +3241,69 @@
 	u32 ecx = msr->index;
 	u64 data = msr->data;
 	switch (ecx) {
+	case MSR_IA32_CR_PAT:
+		if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
+			return 1;
+		vcpu->arch.pat = data;
+		svm->vmcb->save.g_pat = data;
+		mark_dirty(svm->vmcb, VMCB_NPT);
+		break;
 	case MSR_IA32_TSC:
 		kvm_write_tsc(vcpu, msr);
 		break;
+	case MSR_IA32_SPEC_CTRL:
+		if (!msr->host_initiated &&
+		    !guest_cpuid_has_spec_ctrl(vcpu))
+			return 1;
+
+		/* The STIBP bit doesn't fault even if it's not advertised */
+		if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_SSBD))
+			return 1;
+
+		svm->spec_ctrl = data;
+
+		if (!data)
+			break;
+
+		/*
+		 * For non-nested:
+		 * When it's written (to non-zero) for the first time, pass
+		 * it through.
+		 *
+		 * For nested:
+		 * The handling of the MSR bitmap for L2 guests is done in
+		 * nested_svm_vmrun_msrpm.
+		 * We update the L1 MSR bit as well since it will end up
+		 * touching the MSR anyway now.
+		 */
+		set_msr_interception(svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1);
+		break;
+	case MSR_IA32_PRED_CMD:
+		if (!msr->host_initiated &&
+		    !guest_cpuid_has_ibpb(vcpu))
+			return 1;
+
+		if (data & ~PRED_CMD_IBPB)
+			return 1;
+
+		if (!data)
+			break;
+
+		wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
+		if (is_guest_mode(vcpu))
+			break;
+		set_msr_interception(svm->msrpm, MSR_IA32_PRED_CMD, 0, 1);
+		break;
+	case MSR_AMD64_VIRT_SPEC_CTRL:
+		if (!msr->host_initiated &&
+		    !guest_cpuid_has_virt_ssbd(vcpu))
+			return 1;
+
+		if (data & ~SPEC_CTRL_SSBD)
+			return 1;
+
+		svm->virt_spec_ctrl = data;
+		break;
 	case MSR_STAR:
 		svm->vmcb->save.star = data;
 		break;
@@ -3169,6 +3356,24 @@
 	case MSR_VM_IGNNE:
 		vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
 		break;
+	case MSR_F10H_DECFG: {
+		struct kvm_msr_entry msr_entry;
+
+		msr_entry.index = msr->index;
+		if (svm_get_msr_feature(&msr_entry))
+			return 1;
+
+		/* Check the supported bits */
+		if (data & ~msr_entry.data)
+			return 1;
+
+		/* Don't allow the guest to change a bit, #GP */
+		if (!msr->host_initiated && (data ^ msr_entry.data))
+			return 1;
+
+		svm->msr_decfg = data;
+		break;
+	}
 	default:
 		return kvm_set_msr_common(vcpu, msr);
 	}
@@ -3561,12 +3766,16 @@
 	return;
 }
 
-static int svm_cpu_uses_apicv(struct kvm_vcpu *vcpu)
+static bool svm_get_enable_apicv(void)
+{
+	return false;
+}
+
+static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
 {
-	return 0;
 }
 
-static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu)
+static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
 {
 	return;
 }
@@ -3801,8 +4010,18 @@
 
 	clgi();
 
+	/*
+	 * If this vCPU has touched SPEC_CTRL, restore the guest's value if
+	 * it's non-zero. Since vmentry is serialising on affected CPUs, there
+	 * is no need to worry about the conditional branch over the wrmsr
+	 * being speculatively taken.
+	 */
+	x86_spec_ctrl_set_guest(svm->spec_ctrl, svm->virt_spec_ctrl);
+
 	local_irq_enable();
 
+	amd_clear_divider();
+
 	asm volatile (
 		"push %%" _ASM_BP "; \n\t"
 		"mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"
@@ -3847,6 +4066,25 @@
 		"mov %%r14, %c[r14](%[svm]) \n\t"
 		"mov %%r15, %c[r15](%[svm]) \n\t"
 #endif
+		/*
+		* Clear host registers marked as clobbered to prevent
+		* speculative use.
+		*/
+		"xor %%" _ASM_BX ", %%" _ASM_BX " \n\t"
+		"xor %%" _ASM_CX ", %%" _ASM_CX " \n\t"
+		"xor %%" _ASM_DX ", %%" _ASM_DX " \n\t"
+		"xor %%" _ASM_SI ", %%" _ASM_SI " \n\t"
+		"xor %%" _ASM_DI ", %%" _ASM_DI " \n\t"
+#ifdef CONFIG_X86_64
+		"xor %%r8, %%r8 \n\t"
+		"xor %%r9, %%r9 \n\t"
+		"xor %%r10, %%r10 \n\t"
+		"xor %%r11, %%r11 \n\t"
+		"xor %%r12, %%r12 \n\t"
+		"xor %%r13, %%r13 \n\t"
+		"xor %%r14, %%r14 \n\t"
+		"xor %%r15, %%r15 \n\t"
+#endif
 		"pop %%" _ASM_BP
 		:
 		: [svm]"a"(svm),
@@ -3876,6 +4114,9 @@
 #endif
 		);
 
+	/* Eliminate branch target predictions from guest mode */
+	vmexit_fill_RSB();
+
 #ifdef CONFIG_X86_64
 	wrmsrl(MSR_GS_BASE, svm->host.gs_base);
 #else
@@ -3885,10 +4126,30 @@
 #endif
 #endif
 
+	/*
+	 * We do not use IBRS in the kernel. If this vCPU has used the
+	 * SPEC_CTRL MSR it may have left it on; save the value and
+	 * turn it off. This is much more efficient than blindly adding
+	 * it to the atomic save/restore list. Especially as the former
+	 * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
+	 *
+	 * For non-nested case:
+	 * If the L01 MSR bitmap does not intercept the MSR, then we need to
+	 * save it.
+	 *
+	 * For nested case:
+	 * If the L02 MSR bitmap does not intercept the MSR, then we need to
+	 * save it.
+	 */
+	if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)))
+		svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
+
 	reload_tss(vcpu);
 
 	local_irq_disable();
 
+	x86_spec_ctrl_restore_host(svm->spec_ctrl, svm->virt_spec_ctrl);
+
 	vcpu->arch.cr2 = svm->vmcb->save.cr2;
 	vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
 	vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
@@ -3985,8 +4246,15 @@
 	return false;
 }
 
-static bool svm_has_high_real_mode_segbase(void)
+static bool svm_has_emulated_msr(int index)
 {
+	switch (index) {
+	case MSR_IA32_MCG_EXT_CTL:
+		return false;
+	default:
+		break;
+	}
+
 	return true;
 }
 
@@ -4269,7 +4537,7 @@
 	.hardware_enable = svm_hardware_enable,
 	.hardware_disable = svm_hardware_disable,
 	.cpu_has_accelerated_tpr = svm_cpu_has_accelerated_tpr,
-	.cpu_has_high_real_mode_segbase = svm_has_high_real_mode_segbase,
+	.has_emulated_msr = svm_has_emulated_msr,
 
 	.vcpu_create = svm_create_vcpu,
 	.vcpu_free = svm_free_vcpu,
@@ -4280,6 +4548,7 @@
 	.vcpu_put = svm_vcpu_put,
 
 	.update_bp_intercept = update_bp_intercept,
+	.get_msr_feature = svm_get_msr_feature,
 	.get_msr = svm_get_msr,
 	.set_msr = svm_set_msr,
 	.get_segment_base = svm_get_segment_base,
@@ -4328,7 +4597,8 @@
 	.enable_irq_window = enable_irq_window,
 	.update_cr8_intercept = update_cr8_intercept,
 	.set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
-	.cpu_uses_apicv = svm_cpu_uses_apicv,
+	.get_enable_apicv = svm_get_enable_apicv,
+	.refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl,
 	.load_eoi_exitmap = svm_load_eoi_exitmap,
 	.sync_pir_to_irr = svm_sync_pir_to_irr,
 
--- linux-4.4.0.orig/arch/x86/kvm/trace.h
+++ linux-4.4.0/arch/x86/kvm/trace.h
@@ -268,7 +268,7 @@
 #define kvm_trace_sym_exc						\
 	EXS(DE), EXS(DB), EXS(BP), EXS(OF), EXS(BR), EXS(UD), EXS(NM),	\
 	EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF),		\
-	EXS(MF), EXS(MC)
+	EXS(MF), EXS(AC), EXS(MC)
 
 /*
  * Tracepoint for kvm interrupt injection:
@@ -434,13 +434,13 @@
 );
 
 TRACE_EVENT(kvm_apic_accept_irq,
-	    TP_PROTO(__u32 apicid, __u16 dm, __u8 tm, __u8 vec),
+	    TP_PROTO(__u32 apicid, __u16 dm, __u16 tm, __u8 vec),
 	    TP_ARGS(apicid, dm, tm, vec),
 
 	TP_STRUCT__entry(
 		__field(	__u32,		apicid		)
 		__field(	__u16,		dm		)
-		__field(	__u8,		tm		)
+		__field(	__u16,		tm		)
 		__field(	__u8,		vec		)
 	),
 
@@ -809,8 +809,7 @@
 
 #define host_clocks					\
 	{VCLOCK_NONE, "none"},				\
-	{VCLOCK_TSC,  "tsc"},				\
-	{VCLOCK_HPET, "hpet"}				\
+	{VCLOCK_TSC,  "tsc"}				\
 
 TRACE_EVENT(kvm_update_master_clock,
 	TP_PROTO(bool use_master_clock, unsigned int host_clock, bool offset_matched),
--- linux-4.4.0.orig/arch/x86/kvm/vmx.c
+++ linux-4.4.0/arch/x86/kvm/vmx.c
@@ -19,6 +19,7 @@
 #include "irq.h"
 #include "mmu.h"
 #include "cpuid.h"
+#include "lapic.h"
 
 #include <linux/kvm_host.h>
 #include <linux/module.h>
@@ -26,16 +27,19 @@
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/sched.h>
+#include <linux/sched/smt.h>
 #include <linux/moduleparam.h>
 #include <linux/mod_devicetable.h>
 #include <linux/trace_events.h>
 #include <linux/slab.h>
 #include <linux/tboot.h>
 #include <linux/hrtimer.h>
+#include <linux/nospec.h>
 #include "kvm_cache_regs.h"
 #include "x86.h"
 
 #include <asm/cpu.h>
+#include <asm/cpu_device_id.h>
 #include <asm/io.h>
 #include <asm/desc.h>
 #include <asm/vmx.h>
@@ -47,6 +51,8 @@
 #include <asm/kexec.h>
 #include <asm/apic.h>
 #include <asm/irq_remapping.h>
+#include <asm/microcode.h>
+#include <asm/spec-ctrl.h>
 
 #include "trace.h"
 #include "pmu.h"
@@ -107,6 +113,14 @@
 static bool __read_mostly enable_pml = 1;
 module_param_named(pml, enable_pml, bool, S_IRUGO);
 
+#define MSR_TYPE_R	1
+#define MSR_TYPE_W	2
+#define MSR_TYPE_RW	3
+
+#define MSR_BITMAP_MODE_X2APIC		1
+#define MSR_BITMAP_MODE_X2APIC_APICV	2
+#define MSR_BITMAP_MODE_LM		4
+
 #define KVM_VMX_TSC_MULTIPLIER_MAX     0xffffffffffffffffULL
 
 #define KVM_GUEST_CR0_MASK (X86_CR0_NW | X86_CR0_CD)
@@ -124,6 +138,12 @@
 
 #define VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE 5
 
+#define VMX_VPID_EXTENT_SUPPORTED_MASK		\
+	(VMX_VPID_EXTENT_INDIVIDUAL_ADDR_BIT |	\
+	VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT |	\
+	VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT |	\
+	VMX_VPID_EXTENT_SINGLE_NON_GLOBAL_BIT)
+
 /*
  * These 2 parameters are used to config the controls for Pause-Loop Exiting:
  * ple_gap:    upper bound on the amount of time between two successive
@@ -163,8 +183,160 @@
 
 extern const ulong vmx_return;
 
+static DEFINE_STATIC_KEY_FALSE(vmx_l1d_should_flush);
+static DEFINE_STATIC_KEY_FALSE(vmx_l1d_flush_cond);
+static DEFINE_MUTEX(vmx_l1d_flush_mutex);
+
+/* Storage for pre module init parameter parsing */
+static enum vmx_l1d_flush_state __read_mostly vmentry_l1d_flush_param = VMENTER_L1D_FLUSH_AUTO;
+
+static const struct {
+	const char *option;
+	bool for_parse;
+} vmentry_l1d_param[] = {
+	[VMENTER_L1D_FLUSH_AUTO]	 = {"auto", true},
+	[VMENTER_L1D_FLUSH_NEVER]	 = {"never", true},
+	[VMENTER_L1D_FLUSH_COND]	 = {"cond", true},
+	[VMENTER_L1D_FLUSH_ALWAYS]	 = {"always", true},
+	[VMENTER_L1D_FLUSH_EPT_DISABLED] = {"EPT disabled", false},
+	[VMENTER_L1D_FLUSH_NOT_REQUIRED] = {"not required", false},
+};
+
+#define L1D_CACHE_ORDER 4
+static void *vmx_l1d_flush_pages;
+
+/* Control for disabling CPU Fill buffer clear */
+static bool __read_mostly vmx_fb_clear_ctrl_available;
+
+static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf)
+{
+	struct page *page;
+	unsigned int i;
+
+	if (!enable_ept) {
+		l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_EPT_DISABLED;
+		return 0;
+	}
+
+       if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) {
+	       u64 msr;
+
+	       rdmsrl(MSR_IA32_ARCH_CAPABILITIES, msr);
+	       if (msr & ARCH_CAP_SKIP_VMENTRY_L1DFLUSH) {
+		       l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_NOT_REQUIRED;
+		       return 0;
+	       }
+       }
+
+	/* If set to auto use the default l1tf mitigation method */
+	if (l1tf == VMENTER_L1D_FLUSH_AUTO) {
+		switch (l1tf_mitigation) {
+		case L1TF_MITIGATION_OFF:
+			l1tf = VMENTER_L1D_FLUSH_NEVER;
+			break;
+		case L1TF_MITIGATION_FLUSH_NOWARN:
+		case L1TF_MITIGATION_FLUSH:
+		case L1TF_MITIGATION_FLUSH_NOSMT:
+			l1tf = VMENTER_L1D_FLUSH_COND;
+			break;
+		case L1TF_MITIGATION_FULL:
+		case L1TF_MITIGATION_FULL_FORCE:
+			l1tf = VMENTER_L1D_FLUSH_ALWAYS;
+			break;
+		}
+	} else if (l1tf_mitigation == L1TF_MITIGATION_FULL_FORCE) {
+		l1tf = VMENTER_L1D_FLUSH_ALWAYS;
+	}
+
+	if (l1tf != VMENTER_L1D_FLUSH_NEVER && !vmx_l1d_flush_pages &&
+	    !boot_cpu_has(X86_FEATURE_FLUSH_L1D)) {
+		page = alloc_pages(GFP_KERNEL, L1D_CACHE_ORDER);
+		if (!page)
+			return -ENOMEM;
+		vmx_l1d_flush_pages = page_address(page);
+
+		/*
+		 * Initialize each page with a different pattern in
+		 * order to protect against KSM in the nested
+		 * virtualization case.
+		 */
+		for (i = 0; i < 1u << L1D_CACHE_ORDER; ++i) {
+			memset(vmx_l1d_flush_pages + i * PAGE_SIZE, i + 1,
+			       PAGE_SIZE);
+		}
+	}
+
+	l1tf_vmx_mitigation = l1tf;
+
+	if (l1tf != VMENTER_L1D_FLUSH_NEVER)
+		static_branch_enable(&vmx_l1d_should_flush);
+	else
+		static_branch_disable(&vmx_l1d_should_flush);
+
+	if (l1tf == VMENTER_L1D_FLUSH_COND)
+		static_branch_enable(&vmx_l1d_flush_cond);
+	else
+		static_branch_disable(&vmx_l1d_flush_cond);
+	return 0;
+}
+
+static int vmentry_l1d_flush_parse(const char *s)
+{
+	unsigned int i;
+
+	if (s) {
+		for (i = 0; i < ARRAY_SIZE(vmentry_l1d_param); i++) {
+			if (vmentry_l1d_param[i].for_parse &&
+			    sysfs_streq(s, vmentry_l1d_param[i].option))
+				return i;
+		}
+	}
+	return -EINVAL;
+}
+
+static int vmentry_l1d_flush_set(const char *s, const struct kernel_param *kp)
+{
+	int l1tf, ret;
+
+	l1tf = vmentry_l1d_flush_parse(s);
+	if (l1tf < 0)
+		return l1tf;
+
+	if (!boot_cpu_has(X86_BUG_L1TF))
+		return 0;
+
+	/*
+	 * Has vmx_init() run already? If not then this is the pre init
+	 * parameter parsing. In that case just store the value and let
+	 * vmx_init() do the proper setup after enable_ept has been
+	 * established.
+	 */
+	if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_AUTO) {
+		vmentry_l1d_flush_param = l1tf;
+		return 0;
+	}
+
+	mutex_lock(&vmx_l1d_flush_mutex);
+	ret = vmx_setup_l1d_flush(l1tf);
+	mutex_unlock(&vmx_l1d_flush_mutex);
+	return ret;
+}
+
+static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp)
+{
+	if (WARN_ON_ONCE(l1tf_vmx_mitigation >= ARRAY_SIZE(vmentry_l1d_param)))
+		return sprintf(s, "???\n");
+
+	return sprintf(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option);
+}
+
+static const struct kernel_param_ops vmentry_l1d_flush_ops = {
+	.set = vmentry_l1d_flush_set,
+	.get = vmentry_l1d_flush_get,
+};
+module_param_cb(vmentry_l1d_flush, &vmentry_l1d_flush_ops, NULL, 0644);
+
 #define NR_AUTOLOAD_MSRS 8
-#define VMCS02_POOL_SIZE 1
 
 struct vmcs {
 	u32 revision_id;
@@ -179,8 +351,10 @@
  */
 struct loaded_vmcs {
 	struct vmcs *vmcs;
+	struct vmcs *shadow_vmcs;
 	int cpu;
 	int launched;
+	unsigned long *msr_bitmap;
 	struct list_head loaded_vmcss_on_cpu_link;
 };
 
@@ -197,7 +371,7 @@
  * stored in guest memory specified by VMPTRLD, but is opaque to the guest,
  * which must access it using VMREAD/VMWRITE/VMCLEAR instructions.
  * More than one of these structures may exist, if L1 runs multiple L2 guests.
- * nested_vmx_run() will use the data here to build a vmcs02: a VMCS for the
+ * nested_vmx_run() will use the data here to build the vmcs02: a VMCS for the
  * underlying hardware which will be used to run L2.
  * This structure is packed to ensure that its layout is identical across
  * machines (necessary for live migration).
@@ -376,13 +550,6 @@
  */
 #define VMCS12_SIZE 0x1000
 
-/* Used to remember the last vmcs02 used for some recently used vmcs12s */
-struct vmcs02_list {
-	struct list_head list;
-	gpa_t vmptr;
-	struct loaded_vmcs vmcs02;
-};
-
 /*
  * The nested_vmx structure is part of vcpu_vmx, and holds information we need
  * for correct emulation of VMX (i.e., nested VMX) on this vcpu.
@@ -397,22 +564,22 @@
 	/* The host-usable pointer to the above */
 	struct page *current_vmcs12_page;
 	struct vmcs12 *current_vmcs12;
-	struct vmcs *current_shadow_vmcs;
 	/*
 	 * Indicates if the shadow vmcs must be updated with the
 	 * data hold by vmcs12
 	 */
 	bool sync_shadow_vmcs;
 
-	/* vmcs02_list cache of VMCSs recently used to run L2 guests */
-	struct list_head vmcs02_pool;
-	int vmcs02_num;
 	u64 vmcs01_tsc_offset;
+	bool change_vmcs01_virtual_x2apic_mode;
 	/* L2 must run next, and mustn't decide to exit to L1. */
 	bool nested_run_pending;
+
+	struct loaded_vmcs vmcs02;
+
 	/*
-	 * Guest pages referred to in vmcs02 with host-physical pointers, so
-	 * we must keep them pinned while L2 runs.
+	 * Guest pages referred to in the vmcs02 with host-physical
+	 * pointers, so we must keep them pinned while L2 runs.
 	 */
 	struct page *apic_access_page;
 	struct page *virtual_apic_page;
@@ -517,11 +684,17 @@
 			(unsigned long *)&pi_desc->control);
 }
 
+struct vmx_msrs {
+	unsigned int		nr;
+	struct vmx_msr_entry	val[NR_AUTOLOAD_MSRS];
+};
+
 struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
 	unsigned long         host_rsp;
 	u8                    fail;
 	bool                  nmi_known_unmasked;
+	u8		      msr_bitmap_mode;
 	u32                   exit_intr_info;
 	u32                   idt_vectoring_info;
 	ulong                 rflags;
@@ -533,6 +706,9 @@
 	u64 		      msr_host_kernel_gs_base;
 	u64 		      msr_guest_kernel_gs_base;
 #endif
+
+	u64 		      spec_ctrl;
+
 	u32 vm_entry_controls_shadow;
 	u32 vm_exit_controls_shadow;
 	/*
@@ -544,9 +720,8 @@
 	struct loaded_vmcs   *loaded_vmcs;
 	bool                  __launched; /* temporary, used in vmx_vcpu_run */
 	struct msr_autoload {
-		unsigned nr;
-		struct vmx_msr_entry guest[NR_AUTOLOAD_MSRS];
-		struct vmx_msr_entry host[NR_AUTOLOAD_MSRS];
+		struct vmx_msrs guest;
+		struct vmx_msrs host;
 	} msr_autoload;
 	struct {
 		int           loaded;
@@ -595,6 +770,11 @@
 	/* Support for PML */
 #define PML_ENTITY_NUM		512
 	struct page *pml_pg;
+
+	u64 current_tsc_ratio;
+
+	u64 msr_ia32_mcu_opt_ctrl;
+	bool disable_fb_clear;
 };
 
 enum segment_cache_field {
@@ -823,13 +1003,18 @@
 
 static inline short vmcs_field_to_offset(unsigned long field)
 {
-	BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX);
+	const size_t size = ARRAY_SIZE(vmcs_field_to_offset_table);
+	unsigned short offset;
 
-	if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) ||
-	    vmcs_field_to_offset_table[field] == 0)
+	BUILD_BUG_ON(size > SHRT_MAX);
+	if (field >= size)
 		return -ENOENT;
 
-	return vmcs_field_to_offset_table[field];
+	field = array_index_nospec(field, size);
+	offset = vmcs_field_to_offset_table[field];
+	if (offset == 0)
+		return -ENOENT;
+	return offset;
 }
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
@@ -860,9 +1045,7 @@
 static u64 construct_eptp(unsigned long root_hpa);
 static void kvm_cpu_vmxon(u64 addr);
 static void kvm_cpu_vmxoff(void);
-static bool vmx_mpx_supported(void);
 static bool vmx_xsaves_supported(void);
-static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu);
 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);
@@ -870,10 +1053,12 @@
 			    struct kvm_segment *var, int seg);
 static bool guest_state_valid(struct kvm_vcpu *vcpu);
 static u32 vmx_segment_access_rights(struct kvm_segment *var);
-static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu);
 static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx);
 static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx);
 static int alloc_identity_pagetable(struct kvm *kvm);
+static void vmx_update_msr_bitmap(struct kvm_vcpu *vcpu);
+static void __always_inline vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
+							  u32 msr, int type);
 
 static DEFINE_PER_CPU(struct vmcs *, vmxarea);
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -893,11 +1078,6 @@
 
 static unsigned long *vmx_io_bitmap_a;
 static unsigned long *vmx_io_bitmap_b;
-static unsigned long *vmx_msr_bitmap_legacy;
-static unsigned long *vmx_msr_bitmap_longmode;
-static unsigned long *vmx_msr_bitmap_legacy_x2apic;
-static unsigned long *vmx_msr_bitmap_longmode_x2apic;
-static unsigned long *vmx_msr_bitmap_nested;
 static unsigned long *vmx_vmread_bitmap;
 static unsigned long *vmx_vmwrite_bitmap;
 
@@ -996,6 +1176,13 @@
 		(INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK);
 }
 
+/* Undocumented: icebp/int1 */
+static inline bool is_icebp(u32 intr_info)
+{
+	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
+		== (INTR_TYPE_PRIV_SW_EXCEPTION | INTR_INFO_VALID_MASK);
+}
+
 static inline bool cpu_has_vmx_msr_bitmap(void)
 {
 	return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS;
@@ -1105,6 +1292,11 @@
 	return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
 }
 
+static inline bool cpu_has_vmx_invvpid(void)
+{
+	return vmx_capability.vpid & VMX_VPID_INVVPID_BIT;
+}
+
 static inline bool cpu_has_vmx_ept(void)
 {
 	return vmcs_config.cpu_based_2nd_exec_ctrl &
@@ -1244,10 +1436,10 @@
 	return vmcs12->pin_based_vm_exec_control & PIN_BASED_POSTED_INTR;
 }
 
-static inline bool is_exception(u32 intr_info)
+static inline bool is_nmi(u32 intr_info)
 {
 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
-		== (INTR_TYPE_HARD_EXCEPTION | INTR_INFO_VALID_MASK);
+		== (INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK);
 }
 
 static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
@@ -1267,7 +1459,7 @@
 	return -1;
 }
 
-static inline void __invvpid(int ext, u16 vpid, gva_t gva)
+static inline void __invvpid(unsigned long ext, u16 vpid, gva_t gva)
 {
     struct {
 	u64 vpid : 16;
@@ -1281,7 +1473,7 @@
 		  : : "a"(&operand), "c"(ext) : "cc", "memory");
 }
 
-static inline void __invept(int ext, u64 eptp, gpa_t gpa)
+static inline void __invept(unsigned long ext, u64 eptp, gpa_t gpa)
 {
 	struct {
 		u64 eptp, gpa;
@@ -1293,6 +1485,60 @@
 			: : "a" (&operand), "c" (ext) : "cc", "memory");
 }
 
+static void vmx_setup_fb_clear_ctrl(void)
+{
+	u64 msr;
+
+	if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES) &&
+	    !boot_cpu_has_bug(X86_BUG_MDS) &&
+	    !boot_cpu_has_bug(X86_BUG_TAA)) {
+		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, msr);
+		if (msr & ARCH_CAP_FB_CLEAR_CTRL)
+			vmx_fb_clear_ctrl_available = true;
+	}
+}
+
+static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx)
+{
+	u64 msr;
+
+	if (!vmx->disable_fb_clear)
+		return;
+
+	rdmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+	msr |= FB_CLEAR_DIS;
+	wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+	/* Cache the MSR value to avoid reading it later */
+	vmx->msr_ia32_mcu_opt_ctrl = msr;
+}
+
+static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx)
+{
+	if (!vmx->disable_fb_clear)
+		return;
+
+	vmx->msr_ia32_mcu_opt_ctrl &= ~FB_CLEAR_DIS;
+	wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
+}
+
+static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx)
+{
+	vmx->disable_fb_clear = vmx_fb_clear_ctrl_available;
+
+	/*
+	 * If guest will not execute VERW, there is no need to set FB_CLEAR_DIS
+	 * at VMEntry. Skip the MSR read/write when a guest has no use case to
+	 * execute VERW.
+	 */
+	if ((vcpu->arch.arch_capabilities & ARCH_CAP_FB_CLEAR) ||
+	   ((vcpu->arch.arch_capabilities & ARCH_CAP_MDS_NO) &&
+	    (vcpu->arch.arch_capabilities & ARCH_CAP_TAA_NO) &&
+	    (vcpu->arch.arch_capabilities & ARCH_CAP_PSDP_NO) &&
+	    (vcpu->arch.arch_capabilities & ARCH_CAP_FBSDP_NO) &&
+	    (vcpu->arch.arch_capabilities & ARCH_CAP_SBDR_SSDP_NO)))
+		vmx->disable_fb_clear = false;
+}
+
 static struct shared_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
 {
 	int i;
@@ -1319,6 +1565,8 @@
 static inline void loaded_vmcs_init(struct loaded_vmcs *loaded_vmcs)
 {
 	vmcs_clear(loaded_vmcs->vmcs);
+	if (loaded_vmcs->shadow_vmcs && loaded_vmcs->launched)
+		vmcs_clear(loaded_vmcs->shadow_vmcs);
 	loaded_vmcs->cpu = -1;
 	loaded_vmcs->launched = 0;
 }
@@ -1334,6 +1582,7 @@
 	if (error)
 		printk(KERN_ERR "kvm: vmptrld %p/%llx failed\n",
 		       vmcs, phys_addr);
+
 }
 
 #ifdef CONFIG_KEXEC_CORE
@@ -1662,6 +1911,52 @@
 	vmcs_write32(EXCEPTION_BITMAP, eb);
 }
 
+/*
+ * Check if MSR is intercepted for currently loaded MSR bitmap.
+ */
+static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr)
+{
+	unsigned long *msr_bitmap;
+	int f = sizeof(unsigned long);
+
+	if (!cpu_has_vmx_msr_bitmap())
+		return true;
+
+	msr_bitmap = to_vmx(vcpu)->loaded_vmcs->msr_bitmap;
+
+	if (msr <= 0x1fff) {
+		return !!test_bit(msr, msr_bitmap + 0x800 / f);
+	} else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+		msr &= 0x1fff;
+		return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+	}
+
+	return true;
+}
+
+/*
+ * Check if MSR is intercepted for L01 MSR bitmap.
+ */
+static bool msr_write_intercepted_l01(struct kvm_vcpu *vcpu, u32 msr)
+{
+	unsigned long *msr_bitmap;
+	int f = sizeof(unsigned long);
+
+	if (!cpu_has_vmx_msr_bitmap())
+		return true;
+
+	msr_bitmap = to_vmx(vcpu)->vmcs01.msr_bitmap;
+
+	if (msr <= 0x1fff) {
+		return !!test_bit(msr, msr_bitmap + 0x800 / f);
+	} else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+		msr &= 0x1fff;
+		return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+	}
+
+	return true;
+}
+
 static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
 		unsigned long entry, unsigned long exit)
 {
@@ -1669,9 +1964,20 @@
 	vm_exit_controls_clearbit(vmx, exit);
 }
 
+static int find_msr(struct vmx_msrs *m, int msr)
+{
+	unsigned int i;
+
+	for (i = 0; i < m->nr; ++i) {
+		if (m->val[i].index == msr)
+			return i;
+	}
+	return -ENOENT;
+}
+
 static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
 {
-	unsigned i;
+	int i;
 	struct msr_autoload *m = &vmx->msr_autoload;
 
 	switch (msr) {
@@ -1692,18 +1998,20 @@
 		}
 		break;
 	}
-
-	for (i = 0; i < m->nr; ++i)
-		if (m->guest[i].index == msr)
-			break;
-
-	if (i == m->nr)
-		return;
-	--m->nr;
-	m->guest[i] = m->guest[m->nr];
-	m->host[i] = m->host[m->nr];
-	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr);
-	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
+	i = find_msr(&m->guest, msr);
+	if (i < 0)
+		goto skip_guest;
+	--m->guest.nr;
+	m->guest.val[i] = m->guest.val[m->guest.nr];
+	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
+
+skip_guest:
+	i = find_msr(&m->host, msr);
+	if (i < 0)
+		return;
+	--m->host.nr;
+	m->host.val[i] = m->host.val[m->host.nr];
+	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
 }
 
 static void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
@@ -1718,9 +2026,9 @@
 }
 
 static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
-				  u64 guest_val, u64 host_val)
+				  u64 guest_val, u64 host_val, bool entry_only)
 {
-	unsigned i;
+	int i, j = 0;
 	struct msr_autoload *m = &vmx->msr_autoload;
 
 	switch (msr) {
@@ -1746,26 +2054,40 @@
 			return;
 		}
 		break;
+	case MSR_IA32_PEBS_ENABLE:
+		/* PEBS needs a quiescent period after being disabled (to write
+		 * a record).  Disabling PEBS through VMX MSR swapping doesn't
+		 * provide that period, so a CPU could write host's record into
+		 * guest's memory.
+		 */
+		wrmsrl(MSR_IA32_PEBS_ENABLE, 0);
 	}
 
-	for (i = 0; i < m->nr; ++i)
-		if (m->guest[i].index == msr)
-			break;
+	i = find_msr(&m->guest, msr);
+	if (!entry_only)
+		j = find_msr(&m->host, msr);
 
-	if (i == NR_AUTOLOAD_MSRS) {
+	if (i == NR_AUTOLOAD_MSRS || j == NR_AUTOLOAD_MSRS) {
 		printk_once(KERN_WARNING "Not enough msr switch entries. "
 				"Can't add msr %x\n", msr);
 		return;
-	} else if (i == m->nr) {
-		++m->nr;
-		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr);
-		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
 	}
+	if (i < 0) {
+		i = m->guest.nr++;
+		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
+	}
+	m->guest.val[i].index = msr;
+	m->guest.val[i].value = guest_val;
 
-	m->guest[i].index = msr;
-	m->guest[i].value = guest_val;
-	m->host[i].index = msr;
-	m->host[i].value = host_val;
+	if (entry_only)
+		return;
+
+	if (j < 0) {
+		j = m->host.nr++;
+		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
+	}
+	m->host.val[j].index = msr;
+	m->host.val[j].value = host_val;
 }
 
 static void reload_tss(void)
@@ -1783,26 +2105,23 @@
 
 static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)
 {
-	u64 guest_efer;
-	u64 ignore_bits;
+	u64 guest_efer = vmx->vcpu.arch.efer;
+	u64 ignore_bits = 0;
 
-	guest_efer = vmx->vcpu.arch.efer;
+	/* Shadow paging assumes NX to be available.  */
+	if (!enable_ept)
+		guest_efer |= EFER_NX;
 
 	/*
-	 * NX is emulated; LMA and LME handled by hardware; SCE meaningless
-	 * outside long mode
+	 * LMA and LME handled by hardware; SCE meaningless outside long mode.
 	 */
-	ignore_bits = EFER_NX | EFER_SCE;
+	ignore_bits |= EFER_SCE;
 #ifdef CONFIG_X86_64
 	ignore_bits |= EFER_LMA | EFER_LME;
 	/* SCE is meaningful only in long mode on Intel */
 	if (guest_efer & EFER_LMA)
 		ignore_bits &= ~(u64)EFER_SCE;
 #endif
-	guest_efer &= ~ignore_bits;
-	guest_efer |= host_efer & ignore_bits;
-	vmx->guest_msrs[efer_offset].data = guest_efer;
-	vmx->guest_msrs[efer_offset].mask = ~ignore_bits;
 
 	clear_atomic_switch_msr(vmx, MSR_EFER);
 
@@ -1813,16 +2132,21 @@
 	 */
 	if (cpu_has_load_ia32_efer ||
 	    (enable_ept && ((vmx->vcpu.arch.efer ^ host_efer) & EFER_NX))) {
-		guest_efer = vmx->vcpu.arch.efer;
 		if (!(guest_efer & EFER_LMA))
 			guest_efer &= ~EFER_LME;
 		if (guest_efer != host_efer)
 			add_atomic_switch_msr(vmx, MSR_EFER,
-					      guest_efer, host_efer);
+					      guest_efer, host_efer, false);
 		return false;
-	}
+	} else {
+		guest_efer &= ~ignore_bits;
+		guest_efer |= host_efer & ignore_bits;
 
-	return true;
+		vmx->guest_msrs[efer_offset].data = guest_efer;
+		vmx->guest_msrs[efer_offset].mask = ~ignore_bits;
+
+		return true;
+	}
 }
 
 static unsigned long segment_base(u16 selector)
@@ -2010,8 +2334,8 @@
 
 		/* Allow posting non-urgent interrupts */
 		new.sn = 0;
-	} while (cmpxchg(&pi_desc->control, old.control,
-			new.control) != old.control);
+	} while (cmpxchg64(&pi_desc->control, old.control,
+			   new.control) != old.control);
 }
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
@@ -2030,6 +2354,7 @@
 	if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
 		per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
 		vmcs_load(vmx->loaded_vmcs->vmcs);
+		indirect_branch_prediction_barrier();
 	}
 
 	if (vmx->loaded_vmcs->cpu != cpu) {
@@ -2062,14 +2387,16 @@
 		rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
 		vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
 
-		/* Setup TSC multiplier */
-		if (cpu_has_vmx_tsc_scaling())
-			vmcs_write64(TSC_MULTIPLIER,
-				     vcpu->arch.tsc_scaling_ratio);
-
 		vmx->loaded_vmcs->cpu = cpu;
 	}
 
+	/* Setup TSC multiplier */
+	if (kvm_has_tsc_control &&
+	    vmx->current_tsc_ratio != vcpu->arch.tsc_scaling_ratio) {
+		vmx->current_tsc_ratio = vcpu->arch.tsc_scaling_ratio;
+		vmcs_write64(TSC_MULTIPLIER, vmx->current_tsc_ratio);
+	}
+
 	vmx_vcpu_pi_load(vcpu, cpu);
 }
 
@@ -2242,7 +2569,7 @@
 	if (!(vmcs12->exception_bitmap & (1u << nr)))
 		return 0;
 
-	nested_vmx_vmexit(vcpu, to_vmx(vcpu)->exit_reason,
+	nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
 			  vmcs_read32(VM_EXIT_INTR_INFO),
 			  vmcs_readl(EXIT_QUALIFICATION));
 	return 1;
@@ -2273,6 +2600,8 @@
 		return;
 	}
 
+	WARN_ON_ONCE(vmx->emulation_required);
+
 	if (kvm_exception_is_soft(nr)) {
 		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
 			     vmx->vcpu.arch.event_exit_inst_len);
@@ -2305,27 +2634,6 @@
 	vmx->guest_msrs[from] = tmp;
 }
 
-static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
-{
-	unsigned long *msr_bitmap;
-
-	if (is_guest_mode(vcpu))
-		msr_bitmap = vmx_msr_bitmap_nested;
-	else if (vcpu->arch.apic_base & X2APIC_ENABLE) {
-		if (is_long_mode(vcpu))
-			msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
-		else
-			msr_bitmap = vmx_msr_bitmap_legacy_x2apic;
-	} else {
-		if (is_long_mode(vcpu))
-			msr_bitmap = vmx_msr_bitmap_longmode;
-		else
-			msr_bitmap = vmx_msr_bitmap_legacy;
-	}
-
-	vmcs_write64(MSR_BITMAP, __pa(msr_bitmap));
-}
-
 /*
  * Set up the vmcs to automatically save and restore system
  * msrs.  Don't touch the 64-bit msrs if the guest is in legacy
@@ -2366,7 +2674,7 @@
 	vmx->save_nmsrs = save_nmsrs;
 
 	if (cpu_has_vmx_msr_bitmap())
-		vmx_set_msr_bitmap(&vmx->vcpu);
+		vmx_update_msr_bitmap(&vmx->vcpu);
 }
 
 /*
@@ -2498,7 +2806,7 @@
 	vmx->nested.nested_vmx_pinbased_ctls_high |=
 		PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
 		PIN_BASED_VMX_PREEMPTION_TIMER;
-	if (vmx_cpu_uses_apicv(&vmx->vcpu))
+	if (kvm_vcpu_apicv_active(&vmx->vcpu))
 		vmx->nested.nested_vmx_pinbased_ctls_high |=
 			PIN_BASED_POSTED_INTR;
 
@@ -2519,7 +2827,7 @@
 		VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER |
 		VM_EXIT_SAVE_VMX_PREEMPTION_TIMER | VM_EXIT_ACK_INTR_ON_EXIT;
 
-	if (vmx_mpx_supported())
+	if (kvm_mpx_supported())
 		vmx->nested.nested_vmx_exit_ctls_high |= VM_EXIT_CLEAR_BNDCFGS;
 
 	/* We support free control of debug control saving. */
@@ -2540,7 +2848,7 @@
 		VM_ENTRY_LOAD_IA32_PAT;
 	vmx->nested.nested_vmx_entry_ctls_high |=
 		(VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | VM_ENTRY_LOAD_IA32_EFER);
-	if (vmx_mpx_supported())
+	if (kvm_mpx_supported())
 		vmx->nested.nested_vmx_entry_ctls_high |= VM_ENTRY_LOAD_BNDCFGS;
 
 	/* We support free control of debug control loading. */
@@ -2616,9 +2924,15 @@
 	} else
 		vmx->nested.nested_vmx_ept_caps = 0;
 
+	/*
+	 * Old versions of KVM use the single-context version without
+	 * checking for support, so declare that it is supported even
+	 * though it is treated as global context.  The alternative is
+	 * not failing the single-context invvpid, and it is worse.
+	 */
 	if (enable_vpid)
 		vmx->nested.nested_vmx_vpid_caps = VMX_VPID_INVVPID_BIT |
-				VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
+			VMX_VPID_EXTENT_SUPPORTED_MASK;
 	else
 		vmx->nested.nested_vmx_vpid_caps = 0;
 
@@ -2747,6 +3061,11 @@
 	return 0;
 }
 
+static int vmx_get_msr_feature(struct kvm_msr_entry *msr)
+{
+	return 1;
+}
+
 /*
  * Reads an msr value (of 'msr_index') into 'pdata'.
  * Returns 0 on success, non-0 otherwise.
@@ -2774,6 +3093,13 @@
 	case MSR_IA32_TSC:
 		msr_info->data = guest_read_tsc(vcpu);
 		break;
+	case MSR_IA32_SPEC_CTRL:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_spec_ctrl(vcpu))
+			return 1;
+
+		msr_info->data = to_vmx(vcpu)->spec_ctrl;
+		break;
 	case MSR_IA32_SYSENTER_CS:
 		msr_info->data = vmcs_read32(GUEST_SYSENTER_CS);
 		break;
@@ -2784,7 +3110,8 @@
 		msr_info->data = vmcs_readl(GUEST_SYSENTER_ESP);
 		break;
 	case MSR_IA32_BNDCFGS:
-		if (!vmx_mpx_supported())
+		if (!kvm_mpx_supported() ||
+		    (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu)))
 			return 1;
 		msr_info->data = vmcs_read64(GUEST_BNDCFGS);
 		break;
@@ -2861,13 +3188,74 @@
 		vmcs_writel(GUEST_SYSENTER_ESP, data);
 		break;
 	case MSR_IA32_BNDCFGS:
-		if (!vmx_mpx_supported())
+		if (!kvm_mpx_supported() ||
+		    (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu)))
+			return 1;
+		if (is_noncanonical_address(data & PAGE_MASK) ||
+		    (data & MSR_IA32_BNDCFGS_RSVD))
 			return 1;
 		vmcs_write64(GUEST_BNDCFGS, data);
 		break;
 	case MSR_IA32_TSC:
 		kvm_write_tsc(vcpu, msr_info);
 		break;
+	case MSR_IA32_SPEC_CTRL:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_spec_ctrl(vcpu))
+			return 1;
+
+		/* The STIBP bit doesn't fault even if it's not advertised */
+		if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_SSBD))
+			return 1;
+
+		vmx->spec_ctrl = data;
+
+		if (!data)
+			break;
+
+		/*
+		 * For non-nested:
+		 * When it's written (to non-zero) for the first time, pass
+		 * it through.
+		 *
+		 * For nested:
+		 * The handling of the MSR bitmap for L2 guests is done in
+		 * nested_vmx_merge_msr_bitmap. We should not touch the
+		 * vmcs02.msr_bitmap here since it gets completely overwritten
+		 * in the merging. We update the vmcs01 here for L1 as well
+		 * since it will end up touching the MSR anyway now.
+		 */
+		vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap,
+					      MSR_IA32_SPEC_CTRL,
+					      MSR_TYPE_RW);
+		break;
+	case MSR_IA32_PRED_CMD:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_ibpb(vcpu))
+			return 1;
+
+		if (data & ~PRED_CMD_IBPB)
+			return 1;
+
+		if (!data)
+			break;
+
+		wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
+
+		/*
+		 * For non-nested:
+		 * When it's written (to non-zero) for the first time, pass
+		 * it through.
+		 *
+		 * For nested:
+		 * The handling of the MSR bitmap for L2 guests is done in
+		 * nested_vmx_merge_msr_bitmap. We should not touch the
+		 * vmcs02.msr_bitmap here since it gets completely overwritten
+		 * in the merging.
+		 */
+		vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap, MSR_IA32_PRED_CMD,
+					      MSR_TYPE_W);
+		break;
 	case MSR_IA32_CR_PAT:
 		if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
 			if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
@@ -2904,7 +3292,7 @@
 		vcpu->arch.ia32_xss = data;
 		if (vcpu->arch.ia32_xss != host_xss)
 			add_atomic_switch_msr(vmx, MSR_IA32_XSS,
-				vcpu->arch.ia32_xss, host_xss);
+				vcpu->arch.ia32_xss, host_xss, false);
 		else
 			clear_atomic_switch_msr(vmx, MSR_IA32_XSS);
 		break;
@@ -2930,9 +3318,13 @@
 			}
 			break;
 		}
-		ret = kvm_set_msr_common(vcpu, msr_info);
+			ret = kvm_set_msr_common(vcpu, msr_info);
 	}
 
+	/* FB_CLEAR may have changed, also update the FB_CLEAR_DIS behavior */
+	if (msr_index == MSR_IA32_ARCH_CAPABILITIES)
+		vmx_update_fb_clear_dis(vcpu, vmx);
+
 	return ret;
 }
 
@@ -3293,11 +3685,6 @@
 	return vmcs;
 }
 
-static struct vmcs *alloc_vmcs(void)
-{
-	return alloc_vmcs_cpu(raw_smp_processor_id());
-}
-
 static void free_vmcs(struct vmcs *vmcs)
 {
 	free_pages((unsigned long)vmcs, vmcs_config.order);
@@ -3313,6 +3700,36 @@
 	loaded_vmcs_clear(loaded_vmcs);
 	free_vmcs(loaded_vmcs->vmcs);
 	loaded_vmcs->vmcs = NULL;
+	if (loaded_vmcs->msr_bitmap)
+		free_page((unsigned long)loaded_vmcs->msr_bitmap);
+	WARN_ON(loaded_vmcs->shadow_vmcs != NULL);
+}
+
+static struct vmcs *alloc_vmcs(void)
+{
+	return alloc_vmcs_cpu(raw_smp_processor_id());
+}
+
+static int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
+{
+	loaded_vmcs->vmcs = alloc_vmcs();
+	if (!loaded_vmcs->vmcs)
+		return -ENOMEM;
+
+	loaded_vmcs->shadow_vmcs = NULL;
+	loaded_vmcs_init(loaded_vmcs);
+
+	if (cpu_has_vmx_msr_bitmap()) {
+		loaded_vmcs->msr_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
+		if (!loaded_vmcs->msr_bitmap)
+			goto out_vmcs;
+		memset(loaded_vmcs->msr_bitmap, 0xff, PAGE_SIZE);
+	}
+	return 0;
+
+out_vmcs:
+	free_loaded_vmcs(loaded_vmcs);
+	return -ENOMEM;
 }
 
 static void free_kvm_area(void)
@@ -3334,7 +3751,7 @@
 	for (i = j = 0; i < max_shadow_read_write_fields; i++) {
 		switch (shadow_read_write_fields[i]) {
 		case GUEST_BNDCFGS:
-			if (!vmx_mpx_supported())
+			if (!kvm_mpx_supported())
 				continue;
 			break;
 		default:
@@ -3470,7 +3887,7 @@
 	}
 
 	vmcs_write16(sf->selector, var.selector);
-	vmcs_write32(sf->base, var.base);
+	vmcs_writel(sf->base, var.base);
 	vmcs_write32(sf->limit, var.limit);
 	vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(&var));
 }
@@ -4099,19 +4516,39 @@
 		 (ss.selector & SEGMENT_RPL_MASK));
 }
 
-/*
- * Check if guest state is valid. Returns true if valid, false if
- * not.
- * We assume that registers are always usable
- */
-static bool guest_state_valid(struct kvm_vcpu *vcpu)
+static bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu,
+					unsigned int port, int size);
+static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
+				       struct vmcs12 *vmcs12)
 {
-	if (enable_unrestricted_guest)
-		return true;
+	unsigned long exit_qualification;
+	unsigned short port;
+	int size;
 
-	/* real mode guest state checks */
-	if (!is_protmode(vcpu) || (vmx_get_rflags(vcpu) & X86_EFLAGS_VM)) {
-		if (!rmode_segment_valid(vcpu, VCPU_SREG_CS))
+	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
+		return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING);
+
+	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
+
+	port = exit_qualification >> 16;
+	size = (exit_qualification & 7) + 1;
+
+	return nested_vmx_check_io_bitmaps(vcpu, port, size);
+}
+
+/*
+ * Check if guest state is valid. Returns true if valid, false if
+ * not.
+ * We assume that registers are always usable
+ */
+static bool guest_state_valid(struct kvm_vcpu *vcpu)
+{
+	if (enable_unrestricted_guest)
+		return true;
+
+	/* real mode guest state checks */
+	if (!is_protmode(vcpu) || (vmx_get_rflags(vcpu) & X86_EFLAGS_VM)) {
+		if (!rmode_segment_valid(vcpu, VCPU_SREG_CS))
 			return false;
 		if (!rmode_segment_valid(vcpu, VCPU_SREG_SS))
 			return false;
@@ -4311,10 +4748,8 @@
 	spin_unlock(&vmx_vpid_lock);
 }
 
-#define MSR_TYPE_R	1
-#define MSR_TYPE_W	2
-static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
-						u32 msr, int type)
+static void __always_inline vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
+							  u32 msr, int type)
 {
 	int f = sizeof(unsigned long);
 
@@ -4348,8 +4783,8 @@
 	}
 }
 
-static void __vmx_enable_intercept_for_msr(unsigned long *msr_bitmap,
-						u32 msr, int type)
+static void __always_inline vmx_enable_intercept_for_msr(unsigned long *msr_bitmap,
+							 u32 msr, int type)
 {
 	int f = sizeof(unsigned long);
 
@@ -4429,68 +4864,124 @@
 	}
 }
 
-static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only)
+static void __always_inline vmx_set_intercept_for_msr(unsigned long *msr_bitmap,
+			     			      u32 msr, int type, bool value)
+{
+	if (value)
+		vmx_enable_intercept_for_msr(msr_bitmap, msr, type);
+	else
+		vmx_disable_intercept_for_msr(msr_bitmap, msr, type);
+}
+
+static u8 vmx_msr_bitmap_mode(struct kvm_vcpu *vcpu)
 {
-	if (!longmode_only)
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy,
-						msr, MSR_TYPE_R | MSR_TYPE_W);
-	__vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode,
-						msr, MSR_TYPE_R | MSR_TYPE_W);
+	u8 mode = 0;
+
+	if (cpu_has_secondary_exec_ctrls() &&
+	    (vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
+	     SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
+		mode |= MSR_BITMAP_MODE_X2APIC;
+		if (enable_apicv && kvm_vcpu_apicv_active(vcpu))
+			mode |= MSR_BITMAP_MODE_X2APIC_APICV;
+	}
+
+	if (is_long_mode(vcpu))
+		mode |= MSR_BITMAP_MODE_LM;
+
+	return mode;
 }
 
-static void vmx_enable_intercept_msr_read_x2apic(u32 msr)
+#define X2APIC_MSR(r) (APIC_BASE_MSR + ((r) >> 4))
+
+static void vmx_update_msr_bitmap_x2apic(unsigned long *msr_bitmap,
+					 u8 mode)
 {
-	__vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
-			msr, MSR_TYPE_R);
-	__vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
-			msr, MSR_TYPE_R);
+	int msr;
+
+	for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
+		unsigned word = msr / BITS_PER_LONG;
+		msr_bitmap[word] = (mode & MSR_BITMAP_MODE_X2APIC_APICV) ? 0 : ~0;
+		msr_bitmap[word + (0x800 / sizeof(long))] = ~0;
+	}
+
+	if (mode & MSR_BITMAP_MODE_X2APIC) {
+		/*
+		 * TPR reads and writes can be virtualized even if virtual interrupt
+		 * delivery is not in use.
+		 */
+		vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_TASKPRI), MSR_TYPE_RW);
+		if (mode & MSR_BITMAP_MODE_X2APIC_APICV) {
+			vmx_enable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_ID), MSR_TYPE_R);
+			vmx_enable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_TMCCT), MSR_TYPE_R);
+			vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_EOI), MSR_TYPE_W);
+			vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_SELF_IPI), MSR_TYPE_W);
+		}
+	}
 }
 
-static void vmx_disable_intercept_msr_read_x2apic(u32 msr)
+static void vmx_update_msr_bitmap(struct kvm_vcpu *vcpu)
 {
-	__vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
-			msr, MSR_TYPE_R);
-	__vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
-			msr, MSR_TYPE_R);
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap;
+	u8 mode = vmx_msr_bitmap_mode(vcpu);
+	u8 changed = mode ^ vmx->msr_bitmap_mode;
+
+	if (!changed)
+		return;
+
+	vmx_set_intercept_for_msr(msr_bitmap, MSR_KERNEL_GS_BASE, MSR_TYPE_RW,
+				  !(mode & MSR_BITMAP_MODE_LM));
+
+	if (changed & (MSR_BITMAP_MODE_X2APIC | MSR_BITMAP_MODE_X2APIC_APICV))
+		vmx_update_msr_bitmap_x2apic(msr_bitmap, mode);
+
+	vmx->msr_bitmap_mode = mode;
 }
 
-static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
+static bool vmx_get_enable_apicv(void)
 {
-	__vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
-			msr, MSR_TYPE_W);
-	__vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
-			msr, MSR_TYPE_W);
+	return enable_apicv;
 }
 
-static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu)
+static void nested_mark_vmcs12_pages_dirty(struct kvm_vcpu *vcpu)
 {
-	return enable_apicv && lapic_in_kernel(vcpu);
+	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+	gfn_t gfn;
+
+	/*
+	 * Don't need to mark the APIC access page dirty; it is never
+	 * written to by the CPU during APIC virtualization.
+	 */
+
+	if (nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) {
+		gfn = vmcs12->virtual_apic_page_addr >> PAGE_SHIFT;
+		kvm_vcpu_mark_page_dirty(vcpu, gfn);
+	}
+
+	if (nested_cpu_has_posted_intr(vmcs12)) {
+		gfn = vmcs12->posted_intr_desc_addr >> PAGE_SHIFT;
+		kvm_vcpu_mark_page_dirty(vcpu, gfn);
+	}
 }
 
-static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
+
+static void vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	int max_irr;
 	void *vapic_page;
 	u16 status;
 
-	if (vmx->nested.pi_desc &&
-	    vmx->nested.pi_pending) {
-		vmx->nested.pi_pending = false;
-		if (!pi_test_and_clear_on(vmx->nested.pi_desc))
-			return 0;
-
-		max_irr = find_last_bit(
-			(unsigned long *)vmx->nested.pi_desc->pir, 256);
+	if (!vmx->nested.pi_desc || !vmx->nested.pi_pending)
+		return;
 
-		if (max_irr == 256)
-			return 0;
+	vmx->nested.pi_pending = false;
+	if (!pi_test_and_clear_on(vmx->nested.pi_desc))
+		return;
 
+	max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256);
+	if (max_irr != 256) {
 		vapic_page = kmap(vmx->nested.virtual_apic_page);
-		if (!vapic_page) {
-			WARN_ON(1);
-			return -ENOMEM;
-		}
 		__kvm_apic_update_irr(vmx->nested.pi_desc->pir, vapic_page);
 		kunmap(vmx->nested.virtual_apic_page);
 
@@ -4501,28 +4992,38 @@
 			vmcs_write16(GUEST_INTR_STATUS, status);
 		}
 	}
-	return 0;
+
+	nested_mark_vmcs12_pages_dirty(vcpu);
 }
 
 static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_SMP
 	if (vcpu->mode == IN_GUEST_MODE) {
-		struct vcpu_vmx *vmx = to_vmx(vcpu);
-
 		/*
-		 * Currently, we don't support urgent interrupt,
-		 * all interrupts are recognized as non-urgent
-		 * interrupt, so we cannot post interrupts when
-		 * 'SN' is set.
+		 * The vector of interrupt to be delivered to vcpu had
+		 * been set in PIR before this function.
 		 *
-		 * If the vcpu is in guest mode, it means it is
-		 * running instead of being scheduled out and
-		 * waiting in the run queue, and that's the only
-		 * case when 'SN' is set currently, warning if
-		 * 'SN' is set.
+		 * Following cases will be reached in this block, and
+		 * we always send a notification event in all cases as
+		 * explained below.
+		 *
+		 * Case 1: vcpu keeps in non-root mode. Sending a
+		 * notification event posts the interrupt to vcpu.
+		 *
+		 * Case 2: vcpu exits to root mode and is still
+		 * runnable. PIR will be synced to vIRR before the
+		 * next vcpu entry. Sending a notification event in
+		 * this case has no effect, as vcpu is not in root
+		 * mode.
+		 *
+		 * Case 3: vcpu exits to root mode and is blocked.
+		 * vcpu_block() has already synced PIR to vIRR and
+		 * never blocks vcpu if vIRR is not cleared. Therefore,
+		 * a blocked vcpu here does not wait for any requested
+		 * interrupts in PIR, and sending a notification event
+		 * which has no effect is safe here.
 		 */
-		WARN_ON_ONCE(pi_test_sn(&vmx->pi_desc));
 
 		apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
 				POSTED_INTR_VECTOR);
@@ -4539,14 +5040,15 @@
 
 	if (is_guest_mode(vcpu) &&
 	    vector == vmx->nested.posted_intr_nv) {
-		/* the PIR and ON have been set by L1. */
-		kvm_vcpu_trigger_posted_interrupt(vcpu);
 		/*
 		 * If a posted intr is not recognized by hardware,
 		 * we will accomplish it in the next vmentry.
 		 */
 		vmx->nested.pi_pending = true;
 		kvm_make_request(KVM_REQ_EVENT, vcpu);
+		/* the PIR and ON have been set by L1. */
+		if (!kvm_vcpu_trigger_posted_interrupt(vcpu))
+			kvm_vcpu_kick(vcpu);
 		return 0;
 	}
 	return -1;
@@ -4586,11 +5088,6 @@
 	kvm_apic_update_irr(vcpu, vmx->pi_desc.pir);
 }
 
-static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu)
-{
-	return;
-}
-
 /*
  * Set up the vmcs's constant host-state fields, i.e., host-state fields that
  * will not change in the lifetime of the guest.
@@ -4660,11 +5157,31 @@
 {
 	u32 pin_based_exec_ctrl = vmcs_config.pin_based_exec_ctrl;
 
-	if (!vmx_cpu_uses_apicv(&vmx->vcpu))
+	if (!kvm_vcpu_apicv_active(&vmx->vcpu))
 		pin_based_exec_ctrl &= ~PIN_BASED_POSTED_INTR;
 	return pin_based_exec_ctrl;
 }
 
+static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
+{
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+	vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
+	if (cpu_has_secondary_exec_ctrls()) {
+		if (kvm_vcpu_apicv_active(vcpu))
+			vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
+				      SECONDARY_EXEC_APIC_REGISTER_VIRT |
+				      SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
+		else
+			vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
+					SECONDARY_EXEC_APIC_REGISTER_VIRT |
+					SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
+	}
+
+	if (cpu_has_vmx_msr_bitmap())
+		vmx_update_msr_bitmap(vcpu);
+}
+
 static u32 vmx_exec_control(struct vcpu_vmx *vmx)
 {
 	u32 exec_control = vmcs_config.cpu_based_exec_ctrl;
@@ -4703,7 +5220,7 @@
 		exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
 	if (!ple_gap)
 		exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING;
-	if (!vmx_cpu_uses_apicv(&vmx->vcpu))
+	if (!kvm_vcpu_apicv_active(&vmx->vcpu))
 		exec_control &= ~(SECONDARY_EXEC_APIC_REGISTER_VIRT |
 				  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
 	exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
@@ -4754,7 +5271,7 @@
 		vmcs_write64(VMWRITE_BITMAP, __pa(vmx_vmwrite_bitmap));
 	}
 	if (cpu_has_vmx_msr_bitmap())
-		vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy));
+		vmcs_write64(MSR_BITMAP, __pa(vmx->vmcs01.msr_bitmap));
 
 	vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
 
@@ -4767,7 +5284,7 @@
 		vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
 				vmx_secondary_exec_control(vmx));
 
-	if (vmx_cpu_uses_apicv(&vmx->vcpu)) {
+	if (kvm_vcpu_apicv_active(&vmx->vcpu)) {
 		vmcs_write64(EOI_EXIT_BITMAP0, 0);
 		vmcs_write64(EOI_EXIT_BITMAP1, 0);
 		vmcs_write64(EOI_EXIT_BITMAP2, 0);
@@ -4804,9 +5321,9 @@
 
 	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
-	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host));
+	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val));
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
-	vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest));
+	vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest.val));
 
 	if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT)
 		vmcs_write64(GUEST_IA32_PAT, vmx->vcpu.arch.pat);
@@ -4826,7 +5343,6 @@
 		++vmx->nmsrs;
 	}
 
-
 	vm_exit_controls_init(vmx, vmcs_config.vmexit_ctrl);
 
 	/* 22.2.1, 20.8.1 */
@@ -4838,6 +5354,12 @@
 	if (vmx_xsaves_supported())
 		vmcs_write64(XSS_EXIT_BITMAP, VMX_XSS_EXIT_BITMAP);
 
+	if (enable_pml) {
+		ASSERT(vmx->pml_pg);
+		vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg));
+		vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+	}
+
 	return 0;
 }
 
@@ -4848,6 +5370,8 @@
 	u64 cr0;
 
 	vmx->rmode.vm86_active = 0;
+	vcpu->arch.microcode_version = 0x100000000ULL;
+	vmx->spec_ctrl = 0;
 
 	vmx->soft_vnmi_blocked = 0;
 
@@ -4892,7 +5416,7 @@
 		vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 	}
 
-	vmcs_writel(GUEST_RFLAGS, 0x02);
+	kvm_set_rflags(vcpu, X86_EFLAGS_FIXED);
 	kvm_rip_write(vcpu, 0xfff0);
 
 	vmcs_writel(GUEST_GDTR_BASE, 0);
@@ -4919,21 +5443,23 @@
 
 	kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
 
-	if (vmx_cpu_uses_apicv(vcpu))
+	if (kvm_vcpu_apicv_active(vcpu))
 		memset(&vmx->pi_desc, 0, sizeof(struct pi_desc));
 
 	if (vmx->vpid != 0)
 		vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
 
 	cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
-	vmx_set_cr0(vcpu, cr0); /* enter rmode */
 	vmx->vcpu.arch.cr0 = cr0;
+	vmx_set_cr0(vcpu, cr0); /* enter rmode */
 	vmx_set_cr4(vcpu, 0);
 	vmx_set_efer(vcpu, 0);
 	vmx_fpu_activate(vcpu);
 	update_exception_bitmap(vcpu);
 
 	vpid_sync_context(vmx->vpid);
+
+	vmx_update_fb_clear_dis(vcpu, vmx);
 }
 
 /*
@@ -5174,7 +5700,7 @@
  */
 static void kvm_machine_check(void)
 {
-#if defined(CONFIG_X86_MCE) && defined(CONFIG_X86_64)
+#if defined(CONFIG_X86_MCE)
 	struct pt_regs regs = {
 		.cs = 3, /* Fake ring 3 no matter what the guest ran on */
 		.flags = X86_EFLAGS_IF,
@@ -5205,7 +5731,7 @@
 	if (is_machine_check(intr_info))
 		return handle_machine_check(vcpu);
 
-	if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR)
+	if (is_nmi(intr_info))
 		return 1;  /* already handled by vmx_vcpu_run() */
 
 	if (is_no_device(intr_info)) {
@@ -5219,6 +5745,8 @@
 			return 1;
 		}
 		er = emulate_instruction(vcpu, EMULTYPE_TRAP_UD);
+		if (er == EMULATE_USER_EXIT)
+			return 0;
 		if (er != EMULATE_DONE)
 			kvm_queue_exception(vcpu, UD_VECTOR);
 		return 1;
@@ -5249,6 +5777,7 @@
 		BUG_ON(enable_ept);
 		cr2 = vmcs_readl(EXIT_QUALIFICATION);
 		trace_kvm_page_fault(cr2, error_code);
+		vcpu->arch.l1tf_flush_l1d = true;
 
 		if (kvm_event_needs_reinjection(vcpu))
 			kvm_mmu_unprotect_page_virt(vcpu, cr2);
@@ -5270,7 +5799,7 @@
 		      (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
 			vcpu->arch.dr6 &= ~15;
 			vcpu->arch.dr6 |= dr6 | DR6_RTM;
-			if (!(dr6 & ~DR6_RESERVED)) /* icebp */
+			if (is_icebp(intr_info))
 				skip_emulated_instruction(vcpu);
 
 			kvm_queue_exception(vcpu, DB_VECTOR);
@@ -5310,6 +5839,7 @@
 static int handle_triple_fault(struct kvm_vcpu *vcpu)
 {
 	vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
+	vcpu->mmio_needed = 0;
 	return 0;
 }
 
@@ -5616,6 +6146,7 @@
 
 	msr_info.index = ecx;
 	msr_info.host_initiated = false;
+
 	if (vmx_get_msr(vcpu, &msr_info)) {
 		trace_kvm_msr_read_ex(ecx);
 		kvm_inject_gp(vcpu, 0);
@@ -5901,21 +6432,29 @@
 
 	gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
 	if (!kvm_io_bus_write(vcpu, KVM_FAST_MMIO_BUS, gpa, 0, NULL)) {
-		skip_emulated_instruction(vcpu);
 		trace_kvm_fast_mmio(gpa);
-		return 1;
+		/*
+		* Doing kvm_skip_emulated_instruction() depends on undefined
+		* behavior: Intel's manual doesn't mandate
+		* VM_EXIT_INSTRUCTION_LEN to be set in VMCS when EPT MISCONFIG
+		* occurs and while on real hardware it was observed to be set,
+		* other hypervisors (namely Hyper-V) don't set it, we end up
+		* advancing IP with some random value. Disable fast mmio when
+		* running nested and keep it for real hardware in hope that
+		* VM_EXIT_INSTRUCTION_LEN will always be set correctly.
+		*/
+		if (!static_cpu_has(X86_FEATURE_HYPERVISOR)) {
+			skip_emulated_instruction(vcpu);
+			return 1;
+		}
+		else
+			return emulate_instruction(vcpu, EMULTYPE_SKIP) ==
+								EMULATE_DONE;
 	}
 
-	ret = handle_mmio_page_fault(vcpu, gpa, true);
-	if (likely(ret == RET_MMIO_PF_EMULATE))
-		return x86_emulate_instruction(vcpu, gpa, 0, NULL, 0) ==
-					      EMULATE_DONE;
-
-	if (unlikely(ret == RET_MMIO_PF_INVALID))
-		return kvm_mmu_page_fault(vcpu, gpa, 0, NULL, 0);
-
-	if (unlikely(ret == RET_MMIO_PF_RETRY))
-		return 1;
+	ret = kvm_mmu_page_fault(vcpu, gpa, PFERR_RSVD_MASK, NULL, 0);
+	if (ret >= 0)
+		return ret;
 
 	/* It is the real ept misconfig */
 	WARN_ON(1);
@@ -5959,7 +6498,7 @@
 		if (test_bit(KVM_REQ_EVENT, &vcpu->requests))
 			return 1;
 
-		err = emulate_instruction(vcpu, EMULTYPE_NO_REEXECUTE);
+		err = emulate_instruction(vcpu, 0);
 
 		if (err == EMULATE_USER_EXIT) {
 			++vcpu->stat.mmio_exits;
@@ -5967,12 +6506,12 @@
 			goto out;
 		}
 
-		if (err != EMULATE_DONE) {
-			vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-			vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
-			vcpu->run->internal.ndata = 0;
-			return 0;
-		}
+		if (err != EMULATE_DONE)
+			goto emulation_error;
+
+		if (vmx->emulation_required && !vmx->rmode.vm86_active &&
+		    vcpu->arch.exception.pending)
+			goto emulation_error;
 
 		if (vcpu->arch.halt_request) {
 			vcpu->arch.halt_request = 0;
@@ -5988,6 +6527,12 @@
 
 out:
 	return ret;
+
+emulation_error:
+	vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+	vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+	vcpu->run->internal.ndata = 0;
+	return 0;
 }
 
 static int __grow_ple_window(int val)
@@ -6081,7 +6626,7 @@
 
 static __init int hardware_setup(void)
 {
-	int r = -ENOMEM, i, msr;
+	int r = -ENOMEM, i;
 
 	rdmsrl_safe(MSR_EFER, &host_efer);
 
@@ -6096,66 +6641,33 @@
 	if (!vmx_io_bitmap_b)
 		goto out;
 
-	vmx_msr_bitmap_legacy = (unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_legacy)
-		goto out1;
-
-	vmx_msr_bitmap_legacy_x2apic =
-				(unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_legacy_x2apic)
-		goto out2;
-
-	vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_longmode)
-		goto out3;
-
-	vmx_msr_bitmap_longmode_x2apic =
-				(unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_longmode_x2apic)
-		goto out4;
-
-	if (nested) {
-		vmx_msr_bitmap_nested =
-			(unsigned long *)__get_free_page(GFP_KERNEL);
-		if (!vmx_msr_bitmap_nested)
-			goto out5;
-	}
-
 	vmx_vmread_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
 	if (!vmx_vmread_bitmap)
-		goto out6;
+		goto out1;
 
 	vmx_vmwrite_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
 	if (!vmx_vmwrite_bitmap)
-		goto out7;
+		goto out2;
 
 	memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE);
 	memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE);
 
-	/*
-	 * Allow direct access to the PC debug port (it is often used for I/O
-	 * delays, but the vmexits simply slow things down).
-	 */
 	memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE);
-	clear_bit(0x80, vmx_io_bitmap_a);
 
 	memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);
 
-	memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE);
-	memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE);
-	if (nested)
-		memset(vmx_msr_bitmap_nested, 0xff, PAGE_SIZE);
-
 	if (setup_vmcs_config(&vmcs_config) < 0) {
 		r = -EIO;
-		goto out8;
+		goto out3;
 	}
 
 	if (boot_cpu_has(X86_FEATURE_NX))
 		kvm_enable_efer_bits(EFER_NX);
 
-	if (!cpu_has_vmx_vpid())
+	if (!cpu_has_vmx_vpid() || !cpu_has_vmx_invvpid() ||
+		!(cpu_has_vmx_invvpid_single() || cpu_has_vmx_invvpid_global()))
 		enable_vpid = 0;
+
 	if (!cpu_has_vmx_shadow_vmcs())
 		enable_shadow_vmcs = 0;
 	if (enable_shadow_vmcs)
@@ -6203,48 +6715,8 @@
 		kvm_tsc_scaling_ratio_frac_bits = 48;
 	}
 
-	if (enable_apicv)
-		kvm_x86_ops->update_cr8_intercept = NULL;
-	else {
-		kvm_x86_ops->hwapic_irr_update = NULL;
-		kvm_x86_ops->hwapic_isr_update = NULL;
-		kvm_x86_ops->deliver_posted_interrupt = NULL;
-		kvm_x86_ops->sync_pir_to_irr = vmx_sync_pir_to_irr_dummy;
-	}
-
-	vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
-	vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
-	vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
-	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
-	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
-	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
-	vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
-
-	memcpy(vmx_msr_bitmap_legacy_x2apic,
-			vmx_msr_bitmap_legacy, PAGE_SIZE);
-	memcpy(vmx_msr_bitmap_longmode_x2apic,
-			vmx_msr_bitmap_longmode, PAGE_SIZE);
-
 	set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
 
-	if (enable_apicv) {
-		for (msr = 0x800; msr <= 0x8ff; msr++)
-			vmx_disable_intercept_msr_read_x2apic(msr);
-
-		/* According SDM, in x2apic mode, the whole id reg is used.
-		 * But in KVM, it only use the highest eight bits. Need to
-		 * intercept it */
-		vmx_enable_intercept_msr_read_x2apic(0x802);
-		/* TMCCT */
-		vmx_enable_intercept_msr_read_x2apic(0x839);
-		/* TPR */
-		vmx_disable_intercept_msr_write_x2apic(0x808);
-		/* EOI */
-		vmx_disable_intercept_msr_write_x2apic(0x80b);
-		/* SELF-IPI */
-		vmx_disable_intercept_msr_write_x2apic(0x83f);
-	}
-
 	if (enable_ept) {
 		kvm_mmu_set_mask_ptes(0ull,
 			(enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
@@ -6275,21 +6747,10 @@
 
 	return alloc_kvm_area();
 
-out8:
-	free_page((unsigned long)vmx_vmwrite_bitmap);
-out7:
-	free_page((unsigned long)vmx_vmread_bitmap);
-out6:
-	if (nested)
-		free_page((unsigned long)vmx_msr_bitmap_nested);
-out5:
-	free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
-out4:
-	free_page((unsigned long)vmx_msr_bitmap_longmode);
 out3:
-	free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
+	free_page((unsigned long)vmx_vmwrite_bitmap);
 out2:
-	free_page((unsigned long)vmx_msr_bitmap_legacy);
+	free_page((unsigned long)vmx_vmread_bitmap);
 out1:
 	free_page((unsigned long)vmx_io_bitmap_b);
 out:
@@ -6300,16 +6761,10 @@
 
 static __exit void hardware_unsetup(void)
 {
-	free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
-	free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
-	free_page((unsigned long)vmx_msr_bitmap_legacy);
-	free_page((unsigned long)vmx_msr_bitmap_longmode);
 	free_page((unsigned long)vmx_io_bitmap_b);
 	free_page((unsigned long)vmx_io_bitmap_a);
 	free_page((unsigned long)vmx_vmwrite_bitmap);
 	free_page((unsigned long)vmx_vmread_bitmap);
-	if (nested)
-		free_page((unsigned long)vmx_msr_bitmap_nested);
 
 	free_kvm_area();
 }
@@ -6353,93 +6808,6 @@
 }
 
 /*
- * To run an L2 guest, we need a vmcs02 based on the L1-specified vmcs12.
- * We could reuse a single VMCS for all the L2 guests, but we also want the
- * option to allocate a separate vmcs02 for each separate loaded vmcs12 - this
- * allows keeping them loaded on the processor, and in the future will allow
- * optimizations where prepare_vmcs02 doesn't need to set all the fields on
- * every entry if they never change.
- * So we keep, in vmx->nested.vmcs02_pool, a cache of size VMCS02_POOL_SIZE
- * (>=0) with a vmcs02 for each recently loaded vmcs12s, most recent first.
- *
- * The following functions allocate and free a vmcs02 in this pool.
- */
-
-/* Get a VMCS from the pool to use as vmcs02 for the current vmcs12. */
-static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx)
-{
-	struct vmcs02_list *item;
-	list_for_each_entry(item, &vmx->nested.vmcs02_pool, list)
-		if (item->vmptr == vmx->nested.current_vmptr) {
-			list_move(&item->list, &vmx->nested.vmcs02_pool);
-			return &item->vmcs02;
-		}
-
-	if (vmx->nested.vmcs02_num >= max(VMCS02_POOL_SIZE, 1)) {
-		/* Recycle the least recently used VMCS. */
-		item = list_entry(vmx->nested.vmcs02_pool.prev,
-			struct vmcs02_list, list);
-		item->vmptr = vmx->nested.current_vmptr;
-		list_move(&item->list, &vmx->nested.vmcs02_pool);
-		return &item->vmcs02;
-	}
-
-	/* Create a new VMCS */
-	item = kmalloc(sizeof(struct vmcs02_list), GFP_KERNEL);
-	if (!item)
-		return NULL;
-	item->vmcs02.vmcs = alloc_vmcs();
-	if (!item->vmcs02.vmcs) {
-		kfree(item);
-		return NULL;
-	}
-	loaded_vmcs_init(&item->vmcs02);
-	item->vmptr = vmx->nested.current_vmptr;
-	list_add(&(item->list), &(vmx->nested.vmcs02_pool));
-	vmx->nested.vmcs02_num++;
-	return &item->vmcs02;
-}
-
-/* Free and remove from pool a vmcs02 saved for a vmcs12 (if there is one) */
-static void nested_free_vmcs02(struct vcpu_vmx *vmx, gpa_t vmptr)
-{
-	struct vmcs02_list *item;
-	list_for_each_entry(item, &vmx->nested.vmcs02_pool, list)
-		if (item->vmptr == vmptr) {
-			free_loaded_vmcs(&item->vmcs02);
-			list_del(&item->list);
-			kfree(item);
-			vmx->nested.vmcs02_num--;
-			return;
-		}
-}
-
-/*
- * Free all VMCSs saved for this vcpu, except the one pointed by
- * vmx->loaded_vmcs. We must be running L1, so vmx->loaded_vmcs
- * must be &vmx->vmcs01.
- */
-static void nested_free_all_saved_vmcss(struct vcpu_vmx *vmx)
-{
-	struct vmcs02_list *item, *n;
-
-	WARN_ON(vmx->loaded_vmcs != &vmx->vmcs01);
-	list_for_each_entry_safe(item, n, &vmx->nested.vmcs02_pool, list) {
-		/*
-		 * Something will leak if the above WARN triggers.  Better than
-		 * a use-after-free.
-		 */
-		if (vmx->loaded_vmcs == &item->vmcs02)
-			continue;
-
-		free_loaded_vmcs(&item->vmcs02);
-		list_del(&item->list);
-		kfree(item);
-		vmx->nested.vmcs02_num--;
-	}
-}
-
-/*
  * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(),
  * set the success or error code of an emulated VMX instruction, as specified
  * by Vol 2B, VMX Instruction Reference, "Conventions".
@@ -6539,6 +6907,10 @@
 	/* Addr = segment_base + offset */
 	/* offset = base + [index * scale] + displacement */
 	off = exit_qualification; /* holds the displacement */
+	if (addr_size == 1)
+		off = (gva_t)sign_extend64(off, 31);
+	else if (addr_size == 0)
+		off = (gva_t)sign_extend64(off, 15);
 	if (base_is_valid)
 		off += kvm_register_read(vcpu, base_reg);
 	if (index_is_valid)
@@ -6551,7 +6923,13 @@
 
 	/* Checks for #GP/#SS exceptions. */
 	exn = false;
-	if (is_protmode(vcpu)) {
+	if (is_long_mode(vcpu)) {
+		/* Long mode: #GP(0)/#SS(0) if the memory address is in a
+		 * non-canonical form. This is the only check on the memory
+		 * destination for long mode!
+		 */
+		exn = is_noncanonical_address(*ret);
+	} else if (is_protmode(vcpu)) {
 		/* Protected mode: apply checks for segment validity in the
 		 * following order:
 		 * - segment type check (#GP(0) may be thrown)
@@ -6568,24 +6946,23 @@
 			 * execute-only code segment
 			 */
 			exn = ((s.type & 0xa) == 8);
-	}
-	if (exn) {
-		kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
-		return 1;
-	}
-	if (is_long_mode(vcpu)) {
-		/* Long mode: #GP(0)/#SS(0) if the memory address is in a
-		 * non-canonical form. This is an only check for long mode.
-		 */
-		exn = is_noncanonical_address(*ret);
-	} else if (is_protmode(vcpu)) {
+		if (exn) {
+			kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
+			return 1;
+		}
 		/* Protected mode: #GP(0)/#SS(0) if the segment is unusable.
 		 */
 		exn = (s.unusable != 0);
-		/* Protected mode: #GP(0)/#SS(0) if the memory
-		 * operand is outside the segment limit.
-		 */
-		exn = exn || (off + sizeof(u64) > s.limit);
+
+		/*
+		 * Protected mode: #GP(0)/#SS(0) if the memory operand is
+		 * outside the segment limit.  All CPUs that support VMX ignore
+		 * limit checks for flat segments, i.e. segments with base==0,
+		 * limit==0xffffffff and of type expand-up data or code.
+		 */
+		if (!(s.base == 0 && s.limit == 0xffffffff &&
+		     ((s.type & 8) || !(s.type & 4))))
+			exn = exn || (off + sizeof(u64) > s.limit);
 	}
 	if (exn) {
 		kvm_queue_exception_e(vcpu,
@@ -6619,8 +6996,7 @@
 			vmcs_read32(VMX_INSTRUCTION_INFO), false, &gva))
 		return 1;
 
-	if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr,
-				sizeof(vmptr), &e)) {
+	if (kvm_read_guest_virt(vcpu, gva, &vmptr, sizeof(vmptr), &e)) {
 		kvm_inject_page_fault(vcpu, &e);
 		return 1;
 	}
@@ -6644,14 +7020,20 @@
 		}
 
 		page = nested_get_page(vcpu, vmptr);
-		if (page == NULL ||
-		    *(u32 *)kmap(page) != VMCS12_REVISION) {
+		if (page == NULL) {
 			nested_vmx_failInvalid(vcpu);
+			skip_emulated_instruction(vcpu);
+			return 1;
+		}
+		if (*(u32 *)kmap(page) != VMCS12_REVISION) {
 			kunmap(page);
+			nested_release_page_clean(page);
+			nested_vmx_failInvalid(vcpu);
 			skip_emulated_instruction(vcpu);
 			return 1;
 		}
 		kunmap(page);
+		nested_release_page_clean(page);
 		vmx->nested.vmxon_ptr = vmptr;
 		break;
 	case EXIT_REASON_VMCLEAR:
@@ -6708,6 +7090,7 @@
 	struct vmcs *shadow_vmcs;
 	const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED
 		| FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
+	int r;
 
 	/* The Intel VMX Instruction Reference lists a bunch of bits that
 	 * are prerequisite to running VMXON, most notably cr4.VMXE must be
@@ -6747,29 +7130,38 @@
 		return 1;
 	}
 
+	r = alloc_loaded_vmcs(&vmx->nested.vmcs02);
+	if (r < 0)
+		goto out_vmcs02;
+
 	if (enable_shadow_vmcs) {
 		shadow_vmcs = alloc_vmcs();
 		if (!shadow_vmcs)
-			return -ENOMEM;
+			goto out_shadow_vmcs;
 		/* mark vmcs as shadow */
 		shadow_vmcs->revision_id |= (1u << 31);
 		/* init shadow vmcs */
 		vmcs_clear(shadow_vmcs);
-		vmx->nested.current_shadow_vmcs = shadow_vmcs;
+		vmx->vmcs01.shadow_vmcs = shadow_vmcs;
 	}
 
-	INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool));
-	vmx->nested.vmcs02_num = 0;
-
 	hrtimer_init(&vmx->nested.preemption_timer, CLOCK_MONOTONIC,
 		     HRTIMER_MODE_REL);
 	vmx->nested.preemption_timer.function = vmx_preemption_timer_fn;
 
+	vmx->nested.vpid02 = allocate_vpid();
+
 	vmx->nested.vmxon = true;
 
 	skip_emulated_instruction(vcpu);
 	nested_vmx_succeed(vcpu);
 	return 1;
+
+out_shadow_vmcs:
+	free_loaded_vmcs(&vmx->nested.vmcs02);
+
+out_vmcs02:
+	return -ENOMEM;
 }
 
 /*
@@ -6836,11 +7228,15 @@
 	if (!vmx->nested.vmxon)
 		return;
 
+	hrtimer_cancel(&vmx->nested.preemption_timer);
 	vmx->nested.vmxon = false;
 	free_vpid(vmx->nested.vpid02);
 	nested_release_vmcs12(vmx);
-	if (enable_shadow_vmcs)
-		free_vmcs(vmx->nested.current_shadow_vmcs);
+	if (enable_shadow_vmcs) {
+		vmcs_clear(vmx->vmcs01.shadow_vmcs);
+		free_vmcs(vmx->vmcs01.shadow_vmcs);
+		vmx->vmcs01.shadow_vmcs = NULL;
+	}
 	/* Unpin physical memory we referred to in current vmcs02 */
 	if (vmx->nested.apic_access_page) {
 		nested_release_page(vmx->nested.apic_access_page);
@@ -6857,7 +7253,7 @@
 		vmx->nested.pi_desc = NULL;
 	}
 
-	nested_free_all_saved_vmcss(vmx);
+	free_loaded_vmcs(&vmx->nested.vmcs02);
 }
 
 /* Emulate the VMXOFF instruction */
@@ -6875,9 +7271,8 @@
 static int handle_vmclear(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	u32 zero = 0;
 	gpa_t vmptr;
-	struct vmcs12 *vmcs12;
-	struct page *page;
 
 	if (!nested_vmx_check_permission(vcpu))
 		return 1;
@@ -6888,24 +7283,9 @@
 	if (vmptr == vmx->nested.current_vmptr)
 		nested_release_vmcs12(vmx);
 
-	page = nested_get_page(vcpu, vmptr);
-	if (page == NULL) {
-		/*
-		 * For accurate processor emulation, VMCLEAR beyond available
-		 * physical memory should do nothing at all. However, it is
-		 * possible that a nested vmx bug, not a guest hypervisor bug,
-		 * resulted in this case, so let's shut down before doing any
-		 * more damage:
-		 */
-		kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
-		return 1;
-	}
-	vmcs12 = kmap(page);
-	vmcs12->launch_state = 0;
-	kunmap(page);
-	nested_release_page(page);
-
-	nested_free_vmcs02(vmx, vmptr);
+	kvm_vcpu_write_guest(vcpu,
+			vmptr + offsetof(struct vmcs12, launch_state),
+			&zero, sizeof(zero));
 
 	skip_emulated_instruction(vcpu);
 	nested_vmx_succeed(vcpu);
@@ -7016,7 +7396,7 @@
 	int i;
 	unsigned long field;
 	u64 field_value;
-	struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
+	struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
 	const unsigned long *fields = shadow_read_write_fields;
 	const int num_fields = max_shadow_read_write_fields;
 
@@ -7065,7 +7445,7 @@
 	int i, q;
 	unsigned long field;
 	u64 field_value = 0;
-	struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
+	struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
 
 	vmcs_load(shadow_vmcs);
 
@@ -7120,6 +7500,7 @@
 	unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 	u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
 	gva_t gva = 0;
+	struct x86_exception e;
 
 	if (!nested_vmx_check_permission(vcpu) ||
 	    !nested_vmx_check_vmcs12(vcpu))
@@ -7146,8 +7527,12 @@
 				vmx_instruction_info, true, &gva))
 			return 1;
 		/* _system ok, as nested_vmx_check_permission verified cpl=0 */
-		kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, gva,
-			     &field_value, (is_long_mode(vcpu) ? 8 : 4), NULL);
+		if (kvm_write_guest_virt_system(vcpu, gva, &field_value,
+						(is_long_mode(vcpu) ? 8 : 4),
+						&e)) {
+			kvm_inject_page_fault(vcpu, &e);
+			return 1;
+		}
 	}
 
 	nested_vmx_succeed(vcpu);
@@ -7182,8 +7567,8 @@
 		if (get_vmx_mem_address(vcpu, exit_qualification,
 				vmx_instruction_info, false, &gva))
 			return 1;
-		if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva,
-			   &field_value, (is_64_bit_mode(vcpu) ? 8 : 4), &e)) {
+		if (kvm_read_guest_virt(vcpu, gva, &field_value,
+					(is_64_bit_mode(vcpu) ? 8 : 4), &e)) {
 			kvm_inject_page_fault(vcpu, &e);
 			return 1;
 		}
@@ -7248,7 +7633,7 @@
 			vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
 				      SECONDARY_EXEC_SHADOW_VMCS);
 			vmcs_write64(VMCS_LINK_POINTER,
-				     __pa(vmx->nested.current_shadow_vmcs));
+				     __pa(vmx->vmcs01.shadow_vmcs));
 			vmx->nested.sync_shadow_vmcs = true;
 		}
 	}
@@ -7273,9 +7658,9 @@
 			vmx_instruction_info, true, &vmcs_gva))
 		return 1;
 	/* ok to use *_system, as nested_vmx_check_permission verified cpl=0 */
-	if (kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, vmcs_gva,
-				 (void *)&to_vmx(vcpu)->nested.current_vmptr,
-				 sizeof(u64), &e)) {
+	if (kvm_write_guest_virt_system(vcpu, vmcs_gva,
+					(void *)&to_vmx(vcpu)->nested.current_vmptr,
+					sizeof(u64), &e)) {
 		kvm_inject_page_fault(vcpu, &e);
 		return 1;
 	}
@@ -7316,9 +7701,10 @@
 
 	types = (vmx->nested.nested_vmx_ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6;
 
-	if (!(types & (1UL << type))) {
+	if (type >= 32 || !(types & (1 << type))) {
 		nested_vmx_failValid(vcpu,
 				VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+		skip_emulated_instruction(vcpu);
 		return 1;
 	}
 
@@ -7328,8 +7714,7 @@
 	if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
 			vmx_instruction_info, false, &gva))
 		return 1;
-	if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &operand,
-				sizeof(operand), &e)) {
+	if (kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e)) {
 		kvm_inject_page_fault(vcpu, &e);
 		return 1;
 	}
@@ -7372,11 +7757,13 @@
 	vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
 	type = kvm_register_readl(vcpu, (vmx_instruction_info >> 28) & 0xf);
 
-	types = (vmx->nested.nested_vmx_vpid_caps >> 8) & 0x7;
+	types = (vmx->nested.nested_vmx_vpid_caps &
+			VMX_VPID_EXTENT_SUPPORTED_MASK) >> 8;
 
-	if (!(types & (1UL << type))) {
+	if (type >= 32 || !(types & (1 << type))) {
 		nested_vmx_failValid(vcpu,
 			VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+		skip_emulated_instruction(vcpu);
 		return 1;
 	}
 
@@ -7386,23 +7773,33 @@
 	if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
 			vmx_instruction_info, false, &gva))
 		return 1;
-	if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vpid,
-				sizeof(u32), &e)) {
+	if (kvm_read_guest_virt(vcpu, gva, &vpid, sizeof(u32), &e)) {
 		kvm_inject_page_fault(vcpu, &e);
 		return 1;
 	}
 
 	switch (type) {
+	case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
+	case VMX_VPID_EXTENT_SINGLE_CONTEXT:
+	case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL:
+		if (!vpid) {
+			nested_vmx_failValid(vcpu,
+				VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+			skip_emulated_instruction(vcpu);
+			return 1;
+		}
+		break;
 	case VMX_VPID_EXTENT_ALL_CONTEXT:
-		__vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
-		nested_vmx_succeed(vcpu);
 		break;
 	default:
-		/* Trap single context invalidation invvpid calls */
-		BUG_ON(1);
-		break;
+		WARN_ON_ONCE(1);
+		skip_emulated_instruction(vcpu);
+		return 1;
 	}
 
+	__vmx_flush_tlb(vcpu, vmx->nested.vpid02);
+	nested_vmx_succeed(vcpu);
+
 	skip_emulated_instruction(vcpu);
 	return 1;
 }
@@ -7495,23 +7892,17 @@
 static const int kvm_vmx_max_exit_handlers =
 	ARRAY_SIZE(kvm_vmx_exit_handlers);
 
-static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
-				       struct vmcs12 *vmcs12)
+/*
+ * Return true if an IO instruction with the specified port and size should cause
+ * a VM-exit into L1.
+ */
+bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
+				 int size)
 {
-	unsigned long exit_qualification;
+	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
 	gpa_t bitmap, last_bitmap;
-	unsigned int port;
-	int size;
 	u8 b;
 
-	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
-		return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING);
-
-	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
-
-	port = exit_qualification >> 16;
-	size = (exit_qualification & 7) + 1;
-
 	last_bitmap = (gpa_t)-1;
 	b = -1;
 
@@ -7586,11 +7977,13 @@
 {
 	unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 	int cr = exit_qualification & 15;
-	int reg = (exit_qualification >> 8) & 15;
-	unsigned long val = kvm_register_readl(vcpu, reg);
+	int reg;
+	unsigned long val;
 
 	switch ((exit_qualification >> 4) & 3) {
 	case 0: /* mov to cr */
+		reg = (exit_qualification >> 8) & 15;
+		val = kvm_register_readl(vcpu, reg);
 		switch (cr) {
 		case 0:
 			if (vmcs12->cr0_guest_host_mask &
@@ -7645,6 +8038,7 @@
 		 * lmsw can change bits 1..3 of cr0, and only set bit 0 of
 		 * cr0. Other attempted changes are ignored, with no exit.
 		 */
+		val = (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f;
 		if (vmcs12->cr0_guest_host_mask & 0xe &
 		    (val ^ vmcs12->cr0_read_shadow))
 			return true;
@@ -7676,8 +8070,21 @@
 				vmcs_read32(VM_EXIT_INTR_ERROR_CODE),
 				KVM_ISA_VMX);
 
-	if (vmx->nested.nested_run_pending)
-		return false;
+	/*
+	 * The host physical addresses of some pages of guest memory
+	 * are loaded into the vmcs02 (e.g. vmcs12's Virtual APIC
+	 * Page). The CPU may write to these pages via their host
+	 * physical address while L2 is running, bypassing any
+	 * address-translation-based dirty tracking (e.g. EPT write
+	 * protection).
+	 *
+	 * Mark them dirty on every exit from L2 to prevent them from
+	 * getting out of sync with dirty tracking.
+	 */
+	nested_mark_vmcs12_pages_dirty(vcpu);
+
+	if (vmx->nested.nested_run_pending)
+		return false;
 
 	if (unlikely(vmx->fail)) {
 		pr_info_ratelimited("%s failed vm entry %x\n", __func__,
@@ -7685,9 +8092,9 @@
 		return true;
 	}
 
-	switch (exit_reason) {
+	switch ((u16)exit_reason) {
 	case EXIT_REASON_EXCEPTION_NMI:
-		if (!is_exception(intr_info))
+		if (is_nmi(intr_info))
 			return false;
 		else if (is_page_fault(intr_info))
 			return enable_ept;
@@ -7707,8 +8114,6 @@
 	case EXIT_REASON_TASK_SWITCH:
 		return true;
 	case EXIT_REASON_CPUID:
-		if (kvm_register_read(vcpu, VCPU_REGS_RAX) == 0xa)
-			return false;
 		return true;
 	case EXIT_REASON_HLT:
 		return nested_cpu_has(vmcs12, CPU_BASED_HLT_EXITING);
@@ -7793,6 +8198,9 @@
 		return nested_cpu_has2(vmcs12, SECONDARY_EXEC_XSAVES);
 	case EXIT_REASON_PCOMMIT:
 		return nested_cpu_has2(vmcs12, SECONDARY_EXEC_PCOMMIT);
+	case EXIT_REASON_PML_FULL:
+		/* We don't expose PML support to L1. */
+		return false;
 	default:
 		return true;
 	}
@@ -7804,22 +8212,6 @@
 	*info2 = vmcs_read32(VM_EXIT_INTR_INFO);
 }
 
-static int vmx_create_pml_buffer(struct vcpu_vmx *vmx)
-{
-	struct page *pml_pg;
-
-	pml_pg = alloc_page(GFP_KERNEL | __GFP_ZERO);
-	if (!pml_pg)
-		return -ENOMEM;
-
-	vmx->pml_pg = pml_pg;
-
-	vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg));
-	vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
-
-	return 0;
-}
-
 static void vmx_destroy_pml_buffer(struct vcpu_vmx *vmx)
 {
 	if (vmx->pml_pg) {
@@ -7880,7 +8272,7 @@
 static void vmx_dump_sel(char *name, uint32_t sel)
 {
 	pr_err("%s sel=0x%04x, attr=0x%05x, limit=0x%08x, base=0x%016lx\n",
-	       name, vmcs_read32(sel),
+	       name, vmcs_read16(sel),
 	       vmcs_read32(sel + GUEST_ES_AR_BYTES - GUEST_ES_SELECTOR),
 	       vmcs_read32(sel + GUEST_ES_LIMIT - GUEST_ES_SELECTOR),
 	       vmcs_readl(sel + GUEST_ES_BASE - GUEST_ES_SELECTOR));
@@ -8090,6 +8482,8 @@
 	if ((vectoring_info & VECTORING_INFO_VALID_MASK) &&
 			(exit_reason != EXIT_REASON_EXCEPTION_NMI &&
 			exit_reason != EXIT_REASON_EPT_VIOLATION &&
+			exit_reason != EXIT_REASON_PML_FULL &&
+			exit_reason != EXIT_REASON_APIC_ACCESS &&
 			exit_reason != EXIT_REASON_TASK_SWITCH)) {
 		vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
 		vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV;
@@ -8129,6 +8523,79 @@
 	}
 }
 
+/*
+ * Software based L1D cache flush which is used when microcode providing
+ * the cache control MSR is not loaded.
+ *
+ * The L1D cache is 32 KiB on Nehalem and later microarchitectures, but to
+ * flush it is required to read in 64 KiB because the replacement algorithm
+ * is not exactly LRU. This could be sized at runtime via topology
+ * information but as all relevant affected CPUs have 32KiB L1D cache size
+ * there is no point in doing so.
+ */
+#define L1D_CACHE_ORDER 4
+static void *vmx_l1d_flush_pages;
+
+static void vmx_l1d_flush(struct kvm_vcpu *vcpu)
+{
+	int size = PAGE_SIZE << L1D_CACHE_ORDER;
+
+	/*
+	 * This code is only executed when the the flush mode is 'cond' or
+	 * 'always'
+	 */
+	if (static_branch_likely(&vmx_l1d_flush_cond)) {
+		bool flush_l1d;
+
+		/*
+		 * Clear the per-vcpu flush bit, it gets set again
+		 * either from vcpu_run() or from one of the unsafe
+		 * VMEXIT handlers.
+		 */
+		flush_l1d = vcpu->arch.l1tf_flush_l1d;
+		vcpu->arch.l1tf_flush_l1d = false;
+
+		/*
+		 * Clear the per-cpu flush bit, it gets set again from
+		 * the interrupt handlers.
+		 */
+		flush_l1d |= kvm_get_cpu_l1tf_flush_l1d();
+		kvm_clear_cpu_l1tf_flush_l1d();
+
+		if (!flush_l1d)
+			return;
+	}
+
+	vcpu->stat.l1d_flush++;
+
+	if (static_cpu_has(X86_FEATURE_FLUSH_L1D)) {
+		wrmsrl(MSR_IA32_FLUSH_CMD, L1D_FLUSH);
+		return;
+	}
+
+	asm volatile(
+		/* First ensure the pages are in the TLB */
+		"xorl	%%eax, %%eax\n"
+		".Lpopulate_tlb:\n\t"
+		"movzbl	(%[flush_pages], %%" _ASM_AX "), %%ecx\n\t"
+		"addl	$4096, %%eax\n\t"
+		"cmpl	%%eax, %[size]\n\t"
+		"jne	.Lpopulate_tlb\n\t"
+		"xorl	%%eax, %%eax\n\t"
+		"cpuid\n\t"
+		/* Now fill the cache */
+		"xorl	%%eax, %%eax\n"
+		".Lfill_cache:\n"
+		"movzbl	(%[flush_pages], %%" _ASM_AX "), %%ecx\n\t"
+		"addl	$64, %%eax\n\t"
+		"cmpl	%%eax, %[size]\n\t"
+		"jne	.Lfill_cache\n\t"
+		"lfence\n"
+		:: [flush_pages] "r" (vmx_l1d_flush_pages),
+		    [size] "r" (size)
+		: "eax", "ebx", "ecx", "edx");
+}
+
 static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
 	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
@@ -8149,12 +8616,18 @@
 {
 	u32 sec_exec_control;
 
+	/* Postpone execution until vmcs01 is the current VMCS. */
+	if (is_guest_mode(vcpu)) {
+		to_vmx(vcpu)->nested.change_vmcs01_virtual_x2apic_mode = true;
+		return;
+	}
+
 	/*
 	 * There is not point to enable virtualize x2apic without enable
 	 * apicv
 	 */
 	if (!cpu_has_vmx_virtualize_x2apic_mode() ||
-				!vmx_cpu_uses_apicv(vcpu))
+				!kvm_vcpu_apicv_active(vcpu))
 		return;
 
 	if (!cpu_need_tpr_shadow(vcpu))
@@ -8171,7 +8644,7 @@
 	}
 	vmcs_write32(SECONDARY_VM_EXEC_CONTROL, sec_exec_control);
 
-	vmx_set_msr_bitmap(vcpu);
+	vmx_update_msr_bitmap(vcpu);
 }
 
 static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu, hpa_t hpa)
@@ -8259,10 +8732,9 @@
 	}
 }
 
-static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu)
+static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
 {
-	u64 *eoi_exit_bitmap = vcpu->arch.eoi_exit_bitmap;
-	if (!vmx_cpu_uses_apicv(vcpu))
+	if (!kvm_vcpu_apicv_active(vcpu))
 		return;
 
 	vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
@@ -8287,8 +8759,7 @@
 		kvm_machine_check();
 
 	/* We need to handle NMIs before interrupts are enabled */
-	if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR &&
-	    (exit_intr_info & INTR_INFO_VALID_MASK)) {
+	if (is_nmi(exit_intr_info)) {
 		kvm_before_handle_nmi(&vmx->vcpu);
 		asm("int $2");
 		kvm_after_handle_nmi(&vmx->vcpu);
@@ -8327,13 +8798,13 @@
 			"pushf\n\t"
 			"orl $0x200, (%%" _ASM_SP ")\n\t"
 			__ASM_SIZE(push) " $%c[cs]\n\t"
-			"call *%[entry]\n\t"
+			CALL_NOSPEC
 			:
 #ifdef CONFIG_X86_64
 			[sp]"=&r"(tmp)
 #endif
 			:
-			[entry]"r"(entry),
+			THUNK_TARGET(entry),
 			[ss]"i"(__KERNEL_DS),
 			[cs]"i"(__KERNEL_CS)
 			);
@@ -8341,9 +8812,21 @@
 		local_irq_enable();
 }
 
-static bool vmx_has_high_real_mode_segbase(void)
+static bool vmx_has_emulated_msr(int index)
 {
-	return enable_unrestricted_guest || emulate_invalid_guest_state;
+	switch (index) {
+	case MSR_IA32_SMBASE:
+		/*
+		 * We cannot do SMM unless we can run the guest in big
+		 * real mode.
+		 */
+		return enable_unrestricted_guest || emulate_invalid_guest_state;
+	case MSR_AMD64_VIRT_SPEC_CTRL:
+		/* This is AMD only.  */
+		return false;
+	default:
+		return true;
+	}
 }
 
 static bool vmx_mpx_supported(void)
@@ -8486,13 +8969,39 @@
 			clear_atomic_switch_msr(vmx, msrs[i].msr);
 		else
 			add_atomic_switch_msr(vmx, msrs[i].msr, msrs[i].guest,
-					msrs[i].host);
+					msrs[i].host, false);
+}
+
+u64 __always_inline vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx)
+{
+	u64 guestval, hostval = this_cpu_read(x86_spec_ctrl_current);
+
+	if (!cpu_feature_enabled(X86_FEATURE_MSR_SPEC_CTRL))
+		return 0;
+
+	rdmsrl(MSR_IA32_SPEC_CTRL, guestval);
+
+	/*
+	 * If the guest/host SPEC_CTRL values differ, restore the host value.
+	 *
+	 * For legacy IBRS, the IBRS bit always needs to be written after
+	 * transitioning from a less privileged predictor mode, regardless of
+	 * whether the guest/host values differ.
+	 */
+	if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) ||
+	    guestval != hostval)
+		native_wrmsrl(MSR_IA32_SPEC_CTRL, hostval);
+
+	barrier_nospec();
+
+	return guestval;
 }
 
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	unsigned long debugctlmsr, cr4;
+	u64 spec_ctrl;
 
 	/* Record the guest's net vcpu time for enforced NMI injections. */
 	if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked))
@@ -8533,9 +9042,30 @@
 		vmx_set_interrupt_shadow(vcpu, 0);
 
 	atomic_switch_perf_msrs(vmx);
+
 	debugctlmsr = get_debugctlmsr();
 
+	/*
+	 * If this vCPU has touched SPEC_CTRL, restore the guest's value if
+	 * it's non-zero. Since vmentry is serialising on affected CPUs, there
+	 * is no need to worry about the conditional branch over the wrmsr
+	 * being speculatively taken.
+	 */
+	x86_spec_ctrl_set_guest(vmx->spec_ctrl, 0);
+
+	/* L1D Flush includes CPU buffer clear to mitigate MDS */
+	if (static_branch_unlikely(&vmx_l1d_should_flush))
+		vmx_l1d_flush(vcpu);
+	else if (static_branch_unlikely(&mds_user_clear))
+		mds_clear_cpu_buffers();
+	else if (static_branch_unlikely(&mmio_stale_data_clear) &&
+		 kvm_arch_has_assigned_device(vcpu->kvm))
+		mds_clear_cpu_buffers();
+
 	vmx->__launched = vmx->loaded_vmcs->launched;
+
+	vmx_disable_fb_clear(vmx);
+
 	asm(
 		/* Store host registers */
 		"push %%" _ASM_DX "; push %%" _ASM_BP ";"
@@ -8583,6 +9113,7 @@
 		/* Save guest registers, load host registers, keep flags */
 		"mov %0, %c[wordsize](%%" _ASM_SP ") \n\t"
 		"pop %0 \n\t"
+		"setbe %c[fail](%0)\n\t"
 		"mov %%" _ASM_AX ", %c[rax](%0) \n\t"
 		"mov %%" _ASM_BX ", %c[rbx](%0) \n\t"
 		__ASM_SIZE(pop) " %c[rcx](%0) \n\t"
@@ -8599,12 +9130,23 @@
 		"mov %%r13, %c[r13](%0) \n\t"
 		"mov %%r14, %c[r14](%0) \n\t"
 		"mov %%r15, %c[r15](%0) \n\t"
+		"xor %%r8d,  %%r8d \n\t"
+		"xor %%r9d,  %%r9d \n\t"
+		"xor %%r10d, %%r10d \n\t"
+		"xor %%r11d, %%r11d \n\t"
+		"xor %%r12d, %%r12d \n\t"
+		"xor %%r13d, %%r13d \n\t"
+		"xor %%r14d, %%r14d \n\t"
+		"xor %%r15d, %%r15d \n\t"
 #endif
 		"mov %%cr2, %%" _ASM_AX "   \n\t"
 		"mov %%" _ASM_AX ", %c[cr2](%0) \n\t"
 
+		"xor %%eax, %%eax \n\t"
+		"xor %%ebx, %%ebx \n\t"
+		"xor %%esi, %%esi \n\t"
+		"xor %%edi, %%edi \n\t"
 		"pop  %%" _ASM_BP "; pop  %%" _ASM_DX " \n\t"
-		"setbe %c[fail](%0) \n\t"
 		".pushsection .rodata \n\t"
 		".global vmx_return \n\t"
 		"vmx_return: " _ASM_PTR " 2b \n\t"
@@ -8640,6 +9182,45 @@
 		, "eax", "ebx", "edi", "esi"
 #endif
 	      );
+	/*
+	 * IMPORTANT: RSB filling and SPEC_CTRL handling must be done before
+	 * the first unbalanced RET after vmexit!
+	 *
+	 * For retpoline or IBRS, RSB filling is needed to prevent poisoned RSB
+	 * entries and (in some cases) RSB underflow.
+	 *
+	 * eIBRS has its own protection against poisoned RSB, so it doesn't
+	 * need the RSB filling sequence.  But it does need to be enabled, and a
+	 * single call to retire, before the first unbalanced RET.
+	 *
+	 * So no RETs before vmx_spec_ctrl_restore_host() below.
+	 */
+	vmexit_fill_RSB();
+
+	/* Save this for below */
+	spec_ctrl = vmx_spec_ctrl_restore_host(vmx);
+
+	asm volatile(CLEAR_BRANCH_HISTORY_VMEXIT);
+
+	vmx_enable_fb_clear(vmx);
+
+	/*
+	 * We do not use IBRS in the kernel. If this vCPU has used the
+	 * SPEC_CTRL MSR it may have left it on; save the value and
+	 * turn it off. This is much more efficient than blindly adding
+	 * it to the atomic save/restore list. Especially as the former
+	 * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
+	 *
+	 * For non-nested case:
+	 * If the L01 MSR bitmap does not intercept the MSR, then we need to
+	 * save it.
+	 *
+	 * For nested case:
+	 * If the L02 MSR bitmap does not intercept the MSR, then we need to
+	 * save it.
+	 */
+	if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)))
+		vmx->spec_ctrl = spec_ctrl;
 
 	/* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */
 	if (debugctlmsr)
@@ -8702,6 +9283,22 @@
 	put_cpu();
 }
 
+/*
+ * Ensure that the current vmcs of the logical processor is the
+ * vmcs01 of the vcpu before calling free_nested().
+ */
+static void vmx_free_vcpu_nested(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       int r;
+
+       r = vcpu_load(vcpu);
+       BUG_ON(r);
+       vmx_load_vmcs01(vcpu);
+       free_nested(vmx);
+       vcpu_put(vcpu);
+}
+
 static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -8710,8 +9307,7 @@
 		vmx_destroy_pml_buffer(vmx);
 	free_vpid(vmx->vpid);
 	leave_guest_mode(vcpu);
-	vmx_load_vmcs01(vcpu);
-	free_nested(vmx);
+	vmx_free_vcpu_nested(vcpu);
 	free_loaded_vmcs(vmx->loaded_vmcs);
 	kfree(vmx->guest_msrs);
 	kvm_vcpu_uninit(vcpu);
@@ -8722,6 +9318,7 @@
 {
 	int err;
 	struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+	unsigned long *msr_bitmap;
 	int cpu;
 
 	if (!vmx)
@@ -8733,25 +9330,45 @@
 	if (err)
 		goto free_vcpu;
 
+	err = -ENOMEM;
+
+	/*
+	 * If PML is turned on, failure on enabling PML just results in failure
+	 * of creating the vcpu, therefore we can simplify PML logic (by
+	 * avoiding dealing with cases, such as enabling PML partially on vcpus
+	 * for the guest, etc.
+	 */
+	if (enable_pml) {
+		vmx->pml_pg = alloc_page(GFP_KERNEL | __GFP_ZERO);
+		if (!vmx->pml_pg)
+			goto uninit_vcpu;
+	}
+
 	vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
 	BUILD_BUG_ON(ARRAY_SIZE(vmx_msr_index) * sizeof(vmx->guest_msrs[0])
 		     > PAGE_SIZE);
 
-	err = -ENOMEM;
-	if (!vmx->guest_msrs) {
-		goto uninit_vcpu;
-	}
+	if (!vmx->guest_msrs)
+		goto free_pml;
 
-	vmx->loaded_vmcs = &vmx->vmcs01;
-	vmx->loaded_vmcs->vmcs = alloc_vmcs();
-	if (!vmx->loaded_vmcs->vmcs)
-		goto free_msrs;
 	if (!vmm_exclusive)
 		kvm_cpu_vmxon(__pa(per_cpu(vmxarea, raw_smp_processor_id())));
-	loaded_vmcs_init(vmx->loaded_vmcs);
+	err = alloc_loaded_vmcs(&vmx->vmcs01);
 	if (!vmm_exclusive)
 		kvm_cpu_vmxoff();
+	if (err < 0)
+		goto free_msrs;
+
+	msr_bitmap = vmx->vmcs01.msr_bitmap;
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_FS_BASE, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_GS_BASE, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_KERNEL_GS_BASE, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_CS, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_ESP, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_EIP, MSR_TYPE_RW);
+	vmx->msr_bitmap_mode = 0;
 
+	vmx->loaded_vmcs = &vmx->vmcs01;
 	cpu = get_cpu();
 	vmx_vcpu_load(&vmx->vcpu, cpu);
 	vmx->vcpu.cpu = cpu;
@@ -8775,34 +9392,21 @@
 			goto free_vmcs;
 	}
 
-	if (nested) {
+	if (nested)
 		nested_vmx_setup_ctls_msrs(vmx);
-		vmx->nested.vpid02 = allocate_vpid();
-	}
 
 	vmx->nested.posted_intr_nv = -1;
 	vmx->nested.current_vmptr = -1ull;
 	vmx->nested.current_vmcs12 = NULL;
 
-	/*
-	 * If PML is turned on, failure on enabling PML just results in failure
-	 * of creating the vcpu, therefore we can simplify PML logic (by
-	 * avoiding dealing with cases, such as enabling PML partially on vcpus
-	 * for the guest, etc.
-	 */
-	if (enable_pml) {
-		err = vmx_create_pml_buffer(vmx);
-		if (err)
-			goto free_vmcs;
-	}
-
 	return &vmx->vcpu;
 
 free_vmcs:
-	free_vpid(vmx->nested.vpid02);
 	free_loaded_vmcs(vmx->loaded_vmcs);
 free_msrs:
 	kfree(vmx->guest_msrs);
+free_pml:
+	vmx_destroy_pml_buffer(vmx);
 uninit_vcpu:
 	kvm_vcpu_uninit(&vmx->vcpu);
 free_vcpu:
@@ -8811,6 +9415,37 @@
 	return ERR_PTR(err);
 }
 
+#define L1TF_MSG_SMT "L1TF CPU bug present and SMT on, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/l1tf.html for details.\n"
+#define L1TF_MSG_L1D "L1TF CPU bug present and virtualization mitigation disabled, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/l1tf.html for details.\n"
+
+static int vmx_vm_init(struct kvm *kvm)
+{
+	if (boot_cpu_has(X86_BUG_L1TF) && enable_ept) {
+		switch (l1tf_mitigation) {
+		case L1TF_MITIGATION_OFF:
+		case L1TF_MITIGATION_FLUSH_NOWARN:
+			/* 'I explicitly don't care' is set */
+			break;
+		case L1TF_MITIGATION_FLUSH:
+		case L1TF_MITIGATION_FLUSH_NOSMT:
+		case L1TF_MITIGATION_FULL:
+			/*
+			 * Warn upon starting the first VM in a potentially
+			 * insecure environment.
+			 */
+			if (sched_smt_active())
+				pr_warn_once(L1TF_MSG_SMT);
+			if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_NEVER)
+				pr_warn_once(L1TF_MSG_L1D);
+			break;
+		case L1TF_MITIGATION_FULL_FORCE:
+			/* Flush is enforced */
+			break;
+		}
+	}
+	return 0;
+}
+
 static void __init vmx_check_processor_compat(void *rtn)
 {
 	struct vmcs_config vmcs_conf;
@@ -8932,7 +9567,8 @@
 			best->ebx &= ~bit(X86_FEATURE_INVPCID);
 	}
 
-	vmcs_set_secondary_exec_control(secondary_exec_ctl);
+	if (cpu_has_secondary_exec_ctrls())
+		vmcs_set_secondary_exec_control(secondary_exec_ctl);
 
 	if (static_cpu_has(X86_FEATURE_PCOMMIT) && nested) {
 		if (guest_cpuid_has_pcommit(vcpu))
@@ -9146,9 +9782,26 @@
 {
 	int msr;
 	struct page *page;
-	unsigned long *msr_bitmap;
+	unsigned long *msr_bitmap_l1;
+	unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.vmcs02.msr_bitmap;
+	/*
+	 * pred_cmd & spec_ctrl are trying to verify two things:
+	 *
+	 * 1. L0 gave a permission to L1 to actually passthrough the MSR. This
+	 *    ensures that we do not accidentally generate an L02 MSR bitmap
+	 *    from the L12 MSR bitmap that is too permissive.
+	 * 2. That L1 or L2s have actually used the MSR. This avoids
+	 *    unnecessarily merging of the bitmap if the MSR is unused. This
+	 *    works properly because we only update the L01 MSR bitmap lazily.
+	 *    So even if L0 should pass L1 these MSRs, the L01 bitmap is only
+	 *    updated to reflect this when L1 (or its L2s) actually write to
+	 *    the MSR.
+	 */
+	bool pred_cmd = !msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD);
+	bool spec_ctrl = !msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL);
 
-	if (!nested_cpu_has_virt_x2apic_mode(vmcs12))
+	if (!nested_cpu_has_virt_x2apic_mode(vmcs12) &&
+	    !pred_cmd && !spec_ctrl)
 		return false;
 
 	page = nested_get_page(vcpu, vmcs12->msr_bitmap);
@@ -9156,64 +9809,46 @@
 		WARN_ON(1);
 		return false;
 	}
-	msr_bitmap = (unsigned long *)kmap(page);
-	if (!msr_bitmap) {
-		nested_release_page_clean(page);
-		WARN_ON(1);
-		return false;
-	}
+	msr_bitmap_l1 = (unsigned long *)kmap(page);
+
+	memset(msr_bitmap_l0, 0xff, PAGE_SIZE);
 
 	if (nested_cpu_has_virt_x2apic_mode(vmcs12)) {
 		if (nested_cpu_has_apic_reg_virt(vmcs12))
 			for (msr = 0x800; msr <= 0x8ff; msr++)
 				nested_vmx_disable_intercept_for_msr(
-					msr_bitmap,
-					vmx_msr_bitmap_nested,
+					msr_bitmap_l1, msr_bitmap_l0,
 					msr, MSR_TYPE_R);
-		/* TPR is allowed */
-		nested_vmx_disable_intercept_for_msr(msr_bitmap,
-				vmx_msr_bitmap_nested,
+
+		nested_vmx_disable_intercept_for_msr(
+				msr_bitmap_l1, msr_bitmap_l0,
 				APIC_BASE_MSR + (APIC_TASKPRI >> 4),
 				MSR_TYPE_R | MSR_TYPE_W);
+
 		if (nested_cpu_has_vid(vmcs12)) {
-			/* EOI and self-IPI are allowed */
 			nested_vmx_disable_intercept_for_msr(
-				msr_bitmap,
-				vmx_msr_bitmap_nested,
+				msr_bitmap_l1, msr_bitmap_l0,
 				APIC_BASE_MSR + (APIC_EOI >> 4),
 				MSR_TYPE_W);
 			nested_vmx_disable_intercept_for_msr(
-				msr_bitmap,
-				vmx_msr_bitmap_nested,
+				msr_bitmap_l1, msr_bitmap_l0,
 				APIC_BASE_MSR + (APIC_SELF_IPI >> 4),
 				MSR_TYPE_W);
 		}
-	} else {
-		/*
-		 * Enable reading intercept of all the x2apic
-		 * MSRs. We should not rely on vmcs12 to do any
-		 * optimizations here, it may have been modified
-		 * by L1.
-		 */
-		for (msr = 0x800; msr <= 0x8ff; msr++)
-			__vmx_enable_intercept_for_msr(
-				vmx_msr_bitmap_nested,
-				msr,
-				MSR_TYPE_R);
-
-		__vmx_enable_intercept_for_msr(
-				vmx_msr_bitmap_nested,
-				APIC_BASE_MSR + (APIC_TASKPRI >> 4),
-				MSR_TYPE_W);
-		__vmx_enable_intercept_for_msr(
-				vmx_msr_bitmap_nested,
-				APIC_BASE_MSR + (APIC_EOI >> 4),
-				MSR_TYPE_W);
-		__vmx_enable_intercept_for_msr(
-				vmx_msr_bitmap_nested,
-				APIC_BASE_MSR + (APIC_SELF_IPI >> 4),
-				MSR_TYPE_W);
 	}
+
+	if (spec_ctrl)
+		nested_vmx_disable_intercept_for_msr(
+					msr_bitmap_l1, msr_bitmap_l0,
+					MSR_IA32_SPEC_CTRL,
+					MSR_TYPE_R | MSR_TYPE_W);
+
+	if (pred_cmd)
+		nested_vmx_disable_intercept_for_msr(
+					msr_bitmap_l1, msr_bitmap_l0,
+					MSR_IA32_PRED_CMD,
+					MSR_TYPE_W);
+
 	kunmap(page);
 	nested_release_page_clean(page);
 
@@ -9624,13 +10259,18 @@
 		vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
 				page_to_phys(vmx->nested.virtual_apic_page));
 		vmcs_write32(TPR_THRESHOLD, vmcs12->tpr_threshold);
+	} else {
+#ifdef CONFIG_X86_64
+		exec_control |= CPU_BASED_CR8_LOAD_EXITING |
+				CPU_BASED_CR8_STORE_EXITING;
+#endif
 	}
 
 	if (cpu_has_vmx_msr_bitmap() &&
-	    exec_control & CPU_BASED_USE_MSR_BITMAPS) {
-		nested_vmx_merge_msr_bitmap(vcpu, vmcs12);
-		/* MSR_BITMAP will be set by following vmx_set_efer. */
-	} else
+	    exec_control & CPU_BASED_USE_MSR_BITMAPS &&
+	    nested_vmx_merge_msr_bitmap(vcpu, vmcs12))
+		; /* MSR_BITMAP will be set by following vmx_set_efer. */
+	else
 		exec_control &= ~CPU_BASED_USE_MSR_BITMAPS;
 
 	/*
@@ -9682,6 +10322,9 @@
 	else
 		vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
 
+	if (cpu_has_vmx_msr_bitmap())
+		vmcs_write64(MSR_BITMAP, __pa(vmx->nested.vmcs02.msr_bitmap));
+
 	if (enable_vpid) {
 		/*
 		 * There is no direct mapping between vpid02 and vpid12, the
@@ -9704,6 +10347,18 @@
 
 	}
 
+	if (enable_pml) {
+		/*
+		 * Conceptually we want to copy the PML address and index from
+		 * vmcs01 here, and then back to vmcs01 on nested vmexit. But,
+		 * since we always flush the log on each vmexit, this happens
+		 * to be equivalent to simply resetting the fields in vmcs02.
+		 */
+		ASSERT(vmx->pml_pg);
+		vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg));
+		vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+	}
+
 	if (nested_cpu_has_ept(vmcs12)) {
 		kvm_mmu_unload(vcpu);
 		nested_ept_init_mmu_context(vcpu);
@@ -9762,7 +10417,6 @@
 	struct vmcs12 *vmcs12;
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	int cpu;
-	struct loaded_vmcs *vmcs02;
 	bool ia32e;
 	u32 msr_entry_idx;
 
@@ -9773,6 +10427,8 @@
 	skip_emulated_instruction(vcpu);
 	vmcs12 = get_vmcs12(vcpu);
 
+	ia32e = !!(vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE);
+
 	if (enable_shadow_vmcs)
 		copy_shadow_to_vmcs12(vmx);
 
@@ -9858,6 +10514,13 @@
 		return 1;
 	}
 
+	if ((vmcs12->guest_cr0 & (X86_CR0_PG | X86_CR0_PE)) == X86_CR0_PG)
+		return 1;
+
+	if ((ia32e && !(vmcs12->guest_cr4 & X86_CR4_PAE)) ||
+	    (ia32e && !(vmcs12->guest_cr0 & X86_CR0_PG)))
+		return 1;
+
 	/*
 	 * If the load IA32_EFER VM-entry control is 1, the following checks
 	 * are performed on the field for the IA32_EFER MSR:
@@ -9868,7 +10531,6 @@
 	 *   CR0.PG) is 1.
 	 */
 	if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER) {
-		ia32e = (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) != 0;
 		if (!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer) ||
 		    ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA) ||
 		    ((vmcs12->guest_cr0 & X86_CR0_PG) &&
@@ -9902,10 +10564,6 @@
 	 * the nested entry.
 	 */
 
-	vmcs02 = nested_get_current_vmcs02(vmx);
-	if (!vmcs02)
-		return -ENOMEM;
-
 	enter_guest_mode(vcpu);
 
 	vmx->nested.vmcs01_tsc_offset = vmcs_read64(TSC_OFFSET);
@@ -9914,7 +10572,7 @@
 		vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
 
 	cpu = get_cpu();
-	vmx->loaded_vmcs = vmcs02;
+	vmx->loaded_vmcs = &vmx->nested.vmcs02;
 	vmx_vcpu_put(vcpu);
 	vmx_vcpu_load(vcpu, cpu);
 	vcpu->cpu = cpu;
@@ -9937,6 +10595,9 @@
 
 	vmcs12->launch_state = 1;
 
+	/* Hide L1D cache contents from the nested guest.  */
+	vmx->vcpu.arch.l1tf_flush_l1d = true;
+
 	if (vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT)
 		return kvm_vcpu_halt(vcpu);
 
@@ -10066,7 +10727,8 @@
 		return 0;
 	}
 
-	return vmx_complete_nested_posted_interrupt(vcpu);
+	vmx_complete_nested_posted_interrupt(vcpu);
+	return 0;
 }
 
 static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
@@ -10197,7 +10859,7 @@
 	vmcs12->guest_sysenter_cs = vmcs_read32(GUEST_SYSENTER_CS);
 	vmcs12->guest_sysenter_esp = vmcs_readl(GUEST_SYSENTER_ESP);
 	vmcs12->guest_sysenter_eip = vmcs_readl(GUEST_SYSENTER_EIP);
-	if (vmx_mpx_supported())
+	if (kvm_mpx_supported())
 		vmcs12->guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
 	if (nested_cpu_has_xsaves(vmcs12))
 		vmcs12->xss_exit_bitmap = vmcs_read64(XSS_EXIT_BITMAP);
@@ -10284,7 +10946,7 @@
 	 * (KVM doesn't change it)- no reason to call set_cr4_guest_host_mask();
 	 */
 	vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK);
-	kvm_set_cr4(vcpu, vmcs12->host_cr4);
+	vmx_set_cr4(vcpu, vmcs12->host_cr4);
 
 	nested_ept_uninit_mmu_context(vcpu);
 
@@ -10309,6 +10971,8 @@
 	vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->host_ia32_sysenter_eip);
 	vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base);
 	vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base);
+	vmcs_write32(GUEST_IDTR_LIMIT, 0xFFFF);
+	vmcs_write32(GUEST_GDTR_LIMIT, 0xFFFF);
 
 	/* If not VM_EXIT_CLEAR_BNDCFGS, the L2 value propagates to L1.  */
 	if (vmcs12->vm_exit_controls & VM_EXIT_CLEAR_BNDCFGS)
@@ -10372,7 +11036,7 @@
 	vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 
 	if (cpu_has_vmx_msr_bitmap())
-		vmx_set_msr_bitmap(vcpu);
+		vmx_update_msr_bitmap(vcpu);
 
 	if (nested_vmx_load_msr(vcpu, vmcs12->vm_exit_msr_load_addr,
 				vmcs12->vm_exit_msr_load_count))
@@ -10423,15 +11087,17 @@
 	vm_exit_controls_init(vmx, vmcs_read32(VM_EXIT_CONTROLS));
 	vmx_segment_cache_clear(vmx);
 
-	/* if no vmcs02 cache requested, remove the one we used */
-	if (VMCS02_POOL_SIZE == 0)
-		nested_free_vmcs02(vmx, vmx->nested.current_vmptr);
-
 	load_vmcs12_host_state(vcpu, vmcs12);
 
 	/* Update TSC_OFFSET if TSC was changed while L2 ran */
 	vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
 
+	if (vmx->nested.change_vmcs01_virtual_x2apic_mode) {
+		vmx->nested.change_vmcs01_virtual_x2apic_mode = false;
+		vmx_set_virtual_x2apic_mode(vcpu,
+				vcpu->arch.apic_base & X2APIC_ENABLE);
+	}
+
 	/* This is needed for same reason as it was needed in prepare_vmcs02 */
 	vmx->host_rsp = 0;
 
@@ -10479,8 +11145,10 @@
  */
 static void vmx_leave_nested(struct kvm_vcpu *vcpu)
 {
-	if (is_guest_mode(vcpu))
+	if (is_guest_mode(vcpu)) {
+		to_vmx(vcpu)->nested.nested_run_pending = 0;
 		nested_vmx_vmexit(vcpu, -1, 0, 0);
+	}
 	free_nested(to_vmx(vcpu));
 }
 
@@ -10503,11 +11171,71 @@
 		to_vmx(vcpu)->nested.sync_shadow_vmcs = true;
 }
 
+static int vmx_check_intercept_io(struct kvm_vcpu *vcpu,
+				  struct x86_instruction_info *info)
+{
+	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+	unsigned short port;
+	bool intercept;
+	int size;
+
+	if (info->intercept == x86_intercept_in ||
+	    info->intercept == x86_intercept_ins) {
+		port = info->src_val;
+		size = info->dst_bytes;
+	} else {
+		port = info->dst_val;
+		size = info->src_bytes;
+	}
+
+	/*
+	 * If the 'use IO bitmaps' VM-execution control is 0, IO instruction
+	 * VM-exits depend on the 'unconditional IO exiting' VM-execution
+	 * control.
+	 *
+	 * Otherwise, IO instruction VM-exits are controlled by the IO bitmaps.
+	 */
+	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
+		intercept = nested_cpu_has(vmcs12,
+					   CPU_BASED_UNCOND_IO_EXITING);
+	else
+		intercept = nested_vmx_check_io_bitmaps(vcpu, port, size);
+
+	return intercept ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE;
+}
+
 static int vmx_check_intercept(struct kvm_vcpu *vcpu,
 			       struct x86_instruction_info *info,
 			       enum x86_intercept_stage stage)
 {
-	return X86EMUL_CONTINUE;
+	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+	struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
+
+	switch (info->intercept) {
+	/*
+	 * RDPID causes #UD if disabled through secondary execution controls.
+	 * Because it is marked as EmulateOnUD, we need to intercept it here.
+	 */
+	case x86_intercept_rdtscp:
+		if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
+			ctxt->exception.vector = UD_VECTOR;
+			ctxt->exception.error_code_valid = false;
+			return X86EMUL_PROPAGATE_FAULT;
+		}
+		break;
+
+	case x86_intercept_in:
+	case x86_intercept_ins:
+	case x86_intercept_out:
+	case x86_intercept_outs:
+		return vmx_check_intercept_io(vcpu, info);
+
+	/* TODO: check more intercepts... */
+	default:
+		break;
+	}
+
+	return X86EMUL_UNHANDLEABLE;
 }
 
 static void vmx_sched_in(struct kvm_vcpu *vcpu, int cpu)
@@ -10541,6 +11269,40 @@
 	kvm_mmu_clear_dirty_pt_masked(kvm, memslot, offset, mask);
 }
 
+static void __pi_post_block(struct kvm_vcpu *vcpu)
+{
+	struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
+	struct pi_desc old, new;
+	unsigned int dest;
+
+	do {
+		old.control = new.control = pi_desc->control;
+		WARN(old.nv != POSTED_INTR_WAKEUP_VECTOR,
+		     "Wakeup handler not enabled while the VCPU is blocked\n");
+
+		dest = cpu_physical_id(vcpu->cpu);
+
+		if (x2apic_enabled())
+			new.ndst = dest;
+		else
+			new.ndst = (dest << 8) & 0xFF00;
+
+		/* Allow posting non-urgent interrupts */
+		new.sn = 0;
+
+		/* set 'NV' to 'notification vector' */
+		new.nv = POSTED_INTR_VECTOR;
+	} while (cmpxchg64(&pi_desc->control, old.control,
+			new.control) != old.control);
+
+	if (!WARN_ON_ONCE(vcpu->pre_pcpu == -1)) {
+		spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
+		list_del(&vcpu->blocked_vcpu_list);
+		spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
+		vcpu->pre_pcpu = -1;
+	}
+}
+
 /*
  * This routine does the following things for vCPU which is going
  * to be blocked if VT-d PI is enabled.
@@ -10554,9 +11316,8 @@
  *   this case, return 1, otherwise, return 0.
  *
  */
-static int vmx_pre_block(struct kvm_vcpu *vcpu)
+static int pi_pre_block(struct kvm_vcpu *vcpu)
 {
-	unsigned long flags;
 	unsigned int dest;
 	struct pi_desc old, new;
 	struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
@@ -10565,34 +11326,20 @@
 		!irq_remapping_cap(IRQ_POSTING_CAP))
 		return 0;
 
-	vcpu->pre_pcpu = vcpu->cpu;
-	spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock,
-			  vcpu->pre_pcpu), flags);
-	list_add_tail(&vcpu->blocked_vcpu_list,
-		      &per_cpu(blocked_vcpu_on_cpu,
-		      vcpu->pre_pcpu));
-	spin_unlock_irqrestore(&per_cpu(blocked_vcpu_on_cpu_lock,
-			       vcpu->pre_pcpu), flags);
+	WARN_ON(irqs_disabled());
+	local_irq_disable();
+	if (!WARN_ON_ONCE(vcpu->pre_pcpu != -1)) {
+		vcpu->pre_pcpu = vcpu->cpu;
+		spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
+		list_add_tail(&vcpu->blocked_vcpu_list,
+			      &per_cpu(blocked_vcpu_on_cpu,
+				       vcpu->pre_pcpu));
+		spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
+	}
 
 	do {
 		old.control = new.control = pi_desc->control;
 
-		/*
-		 * We should not block the vCPU if
-		 * an interrupt is posted for it.
-		 */
-		if (pi_test_on(pi_desc) == 1) {
-			spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock,
-					  vcpu->pre_pcpu), flags);
-			list_del(&vcpu->blocked_vcpu_list);
-			spin_unlock_irqrestore(
-					&per_cpu(blocked_vcpu_on_cpu_lock,
-					vcpu->pre_pcpu), flags);
-			vcpu->pre_pcpu = -1;
-
-			return 1;
-		}
-
 		WARN((pi_desc->sn == 1),
 		     "Warning: SN field of posted-interrupts "
 		     "is set before blocking\n");
@@ -10614,51 +11361,39 @@
 
 		/* set 'NV' to 'wakeup vector' */
 		new.nv = POSTED_INTR_WAKEUP_VECTOR;
-	} while (cmpxchg(&pi_desc->control, old.control,
-			new.control) != old.control);
+	} while (cmpxchg64(&pi_desc->control, old.control,
+			   new.control) != old.control);
 
-	return 0;
+	/* We should not block the vCPU if an interrupt is posted for it.  */
+	if (pi_test_on(pi_desc) == 1)
+		__pi_post_block(vcpu);
+
+	local_irq_enable();
+	return (vcpu->pre_pcpu == -1);
 }
 
-static void vmx_post_block(struct kvm_vcpu *vcpu)
+static int vmx_pre_block(struct kvm_vcpu *vcpu)
 {
-	struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
-	struct pi_desc old, new;
-	unsigned int dest;
-	unsigned long flags;
-
-	if (!kvm_arch_has_assigned_device(vcpu->kvm) ||
-		!irq_remapping_cap(IRQ_POSTING_CAP))
-		return;
-
-	do {
-		old.control = new.control = pi_desc->control;
-
-		dest = cpu_physical_id(vcpu->cpu);
+	if (pi_pre_block(vcpu))
+		return 1;
 
-		if (x2apic_enabled())
-			new.ndst = dest;
-		else
-			new.ndst = (dest << 8) & 0xFF00;
+	return 0;
+}
 
-		/* Allow posting non-urgent interrupts */
-		new.sn = 0;
+static void pi_post_block(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->pre_pcpu == -1)
+		return;
 
-		/* set 'NV' to 'notification vector' */
-		new.nv = POSTED_INTR_VECTOR;
-	} while (cmpxchg(&pi_desc->control, old.control,
-			new.control) != old.control);
+	WARN_ON(irqs_disabled());
+	local_irq_disable();
+	__pi_post_block(vcpu);
+	local_irq_enable();
+}
 
-	if(vcpu->pre_pcpu != -1) {
-		spin_lock_irqsave(
-			&per_cpu(blocked_vcpu_on_cpu_lock,
-			vcpu->pre_pcpu), flags);
-		list_del(&vcpu->blocked_vcpu_list);
-		spin_unlock_irqrestore(
-			&per_cpu(blocked_vcpu_on_cpu_lock,
-			vcpu->pre_pcpu), flags);
-		vcpu->pre_pcpu = -1;
-	}
+static void vmx_post_block(struct kvm_vcpu *vcpu)
+{
+	pi_post_block(vcpu);
 }
 
 /*
@@ -10678,7 +11413,7 @@
 	struct kvm_lapic_irq irq;
 	struct kvm_vcpu *vcpu;
 	struct vcpu_data vcpu_info;
-	int idx, ret = -EINVAL;
+	int idx, ret = 0;
 
 	if (!kvm_arch_has_assigned_device(kvm) ||
 		!irq_remapping_cap(IRQ_POSTING_CAP))
@@ -10686,7 +11421,12 @@
 
 	idx = srcu_read_lock(&kvm->irq_srcu);
 	irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
-	BUG_ON(guest_irq >= irq_rt->nr_rt_entries);
+	if (guest_irq >= irq_rt->nr_rt_entries ||
+	    hlist_empty(&irq_rt->map[guest_irq])) {
+		pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n",
+			     guest_irq, irq_rt->nr_rt_entries);
+		goto out;
+	}
 
 	hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
 		if (e->type != KVM_IRQ_ROUTING_MSI)
@@ -10716,12 +11456,8 @@
 
 		if (set)
 			ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
-		else {
-			/* suppress notification event before unposting */
-			pi_set_sn(vcpu_to_pi_desc(vcpu));
+		else
 			ret = irq_set_vcpu_affinity(host_irq, NULL);
-			pi_clear_sn(vcpu_to_pi_desc(vcpu));
-		}
 
 		if (ret < 0) {
 			printk(KERN_INFO "%s: failed to update PI IRTE\n",
@@ -10745,7 +11481,9 @@
 	.hardware_enable = hardware_enable,
 	.hardware_disable = hardware_disable,
 	.cpu_has_accelerated_tpr = report_flexpriority,
-	.cpu_has_high_real_mode_segbase = vmx_has_high_real_mode_segbase,
+	.has_emulated_msr = vmx_has_emulated_msr,
+
+	.vm_init = vmx_vm_init,
 
 	.vcpu_create = vmx_create_vcpu,
 	.vcpu_free = vmx_free_vcpu,
@@ -10756,6 +11494,7 @@
 	.vcpu_put = vmx_vcpu_put,
 
 	.update_bp_intercept = update_exception_bitmap,
+	.get_msr_feature = vmx_get_msr_feature,
 	.get_msr = vmx_get_msr,
 	.set_msr = vmx_set_msr,
 	.get_segment_base = vmx_get_segment_base,
@@ -10805,7 +11544,8 @@
 	.update_cr8_intercept = update_cr8_intercept,
 	.set_virtual_x2apic_mode = vmx_set_virtual_x2apic_mode,
 	.set_apic_access_page_addr = vmx_set_apic_access_page_addr,
-	.cpu_uses_apicv = vmx_cpu_uses_apicv,
+	.get_enable_apicv = vmx_get_enable_apicv,
+	.refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
 	.load_eoi_exitmap = vmx_load_eoi_exitmap,
 	.hwapic_irr_update = vmx_hwapic_irr_update,
 	.hwapic_isr_update = vmx_hwapic_isr_update,
@@ -10858,30 +11598,61 @@
 	.update_pi_irte = vmx_update_pi_irte,
 };
 
-static int __init vmx_init(void)
+static void vmx_cleanup_l1d_flush(void)
 {
-	int r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx),
-                     __alignof__(struct vcpu_vmx), THIS_MODULE);
-	if (r)
-		return r;
+	if (vmx_l1d_flush_pages) {
+		free_pages((unsigned long)vmx_l1d_flush_pages, L1D_CACHE_ORDER);
+		vmx_l1d_flush_pages = NULL;
+	}
+	/* Restore state so sysfs ignores VMX */
+	l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_AUTO;
+}
 
+static void vmx_exit(void)
+{
 #ifdef CONFIG_KEXEC_CORE
-	rcu_assign_pointer(crash_vmclear_loaded_vmcss,
-			   crash_vmclear_local_loaded_vmcss);
+	RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL);
+	synchronize_rcu();
 #endif
 
-	return 0;
+	kvm_exit();
+
+	vmx_cleanup_l1d_flush();
 }
+module_exit(vmx_exit);
 
-static void __exit vmx_exit(void)
+static int __init vmx_init(void)
 {
+	int r;
+
+	r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx),
+		     __alignof__(struct vcpu_vmx), THIS_MODULE);
+	if (r)
+		return r;
+
+	/*
+	 * Must be called after kvm_init() so enable_ept is properly set
+	 * up. Hand the parameter mitigation value in which was stored in
+	 * the pre module init parser. If no parameter was given, it will
+	 * contain 'auto' which will be turned into the default 'cond'
+	 * mitigation mode.
+	 */
+	if (boot_cpu_has(X86_BUG_L1TF)) {
+		r = vmx_setup_l1d_flush(vmentry_l1d_flush_param);
+		if (r) {
+			vmx_exit();
+			return r;
+		}
+	}
+
+	vmx_setup_fb_clear_ctrl();
+
 #ifdef CONFIG_KEXEC_CORE
-	RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL);
-	synchronize_rcu();
+	rcu_assign_pointer(crash_vmclear_loaded_vmcss,
+			   crash_vmclear_local_loaded_vmcss);
 #endif
 
-	kvm_exit();
+	return 0;
 }
 
 module_init(vmx_init)
-module_exit(vmx_exit)
--- linux-4.4.0.orig/arch/x86/kvm/x86.c
+++ linux-4.4.0/arch/x86/kvm/x86.c
@@ -53,6 +53,8 @@
 #include <linux/pvclock_gtod.h>
 #include <linux/kvm_irqfd.h>
 #include <linux/irqbypass.h>
+#include <linux/nospec.h>
+#include <asm/nospec-branch.h>
 #include <trace/events/kvm.h>
 
 #define CREATE_TRACE_POINTS
@@ -169,6 +171,7 @@
 	{ "insn_emulation_fail", VCPU_STAT(insn_emulation_fail) },
 	{ "irq_injections", VCPU_STAT(irq_injections) },
 	{ "nmi_injections", VCPU_STAT(nmi_injections) },
+	{ "l1d_flush", VCPU_STAT(l1d_flush) },
 	{ "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped) },
 	{ "mmu_pte_write", VM_STAT(mmu_pte_write) },
 	{ "mmu_pte_updated", VM_STAT(mmu_pte_updated) },
@@ -184,6 +187,8 @@
 
 u64 __read_mostly host_xcr0;
 
+extern bool gds_ucode_mitigated(void);
+
 static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt);
 
 static inline void kvm_async_pf_hash_reset(struct kvm_vcpu *vcpu)
@@ -199,7 +204,18 @@
 	struct kvm_shared_msrs *locals
 		= container_of(urn, struct kvm_shared_msrs, urn);
 	struct kvm_shared_msr_values *values;
+	unsigned long flags;
 
+	/*
+	 * Disabling irqs at this point since the following code could be
+	 * interrupted and executed through kvm_arch_hardware_disable()
+	 */
+	local_irq_save(flags);
+	if (locals->registered) {
+		locals->registered = false;
+		user_return_notifier_unregister(urn);
+	}
+	local_irq_restore(flags);
 	for (slot = 0; slot < shared_msrs_global.nr; ++slot) {
 		values = &locals->values[slot];
 		if (values->host != values->curr) {
@@ -207,8 +223,6 @@
 			values->curr = values->host;
 		}
 	}
-	locals->registered = false;
-	user_return_notifier_unregister(urn);
 }
 
 static void shared_msr_update(unsigned slot, u32 msr)
@@ -251,13 +265,14 @@
 	struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu);
 	int err;
 
-	if (((value ^ smsr->values[slot].curr) & mask) == 0)
+	value = (value & mask) | (smsr->values[slot].host & ~mask);
+	if (value == smsr->values[slot].curr)
 		return 0;
-	smsr->values[slot].curr = value;
 	err = wrmsrl_safe(shared_msrs_global.msrs[slot], value);
 	if (err)
 		return 1;
 
+	smsr->values[slot].curr = value;
 	if (!smsr->registered) {
 		smsr->urn.on_user_return = kvm_on_user_return;
 		user_return_notifier_register(&smsr->urn);
@@ -514,8 +529,14 @@
 				       data, offset, len, access);
 }
 
+static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu)
+{
+	return rsvd_bits(cpuid_maxphyaddr(vcpu), 63) | rsvd_bits(5, 8) |
+	       rsvd_bits(1, 2);
+}
+
 /*
- * Load the pae pdptrs.  Return true is they are all valid.
+ * Load the pae pdptrs.  Return 1 if they are all valid, 0 otherwise.
  */
 int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3)
 {
@@ -534,8 +555,7 @@
 	}
 	for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
 		if (is_present_gpte(pdpte[i]) &&
-		    (pdpte[i] &
-		     vcpu->arch.mmu.guest_rsvd_check.rsvd_bits_mask[0][2])) {
+		    (pdpte[i] & pdptr_rsvd_bits(vcpu))) {
 			ret = 0;
 			goto out;
 		}
@@ -561,7 +581,7 @@
 	gfn_t gfn;
 	int r;
 
-	if (is_long_mode(vcpu) || !is_pae(vcpu))
+	if (is_long_mode(vcpu) || !is_pae(vcpu) || !is_paging(vcpu))
 		return false;
 
 	if (!test_bit(VCPU_EXREG_PDPTR,
@@ -697,7 +717,6 @@
 		if ((xcr0 & XFEATURE_MASK_AVX512) != XFEATURE_MASK_AVX512)
 			return 1;
 	}
-	kvm_put_guest_xcr0(vcpu);
 	vcpu->arch.xcr0 = xcr0;
 
 	if ((xcr0 ^ old_xcr0) & XFEATURE_MASK_EXTEND)
@@ -751,7 +770,8 @@
 			return 1;
 
 		/* PCID can not be enabled when cr3[11:0]!=000H or EFER.LMA=0 */
-		if ((kvm_read_cr3(vcpu) & X86_CR3_PCID_MASK) || !is_long_mode(vcpu))
+		if ((kvm_read_cr3(vcpu) & X86_CR3_PCID_ASID_MASK) ||
+		    !is_long_mode(vcpu))
 			return 1;
 	}
 
@@ -858,9 +878,11 @@
 
 static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
 {
+	size_t size = ARRAY_SIZE(vcpu->arch.db);
+
 	switch (dr) {
 	case 0 ... 3:
-		vcpu->arch.db[dr] = val;
+		vcpu->arch.db[array_index_nospec(dr, size)] = val;
 		if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
 			vcpu->arch.eff_db[dr] = val;
 		break;
@@ -897,9 +919,11 @@
 
 int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
 {
+	size_t size = ARRAY_SIZE(vcpu->arch.db);
+
 	switch (dr) {
 	case 0 ... 3:
-		*val = vcpu->arch.db[dr];
+		*val = vcpu->arch.db[array_index_nospec(dr, size)];
 		break;
 	case 4:
 		/* fall through */
@@ -951,7 +975,8 @@
 	MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
 	MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
-	MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS
+	MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS, MSR_TSC_AUX,
+	MSR_IA32_ARCH_CAPABILITIES, MSR_IA32_SPEC_CTRL,
 };
 
 static unsigned num_msrs_to_save;
@@ -966,6 +991,8 @@
 	HV_X64_MSR_RESET,
 	HV_X64_MSR_VP_INDEX,
 	HV_X64_MSR_VP_RUNTIME,
+	HV_X64_MSR_SCONTROL,
+	HV_X64_MSR_STIMER0_CONFIG,
 	HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
 	MSR_KVM_PV_EOI_EN,
 
@@ -975,15 +1002,125 @@
 	MSR_IA32_MCG_STATUS,
 	MSR_IA32_MCG_CTL,
 	MSR_IA32_SMBASE,
+	MSR_AMD64_VIRT_SPEC_CTRL,
 };
 
 static unsigned num_emulated_msrs;
 
-bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
+/*
+ * List of msr numbers which are used to expose MSR-based features that
+ * can be used by a hypervisor to validate requested CPU features.
+ */
+static u32 msr_based_features[] = {
+	MSR_F10H_DECFG,
+	MSR_IA32_UCODE_REV,
+	MSR_IA32_ARCH_CAPABILITIES,
+};
+
+static unsigned int num_msr_based_features;
+
+u64 kvm_get_arch_capabilities(void)
 {
-	if (efer & efer_reserved_bits)
-		return false;
+	u64 data;
+
+	rdmsrl_safe(MSR_IA32_ARCH_CAPABILITIES, &data);
+
+	/*
+	 * If nx_huge_pages is enabled, KVM's shadow paging will ensure that
+	 * the nested hypervisor runs with NX huge pages.  If it is not,
+	 * L1 is anyway vulnerable to ITLB_MULTIHIT explots from other
+	 * L1 guests, so it need not worry about its own (L2) guests.
+	 */
+	data |= ARCH_CAP_PSCHANGE_MC_NO;
+
+	/*
+	 * If we're doing cache flushes (either "always" or "cond")
+	 * we will do one whenever the guest does a vmlaunch/vmresume.
+	 * If an outer hypervisor is doing the cache flush for us
+	 * (VMENTER_L1D_FLUSH_NESTED_VM), we can safely pass that
+	 * capability to the guest too, and if EPT is disabled we're not
+	 * vulnerable.  Overall, only VMENTER_L1D_FLUSH_NEVER will
+	 * require a nested hypervisor to do a flush of its own.
+	 */
+	if (l1tf_vmx_mitigation != VMENTER_L1D_FLUSH_NEVER)
+		data |= ARCH_CAP_SKIP_VMENTRY_L1DFLUSH;
+
+	if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN))
+		data |= ARCH_CAP_RDCL_NO;
+	if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS))
+		data |= ARCH_CAP_SSB_NO;
+	if (!boot_cpu_has_bug(X86_BUG_MDS))
+		data |= ARCH_CAP_MDS_NO;
+
+	/*
+	 * On TAA affected systems, export MDS_NO=0 when:
+	 *	- TSX is enabled on the host, i.e. X86_FEATURE_RTM=1.
+	 *	- Updated microcode is present. This is detected by
+	 *	  the presence of ARCH_CAP_TSX_CTRL_MSR and ensures
+	 *	  that VERW clears CPU buffers.
+	 *
+	 * When MDS_NO=0 is exported, guests deploy clear CPU buffer
+	 * mitigation and don't complain:
+	 *
+	 *	"Vulnerable: Clear CPU buffers attempted, no microcode"
+	 *
+	 * If TSX is disabled on the system, guests are also mitigated against
+	 * TAA and clear CPU buffer mitigation is not required for guests.
+	 */
+	if (!boot_cpu_has(X86_FEATURE_RTM))
+		data &= ~ARCH_CAP_TAA_NO;
+	else if (!boot_cpu_has_bug(X86_BUG_TAA))
+		data |= ARCH_CAP_TAA_NO;
+	else if (data & ARCH_CAP_TSX_CTRL_MSR)
+		data &= ~ARCH_CAP_MDS_NO;
+
+	/* KVM does not emulate MSR_IA32_TSX_CTRL.  */
+	data &= ~ARCH_CAP_TSX_CTRL_MSR;
+
+	/* Guests don't need to know "Fill buffer clear control" exists */
+	data &= ~ARCH_CAP_FB_CLEAR_CTRL;
+
+	if (!boot_cpu_has_bug(X86_BUG_GDS) || gds_ucode_mitigated())
+		data |= ARCH_CAP_GDS_NO;
+
+	return data;
+}
+
+EXPORT_SYMBOL_GPL(kvm_get_arch_capabilities);
 
+static int kvm_get_msr_feature(struct kvm_msr_entry *msr)
+{
+	switch (msr->index) {
+	case MSR_IA32_ARCH_CAPABILITIES:
+		msr->data = kvm_get_arch_capabilities();
+		break;
+	case MSR_IA32_UCODE_REV:
+		rdmsrl_safe(msr->index, &msr->data);
+		break;
+	default:
+		if (kvm_x86_ops->get_msr_feature(msr))
+			return 1;
+	}
+	return 0;
+}
+
+static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
+{
+	struct kvm_msr_entry msr;
+	int r;
+
+	msr.index = index;
+	r = kvm_get_msr_feature(&msr);
+	if (r)
+		return r;
+
+	*data = msr.data;
+
+	return 0;
+}
+
+static bool __kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
 	if (efer & EFER_FFXSR) {
 		struct kvm_cpuid_entry2 *feat;
 
@@ -1001,19 +1138,33 @@
 	}
 
 	return true;
+
+}
+bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+	if (efer & efer_reserved_bits)
+		return false;
+
+	return __kvm_valid_efer(vcpu, efer);
 }
 EXPORT_SYMBOL_GPL(kvm_valid_efer);
 
-static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
+static int set_efer(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
 	u64 old_efer = vcpu->arch.efer;
+	u64 efer = msr_info->data;
 
-	if (!kvm_valid_efer(vcpu, efer))
+	if (efer & efer_reserved_bits)
 		return 1;
 
-	if (is_paging(vcpu)
-	    && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME))
-		return 1;
+	if (!msr_info->host_initiated) {
+		if (!__kvm_valid_efer(vcpu, efer))
+			return 1;
+
+		if (is_paging(vcpu) &&
+		    (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME))
+			return 1;
+	}
 
 	efer &= ~EFER_LMA;
 	efer |= vcpu->arch.efer & EFER_LMA;
@@ -1241,12 +1392,6 @@
 static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz);
 static unsigned long max_tsc_khz;
 
-static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
-{
-	return pvclock_scale_delta(nsec, vcpu->arch.virtual_tsc_mult,
-				   vcpu->arch.virtual_tsc_shift);
-}
-
 static u32 adjust_tsc_khz(u32 khz, s32 ppm)
 {
 	u64 v = (u64)khz * (1000000 + ppm);
@@ -1271,7 +1416,7 @@
 			vcpu->arch.tsc_always_catchup = 1;
 			return 0;
 		} else {
-			WARN(1, "user requested TSC rate below hardware speed\n");
+			pr_warn_ratelimited("user requested TSC rate below hardware speed\n");
 			return -1;
 		}
 	}
@@ -1281,8 +1426,8 @@
 				user_tsc_khz, tsc_khz);
 
 	if (ratio == 0 || ratio >= kvm_max_tsc_scaling_ratio) {
-		WARN_ONCE(1, "Invalid TSC scaling ratio - virtual-tsc-khz=%u\n",
-			  user_tsc_khz);
+		pr_warn_ratelimited("Invalid TSC scaling ratio - virtual-tsc-khz=%u\n",
+			            user_tsc_khz);
 		return -1;
 	}
 
@@ -1804,6 +1949,9 @@
 	 */
 	BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0);
 
+	if (guest_hv_clock.version & 1)
+		++guest_hv_clock.version;  /* first time write, random junk */
+
 	vcpu->hv_clock.version = guest_hv_clock.version + 1;
 	kvm_write_guest_cached(v->kvm, &vcpu->pv_time,
 				&vcpu->hv_clock,
@@ -1916,7 +2064,10 @@
 	default:
 		if (msr >= MSR_IA32_MC0_CTL &&
 		    msr < MSR_IA32_MCx_CTL(bank_num)) {
-			u32 offset = msr - MSR_IA32_MC0_CTL;
+			u32 offset = array_index_nospec(
+				msr - MSR_IA32_MC0_CTL,
+				MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL);
+
 			/* only 0 or all 1s can be written to IA32_MCi_CTL
 			 * some Linux kernels though clear bit 10 in bank 4 to
 			 * workaround a BIOS/GART TBL issue on AMD K8s, ignore
@@ -2033,15 +2184,23 @@
 
 	switch (msr) {
 	case MSR_AMD64_NB_CFG:
-	case MSR_IA32_UCODE_REV:
 	case MSR_IA32_UCODE_WRITE:
 	case MSR_VM_HSAVE_PA:
 	case MSR_AMD64_PATCH_LOADER:
 	case MSR_AMD64_BU_CFG2:
 		break;
 
+	case MSR_IA32_UCODE_REV:
+		if (msr_info->host_initiated)
+			vcpu->arch.microcode_version = data;
+		break;
+	case MSR_IA32_ARCH_CAPABILITIES:
+		if (!msr_info->host_initiated)
+			return 1;
+		vcpu->arch.arch_capabilities = data;
+		break;
 	case MSR_EFER:
-		return set_efer(vcpu, data);
+		return set_efer(vcpu, msr_info);
 	case MSR_K7_HWCR:
 		data &= ~(u64)0x40;	/* ignore flush filter disable */
 		data &= ~(u64)0x100;	/* ignore ignne emulation enable */
@@ -2076,7 +2235,7 @@
 		return kvm_mtrr_set_msr(vcpu, msr, data);
 	case MSR_IA32_APICBASE:
 		return kvm_set_apic_base(vcpu, msr_info);
-	case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
+	case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff:
 		return kvm_x2apic_msr_write(vcpu, msr, data);
 	case MSR_IA32_TSCDEADLINE:
 		kvm_set_lapic_tscdeadline_msr(vcpu, data);
@@ -2198,6 +2357,7 @@
 	case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
 	case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
 	case HV_X64_MSR_CRASH_CTL:
+	case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
 		return kvm_hv_set_msr_common(vcpu, msr, data,
 					     msr_info->host_initiated);
 	case MSR_IA32_BBL_CR_CTL3:
@@ -2272,7 +2432,10 @@
 	default:
 		if (msr >= MSR_IA32_MC0_CTL &&
 		    msr < MSR_IA32_MCx_CTL(bank_num)) {
-			u32 offset = msr - MSR_IA32_MC0_CTL;
+			u32 offset = array_index_nospec(
+				msr - MSR_IA32_MC0_CTL,
+				MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL);
+
 			data = vcpu->arch.mce_banks[offset];
 			break;
 		}
@@ -2312,7 +2475,13 @@
 		msr_info->data = 0;
 		break;
 	case MSR_IA32_UCODE_REV:
-		msr_info->data = 0x100000000ULL;
+		msr_info->data = vcpu->arch.microcode_version;
+		break;
+	case MSR_IA32_ARCH_CAPABILITIES:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_arch_capabilities(vcpu))
+			return 1;
+		msr_info->data = vcpu->arch.arch_capabilities;
 		break;
 	case MSR_MTRRcap:
 	case 0x200 ... 0x2ff:
@@ -2337,7 +2506,7 @@
 	case MSR_IA32_APICBASE:
 		msr_info->data = kvm_get_apic_base(vcpu);
 		break;
-	case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
+	case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff:
 		return kvm_x2apic_msr_read(vcpu, msr_info->index, &msr_info->data);
 		break;
 	case MSR_IA32_TSCDEADLINE:
@@ -2402,6 +2571,7 @@
 	case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
 	case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
 	case HV_X64_MSR_CRASH_CTL:
+	case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
 		return kvm_hv_get_msr_common(vcpu,
 					     msr_info->index, &msr_info->data);
 		break;
@@ -2454,13 +2624,11 @@
 		    int (*do_msr)(struct kvm_vcpu *vcpu,
 				  unsigned index, u64 *data))
 {
-	int i, idx;
+	int i;
 
-	idx = srcu_read_lock(&vcpu->kvm->srcu);
 	for (i = 0; i < msrs->nmsrs; ++i)
 		if (do_msr(vcpu, entries[i].index, &entries[i].data))
 			break;
-	srcu_read_unlock(&vcpu->kvm->srcu, idx);
 
 	return i;
 }
@@ -2541,6 +2709,7 @@
 	case KVM_CAP_HYPERV:
 	case KVM_CAP_HYPERV_VAPIC:
 	case KVM_CAP_HYPERV_SPIN:
+	case KVM_CAP_HYPERV_SYNIC:
 	case KVM_CAP_PCI_SEGMENT:
 	case KVM_CAP_DEBUGREGS:
 	case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -2560,6 +2729,7 @@
 	case KVM_CAP_ASSIGN_DEV_IRQ:
 	case KVM_CAP_PCI_2_3:
 #endif
+	case KVM_CAP_GET_MSR_FEATURES:
 		r = 1;
 		break;
 	case KVM_CAP_X86_SMM:
@@ -2571,7 +2741,7 @@
 		 * fringe case that is not enabled except via specific settings
 		 * of the module parameters.
 		 */
-		r = kvm_x86_ops->cpu_has_high_real_mode_segbase();
+		r = kvm_x86_ops->has_emulated_msr(MSR_IA32_SMBASE);
 		break;
 	case KVM_CAP_COALESCED_MMIO:
 		r = KVM_COALESCED_MMIO_PAGE_OFFSET;
@@ -2675,6 +2845,31 @@
 			goto out;
 		r = 0;
 		break;
+	case KVM_GET_MSR_FEATURE_INDEX_LIST: {
+		struct kvm_msr_list __user *user_msr_list = argp;
+		struct kvm_msr_list msr_list;
+		unsigned int n;
+
+		r = -EFAULT;
+		if (copy_from_user(&msr_list, user_msr_list, sizeof(msr_list)))
+			goto out;
+		n = msr_list.nmsrs;
+		msr_list.nmsrs = num_msr_based_features;
+		if (copy_to_user(user_msr_list, &msr_list, sizeof(msr_list)))
+			goto out;
+		r = -E2BIG;
+		if (n < msr_list.nmsrs)
+			goto out;
+		r = -EFAULT;
+		if (copy_to_user(user_msr_list->indices, &msr_based_features,
+				 num_msr_based_features * sizeof(u32)))
+			goto out;
+		r = 0;
+		break;
+	}
+	case KVM_GET_MSRS:
+		r = msr_io(NULL, argp, do_get_msr_feature, 1);
+		break;
 	}
 	default:
 		r = -EINVAL;
@@ -2743,12 +2938,20 @@
 	kvm_x86_ops->vcpu_put(vcpu);
 	kvm_put_guest_fpu(vcpu);
 	vcpu->arch.last_host_tsc = rdtsc();
+	/*
+	 * If userspace has set any breakpoints or watchpoints, dr6 is restored
+	 * on every vmexit, but if not, we might have a stale dr6 from the
+	 * guest. do_debug expects dr6 to be cleared after it runs, do the same.
+	 */
+	set_debugreg(0, 6);
 }
 
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
 				    struct kvm_lapic_state *s)
 {
-	kvm_x86_ops->sync_pir_to_irr(vcpu);
+	if (vcpu->arch.apicv_active)
+		kvm_x86_ops->sync_pir_to_irr(vcpu);
+
 	memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s);
 
 	return 0;
@@ -2840,7 +3043,7 @@
 	unsigned bank_num = mcg_cap & 0xff, bank;
 
 	r = -EINVAL;
-	if (!bank_num || bank_num >= KVM_MAX_MCE_BANKS)
+	if (!bank_num || bank_num > KVM_MAX_MCE_BANKS)
 		goto out;
 	if (mcg_cap & ~(KVM_MCE_CAP_SUPPORTED | 0xff | 0xff0000))
 		goto out;
@@ -2941,6 +3144,8 @@
 	memset(&events->reserved, 0, sizeof(events->reserved));
 }
 
+static void kvm_set_hflags(struct kvm_vcpu *vcpu, unsigned emul_flags);
+
 static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 					      struct kvm_vcpu_events *events)
 {
@@ -2950,6 +3155,16 @@
 			      | KVM_VCPUEVENT_VALID_SMM))
 		return -EINVAL;
 
+	if (events->exception.injected &&
+	    (events->exception.nr > 31 || events->exception.nr == NMI_VECTOR))
+		return -EINVAL;
+
+	/* INITs are latched while in SMM */
+	if (events->flags & KVM_VCPUEVENT_VALID_SMM &&
+	    (events->smi.smm || events->smi.pending) &&
+	    vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED)
+		return -EINVAL;
+
 	process_nmi(vcpu);
 	vcpu->arch.exception.pending = events->exception.injected;
 	vcpu->arch.exception.nr = events->exception.nr;
@@ -2973,10 +3188,13 @@
 		vcpu->arch.apic->sipi_vector = events->sipi_vector;
 
 	if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
+		u32 hflags = vcpu->arch.hflags;
 		if (events->smi.smm)
-			vcpu->arch.hflags |= HF_SMM_MASK;
+			hflags |= HF_SMM_MASK;
 		else
-			vcpu->arch.hflags &= ~HF_SMM_MASK;
+			hflags &= ~HF_SMM_MASK;
+		kvm_set_hflags(vcpu, hflags);
+
 		vcpu->arch.smi_pending = events->smi.pending;
 		if (events->smi.smm_inside_nmi)
 			vcpu->arch.hflags |= HF_SMM_INSIDE_NMI_MASK;
@@ -3014,6 +3232,11 @@
 	if (dbgregs->flags)
 		return -EINVAL;
 
+	if (dbgregs->dr6 & ~0xffffffffull)
+		return -EINVAL;
+	if (dbgregs->dr7 & ~0xffffffffull)
+		return -EINVAL;
+
 	memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db));
 	kvm_update_dr0123(vcpu);
 	vcpu->arch.dr6 = dbgregs->dr6;
@@ -3039,6 +3262,7 @@
 	memcpy(dest, xsave, XSAVE_HDR_OFFSET);
 
 	/* Set XSTATE_BV */
+	xstate_bv &= vcpu->arch.guest_supported_xcr0 | XFEATURE_MASK_FPSSE;
 	*(u64 *)(dest + XSAVE_HDR_OFFSET) = xstate_bv;
 
 	/*
@@ -3115,11 +3339,14 @@
 	}
 }
 
+#define XSAVE_MXCSR_OFFSET 24
+
 static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
 					struct kvm_xsave *guest_xsave)
 {
 	u64 xstate_bv =
 		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
+	u32 mxcsr = *(u32 *)&guest_xsave->region[XSAVE_MXCSR_OFFSET / sizeof(u32)];
 
 	if (cpu_has_xsave) {
 		/*
@@ -3127,11 +3354,13 @@
 		 * CPUID leaf 0xD, index 0, EDX:EAX.  This is for compatibility
 		 * with old userspace.
 		 */
-		if (xstate_bv & ~kvm_supported_xcr0())
+		if (xstate_bv & ~kvm_supported_xcr0() ||
+			mxcsr & ~mxcsr_feature_mask)
 			return -EINVAL;
 		load_xsave(vcpu, (u8 *)guest_xsave->region);
 	} else {
-		if (xstate_bv & ~XFEATURE_MASK_FPSSE)
+		if (xstate_bv & ~XFEATURE_MASK_FPSSE ||
+			mxcsr & ~mxcsr_feature_mask)
 			return -EINVAL;
 		memcpy(&vcpu->arch.guest_fpu.state.fxsave,
 			guest_xsave->region, sizeof(struct fxregs_state));
@@ -3191,6 +3420,20 @@
 	return 0;
 }
 
+static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
+				     struct kvm_enable_cap *cap)
+{
+	if (cap->flags)
+		return -EINVAL;
+
+	switch (cap->cap) {
+	case KVM_CAP_HYPERV_SYNIC:
+		return kvm_hv_activate_synic(vcpu);
+	default:
+		return -EINVAL;
+	}
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
@@ -3290,12 +3533,18 @@
 		r = 0;
 		break;
 	}
-	case KVM_GET_MSRS:
+	case KVM_GET_MSRS: {
+		int idx = srcu_read_lock(&vcpu->kvm->srcu);
 		r = msr_io(vcpu, argp, do_get_msr, 1);
+		srcu_read_unlock(&vcpu->kvm->srcu, idx);
 		break;
-	case KVM_SET_MSRS:
+	}
+	case KVM_SET_MSRS: {
+		int idx = srcu_read_lock(&vcpu->kvm->srcu);
 		r = msr_io(vcpu, argp, do_set_msr, 0);
+		srcu_read_unlock(&vcpu->kvm->srcu, idx);
 		break;
+	}
 	case KVM_TPR_ACCESS_REPORTING: {
 		struct kvm_tpr_access_ctl tac;
 
@@ -3313,6 +3562,7 @@
 	};
 	case KVM_SET_VAPIC_ADDR: {
 		struct kvm_vapic_addr va;
+		int idx;
 
 		r = -EINVAL;
 		if (!lapic_in_kernel(vcpu))
@@ -3320,7 +3570,9 @@
 		r = -EFAULT;
 		if (copy_from_user(&va, argp, sizeof va))
 			goto out;
+		idx = srcu_read_lock(&vcpu->kvm->srcu);
 		r = kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
+		srcu_read_unlock(&vcpu->kvm->srcu, idx);
 		break;
 	}
 	case KVM_X86_SETUP_MCE: {
@@ -3455,6 +3707,15 @@
 		r = kvm_set_guest_paused(vcpu);
 		goto out;
 	}
+	case KVM_ENABLE_CAP: {
+		struct kvm_enable_cap cap;
+
+		r = -EFAULT;
+		if (copy_from_user(&cap, argp, sizeof(cap)))
+			goto out;
+		r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
+		break;
+	}
 	default:
 		r = -EINVAL;
 	}
@@ -3807,7 +4068,7 @@
 				   sizeof(struct kvm_pit_config)))
 			goto out;
 	create_pit:
-		mutex_lock(&kvm->slots_lock);
+		mutex_lock(&kvm->lock);
 		r = -EEXIST;
 		if (kvm->arch.vpit)
 			goto create_pit_unlock;
@@ -3816,7 +4077,7 @@
 		if (kvm->arch.vpit)
 			r = 0;
 	create_pit_unlock:
-		mutex_unlock(&kvm->slots_lock);
+		mutex_unlock(&kvm->lock);
 		break;
 	case KVM_GET_IRQCHIP: {
 		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
@@ -3883,10 +4144,13 @@
 		r = -EFAULT;
 		if (copy_from_user(&u.ps, argp, sizeof u.ps))
 			goto out;
+		mutex_lock(&kvm->lock);
 		r = -ENXIO;
 		if (!kvm->arch.vpit)
-			goto out;
+			goto set_pit_out;
 		r = kvm_vm_ioctl_set_pit(kvm, &u.ps);
+set_pit_out:
+		mutex_unlock(&kvm->lock);
 		break;
 	}
 	case KVM_GET_PIT2: {
@@ -3906,10 +4170,13 @@
 		r = -EFAULT;
 		if (copy_from_user(&u.ps2, argp, sizeof(u.ps2)))
 			goto out;
+		mutex_lock(&kvm->lock);
 		r = -ENXIO;
 		if (!kvm->arch.vpit)
-			goto out;
+			goto set_pit2_out;
 		r = kvm_vm_ioctl_set_pit2(kvm, &u.ps2);
+set_pit2_out:
+		mutex_unlock(&kvm->lock);
 		break;
 	}
 	case KVM_REINJECT_CONTROL: {
@@ -3930,13 +4197,14 @@
 		mutex_unlock(&kvm->lock);
 		break;
 	case KVM_XEN_HVM_CONFIG: {
+		struct kvm_xen_hvm_config xhc;
 		r = -EFAULT;
-		if (copy_from_user(&kvm->arch.xen_hvm_config, argp,
-				   sizeof(struct kvm_xen_hvm_config)))
+		if (copy_from_user(&xhc, argp, sizeof(xhc)))
 			goto out;
 		r = -EINVAL;
-		if (kvm->arch.xen_hvm_config.flags)
+		if (xhc.flags)
 			goto out;
+		memcpy(&kvm->arch.xen_hvm_config, &xhc, sizeof(xhc));
 		r = 0;
 		break;
 	}
@@ -4006,16 +4274,17 @@
 
 		/*
 		 * Even MSRs that are valid in the host may not be exposed
-		 * to the guests in some cases.  We could work around this
-		 * in VMX with the generic MSR save/load machinery, but it
-		 * is not really worthwhile since it will really only
-		 * happen with nested virtualization.
+		 * to the guests in some cases.
 		 */
 		switch (msrs_to_save[i]) {
 		case MSR_IA32_BNDCFGS:
 			if (!kvm_x86_ops->mpx_supported())
 				continue;
 			break;
+		case MSR_TSC_AUX:
+			if (!kvm_x86_ops->rdtscp_supported())
+				continue;
+			break;
 		default:
 			break;
 		}
@@ -4027,20 +4296,27 @@
 	num_msrs_to_save = j;
 
 	for (i = j = 0; i < ARRAY_SIZE(emulated_msrs); i++) {
-		switch (emulated_msrs[i]) {
-		case MSR_IA32_SMBASE:
-			if (!kvm_x86_ops->cpu_has_high_real_mode_segbase())
-				continue;
-			break;
-		default:
-			break;
-		}
+		if (!kvm_x86_ops->has_emulated_msr(emulated_msrs[i]))
+			continue;
 
 		if (j < i)
 			emulated_msrs[j] = emulated_msrs[i];
 		j++;
 	}
 	num_emulated_msrs = j;
+
+	for (i = j = 0; i < ARRAY_SIZE(msr_based_features); i++) {
+		struct kvm_msr_entry msr;
+
+		msr.index = msr_based_features[i];
+		if (kvm_get_msr_feature(&msr))
+			continue;
+
+		if (j < i)
+			msr_based_features[j] = msr_based_features[i];
+		j++;
+	}
+	num_msr_based_features = j;
 }
 
 static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
@@ -4076,7 +4352,7 @@
 					 addr, n, v))
 		    && kvm_io_bus_read(vcpu, KVM_MMIO_BUS, addr, n, v))
 			break;
-		trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v);
+		trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, v);
 		handled += n;
 		addr += n;
 		len -= n;
@@ -4200,24 +4476,35 @@
 	return X86EMUL_CONTINUE;
 }
 
-int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt,
+int kvm_read_guest_virt(struct kvm_vcpu *vcpu,
 			       gva_t addr, void *val, unsigned int bytes,
 			       struct x86_exception *exception)
 {
-	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
 	u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
 
+	/*
+	 * FIXME: this should call handle_emulation_failure if X86EMUL_IO_NEEDED
+	 * is returned, but our callers are not ready for that and they blindly
+	 * call kvm_inject_page_fault.  Ensure that they at least do not leak
+	 * uninitialized kernel stack memory into cr2 and error code.
+	 */
+	memset(exception, 0, sizeof(*exception));
 	return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access,
 					  exception);
 }
 EXPORT_SYMBOL_GPL(kvm_read_guest_virt);
 
-static int kvm_read_guest_virt_system(struct x86_emulate_ctxt *ctxt,
-				      gva_t addr, void *val, unsigned int bytes,
-				      struct x86_exception *exception)
+static int emulator_read_std(struct x86_emulate_ctxt *ctxt,
+			     gva_t addr, void *val, unsigned int bytes,
+			     struct x86_exception *exception, bool system)
 {
 	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
-	return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception);
+	u32 access = 0;
+
+	if (!system && kvm_x86_ops->get_cpl(vcpu) == 3)
+		access |= PFERR_USER_MASK;
+
+	return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception);
 }
 
 static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt,
@@ -4229,18 +4516,16 @@
 	return r < 0 ? X86EMUL_IO_NEEDED : X86EMUL_CONTINUE;
 }
 
-int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
-				       gva_t addr, void *val,
-				       unsigned int bytes,
-				       struct x86_exception *exception)
+static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
+				      struct kvm_vcpu *vcpu, u32 access,
+				      struct x86_exception *exception)
 {
-	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
 	void *data = val;
 	int r = X86EMUL_CONTINUE;
 
 	while (bytes) {
 		gpa_t gpa =  vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr,
-							     PFERR_WRITE_MASK,
+							     access,
 							     exception);
 		unsigned offset = addr & (PAGE_SIZE-1);
 		unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
@@ -4261,6 +4546,37 @@
 out:
 	return r;
 }
+
+static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val,
+			      unsigned int bytes, struct x86_exception *exception,
+			      bool system)
+{
+	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+	u32 access = PFERR_WRITE_MASK;
+
+	if (!system && kvm_x86_ops->get_cpl(vcpu) == 3)
+		access |= PFERR_USER_MASK;
+
+	/*
+	 * FIXME: this should call handle_emulation_failure if X86EMUL_IO_NEEDED
+	 * is returned, but our callers are not ready for that and they blindly
+	 * call kvm_inject_page_fault.  Ensure that they at least do not leak
+	 * uninitialized kernel stack memory into cr2 and error code.
+	 */
+	memset(exception, 0, sizeof(*exception));
+	return kvm_write_guest_virt_helper(addr, val, bytes, vcpu,
+					   access, exception);
+}
+
+int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val,
+				unsigned int bytes, struct x86_exception *exception)
+{
+	/* kvm_write_guest_virt_system can pull in tons of pages. */
+	vcpu->arch.l1tf_flush_l1d = true;
+
+	return kvm_write_guest_virt_helper(addr, val, bytes, vcpu,
+					   PFERR_WRITE_MASK, exception);
+}
 EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
 
 static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
@@ -4324,7 +4640,7 @@
 {
 	if (vcpu->mmio_read_completed) {
 		trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes,
-			       vcpu->mmio_fragments[0].gpa, *(u64 *)val);
+			       vcpu->mmio_fragments[0].gpa, val);
 		vcpu->mmio_read_completed = 0;
 		return 1;
 	}
@@ -4346,14 +4662,14 @@
 
 static int write_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes, void *val)
 {
-	trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val);
+	trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, val);
 	return vcpu_mmio_write(vcpu, gpa, bytes, val);
 }
 
 static int read_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
 			  void *val, int bytes)
 {
-	trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
+	trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, NULL);
 	return X86EMUL_IO_NEEDED;
 }
 
@@ -4574,16 +4890,20 @@
 
 static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
 {
-	/* TODO: String I/O for in kernel device */
-	int r;
+	int r = 0, i;
 
-	if (vcpu->arch.pio.in)
-		r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port,
-				    vcpu->arch.pio.size, pd);
-	else
-		r = kvm_io_bus_write(vcpu, KVM_PIO_BUS,
-				     vcpu->arch.pio.port, vcpu->arch.pio.size,
-				     pd);
+	for (i = 0; i < vcpu->arch.pio.count; i++) {
+		if (vcpu->arch.pio.in)
+			r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port,
+					    vcpu->arch.pio.size, pd);
+		else
+			r = kvm_io_bus_write(vcpu, KVM_PIO_BUS,
+					     vcpu->arch.pio.port, vcpu->arch.pio.size,
+					     pd);
+		if (r)
+			break;
+		pd += vcpu->arch.pio.size;
+	}
 	return r;
 }
 
@@ -4621,6 +4941,8 @@
 	if (vcpu->arch.pio.count)
 		goto data_avail;
 
+	memset(vcpu->arch.pio_data, 0, size * count);
+
 	ret = emulator_pio_in_out(vcpu, size, port, val, count, true);
 	if (ret) {
 data_avail:
@@ -4804,6 +5126,8 @@
 
 	if (var.unusable) {
 		memset(desc, 0, sizeof(*desc));
+		if (base3)
+			*base3 = 0;
 		return false;
 	}
 
@@ -4959,11 +5283,21 @@
 	kvm_x86_ops->set_nmi_mask(emul_to_vcpu(ctxt), masked);
 }
 
+static unsigned emulator_get_hflags(struct x86_emulate_ctxt *ctxt)
+{
+	return emul_to_vcpu(ctxt)->arch.hflags;
+}
+
+static void emulator_set_hflags(struct x86_emulate_ctxt *ctxt, unsigned emul_flags)
+{
+	kvm_set_hflags(emul_to_vcpu(ctxt), emul_flags);
+}
+
 static const struct x86_emulate_ops emulate_ops = {
 	.read_gpr            = emulator_read_gpr,
 	.write_gpr           = emulator_write_gpr,
-	.read_std            = kvm_read_guest_virt_system,
-	.write_std           = kvm_write_guest_virt_system,
+	.read_std            = emulator_read_std,
+	.write_std           = emulator_write_std,
 	.read_phys           = kvm_read_guest_phys_system,
 	.fetch               = kvm_fetch_guest_virt,
 	.read_emulated       = emulator_read_emulated,
@@ -4998,6 +5332,8 @@
 	.intercept           = emulator_intercept,
 	.get_cpuid           = emulator_get_cpuid,
 	.set_nmi_mask        = emulator_set_nmi_mask,
+	.get_hflags          = emulator_get_hflags,
+	.set_hflags          = emulator_set_hflags,
 };
 
 static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask)
@@ -5041,6 +5377,8 @@
 	kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
 
 	ctxt->eflags = kvm_get_rflags(vcpu);
+	ctxt->tf = (ctxt->eflags & X86_EFLAGS_TF) != 0;
+
 	ctxt->eip = kvm_rip_read(vcpu);
 	ctxt->mode = (!is_protmode(vcpu))		? X86EMUL_MODE_REAL :
 		     (ctxt->eflags & X86_EFLAGS_VM)	? X86EMUL_MODE_VM86 :
@@ -5050,7 +5388,6 @@
 	BUILD_BUG_ON(HF_GUEST_MASK != X86EMUL_GUEST_MASK);
 	BUILD_BUG_ON(HF_SMM_MASK != X86EMUL_SMM_MASK);
 	BUILD_BUG_ON(HF_SMM_INSIDE_NMI_MASK != X86EMUL_SMM_INSIDE_NMI_MASK);
-	ctxt->emul_flags = vcpu->arch.hflags;
 
 	init_decode_cache(ctxt);
 	vcpu->arch.emulate_regs_need_sync_from_vcpu = false;
@@ -5094,7 +5431,7 @@
 		vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
 		vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
 		vcpu->run->internal.ndata = 0;
-		r = EMULATE_FAIL;
+		r = EMULATE_USER_EXIT;
 	}
 	kvm_queue_exception(vcpu, UD_VECTOR);
 
@@ -5262,37 +5599,26 @@
 	return dr6;
 }
 
-static void kvm_vcpu_check_singlestep(struct kvm_vcpu *vcpu, unsigned long rflags, int *r)
+static void kvm_vcpu_do_singlestep(struct kvm_vcpu *vcpu, int *r)
 {
 	struct kvm_run *kvm_run = vcpu->run;
 
-	/*
-	 * rflags is the old, "raw" value of the flags.  The new value has
-	 * not been saved yet.
-	 *
-	 * This is correct even for TF set by the guest, because "the
-	 * processor will not generate this exception after the instruction
-	 * that sets the TF flag".
-	 */
-	if (unlikely(rflags & X86_EFLAGS_TF)) {
-		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
-			kvm_run->debug.arch.dr6 = DR6_BS | DR6_FIXED_1 |
-						  DR6_RTM;
-			kvm_run->debug.arch.pc = vcpu->arch.singlestep_rip;
-			kvm_run->debug.arch.exception = DB_VECTOR;
-			kvm_run->exit_reason = KVM_EXIT_DEBUG;
-			*r = EMULATE_USER_EXIT;
-		} else {
-			vcpu->arch.emulate_ctxt.eflags &= ~X86_EFLAGS_TF;
-			/*
-			 * "Certain debug exceptions may clear bit 0-3.  The
-			 * remaining contents of the DR6 register are never
-			 * cleared by the processor".
-			 */
-			vcpu->arch.dr6 &= ~15;
-			vcpu->arch.dr6 |= DR6_BS | DR6_RTM;
-			kvm_queue_exception(vcpu, DB_VECTOR);
-		}
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
+		kvm_run->debug.arch.dr6 = DR6_BS | DR6_FIXED_1 | DR6_RTM;
+		kvm_run->debug.arch.pc = vcpu->arch.singlestep_rip;
+		kvm_run->debug.arch.exception = DB_VECTOR;
+		kvm_run->exit_reason = KVM_EXIT_DEBUG;
+		*r = EMULATE_USER_EXIT;
+	} else {
+		vcpu->arch.emulate_ctxt.eflags &= ~X86_EFLAGS_TF;
+		/*
+		 * "Certain debug exceptions may clear bit 0-3.  The
+		 * remaining contents of the DR6 register are never
+		 * cleared by the processor".
+		 */
+		vcpu->arch.dr6 &= ~15;
+		vcpu->arch.dr6 |= DR6_BS | DR6_RTM;
+		kvm_queue_exception(vcpu, DB_VECTOR);
 	}
 }
 
@@ -5346,6 +5672,8 @@
 	bool writeback = true;
 	bool write_fault_to_spt = vcpu->arch.write_fault_to_shadow_pgtable;
 
+	vcpu->arch.l1tf_flush_l1d = true;
+
 	/*
 	 * Clear write_fault_to_shadow_pgtable here to ensure it is
 	 * never reused.
@@ -5362,7 +5690,8 @@
 		 * handle watchpoints yet, those would be handled in
 		 * the emulate_ops.
 		 */
-		if (kvm_vcpu_check_breakpoint(vcpu, &r))
+		if (!(emulation_type & EMULTYPE_SKIP) &&
+		    kvm_vcpu_check_breakpoint(vcpu, &r))
 			return r;
 
 		ctxt->interruptibility = 0;
@@ -5382,6 +5711,16 @@
 			if (reexecute_instruction(vcpu, cr2, write_fault_to_spt,
 						emulation_type))
 				return EMULATE_DONE;
+			if (ctxt->have_exception) {
+				/*
+				 * #UD should result in just EMULATION_FAILED, and trap-like
+				 * exception should not be encountered during decode.
+				 */
+				WARN_ON_ONCE(ctxt->exception.vector == UD_VECTOR ||
+					     exception_type(ctxt->exception.vector) == EXCPT_TRAP);
+				inject_emulated_exception(vcpu);
+				return EMULATE_DONE;
+			}
 			if (emulation_type & EMULTYPE_SKIP)
 				return EMULATE_FAIL;
 			return handle_emulation_failure(vcpu);
@@ -5446,14 +5785,13 @@
 		unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
 		toggle_interruptibility(vcpu, ctxt->interruptibility);
 		vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
-		if (vcpu->arch.hflags != ctxt->emul_flags)
-			kvm_set_hflags(vcpu, ctxt->emul_flags);
-		kvm_rip_write(vcpu, ctxt->eip);
-		if (r == EMULATE_DONE)
-			kvm_vcpu_check_singlestep(vcpu, rflags, &r);
 		if (!ctxt->have_exception ||
-		    exception_type(ctxt->exception.vector) == EXCPT_TRAP)
+		    exception_type(ctxt->exception.vector) == EXCPT_TRAP) {
+			kvm_rip_write(vcpu, ctxt->eip);
+			if (r == EMULATE_DONE && ctxt->tf)
+				kvm_vcpu_do_singlestep(vcpu, &r);
 			__kvm_set_rflags(vcpu, ctxt->eflags);
+		}
 
 		/*
 		 * For STI, interrupts are shadowed; so KVM_REQ_EVENT will
@@ -5554,17 +5892,17 @@
 
 	smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
 
-	spin_lock(&kvm_lock);
+	mutex_lock(&kvm_lock);
 	list_for_each_entry(kvm, &vm_list, vm_list) {
 		kvm_for_each_vcpu(i, vcpu, kvm) {
 			if (vcpu->cpu != freq->cpu)
 				continue;
 			kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
-			if (vcpu->cpu != smp_processor_id())
+			if (vcpu->cpu != raw_smp_processor_id())
 				send_ipi = 1;
 		}
 	}
-	spin_unlock(&kvm_lock);
+	mutex_unlock(&kvm_lock);
 
 	if (freq->old < freq->new && send_ipi) {
 		/*
@@ -5702,14 +6040,12 @@
 	/* Set the present bit. */
 	mask |= 1ull;
 
-#ifdef CONFIG_X86_64
 	/*
 	 * If reserved bit is not supported, clear the present bit to disable
 	 * mmio page fault.
 	 */
 	if (maxphyaddr == 52)
 		mask &= ~1ull;
-#endif
 
 	kvm_mmu_set_mmio_spte_mask(mask);
 }
@@ -5722,12 +6058,12 @@
 	struct kvm_vcpu *vcpu;
 	int i;
 
-	spin_lock(&kvm_lock);
+	mutex_lock(&kvm_lock);
 	list_for_each_entry(kvm, &vm_list, vm_list)
 		kvm_for_each_vcpu(i, vcpu, kvm)
 			kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
 	atomic_set(&kvm_guest_has_master_clock, 0);
-	spin_unlock(&kvm_lock);
+	mutex_unlock(&kvm_lock);
 }
 
 static DECLARE_WORK(pvclock_gtod_work, pvclock_gtod_update_fn);
@@ -5775,7 +6111,7 @@
 		goto out;
 	}
 	if (ops->disabled_by_bios()) {
-		printk(KERN_ERR "kvm: disabled by bios\n");
+		printk(KERN_WARNING "kvm: disabled by bios\n");
 		r = -EOPNOTSUPP;
 		goto out;
 	}
@@ -5820,6 +6156,7 @@
 
 void kvm_arch_exit(void)
 {
+	kvm_lapic_exit();
 	perf_unregister_guest_info_callbacks(&kvm_guest_cbs);
 
 	if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
@@ -5872,6 +6209,12 @@
 	kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
 }
 
+void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.apicv_active = false;
+	kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
+}
+
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 {
 	unsigned long nr, a0, a1, a2, a3, ret;
@@ -5933,7 +6276,8 @@
 
 	kvm_x86_ops->patch_hypercall(vcpu, instruction);
 
-	return emulator_write_emulated(ctxt, rip, instruction, 3, NULL);
+	return emulator_write_emulated(ctxt, rip, instruction, 3,
+		&ctxt->exception);
 }
 
 static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
@@ -5965,6 +6309,9 @@
 	if (!vcpu->arch.apic)
 		return;
 
+	if (vcpu->arch.apicv_active)
+		return;
+
 	if (!vcpu->arch.apic->vapic_addr)
 		max_irr = kvm_lapic_find_highest_irr(vcpu);
 	else
@@ -6022,12 +6369,10 @@
 	}
 
 	/* try to inject new event if pending */
-	if (vcpu->arch.nmi_pending) {
-		if (kvm_x86_ops->nmi_allowed(vcpu)) {
-			--vcpu->arch.nmi_pending;
-			vcpu->arch.nmi_injected = true;
-			kvm_x86_ops->set_nmi(vcpu);
-		}
+	if (vcpu->arch.nmi_pending && kvm_x86_ops->nmi_allowed(vcpu)) {
+		--vcpu->arch.nmi_pending;
+		vcpu->arch.nmi_injected = true;
+		kvm_x86_ops->set_nmi(vcpu);
 	} else if (kvm_cpu_has_injectable_intr(vcpu)) {
 		/*
 		 * Because interrupts can be injected asynchronously, we are
@@ -6303,18 +6648,24 @@
 
 static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
 {
+	u64 eoi_exit_bitmap[4];
+
 	if (!kvm_apic_hw_enabled(vcpu->arch.apic))
 		return;
 
-	memset(vcpu->arch.eoi_exit_bitmap, 0, 256 / 8);
+	bitmap_zero(vcpu->arch.ioapic_handled_vectors, 256);
 
 	if (irqchip_split(vcpu->kvm))
-		kvm_scan_ioapic_routes(vcpu, vcpu->arch.eoi_exit_bitmap);
+		kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors);
 	else {
-		kvm_x86_ops->sync_pir_to_irr(vcpu);
-		kvm_ioapic_scan_entry(vcpu, vcpu->arch.eoi_exit_bitmap);
-	}
-	kvm_x86_ops->load_eoi_exitmap(vcpu);
+		if (vcpu->arch.apicv_active)
+			kvm_x86_ops->sync_pir_to_irr(vcpu);
+		if (ioapic_in_kernel(vcpu->kvm))
+			kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
+	}
+	bitmap_or((ulong *)eoi_exit_bitmap, vcpu->arch.ioapic_handled_vectors,
+		  vcpu_to_synic(vcpu)->vec_bitmap, 256);
+	kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
 }
 
 static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
@@ -6396,6 +6747,7 @@
 		}
 		if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
 			vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
+			vcpu->mmio_needed = 0;
 			r = 0;
 			goto out;
 		}
@@ -6422,7 +6774,7 @@
 		if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) {
 			BUG_ON(vcpu->arch.pending_ioapic_eoi > 255);
 			if (test_bit(vcpu->arch.pending_ioapic_eoi,
-				     (void *) vcpu->arch.eoi_exit_bitmap)) {
+				     vcpu->arch.ioapic_handled_vectors)) {
 				vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI;
 				vcpu->run->eoi.vector =
 						vcpu->arch.pending_ioapic_eoi;
@@ -6446,6 +6798,14 @@
 			r = 0;
 			goto out;
 		}
+		if (kvm_check_request(KVM_REQ_HV_EXIT, vcpu)) {
+			vcpu->run->exit_reason = KVM_EXIT_HYPERV;
+			vcpu->run->hyperv = vcpu->arch.hyperv.exit;
+			r = 0;
+			goto out;
+		}
+		if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
+			kvm_hv_process_stimers(vcpu);
 	}
 
 	/*
@@ -6457,7 +6817,7 @@
 		 * Update architecture specific hints for APIC
 		 * virtual interrupt delivery.
 		 */
-		if (kvm_x86_ops->hwapic_irr_update)
+		if (vcpu->arch.apicv_active)
 			kvm_x86_ops->hwapic_irr_update(vcpu,
 				kvm_lapic_find_highest_irr(vcpu));
 	}
@@ -6472,10 +6832,12 @@
 		if (inject_pending_event(vcpu, req_int_win) != 0)
 			req_immediate_exit = true;
 		/* enable NMI/IRQ window open exits if needed */
-		else if (vcpu->arch.nmi_pending)
-			kvm_x86_ops->enable_nmi_window(vcpu);
-		else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
-			kvm_x86_ops->enable_irq_window(vcpu);
+		else {
+			if (vcpu->arch.nmi_pending)
+				kvm_x86_ops->enable_nmi_window(vcpu);
+			if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
+				kvm_x86_ops->enable_irq_window(vcpu);
+		}
 
 		if (kvm_lapic_enabled(vcpu)) {
 			update_cr8_intercept(vcpu);
@@ -6493,8 +6855,6 @@
 	kvm_x86_ops->prepare_guest_switch(vcpu);
 	if (vcpu->fpu_active)
 		kvm_load_guest_fpu(vcpu);
-	kvm_load_guest_xcr0(vcpu);
-
 	vcpu->mode = IN_GUEST_MODE;
 
 	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
@@ -6517,6 +6877,8 @@
 		goto cancel_injection;
 	}
 
+	kvm_load_guest_xcr0(vcpu);
+
 	if (req_immediate_exit)
 		smp_send_reschedule(vcpu->cpu);
 
@@ -6543,12 +6905,12 @@
 	 * KVM_DEBUGREG_WONT_EXIT again.
 	 */
 	if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) {
-		int i;
-
 		WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP);
 		kvm_x86_ops->sync_dirty_debug_regs(vcpu);
-		for (i = 0; i < KVM_NR_DB_REGS; i++)
-			vcpu->arch.eff_db[i] = vcpu->arch.db[i];
+		kvm_update_dr0123(vcpu);
+		kvm_update_dr6(vcpu);
+		kvm_update_dr7(vcpu);
+		vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD;
 	}
 
 	/*
@@ -6566,7 +6928,18 @@
 	vcpu->mode = OUTSIDE_GUEST_MODE;
 	smp_wmb();
 
-	/* Interrupt is enabled by handle_external_intr() */
+	kvm_put_guest_xcr0(vcpu);
+
+	/*
+	 * Mark this CPU as needing a branch predictor flush before running
+	 * userspace. Must be done before enabling preemption to ensure it gets
+	 * set for the CPU that actually ran the guest, and not the CPU that it
+	 * may migrate to.
+	 */
+	if (cpu_feature_enabled(X86_FEATURE_IBPB_EXIT_TO_USER))
+		this_cpu_write(x86_ibpb_exit_to_user, true);
+
+	/* handle_external_intr() enables interrupts */
 	kvm_x86_ops->handle_external_intr(vcpu);
 
 	++vcpu->stat.exits;
@@ -6655,6 +7028,7 @@
 	struct kvm *kvm = vcpu->kvm;
 
 	vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
+	vcpu->arch.l1tf_flush_l1d = true;
 
 	for (;;) {
 		if (kvm_vcpu_running(vcpu)) {
@@ -6889,7 +7263,7 @@
 #endif
 
 	kvm_rip_write(vcpu, regs->rip);
-	kvm_set_rflags(vcpu, regs->rflags);
+	kvm_set_rflags(vcpu, regs->rflags | X86_EFLAGS_FIXED);
 
 	vcpu->arch.exception.pending = false;
 
@@ -6967,6 +7341,12 @@
 	    mp_state->mp_state != KVM_MP_STATE_RUNNABLE)
 		return -EINVAL;
 
+	/* INITs are latched while in SMM */
+	if ((is_smm(vcpu) || vcpu->arch.smi_pending) &&
+	    (mp_state->mp_state == KVM_MP_STATE_SIPI_RECEIVED ||
+	     mp_state->mp_state == KVM_MP_STATE_INIT_RECEIVED))
+		return -EINVAL;
+
 	if (mp_state->mp_state == KVM_MP_STATE_SIPI_RECEIVED) {
 		vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
 		set_bit(KVM_APIC_SIPI, &vcpu->arch.apic->pending_events);
@@ -7038,7 +7418,7 @@
 		kvm_update_cpuid(vcpu);
 
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
-	if (!is_long_mode(vcpu) && is_pae(vcpu)) {
+	if (!is_long_mode(vcpu) && is_pae(vcpu) && is_paging(vcpu)) {
 		load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu));
 		mmu_reset_needed = 1;
 	}
@@ -7213,7 +7593,6 @@
 	 * and assume host would use all available bits.
 	 * Guest xcr0 would be loaded later.
 	 */
-	kvm_put_guest_xcr0(vcpu);
 	vcpu->guest_fpu_loaded = 1;
 	__kernel_fpu_begin();
 	__copy_kernel_to_fpregs(&vcpu->arch.guest_fpu.state);
@@ -7222,8 +7601,6 @@
 
 void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
 {
-	kvm_put_guest_xcr0(vcpu);
-
 	if (!vcpu->guest_fpu_loaded) {
 		vcpu->fpu_counter = 0;
 		return;
@@ -7233,25 +7610,17 @@
 	copy_fpregs_to_fpstate(&vcpu->arch.guest_fpu);
 	__kernel_fpu_end();
 	++vcpu->stat.fpu_reload;
-	/*
-	 * If using eager FPU mode, or if the guest is a frequent user
-	 * of the FPU, just leave the FPU active for next time.
-	 * Every 255 times fpu_counter rolls over to 0; a guest that uses
-	 * the FPU in bursts will revert to loading it on demand.
-	 */
-	if (!vcpu->arch.eager_fpu) {
-		if (++vcpu->fpu_counter < 5)
-			kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
-	}
 	trace_kvm_fpu(0);
 }
 
 void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 {
+	void *wbinvd_dirty_mask = vcpu->arch.wbinvd_dirty_mask;
+
 	kvmclock_reset(vcpu);
 
-	free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
 	kvm_x86_ops->vcpu_free(vcpu);
+	free_cpumask_var(wbinvd_dirty_mask);
 }
 
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
@@ -7273,6 +7642,7 @@
 {
 	int r;
 
+	vcpu->arch.arch_capabilities = kvm_get_arch_capabilities();
 	kvm_vcpu_mtrr_init(vcpu);
 	r = vcpu_load(vcpu);
 	if (r)
@@ -7313,7 +7683,7 @@
 	kvm_mmu_unload(vcpu);
 	vcpu_put(vcpu);
 
-	kvm_x86_ops->vcpu_free(vcpu);
+	kvm_arch_vcpu_free(vcpu);
 }
 
 void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
@@ -7528,6 +7898,7 @@
 	BUG_ON(vcpu->kvm == NULL);
 	kvm = vcpu->kvm;
 
+	vcpu->arch.apicv_active = kvm_x86_ops->get_enable_apicv();
 	vcpu->arch.pv.pv_unhalted = false;
 	vcpu->arch.emulate_ctxt.ops = &emulate_ops;
 	if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
@@ -7585,6 +7956,8 @@
 
 	vcpu->arch.pending_external_vector = -1;
 
+	kvm_hv_vcpu_init(vcpu);
+
 	return 0;
 
 fail_free_mce_banks:
@@ -7603,6 +7976,7 @@
 {
 	int idx;
 
+	kvm_hv_vcpu_uninit(vcpu);
 	kvm_pmu_destroy(vcpu);
 	kfree(vcpu->arch.mce_banks);
 	kvm_free_lapic(vcpu);
@@ -7616,6 +7990,7 @@
 
 void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
 {
+	vcpu->arch.l1tf_flush_l1d = true;
 	kvm_x86_ops->sched_in(vcpu, cpu);
 }
 
@@ -7627,6 +8002,7 @@
 	INIT_HLIST_HEAD(&kvm->arch.mask_notifier_list);
 	INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
 	INIT_LIST_HEAD(&kvm->arch.zapped_obsolete_pages);
+	INIT_LIST_HEAD(&kvm->arch.lpage_disallowed_mmu_pages);
 	INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
 	atomic_set(&kvm->arch.noncoherent_dma_count, 0);
 
@@ -7645,9 +8021,17 @@
 	INIT_DELAYED_WORK(&kvm->arch.kvmclock_update_work, kvmclock_update_fn);
 	INIT_DELAYED_WORK(&kvm->arch.kvmclock_sync_work, kvmclock_sync_fn);
 
+	if (kvm_x86_ops->vm_init)
+		return kvm_x86_ops->vm_init(kvm);
+
 	return 0;
 }
 
+int kvm_arch_post_init_vm(struct kvm *kvm)
+{
+	return kvm_mmu_post_init_vm(kvm);
+}
+
 static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
 {
 	int r;
@@ -7701,7 +8085,7 @@
 
 	slot = id_to_memslot(slots, id);
 	if (size) {
-		if (WARN_ON(slot->npages))
+		if (slot->npages)
 			return -EEXIST;
 
 		/*
@@ -7754,6 +8138,11 @@
 }
 EXPORT_SYMBOL_GPL(x86_set_memory_region);
 
+void kvm_arch_pre_destroy_vm(struct kvm *kvm)
+{
+	kvm_mmu_pre_destroy_vm(kvm);
+}
+
 void kvm_arch_destroy_vm(struct kvm *kvm)
 {
 	if (current->mm == kvm->mm) {
@@ -7766,6 +8155,8 @@
 		x86_set_memory_region(kvm, IDENTITY_PAGETABLE_PRIVATE_MEMSLOT, 0, 0);
 		x86_set_memory_region(kvm, TSS_PRIVATE_MEMSLOT, 0, 0);
 	}
+	if (kvm_x86_ops->vm_destroy)
+		kvm_x86_ops->vm_destroy(kvm);
 	kvm_iommu_unmap_guest(kvm);
 	kfree(kvm->arch.vpic);
 	kfree(kvm->arch.vioapic);
@@ -7799,7 +8190,15 @@
 {
 	int i;
 
+	/*
+	 * Clear out the previous array pointers for the KVM_MR_MOVE case.  The
+	 * old arrays will be freed by __kvm_set_memory_region() if installing
+	 * the new memslot is successful.
+	 */
+	memset(&slot->arch, 0, sizeof(slot->arch));
+
 	for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
+		struct kvm_lpage_info *linfo;
 		unsigned long ugfn;
 		int lpages;
 		int level = i + 1;
@@ -7814,15 +8213,16 @@
 		if (i == 0)
 			continue;
 
-		slot->arch.lpage_info[i - 1] = kvm_kvzalloc(lpages *
-					sizeof(*slot->arch.lpage_info[i - 1]));
-		if (!slot->arch.lpage_info[i - 1])
+		linfo = kvm_kvzalloc(lpages * sizeof(*linfo));
+		if (!linfo)
 			goto out_free;
 
+		slot->arch.lpage_info[i - 1] = linfo;
+
 		if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
-			slot->arch.lpage_info[i - 1][0].write_count = 1;
+			linfo[0].disallow_lpage = 1;
 		if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
-			slot->arch.lpage_info[i - 1][lpages - 1].write_count = 1;
+			linfo[lpages - 1].disallow_lpage = 1;
 		ugfn = slot->userspace_addr >> PAGE_SHIFT;
 		/*
 		 * If the gfn and userspace address are not aligned wrt each
@@ -7834,7 +8234,7 @@
 			unsigned long j;
 
 			for (j = 0; j < lpages; ++j)
-				slot->arch.lpage_info[i - 1][j].write_count = 1;
+				linfo[j].disallow_lpage = 1;
 		}
 	}
 
@@ -7867,6 +8267,10 @@
 				const struct kvm_userspace_memory_region *mem,
 				enum kvm_mr_change change)
 {
+	if (change == KVM_MR_MOVE)
+		return kvm_arch_create_memslot(kvm, memslot,
+					       mem->memory_size >> PAGE_SHIFT);
+
 	return 0;
 }
 
@@ -7997,6 +8401,9 @@
 	    kvm_cpu_has_interrupt(vcpu))
 		return true;
 
+	if (kvm_hv_has_stimer_pending(vcpu))
+		return true;
+
 	return false;
 }
 
@@ -8146,6 +8553,13 @@
 				      sizeof(val));
 }
 
+static int apf_get_user(struct kvm_vcpu *vcpu, u32 *val)
+{
+
+	return kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apf.data, val,
+				      sizeof(u32));
+}
+
 void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
 				     struct kvm_async_pf *work)
 {
@@ -8172,21 +8586,32 @@
 				 struct kvm_async_pf *work)
 {
 	struct x86_exception fault;
+	u32 val;
 
-	trace_kvm_async_pf_ready(work->arch.token, work->gva);
 	if (work->wakeup_all)
 		work->arch.token = ~0; /* broadcast wakeup */
 	else
 		kvm_del_async_pf_gfn(vcpu, work->arch.gfn);
+	trace_kvm_async_pf_ready(work->arch.token, work->gva);
 
-	if ((vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) &&
-	    !apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) {
-		fault.vector = PF_VECTOR;
-		fault.error_code_valid = true;
-		fault.error_code = 0;
-		fault.nested_page_fault = false;
-		fault.address = work->arch.token;
-		kvm_inject_page_fault(vcpu, &fault);
+	if (vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED &&
+	    !apf_get_user(vcpu, &val)) {
+		if (val == KVM_PV_REASON_PAGE_NOT_PRESENT &&
+		    vcpu->arch.exception.pending &&
+		    vcpu->arch.exception.nr == PF_VECTOR &&
+		    !apf_put_user(vcpu, 0)) {
+			vcpu->arch.exception.pending = false;
+			vcpu->arch.exception.nr = 0;
+			vcpu->arch.exception.has_error_code = false;
+			vcpu->arch.exception.error_code = 0;
+		} else if (!apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) {
+			fault.vector = PF_VECTOR;
+			fault.error_code_valid = true;
+			fault.error_code = 0;
+			fault.nested_page_fault = false;
+			fault.address = work->arch.token;
+			kvm_inject_page_fault(vcpu, &fault);
+		}
 	}
 	vcpu->arch.apf.halted = false;
 	vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
@@ -8197,8 +8622,7 @@
 	if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED))
 		return true;
 	else
-		return !kvm_event_needs_reinjection(vcpu) &&
-			kvm_x86_ops->interrupt_allowed(vcpu);
+		return kvm_can_do_async_pf(vcpu);
 }
 
 void kvm_arch_start_assignment(struct kvm *kvm)
--- linux-4.4.0.orig/arch/x86/kvm/x86.h
+++ linux-4.4.0/arch/x86/kvm/x86.h
@@ -2,6 +2,7 @@
 #define ARCH_X86_KVM_X86_H
 
 #include <linux/kvm_host.h>
+#include <asm/pvclock.h>
 #include "kvm_cache_regs.h"
 
 #define MSR_IA32_CR_PAT_DEFAULT  0x0007040600070406ULL
@@ -164,11 +165,11 @@
 
 void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr);
 
-int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt,
+int kvm_read_guest_virt(struct kvm_vcpu *vcpu,
 	gva_t addr, void *val, unsigned int bytes,
 	struct x86_exception *exception);
 
-int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
+int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu,
 	gva_t addr, void *val, unsigned int bytes,
 	struct x86_exception *exception);
 
@@ -192,4 +193,11 @@
 extern unsigned int lapic_timer_advance_ns;
 
 extern struct static_key kvm_no_apic_vcpu;
+
+static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
+{
+	return pvclock_scale_delta(nsec, vcpu->arch.virtual_tsc_mult,
+				   vcpu->arch.virtual_tsc_shift);
+}
+
 #endif
--- linux-4.4.0.orig/arch/x86/lib/Makefile
+++ linux-4.4.0/arch/x86/lib/Makefile
@@ -21,8 +21,9 @@
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
+lib-$(CONFIG_RETPOLINE) += retpoline.o
 
-obj-y += msr.o msr-reg.o msr-reg-export.o
+obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
 
 ifeq ($(CONFIG_X86_32),y)
         obj-y += atomic64_32.o
--- linux-4.4.0.orig/arch/x86/lib/checksum_32.S
+++ linux-4.4.0/arch/x86/lib/checksum_32.S
@@ -28,7 +28,8 @@
 #include <linux/linkage.h>
 #include <asm/errno.h>
 #include <asm/asm.h>
-				
+#include <asm/nospec-branch.h>
+
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
  */
@@ -155,7 +156,7 @@
 	negl %ebx
 	lea 45f(%ebx,%ebx,2), %ebx
 	testl %esi, %esi
-	jmp *%ebx
+	JMP_NOSPEC %ebx
 
 	# Handle 2-byte-aligned regions
 20:	addw (%esi), %ax
@@ -437,7 +438,7 @@
 	andl $-32,%edx
 	lea 3f(%ebx,%ebx), %ebx
 	testl %esi, %esi 
-	jmp *%ebx
+	JMP_NOSPEC %ebx
 1:	addl $64,%esi
 	addl $64,%edi 
 	SRC(movb -32(%edx),%bl)	; SRC(movb (%edx),%bl)
--- linux-4.4.0.orig/arch/x86/lib/clear_page_64.S
+++ linux-4.4.0/arch/x86/lib/clear_page_64.S
@@ -1,5 +1,5 @@
 #include <linux/linkage.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative-asm.h>
 
 /*
--- linux-4.4.0.orig/arch/x86/lib/cmdline.c
+++ linux-4.4.0/arch/x86/lib/cmdline.c
@@ -21,12 +21,14 @@
  * @option: option string to look for
  *
  * Returns the position of that @option (starts counting with 1)
- * or 0 on not found.
+ * or 0 on not found.  @option will only be found if it is found
+ * as an entire word in @cmdline.  For instance, if @option="car"
+ * then a cmdline which contains "cart" will not match.
  */
 int cmdline_find_option_bool(const char *cmdline, const char *option)
 {
 	char c;
-	int len, pos = 0, wstart = 0;
+	int pos = 0, wstart = 0;
 	const char *opptr = NULL;
 	enum {
 		st_wordstart = 0,	/* Start of word/after whitespace */
@@ -37,11 +39,14 @@
 	if (!cmdline)
 		return -1;      /* No command line */
 
-	len = min_t(int, strlen(cmdline), COMMAND_LINE_SIZE);
-	if (!len)
+	if (!strlen(cmdline))
 		return 0;
 
-	while (len--) {
+	/*
+	 * This 'pos' check ensures we do not overrun
+	 * a non-NULL-terminated 'cmdline'
+	 */
+	while (pos < COMMAND_LINE_SIZE) {
 		c = *(char *)cmdline++;
 		pos++;
 
@@ -58,17 +63,26 @@
 			/* fall through */
 
 		case st_wordcmp:
-			if (!*opptr)
+			if (!*opptr) {
+				/*
+				 * We matched all the way to the end of the
+				 * option we were looking for.  If the
+				 * command-line has a space _or_ ends, then
+				 * we matched!
+				 */
 				if (!c || myisspace(c))
 					return wstart;
 				else
 					state = st_wordskip;
-			else if (!c)
+			} else if (!c) {
+				/*
+				 * Hit the NULL terminator on the end of
+				 * cmdline.
+				 */
 				return 0;
-			else if (c != *opptr++)
+			} else if (c != *opptr++) {
 				state = st_wordskip;
-			else if (!len)		/* last word and is matching */
-				return wstart;
+			}
 			break;
 
 		case st_wordskip:
@@ -82,3 +96,108 @@
 
 	return 0;	/* Buffer overrun */
 }
+
+/*
+ * Find a non-boolean option (i.e. option=argument). In accordance with
+ * standard Linux practice, if this option is repeated, this returns the
+ * last instance on the command line.
+ *
+ * @cmdline: the cmdline string
+ * @max_cmdline_size: the maximum size of cmdline
+ * @option: option string to look for
+ * @buffer: memory buffer to return the option argument
+ * @bufsize: size of the supplied memory buffer
+ *
+ * Returns the length of the argument (regardless of if it was
+ * truncated to fit in the buffer), or -1 on not found.
+ */
+static int
+__cmdline_find_option(const char *cmdline, int max_cmdline_size,
+		      const char *option, char *buffer, int bufsize)
+{
+	char c;
+	int pos = 0, len = -1;
+	const char *opptr = NULL;
+	char *bufptr = buffer;
+	enum {
+		st_wordstart = 0,	/* Start of word/after whitespace */
+		st_wordcmp,	/* Comparing this word */
+		st_wordskip,	/* Miscompare, skip */
+		st_bufcpy,	/* Copying this to buffer */
+	} state = st_wordstart;
+
+	if (!cmdline)
+		return -1;      /* No command line */
+
+	/*
+	 * This 'pos' check ensures we do not overrun
+	 * a non-NULL-terminated 'cmdline'
+	 */
+	while (pos++ < max_cmdline_size) {
+		c = *(char *)cmdline++;
+		if (!c)
+			break;
+
+		switch (state) {
+		case st_wordstart:
+			if (myisspace(c))
+				break;
+
+			state = st_wordcmp;
+			opptr = option;
+			/* fall through */
+
+		case st_wordcmp:
+			if ((c == '=') && !*opptr) {
+				/*
+				 * We matched all the way to the end of the
+				 * option we were looking for, prepare to
+				 * copy the argument.
+				 */
+				len = 0;
+				bufptr = buffer;
+				state = st_bufcpy;
+				break;
+			} else if (c == *opptr++) {
+				/*
+				 * We are currently matching, so continue
+				 * to the next character on the cmdline.
+				 */
+				break;
+			}
+			state = st_wordskip;
+			/* fall through */
+
+		case st_wordskip:
+			if (myisspace(c))
+				state = st_wordstart;
+			break;
+
+		case st_bufcpy:
+			if (myisspace(c)) {
+				state = st_wordstart;
+			} else {
+				/*
+				 * Increment len, but don't overrun the
+				 * supplied buffer and leave room for the
+				 * NULL terminator.
+				 */
+				if (++len < bufsize)
+					*bufptr++ = c;
+			}
+			break;
+		}
+	}
+
+	if (bufsize)
+		*bufptr = '\0';
+
+	return len;
+}
+
+int cmdline_find_option(const char *cmdline, const char *option, char *buffer,
+			int bufsize)
+{
+	return __cmdline_find_option(cmdline, COMMAND_LINE_SIZE, option,
+				     buffer, bufsize);
+}
--- linux-4.4.0.orig/arch/x86/lib/copy_page_64.S
+++ linux-4.4.0/arch/x86/lib/copy_page_64.S
@@ -1,7 +1,7 @@
 /* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */
 
 #include <linux/linkage.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative-asm.h>
 
 /*
--- linux-4.4.0.orig/arch/x86/lib/copy_user_64.S
+++ linux-4.4.0/arch/x86/lib/copy_user_64.S
@@ -10,7 +10,7 @@
 #include <asm/current.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative-asm.h>
 #include <asm/asm.h>
 #include <asm/smap.h>
@@ -80,7 +80,7 @@
 	movl %edx,%ecx
 	andl $63,%edx
 	shrl $6,%ecx
-	jz 17f
+	jz .L_copy_short_string
 1:	movq (%rsi),%r8
 2:	movq 1*8(%rsi),%r9
 3:	movq 2*8(%rsi),%r10
@@ -101,7 +101,8 @@
 	leaq 64(%rdi),%rdi
 	decl %ecx
 	jnz 1b
-17:	movl %edx,%ecx
+.L_copy_short_string:
+	movl %edx,%ecx
 	andl $7,%edx
 	shrl $3,%ecx
 	jz 20f
@@ -215,6 +216,8 @@
  */
 ENTRY(copy_user_enhanced_fast_string)
 	ASM_STAC
+	cmpl $64,%edx
+	jb .L_copy_short_string	/* less then 64 bytes, avoid the costly 'rep' */
 	movl %edx,%ecx
 1:	rep
 	movsb
@@ -232,17 +235,31 @@
 
 /*
  * copy_user_nocache - Uncached memory copy with exception handling
- * This will force destination/source out of cache for more performance.
+ * This will force destination out of cache for more performance.
+ *
+ * Note: Cached memory copy is used when destination or size is not
+ * naturally aligned. That is:
+ *  - Require 8-byte alignment when size is 8 bytes or larger.
+ *  - Require 4-byte alignment when size is 4 bytes.
  */
 ENTRY(__copy_user_nocache)
 	ASM_STAC
+
+	/* If size is less than 8 bytes, go to 4-byte copy */
 	cmpl $8,%edx
-	jb 20f		/* less then 8 bytes, go to byte copy loop */
+	jb .L_4b_nocache_copy_entry
+
+	/* If destination is not 8-byte aligned, "cache" copy to align it */
 	ALIGN_DESTINATION
+
+	/* Set 4x8-byte copy count and remainder */
 	movl %edx,%ecx
 	andl $63,%edx
 	shrl $6,%ecx
-	jz 17f
+	jz .L_8b_nocache_copy_entry	/* jump if count is 0 */
+
+	/* Perform 4x8-byte nocache loop-copy */
+.L_4x8b_nocache_copy_loop:
 1:	movq (%rsi),%r8
 2:	movq 1*8(%rsi),%r9
 3:	movq 2*8(%rsi),%r10
@@ -262,60 +279,106 @@
 	leaq 64(%rsi),%rsi
 	leaq 64(%rdi),%rdi
 	decl %ecx
-	jnz 1b
-17:	movl %edx,%ecx
+	jnz .L_4x8b_nocache_copy_loop
+
+	/* Set 8-byte copy count and remainder */
+.L_8b_nocache_copy_entry:
+	movl %edx,%ecx
 	andl $7,%edx
 	shrl $3,%ecx
-	jz 20f
-18:	movq (%rsi),%r8
-19:	movnti %r8,(%rdi)
+	jz .L_4b_nocache_copy_entry	/* jump if count is 0 */
+
+	/* Perform 8-byte nocache loop-copy */
+.L_8b_nocache_copy_loop:
+20:	movq (%rsi),%r8
+21:	movnti %r8,(%rdi)
 	leaq 8(%rsi),%rsi
 	leaq 8(%rdi),%rdi
 	decl %ecx
-	jnz 18b
-20:	andl %edx,%edx
-	jz 23f
+	jnz .L_8b_nocache_copy_loop
+
+	/* If no byte left, we're done */
+.L_4b_nocache_copy_entry:
+	andl %edx,%edx
+	jz .L_finish_copy
+
+	/* If destination is not 4-byte aligned, go to byte copy: */
+	movl %edi,%ecx
+	andl $3,%ecx
+	jnz .L_1b_cache_copy_entry
+
+	/* Set 4-byte copy count (1 or 0) and remainder */
 	movl %edx,%ecx
-21:	movb (%rsi),%al
-22:	movb %al,(%rdi)
+	andl $3,%edx
+	shrl $2,%ecx
+	jz .L_1b_cache_copy_entry	/* jump if count is 0 */
+
+	/* Perform 4-byte nocache copy: */
+30:	movl (%rsi),%r8d
+31:	movnti %r8d,(%rdi)
+	leaq 4(%rsi),%rsi
+	leaq 4(%rdi),%rdi
+
+	/* If no bytes left, we're done: */
+	andl %edx,%edx
+	jz .L_finish_copy
+
+	/* Perform byte "cache" loop-copy for the remainder */
+.L_1b_cache_copy_entry:
+	movl %edx,%ecx
+.L_1b_cache_copy_loop:
+40:	movb (%rsi),%al
+41:	movb %al,(%rdi)
 	incq %rsi
 	incq %rdi
 	decl %ecx
-	jnz 21b
-23:	xorl %eax,%eax
+	jnz .L_1b_cache_copy_loop
+
+	/* Finished copying; fence the prior stores */
+.L_finish_copy:
+	xorl %eax,%eax
 	ASM_CLAC
 	sfence
 	ret
 
 	.section .fixup,"ax"
-30:	shll $6,%ecx
+.L_fixup_4x8b_copy:
+	shll $6,%ecx
 	addl %ecx,%edx
-	jmp 60f
-40:	lea (%rdx,%rcx,8),%rdx
-	jmp 60f
-50:	movl %ecx,%edx
-60:	sfence
+	jmp .L_fixup_handle_tail
+.L_fixup_8b_copy:
+	lea (%rdx,%rcx,8),%rdx
+	jmp .L_fixup_handle_tail
+.L_fixup_4b_copy:
+	lea (%rdx,%rcx,4),%rdx
+	jmp .L_fixup_handle_tail
+.L_fixup_1b_copy:
+	movl %ecx,%edx
+.L_fixup_handle_tail:
+	sfence
 	jmp copy_user_handle_tail
 	.previous
 
-	_ASM_EXTABLE(1b,30b)
-	_ASM_EXTABLE(2b,30b)
-	_ASM_EXTABLE(3b,30b)
-	_ASM_EXTABLE(4b,30b)
-	_ASM_EXTABLE(5b,30b)
-	_ASM_EXTABLE(6b,30b)
-	_ASM_EXTABLE(7b,30b)
-	_ASM_EXTABLE(8b,30b)
-	_ASM_EXTABLE(9b,30b)
-	_ASM_EXTABLE(10b,30b)
-	_ASM_EXTABLE(11b,30b)
-	_ASM_EXTABLE(12b,30b)
-	_ASM_EXTABLE(13b,30b)
-	_ASM_EXTABLE(14b,30b)
-	_ASM_EXTABLE(15b,30b)
-	_ASM_EXTABLE(16b,30b)
-	_ASM_EXTABLE(18b,40b)
-	_ASM_EXTABLE(19b,40b)
-	_ASM_EXTABLE(21b,50b)
-	_ASM_EXTABLE(22b,50b)
+	_ASM_EXTABLE(1b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(2b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(3b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(4b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(5b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(6b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(7b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(8b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(9b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(10b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(11b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(12b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(13b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(14b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(15b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(16b,.L_fixup_4x8b_copy)
+	_ASM_EXTABLE(20b,.L_fixup_8b_copy)
+	_ASM_EXTABLE(21b,.L_fixup_8b_copy)
+	_ASM_EXTABLE(30b,.L_fixup_4b_copy)
+	_ASM_EXTABLE(31b,.L_fixup_4b_copy)
+	_ASM_EXTABLE(40b,.L_fixup_1b_copy)
+	_ASM_EXTABLE(41b,.L_fixup_1b_copy)
 ENDPROC(__copy_user_nocache)
--- linux-4.4.0.orig/arch/x86/lib/csum-copy_64.S
+++ linux-4.4.0/arch/x86/lib/csum-copy_64.S
@@ -55,7 +55,7 @@
 	movq  %r12, 3*8(%rsp)
 	movq  %r14, 4*8(%rsp)
 	movq  %r13, 5*8(%rsp)
-	movq  %rbp, 6*8(%rsp)
+	movq  %r15, 6*8(%rsp)
 
 	movq  %r8, (%rsp)
 	movq  %r9, 1*8(%rsp)
@@ -74,7 +74,7 @@
 	/* main loop. clear in 64 byte blocks */
 	/* r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
 	/* r11:	temp3, rdx: temp4, r12 loopcnt */
-	/* r10:	temp5, rbp: temp6, r14 temp7, r13 temp8 */
+	/* r10:	temp5, r15: temp6, r14 temp7, r13 temp8 */
 	.p2align 4
 .Lloop:
 	source
@@ -89,7 +89,7 @@
 	source
 	movq  32(%rdi), %r10
 	source
-	movq  40(%rdi), %rbp
+	movq  40(%rdi), %r15
 	source
 	movq  48(%rdi), %r14
 	source
@@ -103,7 +103,7 @@
 	adcq  %r11, %rax
 	adcq  %rdx, %rax
 	adcq  %r10, %rax
-	adcq  %rbp, %rax
+	adcq  %r15, %rax
 	adcq  %r14, %rax
 	adcq  %r13, %rax
 
@@ -121,7 +121,7 @@
 	dest
 	movq %r10, 32(%rsi)
 	dest
-	movq %rbp, 40(%rsi)
+	movq %r15, 40(%rsi)
 	dest
 	movq %r14, 48(%rsi)
 	dest
@@ -203,7 +203,7 @@
 	movq 3*8(%rsp), %r12
 	movq 4*8(%rsp), %r14
 	movq 5*8(%rsp), %r13
-	movq 6*8(%rsp), %rbp
+	movq 6*8(%rsp), %r15
 	addq $7*8, %rsp
 	ret
 
--- linux-4.4.0.orig/arch/x86/lib/delay.c
+++ linux-4.4.0/arch/x86/lib/delay.c
@@ -26,6 +26,8 @@
 # include <asm/smp.h>
 #endif
 
+#define IBRS_DISABLE_THRESHOLD	1000
+
 /* simple loop based delay: */
 static void delay_loop(unsigned long loops)
 {
@@ -93,11 +95,21 @@
 {
 	u64 start, end, delay, loops = __loops;
 
+	/*
+	 * Timer value of 0 causes MWAITX to wait indefinitely, unless there
+	 * is a store on the memory monitored by MONITORX.
+	 */
+	if (loops == 0)
+		return;
+
 	start = rdtsc_ordered();
 
 	for (;;) {
 		delay = min_t(u64, MWAITX_MAX_LOOPS, loops);
 
+		if (delay > IBRS_DISABLE_THRESHOLD)
+			ubuntu_restrict_branch_speculation_end();
+
 		/*
 		 * Use cpu_tss as a cacheline-aligned, seldomly
 		 * accessed per-cpu variable as the monitor target.
@@ -105,12 +117,15 @@
 		__monitorx(this_cpu_ptr(&cpu_tss), 0, 0);
 
 		/*
-		 * AMD, like Intel, supports the EAX hint and EAX=0xf
-		 * means, do not enter any deep C-state and we use it
+		 * AMD, like Intel's MWAIT version, supports the EAX hint and
+		 * EAX=0xf0 means, do not enter any deep C-state and we use it
 		 * here in delay() to minimize wakeup latency.
 		 */
 		__mwaitx(MWAITX_DISABLE_CSTATES, delay, MWAITX_ECX_TIMER_ENABLE);
 
+		if (delay > IBRS_DISABLE_THRESHOLD)
+			ubuntu_restrict_branch_speculation_start();
+
 		end = rdtsc_ordered();
 
 		if (loops <= end - start)
--- linux-4.4.0.orig/arch/x86/lib/getuser.S
+++ linux-4.4.0/arch/x86/lib/getuser.S
@@ -38,6 +38,8 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 1:	movzbl (%_ASM_AX),%edx
 	xor %eax,%eax
@@ -51,6 +53,8 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 2:	movzwl -1(%_ASM_AX),%edx
 	xor %eax,%eax
@@ -64,6 +68,8 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 3:	movl -3(%_ASM_AX),%edx
 	xor %eax,%eax
@@ -78,6 +84,8 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 4:	movq -7(%_ASM_AX),%rdx
 	xor %eax,%eax
@@ -89,6 +97,8 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user_8
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 4:	movl -7(%_ASM_AX),%edx
 5:	movl -3(%_ASM_AX),%ecx
--- linux-4.4.0.orig/arch/x86/lib/hweight.S
+++ linux-4.4.0/arch/x86/lib/hweight.S
@@ -0,0 +1,79 @@
+#include <linux/linkage.h>
+
+#include <asm/asm.h>
+
+/*
+ * unsigned int __sw_hweight32(unsigned int w)
+ * %rdi: w
+ */
+ENTRY(__sw_hweight32)
+
+#ifdef CONFIG_X86_64
+	movl %edi, %eax				# w
+#endif
+	__ASM_SIZE(push,) %__ASM_REG(dx)
+	movl %eax, %edx				# w -> t
+	shrl %edx				# t >>= 1
+	andl $0x55555555, %edx			# t &= 0x55555555
+	subl %edx, %eax				# w -= t
+
+	movl %eax, %edx				# w -> t
+	shrl $2, %eax				# w_tmp >>= 2
+	andl $0x33333333, %edx			# t	&= 0x33333333
+	andl $0x33333333, %eax			# w_tmp &= 0x33333333
+	addl %edx, %eax				# w = w_tmp + t
+
+	movl %eax, %edx				# w -> t
+	shrl $4, %edx				# t >>= 4
+	addl %edx, %eax				# w_tmp += t
+	andl  $0x0f0f0f0f, %eax			# w_tmp &= 0x0f0f0f0f
+	imull $0x01010101, %eax, %eax		# w_tmp *= 0x01010101
+	shrl $24, %eax				# w = w_tmp >> 24
+	__ASM_SIZE(pop,) %__ASM_REG(dx)
+	ret
+ENDPROC(__sw_hweight32)
+
+ENTRY(__sw_hweight64)
+#ifdef CONFIG_X86_64
+	pushq   %rdi
+	pushq   %rdx
+
+	movq    %rdi, %rdx                      # w -> t
+	movabsq $0x5555555555555555, %rax
+	shrq    %rdx                            # t >>= 1
+	andq    %rdx, %rax                      # t &= 0x5555555555555555
+	movabsq $0x3333333333333333, %rdx
+	subq    %rax, %rdi                      # w -= t
+
+	movq    %rdi, %rax                      # w -> t
+	shrq    $2, %rdi                        # w_tmp >>= 2
+	andq    %rdx, %rax                      # t     &= 0x3333333333333333
+	andq    %rdi, %rdx                      # w_tmp &= 0x3333333333333333
+	addq    %rdx, %rax                      # w = w_tmp + t
+
+	movq    %rax, %rdx                      # w -> t
+	shrq    $4, %rdx                        # t >>= 4
+	addq    %rdx, %rax                      # w_tmp += t
+	movabsq $0x0f0f0f0f0f0f0f0f, %rdx
+	andq    %rdx, %rax                      # w_tmp &= 0x0f0f0f0f0f0f0f0f
+	movabsq $0x0101010101010101, %rdx
+	imulq   %rdx, %rax                      # w_tmp *= 0x0101010101010101
+	shrq    $56, %rax                       # w = w_tmp >> 56
+
+	popq    %rdx
+	popq    %rdi
+	ret
+#else /* CONFIG_X86_32 */
+	/* We're getting an u64 arg in (%eax,%edx): unsigned long hweight64(__u64 w) */
+	pushl   %ecx
+
+	call    __sw_hweight32
+	movl    %eax, %ecx                      # stash away result
+	movl    %edx, %eax                      # second part of input
+	call    __sw_hweight32
+	addl    %ecx, %eax                      # result
+
+	popl    %ecx
+	ret
+#endif
+ENDPROC(__sw_hweight64)
--- linux-4.4.0.orig/arch/x86/lib/insn.c
+++ linux-4.4.0/arch/x86/lib/insn.c
@@ -155,14 +155,24 @@
 			/*
 			 * In 32-bits mode, if the [7:6] bits (mod bits of
 			 * ModRM) on the second byte are not 11b, it is
-			 * LDS or LES.
+			 * LDS or LES or BOUND.
 			 */
 			if (X86_MODRM_MOD(b2) != 3)
 				goto vex_end;
 		}
 		insn->vex_prefix.bytes[0] = b;
 		insn->vex_prefix.bytes[1] = b2;
-		if (inat_is_vex3_prefix(attr)) {
+		if (inat_is_evex_prefix(attr)) {
+			b2 = peek_nbyte_next(insn_byte_t, insn, 2);
+			insn->vex_prefix.bytes[2] = b2;
+			b2 = peek_nbyte_next(insn_byte_t, insn, 3);
+			insn->vex_prefix.bytes[3] = b2;
+			insn->vex_prefix.nbytes = 4;
+			insn->next_byte += 4;
+			if (insn->x86_64 && X86_VEX_W(b2))
+				/* VEX.W overrides opnd_size */
+				insn->opnd_bytes = 8;
+		} else if (inat_is_vex3_prefix(attr)) {
 			b2 = peek_nbyte_next(insn_byte_t, insn, 2);
 			insn->vex_prefix.bytes[2] = b2;
 			insn->vex_prefix.nbytes = 3;
@@ -221,7 +231,9 @@
 		m = insn_vex_m_bits(insn);
 		p = insn_vex_p_bits(insn);
 		insn->attr = inat_get_avx_attribute(op, m, p);
-		if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr))
+		if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) ||
+		    (!inat_accept_vex(insn->attr) &&
+		     !inat_is_group(insn->attr)))
 			insn->attr = 0;	/* This instruction is bad */
 		goto end;	/* VEX has only 1 byte for opcode */
 	}
--- linux-4.4.0.orig/arch/x86/lib/memcpy_64.S
+++ linux-4.4.0/arch/x86/lib/memcpy_64.S
@@ -1,7 +1,7 @@
 /* Copyright 2002 Andi Kleen */
 
 #include <linux/linkage.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative-asm.h>
 
 /*
--- linux-4.4.0.orig/arch/x86/lib/memmove_64.S
+++ linux-4.4.0/arch/x86/lib/memmove_64.S
@@ -6,7 +6,7 @@
  *	- Copyright 2011 Fenghua Yu <fenghua.yu@intel.com>
  */
 #include <linux/linkage.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative-asm.h>
 
 #undef memmove
--- linux-4.4.0.orig/arch/x86/lib/memset_64.S
+++ linux-4.4.0/arch/x86/lib/memset_64.S
@@ -1,7 +1,7 @@
 /* Copyright 2002 Andi Kleen, SuSE Labs */
 
 #include <linux/linkage.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/alternative-asm.h>
 
 .weak memset
--- linux-4.4.0.orig/arch/x86/lib/retpoline.S
+++ linux-4.4.0/arch/x86/lib/retpoline.S
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/stringify.h>
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
+#include <asm/cpufeatures.h>
+#include <asm/alternative-asm.h>
+#include <asm-generic/export.h>
+#include <asm/nospec-branch.h>
+
+.macro THUNK reg
+	.section .text.__x86.indirect_thunk
+
+ENTRY(__x86_indirect_thunk_\reg)
+	CFI_STARTPROC
+	JMP_NOSPEC %\reg
+	CFI_ENDPROC
+ENDPROC(__x86_indirect_thunk_\reg)
+.endm
+
+/*
+ * Despite being an assembler file we can't just use .irp here
+ * because __KSYM_DEPS__ only uses the C preprocessor and would
+ * only see one instance of "__x86_indirect_thunk_\reg" rather
+ * than one per register with the correct names. So we do it
+ * the simple and nasty way...
+ */
+#define __EXPORT_THUNK(sym) _ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym)
+#define EXPORT_THUNK(reg) __EXPORT_THUNK(__x86_indirect_thunk_ ## reg)
+#define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg)
+
+GENERATE_THUNK(_ASM_AX)
+GENERATE_THUNK(_ASM_BX)
+GENERATE_THUNK(_ASM_CX)
+GENERATE_THUNK(_ASM_DX)
+GENERATE_THUNK(_ASM_SI)
+GENERATE_THUNK(_ASM_DI)
+GENERATE_THUNK(_ASM_BP)
+#ifdef CONFIG_64BIT
+GENERATE_THUNK(r8)
+GENERATE_THUNK(r9)
+GENERATE_THUNK(r10)
+GENERATE_THUNK(r11)
+GENERATE_THUNK(r12)
+GENERATE_THUNK(r13)
+GENERATE_THUNK(r14)
+GENERATE_THUNK(r15)
+#endif
--- linux-4.4.0.orig/arch/x86/lib/usercopy_32.c
+++ linux-4.4.0/arch/x86/lib/usercopy_32.c
@@ -570,12 +570,12 @@
 unsigned long __copy_to_user_ll(void __user *to, const void *from,
 				unsigned long n)
 {
-	stac();
+	__uaccess_begin_nospec();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel(to, from, n);
-	clac();
+	__uaccess_end();
 	return n;
 }
 EXPORT_SYMBOL(__copy_to_user_ll);
@@ -583,12 +583,12 @@
 unsigned long __copy_from_user_ll(void *to, const void __user *from,
 					unsigned long n)
 {
-	stac();
+	__uaccess_begin_nospec();
 	if (movsl_is_ok(to, from, n))
 		__copy_user_zeroing(to, from, n);
 	else
 		n = __copy_user_zeroing_intel(to, from, n);
-	clac();
+	__uaccess_end();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll);
@@ -596,13 +596,13 @@
 unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
 					 unsigned long n)
 {
-	stac();
+	__uaccess_begin_nospec();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel((void __user *)to,
 				      (const void *)from, n);
-	clac();
+	__uaccess_end();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nozero);
@@ -610,7 +610,7 @@
 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 					unsigned long n)
 {
-	stac();
+	__uaccess_begin_nospec();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && cpu_has_xmm2)
 		n = __copy_user_zeroing_intel_nocache(to, from, n);
@@ -619,7 +619,7 @@
 #else
 	__copy_user_zeroing(to, from, n);
 #endif
-	clac();
+	__uaccess_end();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache);
@@ -627,7 +627,7 @@
 unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
 					unsigned long n)
 {
-	stac();
+	__uaccess_begin_nospec();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && cpu_has_xmm2)
 		n = __copy_user_intel_nocache(to, from, n);
@@ -636,7 +636,7 @@
 #else
 	__copy_user(to, from, n);
 #endif
-	clac();
+	__uaccess_end();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
--- linux-4.4.0.orig/arch/x86/lib/x86-opcode-map.txt
+++ linux-4.4.0/arch/x86/lib/x86-opcode-map.txt
@@ -13,12 +13,17 @@
 # opcode: escape # escaped-name
 # EndTable
 #
+# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix
+# mnemonics that begin with lowercase 'k' accept a VEX prefix
+#
 #<group maps>
 # GrpTable: GrpXXX
 # reg:  mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
 # EndTable
 #
 # AVX Superscripts
+#  (ev): this opcode requires EVEX prefix.
+#  (evo): this opcode is changed by EVEX prefix (EVEX opcode)
 #  (v): this opcode requires VEX prefix.
 #  (v1): this opcode only supports 128bit VEX.
 #
@@ -137,7 +142,7 @@
 # 0x60 - 0x6f
 60: PUSHA/PUSHAD (i64)
 61: POPA/POPAD (i64)
-62: BOUND Gv,Ma (i64)
+62: BOUND Gv,Ma (i64) | EVEX (Prefix)
 63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64)
 64: SEG=FS (Prefix)
 65: SEG=GS (Prefix)
@@ -399,17 +404,17 @@
 3f:
 # 0x0f 0x40-0x4f
 40: CMOVO Gv,Ev
-41: CMOVNO Gv,Ev
-42: CMOVB/C/NAE Gv,Ev
+41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66)
+42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66)
 43: CMOVAE/NB/NC Gv,Ev
-44: CMOVE/Z Gv,Ev
-45: CMOVNE/NZ Gv,Ev
-46: CMOVBE/NA Gv,Ev
-47: CMOVA/NBE Gv,Ev
+44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66)
+45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66)
+46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66)
+47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66)
 48: CMOVS Gv,Ev
 49: CMOVNS Gv,Ev
-4a: CMOVP/PE Gv,Ev
-4b: CMOVNP/PO Gv,Ev
+4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66)
+4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk
 4c: CMOVL/NGE Gv,Ev
 4d: CMOVNL/GE Gv,Ev
 4e: CMOVLE/NG Gv,Ev
@@ -426,7 +431,7 @@
 58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1)
 59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1)
 5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1)
-5b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3)
+5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3)
 5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1)
 5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1)
 5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1)
@@ -447,7 +452,7 @@
 6c: vpunpcklqdq Vx,Hx,Wx (66),(v1)
 6d: vpunpckhqdq Vx,Hx,Wx (66),(v1)
 6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1)
-6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3)
+6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev)
 # 0x0f 0x70-0x7f
 70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1)
 71: Grp12 (1A)
@@ -458,14 +463,14 @@
 76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1)
 # Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX.
 77: emms | vzeroupper | vzeroall
-78: VMREAD Ey,Gy
-79: VMWRITE Gy,Ey
-7a:
-7b:
+78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev)
+79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev)
+7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev)
+7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev)
 7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2)
 7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2)
 7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1)
-7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqu Wx,Vx (F3)
+7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev)
 # 0x0f 0x80-0x8f
 # Note: "forced64" is Intel CPU behavior (see comment about CALL insn).
 80: JO Jz (f64)
@@ -485,16 +490,16 @@
 8e: JLE/JNG Jz (f64)
 8f: JNLE/JG Jz (f64)
 # 0x0f 0x90-0x9f
-90: SETO Eb
-91: SETNO Eb
-92: SETB/C/NAE Eb
-93: SETAE/NB/NC Eb
+90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66)
+91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66)
+92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2)
+93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2)
 94: SETE/Z Eb
 95: SETNE/NZ Eb
 96: SETBE/NA Eb
 97: SETA/NBE Eb
-98: SETS Eb
-99: SETNS Eb
+98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66)
+99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66)
 9a: SETP/PE Eb
 9b: SETNP/PO Eb
 9c: SETL/NGE Eb
@@ -564,11 +569,11 @@
 d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1)
 d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1)
 da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1)
-db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1)
+db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo)
 dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1)
 dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1)
 de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1)
-df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1)
+df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo)
 # 0x0f 0xe0-0xef
 e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1)
 e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1)
@@ -576,16 +581,16 @@
 e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1)
 e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1)
 e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1)
-e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2)
+e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2)
 e7: movntq Mq,Pq | vmovntdq Mx,Vx (66)
 e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1)
 e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1)
 ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1)
-eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1)
+eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo)
 ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1)
 ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1)
 ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1)
-ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1)
+ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo)
 # 0x0f 0xf0-0xff
 f0: vlddqu Vx,Mx (F2)
 f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1)
@@ -626,81 +631,105 @@
 0e: vtestps Vx,Wx (66),(v)
 0f: vtestpd Vx,Wx (66),(v)
 # 0x0f 0x38 0x10-0x1f
-10: pblendvb Vdq,Wdq (66)
-11:
-12:
-13: vcvtph2ps Vx,Wx,Ib (66),(v)
-14: blendvps Vdq,Wdq (66)
-15: blendvpd Vdq,Wdq (66)
-16: vpermps Vqq,Hqq,Wqq (66),(v)
+10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev)
+11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev)
+12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev)
+13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev)
+14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo)
+15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo)
+16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo)
 17: vptest Vx,Wx (66)
 18: vbroadcastss Vx,Wd (66),(v)
-19: vbroadcastsd Vqq,Wq (66),(v)
-1a: vbroadcastf128 Vqq,Mdq (66),(v)
-1b:
+19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo)
+1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo)
+1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev)
 1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1)
 1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1)
 1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1)
-1f:
+1f: vpabsq Vx,Wx (66),(ev)
 # 0x0f 0x38 0x20-0x2f
-20: vpmovsxbw Vx,Ux/Mq (66),(v1)
-21: vpmovsxbd Vx,Ux/Md (66),(v1)
-22: vpmovsxbq Vx,Ux/Mw (66),(v1)
-23: vpmovsxwd Vx,Ux/Mq (66),(v1)
-24: vpmovsxwq Vx,Ux/Md (66),(v1)
-25: vpmovsxdq Vx,Ux/Mq (66),(v1)
-26:
-27:
-28: vpmuldq Vx,Hx,Wx (66),(v1)
-29: vpcmpeqq Vx,Hx,Wx (66),(v1)
-2a: vmovntdqa Vx,Mx (66),(v1)
+20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev)
+21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev)
+22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev)
+23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev)
+24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev)
+25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev)
+26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev)
+27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev)
+28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev)
+29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev)
+2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev)
 2b: vpackusdw Vx,Hx,Wx (66),(v1)
-2c: vmaskmovps Vx,Hx,Mx (66),(v)
-2d: vmaskmovpd Vx,Hx,Mx (66),(v)
+2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo)
+2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo)
 2e: vmaskmovps Mx,Hx,Vx (66),(v)
 2f: vmaskmovpd Mx,Hx,Vx (66),(v)
 # 0x0f 0x38 0x30-0x3f
-30: vpmovzxbw Vx,Ux/Mq (66),(v1)
-31: vpmovzxbd Vx,Ux/Md (66),(v1)
-32: vpmovzxbq Vx,Ux/Mw (66),(v1)
-33: vpmovzxwd Vx,Ux/Mq (66),(v1)
-34: vpmovzxwq Vx,Ux/Md (66),(v1)
-35: vpmovzxdq Vx,Ux/Mq (66),(v1)
-36: vpermd Vqq,Hqq,Wqq (66),(v)
+30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev)
+31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev)
+32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev)
+33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev)
+34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev)
+35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev)
+36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo)
 37: vpcmpgtq Vx,Hx,Wx (66),(v1)
-38: vpminsb Vx,Hx,Wx (66),(v1)
-39: vpminsd Vx,Hx,Wx (66),(v1)
-3a: vpminuw Vx,Hx,Wx (66),(v1)
-3b: vpminud Vx,Hx,Wx (66),(v1)
+38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev)
+39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev)
+3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev)
+3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo)
 3c: vpmaxsb Vx,Hx,Wx (66),(v1)
-3d: vpmaxsd Vx,Hx,Wx (66),(v1)
+3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo)
 3e: vpmaxuw Vx,Hx,Wx (66),(v1)
-3f: vpmaxud Vx,Hx,Wx (66),(v1)
+3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo)
 # 0x0f 0x38 0x40-0x8f
-40: vpmulld Vx,Hx,Wx (66),(v1)
+40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo)
 41: vphminposuw Vdq,Wdq (66),(v1)
-42:
-43:
-44:
+42: vgetexpps/d Vx,Wx (66),(ev)
+43: vgetexpss/d Vx,Hx,Wx (66),(ev)
+44: vplzcntd/q Vx,Wx (66),(ev)
 45: vpsrlvd/q Vx,Hx,Wx (66),(v)
-46: vpsravd Vx,Hx,Wx (66),(v)
+46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo)
 47: vpsllvd/q Vx,Hx,Wx (66),(v)
-# Skip 0x48-0x57
+# Skip 0x48-0x4b
+4c: vrcp14ps/d Vpd,Wpd (66),(ev)
+4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev)
+4e: vrsqrt14ps/d Vpd,Wpd (66),(ev)
+4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev)
+# Skip 0x50-0x57
 58: vpbroadcastd Vx,Wx (66),(v)
-59: vpbroadcastq Vx,Wx (66),(v)
-5a: vbroadcasti128 Vqq,Mdq (66),(v)
-# Skip 0x5b-0x77
+59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo)
+5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo)
+5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev)
+# Skip 0x5c-0x63
+64: vpblendmd/q Vx,Hx,Wx (66),(ev)
+65: vblendmps/d Vx,Hx,Wx (66),(ev)
+66: vpblendmb/w Vx,Hx,Wx (66),(ev)
+# Skip 0x67-0x74
+75: vpermi2b/w Vx,Hx,Wx (66),(ev)
+76: vpermi2d/q Vx,Hx,Wx (66),(ev)
+77: vpermi2ps/d Vx,Hx,Wx (66),(ev)
 78: vpbroadcastb Vx,Wx (66),(v)
 79: vpbroadcastw Vx,Wx (66),(v)
-# Skip 0x7a-0x7f
+7a: vpbroadcastb Vx,Rv (66),(ev)
+7b: vpbroadcastw Vx,Rv (66),(ev)
+7c: vpbroadcastd/q Vx,Rv (66),(ev)
+7d: vpermt2b/w Vx,Hx,Wx (66),(ev)
+7e: vpermt2d/q Vx,Hx,Wx (66),(ev)
+7f: vpermt2ps/d Vx,Hx,Wx (66),(ev)
 80: INVEPT Gy,Mdq (66)
 81: INVPID Gy,Mdq (66)
 82: INVPCID Gy,Mdq (66)
+83: vpmultishiftqb Vx,Hx,Wx (66),(ev)
+88: vexpandps/d Vpd,Wpd (66),(ev)
+89: vpexpandd/q Vx,Wx (66),(ev)
+8a: vcompressps/d Wx,Vx (66),(ev)
+8b: vpcompressd/q Wx,Vx (66),(ev)
 8c: vpmaskmovd/q Vx,Hx,Mx (66),(v)
+8d: vpermb/w Vx,Hx,Wx (66),(ev)
 8e: vpmaskmovd/q Mx,Vx,Hx (66),(v)
 # 0x0f 0x38 0x90-0xbf (FMA)
-90: vgatherdd/q Vx,Hx,Wx (66),(v)
-91: vgatherqd/q Vx,Hx,Wx (66),(v)
+90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo)
+91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo)
 92: vgatherdps/d Vx,Hx,Wx (66),(v)
 93: vgatherqps/d Vx,Hx,Wx (66),(v)
 94:
@@ -715,6 +744,10 @@
 9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
 9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v)
 9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
+a0: vpscatterdd/q Wx,Vx (66),(ev)
+a1: vpscatterqd/q Wx,Vx (66),(ev)
+a2: vscatterdps/d Wx,Vx (66),(ev)
+a3: vscatterqps/d Wx,Vx (66),(ev)
 a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v)
 a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v)
 a8: vfmadd213ps/d Vx,Hx,Wx (66),(v)
@@ -725,6 +758,8 @@
 ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
 ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v)
 af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
+b4: vpmadd52luq Vx,Hx,Wx (66),(ev)
+b5: vpmadd52huq Vx,Hx,Wx (66),(ev)
 b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v)
 b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v)
 b8: vfmadd231ps/d Vx,Hx,Wx (66),(v)
@@ -736,12 +771,15 @@
 be: vfnmsub231ps/d Vx,Hx,Wx (66),(v)
 bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
 # 0x0f 0x38 0xc0-0xff
-c8: sha1nexte Vdq,Wdq
+c4: vpconflictd/q Vx,Wx (66),(ev)
+c6: Grp18 (1A)
+c7: Grp19 (1A)
+c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev)
 c9: sha1msg1 Vdq,Wdq
-ca: sha1msg2 Vdq,Wdq
-cb: sha256rnds2 Vdq,Wdq
-cc: sha256msg1 Vdq,Wdq
-cd: sha256msg2 Vdq,Wdq
+ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev)
+cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev)
+cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev)
+cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev)
 db: VAESIMC Vdq,Wdq (66),(v1)
 dc: VAESENC Vdq,Hdq,Wdq (66),(v1)
 dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1)
@@ -763,15 +801,15 @@
 00: vpermq Vqq,Wqq,Ib (66),(v)
 01: vpermpd Vqq,Wqq,Ib (66),(v)
 02: vpblendd Vx,Hx,Wx,Ib (66),(v)
-03:
+03: valignd/q Vx,Hx,Wx,Ib (66),(ev)
 04: vpermilps Vx,Wx,Ib (66),(v)
 05: vpermilpd Vx,Wx,Ib (66),(v)
 06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v)
 07:
-08: vroundps Vx,Wx,Ib (66)
-09: vroundpd Vx,Wx,Ib (66)
-0a: vroundss Vss,Wss,Ib (66),(v1)
-0b: vroundsd Vsd,Wsd,Ib (66),(v1)
+08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo)
+09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo)
+0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo)
+0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo)
 0c: vblendps Vx,Hx,Wx,Ib (66)
 0d: vblendpd Vx,Hx,Wx,Ib (66)
 0e: vpblendw Vx,Hx,Wx,Ib (66),(v1)
@@ -780,26 +818,51 @@
 15: vpextrw Rd/Mw,Vdq,Ib (66),(v1)
 16: vpextrd/q Ey,Vdq,Ib (66),(v1)
 17: vextractps Ed,Vdq,Ib (66),(v1)
-18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v)
-19: vextractf128 Wdq,Vqq,Ib (66),(v)
+18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo)
+19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo)
+1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev)
+1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev)
 1d: vcvtps2ph Wx,Vx,Ib (66),(v)
+1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev)
+1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev)
 20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1)
 21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1)
 22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1)
-38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v)
-39: vextracti128 Wdq,Vqq,Ib (66),(v)
+23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev)
+25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev)
+26: vgetmantps/d Vx,Wx,Ib (66),(ev)
+27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev)
+30: kshiftrb/w Vk,Uk,Ib (66),(v)
+31: kshiftrd/q Vk,Uk,Ib (66),(v)
+32: kshiftlb/w Vk,Uk,Ib (66),(v)
+33: kshiftld/q Vk,Uk,Ib (66),(v)
+38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo)
+39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo)
+3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev)
+3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev)
+3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev)
+3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev)
 40: vdpps Vx,Hx,Wx,Ib (66)
 41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1)
-42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1)
+42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo)
+43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev)
 44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1)
 46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v)
 4a: vblendvps Vx,Hx,Wx,Lx (66),(v)
 4b: vblendvpd Vx,Hx,Wx,Lx (66),(v)
 4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1)
+50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev)
+51: vrangess/d Vx,Hx,Wx,Ib (66),(ev)
+54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev)
+55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev)
+56: vreduceps/d Vx,Wx,Ib (66),(ev)
+57: vreducess/d Vx,Hx,Wx,Ib (66),(ev)
 60: vpcmpestrm Vdq,Wdq,Ib (66),(v1)
 61: vpcmpestri Vdq,Wdq,Ib (66),(v1)
 62: vpcmpistrm Vdq,Wdq,Ib (66),(v1)
 63: vpcmpistri Vdq,Wdq,Ib (66),(v1)
+66: vfpclassps/d Vk,Wx,Ib (66),(ev)
+67: vfpclassss/d Vk,Wx,Ib (66),(ev)
 cc: sha1rnds4 Vdq,Wdq,Ib
 df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1)
 f0: RORX Gy,Ey,Ib (F2),(v)
@@ -833,7 +896,7 @@
 
 GrpTable: Grp3_1
 0: TEST Eb,Ib
-1:
+1: TEST Eb,Ib
 2: NOT Eb
 3: NEG Eb
 4: MUL AL,Eb
@@ -927,8 +990,10 @@
 EndTable
 
 GrpTable: Grp13
+0: vprord/q Hx,Wx,Ib (66),(ev)
+1: vprold/q Hx,Wx,Ib (66),(ev)
 2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1)
-4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1)
+4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo)
 6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1)
 EndTable
 
@@ -963,6 +1028,20 @@
 3: BLSI By,Ey (v)
 EndTable
 
+GrpTable: Grp18
+1: vgatherpf0dps/d Wx (66),(ev)
+2: vgatherpf1dps/d Wx (66),(ev)
+5: vscatterpf0dps/d Wx (66),(ev)
+6: vscatterpf1dps/d Wx (66),(ev)
+EndTable
+
+GrpTable: Grp19
+1: vgatherpf0qps/d Wx (66),(ev)
+2: vgatherpf1qps/d Wx (66),(ev)
+5: vscatterpf0qps/d Wx (66),(ev)
+6: vscatterpf1qps/d Wx (66),(ev)
+EndTable
+
 # AMD's Prefetch Group
 GrpTable: GrpP
 0: PREFETCH
--- linux-4.4.0.orig/arch/x86/math-emu/Makefile
+++ linux-4.4.0/arch/x86/math-emu/Makefile
@@ -5,8 +5,8 @@
 #DEBUG	= -DDEBUGGING
 DEBUG	=
 PARANOID = -DPARANOID
-EXTRA_CFLAGS	:= $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
-EXTRA_AFLAGS	:= $(PARANOID)
+ccflags-y += $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
+asflags-y += $(PARANOID)
 
 # From 'C' language sources:
 C_OBJS =fpu_entry.o errors.o \
--- linux-4.4.0.orig/arch/x86/math-emu/fpu_emu.h
+++ linux-4.4.0/arch/x86/math-emu/fpu_emu.h
@@ -176,7 +176,7 @@
 #define setexponentpos(x,y) { (*(short *)&((x)->exp)) = \
   ((y) + EXTENDED_Ebias) & 0x7fff; }
 #define exponent16(x)         (*(short *)&((x)->exp))
-#define setexponent16(x,y)  { (*(short *)&((x)->exp)) = (y); }
+#define setexponent16(x,y)  { (*(short *)&((x)->exp)) = (u16)(y); }
 #define addexponent(x,y)    { (*(short *)&((x)->exp)) += (y); }
 #define stdexp(x)           { (*(short *)&((x)->exp)) += EXTENDED_Ebias; }
 
--- linux-4.4.0.orig/arch/x86/math-emu/reg_compare.c
+++ linux-4.4.0/arch/x86/math-emu/reg_compare.c
@@ -168,7 +168,7 @@
 /* This function requires that st(0) is not empty */
 int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
 {
-	int f = 0, c;
+	int f, c;
 
 	c = compare(loaded_data, loaded_tag);
 
@@ -189,12 +189,12 @@
 		case COMP_No_Comp:
 			f = SW_C3 | SW_C2 | SW_C0;
 			break;
-#ifdef PARANOID
 		default:
+#ifdef PARANOID
 			EXCEPTION(EX_INTERNAL | 0x121);
+#endif /* PARANOID */
 			f = SW_C3 | SW_C2 | SW_C0;
 			break;
-#endif /* PARANOID */
 		}
 	setcc(f);
 	if (c & COMP_Denormal) {
@@ -205,7 +205,7 @@
 
 static int compare_st_st(int nr)
 {
-	int f = 0, c;
+	int f, c;
 	FPU_REG *st_ptr;
 
 	if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
@@ -235,12 +235,12 @@
 		case COMP_No_Comp:
 			f = SW_C3 | SW_C2 | SW_C0;
 			break;
-#ifdef PARANOID
 		default:
+#ifdef PARANOID
 			EXCEPTION(EX_INTERNAL | 0x122);
+#endif /* PARANOID */
 			f = SW_C3 | SW_C2 | SW_C0;
 			break;
-#endif /* PARANOID */
 		}
 	setcc(f);
 	if (c & COMP_Denormal) {
@@ -283,12 +283,12 @@
 	case COMP_No_Comp:
 		f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
 		break;
-#ifdef PARANOID
 	default:
+#ifdef PARANOID
 		EXCEPTION(EX_INTERNAL | 0x122);
+#endif /* PARANOID */
 		f = 0;
 		break;
-#endif /* PARANOID */
 	}
 	FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
 	if (c & COMP_Denormal) {
--- linux-4.4.0.orig/arch/x86/math-emu/reg_constant.c
+++ linux-4.4.0/arch/x86/math-emu/reg_constant.c
@@ -17,7 +17,7 @@
 #include "control_w.h"
 
 #define MAKE_REG(s, e, l, h) { l, h, \
-		((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
+		(u16)((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
 
 FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
 #if 0
--- linux-4.4.0.orig/arch/x86/math-emu/wm_sqrt.S
+++ linux-4.4.0/arch/x86/math-emu/wm_sqrt.S
@@ -208,7 +208,7 @@
 
 #ifdef PARANOID
 /* It should be possible to get here only if the arg is ffff....ffff */
-	cmp	$0xffffffff,FPU_fsqrt_arg_1
+	cmpl	$0xffffffff,FPU_fsqrt_arg_1
 	jnz	sqrt_stage_2_error
 #endif /* PARANOID */
 
--- linux-4.4.0.orig/arch/x86/mm/Makefile
+++ linux-4.4.0/arch/x86/mm/Makefile
@@ -1,5 +1,5 @@
 obj-y	:=  init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
-	    pat.o pgtable.o physaddr.o gup.o setup_nx.o
+	    pat.o pgtable.o physaddr.o gup.o setup_nx.o tlb.o
 
 # Make sure __phys_addr has no stackprotector
 nostackp := $(call cc-option, -fno-stack-protector)
@@ -9,7 +9,6 @@
 CFLAGS_fault.o := -I$(src)/../include/asm/trace
 
 obj-$(CONFIG_X86_PAT)		+= pat_rbtree.o
-obj-$(CONFIG_SMP)		+= tlb.o
 
 obj-$(CONFIG_X86_32)		+= pgtable_32.o iomap_32.o
 
@@ -33,3 +32,4 @@
 obj-$(CONFIG_NUMA_EMU)		+= numa_emulation.o
 
 obj-$(CONFIG_X86_INTEL_MPX)	+= mpx.o
+obj-$(CONFIG_PAGE_TABLE_ISOLATION)		+= kaiser.o
--- linux-4.4.0.orig/arch/x86/mm/dump_pagetables.c
+++ linux-4.4.0/arch/x86/mm/dump_pagetables.c
@@ -15,6 +15,7 @@
 #include <linux/debugfs.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/seq_file.h>
 
 #include <asm/pgtable.h>
@@ -407,6 +408,7 @@
 		} else
 			note_page(m, &st, __pgprot(0), 1);
 
+		cond_resched();
 		start++;
 	}
 
--- linux-4.4.0.orig/arch/x86/mm/fault.c
+++ linux-4.4.0/arch/x86/mm/fault.c
@@ -16,6 +16,7 @@
 #include <linux/uaccess.h>		/* faulthandler_disabled()	*/
 
 #include <asm/traps.h>			/* dotraplinkage, ...		*/
+#include <asm/sections.h>
 #include <asm/pgalloc.h>		/* pgd_*(), ...			*/
 #include <asm/kmemcheck.h>		/* kmemcheck_*(), ...		*/
 #include <asm/fixmap.h>			/* VSYSCALL_ADDR		*/
@@ -216,18 +217,19 @@
 
 	pmd = pmd_offset(pud, address);
 	pmd_k = pmd_offset(pud_k, address);
-	if (!pmd_present(*pmd_k))
-		return NULL;
 
-	if (!pmd_present(*pmd))
+	if (pmd_present(*pmd) != pmd_present(*pmd_k))
 		set_pmd(pmd, *pmd_k);
+
+	if (!pmd_present(*pmd_k))
+		return NULL;
 	else
-		BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
+		BUG_ON(pmd_pfn(*pmd) != pmd_pfn(*pmd_k));
 
 	return pmd_k;
 }
 
-void vmalloc_sync_all(void)
+static void vmalloc_sync(void)
 {
 	unsigned long address;
 
@@ -242,22 +244,28 @@
 		spin_lock(&pgd_lock);
 		list_for_each_entry(page, &pgd_list, lru) {
 			spinlock_t *pgt_lock;
-			pmd_t *ret;
 
 			/* the pgt_lock only for Xen */
 			pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
 
 			spin_lock(pgt_lock);
-			ret = vmalloc_sync_one(page_address(page), address);
+			vmalloc_sync_one(page_address(page), address);
 			spin_unlock(pgt_lock);
-
-			if (!ret)
-				break;
 		}
 		spin_unlock(&pgd_lock);
 	}
 }
 
+void vmalloc_sync_mappings(void)
+{
+	vmalloc_sync();
+}
+
+void vmalloc_sync_unmappings(void)
+{
+	vmalloc_sync();
+}
+
 /*
  * 32-bit:
  *
@@ -273,8 +281,6 @@
 	if (!(address >= VMALLOC_START && address < VMALLOC_END))
 		return -1;
 
-	WARN_ON_ONCE(in_nmi());
-
 	/*
 	 * Synchronize this task's top level page-table
 	 * with the 'reference' page table.
@@ -287,6 +293,9 @@
 	if (!pmd_k)
 		return -1;
 
+	if (pmd_large(*pmd_k))
+		return 0;
+
 	pte_k = pte_offset_kernel(pmd_k, address);
 	if (!pte_present(*pte_k))
 		return -1;
@@ -351,17 +360,27 @@
 
 #else /* CONFIG_X86_64: */
 
-void vmalloc_sync_all(void)
+void vmalloc_sync_mappings(void)
 {
+	/*
+	 * 64-bit mappings might allocate new p4d/pud pages
+	 * that need to be propagated to all tasks' PGDs.
+	 */
 	sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END, 0);
 }
 
+void vmalloc_sync_unmappings(void)
+{
+	/*
+	 * Unmappings never allocate or free p4d/pud pages.
+	 * No work is required here.
+	 */
+}
+
 /*
  * 64-bit:
  *
  *   Handle a fault on the vmalloc area
- *
- * This assumes no large pages in there.
  */
 static noinline int vmalloc_fault(unsigned long address)
 {
@@ -374,8 +393,6 @@
 	if (!(address >= VMALLOC_START && address < VMALLOC_END))
 		return -1;
 
-	WARN_ON_ONCE(in_nmi());
-
 	/*
 	 * Copy kernel mappings over when needed. This can also
 	 * happen within a race in page table update. In the later
@@ -403,17 +420,23 @@
 	if (pud_none(*pud_ref))
 		return -1;
 
-	if (pud_none(*pud) || pud_page_vaddr(*pud) != pud_page_vaddr(*pud_ref))
+	if (pud_none(*pud) || pud_pfn(*pud) != pud_pfn(*pud_ref))
 		BUG();
 
+	if (pud_large(*pud))
+		return 0;
+
 	pmd = pmd_offset(pud, address);
 	pmd_ref = pmd_offset(pud_ref, address);
 	if (pmd_none(*pmd_ref))
 		return -1;
 
-	if (pmd_none(*pmd) || pmd_page(*pmd) != pmd_page(*pmd_ref))
+	if (pmd_none(*pmd) || pmd_pfn(*pmd) != pmd_pfn(*pmd_ref))
 		BUG();
 
+	if (pmd_large(*pmd))
+		return 0;
+
 	pte_ref = pte_offset_kernel(pmd_ref, address);
 	if (!pte_present(*pte_ref))
 		return -1;
--- linux-4.4.0.orig/arch/x86/mm/gup.c
+++ linux-4.4.0/arch/x86/mm/gup.c
@@ -368,7 +368,14 @@
 		next = pgd_addr_end(addr, end);
 		if (pgd_none(pgd))
 			goto slow;
-		if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+		/*
+		 * The FAST_GUP case requires FOLL_WRITE even for pure reads,
+		 * because get_user_pages() may need to cause an early COW in
+		 * order to avoid confusing the normal COW routines. So only
+		 * targets that are already writable are safe to do by just
+		 * looking at the page tables.
+		 */
+		if (!gup_pud_range(pgd, addr, next, 1, pages, &nr))
 			goto slow;
 	} while (pgdp++, addr = next, addr != end);
 	local_irq_enable();
@@ -388,7 +395,7 @@
 
 		ret = get_user_pages_unlocked(current, mm, start,
 					      (end - start) >> PAGE_SHIFT,
-					      write, 0, pages);
+					      pages, write ? FOLL_WRITE : 0);
 
 		/* Have to be a bit careful with return values */
 		if (nr > 0) {
--- linux-4.4.0.orig/arch/x86/mm/hugetlbpage.c
+++ linux-4.4.0/arch/x86/mm/hugetlbpage.c
@@ -144,7 +144,7 @@
 		addr = ALIGN(addr, huge_page_size(h));
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 	if (mm->get_unmapped_area == arch_get_unmapped_area)
--- linux-4.4.0.orig/arch/x86/mm/ident_map.c
+++ linux-4.4.0/arch/x86/mm/ident_map.c
@@ -0,0 +1,77 @@
+
+static void ident_pmd_init(struct x86_mapping_info *info, pmd_t *pmd_page,
+			   unsigned long addr, unsigned long end)
+{
+	addr &= PMD_MASK;
+	for (; addr < end; addr += PMD_SIZE) {
+		pmd_t *pmd = pmd_page + pmd_index(addr);
+
+		if (pmd_present(*pmd))
+			continue;
+
+		set_pmd(pmd, __pmd((addr - info->offset) | info->pmd_flag));
+	}
+}
+static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
+			  unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+
+	for (; addr < end; addr = next) {
+		pud_t *pud = pud_page + pud_index(addr);
+		pmd_t *pmd;
+
+		next = (addr & PUD_MASK) + PUD_SIZE;
+		if (next > end)
+			next = end;
+
+		if (pud_present(*pud)) {
+			pmd = pmd_offset(pud, 0);
+			ident_pmd_init(info, pmd, addr, next);
+			continue;
+		}
+		pmd = (pmd_t *)info->alloc_pgt_page(info->context);
+		if (!pmd)
+			return -ENOMEM;
+		ident_pmd_init(info, pmd, addr, next);
+		set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
+	}
+
+	return 0;
+}
+
+int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
+			      unsigned long pstart, unsigned long pend)
+{
+	unsigned long addr = pstart + info->offset;
+	unsigned long end = pend + info->offset;
+	unsigned long next;
+	int result;
+
+	for (; addr < end; addr = next) {
+		pgd_t *pgd = pgd_page + pgd_index(addr);
+		pud_t *pud;
+
+		next = (addr & PGDIR_MASK) + PGDIR_SIZE;
+		if (next > end)
+			next = end;
+
+		if (pgd_present(*pgd)) {
+			pud = pud_offset(pgd, 0);
+			result = ident_pud_init(info, pud, addr, next);
+			if (result)
+				return result;
+			continue;
+		}
+
+		pud = (pud_t *)info->alloc_pgt_page(info->context);
+		if (!pud)
+			return -ENOMEM;
+		result = ident_pud_init(info, pud, addr, next);
+		if (result)
+			return result;
+		set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
+	}
+
+	return 0;
+}
--- linux-4.4.0.orig/arch/x86/mm/init.c
+++ linux-4.4.0/arch/x86/mm/init.c
@@ -4,6 +4,8 @@
 #include <linux/swap.h>
 #include <linux/memblock.h>
 #include <linux/bootmem.h>	/* for max_low_pfn */
+#include <linux/swapfile.h>
+#include <linux/swapops.h>
 
 #include <asm/cacheflush.h>
 #include <asm/e820.h>
@@ -107,8 +109,6 @@
 	} else {
 		pfn = pgt_buf_end;
 		pgt_buf_end += num;
-		printk(KERN_DEBUG "BRK [%#010lx, %#010lx] PGTABLE\n",
-			pfn << PAGE_SHIFT, (pgt_buf_end << PAGE_SHIFT) - 1);
 	}
 
 	for (i = 0; i < num; i++) {
@@ -165,7 +165,7 @@
 		cr4_set_bits_and_update_boot(X86_CR4_PSE);
 
 	/* Enable PGE if available */
-	if (cpu_has_pge) {
+	if (cpu_has_pge && !kaiser_enabled) {
 		cr4_set_bits_and_update_boot(X86_CR4_PGE);
 		__supported_pte_mask |= _PAGE_GLOBAL;
 	} else
@@ -628,21 +628,40 @@
  * devmem_is_allowed() checks to see if /dev/mem access to a certain address
  * is valid. The argument is a physical page number.
  *
- *
- * On x86, access has to be given to the first megabyte of ram because that area
- * contains BIOS code and data regions used by X and dosemu and similar apps.
- * Access has to be given to non-kernel-ram areas as well, these contain the PCI
- * mmio resources as well as potential bios/acpi data regions.
+ * On x86, access has to be given to the first megabyte of RAM because that
+ * area traditionally contains BIOS code and data regions used by X, dosemu,
+ * and similar apps. Since they map the entire memory range, the whole range
+ * must be allowed (for mapping), but any areas that would otherwise be
+ * disallowed are flagged as being "zero filled" instead of rejected.
+ * Access has to be given to non-kernel-ram areas as well, these contain the
+ * PCI mmio resources as well as potential bios/acpi data regions.
  */
 int devmem_is_allowed(unsigned long pagenr)
 {
-	if (pagenr < 256)
-		return 1;
-	if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
+	if (page_is_ram(pagenr)) {
+		/*
+		 * For disallowed memory regions in the low 1MB range,
+		 * request that the page be shown as all zeros.
+		 */
+		if (pagenr < 256)
+			return 2;
+
+		return 0;
+	}
+
+	/*
+	 * This must follow RAM test, since System RAM is considered a
+	 * restricted resource under CONFIG_STRICT_IOMEM.
+	 */
+	if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) {
+		/* Low 1MB bypasses iomem restrictions. */
+		if (pagenr < 256)
+			return 1;
+
 		return 0;
-	if (!page_is_ram(pagenr))
-		return 1;
-	return 0;
+	}
+
+	return 1;
 }
 
 void free_init_pages(char *what, unsigned long begin, unsigned long end)
@@ -734,13 +753,11 @@
 }
 
 DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = {
-#ifdef CONFIG_SMP
 	.active_mm = &init_mm,
 	.state = 0,
-#endif
 	.cr4 = ~0UL,	/* fail hard if we screw up cr4 shadow initialization */
 };
-EXPORT_SYMBOL_GPL(cpu_tlbstate);
+EXPORT_PER_CPU_SYMBOL(cpu_tlbstate);
 
 void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache)
 {
@@ -750,3 +767,26 @@
 	__cachemode2pte_tbl[cache] = __cm_idx2pte(entry);
 	__pte2cachemode_tbl[entry] = cache;
 }
+
+#ifdef CONFIG_SWAP
+unsigned long max_swapfile_size(void)
+{
+	unsigned long pages;
+
+	pages = generic_max_swapfile_size();
+
+	if (boot_cpu_has_bug(X86_BUG_L1TF)) {
+		/* Limit the swap file size to MAX_PA/2 for L1TF workaround */
+		unsigned long long l1tf_limit = l1tf_pfn_limit();
+		/*
+		 * We encode swap offsets also with 3 bits below those for pfn
+		 * which makes the usable limit higher.
+		 */
+#if CONFIG_PGTABLE_LEVELS > 2
+		l1tf_limit <<= PAGE_SHIFT - SWP_OFFSET_FIRST_BIT;
+#endif
+		pages = min_t(unsigned long long, l1tf_limit, pages);
+	}
+	return pages;
+}
+#endif
--- linux-4.4.0.orig/arch/x86/mm/init_64.c
+++ linux-4.4.0/arch/x86/mm/init_64.c
@@ -56,79 +56,7 @@
 
 #include "mm_internal.h"
 
-static void ident_pmd_init(unsigned long pmd_flag, pmd_t *pmd_page,
-			   unsigned long addr, unsigned long end)
-{
-	addr &= PMD_MASK;
-	for (; addr < end; addr += PMD_SIZE) {
-		pmd_t *pmd = pmd_page + pmd_index(addr);
-
-		if (!pmd_present(*pmd))
-			set_pmd(pmd, __pmd(addr | pmd_flag));
-	}
-}
-static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
-			  unsigned long addr, unsigned long end)
-{
-	unsigned long next;
-
-	for (; addr < end; addr = next) {
-		pud_t *pud = pud_page + pud_index(addr);
-		pmd_t *pmd;
-
-		next = (addr & PUD_MASK) + PUD_SIZE;
-		if (next > end)
-			next = end;
-
-		if (pud_present(*pud)) {
-			pmd = pmd_offset(pud, 0);
-			ident_pmd_init(info->pmd_flag, pmd, addr, next);
-			continue;
-		}
-		pmd = (pmd_t *)info->alloc_pgt_page(info->context);
-		if (!pmd)
-			return -ENOMEM;
-		ident_pmd_init(info->pmd_flag, pmd, addr, next);
-		set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
-	}
-
-	return 0;
-}
-
-int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
-			      unsigned long addr, unsigned long end)
-{
-	unsigned long next;
-	int result;
-	int off = info->kernel_mapping ? pgd_index(__PAGE_OFFSET) : 0;
-
-	for (; addr < end; addr = next) {
-		pgd_t *pgd = pgd_page + pgd_index(addr) + off;
-		pud_t *pud;
-
-		next = (addr & PGDIR_MASK) + PGDIR_SIZE;
-		if (next > end)
-			next = end;
-
-		if (pgd_present(*pgd)) {
-			pud = pud_offset(pgd, 0);
-			result = ident_pud_init(info, pud, addr, next);
-			if (result)
-				return result;
-			continue;
-		}
-
-		pud = (pud_t *)info->alloc_pgt_page(info->context);
-		if (!pud)
-			return -ENOMEM;
-		result = ident_pud_init(info, pud, addr, next);
-		if (result)
-			return result;
-		set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
-	}
-
-	return 0;
-}
+#include "ident_map.c"
 
 /*
  * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the
@@ -395,6 +323,16 @@
 			continue;
 		if (vaddr < (unsigned long) _text || vaddr > end)
 			set_pmd(pmd, __pmd(0));
+		else if (kaiser_enabled) {
+			/*
+			 * level2_kernel_pgt is initialized with _PAGE_GLOBAL:
+			 * clear that now.  This is not important, so long as
+			 * CR4.PGE remains clear, but it removes an anomaly.
+			 * Physical mapping setup below avoids _PAGE_GLOBAL
+			 * by use of massage_pgprot() inside pfn_pte() etc.
+			 */
+			set_pmd(pmd, pmd_clear_flags(*pmd, _PAGE_GLOBAL));
+		}
 	}
 }
 
--- linux-4.4.0.orig/arch/x86/mm/ioremap.c
+++ linux-4.4.0/arch/x86/mm/ioremap.c
@@ -348,11 +348,11 @@
 	    (void __force *)addr < phys_to_virt(ISA_END_ADDRESS))
 		return;
 
+	mmiotrace_iounmap(addr);
+
 	addr = (volatile void __iomem *)
 		(PAGE_MASK & (unsigned long __force)addr);
 
-	mmiotrace_iounmap(addr);
-
 	/* Use the vm area unlocked, assuming the caller
 	   ensures there isn't another iounmap for the same address
 	   in parallel. Reuse of the virtual address is prevented by
--- linux-4.4.0.orig/arch/x86/mm/kaiser.c
+++ linux-4.4.0/arch/x86/mm/kaiser.c
@@ -0,0 +1,484 @@
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/ftrace.h>
+#include <linux/cpu.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Kernel/User page tables isolation: " fmt
+
+#include <asm/kaiser.h>
+#include <asm/tlbflush.h>	/* to verify its kaiser declarations */
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/desc.h>
+#include <asm/sections.h>
+#include <asm/cmdline.h>
+#include <asm/vsyscall.h>
+
+int kaiser_enabled __read_mostly = 1;
+EXPORT_SYMBOL(kaiser_enabled);	/* for inlined TLB flush functions */
+
+__visible
+DEFINE_PER_CPU_USER_MAPPED(unsigned long, unsafe_stack_register_backup);
+
+/*
+ * These can have bit 63 set, so we can not just use a plain "or"
+ * instruction to get their value or'd into CR3.  It would take
+ * another register.  So, we use a memory reference to these instead.
+ *
+ * This is also handy because systems that do not support PCIDs
+ * just end up or'ing a 0 into their CR3, which does no harm.
+ */
+DEFINE_PER_CPU(unsigned long, x86_cr3_pcid_user);
+
+/*
+ * At runtime, the only things we map are some things for CPU
+ * hotplug, and stacks for new processes.  No two CPUs will ever
+ * be populating the same addresses, so we only need to ensure
+ * that we protect between two CPUs trying to allocate and
+ * populate the same page table page.
+ *
+ * Only take this lock when doing a set_p[4um]d(), but it is not
+ * needed for doing a set_pte().  We assume that only the *owner*
+ * of a given allocation will be doing this for _their_
+ * allocation.
+ *
+ * This ensures that once a system has been running for a while
+ * and there have been stacks all over and these page tables
+ * are fully populated, there will be no further acquisitions of
+ * this lock.
+ */
+static DEFINE_SPINLOCK(shadow_table_allocation_lock);
+
+/*
+ * Returns -1 on error.
+ */
+static inline unsigned long get_pa_from_mapping(unsigned long vaddr)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	pgd = pgd_offset_k(vaddr);
+	/*
+	 * We made all the kernel PGDs present in kaiser_init().
+	 * We expect them to stay that way.
+	 */
+	BUG_ON(pgd_none(*pgd));
+	/*
+	 * PGDs are either 512GB or 128TB on all x86_64
+	 * configurations.  We don't handle these.
+	 */
+	BUG_ON(pgd_large(*pgd));
+
+	pud = pud_offset(pgd, vaddr);
+	if (pud_none(*pud)) {
+		WARN_ON_ONCE(1);
+		return -1;
+	}
+
+	if (pud_large(*pud))
+		return (pud_pfn(*pud) << PAGE_SHIFT) | (vaddr & ~PUD_PAGE_MASK);
+
+	pmd = pmd_offset(pud, vaddr);
+	if (pmd_none(*pmd)) {
+		WARN_ON_ONCE(1);
+		return -1;
+	}
+
+	if (pmd_large(*pmd))
+		return (pmd_pfn(*pmd) << PAGE_SHIFT) | (vaddr & ~PMD_PAGE_MASK);
+
+	pte = pte_offset_kernel(pmd, vaddr);
+	if (pte_none(*pte)) {
+		WARN_ON_ONCE(1);
+		return -1;
+	}
+
+	return (pte_pfn(*pte) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
+}
+
+/*
+ * This is a relatively normal page table walk, except that it
+ * also tries to allocate page tables pages along the way.
+ *
+ * Returns a pointer to a PTE on success, or NULL on failure.
+ */
+static pte_t *kaiser_pagetable_walk(unsigned long address, bool user)
+{
+	pmd_t *pmd;
+	pud_t *pud;
+	pgd_t *pgd = native_get_shadow_pgd(pgd_offset_k(address));
+	gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO);
+	unsigned long prot = _KERNPG_TABLE;
+
+	if (pgd_none(*pgd)) {
+		WARN_ONCE(1, "All shadow pgds should have been populated");
+		return NULL;
+	}
+	BUILD_BUG_ON(pgd_large(*pgd) != 0);
+
+	if (user) {
+		/*
+		 * The vsyscall page is the only page that will have
+		 *  _PAGE_USER set. Catch everything else.
+		 */
+		BUG_ON(address != VSYSCALL_ADDR);
+
+		set_pgd(pgd, __pgd(pgd_val(*pgd) | _PAGE_USER));
+		prot = _PAGE_TABLE;
+	}
+
+	pud = pud_offset(pgd, address);
+	/* The shadow page tables do not use large mappings: */
+	if (pud_large(*pud)) {
+		WARN_ON(1);
+		return NULL;
+	}
+	if (pud_none(*pud)) {
+		unsigned long new_pmd_page = __get_free_page(gfp);
+		if (!new_pmd_page)
+			return NULL;
+		spin_lock(&shadow_table_allocation_lock);
+		if (pud_none(*pud)) {
+			set_pud(pud, __pud(prot | __pa(new_pmd_page)));
+			__inc_zone_page_state(virt_to_page((void *)
+						new_pmd_page), NR_KAISERTABLE);
+		} else
+			free_page(new_pmd_page);
+		spin_unlock(&shadow_table_allocation_lock);
+	}
+
+	pmd = pmd_offset(pud, address);
+	/* The shadow page tables do not use large mappings: */
+	if (pmd_large(*pmd)) {
+		WARN_ON(1);
+		return NULL;
+	}
+	if (pmd_none(*pmd)) {
+		unsigned long new_pte_page = __get_free_page(gfp);
+		if (!new_pte_page)
+			return NULL;
+		spin_lock(&shadow_table_allocation_lock);
+		if (pmd_none(*pmd)) {
+			set_pmd(pmd, __pmd(prot | __pa(new_pte_page)));
+			__inc_zone_page_state(virt_to_page((void *)
+						new_pte_page), NR_KAISERTABLE);
+		} else
+			free_page(new_pte_page);
+		spin_unlock(&shadow_table_allocation_lock);
+	}
+
+	return pte_offset_kernel(pmd, address);
+}
+
+static int kaiser_add_user_map(const void *__start_addr, unsigned long size,
+			       unsigned long flags)
+{
+	int ret = 0;
+	pte_t *pte;
+	unsigned long start_addr = (unsigned long )__start_addr;
+	unsigned long address = start_addr & PAGE_MASK;
+	unsigned long end_addr = PAGE_ALIGN(start_addr + size);
+	unsigned long target_address;
+
+	/*
+	 * It is convenient for callers to pass in __PAGE_KERNEL etc,
+	 * and there is no actual harm from setting _PAGE_GLOBAL, so
+	 * long as CR4.PGE is not set.  But it is nonetheless troubling
+	 * to see Kaiser itself setting _PAGE_GLOBAL (now that "nokaiser"
+	 * requires that not to be #defined to 0): so mask it off here.
+	 */
+	flags &= ~_PAGE_GLOBAL;
+	if (!(__supported_pte_mask & _PAGE_NX))
+		flags &= ~_PAGE_NX;
+
+	for (; address < end_addr; address += PAGE_SIZE) {
+		target_address = get_pa_from_mapping(address);
+		if (target_address == -1) {
+			ret = -EIO;
+			break;
+		}
+		pte = kaiser_pagetable_walk(address, flags & _PAGE_USER);
+		if (!pte) {
+			ret = -ENOMEM;
+			break;
+		}
+		if (pte_none(*pte)) {
+			set_pte(pte, __pte(flags | target_address));
+		} else {
+			pte_t tmp;
+			set_pte(&tmp, __pte(flags | target_address));
+			WARN_ON_ONCE(!pte_same(*pte, tmp));
+		}
+	}
+	return ret;
+}
+
+static int kaiser_add_user_map_ptrs(const void *start, const void *end, unsigned long flags)
+{
+	unsigned long size = end - start;
+
+	return kaiser_add_user_map(start, size, flags);
+}
+
+/*
+ * Ensure that the top level of the (shadow) page tables are
+ * entirely populated.  This ensures that all processes that get
+ * forked have the same entries.  This way, we do not have to
+ * ever go set up new entries in older processes.
+ *
+ * Note: we never free these, so there are no updates to them
+ * after this.
+ */
+static void __init kaiser_init_all_pgds(void)
+{
+	pgd_t *pgd;
+	int i = 0;
+
+	pgd = native_get_shadow_pgd(pgd_offset_k((unsigned long )0));
+	for (i = PTRS_PER_PGD / 2; i < PTRS_PER_PGD; i++) {
+		pgd_t new_pgd;
+		pud_t *pud = pud_alloc_one(&init_mm,
+					   PAGE_OFFSET + i * PGDIR_SIZE);
+		if (!pud) {
+			WARN_ON(1);
+			break;
+		}
+		inc_zone_page_state(virt_to_page(pud), NR_KAISERTABLE);
+		new_pgd = __pgd(_KERNPG_TABLE |__pa(pud));
+		/*
+		 * Make sure not to stomp on some other pgd entry.
+		 */
+		if (!pgd_none(pgd[i])) {
+			WARN_ON(1);
+			continue;
+		}
+		set_pgd(pgd + i, new_pgd);
+	}
+}
+
+#define kaiser_add_user_map_early(start, size, flags) do {	\
+	int __ret = kaiser_add_user_map(start, size, flags);	\
+	WARN_ON(__ret);						\
+} while (0)
+
+#define kaiser_add_user_map_ptrs_early(start, end, flags) do {		\
+	int __ret = kaiser_add_user_map_ptrs(start, end, flags);	\
+	WARN_ON(__ret);							\
+} while (0)
+
+void __init kaiser_check_boottime_disable(void)
+{
+	char arg[5];
+	int ret;
+
+	if (boot_cpu_has(X86_FEATURE_XENPV))
+		goto silent_disable;
+
+	ret = cmdline_find_option(boot_command_line, "pti", arg, sizeof(arg));
+	if (ret > 0) {
+		if (!strncmp(arg, "on", 2))
+			goto enable;
+
+		if (!strncmp(arg, "off", 3))
+			goto disable;
+
+		if (!strncmp(arg, "auto", 4))
+			goto skip;
+	}
+
+	if (cmdline_find_option_bool(boot_command_line, "nopti") ||
+	    cpu_mitigations_off())
+		goto disable;
+
+skip:
+	if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN))
+		goto disable;
+
+enable:
+	setup_force_cpu_cap(X86_FEATURE_KAISER);
+	return;
+
+disable:
+	pr_info("disabled\n");
+
+silent_disable:
+	kaiser_enabled = 0;
+	setup_clear_cpu_cap(X86_FEATURE_KAISER);
+}
+
+/*
+ * If anything in here fails, we will likely die on one of the
+ * first kernel->user transitions and init will die.  But, we
+ * will have most of the kernel up by then and should be able to
+ * get a clean warning out of it.  If we BUG_ON() here, we run
+ * the risk of being before we have good console output.
+ */
+void __init kaiser_init(void)
+{
+	int cpu;
+
+	if (!kaiser_enabled)
+		return;
+
+	kaiser_init_all_pgds();
+
+	/*
+	 * Note that this sets _PAGE_USER and it needs to happen when the
+	 * pagetable hierarchy gets created, i.e., early. Otherwise
+	 * kaiser_pagetable_walk() will encounter initialized PTEs in the
+	 * hierarchy and not set the proper permissions, leading to the
+	 * pagefaults with page-protection violations when trying to read the
+	 * vsyscall page. For example.
+	 */
+	if (vsyscall_enabled())
+		kaiser_add_user_map_early((void *)VSYSCALL_ADDR,
+					  PAGE_SIZE,
+					  vsyscall_pgprot);
+
+	for_each_possible_cpu(cpu) {
+		void *percpu_vaddr = __per_cpu_user_mapped_start +
+				     per_cpu_offset(cpu);
+		unsigned long percpu_sz = __per_cpu_user_mapped_end -
+					  __per_cpu_user_mapped_start;
+		kaiser_add_user_map_early(percpu_vaddr, percpu_sz,
+					  __PAGE_KERNEL);
+	}
+
+	/*
+	 * Map the entry/exit text section, which is needed at
+	 * switches from user to and from kernel.
+	 */
+	kaiser_add_user_map_ptrs_early(__entry_text_start, __entry_text_end,
+				       __PAGE_KERNEL_RX);
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	kaiser_add_user_map_ptrs_early(__irqentry_text_start,
+				       __irqentry_text_end,
+				       __PAGE_KERNEL_RX);
+#endif
+	kaiser_add_user_map_early((void *)idt_descr.address,
+				  sizeof(gate_desc) * NR_VECTORS,
+				  __PAGE_KERNEL_RO);
+#ifdef CONFIG_TRACING
+	kaiser_add_user_map_early(&trace_idt_descr,
+				  sizeof(trace_idt_descr),
+				  __PAGE_KERNEL);
+	kaiser_add_user_map_early(&trace_idt_table,
+				  sizeof(gate_desc) * NR_VECTORS,
+				  __PAGE_KERNEL);
+#endif
+	kaiser_add_user_map_early(&debug_idt_descr, sizeof(debug_idt_descr),
+				  __PAGE_KERNEL);
+	kaiser_add_user_map_early(&debug_idt_table,
+				  sizeof(gate_desc) * NR_VECTORS,
+				  __PAGE_KERNEL);
+
+	pr_info("enabled\n");
+}
+
+/* Add a mapping to the shadow mapping, and synchronize the mappings */
+int kaiser_add_mapping(unsigned long addr, unsigned long size, unsigned long flags)
+{
+	if (!kaiser_enabled)
+		return 0;
+	return kaiser_add_user_map((const void *)addr, size, flags);
+}
+
+void kaiser_remove_mapping(unsigned long start, unsigned long size)
+{
+	extern void unmap_pud_range_nofree(pgd_t *pgd,
+				unsigned long start, unsigned long end);
+	unsigned long end = start + size;
+	unsigned long addr, next;
+	pgd_t *pgd;
+
+	if (!kaiser_enabled)
+		return;
+	pgd = native_get_shadow_pgd(pgd_offset_k(start));
+	for (addr = start; addr < end; pgd++, addr = next) {
+		next = pgd_addr_end(addr, end);
+		unmap_pud_range_nofree(pgd, addr, next);
+	}
+}
+
+/*
+ * Page table pages are page-aligned.  The lower half of the top
+ * level is used for userspace and the top half for the kernel.
+ * This returns true for user pages that need to get copied into
+ * both the user and kernel copies of the page tables, and false
+ * for kernel pages that should only be in the kernel copy.
+ */
+static inline bool is_userspace_pgd(pgd_t *pgdp)
+{
+	return ((unsigned long)pgdp % PAGE_SIZE) < (PAGE_SIZE / 2);
+}
+
+pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd)
+{
+	if (!kaiser_enabled)
+		return pgd;
+	/*
+	 * Do we need to also populate the shadow pgd?  Check _PAGE_USER to
+	 * skip cases like kexec and EFI which make temporary low mappings.
+	 */
+	if (pgd.pgd & _PAGE_USER) {
+		if (is_userspace_pgd(pgdp)) {
+			native_get_shadow_pgd(pgdp)->pgd = pgd.pgd;
+			/*
+			 * Even if the entry is *mapping* userspace, ensure
+			 * that userspace can not use it.  This way, if we
+			 * get out to userspace running on the kernel CR3,
+			 * userspace will crash instead of running.
+			 */
+			if (__supported_pte_mask & _PAGE_NX)
+				pgd.pgd |= _PAGE_NX;
+		}
+	} else if (!pgd.pgd) {
+		/*
+		 * pgd_clear() cannot check _PAGE_USER, and is even used to
+		 * clear corrupted pgd entries: so just rely on cases like
+		 * kexec and EFI never to be using pgd_clear().
+		 */
+		if (!WARN_ON_ONCE((unsigned long)pgdp & PAGE_SIZE) &&
+		    is_userspace_pgd(pgdp))
+			native_get_shadow_pgd(pgdp)->pgd = pgd.pgd;
+	}
+	return pgd;
+}
+
+void kaiser_setup_pcid(void)
+{
+	unsigned long user_cr3 = KAISER_SHADOW_PGD_OFFSET;
+
+	if (this_cpu_has(X86_FEATURE_PCID))
+		user_cr3 |= X86_CR3_PCID_USER_NOFLUSH;
+	/*
+	 * These variables are used by the entry/exit
+	 * code to change PCID and pgd and TLB flushing.
+	 */
+	this_cpu_write(x86_cr3_pcid_user, user_cr3);
+}
+
+/*
+ * Make a note that this cpu will need to flush USER tlb on return to user.
+ * If cpu does not have PCID, then the NOFLUSH bit will never have been set.
+ */
+void kaiser_flush_tlb_on_return_to_user(void)
+{
+	if (this_cpu_has(X86_FEATURE_PCID))
+		this_cpu_write(x86_cr3_pcid_user,
+			X86_CR3_PCID_USER_FLUSH | KAISER_SHADOW_PGD_OFFSET);
+}
+EXPORT_SYMBOL(kaiser_flush_tlb_on_return_to_user);
--- linux-4.4.0.orig/arch/x86/mm/kasan_init_64.c
+++ linux-4.4.0/arch/x86/mm/kasan_init_64.c
@@ -1,3 +1,4 @@
+#define DISABLE_BRANCH_PROFILING
 #define pr_fmt(fmt) "kasan: " fmt
 #include <linux/bootmem.h>
 #include <linux/kasan.h>
@@ -120,11 +121,22 @@
 	kasan_populate_zero_shadow(kasan_mem_to_shadow((void *)MODULES_END),
 			(void *)KASAN_SHADOW_END);
 
-	memset(kasan_zero_page, 0, PAGE_SIZE);
-
 	load_cr3(init_level4_pgt);
 	__flush_tlb_all();
-	init_task.kasan_depth = 0;
 
+	/*
+	 * kasan_zero_page has been used as early shadow memory, thus it may
+	 * contain some garbage. Now we can clear and write protect it, since
+	 * after the TLB flush no one should write to it.
+	 */
+	memset(kasan_zero_page, 0, PAGE_SIZE);
+	for (i = 0; i < PTRS_PER_PTE; i++) {
+		pte_t pte = __pte(__pa(kasan_zero_page) | __PAGE_KERNEL_RO);
+		set_pte(&kasan_zero_pte[i], pte);
+	}
+	/* Flush TLBs again to be sure that write protection applied. */
+	__flush_tlb_all();
+
+	init_task.kasan_depth = 0;
 	pr_info("KernelAddressSanitizer initialized\n");
 }
--- linux-4.4.0.orig/arch/x86/mm/kmmio.c
+++ linux-4.4.0/arch/x86/mm/kmmio.c
@@ -33,7 +33,7 @@
 struct kmmio_fault_page {
 	struct list_head list;
 	struct kmmio_fault_page *release_next;
-	unsigned long page; /* location of the fault page */
+	unsigned long addr; /* the requested address */
 	pteval_t old_presence; /* page presence prior to arming */
 	bool armed;
 
@@ -70,9 +70,16 @@
 static struct list_head kmmio_page_table[KMMIO_PAGE_TABLE_SIZE];
 static LIST_HEAD(kmmio_probes);
 
-static struct list_head *kmmio_page_list(unsigned long page)
+static struct list_head *kmmio_page_list(unsigned long addr)
 {
-	return &kmmio_page_table[hash_long(page, KMMIO_PAGE_HASH_BITS)];
+	unsigned int l;
+	pte_t *pte = lookup_address(addr, &l);
+
+	if (!pte)
+		return NULL;
+	addr &= page_level_mask(l);
+
+	return &kmmio_page_table[hash_long(addr, KMMIO_PAGE_HASH_BITS)];
 }
 
 /* Accessed per-cpu */
@@ -98,15 +105,19 @@
 }
 
 /* You must be holding RCU read lock. */
-static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page)
+static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long addr)
 {
 	struct list_head *head;
 	struct kmmio_fault_page *f;
+	unsigned int l;
+	pte_t *pte = lookup_address(addr, &l);
 
-	page &= PAGE_MASK;
-	head = kmmio_page_list(page);
+	if (!pte)
+		return NULL;
+	addr &= page_level_mask(l);
+	head = kmmio_page_list(addr);
 	list_for_each_entry_rcu(f, head, list) {
-		if (f->page == page)
+		if (f->addr == addr)
 			return f;
 	}
 	return NULL;
@@ -114,33 +125,38 @@
 
 static void clear_pmd_presence(pmd_t *pmd, bool clear, pmdval_t *old)
 {
+	pmd_t new_pmd;
 	pmdval_t v = pmd_val(*pmd);
 	if (clear) {
-		*old = v & _PAGE_PRESENT;
-		v &= ~_PAGE_PRESENT;
-	} else	/* presume this has been called with clear==true previously */
-		v |= *old;
-	set_pmd(pmd, __pmd(v));
+		*old = v;
+		new_pmd = pmd_mknotpresent(*pmd);
+	} else {
+		/* Presume this has been called with clear==true previously */
+		new_pmd = __pmd(*old);
+	}
+	set_pmd(pmd, new_pmd);
 }
 
 static void clear_pte_presence(pte_t *pte, bool clear, pteval_t *old)
 {
 	pteval_t v = pte_val(*pte);
 	if (clear) {
-		*old = v & _PAGE_PRESENT;
-		v &= ~_PAGE_PRESENT;
-	} else	/* presume this has been called with clear==true previously */
-		v |= *old;
-	set_pte_atomic(pte, __pte(v));
+		*old = v;
+		/* Nothing should care about address */
+		pte_clear(&init_mm, 0, pte);
+	} else {
+		/* Presume this has been called with clear==true previously */
+		set_pte_atomic(pte, __pte(*old));
+	}
 }
 
 static int clear_page_presence(struct kmmio_fault_page *f, bool clear)
 {
 	unsigned int level;
-	pte_t *pte = lookup_address(f->page, &level);
+	pte_t *pte = lookup_address(f->addr, &level);
 
 	if (!pte) {
-		pr_err("no pte for page 0x%08lx\n", f->page);
+		pr_err("no pte for addr 0x%08lx\n", f->addr);
 		return -1;
 	}
 
@@ -156,7 +172,7 @@
 		return -1;
 	}
 
-	__flush_tlb_one(f->page);
+	__flush_tlb_one(f->addr);
 	return 0;
 }
 
@@ -176,12 +192,12 @@
 	int ret;
 	WARN_ONCE(f->armed, KERN_ERR pr_fmt("kmmio page already armed.\n"));
 	if (f->armed) {
-		pr_warning("double-arm: page 0x%08lx, ref %d, old %d\n",
-			   f->page, f->count, !!f->old_presence);
+		pr_warning("double-arm: addr 0x%08lx, ref %d, old %d\n",
+			   f->addr, f->count, !!f->old_presence);
 	}
 	ret = clear_page_presence(f, true);
-	WARN_ONCE(ret < 0, KERN_ERR pr_fmt("arming 0x%08lx failed.\n"),
-		  f->page);
+	WARN_ONCE(ret < 0, KERN_ERR pr_fmt("arming at 0x%08lx failed.\n"),
+		  f->addr);
 	f->armed = true;
 	return ret;
 }
@@ -191,7 +207,7 @@
 {
 	int ret = clear_page_presence(f, false);
 	WARN_ONCE(ret < 0,
-			KERN_ERR "kmmio disarming 0x%08lx failed.\n", f->page);
+			KERN_ERR "kmmio disarming at 0x%08lx failed.\n", f->addr);
 	f->armed = false;
 }
 
@@ -215,6 +231,12 @@
 	struct kmmio_context *ctx;
 	struct kmmio_fault_page *faultpage;
 	int ret = 0; /* default to fault not handled */
+	unsigned long page_base = addr;
+	unsigned int l;
+	pte_t *pte = lookup_address(addr, &l);
+	if (!pte)
+		return -EINVAL;
+	page_base &= page_level_mask(l);
 
 	/*
 	 * Preemption is now disabled to prevent process switch during
@@ -227,7 +249,7 @@
 	preempt_disable();
 	rcu_read_lock();
 
-	faultpage = get_kmmio_fault_page(addr);
+	faultpage = get_kmmio_fault_page(page_base);
 	if (!faultpage) {
 		/*
 		 * Either this page fault is not caused by kmmio, or
@@ -239,7 +261,7 @@
 
 	ctx = &get_cpu_var(kmmio_ctx);
 	if (ctx->active) {
-		if (addr == ctx->addr) {
+		if (page_base == ctx->addr) {
 			/*
 			 * A second fault on the same page means some other
 			 * condition needs handling by do_page_fault(), the
@@ -267,9 +289,9 @@
 	ctx->active++;
 
 	ctx->fpage = faultpage;
-	ctx->probe = get_kmmio_probe(addr);
+	ctx->probe = get_kmmio_probe(page_base);
 	ctx->saved_flags = (regs->flags & (X86_EFLAGS_TF | X86_EFLAGS_IF));
-	ctx->addr = addr;
+	ctx->addr = page_base;
 
 	if (ctx->probe && ctx->probe->pre_handler)
 		ctx->probe->pre_handler(ctx->probe, regs, addr);
@@ -354,12 +376,11 @@
 }
 
 /* You must be holding kmmio_lock. */
-static int add_kmmio_fault_page(unsigned long page)
+static int add_kmmio_fault_page(unsigned long addr)
 {
 	struct kmmio_fault_page *f;
 
-	page &= PAGE_MASK;
-	f = get_kmmio_fault_page(page);
+	f = get_kmmio_fault_page(addr);
 	if (f) {
 		if (!f->count)
 			arm_kmmio_fault_page(f);
@@ -372,26 +393,25 @@
 		return -1;
 
 	f->count = 1;
-	f->page = page;
+	f->addr = addr;
 
 	if (arm_kmmio_fault_page(f)) {
 		kfree(f);
 		return -1;
 	}
 
-	list_add_rcu(&f->list, kmmio_page_list(f->page));
+	list_add_rcu(&f->list, kmmio_page_list(f->addr));
 
 	return 0;
 }
 
 /* You must be holding kmmio_lock. */
-static void release_kmmio_fault_page(unsigned long page,
+static void release_kmmio_fault_page(unsigned long addr,
 				struct kmmio_fault_page **release_list)
 {
 	struct kmmio_fault_page *f;
 
-	page &= PAGE_MASK;
-	f = get_kmmio_fault_page(page);
+	f = get_kmmio_fault_page(addr);
 	if (!f)
 		return;
 
@@ -419,19 +439,29 @@
 	unsigned long flags;
 	int ret = 0;
 	unsigned long size = 0;
+	unsigned long addr = p->addr & PAGE_MASK;
 	const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
+	unsigned int l;
+	pte_t *pte;
 
 	spin_lock_irqsave(&kmmio_lock, flags);
-	if (get_kmmio_probe(p->addr)) {
+	if (get_kmmio_probe(addr)) {
 		ret = -EEXIST;
 		goto out;
 	}
+
+	pte = lookup_address(addr, &l);
+	if (!pte) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	kmmio_count++;
 	list_add_rcu(&p->list, &kmmio_probes);
 	while (size < size_lim) {
-		if (add_kmmio_fault_page(p->addr + size))
+		if (add_kmmio_fault_page(addr + size))
 			pr_err("Unable to set page fault.\n");
-		size += PAGE_SIZE;
+		size += page_level_size(l);
 	}
 out:
 	spin_unlock_irqrestore(&kmmio_lock, flags);
@@ -503,14 +533,21 @@
 {
 	unsigned long flags;
 	unsigned long size = 0;
+	unsigned long addr = p->addr & PAGE_MASK;
 	const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
 	struct kmmio_fault_page *release_list = NULL;
 	struct kmmio_delayed_release *drelease;
+	unsigned int l;
+	pte_t *pte;
+
+	pte = lookup_address(addr, &l);
+	if (!pte)
+		return;
 
 	spin_lock_irqsave(&kmmio_lock, flags);
 	while (size < size_lim) {
-		release_kmmio_fault_page(p->addr + size, &release_list);
-		size += PAGE_SIZE;
+		release_kmmio_fault_page(addr + size, &release_list);
+		size += page_level_size(l);
 	}
 	list_del_rcu(&p->list);
 	kmmio_count--;
--- linux-4.4.0.orig/arch/x86/mm/mmap.c
+++ linux-4.4.0/arch/x86/mm/mmap.c
@@ -94,18 +94,6 @@
 }
 
 /*
- * Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64
- * does, but not when emulating X86_32
- */
-static unsigned long mmap_legacy_base(unsigned long rnd)
-{
-	if (mmap_is_ia32())
-		return TASK_UNMAPPED_BASE;
-	else
-		return TASK_UNMAPPED_BASE + rnd;
-}
-
-/*
  * This function, called very early during the creation of a new
  * process VM image, sets up which VM layout function to use:
  */
@@ -116,7 +104,7 @@
 	if (current->flags & PF_RANDOMIZE)
 		random_factor = arch_mmap_rnd();
 
-	mm->mmap_legacy_base = mmap_legacy_base(random_factor);
+	mm->mmap_legacy_base = TASK_UNMAPPED_BASE + random_factor;
 
 	if (mmap_is_legacy()) {
 		mm->mmap_base = mm->mmap_legacy_base;
@@ -133,3 +121,24 @@
 		return "[mpx]";
 	return NULL;
 }
+
+/*
+ * Only allow root to set high MMIO mappings to PROT_NONE.
+ * This prevents an unpriv. user to set them to PROT_NONE and invert
+ * them, then pointing to valid memory for L1TF speculation.
+ *
+ * Note: for locked down kernels may want to disable the root override.
+ */
+bool pfn_modify_allowed(unsigned long pfn, pgprot_t prot)
+{
+	if (!boot_cpu_has_bug(X86_BUG_L1TF))
+		return true;
+	if (!__pte_needs_invert(pgprot_val(prot)))
+		return true;
+	/* If it's real memory always allow */
+	if (pfn_valid(pfn))
+		return true;
+	if (pfn >= l1tf_pfn_limit() && !capable(CAP_SYS_ADMIN))
+		return false;
+	return true;
+}
--- linux-4.4.0.orig/arch/x86/mm/mmio-mod.c
+++ linux-4.4.0/arch/x86/mm/mmio-mod.c
@@ -385,7 +385,7 @@
 	int cpu;
 	int err;
 
-	if (downed_cpus == NULL &&
+	if (!cpumask_available(downed_cpus) &&
 	    !alloc_cpumask_var(&downed_cpus, GFP_KERNEL)) {
 		pr_notice("Failed to allocate mask\n");
 		goto out;
@@ -415,7 +415,7 @@
 	int cpu;
 	int err;
 
-	if (downed_cpus == NULL || cpumask_weight(downed_cpus) == 0)
+	if (!cpumask_available(downed_cpus) || cpumask_weight(downed_cpus) == 0)
 		return;
 	pr_notice("Re-enabling CPUs...\n");
 	for_each_cpu(cpu, downed_cpus) {
--- linux-4.4.0.orig/arch/x86/mm/mpx.c
+++ linux-4.4.0/arch/x86/mm/mpx.c
@@ -123,7 +123,7 @@
 		break;
 	}
 
-	if (regno > nr_registers) {
+	if (regno >= nr_registers) {
 		WARN_ONCE(1, "decoded an instruction with an invalid register");
 		return -EINVAL;
 	}
@@ -293,7 +293,7 @@
 	 * We were not able to extract an address from the instruction,
 	 * probably because there was something invalid in it.
 	 */
-	if (info->si_addr == (void *)-1) {
+	if (info->si_addr == (void __user *)-1) {
 		err = -EINVAL;
 		goto err_out;
 	}
@@ -525,15 +525,7 @@
 	if (!kernel_managing_mpx_tables(current->mm))
 		return -EINVAL;
 
-	if (do_mpx_bt_fault()) {
-		force_sig(SIGSEGV, current);
-		/*
-		 * The force_sig() is essentially "handling" this
-		 * exception, so we do not pass up the error
-		 * from do_mpx_bt_fault().
-		 */
-	}
-	return 0;
+	return do_mpx_bt_fault();
 }
 
 /*
@@ -544,10 +536,9 @@
 {
 	long gup_ret;
 	int nr_pages = 1;
-	int force = 0;
 
 	gup_ret = get_user_pages(current, current->mm, (unsigned long)addr,
-				 nr_pages, write, force, NULL, NULL);
+				 nr_pages, write ? FOLL_WRITE : 0, NULL, NULL);
 	/*
 	 * get_user_pages() returns number of pages gotten.
 	 * 0 means we failed to fault in and get anything,
--- linux-4.4.0.orig/arch/x86/mm/numa_32.c
+++ linux-4.4.0/arch/x86/mm/numa_32.c
@@ -100,5 +100,6 @@
 	printk(KERN_DEBUG "High memory starts at vaddr %08lx\n",
 			(ulong) pfn_to_kaddr(highstart_pfn));
 
+	__vmalloc_start_set = true;
 	setup_bootmem_allocator();
 }
--- linux-4.4.0.orig/arch/x86/mm/numa_emulation.c
+++ linux-4.4.0/arch/x86/mm/numa_emulation.c
@@ -60,7 +60,7 @@
 	eb->nid = nid;
 
 	if (emu_nid_to_phys[nid] == NUMA_NO_NODE)
-		emu_nid_to_phys[nid] = nid;
+		emu_nid_to_phys[nid] = pb->nid;
 
 	pb->start += size;
 	if (pb->start >= pb->end) {
--- linux-4.4.0.orig/arch/x86/mm/pageattr.c
+++ linux-4.4.0/arch/x86/mm/pageattr.c
@@ -33,7 +33,7 @@
 	pgd_t		*pgd;
 	pgprot_t	mask_set;
 	pgprot_t	mask_clr;
-	int		numpages;
+	unsigned long	numpages;
 	int		flags;
 	unsigned long	pfn;
 	unsigned	force_split : 1;
@@ -52,6 +52,7 @@
 #define CPA_FLUSHTLB 1
 #define CPA_ARRAY 2
 #define CPA_PAGES_ARRAY 4
+#define CPA_FREE_PAGETABLES 8
 
 #ifdef CONFIG_PROC_FS
 static unsigned long direct_pages_count[PG_LEVEL_NUM];
@@ -414,24 +415,30 @@
 phys_addr_t slow_virt_to_phys(void *__virt_addr)
 {
 	unsigned long virt_addr = (unsigned long)__virt_addr;
-	unsigned long phys_addr, offset;
+	phys_addr_t phys_addr;
+	unsigned long offset;
 	enum pg_level level;
 	pte_t *pte;
 
 	pte = lookup_address(virt_addr, &level);
 	BUG_ON(!pte);
 
+	/*
+	 * pXX_pfn() returns unsigned long, which must be cast to phys_addr_t
+	 * before being left-shifted PAGE_SHIFT bits -- this trick is to
+	 * make 32-PAE kernel work correctly.
+	 */
 	switch (level) {
 	case PG_LEVEL_1G:
-		phys_addr = pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PUD_PAGE_MASK;
 		break;
 	case PG_LEVEL_2M:
-		phys_addr = pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PMD_PAGE_MASK;
 		break;
 	default:
-		phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PAGE_MASK;
 	}
 
@@ -717,10 +724,13 @@
 	return 0;
 }
 
-static bool try_to_free_pte_page(pte_t *pte)
+static bool try_to_free_pte_page(struct cpa_data *cpa, pte_t *pte)
 {
 	int i;
 
+	if (!(cpa->flags & CPA_FREE_PAGETABLES))
+		return false;
+
 	for (i = 0; i < PTRS_PER_PTE; i++)
 		if (!pte_none(pte[i]))
 			return false;
@@ -729,10 +739,13 @@
 	return true;
 }
 
-static bool try_to_free_pmd_page(pmd_t *pmd)
+static bool try_to_free_pmd_page(struct cpa_data *cpa, pmd_t *pmd)
 {
 	int i;
 
+	if (!(cpa->flags & CPA_FREE_PAGETABLES))
+		return false;
+
 	for (i = 0; i < PTRS_PER_PMD; i++)
 		if (!pmd_none(pmd[i]))
 			return false;
@@ -753,7 +766,9 @@
 	return true;
 }
 
-static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end)
+static bool unmap_pte_range(struct cpa_data *cpa, pmd_t *pmd,
+			    unsigned long start,
+			    unsigned long end)
 {
 	pte_t *pte = pte_offset_kernel(pmd, start);
 
@@ -764,22 +779,23 @@
 		pte++;
 	}
 
-	if (try_to_free_pte_page((pte_t *)pmd_page_vaddr(*pmd))) {
+	if (try_to_free_pte_page(cpa, (pte_t *)pmd_page_vaddr(*pmd))) {
 		pmd_clear(pmd);
 		return true;
 	}
 	return false;
 }
 
-static void __unmap_pmd_range(pud_t *pud, pmd_t *pmd,
+static void __unmap_pmd_range(struct cpa_data *cpa, pud_t *pud, pmd_t *pmd,
 			      unsigned long start, unsigned long end)
 {
-	if (unmap_pte_range(pmd, start, end))
-		if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud)))
+	if (unmap_pte_range(cpa, pmd, start, end))
+		if (try_to_free_pmd_page(cpa, (pmd_t *)pud_page_vaddr(*pud)))
 			pud_clear(pud);
 }
 
-static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end)
+static void unmap_pmd_range(struct cpa_data *cpa, pud_t *pud,
+			    unsigned long start, unsigned long end)
 {
 	pmd_t *pmd = pmd_offset(pud, start);
 
@@ -790,7 +806,7 @@
 		unsigned long next_page = (start + PMD_SIZE) & PMD_MASK;
 		unsigned long pre_end = min_t(unsigned long, end, next_page);
 
-		__unmap_pmd_range(pud, pmd, start, pre_end);
+		__unmap_pmd_range(cpa, pud, pmd, start, pre_end);
 
 		start = pre_end;
 		pmd++;
@@ -803,7 +819,8 @@
 		if (pmd_large(*pmd))
 			pmd_clear(pmd);
 		else
-			__unmap_pmd_range(pud, pmd, start, start + PMD_SIZE);
+			__unmap_pmd_range(cpa, pud, pmd,
+					  start, start + PMD_SIZE);
 
 		start += PMD_SIZE;
 		pmd++;
@@ -813,17 +830,19 @@
 	 * 4K leftovers?
 	 */
 	if (start < end)
-		return __unmap_pmd_range(pud, pmd, start, end);
+		return __unmap_pmd_range(cpa, pud, pmd, start, end);
 
 	/*
 	 * Try again to free the PMD page if haven't succeeded above.
 	 */
 	if (!pud_none(*pud))
-		if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud)))
+		if (try_to_free_pmd_page(cpa, (pmd_t *)pud_page_vaddr(*pud)))
 			pud_clear(pud);
 }
 
-static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
+static void __unmap_pud_range(struct cpa_data *cpa, pgd_t *pgd,
+			      unsigned long start,
+			      unsigned long end)
 {
 	pud_t *pud = pud_offset(pgd, start);
 
@@ -834,7 +853,7 @@
 		unsigned long next_page = (start + PUD_SIZE) & PUD_MASK;
 		unsigned long pre_end	= min_t(unsigned long, end, next_page);
 
-		unmap_pmd_range(pud, start, pre_end);
+		unmap_pmd_range(cpa, pud, start, pre_end);
 
 		start = pre_end;
 		pud++;
@@ -848,7 +867,7 @@
 		if (pud_large(*pud))
 			pud_clear(pud);
 		else
-			unmap_pmd_range(pud, start, start + PUD_SIZE);
+			unmap_pmd_range(cpa, pud, start, start + PUD_SIZE);
 
 		start += PUD_SIZE;
 		pud++;
@@ -858,7 +877,7 @@
 	 * 2M leftovers?
 	 */
 	if (start < end)
-		unmap_pmd_range(pud, start, end);
+		unmap_pmd_range(cpa, pud, start, end);
 
 	/*
 	 * No need to try to free the PUD page because we'll free it in
@@ -866,6 +885,24 @@
 	 */
 }
 
+static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
+{
+	struct cpa_data cpa = {
+		.flags = CPA_FREE_PAGETABLES,
+	};
+
+	__unmap_pud_range(&cpa, pgd, start, end);
+}
+
+void unmap_pud_range_nofree(pgd_t *pgd, unsigned long start, unsigned long end)
+{
+	struct cpa_data cpa = {
+		.flags = 0,
+	};
+
+	__unmap_pud_range(&cpa, pgd, start, end);
+}
+
 static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end)
 {
 	pgd_t *pgd_entry = root + pgd_index(addr);
@@ -905,24 +942,19 @@
 	pte = pte_offset_kernel(pmd, start);
 
 	while (num_pages-- && start < end) {
-
-		/* deal with the NX bit */
-		if (!(pgprot_val(pgprot) & _PAGE_NX))
-			cpa->pfn &= ~_PAGE_NX;
-
-		set_pte(pte, pfn_pte(cpa->pfn >> PAGE_SHIFT, pgprot));
+		set_pte(pte, pfn_pte(cpa->pfn, pgprot));
 
 		start	 += PAGE_SIZE;
-		cpa->pfn += PAGE_SIZE;
+		cpa->pfn++;
 		pte++;
 	}
 }
 
-static int populate_pmd(struct cpa_data *cpa,
-			unsigned long start, unsigned long end,
-			unsigned num_pages, pud_t *pud, pgprot_t pgprot)
+static long populate_pmd(struct cpa_data *cpa,
+			 unsigned long start, unsigned long end,
+			 unsigned num_pages, pud_t *pud, pgprot_t pgprot)
 {
-	unsigned int cur_pages = 0;
+	long cur_pages = 0;
 	pmd_t *pmd;
 	pgprot_t pmd_pgprot;
 
@@ -969,11 +1001,11 @@
 
 		pmd = pmd_offset(pud, start);
 
-		set_pmd(pmd, __pmd(cpa->pfn | _PAGE_PSE |
-				   massage_pgprot(pmd_pgprot)));
+		set_pmd(pmd, pmd_mkhuge(pfn_pmd(cpa->pfn,
+				        canon_pgprot(pmd_pgprot))));
 
 		start	  += PMD_SIZE;
-		cpa->pfn  += PMD_SIZE;
+		cpa->pfn  += PMD_SIZE >> PAGE_SHIFT;
 		cur_pages += PMD_SIZE >> PAGE_SHIFT;
 	}
 
@@ -992,12 +1024,12 @@
 	return num_pages;
 }
 
-static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd,
-			pgprot_t pgprot)
+static long populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd,
+			 pgprot_t pgprot)
 {
 	pud_t *pud;
 	unsigned long end;
-	int cur_pages = 0;
+	long cur_pages = 0;
 	pgprot_t pud_pgprot;
 
 	end = start + (cpa->numpages << PAGE_SHIFT);
@@ -1042,18 +1074,18 @@
 	 * Map everything starting from the Gb boundary, possibly with 1G pages
 	 */
 	while (end - start >= PUD_SIZE) {
-		set_pud(pud, __pud(cpa->pfn | _PAGE_PSE |
-				   massage_pgprot(pud_pgprot)));
+		set_pud(pud, pud_mkhuge(pfn_pud(cpa->pfn,
+					canon_pgprot(pud_pgprot))));
 
 		start	  += PUD_SIZE;
-		cpa->pfn  += PUD_SIZE;
+		cpa->pfn  += PUD_SIZE >> PAGE_SHIFT;
 		cur_pages += PUD_SIZE >> PAGE_SHIFT;
 		pud++;
 	}
 
 	/* Map trailing leftover */
 	if (start < end) {
-		int tmp;
+		long tmp;
 
 		pud = pud_offset(pgd, start);
 		if (pud_none(*pud))
@@ -1079,7 +1111,7 @@
 	pgprot_t pgprot = __pgprot(_KERNPG_TABLE);
 	pud_t *pud = NULL;	/* shut up gcc */
 	pgd_t *pgd_entry;
-	int ret;
+	long ret;
 
 	pgd_entry = cpa->pgd + pgd_index(addr);
 
@@ -1314,7 +1346,8 @@
 
 static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
 {
-	int ret, numpages = cpa->numpages;
+	unsigned long numpages = cpa->numpages;
+	int ret;
 
 	while (numpages) {
 		/*
@@ -1345,7 +1378,7 @@
 		 * CPA operation. Either a large page has been
 		 * preserved or a single page update happened.
 		 */
-		BUG_ON(cpa->numpages > numpages);
+		BUG_ON(cpa->numpages > numpages || !cpa->numpages);
 		numpages -= cpa->numpages;
 		if (cpa->flags & (CPA_PAGES_ARRAY | CPA_ARRAY))
 			cpa->curpage++;
--- linux-4.4.0.orig/arch/x86/mm/pat.c
+++ linux-4.4.0/arch/x86/mm/pat.c
@@ -36,13 +36,22 @@
 #undef pr_fmt
 #define pr_fmt(fmt) "" fmt
 
-static bool boot_cpu_done;
+static bool __read_mostly boot_cpu_done;
+static bool __read_mostly pat_disabled = !IS_ENABLED(CONFIG_X86_PAT);
+static bool __read_mostly pat_initialized;
+static bool __read_mostly init_cm_done;
 
-static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT);
-
-static inline void pat_disable(const char *reason)
+void pat_disable(const char *reason)
 {
-	__pat_enabled = 0;
+	if (pat_disabled)
+		return;
+
+	if (boot_cpu_done) {
+		WARN_ONCE(1, "x86/PAT: PAT cannot be disabled after initialization\n");
+		return;
+	}
+
+	pat_disabled = true;
 	pr_info("x86/PAT: %s\n", reason);
 }
 
@@ -55,7 +64,7 @@
 
 bool pat_enabled(void)
 {
-	return !!__pat_enabled;
+	return pat_initialized;
 }
 EXPORT_SYMBOL_GPL(pat_enabled);
 
@@ -180,7 +189,7 @@
  * configuration.
  * Using lower indices is preferred, so we start with highest index.
  */
-void pat_init_cache_modes(u64 pat)
+static void __init_cache_modes(u64 pat)
 {
 	enum page_cache_mode cache;
 	char pat_msg[33];
@@ -193,6 +202,8 @@
 		update_cache_mode_entry(i, cache);
 	}
 	pr_info("x86/PAT: Configuration [0-7]: %s\n", pat_msg);
+
+	init_cm_done = true;
 }
 
 #define PAT(x, y)	((u64)PAT_ ## y << ((x)*8))
@@ -201,14 +212,11 @@
 {
 	u64 tmp_pat;
 
-	if (!cpu_has_pat) {
+	if (!boot_cpu_has(X86_FEATURE_PAT)) {
 		pat_disable("PAT not supported by CPU.");
 		return;
 	}
 
-	if (!pat_enabled())
-		goto done;
-
 	rdmsrl(MSR_IA32_CR_PAT, tmp_pat);
 	if (!tmp_pat) {
 		pat_disable("PAT MSR is 0, disabled.");
@@ -216,17 +224,14 @@
 	}
 
 	wrmsrl(MSR_IA32_CR_PAT, pat);
+	pat_initialized = true;
 
-done:
-	pat_init_cache_modes(pat);
+	__init_cache_modes(pat);
 }
 
 static void pat_ap_init(u64 pat)
 {
-	if (!pat_enabled())
-		return;
-
-	if (!cpu_has_pat) {
+	if (!boot_cpu_has(X86_FEATURE_PAT)) {
 		/*
 		 * If this happens we are on a secondary CPU, but switched to
 		 * PAT on the boot CPU. We have no way to undo PAT.
@@ -237,18 +242,31 @@
 	wrmsrl(MSR_IA32_CR_PAT, pat);
 }
 
-void pat_init(void)
+void init_cache_modes(void)
 {
-	u64 pat;
-	struct cpuinfo_x86 *c = &boot_cpu_data;
+	u64 pat = 0;
 
-	if (!pat_enabled()) {
+	if (init_cm_done)
+		return;
+
+	if (boot_cpu_has(X86_FEATURE_PAT)) {
+		/*
+		 * CPU supports PAT. Set PAT table to be consistent with
+		 * PAT MSR. This case supports "nopat" boot option, and
+		 * virtual machine environments which support PAT without
+		 * MTRRs. In specific, Xen has unique setup to PAT MSR.
+		 *
+		 * If PAT MSR returns 0, it is considered invalid and emulates
+		 * as No PAT.
+		 */
+		rdmsrl(MSR_IA32_CR_PAT, pat);
+	}
+
+	if (!pat) {
 		/*
 		 * No PAT. Emulate the PAT table that corresponds to the two
-		 * cache bits, PWT (Write Through) and PCD (Cache Disable). This
-		 * setup is the same as the BIOS default setup when the system
-		 * has PAT but the "nopat" boot option has been specified. This
-		 * emulated PAT table is used when MSR_IA32_CR_PAT returns 0.
+		 * cache bits, PWT (Write Through) and PCD (Cache Disable).
+		 * This setup is also the same as the BIOS default setup.
 		 *
 		 * PTE encoding:
 		 *
@@ -265,10 +283,32 @@
 		 */
 		pat = PAT(0, WB) | PAT(1, WT) | PAT(2, UC_MINUS) | PAT(3, UC) |
 		      PAT(4, WB) | PAT(5, WT) | PAT(6, UC_MINUS) | PAT(7, UC);
+	}
+
+	__init_cache_modes(pat);
+}
+
+/**
+ * pat_init - Initialize PAT MSR and PAT table
+ *
+ * This function initializes PAT MSR and PAT table with an OS-defined value
+ * to enable additional cache attributes, WC and WT.
+ *
+ * This function must be called on all CPUs using the specific sequence of
+ * operations defined in Intel SDM. mtrr_rendezvous_handler() provides this
+ * procedure for PAT.
+ */
+void pat_init(void)
+{
+	u64 pat;
+	struct cpuinfo_x86 *c = &boot_cpu_data;
 
-	} else if ((c->x86_vendor == X86_VENDOR_INTEL) &&
-		   (((c->x86 == 0x6) && (c->x86_model <= 0xd)) ||
-		    ((c->x86 == 0xf) && (c->x86_model <= 0x6)))) {
+	if (pat_disabled)
+		return;
+
+	if ((c->x86_vendor == X86_VENDOR_INTEL) &&
+	    (((c->x86 == 0x6) && (c->x86_model <= 0xd)) ||
+	     ((c->x86 == 0xf) && (c->x86_model <= 0x6)))) {
 		/*
 		 * PAT support with the lower four entries. Intel Pentium 2,
 		 * 3, M, and 4 are affected by PAT errata, which makes the
@@ -686,6 +726,20 @@
 	free_memtype(start, end);
 }
 
+int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size)
+{
+	enum page_cache_mode type = _PAGE_CACHE_MODE_WC;
+
+	return io_reserve_memtype(start, start + size, &type);
+}
+EXPORT_SYMBOL(arch_io_reserve_memtype_wc);
+
+void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size)
+{
+	io_free_memtype(start, start + size);
+}
+EXPORT_SYMBOL(arch_io_free_memtype_wc);
+
 pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
 				unsigned long size, pgprot_t vma_prot)
 {
@@ -710,11 +764,8 @@
 		return 1;
 
 	while (cursor < to) {
-		if (!devmem_is_allowed(pfn)) {
-			pr_info("x86/PAT: Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n",
-				current->comm, from, to - 1);
+		if (!devmem_is_allowed(pfn))
 			return 0;
-		}
 		cursor += PAGE_SIZE;
 		pfn++;
 	}
@@ -733,25 +784,6 @@
 	if (file->f_flags & O_DSYNC)
 		pcm = _PAGE_CACHE_MODE_UC_MINUS;
 
-#ifdef CONFIG_X86_32
-	/*
-	 * On the PPro and successors, the MTRRs are used to set
-	 * memory types for physical addresses outside main memory,
-	 * so blindly setting UC or PWT on those pages is wrong.
-	 * For Pentiums and earlier, the surround logic should disable
-	 * caching for the high addresses through the KEN pin, but
-	 * we maintain the tradition of paranoia in this code.
-	 */
-	if (!pat_enabled() &&
-	    !(boot_cpu_has(X86_FEATURE_MTRR) ||
-	      boot_cpu_has(X86_FEATURE_K6_MTRR) ||
-	      boot_cpu_has(X86_FEATURE_CYRIX_ARR) ||
-	      boot_cpu_has(X86_FEATURE_CENTAUR_MCR)) &&
-	    (pfn << PAGE_SHIFT) >= __pa(high_memory)) {
-		pcm = _PAGE_CACHE_MODE_UC;
-	}
-#endif
-
 	*vma_prot = __pgprot((pgprot_val(*vma_prot) & ~_PAGE_CACHE_MASK) |
 			     cachemode2protval(pcm));
 	return 1;
@@ -874,6 +906,38 @@
 		free_memtype(paddr, paddr + size);
 }
 
+static int get_pat_info(struct vm_area_struct *vma, resource_size_t *paddr,
+		pgprot_t *pgprot)
+{
+	unsigned long prot;
+
+	VM_WARN_ON_ONCE(!(vma->vm_flags & VM_PAT));
+
+	/*
+	 * We need the starting PFN and cachemode used for track_pfn_remap()
+	 * that covered the whole VMA. For most mappings, we can obtain that
+	 * information from the page tables. For COW mappings, we might now
+	 * suddenly have anon folios mapped and follow_phys() will fail.
+	 *
+	 * Fallback to using vma->vm_pgoff, see remap_pfn_range_notrack(), to
+	 * detect the PFN. If we need the cachemode as well, we're out of luck
+	 * for now and have to fail fork().
+	 */
+	if (!follow_phys(vma, vma->vm_start, 0, &prot, paddr)) {
+		if (pgprot)
+			*pgprot = __pgprot(prot);
+		return 0;
+	}
+	if (is_cow_mapping(vma->vm_flags)) {
+		if (pgprot)
+			return -EINVAL;
+		*paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
+		return 0;
+	}
+	WARN_ON_ONCE(1);
+	return -EINVAL;
+}
+
 /*
  * track_pfn_copy is called when vma that is covering the pfnmap gets
  * copied through copy_page_range().
@@ -884,20 +948,13 @@
 int track_pfn_copy(struct vm_area_struct *vma)
 {
 	resource_size_t paddr;
-	unsigned long prot;
 	unsigned long vma_size = vma->vm_end - vma->vm_start;
 	pgprot_t pgprot;
 
 	if (vma->vm_flags & VM_PAT) {
-		/*
-		 * reserve the whole chunk covered by vma. We need the
-		 * starting address and protection from pte.
-		 */
-		if (follow_phys(vma, vma->vm_start, 0, &prot, &paddr)) {
-			WARN_ON_ONCE(1);
+		if (get_pat_info(vma, &paddr, &pgprot))
 			return -EINVAL;
-		}
-		pgprot = __pgprot(prot);
+		/* reserve the whole chunk covered by vma. */
 		return reserve_pfn_range(paddr, vma_size, &pgprot, 1);
 	}
 
@@ -973,7 +1030,6 @@
 		 unsigned long size)
 {
 	resource_size_t paddr;
-	unsigned long prot;
 
 	if (!(vma->vm_flags & VM_PAT))
 		return;
@@ -981,11 +1037,8 @@
 	/* free the chunk starting from pfn or the whole chunk */
 	paddr = (resource_size_t)pfn << PAGE_SHIFT;
 	if (!paddr && !size) {
-		if (follow_phys(vma, vma->vm_start, 0, &prot, &paddr)) {
-			WARN_ON_ONCE(1);
+		if (get_pat_info(vma, &paddr, NULL))
 			return;
-		}
-
 		size = vma->vm_end - vma->vm_start;
 	}
 	free_pfn_range(paddr, size);
--- linux-4.4.0.orig/arch/x86/mm/pgtable.c
+++ linux-4.4.0/arch/x86/mm/pgtable.c
@@ -1,12 +1,13 @@
 #include <linux/mm.h>
 #include <linux/gfp.h>
+#include <linux/hugetlb.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/tlb.h>
 #include <asm/fixmap.h>
 #include <asm/mtrr.h>
 
-#define PGALLOC_GFP GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO
+#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
 
 #ifdef CONFIG_HIGHPTE
 #define PGALLOC_USER_GFP __GFP_HIGHMEM
@@ -246,7 +247,7 @@
 		if (pgd_val(pgd) != 0) {
 			pmd_t *pmd = (pmd_t *)pgd_page_vaddr(pgd);
 
-			pgdp[i] = native_make_pgd(0);
+			pgd_clear(&pgdp[i]);
 
 			paravirt_release_pmd(pgd_val(pgd) >> PAGE_SHIFT);
 			pmd_free(mm, pmd);
@@ -340,14 +341,24 @@
 		kmem_cache_free(pgd_cache, pgd);
 }
 #else
+
+/*
+ * Instead of one pgd, Kaiser acquires two pgds.  Being order-1, it is
+ * both 8k in size and 8k-aligned.  That lets us just flip bit 12
+ * in a pointer to swap between the two 4k halves.
+ */
+#define PGD_ALLOCATION_ORDER	kaiser_enabled
+
 static inline pgd_t *_pgd_alloc(void)
 {
-	return (pgd_t *)__get_free_page(PGALLOC_GFP);
+	/* No __GFP_REPEAT: to avoid page allocation stalls in order-1 case */
+	return (pgd_t *)__get_free_pages(PGALLOC_GFP & ~__GFP_REPEAT,
+					 PGD_ALLOCATION_ORDER);
 }
 
 static inline void _pgd_free(pgd_t *pgd)
 {
-	free_page((unsigned long)pgd);
+	free_pages((unsigned long)pgd, PGD_ALLOCATION_ORDER);
 }
 #endif /* CONFIG_X86_PAE */
 
@@ -413,7 +424,7 @@
 	int changed = !pte_same(*ptep, entry);
 
 	if (changed && dirty) {
-		*ptep = entry;
+		set_pte(ptep, entry);
 		pte_update_defer(vma->vm_mm, address, ptep);
 	}
 
@@ -430,7 +441,7 @@
 	VM_BUG_ON(address & ~HPAGE_PMD_MASK);
 
 	if (changed && dirty) {
-		*pmdp = entry;
+		set_pmd(pmdp, entry);
 		pmd_update_defer(vma->vm_mm, address, pmdp);
 		/*
 		 * We had a write-protection fault here and changed the pmd
@@ -556,8 +567,8 @@
 	fixmaps_set++;
 }
 
-void native_set_fixmap(enum fixed_addresses idx, phys_addr_t phys,
-		       pgprot_t flags)
+void native_set_fixmap(unsigned /* enum fixed_addresses */ idx,
+		       phys_addr_t phys, pgprot_t flags)
 {
 	__native_set_fixmap(idx, pfn_pte(phys >> PAGE_SHIFT, flags));
 }
@@ -590,6 +601,10 @@
 	    (mtrr != MTRR_TYPE_WRBACK))
 		return 0;
 
+	/* Bail out if we are we on a populated non-leaf entry: */
+	if (pud_present(*pud) && !pud_huge(*pud))
+		return 0;
+
 	prot = pgprot_4k_2_large(prot);
 
 	set_pte((pte_t *)pud, pfn_pte(
@@ -618,6 +633,10 @@
 		return 0;
 	}
 
+	/* Bail out if we are we on a populated non-leaf entry: */
+	if (pmd_present(*pmd) && !pmd_huge(*pmd))
+		return 0;
+
 	prot = pgprot_4k_2_large(prot);
 
 	set_pte((pte_t *)pmd, pfn_pte(
@@ -656,4 +675,99 @@
 
 	return 0;
 }
+
+#ifdef CONFIG_X86_64
+/**
+ * pud_free_pmd_page - Clear pud entry and free pmd page.
+ * @pud: Pointer to a PUD.
+ * @addr: Virtual address associated with pud.
+ *
+ * Context: The pud range has been unmapped and TLB purged.
+ * Return: 1 if clearing the entry succeeded. 0 otherwise.
+ *
+ * NOTE: Callers must allow a single page allocation.
+ */
+int pud_free_pmd_page(pud_t *pud, unsigned long addr)
+{
+	pmd_t *pmd, *pmd_sv;
+	pte_t *pte;
+	int i;
+
+	if (pud_none(*pud))
+		return 1;
+
+	pmd = (pmd_t *)pud_page_vaddr(*pud);
+	pmd_sv = (pmd_t *)__get_free_page(GFP_KERNEL);
+	if (!pmd_sv)
+		return 0;
+
+	for (i = 0; i < PTRS_PER_PMD; i++) {
+		pmd_sv[i] = pmd[i];
+		if (!pmd_none(pmd[i]))
+			pmd_clear(&pmd[i]);
+	}
+
+	pud_clear(pud);
+
+	/* INVLPG to clear all paging-structure caches */
+	flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1);
+
+	for (i = 0; i < PTRS_PER_PMD; i++) {
+		if (!pmd_none(pmd_sv[i])) {
+			pte = (pte_t *)pmd_page_vaddr(pmd_sv[i]);
+			free_page((unsigned long)pte);
+		}
+	}
+
+	free_page((unsigned long)pmd_sv);
+
+	pgtable_pmd_page_dtor(virt_to_page(pmd));
+	free_page((unsigned long)pmd);
+
+	return 1;
+}
+
+/**
+ * pmd_free_pte_page - Clear pmd entry and free pte page.
+ * @pmd: Pointer to a PMD.
+ * @addr: Virtual address associated with pmd.
+ *
+ * Context: The pmd range has been unmapped and TLB purged.
+ * Return: 1 if clearing the entry succeeded. 0 otherwise.
+ */
+int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
+{
+	pte_t *pte;
+
+	if (pmd_none(*pmd))
+		return 1;
+
+	pte = (pte_t *)pmd_page_vaddr(*pmd);
+	pmd_clear(pmd);
+
+	/* INVLPG to clear all paging-structure caches */
+	flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1);
+
+	free_page((unsigned long)pte);
+
+	return 1;
+}
+
+#else /* !CONFIG_X86_64 */
+
+int pud_free_pmd_page(pud_t *pud, unsigned long addr)
+{
+	return pud_none(*pud);
+}
+
+/*
+ * Disable free page handling on x86-PAE. This assures that ioremap()
+ * does not update sync'd pmd entries. See vmalloc_sync_one().
+ */
+int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
+{
+	return pmd_none(*pmd);
+}
+
+#endif /* CONFIG_X86_64 */
 #endif	/* CONFIG_HAVE_ARCH_HUGE_VMAP */
--- linux-4.4.0.orig/arch/x86/mm/setup_nx.c
+++ linux-4.4.0/arch/x86/mm/setup_nx.c
@@ -4,6 +4,7 @@
 
 #include <asm/pgtable.h>
 #include <asm/proto.h>
+#include <asm/cpufeature.h>
 
 static int disable_nx;
 
@@ -31,7 +32,7 @@
 
 void x86_configure_nx(void)
 {
-	if (cpu_has_nx && !disable_nx)
+	if (boot_cpu_has(X86_FEATURE_NX) && !disable_nx)
 		__supported_pte_mask |= _PAGE_NX;
 	else
 		__supported_pte_mask &= ~_PAGE_NX;
@@ -39,7 +40,7 @@
 
 void __init x86_report_nx(void)
 {
-	if (!cpu_has_nx) {
+	if (!boot_cpu_has(X86_FEATURE_NX)) {
 		printk(KERN_NOTICE "Notice: NX (Execute Disable) protection "
 		       "missing in CPU!\n");
 	} else {
--- linux-4.4.0.orig/arch/x86/mm/testmmiotrace.c
+++ linux-4.4.0/arch/x86/mm/testmmiotrace.c
@@ -9,7 +9,7 @@
 #include <linux/mmiotrace.h>
 
 static unsigned long mmio_address;
-module_param(mmio_address, ulong, 0);
+module_param_hw(mmio_address, ulong, iomem, 0);
 MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB "
 				"(or 8 MB if read_far is non-zero).");
 
@@ -115,6 +115,9 @@
 {
 	unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
 
+	if (secure_modules())
+		return -EPERM;
+
 	if (mmio_address == 0) {
 		pr_err("you have to use the module argument mmio_address.\n");
 		pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n");
--- linux-4.4.0.orig/arch/x86/mm/tlb.c
+++ linux-4.4.0/arch/x86/mm/tlb.c
@@ -6,16 +6,19 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/cpu.h>
+#include <linux/debugfs.h>
 
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
+#include <asm/nospec-branch.h>
 #include <asm/cache.h>
 #include <asm/apic.h>
 #include <asm/uv/uv.h>
-#include <linux/debugfs.h>
+#include <asm/kaiser.h>
+#include <asm/microcode.h>
 
 /*
- *	Smarter SMP flushing macros.
+ *	TLB flushing, formerly SMP-only
  *		c/o Linus Torvalds.
  *
  *	These mean you can really definitely utterly forget about
@@ -28,12 +31,50 @@
  *	Implement flush IPI by CALL_FUNCTION_VECTOR, Alex Shi
  */
 
+/*
+ * Use bit 0 to mangle the TIF_SPEC_IB state into the mm pointer which is
+ * stored in cpu_tlb_state.last_user_mm_ibpb.
+ */
+#define LAST_USER_MM_IBPB	0x1UL
+
+atomic64_t last_mm_ctx_id = ATOMIC64_INIT(1);
+
 struct flush_tlb_info {
 	struct mm_struct *flush_mm;
 	unsigned long flush_start;
 	unsigned long flush_end;
 };
 
+static void load_new_mm_cr3(pgd_t *pgdir)
+{
+	unsigned long new_mm_cr3 = __pa(pgdir);
+
+	if (kaiser_enabled) {
+		/*
+		 * We reuse the same PCID for different tasks, so we must
+		 * flush all the entries for the PCID out when we change tasks.
+		 * Flush KERN below, flush USER when returning to userspace in
+		 * kaiser's SWITCH_USER_CR3 (_SWITCH_TO_USER_CR3) macro.
+		 *
+		 * invpcid_flush_single_context(X86_CR3_PCID_ASID_USER) could
+		 * do it here, but can only be used if X86_FEATURE_INVPCID is
+		 * available - and many machines support pcid without invpcid.
+		 *
+		 * If X86_CR3_PCID_KERN_FLUSH actually added something, then it
+		 * would be needed in the write_cr3() below - if PCIDs enabled.
+		 */
+		BUILD_BUG_ON(X86_CR3_PCID_KERN_FLUSH);
+		kaiser_flush_tlb_on_return_to_user();
+	}
+
+	/*
+	 * Caution: many callers of this function expect
+	 * that load_cr3() is serializing and orders TLB
+	 * fills with respect to the mm_cpumask writes.
+	 */
+	write_cr3(new_mm_cr3);
+}
+
 /*
  * We cannot call mmdrop() because we are in interrupt context,
  * instead update mm->cpu_vm_mask.
@@ -45,7 +86,7 @@
 		BUG();
 	if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) {
 		cpumask_clear_cpu(cpu, mm_cpumask(active_mm));
-		load_cr3(swapper_pg_dir);
+		load_new_mm_cr3(swapper_pg_dir);
 		/*
 		 * This gets called in the idle path where RCU
 		 * functions differently.  Tracing normally
@@ -57,6 +98,199 @@
 }
 EXPORT_SYMBOL_GPL(leave_mm);
 
+void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+	       struct task_struct *tsk)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	switch_mm_irqs_off(prev, next, tsk);
+	local_irq_restore(flags);
+}
+
+static inline unsigned long mm_mangle_tif_spec_ib(struct task_struct *next)
+{
+	unsigned long next_tif = task_thread_info(next)->flags;
+	unsigned long ibpb = (next_tif >> TIF_SPEC_IB) & LAST_USER_MM_IBPB;
+
+	return (unsigned long)next->mm | ibpb;
+}
+
+static void cond_ibpb(struct task_struct *next)
+{
+	if (!next || !next->mm)
+		return;
+
+	/*
+	 * Both, the conditional and the always IBPB mode use the mm
+	 * pointer to avoid the IBPB when switching between tasks of the
+	 * same process. Using the mm pointer instead of mm->context.ctx_id
+	 * opens a hypothetical hole vs. mm_struct reuse, which is more or
+	 * less impossible to control by an attacker. Aside of that it
+	 * would only affect the first schedule so the theoretically
+	 * exposed data is not really interesting.
+	 */
+	if (static_branch_likely(&switch_mm_cond_ibpb)) {
+		unsigned long prev_mm, next_mm;
+
+		/*
+		 * This is a bit more complex than the always mode because
+		 * it has to handle two cases:
+		 *
+		 * 1) Switch from a user space task (potential attacker)
+		 *    which has TIF_SPEC_IB set to a user space task
+		 *    (potential victim) which has TIF_SPEC_IB not set.
+		 *
+		 * 2) Switch from a user space task (potential attacker)
+		 *    which has TIF_SPEC_IB not set to a user space task
+		 *    (potential victim) which has TIF_SPEC_IB set.
+		 *
+		 * This could be done by unconditionally issuing IBPB when
+		 * a task which has TIF_SPEC_IB set is either scheduled in
+		 * or out. Though that results in two flushes when:
+		 *
+		 * - the same user space task is scheduled out and later
+		 *   scheduled in again and only a kernel thread ran in
+		 *   between.
+		 *
+		 * - a user space task belonging to the same process is
+		 *   scheduled in after a kernel thread ran in between
+		 *
+		 * - a user space task belonging to the same process is
+		 *   scheduled in immediately.
+		 *
+		 * Optimize this with reasonably small overhead for the
+		 * above cases. Mangle the TIF_SPEC_IB bit into the mm
+		 * pointer of the incoming task which is stored in
+		 * cpu_tlbstate.last_user_mm_ibpb for comparison.
+		 */
+		next_mm = mm_mangle_tif_spec_ib(next);
+		prev_mm = this_cpu_read(cpu_tlbstate.last_user_mm_ibpb);
+
+		/*
+		 * Issue IBPB only if the mm's are different and one or
+		 * both have the IBPB bit set.
+		 */
+		if (next_mm != prev_mm &&
+		    (next_mm | prev_mm) & LAST_USER_MM_IBPB)
+			indirect_branch_prediction_barrier();
+
+		this_cpu_write(cpu_tlbstate.last_user_mm_ibpb, next_mm);
+	}
+
+	if (static_branch_unlikely(&switch_mm_always_ibpb)) {
+		/*
+		 * Only flush when switching to a user space task with a
+		 * different context than the user space task which ran
+		 * last on this CPU.
+		 */
+		if (this_cpu_read(cpu_tlbstate.last_user_mm) != next->mm) {
+			indirect_branch_prediction_barrier();
+			this_cpu_write(cpu_tlbstate.last_user_mm, next->mm);
+		}
+	}
+}
+
+void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
+			struct task_struct *tsk)
+{
+	unsigned cpu = smp_processor_id();
+
+	if (likely(prev != next)) {
+		/*
+		 * Avoid user/user BTB poisoning by flushing the branch
+		 * predictor when switching between processes. This stops
+		 * one process from doing Spectre-v2 attacks on another.
+		 */
+		cond_ibpb(tsk);
+
+		this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+		this_cpu_write(cpu_tlbstate.active_mm, next);
+		cpumask_set_cpu(cpu, mm_cpumask(next));
+
+		/*
+		 * Re-load page tables.
+		 *
+		 * This logic has an ordering constraint:
+		 *
+		 *  CPU 0: Write to a PTE for 'next'
+		 *  CPU 0: load bit 1 in mm_cpumask.  if nonzero, send IPI.
+		 *  CPU 1: set bit 1 in next's mm_cpumask
+		 *  CPU 1: load from the PTE that CPU 0 writes (implicit)
+		 *
+		 * We need to prevent an outcome in which CPU 1 observes
+		 * the new PTE value and CPU 0 observes bit 1 clear in
+		 * mm_cpumask.  (If that occurs, then the IPI will never
+		 * be sent, and CPU 0's TLB will contain a stale entry.)
+		 *
+		 * The bad outcome can occur if either CPU's load is
+		 * reordered before that CPU's store, so both CPUs must
+		 * execute full barriers to prevent this from happening.
+		 *
+		 * Thus, switch_mm needs a full barrier between the
+		 * store to mm_cpumask and any operation that could load
+		 * from next->pgd.  TLB fills are special and can happen
+		 * due to instruction fetches or for no reason at all,
+		 * and neither LOCK nor MFENCE orders them.
+		 * Fortunately, load_cr3() is serializing and gives the
+		 * ordering guarantee we need.
+		 *
+		 */
+		load_new_mm_cr3(next->pgd);
+
+		trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
+
+		/* Stop flush ipis for the previous mm */
+		cpumask_clear_cpu(cpu, mm_cpumask(prev));
+
+		/* Load per-mm CR4 state */
+		load_mm_cr4(next);
+
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+		/*
+		 * Load the LDT, if the LDT is different.
+		 *
+		 * It's possible that prev->context.ldt doesn't match
+		 * the LDT register.  This can happen if leave_mm(prev)
+		 * was called and then modify_ldt changed
+		 * prev->context.ldt but suppressed an IPI to this CPU.
+		 * In this case, prev->context.ldt != NULL, because we
+		 * never set context.ldt to NULL while the mm still
+		 * exists.  That means that next->context.ldt !=
+		 * prev->context.ldt, because mms never share an LDT.
+		 */
+		if (unlikely(prev->context.ldt != next->context.ldt))
+			load_mm_ldt(next);
+#endif
+	} else {
+		this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+		BUG_ON(this_cpu_read(cpu_tlbstate.active_mm) != next);
+
+		if (!cpumask_test_cpu(cpu, mm_cpumask(next))) {
+			/*
+			 * On established mms, the mm_cpumask is only changed
+			 * from irq context, from ptep_clear_flush() while in
+			 * lazy tlb mode, and here. Irqs are blocked during
+			 * schedule, protecting us from simultaneous changes.
+			 */
+			cpumask_set_cpu(cpu, mm_cpumask(next));
+
+			/*
+			 * We were in lazy tlb mode and leave_mm disabled
+			 * tlb flush IPI delivery. We must reload CR3
+			 * to make sure to use no freed page tables.
+			 *
+			 * As above, load_cr3() is serializing and orders TLB
+			 * fills with respect to the mm_cpumask write.
+			 */
+			load_new_mm_cr3(next->pgd);
+			trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
+			load_mm_cr4(next);
+			load_mm_ldt(next);
+		}
+	}
+}
+
 /*
  * The flush IPI assumes that a thread switch happens in this order:
  * [cpu0: the cpu that switches]
@@ -104,10 +338,8 @@
 
 	inc_irq_stat(irq_tlb_count);
 
-	if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm))
+	if (f->flush_mm && f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm))
 		return;
-	if (!f->flush_end)
-		f->flush_end = f->flush_start + PAGE_SIZE;
 
 	count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
 	if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
@@ -135,12 +367,18 @@
 				 unsigned long end)
 {
 	struct flush_tlb_info info;
+
 	info.flush_mm = mm;
 	info.flush_start = start;
 	info.flush_end = end;
 
 	count_vm_tlb_event(NR_TLB_REMOTE_FLUSH);
-	trace_tlb_flush(TLB_REMOTE_SEND_IPI, end - start);
+	if (end == TLB_FLUSH_ALL)
+		trace_tlb_flush(TLB_REMOTE_SEND_IPI, TLB_FLUSH_ALL);
+	else
+		trace_tlb_flush(TLB_REMOTE_SEND_IPI,
+				(end - start) >> PAGE_SHIFT);
+
 	if (is_uv_system()) {
 		unsigned int cpu;
 
@@ -154,20 +392,6 @@
 	smp_call_function_many(cpumask, flush_tlb_func, &info, 1);
 }
 
-void flush_tlb_current_task(void)
-{
-	struct mm_struct *mm = current->mm;
-
-	preempt_disable();
-
-	count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
-	local_flush_tlb();
-	trace_tlb_flush(TLB_LOCAL_SHOOTDOWN, TLB_FLUSH_ALL);
-	if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
-		flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL);
-	preempt_enable();
-}
-
 /*
  * See Documentation/x86/tlb.txt for details.  We choose 33
  * because it is large enough to cover the vast majority (at
@@ -188,19 +412,33 @@
 	unsigned long base_pages_to_flush = TLB_FLUSH_ALL;
 
 	preempt_disable();
-	if (current->active_mm != mm)
+
+	if ((end != TLB_FLUSH_ALL) && !(vmflag & VM_HUGETLB))
+		base_pages_to_flush = (end - start) >> PAGE_SHIFT;
+	if (base_pages_to_flush > tlb_single_page_flush_ceiling)
+		base_pages_to_flush = TLB_FLUSH_ALL;
+
+	if (current->active_mm != mm) {
+		/* Synchronize with switch_mm. */
+		smp_mb();
+
 		goto out;
+	}
 
 	if (!current->mm) {
 		leave_mm(smp_processor_id());
+
+		/* Synchronize with switch_mm. */
+		smp_mb();
+
 		goto out;
 	}
 
-	if ((end != TLB_FLUSH_ALL) && !(vmflag & VM_HUGETLB))
-		base_pages_to_flush = (end - start) >> PAGE_SHIFT;
-
-	if (base_pages_to_flush > tlb_single_page_flush_ceiling) {
-		base_pages_to_flush = TLB_FLUSH_ALL;
+	/*
+	 * Both branches below are implicit full barriers (MOV to CR or
+	 * INVLPG) that synchronize with switch_mm.
+	 */
+	if (base_pages_to_flush == TLB_FLUSH_ALL) {
 		count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
 		local_flush_tlb();
 	} else {
@@ -221,25 +459,6 @@
 	preempt_enable();
 }
 
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long start)
-{
-	struct mm_struct *mm = vma->vm_mm;
-
-	preempt_disable();
-
-	if (current->active_mm == mm) {
-		if (current->mm)
-			__flush_tlb_one(start);
-		else
-			leave_mm(smp_processor_id());
-	}
-
-	if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
-		flush_tlb_others(mm_cpumask(mm), mm, start, 0UL);
-
-	preempt_enable();
-}
-
 static void do_flush_tlb_all(void *info)
 {
 	count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
--- linux-4.4.0.orig/arch/x86/net/bpf_jit_comp.c
+++ linux-4.4.0/arch/x86/net/bpf_jit_comp.c
@@ -12,9 +12,11 @@
 #include <linux/filter.h>
 #include <linux/if_vlan.h>
 #include <asm/cacheflush.h>
+#include <asm/nospec-branch.h>
 #include <linux/bpf.h>
 
 int bpf_jit_enable __read_mostly;
+u8 bpf_jit_fence = 0;
 
 /*
  * assembly code in arch/x86/net/bpf_jit.S
@@ -106,6 +108,18 @@
 	set_fs(old_fs);
 }
 
+static void emit_memory_barrier(u8 **pprog)
+{
+	u8 *prog = *pprog;
+	int cnt = 0;
+
+	if (bpf_jit_fence)
+			EMIT3(0x0f, 0xae, 0xe8);
+
+	*pprog = prog;
+	return;
+}
+
 #define CHOOSE_LOAD_FUNC(K, func) \
 	((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
 
@@ -144,6 +158,19 @@
 			     BIT(BPF_REG_9));
 }
 
+/*
+ * is_ereg_8l() == true if BPF register 'reg' is mapped to access x86-64
+ * lower 8-bit registers dil,sil,bpl,spl,r8b..r15b, which need extra byte
+ * of encoding. al,cl,dl,bl have simpler encoding.
+ */
+static bool is_ereg_8l(u32 reg)
+{
+	return is_ereg(reg) ||
+	    (1 << reg) & (BIT(BPF_REG_1) |
+			  BIT(BPF_REG_2) |
+			  BIT(BPF_REG_FP));
+}
+
 /* add modifiers if 'reg' maps to x64 registers r8..r15 */
 static u8 add_1mod(u8 byte, u32 reg)
 {
@@ -266,10 +293,10 @@
 	/* if (index >= array->map.max_entries)
 	 *   goto out;
 	 */
-	EMIT4(0x48, 0x8B, 0x46,                   /* mov rax, qword ptr [rsi + 16] */
+	EMIT2(0x89, 0xD2);                        /* mov edx, edx */
+	EMIT3(0x39, 0x56,                         /* cmp dword ptr [rsi + 16], edx */
 	      offsetof(struct bpf_array, map.max_entries));
-	EMIT3(0x48, 0x39, 0xD0);                  /* cmp rax, rdx */
-#define OFFSET1 47 /* number of bytes to jump */
+#define OFFSET1 (41 + RETPOLINE_RAX_BPF_JIT_SIZE) /* number of bytes to jump */
 	EMIT2(X86_JBE, OFFSET1);                  /* jbe out */
 	label1 = cnt;
 
@@ -278,22 +305,21 @@
 	 */
 	EMIT2_off32(0x8B, 0x85, -STACKSIZE + 36); /* mov eax, dword ptr [rbp - 516] */
 	EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT);     /* cmp eax, MAX_TAIL_CALL_CNT */
-#define OFFSET2 36
+#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE)
 	EMIT2(X86_JA, OFFSET2);                   /* ja out */
 	label2 = cnt;
 	EMIT3(0x83, 0xC0, 0x01);                  /* add eax, 1 */
 	EMIT2_off32(0x89, 0x85, -STACKSIZE + 36); /* mov dword ptr [rbp - 516], eax */
 
 	/* prog = array->ptrs[index]; */
-	EMIT4_off32(0x48, 0x8D, 0x84, 0xD6,       /* lea rax, [rsi + rdx * 8 + offsetof(...)] */
+	EMIT4_off32(0x48, 0x8B, 0x84, 0xD6,       /* mov rax, [rsi + rdx * 8 + offsetof(...)] */
 		    offsetof(struct bpf_array, ptrs));
-	EMIT3(0x48, 0x8B, 0x00);                  /* mov rax, qword ptr [rax] */
 
 	/* if (prog == NULL)
 	 *   goto out;
 	 */
-	EMIT4(0x48, 0x83, 0xF8, 0x00);            /* cmp rax, 0 */
-#define OFFSET3 10
+	EMIT3(0x48, 0x85, 0xC0);		  /* test rax,rax */
+#define OFFSET3 (8 + RETPOLINE_RAX_BPF_JIT_SIZE)
 	EMIT2(X86_JE, OFFSET3);                   /* je out */
 	label3 = cnt;
 
@@ -306,7 +332,7 @@
 	 * rdi == ctx (1st arg)
 	 * rax == prog->bpf_func + prologue_size
 	 */
-	EMIT2(0xFF, 0xE0);                        /* jmp rax */
+	RETPOLINE_RAX_BPF_JIT();
 
 	/* out: */
 	BUILD_BUG_ON(cnt - label1 != OFFSET1);
@@ -379,7 +405,7 @@
 			case BPF_ADD: b2 = 0x01; break;
 			case BPF_SUB: b2 = 0x29; break;
 			case BPF_AND: b2 = 0x21; break;
-			case BPF_OR: b2 = 0x09; break;
+			case BPF_OR: b2 = 0x09; emit_memory_barrier(&prog); break;
 			case BPF_XOR: b2 = 0x31; break;
 			}
 			if (BPF_CLASS(insn->code) == BPF_ALU64)
@@ -607,6 +633,16 @@
 		case BPF_ALU64 | BPF_RSH | BPF_X:
 		case BPF_ALU64 | BPF_ARSH | BPF_X:
 
+			/* If blinding is enabled, each
+			 * BPF_LD | BPF_IMM | BPF_DW instruction
+			 * is converted to 4 eBPF instructions with
+			 * BPF_ALU64_IMM(BPF_LSH, BPF_REG_AX, 32)
+			 * always present(number 3). Detect such cases
+			 * and insert memory barriers. */
+			if ((BPF_CLASS(insn->code) == BPF_ALU64)
+				&& (BPF_OP(insn->code) == BPF_LSH)
+				&& (src_reg == BPF_REG_AX))
+				emit_memory_barrier(&prog);
 			/* check for bad case when dst_reg == rcx */
 			if (dst_reg == BPF_REG_4) {
 				/* mov r11, dst_reg */
@@ -731,9 +767,8 @@
 			/* STX: *(u8*)(dst_reg + off) = src_reg */
 		case BPF_STX | BPF_MEM | BPF_B:
 			/* emit 'mov byte ptr [rax + off], al' */
-			if (is_ereg(dst_reg) || is_ereg(src_reg) ||
-			    /* have to add extra byte for x86 SIL, DIL regs */
-			    src_reg == BPF_REG_1 || src_reg == BPF_REG_2)
+			if (is_ereg(dst_reg) || is_ereg_8l(src_reg))
+				/* Add extra byte for eregs or SIL,DIL,BPL in src_reg */
 				EMIT2(add_2mod(0x40, dst_reg, src_reg), 0x88);
 			else
 				EMIT1(0x88);
@@ -1026,8 +1061,17 @@
 		}
 
 		if (image) {
-			if (unlikely(proglen + ilen > oldproglen)) {
-				pr_err("bpf_jit_compile fatal error\n");
+			/*
+			 * When populating the image, assert that:
+			 *
+			 *  i) We do not write beyond the allocated space, and
+			 * ii) addrs[i] did not change from the prior run, in order
+			 *     to validate assumptions made for computing branch
+			 *     displacements.
+			 */
+			if (unlikely(proglen + ilen > oldproglen ||
+				     proglen + ilen != addrs[i])) {
+				pr_err("bpf_jit: fatal error\n");
 				return -EFAULT;
 			}
 			memcpy(image + proglen, temp, ilen);
@@ -1043,7 +1087,7 @@
 {
 }
 
-void bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
 {
 	struct bpf_binary_header *header = NULL;
 	int proglen, oldproglen = 0;
@@ -1054,14 +1098,17 @@
 	int i;
 
 	if (!bpf_jit_enable)
-		return;
+		return prog;
 
 	if (!prog || !prog->len)
-		return;
+		return prog;
+
+	if (bpf_jit_fence_present() && bpf_jit_blinding_enabled())
+		bpf_jit_fence = 1;
 
 	addrs = kmalloc(prog->len * sizeof(*addrs), GFP_KERNEL);
 	if (!addrs)
-		return;
+		return prog;
 
 	/* Before first pass, make a rough estimation of addrs[]
 	 * each bpf instruction is translated to less than 64 bytes
@@ -1077,7 +1124,7 @@
 	 * may converge on the last pass. In such case do one more
 	 * pass to emit the final image
 	 */
-	for (pass = 0; pass < 10 || image; pass++) {
+	for (pass = 0; pass < 20 || image; pass++) {
 		proglen = do_jit(prog, addrs, image, oldproglen, &ctx);
 		if (proglen <= 0) {
 			image = NULL;
@@ -1100,6 +1147,7 @@
 				goto out;
 		}
 		oldproglen = proglen;
+		cond_resched();
 	}
 
 	if (bpf_jit_enable > 1)
@@ -1113,6 +1161,7 @@
 	}
 out:
 	kfree(addrs);
+	return prog;
 }
 
 void bpf_jit_free(struct bpf_prog *fp)
--- linux-4.4.0.orig/arch/x86/oprofile/nmi_int.c
+++ linux-4.4.0/arch/x86/oprofile/nmi_int.c
@@ -471,7 +471,7 @@
 		goto fail;
 
 	for_each_possible_cpu(cpu) {
-		if (!cpu)
+		if (!IS_ENABLED(CONFIG_SMP) || !cpu)
 			continue;
 
 		memcpy(per_cpu(cpu_msrs, cpu).counters,
--- linux-4.4.0.orig/arch/x86/oprofile/op_model_amd.c
+++ linux-4.4.0/arch/x86/oprofile/op_model_amd.c
@@ -24,7 +24,6 @@
 #include <asm/nmi.h>
 #include <asm/apic.h>
 #include <asm/processor.h>
-#include <asm/cpufeature.h>
 
 #include "op_x86_model.h"
 #include "op_counter.h"
--- linux-4.4.0.orig/arch/x86/oprofile/op_model_ppro.c
+++ linux-4.4.0/arch/x86/oprofile/op_model_ppro.c
@@ -212,8 +212,8 @@
 	eax.full = cpuid_eax(0xa);
 
 	/* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
-	if (eax.split.version_id == 0 && __this_cpu_read(cpu_info.x86) == 6 &&
-		__this_cpu_read(cpu_info.x86_model) == 15) {
+	if (eax.split.version_id == 0 && boot_cpu_data.x86 == 6 &&
+	    boot_cpu_data.x86_model == 15) {
 		eax.split.version_id = 2;
 		eax.split.num_counters = 2;
 		eax.split.bit_width = 40;
--- linux-4.4.0.orig/arch/x86/pci/acpi.c
+++ linux-4.4.0/arch/x86/pci/acpi.c
@@ -114,6 +114,16 @@
 			DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"),
 		},
 	},
+	/* https://bugzilla.kernel.org/show_bug.cgi?id=42606 */
+	{
+		.callback = set_nouse_crs,
+		.ident = "Supermicro X8DTH",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X8DTH-i/6/iF/6F"),
+			DMI_MATCH(DMI_BIOS_VERSION, "2.0a"),
+		},
+	},
 
 	/* https://bugzilla.kernel.org/show_bug.cgi?id=15362 */
 	{
--- linux-4.4.0.orig/arch/x86/pci/broadcom_bus.c
+++ linux-4.4.0/arch/x86/pci/broadcom_bus.c
@@ -50,8 +50,8 @@
 	word1 = read_pci_config_16(bus, slot, func, 0xc0);
 	word2 = read_pci_config_16(bus, slot, func, 0xc2);
 	if (word1 != word2) {
-		res.start = (word1 << 16) | 0x0000;
-		res.end   = (word2 << 16) | 0xffff;
+		res.start = ((resource_size_t) word1 << 16) | 0x0000;
+		res.end   = ((resource_size_t) word2 << 16) | 0xffff;
 		res.flags = IORESOURCE_MEM;
 		update_res(info, res.start, res.end, res.flags, 0);
 	}
@@ -97,7 +97,7 @@
 	 * We should get host bridge information from ACPI unless the BIOS
 	 * doesn't support it.
 	 */
-	if (acpi_os_get_root_pointer())
+	if (!acpi_disabled && acpi_os_get_root_pointer())
 		return 0;
 #endif
 
--- linux-4.4.0.orig/arch/x86/pci/common.c
+++ linux-4.4.0/arch/x86/pci/common.c
@@ -35,6 +35,7 @@
 #endif
 int pcibios_last_bus = -1;
 unsigned long pirq_table_addr;
+unsigned int pci_early_clear_msi;
 const struct pci_raw_ops *__read_mostly raw_pci_ops;
 const struct pci_raw_ops *__read_mostly raw_pci_ext_ops;
 
@@ -621,6 +622,9 @@
 	} else if (!strcmp(str, "skip_isa_align")) {
 		pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
 		return NULL;
+	} else if (!strcmp(str, "clearmsi")) {
+		pci_early_clear_msi = 1;
+		return NULL;
 	} else if (!strcmp(str, "noioapicquirk")) {
 		noioapicquirk = 1;
 		return NULL;
@@ -673,28 +677,22 @@
 	return 0;
 }
 
-int pcibios_alloc_irq(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-	/*
-	 * If the PCI device was already claimed by core code and has
-	 * MSI enabled, probing of the pcibios IRQ will overwrite
-	 * dev->irq.  So bail out if MSI is already enabled.
-	 */
-	if (pci_dev_msi_enabled(dev))
-		return -EBUSY;
+	int err;
 
-	return pcibios_enable_irq(dev);
-}
+	if ((err = pci_enable_resources(dev, mask)) < 0)
+		return err;
 
-void pcibios_free_irq(struct pci_dev *dev)
-{
-	if (pcibios_disable_irq)
-		pcibios_disable_irq(dev);
+	if (!pci_dev_msi_enabled(dev))
+		return pcibios_enable_irq(dev);
+	return 0;
 }
 
-int pcibios_enable_device(struct pci_dev *dev, int mask)
+void pcibios_disable_device (struct pci_dev *dev)
 {
-	return pci_enable_resources(dev, mask);
+	if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
+		pcibios_disable_irq(dev);
 }
 
 int pci_ext_cfg_avail(void)
--- linux-4.4.0.orig/arch/x86/pci/early.c
+++ linux-4.4.0/arch/x86/pci/early.c
@@ -50,6 +50,31 @@
 	outw(val, 0xcfc + (offset&2));
 }
 
+u32 pci_early_find_cap(int bus, int slot, int func, int cap)
+{
+	int bytes;
+	u8 pos;
+
+	if (!(read_pci_config_16(bus, slot, func, PCI_STATUS) &
+						PCI_STATUS_CAP_LIST))
+		return 0;
+
+	pos = read_pci_config_byte(bus, slot, func, PCI_CAPABILITY_LIST);
+	for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
+		u8 id;
+
+		pos &= ~3;
+		id = read_pci_config_byte(bus, slot, func, pos+PCI_CAP_LIST_ID);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+		pos = read_pci_config_byte(bus, slot, func,
+						pos+PCI_CAP_LIST_NEXT);
+	}
+	return 0;
+}
+
 int early_pci_allowed(void)
 {
 	return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) ==
--- linux-4.4.0.orig/arch/x86/pci/fixup.c
+++ linux-4.4.0/arch/x86/pci/fixup.c
@@ -540,3 +540,28 @@
         }
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone);
+
+/*
+ * Device [1022:7914]
+ * When in D0, PME# doesn't get asserted when plugging USB 2.0 device.
+ */
+static void pci_fixup_amd_fch_xhci_pme(struct pci_dev *dev)
+{
+	dev_info(&dev->dev, "PME# does not work under D0, disabling it\n");
+	dev->pme_support &= ~(PCI_PM_CAP_PME_D0 >> PCI_PM_CAP_PME_SHIFT);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x7914, pci_fixup_amd_fch_xhci_pme);
+
+/*
+ * Broadwell EP Home Agent BARs erroneously return non-zero values when read.
+ *
+ * See http://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v4-spec-update.html
+ * entry BDF2.
+ */
+static void pci_bdwep_bar(struct pci_dev *dev)
+{
+	dev->non_compliant_bars = 1;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_bdwep_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_bdwep_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_bdwep_bar);
--- linux-4.4.0.orig/arch/x86/pci/intel_mid_pci.c
+++ linux-4.4.0/arch/x86/pci/intel_mid_pci.c
@@ -37,6 +37,7 @@
 
 /* Quirks for the listed devices */
 #define PCI_DEVICE_ID_INTEL_MRFL_MMC	0x1190
+#define PCI_DEVICE_ID_INTEL_MRFL_HSU	0x1191
 
 /* Fixed BAR fields */
 #define PCIE_VNDR_CAP_ID_FIXED_BAR 0x00	/* Fixed BAR (TBD) */
@@ -215,7 +216,7 @@
 	int polarity;
 	int ret;
 
-	if (pci_has_managed_irq(dev))
+	if (dev->irq_managed && dev->irq > 0)
 		return 0;
 
 	switch (intel_mid_identify_cpu()) {
@@ -225,13 +226,20 @@
 		/* Special treatment for IRQ0 */
 		if (dev->irq == 0) {
 			/*
+			 * Skip HS UART common registers device since it has
+			 * IRQ0 assigned and not used by the kernel.
+			 */
+			if (dev->device == PCI_DEVICE_ID_INTEL_MRFL_HSU)
+				return -EBUSY;
+			/*
 			 * TNG has IRQ0 assigned to eMMC controller. But there
 			 * are also other devices with bogus PCI configuration
 			 * that have IRQ0 assigned. This check ensures that
-			 * eMMC gets it.
+			 * eMMC gets it. The rest of devices still could be
+			 * enabled without interrupt line being allocated.
 			 */
 			if (dev->device != PCI_DEVICE_ID_INTEL_MRFL_MMC)
-				return -EBUSY;
+				return 0;
 		}
 		break;
 	default:
@@ -256,13 +264,10 @@
 
 static void intel_mid_pci_irq_disable(struct pci_dev *dev)
 {
-	if (pci_has_managed_irq(dev)) {
+	if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
+	    dev->irq > 0) {
 		mp_unmap_irq(dev->irq);
 		dev->irq_managed = 0;
-		/*
-		 * Don't reset dev->irq here, otherwise
-		 * intel_mid_pci_irq_enable() will fail on next call.
-		 */
 	}
 }
 
--- linux-4.4.0.orig/arch/x86/pci/irq.c
+++ linux-4.4.0/arch/x86/pci/irq.c
@@ -1117,6 +1117,8 @@
 
 void __init pcibios_irq_init(void)
 {
+	struct irq_routing_table *rtable = NULL;
+
 	DBG(KERN_DEBUG "PCI: IRQ init\n");
 
 	if (raw_pci_ops == NULL)
@@ -1127,8 +1129,10 @@
 	pirq_table = pirq_find_routing_table();
 
 #ifdef CONFIG_PCI_BIOS
-	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
+	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) {
 		pirq_table = pcibios_get_irq_routing_table();
+		rtable = pirq_table;
+	}
 #endif
 	if (pirq_table) {
 		pirq_peer_trick();
@@ -1143,8 +1147,10 @@
 		 * If we're using the I/O APIC, avoid using the PCI IRQ
 		 * routing table
 		 */
-		if (io_apic_assign_pci_irqs)
+		if (io_apic_assign_pci_irqs) {
+			kfree(rtable);
 			pirq_table = NULL;
+		}
 	}
 
 	x86_init.pci.fixup_irqs();
@@ -1202,7 +1208,7 @@
 			struct pci_dev *temp_dev;
 			int irq;
 
-			if (pci_has_managed_irq(dev))
+			if (dev->irq_managed && dev->irq > 0)
 				return 0;
 
 			irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
@@ -1230,7 +1236,8 @@
 			}
 			dev = temp_dev;
 			if (irq >= 0) {
-				pci_set_managed_irq(dev, irq);
+				dev->irq_managed = 1;
+				dev->irq = irq;
 				dev_info(&dev->dev, "PCI->APIC IRQ transform: "
 					 "INT %c -> IRQ %d\n", 'A' + pin - 1, irq);
 				return 0;
@@ -1256,10 +1263,24 @@
 	return 0;
 }
 
+bool mp_should_keep_irq(struct device *dev)
+{
+	if (dev->power.is_prepared)
+		return true;
+#ifdef CONFIG_PM
+	if (dev->power.runtime_status == RPM_SUSPENDING)
+		return true;
+#endif
+
+	return false;
+}
+
 static void pirq_disable_irq(struct pci_dev *dev)
 {
-	if (io_apic_assign_pci_irqs && pci_has_managed_irq(dev)) {
+	if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
+	    dev->irq_managed && dev->irq) {
 		mp_unmap_irq(dev->irq);
-		pci_reset_managed_irq(dev);
+		dev->irq = 0;
+		dev->irq_managed = 0;
 	}
 }
--- linux-4.4.0.orig/arch/x86/pci/xen.c
+++ linux-4.4.0/arch/x86/pci/xen.c
@@ -231,23 +231,14 @@
 		return 1;
 
 	for_each_pci_msi_entry(msidesc, dev) {
-		__pci_read_msi_msg(msidesc, &msg);
-		pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
-			((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
-		if (msg.data != XEN_PIRQ_MSI_DATA ||
-		    xen_irq_from_pirq(pirq) < 0) {
-			pirq = xen_allocate_pirq_msi(dev, msidesc);
-			if (pirq < 0) {
-				irq = -ENODEV;
-				goto error;
-			}
-			xen_msi_compose_msg(dev, pirq, &msg);
-			__pci_write_msi_msg(msidesc, &msg);
-			dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
-		} else {
-			dev_dbg(&dev->dev,
-				"xen: msi already bound to pirq=%d\n", pirq);
+		pirq = xen_allocate_pirq_msi(dev, msidesc);
+		if (pirq < 0) {
+			irq = -ENODEV;
+			goto error;
 		}
+		xen_msi_compose_msg(dev, pirq, &msg);
+		__pci_write_msi_msg(msidesc, &msg);
+		dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
 		irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
 					       (type == PCI_CAP_ID_MSI) ? nvec : 1,
 					       (type == PCI_CAP_ID_MSIX) ?
@@ -488,8 +479,11 @@
 #endif
 	__acpi_register_gsi = acpi_register_gsi_xen;
 	__acpi_unregister_gsi = NULL;
-	/* Pre-allocate legacy irqs */
-	for (irq = 0; irq < nr_legacy_irqs(); irq++) {
+	/*
+	 * Pre-allocate the legacy IRQs.  Use NR_LEGACY_IRQS here
+	 * because we don't have a PIC and thus nr_legacy_irqs() is zero.
+	 */
+	for (irq = 0; irq < NR_IRQS_LEGACY; irq++) {
 		int trigger, polarity;
 
 		if (acpi_get_override_irq(irq, &trigger, &polarity) == -1)
--- linux-4.4.0.orig/arch/x86/platform/efi/early_printk.c
+++ linux-4.4.0/arch/x86/platform/efi/early_printk.c
@@ -179,7 +179,7 @@
 			num--;
 		}
 
-		if (efi_x >= si->lfb_width) {
+		if (efi_x + font->width > si->lfb_width) {
 			efi_x = 0;
 			efi_y += font->height;
 		}
--- linux-4.4.0.orig/arch/x86/platform/efi/efi-bgrt.c
+++ linux-4.4.0/arch/x86/platform/efi/efi-bgrt.c
@@ -28,8 +28,7 @@
 void __init efi_bgrt_init(void)
 {
 	acpi_status status;
-	void __iomem *image;
-	bool ioremapped = false;
+	void *image;
 	struct bmp_header bmp_header;
 
 	if (acpi_disabled)
@@ -70,20 +69,14 @@
 		return;
 	}
 
-	image = efi_lookup_mapped_addr(bgrt_tab->image_address);
+	image = memremap(bgrt_tab->image_address, sizeof(bmp_header), MEMREMAP_WB);
 	if (!image) {
-		image = early_ioremap(bgrt_tab->image_address,
-				       sizeof(bmp_header));
-		ioremapped = true;
-		if (!image) {
-			pr_err("Ignoring BGRT: failed to map image header memory\n");
-			return;
-		}
+		pr_err("Ignoring BGRT: failed to map image header memory\n");
+		return;
 	}
 
-	memcpy_fromio(&bmp_header, image, sizeof(bmp_header));
-	if (ioremapped)
-		early_iounmap(image, sizeof(bmp_header));
+	memcpy(&bmp_header, image, sizeof(bmp_header));
+	memunmap(image);
 	bgrt_image_size = bmp_header.size;
 
 	bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL | __GFP_NOWARN);
@@ -93,18 +86,14 @@
 		return;
 	}
 
-	if (ioremapped) {
-		image = early_ioremap(bgrt_tab->image_address,
-				       bmp_header.size);
-		if (!image) {
-			pr_err("Ignoring BGRT: failed to map image memory\n");
-			kfree(bgrt_image);
-			bgrt_image = NULL;
-			return;
-		}
+	image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB);
+	if (!image) {
+		pr_err("Ignoring BGRT: failed to map image memory\n");
+		kfree(bgrt_image);
+		bgrt_image = NULL;
+		return;
 	}
 
-	memcpy_fromio(bgrt_image, image, bgrt_image_size);
-	if (ioremapped)
-		early_iounmap(image, bmp_header.size);
+	memcpy(bgrt_image, image, bgrt_image_size);
+	memunmap(image);
 }
--- linux-4.4.0.orig/arch/x86/platform/efi/efi.c
+++ linux-4.4.0/arch/x86/platform/efi/efi.c
@@ -89,6 +89,8 @@
 	pgd_t *save_pgd;
 
 	save_pgd = efi_call_phys_prolog();
+	if (!save_pgd && efi_enabled(EFI_OLD_MEMMAP))
+		return EFI_BAD_BUFFER_SIZE;
 
 	/* Disable interrupts around EFI calls: */
 	local_irq_save(flags);
@@ -465,7 +467,6 @@
 	efi_char16_t *c16;
 	char vendor[100] = "unknown";
 	int i = 0;
-	void *tmp;
 
 #ifdef CONFIG_X86_32
 	if (boot_params.efi_info.efi_systab_hi ||
@@ -490,14 +491,16 @@
 	/*
 	 * Show what we know for posterity
 	 */
-	c16 = tmp = early_memremap(efi.systab->fw_vendor, 2);
+	c16 = early_memremap_ro(efi.systab->fw_vendor,
+				sizeof(vendor) * sizeof(efi_char16_t));
 	if (c16) {
-		for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
-			vendor[i] = *c16++;
+		for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
+			vendor[i] = c16[i];
 		vendor[i] = '\0';
-	} else
+		early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
+	} else {
 		pr_err("Could not map the firmware vendor!\n");
-	early_memunmap(tmp, 2);
+	}
 
 	pr_info("EFI v%u.%.02u by %s\n",
 		efi.systab->hdr.revision >> 16,
@@ -859,9 +862,6 @@
 
 	if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
 		runtime_code_page_mkexec();
-
-	/* clean DUMMY object */
-	efi_delete_dummy_variable();
 #endif
 }
 
--- linux-4.4.0.orig/arch/x86/platform/efi/efi_64.c
+++ linux-4.4.0/arch/x86/platform/efi/efi_64.c
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 
 #include <asm/setup.h>
+#include <asm/sections.h>
 #include <asm/page.h>
 #include <asm/e820.h>
 #include <asm/pgtable.h>
@@ -40,6 +41,7 @@
 #include <asm/fixmap.h>
 #include <asm/realmode.h>
 #include <asm/time.h>
+#include <asm/nospec-branch.h>
 
 /*
  * We allocate runtime services regions bottom-up, starting from -4G, i.e.
@@ -90,6 +92,8 @@
 
 	n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
 	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+	if (!save_pgd)
+		return NULL;
 
 	for (pgd = 0; pgd < n_pgds; pgd++) {
 		save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);
@@ -143,7 +147,7 @@
 
 int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
 {
-	unsigned long text;
+	unsigned long pfn, text;
 	struct page *page;
 	unsigned npages;
 	pgd_t *pgd;
@@ -160,7 +164,8 @@
 	 * and ident-map those pages containing the map before calling
 	 * phys_efi_set_virtual_address_map().
 	 */
-	if (kernel_map_pages_in_pgd(pgd, pa_memmap, pa_memmap, num_pages, _PAGE_NX)) {
+	pfn = pa_memmap >> PAGE_SHIFT;
+	if (kernel_map_pages_in_pgd(pgd, pfn, pa_memmap, num_pages, _PAGE_NX)) {
 		pr_err("Error ident-mapping new memmap (0x%lx)!\n", pa_memmap);
 		return 1;
 	}
@@ -185,8 +190,9 @@
 
 	npages = (_end - _text) >> PAGE_SHIFT;
 	text = __pa(_text);
+	pfn = text >> PAGE_SHIFT;
 
-	if (kernel_map_pages_in_pgd(pgd, text >> PAGE_SHIFT, text, npages, 0)) {
+	if (kernel_map_pages_in_pgd(pgd, pfn, text, npages, 0)) {
 		pr_err("Failed to map kernel text 1:1\n");
 		return 1;
 	}
@@ -204,12 +210,14 @@
 static void __init __map_region(efi_memory_desc_t *md, u64 va)
 {
 	pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd);
-	unsigned long pf = 0;
+	unsigned long flags = 0;
+	unsigned long pfn;
 
 	if (!(md->attribute & EFI_MEMORY_WB))
-		pf |= _PAGE_PCD;
+		flags |= _PAGE_PCD;
 
-	if (kernel_map_pages_in_pgd(pgd, md->phys_addr, va, md->num_pages, pf))
+	pfn = md->phys_addr >> PAGE_SHIFT;
+	if (kernel_map_pages_in_pgd(pgd, pfn, va, md->num_pages, flags))
 		pr_warn("Error mapping PA 0x%llx -> VA 0x%llx!\n",
 			   md->phys_addr, va);
 }
@@ -347,10 +355,12 @@
 									\
 	efi_sync_low_kernel_mappings();					\
 	local_irq_save(flags);						\
+	firmware_restrict_branch_speculation_start();			\
 									\
 	efi_scratch.prev_cr3 = read_cr3();				\
 	write_cr3((unsigned long)efi_scratch.efi_pgt);			\
 	__flush_tlb_all();						\
+	firmware_restrict_branch_speculation_end();			\
 									\
 	func = runtime_service32(f);					\
 	__s = efi64_thunk(func, __VA_ARGS__);			\
--- linux-4.4.0.orig/arch/x86/platform/efi/quirks.c
+++ linux-4.4.0/arch/x86/platform/efi/quirks.c
@@ -9,6 +9,7 @@
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
 #include <asm/efi.h>
+#include <asm/sections.h>
 #include <asm/uv/uv.h>
 
 #define EFI_MIN_RESERVE 5120
@@ -54,13 +55,41 @@
 }
 
 /*
+ * In the nonblocking case we do not attempt to perform garbage
+ * collection if we do not have enough free space. Rather, we do the
+ * bare minimum check and give up immediately if the available space
+ * is below EFI_MIN_RESERVE.
+ *
+ * This function is intended to be small and simple because it is
+ * invoked from crash handler paths.
+ */
+static efi_status_t
+query_variable_store_nonblocking(u32 attributes, unsigned long size)
+{
+	efi_status_t status;
+	u64 storage_size, remaining_size, max_size;
+
+	status = efi.query_variable_info_nonblocking(attributes, &storage_size,
+						     &remaining_size,
+						     &max_size);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	if (remaining_size - size < EFI_MIN_RESERVE)
+		return EFI_OUT_OF_RESOURCES;
+
+	return EFI_SUCCESS;
+}
+
+/*
  * Some firmware implementations refuse to boot if there's insufficient space
  * in the variable store. Ensure that we never use more than a safe limit.
  *
  * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
  * store.
  */
-efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
+efi_status_t efi_query_variable_store(u32 attributes, unsigned long size,
+				      bool nonblocking)
 {
 	efi_status_t status;
 	u64 storage_size, remaining_size, max_size;
@@ -68,6 +97,9 @@
 	if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
 		return 0;
 
+	if (nonblocking)
+		return query_variable_store_nonblocking(attributes, size);
+
 	status = efi.query_variable_info(attributes, &storage_size,
 					 &remaining_size, &max_size);
 	if (status != EFI_SUCCESS)
--- linux-4.4.0.orig/arch/x86/platform/goldfish/goldfish.c
+++ linux-4.4.0/arch/x86/platform/goldfish/goldfish.c
@@ -42,10 +42,22 @@
 	}
 };
 
+static bool goldfish_enable __initdata;
+
+static int __init goldfish_setup(char *str)
+{
+	goldfish_enable = true;
+	return 0;
+}
+__setup("goldfish", goldfish_setup);
+
 static int __init goldfish_init(void)
 {
+	if (!goldfish_enable)
+		return -ENODEV;
+
 	platform_device_register_simple("goldfish_pdev_bus", -1,
-						goldfish_pdev_bus_resources, 2);
+					goldfish_pdev_bus_resources, 2);
 	return 0;
 }
 device_initcall(goldfish_init);
--- linux-4.4.0.orig/arch/x86/platform/intel-mid/device_libs/platform_wdt.c
+++ linux-4.4.0/arch/x86/platform/intel-mid/device_libs/platform_wdt.c
@@ -16,8 +16,9 @@
 #include <linux/platform_data/intel-mid_wdt.h>
 #include <asm/intel-mid.h>
 #include <asm/io_apic.h>
+#include <asm/hw_irq.h>
 
-#define TANGIER_EXT_TIMER0_MSI 15
+#define TANGIER_EXT_TIMER0_MSI 12
 
 static struct platform_device wdt_dev = {
 	.name = "intel_mid_wdt",
--- linux-4.4.0.orig/arch/x86/platform/olpc/olpc-xo15-sci.c
+++ linux-4.4.0/arch/x86/platform/olpc/olpc-xo15-sci.c
@@ -196,6 +196,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int xo15_sci_resume(struct device *dev)
 {
 	/* Enable all EC events */
@@ -207,6 +208,7 @@
 
 	return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(xo15_sci_pm, NULL, xo15_sci_resume);
 
--- linux-4.4.0.orig/arch/x86/platform/uv/tlb_uv.c
+++ linux-4.4.0/arch/x86/platform/uv/tlb_uv.c
@@ -1249,6 +1249,7 @@
 	struct msg_desc msgdesc;
 
 	ack_APIC_irq();
+	kvm_set_cpu_l1tf_flush_l1d();
 	time_start = get_cycles();
 
 	bcp = &per_cpu(bau_control, smp_processor_id());
--- linux-4.4.0.orig/arch/x86/power/cpu.c
+++ linux-4.4.0/arch/x86/power/cpu.c
@@ -12,6 +12,8 @@
 #include <linux/export.h>
 #include <linux/smp.h>
 #include <linux/perf_event.h>
+#include <linux/dmi.h>
+#include <linux/tboot.h>
 
 #include <asm/pgtable.h>
 #include <asm/proto.h>
@@ -23,6 +25,7 @@
 #include <asm/debugreg.h>
 #include <asm/cpu.h>
 #include <asm/mmu_context.h>
+#include <asm/cpu_device_id.h>
 
 #ifdef CONFIG_X86_32
 __visible unsigned long saved_context_ebx;
@@ -32,6 +35,29 @@
 #endif
 struct saved_context saved_context;
 
+static void msr_save_context(struct saved_context *ctxt)
+{
+	struct saved_msr *msr = ctxt->saved_msrs.array;
+	struct saved_msr *end = msr + ctxt->saved_msrs.num;
+
+	while (msr < end) {
+		msr->valid = !rdmsrl_safe(msr->info.msr_no, &msr->info.reg.q);
+		msr++;
+	}
+}
+
+static void msr_restore_context(struct saved_context *ctxt)
+{
+	struct saved_msr *msr = ctxt->saved_msrs.array;
+	struct saved_msr *end = msr + ctxt->saved_msrs.num;
+
+	while (msr < end) {
+		if (msr->valid)
+			wrmsrl(msr->info.msr_no, msr->info.reg.q);
+		msr++;
+	}
+}
+
 /**
  *	__save_processor_state - save CPU registers before creating a
  *		hibernation image and before restoring the memory state from it
@@ -111,6 +137,7 @@
 #endif
 	ctxt->misc_enable_saved = !rdmsrl_safe(MSR_IA32_MISC_ENABLE,
 					       &ctxt->misc_enable);
+	msr_save_context(ctxt);
 }
 
 /* Needed by apm.c */
@@ -229,6 +256,7 @@
 	x86_platform.restore_sched_clock_state();
 	mtrr_bp_restore();
 	perf_restore_debug_store();
+	msr_restore_context(ctxt);
 }
 
 /* Needed by apm.c */
@@ -240,6 +268,35 @@
 EXPORT_SYMBOL(restore_processor_state);
 #endif
 
+#if defined(CONFIG_HIBERNATION) && defined(CONFIG_HOTPLUG_CPU)
+static void resume_play_dead(void)
+{
+	play_dead_common();
+	tboot_shutdown(TB_SHUTDOWN_WFS);
+	hlt_play_dead();
+}
+
+int hibernate_resume_nonboot_cpu_disable(void)
+{
+	void (*play_dead)(void) = smp_ops.play_dead;
+	int ret;
+
+	/*
+	 * Ensure that MONITOR/MWAIT will not be used in the "play dead" loop
+	 * during hibernate image restoration, because it is likely that the
+	 * monitored address will be actually written to at that time and then
+	 * the "dead" CPU will attempt to execute instructions again, but the
+	 * address in its instruction pointer may not be possible to resolve
+	 * any more at that point (the page tables used by it previously may
+	 * have been overwritten by hibernate image data).
+	 */
+	smp_ops.play_dead = resume_play_dead;
+	ret = disable_nonboot_cpus();
+	smp_ops.play_dead = play_dead;
+	return ret;
+}
+#endif
+
 /*
  * When bsp_check() is called in hibernate and suspend, cpu hotplug
  * is disabled already. So it's unnessary to handle race condition between
@@ -320,3 +377,128 @@
 }
 
 core_initcall(bsp_pm_check_init);
+
+static int msr_build_context(const u32 *msr_id, const int num)
+{
+	struct saved_msrs *saved_msrs = &saved_context.saved_msrs;
+	struct saved_msr *msr_array;
+	int total_num;
+	int i, j;
+
+	total_num = saved_msrs->num + num;
+
+	msr_array = kmalloc_array(total_num, sizeof(struct saved_msr), GFP_KERNEL);
+	if (!msr_array) {
+		pr_err("x86/pm: Can not allocate memory to save/restore MSRs during suspend.\n");
+		return -ENOMEM;
+	}
+
+	if (saved_msrs->array) {
+		/*
+		 * Multiple callbacks can invoke this function, so copy any
+		 * MSR save requests from previous invocations.
+		 */
+		memcpy(msr_array, saved_msrs->array,
+		       sizeof(struct saved_msr) * saved_msrs->num);
+
+		kfree(saved_msrs->array);
+	}
+
+	for (i = saved_msrs->num, j = 0; i < total_num; i++, j++) {
+		msr_array[i].info.msr_no	= msr_id[j];
+		msr_array[i].valid		= false;
+		msr_array[i].info.reg.q		= 0;
+	}
+	saved_msrs->num   = total_num;
+	saved_msrs->array = msr_array;
+
+	return 0;
+}
+
+/*
+ * The following sections are a quirk framework for problematic BIOSen:
+ * Sometimes MSRs are modified by the BIOSen after suspended to
+ * RAM, this might cause unexpected behavior after wakeup.
+ * Thus we save/restore these specified MSRs across suspend/resume
+ * in order to work around it.
+ *
+ * For any further problematic BIOSen/platforms,
+ * please add your own function similar to msr_initialize_bdw.
+ */
+static int msr_initialize_bdw(const struct dmi_system_id *d)
+{
+	/* Add any extra MSR ids into this array. */
+	u32 bdw_msr_id[] = { MSR_IA32_THERM_CONTROL };
+
+	pr_info("x86/pm: %s detected, MSR saving is needed during suspending.\n", d->ident);
+	return msr_build_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
+}
+
+static struct dmi_system_id msr_save_dmi_table[] = {
+	{
+	 .callback = msr_initialize_bdw,
+	 .ident = "BROADWELL BDX_EP",
+	 .matches = {
+		DMI_MATCH(DMI_PRODUCT_NAME, "GRANTLEY"),
+		DMI_MATCH(DMI_PRODUCT_VERSION, "E63448-400"),
+		},
+	},
+	{}
+};
+
+static int msr_save_cpuid_features(const struct x86_cpu_id *c)
+{
+	u32 cpuid_msr_id[] = {
+		MSR_AMD64_CPUID_FN_1,
+	};
+
+	pr_info("x86/pm: family %#hx cpu detected, MSR saving is needed during suspending.\n",
+		c->family);
+
+	return msr_build_context(cpuid_msr_id, ARRAY_SIZE(cpuid_msr_id));
+}
+
+static const struct x86_cpu_id msr_save_cpu_table[] = {
+	{
+		.vendor = X86_VENDOR_AMD,
+		.family = 0x15,
+		.model = X86_MODEL_ANY,
+		.feature = X86_FEATURE_ANY,
+		.driver_data = (kernel_ulong_t)msr_save_cpuid_features,
+	},
+	{
+		.vendor = X86_VENDOR_AMD,
+		.family = 0x16,
+		.model = X86_MODEL_ANY,
+		.feature = X86_FEATURE_ANY,
+		.driver_data = (kernel_ulong_t)msr_save_cpuid_features,
+	},
+	{}
+};
+
+typedef int (*pm_cpu_match_t)(const struct x86_cpu_id *);
+static int pm_cpu_check(const struct x86_cpu_id *c)
+{
+	const struct x86_cpu_id *m;
+	int ret = 0;
+
+	m = x86_match_cpu(msr_save_cpu_table);
+	if (m) {
+		pm_cpu_match_t fn;
+
+		fn = (pm_cpu_match_t)m->driver_data;
+		ret = fn(m);
+	}
+
+	return ret;
+}
+
+static int pm_check_save_msr(void)
+{
+	dmi_check_system(msr_save_dmi_table);
+	pm_cpu_check(msr_save_cpu_table);
+
+	return 0;
+}
+
+device_initcall(pm_check_save_msr);
--- linux-4.4.0.orig/arch/x86/power/hibernate_32.c
+++ linux-4.4.0/arch/x86/power/hibernate_32.c
@@ -142,7 +142,7 @@
 #endif
 }
 
-int swsusp_arch_resume(void)
+asmlinkage int swsusp_arch_resume(void)
 {
 	int error;
 
--- linux-4.4.0.orig/arch/x86/power/hibernate_64.c
+++ linux-4.4.0/arch/x86/power/hibernate_64.c
@@ -19,6 +19,7 @@
 #include <asm/mtrr.h>
 #include <asm/sections.h>
 #include <asm/suspend.h>
+#include <asm/tlbflush.h>
 
 /* Defined in hibernate_asm_64.S */
 extern asmlinkage __visible int restore_image(void);
@@ -28,6 +29,7 @@
  * kernel's text (this value is passed in the image header).
  */
 unsigned long restore_jump_address __visible;
+unsigned long jump_address_phys;
 
 /*
  * Value of the cr3 register from before the hibernation (this value is passed
@@ -37,7 +39,43 @@
 
 pgd_t *temp_level4_pgt __visible;
 
-void *relocated_restore_code __visible;
+unsigned long relocated_restore_code __visible;
+
+static int set_up_temporary_text_mapping(void)
+{
+	pmd_t *pmd;
+	pud_t *pud;
+
+	/*
+	 * The new mapping only has to cover the page containing the image
+	 * kernel's entry point (jump_address_phys), because the switch over to
+	 * it is carried out by relocated code running from a page allocated
+	 * specifically for this purpose and covered by the identity mapping, so
+	 * the temporary kernel text mapping is only needed for the final jump.
+	 * Moreover, in that mapping the virtual address of the image kernel's
+	 * entry point must be the same as its virtual address in the image
+	 * kernel (restore_jump_address), so the image kernel's
+	 * restore_registers() code doesn't find itself in a different area of
+	 * the virtual address space after switching over to the original page
+	 * tables used by the image kernel.
+	 */
+	pud = (pud_t *)get_safe_page(GFP_ATOMIC);
+	if (!pud)
+		return -ENOMEM;
+
+	pmd = (pmd_t *)get_safe_page(GFP_ATOMIC);
+	if (!pmd)
+		return -ENOMEM;
+
+	set_pmd(pmd + pmd_index(restore_jump_address),
+		__pmd((jump_address_phys & PMD_MASK) | __PAGE_KERNEL_LARGE_EXEC));
+	set_pud(pud + pud_index(restore_jump_address),
+		__pud(__pa(pmd) | _KERNPG_TABLE));
+	set_pgd(temp_level4_pgt + pgd_index(restore_jump_address),
+		__pgd(__pa(pud) | _KERNPG_TABLE));
+
+	return 0;
+}
 
 static void *alloc_pgt_page(void *context)
 {
@@ -49,7 +87,7 @@
 	struct x86_mapping_info info = {
 		.alloc_pgt_page	= alloc_pgt_page,
 		.pmd_flag	= __PAGE_KERNEL_LARGE_EXEC,
-		.kernel_mapping = true,
+		.offset		= __PAGE_OFFSET,
 	};
 	unsigned long mstart, mend;
 	int result;
@@ -59,9 +97,10 @@
 	if (!temp_level4_pgt)
 		return -ENOMEM;
 
-	/* It is safe to reuse the original kernel mapping */
-	set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map),
-		init_level4_pgt[pgd_index(__START_KERNEL_map)]);
+	/* Prepare a temporary mapping for the kernel text */
+	result = set_up_temporary_text_mapping();
+	if (result)
+		return result;
 
 	/* Set up the direct mapping from scratch */
 	for (i = 0; i < nr_pfn_mapped; i++) {
@@ -78,19 +117,50 @@
 	return 0;
 }
 
-int swsusp_arch_resume(void)
+static int relocate_restore_code(void)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+
+	relocated_restore_code = get_safe_page(GFP_ATOMIC);
+	if (!relocated_restore_code)
+		return -ENOMEM;
+
+	memcpy((void *)relocated_restore_code, &core_restore_code, PAGE_SIZE);
+
+	/* Make the page containing the relocated code executable */
+	pgd = (pgd_t *)__va(read_cr3()) + pgd_index(relocated_restore_code);
+	pud = pud_offset(pgd, relocated_restore_code);
+	if (pud_large(*pud)) {
+		set_pud(pud, __pud(pud_val(*pud) & ~_PAGE_NX));
+	} else {
+		pmd_t *pmd = pmd_offset(pud, relocated_restore_code);
+
+		if (pmd_large(*pmd)) {
+			set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_NX));
+		} else {
+			pte_t *pte = pte_offset_kernel(pmd, relocated_restore_code);
+
+			set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_NX));
+		}
+	}
+	__flush_tlb_all();
+
+	return 0;
+}
+
+asmlinkage int swsusp_arch_resume(void)
 {
 	int error;
 
 	/* We have got enough memory and from now on we cannot recover */
-	if ((error = set_up_temporary_mappings()))
+	error = set_up_temporary_mappings();
+	if (error)
 		return error;
 
-	relocated_restore_code = (void *)get_safe_page(GFP_ATOMIC);
-	if (!relocated_restore_code)
-		return -ENOMEM;
-	memcpy(relocated_restore_code, &core_restore_code,
-	       &restore_registers - &core_restore_code);
+	error = relocate_restore_code();
+	if (error)
+		return error;
 
 	restore_image();
 	return 0;
@@ -109,11 +179,12 @@
 
 struct restore_data_record {
 	unsigned long jump_address;
+	unsigned long jump_address_phys;
 	unsigned long cr3;
 	unsigned long magic;
 };
 
-#define RESTORE_MAGIC	0x0123456789ABCDEFUL
+#define RESTORE_MAGIC	0x123456789ABCDEF0UL
 
 /**
  *	arch_hibernation_header_save - populate the architecture specific part
@@ -126,7 +197,8 @@
 
 	if (max_size < sizeof(struct restore_data_record))
 		return -EOVERFLOW;
-	rdr->jump_address = restore_jump_address;
+	rdr->jump_address = (unsigned long)&restore_registers;
+	rdr->jump_address_phys = __pa_symbol(&restore_registers);
 	rdr->cr3 = restore_cr3;
 	rdr->magic = RESTORE_MAGIC;
 	return 0;
@@ -142,6 +214,7 @@
 	struct restore_data_record *rdr = addr;
 
 	restore_jump_address = rdr->jump_address;
+	jump_address_phys = rdr->jump_address_phys;
 	restore_cr3 = rdr->cr3;
 	return (rdr->magic == RESTORE_MAGIC) ? 0 : -EINVAL;
 }
--- linux-4.4.0.orig/arch/x86/power/hibernate_asm_64.S
+++ linux-4.4.0/arch/x86/power/hibernate_asm_64.S
@@ -21,6 +21,7 @@
 #include <asm/page_types.h>
 #include <asm/asm-offsets.h>
 #include <asm/processor-flags.h>
+#include <asm/nospec-branch.h>
 
 ENTRY(swsusp_arch_suspend)
 	movq	$saved_context, %rax
@@ -42,9 +43,6 @@
 	pushfq
 	popq	pt_regs_flags(%rax)
 
-	/* save the address of restore_registers */
-	movq	$restore_registers, %rax
-	movq	%rax, restore_jump_address(%rip)
 	/* save cr3 */
 	movq	%cr3, %rax
 	movq	%rax, restore_cr3(%rip)
@@ -53,31 +51,35 @@
 	ret
 
 ENTRY(restore_image)
-	/* switch to temporary page tables */
-	movq	$__PAGE_OFFSET, %rdx
-	movq	temp_level4_pgt(%rip), %rax
-	subq	%rdx, %rax
-	movq	%rax, %cr3
-	/* Flush TLB */
-	movq	mmu_cr4_features(%rip), %rax
-	movq	%rax, %rdx
-	andq	$~(X86_CR4_PGE), %rdx
-	movq	%rdx, %cr4;  # turn off PGE
-	movq	%cr3, %rcx;  # flush TLB
-	movq	%rcx, %cr3;
-	movq	%rax, %cr4;  # turn PGE back on
-
 	/* prepare to jump to the image kernel */
-	movq	restore_jump_address(%rip), %rax
-	movq	restore_cr3(%rip), %rbx
+	movq	restore_jump_address(%rip), %r8
+	movq	restore_cr3(%rip), %r9
+
+	/* prepare to switch to temporary page tables */
+	movq	temp_level4_pgt(%rip), %rax
+	movq	mmu_cr4_features(%rip), %rbx
 
 	/* prepare to copy image data to their original locations */
 	movq	restore_pblist(%rip), %rdx
+
+	/* jump to relocated restore code */
 	movq	relocated_restore_code(%rip), %rcx
+	ANNOTATE_RETPOLINE_SAFE
 	jmpq	*%rcx
 
 	/* code below has been relocated to a safe page */
 ENTRY(core_restore_code)
+	/* switch to temporary page tables */
+	movq	$__PAGE_OFFSET, %rcx
+	subq	%rcx, %rax
+	movq	%rax, %cr3
+	/* flush TLB */
+	movq	%rbx, %rcx
+	andq	$~(X86_CR4_PGE), %rcx
+	movq	%rcx, %cr4;  # turn off PGE
+	movq	%cr3, %rcx;  # flush TLB
+	movq	%rcx, %cr3;
+	movq	%rbx, %cr4;  # turn PGE back on
 .Lloop:
 	testq	%rdx, %rdx
 	jz	.Ldone
@@ -92,23 +94,17 @@
 	/* progress to the next pbe */
 	movq	pbe_next(%rdx), %rdx
 	jmp	.Lloop
+
 .Ldone:
 	/* jump to the restore_registers address from the image header */
-	jmpq	*%rax
-	/*
-	 * NOTE: This assumes that the boot kernel's text mapping covers the
-	 * image kernel's page containing restore_registers and the address of
-	 * this page is the same as in the image kernel's text mapping (it
-	 * should always be true, because the text mapping is linear, starting
-	 * from 0, and is supposed to cover the entire kernel text for every
-	 * kernel).
-	 *
-	 * code below belongs to the image kernel
-	 */
+	ANNOTATE_RETPOLINE_SAFE
+	jmpq	*%r8
 
+	 /* code below belongs to the image kernel */
+	.align PAGE_SIZE
 ENTRY(restore_registers)
 	/* go back to the original page tables */
-	movq    %rbx, %cr3
+	movq    %r9, %cr3
 
 	/* Flush TLB, including "global" things (vmalloc) */
 	movq	mmu_cr4_features(%rip), %rax
--- linux-4.4.0.orig/arch/x86/purgatory/Makefile
+++ linux-4.4.0/arch/x86/purgatory/Makefile
@@ -12,6 +12,7 @@
 
 KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes -fno-zero-initialized-in-bss -fno-builtin -ffreestanding -c -MD -Os -mcmodel=large
 KBUILD_CFLAGS += -m$(BITS)
+KBUILD_CFLAGS += $(call cc-option,-fno-PIE)
 
 $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
 		$(call if_changed,ld)
--- linux-4.4.0.orig/arch/x86/ras/mce_amd_inj.c
+++ linux-4.4.0/arch/x86/ras/mce_amd_inj.c
@@ -20,6 +20,7 @@
 #include <linux/pci.h>
 
 #include <asm/mce.h>
+#include <asm/smp.h>
 #include <asm/amd_nb.h>
 #include <asm/irq_vectors.h>
 
@@ -206,7 +207,7 @@
 	struct cpuinfo_x86 *c = &boot_cpu_data;
 	u32 cores_per_node;
 
-	cores_per_node = c->x86_max_cores / amd_get_nodes_per_socket();
+	cores_per_node = (c->x86_max_cores * smp_num_siblings) / amd_get_nodes_per_socket();
 
 	return cores_per_node * node_id;
 }
--- linux-4.4.0.orig/arch/x86/realmode/init.c
+++ linux-4.4.0/arch/x86/realmode/init.c
@@ -4,6 +4,7 @@
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
 #include <asm/realmode.h>
+#include <asm/kaiser.h>
 
 struct real_mode_header *real_mode_header;
 u32 *trampoline_cr4_features;
@@ -15,7 +16,8 @@
 	size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
 
 	/* Has to be under 1M so we can execute real-mode AP code. */
-	mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
+	mem = memblock_find_in_range(0, 1 << 20, size,
+				     KAISER_KERNEL_PGD_ALIGNMENT);
 	if (!mem)
 		panic("Cannot allocate trampoline\n");
 
--- linux-4.4.0.orig/arch/x86/realmode/rm/Makefile
+++ linux-4.4.0/arch/x86/realmode/rm/Makefile
@@ -43,7 +43,7 @@
 targets += realmode.lds
 $(obj)/realmode.lds: $(obj)/pasyms.h
 
-LDFLAGS_realmode.elf := --emit-relocs -T
+LDFLAGS_realmode.elf := -m elf_i386 --emit-relocs -T
 CPPFLAGS_realmode.lds += -P -C -I$(obj)
 
 targets += realmode.elf
--- linux-4.4.0.orig/arch/x86/realmode/rm/trampoline_32.S
+++ linux-4.4.0/arch/x86/realmode/rm/trampoline_32.S
@@ -22,6 +22,7 @@
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page_types.h>
+#include <asm/nospec-branch.h>
 #include "realmode.h"
 
 	.text
@@ -60,6 +61,7 @@
 	.section ".text32","ax"
 	.code32
 ENTRY(startup_32)			# note: also used from wakeup_asm.S
+	ANNOTATE_RETPOLINE_SAFE
 	jmp	*%eax
 
 	.bss
--- linux-4.4.0.orig/arch/x86/realmode/rm/trampoline_64.S
+++ linux-4.4.0/arch/x86/realmode/rm/trampoline_64.S
@@ -30,6 +30,7 @@
 #include <asm/msr.h>
 #include <asm/segment.h>
 #include <asm/processor-flags.h>
+#include <asm/kaiser.h>
 #include "realmode.h"
 
 	.text
@@ -139,7 +140,7 @@
 tr_gdt_end:
 
 	.bss
-	.balign	PAGE_SIZE
+	.balign	KAISER_KERNEL_PGD_ALIGNMENT
 GLOBAL(trampoline_pgd)		.space	PAGE_SIZE
 
 	.balign	8
--- linux-4.4.0.orig/arch/x86/tools/gen-insn-attr-x86.awk
+++ linux-4.4.0/arch/x86/tools/gen-insn-attr-x86.awk
@@ -68,16 +68,18 @@
 
 	lprefix1_expr = "\\((66|!F3)\\)"
 	lprefix2_expr = "\\(F3\\)"
-	lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)"
+	lprefix3_expr = "\\((F2|!F3|66&F2)\\)"
 	lprefix_expr = "\\((66|F2|F3)\\)"
 	max_lprefix = 4
 
-	# All opcodes starting with lower-case 'v' or with (v1) superscript
+	# All opcodes starting with lower-case 'v', 'k' or with (v1) superscript
 	# accepts VEX prefix
-	vexok_opcode_expr = "^v.*"
+	vexok_opcode_expr = "^[vk].*"
 	vexok_expr = "\\(v1\\)"
 	# All opcodes with (v) superscript supports *only* VEX prefix
 	vexonly_expr = "\\(v\\)"
+	# All opcodes with (ev) superscript supports *only* EVEX prefix
+	evexonly_expr = "\\(ev\\)"
 
 	prefix_expr = "\\(Prefix\\)"
 	prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
@@ -95,6 +97,7 @@
 	prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
 	prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
 	prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
+	prefix_num["EVEX"] = "INAT_PFX_EVEX"
 
 	clear_vars()
 }
@@ -253,7 +256,7 @@
 	return add_flags(imm, mod)
 }
 
-/^[0-9a-f]+\:/ {
+/^[0-9a-f]+:/ {
 	if (NR == 1)
 		next
 	# get index
@@ -319,7 +322,9 @@
 			flags = add_flags(flags, "INAT_MODRM")
 
 		# check VEX codes
-		if (match(ext, vexonly_expr))
+		if (match(ext, evexonly_expr))
+			flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY")
+		else if (match(ext, vexonly_expr))
 			flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
 		else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
 			flags = add_flags(flags, "INAT_VEXOK")
--- linux-4.4.0.orig/arch/x86/tools/relocs.c
+++ linux-4.4.0/arch/x86/tools/relocs.c
@@ -769,9 +769,12 @@
 		break;
 
 	case R_X86_64_PC32:
+	case R_X86_64_PLT32:
 		/*
 		 * PC relative relocations don't need to be adjusted unless
 		 * referencing a percpu symbol.
+		 *
+		 * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32.
 		 */
 		if (is_percpu_sym(sym, symname))
 			add_reloc(&relocs32neg, offset);
@@ -836,9 +839,11 @@
 	case R_386_PC32:
 	case R_386_PC16:
 	case R_386_PC8:
+	case R_386_PLT32:
 		/*
-		 * NONE can be ignored and PC relative relocations don't
-		 * need to be adjusted.
+		 * NONE can be ignored and PC relative relocations don't need
+		 * to be adjusted. Because sym must be defined, R_386_PLT32 can
+		 * be treated the same way as R_386_PC32.
 		 */
 		break;
 
@@ -879,9 +884,11 @@
 	case R_386_PC32:
 	case R_386_PC16:
 	case R_386_PC8:
+	case R_386_PLT32:
 		/*
-		 * NONE can be ignored and PC relative relocations don't
-		 * need to be adjusted.
+		 * NONE can be ignored and PC relative relocations don't need
+		 * to be adjusted. Because sym must be defined, R_386_PLT32 can
+		 * be treated the same way as R_386_PC32.
 		 */
 		break;
 
@@ -992,11 +999,12 @@
 		die("Segment relocations found but --realmode not specified\n");
 
 	/* Order the relocations for more efficient processing */
-	sort_relocs(&relocs16);
 	sort_relocs(&relocs32);
 #if ELF_BITS == 64
 	sort_relocs(&relocs32neg);
 	sort_relocs(&relocs64);
+#else
+	sort_relocs(&relocs16);
 #endif
 
 	/* Print the relocations */
--- linux-4.4.0.orig/arch/x86/um/asm/barrier.h
+++ linux-4.4.0/arch/x86/um/asm/barrier.h
@@ -3,7 +3,7 @@
 
 #include <asm/asm.h>
 #include <asm/segment.h>
-#include <asm/cpufeature.h>
+#include <asm/cpufeatures.h>
 #include <asm/cmpxchg.h>
 #include <asm/nops.h>
 
--- linux-4.4.0.orig/arch/x86/um/ldt.c
+++ linux-4.4.0/arch/x86/um/ldt.c
@@ -6,6 +6,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/syscalls.h>
 #include <linux/uaccess.h>
 #include <asm/unistd.h>
 #include <os.h>
@@ -369,7 +370,9 @@
 	mm->arch.ldt.entry_count = 0;
 }
 
-int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
+SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr ,
+		unsigned long , bytecount)
 {
-	return do_modify_ldt_skas(func, ptr, bytecount);
+	/* See non-um modify_ldt() for why we do this cast */
+	return (unsigned int)do_modify_ldt_skas(func, ptr, bytecount);
 }
--- linux-4.4.0.orig/arch/x86/um/ptrace_64.c
+++ linux-4.4.0/arch/x86/um/ptrace_64.c
@@ -121,7 +121,7 @@
 	else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
 		(addr <= offsetof(struct user, u_debugreg[7]))) {
 		addr -= offsetof(struct user, u_debugreg[0]);
-		addr = addr >> 2;
+		addr = addr >> 3;
 		if ((addr == 4) || (addr == 5))
 			return -EIO;
 		child->thread.arch.debugregs[addr] = data;
--- linux-4.4.0.orig/arch/x86/um/setjmp_32.S
+++ linux-4.4.0/arch/x86/um/setjmp_32.S
@@ -16,9 +16,9 @@
 
 	.text
 	.align 4
-	.globl setjmp
-	.type setjmp, @function
-setjmp:
+	.globl kernel_setjmp
+	.type kernel_setjmp, @function
+kernel_setjmp:
 #ifdef _REGPARM
 	movl %eax,%edx
 #else
@@ -35,13 +35,13 @@
 	movl %ecx,20(%edx)		# Return address
 	ret
 
-	.size setjmp,.-setjmp
+	.size kernel_setjmp,.-kernel_setjmp
 
 	.text
 	.align 4
-	.globl longjmp
-	.type longjmp, @function
-longjmp:
+	.globl kernel_longjmp
+	.type kernel_longjmp, @function
+kernel_longjmp:
 #ifdef _REGPARM
 	xchgl %eax,%edx
 #else
@@ -55,4 +55,4 @@
 	movl 16(%edx),%edi
 	jmp *20(%edx)
 
-	.size longjmp,.-longjmp
+	.size kernel_longjmp,.-kernel_longjmp
--- linux-4.4.0.orig/arch/x86/um/setjmp_64.S
+++ linux-4.4.0/arch/x86/um/setjmp_64.S
@@ -18,9 +18,9 @@
 
 	.text
 	.align 4
-	.globl setjmp
-	.type setjmp, @function
-setjmp:
+	.globl kernel_setjmp
+	.type kernel_setjmp, @function
+kernel_setjmp:
 	pop  %rsi			# Return address, and adjust the stack
 	xorl %eax,%eax			# Return value
 	movq %rbx,(%rdi)
@@ -34,13 +34,13 @@
 	movq %rsi,56(%rdi)		# Return address
 	ret
 
-	.size setjmp,.-setjmp
+	.size kernel_setjmp,.-kernel_setjmp
 
 	.text
 	.align 4
-	.globl longjmp
-	.type longjmp, @function
-longjmp:
+	.globl kernel_longjmp
+	.type kernel_longjmp, @function
+kernel_longjmp:
 	movl %esi,%eax			# Return value (int)
 	movq (%rdi),%rbx
 	movq 8(%rdi),%rsp
@@ -51,4 +51,4 @@
 	movq 48(%rdi),%r15
 	jmp *56(%rdi)
 
-	.size longjmp,.-longjmp
+	.size kernel_longjmp,.-kernel_longjmp
--- linux-4.4.0.orig/arch/x86/um/stub_segv.c
+++ linux-4.4.0/arch/x86/um/stub_segv.c
@@ -6,11 +6,12 @@
 #include <sysdep/stub.h>
 #include <sysdep/faultinfo.h>
 #include <sysdep/mcontext.h>
+#include <sys/ucontext.h>
 
 void __attribute__ ((__section__ (".__syscall_stub")))
 stub_segv_handler(int sig, siginfo_t *info, void *p)
 {
-	struct ucontext *uc = p;
+	ucontext_t *uc = p;
 
 	GET_FAULTINFO_FROM_MC(*((struct faultinfo *) STUB_DATA),
 			      &uc->uc_mcontext);
--- linux-4.4.0.orig/arch/x86/xen/apic.c
+++ linux-4.4.0/arch/x86/xen/apic.c
@@ -66,7 +66,7 @@
 
 	ret = HYPERVISOR_dom0_op(&op);
 	if (ret)
-		return 0;
+		op.u.pcpu_info.apic_id = BAD_APICID;
 
 	return op.u.pcpu_info.apic_id << 24;
 }
@@ -142,6 +142,14 @@
 {
 }
 
+static int xen_cpu_present_to_apicid(int cpu)
+{
+	if (cpu_present(cpu))
+		return xen_get_apic_id(xen_apic_read(APIC_ID));
+	else
+		return BAD_APICID;
+}
+
 static struct apic xen_pv_apic = {
 	.name 				= "Xen PV",
 	.probe 				= xen_apic_probe_pv,
@@ -162,7 +170,7 @@
 
 	.ioapic_phys_id_map		= default_ioapic_phys_id_map, /* Used on 32-bit */
 	.setup_apic_routing		= NULL,
-	.cpu_present_to_apicid		= default_cpu_present_to_apicid,
+	.cpu_present_to_apicid		= xen_cpu_present_to_apicid,
 	.apicid_to_cpu_present		= physid_set_mask_of_physid, /* Used on 32-bit */
 	.check_phys_apicid_present	= default_check_phys_apicid_present, /* smp_sanity_check needs it */
 	.phys_pkg_id			= xen_phys_pkg_id, /* detect_ht */
--- linux-4.4.0.orig/arch/x86/xen/enlighten.c
+++ linux-4.4.0/arch/x86/xen/enlighten.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/cpu.h>
+#include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/smp.h>
@@ -74,7 +75,6 @@
 #include <asm/mach_traps.h>
 #include <asm/mwait.h>
 #include <asm/pci_x86.h>
-#include <asm/pat.h>
 #include <asm/cpu.h>
 
 #ifdef CONFIG_ACPI
@@ -434,6 +434,12 @@
 		~((1 << X86_FEATURE_MTRR) |  /* disable MTRR */
 		  (1 << X86_FEATURE_ACC));   /* thermal monitoring */
 
+	/*
+	 * Xen PV would need some work to support PCID: CR3 handling as well
+	 * as xen_flush_tlb_others() would need updating.
+	 */
+	cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_PCID % 32));  /* disable PCID */
+
 	if (!xen_initial_domain())
 		cpuid_leaf1_edx_mask &=
 			~((1 << X86_FEATURE_ACPI));  /* disable ACPI */
@@ -455,6 +461,12 @@
 		cpuid_leaf1_ecx_set_mask = (1 << (X86_FEATURE_MWAIT % 32));
 }
 
+static void __init xen_init_capabilities(void)
+{
+	if (xen_pv_domain())
+		setup_force_cpu_cap(X86_FEATURE_XENPV);
+}
+
 static void xen_set_debugreg(int reg, unsigned long val)
 {
 	HYPERVISOR_set_debugreg(reg, val);
@@ -961,7 +973,7 @@
 	tss->x86_tss.sp0 = thread->sp0;
 }
 
-static void xen_set_iopl_mask(unsigned mask)
+void xen_set_iopl_mask(unsigned mask)
 {
 	struct physdev_set_iopl set_iopl;
 
@@ -1229,10 +1241,7 @@
 
 	.iret = xen_iret,
 #ifdef CONFIG_X86_64
-	.usergs_sysret32 = xen_sysret32,
 	.usergs_sysret64 = xen_sysret64,
-#else
-	.irq_enable_sysexit = xen_sysexit,
 #endif
 
 	.load_tr_desc = paravirt_nop,
@@ -1519,7 +1528,6 @@
 {
 	struct physdev_set_iopl set_iopl;
 	unsigned long initrd_start = 0;
-	u64 pat;
 	int rc;
 
 	if (!xen_start_info)
@@ -1583,6 +1591,7 @@
 
 	xen_init_irq_ops();
 	xen_init_cpuid_mask();
+	xen_init_capabilities();
 
 #ifdef CONFIG_X86_LOCAL_APIC
 	/*
@@ -1627,13 +1636,6 @@
 				   xen_start_info->nr_pages);
 	xen_reserve_special_pages();
 
-	/*
-	 * Modify the cache mode translation tables to match Xen's PAT
-	 * configuration.
-	 */
-	rdmsrl(MSR_IA32_CR_PAT, pat);
-	pat_init_cache_modes(pat);
-
 	/* keep using Xen gdt for now; no urgent need to change it */
 
 #ifdef CONFIG_X86_32
@@ -1886,14 +1888,6 @@
 }
 EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
 
-static void xen_set_cpu_features(struct cpuinfo_x86 *c)
-{
-	if (xen_pv_domain()) {
-		clear_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS);
-		set_cpu_cap(c, X86_FEATURE_XENPV);
-	}
-}
-
 const struct hypervisor_x86 x86_hyper_xen = {
 	.name			= "Xen",
 	.detect			= xen_platform,
@@ -1901,7 +1895,6 @@
 	.init_platform		= xen_hvm_guest_init,
 #endif
 	.x2apic_available	= xen_x2apic_para_available,
-	.set_cpu_features       = xen_set_cpu_features,
 };
 EXPORT_SYMBOL(x86_hyper_xen);
 
--- linux-4.4.0.orig/arch/x86/xen/mmu.c
+++ linux-4.4.0/arch/x86/xen/mmu.c
@@ -1113,7 +1113,7 @@
 
 	/* NOTE: The loop is more greedy than the cleanup_highmap variant.
 	 * We include the PMD passed in on _both_ boundaries. */
-	for (; vaddr <= vaddr_end && (pmd < (level2_kernel_pgt + PAGE_SIZE));
+	for (; vaddr <= vaddr_end && (pmd < (level2_kernel_pgt + PTRS_PER_PMD));
 			pmd++, vaddr += PMD_SIZE) {
 		if (pmd_none(*pmd))
 			continue;
@@ -1316,8 +1316,6 @@
 	struct mmuext_op *op;
 	struct multicall_space mcs;
 
-	trace_xen_mmu_flush_tlb_all(0);
-
 	preempt_disable();
 
 	mcs = xen_mc_entry(sizeof(*op));
@@ -1335,8 +1333,6 @@
 	struct mmuext_op *op;
 	struct multicall_space mcs;
 
-	trace_xen_mmu_flush_tlb(0);
-
 	preempt_disable();
 
 	mcs = xen_mc_entry(sizeof(*op));
@@ -2038,7 +2034,8 @@
 
 /*
  * Translate a virtual address to a physical one without relying on mapped
- * page tables.
+ * page tables. Don't rely on big pages being aligned in (guest) physical
+ * space!
  */
 static phys_addr_t __init xen_early_virt_to_phys(unsigned long vaddr)
 {
@@ -2059,7 +2056,7 @@
 						       sizeof(pud)));
 	if (!pud_present(pud))
 		return 0;
-	pa = pud_pfn(pud) << PAGE_SHIFT;
+	pa = pud_val(pud) & PTE_PFN_MASK;
 	if (pud_large(pud))
 		return pa + (vaddr & ~PUD_MASK);
 
@@ -2067,7 +2064,7 @@
 						       sizeof(pmd)));
 	if (!pmd_present(pmd))
 		return 0;
-	pa = pmd_pfn(pmd) << PAGE_SHIFT;
+	pa = pmd_val(pmd) & PTE_PFN_MASK;
 	if (pmd_large(pmd))
 		return pa + (vaddr & ~PMD_MASK);
 
--- linux-4.4.0.orig/arch/x86/xen/p2m.c
+++ linux-4.4.0/arch/x86/xen/p2m.c
@@ -723,9 +723,12 @@
 
 	for (i = 0; i < count; i++) {
 		unsigned long mfn, pfn;
+		struct gnttab_unmap_grant_ref unmap[2];
+		int rc;
 
 		/* Do not add to override if the map failed. */
-		if (map_ops[i].status)
+		if (map_ops[i].status != GNTST_okay ||
+		    (kmap_ops && kmap_ops[i].status != GNTST_okay))
 			continue;
 
 		if (map_ops[i].flags & GNTMAP_contains_pte) {
@@ -739,10 +742,46 @@
 
 		WARN(pfn_to_mfn(pfn) != INVALID_P2M_ENTRY, "page must be ballooned");
 
-		if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) {
-			ret = -ENOMEM;
-			goto out;
+		if (likely(set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
+			continue;
+
+		/*
+		 * Signal an error for this slot. This in turn requires
+		 * immediate unmapping.
+		 */
+		map_ops[i].status = GNTST_general_error;
+		unmap[0].host_addr = map_ops[i].host_addr,
+		unmap[0].handle = map_ops[i].handle;
+		map_ops[i].handle = ~0;
+		if (map_ops[i].flags & GNTMAP_device_map)
+			unmap[0].dev_bus_addr = map_ops[i].dev_bus_addr;
+		else
+			unmap[0].dev_bus_addr = 0;
+
+		if (kmap_ops) {
+			kmap_ops[i].status = GNTST_general_error;
+			unmap[1].host_addr = kmap_ops[i].host_addr,
+			unmap[1].handle = kmap_ops[i].handle;
+			kmap_ops[i].handle = ~0;
+			if (kmap_ops[i].flags & GNTMAP_device_map)
+				unmap[1].dev_bus_addr = kmap_ops[i].dev_bus_addr;
+			else
+				unmap[1].dev_bus_addr = 0;
 		}
+
+		/*
+		 * Pre-populate both status fields, to be recognizable in
+		 * the log message below.
+		 */
+		unmap[0].status = 1;
+		unmap[1].status = 1;
+
+		rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
+					       unmap, 1 + !!kmap_ops);
+		if (rc || unmap[0].status != GNTST_okay ||
+		    unmap[1].status != GNTST_okay)
+			pr_err_once("gnttab unmap failed: rc=%d st0=%d st1=%d\n",
+				    rc, unmap[0].status, unmap[1].status);
 	}
 
 out:
@@ -763,17 +802,15 @@
 		unsigned long mfn = __pfn_to_mfn(page_to_pfn(pages[i]));
 		unsigned long pfn = page_to_pfn(pages[i]);
 
-		if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) {
+		if (mfn != INVALID_P2M_ENTRY && (mfn & FOREIGN_FRAME_BIT))
+			set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+		else
 			ret = -EINVAL;
-			goto out;
-		}
-
-		set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
 	}
 	if (kunmap_ops)
 		ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
-						kunmap_ops, count);
-out:
+						kunmap_ops, count) ?: ret;
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping);
--- linux-4.4.0.orig/arch/x86/xen/pmu.c
+++ linux-4.4.0/arch/x86/xen/pmu.c
@@ -11,7 +11,7 @@
 #include "pmu.h"
 
 /* x86_pmu.handle_irq definition */
-#include "../kernel/cpu/perf_event.h"
+#include "../events/perf_event.h"
 
 #define XENPMU_IRQ_PROCESSING    1
 struct xenpmu {
@@ -477,7 +477,7 @@
 irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id)
 {
 	int err, ret = IRQ_NONE;
-	struct pt_regs regs;
+	struct pt_regs regs = {0};
 	const struct xen_pmu_data *xenpmu_data = get_xenpmu_data();
 	uint8_t xenpmu_flags = get_xenpmu_flags();
 
--- linux-4.4.0.orig/arch/x86/xen/setup.c
+++ linux-4.4.0/arch/x86/xen/setup.c
@@ -11,6 +11,7 @@
 #include <linux/memblock.h>
 #include <linux/cpuidle.h>
 #include <linux/cpufreq.h>
+#include <linux/irq.h>
 
 #include <asm/elf.h>
 #include <asm/vdso.h>
@@ -393,6 +394,9 @@
 	unsigned long i = 0;
 	unsigned long n = end_pfn - start_pfn;
 
+	if (remap_pfn == 0)
+		remap_pfn = nr_pages;
+
 	while (i < n) {
 		unsigned long cur_pfn = start_pfn + i;
 		unsigned long left = n - i;
@@ -438,17 +442,29 @@
 	return remap_pfn;
 }
 
-static void __init xen_set_identity_and_remap(unsigned long nr_pages)
+static unsigned long __init xen_count_remap_pages(
+	unsigned long start_pfn, unsigned long end_pfn, unsigned long nr_pages,
+	unsigned long remap_pages)
+{
+	if (start_pfn >= nr_pages)
+		return remap_pages;
+
+	return remap_pages + min(end_pfn, nr_pages) - start_pfn;
+}
+
+static unsigned long __init xen_foreach_remap_area(unsigned long nr_pages,
+	unsigned long (*func)(unsigned long start_pfn, unsigned long end_pfn,
+			      unsigned long nr_pages, unsigned long last_val))
 {
 	phys_addr_t start = 0;
-	unsigned long last_pfn = nr_pages;
+	unsigned long ret_val = 0;
 	const struct e820entry *entry = xen_e820_map;
 	int i;
 
 	/*
 	 * Combine non-RAM regions and gaps until a RAM region (or the
-	 * end of the map) is reached, then set the 1:1 map and
-	 * remap the memory in those non-RAM regions.
+	 * end of the map) is reached, then call the provided function
+	 * to perform its duty on the non-RAM region.
 	 *
 	 * The combined non-RAM regions are rounded to a whole number
 	 * of pages so any partial pages are accessible via the 1:1
@@ -466,14 +482,13 @@
 				end_pfn = PFN_UP(entry->addr);
 
 			if (start_pfn < end_pfn)
-				last_pfn = xen_set_identity_and_remap_chunk(
-						start_pfn, end_pfn, nr_pages,
-						last_pfn);
+				ret_val = func(start_pfn, end_pfn, nr_pages,
+					       ret_val);
 			start = end;
 		}
 	}
 
-	pr_info("Released %ld page(s)\n", xen_released_pages);
+	return ret_val;
 }
 
 /*
@@ -596,35 +611,6 @@
 	}
 }
 
-static unsigned long __init xen_count_remap_pages(unsigned long max_pfn)
-{
-	unsigned long extra = 0;
-	unsigned long start_pfn, end_pfn;
-	const struct e820entry *entry = xen_e820_map;
-	int i;
-
-	end_pfn = 0;
-	for (i = 0; i < xen_e820_map_entries; i++, entry++) {
-		start_pfn = PFN_DOWN(entry->addr);
-		/* Adjacent regions on non-page boundaries handling! */
-		end_pfn = min(end_pfn, start_pfn);
-
-		if (start_pfn >= max_pfn)
-			return extra + max_pfn - end_pfn;
-
-		/* Add any holes in map to result. */
-		extra += start_pfn - end_pfn;
-
-		end_pfn = PFN_UP(entry->addr + entry->size);
-		end_pfn = min(end_pfn, max_pfn);
-
-		if (entry->type != E820_RAM)
-			extra += end_pfn - start_pfn;
-	}
-
-	return extra;
-}
-
 bool __init xen_is_e820_reserved(phys_addr_t start, phys_addr_t size)
 {
 	struct e820entry *entry;
@@ -728,10 +714,9 @@
 		size = PFN_PHYS(xen_start_info->nr_p2m_frames);
 	}
 
-	if (!xen_is_e820_reserved(start, size)) {
-		memblock_reserve(start, size);
+	memblock_reserve(start, size);
+	if (!xen_is_e820_reserved(start, size))
 		return;
-	}
 
 #ifdef CONFIG_X86_32
 	/*
@@ -742,6 +727,7 @@
 	BUG();
 #else
 	xen_relocate_p2m();
+	memblock_free(start, size);
 #endif
 }
 
@@ -804,7 +790,7 @@
 	max_pages = xen_get_max_pages();
 
 	/* How many extra pages do we need due to remapping? */
-	max_pages += xen_count_remap_pages(max_pfn);
+	max_pages += xen_foreach_remap_area(max_pfn, xen_count_remap_pages);
 
 	if (max_pages > max_pfn)
 		extra_pages += max_pages - max_pfn;
@@ -922,7 +908,9 @@
 	 * Set identity map on non-RAM pages and prepare remapping the
 	 * underlying RAM.
 	 */
-	xen_set_identity_and_remap(max_pfn);
+	xen_foreach_remap_area(max_pfn, xen_set_identity_and_remap_chunk);
+
+	pr_info("Released %ld page(s)\n", xen_released_pages);
 
 	return "Xen";
 }
--- linux-4.4.0.orig/arch/x86/xen/smp.c
+++ linux-4.4.0/arch/x86/xen/smp.c
@@ -28,6 +28,7 @@
 #include <xen/interface/vcpu.h>
 #include <xen/interface/xenpmu.h>
 
+#include <asm/spec-ctrl.h>
 #include <asm/xen/interface.h>
 #include <asm/xen/hypercall.h>
 
@@ -87,6 +88,8 @@
 	cpu_data(cpu).x86_max_cores = 1;
 	set_cpu_sibling_map(cpu);
 
+	speculative_store_bypass_ht_init();
+
 	xen_setup_cpu_clockevents();
 
 	notify_cpu_starting(cpu);
@@ -113,6 +116,7 @@
 #endif
 	cpu_bringup();
 	cpu_startup_entry(CPUHP_ONLINE);
+	prevent_tail_call_optimization();
 }
 
 static void xen_smp_intr_free(unsigned int cpu)
@@ -357,6 +361,8 @@
 	}
 	set_cpu_sibling_map(0);
 
+	speculative_store_bypass_ht_init();
+
 	xen_pmu_init(0);
 
 	if (xen_smp_intr_init(0))
--- linux-4.4.0.orig/arch/x86/xen/spinlock.c
+++ linux-4.4.0/arch/x86/xen/spinlock.c
@@ -8,6 +8,7 @@
 #include <linux/log2.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
+#include <linux/atomic.h>
 
 #include <asm/paravirt.h>
 
@@ -19,6 +20,7 @@
 
 static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
 static DEFINE_PER_CPU(char *, irq_name);
+static DEFINE_PER_CPU(atomic_t, xen_qlock_wait_nest);
 static bool xen_pvspin = true;
 
 #ifdef CONFIG_QUEUED_SPINLOCKS
@@ -27,6 +29,12 @@
 
 static void xen_qlock_kick(int cpu)
 {
+	int irq = per_cpu(lock_kicker_irq, cpu);
+
+	/* Don't kick if the target's kicker interrupt is not initialized. */
+	if (irq == -1)
+		return;
+
 	xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
 }
 
@@ -36,33 +44,24 @@
 static void xen_qlock_wait(u8 *byte, u8 val)
 {
 	int irq = __this_cpu_read(lock_kicker_irq);
+	atomic_t *nest_cnt = this_cpu_ptr(&xen_qlock_wait_nest);
 
 	/* If kicker interrupts not initialized yet, just spin */
-	if (irq == -1)
+	if (irq == -1 || in_nmi())
 		return;
 
-	/* clear pending */
-	xen_clear_irq_pending(irq);
-	barrier();
-
-	/*
-	 * We check the byte value after clearing pending IRQ to make sure
-	 * that we won't miss a wakeup event because of the clearing.
-	 *
-	 * The sync_clear_bit() call in xen_clear_irq_pending() is atomic.
-	 * So it is effectively a memory barrier for x86.
-	 */
-	if (READ_ONCE(*byte) != val)
-		return;
+	/* Detect reentry. */
+	atomic_inc(nest_cnt);
 
-	/*
-	 * If an interrupt happens here, it will leave the wakeup irq
-	 * pending, which will cause xen_poll_irq() to return
-	 * immediately.
-	 */
+	/* If irq pending already and no nested call clear it. */
+	if (atomic_read(nest_cnt) == 1 && xen_test_irq_pending(irq)) {
+		xen_clear_irq_pending(irq);
+	} else if (READ_ONCE(*byte) == val) {
+		/* Block until irq becomes pending (or a spurious wakeup) */
+		xen_poll_irq(irq);
+	}
 
-	/* Block until irq becomes pending (or perhaps a spurious wakeup) */
-	xen_poll_irq(irq);
+	atomic_dec(nest_cnt);
 }
 
 #else /* CONFIG_QUEUED_SPINLOCKS */
@@ -302,10 +301,20 @@
 
 void xen_uninit_lock_cpu(int cpu)
 {
+	int irq;
+
 	if (!xen_pvspin)
 		return;
 
-	unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+	/*
+	 * When booting the kernel with 'mitigations=auto,nosmt', the secondary
+	 * CPUs are not activated, and lock_kicker_irq is not initialized.
+	 */
+	irq = per_cpu(lock_kicker_irq, cpu);
+	if (irq == -1)
+		return;
+
+	unbind_from_irqhandler(irq, NULL);
 	per_cpu(lock_kicker_irq, cpu) = -1;
 	kfree(per_cpu(irq_name, cpu));
 	per_cpu(irq_name, cpu) = NULL;
--- linux-4.4.0.orig/arch/x86/xen/suspend.c
+++ linux-4.4.0/arch/x86/xen/suspend.c
@@ -1,11 +1,14 @@
 #include <linux/types.h>
 #include <linux/tick.h>
+#include <linux/percpu-defs.h>
 
 #include <xen/xen.h>
 #include <xen/interface/xen.h>
 #include <xen/grant_table.h>
 #include <xen/events.h>
 
+#include <asm/cpufeatures.h>
+#include <asm/msr-index.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/page.h>
 #include <asm/fixmap.h>
@@ -34,7 +37,8 @@
 {
 #ifdef CONFIG_XEN_PVHVM
 	int cpu;
-	xen_hvm_init_shared_info();
+	if (!suspend_cancelled)
+	    xen_hvm_init_shared_info();
 	xen_callback_vector();
 	xen_unplug_emulated_devices();
 	if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
@@ -67,6 +71,8 @@
 	xen_mm_unpin_all();
 }
 
+static DEFINE_PER_CPU(u64, spec_ctrl);
+
 void xen_arch_pre_suspend(void)
 {
 	if (xen_pv_domain())
@@ -83,6 +89,9 @@
 
 static void xen_vcpu_notify_restore(void *data)
 {
+	if (xen_pv_domain() && boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+		wrmsrl(MSR_IA32_SPEC_CTRL, this_cpu_read(spec_ctrl));
+
 	/* Boot processor notified via generic timekeeping_resume() */
 	if (smp_processor_id() == 0)
 		return;
@@ -92,7 +101,15 @@
 
 static void xen_vcpu_notify_suspend(void *data)
 {
+	u64 tmp;
+
 	tick_suspend_local();
+
+	if (xen_pv_domain() && boot_cpu_has(X86_FEATURE_SPEC_CTRL)) {
+		rdmsrl(MSR_IA32_SPEC_CTRL, tmp);
+		this_cpu_write(spec_ctrl, tmp);
+		wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+	}
 }
 
 void xen_arch_resume(void)
--- linux-4.4.0.orig/arch/x86/xen/time.c
+++ linux-4.4.0/arch/x86/xen/time.c
@@ -343,11 +343,11 @@
 	WARN_ON(!clockevent_state_oneshot(evt));
 
 	single.timeout_abs_ns = get_abs_timeout(delta);
-	single.flags = VCPU_SSHOTTMR_future;
+	/* Get an event anyway, even if the timeout is already expired */
+	single.flags = 0;
 
 	ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
-
-	BUG_ON(ret != 0 && ret != -ETIME);
+	BUG_ON(ret != 0);
 
 	return ret;
 }
--- linux-4.4.0.orig/arch/x86/xen/xen-asm_32.S
+++ linux-4.4.0/arch/x86/xen/xen-asm_32.S
@@ -35,20 +35,6 @@
 	ret
 
 /*
- * We can't use sysexit directly, because we're not running in ring0.
- * But we can easily fake it up using iret.  Assuming xen_sysexit is
- * jumped to with a standard stack frame, we can just strip it back to
- * a standard iret frame and use iret.
- */
-ENTRY(xen_sysexit)
-	movl PT_EAX(%esp), %eax			/* Shouldn't be necessary? */
-	orl $X86_EFLAGS_IF, PT_EFLAGS(%esp)
-	lea PT_EIP(%esp), %esp
-
-	jmp xen_iret
-ENDPROC(xen_sysexit)
-
-/*
  * This is run where a normal iret would be run, with the same stack setup:
  *	8: eflags
  *	4: cs
--- linux-4.4.0.orig/arch/x86/xen/xen-ops.h
+++ linux-4.4.0/arch/x86/xen/xen-ops.h
@@ -139,9 +139,6 @@
 
 /* These are not functions, and cannot be called normally */
 __visible void xen_iret(void);
-#ifdef CONFIG_X86_32
-__visible void xen_sysexit(void);
-#endif
 __visible void xen_sysret32(void);
 __visible void xen_sysret64(void);
 __visible void xen_adjust_exception_frame(void);
--- linux-4.4.0.orig/arch/xtensa/boot/Makefile
+++ linux-4.4.0/arch/xtensa/boot/Makefile
@@ -31,7 +31,7 @@
 	      $(addprefix $(obj)/,$(host-progs))
 	$(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
 
-OBJCOPYFLAGS = --strip-all -R .comment -R .note.gnu.build-id -O binary
+OBJCOPYFLAGS = --strip-all -R .comment -R .notes -O binary
 
 vmlinux.bin: vmlinux FORCE
 	$(call if_changed,objcopy)
--- linux-4.4.0.orig/arch/xtensa/configs/smp_lx200_defconfig
+++ linux-4.4.0/arch/xtensa/configs/smp_lx200_defconfig
@@ -35,6 +35,7 @@
 CONFIG_HOTPLUG_CPU=y
 # CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX is not set
 # CONFIG_PCI is not set
+CONFIG_VECTORS_OFFSET=0x00002000
 CONFIG_XTENSA_PLATFORM_XTFPGA=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug"
--- linux-4.4.0.orig/arch/xtensa/include/asm/futex.h
+++ linux-4.4.0/arch/xtensa/include/asm/futex.h
@@ -44,18 +44,10 @@
 	: "r" (uaddr), "I" (-EFAULT), "r" (oparg)	\
 	: "memory")
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 #if !XCHAL_HAVE_S32C1I
 	return -ENOSYS;
@@ -89,19 +81,10 @@
 
 	pagefault_enable();
 
-	if (ret)
-		return ret;
+	if (!ret)
+		*oval = oldval;
 
-	switch (cmp) {
-	case FUTEX_OP_CMP_EQ: return (oldval == cmparg);
-	case FUTEX_OP_CMP_NE: return (oldval != cmparg);
-	case FUTEX_OP_CMP_LT: return (oldval < cmparg);
-	case FUTEX_OP_CMP_GE: return (oldval >= cmparg);
-	case FUTEX_OP_CMP_LE: return (oldval <= cmparg);
-	case FUTEX_OP_CMP_GT: return (oldval > cmparg);
-	}
-
-	return -ENOSYS;
+	return ret;
 }
 
 static inline int
@@ -109,7 +92,6 @@
 			      u32 oldval, u32 newval)
 {
 	int ret = 0;
-	u32 prev;
 
 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
@@ -120,26 +102,24 @@
 
 	__asm__ __volatile__ (
 	"	# futex_atomic_cmpxchg_inatomic\n"
-	"1:	l32i	%1, %3, 0\n"
-	"	mov	%0, %5\n"
-	"	wsr	%1, scompare1\n"
-	"2:	s32c1i	%0, %3, 0\n"
-	"3:\n"
+	"	wsr	%5, scompare1\n"
+	"1:	s32c1i	%1, %4, 0\n"
+	"	s32i	%1, %6, 0\n"
+	"2:\n"
 	"	.section .fixup,\"ax\"\n"
 	"	.align 4\n"
-	"4:	.long	3b\n"
-	"5:	l32r	%1, 4b\n"
-	"	movi	%0, %6\n"
+	"3:	.long	2b\n"
+	"4:	l32r	%1, 3b\n"
+	"	movi	%0, %7\n"
 	"	jx	%1\n"
 	"	.previous\n"
 	"	.section __ex_table,\"a\"\n"
-	"	.long 1b,5b,2b,5b\n"
+	"	.long 1b,4b\n"
 	"	.previous\n"
-	: "+r" (ret), "=&r" (prev), "+m" (*uaddr)
-	: "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
+	: "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
+	: "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
 	: "memory");
 
-	*uval = prev;
 	return ret;
 }
 
--- linux-4.4.0.orig/arch/xtensa/include/asm/irq.h
+++ linux-4.4.0/arch/xtensa/include/asm/irq.h
@@ -29,7 +29,8 @@
 # define PLATFORM_NR_IRQS 0
 #endif
 #define XTENSA_NR_IRQS XCHAL_NUM_INTERRUPTS
-#define NR_IRQS (XTENSA_NR_IRQS + VARIANT_NR_IRQS + PLATFORM_NR_IRQS)
+#define NR_IRQS (XTENSA_NR_IRQS + VARIANT_NR_IRQS + PLATFORM_NR_IRQS + 1)
+#define XTENSA_PIC_LINUX_IRQ(hwirq) ((hwirq) + 1)
 
 #if VARIANT_NR_IRQS == 0
 static inline void variant_init_irq(void) { }
--- linux-4.4.0.orig/arch/xtensa/include/asm/processor.h
+++ linux-4.4.0/arch/xtensa/include/asm/processor.h
@@ -24,7 +24,11 @@
 # error Linux requires the Xtensa Windowed Registers Option.
 #endif
 
-#define ARCH_SLAB_MINALIGN	XCHAL_DATA_WIDTH
+/* Xtensa ABI requires stack alignment to be at least 16 */
+
+#define STACK_ALIGN (XCHAL_DATA_WIDTH > 16 ? XCHAL_DATA_WIDTH : 16)
+
+#define ARCH_SLAB_MINALIGN STACK_ALIGN
 
 /*
  * User space process size: 1 GB.
--- linux-4.4.0.orig/arch/xtensa/kernel/asm-offsets.c
+++ linux-4.4.0/arch/xtensa/kernel/asm-offsets.c
@@ -90,14 +90,14 @@
 	DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
 	DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable));
 #if XTENSA_HAVE_COPROCESSORS
-	DEFINE(THREAD_XTREGS_CP0, offsetof (struct thread_info, xtregs_cp));
-	DEFINE(THREAD_XTREGS_CP1, offsetof (struct thread_info, xtregs_cp));
-	DEFINE(THREAD_XTREGS_CP2, offsetof (struct thread_info, xtregs_cp));
-	DEFINE(THREAD_XTREGS_CP3, offsetof (struct thread_info, xtregs_cp));
-	DEFINE(THREAD_XTREGS_CP4, offsetof (struct thread_info, xtregs_cp));
-	DEFINE(THREAD_XTREGS_CP5, offsetof (struct thread_info, xtregs_cp));
-	DEFINE(THREAD_XTREGS_CP6, offsetof (struct thread_info, xtregs_cp));
-	DEFINE(THREAD_XTREGS_CP7, offsetof (struct thread_info, xtregs_cp));
+	DEFINE(THREAD_XTREGS_CP0, offsetof(struct thread_info, xtregs_cp.cp0));
+	DEFINE(THREAD_XTREGS_CP1, offsetof(struct thread_info, xtregs_cp.cp1));
+	DEFINE(THREAD_XTREGS_CP2, offsetof(struct thread_info, xtregs_cp.cp2));
+	DEFINE(THREAD_XTREGS_CP3, offsetof(struct thread_info, xtregs_cp.cp3));
+	DEFINE(THREAD_XTREGS_CP4, offsetof(struct thread_info, xtregs_cp.cp4));
+	DEFINE(THREAD_XTREGS_CP5, offsetof(struct thread_info, xtregs_cp.cp5));
+	DEFINE(THREAD_XTREGS_CP6, offsetof(struct thread_info, xtregs_cp.cp6));
+	DEFINE(THREAD_XTREGS_CP7, offsetof(struct thread_info, xtregs_cp.cp7));
 #endif
 	DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user));
 	DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t));
--- linux-4.4.0.orig/arch/xtensa/kernel/head.S
+++ linux-4.4.0/arch/xtensa/kernel/head.S
@@ -88,9 +88,12 @@
 	initialize_mmu
 #if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
 	rsr	a2, excsave1
-	movi	a3, 0x08000000
+	movi	a3, XCHAL_KSEG_PADDR
+	bltu	a2, a3, 1f
+	sub	a2, a2, a3
+	movi	a3, XCHAL_KSEG_SIZE
 	bgeu	a2, a3, 1f
-	movi	a3, 0xd0000000
+	movi	a3, XCHAL_KSEG_CACHED_VADDR
 	add	a2, a2, a3
 	wsr	a2, excsave1
 1:
@@ -128,7 +131,7 @@
 	wsr	a0, icountlevel
 
 	.set	_index, 0
-	.rept	XCHAL_NUM_DBREAK - 1
+	.rept	XCHAL_NUM_DBREAK
 	wsr	a0, SREG_DBREAKC + _index
 	.set	_index, _index + 1
 	.endr
@@ -283,12 +286,13 @@
 
 	movi	a2, cpu_start_ccount
 1:
+	memw
 	l32i	a3, a2, 0
 	beqi	a3, 0, 1b
 	movi	a3, 0
 	s32i	a3, a2, 0
-	memw
 1:
+	memw
 	l32i	a3, a2, 0
 	beqi	a3, 0, 1b
 	wsr	a3, ccount
@@ -325,11 +329,13 @@
 	rsr	a0, prid
 	neg	a2, a0
 	movi	a3, cpu_start_id
+	memw
 	s32i	a2, a3, 0
 #if XCHAL_DCACHE_IS_WRITEBACK
 	dhwbi	a3, 0
 #endif
 1:
+	memw
 	l32i	a2, a3, 0
 	dhi	a3, 0
 	bne	a2, a0, 1b
--- linux-4.4.0.orig/arch/xtensa/kernel/irq.c
+++ linux-4.4.0/arch/xtensa/kernel/irq.c
@@ -34,11 +34,6 @@
 {
 	int irq = irq_find_mapping(NULL, hwirq);
 
-	if (hwirq >= NR_IRQS) {
-		printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
-				__func__, hwirq);
-	}
-
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 	/* Debugging check for stack overflow: is there less than 1KB free? */
 	{
--- linux-4.4.0.orig/arch/xtensa/kernel/process.c
+++ linux-4.4.0/arch/xtensa/kernel/process.c
@@ -83,18 +83,21 @@
 
 void coprocessor_flush_all(struct thread_info *ti)
 {
-	unsigned long cpenable;
+	unsigned long cpenable, old_cpenable;
 	int i;
 
 	preempt_disable();
 
+	RSR_CPENABLE(old_cpenable);
 	cpenable = ti->cpenable;
+	WSR_CPENABLE(cpenable);
 
 	for (i = 0; i < XCHAL_CP_MAX; i++) {
 		if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti)
 			coprocessor_flush(ti, i);
 		cpenable >>= 1;
 	}
+	WSR_CPENABLE(old_cpenable);
 
 	preempt_enable();
 }
--- linux-4.4.0.orig/arch/xtensa/kernel/setup.c
+++ linux-4.4.0/arch/xtensa/kernel/setup.c
@@ -133,6 +133,8 @@
 
 __tagtable(BP_TAG_INITRD, parse_tag_initrd);
 
+#endif /* CONFIG_BLK_DEV_INITRD */
+
 #ifdef CONFIG_OF
 
 static int __init parse_tag_fdt(const bp_tag_t *tag)
@@ -145,8 +147,6 @@
 
 #endif /* CONFIG_OF */
 
-#endif /* CONFIG_BLK_DEV_INITRD */
-
 static int __init parse_tag_cmdline(const bp_tag_t* tag)
 {
 	strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
@@ -716,7 +716,8 @@
 static void *
 c_next(struct seq_file *f, void *v, loff_t *pos)
 {
-	return NULL;
+	++*pos;
+	return c_start(f, pos);
 }
 
 static void
--- linux-4.4.0.orig/arch/xtensa/kernel/smp.c
+++ linux-4.4.0/arch/xtensa/kernel/smp.c
@@ -80,7 +80,7 @@
 {
 	unsigned i;
 
-	for (i = 0; i < max_cpus; ++i)
+	for_each_possible_cpu(i)
 		set_cpu_present(i, true);
 }
 
@@ -93,6 +93,11 @@
 	pr_info("%s: Core Count = %d\n", __func__, ncpus);
 	pr_info("%s: Core Id = %d\n", __func__, core_id);
 
+	if (ncpus > NR_CPUS) {
+		ncpus = NR_CPUS;
+		pr_info("%s: limiting core count by %d\n", __func__, ncpus);
+	}
+
 	for (i = 0; i < ncpus; ++i)
 		set_cpu_possible(i, true);
 }
@@ -192,9 +197,11 @@
 	int i;
 
 #ifdef CONFIG_HOTPLUG_CPU
-	cpu_start_id = cpu;
-	system_flush_invalidate_dcache_range(
-			(unsigned long)&cpu_start_id, sizeof(cpu_start_id));
+	WRITE_ONCE(cpu_start_id, cpu);
+	/* Pairs with the third memw in the cpu_restart */
+	mb();
+	system_flush_invalidate_dcache_range((unsigned long)&cpu_start_id,
+					     sizeof(cpu_start_id));
 #endif
 	smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1);
 
@@ -203,18 +210,21 @@
 			ccount = get_ccount();
 		while (!ccount);
 
-		cpu_start_ccount = ccount;
+		WRITE_ONCE(cpu_start_ccount, ccount);
 
-		while (time_before(jiffies, timeout)) {
+		do {
+			/*
+			 * Pairs with the first two memws in the
+			 * .Lboot_secondary.
+			 */
 			mb();
-			if (!cpu_start_ccount)
-				break;
-		}
+			ccount = READ_ONCE(cpu_start_ccount);
+		} while (ccount && time_before(jiffies, timeout));
 
-		if (cpu_start_ccount) {
+		if (ccount) {
 			smp_call_function_single(0, mx_cpu_stop,
-					(void *)cpu, 1);
-			cpu_start_ccount = 0;
+						 (void *)cpu, 1);
+			WRITE_ONCE(cpu_start_ccount, 0);
 			return -EIO;
 		}
 	}
@@ -234,6 +244,7 @@
 	pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n",
 			__func__, cpu, idle, start_info.stack);
 
+	init_completion(&cpu_running);
 	ret = boot_secondary(cpu, idle);
 	if (ret == 0) {
 		wait_for_completion_timeout(&cpu_running,
@@ -295,8 +306,10 @@
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 	while (time_before(jiffies, timeout)) {
 		system_invalidate_dcache_range((unsigned long)&cpu_start_id,
-				sizeof(cpu_start_id));
-		if (cpu_start_id == -cpu) {
+					       sizeof(cpu_start_id));
+		/* Pairs with the second memw in the cpu_restart */
+		mb();
+		if (READ_ONCE(cpu_start_id) == -cpu) {
 			platform_cpu_kill(cpu);
 			return;
 		}
--- linux-4.4.0.orig/arch/xtensa/kernel/stacktrace.c
+++ linux-4.4.0/arch/xtensa/kernel/stacktrace.c
@@ -272,10 +272,14 @@
 	return 1;
 }
 
+/*
+ * level == 0 is for the return address from the caller of this function,
+ * not from this function itself.
+ */
 unsigned long return_address(unsigned level)
 {
 	struct return_addr_data r = {
-		.skip = level + 1,
+		.skip = level,
 	};
 	walk_stackframe(stack_pointer(NULL), return_address_cb, &r);
 	return r.addr;
--- linux-4.4.0.orig/arch/xtensa/kernel/syscall.c
+++ linux-4.4.0/arch/xtensa/kernel/syscall.c
@@ -87,7 +87,7 @@
 		/* At this point:  (!vmm || addr < vmm->vm_end). */
 		if (TASK_SIZE - len < addr)
 			return -ENOMEM;
-		if (!vmm || addr + len <= vmm->vm_start)
+		if (!vmm || addr + len <= vm_start_gap(vmm))
 			return addr;
 		addr = vmm->vm_end;
 		if (flags & MAP_SHARED)
--- linux-4.4.0.orig/arch/xtensa/kernel/time.c
+++ linux-4.4.0/arch/xtensa/kernel/time.c
@@ -87,7 +87,7 @@
 		container_of(evt, struct ccount_timer, evt);
 
 	if (timer->irq_enabled) {
-		disable_irq(evt->irq);
+		disable_irq_nosync(evt->irq);
 		timer->irq_enabled = 0;
 	}
 	return 0;
--- linux-4.4.0.orig/arch/xtensa/kernel/traps.c
+++ linux-4.4.0/arch/xtensa/kernel/traps.c
@@ -309,7 +309,7 @@
 	info.si_errno = 0;
 	info.si_code = BUS_ADRALN;
 	info.si_addr = (void *) regs->excvaddr;
-	force_sig_info(SIGSEGV, &info, current);
+	force_sig_info(SIGBUS, &info, current);
 
 }
 #endif
--- linux-4.4.0.orig/arch/xtensa/kernel/vmlinux.lds.S
+++ linux-4.4.0/arch/xtensa/kernel/vmlinux.lds.S
@@ -110,6 +110,7 @@
   .fixup   : { *(.fixup) }
 
   EXCEPTION_TABLE(16)
+  NOTES
   /* Data section */
 
   _sdata = .;
--- linux-4.4.0.orig/arch/xtensa/kernel/xtensa_ksyms.c
+++ linux-4.4.0/arch/xtensa/kernel/xtensa_ksyms.c
@@ -82,13 +82,13 @@
 }
 EXPORT_SYMBOL(__xtensa_libgcc_window_spill);
 
-unsigned long __sync_fetch_and_and_4(unsigned long *p, unsigned long v)
+unsigned int __sync_fetch_and_and_4(volatile void *p, unsigned int v)
 {
 	BUG();
 }
 EXPORT_SYMBOL(__sync_fetch_and_and_4);
 
-unsigned long __sync_fetch_and_or_4(unsigned long *p, unsigned long v)
+unsigned int __sync_fetch_and_or_4(volatile void *p, unsigned int v)
 {
 	BUG();
 }
@@ -116,13 +116,6 @@
 // FIXME EXPORT_SYMBOL(screen_info);
 #endif
 
-EXPORT_SYMBOL(outsb);
-EXPORT_SYMBOL(outsw);
-EXPORT_SYMBOL(outsl);
-EXPORT_SYMBOL(insb);
-EXPORT_SYMBOL(insw);
-EXPORT_SYMBOL(insl);
-
 extern long common_exception_return;
 EXPORT_SYMBOL(common_exception_return);
 
--- linux-4.4.0.orig/arch/xtensa/mm/cache.c
+++ linux-4.4.0/arch/xtensa/mm/cache.c
@@ -74,8 +74,10 @@
 			kvaddr = TLBTEMP_BASE_1 +
 				(page_to_phys(page) & DCACHE_ALIAS_MASK);
 
+			preempt_disable();
 			__invalidate_dcache_page_alias(kvaddr,
 						       page_to_phys(page));
+			preempt_enable();
 		}
 	}
 }
@@ -97,11 +99,11 @@
 	unsigned long paddr;
 	void *kvaddr = coherent_kvaddr(page, TLBTEMP_BASE_1, vaddr, &paddr);
 
-	pagefault_disable();
+	preempt_disable();
 	kmap_invalidate_coherent(page, vaddr);
 	set_bit(PG_arch_1, &page->flags);
 	clear_page_alias(kvaddr, paddr);
-	pagefault_enable();
+	preempt_enable();
 }
 
 void copy_user_highpage(struct page *dst, struct page *src,
@@ -113,11 +115,11 @@
 	void *src_vaddr = coherent_kvaddr(src, TLBTEMP_BASE_2, vaddr,
 					  &src_paddr);
 
-	pagefault_disable();
+	preempt_disable();
 	kmap_invalidate_coherent(dst, vaddr);
 	set_bit(PG_arch_1, &dst->flags);
 	copy_page_alias(dst_vaddr, src_vaddr, dst_paddr, src_paddr);
-	pagefault_enable();
+	preempt_enable();
 }
 
 #endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
@@ -162,6 +164,7 @@
 		if (!alias && !mapping)
 			return;
 
+		preempt_disable();
 		virt = TLBTEMP_BASE_1 + (phys & DCACHE_ALIAS_MASK);
 		__flush_invalidate_dcache_page_alias(virt, phys);
 
@@ -172,6 +175,7 @@
 
 		if (mapping)
 			__invalidate_icache_page_alias(virt, phys);
+		preempt_enable();
 	}
 
 	/* There shouldn't be an entry in the cache for this page anymore. */
@@ -204,8 +208,10 @@
 	unsigned long phys = page_to_phys(pfn_to_page(pfn));
 	unsigned long virt = TLBTEMP_BASE_1 + (address & DCACHE_ALIAS_MASK);
 
+	preempt_disable();
 	__flush_invalidate_dcache_page_alias(virt, phys);
 	__invalidate_icache_page_alias(virt, phys);
+	preempt_enable();
 }
 
 #endif
@@ -231,11 +237,13 @@
 		unsigned long phys = page_to_phys(page);
 		unsigned long tmp;
 
+		preempt_disable();
 		tmp = TLBTEMP_BASE_1 + (phys & DCACHE_ALIAS_MASK);
 		__flush_invalidate_dcache_page_alias(tmp, phys);
 		tmp = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
 		__flush_invalidate_dcache_page_alias(tmp, phys);
 		__invalidate_icache_page_alias(tmp, phys);
+		preempt_enable();
 
 		clear_bit(PG_arch_1, &page->flags);
 	}
@@ -269,7 +277,9 @@
 
 	if (alias) {
 		unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+		preempt_disable();
 		__flush_invalidate_dcache_page_alias(t, phys);
+		preempt_enable();
 	}
 
 	/* Copy data */
@@ -284,9 +294,11 @@
 	if (alias) {
 		unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
 
+		preempt_disable();
 		__flush_invalidate_dcache_range((unsigned long) dst, len);
 		if ((vma->vm_flags & VM_EXEC) != 0)
 			__invalidate_icache_page_alias(t, phys);
+		preempt_enable();
 
 	} else if ((vma->vm_flags & VM_EXEC) != 0) {
 		__flush_dcache_range((unsigned long)dst,len);
@@ -308,7 +320,9 @@
 
 	if (alias) {
 		unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+		preempt_disable();
 		__flush_invalidate_dcache_page_alias(t, phys);
+		preempt_enable();
 	}
 
 	memcpy(dst, src, len);
--- linux-4.4.0.orig/arch/xtensa/mm/tlb.c
+++ linux-4.4.0/arch/xtensa/mm/tlb.c
@@ -218,6 +218,8 @@
 	unsigned tlbidx = w | (e << PAGE_SHIFT);
 	unsigned r0 = dtlb ?
 		read_dtlb_virtual(tlbidx) : read_itlb_virtual(tlbidx);
+	unsigned r1 = dtlb ?
+		read_dtlb_translation(tlbidx) : read_itlb_translation(tlbidx);
 	unsigned vpn = (r0 & PAGE_MASK) | (e << PAGE_SHIFT);
 	unsigned pte = get_pte_for_vaddr(vpn);
 	unsigned mm_asid = (get_rasid_register() >> 8) & ASID_MASK;
@@ -233,8 +235,6 @@
 	}
 
 	if (tlb_asid == mm_asid) {
-		unsigned r1 = dtlb ? read_dtlb_translation(tlbidx) :
-			read_itlb_translation(tlbidx);
 		if ((pte ^ r1) & PAGE_MASK) {
 			pr_err("%cTLB: way: %u, entry: %u, mapping: %08x->%08x, PTE: %08x\n",
 					dtlb ? 'D' : 'I', w, e, r0, r1, pte);
--- linux-4.4.0.orig/arch/xtensa/platforms/iss/console.c
+++ linux-4.4.0/arch/xtensa/platforms/iss/console.c
@@ -100,21 +100,23 @@
 {
 	struct tty_port *port = (struct tty_port *)priv;
 	int i = 0;
+	int rd = 1;
 	unsigned char c;
 
 	spin_lock(&timer_lock);
 
 	while (simc_poll(0)) {
-		simc_read(0, &c, 1);
+		rd = simc_read(0, &c, 1);
+		if (rd <= 0)
+			break;
 		tty_insert_flip_char(port, c, TTY_NORMAL);
 		i++;
 	}
 
 	if (i)
 		tty_flip_buffer_push(port);
-
-
-	mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
+	if (rd)
+		mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
 	spin_unlock(&timer_lock);
 }
 
--- linux-4.4.0.orig/arch/xtensa/platforms/iss/simdisk.c
+++ linux-4.4.0/arch/xtensa/platforms/iss/simdisk.c
@@ -21,7 +21,6 @@
 #include <platform/simcall.h>
 
 #define SIMDISK_MAJOR 240
-#define SECTOR_SHIFT 9
 #define SIMDISK_MINORS 1
 #define MAX_SIMDISK_COUNT 10
 
--- linux-4.4.0.orig/arch/xtensa/platforms/xtfpga/include/platform/hardware.h
+++ linux-4.4.0/arch/xtensa/platforms/xtfpga/include/platform/hardware.h
@@ -24,16 +24,18 @@
 
 /* Interrupt configuration. */
 
-#define PLATFORM_NR_IRQS	10
+#define PLATFORM_NR_IRQS	0
 
 /* Default assignment of LX60 devices to external interrupts. */
 
 #ifdef CONFIG_XTENSA_MX
 #define DUART16552_INTNUM	XCHAL_EXTINT3_NUM
 #define OETH_IRQ		XCHAL_EXTINT4_NUM
+#define C67X00_IRQ		XCHAL_EXTINT8_NUM
 #else
 #define DUART16552_INTNUM	XCHAL_EXTINT0_NUM
 #define OETH_IRQ		XCHAL_EXTINT1_NUM
+#define C67X00_IRQ		XCHAL_EXTINT5_NUM
 #endif
 
 /*
@@ -63,5 +65,5 @@
 
 #define C67X00_PADDR		(XCHAL_KIO_PADDR + 0x0D0D0000)
 #define C67X00_SIZE		0x10
-#define C67X00_IRQ		5
+
 #endif /* __XTENSA_XTAVNET_HARDWARE_H */
--- linux-4.4.0.orig/arch/xtensa/platforms/xtfpga/setup.c
+++ linux-4.4.0/arch/xtensa/platforms/xtfpga/setup.c
@@ -209,8 +209,8 @@
 		.flags = IORESOURCE_MEM,
 	},
 	[2] = { /* IRQ number */
-		.start = OETH_IRQ,
-		.end   = OETH_IRQ,
+		.start = XTENSA_PIC_LINUX_IRQ(OETH_IRQ),
+		.end   = XTENSA_PIC_LINUX_IRQ(OETH_IRQ),
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -246,8 +246,8 @@
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = { /* IRQ number */
-		.start = C67X00_IRQ,
-		.end   = C67X00_IRQ,
+		.start = XTENSA_PIC_LINUX_IRQ(C67X00_IRQ),
+		.end   = XTENSA_PIC_LINUX_IRQ(C67X00_IRQ),
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -280,7 +280,7 @@
 static struct plat_serial8250_port serial_platform_data[] = {
 	[0] = {
 		.mapbase	= DUART16552_PADDR,
-		.irq		= DUART16552_INTNUM,
+		.irq		= XTENSA_PIC_LINUX_IRQ(DUART16552_INTNUM),
 		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
 				  UPF_IOREMAP,
 		.iotype		= UPIO_MEM32,
--- linux-4.4.0.orig/block/bio-integrity.c
+++ linux-4.4.0/block/bio-integrity.c
@@ -66,7 +66,7 @@
 	}
 
 	if (unlikely(!bip))
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	memset(bip, 0, sizeof(*bip));
 
@@ -89,7 +89,7 @@
 	return bip;
 err:
 	mempool_free(bip, bs->bio_integrity_pool);
-	return NULL;
+	return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL(bio_integrity_alloc);
 
@@ -175,6 +175,9 @@
 	if (!bio_is_rw(bio))
 		return false;
 
+	if (!bio_sectors(bio))
+		return false;
+
 	/* Already protected? */
 	if (bio_integrity(bio))
 		return false;
@@ -276,17 +279,27 @@
 	unsigned int len, nr_pages;
 	unsigned int bytes, offset, i;
 	unsigned int intervals;
+	gfp_t gfp = GFP_NOIO;
 
 	bi = bdev_get_integrity(bio->bi_bdev);
 	q = bdev_get_queue(bio->bi_bdev);
 	BUG_ON(bi == NULL);
 	BUG_ON(bio_integrity(bio));
 
+	if (bio_data_dir(bio) == WRITE)
+		/*
+		 * Zero the memory allocated to not leak uninitialized kernel
+		 * memory to disk.  For PI this only affects the app tag, but
+		 * for non-integrity metadata it affects the entire metadata
+		 * buffer.
+		 */
+		gfp |= __GFP_ZERO;
+
 	intervals = bio_integrity_intervals(bi, bio_sectors(bio));
 
 	/* Allocate kernel buffer for protection data */
 	len = intervals * bi->tuple_size;
-	buf = kmalloc(len, GFP_NOIO | q->bounce_gfp);
+	buf = kmalloc(len, gfp | q->bounce_gfp);
 	if (unlikely(buf == NULL)) {
 		printk(KERN_ERR "could not allocate integrity buffer\n");
 		return -ENOMEM;
--- linux-4.4.0.orig/block/bio.c
+++ linux-4.4.0/block/bio.c
@@ -373,10 +373,14 @@
 	bio_list_init(&punt);
 	bio_list_init(&nopunt);
 
-	while ((bio = bio_list_pop(current->bio_list)))
+	while ((bio = bio_list_pop(&current->bio_list[0])))
 		bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
+	current->bio_list[0] = nopunt;
 
-	*current->bio_list = nopunt;
+	bio_list_init(&nopunt);
+	while ((bio = bio_list_pop(&current->bio_list[1])))
+		bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
+	current->bio_list[1] = nopunt;
 
 	spin_lock(&bs->rescue_lock);
 	bio_list_merge(&bs->rescue_list, &punt);
@@ -464,7 +468,9 @@
 		 * we retry with the original gfp_flags.
 		 */
 
-		if (current->bio_list && !bio_list_empty(current->bio_list))
+		if (current->bio_list &&
+		    (!bio_list_empty(&current->bio_list[0]) ||
+		     !bio_list_empty(&current->bio_list[1])))
 			gfp_mask &= ~__GFP_DIRECT_RECLAIM;
 
 		p = mempool_alloc(bs->bio_pool, gfp_mask);
@@ -584,6 +590,8 @@
 	bio->bi_rw = bio_src->bi_rw;
 	bio->bi_iter = bio_src->bi_iter;
 	bio->bi_io_vec = bio_src->bi_io_vec;
+
+	bio_clone_blkcg_association(bio, bio_src);
 }
 EXPORT_SYMBOL(__bio_clone_fast);
 
@@ -689,6 +697,8 @@
 		}
 	}
 
+	bio_clone_blkcg_association(bio, bio_src);
+
 	return bio;
 }
 EXPORT_SYMBOL(bio_clone_bioset);
@@ -1090,9 +1100,12 @@
 	if (!bio_flagged(bio, BIO_NULL_MAPPED)) {
 		/*
 		 * if we're in a workqueue, the request is orphaned, so
-		 * don't copy into a random user address space, just free.
+		 * don't copy into a random user address space, just free
+		 * and return -EINTR so user space doesn't expect any data.
 		 */
-		if (current->mm && bio_data_dir(bio) == READ)
+		if (!current->mm)
+			ret = -EINTR;
+		else if (bio_data_dir(bio) == READ)
 			ret = bio_copy_to_iter(bio, bmd->iter);
 		if (bmd->is_our_pages)
 			bio_free_pages(bio);
@@ -1203,8 +1216,11 @@
 			}
 		}
 
-		if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes)
+		if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) {
+			if (!map_data)
+				__free_page(page);
 			break;
+		}
 
 		len -= bytes;
 		offset = 0;
@@ -1255,6 +1271,7 @@
 	int ret, offset;
 	struct iov_iter i;
 	struct iovec iov;
+	struct bio_vec *bvec;
 
 	iov_for_each(iov, i, *iter) {
 		unsigned long uaddr = (unsigned long) iov.iov_base;
@@ -1299,7 +1316,12 @@
 		ret = get_user_pages_fast(uaddr, local_nr_pages,
 				(iter->type & WRITE) != WRITE,
 				&pages[cur_page]);
-		if (ret < local_nr_pages) {
+		if (unlikely(ret < local_nr_pages)) {
+			for (j = cur_page; j < page_limit; j++) {
+				if (!pages[j])
+					break;
+				put_page(pages[j]);
+			}
 			ret = -EFAULT;
 			goto out_unmap;
 		}
@@ -1307,6 +1329,7 @@
 		offset = uaddr & ~PAGE_MASK;
 		for (j = cur_page; j < page_limit; j++) {
 			unsigned int bytes = PAGE_SIZE - offset;
+			unsigned short prev_bi_vcnt = bio->bi_vcnt;
 
 			if (len <= 0)
 				break;
@@ -1321,6 +1344,13 @@
 					    bytes)
 				break;
 
+			/*
+			 * check if vector was merged with previous
+			 * drop page reference if needed
+			 */
+			if (bio->bi_vcnt == prev_bi_vcnt)
+				put_page(pages[j]);
+
 			len -= bytes;
 			offset = 0;
 		}
@@ -1353,10 +1383,8 @@
 	return bio;
 
  out_unmap:
-	for (j = 0; j < nr_pages; j++) {
-		if (!pages[j])
-			break;
-		page_cache_release(pages[j]);
+	bio_for_each_segment_all(bvec, bio, j) {
+		page_cache_release(bvec->bv_page);
 	}
  out:
 	kfree(pages);
@@ -1513,7 +1541,7 @@
 		if (bytes > len)
 			bytes = len;
 
-		page = alloc_page(q->bounce_gfp | gfp_mask);
+		page = alloc_page(q->bounce_gfp | __GFP_ZERO | gfp_mask);
 		if (!page)
 			goto cleanup;
 
@@ -2011,6 +2039,17 @@
 	}
 }
 
+/**
+ * bio_clone_blkcg_association - clone blkcg association from src to dst bio
+ * @dst: destination bio
+ * @src: source bio
+ */
+void bio_clone_blkcg_association(struct bio *dst, struct bio *src)
+{
+	if (src->bi_css)
+		WARN_ON(bio_associate_blkcg(dst, src->bi_css));
+}
+
 #endif /* CONFIG_BLK_CGROUP */
 
 static void __init biovec_init_slabs(void)
--- linux-4.4.0.orig/block/blk-cgroup.c
+++ linux-4.4.0/block/blk-cgroup.c
@@ -184,8 +184,9 @@
 		goto err_free_blkg;
 	}
 
-	wb_congested = wb_congested_get_create(&q->backing_dev_info,
-					       blkcg->css.id, GFP_NOWAIT);
+	wb_congested = wb_congested_get_create(q->backing_dev_info,
+					       blkcg->css.id,
+					       GFP_NOWAIT | __GFP_NOWARN);
 	if (!wb_congested) {
 		ret = -ENOMEM;
 		goto err_put_css;
@@ -193,7 +194,7 @@
 
 	/* allocate */
 	if (!new_blkg) {
-		new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT);
+		new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT | __GFP_NOWARN);
 		if (unlikely(!new_blkg)) {
 			ret = -ENOMEM;
 			goto err_put_congested;
@@ -468,8 +469,8 @@
 const char *blkg_dev_name(struct blkcg_gq *blkg)
 {
 	/* some drivers (floppy) instantiate a queue w/o disk registered */
-	if (blkg->q->backing_dev_info.dev)
-		return dev_name(blkg->q->backing_dev_info.dev);
+	if (blkg->q->backing_dev_info->dev)
+		return dev_name(blkg->q->backing_dev_info->dev);
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(blkg_dev_name);
@@ -788,6 +789,7 @@
 {
 	struct gendisk *disk;
 	struct blkcg_gq *blkg;
+	struct module *owner;
 	unsigned int major, minor;
 	int key_len, part, ret;
 	char *body;
@@ -804,7 +806,9 @@
 	if (!disk)
 		return -ENODEV;
 	if (part) {
+		owner = disk->fops->owner;
 		put_disk(disk);
+		module_put(owner);
 		return -ENODEV;
 	}
 
@@ -820,7 +824,9 @@
 		ret = PTR_ERR(blkg);
 		rcu_read_unlock();
 		spin_unlock_irq(disk->queue->queue_lock);
+		owner = disk->fops->owner;
 		put_disk(disk);
+		module_put(owner);
 		/*
 		 * If queue was bypassing, we should retry.  Do so after a
 		 * short msleep().  It isn't strictly necessary but queue
@@ -851,9 +857,13 @@
 void blkg_conf_finish(struct blkg_conf_ctx *ctx)
 	__releases(ctx->disk->queue->queue_lock) __releases(rcu)
 {
+	struct module *owner;
+
 	spin_unlock_irq(ctx->disk->queue->queue_lock);
 	rcu_read_unlock();
+	owner = ctx->disk->fops->owner;
 	put_disk(ctx->disk);
+	module_put(owner);
 }
 EXPORT_SYMBOL_GPL(blkg_conf_finish);
 
@@ -1013,7 +1023,7 @@
 	}
 
 	spin_lock_init(&blkcg->lock);
-	INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT);
+	INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT | __GFP_NOWARN);
 	INIT_HLIST_HEAD(&blkcg->blkg_list);
 #ifdef CONFIG_CGROUP_WRITEBACK
 	INIT_LIST_HEAD(&blkcg->cgwb_list);
@@ -1069,10 +1079,8 @@
 	if (preloaded)
 		radix_tree_preload_end();
 
-	if (IS_ERR(blkg)) {
-		blkg_free(new_blkg);
+	if (IS_ERR(blkg))
 		return PTR_ERR(blkg);
-	}
 
 	q->root_blkg = blkg;
 	q->root_rl.blkg = blkg;
@@ -1231,7 +1239,7 @@
 		if (blkg->pd[pol->plid])
 			continue;
 
-		pd = pol->pd_alloc_fn(GFP_NOWAIT, q->node);
+		pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q->node);
 		if (!pd)
 			swap(pd, pd_prealloc);
 		if (!pd) {
@@ -1331,10 +1339,8 @@
 			struct blkcg_policy_data *cpd;
 
 			cpd = pol->cpd_alloc_fn(GFP_KERNEL);
-			if (!cpd) {
-				mutex_unlock(&blkcg_pol_mutex);
+			if (!cpd)
 				goto err_free_cpds;
-			}
 
 			blkcg->cpd[pol->plid] = cpd;
 			cpd->blkcg = blkcg;
--- linux-4.4.0.orig/block/blk-core.c
+++ linux-4.4.0/block/blk-core.c
@@ -73,7 +73,7 @@
 	 * flip its congestion state for events on other blkcgs.
 	 */
 	if (rl == &rl->q->root_rl)
-		clear_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+		clear_wb_congested(rl->q->backing_dev_info->wb.congested, sync);
 #endif
 }
 
@@ -84,7 +84,7 @@
 #else
 	/* see blk_clear_congested() */
 	if (rl == &rl->q->root_rl)
-		set_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+		set_wb_congested(rl->q->backing_dev_info->wb.congested, sync);
 #endif
 }
 
@@ -103,22 +103,6 @@
 	q->nr_congestion_off = nr;
 }
 
-/**
- * blk_get_backing_dev_info - get the address of a queue's backing_dev_info
- * @bdev:	device
- *
- * Locates the passed device's request queue and returns the address of its
- * backing_dev_info.  This function can only be called if @bdev is opened
- * and the return value is never NULL.
- */
-struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
-{
-	struct request_queue *q = bdev_get_queue(bdev);
-
-	return &q->backing_dev_info;
-}
-EXPORT_SYMBOL(blk_get_backing_dev_info);
-
 void blk_rq_init(struct request_queue *q, struct request *rq)
 {
 	memset(rq, 0, sizeof(*rq));
@@ -233,7 +217,7 @@
  **/
 void blk_start_queue(struct request_queue *q)
 {
-	WARN_ON(!irqs_disabled());
+	WARN_ON(!in_interrupt() && !irqs_disabled());
 
 	queue_flag_clear(QUEUE_FLAG_STOPPED, q);
 	__blk_run_queue(q);
@@ -282,6 +266,7 @@
 void blk_sync_queue(struct request_queue *q)
 {
 	del_timer_sync(&q->timeout);
+	cancel_work_sync(&q->timeout_work);
 
 	if (q->mq_ops) {
 		struct blk_mq_hw_ctx *hctx;
@@ -515,7 +500,9 @@
 
 void blk_set_queue_dying(struct request_queue *q)
 {
-	queue_flag_set_unlocked(QUEUE_FLAG_DYING, q);
+	spin_lock_irq(q->queue_lock);
+	queue_flag_set(QUEUE_FLAG_DYING, q);
+	spin_unlock_irq(q->queue_lock);
 
 	if (q->mq_ops)
 		blk_mq_wake_waiters(q);
@@ -524,8 +511,8 @@
 
 		blk_queue_for_each_rl(rl, q) {
 			if (rl->rq_pool) {
-				wake_up(&rl->wait[BLK_RW_SYNC]);
-				wake_up(&rl->wait[BLK_RW_ASYNC]);
+				wake_up_all(&rl->wait[BLK_RW_SYNC]);
+				wake_up_all(&rl->wait[BLK_RW_ASYNC]);
 			}
 		}
 	}
@@ -581,7 +568,7 @@
 	blk_flush_integrity();
 
 	/* @q won't process any more request, flush async actions */
-	del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
+	del_timer_sync(&q->backing_dev_info->laptop_mode_wb_timer);
 	blk_sync_queue(q);
 
 	if (q->mq_ops)
@@ -593,8 +580,6 @@
 		q->queue_lock = &q->__queue_lock;
 	spin_unlock_irq(lock);
 
-	bdi_unregister(&q->backing_dev_info);
-
 	/* @q is and will stay empty, shutdown and put */
 	blk_put_queue(q);
 }
@@ -646,24 +631,20 @@
 }
 EXPORT_SYMBOL(blk_alloc_queue);
 
-int blk_queue_enter(struct request_queue *q, gfp_t gfp)
+int blk_queue_enter(struct request_queue *q, bool nowait)
 {
 	while (true) {
-		int ret;
-
 		if (percpu_ref_tryget_live(&q->q_usage_counter))
 			return 0;
 
-		if (!gfpflags_allow_blocking(gfp))
+		if (nowait)
 			return -EBUSY;
 
-		ret = wait_event_interruptible(q->mq_freeze_wq,
-				!atomic_read(&q->mq_freeze_depth) ||
-				blk_queue_dying(q));
+		wait_event(q->mq_freeze_wq,
+			   !atomic_read(&q->mq_freeze_depth) ||
+			   blk_queue_dying(q));
 		if (blk_queue_dying(q))
 			return -ENODEV;
-		if (ret)
-			return ret;
 	}
 }
 
@@ -680,10 +661,16 @@
 	wake_up_all(&q->mq_freeze_wq);
 }
 
+static void blk_rq_timed_out_timer(unsigned long data)
+{
+	struct request_queue *q = (struct request_queue *)data;
+
+	kblockd_schedule_work(&q->timeout_work);
+}
+
 struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 {
 	struct request_queue *q;
-	int err;
 
 	q = kmem_cache_alloc_node(blk_requestq_cachep,
 				gfp_mask | __GFP_ZERO, node_id);
@@ -698,19 +685,20 @@
 	if (!q->bio_split)
 		goto fail_id;
 
-	q->backing_dev_info.ra_pages =
+	q->backing_dev_info = bdi_alloc_node(gfp_mask, node_id);
+	if (!q->backing_dev_info)
+		goto fail_split;
+
+	q->backing_dev_info->ra_pages =
 			(VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-	q->backing_dev_info.capabilities = BDI_CAP_CGROUP_WRITEBACK;
-	q->backing_dev_info.name = "block";
+	q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
+	q->backing_dev_info->name = "block";
 	q->node = node_id;
 
-	err = bdi_init(&q->backing_dev_info);
-	if (err)
-		goto fail_split;
-
-	setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
+	setup_timer(&q->backing_dev_info->laptop_mode_wb_timer,
 		    laptop_mode_timer_fn, (unsigned long) q);
 	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
+	INIT_WORK(&q->timeout_work, NULL);
 	INIT_LIST_HEAD(&q->queue_head);
 	INIT_LIST_HEAD(&q->timeout_list);
 	INIT_LIST_HEAD(&q->icq_list);
@@ -721,6 +709,9 @@
 
 	kobject_init(&q->kobj, &blk_queue_ktype);
 
+#ifdef CONFIG_BLK_DEV_IO_TRACE
+	mutex_init(&q->blk_trace_mutex);
+#endif
 	mutex_init(&q->sysfs_lock);
 	spin_lock_init(&q->__queue_lock);
 
@@ -758,7 +749,7 @@
 fail_ref:
 	percpu_ref_exit(&q->q_usage_counter);
 fail_bdi:
-	bdi_destroy(&q->backing_dev_info);
+	bdi_put(q->backing_dev_info);
 fail_split:
 	bioset_free(q->bio_split);
 fail_id:
@@ -841,6 +832,7 @@
 	if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
 		goto fail;
 
+	INIT_WORK(&q->timeout_work, blk_timeout_work);
 	q->request_fn		= rfn;
 	q->prep_rq_fn		= NULL;
 	q->unprep_rq_fn		= NULL;
@@ -872,6 +864,7 @@
 
 fail:
 	blk_free_flush_queue(q->fq);
+	q->fq = NULL;
 	return NULL;
 }
 EXPORT_SYMBOL(blk_init_allocated_queue);
@@ -1181,7 +1174,7 @@
 	 * disturb iosched and blkcg but weird is bettern than dead.
 	 */
 	printk_ratelimited(KERN_WARNING "%s: dev %s: request aux data allocation failed, iosched may be disturbed\n",
-			   __func__, dev_name(q->backing_dev_info.dev));
+			   __func__, dev_name(q->backing_dev_info->dev));
 
 	rq->cmd_flags &= ~REQ_ELVPRIV;
 	rq->elv.icq = NULL;
@@ -1292,7 +1285,9 @@
 struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
 {
 	if (q->mq_ops)
-		return blk_mq_alloc_request(q, rw, gfp_mask, false);
+		return blk_mq_alloc_request(q, rw,
+			(gfp_mask & __GFP_DIRECT_RECLAIM) ?
+				0 : BLK_MQ_REQ_NOWAIT);
 	else
 		return blk_old_get_request(q, rw, gfp_mask);
 }
@@ -2019,7 +2014,14 @@
  */
 blk_qc_t generic_make_request(struct bio *bio)
 {
-	struct bio_list bio_list_on_stack;
+	/*
+	 * bio_list_on_stack[0] contains bios submitted by the current
+	 * make_request_fn.
+	 * bio_list_on_stack[1] contains bios that were submitted before
+	 * the current make_request_fn, but that haven't been processed
+	 * yet.
+	 */
+	struct bio_list bio_list_on_stack[2];
 	blk_qc_t ret = BLK_QC_T_NONE;
 
 	if (!generic_make_request_checks(bio))
@@ -2036,7 +2038,7 @@
 	 * should be added at the tail
 	 */
 	if (current->bio_list) {
-		bio_list_add(current->bio_list, bio);
+		bio_list_add(&current->bio_list[0], bio);
 		goto out;
 	}
 
@@ -2055,24 +2057,40 @@
 	 * bio_list, and call into ->make_request() again.
 	 */
 	BUG_ON(bio->bi_next);
-	bio_list_init(&bio_list_on_stack);
-	current->bio_list = &bio_list_on_stack;
+	bio_list_init(&bio_list_on_stack[0]);
+	current->bio_list = bio_list_on_stack;
 	do {
 		struct request_queue *q = bdev_get_queue(bio->bi_bdev);
 
-		if (likely(blk_queue_enter(q, __GFP_DIRECT_RECLAIM) == 0)) {
+		if (likely(blk_queue_enter(q, false) == 0)) {
+			struct bio_list lower, same;
+
+			/* Create a fresh bio_list for all subordinate requests */
+			bio_list_on_stack[1] = bio_list_on_stack[0];
+			bio_list_init(&bio_list_on_stack[0]);
 
 			ret = q->make_request_fn(q, bio);
 
 			blk_queue_exit(q);
 
-			bio = bio_list_pop(current->bio_list);
+			/* sort new bios into those for a lower level
+			 * and those for the same level
+			 */
+			bio_list_init(&lower);
+			bio_list_init(&same);
+			while ((bio = bio_list_pop(&bio_list_on_stack[0])) != NULL)
+				if (q == bdev_get_queue(bio->bi_bdev))
+					bio_list_add(&same, bio);
+				else
+					bio_list_add(&lower, bio);
+			/* now assemble so we handle the lowest level first */
+			bio_list_merge(&bio_list_on_stack[0], &lower);
+			bio_list_merge(&bio_list_on_stack[0], &same);
+			bio_list_merge(&bio_list_on_stack[0], &bio_list_on_stack[1]);
 		} else {
-			struct bio *bio_next = bio_list_pop(current->bio_list);
-
 			bio_io_error(bio);
-			bio = bio_next;
 		}
+		bio = bio_list_pop(&bio_list_on_stack[0]);
 	} while (bio);
 	current->bio_list = NULL; /* deactivate */
 
@@ -2189,7 +2207,7 @@
 	if (q->mq_ops) {
 		if (blk_queue_io_stat(q))
 			blk_account_io_start(rq, true);
-		blk_mq_insert_request(rq, false, true, true);
+		blk_mq_insert_request(rq, false, true, false);
 		return 0;
 	}
 
@@ -2727,7 +2745,7 @@
 	BUG_ON(blk_queued_rq(req));
 
 	if (unlikely(laptop_mode) && req->cmd_type == REQ_TYPE_FS)
-		laptop_io_completion(&req->q->backing_dev_info);
+		laptop_io_completion(req->q->backing_dev_info);
 
 	blk_delete_timer(req);
 
--- linux-4.4.0.orig/block/blk-integrity.c
+++ linux-4.4.0/block/blk-integrity.c
@@ -412,12 +412,13 @@
 
 	bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE |
 		template->flags;
-	bi->interval_exp = ilog2(queue_logical_block_size(disk->queue));
+	bi->interval_exp = template->interval_exp ? :
+		ilog2(queue_logical_block_size(disk->queue));
 	bi->profile = template->profile ? template->profile : &nop_profile;
 	bi->tuple_size = template->tuple_size;
 	bi->tag_size = template->tag_size;
 
-	blk_integrity_revalidate(disk);
+	disk->queue->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
 }
 EXPORT_SYMBOL(blk_integrity_register);
 
@@ -430,26 +431,11 @@
  */
 void blk_integrity_unregister(struct gendisk *disk)
 {
-	blk_integrity_revalidate(disk);
+	disk->queue->backing_dev_info->capabilities &= ~BDI_CAP_STABLE_WRITES;
 	memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity));
 }
 EXPORT_SYMBOL(blk_integrity_unregister);
 
-void blk_integrity_revalidate(struct gendisk *disk)
-{
-	struct blk_integrity *bi = &disk->queue->integrity;
-
-	if (!(disk->flags & GENHD_FL_UP))
-		return;
-
-	if (bi->profile)
-		disk->queue->backing_dev_info.capabilities |=
-			BDI_CAP_STABLE_WRITES;
-	else
-		disk->queue->backing_dev_info.capabilities &=
-			~BDI_CAP_STABLE_WRITES;
-}
-
 void blk_integrity_add(struct gendisk *disk)
 {
 	if (kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype,
--- linux-4.4.0.orig/block/blk-map.c
+++ linux-4.4.0/block/blk-map.c
@@ -90,6 +90,9 @@
 	if (!iter || !iter->count)
 		return -EINVAL;
 
+	if (!iter_is_iovec(iter))
+		return -EINVAL;
+
 	iov_for_each(iov, i, *iter) {
 		unsigned long uaddr = (unsigned long) iov.iov_base;
 
--- linux-4.4.0.orig/block/blk-merge.c
+++ linux-4.4.0/block/blk-merge.c
@@ -68,6 +68,18 @@
 	return bio_split(bio, q->limits.max_write_same_sectors, GFP_NOIO, bs);
 }
 
+static inline unsigned get_max_io_size(struct request_queue *q,
+				       struct bio *bio)
+{
+	unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector);
+	unsigned mask = queue_logical_block_size(q) - 1;
+
+	/* aligned to logical block size */
+	sectors &= ~(mask >> 9);
+
+	return sectors;
+}
+
 static struct bio *blk_bio_segment_split(struct request_queue *q,
 					 struct bio *bio,
 					 struct bio_set *bs,
@@ -79,9 +91,29 @@
 	unsigned front_seg_size = bio->bi_seg_front_size;
 	bool do_split = true;
 	struct bio *new = NULL;
+	const unsigned max_sectors = get_max_io_size(q, bio);
+	unsigned bvecs = 0;
 
 	bio_for_each_segment(bv, bio, iter) {
-		if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q))
+		/*
+		 * With arbitrary bio size, the incoming bio may be very
+		 * big. We have to split the bio into small bios so that
+		 * each holds at most BIO_MAX_PAGES bvecs because
+		 * bio_clone() can fail to allocate big bvecs.
+		 *
+		 * It should have been better to apply the limit per
+		 * request queue in which bio_clone() is involved,
+		 * instead of globally. The biggest blocker is the
+		 * bio_clone() in bio bounce.
+		 *
+		 * If bio is splitted by this reason, we should have
+		 * allowed to continue bios merging, but don't do
+		 * that now for making the change simple.
+		 *
+		 * TODO: deal with bio bounce's bio_clone() gracefully
+		 * and convert the global limit into per-queue limit.
+		 */
+		if (bvecs++ >= BIO_MAX_PAGES)
 			goto split;
 
 		/*
@@ -91,6 +123,21 @@
 		if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset))
 			goto split;
 
+		if (sectors + (bv.bv_len >> 9) > max_sectors) {
+			/*
+			 * Consider this a new segment if we're splitting in
+			 * the middle of this vector.
+			 */
+			if (nsegs < queue_max_segments(q) &&
+			    sectors < max_sectors) {
+				nsegs++;
+				sectors = max_sectors;
+			}
+			if (sectors)
+				goto split;
+			/* Make this single bvec as the 1st segment */
+		}
+
 		if (bvprvp && blk_queue_cluster(q)) {
 			if (seg_size + bv.bv_len > queue_max_segment_size(q))
 				goto new_segment;
@@ -249,13 +296,7 @@
 
 void blk_recount_segments(struct request_queue *q, struct bio *bio)
 {
-	unsigned short seg_cnt;
-
-	/* estimate segment number by bi_vcnt for non-cloned bio */
-	if (bio_flagged(bio, BIO_CLONED))
-		seg_cnt = bio_segments(bio);
-	else
-		seg_cnt = bio->bi_vcnt;
+	unsigned short seg_cnt = bio_segments(bio);
 
 	if (test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags) &&
 			(seg_cnt < queue_max_segments(q)))
--- linux-4.4.0.orig/block/blk-mq-sysfs.c
+++ linux-4.4.0/block/blk-mq-sysfs.c
@@ -231,20 +231,25 @@
 
 static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page)
 {
+	const size_t size = PAGE_SIZE - 1;
 	unsigned int i, first = 1;
-	ssize_t ret = 0;
+	int ret = 0, pos = 0;
 
 	for_each_cpu(i, hctx->cpumask) {
 		if (first)
-			ret += sprintf(ret + page, "%u", i);
+			ret = snprintf(pos + page, size - pos, "%u", i);
 		else
-			ret += sprintf(ret + page, ", %u", i);
+			ret = snprintf(pos + page, size - pos, ", %u", i);
+
+		if (ret >= size - pos)
+			break;
 
 		first = 0;
+		pos += ret;
 	}
 
-	ret += sprintf(ret + page, "\n");
-	return ret;
+	ret = snprintf(pos + page, size + 1 - pos, "\n");
+	return pos + ret;
 }
 
 static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_dispatched = {
@@ -413,14 +418,17 @@
 	struct blk_mq_hw_ctx *hctx;
 	struct blk_mq_ctx *ctx;
 	int i;
+	int cpu;
 
 	kobject_init(&q->mq_kobj, &blk_mq_ktype);
 
 	queue_for_each_hw_ctx(q, hctx, i)
 		kobject_init(&hctx->kobj, &blk_mq_hw_ktype);
 
-	queue_for_each_ctx(q, ctx, i)
+	for_each_possible_cpu(cpu) {
+		ctx = per_cpu_ptr(q->queue_ctx, cpu);
 		kobject_init(&ctx->kobj, &blk_mq_ctx_ktype);
+	}
 }
 
 int blk_mq_register_disk(struct gendisk *disk)
--- linux-4.4.0.orig/block/blk-mq-tag.c
+++ linux-4.4.0/block/blk-mq-tag.c
@@ -268,7 +268,7 @@
 	if (tag != -1)
 		return tag;
 
-	if (!gfpflags_allow_blocking(data->gfp))
+	if (data->flags & BLK_MQ_REQ_NOWAIT)
 		return -1;
 
 	bs = bt_wait_ptr(bt, hctx);
@@ -303,7 +303,7 @@
 		data->ctx = blk_mq_get_ctx(data->q);
 		data->hctx = data->q->mq_ops->map_queue(data->q,
 				data->ctx->cpu);
-		if (data->reserved) {
+		if (data->flags & BLK_MQ_REQ_RESERVED) {
 			bt = &data->hctx->tags->breserved_tags;
 		} else {
 			last_tag = &data->ctx->last_tag;
@@ -349,10 +349,9 @@
 
 unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data)
 {
-	if (!data->reserved)
-		return __blk_mq_get_tag(data);
-
-	return __blk_mq_get_reserved_tag(data);
+	if (data->flags & BLK_MQ_REQ_RESERVED)
+		return __blk_mq_get_reserved_tag(data);
+	return __blk_mq_get_tag(data);
 }
 
 static struct bt_wait_state *bt_wake_ptr(struct blk_mq_bitmap_tags *bt)
@@ -481,6 +480,11 @@
 	struct blk_mq_hw_ctx *hctx;
 	int i;
 
+	/*
+	 * Avoid potential races with things like queue removal.
+	 */
+	if (!percpu_ref_tryget(&q->q_usage_counter))
+		return;
 
 	queue_for_each_hw_ctx(q, hctx, i) {
 		struct blk_mq_tags *tags = hctx->tags;
@@ -497,7 +501,7 @@
 		bt_for_each(hctx, &tags->bitmap_tags, tags->nr_reserved_tags, fn, priv,
 		      false);
 	}
-
+	blk_queue_exit(q);
 }
 
 static unsigned int bt_unused_tags(struct blk_mq_bitmap_tags *bt)
--- linux-4.4.0.orig/block/blk-mq.c
+++ linux-4.4.0/block/blk-mq.c
@@ -229,8 +229,8 @@
 	return NULL;
 }
 
-struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp,
-		bool reserved)
+struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
+		unsigned int flags)
 {
 	struct blk_mq_ctx *ctx;
 	struct blk_mq_hw_ctx *hctx;
@@ -238,24 +238,22 @@
 	struct blk_mq_alloc_data alloc_data;
 	int ret;
 
-	ret = blk_queue_enter(q, gfp);
+	ret = blk_queue_enter(q, flags & BLK_MQ_REQ_NOWAIT);
 	if (ret)
 		return ERR_PTR(ret);
 
 	ctx = blk_mq_get_ctx(q);
 	hctx = q->mq_ops->map_queue(q, ctx->cpu);
-	blk_mq_set_alloc_data(&alloc_data, q, gfp & ~__GFP_DIRECT_RECLAIM,
-			reserved, ctx, hctx);
+	blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx);
 
 	rq = __blk_mq_alloc_request(&alloc_data, rw);
-	if (!rq && (gfp & __GFP_DIRECT_RECLAIM)) {
+	if (!rq && !(flags & BLK_MQ_REQ_NOWAIT)) {
 		__blk_mq_run_hw_queue(hctx);
 		blk_mq_put_ctx(ctx);
 
 		ctx = blk_mq_get_ctx(q);
 		hctx = q->mq_ops->map_queue(q, ctx->cpu);
-		blk_mq_set_alloc_data(&alloc_data, q, gfp, reserved, ctx,
-				hctx);
+		blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx);
 		rq =  __blk_mq_alloc_request(&alloc_data, rw);
 		ctx = alloc_data.ctx;
 	}
@@ -268,6 +266,45 @@
 }
 EXPORT_SYMBOL(blk_mq_alloc_request);
 
+struct request *blk_mq_alloc_request_hctx(struct request_queue *q, int rw,
+		unsigned int flags, unsigned int hctx_idx)
+{
+	struct blk_mq_hw_ctx *hctx;
+	struct blk_mq_ctx *ctx;
+	struct request *rq;
+	struct blk_mq_alloc_data alloc_data;
+	int ret;
+
+	/*
+	 * If the tag allocator sleeps we could get an allocation for a
+	 * different hardware context.  No need to complicate the low level
+	 * allocator for this for the rare use case of a command tied to
+	 * a specific queue.
+	 */
+	if (WARN_ON_ONCE(!(flags & BLK_MQ_REQ_NOWAIT)))
+		return ERR_PTR(-EINVAL);
+
+	if (hctx_idx >= q->nr_hw_queues)
+		return ERR_PTR(-EIO);
+
+	ret = blk_queue_enter(q, true);
+	if (ret)
+		return ERR_PTR(ret);
+
+	hctx = q->queue_hw_ctx[hctx_idx];
+	ctx = __blk_mq_get_ctx(q, cpumask_first(hctx->cpumask));
+
+	blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx);
+	rq = __blk_mq_alloc_request(&alloc_data, rw);
+	if (!rq) {
+		blk_queue_exit(q);
+		return ERR_PTR(-EWOULDBLOCK);
+	}
+
+	return rq;
+}
+EXPORT_SYMBOL_GPL(blk_mq_alloc_request_hctx);
+
 static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx,
 				  struct blk_mq_ctx *ctx, struct request *rq)
 {
@@ -601,8 +638,10 @@
 		 * If a request wasn't started before the queue was
 		 * marked dying, kill it here or it'll go unnoticed.
 		 */
-		if (unlikely(blk_queue_dying(rq->q)))
-			blk_mq_complete_request(rq, -EIO);
+		if (unlikely(blk_queue_dying(rq->q))) {
+			rq->errors = -EIO;
+			blk_mq_end_request(rq, rq->errors);
+		}
 		return;
 	}
 	if (rq->cmd_flags & REQ_NO_TIMEOUT)
@@ -617,15 +656,32 @@
 	}
 }
 
-static void blk_mq_rq_timer(unsigned long priv)
+static void blk_mq_timeout_work(struct work_struct *work)
 {
-	struct request_queue *q = (struct request_queue *)priv;
+	struct request_queue *q =
+		container_of(work, struct request_queue, timeout_work);
 	struct blk_mq_timeout_data data = {
 		.next		= 0,
 		.next_set	= 0,
 	};
 	int i;
 
+	/* A deadlock might occur if a request is stuck requiring a
+	 * timeout at the same time a queue freeze is waiting
+	 * completion, since the timeout code would not be able to
+	 * acquire the queue reference here.
+	 *
+	 * That's why we don't use blk_queue_enter here; instead, we use
+	 * percpu_ref_tryget directly, because we need to be able to
+	 * obtain a reference even in the short window between the queue
+	 * starting to freeze, by dropping the first reference in
+	 * blk_mq_freeze_queue_start, and the moment the last request is
+	 * consumed, marked by the instant q_usage_counter reaches
+	 * zero.
+	 */
+	if (!percpu_ref_tryget(&q->q_usage_counter))
+		return;
+
 	blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &data);
 
 	if (data.next_set) {
@@ -640,6 +696,7 @@
 				blk_mq_tag_idle(hctx);
 		}
 	}
+	blk_queue_exit(q);
 }
 
 /*
@@ -730,11 +787,12 @@
 	struct list_head *dptr;
 	int queued;
 
-	WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask));
-
 	if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
 		return;
 
+	WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask) &&
+		cpu_online(hctx->next_cpu));
+
 	hctx->run++;
 
 	/*
@@ -778,7 +836,7 @@
 		switch (ret) {
 		case BLK_MQ_RQ_QUEUE_OK:
 			queued++;
-			continue;
+			break;
 		case BLK_MQ_RQ_QUEUE_BUSY:
 			list_add(&rq->queuelist, &rq_list);
 			__blk_mq_requeue_request(rq);
@@ -840,7 +898,7 @@
 		return WORK_CPU_UNBOUND;
 
 	if (--hctx->next_cpu_batch <= 0) {
-		int cpu = hctx->next_cpu, next_cpu;
+		int next_cpu;
 
 		next_cpu = cpumask_next(hctx->next_cpu, hctx->cpumask);
 		if (next_cpu >= nr_cpu_ids)
@@ -848,8 +906,6 @@
 
 		hctx->next_cpu = next_cpu;
 		hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH;
-
-		return cpu;
 	}
 
 	return hctx->next_cpu;
@@ -973,10 +1029,11 @@
 EXPORT_SYMBOL(blk_mq_delay_queue);
 
 static inline void __blk_mq_insert_req_list(struct blk_mq_hw_ctx *hctx,
-					    struct blk_mq_ctx *ctx,
 					    struct request *rq,
 					    bool at_head)
 {
+	struct blk_mq_ctx *ctx = rq->mq_ctx;
+
 	trace_block_rq_insert(hctx->queue, rq);
 
 	if (at_head)
@@ -990,20 +1047,16 @@
 {
 	struct blk_mq_ctx *ctx = rq->mq_ctx;
 
-	__blk_mq_insert_req_list(hctx, ctx, rq, at_head);
+	__blk_mq_insert_req_list(hctx, rq, at_head);
 	blk_mq_hctx_mark_pending(hctx, ctx);
 }
 
 void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
-		bool async)
+			   bool async)
 {
+	struct blk_mq_ctx *ctx = rq->mq_ctx;
 	struct request_queue *q = rq->q;
 	struct blk_mq_hw_ctx *hctx;
-	struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx;
-
-	current_ctx = blk_mq_get_ctx(q);
-	if (!cpu_online(ctx->cpu))
-		rq->mq_ctx = ctx = current_ctx;
 
 	hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
@@ -1013,8 +1066,6 @@
 
 	if (run_queue)
 		blk_mq_run_hw_queue(hctx, async);
-
-	blk_mq_put_ctx(current_ctx);
 }
 
 static void blk_mq_insert_requests(struct request_queue *q,
@@ -1025,14 +1076,9 @@
 
 {
 	struct blk_mq_hw_ctx *hctx;
-	struct blk_mq_ctx *current_ctx;
 
 	trace_block_unplug(q, depth, !from_schedule);
 
-	current_ctx = blk_mq_get_ctx(q);
-
-	if (!cpu_online(ctx->cpu))
-		ctx = current_ctx;
 	hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
 	/*
@@ -1044,15 +1090,14 @@
 		struct request *rq;
 
 		rq = list_first_entry(list, struct request, queuelist);
+		BUG_ON(rq->mq_ctx != ctx);
 		list_del_init(&rq->queuelist);
-		rq->mq_ctx = ctx;
-		__blk_mq_insert_req_list(hctx, ctx, rq, false);
+		__blk_mq_insert_req_list(hctx, rq, false);
 	}
 	blk_mq_hctx_mark_pending(hctx, ctx);
 	spin_unlock(&ctx->lock);
 
 	blk_mq_run_hw_queue(hctx, from_schedule);
-	blk_mq_put_ctx(current_ctx);
 }
 
 static int plug_ctx_cmp(void *priv, struct list_head *a, struct list_head *b)
@@ -1175,8 +1220,7 @@
 		rw |= REQ_SYNC;
 
 	trace_block_getrq(q, bio, rw);
-	blk_mq_set_alloc_data(&alloc_data, q, GFP_ATOMIC, false, ctx,
-			hctx);
+	blk_mq_set_alloc_data(&alloc_data, q, BLK_MQ_REQ_NOWAIT, ctx, hctx);
 	rq = __blk_mq_alloc_request(&alloc_data, rw);
 	if (unlikely(!rq)) {
 		__blk_mq_run_hw_queue(hctx);
@@ -1185,8 +1229,7 @@
 
 		ctx = blk_mq_get_ctx(q);
 		hctx = q->mq_ops->map_queue(q, ctx->cpu);
-		blk_mq_set_alloc_data(&alloc_data, q,
-				__GFP_RECLAIM|__GFP_HIGH, false, ctx, hctx);
+		blk_mq_set_alloc_data(&alloc_data, q, 0, ctx, hctx);
 		rq = __blk_mq_alloc_request(&alloc_data, rw);
 		ctx = alloc_data.ctx;
 		hctx = alloc_data.hctx;
@@ -1252,19 +1295,16 @@
 
 	blk_queue_bounce(q, &bio);
 
+	blk_queue_split(q, &bio, q->bio_split);
+
 	if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
 		bio_io_error(bio);
 		return BLK_QC_T_NONE;
 	}
 
-	blk_queue_split(q, &bio, q->bio_split);
-
-	if (!is_flush_fua && !blk_queue_nomerges(q)) {
-		if (blk_attempt_plug_merge(q, bio, &request_count,
-					   &same_queue_rq))
-			return BLK_QC_T_NONE;
-	} else
-		request_count = blk_plug_queued_count(q);
+	if (!is_flush_fua && !blk_queue_nomerges(q) &&
+	    blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq))
+		return BLK_QC_T_NONE;
 
 	rq = blk_mq_map_request(q, bio, &data);
 	if (unlikely(!rq))
@@ -1311,9 +1351,9 @@
 		blk_mq_put_ctx(data.ctx);
 		if (!old_rq)
 			goto done;
-		if (!blk_mq_direct_issue_request(old_rq, &cookie))
-			goto done;
-		blk_mq_insert_request(old_rq, false, true, true);
+		if (test_bit(BLK_MQ_S_STOPPED, &data.hctx->state) ||
+		    blk_mq_direct_issue_request(old_rq, &cookie) != 0)
+			blk_mq_insert_request(old_rq, false, true, true);
 		goto done;
 	}
 
@@ -1355,9 +1395,11 @@
 
 	blk_queue_split(q, &bio, q->bio_split);
 
-	if (!is_flush_fua && !blk_queue_nomerges(q) &&
-	    blk_attempt_plug_merge(q, bio, &request_count, NULL))
-		return BLK_QC_T_NONE;
+	if (!is_flush_fua && !blk_queue_nomerges(q)) {
+		if (blk_attempt_plug_merge(q, bio, &request_count, NULL))
+			return BLK_QC_T_NONE;
+	} else
+		request_count = blk_plug_queued_count(q);
 
 	rq = blk_mq_map_request(q, bio, &data);
 	if (unlikely(!rq))
@@ -1471,7 +1513,7 @@
 	INIT_LIST_HEAD(&tags->page_list);
 
 	tags->rqs = kzalloc_node(set->queue_depth * sizeof(struct request *),
-				 GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY,
+				 GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY,
 				 set->numa_node);
 	if (!tags->rqs) {
 		blk_mq_free_tags(tags);
@@ -1492,12 +1534,12 @@
 		int to_do;
 		void *p;
 
-		while (left < order_to_size(this_order - 1) && this_order)
+		while (this_order && left < order_to_size(this_order - 1))
 			this_order--;
 
 		do {
 			page = alloc_pages_node(set->numa_node,
-				GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO,
+				GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO,
 				this_order);
 			if (page)
 				break;
@@ -1518,7 +1560,7 @@
 		 * Allow kmemleak to scan these pages as they contain pointers
 		 * to additional allocations like via ops->init_request().
 		 */
-		kmemleak_alloc(p, order_to_size(this_order), 1, GFP_KERNEL);
+		kmemleak_alloc(p, order_to_size(this_order), 1, GFP_NOIO);
 		entries_per_page = order_to_size(this_order) / rq_size;
 		to_do = min(entries_per_page, set->queue_depth - i);
 		left -= to_do * rq_size;
@@ -1570,16 +1612,17 @@
 	return 0;
 }
 
+/*
+ * 'cpu' is going away. splice any existing rq_list entries from this
+ * software queue to the hw queue dispatch list, and ensure that it
+ * gets run.
+ */
 static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
 {
-	struct request_queue *q = hctx->queue;
 	struct blk_mq_ctx *ctx;
 	LIST_HEAD(tmp);
 
-	/*
-	 * Move ctx entries to new CPU, if this one is going away.
-	 */
-	ctx = __blk_mq_get_ctx(q, cpu);
+	ctx = __blk_mq_get_ctx(hctx->queue, cpu);
 
 	spin_lock(&ctx->lock);
 	if (!list_empty(&ctx->rq_list)) {
@@ -1591,24 +1634,11 @@
 	if (list_empty(&tmp))
 		return NOTIFY_OK;
 
-	ctx = blk_mq_get_ctx(q);
-	spin_lock(&ctx->lock);
-
-	while (!list_empty(&tmp)) {
-		struct request *rq;
-
-		rq = list_first_entry(&tmp, struct request, queuelist);
-		rq->mq_ctx = ctx;
-		list_move_tail(&rq->queuelist, &ctx->rq_list);
-	}
-
-	hctx = q->mq_ops->map_queue(q, ctx->cpu);
-	blk_mq_hctx_mark_pending(hctx, ctx);
-
-	spin_unlock(&ctx->lock);
+	spin_lock(&hctx->lock);
+	list_splice_tail_init(&tmp, &hctx->dispatch);
+	spin_unlock(&hctx->lock);
 
 	blk_mq_run_hw_queue(hctx, true);
-	blk_mq_put_ctx(ctx);
 	return NOTIFY_OK;
 }
 
@@ -1635,7 +1665,8 @@
 {
 	unsigned flush_start_tag = set->queue_depth;
 
-	blk_mq_tag_idle(hctx);
+	if (blk_mq_hw_queue_mapped(hctx))
+		blk_mq_tag_idle(hctx);
 
 	if (set->ops->exit_request)
 		set->ops->exit_request(set->driver_data,
@@ -1801,7 +1832,7 @@
 static void blk_mq_map_swqueue(struct request_queue *q,
 			       const struct cpumask *online_mask)
 {
-	unsigned int i;
+	unsigned int i, hctx_idx;
 	struct blk_mq_hw_ctx *hctx;
 	struct blk_mq_ctx *ctx;
 	struct blk_mq_tag_set *set = q->tag_set;
@@ -1819,11 +1850,27 @@
 	/*
 	 * Map software to hardware queues
 	 */
-	queue_for_each_ctx(q, ctx, i) {
+	for_each_possible_cpu(i) {
 		/* If the cpu isn't online, the cpu is mapped to first hctx */
 		if (!cpumask_test_cpu(i, online_mask))
 			continue;
 
+		hctx_idx = q->mq_map[i];
+		/* unmapped hw queue can be remapped after CPU topo changed */
+		if (!set->tags[hctx_idx]) {
+			set->tags[hctx_idx] = blk_mq_init_rq_map(set, hctx_idx);
+
+			/*
+			 * If tags initialization fail for some hctx,
+			 * that hctx won't be brought online.  In this
+			 * case, remap the current ctx to hctx[0] which
+			 * is guaranteed to always have tags allocated
+			 */
+			if (!set->tags[hctx_idx])
+				q->mq_map[i] = 0;
+		}
+
+		ctx = per_cpu_ptr(q->queue_ctx, i);
 		hctx = q->mq_ops->map_queue(q, i);
 		cpumask_set_cpu(i, hctx->cpumask);
 		ctx->index_hw = hctx->nr_ctx;
@@ -1840,7 +1887,11 @@
 		 * disable it and free the request entries.
 		 */
 		if (!hctx->nr_ctx) {
-			if (set->tags[i]) {
+			/* Never unmap queue 0.  We need it as a
+			 * fallback in case of a new remap fails
+			 * allocation
+			 */
+			if (i && set->tags[i]) {
 				blk_mq_free_rq_map(set, set->tags[i], i);
 				set->tags[i] = NULL;
 			}
@@ -1848,12 +1899,10 @@
 			continue;
 		}
 
-		/* unmapped hw queue can be remapped after CPU topo changed */
-		if (!set->tags[i])
-			set->tags[i] = blk_mq_init_rq_map(set, i);
 		hctx->tags = set->tags[i];
 		WARN_ON(!hctx->tags);
 
+		cpumask_copy(hctx->tags->cpumask, hctx->cpumask);
 		/*
 		 * Set the map size to the number of mapped software queues.
 		 * This is more accurate and more efficient than looping
@@ -1867,14 +1916,6 @@
 		hctx->next_cpu = cpumask_first(hctx->cpumask);
 		hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH;
 	}
-
-	queue_for_each_ctx(q, ctx, i) {
-		if (!cpumask_test_cpu(i, online_mask))
-			continue;
-
-		hctx = q->mq_ops->map_queue(q, i);
-		cpumask_set_cpu(i, hctx->tags->cpumask);
-	}
 }
 
 static void queue_set_hctx_shared(struct request_queue *q, bool shared)
@@ -2019,7 +2060,7 @@
 		hctxs[i]->queue_num = i;
 	}
 
-	setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q);
+	INIT_WORK(&q->timeout_work, blk_mq_timeout_work);
 	blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ);
 
 	q->nr_queues = nr_cpu_ids;
--- linux-4.4.0.orig/block/blk-mq.h
+++ linux-4.4.0/block/blk-mq.h
@@ -96,8 +96,7 @@
 struct blk_mq_alloc_data {
 	/* input parameter */
 	struct request_queue *q;
-	gfp_t gfp;
-	bool reserved;
+	unsigned int flags;
 
 	/* input & output parameter */
 	struct blk_mq_ctx *ctx;
@@ -105,13 +104,11 @@
 };
 
 static inline void blk_mq_set_alloc_data(struct blk_mq_alloc_data *data,
-		struct request_queue *q, gfp_t gfp, bool reserved,
-		struct blk_mq_ctx *ctx,
-		struct blk_mq_hw_ctx *hctx)
+		struct request_queue *q, unsigned int flags,
+		struct blk_mq_ctx *ctx, struct blk_mq_hw_ctx *hctx)
 {
 	data->q = q;
-	data->gfp = gfp;
-	data->reserved = reserved;
+	data->flags = flags;
 	data->ctx = ctx;
 	data->hctx = hctx;
 }
--- linux-4.4.0.orig/block/blk-settings.c
+++ linux-4.4.0/block/blk-settings.c
@@ -91,8 +91,8 @@
 	lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
 	lim->virt_boundary_mask = 0;
 	lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
-	lim->max_sectors = lim->max_dev_sectors = lim->max_hw_sectors =
-		BLK_SAFE_MAX_SECTORS;
+	lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS;
+	lim->max_dev_sectors = 0;
 	lim->chunk_sectors = 0;
 	lim->max_write_same_sectors = 0;
 	lim->max_discard_sectors = 0;
@@ -349,7 +349,7 @@
  *   storage device can address.  The default of 512 covers most
  *   hardware.
  **/
-void blk_queue_logical_block_size(struct request_queue *q, unsigned short size)
+void blk_queue_logical_block_size(struct request_queue *q, unsigned int size)
 {
 	q->limits.logical_block_size = size;
 
@@ -494,6 +494,14 @@
 }
 EXPORT_SYMBOL(blk_queue_stack_limits);
 
+static unsigned int blk_round_down_sectors(unsigned int sectors, unsigned int lbs)
+{
+	sectors = round_down(sectors, lbs >> SECTOR_SHIFT);
+	if (sectors < PAGE_SIZE >> SECTOR_SHIFT)
+		sectors = PAGE_SIZE >> SECTOR_SHIFT;
+	return sectors;
+}
+
 /**
  * blk_stack_limits - adjust queue_limits for stacked devices
  * @t:	the stacking driver limits (top device)
@@ -606,6 +614,10 @@
 		ret = -1;
 	}
 
+	t->max_sectors = blk_round_down_sectors(t->max_sectors, t->logical_block_size);
+	t->max_hw_sectors = blk_round_down_sectors(t->max_hw_sectors, t->logical_block_size);
+	t->max_dev_sectors = blk_round_down_sectors(t->max_dev_sectors, t->logical_block_size);
+
 	/* Discard alignment and granularity */
 	if (b->discard_granularity) {
 		alignment = queue_limit_discard_alignment(b, start);
--- linux-4.4.0.orig/block/blk-sysfs.c
+++ linux-4.4.0/block/blk-sysfs.c
@@ -75,7 +75,7 @@
 
 static ssize_t queue_ra_show(struct request_queue *q, char *page)
 {
-	unsigned long ra_kb = q->backing_dev_info.ra_pages <<
+	unsigned long ra_kb = q->backing_dev_info->ra_pages <<
 					(PAGE_CACHE_SHIFT - 10);
 
 	return queue_var_show(ra_kb, (page));
@@ -90,7 +90,7 @@
 	if (ret < 0)
 		return ret;
 
-	q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10);
+	q->backing_dev_info->ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10);
 
 	return ret;
 }
@@ -578,7 +578,7 @@
 	struct request_queue *q =
 		container_of(kobj, struct request_queue, kobj);
 
-	bdi_exit(&q->backing_dev_info);
+	bdi_put(q->backing_dev_info);
 	blkcg_exit_queue(q);
 
 	if (q->elevator) {
--- linux-4.4.0.orig/block/blk-throttle.c
+++ linux-4.4.0/block/blk-throttle.c
@@ -505,6 +505,17 @@
 static void throtl_schedule_pending_timer(struct throtl_service_queue *sq,
 					  unsigned long expires)
 {
+	unsigned long max_expire = jiffies + 8 * throtl_slice;
+
+	/*
+	 * Since we are adjusting the throttle limit dynamically, the sleep
+	 * time calculated according to previous limit might be invalid. It's
+	 * possible the cgroup sleep time is very long and no other cgroups
+	 * have IO running so notify the limit changes. Make sure the cgroup
+	 * doesn't sleep too long to avoid the missed notification.
+	 */
+	if (time_after(expires, max_expire))
+		expires = max_expire;
 	mod_timer(&sq->pending_timer, expires);
 	throtl_log(sq, "schedule timer. delay=%lu jiffies=%lu",
 		   expires - jiffies, jiffies);
--- linux-4.4.0.orig/block/blk-timeout.c
+++ linux-4.4.0/block/blk-timeout.c
@@ -127,9 +127,10 @@
 	}
 }
 
-void blk_rq_timed_out_timer(unsigned long data)
+void blk_timeout_work(struct work_struct *work)
 {
-	struct request_queue *q = (struct request_queue *) data;
+	struct request_queue *q =
+		container_of(work, struct request_queue, timeout_work);
 	unsigned long flags, next = 0;
 	struct request *rq, *tmp;
 	int next_set = 0;
--- linux-4.4.0.orig/block/blk.h
+++ linux-4.4.0/block/blk.h
@@ -93,7 +93,7 @@
 }
 #endif
 
-void blk_rq_timed_out_timer(unsigned long data);
+void blk_timeout_work(struct work_struct *work);
 unsigned long blk_rq_timeout(unsigned long timeout);
 void blk_add_timer(struct request *req);
 void blk_delete_timer(struct request *);
--- linux-4.4.0.orig/block/bsg.c
+++ linux-4.4.0/block/bsg.c
@@ -655,6 +655,9 @@
 
 	dprintk("%s: write %Zd bytes\n", bd->name, count);
 
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS)))
+		return -EINVAL;
+
 	bsg_set_block(bd, file);
 
 	bytes_written = 0;
--- linux-4.4.0.orig/block/cfq-iosched.c
+++ linux-4.4.0/block/cfq-iosched.c
@@ -1572,7 +1572,7 @@
 {
 	struct cfq_group_data *cgd;
 
-	cgd = kzalloc(sizeof(*cgd), GFP_KERNEL);
+	cgd = kzalloc(sizeof(*cgd), gfp);
 	if (!cgd)
 		return NULL;
 	return &cgd->cpd;
@@ -2905,7 +2905,8 @@
 	 * for devices that support queuing, otherwise we still have a problem
 	 * with sync vs async workloads.
 	 */
-	if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag)
+	if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag &&
+		!cfqd->cfq_group_idle)
 		return;
 
 	WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list));
@@ -3003,7 +3004,6 @@
 	if (time_before(jiffies, rq->fifo_time))
 		rq = NULL;
 
-	cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
 	return rq;
 }
 
@@ -3377,6 +3377,9 @@
 {
 	unsigned int max_dispatch;
 
+	if (cfq_cfqq_must_dispatch(cfqq))
+		return true;
+
 	/*
 	 * Drain async requests before we start sync IO
 	 */
@@ -3468,15 +3471,20 @@
 
 	BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
 
+	rq = cfq_check_fifo(cfqq);
+	if (rq)
+		cfq_mark_cfqq_must_dispatch(cfqq);
+
 	if (!cfq_may_dispatch(cfqd, cfqq))
 		return false;
 
 	/*
 	 * follow expired path, else get first next available
 	 */
-	rq = cfq_check_fifo(cfqq);
 	if (!rq)
 		rq = cfqq->next_rq;
+	else
+		cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
 
 	/*
 	 * insert request into driver dispatch list
@@ -3803,7 +3811,8 @@
 			goto out;
 	}
 
-	cfqq = kmem_cache_alloc_node(cfq_pool, GFP_NOWAIT | __GFP_ZERO,
+	cfqq = kmem_cache_alloc_node(cfq_pool,
+				     GFP_NOWAIT | __GFP_ZERO | __GFP_NOWARN,
 				     cfqd->queue->node);
 	if (!cfqq) {
 		cfqq = &cfqd->oom_cfqq;
@@ -3944,7 +3953,7 @@
 	 * if the new request is sync, but the currently running queue is
 	 * not, let the sync request have priority.
 	 */
-	if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
+	if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq) && !cfq_cfqq_must_dispatch(cfqq))
 		return true;
 
 	if (new_cfqq->cfqg != cfqq->cfqg)
--- linux-4.4.0.orig/block/compat_ioctl.c
+++ linux-4.4.0/block/compat_ioctl.c
@@ -4,8 +4,8 @@
 #include <linux/cdrom.h>
 #include <linux/compat.h>
 #include <linux/elevator.h>
-#include <linux/fd.h>
 #include <linux/hdreg.h>
+#include <linux/pr.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/types.h>
@@ -209,318 +209,6 @@
 #define BLKBSZSET_32		_IOW(0x12, 113, int)
 #define BLKGETSIZE64_32		_IOR(0x12, 114, int)
 
-struct compat_floppy_drive_params {
-	char		cmos;
-	compat_ulong_t	max_dtr;
-	compat_ulong_t	hlt;
-	compat_ulong_t	hut;
-	compat_ulong_t	srt;
-	compat_ulong_t	spinup;
-	compat_ulong_t	spindown;
-	unsigned char	spindown_offset;
-	unsigned char	select_delay;
-	unsigned char	rps;
-	unsigned char	tracks;
-	compat_ulong_t	timeout;
-	unsigned char	interleave_sect;
-	struct floppy_max_errors max_errors;
-	char		flags;
-	char		read_track;
-	short		autodetect[8];
-	compat_int_t	checkfreq;
-	compat_int_t	native_format;
-};
-
-struct compat_floppy_drive_struct {
-	signed char	flags;
-	compat_ulong_t	spinup_date;
-	compat_ulong_t	select_date;
-	compat_ulong_t	first_read_date;
-	short		probed_format;
-	short		track;
-	short		maxblock;
-	short		maxtrack;
-	compat_int_t	generation;
-	compat_int_t	keep_data;
-	compat_int_t	fd_ref;
-	compat_int_t	fd_device;
-	compat_int_t	last_checked;
-	compat_caddr_t dmabuf;
-	compat_int_t	bufblocks;
-};
-
-struct compat_floppy_fdc_state {
-	compat_int_t	spec1;
-	compat_int_t	spec2;
-	compat_int_t	dtr;
-	unsigned char	version;
-	unsigned char	dor;
-	compat_ulong_t	address;
-	unsigned int	rawcmd:2;
-	unsigned int	reset:1;
-	unsigned int	need_configure:1;
-	unsigned int	perp_mode:2;
-	unsigned int	has_fifo:1;
-	unsigned int	driver_version;
-	unsigned char	track[4];
-};
-
-struct compat_floppy_write_errors {
-	unsigned int	write_errors;
-	compat_ulong_t	first_error_sector;
-	compat_int_t	first_error_generation;
-	compat_ulong_t	last_error_sector;
-	compat_int_t	last_error_generation;
-	compat_uint_t	badness;
-};
-
-#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
-#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
-#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
-#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
-#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
-#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
-#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
-#define FDWERRORGET32  _IOR(2, 0x17, struct compat_floppy_write_errors)
-
-static struct {
-	unsigned int	cmd32;
-	unsigned int	cmd;
-} fd_ioctl_trans_table[] = {
-	{ FDSETPRM32, FDSETPRM },
-	{ FDDEFPRM32, FDDEFPRM },
-	{ FDGETPRM32, FDGETPRM },
-	{ FDSETDRVPRM32, FDSETDRVPRM },
-	{ FDGETDRVPRM32, FDGETDRVPRM },
-	{ FDGETDRVSTAT32, FDGETDRVSTAT },
-	{ FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
-	{ FDGETFDCSTAT32, FDGETFDCSTAT },
-	{ FDWERRORGET32, FDWERRORGET }
-};
-
-#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
-
-static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
-		unsigned int cmd, unsigned long arg)
-{
-	mm_segment_t old_fs = get_fs();
-	void *karg = NULL;
-	unsigned int kcmd = 0;
-	int i, err;
-
-	for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
-		if (cmd == fd_ioctl_trans_table[i].cmd32) {
-			kcmd = fd_ioctl_trans_table[i].cmd;
-			break;
-		}
-	if (!kcmd)
-		return -EINVAL;
-
-	switch (cmd) {
-	case FDSETPRM32:
-	case FDDEFPRM32:
-	case FDGETPRM32:
-	{
-		compat_uptr_t name;
-		struct compat_floppy_struct __user *uf;
-		struct floppy_struct *f;
-
-		uf = compat_ptr(arg);
-		f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
-		if (!karg)
-			return -ENOMEM;
-		if (cmd == FDGETPRM32)
-			break;
-		err = __get_user(f->size, &uf->size);
-		err |= __get_user(f->sect, &uf->sect);
-		err |= __get_user(f->head, &uf->head);
-		err |= __get_user(f->track, &uf->track);
-		err |= __get_user(f->stretch, &uf->stretch);
-		err |= __get_user(f->gap, &uf->gap);
-		err |= __get_user(f->rate, &uf->rate);
-		err |= __get_user(f->spec1, &uf->spec1);
-		err |= __get_user(f->fmt_gap, &uf->fmt_gap);
-		err |= __get_user(name, &uf->name);
-		f->name = compat_ptr(name);
-		if (err) {
-			err = -EFAULT;
-			goto out;
-		}
-		break;
-	}
-	case FDSETDRVPRM32:
-	case FDGETDRVPRM32:
-	{
-		struct compat_floppy_drive_params __user *uf;
-		struct floppy_drive_params *f;
-
-		uf = compat_ptr(arg);
-		f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
-		if (!karg)
-			return -ENOMEM;
-		if (cmd == FDGETDRVPRM32)
-			break;
-		err = __get_user(f->cmos, &uf->cmos);
-		err |= __get_user(f->max_dtr, &uf->max_dtr);
-		err |= __get_user(f->hlt, &uf->hlt);
-		err |= __get_user(f->hut, &uf->hut);
-		err |= __get_user(f->srt, &uf->srt);
-		err |= __get_user(f->spinup, &uf->spinup);
-		err |= __get_user(f->spindown, &uf->spindown);
-		err |= __get_user(f->spindown_offset, &uf->spindown_offset);
-		err |= __get_user(f->select_delay, &uf->select_delay);
-		err |= __get_user(f->rps, &uf->rps);
-		err |= __get_user(f->tracks, &uf->tracks);
-		err |= __get_user(f->timeout, &uf->timeout);
-		err |= __get_user(f->interleave_sect, &uf->interleave_sect);
-		err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors));
-		err |= __get_user(f->flags, &uf->flags);
-		err |= __get_user(f->read_track, &uf->read_track);
-		err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect));
-		err |= __get_user(f->checkfreq, &uf->checkfreq);
-		err |= __get_user(f->native_format, &uf->native_format);
-		if (err) {
-			err = -EFAULT;
-			goto out;
-		}
-		break;
-	}
-	case FDGETDRVSTAT32:
-	case FDPOLLDRVSTAT32:
-		karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
-		if (!karg)
-			return -ENOMEM;
-		break;
-	case FDGETFDCSTAT32:
-		karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
-		if (!karg)
-			return -ENOMEM;
-		break;
-	case FDWERRORGET32:
-		karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
-		if (!karg)
-			return -ENOMEM;
-		break;
-	default:
-		return -EINVAL;
-	}
-	set_fs(KERNEL_DS);
-	err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
-	set_fs(old_fs);
-	if (err)
-		goto out;
-	switch (cmd) {
-	case FDGETPRM32:
-	{
-		struct floppy_struct *f = karg;
-		struct compat_floppy_struct __user *uf = compat_ptr(arg);
-
-		err = __put_user(f->size, &uf->size);
-		err |= __put_user(f->sect, &uf->sect);
-		err |= __put_user(f->head, &uf->head);
-		err |= __put_user(f->track, &uf->track);
-		err |= __put_user(f->stretch, &uf->stretch);
-		err |= __put_user(f->gap, &uf->gap);
-		err |= __put_user(f->rate, &uf->rate);
-		err |= __put_user(f->spec1, &uf->spec1);
-		err |= __put_user(f->fmt_gap, &uf->fmt_gap);
-		err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name);
-		break;
-	}
-	case FDGETDRVPRM32:
-	{
-		struct compat_floppy_drive_params __user *uf;
-		struct floppy_drive_params *f = karg;
-
-		uf = compat_ptr(arg);
-		err = __put_user(f->cmos, &uf->cmos);
-		err |= __put_user(f->max_dtr, &uf->max_dtr);
-		err |= __put_user(f->hlt, &uf->hlt);
-		err |= __put_user(f->hut, &uf->hut);
-		err |= __put_user(f->srt, &uf->srt);
-		err |= __put_user(f->spinup, &uf->spinup);
-		err |= __put_user(f->spindown, &uf->spindown);
-		err |= __put_user(f->spindown_offset, &uf->spindown_offset);
-		err |= __put_user(f->select_delay, &uf->select_delay);
-		err |= __put_user(f->rps, &uf->rps);
-		err |= __put_user(f->tracks, &uf->tracks);
-		err |= __put_user(f->timeout, &uf->timeout);
-		err |= __put_user(f->interleave_sect, &uf->interleave_sect);
-		err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors));
-		err |= __put_user(f->flags, &uf->flags);
-		err |= __put_user(f->read_track, &uf->read_track);
-		err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect));
-		err |= __put_user(f->checkfreq, &uf->checkfreq);
-		err |= __put_user(f->native_format, &uf->native_format);
-		break;
-	}
-	case FDGETDRVSTAT32:
-	case FDPOLLDRVSTAT32:
-	{
-		struct compat_floppy_drive_struct __user *uf;
-		struct floppy_drive_struct *f = karg;
-
-		uf = compat_ptr(arg);
-		err = __put_user(f->flags, &uf->flags);
-		err |= __put_user(f->spinup_date, &uf->spinup_date);
-		err |= __put_user(f->select_date, &uf->select_date);
-		err |= __put_user(f->first_read_date, &uf->first_read_date);
-		err |= __put_user(f->probed_format, &uf->probed_format);
-		err |= __put_user(f->track, &uf->track);
-		err |= __put_user(f->maxblock, &uf->maxblock);
-		err |= __put_user(f->maxtrack, &uf->maxtrack);
-		err |= __put_user(f->generation, &uf->generation);
-		err |= __put_user(f->keep_data, &uf->keep_data);
-		err |= __put_user(f->fd_ref, &uf->fd_ref);
-		err |= __put_user(f->fd_device, &uf->fd_device);
-		err |= __put_user(f->last_checked, &uf->last_checked);
-		err |= __put_user((u64)f->dmabuf, &uf->dmabuf);
-		err |= __put_user((u64)f->bufblocks, &uf->bufblocks);
-		break;
-	}
-	case FDGETFDCSTAT32:
-	{
-		struct compat_floppy_fdc_state __user *uf;
-		struct floppy_fdc_state *f = karg;
-
-		uf = compat_ptr(arg);
-		err = __put_user(f->spec1, &uf->spec1);
-		err |= __put_user(f->spec2, &uf->spec2);
-		err |= __put_user(f->dtr, &uf->dtr);
-		err |= __put_user(f->version, &uf->version);
-		err |= __put_user(f->dor, &uf->dor);
-		err |= __put_user(f->address, &uf->address);
-		err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address),
-				   (char *)&f->address + sizeof(f->address), sizeof(int));
-		err |= __put_user(f->driver_version, &uf->driver_version);
-		err |= __copy_to_user(uf->track, f->track, sizeof(f->track));
-		break;
-	}
-	case FDWERRORGET32:
-	{
-		struct compat_floppy_write_errors __user *uf;
-		struct floppy_write_errors *f = karg;
-
-		uf = compat_ptr(arg);
-		err = __put_user(f->write_errors, &uf->write_errors);
-		err |= __put_user(f->first_error_sector, &uf->first_error_sector);
-		err |= __put_user(f->first_error_generation, &uf->first_error_generation);
-		err |= __put_user(f->last_error_sector, &uf->last_error_sector);
-		err |= __put_user(f->last_error_generation, &uf->last_error_generation);
-		err |= __put_user(f->badness, &uf->badness);
-		break;
-	}
-	default:
-		break;
-	}
-	if (err)
-		err = -EFAULT;
-
-out:
-	kfree(karg);
-	return err;
-}
-
 static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
 			unsigned cmd, unsigned long arg)
 {
@@ -537,16 +225,6 @@
 	case HDIO_GET_ADDRESS:
 	case HDIO_GET_BUSSTATE:
 		return compat_hdio_ioctl(bdev, mode, cmd, arg);
-	case FDSETPRM32:
-	case FDDEFPRM32:
-	case FDGETPRM32:
-	case FDSETDRVPRM32:
-	case FDGETDRVPRM32:
-	case FDGETDRVSTAT32:
-	case FDPOLLDRVSTAT32:
-	case FDGETFDCSTAT32:
-	case FDWERRORGET32:
-		return compat_fd_ioctl(bdev, mode, cmd, arg);
 	case CDROMREADAUDIO:
 		return compat_cdrom_read_audio(bdev, mode, cmd, arg);
 	case CDROM_SEND_PACKET:
@@ -566,23 +244,6 @@
 	case HDIO_DRIVE_CMD:
 	/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
 	case 0x330:
-	/* 0x02 -- Floppy ioctls */
-	case FDMSGON:
-	case FDMSGOFF:
-	case FDSETEMSGTRESH:
-	case FDFLUSH:
-	case FDWERRORCLR:
-	case FDSETMAXERRS:
-	case FDGETMAXERRS:
-	case FDGETDRVTYP:
-	case FDEJECT:
-	case FDCLRPRM:
-	case FDFMTBEG:
-	case FDFMTEND:
-	case FDRESET:
-	case FDTWADDLE:
-	case FDFMTTRK:
-	case FDRAWCMD:
 	/* CDROM stuff */
 	case CDROMPAUSE:
 	case CDROMRESUME:
@@ -661,7 +322,6 @@
 	struct block_device *bdev = inode->i_bdev;
 	struct gendisk *disk = bdev->bd_disk;
 	fmode_t mode = file->f_mode;
-	struct backing_dev_info *bdi;
 	loff_t size;
 	unsigned int max_sectors;
 
@@ -708,9 +368,8 @@
 	case BLKFRAGET:
 		if (!arg)
 			return -EINVAL;
-		bdi = blk_get_backing_dev_info(bdev);
 		return compat_put_long(arg,
-				       (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
+			       (bdev->bd_bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
 	case BLKROGET: /* compatible */
 		return compat_put_int(arg, bdev_read_only(bdev) != 0);
 	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
@@ -728,8 +387,7 @@
 	case BLKFRASET:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
-		bdi = blk_get_backing_dev_info(bdev);
-		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
+		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
 		return 0;
 	case BLKGETSIZE:
 		size = i_size_read(bdev->bd_inode);
@@ -746,6 +404,14 @@
 	case BLKTRACETEARDOWN: /* compatible */
 		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
 		return ret;
+	case IOC_PR_REGISTER:
+	case IOC_PR_RESERVE:
+	case IOC_PR_RELEASE:
+	case IOC_PR_PREEMPT:
+	case IOC_PR_PREEMPT_ABORT:
+	case IOC_PR_CLEAR:
+		return blkdev_ioctl(bdev, mode, cmd,
+				(unsigned long)compat_ptr(arg));
 	default:
 		if (disk->fops->compat_ioctl)
 			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
--- linux-4.4.0.orig/block/genhd.c
+++ linux-4.4.0/block/genhd.c
@@ -158,14 +158,17 @@
 		part = rcu_dereference(ptbl->part[piter->idx]);
 		if (!part)
 			continue;
+		get_device(part_to_dev(part));
+		piter->part = part;
 		if (!part_nr_sects_read(part) &&
 		    !(piter->flags & DISK_PITER_INCL_EMPTY) &&
 		    !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 &&
-		      piter->idx == 0))
+		      piter->idx == 0)) {
+			put_device(part_to_dev(part));
+			piter->part = NULL;
 			continue;
+		}
 
-		get_device(part_to_dev(part));
-		piter->part = part;
 		piter->idx += inc;
 		break;
 	}
@@ -611,8 +614,8 @@
 	disk_alloc_events(disk);
 
 	/* Register BDI before referencing it from bdev */
-	bdi = &disk->queue->backing_dev_info;
-	bdi_register_dev(bdi, disk_devt(disk));
+	bdi = disk->queue->backing_dev_info;
+	bdi_register_owner(bdi, disk_to_dev(disk));
 
 	blk_register_region(disk_devt(disk), disk->minors, NULL,
 			    exact_match, exact_lock, disk);
@@ -647,16 +650,27 @@
 			     DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
 	while ((part = disk_part_iter_next(&piter))) {
 		invalidate_partition(disk, part->partno);
+		bdev_unhash_inode(part_devt(part));
 		delete_partition(disk, part->partno);
 	}
 	disk_part_iter_exit(&piter);
 
 	invalidate_partition(disk, 0);
+	bdev_unhash_inode(disk_devt(disk));
 	set_capacity(disk, 0);
 	disk->flags &= ~GENHD_FL_UP;
 
 	sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
-	blk_unregister_queue(disk);
+	if (disk->queue) {
+		/*
+		 * Unregister bdi before releasing device numbers (as they can
+		 * get reused and we'd get clashes in sysfs).
+		 */
+		bdi_unregister(disk->queue->backing_dev_info);
+		blk_unregister_queue(disk);
+	} else {
+		WARN_ON(1);
+	}
 	blk_unregister_region(disk_devt(disk), disk->minors);
 
 	part_stat_set_all(&disk->part0, 0);
@@ -664,7 +678,6 @@
 
 	kobject_put(disk->part0.holder_dir);
 	kobject_put(disk->slave_dir);
-	disk->driverfs_dev = NULL;
 	if (!sysfs_deprecated)
 		sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
 	pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
@@ -831,6 +844,7 @@
 	if (iter) {
 		class_dev_iter_exit(iter);
 		kfree(iter);
+		seqf->private = NULL;
 	}
 }
 
@@ -1312,7 +1326,7 @@
 	owner = disk->fops->owner;
 	if (owner && !try_module_get(owner))
 		return NULL;
-	kobj = kobject_get(&disk_to_dev(disk)->kobj);
+	kobj = kobject_get_unless_zero(&disk_to_dev(disk)->kobj);
 	if (kobj == NULL) {
 		module_put(owner);
 		return NULL;
--- linux-4.4.0.orig/block/ioctl.c
+++ linux-4.4.0/block/ioctl.c
@@ -18,7 +18,7 @@
 	struct blkpg_ioctl_arg a;
 	struct blkpg_partition p;
 	struct disk_part_iter piter;
-	long long start, length;
+	sector_t start, length;
 	int partno;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -33,6 +33,13 @@
 	partno = p.pno;
 	if (partno <= 0)
 		return -EINVAL;
+	if (a.op != BLKPG_DEL_PARTITION) {
+		if (p.start < 0 || p.length <= 0 || p.start + p.length < 0)
+			return -EINVAL;
+		/* Check that the partition is aligned to the block size */
+		if (!IS_ALIGNED(p.start | p.length, bdev_logical_block_size(bdev)))
+			return -EINVAL;
+	}
 	switch (a.op) {
 		case BLKPG_ADD_PARTITION:
 			start = p.start >> 9;
@@ -496,7 +503,6 @@
 int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 			unsigned long arg)
 {
-	struct backing_dev_info *bdi;
 	void __user *argp = (void __user *)arg;
 	loff_t size;
 	unsigned int max_sectors;
@@ -519,8 +525,7 @@
 	case BLKFRAGET:
 		if (!arg)
 			return -EINVAL;
-		bdi = blk_get_backing_dev_info(bdev);
-		return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
+		return put_long(arg, (bdev->bd_bdi->ra_pages*PAGE_CACHE_SIZE) / 512);
 	case BLKROGET:
 		return put_int(arg, bdev_read_only(bdev) != 0);
 	case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
@@ -547,8 +552,7 @@
 	case BLKFRASET:
 		if(!capable(CAP_SYS_ADMIN))
 			return -EACCES;
-		bdi = blk_get_backing_dev_info(bdev);
-		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
+		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
 		return 0;
 	case BLKBSZSET:
 		return blkdev_bszset(bdev, mode, argp);
--- linux-4.4.0.orig/block/ioprio.c
+++ linux-4.4.0/block/ioprio.c
@@ -150,8 +150,10 @@
 	if (ret)
 		goto out;
 	ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
+	task_lock(p);
 	if (p->io_context)
 		ret = p->io_context->ioprio;
+	task_unlock(p);
 out:
 	return ret;
 }
--- linux-4.4.0.orig/block/partition-generic.c
+++ linux-4.4.0/block/partition-generic.c
@@ -309,8 +309,10 @@
 
 	if (info) {
 		struct partition_meta_info *pinfo = alloc_part_info(disk);
-		if (!pinfo)
+		if (!pinfo) {
+			err = -ENOMEM;
 			goto out_free_stats;
+		}
 		memcpy(pinfo, info, sizeof(*info));
 		p->info = pinfo;
 	}
@@ -349,15 +351,20 @@
 			goto out_del;
 	}
 
+	err = hd_ref_init(p);
+	if (err) {
+		if (flags & ADDPART_FLAG_WHOLEDISK)
+			goto out_remove_file;
+		goto out_del;
+	}
+
 	/* everything is up and running, commence */
 	rcu_assign_pointer(ptbl->part[partno], p);
 
 	/* suppress uevent if the disk suppresses it */
 	if (!dev_get_uevent_suppress(ddev))
 		kobject_uevent(&pdev->kobj, KOBJ_ADD);
-
-	if (!hd_ref_init(p))
-		return p;
+	return p;
 
 out_free_info:
 	free_part_info(p);
@@ -366,6 +373,8 @@
 out_free:
 	kfree(p);
 	return ERR_PTR(err);
+out_remove_file:
+	device_remove_file(pdev, &dev_attr_whole_disk);
 out_del:
 	kobject_put(p->holder_dir);
 	device_del(pdev);
@@ -428,7 +437,6 @@
 
 	if (disk->fops->revalidate_disk)
 		disk->fops->revalidate_disk(disk);
-	blk_integrity_revalidate(disk);
 	check_disk_size_change(disk, bdev);
 	bdev->bd_invalidated = 0;
 	if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
--- linux-4.4.0.orig/block/partitions/aix.c
+++ linux-4.4.0/block/partitions/aix.c
@@ -177,7 +177,7 @@
 	u32 vgda_sector = 0;
 	u32 vgda_len = 0;
 	int numlvs = 0;
-	struct pvd *pvd;
+	struct pvd *pvd = NULL;
 	struct lv_info {
 		unsigned short pps_per_lv;
 		unsigned short pps_found;
@@ -231,10 +231,11 @@
 				if (lvip[i].pps_per_lv)
 					foundlvs += 1;
 			}
+			/* pvd loops depend on n[].name and lvip[].pps_per_lv */
+			pvd = alloc_pvd(state, vgda_sector + 17);
 		}
 		put_dev_sector(sect);
 	}
-	pvd = alloc_pvd(state, vgda_sector + 17);
 	if (pvd) {
 		int numpps = be16_to_cpu(pvd->pp_count);
 		int psn_part1 = be32_to_cpu(pvd->psn_part1);
@@ -281,10 +282,14 @@
 				next_lp_ix += 1;
 		}
 		for (i = 0; i < state->limit; i += 1)
-			if (lvip[i].pps_found && !lvip[i].lv_is_contiguous)
+			if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) {
+				char tmp[sizeof(n[i].name) + 1]; // null char
+
+				snprintf(tmp, sizeof(tmp), "%s", n[i].name);
 				pr_warn("partition %s (%u pp's found) is "
 					"not contiguous\n",
-					n[i].name, lvip[i].pps_found);
+					tmp, lvip[i].pps_found);
+			}
 		kfree(pvd);
 	}
 	kfree(n);
--- linux-4.4.0.orig/block/partitions/atari.c
+++ linux-4.4.0/block/partitions/atari.c
@@ -42,6 +42,13 @@
 	int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
 #endif
 
+	/*
+	 * ATARI partition scheme supports 512 lba only.  If this is not
+	 * the case, bail early to avoid miscalculating hd_size.
+	 */
+	if (bdev_logical_block_size(state->bdev) != 512)
+		return 0;
+
 	rs = read_part_sector(state, 0, &sect);
 	if (!rs)
 		return -1;
--- linux-4.4.0.orig/block/partitions/efi.c
+++ linux-4.4.0/block/partitions/efi.c
@@ -293,7 +293,7 @@
 	if (!gpt)
 		return NULL;
 
-	count = le32_to_cpu(gpt->num_partition_entries) *
+	count = (size_t)le32_to_cpu(gpt->num_partition_entries) *
                 le32_to_cpu(gpt->sizeof_partition_entry);
 	if (!count)
 		return NULL;
@@ -352,7 +352,7 @@
 			gpt_header **gpt, gpt_entry **ptes)
 {
 	u32 crc, origcrc;
-	u64 lastlba;
+	u64 lastlba, pt_size;
 
 	if (!ptes)
 		return 0;
@@ -434,13 +434,20 @@
 		goto fail;
 	}
 
+	/* Sanity check partition table size */
+	pt_size = (u64)le32_to_cpu((*gpt)->num_partition_entries) *
+		le32_to_cpu((*gpt)->sizeof_partition_entry);
+	if (pt_size > KMALLOC_MAX_SIZE) {
+		pr_debug("GUID Partition Table is too large: %llu > %lu bytes\n",
+			 (unsigned long long)pt_size, KMALLOC_MAX_SIZE);
+		goto fail;
+	}
+
 	if (!(*ptes = alloc_read_gpt_entries(state, *gpt)))
 		goto fail;
 
 	/* Check the GUID Partition Entry Array CRC */
-	crc = efi_crc32((const unsigned char *) (*ptes),
-			le32_to_cpu((*gpt)->num_partition_entries) *
-			le32_to_cpu((*gpt)->sizeof_partition_entry));
+	crc = efi_crc32((const unsigned char *) (*ptes), pt_size);
 
 	if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
 		pr_debug("GUID Partitition Entry Array CRC check failed.\n");
--- linux-4.4.0.orig/block/partitions/msdos.c
+++ linux-4.4.0/block/partitions/msdos.c
@@ -300,6 +300,10 @@
 			continue;
 		bsd_start = le32_to_cpu(p->p_offset);
 		bsd_size = le32_to_cpu(p->p_size);
+		/* FreeBSD has relative offset if C partition offset is zero */
+		if (memcmp(flavour, "bsd\0", 4) == 0 &&
+		    le32_to_cpu(l->d_partitions[2].p_offset) == 0)
+			bsd_start += offset;
 		if (offset == bsd_start && size == bsd_size)
 			/* full parent partition, we have it already */
 			continue;
--- linux-4.4.0.orig/block/scsi_ioctl.c
+++ linux-4.4.0/block/scsi_ioctl.c
@@ -28,6 +28,9 @@
 #include <linux/slab.h>
 #include <linux/times.h>
 #include <linux/uio.h>
+#include <linux/fd.h>
+#include <linux/raid/md_u.h>
+#include <linux/mtio.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
@@ -182,6 +185,9 @@
 	__set_bit(WRITE_16, filter->write_ok);
 	__set_bit(WRITE_LONG, filter->write_ok);
 	__set_bit(WRITE_LONG_2, filter->write_ok);
+	__set_bit(WRITE_SAME, filter->write_ok);
+	__set_bit(WRITE_SAME_16, filter->write_ok);
+	__set_bit(WRITE_SAME_32, filter->write_ok);
 	__set_bit(ERASE, filter->write_ok);
 	__set_bit(GPCMD_MODE_SELECT_10, filter->write_ok);
 	__set_bit(MODE_SELECT, filter->write_ok);
@@ -705,8 +711,17 @@
 	case SG_GET_RESERVED_SIZE:
 	case SG_SET_RESERVED_SIZE:
 	case SG_EMULATED_HOST:
+	case BLKFLSBUF:
+	case BLKROSET:
 		return 0;
 	case CDROM_GET_CAPABILITY:
+	case CDROM_DRIVE_STATUS:
+	case FDGETPRM:
+	case RAID_VERSION:
+	case MTIOCGET:
+#ifdef CONFIG_COMPAT
+	case 0x801c6d02:        /* MTIOCGET32 */
+#endif
 		/* Keep this until we remove the printk below.  udev sends it
 		 * and we do not want to spam dmesg about it.   CD-ROMs do
 		 * not have partitions, so we get here only for disks.
--- linux-4.4.0.orig/certs/Kconfig
+++ linux-4.4.0/certs/Kconfig
@@ -39,4 +39,20 @@
 	  form of DER-encoded *.x509 files in the top-level build directory,
 	  those are no longer used. You will need to set this option instead.
 
+config SYSTEM_EXTRA_CERTIFICATE
+	bool "Reserve area for inserting a certificate without recompiling"
+	depends on SYSTEM_TRUSTED_KEYRING
+	help
+	  If set, space for an extra certificate will be reserved in the kernel
+	  image. This allows introducing a trusted certificate to the default
+	  system keyring without recompiling the kernel.
+
+config SYSTEM_EXTRA_CERTIFICATE_SIZE
+	int "Number of bytes to reserve for the extra certificate"
+	depends on SYSTEM_EXTRA_CERTIFICATE
+	default 4096
+	help
+	  This is the number of bytes reserved in the kernel image for a
+	  certificate to be inserted.
+
 endmenu
--- linux-4.4.0.orig/certs/Makefile
+++ linux-4.4.0/certs/Makefile
@@ -36,29 +36,34 @@
 $(error Could not determine digest type to use from kernel config)
 endif
 
+redirect_openssl	= 2>&1
+quiet_redirect_openssl	= 2>&1
+silent_redirect_openssl = 2>/dev/null
+
 # We do it this way rather than having a boolean option for enabling an
 # external private key, because 'make randconfig' might enable such a
 # boolean option and we unfortunately can't make it depend on !RANDCONFIG.
 ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem")
 $(obj)/signing_key.pem: $(obj)/x509.genkey
-	@echo "###"
-	@echo "### Now generating an X.509 key pair to be used for signing modules."
-	@echo "###"
-	@echo "### If this takes a long time, you might wish to run rngd in the"
-	@echo "### background to keep the supply of entropy topped up.  It"
-	@echo "### needs to be run as root, and uses a hardware random"
-	@echo "### number generator if one is available."
-	@echo "###"
-	openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
+	@$(kecho) "###"
+	@$(kecho) "### Now generating an X.509 key pair to be used for signing modules."
+	@$(kecho) "###"
+	@$(kecho) "### If this takes a long time, you might wish to run rngd in the"
+	@$(kecho) "### background to keep the supply of entropy topped up.  It"
+	@$(kecho) "### needs to be run as root, and uses a hardware random"
+	@$(kecho) "### number generator if one is available."
+	@$(kecho) "###"
+	$(Q)openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
 		-batch -x509 -config $(obj)/x509.genkey \
 		-outform PEM -out $(obj)/signing_key.pem \
-		-keyout $(obj)/signing_key.pem 2>&1
-	@echo "###"
-	@echo "### Key pair generated."
-	@echo "###"
+		-keyout $(obj)/signing_key.pem \
+		$($(quiet)redirect_openssl)
+	@$(kecho) "###"
+	@$(kecho) "### Key pair generated."
+	@$(kecho) "###"
 
 $(obj)/x509.genkey:
-	@echo Generating X.509 key generation config
+	@$(kecho) Generating X.509 key generation config
 	@echo  >$@ "[ req ]"
 	@echo >>$@ "default_bits = 4096"
 	@echo >>$@ "distinguished_name = req_distinguished_name"
--- linux-4.4.0.orig/certs/system_certificates.S
+++ linux-4.4.0/certs/system_certificates.S
@@ -13,6 +13,18 @@
 	.incbin "certs/x509_certificate_list"
 __cert_list_end:
 
+#ifdef CONFIG_SYSTEM_EXTRA_CERTIFICATE
+	.globl VMLINUX_SYMBOL(system_extra_cert)
+	.size system_extra_cert, CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE
+VMLINUX_SYMBOL(system_extra_cert):
+	.fill CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE, 1, 0
+
+	.globl VMLINUX_SYMBOL(system_extra_cert_used)
+VMLINUX_SYMBOL(system_extra_cert_used):
+	.int 0
+
+#endif /* CONFIG_SYSTEM_EXTRA_CERTIFICATE */
+
 	.align 8
 	.globl VMLINUX_SYMBOL(system_certificate_list_size)
 VMLINUX_SYMBOL(system_certificate_list_size):
--- linux-4.4.0.orig/certs/system_keyring.c
+++ linux-4.4.0/certs/system_keyring.c
@@ -20,6 +20,9 @@
 
 struct key *system_trusted_keyring;
 EXPORT_SYMBOL_GPL(system_trusted_keyring);
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
+struct key *system_blacklist_keyring;
+#endif
 
 extern __initconst const u8 system_certificate_list[];
 extern __initconst const unsigned long system_certificate_list_size;
@@ -41,6 +44,20 @@
 		panic("Can't allocate system trusted keyring\n");
 
 	set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
+
+	#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
+	system_blacklist_keyring = keyring_alloc(".system_blacklist_keyring",
+				    KUIDT_INIT(0), KGIDT_INIT(0),
+				    current_cred(),
+				    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+				    KEY_USR_VIEW | KEY_USR_READ,
+				    KEY_ALLOC_NOT_IN_QUOTA, NULL);
+	if (IS_ERR(system_blacklist_keyring))
+		panic("Can't allocate system blacklist keyring\n");
+
+	set_bit(KEY_FLAG_TRUSTED_ONLY, &system_blacklist_keyring->flags);
+#endif
+
 	return 0;
 }
 
@@ -84,12 +101,13 @@
 					   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 					   KEY_USR_VIEW | KEY_USR_READ),
 					   KEY_ALLOC_NOT_IN_QUOTA |
-					   KEY_ALLOC_TRUSTED);
+					   KEY_ALLOC_TRUSTED |
+					   KEY_ALLOC_BUILT_IN);
 		if (IS_ERR(key)) {
 			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
 			       PTR_ERR(key));
+			WARN_ON_ONCE(1);
 		} else {
-			set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
 			pr_notice("Loaded X.509 cert '%s'\n",
 				  key_ref_to_ptr(key)->description);
 			key_ref_put(key);
@@ -138,6 +156,16 @@
 	if (ret < 0)
 		goto error;
 
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
+	ret = pkcs7_validate_trust(pkcs7, system_blacklist_keyring, &trusted);
+	if (!ret) {
+		/* module is signed with a cert in the blacklist.  reject */
+		pr_err("Module key is in the blacklist\n");
+		ret = -EKEYREJECTED;
+		goto error;
+	}
+#endif
+
 	ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
 	if (ret < 0)
 		goto error;
--- linux-4.4.0.orig/crypto/Kconfig
+++ linux-4.4.0/crypto/Kconfig
@@ -102,6 +102,15 @@
 	select CRYPTO_AKCIPHER2
 	select CRYPTO_ALGAPI
 
+config CRYPTO_KPP2
+	tristate
+	select CRYPTO_ALGAPI2
+
+config CRYPTO_KPP
+	tristate
+	select CRYPTO_ALGAPI
+	select CRYPTO_KPP2
+
 config CRYPTO_RSA
 	tristate "RSA algorithm"
 	select CRYPTO_AKCIPHER
@@ -110,6 +119,20 @@
 	help
 	  Generic implementation of the RSA public key algorithm.
 
+config CRYPTO_DH
+	tristate "Diffie-Hellman algorithm"
+	select CRYPTO_KPP
+	select MPILIB
+	help
+	  Generic implementation of the Diffie-Hellman algorithm.
+
+config CRYPTO_ECDH
+	tristate "ECDH algorithm"
+	select CRYTPO_KPP
+	select CRYPTO_RNG_DEFAULT
+	help
+	  Generic implementation of the ECDH algorithm
+
 config CRYPTO_MANAGER
 	tristate "Cryptographic algorithm manager"
 	select CRYPTO_MANAGER2
@@ -124,6 +147,7 @@
 	select CRYPTO_BLKCIPHER2
 	select CRYPTO_PCOMP2
 	select CRYPTO_AKCIPHER2
+	select CRYPTO_KPP2
 
 config CRYPTO_USER
 	tristate "Userspace cryptographic algorithm configuration"
--- linux-4.4.0.orig/crypto/Makefile
+++ linux-4.4.0/crypto/Makefile
@@ -30,9 +30,15 @@
 
 obj-$(CONFIG_CRYPTO_PCOMP2) += pcompress.o
 obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o
+obj-$(CONFIG_CRYPTO_KPP2) += kpp.o
+
+dh_generic-y := dh.o
+dh_generic-y += dh_helper.o
+obj-$(CONFIG_CRYPTO_DH) += dh_generic.o
 
 $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
 $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h
+$(obj)/rsa_helper.o: $(obj)/rsapubkey-asn1.h $(obj)/rsaprivkey-asn1.h
 clean-files += rsapubkey-asn1.c rsapubkey-asn1.h
 clean-files += rsaprivkey-asn1.c rsaprivkey-asn1.h
 
@@ -61,6 +67,7 @@
 obj-$(CONFIG_CRYPTO_SHA256) += sha256_generic.o
 obj-$(CONFIG_CRYPTO_SHA512) += sha512_generic.o
 obj-$(CONFIG_CRYPTO_WP512) += wp512.o
+CFLAGS_wp512.o := $(call cc-option,-fno-schedule-insns)  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149
 obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
 obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
 obj-$(CONFIG_CRYPTO_ECB) += ecb.o
@@ -84,6 +91,7 @@
 obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o
 obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
 obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o
+CFLAGS_serpent_generic.o := $(call cc-option,-fsched-pressure)  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149
 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
 obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o
 obj-$(CONFIG_CRYPTO_CAST_COMMON) += cast_common.o
@@ -122,6 +130,11 @@
 obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
 obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
 
+ecdh_generic-y := ecc.o
+ecdh_generic-y += ecdh.o
+ecdh_generic-y += ecdh_helper.o
+obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
+
 #
 # generic algorithms and the async_tx api
 #
--- linux-4.4.0.orig/crypto/ablkcipher.c
+++ linux-4.4.0/crypto/ablkcipher.c
@@ -73,11 +73,9 @@
 	return max(start, end_page);
 }
 
-static inline unsigned int ablkcipher_done_slow(struct ablkcipher_walk *walk,
-						unsigned int bsize)
+static inline void ablkcipher_done_slow(struct ablkcipher_walk *walk,
+					unsigned int n)
 {
-	unsigned int n = bsize;
-
 	for (;;) {
 		unsigned int len_this_page = scatterwalk_pagelen(&walk->out);
 
@@ -89,17 +87,13 @@
 		n -= len_this_page;
 		scatterwalk_start(&walk->out, sg_next(walk->out.sg));
 	}
-
-	return bsize;
 }
 
-static inline unsigned int ablkcipher_done_fast(struct ablkcipher_walk *walk,
-						unsigned int n)
+static inline void ablkcipher_done_fast(struct ablkcipher_walk *walk,
+					unsigned int n)
 {
 	scatterwalk_advance(&walk->in, n);
 	scatterwalk_advance(&walk->out, n);
-
-	return n;
 }
 
 static int ablkcipher_walk_next(struct ablkcipher_request *req,
@@ -109,39 +103,40 @@
 			 struct ablkcipher_walk *walk, int err)
 {
 	struct crypto_tfm *tfm = req->base.tfm;
-	unsigned int nbytes = 0;
+	unsigned int n; /* bytes processed */
+	bool more;
 
-	if (likely(err >= 0)) {
-		unsigned int n = walk->nbytes - err;
+	if (unlikely(err < 0))
+		goto finish;
 
-		if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW)))
-			n = ablkcipher_done_fast(walk, n);
-		else if (WARN_ON(err)) {
+	n = walk->nbytes - err;
+	walk->total -= n;
+	more = (walk->total != 0);
+
+	if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW))) {
+		ablkcipher_done_fast(walk, n);
+	} else {
+		if (WARN_ON(err)) {
+			/* unexpected case; didn't process all bytes */
 			err = -EINVAL;
-			goto err;
-		} else
-			n = ablkcipher_done_slow(walk, n);
-
-		nbytes = walk->total - n;
-		err = 0;
+			goto finish;
+		}
+		ablkcipher_done_slow(walk, n);
 	}
 
-	scatterwalk_done(&walk->in, 0, nbytes);
-	scatterwalk_done(&walk->out, 1, nbytes);
+	scatterwalk_done(&walk->in, 0, more);
+	scatterwalk_done(&walk->out, 1, more);
 
-err:
-	walk->total = nbytes;
-	walk->nbytes = nbytes;
-
-	if (nbytes) {
+	if (more) {
 		crypto_yield(req->base.flags);
 		return ablkcipher_walk_next(req, walk);
 	}
-
+	err = 0;
+finish:
+	walk->nbytes = 0;
 	if (walk->iv != req->info)
 		memcpy(req->info, walk->iv, tfm->crt_ablkcipher.ivsize);
 	kfree(walk->iv_buffer);
-
 	return err;
 }
 EXPORT_SYMBOL_GPL(ablkcipher_walk_done);
@@ -389,6 +384,7 @@
 	strncpy(rblkcipher.type, "ablkcipher", sizeof(rblkcipher.type));
 	strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "<default>",
 		sizeof(rblkcipher.geniv));
+	rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0';
 
 	rblkcipher.blocksize = alg->cra_blocksize;
 	rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize;
@@ -470,6 +466,7 @@
 	strncpy(rblkcipher.type, "givcipher", sizeof(rblkcipher.type));
 	strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "<built-in>",
 		sizeof(rblkcipher.geniv));
+	rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0';
 
 	rblkcipher.blocksize = alg->cra_blocksize;
 	rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize;
--- linux-4.4.0.orig/crypto/aead.c
+++ linux-4.4.0/crypto/aead.c
@@ -44,8 +44,7 @@
 	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
 	memcpy(alignbuffer, key, keylen);
 	ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen);
-	memset(alignbuffer, 0, keylen);
-	kfree(buffer);
+	kzfree(buffer);
 	return ret;
 }
 
--- linux-4.4.0.orig/crypto/af_alg.c
+++ linux-4.4.0/crypto/af_alg.c
@@ -76,6 +76,8 @@
 		goto unlock;
 
 	type->ops->owner = THIS_MODULE;
+	if (type->ops_nokey)
+		type->ops_nokey->owner = THIS_MODULE;
 	node->type = type;
 	list_add(&node->list, &alg_types);
 	err = 0;
@@ -125,14 +127,31 @@
 }
 EXPORT_SYMBOL_GPL(af_alg_release);
 
+void af_alg_release_parent(struct sock *sk)
+{
+	struct alg_sock *ask = alg_sk(sk);
+	unsigned int nokey = atomic_read(&ask->nokey_refcnt);
+
+	sk = ask->parent;
+	ask = alg_sk(sk);
+
+	if (nokey)
+		atomic_dec(&ask->nokey_refcnt);
+
+	if (atomic_dec_and_test(&ask->refcnt))
+		sock_put(sk);
+}
+EXPORT_SYMBOL_GPL(af_alg_release_parent);
+
 static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	const u32 forbidden = CRYPTO_ALG_INTERNAL;
+	const u32 allowed = CRYPTO_ALG_KERN_DRIVER_ONLY;
 	struct sock *sk = sock->sk;
 	struct alg_sock *ask = alg_sk(sk);
 	struct sockaddr_alg *sa = (void *)uaddr;
 	const struct af_alg_type *type;
 	void *private;
+	int err;
 
 	if (sock->state == SS_CONNECTED)
 		return -EINVAL;
@@ -140,6 +159,10 @@
 	if (addr_len != sizeof(*sa))
 		return -EINVAL;
 
+	/* If caller uses non-allowed flag, return error. */
+	if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
+		return -EINVAL;
+
 	sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
 	sa->salg_name[sizeof(sa->salg_name) - 1] = 0;
 
@@ -152,24 +175,28 @@
 	if (IS_ERR(type))
 		return PTR_ERR(type);
 
-	private = type->bind(sa->salg_name,
-			     sa->salg_feat & ~forbidden,
-			     sa->salg_mask & ~forbidden);
+	private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask);
 	if (IS_ERR(private)) {
 		module_put(type->owner);
 		return PTR_ERR(private);
 	}
 
+	err = -EBUSY;
 	lock_sock(sk);
+	if (atomic_read(&ask->refcnt))
+		goto unlock;
 
 	swap(ask->type, type);
 	swap(ask->private, private);
 
+	err = 0;
+
+unlock:
 	release_sock(sk);
 
 	alg_do_release(type, private);
 
-	return 0;
+	return err;
 }
 
 static int alg_setkey(struct sock *sk, char __user *ukey,
@@ -202,11 +229,15 @@
 	struct sock *sk = sock->sk;
 	struct alg_sock *ask = alg_sk(sk);
 	const struct af_alg_type *type;
-	int err = -ENOPROTOOPT;
+	int err = -EBUSY;
 
 	lock_sock(sk);
+	if (atomic_read(&ask->refcnt) != atomic_read(&ask->nokey_refcnt))
+		goto unlock;
+
 	type = ask->type;
 
+	err = -ENOPROTOOPT;
 	if (level != SOL_ALG || !type)
 		goto unlock;
 
@@ -238,6 +269,7 @@
 	struct alg_sock *ask = alg_sk(sk);
 	const struct af_alg_type *type;
 	struct sock *sk2;
+	unsigned int nokey;
 	int err;
 
 	lock_sock(sk);
@@ -257,20 +289,31 @@
 	security_sk_clone(sk, sk2);
 
 	err = type->accept(ask->private, sk2);
-	if (err) {
-		sk_free(sk2);
+
+	nokey = err == -ENOKEY;
+	if (nokey && type->accept_nokey)
+		err = type->accept_nokey(ask->private, sk2);
+
+	if (err)
 		goto unlock;
-	}
 
 	sk2->sk_family = PF_ALG;
 
-	sock_hold(sk);
+	if (atomic_inc_return_relaxed(&ask->refcnt) == 1)
+		sock_hold(sk);
+	if (nokey) {
+		atomic_inc(&ask->nokey_refcnt);
+		atomic_set(&alg_sk(sk2)->nokey_refcnt, 1);
+	}
 	alg_sk(sk2)->parent = sk;
 	alg_sk(sk2)->type = type;
 
 	newsock->ops = type->ops;
 	newsock->state = SS_CONNECTED;
 
+	if (nokey)
+		newsock->ops = type->ops_nokey;
+
 	err = 0;
 
 unlock:
--- linux-4.4.0.orig/crypto/ahash.c
+++ linux-4.4.0/crypto/ahash.c
@@ -31,6 +31,7 @@
 	crypto_completion_t complete;
 	void *data;
 	u8 *result;
+	u32 flags;
 	void *ubuf[] CRYPTO_MINALIGN_ATTR;
 };
 
@@ -69,8 +70,9 @@
 	struct scatterlist *sg;
 
 	sg = walk->sg;
-	walk->pg = sg_page(sg);
 	walk->offset = sg->offset;
+	walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
+	walk->offset = offset_in_page(walk->offset);
 	walk->entrylen = sg->length;
 
 	if (walk->entrylen > walk->total)
@@ -83,19 +85,20 @@
 int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
 {
 	unsigned int alignmask = walk->alignmask;
-	unsigned int nbytes = walk->entrylen;
 
 	walk->data -= walk->offset;
 
-	if (nbytes && walk->offset & alignmask && !err) {
-		walk->offset = ALIGN(walk->offset, alignmask + 1);
-		walk->data += walk->offset;
-
-		nbytes = min(nbytes,
-			     ((unsigned int)(PAGE_SIZE)) - walk->offset);
-		walk->entrylen -= nbytes;
+	if (walk->entrylen && (walk->offset & alignmask) && !err) {
+		unsigned int nbytes;
 
-		return nbytes;
+		walk->offset = ALIGN(walk->offset, alignmask + 1);
+		nbytes = min(walk->entrylen,
+			     (unsigned int)(PAGE_SIZE - walk->offset));
+		if (nbytes) {
+			walk->entrylen -= nbytes;
+			walk->data += walk->offset;
+			return nbytes;
+		}
 	}
 
 	if (walk->flags & CRYPTO_ALG_ASYNC)
@@ -112,7 +115,7 @@
 	if (err)
 		return err;
 
-	if (nbytes) {
+	if (walk->entrylen) {
 		walk->offset = 0;
 		walk->pg++;
 		return hash_walk_next(walk);
@@ -269,6 +272,8 @@
 	priv->result = req->result;
 	priv->complete = req->base.complete;
 	priv->data = req->base.data;
+	priv->flags = req->base.flags;
+
 	/*
 	 * WARNING: We do not backup req->priv here! The req->priv
 	 *          is for internal use of the Crypto API and the
@@ -283,38 +288,44 @@
 	return 0;
 }
 
-static void ahash_restore_req(struct ahash_request *req)
+static void ahash_restore_req(struct ahash_request *req, int err)
 {
 	struct ahash_request_priv *priv = req->priv;
 
+	if (!err)
+		memcpy(priv->result, req->result,
+		       crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+
 	/* Restore the original crypto request. */
 	req->result = priv->result;
-	req->base.complete = priv->complete;
-	req->base.data = priv->data;
+
+	ahash_request_set_callback(req, priv->flags,
+				   priv->complete, priv->data);
 	req->priv = NULL;
 
 	/* Free the req->priv.priv from the ADJUSTED request. */
 	kzfree(priv);
 }
 
-static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
+static void ahash_notify_einprogress(struct ahash_request *req)
 {
 	struct ahash_request_priv *priv = req->priv;
+	struct crypto_async_request oreq;
 
-	if (err == -EINPROGRESS)
-		return;
-
-	if (!err)
-		memcpy(priv->result, req->result,
-		       crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+	oreq.data = priv->data;
 
-	ahash_restore_req(req);
+	priv->complete(&oreq, -EINPROGRESS);
 }
 
 static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
 {
 	struct ahash_request *areq = req->data;
 
+	if (err == -EINPROGRESS) {
+		ahash_notify_einprogress(areq);
+		return;
+	}
+
 	/*
 	 * Restore the original request, see ahash_op_unaligned() for what
 	 * goes where.
@@ -325,7 +336,7 @@
 	 */
 
 	/* First copy req->result into req->priv.result */
-	ahash_op_unaligned_finish(areq, err);
+	ahash_restore_req(areq, err);
 
 	/* Complete the ORIGINAL request. */
 	areq->base.complete(&areq->base, err);
@@ -341,7 +352,12 @@
 		return err;
 
 	err = op(req);
-	ahash_op_unaligned_finish(req, err);
+	if (err == -EINPROGRESS ||
+	    (err == -EBUSY && (ahash_request_flags(req) &
+			       CRYPTO_TFM_REQ_MAY_BACKLOG)))
+		return err;
+
+	ahash_restore_req(req, err);
 
 	return err;
 }
@@ -376,25 +392,14 @@
 }
 EXPORT_SYMBOL_GPL(crypto_ahash_digest);
 
-static void ahash_def_finup_finish2(struct ahash_request *req, int err)
+static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
 {
-	struct ahash_request_priv *priv = req->priv;
+	struct ahash_request *areq = req->data;
 
 	if (err == -EINPROGRESS)
 		return;
 
-	if (!err)
-		memcpy(priv->result, req->result,
-		       crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
-
-	ahash_restore_req(req);
-}
-
-static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
-{
-	struct ahash_request *areq = req->data;
-
-	ahash_def_finup_finish2(areq, err);
+	ahash_restore_req(areq, err);
 
 	areq->base.complete(&areq->base, err);
 }
@@ -405,11 +410,15 @@
 		goto out;
 
 	req->base.complete = ahash_def_finup_done2;
-	req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
 	err = crypto_ahash_reqtfm(req)->final(req);
+	if (err == -EINPROGRESS ||
+	    (err == -EBUSY && (ahash_request_flags(req) &
+			       CRYPTO_TFM_REQ_MAY_BACKLOG)))
+		return err;
 
 out:
-	ahash_def_finup_finish2(req, err);
+	ahash_restore_req(req, err);
 	return err;
 }
 
@@ -417,7 +426,16 @@
 {
 	struct ahash_request *areq = req->data;
 
+	if (err == -EINPROGRESS) {
+		ahash_notify_einprogress(areq);
+		return;
+	}
+
+	areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
 	err = ahash_def_finup_finish1(areq, err);
+	if (areq->priv)
+		return;
 
 	areq->base.complete(&areq->base, err);
 }
@@ -432,6 +450,11 @@
 		return err;
 
 	err = tfm->update(req);
+	if (err == -EINPROGRESS ||
+	    (err == -EBUSY && (ahash_request_flags(req) &
+			       CRYPTO_TFM_REQ_MAY_BACKLOG)))
+		return err;
+
 	return ahash_def_finup_finish1(req, err);
 }
 
@@ -451,6 +474,7 @@
 	struct ahash_alg *alg = crypto_ahash_alg(hash);
 
 	hash->setkey = ahash_nosetkey;
+	hash->has_setkey = false;
 	hash->export = ahash_no_export;
 	hash->import = ahash_no_import;
 
@@ -463,8 +487,10 @@
 	hash->finup = alg->finup ?: ahash_def_finup;
 	hash->digest = alg->digest;
 
-	if (alg->setkey)
+	if (alg->setkey) {
 		hash->setkey = alg->setkey;
+		hash->has_setkey = true;
+	}
 	if (alg->export)
 		hash->export = alg->export;
 	if (alg->import)
@@ -612,5 +638,16 @@
 }
 EXPORT_SYMBOL_GPL(ahash_attr_alg);
 
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
+{
+	struct crypto_alg *alg = &halg->base;
+
+	if (alg->cra_type != &crypto_ahash_type)
+		return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
+
+	return __crypto_ahash_alg(alg)->setkey != NULL;
+}
+EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
--- linux-4.4.0.orig/crypto/algapi.c
+++ linux-4.4.0/crypto/algapi.c
@@ -168,6 +168,18 @@
 
 			spawn->alg = NULL;
 			spawns = &inst->alg.cra_users;
+
+			/*
+			 * We may encounter an unregistered instance here, since
+			 * an instance's spawns are set up prior to the instance
+			 * being registered.  An unregistered instance will have
+			 * NULL ->cra_users.next, since ->cra_users isn't
+			 * properly initialized until registration.  But an
+			 * unregistered instance cannot have any users, so treat
+			 * it the same as ->cra_users being empty.
+			 */
+			if (spawns->next == NULL)
+				break;
 		}
 	} while ((spawns = crypto_more_spawns(alg, &stack, &top,
 					      &secondary_spawns)));
@@ -357,6 +369,7 @@
 	struct crypto_larval *larval;
 	int err;
 
+	alg->cra_flags &= ~CRYPTO_ALG_DEAD;
 	err = crypto_check_alg(alg);
 	if (err)
 		return err;
@@ -640,11 +653,9 @@
 
 void crypto_drop_spawn(struct crypto_spawn *spawn)
 {
-	if (!spawn->alg)
-		return;
-
 	down_write(&crypto_alg_sem);
-	list_del(&spawn->list);
+	if (spawn->alg)
+		list_del(&spawn->list);
 	up_write(&crypto_alg_sem);
 }
 EXPORT_SYMBOL_GPL(crypto_drop_spawn);
@@ -652,22 +663,16 @@
 static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
 {
 	struct crypto_alg *alg;
-	struct crypto_alg *alg2;
 
 	down_read(&crypto_alg_sem);
 	alg = spawn->alg;
-	alg2 = alg;
-	if (alg2)
-		alg2 = crypto_mod_get(alg2);
-	up_read(&crypto_alg_sem);
-
-	if (!alg2) {
-		if (alg)
-			crypto_shoot_alg(alg);
-		return ERR_PTR(-EAGAIN);
+	if (alg && !crypto_mod_get(alg)) {
+		alg->cra_flags |= CRYPTO_ALG_DYING;
+		alg = NULL;
 	}
+	up_read(&crypto_alg_sem);
 
-	return alg;
+	return alg ?: ERR_PTR(-EAGAIN);
 }
 
 struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
--- linux-4.4.0.orig/crypto/algboss.c
+++ linux-4.4.0/crypto/algboss.c
@@ -194,8 +194,6 @@
 	if (IS_ERR(thread))
 		goto err_put_larval;
 
-	wait_for_completion_interruptible(&larval->completion);
-
 	return NOTIFY_STOP;
 
 err_put_larval:
--- linux-4.4.0.orig/crypto/algif_aead.c
+++ linux-4.4.0/crypto/algif_aead.c
@@ -29,6 +29,11 @@
 	struct scatterlist sg[ALG_MAX_PAGES];
 };
 
+struct aead_tfm {
+	struct crypto_aead *aead;
+	bool has_key;
+};
+
 struct aead_ctx {
 	struct aead_sg_list tsgl;
 	/*
@@ -46,9 +51,10 @@
 	unsigned long used;
 
 	unsigned int len;
-	bool more;
-	bool merge;
-	bool enc;
+	bool		more:1,
+			merge:1,
+			enc:1,
+			write:1;
 
 	size_t aead_assoclen;
 	struct aead_request aead_req;
@@ -201,6 +207,12 @@
 	}
 
 	lock_sock(sk);
+	if (ctx->write) {
+		release_sock(sk);
+		return -EBUSY;
+	}
+	ctx->write = true;
+
 	if (!ctx->more && ctx->used)
 		goto unlock;
 
@@ -292,6 +304,7 @@
 
 unlock:
 	aead_data_wakeup(sk);
+	ctx->write = false;
 	release_sock(sk);
 
 	return err ?: copied;
@@ -513,24 +526,143 @@
 	.poll		=	aead_poll,
 };
 
+static int aead_check_key(struct socket *sock)
+{
+	int err = 0;
+	struct sock *psk;
+	struct alg_sock *pask;
+	struct aead_tfm *tfm;
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+
+	lock_sock(sk);
+	if (!atomic_read(&ask->nokey_refcnt))
+		goto unlock_child;
+
+	psk = ask->parent;
+	pask = alg_sk(ask->parent);
+	tfm = pask->private;
+
+	err = -ENOKEY;
+	lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+	if (!tfm->has_key)
+		goto unlock;
+
+	atomic_dec(&pask->nokey_refcnt);
+	atomic_set(&ask->nokey_refcnt, 0);
+
+	err = 0;
+
+unlock:
+	release_sock(psk);
+unlock_child:
+	release_sock(sk);
+
+	return err;
+}
+
+static int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+				  size_t size)
+{
+	int err;
+
+	err = aead_check_key(sock);
+	if (err)
+		return err;
+
+	return aead_sendmsg(sock, msg, size);
+}
+
+static ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page,
+				       int offset, size_t size, int flags)
+{
+	int err;
+
+	err = aead_check_key(sock);
+	if (err)
+		return err;
+
+	return aead_sendpage(sock, page, offset, size, flags);
+}
+
+static int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+				  size_t ignored, int flags)
+{
+	int err;
+
+	err = aead_check_key(sock);
+	if (err)
+		return err;
+
+	return aead_recvmsg(sock, msg, ignored, flags);
+}
+
+static struct proto_ops algif_aead_ops_nokey = {
+	.family		=	PF_ALG,
+
+	.connect	=	sock_no_connect,
+	.socketpair	=	sock_no_socketpair,
+	.getname	=	sock_no_getname,
+	.ioctl		=	sock_no_ioctl,
+	.listen		=	sock_no_listen,
+	.shutdown	=	sock_no_shutdown,
+	.getsockopt	=	sock_no_getsockopt,
+	.mmap		=	sock_no_mmap,
+	.bind		=	sock_no_bind,
+	.accept		=	sock_no_accept,
+	.setsockopt	=	sock_no_setsockopt,
+
+	.release	=	af_alg_release,
+	.sendmsg	=	aead_sendmsg_nokey,
+	.sendpage	=	aead_sendpage_nokey,
+	.recvmsg	=	aead_recvmsg_nokey,
+	.poll		=	aead_poll,
+};
+
 static void *aead_bind(const char *name, u32 type, u32 mask)
 {
-	return crypto_alloc_aead(name, type, mask);
+	struct aead_tfm *tfm;
+	struct crypto_aead *aead;
+
+	tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+	if (!tfm)
+		return ERR_PTR(-ENOMEM);
+
+	aead = crypto_alloc_aead(name, type, mask);
+	if (IS_ERR(aead)) {
+		kfree(tfm);
+		return ERR_CAST(aead);
+	}
+
+	tfm->aead = aead;
+
+	return tfm;
 }
 
 static void aead_release(void *private)
 {
-	crypto_free_aead(private);
+	struct aead_tfm *tfm = private;
+
+	crypto_free_aead(tfm->aead);
+	kfree(tfm);
 }
 
 static int aead_setauthsize(void *private, unsigned int authsize)
 {
-	return crypto_aead_setauthsize(private, authsize);
+	struct aead_tfm *tfm = private;
+
+	return crypto_aead_setauthsize(tfm->aead, authsize);
 }
 
 static int aead_setkey(void *private, const u8 *key, unsigned int keylen)
 {
-	return crypto_aead_setkey(private, key, keylen);
+	struct aead_tfm *tfm = private;
+	int err;
+
+	err = crypto_aead_setkey(tfm->aead, key, keylen);
+	tfm->has_key = !err;
+
+	return err;
 }
 
 static void aead_sock_destruct(struct sock *sk)
@@ -546,12 +678,14 @@
 	af_alg_release_parent(sk);
 }
 
-static int aead_accept_parent(void *private, struct sock *sk)
+static int aead_accept_parent_nokey(void *private, struct sock *sk)
 {
 	struct aead_ctx *ctx;
 	struct alg_sock *ask = alg_sk(sk);
-	unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(private);
-	unsigned int ivlen = crypto_aead_ivsize(private);
+	struct aead_tfm *tfm = private;
+	struct crypto_aead *aead = tfm->aead;
+	unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(aead);
+	unsigned int ivlen = crypto_aead_ivsize(aead);
 
 	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
 	if (!ctx)
@@ -566,18 +700,12 @@
 	memset(ctx->iv, 0, ivlen);
 
 	ctx->len = len;
-	ctx->used = 0;
-	ctx->more = 0;
-	ctx->merge = 0;
-	ctx->enc = 0;
-	ctx->tsgl.cur = 0;
-	ctx->aead_assoclen = 0;
 	af_alg_init_completion(&ctx->completion);
 	sg_init_table(ctx->tsgl.sg, ALG_MAX_PAGES);
 
 	ask->private = ctx;
 
-	aead_request_set_tfm(&ctx->aead_req, private);
+	aead_request_set_tfm(&ctx->aead_req, aead);
 	aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
 				  af_alg_complete, &ctx->completion);
 
@@ -586,13 +714,25 @@
 	return 0;
 }
 
+static int aead_accept_parent(void *private, struct sock *sk)
+{
+	struct aead_tfm *tfm = private;
+
+	if (!tfm->has_key)
+		return -ENOKEY;
+
+	return aead_accept_parent_nokey(private, sk);
+}
+
 static const struct af_alg_type algif_type_aead = {
 	.bind		=	aead_bind,
 	.release	=	aead_release,
 	.setkey		=	aead_setkey,
 	.setauthsize	=	aead_setauthsize,
 	.accept		=	aead_accept_parent,
+	.accept_nokey	=	aead_accept_parent_nokey,
 	.ops		=	&algif_aead_ops,
+	.ops_nokey	=	&algif_aead_ops_nokey,
 	.name		=	"aead",
 	.owner		=	THIS_MODULE
 };
--- linux-4.4.0.orig/crypto/algif_hash.c
+++ linux-4.4.0/crypto/algif_hash.c
@@ -34,6 +34,11 @@
 	struct ahash_request req;
 };
 
+struct algif_hash_tfm {
+	struct crypto_ahash *hash;
+	bool has_key;
+};
+
 static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
 			size_t ignored)
 {
@@ -49,7 +54,8 @@
 
 	lock_sock(sk);
 	if (!ctx->more) {
-		err = crypto_ahash_init(&ctx->req);
+		err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req),
+						&ctx->completion);
 		if (err)
 			goto unlock;
 	}
@@ -120,6 +126,7 @@
 	} else {
 		if (!ctx->more) {
 			err = crypto_ahash_init(&ctx->req);
+			err = af_alg_wait_for_completion(err, &ctx->completion);
 			if (err)
 				goto unlock;
 		}
@@ -177,7 +184,7 @@
 	struct alg_sock *ask = alg_sk(sk);
 	struct hash_ctx *ctx = ask->private;
 	struct ahash_request *req = &ctx->req;
-	char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req))];
+	char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req)) ? : 1];
 	struct sock *sk2;
 	struct alg_sock *ask2;
 	struct hash_ctx *ctx2;
@@ -235,19 +242,148 @@
 	.accept		=	hash_accept,
 };
 
+static int hash_check_key(struct socket *sock)
+{
+	int err = 0;
+	struct sock *psk;
+	struct alg_sock *pask;
+	struct algif_hash_tfm *tfm;
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+
+	lock_sock(sk);
+	if (!atomic_read(&ask->nokey_refcnt))
+		goto unlock_child;
+
+	psk = ask->parent;
+	pask = alg_sk(ask->parent);
+	tfm = pask->private;
+
+	err = -ENOKEY;
+	lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+	if (!tfm->has_key)
+		goto unlock;
+
+	atomic_dec(&pask->nokey_refcnt);
+	atomic_set(&ask->nokey_refcnt, 0);
+
+	err = 0;
+
+unlock:
+	release_sock(psk);
+unlock_child:
+	release_sock(sk);
+
+	return err;
+}
+
+static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+			      size_t size)
+{
+	int err;
+
+	err = hash_check_key(sock);
+	if (err)
+		return err;
+
+	return hash_sendmsg(sock, msg, size);
+}
+
+static ssize_t hash_sendpage_nokey(struct socket *sock, struct page *page,
+				   int offset, size_t size, int flags)
+{
+	int err;
+
+	err = hash_check_key(sock);
+	if (err)
+		return err;
+
+	return hash_sendpage(sock, page, offset, size, flags);
+}
+
+static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+			      size_t ignored, int flags)
+{
+	int err;
+
+	err = hash_check_key(sock);
+	if (err)
+		return err;
+
+	return hash_recvmsg(sock, msg, ignored, flags);
+}
+
+static int hash_accept_nokey(struct socket *sock, struct socket *newsock,
+			     int flags)
+{
+	int err;
+
+	err = hash_check_key(sock);
+	if (err)
+		return err;
+
+	return hash_accept(sock, newsock, flags);
+}
+
+static struct proto_ops algif_hash_ops_nokey = {
+	.family		=	PF_ALG,
+
+	.connect	=	sock_no_connect,
+	.socketpair	=	sock_no_socketpair,
+	.getname	=	sock_no_getname,
+	.ioctl		=	sock_no_ioctl,
+	.listen		=	sock_no_listen,
+	.shutdown	=	sock_no_shutdown,
+	.getsockopt	=	sock_no_getsockopt,
+	.mmap		=	sock_no_mmap,
+	.bind		=	sock_no_bind,
+	.setsockopt	=	sock_no_setsockopt,
+	.poll		=	sock_no_poll,
+
+	.release	=	af_alg_release,
+	.sendmsg	=	hash_sendmsg_nokey,
+	.sendpage	=	hash_sendpage_nokey,
+	.recvmsg	=	hash_recvmsg_nokey,
+	.accept		=	hash_accept_nokey,
+};
+
 static void *hash_bind(const char *name, u32 type, u32 mask)
 {
-	return crypto_alloc_ahash(name, type, mask);
+	struct algif_hash_tfm *tfm;
+	struct crypto_ahash *hash;
+
+	tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+	if (!tfm)
+		return ERR_PTR(-ENOMEM);
+
+	hash = crypto_alloc_ahash(name, type, mask);
+	if (IS_ERR(hash)) {
+		kfree(tfm);
+		return ERR_CAST(hash);
+	}
+
+	tfm->hash = hash;
+
+	return tfm;
 }
 
 static void hash_release(void *private)
 {
-	crypto_free_ahash(private);
+	struct algif_hash_tfm *tfm = private;
+
+	crypto_free_ahash(tfm->hash);
+	kfree(tfm);
 }
 
 static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
 {
-	return crypto_ahash_setkey(private, key, keylen);
+	struct algif_hash_tfm *tfm = private;
+	int err;
+
+	err = crypto_ahash_setkey(tfm->hash, key, keylen);
+	tfm->has_key = !err;
+
+	return err;
 }
 
 static void hash_sock_destruct(struct sock *sk)
@@ -261,12 +397,14 @@
 	af_alg_release_parent(sk);
 }
 
-static int hash_accept_parent(void *private, struct sock *sk)
+static int hash_accept_parent_nokey(void *private, struct sock *sk)
 {
 	struct hash_ctx *ctx;
 	struct alg_sock *ask = alg_sk(sk);
-	unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(private);
-	unsigned ds = crypto_ahash_digestsize(private);
+	struct algif_hash_tfm *tfm = private;
+	struct crypto_ahash *hash = tfm->hash;
+	unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash);
+	unsigned ds = crypto_ahash_digestsize(hash);
 
 	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
 	if (!ctx)
@@ -286,7 +424,7 @@
 
 	ask->private = ctx;
 
-	ahash_request_set_tfm(&ctx->req, private);
+	ahash_request_set_tfm(&ctx->req, hash);
 	ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
 				   af_alg_complete, &ctx->completion);
 
@@ -295,12 +433,24 @@
 	return 0;
 }
 
+static int hash_accept_parent(void *private, struct sock *sk)
+{
+	struct algif_hash_tfm *tfm = private;
+
+	if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash))
+		return -ENOKEY;
+
+	return hash_accept_parent_nokey(private, sk);
+}
+
 static const struct af_alg_type algif_type_hash = {
 	.bind		=	hash_bind,
 	.release	=	hash_release,
 	.setkey		=	hash_setkey,
 	.accept		=	hash_accept_parent,
+	.accept_nokey	=	hash_accept_parent_nokey,
 	.ops		=	&algif_hash_ops,
+	.ops_nokey	=	&algif_hash_ops_nokey,
 	.name		=	"hash",
 	.owner		=	THIS_MODULE
 };
--- linux-4.4.0.orig/crypto/algif_skcipher.c
+++ linux-4.4.0/crypto/algif_skcipher.c
@@ -31,6 +31,11 @@
 	struct scatterlist sg[0];
 };
 
+struct skcipher_tfm {
+	struct crypto_skcipher *skcipher;
+	bool has_key;
+};
+
 struct skcipher_ctx {
 	struct list_head tsgl;
 	struct af_alg_sgl rsgl;
@@ -43,9 +48,10 @@
 	unsigned used;
 
 	unsigned int len;
-	bool more;
-	bool merge;
-	bool enc;
+	bool		more:1,
+			merge:1,
+			enc:1,
+			write:1;
 
 	struct skcipher_request req;
 };
@@ -60,18 +66,10 @@
 	struct skcipher_async_rsgl first_sgl;
 	struct list_head list;
 	struct scatterlist *tsg;
-	char iv[];
+	atomic_t *inflight;
+	struct skcipher_request req;
 };
 
-#define GET_SREQ(areq, ctx) (struct skcipher_async_req *)((char *)areq + \
-	crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req)))
-
-#define GET_REQ_SIZE(ctx) \
-	crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req))
-
-#define GET_IV_SIZE(ctx) \
-	crypto_skcipher_ivsize(crypto_skcipher_reqtfm(&ctx->req))
-
 #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \
 		      sizeof(struct scatterlist) - 1)
 
@@ -89,23 +87,25 @@
 	}
 	sgl = sreq->tsg;
 	n = sg_nents(sgl);
-	for_each_sg(sgl, sg, n, i)
-		put_page(sg_page(sg));
+	for_each_sg(sgl, sg, n, i) {
+		struct page *page = sg_page(sg);
+
+		/* some SGs may not have a page mapped */
+		if (page && atomic_read(&page->_count))
+			put_page(page);
+	}
 
 	kfree(sreq->tsg);
 }
 
 static void skcipher_async_cb(struct crypto_async_request *req, int err)
 {
-	struct sock *sk = req->data;
-	struct alg_sock *ask = alg_sk(sk);
-	struct skcipher_ctx *ctx = ask->private;
-	struct skcipher_async_req *sreq = GET_SREQ(req, ctx);
+	struct skcipher_async_req *sreq = req->data;
 	struct kiocb *iocb = sreq->iocb;
 
-	atomic_dec(&ctx->inflight);
+	atomic_dec(sreq->inflight);
 	skcipher_free_async_sgls(sreq);
-	kfree(req);
+	kzfree(sreq);
 	iocb->ki_complete(iocb, err, err);
 }
 
@@ -144,8 +144,10 @@
 		sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
 		sgl->cur = 0;
 
-		if (sg)
+		if (sg) {
 			sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
+			sg_unmark_end(sg + (MAX_SGL_ENTS - 1));
+		}
 
 		list_add_tail(&sgl->list, &ctx->tsgl);
 	}
@@ -301,8 +303,11 @@
 {
 	struct sock *sk = sock->sk;
 	struct alg_sock *ask = alg_sk(sk);
+	struct sock *psk = ask->parent;
+	struct alg_sock *pask = alg_sk(psk);
 	struct skcipher_ctx *ctx = ask->private;
-	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req);
+	struct skcipher_tfm *skc = pask->private;
+	struct crypto_skcipher *tfm = skc->skcipher;
 	unsigned ivsize = crypto_skcipher_ivsize(tfm);
 	struct skcipher_sg_list *sgl;
 	struct af_alg_control con = {};
@@ -336,6 +341,12 @@
 	err = -EINVAL;
 
 	lock_sock(sk);
+	if (ctx->write) {
+		release_sock(sk);
+		return -EBUSY;
+	}
+	ctx->write = true;
+
 	if (!ctx->more && ctx->used)
 		goto unlock;
 
@@ -387,7 +398,8 @@
 
 		sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list);
 		sg = sgl->sg;
-		sg_unmark_end(sg + sgl->cur);
+		if (sgl->cur)
+			sg_unmark_end(sg + sgl->cur - 1);
 		do {
 			i = sgl->cur;
 			plen = min_t(int, len, PAGE_SIZE);
@@ -425,6 +437,7 @@
 
 unlock:
 	skcipher_data_wakeup(sk);
+	ctx->write = false;
 	release_sock(sk);
 
 	return copied ?: err;
@@ -503,37 +516,43 @@
 {
 	struct sock *sk = sock->sk;
 	struct alg_sock *ask = alg_sk(sk);
+	struct sock *psk = ask->parent;
+	struct alg_sock *pask = alg_sk(psk);
 	struct skcipher_ctx *ctx = ask->private;
+	struct skcipher_tfm *skc = pask->private;
+	struct crypto_skcipher *tfm = skc->skcipher;
 	struct skcipher_sg_list *sgl;
 	struct scatterlist *sg;
 	struct skcipher_async_req *sreq;
 	struct skcipher_request *req;
 	struct skcipher_async_rsgl *last_rsgl = NULL;
-	unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx);
-	unsigned int reqlen = sizeof(struct skcipher_async_req) +
-				GET_REQ_SIZE(ctx) + GET_IV_SIZE(ctx);
+	unsigned int txbufs = 0, len = 0, tx_nents;
+	unsigned int reqsize = crypto_skcipher_reqsize(tfm);
+	unsigned int ivsize = crypto_skcipher_ivsize(tfm);
 	int err = -ENOMEM;
 	bool mark = false;
+	char *iv;
 
-	lock_sock(sk);
-	req = kmalloc(reqlen, GFP_KERNEL);
-	if (unlikely(!req))
-		goto unlock;
+	sreq = kzalloc(sizeof(*sreq) + reqsize + ivsize, GFP_KERNEL);
+	if (unlikely(!sreq))
+		goto out;
 
-	sreq = GET_SREQ(req, ctx);
+	req = &sreq->req;
+	iv = (char *)(req + 1) + reqsize;
 	sreq->iocb = msg->msg_iocb;
-	memset(&sreq->first_sgl, '\0', sizeof(struct skcipher_async_rsgl));
 	INIT_LIST_HEAD(&sreq->list);
+	sreq->inflight = &ctx->inflight;
+
+	lock_sock(sk);
+	tx_nents = skcipher_all_sg_nents(ctx);
 	sreq->tsg = kcalloc(tx_nents, sizeof(*sg), GFP_KERNEL);
-	if (unlikely(!sreq->tsg)) {
-		kfree(req);
+	if (unlikely(ZERO_OR_NULL_PTR(sreq->tsg)))
 		goto unlock;
-	}
 	sg_init_table(sreq->tsg, tx_nents);
-	memcpy(sreq->iv, ctx->iv, GET_IV_SIZE(ctx));
-	skcipher_request_set_tfm(req, crypto_skcipher_reqtfm(&ctx->req));
-	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-				      skcipher_async_cb, sk);
+	memcpy(iv, ctx->iv, ivsize);
+	skcipher_request_set_tfm(req, tfm);
+	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
+				      skcipher_async_cb, sreq);
 
 	while (iov_iter_count(&msg->msg_iter)) {
 		struct skcipher_async_rsgl *rsgl;
@@ -609,20 +628,22 @@
 		sg_mark_end(sreq->tsg + txbufs - 1);
 
 	skcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg,
-				   len, sreq->iv);
+				   len, iv);
 	err = ctx->enc ? crypto_skcipher_encrypt(req) :
 			 crypto_skcipher_decrypt(req);
 	if (err == -EINPROGRESS) {
 		atomic_inc(&ctx->inflight);
 		err = -EIOCBQUEUED;
+		sreq = NULL;
 		goto unlock;
 	}
 free:
 	skcipher_free_async_sgls(sreq);
-	kfree(req);
 unlock:
 	skcipher_wmem_wakeup(sk);
 	release_sock(sk);
+	kzfree(sreq);
+out:
 	return err;
 }
 
@@ -631,9 +652,12 @@
 {
 	struct sock *sk = sock->sk;
 	struct alg_sock *ask = alg_sk(sk);
+	struct sock *psk = ask->parent;
+	struct alg_sock *pask = alg_sk(psk);
 	struct skcipher_ctx *ctx = ask->private;
-	unsigned bs = crypto_skcipher_blocksize(crypto_skcipher_reqtfm(
-		&ctx->req));
+	struct skcipher_tfm *skc = pask->private;
+	struct crypto_skcipher *tfm = skc->skcipher;
+	unsigned bs = crypto_skcipher_blocksize(tfm);
 	struct skcipher_sg_list *sgl;
 	struct scatterlist *sg;
 	int err = -EAGAIN;
@@ -642,13 +666,6 @@
 
 	lock_sock(sk);
 	while (msg_data_left(msg)) {
-		sgl = list_first_entry(&ctx->tsgl,
-				       struct skcipher_sg_list, list);
-		sg = sgl->sg;
-
-		while (!sg->length)
-			sg++;
-
 		if (!ctx->used) {
 			err = skcipher_wait_for_data(sk, flags);
 			if (err)
@@ -669,6 +686,13 @@
 		if (!used)
 			goto free;
 
+		sgl = list_first_entry(&ctx->tsgl,
+				       struct skcipher_sg_list, list);
+		sg = sgl->sg;
+
+		while (!sg->length)
+			sg++;
+
 		skcipher_request_set_crypt(&ctx->req, sg, ctx->rsgl.sg, used,
 					   ctx->iv);
 
@@ -748,19 +772,136 @@
 	.poll		=	skcipher_poll,
 };
 
+static int skcipher_check_key(struct socket *sock)
+{
+	int err = 0;
+	struct sock *psk;
+	struct alg_sock *pask;
+	struct skcipher_tfm *tfm;
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+
+	lock_sock(sk);
+	if (!atomic_read(&ask->nokey_refcnt))
+		goto unlock_child;
+
+	psk = ask->parent;
+	pask = alg_sk(ask->parent);
+	tfm = pask->private;
+
+	err = -ENOKEY;
+	lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+	if (!tfm->has_key)
+		goto unlock;
+
+	atomic_dec(&pask->nokey_refcnt);
+	atomic_set(&ask->nokey_refcnt, 0);
+
+	err = 0;
+
+unlock:
+	release_sock(psk);
+unlock_child:
+	release_sock(sk);
+
+	return err;
+}
+
+static int skcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+				  size_t size)
+{
+	int err;
+
+	err = skcipher_check_key(sock);
+	if (err)
+		return err;
+
+	return skcipher_sendmsg(sock, msg, size);
+}
+
+static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page,
+				       int offset, size_t size, int flags)
+{
+	int err;
+
+	err = skcipher_check_key(sock);
+	if (err)
+		return err;
+
+	return skcipher_sendpage(sock, page, offset, size, flags);
+}
+
+static int skcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+				  size_t ignored, int flags)
+{
+	int err;
+
+	err = skcipher_check_key(sock);
+	if (err)
+		return err;
+
+	return skcipher_recvmsg(sock, msg, ignored, flags);
+}
+
+static struct proto_ops algif_skcipher_ops_nokey = {
+	.family		=	PF_ALG,
+
+	.connect	=	sock_no_connect,
+	.socketpair	=	sock_no_socketpair,
+	.getname	=	sock_no_getname,
+	.ioctl		=	sock_no_ioctl,
+	.listen		=	sock_no_listen,
+	.shutdown	=	sock_no_shutdown,
+	.getsockopt	=	sock_no_getsockopt,
+	.mmap		=	sock_no_mmap,
+	.bind		=	sock_no_bind,
+	.accept		=	sock_no_accept,
+	.setsockopt	=	sock_no_setsockopt,
+
+	.release	=	af_alg_release,
+	.sendmsg	=	skcipher_sendmsg_nokey,
+	.sendpage	=	skcipher_sendpage_nokey,
+	.recvmsg	=	skcipher_recvmsg_nokey,
+	.poll		=	skcipher_poll,
+};
+
 static void *skcipher_bind(const char *name, u32 type, u32 mask)
 {
-	return crypto_alloc_skcipher(name, type, mask);
+	struct skcipher_tfm *tfm;
+	struct crypto_skcipher *skcipher;
+
+	tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+	if (!tfm)
+		return ERR_PTR(-ENOMEM);
+
+	skcipher = crypto_alloc_skcipher(name, type, mask);
+	if (IS_ERR(skcipher)) {
+		kfree(tfm);
+		return ERR_CAST(skcipher);
+	}
+
+	tfm->skcipher = skcipher;
+
+	return tfm;
 }
 
 static void skcipher_release(void *private)
 {
-	crypto_free_skcipher(private);
+	struct skcipher_tfm *tfm = private;
+
+	crypto_free_skcipher(tfm->skcipher);
+	kfree(tfm);
 }
 
 static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
 {
-	return crypto_skcipher_setkey(private, key, keylen);
+	struct skcipher_tfm *tfm = private;
+	int err;
+
+	err = crypto_skcipher_setkey(tfm->skcipher, key, keylen);
+	tfm->has_key = !err;
+
+	return err;
 }
 
 static void skcipher_wait(struct sock *sk)
@@ -788,38 +929,36 @@
 	af_alg_release_parent(sk);
 }
 
-static int skcipher_accept_parent(void *private, struct sock *sk)
+static int skcipher_accept_parent_nokey(void *private, struct sock *sk)
 {
 	struct skcipher_ctx *ctx;
 	struct alg_sock *ask = alg_sk(sk);
-	unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(private);
+	struct skcipher_tfm *tfm = private;
+	struct crypto_skcipher *skcipher = tfm->skcipher;
+	unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(skcipher);
 
 	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
+	memset(ctx, 0, len);
 
-	ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(private),
+	ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(skcipher),
 			       GFP_KERNEL);
 	if (!ctx->iv) {
 		sock_kfree_s(sk, ctx, len);
 		return -ENOMEM;
 	}
-
-	memset(ctx->iv, 0, crypto_skcipher_ivsize(private));
+	memset(ctx->iv, 0, crypto_skcipher_ivsize(skcipher));
 
 	INIT_LIST_HEAD(&ctx->tsgl);
 	ctx->len = len;
-	ctx->used = 0;
-	ctx->more = 0;
-	ctx->merge = 0;
-	ctx->enc = 0;
-	atomic_set(&ctx->inflight, 0);
 	af_alg_init_completion(&ctx->completion);
 
 	ask->private = ctx;
 
-	skcipher_request_set_tfm(&ctx->req, private);
-	skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+	skcipher_request_set_tfm(&ctx->req, skcipher);
+	skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_SLEEP |
+						 CRYPTO_TFM_REQ_MAY_BACKLOG,
 				      af_alg_complete, &ctx->completion);
 
 	sk->sk_destruct = skcipher_sock_destruct;
@@ -827,12 +966,24 @@
 	return 0;
 }
 
+static int skcipher_accept_parent(void *private, struct sock *sk)
+{
+	struct skcipher_tfm *tfm = private;
+
+	if (!tfm->has_key && crypto_skcipher_has_setkey(tfm->skcipher))
+		return -ENOKEY;
+
+	return skcipher_accept_parent_nokey(private, sk);
+}
+
 static const struct af_alg_type algif_type_skcipher = {
 	.bind		=	skcipher_bind,
 	.release	=	skcipher_release,
 	.setkey		=	skcipher_setkey,
 	.accept		=	skcipher_accept_parent,
+	.accept_nokey	=	skcipher_accept_parent_nokey,
 	.ops		=	&algif_skcipher_ops,
+	.ops_nokey	=	&algif_skcipher_ops_nokey,
 	.name		=	"skcipher",
 	.owner		=	THIS_MODULE
 };
--- linux-4.4.0.orig/crypto/api.c
+++ linux-4.4.0/crypto/api.c
@@ -355,13 +355,12 @@
 	return len;
 }
 
-void crypto_shoot_alg(struct crypto_alg *alg)
+static void crypto_shoot_alg(struct crypto_alg *alg)
 {
 	down_write(&crypto_alg_sem);
 	alg->cra_flags |= CRYPTO_ALG_DYING;
 	up_write(&crypto_alg_sem);
 }
-EXPORT_SYMBOL_GPL(crypto_shoot_alg);
 
 struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
 				      u32 mask)
--- linux-4.4.0.orig/crypto/asymmetric_keys/Kconfig
+++ linux-4.4.0/crypto/asymmetric_keys/Kconfig
@@ -14,6 +14,7 @@
 	select MPILIB
 	select PUBLIC_KEY_ALGO_RSA
 	select CRYPTO_HASH_INFO
+	select CRYPTO_AKCIPHER
 	help
 	  This option provides support for asymmetric public key type handling.
 	  If signature generation and/or verification are to be used,
@@ -22,7 +23,7 @@
 
 config PUBLIC_KEY_ALGO_RSA
 	tristate "RSA public-key algorithm"
-	select MPILIB
+	select CRYPTO_RSA
 	help
 	  This option enables support for the RSA algorithm (PKCS#1, RFC3447).
 
@@ -67,4 +68,12 @@
 	  This option provides support for verifying the signature(s) on a
 	  signed PE binary.
 
+config EFI_SIGNATURE_LIST_PARSER
+	bool "EFI signature list parser"
+	depends on EFI
+	select X509_CERTIFICATE_PARSER
+	help
+	  This option provides support for parsing EFI signature lists for
+	  X.509 certificates and turning them into keys.
+
 endif # ASYMMETRIC_KEY_TYPE
--- linux-4.4.0.orig/crypto/asymmetric_keys/Makefile
+++ linux-4.4.0/crypto/asymmetric_keys/Makefile
@@ -8,6 +8,7 @@
 
 obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
 obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
+obj-$(CONFIG_EFI_SIGNATURE_LIST_PARSER) += efi_parser.o
 
 #
 # X.509 Certificate handling
@@ -16,21 +17,18 @@
 x509_key_parser-y := \
 	x509-asn1.o \
 	x509_akid-asn1.o \
-	x509_rsakey-asn1.o \
 	x509_cert_parser.o \
 	x509_public_key.o
 
 $(obj)/x509_cert_parser.o: \
 	$(obj)/x509-asn1.h \
-	$(obj)/x509_akid-asn1.h \
-	$(obj)/x509_rsakey-asn1.h
+	$(obj)/x509_akid-asn1.h
+
 $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
 $(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h
-$(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
 
 clean-files	+= x509-asn1.c x509-asn1.h
 clean-files	+= x509_akid-asn1.c x509_akid-asn1.h
-clean-files	+= x509_rsakey-asn1.c x509_rsakey-asn1.h
 
 #
 # PKCS#7 message handling
--- linux-4.4.0.orig/crypto/asymmetric_keys/efi_parser.c
+++ linux-4.4.0/crypto/asymmetric_keys/efi_parser.c
@@ -0,0 +1,109 @@
+/* EFI signature/key/certificate list parser
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "EFI: "fmt
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/err.h>
+#include <linux/efi.h>
+#include <keys/asymmetric-type.h>
+
+static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID;
+
+/**
+ * parse_efi_signature_list - Parse an EFI signature list for certificates
+ * @data: The data blob to parse
+ * @size: The size of the data blob
+ * @keyring: The keyring to add extracted keys to
+ */
+int __init parse_efi_signature_list(const void *data, size_t size, struct key *keyring)
+{
+	unsigned offs = 0;
+	size_t lsize, esize, hsize, elsize;
+
+	pr_devel("-->%s(,%zu)\n", __func__, size);
+
+	while (size > 0) {
+		efi_signature_list_t list;
+		const efi_signature_data_t *elem;
+		key_ref_t key;
+
+		if (size < sizeof(list))
+			return -EBADMSG;
+
+		memcpy(&list, data, sizeof(list));
+		pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
+			 offs,
+			 list.signature_type.b, list.signature_list_size,
+			 list.signature_header_size, list.signature_size);
+
+		lsize = list.signature_list_size;
+		hsize = list.signature_header_size;
+		esize = list.signature_size;
+		elsize = lsize - sizeof(list) - hsize;
+
+		if (lsize > size) {
+			pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
+				 __func__, offs);
+			return -EBADMSG;
+		}
+		if (lsize < sizeof(list) ||
+		    lsize - sizeof(list) < hsize ||
+		    esize < sizeof(*elem) ||
+		    elsize < esize ||
+		    elsize % esize != 0) {
+			pr_devel("- bad size combo @%x\n", offs);
+			return -EBADMSG;
+		}
+
+		if (efi_guidcmp(list.signature_type, efi_cert_x509_guid) != 0) {
+			data += lsize;
+			size -= lsize;
+			offs += lsize;
+			continue;
+		}
+
+		data += sizeof(list) + hsize;
+		size -= sizeof(list) + hsize;
+		offs += sizeof(list) + hsize;
+
+		for (; elsize > 0; elsize -= esize) {
+			elem = data;
+
+			pr_devel("ELEM[%04x]\n", offs);
+
+			key = key_create_or_update(
+				make_key_ref(keyring, 1),
+				"asymmetric",
+				NULL,
+				&elem->signature_data,
+				esize - sizeof(*elem),
+				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
+				KEY_USR_VIEW,
+				KEY_ALLOC_NOT_IN_QUOTA |
+				KEY_ALLOC_TRUSTED);
+
+			if (IS_ERR(key))
+				pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
+				       PTR_ERR(key));
+			else
+				pr_notice("Loaded cert '%s' linked to '%s'\n",
+					  key_ref_to_ptr(key)->description,
+					  keyring->description);
+
+			data += esize;
+			size -= esize;
+			offs += esize;
+		}
+	}
+
+	return 0;
+}
--- linux-4.4.0.orig/crypto/asymmetric_keys/pkcs7_parser.c
+++ linux-4.4.0/crypto/asymmetric_keys/pkcs7_parser.c
@@ -15,7 +15,7 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/oid_registry.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
 #include "pkcs7_parser.h"
 #include "pkcs7-asn1.h"
 
@@ -44,7 +44,7 @@
 static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
 {
 	if (sinfo) {
-		mpi_free(sinfo->sig.mpi[0]);
+		kfree(sinfo->sig.s);
 		kfree(sinfo->sig.digest);
 		kfree(sinfo->signing_cert_id);
 		kfree(sinfo);
@@ -87,9 +87,12 @@
 static int pkcs7_check_authattrs(struct pkcs7_message *msg)
 {
 	struct pkcs7_signed_info *sinfo;
-	bool want;
+	bool want = false;
 
 	sinfo = msg->signed_infos;
+	if (!sinfo)
+		goto inconsistent;
+
 	if (sinfo->authattrs) {
 		want = true;
 		msg->have_authattrs = true;
@@ -547,9 +550,7 @@
 	struct pkcs7_signed_info *sinfo = ctx->sinfo;
 
 	if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
-	    !test_bit(sinfo_has_message_digest, &sinfo->aa_set) ||
-	    (ctx->msg->data_type == OID_msIndirectData &&
-	     !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) {
+	    !test_bit(sinfo_has_message_digest, &sinfo->aa_set)) {
 		pr_warn("Missing required AuthAttr\n");
 		return -EBADMSG;
 	}
@@ -616,16 +617,14 @@
 			     const void *value, size_t vlen)
 {
 	struct pkcs7_parse_context *ctx = context;
-	MPI mpi;
 
 	BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA);
 
-	mpi = mpi_read_raw_data(value, vlen);
-	if (!mpi)
+	ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL);
+	if (!ctx->sinfo->sig.s)
 		return -ENOMEM;
 
-	ctx->sinfo->sig.mpi[0] = mpi;
-	ctx->sinfo->sig.nr_mpi = 1;
+	ctx->sinfo->sig.s_size = vlen;
 	return 0;
 }
 
--- linux-4.4.0.orig/crypto/asymmetric_keys/pkcs7_trust.c
+++ linux-4.4.0/crypto/asymmetric_keys/pkcs7_trust.c
@@ -17,7 +17,7 @@
 #include <linux/asn1.h>
 #include <linux/key.h>
 #include <keys/asymmetric-type.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
 #include "pkcs7_parser.h"
 
 /**
@@ -178,6 +178,8 @@
 	int cached_ret = -ENOKEY;
 	int ret;
 
+	*_trusted = false;
+
 	for (p = pkcs7->certs; p; p = p->next)
 		p->seen = false;
 
--- linux-4.4.0.orig/crypto/asymmetric_keys/pkcs7_verify.c
+++ linux-4.4.0/crypto/asymmetric_keys/pkcs7_verify.c
@@ -16,7 +16,7 @@
 #include <linux/err.h>
 #include <linux/asn1.h>
 #include <crypto/hash.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
 #include "pkcs7_parser.h"
 
 /*
--- linux-4.4.0.orig/crypto/asymmetric_keys/public_key.c
+++ linux-4.4.0/crypto/asymmetric_keys/public_key.c
@@ -18,24 +18,16 @@
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <keys/asymmetric-subtype.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
 
 MODULE_LICENSE("GPL");
 
 const char *const pkey_algo_name[PKEY_ALGO__LAST] = {
-	[PKEY_ALGO_DSA]		= "DSA",
-	[PKEY_ALGO_RSA]		= "RSA",
+	[PKEY_ALGO_DSA]		= "dsa",
+	[PKEY_ALGO_RSA]		= "rsa",
 };
 EXPORT_SYMBOL_GPL(pkey_algo_name);
 
-const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST] = {
-#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
-	defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
-	[PKEY_ALGO_RSA]		= &RSA_public_key_algorithm,
-#endif
-};
-EXPORT_SYMBOL_GPL(pkey_algo);
-
 const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
 	[PKEY_ID_PGP]		= "PGP",
 	[PKEY_ID_X509]		= "X509",
@@ -43,6 +35,12 @@
 };
 EXPORT_SYMBOL_GPL(pkey_id_type_name);
 
+static int (*alg_verify[PKEY_ALGO__LAST])(const struct public_key *pkey,
+	const struct public_key_signature *sig) = {
+	NULL,
+	rsa_verify_signature
+};
+
 /*
  * Provide a part of a description of the key for /proc/keys.
  */
@@ -53,7 +51,8 @@
 
 	if (key)
 		seq_printf(m, "%s.%s",
-			   pkey_id_type_name[key->id_type], key->algo->name);
+			   pkey_id_type_name[key->id_type],
+			   pkey_algo_name[key->pkey_algo]);
 }
 
 /*
@@ -62,50 +61,31 @@
 void public_key_destroy(void *payload)
 {
 	struct public_key *key = payload;
-	int i;
 
-	if (key) {
-		for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
-			mpi_free(key->mpi[i]);
-		kfree(key);
-	}
+	if (key)
+		kfree(key->key);
+	kfree(key);
 }
 EXPORT_SYMBOL_GPL(public_key_destroy);
 
 /*
  * Verify a signature using a public key.
  */
-int public_key_verify_signature(const struct public_key *pk,
+int public_key_verify_signature(const struct public_key *pkey,
 				const struct public_key_signature *sig)
 {
-	const struct public_key_algorithm *algo;
-
-	BUG_ON(!pk);
-	BUG_ON(!pk->mpi[0]);
-	BUG_ON(!pk->mpi[1]);
+	BUG_ON(!pkey);
 	BUG_ON(!sig);
 	BUG_ON(!sig->digest);
-	BUG_ON(!sig->mpi[0]);
+	BUG_ON(!sig->s);
+
+	if (pkey->pkey_algo >= PKEY_ALGO__LAST)
+		return -ENOPKG;
 
-	algo = pk->algo;
-	if (!algo) {
-		if (pk->pkey_algo >= PKEY_ALGO__LAST)
-			return -ENOPKG;
-		algo = pkey_algo[pk->pkey_algo];
-		if (!algo)
-			return -ENOPKG;
-	}
-
-	if (!algo->verify_signature)
-		return -ENOTSUPP;
-
-	if (sig->nr_mpi != algo->n_sig_mpi) {
-		pr_debug("Signature has %u MPI not %u\n",
-			 sig->nr_mpi, algo->n_sig_mpi);
-		return -EINVAL;
-	}
+	if (!alg_verify[pkey->pkey_algo])
+		return -ENOPKG;
 
-	return algo->verify_signature(pk, sig);
+	return alg_verify[pkey->pkey_algo](pkey, sig);
 }
 EXPORT_SYMBOL_GPL(public_key_verify_signature);
 
--- linux-4.4.0.orig/crypto/asymmetric_keys/rsa.c
+++ linux-4.4.0/crypto/asymmetric_keys/rsa.c
@@ -11,10 +11,10 @@
 
 #define pr_fmt(fmt) "RSA: "fmt
 #include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/slab.h>
+#include <crypto/akcipher.h>
+#include <crypto/public_key.h>
 #include <crypto/algapi.h>
-#include "public_key.h"
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("RSA Public Key Algorithm");
@@ -84,72 +84,10 @@
 #undef _
 };
 
-/*
- * RSAVP1() function [RFC3447 sec 5.2.2]
- */
-static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
-{
-	MPI m;
-	int ret;
-
-	/* (1) Validate 0 <= s < n */
-	if (mpi_cmp_ui(s, 0) < 0) {
-		kleave(" = -EBADMSG [s < 0]");
-		return -EBADMSG;
-	}
-	if (mpi_cmp(s, key->rsa.n) >= 0) {
-		kleave(" = -EBADMSG [s >= n]");
-		return -EBADMSG;
-	}
-
-	m = mpi_alloc(0);
-	if (!m)
-		return -ENOMEM;
-
-	/* (2) m = s^e mod n */
-	ret = mpi_powm(m, s, key->rsa.e, key->rsa.n);
-	if (ret < 0) {
-		mpi_free(m);
-		return ret;
-	}
-
-	*_m = m;
-	return 0;
-}
-
-/*
- * Integer to Octet String conversion [RFC3447 sec 4.1]
- */
-static int RSA_I2OSP(MPI x, size_t xLen, u8 **pX)
-{
-	unsigned X_size, x_size;
-	int X_sign;
-	u8 *X;
-
-	/* Make sure the string is the right length.  The number should begin
-	 * with { 0x00, 0x01, ... } so we have to account for 15 leading zero
-	 * bits not being reported by MPI.
-	 */
-	x_size = mpi_get_nbits(x);
-	pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8);
-	if (x_size != xLen * 8 - 15)
-		return -ERANGE;
-
-	X = mpi_get_buffer(x, &X_size, &X_sign);
-	if (!X)
-		return -ENOMEM;
-	if (X_sign < 0) {
-		kfree(X);
-		return -EBADMSG;
-	}
-	if (X_size != xLen - 1) {
-		kfree(X);
-		return -EBADMSG;
-	}
-
-	*pX = X;
-	return 0;
-}
+struct rsa_completion {
+	struct completion completion;
+	int err;
+};
 
 /*
  * Perform the RSA signature verification.
@@ -160,7 +98,7 @@
  * @asn1_template: The DigestInfo ASN.1 template
  * @asn1_size: Size of asm1_template[]
  */
-static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
+static int rsa_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
 		      const u8 *asn1_template, size_t asn1_size)
 {
 	unsigned PS_end, T_offset, i;
@@ -170,9 +108,11 @@
 	if (k < 2 + 1 + asn1_size + hash_size)
 		return -EBADMSG;
 
-	/* Decode the EMSA-PKCS1-v1_5 */
-	if (EM[1] != 0x01) {
-		kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]);
+	/* Decode the EMSA-PKCS1-v1_5
+	 * note: leading zeros are stripped by the RSA implementation
+	 */
+	if (EM[0] != 0x01) {
+		kleave(" = -EBADMSG [EM[0] == %02u]", EM[0]);
 		return -EBADMSG;
 	}
 
@@ -183,7 +123,7 @@
 		return -EBADMSG;
 	}
 
-	for (i = 2; i < PS_end; i++) {
+	for (i = 1; i < PS_end; i++) {
 		if (EM[i] != 0xff) {
 			kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]);
 			return -EBADMSG;
@@ -204,75 +144,81 @@
 	return 0;
 }
 
-/*
- * Perform the verification step [RFC3447 sec 8.2.2].
- */
-static int RSA_verify_signature(const struct public_key *key,
-				const struct public_key_signature *sig)
+static void public_key_verify_done(struct crypto_async_request *req, int err)
 {
-	size_t tsize;
-	int ret;
+	struct rsa_completion *compl = req->data;
 
-	/* Variables as per RFC3447 sec 8.2.2 */
-	const u8 *H = sig->digest;
-	u8 *EM = NULL;
-	MPI m = NULL;
-	size_t k;
-
-	kenter("");
-
-	if (!RSA_ASN1_templates[sig->pkey_hash_algo].data)
-		return -ENOTSUPP;
-
-	/* (1) Check the signature size against the public key modulus size */
-	k = mpi_get_nbits(key->rsa.n);
-	tsize = mpi_get_nbits(sig->rsa.s);
-
-	/* According to RFC 4880 sec 3.2, length of MPI is computed starting
-	 * from most significant bit.  So the RFC 3447 sec 8.2.2 size check
-	 * must be relaxed to conform with shorter signatures - so we fail here
-	 * only if signature length is longer than modulus size.
-	 */
-	pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize);
-	if (k < tsize) {
-		ret = -EBADMSG;
-		goto error;
+	if (err == -EINPROGRESS)
+		return;
+
+	compl->err = err;
+	complete(&compl->completion);
+}
+
+int rsa_verify_signature(const struct public_key *pkey,
+			 const struct public_key_signature *sig)
+{
+	struct crypto_akcipher *tfm;
+	struct akcipher_request *req;
+	struct rsa_completion compl;
+	struct scatterlist sig_sg, sg_out;
+	void *outbuf = NULL;
+	unsigned int outlen = 0;
+	int ret = -ENOMEM;
+
+	tfm = crypto_alloc_akcipher("rsa", 0, 0);
+	if (IS_ERR(tfm))
+		goto error_out;
+
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		goto error_free_tfm;
+
+	ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
+	if (ret)
+		goto error_free_req;
+
+	ret = -EINVAL;
+	outlen = crypto_akcipher_maxsize(tfm);
+	if (!outlen)
+		goto error_free_req;
+
+	/* Initialize the output buffer */
+	ret = -ENOMEM;
+	outbuf = kmalloc(outlen, GFP_KERNEL);
+	if (!outbuf)
+		goto error_free_req;
+
+	sg_init_one(&sig_sg, sig->s, sig->s_size);
+	sg_init_one(&sg_out, outbuf, outlen);
+	akcipher_request_set_crypt(req, &sig_sg, &sg_out, sig->s_size, outlen);
+	init_completion(&compl.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+				      CRYPTO_TFM_REQ_MAY_SLEEP,
+				      public_key_verify_done, &compl);
+
+	ret = crypto_akcipher_verify(req);
+	if (ret == -EINPROGRESS) {
+		wait_for_completion(&compl.completion);
+		ret = compl.err;
 	}
 
-	/* Round up and convert to octets */
-	k = (k + 7) / 8;
+	if (ret)
+		goto error_free_req;
 
-	/* (2b) Apply the RSAVP1 verification primitive to the public key */
-	ret = RSAVP1(key, sig->rsa.s, &m);
-	if (ret < 0)
-		goto error;
-
-	/* (2c) Convert the message representative (m) to an encoded message
-	 *      (EM) of length k octets.
-	 *
-	 *      NOTE!  The leading zero byte is suppressed by MPI, so we pass a
-	 *      pointer to the _preceding_ byte to RSA_verify()!
+	/* Output from the operation is an encoded message (EM) of
+	 * length k octets.
 	 */
-	ret = RSA_I2OSP(m, k, &EM);
-	if (ret < 0)
-		goto error;
-
-	ret = RSA_verify(H, EM - 1, k, sig->digest_size,
+	outlen = req->dst_len;
+	ret = rsa_verify(sig->digest, outbuf, outlen, sig->digest_size,
 			 RSA_ASN1_templates[sig->pkey_hash_algo].data,
 			 RSA_ASN1_templates[sig->pkey_hash_algo].size);
-
-error:
-	kfree(EM);
-	mpi_free(m);
-	kleave(" = %d", ret);
+error_free_req:
+	akcipher_request_free(req);
+error_free_tfm:
+	crypto_free_akcipher(tfm);
+error_out:
+	kfree(outbuf);
 	return ret;
 }
-
-const struct public_key_algorithm RSA_public_key_algorithm = {
-	.name		= "RSA",
-	.n_pub_mpi	= 2,
-	.n_sec_mpi	= 3,
-	.n_sig_mpi	= 1,
-	.verify_signature = RSA_verify_signature,
-};
-EXPORT_SYMBOL_GPL(RSA_public_key_algorithm);
+EXPORT_SYMBOL_GPL(rsa_verify_signature);
--- linux-4.4.0.orig/crypto/asymmetric_keys/x509_cert_parser.c
+++ linux-4.4.0/crypto/asymmetric_keys/x509_cert_parser.c
@@ -15,11 +15,10 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/oid_registry.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
 #include "x509_parser.h"
 #include "x509-asn1.h"
 #include "x509_akid-asn1.h"
-#include "x509_rsakey-asn1.h"
 
 struct x509_parse_context {
 	struct x509_certificate	*cert;		/* Certificate being constructed */
@@ -56,7 +55,7 @@
 		kfree(cert->akid_id);
 		kfree(cert->akid_skid);
 		kfree(cert->sig.digest);
-		mpi_free(cert->sig.rsa.s);
+		kfree(cert->sig.s);
 		kfree(cert);
 	}
 }
@@ -103,12 +102,12 @@
 		}
 	}
 
-	/* Decode the public key */
-	ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx,
-			       ctx->key, ctx->key_size);
-	if (ret < 0)
+	cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
+	if (!cert->pub->key)
 		goto error_decode;
 
+	cert->pub->keylen = ctx->key_size;
+
 	/* Generate cert issuer + serial number key ID */
 	kid = asymmetric_key_generate_id(cert->raw_serial,
 					 cert->raw_serial_size,
@@ -124,6 +123,7 @@
 	return cert;
 
 error_decode:
+	kfree(cert->pub->key);
 	kfree(ctx);
 error_no_ctx:
 	x509_free_certificate(cert);
@@ -399,34 +399,13 @@
 	ctx->cert->pub->pkey_algo = PKEY_ALGO_RSA;
 
 	/* Discard the BIT STRING metadata */
+	if (vlen < 1 || *(const u8 *)value != 0)
+		return -EBADMSG;
 	ctx->key = value + 1;
 	ctx->key_size = vlen - 1;
 	return 0;
 }
 
-/*
- * Extract a RSA public key value
- */
-int rsa_extract_mpi(void *context, size_t hdrlen,
-		    unsigned char tag,
-		    const void *value, size_t vlen)
-{
-	struct x509_parse_context *ctx = context;
-	MPI mpi;
-
-	if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) {
-		pr_err("Too many public key MPIs in certificate\n");
-		return -EBADMSG;
-	}
-
-	mpi = mpi_read_raw_data(value, vlen);
-	if (!mpi)
-		return -ENOMEM;
-
-	ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi;
-	return 0;
-}
-
 /* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */
 #define SEQ_TAG_KEYID (ASN1_CONT << 6)
 
@@ -494,7 +473,7 @@
 		     unsigned char tag,
 		     const unsigned char *value, size_t vlen)
 {
-	static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30,
+	static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
 						       31, 31, 30, 31, 30, 31 };
 	const unsigned char *p = value;
 	unsigned year, mon, day, hour, min, sec, mon_len;
@@ -540,9 +519,9 @@
 		if (year % 4 == 0) {
 			mon_len = 29;
 			if (year % 100 == 0) {
-				year /= 100;
-				if (year % 4 != 0)
-					mon_len = 28;
+				mon_len = 28;
+				if (year % 400 == 0)
+					mon_len = 29;
 			}
 		}
 	}
--- linux-4.4.0.orig/crypto/asymmetric_keys/x509_public_key.c
+++ linux-4.4.0/crypto/asymmetric_keys/x509_public_key.c
@@ -13,15 +13,11 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/mpi.h>
-#include <linux/asn1_decoder.h>
 #include <keys/asymmetric-subtype.h>
 #include <keys/asymmetric-parser.h>
 #include <keys/system_keyring.h>
 #include <crypto/hash.h>
 #include "asymmetric_keys.h"
-#include "public_key.h"
 #include "x509_parser.h"
 
 static bool use_builtin_keys;
@@ -167,13 +163,15 @@
 
 	if (cert->unsupported_crypto)
 		return -ENOPKG;
-	if (cert->sig.rsa.s)
+	if (cert->sig.s)
 		return 0;
 
-	cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
-	if (!cert->sig.rsa.s)
+	cert->sig.s = kmemdup(cert->raw_sig, cert->raw_sig_size,
+			      GFP_KERNEL);
+	if (!cert->sig.s)
 		return -ENOMEM;
-	cert->sig.nr_mpi = 1;
+
+	cert->sig.s_size = cert->raw_sig_size;
 
 	/* Allocate the hashing algorithm we're going to need and find out how
 	 * big the hash operational data will be.
@@ -296,8 +294,6 @@
 	if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
 	    cert->sig.pkey_algo >= PKEY_ALGO__LAST ||
 	    cert->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
-	    !pkey_algo[cert->pub->pkey_algo] ||
-	    !pkey_algo[cert->sig.pkey_algo] ||
 	    !hash_algo_name[cert->sig.pkey_hash_algo]) {
 		ret = -ENOPKG;
 		goto error_free_cert;
@@ -309,7 +305,6 @@
 		 pkey_algo_name[cert->sig.pkey_algo],
 		 hash_algo_name[cert->sig.pkey_hash_algo]);
 
-	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
 	cert->pub->id_type = PKEY_ID_X509;
 
 	/* Check the signature on the key if it appears to be self-signed */
@@ -321,6 +316,8 @@
 			goto error_free_cert;
 	} else if (!prep->trusted) {
 		ret = x509_validate_trust(cert, get_system_trusted_keyring());
+		if (ret)
+			ret = x509_validate_trust(cert, get_ima_mok_keyring());
 		if (!ret)
 			prep->trusted = 1;
 	}
--- linux-4.4.0.orig/crypto/async_tx/async_pq.c
+++ linux-4.4.0/crypto/async_tx/async_pq.c
@@ -62,9 +62,6 @@
 	dma_addr_t dma_dest[2];
 	int src_off = 0;
 
-	if (submit->flags & ASYNC_TX_FENCE)
-		dma_flags |= DMA_PREP_FENCE;
-
 	while (src_cnt > 0) {
 		submit->flags = flags_orig;
 		pq_src_cnt = min(src_cnt, dma_maxpq(dma, dma_flags));
@@ -83,6 +80,8 @@
 			if (cb_fn_orig)
 				dma_flags |= DMA_PREP_INTERRUPT;
 		}
+		if (submit->flags & ASYNC_TX_FENCE)
+			dma_flags |= DMA_PREP_FENCE;
 
 		/* Drivers force forward progress in case they can not provide
 		 * a descriptor
@@ -368,8 +367,6 @@
 
 		dma_set_unmap(tx, unmap);
 		async_tx_submit(chan, tx, submit);
-
-		return tx;
 	} else {
 		struct page *p_src = P(blocks, disks);
 		struct page *q_src = Q(blocks, disks);
@@ -424,9 +421,11 @@
 		submit->cb_param = cb_param_orig;
 		submit->flags = flags_orig;
 		async_tx_sync_epilog(submit);
-
-		return NULL;
+		tx = NULL;
 	}
+	dmaengine_unmap_put(unmap);
+
+	return tx;
 }
 EXPORT_SYMBOL_GPL(async_syndrome_val);
 
--- linux-4.4.0.orig/crypto/authenc.c
+++ linux-4.4.0/crypto/authenc.c
@@ -58,14 +58,22 @@
 		return -EINVAL;
 	if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
 		return -EINVAL;
-	if (RTA_PAYLOAD(rta) < sizeof(*param))
+
+	/*
+	 * RTA_OK() didn't align the rtattr's payload when validating that it
+	 * fits in the buffer.  Yet, the keys should start on the next 4-byte
+	 * aligned boundary.  To avoid confusion, require that the rtattr
+	 * payload be exactly the param struct, which has a 4-byte aligned size.
+	 */
+	if (RTA_PAYLOAD(rta) != sizeof(*param))
 		return -EINVAL;
+	BUILD_BUG_ON(sizeof(*param) % RTA_ALIGNTO);
 
 	param = RTA_DATA(rta);
 	keys->enckeylen = be32_to_cpu(param->enckeylen);
 
-	key += RTA_ALIGN(rta->rta_len);
-	keylen -= RTA_ALIGN(rta->rta_len);
+	key += rta->rta_len;
+	keylen -= rta->rta_len;
 
 	if (keylen < keys->enckeylen)
 		return -EINVAL;
@@ -108,6 +116,7 @@
 				       CRYPTO_TFM_RES_MASK);
 
 out:
+	memzero_explicit(&keys, sizeof(keys));
 	return err;
 
 badkey:
--- linux-4.4.0.orig/crypto/authencesn.c
+++ linux-4.4.0/crypto/authencesn.c
@@ -90,6 +90,7 @@
 					   CRYPTO_TFM_RES_MASK);
 
 out:
+	memzero_explicit(&keys, sizeof(keys));
 	return err;
 
 badkey:
@@ -202,6 +203,9 @@
 	struct scatterlist *src, *dst;
 	int err;
 
+	if (assoclen < 8)
+		return -EINVAL;
+
 	sg_init_table(areq_ctx->src, 2);
 	src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen);
 	dst = src;
@@ -245,6 +249,9 @@
 	u8 *ihash = ohash + crypto_ahash_digestsize(auth);
 	u32 tmp[2];
 
+	if (!authsize)
+		goto decrypt;
+
 	/* Move high-order bits of sequence number back. */
 	scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
 	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
@@ -253,6 +260,8 @@
 	if (crypto_memneq(ihash, ohash, authsize))
 		return -EBADMSG;
 
+decrypt:
+
 	sg_init_table(areq_ctx->dst, 2);
 	dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
 
@@ -270,7 +279,7 @@
 	struct aead_request *req = areq->data;
 
 	err = err ?: crypto_authenc_esn_decrypt_tail(req, 0);
-	aead_request_complete(req, err);
+	authenc_esn_request_complete(req, err);
 }
 
 static int crypto_authenc_esn_decrypt(struct aead_request *req)
@@ -290,6 +299,9 @@
 	u32 tmp[2];
 	int err;
 
+	if (assoclen < 8)
+		return -EINVAL;
+
 	cryptlen -= authsize;
 
 	if (req->src != dst) {
--- linux-4.4.0.orig/crypto/blkcipher.c
+++ linux-4.4.0/crypto/blkcipher.c
@@ -71,19 +71,18 @@
 	return max(start, end_page);
 }
 
-static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk,
-					       unsigned int bsize)
+static inline void blkcipher_done_slow(struct blkcipher_walk *walk,
+				       unsigned int bsize)
 {
 	u8 *addr;
 
 	addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1);
 	addr = blkcipher_get_spot(addr, bsize);
 	scatterwalk_copychunks(addr, &walk->out, bsize, 1);
-	return bsize;
 }
 
-static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk,
-					       unsigned int n)
+static inline void blkcipher_done_fast(struct blkcipher_walk *walk,
+				       unsigned int n)
 {
 	if (walk->flags & BLKCIPHER_WALK_COPY) {
 		blkcipher_map_dst(walk);
@@ -97,49 +96,48 @@
 
 	scatterwalk_advance(&walk->in, n);
 	scatterwalk_advance(&walk->out, n);
-
-	return n;
 }
 
 int blkcipher_walk_done(struct blkcipher_desc *desc,
 			struct blkcipher_walk *walk, int err)
 {
-	unsigned int nbytes = 0;
+	unsigned int n; /* bytes processed */
+	bool more;
 
-	if (likely(err >= 0)) {
-		unsigned int n = walk->nbytes - err;
+	if (unlikely(err < 0))
+		goto finish;
 
-		if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW)))
-			n = blkcipher_done_fast(walk, n);
-		else if (WARN_ON(err)) {
+	n = walk->nbytes - err;
+	walk->total -= n;
+	more = (walk->total != 0);
+
+	if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) {
+		blkcipher_done_fast(walk, n);
+	} else {
+		if (WARN_ON(err)) {
+			/* unexpected case; didn't process all bytes */
 			err = -EINVAL;
-			goto err;
-		} else
-			n = blkcipher_done_slow(walk, n);
-
-		nbytes = walk->total - n;
-		err = 0;
+			goto finish;
+		}
+		blkcipher_done_slow(walk, n);
 	}
 
-	scatterwalk_done(&walk->in, 0, nbytes);
-	scatterwalk_done(&walk->out, 1, nbytes);
+	scatterwalk_done(&walk->in, 0, more);
+	scatterwalk_done(&walk->out, 1, more);
 
-err:
-	walk->total = nbytes;
-	walk->nbytes = nbytes;
-
-	if (nbytes) {
+	if (more) {
 		crypto_yield(desc->flags);
 		return blkcipher_walk_next(desc, walk);
 	}
-
+	err = 0;
+finish:
+	walk->nbytes = 0;
 	if (walk->iv != desc->info)
 		memcpy(desc->info, walk->iv, walk->ivsize);
 	if (walk->buffer != walk->page)
 		kfree(walk->buffer);
 	if (walk->page)
 		free_page((unsigned long)walk->page);
-
 	return err;
 }
 EXPORT_SYMBOL_GPL(blkcipher_walk_done);
@@ -234,6 +232,8 @@
 		return blkcipher_walk_done(desc, walk, -EINVAL);
 	}
 
+	bsize = min(walk->walk_blocksize, n);
+
 	walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY |
 			 BLKCIPHER_WALK_DIFF);
 	if (!scatterwalk_aligned(&walk->in, walk->alignmask) ||
@@ -246,7 +246,6 @@
 		}
 	}
 
-	bsize = min(walk->walk_blocksize, n);
 	n = scatterwalk_clamp(&walk->in, n);
 	n = scatterwalk_clamp(&walk->out, n);
 
@@ -516,6 +515,7 @@
 	strncpy(rblkcipher.type, "blkcipher", sizeof(rblkcipher.type));
 	strncpy(rblkcipher.geniv, alg->cra_blkcipher.geniv ?: "<default>",
 		sizeof(rblkcipher.geniv));
+	rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0';
 
 	rblkcipher.blocksize = alg->cra_blocksize;
 	rblkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
--- linux-4.4.0.orig/crypto/chacha20poly1305.c
+++ linux-4.4.0/crypto/chacha20poly1305.c
@@ -600,6 +600,11 @@
 			       CRYPTO_ALG_TYPE_AHASH_MASK);
 	if (IS_ERR(poly))
 		return PTR_ERR(poly);
+	poly_hash = __crypto_hash_alg_common(poly);
+
+	err = -EINVAL;
+	if (poly_hash->digestsize != POLY1305_DIGEST_SIZE)
+		goto out_put_poly;
 
 	err = -ENOMEM;
 	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
@@ -608,7 +613,6 @@
 
 	ctx = aead_instance_ctx(inst);
 	ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize;
-	poly_hash = __crypto_hash_alg_common(poly);
 	err = crypto_init_ahash_spawn(&ctx->poly, poly_hash,
 				      aead_crypto_instance(inst));
 	if (err)
@@ -633,8 +637,8 @@
 
 	err = -ENAMETOOLONG;
 	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
-		     "%s(%s,%s)", name, chacha_name,
-		     poly_name) >= CRYPTO_MAX_ALG_NAME)
+		     "%s(%s,%s)", name, chacha->cra_name,
+		     poly->cra_name) >= CRYPTO_MAX_ALG_NAME)
 		goto out_drop_chacha;
 	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
 		     "%s(%s,%s)", name, chacha->cra_driver_name,
--- linux-4.4.0.orig/crypto/cipher.c
+++ linux-4.4.0/crypto/cipher.c
@@ -37,8 +37,7 @@
 	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
 	memcpy(alignbuffer, key, keylen);
 	ret = cia->cia_setkey(tfm, alignbuffer, keylen);
-	memset(alignbuffer, 0, keylen);
-	kfree(buffer);
+	kzfree(buffer);
 	return ret;
 
 }
--- linux-4.4.0.orig/crypto/crc32c_generic.c
+++ linux-4.4.0/crypto/crc32c_generic.c
@@ -172,4 +172,3 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CRYPTO("crc32c");
 MODULE_ALIAS_CRYPTO("crc32c-generic");
-MODULE_SOFTDEP("pre: crc32c");
--- linux-4.4.0.orig/crypto/crct10dif_generic.c
+++ linux-4.4.0/crypto/crct10dif_generic.c
@@ -65,10 +65,9 @@
 	return 0;
 }
 
-static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
-			u8 *out)
+static int __chksum_finup(__u16 crc, const u8 *data, unsigned int len, u8 *out)
 {
-	*(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
+	*(__u16 *)out = crc_t10dif_generic(crc, data, len);
 	return 0;
 }
 
@@ -77,15 +76,13 @@
 {
 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
-	return __chksum_finup(&ctx->crc, data, len, out);
+	return __chksum_finup(ctx->crc, data, len, out);
 }
 
 static int chksum_digest(struct shash_desc *desc, const u8 *data,
 			 unsigned int length, u8 *out)
 {
-	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-	return __chksum_finup(&ctx->crc, data, length, out);
+	return __chksum_finup(0, data, length, out);
 }
 
 static struct shash_alg alg = {
--- linux-4.4.0.orig/crypto/cryptd.c
+++ linux-4.4.0/crypto/cryptd.c
@@ -594,9 +594,14 @@
 
 static int cryptd_hash_import(struct ahash_request *req, const void *in)
 {
-	struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct shash_desc *desc = cryptd_shash_desc(req);
 
-	return crypto_shash_import(&rctx->desc, in);
+	desc->tfm = ctx->child;
+	desc->flags = req->base.flags;
+
+	return crypto_shash_import(desc, in);
 }
 
 static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
@@ -637,6 +642,7 @@
 	inst->alg.halg.base.cra_flags = type;
 
 	inst->alg.halg.digestsize = salg->digestsize;
+	inst->alg.halg.statesize = salg->statesize;
 	inst->alg.halg.base.cra_ctxsize = sizeof(struct cryptd_hash_ctx);
 
 	inst->alg.halg.base.cra_init = cryptd_hash_init_tfm;
@@ -648,7 +654,8 @@
 	inst->alg.finup  = cryptd_hash_finup_enqueue;
 	inst->alg.export = cryptd_hash_export;
 	inst->alg.import = cryptd_hash_import;
-	inst->alg.setkey = cryptd_hash_setkey;
+	if (crypto_shash_alg_has_setkey(salg))
+		inst->alg.setkey = cryptd_hash_setkey;
 	inst->alg.digest = cryptd_hash_digest_enqueue;
 
 	err = ahash_register_instance(tmpl, inst);
--- linux-4.4.0.orig/crypto/crypto_user.c
+++ linux-4.4.0/crypto/crypto_user.c
@@ -28,6 +28,7 @@
 #include <crypto/internal/skcipher.h>
 #include <crypto/internal/rng.h>
 #include <crypto/akcipher.h>
+#include <crypto/kpp.h>
 
 #include "internal.h"
 
@@ -54,6 +55,9 @@
 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
 		int match = 0;
 
+		if (crypto_is_larval(q))
+			continue;
+
 		if ((q->cra_flags ^ p->cru_type) & p->cru_mask)
 			continue;
 
@@ -126,6 +130,21 @@
 	return -EMSGSIZE;
 }
 
+static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_report_kpp rkpp;
+
+	strncpy(rkpp.type, "kpp", sizeof(rkpp.type));
+
+	if (nla_put(skb, CRYPTOCFGA_REPORT_KPP,
+		    sizeof(struct crypto_report_kpp), &rkpp))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
 static int crypto_report_one(struct crypto_alg *alg,
 			     struct crypto_user_alg *ualg, struct sk_buff *skb)
 {
@@ -176,6 +195,10 @@
 			goto nla_put_failure;
 
 		break;
+	case CRYPTO_ALG_TYPE_KPP:
+		if (crypto_report_kpp(skb, alg))
+			goto nla_put_failure;
+		break;
 	}
 
 out:
@@ -246,38 +269,43 @@
 drop_alg:
 	crypto_mod_put(alg);
 
-	if (err)
+	if (err) {
+		kfree_skb(skb);
 		return err;
+	}
 
 	return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
 }
 
 static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct crypto_alg *alg;
+	const size_t start_pos = cb->args[0];
+	size_t pos = 0;
 	struct crypto_dump_info info;
-	int err;
-
-	if (cb->args[0])
-		goto out;
-
-	cb->args[0] = 1;
+	struct crypto_alg *alg;
+	int res;
 
 	info.in_skb = cb->skb;
 	info.out_skb = skb;
 	info.nlmsg_seq = cb->nlh->nlmsg_seq;
 	info.nlmsg_flags = NLM_F_MULTI;
 
+	down_read(&crypto_alg_sem);
 	list_for_each_entry(alg, &crypto_alg_list, cra_list) {
-		err = crypto_report_alg(alg, &info);
-		if (err)
-			goto out_err;
+		if (pos >= start_pos) {
+			res = crypto_report_alg(alg, &info);
+			if (res == -EMSGSIZE)
+				break;
+			if (res)
+				goto out;
+		}
+		pos++;
 	}
-
+	cb->args[0] = pos;
+	res = skb->len;
 out:
-	return skb->len;
-out_err:
-	return err;
+	up_read(&crypto_alg_sem);
+	return res;
 }
 
 static int crypto_dump_report_done(struct netlink_callback *cb)
@@ -455,6 +483,7 @@
 	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
 	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
 	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
+	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
 	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = 0,
 };
 
@@ -494,22 +523,26 @@
 	if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
 	    (nlh->nlmsg_flags & NLM_F_DUMP))) {
 		struct crypto_alg *alg;
-		u16 dump_alloc = 0;
+		unsigned long dump_alloc = 0;
 
 		if (link->dump == NULL)
 			return -EINVAL;
 
+		down_read(&crypto_alg_sem);
 		list_for_each_entry(alg, &crypto_alg_list, cra_list)
 			dump_alloc += CRYPTO_REPORT_MAXSIZE;
+		up_read(&crypto_alg_sem);
 
 		{
 			struct netlink_dump_control c = {
 				.dump = link->dump,
 				.done = link->done,
-				.min_dump_alloc = dump_alloc,
+				.min_dump_alloc = min(dump_alloc, 65535UL),
 			};
-			return netlink_dump_start(crypto_nlsk, skb, nlh, &c);
+			err = netlink_dump_start(crypto_nlsk, skb, nlh, &c);
 		}
+
+		return err;
 	}
 
 	err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX,
--- linux-4.4.0.orig/crypto/cts.c
+++ linux-4.4.0/crypto/cts.c
@@ -137,8 +137,8 @@
 	lcldesc.info = desc->info;
 	lcldesc.flags = desc->flags;
 
-	if (tot_blocks == 1) {
-		err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src, bsize);
+	if (tot_blocks <= 1) {
+		err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src, nbytes);
 	} else if (nbytes <= bsize * 2) {
 		err = cts_cbc_encrypt(ctx, desc, dst, src, 0, nbytes);
 	} else {
@@ -232,8 +232,8 @@
 	lcldesc.info = desc->info;
 	lcldesc.flags = desc->flags;
 
-	if (tot_blocks == 1) {
-		err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src, bsize);
+	if (tot_blocks <= 1) {
+		err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src, nbytes);
 	} else if (nbytes <= bsize * 2) {
 		err = cts_cbc_decrypt(ctx, desc, dst, src, 0, nbytes);
 	} else {
--- linux-4.4.0.orig/crypto/dh.c
+++ linux-4.4.0/crypto/dh.c
@@ -0,0 +1,189 @@
+/*  Diffie-Hellman Key Agreement Method [RFC2631]
+ *
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <crypto/internal/kpp.h>
+#include <crypto/kpp.h>
+#include <crypto/dh.h>
+#include <linux/mpi.h>
+
+struct dh_ctx {
+	MPI p;
+	MPI g;
+	MPI xa;
+};
+
+static inline void dh_clear_params(struct dh_ctx *ctx)
+{
+	mpi_free(ctx->p);
+	mpi_free(ctx->g);
+	ctx->p = NULL;
+	ctx->g = NULL;
+}
+
+static void dh_free_ctx(struct dh_ctx *ctx)
+{
+	dh_clear_params(ctx);
+	mpi_free(ctx->xa);
+	ctx->xa = NULL;
+}
+
+/*
+ * If base is g we compute the public key
+ *	ya = g^xa mod p; [RFC2631 sec 2.1.1]
+ * else if base if the counterpart public key we compute the shared secret
+ *	ZZ = yb^xa mod p; [RFC2631 sec 2.1.1]
+ */
+static int _compute_val(const struct dh_ctx *ctx, MPI base, MPI val)
+{
+	/* val = base^xa mod p */
+	return mpi_powm(val, base, ctx->xa, ctx->p);
+}
+
+static inline struct dh_ctx *dh_get_ctx(struct crypto_kpp *tfm)
+{
+	return kpp_tfm_ctx(tfm);
+}
+
+static int dh_check_params_length(unsigned int p_len)
+{
+	return (p_len < 1536) ? -EINVAL : 0;
+}
+
+static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
+{
+	if (unlikely(!params->p || !params->g))
+		return -EINVAL;
+
+	if (dh_check_params_length(params->p_size << 3))
+		return -EINVAL;
+
+	ctx->p = mpi_read_raw_data(params->p, params->p_size);
+	if (!ctx->p)
+		return -EINVAL;
+
+	ctx->g = mpi_read_raw_data(params->g, params->g_size);
+	if (!ctx->g) {
+		mpi_free(ctx->p);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dh_set_secret(struct crypto_kpp *tfm, void *buf, unsigned int len)
+{
+	struct dh_ctx *ctx = dh_get_ctx(tfm);
+	struct dh params;
+
+	if (crypto_dh_decode_key(buf, len, &params) < 0)
+		return -EINVAL;
+
+	if (dh_set_params(ctx, &params) < 0)
+		return -EINVAL;
+
+	ctx->xa = mpi_read_raw_data(params.key, params.key_size);
+	if (!ctx->xa) {
+		dh_clear_params(ctx);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dh_compute_value(struct kpp_request *req)
+{
+	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+	struct dh_ctx *ctx = dh_get_ctx(tfm);
+	MPI base, val = mpi_alloc(0);
+	int ret = 0;
+	int sign;
+
+	if (!val)
+		return -ENOMEM;
+
+	if (unlikely(!ctx->xa)) {
+		ret = -EINVAL;
+		goto err_free_val;
+	}
+
+	if (req->src) {
+		base = mpi_read_raw_from_sgl(req->src, req->src_len);
+		if (!base) {
+			ret = EINVAL;
+			goto err_free_val;
+		}
+	} else {
+		base = ctx->g;
+	}
+
+	ret = _compute_val(ctx, base, val);
+	if (ret)
+		goto err_free_base;
+
+	ret = mpi_write_to_sgl(val, req->dst, &req->dst_len, &sign);
+	if (ret)
+		goto err_free_base;
+
+	if (sign < 0)
+		ret = -EBADMSG;
+err_free_base:
+	if (req->src)
+		mpi_free(base);
+err_free_val:
+	mpi_free(val);
+	return ret;
+}
+
+static int dh_max_size(struct crypto_kpp *tfm)
+{
+	struct dh_ctx *ctx = dh_get_ctx(tfm);
+
+	return mpi_get_size(ctx->p);
+}
+
+static void dh_exit_tfm(struct crypto_kpp *tfm)
+{
+	struct dh_ctx *ctx = dh_get_ctx(tfm);
+
+	dh_free_ctx(ctx);
+}
+
+static struct kpp_alg dh = {
+	.set_secret = dh_set_secret,
+	.generate_public_key = dh_compute_value,
+	.compute_shared_secret = dh_compute_value,
+	.max_size = dh_max_size,
+	.exit = dh_exit_tfm,
+	.base = {
+		.cra_name = "dh",
+		.cra_driver_name = "dh-generic",
+		.cra_priority = 100,
+		.cra_module = THIS_MODULE,
+		.cra_ctxsize = sizeof(struct dh_ctx),
+	},
+};
+
+static int dh_init(void)
+{
+	return crypto_register_kpp(&dh);
+}
+
+static void dh_exit(void)
+{
+	crypto_unregister_kpp(&dh);
+}
+
+module_init(dh_init);
+module_exit(dh_exit);
+MODULE_ALIAS_CRYPTO("dh");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DH generic algorithm");
--- linux-4.4.0.orig/crypto/dh_helper.c
+++ linux-4.4.0/crypto/dh_helper.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <crypto/dh.h>
+#include <crypto/kpp.h>
+
+#define DH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 3 * sizeof(int))
+
+static inline u8 *dh_pack_data(void *dst, const void *src, size_t size)
+{
+	memcpy(dst, src, size);
+	return dst + size;
+}
+
+static inline const u8 *dh_unpack_data(void *dst, const void *src, size_t size)
+{
+	memcpy(dst, src, size);
+	return src + size;
+}
+
+static inline int dh_data_size(const struct dh *p)
+{
+	return p->key_size + p->p_size + p->g_size;
+}
+
+int crypto_dh_key_len(const struct dh *p)
+{
+	return DH_KPP_SECRET_MIN_SIZE + dh_data_size(p);
+}
+EXPORT_SYMBOL_GPL(crypto_dh_key_len);
+
+int crypto_dh_encode_key(char *buf, unsigned int len, const struct dh *params)
+{
+	u8 *ptr = buf;
+	struct kpp_secret secret = {
+		.type = CRYPTO_KPP_SECRET_TYPE_DH,
+		.len = len
+	};
+
+	if (unlikely(!buf))
+		return -EINVAL;
+
+	if (len != crypto_dh_key_len(params))
+		return -EINVAL;
+
+	ptr = dh_pack_data(ptr, &secret, sizeof(secret));
+	ptr = dh_pack_data(ptr, &params->key_size, sizeof(params->key_size));
+	ptr = dh_pack_data(ptr, &params->p_size, sizeof(params->p_size));
+	ptr = dh_pack_data(ptr, &params->g_size, sizeof(params->g_size));
+	ptr = dh_pack_data(ptr, params->key, params->key_size);
+	ptr = dh_pack_data(ptr, params->p, params->p_size);
+	dh_pack_data(ptr, params->g, params->g_size);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_dh_encode_key);
+
+int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params)
+{
+	const u8 *ptr = buf;
+	struct kpp_secret secret;
+
+	if (unlikely(!buf || len < DH_KPP_SECRET_MIN_SIZE))
+		return -EINVAL;
+
+	ptr = dh_unpack_data(&secret, ptr, sizeof(secret));
+	if (secret.type != CRYPTO_KPP_SECRET_TYPE_DH)
+		return -EINVAL;
+
+	ptr = dh_unpack_data(&params->key_size, ptr, sizeof(params->key_size));
+	ptr = dh_unpack_data(&params->p_size, ptr, sizeof(params->p_size));
+	ptr = dh_unpack_data(&params->g_size, ptr, sizeof(params->g_size));
+	if (secret.len != crypto_dh_key_len(params))
+		return -EINVAL;
+
+	/* Don't allocate memory. Set pointers to data within
+	 * the given buffer
+	 */
+	params->key = (void *)ptr;
+	params->p = (void *)(ptr + params->key_size);
+	params->g = (void *)(ptr + params->key_size + params->p_size);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_dh_decode_key);
--- linux-4.4.0.orig/crypto/ecc.c
+++ linux-4.4.0/crypto/ecc.c
@@ -0,0 +1,1104 @@
+/*
+ * Copyright (c) 2013, Kenneth MacKay
+ * 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.
+ *
+ * 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
+ * HOLDER 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/random.h>
+#include <linux/slab.h>
+#include <linux/swab.h>
+#include <linux/fips.h>
+#include <crypto/ecdh.h>
+#include <crypto/rng.h>
+
+#include "ecc.h"
+#include "ecc_curve_defs.h"
+
+typedef struct {
+	u64 m_low;
+	u64 m_high;
+} uint128_t;
+
+static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
+{
+	switch (curve_id) {
+	/* In FIPS mode only allow P256 and higher */
+	case ECC_CURVE_NIST_P192:
+		return fips_enabled ? NULL : &nist_p192;
+	case ECC_CURVE_NIST_P256:
+		return &nist_p256;
+	default:
+		return NULL;
+	}
+}
+
+static u64 *ecc_alloc_digits_space(unsigned int ndigits)
+{
+	size_t len = ndigits * sizeof(u64);
+
+	if (!len)
+		return NULL;
+
+	return kmalloc(len, GFP_KERNEL);
+}
+
+static void ecc_free_digits_space(u64 *space)
+{
+	kzfree(space);
+}
+
+static struct ecc_point *ecc_alloc_point(unsigned int ndigits)
+{
+	struct ecc_point *p = kmalloc(sizeof(*p), GFP_KERNEL);
+
+	if (!p)
+		return NULL;
+
+	p->x = ecc_alloc_digits_space(ndigits);
+	if (!p->x)
+		goto err_alloc_x;
+
+	p->y = ecc_alloc_digits_space(ndigits);
+	if (!p->y)
+		goto err_alloc_y;
+
+	p->ndigits = ndigits;
+
+	return p;
+
+err_alloc_y:
+	ecc_free_digits_space(p->x);
+err_alloc_x:
+	kfree(p);
+	return NULL;
+}
+
+static void ecc_free_point(struct ecc_point *p)
+{
+	if (!p)
+		return;
+
+	kzfree(p->x);
+	kzfree(p->y);
+	kzfree(p);
+}
+
+static void vli_clear(u64 *vli, unsigned int ndigits)
+{
+	int i;
+
+	for (i = 0; i < ndigits; i++)
+		vli[i] = 0;
+}
+
+/* Returns true if vli == 0, false otherwise. */
+static bool vli_is_zero(const u64 *vli, unsigned int ndigits)
+{
+	int i;
+
+	for (i = 0; i < ndigits; i++) {
+		if (vli[i])
+			return false;
+	}
+
+	return true;
+}
+
+/* Returns nonzero if bit bit of vli is set. */
+static u64 vli_test_bit(const u64 *vli, unsigned int bit)
+{
+	return (vli[bit / 64] & ((u64)1 << (bit % 64)));
+}
+
+/* Counts the number of 64-bit "digits" in vli. */
+static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
+{
+	int i;
+
+	/* Search from the end until we find a non-zero digit.
+	 * We do it in reverse because we expect that most digits will
+	 * be nonzero.
+	 */
+	for (i = ndigits - 1; i >= 0 && vli[i] == 0; i--);
+
+	return (i + 1);
+}
+
+/* Counts the number of bits required for vli. */
+static unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
+{
+	unsigned int i, num_digits;
+	u64 digit;
+
+	num_digits = vli_num_digits(vli, ndigits);
+	if (num_digits == 0)
+		return 0;
+
+	digit = vli[num_digits - 1];
+	for (i = 0; digit; i++)
+		digit >>= 1;
+
+	return ((num_digits - 1) * 64 + i);
+}
+
+/* Sets dest = src. */
+static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
+{
+	int i;
+
+	for (i = 0; i < ndigits; i++)
+		dest[i] = src[i];
+}
+
+/* Returns sign of left - right. */
+static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
+{
+	int i;
+
+	for (i = ndigits - 1; i >= 0; i--) {
+		if (left[i] > right[i])
+			return 1;
+		else if (left[i] < right[i])
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Computes result = in << c, returning carry. Can modify in place
+ * (if result == in). 0 < shift < 64.
+ */
+static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
+		      unsigned int ndigits)
+{
+	u64 carry = 0;
+	int i;
+
+	for (i = 0; i < ndigits; i++) {
+		u64 temp = in[i];
+
+		result[i] = (temp << shift) | carry;
+		carry = temp >> (64 - shift);
+	}
+
+	return carry;
+}
+
+/* Computes vli = vli >> 1. */
+static void vli_rshift1(u64 *vli, unsigned int ndigits)
+{
+	u64 *end = vli;
+	u64 carry = 0;
+
+	vli += ndigits;
+
+	while (vli-- > end) {
+		u64 temp = *vli;
+		*vli = (temp >> 1) | carry;
+		carry = temp << 63;
+	}
+}
+
+/* Computes result = left + right, returning carry. Can modify in place. */
+static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
+		   unsigned int ndigits)
+{
+	u64 carry = 0;
+	int i;
+
+	for (i = 0; i < ndigits; i++) {
+		u64 sum;
+
+		sum = left[i] + right[i] + carry;
+		if (sum != left[i])
+			carry = (sum < left[i]);
+
+		result[i] = sum;
+	}
+
+	return carry;
+}
+
+/* Computes result = left - right, returning borrow. Can modify in place. */
+static u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
+		   unsigned int ndigits)
+{
+	u64 borrow = 0;
+	int i;
+
+	for (i = 0; i < ndigits; i++) {
+		u64 diff;
+
+		diff = left[i] - right[i] - borrow;
+		if (diff != left[i])
+			borrow = (diff > left[i]);
+
+		result[i] = diff;
+	}
+
+	return borrow;
+}
+
+static uint128_t mul_64_64(u64 left, u64 right)
+{
+	u64 a0 = left & 0xffffffffull;
+	u64 a1 = left >> 32;
+	u64 b0 = right & 0xffffffffull;
+	u64 b1 = right >> 32;
+	u64 m0 = a0 * b0;
+	u64 m1 = a0 * b1;
+	u64 m2 = a1 * b0;
+	u64 m3 = a1 * b1;
+	uint128_t result;
+
+	m2 += (m0 >> 32);
+	m2 += m1;
+
+	/* Overflow */
+	if (m2 < m1)
+		m3 += 0x100000000ull;
+
+	result.m_low = (m0 & 0xffffffffull) | (m2 << 32);
+	result.m_high = m3 + (m2 >> 32);
+
+	return result;
+}
+
+static uint128_t add_128_128(uint128_t a, uint128_t b)
+{
+	uint128_t result;
+
+	result.m_low = a.m_low + b.m_low;
+	result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
+
+	return result;
+}
+
+static void vli_mult(u64 *result, const u64 *left, const u64 *right,
+		     unsigned int ndigits)
+{
+	uint128_t r01 = { 0, 0 };
+	u64 r2 = 0;
+	unsigned int i, k;
+
+	/* Compute each digit of result in sequence, maintaining the
+	 * carries.
+	 */
+	for (k = 0; k < ndigits * 2 - 1; k++) {
+		unsigned int min;
+
+		if (k < ndigits)
+			min = 0;
+		else
+			min = (k + 1) - ndigits;
+
+		for (i = min; i <= k && i < ndigits; i++) {
+			uint128_t product;
+
+			product = mul_64_64(left[i], right[k - i]);
+
+			r01 = add_128_128(r01, product);
+			r2 += (r01.m_high < product.m_high);
+		}
+
+		result[k] = r01.m_low;
+		r01.m_low = r01.m_high;
+		r01.m_high = r2;
+		r2 = 0;
+	}
+
+	result[ndigits * 2 - 1] = r01.m_low;
+}
+
+static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
+{
+	uint128_t r01 = { 0, 0 };
+	u64 r2 = 0;
+	int i, k;
+
+	for (k = 0; k < ndigits * 2 - 1; k++) {
+		unsigned int min;
+
+		if (k < ndigits)
+			min = 0;
+		else
+			min = (k + 1) - ndigits;
+
+		for (i = min; i <= k && i <= k - i; i++) {
+			uint128_t product;
+
+			product = mul_64_64(left[i], left[k - i]);
+
+			if (i < k - i) {
+				r2 += product.m_high >> 63;
+				product.m_high = (product.m_high << 1) |
+						 (product.m_low >> 63);
+				product.m_low <<= 1;
+			}
+
+			r01 = add_128_128(r01, product);
+			r2 += (r01.m_high < product.m_high);
+		}
+
+		result[k] = r01.m_low;
+		r01.m_low = r01.m_high;
+		r01.m_high = r2;
+		r2 = 0;
+	}
+
+	result[ndigits * 2 - 1] = r01.m_low;
+}
+
+/* Computes result = (left + right) % mod.
+ * Assumes that left < mod and right < mod, result != mod.
+ */
+static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
+			const u64 *mod, unsigned int ndigits)
+{
+	u64 carry;
+
+	carry = vli_add(result, left, right, ndigits);
+
+	/* result > mod (result = mod + remainder), so subtract mod to
+	 * get remainder.
+	 */
+	if (carry || vli_cmp(result, mod, ndigits) >= 0)
+		vli_sub(result, result, mod, ndigits);
+}
+
+/* Computes result = (left - right) % mod.
+ * Assumes that left < mod and right < mod, result != mod.
+ */
+static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
+			const u64 *mod, unsigned int ndigits)
+{
+	u64 borrow = vli_sub(result, left, right, ndigits);
+
+	/* In this case, p_result == -diff == (max int) - diff.
+	 * Since -x % d == d - x, we can get the correct result from
+	 * result + mod (with overflow).
+	 */
+	if (borrow)
+		vli_add(result, result, mod, ndigits);
+}
+
+/* Computes p_result = p_product % curve_p.
+ * See algorithm 5 and 6 from
+ * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf
+ */
+static void vli_mmod_fast_192(u64 *result, const u64 *product,
+			      const u64 *curve_prime, u64 *tmp)
+{
+	const unsigned int ndigits = 3;
+	int carry;
+
+	vli_set(result, product, ndigits);
+
+	vli_set(tmp, &product[3], ndigits);
+	carry = vli_add(result, result, tmp, ndigits);
+
+	tmp[0] = 0;
+	tmp[1] = product[3];
+	tmp[2] = product[4];
+	carry += vli_add(result, result, tmp, ndigits);
+
+	tmp[0] = tmp[1] = product[5];
+	tmp[2] = 0;
+	carry += vli_add(result, result, tmp, ndigits);
+
+	while (carry || vli_cmp(curve_prime, result, ndigits) != 1)
+		carry -= vli_sub(result, result, curve_prime, ndigits);
+}
+
+/* Computes result = product % curve_prime
+ * from http://www.nsa.gov/ia/_files/nist-routines.pdf
+ */
+static void vli_mmod_fast_256(u64 *result, const u64 *product,
+			      const u64 *curve_prime, u64 *tmp)
+{
+	int carry;
+	const unsigned int ndigits = 4;
+
+	/* t */
+	vli_set(result, product, ndigits);
+
+	/* s1 */
+	tmp[0] = 0;
+	tmp[1] = product[5] & 0xffffffff00000000ull;
+	tmp[2] = product[6];
+	tmp[3] = product[7];
+	carry = vli_lshift(tmp, tmp, 1, ndigits);
+	carry += vli_add(result, result, tmp, ndigits);
+
+	/* s2 */
+	tmp[1] = product[6] << 32;
+	tmp[2] = (product[6] >> 32) | (product[7] << 32);
+	tmp[3] = product[7] >> 32;
+	carry += vli_lshift(tmp, tmp, 1, ndigits);
+	carry += vli_add(result, result, tmp, ndigits);
+
+	/* s3 */
+	tmp[0] = product[4];
+	tmp[1] = product[5] & 0xffffffff;
+	tmp[2] = 0;
+	tmp[3] = product[7];
+	carry += vli_add(result, result, tmp, ndigits);
+
+	/* s4 */
+	tmp[0] = (product[4] >> 32) | (product[5] << 32);
+	tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);
+	tmp[2] = product[7];
+	tmp[3] = (product[6] >> 32) | (product[4] << 32);
+	carry += vli_add(result, result, tmp, ndigits);
+
+	/* d1 */
+	tmp[0] = (product[5] >> 32) | (product[6] << 32);
+	tmp[1] = (product[6] >> 32);
+	tmp[2] = 0;
+	tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);
+	carry -= vli_sub(result, result, tmp, ndigits);
+
+	/* d2 */
+	tmp[0] = product[6];
+	tmp[1] = product[7];
+	tmp[2] = 0;
+	tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);
+	carry -= vli_sub(result, result, tmp, ndigits);
+
+	/* d3 */
+	tmp[0] = (product[6] >> 32) | (product[7] << 32);
+	tmp[1] = (product[7] >> 32) | (product[4] << 32);
+	tmp[2] = (product[4] >> 32) | (product[5] << 32);
+	tmp[3] = (product[6] << 32);
+	carry -= vli_sub(result, result, tmp, ndigits);
+
+	/* d4 */
+	tmp[0] = product[7];
+	tmp[1] = product[4] & 0xffffffff00000000ull;
+	tmp[2] = product[5];
+	tmp[3] = product[6] & 0xffffffff00000000ull;
+	carry -= vli_sub(result, result, tmp, ndigits);
+
+	if (carry < 0) {
+		do {
+			carry += vli_add(result, result, curve_prime, ndigits);
+		} while (carry < 0);
+	} else {
+		while (carry || vli_cmp(curve_prime, result, ndigits) != 1)
+			carry -= vli_sub(result, result, curve_prime, ndigits);
+	}
+}
+
+/* Computes result = product % curve_prime
+ *  from http://www.nsa.gov/ia/_files/nist-routines.pdf
+*/
+static bool vli_mmod_fast(u64 *result, u64 *product,
+			  const u64 *curve_prime, unsigned int ndigits)
+{
+	u64 tmp[2 * ndigits];
+
+	switch (ndigits) {
+	case 3:
+		vli_mmod_fast_192(result, product, curve_prime, tmp);
+		break;
+	case 4:
+		vli_mmod_fast_256(result, product, curve_prime, tmp);
+		break;
+	default:
+		pr_err("unsupports digits size!\n");
+		return false;
+	}
+
+	return true;
+}
+
+/* Computes result = (left * right) % curve_prime. */
+static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
+			      const u64 *curve_prime, unsigned int ndigits)
+{
+	u64 product[2 * ndigits];
+
+	vli_mult(product, left, right, ndigits);
+	vli_mmod_fast(result, product, curve_prime, ndigits);
+}
+
+/* Computes result = left^2 % curve_prime. */
+static void vli_mod_square_fast(u64 *result, const u64 *left,
+				const u64 *curve_prime, unsigned int ndigits)
+{
+	u64 product[2 * ndigits];
+
+	vli_square(product, left, ndigits);
+	vli_mmod_fast(result, product, curve_prime, ndigits);
+}
+
+#define EVEN(vli) (!(vli[0] & 1))
+/* Computes result = (1 / p_input) % mod. All VLIs are the same size.
+ * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
+ * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf
+ */
+static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
+			unsigned int ndigits)
+{
+	u64 a[ndigits], b[ndigits];
+	u64 u[ndigits], v[ndigits];
+	u64 carry;
+	int cmp_result;
+
+	if (vli_is_zero(input, ndigits)) {
+		vli_clear(result, ndigits);
+		return;
+	}
+
+	vli_set(a, input, ndigits);
+	vli_set(b, mod, ndigits);
+	vli_clear(u, ndigits);
+	u[0] = 1;
+	vli_clear(v, ndigits);
+
+	while ((cmp_result = vli_cmp(a, b, ndigits)) != 0) {
+		carry = 0;
+
+		if (EVEN(a)) {
+			vli_rshift1(a, ndigits);
+
+			if (!EVEN(u))
+				carry = vli_add(u, u, mod, ndigits);
+
+			vli_rshift1(u, ndigits);
+			if (carry)
+				u[ndigits - 1] |= 0x8000000000000000ull;
+		} else if (EVEN(b)) {
+			vli_rshift1(b, ndigits);
+
+			if (!EVEN(v))
+				carry = vli_add(v, v, mod, ndigits);
+
+			vli_rshift1(v, ndigits);
+			if (carry)
+				v[ndigits - 1] |= 0x8000000000000000ull;
+		} else if (cmp_result > 0) {
+			vli_sub(a, a, b, ndigits);
+			vli_rshift1(a, ndigits);
+
+			if (vli_cmp(u, v, ndigits) < 0)
+				vli_add(u, u, mod, ndigits);
+
+			vli_sub(u, u, v, ndigits);
+			if (!EVEN(u))
+				carry = vli_add(u, u, mod, ndigits);
+
+			vli_rshift1(u, ndigits);
+			if (carry)
+				u[ndigits - 1] |= 0x8000000000000000ull;
+		} else {
+			vli_sub(b, b, a, ndigits);
+			vli_rshift1(b, ndigits);
+
+			if (vli_cmp(v, u, ndigits) < 0)
+				vli_add(v, v, mod, ndigits);
+
+			vli_sub(v, v, u, ndigits);
+			if (!EVEN(v))
+				carry = vli_add(v, v, mod, ndigits);
+
+			vli_rshift1(v, ndigits);
+			if (carry)
+				v[ndigits - 1] |= 0x8000000000000000ull;
+		}
+	}
+
+	vli_set(result, u, ndigits);
+}
+
+/* ------ Point operations ------ */
+
+/* Returns true if p_point is the point at infinity, false otherwise. */
+static bool ecc_point_is_zero(const struct ecc_point *point)
+{
+	return (vli_is_zero(point->x, point->ndigits) &&
+		vli_is_zero(point->y, point->ndigits));
+}
+
+/* Point multiplication algorithm using Montgomery's ladder with co-Z
+ * coordinates. From http://eprint.iacr.org/2011/338.pdf
+ */
+
+/* Double in place */
+static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
+				      u64 *curve_prime, unsigned int ndigits)
+{
+	/* t1 = x, t2 = y, t3 = z */
+	u64 t4[ndigits];
+	u64 t5[ndigits];
+
+	if (vli_is_zero(z1, ndigits))
+		return;
+
+	/* t4 = y1^2 */
+	vli_mod_square_fast(t4, y1, curve_prime, ndigits);
+	/* t5 = x1*y1^2 = A */
+	vli_mod_mult_fast(t5, x1, t4, curve_prime, ndigits);
+	/* t4 = y1^4 */
+	vli_mod_square_fast(t4, t4, curve_prime, ndigits);
+	/* t2 = y1*z1 = z3 */
+	vli_mod_mult_fast(y1, y1, z1, curve_prime, ndigits);
+	/* t3 = z1^2 */
+	vli_mod_square_fast(z1, z1, curve_prime, ndigits);
+
+	/* t1 = x1 + z1^2 */
+	vli_mod_add(x1, x1, z1, curve_prime, ndigits);
+	/* t3 = 2*z1^2 */
+	vli_mod_add(z1, z1, z1, curve_prime, ndigits);
+	/* t3 = x1 - z1^2 */
+	vli_mod_sub(z1, x1, z1, curve_prime, ndigits);
+	/* t1 = x1^2 - z1^4 */
+	vli_mod_mult_fast(x1, x1, z1, curve_prime, ndigits);
+
+	/* t3 = 2*(x1^2 - z1^4) */
+	vli_mod_add(z1, x1, x1, curve_prime, ndigits);
+	/* t1 = 3*(x1^2 - z1^4) */
+	vli_mod_add(x1, x1, z1, curve_prime, ndigits);
+	if (vli_test_bit(x1, 0)) {
+		u64 carry = vli_add(x1, x1, curve_prime, ndigits);
+
+		vli_rshift1(x1, ndigits);
+		x1[ndigits - 1] |= carry << 63;
+	} else {
+		vli_rshift1(x1, ndigits);
+	}
+	/* t1 = 3/2*(x1^2 - z1^4) = B */
+
+	/* t3 = B^2 */
+	vli_mod_square_fast(z1, x1, curve_prime, ndigits);
+	/* t3 = B^2 - A */
+	vli_mod_sub(z1, z1, t5, curve_prime, ndigits);
+	/* t3 = B^2 - 2A = x3 */
+	vli_mod_sub(z1, z1, t5, curve_prime, ndigits);
+	/* t5 = A - x3 */
+	vli_mod_sub(t5, t5, z1, curve_prime, ndigits);
+	/* t1 = B * (A - x3) */
+	vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
+	/* t4 = B * (A - x3) - y1^4 = y3 */
+	vli_mod_sub(t4, x1, t4, curve_prime, ndigits);
+
+	vli_set(x1, z1, ndigits);
+	vli_set(z1, y1, ndigits);
+	vli_set(y1, t4, ndigits);
+}
+
+/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
+static void apply_z(u64 *x1, u64 *y1, u64 *z, u64 *curve_prime,
+		    unsigned int ndigits)
+{
+	u64 t1[ndigits];
+
+	vli_mod_square_fast(t1, z, curve_prime, ndigits);    /* z^2 */
+	vli_mod_mult_fast(x1, x1, t1, curve_prime, ndigits); /* x1 * z^2 */
+	vli_mod_mult_fast(t1, t1, z, curve_prime, ndigits);  /* z^3 */
+	vli_mod_mult_fast(y1, y1, t1, curve_prime, ndigits); /* y1 * z^3 */
+}
+
+/* P = (x1, y1) => 2P, (x2, y2) => P' */
+static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2,
+				u64 *p_initial_z, u64 *curve_prime,
+				unsigned int ndigits)
+{
+	u64 z[ndigits];
+
+	vli_set(x2, x1, ndigits);
+	vli_set(y2, y1, ndigits);
+
+	vli_clear(z, ndigits);
+	z[0] = 1;
+
+	if (p_initial_z)
+		vli_set(z, p_initial_z, ndigits);
+
+	apply_z(x1, y1, z, curve_prime, ndigits);
+
+	ecc_point_double_jacobian(x1, y1, z, curve_prime, ndigits);
+
+	apply_z(x2, y2, z, curve_prime, ndigits);
+}
+
+/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
+ * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
+ * or P => P', Q => P + Q
+ */
+static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
+		     unsigned int ndigits)
+{
+	/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+	u64 t5[ndigits];
+
+	/* t5 = x2 - x1 */
+	vli_mod_sub(t5, x2, x1, curve_prime, ndigits);
+	/* t5 = (x2 - x1)^2 = A */
+	vli_mod_square_fast(t5, t5, curve_prime, ndigits);
+	/* t1 = x1*A = B */
+	vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
+	/* t3 = x2*A = C */
+	vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits);
+	/* t4 = y2 - y1 */
+	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+	/* t5 = (y2 - y1)^2 = D */
+	vli_mod_square_fast(t5, y2, curve_prime, ndigits);
+
+	/* t5 = D - B */
+	vli_mod_sub(t5, t5, x1, curve_prime, ndigits);
+	/* t5 = D - B - C = x3 */
+	vli_mod_sub(t5, t5, x2, curve_prime, ndigits);
+	/* t3 = C - B */
+	vli_mod_sub(x2, x2, x1, curve_prime, ndigits);
+	/* t2 = y1*(C - B) */
+	vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits);
+	/* t3 = B - x3 */
+	vli_mod_sub(x2, x1, t5, curve_prime, ndigits);
+	/* t4 = (y2 - y1)*(B - x3) */
+	vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits);
+	/* t4 = y3 */
+	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+
+	vli_set(x2, t5, ndigits);
+}
+
+/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
+ * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
+ * or P => P - Q, Q => P + Q
+ */
+static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
+		       unsigned int ndigits)
+{
+	/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+	u64 t5[ndigits];
+	u64 t6[ndigits];
+	u64 t7[ndigits];
+
+	/* t5 = x2 - x1 */
+	vli_mod_sub(t5, x2, x1, curve_prime, ndigits);
+	/* t5 = (x2 - x1)^2 = A */
+	vli_mod_square_fast(t5, t5, curve_prime, ndigits);
+	/* t1 = x1*A = B */
+	vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
+	/* t3 = x2*A = C */
+	vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits);
+	/* t4 = y2 + y1 */
+	vli_mod_add(t5, y2, y1, curve_prime, ndigits);
+	/* t4 = y2 - y1 */
+	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+
+	/* t6 = C - B */
+	vli_mod_sub(t6, x2, x1, curve_prime, ndigits);
+	/* t2 = y1 * (C - B) */
+	vli_mod_mult_fast(y1, y1, t6, curve_prime, ndigits);
+	/* t6 = B + C */
+	vli_mod_add(t6, x1, x2, curve_prime, ndigits);
+	/* t3 = (y2 - y1)^2 */
+	vli_mod_square_fast(x2, y2, curve_prime, ndigits);
+	/* t3 = x3 */
+	vli_mod_sub(x2, x2, t6, curve_prime, ndigits);
+
+	/* t7 = B - x3 */
+	vli_mod_sub(t7, x1, x2, curve_prime, ndigits);
+	/* t4 = (y2 - y1)*(B - x3) */
+	vli_mod_mult_fast(y2, y2, t7, curve_prime, ndigits);
+	/* t4 = y3 */
+	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+
+	/* t7 = (y2 + y1)^2 = F */
+	vli_mod_square_fast(t7, t5, curve_prime, ndigits);
+	/* t7 = x3' */
+	vli_mod_sub(t7, t7, t6, curve_prime, ndigits);
+	/* t6 = x3' - B */
+	vli_mod_sub(t6, t7, x1, curve_prime, ndigits);
+	/* t6 = (y2 + y1)*(x3' - B) */
+	vli_mod_mult_fast(t6, t6, t5, curve_prime, ndigits);
+	/* t2 = y3' */
+	vli_mod_sub(y1, t6, y1, curve_prime, ndigits);
+
+	vli_set(x1, t7, ndigits);
+}
+
+static void ecc_point_mult(struct ecc_point *result,
+			   const struct ecc_point *point, const u64 *scalar,
+			   u64 *initial_z, u64 *curve_prime,
+			   unsigned int ndigits)
+{
+	/* R0 and R1 */
+	u64 rx[2][ndigits];
+	u64 ry[2][ndigits];
+	u64 z[ndigits];
+	int i, nb;
+	int num_bits = vli_num_bits(scalar, ndigits);
+
+	vli_set(rx[1], point->x, ndigits);
+	vli_set(ry[1], point->y, ndigits);
+
+	xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve_prime,
+			    ndigits);
+
+	for (i = num_bits - 2; i > 0; i--) {
+		nb = !vli_test_bit(scalar, i);
+		xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime,
+			   ndigits);
+		xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime,
+			 ndigits);
+	}
+
+	nb = !vli_test_bit(scalar, 0);
+	xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime,
+		   ndigits);
+
+	/* Find final 1/Z value. */
+	/* X1 - X0 */
+	vli_mod_sub(z, rx[1], rx[0], curve_prime, ndigits);
+	/* Yb * (X1 - X0) */
+	vli_mod_mult_fast(z, z, ry[1 - nb], curve_prime, ndigits);
+	/* xP * Yb * (X1 - X0) */
+	vli_mod_mult_fast(z, z, point->x, curve_prime, ndigits);
+
+	/* 1 / (xP * Yb * (X1 - X0)) */
+	vli_mod_inv(z, z, curve_prime, point->ndigits);
+
+	/* yP / (xP * Yb * (X1 - X0)) */
+	vli_mod_mult_fast(z, z, point->y, curve_prime, ndigits);
+	/* Xb * yP / (xP * Yb * (X1 - X0)) */
+	vli_mod_mult_fast(z, z, rx[1 - nb], curve_prime, ndigits);
+	/* End 1/Z calculation */
+
+	xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, ndigits);
+
+	apply_z(rx[0], ry[0], z, curve_prime, ndigits);
+
+	vli_set(result->x, rx[0], ndigits);
+	vli_set(result->y, ry[0], ndigits);
+}
+
+static inline void ecc_swap_digits(const u64 *in, u64 *out,
+				   unsigned int ndigits)
+{
+	int i;
+
+	for (i = 0; i < ndigits; i++)
+		out[i] = __swab64(in[ndigits - 1 - i]);
+}
+
+int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
+		     const u64 *private_key, unsigned int private_key_len)
+{
+	int nbytes;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+
+	if (!private_key)
+		return -EINVAL;
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	if (private_key_len != nbytes)
+		return -EINVAL;
+
+	if (vli_is_zero(private_key, ndigits))
+		return -EINVAL;
+
+	/* Make sure the private key is in the range [1, n-1]. */
+	if (vli_cmp(curve->n, private_key, ndigits) != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * ECC private keys are generated using the method of extra random bits,
+ * equivalent to that described in FIPS 186-4, Appendix B.4.1.
+ *
+ * d = (c mod(n–1)) + 1    where c is a string of random bits, 64 bits longer
+ *                         than requested
+ * 0 <= c mod(n-1) <= n-2  and implies that
+ * 1 <= d <= n-1
+ *
+ * This method generates a private key uniformly distributed in the range
+ * [1, n-1].
+ */
+int ecc_gen_privkey(unsigned int curve_id, unsigned int ndigits, u64 *privkey)
+{
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+	u64 priv[ndigits];
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	unsigned int nbits = vli_num_bits(curve->n, ndigits);
+	int err;
+
+	/* Check that N is included in Table 1 of FIPS 186-4, section 6.1.1 */
+	if (nbits < 160)
+		return -EINVAL;
+
+	/*
+	 * FIPS 186-4 recommends that the private key should be obtained from a
+	 * RBG with a security strength equal to or greater than the security
+	 * strength associated with N.
+	 *
+	 * The maximum security strength identified by NIST SP800-57pt1r4 for
+	 * ECC is 256 (N >= 512).
+	 *
+	 * This condition is met by the default RNG because it selects a favored
+	 * DRBG with a security strength of 256.
+	 */
+	if (crypto_get_default_rng())
+		return -EFAULT;
+
+	err = crypto_rng_get_bytes(crypto_default_rng, (u8 *)priv, nbytes);
+	crypto_put_default_rng();
+	if (err)
+		return err;
+
+	if (vli_is_zero(priv, ndigits))
+		return -EINVAL;
+
+	/* Make sure the private key is in the range [1, n-1]. */
+	if (vli_cmp(curve->n, priv, ndigits) != 1)
+		return -EINVAL;
+
+	ecc_swap_digits(priv, privkey, ndigits);
+
+	return 0;
+}
+
+int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits,
+		     const u64 *private_key, u64 *public_key)
+{
+	int ret = 0;
+	struct ecc_point *pk;
+	u64 priv[ndigits];
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+
+	if (!private_key || !curve) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ecc_swap_digits(private_key, priv, ndigits);
+
+	pk = ecc_alloc_point(ndigits);
+	if (!pk) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ecc_point_mult(pk, &curve->g, priv, NULL, curve->p, ndigits);
+	if (ecc_point_is_zero(pk)) {
+		ret = -EAGAIN;
+		goto err_free_point;
+	}
+
+	ecc_swap_digits(pk->x, public_key, ndigits);
+	ecc_swap_digits(pk->y, &public_key[ndigits], ndigits);
+
+err_free_point:
+	ecc_free_point(pk);
+out:
+	return ret;
+}
+
+/* SP800-56A section 5.6.2.3.4 partial verification: ephemeral keys only */
+static int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve,
+				       struct ecc_point *pk)
+{
+	u64 yy[ECC_MAX_DIGITS], xxx[ECC_MAX_DIGITS], w[ECC_MAX_DIGITS];
+
+	/* Check 1: Verify key is not the zero point. */
+	if (ecc_point_is_zero(pk))
+		return -EINVAL;
+
+	/* Check 2: Verify key is in the range [1, p-1]. */
+	if (vli_cmp(curve->p, pk->x, pk->ndigits) != 1)
+		return -EINVAL;
+	if (vli_cmp(curve->p, pk->y, pk->ndigits) != 1)
+		return -EINVAL;
+
+	/* Check 3: Verify that y^2 == (x^3 + a·x + b) mod p */
+	vli_mod_square_fast(yy, pk->y, curve->p, pk->ndigits); /* y^2 */
+	vli_mod_square_fast(xxx, pk->x, curve->p, pk->ndigits); /* x^2 */
+	vli_mod_mult_fast(xxx, xxx, pk->x, curve->p, pk->ndigits); /* x^3 */
+	vli_mod_mult_fast(w, curve->a, pk->x, curve->p, pk->ndigits); /* a·x */
+	vli_mod_add(w, w, curve->b, curve->p, pk->ndigits); /* a·x + b */
+	vli_mod_add(w, w, xxx, curve->p, pk->ndigits); /* x^3 + a·x + b */
+	if (vli_cmp(yy, w, pk->ndigits) != 0) /* Equation */
+		return -EINVAL;
+
+	return 0;
+
+}
+
+int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
+			      const u64 *private_key, const u64 *public_key,
+			      u64 *secret)
+{
+	int ret = 0;
+	struct ecc_point *product, *pk;
+	u64 priv[ndigits];
+	u64 rand_z[ndigits];
+	unsigned int nbytes;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+
+	if (!private_key || !public_key || !curve) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	get_random_bytes(rand_z, nbytes);
+
+	pk = ecc_alloc_point(ndigits);
+	if (!pk) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ecc_swap_digits(public_key, pk->x, ndigits);
+	ecc_swap_digits(&public_key[ndigits], pk->y, ndigits);
+	ret = ecc_is_pubkey_valid_partial(curve, pk);
+	if (ret)
+		goto err_alloc_product;
+
+	ecc_swap_digits(private_key, priv, ndigits);
+
+	product = ecc_alloc_point(ndigits);
+	if (!product) {
+		ret = -ENOMEM;
+		goto err_alloc_product;
+	}
+
+	ecc_point_mult(product, pk, priv, rand_z, curve->p, ndigits);
+
+	ecc_swap_digits(product->x, secret, ndigits);
+
+	if (ecc_point_is_zero(product))
+		ret = -EFAULT;
+
+	ecc_free_point(product);
+err_alloc_product:
+	ecc_free_point(pk);
+out:
+	return ret;
+}
--- linux-4.4.0.orig/crypto/ecc.h
+++ linux-4.4.0/crypto/ecc.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013, Kenneth MacKay
+ * 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.
+ *
+ * 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
+ * HOLDER 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 _CRYPTO_ECC_H
+#define _CRYPTO_ECC_H
+
+#define ECC_MAX_DIGITS	4 /* 256 */
+
+#define ECC_DIGITS_TO_BYTES_SHIFT 3
+
+/**
+ * ecc_is_key_valid() - Validate a given ECDH private key
+ *
+ * @curve_id:		id representing the curve to use
+ * @ndigits:		curve's number of digits
+ * @private_key:	private key to be used for the given curve
+ * @private_key_len:	private key length
+ *
+ * Returns 0 if the key is acceptable, a negative value otherwise
+ */
+int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
+		     const u64 *private_key, unsigned int private_key_len);
+
+/**
+ * ecc_gen_privkey() -  Generates an ECC private key.
+ * The private key is a random integer in the range 0 < random < n, where n is a
+ * prime that is the order of the cyclic subgroup generated by the distinguished
+ * point G.
+ * @curve_id:		id representing the curve to use
+ * @ndigits:		curve number of digits
+ * @private_key:	buffer for storing the generated private key
+ *
+ * Returns 0 if the private key was generated successfully, a negative value
+ * if an error occurred.
+ */
+int ecc_gen_privkey(unsigned int curve_id, unsigned int ndigits, u64 *privkey);
+
+/**
+ * ecc_make_pub_key() - Compute an ECC public key
+ *
+ * @curve_id:		id representing the curve to use
+ * @ndigits:		curve's number of digits
+ * @private_key:	pregenerated private key for the given curve
+ * @public_key:		buffer for storing the generated public key
+ *
+ * Returns 0 if the public key was generated successfully, a negative value
+ * if an error occurred.
+ */
+int ecc_make_pub_key(const unsigned int curve_id, unsigned int ndigits,
+		     const u64 *private_key, u64 *public_key);
+
+/**
+ * crypto_ecdh_shared_secret() - Compute a shared secret
+ *
+ * @curve_id:		id representing the curve to use
+ * @ndigits:		curve's number of digits
+ * @private_key:	private key of part A
+ * @public_key:		public key of counterpart B
+ * @secret:		buffer for storing the calculated shared secret
+ *
+ * Note: It is recommended that you hash the result of crypto_ecdh_shared_secret
+ * before using it for symmetric encryption or HMAC.
+ *
+ * Returns 0 if the shared secret was generated successfully, a negative value
+ * if an error occurred.
+ */
+int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
+			      const u64 *private_key, const u64 *public_key,
+			      u64 *secret);
+#endif
--- linux-4.4.0.orig/crypto/ecc_curve_defs.h
+++ linux-4.4.0/crypto/ecc_curve_defs.h
@@ -0,0 +1,71 @@
+#ifndef _CRYTO_ECC_CURVE_DEFS_H
+#define _CRYTO_ECC_CURVE_DEFS_H
+
+struct ecc_point {
+	u64 *x;
+	u64 *y;
+	u8 ndigits;
+};
+
+struct ecc_curve {
+	char *name;
+	struct ecc_point g;
+	u64 *p;
+	u64 *n;
+	u64 *a;
+	u64 *b;
+};
+
+/* NIST P-192: a = p - 3 */
+static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull,
+				0x188DA80EB03090F6ull };
+static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull, 0x631011ED6B24CDD5ull,
+				0x07192B95FFC8DA78ull };
+static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull,
+				0xFFFFFFFFFFFFFFFFull };
+static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull,
+				0xFFFFFFFFFFFFFFFFull };
+static u64 nist_p192_a[] = { 0xFFFFFFFFFFFFFFFCull, 0xFFFFFFFFFFFFFFFEull,
+				0xFFFFFFFFFFFFFFFEull };
+static u64 nist_p192_b[] = { 0xFEB8DEECC146B9B1ull, 0x0FA7E9AB72243049ull,
+				0x64210519E59C80E7ull };
+static struct ecc_curve nist_p192 = {
+	.name = "nist_192",
+	.g = {
+		.x = nist_p192_g_x,
+		.y = nist_p192_g_y,
+		.ndigits = 3,
+	},
+	.p = nist_p192_p,
+	.n = nist_p192_n,
+	.a = nist_p192_a,
+	.b = nist_p192_b
+};
+
+/* NIST P-256: a = p - 3 */
+static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull,
+				0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull };
+static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull,
+				0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull };
+static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull,
+				0x0000000000000000ull, 0xFFFFFFFF00000001ull };
+static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull };
+static u64 nist_p256_a[] = { 0xFFFFFFFFFFFFFFFCull, 0x00000000FFFFFFFFull,
+				0x0000000000000000ull, 0xFFFFFFFF00000001ull };
+static u64 nist_p256_b[] = { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull,
+				0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull };
+static struct ecc_curve nist_p256 = {
+	.name = "nist_256",
+	.g = {
+		.x = nist_p256_g_x,
+		.y = nist_p256_g_y,
+		.ndigits = 4,
+	},
+	.p = nist_p256_p,
+	.n = nist_p256_n,
+	.a = nist_p256_a,
+	.b = nist_p256_b
+};
+
+#endif
--- linux-4.4.0.orig/crypto/ecdh.c
+++ linux-4.4.0/crypto/ecdh.c
@@ -0,0 +1,153 @@
+/* ECDH key-agreement protocol
+ *
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <crypto/internal/kpp.h>
+#include <crypto/kpp.h>
+#include <crypto/ecdh.h>
+#include <linux/scatterlist.h>
+#include "ecc.h"
+
+struct ecdh_ctx {
+	unsigned int curve_id;
+	unsigned int ndigits;
+	u64 private_key[ECC_MAX_DIGITS];
+	u64 public_key[2 * ECC_MAX_DIGITS];
+	u64 shared_secret[ECC_MAX_DIGITS];
+};
+
+static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
+{
+	return kpp_tfm_ctx(tfm);
+}
+
+static unsigned int ecdh_supported_curve(unsigned int curve_id)
+{
+	switch (curve_id) {
+	case ECC_CURVE_NIST_P192: return 3;
+	case ECC_CURVE_NIST_P256: return 4;
+	default: return 0;
+	}
+}
+
+static int ecdh_set_secret(struct crypto_kpp *tfm, void *buf, unsigned int len)
+{
+	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
+	struct ecdh params;
+	unsigned int ndigits;
+
+	if (crypto_ecdh_decode_key(buf, len, &params) < 0)
+		return -EINVAL;
+
+	ndigits = ecdh_supported_curve(params.curve_id);
+	if (!ndigits)
+		return -EINVAL;
+
+	ctx->curve_id = params.curve_id;
+	ctx->ndigits = ndigits;
+
+	if (!params.key || !params.key_size)
+		return ecc_gen_privkey(ctx->curve_id, ctx->ndigits,
+				       ctx->private_key);
+
+	if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
+			     (const u64 *)params.key, params.key_size) < 0)
+		return -EINVAL;
+
+	memcpy(ctx->private_key, params.key, params.key_size);
+
+	return 0;
+}
+
+static int ecdh_compute_value(struct kpp_request *req)
+{
+	int ret = 0;
+	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
+	size_t copied, nbytes;
+	void *buf;
+
+	nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	if (req->src) {
+		copied = sg_copy_to_buffer(req->src, 1, ctx->public_key,
+					   2 * nbytes);
+		if (copied != 2 * nbytes)
+			return -EINVAL;
+
+		ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
+						ctx->private_key,
+						ctx->public_key,
+						ctx->shared_secret);
+
+		buf = ctx->shared_secret;
+	} else {
+		ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits,
+				       ctx->private_key, ctx->public_key);
+		buf = ctx->public_key;
+		/* Public part is a point thus it has both coordinates */
+		nbytes *= 2;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes);
+	if (copied != nbytes)
+		return -EINVAL;
+
+	return ret;
+}
+
+static int ecdh_max_size(struct crypto_kpp *tfm)
+{
+	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
+	int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	/* Public key is made of two coordinates */
+	return 2 * nbytes;
+}
+
+static void no_exit_tfm(struct crypto_kpp *tfm)
+{
+	return;
+}
+
+static struct kpp_alg ecdh = {
+	.set_secret = ecdh_set_secret,
+	.generate_public_key = ecdh_compute_value,
+	.compute_shared_secret = ecdh_compute_value,
+	.max_size = ecdh_max_size,
+	.exit = no_exit_tfm,
+	.base = {
+		.cra_name = "ecdh",
+		.cra_driver_name = "ecdh-generic",
+		.cra_priority = 100,
+		.cra_module = THIS_MODULE,
+		.cra_ctxsize = sizeof(struct ecdh_ctx),
+	},
+};
+
+static int ecdh_init(void)
+{
+	return crypto_register_kpp(&ecdh);
+}
+
+static void ecdh_exit(void)
+{
+	crypto_unregister_kpp(&ecdh);
+}
+
+module_init(ecdh_init);
+module_exit(ecdh_exit);
+MODULE_ALIAS_CRYPTO("ecdh");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ECDH generic algorithm");
--- linux-4.4.0.orig/crypto/ecdh_helper.c
+++ linux-4.4.0/crypto/ecdh_helper.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <crypto/ecdh.h>
+#include <crypto/kpp.h>
+
+#define ECDH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 2 * sizeof(short))
+
+static inline u8 *ecdh_pack_data(void *dst, const void *src, size_t sz)
+{
+	memcpy(dst, src, sz);
+	return dst + sz;
+}
+
+static inline const u8 *ecdh_unpack_data(void *dst, const void *src, size_t sz)
+{
+	memcpy(dst, src, sz);
+	return src + sz;
+}
+
+int crypto_ecdh_key_len(const struct ecdh *params)
+{
+	return ECDH_KPP_SECRET_MIN_SIZE + params->key_size;
+}
+EXPORT_SYMBOL_GPL(crypto_ecdh_key_len);
+
+int crypto_ecdh_encode_key(char *buf, unsigned int len,
+			   const struct ecdh *params)
+{
+	u8 *ptr = buf;
+	struct kpp_secret secret = {
+		.type = CRYPTO_KPP_SECRET_TYPE_ECDH,
+		.len = len
+	};
+
+	if (unlikely(!buf))
+		return -EINVAL;
+
+	if (len != crypto_ecdh_key_len(params))
+		return -EINVAL;
+
+	ptr = ecdh_pack_data(ptr, &secret, sizeof(secret));
+	ptr = ecdh_pack_data(ptr, &params->curve_id, sizeof(params->curve_id));
+	ptr = ecdh_pack_data(ptr, &params->key_size, sizeof(params->key_size));
+	ecdh_pack_data(ptr, params->key, params->key_size);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_ecdh_encode_key);
+
+int crypto_ecdh_decode_key(const char *buf, unsigned int len,
+			   struct ecdh *params)
+{
+	const u8 *ptr = buf;
+	struct kpp_secret secret;
+
+	if (unlikely(!buf || len < ECDH_KPP_SECRET_MIN_SIZE))
+		return -EINVAL;
+
+	ptr = ecdh_unpack_data(&secret, ptr, sizeof(secret));
+	if (secret.type != CRYPTO_KPP_SECRET_TYPE_ECDH)
+		return -EINVAL;
+
+	ptr = ecdh_unpack_data(&params->curve_id, ptr, sizeof(params->curve_id));
+	ptr = ecdh_unpack_data(&params->key_size, ptr, sizeof(params->key_size));
+	if (secret.len != crypto_ecdh_key_len(params))
+		return -EINVAL;
+
+	/* Don't allocate memory. Set pointer to data
+	 * within the given buffer
+	 */
+	params->key = (void *)ptr;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_ecdh_decode_key);
--- linux-4.4.0.orig/crypto/echainiv.c
+++ linux-4.4.0/crypto/echainiv.c
@@ -1,8 +1,8 @@
 /*
  * echainiv: Encrypted Chain IV Generator
  *
- * This generator generates an IV based on a sequence number by xoring it
- * with a salt and then encrypting it with the same key as used to encrypt
+ * This generator generates an IV based on a sequence number by multiplying
+ * it with a salt and then encrypting it with the same key as used to encrypt
  * the plain text.  This algorithm requires that the block size be equal
  * to the IV size.  It is mainly useful for CBC.
  *
@@ -23,81 +23,17 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/percpu.h>
-#include <linux/spinlock.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 
-#define MAX_IV_SIZE 16
-
-static DEFINE_PER_CPU(u32 [MAX_IV_SIZE / sizeof(u32)], echainiv_iv);
-
-/* We don't care if we get preempted and read/write IVs from the next CPU. */
-static void echainiv_read_iv(u8 *dst, unsigned size)
-{
-	u32 *a = (u32 *)dst;
-	u32 __percpu *b = echainiv_iv;
-
-	for (; size >= 4; size -= 4) {
-		*a++ = this_cpu_read(*b);
-		b++;
-	}
-}
-
-static void echainiv_write_iv(const u8 *src, unsigned size)
-{
-	const u32 *a = (const u32 *)src;
-	u32 __percpu *b = echainiv_iv;
-
-	for (; size >= 4; size -= 4) {
-		this_cpu_write(*b, *a);
-		a++;
-		b++;
-	}
-}
-
-static void echainiv_encrypt_complete2(struct aead_request *req, int err)
-{
-	struct aead_request *subreq = aead_request_ctx(req);
-	struct crypto_aead *geniv;
-	unsigned int ivsize;
-
-	if (err == -EINPROGRESS)
-		return;
-
-	if (err)
-		goto out;
-
-	geniv = crypto_aead_reqtfm(req);
-	ivsize = crypto_aead_ivsize(geniv);
-
-	echainiv_write_iv(subreq->iv, ivsize);
-
-	if (req->iv != subreq->iv)
-		memcpy(req->iv, subreq->iv, ivsize);
-
-out:
-	if (req->iv != subreq->iv)
-		kzfree(subreq->iv);
-}
-
-static void echainiv_encrypt_complete(struct crypto_async_request *base,
-					 int err)
-{
-	struct aead_request *req = base->data;
-
-	echainiv_encrypt_complete2(req, err);
-	aead_request_complete(req, err);
-}
-
 static int echainiv_encrypt(struct aead_request *req)
 {
 	struct crypto_aead *geniv = crypto_aead_reqtfm(req);
 	struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
 	struct aead_request *subreq = aead_request_ctx(req);
-	crypto_completion_t compl;
-	void *data;
+	__be64 nseqno;
+	u64 seqno;
 	u8 *info;
 	unsigned int ivsize = crypto_aead_ivsize(geniv);
 	int err;
@@ -107,8 +43,6 @@
 
 	aead_request_set_tfm(subreq, ctx->child);
 
-	compl = echainiv_encrypt_complete;
-	data = req;
 	info = req->iv;
 
 	if (req->src != req->dst) {
@@ -123,29 +57,30 @@
 			return err;
 	}
 
-	if (unlikely(!IS_ALIGNED((unsigned long)info,
-				 crypto_aead_alignmask(geniv) + 1))) {
-		info = kmalloc(ivsize, req->base.flags &
-				       CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
-								  GFP_ATOMIC);
-		if (!info)
-			return -ENOMEM;
-
-		memcpy(info, req->iv, ivsize);
-	}
-
-	aead_request_set_callback(subreq, req->base.flags, compl, data);
+	aead_request_set_callback(subreq, req->base.flags,
+				  req->base.complete, req->base.data);
 	aead_request_set_crypt(subreq, req->dst, req->dst,
 			       req->cryptlen, info);
 	aead_request_set_ad(subreq, req->assoclen);
 
-	crypto_xor(info, ctx->salt, ivsize);
+	memcpy(&nseqno, info + ivsize - 8, 8);
+	seqno = be64_to_cpu(nseqno);
+	memset(info, 0, ivsize);
+
 	scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
-	echainiv_read_iv(info, ivsize);
 
-	err = crypto_aead_encrypt(subreq);
-	echainiv_encrypt_complete2(req, err);
-	return err;
+	do {
+		u64 a;
+
+		memcpy(&a, ctx->salt + ivsize - 8, 8);
+
+		a |= 1;
+		a *= seqno;
+
+		memcpy(info + ivsize - 8, &a, 8);
+	} while ((ivsize -= 8));
+
+	return crypto_aead_encrypt(subreq);
 }
 
 static int echainiv_decrypt(struct aead_request *req)
@@ -192,8 +127,7 @@
 	alg = crypto_spawn_aead_alg(spawn);
 
 	err = -EINVAL;
-	if (inst->alg.ivsize & (sizeof(u32) - 1) ||
-	    inst->alg.ivsize > MAX_IV_SIZE)
+	if (inst->alg.ivsize & (sizeof(u64) - 1) || !inst->alg.ivsize)
 		goto free_inst;
 
 	inst->alg.encrypt = echainiv_encrypt;
@@ -202,7 +136,6 @@
 	inst->alg.init = aead_init_geniv;
 	inst->alg.exit = aead_exit_geniv;
 
-	inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
 	inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
 	inst->alg.base.cra_ctxsize += inst->alg.ivsize;
 
--- linux-4.4.0.orig/crypto/gcm.c
+++ linux-4.4.0/crypto/gcm.c
@@ -117,7 +117,7 @@
 	struct crypto_ablkcipher *ctr = ctx->ctr;
 	struct {
 		be128 hash;
-		u8 iv[8];
+		u8 iv[16];
 
 		struct crypto_gcm_setkey_result result;
 
@@ -152,10 +152,8 @@
 
 	err = crypto_ablkcipher_encrypt(&data->req);
 	if (err == -EINPROGRESS || err == -EBUSY) {
-		err = wait_for_completion_interruptible(
-			&data->result.completion);
-		if (!err)
-			err = data->result.err;
+		wait_for_completion(&data->result.completion);
+		err = data->result.err;
 	}
 
 	if (err)
@@ -618,7 +616,6 @@
 
 static int crypto_gcm_create_common(struct crypto_template *tmpl,
 				    struct rtattr **tb,
-				    const char *full_name,
 				    const char *ctr_name,
 				    const char *ghash_name)
 {
@@ -639,7 +636,9 @@
 
 	ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type,
 				    CRYPTO_ALG_TYPE_HASH,
-				    CRYPTO_ALG_TYPE_AHASH_MASK);
+				    CRYPTO_ALG_TYPE_AHASH_MASK |
+				    crypto_requires_sync(algt->type,
+							 algt->mask));
 	if (IS_ERR(ghash_alg))
 		return PTR_ERR(ghash_alg);
 
@@ -657,7 +656,8 @@
 		goto err_free_inst;
 
 	err = -EINVAL;
-	if (ghash->digestsize != 16)
+	if (strcmp(ghash->base.cra_name, "ghash") != 0 ||
+	    ghash->digestsize != 16)
 		goto err_drop_ghash;
 
 	crypto_set_skcipher_spawn(&ctx->ctr, aead_crypto_instance(inst));
@@ -669,24 +669,24 @@
 
 	ctr = crypto_skcipher_spawn_alg(&ctx->ctr);
 
-	/* We only support 16-byte blocks. */
-	if (ctr->cra_ablkcipher.ivsize != 16)
-		goto out_put_ctr;
-
-	/* Not a stream cipher? */
+	/* The skcipher algorithm must be CTR mode, using 16-byte blocks. */
 	err = -EINVAL;
-	if (ctr->cra_blocksize != 1)
+	if (strncmp(ctr->cra_name, "ctr(", 4) != 0 ||
+	    ctr->cra_ablkcipher.ivsize != 16 ||
+	    ctr->cra_blocksize != 1)
 		goto out_put_ctr;
 
 	err = -ENAMETOOLONG;
+	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
+		     "gcm(%s", ctr->cra_name + 4) >= CRYPTO_MAX_ALG_NAME)
+		goto out_put_ctr;
+
 	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
 		     "gcm_base(%s,%s)", ctr->cra_driver_name,
 		     ghash_alg->cra_driver_name) >=
 	    CRYPTO_MAX_ALG_NAME)
 		goto out_put_ctr;
 
-	memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
-
 	inst->alg.base.cra_flags = (ghash->base.cra_flags | ctr->cra_flags) &
 				   CRYPTO_ALG_ASYNC;
 	inst->alg.base.cra_priority = (ghash->base.cra_priority +
@@ -727,7 +727,6 @@
 {
 	const char *cipher_name;
 	char ctr_name[CRYPTO_MAX_ALG_NAME];
-	char full_name[CRYPTO_MAX_ALG_NAME];
 
 	cipher_name = crypto_attr_alg_name(tb[1]);
 	if (IS_ERR(cipher_name))
@@ -737,12 +736,7 @@
 	    CRYPTO_MAX_ALG_NAME)
 		return -ENAMETOOLONG;
 
-	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >=
-	    CRYPTO_MAX_ALG_NAME)
-		return -ENAMETOOLONG;
-
-	return crypto_gcm_create_common(tmpl, tb, full_name,
-					ctr_name, "ghash");
+	return crypto_gcm_create_common(tmpl, tb, ctr_name, "ghash");
 }
 
 static struct crypto_template crypto_gcm_tmpl = {
@@ -756,7 +750,6 @@
 {
 	const char *ctr_name;
 	const char *ghash_name;
-	char full_name[CRYPTO_MAX_ALG_NAME];
 
 	ctr_name = crypto_attr_alg_name(tb[1]);
 	if (IS_ERR(ctr_name))
@@ -766,12 +759,7 @@
 	if (IS_ERR(ghash_name))
 		return PTR_ERR(ghash_name);
 
-	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)",
-		     ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME)
-		return -ENAMETOOLONG;
-
-	return crypto_gcm_create_common(tmpl, tb, full_name,
-					ctr_name, ghash_name);
+	return crypto_gcm_create_common(tmpl, tb, ctr_name, ghash_name);
 }
 
 static struct crypto_template crypto_gcm_base_tmpl = {
--- linux-4.4.0.orig/crypto/ghash-generic.c
+++ linux-4.4.0/crypto/ghash-generic.c
@@ -14,24 +14,13 @@
 
 #include <crypto/algapi.h>
 #include <crypto/gf128mul.h>
+#include <crypto/ghash.h>
 #include <crypto/internal/hash.h>
 #include <linux/crypto.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
-#define GHASH_BLOCK_SIZE	16
-#define GHASH_DIGEST_SIZE	16
-
-struct ghash_ctx {
-	struct gf128mul_4k *gf128;
-};
-
-struct ghash_desc_ctx {
-	u8 buffer[GHASH_BLOCK_SIZE];
-	u32 bytes;
-};
-
 static int ghash_init(struct shash_desc *desc)
 {
 	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
@@ -45,6 +34,7 @@
 			const u8 *key, unsigned int keylen)
 {
 	struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
+	be128 k;
 
 	if (keylen != GHASH_BLOCK_SIZE) {
 		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
@@ -53,7 +43,12 @@
 
 	if (ctx->gf128)
 		gf128mul_free_4k(ctx->gf128);
-	ctx->gf128 = gf128mul_init_4k_lle((be128 *)key);
+
+	BUILD_BUG_ON(sizeof(k) != GHASH_BLOCK_SIZE);
+	memcpy(&k, key, GHASH_BLOCK_SIZE); /* avoid violating alignment rules */
+	ctx->gf128 = gf128mul_init_4k_lle(&k);
+	memzero_explicit(&k, GHASH_BLOCK_SIZE);
+
 	if (!ctx->gf128)
 		return -ENOMEM;
 
--- linux-4.4.0.orig/crypto/hash_info.c
+++ linux-4.4.0/crypto/hash_info.c
@@ -31,6 +31,7 @@
 	[HASH_ALGO_TGR_128]	= "tgr128",
 	[HASH_ALGO_TGR_160]	= "tgr160",
 	[HASH_ALGO_TGR_192]	= "tgr192",
+	[HASH_ALGO_SM3_256]	= "sm3-256",
 };
 EXPORT_SYMBOL_GPL(hash_algo_name);
 
@@ -52,5 +53,6 @@
 	[HASH_ALGO_TGR_128]	= TGR128_DIGEST_SIZE,
 	[HASH_ALGO_TGR_160]	= TGR160_DIGEST_SIZE,
 	[HASH_ALGO_TGR_192]	= TGR192_DIGEST_SIZE,
+	[HASH_ALGO_SM3_256]	= SM3256_DIGEST_SIZE,
 };
 EXPORT_SYMBOL_GPL(hash_digest_size);
--- linux-4.4.0.orig/crypto/hmac.c
+++ linux-4.4.0/crypto/hmac.c
@@ -194,11 +194,15 @@
 	salg = shash_attr_alg(tb[1], 0, 0);
 	if (IS_ERR(salg))
 		return PTR_ERR(salg);
+	alg = &salg->base;
 
+	/* The underlying hash algorithm must be unkeyed */
 	err = -EINVAL;
+	if (crypto_shash_alg_has_setkey(salg))
+		goto out_put_alg;
+
 	ds = salg->digestsize;
 	ss = salg->statesize;
-	alg = &salg->base;
 	if (ds > alg->cra_blocksize ||
 	    ss < alg->cra_blocksize)
 		goto out_put_alg;
--- linux-4.4.0.orig/crypto/internal.h
+++ linux-4.4.0/crypto/internal.h
@@ -87,7 +87,6 @@
 void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
 			  struct crypto_alg *nalg);
 void crypto_remove_final(struct list_head *list);
-void crypto_shoot_alg(struct crypto_alg *alg);
 struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
 				      u32 mask);
 void *crypto_create_tfm(struct crypto_alg *alg,
--- linux-4.4.0.orig/crypto/keywrap.c
+++ linux-4.4.0/crypto/keywrap.c
@@ -212,7 +212,7 @@
 			  SEMIBSIZE))
 		ret = -EBADMSG;
 
-	memzero_explicit(&block, sizeof(struct crypto_kw_block));
+	memzero_explicit(block, sizeof(struct crypto_kw_block));
 
 	return ret;
 }
@@ -297,7 +297,7 @@
 	/* establish the IV for the caller to pick up */
 	memcpy(desc->info, block->A, SEMIBSIZE);
 
-	memzero_explicit(&block, sizeof(struct crypto_kw_block));
+	memzero_explicit(block, sizeof(struct crypto_kw_block));
 
 	return 0;
 }
--- linux-4.4.0.orig/crypto/kpp.c
+++ linux-4.4.0/crypto/kpp.c
@@ -0,0 +1,123 @@
+/*
+ * Key-agreement Protocol Primitives (KPP)
+ *
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <linux/cryptouser.h>
+#include <net/netlink.h>
+#include <crypto/kpp.h>
+#include <crypto/internal/kpp.h>
+#include "internal.h"
+
+#ifdef CONFIG_NET
+static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_report_kpp rkpp;
+
+	strncpy(rkpp.type, "kpp", sizeof(rkpp.type));
+
+	if (nla_put(skb, CRYPTOCFGA_REPORT_KPP,
+		    sizeof(struct crypto_report_kpp), &rkpp))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+#else
+static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	return -ENOSYS;
+}
+#endif
+
+static void crypto_kpp_show(struct seq_file *m, struct crypto_alg *alg)
+	__attribute__ ((unused));
+
+static void crypto_kpp_show(struct seq_file *m, struct crypto_alg *alg)
+{
+	seq_puts(m, "type         : kpp\n");
+}
+
+static void crypto_kpp_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_kpp *kpp = __crypto_kpp_tfm(tfm);
+	struct kpp_alg *alg = crypto_kpp_alg(kpp);
+
+	alg->exit(kpp);
+}
+
+static int crypto_kpp_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_kpp *kpp = __crypto_kpp_tfm(tfm);
+	struct kpp_alg *alg = crypto_kpp_alg(kpp);
+
+	if (alg->exit)
+		kpp->base.exit = crypto_kpp_exit_tfm;
+
+	if (alg->init)
+		return alg->init(kpp);
+
+	return 0;
+}
+
+static const struct crypto_type crypto_kpp_type = {
+	.extsize = crypto_alg_extsize,
+	.init_tfm = crypto_kpp_init_tfm,
+#ifdef CONFIG_PROC_FS
+	.show = crypto_kpp_show,
+#endif
+	.report = crypto_kpp_report,
+	.maskclear = ~CRYPTO_ALG_TYPE_MASK,
+	.maskset = CRYPTO_ALG_TYPE_MASK,
+	.type = CRYPTO_ALG_TYPE_KPP,
+	.tfmsize = offsetof(struct crypto_kpp, base),
+};
+
+struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask)
+{
+	return crypto_alloc_tfm(alg_name, &crypto_kpp_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_kpp);
+
+static void kpp_prepare_alg(struct kpp_alg *alg)
+{
+	struct crypto_alg *base = &alg->base;
+
+	base->cra_type = &crypto_kpp_type;
+	base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+	base->cra_flags |= CRYPTO_ALG_TYPE_KPP;
+}
+
+int crypto_register_kpp(struct kpp_alg *alg)
+{
+	struct crypto_alg *base = &alg->base;
+
+	kpp_prepare_alg(alg);
+	return crypto_register_alg(base);
+}
+EXPORT_SYMBOL_GPL(crypto_register_kpp);
+
+void crypto_unregister_kpp(struct kpp_alg *alg)
+{
+	crypto_unregister_alg(&alg->base);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_kpp);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Key-agreement Protocol Primitives");
--- linux-4.4.0.orig/crypto/lrw.c
+++ linux-4.4.0/crypto/lrw.c
@@ -132,7 +132,12 @@
 		return x + ffz(val);
 	}
 
-	return x;
+	/*
+	 * If we get here, then x == 128 and we are incrementing the counter
+	 * from all ones to all zeros. This means we must return index 127, i.e.
+	 * the one corresponding to key2*{ 1,...,1 }.
+	 */
+	return 127;
 }
 
 static int crypt(struct blkcipher_desc *d,
@@ -372,7 +377,7 @@
 	return inst;
 }
 
-static void free(struct crypto_instance *inst)
+static void free_inst(struct crypto_instance *inst)
 {
 	crypto_drop_spawn(crypto_instance_ctx(inst));
 	kfree(inst);
@@ -381,7 +386,7 @@
 static struct crypto_template crypto_tmpl = {
 	.name = "lrw",
 	.alloc = alloc,
-	.free = free,
+	.free = free_inst,
 	.module = THIS_MODULE,
 };
 
--- linux-4.4.0.orig/crypto/mcryptd.c
+++ linux-4.4.0/crypto/mcryptd.c
@@ -80,6 +80,7 @@
 		pr_debug("cpu_queue #%d %p\n", cpu, queue->cpu_queue);
 		crypto_init_queue(&cpu_queue->queue, max_cpu_qlen);
 		INIT_WORK(&cpu_queue->work, mcryptd_queue_worker);
+		spin_lock_init(&cpu_queue->q_lock);
 	}
 	return 0;
 }
@@ -103,15 +104,16 @@
 	int cpu, err;
 	struct mcryptd_cpu_queue *cpu_queue;
 
-	cpu = get_cpu();
-	cpu_queue = this_cpu_ptr(queue->cpu_queue);
-	rctx->tag.cpu = cpu;
+	cpu_queue = raw_cpu_ptr(queue->cpu_queue);
+	spin_lock(&cpu_queue->q_lock);
+	cpu = smp_processor_id();
+	rctx->tag.cpu = smp_processor_id();
 
 	err = crypto_enqueue_request(&cpu_queue->queue, request);
 	pr_debug("enqueue request: cpu %d cpu_queue %p request %p\n",
 		 cpu, cpu_queue, request);
+	spin_unlock(&cpu_queue->q_lock);
 	queue_work_on(cpu, kcrypto_wq, &cpu_queue->work);
-	put_cpu();
 
 	return err;
 }
@@ -164,16 +166,11 @@
 	cpu_queue = container_of(work, struct mcryptd_cpu_queue, work);
 	i = 0;
 	while (i < MCRYPTD_BATCH || single_task_running()) {
-		/*
-		 * preempt_disable/enable is used to prevent
-		 * being preempted by mcryptd_enqueue_request()
-		 */
-		local_bh_disable();
-		preempt_disable();
+
+		spin_lock_bh(&cpu_queue->q_lock);
 		backlog = crypto_get_backlog(&cpu_queue->queue);
 		req = crypto_dequeue_request(&cpu_queue->queue);
-		preempt_enable();
-		local_bh_enable();
+		spin_unlock_bh(&cpu_queue->q_lock);
 
 		if (!req) {
 			mcryptd_opportunistic_flush();
@@ -188,7 +185,7 @@
 		++i;
 	}
 	if (cpu_queue->queue.qlen)
-		queue_work(kcrypto_wq, &cpu_queue->work);
+		queue_work_on(smp_processor_id(), kcrypto_wq, &cpu_queue->work);
 }
 
 void mcryptd_flusher(struct work_struct *__work)
@@ -258,18 +255,22 @@
 	goto out;
 }
 
-static inline void mcryptd_check_internal(struct rtattr **tb, u32 *type,
+static inline bool mcryptd_check_internal(struct rtattr **tb, u32 *type,
 					  u32 *mask)
 {
 	struct crypto_attr_type *algt;
 
 	algt = crypto_get_attr_type(tb);
 	if (IS_ERR(algt))
-		return;
-	if ((algt->type & CRYPTO_ALG_INTERNAL))
-		*type |= CRYPTO_ALG_INTERNAL;
-	if ((algt->mask & CRYPTO_ALG_INTERNAL))
-		*mask |= CRYPTO_ALG_INTERNAL;
+		return false;
+
+	*type |= algt->type & CRYPTO_ALG_INTERNAL;
+	*mask |= algt->mask & CRYPTO_ALG_INTERNAL;
+
+	if (*type & *mask & CRYPTO_ALG_INTERNAL)
+		return true;
+	else
+		return false;
 }
 
 static int mcryptd_hash_init_tfm(struct crypto_tfm *tfm)
@@ -498,7 +499,8 @@
 	u32 mask = 0;
 	int err;
 
-	mcryptd_check_internal(tb, &type, &mask);
+	if (!mcryptd_check_internal(tb, &type, &mask))
+		return -EINVAL;
 
 	salg = shash_attr_alg(tb[1], type, mask);
 	if (IS_ERR(salg))
@@ -526,6 +528,7 @@
 	inst->alg.halg.base.cra_flags = type;
 
 	inst->alg.halg.digestsize = salg->digestsize;
+	inst->alg.halg.statesize = salg->statesize;
 	inst->alg.halg.base.cra_ctxsize = sizeof(struct mcryptd_hash_ctx);
 
 	inst->alg.halg.base.cra_init = mcryptd_hash_init_tfm;
--- linux-4.4.0.orig/crypto/pcbc.c
+++ linux-4.4.0/crypto/pcbc.c
@@ -52,7 +52,7 @@
 	unsigned int nbytes = walk->nbytes;
 	u8 *src = walk->src.virt.addr;
 	u8 *dst = walk->dst.virt.addr;
-	u8 *iv = walk->iv;
+	u8 * const iv = walk->iv;
 
 	do {
 		crypto_xor(iv, src, bsize);
@@ -76,7 +76,7 @@
 	int bsize = crypto_cipher_blocksize(tfm);
 	unsigned int nbytes = walk->nbytes;
 	u8 *src = walk->src.virt.addr;
-	u8 *iv = walk->iv;
+	u8 * const iv = walk->iv;
 	u8 tmpbuf[bsize];
 
 	do {
@@ -89,8 +89,6 @@
 		src += bsize;
 	} while ((nbytes -= bsize) >= bsize);
 
-	memcpy(walk->iv, iv, bsize);
-
 	return nbytes;
 }
 
@@ -130,7 +128,7 @@
 	unsigned int nbytes = walk->nbytes;
 	u8 *src = walk->src.virt.addr;
 	u8 *dst = walk->dst.virt.addr;
-	u8 *iv = walk->iv;
+	u8 * const iv = walk->iv;
 
 	do {
 		fn(crypto_cipher_tfm(tfm), dst, src);
@@ -142,8 +140,6 @@
 		dst += bsize;
 	} while ((nbytes -= bsize) >= bsize);
 
-	memcpy(walk->iv, iv, bsize);
-
 	return nbytes;
 }
 
@@ -156,7 +152,7 @@
 	int bsize = crypto_cipher_blocksize(tfm);
 	unsigned int nbytes = walk->nbytes;
 	u8 *src = walk->src.virt.addr;
-	u8 *iv = walk->iv;
+	u8 * const iv = walk->iv;
 	u8 tmpbuf[bsize];
 
 	do {
@@ -169,8 +165,6 @@
 		src += bsize;
 	} while ((nbytes -= bsize) >= bsize);
 
-	memcpy(walk->iv, iv, bsize);
-
 	return nbytes;
 }
 
--- linux-4.4.0.orig/crypto/pcrypt.c
+++ linux-4.4.0/crypto/pcrypt.c
@@ -130,7 +130,6 @@
 	struct padata_priv *padata = pcrypt_request_padata(preq);
 
 	padata->info = err;
-	req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
 	padata_do_serial(padata);
 }
@@ -254,6 +253,14 @@
 	crypto_free_aead(ctx->child);
 }
 
+static void pcrypt_free(struct aead_instance *inst)
+{
+	struct pcrypt_instance_ctx *ctx = aead_instance_ctx(inst);
+
+	crypto_drop_aead(&ctx->spawn);
+	kfree(inst);
+}
+
 static int pcrypt_init_instance(struct crypto_instance *inst,
 				struct crypto_alg *alg)
 {
@@ -319,6 +326,8 @@
 	inst->alg.encrypt = pcrypt_aead_encrypt;
 	inst->alg.decrypt = pcrypt_aead_decrypt;
 
+	inst->free = pcrypt_free;
+
 	err = aead_register_instance(tmpl, inst);
 	if (err)
 		goto out_drop_aead;
@@ -349,14 +358,6 @@
 	return -EINVAL;
 }
 
-static void pcrypt_free(struct crypto_instance *inst)
-{
-	struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst);
-
-	crypto_drop_aead(&ctx->spawn);
-	kfree(inst);
-}
-
 static int pcrypt_cpumask_change_notify(struct notifier_block *self,
 					unsigned long val, void *data)
 {
@@ -392,7 +393,7 @@
 	int ret;
 
 	pinst->kobj.kset = pcrypt_kset;
-	ret = kobject_add(&pinst->kobj, NULL, name);
+	ret = kobject_add(&pinst->kobj, NULL, "%s", name);
 	if (!ret)
 		kobject_uevent(&pinst->kobj, KOBJ_ADD);
 
@@ -469,7 +470,6 @@
 static struct crypto_template pcrypt_tmpl = {
 	.name = "pcrypt",
 	.create = pcrypt_create,
-	.free = pcrypt_free,
 	.module = THIS_MODULE,
 };
 
@@ -504,11 +504,12 @@
 
 static void __exit pcrypt_exit(void)
 {
+	crypto_unregister_template(&pcrypt_tmpl);
+
 	pcrypt_fini_padata(&pencrypt);
 	pcrypt_fini_padata(&pdecrypt);
 
 	kset_unregister(pcrypt_kset);
-	crypto_unregister_template(&pcrypt_tmpl);
 }
 
 module_init(pcrypt_init);
--- linux-4.4.0.orig/crypto/poly1305_generic.c
+++ linux-4.4.0/crypto/poly1305_generic.c
@@ -51,17 +51,6 @@
 }
 EXPORT_SYMBOL_GPL(crypto_poly1305_init);
 
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
-			   const u8 *key, unsigned int keylen)
-{
-	/* Poly1305 requires a unique key for each tag, which implies that
-	 * we can't set it on the tfm that gets accessed by multiple users
-	 * simultaneously. Instead we expect the key as the first 32 bytes in
-	 * the update() call. */
-	return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(crypto_poly1305_setkey);
-
 static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
 {
 	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
@@ -80,6 +69,11 @@
 	dctx->s[3] = le32_to_cpuvp(key + 12);
 }
 
+/*
+ * Poly1305 requires a unique key for each tag, which implies that we can't set
+ * it on the tfm that gets accessed by multiple users simultaneously. Instead we
+ * expect the key as the first 32 bytes in the update() call.
+ */
 unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
 					const u8 *src, unsigned int srclen)
 {
@@ -285,7 +279,6 @@
 	.init		= crypto_poly1305_init,
 	.update		= crypto_poly1305_update,
 	.final		= crypto_poly1305_final,
-	.setkey		= crypto_poly1305_setkey,
 	.descsize	= sizeof(struct poly1305_desc_ctx),
 	.base		= {
 		.cra_name		= "poly1305",
--- linux-4.4.0.orig/crypto/salsa20_generic.c
+++ linux-4.4.0/crypto/salsa20_generic.c
@@ -186,14 +186,7 @@
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt_block(desc, &walk, 64);
 
-	salsa20_ivsetup(ctx, walk.iv);
-
-	if (likely(walk.nbytes == nbytes))
-	{
-		salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
-				      walk.src.virt.addr, nbytes);
-		return blkcipher_walk_done(desc, &walk, 0);
-	}
+	salsa20_ivsetup(ctx, desc->info);
 
 	while (walk.nbytes >= 64) {
 		salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
--- linux-4.4.0.orig/crypto/scatterwalk.c
+++ linux-4.4.0/crypto/scatterwalk.c
@@ -72,7 +72,8 @@
 
 void scatterwalk_done(struct scatter_walk *walk, int out, int more)
 {
-	if (!(scatterwalk_pagelen(walk) & (PAGE_SIZE - 1)) || !more)
+	if (!more || walk->offset >= walk->sg->offset + walk->sg->length ||
+	    !(walk->offset & (PAGE_SIZE - 1)))
 		scatterwalk_pagedone(walk, out, more);
 }
 EXPORT_SYMBOL_GPL(scatterwalk_done);
--- linux-4.4.0.orig/crypto/shash.c
+++ linux-4.4.0/crypto/shash.c
@@ -24,11 +24,12 @@
 
 static const struct crypto_type crypto_shash_type;
 
-static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
-			   unsigned int keylen)
+int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+		    unsigned int keylen)
 {
 	return -ENOSYS;
 }
+EXPORT_SYMBOL_GPL(shash_no_setkey);
 
 static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
 				  unsigned int keylen)
@@ -40,7 +41,7 @@
 	int err;
 
 	absize = keylen + (alignmask & ~(crypto_tfm_ctx_alignment() - 1));
-	buffer = kmalloc(absize, GFP_KERNEL);
+	buffer = kmalloc(absize, GFP_ATOMIC);
 	if (!buffer)
 		return -ENOMEM;
 
@@ -274,12 +275,14 @@
 
 int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc)
 {
-	struct scatterlist *sg = req->src;
-	unsigned int offset = sg->offset;
 	unsigned int nbytes = req->nbytes;
+	struct scatterlist *sg;
+	unsigned int offset;
 	int err;
 
-	if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
+	if (nbytes &&
+	    (sg = req->src, offset = sg->offset,
+	     nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset))) {
 		void *data;
 
 		data = kmap_atomic(sg_page(sg));
@@ -354,9 +357,10 @@
 	crt->final = shash_async_final;
 	crt->finup = shash_async_finup;
 	crt->digest = shash_async_digest;
+	crt->setkey = shash_async_setkey;
+
+	crt->has_setkey = alg->setkey != shash_no_setkey;
 
-	if (alg->setkey)
-		crt->setkey = shash_async_setkey;
 	if (alg->export)
 		crt->export = shash_async_export;
 	if (alg->import)
--- linux-4.4.0.orig/crypto/skcipher.c
+++ linux-4.4.0/crypto/skcipher.c
@@ -118,6 +118,7 @@
 	skcipher->decrypt = skcipher_decrypt_blkcipher;
 
 	skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher);
+	skcipher->has_setkey = calg->cra_blkcipher.max_keysize;
 
 	return 0;
 }
@@ -210,6 +211,7 @@
 	skcipher->ivsize = crypto_ablkcipher_ivsize(ablkcipher);
 	skcipher->reqsize = crypto_ablkcipher_reqsize(ablkcipher) +
 			    sizeof(struct ablkcipher_request);
+	skcipher->has_setkey = calg->cra_ablkcipher.max_keysize;
 
 	return 0;
 }
--- linux-4.4.0.orig/crypto/tcrypt.c
+++ linux-4.4.0/crypto/tcrypt.c
@@ -291,11 +291,13 @@
 	}
 
 	sg_init_table(sg, np + 1);
-	np--;
+	if (rem)
+		np--;
 	for (k = 0; k < np; k++)
 		sg_set_buf(&sg[k + 1], xbuf[k], PAGE_SIZE);
 
-	sg_set_buf(&sg[k + 1], xbuf[k], rem);
+	if (rem)
+		sg_set_buf(&sg[k + 1], xbuf[k], rem);
 }
 
 static void test_aead_speed(const char *algo, int enc, unsigned int secs,
@@ -410,7 +412,7 @@
 			}
 
 			sg_init_aead(sg, xbuf,
-				    *b_size + (enc ? authsize : 0));
+				    *b_size + (enc ? 0 : authsize));
 
 			sg_init_aead(sgout, xoutbuf,
 				    *b_size + (enc ? authsize : 0));
@@ -418,7 +420,9 @@
 			sg_set_buf(&sg[0], assoc, aad_size);
 			sg_set_buf(&sgout[0], assoc, aad_size);
 
-			aead_request_set_crypt(req, sg, sgout, *b_size, iv);
+			aead_request_set_crypt(req, sg, sgout,
+					       *b_size + (enc ? 0 : authsize),
+					       iv);
 			aead_request_set_ad(req, aad_size);
 
 			if (secs)
--- linux-4.4.0.orig/crypto/testmgr.c
+++ linux-4.4.0/crypto/testmgr.c
@@ -32,6 +32,7 @@
 #include <crypto/rng.h>
 #include <crypto/drbg.h>
 #include <crypto/akcipher.h>
+#include <crypto/kpp.h>
 
 #include "internal.h"
 
@@ -123,6 +124,11 @@
 	unsigned int count;
 };
 
+struct kpp_test_suite {
+	struct kpp_testvec *vecs;
+	unsigned int count;
+};
+
 struct alg_test_desc {
 	const char *alg;
 	int (*test)(const struct alg_test_desc *desc, const char *driver,
@@ -138,6 +144,7 @@
 		struct cprng_test_suite cprng;
 		struct drbg_test_suite drbg;
 		struct akcipher_test_suite akcipher;
+		struct kpp_test_suite kpp;
 	} suite;
 };
 
@@ -488,6 +495,8 @@
 	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
 				  tcrypt_complete, &result);
 
+	iv_len = crypto_aead_ivsize(tfm);
+
 	for (i = 0, j = 0; i < tcount; i++) {
 		if (template[i].np)
 			continue;
@@ -508,7 +517,6 @@
 
 		memcpy(input, template[i].input, template[i].ilen);
 		memcpy(assoc, template[i].assoc, template[i].alen);
-		iv_len = crypto_aead_ivsize(tfm);
 		if (template[i].iv)
 			memcpy(iv, template[i].iv, iv_len);
 		else
@@ -617,7 +625,7 @@
 		j++;
 
 		if (template[i].iv)
-			memcpy(iv, template[i].iv, MAX_IVLEN);
+			memcpy(iv, template[i].iv, iv_len);
 		else
 			memset(iv, 0, MAX_IVLEN);
 
@@ -1846,9 +1854,137 @@
 
 }
 
+static int do_test_kpp(struct crypto_kpp *tfm, struct kpp_testvec *vec,
+		       const char *alg)
+{
+	struct kpp_request *req;
+	void *input_buf = NULL;
+	void *output_buf = NULL;
+	struct tcrypt_result result;
+	unsigned int out_len_max;
+	int err = -ENOMEM;
+	struct scatterlist src, dst;
+
+	req = kpp_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return err;
+
+	init_completion(&result.completion);
+
+	err = crypto_kpp_set_secret(tfm, vec->secret, vec->secret_size);
+	if (err < 0)
+		goto free_req;
+
+	out_len_max = crypto_kpp_maxsize(tfm);
+	output_buf = kzalloc(out_len_max, GFP_KERNEL);
+	if (!output_buf) {
+		err = -ENOMEM;
+		goto free_req;
+	}
+
+	/* Use appropriate parameter as base */
+	kpp_request_set_input(req, NULL, 0);
+	sg_init_one(&dst, output_buf, out_len_max);
+	kpp_request_set_output(req, &dst, out_len_max);
+	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				 tcrypt_complete, &result);
+
+	/* Compute public key */
+	err = wait_async_op(&result, crypto_kpp_generate_public_key(req));
+	if (err) {
+		pr_err("alg: %s: generate public key test failed. err %d\n",
+		       alg, err);
+		goto free_output;
+	}
+	/* Verify calculated public key */
+	if (memcmp(vec->expected_a_public, sg_virt(req->dst),
+		   vec->expected_a_public_size)) {
+		pr_err("alg: %s: generate public key test failed. Invalid output\n",
+		       alg);
+		err = -EINVAL;
+		goto free_output;
+	}
+
+	/* Calculate shared secret key by using counter part (b) public key. */
+	input_buf = kzalloc(vec->b_public_size, GFP_KERNEL);
+	if (!input_buf) {
+		err = -ENOMEM;
+		goto free_output;
+	}
+
+	memcpy(input_buf, vec->b_public, vec->b_public_size);
+	sg_init_one(&src, input_buf, vec->b_public_size);
+	sg_init_one(&dst, output_buf, out_len_max);
+	kpp_request_set_input(req, &src, vec->b_public_size);
+	kpp_request_set_output(req, &dst, out_len_max);
+	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				 tcrypt_complete, &result);
+	err = wait_async_op(&result, crypto_kpp_compute_shared_secret(req));
+	if (err) {
+		pr_err("alg: %s: compute shard secret test failed. err %d\n",
+		       alg, err);
+		goto free_all;
+	}
+	/*
+	 * verify shared secret from which the user will derive
+	 * secret key by executing whatever hash it has chosen
+	 */
+	if (memcmp(vec->expected_ss, sg_virt(req->dst),
+		   vec->expected_ss_size)) {
+		pr_err("alg: %s: compute shared secret test failed. Invalid output\n",
+		       alg);
+		err = -EINVAL;
+	}
+
+free_all:
+	kfree(input_buf);
+free_output:
+	kfree(output_buf);
+free_req:
+	kpp_request_free(req);
+	return err;
+}
+
+static int test_kpp(struct crypto_kpp *tfm, const char *alg,
+		    struct kpp_testvec *vecs, unsigned int tcount)
+{
+	int ret, i;
+
+	for (i = 0; i < tcount; i++) {
+		ret = do_test_kpp(tfm, vecs++, alg);
+		if (ret) {
+			pr_err("alg: %s: test failed on vector %d, err=%d\n",
+			       alg, i + 1, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver,
+			u32 type, u32 mask)
+{
+	struct crypto_kpp *tfm;
+	int err = 0;
+
+	tfm = crypto_alloc_kpp(driver, type | CRYPTO_ALG_INTERNAL, mask);
+	if (IS_ERR(tfm)) {
+		pr_err("alg: kpp: Failed to load tfm for %s: %ld\n",
+		       driver, PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+	if (desc->suite.kpp.vecs)
+		err = test_kpp(tfm, desc->alg, desc->suite.kpp.vecs,
+			       desc->suite.kpp.count);
+
+	crypto_free_kpp(tfm);
+	return err;
+}
+
 static int do_test_rsa(struct crypto_akcipher *tfm,
 		       struct akcipher_testvec *vecs)
 {
+	char *xbuf[XBUFSIZE];
 	struct akcipher_request *req;
 	void *outbuf_enc = NULL;
 	void *outbuf_dec = NULL;
@@ -1857,9 +1993,12 @@
 	int err = -ENOMEM;
 	struct scatterlist src, dst, src_tab[2];
 
+	if (testmgr_alloc_buf(xbuf))
+		return err;
+
 	req = akcipher_request_alloc(tfm, GFP_KERNEL);
 	if (!req)
-		return err;
+		goto free_xbuf;
 
 	init_completion(&result.completion);
 
@@ -1877,9 +2016,14 @@
 	if (!outbuf_enc)
 		goto free_req;
 
+	if (WARN_ON(vecs->m_size > PAGE_SIZE))
+		goto free_all;
+
+	memcpy(xbuf[0], vecs->m, vecs->m_size);
+
 	sg_init_table(src_tab, 2);
-	sg_set_buf(&src_tab[0], vecs->m, 8);
-	sg_set_buf(&src_tab[1], vecs->m + 8, vecs->m_size - 8);
+	sg_set_buf(&src_tab[0], xbuf[0], 8);
+	sg_set_buf(&src_tab[1], xbuf[0] + 8, vecs->m_size - 8);
 	sg_init_one(&dst, outbuf_enc, out_len_max);
 	akcipher_request_set_crypt(req, src_tab, &dst, vecs->m_size,
 				   out_len_max);
@@ -1898,7 +2042,7 @@
 		goto free_all;
 	}
 	/* verify that encrypted message is equal to expected */
-	if (memcmp(vecs->c, sg_virt(req->dst), vecs->c_size)) {
+	if (memcmp(vecs->c, outbuf_enc, vecs->c_size)) {
 		pr_err("alg: rsa: encrypt test failed. Invalid output\n");
 		err = -EINVAL;
 		goto free_all;
@@ -1913,7 +2057,13 @@
 		err = -ENOMEM;
 		goto free_all;
 	}
-	sg_init_one(&src, vecs->c, vecs->c_size);
+
+	if (WARN_ON(vecs->c_size > PAGE_SIZE))
+		goto free_all;
+
+	memcpy(xbuf[0], vecs->c, vecs->c_size);
+
+	sg_init_one(&src, xbuf[0], vecs->c_size);
 	sg_init_one(&dst, outbuf_dec, out_len_max);
 	init_completion(&result.completion);
 	akcipher_request_set_crypt(req, &src, &dst, vecs->c_size, out_len_max);
@@ -1940,6 +2090,8 @@
 	kfree(outbuf_enc);
 free_req:
 	akcipher_request_free(req);
+free_xbuf:
+	testmgr_free_buf(xbuf);
 	return err;
 }
 
@@ -2743,6 +2895,16 @@
 			}
 		}
 	}, {
+		.alg = "dh",
+		.test = alg_test_kpp,
+		.fips_allowed = 1,
+		.suite = {
+			.kpp = {
+				.vecs = dh_tv_template,
+				.count = DH_TEST_VECTORS
+			}
+		}
+	}, {
 		.alg = "digest_null",
 		.test = alg_test_null,
 	}, {
@@ -3171,6 +3333,16 @@
 			}
 		}
 	}, {
+		.alg = "ecdh",
+		.test = alg_test_kpp,
+		.fips_allowed = 1,
+		.suite = {
+			.kpp = {
+				.vecs = ecdh_tv_template,
+				.count = ECDH_TEST_VECTORS
+			}
+		}
+	}, {
 		.alg = "gcm(aes)",
 		.test = alg_test_aead,
 		.fips_allowed = 1,
--- linux-4.4.0.orig/crypto/testmgr.h
+++ linux-4.4.0/crypto/testmgr.h
@@ -136,6 +136,17 @@
 	bool public_key_vec;
 };
 
+struct kpp_testvec {
+	unsigned char *secret;
+	unsigned char *b_public;
+	unsigned char *expected_a_public;
+	unsigned char *expected_ss;
+	unsigned short secret_size;
+	unsigned short b_public_size;
+	unsigned short expected_a_public_size;
+	unsigned short expected_ss_size;
+};
+
 static char zeroed_string[48];
 
 /*
@@ -333,6 +344,318 @@
 	}
 };
 
+#define DH_TEST_VECTORS 2
+
+struct kpp_testvec dh_tv_template[] = {
+	{
+	.secret =
+#ifdef __LITTLE_ENDIAN
+	"\x01\x00" /* type */
+	"\x11\x02" /* len */
+	"\x00\x01\x00\x00" /* key_size */
+	"\x00\x01\x00\x00" /* p_size */
+	"\x01\x00\x00\x00" /* g_size */
+#else
+	"\x00\x01" /* type */
+	"\x02\x11" /* len */
+	"\x00\x00\x01\x00" /* key_size */
+	"\x00\x00\x01\x00" /* p_size */
+	"\x00\x00\x00\x01" /* g_size */
+#endif
+	/* xa */
+	"\x44\xc1\x48\x36\xa7\x2b\x6f\x4e\x43\x03\x68\xad\x31\x00\xda\xf3"
+	"\x2a\x01\xa8\x32\x63\x5f\x89\x32\x1f\xdf\x4c\xa1\x6a\xbc\x10\x15"
+	"\x90\x35\xc9\x26\x41\xdf\x7b\xaa\x56\x56\x3d\x85\x44\xb5\xc0\x8e"
+	"\x37\x83\x06\x50\xb3\x5f\x0e\x28\x2c\xd5\x46\x15\xe3\xda\x7d\x74"
+	"\x87\x13\x91\x4f\xd4\x2d\xf6\xc7\x5e\x14\x2c\x11\xc2\x26\xb4\x3a"
+	"\xe3\xb2\x36\x20\x11\x3b\x22\xf2\x06\x65\x66\xe2\x57\x58\xf8\x22"
+	"\x1a\x94\xbd\x2b\x0e\x8c\x55\xad\x61\x23\x45\x2b\x19\x1e\x63\x3a"
+	"\x13\x61\xe3\xa0\x79\x70\x3e\x6d\x98\x32\xbc\x7f\x82\xc3\x11\xd8"
+	"\xeb\x53\xb5\xfc\xb5\xd5\x3c\x4a\xea\x92\x3e\x01\xce\x15\x65\xd4"
+	"\xaa\x85\xc1\x11\x90\x83\x31\x6e\xfe\xe7\x7f\x7d\xed\xab\xf9\x29"
+	"\xf8\xc7\xf1\x68\xc6\xb7\xe4\x1f\x2f\x28\xa0\xc9\x1a\x50\x64\x29"
+	"\x4b\x01\x6d\x1a\xda\x46\x63\x21\x07\x40\x8c\x8e\x4c\x6f\xb5\xe5"
+	"\x12\xf3\xc2\x1b\x48\x27\x5e\x27\x01\xb1\xaa\xed\x68\x9b\x83\x18"
+	"\x8f\xb1\xeb\x1f\x04\xd1\x3c\x79\xed\x4b\xf7\x0a\x33\xdc\xe0\xc6"
+	"\xd8\x02\x51\x59\x00\x74\x30\x07\x4c\x2d\xac\xe4\x13\xf1\x80\xf0"
+	"\xce\xfa\xff\xa9\xce\x29\x46\xdd\x9d\xad\xd1\xc3\xc6\x58\x1a\x63"
+	/* p */
+	"\xb9\x36\x3a\xf1\x82\x1f\x60\xd3\x22\x47\xb8\xbc\x2d\x22\x6b\x81"
+	"\x7f\xe8\x20\x06\x09\x23\x73\x49\x9a\x59\x8b\x35\x25\xf8\x31\xbc"
+	"\x7d\xa8\x1c\x9d\x56\x0d\x1a\xf7\x4b\x4f\x96\xa4\x35\x77\x6a\x89"
+	"\xab\x42\x00\x49\x21\x71\xed\x28\x16\x1d\x87\x5a\x10\xa7\x9c\x64"
+	"\x94\xd4\x87\x3d\x28\xef\x44\xfe\x4b\xe2\xb4\x15\x8c\x82\xa6\xf3"
+	"\x50\x5f\xa8\xe8\xa2\x60\xe7\x00\x86\x78\x05\xd4\x78\x19\xa1\x98"
+	"\x62\x4e\x4a\x00\x78\x56\x96\xe6\xcf\xd7\x10\x1b\x74\x5d\xd0\x26"
+	"\x61\xdb\x6b\x32\x09\x51\xd8\xa5\xfd\x54\x16\x71\x01\xb3\x39\xe6"
+	"\x4e\x69\xb1\xd7\x06\x8f\xd6\x1e\xdc\x72\x25\x26\x74\xc8\x41\x06"
+	"\x5c\xd1\x26\x5c\xb0\x2f\xf9\x59\x13\xc1\x2a\x0f\x78\xea\x7b\xf7"
+	"\xbd\x59\xa0\x90\x1d\xfc\x33\x5b\x4c\xbf\x05\x9c\x3a\x3f\x69\xa2"
+	"\x45\x61\x4e\x10\x6a\xb3\x17\xc5\x68\x30\xfb\x07\x5f\x34\xc6\xfb"
+	"\x73\x07\x3c\x70\xf6\xae\xe7\x72\x84\xc3\x18\x81\x8f\xe8\x11\x1f"
+	"\x3d\x83\x83\x01\x2a\x14\x73\xbf\x32\x32\x2e\xc9\x4d\xdb\x2a\xca"
+	"\xee\x71\xf9\xda\xad\xe8\x82\x0b\x4d\x0c\x1f\xb6\x1d\xef\x00\x67"
+	"\x74\x3d\x95\xe0\xb7\xc4\x30\x8a\x24\x87\x12\x47\x27\x70\x0d\x73"
+	/* g */
+	"\x02",
+	.b_public =
+	"\x2a\x67\x5c\xfd\x63\x5d\xc0\x97\x0a\x8b\xa2\x1f\xf8\x8a\xcb\x54"
+	"\xca\x2f\xd3\x49\x3f\x01\x8e\x87\xfe\xcc\x94\xa0\x3e\xd4\x26\x79"
+	"\x9a\x94\x3c\x11\x81\x58\x5c\x60\x3d\xf5\x98\x90\x89\x64\x62\x1f"
+	"\xbd\x05\x6d\x2b\xcd\x84\x40\x9b\x4a\x1f\xe0\x19\xf1\xca\x20\xb3"
+	"\x4e\xa0\x4f\x15\xcc\xa5\xfe\xa5\xb4\xf5\x0b\x18\x7a\x5a\x37\xaa"
+	"\x58\x00\x19\x7f\xe2\xa3\xd9\x1c\x44\x57\xcc\xde\x2e\xc1\x38\xea"
+	"\xeb\xe3\x90\x40\xc4\x6c\xf7\xcd\xe9\x22\x50\x71\xf5\x7c\xdb\x37"
+	"\x0e\x80\xc3\xed\x7e\xb1\x2b\x2f\xbe\x71\xa6\x11\xa5\x9d\xf5\x39"
+	"\xf1\xa2\xe5\x85\xbc\x25\x91\x4e\x84\x8d\x26\x9f\x4f\xe6\x0f\xa6"
+	"\x2b\x6b\xf9\x0d\xaf\x6f\xbb\xfa\x2d\x79\x15\x31\x57\xae\x19\x60"
+	"\x22\x0a\xf5\xfd\x98\x0e\xbf\x5d\x49\x75\x58\x37\xbc\x7f\xf5\x21"
+	"\x56\x1e\xd5\xb3\x50\x0b\xca\x96\xf3\xd1\x3f\xb3\x70\xa8\x6d\x63"
+	"\x48\xfb\x3d\xd7\x29\x91\x45\xb5\x48\xcd\xb6\x78\x30\xf2\x3f\x1e"
+	"\xd6\x22\xd6\x35\x9b\xf9\x1f\x85\xae\xab\x4b\xd7\xe0\xc7\x86\x67"
+	"\x3f\x05\x7f\xa6\x0d\x2f\x0d\xbf\x53\x5f\x4d\x2c\x6d\x5e\x57\x40"
+	"\x30\x3a\x23\x98\xf9\xb4\x32\xf5\x32\x83\xdd\x0b\xae\x33\x97\x2f",
+	.expected_a_public =
+	"\x5c\x24\xdf\xeb\x5b\x4b\xf8\xc5\xef\x39\x48\x82\xe0\x1e\x62\xee"
+	"\x8a\xae\xdf\x93\x6c\x2b\x16\x95\x92\x16\x3f\x16\x7b\x75\x03\x85"
+	"\xd9\xf1\x69\xc2\x14\x87\x45\xfc\xa4\x19\xf6\xf0\xa4\xf3\xec\xd4"
+	"\x6c\x5c\x03\x3b\x94\xc2\x2f\x92\xe4\xce\xb3\xe4\x72\xe8\x17\xe6"
+	"\x23\x7e\x00\x01\x09\x59\x13\xbf\xc1\x2f\x99\xa9\x07\xaa\x02\x23"
+	"\x4a\xca\x39\x4f\xbc\xec\x0f\x27\x4f\x19\x93\x6c\xb9\x30\x52\xfd"
+	"\x2b\x9d\x86\xf1\x06\x1e\xb6\x56\x27\x4a\xc9\x8a\xa7\x8a\x48\x5e"
+	"\xb5\x60\xcb\xdf\xff\x03\x26\x10\xbf\x90\x8f\x46\x60\xeb\x9b\x9a"
+	"\xd6\x6f\x44\x91\x03\x92\x18\x2c\x96\x5e\x40\x19\xfb\xf4\x4f\x3a"
+	"\x02\x7b\xaf\xcc\x22\x20\x79\xb9\xf8\x9f\x8f\x85\x6b\xec\x44\xbb"
+	"\xe6\xa8\x8e\xb1\xe8\x2c\xee\x64\xee\xf8\xbd\x00\xf3\xe2\x2b\x93"
+	"\xcd\xe7\xc4\xdf\xc9\x19\x46\xfe\xb6\x07\x73\xc1\x8a\x64\x79\x26"
+	"\xe7\x30\xad\x2a\xdf\xe6\x8f\x59\xf5\x81\xbf\x4a\x29\x91\xe7\xb7"
+	"\xcf\x48\x13\x27\x75\x79\x40\xd9\xd6\x32\x52\x4e\x6a\x86\xae\x6f"
+	"\xc2\xbf\xec\x1f\xc2\x69\xb2\xb6\x59\xe5\xa5\x17\xa4\x77\xb7\x62"
+	"\x46\xde\xe8\xd2\x89\x78\x9a\xef\xa3\xb5\x8f\x26\xec\x80\xda\x39",
+	.expected_ss =
+	"\x8f\xf3\xac\xa2\xea\x22\x11\x5c\x45\x65\x1a\x77\x75\x2e\xcf\x46"
+	"\x23\x14\x1e\x67\x53\x4d\x35\xb0\x38\x1d\x4e\xb9\x41\x9a\x21\x24"
+	"\x6e\x9f\x40\xfe\x90\x51\xb1\x06\xa4\x7b\x87\x17\x2f\xe7\x5e\x22"
+	"\xf0\x7b\x54\x84\x0a\xac\x0a\x90\xd2\xd7\xe8\x7f\xe7\xe3\x30\x75"
+	"\x01\x1f\x24\x75\x56\xbe\xcc\x8d\x1e\x68\x0c\x41\x72\xd3\xfa\xbb"
+	"\xe5\x9c\x60\xc7\x28\x77\x0c\xbe\x89\xab\x08\xd6\x21\xe7\x2e\x1a"
+	"\x58\x7a\xca\x4f\x22\xf3\x2b\x30\xfd\xf4\x98\xc1\xa3\xf8\xf6\xcc"
+	"\xa9\xe4\xdb\x5b\xee\xd5\x5c\x6f\x62\x4c\xd1\x1a\x02\x2a\x23\xe4"
+	"\xb5\x57\xf3\xf9\xec\x04\x83\x54\xfe\x08\x5e\x35\xac\xfb\xa8\x09"
+	"\x82\x32\x60\x11\xb2\x16\x62\x6b\xdf\xda\xde\x9c\xcb\x63\x44\x6c"
+	"\x59\x26\x6a\x8f\xb0\x24\xcb\xa6\x72\x48\x1e\xeb\xe0\xe1\x09\x44"
+	"\xdd\xee\x66\x6d\x84\xcf\xa5\xc1\xb8\x36\x74\xd3\x15\x96\xc3\xe4"
+	"\xc6\x5a\x4d\x23\x97\x0c\x5c\xcb\xa9\xf5\x29\xc2\x0e\xff\x93\x82"
+	"\xd3\x34\x49\xad\x64\xa6\xb1\xc0\x59\x28\x75\x60\xa7\x8a\xb0\x11"
+	"\x56\x89\x42\x74\x11\xf5\xf6\x5e\x6f\x16\x54\x6a\xb1\x76\x4d\x50"
+	"\x8a\x68\xc1\x5b\x82\xb9\x0d\x00\x32\x50\xed\x88\x87\x48\x92\x17",
+	.secret_size = 529,
+	.b_public_size = 256,
+	.expected_a_public_size = 256,
+	.expected_ss_size = 256,
+	},
+	{
+	.secret =
+#ifdef __LITTLE_ENDIAN
+	"\x01\x00" /* type */
+	"\x11\x02" /* len */
+	"\x00\x01\x00\x00" /* key_size */
+	"\x00\x01\x00\x00" /* p_size */
+	"\x01\x00\x00\x00" /* g_size */
+#else
+	"\x00\x01" /* type */
+	"\x02\x11" /* len */
+	"\x00\x00\x01\x00" /* key_size */
+	"\x00\x00\x01\x00" /* p_size */
+	"\x00\x00\x00\x01" /* g_size */
+#endif
+	/* xa */
+	"\x4d\x75\xa8\x6e\xba\x23\x3a\x0c\x63\x56\xc8\xc9\x5a\xa7\xd6\x0e"
+	"\xed\xae\x40\x78\x87\x47\x5f\xe0\xa7\x7b\xba\x84\x88\x67\x4e\xe5"
+	"\x3c\xcc\x5c\x6a\xe7\x4a\x20\xec\xbe\xcb\xf5\x52\x62\x9f\x37\x80"
+	"\x0c\x72\x7b\x83\x66\xa4\xf6\x7f\x95\x97\x1c\x6a\x5c\x7e\xf1\x67"
+	"\x37\xb3\x93\x39\x3d\x0b\x55\x35\xd9\xe5\x22\x04\x9f\xf8\xc1\x04"
+	"\xce\x13\xa5\xac\xe1\x75\x05\xd1\x2b\x53\xa2\x84\xef\xb1\x18\xf4"
+	"\x66\xdd\xea\xe6\x24\x69\x5a\x49\xe0\x7a\xd8\xdf\x1b\xb7\xf1\x6d"
+	"\x9b\x50\x2c\xc8\x1c\x1c\xa3\xb4\x37\xfb\x66\x3f\x67\x71\x73\xa9"
+	"\xff\x5f\xd9\xa2\x25\x6e\x25\x1b\x26\x54\xbf\x0c\xc6\xdb\xea\x0a"
+	"\x52\x6c\x16\x7c\x27\x68\x15\x71\x58\x73\x9d\xe6\xc2\x80\xaa\x97"
+	"\x31\x66\xfb\xa6\xfb\xfd\xd0\x9c\x1d\xbe\x81\x48\xf5\x9a\x32\xf1"
+	"\x69\x62\x18\x78\xae\x72\x36\xe6\x94\x27\xd1\xff\x18\x4f\x28\x6a"
+	"\x16\xbd\x6a\x60\xee\xe5\xf9\x6d\x16\xe4\xb8\xa6\x41\x9b\x23\x7e"
+	"\xf7\x9d\xd1\x1d\x03\x15\x66\x3a\xcf\xb6\x2c\x13\x96\x2c\x52\x21"
+	"\xe4\x2d\x48\x7a\x8a\x5d\xb2\x88\xed\x98\x61\x79\x8b\x6a\x1e\x5f"
+	"\xd0\x8a\x2d\x99\x5a\x2b\x0f\xbc\xef\x53\x8f\x32\xc1\xa2\x99\x26"
+	/* p */
+	"\xb9\x36\x3a\xf1\x82\x1f\x60\xd3\x22\x47\xb8\xbc\x2d\x22\x6b\x81"
+	"\x7f\xe8\x20\x06\x09\x23\x73\x49\x9a\x59\x8b\x35\x25\xf8\x31\xbc"
+	"\x7d\xa8\x1c\x9d\x56\x0d\x1a\xf7\x4b\x4f\x96\xa4\x35\x77\x6a\x89"
+	"\xab\x42\x00\x49\x21\x71\xed\x28\x16\x1d\x87\x5a\x10\xa7\x9c\x64"
+	"\x94\xd4\x87\x3d\x28\xef\x44\xfe\x4b\xe2\xb4\x15\x8c\x82\xa6\xf3"
+	"\x50\x5f\xa8\xe8\xa2\x60\xe7\x00\x86\x78\x05\xd4\x78\x19\xa1\x98"
+	"\x62\x4e\x4a\x00\x78\x56\x96\xe6\xcf\xd7\x10\x1b\x74\x5d\xd0\x26"
+	"\x61\xdb\x6b\x32\x09\x51\xd8\xa5\xfd\x54\x16\x71\x01\xb3\x39\xe6"
+	"\x4e\x69\xb1\xd7\x06\x8f\xd6\x1e\xdc\x72\x25\x26\x74\xc8\x41\x06"
+	"\x5c\xd1\x26\x5c\xb0\x2f\xf9\x59\x13\xc1\x2a\x0f\x78\xea\x7b\xf7"
+	"\xbd\x59\xa0\x90\x1d\xfc\x33\x5b\x4c\xbf\x05\x9c\x3a\x3f\x69\xa2"
+	"\x45\x61\x4e\x10\x6a\xb3\x17\xc5\x68\x30\xfb\x07\x5f\x34\xc6\xfb"
+	"\x73\x07\x3c\x70\xf6\xae\xe7\x72\x84\xc3\x18\x81\x8f\xe8\x11\x1f"
+	"\x3d\x83\x83\x01\x2a\x14\x73\xbf\x32\x32\x2e\xc9\x4d\xdb\x2a\xca"
+	"\xee\x71\xf9\xda\xad\xe8\x82\x0b\x4d\x0c\x1f\xb6\x1d\xef\x00\x67"
+	"\x74\x3d\x95\xe0\xb7\xc4\x30\x8a\x24\x87\x12\x47\x27\x70\x0d\x73"
+	/* g */
+	"\x02",
+	.b_public =
+	"\x99\x4d\xd9\x01\x84\x8e\x4a\x5b\xb8\xa5\x64\x8c\x6c\x00\x5c\x0e"
+	"\x1e\x1b\xee\x5d\x9f\x53\xe3\x16\x70\x01\xed\xbf\x4f\x14\x36\x6e"
+	"\xe4\x43\x45\x43\x49\xcc\xb1\xb0\x2a\xc0\x6f\x22\x55\x42\x17\x94"
+	"\x18\x83\xd7\x2a\x5c\x51\x54\xf8\x4e\x7c\x10\xda\x76\x68\x57\x77"
+	"\x1e\x62\x03\x30\x04\x7b\x4c\x39\x9c\x54\x01\x54\xec\xef\xb3\x55"
+	"\xa4\xc0\x24\x6d\x3d\xbd\xcc\x46\x5b\x00\x96\xc7\xea\x93\xd1\x3f"
+	"\xf2\x6a\x72\xe3\xf2\xc1\x92\x24\x5b\xda\x48\x70\x2c\xa9\x59\x97"
+	"\x19\xb1\xd6\x54\xb3\x9c\x2e\xb0\x63\x07\x9b\x5e\xac\xb5\xf2\xb1"
+	"\x5b\xf8\xf3\xd7\x2d\x37\x9b\x68\x6c\xf8\x90\x07\xbc\x37\x9a\xa5"
+	"\xe2\x91\x12\x25\x47\x77\xe3\x3d\xb2\x95\x69\x44\x0b\x91\x1e\xaf"
+	"\x7c\x8c\x7c\x34\x41\x6a\xab\x60\x6e\xc6\x52\xec\x7e\x94\x0a\x37"
+	"\xec\x98\x90\xdf\x3f\x02\xbd\x23\x52\xdd\xd9\xe5\x31\x80\x74\x25"
+	"\xb6\xd2\xd3\xcc\xd5\xcc\x6d\xf9\x7e\x4d\x78\xab\x77\x51\xfa\x77"
+	"\x19\x94\x49\x8c\x05\xd4\x75\xed\xd2\xb3\x64\x57\xe0\x52\x99\xc0"
+	"\x83\xe3\xbb\x5e\x2b\xf1\xd2\xc0\xb1\x37\x36\x0b\x7c\xb5\x63\x96"
+	"\x8e\xde\x04\x23\x11\x95\x62\x11\x9a\xce\x6f\x63\xc8\xd5\xd1\x8f",
+	.expected_a_public =
+	"\x90\x89\xe4\x82\xd6\x0a\xcf\x1a\xae\xce\x1b\x66\xa7\x19\x71\x18"
+	"\x8f\x95\x4b\x5b\x80\x45\x4a\x5a\x43\x99\x4d\x37\xcf\xa3\xa7\x28"
+	"\x9c\xc7\x73\xf1\xb2\x17\xf6\x99\xe3\x6b\x56\xcb\x3e\x35\x60\x7d"
+	"\x65\xc7\x84\x6b\x3e\x60\xee\xcd\xd2\x70\xe7\xc9\x32\x1c\xf0\xb4"
+	"\xf9\x52\xd9\x88\x75\xfd\x40\x2c\xa7\xbe\x19\x1c\x0a\xae\x93\xe1"
+	"\x71\xc7\xcd\x4f\x33\x5c\x10\x7d\x39\x56\xfc\x73\x84\xb2\x67\xc3"
+	"\x77\x26\x20\x97\x2b\xf8\x13\x43\x93\x9c\x9a\xa4\x08\xc7\x34\x83"
+	"\xe6\x98\x61\xe7\x16\x30\x2c\xb1\xdb\x2a\xb2\xcc\xc3\x02\xa5\x3c"
+	"\x71\x50\x14\x83\xc7\xbb\xa4\xbe\x98\x1b\xfe\xcb\x43\xe9\x97\x62"
+	"\xd6\xf0\x8c\xcb\x1c\xba\x1e\xa8\xa6\xa6\x50\xfc\x85\x7d\x47\xbf"
+	"\xf4\x3e\x23\xd3\x5f\xb2\x71\x3e\x40\x94\xaa\x87\x83\x2c\x6c\x8e"
+	"\x60\xfd\xdd\xf7\xf4\x76\x03\xd3\x1d\xec\x18\x51\xa3\xf2\x44\x1a"
+	"\x3f\xb4\x7c\x18\x0d\x68\x65\x92\x54\x0d\x2d\x81\x16\xf1\x84\x66"
+	"\x89\x92\xd0\x1a\x5e\x1f\x42\x46\x5b\xe5\x83\x86\x80\xd9\xcd\x3a"
+	"\x5a\x2f\xb9\x59\x9b\xe4\x43\x84\x64\xf3\x09\x1a\x0a\xa2\x64\x0f"
+	"\x77\x4e\x8d\x8b\xe6\x88\xd1\xfc\xaf\x8f\xdf\x1d\xbc\x31\xb3\xbd",
+	.expected_ss =
+	"\x34\xc3\x35\x14\x88\x46\x26\x23\x97\xbb\xdd\x28\x5c\x94\xf6\x47"
+	"\xca\xb3\x19\xaf\xca\x44\x9b\xc2\x7d\x89\xfd\x96\x14\xfd\x6d\x58"
+	"\xd8\xc4\x6b\x61\x2a\x0d\xf2\x36\x45\xc8\xe4\xa4\xed\x81\x53\x81"
+	"\x66\x1e\xe0\x5a\xb1\x78\x2d\x0b\x5c\xb4\xd1\xfc\x90\xc6\x9c\xdb"
+	"\x5a\x30\x0b\x14\x7d\xbe\xb3\x7d\xb1\xb2\x76\x3c\x6c\xef\x74\x6b"
+	"\xe7\x1f\x64\x0c\xab\x65\xe1\x76\x5c\x3d\x83\xb5\x8a\xfb\xaf\x0f"
+	"\xf2\x06\x14\x8f\xa0\xf6\xc1\x89\x78\xf2\xba\x72\x73\x3c\xf7\x76"
+	"\x21\x67\xbc\x24\x31\xb8\x09\x65\x0f\x0c\x02\x32\x4a\x98\x14\xfc"
+	"\x72\x2c\x25\x60\x68\x5f\x2f\x30\x1e\x5b\xf0\x3b\xd1\xa2\x87\xa0"
+	"\x54\xdf\xdb\xc0\xee\x0a\x0f\x47\xc9\x90\x20\x2c\xf9\xe3\x52\xad"
+	"\x27\x65\x8d\x54\x8d\xa8\xa1\xf3\xed\x15\xd4\x94\x28\x90\x31\x93"
+	"\x1b\xc0\x51\xbb\x43\x5d\x76\x3b\x1d\x2a\x71\x50\xea\x5d\x48\x94"
+	"\x7f\x6f\xf1\x48\xdb\x30\xe5\xae\x64\x79\xd9\x7a\xdb\xc6\xff\xd8"
+	"\x5e\x5a\x64\xbd\xf6\x85\x04\xe8\x28\x6a\xac\xef\xce\x19\x8e\x9a"
+	"\xfe\x75\xc0\x27\x69\xe3\xb3\x7b\x21\xa7\xb1\x16\xa4\x85\x23\xee"
+	"\xb0\x1b\x04\x6e\xbd\xab\x16\xde\xfd\x86\x6b\xa9\x95\xd7\x0b\xfd",
+	.secret_size = 529,
+	.b_public_size = 256,
+	.expected_a_public_size = 256,
+	.expected_ss_size = 256,
+	}
+};
+
+#ifdef CONFIG_CRYPTO_FIPS
+#define ECDH_TEST_VECTORS 1
+#else
+#define ECDH_TEST_VECTORS 2
+#endif
+struct kpp_testvec ecdh_tv_template[] = {
+	{
+#ifndef CONFIG_CRYPTO_FIPS
+	.secret =
+#ifdef __LITTLE_ENDIAN
+	"\x02\x00" /* type */
+	"\x20\x00" /* len */
+	"\x01\x00" /* curve_id */
+	"\x18\x00" /* key_size */
+#else
+	"\x00\x02" /* type */
+	"\x00\x20" /* len */
+	"\x00\x01" /* curve_id */
+	"\x00\x18" /* key_size */
+#endif
+	"\xb5\x05\xb1\x71\x1e\xbf\x8c\xda"
+	"\x4e\x19\x1e\x62\x1f\x23\x23\x31"
+	"\x36\x1e\xd3\x84\x2f\xcc\x21\x72",
+	.b_public =
+	"\xc3\xba\x67\x4b\x71\xec\xd0\x76"
+	"\x7a\x99\x75\x64\x36\x13\x9a\x94"
+	"\x5d\x8b\xdc\x60\x90\x91\xfd\x3f"
+	"\xb0\x1f\x8a\x0a\x68\xc6\x88\x6e"
+	"\x83\x87\xdd\x67\x09\xf8\x8d\x96"
+	"\x07\xd6\xbd\x1c\xe6\x8d\x9d\x67",
+	.expected_a_public =
+	"\x1a\x04\xdb\xa5\xe1\xdd\x4e\x79"
+	"\xa3\xe6\xef\x0e\x5c\x80\x49\x85"
+	"\xfa\x78\xb4\xef\x49\xbd\x4c\x7c"
+	"\x22\x90\x21\x02\xf9\x1b\x81\x5d"
+	"\x0c\x8a\xa8\x98\xd6\x27\x69\x88"
+	"\x5e\xbc\x94\xd8\x15\x9e\x21\xce",
+	.expected_ss =
+	"\xf4\x57\xcc\x4f\x1f\x4e\x31\xcc"
+	"\xe3\x40\x60\xc8\x06\x93\xc6\x2e"
+	"\x99\x80\x81\x28\xaf\xc5\x51\x74",
+	.secret_size = 32,
+	.b_public_size = 48,
+	.expected_a_public_size = 48,
+	.expected_ss_size = 24
+	}, {
+#endif
+	.secret =
+#ifdef __LITTLE_ENDIAN
+	"\x02\x00" /* type */
+	"\x28\x00" /* len */
+	"\x02\x00" /* curve_id */
+	"\x20\x00" /* key_size */
+#else
+	"\x00\x02" /* type */
+	"\x00\x28" /* len */
+	"\x00\x02" /* curve_id */
+	"\x00\x20" /* key_size */
+#endif
+	"\x24\xd1\x21\xeb\xe5\xcf\x2d\x83"
+	"\xf6\x62\x1b\x6e\x43\x84\x3a\xa3"
+	"\x8b\xe0\x86\xc3\x20\x19\xda\x92"
+	"\x50\x53\x03\xe1\xc0\xea\xb8\x82",
+	.expected_a_public =
+	"\x1a\x7f\xeb\x52\x00\xbd\x3c\x31"
+	"\x7d\xb6\x70\xc1\x86\xa6\xc7\xc4"
+	"\x3b\xc5\x5f\x6c\x6f\x58\x3c\xf5"
+	"\xb6\x63\x82\x77\x33\x24\xa1\x5f"
+	"\x6a\xca\x43\x6f\xf7\x7e\xff\x02"
+	"\x37\x08\xcc\x40\x5e\x7a\xfd\x6a"
+	"\x6a\x02\x6e\x41\x87\x68\x38\x77"
+	"\xfa\xa9\x44\x43\x2d\xef\x09\xdf",
+	.expected_ss =
+	"\xea\x17\x6f\x7e\x6e\x57\x26\x38"
+	"\x8b\xfb\x41\xeb\xba\xc8\x6d\xa5"
+	"\xa8\x72\xd1\xff\xc9\x47\x3d\xaa"
+	"\x58\x43\x9f\x34\x0f\x8c\xf3\xc9",
+	.b_public =
+	"\xcc\xb4\xda\x74\xb1\x47\x3f\xea"
+	"\x6c\x70\x9e\x38\x2d\xc7\xaa\xb7"
+	"\x29\xb2\x47\x03\x19\xab\xdd\x34"
+	"\xbd\xa8\x2c\x93\xe1\xa4\x74\xd9"
+	"\x64\x63\xf7\x70\x20\x2f\xa4\xe6"
+	"\x9f\x4a\x38\xcc\xc0\x2c\x49\x2f"
+	"\xb1\x32\xbb\xaf\x22\x61\xda\xcb"
+	"\x6f\xdb\xa9\xaa\xfc\x77\x81\xf3",
+	.secret_size = 40,
+	.b_public_size = 64,
+	.expected_a_public_size = 64,
+	.expected_ss_size = 32
+	}
+};
+
 /*
  * MD4 test vectors from RFC1320
  */
@@ -3494,7 +3817,49 @@
 		.psize		= 80,
 		.digest		= "\x13\x00\x00\x00\x00\x00\x00\x00"
 				  "\x00\x00\x00\x00\x00\x00\x00\x00",
-	},
+	}, { /* Regression test for overflow in AVX2 implementation */
+		.plaintext	= "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff\xff\xff\xff\xff"
+				  "\xff\xff\xff\xff",
+		.psize		= 300,
+		.digest		= "\xfb\x5e\x96\xd8\x61\xd5\xc7\xc8"
+				  "\x78\xe5\x87\xcc\x2d\x5a\x22\xe1",
+	}
 };
 
 /*
@@ -21778,7 +22143,7 @@
 			  "\x09\x75\x9a\x9b\x3c\x9b\x27\x39",
 		.klen	= 32,
 		.iv	= "\x03\xf9\xd9\x4e\x63\xb5\x3d\x9d"
-			  "\x43\xf6\x1e\x50",
+			  "\x43\xf6\x1e\x50\0\0\0\0",
 		.assoc	= "\x57\xf5\x6b\x8b\x57\x5c\x3d\x3b"
 			  "\x13\x02\x01\x0c\x83\x4c\x96\x35"
 			  "\x8e\xd6\x39\xcf\x7d\x14\x9b\x94"
--- linux-4.4.0.orig/crypto/tgr192.c
+++ linux-4.4.0/crypto/tgr192.c
@@ -25,8 +25,9 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <asm/byteorder.h>
 #include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #define TGR192_DIGEST_SIZE 24
 #define TGR160_DIGEST_SIZE 20
@@ -468,10 +469,9 @@
 	u64 a, b, c, aa, bb, cc;
 	u64 x[8];
 	int i;
-	const __le64 *ptr = (const __le64 *)data;
 
 	for (i = 0; i < 8; i++)
-		x[i] = le64_to_cpu(ptr[i]);
+		x[i] = get_unaligned_le64(data + i * sizeof(__le64));
 
 	/* save */
 	a = aa = tctx->a;
--- linux-4.4.0.orig/crypto/vmac.c
+++ linux-4.4.0/crypto/vmac.c
@@ -1,6 +1,10 @@
 /*
- * Modified to interface to the Linux kernel
+ * VMAC: Message Authentication Code using Universal Hashing
+ *
+ * Reference: https://tools.ietf.org/html/draft-krovetz-vmac-01
+ *
  * Copyright (c) 2009, Intel Corporation.
+ * Copyright (c) 2018, Google 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,
@@ -16,14 +20,15 @@
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
 
-/* --------------------------------------------------------------------------
- * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai.
- * This implementation is herby placed in the public domain.
- * The authors offers no warranty. Use at your own risk.
- * Please send bug reports to the authors.
- * Last modified: 17 APR 08, 1700 PDT
- * ----------------------------------------------------------------------- */
+/*
+ * Derived from:
+ *	VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai.
+ *	This implementation is herby placed in the public domain.
+ *	The authors offers no warranty. Use at your own risk.
+ *	Last modified: 17 APR 08, 1700 PDT
+ */
 
+#include <asm/unaligned.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/crypto.h>
@@ -31,10 +36,36 @@
 #include <linux/scatterlist.h>
 #include <asm/byteorder.h>
 #include <crypto/scatterwalk.h>
-#include <crypto/vmac.h>
 #include <crypto/internal/hash.h>
 
 /*
+ * User definable settings.
+ */
+#define VMAC_TAG_LEN	64
+#define VMAC_KEY_SIZE	128/* Must be 128, 192 or 256			*/
+#define VMAC_KEY_LEN	(VMAC_KEY_SIZE/8)
+#define VMAC_NHBYTES	128/* Must 2^i for any 3 < i < 13 Standard = 128*/
+
+/* per-transform (per-key) context */
+struct vmac_tfm_ctx {
+	struct crypto_cipher *cipher;
+	u64 nhkey[(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)];
+	u64 polykey[2*VMAC_TAG_LEN/64];
+	u64 l3key[2*VMAC_TAG_LEN/64];
+};
+
+/* per-request context */
+struct vmac_desc_ctx {
+	union {
+		u8 partial[VMAC_NHBYTES];	/* partial block */
+		__le64 partial_words[VMAC_NHBYTES / 8];
+	};
+	unsigned int partial_size;	/* size of the partial block */
+	bool first_block_processed;
+	u64 polytmp[2*VMAC_TAG_LEN/64];	/* running total of L2-hash */
+};
+
+/*
  * Constants and masks
  */
 #define UINT64_C(x) x##ULL
@@ -318,13 +349,6 @@
 	} while (0)
 #endif
 
-static void vhash_abort(struct vmac_ctx *ctx)
-{
-	ctx->polytmp[0] = ctx->polykey[0] ;
-	ctx->polytmp[1] = ctx->polykey[1] ;
-	ctx->first_block_processed = 0;
-}
-
 static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len)
 {
 	u64 rh, rl, t, z = 0;
@@ -364,280 +388,209 @@
 	return rl;
 }
 
-static void vhash_update(const unsigned char *m,
-			unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */
-			struct vmac_ctx *ctx)
-{
-	u64 rh, rl, *mptr;
-	const u64 *kptr = (u64 *)ctx->nhkey;
-	int i;
-	u64 ch, cl;
-	u64 pkh = ctx->polykey[0];
-	u64 pkl = ctx->polykey[1];
-
-	if (!mbytes)
-		return;
-
-	BUG_ON(mbytes % VMAC_NHBYTES);
+/* L1 and L2-hash one or more VMAC_NHBYTES-byte blocks */
+static void vhash_blocks(const struct vmac_tfm_ctx *tctx,
+			 struct vmac_desc_ctx *dctx,
+			 const __le64 *mptr, unsigned int blocks)
+{
+	const u64 *kptr = tctx->nhkey;
+	const u64 pkh = tctx->polykey[0];
+	const u64 pkl = tctx->polykey[1];
+	u64 ch = dctx->polytmp[0];
+	u64 cl = dctx->polytmp[1];
+	u64 rh, rl;
 
-	mptr = (u64 *)m;
-	i = mbytes / VMAC_NHBYTES;  /* Must be non-zero */
-
-	ch = ctx->polytmp[0];
-	cl = ctx->polytmp[1];
-
-	if (!ctx->first_block_processed) {
-		ctx->first_block_processed = 1;
+	if (!dctx->first_block_processed) {
+		dctx->first_block_processed = true;
 		nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl);
 		rh &= m62;
 		ADD128(ch, cl, rh, rl);
 		mptr += (VMAC_NHBYTES/sizeof(u64));
-		i--;
+		blocks--;
 	}
 
-	while (i--) {
+	while (blocks--) {
 		nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl);
 		rh &= m62;
 		poly_step(ch, cl, pkh, pkl, rh, rl);
 		mptr += (VMAC_NHBYTES/sizeof(u64));
 	}
 
-	ctx->polytmp[0] = ch;
-	ctx->polytmp[1] = cl;
+	dctx->polytmp[0] = ch;
+	dctx->polytmp[1] = cl;
 }
 
-static u64 vhash(unsigned char m[], unsigned int mbytes,
-			u64 *tagl, struct vmac_ctx *ctx)
+static int vmac_setkey(struct crypto_shash *tfm,
+		       const u8 *key, unsigned int keylen)
 {
-	u64 rh, rl, *mptr;
-	const u64 *kptr = (u64 *)ctx->nhkey;
-	int i, remaining;
-	u64 ch, cl;
-	u64 pkh = ctx->polykey[0];
-	u64 pkl = ctx->polykey[1];
-
-	mptr = (u64 *)m;
-	i = mbytes / VMAC_NHBYTES;
-	remaining = mbytes % VMAC_NHBYTES;
-
-	if (ctx->first_block_processed) {
-		ch = ctx->polytmp[0];
-		cl = ctx->polytmp[1];
-	} else if (i) {
-		nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, ch, cl);
-		ch &= m62;
-		ADD128(ch, cl, pkh, pkl);
-		mptr += (VMAC_NHBYTES/sizeof(u64));
-		i--;
-	} else if (remaining) {
-		nh_16(mptr, kptr, 2*((remaining+15)/16), ch, cl);
-		ch &= m62;
-		ADD128(ch, cl, pkh, pkl);
-		mptr += (VMAC_NHBYTES/sizeof(u64));
-		goto do_l3;
-	} else {/* Empty String */
-		ch = pkh; cl = pkl;
-		goto do_l3;
-	}
-
-	while (i--) {
-		nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl);
-		rh &= m62;
-		poly_step(ch, cl, pkh, pkl, rh, rl);
-		mptr += (VMAC_NHBYTES/sizeof(u64));
-	}
-	if (remaining) {
-		nh_16(mptr, kptr, 2*((remaining+15)/16), rh, rl);
-		rh &= m62;
-		poly_step(ch, cl, pkh, pkl, rh, rl);
-	}
-
-do_l3:
-	vhash_abort(ctx);
-	remaining *= 8;
-	return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1], remaining);
-}
-
-static u64 vmac(unsigned char m[], unsigned int mbytes,
-			const unsigned char n[16], u64 *tagl,
-			struct vmac_ctx_t *ctx)
-{
-	u64 *in_n, *out_p;
-	u64 p, h;
-	int i;
-
-	in_n = ctx->__vmac_ctx.cached_nonce;
-	out_p = ctx->__vmac_ctx.cached_aes;
-
-	i = n[15] & 1;
-	if ((*(u64 *)(n+8) != in_n[1]) || (*(u64 *)(n) != in_n[0])) {
-		in_n[0] = *(u64 *)(n);
-		in_n[1] = *(u64 *)(n+8);
-		((unsigned char *)in_n)[15] &= 0xFE;
-		crypto_cipher_encrypt_one(ctx->child,
-			(unsigned char *)out_p, (unsigned char *)in_n);
+	struct vmac_tfm_ctx *tctx = crypto_shash_ctx(tfm);
+	__be64 out[2];
+	u8 in[16] = { 0 };
+	unsigned int i;
+	int err;
 
-		((unsigned char *)in_n)[15] |= (unsigned char)(1-i);
+	if (keylen != VMAC_KEY_LEN) {
+		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
 	}
-	p = be64_to_cpup(out_p + i);
-	h = vhash(m, mbytes, (u64 *)0, &ctx->__vmac_ctx);
-	return le64_to_cpu(p + h);
-}
-
-static int vmac_set_key(unsigned char user_key[], struct vmac_ctx_t *ctx)
-{
-	u64 in[2] = {0}, out[2];
-	unsigned i;
-	int err = 0;
 
-	err = crypto_cipher_setkey(ctx->child, user_key, VMAC_KEY_LEN);
+	err = crypto_cipher_setkey(tctx->cipher, key, keylen);
 	if (err)
 		return err;
 
 	/* Fill nh key */
-	((unsigned char *)in)[0] = 0x80;
-	for (i = 0; i < sizeof(ctx->__vmac_ctx.nhkey)/8; i += 2) {
-		crypto_cipher_encrypt_one(ctx->child,
-			(unsigned char *)out, (unsigned char *)in);
-		ctx->__vmac_ctx.nhkey[i] = be64_to_cpup(out);
-		ctx->__vmac_ctx.nhkey[i+1] = be64_to_cpup(out+1);
-		((unsigned char *)in)[15] += 1;
+	in[0] = 0x80;
+	for (i = 0; i < ARRAY_SIZE(tctx->nhkey); i += 2) {
+		crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in);
+		tctx->nhkey[i] = be64_to_cpu(out[0]);
+		tctx->nhkey[i+1] = be64_to_cpu(out[1]);
+		in[15]++;
 	}
 
 	/* Fill poly key */
-	((unsigned char *)in)[0] = 0xC0;
-	in[1] = 0;
-	for (i = 0; i < sizeof(ctx->__vmac_ctx.polykey)/8; i += 2) {
-		crypto_cipher_encrypt_one(ctx->child,
-			(unsigned char *)out, (unsigned char *)in);
-		ctx->__vmac_ctx.polytmp[i] =
-			ctx->__vmac_ctx.polykey[i] =
-				be64_to_cpup(out) & mpoly;
-		ctx->__vmac_ctx.polytmp[i+1] =
-			ctx->__vmac_ctx.polykey[i+1] =
-				be64_to_cpup(out+1) & mpoly;
-		((unsigned char *)in)[15] += 1;
+	in[0] = 0xC0;
+	in[15] = 0;
+	for (i = 0; i < ARRAY_SIZE(tctx->polykey); i += 2) {
+		crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in);
+		tctx->polykey[i] = be64_to_cpu(out[0]) & mpoly;
+		tctx->polykey[i+1] = be64_to_cpu(out[1]) & mpoly;
+		in[15]++;
 	}
 
 	/* Fill ip key */
-	((unsigned char *)in)[0] = 0xE0;
-	in[1] = 0;
-	for (i = 0; i < sizeof(ctx->__vmac_ctx.l3key)/8; i += 2) {
+	in[0] = 0xE0;
+	in[15] = 0;
+	for (i = 0; i < ARRAY_SIZE(tctx->l3key); i += 2) {
 		do {
-			crypto_cipher_encrypt_one(ctx->child,
-				(unsigned char *)out, (unsigned char *)in);
-			ctx->__vmac_ctx.l3key[i] = be64_to_cpup(out);
-			ctx->__vmac_ctx.l3key[i+1] = be64_to_cpup(out+1);
-			((unsigned char *)in)[15] += 1;
-		} while (ctx->__vmac_ctx.l3key[i] >= p64
-			|| ctx->__vmac_ctx.l3key[i+1] >= p64);
+			crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in);
+			tctx->l3key[i] = be64_to_cpu(out[0]);
+			tctx->l3key[i+1] = be64_to_cpu(out[1]);
+			in[15]++;
+		} while (tctx->l3key[i] >= p64 || tctx->l3key[i+1] >= p64);
 	}
 
-	/* Invalidate nonce/aes cache and reset other elements */
-	ctx->__vmac_ctx.cached_nonce[0] = (u64)-1; /* Ensure illegal nonce */
-	ctx->__vmac_ctx.cached_nonce[1] = (u64)0;  /* Ensure illegal nonce */
-	ctx->__vmac_ctx.first_block_processed = 0;
-
-	return err;
+	return 0;
 }
 
-static int vmac_setkey(struct crypto_shash *parent,
-		const u8 *key, unsigned int keylen)
+static int vmac_init(struct shash_desc *desc)
 {
-	struct vmac_ctx_t *ctx = crypto_shash_ctx(parent);
+	const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+	struct vmac_desc_ctx *dctx = shash_desc_ctx(desc);
 
-	if (keylen != VMAC_KEY_LEN) {
-		crypto_shash_set_flags(parent, CRYPTO_TFM_RES_BAD_KEY_LEN);
-		return -EINVAL;
-	}
-
-	return vmac_set_key((u8 *)key, ctx);
-}
-
-static int vmac_init(struct shash_desc *pdesc)
-{
+	dctx->partial_size = 0;
+	dctx->first_block_processed = false;
+	memcpy(dctx->polytmp, tctx->polykey, sizeof(dctx->polytmp));
 	return 0;
 }
 
-static int vmac_update(struct shash_desc *pdesc, const u8 *p,
-		unsigned int len)
+static int vmac_update(struct shash_desc *desc, const u8 *p, unsigned int len)
 {
-	struct crypto_shash *parent = pdesc->tfm;
-	struct vmac_ctx_t *ctx = crypto_shash_ctx(parent);
-	int expand;
-	int min;
-
-	expand = VMAC_NHBYTES - ctx->partial_size > 0 ?
-			VMAC_NHBYTES - ctx->partial_size : 0;
-
-	min = len < expand ? len : expand;
-
-	memcpy(ctx->partial + ctx->partial_size, p, min);
-	ctx->partial_size += min;
-
-	if (len < expand)
-		return 0;
-
-	vhash_update(ctx->partial, VMAC_NHBYTES, &ctx->__vmac_ctx);
-	ctx->partial_size = 0;
-
-	len -= expand;
-	p += expand;
-
-	if (len % VMAC_NHBYTES) {
-		memcpy(ctx->partial, p + len - (len % VMAC_NHBYTES),
-			len % VMAC_NHBYTES);
-		ctx->partial_size = len % VMAC_NHBYTES;
+	const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+	struct vmac_desc_ctx *dctx = shash_desc_ctx(desc);
+	unsigned int n;
+
+	if (dctx->partial_size) {
+		n = min(len, VMAC_NHBYTES - dctx->partial_size);
+		memcpy(&dctx->partial[dctx->partial_size], p, n);
+		dctx->partial_size += n;
+		p += n;
+		len -= n;
+		if (dctx->partial_size == VMAC_NHBYTES) {
+			vhash_blocks(tctx, dctx, dctx->partial_words, 1);
+			dctx->partial_size = 0;
+		}
+	}
+
+	if (len >= VMAC_NHBYTES) {
+		n = round_down(len, VMAC_NHBYTES);
+		/* TODO: 'p' may be misaligned here */
+		vhash_blocks(tctx, dctx, (const __le64 *)p, n / VMAC_NHBYTES);
+		p += n;
+		len -= n;
+	}
+
+	if (len) {
+		memcpy(dctx->partial, p, len);
+		dctx->partial_size = len;
 	}
 
-	vhash_update(p, len - len % VMAC_NHBYTES, &ctx->__vmac_ctx);
-
 	return 0;
 }
 
-static int vmac_final(struct shash_desc *pdesc, u8 *out)
+static u64 vhash_final(const struct vmac_tfm_ctx *tctx,
+		       struct vmac_desc_ctx *dctx)
 {
-	struct crypto_shash *parent = pdesc->tfm;
-	struct vmac_ctx_t *ctx = crypto_shash_ctx(parent);
-	vmac_t mac;
-	u8 nonce[16] = {};
-
-	/* vmac() ends up accessing outside the array bounds that
-	 * we specify.  In appears to access up to the next 2-word
-	 * boundary.  We'll just be uber cautious and zero the
-	 * unwritten bytes in the buffer.
-	 */
-	if (ctx->partial_size) {
-		memset(ctx->partial + ctx->partial_size, 0,
-			VMAC_NHBYTES - ctx->partial_size);
-	}
-	mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx);
-	memcpy(out, &mac, sizeof(vmac_t));
-	memzero_explicit(&mac, sizeof(vmac_t));
-	memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx));
-	ctx->partial_size = 0;
+	unsigned int partial = dctx->partial_size;
+	u64 ch = dctx->polytmp[0];
+	u64 cl = dctx->polytmp[1];
+
+	/* L1 and L2-hash the final block if needed */
+	if (partial) {
+		/* Zero-pad to next 128-bit boundary */
+		unsigned int n = round_up(partial, 16);
+		u64 rh, rl;
+
+		memset(&dctx->partial[partial], 0, n - partial);
+		nh_16(dctx->partial_words, tctx->nhkey, n / 8, rh, rl);
+		rh &= m62;
+		if (dctx->first_block_processed)
+			poly_step(ch, cl, tctx->polykey[0], tctx->polykey[1],
+				  rh, rl);
+		else
+			ADD128(ch, cl, rh, rl);
+	}
+
+	/* L3-hash the 128-bit output of L2-hash */
+	return l3hash(ch, cl, tctx->l3key[0], tctx->l3key[1], partial * 8);
+}
+
+static int vmac_final(struct shash_desc *desc, u8 *out)
+{
+	const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+	struct vmac_desc_ctx *dctx = shash_desc_ctx(desc);
+	static const u8 nonce[16] = {}; /* TODO: this is insecure */
+	union {
+		u8 bytes[16];
+		__be64 pads[2];
+	} block;
+	int index;
+	u64 hash, pad;
+
+	/* Finish calculating the VHASH of the message */
+	hash = vhash_final(tctx, dctx);
+
+	/* Generate pseudorandom pad by encrypting the nonce */
+	memcpy(&block, nonce, 16);
+	index = block.bytes[15] & 1;
+	block.bytes[15] &= ~1;
+	crypto_cipher_encrypt_one(tctx->cipher, block.bytes, block.bytes);
+	pad = be64_to_cpu(block.pads[index]);
+
+	/* The VMAC is the sum of VHASH and the pseudorandom pad */
+	put_unaligned_le64(hash + pad, out);
 	return 0;
 }
 
 static int vmac_init_tfm(struct crypto_tfm *tfm)
 {
-	struct crypto_cipher *cipher;
-	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
-	struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm);
+	struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+	struct crypto_cipher *cipher;
 
 	cipher = crypto_spawn_cipher(spawn);
 	if (IS_ERR(cipher))
 		return PTR_ERR(cipher);
 
-	ctx->child = cipher;
+	tctx->cipher = cipher;
 	return 0;
 }
 
 static void vmac_exit_tfm(struct crypto_tfm *tfm)
 {
-	struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm);
-	crypto_free_cipher(ctx->child);
+	struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_cipher(tctx->cipher);
 }
 
 static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb)
@@ -655,6 +608,10 @@
 	if (IS_ERR(alg))
 		return PTR_ERR(alg);
 
+	err = -EINVAL;
+	if (alg->cra_blocksize != 16)
+		goto out_put_alg;
+
 	inst = shash_alloc_instance("vmac", alg);
 	err = PTR_ERR(inst);
 	if (IS_ERR(inst))
@@ -670,11 +627,12 @@
 	inst->alg.base.cra_blocksize = alg->cra_blocksize;
 	inst->alg.base.cra_alignmask = alg->cra_alignmask;
 
-	inst->alg.digestsize = sizeof(vmac_t);
-	inst->alg.base.cra_ctxsize = sizeof(struct vmac_ctx_t);
+	inst->alg.base.cra_ctxsize = sizeof(struct vmac_tfm_ctx);
 	inst->alg.base.cra_init = vmac_init_tfm;
 	inst->alg.base.cra_exit = vmac_exit_tfm;
 
+	inst->alg.descsize = sizeof(struct vmac_desc_ctx);
+	inst->alg.digestsize = VMAC_TAG_LEN / 8;
 	inst->alg.init = vmac_init;
 	inst->alg.update = vmac_update;
 	inst->alg.final = vmac_final;
--- linux-4.4.0.orig/crypto/xts.c
+++ linux-4.4.0/crypto/xts.c
@@ -35,16 +35,11 @@
 {
 	struct priv *ctx = crypto_tfm_ctx(parent);
 	struct crypto_cipher *child = ctx->tweak;
-	u32 *flags = &parent->crt_flags;
 	int err;
 
-	/* key consists of keys of equal size concatenated, therefore
-	 * the length must be even */
-	if (keylen % 2) {
-		/* tell the user why there was an error */
-		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-		return -EINVAL;
-	}
+	err = xts_check_key(parent, key, keylen);
+	if (err)
+		return err;
 
 	/* we need two cipher instances: one to compute the initial 'tweak'
 	 * by encrypting the IV (usually the 'plain' iv) and the other
@@ -334,7 +329,7 @@
 	return inst;
 }
 
-static void free(struct crypto_instance *inst)
+static void free_inst(struct crypto_instance *inst)
 {
 	crypto_drop_spawn(crypto_instance_ctx(inst));
 	kfree(inst);
@@ -343,7 +338,7 @@
 static struct crypto_template crypto_tmpl = {
 	.name = "xts",
 	.alloc = alloc,
-	.free = free,
+	.free = free_inst,
 	.module = THIS_MODULE,
 };
 
--- linux-4.4.0.orig/debian.master/NOTES
+++ linux-4.4.0/debian.master/NOTES
@@ -0,0 +1,4 @@
+eSCO patch removed. Replaced upstream with a disable_esco module parm.
+airprime: Module gone, use option driver instead
+AppArmor: Patch is all there and ported. Ooops when enabled, so default
+	off (still can be enabled apparmor=1)
--- linux-4.4.0.orig/debian.master/changelog
+++ linux-4.4.0/debian.master/changelog
@@ -0,0 +1,42623 @@
+linux (4.4.0-279.313) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-279.313 -proposed tracker (LP: #2144095)
+
+  * CVE-2021-47254
+    - gfs2: Fix use-after-free in gfs2_glock_shrink_scan
+
+  * CVE-2024-46777
+    - udf: Avoid excessive partition lengths
+
+  * CVE-2021-47145
+    - btrfs: do not BUG_ON in link_to_fixup_dir
+
+  * CVE-2025-21735
+    - NFC: nci: Add bounds checking in nci_hci_create_pipe()
+
+  * CVE-2021-47142
+    - drm/amdgpu: Fix a use-after-free
+
+  * CVE-2026-23074
+    - net/sched: Enforce that teql can only be used as root qdisc
+
+  * CVE-2026-23060
+    - crypto: authencesn - reject too-short AAD (assoclen<8) to match ESP/ESN
+      spec
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 13 Mar 2026 10:13:30 +0100
+
+linux (4.4.0-278.312) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-278.312 -proposed tracker (LP: #2140783)
+
+  * CVE-2024-47659
+    - smack: tcp: ipv4, fix incorrect labeling
+
+  * CVE-2025-21704
+    - cdc-acm: reassemble fragmented notifications
+    - usb: cdc-acm: Check control transfer buffer size before access
+    - usb: cdc-acm: Fix handling of oversized fragments
+    - USB: cdc-acm: rework notification_buffer resizing
+
+  * CVE-2022-48875
+    - wifi: mac80211: sdata can be NULL during AMPDU start
+
+  * CVE-2024-56593
+    - wifi: brcmfmac: Fix oops due to NULL pointer dereference in
+      brcmf_sdiod_sglist_rw()
+
+  * CVE-2024-56548
+    - hfsplus: don't query the device logical block size multiple times
+
+  * CVE-2022-49267
+    - mmc: core: use sysfs_emit() instead of sprintf()
+
+  * CVE-2024-49927
+    - x86/ioapic: Handle allocation failures gracefully
+
+  * CVE-2025-40256
+    - xfrm: also call xfrm_state_delete_tunnel at destroy time for states that
+      were never added
+
+  * CVE-2025-40215
+    - xfrm: delete x->tunnel as we delete x
+
+  * CVE-2021-47599
+    - btrfs: use RCU in btrfs_show_devname for device list traversal
+    - btrfs: convert latest_bdev type to btrfs_device and rename
+    - btrfs: use latest_dev in btrfs_show_devname
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 06 Feb 2026 18:49:47 +0100
+
+linux (4.4.0-277.311) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-277.311 -proposed tracker (LP: #2137920)
+
+  * CVE-2024-49959
+    - jbd2: stop waiting for space when jbd2_cleanup_journal_tail() returns
+      error
+
+  * CVE-2024-56606
+    - af_packet: avoid erroring out after sock_init_data() in packet_create()
+
+  * CVE-2021-47104
+    - IB/qib: Fix memory leak in qib_user_sdma_queue_pkts()
+
+  * CVE-2021-47485
+    - IB/qib: Protect from buffer overflow in struct qib_user_sdma_pkt fields
+
+  * CVE-2024-53164
+    - net: sched: fix ordering of qlen adjustment
+
+  * CVE-2025-39993
+    - media: imon: reorganize serialization
+    - media: rc: fix races with imon_disconnect()
+
+  * CVE-2024-50195
+    - posix-clock: Fix missing timespec64 check in pc_clock_settime()
+    - posix-clock: posix-clock: Fix unbalanced locking in pc_clock_settime()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 09 Jan 2026 17:17:07 +0100
+
+linux (4.4.0-276.310) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-276.310 -proposed tracker (LP: #2131920)
+
+  * crypto: af_alg: sendmsg() on AF_ALG sockets for skcipher fails with EBUSY
+    (LP: #2131904)
+    - crypto: algif_aead - fix uninitialized ctx->init
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Wed, 19 Nov 2025 15:58:58 +0100
+
+linux (4.4.0-275.309) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-275.309 -proposed tracker (LP: #2131305)
+
+  * CVE-2025-21855
+    - ibmvnic: Don't reference skb after sending to VIOS
+
+  * CVE-2024-53112
+    - ocfs2: uncache inode which has failed entering the group
+
+  * CVE-2021-47269
+    - usb: dwc3: ep0: fix NULL pointer exception
+
+  * CVE-2021-47146
+    - mld: fix panic in mld_newpack()
+
+  * CVE-2021-47385
+    - hwmon: (w83792d) Fix NULL pointer dereference by removing unnecessary
+      structure field
+
+  * CVE-2025-40018
+    - ipvs: Defer ip_vs_ftp unregister during netns cleanup
+
+  * CVE-2024-50179
+    - ceph: remove the incorrect Fw reference check when dirtying pages
+
+  * CVE-2021-47634
+    - ubi: Fix race condition between ctrl_cdev_ioctl and ubi_cdev_ioctl
+
+  * CVE-2025-21722
+    - nilfs2: do not force clear folio if buffer is referenced
+    - nilfs2: protect access to buffers with no active references
+
+  * CVE-2022-49026
+    - e100: Fix possible use after free in e100_xmit_prepare
+
+  * CVE-2025-21715
+    - net: davicom: fix UAF in dm9000_drv_remove
+
+  * CVE-2025-39964
+    - crypto: af_alg - Disallow concurrent writes in af_alg_sendmsg
+    - crypto: af_alg - Fix incorrect boolean values in af_alg_ctx
+
+  * CVE-2025-38666
+    - net: appletalk: fix kerneldoc warnings
+    - net: appletalk: Fix use-after-free in AARP proxy probe
+
+  * CVE-2024-53217
+    - nfsd: restore callback functionality for NFSv4.0
+
+  * CVE-2024-49935
+    - ACPI: PAD: fix crash in exit_round_robin()
+
+  * CVE-2024-50095
+    - IB/mad: pass ib_mad_send_buf explicitly to the recv_handler
+    - IB/mad: Issue complete whenever decrements agent refcount
+    - RDMA/mad: Improve handling of timed out WRs of mad agent
+
+  * CVE-2024-50067
+    - uprobes: encapsulate preparation of uprobe args buffer
+    - uprobe: avoid out-of-bounds memory access of fetching args
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 14 Nov 2025 17:44:16 +0100
+
+linux (4.4.0-274.308) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-274.308 -proposed tracker (LP: #2127262)
+
+  * VMSCAPE CVE-2025-40300 (LP: #2124105) // CVE-2025-40300
+    - Documentation/hw-vuln: Add VMSCAPE documentation
+    - x86/vmscape: Enumerate VMSCAPE bug
+    - x86/vmscape: Add conditional IBPB mitigation
+    - x86/vmscape: Enable the mitigation
+    - x86/bugs: Move cpu_bugs_smt_update() down
+    - x86/vmscape: Warn when STIBP is disabled with SMT
+    - x86/cpu: Add old Intel CPUs to affected list
+    - [Config] enable CONFIG_MITIGATION_VMSCAPE
+
+  * CVE-2023-52574
+    - team: fix null-ptr-deref when team device type is changed
+
+  * CVE-2024-53124
+    - net: fix data-races around sk->sk_forward_alloc
+
+  * CVE-2024-50006
+    - ext4: fix i_data_sem unlock order in ext4_ind_migrate()
+
+  * CVE-2024-53150
+    - ALSA: usb-audio: Fix out of bounds reads when finding clock sources
+
+  * CVE-2025-37838
+    - HSI: ssi_protocol: Fix use after free vulnerability in ssi_protocol
+      Driver Due to Race Condition
+
+  * CVE-2021-47294 // CVE-2024-41006
+    - netrom: Fix a memory leak in nr_heartbeat_expiry()
+
+  * CVE-2021-47294
+    - netrom: Decrease sock refcount when sock timers expire
+    - netrom: Fix use-after-free of a listening socket.
+
+  * CVE-2024-50299
+    - sctp: properly validate chunk size in sctp_sf_ootb()
+
+  * CVE-2024-56767
+    - dmaengine: at_xdmac: avoid null_prt_deref in at_xdmac_prep_dma_memset
+
+  * CVE-2023-52650
+    - drm/tegra: dsi: Add missing check for of_find_device_by_node
+
+  * CVE-2021-47330
+    - tty: serial: 8250: serial_cs: Fix a memory leak in error handling path
+
+  * CVE-2025-38352
+    - posix-cpu-timers: fix race between handle_posix_cpu_timers() and
+      posix_cpu_timer_del()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 10 Oct 2025 22:32:44 +0200
+
+linux (4.4.0-273.307) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-273.307 -proposed tracker (LP: #2124194)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * CVE-2024-49924
+    - fbdev: pxafb: Fix possible use after free in pxafb_task()
+
+  * CVE-2025-37785
+    - ext4: optimize __ext4_check_dir_entry()
+    - ext4: fix OOB read when checking dotdot dir
+
+  * CVE-2021-47319
+    - virtio-blk: Fix memory leak among suspend/resume procedure
+
+  * CVE-2025-21796
+    - nfsd: clear acl_access/acl_default after releasing them
+
+  * CVE-2024-27078
+    - media: v4l2-tpg: fix some memleaks in tpg_alloc
+
+  * CVE-2025-38617
+    - net/packet: fix a race in packet_set_ring() and packet_notifier()
+
+  * CVE-2025-38618
+    - vsock: Do not allow binding to VMADDR_PORT_ANY
+
+  * CVE-2024-35849
+    - btrfs: fix information leak in btrfs_ioctl_logical_to_ino()
+
+  * CVE-2021-47589
+    - igbvf: fix double free in `igbvf_probe`
+
+  * CVE-2021-47149
+    - net: fujitsu: fix potential null-ptr-deref
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Wed, 17 Sep 2025 21:22:09 +0200
+
+linux (4.4.0-272.306) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-272.306 -proposed tracker (LP: #2119753)
+
+  * CVE-2024-27074
+    - media: go7007: fix a memleak in go7007_load_encoder
+
+  * CVE-2024-50051
+    - spi: mpc52xx: Add cancel_work_sync before module remove
+
+  * CVE-2024-53130
+    - nilfs2: fix null-ptr-deref in block_dirty_buffer tracepoint
+
+  * CVE-2024-53131
+    - nilfs2: fix null-ptr-deref in block_touch_buffer tracepoint
+
+  * CVE-2023-52477
+    - usb: hub: Guard against accesses to uninitialized BOS descriptors
+
+  * CVE-2021-47345
+    - RDMA/cma: Fix rdma_resolve_route() memory leak
+
+  * CVE-2024-50202
+    - make ext2_get_page() and friends work without external serialization
+    - nilfs2: Remove check for PageError
+    - nilfs2: return the mapped address from nilfs_get_page()
+    - nilfs2: propagate directory read errors from nilfs_find_entry()
+
+  * CVE-2024-57996 // CVE-2025-37752
+    - net_sched: sch_sfq: move the limit validation
+
+  * CVE-2024-47685
+    - skbuff/mac80211: introduce and use skb_put_zero()
+    - netfilter: nf_reject_ipv6: fix nf_reject_ip6_tcphdr_put()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Thu, 07 Aug 2025 16:51:14 +0200
+
+linux (4.4.0-271.305) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-271.305 -proposed tracker (LP: #2116540)
+
+  * CVE-2023-52975
+    - scsi: libiscsi: Fix use-after-free race during iscsi_session_teardown
+    - scsi: iscsi: Move pool freeing
+    - scsi: iscsi_tcp: Fix UAF during logout when accessing the shost
+      ipaddress
+
+  * CVE-2024-49883
+    - ext4: aovid use-after-free in ext4_ext_insert_extent()
+
+  * CVE-2024-53239
+    - ALSA: 6fire: Use common error handling code in usb6fire_chip_probe()
+    - ALSA: 6fire: Release resources at card release
+
+  * CVE-2024-49950
+    - Bluetooth: L2CAP: Fix uaf in l2cap_connect
+    - Bluetooth: hci_core: Fix calling mgmt_device_connected
+
+  * CVE-2024-50073
+    - tty: n_gsm: Fix use-after-free in gsm_cleanup_mux
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 11 Jul 2025 14:38:45 +0200
+
+linux (4.4.0-270.304) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-270.304 -proposed tracker (LP: #2114482)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update variants
+
+  * CVE-2021-47260
+    - NFS: Fix a potential NULL dereference in nfs_get_client()
+
+  * CVE-2024-53197
+    - ALSA: usb-audio: Fix potential out-of-bound accesses for Extigy and Mbox
+      devices
+    - ALSA: usb-audio: Fix a DMA to stack memory bug
+
+  * CVE-2021-47576
+    - scsi: scsi_debug: Sanity check block descriptor length in
+      resp_mode_select()
+
+  * CVE-2024-46787
+    - userfaultfd: fix checks for huge PMDs
+
+  * CVE-2025-37798
+    - net_sched: call qlen_notify only if child qdisc is empty
+    - sch_htb: make htb_qlen_notify() idempotent
+    - sch_htb: make htb_deactivate() idempotent
+    - sch_drr: make drr_qlen_notify() idempotent
+    - sch_hfsc: make hfsc_qlen_notify() idempotent
+    - sch_qfq: make qfq_qlen_notify() idempotent
+    - codel: remove sch->q.qlen check before qdisc_tree_reduce_backlog()
+
+  * CVE-2022-49909
+    - Bluetooth: L2CAP: fix use-after-free in l2cap_conn_del()
+
+  * CVE-2024-50116
+    - nilfs2: fix kernel bug due to missing clearing of buffer delay flag
+
+  * CVE-2024-49958
+    - ocfs2: reserve space for inline xattr before attaching reflink tree
+
+  * CVE-2021-47195
+    - spi: fix use-after-free of the add_lock mutex
+
+  * CVE-2021-47469
+    - spi: Fix deadlock when adding SPI controllers on SPI buses
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 13 Jun 2025 18:47:34 +0200
+
+linux (4.4.0-269.303) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-269.303 -proposed tracker (LP: #2110969)
+
+  * CVE-2024-56596
+    - jfs: fix array-index-out-of-bounds in jfs_readdir
+
+  * CVE-2024-53168
+    - sock: Change the netns_core member name.
+    - sock: Move the socket inuse to namespace.
+    - sock: Hide unused variable when !CONFIG_PROC_FS.
+    - sock: fix /proc/net/sockstat underflow in sk_clone_lock()
+    - net: make sock_inuse_add() available
+    - sunrpc: fix one UAF issue caused by sunrpc kernel tcp socket
+
+  * CVE-2024-42301
+    - dev/parport: fix the array out-of-bounds risk
+    - parport: Proper fix for array out-of-bounds access
+
+  * CVE-2021-47211
+    - ALSA: usb-audio: fix null pointer dereference on pointer cs_desc
+
+  * CVE-2024-47701
+    - ext4: avoid OOB when system.data xattr changes underneath the filesystem
+
+  * CVE-2024-57850
+    - jffs2: Prevent rtime decompress memory corruption
+    - jffs2: Fix rtime decompressor
+
+  * CVE-2023-52458
+    - block: check partition alignment
+    - block: add check that partition length needs to be aligned with block size
+
+  * CVE-2021-47353
+    - udf: Fix NULL pointer dereference in udf_symlink function
+
+  * CVE-2024-26966
+    - clk: qcom: mmcc-apq8084: fix terminating of frequency table arrays
+
+  * CVE-2024-56551
+    - drm/amdgpu: fix usage slab after free
+
+  * CVE-2024-53155
+    - ocfs2: fix uninitialized value in ocfs2_file_read_iter()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 16 May 2025 14:27:44 +0200
+
+linux (4.4.0-268.302) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-268.302 -proposed tracker (LP: #2107200)
+
+  * CVE-2021-46959
+    - spi: Fix use-after-free with devm_spi_alloc_*
+
+  * CVE-2021-47245
+    - netfilter: synproxy: Fix out of bounds when parsing TCP options
+
+  * CVE-2023-52741
+    - cifs: Fix use-after-free in rdata->read_into_pages()
+
+  * CVE-2024-47709
+    - can: bcm: Clear bo->bcm_proc_read after remove_proc_entry().
+
+  * CVE-2024-46771
+    - can: bcm: Remove proc entry when dev is unregistered.
+
+  * CVE-2021-47506
+    - nfsd: fix use-after-free due to delegation race
+
+  * CVE-2025-21971
+    - net_sched: Prevent creation of classes with TC_H_ROOT
+
+  * CVE-2024-53140
+    - netlink: terminate outstanding dump on socket close
+
+  * CVE-2021-47150
+    - net: fec: fix the potential memory leak in fec_enet_init()
+
+  * CVE-2021-47587
+    - net: systemport: Add global locking for descriptor lifecycle
+
+  * CVE-2024-53063
+    - media: dvbdev: prevent the risk of out of memory access
+    - media: dvbdev: fix the logic when DVB_DYNAMIC_MINORS is not set
+
+  * CVE-2024-39493
+    - crypto: qat - Fix ADF_DEV_RESET_SYNC memory leak
+
+  * CVE-2024-26974
+    - crypto: qat - fix double free during reset
+    - crypto: qat - resolve race condition during AER recovery
+
+  * CVE-2024-26996
+    - usb: gadget: f_ncm: Fix UAF ncm object at re-bind after usb ep transport
+      error
+
+  * CVE-2024-46780
+    - nilfs2: protect references to superblock parameters exposed in sysfs
+
+  * CVE-2024-50237
+    - wifi: mac80211: do not pass a stopped vif to the driver in .get_txpower
+
+  * CVE-2024-26689
+    - ceph: prevent use-after-free in encode_cap_msg()
+
+  * CVE-2024-49944
+    - sctp: set sk_state back to CLOSED if autobind fails in sctp_listen_start
+
+  * CVE-2024-53066
+    - nfs: Fix KMSAN warning in decode_getfattr_attrs()
+
+  * CVE-2021-47191
+    - scsi: scsi_debug: Fix out-of-bound read in resp_readcap16()
+
+  * CVE-2024-56598
+    - jfs: array-index-out-of-bounds fix in dtReadFirst
+
+  * CVE-2024-56650
+    - netfilter: x_tables: fix LED ID check in led_tg_check()
+
+  * CVE-2024-53173
+    - NFSv4.0: Fix a use-after-free problem in the asynchronous open()
+
+  * CVE-2024-56631
+    - scsi: sg: Fix slab-use-after-free read in sg_release()
+
+  * CVE-2024-50256
+    - netfilter: nf_reject_ipv6: fix potential crash in nf_send_reset6()
+
+  * CVE-2024-56770
+    - net/sched: netem: account for backlog updates from child qdisc
+    - netem: Update sch->q.qlen before qdisc_tree_reduce_backlog()
+
+  * CVE-2024-35864
+    - smb: client: fix potential UAF in cifs_debug_files_proc_show()
+    - smb: client: fix potential UAF in smb2_is_valid_lease_break()
+
+  * CVE-2021-47219
+    - scsi: scsi_debug: Fix out-of-bound read in resp_report_tgtpgs()
+
+  * CVE-2024-26915
+    - drm/amdgpu: Add check to prevent IH overflow
+    - drm/amdgpu: Reset IH OVERFLOW_CLEAR bit
+
+  * CVE-2024-56661
+    - tipc: fix NULL deref in cleanup_bearer()
+
+  * CVE-2024-56642
+    - tipc: Fix use-after-free of kernel socket in cleanup_bearer().
+
+  * CVE-2021-47163
+    - tipc: wait and exit until all work queues are done
+
+  * CVE-2021-47500
+    - iio: mma8452: Fix trigger reference couting
+
+  * CVE-2022-23041
+    - xen/grant-table: add gnttab_try_end_foreign_access()
+    - xen/gnttab: fix gnttab_end_foreign_access() without page specified
+
+  * CVE-2024-36934
+    - bna: ensure the copied buf is NUL terminated
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 11 Apr 2025 22:33:33 +0200
+
+linux (4.4.0-267.301) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-267.301 -proposed tracker (LP: #2102293)
+
+  * CVE-2024-27397 (LP: #2090990)
+    - netfilter: nf_tables: fix inconsistent element expiration calculation
+    - time: Introduce jiffies64_to_nsecs()
+    - netfilter: nf_tables: support timeouts larger than 23 days
+    - netfilter: nft_dynset: fix timeout updates on 32bit
+    - netfilter: nf_tables: elements with timeout below CONFIG_HZ never expire
+
+  * CVE-2024-50302
+    - HID: core: zero-initialize the report buffer
+
+  * CVE-2021-47602
+    - mac80211: track only QoS data frames for admission control
+
+  * CVE-2024-49948
+    - net: add more sanity checks to qdisc_pkt_len_init()
+
+  * CVE-2021-47320
+    - nfs: fix acl memory leak of posix_acl_create()
+
+  * CVE-2024-49952
+    - netfilter: nf_tables: prevent nf_skb_duplicated corruption
+
+  * CVE-2024-50167
+    - be2net: fix potential memory leak in be_xmit()
+
+  * CVE-2025-21702
+    - pfifo_tail_enqueue: Drop new packet when sch->limit == 0
+
+  * CVE-2025-21700
+    - net: sched: Disallow replacing of child qdisc from one parent to another
+
+  * CVE-2021-47483
+    - regmap: Fix possible double-free in regcache_rbtree_exit()
+
+  * CVE-2024-56595
+    - jfs: add a check to prevent array-index-out-of-bounds in dbAdjTree
+
+  * CVE-2021-47119
+    - ext4: fix memory leak in ext4_fill_super
+
+  * CVE-2021-47122
+    - net: caif: add proper error handling
+    - net: caif: added cfserl_release function
+    - net: caif: fix memory leak in caif_device_notify
+
+  * CVE-2024-46826
+    - ELF: fix kernel.randomize_va_space double read
+
+  * CVE-2024-56600
+    - net: inet6: do not leave a dangling sk pointer in inet6_create()
+
+  * CVE-2024-56658
+    - net: defer final 'struct net' free in netns dismantle
+
+  * CVE-2024-53227
+    - scsi: bfa: Fix use-after-free in bfad_im_module_exit()
+
+  * CVE-2024-53165
+    - sh: intc: Fix use-after-free bug in register_intc_controller()
+
+  * CVE-2024-50265
+    - ocfs2: remove entry once instead of null-ptr-dereference in
+      ocfs2_xa_remove()
+
+  * CVE-2021-47235
+    - net: ethernet: fix potential use-after-free in ec_bhf_remove
+
+  * CVE-2024-26921
+    - ipv4: ipv6: netfilter: Adjust the frag mem limit when truesize changes
+    - net: IP defrag: encapsulate rbtree defrag code into callable functions
+    - ipv4: remove unnecessary type castings
+    - netfilter: ipv6: nf_defrag: avoid/free clone operations
+    - inet: kill unused skb_free op
+    - netfilter: ipv6: avoid nf_iterate recursion
+    - netfilter: ipv6: nf_defrag: fix NULL deref panic
+    - openvswitch: Orphan skbs before IPv6 defrag
+    - openvswitch: Fix skb leak in IPv6 reassembly.
+    - netfilter: ipv6: nf_defrag: drop mangled skb on ream error
+    - netfilter: ipv6: nf_defrag: Pass on packets to stack per RFC2460
+    - netfilter: ipv6: nf_defrag: Kill frag queue on RFC2460 failure
+    - net: IP6 defrag: use rbtrees in nf_conntrack_reasm.c
+    - netfilter: ipv6: nf_defrag: fix leakage of unqueued fragments
+    - netfilter: ipv6: nf_defrag: accept duplicate fragments again
+    - net: add __sock_wfree() helper
+    - inet: inet_defrag: prevent sk release while still in use
+
+  * CVE-2024-26863
+    - hsr: Fix uninit-value access in hsr_get_node()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 14 Mar 2025 19:16:58 +0100
+
+linux (4.4.0-266.300) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-266.300 -proposed tracker (LP: #2098709)
+
+  * Xenial backport of upstream patch breaks arm64 boot (LP: #2098704)
+    - Revert "bpf: Take return from set_memory_ro() into account with
+      bpf_prog_lock_ro()"
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Mon, 17 Feb 2025 19:57:36 +0100
+
+linux (4.4.0-265.299) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-265.299 -proposed tracker (LP: #2097857)
+
+  * CVE-2024-41063
+    - Bluetooth: fix power_on vs close race
+    - Bluetooth: hci_core: cancel all works upon hci_unregister_dev()
+
+  * CVE-2024-53104
+    - media: uvcvideo: Skip parsing frames of type UVC_VS_UNDEFINED in
+      uvc_parse_format
+
+  * CVE-2024-53156
+    - wifi: ath9k: add range check for conn_rsp_epid in htc_connect_service()
+
+  * CVE-2021-47606
+    - net: netlink: af_netlink: Prevent empty skb by adding a check on len.
+
+  * CVE-2024-49902
+    - jfs: check if leafidx greater than num leaves per dmap tree
+
+  * CVE-2023-52799 // CVE-2024-49902
+    - jfs: fix array-index-out-of-bounds in dbFindLeaf
+
+  * CVE-2023-52818
+    - drm/amd: Fix UBSAN array-index-out-of-bounds for SMU7
+
+  * CVE-2024-50117
+    - drm/amd: Guard against bad data for ATIF ACPI method
+
+  * CVE-2024-50148
+    - Bluetooth: bnep: fix wild-memory-access in proto_unregister
+
+  * CVE-2024-44938
+    - jfs: Fix shift-out-of-bounds in dbDiscardAG
+
+  * CVE-2022-48994
+    - ALSA: seq: Fix function prototype mismatch in snd_seq_expand_var_event
+
+  * CVE-2024-50233
+    - staging: iio: frequency: ad9832: fix division by zero in
+      ad9832_calc_freqreg()
+
+  * CVE-2023-52880
+    - tty: n_gsm: require CAP_NET_ADMIN to attach N_GSM0710 ldisc
+
+  * CVE-2024-50171
+    - net: systemport: fix potential memory leak in bcm_sysport_xmit()
+
+  * CVE-2024-43900
+    - media: xc2028: avoid use-after-free in load_firmware_cb()
+
+  * CVE-2024-40981
+    - batman-adv: bypass empty buckets in batadv_purge_orig_ref()
+
+  * CVE-2024-43893
+    - serial: core: check uartclk for zero to avoid divide by zero
+
+  * CVE-2024-36886
+    - tipc: fix UAF in error path
+
+  * CVE-2024-40943
+    - ocfs2: fix races between hole punching and AIO+DIO
+
+  * CVE-2024-38567
+    - USB: core: add helpers to retrieve endpoints in reverse order
+    - USB: core: Add routines for endpoint checks in old drivers
+    - wifi: carl9170: add a proper sanity check for endpoints
+
+  * CVE-2024-44931
+    - gpio: prevent potential speculation leaks in gpio_device_get_desc()
+
+  * CVE-2024-43863
+    - drm/vmwgfx: Fix a deadlock in dma buf fence polling
+
+  * CVE-2024-43892
+    - memcg: remove memcg_cgroup::id from IDR on mem_cgroup_css_alloc() failure
+    - memcg: protect concurrent access to mem_cgroup_idr
+
+  * CVE-2024-43854
+    - block: initialize integrity buffer to zero before writing it to media
+
+  * CVE-2024-40911
+    - wifi: cfg80211: Lock wiphy in cfg80211_get_station
+
+  * CVE-2024-41064
+    - powerpc/eeh: avoid possible crash when edev->pdev changes
+
+  * CVE-2024-36964
+    - fs/9p: only translate RWX permissions for plain 9P2000
+
+  * CVE-2024-35896
+    - netfilter: validate user input for expected length
+    - netfilter: complete validation of user input
+
+  * CVE-2024-26685
+    - nilfs2: fix potential bug in end_buffer_async_write
+
+  * CVE-2024-36952
+    - scsi: lpfc: Move NPIV's transport unregistration to after resource clean up
+
+  * CVE-2024-40910
+    - ax25: Fix refcount imbalance on inbound connections
+
+  * CVE-2021-47103
+    - inet: fully convert sk->sk_rx_dst to RCU rules
+
+  * CVE-2023-52488
+    - regmap: Add regmap_noinc_read API
+    - regmap: Add regmap_noinc_write API
+    - regmap: fix page selection for noinc writes
+    - regmap: fix page selection for noinc reads
+    - regmap: prevent noinc writes from clobbering cache
+    - serial: sc16is7xx: convert from _raw_ to _noinc_ regmap functions for FIFO
+
+  * CVE-2024-42068
+    - bpf: Take return from set_memory_ro() into account with bpf_prog_lock_ro()
+
+  * CVE-2024-42070
+    - netfilter: nf_tables: fully validate NFT_DATA_VALUE on store to data
+      registers
+
+  * CVE-2023-52522
+    - net: fix possible store tearing in neigh_periodic_work()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Wed, 12 Feb 2025 18:42:15 +0100
+
+linux (4.4.0-264.298) xenial; urgency=medium
+
+  * CVE-2025-0927
+    - SAUCE: fs: hfs/hfsplus: add key_len boundary check to hfs_bnode_read_key
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 07 Feb 2025 17:41:14 +0100
+
+linux (4.4.0-263.297) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-263.297 -proposed tracker (LP: #2093447)
+
+  * CVE-2024-53141
+    - netfilter: ipset: add missing range check in bitmap_ip_uadt
+
+  * CVE-2024-42311
+    - hfs: fix to initialize fields of hfs_inode_info after hfs_alloc_inode()
+
+  * CVE-2024-40982
+    - ssb: Fix potential NULL pointer dereference in ssb_device_uevent()
+
+  * CVE-2024-41012
+    - filelock: Remove locks reliably when fcntl/close race is detected
+    - filelock: Fix fcntl/close race recovery compat path
+    - filelock: Correct the filelock owner in fcntl_setlk/fcntl_setlk64
+
+  * CVE-2024-41066
+    - ibmvnic: Add tx check to prevent skb leak
+
+  * CVE-2024-43914
+    - md/raid5: avoid BUG_ON() while continue reshape after reassembling
+
+  * CVE-2024-42252
+    - closures: Change BUG_ON() to WARN_ON()
+
+  * CVE-2024-38553
+    - net: fec: remove .ndo_poll_controller to avoid deadlocks
+
+  * CVE-2024-38597
+    - eth: sungem: remove .ndo_poll_controller to avoid deadlocks
+
+  * CVE-2024-38553 // CVE-2024-38597
+    - netpoll: make ndo_poll_controller() optional
+    - bonding: use netpoll_poll_dev() helper
+    - netpoll: do not test NAPI_STATE_SCHED in poll_one_napi()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 10 Jan 2025 17:09:31 +0100
+
+linux (4.4.0-262.296) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-262.296 -proposed tracker (LP: #2089998)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * CVE-2024-53057
+    - net/sched: stop qdisc_tree_reduce_backlog on TC_H_ROOT
+
+  * CVE-2024-38619
+    - usb-storage: alauda: Check whether the media is initialized
+
+  * CVE-2024-42153
+    - i2c: img-scb: use setup_timer
+    - i2c/busses: Convert timers to use timer_setup()
+    - i2c: pnx: Fix potential deadlock warning from del_timer_sync() call in isr
+
+  * CVE-2024-44944
+    - netfilter: ctnetlink: use helper function to calculate expect ID
+
+  * CVE-2024-44947
+    - fuse: Initialize beyond-EOF page contents before setting uptodate
+
+  * CVE-2024-45021
+    - memcg_write_event_control(): fix a user-triggerable oops
+
+  * CVE-2024-49967
+    - ext4: no need to continue when the number of entries is 1
+
+  * CVE-2020-12351 // CVE-2020-12352 // CVE-2020-24490
+    - [Config] Disable BlueZ highspeed support
+
+  * CVE-2024-36270
+    - netfilter: tproxy: bail out if IP has been disabled on the device
+
+  * CVE-2024-40912
+    - wifi: mac80211: Fix deadlock in ieee80211_sta_ps_deliver_wakeup()
+
+  * CVE-2024-43856
+    - dma: fix call order in dmam_free_coherent
+
+  * CVE-2024-43884
+    - Bluetooth: MGMT: Add error handling to pair_device()
+
+  * CVE-2024-40959
+    - xfrm6: check ip6_dst_idev() return value in xfrm6_get_saddr()
+
+  * CVE-2024-42090
+    - pinctrl: fix deadlock in create_pinctrl() when handling -EPROBE_DEFER
+
+  * CVE-2024-39301
+    - net/9p: fix uninit-value in p9_client_rpc()
+
+  * CVE-2024-38633
+    - serial: max3100: Update uart_driver_registered on driver removal
+
+  * CVE-2024-36941
+    - wifi: nl80211: don't free NULL coalescing rule
+
+  * CVE-2024-26777
+    - fbdev: sis: Error out if pixclock equals zero
+
+  * CVE-2024-26625
+    - llc: call sock_orphan() at release time
+
+  * CVE-2021-47501
+    - i40e: Fix NULL pointer dereference in i40e_dbg_dump_desc
+
+  * CVE-2024-36946
+    - phonet: fix rtm_phonet_notify() skb allocation
+
+  * CVE-2021-47086
+    - phonet/pep: refuse to enable an unbound pipe
+
+  * CVE-2023-52594
+    - wifi: ath9k: Fix potential array-index-out-of-bounds read in
+      ath9k_htc_txstatus()
+
+  * CVE-2021-47118
+    - pid: take a reference when initializing `cad_pid`
+
+  * CVE-2024-42101
+    - drm/nouveau: fix null pointer dereference in nouveau_connector_get_modes
+
+  * CVE-2024-36968
+    - Bluetooth: L2CAP: Fix div-by-zero in l2cap_le_flowctl_init()
+
+  * CVE-2023-52507
+    - nfc: nci: assert requested protocol is valid
+
+  * CVE-2023-52509
+    - ravb: Fix use-after-free issue in ravb_tx_timeout_work()
+
+  * CVE-2024-35886
+    - ipv6: Fix infinite recursion in fib6_dump_done().
+
+  * CVE-2022-36402
+    - drm/vmwgfx: Use enum to represent graphics context capabilities
+    - drm/vmwgfx: Fix shader stage validation
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 29 Nov 2024 18:11:49 +0100
+
+linux (4.4.0-261.295) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-261.295 -proposed tracker (LP: #2086155)
+
+  * CVE-2024-26633
+    - ip6_tunnel: fix NEXTHDR_FRAGMENT handling in ip6_tnl_parse_tlv_enc_lim()
+
+  * CVE-2023-52502
+    - net: nfc: fix races in nfc_llcp_sock_get() and nfc_llcp_sock_get_sn()
+
+  * CVE-2024-41095
+    - drm/nouveau/dispnv04: fix null pointer dereference in nv17_tv_get_ld_modes
+
+  * CVE-2022-48938
+    - CDC-NCM: avoid overflow in sanity checking
+
+  * CVE-2024-42309
+    - drm/gma500: fix null pointer dereference in psb_intel_lvds_get_modes
+
+  * CVE-2022-24448
+    - NFSv4: Handle case where the lookup of a directory fails
+    - NFS: LOOKUP_DIRECTORY is also ok with symlinks
+
+  * CVE-2024-38560
+    - new helper: memdup_user_nul()
+    - scsi: bfa: Ensure the copied buf is NUL terminated
+
+  * CVE-2021-47055
+    - mtd: require write permissions for locking and badblock ioctls
+
+  * CVE-2024-42310
+    - drm/gma500: fix null pointer dereference in cdv_intel_lvds_get_modes
+
+  * CVE-2024-42240
+    - x86/bhi: Avoid warning in #DB handler due to BHI mitigation
+
+  * CVE-2024-41089
+    - drm/nouveau/dispnv04: fix null pointer dereference in nv17_tv_get_hd_modes
+
+  * CVE-2024-46743
+    - of: irq: use of_property_read_u32()
+    - of/irq: use of_property_read_u32_index to parse interrupts property
+    - of/irq: Prevent device address out-of-bounds read in interrupt map walk
+
+  * CVE-2024-46757
+    - hwmon: (nct6775-core) Fix underflows seen when writing limit attributes
+
+  * CVE-2024-42244
+    - USB: serial: mos7840: fix crash on resume
+
+  * CVE-2024-46756
+    - hwmon: (w83627ehf) Fix underflows seen when writing limit attributes
+
+  * CVE-2024-46758
+    - hwmon: (lm95234) Fix underflows seen when writing limit attributes
+
+  * CVE-2024-46759
+    - hwmon: (adc128d818) Fix underflows seen when writing limit attributes
+
+  * CVE-2024-46723
+    - drm/amdgpu: fix ucode out-of-bounds read warning
+
+  * CVE-2024-46800
+    - sch/netem: fix use after free in netem_dequeue
+
+  * CVE-2024-46722
+    - drm/amdgpu: fix mc_data out-of-bounds read warning
+
+  * CVE-2024-46738
+    - VMCI: Fix use-after-free when removing resource in vmci_resource_remove()
+
+  * CVE-2023-52578
+    - net/core: relax BUILD_BUG_ON in netdev_stats_to_stats64
+    - net: core: Fix slab-out-of-bounds in netdev_stats_to_stats64
+    - net: add atomic_long_t to net_device_stats fields
+    - net: Fix unwanted sign extension in netdev_stats_to_stats64()
+    - net: bridge: use DEV_STATS_INC()
+
+  * CVE-2023-52599
+    - jfs: fix array-index-out-of-bounds in diNewExt
+
+  * CVE-2024-26636
+    - llc: make llc_ui_sendmsg() more robust against bonding changes
+
+  * CVE-2024-44942
+    - f2fs: fix to do sanity check on F2FS_INLINE_DATA flag in inode during GC
+
+  * CVE-2024-26675
+    - ppp_async: limit MRU to 64K
+
+  * CVE-2024-44998
+    - atm: idt77252: prevent use after free in dequeue_rx()
+
+  * CVE-2022-48733
+    - btrfs: fix use-after-free after failure to create a snapshot
+
+  * CVE-2024-35877
+    - x86/mm/pat: fix VM_PAT handling in COW mappings
+
+  * CVE-2022-48943
+    - KVM: x86/mmu: make apf token non-zero to fix bug
+
+  * CVE-2024-41059
+    - hfsplus: fix uninit-value in copy_name
+
+  * CVE-2024-42104
+    - nilfs2: add missing check for inode numbers on directory entries
+
+  * CVE-2024-43882
+    - exec: Fix ToCToU between perm check and set-uid/gid usage
+
+  * CVE-2024-44987
+    - ipv6: prevent UAF in ip6_send_skb()
+
+  * CVE-2023-52531
+    - wifi: iwlwifi: mvm: Fix a memory corruption issue
+
+  * CVE-2024-26668
+    - compiler.h: enable builtin overflow checkers and add fallback code
+    - netfilter: nft_limit: reject configurations that cause integer overflow
+
+  * CVE-2024-38538
+    - net: bridge: xmit: make sure we have at least eth header len bytes
+
+  * CVE-2024-41071
+    - wifi: mac80211: Avoid address calculations via out of bounds array indexing
+
+  * CVE-2023-52614
+    - PM / devfreq: Fix buffer overflow in trans_stat_show
+
+  * CVE-2024-27397
+    - netfilter: nf_tables: use timestamp to check for set element timeout
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 01 Nov 2024 11:36:54 +0100
+
+linux (4.4.0-260.294) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-260.294 -proposed tracker (LP: #2082326)
+
+  * CVE-2024-44940
+    - fou: remove warn in gue_gro_receive on unsupported protocol
+
+  * CVE-2024-46673
+    - scsi: aacraid: Fix double-free on probe failure
+
+  * CVE-2024-26812
+    - vfio/pci: Fix ordering of eventfd vs virqfd shutdown
+    - vfio: Introduce interface to flush virqfd inject workqueue
+    - vfio/pci: Create persistent INTx handler
+
+  * CVE-2024-26810
+    - vfio/pci: Lock external INTx masking ops
+
+  * CVE-2024-42284
+    - tipc: Return non-zero value from tipc_udp_addr2str() on error
+
+  * CVE-2024-38602
+    - ax25: Fix reference count leak issues of ax25_dev
+
+  * CVE-2024-38627
+    - stm class: Fix a double free in stm_register_device()
+
+  * CVE-2024-39487
+    - bonding: Fix out-of-bounds read in bond_option_arp_ip_targets_set()
+
+  * CVE-2024-42280
+    - mISDN: Fix a use after free in hfcmulti_tx()
+
+  * CVE-2024-42271
+    - net/iucv: fix use after free in iucv_sock_close()
+
+  * CVE-2024-43858
+    - jfs: Fix array-index-out-of-bounds in diFree
+
+  * CVE-2024-42229
+    - crypto: aead,cipher - zeroize key buffer after use
+
+  * CVE-2024-38621
+    - media: stk1160: fix bounds checking in stk1160_copy_video()
+
+  * CVE-2024-27436
+    - ALSA: usb-audio: Stop parsing channels bits when all channels are found.
+
+  * CVE-2024-41097
+    - usb: atm: cxacru: fix endpoint checking in cxacru_bind()
+
+  * CVE-2024-38630
+    - watchdog: cpu5wdt.c: Fix use-after-free bug caused by cpu5wdt_trigger
+
+  * CVE-2024-42089
+    - ASoC: fsl-asoc-card: set priv->pdev before using it
+
+  * CVE-2024-39494
+    - constify ima_d_path()
+    - ima: fix ima_d_path() possible race with rename
+    - ima: pass filename to ima_rdwr_violation_check()
+    - include/linux/dcache.h: use unsigned chars in struct name_snapshot
+    - ovl_lookup_real_one(): don't bother with strlen()
+    - ima: Fix use-after-free on a dentry's dname.name
+
+  * CVE-2024-42223
+    - media: dvb-frontends: tda10048: Fix integer overflow
+
+  * CVE-2023-52528
+    - usbnet/smsc75xx: silence uninitialized variable warning
+    - net: usb: smsc75xx: Fix uninit-value access in __smsc75xx_read_reg
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 27 Sep 2024 16:50:34 +0200
+
+linux (4.4.0-259.293) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-259.293 -proposed tracker (LP: #2078241)
+
+  * CVE-2024-26851
+    - netfilter: nf_conntrack_h323: Add protection for bmp length out of range
+
+  * CVE-2024-26880
+    - dm: call the resume method on internal suspend
+
+  * CVE-2024-38583
+    - timer: Prepare to change timer callback argument type
+    - um/time: Fixup namespace collision
+    - timer: Provide wrappers safe for use with LOCKDEP
+    - fs/nilfs2: convert timers to use timer_setup()
+    - nilfs2: fix use-after-free of timer for log writer thread
+
+  * CVE-2024-42228
+    - drm/amdgpu: Using uninitialized value *size when calling amdgpu_vce_cs_reloc
+
+  * CVE-2022-48850
+    - net-sysfs: add check for netdevice being present to speed_show
+
+  * CVE-2024-26733
+    - arp: Prevent overflow in arp_req_get().
+
+  * CVE-2024-40902
+    - jfs: xattr: fix buffer overflow for invalid xattr
+
+  * CVE-2021-47181
+    - usb: musb: tusb6010: check return value after calling
+      platform_get_resource()
+
+  * CVE-2022-48791
+    - scsi: pm80xx: Fix TMF task completion race condition
+    - scsi: pm8001: Fix use-after-free for aborted TMF sas_task
+
+  * CVE-2024-38570
+    - GFS2: Reintroduce a timeout in function gfs2_gl_hash_clear
+    - gfs2: Rename sd_{ glock => kill }_wait
+    - gfs2: Fix potential glock use-after-free on unmount
+
+  * CVE-2023-52527
+    - ipv4, ipv6: Fix handling of transhdrlen in __ip{,6}_append_data()
+
+  * CVE-2024-27437
+    - genirq: Add IRQF_NO_AUTOEN for request_irq/nmi()
+    - vfio/pci: Disable auto-enable of exclusive INTx IRQ
+
+  * CVE-2024-26651
+    - sr9800: Add check for usbnet_get_endpoints
+
+  * CVE-2024-42154
+    - tcp_metrics: validate source addr length
+
+  * CVE-2022-48863
+    - mISDN: Fix memory leak in dsp_pipeline_build()
+
+  * CVE-2024-26677
+    - rxrpc: Fix delayed ACKs to not set the reference serial number
+
+  * CVE-2022-48836
+    - Input: aiptek - properly check endpoint type
+
+  * CVE-2022-48838
+    - usb: gadget: Fix use-after-free bug by not setting udc->dev.driver
+
+  * CVE-2022-48851
+    - staging: gdm724x: fix use after free in gdm_lte_rx()
+
+  * CVE-2021-47188
+    - scsi: ufs: core: Improve SCSI abort handling
+
+  * CVE-2023-52809
+    - scsi: libfc: Fix potential NULL pointer dereference in fc_lport_ptp_setup()
+
+  * CVE-2022-48857
+    - NFC: port100: fix use-after-free in port100_send_complete
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Thu, 29 Aug 2024 13:45:03 +0200
+
+linux (4.4.0-258.292) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-258.292 -proposed tracker (LP: #2075816)
+
+  * CVE-2021-46906
+    - HID: usbhid: fix info leak in hid_submit_ctrl
+
+  * CVE-2021-47239
+    - net: usb: fix possible use-after-free in smsc75xx_bind
+
+  * CVE-2021-47171
+    - net: usb: fix memory leak in smsc75xx_bind
+
+  * CVE-2024-27013
+    - tun: limit printing rate when illegal packet received by tun dev
+
+  * CVE-2021-47518
+    - nfc: fix potential NULL pointer deref in nfc_genl_dump_ses_done
+
+  * CVE-2023-52806
+    - ALSA: hda: Fix possible null-ptr-deref when assigning a stream
+
+  * CVE-2021-46905
+    - net: hso: fix NULL-deref on disconnect regression
+
+  * CVE-2021-46904
+    - net: hso: fix null-ptr-deref during tty device unregistration
+
+  * CVE-2021-47542
+    - net: qlogic: qlcnic: Fix a NULL pointer dereference in
+      qlcnic_83xx_add_rings()
+
+  * CVE-2024-26679
+    - inet: read sk->sk_family once in inet_recv_error()
+
+  * CVE-2024-39484
+    - mmc: davinci: Don't strip remove function when driver is builtin
+
+  * CVE-2021-46924
+    - NFC: st21nfca: Fix memory leak in device probe and remove
+
+  * CVE-2024-26929
+    - scsi: qla2xxx: Fix double free of fcport
+
+  * CVE-2022-48659
+    - mm/slub: fix to return errno if kmalloc() fails
+
+  * CVE-2023-52470
+    - drm/radeon: Remove deprecated create_singlethread_workqueue
+    - drm/radeon: check the alloc_workqueue return value in radeon_crtc_init()
+
+  * CVE-2021-47173
+    - misc/uss720: fix memory leak in uss720_probe
+    - usb: misc: uss720: remove redundant pointer usbdev
+    - usb: misc: fix improper handling of refcount in uss720_probe()
+
+  * CVE-2021-47521
+    - can: sja1000: fix use after free in ems_pcmcia_add_card()
+
+  * CVE-2024-26654
+    - ALSA: sh: aica: Remove deprecated create_workqueue
+    - ALSA: sh: aica: Convert timers to use timer_setup()
+    - ALSA: aica: Fix a long-time build breakage
+    - ALSA: sh: aica: reorder cleanup operations to avoid UAF bugs
+
+  * CVE-2024-26600
+    - phy: ti: phy-omap-usb2: Fix NULL pointer dereference for SRP
+
+  * CVE-2024-39292
+    - um: Add winch to winch_handlers before registering winch IRQ
+
+  * CVE-2024-26687
+    - xen/events: close evtchn after mapping cleanup
+
+  * CVE-2023-52760
+    - gfs2: Fix slab-use-after-free in gfs2_qd_dealloc
+
+  * CVE-2024-36901
+    - ipv6: prevent NULL dereference in ip6_output()
+
+  * CVE-2023-52644
+    - b43: dma: Fix use true/false for bool type variable
+    - wifi: b43: Stop/wake correct queue in DMA Tx path when QoS is disabled
+
+  * CVE-2024-24860
+    - Bluetooth: Fix atomicity violation in {min,max}_key_size_set
+
+  * CVE-2023-52629
+    - sh: push-switch: Reorder cleanup operations to avoid use-after-free bug
+
+  * CVE-2024-22099 // CVE-2024-26903
+    - Bluetooth: rfcomm: Fix null-ptr-deref in rfcomm_check_security
+
+  * CVE-2021-47571
+    - staging: rtl8192e: Fix use after free in _rtl92e_pci_disconnect()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 02 Aug 2024 18:05:35 +0200
+
+linux (4.4.0-257.291) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-257.291 -proposed tracker (LP: #2072141)
+
+  * CVE-2024-26886
+    - Bluetooth: af_bluetooth: Fix deadlock
+
+  * CVE-2023-52620
+    - netfilter: nf_tables: disallow timeout for anonymous sets
+
+  * CVE-2021-46960
+    - cifs: Return correct error code from smb2_get_enc_key
+
+  * CVE-2024-36902
+    - net/ipv6: Refactor fib6_rule_action
+    - ipv6: fib6_rules: avoid possible NULL dereference in fib6_rule_action()
+
+  * CVE-2024-26840
+    - cachefiles: fix memory leak in cachefiles_add_cache()
+
+  * CVE-2024-26857
+    - geneve: implement geneve_get_sk_family helper
+    - geneve: move geneve device lookup before iptunnel_pull_header
+    - geneve: make sure to pull inner header in geneve_rx()
+
+  * CVE-2024-35978
+    - Bluetooth: Fix memory leak in hci_req_sync_complete()
+
+  * CVE-2023-52752
+    - smb: client: fix use-after-free bug in cifs_debug_data_proc_show()
+
+  * CVE-2024-26934
+    - USB: core: Fix deadlock in usb_deauthorize_interface()
+
+  * CVE-2024-35984
+    - i2c: add param sanity check to i2c_transfer()
+    - i2c: smbus: fix NULL function pointer dereference
+
+  * CVE-2024-35982
+    - batman-adv: Avoid infinite loop trying to resize local TT
+
+  * CVE-2024-35997
+    - HID: i2c-hid: remove I2C_HID_READ_PENDING flag to prevent lock-up
+
+  * CVE-2024-26882
+    - net: ip_tunnel: make sure to pull inner header in ip_tunnel_rcv()
+
+  * CVE-2024-26901
+    - do_sys_name_to_handle(): use kzalloc() to fix kernel-infoleak
+
+  * CVE-2024-26884
+    - bpf: Fix hashtab overflow check on 32-bit arches
+
+  * CVE-2024-36016
+    - tty: n_gsm: fix possible out-of-bounds in gsm0_receive()
+
+  * CVE-2023-52436
+    - f2fs: explicitly null-terminate the xattr list
+
+  * CVE-2023-52469
+    - drivers/amd/pm: fix a use-after-free in kv_parse_power_table
+
+  * CVE-2024-27020
+    - netfilter: nf_tables: __nft_expr_type_get() selects specific family type
+    - netfilter: nf_tables: Fix potential data-race in __nft_expr_type_get()
+
+  * CVE-2024-24857 // CVE-2024-24858
+    - Bluetooth: Fix TOCTOU in HCI debugfs implementation
+
+  * CVE-2021-47194
+    - cfg80211: call cfg80211_stop_ap when switch from P2P_GO type
+
+  * CVE-2021-46933
+    - usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.
+
+  * CVE-2024-25739
+    - ubi: Check for too small LEB size in VTBL code
+
+  * CVE-2021-46932
+    - Input: appletouch - initialize work before device registration
+
+  * CVE-2023-52444
+    - f2fs: fix to avoid dirent corruption
+
+  * CVE-2023-52449
+    - mtd: Fix gluebi NULL pointer dereference caused by ftl notifier
+
+  * CVE-2023-46343
+    - nfc: nci: fix possible NULL pointer dereference in send_acknowledge()
+
+  * CVE-2022-48619
+    - Input: add bounds checking to input_set_capability()
+
+  * CVE-2024-26923
+    - af_unix: annote lockless accesses to unix_tot_inflight & gc_in_progress
+    - af_unix: Do not use atomic ops for unix_sk(sk)->inflight.
+    - af_unix: Fix garbage collector racing against connect()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 05 Jul 2024 14:21:12 +0200
+
+linux (4.4.0-256.290) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-256.290 -proposed tracker (LP: #2069738)
+
+  * CVE-2024-2201
+    - x86/cpufeatures: Add new word for scattered features
+    - x86/cpufeatures: Add CPUID_LNX_5 to track recently added Linux-defined word
+    - x86/bugs: Change commas to semicolons in 'spectre_v2' sysfs file
+    - x86/bhi: Add support for clearing branch history at syscall entry
+    - x86/bhi: Define SPEC_CTRL_BHI_DIS_S
+    - x86/bhi: Enumerate Branch History Injection (BHI) bug
+    - x86/bhi: Add BHI mitigation knob
+    - x86/bhi: Mitigate KVM by default
+    - [Config] updateconfigs for CONFIG_BHI_{AUTO|OFF|ON}
+    - x86/bugs: Make sure MSR_SPEC_CTRL is updated properly upon resume from S3
+    - x86/bugs: Fix BHI documentation
+    - x86/bugs: Cache the value of MSR_IA32_ARCH_CAPABILITIES
+    - x86/bugs: Rename various 'ia32_cap' variables to 'x86_arch_cap_msr'
+    - x86/bugs: Fix BHI handling of RRSBA
+    - x86/bugs: Clarify that syscall hardening isn't a BHI mitigation
+    - x86/bugs: Fix BHI retpoline check
+
+  * CVE-2024-23307
+    - md/raid5: fix atomicity violation in raid5_cache_count
+
+  * CVE-2024-26642
+    - netfilter: nf_tables: disallow anonymous set with timeout flag
+
+  * CVE-2024-26720
+    - mm/writeback: fix possible divide-by-zero in wb_dirty_limits(), again
+
+  * CVE-2024-24861
+    - media: xc4000: Fix atomicity violation in xc4000_get_frequency
+
+  * CVE-2023-6270
+    - aoe: fix the potential use-after-free problem in aoecmd_cfg_pkts
+
+  * CVE-2021-33631
+    - ext4: fix kernel BUG in 'ext4_write_inline_data_end()'
+
+  * CVE-2023-52615
+    - hwrng: core - Fix page fault dead lock on mmap-ed hwrng
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Wed, 19 Jun 2024 13:23:18 +0200
+
+linux (4.4.0-254.288) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-254.288 -proposed tracker (LP: #2064637)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] debian.master/dkms-versions -- update from kernel-versions
+      (main/s2024.04.01)
+
+  * CVE-2023-52566
+    - nilfs2: fix potential use after free in nilfs_gccache_submit_read_data()
+
+  * CVE-2023-52530
+    - wifi: mac80211: fix potential key use-after-free
+
+  * CVE-2024-26805
+    - netlink: Fix kernel-infoleak-after-free in __skb_datagram_iter
+
+  * CVE-2024-26635
+    - llc: Drop support for ETH_P_TR_802_2.
+
+  * CVE-2024-26622
+    - tomoyo: fix UAF write bug in tomoyo_write_control()
+
+  * CVE-2024-26614
+    - tcp: make sure init the accept_queue's spinlocks once
+    - ipv6: init the accept_queue's spinlocks in inet6_create
+
+  * CVE-2023-52602
+    - jfs: fix slab-out-of-bounds Read in dtSearch
+
+  * CVE-2023-52601
+    - FS:JFS:UBSAN:array-index-out-of-bounds in dbAdjTree
+    - jfs: Fix memleak in dbAdjCtl
+    - jfs: fix array-index-out-of-bounds in dbAdjTree
+
+  * CVE-2023-52524
+    - net: nfc: llcp: Add lock when modifying device list
+
+  * CVE-2023-47233
+    - wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach
+
+  * CVE-2021-46939
+    - tracing: Restructure trace_clock_global() to never block
+    - tracing: Do no increment trace_clock_global() by one
+
+  * CVE-2024-26801
+    - Bluetooth: Avoid potential use-after-free in hci_error_reset
+
+  * CVE-2024-26704
+    - ext4: fix double-free of blocks due to wrong extents moved_len
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 02 May 2024 16:45:40 +0200
+
+linux (4.4.0-253.287) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-253.287 -proposed tracker (LP: #2059563)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+
+  * CVE-2021-46990
+    - powerpc/64s: Fix crashes when toggling entry flush barrier
+
+  * CVE-2023-52603
+    - UBSAN: array-index-out-of-bounds in dtSplitRoot
+
+  * CVE-2022-20422
+    - arm64: fix oops in concurrently setting insn_emulation sysctls
+
+  * CVE-2023-52451
+    - powerpc/pseries/memhp: Fix access beyond end of drmem array
+
+  * CVE-2023-52600
+    - JFS: fix memleak in jfs_mount
+    - jfs: fix uaf in jfs_evict_inode
+
+  * CVE-2023-51043
+    - drm/atomic: Fix potential use-after-free in nonblocking commits
+
+  * CVE-2024-23851
+    - dm ioctl: log an error if the ioctl structure is corrupted
+    - dm: limit the number of targets and parameter size area
+
+  * Cranky update-dkms-versions rollout (LP: #2055685)
+    - Move debian/dkms-versions to debian.master/dkms-versions
+    - [Packaging] Replace debian/dkms-versions with $(DEBIAN)/dkms-versions
+
+  * Remove getabis scripts (LP: #2059143)
+    - [Packaging] Remove getabis
+
+  * CVE-2019-25162
+    - i2c: Fix a potential use after free
+
+  * CVE-2023-24023
+    - Bluetooth: Add debug setting for changing minimum encryption key size
+    - Bluetooth: Add more enc key size check
+
+  * CVE-2021-46955
+    - openvswitch: fix stack OOB read while fragmenting IPv4 packets
+
+  * CVE-2021-46936
+    - net: fix use-after-free in tw_timer_handler
+
+  * CVE-2021-46966
+    - ACPI: custom_method: fix potential use-after-free issue
+
+  * CVE-2023-52445
+    - media: pvrusb2: fix use after free on context disconnection
+
+  * CVE-2023-1998
+    - x86/speculation: Allow enabling STIBP with legacy IBRS
+
+  * CVE-2023-51779
+    - Bluetooth: af_bluetooth: Fix Use-After-Free in bt_sock_recvmsg
+
+  * CVE-2023-1382
+    - tipc: set con sock in tipc_conn_alloc
+    - tipc: add an extra conn_get in tipc_conn_alloc
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Thu, 28 Mar 2024 16:45:31 +0100
+
+linux (4.4.0-252.286) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-252.286 -proposed tracker (LP: #2055907)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop ABI data
+
+  * CVE-2022-20567
+    - l2tp: don't use inet_shutdown on ppp session destroy
+    - l2tp: fix race in pppol2tp_release with session object destroy
+    - l2tp: fix refcount leakage on PPPoL2TP sockets
+
+  * CVE-2023-51781
+    - appletalk: Fix Use-After-Free in atalk_ioctl
+
+  * CVE-2024-1086
+    - netfilter: nf_tables: reject QUEUE/DROP verdict parameters
+
+  * CVE-2023-39197
+    - netfilter: conntrack: dccp: copy entire header to stack buffer, not just
+      basic one
+
+  * CVE-2023-34256
+    - ext4: avoid a potential slab-out-of-bounds in ext4_group_desc_csum
+
+  * CVE-2024-24855
+    - scsi: lpfc: Fix a possible data race in lpfc_unregister_fcf_rescan()
+
+  * CVE-2024-0775
+    - ext4: improve error recovery code paths in __ext4_remount()
+
+  * Drop ABI checks from kernel build (LP: #2055686)
+    - [Packaging] Remove in-tree abi checks
+    - [Packaging] Bring back install-<flavour> prerequisite for checks-<flavour>
+    - [Packaging] Remove abi-check from final-checks
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Tue, 05 Mar 2024 21:37:05 +0100
+
+linux (4.4.0-251.285) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-251.285 -proposed tracker (LP: #2052153)
+
+  * CVE-2023-51782
+    - net/rose: Fix Use-After-Free in rose_ioctl
+
+  * CVE-2023-51780
+    - atm: Fix Use-After-Free in do_vcc_ioctl
+
+  * CVE-2023-7192
+    - netfilter: ctnetlink: fix possible refcount leak in
+      ctnetlink_create_conntrack()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 02 Feb 2024 22:16:53 +0100
+
+linux (4.4.0-250.284) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-250.284 -proposed tracker (LP: #2049044)
+
+  * CVE-2023-6932
+    - ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
+
+  * CVE-2023-6931
+    - perf: Allow perf_release() with !event->ctx
+    - perf: Fix perf_event_validate_size()
+    - perf: Fix perf_event_validate_size() lockdep splat
+
+  * CVE-2023-6606
+    - smb: client: fix OOB in smbCalcSize()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 15 Jan 2024 06:58:39 -0300
+
+linux (4.4.0-249.283) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-249.283 -proposed tracker (LP: #2046291)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] remove helper scripts
+
+  * CVE-2023-45863
+    - kobject: Fix slab-out-of-bounds in fill_kobj_path()
+
+  * CVE-2023-20588
+    - x86/bugs: Increase the x86 bugs vector size to two u32s
+    - x86/CPU/AMD: Do not leak quotient data after a division by 0
+    - x86/CPU/AMD: Fix the DIV(0) initial fix attempt
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 13 Dec 2023 17:18:19 -0300
+
+linux (4.4.0-248.282) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-248.282 -proposed tracker (LP: #2044347)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * CVE-2023-20593
+    - jump_label: Make it possible for arches to invoke jump_label_init() earlier
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 23 Nov 2023 07:33:23 -0300
+
+linux (4.4.0-247.281) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-247.281 -proposed tracker (LP: #2042032)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * CVE-2023-45871
+    - SAUCE: igb: do not allow bad packets when using RX-ALL
+
+  * CVE-2023-20593
+    - x86/cpu/amd: Move the errata checking functionality up
+    - x86/microcode/AMD: Add a @cpu parameter to the reloading functions
+    - x86/jump_label: Initialize static branching early
+    - x86/CPU: Call detect_nopl() only on the BSP
+    - x86/cpu/amd: Add a Zenbleed fix
+
+  * CVE-2023-39189
+    - netfilter: nfnetlink_osf: avoid OOB read
+
+  * CVE-2023-5717
+    - perf/core: Fix __perf_read_group_add() locking
+    - perf: Disallow mis-matched inherited group reads
+
+  * CVE-2023-31085
+    - ubi: Refuse attaching if mtd's erasesize is 0
+
+  * CVE-2023-39194
+    - net: xfrm: Fix xfrm_address_filter OOB read
+
+  * CVE-2023-39193
+    - netfilter: xt_sctp: validate the flag_info count
+
+  * CVE-2023-39192
+    - netfilter: xt_u32: validate user space input
+
+  * CVE-2023-45862
+    - USB: ene_usb6250: Allocate enough memory for full object
+
+  * CVE-2023-42754
+    - ipv4: fix null-deref in ipv4_link_failure
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 14 Nov 2023 11:39:37 -0300
+
+linux (4.4.0-246.280) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-246.280 -proposed tracker (LP: #2038362)
+
+  * CVE-2023-42755
+    - net/sched: Retire rsvp classifier
+    - [Config] remove NET_CLS_RSVP and NET_CLS_RSVP6
+
+  * CVE-2023-42752
+    - igmp: limit igmpv3_newpack() packet size to IP_MAX_MTU
+
+  * CVE-2023-42753
+    - netfilter: ipset: add the missing IP_SET_HASH_WITH_NET0 macro for
+      ip_set_hash_netportnet.c
+
+  * CVE-2023-4921
+    - net: sched: sch_qfq: Fix UAF in qfq_dequeue()
+
+  * CVE-2023-4623
+    - net/sched: sch_hfsc: Ensure inner classes have fsc curve
+
+  * CVE-2023-34319
+    - xen/netback: Fix buffer overrun triggered by unusual packet
+
+  * CVE-2023-4881
+    - netfilter: nftables: exthdr: fix 4-byte stack OOB write
+
+  * CVE-2023-4622
+    - af_unix: Fix null-ptr-deref in unix_stream_sendpage().
+
+  * CVE-2023-31083
+    - Bluetooth: hci_ldisc: check HCI_UART_PROTO_READY flag in HCIUARTGETPROTO
+
+  * CVE-2023-3772
+    - xfrm: add NULL check in xfrm_update_ae_params
+
+  * CVE-2023-1206
+    - tcp: Reduce chance of collisions in inet6_hashfn().
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 05 Oct 2023 16:59:51 -0300
+
+linux (4.4.0-245.279) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-245.279 -proposed tracker (LP: #2035275)
+
+  * CVE-2022-40982
+    - x86/speculation: Identify processors vulnerable to SMT RSB predictions
+    - init: Provide arch_cpu_finalize_init()
+    - cpu/hotplug: Fix "SMT disabled by BIOS" detection for KVM
+    - x86/cpu: Switch to arch_cpu_finalize_init()
+    - ARM: cpu: Switch to arch_cpu_finalize_init()
+    - um/cpu: Switch to arch_cpu_finalize_init()
+    - init: Remove check_bugs() leftovers
+    - x86/cpu: Add Tiger Lake to Intel family
+    - x86/speculation: Add Gather Data Sampling mitigation
+    - KVM: Add GDS_NO support to KVM
+    - [Config]: Enable CONFIG_ARCH_HAS_CPU_FINALIZE_INIT
+
+  * CVE-2023-4459
+    - net: vmxnet3: fix possible NULL pointer dereference in vmxnet3_rq_cleanup()
+
+  * CVE-2023-4385
+    - fs: jfs: fix possible NULL pointer dereference in dbFree()
+
+  * CVE-2023-4387
+    - net: vmxnet3: fix possible use-after-free bugs in vmxnet3_rq_alloc_rx_buf()
+
+  * CVE-2023-3863
+    - nfc: llcp: simplify llcp_sock_connect() error paths
+    - net: nfc: Fix use-after-free caused by nfc_llcp_find_local
+
+  * CVE-2023-32269
+    - netrom: Fix use-after-free caused by accept on already connected socket
+
+  * CVE-2023-40283
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb
+
+  * CVE-2023-4128
+    - net/sched: cls_u32: No longer copy tcf_result on update to avoid use-after-
+      free
+    - net/sched: cls_fw: No longer copy tcf_result on update to avoid use-after-
+      free
+    - net/sched: cls_route: No longer copy tcf_result on update to avoid use-
+      after-free
+
+  * CVE-2023-3212
+    - gfs2: Don't deref jdesc in evict
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 12 Sep 2023 15:45:45 -0300
+
+linux (4.4.0-244.278) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-244.278 -proposed tracker (LP: #2030665)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+  * CVE-2023-3567
+    - vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF
+
+  * CVE-2023-2985
+    - fs: hfsplus: fix UAF issue in hfsplus_put_super
+
+  * CVE-2023-31084 // CVE-2023-31084 was assigned to this bug.
+    - media: dvb-core: Fix kernel WARNING for blocking operation in wait_event*()
+
+  * CVE-2023-3776
+    - net/sched: cls_fw: Fix improper refcount update leads to use-after-free
+
+  * CVE-2023-3611
+    - net/sched: cls_matchall: fix crash when used with classful qdisc
+    - net/sched: sch_qfq: account for stab overhead in qfq_enqueue
+
+  * CVE-2023-2269
+    - dm ioctl: fix nested locking in table_clear() to remove deadlock concern
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 16 Aug 2023 15:09:02 -0300
+
+linux (4.4.0-243.277) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-243.277 -proposed tracker (LP: #2026875)
+
+  * CVE-2023-2162
+    - scsi: iscsi_tcp: Fix UAF during login when accessing the shost ipaddress
+
+  * CVE-2023-3268
+    - kernel/relay.c: fix read_pos error when multiple readers
+    - relayfs: fix out-of-bounds access in relay_file_read
+
+  * CVE-2023-35001
+    - netfilter: nf_tables: prevent OOB access in nft_byteorder_eval
+
+  * CVE-2023-3390
+    - netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE
+
+  * CVE-2023-3090
+    - ipvlan:Fix out-of-bounds caused by unclear skb->cb
+
+  * CVE-2023-1611
+    - btrfs: fix race between quota disable and quota assign ioctls
+
+  * CVE-2023-3141
+    - memstick: r592: Fix UAF bug in r592_remove due to race condition
+
+  * CVE-2023-3159
+    - firewire: fix potential uaf in outbound_phy_packet_callback()
+
+  * CVE-2023-3161
+    - fbcon: Check font dimension limits
+
+  * CVE-2023-2513
+    - ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h
+    - ext4: fix use-after-free in ext4_xattr_set_entry
+
+  * CVE-2023-0458
+    - prlimit: do_prlimit needs to have a speculation check
+
+  * CVE-2023-2124
+    - xfs: verify buffer contents when we skip log replay
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 13 Jul 2023 11:50:51 -0300
+
+linux (4.4.0-242.276) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-242.276 -proposed tracker (LP: #2024572)
+
+  * CVE-2023-3111
+    - btrfs: unset reloc control if transaction commit fails in
+      prepare_to_relocate()
+
+  * CVE-2023-1990
+    - nfc: st-nci: Fix use after free bug in ndlc_remove due to race condition
+
+  * CVE-2021-3753
+    - vt_kdsetmode: extend console locking
+
+  * CVE-2022-1184
+    - ext4: avoid cycles in directory h-tree
+    - ext4: verify dir block before splitting it
+    - ext4: check if directory block is within i_size
+    - ext4: make sure ext4_append() always allocates new block
+    - ext4: fix check for block being out of directory size
+
+  * CVE-2021-20321
+    - ovl: fix missing negative dentry check in ovl_rename()
+
+  * Bionic update: upstream stable patchset 2022-12-01 (LP: #1998542) //
+    CVE-2022-29901
+    - SAUCE: Fix kernel IBRS implementation
+
+  * CVE-2022-29901
+    - intel_idle: Add SKX support
+    - Revert "x86/cpu: Add a steppings field to struct x86_cpu_id"
+    - x86/cpufeature: Add facility to check for min microcode revisions
+    - x86/cpufeature: Fix various quality problems in the <asm/cpu_device_hd.h>
+      header
+    - x86/devicetable: Move x86 specific macro out of generic code
+    - x86/cpu: Add consistent CPU match macros
+    - x86/cpu: Add a steppings field to struct x86_cpu_id
+    - x86/entry: Remove skip_r11rcx
+    - x86/cpufeatures: Move RETPOLINE flags to word 11
+    - x86/bugs: Report AMD retbleed vulnerability
+    - x86/bugs: Add AMD retbleed= boot parameter
+    - x86/bugs: Keep a per-CPU IA32_SPEC_CTRL value
+    - x86/entry: Add kernel IBRS implementation
+    - x86/bugs: Optimize SPEC_CTRL MSR writes
+    - x86/speculation: Add spectre_v2=ibrs option to support Kernel IBRS
+    - x86/bugs: Split spectre_v2_select_mitigation() and
+      spectre_v2_user_select_mitigation()
+    - x86/bugs: Report Intel retbleed vulnerability
+    - entel_idle: Disable IBRS during long idle
+    - x86/speculation: Change FILL_RETURN_BUFFER to work with objtool
+    - x86/speculation: Add LFENCE to RSB fill sequence
+    - x86/speculation: Fix RSB filling with CONFIG_RETPOLINE=n
+    - x86/speculation: Fix firmware entry SPEC_CTRL handling
+    - x86/speculation: Fix SPEC_CTRL write on SMT state change
+    - x86/speculation: Use cached host SPEC_CTRL value for guest entry/exit
+    - x86/speculation: Remove x86_spec_ctrl_mask
+    - KVM: VMX: Prevent guest RSB poisoning attacks with eIBRS
+    - KVM: VMX: Fix IBRS handling after vmexit
+    - x86/speculation: Fill RSB on vmexit for IBRS
+    - x86/common: Stamp out the stepping madness
+    - x86/cpu/amd: Enumerate BTC_NO
+    - x86/bugs: Add Cannon lake to RETBleed affected CPU list
+    - x86/speculation: Disable RRSBA behavior
+    - x86/speculation: Use DECLARE_PER_CPU for x86_spec_ctrl_current
+    - x86/bugs: Warn when "ibrs" mitigation is selected on Enhanced IBRS parts
+    - x86/speculation: Add RSB VM Exit protections
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 23 Jun 2023 16:35:33 -0300
+
+linux (4.4.0-241.275) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-241.275 -proposed tracker (LP: #2019719)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+
+  * CVE-2023-1073
+    - HID: check empty report_list in hid_validate_values()
+
+  * CVE-2023-31436
+    - net: sched: sch_qfq: prevent slab-out-of-bounds in qfq_activate_agg
+
+  * CVE-2023-1380
+    - wifi: brcmfmac: slab-out-of-bounds read in brcmf_get_assoc_ies()
+
+  * CVE-2023-32233
+    - netfilter: nf_tables: add generic macros to check for generation mask
+    - netfilter: nf_tables: remove check against removal of inactive objects
+    - netfilter: cttimeout: add netns support
+    - netfilter: nfnetlink: pass down netns pointer to call() and call_rcu()
+    - netfilter: nf_tables: add generation mask to tables
+    - netfilter: nf_tables: add generation mask to chains
+    - netfilter: nf_tables: fix update chain error
+    - netfilter: nf_tables: add generation mask to sets
+    - netfilter: nf_tables: check msg_type before nft_trans_set(trans)
+    - netfilter: nf_tables: really skip inactive sets when allocating name
+    - netfilter: nf_tables: add nft_set_is_anonymous() helper
+    - netfilter: nf_tables: reject loops from set element jump to chain
+    - netfilter: nf_tables: fix wrong destroy anonymous sets if binding fails
+    - netfilter: nf_tables: fix *leak* when expr clone fail
+    - netfilter: nf_tables: missing sanitization in data from userspace
+    - netfilter: nf_tables: revisit chain/object refcounting from elements
+    - netfilter: nf_tables: bogus EBUSY in chain deletions
+    - netfilter: nf_tables: can't fail after linking rule into active rule list
+    - netfilter: nf_tables: deactivate expressions in rule replecement routine
+    - netfilter: nf_tables: reverse order in rule replacement expansion
+    - netfilter: nf_tables: split set destruction in deactivate and destroy phase
+    - netfilter: nf_tables: unbind set in rule from commit path
+    - netfilter: nf_tables: fix set double-free in abort path
+    - netfilter: nf_tables: bogus EBUSY when deleting set after flush
+    - netfilter: nf_tables: use-after-free in failing rule with bound set
+    - netfilter: nf_tables: deactivate anonymous set from preparation phase
+
+  * CVE-2023-30456
+    - KVM: nVMX: add missing consistency checks for CR0 and CR4
+
+  * CVE-2023-28328
+    - media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 01 Jun 2023 17:38:33 -0300
+
+linux (4.4.0-240.274) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-240.274 -proposed tracker (LP: #2017289)
+
+  * CVE-2023-1829
+    - net/sched: Retire tcindex classifier
+    - [Config]: Make sure CONFIG_NET_CLS_TCINDEX is not available
+
+  * CVE-2023-1670
+    - xirc2ps_cs: Fix use after free bug in xirc2ps_detach
+
+  * net: sched: Fix use after free in red_enqueue() (LP: #2017013)
+    - net: sched: Fix use after free in red_enqueue()
+
+  * CVE-2022-3586
+    - sch_sfb: Don't assume the skb is still around after enqueueing to child
+    - sch_sfb: Also store skb len before calling child enqueue
+
+  * CVE-2022-4095
+    - staging: rtl8712: fix use after free bugs
+
+  * CVE-2023-1390
+    - tipc: fix NULL deref in tipc_link_xmit()
+    - tipc: Fix backport of b77413446408fdd256599daf00d5be72b5f3e7c6
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Sat, 22 Apr 2023 09:37:14 -0300
+
+linux (4.4.0-239.273) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-239.273 -proposed tracker (LP: #2012774)
+
+  * CVE-2022-2991
+    - lightnvm: disable the subsystem
+    - [Config]: disable CONFIG_NVM as it is broken
+
+  * CVE-2023-23455
+    - net: sched: atm: dont intepret cls results when asked to drop
+
+  * CVE-2022-20132
+    - HID: introduce hid_is_using_ll_driver
+    - HID: add hid_is_usb() function to make it simpler for USB detection
+    - HID: wacom: fix problems when device is not a valid USB device
+    - HID: check for valid USB device for many HID drivers
+    - HID: holtek: fix mouse probing
+
+  * CVE-2022-1205
+    - ax25: Fix UAF bugs in ax25 timers
+    - ax25: Fix NULL pointer dereferences in ax25 timers
+    - ax25: Fix ax25 session cleanup problems
+
+  * CVE-2022-39188
+    - mm: Force TLB flush for PFNMAP mappings before unlink_file_vma()
+    - mm: Fix TLB flush for not-first PFNMAP mappings in unmap_region()
+
+  * CVE-2022-1195
+    - net: hamradio: fix memory leak in mkiss_close
+    - hamradio: defer ax25 kfree after unregister_netdev
+    - hamradio: improve the incomplete fix to avoid NPD
+    - hamradio: defer 6pack kfree after unregister_netdev
+    - hamradio: remove needs_free_netdev to avoid UAF
+
+  * CVE-2023-26607
+    - ntfs: fix use-after-free in ntfs_ucsncmp()
+    - ntfs: fix out-of-bounds read in ntfs_attr_find()
+
+  * CVE-2022-1974
+    - NFC: reorder the logic in nfc_{un,}register_device
+    - nfc: replace improper check device_is_registered() in netlink related
+      functions
+    - NFC: NULL out the dev->rfkill to prevent UAF
+
+  * CVE-2022-3303
+    - ALSA: pcm: oss: Fix race at SNDCTL_DSP_SYNC
+
+  * CVE-2022-4662
+    - USB: core: Prevent nested device-reset calls
+
+  * CVE-2022-2380
+    - video: fbdev: sm712fb: Fix crash in smtcfb_read()
+
+  * CVE-2023-1095
+    - netfilter: nf_tables: fix null deref due to zeroed list head
+
+  * CVE-2023-1074
+    - sctp: fail if no bound addresses can be used for a given scope
+
+  * CVE-2022-0617
+    - udf: Fix NULL ptr deref when converting from inline format
+    - udf: Restore i_lenAlloc when inode expansion fails
+
+  * CVE-2022-1462
+    - tty: fix deadlock caused by calling printk() under tty_port->lock
+    - tty: extract tty_flip_buffer_commit() from tty_flip_buffer_push()
+    - tty: use new tty_insert_flip_string_and_push_buffer() in pty_write()
+
+  * CVE-2023-1118
+    - media: rc: Fix use-after-free bugs caused by ene_tx_irqsim()
+
+  * CVE-2022-41218
+    - media: dvb-core: Fix UAF due to refcount races at releasing
+
+  * CVE-2023-26545
+    - net: mpls: fix stale pointer if allocation fails during device rename
+
+  * CVE-2022-41849
+    - fbdev: smscufx: Fix use-after-free in ufx_ops_open()
+
+  * CVE-2022-3111
+    - power: supply: wm8350-power: Add missing free in free_charger_irq
+
+  * CVE-2021-45868
+    - quota: check block number when reading the block in quota file
+
+  * CVE-2021-4203
+    - cred: allow get_cred() and put_cred() to be given NULL.
+    - af_unix: fix races in sk_peer_pid and sk_peer_cred accesses
+    - net/af_unix: fix a data-race in unix_dgram_poll
+    - net/af_unix: fix a data-race in unix_dgram_sendmsg / unix_release_sock
+
+  * CVE-2021-3772
+    - sctp: use init_tag from inithdr for ABORT chunk
+    - sctp: fix the processing for INIT chunk
+    - sctp: fix the processing for INIT_ACK chunk
+    - sctp: fix the processing for COOKIE_ECHO chunk
+    - sctp: add vtag check in sctp_sf_violation
+    - sctp: add vtag check in sctp_sf_do_8_5_1_E_sa
+    - sctp: add vtag check in sctp_sf_ootb
+
+  * CVE-2022-1516
+    - net/x25: Fix null-ptr-deref caused by x25_disconnect
+
+  * CVE-2022-2318
+    - net: rose: fix UAF bugs caused by timer handler
+
+  * CVE-2022-1975
+    - NFC: netlink: fix sleep in atomic bug when firmware download timeout
+
+  * CVE-2022-3903
+    - USB: move snd_usb_pipe_sanity_check into the USB core
+    - USB: add usb_control_msg_send() and usb_control_msg_recv()
+    - USB: correct API of usb_control_msg_send/recv
+    - media: mceusb: Use new usb_control_msg_*() routines
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 24 Mar 2023 19:42:51 -0300
+
+linux (4.4.0-238.272) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-238.272 -proposed tracker (LP: #2009941)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * CVE-2021-3428
+    - ext4: don't allow overlapping system zones
+    - ext4: check journal inode extents more carefully
+
+  * CVE-2022-47929
+    - net: sched: disallow noqueue for qdisc classes
+
+  * CVE-2020-36516
+    - ipv4: avoid using shared IP generator for connected sockets
+
+  * CVE-2023-0394
+    - ipv6: raw: Deduct extension header length in rawv6_push_pending_frames
+
+  * CVE-2022-36280
+    - drm/vmwgfx: Validate the box size for the snooped cursor
+
+  * CVE-2022-41850
+    - HID: roccat: Fix use-after-free in roccat_read()
+
+  * CVE-2022-3061
+    - video: fbdev: i740fb: Error out if 'pixclock' equals zero
+
+  * CVE-2022-3628
+    - wifi: brcmfmac: Fix potential buffer overflow in brcmf_fweh_event_worker()
+
+  * CVE-2021-3732
+    - ovl: prevent private clone if bind mount is not allowed
+
+  * CVE-2021-28713
+    - xen/console: harden hvc_xen against event channel storms
+
+  * CVE-2021-28712
+    - xen/netfront: read response from backend only once
+    - xen/netfront: disentangle tx_skb_freelist
+    - xen/netfront: don't trust the backend response data blindly
+    - xen/netfront: harden netfront against event channel storms
+
+  * CVE-2021-28711
+    - xen: sync include/xen/interface/io/ring.h with Xen's newest version
+    - xen/blkfront: don't take local copy of a request from the ring page
+    - xen/blkfront: read response from backend only once
+    - xen/blkfront: don't trust the backend response data blindly
+    - xen/blkfront: harden blkfront against event channel storms
+    - xen/blkfront: fix bug in backported patch
+
+  * CVE-2022-20572 // CVE-2022-2503
+    - dm verity: set DM_TARGET_IMMUTABLE feature flag
+
+  * CVE-2022-0487
+    - mmc: moxart: remove unneeded check for drvdata
+    - moxart: fix potential use-after-free on remove path
+
+  * CVE-2021-4149
+    - btrfs: unlock newly allocated extent buffer after error
+
+  * CVE-2022-3646
+    - nilfs2: fix leak of nilfs_root in case of writer thread creation failure
+
+  * CVE-2021-26401
+    - x86/speculation: Use generic retpoline by default on AMD
+
+  * CVE-2021-3659
+    - net: mac802154: Fix general protection fault
+
+  * CVE-2021-3669
+    - ipc: replace costly bailout check in sysvipc_find_ipc()
+
+  * CVE-2022-2663
+    - netfilter: nf_conntrack_irc: Fix forged IP logic
+    - netfilter: nf_conntrack_irc: Tighten matching on DCC message
+
+  * CVE-2022-1016
+    - netfilter: nf_tables: initialize registers in nft_do_chain()
+
+  * CVE-2022-0494
+    - block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern
+
+  * rtcpie in timers from ubuntu_kernel_selftests randomly failing
+    (LP: #1814234)
+    - SAUCE: selftest: rtctest: Force passing unreliable subtest
+
+  * CVE-2022-36879
+    - xfrm: xfrm_policy: fix a possible double xfrm_pols_put() in
+      xfrm_bundle_lookup()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Sat, 11 Mar 2023 06:18:13 -0300
+
+linux (4.4.0-237.271) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-237.271 -proposed tracker (LP: #2007452)
+
+  * CVE-2021-4155
+    - xfs: map unwritten blocks in XFS_IOC_{ALLOC,FREE}SP just like fallocate
+
+  * CVE-2023-0045
+    - x86/bugs: Flush IBP in ib_prctl_set()
+
+  * CVE-2023-23559
+    - wifi: rndis_wlan: Prevent buffer overflow in rndis_query_oid
+
+  * CVE-2022-20566
+    - Bluetooth: L2CAP: Fix use-after-free caused by l2cap_chan_put
+
+  * CVE-2022-41858
+    - drivers: net: slip: fix NPD bug in sl_tx_timeout()
+
+  * 5.15.0-58.64 breaks xen bridge networking (pvh domU) (LP: #2002889)
+    - xen/netback: fix build warning
+
+  * CVE-2022-42895
+    - Bluetooth: L2CAP: Fix attempting to access uninitialized memory
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 15 Feb 2023 20:56:04 -0300
+
+linux (4.4.0-236.270) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-236.270 -proposed tracker (LP: #2000934)
+
+  * CVE-2022-45934
+    - Bluetooth: L2CAP: Fix u8 overflow
+
+  * CVE-2022-42896
+    - Bluetooth: L2CAP: Introduce proper defines for PSM ranges
+    - Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM
+    - Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm
+
+  * CVE-2022-3643
+    - xen-netback: support multiple extra info fragments passed from frontend
+    - xen-netback: fix extra_info handling in xenvif_tx_err()
+    - xen/netback: Ensure protocol headers don't fall in the non-linear area
+
+  * CVE-2022-43945
+    - NFSD: Cap rsize_bop result based on send buffer size
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 03 Jan 2023 09:30:47 -0300
+
+linux (4.4.0-235.269) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-235.269 -proposed tracker (LP: #1997020)
+
+  * CVE-2022-42703
+    - mm/rmap.c: don't reuse anon_vma if we just want a copy
+    - mm: rmap: explicitly reset vma->anon_vma in unlink_anon_vmas()
+    - mm, rmap: handle anon_vma_prepare() common case inline
+    - mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse
+
+  * CVE-2022-3565
+    - mISDN: fix use-after-free bugs in l1oip timer handlers
+
+  * CVE-2022-43750
+    - usb: mon: make mmapped memory read only
+
+  * CVE-2022-3566
+    - tcp: Fix data races around icsk->icsk_af_ops.
+
+  * CVE-2022-3567
+    - ipv6: annotate some data-races around sk->sk_prot
+    - ipv6: Fix data races around sk->sk_prot.
+
+  * CVE-2022-3621
+    - nilfs2: fix NULL pointer dereference at nilfs_bmap_lookup_at_level()
+
+  * CVE-2022-3564
+    - Bluetooth: remove unneeded variable in l2cap_stream_rx
+    - Bluetooth: L2CAP: Fix use-after-free caused by l2cap_reassemble_sdu
+
+  * CVE-2022-3524
+    - tcp/udp: Fix memory leak in ipv6_renew_options().
+
+  * CVE-2022-3635
+    - atm: idt77252: fix use-after-free bugs caused by tst_timer
+
+  * CVE-2022-40768
+    - scsi: stex: Properly zero out the passthrough command structure
+
+  * CVE-2022-3239
+    - media: em28xx: initialize refcount before kref_get
+
+  * CVE-2022-3649
+    - nilfs2: fix use-after-free bug of struct nilfs_root
+
+  * CVE-2022-3594
+    - r8152: Rate limit overflow messages
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 18 Nov 2022 14:42:01 -0300
+
+linux (4.4.0-234.268) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-234.268 -proposed tracker (LP: #1990413)
+
+  * CVE-2022-1729
+    - perf: Fix sys_perf_event_open() race against self
+
+  * CVE-2022-2964
+    - ax88179_178a: Merge memcpy + le32_to_cpus to get_unaligned_le32
+    - net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup
+
+  * CVE-2022-1204
+    - ax25: add refcount in ax25_dev to avoid UAF bugs
+    - ax25: fix reference count leaks of ax25_dev
+    - ax25: fix UAF bugs of net_device caused by rebinding operation
+    - ax25: Fix refcount leaks caused by ax25_cb_del()
+    - ax25: fix UAF bug in ax25_send_control()
+
+  * CVE-2022-1199
+    - ax25: NPD bug when detaching AX25 device
+    - ax25: improve the incomplete fix to avoid UAF and NPD bugs
+    - ax25: Fix NULL pointer dereference in ax25_kill_by_device
+    - ax25: fix NPD bug in ax25_disconnect
+
+  * CVE-2022-0850
+    - ext4: fix kernel infoleak via ext4_extent_header
+
+  * CVE-2022-3202
+    - jfs: fix GPF in diFree
+    - jfs: prevent NULL deref in diFree
+
+  * CVE-2022-2978
+    - SAUCE: fs: fix UAF/GPF bug in nilfs_mdt_destroy
+
+  * CVE-2022-3028
+    - af_key: Do not call xfrm_probe_algs in parallel
+
+  * CVE-2022-2639
+    - openvswitch: fix OOB access in reserve_sfa_size()
+
+  * CVE-2021-4037
+    - xfs: fix up non-directory creation in SGID directories
+
+  * CVE-2022-20368
+    - net/packet: fix slab-out-of-bounds access in packet_recvmsg()
+
+  * CVE-2022-36946
+    - netfilter: nf_queue: do not allow packet truncation below transport header
+      offset
+
+  * CVE-2021-33655
+    - fbcon: Disallow setting font bigger than screen size
+    - fbcon: Prevent that screen size is smaller than font size
+    - fbmem: Check virtual screen sizes in fb_set_var()
+
+  * CVE-2021-33656
+    - vt: drop old FONT ioctls
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 21 Sep 2022 12:36:48 -0300
+
+linux (4.4.0-233.267) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-233.267 -proposed tracker (LP: #1985080)
+
+  * xen blkfront leaks memory when disconnecting devices (LP: #1985527)
+    - Revert "xen/blkfront: force data bouncing when backend is untrusted"
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 11 Aug 2022 19:00:44 -0300
+
+linux (4.4.0-232.266) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-232.266 -proposed tracker (LP: #1985080)
+
+  * CVE-2022-33742
+    - xen/blkfront: force data bouncing when backend is untrusted
+
+  * CVE-2022-33741
+    - net: Rename and export copy_skb_header
+    - xen-netfront: avoid packet loss when ethernet header crosses page boundary
+    - xen/netfront: force data bouncing when backend is untrusted
+
+  * CVE-2022-33740
+    - xen/netfront: fix leaking data in shared pages
+
+  * CVE-2022-26365
+    - xen/blkfront: fix leaking data in shared pages
+
+  * Kernel fails to boot on some AMD systems (LP: #1983030)
+    - x86/tlb: Flush global mappings when KAISER is disabled
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 11 Aug 2022 13:55:53 -0300
+
+linux (4.4.0-231.265) xenial; urgency=medium
+
+  * CVE-2022-2586
+    - SAUCE: netfilter: nf_tables: do not allow SET_ID to refer to another table
+
+  * CVE-2022-2588
+    - SAUCE: net_sched: cls_route: remove from list when handle is 0
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 05 Aug 2022 05:42:26 -0300
+
+linux (4.4.0-230.264) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-230.264 -proposed tracker (LP: #1982029)
+
+  * CVE-2022-34918
+    - netfilter: nf_tables: stricter validation of element data
+
+  * CVE-2022-25258
+    - USB: gadget: validate interface OS descriptor requests
+
+  * CVE-2022-25375
+    - usb: gadget: rndis: check size of RNDIS_MSG_SET command
+    - usb: gadget: rndis: prevent integer overflow in rndis_set_response()
+
+  * CVE-2022-20141
+    - igmp: Add ip_mc_list lock in ip_check_mc_rcu
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 18 Jul 2022 16:27:36 -0300
+
+linux (4.4.0-229.263) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-229.263 -proposed tracker (LP: #1980112)
+
+  * CVE-2022-1679
+    - SAUCE: ath9k: fix use-after-free in ath9k_hif_usb_rx_cb
+
+  * CVE-2022-1419
+    - drm/vgem: Reclassify buffer creation debug message
+    - drm/vgem: Close use-after-free race in vgem_gem_create
+
+  * CVE-2022-1652
+    - floppy: use a statically allocated error counter
+
+  * CVE-2022-1734
+    - nfc: nfcmrvl: main: reorder destructive operations in
+      nfcmrvl_nci_unregister_dev to avoid bugs
+
+  * CVE-2022-1353
+    - af_key: add __GFP_ZERO flag for compose_sadb_supported in function
+      pfkey_register
+
+  * CVE-2021-4202
+    - NFC: reorganize the functions in nci_request
+    - NFC: add NCI_UNREG flag to eliminate the race
+
+  * CVE-2021-4197
+    - cgroup: Use open-time credentials for process migraton perm checks
+
+  * CVE-2022-28356
+    - llc: fix netdevice reference leaks in llc_ui_bind()
+    - netdevice: add the case if dev is NULL
+    - llc: only change llc->dev when bind() succeeds
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 28 Jun 2022 15:33:29 -0300
+
+linux (4.4.0-228.262) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-228.262 -proposed tracker (LP: #1979228)
+
+  * CVE-2021-39714
+    - staging: ion: Prevent incorrect reference counting behavour
+
+  * CVE-2021-3752
+    - Bluetooth: fix use-after-free error in lock_sock_nested()
+
+  * CVE-2021-3609
+    - can: bcm: delay release of struct bcm_op after synchronize_rcu()
+
+  * CVE-2022-21123 // CVE-2022-21125 // CVE-2022-21166
+    - x86/cpu: Add Elkhart Lake to Intel family
+    - cpu/speculation: Add prototype for cpu_show_srbds()
+    - x86/cpu: Add Jasper Lake to Intel family
+    - x86/cpu: Add Cannonlake to Intel family
+    - x86/CPU: Add Icelake model number
+    - x86/CPU: Add more Icelake model numbers
+    - x86/cpu: Add Comet Lake to the Intel CPU models header
+    - x86/cpu: Add Lakefield, Alder Lake and Rocket Lake models to the to Intel
+      CPU family
+    - x86/cpu: Add another Alder Lake CPU to the Intel family
+    - Documentation: Add documentation for Processor MMIO Stale Data
+    - x86/speculation/mmio: Enumerate Processor MMIO Stale Data bug
+    - SAUCE: x86: fixup mds_select_mitigation
+    - x86/speculation: Add a common function for MD_CLEAR mitigation update
+    - x86/speculation/mmio: Add mitigation for Processor MMIO Stale Data
+    - x86/bugs: Group MDS, TAA & Processor MMIO Stale Data mitigations
+    - x86/speculation/mmio: Enable CPU Fill buffer clearing on idle
+    - x86/speculation/mmio: Add sysfs reporting for Processor MMIO Stale Data
+    - x86/speculation/srbds: Update SRBDS mitigation selection
+    - x86/speculation/mmio: Reuse SRBDS mitigation for SBDS
+    - KVM: x86/speculation: Disable Fill buffer clear within guests
+    - x86/speculation/mmio: Print SMT warning
+
+  * CVE-2022-0330
+    - drm/i915: Flush TLBs before releasing backing store
+
+  * CVE-2021-3760
+    - nfc: nci: fix the UAF of rf_conn_info object
+
+  * CVE-2021-39685
+    - USB: gadget: detect too-big endpoint 0 requests
+    - USB: gadget: zero allocate endpoint 0 buffers
+    - USB: gadget: bRequestType is a bitfield, not a enum
+
+  * CVE-2022-24958
+    - usb: gadget: don't release an existing dev->buf
+    - usb: gadget: clear related members when goto fail
+
+  * CVE-2022-28388
+    - can: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error
+      path
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 20 Jun 2022 17:04:22 -0300
+
+linux (4.4.0-227.261) xenial; urgency=medium
+
+  * CVE-2022-1966
+    - netfilter: nf_tables: fix memory leak if expr init fails
+    - netfilter: nf_tables: disallow non-stateful expression in sets earlier
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 03 Jun 2022 09:07:19 -0300
+
+linux (4.4.0-225.258) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-225.258 -proposed tracker (LP: #1975710)
+
+  * CVE-2022-21499
+    - SAUCE: debug: Lock down kgdb
+
+  * Unprivileged users may use PTRACE_SEIZE to set PTRACE_O_SUSPEND_SECCOMP
+    option (LP: #1972740)
+    - ptrace: Check PTRACE_O_SUSPEND_SECCOMP permission on PTRACE_SEIZE
+
+  * ext4: limit length to bitmap_maxbytes (LP: #1972281)
+    - ext4: limit length to bitmap_maxbytes - blocksize in punch_hole
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 25 May 2022 14:40:35 -0300
+
+linux (4.4.0-224.257) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-224.257 -proposed tracker (LP: #1971450)
+
+  * CVE-2021-39713
+    - SAUCE: net: sched: prevent UAF on tc_ctl_tfilter when temporarily dropping
+      rtnl_lock
+
+  * CVE-2022-28390
+    - can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path
+
+  * CVE-2021-4157
+    - pNFS/flexfiles: fix incorrect size check in decode_nfs_fh()
+
+  * Xenial: kernel BUG/Oops/crash in fuse_readdir() due to CVE-2020-36322
+    backport (LP: #1970482)
+    - SAUCE: fuse: fix bad !inode in fuse_direntplus_link()
+
+  * Use kernel-testing repo from launchpad for ADT tests (LP: #1968016)
+    - [Debian] Use kernel-testing repo from launchpad
+
+  * CVE-2022-27223
+    - USB: gadget: validate endpoint index for xilinx udc
+
+  * CVE-2022-26490
+    - nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION
+
+  * CVE-2020-27820
+    - SAUCE: drm/nouveau: disallow manual bind/unbind operations
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 03 May 2022 13:21:01 -0300
+
+linux (4.4.0-223.256) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-223.256 -proposed tracker (LP: #1966469)
+
+  * CVE-2021-0920
+    - net: split out functions related to registering inflight socket files
+    - af_unix: fix garbage collect vs MSG_PEEK
+    - [Config]: Enable new option CONFIG_UNIX_SCM
+
+  * CVE-2021-0935
+    - l2tp: fix races with ipv4-mapped ipv6 addresses
+    - net: ipv6: reset daddr and dport in sk if connect() fails
+    - net: ipv6: keep sk status consistent after datagram connect failure
+
+  * CVE-2020-12888
+    - vfio/type1: Support faulting PFNMAP vmas
+    - vfio-pci: Fault mmaps to enable vma tracking
+    - vfio-pci: Invalidate mmaps and block MMIO access on disabled memory
+    - vfio/pci: Fix SR-IOV VF handling with MMIO blocking
+    - vfio-pci: Use io_remap_pfn_range() for PCI IO memory
+    - vfio/pci: zap_vma_ptes() needs MMU
+
+  * xenial upgrade of lockdown patches dropped ioport denial (LP: #1962315)
+    - Resurect ioport.c portions of "x86: Lock down IO port access when module
+      security is enabled"
+
+  * CVE-2021-4083
+    - fs: add fget_many() and fput_many()
+    - fget: check that the fd still exists after getting a ref to it
+
+  * CVE-2021-28964
+    - btrfs: fix race when cloning extent buffer during rewind of an old root
+    - btrfs: fix race when picking most recent mod log operation for an old root
+
+  * CVE-2021-45486
+    - mm: zero hash tables in allocator
+    - inet: use bigger hash table for IP ID generation
+
+  * CVE-2021-39636
+    - xtables: add xt_match, xt_target and data copy_to_user functions
+    - iptables: use match, target and data copy_to_user helpers
+    - ip6tables: use match, target and data copy_to_user helpers
+    - xtables: extend matches and targets with .usersize
+    - netfilter: x_tables: fix pointer leaks to userspace
+    - netfilter: xtables: zero padding in data_to_user
+
+  * CVE-2021-37159
+    - net: usb: hso: don't print error when allocating urb fails
+    - net: hso: register netdev later to avoid a race condition
+    - usb: hso: fix error handling code of hso_create_net_device
+
+  * linux: Fix failure in ubuntu_boot:log_check test (LP: #1965160)
+    - dmaengine: Replace WARN_TAINT_ONCE() with pr_warn_once()
+
+  * CVE-2020-3702
+    - ath: Use safer key clearing with key cache entries
+    - ath9k: Clear key cache explicitly on disabling hardware
+    - ath: Export ath_hw_keysetmac()
+    - ath: Modify ath_key_delete() to not need full key entry
+    - ath9k: Postpone key cache entry deletion for TXQ frames reference it
+
+  * CVE-2021-43976
+    - mwifiex: Fix skb_over_panic in mwifiex_usb_recv()
+
+  * CVE-2021-42739
+    - media: firewire: firedtv-avc: fix a buffer overflow in avc_ca_pmt()
+
+  * CVE-2020-26141
+    - ath10k: Fix TKIP Michael MIC verification for PCIe
+
+  * CVE-2020-26145
+    - mac80211: add get TID helper
+    - ath10k: add struct for high latency PN replay protection
+    - ath10k: add CCMP PN replay protection for fragmented frames for PCIe
+    - ath10k: drop fragments with multicast DA for PCIe
+
+  * CVE-2021-31916
+    - dm ioctl: fix out of bounds array access when no devices
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 28 Mar 2022 11:14:03 -0300
+
+linux (4.4.0-222.255) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-222.255 -proposed tracker (LP: #1964253)
+
+  * CVE-2021-38208
+    - nfc: fix NULL ptr dereference in llcp_sock_getname() after failed connect
+
+  * CVE-2020-26139
+    - mac80211: do not accept/forward invalid EAPOL frames
+    - mac80211: fix memory corruption in EAPOL handling
+
+  * CVE-2020-36322
+    - fuse: fix bad inode
+    - fuse: fix live lock in fuse_iget()
+
+  * CVE-2021-38198
+    - KVM: nVMX: fix EPT permissions as reported in exit qualification
+    - KVM: X86: MMU: Use the correct inherited permissions to get shadow page
+
+  * linux-4.4 scheduling while atomic on azure (LP: #1960059)
+    - PCI: hv: Do not sleep in compose_msi_msg()
+
+  * CVE-2016-2854
+    - aufs: bugfix, set ACL too in copy-up and chmod
+    - aufs: tiny, extract a part of copy-up dir
+    - aufs: security bugfix, copy-up resets ACL
+
+  * CVE-2016-2853
+    - aufs: security bugfix, test mnt_ns in open(2) for fuse branch
+
+  * CVE-2022-0492
+    - cgroup-v1: Require capabilities to set release_agent
+
+  * CVE-2021-28688
+    - xen-blkback: don't leak persistent grants from xen_blkbk_map()
+
+  * CVE-2020-25673
+    - nfc: Avoid endless loops caused by repeated llcp_sock_connect()
+
+  * CVE-2021-20292
+    - drm/ttm/nouveau: don't call tt destroy callback on alloc failure.
+
+  * CVE-2021-33098
+    - ixgbe: fix large MTU request from VF
+
+  * CVE-2018-5995
+    - percpu: stop printing kernel addresses
+
+  * CVE-2020-12655
+    - xfs: add agf freeblocks verify in xfs_agf_verify
+
+  * CVE-2021-3573
+    - Bluetooth: use correct lock to prevent UAF of hdev object
+    - Bluetooth: defer cleanup of resources in hci_unregister_dev()
+
+  * CVE-2021-20317
+    - rbtree: cache leftmost node internally
+    - lib/timerqueue: Rely on rbtree semantics for next timer
+
+  * CVE-2021-43389
+    - isdn: cpai: check ctr->cnr to avoid array index out of bound
+
+  * CVE-2021-45095
+    - phonet: refcount leak in pep_sock_accep
+
+  * CVE-2021-39648
+    - usb: gadget: configfs: Fix use-after-free issue with udc_name
+
+  * CVE-2021-29650
+    - netfilter: x_tables: Use correct memory barriers.
+
+  * CVE-2021-32399
+    - bluetooth: eliminate the potential race condition when removing the HCI
+      controller
+
+  * CVE-2021-38160
+    - virtio_console: Assure used length from device is limited
+
+  * CVE-2021-33033
+    - cipso,calipso: resolve a number of problems with the DOI refcounts
+
+  * CVE-2021-23134
+    - net/nfc: fix use-after-free llcp_sock_bind/connect
+
+  * CVE-2020-25672
+    - nfc: fix memory leak in llcp_sock_connect()
+
+  * CVE-2020-25671
+    - nfc: fix refcount leak in llcp_sock_connect()
+
+  * CVE-2020-25670
+    - nfc: fix refcount leak in llcp_sock_bind()
+
+  * CVE-2021-40490
+    - ext4: fix race writing to an inline_data file while its xattrs are changing
+
+  * CVE-2021-45469
+    - f2fs: fix to do sanity check on last xattr entry in __f2fs_setxattr()
+
+  * CVE-2021-3506
+    - f2fs: fix to avoid out-of-bounds memory access
+
+  * CVE-2019-19449
+    - f2fs: fix wrong total_sections check and fsmeta check
+    - f2fs: fix to do sanity check on segment/section count
+
+  * CVE-2020-36385
+    - RDMA/ucma: Put a lock around every call to the rdma_cm layer
+    - RDMA/cma: Add missing locking to rdma_accept()
+    - RDMA/ucma: Fix the locking of ctx->file
+    - RDMA/ucma: Rework ucma_migrate_id() to avoid races with destroy
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 09 Mar 2022 11:48:53 +0100
+
+linux (4.4.0-221.254) xenial; urgency=medium
+
+  * CVE-2022-0001
+    - cpu/SMT: create and export cpu_smt_possible()
+    - x86/speculation: Merge one test in spectre_v2_user_select_mitigation()
+    - x86,bugs: Unconditionally allow spectre_v2=retpoline,amd
+    - SAUCE: x86/speculation: Rename RETPOLINE_AMD to RETPOLINE_LFENCE
+    - SAUCE: x86/speculation: Add eIBRS + Retpoline options
+    - SAUCE: Documentation/hw-vuln: Update spectre doc
+
+  * Disable unprivileged BPF by default (LP: #1961338)
+    - bpf: Add kconfig knob for disabling unpriv bpf by default
+    - [Config] set CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 28 Feb 2022 19:10:43 -0300
+
+linux (4.4.0-219.252) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-219.252 -proposed tracker (LP: #1959777)
+
+  * CVE-2021-28972
+    - PCI: rpadlpar: Fix potential drc_name corruption in store functions
+
+  * CVE-2021-0129
+    - Bluetooth: SMP: Fail if remote and local public keys are identical
+
+  * CVE-2021-34693
+    - can: bcm: fix infoleak in struct bcm_msg_head
+
+  * CVE-2021-3564
+    - Bluetooth: fix the erroneous flush_work() order
+
+  * CVE-2020-26147
+    - mac80211: assure all fragments are encrypted
+
+  * CVE-2021-38204
+    - usb: max-3421: Prevent corruption of freed memory
+
+  * CVE-2021-3679
+    - tracing: Fix bug in rb_per_cpu_empty() that might cause deadloop.
+
+  * CVE-2021-3483
+    - firewire: nosy: Fix a use-after-free bug in nosy_ioctl()
+
+  * CVE-2021-33034
+    - Bluetooth: verify AMP hci_chan before amp_destroy
+
+  * CVE-2021-3612
+    - Input: joydev - prevent use of not validated data in JSIOCSBTNMAP ioctl
+
+  * CVE-2021-45485
+    - ipv6: use prandom_u32() for ID generation
+
+  * CVE-2021-42008
+    - net: 6pack: fix slab-out-of-bounds in decode_data
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 03 Feb 2022 14:45:52 -0300
+
+linux (4.4.0-218.251) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-218.251 -proposed tracker (LP: #1952442)
+
+  * CVE-2021-4002
+    - hugetlbfs: flush TLBs correctly after huge_pmd_unshare
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update Ubuntu.md
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 02 Dec 2021 09:53:31 +0100
+
+linux (4.4.0-217.250) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-217.250 -proposed tracker (LP: #1944538)
+
+  * memory leaking when removing a profile (LP: #1939915)
+    - security/apparmor/label.c: Clean code by removing redundant instructions
+    - apparmor: Fix memory leak of profile proxy
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 22 Sep 2021 10:56:53 +0200
+
+linux (4.4.0-216.249) xenial; urgency=medium
+
+  * s390x BPF JIT vulnerabilities (LP: #1943960)
+    - SAUCE: s390/bpf: Fix 64-bit subtraction of the -0x80000000 constant
+    - SAUCE: s390/bpf: Fix optimizing out zero-extensions
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 17 Sep 2021 11:07:39 -0300
+
+linux (4.4.0-214.246) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-214.246 -proposed tracker (LP: #1941638)
+
+  * CVE-2021-3653
+    - KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
+      (CVE-2021-3653)
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 25 Aug 2021 20:42:34 -0300
+
+linux (4.4.0-213.245) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-213.245 -proposed tracker (LP: #1938186)
+
+  * CVE-2021-22555
+    - netfilter: x_tables: fix compat match/target pad out-of-bound write
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 28 Jul 2021 09:31:47 +0200
+
+linux (4.4.0-212.244) xenial; urgency=medium
+
+  * CVE-2021-33909
+    - SAUCE: seq_file: Disallow extremely large seq buffer allocations
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 08 Jul 2021 09:13:34 -0300
+
+linux (4.4.0-211.243) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-211.243 -proposed tracker (LP: #1926472)
+
+  * Taking a memory dump of user mode process on Xenial hosts causes
+    bugcheck/kernel panic and core dump (LP: #1921211)
+    - mm: check VMA flags to avoid invalid PROT_NONE NUMA balancing
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 29 Apr 2021 10:13:40 +0200
+
+linux (4.4.0-210.242) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-210.242 -proposed tracker (LP: #1924644)
+
+  * setting extended attribute may cause memory leak (LP: #1924611)
+    - SAUCE: vfs_setxattr: free converted value if xattr_permission returns error
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 16 Apr 2021 11:33:09 +0200
+
+linux (4.4.0-209.241) xenial; urgency=medium
+
+  * overlayfs calls vfs_setxattr without cap_convert_nscap
+    - vfs: move cap_convert_nscap() call into vfs_setxattr()
+
+  * CVE-2021-29154
+    - SAUCE: bpf, x86: Validate computation of branch displacements for x86-64
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 12 Apr 2021 19:27:28 -0300
+
+linux (4.4.0-208.240) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-208.240 -proposed tracker (LP: #1922069)
+
+  * linux ADT test failure with linux/4.4.0-207.239 -
+    ubuntu_qrt_kernel_security.test-kernel-security.py (LP: #1922200) //
+    CVE-2018-5953 // CVE-2018-5995 // CVE-2018-7754
+    - SAUCE: Revert "printk: hash addresses printed with %p"
+
+  * lxd 2.0.11-0ubuntu1~16.04.4 ADT test failure with linux 4.4.0-207.239
+    (LP: #1921969)
+    - SAUCE: Fix fuse regression in 4.4.0-207.239
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 01 Apr 2021 12:57:17 +0200
+
+linux (4.4.0-207.239) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-207.239 -proposed tracker (LP: #1919558)
+
+  * Xenial update: v4.4.262 upstream stable release (LP: #1920221)
+    - uapi: nfnetlink_cthelper.h: fix userspace compilation error
+    - ath9k: fix transmitting to stations in dynamic SMPS mode
+    - net: Fix gro aggregation for udp encaps with zero csum
+    - can: skb: can_skb_set_owner(): fix ref counting if socket was closed before
+      setting skb ownership
+    - can: flexcan: assert FRZ bit in flexcan_chip_freeze()
+    - can: flexcan: enable RX FIFO after FRZ/HALT valid
+    - netfilter: x_tables: gpf inside xt_find_revision()
+    - cifs: return proper error code in statfs(2)
+    - floppy: fix lock_fdc() signal handling
+    - Revert "mm, slub: consider rest of partial list if acquire_slab() fails"
+    - futex: Change locking rules
+    - futex: Cure exit race
+    - futex: fix dead code in attach_to_pi_owner()
+    - net/mlx4_en: update moderation when config reset
+    - net: lapbether: Remove netif_start_queue / netif_stop_queue
+    - net: davicom: Fix regulator not turned off on failed probe
+    - net: davicom: Fix regulator not turned off on driver removal
+    - media: usbtv: Fix deadlock on suspend
+    - mmc: mxs-mmc: Fix a resource leak in an error handling path in
+      'mxs_mmc_probe()'
+    - mmc: mediatek: fix race condition between msdc_request_timeout and irq
+    - powerpc/perf: Record counter overflow always if SAMPLE_IP is unset
+    - PCI: xgene-msi: Fix race in installing chained irq handler
+    - s390/smp: __smp_rescan_cpus() - move cpumask away from stack
+    - scsi: libiscsi: Fix iscsi_prep_scsi_cmd_pdu() error handling
+    - ALSA: hda/hdmi: Cancel pending works before suspend
+    - ALSA: hda: Avoid spurious unsol event handling during S3/S4
+    - ALSA: usb-audio: Fix "cannot get freq eq" errors on Dell AE515 sound bar
+    - s390/dasd: fix hanging DASD driver unbind
+    - mmc: core: Fix partition switch time for eMMC
+    - scripts/recordmcount.{c,pl}: support -ffunction-sections .text.* section
+      names
+    - Goodix Fingerprint device is not a modem
+    - usb: gadget: f_uac2: always increase endpoint max_packet_size by one audio
+      slot
+    - usb: renesas_usbhs: Clear PIPECFG for re-enabling pipe with other EPNUM
+    - xhci: Improve detection of device initiated wake signal.
+    - USB: serial: io_edgeport: fix memory leak in edge_startup
+    - USB: serial: ch341: add new Product ID
+    - USB: serial: cp210x: add ID for Acuity Brands nLight Air Adapter
+    - USB: serial: cp210x: add some more GE USB IDs
+    - usbip: fix stub_dev to check for stream socket
+    - usbip: fix vhci_hcd to check for stream socket
+    - usbip: fix stub_dev usbip_sockfd_store() races leading to gpf
+    - staging: rtl8192u: fix ->ssid overflow in r8192_wx_set_scan()
+    - staging: rtl8188eu: prevent ->ssid overflow in rtw_wx_set_scan()
+    - staging: rtl8712: unterminated string leads to read overflow
+    - staging: rtl8188eu: fix potential memory corruption in
+      rtw_check_beacon_data()
+    - staging: rtl8712: Fix possible buffer overflow in r8712_sitesurvey_cmd
+    - staging: rtl8192e: Fix possible buffer overflow in _rtl92e_wx_set_scan
+    - staging: comedi: addi_apci_1032: Fix endian problem for COS sample
+    - staging: comedi: addi_apci_1500: Fix endian problem for command sample
+    - staging: comedi: adv_pci1710: Fix endian problem for AI command data
+    - staging: comedi: das6402: Fix endian problem for AI command data
+    - staging: comedi: das800: Fix endian problem for AI command data
+    - staging: comedi: dmm32at: Fix endian problem for AI command data
+    - staging: comedi: me4000: Fix endian problem for AI command data
+    - staging: comedi: pcl711: Fix endian problem for AI command data
+    - staging: comedi: pcl818: Fix endian problem for AI command data
+    - NFSv4.2: fix return value of _nfs4_get_security_label()
+    - block: rsxx: fix error return code of rsxx_pci_probe()
+    - alpha: add $(src)/ rather than $(obj)/ to make source file path
+    - alpha: merge build rules of division routines
+    - alpha: make short build log available for division routines
+    - alpha: Package string routines together
+    - alpha: move exports to actual definitions
+    - alpha: get rid of tail-zeroing in __copy_user()
+    - alpha: switch __copy_user() and __do_clean_user() to normal calling
+      conventions
+    - powerpc/64s: Fix instruction encoding for lis in ppc_function_entry()
+    - media: hdpvr: Fix an error handling path in hdpvr_probe()
+    - KVM: arm64: Fix exclusive limit for IPA size
+    - xen/events: reset affinity of 2-level event when tearing it down
+    - xen/events: don't unmask an event channel when an eoi is pending
+    - xen/events: avoid handling the same event on two cpus at the same time
+    - Linux 4.4.262
+
+  * Xenial update: v4.4.261 upstream stable release (LP: #1920218)
+    - futex: fix irq self-deadlock and satisfy assertion
+    - futex: fix spin_lock() / spin_unlock_irq() imbalance
+    - ALSA: ctxfi: cthw20k2: fix mask on conf to allow 4 bits
+    - rsxx: Return -EFAULT if copy_to_user() fails
+    - dm table: fix iterate_devices based device capability checks
+    - platform/x86: acer-wmi: Add new force_caps module parameter
+    - PCI: Add function 1 DMA alias quirk for Marvell 9215 SATA controller
+    - Linux 4.4.261
+
+  * CVE-2019-19061
+    - iio: imu: adis16400: fix memory leak
+
+  * CVE-2018-5953 // CVE-2018-5995 // CVE-2018-7754
+    - printk: hash addresses printed with %p
+
+  * CVE-2017-5967
+    - time: Remove CONFIG_TIMER_STATS
+    - [Config] Dropped CONFIG_TIMER_STATS
+
+  * CVE-2019-16232
+    - libertas: fix a potential NULL pointer dereference
+
+  * CVE-2015-1350
+    - xfs: Propagate dentry down to inode_change_ok()
+    - fuse: Propagate dentry down to inode_change_ok()
+    - fs: Give dentry to inode_change_ok() instead of inode
+    - fs: Avoid premature clearing of capabilities
+
+  * CVE-2018-13095
+    - xfs: More robust inode extent count validation
+
+  * i40e PF reset due to incorrect MDD event (LP: #1772675)
+    - i40e: change behavior on PF in response to MDD event
+
+  * Xenial update: v4.4.260 upstream stable release (LP: #1918184)
+    - futex: Ensure the correct return value from futex_lock_pi()
+    - net: usb: qmi_wwan: support ZTE P685M modem
+    - iwlwifi: pcie: fix to correct null check
+    - mmc: sdhci-esdhc-imx: fix kernel panic when remove module
+    - scripts: use pkg-config to locate libcrypto
+    - scripts: set proper OpenSSL include dir also for sign-file
+    - hugetlb: fix update_and_free_page contig page struct assumption
+    - JFS: more checks for invalid superblock
+    - xfs: Fix assert failure in xfs_setattr_size()
+    - net: fix up truesize of cloned skb in skb_prepare_for_shift()
+    - mm/hugetlb.c: fix unnecessary address expansion of pmd sharing
+    - staging: fwserial: Fix error handling in fwserial_create
+    - x86/reboot: Add Zotac ZBOX CI327 nano PCI reboot quirk
+    - vt/consolemap: do font sum unsigned
+    - wlcore: Fix command execute failure 19 for wl12xx
+    - pktgen: fix misuse of BUG_ON() in pktgen_thread_worker()
+    - ath10k: fix wmi mgmt tx queue full due to race condition
+    - x86/build: Treat R_386_PLT32 relocation as R_386_PC32
+    - Bluetooth: Fix null pointer dereference in amp_read_loc_assoc_final_data
+    - staging: most: sound: add sanity check for function argument
+    - media: uvcvideo: Allow entities with no pads
+    - Xen/gnttab: handle p2m update errors on a per-slot basis
+    - xen-netback: respect gnttab_map_refs()'s return value
+    - zsmalloc: account the number of compacted pages correctly
+    - swap: fix swapfile read/write offset
+    - media: v4l: ioctl: Fix memory leak in video_usercopy
+    - Linux 4.4.260
+
+  * Xenial update: v4.4.259 upstream stable release (LP: #1918182)
+    - HID: make arrays usage and value to be the same
+    - usb: quirks: add quirk to start video capture on ELMO L-12F document camera
+      reliable
+    - xen-netback: delete NAPI instance when queue fails to initialize
+    - ntfs: check for valid standard information attribute
+    - igb: Remove incorrect "unexpected SYS WRAP" log message
+    - scripts/recordmcount.pl: support big endian for ARCH sh
+    - kdb: Make memory allocations more robust
+    - MIPS: vmlinux.lds.S: add missing PAGE_ALIGNED_DATA() section
+    - Bluetooth: Fix initializing response id after clearing struct
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Spring
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Arndale Octa
+    - Bluetooth: drop HCI device reference before return
+    - Bluetooth: Put HCI device if inquiry procedure interrupts
+    - usb: dwc2: Abort transaction after errors with unknown reason
+    - usb: dwc2: Make "trimming xfer length" a debug message
+    - ARM: s3c: fix fiq for clang IAS
+    - bnxt_en: reverse order of TX disable and carrier off
+    - xen/netback: fix spurious event detection for common event case
+    - b43: N-PHY: Fix the update of coef for the PHY revision >= 3case
+    - fbdev: aty: SPARC64 requires FB_ATY_CT
+    - drm/gma500: Fix error return code in psb_driver_load()
+    - gma500: clean up error handling in init
+    - MIPS: c-r4k: Fix section mismatch for loongson2_sc_init
+    - MIPS: lantiq: Explicitly compare LTQ_EBU_PCC_ISTAT against 0
+    - media: media/pci: Fix memleak in empress_init
+    - media: tm6000: Fix memleak in tm6000_start_stream
+    - ASoC: cs42l56: fix up error handling in probe
+    - media: lmedm04: Fix misuse of comma
+    - media: cx25821: Fix a bug when reallocating some dma memory
+    - media: uvcvideo: Accept invalid bFormatIndex and bFrameIndex values
+    - btrfs: clarify error returns values in __load_free_space_cache
+    - fs/jfs: fix potential integer overflow on shift of a int
+    - jffs2: fix use after free in jffs2_sum_write_data()
+    - clk: meson: clk-pll: fix initializing the old rate (fallback) for a PLL
+    - HID: core: detect and skip invalid inputs to snto32()
+    - dmaengine: fsldma: Fix a resource leak in the remove function
+    - dmaengine: fsldma: Fix a resource leak in an error handling path of the
+      probe function
+    - clocksource/drivers/mxs_timer: Add missing semicolon when DEBUG is defined
+    - regulator: axp20x: Fix reference cout leak
+    - isofs: release buffer head before return
+    - IB/umad: Return EIO in case of when device disassociated
+    - powerpc/47x: Disable 256k page size
+    - mmc: usdhi6rol0: Fix a resource leak in the error handling path of the probe
+    - ARM: 9046/1: decompressor: Do not clear SCTLR.nTLSMD for ARMv7+ cores
+    - amba: Fix resource leak for drivers without .remove
+    - tracepoint: Do not fail unregistering a probe due to memory failure
+    - mfd: wm831x-auxadc: Prevent use after free in wm831x_auxadc_read_irq()
+    - powerpc/pseries/dlpar: handle ibm, configure-connector delay status
+    - perf intel-pt: Fix missing CYC processing in PSB
+    - perf test: Fix unaligned access in sample parsing test
+    - Input: elo - fix an error code in elo_connect()
+    - sparc64: only select COMPAT_BINFMT_ELF if BINFMT_ELF is set
+    - misc: eeprom_93xx46: Fix module alias to enable module autoprobe
+    - misc: eeprom_93xx46: Add module alias to avoid breaking support for non
+      device tree users
+    - VMCI: Use set_page_dirty_lock() when unregistering guest memory
+    - PCI: Align checking of syscall user config accessors
+    - mm/memory.c: fix potential pte_unmap_unlock pte error
+    - mm/hugetlb: fix potential double free in hugetlb_register_node() error path
+    - i2c: brcmstb: Fix brcmstd_send_i2c_cmd condition
+    - scsi: bnx2fc: Fix Kconfig warning & CNIC build errors
+    - block: Move SECTOR_SIZE and SECTOR_SHIFT definitions into <linux/blkdev.h>
+    - blk-settings: align max_sectors on "logical_block_size" boundary
+    - Input: xpad - add support for PowerA Enhanced Wired Controller for Xbox
+      Series X|S
+    - Input: joydev - prevent potential read overflow in ioctl
+    - Input: i8042 - add ASUS Zenbook Flip to noselftest list
+    - USB: serial: option: update interface mapping for ZTE P685M
+    - USB: serial: mos7840: fix error code in mos7840_write()
+    - USB: serial: mos7720: fix error code in mos7720_write()
+    - usb: dwc3: gadget: Fix setting of DEPCFG.bInterval_m1
+    - usb: dwc3: gadget: Fix dep->interval for fullspeed interrupt
+    - KEYS: trusted: Fix migratable=1 failing
+    - btrfs: fix reloc root leak with 0 ref reloc roots on recovery
+    - drivers/misc/vmw_vmci: restrict too big queue size in qp_host_alloc_queue
+    - staging: rtl8188eu: Add Edimax EW-7811UN V2 to device table
+    - x86/reboot: Force all cpus to exit VMX root if VMX is supported
+    - floppy: reintroduce O_NDELAY fix
+    - mm: hugetlb: fix a race between freeing and dissolving the page
+    - usb: renesas_usbhs: Clear pipe running flag in usbhs_pkt_pop()
+    - libnvdimm/dimm: Avoid race between probe and available_slots_show()
+    - module: Ignore _GLOBAL_OFFSET_TABLE_ when warning for undefined symbols
+    - gpio: pcf857x: Fix missing first interrupt
+    - f2fs: fix out-of-repair __setattr_copy()
+    - sparc32: fix a user-triggerable oops in clear_user()
+    - gfs2: Don't skip dlm unlock if glock has an lvb
+    - dm era: Recover committed writeset after crash
+    - dm era: Verify the data block size hasn't changed
+    - dm era: Fix bitset memory leaks
+    - dm era: Use correct value size in equality function of writeset tree
+    - dm era: Reinitialize bitset cache before digesting a new writeset
+    - dm era: only resize metadata in preresume
+    - futex: Fix OWNER_DEAD fixup
+    - dm era: Update in-core bitset after committing the metadata
+    - Linux 4.4.259
+
+  * CVE-2019-16231
+    - fjes: Handle workqueue allocation failure
+
+  * Xenial update: v4.4.258 upstream stable release (LP: #1916661)
+    - tracing: Do not count ftrace events in top level enable output
+    - fgraph: Initialize tracing_graph_pause at task creation
+    - af_key: relax availability checks for skb size calculation
+    - iwlwifi: pcie: add a NULL check in iwl_pcie_txq_unmap
+    - iwlwifi: mvm: guard against device removal in reprobe
+    - SUNRPC: Move simple_get_bytes and simple_get_netobj into private header
+    - SUNRPC: Handle 0 length opaque XDR object data properly
+    - lib/string: Add strscpy_pad() function
+    - include/trace/events/writeback.h: fix -Wstringop-truncation warnings
+    - memcg: fix a crash in wb_workfn when a device disappears
+    - squashfs: add more sanity checks in id lookup
+    - squashfs: add more sanity checks in inode lookup
+    - squashfs: add more sanity checks in xattr id lookup
+    - memblock: do not start bottom-up allocations with kernel_end
+    - netfilter: xt_recent: Fix attempt to update deleted entry
+    - h8300: fix PREEMPTION build, TI_PRE_COUNT undefined
+    - usb: dwc3: ulpi: fix checkpatch warning
+    - usb: dwc3: ulpi: Replace CPU-based busyloop with Protocol-based one
+    - net: watchdog: hold device global xmit lock during tx disable
+    - vsock: fix locking in vsock_shutdown()
+    - x86/build: Disable CET instrumentation in the kernel for 32-bit too
+    - trace: Use -mcount-record for dynamic ftrace
+    - tracing: Fix SKIP_STACK_VALIDATION=1 build due to bad merge with -mrecord-
+      mcount
+    - tracing: Avoid calling cc-option -mrecord-mcount for every Makefile
+    - Xen/x86: don't bail early from clear_foreign_p2m_mapping()
+    - Xen/x86: also check kernel mapping in set_foreign_p2m_mapping()
+    - Xen/gntdev: correct dev_bus_addr handling in gntdev_map_grant_pages()
+    - Xen/gntdev: correct error checking in gntdev_map_grant_pages()
+    - xen/arm: don't ignore return errors from set_phys_to_machine
+    - xen-blkback: don't "handle" error by BUG()
+    - xen-netback: don't "handle" error by BUG()
+    - xen-scsiback: don't "handle" error by BUG()
+    - xen-blkback: fix error handling in xen_blkbk_map()
+    - scsi: qla2xxx: Fix crash during driver load on big endian machines
+    - kvm: check tlbs_dirty directly
+    - Linux 4.4.258
+
+  * Xenial update: v4.4.257 upstream stable release (LP: #1916660)
+    - net_sched: reject silly cell_log in qdisc_get_rtab()
+    - futex,rt_mutex: Provide futex specific rt_mutex API
+    - futex: Remove rt_mutex_deadlock_account_*()
+    - futex: Rework inconsistent rt_mutex/futex_q state
+    - futex: Avoid violating the 10th rule of futex
+    - futex: Replace pointless printk in fixup_owner()
+    - futex: Provide and use pi_state_update_owner()
+    - rtmutex: Remove unused argument from rt_mutex_proxy_unlock()
+    - futex: Use pi_state_update_owner() in put_pi_state()
+    - futex: Simplify fixup_pi_state_owner()
+    - futex: Handle faults correctly for PI futexes
+    - usb: udc: core: Use lock when write to soft_connect
+    - scsi: libfc: Avoid invoking response handler twice if ep is already
+      completed
+    - scsi: ibmvfc: Set default timeout to avoid crash during migration
+    - stable: clamp SUBLEVEL in 4.4 and 4.9
+    - USB: serial: cp210x: add pid/vid for WSDA-200-USB
+    - USB: serial: cp210x: add new VID/PID for supporting Teraoka AD2000
+    - USB: serial: option: Adding support for Cinterion MV31
+    - net: lapb: Copy the skb before sending a packet
+    - [Config] updateconfigs for ELFCORE
+    - ELF/MIPS build fix
+    - elfcore: fix building with clang
+    - USB: gadget: legacy: fix an error code in eth_bind()
+    - USB: usblp: don't call usb_set_interface if there's a single alt
+    - usb: dwc2: Fix endpoint direction check in ep_from_windex
+    - mac80211: fix station rate table updates on assoc
+    - kretprobe: Avoid re-registration of the same kretprobe earlier
+    - cifs: report error instead of invalid when revalidating a dentry fails
+    - mmc: core: Limit retries when analyse of SDIO tuples fails
+    - ARM: footbridge: fix dc21285 PCI configuration accessors
+    - mm: hugetlbfs: fix cannot migrate the fallocated HugeTLB page
+    - mm: hugetlb: fix a race between isolating and freeing page
+    - mm: hugetlb: remove VM_BUG_ON_PAGE from page_huge_active
+    - x86/build: Disable CET instrumentation in the kernel
+    - x86/apic: Add extra serialization for non-serializing MSRs
+    - Input: xpad - sync supported devices with fork on GitHub
+    - ACPI: thermal: Do not call acpi_thermal_check() directly
+    - ALSA: hda/realtek - Fix typo of pincfg for Dell quirk
+    - Linux 4.4.257
+
+  * Xenial update: v4.4.256 upstream stable release (LP: #1916657)
+    - Linux 4.4.256
+
+  * Xenial update: v4.4.255 upstream stable release (LP: #1916656)
+    - ACPI: sysfs: Prefer "compatible" modalias
+    - wext: fix NULL-ptr-dereference with cfg80211's lack of commit()
+    - net: usb: qmi_wwan: added support for Thales Cinterion PLSx3 modem family
+    - KVM: x86/pmu: Fix HW_REF_CPU_CYCLES event pseudo-encoding in
+      intel_arch_events[]
+    - mt7601u: fix kernel crash unplugging the device
+    - mt7601u: fix rx buffer refcounting
+    - y2038: futex: Move compat implementation into futex.c
+    - futex: Move futex exit handling into futex code
+    - futex: Replace PF_EXITPIDONE with a state
+    - exit/exec: Seperate mm_release()
+    - futex: Split futex_mm_release() for exit/exec
+    - futex: Set task::futex_state to DEAD right after handling futex exit
+    - futex: Mark the begin of futex exit explicitly
+    - futex: Sanitize exit state handling
+    - futex: Provide state handling for exec() as well
+    - futex: Add mutex around futex exit
+    - futex: Provide distinct return value when owner is exiting
+    - futex: Prevent exit livelock
+    - ARM: imx: build suspend-imx6.S with arm instruction set
+    - netfilter: nft_dynset: add timeout extension to template
+    - xfrm: Fix oops in xfrm_replay_advance_bmp
+    - RDMA/cxgb4: Fix the reported max_recv_sge value
+    - mac80211: pause TX while changing interface type
+    - can: dev: prevent potential information leak in can_fill_info()
+    - iommu/vt-d: Gracefully handle DMAR units with no supported address widths
+    - iommu/vt-d: Don't dereference iommu_device if IOMMU_API is not built
+    - NFC: fix resource leak when target index is invalid
+    - NFC: fix possible resource leak
+    - Linux 4.4.255
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Wed, 24 Mar 2021 18:17:36 -0600
+
+linux (4.4.0-206.238) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-206.238 -proposed tracker (LP: #1919242)
+
+  * CVE-2021-27365
+    - sysfs: Add sysfs_emit and sysfs_emit_at to format sysfs output
+    - scsi: iscsi: Ensure sysfs attributes are limited to PAGE_SIZE
+    - scsi: iscsi: Verify lengths on passthrough PDUs
+
+  * CVE-2021-27363 // CVE-2021-27364
+    - scsi: iscsi: Restrict sessions and handles to admin capabilities
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 16 Mar 2021 08:21:57 +0100
+
+linux (4.4.0-204.236) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-204.236 -proposed tracker (LP: #1916222)
+
+  * Xenial update: v4.4.254 upstream stable release (LP: #1914648)
+    - ALSA: seq: oss: Fix missing error check in snd_seq_oss_synth_make_info()
+    - ALSA: hda/via: Add minimum mute flag
+    - ACPI: scan: Make acpi_bus_get_device() clear return pointer on error
+    - dm: avoid filesystem lookup in dm_get_dev_t()
+    - ASoC: Intel: haswell: Add missing pm_ops
+    - scsi: ufs: Correct the LUN used in eh_device_reset_handler() callback
+    - drm/nouveau/bios: fix issue shadowing expansion ROMs
+    - drm/nouveau/i2c/gm200: increase width of aux semaphore owner fields
+    - can: dev: can_restart: fix use after free bug
+    - iio: ad5504: Fix setting power-down state
+    - ehci: fix EHCI host controller initialization sequence
+    - usb: bdc: Make bdc pci driver depend on BROKEN
+    - [Config] updateconfigs for USB_BDC_PCI
+    - xhci: make sure TRB is fully written before giving it to the controller
+    - compiler.h: Raise minimum version of GCC to 5.1 for arm64
+    - netfilter: rpfilter: mask ecn bits before fib lookup
+    - sh: dma: fix kconfig dependency for G2_DMA
+    - sh_eth: Fix power down vs. is_opened flag ordering
+    - skbuff: back tiny skbs with kmalloc() in __netdev_alloc_skb() too
+    - ipv6: create multicast route with RTPROT_KERNEL
+    - net_sched: avoid shift-out-of-bounds in tcindex_set_parms()
+    - Revert "mm/slub: fix a memory leak in sysfs_slab_add()"
+    - tracing: Fix race in trace_open and buffer resize call
+    - xen-blkback: set ring->xenblkd to NULL after kthread_stop()
+    - x86/boot/compressed: Disable relocation relaxation
+    - Linux 4.4.254
+
+  * Xenial update: v4.4.253 upstream stable release (LP: #1914647)
+    - ASoC: dapm: remove widget from dirty list on free
+    - mm/hugetlb: fix potential missing huge page size info
+    - ext4: fix bug for rename with RENAME_WHITEOUT
+    - ARC: build: add boot_targets to PHONY
+    - ethernet: ucc_geth: fix definition and size of ucc_geth_tx_global_pram
+    - arch/arc: add copy_user_page() to <asm/page.h> to fix build error on ARC
+    - misdn: dsp: select CONFIG_BITREVERSE
+    - net: ethernet: fs_enet: Add missing MODULE_LICENSE
+    - ACPI: scan: add stub acpi_create_platform_device() for !CONFIG_ACPI
+    - ARM: picoxcell: fix missing interrupt-parent properties
+    - Input: uinput - avoid FF flush when destroying device
+    - dump_common_audit_data(): fix racy accesses to ->d_name
+    - NFS: nfs_igrab_and_active must first reference the superblock
+    - ext4: fix superblock checksum failure when setting password salt
+    - RDMA/usnic: Fix memleak in find_free_vf_and_create_qp_grp
+    - mm, slub: consider rest of partial list if acquire_slab() fails
+    - net: sunrpc: interpret the return value of kstrtou32 correctly
+    - usb: ohci: Make distrust_firmware param default to false
+    - iio: buffer: Fix demux update
+    - nfsd4: readdirplus shouldn't return parent of export
+    - net: cdc_ncm: correct overhead in delayed_ndp_size
+    - netxen_nic: fix MSI/MSI-x interrupts
+    - rndis_host: set proper input size for OID_GEN_PHYSICAL_MEDIUM request
+    - net: dcb: Validate netlink message in DCB handler
+    - net: dcb: Accept RTM_GETDCB messages carrying set-like DCB commands
+    - net: sit: unregister_netdevice on newlink's error path
+    - rxrpc: Fix handling of an unsupported token type in rxrpc_read()
+    - net: avoid 32 x truesize under-estimation for tiny skbs
+    - spi: cadence: cache reference clock rate during probe
+    - Linux 4.4.253
+
+  * Xenial update: v4.4.252 upstream stable release (LP: #1913479)
+    - Revert "UBUNTU: SAUCE: target: fix XCOPY NAA identifier lookup"
+    - target: add XCOPY target/segment desc sense codes
+    - target: bounds check XCOPY segment descriptor list
+    - target: use XCOPY segment descriptor CSCD IDs
+    - xcopy: loop over devices using idr helper
+    - scsi: target: Fix XCOPY NAA identifier lookup
+    - powerpc: Fix incorrect stw{, ux, u, x} instructions in __set_pte_at
+    - net: ip: always refragment ip defragmented packets
+    - net: fix pmtu check in nopmtudisc mode
+    - vmlinux.lds.h: Add PGO and AutoFDO input sections
+    - ubifs: wbuf: Don't leak kernel memory to flash
+    - spi: pxa2xx: Fix use-after-free on unbind
+    - cpufreq: powernow-k8: pass policy rather than use cpufreq_cpu_get()
+    - wil6210: select CONFIG_CRC32
+    - block: rsxx: select CONFIG_CRC32
+    - iommu/intel: Fix memleak in intel_irq_remapping_alloc
+    - block: fix use-after-free in disk_part_iter_next
+    - net: drop bogus skb with CHECKSUM_PARTIAL and offset beyond end of trimmed
+      packet
+    - Linux 4.4.252
+
+  * Xenial update: v4.4.251 upstream stable release (LP: #1913478)
+    - kbuild: don't hardcode depmod path
+    - workqueue: Kick a worker based on the actual activation of delayed works
+    - lib/genalloc: fix the overflow when size is too big
+    - depmod: handle the case of /sbin/depmod without /sbin in PATH
+    - atm: idt77252: call pci_disable_device() on error path
+    - ipv4: Ignore ECN bits for fib lookups in fib_compute_spec_dst()
+    - net: hns: fix return value check in __lb_other_process()
+    - net: hdlc_ppp: Fix issues when mod_timer is called while timer is running
+    - CDC-NCM: remove "connected" log message
+    - vhost_net: fix ubuf refcount incorrectly when sendmsg fails
+    - net: sched: prevent invalid Scell_log shift count
+    - virtio_net: Fix recursive call to cpus_read_lock()
+    - ethernet: ucc_geth: fix use-after-free in ucc_geth_remove()
+    - video: hyperv_fb: Fix the mmap() regression for v5.4.y and older
+    - usb: gadget: enable super speed plus
+    - USB: cdc-acm: blacklist another IR Droid device
+    - usb: chipidea: ci_hdrc_imx: add missing put_device() call in
+      usbmisc_get_init_data()
+    - USB: xhci: fix U1/U2 handling for hardware with XHCI_INTEL_HOST quirk set
+    - usb: uas: Add PNY USB Portable SSD to unusual_uas
+    - USB: serial: iuu_phoenix: fix DMA from stack
+    - USB: serial: option: add LongSung M5710 module support
+    - USB: yurex: fix control-URB timeout handling
+    - USB: usblp: fix DMA to stack
+    - ALSA: usb-audio: Fix UBSAN warnings for MIDI jacks
+    - usb: gadget: select CONFIG_CRC32
+    - usb: gadget: f_uac2: reset wMaxPacketSize
+    - usb: gadget: function: printer: Fix a memory leak for interface descriptor
+    - USB: gadget: legacy: fix return error code in acm_ms_bind()
+    - usb: gadget: Fix spinlock lockup on usb_function_deactivate
+    - usb: gadget: configfs: Preserve function ordering after bind failure
+    - USB: serial: keyspan_pda: remove unused variable
+    - x86/mm: Fix leak of pmd ptlock
+    - ALSA: hda/conexant: add a new hda codec CX11970
+    - Revert "device property: Keep secondary firmware node secondary by type"
+    - netfilter: ipset: fix shift-out-of-bounds in htable_bits()
+    - netfilter: xt_RATEEST: reject non-null terminated string from userspace
+    - x86/mtrr: Correct the range check before performing MTRR type lookups
+    - Linux 4.4.251
+
+  * Xenial update: v4.4.250 upstream stable release (LP: #1912679)
+    - ALSA: hda/ca0132 - Fix work handling in delayed HP detection
+    - ALSA: usb-audio: simplify set_sync_ep_implicit_fb_quirk
+    - ALSA: usb-audio: fix sync-ep altsetting sanity check
+    - ALSA: hda/realtek - Support Dell headset mode for ALC3271
+    - ALSA: hda - Fix a wrong FIXUP for alc289 on Dell machines
+    - ALSA: hda/realtek - Dell headphone has noise on unmute for ALC236
+    - s390/dasd: fix hanging device offline processing
+    - USB: serial: digi_acceleport: fix write-wakeup deadlocks
+    - uapi: move constants from <linux/kernel.h> to <linux/const.h>
+    - of: fix linker-section match-table corruption
+    - reiserfs: add check for an invalid ih_entry_count
+    - misc: vmw_vmci: fix kernel info-leak by initializing dbells in
+      vmci_ctx_get_chkpt_doorbells()
+    - media: gp8psk: initialize stats at power control logic
+    - ALSA: seq: Use bool for snd_seq_queue internal flags
+    - module: set MODULE_STATE_GOING state when a module fails to load
+    - quota: Don't overflow quota file offsets
+    - powerpc: sysdev: add missing iounmap() on error in mpic_msgr_probe()
+    - module: delay kobject uevent until after module init call
+    - iio:magnetometer:mag3110: Fix alignment and data leak issues.
+    - mwifiex: Fix possible buffer overflows in mwifiex_cmd_802_11_ad_hoc_start
+    - Linux 4.4.250
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 19 Feb 2021 11:48:11 +0100
+
+linux (4.4.0-203.235) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-203.235 -proposed tracker (LP: #1914140)
+
+  * Ubuntu 16.04 kernel 4.4.0-202 basic commands hanging (LP: #1913853)
+    - SAUCE: Revert "mm: check that mm is still valid in madvise()"
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Mon, 01 Feb 2021 17:38:49 -0700
+
+linux (4.4.0-202.234) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-202.234 -proposed tracker (LP: #1913086)
+
+  * DMI entry syntax fix for Pegatron / ByteSpeed C15B (LP: #1910639)
+    - Input: i8042 - unbreak Pegatron C15B
+
+  * CVE-2020-29372
+    - mm: check that mm is still valid in madvise()
+
+  * errinjct open fails on IBM POWER LPAR (LP: #1908710)
+    - powerpc/rtas: Fix typo of ibm, open-errinjct in RTAS filter
+
+  * 4.4 kernel panics in kvm wake_up() handler (LP: #1908428)
+    - kvm: vmx: rename vmx_pre/post_block to pi_pre/post_block
+    - KVM: VMX: extract __pi_post_block
+    - KVM: VMX: avoid double list add with VT-d posted interrupts
+
+  * restore reverted commit "crypto: arm64/sha - avoid non-standard inline asm
+    tricks" (LP: #1907489)
+    - crypto: arm64/sha - avoid non-standard inline asm tricks
+
+  * CVE-2020-29374
+    - gup: document and work around "COW can break either way" issue
+
+  * Xenial update: v4.4.249 upstream stable release (LP: #1910139)
+    - spi: bcm2835aux: Fix use-after-free on unbind
+    - spi: bcm2835aux: Restore err assignment in bcm2835aux_spi_probe
+    - ARC: stack unwinding: don't assume non-current task is sleeping
+    - platform/x86: acer-wmi: add automatic keyboard background light toggle key
+      as KEY_LIGHTS_TOGGLE
+    - Input: cm109 - do not stomp on control URB
+    - Input: i8042 - add Acer laptops to the i8042 reset list
+    - [Config] updateconfigs for SPI_DYNAMIC
+    - spi: Prevent adding devices below an unregistering controller
+    - net/mlx4_en: Avoid scheduling restart task if it is already running
+    - tcp: fix cwnd-limited bug for TSO deferral where we send nothing
+    - net: stmmac: delete the eee_ctrl_timer after napi disabled
+    - net: bridge: vlan: fix error return code in __vlan_add()
+    - USB: dummy-hcd: Fix uninitialized array use in init()
+    - USB: add RESET_RESUME quirk for Snapscan 1212
+    - ALSA: usb-audio: Fix potential out-of-bounds shift
+    - ALSA: usb-audio: Fix control 'access overflow' errors from chmap
+    - xhci: Give USB2 ports time to enter U3 in bus suspend
+    - USB: sisusbvga: Make console support depend on BROKEN
+    - [Config] updateconfigs for USB_SISUSBVGA_CON
+    - ALSA: pcm: oss: Fix potential out-of-bounds shift
+    - serial: 8250_omap: Avoid FIFO corruption caused by MDR1 access
+    - USB: serial: cp210x: enable usb generic throttle/unthrottle
+    - scsi: bnx2i: Requires MMU
+    - can: softing: softing_netdev_open(): fix error handling
+    - RDMA/cm: Fix an attempt to use non-valid pointer when cleaning timewait
+    - dm table: Remove BUG_ON(in_interrupt())
+    - soc/tegra: fuse: Fix index bug in get_process_id
+    - USB: serial: option: add interface-number sanity check to flag handling
+    - USB: gadget: f_rndis: fix bitrate for SuperSpeed and above
+    - usb: chipidea: ci_hdrc_imx: Pass DISABLE_DEVICE_STREAMING flag to imx6ul
+    - media: msi2500: assign SPI bus number dynamically
+    - Bluetooth: Fix slab-out-of-bounds read in hci_le_direct_adv_report_evt()
+    - drm/gma500: fix double free of gma_connector
+    - ARM: p2v: fix handling of LPAE translation in BE mode
+    - crypto: talitos - Fix return type of current_desc_hdr()
+    - spi: img-spfi: fix reference leak in img_spfi_resume
+    - ASoC: pcm: DRAIN support reactivation
+    - Bluetooth: Fix null pointer dereference in hci_event_packet()
+    - spi: spi-ti-qspi: fix reference leak in ti_qspi_setup
+    - spi: tegra20-slink: fix reference leak in slink ops of tegra20
+    - spi: tegra20-sflash: fix reference leak in tegra_sflash_resume
+    - spi: tegra114: fix reference leak in tegra spi ops
+    - RDMa/mthca: Work around -Wenum-conversion warning
+    - MIPS: BCM47XX: fix kconfig dependency bug for BCM47XX_BCMA
+    - media: solo6x10: fix missing snd_card_free in error handling case
+    - drm/omap: dmm_tiler: fix return error code in omap_dmm_probe()
+    - Input: ads7846 - fix integer overflow on Rt calculation
+    - Input: ads7846 - fix unaligned access on 7845
+    - powerpc/feature: Fix CPU_FTRS_ALWAYS by removing CPU_FTRS_GENERIC_32
+    - soc: ti: knav_qmss: fix reference leak in knav_queue_probe
+    - soc: ti: Fix reference imbalance in knav_dma_probe
+    - drivers: soc: ti: knav_qmss_queue: Fix error return code in knav_queue_probe
+    - memstick: fix a double-free bug in memstick_check
+    - ARM: dts: at91: sama5d4_xplained: add pincontrol for USB Host
+    - ARM: dts: at91: sama5d3_xplained: add pincontrol for USB Host
+    - orinoco: Move context allocation after processing the skb
+    - cw1200: fix missing destroy_workqueue() on error in cw1200_init_common
+    - mips: cdmm: fix use-after-free in mips_cdmm_bus_discover
+    - NFSv4.2: condition READDIR's mask for security label based on LSM state
+    - lockd: don't use interval-based rebinding over TCP
+    - NFS: switch nfsiod to be an UNBOUND workqueue.
+    - media: saa7146: fix array overflow in vidioc_s_audio()
+    - pinctrl: falcon: add missing put_device() call in pinctrl_falcon_probe()
+    - memstick: r592: Fix error return in r592_probe()
+    - ASoC: jz4740-i2s: add missed checks for clk_get()
+    - dm ioctl: fix error return code in target_message
+    - clocksource/drivers/arm_arch_timer: Correct fault programming of
+      CNTKCTL_EL1.EVNTI
+    - cpufreq: highbank: Add missing MODULE_DEVICE_TABLE
+    - cpufreq: loongson1: Add missing MODULE_ALIAS
+    - cpufreq: scpi: Add missing MODULE_ALIAS
+    - scsi: pm80xx: Fix error return in pm8001_pci_probe()
+    - seq_buf: Avoid type mismatch for seq_buf_init
+    - scsi: fnic: Fix error return code in fnic_probe()
+    - powerpc/pseries/hibernation: drop pseries_suspend_begin() from suspend ops
+    - usb: ehci-omap: Fix PM disable depth umbalance in ehci_hcd_omap_probe
+    - usb: oxu210hp-hcd: Fix memory leak in oxu_create
+    - speakup: fix uninitialized flush_lock
+    - nfs_common: need lock during iterate through the list
+    - x86/kprobes: Restore BTF if the single-stepping is cancelled
+    - extcon: max77693: Fix modalias string
+    - ASoC: wm_adsp: remove "ctl" from list on error in wm_adsp_create_control()
+    - um: chan_xterm: Fix fd leak
+    - nfc: s3fwrn5: Release the nfc firmware
+    - powerpc/ps3: use dma_mapping_error()
+    - checkpatch: fix unescaped left brace
+    - net: bcmgenet: Fix a resource leak in an error handling path in the probe
+      functin
+    - net: allwinner: Fix some resources leak in the error handling path of the
+      probe and in the remove function
+    - net: korina: fix return value
+    - clk: ti: Fix memleak in ti_fapll_synth_setup
+    - perf record: Fix memory leak when using '--user-regs=?' to list registers
+    - qlcnic: Fix error code in probe
+    - clk: s2mps11: Fix a resource leak in error handling paths in the probe
+      function
+    - cfg80211: initialize rekey_data
+    - Input: cros_ec_keyb - send 'scancodes' in addition to key events
+    - Input: goodix - add upside-down quirk for Teclast X98 Pro tablet
+    - media: gspca: Fix memory leak in probe
+    - media: sunxi-cir: ensure IR is handled when it is continuous
+    - media: netup_unidvb: Don't leak SPI master in probe error path
+    - Input: cyapa_gen6 - fix out-of-bounds stack access
+    - Revert "ACPI / resources: Use AE_CTRL_TERMINATE to terminate resources
+      walks"
+    - ACPI: PNP: compare the string length in the matching_id()
+    - ALSA: pcm: oss: Fix a few more UBSAN fixes
+    - s390/dasd: fix list corruption of pavgroup group list
+    - s390/dasd: fix list corruption of lcu list
+    - staging: comedi: mf6x4: Fix AI end-of-conversion detection
+    - powerpc/perf: Exclude kernel samples while counting events in user space.
+    - USB: serial: mos7720: fix parallel-port state restore
+    - USB: serial: keyspan_pda: fix dropped unthrottle interrupts
+    - USB: serial: keyspan_pda: fix write deadlock
+    - USB: serial: keyspan_pda: fix stalled writes
+    - USB: serial: keyspan_pda: fix write-wakeup use-after-free
+    - USB: serial: keyspan_pda: fix tx-unthrottle use-after-free
+    - USB: serial: keyspan_pda: fix write unthrottling
+    - btrfs: quota: Set rescan progress to (u64)-1 if we hit last leaf
+    - btrfs: scrub: Don't use inode page cache in scrub_handle_errored_block()
+    - Btrfs: fix selftests failure due to uninitialized i_mode in test inodes
+    - btrfs: fix return value mixup in btrfs_get_extent
+    - ext4: fix a memory leak of ext4_free_data
+    - ceph: fix race in concurrent __ceph_remove_cap invocations
+    - jffs2: Fix GC exit abnormally
+    - jfs: Fix array index bounds check in dbAdjTree
+    - spi: rb4xx: Don't leak SPI master in probe error path
+    - mtd: parser: cmdline: Fix parsing of part-names with colons
+    - iio: adc: rockchip_saradc: fix missing clk_disable_unprepare() on error in
+      rockchip_saradc_resume
+    - iio:pressure:mpl3115: Force alignment of buffer
+    - xen/xenbus: Allow watches discard events before queueing
+    - xen/xenbus: Add 'will_handle' callback support in xenbus_watch_path()
+    - xen/xenbus/xen_bus_type: Support will_handle watch callback
+    - xen/xenbus: Count pending messages for each watch
+    - xenbus/xenbus_backend: Disallow pending watch messages
+    - PCI: Fix pci_slot_release() NULL pointer dereference
+    - Linux 4.4.249
+
+  * MSFT Touchpad not working on Lenovo Legion-5 15ARH05 (LP: #1887190) //
+    Xenial update: v4.4.249 upstream stable release (LP: #1910139)
+    - pinctrl: amd: remove debounce filter setting in IRQ type setting
+
+  * Xenial update: v4.4.248 upstream stable release (LP: #1910137)
+    - net/af_iucv: set correct sk_protocol for child sockets
+    - rose: Fix Null pointer dereference in rose_send_frame()
+    - usbnet: ipheth: fix connectivity with iOS 14
+    - bonding: wait for sysfs kobject destruction before freeing struct slave
+    - netfilter: bridge: reset skb->pkt_type after NF_INET_POST_ROUTING traversal
+    - net/x25: prevent a couple of overflows
+    - cxgb3: fix error return code in t3_sge_alloc_qset()
+    - net: pasemi: fix error return code in pasemi_mac_open()
+    - dt-bindings: net: correct interrupt flags in examples
+    - Input: xpad - support Ardwiino Controllers
+    - powerpc: Stop exporting __clear_user which is now inlined.
+    - btrfs: sysfs: init devices outside of the chunk_mutex
+    - vlan: consolidate VLAN parsing code and limit max parsing depth
+    - usb: gadget: f_fs: Use local copy of descriptors for userspace copy
+    - USB: serial: kl5kusb105: fix memleak on open
+    - USB: serial: ch341: add new Product ID for CH341A
+    - USB: serial: ch341: sort device-id entries
+    - USB: serial: option: add Fibocom NL668 variants
+    - USB: serial: option: add support for Thales Cinterion EXS82
+    - tty: Fix ->pgrp locking in tiocspgrp()
+    - ALSA: hda/realtek - Add new codec supported for ALC897
+    - ALSA: hda/generic: Add option to enforce preferred_dacs pairs
+    - tty: Fix ->session locking
+    - cifs: fix potential use-after-free in cifs_echo_request()
+    - i2c: imx: Fix reset of I2SR_IAL flag
+    - i2c: imx: Check for I2SR_IAL after every byte
+    - arm64: assembler: make adr_l work in modules under KASLR
+    - iommu/amd: Set DTE[IntTabLen] to represent 512 IRTEs
+    - spi: Introduce device-managed SPI controller allocation
+    - spi: bcm2835: Fix use-after-free on unbind
+    - spi: bcm2835: Release the DMA channel if probe fails after dma_init
+    - tracing: Fix userstacktrace option for instances
+    - btrfs: cleanup cow block on error
+    - mm/userfaultfd: do not access vma->vm_mm after calling handle_userfault()
+    - gfs2: check for empty rgrp tree in gfs2_ri_update
+    - Input: i8042 - fix error return code in i8042_setup_aux()
+    - x86/uprobes: Do not use prefixes.nbytes when looping over prefixes.bytes
+    - Linux 4.4.248
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Wed, 27 Jan 2021 16:23:17 -0700
+
+linux (4.4.0-201.233) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-201.233 -proposed tracker (LP: #1911265)
+
+  * Touchpad not detected on ByteSpeed C15B laptop (LP: #1906128)
+    - Input: i8042 - add ByteSpeed touchpad to noloop table
+
+  * stack trace in kernel (LP: #1903596)
+    - net: napi: remove useless stack trace
+
+  * CVE-2020-27777
+    - powerpc/rtas: Restrict RTAS requests from userspace
+    - [Config]: Set CONFIG_PPC_RTAS_FILTER
+
+  * Xenial update: v4.4.247 upstream stable release (LP: #1906703)
+    - btrfs: tree-checker: Enhance chunk checker to validate chunk profile
+    - btrfs: inode: Verify inode mode to avoid NULL pointer dereference
+    - HID: cypress: Support Varmilo Keyboards' media hotkeys
+    - Input: i8042 - allow insmod to succeed on devices without an i8042
+      controller
+    - HID: hid-sensor-hub: Fix issue with devices with no report ID
+    - x86/xen: don't unbind uninitialized lock_kicker_irq
+    - proc: don't allow async path resolution of /proc/self components
+    - dmaengine: pl330: _prep_dma_memcpy: Fix wrong burst size
+    - scsi: libiscsi: Fix NOP race condition
+    - scsi: target: iscsi: Fix cmd abort fabric stop race
+    - scsi: ufs: Fix race between shutdown and runtime resume flow
+    - bnxt_en: fix error return code in bnxt_init_board()
+    - video: hyperv_fb: Fix the cache type when mapping the VRAM
+    - bnxt_en: Release PCI regions when DMA mask setup fails during probe.
+    - IB/mthca: fix return value of error branch in mthca_init_cq()
+    - nfc: s3fwrn5: use signed integer for parsing GPIO numbers
+    - efivarfs: revert "fix memory leak in efivarfs_create()"
+    - perf probe: Fix to die_entrypc() returns error correctly
+    - USB: core: Change %pK for __user pointers to %px
+    - x86/speculation: Fix prctl() when spectre_v2_user={seccomp,prctl},ibpb
+    - USB: core: add endpoint-blacklist quirk
+    - USB: core: Fix regression in Hercules audio card
+    - btrfs: fix lockdep splat when reading qgroup config on mount
+    - Linux 4.4.247
+
+  * Xenial update: v4.4.246 upstream stable release (LP: #1906700)
+    - ah6: fix error return code in ah6_input()
+    - atm: nicstar: Unmap DMA on send error
+    - net: b44: fix error return code in b44_init_one()
+    - net: bridge: add missing counters to ndo_get_stats64 callback
+    - netlabel: fix our progress tracking in netlbl_unlabel_staticlist()
+    - netlabel: fix an uninitialized warning in netlbl_unlabel_staticlist()
+    - net/mlx4_core: Fix init_hca fields offset
+    - net: x25: Increase refcnt of "struct x25_neigh" in x25_rx_call_request
+    - qlcnic: fix error return code in qlcnic_83xx_restart_hw()
+    - sctp: change to hold/put transport for proto_unreach_timer
+    - net: usb: qmi_wwan: Set DTR quirk for MR400
+    - net: Have netpoll bring-up DSA management interface
+    - pinctrl: rockchip: enable gpio pclk for rockchip_gpio_to_irq
+    - arm64: psci: Avoid printing in cpu_psci_cpu_die()
+    - MIPS: Fix BUILD_ROLLBACK_PROLOGUE for microMIPS
+    - Input: adxl34x - clean up a data type in adxl34x_probe()
+    - arm: dts: imx6qdl-udoo: fix rgmii phy-mode for ksz9031 phy
+    - ARM: dts: imx50-evk: Fix the chip select 1 IOMUX
+    - perf lock: Don't free "lock_seq_stat" if read_count isn't zero
+    - can: dev: can_restart(): post buffer from the right context
+    - can: peak_usb: fix potential integer overflow on shift of a int
+    - can: m_can: m_can_handle_state_change(): fix state change
+    - MIPS: Alchemy: Fix memleak in alchemy_clk_setup_cpu
+    - regulator: ti-abb: Fix array out of bound read access on the first
+      transition
+    - libfs: fix error cast of negative value in simple_attr_write()
+    - ALSA: ctl: fix error path at adding user-defined element set
+    - ALSA: mixart: Fix mutex deadlock
+    - tty: serial: imx: keep console clocks always on
+    - efivarfs: fix memory leak in efivarfs_create()
+    - ext4: fix bogus warning in ext4_update_dx_flag()
+    - xtensa: disable preemption around cache alias management calls
+    - mac80211: minstrel: remove deferred sampling code
+    - mac80211: minstrel: fix tx status processing corner case
+    - mac80211: allow driver to prevent two stations w/ same address
+    - mac80211: free sta in sta_info_insert_finish() on errors
+    - s390/cpum_sf.c: fix file permission for cpum_sfb_size
+    - x86/microcode/intel: Check patch signature before saving microcode for early
+      loading
+    - Linux 4.4.246
+
+  * Xenial update: v4.4.245 upstream stable release (LP: #1906698)
+    - i2c: imx: Fix external abort on interrupt in exit paths
+    - xfs: catch inode allocation state mismatch corruption
+    - xfs: validate cached inodes are free when allocated
+    - powerpc/8xx: Always fault when _PAGE_ACCESSED is not set
+    - Input: sunkbd - avoid use-after-free in teardown paths
+    - mac80211: always wind down STA state
+    - KVM: x86: clflushopt should be treated as a no-op by emulation
+    - Linux 4.4.245
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Wed, 13 Jan 2021 17:48:34 -0700
+
+linux (4.4.0-200.232) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-200.232 -proposed tracker (LP: #1911151)
+
+  * CVE-2020-28374
+    - target: simplify XCOPY wwn->se_dev lookup helper
+    - SAUCE: target: fix XCOPY NAA identifier lookup
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 13 Jan 2021 10:30:27 +0100
+
+linux (4.4.0-198.230) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-198.230 -proposed tracker (LP: #1906052)
+
+  * Xenial update: v4.4.244 upstream stable release (LP: #1904914)
+    - ring-buffer: Fix recursion protection transitions between interrupt context
+    - gfs2: Wake up when sd_glock_disposal becomes zero
+    - mm: mempolicy: fix potential pte_unmap_unlock pte error
+    - time: Prevent undefined behaviour in timespec64_to_ns()
+    - btrfs: reschedule when cloning lots of extents
+    - net: xfrm: fix a race condition during allocing spi
+    - perf tools: Add missing swap for ino_generation
+    - ALSA: hda: prevent undefined shift in snd_hdac_ext_bus_get_link()
+    - can: dev: can_get_echo_skb(): prevent call to kfree_skb() in hard IRQ
+      context
+    - can: dev: __can_get_echo_skb(): fix real payload length return value for RTR
+      frames
+    - can: can_create_echo_skb(): fix echo skb generation: always use skb_clone()
+    - can: peak_usb: add range checking in decode operations
+    - can: peak_usb: peak_usb_get_ts_time(): fix timestamp wrapping
+    - Btrfs: fix missing error return if writeback for extent buffer never started
+    - i40e: Wrong truncation from u16 to u8
+    - i40e: Fix of memory leak and integer truncation in i40e_virtchnl.c
+    - ath9k_htc: Use appropriate rs_datalen type
+    - usb: gadget: goku_udc: fix potential crashes in probe
+    - gfs2: Free rd_bits later in gfs2_clear_rgrpd to fix use-after-free
+    - gfs2: check for live vs. read-only file system in gfs2_fitrim
+    - drm/amdgpu: perform srbm soft reset always on SDMA resume
+    - mac80211: fix use of skb payload instead of header
+    - cfg80211: regulatory: Fix inconsistent format argument
+    - iommu/amd: Increase interrupt remapping table limit to 512 entries
+    - xfs: fix a missing unlock on error in xfs_fs_map_blocks
+    - of/address: Fix of_node memory leak in of_dma_is_coherent
+    - cosa: Add missing kfree in error path of cosa_write
+    - perf: Fix get_recursion_context()
+    - ext4: correctly report "not supported" for {usr,grp}jquota when
+      !CONFIG_QUOTA
+    - ext4: unlock xattr_sem properly in ext4_inline_data_truncate()
+    - usb: cdc-acm: Add DISABLE_ECHO for Renesas USB Download mode
+    - mei: protect mei_cl_mtu from null dereference
+    - ocfs2: initialize ip_next_orphan
+    - don't dump the threads that had been already exiting when zapped.
+    - drm/gma500: Fix out-of-bounds access to struct drm_device.vblank[]
+    - pinctrl: amd: use higher precision for 512 RtcClk
+    - pinctrl: amd: fix incorrect way to disable debounce filter
+    - swiotlb: fix "x86: Don't panic if can not alloc buffer for swiotlb"
+    - IPv6: Set SIT tunnel hard_header_len to zero
+    - net/af_iucv: fix null pointer dereference on shutdown
+    - net/x25: Fix null-ptr-deref in x25_connect
+    - net: Update window_clamp if SOCK_RCVBUF is set
+    - random32: make prandom_u32() output unpredictable
+    - x86/speculation: Allow IBPB to be conditionally enabled on CPUs with always-
+      on STIBP
+    - xen/events: avoid removing an event channel while handling it
+    - xen/events: add a proper barrier to 2-level uevent unmasking
+    - xen/events: fix race in evtchn_fifo_unmask()
+    - xen/events: add a new "late EOI" evtchn framework
+    - xen/blkback: use lateeoi irq binding
+    - xen/netback: use lateeoi irq binding
+    - xen/scsiback: use lateeoi irq binding
+    - xen/pciback: use lateeoi irq binding
+    - xen/events: switch user event channels to lateeoi model
+    - xen/events: use a common cpu hotplug hook for event channels
+    - xen/events: defer eoi in case of excessive number of events
+    - xen/events: block rogue events for some time
+    - Revert "kernel/reboot.c: convert simple_strtoul to kstrtoint"
+    - reboot: fix overflow parsing reboot cpu number
+    - ext4: fix leaking sysfs kobject after failed mount
+    - Convert trailing spaces and periods in path components
+    - Linux 4.4.244
+
+  * Xenial update: v4.4.243 upstream stable release (LP: #1904904)
+    - Linux 4.4.243
+
+  * Xenial update: v4.4.242 upstream stable release (LP: #1903750)
+    - SUNRPC: ECONNREFUSED should cause a rebind.
+    - scripts/setlocalversion: make git describe output more reliable
+    - ravb: Fix bit fields checking in ravb_hwtstamp_get()
+    - tipc: fix memory leak caused by tipc_buf_append()
+    - mtd: lpddr: Fix bad logic in print_drs_error
+    - ata: sata_rcar: Fix DMA boundary mask
+    - fscrypt: return -EXDEV for incompatible rename or link into encrypted dir
+    - f2fs crypto: avoid unneeded memory allocation in ->readdir
+    - powerpc/powernv/smp: Fix spurious DBG() warning
+    - sparc64: remove mm_cpumask clearing to fix kthread_use_mm race
+    - f2fs: fix to check segment boundary during SIT page readahead
+    - um: change sigio_spinlock to a mutex
+    - xfs: fix realtime bitmap/summary file truncation when growing rt volume
+    - video: fbdev: pvr2fb: initialize variables
+    - ath10k: fix VHT NSS calculation when STBC is enabled
+    - mmc: via-sdmmc: Fix data race bug
+    - printk: reduce LOG_BUF_SHIFT range for H8300
+    - kgdb: Make "kgdbcon" work properly with "kgdb_earlycon"
+    - USB: adutux: fix debugging
+    - drivers/net/wan/hdlc_fr: Correctly handle special skb->protocol values
+    - power: supply: test_power: add missing newlines when printing parameters by
+      sysfs
+    - md/bitmap: md_bitmap_get_counter returns wrong blocks
+    - clk: ti: clockdomain: fix static checker warning
+    - net: 9p: initialize sun_server.sun_path to have addr's value only when addr
+      is valid
+    - drivers: watchdog: rdc321x_wdt: Fix race condition bugs
+    - ext4: Detect already used quota file early
+    - gfs2: add validation checks for size of superblock
+    - memory: emif: Remove bogus debugfs error handling
+    - ARM: dts: s5pv210: move PMU node out of clock controller
+    - ARM: dts: s5pv210: remove dedicated 'audio-subsystem' node
+    - md/raid5: fix oops during stripe resizing
+    - leds: bcm6328, bcm6358: use devres LED registering function
+    - NFS: fix nfs_path in case of a rename retry
+    - ACPI / extlog: Check for RDMSR failure
+    - acpi-cpufreq: Honor _PSD table setting on new AMD CPUs
+    - w1: mxc_w1: Fix timeout resolution problem leading to bus error
+    - scsi: mptfusion: Fix null pointer dereferences in mptscsih_remove()
+    - btrfs: reschedule if necessary when logging directory items
+    - vt: keyboard, simplify vt_kdgkbsent
+    - vt: keyboard, extend func_buf_lock to readers
+    - dmaengine: dma-jz4780: Fix race in jz4780_dma_tx_status
+    - iio:gyro:itg3200: Fix timestamp alignment and prevent data leak.
+    - powerpc/powernv/elog: Fix race while processing OPAL error log event.
+    - ubifs: dent: Fix some potential memory leaks while iterating entries
+    - ubi: check kthread_should_stop() after the setting of task state
+    - ia64: fix build error with !COREDUMP
+    - ceph: promote to unsigned long long before shifting
+    - libceph: clear con->out_msg on Policy::stateful_server faults
+    - 9P: Cast to loff_t before multiplying
+    - ring-buffer: Return 0 on success from ring_buffer_resize()
+    - vringh: fix __vringh_iov() when riov and wiov are different
+    - tty: make FONTX ioctl use the tty pointer they were actually passed
+    - arm64: berlin: Select DW_APB_TIMER_OF
+    - cachefiles: Handle readpage error correctly
+    - hil/parisc: Disable HIL driver when it gets stuck
+    - ARM: samsung: fix PM debug build with DEBUG_LL but !MMU
+    - ARM: s3c24xx: fix missing system reset
+    - device property: Keep secondary firmware node secondary by type
+    - device property: Don't clear secondary pointer for shared primary firmware
+      node
+    - staging: comedi: cb_pcidas: Allow 2-channel commands for AO subdevice
+    - Revert "Revert "XEN uses irqdesc::irq_data_common::handler_data to store a
+      per interrupt XEN data pointer which contains XEN specific information.""
+    - xen/events: don't use chip_data for legacy IRQs
+    - tipc: fix use-after-free in tipc_bcast_get_mode
+    - gianfar: Replace skb_realloc_headroom with skb_cow_head for PTP
+    - gianfar: Account for Tx PTP timestamp in the skb headroom
+    - Fonts: Replace discarded const qualifier
+    - ALSA: usb-audio: Add implicit feedback quirk for Qu-16
+    - ftrace: Fix recursion check for NMI test
+    - ftrace: Handle tracing when switching between context
+    - ARM: dts: sun4i-a10: fix cpu_alert temperature
+    - x86/kexec: Use up-to-dated screen_info copy to fill boot params
+    - of: Fix reserved-memory overlap detection
+    - scsi: core: Don't start concurrent async scan on same host
+    - vsock: use ns_capable_noaudit() on socket create
+    - vt: Disable KD_FONT_OP_COPY
+    - fork: fix copy_process(CLONE_PARENT) race with the exiting ->real_parent
+    - serial: 8250_mtk: Fix uart_get_baud_rate warning
+    - serial: txx9: add missing platform_driver_unregister() on error in
+      serial_txx9_init
+    - USB: serial: cyberjack: fix write-URB completion race
+    - USB: serial: option: add LE910Cx compositions 0x1203, 0x1230, 0x1231
+    - USB: serial: option: add Telit FN980 composition 0x1055
+    - USB: Add NO_LPM quirk for Kingston flash drive
+    - ARC: stack unwinding: avoid indefinite looping
+    - Revert "ARC: entry: fix potential EFA clobber when TIF_SYSCALL_TRACE"
+    - Linux 4.4.242
+
+  * [HP 635] Radeon 6310 brightness control does not work (LP: #1894667) //
+    Xenial update: v4.4.242 upstream stable release (LP: #1903750)
+    - ACPI: video: use ACPI backlight for HP 635 Notebook
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Fri, 27 Nov 2020 16:22:59 -0700
+
+linux (4.4.0-197.229) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-197.229 -proposed tracker (LP: #1905489)
+
+  * sha1_ce and sha2_ce modules no longer load on arm64 (LP: #1905336)
+    - SAUCE: Revert "crypto: arm64/sha - avoid non-standard inline asm tricks"
+
+  * Fails to build on powerpc (LP: #1905475)
+    - powerpc/uaccess-flush: fix corenet64_smp_defconfig build
+    - SAUCE: powerpc/uaccess: only include kup-radix.h on PPC_BOOK3S_64
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 25 Nov 2020 06:36:47 -0300
+
+linux (4.4.0-196.228) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-196.228 -proposed tracker (LP: #1905309)
+
+  * CVE-2020-4788
+    - SAUCE: powerpc/64s: Define MASKABLE_RELON_EXCEPTION_PSERIES_OOL
+    - SAUCE: powerpc/64s: move some exception handlers out of line
+    - powerpc/64s: flush L1D on kernel entry
+    - SAUCE: powerpc: Add a framework for user access tracking
+    - powerpc: Implement user_access_begin and friends
+    - powerpc: Fix __clear_user() with KUAP enabled
+    - powerpc/uaccess: Evaluate macro arguments once, before user access is
+      allowed
+    - powerpc/64s: flush L1D after user accesses
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 23 Nov 2020 15:06:11 -0300
+
+linux (4.4.0-195.227) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-195.227 -proposed tracker (LP: #1903107)
+
+  * Update kernel packaging to support forward porting kernels (LP: #1902957)
+    - [Debian] Update for leader included in BACKPORT_SUFFIX
+
+  * Avoid double newline when running insertchanges (LP: #1903293)
+    - [Packaging] insertchanges: avoid double newline
+
+  * EFI: Fails when BootCurrent entry does not exist (LP: #1899993)
+    - efivarfs: Replace invalid slashes with exclamation marks in dentries.
+
+  * CVE-2020-14351
+    - perf/core: Fix race in the perf_mmap_close() function
+
+  * CVE-2020-25645
+    - geneve: add transport ports in route lookup for geneve
+
+  * Xenial update: v4.4.241 upstream stable release (LP: #1902097)
+    - ibmveth: Identify ingress large send packets.
+    - tipc: fix the skb_unshare() in tipc_buf_append()
+    - net/ipv4: always honour route mtu during forwarding
+    - r8169: fix data corruption issue on RTL8402
+    - ALSA: bebob: potential info leak in hwdep_read()
+    - mm/kasan: print name of mem[set,cpy,move]() caller in report
+    - mm/kasan: add API to check memory regions
+    - compiler.h, kasan: Avoid duplicating __read_once_size_nocheck()
+    - compiler.h: Add read_word_at_a_time() function.
+    - lib/strscpy: Shut up KASAN false-positives in strscpy()
+    - x86/mm/ptdump: Fix soft lockup in page table walker
+    - net: hdlc: In hdlc_rcv, check to make sure dev is an HDLC device
+    - net: hdlc_raw_eth: Clear the IFF_TX_SKB_SHARING flag after calling
+      ether_setup
+    - nfc: Ensure presence of NFC_ATTR_FIRMWARE_NAME attribute in
+      nfc_genl_fw_download()
+    - tcp: fix to update snd_wl1 in bulk receiver fast path
+    - icmp: randomize the global rate limiter
+    - cifs: remove bogus debug code
+    - ima: Don't ignore errors from crypto_shash_update()
+    - EDAC/i5100: Fix error handling order in i5100_init_one()
+    - crypto: ixp4xx - Fix the size used in a 'dma_free_coherent()' call
+    - media: Revert "media: exynos4-is: Add missed check for
+      pinctrl_lookup_state()"
+    - media: m5mols: Check function pointer in m5mols_sensor_power
+    - media: omap3isp: Fix memleak in isp_probe
+    - crypto: omap-sham - fix digcnt register handling with export/import
+    - media: tc358743: initialize variable
+    - media: ti-vpe: Fix a missing check and reference count leak
+    - ath6kl: prevent potential array overflow in ath6kl_add_new_sta()
+    - ath9k: Fix potential out of bounds in ath9k_htc_txcompletion_cb()
+    - wcn36xx: Fix reported 802.11n rx_highest rate wcn3660/wcn3680
+    - mwifiex: Do not use GFP_KERNEL in atomic context
+    - drm/gma500: fix error check
+    - scsi: qla4xxx: Fix an error handling path in 'qla4xxx_get_host_stats()'
+    - scsi: csiostor: Fix wrong return value in csio_hw_prep_fw()
+    - backlight: sky81452-backlight: Fix refcount imbalance on error
+    - VMCI: check return value of get_user_pages_fast() for errors
+    - tty: serial: earlycon dependency
+    - pty: do tty_flip_buffer_push without port->lock in pty_write
+    - drivers/virt/fsl_hypervisor: Fix error handling path
+    - video: fbdev: vga16fb: fix setting of pixclock because a pass-by-value error
+    - video: fbdev: sis: fix null ptr dereference
+    - HID: roccat: add bounds checking in kone_sysfs_write_settings()
+    - ath6kl: wmi: prevent a shift wrapping bug in ath6kl_wmi_delete_pstream_cmd()
+    - misc: mic: scif: Fix error handling path
+    - ALSA: seq: oss: Avoid mutex lock for a long-time ioctl
+    - quota: clear padding in v2r1_mem2diskdqb()
+    - net: enic: Cure the enic api locking trainwreck
+    - mfd: sm501: Fix leaks in probe()
+    - usb: gadget: u_ether: enable qmult on SuperSpeed Plus as well
+    - nl80211: fix non-split wiphy information
+    - mwifiex: fix double free
+    - net: korina: fix kfree of rx/tx descriptor array
+    - IB/mlx4: Adjust delayed work when a dup is observed
+    - powerpc/pseries: Fix missing of_node_put() in rng_init()
+    - powerpc/icp-hv: Fix missing of_node_put() in success path
+    - mtd: lpddr: fix excessive stack usage with clang
+    - mtd: mtdoops: Don't write panic data twice
+    - ARM: 9007/1: l2c: fix prefetch bits init in L2X0_AUX_CTRL using DT values
+    - powerpc/tau: Use appropriate temperature sample interval
+    - powerpc/tau: Remove duplicated set_thresholds() call
+    - powerpc/tau: Disable TAU between measurements
+    - perf intel-pt: Fix "context_switch event has no tid" error
+    - kdb: Fix pager search for multi-line strings
+    - powerpc/perf/hv-gpci: Fix starting index value
+    - cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_reboot_notifier
+    - lib/crc32.c: fix trivial typo in preprocessor condition
+    - vfio/pci: Clear token on bypass registration failure
+    - Input: imx6ul_tsc - clean up some errors in imx6ul_tsc_resume()
+    - Input: ep93xx_keypad - fix handling of platform_get_irq() error
+    - Input: omap4-keypad - fix handling of platform_get_irq() error
+    - Input: sun4i-ps2 - fix handling of platform_get_irq() error
+    - KVM: x86: emulating RDPID failure shall return #UD rather than #GP
+    - memory: omap-gpmc: Fix a couple off by ones
+    - memory: fsl-corenet-cf: Fix handling of platform_get_irq() error
+    - arm64: dts: zynqmp: Remove additional compatible string for i2c IPs
+    - powerpc/powernv/opal-dump : Use IRQ_HANDLED instead of numbers in interrupt
+      handler
+    - powerpc/powernv/dump: Fix race while processing OPAL dump
+    - media: firewire: fix memory leak
+    - media: ati_remote: sanity check for both endpoints
+    - media: exynos4-is: Fix several reference count leaks due to
+      pm_runtime_get_sync
+    - media: exynos4-is: Fix a reference count leak due to pm_runtime_get_sync
+    - media: exynos4-is: Fix a reference count leak
+    - media: bdisp: Fix runtime PM imbalance on error
+    - media: media/pci: prevent memory leak in bttv_probe
+    - media: uvcvideo: Ensure all probed info is returned to v4l2
+    - mmc: sdio: Check for CISTPL_VERS_1 buffer size
+    - media: saa7134: avoid a shift overflow
+    - ntfs: add check for mft record size in superblock
+    - PM: hibernate: remove the bogus call to get_gendisk() in software_resume()
+    - scsi: mvumi: Fix error return in mvumi_io_attach()
+    - scsi: target: core: Add CONTROL field for trace events
+    - usb: gadget: function: printer: fix use-after-free in __lock_acquire
+    - udf: Limit sparing table size
+    - udf: Avoid accessing uninitialized data on failed inode read
+    - ath9k: hif_usb: fix race condition between usb_get_urb() and
+      usb_kill_anchored_urbs()
+    - misc: rtsx: Fix memory leak in rtsx_pci_probe
+    - reiserfs: only call unlock_new_inode() if I_NEW
+    - xfs: make sure the rt allocator doesn't run off the end
+    - usb: ohci: Default to per-port over-current protection
+    - Bluetooth: Only mark socket zapped after unlocking
+    - scsi: ibmvfc: Fix error return in ibmvfc_probe()
+    - brcmsmac: fix memory leak in wlc_phy_attach_lcnphy
+    - rtl8xxxu: prevent potential memory leak
+    - Fix use after free in get_capset_info callback.
+    - tty: ipwireless: fix error handling
+    - ipvs: Fix uninit-value in do_ip_vs_set_ctl()
+    - reiserfs: Fix memory leak in reiserfs_parse_options()
+    - brcm80211: fix possible memleak in brcmf_proto_msgbuf_attach
+    - usb: core: Solve race condition in anchor cleanup functions
+    - ath10k: check idx validity in __ath10k_htt_rx_ring_fill_n()
+    - net: korina: cast KSEG0 address to pointer in kfree
+    - usb: cdc-acm: add quirk to blacklist ETAS ES58X devices
+    - USB: cdc-wdm: Make wdm_flush() interruptible and add wdm_fsync().
+    - Linux 4.4.241
+
+  * Xenial update: v4.4.240 upstream stable release (LP: #1902096)
+    - Bluetooth: MGMT: Fix not checking if BT_HS is enabled
+    - Bluetooth: fix kernel oops in store_pending_adv_report
+    - Bluetooth: Consolidate encryption handling in hci_encrypt_cfm
+    - Bluetooth: Fix update of connection state in `hci_encrypt_cfm`
+    - Bluetooth: Disconnect if E0 is used for Level 4
+    - media: usbtv: Fix refcounting mixup
+    - USB: serial: option: add Cellient MPL200 card
+    - USB: serial: option: Add Telit FT980-KS composition
+    - staging: comedi: check validity of wMaxPacketSize of usb endpoints found
+    - USB: serial: pl2303: add device-id for HP GC device
+    - USB: serial: ftdi_sio: add support for FreeCalypso JTAG+UART adapters
+    - reiserfs: Initialize inode keys properly
+    - reiserfs: Fix oops during mount
+    - spi: unbinding slave before calling spi_destroy_queue
+    - crypto: qat - check cipher length for aead AES-CBC-HMAC-SHA
+    - Linux 4.4.240
+
+  * Xenial update: v4.4.239 upstream stable release (LP: #1902095)
+    - gpio: tc35894: fix up tc35894 interrupt configuration
+    - Input: i8042 - add nopnp quirk for Acer Aspire 5 A515
+    - drm/amdgpu: restore proper ref count in amdgpu_display_crtc_set_config
+    - net: dec: de2104x: Increase receive ring size for Tulip
+    - rndis_host: increase sleep time in the query-response loop
+    - drivers/net/wan/lapbether: Make skb->protocol consistent with the header
+    - drivers/net/wan/hdlc: Set skb->protocol before transmitting
+    - nfs: Fix security label length not being reset
+    - clk: samsung: exynos4: mark 'chipid' clock as CLK_IGNORE_UNUSED
+    - iommu/exynos: add missing put_device() call in exynos_iommu_of_xlate()
+    - i2c: cpm: Fix i2c_ram structure
+    - epoll: do not insert into poll queues until all sanity checks are done
+    - epoll: replace ->visited/visited_list with generation count
+    - epoll: EPOLL_CTL_ADD: close the race in decision to take fast path
+    - ep_create_wakeup_source(): dentry name can change under you...
+    - netfilter: ctnetlink: add a range check for l3/l4 protonum
+    - fbdev, newport_con: Move FONT_EXTRA_WORDS macros into linux/font.h
+    - Fonts: Support FONT_EXTRA_WORDS macros for built-in fonts
+    - Revert "ravb: Fixed to be able to unload modules"
+    - fbcon: Fix global-out-of-bounds read in fbcon_get_font()
+    - net: wireless: nl80211: fix out-of-bounds access in nl80211_del_key()
+    - usermodehelper: reset umask to default before executing user process
+    - platform/x86: thinkpad_acpi: initialize tp_nvram_state variable
+    - platform/x86: thinkpad_acpi: re-initialize ACPI buffer size when reuse
+    - driver core: Fix probe_count imbalance in really_probe()
+    - perf top: Fix stdio interface input handling with glibc 2.28+
+    - sctp: fix sctp_auth_init_hmacs() error path
+    - team: set dev->needed_headroom in team_setup_by_port()
+    - net: team: fix memory leak in __team_options_register
+    - mtd: nand: Provide nand_cleanup() function to free NAND related resources
+    - xfrm: clone XFRMA_REPLAY_ESN_VAL in xfrm_do_migrate
+    - xfrm: clone whole liftime_cur structure in xfrm_do_migrate
+    - net: stmmac: removed enabling eee in EEE set callback
+    - xfrm: Use correct address family in xfrm_state_find
+    - bonding: set dev->needed_headroom in bond_setup_by_slave()
+    - rxrpc: Fix rxkad token xdr encoding
+    - rxrpc: Downgrade the BUG() for unsupported token type in rxrpc_read()
+    - rxrpc: Fix server keyring leak
+    - net: usb: rtl8150: set random MAC address when set_ethernet_addr() fails
+    - Linux 4.4.239
+
+  * CVE-2020-12352
+    - Bluetooth: A2MP: Fix not initializing all members
+
+  * CVE-2020-0427
+    - pinctrl: devicetree: Avoid taking direct reference to device name string
+
+  * Xenial update: v4.4.238 upstream stable release (LP: #1899506)
+    - af_key: pfkey_dump needs parameter validation
+    - KVM: fix memory leak in kvm_io_bus_unregister_dev()
+    - kprobes: fix kill kprobe which has been marked as gone
+    - ftrace: Setup correct FTRACE_FL_REGS flags for module
+    - RDMA/ucma: ucma_context reference leak in error path
+    - mtd: Fix comparison in map_word_andequal()
+    - hdlc_ppp: add range checks in ppp_cp_parse_cr()
+    - tipc: use skb_unshare() instead in tipc_buf_append()
+    - net: add __must_check to skb_put_padto()
+    - ip: fix tos reflection in ack and reset packets
+    - serial: 8250: Avoid error message on reprobe
+    - scsi: aacraid: fix illegal IO beyond last LBA
+    - m68k: q40: Fix info-leak in rtc_ioctl
+    - gma/gma500: fix a memory disclosure bug due to uninitialized bytes
+    - ASoC: kirkwood: fix IRQ error handling
+    - PM / devfreq: tegra30: Fix integer overflow on CPU's freq max out
+    - mtd: cfi_cmdset_0002: don't free cfi->cfiq in error path of
+      cfi_amdstd_setup()
+    - mfd: mfd-core: Protect against NULL call-back function pointer
+    - tracing: Adding NULL checks for trace_array descriptor pointer
+    - bcache: fix a lost wake-up problem caused by mca_cannibalize_lock
+    - xfs: fix attr leaf header freemap.size underflow
+    - kernel/sys.c: avoid copying possible padding bytes in copy_to_user
+    - neigh_stat_seq_next() should increase position index
+    - rt_cpu_seq_next should increase position index
+    - seqlock: Require WRITE_ONCE surrounding raw_seqcount_barrier
+    - ACPI: EC: Reference count query handlers under lock
+    - tracing: Set kernel_stack's caller size properly
+    - ar5523: Add USB ID of SMCWUSBT-G2 wireless adapter
+    - Bluetooth: Fix refcount use-after-free issue
+    - mm: pagewalk: fix termination condition in walk_pte_range()
+    - Bluetooth: prefetch channel before killing sock
+    - skbuff: fix a data race in skb_queue_len()
+    - audit: CONFIG_CHANGE don't log internal bookkeeping as an event
+    - selinux: sel_avc_get_stat_idx should increase position index
+    - scsi: lpfc: Fix RQ buffer leakage when no IOCBs available
+    - drm/omap: fix possible object reference leak
+    - dmaengine: tegra-apb: Prevent race conditions on channel's freeing
+    - media: go7007: Fix URB type for interrupt handling
+    - Bluetooth: guard against controllers sending zero'd events
+    - drm/amdgpu: increase atombios cmd timeout
+    - Bluetooth: L2CAP: handle l2cap config request during open state
+    - media: tda10071: fix unsigned sign extension overflow
+    - tpm: ibmvtpm: Wait for buffer to be set before proceeding
+    - tracing: Use address-of operator on section symbols
+    - serial: 8250_omap: Fix sleeping function called from invalid context during
+      probe
+    - SUNRPC: Fix a potential buffer overflow in 'svc_print_xprts()'
+    - ubifs: Fix out-of-bounds memory access caused by abnormal value of node_len
+    - ALSA: usb-audio: Fix case when USB MIDI interface has more than one extra
+      endpoint descriptor
+    - mm/filemap.c: clear page error before actual read
+    - mm/mmap.c: initialize align_offset explicitly for vm_unmapped_area
+    - KVM: Remove CREATE_IRQCHIP/SET_PIT2 race
+    - bdev: Reduce time holding bd_mutex in sync in blkdev_close()
+    - drivers: char: tlclk.c: Avoid data race between init and interrupt handler
+    - dt-bindings: sound: wm8994: Correct required supplies based on actual
+      implementaion
+    - atm: fix a memory leak of vcc->user_back
+    - phy: samsung: s5pv210-usb2: Add delay after reset
+    - Bluetooth: Handle Inquiry Cancel error after Inquiry Complete
+    - USB: EHCI: ehci-mv: fix error handling in mv_ehci_probe()
+    - tty: serial: samsung: Correct clock selection logic
+    - ALSA: hda: Fix potential race in unsol event handler
+    - fuse: don't check refcount after stealing page
+    - USB: EHCI: ehci-mv: fix less than zero comparison of an unsigned int
+    - e1000: Do not perform reset in reset_task if we are already down
+    - printk: handle blank console arguments passed in.
+    - vfio/pci: fix memory leaks of eventfd ctx
+    - perf kcore_copy: Fix module map when there are no modules loaded
+    - mtd: rawnand: omap_elm: Fix runtime PM imbalance on error
+    - ceph: fix potential race in ceph_check_caps
+    - mtd: parser: cmdline: Support MTD names containing one or more colons
+    - x86/speculation/mds: Mark mds_user_clear_cpu_buffers() __always_inline
+    - vfio/pci: Clear error and request eventfd ctx after releasing
+    - vfio/pci: fix racy on error and request eventfd ctx
+    - s390/init: add missing __init annotations
+    - batman-adv: bla: fix type misuse for backbone_gw hash indexing
+    - atm: eni: fix the missed pci_disable_device() for eni_init_one()
+    - batman-adv: mcast/TT: fix wrongly dropped or rerouted packets
+    - ALSA: asihpi: fix iounmap in error handler
+    - MIPS: Add the missing 'CPU_1074K' into __get_cpu_type()
+    - tty: vt, consw->con_scrolldelta cleanup
+    - kprobes: Fix to check probe enabled before disarm_kprobe_ftrace()
+    - lib/string.c: implement stpcpy
+    - ata: define AC_ERR_OK
+    - ata: make qc_prep return ata_completion_errors
+    - ata: sata_mv, avoid trigerrable BUG_ON
+    - Linux 4.4.238
+
+  * *-tools-common packages descriptions have typo "PGKVER" (LP: #1898903)
+    - [Packaging] Fix typo in -tools template s/PGKVER/PKGVER/
+
+  * Xenial update: v4.4.237 upstream stable release (LP: #1897602)
+    - ARM: dts: socfpga: fix register entry for timer3 on Arria10
+    - scsi: libsas: Set data_dir as DMA_NONE if libata marks qc as NODATA
+    - drivers/net/wan/lapbether: Added needed_tailroom
+    - firestream: Fix memleak in fs_open
+    - drivers/net/wan/lapbether: Set network_header before transmitting
+    - xfs: initialize the shortform attr header padding entry
+    - drivers/net/wan/hdlc_cisco: Add hard_header_len
+    - ALSA: hda: fix a runtime pm issue in SOF when integrated GPU is disabled
+    - gcov: Disable gcov build with GCC 10
+    - iio: adc: mcp3422: fix locking scope
+    - iio: adc: mcp3422: fix locking on error path
+    - iio:light:ltr501 Fix timestamp alignment issue.
+    - iio:accel:bmc150-accel: Fix timestamp alignment and prevent data leak.
+    - iio:accel:mma8452: Fix timestamp alignment and prevent data leak.
+    - USB: core: add helpers to retrieve endpoints
+    - staging: wlan-ng: fix out of bounds read in prism2sta_probe_usb()
+    - btrfs: fix wrong address when faulting in pages in the search ioctl
+    - scsi: target: iscsi: Fix hang in iscsit_access_np() when getting
+      tpg->np_login_sem
+    - rbd: require global CAP_SYS_ADMIN for mapping and unmapping
+    - fbcon: remove soft scrollback code
+    - fbcon: remove now unusued 'softback_lines' cursor() argument
+    - vgacon: remove software scrollback support
+    - [Config] updateconfigs for VGACON_SOFT_SCROLLBACK
+    - KVM: VMX: Don't freeze guest when event delivery causes an APIC-access exit
+    - video: fbdev: fix OOB read in vga_8planes_imageblit()
+    - USB: serial: ftdi_sio: add IDs for Xsens Mti USB converter
+    - USB: serial: option: add support for SIM7070/SIM7080/SIM7090 modules
+    - usb: Fix out of sync data toggle if a configured device is reconfigured
+    - gcov: add support for GCC 10.1
+    - NFSv4.1 handle ERR_DELAY error reclaiming locking state on delegation recall
+    - scsi: pm8001: Fix memleak in pm8001_exec_internal_task_abort
+    - scsi: lpfc: Fix FLOGI/PLOGI receive race condition in pt2pt discovery
+    - SUNRPC: stop printk reading past end of string
+    - rapidio: Replace 'select' DMAENGINES 'with depends on'
+    - i2c: algo: pca: Reapply i2c bus settings after reset
+    - MIPS: SNI: Fix MIPS_L1_CACHE_SHIFT
+    - perf test: Free formats for perf pmu parse test
+    - fbcon: Fix user font detection test at fbcon_resize().
+    - MIPS: SNI: Fix spurious interrupts
+    - USB: quirks: Add USB_QUIRK_IGNORE_REMOTE_WAKEUP quirk for BYD zhaoxin
+      notebook
+    - USB: UAS: fix disconnect by unplugging a hub
+    - usblp: fix race between disconnect() and read()
+    - Input: i8042 - add Entroware Proteus EL07R4 to nomux and reset lists
+    - serial: 8250_pci: Add Realtek 816a and 816b
+    - ehci-hcd: Move include to keep CRC stable
+    - powerpc/dma: Fix dma_map_ops::get_required_mask
+    - x86/defconfig: Enable CONFIG_USB_XHCI_HCD=y
+    - Linux 4.4.237
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 09 Nov 2020 11:42:59 +0100
+
+linux (4.4.0-194.226) xenial; urgency=medium
+
+  * CVE-2020-8694
+    - powercap: make attributes only readable by root
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 21 Oct 2020 11:31:44 +0200
+
+linux (4.4.0-193.224) xenial; urgency=medium
+
+  * CVE-2020-16119
+    - SAUCE: dccp: avoid double free of ccid on child socket
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 06 Oct 2020 12:24:31 -0300
+
+linux (4.4.0-192.222) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-192.222 -proposed tracker (LP: #1897734)
+
+  * mwifiex stops working after kernel upgrade (LP: #1897299)
+    - mwifiex: Increase AES key storage size to 256 bits
+
+  * xenial 4.4.0-191-generic in -proposed has a regression (LP: #1896725)
+    - Revert "XEN uses irqdesc::irq_data_common::handler_data to store a per
+      interrupt XEN data pointer which contains XEN specific information."
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 29 Sep 2020 16:43:40 +0200
+
+linux (4.4.0-191.221) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-191.221 -proposed tracker (LP: #1896067)
+
+  * Novalink (mkvterm command failure) (LP: #1892546)
+    - tty: hvcs: Don't NULL tty->driver_data until hvcs_cleanup()
+
+  * Xenial update: v4.4.236 upstream stable release (LP: #1895891)
+    - HID: core: Correctly handle ReportSize being zero
+    - HID: core: Sanitize event code and type when mapping input
+    - perf record/stat: Explicitly call out event modifiers in the documentation
+    - mm, page_alloc: remove unnecessary variable from free_pcppages_bulk
+    - hwmon: (applesmc) check status earlier.
+    - ceph: don't allow setlease on cephfs
+    - s390: don't trace preemption in percpu macros
+    - xen/xenbus: Fix granting of vmalloc'd memory
+    - dmaengine: of-dma: Fix of_dma_router_xlate's of_dma_xlate handling
+    - batman-adv: Avoid uninitialized chaddr when handling DHCP
+    - batman-adv: bla: use netif_rx_ni when not in interrupt context
+    - dmaengine: at_hdmac: check return value of of_find_device_by_node() in
+      at_dma_xlate()
+    - netfilter: nf_tables: incorrect enum nft_list_attributes definition
+    - netfilter: nf_tables: fix destination register zeroing
+    - dmaengine: pl330: Fix burst length if burst size is smaller than bus width
+    - bnxt_en: Check for zero dir entries in NVRAM.
+    - fix regression in "epoll: Keep a reference on files added to the check list"
+    - tg3: Fix soft lockup when tg3_reset_task() fails.
+    - iommu/vt-d: Serialize IOMMU GCMD register modifications
+    - thermal: ti-soc-thermal: Fix bogus thermal shutdowns for omap4430
+    - include/linux/log2.h: add missing () around n in roundup_pow_of_two()
+    - btrfs: drop path before adding new uuid tree entry
+    - btrfs: Remove redundant extent_buffer_get in get_old_root
+    - btrfs: Remove extraneous extent_buffer_get from tree_mod_log_rewind
+    - btrfs: set the lockdep class for log tree extent buffers
+    - uaccess: Add non-pagefault user-space read functions
+    - uaccess: Add non-pagefault user-space write function
+    - btrfs: fix potential deadlock in the search ioctl
+    - net: qmi_wwan: MDM9x30 specific power management
+    - net: qmi_wwan: support "raw IP" mode
+    - net: qmi_wwan: should hold RTNL while changing netdev type
+    - net: qmi_wwan: ignore bogus CDC Union descriptors
+    - Add Dell Wireless 5809e Gobi 4G HSPA+ Mobile Broadband Card (rev3) to
+      qmi_wwan
+    - qmi_wwan: Added support for Gemalto's Cinterion PHxx WWAN interface
+    - qmi_wwan: add support for Quectel EC21 and EC25
+    - NET: usb: qmi_wwan: add support for Telit LE922A PID 0x1040
+    - drivers: net: usb: qmi_wwan: add QMI_QUIRK_SET_DTR for Telit PID 0x1201
+    - usb: qmi_wwan: add D-Link DWM-222 A2 device ID
+    - net: usb: qmi_wwan: add Telit ME910 support
+    - net: usb: qmi_wwan: add Telit 0x1050 composition
+    - ALSA: ca0106: fix error code handling
+    - ALSA: pcm: oss: Remove superfluous WARN_ON() for mulaw sanity check
+    - dm cache metadata: Avoid returning cmd->bm wild pointer on error
+    - dm thin metadata: Avoid returning cmd->bm wild pointer on error
+    - net: refactor bind_bucket fastreuse into helper
+    - net: initialize fastreuse on inet_inherit_port
+    - checkpatch: fix the usage of capture group ( ... )
+    - mm/hugetlb: fix a race between hugetlb sysctl handlers
+    - cfg80211: regulatory: reject invalid hints
+    - net: usb: Fix uninit-was-stored issue in asix_read_phy_addr()
+    - ALSA: firewire-digi00x: add support for console models of Digi00x series
+    - ALSA: firewire-digi00x: exclude Avid Adrenaline from detection
+    - ALSA; firewire-tascam: exclude Tascam FE-8 from detection
+    - fs/affs: use octal for permissions
+    - affs: fix basic permission bits to actually work
+    - ravb: Fixed to be able to unload modules
+    - net: ethernet: mlx4: Fix memory allocation in mlx4_buddy_init()
+    - bnxt_en: Failure to update PHY is not fatal condition.
+    - bnxt: don't enable NAPI until rings are ready
+    - net: usb: dm9601: Add USB ID of Keenetic Plus DSL
+    - sctp: not disable bh in the whole sctp_get_port_local()
+    - net: disable netpoll on fresh napis
+    - Linux 4.4.236
+
+  * clock: overriding the clocksource should select the requested clocksource
+    (LP: #1894591)
+    - clocksource: Defer override invalidation unless clock is unstable
+
+  * alsa/hdmi: the hdmi audio stops working from Ubuntu-4.4.0-155.182
+    (LP: #1895603)
+    - ALSA: hda/hdmi - Read the pin sense from register when repolling
+    - SAUCE: ALSA: hda/hdmi - Check pin_eld->monitor_present
+
+  * Xenial update: v4.4.235 upstream stable release (LP: #1895031)
+    - net: Fix potential wrong skb->protocol in skb_vlan_untag()
+    - tipc: fix uninit skb->data in tipc_nl_compat_dumpit()
+    - ipvlan: fix device features
+    - bonding: show saner speed for broadcast mode
+    - bonding: fix a potential double-unregister
+    - powerpc/pseries: Do not initiate shutdown when system is running on UPS
+    - ALSA: pci: delete repeated words in comments
+    - ASoC: tegra: Fix reference count leaks.
+    - media: pci: ttpci: av7110: fix possible buffer overflow caused by bad DMA
+      value in debiirq()
+    - scsi: target: tcmu: Fix crash on ARM during cmd completion
+    - drm/amdkfd: Fix reference count leaks.
+    - drm/radeon: fix multiple reference count leak
+    - drm/amdgpu: fix ref count leak in amdgpu_driver_open_kms
+    - drm/amd/display: fix ref count leak in amdgpu_drm_ioctl
+    - drm/amdgpu: fix ref count leak in amdgpu_display_crtc_set_config
+    - drm/amdgpu/display: fix ref count leak when pm_runtime_get_sync fails
+    - scsi: lpfc: Fix shost refcount mismatch when deleting vport
+    - selftests/powerpc: Purge extra count_pmc() calls of ebb selftests
+    - PCI: Fix pci_create_slot() reference count leak
+    - rtlwifi: rtl8192cu: Prevent leaking urb
+    - mips/vdso: Fix resource leaks in genvdso.c
+    - drm/nouveau/drm/noveau: fix reference count leak in nouveau_fbcon_open
+    - drm/nouveau: Fix reference count leak in nouveau_connector_detect
+    - locking/lockdep: Fix overflow in presentation of average lock-time
+    - scsi: iscsi: Do not put host in iscsi_set_flashnode_param()
+    - ceph: fix potential mdsc use-after-free crash
+    - scsi: fcoe: Memory leak fix in fcoe_sysfs_fcf_del()
+    - EDAC/ie31200: Fallback if host bridge device is already initialized
+    - media: davinci: vpif_capture: fix potential double free
+    - powerpc/spufs: add CONFIG_COREDUMP dependency
+    - USB: sisusbvga: Fix a potential UB casued by left shifting a negative value
+    - Revert "ath10k: fix DMA related firmware crashes on multiple devices"
+    - i2c: rcar: in slave mode, clear NACK earlier
+    - jbd2: make sure jh have b_transaction set in refile/unfile_buffer
+    - jbd2: abort journal if free a async write error metadata buffer
+    - s390/cio: add cond_resched() in the slow_eval_known_fn() loop
+    - scsi: ufs: Fix possible infinite loop in ufshcd_hold
+    - net: gianfar: Add of_node_put() before goto statement
+    - fbcon: prevent user font height or width change from causing potential out-
+      of-bounds access
+    - USB: lvtest: return proper error code in probe
+    - vt: defer kfree() of vc_screenbuf in vc_do_resize()
+    - vt_ioctl: change VT_RESIZEX ioctl to check for error return from vc_resize()
+    - serial: samsung: Removes the IRQ not found warning
+    - serial: pl011: Don't leak amba_ports entry on driver register error
+    - serial: 8250: change lock order in serial8250_do_startup()
+    - writeback: Protect inode->i_io_list with inode->i_lock
+    - writeback: Avoid skipping inode writeback
+    - writeback: Fix sync livelock due to b_dirty_time processing
+    - XEN uses irqdesc::irq_data_common::handler_data to store a per interrupt XEN
+      data pointer which contains XEN specific information.
+    - xhci: Do warm-reset when both CAS and XDEV_RESUME are set
+    - PM: sleep: core: Fix the handling of pending runtime resume requests
+    - device property: Fix the secondary firmware node handling in
+      set_primary_fwnode()
+    - USB: yurex: Fix bad gfp argument
+    - usb: uas: Add quirk for PNY Pro Elite
+    - USB: Ignore UAS for JMicron JMS567 ATA/ATAPI Bridge
+    - usb: host: ohci-exynos: Fix error handling in exynos_ohci_probe()
+    - usb: storage: Add unusual_uas entry for Sony PSZ drives
+    - btrfs: check the right error variable in btrfs_del_dir_entries_in_log
+    - HID: hiddev: Fix slab-out-of-bounds write in hiddev_ioctl_usage()
+    - ALSA: usb-audio: Update documentation comment for MS2109 quirk
+    - Linux 4.4.235
+
+  * DELL LATITUDE 5491 touchscreen doesn't work (LP: #1889446) // Xenial update:
+    v4.4.235 upstream stable release (LP: #1895031)
+    - USB: quirks: Add no-lpm quirk for another Raydium touchscreen
+
+  * Xenial update: v4.4.234 upstream stable release (LP: #1893248)
+    - cxl: Fix kobject memleak
+    - drm/imx: imx-ldb: Disable both channels for split mode in enc->disable()
+    - perf probe: Fix memory leakage when the probe point is not found
+    - net/compat: Add missing sock updates for SCM_RIGHTS
+    - watchdog: f71808e_wdt: indicate WDIOF_CARDRESET support in
+      watchdog_info.options
+    - watchdog: f71808e_wdt: remove use of wrong watchdog_info option
+    - coredump: fix race condition between collapse_huge_page() and core dumping
+    - khugepaged: khugepaged_test_exit() check mmget_still_valid()
+    - khugepaged: adjust VM_BUG_ON_MM() in __khugepaged_enter()
+    - btrfs: export helpers for subvolume name/id resolution
+    - btrfs: don't show full path of bind mounts in subvol=
+    - romfs: fix uninitialized memory leak in romfs_dev_read()
+    - mm: include CMA pages in lowmem_reserve at boot
+    - mm, page_alloc: fix core hung in free_pcppages_bulk()
+    - ext4: clean up ext4_match() and callers
+    - ext4: fix checking of directory entry validity for inline directories
+    - media: budget-core: Improve exception handling in budget_register()
+    - media: vpss: clean up resources in init
+    - Input: psmouse - add a newline when printing 'proto' by sysfs
+    - m68knommu: fix overwriting of bits in ColdFire V3 cache control
+    - xfs: fix inode quota reservation checks
+    - jffs2: fix UAF problem
+    - scsi: libfc: Free skb in fc_disc_gpn_id_resp() for valid cases
+    - virtio_ring: Avoid loop when vq is broken in virtqueue_poll
+    - xfs: Fix UBSAN null-ptr-deref in xfs_sysfs_init
+    - alpha: fix annotation of io{read,write}{16,32}be()
+    - ext4: fix potential negative array index in do_split()
+    - ASoC: intel: Fix memleak in sst_media_open
+    - powerpc: Allow 4224 bytes of stack expansion for the signal frame
+    - epoll: Keep a reference on files added to the check list
+    - do_epoll_ctl(): clean the failure exits up a bit
+    - mm/hugetlb: fix calculation of adjust_range_if_pmd_sharing_possible
+    - xen: don't reschedule in preemption off sections
+    - omapfb: dss: Fix max fclk divider for omap36xx
+    - KVM: arm/arm64: Don't reschedule in unmap_stage2_range()
+    - Linux 4.4.234
+
+  * CVE-2018-10322
+    - libxfs: synchronize dinode_verify with userspace
+    - xfs: sanity check directory inode di_size
+    - xfs: move inode fork verifiers to xfs_dinode_verify
+    - xfs: enhance dinode verifier
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 18 Sep 2020 11:37:51 +0200
+
+linux (4.4.0-190.220) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-190.220 -proposed tracker (LP: #1893431)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  *  [Hyper-V] VSS and File Copy daemons intermittently fails to start
+    (LP: #1891224)
+    - [Packaging] Bind hv_vss_daemon startup to hv_vss device
+    - [Packaging] bind hv_fcopy_daemon startup to hv_fcopy device
+
+  * CVE-2019-20811
+    - net-sysfs: call dev_hold if kobject_init_and_add success
+
+  * CVE-2020-0067
+    - f2fs: fix to avoid memory leakage in f2fs_listxattr
+
+  * CVE-2019-9453
+    - f2fs: fix to avoid accessing xattr across the boundary
+
+  * Xenial update: 4.4.233 upstream stable release (LP: #1892822)
+    - media: rc: prevent memory leak in cx23888_ir_probe
+    - ath9k_htc: release allocated buffer if timed out
+    - ath9k: release allocated buffer if timed out
+    - nfs: Move call to security_inode_listsecurity into nfs_listxattr
+    - PCI/ASPM: Disable ASPM on ASMedia ASM1083/1085 PCIe-to-PCI bridge
+    - drm/amdgpu: Prevent kernel-infoleak in amdgpu_info_ioctl()
+    - drm: hold gem reference until object is no longer accessed
+    - f2fs: check memory boundary by insane namelen
+    - f2fs: check if file namelen exceeds max value
+    - ARM: 8986/1: hw_breakpoint: Don't invoke overflow handler on uaccess
+      watchpoints
+    - fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins.
+    - rds: Prevent kernel-infoleak in rds_notify_queue_get()
+    - net/x25: Fix x25_neigh refcnt leak when x25 disconnect
+    - net/x25: Fix null-ptr-deref in x25_disconnect
+    - sh: Fix validation of system call number
+    - net: lan78xx: add missing endpoint sanity check
+    - net: lan78xx: fix transfer-buffer memory leak
+    - mlxsw: core: Increase scope of RCU read-side critical section
+    - mac80211: mesh: Free ie data when leaving mesh
+    - nfc: s3fwrn5: add missing release on skb in s3fwrn5_recv_frame
+    - net: ethernet: ravb: exit if re-initialization fails in tx timeout
+    - Revert "i2c: cadence: Fix the hold bit setting"
+    - xen-netfront: fix potential deadlock in xennet_remove()
+    - x86/i8259: Use printk_deferred() to prevent deadlock
+    - random32: update the net random state on interrupt and activity
+    - ARM: percpu.h: fix build error
+    - random: fix circular include dependency on arm64 after addition of percpu.h
+    - random32: remove net_rand_state from the latent entropy gcc plugin
+    - random32: move the pseudo-random 32-bit definitions to prandom.h
+    - ext4: fix direct I/O read error
+    - USB: serial: qcserial: add EM7305 QDL product ID
+    - ALSA: seq: oss: Serialize ioctls
+    - Bluetooth: Fix slab-out-of-bounds read in hci_extended_inquiry_result_evt()
+    - Bluetooth: Prevent out-of-bounds read in hci_inquiry_result_evt()
+    - Bluetooth: Prevent out-of-bounds read in hci_inquiry_result_with_rssi_evt()
+    - vgacon: Fix for missing check in scrollback handling
+    - mtd: properly check all write ioctls for permissions
+    - net/9p: validate fds in p9_fd_open
+    - drm/nouveau/fbcon: fix module unload when fbcon init has failed for some
+      reason
+    - cfg80211: check vendor command doit pointer before use
+    - igb: reinit_locked() should be called with rtnl_lock
+    - atm: fix atm_dev refcnt leaks in atmtcp_remove_persistent
+    - tools lib traceevent: Fix memory leak in process_dynamic_array_len
+    - binder: Prevent context manager from incrementing ref 0
+    - ipv4: Silence suspicious RCU usage warning
+    - ipv6: fix memory leaks on IPV6_ADDRFORM path
+    - Revert "vxlan: fix tos value before xmit"
+    - net: lan78xx: replace bogus endpoint lookup
+    - usb: hso: check for return value in hso_serial_common_create()
+    - vxlan: Ensure FDB dump is performed under RCU
+    - Smack: fix use-after-free in smk_write_relabel_self()
+    - tracepoint: Mark __tracepoint_string's __used
+    - udp: drop corrupt packets earlier to avoid data corruption
+    - gpio: fix oops resulting from calling of_get_named_gpio(NULL, ...)
+    - EDAC: Fix reference count leaks
+    - m68k: mac: Don't send IOP message until channel is idle
+    - m68k: mac: Fix IOP status/control register writes
+    - ARM: at91: pm: add missing put_device() call in at91_pm_sram_init()
+    - ARM: socfpga: PM: add missing put_device() call in
+      socfpga_setup_ocram_self_refresh()
+    - drm/tilcdc: fix leak & null ref in panel_connector_get_modes
+    - Bluetooth: add a mutex lock to avoid UAF in do_enale_set
+    - fs/btrfs: Add cond_resched() for try_release_extent_mapping() stalls
+    - drm/radeon: Fix reference count leaks caused by pm_runtime_get_sync
+    - video: fbdev: neofb: fix memory leak in neo_scan_monitor()
+    - drm/nouveau: fix multiple instances of reference count leaks
+    - drm/debugfs: fix plain echo to connector "force" attribute
+    - mm/mmap.c: Add cond_resched() for exit_mmap() CPU stalls
+    - brcmfmac: To fix Bss Info flag definition Bug
+    - iwlegacy: Check the return value of pcie_capability_read_*()
+    - usb: gadget: net2280: fix memory leak on probe error handling paths
+    - bdc: Fix bug causing crash after multiple disconnects
+    - dyndbg: fix a BUG_ON in ddebug_describe_flags
+    - bcache: fix super block seq numbers comparision in register_cache_set()
+    - ACPICA: Do not increment operation_region reference counts for field units
+    - agp/intel: Fix a memory leak on module initialisation failure
+    - video: fbdev: sm712fb: fix an issue about iounmap for a wrong address
+    - console: newport_con: fix an issue about leak related system resources
+    - iio: improve IIO_CONCENTRATION channel type description
+    - leds: lm355x: avoid enum conversion warning
+    - media: omap3isp: Add missed v4l2_ctrl_handler_free() for
+      preview_init_entities()
+    - scsi: cumana_2: Fix different dev_id between request_irq() and free_irq()
+    - drm/radeon: fix array out-of-bounds read and write issues
+    - scsi: powertec: Fix different dev_id between request_irq() and free_irq()
+    - scsi: eesox: Fix different dev_id between request_irq() and free_irq()
+    - media: firewire: Using uninitialized values in node_probe()
+    - media: exynos4-is: Add missed check for pinctrl_lookup_state()
+    - drm: panel: simple: Fix bpc for LG LB070WV8 panel
+    - mwifiex: Prevent memory corruption handling keys
+    - powerpc/vdso: Fix vdso cpu truncation
+    - PCI/ASPM: Add missing newline in sysfs 'policy'
+    - usb: dwc2: Fix error path in gadget registration
+    - scsi: mesh: Fix panic after host or bus reset
+    - Smack: fix another vsscanf out of bounds
+    - Smack: prevent underflow in smk_set_cipso()
+    - power: supply: check if calc_soc succeeded in pm860x_init_battery
+    - s390/qeth: don't process empty bridge port events
+    - wl1251: fix always return 0 error
+    - net: spider_net: Fix the size used in a 'dma_free_coherent()' call
+    - dlm: Fix kobject memleak
+    - pinctrl-single: fix pcs_parse_pinconf() return value
+    - drivers/net/wan/lapbether: Added needed_headroom and a skb->len check
+    - net/nfc/rawsock.c: add CAP_NET_RAW check.
+    - net: Set fput_needed iff FDPUT_FPUT is set
+    - ALSA: usb-audio: Creative USB X-Fi Pro SB1095 volume knob support
+    - ALSA: usb-audio: fix overeager device match for MacroSilicon MS2109
+    - ALSA: usb-audio: add quirk for Pioneer DDJ-RB
+    - crypto: qat - fix double free in qat_uclo_create_batch_init_list
+    - fs/minix: check return value of sb_getblk()
+    - fs/minix: don't allow getting deleted inodes
+    - fs/minix: reject too-large maximum file size
+    - ALSA: usb-audio: work around streaming quirk for MacroSilicon MS2109
+    - 9p: Fix memory leak in v9fs_mount
+    - parisc: mask out enable and reserved bits from sba imask
+    - ARM: 8992/1: Fix unwind_frame for clang-built kernels
+    - xen/balloon: fix accounting in alloc_xenballooned_pages error path
+    - xen/balloon: make the balloon wait interruptible
+    - PCI: hotplug: ACPI: Fix context refcounting in acpiphp_grab_context()
+    - btrfs: only search for left_info if there is no right_info in
+      try_merge_free_space
+    - btrfs: fix memory leaks after failure to lookup checksums during inode
+      logging
+    - powerpc: Fix circular dependency between percpu.h and mmu.h
+    - net: ethernet: stmmac: Disable hardware multicast filter
+    - net: stmmac: dwmac1000: provide multicast filter fallback
+    - md/raid5: Fix Force reconstruct-write io stuck in degraded raid5
+    - bcache: allocate meta data pages as compound pages
+    - mac80211: fix misplaced while instead of if
+    - MIPS: CPU#0 is not hotpluggable
+    - ext2: fix missing percpu_counter_inc
+    - ocfs2: change slot number type s16 to u16
+    - kprobes: Fix NULL pointer dereference at kprobe_ftrace_handler
+    - pseries: Fix 64 bit logical memory block panic
+    - USB: serial: ftdi_sio: make process-packet buffer unsigned
+    - USB: serial: ftdi_sio: clean up receive processing
+    - iommu/omap: Check for failure of a call to omap_iommu_dump_ctx
+    - iommu/vt-d: Enforce PASID devTLB field mask
+    - i2c: rcar: slave: only send STOP event when we have been addressed
+    - clk: clk-atlas6: fix return value check in atlas6_clk_init()
+    - Input: sentelic - fix error return when fsp_reg_write fails
+    - drm/vmwgfx: Fix two list_for_each loop exit tests
+    - nfs: Fix getxattr kernel panic and memory overflow
+    - fs/ufs: avoid potential u32 multiplication overflow
+    - mfd: dln2: Run event handler loop under spinlock
+    - ALSA: echoaudio: Fix potential Oops in snd_echo_resume()
+    - sh: landisk: Add missing initialization of sh_io_port_base
+    - ipv6: check skb->protocol before lookup for nexthop
+    - Linux 4.4.233
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Sat, 29 Aug 2020 00:39:55 +0200
+
+linux (4.4.0-189.219) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-189.219 -proposed tracker (LP: #1891057)
+
+  * Build and ship a signed wireguard.ko (LP: #1861284)
+    - [Packaging] autoreconstruct -- manage executable debian files
+    - [Packaging] dkms -- dkms package build packaging support
+    - [Packaging] wireguard -- add support for building signed .ko
+    - [Packaging] ignore wireguard modules when wireguard is disabled
+    - [Config] update dkms package versions
+    - [Config] wireguard -- enable for all architectures
+
+  * ipsec: policy priority management is broken (LP: #1890796)
+    - xfrm: policy: match with both mark and mask on user interfaces
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 11 Aug 2020 12:02:46 +0200
+
+linux (4.4.0-188.218) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-188.218 -proposed tracker (LP: #1890670)
+
+  * Xenial update: v4.4.232 upstream stable release (LP: #1889928)
+    - pinctrl: amd: fix npins for uart0 in kerncz_groups
+    - mac80211: allow rx of mesh eapol frames with default rx key
+    - scsi: scsi_transport_spi: Fix function pointer check
+    - xtensa: fix __sync_fetch_and_{and,or}_4 declarations
+    - xtensa: update *pos in cpuinfo_op.next
+    - drivers/net/wan/lapbether: Fixed the value of hard_header_len
+    - net: sky2: initialize return of gm_phy_read
+    - drm/nouveau/i2c/g94-: increase NV_PMGR_DP_AUXCTL_TRANSACTREQ timeout
+    - SUNRPC reverting d03727b248d0 ("NFSv4 fix CLOSE not waiting for direct IO
+      compeletion")
+    - perf/core: Fix locking for children siblings group read
+    - uprobes: Change handle_swbp() to send SIGTRAP with si_code=SI_KERNEL, to fix
+      GDB regression
+    - ALSA: info: Drop WARN_ON() from buffer NULL sanity check
+    - ASoC: rt5670: Correct RT5670_LDO_SEL_MASK
+    - btrfs: fix double free on ulist after backref resolution failure
+    - x86/fpu: Disable bottom halves while loading FPU registers
+    - btrfs: fix mount failure caused by race with umount
+    - hippi: Fix a size used in a 'pci_free_consistent()' in an error handling
+      path
+    - ax88172a: fix ax88172a_unbind() failures
+    - net: dp83640: fix SIOCSHWTSTAMP to update the struct with actual
+      configuration
+    - net: smc91x: Fix possible memory leak in smc_drv_probe()
+    - scripts/decode_stacktrace: strip basepath from all paths
+    - regmap: dev_get_regmap_match(): fix string comparison
+    - usb: gadget: udc: gr_udc: fix memleak on error handling path in gr_ep_init()
+    - arm64: Use test_tsk_thread_flag() for checking TIF_SINGLESTEP
+    - x86: math-emu: Fix up 'cmp' insn for clang ias
+    - Revert "cifs: Fix the target file was deleted when rename failed."
+    - staging: wlan-ng: properly check endpoint types
+    - staging: comedi: addi_apci_1032: check INSN_CONFIG_DIGITAL_TRIG shift
+    - staging: comedi: ni_6527: fix INSN_CONFIG_DIGITAL_TRIG support
+    - staging: comedi: addi_apci_1500: check INSN_CONFIG_DIGITAL_TRIG shift
+    - staging: comedi: addi_apci_1564: check INSN_CONFIG_DIGITAL_TRIG shift
+    - serial: 8250: fix null-ptr-deref in serial8250_start_tx()
+    - serial: 8250_mtk: Fix high-speed baud rates clamping
+    - mm/memcg: fix refcount error while moving and swapping
+    - parisc: Add atomic64_set_release() define to avoid CPU soft lockups
+    - ath9k: Fix general protection fault in ath9k_hif_usb_rx_cb
+    - ath9k: Fix regression with Atheros 9271
+    - AX.25: Fix out-of-bounds read in ax25_connect()
+    - AX.25: Prevent out-of-bounds read in ax25_sendmsg()
+    - net-sysfs: add a newline when printing 'tx_timeout' by sysfs
+    - net: udp: Fix wrong clean up for IS_UDPLITE macro
+    - AX.25: Prevent integer overflows in connect and sendmsg
+    - tcp: allow at most one TLP probe per flight
+    - rxrpc: Fix sendmsg() returning EPIPE due to recvmsg() returning ENODATA
+    - ip6_gre: fix null-ptr-deref in ip6gre_init_net()
+    - drivers/net/wan/x25_asy: Fix to make it work
+    - Makefile: Fix GCC_TOOLCHAIN_DIR prefix for Clang cross compilation
+    - regmap: debugfs: check count when read regmap file
+    - xfs: set format back to extents if xfs_bmap_extents_to_btree
+    - tools/lib/subcmd/pager.c: do not alias select() params
+    - perf: Make perf able to build with latest libbfd
+    - perf tools: Fix snprint warnings for gcc 8
+    - perf annotate: Use asprintf when formatting objdump command line
+    - perf probe: Fix to check blacklist address correctly
+    - Linux 4.4.232
+
+  * Xenial update: v4.4.231 upstream stable release (LP: #1888690)
+    - KVM: s390: reduce number of IO pins to 1
+    - spi: spidev: fix a race between spidev_release and spidev_remove
+    - spi: spidev: fix a potential use-after-free in spidev_release()
+    - scsi: mptscsih: Fix read sense data size
+    - net: cxgb4: fix return error value in t4_prep_fw
+    - smsc95xx: check return value of smsc95xx_reset
+    - smsc95xx: avoid memory leak in smsc95xx_bind
+    - ALSA: compress: fix partial_drain completion state
+    - arm64: kgdb: Fix single-step exception handling oops
+    - ALSA: opl3: fix infoleak in opl3
+    - ALSA: hda - let hs_mic be picked ahead of hp_mic
+    - ALSA: usb-audio: add quirk for MacroSilicon MS2109
+    - KVM: x86: bit 8 of non-leaf PDPEs is not reserved
+    - Revert "ath9k: Fix general protection fault in ath9k_hif_usb_rx_cb"
+    - btrfs: fix fatal extent_buffer readahead vs releasepage race
+    - drm/radeon: fix double free
+    - ARC: entry: fix potential EFA clobber when TIF_SYSCALL_TRACE
+    - ARC: elf: use right ELF_ARCH
+    - bnxt_en: fix NULL dereference in case SR-IOV configuration fails
+    - ipv4: fill fl4_icmp_{type,code} in ping_v4_sendmsg
+    - l2tp: remove skb_dst_set() from l2tp_xmit_skb()
+    - llc: make sure applications use ARPHRD_ETHER
+    - net: Added pointer check for dst->ops->neigh_lookup in dst_neigh_lookup_skb
+    - genetlink: remove genl_bind
+    - tcp: make sure listeners don't initialize congestion-control state
+    - tcp: md5: add missing memory barriers in tcp_md5_do_add()/tcp_md5_hash_key()
+    - tcp: md5: refine tcp_md5_do_add()/tcp_md5_hash_key() barriers
+    - tcp: md5: allow changing MD5 keys in all socket states
+    - i2c: eg20t: Load module automatically if ID matches
+    - Revert "usb/ehci-platform: Set PM runtime as active on resume"
+    - Revert "usb/xhci-plat: Set PM runtime as active on resume"
+    - Revert "usb/ohci-platform: Fix a warning when hibernating"
+    - usb: gadget: udc: atmel: fix uninitialized read in debug printk
+    - staging: comedi: verify array index is correct before using it
+    - perf stat: Zero all the 'ena' and 'run' array slot stats for interval mode
+    - mtd: rawnand: brcmnand: fix CS0 layout
+    - HID: magicmouse: do not set up autorepeat
+    - usb: core: Add a helper function to check the validity of EP type in URB
+    - ALSA: line6: Perform sanity check for each URB creation
+    - ALSA: usb-audio: Fix race against the error recovery URB submission
+    - USB: c67x00: fix use after free in c67x00_giveback_urb
+    - usb: chipidea: core: add wakeup support for extcon
+    - usb: gadget: function: fix missing spinlock in f_uac1_legacy
+    - USB: serial: iuu_phoenix: fix memory corruption
+    - USB: serial: cypress_m8: enable Simply Automated UPB PIM
+    - USB: serial: ch341: add new Product ID for CH340
+    - USB: serial: option: add GosunCn GM500 series
+    - USB: serial: option: add Quectel EG95 LTE modem
+    - virtio: virtio_console: add missing MODULE_DEVICE_TABLE() for rproc serial
+    - fuse: Fix parameter for FS_IOC_{GET,SET}FLAGS
+    - mei: bus: don't clean driver pointer
+    - Input: i8042 - add Lenovo XiaoXin Air 12 to i8042 nomux list
+    - uio_pdrv_genirq: fix use without device tree and no interrupt
+    - MIPS: Fix build for LTS kernel caused by backporting lpj adjustment
+    - hwmon: (emc2103) fix unable to change fan pwm1_enable attribute
+    - dmaengine: fsl-edma: Fix NULL pointer exception in fsl_edma_tx_handler
+    - misc: atmel-ssc: lock with mutex instead of spinlock
+    - sched/fair: handle case of task_h_load() returning 0
+    - Linux 4.4.231
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sun, 09 Aug 2020 01:05:44 -0400
+
+linux (4.4.0-187.217) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-187.217 -proposed tracker (LP: #1888274)
+
+  * Regression in kernel 4.15.0-91 causes kernel panic with Bcache
+    (LP: #1867916)
+    - bcache: check and adjust logical block size for backing devices
+
+  * Xenial update: v4.4.230 upstream stable release (LP: #1887011)
+    - btrfs: cow_file_range() num_bytes and disk_num_bytes are same
+    - btrfs: fix data block group relocation failure due to concurrent scrub
+    - mm: fix swap cache node allocation mask
+    - EDAC/amd64: Read back the scrub rate PCI register on F15h
+    - mm/slub: fix stack overruns with SLUB_STATS
+    - usb: usbtest: fix missing kfree(dev->buf) in usbtest_disconnect
+    - kgdb: Avoid suspicious RCU usage warning
+    - crypto: af_alg - fix use-after-free in af_alg_accept() due to bh_lock_sock()
+    - sched/rt: Show the 'sched_rr_timeslice' SCHED_RR timeslice tuning knob in
+      milliseconds
+    - hwmon: (max6697) Make sure the OVERT mask is set correctly
+    - hwmon: (acpi_power_meter) Fix potential memory leak in
+      acpi_power_meter_add()
+    - virtio-blk: free vblk-vqs in error path of virtblk_probe()
+    - i2c: algo-pca: Add 0x78 as SCL stuck low status for PCA9665
+    - Revert "ALSA: usb-audio: Improve frames size computation"
+    - SMB3: Honor 'seal' flag for multiuser mounts
+    - SMB3: Honor persistent/resilient handle flags for multiuser mounts
+    - cifs: Fix the target file was deleted when rename failed.
+    - MIPS: Add missing EHB in mtc0 -> mfc0 sequence for DSPen
+    - netfilter: nf_conntrack_h323: lost .data_len definition for Q.931/ipv6
+    - Linux 4.4.230
+
+  * Xenial update: v4.4.229 upstream stable release (LP: #1885932)
+    - s390: fix syscall_get_error for compat processes
+    - clk: sunxi: Fix incorrect usage of round_down()
+    - i2c: piix4: Detect secondary SMBus controller on AMD AM4 chipsets
+    - clk: qcom: msm8916: Fix the address location of pll->config_reg
+    - ALSA: isa/wavefront: prevent out of bounds write in ioctl
+    - scsi: qla2xxx: Fix issue with adapter's stopping state
+    - i2c: pxa: clear all master action bits in i2c_pxa_stop_message()
+    - usblp: poison URBs upon disconnect
+    - ps3disk: use the default segment boundary
+    - vfio/pci: fix memory leaks in alloc_perm_bits()
+    - mfd: wm8994: Fix driver operation if loaded as modules
+    - scsi: lpfc: Fix lpfc_nodelist leak when processing unsolicited event
+    - nfsd: Fix svc_xprt refcnt leak when setup callback client failed
+    - powerpc/crashkernel: Take "mem=" option into account
+    - yam: fix possible memory leak in yam_init_driver
+    - mksysmap: Fix the mismatch of '.L' symbols in System.map
+    - scsi: sr: Fix sr_probe() missing deallocate of device minor
+    - scsi: ibmvscsi: Don't send host info in adapter info MAD after LPM
+    - ALSA: usb-audio: Improve frames size computation
+    - s390/qdio: put thinint indicator after early error
+    - tty: hvc: Fix data abort due to race in hvc_open
+    - staging: sm750fb: add missing case while setting FB_VISUAL
+    - i2c: pxa: fix i2c_pxa_scream_blue_murder() debug output
+    - serial: amba-pl011: Make sure we initialize the port.lock spinlock
+    - drivers: base: Fix NULL pointer exception in __platform_driver_probe() if a
+      driver developer is foolish
+    - PCI/ASPM: Allow ASPM on links to PCIe-to-PCI/PCI-X Bridges
+    - power: supply: smb347-charger: IRQSTAT_D is volatile
+    - scsi: mpt3sas: Fix double free warnings
+    - dlm: remove BUG() before panic()
+    - clk: ti: composite: fix memory leak
+    - tty: n_gsm: Fix SOF skipping
+    - tty: n_gsm: Fix waking up upper tty layer when room available
+    - powerpc/pseries/ras: Fix FWNMI_VALID off by one
+    - powerpc/ps3: Fix kexec shutdown hang
+    - vfio-pci: Mask cap zero
+    - usb/ohci-platform: Fix a warning when hibernating
+    - USB: host: ehci-mxc: Add error handling in ehci_mxc_drv_probe()
+    - tty: n_gsm: Fix bogus i++ in gsm_data_kick
+    - clk: samsung: exynos5433: Add IGNORE_UNUSED flag to sclk_i2s1
+    - watchdog: da9062: No need to ping manually before setting timeout
+    - usb: dwc2: gadget: move gadget resume after the core is in L0 state
+    - USB: gadget: udc: s3c2410_udc: Remove pointless NULL check in
+      s3c2410_udc_nuke
+    - usb: gadget: lpc32xx_udc: don't dereference ep pointer before null check
+    - usb: gadget: fix potential double-free in m66592_probe.
+    - net: sunrpc: Fix off-by-one issues in 'rpc_ntop6'
+    - ASoC: fsl_asrc_dma: Fix dma_chan leak when config DMA channel failed
+    - openrisc: Fix issue with argument clobbering for clone/fork
+    - gfs2: Allow lock_nolock mount to specify jid=X
+    - scsi: iscsi: Fix reference count leak in iscsi_boot_create_kobj
+    - lib/zlib: remove outdated and incorrect pre-increment optimization
+    - include/linux/bitops.h: avoid clang shift-count-overflow warnings
+    - elfnote: mark all .note sections SHF_ALLOC
+    - selftests/net: in timestamping, strncpy needs to preserve null byte
+    - scsi: acornscsi: Fix an error handling path in acornscsi_probe()
+    - usb/xhci-plat: Set PM runtime as active on resume
+    - usb/ehci-platform: Set PM runtime as active on resume
+    - perf report: Fix NULL pointer dereference in
+      hists__fprintf_nr_sample_events()
+    - bcache: fix potential deadlock problem in btree_gc_coalesce
+    - block: Fix use-after-free in blkdev_get()
+    - drm: encoder_slave: fix refcouting error for modules
+    - drm/dp_mst: Reformat drm_dp_check_act_status() a bit
+    - drm/qxl: Use correct notify port address when creating cursor ring
+    - selinux: fix double free
+    - ext4: fix partial cluster initialization when splitting extent
+    - drm/dp_mst: Increase ACT retry timeout to 3s
+    - sparc64: fix misuses of access_process_vm() in genregs32_[sg]et()
+    - block: nr_sects_write(): Disable preemption on seqcount write
+    - crypto: algboss - don't wait during notifier callback
+    - kprobes: Fix to protect kick_kprobe_optimizer() by kprobe_mutex
+    - powerpc/kprobes: Fixes for kprobe_lookup_name() on BE
+    - x86/kprobes: Avoid kretprobe recursion bug
+    - kretprobe: Prevent triggering kretprobe from within kprobe_flush_task
+    - e1000e: Do not wake up the system via WOL if device wakeup is disabled
+    - sched/rt, net: Use CONFIG_PREEMPTION.patch
+    - net: core: device_rename: Use rwsem instead of a seqcount
+    - net: Revert "pkt_sched: fq: use proper locking in fq_dump_stats()"
+    - scsi: scsi_devinfo: handle non-terminated strings
+    - l2tp: Allow duplicate session creation with UDP
+    - net: sched: export __netdev_watchdog_up()
+    - fix a braino in "sparc32: fix register window handling in
+      genregs32_[gs]et()"
+    - net: fix memleak in register_netdevice()
+    - net: usb: ax88179_178a: fix packet alignment padding
+    - tg3: driver sleeps indefinitely when EEH errors exceed eeh_max_freezes
+    - ip_tunnel: fix use-after-free in ip_tunnel_lookup()
+    - tcp_cubic: fix spurious HYSTART_DELAY exit upon drop in min RTT
+    - ip6_gre: fix use-after-free in ip6gre_tunnel_lookup()
+    - tcp: grow window for OOO packets only for SACK flows
+    - sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
+    - net: Fix the arp error in some cases
+    - net: Do not clear the sock TX queue in sk_set_socket()
+    - net: core: reduce recursion limit value
+    - mld: fix memory leak in ipv6_mc_destroy_dev()
+    - USB: ohci-sm501: Add missed iounmap() in remove
+    - usb: dwc2: Postponed gadget registration to the udc class driver
+    - usb: add USB_QUIRK_DELAY_INIT for Logitech C922
+    - PCI: Disable MSI for HiSilicon Hip06/Hip07 Root Ports
+    - USB: ehci: reopen solution for Synopsys HC bug
+    - usb: host: ehci-exynos: Fix error check in exynos_ehci_probe()
+    - ALSA: usb-audio: add quirk for Denon DCD-1500RE
+    - xhci: Fix incorrect EP_STATE_MASK
+    - xhci: Fix enumeration issue when setting max packet size for FS devices.
+    - cdc-acm: Add DISABLE_ECHO quirk for Microchip/SMSC chip
+    - ALSA: usb-audio: uac1: Invalidate ctl on interrupt
+    - ALSA: usb-audio: allow clock source validity interrupts
+    - ALSA: usb-audio: Clean up mixer element list traverse
+    - ALSA: usb-audio: Fix OOB access of mixer element list
+    - xhci: Poll for U0 after disabling USB2 LPM
+    - cifs/smb3: Fix data inconsistent when punch hole
+    - cifs/smb3: Fix data inconsistent when zero file range
+    - efi/esrt: Fix reference count leak in esre_create_sysfs_entry.
+    - RDMA/mad: Fix possible memory leak in ib_mad_post_receive_mads()
+    - ARM: imx5: add missing put_device() call in imx_suspend_alloc_ocram()
+    - usb: gadget: udc: Potential Oops in error handling code
+    - netfilter: ipset: fix unaligned atomic access
+    - sched/core: Fix PI boosting between RT and DEADLINE tasks
+    - net: alx: fix race condition in alx_remove
+    - kbuild: improve cc-option to clean up all temporary files
+    - blktrace: break out of blktrace setup on concurrent calls
+    - ACPI: sysfs: Fix pm_profile_attr type
+    - KVM: X86: Fix MSR range of APIC registers in X2APIC mode
+    - mm/slab: use memzero_explicit() in kzfree()
+    - ocfs2: load global_inode_alloc
+    - ocfs2: fix value of OCFS2_INVALID_SLOT
+    - ocfs2: fix panic on nfs server over ocfs2
+    - arm64: perf: Report the PC value in REGS_ABI_32 mode
+    - tracing: Fix event trigger to accept redundant spaces
+    - drm/radeon: fix fb_div check in ni_init_smc_spll_table()
+    - sunrpc: fixed rollback in rpc_gssd_dummy_populate()
+    - SUNRPC: Properly set the @subbuf parameter of xdr_buf_subsegment()
+    - pNFS/flexfiles: Fix list corruption if the mirror count changes
+    - NFSv4 fix CLOSE not waiting for direct IO compeletion
+    - PCI: Disable MSI for HiSilicon Hip06/Hip07 only in Root Port mode
+    - ALSA: usb-audio: Fix invalid NULL check in snd_emuusb_set_samplerate()
+    - Linux 4.4.229
+
+  * Computer is frozen after suspend (LP: #1867983) // Xenial update: v4.4.229
+    upstream stable release (LP: #1885932)
+    - libata: Use per port sync for detach
+
+ -- Ian May <ian.may@canonical.com>  Mon, 20 Jul 2020 14:24:05 -0500
+
+linux (4.4.0-186.216) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-186.216 -proposed tracker (LP: #1885514)
+
+  * Xenial update: v4.4.228 upstream stable release (LP: #1884564)
+    - ipv6: fix IPV6_ADDRFORM operation logic
+    - vxlan: Avoid infinite loop when suppressing NS messages with invalid options
+    - scsi: return correct blkprep status code in case scsi_init_io() fails.
+    - net: phy: marvell: Limit 88m1101 autoneg errata to 88E1145 as well.
+    - pwm: fsl-ftm: Use flat regmap cache
+    - ARM: 8977/1: ptrace: Fix mask for thumb breakpoint hook
+    - sched/fair: Don't NUMA balance for kthreads
+    - ath9k_htc: Silence undersized packet warnings
+    - x86_64: Fix jiffies ODR violation
+    - x86/speculation: Prevent rogue cross-process SSBD shutdown
+    - x86/reboot/quirks: Add MacBook6,1 reboot quirk
+    - efi/efivars: Add missing kobject_put() in sysfs entry creation error path
+    - ALSA: es1688: Add the missed snd_card_free()
+    - ALSA: usb-audio: Fix inconsistent card PM state after resume
+    - ACPI: sysfs: Fix reference count leak in acpi_sysfs_add_hotplug_profile()
+    - ACPI: PM: Avoid using power resources if there are none for D0
+    - cgroup, blkcg: Prepare some symbols for module and !CONFIG_CGROUP usages
+    - nilfs2: fix null pointer dereference at nilfs_segctor_do_construct()
+    - spi: bcm2835aux: Fix controller unregister order
+    - ALSA: pcm: disallow linking stream to itself
+    - x86/speculation: Change misspelled STIPB to STIBP
+    - x86/speculation: Add support for STIBP always-on preferred mode
+    - x86/speculation: Avoid force-disabling IBPB based on STIBP and enhanced
+      IBRS.
+    - x86/speculation: PR_SPEC_FORCE_DISABLE enforcement for indirect branches.
+    - spi: dw: fix possible race condition
+    - spi: dw: Fix controller unregister order
+    - spi: No need to assign dummy value in spi_unregister_controller()
+    - spi: Fix controller unregister order
+    - spi: pxa2xx: Fix controller unregister order
+    - spi: bcm2835: Fix controller unregister order
+    - ovl: initialize error in ovl_copy_xattr
+    - proc: Use new_inode not new_inode_pseudo
+    - video: fbdev: w100fb: Fix a potential double free.
+    - KVM: nSVM: leave ASID aside in copy_vmcb_control_area
+    - KVM: nVMX: Consult only the "basic" exit reason when routing nested exit
+    - KVM: arm64: Make vcpu_cp1x() work on Big Endian hosts
+    - ath9k: Fix use-after-free Read in ath9k_wmi_ctrl_rx
+    - ath9k: Fix use-after-free Write in ath9k_htc_rx_msg
+    - ath9x: Fix stack-out-of-bounds Write in ath9k_hif_usb_rx_cb
+    - ath9k: Fix general protection fault in ath9k_hif_usb_rx_cb
+    - Smack: slab-out-of-bounds in vsscanf
+    - mm/slub: fix a memory leak in sysfs_slab_add()
+    - fat: don't allow to mount if the FAT length == 0
+    - can: kvaser_usb: kvaser_usb_leaf: Fix some info-leaks to USB devices
+    - spi: dw: Zero DMA Tx and Rx configurations on stack
+    - Bluetooth: Add SCO fallback for invalid LMP parameters error
+    - kgdb: Prevent infinite recursive entries to the debugger
+    - spi: dw: Enable interrupts in accordance with DMA xfer mode
+    - clocksource: dw_apb_timer_of: Fix missing clockevent timers
+    - btrfs: do not ignore error from btrfs_next_leaf() when inserting checksums
+    - ARM: 8978/1: mm: make act_mm() respect THREAD_SIZE
+    - net: vmxnet3: fix possible buffer overflow caused by bad DMA value in
+      vmxnet3_get_rss()
+    - staging: android: ion: use vmap instead of vm_map_ram
+    - e1000: Distribute switch variables for initialization
+    - media: dvb: return -EREMOTEIO on i2c transfer failure.
+    - MIPS: Make sparse_init() using top-down allocation
+    - netfilter: nft_nat: return EOPNOTSUPP if type or flags are not supported
+    - lib/mpi: Fix 64-bit MIPS build with Clang
+    - net: lpc-enet: fix error return code in lpc_mii_init()
+    - net: allwinner: Fix use correct return type for ndo_start_xmit()
+    - powerpc/spufs: fix copy_to_user while atomic
+    - mips: cm: Fix an invalid error code of INTVN_*_ERR
+    - kgdb: Fix spurious true from in_dbg_master()
+    - md: don't flush workqueue unconditionally in md_open
+    - mwifiex: Fix memory corruption in dump_station
+    - mips: Add udelay lpj numbers adjustment
+    - x86/mm: Stop printing BRK addresses
+    - m68k: mac: Don't call via_flush_cache() on Mac IIfx
+    - macvlan: Skip loopback packets in RX handler
+    - PCI: Don't disable decoding when mmio_always_on is set
+    - MIPS: Fix IRQ tracing when call handle_fpe() and handle_msa_fpe()
+    - ixgbe: fix signed-integer-overflow warning
+    - spi: dw: Return any value retrieved from the dma_transfer callback
+    - cpuidle: Fix three reference count leaks
+    - ima: Fix ima digest hash table key calculation
+    - ext4: fix EXT_MAX_EXTENT/INDEX to check for zeroed eh_max
+    - Btrfs: fix unreplayable log after snapshot delete + parent dir fsync
+    - btrfs: send: emit file capabilities after chown
+    - btrfs: fix error handling when submitting direct I/O bio
+    - ima: Directly assign the ima_default_policy pointer to ima_rules
+    - PCI: Program MPS for RCiEP devices
+    - e1000e: Relax condition to trigger reset for ME workaround
+    - carl9170: remove P2P_GO support
+    - media: go7007: fix a miss of snd_card_free
+    - b43legacy: Fix case where channel status is corrupted
+    - b43: Fix connection problem with WPA3
+    - b43_legacy: Fix connection problem with WPA3
+    - igb: Report speed and duplex as unknown when device is runtime suspended
+    - power: vexpress: add suppress_bind_attrs to true
+    - pinctrl: samsung: Save/restore eint_mask over suspend for EINT_TYPE GPIOs
+    - sparc32: fix register window handling in genregs32_[gs]et()
+    - kernel/cpu_pm: Fix uninitted local in cpu_pm
+    - ARM: tegra: Correct PL310 Auxiliary Control Register initialization
+    - drivers/macintosh: Fix memleak in windfarm_pm112 driver
+    - kbuild: force to build vmlinux if CONFIG_MODVERSION=y
+    - sunrpc: svcauth_gss_register_pseudoflavor must reject duplicate
+      registrations.
+    - sunrpc: clean up properly in gss_mech_unregister()
+    - w1: omap-hdq: cleanup to add missing newline for some dev_dbg
+    - perf probe: Do not show the skipped events
+    - perf symbols: Fix debuginfo search for Ubuntu
+    - Linux 4.4.228
+
+  * Update lockdown patches (LP: #1884159)
+    - acpi: Disable ACPI table override if the kernel is locked down
+    - SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the testmmiotrace module
+    - Revert "Restrict /dev/mem and /dev/kmem when module loading is restricted"
+    - Revert "x86: Lock down IO port access when module security is enabled"
+    - SAUCE: (efi-lockdown) Restrict /dev/{mem, kmem, port} when the kernel is
+      locked down
+    - Annotate module params that specify hardware parameters (eg. ioport)
+    - Annotate hardware config module parameters in arch/x86/mm/
+    - Annotate hardware config module parameters in drivers/char/ipmi/
+    - Annotate hardware config module parameters in drivers/char/mwave/
+    - Annotate hardware config module parameters in drivers/char/
+    - Annotate hardware config module parameters in drivers/clocksource/
+    - Annotate hardware config module parameters in drivers/cpufreq/
+    - Annotate hardware config module parameters in drivers/gpio/
+    - Annotate hardware config module parameters in drivers/i2c/
+    - Annotate hardware config module parameters in drivers/input/
+    - Annotate hardware config module parameters in drivers/isdn/
+    - Annotate hardware config module parameters in drivers/media/
+    - Annotate hardware config module parameters in drivers/misc/
+    - Annotate hardware config module parameters in drivers/mmc/host/
+    - Annotate hardware config module parameters in drivers/net/appletalk/
+    - Annotate hardware config module parameters in drivers/net/arcnet/
+    - Annotate hardware config module parameters in drivers/net/can/
+    - Annotate hardware config module parameters in drivers/net/ethernet/
+    - Annotate hardware config module parameters in drivers/net/hamradio/
+    - Annotate hardware config module parameters in drivers/net/irda/
+    - Annotate hardware config module parameters in drivers/net/wan/
+    - Annotate hardware config module parameters in drivers/net/wireless/
+    - Annotate hardware config module parameters in drivers/parport/
+    - Annotate hardware config module parameters in drivers/pci/hotplug/
+    - Annotate hardware config module parameters in drivers/pcmcia/
+    - Annotate hardware config module parameters in drivers/scsi/
+    - Annotate hardware config module parameters in drivers/staging/media/
+    - Annotate hardware config module parameters in drivers/staging/speakup/
+    - Annotate hardware config module parameters in drivers/staging/vme/
+    - Annotate hardware config module parameters in drivers/tty/
+    - Annotate hardware config module parameters in drivers/video/
+    - Annotate hardware config module parameters in drivers/watchdog/
+    - Annotate hardware config module parameters in fs/pstore/
+    - Annotate hardware config module parameters in sound/drivers/
+    - Annotate hardware config module parameters in sound/isa/
+    - Annotate hardware config module parameters in sound/oss/
+    - Annotate hardware config module parameters in sound/pci/
+    - SAUCE: (efi-lockdown) Lock down module params that specify hardware
+      parameters (eg. ioport)
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) kexec_file: Disable at runtime if the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - efi/efi_test: Lock down /dev/efi_test and require CAP_SYS_ADMIN
+    - debugfs: prevent access to possibly dead file_operations at file open
+    - debugfs: prevent access to removed files' private data
+    - debugfs: add support for self-protecting attribute file fops
+    - debugfs: unproxify integer attribute files
+    - debugfs: unproxify files created through debugfs_create_bool()
+    - debugfs: unproxify files created through debugfs_create_blob()
+    - debugfs: unproxify files created through debugfs_create_u32_array()
+    - debugfs: full_proxy_open(): free proxy on ->open() failure
+    - debugfs: open_proxy_open(): avoid double fops release
+    - SAUCE: (efi-lockdown) debugfs: Disallow use of debugfs files when the kernel
+      is locked down
+
+  * Xenial update: v4.4.227 upstream stable release (LP: #1883918)
+    - scsi: scsi_devinfo: fixup string compare
+    - usb: gadget: f_uac2: fix error handling in afunc_bind (again)
+    - platform/x86: acer-wmi: setup accelerometer when ACPI device was found
+    - esp6: fix memleak on error path in esp6_input
+    - IB/mlx4: Fix an error handling path in 'mlx4_ib_rereg_user_mr()'
+    - ALSA: hda - No loopback on ALC299 codec
+    - spi: dw: use "smp_mb()" to avoid sending spi data error
+    - s390/ftrace: save traced function caller
+    - ARC: Fix ICCM & DCCM runtime size checks
+    - x86/mmiotrace: Use cpumask_available() for cpumask_var_t variables
+    - net: bmac: Fix read of MAC address from ROM
+    - net/ethernet/freescale: rework quiesce/activate for ucc_geth
+    - net: ethernet: stmmac: Enable interface clocks on probe for IPQ806x
+    - pppoe: only process PADT targeted at local interfaces
+    - mmc: fix compilation of user API
+    - slcan: Fix double-free on slcan_open() error path
+    - slip: not call free_netdev before rtnl_unlock in slip_open
+    - scsi: ufs: Release clock if DMA map fails
+    - devinet: fix memleak in inetdev_init()
+    - NFC: st21nfca: add missed kfree_skb() in an error path
+    - vsock: fix timeout in vsock_accept()
+    - l2tp: add sk_family checks to l2tp_validate_socket
+    - l2tp: do not use inet_hash()/inet_unhash()
+    - USB: serial: qcserial: add DW5816e QDL support
+    - USB: serial: usb_wwan: do not resubmit rx urb on fatal errors
+    - USB: serial: option: add Telit LE910C1-EUX compositions
+    - vt: keyboard: avoid signed integer overflow in k_ascii
+    - staging: rtl8712: Fix IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK
+    - x86/cpu: Rename cpu_data.x86_mask to cpu_data.x86_stepping
+    - x86/speculation: Add SRBDS vulnerability and mitigation documentation
+    - x86/speculation: Add Ivy Bridge to affected list
+    - iio: vcnl4000: Fix i2c swapped word reading.
+    - uprobes: ensure that uprobe->offset and ->ref_ctr_offset are properly
+      aligned
+    - Linux 4.4.227
+
+  * Xenial update: v4.4.226 upstream stable release (LP: #1883917)
+    - ax25: fix setsockopt(SO_BINDTODEVICE)
+    - net: revert "net: get rid of an signed integer overflow in
+      ip_idents_reserve()"
+    - sctp: Start shutdown on association restart if in SHUTDOWN-SENT state and
+      socket is closed
+    - net/mlx5: Add command entry handling completion
+    - net: sun: fix missing release regions in cas_init_one().
+    - net/mlx4_core: fix a memory leak bug.
+    - uapi: fix linux/if_pppol2tp.h userspace compilation errors
+    - IB/cma: Fix reference count leak when no ipv4 addresses are set
+    - cachefiles: Fix race between read_waiter and read_copier involving op->to_do
+    - usb: gadget: legacy: fix redundant initialization warnings
+    - cifs: Fix null pointer check in cifs_read
+    - Input: usbtouchscreen - add support for BonXeon TP
+    - Input: evdev - call input_flush_device() on release(), not flush()
+    - Input: xpad - add custom init packet for Xbox One S controllers
+    - Input: i8042 - add ThinkPad S230u to i8042 reset list
+    - IB/qib: Call kobject_put() when kobject_init_and_add() fails
+    - ALSA: hwdep: fix a left shifting 1 by 31 UB bug
+    - ALSA: usb-audio: mixer: volume quirk for ESS Technology Asus USB DAC
+    - exec: Always set cap_ambient in cap_bprm_set_creds
+    - fs/binfmt_elf.c: allocate initialized memory in fill_thread_core_info()
+    - include/asm-generic/topology.h: guard cpumask_of_node() macro argument
+    - iommu: Fix reference count leak in iommu_group_alloc.
+    - parisc: Fix kernel panic in mem_init()
+    - x86/dma: Fix max PFN arithmetic overflow on 32 bit systems
+    - xfrm: allow to accept packets with ipv6 NEXTHDR_HOP in xfrm_input
+    - xfrm: fix a warning in xfrm_policy_insert_list
+    - xfrm: fix a NULL-ptr deref in xfrm_local_error
+    - vti4: eliminated some duplicate code.
+    - ip_vti: receive ipip packet by calling ip_tunnel_rcv
+    - netfilter: nft_reject_bridge: enable reject with bridge vlan
+    - netfilter: ipset: Fix subcounter update skip
+    - netfilter: nf_conntrack_pptp: prevent buffer overflows in debug code
+    - qlcnic: fix missing release in qlcnic_83xx_interrupt_test.
+    - bonding: Fix reference count leak in bond_sysfs_slave_add.
+    - netfilter: nf_conntrack_pptp: fix compilation warning with W=1 build
+    - mm: remove VM_BUG_ON(PageSlab()) from page_mapcount()
+    - genirq/generic_pending: Do not lose pending affinity update
+    - usb: renesas_usbhs: gadget: fix spin_lock_init() for &uep->lock
+    - mac80211: fix memory leak
+    - net: rtnl_configure_link: fix dev flags changes arg to __dev_notify_flags
+    - mm/vmalloc.c: don't dereference possible NULL pointer in __vunmap()
+    - asm-prototypes: Clear any CPP defines before declaring the functions
+    - sc16is7xx: move label 'err_spi' to correct section
+    - drm/msm: Fix possible null dereference on failure of get_pages()
+    - printk: help pr_debug and pr_devel to optimize out arguments
+    - scsi: zfcp: fix request object use-after-free in send path causing wrong
+      traces
+    - Linux 4.4.226
+
+  * Xenial update: v4.4.225 upstream stable release (LP: #1883916)
+    - igb: use igb_adapter->io_addr instead of e1000_hw->hw_addr
+    - padata: Remove unused but set variables
+    - padata: get_next is never NULL
+    - padata: ensure the reorder timer callback runs on the correct CPU
+    - padata: ensure padata_do_serial() runs on the correct CPU
+    - evm: Check also if *tfm is an error pointer in init_desc()
+    - fix multiplication overflow in copy_fdtable()
+    - HID: multitouch: add eGalaxTouch P80H84 support
+    - ceph: fix double unlock in handle_cap_export()
+    - USB: core: Fix misleading driver bug report
+    - platform/x86: asus-nb-wmi: Do not load on Asus T100TA and T200TA
+    - ARM: futex: Address build warning
+    - media: Fix media_open() to clear filp->private_data in error leg
+    - drivers/media/media-devnode: clear private_data before put_device()
+    - media-devnode: add missing mutex lock in error handler
+    - media-devnode: fix namespace mess
+    - media-device: dynamically allocate struct media_devnode
+    - media: fix use-after-free in cdev_put() when app exits after driver unbind
+    - media: fix media devnode ioctl/syscall and unregister race
+    - i2c: dev: switch from register_chrdev to cdev API
+    - i2c: dev: don't start function name with 'return'
+    - i2c: dev: use after free in detach
+    - i2c-dev: don't get i2c adapter via i2c_dev
+    - i2c: dev: Fix the race between the release of i2c_dev and cdev
+    - padata: set cpu_index of unused CPUs to -1
+    - sched/fair, cpumask: Export for_each_cpu_wrap()
+    - padata: Replace delayed timer with immediate workqueue in padata_reorder
+    - padata: initialize pd->cpu with effective cpumask
+    - padata: purge get_cpu and reorder_via_wq from padata_do_serial
+    - ALSA: pcm: fix incorrect hw_base increase
+    - platform/x86: alienware-wmi: fix kfree on potentially uninitialized pointer
+    - libnvdimm/btt: Remove unnecessary code in btt_freelist_init
+    - l2tp: lock socket before checking flags in connect()
+    - l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
+    - l2tp: hold session while sending creation notifications
+    - l2tp: take a reference on sessions used in genetlink handlers
+    - l2tp: don't use l2tp_tunnel_find() in l2tp_ip and l2tp_ip6
+    - net: l2tp: export debug flags to UAPI
+    - net: l2tp: deprecate PPPOL2TP_MSG_* in favour of L2TP_MSG_*
+    - net: l2tp: ppp: change PPPOL2TP_MSG_* => L2TP_MSG_*
+    - New kernel function to get IP overhead on a socket.
+    - L2TP:Adjust intf MTU, add underlay L3, L2 hdrs.
+    - l2tp: remove useless duplicate session detection in l2tp_netlink
+    - l2tp: remove l2tp_session_find()
+    - l2tp: define parameters of l2tp_session_get*() as "const"
+    - l2tp: define parameters of l2tp_tunnel_find*() as "const"
+    - l2tp: initialise session's refcount before making it reachable
+    - l2tp: hold tunnel while looking up sessions in l2tp_netlink
+    - l2tp: hold tunnel while processing genl delete command
+    - l2tp: hold tunnel while handling genl tunnel updates
+    - l2tp: hold tunnel while handling genl TUNNEL_GET commands
+    - l2tp: hold tunnel used while creating sessions with netlink
+    - l2tp: prevent creation of sessions on terminated tunnels
+    - l2tp: fix l2tp_eth module loading
+    - l2tp: don't register sessions in l2tp_session_create()
+    - l2tp: initialise l2tp_eth sessions before registering them
+    - l2tp: protect sock pointer of struct pppol2tp_session with RCU
+    - l2tp: initialise PPP sessions before registering them
+    - Revert "gfs2: Don't demote a glock until its revokes are written"
+    - staging: iio: ad2s1210: Fix SPI reading
+    - mei: release me_cl object reference
+    - iio: sca3000: Remove an erroneous 'get_device()'
+    - l2tp: device MTU setup, tunnel socket needs a lock
+    - cpumask: Make for_each_cpu_wrap() available on UP as well
+    - Linux 4.4.225
+
+  * smpboot: don't call topology_sane() when Sub-NUMA-Clustering is enabled
+    (LP: #1882478)
+    - x86, sched: Allow topologies where NUMA nodes share an LLC
+
+  * CVE-2020-11935
+    - SAUCE: aufs: do not call i_readcount_inc()
+    - SAUCE: aufs: bugfix, IMA i_readcount
+
+  * CVE-2019-12380
+    - efi/x86/Add missing error handling to old_memmap 1:1 mapping code
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 01 Jul 2020 00:39:42 -0400
+
+linux (4.4.0-185.215) xenial; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * CVE-2020-0543
+    - UBUNTU/SAUCE: x86/speculation/srbds: do not try to turn mitigation off when
+      not supported
+
+  * Xenial update: 4.4.224 upstream stable release (LP: #1881356)
+    - USB: serial: qcserial: Add DW5816e support
+    - Revert "net: phy: Avoid polling PHY with PHY_IGNORE_INTERRUPTS"
+    - dp83640: reverse arguments to list_add_tail
+    - net/mlx4_core: Fix use of ENOSPC around mlx4_counter_alloc()
+    - sch_sfq: validate silly quantum values
+    - sch_choke: avoid potential panic in choke_reset()
+    - enic: do not overwrite error code
+    - ipv6: fix cleanup ordering for ip6_mr failure
+    - binfmt_elf: move brk out of mmap when doing direct loader exec
+    - x86/apm: Don't access __preempt_count with zeroed fs
+    - Revert "IB/ipoib: Update broadcast object if PKey value was changed in index
+      0"
+    - USB: uas: add quirk for LaCie 2Big Quadra
+    - USB: serial: garmin_gps: add sanity checking for data length
+    - batman-adv: fix batadv_nc_random_weight_tq
+    - scripts/decodecode: fix trapping instruction formatting
+    - phy: micrel: Ensure interrupts are reenabled on resume
+    - binfmt_elf: Do not move brk for INTERP-less ET_EXEC
+    - ext4: add cond_resched() to ext4_protect_reserved_inode
+    - blktrace: Fix potential deadlock between delete & sysfs ops
+    - blktrace: fix unlocked access to init/start-stop/teardown
+    - blktrace: fix trace mutex deadlock
+    - ptp: do not explicitly set drvdata in ptp_clock_register()
+    - ptp: use is_visible method to hide unused attributes
+    - ptp: create "pins" together with the rest of attributes
+    - chardev: add helper function to register char devs with a struct device
+    - ptp: Fix pass zero to ERR_PTR() in ptp_clock_register
+    - ptp: fix the race between the release of ptp_clock and cdev
+    - ptp: free ptp device pin descriptors properly
+    - net: handle no dst on skb in icmp6_send
+    - net/sonic: Fix a resource leak in an error handling path in
+      'jazz_sonic_probe()'
+    - net: moxa: Fix a potential double 'free_irq()'
+    - drop_monitor: work around gcc-10 stringop-overflow warning
+    - scsi: sg: add sg_remove_request in sg_write
+    - cifs: Check for timeout on Negotiate stage
+    - cifs: Fix a race condition with cifs_echo_request
+    - dmaengine: pch_dma.c: Avoid data race between probe and irq handler
+    - dmaengine: mmp_tdma: Reset channel error on release
+    - drm/qxl: lost qxl_bo_kunmap_atomic_page in qxl_image_init_helper()
+    - ipc/util.c: sysvipc_find_ipc() incorrectly updates position index
+    - net: openvswitch: fix csum updates for MPLS actions
+    - gre: do not keep the GRE header around in collect medata mode
+    - mm/memory_hotplug.c: fix overflow in test_pages_in_a_zone()
+    - scsi: qla2xxx: Avoid double completion of abort command
+    - i40e: avoid NVM acquire deadlock during NVM update
+    - net/mlx5: Fix driver load error flow when firmware is stuck
+    - netfilter: conntrack: avoid gcc-10 zero-length-bounds warning
+    - IB/mlx4: Test return value of calls to ib_get_cached_pkey
+    - pnp: Use list_for_each_entry() instead of open coding
+    - gcc-10 warnings: fix low-hanging fruit
+    - kbuild: compute false-positive -Wmaybe-uninitialized cases in Kconfig
+    - Stop the ad-hoc games with -Wno-maybe-initialized
+    - gcc-10: disable 'zero-length-bounds' warning for now
+    - gcc-10: disable 'array-bounds' warning for now
+    - gcc-10: disable 'stringop-overflow' warning for now
+    - gcc-10: disable 'restrict' warning for now
+    - blk-mq: sync the update nr_hw_queues with blk_mq_queue_tag_busy_iter
+    - blk-mq: Allow blocking queue tag iter callbacks
+    - x86/paravirt: Remove the unused irq_enable_sysexit pv op
+    - gcc-10: avoid shadowing standard library 'free()' in crypto
+    - net: fix a potential recursive NETDEV_FEAT_CHANGE
+    - net: ipv4: really enforce backoff for redirects
+    - ALSA: hda/realtek - Limit int mic boost for Thinkpad T530
+    - ALSA: rawmidi: Fix racy buffer resize under concurrent accesses
+    - ALSA: rawmidi: Initialize allocated buffers
+    - ARM: dts: imx27-phytec-phycard-s-rdk: Fix the I2C1 pinctrl entries
+    - x86: Fix early boot crash on gcc-10, third try
+    - exec: Move would_dump into flush_old_exec
+    - usb: gadget: net2272: Fix a memory leak in an error handling path in
+      'net2272_plat_probe()'
+    - usb: gadget: audio: Fix a missing error return value in audio_bind()
+    - usb: gadget: legacy: fix error return code in gncm_bind()
+    - usb: gadget: legacy: fix error return code in cdc_bind()
+    - ARM: dts: r8a7740: Add missing extal2 to CPG node
+    - KVM: x86: Fix off-by-one error in kvm_vcpu_ioctl_x86_setup_mce
+    - Makefile: disallow data races on gcc-10 as well
+    - scsi: iscsi: Fix a potential deadlock in the timeout handler
+    - Linux 4.4.224
+
+  * upgrading to 4.15.0-99-generic breaks the sound and the trackpad
+    (LP: #1875916) // Xenial update: 4.4.224 upstream stable release
+    (LP: #1881356)
+    - Revert "ALSA: hda/realtek: Fix pop noise on ALC225"
+
+  * CVE-2020-10711
+    - netlabel: cope with NULL catmap
+
+  * CVE-2020-13143
+    - USB: gadget: fix illegal array access in binding with UDC
+
+  * ext2 build failure on 4.4.0-180.210 (LP: #1880213)
+    - ext2: fix debug reference to ext2_xattr_cache
+
+  * test_bpf of ubuntu_kernel_selftests.net ADT test failure with linux
+    4.4.0-180.210 (LP: #1879752)
+    - bpf, test: fix ld_abs + vlan push/pop stress test
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Mon, 08 Jun 2020 14:45:12 -0300
+
+linux (4.4.0-184.214) xenial; urgency=medium
+
+  * CVE-2020-0543
+    - SAUCE: x86/cpu: Add a steppings field to struct x86_cpu_id
+    - SAUCE: x86/cpu: Add 'table' argument to cpu_matches()
+    - SAUCE: x86/speculation: Add Special Register Buffer Data Sampling (SRBDS)
+      mitigation
+    - SAUCE: x86/speculation: Add SRBDS vulnerability and mitigation documentation
+    - SAUCE: x86/speculation: Add Ivy Bridge to affected list
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 03 Jun 2020 12:51:31 +0200
+
+linux (4.4.0-181.211) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-181.211 -proposed tracker (LP: #1881170)
+
+  * CVE-2020-12769
+    - spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls
+
+  * I2C bus on Dell Edge Gateway stops working after upgrading to
+    Ubuntu-4.4.0-180.210 (LP: #1881124)
+    - SAUCE: Revert: Revert "ACPI / LPSS: allow to use specific PM domain during
+      ->probe()"
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Fri, 29 May 2020 02:56:23 -0400
+
+linux (4.4.0-180.210) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-180.210 -proposed tracker (LP: #1878873)
+
+  * Xenial update: 4.4.223 upstream stable release (LP: #1878232)
+    - mwifiex: fix PCIe register information for 8997 chipset
+    - drm/qxl: qxl_release use after free
+    - drm/qxl: qxl_release leak in qxl_draw_dirty_fb()
+    - staging: rtl8192u: Fix crash due to pointers being "confusing"
+    - usb: gadget: f_acm: Fix configfs attr name
+    - usb: gadged: pch_udc: get rid of redundant assignments
+    - usb: gadget: pch_udc: reorder spin_[un]lock to avoid deadlock
+    - usb: gadget: udc: core: don't starve DMA resources
+    - MIPS: Fix macro typo
+    - MIPS: ptrace: Drop cp0_tcstatus from regoffset_table[]
+    - MIPS: BMIPS: Fix PRID_IMP_BMIPS5000 masking for BMIPS5200
+    - MIPS: smp-cps: Stop printing EJTAG exceptions to UART
+    - MIPS: scall: Handle seccomp filters which redirect syscalls
+    - MIPS: BMIPS: BMIPS5000 has I cache filing from D cache
+    - MIPS: BMIPS: Clear MIPS_CACHE_ALIASES earlier
+    - MIPS: BMIPS: local_r4k___flush_cache_all needs to blast S-cache
+    - MIPS: BMIPS: Pretty print BMIPS5200 processor name
+    - MIPS: Fix HTW config on XPA kernel without LPA enabled
+    - MIPS: BMIPS: Adjust mips-hpt-frequency for BCM7435
+    - MIPS: math-emu: Fix BC1{EQ,NE}Z emulation
+    - MIPS: Fix BC1{EQ,NE}Z return offset calculation
+    - MIPS: perf: Fix I6400 event numbers
+    - MIPS: KVM: Fix translation of MFC0 ErrCtl
+    - MIPS: SMP: Update cpu_foreign_map on CPU disable
+    - MIPS: c-r4k: Fix protected_writeback_scache_line for EVA
+    - MIPS: Octeon: Off by one in octeon_irq_gpio_map()
+    - bpf, mips: fix off-by-one in ctx offset allocation
+    - MIPS: RM7000: Double locking bug in rm7k_tc_disable()
+    - MIPS: Define AT_VECTOR_SIZE_ARCH for ARCH_DLINFO
+    - mips/panic: replace smp_send_stop() with kdump friendly version in panic
+      path
+    - ARM: dts: armadillo800eva Correct extal1 frequency to 24 MHz
+    - ARM: imx: select SRC for i.MX7
+    - ARM: dts: kirkwood: gpio pin fixes for linkstation ls-wxl/wsxl
+    - ARM: dts: kirkwood: gpio pin fixes for linkstation ls-wvl/vl
+    - ARM: dts: kirkwood: gpio-leds fixes for linkstation ls-wxl/wsxl
+    - ARM: dts: kirkwood: gpio-leds fixes for linkstation ls-wvl/vl
+    - ARM: dts: orion5x: gpio pin fixes for linkstation lswtgl
+    - ARM: dts: orion5x: fix the missing mtd flash on linkstation lswtgl
+    - ARM: dts: kirkwood: use unique machine name for ds112
+    - ARM: dts: kirkwood: add kirkwood-ds112.dtb to Makefile
+    - ARM: OMAP2+: hwmod: fix _idle() hwmod state sanity check sequence
+    - perf/x86: Fix filter_events() bug with event mappings
+    - x86/LDT: Print the real LDT base address
+    - x86/apic/uv: Silence a shift wrapping warning
+    - ALSA: fm801: explicitly free IRQ line
+    - ALSA: fm801: propagate TUNER_ONLY bit when autodetected
+    - ALSA: fm801: detect FM-only card earlier
+    - netfilter: nfnetlink: use original skbuff when acking batches
+    - xfrm: fix crash in XFRM_MSG_GETSA netlink handler
+    - mwifiex: fix IBSS data path issue.
+    - mwifiex: add missing check for PCIe8997 chipset
+    - iwlwifi: set max firmware version of 7265 to 17
+    - Bluetooth: btmrvl: fix hung task warning dump
+    - dccp: limit sk_filter trim to payload
+    - net/mlx4_core: Do not BUG_ON during reset when PCI is offline
+    - mlxsw: pci: Correctly determine if descriptor queue is full
+    - PCI: Supply CPU physical address (not bus address) to iomem_is_exclusive()
+    - alpha/PCI: Call iomem_is_exclusive() for IORESOURCE_MEM, but not
+      IORESOURCE_IO
+    - vfio/pci: Allow VPD short read
+    - mlxsw: Treat local port 64 as valid
+    - IB/mlx4: Initialize hop_limit when creating address handle
+    - GRE: Disable segmentation offloads w/ CSUM and we are encapsulated via FOU
+    - powerpc/pci/of: Parse unassigned resources
+    - firmware: actually return NULL on failed request_firmware_nowait()
+    - c8sectpfe: Rework firmware loading mechanism
+    - net/mlx5: Avoid passing dma address 0 to firmware
+    - IB/mlx5: Fix RC transport send queue overhead computation
+    - net/mlx5: Make command timeout way shorter
+    - IB/mlx5: Fix FW version diaplay in sysfs
+    - net/mlx5e: Fix MLX5E_100BASE_T define
+    - net/mlx5: Fix the size of modify QP mailbox
+    - net/mlx5: Fix masking of reserved bits in XRCD number
+    - net/mlx5e: Fix blue flame quota logic
+    - net/mlx5: use mlx5_buf_alloc_node instead of mlx5_buf_alloc in
+      mlx5_wq_ll_create
+    - net/mlx5: Avoid calling sleeping function by the health poll thread
+    - net/mlx5: Fix wait_vital for VFs and remove fixed sleep
+    - net/mlx5: Fix potential deadlock in command mode change
+    - net/mlx5: Add timeout handle to commands with callback
+    - net/mlx5: Fix pci error recovery flow
+    - net/mlx5e: Copy all L2 headers into inline segment
+    - net_sched: keep backlog updated with qlen
+    - sch_drr: update backlog as well
+    - sch_hfsc: always keep backlog updated
+    - sch_prio: update backlog as well
+    - sch_qfq: keep backlog updated with qlen
+    - sch_sfb: keep backlog updated with qlen
+    - sch_tbf: update backlog as well
+    - btrfs: cleaner_kthread() doesn't need explicit freeze
+    - irda: Free skb on irda_accept error path.
+    - phy: fix device reference leaks
+    - bonding: prevent out of bound accesses
+    - mtd: nand: fix ONFI parameter page layout
+    - ath10k: free cached fw bin contents when get board id fails
+    - xprtrdma: checking for NULL instead of IS_ERR()
+    - xprtrdma: Fix additional uses of spin_lock_irqsave(rb_lock)
+    - xprtrdma: xprt_rdma_free() must not release backchannel reqs
+    - xprtrdma: rpcrdma_bc_receive_call() should init rq_private_buf.len
+    - RDMA/cxgb3: device driver frees DMA memory with different size
+    - mlxsw: spectrum: Don't forward packets when STP state is DISABLED
+    - mlxsw: spectrum: Disable learning according to STP state
+    - mlxsw: spectrum: Don't count internal TX header bytes to stats
+    - mlxsw: spectrum: Indicate support for autonegotiation
+    - mlxsw: spectrum: Fix misuse of hard_header_len
+    - net: tcp_memcontrol: properly detect ancestor socket pressure
+    - tcp: do not set rtt_min to 1
+    - RDS:TCP: Synchronize rds_tcp_accept_one with rds_send_xmit when resetting
+      t_sock
+    - net: ipv6: tcp reset, icmp need to consider L3 domain
+    - batman-adv: Fix lockdep annotation of batadv_tlv_container_remove
+    - batman-adv: replace WARN with rate limited output on non-existing VLAN
+    - tty: serial: msm: Support more bauds
+    - serial: samsung: Fix possible out of bounds access on non-DT platform
+    - isa: Call isa_bus_init before dependent ISA bus drivers register
+    - Btrfs: clean up an error code in btrfs_init_space_info()
+    - Input: gpio-keys - fix check for disabling unsupported keys
+    - Input: edt-ft5x06 - fix setting gain, offset, and threshold via device tree
+    - net/xfrm_input: fix possible NULL deref of tunnel.ip6->parms.i_key
+    - xfrm_user: propagate sec ctx allocation errors
+    - xfrm: Fix memory leak of aead algorithm name
+    - mac80211: fix mgmt-tx abort cookie and leak
+    - mac80211: TDLS: always downgrade invalid chandefs
+    - mac80211: TDLS: change BW calculation for WIDER_BW peers
+    - mac80211: Fix BW upgrade for TDLS peers
+    - NFS: Fix an LOCK/OPEN race when unlinking an open file
+    - net: get rid of an signed integer overflow in ip_idents_reserve()
+    - mtd: nand: denali: add missing nand_release() call in denali_remove()
+    - ASoC: Intel: pass correct parameter in sst_alloc_stream_mrfld()
+    - ASoC: tegra_alc5632: check return value
+    - ASoC: fsl_ssi: mark SACNT register volatile
+    - Revert "ACPI / LPSS: allow to use specific PM domain during ->probe()"
+    - mmc: sdhci: restore behavior when setting VDD via external regulator
+    - mmc: sd: limit SD card power limit according to cards capabilities
+    - mmc: debugfs: correct wrong voltage value
+    - mmc: block: return error on failed mmc_blk_get()
+    - clk: rockchip: Revert "clk: rockchip: reset init state before mmc card
+      initialization"
+    - mmc: dw_mmc: rockchip: Set the drive phase properly
+    - mmc: moxart: fix wait_for_completion_interruptible_timeout return variable
+      type
+    - mmc: sdhci: Fix regression setting power on Trats2 board
+    - perf tools: Fix perf regs mask generation
+    - powerpc/book3s: Fix MCE console messages for unrecoverable MCE.
+    - sctp: fix the transports round robin issue when init is retransmitted
+    - sunrpc: Update RPCBIND_MAXNETIDLEN
+    - NFC: nci: memory leak in nci_core_conn_create()
+    - net: phy: Avoid polling PHY with PHY_IGNORE_INTERRUPTS
+    - net: phy: Fix phy_mac_interrupt()
+    - net: phy: bcm7xxx: Fix shadow mode 2 disabling
+    - of_mdio: fix node leak in of_phy_register_fixed_link error path
+    - phy: micrel: Fix finding PHY properties in MAC node for KSZ9031.
+    - net: dsa: slave: fix of-node leak and phy priority
+    - drivers: net: cpsw: don't ignore phy-mode if phy-handle is used
+    - iommu/dma: Respect IOMMU aperture when allocating
+    - mdio-sun4i: oops in error handling in probe
+    - iio:ad7797: Use correct attribute_group
+    - selftests/ipc: Fix test failure seen after initial test run
+    - wimax/i2400m: Fix potential urb refcnt leak
+    - cifs: protect updating server->dstaddr with a spinlock
+    - scripts/config: allow colons in option strings for sed
+    - lib/mpi: Fix building for powerpc with clang
+    - net: bcmgenet: suppress warnings on failed Rx SKB allocations
+    - net: systemport: suppress warnings on failed Rx SKB allocations
+    - rc: allow rc modules to be loaded if rc-main is not a module
+    - lirc_imon: do not leave imon_probe() with mutex held
+    - am437x-vpfe: fix an uninitialized variable bug
+    - cx23885: uninitialized variable in cx23885_av_work_handler()
+    - ath9k_htc: check for underflow in ath9k_htc_rx_msg()
+    - VFIO: platform: reset: fix a warning message condition
+    - net: moxa: fix an error code
+    - mfd: lp8788-irq: Uninitialized variable in irq handler
+    - ethernet: micrel: fix some error codes
+    - power: ipaq-micro-battery: freeing the wrong variable
+    - i40e: fix an uninitialized variable bug
+    - qede: uninitialized variable in qede_start_xmit()
+    - qlcnic: potential NULL dereference in qlcnic_83xx_get_minidump_template()
+    - qlcnic: use the correct ring in qlcnic_83xx_process_rcv_ring_diag()
+    - target: Fix a memory leak in target_dev_lba_map_store()
+    - memory/tegra: Add number of TLB lines for Tegra124
+    - pinctrl: bcm2835: Fix memory leak in error path
+    - be2net: Don't leak iomapped memory on removal.
+    - ipv4: Fix memory leak in exception case for splitting tries
+    - flow_dissector: Check for IP fragmentation even if not using IPv4 address
+    - ipv4: fix checksum annotation in udp4_csum_init
+    - ipv4: do not abuse GFP_ATOMIC in inet_netconf_notify_devconf()
+    - ipv4: accept u8 in IP_TOS ancillary data
+    - net: vrf: Fix dev refcnt leak due to IPv6 prefix route
+    - ipv6: fix checksum annotation in udp6_csum_init
+    - ipv6: do not abuse GFP_ATOMIC in inet6_netconf_notify_devconf()
+    - ipv6: add missing netconf notif when 'all' is updated
+    - net: ipv6: Fix processing of RAs in presence of VRF
+    - netfilter: nf_tables: fix a wrong check to skip the inactive rules
+    - netfilter: nft_dynset: fix panic if NFT_SET_HASH is not enabled
+    - netfilter: nf_tables: destroy the set if fail to add transaction
+    - netfilter: nft_dup: do not use sreg_dev if the user doesn't specify it
+    - udp: restore UDPlite many-cast delivery
+    - clk: st: avoid uninitialized variable use
+    - clk: gpio: handle error codes for of_clk_get_parent_count()
+    - clk: ti: omap3+: dpll: use non-locking version of clk_get_rate
+    - clk: multiplier: Prevent the multiplier from under / over flowing
+    - clk: imx: clk-pllv3: fix incorrect handle of enet powerdown bit
+    - clk: xgene: Don't call __pa on ioremaped address
+    - cls_bpf: reset class and reuse major in da
+    - arm64: bpf: jit JMP_JSET_{X,K}
+    - bpf, trace: check event type in bpf_perf_event_read
+    - bpf: fix map not being uncharged during map creation failure
+    - net/mlx4_core: Fix potential corruption in counters database
+    - net/mlx4_core: Fix access to uninitialized index
+    - net/mlx4_en: Fix the return value of a failure in VLAN VID add/kill
+    - net/mlx4_core: Check device state before unregistering it
+    - net/mlx4_core: Fix the resource-type enum in res tracker to conform to FW
+      spec
+    - net/mlx4_en: Process all completions in RX rings after port goes up
+    - net/mlx4_core: Do not access comm channel if it has not yet been initialized
+    - net/mlx4_en: Fix potential deadlock in port statistics flow
+    - net/mlx4: Fix uninitialized fields in rule when adding promiscuous mode to
+      device managed flow steering
+    - net/mlx4_core: Fix QUERY FUNC CAP flags
+    - mlxsw: switchx2: Fix misuse of hard_header_len
+    - mlxsw: switchx2: Fix ethernet port initialization
+    - sched/fair: Fix calc_cfs_shares() fixed point arithmetics width confusion
+    - net_sched: flower: Avoid dissection of unmasked keys
+    - pkt_sched: fq: use proper locking in fq_dump_stats()
+    - sched/preempt: Fix preempt_count manipulations
+    - power: bq27xxx: fix reading for bq27000 and bq27010
+    - power: bq27xxx: fix register numbers of bq27500
+    - power: test_power: correctly handle empty writes
+    - power: bq27xxx_battery: Fix bq27541 AveragePower register address
+    - power_supply: tps65217-charger: Fix NULL deref during property export
+    - net: vrf: Fix dst reference counting
+    - net: Don't delete routes in different VRFs
+    - vti6: fix input path
+    - ipv4: Fix table id reference in fib_sync_down_addr
+    - mlx4: do not call napi_schedule() without care
+    - xprtrdma: Fix backchannel allocation of extra rpcrdma_reps
+    - ALSA: fm801: Initialize chip after IRQ handler is registered
+    - bonding: fix length of actor system
+    - MIPS: perf: Remove incorrect odd/even counter handling for I6400
+    - Revert "cpufreq: Drop rwsem lock around CPUFREQ_GOV_POLICY_EXIT"
+    - net: dsa: mv88e6xxx: unlock DSA and CPU ports
+    - gfs2: fix flock panic issue
+    - blk-mq: fix undefined behaviour in order_to_size()
+    - dm: fix second blk_delay_queue() parameter to be in msec units not jiffies
+    - dmaengine: edma: Add probe callback to edma_tptc_driver
+    - openvswitch: update checksum in {push,pop}_mpls
+    - cxgb4/cxgb4vf: Fixes regression in perf when tx vlan offload is disabled
+    - net: bcmgenet: fix skb_len in bcmgenet_xmit_single()
+    - net: bcmgenet: device stats are unsigned long
+    - gre: do not assign header_ops in collect metadata mode
+    - gre: build header correctly for collect metadata tunnels
+    - gre: reject GUE and FOU in collect metadata mode
+    - sfc: fix potential stack corruption from running past stat bitmask
+    - sfc: clear napi_hash state when copying channels
+    - net: bcmsysport: Device stats are unsigned long
+    - cxgbi: fix uninitialized flowi6
+    - net: macb: add missing free_netdev() on error in macb_probe()
+    - macvtap: segmented packet is consumed
+    - tipc: fix the error handling in tipc_udp_enable()
+    - net: icmp6_send should use dst dev to determine L3 domain
+    - et131x: Fix logical vs bitwise check in et131x_tx_timeout()
+    - net: ethernet: stmmac: dwmac-sti: fix probe error path
+    - rtnl: reset calcit fptr in rtnl_unregister()
+    - net: ethernet: stmmac: dwmac-rk: fix probe error path
+    - fq_codel: return non zero qlen in class dumps
+    - net: ethernet: stmmac: dwmac-generic: fix probe error path
+    - bnxt: add a missing rcu synchronization
+    - qdisc: fix a module refcount leak in qdisc_create_dflt()
+    - net: axienet: Fix return value check in axienet_probe()
+    - bnxt_en: Remove locking around txr->dev_state
+    - net: ethernet: davinci_emac: Fix devioctl while in fixed link
+    - net: ethernet: mvneta: Remove IFF_UNICAST_FLT which is not implemented
+    - net: ethernet: ti: cpsw: fix device and of_node leaks
+    - net: ethernet: ti: cpsw: fix secondary-emac probe error path
+    - net: hns: fix device reference leaks
+    - net: bridge: don't increment tx_dropped in br_do_proxy_arp
+    - net: dsa: mv88e6xxx: enable SA learning on DSA ports
+    - net: ehea: avoid null pointer dereference
+    - l2tp: fix use-after-free during module unload
+    - hwrng: exynos - Disable runtime PM on driver unbind
+    - net: icmp_route_lookup should use rt dev to determine L3 domain
+    - net: mvneta: fix trivial cut-off issue in mvneta_ethtool_update_stats
+    - net: macb: replace macb_writel() call by queue_writel() to update queue ISR
+    - ravb: Add missing free_irq() call to ravb_close()
+    - mvpp2: use correct size for memset
+    - net: vxlan: lwt: Fix vxlan local traffic.
+    - net: ethoc: Fix early error paths
+    - net: mv643xx_eth: fix packet corruption with TSO and tiny unaligned packets.
+    - regulator: core: Rely on regulator_dev_release to free constraints
+    - net: dsa: mv88e6xxx: fix port VLAN maps
+    - at803x: fix reset handling
+    - cxl: Fix DAR check & use REGION_ID instead of opencoding
+    - net: ethernet: davinci_emac: Fix platform_data overwrite
+    - ata: sata_dwc_460ex: remove incorrect locking
+    - pinctrl: tegra: Correctly check the supported configuration
+    - brcmfmac: add fallback for devices that do not report per-chain values
+    - brcmfmac: restore stopping netdev queue when bus clogs up
+    - bridge: Fix problems around fdb entries pointing to the bridge device
+    - bna: add missing per queue ethtool stat
+    - net: skbuff: Remove errornous length validation in skb_vlan_pop()
+    - net: ep93xx_eth: Do not crash unloading module
+    - macvlan: Fix potential use-after free for broadcasts
+    - sctp: Fix SHUTDOWN CTSN Ack in the peer restart case
+    - ALSA: hda: Match both PCI ID and SSID for driver blacklist
+    - mac80211: add ieee80211_is_any_nullfunc()
+    - Linux 4.4.223
+
+  * Xenial update: 4.4.222 upstream stable release (LP: #1878246)
+    - ext4: fix special inode number checks in __ext4_iget()
+    - drm/qxl: qxl_release leak in qxl_hw_surface_alloc()
+    - ALSA: pcm: oss: Place the plugin buffer overflow checks correctly
+    - PM: ACPI: Output correct message on target power state
+    - RDMA/mlx4: Initialize ib_spec on the stack
+    - vfio/type1: Fix VA->PA translation for PFNMAP VMAs in vaddr_get_pfn()
+    - ALSA: opti9xx: shut up gcc-10 range warning
+    - nfs: Fix potential posix_acl refcnt leak in nfs3_set_acl
+    - dmaengine: dmatest: Fix iteration non-stop logic
+    - i2c: designware-pci: use IRQF_COND_SUSPEND flag
+    - perf hists: Fix HISTC_MEM_DCACHELINE width setting
+    - powerpc/perf: Remove PPMU_HAS_SSLOT flag for Power8
+    - perf/x86: Fix uninitialized value usage
+    - exynos4-is: fix a format string bug
+    - ASoC: wm8960: Fix WM8960_SYSCLK_PLL mode
+    - ASoC: imx-spdif: Fix crash on suspend
+    - ipv6: use READ_ONCE() for inet->hdrincl as in ipv4
+    - selinux: properly handle multiple messages in selinux_netlink_send()
+    - Linux 4.4.222
+
+  * Xenial update: 4.4.221 upstream stable release (LP: #1878098)
+    - ext4: fix extent_status fragmentation for plain files
+    - ALSA: hda - Fix incorrect usage of IS_REACHABLE()
+    - net: ipv4: emulate READ_ONCE() on ->hdrincl bit-field in raw_sendmsg()
+    - net: ipv4: avoid unused variable warning for sysctl
+    - crypto: mxs-dcp - make symbols 'sha1_null_hash' and 'sha256_null_hash'
+      static
+    - vti4: removed duplicate log message.
+    - scsi: lpfc: Fix kasan slab-out-of-bounds error in lpfc_unreg_login
+    - ceph: return ceph_mdsc_do_request() errors from __get_parent()
+    - ceph: don't skip updating wanted caps when cap is stale
+    - pwm: rcar: Fix late Runtime PM enablement
+    - scsi: iscsi: Report unbind session event when the target has been removed
+    - ASoC: Intel: atom: Take the drv->lock mutex before calling
+      sst_send_slot_map()
+    - kernel/gcov/fs.c: gcov_seq_next() should increase position index
+    - ipc/util.c: sysvipc_find_ipc() should increase position index
+    - s390/cio: avoid duplicated 'ADD' uevents
+    - pwm: renesas-tpu: Fix late Runtime PM enablement
+    - pwm: bcm2835: Dynamically allocate base
+    - ipv6: fix restrict IPV6_ADDRFORM operation
+    - macvlan: fix null dereference in macvlan_device_event()
+    - net: netrom: Fix potential nr_neigh refcnt leak in nr_add_node
+    - net/x25: Fix x25_neigh refcnt leak when receiving frame
+    - tcp: cache line align MAX_TCP_HEADER
+    - team: fix hang in team_mode_get()
+    - xfrm: Always set XFRM_TRANSFORMED in xfrm{4,6}_output_finish
+    - ALSA: hda: Remove ASUS ROG Zenith from the blacklist
+    - iio: xilinx-xadc: Fix ADC-B powerdown
+    - iio: xilinx-xadc: Fix clearing interrupt when enabling trigger
+    - iio: xilinx-xadc: Fix sequencer configuration for aux channels in
+      simultaneous mode
+    - fs/namespace.c: fix mountpoint reference counter race
+    - USB: sisusbvga: Change port variable from signed to unsigned
+    - USB: Add USB_QUIRK_DELAY_CTRL_MSG and USB_QUIRK_DELAY_INIT for Corsair K70
+      RGB RAPIDFIRE
+    - drivers: usb: core: Don't disable irqs in usb_sg_wait() during URB submit.
+    - drivers: usb: core: Minimize irq disabling in usb_sg_cancel()
+    - USB: core: Fix free-while-in-use bug in the USB S-Glibrary
+    - USB: hub: Fix handling of connect changes during sleep
+    - ALSA: usx2y: Fix potential NULL dereference
+    - ALSA: usb-audio: Fix usb audio refcnt leak when getting spdif
+    - ALSA: usb-audio: Filter out unsupported sample rates on Focusrite devices
+    - KVM: Check validity of resolved slot when searching memslots
+    - KVM: VMX: Enable machine check support for 32bit targets
+    - tty: hvc: fix buffer overflow during hvc_alloc().
+    - tty: rocket, avoid OOB access
+    - usb-storage: Add unusual_devs entry for JMicron JMS566
+    - audit: check the length of userspace generated audit records
+    - ASoC: dapm: fixup dapm kcontrol widget
+    - ARM: imx: provide v7_cpu_resume() only on ARM_CPU_SUSPEND=y
+    - staging: comedi: dt2815: fix writing hi byte of analog output
+    - staging: comedi: Fix comedi_device refcnt leak in comedi_open
+    - staging: vt6656: Fix drivers TBTT timing counter.
+    - staging: vt6656: Power save stop wake_up_count wrap around.
+    - UAS: no use logging any details in case of ENODEV
+    - UAS: fix deadlock in error handling and PM flushing work
+    - usb: f_fs: Clear OS Extended descriptor counts to zero in ffs_data_reset()
+    - remoteproc: Fix wrong rvring index computation
+    - sctp: use right member as the param of list_for_each_entry
+    - fuse: fix possibly missed wake-up after abort
+    - mtd: cfi: fix deadloop in cfi_cmdset_0002.c do_write_buffer
+    - usb: gadget: udc: bdc: Remove unnecessary NULL checks in bdc_req_complete
+    - net/cxgb4: Check the return from t4_query_params properly
+    - perf/core: fix parent pid/tid in task exit events
+    - bpf, x86: Fix encoding for lower 8-bit registers in BPF_STX BPF_B
+    - scsi: target: fix PR IN / READ FULL STATUS for FC
+    - xen/xenbus: ensure xenbus_map_ring_valloc() returns proper grant status
+    - ext4: convert BUG_ON's to WARN_ON's in mballoc.c
+    - ext4: avoid declaring fs inconsistent due to invalid file handles
+    - ext4: protect journal inode's blocks using block_validity
+    - ext4: don't perform block validity checks on the journal inode
+    - ext4: fix block validity checks for journal inodes using indirect blocks
+    - ext4: unsigned int compared against zero
+    - propagate_one(): mnt_set_mountpoint() needs mount_lock
+    - Linux 4.4.221
+
+  * Xenial update: 4.4.220 upstream stable release (LP: #1875905)
+    - bus: sunxi-rsb: Return correct data when mixing 16-bit and 8-bit reads
+    - net: vxge: fix wrong __VA_ARGS__ usage
+    - qlcnic: Fix bad kzalloc null test
+    - i2c: st: fix missing struct parameter description
+    - irqchip/versatile-fpga: Handle chained IRQs properly
+    - selftests/x86/ptrace_syscall_32: Fix no-vDSO segfault
+    - libata: Remove extra scsi_host_put() in ata_scsi_add_hosts()
+    - gfs2: Don't demote a glock until its revokes are written
+    - x86/boot: Use unsigned comparison for addresses
+    - locking/lockdep: Avoid recursion in lockdep_count_{for,back}ward_deps()
+    - btrfs: remove a BUG_ON() from merge_reloc_roots()
+    - btrfs: track reloc roots based on their commit root bytenr
+    - misc: rtsx: set correct pcr_ops for rts522A
+    - ASoC: fix regwmask
+    - ASoC: dapm: connect virtual mux with default value
+    - ASoC: dpcm: allow start or stop during pause for backend
+    - ASoC: topology: use name_prefix for new kcontrol
+    - usb: gadget: f_fs: Fix use after free issue as part of queue failure
+    - usb: gadget: composite: Inform controller driver of self-powered
+    - ALSA: usb-audio: Add mixer workaround for TRX40 and co
+    - ALSA: hda: Add driver blacklist
+    - ALSA: hda: Fix potential access overflow in beep helper
+    - ALSA: ice1724: Fix invalid access for enumerated ctl items
+    - ALSA: pcm: oss: Fix regression by buffer overflow fix
+    - acpi/x86: ignore unspecified bit positions in the ACPI global lock field
+    - thermal: devfreq_cooling: inline all stubs for CONFIG_DEVFREQ_THERMAL=n
+    - irqchip/versatile-fpga: Apply clear-mask earlier
+    - MIPS: OCTEON: irq: Fix potential NULL pointer dereference
+    - ath9k: Handle txpower changes even when TPC is disabled
+    - signal: Extend exec_id to 64bits
+    - x86/entry/32: Add missing ASM_CLAC to general_protection entry
+    - KVM: x86: Allocate new rmap and large page tracking when moving memslot
+    - crypto: mxs-dcp - fix scatterlist linearization for hash
+    - futex: futex_wake_op, do not fail on invalid op
+    - xen-netfront: Rework the fix for Rx stall during OOM and network stress
+    - ALSA: hda: Initialize power_state field properly
+    - Btrfs: incremental send, fix invalid memory access
+    - IB/ipoib: Fix lockdep issue found on ipoib_ib_dev_heavy_flush
+    - scsi: zfcp: fix missing erp_lock in port recovery trigger for point-to-point
+    - arm64: armv8_deprecated: Fix undef_hook mask for thumb setend
+    - ext4: fix a data race at inode->i_blocks
+    - ocfs2: no need try to truncate file beyond i_size
+    - s390/diag: fix display of diagnose call statistics
+    - Input: i8042 - add Acer Aspire 5738z to nomux list
+    - kmod: make request_module() return an error when autoloading is disabled
+    - hfsplus: fix crash and filesystem corruption when deleting files
+    - powerpc/64/tm: Don't let userspace set regs->trap via sigreturn
+    - Btrfs: fix crash during unmount due to race with delayed inode workers
+    - drm/dp_mst: Fix clearing payload state on topology disable
+    - ipmi: fix hung processes in __get_guid()
+    - powerpc/fsl_booke: Avoid creating duplicate tlb1 entry
+    - misc: echo: Remove unnecessary parentheses and simplify check for zero
+    - mfd: dln2: Fix sanity checking for endpoints
+    - net: ipv4: devinet: Fix crash when add/del multicast IP with autojoin
+    - net: ipv6: do not consider routes via gateways for anycast address check
+    - scsi: ufs: Fix ufshcd_hold() caused scheduling while atomic
+    - jbd2: improve comments about freeing data buffers whose page mapping is NULL
+    - ext4: fix incorrect group count in ext4_fill_super error message
+    - ext4: fix incorrect inodes per group in error message
+    - ASoC: Intel: mrfld: fix incorrect check on p->sink
+    - ASoC: Intel: mrfld: return error codes when an error occurs
+    - ALSA: usb-audio: Don't override ignore_ctl_error value from the map
+    - mac80211_hwsim: Use kstrndup() in place of kasprintf()
+    - ext4: do not zeroout extents beyond i_disksize
+    - dm flakey: check for null arg_name in parse_features()
+    - kvm: x86: Host feature SSBD doesn't imply guest feature SPEC_CTRL_SSBD
+    - x86/mitigations: Clear CPU buffers on the SYSCALL fast path
+    - tracing: Fix the race between registering 'snapshot' event trigger and
+      triggering 'snapshot' operation
+    - scsi: sg: add sg_remove_request in sg_common_write
+    - ALSA: hda: Don't release card at firmware loading error
+    - video: fbdev: sis: Remove unnecessary parentheses and commented code
+    - drm: NULL pointer dereference [null-pointer-deref] (CWE 476) problem
+    - wil6210: increase firmware ready timeout
+    - wil6210: fix temperature debugfs
+    - scsi: ufs: ufs-qcom: remove broken hci version quirk
+    - wil6210: rate limit wil_rx_refill error
+    - rtc: pm8xxx: Fix issue in RTC write path
+    - soc: qcom: smem: Use le32_to_cpu for comparison
+    - of: fix missing kobject init for !SYSFS && OF_DYNAMIC config
+    - of: unittest: kmemleak in of_unittest_platform_populate()
+    - clk: at91: usb: continue if clk_hw_round_rate() return zero
+    - clk: tegra: Fix Tegra PMC clock out parents
+    - NFS: direct.c: Fix memory leak of dreq when nfs_get_lock_context fails
+    - ext4: do not commit super on read-only bdev
+    - percpu_counter: fix a data race at vm_committed_as
+    - compiler.h: fix error in BUILD_BUG_ON() reporting
+    - NFS: Fix memory leaks in nfs_pageio_stop_mirroring()
+    - ext2: fix empty body warnings when -Wextra is used
+    - iommu/amd: Fix the configuration of GCR3 table root pointer
+    - fbdev: potential information leak in do_fb_ioctl()
+    - tty: evh_bytechan: Fix out of bounds accesses
+    - locktorture: Print ratio of acquisitions, not failures
+    - mtd: lpddr: Fix a double free in probe()
+    - mtd: phram: fix a double free issue in error path
+    - x86/CPU: Add native CPUID variants returning a single datum
+    - x86/microcode/intel: replace sync_core() with native_cpuid_reg(eax)
+    - x86/vdso: Fix lsl operand order
+    - Linux 4.4.220
+
+  * Panic on suspend/resume Kernel panic - not syncing: stack-protector: Kernel
+    stack is corrupted in: sata_pmp_eh_recover+0xa2b/0xa40 (LP: #1821434) //
+    Xenial update: 4.4.220 upstream stable release (LP: #1875905)
+    - libata: Return correct status in sata_pmp_eh_recover_pm() when
+      ATA_DFLAG_DETACH is set
+
+  * psock_tpacket from the net test in ubuntu_kernel_selftests failed on KVM
+    kernels (LP: #1812176)
+    - selftests/net: skip psock_tpacket test if KALLSYMS was not enabled
+
+  * tunnels over IPv6 are unencrypted when using IPsec (LP: #1876982) //
+    CVE-2020-1749
+    - net: ipv6: add net argument to ip6_dst_lookup_flow
+    - net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup
+
+  * Bionic ubuntu ethtool doesn't check ring parameters boundaries
+    (LP: #1874444)
+    - ethtool: Ensure new ring parameters are within bounds during SRINGPARAM
+
+  * Improve TSC refinement (and calibration) reliability (LP: #1877858)
+    - x86/tsc: Make calibration refinement more robust
+
+  * Do not treat unresolved test case in ftrace from ubuntu_kernel_selftests as
+    failure (LP: #1877958)
+    - ftrace/selftest: make unresolved cases cause failure if --fail-unresolved
+      set
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 15 May 2020 18:03:36 +0200
+
+linux (4.4.0-179.209) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-179.209 -proposed tracker (LP: #1874804)
+
+  * Add debian/rules targets to compile/run kernel selftests (LP: #1874286)
+    - [Packaging] add support to compile/run selftests
+
+  * getitimer returns it_value=0 erroneously (LP: #1349028)
+    - [Config] CONTEXT_TRACKING_FORCE policy should be unset
+
+  * CVE-2020-11608
+    - media: ov519: add missing endpoint sanity checks
+
+  * CVE-2019-19060
+    - iio: imu: adis16400: release allocated memory on failure
+
+  * Xenial update: 4.4.219 upstream stable release (LP: #1874045)
+    - drm/bochs: downgrade pci_request_region failure from error to warning
+    - ipv4: fix a RCU-list lock in fib_triestat_seq_show
+    - net, ip_tunnel: fix interface lookup with no key
+    - sctp: fix possibly using a bad saddr with a given dst
+    - l2tp: Correctly return -EBADF from pppol2tp_getname.
+    - net: l2tp: Make l2tp_ip6 namespace aware
+    - l2tp: fix race in l2tp_recv_common()
+    - l2tp: ensure session can't get removed during pppol2tp_session_ioctl()
+    - l2tp: fix duplicate session creation
+    - l2tp: Refactor the codes with existing macros instead of literal number
+    - l2tp: ensure sessions are freed after their PPPOL2TP socket
+    - l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall()
+    - usb: gadget: uac2: Drop unused device qualifier descriptor
+    - usb: gadget: printer: Drop unused device qualifier descriptor
+    - padata: always acquire cpu_hotplug_lock before pinst->lock
+    - mm: mempolicy: require at least one nodeid for MPOL_PREFERRED
+    - net: stmmac: dwmac1000: fix out-of-bounds mac address reg setting
+    - random: always use batched entropy for get_random_u{32,64}
+    - tools/accounting/getdelays.c: fix netlink attribute length
+    - power: supply: axp288_charger: Fix unchecked return value
+    - ASoC: jz4740-i2s: Fix divider written at incorrect offset in register
+    - IB/hfi1: Call kobject_put() when kobject_init_and_add() fails
+    - Bluetooth: RFCOMM: fix ODEBUG bug in rfcomm_dev_ioctl
+    - RDMA/cm: Update num_paths in cma_resolve_iboe_route error flow
+    - clk: qcom: rcg: Return failure for RCG update
+    - drm_dp_mst_topology: fix broken drm_dp_sideband_parse_remote_dpcd_read()
+    - Linux 4.4.219
+
+  * Xenial update: 4.4.218 upstream stable release (LP: #1873852)
+    - spi: qup: call spi_qup_pm_resume_runtime before suspending
+    - powerpc: Include .BTF section
+    - ARM: dts: dra7: Add "dma-ranges" property to PCIe RC DT nodes
+    - spi/zynqmp: remove entry that causes a cs glitch
+    - drm/exynos: dsi: propagate error value and silence meaningless warning
+    - drm/exynos: dsi: fix workaround for the legacy clock name
+    - altera-stapl: altera_get_note: prevent write beyond end of 'key'
+    - USB: Disable LPM on WD19's Realtek Hub
+    - usb: quirks: add NO_LPM quirk for RTL8153 based ethernet adapters
+    - USB: serial: option: add ME910G1 ECM composition 0x110b
+    - usb: host: xhci-plat: add a shutdown
+    - USB: serial: pl2303: add device-id for HP LD381
+    - ALSA: line6: Fix endless MIDI read loop
+    - ALSA: seq: virmidi: Fix running status after receiving sysex
+    - ALSA: seq: oss: Fix running status after receiving sysex
+    - ALSA: pcm: oss: Avoid plugin buffer overflow
+    - ALSA: pcm: oss: Remove WARNING from snd_pcm_plug_alloc() checks
+    - staging: rtl8188eu: Add device id for MERCUSYS MW150US v2
+    - staging/speakup: fix get_word non-space look-ahead
+    - intel_th: Fix user-visible error codes
+    - rtc: max8907: add missing select REGMAP_IRQ
+    - memcg: fix NULL pointer dereference in __mem_cgroup_usage_unregister_event
+    - mm: slub: be more careful about the double cmpxchg of freelist
+    - mm, slub: prevent kmalloc_node crashes and memory leaks
+    - x86/mm: split vmalloc_sync_all()
+    - USB: cdc-acm: fix close_delay and closing_wait units in TIOCSSERIAL
+    - USB: cdc-acm: fix rounding error in TIOCSSERIAL
+    - kbuild: Disable -Wpointer-to-enum-cast
+    - futex: Fix inode life-time issue
+    - futex: Unbreak futex hashing
+    - arm64: smp: fix smp_send_stop() behaviour
+    - Revert "drm/dp_mst: Skip validating ports during destruction, just ref"
+    - hsr: fix general protection fault in hsr_addr_is_self()
+    - net: dsa: Fix duplicate frames flooded by learning
+    - net_sched: cls_route: remove the right filter from hashtable
+    - net_sched: keep alloc_hash updated after hash allocation
+    - NFC: fdp: Fix a signedness bug in fdp_nci_send_patch()
+    - slcan: not call free_netdev before rtnl_unlock in slcan_open
+    - vxlan: check return value of gro_cells_init()
+    - hsr: use rcu_read_lock() in hsr_get_node_{list/status}()
+    - hsr: add restart routine into hsr_get_node_list()
+    - hsr: set .netnsok flag
+    - vhost: Check docket sk_family instead of call getname
+    - IB/ipoib: Do not warn if IPoIB debugfs doesn't exist
+    - uapi glibc compat: fix outer guard of net device flags enum
+    - KVM: VMX: Do not allow reexecute_instruction() when skipping MMIO instr
+    - drivers/hwspinlock: use correct radix tree API
+    - net: ipv4: don't let PMTU updates increase route MTU
+    - cpupower: avoid multiple definition with gcc -fno-common
+    - dt-bindings: net: FMan erratum A050385
+    - scsi: ipr: Fix softlockup when rescanning devices in petitboot
+    - mac80211: Do not send mesh HWMP PREQ if HWMP is disabled
+    - sxgbe: Fix off by one in samsung driver strncpy size arg
+    - i2c: hix5hd2: add missed clk_disable_unprepare in remove
+    - perf probe: Do not depend on dwfl_module_addrsym()
+    - scripts/dtc: Remove redundant YYLOC global declaration
+    - scsi: sd: Fix optimal I/O size for devices that change reported values
+    - mac80211: mark station unauthorized before key removal
+    - genirq: Fix reference leaks on irq affinity notifiers
+    - vti[6]: fix packet tx through bpf_redirect() in XinY cases
+    - xfrm: fix uctx len check in verify_sec_ctx_len
+    - xfrm: add the missing verify_sec_ctx_len check in xfrm_add_acquire
+    - xfrm: policy: Fix doulbe free in xfrm_policy_timer
+    - vti6: Fix memory leak of skb if input policy check fails
+    - tools: Let O= makes handle a relative path with -C option
+    - USB: serial: option: add support for ASKEY WWHC050
+    - USB: serial: option: add BroadMobi BM806U
+    - USB: serial: option: add Wistron Neweb D19Q1
+    - USB: cdc-acm: restore capability check order
+    - USB: serial: io_edgeport: fix slab-out-of-bounds read in
+      edge_interrupt_callback
+    - usb: musb: fix crash with highmen PIO and usbmon
+    - media: flexcop-usb: fix endpoint sanity check
+    - media: usbtv: fix control-message timeouts
+    - staging: rtl8188eu: Add ASUS USB-N10 Nano B1 to device table
+    - staging: wlan-ng: fix use-after-free Read in hfa384x_usbin_callback
+    - libfs: fix infoleak in simple_attr_read()
+    - media: ov519: add missing endpoint sanity checks
+    - media: dib0700: fix rc endpoint lookup
+    - media: stv06xx: add missing descriptor sanity checks
+    - media: xirlink_cit: add missing descriptor sanity checks
+    - vt: selection, introduce vc_is_sel
+    - vt: ioctl, switch VT_IS_IN_USE and VT_BUSY to inlines
+    - vt: switch vt_dont_switch to bool
+    - vt: vt_ioctl: remove unnecessary console allocation checks
+    - vt: vt_ioctl: fix VT_DISALLOCATE freeing in-use virtual console
+    - locking/atomic, kref: Add kref_read()
+    - vt: vt_ioctl: fix use-after-free in vt_in_use()
+    - bpf: Explicitly memset the bpf_attr structure
+    - net: ks8851-ml: Fix IO operations, again
+    - perf map: Fix off by one in strncpy() size argument
+    - Linux 4.4.218
+
+  * Pop sound from build-in speaker during cold boot and resume from S3
+    (LP: #1866357) // Xenial update: 4.4.218 upstream stable release
+    (LP: #1873852)
+    - ALSA: hda/realtek: Fix pop noise on ALC225
+
+  * CVE-2020-11494
+    - slcan: Don't transmit uninitialized stack data in padding
+
+  * add_key05 from ubuntu_ltp_syscalls failed (LP: #1869644)
+    - KEYS: reaching the keys quotas correctly
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 24 Apr 2020 19:06:47 +0200
+
+linux (4.4.0-178.208) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-178.208 -proposed tracker (LP: #1870660)
+
+  * CVE-2019-19768
+    - blktrace: Protect q->blk_trace with RCU
+    - blktrace: fix dereference after null check
+
+  * Multiple Kexec in AWS Nitro instances fail (LP: #1869948)
+    - net: ena: Add PCI shutdown handler to allow safe kexec
+
+  * Insert test_bpf module will report 4 failures for ubuntu_bpf_jit on X s390x
+    (LP: #1768452)
+    - test_bpf: flag tests that cannot be jited on s390
+
+  * Mounting LVM snapshots with xfs can hit kernel BUG in nvme driver
+    (LP: #1869229)
+    - block: fix bio_will_gap() for first bvec with offset
+
+  * Xenial update: 4.4.217 upstream stable release (LP: #1868629)
+    - NFS: Remove superfluous kmap in nfs_readdir_xdr_to_array
+    - r8152: check disconnect status after long sleep
+    - net: nfc: fix bounds checking bugs on "pipe"
+    - bnxt_en: reinitialize IRQs when MTU is modified
+    - fib: add missing attribute validation for tun_id
+    - nl802154: add missing attribute validation
+    - nl802154: add missing attribute validation for dev_type
+    - team: add missing attribute validation for port ifindex
+    - team: add missing attribute validation for array index
+    - nfc: add missing attribute validation for SE API
+    - nfc: add missing attribute validation for vendor subcommand
+    - ipvlan: add cond_resched_rcu() while processing muticast backlog
+    - ipvlan: do not add hardware address of master to its unicast filter list
+    - ipvlan: egress mcast packets are not exceptional
+    - ipvlan: do not use cond_resched_rcu() in ipvlan_process_multicast()
+    - ipvlan: don't deref eth hdr before checking it's set
+    - macvlan: add cond_resched() during multicast processing
+    - net: fec: validate the new settings in fec_enet_set_coalesce()
+    - slip: make slhc_compress() more robust against malicious packets
+    - bonding/alb: make sure arp header is pulled before accessing it
+    - net: fq: add missing attribute validation for orphan mask
+    - iommu/vt-d: quirk_ioat_snb_local_iommu: replace WARN_TAINT with pr_warn +
+      add_taint
+    - drm/amd/display: remove duplicated assignment to grph_obj_type
+    - gfs2_atomic_open(): fix O_EXCL|O_CREAT handling on cold dcache
+    - KVM: x86: clear stale x86_emulate_ctxt->intercept value
+    - ARC: define __ALIGN_STR and __ALIGN symbols for ARC
+    - efi: Fix a race and a buffer overflow while reading efivars via sysfs
+    - iommu/vt-d: dmar: replace WARN_TAINT with pr_warn + add_taint
+    - iommu/vt-d: Fix a bug in intel_iommu_iova_to_phys() for huge page
+    - nl80211: add missing attribute validation for critical protocol indication
+    - nl80211: add missing attribute validation for channel switch
+    - netfilter: cthelper: add missing attribute validation for cthelper
+    - iommu/vt-d: Fix the wrong printing in RHSA parsing
+    - iommu/vt-d: Ignore devices with out-of-spec domain number
+    - ipv6: restrict IPV6_ADDRFORM operation
+    - efi: Add a sanity check to efivar_store_raw()
+    - batman-adv: Fix invalid read while copying bat_iv.bcast_own
+    - batman-adv: Only put gw_node list reference when removed
+    - batman-adv: Only put orig_node_vlan list reference when removed
+    - batman-adv: Avoid endless loop in bat-on-bat netdevice check
+    - batman-adv: Fix unexpected free of bcast_own on add_if error
+    - batman-adv: Fix integer overflow in batadv_iv_ogm_calc_tq
+    - batman-adv: init neigh node last seen field
+    - batman-adv: Deactivate TO_BE_ACTIVATED hardif on shutdown
+    - batman-adv: Drop reference to netdevice on last reference
+    - batman-adv: Fix reference counting of vlan object for tt_local_entry
+    - batman-adv: Avoid duplicate neigh_node additions
+    - batman-adv: fix skb deref after free
+    - batman-adv: Fix use-after-free/double-free of tt_req_node
+    - batman-adv: Fix ICMP RR ethernet access after skb_linearize
+    - batman-adv: Clean up untagged vlan when destroying via rtnl-link
+    - batman-adv: Avoid nullptr dereference in bla after vlan_insert_tag
+    - batman-adv: Avoid nullptr dereference in dat after vlan_insert_tag
+    - batman-adv: Fix orig_node_vlan leak on orig_node_release
+    - batman-adv: lock crc access in bridge loop avoidance
+    - batman-adv: Fix non-atomic bla_claim::backbone_gw access
+    - batman-adv: Fix reference leak in batadv_find_router
+    - batman-adv: Free last_bonding_candidate on release of orig_node
+    - batman-adv: Fix speedy join in gateway client mode
+    - batman-adv: Add missing refcnt for last_candidate
+    - batman-adv: Fix double free during fragment merge error
+    - batman-adv: Fix transmission of final, 16th fragment
+    - batman-adv: Fix rx packet/bytes stats on local ARP reply
+    - batman-adv: fix TT sync flag inconsistencies
+    - batman-adv: Fix lock for ogm cnt access in batadv_iv_ogm_calc_tq
+    - batman-adv: Fix internal interface indices types
+    - batman-adv: update data pointers after skb_cow()
+    - batman-adv: Fix skbuff rcsum on packet reroute
+    - batman-adv: Avoid race in TT TVLV allocator helper
+    - batman-adv: Fix TT sync flags for intermediate TT responses
+    - batman-adv: prevent TT request storms by not sending inconsistent TT TLVLs
+    - batman-adv: Fix debugfs path for renamed hardif
+    - batman-adv: Fix debugfs path for renamed softif
+    - batman-adv: Avoid storing non-TT-sync flags on singular entries too
+    - batman-adv: Prevent duplicated gateway_node entry
+    - batman-adv: Prevent duplicated nc_node entry
+    - batman-adv: Prevent duplicated global TT entry
+    - batman-adv: Prevent duplicated tvlv handler
+    - batman-adv: Reduce claim hash refcnt only for removed entry
+    - batman-adv: Reduce tt_local hash refcnt only for removed entry
+    - batman-adv: Reduce tt_global hash refcnt only for removed entry
+    - batman-adv: Only read OGM tvlv_len after buffer len check
+    - batman-adv: Avoid free/alloc race when handling OGM buffer
+    - batman-adv: Don't schedule OGM for disabled interface
+    - perf/amd/uncore: Replace manual sampling check with CAP_NO_INTERRUPT flag
+    - net: ks8851-ml: Fix IRQ handling and locking
+    - signal: avoid double atomic counter increments for user accounting
+    - jbd2: fix data races at struct journal_head
+    - ARM: 8957/1: VDSO: Match ARMv8 timer in cntvct_functional()
+    - ARM: 8958/1: rename missed uaccess .fixup section
+    - mm: slub: add missing TID bump in kmem_cache_alloc_bulk()
+    - ipv4: ensure rcu_read_lock() in cipso_v4_error()
+    - Linux 4.4.217
+
+  * Xenial update: 4.4.216 upstream stable release (LP: #1868628)
+    - iwlwifi: pcie: fix rb_allocator workqueue allocation
+    - ext4: fix potential race between online resizing and write operations
+    - ext4: fix potential race between s_flex_groups online resizing and access
+    - ext4: fix potential race between s_group_info online resizing and access
+    - ipmi:ssif: Handle a possible NULL pointer reference
+    - mac80211: consider more elements in parsing CRC
+    - cfg80211: check wiphy driver existence for drvinfo report
+    - cifs: Fix mode output in debugging statements
+    - cfg80211: add missing policy for NL80211_ATTR_STATUS_CODE
+    - sysrq: Restore original console_loglevel when sysrq disabled
+    - sysrq: Remove duplicated sysrq message
+    - net: fib_rules: Correctly set table field when table number exceeds 8 bits
+    - net: phy: restore mdio regs in the iproc mdio driver
+    - ipv6: Fix nlmsg_flags when splitting a multipath route
+    - ipv6: Fix route replacement with dev-only route
+    - sctp: move the format error check out of __sctp_sf_do_9_1_abort
+    - nfc: pn544: Fix occasional HW initialization failure
+    - net: sched: correct flower port blocking
+    - ext4: potential crash on allocation error in ext4_alloc_flex_bg_array()
+    - audit: fix error handling in audit_data_to_entry()
+    - HID: core: fix off-by-one memset in hid_report_raw_event()
+    - HID: core: increase HID report buffer size to 8KiB
+    - HID: hiddev: Fix race in in hiddev_disconnect()
+    - MIPS: VPE: Fix a double free and a memory leak in 'release_vpe()'
+    - i2c: jz4780: silence log flood on txabrt
+    - ecryptfs: Fix up bad backport of fe2e082f5da5b4a0a92ae32978f81507ef37ec66
+    - net: netlink: cap max groups which will be considered in netlink_bind()
+    - namei: only return -ECHILD from follow_dotdot_rcu()
+    - KVM: Check for a bad hva before dropping into the ghc slow path
+    - slip: stop double free sl->dev in slip_open
+    - mm: make page ref count overflow check tighter and more explicit
+    - mm, gup: remove broken VM_BUG_ON_PAGE compound check for hugepages
+    - audit: always check the netlink payload length in audit_receive_msg()
+    - serial: ar933x_uart: set UART_CS_{RX,TX}_READY_ORIDE
+    - usb: gadget: ffs: ffs_aio_cancel(): Save/restore IRQ flags
+    - usb: gadget: serial: fix Tx stall after buffer overflow
+    - drm: msm: Fix return type of dsi_mgr_connector_mode_valid for kCFI
+    - drm/msm/dsi: save pll state before dsi host is powered off
+    - net: ks8851-ml: Remove 8-bit bus accessors
+    - net: ks8851-ml: Fix 16-bit data access
+    - net: ks8851-ml: Fix 16-bit IO operation
+    - watchdog: da9062: do not ping the hw during stop()
+    - s390/cio: cio_ignore_proc_seq_next should increase position index
+    - cifs: don't leak -EAGAIN for stat() during reconnect
+    - usb: storage: Add quirk for Samsung Fit flash
+    - usb: quirks: add NO_LPM quirk for Logitech Screen Share
+    - usb: core: hub: do error out if usb_autopm_get_interface() fails
+    - usb: core: port: do error out if usb_autopm_get_interface() fails
+    - vgacon: Fix a UAF in vgacon_invert_region
+    - fat: fix uninit-memory access for partial initialized inode
+    - vt: selection, close sel_buffer race
+    - vt: selection, push console lock down
+    - vt: selection, push sel_lock up
+    - dmaengine: tegra-apb: Fix use-after-free
+    - dmaengine: tegra-apb: Prevent race conditions of tasklet vs free list
+    - ASoC: pcm: Fix possible buffer overflow in dpcm state sysfs output
+    - ASoC: pcm512x: Fix unbalanced regulator enable call in probe error path
+    - ASoC: dapm: Correct DAPM handling of active widgets during shutdown
+    - RDMA/iwcm: Fix iwcm work deallocation
+    - RMDA/cm: Fix missing ib_cm_destroy_id() in ib_cm_insert_listen()
+    - ARM: imx: build v7_cpu_resume() unconditionally
+    - hwmon: (adt7462) Fix an error return in ADT7462_REG_VOLT()
+    - dmaengine: coh901318: Fix a double lock bug in dma_tc_handle()
+    - powerpc: fix hardware PMU exception bug on PowerVM compatibility mode
+      systems
+    - dm cache: fix a crash due to incorrect work item cancelling
+    - crypto: algif_skcipher - use ZERO_OR_NULL_PTR in skcipher_recvmsg_async
+    - Linux 4.4.216
+
+  * Xenial update: 4.4.215 upstream stable release (LP: #1868627)
+    - ALSA: hda: Use scnprintf() for printing texts for sysfs/procfs
+    - ecryptfs: fix a memory leak bug in parse_tag_1_packet()
+    - ecryptfs: fix a memory leak bug in ecryptfs_init_messaging()
+    - ALSA: usb-audio: Apply sample rate quirk for Audioengine D1
+    - ubifs: Fix deadlock in concurrent bulk-read and writepage
+    - ext4: fix checksum errors with indexed dirs
+    - Btrfs: fix race between using extent maps and merging them
+    - btrfs: log message when rw remount is attempted with unclean tree-log
+    - padata: Remove broken queue flushing
+    - s390/time: Fix clk type in get_tod_clock
+    - hwmon: (pmbus/ltc2978) Fix PMBus polling of MFR_COMMON definitions.
+    - jbd2: move the clearing of b_modified flag to the journal_unmap_buffer()
+    - jbd2: do not clear the BH_Mapped flag when forgetting a metadata buffer
+    - btrfs: print message when tree-log replay starts
+    - scsi: qla2xxx: fix a potential NULL pointer dereference
+    - Revert "KVM: VMX: Add non-canonical check on writes to RTIT address MSRs"
+    - drm/gma500: Fixup fbdev stolen size usage evaluation
+    - brcmfmac: Fix use after free in brcmf_sdio_readframes()
+    - gianfar: Fix TX timestamping with a stacked DSA driver
+    - pinctrl: sh-pfc: sh7264: Fix CAN function GPIOs
+    - media: i2c: mt9v032: fix enum mbus codes and frame sizes
+    - media: sti: bdisp: fix a possible sleep-in-atomic-context bug in
+      bdisp_device_run()
+    - efi/x86: Map the entire EFI vendor string before copying it
+    - MIPS: Loongson: Fix potential NULL dereference in loongson3_platform_init()
+    - uio: fix a sleep-in-atomic-context bug in uio_dmem_genirq_irqcontrol()
+    - usb: gadget: udc: fix possible sleep-in-atomic-context bugs in gr_probe()
+    - nfs: NFS_SWAP should depend on SWAP
+    - jbd2: clear JBD2_ABORT flag before journal_reset to update log tail info
+      when load journal
+    - tracing: Fix very unlikely race of registering two stat tracers
+    - ext4, jbd2: ensure panic when aborting with zero errno
+    - kconfig: fix broken dependency in randconfig-generated .config
+    - clk: qcom: rcg2: Don't crash if our parent can't be found; return an error
+    - drm/amdgpu: remove 4 set but not used variable in
+      amdgpu_atombios_get_connector_info_from_object_table
+    - regulator: rk808: Lower log level on optional GPIOs being not available
+    - NFC: port100: Convert cpu_to_le16(le16_to_cpu(E1) + E2) to use
+      le16_add_cpu().
+    - reiserfs: Fix spurious unlock in reiserfs_fill_super() error handling
+    - ALSA: usx2y: Adjust indentation in snd_usX2Y_hwdep_dsp_status
+    - b43legacy: Fix -Wcast-function-type
+    - ipw2x00: Fix -Wcast-function-type
+    - iwlegacy: Fix -Wcast-function-type
+    - rtlwifi: rtl_pci: Fix -Wcast-function-type
+    - orinoco: avoid assertion in case of NULL pointer
+    - ACPICA: Disassembler: create buffer fields in ACPI_PARSE_LOAD_PASS1
+    - scsi: aic7xxx: Adjust indentation in ahc_find_syncrate
+    - ARM: dts: r8a7779: Add device node for ARM global timer
+    - x86/vdso: Provide missing include file
+    - pinctrl: sh-pfc: sh7269: Fix CAN function GPIOs
+    - ALSA: sh: Fix compile warning wrt const
+    - tools lib api fs: Fix gcc9 stringop-truncation compilation error
+    - usbip: Fix unsafe unaligned pointer usage
+    - soc/tegra: fuse: Correct straps' address for older Tegra124 device trees
+    - rcu: Use WRITE_ONCE() for assignments to ->pprev for hlist_nulls
+    - Input: edt-ft5x06 - work around first register access error
+    - wan: ixp4xx_hss: fix compile-testing on 64-bit
+    - ASoC: atmel: fix build error with CONFIG_SND_ATMEL_SOC_DMA=m
+    - PCI: Don't disable bridge BARs when assigning bus resources
+    - driver core: Print device when resources present in really_probe()
+    - drm/nouveau: Fix copy-paste error in nouveau_fence_wait_uevent_handler
+    - drm/vmwgfx: prevent memory leak in vmw_cmdbuf_res_add
+    - iommu/arm-smmu-v3: Use WRITE_ONCE() when changing validity of an STE
+    - scsi: iscsi: Don't destroy session if there are outstanding connections
+    - cmd64x: potential buffer overflow in cmd64x_program_timings()
+    - ide: serverworks: potential overflow in svwks_set_pio_mode()
+    - remoteproc: Initialize rproc_class before use
+    - s390/ftrace: generate traced function stack frame
+    - ALSA: hda - Add docking station support for Lenovo Thinkpad T420s
+    - jbd2: switch to use jbd2_journal_abort() when failed to submit the commit
+      record
+    - ARM: 8951/1: Fix Kexec compilation issue.
+    - hostap: Adjust indentation in prism2_hostapd_add_sta
+    - iwlegacy: ensure loop counter addr does not wrap and cause an infinite loop
+    - drm/nouveau/disp/nv50-: prevent oops when no channel method map provided
+    - trigger_next should increase position index
+    - radeon: insert 10ms sleep in dce5_crtc_load_lut
+    - ocfs2: fix a NULL pointer dereference when call
+      ocfs2_update_inode_fsync_trans()
+    - lib/scatterlist.c: adjust indentation in __sg_alloc_table
+    - reiserfs: prevent NULL pointer dereference in reiserfs_insert_item()
+    - bcache: explicity type cast in bset_bkey_last()
+    - irqchip/gic-v3-its: Reference to its_invall_cmd descriptor when building
+      INVALL
+    - microblaze: Prevent the overflow of the start
+    - brd: check and limit max_part par
+    - selinux: ensure we cleanup the internal AVC counters on error in
+      avc_update()
+    - enic: prevent waking up stopped tx queues over watchdog reset
+    - floppy: check FDC index for errors before assigning it
+    - staging: android: ashmem: Disallow ashmem memory from being remapped
+    - staging: vt6656: fix sign of rx_dbm to bb_pre_ed_rssi.
+    - usb: uas: fix a plug & unplug racing
+    - USB: Fix novation SourceControl XL after suspend
+    - USB: hub: Don't record a connect-change event during reset-resume
+    - staging: rtl8188eu: Fix potential security hole
+    - staging: rtl8188eu: Fix potential overuse of kernel memory
+    - x86/mce/amd: Fix kobject lifetime
+    - tty: serial: imx: setup the correct sg entry for tx dma
+    - xhci: apply XHCI_PME_STUCK_QUIRK to Intel Comet Lake platforms
+    - VT_RESIZEX: get rid of field-by-field copyin
+    - vt: vt_ioctl: fix race in VT_RESIZEX
+    - netfilter: xt_bpf: add overflow checks
+    - ext4: fix a data race in EXT4_I(inode)->i_disksize
+    - ext4: add cond_resched() to __ext4_find_entry()
+    - KVM: apic: avoid calculating pending eoi from an uninitialized val
+    - Btrfs: fix btrfs_wait_ordered_range() so that it waits for all ordered
+      extents
+    - scsi: Revert "RDMA/isert: Fix a recently introduced regression related to
+      logout"
+    - scsi: Revert "target: iscsi: Wait for all commands to finish before freeing
+      a session"
+    - ecryptfs: replace BUG_ON with error handling code
+    - ALSA: rawmidi: Avoid bit fields for state flags
+    - ALSA: seq: Avoid concurrent access to queue flags
+    - ALSA: seq: Fix concurrent access to queue current tick/time
+    - xen: Enable interrupts when calling _cond_resched()
+    - Linux 4.4.215
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sun, 05 Apr 2020 18:51:07 -0400
+
+linux (4.4.0-177.207) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-177.207 -proposed tracker (LP: #1867243)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+
+  * Xenial update: 4.4.214 upstream stable release (LP: #1864775)
+    - media: iguanair: fix endpoint sanity check
+    - x86/cpu: Update cached HLE state on write to TSX_CTRL_CPUID_CLEAR
+    - sparc32: fix struct ipc64_perm type definition
+    - ASoC: qcom: Fix of-node refcount unbalance to link->codec_of_node
+    - cls_rsvp: fix rsvp_policy
+    - net: hsr: fix possible NULL deref in hsr_handle_frame()
+    - net_sched: fix an OOB access in cls_tcindex
+    - tcp: clear tp->total_retrans in tcp_disconnect()
+    - tcp: clear tp->segs_{in|out} in tcp_disconnect()
+    - media: uvcvideo: Avoid cyclic entity chains due to malformed USB descriptors
+    - mfd: dln2: More sanity checking for endpoints
+    - brcmfmac: Fix memory leak in brcmf_usbdev_qinit
+    - usb: gadget: legacy: set max_speed to super-speed
+    - usb: gadget: f_ncm: Use atomic_t to track in-flight request
+    - usb: gadget: f_ecm: Use atomic_t to track in-flight request
+    - ALSA: dummy: Fix PCM format loop in proc output
+    - lib/test_kasan.c: fix memory leak in kmalloc_oob_krealloc_more()
+    - powerpc/pseries: Advance pfn if section is not present in lmb_is_removable()
+    - mmc: spi: Toggle SPI polarity, do not hardcode it
+    - PCI: keystone: Fix link training retries initiation
+    - crypto: api - Check spawn->alg under lock in crypto_drop_spawn
+    - scsi: qla2xxx: Fix mtcp dump collection failure
+    - power: supply: ltc2941-battery-gauge: fix use-after-free
+    - of: Add OF_DMA_DEFAULT_COHERENT & select it on powerpc
+    - dm space map common: fix to ensure new block isn't already in use
+    - crypto: pcrypt - Do not clear MAY_SLEEP flag in original request
+    - crypto: api - Fix race condition in crypto_spawn_alg
+    - crypto: picoxcell - adjust the position of tasklet_init and fix missed
+      tasklet_kill
+    - btrfs: set trans->drity in btrfs_commit_transaction
+    - ARM: tegra: Enable PLLP bypass during Tegra124 LP1
+    - mwifiex: fix unbalanced locking in mwifiex_process_country_ie()
+    - sunrpc: expiry_time should be seconds not timeval
+    - KVM: x86: Refactor prefix decoding to prevent Spectre-v1/L1TF attacks
+    - KVM: x86: Protect DR-based index computations from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF
+      attacks
+    - KVM: x86: Protect ioapic_write_indirect() from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect MSR-based index computations in pmu.h from Spectre-v1/L1TF
+      attacks
+    - KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect MSR-based index computations from Spectre-v1/L1TF attacks
+      in x86.c
+    - KVM: x86: Protect x86_decode_insn from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect MSR-based index computations in fixed_msr_to_seg_unit()
+      from Spectre-v1/L1TF attacks
+    - KVM: PPC: Book3S HV: Uninit vCPU if vcore creation fails
+    - KVM: PPC: Book3S PR: Free shared page if mmu initialization fails
+    - KVM: x86: Free wbinvd_dirty_mask if vCPU creation fails
+    - scsi: qla2xxx: Fix the endianness of the qla82xx_get_fw_size() return type
+    - scsi: csiostor: Adjust indentation in csio_device_reset
+    - scsi: qla4xxx: Adjust indentation in qla4xxx_mem_free
+    - ext2: Adjust indentation in ext2_fill_super
+    - powerpc/44x: Adjust indentation in ibm4xx_denali_fixup_memsize
+    - NFC: pn544: Adjust indentation in pn544_hci_check_presence
+    - ppp: Adjust indentation into ppp_async_input
+    - net: smc911x: Adjust indentation in smc911x_phy_configure
+    - net: tulip: Adjust indentation in {dmfe, uli526x}_init_module
+    - mfd: da9062: Fix watchdog compatible string
+    - mfd: rn5t618: Mark ADC control register volatile
+    - net: systemport: Avoid RBUF stuck in Wake-on-LAN mode
+    - bonding/alb: properly access headers in bond_alb_xmit()
+    - NFS: Fix memory leaks and corruption in readdir
+    - NFS: Fix bool initialization/comparison
+    - NFS: Directory page cache pages need to be locked when read
+    - Btrfs: fix assertion failure on fsync with NO_HOLES enabled
+    - btrfs: remove trivial locking wrappers of tree mod log
+    - Btrfs: fix race between adding and putting tree mod seq elements and nodes
+    - drm: atmel-hlcdc: enable clock before configuring timing engine
+    - KVM: x86: drop picdev_in_range()
+    - KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks
+    - KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect kvm_lapic_reg_write() from Spectre-v1/L1TF attacks
+    - btrfs: flush write bio if we loop in extent_write_cache_pages
+    - KVM: x86/mmu: Apply max PA check for MMIO sptes to 32-bit KVM
+    - KVM: VMX: Add non-canonical check on writes to RTIT address MSRs
+    - KVM: nVMX: vmread should not set rflags to specify success in case of #PF
+    - cifs: fail i/o on soft mounts if sessionsetup errors out
+    - clocksource: Prevent double add_timer_on() for watchdog_timer
+    - perf/core: Fix mlock accounting in perf_mmap()
+    - ASoC: pcm: update FE/BE trigger order based on the command
+    - scsi: ufs: Fix ufshcd_probe_hba() reture value in case
+      ufshcd_scsi_add_wlus() fails
+    - rtc: hym8563: Return -EINVAL if the time is known to be invalid
+    - ARC: [plat-axs10x]: Add missing multicast filter number to GMAC node
+    - ARM: dts: at91: sama5d3: fix maximum peripheral clock rates
+    - ARM: dts: at91: sama5d3: define clock rate range for tcb1
+    - powerpc/pseries: Allow not having ibm, hypertas-functions::hcall-multi-tce
+      for DDW
+    - pinctrl: sh-pfc: r8a7778: Fix duplicate SDSELF_B and SD1_CLK_B
+    - mwifiex: Fix possible buffer overflows in mwifiex_ret_wmm_get_status()
+    - mwifiex: Fix possible buffer overflows in mwifiex_cmd_append_vsie_tlv()
+    - libertas: don't exit from lbs_ibss_join_existing() with RCU read lock held
+    - libertas: make lbs_ibss_join_existing() return error code on rates overflow
+    - Linux 4.4.214
+
+  * 5.4.0-11 crash on cryptsetup open (LP: #1860231) // Xenial update: 4.4.214
+    upstream stable release (LP: #1864775)
+    - dm: fix potential for q->make_request_fn NULL pointer
+
+  * Xenial update: 4.4.213 upstream stable release (LP: #1864774)
+    - ALSA: pcm: Add missing copy ops check before clearing buffer
+    - orinoco_usb: fix interface sanity check
+    - rsi_91x_usb: fix interface sanity check
+    - USB: serial: ir-usb: add missing endpoint sanity check
+    - USB: serial: ir-usb: fix link-speed handling
+    - USB: serial: ir-usb: fix IrLAP framing
+    - staging: most: net: fix buffer overflow
+    - staging: wlan-ng: ensure error return is actually returned
+    - staging: vt6656: correct packet types for CTS protect, mode.
+    - staging: vt6656: use NULLFUCTION stack on mac80211
+    - staging: vt6656: Fix false Tx excessive retries reporting.
+    - ath9k: fix storage endpoint lookup
+    - brcmfmac: fix interface sanity check
+    - rtl8xxxu: fix interface sanity check
+    - zd1211rw: fix storage endpoint lookup
+    - watchdog: rn5t618_wdt: fix module aliases
+    - drivers/net/b44: Change to non-atomic bit operations on pwol_mask
+    - net: wan: sdla: Fix cast from pointer to integer of different size
+    - atm: eni: fix uninitialized variable warning
+    - usb-storage: Disable UAS on JMicron SATA enclosure
+    - net_sched: ematch: reject invalid TCF_EM_SIMPLE
+    - crypto: af_alg - Use bh_lock_sock in sk_destruct
+    - crypto: pcrypt - Fix user-after-free on module unload
+    - arm64: kbuild: remove compressed images on 'make ARCH=arm64 (dist)clean'
+    - mm/mempolicy.c: fix out of bounds write in mpol_parse_str()
+    - reiserfs: Fix memory leak of journal device string
+    - media: digitv: don't continue if remote control state can't be read
+    - media: gspca: zero usb_buf
+    - media: dvb-usb/dvb-usb-urb.c: initialize actlen to 0
+    - ttyprintk: fix a potential deadlock in interrupt context issue
+    - usb: dwc3: turn off VBUS when leaving host mode
+    - media: si470x-i2c: Move free() past last use of 'radio'
+    - clk: mmp2: Fix the order of timer mux parents
+    - ixgbevf: Remove limit of 10 entries for unicast filter list
+    - ixgbe: Fix calculation of queue with VFs and flow director on interface flap
+    - wireless: wext: avoid gcc -O3 warning
+    - vti[6]: fix packet tx through bpf_redirect()
+    - scsi: fnic: do not queue commands during fwreset
+    - airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE
+    - airo: Add missing CAP_NET_ADMIN check in AIROOLDIOCTL/SIOCDEVPRIVATE
+    - r8152: get default setting of WOL before initializing
+    - qlcnic: Fix CPU soft lockup while collecting firmware dump
+    - net/fsl: treat fsl,erratum-a011043
+    - net/sonic: Add mutual exclusion for accessing shared state
+    - net/sonic: Use MMIO accessors
+    - net/sonic: Fix receive buffer handling
+    - net/sonic: Quiesce SONIC before re-initializing descriptor memory
+    - seq_tab_next() should increase position index
+    - l2t_seq_next should increase position index
+    - net: Fix skb->csum update in inet_proto_csum_replace16().
+    - btrfs: fix mixed block count of available space
+    - btrfs: do not zero f_bavail if we have available space
+    - Linux 4.4.213
+
+  * Xenial update: 4.4.212 upstream stable release (LP: #1864773)
+    - powerpc/archrandom: fix arch_get_random_seed_int()
+    - mt7601u: fix bbp version check in mt7601u_wait_bbp_ready
+    - drm/virtio: fix bounds check in virtio_gpu_cmd_get_capset()
+    - ALSA: hda: fix unused variable warning
+    - ALSA: usb-audio: update quirk for B&W PX to remove microphone
+    - staging: comedi: ni_mio_common: protect register write overflow
+    - pcrypt: use format specifier in kobject_add
+    - exportfs: fix 'passing zero to ERR_PTR()' warning
+    - drm/dp_mst: Skip validating ports during destruction, just ref
+    - pinctrl: sh-pfc: r8a7740: Add missing REF125CK pin to gether_gmii group
+    - pinctrl: sh-pfc: r8a7740: Add missing LCD0 marks to lcd0_data24_1 group
+    - pinctrl: sh-pfc: r8a7791: Remove bogus ctrl marks from qspi_data4_b group
+    - pinctrl: sh-pfc: r8a7791: Remove bogus marks from vin1_b_data18 group
+    - pinctrl: sh-pfc: sh73a0: Add missing TO pin to tpu4_to3 group
+    - pinctrl: sh-pfc: r8a7794: Remove bogus IPSR9 field
+    - pinctrl: sh-pfc: sh7734: Add missing IPSR11 field
+    - pinctrl: sh-pfc: sh7269: Add missing PCIOR0 field
+    - pinctrl: sh-pfc: sh7734: Remove bogus IPSR10 value
+    - Input: nomadik-ske-keypad - fix a loop timeout test
+    - clk: highbank: fix refcount leak in hb_clk_init()
+    - clk: qoriq: fix refcount leak in clockgen_init()
+    - clk: socfpga: fix refcount leak
+    - clk: samsung: exynos4: fix refcount leak in exynos4_get_xom()
+    - clk: imx6q: fix refcount leak in imx6q_clocks_init()
+    - clk: imx6sx: fix refcount leak in imx6sx_clocks_init()
+    - clk: imx7d: fix refcount leak in imx7d_clocks_init()
+    - clk: vf610: fix refcount leak in vf610_clocks_init()
+    - clk: armada-370: fix refcount leak in a370_clk_init()
+    - clk: kirkwood: fix refcount leak in kirkwood_clk_init()
+    - clk: armada-xp: fix refcount leak in axp_clk_init()
+    - IB/usnic: Fix out of bounds index check in query pkey
+    - RDMA/ocrdma: Fix out of bounds index check in query pkey
+    - media: s5p-jpeg: Correct step and max values for
+      V4L2_CID_JPEG_RESTART_INTERVAL
+    - crypto: tgr192 - fix unaligned memory access
+    - ASoC: imx-sgtl5000: put of nodes if finding codec fails
+    - rtc: cmos: ignore bogus century byte
+    - tty: ipwireless: Fix potential NULL pointer dereference
+    - rtc: ds1672: fix unintended sign extension
+    - rtc: 88pm860x: fix unintended sign extension
+    - rtc: 88pm80x: fix unintended sign extension
+    - rtc: pm8xxx: fix unintended sign extension
+    - fbdev: chipsfb: remove set but not used variable 'size'
+    - pinctrl: sh-pfc: emev2: Add missing pinmux functions
+    - pinctrl: sh-pfc: r8a7791: Fix scifb2_data_c pin group
+    - pinctrl: sh-pfc: sh73a0: Fix fsic_spdif pin groups
+    - block: don't use bio->bi_vcnt to figure out segment number
+    - vfio_pci: Enable memory accesses before calling pci_map_rom
+    - cdc-wdm: pass return value of recover_from_urb_loss
+    - drm/nouveau/bios/ramcfg: fix missing parentheses when calculating RON
+    - drm/nouveau/pmu: don't print reply values if exec is false
+    - ASoC: qcom: Fix of-node refcount unbalance in apq8016_sbc_parse_of()
+    - fs/nfs: Fix nfs_parse_devname to not modify it's argument
+    - clocksource/drivers/sun5i: Fail gracefully when clock rate is unavailable
+    - ARM: 8847/1: pm: fix HYP/SVC mode mismatch when MCPM is used
+    - regulator: wm831x-dcdc: Fix list of wm831x_dcdc_ilim from mA to uA
+    - nios2: ksyms: Add missing symbol exports
+    - scsi: megaraid_sas: reduce module load time
+    - xen, cpu_hotplug: Prevent an out of bounds access
+    - net: sh_eth: fix a missing check of of_get_phy_mode
+    - media: ivtv: update *pos correctly in ivtv_read_pos()
+    - media: cx18: update *pos correctly in cx18_read_pos()
+    - media: wl128x: Fix an error code in fm_download_firmware()
+    - media: cx23885: check allocation return
+    - jfs: fix bogus variable self-initialization
+    - m68k: mac: Fix VIA timer counter accesses
+    - ARM: OMAP2+: Fix potentially uninitialized return value for _setup_reset()
+    - media: davinci-isif: avoid uninitialized variable use
+    - spi: tegra114: clear packed bit for unpacked mode
+    - spi: tegra114: fix for unpacked mode transfers
+    - soc/fsl/qe: Fix an error code in qe_pin_request()
+    - spi: bcm2835aux: fix driver to not allow 65535 (=-1) cs-gpios
+    - ehea: Fix a copy-paste err in ehea_init_port_res
+    - scsi: qla2xxx: Unregister chrdev if module initialization fails
+    - ARM: pxa: ssp: Fix "WARNING: invalid free of devm_ allocated data"
+    - hwmon: (w83627hf) Use request_muxed_region for Super-IO accesses
+    - tipc: set sysctl_tipc_rmem and named_timeout right range
+    - powerpc: vdso: Make vdso32 installation conditional in vdso_install
+    - media: ov2659: fix unbalanced mutex_lock/unlock
+    - 6lowpan: Off by one handling ->nexthdr
+    - dmaengine: axi-dmac: Don't check the number of frames for alignment
+    - ALSA: usb-audio: Handle the error from snd_usb_mixer_apply_create_quirk()
+    - packet: in recvmsg msg_name return at least sizeof sockaddr_ll
+    - ASoC: fix valid stream condition
+    - IB/mlx5: Add missing XRC options to QP optional params mask
+    - iommu/vt-d: Make kernel parameter igfx_off work with vIOMMU
+    - media: omap_vout: potential buffer overflow in vidioc_dqbuf()
+    - media: davinci/vpbe: array underflow in vpbe_enum_outputs()
+    - platform/x86: alienware-wmi: printing the wrong error code
+    - netfilter: ebtables: CONFIG_COMPAT: reject trailing data after last rule
+    - ARM: riscpc: fix lack of keyboard interrupts after irq conversion
+    - kdb: do a sanity check on the cpu in kdb_per_cpu()
+    - backlight: lm3630a: Return 0 on success in update_status functions
+    - thermal: cpu_cooling: Actually trace CPU load in thermal_power_cpu_get_power
+    - spi: spi-fsl-spi: call spi_finalize_current_message() at the end
+    - misc: sgi-xp: Properly initialize buf in xpc_get_rsvd_page_pa
+    - iommu: Use right function to get group for device
+    - signal/cifs: Fix cifs_put_tcp_session to call send_sig instead of force_sig
+    - inet: frags: call inet_frags_fini() after unregister_pernet_subsys()
+    - media: vivid: fix incorrect assignment operation when setting video mode
+    - powerpc/cacheinfo: add cacheinfo_teardown, cacheinfo_rebuild
+    - drm/msm/mdp5: Fix mdp5_cfg_init error return
+    - net/af_iucv: always register net_device notifier
+    - ASoC: ti: davinci-mcasp: Fix slot mask settings when using multiple AXRs
+    - rtc: pcf8563: Clear event flags and disable interrupts before requesting irq
+    - drm/msm/a3xx: remove TPL1 regs from snapshot
+    - iommu/amd: Make iommu_disable safer
+    - mfd: intel-lpss: Release IDA resources
+    - devres: allow const resource arguments
+    - net: pasemi: fix an use-after-free in pasemi_mac_phy_init()
+    - scsi: libfc: fix null pointer dereference on a null lport
+    - libertas_tf: Use correct channel range in lbtf_geo_init
+    - usb: host: xhci-hub: fix extra endianness conversion
+    - mic: avoid statically declaring a 'struct device'.
+    - x86/kgbd: Use NMI_VECTOR not APIC_DM_NMI
+    - ALSA: aoa: onyx: always initialize register read value
+    - cifs: fix rmmod regression in cifs.ko caused by force_sig changes
+    - crypto: caam - free resources in case caam_rng registration failed
+    - ext4: set error return correctly when ext4_htree_store_dirent fails
+    - ASoC: es8328: Fix copy-paste error in es8328_right_line_controls
+    - ASoC: cs4349: Use PM ops 'cs4349_runtime_pm'
+    - ASoC: wm8737: Fix copy-paste error in wm8737_snd_controls
+    - signal: Allow cifs and drbd to receive their terminating signals
+    - dmaengine: dw: platform: Switch to acpi_dma_controller_register()
+    - mac80211: minstrel_ht: fix per-group max throughput rate initialization
+    - mips: avoid explicit UB in assignment of mips_io_port_base
+    - ahci: Do not export local variable ahci_em_messages
+    - Partially revert "kfifo: fix kfifo_alloc() and kfifo_init()"
+    - power: supply: Init device wakeup after device_add()
+    - x86, perf: Fix the dependency of the x86 insn decoder selftest
+    - bcma: fix incorrect update of BCMA_CORE_PCI_MDIO_DATA
+    - iio: dac: ad5380: fix incorrect assignment to val
+    - ath9k: dynack: fix possible deadlock in ath_dynack_node_{de}init
+    - net: sonic: return NETDEV_TX_OK if failed to map buffer
+    - Btrfs: fix hang when loading existing inode cache off disk
+    - hwmon: (shtc1) fix shtc1 and shtw1 id mask
+    - net: sonic: replace dev_kfree_skb in sonic_send_packet
+    - net/rds: Fix 'ib_evt_handler_call' element in 'rds_ib_stat_names'
+    - iommu/amd: Wait for completion of IOTLB flush in attach_device
+    - net: hisilicon: Fix signedness bug in hix5hd2_dev_probe()
+    - net: broadcom/bcmsysport: Fix signedness in bcm_sysport_probe()
+    - net: ethernet: stmmac: Fix signedness bug in ipq806x_gmac_of_parse()
+    - mac80211: accept deauth frames in IBSS mode
+    - llc: fix another potential sk_buff leak in llc_ui_sendmsg()
+    - llc: fix sk_buff refcounting in llc_conn_state_process()
+    - net: stmmac: fix length of PTP clock's name string
+    - drm/msm/dsi: Implement reset correctly
+    - dmaengine: imx-sdma: fix size check for sdma script_number
+    - net: qca_spi: Move reset_count to struct qcaspi
+    - media: ov6650: Fix incorrect use of JPEG colorspace
+    - media: ov6650: Fix some format attributes not under control
+    - media: ov6650: Fix .get_fmt() V4L2_SUBDEV_FORMAT_TRY support
+    - MIPS: Loongson: Fix return value of loongson_hwmon_init
+    - net: neigh: use long type to store jiffies delta
+    - packet: fix data-race in fanout_flow_is_huge()
+    - dmaengine: ti: edma: fix missed failure handling
+    - drm/radeon: fix bad DMA from INTERRUPT_CNTL2
+    - arm64: dts: juno: Fix UART frequency
+    - m68k: Call timer_interrupt() with interrupts disabled
+    - firestream: fix memory leaks
+    - net: cxgb3_main: Add CAP_NET_ADMIN check to CHELSIO_GET_MEM
+    - net, ip_tunnel: fix namespaces move
+    - net_sched: fix datalen for ematch
+    - net: usb: lan78xx: Add .ndo_features_check
+    - hwmon: (adt7475) Make volt2reg return same reg as reg2volt input
+    - Input: keyspan-remote - fix control-message timeouts
+    - ARM: 8950/1: ftrace/recordmcount: filter relocation types
+    - mmc: sdhci: fix minimum clock rate for v3 controller
+    - Input: sur40 - fix interface sanity checks
+    - Input: gtco - fix endpoint sanity check
+    - Input: aiptek - fix endpoint sanity check
+    - hwmon: (nct7802) Fix voltage limits to wrong registers
+    - scsi: RDMA/isert: Fix a recently introduced regression related to logout
+    - tracing: xen: Ordered comparison of function pointers
+    - iio: buffer: align the size of scan bytes to size of the largest element
+    - scsi: iscsi: Avoid potential deadlock in iscsi_if_rx func
+    - md: Avoid namespace collision with bitmap API
+    - bitmap: Add bitmap_alloc(), bitmap_zalloc() and bitmap_free()
+    - netfilter: ipset: use bitmap infrastructure completely
+    - net/x25: fix nonblocking connect
+    - Revert "UBUNTU: SAUCE: libertas: Fix two buffer overflows at parsing bss
+      descriptor"
+    - libertas: Fix two buffer overflows at parsing bss descriptor
+    - Linux 4.4.212
+
+  * CVE-2020-8428
+    - do_last(): fetch directory ->i_mode and ->i_uid before it's too late
+    - vfs: fix do_last() regression
+
+  * xfs fill_fs test in fallocate06 from ubuntu_ltp_syscalls failed
+    (LP: #1865967)
+    - xfs: Fix tail rounding in xfs_alloc_file_space()
+
+  * ipc/sem.c : process loops infinitely in exit_sem() (LP: #1858834)
+    - Revert "ipc, sem: remove uneeded sem_undo_list lock usage in exit_sem()"
+
+  * quotactl07 from ubuntu_ltp_syscalls failed (LP: #1864092)
+    - xfs: Sanity check flags of Q_XQUOTARM call
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sun, 15 Mar 2020 19:16:50 -0400
+
+linux (4.4.0-176.206) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-176.206 -proposed tracker (LP: #1865106)
+
+  * CVE-2020-2732
+    - x86/vdso: Use RDPID in preference to LSL when available
+    - KVM: x86: emulate RDPID
+    - KVM: nVMX: Don't emulate instructions in guest mode
+    - KVM: nVMX: Refactor IO bitmap checks into helper function
+    - KVM: nVMX: Check IO instruction VM-exit conditions
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Thu, 27 Feb 2020 23:41:44 -0500
+
+linux (4.4.0-175.205) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-175.205 -proposed tracker (LP: #1863338)
+
+  * run_afpackettests in ubuntu_kernel_selftests failed with "./in_netns.sh:
+    Permission denied" (LP: #1861973)
+    - [Debian] autoreconstruct - add resoration of execute permissions
+
+  * pty03 from pty in ubuntu_ltp failed on Eoan (LP: #1862114)
+    - can, slip: Protect tty->disc_data in write_wakeup and close with RCU
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Fri, 14 Feb 2020 16:27:12 -0300
+
+linux (4.4.0-174.204) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-174.204 -proposed tracker (LP: #1861122)
+
+  * Xenial update: 4.4.211 upstream stable release (LP: #1860681)
+    - hidraw: Return EPOLLOUT from hidraw_poll
+    - HID: hidraw: Fix returning EPOLLOUT from hidraw_poll
+    - HID: hidraw, uhid: Always report EPOLLOUT
+    - cfg80211/mac80211: make ieee80211_send_layer2_update a public function
+    - mac80211: Do not send Layer 2 Update frame before authorization
+    - media: usb:zr364xx:Fix KASAN:null-ptr-deref Read in zr364xx_vidioc_querycap
+    - p54usb: Fix race between disconnect and firmware loading
+    - ALSA: line6: Fix write on zero-sized buffer
+    - ALSA: line6: Fix memory leak at line6_init_pcm() error path
+    - xen: let alloc_xenballooned_pages() fail if not enough memory free
+    - wimax: i2400: fix memory leak
+    - wimax: i2400: Fix memory leak in i2400m_op_rfkill_sw_toggle
+    - ext4: fix use-after-free race with debug_want_extra_isize
+    - ext4: add more paranoia checking in ext4_expand_extra_isize handling
+    - rtc: mt6397: fix alarm register overwrite
+    - iommu: Remove device link to group on failure
+    - gpio: Fix error message on out-of-range GPIO in lookup table
+    - hsr: reset network header when supervision frame is created
+    - cifs: Adjust indentation in smb2_open_file
+    - RDMA/srpt: Report the SCSI residual to the initiator
+    - scsi: enclosure: Fix stale device oops with hot replug
+    - scsi: sd: Clear sdkp->protection_type if disk is reformatted without PI
+    - platform/x86: asus-wmi: Fix keyboard brightness cannot be set to 0
+    - iio: imu: adis16480: assign bias value only if operation succeeded
+    - mei: fix modalias documentation
+    - clk: samsung: exynos5420: Preserve CPU clocks configuration during
+      suspend/resume
+    - compat_ioctl: handle SIOCOUTQNSD
+    - tty: serial: imx: use the sg count from dma_map_sg
+    - tty: serial: pch_uart: correct usage of dma_unmap_sg
+    - media: exynos4-is: Fix recursive locking in isp_video_release()
+    - spi: atmel: fix handling of cs_change set on non-last xfer
+    - rtlwifi: Remove unnecessary NULL check in rtl_regd_init
+    - rtc: msm6242: Fix reading of 10-hour digit
+    - rseq/selftests: Turn off timeout setting
+    - hexagon: work around compiler crash
+    - ocfs2: call journal flush to mark journal as empty after journal recovery
+      when mount
+    - ALSA: seq: Fix racy access for queue timer in proc read
+    - Fix built-in early-load Intel microcode alignment
+    - block: fix an integer overflow in logical block size
+    - USB: serial: simple: Add Motorola Solutions TETRA MTP3xxx and MTP85xx
+    - USB: serial: opticon: fix control-message timeouts
+    - USB: serial: suppress driver bind attributes
+    - USB: serial: ch341: handle unbound port at reset_resume
+    - USB: serial: io_edgeport: add missing active-port sanity check
+    - USB: serial: quatech2: handle unbound ports
+    - scsi: mptfusion: Fix double fetch bug in ioctl
+    - usb: core: hub: Improved device recognition on remote wakeup
+    - x86/efistub: Disable paging at mixed mode entry
+    - mm/page-writeback.c: avoid potential division by zero in wb_min_max_ratio()
+    - net: stmmac: 16KB buffer must be 16 byte aligned
+    - net: stmmac: Enable 16KB buffer size
+    - USB: serial: io_edgeport: use irqsave() in USB's complete callback
+    - USB: serial: io_edgeport: handle unbound ports on URB completion
+    - USB: serial: keyspan: handle unbound ports
+    - scsi: fnic: use kernel's '%pM' format option to print MAC
+    - scsi: fnic: fix invalid stack access
+    - arm64: dts: agilex/stratix10: fix pmu interrupt numbers
+    - netfilter: fix a use-after-free in mtype_destroy()
+    - batman-adv: Fix DAT candidate selection on little endian systems
+    - macvlan: use skb_reset_mac_header() in macvlan_queue_xmit()
+    - r8152: add missing endpoint sanity check
+    - tcp: fix marked lost packets not being retransmitted
+    - net: usb: lan78xx: limit size of local TSO packets
+    - xen/blkfront: Adjust indentation in xlvbd_alloc_gendisk
+    - cw1200: Fix a signedness bug in cw1200_load_firmware()
+    - cfg80211: check for set_wiphy_params
+    - scsi: esas2r: unlock on error in esas2r_nvram_read_direct()
+    - scsi: qla4xxx: fix double free bug
+    - scsi: bnx2i: fix potential use after free
+    - scsi: target: core: Fix a pr_debug() argument
+    - scsi: core: scsi_trace: Use get_unaligned_be*()
+    - perf probe: Fix wrong address verification
+    - regulator: ab8500: Remove SYSCLKREQ from enum ab8505_regulator_id
+    - Linux 4.4.211
+
+  * Xenial update: 4.4.210 upstream stable release (LP: #1859865)
+    - chardev: Avoid potential use-after-free in 'chrdev_open()'
+    - usb: chipidea: host: Disable port power only if previously enabled
+    - ALSA: usb-audio: Apply the sample rate quirk for Bose Companion 5
+    - kernel/trace: Fix do not unregister tracepoints when register
+      sched_migrate_task fail
+    - tracing: Have stack tracer compile when MCOUNT_INSN_SIZE is not defined
+    - HID: Fix slab-out-of-bounds read in hid_field_extract
+    - HID: uhid: Fix returning EPOLLOUT from uhid_char_poll
+    - HID: hid-input: clear unmapped usages
+    - Input: add safety guards to input_set_keycode()
+    - drm/dp_mst: correct the shifting in DP_REMOTE_I2C_READ
+    - can: gs_usb: gs_usb_probe(): use descriptors of current altsetting
+    - can: mscan: mscan_rx_poll(): fix rx path lockup when returning from polling
+      to irq mode
+    - can: can_dropped_invalid_skb(): ensure an initialized headroom in outgoing
+      CAN sk_buffs
+    - staging: vt6656: set usb_set_intfdata on driver fail.
+    - USB: serial: option: add ZLP support for 0x1bc7/0x9010
+    - usb: musb: Disable pullup at init
+    - usb: musb: dma: Correct parameter passed to IRQ handler
+    - staging: rtl8188eu: Add device code for TP-Link TL-WN727N v5.21
+    - tty: link tty and port before configuring it as console
+    - tty: always relink the port
+    - mwifiex: pcie: Fix memory leak in mwifiex_pcie_alloc_cmdrsp_buf
+    - scsi: bfa: release allocated memory in case of error
+    - rtl8xxxu: prevent leaking urb
+    - USB: Fix: Don't skip endpoint descriptors with maxpacket=0
+    - netfilter: arp_tables: init netns pointer in xt_tgchk_param struct
+    - netfilter: ipset: avoid null deref when IPSET_ATTR_LINENO is present
+    - Linux 4.4.210
+
+  * Xenial update: 4.4.209 upstream stable release (LP: #1859640)
+    - PM / devfreq: Don't fail devfreq_dev_release if not in list
+    - RDMA/cma: add missed unregister_pernet_subsys in init failure
+    - scsi: lpfc: Fix memory leak on lpfc_bsg_write_ebuf_set func
+    - scsi: qla2xxx: Don't call qlt_async_event twice
+    - scsi: iscsi: qla4xxx: fix double free in probe
+    - scsi: libsas: stop discovering if oob mode is disconnected
+    - usb: gadget: fix wrong endpoint desc
+    - md: raid1: check rdev before reference in raid1_sync_request func
+    - s390/cpum_sf: Adjust sampling interval to avoid hitting sample limits
+    - s390/cpum_sf: Avoid SBD overflow condition in irq handler
+    - xen/balloon: fix ballooned page accounting without hotplug enabled
+    - xfs: fix mount failure crash on invalid iclog memory access
+    - taskstats: fix data-race
+    - ALSA: ice1724: Fix sleep-in-atomic in Infrasonic Quartet support code
+    - MIPS: Avoid VDSO ABI breakage due to global register variable
+    - locks: print unsigned ino in /proc/locks
+    - dmaengine: Fix access to uninitialized dma_slave_caps
+    - compat_ioctl: block: handle Persistent Reservations
+    - gpiolib: fix up emulated open drain outputs
+    - ALSA: cs4236: fix error return comparison of an unsigned integer
+    - ftrace: Avoid potential division by zero in function profiler
+    - Bluetooth: btusb: fix PM leak in error case of setup
+    - Bluetooth: delete a stray unlock
+    - tty: serial: msm_serial: Fix lockup for sysrq and oops
+    - drm/mst: Fix MST sideband up-reply failure handling
+    - powerpc/pseries/hvconsole: Fix stack overread via udbg
+    - ath9k_htc: Modify byte order for an error message
+    - ath9k_htc: Discard undersized packets
+    - net: add annotations on hh->hh_len lockless accesses
+    - s390/smp: fix physical to logical CPU map for SMT
+    - locking/x86: Remove the unused atomic_inc_short() methd
+    - pstore/ram: Write new dumps to start of recycled zones
+    - locking/spinlock/debug: Fix various data races
+    - netfilter: ctnetlink: netns exit must wait for callbacks
+    - ARM: vexpress: Set-up shared OPP table instead of individual for each CPU
+    - netfilter: uapi: Avoid undefined left-shift in xt_sctp.h
+    - ARM: dts: am437x-gp/epos-evm: fix panel compatible
+    - powerpc: Ensure that swiotlb buffer is allocated from low memory
+    - bnx2x: Do not handle requests from VFs after parity
+    - bnx2x: Fix logic to get total no. of PFs per engine
+    - net: usb: lan78xx: Fix error message format specifier
+    - rfkill: Fix incorrect check to avoid NULL pointer dereference
+    - ASoC: wm8962: fix lambda value
+    - regulator: rn5t618: fix module aliases
+    - kconfig: don't crash on NULL expressions in expr_eq()
+    - parisc: Fix compiler warnings in debug_core.c
+    - llc2: Fix return statement of llc_stat_ev_rx_null_dsap_xid_c (and _test_c)
+    - net: stmmac: dwmac-sunxi: Allow all RGMII modes
+    - net: usb: lan78xx: fix possible skb leak
+    - pkt_sched: fq: do not accept silly TCA_FQ_QUANTUM
+    - sctp: free cmd->obj.chunk for the unprocessed SCTP_CMD_REPLY
+    - tcp: fix "old stuff" D-SACK causing SACK to be treated as D-SACK
+    - vlan: vlan_changelink() should propagate errors
+    - vlan: fix memory leak in vlan_dev_set_egress_priority
+    - vxlan: fix tos value before xmit
+    - macvlan: do not assume mac_header is set in macvlan_broadcast()
+    - USB: core: fix check for duplicate endpoints
+    - USB: serial: option: add Telit ME910G1 0x110a composition
+    - Linux 4.4.209
+
+  * overlayfs : broken access to r/w files (LP: #1851243)
+    - SAUCE: Revert "ovl: modify ovl_permission() to do checks on two inodes"
+
+  * net selftest psock_fanout fails on xenial s390x due to incorrect queue
+    lengths (LP: #1853375)
+    - selftests/net: cleanup unused parameter in psock_fanout
+    - selftests/net: ignore background traffic in psock_fanout
+
+  * multi-zone raid0 corruption (LP: #1850540)
+    - md/raid0: avoid RAID0 data corruption due to layout confusion.
+    - md: add feature flag MD_FEATURE_RAID0_LAYOUT
+    - md/raid0: fix warning message for parameter default_layout
+    - md/raid0: Fix an error message in raid0_make_request()
+    - SAUCE: md/raid0: Link to wiki with guidance on multi-zone RAID0 layout
+      migration
+    - SAUCE: md/raid0: Use kernel specific layout
+
+  * CVE-2019-20096
+    - dccp: Fix memleak in __feat_register_sp
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 29 Jan 2020 00:47:22 -0500
+
+linux (4.4.0-173.203) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-173.203 -proposed tracker (LP: #1859718)
+
+  * CVE-2019-14615
+    - drm/i915/gen9: Clear residual context state on context switch
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Tue, 14 Jan 2020 22:02:26 -0300
+
+linux (4.4.0-172.202) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-172.202 -proposed tracker (LP: #1858594)
+
+  * tools/perf fails to build after Xenial update to 4.4.208 upstream stable
+    release (LP: #1858798)
+    - Revert "perf report: Add warning when libunwind not compiled in"
+
+  * CVE-2019-18885
+    - btrfs: refactor btrfs_find_device() take fs_devices as argument
+    - btrfs: merge btrfs_find_device and find_device
+
+  *  Integrate Intel SGX driver into linux-azure (LP: #1844245)
+    - [Packaging] Add systemd service to load intel_sgx
+
+  * Xenial update: 4.4.208 upstream stable release (LP: #1858462)
+    - btrfs: do not leak reloc root if we fail to read the fs root
+    - btrfs: handle ENOENT in btrfs_uuid_tree_iterate
+    - ALSA: hda/ca0132 - Keep power on during processing DSP response
+    - ALSA: hda/ca0132 - Avoid endless loop
+    - drm: mst: Fix query_payload ack reply struct
+    - iio: light: bh1750: Resolve compiler warning and make code more readable
+    - spi: Add call to spi_slave_abort() function when spidev driver is released
+    - staging: rtl8188eu: fix possible null dereference
+    - rtlwifi: prevent memory leak in rtl_usb_probe
+    - IB/iser: bound protection_sg size by data_sg size
+    - media: am437x-vpfe: Setting STD to current value is not an error
+    - media: i2c: ov2659: fix s_stream return value
+    - media: i2c: ov2659: Fix missing 720p register config
+    - media: ov6650: Fix stored frame format not in sync with hardware
+    - tools/power/cpupower: Fix initializer override in hsw_ext_cstates
+    - usb: renesas_usbhs: add suspend event support in gadget mode
+    - hwrng: omap3-rom - Call clk_disable_unprepare() on exit only if not idled
+    - regulator: max8907: Fix the usage of uninitialized variable in
+      max8907_regulator_probe()
+    - media: flexcop-usb: fix NULL-ptr deref in flexcop_usb_transfer_init()
+    - samples: pktgen: fix proc_cmd command result check logic
+    - mwifiex: pcie: Fix memory leak in mwifiex_pcie_init_evt_ring
+    - media: ti-vpe: vpe: fix a v4l2-compliance warning about invalid pixel format
+    - media: ti-vpe: vpe: fix a v4l2-compliance failure about frame sequence
+      number
+    - media: ti-vpe: vpe: Make sure YUYV is set as default format
+    - extcon: sm5502: Reset registers during initialization
+    - x86/mm: Use the correct function type for native_set_fixmap()
+    - perf report: Add warning when libunwind not compiled in
+    - iio: adc: max1027: Reset the device at probe time
+    - Bluetooth: hci_core: fix init for HCI_USER_CHANNEL
+    - drm/gma500: fix memory disclosures due to uninitialized bytes
+    - x86/ioapic: Prevent inconsistent state when moving an interrupt
+    - arm64: psci: Reduce the waiting time for cpu_psci_cpu_kill()
+    - libata: Ensure ata_port probe has completed before detach
+    - pinctrl: sh-pfc: sh7734: Fix duplicate TCLK1_B
+    - bnx2x: Fix PF-VF communication over multi-cos queues.
+    - spi: img-spfi: fix potential double release
+    - rtlwifi: fix memory leak in rtl92c_set_fw_rsvdpagepkt()
+    - perf probe: Fix to find range-only function instance
+    - perf probe: Fix to list probe event with correct line number
+    - perf probe: Walk function lines in lexical blocks
+    - perf probe: Fix to probe an inline function which has no entry pc
+    - perf probe: Fix to show ranges of variables in functions without entry_pc
+    - perf probe: Fix to show inlined function callsite without entry_pc
+    - perf probe: Skip overlapped location on searching variables
+    - perf probe: Return a better scope DIE if there is no best scope
+    - perf probe: Fix to show calling lines of inlined functions
+    - perf probe: Skip end-of-sequence and non statement lines
+    - perf probe: Filter out instances except for inlined subroutine and
+      subprogram
+    - ath10k: fix get invalid tx rate for Mesh metric
+    - media: pvrusb2: Fix oops on tear-down when radio support is not present
+    - media: si470x-i2c: add missed operations in remove
+    - EDAC/ghes: Fix grain calculation
+    - spi: pxa2xx: Add missed security checks
+    - ASoC: rt5677: Mark reg RT5677_PWR_ANLG2 as volatile
+    - parport: load lowlevel driver if ports not found
+    - cpufreq: Register drivers only after CPU devices have been registered
+    - x86/crash: Add a forward declaration of struct kimage
+    - spi: tegra20-slink: add missed clk_unprepare
+    - btrfs: don't prematurely free work in end_workqueue_fn()
+    - iwlwifi: check kasprintf() return value
+    - fbtft: Make sure string is NULL terminated
+    - crypto: sun4i-ss - Fix 64-bit size_t warnings on sun4i-ss-hash.c
+    - crypto: vmx - Avoid weird build failures
+    - libtraceevent: Fix memory leakage in copy_filter_type
+    - net: phy: initialise phydev speed and duplex sanely
+    - Revert "mmc: sdhci: Fix incorrect switch to HS mode"
+    - usb: xhci: Fix build warning seen with CONFIG_PM=n
+    - btrfs: do not call synchronize_srcu() in inode_tree_del
+    - btrfs: return error pointer from alloc_test_extent_buffer
+    - btrfs: abort transaction after failed inode updates in create_subvol
+    - Btrfs: fix removal logic of the tree mod log that leads to use-after-free
+      issues
+    - ALSA: pcm: Avoid possible info leaks from PCM stream buffers
+    - af_packet: set defaule value for tmo
+    - fjes: fix missed check in fjes_acpi_add
+    - mod_devicetable: fix PHY module format
+    - net: hisilicon: Fix a BUG trigered by wrong bytes_compl
+    - net: nfc: nci: fix a possible sleep-in-atomic-context bug in
+      nci_uart_tty_receive()
+    - net: qlogic: Fix error paths in ql_alloc_large_buffers()
+    - net: usb: lan78xx: Fix suspend/resume PHY register access error
+    - sctp: fully initialize v4 addr in some functions
+    - net: dst: Force 4-byte alignment of dst_metrics
+    - usbip: Fix error path of vhci_recv_ret_submit()
+    - USB: EHCI: Do not return -EPIPE when hub is disconnected
+    - platform/x86: hp-wmi: Make buffer for HPWMI_FEATURE2_QUERY 128 bytes
+    - staging: comedi: gsc_hpdi: check dma_alloc_coherent() return value
+    - ext4: check for directory entries too close to block end
+    - powerpc/irq: fix stack overflow verification
+    - mmc: sdhci-of-esdhc: fix P2020 errata handling
+    - perf probe: Fix to show function entry line as probe-able
+    - scsi: mpt3sas: Fix clear pending bit in ioctl status
+    - scsi: lpfc: Fix locking on mailbox command completion
+    - Input: atmel_mxt_ts - disable IRQ across suspend
+    - iommu/tegra-smmu: Fix page tables in > 4 GiB memory
+    - scsi: target: compare full CHAP_A Algorithm strings
+    - scsi: lpfc: Fix SLI3 hba in loop mode not discovering devices
+    - scsi: csiostor: Don't enable IRQs too early
+    - powerpc/pseries: Mark accumulate_stolen_time() as notrace
+    - dma-debug: add a schedule point in debug_dma_dump_mappings()
+    - clocksource/drivers/asm9260: Add a check for of_clk_get
+    - powerpc/security/book3s64: Report L1TF status in sysfs
+    - jbd2: Fix statistics for the number of logged blocks
+    - scsi: tracing: Fix handling of TRANSFER LENGTH == 0 for READ(6) and WRITE(6)
+    - scsi: lpfc: Fix duplicate unreg_rpi error in port offline flow
+    - clk: qcom: Allow constant ratio freq tables for rcg
+    - irqchip/irq-bcm7038-l1: Enable parent IRQ if necessary
+    - irqchip: ingenic: Error out if IRQ domain creation failed
+    - fs/quota: handle overflows of sysctl fs.quota.* and report as unsigned long
+    - scsi: lpfc: fix: Coverity: lpfc_cmpl_els_rsp(): Null pointer dereferences
+    - scsi: ufs: fix potential bug which ends in system hang
+    - powerpc/pseries/cmm: Implement release() function for sysfs device
+    - powerpc/security: Fix wrong message when RFI Flush is disable
+    - clk: pxa: fix one of the pxa RTC clocks
+    - bcache: at least try to shrink 1 node in bch_mca_scan()
+    - HID: Improve Windows Precision Touchpad detection.
+    - ext4: work around deleting a file with i_nlink == 0 safely
+    - scsi: pm80xx: Fix for SATA device discovery
+    - scsi: target: iscsi: Wait for all commands to finish before freeing a
+      session
+    - gpio: mpc8xxx: Don't overwrite default irq_set_type callback
+    - scripts/kallsyms: fix definitely-lost memory leak
+    - cdrom: respect device capabilities during opening action
+    - perf regs: Make perf_reg_name() return "unknown" instead of NULL
+    - libfdt: define INT32_MAX and UINT32_MAX in libfdt_env.h
+    - s390/cpum_sf: Check for SDBT and SDB consistency
+    - ocfs2: fix passing zero to 'PTR_ERR' warning
+    - kernel: sysctl: make drop_caches write-only
+    - ALSA: hda - Downgrade error message for single-cmd fallback
+    - Make filldir[64]() verify the directory entry filename is valid
+    - filldir[64]: remove WARN_ON_ONCE() for bad directory entries
+    - net: davinci_cpdma: use dma_addr_t for DMA address
+    - netfilter: ebtables: compat: reject all padding in matches/watchers
+    - 6pack,mkiss: fix possible deadlock
+    - netfilter: bridge: make sure to pull arp header in br_nf_forward_arp()
+    - net: icmp: fix data-race in cmp_global_allow()
+    - hrtimer: Annotate lockless access to timer->state
+    - mmc: sdhci: Update the tuning failed messages to pr_debug level
+    - tcp: do not send empty skb from tcp_write_xmit()
+    - Linux 4.4.208
+
+  * Xenial update: 4.4.207 upstream stable release (LP: #1858489)
+    - x86/apic/32: Avoid bogus LDR warnings
+    - usb: gadget: u_serial: add missing port entry locking
+    - tty: serial: msm_serial: Fix flow control
+    - x86/PCI: Avoid AMD FCH XHCI USB PME# from D0 defect
+    - serial: serial_core: Perform NULL checks for break_ctl ops
+    - serial: ifx6x60: add missed pm_runtime_disable
+    - autofs: fix a leak in autofs_expire_indirect()
+    - NFC: nxp-nci: Fix NULL pointer dereference after I2C communication error
+    - Input: cyttsp4_core - fix use after free bug
+    - ALSA: pcm: Fix stream lock usage in snd_pcm_period_elapsed()
+    - rsxx: add missed destroy_workqueue calls in remove
+    - net: ep93xx_eth: fix mismatch of request_mem_region in remove
+    - serial: core: Allow processing sysrq at port unlock time
+    - iwlwifi: mvm: Send non offchannel traffic via AP sta
+    - ARM: 8813/1: Make aligned 2-byte getuser()/putuser() atomic on ARMv6+
+    - extcon: max8997: Fix lack of path setting in USB device mode
+    - clk: rockchip: fix rk3188 sclk_smc gate data
+    - clk: rockchip: fix rk3188 sclk_mac_lbtest parameter ordering
+    - dlm: fix missing idr_destroy for recover_idr
+    - MIPS: SiByte: Enable ZONE_DMA32 for LittleSur
+    - scsi: zfcp: drop default switch case which might paper over missing case
+    - pinctrl: qcom: ssbi-gpio: fix gpio-hog related boot issues
+    - Staging: iio: adt7316: Fix i2c data reading, set the data field
+    - regulator: Fix return value of _set_load() stub
+    - MIPS: OCTEON: octeon-platform: fix typing
+    - math-emu/soft-fp.h: (_FP_ROUND_ZERO) cast 0 to void to fix warning
+    - rtc: max8997: Fix the returned value in case of error in
+      'max8997_rtc_read_alarm()'
+    - rtc: dt-binding: abx80x: fix resistance scale
+    - ARM: dts: exynos: Use Samsung SoC specific compatible for DWC2 module
+    - dmaengine: coh901318: Fix a double-lock bug
+    - dmaengine: coh901318: Remove unused variable
+    - ACPI: fix acpi_find_child_device() invocation in acpi_preset_companion()
+    - dma-mapping: fix return type of dma_set_max_seg_size()
+    - altera-stapl: check for a null key before strcasecmp'ing it
+    - serial: imx: fix error handling in console_setup
+    - i2c: imx: don't print error message on probe defer
+    - dlm: NULL check before kmem_cache_destroy is not needed
+    - nfsd: fix a warning in __cld_pipe_upcall()
+    - ARM: OMAP1/2: fix SoC name printing
+    - net/x25: fix called/calling length calculation in x25_parse_address_block
+    - net/x25: fix null_x25_address handling
+    - ARM: dts: mmp2: fix the gpio interrupt cell number
+    - tcp: fix off-by-one bug on aborting window-probing socket
+    - modpost: skip ELF local symbols during section mismatch check
+    - kbuild: fix single target build for external module
+    - ARM: dts: pxa: clean up USB controller nodes
+    - dlm: fix invalid cluster name warning
+    - powerpc/math-emu: Update macros from GCC
+    - MIPS: OCTEON: cvmx_pko_mem_debug8: use oldest forward compatible definition
+    - nfsd: Return EPERM, not EACCES, in some SETATTR cases
+    - mlx4: Use snprintf instead of complicated strcpy
+    - ARM: dts: sunxi: Fix PMU compatible strings
+    - sched/fair: Scale bandwidth quota and period without losing quota/period
+      ratio precision
+    - fuse: verify nlink
+    - fuse: verify attributes
+    - ALSA: pcm: oss: Avoid potential buffer overflows
+    - Input: goodix - add upside-down quirk for Teclast X89 tablet
+    - CIFS: Fix SMB2 oplock break processing
+    - tty: vt: keyboard: reject invalid keycodes
+    - can: slcan: Fix use-after-free Read in slcan_open
+    - jbd2: Fix possible overflow in jbd2_log_space_left()
+    - drm/i810: Prevent underflow in ioctl
+    - KVM: x86: do not modify masked bits of shared MSRs
+    - KVM: x86: fix presentation of TSX feature in ARCH_CAPABILITIES
+    - crypto: crypto4xx - fix double-free in crypto4xx_destroy_sdr
+    - spi: atmel: Fix CS high support
+    - RDMA/qib: Validate ->show()/store() callbacks before calling them
+    - thermal: Fix deadlock in thermal thermal_zone_device_check
+    - Revert "KVM: x86: fix out-of-bounds write in KVM_GET_EMULATED_CPUID
+      (CVE-2019-19332)"
+    - KVM: x86: fix out-of-bounds write in KVM_GET_EMULATED_CPUID (CVE-2019-19332)
+    - appletalk: Fix potential NULL pointer dereference in unregister_snap_client
+    - appletalk: Set error code if register_snap_client failed
+    - ALSA: hda - Fix pending unsol events at shutdown
+    - sched/core: Allow putting thread_info into task_struct
+    - sched/core: Add try_get_task_stack() and put_task_stack()
+    - sched/core, x86: Make struct thread_info arch specific again
+    - fs/proc: Stop reporting eip and esp in /proc/PID/stat
+    - fs/proc: Report eip/esp in /prod/PID/stat for coredumping
+    - proc: fix coredump vs read /proc/*/stat race
+    - fs/proc/array.c: allow reporting eip/esp for all coredumping threads
+    - usb: gadget: configfs: Fix missing spin_lock_init()
+    - usb: Allow USB device to be warm reset in suspended state
+    - staging: rtl8188eu: fix interface sanity check
+    - staging: rtl8712: fix interface sanity check
+    - staging: gigaset: fix general protection fault on probe
+    - staging: gigaset: fix illegal free on probe errors
+    - staging: gigaset: add endpoint-type sanity check
+    - xhci: Increase STS_HALT timeout in xhci_suspend()
+    - iio: humidity: hdc100x: fix IIO_HUMIDITYRELATIVE channel reporting
+    - USB: atm: ueagle-atm: add missing endpoint check
+    - USB: idmouse: fix interface sanity checks
+    - USB: serial: io_edgeport: fix epic endpoint lookup
+    - USB: adutux: fix interface sanity check
+    - usb: core: urb: fix URB structure initialization function
+    - usb: mon: Fix a deadlock in usbmon between mmap and read
+    - mtd: spear_smi: Fix Write Burst mode
+    - virtio-balloon: fix managed page counts when migrating pages between zones
+    - btrfs: check page->mapping when loading free space cache
+    - btrfs: Remove btrfs_bio::flags member
+    - rtlwifi: rtl8192de: Fix missing code to retrieve RX buffer address
+    - rtlwifi: rtl8192de: Fix missing callback that tests for hw release of buffer
+    - rtlwifi: rtl8192de: Fix missing enable interrupt flag
+    - lib: raid6: fix awk build warnings
+    - workqueue: Fix spurious sanity check failures in destroy_workqueue()
+    - workqueue: Fix pwq ref leak in rescuer_thread()
+    - ASoC: Jack: Fix NULL pointer dereference in snd_soc_jack_report
+    - blk-mq: avoid sysfs buffer overflow with too many CPU cores
+    - cgroup: pids: use atomic64_t for pids->limit
+    - ar5523: check NULL before memcpy() in ar5523_cmd()
+    - media: bdisp: fix memleak on release
+    - media: radio: wl1273: fix interrupt masking on release
+    - cpuidle: Do not unset the driver if it is there already
+    - ACPI: OSL: only free map once in osl.c
+    - ACPI: bus: Fix NULL pointer check in acpi_bus_get_private_data()
+    - ACPI: PM: Avoid attaching ACPI PM domain to certain devices
+    - pinctrl: samsung: Fix device node refcount leaks in S3C24xx wakeup
+      controller init
+    - pinctrl: samsung: Fix device node refcount leaks in init code
+    - powerpc: Allow 64bit VDSO __kernel_sync_dicache to work across ranges >4GB
+    - video/hdmi: Fix AVI bar unpack
+    - quota: Check that quota is not dirty before release
+    - quota: fix livelock in dquot_writeback_dquots
+    - scsi: zfcp: trace channel log even for FCP command responses
+    - usb: xhci: only set D3hot for pci device
+    - xhci: Fix memory leak in xhci_add_in_port()
+    - xhci: make sure interrupts are restored to correct state
+    - iio: adis16480: Add debugfs_reg_access entry
+    - Btrfs: fix negative subv_writers counter and data space leak after buffered
+      write
+    - scsi: lpfc: Cap NPIV vports to 256
+    - e100: Fix passing zero to 'PTR_ERR' warning in e100_load_ucode_wait
+    - x86/MCE/AMD: Turn off MC4_MISC thresholding on all family 0x15 models
+    - ARM: dts: omap3-tao3530: Fix incorrect MMC card detection GPIO polarity
+    - pinctrl: samsung: Fix device node refcount leaks in S3C64xx wakeup
+      controller init
+    - scsi: qla2xxx: Fix DMA unmap leak
+    - scsi: qla2xxx: Fix qla24xx_process_bidir_cmd()
+    - scsi: qla2xxx: Always check the qla2x00_wait_for_hba_online() return value
+    - powerpc: Fix vDSO clock_getres()
+    - mm/shmem.c: cast the type of unmap_start to u64
+    - blk-mq: make sure that line break can be printed
+    - workqueue: Fix missing kfree(rescuer) in destroy_workqueue()
+    - sunrpc: fix crash when cache_head become valid before update
+    - kernel/module.c: wakeup processes in module_wq on module unload
+    - net: bridge: deny dev_set_mac_address() when unregistering
+    - tcp: md5: fix potential overestimation of TCP option space
+    - tipc: fix ordering of tipc module init and exit routine
+    - inet: protect against too small mtu values.
+    - tcp: fix rejected syncookies due to stale timestamps
+    - tcp: tighten acceptance of ACKs not matching a child socket
+    - tcp: Protect accesses to .ts_recent_stamp with {READ,WRITE}_ONCE()
+    - net: ethernet: ti: cpsw: fix extra rx interrupt
+    - PCI: Fix Intel ACS quirk UPDCR register address
+    - PCI/MSI: Fix incorrect MSI-X masking on resume
+    - xtensa: fix TLB sanity checker
+    - CIFS: Respect O_SYNC and O_DIRECT flags during reconnect
+    - ARM: dts: s3c64xx: Fix init order of clock providers
+    - ARM: tegra: Fix FLOW_CTLR_HALT register clobbering by tegra_resume()
+    - vfio/pci: call irq_bypass_unregister_producer() before freeing irq
+    - dm btree: increase rebalance threshold in __rebalance2()
+    - drm/radeon: fix r1xx/r2xx register checker for POT textures
+    - xhci: fix USB3 device initiated resume race with roothub autosuspend
+    - net: stmmac: use correct DMA buffer size in the RX descriptor
+    - net: stmmac: don't stop NAPI processing when dropping a packet
+    - Linux 4.4.207
+
+  * efivarfs test in ubuntu_kernel_selftest failed on the second run
+    (LP: #1809704)
+    - selftests: efivarfs: return Kselftest Skip code for skipped tests
+    - selftests/efivarfs: clean up test files from test_create*()
+
+  * cifs: kernel NULL pointer dereference, address: 0000000000000038
+    (LP: #1856949)
+    - CIFS: Fix NULL-pointer dereference in smb2_push_mandatory_locks
+
+  * CVE-2019-19332
+    - KVM: x86: fix out-of-bounds write in KVM_GET_EMULATED_CPUID (CVE-2019-19332)
+
+  * CVE-2019-19062
+    - crypto: user - fix memory leak in crypto_report
+
+  * [Hyper-V] KVP daemon fails to start on first boot of disco VM (LP: #1820063)
+    - [Packaging] bind hv_kvp_daemon startup to hv_kvp device
+
+  * False positive test result in run_afpackettests from net in
+    ubuntu_kernel_selftest  (LP: #1825778)
+    - selftests/net: correct the return value for run_afpackettests
+
+  * Xenial update: 4.4.206 upstream stable release (LP: #1855313)
+    - ASoC: compress: fix unsigned integer overflow check
+    - ASoC: kirkwood: fix external clock probe defer
+    - clk: samsung: exynos5420: Preserve PLL configuration during suspend/resume
+    - reset: fix reset_control_ops kerneldoc comment
+    - can: peak_usb: report bus recovery as well
+    - can: c_can: D_CAN: c_can_chip_config(): perform a sofware reset on open
+    - scripts/gdb: fix debugging modules compiled with hot/cold partitioning
+    - block: drbd: remove a stray unlock in __drbd_send_protocol()
+    - scsi: lpfc: Fix dif and first burst use in write commands
+    - ARM: debug-imx: only define DEBUG_IMX_UART_PORT if needed
+    - ARM: dts: imx53-voipac-dmm-668: Fix memory node duplication
+    - parisc: Fix serio address output
+    - parisc: Fix HP SDC hpa address output
+    - arm64: smp: Handle errors reported by the firmware
+    - PM / AVS: SmartReflex: NULL check before some freeing functions is not
+      needed
+    - ARM: ks8695: fix section mismatch warning
+    - ACPI / LPSS: Ignore acpi_device_fix_up_power() return value
+    - crypto: user - support incremental algorithm dumps
+    - mwifiex: fix potential NULL dereference and use after free
+    - mwifiex: debugfs: correct histogram spacing, formatting
+    - rtl818x: fix potential use after free
+    - xfs: require both realtime inodes to mount
+    - ubi: Put MTD device after it is not used
+    - ubi: Do not drop UBI device reference before using
+    - microblaze: adjust the help to the real behavior
+    - microblaze: move "... is ready" messages to arch/microblaze/Makefile
+    - gpiolib: Fix return value of gpio_to_desc() stub if !GPIOLIB
+    - VSOCK: bind to random port for VMADDR_PORT_ANY
+    - btrfs: only track ref_heads in delayed_ref_updates
+    - xen/pciback: Check dev_data before using it
+    - KVM: s390: unregister debug feature on failing arch init
+    - pinctrl: sh-pfc: sh7264: Fix PFCR3 and PFCR0 register configuration
+    - pinctrl: sh-pfc: sh7734: Fix shifted values in IPSR10
+    - HID: doc: fix wrong data structure reference for UHID_OUTPUT
+    - gfs2: take jdata unstuff into account in do_grow
+    - xfs: Align compat attrlist_by_handle with native implementation.
+    - IB/qib: Fix an error code in qib_sdma_verbs_send()
+    - powerpc/book3s/32: fix number of bats in p/v_block_mapped()
+    - powerpc/xmon: fix dump_segments()
+    - drivers/regulator: fix a missing check of return value
+    - serial: max310x: Fix tx_empty() callback
+    - openrisc: Fix broken paths to arch/or32
+    - RDMA/srp: Propagate ib_post_send() failures to the SCSI mid-layer
+    - scsi: qla2xxx: deadlock by configfs_depend_item
+    - scsi: csiostor: fix incorrect dma device in case of vport
+    - ath6kl: Only use match sets when firmware supports it
+    - ath6kl: Fix off by one error in scan completion
+    - powerpc/prom: fix early DEBUG messages
+    - powerpc/mm: Make NULL pointer deferences explicit on bad page faults.
+    - powerpc/44x/bamboo: Fix PCI range
+    - drbd: reject attach of unsuitable uuids even if connected
+    - drbd: fix print_st_err()'s prototype to match the definition
+    - regulator: tps65910: fix a missing check of return value
+    - net/net_namespace: Check the return value of register_pernet_subsys()
+    - um: Make GCOV depend on !KCOV
+    - net: stmicro: fix a missing check of clk_prepare
+    - atl1e: checking the status of atl1e_write_phy_reg
+    - tipc: fix a missing check of genlmsg_put
+    - ocfs2: clear journal dirty flag after shutdown journal
+    - lib/genalloc.c: use vzalloc_node() to allocate the bitmap
+    - lib/genalloc.c: include vmalloc.h
+    - mtd: Check add_mtd_device() ret code
+    - tipc: fix memory leak in tipc_nl_compat_publ_dump
+    - net/core/neighbour: tell kmemleak about hash tables
+    - net/core/neighbour: fix kmemleak minimal reference count for hash tables
+    - sfc: suppress duplicate nvmem partition types in efx_ef10_mtd_probe
+    - decnet: fix DN_IFREQ_SIZE
+    - tipc: fix skb may be leaky in tipc_link_input
+    - sfc: initialise found bitmap in efx_ef10_mtd_probe
+    - net: fix possible overflow in __sk_mem_raise_allocated()
+    - net: dev: Use unsigned integer as an argument to left-shift
+    - scsi: libsas: Support SATA PHY connection rate unmatch fixing during
+      discovery
+    - ACPI / APEI: Switch estatus pool to use vmalloc memory
+    - scsi: libsas: Check SMP PHY control function result
+    - mtd: Remove a debug trace in mtdpart.c
+    - staging: rtl8192e: fix potential use after free
+    - USB: serial: ftdi_sio: add device IDs for U-Blox C099-F9P
+    - mei: bus: prefix device names on bus with the bus name
+    - media: v4l2-ctrl: fix flags for DO_WHITE_BALANCE
+    - net: macb: fix error format in dev_err()
+    - pwm: Clear chip_data in pwm_put()
+    - macvlan: schedule bc_work even if error
+    - openvswitch: fix flow command message size
+    - slip: Fix use-after-free Read in slip_open
+    - openvswitch: drop unneeded BUG_ON() in ovs_flow_cmd_build_info()
+    - openvswitch: remove another BUG_ON()
+    - tipc: fix link name length check
+    - net: sched: fix `tc -s class show` no bstats on class with nolock subqueues
+    - HID: core: check whether Usage Page item is after Usage ID items
+    - hwrng: stm32 - fix unbalanced pm_runtime_enable
+    - platform/x86: hp-wmi: Fix ACPI errors caused by too small buffer
+    - Linux 4.4.206
+    - [Config] updateconfigs for 4.4.206
+
+  * Xenial update: 4.4.205 upstream stable release (LP: #1854857)
+    - Revert "sock: Reset dst when changing sk_mark via setsockopt"
+    - Linux 4.4.205
+
+  * Xenial update: 4.4.204 upstream stable release (LP: #1854855)
+    - net/mlx4_en: fix mlx4 ethtool -N insertion
+    - sfc: Only cancel the PPS workqueue if it exists
+    - net/sched: act_pedit: fix WARN() in the traffic path
+    - net: rtnetlink: prevent underflows in do_setvfinfo()
+    - Revert "fs: ocfs2: fix possible null-pointer dereferences in
+      ocfs2_xa_prepare_entry()"
+    - mm/ksm.c: don't WARN if page is still mapped in remove_stable_node()
+    - asus-wmi: Create quirk for airplane_mode LED
+    - asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UF
+    - asus-wmi: Add quirk_no_rfkill for the Asus N552VW
+    - asus-wmi: Add quirk_no_rfkill for the Asus U303LB
+    - asus-wmi: Add quirk_no_rfkill for the Asus Z550MA
+    - platform/x86: asus-wmi: Filter buggy scan codes on ASUS Q500A
+    - platform/x86: asus-wmi: fix asus ux303ub brightness issue
+    - platform/x86: asus-wmi: Set specified XUSB2PR value for X550LB
+    - asus-wmi: provide access to ALS control
+    - platform/x86: asus-wmi: try to set als by default
+    - platform/x86: asus-nb-wmi: Support ALS on the Zenbook UX430UQ
+    - platform/x86: asus-wmi: add SERIO_I8042 dependency
+    - mwifiex: Fix NL80211_TX_POWER_LIMITED
+    - ALSA: isight: fix leak of reference to firewire unit in error path of .probe
+      callback
+    - printk: fix integer overflow in setup_log_buf()
+    - gfs2: Fix marking bitmaps non-full
+    - synclink_gt(): fix compat_ioctl()
+    - powerpc: Fix signedness bug in update_flash_db()
+    - powerpc/eeh: Fix use of EEH_PE_KEEP on wrong field
+    - brcmsmac: AP mode: update beacon when TIM changes
+    - spi: sh-msiof: fix deferred probing
+    - mmc: mediatek: fix cannot receive new request when msdc_cmd_is_ready fail
+    - btrfs: handle error of get_old_root
+    - gsmi: Fix bug in append_to_eventlog sysfs handler
+    - misc: mic: fix a DMA pool free failure
+    - amiflop: clean up on errors during setup
+    - scsi: ips: fix missing break in switch
+    - KVM/x86: Fix invvpid and invept register operand size in 64-bit mode
+    - scsi: isci: Use proper enumerated type in atapi_d2h_reg_frame_handler
+    - scsi: isci: Change sci_controller_start_task's return type to sci_status
+    - scsi: iscsi_tcp: Explicitly cast param in iscsi_sw_tcp_host_get_param
+    - clk: mmp2: fix the clock id for sdh2_clk and sdh3_clk
+    - scsi: dc395x: fix dma API usage in srb_done
+    - scsi: dc395x: fix DMA API usage in sg_update_list
+    - net: fix warning in af_unix
+    - kprobes, x86/ptrace.h: Make regs_get_kernel_stack_nth() not fault on bad
+      stack
+    - ALSA: i2c/cs8427: Fix int to char conversion
+    - macintosh/windfarm_smu_sat: Fix debug output
+    - USB: misc: appledisplay: fix backlight update_status return code
+    - SUNRPC: Fix a compile warning for cmpxchg64()
+    - atm: zatm: Fix empty body Clang warnings
+    - s390/perf: Return error when debug_register fails
+    - spi: omap2-mcspi: Set FIFO DMA trigger level to word length
+    - sparc: Fix parport build warnings.
+    - ceph: fix dentry leak in ceph_readdir_prepopulate
+    - rtc: s35390a: Change buf's type to u8 in s35390a_init
+    - mISDN: Fix type of switch control variable in ctrl_teimanager
+    - qlcnic: fix a return in qlcnic_dcb_get_capability()
+    - mfd: mc13xxx-core: Fix PMIC shutdown when reading ADC values
+    - mfd: max8997: Enale irq-wakeup unconditionally
+    - selftests/ftrace: Fix to test kprobe $comm arg only if available
+    - thermal: rcar_thermal: Prevent hardware access during system suspend
+    - sparc64: Rework xchg() definition to avoid warnings.
+    - fs/ocfs2/dlm/dlmdebug.c: fix a sleep-in-atomic-context bug in
+      dlm_print_one_mle()
+    - mm/page-writeback.c: fix range_cyclic writeback vs writepages deadlock
+    - um: Make line/tty semantics use true write IRQ
+    - linux/bitmap.h: handle constant zero-size bitmaps correctly
+    - linux/bitmap.h: fix type of nbits in bitmap_shift_right()
+    - hfsplus: fix BUG on bnode parent update
+    - hfs: fix BUG on bnode parent update
+    - hfsplus: prevent btree data loss on ENOSPC
+    - hfs: prevent btree data loss on ENOSPC
+    - hfsplus: fix return value of hfsplus_get_block()
+    - hfs: fix return value of hfs_get_block()
+    - fs/hfs/extent.c: fix array out of bounds read of array extent
+    - igb: shorten maximum PHC timecounter update interval
+    - ntb_netdev: fix sleep time mismatch
+    - ntb: intel: fix return value for ndev_vec_mask()
+    - ocfs2: don't put and assigning null to bh allocated outside
+    - ocfs2: fix clusters leak in ocfs2_defrag_extent()
+    - net: do not abort bulk send on BQL status
+    - sched/fair: Don't increase sd->balance_interval on newidle balance
+    - audit: print empty EXECVE args
+    - wlcore: Fix the return value in case of error in
+      'wlcore_vendor_cmd_smart_config_start()'
+    - rtl8xxxu: Fix missing break in switch
+    - brcmsmac: never log "tid x is not agg'able" by default
+    - wireless: airo: potential buffer overflow in sprintf()
+    - rtlwifi: rtl8192de: Fix misleading REG_MCUFWDL information
+    - scsi: mpt3sas: Fix Sync cache command failure during driver unload
+    - scsi: mpt3sas: Fix driver modifying persistent data in Manufacturing page11
+    - scsi: megaraid_sas: Fix msleep granularity
+    - scsi: lpfc: fcoe: Fix link down issue after 1000+ link bounces
+    - dlm: fix invalid free
+    - dlm: don't leak kernel pointer to userspace
+    - net: bcmgenet: return correct value 'ret' from bcmgenet_power_down
+    - sock: Reset dst when changing sk_mark via setsockopt
+    - pinctrl: qcom: spmi-gpio: fix gpio-hog related boot issues
+    - pinctrl: zynq: Use define directive for PIN_CONFIG_IO_STANDARD
+    - PCI: keystone: Use quirk to limit MRRS for K2G
+    - spi: omap2-mcspi: Fix DMA and FIFO event trigger size mismatch
+    - IB/hfi1: Ensure full Gen3 speed in a Gen4 system
+    - Bluetooth: Fix invalid-free in bcsp_close()
+    - ath9k_hw: fix uninitialized variable data
+    - dm: use blk_set_queue_dying() in __dm_destroy()
+    - arm64: fix for bad_mode() handler to always result in panic
+    - cpufreq: Skip cpufreq resume if it's not suspended
+    - ocfs2: remove ocfs2_is_o2cb_active()
+    - mmc: block: Fix tag condition with packed writes
+    - ARC: perf: Accommodate big-endian CPU
+    - x86/insn: Fix awk regexp warnings
+    - x86/speculation: Fix incorrect MDS/TAA mitigation status
+    - x86/speculation: Fix redundant MDS mitigation message
+    - media: vivid: Set vid_cap_streaming and vid_out_streaming to true
+    - media: vivid: Fix wrong locking that causes race conditions on streaming
+      stop
+    - cpufreq: Add NULL checks to show() and store() methods of cpufreq
+    - media: b2c2-flexcop-usb: add sanity checking
+    - media: cxusb: detect cxusb_ctrl_msg error in query
+    - media: imon: invalid dereference in imon_touch_event
+    - virtio_console: reset on out of memory
+    - virtio_console: don't tie bufs to a vq
+    - virtio_console: allocate inbufs in add_port() only if it is needed
+    - virtio_console: fix uninitialized variable use
+    - virtio_console: drop custom control queue cleanup
+    - virtio_console: move removal code
+    - usb-serial: cp201x: support Mark-10 digital force gauge
+    - appledisplay: fix error handling in the scheduled work
+    - USB: serial: mos7840: add USB ID to support Moxa UPort 2210
+    - USB: serial: mos7720: fix remote wakeup
+    - USB: serial: mos7840: fix remote wakeup
+    - USB: serial: option: add support for DW5821e with eSIM support
+    - USB: serial: option: add support for Foxconn T77W968 LTE modules
+    - staging: comedi: usbduxfast: usbduxfast_ai_cmdtest rounding error
+    - Linux 4.4.204
+
+ -- Connor Kuehl <connor.kuehl@canonical.com>  Wed, 08 Jan 2020 09:26:38 -0800
+
+linux (4.4.0-171.200) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-171.200 -proposed tracker (LP: #1854835)
+
+  * CVE-2019-14901
+    - SAUCE: mwifiex: Fix heap overflow in mmwifiex_process_tdls_action_frame()
+
+  * CVE-2019-14896 // CVE-2019-14897
+    - SAUCE: libertas: Fix two buffer overflows at parsing bss descriptor
+
+  * CVE-2019-14895
+    - SAUCE: mwifiex: fix possible heap overflow in mwifiex_process_country_ie()
+
+  * CVE-2019-18660: patches for Ubuntu (LP: #1853142) // CVE-2019-18660
+    - powerpc/64s: support nospectre_v2 cmdline option
+    - powerpc/book3s64: Fix link stack flush on context switch
+    - KVM: PPC: Book3S HV: Flush link stack on guest exit to host kernel
+
+  * cloudimg: no iavf/i40evf module so no network available with SR-IOV enabled
+    cloud (LP: #1848481)
+    - [Packaging]: include i40evf in generic
+
+  * update ENA driver for DIMLIB dynamic interrupt moderation (LP: #1853180)
+    - net: ena: fix bug that might cause hang after consecutive open/close
+      interface.
+    - net: ena: add intr_moder_rx_interval to struct ena_com_dev and use it
+    - net: ena: switch to dim algorithm for rx adaptive interrupt moderation
+    - net: ena: reimplement set/get_coalesce()
+    - net: ena: enable the interrupt_moderation in driver_supported_features
+    - net: ena: remove code duplication in
+      ena_com_update_nonadaptive_moderation_interval _*()
+    - net: ena: remove old adaptive interrupt moderation code from ena_netdev
+    - net: ena: remove ena_restore_ethtool_params() and relevant fields
+    - net: ena: remove all old adaptive rx interrupt moderation code from ena_com
+    - net: ena: fix update of interrupt moderation register
+    - net: ena: fix retrieval of nonadaptive interrupt moderation intervals
+    - net: ena: fix incorrect update of intr_delay_resolution
+    - net: ena: Select DIMLIB for ENA_ETHERNET
+    - SAUCE: net: ena: fix issues in setting interrupt moderation params in
+      ethtool
+    - SAUCE: net: ena: fix too long default tx interrupt moderation interval
+
+  * backport DIMLIB (lib/dim/) to pre-5.2 kernels (LP: #1852637)
+    - include/linux/bitops.h: introduce BITS_PER_TYPE
+    - linux/kernel.h: move DIV_ROUND_DOWN_ULL() macro
+    - [Config] enable DIMLIB
+    - linux/dim: import DIMLIB (lib/dim/)
+    - SAUCE: linux/dim: avoid library object filename clash
+
+  * Enable framebuffer fonts auto selection for HighDPI screen (LP: #1851623)
+    - fonts: Fix coding style
+    - fonts: Prefer a bigger font for high resolution screens
+
+  * Xenial update: 4.4.203 upstream stable release (LP: #1853881)
+    - slip: Fix memory leak in slip_open error path
+    - ax88172a: fix information leak on short answers
+    - ALSA: usb-audio: Fix missing error check at mixer resolution test
+    - ALSA: usb-audio: not submit urb for stopped endpoint
+    - Input: ff-memless - kill timer in destroy()
+    - ecryptfs_lookup_interpose(): lower_dentry->d_inode is not stable
+    - ecryptfs_lookup_interpose(): lower_dentry->d_parent is not stable either
+    - iommu/vt-d: Fix QI_DEV_IOTLB_PFSID and QI_DEV_EIOTLB_PFSID macros
+    - mm: memcg: switch to css_tryget() in get_mem_cgroup_from_mm()
+    - mm: hugetlb: switch to css_tryget() in hugetlb_cgroup_charge_cgroup()
+    - mmc: sdhci-of-at91: fix quirk2 overwrite
+    - iio: dac: mcp4922: fix error handling in mcp4922_write_raw
+    - ALSA: pcm: signedness bug in snd_pcm_plug_alloc()
+    - ARM: dts: at91/trivial: Fix USART1 definition for at91sam9g45
+    - ALSA: seq: Do error checks at creating system ports
+    - gfs2: Don't set GFS2_RDF_UPTODATE when the lvb is updated
+    - ASoC: dpcm: Properly initialise hw->rate_max
+    - MIPS: BCM47XX: Enable USB power on Netgear WNDR3400v3
+    - ARM: dts: exynos: Fix sound in Snow-rev5 Chromebook
+    - i40e: use correct length for strncpy
+    - i40e: hold the rtnl lock on clearing interrupt scheme
+    - i40e: Prevent deleting MAC address from VF when set by PF
+    - ARM: dts: pxa: fix power i2c base address
+    - rtl8187: Fix warning generated when strncpy() destination length matches the
+      sixe argument
+    - net: lan78xx: Bail out if lan78xx_get_endpoints fails
+    - ASoC: sgtl5000: avoid division by zero if lo_vag is zero
+    - ath10k: wmi: disable softirq's while calling ieee80211_rx
+    - mips: txx9: fix iounmap related issue
+    - of: make PowerMac cache node search conditional on CONFIG_PPC_PMAC
+    - ARM: dts: omap3-gta04: give spi_lcd node a label so that we can overwrite in
+      other DTS files
+    - ARM: dts: omap3-gta04: tvout: enable as display1 alias
+    - ARM: dts: omap3-gta04: make NAND partitions compatible with recent U-Boot
+    - ARM: dts: omap3-gta04: keep vpll2 always on
+    - dmaengine: dma-jz4780: Further residue status fix
+    - signal: Always ignore SIGKILL and SIGSTOP sent to the global init
+    - signal: Properly deliver SIGILL from uprobes
+    - signal: Properly deliver SIGSEGV from x86 uprobes
+    - scsi: sym53c8xx: fix NULL pointer dereference panic in sym_int_sir()
+    - ARM: imx6: register pm_power_off handler if "fsl,pmic-stby-poweroff" is set
+    - scsi: pm80xx: Corrected dma_unmap_sg() parameter
+    - scsi: pm80xx: Fixed system hang issue during kexec boot
+    - kprobes: Don't call BUG_ON() if there is a kprobe in use on free list
+    - nvmem: core: return error code instead of NULL from nvmem_device_get
+    - media: fix: media: pci: meye: validate offset to avoid arbitrary access
+    - ALSA: intel8x0m: Register irq handler after register initializations
+    - pinctrl: at91-pio4: fix has_config check in atmel_pctl_dt_subnode_to_map()
+    - llc: avoid blocking in llc_sap_close()
+    - powerpc/vdso: Correct call frame information
+    - ARM: dts: socfpga: Fix I2C bus unit-address error
+    - pinctrl: at91: don't use the same irqchip with multiple gpiochips
+    - cxgb4: Fix endianness issue in t4_fwcache()
+    - power: supply: ab8500_fg: silence uninitialized variable warnings
+    - power: supply: max8998-charger: Fix platform data retrieval
+    - kernfs: Fix range checks in kernfs_get_target_path
+    - s390/qeth: invoke softirqs after napi_schedule()
+    - PCI/ACPI: Correct error message for ASPM disabling
+    - serial: mxs-auart: Fix potential infinite loop
+    - powerpc/iommu: Avoid derefence before pointer check
+    - powerpc/64s/hash: Fix stab_rr off by one initialization
+    - powerpc/pseries: Disable CPU hotplug across migrations
+    - libfdt: Ensure INT_MAX is defined in libfdt_env.h
+    - power: supply: twl4030_charger: fix charging current out-of-bounds
+    - power: supply: twl4030_charger: disable eoc interrupt on linear charge
+    - net: toshiba: fix return type of ndo_start_xmit function
+    - net: xilinx: fix return type of ndo_start_xmit function
+    - net: broadcom: fix return type of ndo_start_xmit function
+    - net: amd: fix return type of ndo_start_xmit function
+    - usb: chipidea: Fix otg event handler
+    - ARM: dts: am335x-evm: fix number of cpsw
+    - ARM: dts: ux500: Correct SCU unit address
+    - ARM: dts: ux500: Fix LCDA clock line muxing
+    - ARM: dts: ste: Fix SPI controller node names
+    - cpufeature: avoid warning when compiling with clang
+    - bnx2x: Ignore bandwidth attention in single function mode
+    - net: micrel: fix return type of ndo_start_xmit function
+    - x86/CPU: Use correct macros for Cyrix calls
+    - MIPS: kexec: Relax memory restriction
+    - media: pci: ivtv: Fix a sleep-in-atomic-context bug in ivtv_yuv_init()
+    - media: davinci: Fix implicit enum conversion warning
+    - usb: gadget: uvc: configfs: Drop leaked references to config items
+    - usb: gadget: uvc: configfs: Prevent format changes after linking header
+    - usb: gadget: uvc: Factor out video USB request queueing
+    - usb: gadget: uvc: Only halt video streaming endpoint in bulk mode
+    - misc: kgdbts: Fix restrict error
+    - misc: genwqe: should return proper error value.
+    - vfio/pci: Fix potential memory leak in vfio_msi_cap_len
+    - scsi: libsas: always unregister the old device if going to discover new
+    - ARM: dts: tegra30: fix xcvr-setup-use-fuses
+    - ARM: tegra: apalis_t30: fix mmc1 cmd pull-up
+    - net: smsc: fix return type of ndo_start_xmit function
+    - EDAC: Raise the maximum number of memory controllers
+    - Bluetooth: L2CAP: Detect if remote is not able to use the whole MPS
+    - arm64: dts: amd: Fix SPI bus warnings
+    - fuse: use READ_ONCE on congestion_threshold and max_background
+    - Bluetooth: hci_ldisc: Fix null pointer derefence in case of early data
+    - Bluetooth: hci_ldisc: Postpone HCI_UART_PROTO_READY bit set in
+      hci_uart_set_proto()
+    - memfd: Use radix_tree_deref_slot_protected to avoid the warning.
+    - slcan: Fix memory leak in error path
+    - net: cdc_ncm: Signedness bug in cdc_ncm_set_dgram_size()
+    - x86/atomic: Fix smp_mb__{before,after}_atomic()
+    - kprobes/x86: Prohibit probing on exception masking instructions
+    - uprobes/x86: Prohibit probing on MOV SS instruction
+    - [Config] Remove unused SH-Mobile HDMI driver
+    - fbdev: Remove unused SH-Mobile HDMI driver
+    - fbdev: Ditch fb_edid_add_monspecs
+    - block: introduce blk_rq_is_passthrough
+    - libata: have ata_scsi_rw_xlat() fail invalid passthrough requests
+    - net: ovs: fix return type of ndo_start_xmit function
+    - f2fs: return correct errno in f2fs_gc
+    - SUNRPC: Fix priority queue fairness
+    - ath10k: fix vdev-start timeout on error
+    - ath9k: fix reporting calculated new FFT upper max
+    - usb: gadget: udc: fotg210-udc: Fix a sleep-in-atomic-context bug in
+      fotg210_get_status()
+    - nl80211: Fix a GET_KEY reply attribute
+    - dmaengine: ep93xx: Return proper enum in ep93xx_dma_chan_direction
+    - dmaengine: timb_dma: Use proper enum in td_prep_slave_sg
+    - mei: samples: fix a signedness bug in amt_host_if_call()
+    - cxgb4: Use proper enum in cxgb4_dcb_handle_fw_update
+    - cxgb4: Use proper enum in IEEE_FAUX_SYNC
+    - powerpc/pseries: Fix DTL buffer registration
+    - powerpc/pseries: Fix how we iterate over the DTL entries
+    - mtd: rawnand: sh_flctl: Use proper enum for flctl_dma_fifo0_transfer
+    - ixgbe: Fix crash with VFs and flow director on interface flap
+    - IB/mthca: Fix error return code in __mthca_init_one()
+    - ata: ep93xx: Use proper enums for directions
+    - ALSA: hda/sigmatel - Disable automute for Elo VuPoint
+    - KVM: PPC: Book3S PR: Exiting split hack mode needs to fixup both PC and LR
+    - USB: serial: cypress_m8: fix interrupt-out transfer length
+    - mtd: physmap_of: Release resources on error
+    - brcmfmac: fix full timeout waiting for action frame on-channel tx
+    - NFSv4.x: fix lock recovery during delegation recall
+    - dmaengine: ioat: fix prototype of ioat_enumerate_channels
+    - Input: st1232 - set INPUT_PROP_DIRECT property
+    - x86/olpc: Fix build error with CONFIG_MFD_CS5535=m
+    - crypto: mxs-dcp - Fix SHA null hashes and output length
+    - crypto: mxs-dcp - Fix AES issues
+    - ACPI / SBS: Fix rare oops when removing modules
+    - fbdev: sbuslib: use checked version of put_user()
+    - fbdev: sbuslib: integer overflow in sbusfb_ioctl_helper()
+    - bcache: recal cached_dev_sectors on detach
+    - proc/vmcore: Fix i386 build error of missing copy_oldmem_page_encrypted()
+    - backlight: lm3639: Unconditionally call led_classdev_unregister
+    - printk: Give error on attempt to set log buffer length to over 2G
+    - media: isif: fix a NULL pointer dereference bug
+    - GFS2: Flush the GFS2 delete workqueue before stopping the kernel threads
+    - media: cx231xx: fix potential sign-extension overflow on large shift
+    - x86/kexec: Correct KEXEC_BACKUP_SRC_END off-by-one error
+    - gpio: syscon: Fix possible NULL ptr usage
+    - spi: spidev: Fix OF tree warning logic
+    - ARM: 8802/1: Call syscall_trace_exit even when system call skipped
+    - hwmon: (pwm-fan) Silence error on probe deferral
+    - mac80211: minstrel: fix CCK rate group streams value
+    - spi: rockchip: initialize dma_slave_config properly
+    - arm64: uaccess: Ensure PAN is re-enabled after unhandled uaccess fault
+    - Linux 4.4.203
+
+  * Xenial update: 4.4.202 upstream stable release (LP: #1853177)
+    - kvm: mmu: Don't read PDPTEs when paging is not enabled
+    - MIPS: BCM63XX: fix switch core reset on BCM6368
+    - powerpc/Makefile: Use cflags-y/aflags-y for setting endian options
+    - powerpc: Fix compiling a BE kernel with a powerpc64le toolchain
+    - powerpc/boot: Request no dynamic linker for boot wrapper
+    - x86/speculation/taa: Fix printing of TAA_MSG_SMT on IBRS_ALL CPUs
+    - Linux 4.4.202
+
+  * Xenial update: 4.4.201 upstream stable release (LP: #1852335)
+    - CDC-NCM: handle incomplete transfer of MTU
+    - net: fix data-race in neigh_event_send()
+    - NFC: fdp: fix incorrect free object
+    - NFC: st21nfca: fix double free
+    - qede: fix NULL pointer deref in __qede_remove()
+    - nfc: netlink: fix double device reference drop
+    - ALSA: bebob: fix to detect configured source of sampling clock for Focusrite
+      Saffire Pro i/o series
+    - ALSA: hda/ca0132 - Fix possible workqueue stall
+    - mm, vmstat: hide /proc/pagetypeinfo from normal users
+    - dump_stack: avoid the livelock of the dump_lock
+    - perf tools: Fix time sorting
+    - drm/radeon: fix si_enable_smc_cac() failed issue
+    - ceph: fix use-after-free in __ceph_remove_cap()
+    - iio: imu: adis16480: make sure provided frequency is positive
+    - netfilter: nf_tables: Align nft_expr private data to 64-bit
+    - netfilter: ipset: Fix an error code in ip_set_sockfn_get()
+    - can: usb_8dev: fix use-after-free on disconnect
+    - can: c_can: c_can_poll(): only read status register after status IRQ
+    - can: peak_usb: fix a potential out-of-sync while decoding packets
+    - can: gs_usb: gs_can_open(): prevent memory leak
+    - can: peak_usb: fix slab info leak
+    - drivers: usb: usbip: Add missing break statement to switch
+    - configfs: fix a deadlock in configfs_symlink()
+    - PCI: tegra: Enable Relaxed Ordering only for Tegra20 & Tegra30
+    - scsi: qla2xxx: fixup incorrect usage of host_byte
+    - scsi: lpfc: Honor module parameter lpfc_use_adisc
+    - ipvs: move old_secure_tcp into struct netns_ipvs
+    - bonding: fix unexpected IFF_BONDING bit unset
+    - usb: fsl: Check memory resource before releasing it
+    - usb: gadget: udc: atmel: Fix interrupt storm in FIFO mode.
+    - usb: gadget: composite: Fix possible double free memory bug
+    - usb: gadget: configfs: fix concurrent issue between composite APIs
+    - perf/x86/amd/ibs: Fix reading of the IBS OpData register and thus precise
+      RIP validity
+    - USB: Skip endpoints with 0 maxpacket length
+    - scsi: qla2xxx: stop timer in shutdown path
+    - net: hisilicon: Fix "Trying to free already-free IRQ"
+    - NFSv4: Don't allow a cached open with a revoked delegation
+    - igb: Fix constant media auto sense switching when no cable is connected
+    - e1000: fix memory leaks
+    - can: flexcan: disable completely the ECC mechanism
+    - mm/filemap.c: don't initiate writeback if mapping has no dirty pages
+    - cgroup,writeback: don't switch wbs immediately on dead wbs if the memcg is
+      dead
+    - net: prevent load/store tearing on sk->sk_stamp
+    - Linux 4.4.201
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 03 Dec 2019 11:20:54 +0100
+
+linux (4.4.0-170.199) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-170.199 -proposed tracker (LP: #1852306)
+
+  * update ENA driver to version 2.1.0 (LP: #1850175)
+    - net: ena: fix: set freed objects to NULL to avoid failing future allocations
+    - net: ena: fix swapped parameters when calling
+      ena_com_indirect_table_fill_entry
+    - net: ena: fix: Free napi resources when ena_up() fails
+    - net: ena: fix incorrect test of supported hash function
+    - net: ena: fix return value of ena_com_config_llq_info()
+    - net: ena: improve latency by disabling adaptive interrupt moderation by
+      default
+    - net: ena: fix ena_com_fill_hash_function() implementation
+    - net: ena: add handling of llq max tx burst size
+    - net: ena: ethtool: add extra properties retrieval via get_priv_flags
+    - net: ena: replace free_tx/rx_ids union with single free_ids field in
+      ena_ring
+    - net: ena: arrange ena_probe() function variables in reverse christmas tree
+    - net: ena: add newline at the end of pr_err prints
+    - net: ena: allow automatic fallback to polling mode
+    - net: ena: add support for changing max_header_size in LLQ mode
+    - net: ena: optimise calculations for CQ doorbell
+    - net: ena: add good checksum counter
+    - net: ena: use dev_info_once instead of static variable
+    - net: ena: add MAX_QUEUES_EXT get feature admin command
+    - net: ena: enable negotiating larger Rx ring size
+    - net: ena: make ethtool show correct current and max queue sizes
+    - net: ena: allow queue allocation backoff when low on memory
+    - net: ena: add ethtool function for changing io queue sizes
+    - net: ena: remove inline keyword from functions in *.c
+    - net: ena: update driver version from 2.0.3 to 2.1.0
+    - net: ena: Fix bug where ring allocation backoff stopped too late
+    - Revert "net: ena: ethtool: add extra properties retrieval via
+      get_priv_flags"
+    - net: ena: don't wake up tx queue when down
+    - net: ena: clean up indentation issue
+
+  * Bionic update: upstream stable patchset 2019-08-01 (LP: #1838700) // update
+    ENA driver to version 2.1.0 (LP: #1850175)
+    - net: ena: gcc 8: fix compilation warning
+
+  * Skip frame when buffer overflow on UVC camera (LP: #1849871)
+    - media: uvcvideo: Mark buffer error where overflow
+
+  * CVE-2018-20784
+    - sched/fair: Fix infinite loop in update_blocked_averages() by reverting
+      a9e7f6544b9c
+    - sched/fair: Fix hierarchical order in rq->leaf_cfs_rq_list
+    - sched/fair: Add tmp_alone_branch assertion
+    - sched/fair: Fix insertion in rq->leaf_cfs_rq_list
+    - sched/fair: Optimize update_blocked_averages()
+    - sched/fair: Fix O(nr_cgroups) in the load balancing path
+
+  * Xenial update: 4.4.200 upstream stable release (LP: #1852110)
+    - kbuild: add -fcf-protection=none when using retpoline flags
+    - regulator: ti-abb: Fix timeout in ti_abb_wait_txdone/ti_abb_clear_all_txdone
+    - regulator: pfuze100-regulator: Variable "val" in pfuze100_regulator_probe()
+      could be uninitialized
+    - ASoc: rockchip: i2s: Fix RPM imbalance
+    - ARM: dts: logicpd-torpedo-som: Remove twl_keypad
+    - ARM: mm: fix alignment handler faults under memory pressure
+    - scsi: sni_53c710: fix compilation error
+    - scsi: fix kconfig dependency warning related to 53C700_LE_ON_BE
+    - perf kmem: Fix memory leak in compact_gfp_flags()
+    - scsi: target: core: Do not overwrite CDB byte 1
+    - of: unittest: fix memory leak in unittest_data_add
+    - MIPS: bmips: mark exception vectors as char arrays
+    - cifs: Fix cifsInodeInfo lock_sem deadlock when reconnect occurs
+    - dccp: do not leak jiffies on the wire
+    - net: fix sk_page_frag() recursion from memory reclaim
+    - net: hisilicon: Fix ping latency when deal with high throughput
+    - SAUCE: Revert "net: Zeroing the structure ethtool_wolinfo in
+      ethtool_get_wol()"
+    - net: Zeroing the structure ethtool_wolinfo in ethtool_get_wol()
+    - net: add READ_ONCE() annotation in __skb_wait_for_more_packets()
+    - vxlan: check tun_info options_len properly
+    - net/mlx4_core: Dynamically set guaranteed amount of counters per VF
+    - inet: stop leaking jiffies on the wire
+    - net/flow_dissector: switch to siphash
+    - dmaengine: qcom: bam_dma: Fix resource leak
+    - ARM: 8051/1: put_user: fix possible data corruption in put_user
+    - ARM: 8478/2: arm/arm64: add arm-smccc
+    - ARM: 8479/2: add implementation for arm-smccc
+    - ARM: 8480/2: arm64: add implementation for arm-smccc
+    - ARM: 8481/2: drivers: psci: replace psci firmware calls
+    - ARM: uaccess: remove put_user() code duplication
+    - ARM: Move system register accessors to asm/cp15.h
+    - arm/arm64: KVM: Advertise SMCCC v1.1
+    - arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support
+    - firmware/psci: Expose PSCI conduit
+    - firmware/psci: Expose SMCCC version through psci_ops
+    - arm/arm64: smccc: Make function identifiers an unsigned quantity
+    - arm/arm64: smccc: Implement SMCCC v1.1 inline primitive
+    - arm/arm64: smccc: Add SMCCC-specific return codes
+    - arm/arm64: smccc-1.1: Make return values unsigned long
+    - arm/arm64: smccc-1.1: Handle function result as parameters
+    - ARM: add more CPU part numbers for Cortex and Brahma B15 CPUs
+    - ARM: bugs: prepare processor bug infrastructure
+    - ARM: bugs: hook processor bug checking into SMP and suspend paths
+    - ARM: bugs: add support for per-processor bug checking
+    - ARM: spectre: add Kconfig symbol for CPUs vulnerable to Spectre
+    - ARM: spectre-v2: harden branch predictor on context switches
+    - ARM: spectre-v2: add Cortex A8 and A15 validation of the IBE bit
+    - ARM: spectre-v2: harden user aborts in kernel space
+    - ARM: spectre-v2: add firmware based hardening
+    - ARM: spectre-v2: warn about incorrect context switching functions
+    - ARM: spectre-v1: add speculation barrier (csdb) macros
+    - ARM: spectre-v1: add array_index_mask_nospec() implementation
+    - ARM: spectre-v1: fix syscall entry
+    - ARM: signal: copy registers using __copy_from_user()
+    - ARM: vfp: use __copy_from_user() when restoring VFP state
+    - ARM: oabi-compat: copy semops using __copy_from_user()
+    - ARM: use __inttype() in get_user()
+    - ARM: spectre-v1: use get_user() for __get_user()
+    - ARM: spectre-v1: mitigate user accesses
+    - ARM: 8789/1: signal: copy registers using __copy_to_user()
+    - ARM: 8791/1: vfp: use __copy_to_user() when saving VFP state
+    - ARM: 8792/1: oabi-compat: copy oabi events using __copy_to_user()
+    - ARM: 8793/1: signal: replace __put_user_error with __put_user
+    - ARM: 8794/1: uaccess: Prevent speculative use of the current addr_limit
+    - ARM: 8795/1: spectre-v1.1: use put_user() for __put_user()
+    - ARM: 8796/1: spectre-v1,v1.1: provide helpers for address sanitization
+    - ARM: 8810/1: vfp: Fix wrong assignement to ufp_exc
+    - ARM: make lookup_processor_type() non-__init
+    - ARM: split out processor lookup
+    - ARM: clean up per-processor check_bugs method call
+    - ARM: add PROC_VTABLE and PROC_TABLE macros
+    - ARM: spectre-v2: per-CPU vtables to work around big.Little systems
+    - ARM: ensure that processor vtables is not lost after boot
+    - ARM: fix the cockup in the previous patch
+    - alarmtimer: Change remaining ENOTSUPP to EOPNOTSUPP
+    - fs/dcache: move security_d_instantiate() behind attaching dentry to inode
+    - Linux 4.4.200
+    - updateconfigs for Linux v4.4.200
+
+  * Xenial update: 4.4.199 upstream stable release (LP: #1851549)
+    - dm snapshot: use mutex instead of rw_semaphore
+    - dm snapshot: introduce account_start_copy() and account_end_copy()
+    - dm snapshot: rework COW throttling to fix deadlock
+    - dm: Use kzalloc for all structs with embedded biosets/mempools
+    - sc16is7xx: Fix for "Unexpected interrupt: 8"
+    - x86/cpu: Add Atom Tremont (Jacobsville)
+    - scripts/setlocalversion: Improve -dirty check with git-status --no-optional-
+      locks
+    - usb: handle warm-reset port requests on hub resume
+    - exec: load_script: Do not exec truncated interpreter path
+    - iio: fix center temperature of bmc150-accel-core
+    - perf map: Fix overlapped map handling
+    - RDMA/iwcm: Fix a lock inversion issue
+    - fs: cifs: mute -Wunused-const-variable message
+    - serial: mctrl_gpio: Check for NULL pointer
+    - efi/cper: Fix endianness of PCIe class code
+    - efi/x86: Do not clean dummy variable in kexec path
+    - fs: ocfs2: fix possible null-pointer dereferences in
+      ocfs2_xa_prepare_entry()
+    - fs: ocfs2: fix a possible null-pointer dereference in
+      ocfs2_info_scan_inode_alloc()
+    - MIPS: fw: sni: Fix out of bounds init of o32 stack
+    - NFSv4: Fix leak of clp->cl_acceptor string
+    - tracing: Initialize iter->seq after zeroing in tracing_read_pipe()
+    - USB: legousbtower: fix a signedness bug in tower_probe()
+    - thunderbolt: Use 32-bit writes when writing ring producer/consumer
+    - fuse: flush dirty data/metadata before non-truncate setattr
+    - fuse: truncate pending writes on O_TRUNC
+    - ALSA: bebob: Fix prototype of helper function to return negative value
+    - UAS: Revert commit 3ae62a42090f ("UAS: fix alignment of scatter/gather
+      segments")
+    - USB: gadget: Reject endpoints with 0 maxpacket value
+    - USB: ldusb: fix ring-buffer locking
+    - USB: ldusb: fix control-message timeout
+    - USB: serial: whiteheat: fix potential slab corruption
+    - USB: serial: whiteheat: fix line-speed endianness
+    - HID: Fix assumption that devices have inputs
+    - HID: fix error message in hid_open_report()
+    - nl80211: fix validation of mesh path nexthop
+    - s390/cmm: fix information leak in cmm_timeout_handler()
+    - llc: fix sk_buff leak in llc_sap_state_process()
+    - llc: fix sk_buff leak in llc_conn_service()
+    - bonding: fix potential NULL deref in bond_update_slave_arr
+    - net: usb: sr9800: fix uninitialized local variable
+    - sch_netem: fix rcu splat in netem_enqueue()
+    - sctp: fix the issue that flags are ignored when using kernel_connect
+    - sctp: not bind the socket in sctp_connect
+    - xfs: Correctly invert xfs_buftarg LRU isolation logic
+    - Revert "ALSA: hda: Flush interrupts on disabling"
+    - Linux 4.4.199
+
+  * libmbim-proxy using 100% CPU on a Dell Edge Gateway 3002 (LP: #1851347)
+    - USB: cdc-wdm: ignore -EPIPE from GetEncapsulatedResponse
+
+  * Xenial update: v4.4.198 upstream stable release (LP: #1850454)
+    - scsi: ufs: skip shutdown if hba is not powered
+    - scsi: megaraid: disable device when probe failed after enabled device
+    - scsi: qla2xxx: Fix unbound sleep in fcport delete path.
+    - ARM: OMAP2+: Fix missing reset done flag for am3 and am43
+    - ARM: dts: am4372: Set memory bandwidth limit for DISPC
+    - nl80211: fix null pointer dereference
+    - mips: Loongson: Fix the link time qualifier of 'serial_exit()'
+    - net: hisilicon: Fix usage of uninitialized variable in function
+      mdio_sc_cfg_reg_write()
+    - namespace: fix namespace.pl script to support relative paths
+    - loop: Add LOOP_SET_DIRECT_IO to compat ioctl
+    - net: bcmgenet: Fix RGMII_MODE_EN value for GENET v1/2/3
+    - net: bcmgenet: Set phydev->dev_flags only for internal PHYs
+    - sctp: change sctp_prot .no_autobind with true
+    - net: avoid potential infinite loop in tc_ctl_action()
+    - ipv4: Return -ENETUNREACH if we can't create route but saddr is valid
+    - memfd: Fix locking when tagging pins
+    - USB: legousbtower: fix memleak on disconnect
+    - usb: udc: lpc32xx: fix bad bit shift operation
+    - USB: serial: ti_usb_3410_5052: fix port-close races
+    - USB: ldusb: fix memleak on disconnect
+    - USB: usblp: fix use-after-free on disconnect
+    - USB: ldusb: fix read info leaks
+    - scsi: core: try to get module before removing device
+    - ASoC: rsnd: Reinitialize bit clock inversion flag for every format setting
+    - cfg80211: wext: avoid copying malformed SSIDs
+    - mac80211: Reject malformed SSID elements
+    - scsi: zfcp: fix reaction on bit error threshold notification
+    - mm/slub: fix a deadlock in show_slab_objects()
+    - xtensa: drop EXPORT_SYMBOL for outs*/ins*
+    - parisc: Fix vmap memory leak in ioremap()/iounmap()
+    - CIFS: avoid using MID 0xFFFF
+    - btrfs: block-group: Fix a memory leak due to missing btrfs_put_block_group()
+    - memstick: jmb38x_ms: Fix an error handling path in 'jmb38x_ms_probe()'
+    - cpufreq: Avoid cpufreq_suspend() deadlock on system shutdown
+    - xen/netback: fix error path of xenvif_connect_data()
+    - PCI: PM: Fix pci_power_up()
+    - net: sched: Fix memory exposure from short TCA_U32_SEL
+    - RDMA/cxgb4: Do not dma memory off of the stack
+    - Linux 4.4.198
+
+  * Colour banding in Lenovo G50-80 laptop display (i915) (LP: #1819968) //
+    Xenial update: v4.4.198 upstream stable release (LP: #1850454)
+    - drm/edid: Add 6 bpc quirk for SDC panel in Lenovo G50
+
+ -- Connor Kuehl <connor.kuehl@canonical.com>  Wed, 13 Nov 2019 11:18:48 -0800
+
+linux (4.4.0-169.198) xenial; urgency=medium
+
+  * Incomplete i915 fix for 64-bit x86 kernels (LP: #1852141) // CVE-2019-0155
+    - SAUCE: drm/i915/cmdparser: Fix jump whitelist clearing
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 12 Nov 2019 11:19:22 +0100
+
+linux (4.4.0-168.197) xenial; urgency=medium
+
+  * CVE-2018-12207
+    - KVM: x86: MMU: Encapsulate the type of rmap-chain head in a new struct
+    - KVM: x86: MMU: Consolidate quickly_check_mmio_pf() and is_mmio_page_fault()
+    - KVM: x86: MMU: Move handle_mmio_page_fault() call to kvm_mmu_page_fault()
+    - KVM: MMU: rename has_wrprotected_page to mmu_gfn_lpage_is_disallowed
+    - KVM: MMU: introduce kvm_mmu_gfn_{allow,disallow}_lpage
+    - KVM: x86: MMU: Make mmu_set_spte() return emulate value
+    - KVM: x86: MMU: Move initialization of parent_ptes out from
+      kvm_mmu_alloc_page()
+    - KVM: x86: MMU: always set accessed bit in shadow PTEs
+    - KVM: x86: MMU: Move parent_pte handling from kvm_mmu_get_page() to
+      link_shadow_page()
+    - KVM: x86: MMU: Remove unused parameter parent_pte from kvm_mmu_get_page()
+    - KVM: x86: simplify ept_misconfig
+    - KVM: x86: extend usage of RET_MMIO_PF_* constants
+    - KVM: MMU: drop vcpu param in gpte_access
+    - kvm: Convert kvm_lock to a mutex
+    - kvm: x86: Do not release the page inside mmu_set_spte()
+    - KVM: x86: make FNAME(fetch) and __direct_map more similar
+    - KVM: x86: remove now unneeded hugepage gfn adjustment
+    - KVM: x86: change kvm_mmu_page_get_gfn BUG_ON to WARN_ON
+    - KVM: x86: add tracepoints around __direct_map and FNAME(fetch)
+    - SAUCE: KVM: vmx, svm: always run with EFER.NXE=1 when shadow paging is
+      active
+    - SAUCE: x86: Add ITLB_MULTIHIT bug infrastructure
+    - SAUCE: kvm: mmu: ITLB_MULTIHIT mitigation
+    - SAUCE: kvm: Add helper function for creating VM worker threads
+    - SAUCE: kvm: x86: mmu: Recovery of shattered NX large pages
+    - SAUCE: cpu/speculation: Uninline and export CPU mitigations helpers
+    - SAUCE: kvm: x86: mmu: Apply global mitigations knob to ITLB_MULTIHIT
+
+  * CVE-2019-11135
+    - KVM: x86: Emulate MSR_IA32_ARCH_CAPABILITIES on AMD hosts
+    - KVM: x86: use Intel speculation bugs and features as derived in generic x86
+      code
+    - x86/msr: Add the IA32_TSX_CTRL MSR
+    - x86/cpu: Add a helper function x86_read_arch_cap_msr()
+    - x86/cpu: Add a "tsx=" cmdline option with TSX disabled by default
+    - x86/speculation/taa: Add mitigation for TSX Async Abort
+    - x86/speculation/taa: Add sysfs reporting for TSX Async Abort
+    - kvm/x86: Export MDS_NO=0 to guests when TSX is enabled
+    - x86/tsx: Add "auto" option to the tsx= cmdline parameter
+    - x86/speculation/taa: Add documentation for TSX Async Abort
+    - x86/tsx: Add config options to set tsx=on|off|auto
+    - SAUCE: x86/speculation/taa: Call tsx_init()
+    - SAUCE: x86/cpu: Include cpu header from bugs.c
+    - [Config] Disable TSX by default when possible
+
+  * CVE-2019-0154
+    - SAUCE: i915_bpo: drm/i915: Lower RM timeout to avoid DSI hard hangs
+    - SAUCE: i915_bpo: drm/i915/gen8+: Add RC6 CTX corruption WA
+    - SAUCE: drm/i915/gen8+: Add RC6 CTX corruption WA
+
+  * CVE-2019-0155
+    - SAUCE: i915_bpo: drm/i915/gtt: Add read only pages to gen8_pte_encode
+    - SAUCE: i915_bpo: drm/i915/gtt: Read-only pages for insert_entries on bdw+
+    - SAUCE: i915_bpo: drm/i915/gtt: Disable read-only support under GVT
+    - SAUCE: i915_bpo: drm/i915: Rename gen7 cmdparser tables
+    - SAUCE: i915_bpo: drm/i915: Disable Secure Batches for gen6+
+    - SAUCE: i915_bpo: drm/i915/cmdparser: Use binary search for faster register
+      lookup
+    - SAUCE: i915_bpo: drm/i915/cmdparser: Check reg_table_count before
+      derefencing.
+    - SAUCE: i915_bpo: drm/i915: Remove Master tables from cmdparser
+    - SAUCE: i915_bpo: drm/i915: Add support for mandatory cmdparsing
+    - SAUCE: i915_bpo: drm/i915: Support ro ppgtt mapped cmdparser shadow buffers
+    - SAUCE: i915_bpo: drm/i915: Allow parsing of unsized batches
+    - SAUCE: i915_bpo: drm/i915: Add gen9 BCS cmdparsing
+    - SAUCE: i915_bpo: drm/i915/cmdparser: Add support for backward jumps
+    - SAUCE: i915_bpo: drm/i915/cmdparser: Ignore Length operands during command
+      matching
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 06 Nov 2019 09:50:06 +0100
+
+linux (4.4.0-167.196) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-167.196 -proposed tracker (LP: #1849051)
+
+  * Xenial update: 4.4.197 upstream stable release (LP: #1848780)
+    - KVM: s390: Test for bad access register and size at the start of S390_MEM_OP
+    - s390/topology: avoid firing events before kobjs are created
+    - s390/cio: avoid calling strlen on null pointer
+    - s390/cio: exclude subchannels with no parent from pseudo check
+    - KVM: nVMX: handle page fault in vmread fix
+    - ASoC: Define a set of DAPM pre/post-up events
+    - powerpc/powernv: Restrict OPAL symbol map to only be readable by root
+    - can: mcp251x: mcp251x_hw_reset(): allow more time after a reset
+    - crypto: qat - Silence smp_processor_id() warning
+    - ieee802154: atusb: fix use-after-free at disconnect
+    - cfg80211: initialize on-stack chandefs
+    - ima: always return negative code for error
+    - fs: nfs: Fix possible null-pointer dereferences in encode_attrs()
+    - 9p: avoid attaching writeback_fid on mmap with type PRIVATE
+    - xen/pci: reserve MCFG areas earlier
+    - ceph: fix directories inode i_blkbits initialization
+    - drm/amdgpu: Check for valid number of registers to read
+    - thermal: Fix use-after-free when unregistering thermal zone device
+    - fuse: fix memleak in cuse_channel_open
+    - kernel/elfcore.c: include proper prototypes
+    - tools lib traceevent: Do not free tep->cmdlines in add_new_comm() on failure
+    - perf stat: Fix a segmentation fault when using repeat forever
+    - crypto: caam - fix concurrency issue in givencrypt descriptor
+    - cfg80211: add and use strongly typed element iteration macros
+    - cfg80211: Use const more consistently in for_each_element macros
+    - nl80211: validate beacon head
+    - ASoC: sgtl5000: Improve VAG power and mute control
+    - panic: ensure preemption is disabled during panic()
+    - [Config] updateconfigs for USB_RIO500
+    - USB: rio500: Remove Rio 500 kernel driver
+    - USB: yurex: Don't retry on unexpected errors
+    - USB: yurex: fix NULL-derefs on disconnect
+    - USB: usb-skeleton: fix runtime PM after driver unbind
+    - USB: usb-skeleton: fix NULL-deref on disconnect
+    - xhci: Prevent device initiated U1/U2 link pm if exit latency is too long
+    - xhci: Check all endpoints for LPM timeout
+    - usb: xhci: wait for CNR controller not ready bit in xhci resume
+    - USB: adutux: remove redundant variable minor
+    - USB: adutux: fix use-after-free on disconnect
+    - USB: adutux: fix NULL-derefs on disconnect
+    - USB: adutux: fix use-after-free on release
+    - USB: iowarrior: fix use-after-free on disconnect
+    - USB: iowarrior: fix use-after-free on release
+    - USB: iowarrior: fix use-after-free after driver unbind
+    - USB: usblp: fix runtime PM after driver unbind
+    - USB: chaoskey: fix use-after-free on release
+    - USB: ldusb: fix NULL-derefs on driver unbind
+    - serial: uartlite: fix exit path null pointer
+    - USB: serial: keyspan: fix NULL-derefs on open() and write()
+    - USB: serial: ftdi_sio: add device IDs for Sienna and Echelon PL-20
+    - USB: serial: option: add Telit FN980 compositions
+    - USB: serial: option: add support for Cinterion CLS8 devices
+    - USB: serial: fix runtime PM after driver unbind
+    - USB: usblcd: fix I/O after disconnect
+    - USB: microtek: fix info-leak at probe
+    - USB: dummy-hcd: fix power budget for SuperSpeed mode
+    - usb: renesas_usbhs: gadget: Do not discard queues in
+      usb_ep_set_{halt,wedge}()
+    - usb: renesas_usbhs: gadget: Fix usb_ep_set_{halt,wedge}() behavior
+    - USB: legousbtower: fix slab info leak at probe
+    - USB: legousbtower: fix deadlock on disconnect
+    - USB: legousbtower: fix potential NULL-deref on disconnect
+    - USB: legousbtower: fix open after failed reset request
+    - USB: legousbtower: fix use-after-free on release
+    - staging: vt6655: Fix memory leak in vt6655_probe
+    - iio: adc: ad799x: fix probe error handling
+    - iio: light: opt3001: fix mutex unlock race
+    - perf llvm: Don't access out-of-scope array
+    - CIFS: Gracefully handle QueryInfo errors during open
+    - CIFS: Force reval dentry if LOOKUP_REVAL flag is set
+    - kernel/sysctl.c: do not override max_threads provided by userspace
+    - arm64: capabilities: Handle sign of the feature bit
+    - arm64: Rename cpuid_feature field extract routines
+    - Staging: fbtft: fix memory leak in fbtft_framebuffer_alloc
+    - cifs: Check uniqueid for SMB2+ and return -ESTALE if necessary
+    - CIFS: Force revalidate inode when dentry is stale
+    - media: stkwebcam: fix runtime PM after driver unbind
+    - tracing: Get trace_array reference for available_tracers files
+    - x86/asm: Fix MWAITX C-state hint value
+    - Linux 4.4.197
+    - [Config] updateconfigs for USB_RIO500
+
+  * CVE-2019-17666
+    - SAUCE: rtlwifi: Fix potential overflow on P2P code
+
+  * Suspend stopped working from 4.4.0-157 onwards (LP: #1844021) // Xenial
+    update: 4.4.197 upstream stable release (LP: #1848780)
+    - xhci: Increase STS_SAVE timeout in xhci_suspend()
+
+  * Ubuntu 16.04.6 - Shared CEX7C cards defined in z/VM guest not established by
+    zcrypt device driver (LP: #1848173)
+    - SAUCE: s390/zcrypt: CEX7 toleration support
+
+  * Xenial update: 4.4.196 upstream stable release (LP: #1848598)
+    - video: ssd1307fb: Start page range at page_offset
+    - gpu: drm: radeon: Fix a possible null-pointer dereference in
+      radeon_connector_set_property()
+    - ipmi_si: Only schedule continuously in the thread in maintenance mode
+    - clk: qoriq: Fix -Wunused-const-variable
+    - clk: sirf: Don't reference clk_init_data after registration
+    - powerpc/rtas: use device model APIs and serialization during LPM
+    - powerpc/futex: Fix warning: 'oldval' may be used uninitialized in this
+      function
+    - powerpc/pseries/mobility: use cond_resched when updating device tree
+    - pinctrl: tegra: Fix write barrier placement in pmx_writel
+    - vfio_pci: Restore original state on release
+    - powerpc/64s/exception: machine check use correct cfar for late handler
+    - powerpc/pseries: correctly track irq state in default idle
+    - scsi: core: Reduce memory required for SCSI logging
+    - mfd: intel-lpss: Remove D3cold delay
+    - ARM: 8898/1: mm: Don't treat faults reported from cache maintenance as
+      writes
+    - HID: apple: Fix stuck function keys when using FN
+    - security: smack: Fix possible null-pointer dereferences in
+      smack_socket_sock_rcv_skb()
+    - fat: work around race with userspace's read via blockdev while mounting
+    - hypfs: Fix error number left in struct pointer member
+    - ocfs2: wait for recovering done after direct unlock request
+    - kmemleak: increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE default to 16K
+    - ANDROID: binder: remove waitqueue when thread exits.
+    - ANDROID: binder: synchronize_rcu() when using POLLFREE.
+    - hso: fix NULL-deref on tty open
+    - ipv6: drop incoming packets having a v4mapped source address
+    - net: ipv4: avoid mixed n_redirects and rate_tokens usage
+    - net: qlogic: Fix memory leak in ql_alloc_large_buffers
+    - nfc: fix memory leak in llcp_sock_bind()
+    - sch_dsmark: fix potential NULL deref in dsmark_init()
+    - xen-netfront: do not use ~0U as error return value for xennet_fill_frags()
+    - net/rds: Fix error handling in rds_ib_add_one()
+    - sch_cbq: validate TCA_CBQ_WRROPT to avoid crash
+    - Smack: Don't ignore other bprm->unsafe flags if LSM_UNSAFE_PTRACE is set
+    - smack: use GFP_NOFS while holding inode_smack::smk_lock
+    - NFC: fix attrs checks in netlink interface
+    - Linux 4.4.196
+
+  * Xenial update: 4.4.195 upstream stable release (LP: #1848589)
+    - Revert "Bluetooth: validate BLE connection interval updates"
+    - HID: prodikeys: Fix general protection fault during probe
+    - HID: lg: make transfer buffers DMA capable
+    - HID: logitech: Fix general protection fault caused by Logitech driver
+    - HID: hidraw: Fix invalid read in hidraw_ioctl
+    - mtd: cfi_cmdset_0002: Use chip_good() to retry in do_write_oneword()
+    - crypto: talitos - fix missing break in switch statement
+    - net: rds: Fix NULL ptr use in rds_tcp_kill_sock
+    - ASoC: fsl: Fix of-node refcount unbalance in fsl_ssi_probe_from_dt()
+    - ALSA: hda - Add laptop imic fixup for ASUS M9V laptop
+    - SAUCE: Revert "mac80211: handle deauthentication/disassociation from TDLS
+      peer"
+    - mac80211: Print text for disassociation reason
+    - mac80211: handle deauthentication/disassociation from TDLS peer
+    - locking/lockdep: Add debug_locks check in __lock_downgrade()
+    - irqchip/gic-v3-its: Fix LPI release for Multi-MSI devices
+    - f2fs: check all the data segments against all node ones
+    - Revert "f2fs: avoid out-of-range memory access"
+    - f2fs: fix to do sanity check on segment bitmap of LFS curseg
+    - drm: Flush output polling on shutdown
+    - Bluetooth: btrtl: Additional Realtek 8822CE Bluetooth devices
+    - arcnet: provide a buffer big enough to actually receive packets
+    - cdc_ncm: fix divide-by-zero caused by invalid wMaxPacketSize
+    - net/phy: fix DP83865 10 Mbps HDX loopback disable function
+    - openvswitch: change type of UPCALL_PID attribute to NLA_UNSPEC
+    - sch_netem: fix a divide by zero in tabledist()
+    - skge: fix checksum byte order
+    - usbnet: ignore endpoints with invalid wMaxPacketSize
+    - usbnet: sanity checking of packet sizes and device mtu
+    - ALSA: hda: Flush interrupts on disabling
+    - ASoC: sgtl5000: Fix charge pump source assignment
+    - dmaengine: bcm2835: Print error in case setting DMA mask fails
+    - leds: leds-lp5562 allow firmware files up to the maximum length
+    - media: dib0700: fix link error for dibx000_i2c_set_speed
+    - media: hdpvr: Add device num check and handling
+    - sched/fair: Fix imbalance due to CPU affinity
+    - sched/core: Fix CPU controller for !RT_GROUP_SCHED
+    - x86/reboot: Always use NMI fallback when shutdown via reboot vector IPI
+      fails
+    - x86/apic: Soft disable APIC before initializing it
+    - ALSA: hda - Show the fatal CORB/RIRB error more clearly
+    - ALSA: i2c: ak4xxx-adda: Fix a possible null pointer dereference in
+      build_adc_controls()
+    - media: iguanair: add sanity checks
+    - base: soc: Export soc_device_register/unregister APIs
+    - ALSA: usb-audio: Skip bSynchAddress endpoint check if it is invalid
+    - ia64:unwind: fix double free for mod->arch.init_unw_table
+    - md: don't call spare_active in md_reap_sync_thread if all member devices
+      can't work
+    - md: don't set In_sync if array is frozen
+    - efi: cper: print AER info of PCIe fatal error
+    - media: gspca: zero usb_buf on error
+    - dmaengine: iop-adma: use correct printk format strings
+    - media: omap3isp: Don't set streaming state on random subdevs
+    - net: lpc-enet: fix printk format strings
+    - media: radio/si470x: kill urb on error
+    - media: hdpvr: add terminating 0 at end of string
+    - media: saa7146: add cleanup in hexium_attach()
+    - media: cpia2_usb: fix memory leaks
+    - media: saa7134: fix terminology around saa7134_i2c_eeprom_md7134_gate()
+    - media: ov9650: add a sanity check
+    - ACPI / CPPC: do not require the _PSD method
+    - libtraceevent: Change users plugin directory
+    - ACPI: custom_method: fix memory leaks
+    - hwmon: (acpi_power_meter) Change log level for 'unsafe software power cap'
+    - md/raid1: fail run raid1 array when active disk less than one
+    - dmaengine: ti: edma: Do not reset reserved paRAM slots
+    - kprobes: Prohibit probing on BUG() and WARN() address
+    - ASoC: dmaengine: Make the pcm->name equal to pcm->id if the name is not set
+    - mmc: sdhci: Fix incorrect switch to HS mode
+    - libertas: Add missing sentinel at end of if_usb.c fw_table
+    - media: ttusb-dec: Fix info-leak in ttusb_dec_send_command()
+    - ALSA: hda/realtek - Blacklist PC beep for Lenovo ThinkCentre M73/93
+    - btrfs: extent-tree: Make sure we only allocate extents from block groups
+      with the same type
+    - media: omap3isp: Set device on omap3isp subdevs
+    - ALSA: firewire-tascam: handle error code when getting current source of
+      clock
+    - ALSA: firewire-tascam: check intermediate state of clock status and retry
+    - printk: Do not lose last line in kmsg buffer dump
+    - fuse: fix missing unlock_page in fuse_writepage()
+    - parisc: Disable HP HSC-PCI Cards to prevent kernel crash
+    - KVM: x86: always stop emulation on page fault
+    - KVM: x86: set ctxt->have_exception in x86_decode_insn()
+    - KVM: x86: Manually calculate reserved bits when loading PDPTRS
+    - media: sn9c20x: Add MSI MS-1039 laptop to flip_dmi_table
+    - ASoC: Intel: Fix use of potentially uninitialized variable
+    - ARM: zynq: Use memcpy_toio instead of memcpy on smp bring-up
+    - alarmtimer: Use EOPNOTSUPP instead of ENOTSUPP
+    - md/raid6: Set R5_ReadError when there is read failure on parity disk
+    - cfg80211: Purge frame registrations on iftype change
+    - /dev/mem: Bail out upon SIGKILL.
+    - ext4: fix punch hole for inline_data file systems
+    - quota: fix wrong condition in is_quota_modification()
+    - hwrng: core - don't wait on add_early_randomness()
+    - i2c: riic: Clear NACK in tend isr
+    - CIFS: Fix oplock handling for SMB 2.1+ protocols
+    - ovl: filter of trusted xattr results in audit
+    - Btrfs: fix use-after-free when using the tree modification log
+    - btrfs: Relinquish CPUs in btrfs_compare_trees
+    - Btrfs: fix race setting up and completing qgroup rescan workers
+    - Linux 4.4.195
+
+  * [Packaging] Support building Flattened Image Tree (FIT) kernels
+    (LP: #1847969)
+    - [Packaging] add rules to build FIT image
+    - [Packaging] force creation of headers directory
+
+  * bcache: Performance degradation when querying priority_stats (LP: #1840043)
+    - bcache: add cond_resched() in __bch_cache_cmp()
+
+  * Add installer support for iwlmvm adapters (LP: #1848236)
+    - d-i: Add iwlmvm to nic-modules
+
+  * Bad posix clock speculation mitigation backport (LP: #1847189)
+    - SAUCE: Fix posix clock speculation mitigation backport
+
+  * PM / hibernate: fix potential memory corruption (LP: #1847118)
+    - PM / hibernate: memory_bm_find_bit -- tighten node optimisation
+
+  * CVE-2019-17056
+    - nfc: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-17055
+    - mISDN: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-17054
+    - appletalk: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-17053
+    - ieee802154: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-17052
+    - ax25: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-15098
+    - ath6kl: fix a NULL-ptr-deref bug in ath6kl_usb_alloc_urb_from_pipe()
+
+  * arm64: sigaltstack fails with MINSIGSTKSZ for 32-bit processes
+    (LP: #1844155)
+    - signal: Introduce COMPAT_SIGMINSTKSZ for use in compat_sys_sigaltstack
+    - arm64: compat: Provide definition for COMPAT_SIGMINSTKSZ
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Mon, 21 Oct 2019 14:56:55 -0400
+
+linux (4.4.0-166.195) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-166.195 -proposed tracker (LP: #1846069)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * CVE-2017-18232
+    - scsi: libsas: direct call probe and destruct
+
+  * CVE-2018-21008
+    - rsi: add fix for crash during assertions
+
+  * Xenial update: 4.4.194 upstream stable release (LP: #1845405)
+    - bridge/mdb: remove wrong use of NLM_F_MULTI
+    - cdc_ether: fix rndis support for Mediatek based smartphones
+    - ipv6: Fix the link time qualifier of 'ping_v6_proc_exit_net()'
+    - isdn/capi: check message length in capi_write()
+    - net: Fix null de-reference of device refcount
+    - sch_hhf: ensure quantum and hhf_non_hh_weight are non-zero
+    - sctp: Fix the link time qualifier of 'sctp_ctrlsock_exit()'
+    - sctp: use transport pf_retrans in sctp_do_8_2_transport_strike
+    - tcp: fix tcp_ecn_withdraw_cwr() to clear TCP_ECN_QUEUE_CWR
+    - tipc: add NULL pointer check before calling kfree_rcu
+    - tun: fix use-after-free when register netdev failed
+    - Revert "MIPS: SiByte: Enable swiotlb for SWARM, LittleSur and BigSur"
+    - Btrfs: fix assertion failure during fsync and use of stale transaction
+    - genirq: Prevent NULL pointer dereference in resend_irqs()
+    - KVM: s390: Do not leak kernel stack data in the KVM_S390_INTERRUPT ioctl
+    - KVM: x86: work around leak of uninitialized stack contents
+    - KVM: nVMX: handle page fault in vmread
+    - MIPS: VDSO: Prevent use of smp_processor_id()
+    - MIPS: VDSO: Use same -m%-float cflag as the kernel proper
+    - clk: rockchip: Don't yell about bad mmc phases when getting
+    - driver core: Fix use-after-free and double free on glue directory
+    - crypto: talitos - check AES key size
+    - crypto: talitos - check data blocksize in ablkcipher.
+    - x86/build: Add -Wnoaddress-of-packed-member to REALMODE_CFLAGS, to silence
+      GCC9 build warning
+    - MIPS: netlogic: xlr: Remove erroneous check in nlm_fmn_send()
+    - ARC: configs: Remove CONFIG_INITRAMFS_SOURCE from defconfigs
+    - USB: usbcore: Fix slab-out-of-bounds bug during device reset
+    - media: tm6000: double free if usb disconnect while streaming
+    - x86/boot: Add missing bootparam that breaks boot on some platforms
+    - xen-netfront: do not assume sk_buff_head list is empty in error handling
+    - serial: sprd: correct the wrong sequence of arguments
+    - tty/serial: atmel: reschedule TX after RX was started
+    - mwifiex: Fix three heap overflow at parsing element in cfg80211_ap_settings
+    - s390/bpf: fix lcgr instruction encoding
+    - ARM: OMAP2+: Fix omap4 errata warning on other SoCs
+    - s390/bpf: use 32-bit index for tail calls
+    - NFSv4: Fix return values for nfs4_file_open()
+    - NFS: Fix initialisation of I/O result struct in nfs_pgio_rpcsetup
+    - Kconfig: Fix the reference to the IDT77105 Phy driver in the description of
+      ATM_NICSTAR_USE_IDT77105
+    - ARM: 8874/1: mm: only adjust sections of valid mm structures
+    - r8152: Set memory to all 0xFFs on failed reg reads
+    - x86/apic: Fix arch_dynirq_lower_bound() bug for DT enabled machines
+    - netfilter: nf_conntrack_ftp: Fix debug output
+    - NFSv2: Fix eof handling
+    - NFSv2: Fix write regression
+    - cifs: set domainName when a domain-key is used in multiuser
+    - cifs: Use kzfree() to zero out the password
+    - sky2: Disable MSI on yet another ASUS boards (P6Xxxx)
+    - tools/power turbostat: fix buffer overrun
+    - net: seeq: Fix the function used to release some memory in an error handling
+      path
+    - dmaengine: ti: omap-dma: Add cleanup in omap_dma_probe()
+    - keys: Fix missing null pointer check in request_key_auth_describe()
+    - floppy: fix usercopy direction
+    - media: technisat-usb2: break out of loop at end of buffer
+    - ARC: export "abort" for modules
+    - net_sched: let qdisc_put() accept NULL pointer
+    - Linux 4.4.194
+
+  * CVE-2019-14821
+    - KVM: coalesced_mmio: add bounds checking
+
+  * Xenial update: 4.4.193 upstream stable release (LP: #1845395)
+    - ALSA: hda - Fix potential endless loop at applying quirks
+    - ALSA: hda/realtek - Fix overridden device-specific initialization
+    - xfrm: clean up xfrm protocol checks
+    - vhost/test: fix build for vhost test
+    - scripts/decode_stacktrace: match basepath using shell prefix operator, not
+      regex
+    - clk: s2mps11: Add used attribute to s2mps11_dt_match
+    - x86, boot: Remove multiple copy of static function sanitize_boot_params()
+    - af_packet: tone down the Tx-ring unsupported spew.
+    - Linux 4.4.193
+
+  * Xenial update: 4.4.192 upstream stable release (LP: #1845374)
+    - net: tundra: tsi108: use spin_lock_irqsave instead of spin_lock_irq in IRQ
+      context
+    - net: tc35815: Explicitly check NET_IP_ALIGN is not zero in tc35815_rx
+    - Bluetooth: btqca: Add a short delay before downloading the NVM
+    - ibmveth: Convert multicast list size for little-endian system
+    - gpio: Fix build error of function redefinition
+    - cxgb4: fix a memory leak bug
+    - net: myri10ge: fix memory leaks
+    - cx82310_eth: fix a memory leak bug
+    - net: kalmia: fix memory leaks
+    - wimax/i2400m: fix a memory leak bug
+    - ravb: Fix use-after-free ravb_tstamp_skb
+    - Tools: hv: kvp: eliminate 'may be used uninitialized' warning
+    - IB/mlx4: Fix memory leaks
+    - ceph: fix buffer free while holding i_ceph_lock in __ceph_setxattr()
+    - KVM: arm/arm64: Only skip MMIO insn once
+    - libceph: allow ceph_buffer_put() to receive a NULL ceph_buffer
+    - spi: bcm2835aux: ensure interrupts are enabled for shared handler
+    - spi: bcm2835aux: unifying code between polling and interrupt driven code
+    - spi: bcm2835aux: remove dangerous uncontrolled read of fifo
+    - spi: bcm2835aux: fix corruptions for longer spi transfers
+    - Revert "x86/apic: Include the LDR when clearing out APIC registers"
+    - net: fix skb use after free in netpoll
+    - net: stmmac: dwmac-rk: Don't fail if phy regulator is absent
+    - Linux 4.4.192
+
+  * Xenial update: 4.4.191 upstream stable release (LP: #1845036)
+    - HID: Add 044f:b320 ThrustMaster, Inc. 2 in 1 DT
+    - MIPS: kernel: only use i8253 clocksource with periodic clockevent
+    - netfilter: ebtables: fix a memory leak bug in compat
+    - bonding: Force slave speed check after link state recovery for 802.3ad
+    - can: dev: call netif_carrier_off() in register_candev()
+    - st21nfca_connectivity_event_received: null check the allocation
+    - st_nci_hci_connectivity_event_received: null check the allocation
+    - ASoC: ti: davinci-mcasp: Correct slot_width posed constraint
+    - net: usb: qmi_wwan: Add the BroadMobi BM818 card
+    - isdn: mISDN: hfcsusb: Fix possible null-pointer dereferences in
+      start_isoc_chain()
+    - isdn: hfcsusb: Fix mISDN driver crash caused by transfer buffer on the stack
+    - perf bench numa: Fix cpu0 binding
+    - can: sja1000: force the string buffer NULL-terminated
+    - can: peak_usb: force the string buffer NULL-terminated
+    - NFSv4: Fix a potential sleep while atomic in nfs4_do_reclaim()
+    - net: cxgb3_main: Fix a resource leak in a error path in 'init_one()'
+    - net: hisilicon: make hip04_tx_reclaim non-reentrant
+    - net: hisilicon: fix hip04-xmit never return TX_BUSY
+    - net: hisilicon: Fix dma_map_single failed on arm64
+    - libata: add SG safety checks in SFF pio transfers
+    - selftests: kvm: Adding config fragments
+    - HID: wacom: correct misreported EKR ring values
+    - Revert "dm bufio: fix deadlock with loop device"
+    - userfaultfd_release: always remove uffd flags and clear vm_userfaultfd_ctx
+    - x86/retpoline: Don't clobber RFLAGS during CALL_NOSPEC on i386
+    - x86/apic: Handle missing global clockevent gracefully
+    - x86/boot: Save fields explicitly, zero out everything else
+    - x86/boot: Fix boot regression caused by bootparam sanitizing
+    - dm btree: fix order of block initialization in btree_split_beneath
+    - dm space map metadata: fix missing store of apply_bops() return value
+    - dm table: fix invalid memory accesses with too high sector number
+    - cgroup: Disable IRQs while holding css_set_lock
+    - net: arc_emac: fix koops caused by sk_buff free
+    - siphash: implement HalfSipHash1-3 for hash tables
+    - netfilter: ctnetlink: don't use conntrack/expect object addresses as id
+    - netfilter: conntrack: Use consistent ct id hash calculation
+    - x86/pm: Introduce quirk framework to save/restore extra MSR registers around
+      suspend/resume
+    - x86/CPU/AMD: Clear RDRAND CPUID bit on AMD family 15h/16h
+    - scsi: ufs: Fix NULL pointer dereference in ufshcd_config_vreg_hpm()
+    - dmaengine: ste_dma40: fix unneeded variable warning
+    - usb: gadget: composite: Clear "suspended" on reset/disconnect
+    - usb: host: fotg2: restart hcd after port reset
+    - tools: hv: fix KVP and VSS daemons exit code
+    - watchdog: bcm2835_wdt: Fix module autoload
+    - tcp: fix tcp_rtx_queue_tail in case of empty retransmit queue
+    - ALSA: usb-audio: Fix a stack buffer overflow bug in check_input_term
+    - ALSA: usb-audio: Fix an OOB bug in parse_audio_mixer_unit
+    - tcp: make sure EPOLLOUT wont be missed
+    - ALSA: seq: Fix potential concurrent access to the deleted pool
+    - KVM: x86: Don't update RIP or do single-step on faulting emulation
+    - x86/apic: Do not initialize LDR and DFR for bigsmp
+    - x86/apic: Include the LDR when clearing out APIC registers
+    - usb-storage: Add new JMS567 revision to unusual_devs
+    - USB: cdc-wdm: fix race between write and disconnect due to flag abuse
+    - usb: host: ohci: fix a race condition between shutdown and irq
+    - USB: storage: ums-realtek: Update module parameter description for
+      auto_delink_en
+    - ptrace,x86: Make user_64bit_mode() available to 32-bit builds
+    - uprobes/x86: Fix detection of 32-bit user mode
+    - mmc: sdhci-of-at91: add quirk for broken HS200
+    - mmc: core: Fix init of SD cards reporting an invalid VDD range
+    - stm class: Fix a double free of stm_source_device
+    - VMCI: Release resource if the work is already queued
+    - Revert "cfg80211: fix processing world regdomain when non modular"
+    - mac80211: fix possible sta leak
+    - x86/ptrace: fix up botched merge of spectrev1 fix
+    - Linux 4.4.191
+
+  * New ID in ums-realtek module breaks cardreader (LP: #1838886) // Xenial
+    update: 4.4.191 upstream stable release (LP: #1845036)
+    - USB: storage: ums-realtek: Whitelist auto-delink support
+
+  * Xenial update: 4.4.190 upstream stable release (LP: #1845038)
+    - usb: iowarrior: fix deadlock on disconnect
+    - sound: fix a memory leak bug
+    - x86/mm: Check for pfn instead of page in vmalloc_sync_one()
+    - x86/mm: Sync also unmappings in vmalloc_sync_all()
+    - mm/vmalloc: Sync unmappings in __purge_vmap_area_lazy()
+    - perf db-export: Fix thread__exec_comm()
+    - usb: yurex: Fix use-after-free in yurex_delete
+    - can: peak_usb: fix potential double kfree_skb()
+    - netfilter: nfnetlink: avoid deadlock due to synchronous request_module
+    - iscsi_ibft: make ISCSI_IBFT dependson ACPI instead of ISCSI_IBFT_FIND
+    - mac80211: don't warn about CW params when not using them
+    - hwmon: (nct6775) Fix register address and added missed tolerance for nct6106
+    - cpufreq/pasemi: fix use-after-free in pas_cpufreq_cpu_init()
+    - s390/qdio: add sanity checks to the fast-requeue path
+    - ALSA: compress: Fix regression on compressed capture streams
+    - ALSA: compress: Prevent bypasses of set_params
+    - ALSA: compress: Be more restrictive about when a drain is allowed
+    - perf probe: Avoid calling freeing routine multiple times for same pointer
+    - ARM: davinci: fix sleep.S build error on ARMv4
+    - scsi: megaraid_sas: fix panic on loading firmware crashdump
+    - scsi: ibmvfc: fix WARN_ON during event pool release
+    - tty/ldsem, locking/rwsem: Add missing ACQUIRE to read_failed sleep loop
+    - perf/core: Fix creating kernel counters for PMUs that override event->cpu
+    - can: peak_usb: pcan_usb_pro: Fix info-leaks to USB devices
+    - can: peak_usb: pcan_usb_fd: Fix info-leaks to USB devices
+    - hwmon: (nct7802) Fix wrong detection of in4 presence
+    - ALSA: firewire: fix a memory leak bug
+    - mac80211: don't WARN on short WMM parameters from AP
+    - SMB3: Fix deadlock in validate negotiate hits reconnect
+    - smb3: send CAP_DFS capability during session setup
+    - mwifiex: fix 802.11n/WPA detection
+    - scsi: mpt3sas: Use 63-bit DMA addressing on SAS35 HBA
+    - sh: kernel: hw_breakpoint: Fix missing break in switch statement
+    - mm/memcontrol.c: fix use after free in mem_cgroup_iter()
+    - ALSA: hda - Fix a memory leak bug
+    - HID: holtek: test for sanity of intfdata
+    - HID: hiddev: avoid opening a disconnected device
+    - HID: hiddev: do cleanup in failure of opening a device
+    - Input: kbtab - sanity check for endpoint type
+    - Input: iforce - add sanity checks
+    - net: usb: pegasus: fix improper read if get_registers() fail
+    - xen/pciback: remove set but not used variable 'old_state'
+    - irqchip/irq-imx-gpcv2: Forward irq type to parent
+    - perf header: Fix divide by zero error if f_header.attr_size==0
+    - perf header: Fix use of unitialized value warning
+    - libata: zpodd: Fix small read overflow in zpodd_get_mech_type()
+    - scsi: hpsa: correct scsi command status issue after reset
+    - ata: libahci: do not complain in case of deferred probe
+    - kbuild: modpost: handle KBUILD_EXTRA_SYMBOLS only for external modules
+    - IB/core: Add mitigation for Spectre V1
+    - ocfs2: remove set but not used variable 'last_hash'
+    - asm-generic: fix -Wtype-limits compiler warnings
+    - staging: comedi: dt3000: Fix signed integer overflow 'divider * base'
+    - staging: comedi: dt3000: Fix rounding up of timer divisor
+    - USB: core: Fix races in character device registration and deregistraion
+    - usb: cdc-acm: make sure a refcount is taken early enough
+    - USB: serial: option: add D-Link DWM-222 device ID
+    - USB: serial: option: Add support for ZTE MF871A
+    - USB: serial: option: add the BroadMobi BM818 card
+    - USB: serial: option: Add Motorola modem UARTs
+    - Backport minimal compiler_attributes.h to support GCC 9
+    - include/linux/module.h: copy __init/__exit attrs to init/cleanup_module
+    - arm64: compat: Allow single-byte watchpoints on all addresses
+    - Input: psmouse - fix build error of multiple definition
+    - asm-generic: default BUG_ON(x) to if(x)BUG()
+    - scsi: fcoe: Embed fc_rport_priv in fcoe_rport structure
+    - RDMA: Directly cast the sockaddr union to sockaddr
+    - IB/mlx5: Make coding style more consistent
+    - x86/vdso: Remove direct HPET access through the vDSO
+    - iommu/amd: Move iommu_init_pci() to .init section
+    - x86/boot: Disable the address-of-packed-member compiler warning
+    - net/packet: fix race in tpacket_snd()
+    - xen/netback: Reset nr_frags before freeing skb
+    - net/mlx5e: Only support tx/rx pause setting for port owner
+    - sctp: fix the transport error_count check
+    - bonding: Add vlan tx offload to hw_enc_features
+    - Linux 4.4.190
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 01 Oct 2019 10:23:59 +0200
+
+linux (4.4.0-165.193) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-165.193 -proposed tracker (LP: #1844416)
+
+  * Xenial update: 4.4.187 upstream stable release (LP: #1840081)
+    - MIPS: ath79: fix ar933x uart parity mode
+    - MIPS: fix build on non-linux hosts
+    - dmaengine: imx-sdma: fix use-after-free on probe error path
+    - ath10k: Do not send probe response template for mesh
+    - ath9k: Check for errors when reading SREV register
+    - ath6kl: add some bounds checking
+    - ath: DFS JP domain W56 fixed pulse type 3 RADAR detection
+    - batman-adv: fix for leaked TVLV handler.
+    - media: dvb: usb: fix use after free in dvb_usb_device_exit
+    - crypto: talitos - fix skcipher failure due to wrong output IV
+    - media: marvell-ccic: fix DMA s/g desc number calculation
+    - media: vpss: fix a potential NULL pointer dereference
+    - net: stmmac: dwmac1000: Clear unused address entries
+    - signal/pid_namespace: Fix reboot_pid_ns to use send_sig not force_sig
+    - af_key: fix leaks in key_pol_get_resp and dump_sp.
+    - xfrm: Fix xfrm sel prefix length validation
+    - media: staging: media: davinci_vpfe: - Fix for memory leak if decoder
+      initialization fails.
+    - net: phy: Check against net_device being NULL
+    - tua6100: Avoid build warnings.
+    - locking/lockdep: Fix merging of hlocks with non-zero references
+    - media: wl128x: Fix some error handling in fm_v4l2_init_video_device()
+    - cpupower : frequency-set -r option misses the last cpu in related cpu list
+    - net: fec: Do not use netdev messages too early
+    - net: axienet: Fix race condition causing TX hang
+    - s390/qdio: handle PENDING state for QEBSM devices
+    - perf test 6: Fix missing kvm module load for s390
+    - gpio: omap: fix lack of irqstatus_raw0 for OMAP4
+    - gpio: omap: ensure irq is enabled before wakeup
+    - regmap: fix bulk writes on paged registers
+    - bpf: silence warning messages in core
+    - rcu: Force inlining of rcu_read_lock()
+    - xfrm: fix sa selector validation
+    - perf evsel: Make perf_evsel__name() accept a NULL argument
+    - vhost_net: disable zerocopy by default
+    - EDAC/sysfs: Fix memory leak when creating a csrow object
+    - media: i2c: fix warning same module names
+    - ntp: Limit TAI-UTC offset
+    - timer_list: Guard procfs specific code
+    - acpi/arm64: ignore 5.1 FADTs that are reported as 5.0
+    - media: coda: fix mpeg2 sequence number handling
+    - media: coda: increment sequence offset for the last returned frame
+    - mt7601u: do not schedule rx_tasklet when the device has been disconnected
+    - x86/build: Add 'set -e' to mkcapflags.sh to delete broken capflags.c
+    - mt7601u: fix possible memory leak when the device is disconnected
+    - ath10k: fix PCIE device wake up failed
+    - rslib: Fix decoding of shortened codes
+    - rslib: Fix handling of of caller provided syndrome
+    - ixgbe: Check DDM existence in transceiver before access
+    - EDAC: Fix global-out-of-bounds write when setting edac_mc_poll_msec
+    - bcache: check c->gc_thread by IS_ERR_OR_NULL in cache_set_flush()
+    - Bluetooth: hci_bcsp: Fix memory leak in rx_skb
+    - Bluetooth: 6lowpan: search for destination address in all peers
+    - Bluetooth: Check state in l2cap_disconnect_rsp
+    - Bluetooth: validate BLE connection interval updates
+    - crypto: ghash - fix unaligned memory access in ghash_setkey()
+    - crypto: arm64/sha1-ce - correct digest for empty data in finup
+    - crypto: arm64/sha2-ce - correct digest for empty data in finup
+    - Input: gtco - bounds check collection indent level
+    - regulator: s2mps11: Fix buck7 and buck8 wrong voltages
+    - tracing/snapshot: Resize spare buffer if size changed
+    - NFSv4: Handle the special Linux file open access mode
+    - lib/scatterlist: Fix mapping iterator when sg->offset is greater than
+      PAGE_SIZE
+    - ALSA: seq: Break too long mutex context in the write loop
+    - media: v4l2: Test type instead of cfg->type in v4l2_ctrl_new_custom()
+    - media: coda: Remove unbalanced and unneeded mutex unlock
+    - KVM: x86/vPMU: refine kvm_pmu err msg when event creation failed
+    - drm/nouveau/i2c: Enable i2c pads & busses during preinit
+    - padata: use smp_mb in padata_reorder to avoid orphaned padata jobs
+    - 9p/virtio: Add cleanup path in p9_virtio_init
+    - PCI: Do not poll for PME if the device is in D3cold
+    - take floppy compat ioctls to sodding floppy.c
+    - floppy: fix out-of-bounds read in next_valid_format
+    - floppy: fix invalid pointer dereference in drive_name
+    - coda: pass the host file in vma->vm_file on mmap
+    - gpu: ipu-v3: ipu-ic: Fix saturation bit offset in TPMEM
+    - parisc: Fix kernel panic due invalid values in IAOQ0 or IAOQ1
+    - powerpc/32s: fix suspend/resume when IBATs 4-7 are used
+    - powerpc/watchpoint: Restore NV GPRs while returning from exception
+    - eCryptfs: fix a couple type promotion bugs
+    - intel_th: msu: Fix single mode with disabled IOMMU
+    - Bluetooth: Add SMP workaround Microsoft Surface Precision Mouse bug
+    - usb: Handle USB3 remote wakeup for LPM enabled devices correctly
+    - dm bufio: fix deadlock with loop device
+    - bnx2x: Prevent load reordering in tx completion processing
+    - caif-hsi: fix possible deadlock in cfhsi_exit_module()
+    - ipv4: don't set IPv6 only flags to IPv4 addresses
+    - net: bcmgenet: use promisc for unsupported filters
+    - net: neigh: fix multiple neigh timer scheduling
+    - nfc: fix potential illegal memory access
+    - sky2: Disable MSI on ASUS P6T
+    - netrom: fix a memory leak in nr_rx_frame()
+    - netrom: hold sock when setting skb->destructor
+    - tcp: Reset bytes_acked and bytes_received when disconnecting
+    - bonding: validate ip header before check IPPROTO_IGMP
+    - net: bridge: mcast: fix stale nsrcs pointer in igmp3/mld2 report handling
+    - net: bridge: mcast: fix stale ipv6 hdr pointer when handling v6 query
+    - net: bridge: stp: don't cache eth dest pointer before skb pull
+    - elevator: fix truncation of icq_cache_name
+    - NFSv4: Fix open create exclusive when the server reboots
+    - nfsd: increase DRC cache limit
+    - nfsd: give out fewer session slots as limit approaches
+    - nfsd: fix performance-limiting session calculation
+    - nfsd: Fix overflow causing non-working mounts on 1 TB machines
+    - drm/panel: simple: Fix panel_simple_dsi_probe
+    - usb: core: hub: Disable hub-initiated U1/U2
+    - tty: max310x: Fix invalid baudrate divisors calculator
+    - pinctrl: rockchip: fix leaked of_node references
+    - tty: serial: cpm_uart - fix init when SMC is relocated
+    - memstick: Fix error cleanup path of memstick_init
+    - tty/serial: digicolor: Fix digicolor-usart already registered warning
+    - tty: serial: msm_serial: avoid system lockup condition
+    - drm/virtio: Add memory barriers for capset cache.
+    - phy: renesas: rcar-gen2: Fix memory leak at error paths
+    - usb: gadget: Zero ffs_io_data
+    - powerpc/pci/of: Fix OF flags parsing for 64bit BARs
+    - PCI: sysfs: Ignore lockdep for remove attribute
+    - iio: iio-utils: Fix possible incorrect mask calculation
+    - recordmcount: Fix spurious mcount entries on powerpc
+    - mfd: core: Set fwnode for created devices
+    - mfd: arizona: Fix undefined behavior
+    - um: Silence lockdep complaint about mmap_sem
+    - powerpc/4xx/uic: clear pending interrupt after irq type/pol change
+    - serial: sh-sci: Fix TX DMA buffer flushing and workqueue races
+    - kallsyms: exclude kasan local symbols on s390
+    - perf test mmap-thread-lookup: Initialize variable to suppress memory
+      sanitizer warning
+    - f2fs: avoid out-of-range memory access
+    - mailbox: handle failed named mailbox channel request
+    - powerpc/eeh: Handle hugepages in ioremap space
+    - sh: prevent warnings when using iounmap
+    - mm/kmemleak.c: fix check for softirq context
+    - 9p: pass the correct prototype to read_cache_page
+    - mm/mmu_notifier: use hlist_add_head_rcu()
+    - locking/lockdep: Fix lock used or unused stats error
+    - locking/lockdep: Hide unused 'class' variable
+    - usb: wusbcore: fix unbalanced get/put cluster_id
+    - usb: pci-quirks: Correct AMD PLL quirk detection
+    - x86/sysfb_efi: Add quirks for some devices with swapped width and height
+    - x86/speculation/mds: Apply more accurate check on hypervisor platform
+    - hpet: Fix division by zero in hpet_time_div()
+    - ALSA: hda - Add a conexant codec entry to let mute led work
+    - access: avoid the RCU grace period for the temporary subjective credentials
+    - vmstat: Remove BUG_ON from vmstat_update
+    - mm, vmstat: make quiet_vmstat lighter
+    - ipv6: check sk sk_type and protocol early in ip_mroute_set/getsockopt
+    - tcp: reset sk_send_head in tcp_write_queue_purge
+    - ISDN: hfcsusb: checking idx of ep configuration
+    - media: cpia2_usb: first wake up, then free in disconnect
+    - media: radio-raremono: change devm_k*alloc to k*alloc
+    - Bluetooth: hci_uart: check for missing tty operations
+    - sched/fair: Don't free p->numa_faults with concurrent readers
+    - drivers/pps/pps.c: clear offset flags in PPS_SETPARAMS ioctl
+    - ceph: hold i_ceph_lock when removing caps for freeing inode
+    - Linux 4.4.187
+    - perf tests: Add valid callback for parse-events test
+    - SAUCE: Fix perf test 6: Fix missing kvm module load for s390
+
+  * CVE-2018-20976
+    - xfs: clear sb->s_fs_info on mount failure
+
+  * Xenial update: 4.4.189 upstream stable release (LP: #1840335)
+    - arm64: cpufeature: Fix CTR_EL0 field definitions
+    - arm64: cpufeature: Fix feature comparison for CTR_EL0.{CWG,ERG}
+    - netfilter: nfnetlink_acct: validate NFACCT_QUOTA parameter
+    - HID: Add quirk for HP X1200 PIXART OEM mouse
+    - tcp: be more careful in tcp_fragment()
+    - atm: iphase: Fix Spectre v1 vulnerability
+    - net: bridge: delete local fdb on device init failure
+    - net: fix ifindex collision during namespace removal
+    - tipc: compat: allow tipc commands without arguments
+    - net: sched: Fix a possible null-pointer dereference in dequeue_func()
+    - net/mlx5: Use reversed order when unregister devices
+    - bnx2x: Disable multi-cos feature.
+    - compat_ioctl: pppoe: fix PPPOEIOCSFWD handling
+    - spi: bcm2835: Fix 3-wire mode if DMA is enabled
+    - x86: cpufeatures: Sort feature word 7
+    - x86/entry/64: Fix context tracking state warning when load_gs_index fails
+    - Linux 4.4.189
+
+  * CVE-2019-0136
+    - mac80211: handle deauthentication/disassociation from TDLS peer
+
+  * skb_warn_bad_offload kernel splat due to CHECKSUM target not compatible with
+    GSO skbs (LP: #1840619)
+    - netfilter: xt_checksum: ignore gso skbs
+
+  * CVE-2018-20961
+    - usb: gadget: f_midi: fail if set_alt fails to allocate requests
+    - USB: gadget: f_midi: fixing a possible double-free in f_midi
+
+  * CVE-2019-11487
+    - pipe: add pipe_buf_get() helper
+    - mm: add 'try_get_page()' helper function
+    - fs: prevent page refcount overflow in pipe_buf_get
+    - mm: make page ref count overflow check tighter and more explicit
+    - mm, gup: ensure real head page is ref-counted when using hugepages
+    - mm: prevent get_user_pages() from overflowing page refcount
+
+  * Xenial update: 4.4.188 upstream stable release (LP: #1840289)
+    - ARM: riscpc: fix DMA
+    - ARM: dts: rockchip: Mark that the rk3288 timer might stop in suspend
+    - kernel/module.c: Only return -EEXIST for modules that have finished loading
+    - MIPS: lantiq: Fix bitfield masking
+    - dmaengine: rcar-dmac: Reject zero-length slave DMA requests
+    - fs/adfs: super: fix use-after-free bug
+    - btrfs: fix minimum number of chunk errors for DUP
+    - ceph: fix improper use of smp_mb__before_atomic()
+    - scsi: zfcp: fix GCC compiler warning emitted with -Wmaybe-uninitialized
+    - ACPI: fix false-positive -Wuninitialized warning
+    - be2net: Signal that the device cannot transmit during reconfiguration
+    - x86/apic: Silence -Wtype-limits compiler warnings
+    - x86: math-emu: Hide clang warnings for 16-bit overflow
+    - mm/cma.c: fail if fixed declaration can't be honored
+    - coda: add error handling for fget
+    - coda: fix build using bare-metal toolchain
+    - uapi linux/coda_psdev.h: move upc_req definition from uapi to kernel side
+      headers
+    - ipc/mqueue.c: only perform resource calculation if user valid
+    - x86/kvm: Don't call kvm_spurious_fault() from .fixup
+    - selinux: fix memory leak in policydb_init()
+    - s390/dasd: fix endless loop after read unit address configuration
+    - xen/swiotlb: fix condition for calling xen_destroy_contiguous_region()
+    - Linux 4.4.188
+
+  * Line 6 POD HD500 driver fault (LP: #1790595) // Xenial update: 4.4.187
+    upstream stable release (LP: #1840081)
+    - ALSA: line6: Fix wrong altsetting for LINE6_PODHD500_1
+
+  * CVE-2016-10905
+    - GFS2: don't set rgrp gl_object until it's inserted into rgrp tree
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 17 Sep 2019 18:24:13 +0200
+
+linux (4.4.0-164.192) xenial; urgency=medium
+
+  * CVE-2019-14835
+    - SAUCE: vhost: make sure log_num < in_num
+
+ -- Juerg Haefliger <juergh@canonical.com>  Fri, 13 Sep 2019 12:55:05 +0200
+
+linux (4.4.0-161.189) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-161.189 -proposed tracker (LP: #1841544)
+
+  * flock not mediated by 'k' (LP: 1658219)
+    - Revert "UBUNTU: SAUCE: apparmor: flock mediation is not being, enforced on
+      cache check"
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 27 Aug 2019 09:49:19 +0200
+
+linux (4.4.0-160.188) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-160.188 -proposed tracker (LP: #1840021)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * EeePC 1005px laptop backlight is off after system boot up (LP: #1837117)
+    - platform/x86: asus-wmi: Only Tell EC the OS will handle display hotkeys from
+      asus_nb_wmi
+
+  * CVE-2019-10638
+    - [Config] CONFIG_TEST_HASH=n
+    - siphash: add cryptographically secure PRF
+    - inet: switch IP ID generator to siphash
+
+  * Stacked onexec transitions fail when under NO NEW PRIVS restrictions
+    (LP: #1839037)
+    - SAUCE: apparmor: fix nnp subset check failure, when stacking
+
+  * AppArmor onexec transition causes WARN kernel stack trace (LP: #1838627)
+    - SAUCE: apparmor: fix audit failures when performing profile transitions
+
+  * flock not mediated by 'k' (LP: 1658219) // Ubuntu 16.04: read access
+    incorrectly implies 'm' rule (LP: 1838090)
+    - SAUCE: apparmor: flock mediation is not being, enforced on cache check
+
+  * bcache: bch_allocator_thread(): hung task timeout (LP: #1784665) // Tight
+    timeout for bcache removal causes spurious failures (LP: #1796292)
+    - SAUCE: bcache: fix deadlock in bcache_allocator
+
+  * bcache: bch_allocator_thread(): hung task timeout (LP: #1784665)
+    - bcache: improve bcache_reboot()
+    - bcache: add journal statistic
+    - bcache: fix high CPU occupancy during journal
+    - bcache: fix incorrect sysfs output value of strip size
+    - bcache: fix error return value in memory shrink
+    - bcache: fix using of loop variable in memory shrink
+    - bcache: Fix indentation
+    - bcache: Add __printf annotation to __bch_check_keys()
+    - bcache: Annotate switch fall-through
+    - bcache: Fix kernel-doc warnings
+    - bcache: Remove an unused variable
+    - bcache: Suppress more warnings about set-but-not-used variables
+    - bcache: Reduce the number of sparse complaints about lock imbalances
+    - bcache: Move couple of functions to sysfs.c
+
+  * CVE-2019-3900
+    - vhost: introduce vhost_vq_avail_empty()
+    - vhost_net: tx batching
+    - vhost_net: do not stall on zerocopy depletion
+    - vhost-net: set packet weight of tx polling to 2 * vq size
+    - vhost_net: use packet weight for rx handler, too
+    - vhost_net: introduce vhost_exceeds_weight()
+    - vhost: introduce vhost_exceeds_weight()
+    - vhost_net: fix possible infinite loop
+    - vhost: scsi: add weight support
+
+  * Xenial: ZFS deadlock in shrinker path with xattrs (LP: #1839521)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu28
+
+  * CVE-2019-13648
+    - powerpc/tm: Fix oops on sigreturn on systems without TM
+
+  * CVE-2018-20856
+    - block: blk_init_allocated_queue() set q->fq as NULL in the fail case
+
+  * CVE-2019-14283
+    - floppy: fix out-of-bounds read in copy_buffer
+
+  * CVE-2019-14284
+    - floppy: fix div-by-zero in setup_format_params
+
+  * Xenial update: 4.4.186 upstream stable release (LP: #1838467)
+    - Input: elantech - enable middle button support on 2 ThinkPads
+    - samples, bpf: fix to change the buffer size for read()
+    - mac80211: mesh: fix RCU warning
+    - dt-bindings: can: mcp251x: add mcp25625 support
+    - can: mcp251x: add support for mcp25625
+    - Input: imx_keypad - make sure keyboard can always wake up system
+    - ARM: davinci: da850-evm: call regulator_has_full_constraints()
+    - ARM: davinci: da8xx: specify dma_coherent_mask for lcdc
+    - md: fix for divide error in status_resync
+    - bnx2x: Check if transceiver implements DDM before access
+    - udf: Fix incorrect final NOT_ALLOCATED (hole) extent length
+    - x86/ptrace: Fix possible spectre-v1 in ptrace_get_debugreg()
+    - x86/tls: Fix possible spectre-v1 in do_get_thread_area()
+    - mwifiex: Abort at too short BSS descriptor element
+    - fscrypt: don't set policy for a dead directory
+    - mwifiex: Don't abort on small, spec-compliant vendor IEs
+    - USB: serial: ftdi_sio: add ID for isodebug v1
+    - USB: serial: option: add support for GosunCn ME3630 RNDIS mode
+    - usb: gadget: ether: Fix race between gether_disconnect and rx_submit
+    - usb: renesas_usbhs: add a workaround for a race condition of workqueue
+    - staging: comedi: dt282x: fix a null pointer deref on interrupt
+    - staging: comedi: amplc_pci230: fix null pointer deref on interrupt
+    - carl9170: fix misuse of device driver API
+    - VMCI: Fix integer overflow in VMCI handle arrays
+    - MIPS: Remove superfluous check for __linux__
+    - e1000e: start network tx queue only when link is up
+    - perf/core: Fix perf_sample_regs_user() mm check
+    - ARM: omap2: remove incorrect __init annotation
+    - be2net: fix link failure after ethtool offline test
+    - ppp: mppe: Add softdep to arc4
+    - sis900: fix TX completion
+    - dm verity: use message limit for data block corruption message
+    - kvm: x86: avoid warning on repeated KVM_SET_TSS_ADDR
+    - ARC: hide unused function unw_hdr_alloc
+    - s390: fix stfle zero padding
+    - s390/qdio: (re-)initialize tiqdio list entries
+    - s390/qdio: don't touch the dsci in tiqdio_add_input_queues()
+    - KVM: x86: protect KVM_CREATE_PIT/KVM_CREATE_PIT2 with kvm->lock
+    - Linux 4.4.186
+
+ -- Connor Kuehl <connor.kuehl@canonical.com>  Tue, 13 Aug 2019 14:54:45 -0700
+
+linux (4.4.0-159.187) xenial; urgency=medium
+
+  * CVE-2019-1125
+    - x86/cpufeatures: Carve out CQM features retrieval
+    - x86/cpufeatures: Combine word 11 and 12 into a new scattered features word
+    - x86/speculation: Prepare entry code for Spectre v1 swapgs mitigations
+    - x86/speculation: Enable Spectre v1 swapgs mitigations
+    - x86/entry/64: Use JMP instead of JMPQ
+    - x86/speculation/swapgs: Exclude ATOMs from speculation through SWAPGS
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 01 Aug 2019 17:22:24 +0200
+
+linux (4.4.0-158.186) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-158.186 -proposed tracker (LP: #1837609)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] update helper scripts
+
+  * ixgbe{vf} - Physical Function gets IRQ when VF checks link state
+    (LP: #1836760)
+    - ixgbevf: Use cached link state instead of re-reading the value for ethtool
+
+  * CVE-2018-5383
+    - crypto: kpp - Key-agreement Protocol Primitives API (KPP)
+    - crypto: dh - Add DH software implementation
+    - crypto: ecdh - Add ECDH software support
+    - crypto: ecdh - make ecdh_shared_secret unique
+    - crypto: doc - add KPP documentation
+    - crypto: kpp, (ec)dh - fix typos
+    - crypto: ecc - remove unused function arguments
+    - crypto: ecc - remove unnecessary casts
+    - crypto: ecc - rename ecdh_make_pub_key()
+    - crypto: ecdh - add privkey generation support
+    - crypto: ecc - Fix NULL pointer deref. on no default_rng
+    - [Config] CRYPTO_ECDH=m
+    - Bluetooth: convert smp and selftest to crypto kpp API
+    - crypto: ecdh - add public key verification test
+
+  * Xenial update: 4.4.185 upstream stable release (LP: #1836668)
+    - fs/binfmt_flat.c: make load_flat_shared_library() work
+    - scsi: vmw_pscsi: Fix use-after-free in pvscsi_queue_lck()
+    - tracing: Silence GCC 9 array bounds warning
+    - gcc-9: silence 'address-of-packed-member' warning
+    - usb: chipidea: udc: workaround for endpoint conflict issue
+    - Input: uinput - add compat ioctl number translation for UI_*_FF_UPLOAD
+    - apparmor: enforce nullbyte at end of tag string
+    - parport: Fix mem leak in parport_register_dev_model
+    - parisc: Fix compiler warnings in float emulation code
+    - IB/hfi1: Insure freeze_work work_struct is canceled on shutdown
+    - MIPS: uprobes: remove set but not used variable 'epc'
+    - net: hns: Fix loopback test failed at copper ports
+    - sparc: perf: fix updated event period in response to PERF_EVENT_IOC_PERIOD
+    - scripts/checkstack.pl: Fix arm64 wrong or unknown architecture
+    - scsi: ufs: Check that space was properly alloced in copy_query_response
+    - s390/qeth: fix VLAN attribute in bridge_hostnotify udev event
+    - hwmon: (pmbus/core) Treat parameters as paged if on multiple pages
+    - Btrfs: fix race between readahead and device replace/removal
+    - btrfs: start readahead also in seed devices
+    - can: flexcan: fix timeout when set small bitrate
+    - can: purge socket error queue on sock destruct
+    - ARM: imx: cpuidle-imx6sx: Restrict the SW2ISO increase to i.MX6SX
+    - Bluetooth: Align minimum encryption key size for LE and BR/EDR connections
+    - Bluetooth: Fix regression with minimum encryption key size alignment
+    - SMB3: retry on STATUS_INSUFFICIENT_RESOURCES instead of failing write
+    - cfg80211: fix memory leak of wiphy device name
+    - mac80211: drop robust management frames from unknown TA
+    - perf ui helpline: Use strlcpy() as a shorter form of strncpy() + explicit
+      set nul
+    - perf help: Remove needless use of strncpy()
+    - 9p/rdma: do not disconnect on down_interruptible EAGAIN
+    - 9p: acl: fix uninitialized iattr access
+    - 9p/rdma: remove useless check in cm_event_handler
+    - 9p: p9dirent_read: check network-provided name length
+    - net/9p: include trans_common.h to fix missing prototype warning.
+    - ovl: modify ovl_permission() to do checks on two inodes
+    - x86/speculation: Allow guests to use SSBD even if host does not
+    - cpu/speculation: Warn on unsupported mitigations= parameter
+    - sctp: change to hold sk after auth shkey is created successfully
+    - tipc: change to use register_pernet_device
+    - tipc: check msg->req data len in tipc_nl_compat_bearer_disable
+    - team: Always enable vlan tx offload
+    - ipv4: Use return value of inet_iif() for __raw_v4_lookup in the while loop
+    - bonding: Always enable vlan tx offload
+    - net: check before dereferencing netdev_ops during busy poll
+    - Bluetooth: Fix faulty expression for minimum encryption key size check
+    - um: Compile with modern headers
+    - ASoC : cs4265 : readable register too low
+    - spi: bitbang: Fix NULL pointer dereference in spi_unregister_master
+    - ASoC: max98090: remove 24-bit format support if RJ is 0
+    - usb: gadget: fusb300_udc: Fix memory leak of fusb300->ep[i]
+    - usb: gadget: udc: lpc32xx: allocate descriptor with GFP_ATOMIC
+    - scsi: hpsa: correct ioaccel2 chaining
+    - ARC: Assume multiplier is always present
+    - ARC: fix build warning in elf.h
+    - MIPS: math-emu: do not use bools for arithmetic
+    - mfd: omap-usb-tll: Fix register offsets
+    - swiotlb: Make linux/swiotlb.h standalone includible
+    - bug.h: work around GCC PR82365 in BUG()
+    - MIPS: Workaround GCC __builtin_unreachable reordering bug
+    - ptrace: Fix ->ptracer_cred handling for PTRACE_TRACEME
+    - crypto: user - prevent operating on larval algorithms
+    - ALSA: seq: fix incorrect order of dest_client/dest_ports arguments
+    - ALSA: firewire-lib/fireworks: fix miss detection of received MIDI messages
+    - ALSA: usb-audio: fix sign unintended sign extension on left shifts
+    - lib/mpi: Fix karactx leak in mpi_powm
+    - btrfs: Ensure replaced device doesn't have pending chunk allocation
+    - tty: rocket: fix incorrect forward declaration of 'rp_init()'
+    - ARC: handle gcc generated __builtin_trap for older compiler
+    - arm64, vdso: Define vdso_{start,end} as array
+    - KVM: x86: degrade WARN to pr_warn_ratelimited
+    - dmaengine: imx-sdma: remove BD_INTR for channel0
+    - Linux 4.4.185
+
+  * Xenial update: 4.4.184 upstream stable release (LP: #1836667)
+    - Linux 4.4.184
+
+  * Xenial update: 4.4.183 upstream stable release (LP: #1836666)
+    - fs/fat/file.c: issue flush after the writeback of FAT
+    - sysctl: return -EINVAL if val violates minmax
+    - ipc: prevent lockup on alloc_msg and free_msg
+    - hugetlbfs: on restore reserve error path retain subpool reservation
+    - mm/cma.c: fix crash on CMA allocation if bitmap allocation fails
+    - mm/cma_debug.c: fix the break condition in cma_maxchunk_get()
+    - kernel/sys.c: prctl: fix false positive in validate_prctl_map()
+    - mfd: intel-lpss: Set the device in reset state when init
+    - mfd: twl6040: Fix device init errors for ACCCTL register
+    - perf/x86/intel: Allow PEBS multi-entry in watermark mode
+    - drm/bridge: adv7511: Fix low refresh rate selection
+    - ntp: Allow TAI-UTC offset to be set to zero
+    - f2fs: fix to avoid panic in do_recover_data()
+    - f2fs: fix to do sanity check on valid block count of segment
+    - iommu/vt-d: Set intel_iommu_gfx_mapped correctly
+    - ALSA: hda - Register irq handler after the chip initialization
+    - nvmem: core: fix read buffer in place
+    - fuse: retrieve: cap requested size to negotiated max_write
+    - nfsd: allow fh_want_write to be called twice
+    - x86/PCI: Fix PCI IRQ routing table memory leak
+    - platform/chrome: cros_ec_proto: check for NULL transfer function
+    - soc: mediatek: pwrap: Zero initialize rdata in pwrap_init_cipher
+    - clk: rockchip: Turn on "aclk_dmac1" for suspend on rk3288
+    - ARM: dts: imx6sx: Specify IMX6SX_CLK_IPG as "ahb" clock to SDMA
+    - ARM: dts: imx6sx: Specify IMX6SX_CLK_IPG as "ipg" clock to SDMA
+    - ARM: dts: imx6qdl: Specify IMX6QDL_CLK_IPG as "ipg" clock to SDMA
+    - PCI: rpadlpar: Fix leaked device_node references in add/remove paths
+    - PCI: rcar: Fix a potential NULL pointer dereference
+    - video: hgafb: fix potential NULL pointer dereference
+    - video: imsttfb: fix potential NULL pointer dereferences
+    - PCI: xilinx: Check for __get_free_pages() failure
+    - gpio: gpio-omap: add check for off wake capable gpios
+    - dmaengine: idma64: Use actual device for DMA transfers
+    - pwm: tiehrpwm: Update shadow register for disabling PWMs
+    - ARM: dts: exynos: Always enable necessary APIO_1V8 and ABB_1V8 regulators on
+      Arndale Octa
+    - pwm: Fix deadlock warning when removing PWM device
+    - ARM: exynos: Fix undefined instruction during Exynos5422 resume
+    - futex: Fix futex lock the wrong page
+    - ALSA: seq: Cover unsubscribe_port() in list_mutex
+    - libata: Extend quirks for the ST1000LM024 drives with NOLPM quirk
+    - mm/list_lru.c: fix memory leak in __memcg_init_list_lru_node
+    - fs/ocfs2: fix race in ocfs2_dentry_attach_lock()
+    - signal/ptrace: Don't leak unitialized kernel memory with PTRACE_PEEK_SIGINFO
+    - ptrace: restore smp_rmb() in __ptrace_may_access()
+    - i2c: acorn: fix i2c warning
+    - bcache: fix stack corruption by PRECEDING_KEY()
+    - cgroup: Use css_tryget() instead of css_tryget_online() in task_get_css()
+    - ASoC: cs42xx8: Add regcache mask dirty
+    - Drivers: misc: fix out-of-bounds access in function param_set_kgdbts_var
+    - scsi: lpfc: add check for loss of ndlp when sending RRQ
+    - scsi: bnx2fc: fix incorrect cast to u64 on shift operation
+    - usbnet: ipheth: fix racing condition
+    - KVM: x86/pmu: do not mask the value that is written to fixed PMUs
+    - KVM: s390: fix memory slot handling for KVM_SET_USER_MEMORY_REGION
+    - drm/vmwgfx: integer underflow in vmw_cmd_dx_set_shader() leading to an
+      invalid read
+    - drm/vmwgfx: NULL pointer dereference from vmw_cmd_dx_view_define()
+    - USB: Fix chipmunk-like voice when using Logitech C270 for recording audio.
+    - USB: usb-storage: Add new ID to ums-realtek
+    - USB: serial: pl2303: add Allied Telesis VT-Kit3
+    - USB: serial: option: add support for Simcom SIM7500/SIM7600 RNDIS mode
+    - USB: serial: option: add Telit 0x1260 and 0x1261 compositions
+    - ax25: fix inconsistent lock state in ax25_destroy_timer
+    - be2net: Fix number of Rx queues used for flow hashing
+    - ipv6: flowlabel: fl6_sock_lookup() must use atomic_inc_not_zero
+    - lapb: fixed leak of control-blocks.
+    - neigh: fix use-after-free read in pneigh_get_next
+    - sunhv: Fix device naming inconsistency between sunhv_console and sunhv_reg
+    - mISDN: make sure device name is NUL terminated
+    - x86/CPU/AMD: Don't force the CPB cap when running under a hypervisor
+    - perf/ring_buffer: Fix exposing a temporarily decreased data_head
+    - perf/ring_buffer: Add ordering to rb->nest increment
+    - gpio: fix gpio-adp5588 build errors
+    - net: tulip: de4x5: Drop redundant MODULE_DEVICE_TABLE()
+    - i2c: dev: fix potential memory leak in i2cdev_ioctl_rdwr
+    - configfs: Fix use-after-free when accessing sd->s_dentry
+    - ia64: fix build errors by exporting paddr_to_nid()
+    - KVM: PPC: Book3S: Use new mutex to synchronize access to rtas token list
+    - net: sh_eth: fix mdio access in sh_eth_close() for R-Car Gen2 and RZ/A1 SoCs
+    - scsi: libcxgbi: add a check for NULL pointer in cxgbi_check_route()
+    - scsi: libsas: delete sas port if expander discover failed
+    - Revert "crypto: crypto4xx - properly set IV after de- and encrypt"
+    - coredump: fix race condition between mmget_not_zero()/get_task_mm() and core
+      dumping
+    - Abort file_remove_privs() for non-reg. files
+    - Linux 4.4.183
+
+  * CVE-2019-12614
+    - powerpc/pseries/dlpar: Fix a missing check in dlpar_parse_cc_property()
+
+  * bnx2x driver causes 100% CPU load (LP: #1832082)
+    - bnx2x: Prevent ptp_task to be rescheduled indefinitely
+
+  * Xenial update: 4.4.182 upstream stable release (LP: #1836665)
+    - Linux 4.4.182
+
+  * Xenial kernel 4.4.0-155.182 fails to build perf with libnuma (LP: #1836585)
+    - Revert "UBUNTU: SAUCE: perf/bench: Drop definition of BIT in numa.c"
+
+  * CVE-2019-10126
+    - mwifiex: Fix heap overflow in mwifiex_uap_parse_tail_ies()
+
+  * CVE-2019-3846
+    - mwifiex: Fix possible buffer overflows at parsing bss descriptor
+
+ -- Sultan Alsawaf <sultan.alsawaf@canonical.com>  Mon, 29 Jul 2019 09:53:03 -0600
+
+linux (4.4.0-157.185) xenial; urgency=medium
+
+  * linux: 4.4.0-157.185 -proposed tracker (LP: #1837476)
+
+  * systemd 229-4ubuntu21.22 ADT test failure with linux 4.4.0-156.183 (storage)
+    (LP: #1837235)
+    - Revert "block/bio: Do not zero user pages"
+    - Revert "block: Clear kernel memory before copying to user"
+    - Revert "bio_copy_from_iter(): get rid of copying iov_iter"
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 23 Jul 2019 10:55:25 +0200
+
+linux (4.4.0-156.183) xenial; urgency=medium
+
+  * linux: 4.4.0-156.183 -proposed tracker (LP: #1836880)
+
+  * BCM43602 802.11ac Wireless regression - PCI ID 14e4:43ba (LP: #1836801)
+    - brcmfmac: add eth_type_trans back for PCIe full dongle
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 17 Jul 2019 13:06:26 +0200
+
+linux (4.4.0-155.182) xenial; urgency=medium
+
+  * linux: 4.4.0-155.182 -proposed tracker (LP: #1834918)
+
+  * Geneve tunnels don't work when ipv6 is disabled (LP: #1794232)
+    - geneve: correctly handle ipv6.disable module parameter
+
+  * Kernel modules generated incorrectly when system is localized to a non-
+    English language (LP: #1828084)
+    - scripts: override locale from environment when running recordmcount.pl
+
+  * Handle overflow in proc_get_long of sysctl (LP: #1833935)
+    - sysctl: handle overflow in proc_get_long
+
+  * Xenial update: 4.4.181 upstream stable release (LP: #1832661)
+    - x86/speculation/mds: Revert CPU buffer clear on double fault exit
+    - x86/speculation/mds: Improve CPU buffer clear documentation
+    - ARM: exynos: Fix a leaked reference by adding missing of_node_put
+    - crypto: vmx - fix copy-paste error in CTR mode
+    - crypto: crct10dif-generic - fix use via crypto_shash_digest()
+    - crypto: x86/crct10dif-pcl - fix use via crypto_shash_digest()
+    - ALSA: usb-audio: Fix a memory leak bug
+    - ALSA: hda/hdmi - Consider eld_valid when reporting jack event
+    - ALSA: hda/realtek - EAPD turn on later
+    - ASoC: max98090: Fix restore of DAPM Muxes
+    - ASoC: RT5677-SPI: Disable 16Bit SPI Transfers
+    - mm/mincore.c: make mincore() more conservative
+    - ocfs2: fix ocfs2 read inode data panic in ocfs2_iget
+    - mfd: da9063: Fix OTP control register names to match datasheets for
+      DA9063/63L
+    - tty/vt: fix write/write race in ioctl(KDSKBSENT) handler
+    - ext4: actually request zeroing of inode table after grow
+    - ext4: fix ext4_show_options for file systems w/o journal
+    - Btrfs: do not start a transaction at iterate_extent_inodes()
+    - bcache: fix a race between cache register and cacheset unregister
+    - bcache: never set KEY_PTRS of journal key to 0 in journal_reclaim()
+    - ipmi:ssif: compare block number correctly for multi-part return messages
+    - crypto: gcm - Fix error return code in crypto_gcm_create_common()
+    - crypto: gcm - fix incompatibility between "gcm" and "gcm_base"
+    - crypto: chacha20poly1305 - set cra_name correctly
+    - crypto: salsa20 - don't access already-freed walk.iv
+    - crypto: arm/aes-neonbs - don't access already-freed walk.iv
+    - writeback: synchronize sync(2) against cgroup writeback membership switches
+    - fs/writeback.c: use rcu_barrier() to wait for inflight wb switches going
+      into workqueue when umount
+    - ALSA: hda/realtek - Fix for Lenovo B50-70 inverted internal microphone bug
+    - KVM: x86: Skip EFER vs. guest CPUID checks for host-initiated writes
+    - net: avoid weird emergency message
+    - net/mlx4_core: Change the error print to info print
+    - ppp: deflate: Fix possible crash in deflate_init
+    - tipc: switch order of device registration to fix a crash
+    - tipc: fix modprobe tipc failed after switch order of device registration
+    - stm class: Fix channel free in stm output free path
+    - md: add mddev->pers to avoid potential NULL pointer dereference
+    - intel_th: msu: Fix single mode with IOMMU
+    - of: fix clang -Wunsequenced for be32_to_cpu()
+    - cifs: fix strcat buffer overflow and reduce raciness in
+      smb21_set_oplock_level()
+    - media: ov6650: Fix sensor possibly not detected on probe
+    - NFS4: Fix v4.0 client state corruption when mount
+    - clk: tegra: Fix PLLM programming on Tegra124+ when PMC overrides divider
+    - fuse: fix writepages on 32bit
+    - fuse: honor RLIMIT_FSIZE in fuse_file_fallocate
+    - iommu/tegra-smmu: Fix invalid ASID bits on Tegra30/114
+    - ceph: flush dirty inodes before proceeding with remount
+    - tracing: Fix partial reading of trace event's id file
+    - memory: tegra: Fix integer overflow on tick value calculation
+    - perf intel-pt: Fix instructions sampling rate
+    - perf intel-pt: Fix improved sample timestamp
+    - perf intel-pt: Fix sample timestamp wrt non-taken branches
+    - fbdev: sm712fb: fix brightness control on reboot, don't set SR30
+    - fbdev: sm712fb: fix VRAM detection, don't set SR70/71/74/75
+    - fbdev: sm712fb: fix white screen of death on reboot, don't set CR3B-CR3F
+    - fbdev: sm712fb: fix boot screen glitch when sm712fb replaces VGA
+    - fbdev: sm712fb: fix crashes during framebuffer writes by correctly mapping
+      VRAM
+    - fbdev: sm712fb: fix support for 1024x768-16 mode
+    - fbdev: sm712fb: use 1024x768 by default on non-MIPS, fix garbled display
+    - fbdev: sm712fb: fix crashes and garbled display during DPMS modesetting
+    - PCI: Mark Atheros AR9462 to avoid bus reset
+    - dm delay: fix a crash when invalid device is specified
+    - xfrm: policy: Fix out-of-bound array accesses in __xfrm_policy_unlink
+    - xfrm6_tunnel: Fix potential panic when unloading xfrm6_tunnel module
+    - vti4: ipip tunnel deregistration fixes.
+    - xfrm4: Fix uninitialized memory read in _decode_session4
+    - KVM: arm/arm64: Ensure vcpu target is unset on reset failure
+    - power: supply: sysfs: prevent endless uevent loop with
+      CONFIG_POWER_SUPPLY_DEBUG
+    - ufs: fix braino in ufs_get_inode_gid() for solaris UFS flavour
+    - perf bench numa: Add define for RUSAGE_THREAD if not present
+    - Revert "Don't jump to compute_result state from check_result state"
+    - md/raid: raid5 preserve the writeback action after the parity check
+    - btrfs: Honour FITRIM range constraints during free space trim
+    - fbdev: sm712fb: fix memory frequency by avoiding a switch/case fallthrough
+    - ext4: do not delete unlinked inode from orphan list on failed truncate
+    - KVM: x86: fix return value for reserved EFER
+    - bio: fix improper use of smp_mb__before_atomic()
+    - Revert "scsi: sd: Keep disk read-only when re-reading partition"
+    - crypto: vmx - CTR: always increment IV as quadword
+    - gfs2: Fix sign extension bug in gfs2_update_stats
+    - Btrfs: fix race between ranged fsync and writeback of adjacent ranges
+    - btrfs: sysfs: don't leak memory when failing add fsid
+    - fbdev: fix divide error in fb_var_to_videomode
+    - hugetlb: use same fault hash key for shared and private mappings
+    - fbdev: fix WARNING in __alloc_pages_nodemask bug
+    - media: cpia2: Fix use-after-free in cpia2_exit
+    - media: vivid: use vfree() instead of kfree() for dev->bitmap_cap
+    - ssb: Fix possible NULL pointer dereference in ssb_host_pcmcia_exit
+    - at76c50x-usb: Don't register led_trigger if usb_register_driver failed
+    - perf tools: No need to include bitops.h in util.h
+    - gfs2: Fix lru_count going negative
+    - cxgb4: Fix error path in cxgb4_init_module
+    - mmc: core: Verify SD bus width
+    - powerpc/boot: Fix missing check of lseek() return value
+    - ASoC: imx: fix fiq dependencies
+    - spi: pxa2xx: fix SCR (divisor) calculation
+    - brcm80211: potential NULL dereference in
+      brcmf_cfg80211_vndr_cmds_dcmd_handler()
+    - rtc: 88pm860x: prevent use-after-free on device remove
+    - w1: fix the resume command API
+    - dmaengine: pl330: _stop: clear interrupt status
+    - mac80211/cfg80211: update bss channel on channel switch
+    - ASoC: fsl_sai: Update is_slave_mode with correct value
+    - mwifiex: prevent an array overflow
+    - net: cw1200: fix a NULL pointer dereference
+    - bcache: return error immediately in bch_journal_replay()
+    - bcache: fix failure in journal relplay
+    - bcache: add failure check to run_cache_set() for journal replay
+    - bcache: avoid clang -Wunintialized warning
+    - x86/build: Move _etext to actual end of .text
+    - smpboot: Place the __percpu annotation correctly
+    - x86/mm: Remove in_nmi() warning from 64-bit implementation of
+      vmalloc_fault()
+    - mm/uaccess: Use 'unsigned long' to placate UBSAN warnings on older GCC
+      versions
+    - HID: logitech-hidpp: use RAP instead of FAP to get the protocol version
+    - pinctrl: pistachio: fix leaked of_node references
+    - dmaengine: at_xdmac: remove BUG_ON macro in tasklet
+    - media: coda: clear error return value before picture run
+    - media: ov6650: Move v4l2_clk_get() to ov6650_video_probe() helper
+    - media: au0828: stop video streaming only when last user stops
+    - media: ov2659: make S_FMT succeed even if requested format doesn't match
+    - audit: fix a memory leak bug
+    - media: au0828: Fix NULL pointer dereference in au0828_analog_stream_enable()
+    - media: pvrusb2: Prevent a buffer overflow
+    - powerpc/numa: improve control of topology updates
+    - sched/core: Check quota and period overflow at usec to nsec conversion
+    - sched/core: Handle overflow in cpu_shares_write_u64
+    - USB: core: Don't unbind interfaces following device reset failure
+    - x86/irq/64: Limit IST stack overflow check to #DB stack
+    - i40e: don't allow changes to HW VLAN stripping on active port VLANs
+    - RDMA/cxgb4: Fix null pointer dereference on alloc_skb failure
+    - hwmon: (vt1211) Use request_muxed_region for Super-IO accesses
+    - hwmon: (smsc47m1) Use request_muxed_region for Super-IO accesses
+    - hwmon: (smsc47b397) Use request_muxed_region for Super-IO accesses
+    - hwmon: (pc87427) Use request_muxed_region for Super-IO accesses
+    - hwmon: (f71805f) Use request_muxed_region for Super-IO accesses
+    - scsi: libsas: Do discovery on empty PHY to update PHY info
+    - mmc_spi: add a status check for spi_sync_locked
+    - mmc: sdhci-of-esdhc: add erratum eSDHC5 support
+    - mmc: sdhci-of-esdhc: add erratum eSDHC-A001 and A-008358 support
+    - PM / core: Propagate dev->power.wakeup_path when no callbacks
+    - extcon: arizona: Disable mic detect if running when driver is removed
+    - s390: cio: fix cio_irb declaration
+    - cpufreq: ppc_cbe: fix possible object reference leak
+    - cpufreq/pasemi: fix possible object reference leak
+    - cpufreq: pmac32: fix possible object reference leak
+    - x86/build: Keep local relocations with ld.lld
+    - iio: ad_sigma_delta: Properly handle SPI bus locking vs CS assertion
+    - iio: hmc5843: fix potential NULL pointer dereferences
+    - iio: common: ssp_sensors: Initialize calculated_time in
+      ssp_common_process_data
+    - rtlwifi: fix a potential NULL pointer dereference
+    - brcmfmac: fix missing checks for kmemdup
+    - b43: shut up clang -Wuninitialized variable warning
+    - brcmfmac: convert dev_init_lock mutex to completion
+    - brcmfmac: fix race during disconnect when USB completion is in progress
+    - scsi: ufs: Fix regulator load and icc-level configuration
+    - scsi: ufs: Avoid configuring regulator with undefined voltage range
+    - arm64: cpu_ops: fix a leaked reference by adding missing of_node_put
+    - x86/ia32: Fix ia32_restore_sigcontext() AC leak
+    - chardev: add additional check for minor range overlap
+    - HID: core: move Usage Page concatenation to Main item
+    - ASoC: eukrea-tlv320: fix a leaked reference by adding missing of_node_put
+    - ASoC: fsl_utils: fix a leaked reference by adding missing of_node_put
+    - cxgb3/l2t: Fix undefined behaviour
+    - spi: tegra114: reset controller on probe
+    - media: wl128x: prevent two potential buffer overflows
+    - virtio_console: initialize vtermno value for ports
+    - tty: ipwireless: fix missing checks for ioremap
+    - rcutorture: Fix cleanup path for invalid torture_type strings
+    - usb: core: Add PM runtime calls to usb_hcd_platform_shutdown
+    - scsi: qla4xxx: avoid freeing unallocated dma memory
+    - media: m88ds3103: serialize reset messages in m88ds3103_set_frontend
+    - media: go7007: avoid clang frame overflow warning with KASAN
+    - media: saa7146: avoid high stack usage with clang
+    - scsi: lpfc: Fix SLI3 commands being issued on SLI4 devices
+    - spi : spi-topcliff-pch: Fix to handle empty DMA buffers
+    - spi: rspi: Fix sequencer reset during initialization
+    - spi: Fix zero length xfer bug
+    - ASoC: davinci-mcasp: Fix clang warning without CONFIG_PM
+    - ipv6: Consider sk_bound_dev_if when binding a raw socket to an address
+    - llc: fix skb leak in llc_build_and_send_ui_pkt()
+    - net-gro: fix use-after-free read in napi_gro_frags()
+    - net: stmmac: fix reset gpio free missing
+    - usbnet: fix kernel crash after disconnect
+    - tipc: Avoid copying bytes beyond the supplied data
+    - bnxt_en: Fix aggregation buffer leak under OOM condition.
+    - net: mvpp2: fix bad MVPP2_TXQ_SCHED_TOKEN_CNTR_REG queue value
+    - crypto: vmx - ghash: do nosimd fallback manually
+    - xen/pciback: Don't disable PCI_COMMAND on PCI device reset.
+    - Revert "tipc: fix modprobe tipc failed after switch order of device
+      registration"
+    - tipc: fix modprobe tipc failed after switch order of device registration -v2
+    - sparc64: Fix regression in non-hypervisor TLB flush xcall
+    - include/linux/bitops.h: sanitize rotate primitives
+    - xhci: Convert xhci_handshake() to use readl_poll_timeout_atomic()
+    - usb: xhci: avoid null pointer deref when bos field is NULL
+    - USB: Fix slab-out-of-bounds write in usb_get_bos_descriptor
+    - USB: sisusbvga: fix oops in error path of sisusb_probe
+    - USB: Add LPM quirk for Surface Dock GigE adapter
+    - USB: rio500: refuse more than one device at a time
+    - USB: rio500: fix memory leak in close after disconnect
+    - media: usb: siano: Fix general protection fault in smsusb
+    - media: usb: siano: Fix false-positive "uninitialized variable" warning
+    - media: smsusb: better handle optional alignment
+    - scsi: zfcp: fix missing zfcp_port reference put on -EBUSY from port_remove
+    - scsi: zfcp: fix to prevent port_remove with pure auto scan LUNs (only sdevs)
+    - Btrfs: fix race updating log root item during fsync
+    - ALSA: hda/realtek - Set default power save node to 0
+    - drm/nouveau/i2c: Disable i2c bus access after ->fini()
+    - tty: serial: msm_serial: Fix XON/XOFF
+    - tty: max310x: Fix external crystal register setup
+    - memcg: make it work on sparse non-0-node systems
+    - kernel/signal.c: trace_signal_deliver when signal_group_exit
+    - CIFS: cifs_read_allocate_pages: don't iterate through whole page array on
+      ENOMEM
+    - binder: Replace "%p" with "%pK" for stable
+    - binder: replace "%p" with "%pK"
+    - brcmfmac: Add length checks on firmware events
+    - brcmfmac: screening firmware event packet
+    - brcmfmac: revise handling events in receive path
+    - brcmfmac: fix incorrect event channel deduction
+    - brcmfmac: add length checks in scheduled scan result handler
+    - brcmfmac: add subtype check for event handling in data path
+    - userfaultfd: don't pin the user memory in userfaultfd_file_create()
+    - Revert "x86/build: Move _etext to actual end of .text"
+    - net: cdc_ncm: GetNtbFormat endian fix
+    - usb: gadget: fix request length error for isoc transfer
+    - media: uvcvideo: Fix uvc_alloc_entity() allocation alignment
+    - ethtool: fix potential userspace buffer overflow
+    - neighbor: Call __ipv4_neigh_lookup_noref in neigh_xmit
+    - net/mlx4_en: ethtool, Remove unsupported SFP EEPROM high pages query
+    - net: rds: fix memory leak in rds_ib_flush_mr_pool
+    - pktgen: do not sleep with the thread lock held.
+    - rcu: locking and unlocking need to always be at least barriers
+    - parisc: Use implicit space register selection for loading the coherence
+      index of I/O pdirs
+    - fuse: fallocate: fix return with locked inode
+    - MIPS: pistachio: Build uImage.gz by default
+    - genwqe: Prevent an integer overflow in the ioctl
+    - drm/gma500/cdv: Check vbt config bits when detecting lvds panels
+    - fs: stream_open - opener for stream-like files so that read and write can
+      run simultaneously without deadlock
+    - fuse: Add FOPEN_STREAM to use stream_open()
+    - ipv4: Define __ipv4_neigh_lookup_noref when CONFIG_INET is disabled
+    - ethtool: check the return value of get_regs_len
+    - Linux 4.4.181
+
+  * CVE-2019-2054
+    - arm/ptrace: run seccomp after ptrace
+
+  * CVE-2018-12126 // CVE-2018-12127 // CVE-2018-12130
+    - x86/speculation: Remove redundant arch_smt_update() invocation
+
+  * Revert x86/vdso linker changes from #1830890 as this causes glibc
+    2.29-0ubuntu3 FTBFS on eoan (LP: #1834315)
+    - Revert "x86/vdso: Pass --eh-frame-hdr to the linker"
+    - Revert "x86: vdso: Use $LD instead of $CC to link"
+
+  * CONFIG_LOG_BUF_SHIFT set to 14 is too low on arm64 (LP: #1824864)
+    - [Config] CONFIG_LOG_BUF_SHIFT=18 on all 64bit arches
+
+  * CVE-2019-11833
+    - ext4: zero out the unused memory region in the extent tree block
+
+  * idle-page oopses when accessing page frames that are out of range
+    (LP: #1833410)
+    - mm/page_idle.c: fix oops because end_pfn is larger than max_pfn
+
+  * Performance degradation when copying from LVM snapshot backed by NVMe disk
+    (LP: #1833319)
+    - NVMe: Allow request merges
+
+  * Bluetooth regressions with Xenial kernel 4.4.0-152.179 (LP: #1833698)
+    - Revert "Bluetooth: Align minimum encryption key size for LE and BR/EDR
+      connections"
+
+  * 4.4.0-145-generic Kernel Panic  ip6_expire_frag_queue (LP: #1824687)
+    - SAUCE: ipv6: frags: fix skb extraction in ip6_expire_frag_queue()
+
+  * [Xenial] Customer can not SSH to Linux VM due to "VSC State Unhealthy"
+    (LP: #1826416)
+    - vmbus: fix missing signaling in hv_signal_on_read()
+
+  * Xenial update: 4.4.180 upstream stable release (LP: #1830176)
+    - kbuild: simplify ld-option implementation
+    - KVM: fail KVM_SET_VCPU_EVENTS with invalid exception number
+    - cifs: do not attempt cifs operation on smb2+ rename error
+    - MIPS: scall64-o32: Fix indirect syscall number load
+    - trace: Fix preempt_enable_no_resched() abuse
+    - sched/numa: Fix a possible divide-by-zero
+    - ceph: ensure d_name stability in ceph_dentry_hash()
+    - ceph: fix ci->i_head_snapc leak
+    - nfsd: Don't release the callback slot unless it was actually held
+    - sunrpc: don't mark uninitialised items as VALID.
+    - USB: Add new USB LPM helpers
+    - USB: Consolidate LPM checks to avoid enabling LPM twice
+    - powerpc/xmon: Add RFI flush related fields to paca dump
+    - powerpc/64s: Improve RFI L1-D cache flush fallback
+    - powerpc/64s: Fix section mismatch warnings from setup_rfi_flush()
+    - Revert "UBUNTU: SAUCE: powerpc/64s: Add support for a store forwarding
+      barrier at kernel entry/exit"
+    - powerpc/64s: Add support for a store forwarding barrier at kernel entry/exit
+    - powerpc/64s: Add barrier_nospec
+    - powerpc/64s: Add support for ori barrier_nospec patching
+    - powerpc/64s: Patch barrier_nospec in modules
+    - powerpc/64s: Enable barrier_nospec based on firmware settings
+    - powerpc/64: Use barrier_nospec in syscall entry
+    - powerpc: Use barrier_nospec in copy_from_user()
+    - powerpc/64s: Enhance the information in cpu_show_spectre_v1()
+    - powerpc64s: Show ori31 availability in spectre_v1 sysfs file not v2
+    - powerpc/64: Disable the speculation barrier from the command line
+    - powerpc/64: Make stf barrier PPC_BOOK3S_64 specific.
+    - powerpc/64: Add CONFIG_PPC_BARRIER_NOSPEC
+    - powerpc/64: Call setup_barrier_nospec() from setup_arch()
+    - powerpc/64: Make meltdown reporting Book3S 64 specific
+    - powerpc/fsl: Add barrier_nospec implementation for NXP PowerPC Book3E
+    - powerpc/asm: Add a patch_site macro & helpers for patching instructions
+    - powerpc/64s: Add new security feature flags for count cache flush
+    - powerpc/64s: Add support for software count cache flush
+    - powerpc/pseries: Query hypervisor for count cache flush settings
+    - powerpc/powernv: Query firmware for count cache flush settings
+    - powerpc: Avoid code patching freed init sections
+    - powerpc/fsl: Add infrastructure to fixup branch predictor flush
+    - powerpc/fsl: Add macro to flush the branch predictor
+    - powerpc/fsl: Fix spectre_v2 mitigations reporting
+    - powerpc/fsl: Add nospectre_v2 command line argument
+    - powerpc/fsl: Flush the branch predictor at each kernel entry (64bit)
+    - powerpc/fsl: Update Spectre v2 reporting
+    - powerpc/security: Fix spectre_v2 reporting
+    - powerpc/fsl: Fix the flush of branch predictor.
+    - tipc: handle the err returned from cmd header function
+    - slip: make slhc_free() silently accept an error pointer
+    - intel_th: gth: Fix an off-by-one in output unassigning
+    - fs/proc/proc_sysctl.c: Fix a NULL pointer dereference
+    - NFS: Forbid setting AF_INET6 to "struct sockaddr_in"->sin_family.
+    - netfilter: ebtables: CONFIG_COMPAT: drop a bogus WARN_ON
+    - tipc: check bearer name with right length in tipc_nl_compat_bearer_enable
+    - tipc: check link name with right length in tipc_nl_compat_link_set
+    - bpf: reject wrong sized filters earlier
+    - Revert "block/loop: Use global lock for ioctl() operation."
+    - ipv4: add sanity checks in ipv4_link_failure()
+    - team: fix possible recursive locking when add slaves
+    - net: stmmac: move stmmac_check_ether_addr() to driver probe
+    - ipv4: set the tcp_min_rtt_wlen range from 0 to one day
+    - powerpc/fsl: Enable runtime patching if nospectre_v2 boot arg is used
+    - powerpc/fsl: Flush branch predictor when entering KVM
+    - powerpc/fsl: Emulate SPRN_BUCSR register
+    - powerpc/fsl: Flush the branch predictor at each kernel entry (32 bit)
+    - powerpc/fsl: Sanitize the syscall table for NXP PowerPC 32 bit platforms
+    - powerpc/fsl: Fixed warning: orphan section `__btb_flush_fixup'
+    - powerpc/fsl: Add FSL_PPC_BOOK3E as supported arch for nospectre_v2 boot arg
+    - Documentation: Add nospectre_v1 parameter
+    - usbnet: ipheth: prevent TX queue timeouts when device not ready
+    - usbnet: ipheth: fix potential null pointer dereference in ipheth_carrier_set
+    - qlcnic: Avoid potential NULL pointer dereference
+    - netfilter: bridge: set skb transport_header before entering
+      NF_INET_PRE_ROUTING
+    - sc16is7xx: missing unregister/delete driver on error in sc16is7xx_init()
+    - usb: gadget: net2280: Fix overrun of OUT messages
+    - usb: gadget: net2280: Fix net2280_dequeue()
+    - usb: gadget: net2272: Fix net2272_dequeue()
+    - ARM: dts: pfla02: increase phy reset duration
+    - net: ks8851: Dequeue RX packets explicitly
+    - net: ks8851: Reassert reset pin if chip ID check fails
+    - net: ks8851: Delay requesting IRQ until opened
+    - net: ks8851: Set initial carrier state to down
+    - net: xilinx: fix possible object reference leak
+    - net: ibm: fix possible object reference leak
+    - net: ethernet: ti: fix possible object reference leak
+    - scsi: qla4xxx: fix a potential NULL pointer dereference
+    - usb: u132-hcd: fix resource leak
+    - ceph: fix use-after-free on symlink traversal
+    - scsi: zfcp: reduce flood of fcrscn1 trace records on multi-element RSCN
+    - libata: fix using DMA buffers on stack
+    - kconfig/[mn]conf: handle backspace (^H) key
+    - ALSA: line6: use dynamic buffers
+    - ipv4: ip_do_fragment: Preserve skb_iif during fragmentation
+    - ipv6/flowlabel: wait rcu grace period before put_pid()
+    - ipv6: invert flowlabel sharing check in process and user mode
+    - bnxt_en: Improve multicast address setup logic.
+    - packet: validate msg_namelen in send directly
+    - USB: yurex: Fix protection fault after device removal
+    - USB: w1 ds2490: Fix bug caused by improper use of altsetting array
+    - USB: core: Fix unterminated string returned by usb_string()
+    - USB: core: Fix bug caused by duplicate interface PM usage counter
+    - HID: debug: fix race condition with between rdesc_show() and device removal
+    - rtc: sh: Fix invalid alarm warning for non-enabled alarm
+    - bonding: show full hw address in sysfs for slave entries
+    - jffs2: fix use-after-free on symlink traversal
+    - debugfs: fix use-after-free on symlink traversal
+    - rtc: da9063: set uie_unsupported when relevant
+    - vfio/pci: use correct format characters
+    - scsi: storvsc: Fix calculation of sub-channel count
+    - net: hns: Use NAPI_POLL_WEIGHT for hns driver
+    - net: hns: Fix WARNING when remove HNS driver with SMMU enabled
+    - hugetlbfs: fix memory leak for resv_map
+    - xsysace: Fix error handling in ace_setup
+    - ARM: orion: don't use using 64-bit DMA masks
+    - ARM: iop: don't use using 64-bit DMA masks
+    - usb: usbip: fix isoc packet num validation in get_pipe
+    - staging: iio: adt7316: allow adt751x to use internal vref for all dacs
+    - staging: iio: adt7316: fix the dac read calculation
+    - staging: iio: adt7316: fix the dac write calculation
+    - Input: snvs_pwrkey - initialize necessary driver data before enabling IRQ
+    - selinux: never allow relabeling on context mounts
+    - x86/mce: Improve error message when kernel cannot recover, p2
+    - media: v4l2: i2c: ov7670: Fix PLL bypass register values
+    - scsi: libsas: fix a race condition when smp task timeout
+    - ASoC:soc-pcm:fix a codec fixup issue in TDM case
+    - ASoC: cs4270: Set auto-increment bit for register writes
+    - ASoC: tlv320aic32x4: Fix Common Pins
+    - perf/x86/intel: Fix handling of wakeup_events for multi-entry PEBS
+    - scsi: csiostor: fix missing data copy in csio_scsi_err_handler()
+    - iommu/amd: Set exclusion range correctly
+    - genirq: Prevent use-after-free and work list corruption
+    - usb: dwc3: Fix default lpm_nyet_threshold value
+    - scsi: qla2xxx: Fix incorrect region-size setting in optrom SYSFS routines
+    - Bluetooth: hidp: fix buffer overflow
+    - Bluetooth: Align minimum encryption key size for LE and BR/EDR connections
+    - UAS: fix alignment of scatter/gather segments
+    - ipv6: fix a potential deadlock in do_ipv6_setsockopt()
+    - ASoC: Intel: avoid Oops if DMA setup fails
+    - timer/debug: Change /proc/timer_stats from 0644 to 0600
+    - netfilter: compat: initialize all fields in xt_init
+    - platform/x86: sony-laptop: Fix unintentional fall-through
+    - iio: adc: xilinx: fix potential use-after-free on remove
+    - HID: input: add mapping for Expose/Overview key
+    - HID: input: add mapping for keyboard Brightness Up/Down/Toggle keys
+    - libnvdimm/btt: Fix a kmemdup failure check
+    - s390/dasd: Fix capacity calculation for large volumes
+    - s390/3270: fix lockdep false positive on view->lock
+    - KVM: x86: avoid misreporting level-triggered irqs as edge-triggered in
+      tracing
+    - tools lib traceevent: Fix missing equality check for strcmp
+    - init: initialize jump labels before command line option parsing
+    - ipvs: do not schedule icmp errors from tunnels
+    - s390: ctcm: fix ctcm_new_device error return code
+    - gpu: ipu-v3: dp: fix CSC handling
+    - cw1200: fix missing unlock on error in cw1200_hw_scan()
+    - Don't jump to compute_result state from check_result state
+    - x86/microcode/intel: Add a helper which gives the microcode revision
+    - x86: stop exporting msr-index.h to userland
+    - x86/microcode/intel: Check microcode revision before updating sibling
+      threads
+    - x86/MCE: Save microcode revision in machine check records
+    - x86/bugs: Add AMD's variant of SSB_NO
+    - x86/bugs: Add AMD's SPEC_CTRL MSR usage
+    - x86/bugs: Switch the selection of mitigation from CPU vendor to CPU features
+    - x86/bugs: Fix the AMD SSBD usage of the SPEC_CTRL MSR
+    - x86/microcode: Make sure boot_cpu_data.microcode is up-to-date
+    - x86/microcode: Update the new microcode revision unconditionally
+    - x86/mm: Use WRITE_ONCE() when setting PTEs
+    - x86/speculation: Apply IBPB more strictly to avoid cross-process data leak
+    - x86/speculation: Enable cross-hyperthread spectre v2 STIBP mitigation
+    - x86/speculation: Propagate information about RSB filling mitigation to sysfs
+    - x86/speculation: Update the TIF_SSBD comment
+    - x86/speculation: Clean up spectre_v2_parse_cmdline()
+    - x86/speculation: Move STIPB/IBPB string conditionals out of
+      cpu_show_common()
+    - x86/speculation: Disable STIBP when enhanced IBRS is in use
+    - x86/speculation: Rename SSBD update functions
+    - x86/speculation: Reorganize speculation control MSRs update
+    - x86/Kconfig: Select SCHED_SMT if SMP enabled
+    - x86/speculation: Mark string arrays const correctly
+    - x86/speculataion: Mark command line parser data __initdata
+    - x86/speculation: Add command line control for indirect branch speculation
+    - x86/speculation: Prepare for per task indirect branch speculation control
+    - x86/process: Consolidate and simplify switch_to_xtra() code
+    - x86/speculation: Avoid __switch_to_xtra() calls
+    - x86/speculation: Prepare for conditional IBPB in switch_mm()
+    - x86/speculation: Split out TIF update
+    - x86/speculation: Prepare arch_smt_update() for PRCTL mode
+    - x86/speculation: Prevent stale SPEC_CTRL msr content
+    - x86/speculation: Add prctl() control for indirect branch speculation
+    - x86/speculation: Enable prctl mode for spectre_v2_user
+    - x86/speculation: Add seccomp Spectre v2 user space protection mode
+    - x86/speculation: Provide IBPB always command line options
+    - x86/cpu/bugs: Use __initconst for 'const' init data
+    - USB: serial: use variable for status
+    - USB: serial: fix unthrottle races
+    - bridge: Fix error path for kobject_init_and_add()
+    - net: ucc_geth - fix Oops when changing number of buffers in the ring
+    - packet: Fix error path in packet_init
+    - vlan: disable SIOCSHWTSTAMP in container
+    - vrf: sit mtu should not be updated when vrf netdev is the link
+    - ipv4: Fix raw socket lookup for local traffic
+    - bonding: fix arp_validate toggling in active-backup mode
+    - drivers/virt/fsl_hypervisor.c: dereferencing error pointers in ioctl
+    - drivers/virt/fsl_hypervisor.c: prevent integer overflow in ioctl
+    - powerpc/booke64: set RI in default MSR
+    - powerpc/lib: fix book3s/32 boot failure due to code patching
+    - Linux 4.4.180
+    - SAUCE: Clarify IBRS/IBPB runtime state change messages
+    - SAUCE: x86/speculation: Move STIBP hunks
+    - SAUCE: powerpc/speculation: Support 'mitigations=' cmdline option
+    - SAUCE: x86/speculation: Update 'mitigations=' documentation
+    - SAUCE: Show 'pti' instead of 'kaiser' in /proc/cpuinfo
+    - SAUCE: perf/bench: Drop definition of BIT in numa.c
+    - SAUCE: x86/speculation: Fix SSB command line documentation
+
+  * CVE-2018-12126 // CVE-2018-12127 // CVE-2018-12130 // CVE-2019-11091
+    - SAUCE: Synchronize MDS mitigations with upstream
+    - Documentation: Correct the possible MDS sysfs values
+    - x86/speculation/mds: Fix documentation typo
+
+  * CVE-2019-11091
+    - x86/mds: Add MDSUM variant to the MDS documentation
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 02 Jul 2019 13:53:41 +0200
+
+linux (4.4.0-154.181) xenial; urgency=medium
+
+  * linux: 4.4.0-154.181 -proposed tracker (LP: #1834030)
+
+  * CVE-2019-11478
+    - tcp: refine memory limit test in tcp_fragment()
+
+  * CVE-2019-11479
+    - SAUCE: tcp: add tcp_min_snd_mss sysctl
+    - SAUCE: tcp: enforce tcp_min_snd_mss in tcp_mtu_probing()
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Tue, 25 Jun 2019 00:36:38 -0400
+
+linux (4.4.0-151.178) xenial; urgency=medium
+
+  * Remote denial of service (system crash) caused by integer overflow in TCP
+    SACK handling (LP: #1831637)
+    - SAUCE: tcp: limit payload size of sacked skbs
+    - SAUCE: tcp: fix fack_count accounting on tcp_shift_skb_data()
+
+  * Remote denial of service (resource exhaustion) caused by TCP SACK scoreboard
+    manipulation (LP: #1831638)
+    - SAUCE: tcp: tcp_fragment() should apply sane memory limits
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 11 Jun 2019 09:36:19 +0200
+
+linux (4.4.0-150.176) xenial; urgency=medium
+
+  * linux: 4.4.0-150.176 -proposed tracker (LP: #1830941)
+
+  * glibc 2.23-0ubuntu11 ADT test failure with linux 4.4.0-149.175
+    (LP: #1830890)
+    - x86/vdso: Pass --eh-frame-hdr to the linker
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 29 May 2019 14:23:25 -0400
+
+linux (4.4.0-149.175) xenial; urgency=medium
+
+  * linux: 4.4.0-149.175 -proposed tracker (LP: #1829209)
+
+  * disable a.out support (LP: #1818552)
+    - [Config] Disable a.out support
+
+  * autopkgtests run too often, too much and don't skip enough (LP: #1823056)
+    - [Debian] Set +x on rebuild testcase.
+    - [Debian] Skip rebuild test, for regression-suite deps.
+    - [Debian] Make ubuntu-regression-suite skippable on unbootable kernels.
+    - [Debian] make rebuild use skippable error codes when skipping.
+    - [Debian] Only run regression-suite, if requested to.
+
+  * Xenial update: 4.4.179 upstream stable release (LP: #1828420)
+    - arm64: debug: Don't propagate UNKNOWN FAR into si_code for debug signals
+    - arm64: debug: Ensure debug handlers check triggering exception level
+    - ext4: cleanup bh release code in ext4_ind_remove_space()
+    - lib/int_sqrt: optimize initial value compute
+    - tty/serial: atmel: Add is_half_duplex helper
+    - mm: mempolicy: make mbind() return -EIO when MPOL_MF_STRICT is specified
+    - i2c: core-smbus: prevent stack corruption on read I2C_BLOCK_DATA
+    - Bluetooth: Fix decrementing reference count twice in releasing socket
+    - tty/serial: atmel: RS485 HD w/DMA: enable RX after TX is stopped
+    - CIFS: fix POSIX lock leak and invalid ptr deref
+    - h8300: use cc-cross-prefix instead of hardcoding h8300-unknown-linux-
+    - tracing: kdb: Fix ftdump to not sleep
+    - gpio: gpio-omap: fix level interrupt idling
+    - sysctl: handle overflow for file-max
+    - enic: fix build warning without CONFIG_CPUMASK_OFFSTACK
+    - mm/cma.c: cma_declare_contiguous: correct err handling
+    - mm/page_ext.c: fix an imbalance with kmemleak
+    - mm/vmalloc.c: fix kernel BUG at mm/vmalloc.c:512!
+    - mm/slab.c: kmemleak no scan alien caches
+    - ocfs2: fix a panic problem caused by o2cb_ctl
+    - f2fs: do not use mutex lock in atomic context
+    - fs/file.c: initialize init_files.resize_wait
+    - cifs: use correct format characters
+    - dm thin: add sanity checks to thin-pool and external snapshot creation
+    - cifs: Fix NULL pointer dereference of devname
+    - fs: fix guard_bio_eod to check for real EOD errors
+    - tools lib traceevent: Fix buffer overflow in arg_eval
+    - usb: chipidea: Grab the (legacy) USB PHY by phandle first
+    - scsi: core: replace GFP_ATOMIC with GFP_KERNEL in scsi_scan.c
+    - coresight: etm4x: Add support to enable ETMv4.2
+    - ARM: 8840/1: use a raw_spinlock_t in unwind
+    - mmc: omap: fix the maximum timeout setting
+    - e1000e: Fix -Wformat-truncation warnings
+    - IB/mlx4: Increase the timeout for CM cache
+    - scsi: megaraid_sas: return error when create DMA pool failed
+    - perf test: Fix failure of 'evsel-tp-sched' test on s390
+    - SoC: imx-sgtl5000: add missing put_device()
+    - media: sh_veu: Correct return type for mem2mem buffer helpers
+    - media: s5p-jpeg: Correct return type for mem2mem buffer helpers
+    - media: s5p-g2d: Correct return type for mem2mem buffer helpers
+    - media: mx2_emmaprp: Correct return type for mem2mem buffer helpers
+    - leds: lp55xx: fix null deref on firmware load failure
+    - kprobes: Prohibit probing on bsearch()
+    - ARM: 8833/1: Ensure that NEON code always compiles with Clang
+    - ALSA: PCM: check if ops are defined before suspending PCM
+    - bcache: fix input overflow to cache set sysfs file io_error_halflife
+    - bcache: fix input overflow to sequential_cutoff
+    - bcache: improve sysfs_strtoul_clamp()
+    - fbdev: fbmem: fix memory access if logo is bigger than the screen
+    - cdrom: Fix race condition in cdrom_sysctl_register
+    - ASoC: fsl-asoc-card: fix object reference leaks in fsl_asoc_card_probe
+    - soc: qcom: gsbi: Fix error handling in gsbi_probe()
+    - mt7601u: bump supported EEPROM version
+    - ARM: avoid Cortex-A9 livelock on tight dmb loops
+    - tty: increase the default flip buffer limit to 2*640K
+    - media: mt9m111: set initial frame size other than 0x0
+    - hwrng: virtio - Avoid repeated init of completion
+    - soc/tegra: fuse: Fix illegal free of IO base address
+    - hpet: Fix missing '=' character in the __setup() code of hpet_mmap_enable
+    - dmaengine: imx-dma: fix warning comparison of distinct pointer types
+    - netfilter: physdev: relax br_netfilter dependency
+    - media: s5p-jpeg: Check for fmt_ver_flag when doing fmt enumeration
+    - regulator: act8865: Fix act8600_sudcdc_voltage_ranges setting
+    - wlcore: Fix memory leak in case wl12xx_fetch_firmware failure
+    - x86/build: Mark per-CPU symbols as absolute explicitly for LLD
+    - dmaengine: tegra: avoid overflow of byte tracking
+    - drm/dp/mst: Configure no_stop_bit correctly for remote i2c xfers
+    - binfmt_elf: switch to new creds when switching to new mm
+    - kbuild: clang: choose GCC_TOOLCHAIN_DIR not on LD
+    - x86/build: Specify elf_i386 linker emulation explicitly for i386 objects
+    - x86: vdso: Use $LD instead of $CC to link
+    - x86/vdso: Drop implicit common-page-size linker flag
+    - lib/string.c: implement a basic bcmp
+    - tty: mark Siemens R3964 line discipline as BROKEN
+    - [Config]: remove CONFIG_R3964
+    - [Config]: add CONFIG_LDISC_AUTOLOAD=y
+    - tty: ldisc: add sysctl to prevent autoloading of ldiscs
+    - ipv6: Fix dangling pointer when ipv6 fragment
+    - ipv6: sit: reset ip header pointer in ipip6_rcv
+    - net: rds: force to destroy connection if t_sock is NULL in
+      rds_tcp_kill_sock().
+    - qmi_wwan: add Olicard 600
+    - sctp: initialize _pad of sockaddr_in before copying to user memory
+    - tcp: Ensure DCTCP reacts to losses
+    - netns: provide pure entropy for net_hash_mix()
+    - net: ethtool: not call vzalloc for zero sized memory request
+    - ip6_tunnel: Match to ARPHRD_TUNNEL6 for dev type
+    - ALSA: seq: Fix OOB-reads from strlcpy
+    - include/linux/bitrev.h: fix constant bitrev
+    - ASoC: fsl_esai: fix channel swap issue when stream starts
+    - block: do not leak memory in bio_copy_user_iov()
+    - genirq: Respect IRQCHIP_SKIP_SET_WAKE in irq_chip_set_wake_parent()
+    - ARM: dts: at91: Fix typo in ISC_D0 on PC9
+    - arm64: futex: Fix FUTEX_WAKE_OP atomic ops with non-zero result value
+    - xen: Prevent buffer overflow in privcmd ioctl
+    - sched/fair: Do not re-read ->h_load_next during hierarchical load
+      calculation
+    - xtensa: fix return_address
+    - PCI: Add function 1 DMA alias quirk for Marvell 9170 SATA controller
+    - perf/core: Restore mmap record type correctly
+    - ext4: add missing brelse() in add_new_gdb_meta_bg()
+    - ext4: report real fs size after failed resize
+    - ALSA: echoaudio: add a check for ioremap_nocache
+    - ALSA: sb8: add a check for request_region
+    - IB/mlx4: Fix race condition between catas error reset and aliasguid flows
+    - mmc: davinci: remove extraneous __init annotation
+    - ALSA: opl3: fix mismatch between snd_opl3_drum_switch definition and
+      declaration
+    - thermal/int340x_thermal: Add additional UUIDs
+    - thermal/int340x_thermal: fix mode setting
+    - tools/power turbostat: return the exit status of a command
+    - perf top: Fix error handling in cmd_top()
+    - perf evsel: Free evsel->counts in perf_evsel__exit()
+    - perf tests: Fix a memory leak of cpu_map object in the
+      openat_syscall_event_on_all_cpus test
+    - perf tests: Fix a memory leak in test__perf_evsel__tp_sched_test()
+    - x86/hpet: Prevent potential NULL pointer dereference
+    - x86/cpu/cyrix: Use correct macros for Cyrix calls on Geode processors
+    - iommu/vt-d: Check capability before disabling protected memory
+    - x86/hw_breakpoints: Make default case in hw_breakpoint_arch_parse() return
+      an error
+    - fix incorrect error code mapping for OBJECTID_NOT_FOUND
+    - ext4: prohibit fstrim in norecovery mode
+    - rsi: improve kernel thread handling to fix kernel panic
+    - 9p: do not trust pdu content for stat item size
+    - 9p locks: add mount option for lock retry interval
+    - f2fs: fix to do sanity check with current segment number
+    - serial: uartps: console_setup() can't be placed to init section
+    - ARM: samsung: Limit SAMSUNG_PM_CHECK config option to non-Exynos platforms
+    - ACPI / SBS: Fix GPE storm on recent MacBookPro's
+    - cifs: fallback to older infolevels on findfirst queryinfo retry
+    - crypto: sha256/arm - fix crash bug in Thumb2 build
+    - crypto: sha512/arm - fix crash bug in Thumb2 build
+    - iommu/dmar: Fix buffer overflow during PCI bus notification
+    - ARM: 8839/1: kprobe: make patch_lock a raw_spinlock_t
+    - appletalk: Fix use-after-free in atalk_proc_exit
+    - lib/div64.c: off by one in shift
+    - include/linux/swap.h: use offsetof() instead of custom __swapoffset macro
+    - tpm/tpm_crb: Avoid unaligned reads in crb_recv()
+    - ovl: fix uid/gid when creating over whiteout
+    - appletalk: Fix compile regression
+    - bonding: fix event handling for stacked bonds
+    - net: atm: Fix potential Spectre v1 vulnerabilities
+    - net: bridge: multicast: use rcu to access port list from
+      br_multicast_start_querier
+    - net: fou: do not use guehdr after iptunnel_pull_offloads in gue_udp_recv
+    - tcp: tcp_grow_window() needs to respect tcp_space()
+    - ipv4: recompile ip options in ipv4_link_failure
+    - ipv4: ensure rcu_read_lock() in ipv4_link_failure()
+    - crypto: crypto4xx - properly set IV after de- and encrypt
+    - modpost: file2alias: go back to simple devtable lookup
+    - modpost: file2alias: check prototype of handler
+    - tpm/tpm_i2c_atmel: Return -E2BIG when the transfer is incomplete
+    - KVM: x86: Don't clear EFER during SMM transitions for 32-bit vCPU
+    - iio/gyro/bmg160: Use millidegrees for temperature scale
+    - iio: ad_sigma_delta: select channel when reading register
+    - iio: adc: at91: disable adc channel interrupt in timeout case
+    - io: accel: kxcjk1013: restore the range after resume.
+    - staging: comedi: vmk80xx: Fix use of uninitialized semaphore
+    - staging: comedi: vmk80xx: Fix possible double-free of ->usb_rx_buf
+    - staging: comedi: ni_usb6501: Fix use of uninitialized mutex
+    - staging: comedi: ni_usb6501: Fix possible double-free of ->usb_rx_buf
+    - ALSA: core: Fix card races between register and disconnect
+    - crypto: x86/poly1305 - fix overflow during partial reduction
+    - arm64: futex: Restore oldval initialization to work around buggy compilers
+    - x86/kprobes: Verify stack frame on kretprobe
+    - kprobes: Mark ftrace mcount handler functions nokprobe
+    - kprobes: Fix error check when reusing optimized probes
+    - mac80211: do not call driver wake_tx_queue op during reconfig
+    - Revert "kbuild: use -Oz instead of -Os when using clang"
+    - sched/fair: Limit sched_cfs_period_timer() loop to avoid hard lockup
+    - device_cgroup: fix RCU imbalance in error case
+    - mm/vmstat.c: fix /proc/vmstat format for CONFIG_DEBUG_TLBFLUSH=y
+      CONFIG_SMP=n
+    - ALSA: info: Fix racy addition/deletion of nodes
+    - Revert "locking/lockdep: Add debug_locks check in __lock_downgrade()"
+    - kernel/sysctl.c: fix out-of-bounds access when setting file-max
+    - Linux 4.4.179
+
+  * Xenial update: 4.4.178 upstream stable release (LP: #1826212)
+    - mmc: pxamci: fix enum type confusion
+    - drm/vmwgfx: Don't double-free the mode stored in par->set_mode
+    - udf: Fix crash on IO error during truncate
+    - mips: loongson64: lemote-2f: Add IRQF_NO_SUSPEND to "cascade" irqaction.
+    - MIPS: Fix kernel crash for R6 in jump label branch function
+    - futex: Ensure that futex address is aligned in handle_futex_death()
+    - ext4: fix NULL pointer dereference while journal is aborted
+    - ext4: fix data corruption caused by unaligned direct AIO
+    - ext4: brelse all indirect buffer in ext4_ind_remove_space()
+    - mmc: tmio_mmc_core: don't claim spurious interrupts
+    - media: v4l2-ctrls.c/uvc: zero v4l2_event
+    - locking/lockdep: Add debug_locks check in __lock_downgrade()
+    - ALSA: hda - Record the current power state before suspend/resume calls
+    - ALSA: hda - Enforces runtime_resume after S3 and S4 for each codec
+    - mmc: pwrseq_simple: Make reset-gpios optional to match doc
+    - mmc: debugfs: Add a restriction to mmc debugfs clock setting
+    - mmc: make MAN_BKOPS_EN message a debug
+    - mmc: sanitize 'bus width' in debug output
+    - mmc: core: shut up "voltage-ranges unspecified" pr_info()
+    - usb: dwc3: gadget: Fix suspend/resume during device mode
+    - arm64: mm: Add trace_irqflags annotations to do_debug_exception()
+    - mmc: core: fix using wrong io voltage if mmc_select_hs200 fails
+    - mm/rmap: replace BUG_ON(anon_vma->degree) with VM_WARN_ON
+    - extcon: usb-gpio: Don't miss event during suspend/resume
+    - kbuild: setlocalversion: print error to STDERR
+    - usb: gadget: composite: fix dereference after null check coverify warning
+    - usb: gadget: Add the gserial port checking in gs_start_tx()
+    - tcp/dccp: drop SYN packets if accept queue is full
+    - serial: sprd: adjust TIMEOUT to a big value
+    - Hang/soft lockup in d_invalidate with simultaneous calls
+    - arm64: traps: disable irq in die()
+    - usb: renesas_usbhs: gadget: fix unused-but-set-variable warning
+    - serial: sprd: clear timeout interrupt only rather than all interrupts
+    - lib/int_sqrt: optimize small argument
+    - USB: core: only clean up what we allocated
+    - rtc: Fix overflow when converting time64_t to rtc_time
+    - ath10k: avoid possible string overflow
+    - mmc: block: Allow more than 8 partitions per card
+    - arm64: fix COMPAT_SHMLBA definition for large pages
+    - efi: stub: define DISABLE_BRANCH_PROFILING for all architectures
+    - ARM: 8458/1: bL_switcher: add GIC dependency
+    - ARM: 8494/1: mm: Enable PXN when running non-LPAE kernel on LPAE processor
+    - android: unconditionally remove callbacks in sync_fence_free()
+    - vmstat: make vmstat_updater deferrable again and shut down on idle
+    - hid-sensor-hub.c: fix wrong do_div() usage
+    - arm64: hide __efistub_ aliases from kallsyms
+    - perf: Synchronously free aux pages in case of allocation failure
+    - net: diag: support v4mapped sockets in inet_diag_find_one_icsk()
+    - Revert "mmc: block: don't use parameter prefix if built as module"
+    - writeback: initialize inode members that track writeback history
+    - coresight: fixing lockdep error
+    - coresight: coresight_unregister() function cleanup
+    - coresight: release reference taken by 'bus_find_device()'
+    - coresight: remove csdev's link from topology
+    - stm class: Fix locking in unbinding policy path
+    - stm class: Fix link list locking
+    - stm class: Prevent user-controllable allocations
+    - stm class: Support devices with multiple instances
+    - stm class: Fix unlocking braino in the error path
+    - stm class: Guard output assignment against concurrency
+    - stm class: Fix unbalanced module/device refcounting
+    - stm class: Fix a race in unlinking
+    - coresight: "DEVICE_ATTR_RO" should defined as static.
+    - coresight: etm4x: Check every parameter used by dma_xx_coherent.
+    - asm-generic: Fix local variable shadow in __set_fixmap_offset
+    - staging: ashmem: Avoid deadlock with mmap/shrink
+    - staging: ashmem: Add missing include
+    - staging: ion: Set minimum carveout heap allocation order to PAGE_SHIFT
+    - staging: goldfish: audio: fix compiliation on arm
+    - ARM: 8510/1: rework ARM_CPU_SUSPEND dependencies
+    - arm64/kernel: fix incorrect EL0 check in inv_entry macro
+    - mac80211: fix "warning: ‘target_metric’ may be used uninitialized"
+    - perf/ring_buffer: Refuse to begin AUX transaction after rb->aux_mmap_count
+      drops
+    - arm64: kernel: Include _AC definition in page.h
+    - PM / Hibernate: Call flush_icache_range() on pages restored in-place
+    - stm class: Do not leak the chrdev in error path
+    - stm class: Fix stm device initialization order
+    - ipv6: fix endianness error in icmpv6_err
+    - usb: gadget: configfs: add mutex lock before unregister gadget
+    - usb: gadget: rndis: free response queue during REMOTE_NDIS_RESET_MSG
+    - cpu/hotplug: Handle unbalanced hotplug enable/disable
+    - video: fbdev: Set pixclock = 0 in goldfishfb
+    - arm64: kconfig: drop CONFIG_RTC_LIB dependency
+    - mmc: mmc: fix switch timeout issue caused by jiffies precision
+    - cfg80211: size various nl80211 messages correctly
+    - stmmac: copy unicast mac address to MAC registers
+    - dccp: do not use ipv6 header for ipv4 flow
+    - mISDN: hfcpci: Test both vendor & device ID for Digium HFC4S
+    - net/packet: Set __GFP_NOWARN upon allocation in alloc_pg_vec
+    - net: rose: fix a possible stack overflow
+    - Add hlist_add_tail_rcu() (Merge
+      git://git.kernel.org/pub/scm/linux/kernel/git/davem/net)
+    - packets: Always register packet sk in the same order
+    - tcp: do not use ipv6 header for ipv4 flow
+    - vxlan: Don't call gro_cells_destroy() before device is unregistered
+    - sctp: get sctphdr by offset in sctp_compute_cksum
+    - mac8390: Fix mmio access size probe
+    - btrfs: remove WARN_ON in log_dir_items
+    - ARM: imx6q: cpuidle: fix bug that CPU might not wake up at expected time
+    - ALSA: compress: add support for 32bit calls in a 64bit kernel
+    - ALSA: pcm: Fix possible OOB access in PCM oss plugins
+    - ALSA: pcm: Don't suspend stream in unrecoverable PCM state
+    - scsi: sd: Fix a race between closing an sd device and sd I/O
+    - scsi: zfcp: fix rport unblock if deleted SCSI devices on Scsi_Host
+    - scsi: zfcp: fix scsi_eh host reset with port_forced ERP for non-NPIV FCP
+      devices
+    - tty: atmel_serial: fix a potential NULL pointer dereference
+    - staging: vt6655: Remove vif check from vnt_interrupt
+    - staging: vt6655: Fix interrupt race condition on device start up.
+    - serial: max310x: Fix to avoid potential NULL pointer dereference
+    - serial: sh-sci: Fix setting SCSCR_TIE while transferring data
+    - USB: serial: cp210x: add new device id
+    - USB: serial: ftdi_sio: add additional NovaTech products
+    - USB: serial: mos7720: fix mos_parport refcount imbalance on error path
+    - USB: serial: option: set driver_info for SIM5218 and compatibles
+    - USB: serial: option: add Olicard 600
+    - Disable kgdboc failed by echo space to /sys/module/kgdboc/parameters/kgdboc
+    - fs/proc/proc_sysctl.c: fix NULL pointer dereference in put_links
+    - gpio: adnp: Fix testing wrong value in adnp_gpio_direction_input
+    - perf intel-pt: Fix TSC slip
+    - x86/smp: Enforce CONFIG_HOTPLUG_CPU when SMP=y
+    - KVM: Reject device ioctls from processes other than the VM's creator
+    - xhci: Fix port resume done detection for SS ports with LPM enabled
+    - Revert "USB: core: only clean up what we allocated"
+    - arm64: support keyctl() system call in 32-bit mode
+    - coresight: removing bind/unbind options from sysfs
+    - stm class: Hide STM-specific options if STM is disabled
+    - Linux 4.4.178
+
+  * Kprobe event string type argument failed in ftrace from
+    ubuntu_kernel_selftests on B/C i386 (LP: #1825780)
+    - selftests/ftrace: Fix kprobe string testcase to not probe notrace function
+
+  * False positive test result in run_netsocktests from net in
+    ubuntu_kernel_selftest (LP: #1825777)
+    - selftests/net: correct the return value for run_netsocktests
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 15 May 2019 14:39:49 +0200
+
+linux (4.4.0-148.174) xenial; urgency=medium
+
+  * CVE-2018-12126 // CVE-2018-12127 // CVE-2018-12130
+    - Documentation/l1tf: Fix small spelling typo
+    - perf/x86/intel: Add model number for Skylake Server to perf
+    - perf/x86: Add model numbers for Kabylake CPUs
+    - perf/x86/intel: Use Intel family macros for core perf events
+    - perf/x86/msr: Use Intel family macros for MSR events code
+    - perf/x86/msr: Add missing Intel models
+    - SAUCE: perf/x86/{cstate,rapl,uncore}: Use Intel Model name macros
+    - perf/x86/msr: Add missing CPU IDs
+    - x86/speculation: Simplify the CPU bug detection logic
+    - x86/cpu: Sanitize FAM6_ATOM naming
+    - kvm: x86: Report STIBP on GET_SUPPORTED_CPUID
+    - bitops: avoid integer overflow in GENMASK(_ULL)
+    - locking/atomics, asm-generic: Move some macros from <linux/bitops.h> to a
+      new <linux/bits.h> file
+    - tools include: Adopt linux/bits.h
+    - x86/msr-index: Cleanup bit defines
+    - x86/speculation: Consolidate CPU whitelists
+    - x86/speculation/mds: Add basic bug infrastructure for MDS
+    - x86/speculation/mds: Add BUG_MSBDS_ONLY
+    - x86/kvm: Expose X86_FEATURE_MD_CLEAR to guests
+    - x86/speculation/mds: Add mds_clear_cpu_buffers()
+    - locking/static_keys: Provide DECLARE and well as DEFINE macros
+    - x86/speculation/mds: Clear CPU buffers on exit to user
+    - x86/kvm/vmx: Add MDS protection when L1D Flush is not active
+    - x86/speculation/mds: Conditionally clear CPU buffers on idle entry
+    - SAUCE: sched/smt: Introduce sched_smt_{active,present}
+    - SAUCE: Rename the Ubuntu-only spec_ctrl_mutex mutex
+    - SAUCE: x86/speculation: Introduce arch_smt_update()
+    - x86/speculation: Rework SMT state change
+    - x86/speculation: Reorder the spec_v2 code
+    - x86/speculation: Unify conditional spectre v2 print functions
+    - x86/speculation/mds: Add mitigation control for MDS
+    - x86/speculation/mds: Add sysfs reporting for MDS
+    - x86/speculation/mds: Add mitigation mode VMWERV
+    - Documentation: Move L1TF to separate directory
+    - Documentation: Add MDS vulnerability documentation
+    - x86/speculation/mds: Add mds=full,nosmt cmdline option
+    - x86/speculation: Move arch_smt_update() call to after mitigation decisions
+    - x86/speculation/mds: Add SMT warning message
+    - x86/speculation/mds: Fix comment
+    - x86/speculation/mds: Print SMT vulnerable on MSBDS with mitigations off
+    - x86/speculation/mds: Add 'mitigations=' support for MDS
+
+  * CVE-2017-5715 // CVE-2017-5753
+    - s390/speculation: Support 'mitigations=' cmdline option
+
+  * CVE-2017-5715 // CVE-2017-5753 // CVE-2017-5754 // CVE-2018-3639
+    - powerpc/speculation: Support 'mitigations=' cmdline option
+
+  * CVE-2017-5715 // CVE-2017-5754 // CVE-2018-3620 // CVE-2018-3639 //
+    CVE-2018-3646
+    - cpu/speculation: Add 'mitigations=' cmdline option
+    - x86/speculation: Support 'mitigations=' cmdline option
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 07 May 2019 11:35:48 +0200
+
+linux (4.4.0-147.173) xenial; urgency=medium
+
+  * linux: 4.4.0-147.173 -proposed tracker (LP: #1826036)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * Xenial: Sync to upstream v4.9 (Spectre) (LP: #1820872)
+    - SAUCE: cpu/hotplug: Fix Documentation/kernel-parameters.txt
+    - SAUCE: Fix typo in Documentation/kernel-parameters.txt
+    - SAUCE: x86: Move hunks and sync to upstream stable 4.9
+    - Revert "module: Add retpoline tag to VERMAGIC"
+
+  * CVE-2017-5753
+    - posix-timers: Protect posix clock array access against speculation
+    - arm64: fix possible spectre-v1 in ptrace_hbp_get_event()
+    - sched/autogroup: Fix possible Spectre-v1 indexing for sched_prio_to_weight[]
+    - media: dvb_ca_en50221: prevent using slot_info for Spectre attacs
+    - s390/keyboard: sanitize array index in do_kdsk_ioctl
+    - arm64: fix possible spectre-v1 write in ptrace_hbp_set_event()
+    - pktcdvd: Fix possible Spectre-v1 for pkt_devs
+    - net: socket: Fix potential spectre v1 gadget in sock_is_registered
+    - net: sock_diag: Fix spectre v1 gadget in __sock_diag_cmd()
+    - hwmon: (nct6775) Fix potential Spectre v1
+    - mac80211_hwsim: Fix possible Spectre-v1 for hwsim_world_regdom_custom
+    - nl80211: Fix possible Spectre-v1 for NL80211_TXRATE_HT
+    - ipmi: msghandler: Fix potential Spectre v1 vulnerabilities
+    - powerpc/ptrace: Mitigate potential Spectre v1
+    - cfg80211: prevent speculation on cfg80211_classify8021d() return
+    - ALSA: rawmidi: Fix potential Spectre v1 vulnerability
+    - ALSA: seq: oss: Fix Spectre v1 vulnerability
+
+  * CVE-2019-3874
+    - sctp: fix the issue that a __u16 variable may overflow in sctp_ulpq_renege
+    - sctp: use sk_wmem_queued to check for writable space
+    - sctp: implement memory accounting on tx path
+    - sctp: implement memory accounting on rx path
+
+  * Kprobe event argument syntax in ftrace from ubuntu_kernel_selftests failed
+    on B PowerPC (LP: #1812809)
+    - selftests/ftrace: Add ppc support for kprobe args tests
+
+  * CVE-2019-3882
+    - vfio/type1: Limit DMA mappings per container
+
+  * Intel I210 Ethernet card not working after hotplug [8086:1533]
+    (LP: #1818490)
+    - igb: Fix WARN_ONCE on runtime suspend
+
+  * TSC clocksource not available in nested guests (LP: #1822821)
+    - x86/tsc: Add X86_FEATURE_TSC_KNOWN_FREQ flag
+    - kvmclock: fix TSC calibration for nested guests
+
+  * Remove btrfs module after a failed fallocate attempt will cause error on 4.4
+    i386 (LP: #1822579)
+    - Btrfs: fix extent map leak during fallocate error path
+
+  * systemd cause kernel trace "BUG: unable to handle kernel paging request at
+    6db23a14" on Cosmic i386 (LP: #1813244) // systemd cause kernel trace "BUG:
+    unable to handle kernel paging request at 6db23a14" on Cosmic i386
+    (LP: #1813244)
+    - openvswitch: fix flow actions reallocation
+
+ -- Connor Kuehl <connor.kuehl@canonical.com>  Tue, 23 Apr 2019 11:51:25 -0700
+
+linux (4.4.0-146.172) xenial; urgency=medium
+
+  * linux: 4.4.0-146.172 -proposed tracker (LP: #1822834)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - [Packaging] resync retpoline extraction
+
+  * 3b080b2564287be91605bfd1d5ee985696e61d3c in ubuntu_btrfs_kernel_fixes
+    triggers system hang on i386 (LP: #1812845)
+    - btrfs: raid56: properly unmap parity page in finish_parity_scrub()
+
+  * Xenial update: 4.4.177 upstream stable release (LP: #1822271)
+    - ceph: avoid repeatedly adding inode to mdsc->snap_flush_list
+    - numa: change get_mempolicy() to use nr_node_ids instead of MAX_NUMNODES
+    - KEYS: allow reaching the keys quotas exactly
+    - mfd: ti_am335x_tscadc: Use PLATFORM_DEVID_AUTO while registering mfd cells
+    - mfd: twl-core: Fix section annotations on {,un}protect_pm_master
+    - mfd: db8500-prcmu: Fix some section annotations
+    - mfd: ab8500-core: Return zero in get_register_interruptible()
+    - mfd: qcom_rpm: write fw_version to CTRL_REG
+    - mfd: wm5110: Add missing ASRC rate register
+    - mfd: mc13xxx: Fix a missing check of a register-read failure
+    - net: hns: Fix use after free identified by SLUB debug
+    - MIPS: ath79: Enable OF serial ports in the default config
+    - scsi: qla4xxx: check return code of qla4xxx_copy_from_fwddb_param
+    - scsi: isci: initialize shost fully before calling scsi_add_host()
+    - MIPS: jazz: fix 64bit build
+    - isdn: i4l: isdn_tty: Fix some concurrency double-free bugs
+    - atm: he: fix sign-extension overflow on large shift
+    - leds: lp5523: fix a missing check of return value of lp55xx_read
+    - isdn: avm: Fix string plus integer warning from Clang
+    - RDMA/srp: Rework SCSI device reset handling
+    - KEYS: user: Align the payload buffer
+    - KEYS: always initialize keyring_index_key::desc_len
+    - batman-adv: fix uninit-value in batadv_interface_tx()
+    - net/packet: fix 4gb buffer limit due to overflow check
+    - team: avoid complex list operations in team_nl_cmd_options_set()
+    - sit: check if IPv6 enabled before calling ip6_err_gen_icmpv6_unreach()
+    - net/mlx4_en: Force CHECKSUM_NONE for short ethernet frames
+    - ARCv2: Enable unaligned access in early ASM code
+    - Revert "bridge: do not add port to router list when receives query with
+      source 0.0.0.0"
+    - libceph: handle an empty authorize reply
+    - drm/msm: Unblock writer if reader closes file
+    - ASoC: Intel: Haswell/Broadwell: fix setting for .dynamic field
+    - ALSA: compress: prevent potential divide by zero bugs
+    - thermal: int340x_thermal: Fix a NULL vs IS_ERR() check
+    - usb: dwc3: gadget: Fix the uninitialized link_state when udc starts
+    - usb: gadget: Potential NULL dereference on allocation error
+    - ASoC: dapm: change snprintf to scnprintf for possible overflow
+    - ASoC: imx-audmux: change snprintf to scnprintf for possible overflow
+    - ARC: fix __ffs return value to avoid build warnings
+    - mac80211: fix miscounting of ttl-dropped frames
+    - serial: fsl_lpuart: fix maximum acceptable baud rate with over-sampling
+    - scsi: csiostor: fix NULL pointer dereference in csio_vport_set_state()
+    - net: altera_tse: fix connect_local_phy error path
+    - ibmveth: Do not process frames after calling napi_reschedule
+    - mac80211: don't initiate TDLS connection if station is not associated to AP
+    - cfg80211: extend range deviation for DMG
+    - KVM: nSVM: clear events pending from svm_complete_interrupts() when exiting
+      to L1
+    - arm/arm64: KVM: Feed initialized memory to MMIO accesses
+    - KVM: arm/arm64: Fix MMIO emulation data handling
+    - powerpc: Always initialize input array when calling epapr_hypercall()
+    - mmc: spi: Fix card detection during probe
+    - x86/uaccess: Don't leak the AC flag into __put_user() value evaluation
+    - USB: serial: option: add Telit ME910 ECM composition
+    - USB: serial: cp210x: add ID for Ingenico 3070
+    - USB: serial: ftdi_sio: add ID for Hjelmslund Electronics USB485
+    - cpufreq: Use struct kobj_attribute instead of struct global_attr
+    - sockfs: getxattr: Fail with -EOPNOTSUPP for invalid attribute names
+    - ncpfs: fix build warning of strncpy
+    - isdn: isdn_tty: fix build warning of strncpy
+    - staging: lustre: fix buffer overflow of string buffer
+    - net-sysfs: Fix mem leak in netdev_register_kobject
+    - team: Free BPF filter when unregistering netdev
+    - bnxt_en: Drop oversize TX packets to prevent errors.
+    - net: nfc: Fix NULL dereference on nfc_llcp_build_tlv fails
+    - xen-netback: fix occasional leak of grant ref mappings under memory pressure
+    - net: Add __icmp_send helper.
+    - net: avoid use IPCB in cipso_v4_error
+    - net: phy: Micrel KSZ8061: link failure after cable connect
+    - x86/CPU/AMD: Set the CPB bit unconditionally on F17h
+    - applicom: Fix potential Spectre v1 vulnerabilities
+    - MIPS: irq: Allocate accurate order pages for irq stack
+    - hugetlbfs: fix races and page leaks during migration
+    - netlabel: fix out-of-bounds memory accesses
+    - net: dsa: mv88e6xxx: Fix u64 statistics
+    - ip6mr: Do not call __IP6_INC_STATS() from preemptible context
+    - media: uvcvideo: Fix 'type' check leading to overflow
+    - vti4: Fix a ipip packet processing bug in 'IPCOMP' virtual tunnel
+    - perf tools: Handle TOPOLOGY headers with no CPU
+    - IB/{hfi1, qib}: Fix WC.byte_len calculation for UD_SEND_WITH_IMM
+    - ipvs: Fix signed integer overflow when setsockopt timeout
+    - iommu/amd: Fix IOMMU page flush when detach device from a domain
+    - xtensa: SMP: fix ccount_timer_shutdown
+    - xtensa: SMP: fix secondary CPU initialization
+    - xtensa: smp_lx200_defconfig: fix vectors clash
+    - xtensa: SMP: mark each possible CPU as present
+    - xtensa: SMP: limit number of possible CPUs by NR_CPUS
+    - net: altera_tse: fix msgdma_tx_completion on non-zero fill_level case
+    - net: hns: Fix wrong read accesses via Clause 45 MDIO protocol
+    - net: stmmac: dwmac-rk: fix error handling in rk_gmac_powerup()
+    - gpio: vf610: Mask all GPIO interrupts
+    - nfs: Fix NULL pointer dereference of dev_name
+    - scsi: libfc: free skb when receiving invalid flogi resp
+    - platform/x86: Fix unmet dependency warning for SAMSUNG_Q10
+    - cifs: fix computation for MAX_SMB2_HDR_SIZE
+    - x86/kexec: Don't setup EFI info if EFI runtime is not enabled
+    - x86_64: increase stack size for KASAN_EXTRA
+    - mm, memory_hotplug: is_mem_section_removable do not pass the end of a zone
+    - mm, memory_hotplug: test_pages_in_a_zone do not pass the end of zone
+    - fs/drop_caches.c: avoid softlockups in drop_pagecache_sb()
+    - autofs: drop dentry reference only when it is never used
+    - autofs: fix error return in autofs_fill_super()
+    - ARM: pxa: ssp: unneeded to free devm_ allocated data
+    - irqchip/mmp: Only touch the PJ4 IRQ & FIQ bits on enable/disable
+    - dmaengine: at_xdmac: Fix wrongfull report of a channel as in use
+    - dmaengine: dmatest: Abort test in case of mapping error
+    - s390/qeth: fix use-after-free in error path
+    - perf symbols: Filter out hidden symbols from labels
+    - MIPS: Remove function size check in get_frame_info()
+    - Input: wacom_serial4 - add support for Wacom ArtPad II tablet
+    - Input: elan_i2c - add id for touchpad found in Lenovo s21e-20
+    - iscsi_ibft: Fix missing break in switch statement
+    - futex,rt_mutex: Restructure rt_mutex_finish_proxy_lock()
+    - ARM: dts: exynos: Add minimal clkout parameters to Exynos3250 PMU
+    - Revert "x86/platform/UV: Use efi_runtime_lock to serialise BIOS calls"
+    - ARM: dts: exynos: Do not ignore real-world fuse values for thermal zone 0 on
+      Exynos5420
+    - udplite: call proper backlog handlers
+    - netfilter: x_tables: enforce nul-terminated table name from getsockopt
+      GET_ENTRIES
+    - netfilter: nfnetlink_log: just returns error for unknown command
+    - netfilter: nfnetlink_acct: validate NFACCT_FILTER parameters
+    - netfilter: nf_conntrack_tcp: Fix stack out of bounds when parsing TCP
+      options
+    - KEYS: restrict /proc/keys by credentials at open time
+    - l2tp: fix infoleak in l2tp_ip6_recvmsg()
+    - net: hsr: fix memory leak in hsr_dev_finalize()
+    - net: sit: fix UBSAN Undefined behaviour in check_6rd
+    - net/x25: fix use-after-free in x25_device_event()
+    - net/x25: reset state in x25_connect()
+    - pptp: dst_release sk_dst_cache in pptp_sock_destruct
+    - ravb: Decrease TxFIFO depth of Q3 and Q2 to one
+    - route: set the deleted fnhe fnhe_daddr to 0 in ip_del_fnhe to fix a race
+    - tcp: handle inet_csk_reqsk_queue_add() failures
+    - net/mlx4_core: Fix reset flow when in command polling mode
+    - net/mlx4_core: Fix qp mtt size calculation
+    - net/x25: fix a race in x25_bind()
+    - mdio_bus: Fix use-after-free on device_register fails
+    - net: Set rtm_table to RT_TABLE_COMPAT for ipv6 for tables > 255
+    - missing barriers in some of unix_sock ->addr and ->path accesses
+    - ipvlan: disallow userns cap_net_admin to change global mode/flags
+    - vxlan: test dev->flags & IFF_UP before calling gro_cells_receive()
+    - vxlan: Fix GRO cells race condition between receive and link delete
+    - net/hsr: fix possible crash in add_timer()
+    - gro_cells: make sure device is up in gro_cells_receive()
+    - tcp/dccp: remove reqsk_put() from inet_child_forget()
+    - ALSA: bebob: use more identical mod_alias for Saffire Pro 10 I/O against
+      Liquid Saffire 56
+    - fs/9p: use fscache mutex rather than spinlock
+    - It's wrong to add len to sector_nr in raid10 reshape twice
+    - media: videobuf2-v4l2: drop WARN_ON in vb2_warn_zero_bytesused()
+    - 9p: use inode->i_lock to protect i_size_write() under 32-bit
+    - 9p/net: fix memory leak in p9_client_create
+    - ASoC: fsl_esai: fix register setting issue in RIGHT_J mode
+    - stm class: Fix an endless loop in channel allocation
+    - crypto: caam - fixed handling of sg list
+    - crypto: ahash - fix another early termination in hash walk
+    - gpu: ipu-v3: Fix i.MX51 CSI control registers offset
+    - gpu: ipu-v3: Fix CSI offsets for imx53
+    - s390/dasd: fix using offset into zero size array error
+    - ARM: OMAP2+: Variable "reg" in function omap4_dsi_mux_pads() could be
+      uninitialized
+    - Input: matrix_keypad - use flush_delayed_work()
+    - i2c: cadence: Fix the hold bit setting
+    - Input: st-keyscan - fix potential zalloc NULL dereference
+    - ARM: 8824/1: fix a migrating irq bug when hotplug cpu
+    - assoc_array: Fix shortcut creation
+    - net: systemport: Fix reception of BPDUs
+    - pinctrl: meson: meson8b: fix the sdxc_a data 1..3 pins
+    - net: mv643xx_eth: disable clk on error path in mv643xx_eth_shared_probe()
+    - ASoC: topology: free created components in tplg load error
+    - arm64: Relax GIC version check during early boot
+    - tmpfs: fix link accounting when a tmpfile is linked in
+    - ARC: uacces: remove lp_start, lp_end from clobber list
+    - phonet: fix building with clang
+    - mac80211_hwsim: propagate genlmsg_reply return code
+    - net: set static variable an initial value in atl2_probe()
+    - tmpfs: fix uninitialized return value in shmem_link
+    - stm class: Prevent division by zero
+    - crypto: arm64/aes-ccm - fix logical bug in AAD MAC handling
+    - CIFS: Fix read after write for files with read caching
+    - tracing: Do not free iter->trace in fail path of tracing_open_pipe()
+    - ACPI / device_sysfs: Avoid OF modalias creation for removed device
+    - regulator: s2mps11: Fix steps for buck7, buck8 and LDO35
+    - regulator: s2mpa01: Fix step values for some LDOs
+    - clocksource/drivers/exynos_mct: Move one-shot check from tick clear to ISR
+    - clocksource/drivers/exynos_mct: Clear timer interrupt when shutdown
+    - s390/virtio: handle find on invalid queue gracefully
+    - scsi: virtio_scsi: don't send sc payload with tmfs
+    - scsi: target/iscsi: Avoid iscsit_release_commands_from_conn() deadlock
+    - m68k: Add -ffreestanding to CFLAGS
+    - btrfs: ensure that a DUP or RAID1 block group has exactly two stripes
+    - Btrfs: fix corruption reading shared and compressed extents after hole
+      punching
+    - crypto: pcbc - remove bogus memcpy()s with src == dest
+    - cpufreq: tegra124: add missing of_node_put()
+    - cpufreq: pxa2xx: remove incorrect __init annotation
+    - ext4: fix crash during online resizing
+    - ext2: Fix underflow in ext2_max_size()
+    - clk: ingenic: Fix round_rate misbehaving with non-integer dividers
+    - dmaengine: usb-dmac: Make DMAC system sleep callbacks explicit
+    - mm/vmalloc: fix size check for remap_vmalloc_range_partial()
+    - kernel/sysctl.c: add missing range check in do_proc_dointvec_minmax_conv
+    - intel_th: Don't reference unassigned outputs
+    - parport_pc: fix find_superio io compare code, should use equal test.
+    - i2c: tegra: fix maximum transfer size
+    - perf bench: Copy kernel files needed to build mem{cpy,set} x86_64 benchmarks
+    - serial: 8250_pci: Fix number of ports for ACCES serial cards
+    - serial: 8250_pci: Have ACCES cards that use the four port Pericom PI7C9X7954
+      chip use the pci_pericom_setup()
+    - jbd2: clear dirty flag when revoking a buffer from an older transaction
+    - jbd2: fix compile warning when using JBUFFER_TRACE
+    - powerpc/32: Clear on-stack exception marker upon exception return
+    - powerpc/wii: properly disable use of BATs when requested.
+    - powerpc/powernv: Make opal log only readable by root
+    - powerpc/83xx: Also save/restore SPRG4-7 during suspend
+    - ARM: s3c24xx: Fix boolean expressions in osiris_dvs_notify
+    - dm: fix to_sector() for 32bit
+    - NFS41: pop some layoutget errors to application
+    - perf intel-pt: Fix CYC timestamp calculation after OVF
+    - perf auxtrace: Define auxtrace record alignment
+    - perf intel-pt: Fix overlap calculation for padding
+    - md: Fix failed allocation of md_register_thread
+    - NFS: Fix an I/O request leakage in nfs_do_recoalesce
+    - NFS: Don't recoalesce on error in nfs_pageio_complete_mirror()
+    - nfsd: fix memory corruption caused by readdir
+    - nfsd: fix wrong check in write_v4_end_grace()
+    - PM / wakeup: Rework wakeup source timer cancellation
+    - rcu: Do RCU GP kthread self-wakeup from softirq and interrupt
+    - media: uvcvideo: Avoid NULL pointer dereference at the end of streaming
+    - drm/radeon/evergreen_cs: fix missing break in switch statement
+    - KVM: nVMX: Sign extend displacements of VMX instr's mem operands
+    - KVM: nVMX: Ignore limit checks on VMX instructions using flat segments
+    - KVM: X86: Fix residual mmio emulation request to userspace
+    - Linux 4.4.177
+
+  * sky2 ethernet card doesn't work after returning from suspend
+    (LP: #1807259) // sky2 ethernet card link not up after suspend
+    (LP: #1809843) // Xenial update: 4.4.177 upstream stable release
+    (LP: #1822271)
+    - sky2: Disable MSI on Dell Inspiron 1545 and Gateway P-79
+
+  * [CONFIG] please enable highdpi font FONT_TER16x32 (LP: #1819881)
+    - lib/fonts/Kconfig: keep non-Sparc fonts listed together
+    - Fonts: New Terminus large console font
+    - [Config]: enable highdpi Terminus 16x32 font support
+
+  * Hard lockup in 2 CPUs due to deadlock in cpu_stoppers (LP: #1821259)
+    - stop_machine, sched: Fix migrate_swap() vs. active_balance() deadlock
+    - stop_machine: Disable preemption when waking two stopper threads
+    - stop_machine: Disable preemption after queueing stopper threads
+    - stop_machine: Atomically queue and wake stopper threads
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Tue, 02 Apr 2019 23:03:42 -0400
+
+linux (4.4.0-145.171) xenial; urgency=medium
+
+  * linux: 4.4.0-145.171 -proposed tracker (LP: #1821724)
+
+  * linux-generic should depend on linux-base >=4.1 (LP: #1820419)
+    - [Packaging] Fix linux-base dependency
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 26 Mar 2019 13:27:29 +0100
+
+linux (4.4.0-144.170) xenial; urgency=medium
+
+  * linux: 4.4.0-144.170 -proposed tracker (LP: #1819660)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+    - [Packaging] resync retpoline extraction
+
+  * C++ demangling support missing from perf (LP: #1396654)
+    - [Packaging] fix a mistype
+
+  * CVE-2019-9213
+    - mm: enforce min addr even if capable() in expand_downwards()
+
+  * CVE-2019-3460
+    - Bluetooth: Check L2CAP option sizes returned from l2cap_get_conf_opt
+
+  * Xenial update: 4.4.176 upstream stable release (LP: #1818815)
+    - net: fix IPv6 prefix route residue
+    - vsock: cope with memory allocation failure at socket creation time
+    - hwmon: (lm80) Fix missing unlock on error in set_fan_div()
+    - net: Fix for_each_netdev_feature on Big endian
+    - net: Add header for usage of fls64()
+    - tcp: tcp_v4_err() should be more careful
+    - net: Do not allocate page fragments that are not skb aligned
+    - tcp: clear icsk_backoff in tcp_write_queue_purge()
+    - vxlan: test dev->flags & IFF_UP before calling netif_rx()
+    - net: stmmac: Fix a race in EEE enable callback
+    - net: ipv4: use a dedicated counter for icmp_v4 redirect packets
+    - x86: livepatch: Treat R_X86_64_PLT32 as R_X86_64_PC32
+    - mfd: as3722: Handle interrupts on suspend
+    - mfd: as3722: Mark PM functions as __maybe_unused
+    - net/x25: do not hold the cpu too long in x25_new_lci()
+    - mISDN: fix a race in dev_expire_timer()
+    - ax25: fix possible use-after-free
+    - Linux 4.4.176
+
+  * sky2 ethernet card don't work after returning from suspension
+    (LP: #1798921) // Xenial update: 4.4.176 upstream stable release
+    (LP: #1818815)
+    - sky2: Increase D3 delay again
+
+  * Xenial update: 4.4.175 upstream stable release (LP: #1818813)
+    - drm/bufs: Fix Spectre v1 vulnerability
+    - staging: iio: adc: ad7280a: handle error from __ad7280_read32()
+    - ASoC: Intel: mrfld: fix uninitialized variable access
+    - scsi: lpfc: Correct LCB RJT handling
+    - ARM: 8808/1: kexec:offline panic_smp_self_stop CPU
+    - dlm: Don't swamp the CPU with callbacks queued during recovery
+    - x86/PCI: Fix Broadcom CNB20LE unintended sign extension (redux)
+    - powerpc/pseries: add of_node_put() in dlpar_detach_node()
+    - serial: fsl_lpuart: clear parity enable bit when disable parity
+    - ptp: check gettime64 return code in PTP_SYS_OFFSET ioctl
+    - staging:iio:ad2s90: Make probe handle spi_setup failure
+    - staging: iio: ad7780: update voltage on read
+    - ARM: OMAP2+: hwmod: Fix some section annotations
+    - modpost: validate symbol names also in find_elf_symbol
+    - perf tools: Add Hygon Dhyana support
+    - soc/tegra: Don't leak device tree node reference
+    - f2fs: move dir data flush to write checkpoint process
+    - f2fs: fix wrong return value of f2fs_acl_create
+    - sunvdc: Do not spin in an infinite loop when vio_ldc_send() returns EAGAIN
+    - nfsd4: fix crash on writing v4_end_grace before nfsd startup
+    - arm64: ftrace: don't adjust the LR value
+    - ARM: dts: mmp2: fix TWSI2
+    - x86/fpu: Add might_fault() to user_insn()
+    - media: DaVinci-VPBE: fix error handling in vpbe_initialize()
+    - smack: fix access permissions for keyring
+    - usb: hub: delay hub autosuspend if USB3 port is still link training
+    - timekeeping: Use proper seqcount initializer
+    - ARM: dts: Fix OMAP4430 SDP Ethernet startup
+    - mips: bpf: fix encoding bug for mm_srlv32_op
+    - iommu/arm-smmu-v3: Use explicit mb() when moving cons pointer
+    - sata_rcar: fix deferred probing
+    - clk: imx6sl: ensure MMDC CH0 handshake is bypassed
+    - cpuidle: big.LITTLE: fix refcount leak
+    - i2c-axxia: check for error conditions first
+    - udf: Fix BUG on corrupted inode
+    - ARM: pxa: avoid section mismatch warning
+    - ASoC: fsl: Fix SND_SOC_EUKREA_TLV320 build error on i.MX8M
+    - memstick: Prevent memstick host from getting runtime suspended during card
+      detection
+    - tty: serial: samsung: Properly set flags in autoCTS mode
+    - arm64: KVM: Skip MMIO insn after emulation
+    - powerpc/uaccess: fix warning/error with access_ok()
+    - mac80211: fix radiotap vendor presence bitmap handling
+    - xfrm6_tunnel: Fix spi check in __xfrm6_tunnel_alloc_spi
+    - Bluetooth: Fix unnecessary error message for HCI request completion
+    - cw1200: Fix concurrency use-after-free bugs in cw1200_hw_scan()
+    - drbd: narrow rcu_read_lock in drbd_sync_handshake
+    - drbd: disconnect, if the wrong UUIDs are attached on a connected peer
+    - drbd: skip spurious timeout (ping-timeo) when failing promote
+    - drbd: Avoid Clang warning about pointless switch statment
+    - video: clps711x-fb: release disp device node in probe()
+    - fbdev: fbmem: behave better with small rotated displays and many CPUs
+    - fbdev: fbcon: Fix unregister crash when more than one framebuffer
+    - KVM: x86: svm: report MSR_IA32_MCG_EXT_CTL as unsupported
+    - NFS: nfs_compare_mount_options always compare auth flavors.
+    - hwmon: (lm80) fix a missing check of the status of SMBus read
+    - hwmon: (lm80) fix a missing check of bus read in lm80 probe
+    - seq_buf: Make seq_buf_puts() null-terminate the buffer
+    - crypto: ux500 - Use proper enum in cryp_set_dma_transfer
+    - crypto: ux500 - Use proper enum in hash_set_dma_transfer
+    - cifs: check ntwrk_buf_start for NULL before dereferencing it
+    - um: Avoid marking pages with "changed protection"
+    - niu: fix missing checks of niu_pci_eeprom_read
+    - scripts/decode_stacktrace: only strip base path when a prefix of the path
+    - ocfs2: don't clear bh uptodate for block read
+    - isdn: hisax: hfc_pci: Fix a possible concurrency use-after-free bug in
+      HFCPCI_l1hw()
+    - gdrom: fix a memory leak bug
+    - block/swim3: Fix -EBUSY error when re-opening device after unmount
+    - HID: lenovo: Add checks to fix of_led_classdev_register
+    - kernel/hung_task.c: break RCU locks based on jiffies
+    - fs/epoll: drop ovflist branch prediction
+    - exec: load_script: don't blindly truncate shebang string
+    - thermal: hwmon: inline helpers when CONFIG_THERMAL_HWMON is not set
+    - test_hexdump: use memcpy instead of strncpy
+    - tipc: use destination length for copy string
+    - string: drop __must_check from strscpy() and restore strscpy() usages in
+      cgroup
+    - dccp: fool proof ccid_hc_[rt]x_parse_options()
+    - enic: fix checksum validation for IPv6
+    - net: dp83640: expire old TX-skb
+    - skge: potential memory corruption in skge_get_regs()
+    - net: systemport: Fix WoL with password after deep sleep
+    - net: dsa: slave: Don't propagate flag changes on down slave interfaces
+    - ALSA: compress: Fix stop handling on compressed capture streams
+    - ALSA: hda - Serialize codec registrations
+    - fuse: call pipe_buf_release() under pipe lock
+    - fuse: decrement NR_WRITEBACK_TEMP on the right page
+    - fuse: handle zero sized retrieve correctly
+    - dmaengine: imx-dma: fix wrong callback invoke
+    - usb: phy: am335x: fix race condition in _probe
+    - usb: gadget: udc: net2272: Fix bitwise and boolean operations
+    - perf/x86/intel/uncore: Add Node ID mask
+    - x86/MCE: Initialize mce.bank in the case of a fatal error in
+      mce_no_way_out()
+    - perf/core: Don't WARN() for impossible ring-buffer sizes
+    - perf tests evsel-tp-sched: Fix bitwise operator
+    - mtd: rawnand: gpmi: fix MX28 bus master lockup problem
+    - signal: Always notice exiting tasks
+    - signal: Better detection of synchronous signals
+    - misc: vexpress: Off by one in vexpress_syscfg_exec()
+    - debugfs: fix debugfs_rename parameter checking
+    - mips: cm: reprime error cause
+    - MIPS: OCTEON: don't set octeon_dma_bar_type if PCI is disabled
+    - MIPS: VDSO: Include $(ccflags-vdso) in o32,n32 .lds builds
+    - ARM: iop32x/n2100: fix PCI IRQ mapping
+    - mac80211: ensure that mgmt tx skbs have tailroom for encryption
+    - drm/modes: Prevent division by zero htotal
+    - drm/vmwgfx: Fix setting of dma masks
+    - drm/vmwgfx: Return error code from vmw_execbuf_copy_fence_user
+    - HID: debug: fix the ring buffer implementation
+    - NFC: nxp-nci: Include unaligned.h instead of access_ok.h
+    - Revert "cifs: In Kconfig CONFIG_CIFS_POSIX needs depends on legacy (insecure
+      cifs)"
+    - Revert "UBUNTU: [Config] Remove CONFIG_CIFS_POSIX=y"
+    - libceph: avoid KEEPALIVE_PENDING races in ceph_con_keepalive()
+    - xfrm: refine validation of template and selector families
+    - batman-adv: Avoid WARN on net_device without parent in netns
+    - batman-adv: Force mac header to start of data on xmit
+    - Revert "exec: load_script: don't blindly truncate shebang string"
+    - uapi/if_ether.h: prevent redefinition of struct ethhdr
+    - ARM: dts: da850-evm: Correct the sound card name
+    - ARM: dts: kirkwood: Fix polarity of GPIO fan lines
+    - gpio: pl061: handle failed allocations
+    - cifs: Limit memory used by lock request calls to a page
+    - Documentation/network: reword kernel version reference
+    - Revert "Input: elan_i2c - add ACPI ID for touchpad in ASUS Aspire F5-573G"
+    - Input: elan_i2c - add ACPI ID for touchpad in Lenovo V330-15ISK
+    - perf/core: Fix impossible ring-buffer sizes warning
+    - ALSA: hda - Add quirk for HP EliteBook 840 G5
+    - ALSA: usb-audio: Fix implicit fb endpoint setup by quirk
+    - Input: bma150 - register input device after setting private data
+    - Input: elantech - enable 3rd button support on Fujitsu CELSIUS H780
+    - alpha: fix page fault handling for r16-r18 targets
+    - alpha: Fix Eiger NR_IRQS to 128
+    - tracing/uprobes: Fix output for multiple string arguments
+    - x86/platform/UV: Use efi_runtime_lock to serialise BIOS calls
+    - signal: Restore the stop PTRACE_EVENT_EXIT
+    - x86/a.out: Clear the dump structure initially
+    - dm thin: fix bug where bio that overwrites thin block ignores FUA
+    - smsc95xx: Use skb_cow_head to deal with cloned skbs
+    - ch9200: use skb_cow_head() to deal with cloned skbs
+    - kaweth: use skb_cow_head() to deal with cloned skbs
+    - usb: dwc2: Remove unnecessary kfree
+    - pinctrl: msm: fix gpio-hog related boot issues
+    - uapi/if_ether.h: move __UAPI_DEF_ETHHDR libc define
+    - Linux 4.4.175
+
+  * Xenial update: 4.4.174 upstream stable release (LP: #1818806)
+    - inet: frags: change inet_frags_init_net() return value
+    - inet: frags: add a pointer to struct netns_frags
+    - inet: frags: refactor ipfrag_init()
+    - inet: frags: refactor ipv6_frag_init()
+    - inet: frags: refactor lowpan_net_frag_init()
+    - rhashtable: add rhashtable_lookup_get_insert_key()
+    - rhashtable: Add rhashtable_lookup()
+    - rhashtable: add schedule points
+    - inet: frags: use rhashtables for reassembly units
+    - net: ieee802154: 6lowpan: fix frag reassembly
+    - ipfrag: really prevent allocation on netns exit
+    - inet: frags: remove some helpers
+    - inet: frags: get rif of inet_frag_evicting()
+    - inet: frags: remove inet_frag_maybe_warn_overflow()
+    - inet: frags: break the 2GB limit for frags storage
+    - inet: frags: do not clone skb in ip_expire()
+    - ipv6: frags: rewrite ip6_expire_frag_queue()
+    - rhashtable: reorganize struct rhashtable layout
+    - inet: frags: reorganize struct netns_frags
+    - inet: frags: get rid of ipfrag_skb_cb/FRAG_CB
+    - inet: frags: fix ip6frag_low_thresh boundary
+    - ip: discard IPv4 datagrams with overlapping segments.
+    - net: modify skb_rbtree_purge to return the truesize of all purged skbs.
+    - ipv6: defrag: drop non-last frags smaller than min mtu
+    - net: pskb_trim_rcsum() and CHECKSUM_COMPLETE are friends
+    - ip: use rb trees for IP frag queue.
+    - ip: add helpers to process in-order fragments faster.
+    - ip: process in-order fragments efficiently
+    - ip: frags: fix crash in ip_do_fragment()
+    - ipv4: frags: precedence bug in ip_expire()
+    - inet: frags: better deal with smp races
+    - net: fix pskb_trim_rcsum_slow() with odd trim offset
+    - net: ipv4: do not handle duplicate fragments as overlapping
+    - rcu: Force boolean subscript for expedited stall warnings
+    - Linux 4.4.174
+
+  * Xenial update: 4.4.173 upstream stable release (LP: #1818803)
+    - net: Fix usage of pskb_trim_rcsum
+    - openvswitch: Avoid OOB read when parsing flow nlattrs
+    - net: ipv4: Fix memory leak in network namespace dismantle
+    - net_sched: refetch skb protocol for each filter
+    - net: bridge: Fix ethernet header pointer before check skb forwardable
+    - USB: serial: simple: add Motorola Tetra TPG2200 device id
+    - USB: serial: pl2303: add new PID to support PL2303TB
+    - ASoC: atom: fix a missing check of snd_pcm_lib_malloc_pages
+    - ARC: perf: map generic branches to correct hardware condition
+    - s390/early: improve machine detection
+    - s390/smp: fix CPU hotplug deadlock with CPU rescan
+    - char/mwave: fix potential Spectre v1 vulnerability
+    - staging: rtl8188eu: Add device code for D-Link DWA-121 rev B1
+    - tty: Handle problem if line discipline does not have receive_buf
+    - tty/n_hdlc: fix __might_sleep warning
+    - CIFS: Fix possible hang during async MTU reads and writes
+    - Input: xpad - add support for SteelSeries Stratus Duo
+    - KVM: x86: Fix single-step debugging
+    - x86/kaslr: Fix incorrect i8254 outb() parameters
+    - can: dev: __can_get_echo_skb(): fix bogous check for non-existing skb by
+      removing it
+    - can: bcm: check timer values before ktime conversion
+    - vt: invoke notifier on screen size change
+    - perf unwind: Unwind with libdw doesn't take symfs into account
+    - perf unwind: Take pgoff into account when reporting elf to libdwfl
+    - irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size
+    - arm64: mm: remove page_mapping check in __sync_icache_dcache
+    - f2fs: read page index before freeing
+    - Revert "loop: Fix double mutex_unlock(&loop_ctl_mutex) in
+      loop_control_ioctl()"
+    - Revert "loop: Get rid of loop_index_mutex"
+    - Revert "loop: Fold __loop_release into loop_release"
+    - s390/smp: Fix calling smp_call_ipl_cpu() from ipl CPU
+    - fs: add the fsnotify call to vfs_iter_write
+    - ipv6: Consider sk_bound_dev_if when binding a socket to an address
+    - l2tp: copy 4 more bytes to linear part if necessary
+    - net/mlx4_core: Add masking for a few queries on HCA caps
+    - netrom: switch to sock timer API
+    - net/rose: fix NULL ax25_cb kernel panic
+    - ucc_geth: Reset BQL queue when stopping device
+    - l2tp: remove l2specific_len dependency in l2tp_core
+    - l2tp: fix reading optional fields of L2TPv3
+    - CIFS: Do not count -ENODATA as failure for query directory
+    - fs/dcache: Fix incorrect nr_dentry_unused accounting in shrink_dcache_sb()
+    - ARM: cns3xxx: Fix writing to wrong PCI config registers after alignment
+    - arm64: hyp-stub: Forbid kprobing of the hyp-stub
+    - gfs2: Revert "Fix loop in gfs2_rbm_find"
+    - platform/x86: asus-nb-wmi: Map 0x35 to KEY_SCREENLOCK
+    - platform/x86: asus-nb-wmi: Drop mapping of 0x33 and 0x34 scan codes
+    - mmc: sdhci-iproc: handle mmc_of_parse() errors during probe
+    - kernel/exit.c: release ptraced tasks before zap_pid_ns_processes
+    - mm, oom: fix use-after-free in oom_kill_process
+    - cifs: Always resolve hostname before reconnecting
+    - drivers: core: Remove glue dirs from sysfs earlier
+    - mm: migrate: don't rely on __PageMovable() of newpage after unlocking it
+    - fs: don't scan the inode cache before SB_BORN is set
+    - Linux 4.4.173
+
+  * Xenial update: 4.4.172 upstream stable release (LP: #1818797)
+    - tty/ldsem: Wake up readers after timed out down_write()
+    - can: gw: ensure DLC boundaries after CAN frame modification
+    - f2fs: clean up argument of recover_data
+    - f2fs: cover more area with nat_tree_lock
+    - f2fs: move sanity checking of cp into get_valid_checkpoint
+    - f2fs: fix to convert inline directory correctly
+    - f2fs: give -EINVAL for norecovery and rw mount
+    - f2fs: remove an obsolete variable
+    - f2fs: factor out fsync inode entry operations
+    - f2fs: fix inode cache leak
+    - f2fs: fix to avoid reading out encrypted data in page cache
+    - f2fs: not allow to write illegal blkaddr
+    - f2fs: avoid unneeded loop in build_sit_entries
+    - f2fs: use crc and cp version to determine roll-forward recovery
+    - f2fs: introduce get_checkpoint_version for cleanup
+    - f2fs: put directory inodes before checkpoint in roll-forward recovery
+    - f2fs: fix to determine start_cp_addr by sbi->cur_cp_pack
+    - f2fs: detect wrong layout
+    - f2fs: free meta pages if sanity check for ckpt is failed
+    - f2fs: fix race condition in between free nid allocator/initializer
+    - f2fs: return error during fill_super
+    - f2fs: check blkaddr more accuratly before issue a bio
+    - f2fs: sanity check on sit entry
+    - f2fs: enhance sanity_check_raw_super() to avoid potential overflow
+    - f2fs: clean up with is_valid_blkaddr()
+    - f2fs: introduce and spread verify_blkaddr
+    - f2fs: fix to do sanity check with secs_per_zone
+    - f2fs: fix to do sanity check with user_block_count
+    - f2fs: Add sanity_check_inode() function
+    - f2fs: fix to do sanity check with node footer and iblocks
+    - f2fs: fix to do sanity check with reserved blkaddr of inline inode
+    - f2fs: fix to do sanity check with block address in main area
+    - f2fs: fix to do sanity check with block address in main area v2
+    - f2fs: fix to do sanity check with cp_pack_start_sum
+    - f2fs: fix invalid memory access
+    - f2fs: fix missing up_read
+    - f2fs: fix validation of the block count in sanity_check_raw_super
+    - media: em28xx: Fix misplaced reset of dev->v4l::field_count
+    - arm64/kvm: consistently handle host HCR_EL2 flags
+    - arm64: Don't trap host pointer auth use to EL2
+    - ipv6: fix kernel-infoleak in ipv6_local_error()
+    - net: bridge: fix a bug on using a neighbour cache entry without checking its
+      state
+    - packet: Do not leak dev refcounts on error exit
+    - ip: on queued skb use skb_header_pointer instead of pskb_may_pull
+    - crypto: authencesn - Avoid twice completion call in decrypt path
+    - crypto: authenc - fix parsing key with misaligned rta_len
+    - btrfs: wait on ordered extents on abort cleanup
+    - Yama: Check for pid death before checking ancestry
+    - scsi: sd: Fix cache_type_store()
+    - mips: fix n32 compat_ipc_parse_version
+    - mfd: tps6586x: Handle interrupts on suspend
+    - Disable MSI also when pcie-octeon.pcie_disable on
+    - omap2fb: Fix stack memory disclosure
+    - media: vivid: fix error handling of kthread_run
+    - media: vivid: set min width/height to a value > 0
+    - LSM: Check for NULL cred-security on free
+    - media: vb2: vb2_mmap: move lock up
+    - sunrpc: handle ENOMEM in rpcb_getport_async
+    - selinux: fix GPF on invalid policy
+    - sctp: allocate sctp_sockaddr_entry with kzalloc
+    - tipc: fix uninit-value in tipc_nl_compat_link_reset_stats
+    - tipc: fix uninit-value in tipc_nl_compat_bearer_enable
+    - tipc: fix uninit-value in tipc_nl_compat_link_set
+    - tipc: fix uninit-value in tipc_nl_compat_name_table_dump
+    - tipc: fix uninit-value in tipc_nl_compat_doit
+    - block/loop: Use global lock for ioctl() operation.
+    - loop: Fold __loop_release into loop_release
+    - loop: Get rid of loop_index_mutex
+    - loop: Fix double mutex_unlock(&loop_ctl_mutex) in loop_control_ioctl()
+    - drm/fb-helper: Ignore the value of fb_var_screeninfo.pixclock
+    - media: vb2: be sure to unlock mutex on errors
+    - r8169: Add support for new Realtek Ethernet
+    - ipv6: Consider sk_bound_dev_if when binding a socket to a v4 mapped address
+    - ipv6: Take rcu_read_lock in __inet6_bind for mapped addresses
+    - platform/x86: asus-wmi: Tell the EC the OS will handle the display off
+      hotkey
+    - e1000e: allow non-monotonic SYSTIM readings
+    - writeback: don't decrement wb->refcnt if !wb->bdi
+    - MIPS: SiByte: Enable swiotlb for SWARM, LittleSur and BigSur
+    - arm64: perf: set suppress_bind_attrs flag to true
+    - jffs2: Fix use of uninitialized delayed_work, lockdep breakage
+    - pstore/ram: Do not treat empty buffers as valid
+    - powerpc/pseries/cpuidle: Fix preempt warning
+    - media: firewire: Fix app_info parameter type in avc_ca{,_app}_info
+    - net: call sk_dst_reset when set SO_DONTROUTE
+    - scsi: target: use consistent left-aligned ASCII INQUIRY data
+    - clk: imx6q: reset exclusive gates on init
+    - kconfig: fix file name and line number of warn_ignored_character()
+    - kconfig: fix memory leak when EOF is encountered in quotation
+    - mmc: atmel-mci: do not assume idle after atmci_request_end
+    - perf intel-pt: Fix error with config term "pt=0"
+    - perf svghelper: Fix unchecked usage of strncpy()
+    - perf parse-events: Fix unchecked usage of strncpy()
+    - dm kcopyd: Fix bug causing workqueue stalls
+    - dm snapshot: Fix excessive memory usage and workqueue stalls
+    - ALSA: bebob: fix model-id of unit for Apogee Ensemble
+    - sysfs: Disable lockdep for driver bind/unbind files
+    - scsi: megaraid: fix out-of-bound array accesses
+    - ocfs2: fix panic due to unrecovered local alloc
+    - mm/page-writeback.c: don't break integrity writeback on ->writepage() error
+    - mm, proc: be more verbose about unstable VMA flags in /proc/<pid>/smaps
+    - net: speed up skb_rbtree_purge()
+    - ipmi:ssif: Fix handling of multi-part return messages
+    - Linux 4.4.172
+
+  * Xenial update: 4.4.171 upstream stable release (LP: #1818237)
+    - ALSA: hda/realtek - Disable headset Mic VREF for headset mode of ALC225
+    - btrfs: cleanup, stop casting for extent_map->lookup everywhere
+    - btrfs: Enhance chunk validation check
+    - Btrfs: add validadtion checks for chunk loading
+    - Btrfs: check inconsistence between chunk and block group
+    - Btrfs: fix em leak in find_first_block_group
+    - Btrfs: detect corruption when non-root leaf has zero item
+    - Btrfs: check btree node's nritems
+    - Btrfs: fix BUG_ON in btrfs_mark_buffer_dirty
+    - Btrfs: memset to avoid stale content in btree node block
+    - Btrfs: improve check_node to avoid reading corrupted nodes
+    - Btrfs: kill BUG_ON in run_delayed_tree_ref
+    - Btrfs: memset to avoid stale content in btree leaf
+    - Btrfs: fix emptiness check for dirtied extent buffers at check_leaf()
+    - btrfs: struct-funcs, constify readers
+    - btrfs: Refactor check_leaf function for later expansion
+    - btrfs: Check if item pointer overlaps with the item itself
+    - btrfs: Add sanity check for EXTENT_DATA when reading out leaf
+    - btrfs: Add checker for EXTENT_CSUM
+    - btrfs: Move leaf and node validation checker to tree-checker.c
+    - btrfs: tree-checker: Enhance btrfs_check_node output
+    - btrfs: tree-checker: Fix false panic for sanity test
+    - btrfs: tree-checker: Add checker for dir item
+    - btrfs: tree-checker: use %zu format string for size_t
+    - btrfs: tree-check: reduce stack consumption in check_dir_item
+    - btrfs: tree-checker: Verify block_group_item
+    - btrfs: tree-checker: Detect invalid and empty essential trees
+    - btrfs: validate type when reading a chunk
+    - btrfs: Check that each block group has corresponding chunk at mount time
+    - btrfs: Verify that every chunk has corresponding block group at mount time
+    - btrfs: tree-checker: Check level for leaves and nodes
+    - btrfs: tree-checker: Fix misleading group system information
+    - CIFS: Do not hide EINTR after sending network packets
+    - cifs: Fix potential OOB access of lock element array
+    - usb: cdc-acm: send ZLP for Telit 3G Intel based modems
+    - USB: storage: don't insert sane sense for SPC3+ when bad sense specified
+    - USB: storage: add quirk for SMI SM3350
+    - USB: Add USB_QUIRK_DELAY_CTRL_MSG quirk for Corsair K70 RGB
+    - slab: alien caches must not be initialized if the allocation of the alien
+      cache failed
+    - PCI: altera: Fix altera_pcie_link_is_up()
+    - PCI: altera: Reorder read/write functions
+    - PCI: altera: Check link status before retrain link
+    - PCI: altera: Poll for link up status after retraining the link
+    - PCI: altera: Poll for link training status after retraining the link
+    - PCI: altera: Rework config accessors for use without a struct pci_bus
+    - PCI: altera: Move retrain from fixup to altera_pcie_host_init()
+    - ACPI: power: Skip duplicate power resource references in _PRx
+    - i2c: dev: prevent adapter retries and timeout being set as minus value
+    - crypto: cts - fix crash on short inputs
+    - ext4: fix a potential fiemap/page fault deadlock w/ inline_data
+    - sunrpc: use-after-free in svc_process_common()
+    - Linux 4.4.171
+
+  * [Packaging] Allow overlay of config annotations (LP: #1752072)
+    - [Packaging] config-check: Add an include directive
+
+  * CVE-2018-9517
+    - l2tp: pass tunnel pointer to ->session_create()
+
+  * squashfs hardening (LP: #1816756)
+    - squashfs metadata 2: electric boogaloo
+    - Squashfs: Compute expected length from inode size rather than block length
+
+  * Update ENA driver to version 2.0.3K (LP: #1816806)
+    - net: ena: update driver version from 2.0.2 to 2.0.3
+    - net: ena: fix race between link up and device initalization
+    - net: ena: fix crash during failed resume from hibernation
+
+  * bnxt_en_po: TX timed out triggering Netdev Watchdog Timer (LP: #1814095)
+    - SAUCE: bnxt_en_bpo: Fix TX timeout during netpoll
+
+  * CVE-2019-3459
+    - Bluetooth: Verify that l2cap_get_conf_opt provides large enough buffer
+
+  * CVE-2019-7222
+    - KVM: x86: work around leak of uninitialized stack contents (CVE-2019-7222)
+
+  * CVE-2019-7221
+    - KVM: nVMX: unconditionally cancel preemption timer in free_nested
+      (CVE-2019-7221)
+
+  * CVE-2019-6974
+    - kvm: fix kvm_ioctl_create_device() reference counting (CVE-2019-6974)
+
+  * Regular D-state processes impacting LXD containers (LP: #1817628)
+    - mm: do not stall register_shrinker()
+
+  * libsas disks can have non-unique by-path names (LP: #1817784)
+    - scsi: libsas: Fix rphy phy_identifier for PHYs with end devices attached
+
+  * Hard lockups due to unrestricted lapic timer delay (LP: #1817918)
+    - KVM: x86: move nsec_to_cycles from x86.c to x86.h
+    - KVM: LAPIC: cap __delay at lapic_timer_advance_ns
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 14 Mar 2019 10:01:49 +0100
+
+linux (4.4.0-143.169) xenial; urgency=medium
+
+  * linux: 4.4.0-143.169 -proposed tracker (LP: #1814647)
+
+  * x86/kvm: Backport fixup and missing commits (LP: #1811646)
+    - KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID
+    - kvm: nVMX: VMCLEAR an active shadow VMCS after last use
+    - X86/nVMX: Properly set spec_ctrl and pred_cmd before merging MSRs
+    - KVM/VMX: Optimize vmx_vcpu_run() and svm_vcpu_run() by marking the RDMSR
+      path as unlikely()
+    - kvm: x86: IA32_ARCH_CAPABILITIES is always supported
+    - KVM: SVM: Add MSR-based feature support for serializing LFENCE
+    - KVM: X86: Allow userspace to define the microcode version
+    - KVM: x86: SVM: Call x86_spec_ctrl_set_guest/host() with interrupts disabled
+    - KVM: VMX: fixes for vmentry_l1d_flush module parameter
+    - kvm: svm: Ensure an IBPB on all affected CPUs when freeing a vmcb
+    - kvm: vmx: Scrub hardware GPRs at VM-exit
+    - SAUCE: [Fix] x86/KVM/VMX: Add L1D flush logic
+    - SAUCE: KVM: Move code fragments, cleanup and re-indent
+
+  * linux-buildinfo: pull out ABI information into its own package
+    (LP: #1806380)
+    - [Packaging] limit preparation to linux-libc-dev in headers
+    - [Packaging] commonise debhelper invocation
+    - [Packaging] ABI -- accumulate abi information at the end of the build
+    - [Packaging] buildinfo -- add basic build information
+    - [Packaging] buildinfo -- add firmware information to the flavour ABI
+    - [Packaging] buildinfo -- add compiler information to the flavour ABI
+    - [Packaging] buildinfo -- add buildinfo support to getabis
+    - [Config] buildinfo -- add retpoline version markers
+    - [Packaging] getabis -- handle all known package combinations
+    - [Packaging] getabis -- support parsing a simple version
+
+  * signing: only install a signed kernel (LP: #1764794)
+    - [Packaging] update to Debian like control scripts
+    - [Packaging] switch to triggers for postinst.d postrm.d handling
+    - [Packaging] signing -- switch to raw-signing tarballs
+    - [Packaging] signing -- switch to linux-image as signed when available
+    - [Packaging] printenv -- add signing options
+    - [Packaging] fix invocation of header postinst hooks
+    - [Packaging] signing -- add support for signing Opal kernel binaries
+    - [Debian] Use src_pkg_name when constructing udeb control files
+    - [Debian] Dynamically determine linux udebs package name
+    - [Packaging] handle both linux-lts* and linux-hwe* as backports
+    - [Config] linux-source-* is in the primary linux namespace
+    - [Packaging] lookup the upstream tag
+    - [Packaging] zfs/spl -- enhance provides information
+    - [Packaging] switch up to debhelper 9
+    - [Packaging] autopkgtest -- disable d-i when dropping flavours
+    - [debian] support for ship_extras_package=false
+    - [Debian] do_common_tools should always be on
+    - [debian] do not force do_tools_common
+    - [Packaging] Add linux-tools-host package for VM host tools
+    - [Packaging] signing should be conditional
+    - [Packaging] skip cloud tools packaging when not building package
+    - [Packaging] add acpidbg
+    - [debian] prep linux-libc-dev only if do_libc_dev_package=true
+    - [Packaging] Only install cloud init files when do_tools_common=true
+
+  * Redpine: Driver crash with network-manager 1.10 and above (LP: #1813869)
+    - SAUCE: Redpine: enhancement for MAC spoofing to avoid kernel crash
+
+  * Guests using IBRS incur a large performance penalty (LP: #1764956)
+    - SAUCE: Restore the IBRS host state on VMEXIT
+
+  * Xenial update: 4.4.170 upstream stable release (LP: #1811647)
+    - USB: hso: Fix OOB memory access in hso_probe/hso_get_config_data
+    - xhci: Don't prevent USB2 bus suspend in state check intended for USB3 only
+    - USB: serial: option: add GosunCn ZTE WeLink ME3630
+    - USB: serial: option: add HP lt4132
+    - USB: serial: option: add Simcom SIM7500/SIM7600 (MBIM mode)
+    - USB: serial: option: add Fibocom NL668 series
+    - USB: serial: option: add Telit LN940 series
+    - mmc: core: Reset HPI enabled state during re-init and in case of errors
+    - mmc: omap_hsmmc: fix DMA API warning
+    - gpio: max7301: fix driver for use with CONFIG_VMAP_STACK
+    - Drivers: hv: vmbus: Return -EINVAL for the sys files for unopened channels
+    - x86/mtrr: Don't copy uninitialized gentry fields back to userspace
+    - drm/ioctl: Fix Spectre v1 vulnerabilities
+    - ip6mr: Fix potential Spectre v1 vulnerability
+    - ipv4: Fix potential Spectre v1 vulnerability
+    - ax25: fix a use-after-free in ax25_fillin_cb()
+    - ibmveth: fix DMA unmap error in ibmveth_xmit_start error path
+    - ieee802154: lowpan_header_create check must check daddr
+    - ipv6: explicitly initialize udp6_addr in udp_sock_create6()
+    - isdn: fix kernel-infoleak in capi_unlocked_ioctl
+    - netrom: fix locking in nr_find_socket()
+    - packet: validate address length
+    - packet: validate address length if non-zero
+    - sctp: initialize sin6_flowinfo for ipv6 addrs in sctp_inet6addr_event
+    - vhost: make sure used idx is seen before log in vhost_add_used_n()
+    - VSOCK: Send reset control packet when socket is partially bound
+    - xen/netfront: tolerate frags with no data
+    - gro_cell: add napi_disable in gro_cells_destroy
+    - sock: Make sock->sk_stamp thread-safe
+    - ALSA: rme9652: Fix potential Spectre v1 vulnerability
+    - ALSA: emu10k1: Fix potential Spectre v1 vulnerabilities
+    - ALSA: pcm: Fix potential Spectre v1 vulnerability
+    - ALSA: emux: Fix potential Spectre v1 vulnerabilities
+    - ALSA: hda: add mute LED support for HP EliteBook 840 G4
+    - ALSA: hda/tegra: clear pending irq handlers
+    - USB: serial: pl2303: add ids for Hewlett-Packard HP POS pole displays
+    - USB: serial: option: add Fibocom NL678 series
+    - usb: r8a66597: Fix a possible concurrency use-after-free bug in
+      r8a66597_endpoint_disable()
+    - Input: elan_i2c - add ACPI ID for touchpad in ASUS Aspire F5-573G
+    - KVM: x86: Use jmp to invoke kvm_spurious_fault() from .fixup
+    - perf pmu: Suppress potential format-truncation warning
+    - ext4: fix possible use after free in ext4_quota_enable
+    - ext4: missing unlock/put_page() in ext4_try_to_write_inline_data()
+    - ext4: fix EXT4_IOC_GROUP_ADD ioctl
+    - ext4: force inode writes when nfsd calls commit_metadata()
+    - spi: bcm2835: Fix race on DMA termination
+    - spi: bcm2835: Fix book-keeping of DMA termination
+    - spi: bcm2835: Avoid finishing transfer prematurely in IRQ mode
+    - cdc-acm: fix abnormal DATA RX issue for Mediatek Preloader.
+    - media: vivid: free bitmap_cap when updating std/timings/etc.
+    - MIPS: Ensure pmd_present() returns false after pmd_mknotpresent()
+    - MIPS: Align kernel load address to 64KB
+    - CIFS: Fix error mapping for SMB2_LOCK command which caused OFD lock problem
+    - x86/kvm/vmx: do not use vm-exit instruction length for fast MMIO when
+      running nested
+    - spi: bcm2835: Unbreak the build of esoteric configs
+    - powerpc: Fix COFF zImage booting on old powermacs
+    - ARM: imx: update the cpu power up timing setting on i.mx6sx
+    - Input: restore EV_ABS ABS_RESERVED
+    - checkstack.pl: fix for aarch64
+    - xfrm: Fix bucket count reported to userspace
+    - scsi: bnx2fc: Fix NULL dereference in error handling
+    - Input: omap-keypad - fix idle configuration to not block SoC idle states
+    - scsi: zfcp: fix posting too many status read buffers leading to adapter
+      shutdown
+    - hwpoison, memory_hotplug: allow hwpoisoned pages to be offlined
+    - mm, devm_memremap_pages: mark devm_memremap_pages() EXPORT_SYMBOL_GPL
+    - mm, devm_memremap_pages: kill mapping "System RAM" support
+    - sunrpc: fix cache_head leak due to queued request
+    - sunrpc: use SVC_NET() in svcauth_gss_* functions
+    - crypto: x86/chacha20 - avoid sleeping with preemption disabled
+    - ALSA: cs46xx: Potential NULL dereference in probe
+    - ALSA: usb-audio: Avoid access before bLength check in build_audio_procunit()
+    - ALSA: usb-audio: Fix an out-of-bound read in create_composite_quirks
+    - dlm: fixed memory leaks after failed ls_remove_names allocation
+    - dlm: possible memory leak on error path in create_lkb()
+    - dlm: lost put_lkb on error path in receive_convert() and receive_unlock()
+    - dlm: memory leaks on error path in dlm_user_request()
+    - gfs2: Fix loop in gfs2_rbm_find
+    - b43: Fix error in cordic routine
+    - 9p/net: put a lower bound on msize
+    - iommu/vt-d: Handle domain agaw being less than iommu agaw
+    - ceph: don't update importing cap's mseq when handing cap export
+    - genwqe: Fix size check
+    - intel_th: msu: Fix an off-by-one in attribute store
+    - power: supply: olpc_battery: correct the temperature units
+    - Linux 4.4.170
+
+  * Xenial update: 4.4.169 upstream stable release (LP: #1811252)
+    - lib/interval_tree_test.c: make test options module parameters
+    - lib/interval_tree_test.c: allow full tree search
+    - lib/rbtree_test.c: make input module parameters
+    - lib/rbtree-test: lower default params
+    - lib/interval_tree_test.c: allow users to limit scope of endpoint
+    - timer/debug: Change /proc/timer_list from 0444 to 0400
+    - powerpc/boot: Fix random libfdt related build errors
+    - pinctrl: sunxi: a83t: Fix IRQ offset typo for PH11
+    - aio: fix spectre gadget in lookup_ioctx
+    - MMC: OMAP: fix broken MMC on OMAP15XX/OMAP5910/OMAP310
+    - tracing: Fix memory leak in set_trigger_filter()
+    - tracing: Fix memory leak of instance function hash filters
+    - powerpc/msi: Fix NULL pointer access in teardown code
+    - Revert "drm/rockchip: Allow driver to be shutdown on reboot/kexec"
+    - f2fs: fix a panic caused by NULL flush_cmd_control
+    - mac80211: don't WARN on bad WMM parameters from buggy APs
+    - mac80211: Fix condition validating WMM IE
+    - mac80211_hwsim: fix module init error paths for netlink
+    - scsi: libiscsi: Fix NULL pointer dereference in iscsi_eh_session_reset
+    - scsi: vmw_pscsi: Rearrange code to avoid multiple calls to free_irq during
+      unload
+    - x86/earlyprintk/efi: Fix infinite loop on some screen widths
+    - drm/msm: Grab a vblank reference when waiting for commit_done
+    - ARC: io.h: Implement reads{x}()/writes{x}()
+    - bonding: fix 802.3ad state sent to partner when unbinding slave
+    - SUNRPC: Fix a potential race in xprt_connect()
+    - sbus: char: add of_node_put()
+    - drivers/sbus/char: add of_node_put()
+    - drivers/tty: add missing of_node_put()
+    - ide: pmac: add of_node_put()
+    - clk: mmp: Off by one in mmp_clk_add()
+    - Input: omap-keypad - fix keyboard debounce configuration
+    - libata: whitelist all SAMSUNG MZ7KM* solid-state disks
+    - mv88e6060: disable hardware level MAC learning
+    - ARM: 8814/1: mm: improve/fix ARM v7_dma_inv_range() unaligned address
+      handling
+    - cifs: In Kconfig CONFIG_CIFS_POSIX needs depends on legacy (insecure cifs)
+    - [Config] Remove CONFIG_CIFS_POSIX=y
+    - i2c: axxia: properly handle master timeout
+    - i2c: scmi: Fix probe error on devices with an empty SMB0001 ACPI device node
+    - rtc: snvs: add a missing write sync
+    - rtc: snvs: Add timeouts to avoid kernel lockups
+    - ALSA: isa/wavefront: prevent some out of bound writes
+    - Linux 4.4.169
+
+  * Xenial update: 4.4.168 upstream stable release (LP: #1811080)
+    - ipv6: Check available headroom in ip6_xmit() even without options
+    - net: 8139cp: fix a BUG triggered by changing mtu with network traffic
+    - net: phy: don't allow __set_phy_supported to add unsupported modes
+    - net: Prevent invalid access to skb->prev in __qdisc_drop_all
+    - rtnetlink: ndo_dflt_fdb_dump() only work for ARPHRD_ETHER devices
+    - tcp: fix NULL ref in tail loss probe
+    - tun: forbid iface creation with rtnl ops
+    - neighbour: Avoid writing before skb->head in neigh_hh_output()
+    - ARM: OMAP2+: prm44xx: Fix section annotation on
+      omap44xx_prm_enable_io_wakeup
+    - ARM: OMAP1: ams-delta: Fix possible use of uninitialized field
+    - sysv: return 'err' instead of 0 in __sysv_write_inode
+    - s390/cpum_cf: Reject request for sampling in event initialization
+    - hwmon: (ina2xx) Fix current value calculation
+    - ASoC: dapm: Recalculate audio map forcely when card instantiated
+    - hwmon: (w83795) temp4_type has writable permission
+    - Btrfs: send, fix infinite loop due to directory rename dependencies
+    - ASoC: omap-mcpdm: Add pm_qos handling to avoid under/overruns with CPU_IDLE
+    - ASoC: omap-dmic: Add pm_qos handling to avoid overruns with CPU_IDLE
+    - exportfs: do not read dentry after free
+    - bpf: fix check of allowed specifiers in bpf_trace_printk
+    - USB: omap_udc: use devm_request_irq()
+    - USB: omap_udc: fix crashes on probe error and module removal
+    - USB: omap_udc: fix omap_udc_start() on 15xx machines
+    - USB: omap_udc: fix USB gadget functionality on Palm Tungsten E
+    - KVM: x86: fix empty-body warnings
+    - net: thunderx: fix NULL pointer dereference in nic_remove
+    - ixgbe: recognize 1000BaseLX SFP modules as 1Gbps
+    - net: hisilicon: remove unexpected free_netdev
+    - drm/ast: fixed reading monitor EDID not stable issue
+    - xen: xlate_mmu: add missing header to fix 'W=1' warning
+    - fscache: fix race between enablement and dropping of object
+    - fscache, cachefiles: remove redundant variable 'cache'
+    - ocfs2: fix deadlock caused by ocfs2_defrag_extent()
+    - hfs: do not free node before using
+    - hfsplus: do not free node before using
+    - debugobjects: avoid recursive calls with kmemleak
+    - ocfs2: fix potential use after free
+    - pstore: Convert console write to use ->write_buf
+    - ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO internal command
+    - KVM: nVMX: fix msr bitmaps to prevent L2 from accessing L0 x2APIC
+    - KVM: nVMX: mark vmcs12 pages dirty on L2 exit
+    - KVM: nVMX: Eliminate vmcs02 pool
+    - KVM: VMX: introduce alloc_loaded_vmcs
+    - KVM: VMX: make MSR bitmaps per-VCPU
+    - KVM/x86: Add IBPB support
+    - KVM/VMX: Allow direct access to MSR_IA32_SPEC_CTRL
+    - KVM/SVM: Allow direct access to MSR_IA32_SPEC_CTRL
+    - KVM/x86: Remove indirect MSR op calls from SPEC_CTRL
+    - x86/uaccess: Use __uaccess_begin_nospec() and uaccess_try_nospec
+    - KVM: SVM: Implement VIRT_SPEC_CTRL support for SSBD
+    - bpf: support 8-byte metafield access
+    - bpf/verifier: Add spi variable to check_stack_write()
+    - bpf/verifier: Pass instruction index to check_mem_access() and check_xadd()
+    - bpf: Prevent memory disambiguation attack
+    - wil6210: missing length check in wmi_set_ie
+    - mm/hugetlb.c: don't call region_abort if region_chg fails
+    - hugetlbfs: fix offset overflow in hugetlbfs mmap
+    - hugetlbfs: check for pgoff value overflow
+    - hugetlbfs: fix bug in pgoff overflow checking
+    - swiotlb: clean up reporting
+    - sr: pass down correctly sized SCSI sense buffer
+    - mm: remove write/force parameters from __get_user_pages_locked()
+    - mm: remove write/force parameters from __get_user_pages_unlocked()
+    - mm/nommu.c: Switch __get_user_pages_unlocked() to use __get_user_pages()
+    - mm: replace get_user_pages_unlocked() write/force parameters with gup_flags
+    - mm: replace get_user_pages_locked() write/force parameters with gup_flags
+    - mm: replace get_vaddr_frames() write/force parameters with gup_flags
+    - mm: replace get_user_pages() write/force parameters with gup_flags
+    - mm: replace __access_remote_vm() write parameter with gup_flags
+    - mm: replace access_remote_vm() write parameter with gup_flags
+    - proc: don't use FOLL_FORCE for reading cmdline and environment
+    - proc: do not access cmdline nor environ from file-backed areas
+    - media: dvb-frontends: fix i2c access helpers for KASAN
+    - matroxfb: fix size of memcpy
+    - staging: speakup: Replace strncpy with memcpy
+    - rocker: fix rocker_tlv_put_* functions for KASAN
+    - selftests: Move networking/timestamping from Documentation
+    - Linux 4.4.168
+
+  * kernel oops in bcache module (LP: #1793901)
+    - SAUCE: bcache: never writeback a discard operation
+
+  * Userspace break as a result of missing patch backport (LP: #1813873)
+    - tty: Don't hold ldisc lock in tty_reopen() if ldisc present
+
+  * CVE-2019-6133
+    - fork: record start_time late
+
+  * Crash on "ip link add foo type ipip" (LP: #1811803)
+    - SAUCE: fan: Fix NULL pointer dereference
+
+ -- Juerg Haefliger <juergh@canonical.com>  Wed, 06 Feb 2019 10:39:59 +0000
+
+linux (4.4.0-142.168) xenial; urgency=medium
+
+  * linux: 4.4.0-142.168 -proposed tracker (LP: #1811846)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * iptables connlimit allows more connections than the limit when using
+    multiple CPUs (LP: #1811094)
+    - netfilter: xt_connlimit: don't store address in the conn nodes
+    - SAUCE: netfilter: xt_connlimit: remove the 'addr' parameter in add_hlist()
+    - netfilter: nf_conncount: expose connection list interface
+    - netfilter: nf_conncount: Fix garbage collection with zones
+    - netfilter: nf_conncount: fix garbage collection confirm race
+    - netfilter: nf_conncount: don't skip eviction when age is negative
+
+  * CVE-2017-5715
+    - SAUCE: x86/speculation: Cleanup IBPB runtime control handling
+    - SAUCE: x86/speculation: Cleanup IBRS runtime control handling
+    - SAUCE: x86/speculation: Use x86_spec_ctrl_base in entry/exit code
+    - SAUCE: x86/speculation: Move RSB_CTXSW hunk
+
+  * Xenial update: 4.4.167 upstream stable release (LP: #1811077)
+    - media: em28xx: Fix use-after-free when disconnecting
+    - Revert "wlcore: Add missing PM call for
+      wlcore_cmd_wait_for_event_or_timeout()"
+    - rapidio/rionet: do not free skb before reading its length
+    - s390/qeth: fix length check in SNMP processing
+    - usbnet: ipheth: fix potential recvmsg bug and recvmsg bug 2
+    - kvm: mmu: Fix race in emulated page table writes
+    - xtensa: enable coprocessors that are being flushed
+    - xtensa: fix coprocessor context offset definitions
+    - Btrfs: ensure path name is null terminated at btrfs_control_ioctl
+    - ALSA: wss: Fix invalid snd_free_pages() at error path
+    - ALSA: ac97: Fix incorrect bit shift at AC97-SPSA control write
+    - ALSA: control: Fix race between adding and removing a user element
+    - ALSA: sparc: Fix invalid snd_free_pages() at error path
+    - ext2: fix potential use after free
+    - dmaengine: at_hdmac: fix memory leak in at_dma_xlate()
+    - dmaengine: at_hdmac: fix module unloading
+    - btrfs: release metadata before running delayed refs
+    - USB: usb-storage: Add new IDs to ums-realtek
+    - usb: core: quirks: add RESET_RESUME quirk for Cherry G230 Stream series
+    - misc: mic/scif: fix copy-paste error in scif_create_remote_lookup
+    - Kbuild: suppress packed-not-aligned warning for default setting only
+    - exec: avoid gcc-8 warning for get_task_comm
+    - disable stringop truncation warnings for now
+    - kobject: Replace strncpy with memcpy
+    - unifdef: use memcpy instead of strncpy
+    - kernfs: Replace strncpy with memcpy
+    - ip_tunnel: Fix name string concatenate in __ip_tunnel_create()
+    - drm: gma500: fix logic error
+    - scsi: bfa: convert to strlcpy/strlcat
+    - staging: rts5208: fix gcc-8 logic error warning
+    - kdb: use memmove instead of overlapping memcpy
+    - iser: set sector for ambiguous mr status errors
+    - uprobes: Fix handle_swbp() vs. unregister() + register() race once more
+    - MIPS: ralink: Fix mt7620 nd_sd pinmux
+    - mips: fix mips_get_syscall_arg o32 check
+    - drm/ast: Fix incorrect free on ioregs
+    - scsi: scsi_devinfo: cleanly zero-pad devinfo strings
+    - ALSA: trident: Suppress gcc string warning
+    - scsi: csiostor: Avoid content leaks and casts
+    - kgdboc: Fix restrict error
+    - kgdboc: Fix warning with module build
+    - leds: call led_pwm_set() in leds-pwm to enforce default LED_OFF
+    - leds: turn off the LED and wait for completion on unregistering LED class
+      device
+    - leds: leds-gpio: Fix return value check in create_gpio_led()
+    - Input: xpad - quirk all PDP Xbox One gamepads
+    - Input: matrix_keypad - check for errors from of_get_named_gpio()
+    - Input: elan_i2c - add ELAN0620 to the ACPI table
+    - Input: elan_i2c - add ACPI ID for Lenovo IdeaPad 330-15ARR
+    - Input: elan_i2c - add support for ELAN0621 touchpad
+    - btrfs: Always try all copies when reading extent buffers
+    - Btrfs: fix use-after-free when dumping free space
+    - ARC: change defconfig defaults to ARCv2
+    - arc: [devboards] Add support of NFSv3 ACL
+    - mm: cleancache: fix corruption on missed inode invalidation
+    - usb: gadget: dummy: fix nonsensical comparisons
+    - iommu/vt-d: Fix NULL pointer dereference in prq_event_thread()
+    - iommu/ipmmu-vmsa: Fix crash on early domain free
+    - can: rcar_can: Fix erroneous registration
+    - batman-adv: Expand merged fragment buffer for full packet
+    - bnx2x: Assign unique DMAE channel number for FW DMAE transactions.
+    - qed: Fix PTT leak in qed_drain()
+    - qed: Fix reading wrong value in loop condition
+    - net/mlx4_core: Zero out lkey field in SW2HW_MPT fw command
+    - net/mlx4_core: Fix uninitialized variable compilation warning
+    - net/mlx4: Fix UBSAN warning of signed integer overflow
+    - net: faraday: ftmac100: remove netif_running(netdev) check before disabling
+      interrupts
+    - iommu/vt-d: Use memunmap to free memremap
+    - net: amd: add missing of_node_put()
+    - usb: quirk: add no-LPM quirk on SanDisk Ultra Flair device
+    - usb: appledisplay: Add 27" Apple Cinema Display
+    - USB: check usb_get_extra_descriptor for proper size
+    - ALSA: usb-audio: Fix UAF decrement if card has no live interfaces in card.c
+    - ALSA: hda: Add support for AMD Stoney Ridge
+    - ALSA: pcm: Fix starvation on down_write_nonblock()
+    - ALSA: pcm: Call snd_pcm_unlink() conditionally at closing
+    - ALSA: pcm: Fix interval evaluation with openmin/max
+    - virtio/s390: avoid race on vcdev->config
+    - virtio/s390: fix race in ccw_io_helper()
+    - SUNRPC: Fix leak of krb5p encode pages
+    - xhci: Prevent U1/U2 link pm states if exit latency is too long
+    - Staging: lustre: remove two build warnings
+    - cifs: Fix separator when building path from dentry
+    - tty: serial: 8250_mtk: always resume the device in probe.
+    - kgdboc: fix KASAN global-out-of-bounds bug in param_set_kgdboc_var()
+    - mac80211_hwsim: Timer should be initialized before device registered
+    - mac80211: Clear beacon_int in ieee80211_do_stop
+    - mac80211: ignore tx status for PS stations in ieee80211_tx_status_ext
+    - mac80211: fix reordering of buffered broadcast packets
+    - mac80211: ignore NullFunc frames in the duplicate detection
+    - Linux 4.4.167
+
+  * CVE-2018-19407
+    - KVM: X86: Fix scan ioapic use-before-initialization
+
+  * cpu-hotplug test in ubuntu_kernel_selftest always return 0 on Xenial
+    (LP: #1809699)
+    - selftests/cpu-hotplug: exit with failure when test occured unexpected
+      behaviors
+
+  * iommu - need to effectively disable iommu if "intel_iommu=off" is passed as
+    a kernel parameter (LP: #1810328)
+    - iommu/vt-d: Make sure IOMMUs are off when intel_iommu=off
+
+  * ldisc crash on reopened tty (LP: #1791758)
+    - tty: fix data race between tty_init_dev and flush of buf
+    - tty: Drop tty->count on tty_reopen() failure
+    - tty: Hold tty_ldisc_lock() during tty_reopen()
+    - tty: Don't block on IO when ldisc change is pending
+    - tty: Simplify tty->count math in tty_reopen()
+
+  * Xenial update: 4.4.166 upstream stable release (LP: #1810967)
+    - usb: core: Fix hub port connection events lost
+    - usb: xhci: fix timeout for transition from RExit to U0
+    - MAINTAINERS: Add Sasha as a stable branch maintainer
+    - iwlwifi: mvm: support sta_statistics() even on older firmware
+    - v9fs_dir_readdir: fix double-free on p9stat_read error
+    - bfs: add sanity check at bfs_fill_super()
+    - sctp: clear the transport of some out_chunk_list chunks in
+      sctp_assoc_rm_peer
+    - gfs2: Don't leave s_fs_info pointing to freed memory in init_sbd
+    - llc: do not use sk_eat_skb()
+    - drm/ast: change resolution may cause screen blurred
+    - drm/ast: fixed cursor may disappear sometimes
+    - can: dev: can_get_echo_skb(): factor out non sending code to
+      __can_get_echo_skb()
+    - can: dev: __can_get_echo_skb(): replace struct can_frame by canfd_frame to
+      access frame length
+    - can: dev: __can_get_echo_skb(): Don't crash the kernel if can_priv::echo_skb
+      is accessed out of bounds
+    - can: dev: __can_get_echo_skb(): print error message, if trying to echo non
+      existing skb
+    - usb: xhci: Prevent bus suspend if a port connect change or polling state is
+      detected
+    - KVM: PPC: Move and undef TRACE_INCLUDE_PATH/FILE
+    - cpufreq: imx6q: add return value check for voltage scale
+    - SUNRPC: Fix a bogus get/put in generic_key_to_expire()
+    - kdb: Use strscpy with destination buffer size
+    - powerpc/numa: Suppress "VPHN is not supported" messages
+    - tmpfs: make lseek(SEEK_DATA/SEK_HOLE) return ENXIO with a negative offset
+    - of: add helper to lookup compatible child node
+    - NFC: nfcmrvl_uart: fix OF child-node lookup
+    - net: bcmgenet: fix OF child-node lookup
+    - x86/entry: spell EBX register correctly in documentation
+    - x86/entry/64: Remove %ebx handling from error_entry/exit
+    - arm64: remove no-op -p linker flag
+    - ath10k: fix kernel panic due to race in accessing arvif list
+    - Input: xpad - remove spurious events of wireless xpad 360 controller
+    - Input: xpad - handle "present" and "gone" correctly
+    - Input: xpad - update Xbox One Force Feedback Support
+    - Input: xpad - workaround dead irq_out after suspend/ resume
+    - Input: xpad - use LED API when identifying wireless controllers
+    - Input: xpad - correct xbox one pad device name
+    - Input: xpad - remove unused function
+    - Input: xpad - add Mad Catz FightStick TE 2 VID/PID
+    - Input: xpad - prevent spurious input from wired Xbox 360 controllers
+    - Input: xpad - add more third-party controllers
+    - Input: xpad - xbox one elite controller support
+    - Input: xpad - fix rumble on Xbox One controllers with 2015 firmware
+    - Input: xpad - power off wireless 360 controllers on suspend
+    - Input: xpad - add product ID for Xbox One S pad
+    - Input: xpad - fix Xbox One rumble stopping after 2.5 secs
+    - Input: xpad - correctly sort vendor id's
+    - Input: xpad - move reporting xbox one home button to common function
+    - Input: xpad - simplify error condition in init_output
+    - Input: xpad - don't depend on endpoint order
+    - Input: xpad - fix stuck mode button on Xbox One S pad
+    - Input: xpad - restore LED state after device resume
+    - Input: xpad - support some quirky Xbox One pads
+    - Input: xpad - sort supported devices by USB ID
+    - Input: xpad - sync supported devices with xboxdrv
+    - Input: xpad - add USB IDs for Mad Catz Brawlstick and Razer Sabertooth
+    - Input: xpad - sync supported devices with 360Controller
+    - Input: xpad - sync supported devices with XBCD
+    - Input: xpad - constify usb_device_id
+    - Input: xpad - fix PowerA init quirk for some gamepad models
+    - Input: xpad - validate USB endpoint type during probe
+    - Input: xpad - add support for PDP Xbox One controllers
+    - Input: xpad - add PDP device id 0x02a4
+    - Input: xpad - fix some coding style issues
+    - Input: xpad - avoid using __set_bit() for capabilities
+    - Input: xpad - add GPD Win 2 Controller USB IDs
+    - Input: xpad - fix GPD Win 2 controller name
+    - Input: xpad - add support for Xbox1 PDP Camo series gamepad
+    - cw1200: Don't leak memory if krealloc failes
+    - mwifiex: Fix NULL pointer dereference in skb_dequeue()
+    - mwifiex: fix p2p device doesn't find in scan problem
+    - netfilter: nf_tables: fix oops when inserting an element into a verdict map
+    - scsi: ufs: fix bugs related to null pointer access and array size
+    - scsi: ufshcd: Fix race between clk scaling and ungate work
+    - scsi: ufs: fix race between clock gating and devfreq scaling work
+    - scsi: ufshcd: release resources if probe fails
+    - scsi: qla2xxx: do not queue commands when unloading
+    - iwlwifi: mvm: fix regulatory domain update when the firmware starts
+    - tty: wipe buffer.
+    - tty: wipe buffer if not echoing data
+    - usb: xhci: fix uninitialized completion when USB3 port got wrong status
+    - btrfs: Ensure btrfs_trim_fs can trim the whole filesystem
+    - sched/core: Allow __sched_setscheduler() in interrupts when PI is not used
+    - s390/mm: Check for valid vma before zapping in gmap_discard
+    - drm/ast: Remove existing framebuffers before loading driver
+    - Linux 4.4.166
+
+  * Xenial update: 4.4.166 upstream stable release (LP: #1810967) //
+    CVE-2000-1134 // CVE-2007-3852 // CVE-2008-0525 // CVE-2009-0416 //
+    CVE-2011-4834 // CVE-2015-1838 // CVE-2015-7442 // CVE-2016-7489
+    - namei: allow restricted O_CREAT of FIFOs and regular files
+
+  * Xenial update: 4.4.165 upstream stable release (LP: #1810958)
+    - flow_dissector: do not dissect l4 ports for fragments
+    - ip_tunnel: don't force DF when MTU is locked
+    - net-gro: reset skb->pkt_type in napi_reuse_skb()
+    - tg3: Add PHY reset for 5717/5719/5720 in change ring and flow control paths
+    - ipv6: Fix PMTU updates for UDP/raw sockets in presence of VRF
+    - kbuild: Add better clang cross build support
+    - kbuild: clang: add -no-integrated-as to KBUILD_[AC]FLAGS
+    - kbuild: Consolidate header generation from ASM offset information
+    - kbuild: consolidate redundant sed script ASM offset generation
+    - kbuild: fix asm-offset generation to work with clang
+    - kbuild: drop -Wno-unknown-warning-option from clang options
+    - kbuild, LLVMLinux: Add -Werror to cc-option to support clang
+    - kbuild: use -Oz instead of -Os when using clang
+    - kbuild: Add support to generate LLVM assembly files
+    - modules: mark __inittest/__exittest as __maybe_unused
+    - kbuild: clang: Disable 'address-of-packed-member' warning
+    - crypto: arm64/sha - avoid non-standard inline asm tricks
+    - efi/libstub/arm64: Force 'hidden' visibility for section markers
+    - efi/libstub/arm64: Set -fpie when building the EFI stub
+    - kbuild: fix linker feature test macros when cross compiling with Clang
+    - kbuild: Set KBUILD_CFLAGS before incl. arch Makefile
+    - kbuild: move cc-option and cc-disable-warning after incl. arch Makefile
+    - kbuild: clang: fix build failures with sparse check
+    - kbuild: clang: remove crufty HOSTCFLAGS
+    - kbuild: clang: disable unused variable warnings only when constant
+    - kbuild: set no-integrated-as before incl. arch Makefile
+    - kbuild: allow to use GCC toolchain not in Clang search path
+    - arm64: Disable asm-operand-width warning for clang
+    - x86/kbuild: Use cc-option to enable -falign-{jumps/loops}
+    - crypto, x86: aesni - fix token pasting for clang
+    - x86/mm/kaslr: Use the _ASM_MUL macro for multiplication to work around Clang
+      incompatibility
+    - kbuild: Add __cc-option macro
+    - x86/build: Use __cc-option for boot code compiler options
+    - x86/build: Specify stack alignment for clang
+    - x86/boot: #undef memcpy() et al in string.c
+    - x86/build: Fix stack alignment for CLang
+    - x86/build: Use cc-option to validate stack alignment parameter
+    - reiserfs: propagate errors from fill_with_dentries() properly
+    - hfs: prevent btree data loss on root split
+    - hfsplus: prevent btree data loss on root split
+    - um: Give start_idle_thread() a return code
+    - fs/exofs: fix potential memory leak in mount option parsing
+    - clk: samsung: exynos5420: Enable PERIS clocks for suspend
+    - platform/x86: acerhdf: Add BIOS entry for Gateway LT31 v1.3307
+    - arm64: percpu: Initialize ret in the default case
+    - s390/vdso: add missing FORCE to build targets
+    - netfilter: ipset: actually allow allowable CIDR 0 in hash:net,port,net
+    - s390/mm: Fix ERROR: "__node_distance" undefined!
+    - netfilter: ipset: Correct rcu_dereference() call in ip_set_put_comment()
+    - netfilter: xt_IDLETIMER: add sysfs filename checking routine
+    - hwmon: (ibmpowernv) Remove bogus __init annotations
+    - lib/raid6: Fix arm64 test build
+    - zram: close udev startup race condition as default groups
+    - SUNRPC: drop pointless static qualifier in xdr_get_next_encode_buffer()
+    - gfs2: Put bitmap buffers in put_super
+    - btrfs: fix pinned underflow after transaction aborted
+    - Revert "media: videobuf2-core: don't call memop 'finish' when queueing"
+    - media: v4l: event: Add subscription to list before calling "add" operation
+    - uio: Fix an Oops on load
+    - usb: cdc-acm: add entry for Hiro (Conexant) modem
+    - USB: quirks: Add no-lpm quirk for Raydium touchscreens
+    - usb: quirks: Add delay-init quirk for Corsair K70 LUX RGB
+    - misc: atmel-ssc: Fix section annotation on atmel_ssc_get_driver_data
+    - USB: misc: appledisplay: add 20" Apple Cinema Display
+    - drivers/misc/sgi-gru: fix Spectre v1 vulnerability
+    - ACPI / platform: Add SMB0001 HID to forbidden_id_list
+    - new helper: uaccess_kernel()
+    - HID: uhid: forbid UHID_CREATE under KERNEL_DS or elevated privileges
+    - xhci: Fix USB3 NULL pointer dereference at logical disconnect.
+    - Linux 4.4.165
+
+  * Xenial update: 4.4.164 upstream stable release (LP: #1810947)
+    - bcache: fix miss key refill->end in writeback
+    - hwmon: (pmbus) Fix page count auto-detection.
+    - jffs2: free jffs2_sb_info through jffs2_kill_sb()
+    - pcmcia: Implement CLKRUN protocol disabling for Ricoh bridges
+    - ipmi: Fix timer race with module unload
+    - parisc: Fix address in HPMC IVA
+    - parisc: Fix map_pages() to not overwrite existing pte entries
+    - ALSA: hda - Add mic quirk for the Lenovo G50-30 (17aa:3905)
+    - ALSA: ca0106: Disable IZD on SB0570 DAC to fix audio pops
+    - x86/corruption-check: Fix panic in memory_corruption_check() when boot
+      option without value is provided
+    - x86/kconfig: Fall back to ticket spinlocks
+    - [Config] Remove CONFIG{,_ARCH_USE}_QUEUED_SPINLOCKS
+    - sparc: Fix single-pcr perf event counter management.
+    - x86/fpu: Remove second definition of fpu in __fpu__restore_sig()
+    - net: qla3xxx: Remove overflowing shift statement
+    - selftests: ftrace: Add synthetic event syntax testcase
+    - locking/lockdep: Fix debug_locks off performance problem
+    - ataflop: fix error handling during setup
+    - swim: fix cleanup on setup error
+    - tun: Consistently configure generic netdev params via rtnetlink
+    - perf tools: Free temporary 'sys' string in read_event_files()
+    - perf tools: Cleanup trace-event-info 'tdata' leak
+    - mmc: sdhci-pci-o2micro: Add quirk for O2 Micro dev 0x8620 rev 0x01
+    - Bluetooth: btbcm: Add entry for BCM4335C0 UART bluetooth
+    - x86: boot: Fix EFI stub alignment
+    - pinctrl: qcom: spmi-mpp: Fix err handling of pmic_mpp_set_mux
+    - kprobes: Return error if we fail to reuse kprobe instead of BUG_ON()
+    - ACPI / LPSS: Add alternative ACPI HIDs for Cherry Trail DMA controllers
+    - pinctrl: qcom: spmi-mpp: Fix drive strength setting
+    - pinctrl: spmi-mpp: Fix pmic_mpp_config_get() to be compliant
+    - pinctrl: ssbi-gpio: Fix pm8xxx_pin_config_get() to be compliant
+    - ath10k: schedule hardware restart if WMI command times out
+    - scsi: esp_scsi: Track residual for PIO transfers
+    - scsi: megaraid_sas: fix a missing-check bug
+    - tpm: suppress transmit cmd error logs when TPM 1.2 is disabled/deactivated
+    - ext4: fix argument checking in EXT4_IOC_MOVE_EXT
+    - MD: fix invalid stored role for a disk
+    - usb: chipidea: Prevent unbalanced IRQ disable
+    - driver/dma/ioat: Call del_timer_sync() without holding prep_lock
+    - uio: ensure class is registered before devices
+    - scsi: lpfc: Correct soft lockup when running mds diagnostics
+    - signal: Always deliver the kernel's SIGKILL and SIGSTOP to a pid namespace
+      init
+    - dmaengine: dma-jz4780: Return error if not probed from DT
+    - ALSA: hda: Check the non-cached stream buffers more explicitly
+    - xen-swiotlb: use actually allocated size on check physical continuous
+    - tpm: Restore functionality to xen vtpm driver.
+    - xen: fix race in xen_qlock_wait()
+    - xen: make xen_qlock_wait() nestable
+    - net/ipv4: defensive cipso option parsing
+    - libnvdimm: Hold reference on parent while scheduling async init
+    - jbd2: fix use after free in jbd2_log_do_checkpoint()
+    - gfs2_meta: ->mount() can get NULL dev_name
+    - ext4: initialize retries variable in ext4_da_write_inline_data_begin()
+    - HID: hiddev: fix potential Spectre v1
+    - PCI: Add Device IDs for Intel GPU "spurious interrupt" quirk
+    - signal/GenWQE: Fix sending of SIGKILL
+    - crypto: lrw - Fix out-of bounds access on counter overflow
+    - ima: fix showing large 'violations' or 'runtime_measurements_count'
+    - hugetlbfs: dirty pages as they are added to pagecache
+    - kbuild: fix kernel/bounds.c 'W=1' warning
+    - iio: adc: at91: fix acking DRDY irq on simple conversions
+    - iio: adc: at91: fix wrong channel number in triggered buffer mode
+    - w1: omap-hdq: fix missing bus unregister at removal
+    - smb3: allow stats which track session and share reconnects to be reset
+    - smb3: do not attempt cifs operation in smb3 query info error path
+    - smb3: on kerberos mount if server doesn't specify auth type use krb5
+    - printk: Fix panic caused by passing log_buf_len to command line
+    - genirq: Fix race on spurious interrupt detection
+    - NFSv4.1: Fix the r/wsize checking
+    - nfsd: Fix an Oops in free_session()
+    - lockd: fix access beyond unterminated strings in prints
+    - dm ioctl: harden copy_params()'s copy_from_user() from malicious users
+    - powerpc/msi: Fix compile error on mpc83xx
+    - MIPS: OCTEON: fix out of bounds array access on CN68XX
+    - TC: Set DMA masks for devices
+    - kgdboc: Passing ekgdboc to command line causes panic
+    - xen: fix xen_qlock_wait()
+    - media: em28xx: use a default format if TRY_FMT fails
+    - media: em28xx: fix input name for Terratec AV 350
+    - media: em28xx: make v4l2-compliance happier by starting sequence on zero
+    - ext4: avoid running out of journal credits when appending to an inline file
+    - Cramfs: fix abad comparison when wrap-arounds occur
+    - arm64: dts: stratix10: Correct System Manager register size
+    - soc/tegra: pmc: Fix child-node lookup
+    - btrfs: Handle owner mismatch gracefully when walking up tree
+    - btrfs: locking: Add extra check in btrfs_init_new_buffer() to avoid deadlock
+    - btrfs: iterate all devices during trim, instead of fs_devices::alloc_list
+    - btrfs: don't attempt to trim devices that don't support it
+    - btrfs: wait on caching when putting the bg cache
+    - btrfs: reset max_extent_size on clear in a bitmap
+    - btrfs: make sure we create all new block groups
+    - Btrfs: fix wrong dentries after fsync of file that got its parent replaced
+    - btrfs: qgroup: Dirty all qgroups before rescan
+    - Btrfs: fix null pointer dereference on compressed write path error
+    - btrfs: set max_extent_size properly
+    - MD: fix invalid stored role for a disk - try2
+    - tty: check name length in tty_find_polling_driver()
+    - powerpc/nohash: fix undefined behaviour when testing page size support
+    - drm/omap: fix memory barrier bug in DMM driver
+    - media: pci: cx23885: handle adding to list failure
+    - MIPS: kexec: Mark CPU offline before disabling local IRQ
+    - powerpc/boot: Ensure _zimage_start is a weak symbol
+    - sc16is7xx: Fix for multi-channel stall
+    - media: tvp5150: fix width alignment during set_selection()
+    - 9p locks: fix glock.client_id leak in do_lock
+    - 9p: clear dangling pointers in p9stat_free
+    - scsi: qla2xxx: Fix incorrect port speed being set for FC adapters
+    - fuse: Fix use-after-free in fuse_dev_do_read()
+    - fuse: Fix use-after-free in fuse_dev_do_write()
+    - fuse: fix blocked_waitq wakeup
+    - fuse: set FR_SENT while locked
+    - mm, elf: handle vm_brk error
+    - binfmt_elf: fix calculations for bss padding
+    - mm: refuse wrapped vm_brk requests
+    - fs, elf: make sure to page align bss in load_elf_library
+    - mm: do not bug_on on incorrect length in __mm_populate()
+    - e1000: avoid null pointer dereference on invalid stat type
+    - e1000: fix race condition between e1000_down() and e1000_watchdog
+    - bna: ethtool: Avoid reading past end of buffer
+    - MIPS: Loongson-3: Fix CPU UART irq delivery problem
+    - MIPS: Loongson-3: Fix BRIDGE irq delivery problem
+    - xtensa: add NOTES section to the linker script
+    - xtensa: make sure bFLT stack is 16 byte aligned
+    - xtensa: fix boot parameters address translation
+    - clk: s2mps11: Fix matching when built as module and DT node contains
+      compatible
+    - libceph: bump CEPH_MSG_MAX_DATA_LEN
+    - mach64: fix display corruption on big endian machines
+    - mach64: fix image corruption due to reading accelerator registers
+    - vhost/scsi: truncate T10 PI iov_iter to prot_bytes
+    - ocfs2: fix a misuse a of brelse after failing ocfs2_check_dir_entry
+    - mm: thp: relax __GFP_THISNODE for MADV_HUGEPAGE mappings
+    - mtd: docg3: don't set conflicting BCH_CONST_PARAMS option
+    - termios, tty/tty_baudrate.c: fix buffer overrun
+    - arch/alpha, termios: implement BOTHER, IBSHIFT and termios2
+    - Btrfs: fix data corruption due to cloning of eof block
+    - clockevents/drivers/i8253: Add support for PIT shutdown quirk
+    - ext4: add missing brelse() update_backups()'s error path
+    - ext4: add missing brelse() in set_flexbg_block_bitmap()'s error path
+    - ext4: add missing brelse() add_new_gdb_meta_bg()'s error path
+    - ext4: avoid potential extra brelse in setup_new_flex_group_blocks()
+    - ext4: fix possible inode leak in the retry loop of ext4_resize_fs()
+    - ext4: avoid buffer leak in ext4_orphan_add() after prior errors
+    - ext4: fix missing cleanup if ext4_alloc_flex_bg_array() fails while resizing
+    - ext4: avoid possible double brelse() in add_new_gdb() on error path
+    - ext4: fix possible leak of sbi->s_group_desc_leak in error path
+    - ext4: release bs.bh before re-using in ext4_xattr_block_find()
+    - ext4: fix buffer leak in ext4_xattr_move_to_block() on error path
+    - ext4: fix buffer leak in __ext4_read_dirblock() on error path
+    - mount: Prevent MNT_DETACH from disconnecting locked mounts
+    - sunrpc: correct the computation for page_ptr when truncating
+    - rtc: hctosys: Add missing range error reporting
+    - fuse: fix leaked notify reply
+    - configfs: replace strncpy with memcpy
+    - hugetlbfs: fix kernel BUG at fs/hugetlbfs/inode.c:444!
+    - mm: migration: fix migration of huge PMD shared pages
+    - drm/rockchip: Allow driver to be shutdown on reboot/kexec
+    - drm/dp_mst: Check if primary mstb is null
+    - drm/i915/hdmi: Add HDMI 2.0 audio clock recovery N values
+    - Linux 4.4.164
+
+  * Xenial update: 4.4.163 upstream stable release (LP: #1810807)
+    - xfrm: Validate address prefix lengths in the xfrm selector.
+    - xfrm6: call kfree_skb when skb is toobig
+    - mac80211: Always report TX status
+    - cfg80211: reg: Init wiphy_idx in regulatory_hint_core()
+    - ARM: 8799/1: mm: fix pci_ioremap_io() offset check
+    - xfrm: validate template mode
+    - mac80211_hwsim: do not omit multicast announce of first added radio
+    - Bluetooth: SMP: fix crash in unpairing
+    - pxa168fb: prepare the clock
+    - asix: Check for supported Wake-on-LAN modes
+    - ax88179_178a: Check for supported Wake-on-LAN modes
+    - lan78xx: Check for supported Wake-on-LAN modes
+    - sr9800: Check for supported Wake-on-LAN modes
+    - r8152: Check for supported Wake-on-LAN Modes
+    - smsc75xx: Check for Wake-on-LAN modes
+    - smsc95xx: Check for Wake-on-LAN modes
+    - perf/ring_buffer: Prevent concurent ring buffer access
+    - net: cxgb3_main: fix a missing-check bug
+    - KEYS: put keyring if install_session_keyring_to_cred() fails
+    - ipv6: suppress sparse warnings in IP6_ECN_set_ce()
+    - net: drop write-only stack variable
+    - ser_gigaset: use container_of() instead of detour
+    - tracing: Skip more functions when doing stack tracing of events
+    - ARM: dts: apq8064: add ahci ports-implemented mask
+    - x86/mm/pat: Prevent hang during boot when mapping pages
+    - radix-tree: fix radix_tree_iter_retry() for tagged iterators.
+    - af_iucv: Move sockaddr length checks to before accessing sa_family in bind
+      and connect handlers
+    - net/mlx4_en: Resolve dividing by zero in 32-bit system
+    - ipv6: orphan skbs in reassembly unit
+    - um: Avoid longjmp/setjmp symbol clashes with libpthread.a
+    - sched/cgroup: Fix cgroup entity load tracking tear-down
+    - btrfs: don't create or leak aliased root while cleaning up orphans
+    - thermal: allow spear-thermal driver to be a module
+    - thermal: allow u8500-thermal driver to be a module
+    - x86/PCI: Mark Broadwell-EP Home Agent 1 as having non-compliant BARs
+    - aacraid: Start adapter after updating number of MSIX vectors
+    - perf/core: Don't leak event in the syscall error path
+    - usbvision: revert commit 588afcc1
+    - MIPS: Fix FCSR Cause bit handling for correct SIGFPE issue
+    - ASoC: ak4613: Enable cache usage to fix crashes on resume
+    - ASoC: wm8940: Enable cache usage to fix crashes on resume
+    - CIFS: handle guest access errors to Windows shares
+    - arm64: Fix potential race with hardware DBM in ptep_set_access_flags()
+    - xfrm: Clear sk_dst_cache when applying per-socket policy.
+    - scsi: Add STARGET_CREATED_REMOVE state to scsi_target_state
+    - sparc/pci: Refactor dev_archdata initialization into pci_init_dev_archdata
+    - sch_red: update backlog as well
+    - usb-storage: fix bogus hardware error messages for ATA pass-thru devices
+    - bpf: generally move prog destruction to RCU deferral
+    - drm/nouveau/fbcon: fix oops without fbdev emulation
+    - fuse: Dont call set_page_dirty_lock() for ITER_BVEC pages for async_dio
+    - net/mlx5e: Fix LRO modify
+    - net/mlx5e: Correctly handle RSS indirection table when changing number of
+      channels
+    - ALSA: timer: Fix zero-division by continue of uninitialized instance
+    - vti6: flush x-netns xfrm cache when vti interface is removed
+    - brcmfmac: Fix glom_skb leak in brcmf_sdiod_recv_chain
+    - l2tp: hold socket before dropping lock in l2tp_ip{, 6}_recv()
+    - tty: serial: sprd: fix error return code in sprd_probe()
+    - video: fbdev: pxa3xx_gcu: fix error return code in pxa3xx_gcu_probe()
+    - sparc64 mm: Fix more TSB sizing issues
+    - gpu: host1x: fix error return code in host1x_probe()
+    - sparc64: Fix exception handling in UltraSPARC-III memcpy.
+    - gpio: msic: fix error return code in platform_msic_gpio_probe()
+    - usb: imx21-hcd: fix error return code in imx21_probe()
+    - usb: ehci-omap: fix error return code in ehci_hcd_omap_probe()
+    - usb: dwc3: omap: fix error return code in dwc3_omap_probe()
+    - spi/bcm63xx-hspi: fix error return code in bcm63xx_hsspi_probe()
+    - MIPS: Handle non word sized instructions when examining frame
+    - spi/bcm63xx: fix error return code in bcm63xx_spi_probe()
+    - spi: xlp: fix error return code in xlp_spi_probe()
+    - ASoC: spear: fix error return code in spdif_in_probe()
+    - PM / devfreq: tegra: fix error return code in tegra_devfreq_probe()
+    - bonding: avoid defaulting hard_header_len to ETH_HLEN on slave removal
+    - scsi: aacraid: Fix typo in blink status
+    - MIPS: microMIPS: Fix decoding of swsp16 instruction
+    - igb: Remove superfluous reset to PHY and page 0 selection
+    - MIPS: DEC: Fix an int-handler.S CPU_DADDI_WORKAROUNDS regression
+    - ARM: dts: imx53-qsb: disable 1.2GHz OPP
+    - fs/fat/fatent.c: add cond_resched() to fat_count_free_clusters()
+    - mtd: spi-nor: Add support for is25wp series chips
+    - perf tools: Disable parallelism for 'make clean'
+    - bridge: do not add port to router list when receives query with source
+      0.0.0.0
+    - net: bridge: remove ipv6 zero address check in mcast queries
+    - ipv6: mcast: fix a use-after-free in inet6_mc_check
+    - ipv6/ndisc: Preserve IPv6 control buffer if protocol error handlers are
+      called
+    - net/ipv6: Fix index counter for unicast addresses in in6_dump_addrs
+    - net: sched: gred: pass the right attribute to gred_change_table_def()
+    - net: socket: fix a missing-check bug
+    - net: stmmac: Fix stmmac_mdio_reset() when building stmmac as modules
+    - r8169: fix NAPI handling under high load
+    - sctp: fix race on sctp_id2asoc
+    - net: drop skb on failure in ip_check_defrag()
+    - vhost: Fix Spectre V1 vulnerability
+    - rtnetlink: Disallow FDB configuration for non-Ethernet device
+    - mremap: properly flush TLB before releasing the page
+    - crypto: shash - Fix a sleep-in-atomic bug in shash_setkey_unaligned
+    - ahci: don't ignore result code of ahci_reset_controller()
+    - cachefiles: fix the race between cachefiles_bury_object() and rmdir(2)
+    - ptp: fix Spectre v1 vulnerability
+    - RDMA/ucma: Fix Spectre v1 vulnerability
+    - IB/ucm: Fix Spectre v1 vulnerability
+    - cdc-acm: correct counting of UART states in serial state notification
+    - usb: gadget: storage: Fix Spectre v1 vulnerability
+    - USB: fix the usbfs flag sanitization for control transfers
+    - Input: elan_i2c - add ACPI ID for Lenovo IdeaPad 330-15IGM
+    - sched/fair: Fix throttle_list starvation with low CFS quota
+    - x86/percpu: Fix this_cpu_read()
+    - cpuidle: Do not access cpuidle_devices when !CONFIG_CPU_IDLE
+    - l2tp: hold tunnel socket when handling control frames in l2tp_ip and
+      l2tp_ip6
+    - x86/time: Correct the attribute on jiffies' definition
+    - Linux 4.4.163
+
+  * nvme - Polling on timeout (LP: #1807393)
+    - nvme/pci: Poll CQ on timeout
+
+  * Xenial: data corruption when using i40e with iommu (LP: #1802421)
+    - i40e: Drop packet split receive routine
+
+  * Fix Intel I210 doesn't work when ethernet cable gets plugged (LP: #1806818)
+    - igb: Fix an issue that PME is not enabled during runtime suspend
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 16 Jan 2019 17:35:06 +0100
+
+linux (4.4.0-141.167) xenial; urgency=medium
+
+  * linux: 4.4.0-141.167 -proposed tracker (LP: #1806569)
+
+  *  Redpine: firmware assert upon assoc   timeout (LP: #1804360)
+    - SAUCE: Redpine: fix for firmware assert upon assoc timeout
+
+  * CVE-2018-12896
+    - posix-timers: Sanitize overrun handling
+
+  * CVE-2017-5753
+    - ALSA: opl3: Hardening for potential Spectre v1
+    - ALSA: asihpi: Hardening for potential Spectre v1
+    - ALSA: hdspm: Hardening for potential Spectre v1
+    - ALSA: rme9652: Hardening for potential Spectre v1
+    - ALSA: control: Hardening for potential Spectre v1
+    - usbip: vhci_sysfs: fix potential Spectre v1
+    - libahci: Fix possible Spectre-v1 pmp indexing in ahci_led_store()
+
+  * CVE-2018-18710
+    - cdrom: fix improper type cast, which can leat to information leak.
+
+  * CVE-2018-18690
+    - xfs: don't fail when converting shortform attr to long form during
+      ATTR_REPLACE
+
+  * CVE-2017-18174
+    - pinctrl: Add devm_ apis for pinctrl_{register, unregister}
+    - pinctrl: amd: Use devm_pinctrl_register() for pinctrl registration
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 05 Dec 2018 06:11:33 +0000
+
+linux (4.4.0-140.166) xenial; urgency=medium
+
+  * linux: 4.4.0-140.166 -proposed tracker (LP: #1802776)
+
+  * Bypass of mount visibility through userns + mount propagation (LP: #1789161)
+    - mount: Retest MNT_LOCKED in do_umount
+    - mount: Don't allow copying MNT_UNBINDABLE|MNT_LOCKED mounts
+
+  * kdump fail due to an IRQ storm (LP: #1797990)
+    - SAUCE: x86/PCI: Export find_cap() to be used in early PCI code
+    - SAUCE: x86/quirks: Add parameter to clear MSIs early on boot
+    - SAUCE: x86/quirks: Scan all busses for early PCI quirks
+
+  * crash in ENA driver on removing an interface (LP: #1802341)
+    - SAUCE: net: ena: fix crash during ena_remove()
+
+  * xenial guest on arm64 drops to busybox under openstack bionic-rocky
+    (LP: #1797092)
+    - [Config] CONFIG_PCI_ECAM=y
+    - PCI: Provide common functions for ECAM mapping
+    - PCI: generic, thunder: Use generic ECAM API
+    - PCI, of: Move PCI I/O space management to PCI core code
+    - PCI: Move ecam.h to linux/include/pci-ecam.h
+    - PCI: Add parent device field to ECAM struct pci_config_window
+    - PCI: Add pci_unmap_iospace() to unmap I/O resources
+    - PCI/ACPI: Support I/O resources when parsing host bridge resources
+    - [Config] CONFIG_ACPI_MCFG=y
+    - PCI/ACPI: Add generic MCFG table handling
+    - PCI: Refactor pci_bus_assign_domain_nr() for CONFIG_PCI_DOMAINS_GENERIC
+    - PCI: Factor DT-specific pci_bus_find_domain_nr() code out
+    - ARM64: PCI: Add acpi_pci_bus_find_domain_nr()
+    - ARM64: PCI: ACPI support for legacy IRQs parsing and consolidation with DT
+      code
+    - ARM64: PCI: Support ACPI-based PCI host controller
+
+  * [GLK/CLX] Enhanced IBRS (LP: #1786139)
+    - x86/speculation: Remove SPECTRE_V2_IBRS in enum spectre_v2_mitigation
+    - x86/speculation: Support Enhanced IBRS on future CPUs
+
+  * Update ENA driver to version 2.0.1K (LP: #1798182)
+    - net: ena: remove ndo_poll_controller
+    - net: ena: fix warning in rmmod caused by double iounmap
+    - net: ena: fix rare bug when failed restart/resume is followed by driver
+      removal
+    - net: ena: fix NULL dereference due to untimely napi initialization
+    - net: ena: fix auto casting to boolean
+    - net: ena: minor performance improvement
+    - net: ena: complete host info to match latest ENA spec
+    - net: ena: introduce Low Latency Queues data structures according to ENA spec
+    - net: ena: add functions for handling Low Latency Queues in ena_com
+    - net: ena: add functions for handling Low Latency Queues in ena_netdev
+    - net: ena: use CSUM_CHECKED device indication to report skb's checksum status
+    - net: ena: explicit casting and initialization, and clearer error handling
+    - net: ena: limit refill Rx threshold to 256 to avoid latency issues
+    - net: ena: change rx copybreak default to reduce kernel memory pressure
+    - net: ena: remove redundant parameter in ena_com_admin_init()
+    - net: ena: update driver version to 2.0.1
+    - net: ena: fix indentations in ena_defs for better readability
+    - net: ena: Fix Kconfig dependency on X86
+    - net: ena: enable Low Latency Queues
+    - net: ena: fix compilation error in xtensa architecture
+
+  * Xenial update: 4.4.162 upstream stable release (LP: #1801900)
+    - ASoC: wm8804: Add ACPI support
+    - ASoC: sigmadsp: safeload should not have lower byte limit
+    - selftests/efivarfs: add required kernel configs
+    - mfd: omap-usb-host: Fix dts probe of children
+    - sound: enable interrupt after dma buffer initialization
+    - stmmac: fix valid numbers of unicast filter entries
+    - net: macb: disable scatter-gather for macb on sama5d3
+    - ARM: dts: at91: add new compatibility string for macb on sama5d3
+    - drm/amdgpu: Fix SDMA HQD destroy error on gfx_v7
+    - ext4: add corruption check in ext4_xattr_set_entry()
+    - mm/vmstat.c: fix outdated vmstat_text
+    - mach64: detect the dot clock divider correctly on sparc
+    - perf script python: Fix export-to-postgresql.py occasional failure
+    - i2c: i2c-scmi: fix for i2c_smbus_write_block_data
+    - xhci: Don't print a warning when setting link state for disabled ports
+    - jffs2: return -ERANGE when xattr buffer is too small
+    - bnxt_en: Fix TX timeout during netpoll.
+    - bonding: avoid possible dead-lock
+    - ip6_tunnel: be careful when accessing the inner header
+    - ip_tunnel: be careful when accessing the inner header
+    - ipv4: fix use-after-free in ip_cmsg_recv_dstaddr()
+    - net: ipv4: update fnhe_pmtu when first hop's MTU changes
+    - net/ipv6: Display all addresses in output of /proc/net/if_inet6
+    - netlabel: check for IPV4MASK in addrinfo_get
+    - net/usb: cancel pending work when unbinding smsc75xx
+    - qlcnic: fix Tx descriptor corruption on 82xx devices
+    - team: Forbid enslaving team device to itself
+    - net: mvpp2: Extract the correct ethtype from the skb for tx csum offload
+    - net: systemport: Fix wake-up interrupt race during resume
+    - rtnl: limit IFLA_NUM_TX_QUEUES and IFLA_NUM_RX_QUEUES to 4096
+    - KVM: x86: remove eager_fpu field of struct kvm_vcpu_arch
+    - x86/fpu: Remove use_eager_fpu()
+    - x86/fpu: Remove struct fpu::counter
+    - x86/fpu: Finish excising 'eagerfpu'
+    - media: af9035: prevent buffer overflow on write
+    - clocksource/drivers/ti-32k: Add CLOCK_SOURCE_SUSPEND_NONSTOP flag for non-
+      am43 SoCs
+    - Input: atakbd - fix Atari keymap
+    - Input: atakbd - fix Atari CapsLock behaviour
+    - net/mlx4: Use cpumask_available for eq->affinity_mask
+    - powerpc/tm: Fix userspace r13 corruption
+    - powerpc/tm: Avoid possible userspace r1 corruption on reclaim
+    - ARC: build: Get rid of toolchain check
+    - usb: gadget: serial: fix oops when data rx'd after close
+    - HV: properly delay KVP packets when negotiation is in progress
+    - Linux 4.4.162
+
+  * Xenial update: 4.4.161 upstream stable release (LP: #1801893)
+    - mm/vmstat.c: skip NR_TLB_REMOTE_FLUSH* properly
+    - fbdev/omapfb: fix omapfb_memory_read infoleak
+    - x86/vdso: Fix asm constraints on vDSO syscall fallbacks
+    - x86/vdso: Fix vDSO syscall fallback asm constraint regression
+    - PCI: Reprogram bridge prefetch registers on resume
+    - mac80211: fix setting IEEE80211_KEY_FLAG_RX_MGMT for AP mode keys
+    - PM / core: Clear the direct_complete flag on errors
+    - dm cache: fix resize crash if user doesn't reload cache table
+    - xhci: Add missing CAS workaround for Intel Sunrise Point xHCI
+    - USB: serial: simple: add Motorola Tetra MTP6550 id
+    - of: unittest: Disable interrupt node tests for old world MAC systems
+    - ext4: always verify the magic number in xattr blocks
+    - cgroup: Fix deadlock in cpu hotplug path
+    - ath10k: fix use-after-free in ath10k_wmi_cmd_send_nowait
+    - ARC: clone syscall to setp r25 as thread pointer
+    - ucma: fix a use-after-free in ucma_resolve_ip()
+    - ubifs: Check for name being NULL while mounting
+    - tcp: increment sk_drops for dropped rx packets
+    - tcp: use an RB tree for ooo receive queue
+    - tcp: fix a stale ooo_last_skb after a replace
+    - tcp: free batches of packets in tcp_prune_ofo_queue()
+    - tcp: call tcp_drop() from tcp_data_queue_ofo()
+    - tcp: add tcp_ooo_try_coalesce() helper
+    - ath10k: fix scan crash due to incorrect length calculation
+    - ebtables: arpreply: Add the standard target sanity check
+    - Linux 4.4.161
+
+  * mlock203 test in ubuntu_ltp_syscalls failed with Xenial kernel
+    (LP: #1793451)
+    - mm: mlock: avoid increase mm->locked_vm on mlock() when already mlock2(,
+      MLOCK_ONFAULT)
+
+  * execveat03 in ubuntu_ltp_syscalls failed on X/B (LP: #1786729)
+    - cap_inode_getsecurity: use d_find_any_alias() instead of d_find_alias()
+
+  * [Ubuntu] net/af_iucv: fix skb leaks for HiperTransport (LP: #1800639)
+    - net/af_iucv: drop inbound packets with invalid flags
+    - net/af_iucv: fix skb handling on HiperTransport xmit error
+
+  * NULL pointer dereference at 0000000000000020 when access
+    dst_orig->ops->family in function  xfrm_lookup_with_ifid() (LP: #1801878)
+    - xfrm: Fix NULL pointer dereference when skb_dst_force clears the dst_entry.
+
+  * [Ubuntu] qeth: Fix potential array overrun in cmd/rc lookup (LP: #1800641)
+    - s390: qeth_core_mpc: Use ARRAY_SIZE instead of reimplementing its function
+    - s390: qeth: Fix potential array overrun in cmd/rc lookup
+
+  * Packaging resync (LP: #1786013)
+    - [Package] add support for specifying the primary makefile
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Tue, 13 Nov 2018 16:55:46 -0500
+
+linux (4.4.0-139.165) xenial; urgency=medium
+
+  * linux: 4.4.0-139.165 -proposed tracker (LP: #1799401)
+
+  * Kernel panic after the ubuntu_nbd_smoke_test on Xenial kernel (LP: #1793464)
+    - nbd: Remove signal usage
+    - nbd: Timeouts are not user requested disconnects
+    - nbd: Cleanup reset of nbd and bdev after a disconnect
+    - nbd: don't shutdown sock with irq's disabled
+    - nbd: fix race in ioctl
+
+  * fscache: bad refcounting in fscache_op_complete leads to OOPS (LP: #1797314)
+    - SAUCE: fscache: Fix race in decrementing refcount of op->npages
+
+  * xenial: virtio-scsi: CPU soft lockup due to loop in
+    virtscsi_target_destroy() (LP: #1798110)
+    - SAUCE: (no-up) virtio-scsi: Decrement reqs counter before SCSI command
+      requeue
+
+  * Error reported when creating ZFS pool with "-t" option, despite successful
+    pool creation (LP: #1769937)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu26
+
+  * Xenial update: 4.4.160 upstream stable release (LP: #1798770)
+    - crypto: skcipher - Fix -Wstringop-truncation warnings
+    - tsl2550: fix lux1_input error in low light
+    - vmci: type promotion bug in qp_host_get_user_memory()
+    - x86/numa_emulation: Fix emulated-to-physical node mapping
+    - staging: rts5208: fix missing error check on call to rtsx_write_register
+    - uwb: hwa-rc: fix memory leak at probe
+    - power: vexpress: fix corruption in notifier registration
+    - Bluetooth: Add a new Realtek 8723DE ID 0bda:b009
+    - USB: serial: kobil_sct: fix modem-status error handling
+    - 6lowpan: iphc: reset mac_header after decompress to fix panic
+    - md-cluster: clear another node's suspend_area after the copy is finished
+    - media: exynos4-is: Prevent NULL pointer dereference in __isp_video_try_fmt()
+    - powerpc/kdump: Handle crashkernel memory reservation failure
+    - media: fsl-viu: fix error handling in viu_of_probe()
+    - x86/tsc: Add missing header to tsc_msr.c
+    - x86/entry/64: Add two more instruction suffixes
+    - scsi: target/iscsi: Make iscsit_ta_authentication() respect the output
+      buffer size
+    - scsi: klist: Make it safe to use klists in atomic context
+    - scsi: ibmvscsi: Improve strings handling
+    - usb: wusbcore: security: cast sizeof to int for comparison
+    - powerpc/powernv/ioda2: Reduce upper limit for DMA window size
+    - alarmtimer: Prevent overflow for relative nanosleep
+    - s390/extmem: fix gcc 8 stringop-overflow warning
+    - ALSA: snd-aoa: add of_node_put() in error path
+    - media: s3c-camif: ignore -ENOIOCTLCMD from v4l2_subdev_call for s_power
+    - media: soc_camera: ov772x: correct setting of banding filter
+    - media: omap3isp: zero-initialize the isp cam_xclk{a,b} initial data
+    - staging: android: ashmem: Fix mmap size validation
+    - drivers/tty: add error handling for pcmcia_loop_config
+    - media: tm6000: add error handling for dvb_register_adapter
+    - ALSA: hda: Add AZX_DCAPS_PM_RUNTIME for AMD Raven Ridge
+    - ath10k: protect ath10k_htt_rx_ring_free with rx_ring.lock
+    - rndis_wlan: potential buffer overflow in rndis_wlan_auth_indication()
+    - wlcore: Add missing PM call for wlcore_cmd_wait_for_event_or_timeout()
+    - ARM: mvebu: declare asm symbols as character arrays in pmsu.c
+    - HID: hid-ntrig: add error handling for sysfs_create_group
+    - scsi: bnx2i: add error handling for ioremap_nocache
+    - EDAC, i7core: Fix memleaks and use-after-free on probe and remove
+    - ASoC: dapm: Fix potential DAI widget pointer deref when linking DAIs
+    - module: exclude SHN_UNDEF symbols from kallsyms api
+    - nfsd: fix corrupted reply to badly ordered compound
+    - ARM: dts: dra7: fix DCAN node addresses
+    - serial: cpm_uart: return immediately from console poll
+    - spi: tegra20-slink: explicitly enable/disable clock
+    - spi: sh-msiof: Fix invalid SPI use during system suspend
+    - spi: sh-msiof: Fix handling of write value for SISTR register
+    - spi: rspi: Fix invalid SPI use during system suspend
+    - spi: rspi: Fix interrupted DMA transfers
+    - USB: fix error handling in usb_driver_claim_interface()
+    - USB: handle NULL config in usb_find_alt_setting()
+    - slub: make ->cpu_partial unsigned int
+    - Revert "UBUNTU: SAUCE: media: uvcvideo: Support realtek's UVC 1.5 device"
+    - media: uvcvideo: Support realtek's UVC 1.5 device
+    - USB: usbdevfs: sanitize flags more
+    - USB: usbdevfs: restore warning for nonsensical flags
+    - Revert "usb: cdc-wdm: Fix a sleep-in-atomic-context bug in
+      service_outstanding_interrupt()"
+    - USB: remove LPM management from usb_driver_claim_interface()
+    - Input: elantech - enable middle button of touchpad on ThinkPad P72
+    - IB/srp: Avoid that sg_reset -d ${srp_device} triggers an infinite loop
+    - scsi: target: iscsi: Use bin2hex instead of a re-implementation
+    - serial: imx: restore handshaking irq for imx1
+    - arm64: KVM: Tighten guest core register access from userspace
+    - ext4: never move the system.data xattr out of the inode body
+    - thermal: of-thermal: disable passive polling when thermal zone is disabled
+    - net: hns: fix length and page_offset overflow when CONFIG_ARM64_64K_PAGES
+    - e1000: check on netif_running() before calling e1000_up()
+    - e1000: ensure to free old tx/rx rings in set_ringparam()
+    - hwmon: (ina2xx) fix sysfs shunt resistor read access
+    - hwmon: (adt7475) Make adt7475_read_word() return errors
+    - i2c: i801: Allow ACPI AML access I/O ports not reserved for SMBus
+    - arm64: cpufeature: Track 32bit EL0 support
+    - arm64: KVM: Sanitize PSTATE.M when being set from userspace
+    - media: v4l: event: Prevent freeing event subscriptions while accessed
+    - KVM: PPC: Book3S HV: Don't truncate HPTE index in xlate function
+    - mac80211: correct use of IEEE80211_VHT_CAP_RXSTBC_X
+    - mac80211_hwsim: correct use of IEEE80211_VHT_CAP_RXSTBC_X
+    - gpio: adp5588: Fix sleep-in-atomic-context bug
+    - mac80211: mesh: fix HWMP sequence numbering to follow standard
+    - cfg80211: nl80211_update_ft_ies() to validate NL80211_ATTR_IE
+    - RAID10 BUG_ON in raise_barrier when force is true and conf->barrier is 0
+    - i2c: uniphier: issue STOP only for last message or I2C_M_STOP
+    - i2c: uniphier-f: issue STOP only for last message or I2C_M_STOP
+    - net: cadence: Fix a sleep-in-atomic-context bug in macb_halt_tx()
+    - fs/cifs: don't translate SFM_SLASH (U+F026) to backslash
+    - cfg80211: fix a type issue in ieee80211_chandef_to_operating_class()
+    - mac80211: fix a race between restart and CSA flows
+    - mac80211: Fix station bandwidth setting after channel switch
+    - mac80211: shorten the IBSS debug messages
+    - tools/vm/slabinfo.c: fix sign-compare warning
+    - tools/vm/page-types.c: fix "defined but not used" warning
+    - mm: madvise(MADV_DODUMP): allow hugetlbfs pages
+    - usb: gadget: fotg210-udc: Fix memory leak of fotg210->ep[i]
+    - perf probe powerpc: Ignore SyS symbols irrespective of endianness
+    - RDMA/ucma: check fd type in ucma_migrate_id()
+    - USB: yurex: Check for truncation in yurex_read()
+    - drm/nouveau/TBDdevinit: don't fail when PMU/PRE_OS is missing from VBIOS
+    - fs/cifs: suppress a string overflow warning
+    - dm thin metadata: try to avoid ever aborting transactions
+    - arch/hexagon: fix kernel/dma.c build warning
+    - hexagon: modify ffs() and fls() to return int
+    - arm64: jump_label.h: use asm_volatile_goto macro instead of "asm goto"
+    - r8169: Clear RTL_FLAG_TASK_*_PENDING when clearing RTL_FLAG_TASK_ENABLED
+    - s390/qeth: don't dump past end of unknown HW header
+    - cifs: read overflow in is_valid_oplock_break()
+    - xen/manage: don't complain about an empty value in control/sysrq node
+    - xen: avoid crash in disable_hotplug_cpu
+    - xen: fix GCC warning and remove duplicate EVTCHN_ROW/EVTCHN_COL usage
+    - smb2: fix missing files in root share directory listing
+    - crypto: mxs-dcp - Fix wait logic on chan threads
+    - proc: restrict kernel stack dumps to root
+    - ocfs2: fix locking for res->tracking and dlm->tracking_list
+    - dm thin metadata: fix __udivdi3 undefined on 32-bit
+    - Linux 4.4.160
+
+  * Volume control not working Dell XPS 27 (7760) (LP: #1775068) // Xenial
+    update: 4.4.160 upstream stable release (LP: #1798770)
+    - ALSA: hda/realtek - Cannot adjust speaker's volume on Dell XPS 27 7760
+
+  * Xenial update: 4.4.160 upstream stable release (LP: #1798770) //
+    CVE-2018-7755
+    - floppy: Do not copy a kernel pointer to user memory in FDGETPRM ioctl
+
+  * Xenial update: 4.4.159 upstream stable release (LP: #1798617)
+    - NFC: Fix possible memory corruption when handling SHDLC I-Frame commands
+    - NFC: Fix the number of pipes
+    - ASoC: cs4265: fix MMTLR Data switch control
+    - ALSA: bebob: use address returned by kmalloc() instead of kernel stack for
+      streaming DMA mapping
+    - ALSA: emu10k1: fix possible info leak to userspace on
+      SNDRV_EMU10K1_IOCTL_INFO
+    - platform/x86: alienware-wmi: Correct a memory leak
+    - xen/netfront: don't bug in case of too many frags
+    - xen/x86/vpmu: Zero struct pt_regs before calling into sample handling code
+    - ring-buffer: Allow for rescheduling when removing pages
+    - mm: shmem.c: Correctly annotate new inodes for lockdep
+    - gso_segment: Reset skb->mac_len after modifying network header
+    - ipv6: fix possible use-after-free in ip6_xmit()
+    - net/appletalk: fix minor pointer leak to userspace in SIOCFINDIPDDPRT
+    - net: hp100: fix always-true check for link up state
+    - neighbour: confirm neigh entries when ARP packet is received
+    - ocfs2: fix ocfs2 read block panic
+    - drm/nouveau/drm/nouveau: Use pm_runtime_get_noresume() in connector_detect()
+    - tty: vt_ioctl: fix potential Spectre v1
+    - ext4: avoid divide by zero fault when deleting corrupted inline directories
+    - ext4: recalucate superblock checksum after updating free blocks/inodes
+    - ext4: fix online resize's handling of a too-small final block group
+    - ext4: fix online resizing for bigalloc file systems with a 1k block size
+    - ext4: don't mark mmp buffer head dirty
+    - arm64: Add trace_hardirqs_off annotation in ret_to_user
+    - HID: sony: Update device ids
+    - HID: sony: Support DS4 dongle
+    - iw_cxgb4: only allow 1 flush on user qps
+    - Linux 4.4.159
+
+  * Xenial update: 4.4.158 upstream stable release (LP: #1798587)
+    - iommu/arm-smmu-v3: sync the OVACKFLG to PRIQ consumer register
+    - ALSA: msnd: Fix the default sample sizes
+    - ALSA: usb-audio: Fix multiple definitions in AU0828_DEVICE() macro
+    - xfrm: fix 'passing zero to ERR_PTR()' warning
+    - gfs2: Special-case rindex for gfs2_grow
+    - clk: imx6ul: fix missing of_node_put()
+    - kbuild: add .DELETE_ON_ERROR special target
+    - dmaengine: pl330: fix irq race with terminate_all
+    - MIPS: ath79: fix system restart
+    - media: videobuf2-core: check for q->error in vb2_core_qbuf()
+    - mtd/maps: fix solutionengine.c printk format warnings
+    - fbdev: omapfb: off by one in omapfb_register_client()
+    - video: goldfishfb: fix memory leak on driver remove
+    - fbdev/via: fix defined but not used warning
+    - perf powerpc: Fix callchain ip filtering when return address is in a
+      register
+    - fbdev: Distinguish between interlaced and progressive modes
+    - ARM: exynos: Clear global variable on init error path
+    - perf powerpc: Fix callchain ip filtering
+    - powerpc/powernv: opal_put_chars partial write fix
+    - MIPS: jz4740: Bump zload address
+    - mac80211: restrict delayed tailroom needed decrement
+    - xen-netfront: fix queue name setting
+    - arm64: dts: qcom: db410c: Fix Bluetooth LED trigger
+    - s390/qeth: fix race in used-buffer accounting
+    - s390/qeth: reset layer2 attribute on layer switch
+    - platform/x86: toshiba_acpi: Fix defined but not used build warnings
+    - crypto: sharah - Unregister correct algorithms for SAHARA 3
+    - xen-netfront: fix warn message as irq device name has '/'
+    - RDMA/cma: Protect cma dev list with lock
+    - pstore: Fix incorrect persistent ram buffer mapping
+    - xen/netfront: fix waiting for xenbus state change
+    - IB/ipoib: Avoid a race condition between start_xmit and cm_rep_handler
+    - Tools: hv: Fix a bug in the key delete code
+    - misc: hmc6352: fix potential Spectre v1
+    - usb: Don't die twice if PCI xhci host is not responding in resume
+    - USB: Add quirk to support DJI CineSSD
+    - usb: Avoid use-after-free by flushing endpoints early in usb_set_interface()
+    - usb: host: u132-hcd: Fix a sleep-in-atomic-context bug in u132_get_frame()
+    - USB: add quirk for WORLDE Controller KS49 or Prodipe MIDI 49C USB controller
+    - USB: net2280: Fix erroneous synchronization change
+    - USB: serial: io_ti: fix array underflow in completion handler
+    - usb: misc: uss720: Fix two sleep-in-atomic-context bugs
+    - USB: yurex: Fix buffer over-read in yurex_write()
+    - usb: cdc-wdm: Fix a sleep-in-atomic-context bug in
+      service_outstanding_interrupt()
+    - cifs: prevent integer overflow in nxt_dir_entry()
+    - CIFS: fix wrapping bugs in num_entries()
+    - binfmt_elf: Respect error return from `regset->active'
+    - audit: fix use-after-free in audit_add_watch
+    - mtdchar: fix overflows in adjustment of `count`
+    - MIPS: loongson64: cs5536: Fix PCI_OHCI_INT_REG reads
+    - ARM: hisi: handle of_iomap and fix missing of_node_put
+    - ARM: hisi: fix error handling and missing of_node_put
+    - ARM: hisi: check of_iomap and fix missing of_node_put
+    - drm/nouveau: tegra: Detach from ARM DMA/IOMMU mapping
+    - parport: sunbpp: fix error return code
+    - coresight: Handle errors in finding input/output ports
+    - coresight: tpiu: Fix disabling timeouts
+    - gpiolib: Mark gpio_suffixes array with __maybe_unused
+    - drm/amdkfd: Fix error codes in kfd_get_process
+    - rtc: bq4802: add error handling for devm_ioremap
+    - ALSA: pcm: Fix snd_interval_refine first/last with open min/max
+    - selftest: timers: Tweak raw_skew to SKIP when ADJ_OFFSET/other clock
+      adjustments are in progress
+    - drm/panel: type promotion bug in s6e8aa0_read_mtp_id()
+    - pinctrl: qcom: spmi-gpio: Fix pmic_gpio_config_get() to be compliant
+    - USB: serial: ti_usb_3410_5052: fix array underflow in completion handler
+    - mei: bus: type promotion bug in mei_nfc_if_version()
+    - drivers: net: cpsw: fix segfault in case of bad phy-handle
+    - MIPS: VDSO: Match data page cache colouring when D$ aliases
+    - Linux 4.4.158
+
+  * Xenial update: 4.4.157 upstream stable release (LP: #1798539)
+    - i2c: xiic: Make the start and the byte count write atomic
+    - i2c: i801: fix DNV's SMBCTRL register offset
+    - ALSA: hda - Fix cancel_work_sync() stall from jackpoll work
+    - cfq: Give a chance for arming slice idle timer in case of group_idle
+    - kthread: Fix use-after-free if kthread fork fails
+    - kthread: fix boot hang (regression) on MIPS/OpenRISC
+    - staging: rt5208: Fix a sleep-in-atomic bug in xd_copy_page
+    - staging/rts5208: Fix read overflow in memcpy
+    - block,blkcg: use __GFP_NOWARN for best-effort allocations in blkcg
+    - locking/rwsem-xadd: Fix missed wakeup due to reordering of load
+    - selinux: use GFP_NOWAIT in the AVC kmem_caches
+    - locking/osq_lock: Fix osq_lock queue corruption
+    - ARC: [plat-axs*]: Enable SWAP
+    - misc: mic: SCIF Fix scif_get_new_port() error handling
+    - ethtool: Remove trailing semicolon for static inline
+    - gpio: tegra: Move driver registration to subsys_init level
+    - scsi: target: fix __transport_register_session locking
+    - md/raid5: fix data corruption of replacements after originals dropped
+    - misc: ti-st: Fix memory leak in the error path of probe()
+    - uio: potential double frees if __uio_register_device() fails
+    - tty: rocket: Fix possible buffer overwrite on register_PCI
+    - f2fs: do not set free of current section
+    - perf tools: Allow overriding MAX_NR_CPUS at compile time
+    - NFSv4.0 fix client reference leak in callback
+    - macintosh/via-pmu: Add missing mmio accessors
+    - ath10k: prevent active scans on potential unusable channels
+    - MIPS: Fix ISA virt/bus conversion for non-zero PHYS_OFFSET
+    - ata: libahci: Correct setting of DEVSLP register
+    - scsi: 3ware: fix return 0 on the error path of probe
+    - ath10k: disable bundle mgmt tx completion event support
+    - Bluetooth: hidp: Fix handling of strncpy for hid->name information
+    - x86/mm: Remove in_nmi() warning from vmalloc_fault()
+    - gpio: ml-ioh: Fix buffer underwrite on probe error path
+    - net: mvneta: fix mtu change on port without link
+    - MIPS: Octeon: add missing of_node_put()
+    - net: dcb: For wild-card lookups, use priority -1, not 0
+    - Input: atmel_mxt_ts - only use first T9 instance
+    - iommu/ipmmu-vmsa: Fix allocation in atomic context
+    - mfd: ti_am335x_tscadc: Fix struct clk memory leak
+    - f2fs: fix to do sanity check with {sit,nat}_ver_bitmap_bytesize
+    - MIPS: WARN_ON invalid DMA cache maintenance, not BUG_ON
+    - RDMA/cma: Do not ignore net namespace for unbound cm_id
+    - xhci: Fix use-after-free in xhci_free_virt_device
+    - vmw_balloon: include asm/io.h
+    - netfilter: x_tables: avoid stack-out-of-bounds read in
+      xt_copy_counters_from_user
+    - drivers: net: cpsw: fix parsing of phy-handle DT property in dual_emac
+      config
+    - net: ethernet: ti: cpsw: fix mdio device reference leak
+    - ethernet: ti: davinci_emac: add missing of_node_put after calling
+      of_parse_phandle
+    - crypto: vmx - Fix sleep-in-atomic bugs
+    - mtd: ubi: wl: Fix error return code in ubi_wl_init()
+    - autofs: fix autofs_sbi() does not check super block type
+    - Linux 4.4.157
+
+  * Xenial update: 4.4.156 upstream stable release (LP: #1797563)
+    - staging: android: ion: fix ION_IOC_{MAP,SHARE} use-after-free
+    - net: bcmgenet: use MAC link status for fixed phy
+    - qlge: Fix netdev features configuration.
+    - tcp: do not restart timewait timer on rst reception
+    - vti6: remove !skb->ignore_df check from vti6_xmit()
+    - cifs: check if SMB2 PDU size has been padded and suppress the warning
+    - hfsplus: don't return 0 when fill_super() failed
+    - hfs: prevent crash on exit from failed search
+    - fork: don't copy inconsistent signal handler state to child
+    - reiserfs: change j_timestamp type to time64_t
+    - hfsplus: fix NULL dereference in hfsplus_lookup()
+    - fat: validate ->i_start before using
+    - scripts: modpost: check memory allocation results
+    - mm/fadvise.c: fix signed overflow UBSAN complaint
+    - fs/dcache.c: fix kmemcheck splat at take_dentry_name_snapshot()
+    - ipvs: fix race between ip_vs_conn_new() and ip_vs_del_dest()
+    - mfd: sm501: Set coherent_dma_mask when creating subdevices
+    - platform/x86: asus-nb-wmi: Add keymap entry for lid flip action on UX360
+    - irqchip/bcm7038-l1: Hide cpu offline callback when building for !SMP
+    - net/9p: fix error path of p9_virtio_probe
+    - powerpc: Fix size calculation using resource_size()
+    - s390/dasd: fix hanging offline processing due to canceled worker
+    - scsi: aic94xx: fix an error code in aic94xx_init()
+    - PCI: mvebu: Fix I/O space end address calculation
+    - dm kcopyd: avoid softlockup in run_complete_job
+    - staging: comedi: ni_mio_common: fix subdevice flags for PFI subdevice
+    - selftests/powerpc: Kill child processes on SIGINT
+    - smb3: fix reset of bytes read and written stats
+    - SMB3: Number of requests sent should be displayed for SMB3 not just CIFS
+    - powerpc/pseries: Avoid using the size greater than RTAS_ERROR_LOG_MAX.
+    - btrfs: replace: Reset on-disk dev stats value after replace
+    - btrfs: relocation: Only remove reloc rb_trees if reloc control has been
+      initialized
+    - btrfs: Don't remove block group that still has pinned down bytes
+    - debugobjects: Make stack check warning more informative
+    - x86/pae: use 64 bit atomic xchg function in native_ptep_get_and_clear
+    - kbuild: make missing $DEPMOD a Warning instead of an Error
+    - Revert "ARM: imx_v6_v7_defconfig: Select ULPI support"
+    - enic: do not call enic_change_mtu in enic_probe
+    - Fixes: Commit cdbf92675fad ("mm: numa: avoid waiting on freed migrated
+      pages")
+    - genirq: Delay incrementing interrupt count if it's disabled/pending
+    - irqchip/gic-v3-its: Recompute the number of pages on page size change
+    - irqchip/gicv3-its: Fix memory leak in its_free_tables()
+    - irqchip/gicv3-its: Avoid cache flush beyond ITS_BASERn memory size
+    - irqchip/gic-v3: Add missing barrier to 32bit version of gic_read_iar()
+    - irqchip/gic: Make interrupt ID 1020 invalid
+    - ovl: rename is_merge to is_lowest
+    - ovl: override creds with the ones from the superblock mounter
+    - ovl: proper cleanup of workdir
+    - sch_htb: fix crash on init failure
+    - sch_multiq: fix double free on init failure
+    - sch_hhf: fix null pointer dereference on init failure
+    - sch_netem: avoid null pointer deref on init failure
+    - sch_tbf: fix two null pointer dereferences on init failure
+    - mei: me: allow runtime pm for platform with D0i3
+    - ASoC: wm8994: Fix missing break in switch
+    - btrfs: use correct compare function of dirty_metadata_bytes
+    - Linux 4.4.156
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 24 Oct 2018 09:57:17 +0000
+
+linux (4.4.0-138.164) xenial; urgency=medium
+
+  * linux: 4.4.0-138.164 -proposed tracker (LP: #1795582)
+
+  * Linux 4.4.155 stable release build is broken on ppc64 (LP: #1795662)
+    - powerpc/fadump: Return error when fadump registration fails
+
+  * Kernel hang on drive pull caused by regression introduced by commit
+    287922eb0b18 (LP: #1791790)
+    - block: Fix a race between blk_cleanup_queue() and timeout handling
+
+  * qeth: use vzalloc for QUERY OAT buffer (LP: #1793086)
+    - s390/qeth: use vzalloc for QUERY OAT buffer
+
+  * Page leaking in cachefiles_read_backing_file while vmscan is active
+    (LP: #1793430)
+    - SAUCE: cachefiles: Page leaking in cachefiles_read_backing_file while vmscan
+      is active
+
+  * Bugfix for handling of shadow doorbell buffer (LP: #1788222)
+    - nvme-pci: add a memory barrier to nvme_dbbuf_update_and_check_event
+
+  * Xenial update to 4.4.155 stable release (LP: #1792419)
+    - net: 6lowpan: fix reserved space for single frames
+    - net: mac802154: tx: expand tailroom if necessary
+    - 9p/net: Fix zero-copy path in the 9p virtio transport
+    - net: lan78xx: Fix misplaced tasklet_schedule() call
+    - spi: davinci: fix a NULL pointer dereference
+    - drm/i915/userptr: reject zero user_size
+    - powerpc/fadump: handle crash memory ranges array index overflow
+    - powerpc/pseries: Fix endianness while restoring of r3 in MCE handler.
+    - fs/9p/xattr.c: catch the error of p9_client_clunk when setting xattr failed
+    - 9p/virtio: fix off-by-one error in sg list bounds check
+    - net/9p/client.c: version pointer uninitialized
+    - net/9p/trans_fd.c: fix race-condition by flushing workqueue before the
+      kfree()
+    - dm cache metadata: save in-core policy_hint_size to on-disk superblock
+    - iio: ad9523: Fix displayed phase
+    - iio: ad9523: Fix return value for ad952x_store()
+    - vmw_balloon: fix inflation of 64-bit GFNs
+    - vmw_balloon: do not use 2MB without batching
+    - vmw_balloon: VMCI_DOORBELL_SET does not check status
+    - vmw_balloon: fix VMCI use when balloon built into kernel
+    - tracing: Do not call start/stop() functions when tracing_on does not change
+    - tracing/blktrace: Fix to allow setting same value
+    - kthread, tracing: Don't expose half-written comm when creating kthreads
+    - uprobes: Use synchronize_rcu() not synchronize_sched()
+    - 9p: fix multiple NULL-pointer-dereferences
+    - PM / sleep: wakeup: Fix build error caused by missing SRCU support
+    - pnfs/blocklayout: off by one in bl_map_stripe()
+    - ARM: tegra: Fix Tegra30 Cardhu PCA954x reset
+    - mm/tlb: Remove tlb_remove_table() non-concurrent condition
+    - iommu/vt-d: Add definitions for PFSID
+    - iommu/vt-d: Fix dev iotlb pfsid use
+    - osf_getdomainname(): use copy_to_user()
+    - sys: don't hold uts_sem while accessing userspace memory
+    - userns: move user access out of the mutex
+    - ubifs: Fix memory leak in lprobs self-check
+    - Revert "UBIFS: Fix potential integer overflow in allocation"
+    - ubifs: Check data node size before truncate
+    - ubifs: Fix synced_i_size calculation for xattr inodes
+    - pwm: tiehrpwm: Fix disabling of output of PWMs
+    - fb: fix lost console when the user unplugs a USB adapter
+    - udlfb: set optimal write delay
+    - getxattr: use correct xattr length
+    - bcache: release dc->writeback_lock properly in bch_writeback_thread()
+    - perf auxtrace: Fix queue resize
+    - fs/quota: Fix spectre gadget in do_quotactl
+    - x86/io: add interface to reserve io memtype for a resource range. (v1.1)
+    - drm/drivers: add support for using the arch wc mapping API.
+    - Linux 4.4.155
+
+  * Xenial update to 4.4.154 stable release (LP: #1792392)
+    - sched/sysctl: Check user input value of sysctl_sched_time_avg
+    - Cipso: cipso_v4_optptr enter infinite loop
+    - vti6: fix PMTU caching and reporting on xmit
+    - xfrm: fix missing dst_release() after policy blocking lbcast and multicast
+    - xfrm: free skb if nlsk pointer is NULL
+    - mac80211: add stations tied to AP_VLANs during hw reconfig
+    - nl80211: Add a missing break in parse_station_flags
+    - drm/bridge: adv7511: Reset registers on hotplug
+    - scsi: libiscsi: fix possible NULL pointer dereference in case of TMF
+    - drm/imx: imx-ldb: disable LDB on driver bind
+    - drm/imx: imx-ldb: check if channel is enabled before printing warning
+    - usb: gadget: r8a66597: Fix two possible sleep-in-atomic-context bugs in
+      init_controller()
+    - usb: gadget: r8a66597: Fix a possible sleep-in-atomic-context bugs in
+      r8a66597_queue()
+    - usb/phy: fix PPC64 build errors in phy-fsl-usb.c
+    - tools: usb: ffs-test: Fix build on big endian systems
+    - usb: gadget: f_uac2: fix endianness of 'struct cntrl_*_lay3'
+    - tools/power turbostat: fix -S on UP systems
+    - net: caif: Add a missing rcu_read_unlock() in caif_flow_cb
+    - qed: Fix possible race for the link state value.
+    - atl1c: reserve min skb headroom
+    - net: prevent ISA drivers from building on PPC32
+    - can: mpc5xxx_can: check of_iomap return before use
+    - i2c: davinci: Avoid zero value of CLKH
+    - media: staging: omap4iss: Include asm/cacheflush.h after generic includes
+    - bnx2x: Fix invalid memory access in rss hash config path.
+    - net: axienet: Fix double deregister of mdio
+    - selftests/ftrace: Add snapshot and tracing_on test case
+    - zswap: re-check zswap_is_full() after do zswap_shrink()
+    - tools/power turbostat: Read extended processor family from CPUID
+    - Revert "MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum"
+    - enic: handle mtu change for vf properly
+    - arc: fix build errors in arc/include/asm/delay.h
+    - arc: fix type warnings in arc/mm/cache.c
+    - drivers: net: lmc: fix case value for target abort error
+    - scsi: fcoe: drop frames in ELS LOGO error path
+    - scsi: vmw_pvscsi: Return DID_RESET for status SAM_STAT_COMMAND_TERMINATED
+    - mm/memory.c: check return value of ioremap_prot
+    - cifs: add missing debug entries for kconfig options
+    - cifs: check kmalloc before use
+    - smb3: Do not send SMB3 SET_INFO if nothing changed
+    - smb3: don't request leases in symlink creation and query
+    - btrfs: don't leak ret from do_chunk_alloc
+    - s390/kvm: fix deadlock when killed by oom
+    - ext4: check for NUL characters in extended attribute's name
+    - ext4: sysfs: print ext4_super_block fields as little-endian
+    - ext4: reset error code in ext4_find_entry in fallback
+    - arm64: mm: check for upper PAGE_SHIFT bits in pfn_valid()
+    - KVM: arm/arm64: Skip updating PTE entry if no change
+    - KVM: arm/arm64: Skip updating PMD entry if no change
+    - x86/speculation/l1tf: Suggest what to do on systems with too much RAM
+    - x86/process: Re-export start_thread()
+    - fuse: Don't access pipe->buffers without pipe_lock()
+    - fuse: fix double request_end()
+    - fuse: fix unlocked access to processing queue
+    - fuse: umount should wait for all requests
+    - fuse: Fix oops at process_init_reply()
+    - fuse: Add missed unlock_page() to fuse_readpages_fill()
+    - udl-kms: change down_interruptible to down
+    - udl-kms: handle allocation failure
+    - udl-kms: fix crash due to uninitialized memory
+    - ASoC: dpcm: don't merge format from invalid codec dai
+    - ASoC: sirf: Fix potential NULL pointer dereference
+    - pinctrl: freescale: off by one in imx1_pinconf_group_dbg_show()
+    - x86/irqflags: Mark native_restore_fl extern inline
+    - s390: fix br_r1_trampoline for machines without exrl
+    - s390/qdio: reset old sbal_state flags
+    - kprobes: Make list and blacklist root user read only
+    - MIPS: Correct the 64-bit DSP accumulator register size
+    - MIPS: lib: Provide MIPS64r6 __multi3() for GCC < 7
+    - scsi: sysfs: Introduce sysfs_{un,}break_active_protection()
+    - scsi: core: Avoid that SCSI device removal through sysfs triggers a deadlock
+    - iscsi target: fix session creation failure handling
+    - cdrom: Fix info leak/OOB read in cdrom_ioctl_drive_status
+    - Linux 4.4.154
+
+  * Xenial update to 4.4.153 stable release (LP: #1792383)
+    - x86/mm: Fix use-after-free of ldt_struct
+    - ovl: Ensure upper filesystem supports d_type
+    - ovl: Do d_type check only if work dir creation was successful
+    - ovl: warn instead of error if d_type is not supported
+    - Linux 4.4.153
+
+  * Xenial update to 4.4.152 stable release (LP: #1792377)
+    - ARC: Explicitly add -mmedium-calls to CFLAGS
+    - netfilter: ipv6: nf_defrag: reduce struct net memory waste
+    - selftests: pstore: return Kselftest Skip code for skipped tests
+    - selftests: static_keys: return Kselftest Skip code for skipped tests
+    - selftests: user: return Kselftest Skip code for skipped tests
+    - selftests: zram: return Kselftest Skip code for skipped tests
+    - selftests: sync: add config fragment for testing sync framework
+    - ARM: dts: Cygnus: Fix I2C controller interrupt type
+    - usb: dwc2: fix isoc split in transfer with no data
+    - usb: gadget: composite: fix delayed_status race condition when set_interface
+    - usb: gadget: dwc2: fix memory leak in gadget_init()
+    - scsi: xen-scsifront: add error handling for xenbus_printf
+    - arm64: make secondary_start_kernel() notrace
+    - qed: Add sanity check for SIMD fastpath handler.
+    - enic: initialize enic->rfs_h.lock in enic_probe
+    - net: hamradio: use eth_broadcast_addr
+    - net: propagate dev_get_valid_name return code
+    - ARC: Enable machine_desc->init_per_cpu for !CONFIG_SMP
+    - net: davinci_emac: match the mdio device against its compatible if possible
+    - locking/lockdep: Do not record IRQ state within lockdep code
+    - ipv6: mcast: fix unsolicited report interval after receiving querys
+    - Smack: Mark inode instant in smack_task_to_inode
+    - cxgb4: when disabling dcb set txq dcb priority to 0
+    - brcmfmac: stop watchdog before detach and free everything
+    - ARM: dts: am437x: make edt-ft5x06 a wakeup source
+    - usb: xhci: increase CRS timeout value
+    - perf test session topology: Fix test on s390
+    - perf report powerpc: Fix crash if callchain is empty
+    - selftests/x86/sigreturn/64: Fix spurious failures on AMD CPUs
+    - ARM: dts: da850: Fix interrups property for gpio
+    - dmaengine: k3dma: Off by one in k3_of_dma_simple_xlate()
+    - md/raid10: fix that replacement cannot complete recovery after reassemble
+    - drm/exynos: gsc: Fix support for NV16/61, YUV420/YVU420 and YUV422 modes
+    - drm/exynos: decon5433: Fix per-plane global alpha for XRGB modes
+    - drm/exynos: decon5433: Fix WINCONx reset value
+    - bnx2x: Fix receiving tx-timeout in error or recovery state.
+    - m68k: fix "bad page state" oops on ColdFire boot
+    - HID: wacom: Correct touch maximum XY of 2nd-gen Intuos
+    - ARM: imx_v6_v7_defconfig: Select ULPI support
+    - ARM: imx_v4_v5_defconfig: Select ULPI support
+    - tracing: Use __printf markup to silence compiler
+    - kasan: fix shadow_size calculation error in kasan_module_alloc
+    - smsc75xx: Add workaround for gigabit link up hardware errata.
+    - netfilter: x_tables: set module owner for icmp(6) matches
+    - ARM: pxa: irq: fix handling of ICMR registers in suspend/resume
+    - ieee802154: at86rf230: switch from BUG_ON() to WARN_ON() on problem
+    - ieee802154: at86rf230: use __func__ macro for debug messages
+    - ieee802154: fakelb: switch from BUG_ON() to WARN_ON() on problem
+    - drm/armada: fix colorkey mode property
+    - bnxt_en: Fix for system hang if request_irq fails
+    - perf llvm-utils: Remove bashism from kernel include fetch script
+    - ARM: 8780/1: ftrace: Only set kernel memory back to read-only after boot
+    - ARM: dts: am3517.dtsi: Disable reference to OMAP3 OTG controller
+    - ixgbe: Be more careful when modifying MAC filters
+    - packet: reset network header if packet shorter than ll reserved space
+    - qlogic: check kstrtoul() for errors
+    - tcp: remove DELAYED ACK events in DCTCP
+    - drm/nouveau/gem: off by one bugs in nouveau_gem_pushbuf_reloc_apply()
+    - net/ethernet/freescale/fman: fix cross-build error
+    - net: usb: rtl8150: demote allmulti message to dev_dbg()
+    - net: qca_spi: Avoid packet drop during initial sync
+    - net: qca_spi: Make sure the QCA7000 reset is triggered
+    - net: qca_spi: Fix log level if probe fails
+    - tcp: identify cryptic messages as TCP seq # bugs
+    - staging: android: ion: check for kref overflow
+    - KVM: irqfd: fix race between EPOLLHUP and irq_bypass_register_consumer
+    - ext4: fix spectre gadget in ext4_mb_regular_allocator()
+    - parisc: Remove ordered stores from syscall.S
+    - xfrm_user: prevent leaking 2 bytes of kernel memory
+    - netfilter: conntrack: dccp: treat SYNC/SYNCACK as invalid if no prior state
+    - packet: refine ring v3 block size test to hold one frame
+    - bridge: Propagate vlan add failure to user
+    - parisc: Remove unnecessary barriers from spinlock.h
+    - PCI: hotplug: Don't leak pci_slot on registration failure
+    - PCI: Skip MPS logic for Virtual Functions (VFs)
+    - PCI: pciehp: Fix use-after-free on unplug
+    - i2c: imx: Fix race condition in dma read
+    - reiserfs: fix broken xattr handling (heap corruption, bad retval)
+    - Linux 4.4.152
+
+  * Xenial update to 4.4.151 stable release (LP: #1792340)
+    - dccp: fix undefined behavior with 'cwnd' shift in ccid2_cwnd_restart()
+    - l2tp: use sk_dst_check() to avoid race on sk->sk_dst_cache
+    - llc: use refcount_inc_not_zero() for llc_sap_find()
+    - net_sched: Fix missing res info when create new tc_index filter
+    - vsock: split dwork to avoid reinitializations
+    - net_sched: fix NULL pointer dereference when delete tcindex filter
+    - ALSA: hda - Sleep for 10ms after entering D3 on Conexant codecs
+    - ALSA: hda - Turn CX8200 into D3 as well upon reboot
+    - ALSA: vx222: Fix invalid endian conversions
+    - ALSA: virmidi: Fix too long output trigger loop
+    - ALSA: cs5535audio: Fix invalid endian conversion
+    - ALSA: hda: Correct Asrock B85M-ITX power_save blacklist entry
+    - ALSA: memalloc: Don't exceed over the requested size
+    - ALSA: vxpocket: Fix invalid endian conversions
+    - USB: serial: sierra: fix potential deadlock at close
+    - USB: option: add support for DW5821e
+    - ACPI: save NVS memory for Lenovo G50-45
+    - ACPI / PM: save NVS memory for ASUS 1025C laptop
+    - serial: 8250_dw: always set baud rate in dw8250_set_termios
+    - Bluetooth: avoid killing an already killed socket
+    - isdn: Disable IIOCDBGVAR
+    - Linux 4.4.151
+
+  * Xenial update to 4.4.150 stable release (LP: #1792336)
+    - x86/speculation/l1tf: Exempt zeroed PTEs from inversion
+    - Linux 4.4.150
+
+  * Xenial update to 4.4.149 stable release (LP: #1792310)
+    - x86/mm: Disable ioremap free page handling on x86-PAE
+    - tcp: Fix missing range_truesize enlargement in the backport
+    - kasan: don't emit builtin calls when sanitization is off
+    - i2c: ismt: fix wrong device address when unmap the data buffer
+    - kbuild: verify that $DEPMOD is installed
+    - crypto: vmac - require a block cipher with 128-bit block size
+    - crypto: vmac - separate tfm and request context
+    - crypto: blkcipher - fix crash flushing dcache in error path
+    - crypto: ablkcipher - fix crash flushing dcache in error path
+    - ASoC: Intel: cht_bsw_max98090_ti: Fix jack initialization
+    - ioremap: Update pgtable free interfaces with addr
+    - x86/mm: Add TLB purge to free pmd/pte page interfaces
+    - Linux 4.4.149
+
+  * Xenial update to 4.4.149 stable release (LP: #1792310) // CVE-2018-9363
+    - Bluetooth: hidp: buffer overflow in hidp_process_report
+
+  * Xenial update to 4.4.148 stable release (LP: #1792174)
+    - ext4: fix check to prevent initializing reserved inodes
+    - tpm: fix race condition in tpm_common_write()
+    - ipv4+ipv6: Make INET*_ESP select CRYPTO_ECHAINIV
+    - fork: unconditionally clear stack on fork
+    - parisc: Enable CONFIG_MLONGCALLS by default
+    - parisc: Define mb() and add memory barriers to assembler unlock sequences
+    - xen/netfront: don't cache skb_shinfo()
+    - ACPI / LPSS: Add missing prv_offset setting for byt/cht PWM devices
+    - scsi: sr: Avoid that opening a CD-ROM hangs with runtime power management
+      enabled
+    - root dentries need RCU-delayed freeing
+    - fix mntput/mntput race
+    - fix __legitimize_mnt()/mntput() race
+    - IB/core: Make testing MR flags for writability a static inline function
+    - IB/mlx4: Mark user MR as writable if actual virtual memory is writable
+    - IB/ocrdma: fix out of bounds access to local buffer
+    - ARM: dts: imx6sx: fix irq for pcie bridge
+    - kprobes/x86: Fix %p uses in error messages
+    - x86/irqflags: Provide a declaration for native_save_fl
+    - SAUCE: Sync pgtable_64.h with upstream stable
+    - mm: x86: move _PAGE_SWP_SOFT_DIRTY from bit 7 to bit 1
+    - SAUCE: Sync pgtable-3level.h with upstream stable
+    - SAUCE: Sync pgtable.h with upstream stable
+    - mm: Add vm_insert_pfn_prot()
+    - mm: fix cache mode tracking in vm_insert_mixed()
+    - x86/mm/kmmio: Make the tracer robust against L1TF
+    - x86/init: fix build with CONFIG_SWAP=n
+    - Linux 4.4.148
+
+  * Xenial update to 4.4.147 stable release (LP: #1792109)
+    - scsi: qla2xxx: Fix ISP recovery on unload
+    - scsi: qla2xxx: Return error when TMF returns
+    - genirq: Make force irq threading setup more robust
+    - nohz: Fix local_timer_softirq_pending()
+    - netlink: Do not subscribe to non-existent groups
+    - netlink: Don't shift with UB on nlk->ngroups
+    - netlink: Don't shift on 64 for ngroups
+    - ACPI / PCI: Bail early in acpi_pci_add_bus() if there is no ACPI handle
+    - ring_buffer: tracing: Inherit the tracing setting to next ring buffer
+    - i2c: imx: Fix reinit_completion() use
+    - Linux 4.4.147
+
+  * Xenial update to 4.4.146 stable release (LP: #1791953)
+    - MIPS: Fix off-by-one in pci_resource_to_user()
+    - Input: elan_i2c - add ACPI ID for lenovo ideapad 330
+    - Input: i8042 - add Lenovo LaVie Z to the i8042 reset list
+    - Input: elan_i2c - add another ACPI ID for Lenovo Ideapad 330-15AST
+    - tracing: Fix double free of event_trigger_data
+    - tracing: Fix possible double free in event_enable_trigger_func()
+    - tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure
+    - tracing: Quiet gcc warning about maybe unused link variable
+    - xen/netfront: raise max number of slots in xennet_get_responses()
+    - ALSA: emu10k1: add error handling for snd_ctl_add
+    - ALSA: fm801: add error handling for snd_ctl_add
+    - nfsd: fix potential use-after-free in nfsd4_decode_getdeviceinfo
+    - mm: vmalloc: avoid racy handling of debugobjects in vunmap
+    - mm/slub.c: add __printf verification to slab_err()
+    - rtc: ensure rtc_set_alarm fails when alarms are not supported
+    - netfilter: ipset: List timing out entries with "timeout 1" instead of zero
+    - infiniband: fix a possible use-after-free bug
+    - hvc_opal: don't set tb_ticks_per_usec in udbg_init_opal_common()
+    - powerpc/64s: Fix compiler store ordering to SLB shadow area
+    - RDMA/mad: Convert BUG_ONs to error flows
+    - disable loading f2fs module on PAGE_SIZE > 4KB
+    - f2fs: fix to don't trigger writeback during recovery
+    - usbip: usbip_detach: Fix memory, udev context and udev leak
+    - perf/x86/intel/uncore: Correct fixed counter index check in generic code
+    - perf/x86/intel/uncore: Correct fixed counter index check for NHM
+    - iwlwifi: pcie: fix race in Rx buffer allocator
+    - Bluetooth: hci_qca: Fix "Sleep inside atomic section" warning
+    - Bluetooth: btusb: Add a new Realtek 8723DE ID 2ff8:b011
+    - ASoC: dpcm: fix BE dai not hw_free and shutdown
+    - mfd: cros_ec: Fail early if we cannot identify the EC
+    - mwifiex: handle race during mwifiex_usb_disconnect
+    - wlcore: sdio: check for valid platform device data before suspend
+    - media: videobuf2-core: don't call memop 'finish' when queueing
+    - btrfs: add barriers to btrfs_sync_log before log_commit_wait wakeups
+    - btrfs: qgroup: Finish rescan when hit the last leaf of extent tree
+    - PCI: Prevent sysfs disable of device while driver is attached
+    - ath: Add regulatory mapping for FCC3_ETSIC
+    - ath: Add regulatory mapping for ETSI8_WORLD
+    - ath: Add regulatory mapping for APL13_WORLD
+    - ath: Add regulatory mapping for APL2_FCCA
+    - ath: Add regulatory mapping for Uganda
+    - ath: Add regulatory mapping for Tanzania
+    - ath: Add regulatory mapping for Serbia
+    - ath: Add regulatory mapping for Bermuda
+    - ath: Add regulatory mapping for Bahamas
+    - powerpc/32: Add a missing include header
+    - powerpc/chrp/time: Make some functions static, add missing header include
+    - powerpc/powermac: Add missing prototype for note_bootable_part()
+    - powerpc/powermac: Mark variable x as unused
+    - powerpc/8xx: fix invalid register expression in head_8xx.S
+    - pinctrl: at91-pio4: add missing of_node_put
+    - PCI: pciehp: Request control of native hotplug only if supported
+    - mwifiex: correct histogram data with appropriate index
+    - scsi: ufs: fix exception event handling
+    - ALSA: emu10k1: Rate-limit error messages about page errors
+    - regulator: pfuze100: add .is_enable() for pfuze100_swb_regulator_ops
+    - md: fix NULL dereference of mddev->pers in remove_and_add_spares()
+    - media: smiapp: fix timeout checking in smiapp_read_nvm
+    - ALSA: usb-audio: Apply rate limit to warning messages in URB complete
+      callback
+    - HID: hid-plantronics: Re-resend Update to map button for PTT products
+    - drm/radeon: fix mode_valid's return type
+    - powerpc/embedded6xx/hlwd-pic: Prevent interrupts from being handled by
+      Starlet
+    - HID: i2c-hid: check if device is there before really probing
+    - tty: Fix data race in tty_insert_flip_string_fixed_flag
+    - dma-iommu: Fix compilation when !CONFIG_IOMMU_DMA
+    - media: rcar_jpu: Add missing clk_disable_unprepare() on error in jpu_open()
+    - libata: Fix command retry decision
+    - media: saa7164: Fix driver name in debug output
+    - mtd: rawnand: fsl_ifc: fix FSL NAND driver to read all ONFI parameter pages
+    - brcmfmac: Add support for bcm43364 wireless chipset
+    - s390/cpum_sf: Add data entry sizes to sampling trailer entry
+    - perf: fix invalid bit in diagnostic entry
+    - scsi: 3w-9xxx: fix a missing-check bug
+    - scsi: 3w-xxxx: fix a missing-check bug
+    - scsi: megaraid: silence a static checker bug
+    - thermal: exynos: fix setting rising_threshold for Exynos5433
+    - bpf: fix references to free_bpf_prog_info() in comments
+    - media: siano: get rid of __le32/__le16 cast warnings
+    - drm/atomic: Handling the case when setting old crtc for plane
+    - ALSA: hda/ca0132: fix build failure when a local macro is defined
+    - memory: tegra: Do not handle spurious interrupts
+    - memory: tegra: Apply interrupts mask per SoC
+    - drm/gma500: fix psb_intel_lvds_mode_valid()'s return type
+    - ipconfig: Correctly initialise ic_nameservers
+    - rsi: Fix 'invalid vdd' warning in mmc
+    - audit: allow not equal op for audit by executable
+    - microblaze: Fix simpleImage format generation
+    - usb: hub: Don't wait for connect state at resume for powered-off ports
+    - crypto: authencesn - don't leak pointers to authenc keys
+    - crypto: authenc - don't leak pointers to authenc keys
+    - media: omap3isp: fix unbalanced dma_iommu_mapping
+    - scsi: scsi_dh: replace too broad "TP9" string with the exact models
+    - scsi: megaraid_sas: Increase timeout by 1 sec for non-RAID fastpath IOs
+    - media: si470x: fix __be16 annotations
+    - drm: Add DP PSR2 sink enable bit
+    - random: mix rdrand with entropy sent in from userspace
+    - squashfs: be more careful about metadata corruption
+    - ext4: fix inline data updates with checksums enabled
+    - ext4: check for allocation block validity with block group locked
+    - dmaengine: pxa_dma: remove duplicate const qualifier
+    - ASoC: pxa: Fix module autoload for platform drivers
+    - ipv4: remove BUG_ON() from fib_compute_spec_dst
+    - net: fix amd-xgbe flow-control issue
+    - net: lan78xx: fix rx handling before first packet is send
+    - xen-netfront: wait xenbus state change when load module manually
+    - NET: stmmac: align DMA stuff to largest cache line length
+    - tcp: do not force quickack when receiving out-of-order packets
+    - tcp: add max_quickacks param to tcp_incr_quickack and
+      tcp_enter_quickack_mode
+    - tcp: do not aggressively quick ack after ECN events
+    - tcp: refactor tcp_ecn_check_ce to remove sk type cast
+    - tcp: add one more quick ack after after ECN events
+    - inet: frag: enforce memory limits earlier
+    - net: dsa: Do not suspend/resume closed slave_dev
+    - netlink: Fix spectre v1 gadget in netlink_create()
+    - squashfs: more metadata hardening
+    - squashfs: more metadata hardenings
+    - can: ems_usb: Fix memory leak on ems_usb_disconnect()
+    - net: socket: fix potential spectre v1 gadget in socketcall
+    - virtio_balloon: fix another race between migration and ballooning
+    - kvm: x86: vmx: fix vpid leak
+    - crypto: padlock-aes - Fix Nano workaround data corruption
+    - scsi: sg: fix minor memory leak in error path
+    - Linux 4.4.146
+
+  * Xenial update to 4.4.145 stable release (LP: #1791942)
+    - MIPS: ath79: fix register address in ath79_ddr_wb_flush()
+    - ip: hash fragments consistently
+    - net/mlx4_core: Save the qpn from the input modifier in RST2INIT wrapper
+    - rtnetlink: add rtnl_link_state check in rtnl_configure_link
+    - tcp: fix dctcp delayed ACK schedule
+    - tcp: helpers to send special DCTCP ack
+    - tcp: do not cancel delay-AcK on DCTCP special ACK
+    - tcp: do not delay ACK in DCTCP upon CE status change
+    - ip: in cmsg IP(V6)_ORIGDSTADDR call pskb_may_pull
+    - usb: cdc_acm: Add quirk for Castles VEGA3000
+    - usb: core: handle hub C_PORT_OVER_CURRENT condition
+    - usb: gadget: f_fs: Only return delayed status when len is 0
+    - driver core: Partially revert "driver core: correct device's shutdown order"
+    - can: xilinx_can: fix RX loop if RXNEMP is asserted without RXOK
+    - can: xilinx_can: fix recovery from error states not being propagated
+    - can: xilinx_can: fix device dropping off bus on RX overrun
+    - can: xilinx_can: keep only 1-2 frames in TX FIFO to fix TX accounting
+    - can: xilinx_can: fix incorrect clear of non-processed interrupts
+    - can: xilinx_can: fix RX overflow interrupt not being enabled
+    - turn off -Wattribute-alias
+    - ARM: fix put_user() for gcc-8
+    - Linux 4.4.145
+
+  * kernel panic - null pointer dereference on ipset operations (LP: #1793753)
+    - netfilter: ipset: fix race condition in ipset save, swap and delete
+    - netfilter: ipset: Fix race between dump and swap
+
+  * Improvements to the kernel source package preparation (LP: #1793461)
+    - [Packaging] startnewrelease: add support for backport kernels
+
+  * update ENA driver to latest mainline version (LP: #1792044)
+    - net: ena: Remove redundant unlikely()
+    - net: ena: reduce the severity of some printouts
+    - net: ena: fix rare kernel crash when bar memory remap fails
+    - net: ena: fix wrong max Tx/Rx queues on ethtool
+    - net: ena: improve ENA driver boot time.
+    - net: ena: remove legacy suspend suspend/resume support
+    - net: ena: add power management ops to the ENA driver
+    - net: ena: add statistics for missed tx packets
+    - net: ena: add new admin define for future support of IPv6 RSS
+    - net: ena: increase ena driver version to 1.3.0
+    - net: ena: fix race condition between device reset and link up setup
+    - net: ena: add detection and recovery mechanism for handling missed/misrouted
+      MSI-X
+    - net: ena: increase ena driver version to 1.5.0
+    - net: ena: fix error handling in ena_down() sequence
+    - net: ena: Eliminate duplicate barriers on weakly-ordered archs
+    - SAUCE: ena: devm_kzalloc() -> devm_kcalloc()
+    - net: ena: Fix use of uninitialized DMA address bits field
+    - net: ena: fix surprise unplug NULL dereference kernel crash
+    - net: ena: fix driver when PAGE_SIZE == 64kB
+    - net: ena: fix device destruction to gracefully free resources
+    - net: ena: fix potential double ena_destroy_device()
+    - net: ena: fix missing lock during device destruction
+    - net: ena: fix missing calls to READ_ONCE
+    - net: ena: fix incorrect usage of memory barriers
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 02 Oct 2018 14:39:36 +0000
+
+linux (4.4.0-137.163) xenial; urgency=medium
+
+  * CVE-2018-14633
+    - iscsi target: Use hex2bin instead of a re-implementation
+
+  * CVE-2018-17182
+    - mm: get rid of vmacache_flush_all() entirely
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 24 Sep 2018 13:39:05 +0200
+
+linux (4.4.0-136.162) xenial; urgency=medium
+
+  * linux: 4.4.0-136.162 -proposed tracker (LP: #1791745)
+
+  * CVE-2017-5753
+    - bpf: properly enforce index mask to prevent out-of-bounds speculation
+    - Revert "UBUNTU: SAUCE: bpf: Use barrier_nospec() instead of osb()"
+    - Revert "bpf: prevent speculative execution in eBPF interpreter"
+
+  * L1TF mitigation not effective in some CPU and RAM combinations
+    (LP: #1788563) // CVE-2018-3620 // CVE-2018-3646
+    - x86/speculation/l1tf: Fix overflow in l1tf_pfn_limit() on 32bit
+    - x86/speculation/l1tf: Fix off-by-one error when warning that system has too
+      much RAM
+    - x86/speculation/l1tf: Increase l1tf memory limit for Nehalem+
+
+  * CVE-2018-15594
+    - x86/paravirt: Fix spectre-v2 mitigations for paravirt guests
+
+  * Xenial update to 4.4.144 stable release (LP: #1791080)
+    - KVM/Eventfd: Avoid crash when assign and deassign specific eventfd in
+      parallel.
+    - x86/MCE: Remove min interval polling limitation
+    - fat: fix memory allocation failure handling of match_strdup()
+    - ALSA: rawmidi: Change resized buffers atomically
+    - ARC: Fix CONFIG_SWAP
+    - ARC: mm: allow mprotect to make stack mappings executable
+    - mm: memcg: fix use after free in mem_cgroup_iter()
+    - ipv4: Return EINVAL when ping_group_range sysctl doesn't map to user ns
+    - ipv6: fix useless rol32 call on hash
+    - lib/rhashtable: consider param->min_size when setting initial table size
+    - net/ipv4: Set oif in fib_compute_spec_dst
+    - net: phy: fix flag masking in __set_phy_supported
+    - ptp: fix missing break in switch
+    - tg3: Add higher cpu clock for 5762.
+    - net: Don't copy pfmemalloc flag in __copy_skb_header()
+    - skbuff: Unconditionally copy pfmemalloc in __skb_clone()
+    - xhci: Fix perceived dead host due to runtime suspend race with event handler
+    - x86/paravirt: Make native_save_fl() extern inline
+    - SAUCE: Add missing CPUID_7_EDX defines
+    - SAUCE: x86/speculation: Expose indirect_branch_prediction_barrier()
+    - x86/pti: Mark constant arrays as __initconst
+    - x86/asm/entry/32: Simplify pushes of zeroed pt_regs->REGs
+    - x86/entry/64/compat: Clear registers for compat syscalls, to reduce
+      speculation attack surface
+    - x86/speculation: Clean up various Spectre related details
+    - x86/speculation: Fix up array_index_nospec_mask() asm constraint
+    - x86/xen: Zero MSR_IA32_SPEC_CTRL before suspend
+    - x86/mm: Factor out LDT init from context init
+    - x86/mm: Give each mm TLB flush generation a unique ID
+    - SAUCE: x86/speculation: Use Indirect Branch Prediction Barrier in context
+      switch
+    - x86/speculation: Use IBRS if available before calling into firmware
+    - x86/speculation: Move firmware_restrict_branch_speculation_*() from C to CPP
+    - selftest/seccomp: Fix the seccomp(2) signature
+    - xen: set cpu capabilities from xen_start_kernel()
+    - x86/amd: don't set X86_BUG_SYSRET_SS_ATTRS when running under Xen
+    - SAUCE: Preserve SPEC_CTRL MSR in new inlines
+    - SAUCE: Add Knights Mill to NO SSB list
+    - x86/process: Correct and optimize TIF_BLOCKSTEP switch
+    - x86/process: Optimize TIF_NOTSC switch
+    - Revert "x86/cpufeatures: Add FEATURE_ZEN"
+    - Revert "x86/cpu/AMD: Fix erratum 1076 (CPB bit)"
+    - x86/cpu/AMD: Fix erratum 1076 (CPB bit)
+    - x86/cpufeatures: Add FEATURE_ZEN
+    - x86/xen: Add call of speculative_store_bypass_ht_init() to PV paths
+    - x86/cpu: Re-apply forced caps every time CPU caps are re-read
+    - block: do not use interruptible wait anywhere
+    - clk: tegra: Fix PLL_U post divider and initial rate on Tegra30
+    - ubi: Introduce vol_ignored()
+    - ubi: Rework Fastmap attach base code
+    - ubi: Be more paranoid while seaching for the most recent Fastmap
+    - ubi: Fix races around ubi_refill_pools()
+    - ubi: Fix Fastmap's update_vol()
+    - ubi: fastmap: Erase outdated anchor PEBs during attach
+    - Linux 4.4.144
+
+  * CVE-2017-5715 (Spectre v2 s390x)
+    - s390: detect etoken facility
+    - s390/lib: use expoline for all bcr instructions
+    - SAUCE: s390: use expoline thunks for all branches generated by the BPF JIT
+
+  * Xenial update to 4.4.143 stable release (LP: #1790884)
+    - compiler, clang: suppress warning for unused static inline functions
+    - compiler, clang: properly override 'inline' for clang
+    - compiler, clang: always inline when CONFIG_OPTIMIZE_INLINING is disabled
+    - compiler-gcc.h: Add __attribute__((gnu_inline)) to all inline declarations
+    - x86/asm: Add _ASM_ARG* constants for argument registers to <asm/asm.h>
+    - ocfs2: subsystem.su_mutex is required while accessing the item->ci_parent
+    - bcm63xx_enet: correct clock usage
+    - bcm63xx_enet: do not write to random DMA channel on BCM6345
+    - crypto: crypto4xx - remove bad list_del
+    - crypto: crypto4xx - fix crypto4xx_build_pdr, crypto4xx_build_sdr leak
+    - atm: zatm: Fix potential Spectre v1
+    - net: dccp: avoid crash in ccid3_hc_rx_send_feedback()
+    - net: dccp: switch rx_tstamp_last_feedback to monotonic clock
+    - net/mlx5: Fix incorrect raw command length parsing
+    - net: sungem: fix rx checksum support
+    - qed: Limit msix vectors in kdump kernel to the minimum required count.
+    - r8152: napi hangup fix after disconnect
+    - tcp: fix Fast Open key endianness
+    - tcp: prevent bogus FRTO undos with non-SACK flows
+    - vhost_net: validate sock before trying to put its fd
+    - net_sched: blackhole: tell upper qdisc about dropped packets
+    - net/mlx5: Fix command interface race in polling mode
+    - net: cxgb3_main: fix potential Spectre v1
+    - rtlwifi: rtl8821ae: fix firmware is not ready to run
+    - MIPS: Call dump_stack() from show_regs()
+    - MIPS: Use async IPIs for arch_trigger_cpumask_backtrace()
+    - netfilter: ebtables: reject non-bridge targets
+    - KEYS: DNS: fix parsing multiple options
+    - rds: avoid unenecessary cong_update in loop transport
+    - net/nfc: Avoid stalls when nfc_alloc_send_skb() returned NULL.
+    - Linux 4.4.143
+
+  * Xenial update to 4.4.142 stable release (LP: #1790883)
+    - Kbuild: fix # escaping in .cmd files for future Make
+    - perf tools: Move syscall number fallbacks from perf-sys.h to
+      tools/arch/x86/include/asm/
+    - Linux 4.4.142
+
+  * Xenial update to 4.4.141 stable release (LP: #1790620)
+    - MIPS: Fix ioremap() RAM check
+    - ibmasm: don't write out of bounds in read handler
+    - vmw_balloon: fix inflation with batching
+    - ahci: Disable LPM on Lenovo 50 series laptops with a too old BIOS
+    - USB: serial: ch341: fix type promotion bug in ch341_control_in()
+    - USB: serial: cp210x: add another USB ID for Qivicon ZigBee stick
+    - USB: serial: keyspan_pda: fix modem-status error handling
+    - USB: yurex: fix out-of-bounds uaccess in read handler
+    - USB: serial: mos7840: fix status-register error handling
+    - usb: quirks: add delay quirks for Corsair Strafe
+    - xhci: xhci-mem: off by one in xhci_stream_id_to_ring()
+    - HID: usbhid: add quirk for innomedia INNEX GENESIS/ATARI adapter
+    - tools build: fix # escaping in .cmd files for future Make
+    - iw_cxgb4: correctly enforce the max reg_mr depth
+    - x86/cpufeature: Move some of the scattered feature bits to x86_capability
+    - x86/cpu: Provide a config option to disable static_cpu_has
+    - x86/fpu: Add an XSTATE_OP() macro
+    - x86/fpu: Get rid of xstate_fault()
+    - x86/headers: Don't include asm/processor.h in asm/atomic.h
+    - x86/cpufeature: Replace the old static_cpu_has() with safe variant
+    - x86/cpufeature: Get rid of the non-asm goto variant
+    - x86/alternatives: Add an auxilary section
+    - x86/alternatives: Discard dynamic check after init
+    - x86/vdso: Use static_cpu_has()
+    - x86/boot: Simplify kernel load address alignment check
+    - x86/cpufeature: Speed up cpu_feature_enabled()
+    - x86/cpufeature, x86/mm/pkeys: Add protection keys related CPUID definitions
+    - x86/mm/pkeys: Fix mismerge of protection keys CPUID bits
+    - x86/cpu: Add detection of AMD RAS Capabilities
+    - x86/cpufeature, x86/mm/pkeys: Fix broken compile-time disabling of pkeys
+    - x86/cpufeature: Make sure DISABLED/REQUIRED macros are updated
+    - x86/cpufeature: Add helper macro for mask check macros
+    - uprobes/x86: Remove incorrect WARN_ON() in uprobe_init_insn()
+    - netfilter: nf_queue: augment nfqa_cfg_policy
+    - netfilter: x_tables: initialise match/target check parameter struct
+    - loop: add recursion validation to LOOP_CHANGE_FD
+    - PM / hibernate: Fix oops at snapshot_write()
+    - SAUCE: RDMA/ucm: Blacklist UCM module
+    - loop: remember whether sysfs_create_group() was done
+    - Linux 4.4.141
+    - [Config] Refresh configs for 4.4.141
+
+  * regression with EXT4 file systems and meta_bg flag (LP: #1789653)
+    - ext4: fix false negatives *and* false positives in ext4_check_descriptors()
+
+  * CVE-2018-15572
+    - x86/speculation: Protect against userspace-userspace spectreRSB
+
+  * random oopses on s390 systems using NVMe devices (LP: #1790480)
+    - s390/pci: fix out of bounds access during irq setup
+
+  * CVE-2018-6555
+    - SAUCE: irda: Only insert new objects into the global database via setsockopt
+
+  * CVE-2018-6554
+    - SAUCE: irda: Fix memory leak caused by repeated binds of irda socket
+
+  * errors when scanning partition table of corrupted AIX disk (LP: #1787281)
+    - partitions/aix: fix usage of uninitialized lv_info and lvname structures
+    - partitions/aix: append null character to print data from disk
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 11 Sep 2018 15:50:12 +0200
+
+linux (4.4.0-135.161) xenial; urgency=medium
+
+  * linux: 4.4.0-135.161 -proposed tracker (LP: #1788766)
+
+  * [Regression] APM Merlin boards fail to recover link after interface down/up
+    (LP: #1785739)
+    - net: phylib: fix interrupts re-enablement in phy_start
+    - net: phy: fix phy_start to consider PHY_IGNORE_INTERRUPT
+
+  * qeth: don't clobber buffer on async TX completion (LP: #1786057)
+    - s390/qeth: don't clobber buffer on async TX completion
+
+  * nvme: avoid cqe corruption (LP: #1788035)
+    - nvme: avoid cqe corruption when update at the same time as read
+
+  * CacheFiles: Error: Overlong wait for old active object to go away.
+    (LP: #1776254)
+    - cachefiles: Fix missing clear of the CACHEFILES_OBJECT_ACTIVE flag
+    - cachefiles: Wait rather than BUG'ing on "Unexpected object collision"
+
+  * fscache cookie refcount updated incorrectly during fscache object allocation
+    (LP: #1776277) // fscache cookie refcount updated incorrectly during fscache
+    object allocation (LP: #1776277)
+    - fscache: Fix reference overput in fscache_attach_object() error handling
+
+  * FS-Cache: Assertion failed: FS-Cache: 6 == 5 is false (LP: #1774336)
+    - Revert "UBUNTU: SAUCE: CacheFiles: fix a read_waiter/read_copier race"
+    - fscache: Allow cancelled operations to be enqueued
+    - cachefiles: Fix refcounting bug in backing-file read monitoring
+
+  * linux-cloud-tools-common: Ensure hv-kvp-daemon.service starts before
+    walinuxagent.service (LP: #1739107)
+    - [Debian] hyper-v -- Ensure that hv-kvp-daemon.service starts before
+      walinuxagent.service
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sun, 26 Aug 2018 23:56:50 -0400
+
+linux (4.4.0-134.160) xenial; urgency=medium
+
+  * linux: 4.4.0-134.160 -proposed tracker (LP: #1787177)
+
+  * locking sockets broken due to missing AppArmor socket mediation patches
+    (LP: #1780227)
+    - UBUNTU SAUCE: apparmor: fix apparmor mediating locking non-fs, unix sockets
+
+  * Backport namespaced fscaps to xenial 4.4 (LP: #1778286)
+    - Introduce v3 namespaced file capabilities
+    - commoncap: move assignment of fs_ns to avoid null pointer dereference
+    - capabilities: fix buffer overread on very short xattr
+    - commoncap: Handle memory allocation failure.
+
+  * Xenial update to 4.4.140 stable release (LP: #1784409)
+    - usb: cdc_acm: Add quirk for Uniden UBC125 scanner
+    - USB: serial: cp210x: add CESINEL device ids
+    - USB: serial: cp210x: add Silicon Labs IDs for Windows Update
+    - n_tty: Fix stall at n_tty_receive_char_special().
+    - staging: android: ion: Return an ERR_PTR in ion_map_kernel
+    - n_tty: Access echo_* variables carefully.
+    - x86/boot: Fix early command-line parsing when matching at end
+    - ath10k: fix rfc1042 header retrieval in QCA4019 with eth decap mode
+    - i2c: rcar: fix resume by always initializing registers before transfer
+    - ipv4: Fix error return value in fib_convert_metrics()
+    - kprobes/x86: Do not modify singlestep buffer while resuming
+    - nvme-pci: initialize queue memory before interrupts
+    - netfilter: nf_tables: use WARN_ON_ONCE instead of BUG_ON in nft_do_chain()
+    - ARM: dts: imx6q: Use correct SDMA script for SPI5 core
+    - ubi: fastmap: Correctly handle interrupted erasures in EBA
+    - mm: hugetlb: yield when prepping struct pages
+    - tracing: Fix missing return symbol in function_graph output
+    - scsi: sg: mitigate read/write abuse
+    - s390: Correct register corruption in critical section cleanup
+    - drbd: fix access after free
+    - cifs: Fix infinite loop when using hard mount option
+    - jbd2: don't mark block as modified if the handle is out of credits
+    - ext4: make sure bitmaps and the inode table don't overlap with bg
+      descriptors
+    - ext4: always check block group bounds in ext4_init_block_bitmap()
+    - ext4: only look at the bg_flags field if it is valid
+    - ext4: verify the depth of extent tree in ext4_find_extent()
+    - ext4: include the illegal physical block in the bad map ext4_error msg
+    - ext4: clear i_data in ext4_inode_info when removing inline data
+    - ext4: add more inode number paranoia checks
+    - ext4: add more mount time checks of the superblock
+    - ext4: check superblock mapped prior to committing
+    - HID: i2c-hid: Fix "incomplete report" noise
+    - HID: hiddev: fix potential Spectre v1
+    - HID: debug: check length before copy_to_user()
+    - x86/mce: Detect local MCEs properly
+    - x86/mce: Fix incorrect "Machine check from unknown source" message
+    - media: cx25840: Use subdev host data for PLL override
+    - mm, page_alloc: do not break __GFP_THISNODE by zonelist reset
+    - dm bufio: avoid sleeping while holding the dm_bufio lock
+    - dm bufio: drop the lock when doing GFP_NOIO allocation
+    - mtd: rawnand: mxc: set spare area size register explicitly
+    - dm bufio: don't take the lock in dm_bufio_shrink_count
+    - mtd: cfi_cmdset_0002: Change definition naming to retry write operation
+    - mtd: cfi_cmdset_0002: Change erase functions to retry for error
+    - mtd: cfi_cmdset_0002: Change erase functions to check chip good only
+    - netfilter: nf_log: don't hold nf_log_mutex during user access
+    - staging: comedi: quatech_daqp_cs: fix no-op loop daqp_ao_insn_write()
+    - Linux 4.4.140
+
+  * Xenial update to 4.4.139 stable release (LP: #1784382)
+    - xfrm6: avoid potential infinite loop in _decode_session6()
+    - netfilter: ebtables: handle string from userspace with care
+    - ipvs: fix buffer overflow with sync daemon and service
+    - atm: zatm: fix memcmp casting
+    - net: qmi_wwan: Add Netgear Aircard 779S
+    - net/sonic: Use dma_mapping_error()
+    - Revert "Btrfs: fix scrub to repair raid6 corruption"
+    - tcp: do not overshoot window_clamp in tcp_rcv_space_adjust()
+    - Btrfs: make raid6 rebuild retry more
+    - usb: musb: fix remote wakeup racing with suspend
+    - bonding: re-evaluate force_primary when the primary slave name changes
+    - tcp: verify the checksum of the first data segment in a new connection
+    - ext4: update mtime in ext4_punch_hole even if no blocks are released
+    - ext4: fix fencepost error in check for inode count overflow during resize
+    - driver core: Don't ignore class_dir_create_and_add() failure.
+    - btrfs: scrub: Don't use inode pages for device replace
+    - ALSA: hda - Handle kzalloc() failure in snd_hda_attach_pcm_stream()
+    - ALSA: hda: add dock and led support for HP EliteBook 830 G5
+    - ALSA: hda: add dock and led support for HP ProBook 640 G4
+    - cpufreq: Fix new policy initialization during limits updates via sysfs
+    - libata: zpodd: make arrays cdb static, reduces object code size
+    - libata: zpodd: small read overflow in eject_tray()
+    - libata: Drop SanDisk SD7UB3Q*G1001 NOLPM quirk
+    - w1: mxc_w1: Enable clock before calling clk_get_rate() on it
+    - x86/spectre_v1: Disable compiler optimizations over
+      array_index_mask_nospec()
+    - m68k/mm: Adjust VM area to be unmapped by gap size for __iounmap()
+    - serial: sh-sci: Use spin_{try}lock_irqsave instead of open coding version
+    - signal/xtensa: Consistenly use SIGBUS in do_unaligned_user
+    - usb: do not reset if a low-speed or full-speed device timed out
+    - 1wire: family module autoload fails because of upper/lower case mismatch.
+    - ASoC: dapm: delete dapm_kcontrol_data paths list before freeing it
+    - ASoC: cirrus: i2s: Fix LRCLK configuration
+    - ASoC: cirrus: i2s: Fix {TX|RX}LinCtrlData setup
+    - lib/vsprintf: Remove atomic-unsafe support for %pCr
+    - mips: ftrace: fix static function graph tracing
+    - branch-check: fix long->int truncation when profiling branches
+    - ipmi:bt: Set the timeout before doing a capabilities check
+    - Bluetooth: hci_qca: Avoid missing rampatch failure with userspace fw loader
+    - fuse: atomic_o_trunc should truncate pagecache
+    - fuse: don't keep dead fuse_conn at fuse_fill_super().
+    - fuse: fix control dir setup and teardown
+    - powerpc/mm/hash: Add missing isync prior to kernel stack SLB switch
+    - powerpc/ptrace: Fix setting 512B aligned breakpoints with
+      PTRACE_SET_DEBUGREG
+    - powerpc/ptrace: Fix enforcement of DAWR constraints
+    - cpuidle: powernv: Fix promotion from snooze if next state disabled
+    - powerpc/fadump: Unregister fadump on kexec down path.
+    - ARM: 8764/1: kgdb: fix NUMREGBYTES so that gdb_regs[] is the correct size
+    - of: unittest: for strings, account for trailing \0 in property length field
+    - IB/qib: Fix DMA api warning with debug kernel
+    - RDMA/mlx4: Discard unknown SQP work requests
+    - mtd: cfi_cmdset_0002: Change write buffer to check correct value
+    - mtd: cfi_cmdset_0002: Use right chip in do_ppb_xxlock()
+    - mtd: cfi_cmdset_0002: fix SEGV unlocking multiple chips
+    - mtd: cfi_cmdset_0002: Fix unlocking requests crossing a chip boudary
+    - mtd: cfi_cmdset_0002: Avoid walking all chips when unlocking.
+    - MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum
+    - PCI: pciehp: Clear Presence Detect and Data Link Layer Status Changed on
+      resume
+    - MIPS: io: Add barrier after register read in inX()
+    - time: Make sure jiffies_to_msecs() preserves non-zero time periods
+    - Btrfs: fix clone vs chattr NODATASUM race
+    - iio:buffer: make length types match kfifo types
+    - scsi: qla2xxx: Fix setting lower transfer speed if GPSC fails
+    - scsi: zfcp: fix missing SCSI trace for result of eh_host_reset_handler
+    - scsi: zfcp: fix missing SCSI trace for retry of abort / scsi_eh TMF
+    - scsi: zfcp: fix misleading REC trigger trace where erp_action setup failed
+    - scsi: zfcp: fix missing REC trigger trace on terminate_rport_io early return
+    - scsi: zfcp: fix missing REC trigger trace on terminate_rport_io for
+      ERP_FAILED
+    - scsi: zfcp: fix missing REC trigger trace for all objects in ERP_FAILED
+    - scsi: zfcp: fix missing REC trigger trace on enqueue without ERP thread
+    - linvdimm, pmem: Preserve read-only setting for pmem devices
+    - md: fix two problems with setting the "re-add" device state.
+    - ubi: fastmap: Cancel work upon detach
+    - UBIFS: Fix potential integer overflow in allocation
+    - xfrm: skip policies marked as dead while rehashing
+    - backlight: as3711_bl: Fix Device Tree node lookup
+    - backlight: max8925_bl: Fix Device Tree node lookup
+    - backlight: tps65217_bl: Fix Device Tree node lookup
+    - mfd: intel-lpss: Program REMAP register in PIO mode
+    - perf tools: Fix symbol and object code resolution for vdso32 and vdsox32
+    - perf intel-pt: Fix sync_switch INTEL_PT_SS_NOT_TRACING
+    - perf intel-pt: Fix decoding to accept CBR between FUP and corresponding TIP
+    - perf intel-pt: Fix MTC timing after overflow
+    - perf intel-pt: Fix "Unexpected indirect branch" error
+    - perf intel-pt: Fix packet decoding of CYC packets
+    - media: v4l2-compat-ioctl32: prevent go past max size
+    - media: dvb_frontend: fix locking issues at dvb_frontend_get_event()
+    - nfsd: restrict rd_maxcount to svc_max_payload in nfsd_encode_readdir
+    - NFSv4: Fix possible 1-byte stack overflow in
+      nfs_idmap_read_and_verify_message
+    - video: uvesafb: Fix integer overflow in allocation
+    - Input: elan_i2c - add ELAN0618 (Lenovo v330 15IKB) ACPI ID
+    - xen: Remove unnecessary BUG_ON from __unbind_from_irq()
+    - udf: Detect incorrect directory size
+    - Input: elan_i2c_smbus - fix more potential stack buffer overflows
+    - Input: elantech - enable middle button of touchpads on ThinkPad P52
+    - Input: elantech - fix V4 report decoding for module with middle key
+    - ALSA: hda/realtek - Add a quirk for FSC ESPRIMO U9210
+    - Btrfs: fix unexpected cow in run_delalloc_nocow
+    - spi: Fix scatterlist elements size in spi_map_buf
+    - block: Fix transfer when chunk sectors exceeds max
+    - dm thin: handle running out of data space vs concurrent discard
+    - cdc_ncm: avoid padding beyond end of skb
+    - Bluetooth: Fix connection if directed advertising and privacy is used
+    - Linux 4.4.139
+
+  * Support AverMedia DVD EZMaker 7 USB video capture dongle (LP: #1620762) //
+    Xenial update to 4.4.139 stable release (LP: #1784382)
+    - media: cx231xx: Add support for AverMedia DVD EZMaker 7
+
+  * vfio/pci: cannot assign a i40e pf device to a vm using vfio-pci
+    (LP: #1779830)
+    - vfio/pci: Hide broken INTx support from user
+
+  * Kernel error "task zfs:pid blocked for more than 120 seconds" (LP: #1781364)
+    - SAUCE: (noup) zfs to 0.6.5.6-0ubuntu25
+
+  * Allow multiple mounts of zfs datasets (LP: #1759848)
+    - SAUCE: Allow mounting datasets more than once (LP: #1759848)
+
+  * CVE-2018-12233
+    - jfs: Fix inconsistency between memory allocation and ea_buf->max_size
+
+  * Redpine: Observed kernel panic while running wireless tests in regression
+    mode (LP: #1773410) // Redpine: Observed kernel panic while running soft-ap
+    tests (LP: #1777850)
+    - SAUCE: Redpine: improve cancel_hw_scan handling to fix kernel panic
+
+  * [HMS] Upgrades to Support SocketCAN over USB on Dell IoT 300x Gateways
+    (LP: #1783241)
+    - SAUCE: (no-up) upgrade IXXAT USB SocketCAN driver
+
+  * CVE-2018-13094
+    - xfs: don't call xfs_da_shrink_inode with NULL bp
+
+  * other users' coredumps can be read via setgid directory and killpriv bypass
+    (LP: #1779923) // CVE-2018-13405
+    - Fix up non-directory creation in SGID directories
+
+  * snapcraft.yaml: missing ubuntu-retpoline-extract-one script breaks the build
+    (LP: #1782116)
+    - snapcraft.yaml: copy retpoline-extract-one to scripts before build
+
+  * Enable basic support for Solarflare 8000 series NIC (LP: #1783152)
+    - sfc: make TSO version a per-queue parameter
+    - sfc: Add PCI ID for Solarflare 8000 series 10/40G NIC
+
+  * Redpine: Observed kernel panic while running wireless regressions tests
+    (LP: #1777858)
+    - SAUCE: Redpine: improve kernel thread handling to fix kernel panic
+
+  * Xenial update to 4.4.138 stable release (LP: #1777389)
+    - x86: Remove unused function cpu_has_ht_siblings()
+    - x86/cpufeature: Remove unused and seldomly used cpu_has_xx macros
+    - x86/fpu: Disable AVX when eagerfpu is off
+    - x86/fpu: Revert ("x86/fpu: Disable AVX when eagerfpu is off")
+    - x86/fpu: Hard-disable lazy FPU mode
+    - af_key: Always verify length of provided sadb_key
+    - x86/crypto, x86/fpu: Remove X86_FEATURE_EAGER_FPU #ifdef from the crc32c
+      code
+    - gpio: No NULL owner
+    - Clarify (and fix) MAX_LFS_FILESIZE macros
+    - serial: samsung: fix maxburst parameter for DMA transactions
+    - vmw_balloon: fixing double free when batching mode is off
+    - Input: goodix - add new ACPI id for GPD Win 2 touch screen
+    - crypto: vmx - Remove overly verbose printk from AES init routines
+    - Linux 4.4.138
+
+  * Redpine: wifi-ap stopped working after restart (LP: #1773400)
+    - SAUCE: Redpine: fix soft-ap invisible issue
+
+  * Xenial update to 4.4.137 stable release (LP: #1777063)
+    - tpm: do not suspend/resume if power stays on
+    - tpm: self test failure should not cause suspend to fail
+    - mmap: introduce sane default mmap limits
+    - mmap: relax file size limit for regular files
+    - kconfig: Avoid format overflow warning from GCC 8.1
+    - xfs: fix incorrect log_flushed on fsync
+    - drm: set FMODE_UNSIGNED_OFFSET for drm files
+    - brcmfmac: Fix check for ISO3166 code
+    - bnx2x: use the right constant
+    - dccp: don't free ccid2_hc_tx_sock struct in dccp_disconnect()
+    - enic: set DMA mask to 47 bit
+    - ip6mr: only set ip6mr_table from setsockopt when ip6mr_new_table succeeds
+    - ipv4: remove warning in ip_recv_error
+    - isdn: eicon: fix a missing-check bug
+    - netdev-FAQ: clarify DaveM's position for stable backports
+    - net/packet: refine check for priv area size
+    - net: usb: cdc_mbim: add flag FLAG_SEND_ZLP
+    - packet: fix reserve calculation
+    - qed: Fix mask for physical address in ILT entry
+    - net/mlx4: Fix irq-unsafe spinlock usage
+    - team: use netdev_features_t instead of u32
+    - rtnetlink: validate attributes in do_setlink()
+    - net: phy: broadcom: Fix bcm_write_exp()
+    - net: metrics: add proper netlink validation
+    - Linux 4.4.137
+
+  * Xenial update to 4.4.136 stable release (LP: #1776177)
+    - arm64: lse: Add early clobbers to some input/output asm operands
+    - powerpc/64s: Clear PCR on boot
+    - USB: serial: cp210x: use tcflag_t to fix incompatible pointer type
+    - sh: New gcc support
+    - xfs: detect agfl count corruption and reset agfl
+    - Input: elan_i2c_smbus - fix corrupted stack
+    - tracing: Fix crash when freeing instances with event triggers
+    - selinux: KASAN: slab-out-of-bounds in xattr_getsecurity
+    - cfg80211: further limit wiphy names to 64 bytes
+    - rtlwifi: rtl8192cu: Remove variable self-assignment in rf.c
+    - ASoC: Intel: sst: remove redundant variable dma_dev_name
+    - irda: fix overly long udelay()
+    - tcp: avoid integer overflows in tcp_rcv_space_adjust()
+    - i2c: rcar: make sure clocks are on when doing clock calculation
+    - i2c: rcar: rework hw init
+    - i2c: rcar: remove unused IOERROR state
+    - i2c: rcar: remove spinlock
+    - i2c: rcar: refactor setup of a msg
+    - i2c: rcar: init new messages in irq
+    - i2c: rcar: don't issue stop when HW does it automatically
+    - i2c: rcar: check master irqs before slave irqs
+    - i2c: rcar: revoke START request early
+    - dmaengine: usb-dmac: fix endless loop in usb_dmac_chan_terminate_all()
+    - iio:kfifo_buf: check for uint overflow
+    - MIPS: ptrace: Fix PTRACE_PEEKUSR requests for 64-bit FGRs
+    - MIPS: prctl: Disallow FRE without FR with PR_SET_FP_MODE requests
+    - scsi: scsi_transport_srp: Fix shost to rport translation
+    - stm class: Use vmalloc for the master map
+    - hwtracing: stm: fix build error on some arches
+    - drm/i915: Disable LVDS on Radiant P845
+    - Kbuild: change CC_OPTIMIZE_FOR_SIZE definition
+    - [Config] Add CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+    - fix io_destroy()/aio_complete() race
+    - mm: fix the NULL mapping case in __isolate_lru_page()
+    - sparc64: Fix build warnings with gcc 7.
+    - Linux 4.4.136
+
+  * Xenial update to 4.4.135 stable release (LP: #1776158)
+    - Revert "vti4: Don't override MTU passed on link creation via IFLA_MTU"
+    - Linux 4.4.135
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 15 Aug 2018 13:51:11 +0000
+
+linux (4.4.0-133.159) xenial; urgency=medium
+
+  * CVE-2018-5390
+    - tcp: avoid collapses in tcp_prune_queue() if possible
+    - tcp: detect malicious patterns in tcp_collapse_ofo_queue()
+
+  * CVE-2018-5391
+    - Revert "net: increase fragment memory usage limits"
+
+  * CVE-2018-3620 // CVE-2018-3646
+    - KVM: x86: introduce linear_{read,write}_system
+    - KVM: x86: pass kvm_vcpu to kvm_read_guest_virt and
+      kvm_write_guest_virt_system
+    - kvm: x86: use correct privilege level for sgdt/sidt/fxsave/fxrstor access
+    - x86/speculation/l1tf: Increase 32bit PAE __PHYSICAL_PAGE_SHIFT
+    - x86/speculation/l1tf: Change order of offset/type in swap entry
+    - x86/speculation/l1tf: Protect swap entries against L1TF
+    - x86/mm: Simplify p[g4um]d_page() macros
+    - x86/speculation/l1tf: Protect PROT_NONE PTEs against speculation
+    - x86/speculation/l1tf: Make sure the first page is always reserved
+    - SAUCE: x86/cpu: Add Knights Mill/Gemini Lake
+    - x86/speculation/l1tf: Add sysfs reporting for l1tf
+    - x86/speculation/l1tf: Disallow non privileged high MMIO PROT_NONE mappings
+    - x86/speculation/l1tf: Limit swap file size to MAX_PA/2
+    - x86/smp: Provide topology_is_primary_thread()
+    - x86/topology: Provide topology_smt_supported()
+    - cpu/hotplug: Split do_cpu_down()
+    - x86/topology: Add topology_max_smt_threads()
+    - cpu/hotplug: Provide knobs to control SMT
+    - x86/CPU: Modify detect_extended_topology() to return result
+    - x86/cpu: Remove the pointless CPU printout
+    - x86/cpu/AMD: Remove the pointless detect_ht() call
+    - x86/cpu/common: Provide detect_ht_early()
+    - x86/cpu/topology: Provide detect_extended_topology_early()
+    - x86/cpu/intel: Evaluate smp_num_siblings early
+    - x86/cpu/AMD: Evaluate smp_num_siblings early
+    - x86/apic: Ignore secondary threads if nosmt=force
+    - x86/speculation/l1tf: Extend 64bit swap file size limit
+    - x86/CPU/AMD: Move TOPOEXT reenablement before reading smp_num_siblings
+    - x86/cpufeatures: Add detection of L1D cache flush support.
+    - x86/speculation/l1tf: Protect PAE swap entries against L1TF
+    - x86/speculation/l1tf: Fix up pte->pfn conversion for PAE
+    - Revert "x86/apic: Ignore secondary threads if nosmt=force"
+    - SAUCE: x86/mce: register mce notifier earlier
+    - cpu/hotplug: Boot HT siblings at least once
+    - KVM: x86: Introducing kvm_x86_ops VM init/destroy hooks
+    - x86/KVM: Warn user if KVM is loaded SMT and L1TF CPU bug being present.
+    - x86/KVM/VMX: Add module argument for L1TF mitigation
+    - x86/KVM/VMX: Add L1D flush algorithm
+    - x86/KVM/VMX: Add L1D MSR based flush
+    - x86/KVM/VMX: Add L1D flush logic
+    - x86/KVM/VMX: Split the VMX MSR LOAD structures to have an host/guest numbers
+    - x86/KVM/VMX: Add find_msr() helper function
+    - x86/KVM/VMX: Seperate the VMX AUTOLOAD guest/host number accounting.
+    - x86/KVM/VMX: Extend add_atomic_switch_msr() to allow VMENTER only MSRs
+    - x86/KVM/VMX: Use MSR save list for IA32_FLUSH_CMD if required
+    - cpu/hotplug: Online siblings when SMT control is turned on
+    - x86/litf: Introduce vmx status variable
+    - x86/kvm: Drop L1TF MSR list approach
+    - x86/l1tf: Handle EPT disabled state proper
+    - x86/kvm: Move l1tf setup function
+    - x86/kvm: Add static key for flush always
+    - x86/kvm: Serialize L1D flush parameter setter
+    - x86/kvm: Allow runtime control of L1D flush
+    - cpu/hotplug: Expose SMT control init function
+    - cpu/hotplug: Set CPU_SMT_NOT_SUPPORTED early
+    - x86/bugs, kvm: Introduce boot-time control of L1TF mitigations
+    - Documentation: Add section about CPU vulnerabilities
+    - x86/speculation/l1tf: Unbreak !__HAVE_ARCH_PFN_MODIFY_ALLOWED architectures
+    - x86/KVM/VMX: Initialize the vmx_l1d_flush_pages' content
+    - Documentation/l1tf: Fix typos
+    - cpu/hotplug: detect SMT disabled by BIOS
+    - x86/KVM/VMX: Don't set l1tf_flush_l1d to true from vmx_l1d_flush()
+    - x86/KVM/VMX: Replace 'vmx_l1d_flush_always' with 'vmx_l1d_flush_cond'
+    - x86/KVM/VMX: Move the l1tf_flush_l1d test to vmx_l1d_flush()
+    - x86/irq: Demote irq_cpustat_t::__softirq_pending to u16
+    - x86/KVM/VMX: Introduce per-host-cpu analogue of l1tf_flush_l1d
+    - x86: Don't include linux/irq.h from asm/hardirq.h
+    - x86/apic: Order irq_enter/exit() calls correctly vs. ack_APIC_irq()
+    - x86/irq: Let interrupt handlers set kvm_cpu_l1tf_flush_l1d
+    - x86/KVM/VMX: Don't set l1tf_flush_l1d from vmx_handle_external_intr()
+    - Documentation/l1tf: Remove Yonah processors from not vulnerable list
+    - x86/speculation: Simplify sysfs report of VMX L1TF vulnerability
+    - x86/speculation: Use ARCH_CAPABILITIES to skip L1D flush on vmentry
+    - KVM/VMX: Emulate MSR_IA32_ARCH_CAPABILITIES
+    - KVM: x86: Add a framework for supporting MSR-based features
+    - KVM: X86: Introduce kvm_get_msr_feature()
+    - KVM: VMX: support MSR_IA32_ARCH_CAPABILITIES as a feature MSR
+    - KVM: VMX: Tell the nested hypervisor to skip L1D flush on vmentry
+    - cpu/hotplug: Fix SMT supported evaluation
+    - x86/speculation/l1tf: Invert all not present mappings
+    - x86/speculation/l1tf: Make pmd/pud_mknotpresent() invert
+    - x86/mm/pat: Ensure cpa->pfn only contains page frame numbers
+    - SAUCE: Add pfn_pud() and pud_mkhuge()
+    - x86/mm/pat: Make set_memory_np() L1TF safe
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 08 Aug 2018 12:04:38 +0200
+
+linux (4.4.0-131.157) xenial; urgency=medium
+
+  * linux: 4.4.0-131.157 -proposed tracker (LP: #1779376)
+
+  * Cannot set MTU higher than 1500 in Xen instance (LP: #1781413)
+    - xen-netfront: Fix mismatched rtnl_unlock
+    - xen-netfront: Update features after registering netdev
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 18 Jun 2018 17:00:46 +0200
+
+linux (4.4.0-130.156) xenial; urgency=medium
+
+  * linux: 4.4.0-130.156 -proposed tracker (LP: #1776822)
+
+  * CVE-2018-3665 (x86)
+    - x86/fpu: Fix early FPU command-line parsing
+    - x86/fpu: Fix 'no387' regression
+    - x86/fpu: Disable MPX when eagerfpu is off
+    - x86/fpu: Default eagerfpu=on on all CPUs
+    - x86/fpu: Fix FNSAVE usage in eagerfpu mode
+    - x86/fpu: Fix math emulation in eager fpu mode
+    - x86/fpu: Fix eager-FPU handling on legacy FPU machines
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 14 Jun 2018 06:53:41 +0200
+
+linux (4.4.0-129.155) xenial; urgency=medium
+
+  * linux: 4.4.0-129.155 -proposed tracker (LP: #1776352)
+
+  * Xenial update to 4.4.134 stable release (LP: #1775771)
+    - MIPS: ptrace: Expose FIR register through FP regset
+    - MIPS: Fix ptrace(2) PTRACE_PEEKUSR and PTRACE_POKEUSR accesses to o32 FGRs
+    - KVM: Fix spelling mistake: "cop_unsuable" -> "cop_unusable"
+    - affs_lookup(): close a race with affs_remove_link()
+    - aio: fix io_destroy(2) vs. lookup_ioctx() race
+    - ALSA: timer: Fix pause event notification
+    - mmc: sdhci-iproc: fix 32bit writes for TRANSFER_MODE register
+    - libata: Blacklist some Sandisk SSDs for NCQ
+    - libata: blacklist Micron 500IT SSD with MU01 firmware
+    - xen-swiotlb: fix the check condition for xen_swiotlb_free_coherent
+    - Revert "ipc/shm: Fix shmat mmap nil-page protection"
+    - ipc/shm: fix shmat() nil address after round-down when remapping
+    - kasan: fix memory hotplug during boot
+    - kernel/sys.c: fix potential Spectre v1 issue
+    - kernel/signal.c: avoid undefined behaviour in kill_something_info
+    - xfs: remove racy hasattr check from attr ops
+    - do d_instantiate/unlock_new_inode combinations safely
+    - firewire-ohci: work around oversized DMA reads on JMicron controllers
+    - NFSv4: always set NFS_LOCK_LOST when a lock is lost.
+    - ALSA: hda - Use IS_REACHABLE() for dependency on input
+    - ASoC: au1x: Fix timeout tests in au1xac97c_ac97_read()
+    - kvm: x86: fix KVM_XEN_HVM_CONFIG ioctl
+    - tracing/hrtimer: Fix tracing bugs by taking all clock bases and modes into
+      account
+    - PCI: Add function 1 DMA alias quirk for Marvell 9128
+    - tools lib traceevent: Simplify pointer print logic and fix %pF
+    - perf callchain: Fix attr.sample_max_stack setting
+    - tools lib traceevent: Fix get_field_str() for dynamic strings
+    - dm thin: fix documentation relative to low water mark threshold
+    - nfs: Do not convert nfs_idmap_cache_timeout to jiffies
+    - watchdog: sp5100_tco: Fix watchdog disable bit
+    - kconfig: Don't leak main menus during parsing
+    - kconfig: Fix automatic menu creation mem leak
+    - kconfig: Fix expr_free() E_NOT leak
+    - ipmi/powernv: Fix error return code in ipmi_powernv_probe()
+    - Btrfs: set plug for fsync
+    - btrfs: Fix out of bounds access in btrfs_search_slot
+    - Btrfs: fix scrub to repair raid6 corruption
+    - scsi: fas216: fix sense buffer initialization
+    - HID: roccat: prevent an out of bounds read in kovaplus_profile_activated()
+    - jffs2: Fix use-after-free bug in jffs2_iget()'s error handling path
+    - powerpc/numa: Use ibm,max-associativity-domains to discover possible nodes
+    - powerpc/numa: Ensure nodes initialized for hotplug
+    - RDMA/mlx5: Avoid memory leak in case of XRCD dealloc failure
+    - ntb_transport: Fix bug with max_mw_size parameter
+    - ocfs2: return -EROFS to mount.ocfs2 if inode block is invalid
+    - ocfs2/acl: use 'ip_xattr_sem' to protect getting extended attribute
+    - ocfs2: return error when we attempt to access a dirty bh in jbd2
+    - mm/mempolicy: fix the check of nodemask from user
+    - mm/mempolicy: add nodes_empty check in SYSC_migrate_pages
+    - asm-generic: provide generic_pmdp_establish()
+    - mm: pin address_space before dereferencing it while isolating an LRU page
+    - IB/ipoib: Fix for potential no-carrier state
+    - x86/power: Fix swsusp_arch_resume prototype
+    - firmware: dmi_scan: Fix handling of empty DMI strings
+    - ACPI: processor_perflib: Do not send _PPC change notification if not ready
+    - MIPS: TXx9: use IS_BUILTIN() for CONFIG_LEDS_CLASS
+    - xen-netfront: Fix race between device setup and open
+    - xen/grant-table: Use put_page instead of free_page
+    - RDS: IB: Fix null pointer issue
+    - arm64: spinlock: Fix theoretical trylock() A-B-A with LSE atomics
+    - proc: fix /proc/*/map_files lookup
+    - cifs: silence compiler warnings showing up with gcc-8.0.0
+    - bcache: properly set task state in bch_writeback_thread()
+    - bcache: fix for allocator and register thread race
+    - bcache: fix for data collapse after re-attaching an attached device
+    - bcache: return attach error when no cache set exist
+    - tools/libbpf: handle issues with bpf ELF objects containing .eh_frames
+    - locking/qspinlock: Ensure node->count is updated before initialising node
+    - irqchip/gic-v3: Change pr_debug message to pr_devel
+    - scsi: ufs: Enable quirk to ignore sending WRITE_SAME command
+    - scsi: bnx2fc: Fix check in SCSI completion handler for timed out request
+    - scsi: sym53c8xx_2: iterator underflow in sym_getsync()
+    - scsi: mptfusion: Add bounds check in mptctl_hp_targetinfo()
+    - scsi: qla2xxx: Avoid triggering undefined behavior in
+      qla2x00_mbx_completion()
+    - ARC: Fix malformed ARC_EMUL_UNALIGNED default
+    - usb: gadget: f_uac2: fix bFirstInterface in composite gadget
+    - usb: gadget: fsl_udc_core: fix ep valid checks
+    - usb: dwc2: Fix dwc2_hsotg_core_init_disconnected()
+    - selftests: memfd: add config fragment for fuse
+    - scsi: storvsc: Increase cmd_per_lun for higher speed devices
+    - scsi: aacraid: fix shutdown crash when init fails
+    - scsi: qla4xxx: skip error recovery in case of register disconnect.
+    - ARM: OMAP2+: timer: fix a kmemleak caused in omap_get_timer_dt
+    - ARM: OMAP3: Fix prm wake interrupt for resume
+    - ARM: OMAP1: clock: Fix debugfs_create_*() usage
+    - NFC: llcp: Limit size of SDP URI
+    - mac80211: round IEEE80211_TX_STATUS_HEADROOM up to multiple of 4
+    - md raid10: fix NULL deference in handle_write_completed()
+    - drm/exynos: fix comparison to bitshift when dealing with a mask
+    - usb: musb: fix enumeration after resume
+    - locking/xchg/alpha: Add unconditional memory barrier to cmpxchg()
+    - md: raid5: avoid string overflow warning
+    - kernel/relay.c: limit kmalloc size to KMALLOC_MAX_SIZE
+    - powerpc/bpf/jit: Fix 32-bit JIT for seccomp_data access
+    - s390/cio: fix return code after missing interrupt
+    - s390/cio: clear timer when terminating driver I/O
+    - ARM: OMAP: Fix dmtimer init for omap1
+    - smsc75xx: fix smsc75xx_set_features()
+    - regulatory: add NUL to request alpha2
+    - locking/xchg/alpha: Fix xchg() and cmpxchg() memory ordering bugs
+    - x86/topology: Update the 'cpu cores' field in /proc/cpuinfo correctly across
+      CPU hotplug operations
+    - media: dmxdev: fix error code for invalid ioctls
+    - md/raid1: fix NULL pointer dereference
+    - batman-adv: fix packet checksum in receive path
+    - batman-adv: invalidate checksum on fragment reassembly
+    - netfilter: ebtables: convert BUG_ONs to WARN_ONs
+    - nvme-pci: Fix nvme queue cleanup if IRQ setup fails
+    - clocksource/drivers/fsl_ftm_timer: Fix error return checking
+    - r8152: fix tx packets accounting
+    - virtio-gpu: fix ioctl and expose the fixed status to userspace.
+    - dmaengine: rcar-dmac: fix max_chunk_size for R-Car Gen3
+    - bcache: fix kcrashes with fio in RAID5 backend dev
+    - sit: fix IFLA_MTU ignored on NEWLINK
+    - gianfar: Fix Rx byte accounting for ndev stats
+    - net/tcp/illinois: replace broken algorithm reference link
+    - xen/pirq: fix error path cleanup when binding MSIs
+    - Btrfs: send, fix issuing write op when processing hole in no data mode
+    - selftests/powerpc: Skip the subpage_prot tests if the syscall is unavailable
+    - KVM: PPC: Book3S HV: Fix VRMA initialization with 2MB or 1GB memory backing
+    - watchdog: f71808e_wdt: Fix magic close handling
+    - e1000e: Fix check_for_link return value with autoneg off
+    - e1000e: allocate ring descriptors with dma_zalloc_coherent
+    - usb: musb: call pm_runtime_{get,put}_sync before reading vbus registers
+    - scsi: mpt3sas: Do not mark fw_event workqueue as WQ_MEM_RECLAIM
+    - scsi: sd: Keep disk read-only when re-reading partition
+    - fbdev: Fixing arbitrary kernel leak in case FBIOGETCMAP_SPARC in
+      sbusfb_ioctl_helper().
+    - xen: xenbus: use put_device() instead of kfree()
+    - USB: OHCI: Fix NULL dereference in HCDs using HCD_LOCAL_MEM
+    - netfilter: ebtables: fix erroneous reject of last rule
+    - bnxt_en: Check valid VNIC ID in bnxt_hwrm_vnic_set_tpa().
+    - workqueue: use put_device() instead of kfree()
+    - ipv4: lock mtu in fnhe when received PMTU < net.ipv4.route.min_pmtu
+    - sunvnet: does not support GSO for sctp
+    - net: Fix vlan untag for bridge and vlan_dev with reorder_hdr off
+    - batman-adv: fix header size check in batadv_dbg_arp()
+    - vti4: Don't count header length twice on tunnel setup
+    - vti4: Don't override MTU passed on link creation via IFLA_MTU
+    - perf/cgroup: Fix child event counting bug
+    - RDMA/ucma: Correct option size check using optlen
+    - mm/mempolicy.c: avoid use uninitialized preferred_node
+    - selftests: ftrace: Add probe event argument syntax testcase
+    - selftests: ftrace: Add a testcase for string type with kprobe_event
+    - selftests: ftrace: Add a testcase for probepoint
+    - batman-adv: fix multicast-via-unicast transmission with AP isolation
+    - batman-adv: fix packet loss for broadcasted DHCP packets to a server
+    - ARM: 8748/1: mm: Define vdso_start, vdso_end as array
+    - net: qmi_wwan: add BroadMobi BM806U 2020:2033
+    - net/usb/qmi_wwan.c: Add USB id for lt4120 modem
+    - net-usb: add qmi_wwan if on lte modem wistron neweb d18q1
+    - llc: properly handle dev_queue_xmit() return value
+    - mm/kmemleak.c: wait for scan completion before disabling free
+    - net: Fix untag for vlan packets without ethernet header
+    - net: mvneta: fix enable of all initialized RXQs
+    - sh: fix debug trap failure to process signals before return to user
+    - x86/pgtable: Don't set huge PUD/PMD on non-leaf entries
+    - fs/proc/proc_sysctl.c: fix potential page fault while unregistering sysctl
+      table
+    - swap: divide-by-zero when zero length swap file on ssd
+    - sr: get/drop reference to device in revalidate and check_events
+    - Force log to disk before reading the AGF during a fstrim
+    - cpufreq: CPPC: Initialize shared perf capabilities of CPUs
+    - scsi: aacraid: Insure command thread is not recursively stopped
+    - dp83640: Ensure against premature access to PHY registers after reset
+    - mm/ksm: fix interaction with THP
+    - mm: fix races between address_space dereference and free in page_evicatable
+    - Btrfs: bail out on error during replay_dir_deletes
+    - Btrfs: fix NULL pointer dereference in log_dir_items
+    - btrfs: Fix possible softlock on single core machines
+    - ocfs2/dlm: don't handle migrate lockres if already in shutdown
+    - sched/rt: Fix rq->clock_update_flags < RQCF_ACT_SKIP warning
+    - KVM: VMX: raise internal error for exception during invalid protected mode
+      state
+    - fscache: Fix hanging wait on page discarded by writeback
+    - sparc64: Make atomic_xchg() an inline function rather than a macro.
+    - rtc: snvs: Fix usage of snvs_rtc_enable
+    - net: bgmac: Fix endian access in bgmac_dma_tx_ring_free()
+    - Bluetooth: btusb: Add USB ID 7392:a611 for Edimax EW-7611ULB
+    - btrfs: tests/qgroup: Fix wrong tree backref level
+    - Btrfs: fix copy_items() return value when logging an inode
+    - btrfs: fix lockdep splat in btrfs_alloc_subvolume_writers
+    - xen/acpi: off by one in read_acpi_id()
+    - ACPI: acpi_pad: Fix memory leak in power saving threads
+    - powerpc/mpic: Check if cpu_possible() in mpic_physmask()
+    - m68k: set dma and coherent masks for platform FEC ethernets
+    - parisc/pci: Switch LBA PCI bus from Hard Fail to Soft Fail mode
+    - hwmon: (nct6775) Fix writing pwmX_mode
+    - rtc: hctosys: Ensure system time doesn't overflow time_t
+    - powerpc/perf: Prevent kernel address leak to userspace via BHRB buffer
+    - powerpc/perf: Fix kernel address leak via sampling registers
+    - tools/thermal: tmon: fix for segfault
+    - selftests: Print the test we're running to /dev/kmsg
+    - net/mlx5: Protect from command bit overflow
+    - ath10k: Fix kernel panic while using worker (ath10k_sta_rc_update_wk)
+    - ima: Fix Kconfig to select TPM 2.0 CRB interface
+    - [Config] CONFIG_TCG_CRB=y
+    - ima: Fallback to the builtin hash algorithm
+    - arm: dts: socfpga: fix GIC PPI warning
+    - usb: dwc3: Update DWC_usb31 GTXFIFOSIZ reg fields
+    - cpufreq: cppc_cpufreq: Fix cppc_cpufreq_init() failure path
+    - clk: Don't show the incorrect clock phase
+    - zorro: Set up z->dev.dma_mask for the DMA API
+    - bcache: quit dc->writeback_thread when BCACHE_DEV_DETACHING is set
+    - ACPICA: Events: add a return on failure from acpi_hw_register_read
+    - ACPICA: acpi: acpica: fix acpi operand cache leak in nseval.c
+    - i2c: mv64xxx: Apply errata delay only in standard mode
+    - KVM: lapic: stop advertising DIRECTED_EOI when in-kernel IOAPIC is in use
+    - xhci: zero usb device slot_id member when disabling and freeing a xhci slot
+    - MIPS: ath79: Fix AR724X_PLL_REG_PCIE_CONFIG offset
+    - PCI: Restore config space on runtime resume despite being unbound
+    - ipmi_ssif: Fix kernel panic at msg_done_handler
+    - usb: dwc2: Fix interval type issue
+    - usb: gadget: ffs: Let setup() return USB_GADGET_DELAYED_STATUS
+    - usb: gadget: ffs: Execute copy_to_user() with USER_DS set
+    - powerpc: Add missing prototype for arch_irq_work_raise()
+    - ASoC: topology: create TLV data for dapm widgets
+    - perf/core: Fix perf_output_read_group()
+    - hwmon: (pmbus/max8688) Accept negative page register values
+    - hwmon: (pmbus/adm1275) Accept negative page register values
+    - cdrom: do not call check_disk_change() inside cdrom_open()
+    - gfs2: Fix fallocate chunk size
+    - usb: gadget: udc: change comparison to bitshift when dealing with a mask
+    - usb: gadget: composite: fix incorrect handling of OS desc requests
+    - x86/devicetree: Initialize device tree before using it
+    - x86/devicetree: Fix device IRQ settings in DT
+    - ALSA: vmaster: Propagate slave error
+    - media: cx23885: Override 888 ImpactVCBe crystal frequency
+    - media: cx23885: Set subdev host data to clk_freq pointer
+    - media: s3c-camif: fix out-of-bounds array access
+    - dmaengine: pl330: fix a race condition in case of threaded irqs
+    - media: em28xx: USB bulk packet size fix
+    - clk: rockchip: Prevent calculating mmc phase if clock rate is zero
+    - enic: enable rq before updating rq descriptors
+    - hwrng: stm32 - add reset during probe
+    - staging: rtl8192u: return -ENOMEM on failed allocation of priv->oldaddr
+    - rtc: tx4939: avoid unintended sign extension on a 24 bit shift
+    - serial: xuartps: Fix out-of-bounds access through DT alias
+    - serial: samsung: Fix out-of-bounds access through serial port index
+    - serial: mxs-auart: Fix out-of-bounds access through serial port index
+    - serial: imx: Fix out-of-bounds access through serial port index
+    - serial: fsl_lpuart: Fix out-of-bounds access through DT alias
+    - serial: arc_uart: Fix out-of-bounds access through DT alias
+    - PCI: Add function 1 DMA alias quirk for Marvell 88SE9220
+    - udf: Provide saner default for invalid uid / gid
+    - media: cx25821: prevent out-of-bounds read on array card
+    - clk: samsung: s3c2410: Fix PLL rates
+    - clk: samsung: exynos5260: Fix PLL rates
+    - clk: samsung: exynos5433: Fix PLL rates
+    - clk: samsung: exynos5250: Fix PLL rates
+    - clk: samsung: exynos3250: Fix PLL rates
+    - crypto: sunxi-ss - Add MODULE_ALIAS to sun4i-ss
+    - audit: return on memory error to avoid null pointer dereference
+    - MIPS: Octeon: Fix logging messages with spurious periods after newlines
+    - drm/rockchip: Respect page offset for PRIME mmap calls
+    - x86/apic: Set up through-local-APIC mode on the boot CPU if 'noapic'
+      specified
+    - perf tests: Use arch__compare_symbol_names to compare symbols
+    - perf report: Fix memory corruption in --branch-history mode --branch-history
+    - selftests/net: fixes psock_fanout eBPF test case
+    - netlabel: If PF_INET6, check sk_buff ip header version
+    - scsi: lpfc: Fix issue_lip if link is disabled
+    - scsi: lpfc: Fix soft lockup in lpfc worker thread during LIP testing
+    - scsi: lpfc: Fix frequency of Release WQE CQEs
+    - regulator: of: Add a missing 'of_node_put()' in an error handling path of
+      'of_regulator_match()'
+    - ASoC: samsung: i2s: Ensure the RCLK rate is properly determined
+    - Bluetooth: btusb: Add device ID for RTL8822BE
+    - kdb: make "mdr" command repeat
+    - s390/ftrace: use expoline for indirect branches
+    - Linux 4.4.134
+
+  * Support SocketCAN over USB on Dell IoT 300x Gateways (LP: #1774563)
+    - [Config] CONFIG_CAN_HMS_USB=m
+    - SAUCE: (no-up) Support IXXAT USB SocketCAN device
+    - i386/amd64 -- Add new module ixx_usb
+
+  * Ubuntu 16.04 (4.4.0-127) hangs on boot with virtio-scsi MQ enabled
+    (LP: #1775235)
+    - SAUCE: (no-up) virtio-scsi: Increment reqs counter.
+
+  * register on binfmt_misc may overflow and crash the system (LP: #1775856)
+    - fs/binfmt_misc.c: do not allow offset overflow
+
+  * The kernel NULL pointer dereference happens when accessing the task_struct
+    by task_cpu() in function cpuacct_charge() (LP: #1775326)
+    - sched/cpuacct: Simplify the cpuacct code
+
+  * Xenial update to 4.4.133 stable release (LP: #1775477)
+    - 8139too: Use disable_irq_nosync() in rtl8139_poll_controller()
+    - bridge: check iface upper dev when setting master via ioctl
+    - dccp: fix tasklet usage
+    - ipv4: fix memory leaks in udp_sendmsg, ping_v4_sendmsg
+    - llc: better deal with too small mtu
+    - net: ethernet: sun: niu set correct packet size in skb
+    - net/mlx4_en: Verify coalescing parameters are in range
+    - net_sched: fq: take care of throttled flows before reuse
+    - net: support compat 64-bit time in {s,g}etsockopt
+    - openvswitch: Don't swap table in nlattr_set() after OVS_ATTR_NESTED is found
+    - qmi_wwan: do not steal interfaces from class drivers
+    - r8169: fix powering up RTL8168h
+    - sctp: handle two v4 addrs comparison in sctp_inet6_cmp_addr
+    - sctp: use the old asoc when making the cookie-ack chunk in dupcook_d
+    - tg3: Fix vunmap() BUG_ON() triggered from tg3_free_consistent().
+    - bonding: do not allow rlb updates to invalid mac
+    - tcp: ignore Fast Open on repair mode
+    - sctp: fix the issue that the cookie-ack with auth can't get processed
+    - sctp: delay the authentication for the duplicated cookie-echo chunk
+    - ALSA: timer: Call notifier in the same spinlock
+    - audit: move calcs after alloc and check when logging set loginuid
+    - arm64: introduce mov_q macro to move a constant into a 64-bit register
+    - [Config] Add CONFIG_ARM64_ERRATUM_1024718=y
+    - arm64: Add work around for Arm Cortex-A55 Erratum 1024718
+    - futex: Remove unnecessary warning from get_futex_key
+    - futex: Remove duplicated code and fix undefined behaviour
+    - xfrm: fix xfrm_do_migrate() with AEAD e.g(AES-GCM)
+    - lockd: lost rollback of set_grace_period() in lockd_down_net()
+    - Revert "ARM: dts: imx6qdl-wandboard: Fix audio channel swap"
+    - l2tp: revert "l2tp: fix missing print session offset info"
+    - pipe: cap initial pipe capacity according to pipe-max-size limit
+    - futex: futex_wake_op, fix sign_extend32 sign bits
+    - kernel/exit.c: avoid undefined behaviour when calling wait4()
+    - usbip: usbip_host: refine probe and disconnect debug msgs to be useful
+    - usbip: usbip_host: delete device from busid_table after rebind
+    - usbip: usbip_host: run rebind from exit when module is removed
+    - usbip: usbip_host: fix NULL-ptr deref and use-after-free errors
+    - usbip: usbip_host: fix bad unlock balance during stub_probe()
+    - ALSA: usb: mixer: volume quirk for CM102-A+/102S+
+    - ALSA: hda: Add Lenovo C50 All in one to the power_save blacklist
+    - ALSA: control: fix a redundant-copy issue
+    - spi: pxa2xx: Allow 64-bit DMA
+    - powerpc/powernv: panic() on OPAL < V3
+    - powerpc/powernv: Remove OPALv2 firmware define and references
+    - powerpc/powernv: remove FW_FEATURE_OPALv3 and just use FW_FEATURE_OPAL
+    - cpuidle: coupled: remove unused define cpuidle_coupled_lock
+    - powerpc: Don't preempt_disable() in show_cpuinfo()
+    - vmscan: do not force-scan file lru if its absolute size is small
+    - mm: filemap: remove redundant code in do_read_cache_page
+    - mm: filemap: avoid unnecessary calls to lock_page when waiting for IO to
+      complete during a read
+    - signals: avoid unnecessary taking of sighand->siglock
+    - tracing/x86/xen: Remove zero data size trace events
+      trace_xen_mmu_flush_tlb{_all}
+    - proc read mm's {arg,env}_{start,end} with mmap semaphore taken.
+    - powerpc/powernv: Fix NVRAM sleep in invalid context when crashing
+    - mm: don't allow deferred pages with NEED_PER_CPU_KM
+    - s390/qdio: fix access to uninitialized qdio_q fields
+    - s390/qdio: don't release memory in qdio_setup_irq()
+    - s390: remove indirect branch from do_softirq_own_stack
+    - efi: Avoid potential crashes, fix the 'struct efi_pci_io_protocol_32'
+      definition for mixed mode
+    - ARM: 8771/1: kprobes: Prohibit kprobes on do_undefinstr
+    - tick/broadcast: Use for_each_cpu() specially on UP kernels
+    - ARM: 8769/1: kprobes: Fix to use get_kprobe_ctlblk after irq-disabed
+    - ARM: 8770/1: kprobes: Prohibit probing on optimized_callback
+    - ARM: 8772/1: kprobes: Prohibit kprobes on get_user functions
+    - Btrfs: fix xattr loss after power failure
+    - btrfs: fix crash when trying to resume balance without the resume flag
+    - btrfs: fix reading stale metadata blocks after degraded raid1 mounts
+    - net: test tailroom before appending to linear skb
+    - packet: in packet_snd start writing at link layer allocation
+    - sock_diag: fix use-after-free read in __sk_free
+    - tcp: purge write queue in tcp_connect_init()
+    - ext2: fix a block leak
+    - s390: add assembler macros for CPU alternatives
+    - s390: move expoline assembler macros to a header
+    - s390/lib: use expoline for indirect branches
+    - s390/kernel: use expoline for indirect branches
+    - s390: move spectre sysfs attribute code
+    - s390: extend expoline to BC instructions
+    - s390: use expoline thunks in the BPF JIT
+    - scsi: libsas: defer ata device eh commands to libata
+    - scsi: sg: allocate with __GFP_ZERO in sg_build_indirect()
+    - scsi: zfcp: fix infinite iteration on ERP ready list
+    - dmaengine: ensure dmaengine helpers check valid callback
+    - time: Fix CLOCK_MONOTONIC_RAW sub-nanosecond accounting
+    - gpio: rcar: Add Runtime PM handling for interrupts
+    - cfg80211: limit wiphy names to 128 bytes
+    - hfsplus: stop workqueue when fill_super() failed
+    - x86/kexec: Avoid double free_page() upon do_kexec_load() failure
+    - Linux 4.4.133
+
+  * vmxnet3: update to latest ToT (LP: #1768143)
+    - vmxnet3: avoid xmit reset due to a race in vmxnet3
+    - vmxnet3: use correct flag to indicate LRO feature
+    - vmxnet3: fix incorrect dereference when rxvlan is disabled
+
+  * Prevent speculation on user controlled pointer (LP: #1775137)
+    - x86: reorganize SMAP handling in user space accesses
+    - x86: fix SMAP in 32-bit environments
+    - x86: Introduce __uaccess_begin_nospec() and uaccess_try_nospec
+    - x86/usercopy: Replace open coded stac/clac with __uaccess_{begin, end}
+    - x86/uaccess: Use __uaccess_begin_nospec() and uaccess_try_nospec
+
+  * Xenial update to 4.4.132 stable release (LP: #1774173)
+    - perf/core: Fix the perf_cpu_time_max_percent check
+    - bpf: map_get_next_key to return first key on NULL
+    - percpu: include linux/sched.h for cond_resched()
+    - mac80211: allow not sending MIC up from driver for HW crypto
+    - mac80211: allow same PN for AMSDU sub-frames
+    - mac80211: Add RX flag to indicate ICV stripped
+    - ath10k: fix rfc1042 header retrieval in QCA4019 with eth decap mode
+    - ath10k: rebuild crypto header in rx data frames
+    - gpmi-nand: Handle ECC Errors in erased pages
+    - USB: serial: option: Add support for Quectel EP06
+    - ALSA: pcm: Check PCM state at xfern compat ioctl
+    - ALSA: seq: Fix races at MIDI encoding in snd_virmidi_output_trigger()
+    - ALSA: aloop: Mark paused device as inactive
+    - ALSA: aloop: Add missing cable lock to ctl API callbacks
+    - tracepoint: Do not warn on ENOMEM
+    - Input: leds - fix out of bound access
+    - Input: atmel_mxt_ts - add touchpad button mapping for Samsung Chromebook Pro
+    - xfs: prevent creating negative-sized file via INSERT_RANGE
+    - RDMA/ucma: Allow resolving address w/o specifying source address
+    - RDMA/mlx5: Protect from shift operand overflow
+    - NET: usb: qmi_wwan: add support for ublox R410M PID 0x90b2
+    - IB/mlx5: Use unlimited rate when static rate is not supported
+    - drm/vmwgfx: Fix a buffer object leak
+    - test_firmware: fix setting old custom fw path back on exit, second try
+    - USB: serial: visor: handle potential invalid device configuration
+    - USB: Accept bulk endpoints with 1024-byte maxpacket
+    - USB: serial: option: reimplement interface masking
+    - USB: serial: option: adding support for ublox R410M
+    - usb: musb: host: fix potential NULL pointer dereference
+    - ipvs: fix rtnl_lock lockups caused by start_sync_thread
+    - crypto: af_alg - fix possible uninit-value in alg_bind()
+    - netlink: fix uninit-value in netlink_sendmsg
+    - net: fix rtnh_ok()
+    - net: initialize skb->peeked when cloning
+    - net: fix uninit-value in __hw_addr_add_ex()
+    - dccp: initialize ireq->ir_mark
+    - soreuseport: initialise timewait reuseport field
+    - perf: Remove superfluous allocation error check
+    - tcp: fix TCP_REPAIR_QUEUE bound checking
+    - bdi: Fix oops in wb_workfn()
+    - f2fs: fix a dead loop in f2fs_fiemap()
+    - xfrm_user: fix return value from xfrm_user_rcv_msg
+    - rfkill: gpio: fix memory leak in probe error path
+    - libata: Apply NOLPM quirk for SanDisk SD7UB3Q*G1001 SSDs
+    - tracing: Fix regex_match_front() to not over compare the test string
+    - can: kvaser_usb: Increase correct stats counter in kvaser_usb_rx_can_msg()
+    - net: atm: Fix potential Spectre v1
+    - atm: zatm: Fix potential Spectre v1
+    - Revert "Bluetooth: btusb: Fix quirk for Atheros 1525/QCA6174"
+    - tracing/uprobe_event: Fix strncpy corner case
+    - perf/x86: Fix possible Spectre-v1 indexing for hw_perf_event cache_*
+    - perf/x86/cstate: Fix possible Spectre-v1 indexing for pkg_msr
+    - perf/x86/msr: Fix possible Spectre-v1 indexing in the MSR driver
+    - perf/core: Fix possible Spectre-v1 indexing for ->aux_pages[]
+    - perf/x86: Fix possible Spectre-v1 indexing for x86_pmu::event_map()
+    - Linux 4.4.132
+
+  * Update to upstream's implementation of Spectre v1 mitigation (LP: #1774181)
+    - Documentation: Document array_index_nospec
+    - array_index_nospec: Sanitize speculative array de-references
+    - x86: Implement array_index_mask_nospec
+    - x86: Introduce barrier_nospec
+    - x86/get_user: Use pointer masking to limit speculation
+    - x86/syscall: Sanitize syscall table de-references under speculation
+    - vfs, fdtable: Prevent bounds-check bypass via speculative execution
+    - nl80211: Sanitize array index in parse_txq_params
+    - x86/spectre: Report get_user mitigation for spectre_v1
+    - x86/kvm: Update spectre-v1 mitigation
+    - nospec: Allow index argument to have const-qualified type
+    - x86/syscall: Sanitize syscall table de-references under speculation fix
+    - mpls, nospec: Sanitize array index in mpls_label_ok()
+    - nospec: Include <asm/barrier.h> dependency
+    - nospec: Move array_index_nospec() parameter checking into separate macro
+    - nospec: Kill array_index_nospec_mask_check()
+    - ALSA: seq: oss: Hardening for potential Spectre v1
+    - ALSA: hda: Hardening for potential Spectre v1
+    - SAUCE: Replace osb() calls with array_index_nospec()
+    - SAUCE: Rename osb() to barrier_nospec()
+    - SAUCE: bpf: Use barrier_nospec() instead of osb()
+
+  * CVE-2018-3639 (x86)
+    - KVM: x86: remove magic number with enum cpuid_leafs
+    - SAUCE: x86/cpufeatures: Move CPUID_7_EDX CPUID bits to word 18
+    - SAUCE: x86: Remove double include
+    - SAUCE: x86/pti: Evaluate X86_BUG_CPU_MELTDOWN when pti=auto
+    - SAUCE: x86/speculation: Query individual feature flags when reloading
+      microcode
+
+  * cpum_sf: ensure sample freq is non-zero (LP: #1772593)
+    - s390/cpum_sf: ensure sample frequency of perf event attributes is non-zero
+
+  * ELANPAD ELAN0612 does not work, patch available (LP: #1773509)
+    - SAUCE: Input: elan_i2c - add ELAN0612 to the ACPI table
+
+  * FS-Cache: Assertion failed: FS-Cache: 6 == 5 is false (LP: #1774336)
+    - SAUCE: CacheFiles: fix a read_waiter/read_copier race
+
+  * Kernel 4.4 NBD size overflow with image size exceeding 1TB (LP: #1772575)
+    - nbd: use loff_t for blocksize and nbd_set_size args
+    - nbd: fix 64-bit division
+
+  * 4.4.0-127.153 generates many "sit: non-ECT" messages (LP: #1772775)
+    - Revert "sit: reload iphdr in ipip6_rcv"
+
+  * Creation of IMA file hashes fails when appraisal is enabled (LP: #1771826)
+    - Revert "ima: limit file hash setting by user to fix and log modes"
+
+  * Setting ipv6.disable=1 prevents both IPv4 and IPv6 socket opening for VXLAN
+    tunnels (LP: #1771301)
+    - vxlan: correctly handle ipv6.disable module parameter
+
+  * CVE-2018-7755
+    - SAUCE: floppy: Do not copy a kernel pointer to user memory in FDGETPRM ioctl
+
+  * Support UVC1.5 Camera for Xenial (LP: #1773905)
+    - uvcvideo: Enable UVC 1.5 device detection
+
+  * Kernel produces empty lines in /proc/PID/status (LP: #1772671)
+    - SAUCE: seccomp: Remove double newline sequence in /proc/PID/status
+
+  * rfi-flush: Switch to new linear fallback flush (LP: #1744173)
+    - powerpc/64s: Improve RFI L1-D cache flush fallback
+    - SAUCE: rfi-flush: Make it possible to call setup_rfi_flush() again
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Tue, 12 Jun 2018 04:10:32 -0400
+
+linux (4.4.0-128.154) xenial; urgency=medium
+
+  * linux: 4.4.0-128.154 -proposed tracker (LP: #1772960)
+
+  * CVE-2018-3639 (x86)
+    - x86/cpu: Make alternative_msr_write work for 32-bit code
+    - x86/bugs: Fix the parameters alignment and missing void
+    - KVM: SVM: Move spec control call after restore of GS
+    - x86/speculation: Use synthetic bits for IBRS/IBPB/STIBP
+    - x86/cpufeatures: Disentangle MSR_SPEC_CTRL enumeration from IBRS
+    - x86/cpufeatures: Disentangle SSBD enumeration
+    - x86/cpu/AMD: Fix erratum 1076 (CPB bit)
+    - x86/cpufeatures: Add FEATURE_ZEN
+    - x86/speculation: Handle HT correctly on AMD
+    - x86/bugs, KVM: Extend speculation control for VIRT_SPEC_CTRL
+    - x86/speculation: Add virtualized speculative store bypass disable support
+    - x86/speculation: Rework speculative_store_bypass_update()
+    - x86/bugs: Unify x86_spec_ctrl_{set_guest,restore_host}
+    - x86/bugs: Expose x86_spec_ctrl_base directly
+    - x86/bugs: Remove x86_spec_ctrl_set()
+    - x86/bugs: Rework spec_ctrl base and mask logic
+    - x86/speculation, KVM: Implement support for VIRT_SPEC_CTRL/LS_CFG
+    - KVM: SVM: Implement VIRT_SPEC_CTRL support for SSBD
+    - x86/bugs: Rename SSBD_NO to SSB_NO
+    - KVM: VMX: Expose SSBD properly to guests.
+
+  * [i915_bpo] Fix flickering issue after panel change (LP: #1770565)
+    - drm/i915: Fix iboost setting for DDI with 4 lanes on SKL
+    - drm/i915: Name the "iboost bit"
+    - drm/i915: Program iboost settings for HDMI/DVI on SKL
+    - drm/i915: Move bxt_ddi_vswing_sequence() call into intel_ddi_pre_enable()
+      for HDMI
+    - drm/i915: Explicitly use ddi buf trans entry 9 for hdmi
+    - drm/i915: Split DP/eDP/FDI and HDMI/DVI DDI buffer programming apart
+    - drm/i915: Get the iboost setting based on the port type
+    - drm/i915: Simplify intel_ddi_get_encoder_port()
+    - drm/i915: Fix iboost setting for SKL Y/U DP DDI buffer translation entry 2
+    - drm/i915: KBL - Recommended buffer translation programming for DisplayPort
+    - drm/i915: Ignore OpRegion panel type except on select machines
+
+  * [SRU][Bionic/Artful] fix false positives in W+X checking (LP: #1769696)
+    - init: fix false positives in W+X checking
+
+  * [Ubuntu 16.04] kernel: fix rwlock implementation (LP: #1761674)
+    - SAUCE: (no-up) s390: fix rwlock implementation
+
+  * linux < 4.11: unable to use netfilter logging from non-init namespaces
+    (LP: #1766573)
+    - netfilter: allow logging from non-init namespaces
+
+  * [LTC Test] Ubuntu 18.04:  tm_sigreturn failed on P8 compat mode 16.04.04
+    guest (LP: #1771439)
+    - powerpc: signals: Discard transaction state from signal frames
+
+  * QCA9377 requires more IRAM banks for its new firmware (LP: #1748345)
+    - ath10k: update the IRAM bank number for QCA9377
+
+  * i915/kbl_dmc_ver1.bin failed with error -2 package 1.157.17 kernel
+    4.4.0-116-generic (LP: #1752536)
+    - ubuntu: i915_bpo - Add MODULE_FIRMWARE for Geminilake's DMC
+
+  * Xenial update to 4.4.131 stable release (LP: #1768825)
+    - ext4: prevent right-shifting extents beyond EXT_MAX_BLOCKS
+    - ext4: set h_journal if there is a failure starting a reserved handle
+    - ext4: add validity checks for bitmap block numbers
+    - ext4: fix bitmap position validation
+    - usbip: usbip_host: fix to hold parent lock for device_attach() calls
+    - usbip: vhci_hcd: Fix usb device and sockfd leaks
+    - USB: serial: simple: add libtransistor console
+    - USB: serial: ftdi_sio: use jtag quirk for Arrow USB Blaster
+    - USB: serial: cp210x: add ID for NI USB serial console
+    - usb: core: Add quirk for HP v222w 16GB Mini
+    - USB: Increment wakeup count on remote wakeup.
+    - ALSA: usb-audio: Skip broken EU on Dell dock USB-audio
+    - virtio: add ability to iterate over vqs
+    - virtio_console: free buffers after reset
+    - drm/virtio: fix vq wait_event condition
+    - tty: Don't call panic() at tty_ldisc_init()
+    - tty: n_gsm: Fix long delays with control frame timeouts in ADM mode
+    - tty: n_gsm: Fix DLCI handling for ADM mode if debug & 2 is not set
+    - tty: Use __GFP_NOFAIL for tty_ldisc_get()
+    - ALSA: core: Report audio_tstamp in snd_pcm_sync_ptr
+    - ALSA: seq: oss: Fix unbalanced use lock for synth MIDI device
+    - ALSA: hda/realtek - Add some fixes for ALC233
+    - mtd: cfi: cmdset_0001: Do not allow read/write to suspend erase block.
+    - mtd: cfi: cmdset_0001: Workaround Micron Erase suspend bug.
+    - mtd: cfi: cmdset_0002: Do not allow read/write to suspend erase block.
+    - kobject: don't use WARN for registration failures
+    - scsi: sd: Defer spinning up drive while SANITIZE is in progress
+    - ARM: amba: Make driver_override output consistent with other buses
+    - ARM: amba: Fix race condition with driver_override
+    - ARM: amba: Don't read past the end of sysfs "driver_override" buffer
+    - ASoC: fsl_esai: Fix divisor calculation failure at lower ratio
+    - libceph: validate con->state at the top of try_write()
+    - x86/ipc: Fix x32 version of shmid64_ds and msqid64_ds
+    - x86/smpboot: Don't use mwait_play_dead() on AMD systems
+    - serial: mctrl_gpio: export mctrl_gpio_disable_ms and mctrl_gpio_init
+    - serial: mctrl_gpio: Add missing module license
+    - Linux 4.4.131
+
+  * Xenial update to 4.4.130 stable release (LP: #1768474) // CVE-2017-5715 //
+    CVE-2017-5753
+    - SAUCE: s390: print messages for gmb and nobp
+
+  * Xenial update to 4.4.130 stable release (LP: #1768474)
+    - cifs: do not allow creating sockets except with SMB1 posix exensions
+    - x86/tsc: Prevent 32bit truncation in calc_hpet_ref()
+    - perf: Return proper values for user stack errors
+    - staging: ion : Donnot wakeup kswapd in ion system alloc
+    - r8152: add Linksys USB3GIGV1 id
+    - Input: drv260x - fix initializing overdrive voltage
+    - ath9k_hw: check if the chip failed to wake up
+    - jbd2: fix use after free in kjournald2()
+    - Revert "ath10k: send (re)assoc peer command when NSS changed"
+    - Revert "UBUNTU: SAUCE: s390: print messages for gmb and nobp"
+    - Revert "UBUNTU: SAUCE: s390: improve cpu alternative handling for gmb and
+      nobp"
+    - Revert "s390: add ppa to kernel entry / exit"
+    - Revert "s390: introduce CPU alternatives"
+    - s390: introduce CPU alternatives
+    - s390: enable CPU alternatives unconditionally
+    - s390/alternative: use a copy of the facility bit mask
+    - s390: add options to change branch prediction behaviour for the kernel
+    - s390: scrub registers on kernel entry and KVM exit
+    - s390: add optimized array_index_mask_nospec
+    - s390: run user space and KVM guests with modified branch prediction
+    - s390: introduce execute-trampolines for branches
+    - s390: Replace IS_ENABLED(EXPOLINE_*) with IS_ENABLED(CONFIG_EXPOLINE_*)
+    - s390: do not bypass BPENTER for interrupt system calls
+    - s390/entry.S: fix spurious zeroing of r0
+    - s390: move nobp parameter functions to nospec-branch.c
+    - s390: add automatic detection of the spectre defense
+    - [Config] Add CONFIG_EXPOLINE=y and CONFIG_EXPOLINE_AUTO=y
+    - s390: report spectre mitigation via syslog
+    - s390: add sysfs attributes for spectre
+    - s390: correct nospec auto detection init order
+    - s390: correct module section names for expoline code revert
+    - bonding: do not set slave_dev npinfo before slave_enable_netpoll in
+      bond_enslave
+    - KEYS: DNS: limit the length of option strings
+    - l2tp: check sockaddr length in pppol2tp_connect()
+    - net: validate attribute sizes in neigh_dump_table()
+    - llc: delete timers synchronously in llc_sk_free()
+    - tcp: don't read out-of-bounds opsize
+    - team: avoid adding twice the same option to the event list
+    - team: fix netconsole setup over team
+    - packet: fix bitfield update race
+    - pppoe: check sockaddr length in pppoe_connect()
+    - vlan: Fix reading memory beyond skb->tail in skb_vlan_tagged_multi
+    - sctp: do not check port in sctp_inet6_cmp_addr
+    - llc: hold llc_sap before release_sock()
+    - llc: fix NULL pointer deref for SOCK_ZAPPED
+    - tipc: add policy for TIPC_NLA_NET_ADDR
+    - net: fix deadlock while clearing neighbor proxy table
+    - tcp: md5: reject TCP_MD5SIG or TCP_MD5SIG_EXT on established sockets
+    - net: af_packet: fix race in PACKET_{R|T}X_RING
+    - ipv6: add RTA_TABLE and RTA_PREFSRC to rtm_ipv6_policy
+    - scsi: mptsas: Disable WRITE SAME
+    - cdrom: information leak in cdrom_ioctl_media_changed()
+    - s390/cio: update chpid descriptor after resource accessibility event
+    - s390/uprobes: implement arch_uretprobe_is_alive()
+    - Linux 4.4.130
+    - SAUCE: s390: Add 'nogmb' kernel parameter
+
+  * Xenial update to 4.4.129 stable release (LP: #1768429)
+    - media: v4l2-compat-ioctl32: don't oops on overlay
+    - parisc: Fix out of array access in match_pci_device()
+    - perf intel-pt: Fix overlap detection to identify consecutive buffers
+      correctly
+    - perf intel-pt: Fix sync_switch
+    - perf intel-pt: Fix error recovery from missing TIP packet
+    - perf intel-pt: Fix timestamp following overflow
+    - radeon: hide pointless #warning when compile testing
+    - block/loop: fix deadlock after loop_set_status
+    - s390/qdio: don't retry EQBS after CCQ 96
+    - s390/qdio: don't merge ERROR output buffers
+    - s390/ipl: ensure loadparm valid flag is set
+    - getname_kernel() needs to make sure that ->name != ->iname in long case
+    - rtl8187: Fix NULL pointer dereference in priv->conf_mutex
+    - hwmon: (ina2xx) Fix access to uninitialized mutex
+    - cdc_ether: flag the Cinterion AHS8 modem by gemalto as WWAN
+    - slip: Check if rstate is initialized before uncompressing
+    - lan78xx: Correctly indicate invalid OTP
+    - x86/hweight: Get rid of the special calling convention
+    - [Config] Remove ARCH_HWEIGHT_CFLAGS
+    - x86/hweight: Don't clobber %rdi
+    - tty: make n_tty_read() always abort if hangup is in progress
+    - ubifs: Check ubifs_wbuf_sync() return code
+    - ubi: fastmap: Don't flush fastmap work on detach
+    - ubi: Fix error for write access
+    - ubi: Reject MLC NAND
+    - fs/reiserfs/journal.c: add missing resierfs_warning() arg
+    - resource: fix integer overflow at reallocation
+    - ipc/shm: fix use-after-free of shm file via remap_file_pages()
+    - mm, slab: reschedule cache_reap() on the same CPU
+    - usb: musb: gadget: misplaced out of bounds check
+    - ARM: dts: at91: at91sam9g25: fix mux-mask pinctrl property
+    - ARM: dts: at91: sama5d4: fix pinctrl compatible string
+    - xen-netfront: Fix hang on device removal
+    - regmap: Fix reversed bounds check in regmap_raw_write()
+    - ACPI / video: Add quirk to force acpi-video backlight on Samsung 670Z5E
+    - ACPI / hotplug / PCI: Check presence of slot itself in get_slot_status()
+    - USB:fix USB3 devices behind USB3 hubs not resuming at hibernate thaw
+    - usb: dwc3: pci: Properly cleanup resource
+    - HID: i2c-hid: fix size check and type usage
+    - powerpc/powernv: Handle unknown OPAL errors in opal_nvram_write()
+    - powerpc/64: Fix smp_wmb barrier definition use use lwsync consistently
+    - powerpc/powernv: define a standard delay for OPAL_BUSY type retry loops
+    - powerpc/powernv: Fix OPAL NVRAM driver OPAL_BUSY loops
+    - HID: Fix hid_report_len usage
+    - HID: core: Fix size as type u32
+    - ASoC: ssm2602: Replace reg_default_raw with reg_default
+    - thunderbolt: Resume control channel after hibernation image is created
+    - random: use a tighter cap in credit_entropy_bits_safe()
+    - jbd2: if the journal is aborted then don't allow update of the log tail
+    - ext4: don't update checksum of new initialized bitmaps
+    - ext4: fail ext4_iget for root directory if unallocated
+    - RDMA/ucma: Don't allow setting RDMA_OPTION_IB_PATH without an RDMA device
+    - ALSA: pcm: Fix UAF at PCM release via PCM timer access
+    - IB/srp: Fix srp_abort()
+    - IB/srp: Fix completion vector assignment algorithm
+    - dmaengine: at_xdmac: fix rare residue corruption
+    - um: Use POSIX ucontext_t instead of struct ucontext
+    - iommu/vt-d: Fix a potential memory leak
+    - mmc: jz4740: Fix race condition in IRQ mask update
+    - clk: mvebu: armada-38x: add support for 1866MHz variants
+    - clk: mvebu: armada-38x: add support for missing clocks
+    - clk: bcm2835: De-assert/assert PLL reset signal when appropriate
+    - thermal: imx: Fix race condition in imx_thermal_probe()
+    - watchdog: f71808e_wdt: Fix WD_EN register read
+    - ALSA: oss: consolidate kmalloc/memset 0 call to kzalloc
+    - ALSA: pcm: Use ERESTARTSYS instead of EINTR in OSS emulation
+    - ALSA: pcm: Avoid potential races between OSS ioctls and read/write
+    - ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams
+    - ALSA: pcm: Fix mutex unbalance in OSS emulation ioctls
+    - ALSA: pcm: Fix endless loop for XRUN recovery in OSS emulation
+    - vfio-pci: Virtualize PCIe & AF FLR
+    - vfio/pci: Virtualize Maximum Payload Size
+    - vfio/pci: Virtualize Maximum Read Request Size
+    - ext4: don't allow r/w mounts if metadata blocks overlap the superblock
+    - drm/radeon: Fix PCIe lane width calculation
+    - ext4: fix crashes in dioread_nolock mode
+    - ext4: fix deadlock between inline_data and ext4_expand_extra_isize_ea()
+    - ALSA: line6: Use correct endpoint type for midi output
+    - ALSA: rawmidi: Fix missing input substream checks in compat ioctls
+    - ALSA: hda - New VIA controller suppor no-snoop path
+    - HID: hidraw: Fix crash on HIDIOCGFEATURE with a destroyed device
+    - MIPS: uaccess: Add micromips clobbers to bzero invocation
+    - MIPS: memset.S: EVA & fault support for small_memset
+    - MIPS: memset.S: Fix return of __clear_user from Lpartial_fixup
+    - MIPS: memset.S: Fix clobber of v1 in last_fixup
+    - powerpc/eeh: Fix enabling bridge MMIO windows
+    - powerpc/lib: Fix off-by-one in alternate feature patching
+    - jffs2_kill_sb(): deal with failed allocations
+    - hypfs_kill_super(): deal with failed allocations
+    - rpc_pipefs: fix double-dput()
+    - Don't leak MNT_INTERNAL away from internal mounts
+    - autofs: mount point create should honour passed in mode
+    - mm: allow GFP_{FS,IO} for page_cache_read page cache allocation
+    - mm/filemap.c: fix NULL pointer in page_cache_tree_insert()
+    - ext4: bugfix for mmaped pages in mpage_release_unused_pages()
+    - fanotify: fix logic of events on child
+    - writeback: safer lock nesting
+    - Linux 4.4.129
+
+  * CVE-2018-8087
+    - mac80211_hwsim: fix possible memory leak in hwsim_new_radio_nl()
+
+  * Integrated Webcam Realtek Integrated_Webcam_HD (0bda:58f4) not working in
+    DELL XPS 13 9370 with firmware 1.50 (LP: #1763748)
+    - SAUCE: media: uvcvideo: Support realtek's UVC 1.5 device
+
+  * [Xenial] Kernels OOPS when mwifiex is in AP mode (LP: #1769671)
+    - Revert "UBUNTU: SAUCE: mwifiex: do not dereference invalid pointer"
+    - Revert "UBUNTU: SAUCE: net/wireless: do not dereference invalid pointer"
+    - mwifiex: cfg80211: do not change virtual interface during scan processing
+
+  * user space process hung in 'D' state waiting for disk io to complete
+    (LP: #1750038)
+    - NFS: Use GFP_NOIO for two allocations in writeback
+
+  * Acer Swift sf314-52 power button not managed  (LP: #1766054)
+    - SAUCE: platform/x86: acer-wmi: add another KEY_POWER keycode
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 25 May 2018 15:58:45 +0200
+
+linux (4.4.0-127.153) xenial; urgency=medium
+
+  * CVE-2018-3639 (powerpc)
+    - powerpc/pseries: Support firmware disable of RFI flush
+    - powerpc/powernv: Support firmware disable of RFI flush
+    - powerpc/rfi-flush: Move the logic to avoid a redo into the debugfs code
+    - powerpc/rfi-flush: Make it possible to call setup_rfi_flush() again
+    - powerpc/rfi-flush: Always enable fallback flush on pseries
+    - powerpc/rfi-flush: Differentiate enabled and patched flush types
+    - powerpc/rfi-flush: Call setup_rfi_flush() after LPM migration
+    - powerpc/pseries: Add new H_GET_CPU_CHARACTERISTICS flags
+    - powerpc: Add security feature flags for Spectre/Meltdown
+    - powerpc/pseries: Set or clear security feature flags
+    - powerpc/powernv: Set or clear security feature flags
+    - powerpc/64s: Move cpu_show_meltdown()
+    - powerpc/64s: Enhance the information in cpu_show_meltdown()
+    - powerpc/powernv: Use the security flags in pnv_setup_rfi_flush()
+    - powerpc/pseries: Use the security flags in pseries_setup_rfi_flush()
+    - powerpc/64s: Wire up cpu_show_spectre_v1()
+    - powerpc/64s: Wire up cpu_show_spectre_v2()
+    - powerpc/pseries: Fix clearing of security feature flags
+    - powerpc: Move default security feature flags
+    - powerpc/pseries: Restore default security feature flags on setup
+    - SAUCE: powerpc/64s: Add support for a store forwarding barrier at kernel
+      entry/exit
+
+  * CVE-2018-3639 (x86)
+    - SAUCE: Clean up IBPB and IBRS control functions and macros
+    - SAUCE: Fix up IBPB and IBRS kernel parameters documentation
+    - SAUCE: Remove #define X86_FEATURE_PTI
+    - x86/cpufeature: Move some of the scattered feature bits to x86_capability
+    - x86/cpufeature: Cleanup get_cpu_cap()
+    - x86/cpu: Probe CPUID leaf 6 even when cpuid_level == 6
+    - x86/cpufeatures: Add CPUID_7_EDX CPUID leaf
+    - x86/cpufeatures: Add Intel feature bits for Speculation Control
+    - SAUCE: x86/kvm: Expose SPEC_CTRL from the leaf
+    - x86/cpufeatures: Add AMD feature bits for Speculation Control
+    - x86/msr: Add definitions for new speculation control MSRs
+    - SAUCE: x86/msr: Rename MSR spec control feature bits
+    - x86/pti: Do not enable PTI on CPUs which are not vulnerable to Meltdown
+    - x86/cpufeature: Blacklist SPEC_CTRL/PRED_CMD on early Spectre v2 microcodes
+    - x86/speculation: Add basic IBPB (Indirect Branch Prediction Barrier) support
+    - x86/speculation: Add <asm/msr-index.h> dependency
+    - x86/cpufeatures: Clean up Spectre v2 related CPUID flags
+    - x86/cpuid: Fix up "virtual" IBRS/IBPB/STIBP feature bits on Intel
+    - SAUCE: x86/speculation: Move vendor specific IBRS/IBPB control code
+    - SAUCE: x86: Add alternative_msr_write
+    - SAUCE: x86/nospec: Simplify alternative_msr_write()
+    - SAUCE: x86/bugs: Concentrate bug detection into a separate function
+    - SAUCE: x86/bugs: Concentrate bug reporting into a separate function
+    - arch: Introduce post-init read-only memory
+    - SAUCE: x86/bugs: Read SPEC_CTRL MSR during boot and re-use reserved bits
+    - SAUCE: x86/bugs, KVM: Support the combination of guest and host IBRS
+    - SAUCE: x86/bugs: Expose /sys/../spec_store_bypass
+    - SAUCE: x86/cpufeatures: Add X86_FEATURE_RDS
+    - SAUCE: x86/bugs: Provide boot parameters for the spec_store_bypass_disable
+      mitigation
+    - SAUCE: x86/bugs/intel: Set proper CPU features and setup RDS
+    - SAUCE: x86/bugs: Whitelist allowed SPEC_CTRL MSR values
+    - SAUCE: x86/bugs/AMD: Add support to disable RDS on Fam[15,16,17]h if
+      requested
+    - SAUCE: x86/KVM/VMX: Expose SPEC_CTRL Bit(2) to the guest
+    - SAUCE: x86/speculation: Create spec-ctrl.h to avoid include hell
+    - SAUCE: prctl: Add speculation control prctls
+    - x86/process: Optimize TIF checks in __switch_to_xtra()
+    - SAUCE: x86/process: Allow runtime control of Speculative Store Bypass
+    - SAUCE: x86/speculation: Add prctl for Speculative Store Bypass mitigation
+    - SAUCE: nospec: Allow getting/setting on non-current task
+    - SAUCE: proc: Provide details on speculation flaw mitigations
+    - SAUCE: seccomp: Enable speculation flaw mitigations
+    - SAUCE: x86/bugs: Honour SPEC_CTRL default
+    - SAUCE: x86/bugs: Make boot modes __ro_after_init
+    - SAUCE: prctl: Add force disable speculation
+    - SAUCE: seccomp: Use PR_SPEC_FORCE_DISABLE
+    - selftest/seccomp: Fix the flag name SECCOMP_FILTER_FLAG_TSYNC
+    - SAUCE: seccomp: Add filter flag to opt-out of SSB mitigation
+    - SAUCE: seccomp: Move speculation migitation control to arch code
+    - SAUCE: x86/speculation: Make "seccomp" the default mode for Speculative
+      Store Bypass
+    - SAUCE: x86/bugs: Rename _RDS to _SSBD
+    - SAUCE: proc: Use underscores for SSBD in 'status'
+    - SAUCE: Documentation/spec_ctrl: Do some minor cleanups
+    - SAUCE: x86/bugs: Fix __ssb_select_mitigation() return type
+    - SAUCE: x86/bugs: Make cpu_show_common() static
+    - x86/entry: define _TIF_ALLWORK_MASK flags explicitly
+    - Revert "x86/cpufeature: Blacklist SPEC_CTRL/PRED_CMD on early Spectre v2
+      microcodes"
+    - SAUCE: kvm/cpuid: Fix CPUID_7_0.EDX handling
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Sat, 19 May 2018 11:58:02 +0200
+
+linux (4.4.0-125.150) xenial; urgency=medium
+
+  * linux: 4.4.0-125.150 -proposed tracker (LP: #1770011)
+
+  * Unable to insert test_bpf module on Xenial (LP: #1765698)
+    - bpf: fix selftests/bpf test_kmod.sh failure when CONFIG_BPF_JIT_ALWAYS_ON=y
+    - test_bpf: Fix testing with CONFIG_BPF_JIT_ALWAYS_ON=y on other arches
+
+  * virtio_scsi race can corrupt memory, panic kernel (LP: #1765241)
+    - SAUCE: (no-up) virtio-scsi: Fix race in target free
+
+  * bpf_map_lookup_elem: BUG: unable to handle kernel paging request
+    (LP: #1763454) // CVE-2017-17862
+    - SAUCE: Add missing hunks from "bpf: fix branch pruning logic"
+
+  * Xenial: rfkill: fix missing return on rfkill_init  (LP: #1764810)
+    - rfkill: fix missing return on rfkill_init
+
+  * "ip a" command on a guest VM shows UNKNOWN status (LP: #1761534)
+    - virtio-net: Fix operstate for virtio when no VIRTIO_NET_F_STATUS
+
+  * Xenial update to 4.4.128 stable release (LP: #1765010)
+    - cfg80211: make RATE_INFO_BW_20 the default
+    - md/raid5: make use of spin_lock_irq over local_irq_disable + spin_lock
+    - rtc: snvs: fix an incorrect check of return value
+    - x86/asm: Don't use RBP as a temporary register in
+      csum_partial_copy_generic()
+    - NFSv4.1: RECLAIM_COMPLETE must handle NFS4ERR_CONN_NOT_BOUND_TO_SESSION
+    - IB/srpt: Fix abort handling
+    - af_key: Fix slab-out-of-bounds in pfkey_compile_policy.
+    - mac80211: bail out from prep_connection() if a reconfig is ongoing
+    - bna: Avoid reading past end of buffer
+    - qlge: Avoid reading past end of buffer
+    - ipmi_ssif: unlock on allocation failure
+    - net: cdc_ncm: Fix TX zero padding
+    - net: ethernet: ti: cpsw: adjust cpsw fifos depth for fullduplex flow control
+    - lockd: fix lockd shutdown race
+    - drivers/misc/vmw_vmci/vmci_queue_pair.c: fix a couple integer overflow tests
+    - pidns: disable pid allocation if pid_ns_prepare_proc() is failed in
+      alloc_pid()
+    - s390: move _text symbol to address higher than zero
+    - net/mlx4_en: Avoid adding steering rules with invalid ring
+    - NFSv4.1: Work around a Linux server bug...
+    - CIFS: silence lockdep splat in cifs_relock_file()
+    - net: qca_spi: Fix alignment issues in rx path
+    - netxen_nic: set rcode to the return status from the call to netxen_issue_cmd
+    - Input: elan_i2c - check if device is there before really probing
+    - Input: elantech - force relative mode on a certain module
+    - KVM: PPC: Book3S PR: Check copy_to/from_user return values
+    - vmxnet3: ensure that adapter is in proper state during force_close
+    - SMB2: Fix share type handling
+    - bus: brcmstb_gisb: Use register offsets with writes too
+    - bus: brcmstb_gisb: correct support for 64-bit address output
+    - PowerCap: Fix an error code in powercap_register_zone()
+    - ARM: dts: imx53-qsrb: Pulldown PMIC IRQ pin
+    - staging: wlan-ng: prism2mgmt.c: fixed a double endian conversion before
+      calling hfa384x_drvr_setconfig16, also fixes relative sparse warning
+    - x86/tsc: Provide 'tsc=unstable' boot parameter
+    - ARM: dts: imx6qdl-wandboard: Fix audio channel swap
+    - ipv6: avoid dad-failures for addresses with NODAD
+    - async_tx: Fix DMA_PREP_FENCE usage in do_async_gen_syndrome()
+    - usb: dwc3: keystone: check return value
+    - btrfs: fix incorrect error return ret being passed to mapping_set_error
+    - ata: libahci: properly propagate return value of platform_get_irq()
+    - neighbour: update neigh timestamps iff update is effective
+    - arp: honour gratuitous ARP _replies_
+    - usb: chipidea: properly handle host or gadget initialization failure
+    - USB: ene_usb6250: fix first command execution
+    - net: x25: fix one potential use-after-free issue
+    - USB: ene_usb6250: fix SCSI residue overwriting
+    - serial: 8250: omap: Disable DMA for console UART
+    - serial: sh-sci: Fix race condition causing garbage during shutdown
+    - sh_eth: Use platform device for printing before register_netdev()
+    - scsi: csiostor: fix use after free in csio_hw_use_fwconfig()
+    - powerpc/mm: Fix virt_addr_valid() etc. on 64-bit hash
+    - ath5k: fix memory leak on buf on failed eeprom read
+    - selftests/powerpc: Fix TM resched DSCR test with some compilers
+    - xfrm: fix state migration copy replay sequence numbers
+    - iio: hi8435: avoid garbage event at first enable
+    - iio: hi8435: cleanup reset gpio
+    - ext4: handle the rest of ext4_mb_load_buddy() ENOMEM errors
+    - md-cluster: fix potential lock issue in add_new_disk
+    - ARM: davinci: da8xx: Create DSP device only when assigned memory
+    - ray_cs: Avoid reading past end of buffer
+    - leds: pca955x: Correct I2C Functionality
+    - sched/numa: Use down_read_trylock() for the mmap_sem
+    - net/mlx5: Tolerate irq_set_affinity_hint() failures
+    - selinux: do not check open permission on sockets
+    - block: fix an error code in add_partition()
+    - mlx5: fix bug reading rss_hash_type from CQE
+    - net: ieee802154: fix net_device reference release too early
+    - libceph: NULL deref on crush_decode() error path
+    - netfilter: ctnetlink: fix incorrect nf_ct_put during hash resize
+    - pNFS/flexfiles: missing error code in ff_layout_alloc_lseg()
+    - ASoC: rsnd: SSI PIO adjust to 24bit mode
+    - scsi: bnx2fc: fix race condition in bnx2fc_get_host_stats()
+    - fix race in drivers/char/random.c:get_reg()
+    - ext4: fix off-by-one on max nr_pages in ext4_find_unwritten_pgoff()
+    - tcp: better validation of received ack sequences
+    - net: move somaxconn init from sysctl code
+    - Input: elan_i2c - clear INT before resetting controller
+    - bonding: Don't update slave->link until ready to commit
+    - KVM: nVMX: Fix handling of lmsw instruction
+    - net: llc: add lock_sock in llc_ui_bind to avoid a race condition
+    - ARM: dts: ls1021a: add "fsl,ls1021a-esdhc" compatible string to esdhc node
+    - thermal: power_allocator: fix one race condition issue for thermal_instances
+      list
+    - perf probe: Add warning message if there is unexpected event name
+    - l2tp: fix missing print session offset info
+    - rds; Reset rs->rs_bound_addr in rds_add_bound() failure path
+    - hwmon: (ina2xx) Make calibration register value fixed
+    - media: videobuf2-core: don't go out of the buffer range
+    - ASoC: Intel: cht_bsw_rt5645: Analog Mic support
+    - scsi: mpt3sas: Proper handling of set/clear of "ATA command pending" flag.
+    - vfb: fix video mode and line_length being set when loaded
+    - gpio: label descriptors using the device name
+    - ASoC: Intel: sst: Fix the return value of 'sst_send_byte_stream_mrfld()'
+    - wl1251: check return from call to wl1251_acx_arp_ip_filter
+    - hdlcdrv: Fix divide by zero in hdlcdrv_ioctl
+    - ovl: filter trusted xattr for non-admin
+    - powerpc/[booke|4xx]: Don't clobber TCR[WP] when setting TCR[DIE]
+    - dmaengine: imx-sdma: Handle return value of clk_prepare_enable
+    - arm64: futex: Fix undefined behaviour with FUTEX_OP_OPARG_SHIFT usage
+    - net/mlx5: avoid build warning for uniprocessor
+    - cxgb4: FW upgrade fixes
+    - rtc: opal: Handle disabled TPO in opal_get_tpo_time()
+    - rtc: interface: Validate alarm-time before handling rollover
+    - SUNRPC: ensure correct error is reported by xs_tcp_setup_socket()
+    - net: freescale: fix potential null pointer dereference
+    - KVM: SVM: do not zero out segment attributes if segment is unusable or not
+      present
+    - clk: scpi: fix return type of __scpi_dvfs_round_rate
+    - clk: Fix __set_clk_rates error print-string
+    - powerpc/spufs: Fix coredump of SPU contexts
+    - perf trace: Add mmap alias for s390
+    - qlcnic: Fix a sleep-in-atomic bug in qlcnic_82xx_hw_write_wx_2M and
+      qlcnic_82xx_hw_read_wx_2M
+    - mISDN: Fix a sleep-in-atomic bug
+    - drm/omap: fix tiled buffer stride calculations
+    - cxgb4: fix incorrect cim_la output for T6
+    - Fix serial console on SNI RM400 machines
+    - bio-integrity: Do not allocate integrity context for bio w/o data
+    - skbuff: return -EMSGSIZE in skb_to_sgvec to prevent overflow
+    - sit: reload iphdr in ipip6_rcv
+    - net/mlx4: Fix the check in attaching steering rules
+    - net/mlx4: Check if Granular QoS per VF has been enabled before updating QP
+      qos_vport
+    - perf header: Set proper module name when build-id event found
+    - perf report: Ensure the perf DSO mapping matches what libdw sees
+    - tags: honor COMPILED_SOURCE with apart output directory
+    - e1000e: fix race condition around skb_tstamp_tx()
+    - cx25840: fix unchecked return values
+    - mceusb: sporadic RX truncation corruption fix
+    - net: phy: avoid genphy_aneg_done() for PHYs without clause 22 support
+    - ARM: imx: Add MXC_CPU_IMX6ULL and cpu_is_imx6ull
+    - e1000e: Undo e1000e_pm_freeze if __e1000_shutdown fails
+    - perf/core: Correct event creation with PERF_FORMAT_GROUP
+    - MIPS: mm: fixed mappings: correct initialisation
+    - MIPS: mm: adjust PKMAP location
+    - MIPS: kprobes: flush_insn_slot should flush only if probe initialised
+    - Fix loop device flush before configure v3
+    - net: emac: fix reset timeout with AR8035 phy
+    - skbuff: only inherit relevant tx_flags
+    - xen: avoid type warning in xchg_xen_ulong
+    - bnx2x: Allow vfs to disable txvlan offload
+    - sctp: fix recursive locking warning in sctp_do_peeloff
+    - sparc64: ldc abort during vds iso boot
+    - iio: magnetometer: st_magn_spi: fix spi_device_id table
+    - Bluetooth: Send HCI Set Event Mask Page 2 command only when needed
+    - cpuidle: dt: Add missing 'of_node_put()'
+    - ACPICA: Events: Add runtime stub support for event APIs
+    - ACPICA: Disassembler: Abort on an invalid/unknown AML opcode
+    - s390/dasd: fix hanging safe offline
+    - vxlan: dont migrate permanent fdb entries during learn
+    - bcache: stop writeback thread after detaching
+    - bcache: segregate flash only volume write streams
+    - scsi: libsas: fix memory leak in sas_smp_get_phy_events()
+    - scsi: libsas: fix error when getting phy events
+    - scsi: libsas: initialize sas_phy status according to response of DISCOVER
+    - blk-mq: fix kernel oops in blk_mq_tag_idle()
+    - tty: n_gsm: Allow ADM response in addition to UA for control dlci
+    - EDAC, mv64x60: Fix an error handling path
+    - cxgb4vf: Fix SGE FL buffer initialization logic for 64K pages
+    - perf tools: Fix copyfile_offset update of output offset
+    - ipsec: check return value of skb_to_sgvec always
+    - rxrpc: check return value of skb_to_sgvec always
+    - virtio_net: check return value of skb_to_sgvec always
+    - virtio_net: check return value of skb_to_sgvec in one more location
+    - random: use lockless method of accessing and updating f->reg_idx
+    - futex: Remove requirement for lock_page() in get_futex_key()
+    - Kbuild: provide a __UNIQUE_ID for clang
+    - arp: fix arp_filter on l3slave devices
+    - net: fix possible out-of-bound read in skb_network_protocol()
+    - net/ipv6: Fix route leaking between VRFs
+    - netlink: make sure nladdr has correct size in netlink_connect()
+    - net/sched: fix NULL dereference in the error path of tcf_bpf_init()
+    - pptp: remove a buggy dst release in pptp_connect()
+    - sctp: do not leak kernel memory to user space
+    - sctp: sctp_sockaddr_af must check minimal addr length for AF_INET6
+    - vhost: correctly remove wait queue during poll failure
+    - vlan: also check phy_driver ts_info for vlan's real device
+    - bonding: fix the err path for dev hwaddr sync in bond_enslave
+    - bonding: move dev_mc_sync after master_upper_dev_link in bond_enslave
+    - bonding: process the err returned by dev_set_allmulti properly in
+      bond_enslave
+    - net: fool proof dev_valid_name()
+    - ip_tunnel: better validate user provided tunnel names
+    - ipv6: sit: better validate user provided tunnel names
+    - ip6_gre: better validate user provided tunnel names
+    - ip6_tunnel: better validate user provided tunnel names
+    - vti6: better validate user provided tunnel names
+    - r8169: fix setting driver_data after register_netdev
+    - net sched actions: fix dumping which requires several messages to user space
+    - net/ipv6: Increment OUTxxx counters after netfilter hook
+    - ipv6: the entire IPv6 header chain must fit the first fragment
+    - vrf: Fix use after free and double free in vrf_finish_output
+    - Revert "xhci: plat: Register shutdown for xhci_plat"
+    - Linux 4.4.128
+
+  * sky2 gigabit ethernet driver sometimes stops working after lid-open resume
+    from sleep (88E8055) (LP: #1758507) // Xenial update to 4.4.128 stable
+    release (LP: #1765010)
+    - sky2: Increase D3 delay to sky2 stops working after suspend
+
+  * Xenial update to 4.4.127 stable release (LP: #1765007)
+    - mtd: jedec_probe: Fix crash in jedec_read_mfr()
+    - ALSA: pcm: Use dma_bytes as size parameter in dma_mmap_coherent()
+    - ALSA: pcm: potential uninitialized return values
+    - partitions/msdos: Unable to mount UFS 44bsd partitions
+    - usb: gadget: define free_ep_req as universal function
+    - usb: gadget: change len to size_t on alloc_ep_req()
+    - usb: gadget: fix usb_ep_align_maybe endianness and new usb_ep_align
+    - usb: gadget: align buffer size when allocating for OUT endpoint
+    - usb: gadget: f_hid: fix: Prevent accessing released memory
+    - kprobes/x86: Fix to set RWX bits correctly before releasing trampoline
+    - ACPI, PCI, irq: remove redundant check for null string pointer
+    - writeback: fix the wrong congested state variable definition
+    - PCI: Make PCI_ROM_ADDRESS_MASK a 32-bit constant
+    - dm ioctl: remove double parentheses
+    - Input: mousedev - fix implicit conversion warning
+    - netfilter: nf_nat_h323: fix logical-not-parentheses warning
+    - genirq: Use cpumask_available() for check of cpumask variable
+    - cpumask: Add helper cpumask_available()
+    - selinux: Remove unnecessary check of array base in selinux_set_mapping()
+    - fs: compat: Remove warning from COMPATIBLE_IOCTL
+    - jiffies.h: declare jiffies and jiffies_64 with ____cacheline_aligned_in_smp
+    - frv: declare jiffies to be located in the .data section
+    - audit: add tty field to LOGIN event
+    - tty: provide tty_name() even without CONFIG_TTY
+    - netfilter: ctnetlink: Make some parameters integer to avoid enum mismatch
+    - selinux: Remove redundant check for unknown labeling behavior
+    - arm64: avoid overflow in VA_START and PAGE_OFFSET
+    - xfrm_user: uncoditionally validate esn replay attribute struct
+    - RDMA/ucma: Check AF family prior resolving address
+    - RDMA/ucma: Fix use-after-free access in ucma_close
+    - RDMA/ucma: Ensure that CM_ID exists prior to access it
+    - RDMA/ucma: Check that device is connected prior to access it
+    - RDMA/ucma: Check that device exists prior to accessing it
+    - RDMA/ucma: Don't allow join attempts for unsupported AF family
+    - RDMA/ucma: Introduce safer rdma_addr_size() variants
+    - net: xfrm: use preempt-safe this_cpu_read() in ipcomp_alloc_tfms()
+    - xfrm: Refuse to insert 32 bit userspace socket policies on 64 bit systems
+    - netfilter: bridge: ebt_among: add more missing match size checks
+    - netfilter: x_tables: add and use xt_check_proc_name
+    - Bluetooth: Fix missing encryption refresh on Security Request
+    - llist: clang: introduce member_address_is_nonnull()
+    - scsi: virtio_scsi: always read VPD pages for multiqueue too
+    - usb: dwc2: Improve gadget state disconnection handling
+    - USB: serial: ftdi_sio: add RT Systems VX-8 cable
+    - USB: serial: ftdi_sio: add support for Harman FirmwareHubEmulator
+    - USB: serial: cp210x: add ELDAT Easywave RX09 id
+    - mei: remove dev_err message on an unsupported ioctl
+    - media: usbtv: prevent double free in error case
+    - parport_pc: Add support for WCH CH382L PCI-E single parallel port card.
+    - crypto: ahash - Fix early termination in hash walk
+    - crypto: x86/cast5-avx - fix ECB encryption when long sg follows short one
+    - fs/proc: Stop trying to report thread stacks
+    - staging: comedi: ni_mio_common: ack ai fifo error interrupts.
+    - Input: i8042 - add Lenovo ThinkPad L460 to i8042 reset list
+    - Input: i8042 - enable MUX on Sony VAIO VGN-CS series to fix touchpad
+    - vt: change SGR 21 to follow the standards
+    - Documentation: pinctrl: palmas: Add ti,palmas-powerhold-override property
+      definition
+    - ARM: dts: dra7: Add power hold and power controller properties to palmas
+    - ARM: dts: am57xx-beagle-x15-common: Add overide powerhold property
+    - md/raid10: reset the 'first' at the end of loop
+    - net: hns: Fix ethtool private flags
+    - Revert "PCI/MSI: Stop disabling MSI/MSI-X in pci_device_shutdown()"
+    - Revert "ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin"
+    - Revert "ARM: dts: omap3-n900: Fix the audio CODEC's reset pin"
+    - Revert "cpufreq: Fix governor module removal race"
+    - Revert "mtip32xx: use runtime tag to initialize command header"
+    - spi: davinci: fix up dma_mapping_error() incorrect patch
+    - net: cavium: liquidio: fix up "Avoid dma_unmap_single on uninitialized
+      ndata"
+    - Revert "ip6_vti: adjust vti mtu according to mtu of lower device"
+    - Linux 4.4.127
+
+  * Xenial update to 4.4.126 stable release (LP: #1764999)
+    - scsi: sg: don't return bogus Sg_requests
+    - Revert "genirq: Use irqd_get_trigger_type to compare the trigger type for
+      shared IRQs"
+    - net: Fix hlist corruptions in inet_evict_bucket()
+    - dccp: check sk for closed state in dccp_sendmsg()
+    - ipv6: fix access to non-linear packet in ndisc_fill_redirect_hdr_option()
+    - l2tp: do not accept arbitrary sockets
+    - net: ethernet: arc: Fix a potential memory leak if an optional regulator is
+      deferred
+    - net: ethernet: ti: cpsw: add check for in-band mode setting with RGMII PHY
+      interface
+    - net/iucv: Free memory obtained by kzalloc
+    - netlink: avoid a double skb free in genlmsg_mcast()
+    - net: Only honor ifindex in IP_PKTINFO if non-0
+    - skbuff: Fix not waking applications when errors are enqueued
+    - team: Fix double free in error path
+    - s390/qeth: free netdevice when removing a card
+    - s390/qeth: when thread completes, wake up all waiters
+    - s390/qeth: lock read device while queueing next buffer
+    - s390/qeth: on channel error, reject further cmd requests
+    - ieee802154: 6lowpan: fix possible NULL deref in lowpan_device_event()
+    - net: fec: Fix unbalanced PM runtime calls
+    - net: systemport: Rewrite __bcm_sysport_tx_reclaim()
+    - Linux 4.4.126
+
+  * Xenial update to 4.4.125 stable release (LP: #1764973)
+    - MIPS: ralink: Remove ralink_halt()
+    - iio: st_pressure: st_accel: pass correct platform data to init
+    - ALSA: usb-audio: Fix parsing descriptor of UAC2 processing unit
+    - ALSA: aloop: Sync stale timer before release
+    - ALSA: aloop: Fix access to not-yet-ready substream via cable
+    - ALSA: hda/realtek - Always immediately update mute LED with pin VREF
+    - mmc: dw_mmc: fix falling from idmac to PIO mode when dw_mci_reset occurs
+    - PCI: Add function 1 DMA alias quirk for Highpoint RocketRAID 644L
+    - ahci: Add PCI-id for the Highpoint Rocketraid 644L card
+    - clk: bcm2835: Protect sections updating shared registers
+    - Bluetooth: btusb: Fix quirk for Atheros 1525/QCA6174
+    - libata: fix length validation of ATAPI-relayed SCSI commands
+    - libata: remove WARN() for DMA or PIO command without data
+    - libata: Apply NOLPM quirk to Crucial MX100 512GB SSDs
+    - libata: Enable queued TRIM for Samsung SSD 860
+    - libata: Apply NOLPM quirk to Crucial M500 480 and 960GB SSDs
+    - libata: Make Crucial BX100 500GB LPM quirk apply to all firmware versions
+    - libata: Modify quirks for MX100 to limit NCQ_TRIM quirk to MU01 version
+    - mm/vmalloc: add interfaces to free unmapped page table
+    - x86/mm: implement free pmd/pte page interfaces
+    - drm/vmwgfx: Fix a destoy-while-held mutex problem.
+    - drm/radeon: Don't turn off DP sink when disconnected
+    - drm: udl: Properly check framebuffer mmap offsets
+    - acpi, numa: fix pxm to online numa node associations
+    - brcmfmac: fix P2P_DEVICE ethernet address generation
+    - rtlwifi: rtl8723be: Fix loss of signal
+    - tracing: probeevent: Fix to support minus offset from symbol
+    - mtd: nand: fsl_ifc: Fix nand waitfunc return value
+    - staging: ncpfs: memory corruption in ncp_read_kernel()
+    - can: cc770: Fix stalls on rt-linux, remove redundant IRQ ack
+    - can: cc770: Fix queue stall & dropped RTR reply
+    - can: cc770: Fix use after free in cc770_tx_interrupt()
+    - tty: vt: fix up tabstops properly
+    - x86/build/64: Force the linker to use 2MB page size
+    - x86/boot/64: Verify alignment of the LOAD segment
+    - perf/x86/intel: Don't accidentally clear high bits in bdw_limit_period()
+    - staging: lustre: ptlrpc: kfree used instead of kvfree
+    - kbuild: disable clang's default use of -fmerge-all-constants
+    - bpf: skip unnecessary capability check
+    - bpf, x64: increase number of passes
+    - Linux 4.4.125
+
+  * System fails to start (boot) on battery due to read-only root file-system
+    (LP: #1726930) // Xenial update to 4.4.125 stable release (LP: #1764973)
+    - libata: disable LPM for Crucial BX100 SSD 500GB drive
+
+  * Xenial update to 4.4.124 stable release (LP: #1764762)
+    - tpm: fix potential buffer overruns caused by bit glitches on the bus
+    - tpm_tis: fix potential buffer overruns caused by bit glitches on the bus
+    - staging: android: ashmem: Fix possible deadlock in ashmem_ioctl
+    - platform/x86: asus-nb-wmi: Add wapf4 quirk for the X302UA
+    - regulator: anatop: set default voltage selector for pcie
+    - x86: i8259: export legacy_pic symbol
+    - rtc: cmos: Do not assume irq 8 for rtc when there are no legacy irqs
+    - Input: ar1021_i2c - fix too long name in driver's device table
+    - time: Change posix clocks ops interfaces to use timespec64
+    - ACPI/processor: Fix error handling in __acpi_processor_start()
+    - ACPI/processor: Replace racy task affinity logic
+    - cpufreq/sh: Replace racy task affinity logic
+    - genirq: Use irqd_get_trigger_type to compare the trigger type for shared
+      IRQs
+    - i2c: i2c-scmi: add a MS HID
+    - net: ipv6: send unsolicited NA on admin up
+    - media/dvb-core: Race condition when writing to CAM
+    - spi: dw: Disable clock after unregistering the host
+    - ath: Fix updating radar flags for coutry code India
+    - clk: ns2: Correct SDIO bits
+    - scsi: virtio_scsi: Always try to read VPD pages
+    - KVM: PPC: Book3S PR: Exit KVM on failed mapping
+    - ARM: 8668/1: ftrace: Fix dynamic ftrace with DEBUG_RODATA and !FRAME_POINTER
+    - iommu/omap: Register driver before setting IOMMU ops
+    - md/raid10: wait up frozen array in handle_write_completed
+    - NFS: Fix missing pg_cleanup after nfs_pageio_cond_complete()
+    - tcp: remove poll() flakes with FastOpen
+    - e1000e: fix timing for 82579 Gigabit Ethernet controller
+    - ALSA: hda - Fix headset microphone detection for ASUS N551 and N751
+    - IB/ipoib: Fix deadlock between ipoib_stop and mcast join flow
+    - IB/ipoib: Update broadcast object if PKey value was changed in index 0
+    - HSI: ssi_protocol: double free in ssip_pn_xmit()
+    - IB/mlx4: Take write semaphore when changing the vma struct
+    - IB/mlx4: Change vma from shared to private
+    - ASoC: Intel: Skylake: Uninitialized variable in probe_codec()
+    - Fix driver usage of 128B WQEs when WQ_CREATE is V1.
+    - netfilter: xt_CT: fix refcnt leak on error path
+    - openvswitch: Delete conntrack entry clashing with an expectation.
+    - mmc: host: omap_hsmmc: checking for NULL instead of IS_ERR()
+    - wan: pc300too: abort path on failure
+    - qlcnic: fix unchecked return value
+    - scsi: mac_esp: Replace bogus memory barrier with spinlock
+    - infiniband/uverbs: Fix integer overflows
+    - NFS: don't try to cross a mountpount when there isn't one there.
+    - Revert "UBUNTU: SAUCE: (no-up) iio: st_pressure: st_accel: Initialise sensor
+      platform data properly"
+    - iio: st_pressure: st_accel: Initialise sensor platform data properly
+    - mt7601u: check return value of alloc_skb
+    - rndis_wlan: add return value validation
+    - Btrfs: send, fix file hole not being preserved due to inline extent
+    - mac80211: don't parse encrypted management frames in ieee80211_frame_acked
+    - mfd: palmas: Reset the POWERHOLD mux during power off
+    - mtip32xx: use runtime tag to initialize command header
+    - staging: unisys: visorhba: fix s-Par to boot with option CONFIG_VMAP_STACK
+      set to y
+    - staging: wilc1000: fix unchecked return value
+    - mmc: sdhci-of-esdhc: limit SD clock for ls1012a/ls1046a
+    - ARM: DRA7: clockdomain: Change the CLKTRCTRL of CM_PCIE_CLKSTCTRL to SW_WKUP
+    - ipmi/watchdog: fix wdog hang on panic waiting for ipmi response
+    - ACPI / PMIC: xpower: Fix power_table addresses
+    - drm/nouveau/kms: Increase max retries in scanout position queries.
+    - bnx2x: Align RX buffers
+    - power: supply: pda_power: move from timer to delayed_work
+    - Input: twl4030-pwrbutton - use correct device for irq request
+    - md/raid10: skip spare disk as 'first' disk
+    - ia64: fix module loading for gcc-5.4
+    - tcm_fileio: Prevent information leak for short reads
+    - video: fbdev: udlfb: Fix buffer on stack
+    - sm501fb: don't return zero on failure path in sm501fb_start()
+    - net: hns: fix ethtool_get_strings overflow in hns driver
+    - cifs: small underflow in cnvrtDosUnixTm()
+    - rtc: ds1374: wdt: Fix issue with timeout scaling from secs to wdt ticks
+    - rtc: ds1374: wdt: Fix stop/start ioctl always returning -EINVAL
+    - perf tests kmod-path: Don't fail if compressed modules aren't supported
+    - Bluetooth: hci_qca: Avoid setup failure on missing rampatch
+    - media: c8sectpfe: fix potential NULL pointer dereference in
+      c8sectpfe_timer_interrupt
+    - drm/msm: fix leak in failed get_pages
+    - RDMA/iwpm: Fix uninitialized error code in iwpm_send_mapinfo()
+    - rtlwifi: rtl_pci: Fix the bug when inactiveps is enabled.
+    - media: bt8xx: Fix err 'bt878_probe()'
+    - media: [RESEND] media: dvb-frontends: Add delay to Si2168 restart
+    - cros_ec: fix nul-termination for firmware build info
+    - platform/chrome: Use proper protocol transfer function
+    - mmc: avoid removing non-removable hosts during suspend
+    - IB/ipoib: Avoid memory leak if the SA returns a different DGID
+    - RDMA/cma: Use correct size when writing netlink stats
+    - IB/umem: Fix use of npages/nmap fields
+    - vgacon: Set VGA struct resource types
+    - drm/omap: DMM: Check for DMM readiness after successful transaction commit
+    - pty: cancel pty slave port buf's work in tty_release
+    - coresight: Fix disabling of CoreSight TPIU
+    - pinctrl: Really force states during suspend/resume
+    - iommu/vt-d: clean up pr_irq if request_threaded_irq fails
+    - ip6_vti: adjust vti mtu according to mtu of lower device
+    - RDMA/ocrdma: Fix permissions for OCRDMA_RESET_STATS
+    - nfsd4: permit layoutget of executable-only files
+    - clk: si5351: Rename internal plls to avoid name collisions
+    - dmaengine: ti-dma-crossbar: Fix event mapping for TPCC_EVT_MUX_60_63
+    - RDMA/ucma: Fix access to non-initialized CM_ID object
+    - Linux 4.4.124
+
+  * Xenial update to 4.4.123 stable release (LP: #1764666)
+    - blkcg: fix double free of new_blkg in blkcg_init_queue
+    - Input: tsc2007 - check for presence and power down tsc2007 during probe
+    - staging: speakup: Replace BUG_ON() with WARN_ON().
+    - staging: wilc1000: add check for kmalloc allocation failure.
+    - HID: reject input outside logical range only if null state is set
+    - drm: qxl: Don't alloc fbdev if emulation is not supported
+    - ath10k: fix a warning during channel switch with multiple vaps
+    - PCI/MSI: Stop disabling MSI/MSI-X in pci_device_shutdown()
+    - selinux: check for address length in selinux_socket_bind()
+    - perf sort: Fix segfault with basic block 'cycles' sort dimension
+    - i40e: Acquire NVM lock before reads on all devices
+    - i40e: fix ethtool to get EEPROM data from X722 interface
+    - perf tools: Make perf_event__synthesize_mmap_events() scale
+    - drivers: net: xgene: Fix hardware checksum setting
+    - drm: Defer disabling the vblank IRQ until the next interrupt (for instant-
+      off)
+    - ath10k: disallow DFS simulation if DFS channel is not enabled
+    - perf probe: Return errno when not hitting any event
+    - HID: clamp input to logical range if no null state
+    - net/8021q: create device with all possible features in wanted_features
+    - ARM: dts: Adjust moxart IRQ controller and flags
+    - batman-adv: handle race condition for claims between gateways
+    - of: fix of_device_get_modalias returned length when truncating buffers
+    - solo6x10: release vb2 buffers in solo_stop_streaming()
+    - scsi: ipr: Fix missed EH wakeup
+    - media: i2c/soc_camera: fix ov6650 sensor getting wrong clock
+    - timers, sched_clock: Update timeout for clock wrap
+    - sysrq: Reset the watchdog timers while displaying high-resolution timers
+    - Input: qt1070 - add OF device ID table
+    - sched: act_csum: don't mangle TCP and UDP GSO packets
+    - ASoC: rcar: ssi: don't set SSICR.CKDV = 000 with SSIWSR.CONT
+    - spi: omap2-mcspi: poll OMAP2_MCSPI_CHSTAT_RXS for PIO transfer
+    - tcp: sysctl: Fix a race to avoid unexpected 0 window from space
+    - dmaengine: imx-sdma: add 1ms delay to ensure SDMA channel is stopped
+    - driver: (adm1275) set the m,b and R coefficients correctly for power
+    - mm: Fix false-positive VM_BUG_ON() in page_cache_{get,add}_speculative()
+    - blk-throttle: make sure expire time isn't too big
+    - f2fs: relax node version check for victim data in gc
+    - bonding: refine bond_fold_stats() wrap detection
+    - braille-console: Fix value returned by _braille_console_setup
+    - drm/vmwgfx: Fixes to vmwgfx_fb
+    - vxlan: vxlan dev should inherit lowerdev's gso_max_size
+    - NFC: nfcmrvl: Include unaligned.h instead of access_ok.h
+    - NFC: nfcmrvl: double free on error path
+    - ARM: dts: r8a7790: Correct parent of SSI[0-9] clocks
+    - ARM: dts: r8a7791: Correct parent of SSI[0-9] clocks
+    - powerpc: Avoid taking a data miss on every userspace instruction miss
+    - net/faraday: Add missing include of of.h
+    - ARM: dts: koelsch: Correct clock frequency of X2 DU clock input
+    - reiserfs: Make cancel_old_flush() reliable
+    - ALSA: firewire-digi00x: handle all MIDI messages on streaming packets
+    - fm10k: correctly check if interface is removed
+    - apparmor: Make path_max parameter readonly
+    - iommu/iova: Fix underflow bug in __alloc_and_insert_iova_range
+    - video: ARM CLCD: fix dma allocation size
+    - drm/radeon: Fail fb creation from imported dma-bufs.
+    - drm/amdgpu: Fail fb creation from imported dma-bufs. (v2)
+    - coresight: Fixes coresight DT parse to get correct output port ID.
+    - MIPS: BPF: Quit clobbering callee saved registers in JIT code.
+    - MIPS: BPF: Fix multiple problems in JIT skb access helpers.
+    - MIPS: r2-on-r6-emu: Fix BLEZL and BGTZL identification
+    - MIPS: r2-on-r6-emu: Clear BLTZALL and BGEZALL debugfs counters
+    - regulator: isl9305: fix array size
+    - md/raid6: Fix anomily when recovering a single device in RAID6.
+    - usb: dwc2: Make sure we disconnect the gadget state
+    - usb: gadget: dummy_hcd: Fix wrong power status bit clear/reset in
+      dummy_hub_control()
+    - drivers/perf: arm_pmu: handle no platform_device
+    - perf inject: Copy events when reordering events in pipe mode
+    - perf session: Don't rely on evlist in pipe mode
+    - scsi: sg: check for valid direction before starting the request
+    - scsi: sg: close race condition in sg_remove_sfp_usercontext()
+    - kprobes/x86: Fix kprobe-booster not to boost far call instructions
+    - kprobes/x86: Set kprobes pages read-only
+    - pwm: tegra: Increase precision in PWM rate calculation
+    - wil6210: fix memory access violation in wil_memcpy_from/toio_32
+    - drm/edid: set ELD connector type in drm_edid_to_eld()
+    - video/hdmi: Allow "empty" HDMI infoframes
+    - HID: elo: clear BTN_LEFT mapping
+    - ARM: dts: exynos: Correct Trats2 panel reset line
+    - sched: Stop switched_to_rt() from sending IPIs to offline CPUs
+    - sched: Stop resched_cpu() from sending IPIs to offline CPUs
+    - test_firmware: fix setting old custom fw path back on exit
+    - net: xfrm: allow clearing socket xfrm policies.
+    - mtd: nand: fix interpretation of NAND_CMD_NONE in nand_command[_lp]()
+    - ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin
+    - ARM: dts: omap3-n900: Fix the audio CODEC's reset pin
+    - ath10k: update tdls teardown state to target
+    - cpufreq: Fix governor module removal race
+    - clk: qcom: msm8916: fix mnd_width for codec_digcodec
+    - ath10k: fix invalid STS_CAP_OFFSET_MASK
+    - tools/usbip: fixes build with musl libc toolchain
+    - spi: sun6i: disable/unprepare clocks on remove
+    - scsi: core: scsi_get_device_flags_keyed(): Always return device flags
+    - scsi: devinfo: apply to HP XP the same flags as Hitachi VSP
+    - scsi: dh: add new rdac devices
+    - media: cpia2: Fix a couple off by one bugs
+    - veth: set peer GSO values
+    - drm/amdkfd: Fix memory leaks in kfd topology
+    - agp/intel: Flush all chipset writes after updating the GGTT
+    - mac80211_hwsim: enforce PS_MANUAL_POLL to be set after PS_ENABLED
+    - mac80211: remove BUG() when interface type is invalid
+    - ASoC: nuc900: Fix a loop timeout test
+    - ipvlan: add L2 check for packets arriving via virtual devices
+    - rcutorture/configinit: Fix build directory error message
+    - ima: relax requiring a file signature for new files with zero length
+    - selftests/x86/entry_from_vm86: Exit with 1 if we fail
+    - selftests/x86: Add tests for User-Mode Instruction Prevention
+    - selftests/x86: Add tests for the STR and SLDT instructions
+    - selftests/x86/entry_from_vm86: Add test cases for POPF
+    - x86/vm86/32: Fix POPF emulation
+    - x86/mm: Fix vmalloc_fault to use pXd_large
+    - ALSA: pcm: Fix UAF in snd_pcm_oss_get_formats()
+    - ALSA: hda - Revert power_save option default value
+    - ALSA: seq: Fix possible UAF in snd_seq_check_queue()
+    - ALSA: seq: Clear client entry before deleting else at closing
+    - drm/amdgpu/dce: Don't turn off DP sink when disconnected
+    - fs: Teach path_connected to handle nfs filesystems with multiple roots.
+    - lock_parent() needs to recheck if dentry got __dentry_kill'ed under it
+    - fs/aio: Add explicit RCU grace period when freeing kioctx
+    - fs/aio: Use RCU accessors for kioctx_table->table[]
+    - irqchip/gic-v3-its: Ensure nr_ites >= nr_lpis
+    - scsi: sg: fix SG_DXFER_FROM_DEV transfers
+    - scsi: sg: fix static checker warning in sg_is_valid_dxfer
+    - scsi: sg: only check for dxfer_len greater than 256M
+    - ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux
+    - btrfs: alloc_chunk: fix DUP stripe size handling
+    - btrfs: Fix use-after-free when cleaning up fs_devs with a single stale
+      device
+    - USB: gadget: udc: Add missing platform_device_put() on error in
+      bdc_pci_probe()
+    - usb: gadget: bdc: 64-bit pointer capability check
+    - Linux 4.4.123
+
+  * Xenial update to 4.4.123 stable release (LP: #1764666) // CVE-2017-16995
+    - Revert "bpf: fix incorrect sign extension in check_alu_op()"
+    - bpf: fix incorrect sign extension in check_alu_op()
+
+  * Xenial update to 4.4.122 stable release (LP: #1764627)
+    - RDMA/ucma: Limit possible option size
+    - RDMA/ucma: Check that user doesn't overflow QP state
+    - RDMA/mlx5: Fix integer overflow while resizing CQ
+    - scsi: qla2xxx: Fix NULL pointer crash due to active timer for ABTS
+    - workqueue: Allow retrieval of current task's work struct
+    - drm: Allow determining if current task is output poll worker
+    - drm/nouveau: Fix deadlock on runtime suspend
+    - drm/radeon: Fix deadlock on runtime suspend
+    - drm/amdgpu: Fix deadlock on runtime suspend
+    - drm/amdgpu: Notify sbios device ready before send request
+    - drm/radeon: fix KV harvesting
+    - drm/amdgpu: fix KV harvesting
+    - MIPS: BMIPS: Do not mask IPIs during suspend
+    - MIPS: ath25: Check for kzalloc allocation failure
+    - MIPS: OCTEON: irq: Check for null return on kzalloc allocation
+    - Input: matrix_keypad - fix race when disabling interrupts
+    - loop: Fix lost writes caused by missing flag
+    - kbuild: Handle builtin dtb file names containing hyphens
+    - bcache: don't attach backing with duplicate UUID
+    - x86/MCE: Serialize sysfs changes
+    - ALSA: hda/realtek - Fix dock line-out volume on Dell Precision 7520
+    - ALSA: seq: More protection for concurrent write and ioctl races
+    - ALSA: hda: add dock and led support for HP EliteBook 820 G3
+    - ALSA: hda: add dock and led support for HP ProBook 640 G2
+    - watchdog: hpwdt: SMBIOS check
+    - watchdog: hpwdt: Check source of NMI
+    - watchdog: hpwdt: fix unused variable warning
+    - netfilter: nfnetlink_queue: fix timestamp attribute
+    - Input: tca8418_keypad - remove double read of key event register
+    - tc358743: fix register i2c_rd/wr function fix
+    - netfilter: add back stackpointer size checks
+    - netfilter: x_tables: fix missing timer initialization in xt_LED
+    - netfilter: nat: cope with negative port range
+    - netfilter: IDLETIMER: be syzkaller friendly
+    - netfilter: ebtables: CONFIG_COMPAT: don't trust userland offsets
+    - netfilter: bridge: ebt_among: add missing match size checks
+    - netfilter: ipv6: fix use-after-free Write in nf_nat_ipv6_manip_pkt
+    - netfilter: use skb_to_full_sk in ip_route_me_harder
+    - ext4: inplace xattr block update fails to deduplicate blocks
+    - ubi: Fix race condition between ubi volume creation and udev
+    - scsi: qla2xxx: Replace fcport alloc with qla2x00_alloc_fcport
+    - NFS: Fix an incorrect type in struct nfs_direct_req
+    - Revert "ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux"
+    - x86/module: Detect and skip invalid relocations
+    - x86: Treat R_X86_64_PLT32 as R_X86_64_PC32
+    - serial: sh-sci: prevent lockup on full TTY buffers
+    - tty/serial: atmel: add new version check for usart
+    - uas: fix comparison for error code
+    - staging: comedi: fix comedi_nsamples_left.
+    - staging: android: ashmem: Fix lockdep issue during llseek
+    - USB: storage: Add JMicron bridge 152d:2567 to unusual_devs.h
+    - usb: quirks: add control message delay for 1b1c:1b20
+    - USB: usbmon: remove assignment from IS_ERR argument
+    - usb: usbmon: Read text within supplied buffer size
+    - usb: gadget: f_fs: Fix use-after-free in ffs_fs_kill_sb()
+    - serial: 8250_pci: Add Brainboxes UC-260 4 port serial device
+    - fixup: sctp: verify size of a new chunk in _sctp_make_chunk()
+    - Linux 4.4.122
+
+  * Xenial update to 4.4.122 stable release (LP: #1764627) // CVE-2018-1000004.
+    - ALSA: seq: Don't allow resizing pool in use
+
+  * Xenial update to 4.4.121 stable release (LP: #1764367)
+    - tpm: st33zp24: fix potential buffer overruns caused by bit glitches on the
+      bus
+    - tpm_i2c_infineon: fix potential buffer overruns caused by bit glitches on
+      the bus
+    - tpm_i2c_nuvoton: fix potential buffer overruns caused by bit glitches on the
+      bus
+    - ALSA: usb-audio: Add a quirck for B&W PX headphones
+    - ALSA: hda: Add a power_save blacklist
+    - cpufreq: s3c24xx: Fix broken s3c_cpufreq_init()
+    - media: m88ds3103: don't call a non-initalized function
+    - ARM: mvebu: Fix broken PL310_ERRATA_753970 selects
+    - KVM: mmu: Fix overlap between public and private memslots
+    - btrfs: Don't clear SGID when inheriting ACLs
+    - ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux
+    - x86/apic/vector: Handle legacy irq data correctly
+    - leds: do not overflow sysfs buffer in led_trigger_show
+    - x86/spectre: Fix an error message
+    - bridge: check brport attr show in brport_show
+    - fib_semantics: Don't match route with mismatching tclassid
+    - hdlc_ppp: carrier detect ok, don't turn off negotiation
+    - ipv6 sit: work around bogus gcc-8 -Wrestrict warning
+    - net: fix race on decreasing number of TX queues
+    - net: ipv4: don't allow setting net.ipv4.route.min_pmtu below 68
+    - netlink: ensure to loop over all netns in genlmsg_multicast_allns()
+    - ppp: prevent unregistered channels from connecting to PPP units
+    - udplite: fix partial checksum initialization
+    - sctp: fix dst refcnt leak in sctp_v4_get_dst
+    - sctp: fix dst refcnt leak in sctp_v6_get_dst()
+    - s390/qeth: fix SETIP command handling
+    - s390/qeth: fix IPA command submission race
+    - sctp: verify size of a new chunk in _sctp_make_chunk()
+    - net: mpls: Pull common label check into helper
+    - dm io: fix duplicate bio completion due to missing ref count
+    - bpf, x64: implement retpoline for tail call
+    - btrfs: preserve i_mode if __btrfs_set_acl() fails
+    - Linux 4.4.121
+
+  * Xenial update to 4.4.120 stable release (LP: #1764316)
+    - hrtimer: Ensure POSIX compliance (relative CLOCK_REALTIME hrtimers)
+    - f2fs: fix a bug caused by NULL extent tree
+    - mtd: nand: gpmi: Fix failure when a erased page has a bitflip at BBM
+    - ipv6: icmp6: Allow icmp messages to be looped back
+    - ARM: 8731/1: Fix csum_partial_copy_from_user() stack mismatch
+    - sget(): handle failures of register_shrinker()
+    - drm/nouveau/pci: do a msi rearm on init
+    - spi: atmel: fixed spin_lock usage inside atmel_spi_remove
+    - net: arc_emac: fix arc_emac_rx() error paths
+    - scsi: storvsc: Fix scsi_cmd error assignments in storvsc_handle_error
+    - ARM: dts: ls1021a: fix incorrect clock references
+    - lib/mpi: Fix umul_ppmm() for MIPS64r6
+    - tg3: Add workaround to restrict 5762 MRRS to 2048
+    - tg3: Enable PHY reset in MTU change path for 5720
+    - bnx2x: Improve reliability in case of nested PCI errors
+    - s390/dasd: fix wrongly assigned configuration data
+    - IB/mlx4: Fix mlx4_ib_alloc_mr error flow
+    - IB/ipoib: Fix race condition in neigh creation
+    - xfs: quota: fix missed destroy of qi_tree_lock
+    - xfs: quota: check result of register_shrinker()
+    - e1000: fix disabling already-disabled warning
+    - drm/ttm: check the return value of kzalloc
+    - mac80211: mesh: drop frames appearing to be from us
+    - can: flex_can: Correct the checking for frame length in flexcan_start_xmit()
+    - bnxt_en: Fix the 'Invalid VF' id check in bnxt_vf_ndo_prep routine.
+    - xen-netfront: enable device after manual module load
+    - mdio-sun4i: Fix a memory leak
+    - SolutionEngine771x: fix Ether platform data
+    - xen/gntdev: Fix off-by-one error when unmapping with holes
+    - xen/gntdev: Fix partial gntdev_mmap() cleanup
+    - sctp: make use of pre-calculated len
+    - net: gianfar_ptp: move set_fipers() to spinlock protecting area
+    - MIPS: Implement __multi3 for GCC7 MIPS64r6 builds
+    - Linux 4.4.120
+
+  * Xenial update to 4.4.119 stable release (LP: #1762453)
+    - netfilter: drop outermost socket lock in getsockopt()
+    - powerpc/64s: Fix RFI flush dependency on HARDLOCKUP_DETECTOR
+    - PCI: keystone: Fix interrupt-controller-node lookup
+    - ip_tunnel: replace dst_cache with generic implementation
+    - ip_tunnel: fix preempt warning in ip tunnel creation/updating
+    - scsi: ibmvfc: fix misdefined reserved field in ibmvfc_fcp_rsp_info
+    - cfg80211: fix cfg80211_beacon_dup
+    - iio: buffer: check if a buffer has been set up when poll is called
+    - iio: adis_lib: Initialize trigger before requesting interrupt
+    - x86/oprofile: Fix bogus GCC-8 warning in nmi_setup()
+    - irqchip/gic-v3: Use wmb() instead of smb_wmb() in gic_raise_softirq()
+    - usb: ohci: Proper handling of ed_rm_list to handle race condition between
+      usb_kill_urb() and finish_unlinks()
+    - arm64: Disable unhandled signal log messages by default
+    - Add delay-init quirk for Corsair K70 RGB keyboards
+    - usb: dwc3: gadget: Set maxpacket size for ep0 IN
+    - usb: ldusb: add PIDs for new CASSY devices supported by this driver
+    - usb: gadget: f_fs: Process all descriptors during bind
+    - usb: renesas_usbhs: missed the "running" flag in usb_dmac with rx path
+    - drm/amdgpu: Avoid leaking PM domain on driver unbind (v2)
+    - binder: add missing binder_unlock()
+    - Linux 4.4.119
+
+  * [regression] Colour banding and artefacts appear system-wide on an Asus
+    Zenbook UX303LA with Intel HD 4400 graphics (LP: #1749420) // Xenial update
+    to 4.4.119 stable release (LP: #1762453)
+    - drm/edid: Add 6 bpc quirk for CPT panel in Asus UX303LA
+
+  * Xenial update to 4.4.118 stable release (LP: #1756866)
+    - net: add dst_cache support
+    - [Config] Add CONFIG_DST_CACHE=y
+    - net: replace dst_cache ip6_tunnel implementation with the generic one
+    - cfg80211: check dev_set_name() return value
+    - mm,vmscan: Make unregister_shrinker() no-op if register_shrinker() failed.
+    - xfrm: Fix stack-out-of-bounds read on socket policy lookup.
+    - xfrm: check id proto in validate_tmpl()
+    - blktrace: fix unlocked registration of tracepoints
+    - drm: Require __GFP_NOFAIL for the legacy drm_modeset_lock_all
+    - Provide a function to create a NUL-terminated string from unterminated data
+    - selinux: ensure the context is NUL terminated in
+      security_context_to_sid_core()
+    - selinux: skip bounded transition processing if the policy isn't loaded
+    - crypto: x86/twofish-3way - Fix %rbp usage
+    - KVM: x86: fix escape of guest dr6 to the host
+    - netfilter: x_tables: fix int overflow in xt_alloc_table_info()
+    - netfilter: x_tables: avoid out-of-bounds reads in
+      xt_request_find_{match|target}
+    - netfilter: ipt_CLUSTERIP: fix out-of-bounds accesses in clusterip_tg_check()
+    - netfilter: on sockopt() acquire sock lock only in the required scope
+    - netfilter: xt_RATEEST: acquire xt_rateest_mutex for hash insert
+    - net: avoid skb_warn_bad_offload on IS_ERR
+    - ASoC: ux500: add MODULE_LICENSE tag
+    - video: fbdev/mmp: add MODULE_LICENSE
+    - arm64: dts: add #cooling-cells to CPU nodes
+    - Make DST_CACHE a silent config option
+    - dn_getsockoptdecnet: move nf_{get/set}sockopt outside sock lock
+    - staging: android: ashmem: Fix a race condition in pin ioctls
+    - binder: check for binder_thread allocation failure in binder_poll()
+    - staging: iio: adc: ad7192: fix external frequency setting
+    - usbip: keep usbip_device sockfd state in sync with tcp_socket
+    - usb: build drivers/usb/common/ when USB_SUPPORT is set
+    - ARM: OMAP2+: Fix SRAM virt to phys translation for save_secure_ram_context
+    - ARM: AM33xx: PRM: Remove am33xx_pwrdm_read_prev_pwrst function
+    - ARM: dts: Fix omap4 hang with GPS connected to USB by using wakeupgen
+    - ARM: dts: am4372: Correct the interrupts_properties of McASP
+    - perf top: Fix window dimensions change handling
+    - perf bench numa: Fixup discontiguous/sparse numa nodes
+    - media: s5k6aa: describe some function parameters
+    - pinctrl: sunxi: Fix A80 interrupt pin bank
+    - RDMA/cma: Make sure that PSN is not over max allowed
+    - scripts/kernel-doc: Don't fail with status != 0 if error encountered with
+      -none
+    - ipvlan: Add the skb->mark as flow4's member to lookup route
+    - powerpc/perf: Fix oops when grouping different pmu events
+    - s390/dasd: prevent prefix I/O error
+    - gianfar: fix a flooded alignment reports because of padding issue.
+    - net_sched: red: Avoid devision by zero
+    - net_sched: red: Avoid illegal values
+    - btrfs: Fix possible off-by-one in btrfs_search_path_in_tree
+    - 509: fix printing uninitialized stack memory when OID is empty
+    - dmaengine: ioat: Fix error handling path
+    - dmaengine: at_hdmac: fix potential NULL pointer dereference in
+      atc_prep_dma_interleaved
+    - clk: fix a panic error caused by accessing NULL pointer
+    - ASoC: rockchip: disable clock on error
+    - spi: sun4i: disable clocks in the remove function
+    - xfrm: Fix stack-out-of-bounds with misconfigured transport mode policies.
+    - drm/armada: fix leak of crtc structure
+    - dmaengine: jz4740: disable/unprepare clk if probe fails
+    - mm/early_ioremap: Fix boot hang with earlyprintk=efi,keep
+    - x86/mm/kmmio: Fix mmiotrace for page unaligned addresses
+    - xen: XEN_ACPI_PROCESSOR is Dom0-only
+    - hippi: Fix a Fix a possible sleep-in-atomic bug in rr_close
+    - virtio_balloon: prevent uninitialized variable use
+    - isdn: icn: remove a #warning
+    - vmxnet3: prevent building with 64K pages
+    - [Config] ppc64el: Drop vmxnet3 module
+    - gpio: intel-mid: Fix build warning when !CONFIG_PM
+    - platform/x86: intel_mid_thermal: Fix suspend handlers unused warning
+    - video: fbdev: via: remove possibly unused variables
+    - scsi: advansys: fix build warning for PCI=n
+    - x86/ras/inject: Make it depend on X86_LOCAL_APIC=y
+    - arm64: define BUG() instruction without CONFIG_BUG
+    - x86/fpu/math-emu: Fix possible uninitialized variable use
+    - tools build: Add tools tree support for 'make -s'
+    - x86/build: Silence the build with "make -s"
+    - thermal: fix INTEL_SOC_DTS_IOSF_CORE dependencies
+    - x86: add MULTIUSER dependency for KVM
+    - x86/platform: Add PCI dependency for PUNIT_ATOM_DEBUG
+    - scsi: advansys: fix uninitialized data access
+    - arm64: Kconfig: select COMPAT_BINFMT_ELF only when BINFMT_ELF is set
+    - ALSA: hda/ca0132 - fix possible NULL pointer use
+    - reiserfs: avoid a -Wmaybe-uninitialized warning
+    - ssb: mark ssb_bus_register as __maybe_unused
+    - thermal: spear: use __maybe_unused for PM functions
+    - x86/boot: Avoid warning for zero-filling .bss
+    - scsi: sim710: fix build warning
+    - drivers/net: fix eisa_driver probe section mismatch
+    - dpt_i2o: fix build warning
+    - profile: hide unused functions when !CONFIG_PROC_FS
+    - md: avoid warning for 32-bit sector_t
+    - mtd: ichxrom: maybe-uninitialized with gcc-4.9
+    - mtd: maps: add __init attribute
+    - mptfusion: hide unused seq_mpt_print_ioc_summary function
+    - scsi: fdomain: drop fdomain_pci_tbl when built-in
+    - video: fbdev: sis: remove unused variable
+    - staging: ste_rmi4: avoid unused function warnings
+    - fbdev: sis: enforce selection of at least one backend
+    - video: Use bool instead int pointer for get_opt_bool() argument
+    - scsi: mvumi: use __maybe_unused to hide pm functions
+    - SCSI: initio: remove duplicate module device table
+    - pwc: hide unused label
+    - usb: musb/ux500: remove duplicate check for dma_is_compatible
+    - tty: hvc_xen: hide xen_console_remove when unused
+    - target/user: Fix cast from pointer to phys_addr_t
+    - driver-core: use 'dev' argument in dev_dbg_ratelimited stub
+    - fbdev: auo_k190x: avoid unused function warnings
+    - amd-xgbe: Fix unused suspend handlers build warning
+    - mtd: sh_flctl: pass FIFO as physical address
+    - mtd: cfi: enforce valid geometry configuration
+    - fbdev: s6e8ax0: avoid unused function warnings
+    - modsign: hide openssl output in silent builds
+    - fbdev: sm712fb: avoid unused function warnings
+    - hwrng: exynos - use __maybe_unused to hide pm functions
+    - USB: cdc_subset: only build when one driver is enabled
+    - [Config] Add CONFIG_USB_NET_CDC_SUBSET_ENABLE=m
+    - rtlwifi: fix gcc-6 indentation warning
+    - staging: wilc1000: fix kbuild test robot error
+    - x86/platform/olpc: Fix resume handler build warning
+    - netfilter: ipvs: avoid unused variable warnings
+    - ipv4: ipconfig: avoid unused ic_proto_used symbol
+    - tc1100-wmi: fix build warning when CONFIG_PM not enabled
+    - tlan: avoid unused label with PCI=n
+    - drm/vmwgfx: use *_32_bits() macros
+    - tty: cyclades: cyz_interrupt is only used for PCI
+    - genirq/msi: Add stubs for get_cached_msi_msg/pci_write_msi_msg
+    - ASoC: mediatek: add i2c dependency
+    - iio: adc: axp288: remove redundant duplicate const on axp288_adc_channels
+    - infiniband: cxgb4: use %pR format string for printing resources
+    - b2c2: flexcop: avoid unused function warnings
+    - i2c: remove __init from i2c_register_board_info()
+    - staging: unisys: visorinput depends on INPUT
+    - tc358743: fix register i2c_rd/wr functions
+    - drm/nouveau: hide gcc-4.9 -Wmaybe-uninitialized
+    - Input: tca8418_keypad - hide gcc-4.9 -Wmaybe-uninitialized warning
+    - KVM: add X86_LOCAL_APIC dependency
+    - go7007: add MEDIA_CAMERA_SUPPORT dependency
+    - em28xx: only use mt9v011 if camera support is enabled
+    - ISDN: eicon: reduce stack size of sig_ind function
+    - ASoC: rockchip: use __maybe_unused to hide st_irq_syscfg_resume
+    - serial: 8250_mid: fix broken DMA dependency
+    - drm/gma500: Sanity-check pipe index
+    - hdpvr: hide unused variable
+    - v4l: remove MEDIA_TUNER dependency for VIDEO_TUNER
+    - cw1200: fix bogus maybe-uninitialized warning
+    - wireless: cw1200: use __maybe_unused to hide pm functions_
+    - perf/x86: Shut up false-positive -Wmaybe-uninitialized warning
+    - dmaengine: zx: fix build warning
+    - net: hp100: remove unnecessary #ifdefs
+    - gpio: xgene: mark PM functions as __maybe_unused
+    - ncpfs: fix unused variable warning
+    - Revert "power: bq27xxx_battery: Remove unneeded dependency in Kconfig"
+    - power: bq27xxx_battery: mark some symbols __maybe_unused
+    - isdn: sc: work around type mismatch warning
+    - binfmt_elf: compat: avoid unused function warning
+    - idle: i7300: add PCI dependency
+    - usb: phy: msm add regulator dependency
+    - ncr5380: shut up gcc indentation warning
+    - ARM: tegra: select USB_ULPI from EHCI rather than platform
+    - ASoC: Intel: Kconfig: fix build when ACPI is not enabled
+    - netlink: fix nla_put_{u8,u16,u32} for KASAN
+    - dell-wmi, dell-laptop: depends DMI
+    - genksyms: Fix segfault with invalid declarations
+    - x86/microcode/AMD: Change load_microcode_amd()'s param to bool to fix
+      preemptibility bug
+    - drm/gma500: remove helper function
+    - kasan: rework Kconfig settings
+    - KVM: async_pf: Fix #DF due to inject "Page not Present" and "Page Ready"
+      exceptions simultaneously
+    - x86/retpoline: Remove the esp/rsp thunk
+    - module/retpoline: Warn about missing retpoline in module
+    - x86/nospec: Fix header guards names
+    - x86/bugs: Drop one "mitigation" from dmesg
+    - x86/cpu/bugs: Make retpoline module warning conditional
+    - x86/spectre: Check CONFIG_RETPOLINE in command line parser
+    - x86/spectre: Fix spelling mistake: "vunerable"-> "vulnerable"
+    - x86/paravirt: Remove 'noreplace-paravirt' cmdline option
+    - x86/retpoline: Avoid retpolines for built-in __init functions
+    - x86/spectre: Simplify spectre_v2 command line parsing
+    - x86/speculation: Fix typo IBRS_ATT, which should be IBRS_ALL
+    - KVM: nVMX: kmap() can't fail
+    - KVM: nVMX: vmx_complete_nested_posted_interrupt() can't fail
+    - kvm: nVMX: Fix kernel panics induced by illegal INVEPT/INVVPID types
+    - KVM: VMX: clean up declaration of VPID/EPT invalidation types
+    - KVM: nVMX: invvpid handling improvements
+    - crypto: s5p-sss - Fix kernel Oops in AES-ECB mode
+    - net: dst_cache_per_cpu_dst_set() can be static
+    - ARM: omap2: hide omap3_save_secure_ram on non-OMAP3 builds
+    - Linux 4.4.118
+
+  * ibrs/ibpb fixes result in excessive kernel logging  (LP: #1755627)
+    - SAUCE: remove ibrs_dump sysctl interface
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 07 May 2018 09:23:29 +0200
+
+linux (4.4.0-124.148) xenial; urgency=medium
+
+  * CVE-2018-8897
+    - x86/entry/64: Don't use IST entry for #BP stack
+
+  * CVE-2018-1087
+    - kvm/x86: fix icebp instruction handling
+
+  * CVE-2018-1000199
+    - perf/hwbp: Simplify the perf-hwbp code, fix documentation
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 02 May 2018 11:37:20 +0200
+
+linux (4.4.0-122.146) xenial; urgency=medium
+
+  * linux: 4.4.0-122.146 -proposed tracker (LP: #1766264)
+
+  * Redpine: WiFi scan stopping issue observed with BLE (LP: #1757435)
+    - SAUCE: Redpine: resolve wifi scan stop issue in stress tests
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 23 Apr 2018 16:25:01 +0200
+
+linux (4.4.0-121.145) xenial; urgency=medium
+
+  * linux: 4.4.0-121.145 -proposed tracker (LP: #1763687)
+
+  * Ubuntu-4.4.0-120.144 fails to boot on arm64* hardware (LP: #1763644)
+    - [Config] arm64: disable BPF_JIT_ALWAYS_ON
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 13 Apr 2018 14:42:14 +0200
+
+linux (4.4.0-120.144) xenial; urgency=medium
+
+  * linux: 4.4.0-120.144 -proposed tracker (LP: #1761438)
+
+  * intel-microcode 3.20180312.0 causes lockup at login screen(w/ linux-
+    image-4.13.0-37-generic) (LP: #1759920) // CVE-2017-5715 (Spectre v2 Intel)
+    - Revert "x86/mm: Only set IBPB when the new thread cannot ptrace current
+      thread"
+    - x86/speculation: Use Indirect Branch Prediction Barrier in context switch
+
+  * DKMS driver builds fail with: Cannot use CONFIG_STACK_VALIDATION=y, please
+    install libelf-dev, libelf-devel or elfutils-libelf-devel (LP: #1760876)
+    - [Packaging] include the retpoline extractor in the headers
+
+  * retpoline hints: primary infrastructure and initial hints (LP: #1758856)
+    - [Packaging] retpoline-extract: flag *0xNNN(%reg) branches
+    - x86/speculation, objtool: Annotate indirect calls/jumps for objtool
+    - x86/speculation, objtool: Annotate indirect calls/jumps for objtool on 32bit
+    - x86/paravirt, objtool: Annotate indirect calls
+    - x86/asm: Stop depending on ptrace.h in alternative.h
+    - [Packaging] retpoline -- add safe usage hint support
+    - [Packaging] retpoline-check -- only report additions
+    - [Packaging] retpoline -- widen indirect call/jmp detection
+    - [Packaging] retpoline -- elide %rip relative indirections
+    - [Packaging] retpoline -- clear hint information from packages
+    - SAUCE: modpost: add discard to non-allocatable whitelist
+    - KVM: x86: Make indirect calls in emulator speculation safe
+    - KVM: VMX: Make indirect call speculation safe
+    - x86/boot, objtool: Annotate indirect jump in secondary_startup_64()
+    - SAUCE: early/late -- annotate indirect calls in early/late initialisation
+      code
+    - SAUCE: vga_set_mode -- avoid jump tables
+    - [Config] retpoline -- switch to new format
+    - [Packaging] final-checks -- remove check for empty retpoline files
+
+  * Xenial update to 4.4.117 stable release (LP: #1756860)
+    - IB/mlx4: Fix incorrectly releasing steerable UD QPs when have only ETH ports
+    - PM / devfreq: Propagate error from devfreq_add_device()
+    - s390: fix handling of -1 in set{,fs}[gu]id16 syscalls
+    - ARM: dts: STi: Add gpio polarity for "hdmi,hpd-gpio" property
+    - arm: spear600: Add missing interrupt-parent of rtc
+    - arm: spear13xx: Fix dmas cells
+    - arm: spear13xx: Fix spics gpio controller's warning
+    - ALSA: seq: Fix regression by incorrect ioctl_mutex usages
+    - KVM/x86: Reduce retpoline performance impact in slot_handle_level_range(),
+      by always inlining iterator helper methods
+    - x86/cpu: Change type of x86_cache_size variable to unsigned int
+    - drm/radeon: adjust tested variable
+    - rtc-opal: Fix handling of firmware error codes, prevent busy loops
+    - ext4: save error to disk in __ext4_grp_locked_error()
+    - ext4: correct documentation for grpid mount option
+    - mm: hide a #warning for COMPILE_TEST
+    - video: fbdev: atmel_lcdfb: fix display-timings lookup
+    - console/dummy: leave .con_font_get set to NULL
+    - rtlwifi: rtl8821ae: Fix connection lost problem correctly
+    - Btrfs: fix deadlock in run_delalloc_nocow
+    - Btrfs: fix crash due to not cleaning up tree log block's dirty bits
+    - Btrfs: fix unexpected -EEXIST when creating new inode
+    - ALSA: hda - Fix headset mic detection problem for two Dell machines
+    - ALSA: usb-audio: Fix UAC2 get_ctl request with a RANGE attribute
+    - ALSA: hda/realtek: PCI quirk for Fujitsu U7x7
+    - ALSA: usb-audio: add implicit fb quirk for Behringer UFX1204
+    - ALSA: seq: Fix racy pool initializations
+    - mvpp2: fix multicast address filter
+    - dm: correctly handle chained bios in dec_pending()
+    - x86: fix build warnign with 32-bit PAE
+    - vfs: don't do RCU lookup of empty pathnames
+    - ARM: pxa/tosa-bt: add MODULE_LICENSE tag
+    - ARM: dts: s5pv210: add interrupt-parent for ohci
+    - media: r820t: fix r820t_write_reg for KASAN
+    - Linux 4.4.117
+
+  * zfs system process hung on container stop/delete (LP: #1754584)
+    - SAUCE: (noup) zfs to 0.6.5.6-0ubuntu19
+    - SAUCE: Fix non-prefaulted page deadlock (LP: #1754584)
+
+  * apparmor: fix bad __initdata tagging on, apparmor_initialized (LP: #1758471)
+    - SAUCE: apparmor: fix bad __initdata tagging on, apparmor_initialized
+
+  * Xenial update to 4.4.116 stable release (LP: #1756121)
+    - powerpc/bpf/jit: Disable classic BPF JIT on ppc64le
+    - powerpc/64: Fix flush_(d|i)cache_range() called from modules
+    - powerpc: Fix VSX enabling/flushing to also test MSR_FP and MSR_VEC
+    - powerpc: Simplify module TOC handling
+    - ASoC: pcm512x: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - usbip: vhci_hcd: clear just the USB_PORT_STAT_POWER bit
+    - usbip: fix 3eee23c3ec14 tcp_socket address still in the status file
+    - net: cdc_ncm: initialize drvflags before usage
+    - ASoC: simple-card: Fix misleading error message
+    - ASoC: rsnd: don't call free_irq() on Parent SSI
+    - ASoC: rsnd: avoid duplicate free_irq()
+    - drm: rcar-du: Use the VBK interrupt for vblank events
+    - drm: rcar-du: Fix race condition when disabling planes at CRTC stop
+    - x86/asm: Fix inline asm call constraints for GCC 4.4
+    - ip6mr: fix stale iterator
+    - net: igmp: add a missing rcu locking section
+    - qlcnic: fix deadlock bug
+    - r8169: fix RTL8168EP take too long to complete driver initialization.
+    - tcp: release sk_frag.page in tcp_disconnect
+    - vhost_net: stop device during reset owner
+    - media: soc_camera: soc_scale_crop: add missing
+      MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - KEYS: encrypted: fix buffer overread in valid_master_desc()
+    - don't put symlink bodies in pagecache into highmem
+    - crypto: tcrypt - fix S/G table for test_aead_speed()
+    - x86/microcode: Do the family check first
+    - powerpc/pseries: include linux/types.h in asm/hvcall.h
+    - cifs: Fix missing put_xid in cifs_file_strict_mmap
+    - cifs: Fix autonegotiate security settings mismatch
+    - CIFS: zero sensitive data when freeing
+    - dmaengine: dmatest: fix container_of member in dmatest_callback
+    - x86/kaiser: fix build error with KASAN && !FUNCTION_GRAPH_TRACER
+    - kaiser: fix compile error without vsyscall
+    - netfilter: nf_queue: Make the queue_handler pernet
+    - posix-timer: Properly check sigevent->sigev_notify
+    - usb: gadget: uvc: Missing files for configfs interface
+    - sched/rt: Use container_of() to get root domain in rto_push_irq_work_func()
+    - sched/rt: Up the root domain ref count when passing it around via IPIs
+    - media: dvb-usb-v2: lmedm04: Improve logic checking of warm start
+    - media: dvb-usb-v2: lmedm04: move ts2020 attach to dm04_lme2510_tuner
+    - mtd: cfi: convert inline functions to macros
+    - mtd: nand: brcmnand: Disable prefetch by default
+    - mtd: nand: Fix nand_do_read_oob() return value
+    - mtd: nand: sunxi: Fix ECC strength choice
+    - ubi: block: Fix locking for idr_alloc/idr_remove
+    - nfs/pnfs: fix nfs_direct_req ref leak when i/o falls back to the mds
+    - NFS: Add a cond_resched() to nfs_commit_release_pages()
+    - NFS: commit direct writes even if they fail partially
+    - NFS: reject request for id_legacy key without auxdata
+    - kernfs: fix regression in kernfs_fop_write caused by wrong type
+    - ahci: Annotate PCI ids for mobile Intel chipsets as such
+    - ahci: Add PCI ids for Intel Bay Trail, Cherry Trail and Apollo Lake AHCI
+    - ahci: Add Intel Cannon Lake PCH-H PCI ID
+    - crypto: hash - introduce crypto_hash_alg_has_setkey()
+    - crypto: cryptd - pass through absence of ->setkey()
+    - crypto: poly1305 - remove ->setkey() method
+    - nsfs: mark dentry with DCACHE_RCUACCESS
+    - media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
+    - vb2: V4L2_BUF_FLAG_DONE is set after DQBUF
+    - media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
+    - media: v4l2-compat-ioctl32.c: fix the indentation
+    - media: v4l2-compat-ioctl32.c: move 'helper' functions to
+      __get/put_v4l2_format32
+    - media: v4l2-compat-ioctl32.c: avoid sizeof(type)
+    - media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
+    - media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
+    - media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
+    - media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
+    - media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
+    - media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
+    - media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
+    - media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
+    - crypto: caam - fix endless loop when DECO acquire fails
+    - arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
+    - KVM: nVMX: Fix races when sending nested PI while dest enters/leaves L2
+    - watchdog: imx2_wdt: restore previous timeout after suspend+resume
+    - media: ts2020: avoid integer overflows on 32 bit machines
+    - media: cxusb, dib0700: ignore XC2028_I2C_FLUSH
+    - kernel/async.c: revert "async: simplify lowest_in_progress()"
+    - HID: quirks: Fix keyboard + touchpad on Toshiba Click Mini not working
+    - Bluetooth: btsdio: Do not bind to non-removable BCM43341
+    - Bluetooth: btusb: Restore QCA Rome suspend/resume fix with a "rewritten"
+      version
+    - signal/openrisc: Fix do_unaligned_access to send the proper signal
+    - signal/sh: Ensure si_signo is initialized in do_divide_error
+    - alpha: fix crash if pthread_create races with signal delivery
+    - alpha: fix reboot on Avanti platform
+    - xtensa: fix futex_atomic_cmpxchg_inatomic
+    - EDAC, octeon: Fix an uninitialized variable warning
+    - pktcdvd: Fix pkt_setup_dev() error path
+    - btrfs: Handle btrfs_set_extent_delalloc failure in fixup worker
+    - ACPI: sbshc: remove raw pointer from printk() message
+    - ovl: fix failure to fsync lower dir
+    - mn10300/misalignment: Use SIGSEGV SEGV_MAPERR to report a failed user copy
+    - ftrace: Remove incorrect setting of glob search field
+    - Linux 4.4.116
+
+  * Xenial update to 4.4.116 stable release (LP: #1756121) // CVE-2017-5754
+    - Revert "UBUNTU: SAUCE: UBUNTU: [Config] Disable CONFIG_PPC_DEBUG_RFI"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fix some RFI conversions in the KVM code"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fix the 32-bit KVM build"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fallback flush add load dependency"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Use rfi-flush in printks"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Add no_rfi_flush and nopti comandline
+      options"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Refactor the macros so the nops are
+      defined once"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fix HRFI_TO_UNKNOWN"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fix the fallback flush to actually
+      activate"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Rework pseries logic to be more cautious"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Rework powernv logic to be more cautious"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Add barriers to the fallback L1D flushing"
+    - Revert "UBUNTU: SAUCE: Fix compilation errors for arch/powerpc/lib/feature-
+      fixups.c"
+    - Revert "UBUNTU: SAUCE: Remove setup.h include file otherwise compilation
+      complains about missing header file."
+    - Revert "UBUNTU: SAUCE: powerpc/asm: Allow including ppc_asm.h in asm files"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Add speculation barrier before ori 30,30,0
+      flush"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Allow HV to advertise multiple flush
+      types"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Support more than one flush type at once"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Expand the RFI section to two nop slots"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Push the instruction selection down to the
+      patching routine"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Make l1d_flush_type bit flags"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Implement congruence-first fallback flush"
+    - Revert "UBUNTU: SAUCE: KVM: Revert the implementation of
+      H_GET_CPU_CHARACTERISTICS"
+    - Revert "UBUNTU: SAUCE: rfi-flush: kvmppc_skip_(H)interrupt returns to host"
+    - Revert "UBUNTU: SAUCE: Fixup rfid in kvmppc_skip_Hinterrupt should be hrfid"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Add HRFI_TO_UNKNOWN and use it in denorm"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Make DEBUG_RFI a CONFIG option"
+    - Revert "UBUNTU: SAUCE: powerpc: Secure memory rfi flush"
+    - powerpc/pseries: Add H_GET_CPU_CHARACTERISTICS flags & wrapper
+    - powerpc/64: Add macros for annotating the destination of rfid/hrfid
+    - powerpc/64s: Simple RFI macro conversions
+    - powerpc/64: Convert fast_exception_return to use RFI_TO_USER/KERNEL
+    - powerpc/64: Convert the syscall exit path to use RFI_TO_USER/KERNEL
+    - powerpc/64s: Convert slb_miss_common to use RFI_TO_USER/KERNEL
+    - powerpc/64s: Add support for RFI flush of L1-D cache
+    - powerpc/64s: Support disabling RFI flush with no_rfi_flush and nopti
+    - powerpc/pseries: Query hypervisor for RFI flush settings
+    - powerpc/powernv: Check device-tree for RFI flush settings
+    - powerpc/64s: Wire up cpu_show_meltdown()
+    - powerpc/64s: Allow control of RFI flush via debugfs
+
+  * Intel i40e PF reset due to incorrect MDD detection (continues...)
+    (LP: #1723127)
+    - i40e/i40evf: Account for frags split over multiple descriptors in check
+      linearize
+    - i40e/i40evf: Allow up to 12K bytes of data per Tx descriptor instead of 8K
+
+  * Xenial update to 4.4.115 stable release (LP: #1755509)
+    - x86: bpf_jit: small optimization in emit_bpf_tail_call()
+    - bpf: fix bpf_tail_call() x64 JIT
+    - [Config] CONFIG_BPF_JIT_ALWAYS_ON=y
+    - bpf: introduce BPF_JIT_ALWAYS_ON config
+    - bpf: arsh is not supported in 32 bit alu thus reject it
+    - bpf: avoid false sharing of map refcount with max_entries
+    - bpf: fix divides by zero
+    - bpf: fix 32-bit divide by zero
+    - bpf: reject stores into ctx via st and xadd
+    - x86/pti: Make unpoison of pgd for trusted boot work for real
+    - kaiser: fix intel_bts perf crashes
+    - ALSA: seq: Make ioctls race-free
+    - crypto: aesni - handle zero length dst buffer
+    - crypto: af_alg - whitelist mask and type
+    - power: reset: zx-reboot: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - gpio: iop: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - gpio: ath79: add missing MODULE_DESCRIPTION/LICENSE
+    - mtd: nand: denali_pci: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - igb: Free IRQs when device is hotplugged
+    - KVM: x86: emulator: Return to user-mode on L1 CPL=0 emulation failure
+    - KVM: x86: Don't re-execute instruction when not passing CR2 value
+    - KVM: X86: Fix operand/address-size during instruction decoding
+    - KVM: x86: ioapic: Fix level-triggered EOI and IOAPIC reconfigure race
+    - KVM: x86: ioapic: Clear Remote IRR when entry is switched to edge-triggered
+    - KVM: x86: ioapic: Preserve read-only values in the redirection table
+    - ACPI / bus: Leave modalias empty for devices which are not present
+    - cpufreq: Add Loongson machine dependencies
+    - bcache: check return value of register_shrinker
+    - drm/amdgpu: Fix SDMA load/unload sequence on HWS disabled mode
+    - drm/amdkfd: Fix SDMA ring buffer size calculation
+    - drm/amdkfd: Fix SDMA oversubsription handling
+    - openvswitch: fix the incorrect flow action alloc size
+    - mac80211: fix the update of path metric for RANN frame
+    - btrfs: fix deadlock when writing out space cache
+    - KVM: VMX: Fix rflags cache during vCPU reset
+    - xen-netfront: remove warning when unloading module
+    - nfsd: CLOSE SHOULD return the invalid special stateid for NFSv4.x (x>0)
+    - nfsd: Ensure we check stateid validity in the seqid operation checks
+    - grace: replace BUG_ON by WARN_ONCE in exit_net hook
+    - nfsd: check for use of the closed special stateid
+    - lockd: fix "list_add double add" caused by legacy signal interface
+    - hwmon: (pmbus) Use 64bit math for DIRECT format values
+    - powerpc/ppc64el -- Remove ll_temac module from 64-bit builds
+    - net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit
+    - quota: Check for register_shrinker() failure.
+    - SUNRPC: Allow connect to return EHOSTUNREACH
+    - kmemleak: add scheduling point to kmemleak_scan()
+    - drm/omap: Fix error handling path in 'omap_dmm_probe()'
+    - xfs: ubsan fixes
+    - scsi: aacraid: Prevent crash in case of free interrupt during scsi EH path
+    - scsi: ufs: ufshcd: fix potential NULL pointer dereference in
+      ufshcd_config_vreg
+    - media: usbtv: add a new usbid
+    - usb: gadget: don't dereference g until after it has been null checked
+    - staging: rtl8188eu: Fix incorrect response to SIOCGIWESSID
+    - usb: option: Add support for FS040U modem
+    - USB: serial: pl2303: new device id for Chilitag
+    - USB: cdc-acm: Do not log urb submission errors on disconnect
+    - CDC-ACM: apply quirk for card reader
+    - USB: serial: io_edgeport: fix possible sleep-in-atomic
+    - usbip: prevent bind loops on devices attached to vhci_hcd
+    - usbip: list: don't list devices attached to vhci_hcd
+    - USB: serial: simple: add Motorola Tetra driver
+    - usb: f_fs: Prevent gadget unbind if it is already unbound
+    - usb: uas: unconditionally bring back host after reset
+    - selinux: general protection fault in sock_has_perm
+    - serial: imx: Only wakeup via RTSDEN bit if the system has RTS/CTS
+    - spi: imx: do not access registers while clocks disabled
+    - Linux 4.4.115
+
+  * retpoline: ignore %cs:0xNNN constant indirections (LP: #1752655)
+    - [Packaging] retpoline -- elide %cs:0xNNNN constants on i386
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 05 Apr 2018 15:03:15 +0200
+
+linux (4.4.0-119.143) xenial; urgency=medium
+
+  * linux: 4.4.0-119.143 -proposed tracker (LP: #1760327)
+
+  * Dell XPS 13 9360 bluetooth scan can not detect any device (LP: #1759821)
+    - Revert "Bluetooth: btusb: fix QCA Rome suspend/resume"
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sat, 31 Mar 2018 17:09:19 +0000
+
+linux (4.4.0-118.142) xenial; urgency=medium
+
+  * linux: 4.4.0-118.142 -proposed tracker (LP: #1759607)
+
+  * Kernel panic with AWS 4.4.0-1053 / 4.4.0-1015 (Trusty) (LP: #1758869)
+    - x86/microcode/AMD: Do not load when running on a hypervisor
+
+  * CVE-2018-8043
+    - net: phy: mdio-bcm-unimac: fix potential NULL dereference in
+      unimac_mdio_probe()
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 28 Mar 2018 14:15:10 -0400
+
+linux (4.4.0-117.141) xenial; urgency=medium
+
+  * linux: 4.4.0-117.141 -proposed tracker (LP: #1755208)
+
+  * Xenial update to 4.4.114 stable release (LP: #1754592)
+    - x86/asm/32: Make sync_core() handle missing CPUID on all 32-bit kernels
+    - usbip: prevent vhci_hcd driver from leaking a socket pointer address
+    - usbip: Fix implicit fallthrough warning
+    - usbip: Fix potential format overflow in userspace tools
+    - x86/microcode/intel: Fix BDW late-loading revision check
+    - x86/retpoline: Fill RSB on context switch for affected CPUs
+    - sched/deadline: Use the revised wakeup rule for suspending constrained dl
+      tasks
+    - can: af_can: can_rcv(): replace WARN_ONCE by pr_warn_once
+    - can: af_can: canfd_rcv(): replace WARN_ONCE by pr_warn_once
+    - PM / sleep: declare __tracedata symbols as char[] rather than char
+    - time: Avoid undefined behaviour in ktime_add_safe()
+    - timers: Plug locking race vs. timer migration
+    - Prevent timer value 0 for MWAITX
+    - drivers: base: cacheinfo: fix x86 with CONFIG_OF enabled
+    - drivers: base: cacheinfo: fix boot error message when acpi is enabled
+    - PCI: layerscape: Add "fsl,ls2085a-pcie" compatible ID
+    - PCI: layerscape: Fix MSG TLP drop setting
+    - mmc: sdhci-of-esdhc: add/remove some quirks according to vendor version
+    - fs/select: add vmalloc fallback for select(2)
+    - hwpoison, memcg: forcibly uncharge LRU pages
+    - cma: fix calculation of aligned offset
+    - mm, page_alloc: fix potential false positive in __zone_watermark_ok
+    - ipc: msg, make msgrcv work with LONG_MIN
+    - x86/ioapic: Fix incorrect pointers in ioapic_setup_resources()
+    - ACPI / processor: Avoid reserving IO regions too early
+    - ACPI / scan: Prefer devices without _HID/_CID for _ADR matching
+    - ACPICA: Namespace: fix operand cache leak
+    - netfilter: x_tables: speed up jump target validation
+    - netfilter: arp_tables: fix invoking 32bit "iptable -P INPUT ACCEPT" failed
+      in 64bit kernel
+    - netfilter: nf_dup_ipv6: set again FLOWI_FLAG_KNOWN_NH at flowi6_flags
+    - netfilter: nf_ct_expect: remove the redundant slash when policy name is
+      empty
+    - netfilter: nfnetlink_queue: reject verdict request from different portid
+    - netfilter: restart search if moved to other chain
+    - netfilter: nf_conntrack_sip: extend request line validation
+    - netfilter: use fwmark_reflect in nf_send_reset
+    - ext2: Don't clear SGID when inheriting ACLs
+    - reiserfs: fix race in prealloc discard
+    - reiserfs: don't preallocate blocks for extended attributes
+    - reiserfs: Don't clear SGID when inheriting ACLs
+    - fs/fcntl: f_setown, avoid undefined behaviour
+    - scsi: libiscsi: fix shifting of DID_REQUEUE host byte
+    - Input: trackpoint - force 3 buttons if 0 button is reported
+    - usb: usbip: Fix possible deadlocks reported by lockdep
+    - usbip: fix stub_rx: get_pipe() to validate endpoint number
+    - usbip: fix stub_rx: harden CMD_SUBMIT path to handle malicious input
+    - usbip: prevent leaking socket pointer address in messages
+    - um: link vmlinux with -no-pie
+    - vsyscall: Fix permissions for emulate mode with KAISER/PTI
+    - eventpoll.h: add missing epoll event masks
+    - x86/microcode/intel: Extend BDW late-loading further with LLC size check
+    - hrtimer: Reset hrtimer cpu base proper on CPU hotplug
+    - dccp: don't restart ccid2_hc_tx_rto_expire() if sk in closed state
+    - ipv6: Fix getsockopt() for sockets with default IPV6_AUTOFLOWLABEL
+    - ipv6: fix udpv6 sendmsg crash caused by too small MTU
+    - ipv6: ip6_make_skb() needs to clear cork.base.dst
+    - lan78xx: Fix failure in USB Full Speed
+    - net: igmp: fix source address check for IGMPv3 reports
+    - tcp: __tcp_hdrlen() helper
+    - net: qdisc_pkt_len_init() should be more robust
+    - pppoe: take ->needed_headroom of lower device into account on xmit
+    - r8169: fix memory corruption on retrieval of hardware statistics.
+    - sctp: do not allow the v4 socket to bind a v4mapped v6 address
+    - sctp: return error if the asoc has been peeled off in sctp_wait_for_sndbuf
+    - vmxnet3: repair memory leak
+    - net: Allow neigh contructor functions ability to modify the primary_key
+    - ipv4: Make neigh lookup keys for loopback/point-to-point devices be
+      INADDR_ANY
+    - flow_dissector: properly cap thoff field
+    - net: tcp: close sock if net namespace is exiting
+    - nfsd: auth: Fix gid sorting when rootsquash enabled
+    - Linux 4.4.114
+
+  * Xenial update to 4.4.113 stable release (LP: #1754375)
+    - gcov: disable for COMPILE_TEST
+    - scsi: sg: disable SET_FORCE_LOW_DMA
+    - futex: Prevent overflow by strengthen input validation
+    - ALSA: pcm: Remove yet superfluous WARN_ON()
+    - ALSA: hda - Apply headphone noise quirk for another Dell XPS 13 variant
+    - ALSA: hda - Apply the existing quirk to iMac 14,1
+    - af_key: fix buffer overread in verify_address_len()
+    - af_key: fix buffer overread in parse_exthdrs()
+    - scsi: hpsa: fix volume offline state
+    - sched/deadline: Zero out positive runtime after throttling constrained tasks
+    - pipe: avoid round_pipe_size() nr_pages overflow on 32-bit
+    - x86/apic/vector: Fix off by one in error path
+    - Input: 88pm860x-ts - fix child-node lookup
+    - Input: twl6040-vibra - fix DT node memory management
+    - Input: twl6040-vibra - fix child-node lookup
+    - Input: twl4030-vibra - fix sibling-node lookup
+    - tracing: Fix converting enum's from the map in trace_event_eval_update()
+    - phy: work around 'phys' references to usb-nop-xceiv devices
+    - ARM: dts: kirkwood: fix pin-muxing of MPP7 on OpenBlocks A7
+    - can: peak: fix potential bug in packet fragmentation
+    - dm btree: fix serious bug in btree_split_beneath()
+    - dm thin metadata: THIN_MAX_CONCURRENT_LOCKS should be 6
+    - arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
+    - kbuild: modversions for EXPORT_SYMBOL() for asm
+    - x86/pti: Document fix wrong index
+    - MIPS: AR7: ensure the port type's FCR value is used
+    - Linux 4.4.113
+
+  * Xenial update to 4.4.113 stable release (LP: #1754375) // CVE-2017-5753
+    (Spectre v1 Intel -> upstream)
+    - Revert "x86/cpu/AMD: Make the LFENCE instruction serialized"
+    - x86/cpu/AMD: Make LFENCE a serializing instruction
+    - x86/cpu/AMD: Use LFENCE_RDTSC in preference to MFENCE_RDTSC
+
+  * i2c-thunderx: erroneous error message "unhandled state: 0" (LP: #1754076)
+    - i2c: octeon: Prevent error message on bus error
+
+  * qeth: fix calculation of required buffer elements for skb (LP: #1750810)
+    - s390/qeth: fix underestimated count of buffer elements
+
+  * Support rfkill-any led trigger for Fujitsu u727 (LP: #1745130)
+    - rfkill: Add rfkill-any LED trigger
+
+  * Redpine: Sometimes Wi-Fi connection shows "unavailable" after resume from
+    WoWLAN S4. WLAN can be recover after reboot or reloading WIFI driver.
+    (LP: #1753438) // Redpine: BLE scanning for nearby beacons per second is too
+    low and result high loss rate. (LP: #1753439)
+    - SAUCE: Redpine: resolve race while resuming from S4
+    - SAUCE: Redpine: Fix card write failure issue at S4 restore
+    - SAUCE: Redpine: Add deep sleep enable before connection
+    - SAUCE: Redpine: resolve power save issue after S4 resume
+
+  * qeth: check not more than 16 SBALEs on the completion queue (LP: #1750568)
+    - qeth: check not more than 16 SBALEs on the completion queue
+
+  * qeth: fix L3 next-hop im xmit qeth hdr (LP: #1750813)
+    - s390/qeth: fix L3 next-hop in xmit qeth hdr
+
+  * qemu-efi-aarch64 in >= artful can't boot xenial cloud images (LP: #1744754)
+    - irqchip/gic-v3: Refactor gic_of_init() for GICv3 driver
+    - irqchip/gic-v3: Add ACPI support for GICv3/4 initialization
+    - irqchip/gic-v3: ACPI: Add redistributor support via GICC structures
+    - irqchip/gic-v3: Remove gic_root_node variable from the ITS code
+    - irqchip/gic-v3-its: Mark its_init() and its children as __init
+    - ACPICA: Headers: Add new constants for the DBG2 ACPI table
+    - of/serial: move earlycon early_param handling to serial
+    - ACPI: parse SPCR and enable matching console
+    - [Config] CONFIG_ACPI_SPCR_TABLE=y
+    - ARM64: ACPI: enable ACPI_SPCR_TABLE
+    - serial: pl011: add console matching function
+
+  * OOM and High CPU utilization in update_blocked_averages because of too many
+    cfs_rqs in rq->leaf_cfs_rq_list (LP: #1747896)
+    - sched/fair: Fix O(nr_cgroups) in load balance path
+
+  * linux-tools: perf incorrectly linking libbfd (LP: #1748922)
+    - SAUCE: tools -- add ability to disable libbfd
+    - [Packaging] correct disablement of libbfd
+
+  * retpoline abi files are empty on i386 (LP: #1751021)
+    - [Packaging] retpoline-extract -- instantiate retpoline files for i386
+    - [Packaging] final-checks -- sanity checking ABI contents
+    - [Packaging] final-checks -- check for empty retpoline files
+
+  * bnx2x_attn_int_deasserted3:4323 MC assert! (LP: #1715519) //
+    CVE-2018-1000026
+    - net: create skb_gso_validate_mac_len()
+    - bnx2x: disable GSO where gso_size is too big for hardware
+
+  * CVE-2017-17448
+    - netfilter: nfnetlink_cthelper: Add missing permission checks
+
+  * TB16 dock ethernet corrupts data with hw checksum silently failing
+    (LP: #1729674)
+    - r8152: disable RX aggregation on Dell TB16 dock
+
+  * linux < 4.8: x-netns vti is broken (LP: #1744078)
+    - net: l3mdev: Add master device lookup by index
+    - xfrm: Only add l3mdev oif to dst lookups
+
+  * Xenial update to 4.4.112 stable release (LP: #1745266)
+    - dm bufio: fix shrinker scans when (nr_to_scan < retain_target)
+    - can: gs_usb: fix return value of the "set_bittiming" callback
+    - IB/srpt: Disable RDMA access by the initiator
+    - MIPS: Validate PR_SET_FP_MODE prctl(2) requests against the ABI of the task
+    - MIPS: Factor out NT_PRFPREG regset access helpers
+    - MIPS: Guard against any partial write attempt with PTRACE_SETREGSET
+    - MIPS: Consistently handle buffer counter with PTRACE_SETREGSET
+    - MIPS: Fix an FCSR access API regression with NT_PRFPREG and MSA
+    - MIPS: Also verify sizeof `elf_fpreg_t' with PTRACE_SETREGSET
+    - MIPS: Disallow outsized PTRACE_SETREGSET NT_PRFPREG regset accesses
+    - net/mac80211/debugfs.c: prevent build failure with CONFIG_UBSAN=y
+    - x86/vsdo: Fix build on PARAVIRT_CLOCK=y, KVM_GUEST=n
+    - x86/acpi: Handle SCI interrupts above legacy space gracefully
+    - iommu/arm-smmu-v3: Don't free page table ops twice
+    - ALSA: pcm: Remove incorrect snd_BUG_ON() usages
+    - ALSA: pcm: Add missing error checks in OSS emulation plugin builder
+    - ALSA: pcm: Abort properly at pending signal in OSS read/write loops
+    - ALSA: pcm: Allow aborting mutex lock at OSS read/write loops
+    - ALSA: aloop: Release cable upon open error path
+    - ALSA: aloop: Fix inconsistent format due to incomplete rule
+    - ALSA: aloop: Fix racy hw constraints adjustment
+    - x86/acpi: Reduce code duplication in mp_override_legacy_irq()
+    - mm/compaction: fix invalid free_pfn and compact_cached_free_pfn
+    - mm/compaction: pass only pageblock aligned range to pageblock_pfn_to_page
+    - mm/page-writeback: fix dirty_ratelimit calculation
+    - mm/zswap: use workqueue to destroy pool
+    - zswap: don't param_set_charp while holding spinlock
+    - locks: don't check for race with close when setting OFD lock
+    - futex: Replace barrier() in unqueue_me() with READ_ONCE()
+    - locking/mutex: Allow next waiter lockless wakeup
+    - usbvision fix overflow of interfaces array
+    - usb: musb: ux500: Fix NULL pointer dereference at system PM
+    - r8152: fix the wake event
+    - r8152: use test_and_clear_bit
+    - r8152: adjust ALDPS function
+    - lan78xx: use skb_cow_head() to deal with cloned skbs
+    - sr9700: use skb_cow_head() to deal with cloned skbs
+    - smsc75xx: use skb_cow_head() to deal with cloned skbs
+    - cx82310_eth: use skb_cow_head() to deal with cloned skbs
+    - x86/mm/pat, /dev/mem: Remove superfluous error message
+    - hwrng: core - sleep interruptible in read
+    - sysrq: Fix warning in sysrq generated crash.
+    - xhci: Fix ring leak in failure path of xhci_alloc_virt_device()
+    - Revert "userfaultfd: selftest: vm: allow to build in vm/ directory"
+    - x86/pti/efi: broken conversion from efi to kernel page table
+    - 8021q: fix a memory leak for VLAN 0 device
+    - ip6_tunnel: disable dst caching if tunnel is dual-stack
+    - net: core: fix module type in sock_diag_bind
+    - RDS: Heap OOB write in rds_message_alloc_sgs()
+    - sh_eth: fix TSU resource handling
+    - sh_eth: fix SH7757 GEther initialization
+    - net: stmmac: enable EEE in MII, GMII or RGMII only
+    - ipv6: fix possible mem leaks in ipv6_make_skb()
+    - crypto: algapi - fix NULL dereference in crypto_remove_spawns()
+    - rbd: set max_segments to USHRT_MAX
+    - x86/microcode/intel: Extend BDW late-loading with a revision check
+    - KVM: x86: Add memory barrier on vmcs field lookup
+    - drm/vmwgfx: Potential off by one in vmw_view_add()
+    - kaiser: Set _PAGE_NX only if supported
+    - bpf: don't (ab)use instructions to store state
+    - bpf: move fixup_bpf_calls() function
+    - bpf: refactor fixup_bpf_calls()
+    - bpf: adjust insn_aux_data when patching insns
+    - bpf: prevent out-of-bounds speculation
+    - bpf, array: fix overflow in max_entries and undefined behavior in index_mask
+    - iscsi-target: Make TASK_REASSIGN use proper se_cmd->cmd_kref
+    - target: Avoid early CMD_T_PRE_EXECUTE failures during ABORT_TASK
+    - USB: serial: cp210x: add IDs for LifeScan OneTouch Verio IQ
+    - USB: serial: cp210x: add new device ID ELV ALC 8xxx
+    - usb: misc: usb3503: make sure reset is low for at least 100us
+    - USB: fix usbmon BUG trigger
+    - usbip: remove kernel addresses from usb device and urb debug msgs
+    - staging: android: ashmem: fix a race condition in ASHMEM_SET_SIZE ioctl
+    - Bluetooth: Prevent stack info leak from the EFS element.
+    - uas: ignore UAS for Norelsys NS1068(X) chips
+    - e1000e: Fix e1000_check_for_copper_link_ich8lan return value.
+    - x86/Documentation: Add PTI description
+    - sysfs/cpu: Fix typos in vulnerability documentation
+    - x86/alternatives: Fix optimize_nops() checking
+    - selftests/x86: Add test_vsyscall
+    - Linux 4.4.112
+
+  * Xenial update to 4.4.111 stable release (LP: #1745263)
+    - x86/kasan: Write protect kasan zero shadow
+    - kernel/acct.c: fix the acct->needcheck check in check_free_space()
+    - crypto: n2 - cure use after free
+    - crypto: chacha20poly1305 - validate the digest size
+    - crypto: pcrypt - fix freeing pcrypt instances
+    - sunxi-rsb: Include OF based modalias in device uevent
+    - fscache: Fix the default for fscache_maybe_release_page()
+    - kernel: make groups_sort calling a responsibility group_info allocators
+    - kernel/signal.c: protect the traced SIGNAL_UNKILLABLE tasks from SIGKILL
+    - kernel/signal.c: protect the SIGNAL_UNKILLABLE tasks from !sig_kernel_only()
+      signals
+    - kernel/signal.c: remove the no longer needed SIGNAL_UNKILLABLE check in
+      complete_signal()
+    - ARC: uaccess: dont use "l" gcc inline asm constraint modifier
+    - parisc: Fix alignment of pa_tlb_lock in assembly on 32-bit SMP kernel
+    - genksyms: Handle string literals with spaces in reference files
+    - module: Issue warnings when tainting kernel
+    - proc: much faster /proc/vmstat
+    - Fix build error in vma.c
+    - Linux 4.4.111
+
+  * x86/net/bpf: return statement missing value (LP: #1745364)
+    - SAUCE: (no-up) arch/x86/bpf: Fix missed return statement
+
+  * Ubuntu 16.04 - s390/cpuinfo: show facilities as reported by stfle
+    (LP: #1744736)
+    - s390/bitops: add for_each_set_bit_inv helper
+    - s390/cpuinfo: show facilities as reported by stfle
+
+  * Xenial update to 4.4.110 stable release (LP: #1745071)
+    - KPTI: Rename to PAGE_TABLE_ISOLATION
+    - SAUCE: Replace CONFIG_KAISER with CONFIG_PAGE_TABLE_ISOLATION
+    - Linux 4.4.110
+
+  * Xenial update to 4.4.109 stable release (LP: #1745069)
+    - ACPI: APEI / ERST: Fix missing error handling in erst_reader()
+    - crypto: mcryptd - protect the per-CPU queue with a lock
+    - mfd: cros ec: spi: Don't send first message too soon
+    - mfd: twl4030-audio: Fix sibling-node lookup
+    - mfd: twl6040: Fix child-node lookup
+    - ALSA: rawmidi: Avoid racy info ioctl via ctl device
+    - ALSA: usb-audio: Fix the missing ctl name suffix at parsing SU
+    - PCI / PM: Force devices to D0 in pci_pm_thaw_noirq()
+    - parisc: Hide Diva-built-in serial aux and graphics card
+    - spi: xilinx: Detect stall with Unknown commands
+    - KVM: X86: Fix load RFLAGS w/o the fixed bit
+    - powerpc/perf: Dereference BHRB entries safely
+    - net: mvneta: clear interface link status on port disable
+    - tracing: Remove extra zeroing out of the ring buffer page
+    - tracing: Fix possible double free on failure of allocating trace buffer
+    - tracing: Fix crash when it fails to alloc ring buffer
+    - ring-buffer: Mask out the info bits when returning buffer page length
+    - iw_cxgb4: Only validate the MSN for successful completions
+    - ASoC: fsl_ssi: AC'97 ops need regmap, clock and cleaning up on failure
+    - ASoC: twl4030: fix child-node lookup
+    - ALSA: hda: Drop useless WARN_ON()
+    - ALSA: hda - fix headset mic detection issue on a Dell machine
+    - x86/vm86/32: Switch to flush_tlb_mm_range() in mark_screen_rdonly()
+    - x86/mm: Remove flush_tlb() and flush_tlb_current_task()
+    - x86/mm: Make flush_tlb_mm_range() more predictable
+    - x86/mm: Reimplement flush_tlb_page() using flush_tlb_mm_range()
+    - x86/mm: Remove the UP asm/tlbflush.h code, always use the (formerly) SMP
+      code
+    - x86/mm: Add the 'nopcid' boot option to turn off PCID
+    - x86/mm/64: Fix reboot interaction with CR4.PCIDE
+    - kbuild: add '-fno-stack-check' to kernel build options
+    - ipv4: igmp: guard against silly MTU values
+    - ipv6: mcast: better catch silly mtu values
+    - net: igmp: Use correct source address on IGMPv3 reports
+    - netlink: Add netns check on taps
+    - net: qmi_wwan: add Sierra EM7565 1199:9091
+    - net: reevalulate autoflowlabel setting after sysctl setting
+    - tcp md5sig: Use skb's saddr when replying to an incoming segment
+    - tg3: Fix rx hang on MTU change with 5717/5719
+    - net: mvmdio: disable/unprepare clocks in EPROBE_DEFER case
+    - sctp: Replace use of sockets_allocated with specified macro.
+    - ipv4: Fix use-after-free when flushing FIB tables
+    - net: bridge: fix early call to br_stp_change_bridge_id and plug newlink
+      leaks
+    - net: phy: micrel: ksz9031: reconfigure autoneg after phy autoneg workaround
+    - sock: free skb in skb_complete_tx_timestamp on error
+    - usbip: fix usbip bind writing random string after command in match_busid
+    - usbip: stub: stop printing kernel pointer addresses in messages
+    - usbip: vhci: stop printing kernel pointer addresses in messages
+    - USB: serial: ftdi_sio: add id for Airbus DS P8GR
+    - USB: serial: qcserial: add Sierra Wireless EM7565
+    - USB: serial: option: add support for Telit ME910 PID 0x1101
+    - USB: serial: option: adding support for YUGA CLM920-NC5
+    - usb: Add device quirk for Logitech HD Pro Webcam C925e
+    - usb: add RESET_RESUME for ELSA MicroLink 56K
+    - USB: Fix off by one in type-specific length check of BOS SSP capability
+    - usb: xhci: Add XHCI_TRUST_TX_LENGTH for Renesas uPD720201
+    - nohz: Prevent a timer interrupt storm in tick_nohz_stop_sched_tick()
+    - x86/smpboot: Remove stale TLB flush invocations
+    - n_tty: fix EXTPROC vs ICANON interaction with TIOCINQ (aka FIONREAD)
+    - mm/vmstat: Make NR_TLB_REMOTE_FLUSH_RECEIVED available even on UP
+    - Linux 4.4.109
+
+  * Xenial update to 4.4.108 stable release (LP: #1745054)
+    - arm64: Initialise high_memory global variable earlier
+    - cxl: Check if vphb exists before iterating over AFU devices
+    - x86/mm: Fix INVPCID asm constraint
+    - x86/mm: Add a 'noinvpcid' boot option to turn off INVPCID
+    - mm/rmap: batched invalidations should use existing api
+    - mm/mmu_context, sched/core: Fix mmu_context.h assumption
+    - sched/core: Add switch_mm_irqs_off() and use it in the scheduler
+    - x86/mm, sched/core: Turn off IRQs in switch_mm()
+    - ARM: Hide finish_arch_post_lock_switch() from modules
+    - sched/core: Idle_task_exit() shouldn't use switch_mm_irqs_off()
+    - x86/irq: Do not substract irq_tlb_count from irq_call_count
+    - ALSA: hda - add support for docking station for HP 820 G2
+    - ALSA: hda - add support for docking station for HP 840 G3
+    - arm: kprobes: Fix the return address of multiple kretprobes
+    - arm: kprobes: Align stack to 8-bytes in test code
+    - cpuidle: Validate cpu_dev in cpuidle_add_sysfs()
+    - crypto: deadlock between crypto_alg_sem/rtnl_mutex/genl_mutex
+    - sch_dsmark: fix invalid skb_cow() usage
+    - bna: integer overflow bug in debugfs
+    - net: qmi_wwan: Add USB IDs for MDM6600 modem on Motorola Droid 4
+    - usb: gadget: f_uvc: Sanity check wMaxPacketSize for SuperSpeed
+    - usb: gadget: udc: remove pointer dereference after free
+    - netfilter: nfnl_cthelper: fix runtime expectation policy updates
+    - netfilter: nfnl_cthelper: Fix memory leak
+    - inet: frag: release spinlock before calling icmp_send()
+    - pinctrl: st: add irq_request/release_resources callbacks
+    - scsi: lpfc: Fix PT2PT PRLI reject
+    - KVM: x86: correct async page present tracepoint
+    - KVM: VMX: Fix enable VPID conditions
+    - ARM: dts: ti: fix PCI bus dtc warnings
+    - hwmon: (asus_atk0110) fix uninitialized data access
+    - HID: xinmo: fix for out of range for THT 2P arcade controller.
+    - r8152: prevent the driver from transmitting packets with carrier off
+    - s390/qeth: no ETH header for outbound AF_IUCV
+    - bna: avoid writing uninitialized data into hw registers
+    - net: Do not allow negative values for busy_read and busy_poll sysctl
+      interfaces
+    - i40e: Do not enable NAPI on q_vectors that have no rings
+    - RDMA/iser: Fix possible mr leak on device removal event
+    - irda: vlsi_ir: fix check for DMA mapping errors
+    - netfilter: nfnl_cthelper: fix a race when walk the nf_ct_helper_hash table
+    - netfilter: nf_nat_snmp: Fix panic when snmp_trap_helper fails to register
+    - ARM: dts: am335x-evmsk: adjust mmc2 param to allow suspend
+    - KVM: pci-assign: do not map smm memory slot pages in vt-d page tables
+    - isdn: kcapi: avoid uninitialized data
+    - xhci: plat: Register shutdown for xhci_plat
+    - netfilter: nfnetlink_queue: fix secctx memory leak
+    - ARM: dma-mapping: disallow dma_get_sgtable() for non-kernel managed memory
+    - cpuidle: powernv: Pass correct drv->cpumask for registration
+    - bnxt_en: Fix NULL pointer dereference in reopen failure path
+    - backlight: pwm_bl: Fix overflow condition
+    - crypto: crypto4xx - increase context and scatter ring buffer elements
+    - rtc: pl031: make interrupt optional
+    - net: phy: at803x: Change error to EINVAL for invalid MAC
+    - PCI: Avoid bus reset if bridge itself is broken
+    - scsi: cxgb4i: fix Tx skb leak
+    - scsi: mpt3sas: Fix IO error occurs on pulling out a drive from RAID1 volume
+      created on two SATA drive
+    - PCI: Create SR-IOV virtfn/physfn links before attaching driver
+    - igb: check memory allocation failure
+    - ixgbe: fix use of uninitialized padding
+    - PCI/AER: Report non-fatal errors only to the affected endpoint
+    - scsi: lpfc: Fix secure firmware updates
+    - scsi: lpfc: PLOGI failures during NPIV testing
+    - fm10k: ensure we process SM mbx when processing VF mbx
+    - tcp: fix under-evaluated ssthresh in TCP Vegas
+    - rtc: set the alarm to the next expiring timer
+    - cpuidle: fix broadcast control when broadcast can not be entered
+    - thermal: hisilicon: Handle return value of clk_prepare_enable
+    - MIPS: math-emu: Fix final emulation phase for certain instructions
+    - Revert "Bluetooth: btusb: driver to enable the usb-wakeup feature"
+    - ALSA: hda - Clear the leftover component assignment at snd_hdac_i915_exit()
+    - ALSA: hda - Degrade i915 binding failure message
+    - ALSA: hda - Fix yet another i915 pointer leftover in error path
+    - alpha: fix build failures
+    - Linux 4.4.108
+
+  * Xenial update to 4.4.107 stable release (LP: #1745052)
+    - crypto: hmac - require that the underlying hash algorithm is unkeyed
+    - crypto: salsa20 - fix blkcipher_walk API usage
+    - autofs: fix careless error in recent commit
+    - tracing: Allocate mask_str buffer dynamically
+    - USB: uas and storage: Add US_FL_BROKEN_FUA for another JMicron JMS567 ID
+    - USB: core: prevent malicious bNumInterfaces overflow
+    - usbip: fix stub_send_ret_submit() vulnerability to null transfer_buffer
+    - ceph: drop negative child dentries before try pruning inode's alias
+    - Bluetooth: btusb: driver to enable the usb-wakeup feature
+    - xhci: Don't add a virt_dev to the devs array before it's fully allocated
+    - sched/rt: Do not pull from current CPU if only one CPU to pull
+    - dmaengine: dmatest: move callback wait queue to thread context
+    - ext4: fix fdatasync(2) after fallocate(2) operation
+    - ext4: fix crash when a directory's i_size is too small
+    - KEYS: add missing permission check for request_key() destination
+    - mac80211: Fix addition of mesh configuration element
+    - usb: phy: isp1301: Add OF device ID table
+    - md-cluster: free md_cluster_info if node leave cluster
+    - userfaultfd: shmem: __do_fault requires VM_FAULT_NOPAGE
+    - userfaultfd: selftest: vm: allow to build in vm/ directory
+    - net: initialize msg.msg_flags in recvfrom
+    - net: bcmgenet: correct the RBUF_OVFL_CNT and RBUF_ERR_CNT MIB values
+    - net: bcmgenet: correct MIB access of UniMAC RUNT counters
+    - net: bcmgenet: reserved phy revisions must be checked first
+    - net: bcmgenet: power down internal phy if open or resume fails
+    - net: bcmgenet: Power up the internal PHY before probing the MII
+    - NFSD: fix nfsd_minorversion(.., NFSD_AVAIL)
+    - NFSD: fix nfsd_reset_versions for NFSv4.
+    - Input: i8042 - add TUXEDO BU1406 (N24_25BU) to the nomux list
+    - drm/omap: fix dmabuf mmap for dma_alloc'ed buffers
+    - netfilter: bridge: honor frag_max_size when refragmenting
+    - writeback: fix memory leak in wb_queue_work()
+    - net: wimax/i2400m: fix NULL-deref at probe
+    - dmaengine: Fix array index out of bounds warning in __get_unmap_pool()
+    - net: Resend IGMP memberships upon peer notification.
+    - mlxsw: reg: Fix SPVM max record count
+    - mlxsw: reg: Fix SPVMLR max record count
+    - intel_th: pci: Add Gemini Lake support
+    - openrisc: fix issue handling 8 byte get_user calls
+    - scsi: hpsa: update check for logical volume status
+    - scsi: hpsa: limit outstanding rescans
+    - fjes: Fix wrong netdevice feature flags
+    - drm/radeon/si: add dpm quirk for Oland
+    - sched/deadline: Make sure the replenishment timer fires in the next period
+    - sched/deadline: Throttle a constrained deadline task activated after the
+      deadline
+    - sched/deadline: Use deadline instead of period when calculating overflow
+    - mmc: mediatek: Fixed bug where clock frequency could be set wrong
+    - drm/radeon: reinstate oland workaround for sclk
+    - afs: Fix missing put_page()
+    - afs: Populate group ID from vnode status
+    - afs: Adjust mode bits processing
+    - afs: Flush outstanding writes when an fd is closed
+    - afs: Migrate vlocation fields to 64-bit
+    - afs: Prevent callback expiry timer overflow
+    - afs: Fix the maths in afs_fs_store_data()
+    - afs: Populate and use client modification time
+    - afs: Fix page leak in afs_write_begin()
+    - afs: Fix afs_kill_pages()
+    - perf symbols: Fix symbols__fixup_end heuristic for corner cases
+    - efi/esrt: Cleanup bad memory map log messages
+    - NFSv4.1 respect server's max size in CREATE_SESSION
+    - btrfs: add missing memset while reading compressed inline extents
+    - target: Use system workqueue for ALUA transitions
+    - target: fix ALUA transition timeout handling
+    - target: fix race during implicit transition work flushes
+    - sfc: don't warn on successful change of MAC
+    - fbdev: controlfb: Add missing modes to fix out of bounds access
+    - video: udlfb: Fix read EDID timeout
+    - video: fbdev: au1200fb: Release some resources if a memory allocation fails
+    - video: fbdev: au1200fb: Return an error code if a memory allocation fails
+    - rtc: pcf8563: fix output clock rate
+    - dmaengine: ti-dma-crossbar: Correct am335x/am43xx mux value type
+    - PCI/PME: Handle invalid data when reading Root Status
+    - powerpc/powernv/cpufreq: Fix the frequency read by /proc/cpuinfo
+    - netfilter: ipvs: Fix inappropriate output of procfs
+    - powerpc/opal: Fix EBUSY bug in acquiring tokens
+    - powerpc/ipic: Fix status get and status clear
+    - target/iscsi: Fix a race condition in iscsit_add_reject_from_cmd()
+    - iscsi-target: fix memory leak in lio_target_tiqn_addtpg()
+    - target:fix condition return in core_pr_dump_initiator_port()
+    - target/file: Do not return error for UNMAP if length is zero
+    - arm-ccn: perf: Prevent module unload while PMU is in use
+    - crypto: tcrypt - fix buffer lengths in test_aead_speed()
+    - mm: Handle 0 flags in _calc_vm_trans() macro
+    - clk: mediatek: add the option for determining PLL source clock
+    - clk: imx6: refine hdmi_isfr's parent to make HDMI work on i.MX6 SoCs w/o VPU
+    - clk: tegra: Fix cclk_lp divisor register
+    - ppp: Destroy the mutex when cleanup
+    - thermal/drivers/step_wise: Fix temperature regulation misbehavior
+    - GFS2: Take inode off order_write list when setting jdata flag
+    - bcache: explicitly destroy mutex while exiting
+    - bcache: fix wrong cache_misses statistics
+    - l2tp: cleanup l2tp_tunnel_delete calls
+    - xfs: fix log block underflow during recovery cycle verification
+    - xfs: fix incorrect extent state in xfs_bmap_add_extent_unwritten_real
+    - PCI: Detach driver before procfs & sysfs teardown on device remove
+    - scsi: hpsa: cleanup sas_phy structures in sysfs when unloading
+    - scsi: hpsa: destroy sas transport properties before scsi_host
+    - powerpc/perf/hv-24x7: Fix incorrect comparison in memord
+    - tty fix oops when rmmod 8250
+    - usb: musb: da8xx: fix babble condition handling
+    - pinctrl: adi2: Fix Kconfig build problem
+    - raid5: Set R5_Expanded on parity devices as well as data.
+    - scsi: scsi_devinfo: Add REPORTLUN2 to EMC SYMMETRIX blacklist entry
+    - vt6655: Fix a possible sleep-in-atomic bug in vt6655_suspend
+    - scsi: sd: change manage_start_stop to bool in sysfs interface
+    - scsi: sd: change allow_restart to bool in sysfs interface
+    - scsi: bfa: integer overflow in debugfs
+    - udf: Avoid overflow when session starts at large offset
+    - macvlan: Only deliver one copy of the frame to the macvlan interface
+    - RDMA/cma: Avoid triggering undefined behavior
+    - IB/ipoib: Grab rtnl lock on heavy flush when calling ndo_open/stop
+    - ath9k: fix tx99 potential info leak
+    - Linux 4.4.107
+
+  * Xenial update to 4.4.106 stable release (LP: #1745047)
+    - can: ti_hecc: Fix napi poll return value for repoll
+    - can: kvaser_usb: free buf in error paths
+    - can: kvaser_usb: Fix comparison bug in kvaser_usb_read_bulk_callback()
+    - can: kvaser_usb: ratelimit errors if incomplete messages are received
+    - can: kvaser_usb: cancel urb on -EPIPE and -EPROTO
+    - can: ems_usb: cancel urb on -EPIPE and -EPROTO
+    - can: esd_usb2: cancel urb on -EPIPE and -EPROTO
+    - can: usb_8dev: cancel urb on -EPIPE and -EPROTO
+    - virtio: release virtio index when fail to device_register
+    - hv: kvp: Avoid reading past allocated blocks from KVP file
+    - isa: Prevent NULL dereference in isa_bus driver callbacks
+    - scsi: libsas: align sata_device's rps_resp on a cacheline
+    - efi: Move some sysfs files to be read-only by root
+    - ASN.1: fix out-of-bounds read when parsing indefinite length item
+    - ASN.1: check for error from ASN1_OP_END__ACT actions
+    - X.509: reject invalid BIT STRING for subjectPublicKey
+    - x86/PCI: Make broadcom_postcore_init() check acpi_disabled
+    - ALSA: pcm: prevent UAF in snd_pcm_info
+    - ALSA: seq: Remove spurious WARN_ON() at timer check
+    - ALSA: usb-audio: Fix out-of-bound error
+    - ALSA: usb-audio: Add check return value for usb_string()
+    - iommu/vt-d: Fix scatterlist offset handling
+    - s390: fix compat system call table
+    - kdb: Fix handling of kallsyms_symbol_next() return value
+    - drm: extra printk() wrapper macros
+    - drm/exynos: gem: Drop NONCONTIG flag for buffers allocated without IOMMU
+    - media: dvb: i2c transfers over usb cannot be done from stack
+    - arm64: KVM: fix VTTBR_BADDR_MASK BUG_ON off-by-one
+    - KVM: VMX: remove I/O port 0x80 bypass on Intel hosts
+    - arm64: fpsimd: Prevent registers leaking from dead tasks
+    - ARM: BUG if jumping to usermode address in kernel mode
+    - ARM: avoid faulting on qemu
+    - thp: reduce indentation level in change_huge_pmd()
+    - thp: fix MADV_DONTNEED vs. numa balancing race
+    - mm: drop unused pmdp_huge_get_and_clear_notify()
+    - Revert "drm/armada: Fix compile fail"
+    - Revert "spi: SPI_FSL_DSPI should depend on HAS_DMA"
+    - Revert "s390/kbuild: enable modversions for symbols exported from asm"
+    - vti6: Don't report path MTU below IPV6_MIN_MTU.
+    - ARM: OMAP2+: gpmc-onenand: propagate error on initialization failure
+    - x86/hpet: Prevent might sleep splat on resume
+    - selftest/powerpc: Fix false failures for skipped tests
+    - module: set __jump_table alignment to 8
+    - ARM: OMAP2+: Fix device node reference counts
+    - ARM: OMAP2+: Release device node after it is no longer needed.
+    - gpio: altera: Use handle_level_irq when configured as a level_high
+    - HID: chicony: Add support for another ASUS Zen AiO keyboard
+    - usb: gadget: configs: plug memory leak
+    - USB: gadgetfs: Fix a potential memory leak in 'dev_config()'
+    - kvm: nVMX: VMCLEAR should not cause the vCPU to shut down
+    - libata: drop WARN from protocol error in ata_sff_qc_issue()
+    - workqueue: trigger WARN if queue_delayed_work() is called with NULL @wq
+    - scsi: lpfc: Fix crash during Hardware error recovery on SLI3 adapters
+    - irqchip/crossbar: Fix incorrect type of register size
+    - KVM: nVMX: reset nested_run_pending if the vCPU is going to be reset
+    - arm: KVM: Survive unknown traps from guests
+    - arm64: KVM: Survive unknown traps from guests
+    - spi_ks8995: fix "BUG: key accdaa28 not in .data!"
+    - bnx2x: prevent crash when accessing PTP with interface down
+    - bnx2x: fix possible overrun of VFPF multicast addresses array
+    - bnx2x: do not rollback VF MAC/VLAN filters we did not configure
+    - ipv6: reorder icmpv6_init() and ip6_mr_init()
+    - crypto: s5p-sss - Fix completing crypto request in IRQ handler
+    - i2c: riic: fix restart condition
+    - zram: set physical queue limits to avoid array out of bounds accesses
+    - netfilter: don't track fragmented packets
+    - axonram: Fix gendisk handling
+    - drm/amd/amdgpu: fix console deadlock if late init failed
+    - powerpc/powernv/ioda2: Gracefully fail if too many TCE levels requested
+    - EDAC, i5000, i5400: Fix use of MTR_DRAM_WIDTH macro
+    - EDAC, i5000, i5400: Fix definition of NRECMEMB register
+    - kbuild: pkg: use --transform option to prefix paths in tar
+    - mac80211_hwsim: Fix memory leak in hwsim_new_radio_nl()
+    - route: also update fnhe_genid when updating a route cache
+    - route: update fnhe_expires for redirect when the fnhe exists
+    - lib/genalloc.c: make the avail variable an atomic_long_t
+    - dynamic-debug-howto: fix optional/omitted ending line number to be LARGE
+      instead of 0
+    - NFS: Fix a typo in nfs_rename()
+    - sunrpc: Fix rpc_task_begin trace point
+    - block: wake up all tasks blocked in get_request()
+    - sparc64/mm: set fields in deferred pages
+    - sctp: do not free asoc when it is already dead in sctp_sendmsg
+    - sctp: use the right sk after waking up from wait_buf sleep
+    - atm: horizon: Fix irq release error
+    - jump_label: Invoke jump_label_test() via early_initcall()
+    - xfrm: Copy policy family in clone_policy
+    - IB/mlx4: Increase maximal message size under UD QP
+    - IB/mlx5: Assign send CQ and recv CQ of UMR QP
+    - afs: Connect up the CB.ProbeUuid
+    - ipvlan: fix ipv6 outbound device
+    - audit: ensure that 'audit=1' actually enables audit for PID 1
+    - ipmi: Stop timers before cleaning up the module
+    - s390: always save and restore all registers on context switch
+    - tipc: fix memory leak in tipc_accept_from_sock()
+    - rds: Fix NULL pointer dereference in __rds_rdma_map
+    - sit: update frag_off info
+    - packet: fix crash in fanout_demux_rollover()
+    - net/packet: fix a race in packet_bind() and packet_notifier()
+    - Revert "x86/efi: Build our own page table structures"
+    - Revert "x86/efi: Hoist page table switching code into efi_call_virt()"
+    - Revert "x86/mm/pat: Ensure cpa->pfn only contains page frame numbers"
+    - arm: KVM: Fix VTTBR_BADDR_MASK BUG_ON off-by-one
+    - usb: gadget: ffs: Forbid usb_ep_alloc_request from sleeping
+    - Linux 4.4.106
+
+  * Xenial update to 4.4.105 stable release (LP: #1745046)
+    - bcache: only permit to recovery read error when cache device is clean
+    - bcache: recover data from backing when data is clean
+    - uas: Always apply US_FL_NO_ATA_1X quirk to Seagate devices
+    - usb: quirks: Add no-lpm quirk for KY-688 USB 3.1 Type-C Hub
+    - serial: 8250_pci: Add Amazon PCI serial device ID
+    - s390/runtime instrumentation: simplify task exit handling
+    - USB: serial: option: add Quectel BG96 id
+    - ima: fix hash algorithm initialization
+    - s390/pci: do not require AIS facility
+    - selftests/x86/ldt_get: Add a few additional tests for limits
+    - serial: 8250_fintek: Fix rs485 disablement on invalid ioctl()
+    - spi: sh-msiof: Fix DMA transfer size check
+    - usb: phy: tahvo: fix error handling in tahvo_usb_probe()
+    - serial: 8250: Preserve DLD[7:4] for PORT_XR17V35X
+    - x86/entry: Use SYSCALL_DEFINE() macros for sys_modify_ldt()
+    - EDAC, sb_edac: Fix missing break in switch
+    - sysrq : fix Show Regs call trace on ARM
+    - perf test attr: Fix ignored test case result
+    - kprobes/x86: Disable preemption in ftrace-based jprobes
+    - net: systemport: Utilize skb_put_padto()
+    - net: systemport: Pad packet before inserting TSB
+    - ARM: OMAP1: DMA: Correct the number of logical channels
+    - vti6: fix device register to report IFLA_INFO_KIND
+    - net/appletalk: Fix kernel memory disclosure
+    - ravb: Remove Rx overflow log messages
+    - nfs: Don't take a reference on fl->fl_file for LOCK operation
+    - KVM: arm/arm64: Fix occasional warning from the timer work function
+    - NFSv4: Fix client recovery when server reboots multiple times
+    - drm/exynos/decon5433: set STANDALONE_UPDATE_F on output enablement
+    - net: sctp: fix array overrun read on sctp_timer_tbl
+    - tipc: fix cleanup at module unload
+    - dmaengine: pl330: fix double lock
+    - tcp: correct memory barrier usage in tcp_check_space()
+    - mm: avoid returning VM_FAULT_RETRY from ->page_mkwrite handlers
+    - xen-netfront: Improve error handling during initialization
+    - net: fec: fix multicast filtering hardware setup
+    - Revert "ocfs2: should wait dio before inode lock in ocfs2_setattr()"
+    - usb: hub: Cycle HUB power when initialization fails
+    - usb: xhci: fix panic in xhci_free_virt_devices_depth_first
+    - usb: ch9: Add size macro for SSP dev cap descriptor
+    - USB: core: Add type-specific length check of BOS descriptors
+    - USB: Increase usbfs transfer limit
+    - USB: devio: Prevent integer overflow in proc_do_submiturb()
+    - USB: usbfs: Filter flags passed in from user space
+    - usb: host: fix incorrect updating of offset
+    - xen-netfront: avoid crashing on resume after a failure in talk_to_netback()
+    - Linux 4.4.105
+
+  * Xenial update to 4.4.104 stable release (LP: #1745043)
+    - x86/mm/pat: Ensure cpa->pfn only contains page frame numbers
+    - x86/efi: Hoist page table switching code into efi_call_virt()
+    - x86/efi: Build our own page table structures
+    - ARM: dts: omap3: logicpd-torpedo-37xx-devkit: Fix MMC1 cd-gpio
+    - x86/efi-bgrt: Fix kernel panic when mapping BGRT data
+    - x86/efi-bgrt: Replace early_memremap() with memremap()
+    - mm/madvise.c: fix madvise() infinite loop under special circumstances
+    - btrfs: clear space cache inode generation always
+    - KVM: x86: pvclock: Handle first-time write to pvclock-page contains random
+      junk
+    - KVM: x86: Exit to user-mode on #UD intercept when emulator requires
+    - KVM: x86: inject exceptions produced by x86_decode_insn
+    - mmc: core: Do not leave the block driver in a suspended state
+    - eeprom: at24: check at24_read/write arguments
+    - bcache: Fix building error on MIPS
+    - Revert "drm/radeon: dont switch vt on suspend"
+    - drm/radeon: fix atombios on big endian
+    - drm/panel: simple: Add missing panel_simple_unprepare() calls
+    - mtd: nand: Fix writing mtdoops to nand flash.
+    - NFS: revalidate "." etc correctly on "open".
+    - drm/i915: Don't try indexed reads to alternate slave addresses
+    - drm/i915: Prevent zero length "index" write
+    - nfsd: Make init_open_stateid() a bit more whole
+    - nfsd: Fix stateid races between OPEN and CLOSE
+    - nfsd: Fix another OPEN stateid race
+    - Linux 4.4.104
+
+  * Xenial update to 4.4.103 stable release (LP: #1744873)
+    - s390: fix transactional execution control register handling
+    - s390/runtime instrumention: fix possible memory corruption
+    - s390/disassembler: add missing end marker for e7 table
+    - s390/disassembler: increase show_code buffer size
+    - AF_VSOCK: Shrink the area influenced by prepare_to_wait
+    - vsock: use new wait API for vsock_stream_sendmsg()
+    - sched: Make resched_cpu() unconditional
+    - lib/mpi: call cond_resched() from mpi_powm() loop
+    - x86/decoder: Add new TEST instruction pattern
+    - ARM: 8722/1: mm: make STRICT_KERNEL_RWX effective for LPAE
+    - ARM: 8721/1: mm: dump: check hardware RO bit for LPAE
+    - MIPS: ralink: Fix MT7628 pinmux
+    - MIPS: ralink: Fix typo in mt7628 pinmux function
+    - ALSA: hda: Add Raven PCI ID
+    - dm bufio: fix integer overflow when limiting maximum cache size
+    - dm: fix race between dm_get_from_kobject() and __dm_destroy()
+    - MIPS: Fix an n32 core file generation regset support regression
+    - MIPS: BCM47XX: Fix LED inversion for WRT54GSv1
+    - autofs: don't fail mount for transient error
+    - nilfs2: fix race condition that causes file system corruption
+    - eCryptfs: use after free in ecryptfs_release_messaging()
+    - bcache: check ca->alloc_thread initialized before wake up it
+    - isofs: fix timestamps beyond 2027
+    - NFS: Fix typo in nomigration mount option
+    - nfs: Fix ugly referral attributes
+    - nfsd: deal with revoked delegations appropriately
+    - rtlwifi: rtl8192ee: Fix memory leak when loading firmware
+    - rtlwifi: fix uninitialized rtlhal->last_suspend_sec time
+    - ata: fixes kernel crash while tracing ata_eh_link_autopsy event
+    - ext4: fix interaction between i_size, fallocate, and delalloc after a crash
+    - ALSA: pcm: update tstamp only if audio_tstamp changed
+    - ALSA: usb-audio: Add sanity checks to FE parser
+    - ALSA: usb-audio: Fix potential out-of-bound access at parsing SU
+    - ALSA: usb-audio: Add sanity checks in v2 clock parsers
+    - ALSA: timer: Remove kernel warning at compat ioctl error paths
+    - ALSA: hda/realtek - Fix ALC700 family no sound issue
+    - fix a page leak in vhost_scsi_iov_to_sgl() error recovery
+    - fs/9p: Compare qid.path in v9fs_test_inode
+    - iscsi-target: Fix non-immediate TMR reference leak
+    - target: Fix QUEUE_FULL + SCSI task attribute handling
+    - KVM: nVMX: set IDTR and GDTR limits when loading L1 host state
+    - KVM: SVM: obey guest PAT
+    - SUNRPC: Fix tracepoint storage issues with svc_recv and svc_rqst_status
+    - clk: ti: dra7-atl-clock: Fix of_node reference counting
+    - clk: ti: dra7-atl-clock: fix child-node lookups
+    - libnvdimm, namespace: fix label initialization to use valid seq numbers
+    - libnvdimm, namespace: make 'resource' attribute only readable by root
+    - IB/srpt: Do not accept invalid initiator port names
+    - IB/srp: Avoid that a cable pull can trigger a kernel crash
+    - NFC: fix device-allocation error return
+    - i40e: Use smp_rmb rather than read_barrier_depends
+    - igb: Use smp_rmb rather than read_barrier_depends
+    - igbvf: Use smp_rmb rather than read_barrier_depends
+    - ixgbevf: Use smp_rmb rather than read_barrier_depends
+    - i40evf: Use smp_rmb rather than read_barrier_depends
+    - fm10k: Use smp_rmb rather than read_barrier_depends
+    - ixgbe: Fix skb list corruption on Power systems
+    - parisc: Fix validity check of pointer size argument in new CAS
+      implementation
+    - powerpc/signal: Properly handle return value from uprobe_deny_signal()
+    - media: Don't do DMA on stack for firmware upload in the AS102 driver
+    - media: rc: check for integer overflow
+    - cx231xx-cards: fix NULL-deref on missing association descriptor
+    - media: v4l2-ctrl: Fix flags field on Control events
+    - sched/rt: Simplify the IPI based RT balancing logic
+    - fscrypt: lock mutex before checking for bounce page pool
+    - net/9p: Switch to wait_event_killable()
+    - PM / OPP: Add missing of_node_put(np)
+    - e1000e: Fix error path in link detection
+    - e1000e: Fix return value test
+    - RDS: RDMA: return appropriate error on rdma map failures
+    - PCI: Apply _HPX settings only to relevant devices
+    - dmaengine: zx: set DMA_CYCLIC cap_mask bit
+    - net: Allow IP_MULTICAST_IF to set index to L3 slave
+    - net: 3com: typhoon: typhoon_init_one: make return values more specific
+    - net: 3com: typhoon: typhoon_init_one: fix incorrect return values
+    - drm/armada: Fix compile fail
+    - ath10k: fix incorrect txpower set by P2P_DEVICE interface
+    - ath10k: ignore configuring the incorrect board_id
+    - ath10k: fix potential memory leak in ath10k_wmi_tlv_op_pull_fw_stats()
+    - ath10k: set CTS protection VDEV param only if VDEV is up
+    - ALSA: hda - Apply ALC269_FIXUP_NO_SHUTUP on HDA_FIXUP_ACT_PROBE
+    - drm: Apply range restriction after color adjustment when allocation
+    - mac80211: Remove invalid flag operations in mesh TSF synchronization
+    - mac80211: Suppress NEW_PEER_CANDIDATE event if no room
+    - iio: light: fix improper return value
+    - staging: iio: cdc: fix improper return value
+    - spi: SPI_FSL_DSPI should depend on HAS_DMA
+    - netfilter: nft_queue: use raw_smp_processor_id()
+    - netfilter: nf_tables: fix oob access
+    - ASoC: rsnd: don't double free kctrl
+    - btrfs: return the actual error value from from btrfs_uuid_tree_iterate
+    - ASoC: wm_adsp: Don't overrun firmware file buffer when reading region data
+    - s390/kbuild: enable modversions for symbols exported from asm
+    - xen: xenbus driver must not accept invalid transaction ids
+    - Revert "sctp: do not peel off an assoc from one netns to another one"
+    - Linux 4.4.103
+
+  * ppc64el: Do not call ibm,os-term on panic (LP: #1736954)
+    - powerpc: Do not call ppc_md.panic in fadump panic notifier
+
+  * Xenial update to 4.4.102 stable release (LP: #1744870)
+    - mm, hwpoison: fixup "mm: check the return value of lookup_page_ext for all
+      call sites"
+    - Linux 4.4.102
+
+  * Xenial update to 4.4.101 stable release (LP: #1744794)
+    - tcp: do not mangle skb->cb[] in tcp_make_synack()
+    - netfilter/ipvs: clear ipvs_property flag when SKB net namespace changed
+    - bonding: discard lowest hash bit for 802.3ad layer3+4
+    - vlan: fix a use-after-free in vlan_device_event()
+    - af_netlink: ensure that NLMSG_DONE never fails in dumps
+    - sctp: do not peel off an assoc from one netns to another one
+    - fealnx: Fix building error on MIPS
+    - net/sctp: Always set scope_id in sctp_inet6_skb_msgname
+    - ima: do not update security.ima if appraisal status is not INTEGRITY_PASS
+    - serial: omap: Fix EFR write on RTS deassertion
+    - arm64: fix dump_instr when PAN and UAO are in use
+    - ocfs2: should wait dio before inode lock in ocfs2_setattr()
+    - ipmi: fix unsigned long underflow
+    - mm/page_alloc.c: broken deferred calculation
+    - coda: fix 'kernel memory exposure attempt' in fsync
+    - mm: check the return value of lookup_page_ext for all call sites
+    - mm/page_ext.c: check if page_ext is not prepared
+    - mm/pagewalk.c: report holes in hugetlb ranges
+    - Linux 4.4.101
+
+  * Xenial update to 4.4.100 stable release (LP: #1744639)
+    - media: imon: Fix null-ptr-deref in imon_probe
+    - media: dib0700: fix invalid dvb_detach argument
+    - KVM: x86: fix singlestepping over syscall
+    - net: cdc_ether: fix divide by 0 on bad descriptors
+    - net: qmi_wwan: fix divide by 0 on bad descriptors
+    - arm: crypto: reduce priority of bit-sliced AES cipher
+    - Bluetooth: btusb: fix QCA Rome suspend/resume
+    - dmaengine: dmatest: warn user when dma test times out
+    - extcon: palmas: Check the parent instance to prevent the NULL
+    - fm10k: request reset when mbx->state changes
+    - ARM: dts: Fix compatible for ti81xx uarts for 8250
+    - ARM: dts: Fix am335x and dm814x scm syscon to probe children
+    - ARM: OMAP2+: Fix init for multiple quirks for the same SoC
+    - ARM: dts: Fix omap3 off mode pull defines
+    - ata: ATA_BMDMA should depend on HAS_DMA
+    - ata: SATA_HIGHBANK should depend on HAS_DMA
+    - ata: SATA_MV should depend on HAS_DMA
+    - drm/sti: sti_vtg: Handle return NULL error from devm_ioremap_nocache
+    - igb: reset the PHY before reading the PHY ID
+    - igb: close/suspend race in netif_device_detach
+    - igb: Fix hw_dbg logging in igb_update_flash_i210
+    - scsi: ufs-qcom: Fix module autoload
+    - scsi: ufs: add capability to keep auto bkops always enabled
+    - staging: rtl8188eu: fix incorrect ERROR tags from logs
+    - scsi: lpfc: FCoE VPort enable-disable does not bring up the VPort
+    - scsi: lpfc: Correct host name in symbolic_name field
+    - scsi: lpfc: Correct issue leading to oops during link reset
+    - scsi: lpfc: Clear the VendorVersion in the PLOGI/PLOGI ACC payload
+    - ALSA: vx: Don't try to update capture stream before running
+    - ALSA: vx: Fix possible transfer overflow
+    - backlight: lcd: Fix race condition during register
+    - backlight: adp5520: Fix error handling in adp5520_bl_probe()
+    - gpu: drm: mgag200: mgag200_main:- Handle error from pci_iomap
+    - ALSA: hda/realtek - Add new codec ID ALC299
+    - arm64: dts: NS2: reserve memory for Nitro firmware
+    - ixgbe: fix AER error handling
+    - ixgbe: handle close/suspend race with netif_device_detach/present
+    - ixgbe: Reduce I2C retry count on X550 devices
+    - ixgbe: add mask for 64 RSS queues
+    - ixgbe: do not disable FEC from the driver
+    - staging: rtl8712: fixed little endian problem
+    - MIPS: End asm function prologue macros with .insn
+    - mm: add PHYS_PFN, use it in __phys_to_pfn()
+    - MIPS: init: Ensure bootmem does not corrupt reserved memory
+    - MIPS: init: Ensure reserved memory regions are not added to bootmem
+    - MIPS: Netlogic: Exclude netlogic,xlp-pic code from XLR builds
+    - Revert "crypto: xts - Add ECB dependency"
+    - Revert "uapi: fix linux/rds.h userspace compilation errors"
+    - uapi: fix linux/rds.h userspace compilation error
+    - uapi: fix linux/rds.h userspace compilation errors
+    - USB: usbfs: compute urb->actual_length for isochronous
+    - USB: Add delay-init quirk for Corsair K70 LUX keyboards
+    - USB: serial: qcserial: add pid/vid for Sierra Wireless EM7355 fw update
+    - USB: serial: garmin_gps: fix I/O after failed probe and remove
+    - USB: serial: garmin_gps: fix memory leak on probe errors
+    - Linux 4.4.100
+
+  * Xenial update to 4.4.99 stable release (LP: #1744636)
+    - mac80211: accept key reinstall without changing anything
+    - mac80211: use constant time comparison with keys
+    - mac80211: don't compare TKIP TX MIC key in reinstall prevention
+    - usb: usbtest: fix NULL pointer dereference
+    - Input: ims-psu - check if CDC union descriptor is sane
+    - ALSA: seq: Cancel pending autoload work at unbinding device
+    - tun/tap: sanitize TUNSETSNDBUF input
+    - tcp: fix tcp_mtu_probe() vs highest_sack
+    - l2tp: check ps->sock before running pppol2tp_session_ioctl()
+    - tun: call dev_get_valid_name() before register_netdevice()
+    - sctp: add the missing sock_owned_by_user check in sctp_icmp_redirect
+    - packet: avoid panic in packet_getsockopt()
+    - ipv6: flowlabel: do not leave opt->tot_len with garbage
+    - net/unix: don't show information about sockets from other namespaces
+    - ip6_gre: only increase err_count for some certain type icmpv6 in ip6gre_err
+    - tun: allow positive return values on dev_get_valid_name() call
+    - sctp: reset owner sk for data chunks on out queues when migrating a sock
+    - ppp: fix race in ppp device destruction
+    - ipip: only increase err_count for some certain type icmp in ipip_err
+    - tcp/dccp: fix ireq->opt races
+    - tcp/dccp: fix lockdep splat in inet_csk_route_req()
+    - tcp/dccp: fix other lockdep splats accessing ireq_opt
+    - security/keys: add CONFIG_KEYS_COMPAT to Kconfig
+    - tipc: fix link attribute propagation bug
+    - brcmfmac: remove setting IBSS mode when stopping AP
+    - target/iscsi: Fix iSCSI task reassignment handling
+    - target: Fix node_acl demo-mode + uncached dynamic shutdown regression
+    - misc: panel: properly restore atomic counter on error path
+    - Linux 4.4.99
+
+  * elantech touchpad of Lenovo L480/580 failed to detect hw_version
+    (LP: #1733605)
+    - Input: elantech - add new icbody type 15
+
+  * Disabling zfs does not always disable module checks for the zfs modules
+    (LP: #1737176)
+    - [Packaging] disable zfs module checks when zfs is disabled
+
+  * Using asymmetric key for IMA appraisal crashes the system in Ubuntu 16.04
+    (LP: #1735977)
+    - integrity: convert digsig to akcipher api
+
+  * CVE-2017-17450
+    - netfilter: xt_osf: Add missing permission checks
+
+  * CVE-2017-15129
+    - net: Fix double free and memory corruption in get_net_ns_by_id()
+
+  * CVE-2018-5344
+    - loop: fix concurrent lo_open/lo_release
+
+  * [KVM] Lower the default for halt_poll_ns to 200000 ns (LP: #1724614)
+    - KVM: x86: lower default for halt_poll_ns
+
+  * $(LOCAL_ENV_CC) and $(LOCAL_ENV_DISTCC_HOSTS) should be properly quoted
+    (LP: #1744077)
+    - [Debian] pass LOCAL_ENV_CC and LOCAL_ENV_DISTCC_HOSTS properly
+
+  * Redpine: Wifi/BT not functioning after s3 resume (LP: #1742090) //
+    [16.04][classic] Redpine: wowlan feature doesn't work (LP: #1742094)
+    - SAUCE: Redpine: fix for wowlan wakeup failure
+    - SAUCE: Redpine: fix data issue with non-uapsd APs
+    - SAUCE: Redpine: fix reset card issue
+    - SAUCE: Redpine: fix wowlan issue
+
+  * Using an NVMe drive causes huge power drain (LP: #1664602) // Samsung SSD
+    960 EVO 500GB refused to change power state (LP: #1705748)
+    - nvme-pci: disable APST on Samsung SSD 960 EVO + ASUS PRIME B350M-A
+
+  * Using an NVMe drive causes huge power drain (LP: #1664602)
+    - nvme/scsi: Remove power management support
+    - nvme: return the whole CQE through the request passthrough interface
+    - nvme: factor out a add nvme_is_write helper
+    - nvme: Modify and export sync command submission for fabrics
+    - nvme: Fix nvme_get/set_features() with a NULL result pointer
+    - nvme: Pass pointers, not dma addresses, to nvme_get/set_features()
+    - nvme: Add a quirk mechanism that uses identify_ctrl
+    - nvme: Enable autonomous power state transitions
+    - nvme: Adjust the Samsung APST quirk
+    - nvme: Quirk APST off on "THNSF5256GPUK TOSHIBA"
+    - nvme: only consider exit latency when choosing useful non-op power states
+    - nvme: relax APST default max latency to 100ms
+    - nvme: Quirk APST on Intel 600P/P3100 devices
+
+  * CVE-2017-17862
+    - bpf: fix branch pruning logic
+
+  * CVE-2017-16995
+    - bpf: fix incorrect sign extension in check_alu_op()
+
+  * CVE-2017-17741
+    - KVM: Fix stack-out-of-bounds read in write_mmio
+
+  * CVE-2018-5333
+    - RDS: null pointer dereference in rds_atomic_free_op
+
+  * the kernel is blackholing IPv6 packets to linkdown nexthops (LP: #1738219)
+    - ipv6: Do not consider linkdown nexthops during multipath
+
+  * /dev/bcache/by-uuid links not created after reboot (LP: #1729145)
+    - SAUCE: (no-up) bcache: decouple emitting a cached_dev CHANGE uevent
+
+  * e1000e in 4.4.0-97-generic breaks 82574L under heavy load. (LP: #1730550)
+    - e1000e: Avoid receiver overrun interrupt bursts
+    - e1000e: Separate signaling for link check/link up
+
+  * ath10k: enhance rf signal strength (LP: #1736317)
+    - ath10k: add max_tx_power for QCA6174 WLAN.RM.2.0 firmware
+
+  * User reports excessive ALUA retry messages (LP: #1720228)
+    - scsi_dh_alua: uninitialized variable in alua_rtpg()
+
+  * Add installer support for new Broadcom network drivers.  (LP: #1734757)
+    - d-i: Add bnxt_en_bpo to nic-modules.
+
+  * Transparent hugepages should default to enabled=madvise (LP: #1703742)
+    - SAUCE: use CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y as default
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 13 Mar 2018 11:55:32 +0100
+
+linux (4.4.0-116.140) xenial; urgency=medium
+
+  * linux: 4.4.0-116.140 -proposed tracker (LP: #1748990)
+
+  * BUG: unable to handle kernel NULL pointer dereference at 0000000000000009
+    (LP: #1748671)
+    - SAUCE: net: ipv4: fix for a race condition in raw_sendmsg -- fix backport
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Mon, 12 Feb 2018 20:17:57 +0000
+
+linux (4.4.0-115.139) xenial; urgency=medium
+
+  * linux: 4.4.0-115.138 -proposed tracker (LP: #1748745)
+
+  * CVE-2017-5715 (Spectre v2 Intel)
+    - Revert "UBUNTU: SAUCE: turn off IBPB when full retpoline is present"
+    - SAUCE: turn off IBRS when full retpoline is present
+    - [Packaging] retpoline files must be sorted
+    - [Packaging] pull in retpoline files
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 11 Feb 2018 11:52:42 +0000
+
+linux (4.4.0-114.137) xenial; urgency=medium
+
+  * linux: 4.4.0-114.137 -proposed tracker (LP: #1748484)
+
+  * ALSA backport missing NVIDIA GPU codec IDs to patch table to
+    Ubuntu 16.04 LTS Kernel (LP: #1744117)
+    - ALSA: hda - Add missing NVIDIA GPU codec IDs to patch table
+
+  * Shutdown hang on 16.04 with iscsi targets (LP: #1569925)
+    - scsi: libiscsi: Allow sd_shutdown on bad transport
+
+  * libata: apply MAX_SEC_1024 to all LITEON EP1 series devices (LP: #1743053)
+    - libata: apply MAX_SEC_1024 to all LITEON EP1 series devices
+
+  * KVM patches for s390x to provide facility bits 81 (ppa15) and 82 (bpb)
+    (LP: #1747090)
+    - KVM: s390: wire up bpb feature
+    - KVM: s390: Enable all facility bits that are known good for passthrough
+
+  * CVE-2017-5715 (Spectre v2 Intel)
+    - SAUCE: drop lingering gmb() macro
+    - x86/feature: Enable the x86 feature to control Speculation
+    - x86/feature: Report presence of IBPB and IBRS control
+    - x86/enter: MACROS to set/clear IBRS and set IBPB
+    - x86/enter: Use IBRS on syscall and interrupts
+    - x86/idle: Disable IBRS entering idle and enable it on wakeup
+    - x86/idle: Disable IBRS when offlining cpu and re-enable on wakeup
+    - x86/mm: Set IBPB upon context switch
+    - x86/mm: Only set IBPB when the new thread cannot ptrace current thread
+    - x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm
+    - x86/kvm: Set IBPB when switching VM
+    - x86/kvm: Toggle IBRS on VM entry and exit
+    - x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature
+    - x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb control
+    - x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR
+    - x86/cpu/AMD: Add speculative control support for AMD
+    - x86/microcode: Extend post microcode reload to support IBPB feature
+    - KVM: SVM: Do not intercept new speculative control MSRs
+    - x86/svm: Set IBRS value on VM entry and exit
+    - x86/svm: Set IBPB when running a different VCPU
+    - KVM: x86: Add speculative control CPUID support for guests
+    - SAUCE: Fix spec_ctrl support in KVM
+    - SAUCE: turn off IBPB when full retpoline is present
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Fri, 09 Feb 2018 20:20:45 +0000
+
+linux (4.4.0-113.136) xenial; urgency=low
+
+  * linux: 4.4.0-113.136 -proposed tracker (LP: #1746936)
+
+  [ Stefan Bader ]
+  * Missing install-time driver for QLogic QED 25/40/100Gb Ethernet NIC
+    (LP: #1743638)
+    - [d-i] Add qede to nic-modules udeb
+
+  * CVE-2017-5753 (Spectre v1 Intel)
+    - x86/cpu/AMD: Make the LFENCE instruction serialized
+    - x86/cpu/AMD: Remove now unused definition of MFENCE_RDTSC feature
+    - SAUCE: reinstate MFENCE_RDTSC feature definition
+    - locking/barriers: introduce new observable speculation barrier
+    - bpf: prevent speculative execution in eBPF interpreter
+    - x86, bpf, jit: prevent speculative execution when JIT is enabled
+    - SAUCE: FIX: x86, bpf, jit: prevent speculative execution when JIT is enabled
+    - carl9170: prevent speculative execution
+    - qla2xxx: prevent speculative execution
+    - Thermal/int340x: prevent speculative execution
+    - ipv4: prevent speculative execution
+    - ipv6: prevent speculative execution
+    - fs: prevent speculative execution
+    - net: mpls: prevent speculative execution
+    - udf: prevent speculative execution
+    - userns: prevent speculative execution
+    - SAUCE: claim mitigation via observable speculation barrier
+    - SAUCE: powerpc: add osb barrier
+    - SAUCE: s390/spinlock: add osb memory barrier
+    - SAUCE: arm64: no osb() implementation yet
+    - SAUCE: arm: no osb() implementation yet
+
+  * CVE-2017-5715 (Spectre v2 retpoline)
+    - x86/cpuid: Provide get_scattered_cpuid_leaf()
+    - x86/cpu: Factor out application of forced CPU caps
+    - x86/cpufeatures: Make CPU bugs sticky
+    - x86/cpufeatures: Add X86_BUG_CPU_INSECURE
+    - x86/cpu, x86/pti: Do not enable PTI on AMD processors
+    - x86/pti: Rename BUG_CPU_INSECURE to BUG_CPU_MELTDOWN
+    - x86/cpufeatures: Add X86_BUG_SPECTRE_V[12]
+    - x86/cpu: Merge bugs.c and bugs_64.c
+    - sysfs/cpu: Add vulnerability folder
+    - x86/cpu: Implement CPU vulnerabilites sysfs functions
+    - x86/alternatives: Add missing '\n' at end of ALTERNATIVE inline asm
+    - x86/mm/32: Move setup_clear_cpu_cap(X86_FEATURE_PCID) earlier
+    - x86/asm: Use register variable to get stack pointer value
+    - x86/kbuild: enable modversions for symbols exported from asm
+    - x86/asm: Make asm/alternative.h safe from assembly
+    - EXPORT_SYMBOL() for asm
+    - kconfig.h: use __is_defined() to check if MODULE is defined
+    - x86/retpoline: Add initial retpoline support
+    - x86/spectre: Add boot time option to select Spectre v2 mitigation
+    - x86/retpoline/crypto: Convert crypto assembler indirect jumps
+    - x86/retpoline/entry: Convert entry assembler indirect jumps
+    - x86/retpoline/ftrace: Convert ftrace assembler indirect jumps
+    - x86/retpoline/hyperv: Convert assembler indirect jumps
+    - x86/retpoline/xen: Convert Xen hypercall indirect jumps
+    - x86/retpoline/checksum32: Convert assembler indirect jumps
+    - x86/retpoline/irq32: Convert assembler indirect jumps
+    - x86/retpoline: Fill return stack buffer on vmexit
+    - x86/retpoline: Remove compile time warning
+    - x86/retpoline: Add LFENCE to the retpoline/RSB filling RSB macros
+    - module: Add retpoline tag to VERMAGIC
+    - x86/mce: Make machine check speculation protected
+    - retpoline: Introduce start/end markers of indirect thunk
+    - kprobes/x86: Blacklist indirect thunk functions for kprobes
+    - kprobes/x86: Disable optimizing on the function jumps to indirect thunk
+    - x86/retpoline: Optimize inline assembler for vmexit_fill_RSB
+    - [Config] CONFIG_RETPOLINE=y
+    - [Packaging] retpoline -- add call site validation
+    - [Config] disable retpoline checks for first upload
+
+  * CVE-2017-5715 (revert embargoed) // CVE-2017-5753 (revert embargoed)
+    - Revert "UBUNTU: SAUCE: Fix spec_ctrl support in KVM"
+    - Revert "x86/cpuid: Provide get_scattered_cpuid_leaf()"
+    - Revert "kvm: vmx: Scrub hardware GPRs at VM-exit"
+    - Revert "Revert "x86/svm: Add code to clear registers on VM exit""
+    - Revert "UBUNTU: SAUCE: x86/microcode: Extend post microcode reload to
+      support IBPB feature -- repair missmerge"
+    - Revert "arm: no gmb() implementation yet"
+    - Revert "arm64: no gmb() implementation yet"
+    - Revert "UBUNTU: SAUCE: x86/kvm: Fix stuff_RSB() for 32-bit"
+    - Revert "s390/spinlock: add gmb memory barrier"
+    - Revert "powerpc: add gmb barrier"
+    - Revert "x86/cpu/AMD: Remove now unused definition of MFENCE_RDTSC feature"
+    - Revert "x86/cpu/AMD: Make the LFENCE instruction serialized"
+    - Revert "x86/svm: Add code to clear registers on VM exit"
+    - Revert "x86/svm: Add code to clobber the RSB on VM exit"
+    - Revert "KVM: x86: Add speculative control CPUID support for guests"
+    - Revert "x86/svm: Set IBPB when running a different VCPU"
+    - Revert "x86/svm: Set IBRS value on VM entry and exit"
+    - Revert "KVM: SVM: Do not intercept new speculative control MSRs"
+    - Revert "x86/microcode: Extend post microcode reload to support IBPB feature"
+    - Revert "x86/cpu/AMD: Add speculative control support for AMD"
+    - Revert "x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR"
+    - Revert "x86/entry: Use retpoline for syscall's indirect calls"
+    - Revert "x86/syscall: Clear unused extra registers on 32-bit compatible
+      syscall entrance"
+    - Revert "x86/syscall: Clear unused extra registers on syscall entrance"
+    - Revert "x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb
+      control"
+    - Revert "x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature"
+    - Revert "x86/kvm: Pad RSB on VM transition"
+    - Revert "x86/kvm: Toggle IBRS on VM entry and exit"
+    - Revert "x86/kvm: Set IBPB when switching VM"
+    - Revert "x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm"
+    - Revert "x86/entry: Stuff RSB for entry to kernel for non-SMEP platform"
+    - Revert "x86/mm: Only set IBPB when the new thread cannot ptrace current
+      thread"
+    - Revert "x86/mm: Set IBPB upon context switch"
+    - Revert "x86/idle: Disable IBRS when offlining cpu and re-enable on wakeup"
+    - Revert "x86/idle: Disable IBRS entering idle and enable it on wakeup"
+    - Revert "x86/enter: Use IBRS on syscall and interrupts"
+    - Revert "x86/enter: MACROS to set/clear IBRS and set IBPB"
+    - Revert "x86/feature: Report presence of IBPB and IBRS control"
+    - Revert "x86/feature: Enable the x86 feature to control Speculation"
+    - Revert "udf: prevent speculative execution"
+    - Revert "net: mpls: prevent speculative execution"
+    - Revert "fs: prevent speculative execution"
+    - Revert "ipv6: prevent speculative execution"
+    - Revert "userns: prevent speculative execution"
+    - Revert "Thermal/int340x: prevent speculative execution"
+    - Revert "qla2xxx: prevent speculative execution"
+    - Revert "carl9170: prevent speculative execution"
+    - Revert "uvcvideo: prevent speculative execution"
+    - Revert "x86, bpf, jit: prevent speculative execution when JIT is enabled"
+    - Revert "bpf: prevent speculative execution in eBPF interpreter"
+
+  * CVE-2017-17712
+    - net: ipv4: fix for a race condition in raw_sendmsg
+
+  * upload urgency should be medium by default (LP: #1745338)
+    - [Packaging] update urgency to medium by default
+
+  * CVE-CVE-2017-12190
+    - more bio_map_user_iov() leak fixes
+
+  * CVE-2015-8952
+    - mbcache2: reimplement mbcache
+    - ext2: convert to mbcache2
+    - ext4: convert to mbcache2
+    - mbcache2: limit cache size
+    - mbcache2: Use referenced bit instead of LRU
+    - ext4: kill ext4_mballoc_ready
+    - ext4: shortcut setting of xattr to the same value
+    - mbcache: remove mbcache
+    - mbcache2: rename to mbcache
+    - mbcache: get rid of _e_hash_list_head
+    - mbcache: add reusable flag to cache entries
+
+  * CVE-2017-15115
+    - sctp: do not peel off an assoc from one netns to another one
+
+  * CVE-2017-8824
+    - dccp: CVE-2017-8824: use-after-free in DCCP code
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 07 Feb 2018 16:05:50 +0000
+
+linux (4.4.0-112.135) xenial; urgency=low
+
+  * linux: 4.4.0-112.135 -proposed tracker (LP: #1744244)
+
+  * CVE-2017-5715 // CVE-2017-5753
+    - x86/cpuid: Provide get_scattered_cpuid_leaf()
+    - SAUCE: Fix spec_ctrl support in KVM
+    - SAUCE: s390: improve cpu alternative handling for gmb and nobp
+    - SAUCE: s390: print messages for gmb and nobp
+    - [Config] KERNEL_NOBP=y
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 19 Jan 2018 11:03:51 +0100
+
+linux (4.4.0-111.134) xenial; urgency=low
+
+  * linux: 4.4.0-111.134 -proposed tracker (LP: #1743362)
+
+  * Do not duplicate changelog entries assigned to more than one bug or CVE
+    (LP: #1743383)
+    - [Packaging] git-ubuntu-log -- handle multiple bugs/cves better
+
+  * CVE-2017-5715 // CVE-2017-5753
+    - SAUCE: x86/microcode: Extend post microcode reload to support IBPB feature
+      -- repair missmerge
+    - Revert "x86/svm: Add code to clear registers on VM exit"
+    - kvm: vmx: Scrub hardware GPRs at VM-exit
+
+  * CVE-2017-5754
+    - SAUCE: powerpc: use sync instead of hwsync mnemonic
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 15 Jan 2018 15:05:02 +0100
+
+linux (4.4.0-110.133) xenial; urgency=low
+
+  * linux: 4.4.0-110.133 -proposed tracker (LP: #1742995)
+
+  * CVE-2017-5753
+    - x86/microcode/AMD: Add support for fam17h microcode loading
+    - bpf: add bpf_patch_insn_single helper
+    - bpf: prepare bpf_int_jit_compile/bpf_prog_select_runtime apis
+    - bpf: add generic constant blinding for use in jits
+    - locking/barriers: introduce new memory barrier gmb()
+    - bpf: prevent speculative execution in eBPF interpreter
+    - x86, bpf, jit: prevent speculative execution when JIT is enabled
+    - uvcvideo: prevent speculative execution
+    - carl9170: prevent speculative execution
+    - qla2xxx: prevent speculative execution
+    - Thermal/int340x: prevent speculative execution
+    - userns: prevent speculative execution
+    - ipv6: prevent speculative execution
+    - fs: prevent speculative execution
+    - net: mpls: prevent speculative execution
+    - udf: prevent speculative execution
+    - x86/feature: Enable the x86 feature to control Speculation
+    - x86/feature: Report presence of IBPB and IBRS control
+    - x86/enter: MACROS to set/clear IBRS and set IBPB
+    - x86/enter: Use IBRS on syscall and interrupts
+    - x86/idle: Disable IBRS entering idle and enable it on wakeup
+    - x86/idle: Disable IBRS when offlining cpu and re-enable on wakeup
+    - x86/mm: Set IBPB upon context switch
+    - x86/mm: Only set IBPB when the new thread cannot ptrace current thread
+    - x86/entry: Stuff RSB for entry to kernel for non-SMEP platform
+    - x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm
+    - x86/kvm: Set IBPB when switching VM
+    - x86/kvm: Toggle IBRS on VM entry and exit
+    - x86/kvm: Pad RSB on VM transition
+    - x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature
+    - x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb control
+    - x86/syscall: Clear unused extra registers on syscall entrance
+    - x86/syscall: Clear unused extra registers on 32-bit compatible syscall
+      entrance
+    - x86/entry: Use retpoline for syscall's indirect calls
+    - x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR
+    - x86/cpu/AMD: Add speculative control support for AMD
+    - x86/microcode: Extend post microcode reload to support IBPB feature
+    - KVM: SVM: Do not intercept new speculative control MSRs
+    - x86/svm: Set IBRS value on VM entry and exit
+    - x86/svm: Set IBPB when running a different VCPU
+    - KVM: x86: Add speculative control CPUID support for guests
+    - x86/svm: Add code to clobber the RSB on VM exit
+    - x86/svm: Add code to clear registers on VM exit
+    - x86/cpu/AMD: Make the LFENCE instruction serialized
+    - x86/cpu/AMD: Remove now unused definition of MFENCE_RDTSC feature
+    - powerpc: add gmb barrier
+    - s390/spinlock: add gmb memory barrier
+    - SAUCE: x86/kvm: Fix stuff_RSB() for 32-bit
+    - arm64: no gmb() implementation yet
+    - arm: no gmb() implementation yet
+
+  * CVE-2017-5715
+    - x86/microcode/AMD: Add support for fam17h microcode loading
+    - bpf: add bpf_patch_insn_single helper
+    - bpf: prepare bpf_int_jit_compile/bpf_prog_select_runtime apis
+    - bpf: add generic constant blinding for use in jits
+    - locking/barriers: introduce new memory barrier gmb()
+    - bpf: prevent speculative execution in eBPF interpreter
+    - x86, bpf, jit: prevent speculative execution when JIT is enabled
+    - uvcvideo: prevent speculative execution
+    - carl9170: prevent speculative execution
+    - qla2xxx: prevent speculative execution
+    - Thermal/int340x: prevent speculative execution
+    - userns: prevent speculative execution
+    - ipv6: prevent speculative execution
+    - fs: prevent speculative execution
+    - net: mpls: prevent speculative execution
+    - udf: prevent speculative execution
+    - x86/feature: Enable the x86 feature to control Speculation
+    - x86/feature: Report presence of IBPB and IBRS control
+    - x86/enter: MACROS to set/clear IBRS and set IBPB
+    - x86/enter: Use IBRS on syscall and interrupts
+    - x86/idle: Disable IBRS entering idle and enable it on wakeup
+    - x86/idle: Disable IBRS when offlining cpu and re-enable on wakeup
+    - x86/mm: Set IBPB upon context switch
+    - x86/mm: Only set IBPB when the new thread cannot ptrace current thread
+    - x86/entry: Stuff RSB for entry to kernel for non-SMEP platform
+    - x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm
+    - x86/kvm: Set IBPB when switching VM
+    - x86/kvm: Toggle IBRS on VM entry and exit
+    - x86/kvm: Pad RSB on VM transition
+    - x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature
+    - x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb control
+    - x86/syscall: Clear unused extra registers on syscall entrance
+    - x86/syscall: Clear unused extra registers on 32-bit compatible syscall
+      entrance
+    - x86/entry: Use retpoline for syscall's indirect calls
+    - x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR
+    - x86/cpu/AMD: Add speculative control support for AMD
+    - x86/microcode: Extend post microcode reload to support IBPB feature
+    - KVM: SVM: Do not intercept new speculative control MSRs
+    - x86/svm: Set IBRS value on VM entry and exit
+    - x86/svm: Set IBPB when running a different VCPU
+    - KVM: x86: Add speculative control CPUID support for guests
+    - x86/svm: Add code to clobber the RSB on VM exit
+    - x86/svm: Add code to clear registers on VM exit
+    - x86/cpu/AMD: Make the LFENCE instruction serialized
+    - x86/cpu/AMD: Remove now unused definition of MFENCE_RDTSC feature
+    - powerpc: add gmb barrier
+    - s390/spinlock: add gmb memory barrier
+    - SAUCE: x86/kvm: Fix stuff_RSB() for 32-bit
+    - arm64: no gmb() implementation yet
+    - arm: no gmb() implementation yet
+
+  * powerpc: flush L1D on return to use (LP: #1742772)
+    - SAUCE: powerpc: Secure memory rfi flush
+    - SAUCE: rfi-flush: Make DEBUG_RFI a CONFIG option
+    - SAUCE: rfi-flush: Add HRFI_TO_UNKNOWN and use it in denorm
+    - SAUCE: Fixup rfid in kvmppc_skip_Hinterrupt should be hrfid
+    - SAUCE: rfi-flush: kvmppc_skip_(H)interrupt returns to host
+    - SAUCE: KVM: Revert the implementation of H_GET_CPU_CHARACTERISTICS
+    - SAUCE: rfi-flush: Implement congruence-first fallback flush
+    - SAUCE: rfi-flush: Make l1d_flush_type bit flags
+    - SAUCE: rfi-flush: Push the instruction selection down to the patching
+      routine
+    - SAUCE: rfi-flush: Expand the RFI section to two nop slots
+    - SAUCE: rfi-flush: Support more than one flush type at once
+    - SAUCE: rfi-flush: Allow HV to advertise multiple flush types
+    - SAUCE: rfi-flush: Add speculation barrier before ori 30,30,0 flush
+    - SAUCE: powerpc/asm: Allow including ppc_asm.h in asm files
+    - SAUCE: Remove setup.h include file otherwise compilation complains about
+      missing header file.
+    - SAUCE: Fix compilation errors for arch/powerpc/lib/feature-fixups.c
+    - SAUCE: rfi-flush: Add barriers to the fallback L1D flushing
+    - SAUCE: rfi-flush: Rework powernv logic to be more cautious
+    - SAUCE: rfi-flush: Rework pseries logic to be more cautious
+    - SAUCE: rfi-flush: Fix the fallback flush to actually activate
+    - SAUCE: rfi-flush: Fix HRFI_TO_UNKNOWN
+    - SAUCE: rfi-flush: Refactor the macros so the nops are defined once
+    - SAUCE: rfi-flush: Add no_rfi_flush and nopti comandline options
+    - SAUCE: rfi-flush: Use rfi-flush in printks
+    - SAUCE: rfi-flush: Fallback flush add load dependency
+    - SAUCE: rfi-flush: Fix the 32-bit KVM build
+    - SAUCE: rfi-flush: Fix some RFI conversions in the KVM code
+    - SAUCE: UBUNTU: [Config] Disable CONFIG_PPC_DEBUG_RFI
+
+  * s390: add ppa to kernel entry/exit (LP: #1742771)
+    - s390: introduce CPU alternatives
+    - s390: add ppa to kernel entry / exit
+
+  * CVE-2017-5754
+    - x86/tlb: Drop the _GPL from the cpu_tlbstate export
+    - Map the vsyscall page with _PAGE_USER
+    - s390: introduce CPU alternatives
+    - s390: add ppa to kernel entry / exit
+    - SAUCE: powerpc: Secure memory rfi flush
+    - SAUCE: rfi-flush: Make DEBUG_RFI a CONFIG option
+    - SAUCE: rfi-flush: Add HRFI_TO_UNKNOWN and use it in denorm
+    - SAUCE: Fixup rfid in kvmppc_skip_Hinterrupt should be hrfid
+    - SAUCE: rfi-flush: kvmppc_skip_(H)interrupt returns to host
+    - SAUCE: KVM: Revert the implementation of H_GET_CPU_CHARACTERISTICS
+    - SAUCE: rfi-flush: Implement congruence-first fallback flush
+    - SAUCE: rfi-flush: Make l1d_flush_type bit flags
+    - SAUCE: rfi-flush: Push the instruction selection down to the patching
+      routine
+    - SAUCE: rfi-flush: Expand the RFI section to two nop slots
+    - SAUCE: rfi-flush: Support more than one flush type at once
+    - SAUCE: rfi-flush: Allow HV to advertise multiple flush types
+    - SAUCE: rfi-flush: Add speculation barrier before ori 30,30,0 flush
+    - SAUCE: powerpc/asm: Allow including ppc_asm.h in asm files
+    - SAUCE: Remove setup.h include file otherwise compilation complains about
+      missing header file.
+    - SAUCE: Fix compilation errors for arch/powerpc/lib/feature-fixups.c
+    - SAUCE: rfi-flush: Add barriers to the fallback L1D flushing
+    - SAUCE: rfi-flush: Rework powernv logic to be more cautious
+    - SAUCE: rfi-flush: Rework pseries logic to be more cautious
+    - SAUCE: rfi-flush: Fix the fallback flush to actually activate
+    - SAUCE: rfi-flush: Fix HRFI_TO_UNKNOWN
+    - SAUCE: rfi-flush: Refactor the macros so the nops are defined once
+    - SAUCE: rfi-flush: Add no_rfi_flush and nopti comandline options
+    - SAUCE: rfi-flush: Use rfi-flush in printks
+    - SAUCE: rfi-flush: Fallback flush add load dependency
+    - SAUCE: rfi-flush: Fix the 32-bit KVM build
+    - SAUCE: rfi-flush: Fix some RFI conversions in the KVM code
+    - SAUCE: UBUNTU: [Config] Disable CONFIG_PPC_DEBUG_RFI
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Fri, 12 Jan 2018 14:47:54 -0200
+
+linux (4.4.0-109.132) xenial; urgency=low
+
+  * linux: 4.4.0-109.132 -proposed tracker (LP: #1742252)
+
+  * Kernel trace with xenial 4.4  (4.4.0-108.131, Candidate kernels for PTI fix)
+    (LP: #1741934)
+    - SAUCE: kaiser: fix perf crashes - fix to original commit
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Tue, 09 Jan 2018 15:56:26 -0200
+
+linux (4.4.0-108.131) xenial; urgency=low
+
+  * linux: 4.4.0-108.131 -proposed tracker (LP: #1741727)
+
+  * CVE-2017-5754
+    - x86/mm: Disable PCID on 32-bit kernels
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Sun, 07 Jan 2018 11:46:05 -0200
+
+linux (4.4.0-107.130) xenial; urgency=low
+
+  * linux: 4.4.0-107.130 -proposed tracker (LP: #1741643)
+
+  * CVE-2017-5754
+    - Revert "UBUNTU: SAUCE: arch/x86/entry/vdso: temporarily disable vdso"
+    - KPTI: Report when enabled
+    - x86, vdso, pvclock: Simplify and speed up the vdso pvclock reader
+    - x86/vdso: Get pvclock data from the vvar VMA instead of the fixmap
+    - x86/kasan: Clear kasan_zero_page after TLB flush
+    - kaiser: Set _PAGE_NX only if supported
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Sat, 06 Jan 2018 17:13:03 +0100
+
+linux (4.4.0-106.129) xenial; urgency=low
+
+  * linux: 4.4.0-106.129 -proposed tracker (LP: #1741528)
+
+  * CVE-2017-5754
+    - KAISER: Kernel Address Isolation
+    - kaiser: merged update
+    - kaiser: do not set _PAGE_NX on pgd_none
+    - kaiser: stack map PAGE_SIZE at THREAD_SIZE-PAGE_SIZE
+    - kaiser: fix build and FIXME in alloc_ldt_struct()
+    - kaiser: KAISER depends on SMP
+    - kaiser: fix regs to do_nmi() ifndef CONFIG_KAISER
+    - kaiser: fix perf crashes
+    - kaiser: ENOMEM if kaiser_pagetable_walk() NULL
+    - kaiser: tidied up asm/kaiser.h somewhat
+    - kaiser: tidied up kaiser_add/remove_mapping slightly
+    - kaiser: kaiser_remove_mapping() move along the pgd
+    - kaiser: cleanups while trying for gold link
+    - kaiser: name that 0x1000 KAISER_SHADOW_PGD_OFFSET
+    - kaiser: delete KAISER_REAL_SWITCH option
+    - kaiser: vmstat show NR_KAISERTABLE as nr_overhead
+    - x86/mm: Enable CR4.PCIDE on supported systems
+    - x86/mm: Build arch/x86/mm/tlb.c even on !SMP
+    - x86/mm, sched/core: Uninline switch_mm()
+    - x86/mm: Add INVPCID helpers
+    - x86/mm: If INVPCID is available, use it to flush global mappings
+    - kaiser: enhanced by kernel and user PCIDs
+    - kaiser: load_new_mm_cr3() let SWITCH_USER_CR3 flush user
+    - kaiser: PCID 0 for kernel and 128 for user
+    - kaiser: x86_cr3_pcid_noflush and x86_cr3_pcid_user
+    - kaiser: paranoid_entry pass cr3 need to paranoid_exit
+    - kaiser: _pgd_alloc() without __GFP_REPEAT to avoid stalls
+    - kaiser: fix unlikely error in alloc_ldt_struct()
+    - kaiser: add "nokaiser" boot option, using ALTERNATIVE
+    - x86/kaiser: Rename and simplify X86_FEATURE_KAISER handling
+    - x86/boot: Add early cmdline parsing for options with arguments
+    - x86/kaiser: Check boottime cmdline params
+    - kaiser: use ALTERNATIVE instead of x86_cr3_pcid_noflush
+    - kaiser: drop is_atomic arg to kaiser_pagetable_walk()
+    - kaiser: asm/tlbflush.h handle noPGE at lower level
+    - kaiser: kaiser_flush_tlb_on_return_to_user() check PCID
+    - x86/paravirt: Dont patch flush_tlb_single
+    - x86/kaiser: Reenable PARAVIRT
+    - kaiser: disabled on Xen PV
+    - x86/kaiser: Move feature detection up
+    - kvm: x86: fix RSM when PCID is non-zero
+    - SAUCE: arch/x86/entry/vdso: temporarily disable vdso
+    - [Config]: CONFIG_KAISER=y
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 05 Jan 2018 19:53:41 +0100
+
+linux (4.4.0-104.127) xenial; urgency=low
+
+  * linux: 4.4.0-104.127 -proposed tracker (LP: #1737511)
+
+  * upgrading linux-image package to 4.4.0-103.126 breaks Ceph network file
+    system connection (LP: #1737033)
+    - Revert "libceph: MOSDOpReply v7 encoding"
+    - Revert "libceph: advertise support for TUNABLES5"
+    - Revert "crush: decode and initialize chooseleaf_stable"
+    - Revert "crush: add chooseleaf_stable tunable"
+    - Revert "crush: ensure take bucket value is valid"
+    - Revert "crush: ensure bucket id is valid before indexing buckets array"
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 11 Dec 2017 12:20:36 +0100
+
+linux (4.4.0-103.126) xenial; urgency=low
+
+  * linux: 4.4.0-103.126 -proposed tracker (LP: #1736181)
+
+  * CVE-2017-1000405
+    - mm, thp: Do not make page table dirty unconditionally in touch_p[mu]d()
+
+  * CVE-2017-16939
+    - netlink: add a start callback for starting a netlink dump
+    - ipsec: Fix aborted xfrm policy dump crash
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 04 Dec 2017 16:50:53 +0100
+
+linux (4.4.0-102.125) xenial; urgency=low
+
+  * linux: 4.4.0-102.125 -proposed tracker (LP: #1733541)
+
+  * tar -x sometimes fails on overlayfs (LP: #1728489)
+    - ovl: check if all layers are on the same fs
+    - ovl: persistent inode number for directories
+
+  * NVMe timeout is too short (LP: #1729119)
+    - nvme: update timeout module parameter type
+
+  * Set PANIC_TIMEOUT=10 on Power Systems (LP: #1730660)
+    - [Config]: Set PANIC_TIMEOUT=10 on ppc64el
+
+  * Cannot pair BLE remote devices when using combo BT SoC (LP: #1731467)
+    - Bluetooth: increase timeout for le auto connections
+
+  * CIFS errors on 4.4.0-98, but not on 4.4.0-97 with same config (LP: #1729337)
+    - SMB3: Validate negotiate request must always be signed
+
+  * Plantronics P610 does not support sample rate reading (LP: #1719853)
+    - ALSA: usb-audio: Add sample rate quirk for Plantronics P610
+
+  * Invalid btree pointer causes the kernel NULL pointer dereference
+    (LP: #1729256)
+    - xfs: reinit btree pointer on attr tree inactivation walk
+
+  * Samba mount/umount in docker container triggers kernel Oops (LP: #1729637)
+    - ipv6: only call ip6_route_dev_notify() once for NETDEV_UNREGISTER
+    - ipv6: fix NULL dereference in ip6_route_dev_notify()
+
+  * [kernel] tty/hvc: Use opal irqchip interface if available (LP: #1728098)
+    - tty/hvc: Use opal irqchip interface if available
+
+  * Device hotplugging with MPT SAS cannot work for VMWare ESXi (LP: #1730852)
+    - scsi: mptsas: Fixup device hotplug for VMWare ESXi
+
+  * NMI watchdog: BUG: soft lockup on Guest upon boot (KVM) (LP: #1727331)
+    - KVM: PPC: Book3S: Treat VTB as a per-subcore register, not per-thread
+
+  * Attempt to map rbd image from ceph jewel/luminous hangs (LP: #1728739)
+    - crush: ensure bucket id is valid before indexing buckets array
+    - crush: ensure take bucket value is valid
+    - crush: add chooseleaf_stable tunable
+    - crush: decode and initialize chooseleaf_stable
+    - libceph: advertise support for TUNABLES5
+    - libceph: MOSDOpReply v7 encoding
+
+  * Xenial update to 4.4.98 stable release (LP: #1732698)
+    - adv7604: Initialize drive strength to default when using DT
+    - video: fbdev: pmag-ba-fb: Remove bad `__init' annotation
+    - PCI: mvebu: Handle changes to the bridge windows while enabled
+    - xen/netback: set default upper limit of tx/rx queues to 8
+    - drm: drm_minor_register(): Clean up debugfs on failure
+    - KVM: PPC: Book 3S: XICS: correct the real mode ICP rejecting counter
+    - iommu/arm-smmu-v3: Clear prior settings when updating STEs
+    - powerpc/corenet: explicitly disable the SDHC controller on kmcoge4
+    - ARM: omap2plus_defconfig: Fix probe errors on UARTs 5 and 6
+    - crypto: vmx - disable preemption to enable vsx in aes_ctr.c
+    - iio: trigger: free trigger resource correctly
+    - phy: increase size of MII_BUS_ID_SIZE and bus_id
+    - serial: sh-sci: Fix register offsets for the IRDA serial port
+    - usb: hcd: initialize hcd->flags to 0 when rm hcd
+    - netfilter: nft_meta: deal with PACKET_LOOPBACK in netdev family
+    - IPsec: do not ignore crypto err in ah4 input
+    - Input: mpr121 - handle multiple bits change of status register
+    - Input: mpr121 - set missing event capability
+    - IB/ipoib: Change list_del to list_del_init in the tx object
+    - s390/qeth: issue STARTLAN as first IPA command
+    - (config) Add NET_DSA=n
+    - net: dsa: select NET_SWITCHDEV
+    - platform/x86: hp-wmi: Fix detection for dock and tablet mode
+    - cdc_ncm: Set NTB format again after altsetting switch for Huawei devices
+    - KEYS: trusted: sanitize all key material
+    - KEYS: trusted: fix writing past end of buffer in trusted_read()
+    - platform/x86: hp-wmi: Fix error value for hp_wmi_tablet_state
+    - platform/x86: hp-wmi: Do not shadow error values
+    - x86/uaccess, sched/preempt: Verify access_ok() context
+    - workqueue: Fix NULL pointer dereference
+    - crypto: x86/sha1-mb - fix panic due to unaligned access
+    - KEYS: fix NULL pointer dereference during ASN.1 parsing [ver #2]
+    - ARM: 8720/1: ensure dump_instr() checks addr_limit
+    - ALSA: seq: Fix OSS sysex delivery in OSS emulation
+    - ALSA: seq: Avoid invalid lockdep class warning
+    - MIPS: microMIPS: Fix incorrect mask in insn_table_MM
+    - MIPS: Fix CM region target definitions
+    - MIPS: SMP: Use a completion event to signal CPU up
+    - MIPS: Fix race on setting and getting cpu_online_mask
+    - MIPS: SMP: Fix deadlock & online race
+    - test: firmware_class: report errors properly on failure
+    - selftests: firmware: add empty string and async tests
+    - selftests: firmware: send expected errors to /dev/null
+    - tools: firmware: check for distro fallback udev cancel rule
+    - MIPS: AR7: Defer registration of GPIO
+    - MIPS: AR7: Ensure that serial ports are properly set up
+    - Input: elan_i2c - add ELAN060C to the ACPI table
+    - drm/vmwgfx: Fix Ubuntu 17.10 Wayland black screen issue
+    - rbd: use GFP_NOIO for parent stat and data requests
+    - can: sun4i: handle overrun in RX FIFO
+    - can: c_can: don't indicate triple sampling support for D_CAN
+    - x86/oprofile/ppro: Do not use __this_cpu*() in preemptible context
+    - PKCS#7: fix unitialized boolean 'want'
+    - Linux 4.4.98
+
+  * ELANTECH Touchpad is not detected in 'Lenovo Ideapad 320 14AST' after fresh
+    install (LP: #1727544)
+    - Input: elan_i2c - add ELAN060C to the ACPI table
+
+  * Xenial update to 4.4.97 stable release (LP: #1731915)
+    - ALSA: timer: Add missing mutex lock for compat ioctls
+    - ALSA: seq: Fix nested rwsem annotation for lockdep splat
+    - cifs: check MaxPathNameComponentLength != 0 before using it
+    - KEYS: return full count in keyring_read() if buffer is too small
+    - KEYS: fix out-of-bounds read during ASN.1 parsing
+    - ASoC: adau17x1: Workaround for noise bug in ADC
+    - arm64: ensure __dump_instr() checks addr_limit
+    - ARM: dts: mvebu: pl310-cache disable double-linefill
+    - ARM: 8715/1: add a private asm/unaligned.h
+    - ocfs2: fstrim: Fix start offset of first cluster group during fstrim
+    - perf tools: Fix build failure on perl script context
+    - drm/msm: Fix potential buffer overflow issue
+    - drm/msm: fix an integer overflow test
+    - tracing/samples: Fix creation and deletion of simple_thread_fn creation
+    - Fix tracing sample code warning.
+    - PM / wakeirq: report a wakeup_event on dedicated wekup irq
+    - mmc: s3cmci: include linux/interrupt.h for tasklet_struct
+    - ARM: pxa: Don't rely on public mmc header to include leds.h
+    - mfd: ab8500-sysctrl: Handle probe deferral
+    - mfd: axp20x: Fix axp288 PEK_DBR and PEK_DBF irqs being swapped
+    - staging: rtl8712u: Fix endian settings for structs describing network
+      packets
+    - ext4: fix stripe-unaligned allocations
+    - ext4: do not use stripe_width if it is not set
+    - i2c: riic: correctly finish transfers
+    - drm/amdgpu: when dpm disabled, also need to stop/start vce.
+    - perf tools: Only increase index if perf_evsel__new_idx() succeeds
+    - cx231xx: Fix I2C on Internal Master 3 Bus
+    - xen/manage: correct return value check on xenbus_scanf()
+    - scsi: aacraid: Process Error for response I/O
+    - platform/x86: intel_mid_thermal: Fix module autoload
+    - staging: lustre: llite: don't invoke direct_IO for the EOF case
+    - staging: lustre: hsm: stack overrun in hai_dump_data_field
+    - staging: lustre: ptlrpc: skip lock if export failed
+    - exynos4-is: fimc-is: Unmap region obtained by of_iomap()
+    - mei: return error on notification request to a disconnected client
+    - s390/dasd: check for device error pointer within state change interrupts
+    - bt8xx: fix memory leak
+    - xen: don't print error message in case of missing Xenstore entry
+    - staging: r8712u: Fix Sparse warning in rtl871x_xmit.c
+    - Linux 4.4.97
+
+  * Xenial update to 4.4.96 stable release (LP: #1731882)
+    - workqueue: replace pool->manager_arb mutex with a flag
+    - ALSA: hda/realtek - Add support for ALC236/ALC3204
+    - ALSA: hda - fix headset mic problem for Dell machines with alc236
+    - ceph: unlock dangling spinlock in try_flush_caps()
+    - usb: xhci: Handle error condition in xhci_stop_device()
+    - spi: uapi: spidev: add missing ioctl header
+    - fuse: fix READDIRPLUS skipping an entry
+    - xen/gntdev: avoid out of bounds access in case of partial gntdev_mmap()
+    - Input: elan_i2c - add ELAN0611 to the ACPI table
+    - Input: gtco - fix potential out-of-bound access
+    - assoc_array: Fix a buggy node-splitting case
+    - scsi: zfcp: fix erp_action use-before-initialize in REC action trace
+    - scsi: sg: Re-fix off by one in sg_fill_request_table()
+    - can: sun4i: fix loopback mode
+    - can: kvaser_usb: Correct return value in printout
+    - can: kvaser_usb: Ignore CMD_FLUSH_QUEUE_REPLY messages
+    - regulator: fan53555: fix I2C device ids
+    - x86/microcode/intel: Disable late loading on model 79
+    - ecryptfs: fix dereference of NULL user_key_payload
+    - Revert "drm: bridge: add DT bindings for TI ths8135"
+    - Linux 4.4.96
+
+  * Touchpad not detected - Lenovo ideapad 320-15IKB (LP: #1723736)
+    - Input: elan_i2c - add ELAN0611 to the ACPI table
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 21 Nov 2017 15:37:52 +0100
+
+linux (4.4.0-101.124) xenial; urgency=low
+
+  * linux: 4.4.0-101.124 -proposed tracker (LP: #1731264)
+
+  * s390/mm: fix write access check in gup_huge_pmd() (LP: #1730596)
+    - s390/mm: fix write access check in gup_huge_pmd()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 10 Nov 2017 08:24:10 -0200
+
+linux (4.4.0-100.123) xenial; urgency=low
+
+  * linux: 4.4.0-100.123 -proposed tracker (LP: #1729273)
+
+  * Xenial update to 4.4.95 stable release (LP: #1729107)
+    - USB: devio: Revert "USB: devio: Don't corrupt user memory"
+    - USB: core: fix out-of-bounds access bug in usb_get_bos_descriptor()
+    - USB: serial: metro-usb: add MS7820 device id
+    - usb: cdc_acm: Add quirk for Elatec TWN3
+    - usb: quirks: add quirk for WORLDE MINI MIDI keyboard
+    - usb: hub: Allow reset retry for USB2 devices on connect bounce
+    - ALSA: usb-audio: Add native DSD support for Pro-Ject Pre Box S2 Digital
+    - can: gs_usb: fix busy loop if no more TX context is available
+    - usb: musb: sunxi: Explicitly release USB PHY on exit
+    - usb: musb: Check for host-mode using is_host_active() on reset interrupt
+    - can: esd_usb2: Fix can_dlc value for received RTR, frames
+    - drm/nouveau/bsp/g92: disable by default
+    - drm/nouveau/mmu: flush tlbs before deleting page tables
+    - ALSA: seq: Enable 'use' locking in all configurations
+    - ALSA: hda: Remove superfluous '-' added by printk conversion
+    - i2c: ismt: Separate I2C block read from SMBus block read
+    - brcmsmac: make some local variables 'static const' to reduce stack size
+    - bus: mbus: fix window size calculation for 4GB windows
+    - clockevents/drivers/cs5535: Improve resilience to spurious interrupts
+    - rtlwifi: rtl8821ae: Fix connection lost problem
+    - KEYS: encrypted: fix dereference of NULL user_key_payload
+    - lib/digsig: fix dereference of NULL user_key_payload
+    - KEYS: don't let add_key() update an uninstantiated key
+    - pkcs7: Prevent NULL pointer dereference, since sinfo is not always set.
+    - parisc: Avoid trashing sr2 and sr3 in LWS code
+    - parisc: Fix double-word compare and exchange in LWS code on 32-bit kernels
+    - sched/autogroup: Fix autogroup_move_group() to never skip sched_move_task()
+    - f2fs crypto: replace some BUG_ON()'s with error checks
+    - f2fs crypto: add missing locking for keyring_key access
+    - fscrypt: fix dereference of NULL user_key_payload
+    - KEYS: Fix race between updating and finding a negative key
+    - fscrypto: require write access to mount to set encryption policy
+    - FS-Cache: fix dereference of NULL user_key_payload
+    - Linux 4.4.95
+
+  * Xenial update to 4.4.94 stable release (LP: #1729105)
+    - percpu: make this_cpu_generic_read() atomic w.r.t. interrupts
+    - drm/dp/mst: save vcpi with payloads
+    - MIPS: Fix minimum alignment requirement of IRQ stack
+    - sctp: potential read out of bounds in sctp_ulpevent_type_enabled()
+    - bpf/verifier: reject BPF_ALU64|BPF_END
+    - udpv6: Fix the checksum computation when HW checksum does not apply
+    - ip6_gre: skb_push ipv6hdr before packing the header in ip6gre_header
+    - net: emac: Fix napi poll list corruption
+    - packet: hold bind lock when rebinding to fanout hook
+    - bpf: one perf event close won't free bpf program attached by another perf
+      event
+    - isdn/i4l: fetch the ppp_write buffer in one shot
+    - vti: fix use after free in vti_tunnel_xmit/vti6_tnl_xmit
+    - l2tp: Avoid schedule while atomic in exit_net
+    - l2tp: fix race condition in l2tp_tunnel_delete
+    - tun: bail out from tun_get_user() if the skb is empty
+    - packet: in packet_do_bind, test fanout with bind_lock held
+    - packet: only test po->has_vnet_hdr once in packet_snd
+    - net: Set sk_prot_creator when cloning sockets to the right proto
+    - tipc: use only positive error codes in messages
+    - Revert "bsg-lib: don't free job in bsg_prepare_job"
+    - locking/lockdep: Add nest_lock integrity test
+    - watchdog: kempld: fix gcc-4.3 build
+    - irqchip/crossbar: Fix incorrect type of local variables
+    - mac80211_hwsim: check HWSIM_ATTR_RADIO_NAME length
+    - mac80211: fix power saving clients handling in iwlwifi
+    - net/mlx4_en: fix overflow in mlx4_en_init_timestamp()
+    - netfilter: nf_ct_expect: Change __nf_ct_expect_check() return value.
+    - iio: adc: xilinx: Fix error handling
+    - Btrfs: send, fix failure to rename top level inode due to name collision
+    - f2fs: do not wait for writeback in write_begin
+    - md/linear: shutup lockdep warnning
+    - sparc64: Migrate hvcons irq to panicked cpu
+    - net/mlx4_core: Fix VF overwrite of module param which disables DMFS on new
+      probed PFs
+    - crypto: xts - Add ECB dependency
+    - ocfs2/dlmglue: prepare tracking logic to avoid recursive cluster lock
+    - slub: do not merge cache if slub_debug contains a never-merge flag
+    - scsi: scsi_dh_emc: return success in clariion_std_inquiry()
+    - net: mvpp2: release reference to txq_cpu[] entry after unmapping
+    - i2c: at91: ensure state is restored after suspending
+    - ceph: clean up unsafe d_parent accesses in build_dentry_path
+    - uapi: fix linux/rds.h userspace compilation errors
+    - uapi: fix linux/mroute6.h userspace compilation errors
+    - target/iscsi: Fix unsolicited data seq_end_offset calculation
+    - nfsd/callback: Cleanup callback cred on shutdown
+    - cpufreq: CPPC: add ACPI_PROCESSOR dependency
+    - Revert "tty: goldfish: Fix a parameter of a call to free_irq"
+    - Linux 4.4.94
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 01 Nov 2017 16:54:28 -0200
+
+linux (4.4.0-99.122) xenial; urgency=low
+
+  * linux: 4.4.0-99.122 -proposed tracker (LP: #1728945)
+
+  * Remove vmbus-rdma driver from Xenial kernel (LP: #1721538)
+    - SAUCE: remove hv_network_direct driver
+    - [Config]: Remove hv_network_direct driver
+
+  * usb 3-1: 2:1: cannot get freq at ep 0x1 (LP: #1708499)
+    - ALSA: usb-audio: Add sample rate quirk for Plantronics C310/C520-M
+
+  * Plantronics Blackwire C520-M - Cannot get freq at ep 0x1, 0x81
+    (LP: #1709282)
+    - ALSA: usb-audio: Add sample rate quirk for Plantronics C310/C520-M
+
+  * wait-for-root fails to detect nbd root (LP: #696435)
+    - nbd: Create size change events for userspace
+
+  * Fix OpenNSL GPL bugs found by CoverityScan static analysis (LP: #1718388)
+    - SAUCE: opennsl: bcm-knet: check for null sinfo to avoid a null pointer
+      dereference
+    - SAUCE: opennsl: bcm-knet: remove redundant null checks on dev->name
+    - SAUCE: opennsl: bde: check for out-of-bounds index io.dev
+
+  * HID: multitouch: Correct ALPS PTP Stick and Touchpad devices ID
+    (LP: #1722719)
+    - Revert "HID: multitouch: Support ALPS PTP stick with pid 0x120A"
+
+  * Xenial update to 4.4.93 stable release (LP: #1724836)
+    - brcmfmac: add length check in brcmf_cfg80211_escan_handler()
+    - ext4: in ext4_seek_{hole,data}, return -ENXIO for negative offsets
+    - CIFS: Reconnect expired SMB sessions
+    - nl80211: Define policy for packet pattern attributes
+    - iwlwifi: mvm: use IWL_HCMD_NOCOPY for MCAST_FILTER_CMD
+    - rcu: Allow for page faults in NMI handlers
+    - USB: dummy-hcd: Fix deadlock caused by disconnect detection
+    - MIPS: math-emu: Remove pr_err() calls from fpu_emu()
+    - dmaengine: edma: Align the memcpy acnt array size with the transfer
+    - HID: usbhid: fix out-of-bounds bug
+    - crypto: shash - Fix zero-length shash ahash digest crash
+    - KVM: nVMX: fix guest CR4 loading when emulating L2 to L1 exit
+    - usb: renesas_usbhs: Fix DMAC sequence for receiving zero-length packet
+    - iommu/amd: Finish TLB flush in amd_iommu_unmap()
+    - ALSA: usb-audio: Kill stray URB at exiting
+    - ALSA: seq: Fix use-after-free at creating a port
+    - ALSA: seq: Fix copy_from_user() call inside lock
+    - ALSA: caiaq: Fix stray URB at probe error path
+    - ALSA: line6: Fix leftover URB at error-path during probe
+    - usb: gadget: composite: Fix use-after-free in
+      usb_composite_overwrite_options
+    - direct-io: Prevent NULL pointer access in submit_page_section
+    - fix unbalanced page refcounting in bio_map_user_iov
+    - USB: serial: ftdi_sio: add id for Cypress WICED dev board
+    - USB: serial: cp210x: add support for ELV TFD500
+    - USB: serial: option: add support for TP-Link LTE module
+    - Revert "UBUNTU: SAUCE: USB: serial: qcserial: add Dell DW5818, DW5819"
+    - USB: serial: qcserial: add Dell DW5818, DW5819
+    - USB: serial: console: fix use-after-free after failed setup
+    - x86/alternatives: Fix alt_max_short macro to really be a max()
+    - Linux 4.4.93
+
+  * NULL pointer dereference in tty_write() in kernel 4.4.0-93.116+
+    (LP: #1721065)
+    - tty: Prepare for destroying line discipline on hangup
+
+  * Xenial update to 4.4.92 stable release (LP: #1724783)
+    - usb: gadget: inode.c: fix unbalanced spin_lock in ep0_write
+    - USB: gadgetfs: Fix crash caused by inadequate synchronization
+    - USB: gadgetfs: fix copy_to_user while holding spinlock
+    - usb: gadget: udc: atmel: set vbus irqflags explicitly
+    - usb-storage: unusual_devs entry to fix write-access regression for Seagate
+      external drives
+    - usb: renesas_usbhs: fix the BCLR setting condition for non-DCP pipe
+    - usb: renesas_usbhs: fix usbhsf_fifo_clear() for RX direction
+    - ALSA: usb-audio: Check out-of-bounds access by corrupted buffer descriptor
+    - usb: pci-quirks.c: Corrected timeout values used in handshake
+    - USB: dummy-hcd: fix connection failures (wrong speed)
+    - USB: dummy-hcd: fix infinite-loop resubmission bug
+    - USB: dummy-hcd: Fix erroneous synchronization change
+    - USB: devio: Don't corrupt user memory
+    - usb: gadget: mass_storage: set msg_registered after msg registered
+    - USB: g_mass_storage: Fix deadlock when driver is unbound
+    - lsm: fix smack_inode_removexattr and xattr_getsecurity memleak
+    - ALSA: compress: Remove unused variable
+    - ALSA: usx2y: Suppress kernel warning at page allocation failures
+    - driver core: platform: Don't read past the end of "driver_override" buffer
+    - Drivers: hv: fcopy: restore correct transfer length
+    - stm class: Fix a use-after-free
+    - ftrace: Fix kmemleak in unregister_ftrace_graph
+    - HID: i2c-hid: allocate hid buffers for real worst case
+    - iwlwifi: add workaround to disable wide channels in 5GHz
+    - scsi: sd: Do not override max_sectors_kb sysfs setting
+    - USB: uas: fix bug in handling of alternate settings
+    - USB: core: harden cdc_parse_cdc_header
+    - usb: Increase quirk delay for USB devices
+    - USB: fix out-of-bounds in usb_set_configuration
+    - xhci: fix finding correct bus_state structure for USB 3.1 hosts
+    - iio: adc: twl4030: Fix an error handling path in 'twl4030_madc_probe()'
+    - iio: adc: twl4030: Disable the vusb3v1 rugulator in the error handling path
+      of 'twl4030_madc_probe()'
+    - iio: ad_sigma_delta: Implement a dedicated reset function
+    - staging: iio: ad7192: Fix - use the dedicated reset function avoiding dma
+      from stack.
+    - iio: core: Return error for failed read_reg
+    - iio: ad7793: Fix the serial interface reset
+    - iio: adc: mcp320x: Fix readout of negative voltages
+    - iio: adc: mcp320x: Fix oops on module unload
+    - uwb: properly check kthread_run return value
+    - uwb: ensure that endpoint is interrupt
+    - brcmfmac: setup passive scan if requested by user-space
+    - drm/i915/bios: ignore HDMI on port A
+    - sched/cpuset/pm: Fix cpuset vs. suspend-resume bugs
+    - ext4: fix data corruption for mmap writes
+    - ext4: Don't clear SGID when inheriting ACLs
+    - ext4: don't allow encrypted operations without keys
+    - Linux 4.4.92
+
+  * Xenial update to 4.4.91 stable release (LP: #1724772)
+    - drm_fourcc: Fix DRM_FORMAT_MOD_LINEAR #define
+    - drm: bridge: add DT bindings for TI ths8135
+    - GFS2: Fix reference to ERR_PTR in gfs2_glock_iter_next
+    - RDS: RDMA: Fix the composite message user notification
+    - ARM: dts: r8a7790: Use R-Car Gen 2 fallback binding for msiof nodes
+    - MIPS: Ensure bss section ends on a long-aligned address
+    - MIPS: ralink: Fix incorrect assignment on ralink_soc
+    - igb: re-assign hw address pointer on reset after PCI error
+    - extcon: axp288: Use vbus-valid instead of -present to determine cable
+      presence
+    - sh_eth: use correct name for ECMR_MPDE bit
+    - hwmon: (gl520sm) Fix overflows and crash seen when writing into limit
+      attributes
+    - iio: adc: axp288: Drop bogus AXP288_ADC_TS_PIN_CTRL register modifications
+    - iio: adc: hx711: Add DT binding for avia,hx711
+    - ARM: 8635/1: nommu: allow enabling REMAP_VECTORS_TO_RAM
+    - tty: goldfish: Fix a parameter of a call to free_irq
+    - IB/ipoib: Fix deadlock over vlan_mutex
+    - IB/ipoib: rtnl_unlock can not come after free_netdev
+    - IB/ipoib: Replace list_del of the neigh->list with list_del_init
+    - drm/amdkfd: fix improper return value on error
+    - USB: serial: mos7720: fix control-message error handling
+    - USB: serial: mos7840: fix control-message error handling
+    - partitions/efi: Fix integer overflow in GPT size calculation
+    - ASoC: dapm: handle probe deferrals
+    - audit: log 32-bit socketcalls
+    - usb: chipidea: vbus event may exist before starting gadget
+    - ASoC: dapm: fix some pointer error handling
+    - MIPS: Lantiq: Fix another request_mem_region() return code check
+    - net: core: Prevent from dereferencing null pointer when releasing SKB
+    - net/packet: check length in getsockopt() called with PACKET_HDRLEN
+    - team: fix memory leaks
+    - usb: plusb: Add support for PL-27A1
+    - mmc: sdio: fix alignment issue in struct sdio_func
+    - bridge: netlink: register netdevice before executing changelink
+    - netfilter: invoke synchronize_rcu after set the _hook_ to NULL
+    - MIPS: IRQ Stack: Unwind IRQ stack onto task stack
+    - exynos-gsc: Do not swap cb/cr for semi planar formats
+    - netfilter: nfnl_cthelper: fix incorrect helper->expect_class_max
+    - parisc: perf: Fix potential NULL pointer dereference
+    - iommu/io-pgtable-arm: Check for leaf entry before dereferencing it
+    - rds: ib: add error handle
+    - md/raid10: submit bio directly to replacement disk
+    - i2c: meson: fix wrong variable usage in meson_i2c_put_data
+    - xfs: remove kmem_zalloc_greedy
+    - libata: transport: Remove circular dependency at free time
+    - drivers: firmware: psci: drop duplicate const from psci_of_match
+    - IB/qib: fix false-postive maybe-uninitialized warning
+    - ARM: remove duplicate 'const' annotations'
+    - ALSA: au88x0: avoid theoretical uninitialized access
+    - ttpci: address stringop overflow warning
+    - Linux 4.4.91
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 31 Oct 2017 11:49:30 -0200
+
+linux (4.4.0-98.121) xenial; urgency=low
+
+  * linux: 4.4.0-98.121 -proposed tracker (LP: #1722299)
+
+  * Controller lockup detected on ProLiant DL380 Gen9 with P440 Controller
+    (LP: #1720359)
+    - scsi: hpsa: limit transfer length to 1MB
+
+  * [Dell Docking IE][0bda:8153] Realtek USB Ethernet leads to system hang
+    (LP: #1720977)
+    - r8152: fix the list rx_done may be used without initialization
+
+  * Add installer support for Broadcom BCM573xx network drivers. (LP: #1720466)
+    - d-i: Add bnxt_en to nic-modules.
+
+  * snapcraft.yaml: add dpkg-dev to the build deps (LP: #1718886)
+    - snapcraft.yaml: add dpkg-dev to the build deps
+
+  * Support setting I2C_TIMEOUT via ioctl for i2c-designware (LP: #1718578)
+    - i2c: designware: Use transfer timeout from ioctl I2C_TIMEOUT
+
+  * 5U84 - ses driver isn't binding right - cannot blink lights on 1 of the 2
+    5u84 (LP: #1693369)
+    - scsi_transport_sas: add function to get SAS endpoint address
+    - ses: fix discovery of SATA devices in SAS enclosures
+    - scsi: sas: provide stub implementation for scsi_is_sas_rphy
+    - scsi: ses: Fix SAS device detection in enclosure
+
+  * multipath -ll is not showing the disks which are actually multipath
+    (LP: #1718397)
+    - fs: aio: fix the increment of aio-nr and counting against aio-max-nr
+
+  * Support Dell Wireless DW5819/5818 WWAN devices (LP: #1721455)
+    - SAUCE: USB: serial: qcserial: add Dell DW5818, DW5819
+
+  * CVE-2017-10911
+    - xen-blkback: don't leak stack data via response ring
+
+  * implement 'complain mode' in seccomp for developer mode with snaps
+    (LP: #1567597)
+    - seccomp: Provide matching filter for introspection
+    - seccomp: Sysctl to display available actions
+    - seccomp: Operation for checking if an action is available
+    - seccomp: Sysctl to configure actions that are allowed to be logged
+    - seccomp: Selftest for detection of filter flag support
+    - seccomp: Action to log before allowing
+
+  * implement errno action logging in seccomp for strict mode with snaps
+    (LP: #1721676)
+    - seccomp: Provide matching filter for introspection
+    - seccomp: Sysctl to display available actions
+    - seccomp: Operation for checking if an action is available
+    - seccomp: Sysctl to configure actions that are allowed to be logged
+    - seccomp: Selftest for detection of filter flag support
+    - seccomp: Filter flag to log all actions except SECCOMP_RET_ALLOW
+
+  * [Xenial] update OpenNSL kernel modules to 6.5.10 (LP: #1721511)
+    - SAUCE: update OpenNSL kernel modules to 6.5.10
+
+  * Xenial update to 4.4.90 stable release (LP: #1721550)
+    - cifs: release auth_key.response for reconnect.
+    - mac80211: flush hw_roc_start work before cancelling the ROC
+    - KVM: PPC: Book3S: Fix race and leak in kvm_vm_ioctl_create_spapr_tce()
+    - tracing: Fix trace_pipe behavior for instance traces
+    - tracing: Erase irqsoff trace with empty write
+    - md/raid5: fix a race condition in stripe batch
+    - md/raid5: preserve STRIPE_ON_UNPLUG_LIST in break_stripe_batch_list
+    - scsi: scsi_transport_iscsi: fix the issue that iscsi_if_rx doesn't parse
+      nlmsg properly
+    - crypto: talitos - Don't provide setkey for non hmac hashing algs.
+    - crypto: talitos - fix sha224
+    - KEYS: fix writing past end of user-supplied buffer in keyring_read()
+    - KEYS: prevent creating a different user's keyrings
+    - KEYS: prevent KEYCTL_READ on negative key
+    - powerpc/pseries: Fix parent_dn reference leak in add_dt_node()
+    - Fix SMB3.1.1 guest authentication to Samba
+    - SMB: Validate negotiate (to protect against downgrade) even if signing off
+    - SMB3: Don't ignore O_SYNC/O_DSYNC and O_DIRECT flags
+    - vfs: Return -ENXIO for negative SEEK_HOLE / SEEK_DATA offsets
+    - nl80211: check for the required netlink attributes presence
+    - bsg-lib: don't free job in bsg_prepare_job
+    - seccomp: fix the usage of get/put_seccomp_filter() in seccomp_get_filter()
+    - arm64: Make sure SPsel is always set
+    - arm64: fault: Route pte translation faults via do_translation_fault
+    - KVM: VMX: Do not BUG() on out-of-bounds guest IRQ
+    - kvm: nVMX: Don't allow L2 to access the hardware CR8
+    - PCI: Fix race condition with driver_override
+    - btrfs: fix NULL pointer dereference from free_reloc_roots()
+    - btrfs: propagate error to btrfs_cmp_data_prepare caller
+    - btrfs: prevent to set invalid default subvolid
+    - x86/fpu: Don't let userspace set bogus xcomp_bv
+    - gfs2: Fix debugfs glocks dump
+    - timer/sysclt: Restrict timer migration sysctl values to 0 and 1
+    - KVM: VMX: do not change SN bit in vmx_update_pi_irte()
+    - KVM: VMX: remove WARN_ON_ONCE in kvm_vcpu_trigger_posted_interrupt
+    - cxl: Fix driver use count
+    - dmaengine: mmp-pdma: add number of requestors
+    - ARM: pxa: add the number of DMA requestor lines
+    - ARM: pxa: fix the number of DMA requestor lines
+    - KVM: VMX: use cmpxchg64
+    - video: fbdev: aty: do not leak uninitialized padding in clk to userspace
+    - swiotlb-xen: implement xen_swiotlb_dma_mmap callback
+    - fix xen_swiotlb_dma_mmap prototype
+    - Linux 4.4.90
+
+  * Xenial update to 4.4.89 stable release (LP: #1721477)
+    - ipv6: accept 64k - 1 packet length in ip6_find_1stfragopt()
+    - ipv6: add rcu grace period before freeing fib6_node
+    - ipv6: fix sparse warning on rt6i_node
+    - qlge: avoid memcpy buffer overflow
+    - Revert "net: phy: Correctly process PHY_HALTED in phy_stop_machine()"
+    - Revert "net: use lib/percpu_counter API for fragmentation mem accounting"
+    - Revert "net: fix percpu memory leaks"
+    - gianfar: Fix Tx flow control deactivation
+    - ipv6: fix memory leak with multiple tables during netns destruction
+    - ipv6: fix typo in fib6_net_exit()
+    - f2fs: check hot_data for roll-forward recovery
+    - x86/fsgsbase/64: Report FSBASE and GSBASE correctly in core dumps
+    - md/raid5: release/flush io in raid5_do_work()
+    - nfsd: Fix general protection fault in release_lock_stateid()
+    - mm: prevent double decrease of nr_reserved_highatomic
+    - tty: improve tty_insert_flip_char() fast path
+    - tty: improve tty_insert_flip_char() slow path
+    - tty: fix __tty_insert_flip_char regression
+    - Input: i8042 - add Gigabyte P57 to the keyboard reset table
+    - MIPS: math-emu: <MAX|MAXA|MIN|MINA>.<D|S>: Fix quiet NaN propagation
+    - MIPS: math-emu: <MAX|MAXA|MIN|MINA>.<D|S>: Fix cases of both inputs zero
+    - MIPS: math-emu: <MAX|MIN>.<D|S>: Fix cases of both inputs negative
+    - MIPS: math-emu: <MAXA|MINA>.<D|S>: Fix cases of input values with opposite
+      signs
+    - MIPS: math-emu: <MAXA|MINA>.<D|S>: Fix cases of both infinite inputs
+    - MIPS: math-emu: MINA.<D|S>: Fix some cases of infinity and zero inputs
+    - crypto: AF_ALG - remove SGL terminator indicator when chaining
+    - ext4: fix incorrect quotaoff if the quota feature is enabled
+    - ext4: fix quota inconsistency during orphan cleanup for read-only mounts
+    - powerpc: Fix DAR reporting when alignment handler faults
+    - block: Relax a check in blk_start_queue()
+    - md/bitmap: disable bitmap_resize for file-backed bitmaps.
+    - skd: Avoid that module unloading triggers a use-after-free
+    - skd: Submit requests to firmware before triggering the doorbell
+    - scsi: zfcp: fix queuecommand for scsi_eh commands when DIX enabled
+    - scsi: zfcp: add handling for FCP_RESID_OVER to the fcp ingress path
+    - scsi: zfcp: fix capping of unsuccessful GPN_FT SAN response trace records
+    - scsi: zfcp: fix passing fsf_req to SCSI trace on TMF to correlate with HBA
+    - scsi: zfcp: fix missing trace records for early returns in TMF eh handlers
+    - scsi: zfcp: fix payload with full FCP_RSP IU in SCSI trace records
+    - scsi: zfcp: trace HBA FSF response by default on dismiss or timedout late
+      response
+    - scsi: zfcp: trace high part of "new" 64 bit SCSI LUN
+    - scsi: megaraid_sas: Check valid aen class range to avoid kernel panic
+    - scsi: megaraid_sas: Return pended IOCTLs with cmd_status
+      MFI_STAT_WRONG_STATE in case adapter is dead
+    - scsi: storvsc: fix memory leak on ring buffer busy
+    - scsi: sg: remove 'save_scat_len'
+    - scsi: sg: use standard lists for sg_requests
+    - scsi: sg: off by one in sg_ioctl()
+    - scsi: sg: factor out sg_fill_request_table()
+    - scsi: sg: fixup infoleak when using SG_GET_REQUEST_TABLE
+    - scsi: qla2xxx: Fix an integer overflow in sysfs code
+    - ftrace: Fix selftest goto location on error
+    - tracing: Apply trace_clock changes to instance max buffer
+    - ARC: Re-enable MMU upon Machine Check exception
+    - PCI: shpchp: Enable bridge bus mastering if MSI is enabled
+    - media: v4l2-compat-ioctl32: Fix timespec conversion
+    - media: uvcvideo: Prevent heap overflow when accessing mapped controls
+    - bcache: initialize dirty stripes in flash_dev_run()
+    - bcache: Fix leak of bdev reference
+    - bcache: do not subtract sectors_to_gc for bypassed IO
+    - bcache: correct cache_dirty_target in __update_writeback_rate()
+    - bcache: Correct return value for sysfs attach errors
+    - bcache: fix for gc and write-back race
+    - bcache: fix bch_hprint crash and improve output
+    - ftrace: Fix memleak when unregistering dynamic ops when tracing disabled
+    - Linux 4.4.89
+
+  * ETPS/2 Elantech Touchpad inconsistently detected (Gigabyte P57W laptop)
+    (LP: #1594214)
+    - Input: i8042 - add Gigabyte P57 to the keyboard reset table
+
+  * Xenial update to 4.4.88 stable release (LP: #1718195)
+    - usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard
+    - USB: serial: option: add support for D-Link DWM-157 C1
+    - usb: Add device quirk for Logitech HD Pro Webcam C920-C
+    - usb:xhci:Fix regression when ATI chipsets detected
+    - USB: core: Avoid race of async_completed() w/ usbdev_release()
+    - staging/rts5208: fix incorrect shift to extract upper nybble
+    - driver core: bus: Fix a potential double free
+    - intel_th: pci: Add Cannon Lake PCH-H support
+    - intel_th: pci: Add Cannon Lake PCH-LP support
+    - ath10k: fix memory leak in rx ring buffer allocation
+    - rtlwifi: rtl_pci_probe: Fix fail path of _rtl_pci_find_adapter
+    - Bluetooth: Add support of 13d3:3494 RTL8723BE device
+    - dlm: avoid double-free on error path in dlm_device_{register,unregister}
+    - mwifiex: correct channel stat buffer overflows
+    - drm/nouveau/pci/msi: disable MSI on big-endian platforms by default
+    - workqueue: Fix flag collision
+    - cs5536: add support for IDE controller variant
+    - scsi: sg: protect against races between mmap() and SG_SET_RESERVED_SIZE
+    - scsi: sg: recheck MMAP_IO request length with lock held
+    - drm: adv7511: really enable interrupts for EDID detection
+    - drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled
+    - drm/bridge: adv7511: Use work_struct to defer hotplug handing to out of irq
+      context
+    - drm/bridge: adv7511: Switch to using drm_kms_helper_hotplug_event()
+    - drm/bridge: adv7511: Re-write the i2c address before EDID probing
+    - btrfs: resume qgroup rescan on rw remount
+    - locktorture: Fix potential memory leak with rw lock test
+    - ALSA: msnd: Optimize / harden DSP and MIDI loops
+    - ARM: 8692/1: mm: abort uaccess retries upon fatal signal
+    - NFS: Fix 2 use after free issues in the I/O code
+    - xfs: XFS_IS_REALTIME_INODE() should be false if no rt device present
+    - Linux 4.4.88
+
+  * Kernel has troule recognizing Corsair Strafe RGB keyboard (LP: #1678477)
+    - usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 10 Oct 2017 08:52:24 -0300
+
+linux (4.4.0-97.120) xenial; urgency=low
+
+  * linux: 4.4.0-97.120 -proposed tracker (LP: #1718149)
+
+  * blk-mq: possible deadlock on CPU hot(un)plug (LP: #1670634)
+    - [Config] s390x -- disable CONFIG_{DM, SCSI}_MQ_DEFAULT
+
+  * Xenial update to 4.4.87 stable release (LP: #1715678)
+    - irqchip: mips-gic: SYNC after enabling GIC region
+    - i2c: ismt: Don't duplicate the receive length for block reads
+    - i2c: ismt: Return EMSGSIZE for block reads with bogus length
+    - ceph: fix readpage from fscache
+    - cpumask: fix spurious cpumask_of_node() on non-NUMA multi-node configs
+    - cpuset: Fix incorrect memory_pressure control file mapping
+    - alpha: uapi: Add support for __SANE_USERSPACE_TYPES__
+    - CIFS: remove endian related sparse warning
+    - wl1251: add a missing spin_lock_init()
+    - xfrm: policy: check policy direction value
+    - drm/ttm: Fix accounting error when fail to get pages for pool
+    - kvm: arm/arm64: Fix race in resetting stage2 PGD
+    - kvm: arm/arm64: Force reading uncached stage2 PGD
+    - epoll: fix race between ep_poll_callback(POLLFREE) and ep_free()/ep_remove()
+    - crypto: algif_skcipher - only call put_page on referenced and used pages
+    - Linux 4.4.87
+
+  * Xenial update to 4.4.86 stable release (LP: #1715430)
+    - scsi: isci: avoid array subscript warning
+    - ALSA: au88x0: Fix zero clear of stream->resources
+    - btrfs: remove duplicate const specifier
+    - i2c: jz4780: drop superfluous init
+    - gcov: add support for gcc version >= 6
+    - gcov: support GCC 7.1
+    - lightnvm: initialize ppa_addr in dev_to_generic_addr()
+    - p54: memset(0) whole array
+    - lpfc: Fix Device discovery failures during switch reboot test.
+    - arm64: mm: abort uaccess retries upon fatal signal
+    - x86/io: Add "memory" clobber to insb/insw/insl/outsb/outsw/outsl
+    - arm64: fpsimd: Prevent registers leaking across exec
+    - scsi: sg: protect accesses to 'reserved' page array
+    - scsi: sg: reset 'res_in_use' after unlinking reserved array
+    - drm/i915: fix compiler warning in drivers/gpu/drm/i915/intel_uncore.c
+    - Linux 4.4.86
+
+  * Xenial update to 4.4.85 stable release (LP: #1714298)
+    - af_key: do not use GFP_KERNEL in atomic contexts
+    - dccp: purge write queue in dccp_destroy_sock()
+    - dccp: defer ccid_hc_tx_delete() at dismantle time
+    - ipv4: fix NULL dereference in free_fib_info_rcu()
+    - net_sched/sfq: update hierarchical backlog when drop packet
+    - ipv4: better IP_MAX_MTU enforcement
+    - sctp: fully initialize the IPv6 address in sctp_v6_to_addr()
+    - tipc: fix use-after-free
+    - ipv6: reset fn->rr_ptr when replacing route
+    - ipv6: repair fib6 tree in failure case
+    - tcp: when rearming RTO, if RTO time is in past then fire RTO ASAP
+    - irda: do not leak initialized list.dev to userspace
+    - net: sched: fix NULL pointer dereference when action calls some targets
+    - net_sched: fix order of queue length updates in qdisc_replace()
+    - mei: me: add broxton pci device ids
+    - mei: me: add lewisburg device ids
+    - Input: trackpoint - add new trackpoint firmware ID
+    - Input: elan_i2c - add ELAN0602 ACPI ID to support Lenovo Yoga310
+    - ALSA: core: Fix unexpected error at replacing user TLV
+    - ALSA: hda - Add stereo mic quirk for Lenovo G50-70 (17aa:3978)
+    - ARCv2: PAE40: Explicitly set MSB counterpart of SLC region ops addresses
+    - i2c: designware: Fix system suspend
+    - drm: Release driver tracking before making the object available again
+    - drm/atomic: If the atomic check fails, return its value first
+    - drm: rcar-du: lvds: Fix PLL frequency-related configuration
+    - drm: rcar-du: lvds: Rename PLLEN bit to PLLON
+    - drm: rcar-du: Fix crash in encoder failure error path
+    - drm: rcar-du: Fix display timing controller parameter
+    - drm: rcar-du: Fix H/V sync signal polarity configuration
+    - tracing: Fix freeing of filter in create_filter() when set_str is false
+    - cifs: Fix df output for users with quota limits
+    - cifs: return ENAMETOOLONG for overlong names in cifs_open()/cifs_lookup()
+    - nfsd: Limit end of page list when decoding NFSv4 WRITE
+    - perf/core: Fix group {cpu,task} validation
+    - Bluetooth: hidp: fix possible might sleep error in hidp_session_thread
+    - Bluetooth: cmtp: fix possible might sleep error in cmtp_session
+    - Bluetooth: bnep: fix possible might sleep error in bnep_session
+    - binder: use group leader instead of open thread
+    - binder: Use wake up hint for synchronous transactions.
+    - ANDROID: binder: fix proc->tsk check.
+    - iio: imu: adis16480: Fix acceleration scale factor for adis16480
+    - iio: hid-sensor-trigger: Fix the race with user space powering up sensors
+    - staging: rtl8188eu: add RNX-N150NUB support
+    - ASoC: simple-card: don't fail if sysclk setting is not supported
+    - ASoC: rsnd: disable SRC.out only when stop timing
+    - ASoC: rsnd: avoid pointless loop in rsnd_mod_interrupt()
+    - ASoC: rsnd: Add missing initialization of ADG req_rate
+    - ASoC: rsnd: ssi: 24bit data needs right-aligned settings
+    - ASoC: rsnd: don't call update callback if it was NULL
+    - ntb_transport: fix qp count bug
+    - ntb_transport: fix bug calculating num_qps_mw
+    - ACPI: ioapic: Clear on-stack resource before using it
+    - ACPI / APEI: Add missing synchronize_rcu() on NOTIFY_SCI removal
+    - Linux 4.4.85
+
+  * Xenial update to 4.4.84 stable release (LP: #1713729)
+    - audit: Fix use after free in audit_remove_watch_rule()
+    - parisc: pci memory bar assignment fails with 64bit kernels on dino/cujo
+    - crypto: x86/sha1 - Fix reads beyond the number of blocks passed
+    - Input: elan_i2c - Add antoher Lenovo ACPI ID for upcoming Lenovo NB
+    - ALSA: seq: 2nd attempt at fixing race creating a queue
+    - Revert "UBUNTU: SAUCE: (no-up) ALSA: usb-audio: Add quirk for sennheiser
+      officerunner"
+    - ALSA: usb-audio: Apply sample rate quirk to Sennheiser headset
+    - ALSA: usb-audio: Add mute TLV for playback volumes on C-Media devices
+    - mm/mempolicy: fix use after free when calling get_mempolicy
+    - xen: fix bio vec merging
+    - x86/asm/64: Clear AC on NMI entries
+    - irqchip/atmel-aic: Fix unbalanced of_node_put() in aic_common_irq_fixup()
+    - irqchip/atmel-aic: Fix unbalanced refcount in aic_common_rtc_irq_fixup()
+    - Sanitize 'move_pages()' permission checks
+    - pids: make task_tgid_nr_ns() safe
+    - perf/x86: Fix LBR related crashes on Intel Atom
+    - usb: optimize acpi companion search for usb port devices
+    - usb: qmi_wwan: add D-Link DWM-222 device ID
+    - Linux 4.4.84
+
+  * Intel i40e PF reset due to incorrect MDD detection (LP: #1713553)
+    - i40e: Limit TX descriptor count in cases where frag size is greater than 16K
+
+  * Neighbour confirmation broken, breaks ARP cache aging (LP: #1715812)
+    - sock: add sk_dst_pending_confirm flag
+    - net: add dst_pending_confirm flag to skbuff
+    - sctp: add dst_pending_confirm flag
+    - tcp: replace dst_confirm with sk_dst_confirm
+    - net: add confirm_neigh method to dst_ops
+    - net: use dst_confirm_neigh for UDP, RAW, ICMP, L2TP
+    - net: pending_confirm is not used anymore
+
+  * CVE-2017-14106
+    - tcp: initialize rcv_mss to TCP_MIN_MSS instead of 0
+
+  * [CIFS] Fix maximum SMB2 header size (LP: #1713884)
+    - CIFS: Fix maximum SMB2 header size
+
+  * Middle button of trackpoint doesn't work (LP: #1715271)
+    - Input: trackpoint - assume 3 buttons when buttons detection fails
+
+  * kernel BUG at /build/linux-lts-xenial-_hWfOZ/linux-lts-
+    xenial-4.4.0/security/apparmor/include/context.h:69! (LP: #1626984)
+    - SAUCE: fix oops when disabled and module parameters, are accessed
+
+  * Touchpad not detected (LP: #1708852)
+    - Input: elan_i2c - add ELAN0608 to the ACPI table
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 19 Sep 2017 17:55:11 +0200
+
+linux (4.4.0-96.119) xenial; urgency=low
+
+  * linux: 4.4.0-96.119 -proposed tracker (LP: #1716613)
+
+  * kernel panic -not syncing: Fatal exception: panic_on_oops (LP: #1708399)
+    - s390/mm: no local TLB flush for clearing-by-ASCE IDTE
+    - SAUCE: s390/mm: fix local TLB flushing vs. detach of an mm address space
+    - SAUCE: s390/mm: fix race on mm->context.flush_mm
+
+  * CVE-2017-1000251
+    - Bluetooth: Properly check L2CAP config option output buffer length
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 12 Sep 2017 15:40:01 +0200
+
+linux (4.4.0-95.118) xenial; urgency=low
+
+  * linux: 4.4.0-95.118 -proposed tracker (LP: #1715651)
+
+  * Xenial update to 4.4.78 stable release broke Address Sanitizer
+    (LP: #1715636)
+    - mm: revert x86_64 and arm64 ELF_ET_DYN_BASE base changes
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 07 Sep 2017 17:26:15 +0200
+
+linux (4.4.0-94.117) xenial; urgency=low
+
+  * linux: 4.4.0-94.117 -proposed tracker (LP: #1713462)
+
+  * mwifiex causes kernel oops when AP mode is enabled (LP: #1712746)
+    - SAUCE: net/wireless: do not dereference invalid pointer
+    - SAUCE: mwifiex: do not dereference invalid pointer
+
+  * Backport more recent Broadcom bnxt_en driver (LP: #1711056)
+    - SAUCE: bnxt_en_bpo: Import bnxt_en driver version 1.8.1
+    - SAUCE: bnxt_en_bpo: Drop distro out-of-tree detection logic
+    - SAUCE: bnxt_en_bpo: Remove unnecessary compile flags
+    - SAUCE: bnxt_en_bpo: Move config settings to Kconfig
+    - SAUCE: bnxt_en_bpo: Remove PCI_IDs handled by the regular driver
+    - SAUCE: bnxt_en_bpo: Rename the backport driver to bnxt_en_bpo
+    - bnxt_en_bpo: [Config] Enable CONFIG_BNXT_BPO=m
+
+  * HID: multitouch: Support ALPS PTP Stick and Touchpad devices (LP: #1712481)
+    - HID: multitouch: Support PTP Stick and Touchpad device
+    - SAUCE: HID: multitouch: Support ALPS PTP stick with pid 0x120A
+
+  * igb: Support using Broadcom 54616 as PHY (LP: #1712024)
+    - SAUCE: igb: add support for using Broadcom 54616 as PHY
+
+  * IPR driver causes multipath to fail paths/stuck IO on Medium Errors
+    (LP: #1682644)
+    - scsi: ipr: do not set DID_PASSTHROUGH on CHECK CONDITION
+
+  * accessing /dev/hvc1 with stress-ng on Ubuntu xenial causes crash
+    (LP: #1711401)
+    - tty/hvc: Use IRQF_SHARED for OPAL hvc consoles
+
+  * memory-hotplug test needs to be fixed (LP: #1710868)
+    - selftests: typo correction for memory-hotplug test
+    - selftests: check hot-pluggagble memory for memory-hotplug test
+    - selftests: check percentage range for memory-hotplug test
+    - selftests: add missing test name in memory-hotplug test
+    - selftests: fix memory-hotplug test
+
+  * HP lt4132 LTE/HSPA+ 4G Module (03f0:a31d) does not work (LP: #1707643)
+    - net: cdc_mbim: apply "NDP to end" quirk to HP lt4132
+
+  * Migrating KSM page causes the VM lock up as the KSM page merging list is too
+    large (LP: #1680513)
+    - ksm: introduce ksm_max_page_sharing per page deduplication limit
+    - ksm: fix use after free with merge_across_nodes = 0
+    - ksm: cleanup stable_node chain collapse case
+    - ksm: swap the two output parameters of chain/chain_prune
+    - ksm: optimize refile of stable_node_dup at the head of the chain
+
+  * sort ABI files with C.UTF-8 locale (LP: #1712345)
+    - [Packaging] sort ABI files with C.UTF-8 locale
+
+  * Include Broadcom GPL modules in Xenial Kernel (LP: #1665783)
+    - [Config] OpenNSL Kconfig/Makefile
+    - Import OpenNSL v3.1.0.17
+    - [Config] CONFIG_OPENNSL=y for amd64
+    - OpenNSL: Enable Kconfig and build
+    - SAUCE: opennsl: add proper CFLAGS
+
+  * Xenial update to 4.4.83 stable release (LP: #1711557)
+    - cpuset: fix a deadlock due to incomplete patching of cpusets_enabled()
+    - mm: ratelimit PFNs busy info message
+    - iscsi-target: fix memory leak in iscsit_setup_text_cmd()
+    - iscsi-target: Fix iscsi_np reset hung task during parallel delete
+    - fuse: initialize the flock flag in fuse_file on allocation
+    - nfs/flexfiles: fix leak of nfs4_ff_ds_version arrays
+    - USB: serial: option: add D-Link DWM-222 device ID
+    - USB: serial: cp210x: add support for Qivicon USB ZigBee dongle
+    - USB: serial: pl2303: add new ATEN device id
+    - usb: musb: fix tx fifo flush handling again
+    - USB: hcd: Mark secondary HCD as dead if the primary one died
+    - staging:iio:resolver:ad2s1210 fix negative IIO_ANGL_VEL read
+    - iio: accel: bmc150: Always restore device to normal mode after suspend-
+      resume
+    - iio: light: tsl2563: use correct event code
+    - uas: Add US_FL_IGNORE_RESIDUE for Initio Corporation INIC-3069
+    - USB: Check for dropped connection before switching to full speed
+    - usb: core: unlink urbs from the tail of the endpoint's urb_list
+    - usb: quirks: Add no-lpm quirk for Moshi USB to Ethernet Adapter
+    - usb:xhci:Add quirk for Certain failing HP keyboard on reset after resume
+    - iio: adc: vf610_adc: Fix VALT selection value for REFSEL bits
+    - pnfs/blocklayout: require 64-bit sector_t
+    - pinctrl: sunxi: add a missing function of A10/A20 pinctrl driver
+    - pinctrl: samsung: Remove bogus irq_[un]mask from resource management
+    - Linux 4.4.83
+
+  * Xenial update to 4.4.82 stable release (LP: #1711535)
+    - tcp: avoid setting cwnd to invalid ssthresh after cwnd reduction states
+    - net: fix keepalive code vs TCP_FASTOPEN_CONNECT
+    - bpf, s390: fix jit branch offset related to ldimm64
+    - net: sched: set xt_tgchk_param par.nft_compat as 0 in ipt_init_target
+    - tcp: fastopen: tcp_connect() must refresh the route
+    - net: avoid skb_warn_bad_offload false positives on UFO
+    - sparc64: Prevent perf from running during super critical sections
+    - KVM: arm/arm64: Handle hva aging while destroying the vm
+    - mm/mempool: avoid KASAN marking mempool poison checks as use-after-free
+    - Linux 4.4.82
+
+  * Xenial update to 4.4.81 stable release (LP: #1711526)
+    - libata: array underflow in ata_find_dev()
+    - workqueue: restore WQ_UNBOUND/max_active==1 to be ordered
+    - ALSA: hda - Fix speaker output from VAIO VPCL14M1R
+    - ASoC: do not close shared backend dailink
+    - KVM: async_pf: make rcu irq exit if not triggered from idle task
+    - mm/page_alloc: Remove kernel address exposure in free_reserved_area()
+    - ext4: fix SEEK_HOLE/SEEK_DATA for blocksize < pagesize
+    - ext4: fix overflow caused by missing cast in ext4_resize_fs()
+    - ARM: dts: armada-38x: Fix irq type for pca955
+    - media: platform: davinci: return -EINVAL for VPFE_CMD_S_CCDC_RAW_PARAMS
+      ioctl
+    - target: Avoid mappedlun symlink creation during lun shutdown
+    - iscsi-target: Always wait for kthread_should_stop() before kthread exit
+    - iscsi-target: Fix early sk_data_ready LOGIN_FLAGS_READY race
+    - iscsi-target: Fix initial login PDU asynchronous socket close OOPs
+    - iscsi-target: Fix delayed logout processing greater than
+      SECONDS_FOR_LOGOUT_COMP
+    - iser-target: Avoid isert_conn->cm_id dereference in isert_login_recv_done
+    - mm, mprotect: flush TLB if potentially racing with a parallel reclaim
+      leaving stale TLB entries
+    - media: lirc: LIRC_GET_REC_RESOLUTION should return microseconds
+    - f2fs: sanity check checkpoint segno and blkoff
+    - drm: rcar-du: fix backport bug
+    - saa7164: fix double fetch PCIe access condition
+    - ipv4: ipv6: initialize treq->txhash in cookie_v[46]_check()
+    - net: Zero terminate ifr_name in dev_ifname().
+    - ipv6: avoid overflow of offset in ip6_find_1stfragopt
+    - ipv4: initialize fib_trie prior to register_netdev_notifier call.
+    - rtnetlink: allocate more memory for dev_set_mac_address()
+    - mcs7780: Fix initialization when CONFIG_VMAP_STACK is enabled
+    - openvswitch: fix potential out of bound access in parse_ct
+    - packet: fix use-after-free in prb_retire_rx_blk_timer_expired()
+    - ipv6: Don't increase IPSTATS_MIB_FRAGFAILS twice in ip6_fragment()
+    - net: ethernet: nb8800: Handle all 4 RGMII modes identically
+    - dccp: fix a memleak that dccp_ipv6 doesn't put reqsk properly
+    - dccp: fix a memleak that dccp_ipv4 doesn't put reqsk properly
+    - dccp: fix a memleak for dccp_feat_init err process
+    - sctp: don't dereference ptr before leaving _sctp_walk_{params, errors}()
+    - sctp: fix the check for _sctp_walk_params and _sctp_walk_errors
+    - net/mlx5: Fix command bad flow on command entry allocation failure
+    - net: phy: Correctly process PHY_HALTED in phy_stop_machine()
+    - net: phy: Fix PHY unbind crash
+    - xen-netback: correctly schedule rate-limited queues
+    - sparc64: Measure receiver forward progress to avoid send mondo timeout
+    - wext: handle NULL extra data in iwe_stream_add_point better
+    - sh_eth: R8A7740 supports packet shecksumming
+    - net: phy: dp83867: fix irq generation
+    - tg3: Fix race condition in tg3_get_stats64().
+    - x86/boot: Add missing declaration of string functions
+    - phy state machine: failsafe leave invalid RUNNING state
+    - scsi: qla2xxx: Get mutex lock before checking optrom_state
+    - drm/virtio: fix framebuffer sparse warning
+    - virtio_blk: fix panic in initialization error path
+    - ARM: 8632/1: ftrace: fix syscall name matching
+    - mm, slab: make sure that KMALLOC_MAX_SIZE will fit into MAX_ORDER
+    - lib/Kconfig.debug: fix frv build failure
+    - signal: protect SIGNAL_UNKILLABLE from unintentional clearing.
+    - mm: don't dereference struct page fields of invalid pages
+    - workqueue: implicit ordered attribute should be overridable
+    - Linux 4.4.81
+
+  * Xenial update to 4.4.80 stable release (LP: #1710646)
+    - af_key: Add lock to key dump
+    - pstore: Make spinlock per zone instead of global
+    - powerpc/pseries: Fix of_node_put() underflow during reconfig remove
+    - crypto: authencesn - Fix digest_null crash
+    - md/raid5: add thread_group worker async_tx_issue_pending_all
+    - drm/vmwgfx: Fix gcc-7.1.1 warning
+    - drm/nouveau/bar/gf100: fix access to upper half of BAR2
+    - KVM: PPC: Book3S HV: Context-switch EBB registers properly
+    - KVM: PPC: Book3S HV: Restore critical SPRs to host values on guest exit
+    - KVM: PPC: Book3S HV: Reload HTM registers explicitly
+    - KVM: PPC: Book3S HV: Save/restore host values of debug registers
+    - Revert "powerpc/numa: Fix percpu allocations to be NUMA aware"
+    - Staging: comedi: comedi_fops: Avoid orphaned proc entry
+    - drm/rcar: Nuke preclose hook
+    - drm: rcar-du: Perform initialization/cleanup at probe/remove time
+    - drm: rcar-du: Simplify and fix probe error handling
+    - perf intel-pt: Fix ip compression
+    - perf intel-pt: Fix last_ip usage
+    - perf intel-pt: Use FUP always when scanning for an IP
+    - perf intel-pt: Ensure never to set 'last_ip' when packet 'count' is zero
+    - xfs: don't BUG() on mixed direct and mapped I/O
+    - nfc: fdp: fix NULL pointer dereference
+    - net: phy: Do not perform software reset for Generic PHY
+    - isdn: Fix a sleep-in-atomic bug
+    - isdn/i4l: fix buffer overflow
+    - ath10k: fix null deref on wmi-tlv when trying spectral scan
+    - wil6210: fix deadlock when using fw_no_recovery option
+    - mailbox: always wait in mbox_send_message for blocking Tx mode
+    - mailbox: skip complete wait event if timer expired
+    - mailbox: handle empty message in tx_tick
+    - mpt3sas: Don't overreach ioc->reply_post[] during initialization
+    - kaweth: fix firmware download
+    - kaweth: fix oops upon failed memory allocation
+    - sched/cgroup: Move sched_online_group() back into css_online() to fix crash
+    - PM / Domains: defer dev_pm_domain_set() until genpd->attach_dev succeeds if
+      present
+    - RDMA/uverbs: Fix the check for port number
+    - libnvdimm, btt: fix btt_rw_page not returning errors
+    - ipmi/watchdog: fix watchdog timeout set on reboot
+    - v4l: s5c73m3: fix negation operator
+    - pstore: Allow prz to control need for locking
+    - pstore: Correctly initialize spinlock and flags
+    - pstore: Use dynamic spinlock initializer
+    - net: skb_needs_check() accepts CHECKSUM_NONE for tx
+    - sched/cputime: Fix prev steal time accouting during CPU hotplug
+    - xen/blkback: don't free be structure too early
+    - xen/blkback: don't use xen_blkif_get() in xen-blkback kthread
+    - tpm: fix a kernel memory leak in tpm-sysfs.c
+    - tpm: Replace device number bitmap with IDR
+    - x86/mce/AMD: Make the init code more robust
+    - r8169: add support for RTL8168 series add-on card.
+    - ARM: dts: n900: Mark eMMC slot with no-sdio and no-sd flags
+    - net/mlx4: Remove BUG_ON from ICM allocation routine
+    - drm/msm: Ensure that the hardware write pointer is valid
+    - drm/msm: Verify that MSM_SUBMIT_BO_FLAGS are set
+    - vfio-pci: use 32-bit comparisons for register address for gcc-4.5
+    - irqchip/keystone: Fix "scheduling while atomic" on rt
+    - ASoC: tlv320aic3x: Mark the RESET register as volatile
+    - spi: dw: Make debugfs name unique between instances
+    - ASoC: nau8825: fix invalid configuration in Pre-Scalar of FLL
+    - irqchip/mxs: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND
+    - openrisc: Add _text symbol to fix ksym build error
+    - dmaengine: ioatdma: Add Skylake PCI Dev ID
+    - dmaengine: ioatdma: workaround SKX ioatdma version
+    - dmaengine: ti-dma-crossbar: Add some 'of_node_put()' in error path.
+    - ARM64: zynqmp: Fix W=1 dtc 1.4 warnings
+    - ARM64: zynqmp: Fix i2c node's compatible string
+    - ARM: s3c2410_defconfig: Fix invalid values for NF_CT_PROTO_*
+    - ACPI / scan: Prefer devices without _HID/_CID for _ADR matching
+    - usb: gadget: Fix copy/pasted error message
+    - Btrfs: adjust outstanding_extents counter properly when dio write is split
+    - tools lib traceevent: Fix prev/next_prio for deadline tasks
+    - xfrm: Don't use sk_family for socket policy lookups
+    - perf tools: Install tools/lib/traceevent plugins with install-bin
+    - perf symbols: Robustify reading of build-id from sysfs
+    - video: fbdev: cobalt_lcdfb: Handle return NULL error from devm_ioremap
+    - vfio-pci: Handle error from pci_iomap
+    - arm64: mm: fix show_pte KERN_CONT fallout
+    - nvmem: imx-ocotp: Fix wrong register size
+    - sh_eth: enable RX descriptor word 0 shift on SH7734
+    - ALSA: usb-audio: test EP_FLAG_RUNNING at urb completion
+    - HID: ignore Petzl USB headlamp
+    - scsi: fnic: Avoid sending reset to firmware when another reset is in
+      progress
+    - scsi: snic: Return error code on memory allocation failure
+    - ASoC: dpcm: Avoid putting stream state to STOP when FE stream is paused
+    - Linux 4.4.80
+
+  * Please only recommend or suggest initramfs-tools | linux-initramfs-tool for
+    kernels able to boot without initramfs (LP: #1700972)
+    - [Debian] Don't depend on initramfs-tools
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 28 Aug 2017 17:07:08 +0200
+
+linux (4.4.0-93.116) xenial; urgency=low
+
+  * linux: 4.4.0-93.116 -proposed tracker (LP: #1709296)
+
+  * Creating conntrack entry failure with kernel 4.4.0-89 (LP: #1709032)
+    - Revert "Revert "netfilter: synproxy: fix conntrackd interaction""
+    - netfilter: nf_ct_ext: fix possible panic after nf_ct_extend_unregister
+
+  * CVE-2017-1000112
+    - Revert "udp: consistently apply ufo or fragmentation"
+    - udp: consistently apply ufo or fragmentation
+
+  * CVE-2017-1000111
+    - Revert "net-packet: fix race in packet_set_ring on PACKET_RESERVE"
+    - packet: fix tp_reserve race in packet_set_ring
+
+  * kernel BUG at [tty_ldisc_reinit] mm/slub.c! (LP: #1709126)
+    - tty: Simplify tty_set_ldisc() exit handling
+    - tty: Reset c_line from driver's init_termios
+    - tty: Handle NULL tty->ldisc
+    - tty: Move tty_ldisc_kill()
+    - tty: Use 'disc' for line discipline index name
+    - tty: Refactor tty_ldisc_reinit() for reuse
+    - tty: Destroy ldisc instance on hangup
+
+  * atheros bt failed after S3 (LP: #1706833)
+    - SAUCE: Bluetooth: Make request workqueue freezable
+
+  * The Precision Touchpad(PTP) button sends incorrect event code (LP: #1708372)
+    - HID: multitouch: handle external buttons for Precision Touchpads
+
+  * Set CONFIG_SATA_HIGHBANK=y on armhf (LP: #1703430)
+    - [Config] CONFIG_SATA_HIGHBANK=y
+
+  * xfs slab objects (memory) leak when xfs shutdown is called (LP: #1706132)
+    - xfs: fix xfs_log_ticket leak in xfs_end_io() after fs shutdown
+
+  * Adt tests of src:linux time out often on armhf lxc containers (LP: #1705495)
+    - [Packaging] tests -- reduce rebuild test to one flavour
+
+  * CVE-2017-7495
+    - ext4: fix data exposure after a crash
+
+  * ubuntu/rsi driver downlink wifi throughput drops to 5-6 Mbps when BT
+    keyboard is connected (LP: #1706991)
+    - SAUCE: Redpine: enable power save by default for coex mode
+    - SAUCE: Redpine: uapsd configuration changes
+
+  * [Hyper-V] hv_netvsc: Exclude non-TCP port numbers from vRSS hashing
+    (LP: #1690174)
+    - hv_netvsc: Exclude non-TCP port numbers from vRSS hashing
+
+  * ath10k doesn't report full RSSI information (LP: #1706531)
+    - ath10k: add per chain RSSI reporting
+
+  * ideapad_laptop don't support v310-14isk (LP: #1705378)
+    - platform/x86: ideapad-laptop: Add several models to no_hw_rfkill
+
+  * [8087:0a2b] Failed to load bluetooth firmware(might affect some other Intel
+    bt devices) (LP: #1705633)
+    - Bluetooth: btintel: Create common Intel Version Read function
+    - Bluetooth: Use switch statement for Intel hardware variants
+    - Bluetooth: Replace constant hw_variant from Intel Bluetooth firmware
+      filename
+    - Bluetooth: hci_intel: Fix firmware file name to use hw_variant
+    - Bluetooth: btintel: Add MODULE_FIRMWARE entries for iBT 3.5 controllers
+
+  * xhci_hcd: ERROR Transfer event TRB DMA ptr not part of current TD ep_index 2
+    comp_code 13 (LP: #1667750)
+    - xhci: Bad Ethernet performance plugged in ASM1042A host
+
+  * OpenPower: Some multipaths temporarily have only a single path
+    (LP: #1696445)
+    - scsi: ses: don't get power status of SES device slot on probe
+
+  * Hotkeys on new Thinkpad systems aren't working (LP: #1705169)
+    - platform/x86: thinkpad_acpi: Adding new hotkey ID for Lenovo thinkpad
+    - platform/x86: thinkpad_acpi: guard generic hotkey case
+    - platform/x86: thinkpad_acpi: add mapping for new hotkeys
+
+  * CVE-2015-7837
+    - SAUCE: (no-up) kexec/uefi: copy secure_boot flag in boot params across kexec
+      reboot
+
+  * misleading kernel warning skb_warn_bad_offload during checksum calculation
+    (LP: #1705447)
+    - net: reduce skb_warn_bad_offload() noise
+
+  * bonding: stack dump when unregistering a netdev (LP: #1704102)
+    - bonding: avoid NETDEV_CHANGEMTU event when unregistering slave
+
+  * Ubuntu 16.04 IOB Error when the Mustang board rebooted (LP: #1693673)
+    - drivers: net: xgene: Fix redundant prefetch buffer cleanup
+
+  * Ubuntu16.04: NVMe 4K+T10 DIF/DIX format returns I/O error on dd with split
+    op (LP: #1689946)
+    - blk-mq: NVMe 512B/4K+T10 DIF/DIX format returns I/O error on dd with split
+      op
+
+  * linux >= 4.2: bonding 802.3ad does not work with 5G, 25G and 50G link speeds
+    (LP: #1697892)
+    - bonding: add 802.3ad support for 100G speeds
+    - bonding: fix 802.3ad aggregator reselection
+    - bonding: add 802.3ad support for 25G speeds
+    - bonding: fix 802.3ad support for 5G and 50G speeds
+
+  * Xenial update to 4.4.79 stable release (LP: #1707233)
+    - disable new gcc-7.1.1 warnings for now
+    - ir-core: fix gcc-7 warning on bool arithmetic
+    - s5p-jpeg: don't return a random width/height
+    - thermal: cpu_cooling: Avoid accessing potentially freed structures
+    - ath9k: fix tx99 use after free
+    - ath9k: fix tx99 bus error
+    - NFC: fix broken device allocation
+    - NFC: nfcmrvl_uart: add missing tty-device sanity check
+    - NFC: nfcmrvl: do not use device-managed resources
+    - NFC: nfcmrvl: use nfc-device for firmware download
+    - NFC: nfcmrvl: fix firmware-management initialisation
+    - nfc: Ensure presence of required attributes in the activate_target handler
+    - nfc: Fix the sockaddr length sanitization in llcp_sock_connect
+    - NFC: Add sockaddr length checks before accessing sa_family in bind handlers
+    - perf intel-pt: Move decoder error setting into one condition
+    - perf intel-pt: Improve sample timestamp
+    - perf intel-pt: Fix missing stack clear
+    - perf intel-pt: Ensure IP is zero when state is INTEL_PT_STATE_NO_IP
+    - perf intel-pt: Clear FUP flag on error
+    - Bluetooth: use constant time memory comparison for secret values
+    - wlcore: fix 64K page support
+    - ASoC: compress: Derive substream from stream based on direction
+    - PM / Domains: Fix unsafe iteration over modified list of device links
+    - PM / Domains: Fix unsafe iteration over modified list of domain providers
+    - scsi: ses: do not add a device to an enclosure if enclosure_add_links()
+      fails.
+    - iscsi-target: Add login_keys_workaround attribute for non RFC initiators
+    - powerpc/64: Fix atomic64_inc_not_zero() to return an int
+    - powerpc: Fix emulation of mcrf in emulate_step()
+    - powerpc: Fix emulation of mfocrf in emulate_step()
+    - powerpc/asm: Mark cr0 as clobbered in mftb()
+    - af_key: Fix sadb_x_ipsecrequest parsing
+    - PCI/PM: Restore the status of PCI devices across hibernation
+    - ipvs: SNAT packet replies only for NATed connections
+    - xhci: fix 20000ms port resume timeout
+    - xhci: Fix NULL pointer dereference when cleaning up streams for removed host
+    - usb: storage: return on error to avoid a null pointer dereference
+    - USB: cdc-acm: add device-id for quirky printer
+    - usb: renesas_usbhs: fix usbhsc_resume() for !USBHSF_RUNTIME_PWCTRL
+    - usb: renesas_usbhs: gadget: disable all eps when the driver stops
+    - md: don't use flush_signals in userspace processes
+    - x86/xen: allow userspace access during hypercalls
+    - cx88: Fix regression in initial video standard setting
+    - Raid5 should update rdev->sectors after reshape
+    - s390/syscalls: Fix out of bounds arguments access
+    - drm/amd/amdgpu: Return error if initiating read out of range on vram
+    - drm/radeon/ci: disable mclk switching for high refresh rates (v2)
+    - drm/radeon: Fix eDP for single-display iMac10,1 (v2)
+    - ipmi: use rcu lock around call to intf->handlers->sender()
+    - ipmi:ssif: Add missing unlock in error branch
+    - f2fs: Don't clear SGID when inheriting ACLs
+    - vfio: Fix group release deadlock
+    - vfio: New external user group/file match
+    - ftrace: Fix uninitialized variable in match_records()
+    - MIPS: Fix mips_atomic_set() retry condition
+    - MIPS: Fix mips_atomic_set() with EVA
+    - MIPS: Negate error syscall return in trace
+    - x86/acpi: Prevent out of bound access caused by broken ACPI tables
+    - x86/ioapic: Pass the correct data to unmask_ioapic_irq()
+    - MIPS: Fix MIPS I ISA /proc/cpuinfo reporting
+    - MIPS: Save static registers before sysmips
+    - MIPS: Actually decode JALX in `__compute_return_epc_for_insn'
+    - MIPS: Fix unaligned PC interpretation in `compute_return_epc'
+    - MIPS: math-emu: Prevent wrong ISA mode instruction emulation
+    - MIPS: Send SIGILL for BPOSGE32 in `__compute_return_epc_for_insn'
+    - MIPS: Rename `sigill_r6' to `sigill_r2r6' in `__compute_return_epc_for_insn'
+    - MIPS: Send SIGILL for linked branches in `__compute_return_epc_for_insn'
+    - MIPS: Fix a typo: s/preset/present/ in r2-to-r6 emulation error message
+    - Input: i8042 - fix crash at boot time
+    - NFS: only invalidate dentrys that are clearly invalid.
+    - udf: Fix deadlock between writeback and udf_setsize()
+    - target: Fix COMPARE_AND_WRITE caw_sem leak during se_cmd quiesce
+    - perf annotate: Fix broken arrow at row 0 connecting jmp instruction to its
+      target
+    - Revert "perf/core: Drop kernel samples even though :u is specified"
+    - staging: rtl8188eu: add TL-WN722N v2 support
+    - ceph: fix race in concurrent readdir
+    - RDMA/core: Initialize port_num in qp_attr
+    - drm/mst: Fix error handling during MST sideband message reception
+    - drm/mst: Avoid dereferencing a NULL mstb in drm_dp_mst_handle_up_req()
+    - drm/mst: Avoid processing partially received up/down message transactions
+    - of: device: Export of_device_{get_modalias, uvent_modalias} to modules
+    - spmi: Include OF based modalias in device uevent
+    - tracing: Fix kmemleak in instance_rmdir
+    - alarmtimer: don't rate limit one-shot timers
+    - Linux 4.4.79
+
+  * Xenial update to 4.4.78 stable release (LP: #1705707)
+    - net_sched: fix error recovery at qdisc creation
+    - net: sched: Fix one possible panic when no destroy callback
+    - net/phy: micrel: configure intterupts after autoneg workaround
+    - ipv6: avoid unregistering inet6_dev for loopback
+    - net: dp83640: Avoid NULL pointer dereference.
+    - tcp: reset sk_rx_dst in tcp_disconnect()
+    - net: prevent sign extension in dev_get_stats()
+    - bpf: prevent leaking pointer via xadd on unpriviledged
+    - net: handle NAPI_GRO_FREE_STOLEN_HEAD case also in napi_frags_finish()
+    - ipv6: dad: don't remove dynamic addresses if link is down
+    - net: ipv6: Compare lwstate in detecting duplicate nexthops
+    - vrf: fix bug_on triggered by rx when destroying a vrf
+    - rds: tcp: use sock_create_lite() to create the accept socket
+    - brcmfmac: fix possible buffer overflow in brcmf_cfg80211_mgmt_tx()
+    - cfg80211: Define nla_policy for NL80211_ATTR_LOCAL_MESH_POWER_MODE
+    - cfg80211: Validate frequencies nested in NL80211_ATTR_SCAN_FREQUENCIES
+    - cfg80211: Check if PMKID attribute is of expected size
+    - irqchip/gic-v3: Fix out-of-bound access in gic_set_affinity
+    - parisc: Report SIGSEGV instead of SIGBUS when running out of stack
+    - parisc: use compat_sys_keyctl()
+    - parisc: DMA API: return error instead of BUG_ON for dma ops on non dma devs
+    - parisc/mm: Ensure IRQs are off in switch_mm()
+    - tools/lib/lockdep: Reduce MAX_LOCK_DEPTH to avoid overflowing lock_chain/:
+      Depth
+    - kernel/extable.c: mark core_kernel_text notrace
+    - mm/list_lru.c: fix list_lru_count_node() to be race free
+    - fs/dcache.c: fix spin lockup issue on nlru->lock
+    - checkpatch: silence perl 5.26.0 unescaped left brace warnings
+    - binfmt_elf: use ELF_ET_DYN_BASE only for PIE
+    - arm: move ELF_ET_DYN_BASE to 4MB
+    - arm64: move ELF_ET_DYN_BASE to 4GB / 4MB
+    - powerpc: move ELF_ET_DYN_BASE to 4GB / 4MB
+    - s390: reduce ELF_ET_DYN_BASE
+    - exec: Limit arg stack to at most 75% of _STK_LIM
+    - vt: fix unchecked __put_user() in tioclinux ioctls
+    - mnt: In umount propagation reparent in a separate pass
+    - mnt: In propgate_umount handle visiting mounts in any order
+    - mnt: Make propagate_umount less slow for overlapping mount propagation trees
+    - selftests/capabilities: Fix the test_execve test
+    - tpm: Get rid of chip->pdev
+    - tpm: Provide strong locking for device removal
+    - Add "shutdown" to "struct class".
+    - tpm: Issue a TPM2_Shutdown for TPM2 devices.
+    - mm: fix overflow check in expand_upwards()
+    - crypto: talitos - Extend max key length for SHA384/512-HMAC and AEAD
+    - crypto: atmel - only treat EBUSY as transient if backlog
+    - crypto: sha1-ssse3 - Disable avx2
+    - crypto: caam - fix signals handling
+    - sched/topology: Fix overlapping sched_group_mask
+    - sched/topology: Optimize build_group_mask()
+    - PM / wakeirq: Convert to SRCU
+    - PM / QoS: return -EINVAL for bogus strings
+    - tracing: Use SOFTIRQ_OFFSET for softirq dectection for more accurate results
+    - KVM: x86: disable MPX if host did not enable MPX XSAVE features
+    - kvm: vmx: Do not disable intercepts for BNDCFGS
+    - kvm: x86: Guest BNDCFGS requires guest MPX support
+    - kvm: vmx: Check value written to IA32_BNDCFGS
+    - kvm: vmx: allow host to access guest MSR_IA32_BNDCFGS
+    - Linux 4.4.78
+
+  * Xenial update to 4.4.77 stable release (LP: #1705238)
+    - fs: add a VALID_OPEN_FLAGS
+    - fs: completely ignore unknown open flags
+    - driver core: platform: fix race condition with driver_override
+    - bgmac: reset & enable Ethernet core before using it
+    - mm: fix classzone_idx underflow in shrink_zones()
+    - tracing/kprobes: Allow to create probe with a module name starting with a
+      digit
+    - usb: dwc3: replace %p with %pK
+    - USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick
+    - Add USB quirk for HVR-950q to avoid intermittent device resets
+    - usb: usbip: set buffer pointers to NULL after free
+    - usb: Fix typo in the definition of Endpoint[out]Request
+    - mac80211_hwsim: Replace bogus hrtimer clockid
+    - sysctl: don't print negative flag for proc_douintvec
+    - sysctl: report EINVAL if value is larger than UINT_MAX for proc_douintvec
+    - pinctrl: sh-pfc: r8a7791: Fix SCIF2 pinmux data
+    - pinctrl: meson: meson8b: fix the NAND DQS pins
+    - pinctrl: sunxi: Fix SPDIF function name for A83T
+    - pinctrl: mxs: atomically switch mux and drive strength config
+    - pinctrl: sh-pfc: Update info pointer after SoC-specific init
+    - USB: serial: option: add two Longcheer device ids
+    - USB: serial: qcserial: new Sierra Wireless EM7305 device ID
+    - gfs2: Fix glock rhashtable rcu bug
+    - x86/tools: Fix gcc-7 warning in relocs.c
+    - x86/uaccess: Optimize copy_user_enhanced_fast_string() for short strings
+    - ath10k: override CE5 config for QCA9377
+    - KEYS: Fix an error code in request_master_key()
+    - RDMA/uverbs: Check port number supplied by user verbs cmds
+    - mqueue: fix a use-after-free in sys_mq_notify()
+    - tools include: Add a __fallthrough statement
+    - tools string: Use __fallthrough in perf_atoll()
+    - tools strfilter: Use __fallthrough
+    - perf top: Use __fallthrough
+    - perf intel-pt: Use __fallthrough
+    - perf thread_map: Correctly size buffer used with dirent->dt_name
+    - perf scripting perl: Fix compile error with some perl5 versions
+    - perf tests: Avoid possible truncation with dirent->d_name + snprintf
+    - perf bench numa: Avoid possible truncation when using snprintf()
+    - perf tools: Use readdir() instead of deprecated readdir_r()
+    - perf thread_map: Use readdir() instead of deprecated readdir_r()
+    - perf script: Use readdir() instead of deprecated readdir_r()
+    - perf tools: Remove duplicate const qualifier
+    - perf annotate browser: Fix behaviour of Shift-Tab with nothing focussed
+    - perf pmu: Fix misleadingly indented assignment (whitespace)
+    - perf dwarf: Guard !x86_64 definitions under #ifdef else clause
+    - perf trace: Do not process PERF_RECORD_LOST twice
+    - perf tests: Remove wrong semicolon in while loop in CQM test
+    - perf tools: Use readdir() instead of deprecated readdir_r() again
+    - md: fix incorrect use of lexx_to_cpu in does_sb_need_changing
+    - md: fix super_offset endianness in super_1_rdev_size_change
+    - tcp: fix tcp_mark_head_lost to check skb len before fragmenting
+    - staging: vt6556: vnt_start Fix missing call to vnt_key_init_table.
+    - staging: comedi: fix clean-up of comedi_class in comedi_init()
+    - ext4: check return value of kstrtoull correctly in reserved_clusters_store
+    - x86/mm/pat: Don't report PAT on CPUs that don't support it
+    - saa7134: fix warm Medion 7134 EEPROM read
+    - Linux 4.4.77
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 11 Aug 2017 16:51:50 +0200
+
+linux (4.4.0-92.115) xenial; urgency=low
+
+  * linux: 4.4.0-92.115 -proposed tracker (LP: #1709812)
+
+  * Creating conntrack entry failure with kernel 4.4.0-89 (LP: #1709032)
+    - Revert "netfilter: synproxy: fix conntrackd interaction"
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 10 Aug 2017 10:29:51 +0200
+
+linux (4.4.0-91.114) xenial; urgency=low
+
+  * CVE-2017-1000112
+    - ipv4: Should use consistent conditional judgement for ip fragment in
+      __ip_append_data and ip_finish_output
+    - ipv6: Don't use ufo handling on later transformed packets
+    - udp: avoid ufo handling on IP payload compression packets
+    - ipv6: Should use consistent conditional judgement for ip6 fragment between
+      __ip6_append_data and ip6_finish_output
+    - net: account for current skb length when deciding about UFO
+    - udp: consistently apply ufo or fragmentation
+
+  * CVE-2017-1000111
+    - net-packet: fix race in packet_set_ring on PACKET_RESERVE
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 07 Aug 2017 13:14:36 +0200
+
+linux (4.4.0-89.112) xenial; urgency=low
+
+  * CVE-2017-7533
+    - dentry name snapshots
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 31 Jul 2017 14:50:32 -0300
+
+linux (4.4.0-88.111) xenial; urgency=low
+
+  * linux: 4.4.0-88.111 -proposed tracker (LP: #1705270)
+
+  * [Xenial] nvme: Quirks for PM1725 controllers (LP: #1704435)
+    - nvme: Quirks for PM1725 controllers
+
+  * Upgrade Redpine WLAN/BT driver to ver. 1.2 (production release)
+    (LP: #1697829)
+    - SAUCE: Redpine: Upgrade to ver. 1.2 production release
+
+  * ubuntu/rsi driver has several issues as picked up by static analysis
+    (LP: #1694733)
+    - SAUCE: Redpine: Upgrade to ver. 1.2 production release
+
+  * Redpine vendor driver - Switching to AP mode causes kernel panic
+    (LP: #1700941)
+    - SAUCE: Redpine: Upgrade to ver. 1.2 production release
+
+  * CVE-2017-10810
+    - drm/virtio: don't leak bo on drm_gem_object_init failure
+
+  * Ath10k to read different board data file if specify in SMBIOS (LP: #1666742)
+    - ath10k: search SMBIOS for OEM board file extension
+
+  * make snap-pkg support (LP: #1700747)
+    - SAUCE: make snap-pkg support
+
+  * ISST-LTE: Briggs:Stratton:UbuntuKVM:  ics_opal_set_affinity on host kernel
+    log using Intel X710 (i40e driver) (LP: #1703663)
+    - i40e: use valid online CPU on q_vector initialization
+
+  * Update snapcraft.yaml (LP: #1700480)
+    - snapcraft.yaml: various improvements
+
+  * Xenial update to 4.4.76 stable release (LP: #1702863)
+    - ipv6: release dst on error in ip6_dst_lookup_tail
+    - net: don't call strlen on non-terminated string in dev_set_alias()
+    - decnet: dn_rtmsg: Improve input length sanitization in
+      dnrmg_receive_user_skb
+    - net: Zero ifla_vf_info in rtnl_fill_vfinfo()
+    - af_unix: Add sockaddr length checks before accessing sa_family in bind and
+      connect handlers
+    - Fix an intermittent pr_emerg warning about lo becoming free.
+    - net: caif: Fix a sleep-in-atomic bug in cfpkt_create_pfx
+    - igmp: acquire pmc lock for ip_mc_clear_src()
+    - igmp: add a missing spin_lock_init()
+    - ipv6: fix calling in6_ifa_hold incorrectly for dad work
+    - net/mlx5: Wait for FW readiness before initializing command interface
+    - decnet: always not take dst->__refcnt when inserting dst into hash table
+    - net: 8021q: Fix one possible panic caused by BUG_ON in free_netdev
+    - sfc: provide dummy definitions of vswitch functions
+    - ipv6: Do not leak throw route references
+    - rtnetlink: add IFLA_GROUP to ifla_policy
+    - netfilter: xt_TCPMSS: add more sanity tests on tcph->doff
+    - netfilter: synproxy: fix conntrackd interaction
+    - NFSv4: fix a reference leak caused WARNING messages
+    - drm/ast: Handle configuration without P2A bridge
+    - mm, swap_cgroup: reschedule when neeed in swap_cgroup_swapoff()
+    - MIPS: Avoid accidental raw backtrace
+    - MIPS: pm-cps: Drop manual cache-line alignment of ready_count
+    - MIPS: Fix IRQ tracing & lockdep when rescheduling
+    - ALSA: hda - Fix endless loop of codec configure
+    - ALSA: hda - set input_path bitmap to zero after moving it to new place
+    - drm/vmwgfx: Free hash table allocated by cmdbuf managed res mgr
+    - usb: gadget: f_fs: Fix possibe deadlock
+    - sysctl: enable strict writes
+    - mm: numa: avoid waiting on freed migrated pages
+    - KVM: x86: fix fixing of hypercalls
+    - scsi: sd: Fix wrong DPOFUA disable in sd_read_cache_type
+    - scsi: lpfc: Set elsiocb contexts to NULL after freeing it
+    - qla2xxx: Fix erroneous invalid handle message
+    - ARM: dts: BCM5301X: Correct GIC_PPI interrupt flags
+    - net: mvneta: Fix for_each_present_cpu usage
+    - MIPS: ath79: fix regression in PCI window initialization
+    - net: korina: Fix NAPI versus resources freeing
+    - MIPS: ralink: MT7688 pinmux fixes
+    - MIPS: ralink: fix USB frequency scaling
+    - MIPS: ralink: Fix invalid assignment of SoC type
+    - MIPS: ralink: fix MT7628 pinmux typos
+    - MIPS: ralink: fix MT7628 wled_an pinmux gpio
+    - mtd: bcm47xxpart: limit scanned flash area on BCM47XX (MIPS) only
+    - bgmac: fix a missing check for build_skb
+    - mtd: bcm47xxpart: don't fail because of bit-flips
+    - bgmac: Fix reversed test of build_skb() return value.
+    - net: bgmac: Fix SOF bit checking
+    - net: bgmac: Start transmit queue in bgmac_open
+    - net: bgmac: Remove superflous netif_carrier_on()
+    - powerpc/eeh: Enable IO path on permanent error
+    - gianfar: Do not reuse pages from emergency reserve
+    - Btrfs: fix truncate down when no_holes feature is enabled
+    - virtio_console: fix a crash in config_work_handler
+    - swiotlb-xen: update dev_addr after swapping pages
+    - xen-netfront: Fix Rx stall during network stress and OOM
+    - scsi: virtio_scsi: Reject commands when virtqueue is broken
+    - platform/x86: ideapad-laptop: handle ACPI event 1
+    - amd-xgbe: Check xgbe_init() return code
+    - net: dsa: Check return value of phy_connect_direct()
+    - drm/amdgpu: check ring being ready before using
+    - vfio/spapr: fail tce_iommu_attach_group() when iommu_data is null
+    - virtio_net: fix PAGE_SIZE > 64k
+    - vxlan: do not age static remote mac entries
+    - ibmveth: Add a proper check for the availability of the checksum features
+    - kernel/panic.c: add missing \n
+    - HID: i2c-hid: Add sleep between POWER ON and RESET
+    - scsi: lpfc: avoid double free of resource identifiers
+    - spi: davinci: use dma_mapping_error()
+    - mac80211: initialize SMPS field in HT capabilities
+    - x86/mpx: Use compatible types in comparison to fix sparse error
+    - coredump: Ensure proper size of sparse core files
+    - swiotlb: ensure that page-sized mappings are page-aligned
+    - s390/ctl_reg: make __ctl_load a full memory barrier
+    - be2net: fix status check in be_cmd_pmac_add()
+    - perf probe: Fix to show correct locations for events on modules
+    - net/mlx4_core: Eliminate warning messages for SRQ_LIMIT under SRIOV
+    - sctp: check af before verify address in sctp_addr_id2transport
+    - ravb: Fix use-after-free on `ifconfig eth0 down`
+    - jump label: fix passing kbuild_cflags when checking for asm goto support
+    - xfrm: fix stack access out of bounds with CONFIG_XFRM_SUB_POLICY
+    - xfrm: NULL dereference on allocation failure
+    - xfrm: Oops on error in pfkey_msg2xfrm_state()
+    - watchdog: bcm281xx: Fix use of uninitialized spinlock.
+    - sched/loadavg: Avoid loadavg spikes caused by delayed NO_HZ accounting
+    - ARM64/ACPI: Fix BAD_MADT_GICC_ENTRY() macro implementation
+    - ARM: 8685/1: ensure memblock-limit is pmd-aligned
+    - x86/mpx: Correctly report do_mpx_bt_fault() failures to user-space
+    - x86/mm: Fix flush_tlb_page() on Xen
+    - ocfs2: o2hb: revert hb threshold to keep compatible
+    - iommu/vt-d: Don't over-free page table directories
+    - iommu: Handle default domain attach failure
+    - iommu/amd: Fix incorrect error handling in amd_iommu_bind_pasid()
+    - cpufreq: s3c2416: double free on driver init error path
+    - KVM: x86: fix emulation of RSM and IRET instructions
+    - KVM: x86/vPMU: fix undefined shift in intel_pmu_refresh()
+    - KVM: x86: zero base3 of unusable segments
+    - KVM: nVMX: Fix exception injection
+    - Linux 4.4.76
+
+  * Xenial update to 4.4.75 stable release (LP: #1702118)
+    - fs/exec.c: account for argv/envp pointers
+    - autofs: sanity check status reported with AUTOFS_DEV_IOCTL_FAIL
+    - lib/cmdline.c: fix get_options() overflow while parsing ranges
+    - KVM: PPC: Book3S HV: Preserve userspace HTM state properly
+    - CIFS: Improve readdir verbosity
+    - HID: Add quirk for Dell PIXART OEM mouse
+    - signal: Only reschedule timers on signals timers have sent
+    - powerpc/kprobes: Pause function_graph tracing during jprobes handling
+    - Input: i8042 - add Fujitsu Lifebook AH544 to notimeout list
+    - time: Fix clock->read(clock) race around clocksource changes
+    - target: Fix kref->refcount underflow in transport_cmd_finish_abort
+    - iscsi-target: Reject immediate data underflow larger than SCSI transfer
+      length
+    - drm/radeon: add a PX quirk for another K53TK variant
+    - drm/radeon: add a quirk for Toshiba Satellite L20-183
+    - drm/amdgpu/atom: fix ps allocation size for EnableDispPowerGating
+    - drm/amdgpu: adjust default display clock
+    - USB: usbip: fix nonconforming hub descriptor
+    - rxrpc: Fix several cases where a padded len isn't checked in ticket decode
+    - of: Add check to of_scan_flat_dt() before accessing initial_boot_params
+    - mtd: spi-nor: fix spansion quad enable
+    - powerpc/slb: Force a full SLB flush when we insert for a bad EA
+    - usb: gadget: f_fs: avoid out of bounds access on comp_desc
+    - net: phy: Initialize mdio clock at probe function
+    - net: phy: fix marvell phy status reading
+    - Linux 4.4.75
+
+  * Xenial update to 4.4.74 stable release (LP: #1702104)
+    - configfs: Fix race between create_link and configfs_rmdir
+    - can: gs_usb: fix memory leak in gs_cmd_reset()
+    - cpufreq: conservative: Allow down_threshold to take values from 1 to 10
+    - vb2: Fix an off by one error in 'vb2_plane_vaddr'
+    - mac80211: don't look at the PM bit of BAR frames
+    - mac80211/wpa: use constant time memory comparison for MACs
+    - mac80211: fix CSA in IBSS mode
+    - mac80211: fix IBSS presp allocation size
+    - serial: efm32: Fix parity management in 'efm32_uart_console_get_options()'
+    - x86/mm/32: Set the '__vmalloc_start_set' flag in initmem_init()
+    - mfd: omap-usb-tll: Fix inverted bit use for USB TLL mode
+    - staging: rtl8188eu: prevent an underflow in rtw_check_beacon_data()
+    - iio: proximity: as3935: recalibrate RCO after resume
+    - USB: hub: fix SS max number of ports
+    - usb: core: fix potential memory leak in error path during hcd creation
+    - pvrusb2: reduce stack usage pvr2_eeprom_analyze()
+    - USB: gadget: dummy_hcd: fix hub-descriptor removable fields
+    - usb: r8a66597-hcd: select a different endpoint on timeout
+    - usb: r8a66597-hcd: decrease timeout
+    - drivers/misc/c2port/c2port-duramar2150.c: checking for NULL instead of
+      IS_ERR()
+    - usb: xhci: ASMedia ASM1042A chipset need shorts TX quirk
+    - USB: gadgetfs, dummy-hcd, net2280: fix locking for callbacks
+    - mm/memory-failure.c: use compound_head() flags for huge pages
+    - swap: cond_resched in swap_cgroup_prepare()
+    - genirq: Release resources in __setup_irq() error path
+    - alarmtimer: Prevent overflow of relative timers
+    - usb: dwc3: exynos fix axius clock error path to do cleanup
+    - MIPS: Fix bnezc/jialc return address calculation
+    - alarmtimer: Rate limit periodic intervals
+    - Linux 4.4.74
+
+  * Side Button (Display Toggle) fails on Dell AIO systems (LP: #1702541)
+    - dell-wmi: Add a WMI event code for display on/off
+
+  * Intel i40e PF reset under load (LP: #1700834)
+    - i40e/i40evf: Limit TSO to 7 descriptors for payload instead of 8 per packet
+
+  * update ENA driver to 1.2.0k from net-next (LP: #1701575)
+    - net: ena: remove superfluous check in ena_remove()
+    - net: ena: fix rare uncompleted admin command false alarm
+    - net: ena: add missing return when ena_com_get_io_handlers() fails
+    - net: ena: fix race condition between submit and completion admin command
+    - net: ena: add missing unmap bars on device removal
+    - net: ena: fix theoretical Rx hang on low memory systems
+    - net: ena: disable admin msix while working in polling mode
+    - net: ena: bug fix in lost tx packets detection mechanism
+    - net: ena: update ena driver to version 1.1.7
+    - net: ena: change return value for unsupported features unsupported return
+      value
+    - net: ena: add hardware hints capability to the driver
+    - net: ena: change sizeof() argument to be the type pointer
+    - net: ena: add reset reason for each device FLR
+    - net: ena: add support for out of order rx buffers refill
+    - net: ena: use napi_schedule_irqoff when possible
+    - net: ena: separate skb allocation to dedicated function
+    - net: ena: use lower_32_bits()/upper_32_bits() to split dma address
+    - net: ena: update driver's rx drop statistics
+    - net: ena: update ena driver to version 1.2.0
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 20 Jul 2017 09:25:21 +0200
+
+linux (4.4.0-87.110) xenial; urgency=low
+
+  * linux: 4.4.0-87.110 -proposed tracker (LP: #1704982)
+
+  * CVE-2017-1000364
+    - mm/mmap.c: do not blow on PROT_NONE MAP_FIXED holes in the stack
+    - mm/mmap.c: expand_downwards: don't require the gap if !vm_prev
+
+  * CIFS causes oops (LP: #1704857)
+    - CIFS: Fix null pointer deref during read resp processing
+    - CIFS: Fix some return values in case of error in 'crypt_message'
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 18 Jul 2017 13:58:43 +0200
+
+linux (4.4.0-86.109) xenial; urgency=low
+
+  * linux: 4.4.0-86.109 -proposed tracker (LP: #1703995)
+
+  * sock_recvmsg has dropped size argument (LP: #1701697)
+    - Packaging: Breaks unfixed iscsitarget versions
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 12 Jul 2017 18:23:18 -0300
+
+linux (4.4.0-85.108) xenial; urgency=low
+
+  * linux: 4.4.0-85.108 -proposed tracker (LP: #1702103)
+
+  * [Hyper-V] Implement Hyper-V PTP Source (LP: #1676635)
+    - SAUCE: hv: make clocksource available for PTP device supporting
+    - Drivers: hv: util: Use hv_get_current_tick() to get current tick
+    - hv_util: switch to using timespec64
+    - hv_utils: implement Hyper-V PTP source
+    - Drivers: hv: util: Fix a typo
+    - Drivers: hv: util: don't forget to init host_ts.lock
+    - hv_utils: drop .getcrosststamp() support from PTP driver
+    - hv_utils: fix TimeSync work on pre-TimeSync-v4 hosts
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 03 Jul 2017 10:50:09 -0300
+
+linux (4.4.0-84.107) xenial; urgency=low
+
+  * linux: 4.4.0-84.107 -proposed tracker (LP: #1701024)
+
+  * Can't disable USB port from BIOS (LP: #1695216)
+    - SAUCE: xhci: AMD Promontory USB disable port support
+
+  * KILLER1435-S[0489:e0a2] BT cannot search BT 4.0 device (LP: #1699651)
+    - Bluetooth: btusb: Add support for 0489:e0a2 QCA_ROME device
+
+  * CIFS: Enable encryption for SMB3 (LP: #1670508)
+    - Revert "Handle mismatched open calls"
+    - Revert "Call echo service immediately after socket reconnect"
+    - cifs: Make echo interval tunable
+    - Prepare for encryption support (first part). Add decryption and encryption
+      key generation. Thanks to Metze for helping with this.
+    - [net] drop 'size' argument of sock_recvmsg()
+    - cifs: merge the hash calculation helpers
+    - cifs: no need to wank with copying and advancing iovec on recvmsg side
+      either
+    - cifs: don't bother with kmap on read_pages side
+    - cifs_readv_receive: use cifs_read_from_socket()
+    - Fix memory leaks in cifs_do_mount()
+    - SMB3: Add mount parameter to allow user to override max credits
+    - SMB2: Separate Kerberos authentication from SMB2_sess_setup
+    - SMB2: Separate RawNTLMSSP authentication from SMB2_sess_setup
+    - SMB3: parsing for new snapshot timestamp mount parm
+    - cifs: Simplify SMB2 and SMB311 dependencies
+    - cifs: Only select the required crypto modules
+    - cifs: Add soft dependencies
+    - CIFS: Separate SMB2 header structure
+    - CIFS: Make SendReceive2() takes resp iov
+    - CIFS: Make send_cancel take rqst as argument
+    - CIFS: Send RFC1001 length in a separate iov
+    - CIFS: Separate SMB2 sync header processing
+    - CIFS: Separate RFC1001 length processing for SMB2 read
+    - CIFS: Add capability to transform requests before sending
+    - CIFS: Enable encryption during session setup phase
+    - CIFS: Encrypt SMB3 requests before sending
+    - CIFS: Add transform header handling callbacks
+    - CIFS: Add mid handle callback
+    - CIFS: Add copy into pages callback for a read operation
+    - CIFS: Decrypt and process small encrypted packets
+    - CIFS: Add capability to decrypt big read responses
+    - CIFS: Allow to switch on encryption with seal mount option
+    - CIFS: Fix possible use after free in demultiplex thread
+    - Call echo service immediately after socket reconnect
+    - Handle mismatched open calls
+
+  * CVE-2017-9150
+    - bpf: don't let ldimm64 leak map addresses on unprivileged
+
+  * CVE-2015-8944
+    - Make file credentials available to the seqfile interfaces
+    - /proc/iomem: only expose physical resource addresses to privileged users
+
+  * Xenial update to 4.4.73 stable release (LP: #1698817)
+    - s390/vmem: fix identity mapping
+    - partitions/msdos: FreeBSD UFS2 file systems are not recognized
+    - ARM: dts: imx6dl: Fix the VDD_ARM_CAP voltage for 396MHz operation
+    - staging: rtl8192e: rtl92e_fill_tx_desc fix write to mapped out memory.
+    - net: xilinx_emaclite: fix freezes due to unordered I/O
+    - net: xilinx_emaclite: fix receive buffer overflow
+    - ipv6: Handle IPv4-mapped src to in6addr_any dst.
+    - ipv6: Inhibit IPv4-mapped src address on the wire.
+    - NET: Fix /proc/net/arp for AX.25
+    - NET: mkiss: Fix panic
+    - net: hns: Fix the device being used for dma mapping during TX
+    - sierra_net: Skip validating irrelevant fields for IDLE LSIs
+    - sierra_net: Add support for IPv6 and Dual-Stack Link Sense Indications
+    - i2c: piix4: Fix request_region size
+    - ipv6: Fix IPv6 packet loss in scenarios involving roaming + snooping
+      switches
+    - PM / runtime: Avoid false-positive warnings from might_sleep_if()
+    - jump label: pass kbuild_cflags when checking for asm goto support
+    - kasan: respect /proc/sys/kernel/traceoff_on_warning
+    - log2: make order_base_2() behave correctly on const input value zero
+    - ethtool: do not vzalloc(0) on registers dump
+    - fscache: Fix dead object requeue
+    - fscache: Clear outstanding writes when disabling a cookie
+    - FS-Cache: Initialise stores_lock in netfs cookie
+    - ipv6: fix flow labels when the traffic class is non-0
+    - drm/nouveau: prevent userspace from deleting client object
+    - drm/nouveau/fence/g84-: protect against concurrent access to semaphore
+      buffers
+    - gianfar: synchronize DMA API usage by free_skb_rx_queue w/ gfar_new_page
+    - pinctrl: berlin-bg4ct: fix the value for "sd1a" of pin SCRD0_CRD_PRES
+    - net: adaptec: starfire: add checks for dma mapping errors
+    - parisc, parport_gsc: Fixes for printk continuation lines
+    - drm/nouveau: Don't enabling polling twice on runtime resume
+    - drm/ast: Fixed system hanged if disable P2A
+    - ravb: unmap descriptors when freeing rings
+    - nfs: Fix "Don't increment lock sequence ID after NFS4ERR_MOVED"
+    - r8152: re-schedule napi for tx
+    - r8152: fix rtl8152_post_reset function
+    - r8152: avoid start_xmit to schedule napi when napi is disabled
+    - sctp: sctp_addr_id2transport should verify the addr before looking up assoc
+    - romfs: use different way to generate fsid for BLOCK or MTD
+    - proc: add a schedule point in proc_pid_readdir()
+    - tipc: ignore requests when the connection state is not CONNECTED
+    - xtensa: don't use linux IRQ #0
+    - s390/kvm: do not rely on the ILC on kvm host protection fauls
+    - sparc64: make string buffers large enough
+    - Linux 4.4.73
+
+  * Xenial update to 4.4.72 stable release (LP: #1698799)
+    - bnx2x: Fix Multi-Cos
+    - ipv6: xfrm: Handle errors reported by xfrm6_find_1stfragopt()
+    - cxgb4: avoid enabling napi twice to the same queue
+    - tcp: disallow cwnd undo when switching congestion control
+    - vxlan: fix use-after-free on deletion
+    - ipv6: Fix leak in ipv6_gso_segment().
+    - net: ping: do not abuse udp_poll()
+    - net: ethoc: enable NAPI before poll may be scheduled
+    - net: bridge: start hello timer only if device is up
+    - sparc64: mm: fix copy_tsb to correctly copy huge page TSBs
+    - sparc: Machine description indices can vary
+    - sparc64: reset mm cpumask after wrap
+    - sparc64: combine activate_mm and switch_mm
+    - sparc64: redefine first version
+    - sparc64: add per-cpu mm of secondary contexts
+    - sparc64: new context wrap
+    - sparc64: delete old wrap code
+    - arch/sparc: support NR_CPUS = 4096
+    - serial: ifx6x60: fix use-after-free on module unload
+    - ptrace: Properly initialize ptracer_cred on fork
+    - KEYS: fix dereferencing NULL payload with nonzero length
+    - KEYS: fix freeing uninitialized memory in key_update()
+    - crypto: gcm - wait for crypto op not signal safe
+    - drm/amdgpu/ci: disable mclk switching for high refresh rates (v2)
+    - nfsd4: fix null dereference on replay
+    - nfsd: Fix up the "supattr_exclcreat" attributes
+    - kvm: async_pf: fix rcu_irq_enter() with irqs enabled
+    - KVM: cpuid: Fix read/write out-of-bounds vulnerability in cpuid emulation
+    - arm: KVM: Allow unaligned accesses at HYP
+    - KVM: async_pf: avoid async pf injection when in guest mode
+    - dmaengine: usb-dmac: Fix DMAOR AE bit definition
+    - dmaengine: ep93xx: Always start from BASE0
+    - xen/privcmd: Support correctly 64KB page granularity when mapping memory
+    - xen-netfront: do not cast grant table reference to signed short
+    - xen-netfront: cast grant table reference first to type int
+    - ext4: fix SEEK_HOLE
+    - ext4: keep existing extra fields when inode expands
+    - ext4: fix fdatasync(2) after extent manipulation operations
+    - usb: gadget: f_mass_storage: Serialize wake and sleep execution
+    - usb: chipidea: udc: fix NULL pointer dereference if udc_start failed
+    - usb: chipidea: debug: check before accessing ci_role
+    - staging/lustre/lov: remove set_fs() call from lov_getstripe()
+    - iio: light: ltr501 Fix interchanged als/ps register field
+    - iio: proximity: as3935: fix AS3935_INT mask
+    - drivers: char: random: add get_random_long()
+    - random: properly align get_random_int_hash
+    - stackprotector: Increase the per-task stack canary's random range from 32
+      bits to 64 bits on 64-bit platforms
+    - cpufreq: cpufreq_register_driver() should return -ENODEV if init fails
+    - target: Re-add check to reject control WRITEs with overflow data
+    - drm/msm: Expose our reservation object when exporting a dmabuf.
+    - Input: elantech - add Fujitsu Lifebook E546/E557 to force crc_enabled
+    - cpuset: consider dying css as offline
+    - fs: add i_blocksize()
+    - ufs: restore proper tail allocation
+    - fix ufs_isblockset()
+    - ufs: restore maintaining ->i_blocks
+    - ufs: set correct ->s_maxsize
+    - ufs_extend_tail(): fix the braino in calling conventions of
+      ufs_new_fragments()
+    - ufs_getfrag_block(): we only grab ->truncate_mutex on block creation path
+    - cxl: Fix error path on bad ioctl
+    - btrfs: use correct types for page indices in btrfs_page_exists_in_range
+    - btrfs: fix memory leak in update_space_info failure path
+    - KVM: arm/arm64: Handle possible NULL stage2 pud when ageing pages
+    - scsi: qla2xxx: don't disable a not previously enabled PCI device
+    - powerpc/eeh: Avoid use after free in eeh_handle_special_event()
+    - powerpc/numa: Fix percpu allocations to be NUMA aware
+    - powerpc/hotplug-mem: Fix missing endian conversion of aa_index
+    - perf/core: Drop kernel samples even though :u is specified
+    - drm/vmwgfx: Handle vmalloc() failure in vmw_local_fifo_reserve()
+    - drm/vmwgfx: Make sure backup_handle is always valid
+    - drm/nouveau/tmr: fully separate alarm execution/pending lists
+    - ALSA: timer: Fix race between read and ioctl
+    - ALSA: timer: Fix missing queue indices reset at SNDRV_TIMER_IOCTL_SELECT
+    - ASoC: Fix use-after-free at card unregistration
+    - drivers: char: mem: Fix wraparound check to allow mappings up to the end
+    - tty: Drop krefs for interrupted tty lock
+    - serial: sh-sci: Fix panic when serial console and DMA are enabled
+    - mm: consider memblock reservations for deferred memory initialization sizing
+    - NFS: Ensure we revalidate attributes before using execute_ok()
+    - NFSv4: Don't perform cached access checks before we've OPENed the file
+    - Make __xfs_xattr_put_listen preperly report errors.
+    - arm64: hw_breakpoint: fix watchpoint matching for tagged pointers
+    - arm64: entry: improve data abort handling of tagged pointers
+    - RDMA/qib,hfi1: Fix MR reference count leak on write with immediate
+    - usercopy: Adjust tests to deal with SMAP/PAN
+    - arm64: armv8_deprecated: ensure extension of addr
+    - arm64: ensure extension of smp_store_release value
+    - Linux 4.4.72
+
+  * Xenial update to 4.4.71 stable release (LP: #1697001)
+    - sparc: Fix -Wstringop-overflow warning
+    - s390/qeth: handle sysfs error during initialization
+    - s390/qeth: unbreak OSM and OSN support
+    - s390/qeth: avoid null pointer dereference on OSN
+    - tcp: avoid fragmenting peculiar skbs in SACK
+    - sctp: fix src address selection if using secondary addresses for ipv6
+    - tcp: eliminate negative reordering in tcp_clean_rtx_queue
+    - net: Improve handling of failures on link and route dumps
+    - bridge: netlink: check vlan_default_pvid range
+    - qmi_wwan: add another Lenovo EM74xx device ID
+    - bridge: start hello_timer when enabling KERNEL_STP in br_stp_start
+    - be2net: Fix offload features for Q-in-Q packets
+    - virtio-net: enable TSO/checksum offloads for Q-in-Q vlans
+    - tcp: avoid fastopen API to be used on AF_UNSPEC
+    - sctp: fix ICMP processing if skb is non-linear
+    - ipv4: add reference counting to metrics
+    - netem: fix skb_orphan_partial()
+    - net: phy: marvell: Limit errata to 88m1101
+    - vlan: Fix tcp checksum offloads in Q-in-Q vlans
+    - i2c: i2c-tiny-usb: fix buffer not being DMA capable
+    - mmc: sdhci-iproc: suppress spurious interrupt with Multiblock read
+    - HID: wacom: Have wacom_tpc_irq guard against possible NULL dereference
+    - scsi: mpt3sas: Force request partial completion alignment
+    - drm/radeon/ci: disable mclk switching for high refresh rates (v2)
+    - drm/radeon: Unbreak HPD handling for r600+
+    - pcmcia: remove left-over %Z format
+    - ALSA: hda - apply STAC_9200_DELL_M22 quirk for Dell Latitude D430
+    - slub/memcg: cure the brainless abuse of sysfs attributes
+    - drm/gma500/psb: Actually use VBT mode when it is found
+    - mm/migrate: fix refcount handling when !hugepage_migration_supported()
+    - mlock: fix mlock count can not decrease in race condition
+    - xfs: Fix missed holes in SEEK_HOLE implementation
+    - xfs: fix off-by-one on max nr_pages in xfs_find_get_desired_pgoff()
+    - xfs: fix over-copying of getbmap parameters from userspace
+    - xfs: handle array index overrun in xfs_dir2_leaf_readbuf()
+    - xfs: prevent multi-fsb dir readahead from reading random blocks
+    - xfs: fix up quotacheck buffer list error handling
+    - xfs: support ability to wait on new inodes
+    - xfs: update ag iterator to support wait on new inodes
+    - xfs: wait on new inodes during quotaoff dquot release
+    - xfs: fix indlen accounting error on partial delalloc conversion
+    - xfs: bad assertion for delalloc an extent that start at i_size
+    - xfs: fix unaligned access in xfs_btree_visit_blocks
+    - xfs: in _attrlist_by_handle, copy the cursor back to userspace
+    - xfs: only return -errno or success from attr ->put_listent
+    - Linux 4.4.71
+
+  * CVE-2017-7346
+    - drm/vmwgfx: limit the number of mip levels in vmw_gb_surface_define_ioctl()
+
+  * Power button does not work on Latitude 7480 (LP: #1697116)
+    - intel-hid: Remove duplicated acpi_remove_notify_handler
+    - platform/x86: intel-hid: Support 5 button array
+
+  * CVE-2017-9074
+    - ipv6: Check ip6_find_1stfragopt() return value properly.
+
+  * CVE-2014-9900
+    - net: Zeroing the structure ethtool_wolinfo in ethtool_get_wol()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 28 Jun 2017 14:47:02 -0300
+
+linux (4.4.0-83.106) xenial; urgency=low
+
+  * linux: 4.4.0-83.106 -proposed tracker (LP: #1700541)
+
+  * CVE-2017-1000364
+    - Revert "UBUNTU: SAUCE: mm: Only expand stack if guard area is hit"
+    - Revert "mm: do not collapse stack gap into THP"
+    - Revert "mm: enlarge stack guard gap"
+    - mm: vma_adjust: remove superfluous confusing update in remove_next == 1 case
+    - mm: larger stack guard gap, between vmas
+    - mm: fix new crash in unmapped_area_topdown()
+    - Allow stack to grow up to address space limit
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 26 Jun 2017 12:27:55 -0300
+
+linux (4.4.0-82.105) xenial; urgency=low
+
+  * linux: 4.4.0-82.105 -proposed tracker (LP: #1699064)
+
+  * CVE-2017-1000364
+    - SAUCE: mm: Only expand stack if guard area is hit
+
+  * linux-aws/linux-gke incorrectly producing and using linux-*-tools-
+    common/linux-*-cloud-tools-common (LP: #1688579)
+    - [Config] make linux-tools-common and linux-cloud-tools-common protection
+      consistent
+
+  * CVE-2017-9242
+    - ipv6: fix out of bound writes in __ip6_append_data()
+
+  * CVE-2017-9075
+    - sctp: do not inherit ipv6_{mc|ac|fl}_list from parent
+
+  * CVE-2017-9074
+    - ipv6: Prevent overrun when parsing v6 header options
+
+  * CVE-2017-9076
+    - ipv6/dccp: do not inherit ipv6_mc_list from parent
+
+  * CVE-2017-9077
+    - ipv6/dccp: do not inherit ipv6_mc_list from parent
+
+  * CVE-2017-8890
+    - dccp/tcp: do not inherit mc_list from parent
+
+  * Module signing exclusion for staging drivers does not work properly
+    (LP: #1690908)
+    - SAUCE: Fix module signing exclusion in package builds
+
+  * extend-diff-ignore should use exact matches (LP: #1693504)
+    - [Packaging] exact extend-diff-ignore matches
+
+  * Dell XPS 9360 wifi 5G performance is poor (LP: #1692836)
+    - SAUCE: ath10k: fix the wifi speed issue for kill 1535
+
+  *  Upgrade Redpine WLAN/BT driver to ver. 1.2.RC12 (LP: #1694607)
+    - SAUCE: Redpine: Upgrade to ver. 1.2.RC12
+
+  * [DP MST] No audio output through HDMI/DP/mDP ports in Dell WD15 and TB15
+    docking stations (LP: #1694665)
+    - drm/i915: Store port enum in intel_encoder
+    - drm/i915: Eliminate redundant local variable definition
+    - drm/i915: Switch to using port stored in intel_encoder
+    - drm/i915: Move audio_connector to intel_encoder
+    - drm/i915/dp: DP audio API changes for MST
+    - drm/i915: abstract ddi being audio enabled
+    - drm/i915/audio: extend get_saved_enc() to support more scenarios
+    - drm/i915: enable dp mst audio
+
+  * Xenial update to 4.4.70 stable release (LP: #1694621)
+    - usb: misc: legousbtower: Fix buffers on stack
+    - usb: misc: legousbtower: Fix memory leak
+    - USB: ene_usb6250: fix DMA to the stack
+    - watchdog: pcwd_usb: fix NULL-deref at probe
+    - char: lp: fix possible integer overflow in lp_setup()
+    - USB: core: replace %p with %pK
+    - ARM: tegra: paz00: Mark panel regulator as enabled on boot
+    - tpm_crb: check for bad response size
+    - infiniband: call ipv6 route lookup via the stub interface
+    - dm btree: fix for dm_btree_find_lowest_key()
+    - dm raid: select the Kconfig option CONFIG_MD_RAID0
+    - dm bufio: avoid a possible ABBA deadlock
+    - dm bufio: check new buffer allocation watermark every 30 seconds
+    - dm cache metadata: fail operations if fail_io mode has been established
+    - dm bufio: make the parameter "retain_bytes" unsigned long
+    - dm thin metadata: call precommit before saving the roots
+    - dm space map disk: fix some book keeping in the disk space map
+    - md: update slab_cache before releasing new stripes when stripes resizing
+    - rtlwifi: rtl8821ae: setup 8812ae RFE according to device type
+    - mwifiex: pcie: fix cmd_buf use-after-free in remove/reset
+    - ima: accept previously set IMA_NEW_FILE
+    - KVM: x86: Fix load damaged SSEx MXCSR register
+    - KVM: X86: Fix read out-of-bounds vulnerability in kvm pio emulation
+    - regulator: tps65023: Fix inverted core enable logic.
+    - s390/kdump: Add final note
+    - s390/cputime: fix incorrect system time
+    - ath9k_htc: Add support of AirTies 1eda:2315 AR9271 device
+    - ath9k_htc: fix NULL-deref at probe
+    - drm/amdgpu: Avoid overflows/divide-by-zero in latency_watermark
+      calculations.
+    - drm/amdgpu: Make display watermark calculations more accurate
+    - drm/nouveau/therm: remove ineffective workarounds for alarm bugs
+    - drm/nouveau/tmr: ack interrupt before processing alarms
+    - drm/nouveau/tmr: fix corruption of the pending list when rescheduling an
+      alarm
+    - drm/nouveau/tmr: avoid processing completed alarms when adding a new one
+    - drm/nouveau/tmr: handle races with hw when updating the next alarm time
+    - cdc-acm: fix possible invalid access when processing notification
+    - proc: Fix unbalanced hard link numbers
+    - of: fix sparse warning in of_pci_range_parser_one
+    - iio: dac: ad7303: fix channel description
+    - pid_ns: Sleep in TASK_INTERRUPTIBLE in zap_pid_ns_processes
+    - pid_ns: Fix race between setns'ed fork() and zap_pid_ns_processes()
+    - USB: serial: ftdi_sio: fix setting latency for unprivileged users
+    - USB: serial: ftdi_sio: add Olimex ARM-USB-TINY(H) PIDs
+    - ext4 crypto: don't let data integrity writebacks fail with ENOMEM
+    - ext4 crypto: fix some error handling
+    - net: qmi_wwan: Add SIMCom 7230E
+    - fscrypt: fix context consistency check when key(s) unavailable
+    - f2fs: check entire encrypted bigname when finding a dentry
+    - fscrypt: avoid collisions when presenting long encrypted filenames
+    - usb: host: xhci-plat: propagate return value of platform_get_irq()
+    - xhci: apply PME_STUCK_QUIRK and MISSING_CAS quirk for Denverton
+    - usb: host: xhci-mem: allocate zeroed Scratchpad Buffer
+    - net: irda: irda-usb: fix firmware name on big-endian hosts
+    - usbvision: fix NULL-deref at probe
+    - mceusb: fix NULL-deref at probe
+    - ttusb2: limit messages to buffer size
+    - usb: musb: tusb6010_omap: Do not reset the other direction's packet size
+    - USB: iowarrior: fix info ioctl on big-endian hosts
+    - usb: serial: option: add Telit ME910 support
+    - USB: serial: qcserial: add more Lenovo EM74xx device IDs
+    - USB: serial: mct_u232: fix big-endian baud-rate handling
+    - USB: serial: io_ti: fix div-by-zero in set_termios
+    - USB: hub: fix SS hub-descriptor handling
+    - USB: hub: fix non-SS hub-descriptor handling
+    - ipx: call ipxitf_put() in ioctl error path
+    - iio: proximity: as3935: fix as3935_write
+    - ceph: fix recursion between ceph_set_acl() and __ceph_setattr()
+    - gspca: konica: add missing endpoint sanity check
+    - s5p-mfc: Fix unbalanced call to clock management
+    - dib0700: fix NULL-deref at probe
+    - zr364xx: enforce minimum size when reading header
+    - dvb-frontends/cxd2841er: define symbol_rate_min/max in T/C fe-ops
+    - cx231xx-audio: fix init error path
+    - cx231xx-audio: fix NULL-deref at probe
+    - cx231xx-cards: fix NULL-deref at probe
+    - powerpc/book3s/mce: Move add_taint() later in virtual mode
+    - powerpc/pseries: Fix of_node_put() underflow during DLPAR remove
+    - powerpc/64e: Fix hang when debugging programs with relocated kernel
+    - ARM: dts: at91: sama5d3_xplained: fix ADC vref
+    - ARM: dts: at91: sama5d3_xplained: not all ADC channels are available
+    - arm64: xchg: hazard against entire exchange variable
+    - arm64: uaccess: ensure extension of access_ok() addr
+    - arm64: documentation: document tagged pointer stack constraints
+    - xc2028: Fix use-after-free bug properly
+    - Revert "UBUNTU: SAUCE: mm: Respect FOLL_FORCE/FOLL_COW for thp"
+    - mm/huge_memory.c: respect FOLL_FORCE/FOLL_COW for thp
+    - staging: rtl8192e: fix 2 byte alignment of register BSSIDR.
+    - staging: rtl8192e: rtl92e_get_eeprom_size Fix read size of EPROM_CMD.
+    - iommu/vt-d: Flush the IOTLB to get rid of the initial kdump mappings
+    - metag/uaccess: Fix access_ok()
+    - metag/uaccess: Check access_ok in strncpy_from_user
+    - uwb: fix device quirk on big-endian hosts
+    - genirq: Fix chained interrupt data ordering
+    - osf_wait4(): fix infoleak
+    - tracing/kprobes: Enforce kprobes teardown after testing
+    - PCI: Fix pci_mmap_fits() for HAVE_PCI_RESOURCE_TO_USER platforms
+    - PCI: Freeze PME scan before suspending devices
+    - drm/edid: Add 10 bpc quirk for LGD 764 panel in HP zBook 17 G2
+    - nfsd: encoders mustn't use unitialized values in error cases
+    - drivers: char: mem: Check for address space wraparound with mmap()
+    - Linux 4.4.70
+
+  * Xenial update to 4.4.69 stable release (LP: #1692900)
+    - xen: adjust early dom0 p2m handling to xen hypervisor behavior
+    - target: Fix compare_and_write_callback handling for non GOOD status
+    - target/fileio: Fix zero-length READ and WRITE handling
+    - target: Convert ACL change queue_depth se_session reference usage
+    - iscsi-target: Set session_fall_back_to_erl0 when forcing reinstatement
+    - usb: host: xhci: print correct command ring address
+    - USB: serial: ftdi_sio: add device ID for Microsemi/Arrow SF2PLUS Dev Kit
+    - USB: Proper handling of Race Condition when two USB class drivers try to
+      call init_usb_class simultaneously
+    - staging: vt6656: use off stack for in buffer USB transfers.
+    - staging: vt6656: use off stack for out buffer USB transfers.
+    - staging: gdm724x: gdm_mux: fix use-after-free on module unload
+    - staging: comedi: jr3_pci: fix possible null pointer dereference
+    - staging: comedi: jr3_pci: cope with jiffies wraparound
+    - usb: misc: add missing continue in switch
+    - usb: Make sure usb/phy/of gets built-in
+    - usb: hub: Fix error loop seen after hub communication errors
+    - usb: hub: Do not attempt to autosuspend disconnected devices
+    - x86/boot: Fix BSS corruption/overwrite bug in early x86 kernel startup
+    - selftests/x86/ldt_gdt_32: Work around a glibc sigaction() bug
+    - x86, pmem: Fix cache flushing for iovec write < 8 bytes
+    - um: Fix PTRACE_POKEUSER on x86_64
+    - KVM: x86: fix user triggerable warning in kvm_apic_accept_events()
+    - KVM: arm/arm64: fix races in kvm_psci_vcpu_on
+    - block: fix blk_integrity_register to use template's interval_exp if not 0
+    - crypto: algif_aead - Require setkey before accept(2)
+    - dm era: save spacemap metadata root after the pre-commit
+    - vfio/type1: Remove locked page accounting workqueue
+    - IB/core: Fix sysfs registration error flow
+    - IB/IPoIB: ibX: failed to create mcg debug file
+    - IB/mlx4: Fix ib device initialization error flow
+    - IB/mlx4: Reduce SRIOV multicast cleanup warning message to debug level
+    - ext4: evict inline data when writing to memory map
+    - fs/xattr.c: zero out memory copied to userspace in getxattr
+    - ceph: fix memory leak in __ceph_setxattr()
+    - fs/block_dev: always invalidate cleancache in invalidate_bdev()
+    - Set unicode flag on cifs echo request to avoid Mac error
+    - SMB3: Work around mount failure when using SMB3 dialect to Macs
+    - CIFS: fix mapping of SFM_SPACE and SFM_PERIOD
+    - cifs: fix CIFS_IOC_GET_MNT_INFO oops
+    - CIFS: add misssing SFM mapping for doublequote
+    - padata: free correct variable
+    - arm64: KVM: Fix decoding of Rt/Rt2 when trapping AArch32 CP accesses
+    - serial: samsung: Use right device for DMA-mapping calls
+    - serial: omap: fix runtime-pm handling on unbind
+    - serial: omap: suspend device on probe errors
+    - tty: pty: Fix ldisc flush after userspace become aware of the data already
+    - Bluetooth: Fix user channel for 32bit userspace on 64bit kernel
+    - Bluetooth: hci_bcm: add missing tty-device sanity check
+    - Bluetooth: hci_intel: add missing tty-device sanity check
+    - mac80211: pass RX aggregation window size to driver
+    - mac80211: pass block ack session timeout to to driver
+    - mac80211: RX BA support for sta max_rx_aggregation_subframes
+    - wlcore: Pass win_size taken from ieee80211_sta to FW
+    - wlcore: Add RX_BA_WIN_SIZE_CHANGE_EVENT event
+    - ipmi: Fix kernel panic at ipmi_ssif_thread()
+    - Linux 4.4.69
+
+  * Support IPMI system interface on Cavium ThunderX (LP: #1688132)
+    - i2c: octeon: Cleanup kerneldoc comments
+    - i2c: octeon: Cleanup i2c-octeon driver
+    - i2c: octeon: Cleanup resource allocation code
+    - i2c: octeon: Support I2C_M_RECV_LEN
+    - i2c: octeon: Increase retry default and use fixed timeout value
+    - i2c: octeon: Move set-clock and init-lowlevel upward
+    - i2c: octeon: Rename [read|write]_sw to reg_[read|write]
+    - i2c: octeon: Introduce helper functions for register access
+    - i2c: octeon: Remove superfluous check in octeon_i2c_test_iflg
+    - i2c: octeon: Improve error status checking
+    - i2c: octeon: Use i2c recovery framework
+    - i2c: octeon: Add flush writeq helper function
+    - i2c: octeon: Enable High-Level Controller
+    - i2c: octeon: Add support for cn78xx chips
+    - i2c: octeon: Remove zero-length message support
+    - i2c: octeon: Improve performance if interrupt is early
+    - i2c: octeon: Add workaround for broken irqs on CN3860
+    - i2c: octeon: Missing AAK flag in case of I2C_M_RECV_LEN
+    - i2c: octeon: Avoid printk after too long SMBUS message
+    - i2c: octeon: Rename driver to prepare for split
+    - i2c: octeon: Split the driver into two parts
+    - [Config] CONFIG_I2C_THUNDERX=m
+    - i2c: thunderx: Add i2c driver for ThunderX SOC
+    - i2c: thunderx: Add SMBUS alert support
+    - i2c: octeon,thunderx: Move register offsets to struct
+    - i2c: octeon: Sort include files alphabetically
+    - i2c: octeon: Use booleon values for booleon variables
+    - i2c: octeon: thunderx: Add MAINTAINERS entry
+    - i2c: octeon: Fix set SCL recovery function
+    - i2c: octeon: Avoid sending STOP during recovery
+    - i2c: octeon: Fix high-level controller status check
+    - i2c: octeon: thunderx: TWSI software reset in recovery
+    - i2c: octeon: thunderx: Remove double-check after interrupt
+    - i2c: octeon: thunderx: Limit register access retries
+    - i2c: thunderx: Enable HWMON class probing
+
+  * Xenial update to 4.4.68 stable release (LP: #1691418)
+    - 9p: fix a potential acl leak
+    - ARM: 8452/3: PJ4: make coprocessor access sequences buildable in Thumb2 mode
+    - cpupower: Fix turbo frequency reporting for pre-Sandy Bridge cores
+    - powerpc/powernv: Fix opal_exit tracepoint opcode
+    - power: supply: bq24190_charger: Fix irq trigger to IRQF_TRIGGER_FALLING
+    - power: supply: bq24190_charger: Call set_mode_host() on pm_resume()
+    - power: supply: bq24190_charger: Install irq_handler_thread() at end of
+      probe()
+    - power: supply: bq24190_charger: Call power_supply_changed() for relevant
+      component
+    - power: supply: bq24190_charger: Don't read fault register outside
+      irq_handle_thread()
+    - power: supply: bq24190_charger: Handle fault before status on interrupt
+    - leds: ktd2692: avoid harmless maybe-uninitialized warning
+    - ARM: OMAP5 / DRA7: Fix HYP mode boot for thumb2 build
+    - mwifiex: debugfs: Fix (sometimes) off-by-1 SSID print
+    - mwifiex: remove redundant dma padding in AMSDU
+    - mwifiex: Avoid skipping WEP key deletion for AP
+    - x86/ioapic: Restore IO-APIC irq_chip retrigger callback
+    - x86/pci-calgary: Fix iommu_free() comparison of unsigned expression >= 0
+    - clk: Make x86/ conditional on CONFIG_COMMON_CLK
+    - kprobes/x86: Fix kernel panic when certain exception-handling addresses are
+      probed
+    - x86/platform/intel-mid: Correct MSI IRQ line for watchdog device
+    - Revert "KVM: nested VMX: disable perf cpuid reporting"
+    - KVM: nVMX: initialize PML fields in vmcs02
+    - KVM: nVMX: do not leak PML full vmexit to L1
+    - usb: host: ehci-exynos: Decrese node refcount on exynos_ehci_get_phy() error
+      paths
+    - usb: host: ohci-exynos: Decrese node refcount on exynos_ehci_get_phy() error
+      paths
+    - usb: chipidea: Only read/write OTGSC from one place
+    - usb: chipidea: Handle extcon events properly
+    - USB: serial: keyspan_pda: fix receive sanity checks
+    - USB: serial: digi_acceleport: fix incomplete rx sanity check
+    - USB: serial: ssu100: fix control-message error handling
+    - USB: serial: io_edgeport: fix epic-descriptor handling
+    - USB: serial: ti_usb_3410_5052: fix control-message error handling
+    - USB: serial: ark3116: fix open error handling
+    - USB: serial: ftdi_sio: fix latency-timer error handling
+    - USB: serial: quatech2: fix control-message error handling
+    - USB: serial: mct_u232: fix modem-status error handling
+    - USB: serial: io_edgeport: fix descriptor error handling
+    - phy: qcom-usb-hs: Add depends on EXTCON
+    - serial: 8250_omap: Fix probe and remove for PM runtime
+    - scsi: mac_scsi: Fix MAC_SCSI=m option when SCSI=m
+    - MIPS: R2-on-R6 MULTU/MADDU/MSUBU emulation bugfix
+    - brcmfmac: Ensure pointer correctly set if skb data location changes
+    - brcmfmac: Make skb header writable before use
+    - staging: wlan-ng: add missing byte order conversion
+    - staging: emxx_udc: remove incorrect __init annotations
+    - ALSA: hda - Fix deadlock of controller device lock at unbinding
+    - tcp: do not underestimate skb->truesize in tcp_trim_head()
+    - bpf, arm64: fix jit branch offset related to ldimm64
+    - tcp: fix wraparound issue in tcp_lp
+    - tcp: do not inherit fastopen_req from parent
+    - ipv4, ipv6: ensure raw socket message is big enough to hold an IP header
+    - rtnetlink: NUL-terminate IFLA_PHYS_PORT_NAME string
+    - ipv6: initialize route null entry in addrconf_init()
+    - ipv6: reorder ip6_route_dev_notifier after ipv6_dev_notf
+    - bnxt_en: allocate enough space for ->ntp_fltr_bmap
+    - f2fs: sanity check segment count
+    - drm/ttm: fix use-after-free races in vm fault handling
+    - block: get rid of blk_integrity_revalidate()
+    - Linux 4.4.68
+
+  * Keyboard backlight control does not work on some dell laptops.
+    (LP: #1693126)
+    - platform/x86: dell-laptop: Add Latitude 7480 and others to the DMI whitelist
+    - platform/x86: dell-laptop: Add keyboard backlight timeout AC settings
+
+  * Upgrade Redpine WLAN/BT driver to ver. 1.2.RC9 (LP: #1690498)
+    - SAUCE: Redpine: Upgrade to ver. 1.2.RC9
+
+  * exec'ing a setuid binary from a threaded program sometimes fails to setuid
+    (LP: #1672819)
+    - SAUCE: exec: ensure file system accounting in check_unsafe_exec is correct
+
+  * attempts to rename vlans / vlans have addr_assign_type of 0 on kernel 4.4
+    (LP: #1682871)
+    - vlan: Propagate MAC address to VLANs
+
+  * Exar usb-serial doesn't restore baud rate after resume from S3/S4
+    (LP: #1690362)
+    - SAUCE: xr-usb-serial: re-initialise baudrate after resume from S3/S4
+
+  * st_pressure, st_accel IIO drivers fail to detect sensors after reloading
+    kernel modules (LP: #1690310)
+    - SAUCE: (no-up) iio: st_pressure: st_accel: Initialise sensor platform data
+      properly
+
+  * nvidia-docker on ppc64le-ubuntu16.04  issue due to cross-thread naming if
+    !PR_DUMPABLE (LP: #1690225)
+    - procfs: fix pthread cross-thread naming if !PR_DUMPABLE
+
+  * linux xenial derivatives fail to build (LP: #1691814)
+    - [Packaging] Set do_tools_common in common vars
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 20 Jun 2017 15:47:03 +0200
+
+linux (4.4.0-81.104) xenial; urgency=low
+
+  * CVE-2017-1000364
+    - mm: enlarge stack guard gap
+    - mm: do not collapse stack gap into THP
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 08 Jun 2017 15:19:41 +0200
+
+linux (4.4.0-79.100) xenial; urgency=low
+
+  * linux: 4.4.0-79.100 -proposed tracker (LP: #1691180)
+
+  * linux-aws/linux-gke incorrectly producing and using linux-*-tools-
+    common/linux-*-cloud-tools-common (LP: #1688579)
+    - [Config] make linux-tools-common and linux-cloud-tools-common provide linux-
+      gke versions
+    - [Config] make linux-tools-common and linux-cloud-tools-common provide linux-
+      aws versions
+    - [Packaging] prevent linux-*-tools-common from being produced from non linux
+      packages
+
+  * CVE-2017-0605
+    - tracing: Use strlcpy() instead of strcpy() in __trace_find_cmdline()
+
+  * i915-bpo crashes on external hdmi input (LP: #1580272)
+    - SAUCE: i915_bpo: Silence the warning about watermark entries not changing
+
+  * Kernel panics on Xenial when using cgroups and strict CFS limits
+    (LP: #1687512)
+    - sched/fair: Initialize throttle_count for new task-groups lazily
+    - sched/fair: Do not announce throttled next buddy in dequeue_task_fair()
+
+  * bonding - mlx5 - speed changed to 0 after changing ring size  (LP: #1687877)
+    - bonding: allow notifications for bond_set_slave_link_state
+
+  * Xenial update to 4.4.67 stable release (LP: #1689296)
+    - timerfd: Protect the might cancel mechanism proper
+    - Handle mismatched open calls
+    - ASoC: intel: Fix PM and non-atomic crash in bytcr drivers
+    - ALSA: ppc/awacs: shut up maybe-uninitialized warning
+    - drbd: avoid redefinition of BITS_PER_PAGE
+    - mtd: avoid stack overflow in MTD CFI code
+    - net: tg3: avoid uninitialized variable warning
+    - netlink: Allow direct reclaim for fallback allocation
+    - IB/qib: rename BITS_PER_PAGE to RVT_BITS_PER_PAGE
+    - IB/ehca: fix maybe-uninitialized warnings
+    - ext4: require encryption feature for EXT4_IOC_SET_ENCRYPTION_POLICY
+    - ext4 crypto: revalidate dentry after adding or removing the key
+    - ext4 crypto: use dget_parent() in ext4_d_revalidate()
+    - ext4/fscrypto: avoid RCU lookup in d_revalidate
+    - nfsd4: minor NFSv2/v3 write decoding cleanup
+    - nfsd: stricter decoding of write-like NFSv2/v3 ops
+    - dm ioctl: prevent stack leak in dm ioctl call
+    - Linux 4.4.67
+
+  * Precision Rack failed to resume from S4 (LP: #1686061)
+    - x86 / hibernate: Use hlt_play_dead() when resuming from hibernation
+    - x86/boot: Split out kernel_ident_mapping_init()
+    - x86/power/64: Always create temporary identity mapping correctly
+
+  * Xenial update to 4.4.66 stable release (LP: #1688505)
+    - f2fs: do more integrity verification for superblock
+    - xc2028: unlock on error in xc2028_set_config()
+    - ARM: OMAP2+: timer: add probe for clocksources
+    - clk: sunxi: Add apb0 gates for H3
+    - crypto: testmgr - fix out of bound read in __test_aead()
+    - drm/amdgpu: fix array out of bounds
+    - ext4: check if in-inode xattr is corrupted in ext4_expand_extra_isize_ea()
+    - md:raid1: fix a dead loop when read from a WriteMostly disk
+    - MIPS: Fix crash registers on non-crashing CPUs
+    - net: cavium: liquidio: Avoid dma_unmap_single on uninitialized ndata
+    - net_sched: close another race condition in tcf_mirred_release()
+    - RDS: Fix the atomicity for congestion map update
+    - regulator: core: Clear the supply pointer if enabling fails
+    - usb: gadget: f_midi: Fixed a bug when buflen was smaller than wMaxPacketSize
+    - xen/x86: don't lose event interrupts
+    - sparc64: kern_addr_valid regression
+    - sparc64: Fix kernel panic due to erroneous #ifdef surrounding pmd_write()
+    - net: neigh: guard against NULL solicit() method
+    - net: phy: handle state correctly in phy_stop_machine
+    - l2tp: purge socket queues in the .destruct() callback
+    - l2tp: take reference on sessions being dumped
+    - l2tp: fix PPP pseudo-wire auto-loading
+    - net: ipv4: fix multipath RTM_GETROUTE behavior when iif is given
+    - sctp: listen on the sock only when it's state is listening or closed
+    - tcp: clear saved_syn in tcp_disconnect()
+    - dp83640: don't recieve time stamps twice
+    - net: ipv6: RTF_PCPU should not be settable from userspace
+    - netpoll: Check for skb->queue_mapping
+    - ip6mr: fix notification device destruction
+    - macvlan: Fix device ref leak when purging bc_queue
+    - ipv6: check skb->protocol before lookup for nexthop
+    - ipv6: check raw payload size correctly in ioctl
+    - ALSA: firewire-lib: fix inappropriate assignment between signed/unsigned
+      type
+    - ALSA: seq: Don't break snd_use_lock_sync() loop by timeout
+    - MIPS: KGDB: Use kernel context for sleeping threads
+    - MIPS: Avoid BUG warning in arch_check_elf
+    - p9_client_readdir() fix
+    - Input: i8042 - add Clevo P650RS to the i8042 reset list
+    - nfsd: check for oversized NFSv2/v3 arguments
+    - ARCv2: save r30 on kernel entry as gcc uses it for code-gen
+    - ftrace/x86: Fix triple fault with graph tracing and suspend-to-ram
+    - Linux 4.4.66
+
+  * Xenial update to 4.4.65 stable release (LP: #1688483)
+    - tipc: make sure IPv6 header fits in skb headroom
+    - tipc: make dist queue pernet
+    - tipc: re-enable compensation for socket receive buffer double counting
+    - tipc: correct error in node fsm
+    - tty: nozomi: avoid a harmless gcc warning
+    - hostap: avoid uninitialized variable use in hfa384x_get_rid
+    - gfs2: avoid uninitialized variable warning
+    - tipc: fix random link resets while adding a second bearer
+    - tipc: fix socket timer deadlock
+    - xc2028: avoid use after free
+    - netfilter: nfnetlink: correctly validate length of batch messages
+    - tipc: check minimum bearer MTU
+    - vfio/pci: Fix integer overflows, bitmask check
+    - staging/android/ion : fix a race condition in the ion driver
+    - ping: implement proper locking
+    - perf/core: Fix concurrent sys_perf_event_open() vs. 'move_group' race
+    - Linux 4.4.65
+
+  * Xenial update to 4.4.64 stable release (LP: #1687638)
+    - KEYS: Disallow keyrings beginning with '.' to be joined as session keyrings
+    - KEYS: Change the name of the dead type to ".dead" to prevent user access
+    - KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings
+    - tracing: Allocate the snapshot buffer before enabling probe
+    - ring-buffer: Have ring_buffer_iter_empty() return true when empty
+    - cifs: Do not send echoes before Negotiate is complete
+    - CIFS: remove bad_network_name flag
+    - s390/mm: fix CMMA vs KSM vs others
+    - VSOCK: Detach QP check should filter out non matching QPs.
+    - Input: elantech - add Fujitsu Lifebook E547 to force crc_enabled
+    - ACPI / power: Avoid maybe-uninitialized warning
+    - mmc: sdhci-esdhc-imx: increase the pad I/O drive strength for DDR50 card
+    - mac80211: reject ToDS broadcast data frames
+    - ubi/upd: Always flush after prepared for an update
+    - powerpc/kprobe: Fix oops when kprobed on 'stdu' instruction
+    - x86/mce/AMD: Give a name to MCA bank 3 when accessed with legacy MSRs
+    - kvm: arm/arm64: Fix locking for kvm_free_stage2_pgd
+    - x86, pmem: fix broken __copy_user_nocache cache-bypass assumptions
+    - block: fix del_gendisk() vs blkdev_ioctl crash
+    - tipc: fix crash during node removal
+    - Linux 4.4.64
+
+  * Xenial update to 4.4.63 stable release (LP: #1687629)
+    - cgroup, kthread: close race window where new kthreads can be migrated to
+      non-root cgroups
+    - thp: fix MADV_DONTNEED vs clear soft dirty race
+    - drm/nouveau/mpeg: mthd returns true on success now
+    - drm/nouveau/mmu/nv4a: use nv04 mmu rather than the nv44 one
+    - CIFS: store results of cifs_reopen_file to avoid infinite wait
+    - Input: xpad - add support for Razer Wildcat gamepad
+    - perf/x86: Avoid exposing wrong/stale data in intel_pmu_lbr_read_32()
+    - x86/vdso: Ensure vdso32_enabled gets set to valid values only
+    - x86/vdso: Plug race between mapping and ELF header setup
+    - acpi, nfit, libnvdimm: fix interleave set cookie calculation (64-bit
+      comparison)
+    - iscsi-target: Fix TMR reference leak during session shutdown
+    - iscsi-target: Drop work-around for legacy GlobalSAN initiator
+    - scsi: sr: Sanity check returned mode data
+    - scsi: sd: Consider max_xfer_blocks if opt_xfer_blocks is unusable
+    - scsi: sd: Fix capacity calculation with 32-bit sector_t
+    - xen, fbfront: fix connecting to backend
+    - libnvdimm: fix reconfig_mutex, mmap_sem, and jbd2_handle lockdep splat
+    - irqchip/irq-imx-gpcv2: Fix spinlock initialization
+    - ftrace: Fix removing of second function probe
+    - char: Drop bogus dependency of DEVPORT on !M68K
+    - char: lack of bool string made CONFIG_DEVPORT always on
+    - Revert "MIPS: Lantiq: Fix cascaded IRQ setup"
+    - kvm: fix page struct leak in handle_vmon
+    - zram: do not use copy_page with non-page aligned address
+    - powerpc: Disable HFSCR[TM] if TM is not supported
+    - crypto: ahash - Fix EINPROGRESS notification callback
+    - ath9k: fix NULL pointer dereference
+    - dvb-usb-v2: avoid use-after-free
+    - ext4: fix inode checksum calculation problem if i_extra_size is small
+    - platform/x86: acer-wmi: setup accelerometer when machine has appropriate
+      notify event
+    - rtc: tegra: Implement clock handling
+    - mm: Tighten x86 /dev/mem with zeroing reads
+    - dvb-usb: don't use stack for firmware load
+    - dvb-usb-firmware: don't do DMA on stack
+    - virtio-console: avoid DMA from stack
+    - pegasus: Use heap buffers for all register access
+    - rtl8150: Use heap buffers for all register access
+    - catc: Combine failure cleanup code in catc_probe()
+    - catc: Use heap buffer for memory size test
+    - tty/serial: atmel: RS485 half duplex w/DMA: enable RX after TX is done
+    - net: ipv6: check route protocol when deleting routes
+    - MIPS: fix Select HAVE_IRQ_EXIT_ON_IRQ_STACK patch.
+    - Linux 4.4.63
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 17 May 2017 16:44:58 +0200
+
+linux (4.4.0-78.99) xenial; urgency=low
+
+  * linux: 4.4.0-78.99 -proposed tracker (LP: #1686645)
+
+  * Please backport fix to reference leak in cgroup blkio throttle
+    (LP: #1683976)
+    - block: fix module reference leak on put_disk() call for cgroups throttle
+
+  * UbuntuKVM guest crashed while running I/O stress test with Ubuntu kernel
+    4.4.0-47-generic (LP: #1659111)
+    - block: Unhash block device inodes on gendisk destruction
+    - block: Use pointer to backing_dev_info from request_queue
+    - block: Dynamically allocate and refcount backing_dev_info
+    - block: Make blk_get_backing_dev_info() safe without open bdev
+    - block: Get rid of blk_get_backing_dev_info()
+    - block: Move bdev_unhash_inode() after invalidate_partition()
+    - block: Unhash also block device inode for the whole device
+    - block: Revalidate i_bdev reference in bd_aquire()
+    - block: Initialize bd_bdi on inode initialization
+    - block: Move bdi_unregister() to del_gendisk()
+    - block: Allow bdi re-registration
+    - bdi: Fix use-after-free in wb_congested_put()
+    - block: Make del_gendisk() safer for disks without queues
+    - block: Fix bdi assignment to bdev inode when racing with disk delete
+    - bdi: Mark congested->bdi as internal
+    - bdi: Make wb->bdi a proper reference
+    - bdi: Unify bdi->wb_list handling for root wb_writeback
+    - bdi: Shutdown writeback on all cgwbs in cgwb_bdi_destroy()
+    - bdi: Do not wait for cgwbs release in bdi_unregister()
+    - bdi: Rename cgwb_bdi_destroy() to cgwb_bdi_unregister()
+    - block: Fix oops in locked_inode_to_wb_and_lock_list()
+    - kobject: Export kobject_get_unless_zero()
+    - block: Fix oops scsi_disk_get()
+
+  * Touchpad not working correctly after kernel upgrade (LP: #1662589)
+    - Input: ALPS - fix V8+ protocol handling (73 03 28)
+
+  * Xenial update to v4.4.62 stable release (LP: #1683728)
+    - drm/i915: Avoid tweaking evaluation thresholds on Baytrail v3
+    - drm/i915: Stop using RP_DOWN_EI on Baytrail
+    - usb: dwc3: gadget: delay unmap of bounced requests
+    - mtd: bcm47xxpart: fix parsing first block after aligned TRX
+    - MIPS: Introduce irq_stack
+    - MIPS: Stack unwinding while on IRQ stack
+    - MIPS: Only change $28 to thread_info if coming from user mode
+    - MIPS: Switch to the irq_stack in interrupts
+    - MIPS: Select HAVE_IRQ_EXIT_ON_IRQ_STACK
+    - MIPS: IRQ Stack: Fix erroneous jal to plat_irq_dispatch
+    - crypto: caam - fix RNG deinstantiation error checking
+    - Linux 4.4.62
+
+  * ifup service of network device stay active after driver stop (LP: #1672144)
+    - net: use net->count to check whether a netns is alive or not
+
+  * [Hyper-V] mkfs regression in kernel 4.4+ (LP: #1682215)
+    - block: relax check on sg gap
+
+  * [Feature] KBL: intel_powerclamp driver support (LP: #1591641)
+    - thermal/powerclamp: remove cpu whitelist
+    - thermal/powerclamp: correct cpu support check
+    - thermal/powerclamp: add back module device table
+
+  * sysfs channel reads of lps22hb pressure sensor are stale (LP: #1682103)
+    - iio: st_pressure: initialize lps22hb bootime
+
+  * Backlight control does not work and there are no entries in
+    /sys/class/backlight (LP: #1667323)
+    - Revert "ACPI / video: Add force_native quirk for HP Pavilion dv6"
+
+  * [Feature] KBL: intel_rapl driver support (LP: #1591640)
+    - powercap/intel_rapl: Add support for Kabylake
+
+  * Xenial update to v4.4.61 stable release (LP: #1682140)
+    - drm/vmwgfx: Type-check lookups of fence objects
+    - drm/vmwgfx: NULL pointer dereference in vmw_surface_define_ioctl()
+    - drm/vmwgfx: avoid calling vzalloc with a 0 size in vmw_get_cap_3d_ioctl()
+    - drm/ttm, drm/vmwgfx: Relax permission checking when opening surfaces
+    - drm/vmwgfx: Remove getparam error message
+    - drm/vmwgfx: fix integer overflow in vmw_surface_define_ioctl()
+    - sysfs: be careful of error returns from ops->show()
+    - staging: android: ashmem: lseek failed due to no FMODE_LSEEK.
+    - arm/arm64: KVM: Take mmap_sem in stage2_unmap_vm
+    - arm/arm64: KVM: Take mmap_sem in kvm_arch_prepare_memory_region
+    - iio: bmg160: reset chip when probing
+    - Reset TreeId to zero on SMB2 TREE_CONNECT
+    - ptrace: fix PTRACE_LISTEN race corrupting task->state
+    - ring-buffer: Fix return value check in test_ringbuffer()
+    - metag/usercopy: Drop unused macros
+    - metag/usercopy: Fix alignment error checking
+    - metag/usercopy: Add early abort to copy_to_user
+    - metag/usercopy: Zero rest of buffer from copy_from_user
+    - metag/usercopy: Set flags before ADDZ
+    - metag/usercopy: Fix src fixup in from user rapf loops
+    - metag/usercopy: Add missing fixups
+    - powerpc/mm: Add missing global TLB invalidate if cxl is active
+    - powerpc: Don't try to fix up misaligned load-with-reservation instructions
+    - nios2: reserve boot memory for device tree
+    - s390/decompressor: fix initrd corruption caused by bss clear
+    - s390/uaccess: get_user() should zero on failure (again)
+    - MIPS: Force o32 fp64 support on 32bit MIPS64r6 kernels
+    - MIPS: ralink: Fix typos in rt3883 pinctrl
+    - MIPS: End spinlocks with .insn
+    - MIPS: Lantiq: fix missing xbar kernel panic
+    - MIPS: Flush wrong invalid FTLB entry for huge page
+    - mm/mempolicy.c: fix error handling in set_mempolicy and mbind.
+    - Linux 4.4.61
+
+  * Xenial update to v4.4.60 stable release (LP: #1681862)
+    - libceph: force GFP_NOIO for socket allocations
+    - xen/setup: Don't relocate p2m over existing one
+    - scsi: mpt3sas: fix hang on ata passthrough commands
+    - scsi: sg: check length passed to SG_NEXT_CMD_LEN
+    - scsi: libsas: fix ata xfer length
+    - ALSA: seq: Fix race during FIFO resize
+    - ALSA: hda - fix a problem for lineout on a Dell AIO machine
+    - ASoC: atmel-classd: fix audio clock rate
+    - ACPI: Fix incompatibility with mcount-based function graph tracing
+    - ACPI: Do not create a platform_device for IOAPIC/IOxAPIC
+    - tty/serial: atmel: fix race condition (TX+DMA)
+    - tty/serial: atmel: fix TX path in atmel_console_write()
+    - USB: fix linked-list corruption in rh_call_control()
+    - KVM: x86: clear bus pointer when destroyed
+    - drm/radeon: Override fpfn for all VRAM placements in radeon_evict_flags
+    - mm, hugetlb: use pte_present() instead of pmd_present() in follow_huge_pmd()
+    - MIPS: Lantiq: Fix cascaded IRQ setup
+    - rtc: s35390a: fix reading out alarm
+    - rtc: s35390a: make sure all members in the output are set
+    - rtc: s35390a: implement reset routine as suggested by the reference
+    - rtc: s35390a: improve irq handling
+    - KVM: kvm_io_bus_unregister_dev() should never fail
+    - power: reset: at91-poweroff: timely shutdown LPDDR memories
+    - blk: improve order of bio handling in generic_make_request()
+    - blk: Ensure users for current->bio_list can see the full list.
+    - padata: avoid race in reordering
+    - Linux 4.4.60
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 27 Apr 2017 10:24:08 -0300
+
+linux (4.4.0-77.98) xenial; urgency=low
+
+  * linux: 4.4.0-77.98 -proposed tracker (LP: #1686040)
+
+  * [Hyper-V][SAUCE] pci-hyperv: Use only 16 bit integer for PCI domain
+    (LP: #1684971)
+    - SAUCE: pci-hyperv: Use only 16 bit integer for PCI domain
+
+  * Upgrade Redpine WLAN/BT driver to ver. 1.2.RC4 (LP: #1669672)
+    - SAUCE: sdhci: use PCI ID to identify Dell IoT gateways
+    - SAUCE: Redpine: Upgrade to ver. 1.2.RC4
+    - [Config] Update CONFIG_VEN_RSI_* configs
+    - SAUCE: Redpine: add copyright to kernel packages
+
+  * Fix RX fail issue on Exar USB serial driver after resume from S3/S4
+    (LP: #1685133)
+    - SAUCE: xr-usb-serial: Update driver for Exar USB serial ports
+
+  * Miscellaneous Ubuntu changes
+    - [Config] updating configs to match redpine driver changes
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 25 Apr 2017 19:32:01 +0200
+
+linux (4.4.0-75.96) xenial; urgency=low
+
+  * linux: 4.4.0-75.96 -proposed tracker (LP: #1684441)
+
+  * [Hyper-V] hv: util: move waiting for release to hv_utils_transport itself
+    (LP: #1682561)
+    - Drivers: hv: util: move waiting for release to hv_utils_transport itself
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 19 Apr 2017 17:14:23 +0200
+
+linux (4.4.0-74.95) xenial; urgency=low
+
+  * linux: 4.4.0-74.95 -proposed tracker (LP: #1682041)
+
+  * [Hyper-V] hv: vmbus: Raise retry/wait limits in vmbus_post_msg()
+    (LP: #1681893)
+    - Drivers: hv: vmbus: Raise retry/wait limits in vmbus_post_msg()
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 12 Apr 2017 10:30:01 +0200
+
+linux (4.4.0-73.94) xenial; urgency=low
+
+  * linux: 4.4.0-73.94 -proposed tracker (LP: #1680416)
+
+  * CVE-2017-6353
+    - sctp: deny peeloff operation on asocs with threads sleeping on it
+
+  * vfat: missing iso8859-1 charset (LP: #1677230)
+    - [Config] NLS_ISO8859_1=y
+
+  * Regression: KVM modules should be on main kernel package (LP: #1678099)
+    - [Config] powerpc: Add kvm-hv and kvm-pr to the generic inclusion list
+
+  * linux-lts-xenial 4.4.0-63.84~14.04.2 ADT test failure with linux-lts-xenial
+    4.4.0-63.84~14.04.2 (LP: #1664912)
+    - SAUCE: apparmor: fix link auditing failure due to, uninitialized var
+
+  * regession tests failing after stackprofile test is run (LP: #1661030)
+    - SAUCE: fix regression with domain change in complain mode
+
+  * Permission denied and inconsistent behavior in complain mode with 'ip netns
+    list' command (LP: #1648903)
+    - SAUCE: fix regression with domain change in complain mode
+
+  * unexpected errno=13 and disconnected path when trying to open /proc/1/ns/mnt
+    from a unshared mount namespace (LP: #1656121)
+    - SAUCE: apparmor: null profiles should inherit parent control flags
+
+  * apparmor refcount leak of profile namespace when removing profiles
+    (LP: #1660849)
+    - SAUCE: apparmor: fix ns ref count link when removing profiles from policy
+
+  * tor in lxd: apparmor="DENIED" operation="change_onexec"
+    namespace="root//CONTAINERNAME_<var-lib-lxd>" profile="unconfined"
+    name="system_tor" (LP: #1648143)
+    - SAUCE: apparmor: Fix no_new_privs blocking change_onexec when using stacked
+      namespaces
+
+  * apparmor oops in bind_mnt when dev_path lookup fails (LP: #1660840)
+    - SAUCE: apparmor: fix oops in bind_mnt when dev_path lookup fails
+
+  * apparmor  auditing denied access of special apparmor .null fi\ le
+    (LP: #1660836)
+    - SAUCE: apparmor: Don't audit denied access of special apparmor .null file
+
+  * apparmor label leak when new label is unused (LP: #1660834)
+    - SAUCE: apparmor: fix label leak when new label is unused
+
+  * apparmor reference count bug in label_merge_insert() (LP: #1660833)
+    - SAUCE: apparmor: fix reference count bug in label_merge_insert()
+
+  * apparmor's raw_data file in securityfs is sometimes truncated (LP: #1638996)
+    - SAUCE: apparmor: fix replacement race in reading rawdata
+
+  * unix domain socket cross permission check failing with nested namespaces
+    (LP: #1660832)
+    - SAUCE: apparmor: fix cross ns perm of unix domain sockets
+
+  * Xenial update to v4.4.59 stable release (LP: #1678960)
+    - xfrm: policy: init locks early
+    - virtio_balloon: init 1st buffer in stats vq
+    - pinctrl: qcom: Don't clear status bit on irq_unmask
+    - c6x/ptrace: Remove useless PTRACE_SETREGSET implementation
+    - h8300/ptrace: Fix incorrect register transfer count
+    - mips/ptrace: Preserve previous registers for short regset write
+    - sparc/ptrace: Preserve previous registers for short regset write
+    - metag/ptrace: Preserve previous registers for short regset write
+    - metag/ptrace: Provide default TXSTATUS for short NT_PRSTATUS
+    - metag/ptrace: Reject partial NT_METAG_RPIPE writes
+    - fscrypt: remove broken support for detecting keyring key revocation
+    - sched/rt: Add a missing rescheduling point
+    - Linux 4.4.59
+
+  * Update ENA driver to 1.1.2 from net-next (LP: #1664312)
+    - net: ena: Remove unnecessary pci_set_drvdata()
+    - net: ena: Fix error return code in ena_device_init()
+    - net: ena: change the return type of ena_set_push_mode() to be void.
+    - net: ena: use setup_timer() and mod_timer()
+    - net/ena: remove ntuple filter support from device feature list
+    - net/ena: fix queues number calculation
+    - net/ena: fix ethtool RSS flow configuration
+    - net/ena: fix RSS default hash configuration
+    - net/ena: fix NULL dereference when removing the driver after device reset
+      failed
+    - net/ena: refactor ena_get_stats64 to be atomic context safe
+    - net/ena: fix potential access to freed memory during device reset
+    - net/ena: use READ_ONCE to access completion descriptors
+    - net/ena: reduce the severity of ena printouts
+    - net/ena: change driver's default timeouts
+    - net/ena: change condition for host attribute configuration
+    - net/ena: update driver version to 1.1.2
+
+  * Xenial update to v4.4.58 stable release (LP: #1677600)
+    - net/openvswitch: Set the ipv6 source tunnel key address attribute correctly
+    - net: bcmgenet: Do not suspend PHY if Wake-on-LAN is enabled
+    - net: properly release sk_frag.page
+    - amd-xgbe: Fix jumbo MTU processing on newer hardware
+    - net: unix: properly re-increment inflight counter of GC discarded candidates
+    - net/mlx5: Increase number of max QPs in default profile
+    - net/mlx5e: Count LRO packets correctly
+    - net: bcmgenet: remove bcmgenet_internal_phy_setup()
+    - ipv4: provide stronger user input validation in nl_fib_input()
+    - socket, bpf: fix sk_filter use after free in sk_clone_lock
+    - tcp: initialize icsk_ack.lrcvtime at session start time
+    - Input: elan_i2c - add ASUS EeeBook X205TA special touchpad fw
+    - Input: i8042 - add noloop quirk for Dell Embedded Box PC 3000
+    - Input: iforce - validate number of endpoints before using them
+    - Input: ims-pcu - validate number of endpoints before using them
+    - Input: hanwang - validate number of endpoints before using them
+    - Input: yealink - validate number of endpoints before using them
+    - Input: cm109 - validate number of endpoints before using them
+    - Input: kbtab - validate number of endpoints before using them
+    - Input: sur40 - validate number of endpoints before using them
+    - ALSA: seq: Fix racy cell insertions during snd_seq_pool_done()
+    - ALSA: ctxfi: Fix the incorrect check of dma_set_mask() call
+    - ALSA: hda - Adding a group of pin definition to fix headset problem
+    - USB: serial: option: add Quectel UC15, UC20, EC21, and EC25 modems
+    - USB: serial: qcserial: add Dell DW5811e
+    - ACM gadget: fix endianness in notifications
+    - usb: gadget: f_uvc: Fix SuperSpeed companion descriptor's wBytesPerInterval
+    - usb-core: Add LINEAR_FRAME_INTR_BINTERVAL USB quirk
+    - USB: uss720: fix NULL-deref at probe
+    - USB: lvtest: fix NULL-deref at probe
+    - USB: idmouse: fix NULL-deref at probe
+    - USB: wusbcore: fix NULL-deref at probe
+    - usb: musb: cppi41: don't check early-TX-interrupt for Isoch transfer
+    - usb: hub: Fix crash after failure to read BOS descriptor
+    - uwb: i1480-dfu: fix NULL-deref at probe
+    - uwb: hwa-rc: fix NULL-deref at probe
+    - mmc: ushc: fix NULL-deref at probe
+    - iio: adc: ti_am335x_adc: fix fifo overrun recovery
+    - iio: hid-sensor-trigger: Change get poll value function order to avoid
+      sensor properties losing after resume from S3
+    - parport: fix attempt to write duplicate procfiles
+    - ext4: mark inode dirty after converting inline directory
+    - mmc: sdhci: Do not disable interrupts while waiting for clock
+    - xen/acpi: upload PM state from init-domain to Xen
+    - iommu/vt-d: Fix NULL pointer dereference in device_to_iommu
+    - ARM: at91: pm: cpu_idle: switch DDR to power-down mode
+    - ARM: dts: at91: sama5d2: add dma properties to UART nodes
+    - cpufreq: Restore policy min/max limits on CPU online
+    - raid10: increment write counter after bio is split
+    - libceph: don't set weight to IN when OSD is destroyed
+    - xfs: don't allow di_size with high bit set
+    - xfs: fix up xfs_swap_extent_forks inline extent handling
+    - nl80211: fix dumpit error path RTNL deadlocks
+    - USB: usbtmc: add missing endpoint sanity check
+    - xfs: clear _XBF_PAGES from buffers when readahead page
+    - igb: add i211 to i210 PHY workaround
+    - vfio/spapr: Postpone allocation of userspace version of TCE table
+    - block: allow WRITE_SAME commands with the SG_IO ioctl
+    - fbcon: Fix vc attr at deinit
+    - crypto: algif_hash - avoid zero-sized array
+    - Linux 4.4.58
+
+  * PS/2 mouse does not work on Dell embedded computer (LP: #1591053)
+    - Input: i8042 - add noloop quirk for Dell Embedded Box PC 3000
+
+  * Xenial update to v4.4.57 stable release (LP: #1676424)
+    - give up on gcc ilog2() constant optimizations
+    - perf/core: Fix event inheritance on fork()
+    - cpufreq: Fix and clean up show_cpuinfo_cur_freq()
+    - powerpc/boot: Fix zImage TOC alignment
+    - md/raid1/10: fix potential deadlock
+    - target/pscsi: Fix TYPE_TAPE + TYPE_MEDIMUM_CHANGER export
+    - scsi: lpfc: Add shutdown method for kexec
+    - scsi: libiscsi: add lock around task lists to fix list corruption regression
+    - target: Fix VERIFY_16 handling in sbc_parse_cdb
+    - isdn/gigaset: fix NULL-deref at probe
+    - gfs2: Avoid alignment hole in struct lm_lockname
+    - percpu: acquire pcpu_lock when updating pcpu_nr_empty_pop_pages
+    - ext4: fix fencepost in s_first_meta_bg validation
+    - Linux 4.4.57
+
+  * Xenial update to v4.4.56 stable release (LP: #1675789)
+    - netlink: remove mmapped netlink support
+    - [Config] CONFIG_NETLINK_MMAP disappeared
+    - vxlan: correctly validate VXLAN ID against VXLAN_N_VID
+    - vti6: return GRE_KEY for vti6
+    - ipv4: mask tos for input route
+    - l2tp: avoid use-after-free caused by l2tp_ip_backlog_recv
+    - net: don't call strlen() on the user buffer in packet_bind_spkt()
+    - net: net_enable_timestamp() can be called from irq contexts
+    - dccp: Unlock sock before calling sk_free()
+    - tcp: fix various issues for sockets morphing to listen state
+    - net: fix socket refcounting in skb_complete_wifi_ack()
+    - net: fix socket refcounting in skb_complete_tx_timestamp()
+    - dccp: fix use-after-free in dccp_feat_activate_values
+    - vrf: Fix use-after-free in vrf_xmit
+    - uapi: fix linux/packet_diag.h userspace compilation error
+    - act_connmark: avoid crashing on malformed nlattrs with null parms
+    - mpls: Send route delete notifications when router module is unloaded
+    - ipv6: make ECMP route replacement less greedy
+    - ipv6: avoid write to a possibly cloned skb
+    - dccp/tcp: fix routing redirect race
+    - dccp: fix memory leak during tear-down of unsuccessful connection request
+    - net sched actions: decrement module reference count after table flush.
+    - fscrypt: fix renaming and linking special files
+    - fscrypto: lock inode while setting encryption policy
+    - x86/kasan: Fix boot with KASAN=y and PROFILE_ANNOTATED_BRANCHES=y
+    - x86/perf: Fix CR4.PCE propagation to use active_mm instead of mm
+    - futex: Fix potential use-after-free in FUTEX_REQUEUE_PI
+    - futex: Add missing error handling to FUTEX_REQUEUE_PI
+    - Linux 4.4.56
+
+  * Kernel linux-image-4.4.0-67-generic prevent the boot on Microsoft Hyper-v
+    2012r2 Gen2 VM (LP: #1674635)
+    - scsi: storvsc: Workaround for virtual DVD SCSI version
+
+  * [Hyper-V][Mellanox] net/mlx4_core: Avoid delays during VF driver device
+    shutdown (LP: #1672785)
+    - net/mlx4_core: Avoid delays during VF driver device shutdown
+
+  * Channel data values for IIO based st_sensors (st_accel, st_pressure) are
+    incorrect (LP: #1676356)
+    - iio: core: added support for IIO_VAL_INT
+    - iio: st_sensors: simplify buffer address handling
+    - iio: st_sensors: read each channel individually
+    - iio:st_sensors: emulate SMBus block read if needed
+    - iio:st_sensors: align on storagebits boundaries
+    - iio:st_pressure: temperature triggered buffering
+    - iio:st_pressure: clean useless static channel initializers
+    - iio: st_pressure: Fix data sign
+
+  * Enable lspcon on i915 (LP: #1676747)
+    - drm: Helper for lspcon in drm_dp_dual_mode
+    - drm/i915: Add lspcon support for I915 driver
+    - drm/i915: Parse VBT data for lspcon
+    - drm/i915: Enable lspcon initialization
+    - drm/i915: Add lspcon resume function
+
+  * stress_smoke_test passing and exiting rc=9 (linux 4.9.0-12.13 ADT test
+    failure with linux 4.9.0-12.13) (LP: #1658633)
+    - ext4: lock the xattr block before checksuming it
+
+  * Fix line-out port noise on Baytrail-I with RT5660 based sound card
+    (LP: #1675327)
+    - SAUCE: (no-up): ASoC: Intel: bytcr-rt5660: Fix noise in line-out
+
+  * Kernel 4.4.0-67 Defaults to ACPI-cpufreq rather than P-State - Dell
+    Precision 5520  (LP: #1674390)
+    - cpufreq: intel_pstate: Enable HWP by default
+
+  * ip_rcv_finish() NULL pointer kernel panic (LP: #1672470)
+    - bridge: drop netfilter fake rtable unconditionally
+
+  * dm-queue-length module is not included in installer/initramfs (LP: #1673350)
+    - d-i: Also add dm-queue-length to multipath modules
+
+  * Broadcom bluetooth modules sometimes fail to initialize (LP: #1483101)
+    - Bluetooth: btbcm: Add a delay for module reset
+
+  * Need support of Broadcom bluetooth device [413c:8143] (LP: #1166113)
+    - Bluetooth: btusb: Add support for 413c:8143
+
+  * i40e Intel X710 error during device probe prevents link set up and ip
+    association (LP: #1672550)
+    - i40e: check for and deal with non-contiguous TCs
+
+  * CIFS: Call echo service immediately after socket reconnect (LP: #1669941)
+    - Call echo service immediately after socket reconnect
+
+  * FC Adapter (LPe32000-based) prints "iotag out of range", goes offline, and
+    delays boot a lot (Ubuntu17.04/Emulex/lpfc)) (LP: #1670490)
+    - scsi: lpfc: Add missing memory barrier
+
+  * No C-State Deeper than C3 utilized by Kaby Lake 7820HQ in Precision 5520
+    (LP: #1672439)
+    - intel_idle: Add KBL support
+
+  * [Hyper-V] Missing PCI patches breaking SR-IOV hot remove (LP: #1670518)
+    - PCI: hv: Fix hv_pci_remove() for hot-remove
+    - PCI: hv: Delete the device earlier from hbus->children for hot-remove
+    - PCI: hv: Make unnecessarily global IRQ masking functions static
+    - PCI: hv: Allocate physically contiguous hypercall params buffer
+
+  * Xenial update to v4.4.55 stable release (LP: #1674292)
+    - USB: serial: digi_acceleport: fix OOB data sanity check
+    - USB: serial: digi_acceleport: fix OOB-event processing
+    - crypto: improve gcc optimization flags for serpent and wp512
+    - MIPS: Update defconfigs for NF_CT_PROTO_DCCP/UDPLITE change
+    - MIPS: ip27: Disable qlge driver in defconfig
+    - MIPS: Update ip27_defconfig for SCSI_DH change
+    - MIPS: ip22: Fix ip28 build for modern gcc
+    - MIPS: Update lemote2f_defconfig for CPU_FREQ_STAT change
+    - mtd: pmcmsp: use kstrndup instead of kmalloc+strncpy
+    - MIPS: ralink: Cosmetic change to prom_init().
+    - MIPS: ralink: Remove unused rt*_wdt_reset functions
+    - cpmac: remove hopeless #warning
+    - mm: memcontrol: avoid unused function warning
+    - MIPS: DEC: Avoid la pseudo-instruction in delay slots
+    - MIPS: Netlogic: Fix CP0_EBASE redefinition warnings
+    - tracing: Add #undef to fix compile error
+    - powerpc: Emulation support for load/store instructions on LE
+    - usb: gadget: dummy_hcd: clear usb_gadget region before registration
+    - usb: dwc3: gadget: make Set Endpoint Configuration macros safe
+    - usb: gadget: function: f_fs: pass companion descriptor along
+    - usb: host: xhci-dbg: HCIVERSION should be a binary number
+    - usb: host: xhci-plat: Fix timeout on removal of hot pluggable xhci
+      controllers
+    - USB: serial: safe_serial: fix information leak in completion handler
+    - USB: serial: omninet: fix reference leaks at open
+    - USB: iowarrior: fix NULL-deref at probe
+    - USB: iowarrior: fix NULL-deref in write
+    - USB: serial: io_ti: fix NULL-deref in interrupt callback
+    - USB: serial: io_ti: fix information leak in completion handler
+    - serial: samsung: Continue to work if DMA request fails
+    - mvsas: fix misleading indentation
+    - KVM: s390: Fix guest migration for huge guests resulting in panic
+    - s390/kdump: Use "LINUX" ELF note name instead of "CORE"
+    - nfit, libnvdimm: fix interleave set cookie calculation
+    - dm: flush queued bios when process blocks to avoid deadlock
+    - ext4: don't BUG when truncating encrypted inodes on the orphan list
+    - Linux 4.4.55
+
+  * Xenial update to v4.4.54 stable release (LP: #1673541)
+    - serial: 8250_pci: Add MKS Tenta SCOM-0800 and SCOM-0801 cards
+    - KVM: s390: Disable dirty log retrieval for UCONTROL guests
+    - KVM: VMX: use correct vmcs_read/write for guest segment selector/base
+    - Bluetooth: Add another AR3012 04ca:3018 device
+    - s390/qdio: clear DSCI prior to scanning multiple input queues
+    - s390/dcssblk: fix device size calculation in dcssblk_direct_access()
+    - s390: TASK_SIZE for kernel threads
+    - s390: make setup_randomness work
+    - s390: use correct input data address for setup_randomness
+    - net: mvpp2: fix DMA address calculation in mvpp2_txq_inc_put()
+    - mnt: Tuck mounts under others instead of creating shadow/side mounts.
+    - IB/ipoib: Fix deadlock between rmmod and set_mode
+    - IB/IPoIB: Add destination address when re-queue packet
+    - IB/srp: Avoid that duplicate responses trigger a kernel bug
+    - IB/srp: Fix race conditions related to task management
+    - ktest: Fix child exit code processing
+    - ceph: remove req from unsafe list when unregistering it
+    - target: Fix NULL dereference during LUN lookup + active I/O shutdown
+    - nlm: Ensure callback code also checks that the files match
+    - pwm: pca9685: Fix period change with same duty cycle
+    - xtensa: move parse_tag_fdt out of #ifdef CONFIG_BLK_DEV_INITRD
+    - mac80211: flush delayed work when entering suspend
+    - drm/amdgpu: add more cases to DCE11 possible crtc mask setup
+    - drm/ast: Fix test for VGA enabled
+    - drm/ast: Call open_key before enable_mmio in POST code
+    - drm/ast: Fix AST2400 POST failure without BMC FW or VBIOS
+    - drm/edid: Add EDID_QUIRK_FORCE_8BPC quirk for Rotel RSX-1058
+    - drm/ttm: Make sure BOs being swapped out are cacheable
+    - drm/atomic: fix an error code in mode_fixup()
+    - fakelb: fix schedule while atomic
+    - drm/i915/dsi: Do not clear DPOUNIT_CLOCK_GATE_DISABLE from
+      vlv_init_display_clock_gating
+    - libceph: use BUG() instead of BUG_ON(1)
+    - fat: fix using uninitialized fields of fat_inode/fsinfo_inode
+    - drivers: hv: Turn off write permission on the hypercall page
+    - Linux 4.4.54
+
+  * Xenial update to v4.4.53 stable release (LP: #1673538)
+    - samples: move mic/mpssd example code from Documentation
+    - MIPS: Fix special case in 64 bit IP checksumming.
+    - MIPS: BCM47XX: Fix button inversion for Asus WL-500W
+    - MIPS: OCTEON: Fix copy_from_user fault handling for large buffers
+    - MIPS: Lantiq: Keep ethernet enabled during boot
+    - MIPS: Clear ISA bit correctly in get_frame_info()
+    - MIPS: Prevent unaligned accesses during stack unwinding
+    - MIPS: Fix get_frame_info() handling of microMIPS function size
+    - MIPS: Fix is_jump_ins() handling of 16b microMIPS instructions
+    - MIPS: Calculate microMIPS ra properly when unwinding the stack
+    - MIPS: Handle microMIPS jumps in the same way as MIPS32/MIPS64 jumps
+    - am437x-vpfe: always assign bpp variable
+    - uvcvideo: Fix a wrong macro
+    - media: fix dm1105.c build error
+    - ARM: at91: define LPDDR types
+    - ARM: dts: at91: Enable DMA on sama5d4_xplained console
+    - ARM: dts: at91: Enable DMA on sama5d2_xplained console
+    - ALSA: hda/realtek - Cannot adjust speaker's volume on a Dell AIO
+    - ALSA: hda - fix Lewisburg audio issue
+    - ALSA: timer: Reject user params with too small ticks
+    - ALSA: ctxfi: Fallback DMA mask to 32bit
+    - ALSA: seq: Fix link corruption by event error handling
+    - ALSA: hda - Add subwoofer support for Dell Inspiron 17 7000 Gaming
+    - ALSA: hda - Fix micmute hotkey problem for a lenovo AIO machine
+    - staging: rtl: fix possible NULL pointer dereference
+    - regulator: Fix regulator_summary for deviceless consumers
+    - iommu/vt-d: Fix some macros that are incorrectly specified in intel-iommu
+    - iommu/vt-d: Tylersburg isoch identity map check is done too late.
+    - mm/page_alloc: fix nodes for reclaim in fast path
+    - mm: vmpressure: fix sending wrong events on underflow
+    - mm: do not access page->mapping directly on page_endio
+    - ipc/shm: Fix shmat mmap nil-page protection
+    - dm cache: fix corruption seen when using cache > 2TB
+    - dm stats: fix a leaked s->histogram_boundaries array
+    - Revert "scsi: storvsc: properly set residual data length on errors"
+    - scsi: storvsc: properly set residual data length on errors
+    - scsi: aacraid: Reorder Adapter status check
+    - scsi: use 'scsi_device_from_queue()' for scsi_dh
+    - sd: get disk reference in sd_check_events()
+    - Fix: Disable sys_membarrier when nohz_full is enabled
+    - jbd2: don't leak modified metadata buffers on an aborted journal
+    - block/loop: fix race between I/O and set_status
+    - loop: fix LO_FLAGS_PARTSCAN hang
+    - ext4: Include forgotten start block on fallocate insert range
+    - ext4: do not polute the extents cache while shifting extents
+    - ext4: trim allocation requests to group size
+    - ext4: fix data corruption in data=journal mode
+    - ext4: fix inline data error paths
+    - ext4: preserve the needs_recovery flag when the journal is aborted
+    - ext4: return EROFS if device is r/o and journal replay is needed
+    - samples/seccomp: fix 64-bit comparison macros
+    - target: Obtain se_node_acl->acl_kref during get_initiator_node_acl
+    - target: Fix multi-session dynamic se_node_acl double free OOPs
+    - ath5k: drop bogus warning on drv_set_key with unsupported cipher
+    - ath9k: fix race condition in enabling/disabling IRQs
+    - ath9k: use correct OTP register offsets for the AR9340 and AR9550
+    - crypto: testmgr - Pad aes_ccm_enc_tv_template vector
+    - fuse: add missing FR_FORCE
+    - arm/arm64: KVM: Enforce unconditional flush to PoC when mapping to stage-2
+    - iio: pressure: mpl115: do not rely on structure field ordering
+    - iio: pressure: mpl3115: do not rely on structure field ordering
+    - can: usb_8dev: Fix memory leak of priv->cmd_msg_buffer
+    - w1: don't leak refcount on slave attach failure in w1_attach_slave_device()
+    - w1: ds2490: USB transfer buffers need to be DMAable
+    - usb: musb: da8xx: Remove CPPI 3.0 quirk and methods
+    - usb: host: xhci: plat: check hcc_params after add hcd
+    - usb: gadget: udc: fsl: Add missing complete function.
+    - hv: allocate synic pages for all present CPUs
+    - hv: init percpu_list in hv_synic_alloc()
+    - Drivers: hv: util: kvp: Fix a rescind processing issue
+    - Drivers: hv: util: Fcopy: Fix a rescind processing issue
+    - Drivers: hv: util: Backup: Fix a rescind processing issue
+    - RDMA/core: Fix incorrect structure packing for booleans
+    - rdma_cm: fail iwarp accepts w/o connection params
+    - gfs2: Add missing rcu locking for glock lookup
+    - rtlwifi: Fix alignment issues
+    - rtlwifi: rtl8192c-common: Fix "BUG: KASAN:
+    - nfsd: minor nfsd_setattr cleanup
+    - nfsd: special case truncates some more
+    - NFSv4: Fix memory and state leak in _nfs4_open_and_get_state
+    - NFSv4: fix getacl head length estimation
+    - NFSv4: fix getacl ERANGE for some ACL buffer sizes
+    - rtc: sun6i: Add some locking
+    - rtc: sun6i: Switch to the external oscillator
+    - md linear: fix a race between linear_add() and linear_congested()
+    - bcma: use (get|put)_device when probing/removing device driver
+    - dmaengine: ipu: Make sure the interrupt routine checks all interrupts.
+    - powerpc/xmon: Fix data-breakpoint
+    - MIPS: IP22: Reformat inline assembler code to modern standards.
+    - MIPS: IP22: Fix build error due to binutils 2.25 uselessnes.
+    - scsi: lpfc: Correct WQ creation for pagesize
+    - Linux 4.4.53
+
+  * move aufs.ko from -extra to linux-image package (LP: #1673498)
+    - [config] aufs.ko moved to linux-image package
+
+  * [Xenial] net: better skb->sender_cpu and skb->napi_id cohabitation
+    (LP: #1673303)
+    - net: better skb->sender_cpu and skb->napi_id cohabitation
+
+  * lsattr 32bit does not work on 64bit kernel (Inappropriate ioctl error)
+    (LP: #1619918)
+    - btrfs: fix btrfs_compat_ioctl failures on non-compat ioctls
+
+  * linux-tools-common should Depends: lsb-release (LP: #1667571)
+    - [Config] linux-tools-common depends on lsb-release
+
+  * Add Use-After-Free Patch for Ubuntu16.10 - EEH on BELL3 adapter fails to
+    recover (serial/tty) (LP: #1669153)
+    - 8250_pci: Fix potential use-after-free in error path
+
+  * [Hyper-V] pci-hyperv: Use device serial number as PCI domain (LP: #1667527)
+    - net/mlx4_core: Use cq quota in SRIOV when creating completion EQs
+    - PCI: hv: Use device serial number as PCI domain
+
+  * [Xenial - 16.04 ]Bonding driver - stack corruption when trying to copy 20
+    bytes to a sockaddr (LP: #1668042)
+    - net/bonding: Enforce active-backup policy for IPoIB bonds
+
+  * Request to backport cxlflash patches to Xenial SRU stream (LP: #1623750)
+    - scsi: cxlflash: Scan host only after the port is ready for I/O
+    - scsi: cxlflash: Remove the device cleanly in the system shutdown path
+    - scsi: cxlflash: Fix to avoid EEH and host reset collisions
+    - scsi: cxlflash: Improve EEH recovery time
+
+  * Xenial update to v4.4.52 stable release (LP: #1669016)
+    - net/llc: avoid BUG_ON() in skb_orphan()
+    - packet: fix races in fanout_add()
+    - packet: Do not call fanout_release from atomic contexts
+    - irda: Fix lockdep annotations in hashbin_delete().
+    - ip: fix IP_CHECKSUM handling
+    - net: socket: fix recvmmsg not returning error from sock_error
+    - tty: serial: msm: Fix module autoload
+    - USB: serial: mos7840: fix another NULL-deref at open
+    - USB: serial: cp210x: add new IDs for GE Bx50v3 boards
+    - USB: serial: ftdi_sio: fix modem-status error handling
+    - USB: serial: ftdi_sio: fix extreme low-latency setting
+    - USB: serial: ftdi_sio: fix line-status over-reporting
+    - USB: serial: spcp8x5: fix modem-status handling
+    - USB: serial: opticon: fix CTS retrieval at open
+    - USB: serial: ark3116: fix register-accessor error handling
+    - x86/platform/goldfish: Prevent unconditional loading
+    - goldfish: Sanitize the broken interrupt handler
+    - block: fix double-free in the failure path of cgwb_bdi_init()
+    - rtlwifi: rtl_usb: Fix for URB leaking when doing ifconfig up/down
+    - Revert "usb: chipidea: imx: enable CI_HDRC_SET_NON_ZERO_TTHA"
+    - kvm: vmx: ensure VMCS is current while enabling PML
+    - Linux 4.4.52
+
+  * Xenial update to v4.4.51 stable release (LP: #1669015)
+    - vfs: fix uninitialized flags in splice_to_pipe()
+    - siano: make it work again with CONFIG_VMAP_STACK
+    - fuse: fix use after free issue in fuse_dev_do_read()
+    - scsi: don't BUG_ON() empty DMA transfers
+    - Fix missing sanity check in /dev/sg
+    - Input: elan_i2c - add ELAN0605 to the ACPI table
+    - drm/radeon: Use mode h/vdisplay fields to hide out of bounds HW cursor
+    - drm/dp/mst: fix kernel oops when turning off secondary monitor
+    - futex: Move futex_init() to core_initcall
+    - ARM: 8658/1: uaccess: fix zeroing of 64-bit get_user()
+    - printk: use rcuidle console tracepoint
+    - NTB: ntb_transport: fix debugfs_remove_recursive
+    - ntb_transport: Pick an unused queue
+    - bcache: Make gc wakeup sane, remove set_task_state()
+    - mmc: core: fix multi-bit bus width without high-speed mode
+    - Linux 4.4.51
+
+  * Xenial update to v4.4.50 stable release (LP: #1666324)
+    - can: Fix kernel panic at security_sock_rcv_skb
+    - ipv6: fix ip6_tnl_parse_tlv_enc_lim()
+    - ipv6: pointer math error in ip6_tnl_parse_tlv_enc_lim()
+    - tcp: fix 0 divide in __tcp_select_window()
+    - net: use a work queue to defer net_disable_timestamp() work
+    - ipv4: keep skb->dst around in presence of IP options
+    - netlabel: out of bound access in cipso_v4_validate()
+    - ip6_gre: fix ip6gre_err() invalid reads
+    - ipv6: tcp: add a missing tcp_v6_restore_cb()
+    - tcp: avoid infinite loop in tcp_splice_read()
+    - tun: read vnet_hdr_sz once
+    - macvtap: read vnet_hdr_size once
+    - mlx4: Invoke softirqs after napi_reschedule
+    - sctp: avoid BUG_ON on sctp_wait_for_sndbuf
+    - sit: fix a double free on error path
+    - net: introduce device min_header_len
+    - packet: round up linear to header len
+    - ping: fix a null pointer dereference
+    - l2tp: do not use udp_ioctl()
+    - Linux 4.4.50
+
+  * FlashGT Integration and Setup: fsbmc30: After 17th reboot of soft bootme,
+    HTX & Linux errors seen with 256 virtual LUNs (LP: #1667239)
+    - cxl: Fix coredump generation when cxl_get_fd() is used
+
+  * [Hyper-V] Ubuntu 14.04.2 LTS Generation 2 SCSI Errors on VSS Based Backups
+    (LP: #1470250)
+    - Drivers: hv: vss: Operation timeouts should match host expectation
+    - SAUCE: Tools: hv: vss: Thaw the filesystem and continue after freeze fails
+
+  * kernel 4.4.0-63 with USB WLAN RTL8192CU freezes desktop (LP: #1666421)
+    - rtlwifi: rtl_usb: Fix missing entry in USB driver's private data
+
+  * Export symbol "dev_pm_qos_update_user_latency_tolerance" (LP: #1666401)
+    - PM / QoS: Export dev_pm_qos_update_user_latency_tolerance
+
+  * Linux ZFS port doesn't respect RLIMIT_FSIZE (LP: #1656259)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu16
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 06 Apr 2017 09:34:27 +0100
+
+linux (4.4.0-72.93) xenial; urgency=low
+
+  * linux: 4.4.0-72.93 -proposed tracker (LP: #1678078)
+
+  * Fix CVE-2017-7308 (LP: #1678009)
+    - net/packet: fix overflow in check for priv area size
+    - net/packet: fix overflow in check for tp_frame_nr
+    - net/packet: fix overflow in check for tp_reserve
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 31 Mar 2017 09:20:03 +0200
+
+linux (4.4.0-71.92) xenial; urgency=low
+
+  * CVE-2017-7184
+    - xfrm_user: validate XFRM_MSG_NEWAE XFRMA_REPLAY_ESN_VAL replay_window
+    - xfrm_user: validate XFRM_MSG_NEWAE incoming ESN size harder
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 24 Mar 2017 09:32:49 -0300
+
+linux (4.4.0-70.91) xenial; urgency=low
+
+  * linux: 4.4.0-70.91 -proposed tracker (LP: #1674938)
+
+  * snaps with classic + jailmode confinement started to fail on zesty
+    (LP: #1666897)
+    - Revert "UBUNTU: SAUCE: apparmor: fix link auditing failure due to,
+      uninitialized var"
+    - Revert "UBUNTU: SAUCE: fix regression with domain change in complain mode"
+    - Revert "UBUNTU: SAUCE: apparmor: flock mediation is not being enforced on
+      cache check"
+    - Revert "UBUNTU: SAUCE: apparmor: null profiles should inherit parent control
+      flags"
+    - Revert "UBUNTU: SAUCE: apparmor: fix ns ref count link when removing
+      profiles from policy"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix no_new_privs blocking change_onexec
+      when using stacked namespaces"
+    - Revert "UBUNTU: SAUCE: apparmor: fix oops in bind_mnt when dev_path lookup
+      fails"
+    - Revert "UBUNTU: SAUCE: apparmor: Don't audit denied access of special
+      apparmor .null file"
+    - Revert "UBUNTU: SAUCE: apparmor: fix label leak when new label is unused"
+    - Revert "UBUNTU: SAUCE: apparmor: fix reference count bug in
+      label_merge_insert()"
+    - Revert "UBUNTU: SAUCE: apparmor: fix replacement race in reading rawdata"
+    - Revert "UBUNTU: SAUCE: apparmor: fix cross ns perm of unix domain sockets"
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 22 Mar 2017 09:28:43 +0100
+
+linux (4.4.0-67.88) xenial; urgency=low
+
+  * linux: 4.4.0-67.88 -proposed tracker (LP: #1667052)
+
+  * Recent KVM RTC cherry-picks break (some) Windows Live-Migrations
+    (LP: #1668594)
+    - kvm: x86: correctly reset dest_map->vector when restoring LAPIC state
+
+  * Regression in 4.4.0-65-generic causes very frequent system crashes
+    (LP: #1669611)
+    - Revert "UBUNTU: SAUCE: apparmor: fix lock ordering for mkdir"
+    - Revert "UBUNTU: SAUCE: apparmor: fix leak on securityfs pin count"
+    - Revert "UBUNTU: SAUCE: apparmor: fix reference count leak when
+      securityfs_setup_d_inode() fails"
+    - Revert "UBUNTU: SAUCE: apparmor: fix not handling error case when
+      securityfs_pin_fs() fails"
+
+  * Upgrade Redpine RS9113 driver to support AP mode (LP: #1665211)
+    - SAUCE: Redpine driver to support Host AP mode
+
+  * NFS client : permission denied when trying to access subshare, since kernel
+    4.4.0-31 (LP: #1649292)
+    - fs: Better permission checking for submounts
+
+  * [Hyper-V] SAUCE: pci-hyperv fixes for SR-IOV on Azure (LP: #1665097)
+    - SAUCE: PCI: hv: Fix wslot_to_devfn() to fix warnings on device removal
+    - SAUCE: pci-hyperv: properly handle pci bus remove
+    - SAUCE: pci-hyperv: lock pci bus on device eject
+
+  * [Hyper-V/Azure] Please include Mellanox OFED drivers in Azure kernel and
+    image (LP: #1650058)
+    - net/mlx4_en: Fix bad WQE issue
+    - net/mlx4_core: Fix racy CQ (Completion Queue) free
+    - net/mlx4_core: Fix when to save some qp context flags for dynamic VST to VGT
+      transitions
+    - net/mlx4_core: Avoid command timeouts during VF driver device shutdown
+
+  * Xenial update to v4.4.49 stable release (LP: #1664960)
+    - ARC: [arcompact] brown paper bag bug in unaligned access delay slot fixup
+    - selinux: fix off-by-one in setprocattr
+    - Revert "x86/ioapic: Restore IO-APIC irq_chip retrigger callback"
+    - cpumask: use nr_cpumask_bits for parsing functions
+    - hns: avoid stack overflow with CONFIG_KASAN
+    - ARM: 8643/3: arm/ptrace: Preserve previous registers for short regset write
+    - target: Don't BUG_ON during NodeACL dynamic -> explicit conversion
+    - target: Use correct SCSI status during EXTENDED_COPY exception
+    - target: Fix early transport_generic_handle_tmr abort scenario
+    - target: Fix COMPARE_AND_WRITE ref leak for non GOOD status
+    - ARM: 8642/1: LPAE: catch pending imprecise abort on unmask
+    - mac80211: Fix adding of mesh vendor IEs
+    - netvsc: Set maximum GSO size in the right place
+    - scsi: zfcp: fix use-after-free by not tracing WKA port open/close on failed
+      send
+    - scsi: aacraid: Fix INTx/MSI-x issue with older controllers
+    - scsi: mpt3sas: disable ASPM for MPI2 controllers
+    - xen-netfront: Delete rx_refill_timer in xennet_disconnect_backend()
+    - ALSA: seq: Fix race at creating a queue
+    - ALSA: seq: Don't handle loop timeout at snd_seq_pool_done()
+    - drm/i915: fix use-after-free in page_flip_completed()
+    - Linux 4.4.49
+
+  * NFS client : kernel 4.4.0-57 crash with nfsv4 enries in /etc/fstab
+    (LP: #1650336)
+    - SUNRPC: fix refcounting problems with auth_gss messages.
+
+  * [0bda:0328] Card reader failed after S3 (LP: #1664809)
+    - usb: hub: Wait for connection to be reestablished after port reset
+
+  * linux-lts-xenial 4.4.0-63.84~14.04.2 ADT test failure with linux-lts-xenial
+    4.4.0-63.84~14.04.2 (LP: #1664912)
+    - SAUCE: apparmor: fix link auditing failure due to, uninitialized var
+
+  * ibmvscsis: Add SGL LIMIT (LP: #1662551)
+    - ibmvscsis: Add SGL limit
+
+  * [Hyper-V] Bug fixes for storvsc (tagged queuing, error conditions)
+    (LP: #1663687)
+    - scsi: storvsc: Enable tracking of queue depth
+    - scsi: storvsc: Remove the restriction on max segment size
+    - scsi: storvsc: Enable multi-queue support
+    - scsi: storvsc: use tagged SRB requests if supported by the device
+    - scsi: storvsc: properly handle SRB_ERROR when sense message is present
+    - scsi: storvsc: properly set residual data length on errors
+
+  * ISST-LTE:pNV: ppc64_cpu command is hung w HDs, SSDs and NVMe (LP: #1662666)
+    - blk-mq: Avoid memory reclaim when remapping queues
+    - blk-mq: Fix failed allocation path when mapping queues
+
+  * Possible missing firmware /lib/firmware/i915/kbl_dmc_ver1.bin for module
+    i915_bpo (LP: #1624164)
+    - SAUCE: i915_bpo: Remove MODULE_FIRMWARE statement for i915/kbl_dmc_ver1.bin
+
+  *  Intel I210 ethernet does not work both after S3 (LP: #1662763)
+    - igb: implement igb_ptp_suspend
+    - igb: call igb_ptp_suspend during suspend/resume cycle
+
+  * [Hyper-V] Fix ring buffer handling to avoid host throttling (LP: #1661430)
+    - Drivers: hv: vmbus: On write cleanup the logic to interrupt the host
+    - Drivers: hv: vmbus: On the read path cleanup the logic to interrupt the host
+    - Drivers: hv: vmbus: finally fix hv_need_to_signal_on_read()
+
+  * brd module compiled as built-in (LP: #1593293)
+    - [Config] CONFIG_BLK_DEV_RAM=m
+
+  * regession tests failing after stackprofile test is run (LP: #1661030)
+    - SAUCE: fix regression with domain change in complain mode
+
+  * Permission denied and inconsistent behavior in complain mode with 'ip netns
+    list' command (LP: #1648903)
+    - SAUCE: fix regression with domain change in complain mode
+
+  * flock not mediated by 'k' (LP: #1658219)
+    - SAUCE: apparmor: flock mediation is not being enforced on cache check
+
+  * unexpected errno=13 and disconnected path when trying to open /proc/1/ns/mnt
+    from a unshared mount namespace (LP: #1656121)
+    - SAUCE: apparmor: null profiles should inherit parent control flags
+
+  * apparmor refcount leak of profile namespace when removing profiles
+    (LP: #1660849)
+    - SAUCE: apparmor: fix ns ref count link when removing profiles from policy
+
+  * tor in lxd: apparmor="DENIED" operation="change_onexec"
+    namespace="root//CONTAINERNAME_<var-lib-lxd>" profile="unconfined"
+    name="system_tor" (LP: #1648143)
+    - SAUCE: apparmor: Fix no_new_privs blocking change_onexec when using stacked
+      namespaces
+
+  * apparmor_parser hangs indefinitely when called by multiple threads
+    (LP: #1645037)
+    - SAUCE: apparmor: fix lock ordering for mkdir
+
+  * apparmor leaking securityfs pin count (LP: #1660846)
+    - SAUCE: apparmor: fix leak on securityfs pin count
+
+  * apparmor reference count leak when securityfs_setup_d_inode\ () fails
+    (LP: #1660845)
+    - SAUCE: apparmor: fix reference count leak when securityfs_setup_d_inode()
+      fails
+
+  * apparmor not checking error if security_pin_fs() fails (LP: #1660842)
+    - SAUCE: apparmor: fix not handling error case when securityfs_pin_fs() fails
+
+  * apparmor oops in bind_mnt when dev_path lookup fails (LP: #1660840)
+    - SAUCE: apparmor: fix oops in bind_mnt when dev_path lookup fails
+
+  * apparmor  auditing denied access of special apparmor .null fi\ le
+    (LP: #1660836)
+    - SAUCE: apparmor: Don't audit denied access of special apparmor .null file
+
+  * apparmor label leak when new label is unused (LP: #1660834)
+    - SAUCE: apparmor: fix label leak when new label is unused
+
+  * apparmor reference count bug in label_merge_insert() (LP: #1660833)
+    - SAUCE: apparmor: fix reference count bug in label_merge_insert()
+
+  * apparmor's raw_data file in securityfs is sometimes truncated (LP: #1638996)
+    - SAUCE: apparmor: fix replacement race in reading rawdata
+
+  * unix domain socket cross permission check failing with nested namespaces
+    (LP: #1660832)
+    - SAUCE: apparmor: fix cross ns perm of unix domain sockets
+
+  * docker permission issues with overlay2 storage driver (LP: #1659417)
+    - SAUCE: overlayfs: Replace ovl_prepare_creds() with ovl_override_creds()
+    - Revert "UBUNTU: SAUCE: cred: Add clone_cred() interface"
+    - ovl: check mounter creds on underlying lookup
+
+  * Enable CONFIG_NET_DROP_MONITOR=m in Ubuntu Kernel (LP: #1660634)
+    - [Config] CONFIG_NET_DROP_MONITOR=m
+
+  * Xenial update to v4.4.48 stable release (LP: #1663657)
+    - PCI/ASPM: Handle PCI-to-PCIe bridges as roots of PCIe hierarchies
+    - ext4: validate s_first_meta_bg at mount time
+    - drm/nouveau/disp/gt215: Fix HDA ELD handling (thus, HDMI audio) on gt215
+    - drm/nouveau/nv1a,nv1f/disp: fix memory clock rate retrieval
+    - crypto: api - Clear CRYPTO_ALG_DEAD bit before registering an alg
+    - crypto: arm64/aes-blk - honour iv_out requirement in CBC and CTR modes
+    - perf/core: Fix PERF_RECORD_MMAP2 prot/flags for anonymous memory
+    - ata: sata_mv:- Handle return value of devm_ioremap.
+    - libata: apply MAX_SEC_1024 to all CX1-JB*-HP devices
+    - powerpc/eeh: Fix wrong flag passed to eeh_unfreeze_pe()
+    - powerpc: Add missing error check to prom_find_boot_cpu()
+    - NFSD: Fix a null reference case in find_or_create_lock_stateid()
+    - svcrpc: fix oops in absence of krb5 module
+    - zswap: disable changing params if init fails
+    - cifs: initialize file_info_lock
+    - mm/memory_hotplug.c: check start_pfn in test_pages_in_a_zone()
+    - mm, fs: check for fatal signals in do_generic_file_read()
+    - can: bcm: fix hrtimer/tasklet termination in bcm op removal
+    - mmc: sdhci: Ignore unexpected CARD_INT interrupts
+    - percpu-refcount: fix reference leak during percpu-atomic transition
+    - HID: wacom: Fix poor prox handling in 'wacom_pl_irq'
+    - KVM: x86: do not save guest-unsupported XSAVE state
+    - USB: serial: qcserial: add Dell DW5570 QDL
+    - USB: serial: pl2303: add ATEN device ID
+    - USB: Add quirk for WORLDE easykey.25 MIDI keyboard
+    - usb: gadget: f_fs: Assorted buffer overflow checks.
+    - USB: serial: option: add device ID for HP lt2523 (Novatel E371)
+    - x86/irq: Make irq activate operations symmetric
+    - base/memory, hotplug: fix a kernel oops in show_valid_zones()
+    - Linux 4.4.48
+
+  * Xenial update to v4.4.47 stable release (LP: #1662507)
+    - r8152: fix the sw rx checksum is unavailable
+    - mlxsw: spectrum: Fix memory leak at skb reallocation
+    - mlxsw: switchx2: Fix memory leak at skb reallocation
+    - mlxsw: pci: Fix EQE structure definition
+    - net: lwtunnel: Handle lwtunnel_fill_encap failure
+    - net: ipv4: fix table id in getroute response
+    - net: systemport: Decouple flow control from __bcm_sysport_tx_reclaim
+    - tcp: fix tcp_fastopen unaligned access complaints on sparc
+    - openvswitch: maintain correct checksum state in conntrack actions
+    - ravb: do not use zero-length alignment DMA descriptor
+    - ax25: Fix segfault after sock connection timeout
+    - net: fix harmonize_features() vs NETIF_F_HIGHDMA
+    - net: phy: bcm63xx: Utilize correct config_intr function
+    - ipv6: addrconf: Avoid addrconf_disable_change() using RCU read-side lock
+    - tcp: initialize max window for a new fastopen socket
+    - bridge: netlink: call br_changelink() during br_dev_newlink()
+    - r8152: don't execute runtime suspend if the tx is not empty
+    - af_unix: move unix_mknod() out of bindlock
+    - qmi_wwan/cdc_ether: add device ID for HP lt2523 (Novatel E371) WWAN card
+    - net: dsa: Bring back device detaching in dsa_slave_suspend()
+    - Linux 4.4.47
+
+  * Xenial update to v4.4.46 stable release (LP: #1660994)
+    - fbdev: color map copying bounds checking
+    - tile/ptrace: Preserve previous registers for short regset write
+    - drm: Fix broken VT switch with video=1366x768 option
+    - mm/mempolicy.c: do not put mempolicy before using its nodemask
+    - sysctl: fix proc_doulongvec_ms_jiffies_minmax()
+    - ISDN: eicon: silence misleading array-bounds warning
+    - RDMA/cma: Fix unknown symbol when CONFIG_IPV6 is not enabled
+    - s390/ptrace: Preserve previous registers for short regset write
+    - can: c_can_pci: fix null-pointer-deref in c_can_start() - set device pointer
+    - can: ti_hecc: add missing prepare and unprepare of the clock
+    - ARC: udelay: fix inline assembler by adding LP_COUNT to clobber list
+    - ARC: [arcompact] handle unaligned access delay slot corner case
+    - parisc: Don't use BITS_PER_LONG in userspace-exported swab.h header
+    - nfs: Don't increment lock sequence ID after NFS4ERR_MOVED
+    - NFSv4.0: always send mode in SETATTR after EXCLUSIVE4
+    - SUNRPC: cleanup ida information when removing sunrpc module
+    - drm/i915: Don't leak edid in intel_crt_detect_ddc()
+    - IB/ipoib: move back IB LL address into the hard header
+    - IB/umem: Release pid in error and ODP flow
+    - s5k4ecgx: select CRC32 helper
+    - pinctrl: broxton: Use correct PADCFGLOCK offset
+    - platform/x86: intel_mid_powerbtn: Set IRQ_ONESHOT
+    - mm, memcg: do not retry precharge charges
+    - Linux 4.4.46
+
+  * Xenial update to v4.4.45 stable release (LP: #1660993)
+    - ftrace/x86: Set ftrace_stub to weak to prevent gcc from using short jumps to
+      it
+    - IB/mlx5: Wait for all async command completions to complete
+    - IB/mlx4: Set traffic class in AH
+    - IB/mlx4: Fix out-of-range array index in destroy qp flow
+    - IB/mlx4: Fix port query for 56Gb Ethernet links
+    - IB/mlx4: When no DMFS for IPoIB, don't allow NET_IF QPs
+    - IB/IPoIB: Remove can't use GFP_NOIO warning
+    - perf scripting: Avoid leaking the scripting_context variable
+    - ARM: dts: imx31: fix clock control module interrupts description
+    - ARM: dts: imx31: move CCM device node to AIPS2 bus devices
+    - ARM: dts: imx31: fix AVIC base address
+    - tmpfs: clear S_ISGID when setting posix ACLs
+    - x86/PCI: Ignore _CRS on Supermicro X8DTH-i/6/iF/6F
+    - svcrpc: don't leak contexts on PROC_DESTROY
+    - fuse: clear FR_PENDING flag when moving requests out of pending queue
+    - PCI: Enumerate switches below PCI-to-PCIe bridges
+    - HID: corsair: fix DMA buffers on stack
+    - HID: corsair: fix control-transfer error handling
+    - mmc: mxs-mmc: Fix additional cycles after transmission stop
+    - ieee802154: atusb: do not use the stack for buffers to make them DMA able
+    - mtd: nand: xway: disable module support
+    - x86/ioapic: Restore IO-APIC irq_chip retrigger callback
+    - qla2xxx: Fix crash due to null pointer access
+    - ubifs: Fix journal replay wrt. xattr nodes
+    - clocksource/exynos_mct: Clear interrupt when cpu is shut down
+    - svcrdma: avoid duplicate dma unmapping during error recovery
+    - ARM: 8634/1: hw_breakpoint: blacklist Scorpion CPUs
+    - ceph: fix bad endianness handling in parse_reply_info_extra
+    - ARM: dts: da850-evm: fix read access to SPI flash
+    - arm64/ptrace: Preserve previous registers for short regset write
+    - arm64/ptrace: Preserve previous registers for short regset write - 2
+    - arm64/ptrace: Preserve previous registers for short regset write - 3
+    - arm64/ptrace: Avoid uninitialised struct padding in fpr_set()
+    - arm64/ptrace: Reject attempts to set incomplete hardware breakpoint fields
+    - ARM: dts: imx6qdl-nitrogen6_max: fix sgtl5000 pinctrl init
+    - ARM: ux500: fix prcmu_is_cpu_in_wfi() calculation
+    - ARM: 8613/1: Fix the uaccess crash on PB11MPCore
+    - blackfin: check devm_pinctrl_get() for errors
+    - ite-cir: initialize use_demodulator before using it
+    - dmaengine: pl330: Fix runtime PM support for terminated transfers
+    - selftest/powerpc: Wrong PMC initialized in pmc56_overflow test
+    - arm64: avoid returning from bad_mode
+    - Linux 4.4.45
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 08 Mar 2017 11:47:26 -0300
+
+linux (4.4.0-66.87) xenial; urgency=low
+
+  * CVE-2017-2636
+    - TTY: n_hdlc, fix lockdep false positive
+    - tty: n_hdlc: get rid of racy n_hdlc.tbuf
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 03 Mar 2017 12:01:27 +0100
+
+linux (4.4.0-64.85) xenial; urgency=low
+
+  * CVE-2017-6074 (LP: #1665935)
+    - dccp: fix freeing skb too early for IPV6_RECVPKTINFO
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 20 Feb 2017 11:06:47 +0100
+
+linux (4.4.0-63.84) xenial; urgency=low
+
+  [ Thadeu Lima de Souza Cascardo ]
+
+  * Release Tracking Bug
+    - LP: #1660704
+
+  * Backport Dirty COW patch to prevent wineserver freeze (LP: #1658270)
+    - SAUCE: mm: Respect FOLL_FORCE/FOLL_COW for thp
+
+  * Kdump through NMI SMP and single core not working on Ubuntu16.10
+    (LP: #1630924)
+    - x86/hyperv: Handle unknown NMIs on one CPU when unknown_nmi_panic
+    - SAUCE: hv: don't reset hv_context.tsc_page on crash
+
+  * [regression 4.8.0-14 -> 4.8.0-17] keyboard and touchscreen lost on Acer
+    Chromebook R11 (LP: #1630238)
+    - [Config] CONFIG_PINCTRL_CHERRYVIEW=y
+
+  * Call trace when testing fstat stressor on ppc64el with virtual  keyboard and
+    mouse present (LP: #1652132)
+    - SAUCE: HID: usbhid: Quirk a AMI virtual mouse and keyboard with ALWAYS_POLL
+
+  * VLAN SR-IOV regression for IXGBE driver (LP: #1658491)
+    - ixgbe: Force VLNCTRL.VFE to be set in all VMDq paths
+
+  * "Out of memory" errors after upgrade to 4.4.0-59 (LP: #1655842)
+    - mm, page_alloc: convert alloc_flags to unsigned
+    - mm, compaction: change COMPACT_ constants into enum
+    - mm, compaction: distinguish COMPACT_DEFERRED from COMPACT_SKIPPED
+    - mm, compaction: simplify __alloc_pages_direct_compact feedback interface
+    - mm, compaction: distinguish between full and partial COMPACT_COMPLETE
+    - mm, compaction: abstract compaction feedback to helpers
+    - mm, oom: protect !costly allocations some more
+    - mm: consider compaction feedback also for costly allocation
+    - mm, oom, compaction: prevent from should_compact_retry looping for ever for
+      costly orders
+    - mm, oom: protect !costly allocations some more for !CONFIG_COMPACTION
+    - mm, oom: prevent premature OOM killer invocation for high order request
+
+  * Backport 3 patches to fix bugs with AIX clients using IBMVSCSI Target Driver
+    (LP: #1657194)
+    - SAUCE: ibmvscsis: Fix max transfer length
+    - SAUCE: ibmvscsis: fix sleeping in interrupt context
+    - SAUCE: ibmvscsis: Fix srp_transfer_data fail return code
+
+  * NVMe: adapter is missing after abnormal shutdown followed by quick reboot,
+    quirk needed (LP: #1656913)
+    - nvme: apply DELAY_BEFORE_CHK_RDY quirk at probe time too
+
+  * Ubuntu 16.10 KVM SRIOV: if enable sriov while ping flood is running ping
+    will stop working (LP: #1625318)
+    - PCI: Do any VF BAR updates before enabling the BARs
+    - PCI: Ignore BAR updates on virtual functions
+    - PCI: Update BARs using property bits appropriate for type
+    - PCI: Separate VF BAR updates from standard BAR updates
+    - PCI: Don't update VF BARs while VF memory space is enabled
+    - PCI: Remove pci_resource_bar() and pci_iov_resource_bar()
+    - PCI: Decouple IORESOURCE_ROM_ENABLE and PCI_ROM_ADDRESS_ENABLE
+    - PCI: Add comments about ROM BAR updating
+
+  * Linux rtc self test fails in a VM under xenial (LP: #1649718)
+    - kvm: x86: Convert ioapic->rtc_status.dest_map to a struct
+    - kvm: x86: Track irq vectors in ioapic->rtc_status.dest_map
+    - kvm: x86: Check dest_map->vector to match eoi signals for rtc
+
+  * Xenial update to v4.4.44 stable release (LP: #1658091)
+    - Input: xpad - use correct product id for x360w controllers
+    - Input: i8042 - add Pegatron touchpad to noloop table
+    - selftests: do not require bash to run netsocktests testcase
+    - selftests: do not require bash for the generated test
+    - mm: fix devm_memremap_pages crash, use mem_hotplug_{begin, done}
+    - ocfs2: fix crash caused by stale lvb with fsdlm plugin
+    - mm/hugetlb.c: fix reservation race when freeing surplus pages
+    - KVM: x86: fix emulation of "MOV SS, null selector"
+    - KVM: eventfd: fix NULL deref irqbypass consumer
+    - jump_labels: API for flushing deferred jump label updates
+    - KVM: x86: flush pending lapic jump label updates on module unload
+    - KVM: x86: add Align16 instruction flag
+    - KVM: x86: add asm_safe wrapper
+    - KVM: x86: emulate FXSAVE and FXRSTOR
+    - KVM: x86: Introduce segmented_write_std
+    - nl80211: fix sched scan netlink socket owner destruction
+    - USB: serial: kl5kusb105: fix line-state error handling
+    - USB: serial: ch341: fix initial modem-control state
+    - USB: serial: ch341: fix open error handling
+    - USB: serial: ch341: fix control-message error handling
+    - USB: serial: ch341: fix open and resume after B0
+    - Input: elants_i2c - avoid divide by 0 errors on bad touchscreen data
+    - i2c: print correct device invalid address
+    - i2c: fix kernel memory disclosure in dev interface
+    - xhci: fix deadlock at host remove by running watchdog correctly
+    - vme: Fix wrong pointer utilization in ca91cx42_slave_get
+    - mnt: Protect the mountpoint hashtable with mount_lock
+    - tty/serial: atmel_serial: BUG: stop DMA from transmitting in stop_tx
+    - sysrq: attach sysrq handler correctly for 32-bit kernel
+    - sysctl: Drop reference added by grab_header in proc_sys_readdir
+    - drm/radeon: drop verde dpm quirks
+    - USB: serial: ch341: fix resume after reset
+    - USB: serial: ch341: fix modem-control and B0 handling
+    - x86/cpu: Fix bootup crashes by sanitizing the argument of the 'clearcpuid='
+      command-line option
+    - btrfs: fix locking when we put back a delayed ref that's too new
+    - btrfs: fix error handling when run_delayed_extent_op fails
+    - pinctrl: meson: fix gpio request disabling other modes
+    - pNFS: Fix race in pnfs_wait_on_layoutreturn
+    - NFS: Fix a performance regression in readdir
+    - NFSv4.1: nfs4_fl_prepare_ds must be careful about reporting success.
+    - cpufreq: powernv: Disable preemption while checking CPU throttling state
+    - block: cfq_cpd_alloc() should use @gfp
+    - ACPI / APEI: Fix NMI notification handling
+    - blk-mq: Always schedule hctx->next_cpu
+    - bus: vexpress-config: fix device reference leak
+    - powerpc/ibmebus: Fix further device reference leaks
+    - powerpc/ibmebus: Fix device reference leaks in sysfs interface
+    - pinctrl: sh-pfc: Do not unconditionally support PIN_CONFIG_BIAS_DISABLE
+    - Linux 4.4.44
+
+  * Add support for RT5660 codec based sound cards on Baytrail (LP: #1657674)
+    - ASoC: rt5660: add rt5660 codec driver
+    - ASoC: rt5660: enable MCLK detection
+    - ASoC: Intel: Atom: flip logic for gain Switch
+    - SAUCE: (no-up) ASoC: rt5660: Add ACPI support
+    - SAUCE: (no-up) ASoC: Intel: Support machine driver for RT5660 on Baytrail
+    - [Config] CONFIG_SND_SOC_INTEL_BYTCR_RT5660_MACH=m, CONFIG_SND_SOC_RT5660=m
+
+  * Support latest Redpine WLAN/BT RS9113 driver (LP: #1657682)
+    - SAUCE: Support Redpine RS9113 WLAN/BT
+    - SAUCE: Separate Redpine RS9113 WLAN/BT vendor and kernel drivers
+    - SAUCE: Redpine RS9113 WLAN/BT driver ver. 0.9.7
+    - SAUCE: RS9113: Use vendor driver to support WLAN/BT card on Caracalla HW
+      only
+    - SAUCE: RS9113: Comment out IDs from upstream driver
+    - [Config] Enable CONFIG_VEN_RSI_* configs
+
+  * [Hyper-V] netvsc: add rcu_read locked to netvsc callback (LP: #1657540)
+    - netvsc: add rcu_read locking to netvsc callback
+
+  * [Hyper-V] Rebase Hyper-V in 16.04 and 16.10 to the the upstream 4.9 kernel
+    (LP: #1650059)
+    - memory-hotplug: add automatic onlining policy for the newly added memory
+    - hv_netvsc: Add query for initial physical link speed
+    - hv_netvsc: Add handler for physical link speed change
+    - hv_netvsc: Implement batching of receive completions
+    - PCI: hv: Use list_move_tail() instead of list_del() + list_add_tail()
+    - hv_netvsc: fix rtnl locking in callback
+    - hv_netvsc: make RSS hash key static
+    - hv_netvsc: use kcalloc
+    - hv_netvsc: style cleanups
+    - hv_netvsc: make inline functions static
+    - hv_netvsc: use ARRAY_SIZE() for NDIS versions
+    - hv_netvsc: make device_remove void
+    - hv_netvsc: init completion during alloc
+    - hv_netvsc: rearrange start_xmit
+    - hv_netvsc: refactor completion function
+    - hv_netvsc: make netvsc_destroy_buf void
+    - hv_netvsc: make variable local
+    - hv_netvsc: report vmbus name in ethtool
+    - hv_netvsc: add ethtool statistics for tx packet issues
+    - Drivers: hv: get rid of redundant messagecount in create_gpadl_header()
+    - Drivers: hv: don't leak memory in vmbus_establish_gpadl()
+    - Drivers: hv: get rid of timeout in vmbus_open()
+    - Drivers: hv: utils: fix a race on userspace daemons registration
+    - Drivers: hv: vmbus: fix the race when querying & updating the percpu list
+    - Drivers: hv: vmbus: Enable explicit signaling policy for NIC channels
+    - Drivers: hv: vmbus: Reduce the delay between retries in vmbus_post_msg()
+    - Drivers: hv: vmbus: Implement a mechanism to tag the channel for low latency
+    - Tools: hv: kvp: ensure kvp device fd is closed on exec
+    - Drivers: hv: balloon: keep track of where ha_region starts
+    - Drivers: hv: balloon: account for gaps in hot add regions
+    - Drivers: hv: balloon: don't wait for ol_waitevent when memhp_auto_online is
+      enabled
+    - Drivers: hv: balloon: replace ha_region_mutex with spinlock
+    - Drivers: hv: balloon: Use available memory value in pressure report
+    - Drivers: hv: cleanup vmbus_open() for wrap around mappings
+    - Drivers: hv: ring_buffer: wrap around mappings for ring buffers
+    - Drivers: hv: ring_buffer: use wrap around mappings in hv_copy{from,
+      to}_ringbuffer()
+    - Drivers: hv: ring_buffer: count on wrap around mappings in
+      get_next_pkt_raw()
+    - Drivers: hv: Introduce a policy for controlling channel affinity
+    - Drivers: hv: utils: Continue to poll VSS channel after handling requests.
+    - Drivers: hv: utils: Check VSS daemon is listening before a hot backup
+    - PCI: hv: Use zero-length array in struct pci_packet
+    - PCI: hv: Use pci_function_description[0] in struct definitions
+    - PCI: hv: Remove the unused 'wrk' in struct hv_pcibus_device
+    - PCI: hv: Handle vmbus_sendpacket() failure in hv_compose_msi_msg()
+    - PCI: hv: Handle hv_pci_generic_compl() error case
+    - Revert "Drivers: hv: ring_buffer: count on wrap around mappings in
+      get_next_pkt_raw()"
+    - Driver: hv: vmbus: Make mmio resource local
+    - Drivers: hv: vmbus: suppress some "hv_vmbus: Unknown GUID" warnings
+    - Drivers: hv: utils: Rename version definitions to reflect protocol version.
+    - Drivers: hv: utils: Use TimeSync samples to adjust the clock after boot.
+    - Drivers: hv: utils: Support TimeSync version 4.0 protocol samples.
+    - Drivers: hv: hv_util: Avoid dynamic allocation in time synch
+    - Revert "hv_netvsc: make inline functions static"
+    - hv_netvsc: use consume_skb
+    - hv_netvsc: dev hold/put reference to VF
+    - hv_netvsc: simplify callback event code
+    - hv_netvsc: improve VF device matching
+    - hv_netvsc: use RCU to protect vf_netdev
+    - hv_netvsc: remove VF in flight counters
+    - hv_netvsc: count multicast packets received
+    - hv_netvsc: fix comments
+    - Drivers: hv: make VMBus bus ids persistent
+    - Drivers: hv: get rid of id in struct vmbus_channel
+    - netvsc: fix checksum on UDP IPV6
+    - netvsc: Remove mistaken udp.h inclusion.
+    - net/hyperv: avoid uninitialized variable
+    - Revert "hv_netvsc: report vmbus name in ethtool"
+    - vmbus: make sysfs names consistent with PCI
+    - netvsc: reduce maximum GSO size
+    - Drivers: hv: vmbus: Base host signaling strictly on the ring state
+    - tools: hv: Add a script to help bonding synthetic and VF NICs
+
+  * Ubuntu - ibmveth: abnormally large TCP MSS value caused a TCP session to
+    hang with a zero window (LP: #1655420)
+    - ibmveth: set correct gso_size and gso_type
+    - ibmveth: calculate gso_segs for large packets
+
+  * netfilter regression introducing a performance slowdown in binary
+    arp/ip/ip6tables (LP: #1640786)
+    - netfilter: x_tables: pass xt_counters struct instead of packet counter
+    - netfilter: x_tables: pass xt_counters struct to counter allocator
+    - netfilter: x_tables: pack percpu counter allocations
+
+  * Move some kernel modules to the main kernel package (part 2) (LP: #1655002)
+    - [Config] Add IBM power drivers to the inclusion list
+
+  * Xenial update to v4.4.43 stable release (LP: #1656876)
+    - netvsc: reduce maximum GSO size
+    - ser_gigaset: return -ENOMEM on error instead of success
+    - net: vrf: Drop conntrack data after pass through VRF device on Tx
+    - ipv6: handle -EFAULT from skb_copy_bits
+    - net, sched: fix soft lockup in tc_classify
+    - net: stmmac: Fix race between stmmac_drv_probe and stmmac_open
+    - net/mlx5: Check FW limitations on log_max_qp before setting it
+    - net/mlx5: Avoid shadowing numa_node
+    - drop_monitor: add missing call to genlmsg_end
+    - drop_monitor: consider inserted data in genlmsg_end
+    - igmp: Make igmp group member RFC 3376 compliant
+    - ipv4: Do not allow MAIN to be alias for new LOCAL w/ custom rules
+    - r8152: split rtl8152_suspend function
+    - r8152: fix rx issue for runtime suspend
+    - gro: Enter slow-path if there is no tailroom
+    - gro: use min_t() in skb_gro_reset_offset()
+    - gro: Disable frag0 optimization on IPv6 ext headers
+    - net: ipv4: Fix multipath selection with vrf
+    - net: vrf: do not allow table id 0
+    - HID: hid-cypress: validate length of report
+    - ALSA: firewire-tascam: Fix to handle error from initialization of stream
+      data
+    - powerpc: Fix build warning on 32-bit PPC
+    - ARM: zynq: Reserve correct amount of non-DMA RAM
+    - ARM: OMAP4+: Fix bad fallthrough for cpuidle
+    - spi: mvebu: fix baudrate calculation for armada variant
+    - ALSA: usb-audio: Add a quirk for Plantronics BT600
+    - mm/init: fix zone boundary creation
+    - Linux 4.4.43
+
+  * Xenial update to v4.4.42 stable release (LP: #1655969)
+    - ALSA: hda - Fix up GPIO for ASUS ROG Ranger
+    - ALSA: hda - Apply asus-mode8 fixup to ASUS X71SL
+    - ALSA: usb-audio: Fix irq/process data synchronization
+    - ARM: davinci: da850: don't add emac clock to lookup table twice
+    - mac80211: initialize fast-xmit 'info' later
+    - KVM: x86: reset MMU on KVM_SET_VCPU_EVENTS
+    - KVM: MIPS: Flush KVM entry code from icache globally
+    - usb: musb: core: add clear_ep_rxintr() to musb_platform_ops
+    - usb: musb: dsps: implement clear_ep_rxintr() callback
+    - usb: storage: unusual_uas: Add JMicron JMS56x to unusual device
+    - usb: gadgetfs: restrict upper bound on device configuration size
+    - USB: gadgetfs: fix unbounded memory allocation bug
+    - USB: gadgetfs: fix use-after-free bug
+    - USB: gadgetfs: fix checks of wTotalLength in config descriptors
+    - USB: fix problems with duplicate endpoint addresses
+    - USB: dummy-hcd: fix bug in stop_activity (handle ep0)
+    - usb: gadget: composite: Test get_alt() presence instead of set_alt()
+    - usb: dwc3: core: avoid Overflow events
+    - usb: xhci: fix possible wild pointer
+    - xhci: workaround for hosts missing CAS bit
+    - usb: xhci: apply XHCI_PME_STUCK_QUIRK to Intel Apollo Lake
+    - xhci: free xhci virtual devices with leaf nodes first
+    - usb: xhci: fix return value of xhci_setup_device()
+    - usb: host: xhci: Fix possible wild pointer when handling abort command
+    - xhci: Handle command completion and timeout race
+    - usb: xhci: hold lock over xhci_abort_cmd_ring()
+    - USB: serial: omninet: fix NULL-derefs at open and disconnect
+    - USB: serial: quatech2: fix sleep-while-atomic in close
+    - USB: serial: pl2303: fix NULL-deref at open
+    - USB: serial: keyspan_pda: verify endpoints at probe
+    - USB: serial: spcp8x5: fix NULL-deref at open
+    - USB: serial: io_ti: fix NULL-deref at open
+    - USB: serial: io_ti: fix another NULL-deref at open
+    - USB: serial: io_ti: fix I/O after disconnect
+    - USB: serial: iuu_phoenix: fix NULL-deref at open
+    - USB: serial: garmin_gps: fix memory leak on failed URB submit
+    - USB: serial: ti_usb_3410_5052: fix NULL-deref at open
+    - USB: serial: io_edgeport: fix NULL-deref at open
+    - USB: serial: oti6858: fix NULL-deref at open
+    - USB: serial: cyberjack: fix NULL-deref at open
+    - USB: serial: kobil_sct: fix NULL-deref in write
+    - USB: serial: mos7840: fix NULL-deref at open
+    - USB: serial: mos7720: fix NULL-deref at open
+    - USB: serial: mos7720: fix use-after-free on probe errors
+    - USB: serial: mos7720: fix parport use-after-free on probe errors
+    - USB: serial: mos7720: fix parallel probe
+    - usb: xhci-mem: use passed in GFP flags instead of GFP_KERNEL
+    - xhci: Use delayed_work instead of timer for command timeout
+    - xhci: Fix race related to abort operation
+    - usb: dwc3: pci: add Intel Gemini Lake PCI ID
+    - usb: musb: Fix trying to free already-free IRQ 4
+    - usb: hub: Move hub_port_disable() to fix warning if PM is disabled
+    - usb: musb: blackfin: add bfin_fifo_offset in bfin_ops
+    - ALSA: usb-audio: Fix bogus error return in snd_usb_create_stream()
+    - USB: serial: kl5kusb105: abort on open exception path
+    - ARM: dts: r8a7794: Correct hsusb parent clock
+    - USB: phy: am335x-control: fix device and of_node leaks
+    - USB: serial: io_ti: bind to interface after fw download
+    - mei: bus: fix mei_cldev_enable KDoc
+    - staging: iio: ad7606: fix improper setting of oversampling pins
+    - usb: dwc3: gadget: always unmap EP0 requests
+    - usb: dwc3: ep0: add dwc3_ep0_prepare_one_trb()
+    - usb: dwc3: ep0: explicitly call dwc3_ep0_prepare_one_trb()
+    - stable-fixup: hotplug: fix unused function warning
+    - ath10k: use the right length of "background"
+    - cris: Only build flash rescue image if CONFIG_ETRAX_AXISFLASHMAP is selected
+    - hwmon: (scpi) Fix module autoload
+    - hwmon: (amc6821) sign extension temperature
+    - hwmon: (ds620) Fix overflows seen when writing temperature limits
+    - hwmon: (nct7802) Fix overflows seen when writing into limit attributes
+    - hwmon: (g762) Fix overflows and crash seen when writing limit attributes
+    - clk: clk-wm831x: fix a logic error
+    - clk: imx31: fix rewritten input argument of mx31_clocks_init()
+    - iommu/amd: Missing error code in amd_iommu_init_device()
+    - iommu/amd: Fix the left value check of cmd buffer
+    - iommu/vt-d: Fix pasid table size encoding
+    - iommu/vt-d: Flush old iommu caches for kdump when the device gets context
+      mapped
+    - ASoC: samsung: i2s: Fixup last IRQ unsafe spin lock call
+    - scsi: mvsas: fix command_active typo
+    - target/iscsi: Fix double free in lio_target_tiqn_addtpg()
+    - irqchip/bcm7038-l1: Implement irq_cpu_offline() callback
+    - PM / wakeirq: Fix dedicated wakeirq for drivers not using autosuspend
+    - mmc: mmc_test: Uninitialized return value
+    - s390/crypto: unlock on error in prng_tdes_read()
+    - crypto: arm64/sha2-ce - fix for big endian
+    - crypto: arm64/ghash-ce - fix for big endian
+    - crypto: arm/aes-ce - fix for big endian
+    - crypto: arm64/aes-ccm-ce: fix for big endian
+    - crypto: arm64/aes-neon - fix for big endian
+    - crypto: arm64/sha1-ce - fix for big endian
+    - crypto: arm64/aes-xts-ce: fix for big endian
+    - crypto: arm64/aes-ce - fix for big endian
+    - md: MD_RECOVERY_NEEDED is set for mddev->recovery
+    - powerpc/pci/rpadlpar: Fix device reference leaks
+    - staging: comedi: dt282x: tidy up register bit defines
+    - cred/userns: define current_user_ns() as a function
+    - net: ti: cpmac: Fix compiler warning due to type confusion
+    - net: vxge: avoid unused function warnings
+    - cx23885-dvb: move initialization of a8293_pdata
+    - drm/radeon: Always store CRTC relative radeon_crtc->cursor_x/y values
+    - tick/broadcast: Prevent NULL pointer dereference
+    - Revert "usb: gadget: composite: always set ep->mult to a sensible value"
+    - usb: gadget: composite: always set ep->mult to a sensible value
+    - Linux 4.4.42
+
+  * Xenial update to v4.4.41 stable release (LP: #1655041)
+    - ssb: Fix error routine when fallback SPROM fails
+    - rtlwifi: Fix enter/exit power_save
+    - cfg80211/mac80211: fix BSS leaks when abandoning assoc attempts
+    - ath9k: Really fix LED polarity for some Mini PCI AR9220 MB92 cards.
+    - mmc: sdhci: Fix recovery from tuning timeout
+    - regulator: stw481x-vmmc: fix ages old enable error
+    - timekeeping_Force_unsigned_clocksource_to_nanoseconds_conversion
+    - clk: bcm2835: Avoid overwriting the div info when disabling a pll_div clk
+    - thermal: hwmon: Properly report critical temperature in sysfs
+    - staging: comedi: ni_mio_common: fix M Series ni_ai_insn_read() data mask
+    - staging: comedi: ni_mio_common: fix E series ni_ai_insn_read() data
+    - ACPI / video: Add force_native quirk for Dell XPS 17 L702X
+    - ACPI / video: Add force_native quirk for HP Pavilion dv6
+    - drm/nouveau/kms: lvds panel strap moved again on maxwell
+    - drm/nouveau/bios: require checksum to match for fast acpi shadow method
+    - drm/nouveau/ltc: protect clearing of comptags with mutex
+    - drm/nouveau/fifo/gf100-: protect channel preempt with subdev mutex
+    - drm/nouveau/i2c/gk110b,gm10x: use the correct implementation
+    - drm/radeon: Also call cursor_move_locked when the cursor size changes
+    - drm/radeon: Hide the HW cursor while it's out of bounds
+    - drm/radeon: add additional pci revision to dpm workaround
+    - drm/gma500: Add compat ioctl
+    - drivers/gpu/drm/ast: Fix infinite loop if read fails
+    - mei: request async autosuspend at the end of enumeration
+    - block: protect iterate_bdevs() against concurrent close
+    - vt: fix Scroll Lock LED trigger name
+    - scsi: megaraid_sas: For SRIOV enabled firmware, ensure VF driver waits for
+      30secs before reset
+    - scsi: megaraid_sas: Do not set MPI2_TYPE_CUDA for JBOD FP path for FW which
+      does not support JBOD sequence map
+    - scsi: zfcp: fix use-after-"free" in FC ingress path after TMF
+    - scsi: zfcp: do not trace pure benign residual HBA responses at default level
+    - scsi: zfcp: fix rport unblock race with LUN recovery
+    - scsi: avoid a permanent stop of the scsi device's request queue
+    - ARC: mm: arc700: Don't assume 2 colours for aliasing VIPT dcache
+    - firmware: fix usermode helper fallback loading
+    - s390/vmlogrdr: fix IUCV buffer allocation
+    - sc16is7xx: Drop bogus use of IRQF_ONESHOT
+    - md/raid5: limit request size according to implementation limits
+    - KVM: PPC: Book3S HV: Save/restore XER in checkpointed register state
+    - KVM: PPC: Book3S HV: Don't lose hardware R/C bit updates in H_PROTECT
+    - kvm: nVMX: Allow L1 to intercept software exceptions (#BP and #OF)
+    - platform/x86: asus-nb-wmi.c: Add X45U quirk
+    - fgraph: Handle a case where a tracer ignores set_graph_notrace
+    - IB/mad: Fix an array index check
+    - IPoIB: Avoid reading an uninitialized member variable
+    - IB/multicast: Check ib_find_pkey() return value
+    - IB/cma: Fix a race condition in iboe_addr_get_sgid()
+    - media: solo6x10: fix lockup by avoiding delayed register write
+    - Input: drv260x - fix input device's parent assignment
+    - PCI: Check for PME in targeted sleep state
+    - libceph: verify authorize reply on connect
+    - nfs_write_end(): fix handling of short copies
+    - powerpc/ps3: Fix system hang with GCC 5 builds
+    - powerpc: Convert cmp to cmpd in idle enter sequence
+    - kconfig/nconf: Fix hang when editing symbol with a long prompt
+    - sg_write()/bsg_write() is not fit to be called under KERNEL_DS
+    - net: mvpp2: fix dma unmapping of TX buffers for fragments
+    - Linux 4.4.41
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 01 Feb 2017 14:00:35 -0200
+
+linux (4.4.0-62.83) xenial; urgency=low
+
+  [ Thadeu Lima de Souza Cascardo ]
+
+  * Release Tracking Bug
+    - LP: #1657430
+
+  * Backport DP MST fixes to i915 (LP: #1657353)
+    - SAUCE: i915_bpo: Fix DP link rate math
+    - SAUCE: i915_bpo: Validate mode against max. link data rate for DP MST
+
+  * Ubuntu xenial - 4.4.0-59-generic i3 I/O performance issue (LP: #1657281)
+    - blk-mq: really fix plug list flushing for nomerge queues
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 18 Jan 2017 09:34:07 -0200
+
+linux (4.4.0-61.82) xenial; urgency=low
+
+  [ Thadeu Lima de Souza Cascardo ]
+
+  * Release Tracking Bug
+    - LP: #1656810
+
+  * Xen MSI setup code incorrectly re-uses cached pirq (LP: #1656381)
+    - SAUCE: xen: do not re-use pirq number cached in pci device msi msg data
+
+  * nvme drive probe failure (LP: #1626894)
+    - nvme: revert NVMe: only setup MSIX once
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 16 Jan 2017 10:30:12 -0200
+
+linux (4.4.0-60.81) xenial; urgency=low
+
+  [ John Donnelly ]
+
+  * Release Tracking Bug
+    - LP: #1656084
+
+  * Couldn't emulate instruction 0x7813427c (LP: #1634129)
+    - KVM: PPC: Book3S PR: Fix illegal opcode emulation
+
+  * perf: 24x7: Eliminate domain name suffix in event names (LP: #1560482)
+    - powerpc/perf/hv-24x7: Fix usage with chip events.
+    - powerpc/perf/hv-24x7: Display change in counter values
+    - powerpc/perf/hv-24x7: Display domain indices in sysfs
+    - powerpc/perf/24x7: Eliminate domain suffix in event names
+
+  * i386 ftrace tests hang on ADT testing (LP: #1655040)
+    - ftrace/x86_32: Set ftrace_stub to weak to prevent gcc from using short jumps
+      to it
+
+  * VMX module autoloading if available (LP: #1651322)
+    - powerpc: Add module autoloading based on CPU features
+    - crypto: vmx - Convert to CPU feature based module autoloading
+
+  * ACPI probe support for AD5592/3 configurable multi-channel converter
+    (LP: #1654497)
+    - SAUCE: iio: dac: ad5592r: Add ACPI support
+    - SAUCE: iio: dac: ad5593r: Add ACPI support
+
+  * Xenial update to v4.4.40 stable release (LP: #1654602)
+    - btrfs: limit async_work allocation and worker func duration
+    - Btrfs: fix tree search logic when replaying directory entry deletes
+    - btrfs: store and load values of stripes_min/stripes_max in balance status
+      item
+    - Btrfs: fix qgroup rescan worker initialization
+    - USB: serial: option: add support for Telit LE922A PIDs 0x1040, 0x1041
+    - USB: serial: option: add dlink dwm-158
+    - USB: serial: kl5kusb105: fix open error path
+    - USB: cdc-acm: add device id for GW Instek AFG-125
+    - usb: hub: Fix auto-remount of safely removed or ejected USB-3 devices
+    - usb: gadget: f_uac2: fix error handling at afunc_bind
+    - usb: gadget: composite: correctly initialize ep->maxpacket
+    - USB: UHCI: report non-PME wakeup signalling for Intel hardware
+    - ALSA: usb-audio: Add QuickCam Communicate Deluxe/S7500 to
+      volume_control_quirks
+    - ALSA: hiface: Fix M2Tech hiFace driver sampling rate change
+    - ALSA: hda/ca0132 - Add quirk for Alienware 15 R2 2016
+    - ALSA: hda - ignore the assoc and seq when comparing pin configurations
+    - ALSA: hda - fix headset-mic problem on a Dell laptop
+    - ALSA: hda - Gate the mic jack on HP Z1 Gen3 AiO
+    - ALSA: hda: when comparing pin configurations, ignore assoc in addition to
+      seq
+    - clk: ti: omap36xx: Work around sprz319 advisory 2.1
+    - Btrfs: fix memory leak in reading btree blocks
+    - Btrfs: bail out if block group has different mixed flag
+    - Btrfs: return gracefully from balance if fs tree is corrupted
+    - Btrfs: don't leak reloc root nodes on error
+    - Btrfs: fix memory leak in do_walk_down
+    - Btrfs: don't BUG() during drop snapshot
+    - btrfs: make file clone aware of fatal signals
+    - block_dev: don't test bdev->bd_contains when it is not stable
+    - ptrace: Capture the ptracer's creds not PT_PTRACE_CAP
+    - crypto: caam - fix AEAD givenc descriptors
+    - ext4: fix mballoc breakage with 64k block size
+    - ext4: fix stack memory corruption with 64k block size
+    - ext4: use more strict checks for inodes_per_block on mount
+    - ext4: fix in-superblock mount options processing
+    - ext4: add sanity checking to count_overhead()
+    - ext4: reject inodes with negative size
+    - ext4: return -ENOMEM instead of success
+    - ext4: do not perform data journaling when data is encrypted
+    - f2fs: set ->owner for debugfs status file's file_operations
+    - loop: return proper error from loop_queue_rq()
+    - mm/vmscan.c: set correct defer count for shrinker
+    - fs: exec: apply CLOEXEC before changing dumpable task flags
+    - exec: Ensure mm->user_ns contains the execed files
+    - usb: gadget: composite: always set ep->mult to a sensible value
+    - blk-mq: Do not invoke .queue_rq() for a stopped queue
+    - dm flakey: return -EINVAL on interval bounds error in flakey_ctr()
+    - dm crypt: mark key as invalid until properly loaded
+    - dm space map metadata: fix 'struct sm_metadata' leak on failed create
+    - ASoC: intel: Fix crash at suspend/resume without card registration
+    - CIFS: Fix a possible memory corruption during reconnect
+    - CIFS: Fix missing nls unload in smb2_reconnect()
+    - CIFS: Fix a possible memory corruption in push locks
+    - kernel/watchdog: use nmi registers snapshot in hardlockup handler
+    - kernel/debug/debug_core.c: more properly delay for secondary CPUs
+    - tpm xen: Remove bogus tpm_chip_unregister
+    - xen/gntdev: Use VM_MIXEDMAP instead of VM_IO to avoid NUMA balancing
+    - arm/xen: Use alloc_percpu rather than __alloc_percpu
+    - xfs: set AGI buffer type in xlog_recover_clear_agi_bucket
+    - driver core: fix race between creating/querying glue dir and its cleanup
+    - ppp: defer netns reference release for ppp channel
+    - Linux 4.4.40
+
+  * igb i210 probe of pci device failed with error -2 (LP: #1639810)
+    - SAUCE: igb: Workaround for igb i210 firmware issue.
+    - SAUCE: igb: add i211 to i210 PHY workaround
+
+  * PowerNV: PCI Slot is invalid after fencedPHB Error injection (LP: #1652018)
+    - powerpc/powernv: Call opal_pci_poll() if needed
+
+  * mfd: intel-lpss: Add default I2C device properties for Apollo Lake
+    (LP: #1635177)
+    - mfd: intel-lpss: Add default I2C device properties for Apollo Lake
+
+  * Xenial update to v4.4.39 stable release (LP: #1650609)
+    - powerpc/eeh: Fix deadlock when PE frozen state can't be cleared
+    - parisc: Purge TLB before setting PTE
+    - parisc: Remove unnecessary TLB purges from flush_dcache_page_asm and
+      flush_icache_page_asm
+    - parisc: Fix TLB related boot crash on SMP machines
+    - zram: restrict add/remove attributes to root only
+    - locking/rtmutex: Prevent dequeue vs. unlock race
+    - locking/rtmutex: Use READ_ONCE() in rt_mutex_owner()
+    - perf/x86: Fix full width counter, counter overflow
+    - crypto: mcryptd - Check mcryptd algorithm compatibility
+    - can: raw: raw_setsockopt: limit number of can_filter that can be set
+    - can: peak: fix bad memory access and free sequence
+    - arm64: futex.h: Add missing PAN toggling
+    - m68k: Fix ndelay() macro
+    - batman-adv: Check for alloc errors when preparing TT local data
+    - hotplug: Make register and unregister notifier API symmetric
+    - crypto: rsa - Add Makefile dependencies to fix parallel builds
+    - Linux 4.4.39
+
+  * Xenial update to v4.4.38 stable release (LP: #1650607)
+    - virtio-net: add a missing synchronize_net()
+    - net: check dead netns for peernet2id_alloc()
+    - ip6_tunnel: disable caching when the traffic class is inherited
+    - net: sky2: Fix shutdown crash
+    - af_unix: conditionally use freezable blocking calls in read
+    - rtnetlink: fix FDB size computation
+    - l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()
+    - net: dsa: bcm_sf2: Ensure we re-negotiate EEE during after link change
+    - net, sched: respect rcu grace period on cls destruction
+    - net/sched: pedit: make sure that offset is valid
+    - netlink: Call cb->done from a worker thread
+    - netlink: Do not schedule work from sk_destruct
+    - net/dccp: fix use-after-free in dccp_invalid_packet
+    - net: bcmgenet: Utilize correct struct device for all DMA operations
+    - sh_eth: remove unchecked interrupts for RZ/A1
+    - geneve: avoid use-after-free of skb->data
+    - net: ping: check minimum size on ICMP header length
+    - sparc32: Fix inverted invalid_frame_pointer checks on sigreturns
+    - sparc64: Fix find_node warning if numa node cannot be found
+    - sparc64: fix compile warning section mismatch in find_node()
+    - constify iov_iter_count() and iter_is_iovec()
+    - Don't feed anything but regular iovec's to blk_rq_map_user_iov
+    - ipv6: Set skb->protocol properly for local output
+    - ipv4: Set skb->protocol properly for local output
+    - esp4: Fix integrity verification when ESN are used
+    - esp6: Fix integrity verification when ESN are used
+    - Linux 4.4.38
+
+  * Xenial update to v4.4.37 stable release (LP: #1650604)
+    - ARC: Don't use "+l" inline asm constraint
+    - zram: fix unbalanced idr management at hot removal
+    - kasan: update kasan_global for gcc 7
+    - x86/traps: Ignore high word of regs->cs in early_fixup_exception()
+    - rcu: Fix soft lockup for rcu_nocb_kthread
+    - PCI: Export pcie_find_root_port
+    - PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)
+    - mwifiex: printk() overflow with 32-byte SSIDs
+    - pwm: Fix device reference leak
+    - arm64: cpufeature: Schedule enable() calls instead of calling them via IPI
+    - arm64: mm: Set PSTATE.PAN from the cpu_enable_pan() call
+    - arm64: suspend: Reconfigure PSTATE after resume from idle
+    - Linux 4.4.37
+
+  * Xenial update to v4.4.36 stable release (LP: #1650601)
+    - iommu/vt-d: Fix PASID table allocation
+    - iommu/vt-d: Fix IOMMU lookup for SR-IOV Virtual Functions
+    - KVM: x86: check for pic and ioapic presence before use
+    - usb: chipidea: move the lock initialization to core file
+    - USB: serial: cp210x: add ID for the Zone DPMX
+    - USB: serial: ftdi_sio: add support for TI CC3200 LaunchPad
+    - Fix USB CB/CBI storage devices with CONFIG_VMAP_STACK=y
+    - scsi: mpt3sas: Fix secure erase premature termination
+    - tile: avoid using clocksource_cyc2ns with absolute cycle count
+    - cfg80211: limit scan results cache size
+    - NFSv4.x: hide array-bounds warning
+    - parisc: Fix races in parisc_setup_cache_timing()
+    - parisc: Fix race in pci-dma.c
+    - parisc: Also flush data TLB in flush_icache_page_asm
+    - mpi: Fix NULL ptr dereference in mpi_powm() [ver #3]
+    - drm/radeon: Ensure vblank interrupt is enabled on DPMS transition to on
+    - mei: me: disable driver on SPT SPS firmware
+    - mei: me: fix place for kaby point device ids.
+    - mei: fix return value on disconnection
+    - scsi: mpt3sas: Unblock device after controller reset
+    - Linux 4.4.36
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] consider renames in gen-auto-reconstruct
+
+ -- John Donnelly <john.donnelly@canonical.com>  Fri, 13 Jan 2017 08:54:11 +0000
+
+linux (4.4.0-59.80) xenial; urgency=low
+
+  [ John Donnelly ]
+
+  * Release Tracking Bug
+    - LP: #1654282
+
+  * [2.1.1] MAAS has nvme0n1 set as boot disk, curtin fails (LP: #1651602)
+    - (fix) nvme: only require 1 interrupt vector, not 2+
+
+ -- John Donnelly <john.donnelly@canonical.com>  Thu, 05 Jan 2017 12:49:16 +0000
+
+linux (4.4.0-58.79) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1651402
+
+  * Support ACPI probe for IIO sensor drivers from ST Micro (LP: #1650123)
+    - SAUCE: iio: st_sensors: match sensors using ACPI handle
+    - SAUCE: iio: st_accel: Support sensor i2c probe using acpi
+    - SAUCE: iio: st_pressure: Support i2c probe using acpi
+    - [Config] CONFIG_HTS221=m, CONFIG_HTS221_I2C=m, CONFIG_HTS221_SPI=m
+
+  * Fix channel data parsing in ST Micro sensor IIO drivers (LP: #1650189)
+    - SAUCE: iio: common: st_sensors: fix channel data parsing
+
+  * ST Micro lng2dm 3-axis "femto" accelerometer support (LP: #1650112)
+    - SAUCE: iio: st-accel: add support for lis2dh12
+    - SAUCE: iio: st_sensors: support active-low interrupts
+    - SAUCE: iio: accel: Add support for the h3lis331dl accelerometer
+    - SAUCE: iio: st_sensors: verify interrupt event to status
+    - SAUCE: iio: st_sensors: support open drain mode
+    - SAUCE: iio:st_sensors: fix power regulator usage
+    - SAUCE: iio: st_sensors: switch to a threaded interrupt
+    - SAUCE: iio: accel: st_accel: Add lis3l02dq support
+    - SAUCE: iio: st_sensors: fix scale configuration for h3lis331dl
+    - SAUCE: iio: accel: st_accel: add support to lng2dm
+    - SAUCE: iio: accel: st_accel: inline per-sensor data
+    - SAUCE: Documentation: dt: iio: accel: add lng2dm sensor device binding
+
+  * ST Micro hts221 relative humidity sensor support (LP: #1650116)
+    - SAUCE: iio: humidity: add support to hts221 rh/temp combo device
+    - SAUCE: Documentation: dt: iio: humidity: add hts221 sensor device binding
+    - SAUCE: iio: humidity: remove
+    - SAUCE: iio: humidity: Support acpi probe for hts211
+
+  * crypto : tolerate new crypto hardware for z Systems (LP: #1644557)
+    - s390/zcrypt: Introduce CEX6 toleration
+
+  * Acer, Inc ID 5986:055a is useless after 14.04.2 installed. (LP: #1433906)
+    - uvcvideo: uvc_scan_fallback() for webcams with broken chain
+
+  * vmxnet3 driver could causes kernel panic with v4.4 if LRO enabled.
+    (LP: #1650635)
+    - vmxnet3: segCnt can be 1 for LRO packets
+
+  * system freeze when swapping to encrypted swap partition (LP: #1647400)
+    - mm, oom: rework oom detection
+    - mm: throttle on IO only when there are too many dirty and writeback pages
+
+  * Kernel Fixes to get TCMU File Backed Optical to work (LP: #1646204)
+    - target/user: Use sense_reason_t in tcmu_queue_cmd_ring
+    - target/user: Return an error if cmd data size is too large
+    - target/user: Fix comments to not refer to data ring
+    - SAUCE: (no-up) target/user: Fix use-after-free of tcmu_cmds if they are
+      expired
+
+  * CVE-2016-9756
+    - KVM: x86: drop error recovery in em_jmp_far and em_ret_far
+
+  * Dell Precision 5520 & 3520 freezes at login screent (LP: #1650054)
+    - ACPI / blacklist: add _REV quirks for Dell Precision 5520 and 3520
+
+  * CVE-2016-9794
+    - ALSA: pcm : Call kill_fasync() in stream lock
+
+  * Allow fuse user namespace mounts by default in xenial (LP: #1634964)
+    - (namespace) mnt: Move the FS_USERNS_MOUNT check into sget_userns
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Refuse uid/gid changes which don't
+      map into s_user_ns"
+    - (namespace) fs: Refuse uid/gid changes which don't map into s_user_ns
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Update posix_acl support to handle
+      user namespace mounts"
+    - (namespace) vfs: Verify acls are valid within superblock's s_user_ns.
+    - SAUCE: (namespace) posix_acl: Export posix_acl_fix_xattr_userns() to modules
+    - SAUCE: (namespace) fuse: Translate ids in posix acl xattrs
+    - (namespace) vfs: Don't modify inodes with a uid or gid unknown to the vfs
+    - (namespace) vfs: Don't create inodes with a uid or gid unknown to the vfs
+    - (namespace) Revert "UBUNTU: SAUCE: quota: Require that qids passed to
+      dqget() be valid and map into s_user_ns"
+    - (namespace) Revert "UBUNTU: SAUCE: quota: Convert ids relative to s_user_ns"
+    - (namespace) quota: Ensure qids map to the filesystem
+    - (namespace) quota: Handle quota data stored in s_user_ns in quota_setxquota
+    - (namespace) dquot: For now explicitly don't support filesystems outside of
+      init_user_ns
+    - (namespace) Revert "UBUNTU: SAUCE: ima/evm: Allow root in s_user_ns to set
+      xattrs"
+    - SAUCE: (namespace) security/integrity: Harden against malformed xattrs
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Allow superblock owner to change
+      ownership of inodes with unmappable ids"
+    - SAUCE: (namespace) fs: Allow superblock owner to change ownership of inodes
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Don't remove suid for CAP_FSETID in
+      s_user_ns"
+    - SAUCE: (namespace) fs: Don't remove suid for CAP_FSETID for userns root
+    - SAUCE: (namespace) fuse: Allow user namespace mounts by default
+
+  * Boot crash in xen_send_IPI_one (LP: #1649821)
+    - xen/qspinlock: Don't kick CPU if IRQ is not initialized
+
+  * linux: Staging modules should be unsigned (LP: #1642368)
+    - [Debian] Suppress module signing for staging drivers
+    - SAUCE: Add rtl drivers to signature inclusion list
+
+  * Ethernet not work after upgrade from kernel 3.19 to 4.4 [10ec:8168]
+    (LP: #1648279)
+    - ACPI / blacklist: Make Dell Latitude 3350 ethernet work
+
+  * CVE-2016-9793
+    - net: avoid signed overflows for SO_{SND|RCV}BUFFORCE
+
+  * [Hyper-V] Kernel panic not functional on 32bit Ubuntu 14.10, 15.04, and
+    15.10 (LP: #1400319)
+    - Drivers: hv: avoid vfree() on crash
+
+  * [Hyper-V] netvsc: fix incorrect receive checksum offloading (LP: #1636656)
+    - netvsc: fix incorrect receive checksum offloading
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Tue, 20 Dec 2016 10:54:41 +0000
+
+linux (4.4.0-57.78) xenial; urgency=low
+
+  * Release Tracking Bug
+    - LP: #1648867
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Do not build the xr-usb-serial driver for s390
+
+ -- Brad Figg <brad.figg@canonical.com>  Fri, 09 Dec 2016 10:51:16 -0800
+
+linux (4.4.0-56.77) xenial; urgency=low
+
+  * Release Tracking Bug
+    - LP: #1648867
+
+  * Release Tracking Bug
+    - LP: #1648579
+
+  * CONFIG_NR_CPUS=256 is too low (LP: #1579205)
+    - [Config] Increase the NR_CPUS to 512 for amd64 to support systems with a
+      large number of cores.
+
+  * NVMe drives in Amazon AWS instance fail to initialize (LP: #1648449)
+    - SAUCE: (no-up) NVMe: only setup MSIX once
+
+ -- Brad Figg <brad.figg@canonical.com>  Thu, 08 Dec 2016 10:50:49 -0800
+
+linux (4.4.0-55.76) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1648503
+
+  * NVMe driver accidentally reverted to use GSI instead of MSIX (LP: #1647887)
+    - (fix) NVMe: restore code to always use MSI/MSI-x interrupts
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Thu, 08 Dec 2016 14:34:40 +0000
+
+linux (4.4.0-54.75) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1648017
+
+  * Update hio driver to 2.1.0.28 (LP: #1646643)
+    - SAUCE: hio: update to Huawei ES3000_V2 (2.1.0.28)
+
+  * linux: Enable live patching for all supported architectures (LP: #1633577)
+    - [Config] CONFIG_LIVEPATCH=y for s390x
+
+  * Botched backport breaks level triggered EOIs in QEMU guests with --machine
+    kernel_irqchip=split (LP: #1644394)
+    - kvm/irqchip: kvm_arch_irq_routing_update renaming split
+
+  * Xenial update to v4.4.35 stable release (LP: #1645453)
+    - x86/cpu/AMD: Fix cpu_llc_id for AMD Fam17h systems
+    - KVM: x86: fix missed SRCU usage in kvm_lapic_set_vapic_addr
+    - KVM: Disable irq while unregistering user notifier
+    - fuse: fix fuse_write_end() if zero bytes were copied
+    - mfd: intel-lpss: Do not put device in reset state on suspend
+    - can: bcm: fix warning in bcm_connect/proc_register
+    - i2c: mux: fix up dependencies
+    - kbuild: add -fno-PIE
+    - scripts/has-stack-protector: add -fno-PIE
+    - x86/kexec: add -fno-PIE
+    - kbuild: Steal gcc's pie from the very beginning
+    - ext4: sanity check the block and cluster size at mount time
+    - crypto: caam - do not register AES-XTS mode on LP units
+    - drm/amdgpu: Attach exclusive fence to prime exported bo's. (v5)
+    - clk: mmp: pxa910: fix return value check in pxa910_clk_init()
+    - clk: mmp: pxa168: fix return value check in pxa168_clk_init()
+    - clk: mmp: mmp2: fix return value check in mmp2_clk_init()
+    - rtc: omap: Fix selecting external osc
+    - iwlwifi: pcie: fix SPLC structure parsing
+    - mfd: core: Fix device reference leak in mfd_clone_cell
+    - uwb: fix device reference leaks
+    - PM / sleep: fix device reference leak in test_suspend
+    - PM / sleep: don't suspend parent when async child suspend_{noirq, late}
+      fails
+    - IB/mlx4: Check gid_index return value
+    - IB/mlx4: Fix create CQ error flow
+    - IB/mlx5: Use cache line size to select CQE stride
+    - IB/mlx5: Fix fatal error dispatching
+    - IB/core: Avoid unsigned int overflow in sg_alloc_table
+    - IB/uverbs: Fix leak of XRC target QPs
+    - IB/cm: Mark stale CM id's whenever the mad agent was unregistered
+    - netfilter: nft_dynset: fix element timeout for HZ != 1000
+    - Linux 4.4.35
+
+  * Upstream stable 4.4.34 and 4.8.10 regression (LP: #1645278)
+    - flow_dissect: call init_default_flow_dissectors() earlier
+
+  * AD5593R configurable multi-channel converter support (LP: #1644726)
+    - iio: dac: Add support for the AD5592R/AD5593R ADCs/DACs
+    - iio: dac: ad5592r: Off by one bug in ad5592r_alloc_channels()
+    - [Config] CONFIG_AD5592R/AD5593R=m
+
+  * ST Micro lps22hb pressure sensor support (LP: #1642258)
+    - iio:st_pressure:initial lps22hb sensor support
+    - iio:st_pressure: align storagebits on power of 2
+    - iio:st_pressure: document sampling gains
+    - iio:st_pressure:lps22hb: temperature support
+
+  * Fix Kernel Crashing under IBM Virtual Scsi Driver (LP: #1642299)
+    - SAUCE: ibmvscsis: Rearrange functions for future patches
+    - SAUCE: ibmvscsis: Synchronize cmds at tpg_enable_store time
+    - SAUCE: ibmvscsis: Synchronize cmds at remove time
+    - SAUCE: ibmvscsis: Clean up properly if target_submit_cmd/tmr fails
+    - SAUCE: ibmvscsis: Return correct partition name/# to client
+    - SAUCE: ibmvscsis: Issues from Dan Carpenter/Smatch
+
+  * System stalls when creating device node on booting (LP: #1643797)
+    - sched/fair: Fix new task's load avg removed from source CPU in
+      wake_up_new_task()
+
+  * nvme: improve performance for virtual Google NVMe devices (LP: #1637565)
+    - blk-mq: add blk_mq_alloc_request_hctx
+    - nvme.h: add NVMe over Fabrics definitions
+    - [Config] CONFIG_NVME_VENDOR_EXT_GOOGLE=y
+    - SAUCE: nvme: improve performance for virtual NVMe devices
+
+  * Move some kernel modules to the main kernel package (LP: #1642228)
+    - [Config] Move some powerpc kernel modules to the main kernel package
+
+  * sched: Match-all classifier is missing in xenial (LP: #1642514)
+    - [Config] CONFIG_NET_CLS_MATCHALL=m
+    - net/sched: introduce Match-all classifier
+
+  * Xenial update to 4.4.34 stable release (LP: #1643637)
+    - dctcp: avoid bogus doubling of cwnd after loss
+    - net: clear sk_err_soft in sk_clone_lock()
+    - net: mangle zero checksum in skb_checksum_help()
+    - bgmac: stop clearing DMA receive control register right after it is set
+    - ip6_tunnel: Clear IP6CB in ip6tunnel_xmit()
+    - tcp: fix potential memory corruption
+    - dccp: do not send reset to already closed sockets
+    - dccp: fix out of bound access in dccp_v4_err()
+    - ipv6: dccp: fix out of bound access in dccp_v6_err()
+    - ipv6: dccp: add missing bind_conflict to dccp_ipv6_mapped
+    - sctp: assign assoc_id earlier in __sctp_connect
+    - fib_trie: Correct /proc/net/route off by one error
+    - sock: fix sendmmsg for partial sendmsg
+    - net: __skb_flow_dissect() must cap its return value
+    - ipv4: use new_gw for redirect neigh lookup
+    - tcp: take care of truncations done by sk_filter()
+    - tty: Prevent ldisc drivers from re-using stale tty fields
+    - sparc: Don't leak context bits into thread->fault_address
+    - sparc: serial: sunhv: fix a double lock bug
+    - sparc64 mm: Fix base TSB sizing when hugetlb pages are used
+    - sparc: Handle negative offsets in arch_jump_label_transform
+    - sparc64: Handle extremely large kernel TSB range flushes sanely.
+    - sparc64: Fix illegal relative branches in hypervisor patched TLB code.
+    - sparc64: Fix instruction count in comment for
+      __hypervisor_flush_tlb_pending.
+    - sparc64: Fix illegal relative branches in hypervisor patched TLB cross-call
+      code.
+    - sparc64: Handle extremely large kernel TLB range flushes more gracefully.
+    - sparc64: Delete __ret_efault.
+    - sparc64: Prepare to move to more saner user copy exception handling.
+    - sparc64: Convert copy_in_user to accurate exception reporting.
+    - sparc64: Convert GENcopy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert U1copy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert NG4copy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert NGcopy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert NG2copy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert U3copy_{from,to}_user to accurate exception reporting.
+    - sparc64: Delete now unused user copy assembler helpers.
+    - sparc64: Delete now unused user copy fixup functions.
+    - Linux 4.4.34
+
+  * Xenial update to v4.4.33 stable release (LP: #1642968)
+    - ALSA: info: Return error for invalid read/write
+    - ALSA: info: Limit the proc text input size
+    - ASoC: cs4270: fix DAPM stream name mismatch
+    - dib0700: fix nec repeat handling
+    - swapfile: fix memory corruption via malformed swapfile
+    - coredump: fix unfreezable coredumping task
+    - s390/hypfs: Use get_free_page() instead of kmalloc to ensure page alignment
+    - ARC: timer: rtc: implement read loop in "C" vs. inline asm
+    - pinctrl: cherryview: Serialize register access in suspend/resume
+    - pinctrl: cherryview: Prevent possible interrupt storm on resume
+    - staging: iio: ad5933: avoid uninitialized variable in error case
+    - drivers: staging: nvec: remove bogus reset command for PS/2 interface
+    - Revert "staging: nvec: ps2: change serio type to passthrough"
+    - staging: nvec: remove managed resource from PS2 driver
+    - USB: cdc-acm: fix TIOCMIWAIT
+    - usb: gadget: u_ether: remove interrupt throttling
+    - drbd: Fix kernel_sendmsg() usage - potential NULL deref
+    - toshiba-wmi: Fix loading the driver on non Toshiba laptops
+    - clk: qoriq: Don't allow CPU clocks higher than starting value
+    - iio: hid-sensors: Increase the precision of scale to fix wrong reading
+      interpretation.
+    - iio: orientation: hid-sensor-rotation: Add PM function (fix non working
+      driver)
+    - scsi: qla2xxx: Fix scsi scan hang triggered if adapter fails during init
+    - scsi: mpt3sas: Fix for block device of raid exists even after deleting raid
+      disk
+    - KVM: MIPS: Precalculate MMIO load resume PC
+    - drm/i915: Respect alternate_ddc_pin for all DDI ports
+    - dmaengine: at_xdmac: fix spurious flag status for mem2mem transfers
+    - tty/serial: at91: fix hardware handshake on Atmel platforms
+    - iommu/amd: Free domain id when free a domain of struct dma_ops_domain
+    - iommu/vt-d: Fix dead-locks in disable_dmar_iommu() path
+    - mei: bus: fix received data size check in NFC fixup
+    - lib/genalloc.c: start search from start of chunk
+    - hwrng: core - Don't use a stack buffer in add_early_randomness()
+    - i40e: fix call of ndo_dflt_bridge_getlink()
+    - ACPI / APEI: Fix incorrect return value of ghes_proc()
+    - ASoC: sun4i-codec: return error code instead of NULL when create_card fails
+    - mmc: mxs: Initialize the spinlock prior to using it
+    - btrfs: qgroup: Prevent qgroup->reserved from going subzero
+    - netfilter: fix namespace handling in nf_log_proc_dostring
+    - Linux 4.4.33
+
+  * Xenial update to 4.4.32 stable release (LP: #1642573)
+    - tcp: fix overflow in __tcp_retransmit_skb()
+    - net: avoid sk_forward_alloc overflows
+    - tcp: fix wrong checksum calculation on MTU probing
+    - tcp: fix a compile error in DBGUNDO()
+    - ip6_gre: fix flowi6_proto value in ip6gre_xmit_other()
+    - ipmr, ip6mr: fix scheduling while atomic and a deadlock with ipmr_get_route
+    - tg3: Avoid NULL pointer dereference in tg3_io_error_detected()
+    - net: fec: set mac address unconditionally
+    - net: pktgen: fix pkt_size
+    - net/sched: act_vlan: Push skb->data to mac_header prior calling skb_vlan_*()
+      functions
+    - net: Add netdev all_adj_list refcnt propagation to fix panic
+    - packet: call fanout_release, while UNREGISTERING a netdev
+    - netlink: do not enter direct reclaim from netlink_dump()
+    - ipv6: tcp: restore IP6CB for pktoptions skbs
+    - ip6_tunnel: fix ip6_tnl_lookup
+    - net: pktgen: remove rcu locking in pktgen_change_name()
+    - bridge: multicast: restore perm router ports on multicast enable
+    - rtnetlink: Add rtnexthop offload flag to compare mask
+    - net: add recursion limit to GRO
+    - ipv4: disable BH in set_ping_group_range()
+    - ipv4: use the right lock for ping_group_range
+    - net: sctp, forbid negative length
+    - udp: fix IP_CHECKSUM handling
+    - net sched filters: fix notification of filter delete with proper handle
+    - sctp: validate chunk len before actually using it
+    - packet: on direct_xmit, limit tso and csum to supported devices
+    - of: silence warnings due to max() usage
+    - Revert KVM: MIPS: Drop other CPU ASIDs on guest MMU changes
+    - KVM: MIPS: Drop other CPU ASIDs on guest MMU changes
+    - drm/amdgpu/dp: add back special handling for NUTMEG
+    - drm/amdgpu: fix DP mode validation
+    - drm/radeon: fix DP mode validation
+    - scsi: megaraid_sas: fix macro MEGASAS_IS_LOGICAL to avoid regression
+    - Linux 4.4.32
+
+  * Xenial update to 4.4.31 stable release (LP: #1642572)
+    - i2c: xgene: Avoid dma_buffer overrun
+    - i2c: core: fix NULL pointer dereference under race condition
+    - drm/dp/mst: Clear port->pdt when tearing down the i2c adapter
+    - h8300: fix syscall restarting
+    - libxfs: clean up _calc_dquots_per_chunk
+    - mm/list_lru.c: avoid error-path NULL pointer deref
+    - mm: memcontrol: do not recurse in direct reclaim
+    - ALSA: usb-audio: Add quirk for Syntek STK1160
+    - ALSA: hda - Merge RIRB_PRE_DELAY into CTX_WORKAROUND caps
+    - ALSA: hda - Raise AZX_DCAPS_RIRB_DELAY handling into top drivers
+    - ALSA: hda - allow 40 bit DMA mask for NVidia devices
+    - ALSA: hda - Adding a new group of pin cfg into ALC295 pin quirk table
+    - ALSA: hda - Fix headset mic detection problem for two Dell laptops
+    - ANDROID: binder: Add strong ref checks
+    - ANDROID: binder: Clear binder and cookie when setting handle in flat binder
+      struct
+    - btrfs: fix races on root_log_ctx lists
+    - ubifs: Abort readdir upon error
+    - ubifs: Fix regression in ubifs_readdir()
+    - mei: txe: don't clean an unprocessed interrupt cause.
+    - usb: gadget: function: u_ether: don't starve tx request queue
+    - USB: serial: fix potential NULL-dereference at probe
+    - USB: serial: ftdi_sio: add support for Infineon TriBoard TC2X7
+    - xhci: use default USB_RESUME_TIMEOUT when resuming ports.
+    - usb: increase ohci watchdog delay to 275 msec
+    - Fix potential infoleak in older kernels
+    - vt: clear selection before resizing
+    - xhci: add restart quirk for Intel Wildcatpoint PCH
+    - tty: limit terminal size to 4M chars
+    - USB: serial: cp210x: fix tiocmget error handling
+    - dm: free io_barrier after blk_cleanup_queue call
+    - KVM: x86: fix wbinvd_dirty_mask use-after-free
+    - KVM: MIPS: Make ERET handle ERL before EXL
+    - ovl: fsync after copy-up
+    - parisc: Ensure consistent state when switching to kernel stack at syscall
+      entry
+    - virtio_ring: Make interrupt suppression spec compliant
+    - virtio: console: Unlock vqs while freeing buffers
+    - dm mirror: fix read error on recovery after default leg failure
+    - Input: i8042 - add XMG C504 to keyboard reset table
+    - firewire: net: guard against rx buffer overflows
+    - firewire: net: fix fragmented datagram_size off-by-one
+    - mac80211: discard multicast and 4-addr A-MSDUs
+    - scsi: megaraid_sas: Fix data integrity failure for JBOD (passthrough)
+      devices
+    - scsi: scsi_debug: Fix memory leak if LBP enabled and module is unloaded
+    - scsi: arcmsr: Send SYNCHRONIZE_CACHE command to firmware
+    - mmc: dw_mmc-pltfm: fix the potential NULL pointer dereference
+    - Revert "drm/radeon: fix DP link training issue with second 4K monitor"
+    - drm/radeon/si_dpm: Limit clocks on HD86xx part
+    - drm/radeon/si_dpm: workaround for SI kickers
+    - drm/radeon: drop register readback in cayman_cp_int_cntl_setup
+    - drm/dp/mst: Check peer device type before attempting EDID read
+    - perf build: Fix traceevent plugins build race
+    - x86/xen: fix upper bound of pmd loop in xen_cleanhighmap()
+    - powerpc/ptrace: Fix out of bounds array access warning
+    - ARM: 8584/1: floppy: avoid gcc-6 warning
+    - mm/cma: silence warnings due to max() usage
+    - drm/exynos: fix error handling in exynos_drm_subdrv_open
+    - cgroup: avoid false positive gcc-6 warning
+    - smc91x: avoid self-comparison warning
+    - Disable "frame-address" warning
+    - UBI: fastmap: scrub PEB when bitflips are detected in a free PEB EC header
+    - pwm: Unexport children before chip removal
+    - usb: dwc3: Fix size used in dma_free_coherent()
+    - tty: vt, fix bogus division in csi_J
+    - kvm: x86: Check memopp before dereference (CVE-2016-8630)
+    - ubi: fastmap: Fix add_vol() return value test in ubi_attach_fastmap()
+    - HID: usbhid: add ATEN CS962 to list of quirky devices
+    - Linux 4.4.31
+
+  * CVE-2016-6213
+    - mnt: Add a per mount namespace limit on the number of mounts
+
+  * ThinkPad T460 hotkeys stop working in Ubuntu 16.04 (LP: #1642114)
+    - thinkpad_acpi: Add support for HKEY version 0x200
+
+  * CVE-2016-4568
+    - videobuf2-v4l2: Verify planes array in buffer dequeueing
+
+  * [SRU] Add 0cf3:e009 to btusb (LP: #1641562)
+    - Bluetooth: btusb: Add support for 0cf3:e009
+
+  * Fix resource leak in btusb (LP: #1641569)
+    - SAUCE: Bluetooth: decrease refcount after use
+
+  * WiFi LED doesn't work on some Edge Gateway units (LP: #1640418)
+    - SAUCE: mwifiex: Use PCI ID instead of DMI ID to identify Edge Gateways
+
+  * [Hyper-V] do not lose pending heartbeat vmbus packets (LP: #1632786)
+    - hv: do not lose pending heartbeat vmbus packets
+
+  * ipv6: connected routes are missing after a down/up cycle on the loopback
+    (LP: #1634545)
+    - ipv6: correctly add local routes when lo goes up
+
+  * audit: prevent a new auditd to stop an old auditd still alive (LP: #1633404)
+    - audit: stop an old auditd being starved out by a new auditd
+
+  * hv_set_ifconfig script parsing fails for certain configuration
+    (LP: #1640109)
+    - hv_set_ifconfig -- handle DHCP interfaces correctly
+    - hv_set_ifconfig -- ensure we include the last stanza
+
+  * CVE-2016-7039 and CVE-2016-8666 (LP: #1631287)
+    - Revert "UBUNTU: SAUCE: net: add recursion limit to GRO"
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Wed, 07 Dec 2016 10:13:50 +0000
+
+linux (4.4.0-53.74) xenial; urgency=low
+
+  * CVE-2016-8655 (LP: #1646318)
+    - packet: fix race condition in packet_set_ring
+
+ -- Brad Figg <brad.figg@canonical.com>  Thu, 01 Dec 2016 10:54:01 -0800
+
+linux (4.4.0-51.72) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1644611
+
+  * 4.4.0-1037-snapdragon #41: kernel panic on boot (LP: #1644596)
+    - Revert "dma-mapping: introduce the DMA_ATTR_NO_WARN attribute"
+    - Revert "powerpc: implement the DMA_ATTR_NO_WARN attribute"
+    - Revert "nvme: use the DMA_ATTR_NO_WARN attribute"
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Thu, 24 Nov 2016 17:56:21 +0000
+
+linux (4.4.0-50.71) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1644169
+
+  * xenial 4.4.0-49.70 kernel breaks LXD userspace (LP: #1644165)
+    - Revert "UBUNTU: SAUCE: (namespace) fuse: Allow user namespace mounts by
+      default"
+    - Revert "UBUNTU: SAUCE: (namespace) fs: Don't remove suid for CAP_FSETID for
+      userns root"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: fs: Don't remove suid for
+      CAP_FSETID in s_user_ns""
+    - Revert "UBUNTU: SAUCE: (namespace) fs: Allow superblock owner to change
+      ownership of inodes"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: fs: Allow superblock owner to
+      change ownership of inodes with unmappable ids""
+    - Revert "UBUNTU: SAUCE: (namespace) security/integrity: Harden against
+      malformed xattrs"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: ima/evm: Allow root in s_user_ns
+      to set xattrs""
+    - Revert "(namespace) dquot: For now explicitly don't support filesystems
+      outside of init_user_ns"
+    - Revert "(namespace) quota: Handle quota data stored in s_user_ns in
+      quota_setxquota"
+    - Revert "(namespace) quota: Ensure qids map to the filesystem"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: quota: Convert ids relative to
+      s_user_ns""
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: quota: Require that qids passed
+      to dqget() be valid and map into s_user_ns""
+    - Revert "(namespace) vfs: Don't create inodes with a uid or gid unknown to
+      the vfs"
+    - Revert "(namespace) vfs: Don't modify inodes with a uid or gid unknown to
+      the vfs"
+    - Revert "UBUNTU: SAUCE: (namespace) fuse: Translate ids in posix acl xattrs"
+    - Revert "UBUNTU: SAUCE: (namespace) posix_acl: Export
+      posix_acl_fix_xattr_userns() to modules"
+    - Revert "(namespace) vfs: Verify acls are valid within superblock's
+      s_user_ns."
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: fs: Update posix_acl support to
+      handle user namespace mounts""
+    - Revert "(namespace) fs: Refuse uid/gid changes which don't map into
+      s_user_ns"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: fs: Refuse uid/gid changes which
+      don't map into s_user_ns""
+    - Revert "(namespace) mnt: Move the FS_USERNS_MOUNT check into sget_userns"
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Wed, 23 Nov 2016 10:16:31 +0000
+
+linux (4.4.0-49.70) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1640921
+
+  * Infiniband driver (kernel module) needed for Azure (LP: #1641139)
+    - SAUCE: RDMA Infiniband for Windows Azure
+    - [Config] CONFIG_HYPERV_INFINIBAND_ND=m
+    - SAUCE: Makefile RDMA infiniband driver for Windows Azure
+    - [Config] Add hv_network_direct.ko to generic inclusion list
+    - SAUCE: RDMA Infiniband for Windows Azure is dependent on amd64
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Fri, 11 Nov 2016 15:36:20 +0000
+
+linux (4.4.0-48.69) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1640758
+
+  * lxc-attach to malicious container allows access to host (LP: #1639345)
+    - Revert "UBUNTU: SAUCE: (noup) ptrace: being capable wrt a process requires
+      mapped uids/gids"
+    - (upstream) mm: Add a user_ns owner to mm_struct and fix ptrace permission
+      checks
+
+  * take 'P' command from upstream xmon (LP: #1637978)
+    - powerpc/xmon: Add xmon command to dump process/task similar to ps(1)
+
+  * zfs: importing zpool with vdev on zvol hangs kernel (LP: #1636517)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu15
+
+  * I2C touchpad does not work on AMD platform (LP: #1612006)
+    - pinctrl/amd: Configure GPIO register using BIOS settings
+    - pinctrl/amd: switch to using a bool for level
+
+  * [LTCTest] vfio_pci not loaded on Ubuntu 16.10 by default (LP: #1636733)
+    - [Config] CONFIG_VFIO_PCI=y for ppc64el
+
+  * QEMU throws failure msg while booting guest with SRIOV VF (LP: #1630554)
+    - KVM: PPC: Always select KVM_VFIO, plus Makefile cleanup
+
+  * Allow fuse user namespace mounts by default in xenial (LP: #1634964)
+    - (namespace) mnt: Move the FS_USERNS_MOUNT check into sget_userns
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Refuse uid/gid changes which don't
+      map into s_user_ns"
+    - (namespace) fs: Refuse uid/gid changes which don't map into s_user_ns
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Update posix_acl support to handle
+      user namespace mounts"
+    - (namespace) vfs: Verify acls are valid within superblock's s_user_ns.
+    - SAUCE: (namespace) posix_acl: Export posix_acl_fix_xattr_userns() to modules
+    - SAUCE: (namespace) fuse: Translate ids in posix acl xattrs
+    - (namespace) vfs: Don't modify inodes with a uid or gid unknown to the vfs
+    - (namespace) vfs: Don't create inodes with a uid or gid unknown to the vfs
+    - (namespace) Revert "UBUNTU: SAUCE: quota: Require that qids passed to
+      dqget() be valid and map into s_user_ns"
+    - (namespace) Revert "UBUNTU: SAUCE: quota: Convert ids relative to s_user_ns"
+    - (namespace) quota: Ensure qids map to the filesystem
+    - (namespace) quota: Handle quota data stored in s_user_ns in quota_setxquota
+    - (namespace) dquot: For now explicitly don't support filesystems outside of
+      init_user_ns
+    - (namespace) Revert "UBUNTU: SAUCE: ima/evm: Allow root in s_user_ns to set
+      xattrs"
+    - SAUCE: (namespace) security/integrity: Harden against malformed xattrs
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Allow superblock owner to change
+      ownership of inodes with unmappable ids"
+    - SAUCE: (namespace) fs: Allow superblock owner to change ownership of inodes
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Don't remove suid for CAP_FSETID in
+      s_user_ns"
+    - SAUCE: (namespace) fs: Don't remove suid for CAP_FSETID for userns root
+    - SAUCE: (namespace) fuse: Allow user namespace mounts by default
+
+  * [Feature] KBL - New device ID for Kabypoint(KbP) (LP: #1591618)
+    - SAUCE: mfd: lpss: Fix Intel Kaby Lake PCH-H properties
+
+  * hio: SSD data corruption under stress test (LP: #1638700)
+    - SAUCE: hio: set bi_error field to signal an I/O error on a BIO
+    - SAUCE: hio: splitting bio in the entry of .make_request_fn
+
+  * Module sha1-mb fails to load (LP: #1637165)
+    - crypto: sha-mb - Fix load failure
+    - crypto: mcryptd - Fix load failure
+
+  * please include mlx5_core modules in linux-image-generic package
+    (LP: #1635223)
+    - [Config] Include mlx5 in main package
+
+  * xgene i2c slimpro driver fails to load (LP: #1625232)
+    - mailbox: Add support for APM X-Gene platform mailbox driver
+    - mailbox/xgene-slimpro: Checking for IS_ERR instead of NULL
+    - mailbox: xgene-slimpro: Fix wrong test for devm_kzalloc
+    - [Config] Enabled XGENE_SLIMPRO_MBOX as a module
+
+  * [Dell][XPS]Touchscreen fails to function after resume from s3 by Lid
+    close/open (LP: #1632527)
+    - gpio/pinctrl: sunxi: stop poking around in private vars
+    - pinctrl: intel: Only restore pins that are used by the driver
+
+  * Xenial update to v4.4.30 stable release (LP: #1638272)
+    - Revert "x86/mm: Expand the exception table logic to allow new handling
+      options"
+    - Revert "fix minor infoleak in get_user_ex()"
+    - Linux 4.4.30
+
+  * Xenial update to v4.4.29 stable release (LP: #1638267)
+    - drm/prime: Pass the right module owner through to dma_buf_export()
+    - drm/amdgpu: fix IB alignment for UVD
+    - drm/amdgpu/dce10: disable hpd on local panels
+    - drm/amdgpu/dce8: disable hpd on local panels
+    - drm/amdgpu/dce11: disable hpd on local panels
+    - drm/amdgpu/dce11: add missing drm_mode_config_cleanup call
+    - drm/amdgpu: change vblank_time's calculation method to reduce computational
+      error.
+    - drm/radeon: narrow asic_init for virtualization
+    - drm/radeon/si/dpm: fix phase shedding setup
+    - drm/radeon: change vblank_time's calculation method to reduce computational
+      error.
+    - drm/vmwgfx: Limit the user-space command buffer size
+    - drm/i915/gen9: fix the WaWmMemoryReadLatency implementation
+    - Revert "drm/i915: Check live status before reading edid"
+    - drm/i915: Account for TSEG size when determining 865G stolen base
+    - drm/i915: Unalias obj->phys_handle and obj->userptr
+    - mm/hugetlb: fix memory offline with hugepage size > memory block size
+    - posix_acl: Clear SGID bit when setting file permissions
+    - ipip: Properly mark ipip GRO packets as encapsulated.
+    - powerpc/eeh: Null check uses of eeh_pe_bus_get
+    - perf stat: Fix interval output values
+    - genirq/generic_chip: Add irq_unmap callback
+    - uio: fix dmem_region_start computation
+    - ARM: clk-imx35: fix name for ckil clk
+    - spi: spi-fsl-dspi: Drop extra spi_master_put in device remove function
+    - mwifiex: correct aid value during tdls setup
+    - crypto: gcm - Fix IV buffer size in crypto_gcm_setkey
+    - crypto: arm/ghash-ce - add missing async import/export
+    - hwrng: omap - Only fail if pm_runtime_get_sync returns < 0
+    - ASoC: topology: Fix error return code in soc_tplg_dapm_widget_create()
+    - ASoC: dapm: Fix possible uninitialized variable in snd_soc_dapm_get_volsw()
+    - ASoC: dapm: Fix value setting for _ENUM_DOUBLE MUX's second channel
+    - ASoC: dapm: Fix kcontrol creation for output driver widget
+    - staging: r8188eu: Fix scheduling while atomic splat
+    - power: bq24257: Fix use of uninitialized pointer bq->charger
+    - dmaengine: ipu: remove bogus NO_IRQ reference
+    - x86/mm: Expand the exception table logic to allow new handling options
+    - s390/cio: fix accidental interrupt enabling during resume
+    - s390/con3270: fix use of uninitialised data
+    - s390/con3270: fix insufficient space padding
+    - clk: qoriq: fix a register offset error
+    - clk: divider: Fix clk_divider_round_rate() to use clk_readl()
+    - perf hists browser: Fix event group display
+    - perf symbols: Check symbol_conf.allow_aliases for kallsyms loading too
+    - perf symbols: Fixup symbol sizes before picking best ones
+    - mpt3sas: Don't spam logs if logging level is 0
+    - powerpc/nvram: Fix an incorrect partition merge
+    - ARM: pxa: pxa_cplds: fix interrupt handling
+    - Linux 4.4.29
+
+  * KVM: PPC: Book3S HV: Migrate pinned pages out of CMA (LP: #1632045)
+    - KVM: PPC: Book3S HV: Migrate pinned pages out of CMA
+
+  * Xenial update to v4.4.28 stable release (LP: #1637510)
+    - gpio: mpc8xxx: Correct irq handler function
+    - mei: me: add kaby point device ids
+    - regulator: tps65910: Work around silicon erratum SWCZ010
+    - clk: imx6: initialize GPU clocks
+    - PM / devfreq: event: remove duplicate devfreq_event_get_drvdata()
+    - rtlwifi: Fix missing country code for Great Britain
+    - mmc: block: don't use CMD23 with very old MMC cards
+    - mmc: sdhci: cast unsigned int to unsigned long long to avoid unexpeted error
+    - PCI: Mark Atheros AR9580 to avoid bus reset
+    - platform: don't return 0 from platform_get_irq[_byname]() on error
+    - cpufreq: intel_pstate: Fix unsafe HWP MSR access
+    - parisc: Increase KERNEL_INITIAL_SIZE for 32-bit SMP kernels
+    - parisc: Fix kernel memory layout regarding position of __gp
+    - parisc: Increase initial kernel mapping size
+    - pstore/ramoops: fixup driver removal
+    - pstore/core: drop cmpxchg based updates
+    - pstore/ram: Use memcpy_toio instead of memcpy
+    - pstore/ram: Use memcpy_fromio() to save old buffer
+    - perf intel-pt: Fix snapshot overlap detection decoder errors
+    - perf intel-pt: Fix estimated timestamps for cycle-accurate mode
+    - perf intel-pt: Fix MTC timestamp calculation for large MTC periods
+    - dm: mark request_queue dead before destroying the DM device
+    - dm: return correct error code in dm_resume()'s retry loop
+    - dm mpath: check if path's request_queue is dying in activate_path()
+    - dm crypt: fix crash on exit
+    - powerpc/vdso64: Use double word compare on pointers
+    - powerpc/powernv: Pass CPU-endian PE number to opal_pci_eeh_freeze_clear()
+    - powerpc/powernv: Use CPU-endian hub diag-data type in
+      pnv_eeh_get_and_dump_hub_diag()
+    - powerpc/powernv: Use CPU-endian PEST in pnv_pci_dump_p7ioc_diag_data()
+    - ubi: Deal with interrupted erasures in WL
+    - zfcp: fix fc_host port_type with NPIV
+    - zfcp: fix ELS/GS request&response length for hardware data router
+    - zfcp: close window with unblocked rport during rport gone
+    - zfcp: retain trace level for SCSI and HBA FSF response records
+    - zfcp: restore: Dont use 0 to indicate invalid LUN in rec trace
+    - zfcp: trace on request for open and close of WKA port
+    - zfcp: restore tracing of handle for port and LUN with HBA records
+    - zfcp: fix D_ID field with actual value on tracing SAN responses
+    - zfcp: fix payload trace length for SAN request&response
+    - zfcp: trace full payload of all SAN records (req,resp,iels)
+    - scsi: zfcp: spin_lock_irqsave() is not nestable
+    - fbdev/efifb: Fix 16 color palette entry calculation
+    - ovl: Fix info leak in ovl_lookup_temp()
+    - ovl: copy_up_xattr(): use strnlen
+    - mb86a20s: fix the locking logic
+    - mb86a20s: fix demod settings
+    - cx231xx: don't return error on success
+    - cx231xx: fix GPIOs for Pixelview SBTVD hybrid
+    - ALSA: hda - Fix a failure of micmute led when having multi adcs
+    - MIPS: Fix -mabi=64 build of vdso.lds
+    - MIPS: ptrace: Fix regs_return_value for kernel context
+    - lib: move strtobool() to kstrtobool()
+    - lib: update single-char callers of strtobool()
+    - lib: add "on"/"off" support to kstrtobool
+    - Input: i8042 - skip selftest on ASUS laptops
+    - Input: elantech - force needed quirks on Fujitsu H760
+    - Input: elantech - add Fujitsu Lifebook E556 to force crc_enabled
+    - sunrpc: fix write space race causing stalls
+    - NFSv4: Don't report revoked delegations as valid in nfs_have_delegation()
+    - NFSv4: nfs4_copy_delegation_stateid() must fail if the delegation is invalid
+    - NFSv4: Open state recovery must account for file permission changes
+    - NFSv4.2: Fix a reference leak in nfs42_proc_layoutstats_generic
+    - scsi: Fix use-after-free
+    - metag: Only define atomic_dec_if_positive conditionally
+    - mm: filemap: don't plant shadow entries without radix tree node
+    - ipc/sem.c: fix complex_count vs. simple op race
+    - arc: don't leak bits of kernel stack into coredump
+    - fs/super.c: fix race between freeze_super() and thaw_super()
+    - cifs: Limit the overall credit acquired
+    - fs/cifs: keep guid when assigning fid to fileinfo
+    - Clarify locking of cifs file and tcon structures and make more granular
+    - Display number of credits available
+    - Set previous session id correctly on SMB3 reconnect
+    - SMB3: GUIDs should be constructed as random but valid uuids
+    - Do not send SMB3 SET_INFO request if nothing is changing
+    - Cleanup missing frees on some ioctls
+    - blkcg: Unlock blkcg_pol_mutex only once when cpd == NULL
+    - x86/e820: Don't merge consecutive E820_PRAM ranges
+    - kvm: x86: memset whole irq_eoi
+    - irqchip/gicv3: Handle loop timeout proper
+    - sd: Fix rw_max for devices that report an optimal xfer size
+    - hpsa: correct skipping masked peripherals
+    - PKCS#7: Don't require SpcSpOpusInfo in Authenticode pkcs7 signatures
+    - bnx2x: Prevent false warning for lack of FC NPIV
+    - net/mlx4_core: Allow resetting VF admin mac to zero
+    - acpi, nfit: check for the correct event code in notifications
+    - mm: workingset: fix crash in shadow node shrinker caused by
+      replace_page_cache_page()
+    - mm: filemap: fix mapping->nrpages double accounting in fuse
+    - Using BUG_ON() as an assert() is _never_ acceptable
+    - s390/mm: fix gmap tlb flush issues
+    - irqchip/gic-v3-its: Fix entry size mask for GITS_BASER
+    - isofs: Do not return EACCES for unknown filesystems
+    - memstick: rtsx_usb_ms: Runtime resume the device when polling for cards
+    - memstick: rtsx_usb_ms: Manage runtime PM when accessing the device
+    - arm64: percpu: rewrite ll/sc loops in assembly
+    - arm64: kernel: Init MDCR_EL2 even in the absence of a PMU
+    - ceph: fix error handling in ceph_read_iter
+    - powerpc/mm: Prevent unlikely crash in copro_calculate_slb()
+    - mmc: core: Annotate cmd_hdr as __le32
+    - mmc: rtsx_usb_sdmmc: Avoid keeping the device runtime resumed when unused
+    - mmc: rtsx_usb_sdmmc: Handle runtime PM while changing the led
+    - ext4: do not advertise encryption support when disabled
+    - jbd2: fix incorrect unlock on j_list_lock
+    - ubifs: Fix xattr_names length in exit paths
+    - target: Re-add missing SCF_ACK_KREF assignment in v4.1.y
+    - target: Make EXTENDED_COPY 0xe4 failure return COPY TARGET DEVICE NOT
+      REACHABLE
+    - target: Don't override EXTENDED_COPY xcopy_pt_cmd SCSI status code
+    - Linux 4.4.28
+
+  * Xenial update to v4.4.27 stable release (LP: #1637501)
+    - serial: 8250_dw: Check the data->pclk when get apb_pclk
+    - btrfs: assign error values to the correct bio structs
+    - drivers: base: dma-mapping: page align the size when unmap_kernel_range
+    - fuse: listxattr: verify xattr list
+    - fuse: invalidate dir dentry after chmod
+    - fuse: fix killing s[ug]id in setattr
+    - i40e: avoid NULL pointer dereference and recursive errors on early PCI error
+    - brcmfmac: fix memory leak in brcmf_fill_bss_param
+    - ASoC: Intel: Atom: add a missing star in a memcpy call
+    - reiserfs: Unlock superblock before calling reiserfs_quota_on_mount()
+    - reiserfs: switch to generic_{get,set,remove}xattr()
+    - async_pq_val: fix DMA memory leak
+    - scsi: arcmsr: Simplify user_len checking
+    - ext4: enforce online defrag restriction for encrypted files
+    - ext4: reinforce check of i_dtime when clearing high fields of uid and gid
+    - ext4: fix memory leak in ext4_insert_range()
+    - ext4: allow DAX writeback for hole punch
+    - ext4: release bh in make_indexed_dir
+    - dlm: free workqueues after the connections
+    - vfs: move permission checking into notify_change() for utimes(NULL)
+    - cfq: fix starvation of asynchronous writes
+    - Linux 4.4.27
+
+  * Xenial update to v4.4.26 stable release (LP: #1637500)
+    - x86/build: Build compressed x86 kernels as PIE
+    - Linux 4.4.26
+
+  * ISST-LTE:pVM nvme 0000:a0:00.0: iommu_alloc failed on NVMe card
+    (LP: #1633128)
+    - dma-mapping: introduce the DMA_ATTR_NO_WARN attribute
+    - powerpc: implement the DMA_ATTR_NO_WARN attribute
+    - nvme: use the DMA_ATTR_NO_WARN attribute
+
+  * CVE-2016-8658
+    - brcmfmac: avoid potential stack overflow in brcmf_cfg80211_start_ap()
+
+  * Hotkey doesn't work on HP x360 (LP: #1620979)
+    - gpiolib: Make it possible to exclude GPIOs from IRQ domain
+    - pinctrl: cherryview: Do not mask all interrupts in probe
+    - pinctrl: cherryview: Do not add all southwest and north GPIOs to IRQ domain
+
+  * Bad page state in process genwqe_gunzip pfn:3c275 in the genwqe device
+    driver (LP: #1559194)
+    - SAUCE: (noup) Bad page state in process genwqe_gunzip pfn:3c275 in the
+      genwqe device driver
+
+  * CVE-2016-7425
+    - scsi: arcmsr: Buffer overflow in arcmsr_iop_message_xfer()
+
+  * Add ipvlan module to 16.04 kernel (LP: #1634705)
+    - [Config] Add ipvlan to the generic inclusion list
+
+  * kernel generates ACPI Exception: AE_NOT_FOUND, Evaluating _DOD incorrectly
+    (LP: #1634607)
+    - ACPI / video: skip evaluating _DOD when it does not exist
+
+  * BT still shows off after resume by wireless hotkey (LP: #1634380)
+    - Bluetooth: btusb: Fix atheros firmware download error
+
+  * ghash-clmulni-intel module fails to load (LP: #1633058)
+    - crypto: ghash-clmulni - Fix load failure
+    - crypto: cryptd - Assign statesize properly
+
+  * Xenial update to v4.4.25 stable release (LP: #1634153)
+    - timekeeping: Fix __ktime_get_fast_ns() regression
+    - ALSA: ali5451: Fix out-of-bound position reporting
+    - ALSA: usb-audio: Extend DragonFly dB scale quirk to cover other variants
+    - ALSA: usb-line6: use the same declaration as definition in header for MIDI
+      manufacturer ID
+    - mfd: rtsx_usb: Avoid setting ucr->current_sg.status
+    - mfd: atmel-hlcdc: Do not sleep in atomic context
+    - mfd: 88pm80x: Double shifting bug in suspend/resume
+    - mfd: wm8350-i2c: Make sure the i2c regmap functions are compiled
+    - KVM: PPC: Book3s PR: Allow access to unprivileged MMCR2 register
+    - KVM: MIPS: Drop other CPU ASIDs on guest MMU changes
+    - KVM: PPC: BookE: Fix a sanity check
+    - x86/boot: Fix kdump, cleanup aborted E820_PRAM max_pfn manipulation
+    - x86/irq: Prevent force migration of irqs which are not in the vector domain
+    - x86/dumpstack: Fix x86_32 kernel_stack_pointer() previous stack access
+    - ARM: dts: mvebu: armada-390: add missing compatibility string and bracket
+    - ARM: dts: MSM8064 remove flags from SPMI/MPP IRQs
+    - ARM: cpuidle: Fix error return code
+    - ima: use file_dentry()
+    - tpm: fix a race condition in tpm2_unseal_trusted()
+    - tpm_crb: fix crb_req_canceled behavior
+    - Linux 4.4.25
+
+  * backport fwts UEFI test driver to Xenial (LP: #1633506)
+    - efi: Add efi_test driver for exporting UEFI runtime service interfaces
+    - [Config] CONFIG_EFI_TEST=m
+
+  * Fix alps driver for multitouch function. (LP: #1633321)
+    - HID: alps: fix multitouch cursor issue
+
+  * xgene merlin crashes when running as iperf server (LP: #1632739)
+    - drivers: net: xgene: optimizing the code
+    - xgene: get_phy_device() doesn't return NULL anymore
+    - drivers: net: xgene: Get channel number from device binding
+    - drivers: net: xgene: constify xgene_cle_ops structure
+    - drivers: net: xgene: Fix error handling
+    - drivers: net: xgene: fix IPv4 forward crash
+    - drivers: net: xgene: fix sharing of irqs
+    - drivers: net: xgene: fix ununiform latency across queues
+    - drivers: net: xgene: fix statistics counters race condition
+    - drivers: net: xgene: fix register offset
+    - drivers: net: xgene: Separate set_speed from mac_init
+    - drivers: net: xgene: Fix module unload crash - hw resource cleanup
+    - drivers: net: xgene: Fix module unload crash - change sw sequence
+    - drivers: net: xgene: Fix module unload crash - clkrst sequence
+    - drivers: net: phy: xgene: Add MDIO driver
+    - drivers: net: xgene: Add backward compatibility
+    - drivers: net: xgene: Enable MDIO driver
+    - drivers: net: xgene: Use exported functions
+    - drivers: net: xgene: ethtool: Use phy_ethtool_gset and sset
+    - dtb: xgene: Add MDIO node
+    - MAINTAINERS: xgene: Add driver and documentation path
+    - [Config] Enable MDIO_XGENE as a modules
+
+  * Add support for KabeLake i219-LOM chips (LP: #1632578)
+    - e1000e: Initial support for KabeLake
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Thu, 10 Nov 2016 11:08:11 +0000
+
+linux (4.4.0-47.68) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1636941
+
+  * Add a driver for Amazon Elastic Network Adapters (ENA) (LP: #1635721)
+    - lib/bitmap.c: conversion routines to/from u32 array
+    - net: ethtool: add new ETHTOOL_xLINKSETTINGS API
+    - net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)
+    - [config] enable CONFIG_ENA_ETHERNET=m (Amazon ENA driver)
+
+  * unexpectedly large memory usage of mounted snaps (LP: #1636847)
+    - [Config] switch squashfs to single threaded decode
+
+ -- Kamal Mostafa <kamal@canonical.com>  Wed, 26 Oct 2016 10:47:55 -0700
+
+linux (4.4.0-46.67) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1635242
+
+  * proc_keys_show crash when reading /proc/keys (LP: #1634496)
+    - SAUCE: KEYS: ensure xbuf is large enough to fix buffer overflow in
+      proc_keys_show (LP: #1634496)
+
+  * [Trusty->Yakkety] powerpc/64: Fix incorrect return value from
+    __copy_tofrom_user (LP: #1632462)
+    - SAUCE: (no-up) powerpc/64: Fix incorrect return value from
+      __copy_tofrom_user
+
+  * Ubuntu 16.10: Oops panic in move_page_tables/page_remove_rmap after running
+    memory_stress_ng. (LP: #1628976)
+    - SAUCE: (no-up) powerpc/pseries: Fix stack corruption in htpe code
+
+  * Paths not failed properly when unmapping virtual FC ports in VIOS (using
+    ibmvfc) (LP: #1632116)
+    - scsi: ibmvfc: Fix I/O hang when port is not mapped
+
+  * PSL data cache should be flushed before resetting CAPI adapter
+    (LP: #1632049)
+    - cxl: Flush PSL cache before resetting the adapter
+
+  * thunder nic: avoid link delays due to RX_PACKET_DIS (LP: #1630038)
+    - net: thunderx: Don't set RX_PACKET_DIS while initializing
+
+  * Support snaps inside of lxd containers (LP: #1611078)
+    - Revert "UBUNTU: SAUCE: apparmor: fix sleep in critical section"
+    - SAUCE: (no-up) apparmor: sync of apparmor 3.6 (from Ubuntu 16.10)
+
+  * crypto/vmx/p8_ghash memory corruption (LP: #1630970)
+    - crypto: ghash-generic - move common definitions to a new header file
+    - crypto: vmx - Fix memory corruption caused by p8_ghash
+    - crypto: vmx - Ensure ghash-generic is enabled
+
+  * Xenial update to v4.4.24 stable release (LP: #1631468)
+    - cpuset: handle race between CPU hotplug and cpuset_hotplug_work
+    - mtd: nand: davinci: Reinitialize the HW ECC engine in 4bit hwctl
+    - mm,ksm: fix endless looping in allocating memory when ksm enable
+    - can: dev: fix deadlock reported after bus-off
+    - x86/init: Fix cr4_init_shadow() on CR4-less machines
+    - x86/boot: Initialize FPU and X86_FEATURE_ALWAYS even if we don't have CPUID
+    - drm/nouveau/fifo/nv04: avoid ramht race against cookie insertion
+    - drm/radeon/si/dpm: add workaround for for Jet parts
+    - ARM: 8616/1: dt: Respect property size when parsing CPUs
+    - ARM: 8617/1: dma: fix dma_max_pfn()
+    - usb: musb: Fix DMA desired mode for Mentor DMA engine
+    - usb: musb: fix DMA for host mode
+    - iwlwifi: mvm: fix a few firmware capability checks
+    - perf/core: Fix pmu::filter_match for SW-led groups
+    - i40e: avoid null pointer dereference
+    - pinctrl: uniphier: fix .pin_dbg_show() callback
+    - pinctrl: Flag strict is a field in struct pinmux_ops
+    - drivers/perf: arm_pmu: Fix leak in error path
+    - mmc: pxamci: fix potential oops
+    - tools/vm/slabinfo: fix an unintentional printf
+    - ipvs: fix bind to link-local mcast IPv6 address in backup
+    - nvmem: Declare nvmem_cell_read() consistently
+    - hwmon: (adt7411) set bit 3 in CFG1 register
+    - spi: sh-msiof: Avoid invalid clock generator parameters
+    - iwlwifi: pcie: fix access to scratch buffer
+    - iwlwifi: mvm: don't use ret when not initialised
+    - ceph: fix race during filling readdir cache
+    - usb: gadget: fsl_qe_udc: signedness bug in qe_get_frame()
+    - gpio: sa1100: fix irq probing for ucb1x00
+    - irqchip/gicv3: Silence noisy DEBUG_PER_CPU_MAPS warning
+    - ARM: 8618/1: decompressor: reset ttbcr fields to use TTBR0 on ARMv7
+    - arm64: debug: avoid resetting stepping state machine when TIF_SINGLESTEP
+    - MIPS: uprobes: remove incorrect set_orig_insn
+    - MIPS: fix uretprobe implementation
+    - MIPS: Malta: Fix IOCU disable switch read for MIPS64
+    - MIPS: uprobes: fix use of uninitialised variable
+    - printk: fix parsing of "brl=" option
+    - tpm: fix byte-order for the value read by tpm2_get_tpm_pt
+    - regulator: qcom_spmi: Add support for S4 supply on pm8941
+    - regulator: qcom_spmi: Add support for get_mode/set_mode on switches
+    - regulator: qcom_spmi: Update mvs1/mvs2 switches on pm8941
+    - regulator: qcom_smd: Fix voltage ranges for pm8x41
+    - ARM: sun5i: Fix typo in trip point temperature
+    - ARM: sa1100: register clocks early
+    - ARM: sa1100: fix 3.6864MHz clock
+    - ARM: sa1100: clear reset status prior to reboot
+    - ARM: shmobile: fix regulator quirk for Gen2
+    - ARM: sa1111: fix pcmcia suspend/resume
+    - hwrng: omap - Fix assumption that runtime_get_sync will always succeed
+    - blk-mq: actually hook up defer list when running requests
+    - pstore: drop file opened reference count
+    - tile: Define AT_VECTOR_SIZE_ARCH for ARCH_DLINFO
+    - iwlmvm: mvm: set correct state in smart-fifo configuration
+    - NFC: fdp: Detect errors from fdp_nci_create_conn()
+    - em28xx-i2c: rt_mutex_trylock() returns zero on failure
+    - gspca: avoid unused variable warnings
+    - ath9k: Fix programming of minCCA power threshold
+    - avr32: off by one in at32_init_pio()
+    - fnic: pci_dma_mapping_error() doesn't return an error code
+    - dmaengine: at_xdmac: fix debug string
+    - svc: Avoid garbage replies when pc_func() returns rpc_drop_reply
+    - NFS: Don't drop CB requests with invalid principals
+    - pNFS/files: Fix layoutcommit after a commit to DS
+    - pNFS/flexfiles: Fix layoutcommit after a commit to DS
+    - ASoC: Intel: Skylake: Fix error return code in skl_probe()
+    - brcmfmac: Fix glob_skb leak in brcmf_sdiod_recv_chain
+    - brcmsmac: Free packet if dma_mapping_error() fails in dma_rxfill
+    - brcmsmac: Initialize power in brcms_c_stf_ss_algo_channel_get()
+    - powerpc/prom: Fix sub-processor option passed to ibm, client-architecture-
+      support
+    - sysctl: handle error writing UINT_MAX to u32 fields
+    - ASoC: omap-mcpdm: Fix irq resource handling
+    - kernel/fork: fix CLONE_CHILD_CLEARTID regression in nscd
+    - dmaengine: at_xdmac: fix to pass correct device identity to free_irq()
+    - KVM: nVMX: postpone VMCS changes on MSR_IA32_APICBASE write
+    - IB/ipoib: Fix memory corruption in ipoib cm mode connect flow
+    - IB/core: Fix use after free in send_leave function
+    - IB/ipoib: Don't allow MC joins during light MC flush
+    - IB/mlx4: Fix incorrect MC join state bit-masking on SR-IOV
+    - IB/mlx4: Fix code indentation in QP1 MAD flow
+    - IB/mlx4: Use correct subnet-prefix in QP1 mads under SR-IOV
+    - batman-adv: remove unused callback from batadv_algo_ops struct
+    - aio: mark AIO pseudo-fs noexec
+    - clk: xgene: Add missing parenthesis when clearing divider value
+    - dm log writes: fix bug with too large bios
+    - USB: serial: cp210x: fix hardware flow-control disable
+    - usb: misc: legousbtower: Fix NULL pointer deference
+    - Staging: fbtft: Fix bug in fbtft-core
+    - USB: serial: cp210x: Add ID for a Juniper console
+    - Revert "usbtmc: convert to devm_kzalloc"
+    - ALSA: hda - Adding one more ALC255 pin definition for headset problem
+    - ACPICA: acpi_get_sleep_type_data: Reduce warnings
+    - ALSA: hda - Fix headset mic detection problem for several Dell laptops
+    - ALSA: hda - Add the top speaker pin config for HP Spectre x360
+    - Linux 4.4.24
+
+  * sha1-powerpc returning wrong results (LP: #1629977)
+    - crypto: sha1-powerpc - little-endian support
+
+  *  Dell Precision Trackpoint not working after suspend (LP: #1630857)
+    - HID: alps: fix stick device not working after resume
+
+  * OOPS on beaglebone on boot of 4.4.0-36-generic under snappy ubuntu core
+    xenial (LP: #1625177)
+    - net: ethernet: ti: cpdma: fix lockup in cpdma_ctlr_destroy()
+    - drivers: net: cpsw: fix wrong regs access in cpsw_remove
+    - drivers: net: cpsw: use of_platform_depopulate()
+    - ARM: OMAP2+: omap_device: fix crash on omap_device removal
+    - ARM: OMAP2+: Fix omap_device for module reload on PM runtime forbid
+    - ARM: OMAP2+: Fix typo in omap_device.c
+    - drivers: net: cpsw: fix suspend when all ethX devices are down
+    - drivers: net: cpsw: fix wrong regs access in cpsw_ndo_open
+    - drivers: net: cpsw: check return code from pm runtime calls
+    - drivers: net: cpsw: remove pm runtime calls from suspend callbacks
+    - drivers: net: cpsw: ethtool: fix accessing to suspended device
+    - drivers: net: cpsw: ndev: fix accessing to suspended device
+    - drivers: net: cpsw: fix kmemleak false-positive reports for sk buffers
+
+  * Autofs parameter substitution broken in kernel 4.4.0-38 and 4.4.0-40
+    (LP: #1629204)
+    - SAUCE: (namespace) autofs4: Use real_cred for requestor's ids
+
+  * Xenial update to v4.4.23 stable release (LP: #1629386)
+    - include/linux/kernel.h: change abs() macro so it uses consistent return type
+    - Fix build warning in kernel/cpuset.c
+    - reiserfs: fix "new_insert_key may be used uninitialized ..."
+    - ipv4: panic in leaf_walk_rcu due to stale node pointer
+    - ipv6: release dst in ping_v6_sendmsg
+    - tcp: cwnd does not increase in TCP YeAH
+    - tcp: properly scale window in tcp_v[46]_reqsk_send_ack()
+    - crypto: arm64/aes-ctr - fix NULL dereference in tail processing
+    - crypto: arm/aes-ctr - fix NULL dereference in tail processing
+    - crypto: skcipher - Fix blkcipher walk OOM crash
+    - crypto: echainiv - Replace chaining with multiplication
+    - ocfs2/dlm: fix race between convert and migration
+    - ocfs2: fix start offset to ocfs2_zero_range_for_truncate()
+    - kbuild: Do not run modules_install and install in paralel
+    - Makefile: revert "Makefile: Document ability to make file.lst and file.S"
+      partially
+    - tools: Support relative directory path for 'O='
+    - kbuild: forbid kernel directory to contain spaces and colons
+    - Kbuild: disable 'maybe-uninitialized' warning for
+      CONFIG_PROFILE_ALL_BRANCHES
+    - gcov: disable -Wmaybe-uninitialized warning
+    - Disable "maybe-uninitialized" warning globally
+    - Disable "frame-address" warning
+    - Makefile: Mute warning for __builtin_return_address(>0) for tracing only
+    - net: caif: fix misleading indentation
+    - Add braces to avoid "ambiguous ‘else’" compiler warnings
+    - am437x-vfpe: fix typo in vpfe_get_app_input_index
+    - ath9k: fix misleading indentation
+    - iwlegacy: avoid warning about missing braces
+    - Staging: iio: adc: fix indent on break statement
+    - nouveau: fix nv40_perfctr_next() cleanup regression
+    - bonding: Fix bonding crash
+    - Revert "af_unix: Fix splice-bind deadlock"
+    - af_unix: split 'u->readlock' into two: 'iolock' and 'bindlock'
+    - vti: flush x-netns xfrm cache when vti interface is removed
+    - net/irda: handle iriap_register_lsap() allocation failure
+    - tipc: fix NULL pointer dereference in shutdown()
+    - net/mlx5: Added missing check of msg length in verifying its signature
+    - net: dsa: bcm_sf2: Fix race condition while unmasking interrupts
+    - Revert "phy: IRQ cannot be shared"
+    - net: smc91x: fix SMC accesses
+    - bridge: re-introduce 'fix parsing of MLDv2 reports'
+    - autofs races
+    - autofs: use dentry flags to block walks during expire
+    - xfs: prevent dropping ioend completions during buftarg wait
+    - fsnotify: add a way to stop queueing events on group shutdown
+    - fanotify: fix list corruption in fanotify_get_response()
+    - fix fault_in_multipages_...() on architectures with no-op access_ok()
+    - mtd: maps: sa1100-flash: potential NULL dereference
+    - mtd: pmcmsp-flash: Allocating too much in init_msp_flash()
+    - power: reset: hisi-reboot: Unmap region obtained by of_iomap
+    - fix memory leaks in tracing_buffers_splice_read()
+    - tracing: Move mutex to protect against resetting of seq data
+    - mm: delete unnecessary and unsafe init_tlb_ubc()
+    - can: flexcan: fix resume function
+    - nl80211: validate number of probe response CSA counters
+    - btrfs: ensure that file descriptor used with subvol ioctls is a dir
+    - i2c-eg20t: fix race between i2c init and interrupt enable
+    - i2c: qup: skip qup_i2c_suspend if the device is already runtime suspended
+    - MIPS: Fix pre-r6 emulation FPU initialisation
+    - MIPS: SMP: Fix possibility of deadlock when bringing CPUs online
+    - MIPS: vDSO: Fix Malta EVA mapping to vDSO page structs
+    - MIPS: Remove compact branch policy Kconfig entries
+    - MIPS: Avoid a BUG warning during prctl(PR_SET_FP_MODE, ...)
+    - MIPS: Add a missing ".set pop" in an early commit
+    - MIPS: paravirt: Fix undefined reference to smp_bootstrap
+    - PM / hibernate: Restore processor state before using per-CPU variables
+    - PM / hibernate: Fix rtree_next_node() to avoid walking off list ends
+    - power_supply: tps65217-charger: fix missing platform_set_drvdata()
+    - power: supply: max17042_battery: fix model download bug.
+    - qxl: check for kmap failures
+    - hostfs: Freeing an ERR_PTR in hostfs_fill_sb_common()
+    - Linux 4.4.23
+
+  * Xenial update to v4.4.22 stable release (LP: #1627730)
+    - ext4: use __GFP_NOFAIL in ext4_free_blocks()
+    - fscrypto: add authorization check for setting encryption policy
+    - clocksource/drivers/sun4i: Clear interrupts after stopping timer in probe
+      function
+    - MIPS: KVM: Check for pfn noslot case
+    - fscrypto: require write access to mount to set encryption policy
+    - lightnvm: put bio before return
+    - powerpc/tm: do not use r13 for tabort_syscall
+    - powerpc/mm: Don't alias user region to other regions below PAGE_OFFSET
+    - kernfs: don't depend on d_find_any_alias() when generating notifications
+    - pNFS: The client must not do I/O to the DS if it's lease has expired
+    - NFSv4.x: Fix a refcount leak in nfs_callback_up_net
+    - nfsd: Close race between nfsd4_release_lockowner and nfsd4_lock
+    - pNFS: Ensure LAYOUTGET and LAYOUTRETURN are properly serialised
+    - NFSv4.1: Fix the CREATE_SESSION slot number accounting
+    - kexec: fix double-free when failing to relocate the purgatory
+    - mm: introduce get_task_exe_file
+    - audit: fix exe_file access in audit_exe_compare
+    - dm flakey: fix reads to be issued if drop_writes configured
+    - IB/uverbs: Fix race between uverbs_close and remove_one
+    - ARC: mm: fix build breakage with STRICT_MM_TYPECHECKS
+    - x86/paravirt: Do not trace _paravirt_ident_*() functions
+    - x86/AMD: Apply erratum 665 on machines without a BIOS fix
+    - kvm-arm: Unmap shadow pagetables properly
+    - iio: accel: kxsd9: Fix raw read return
+    - iio: proximity: as3935: set up buffer timestamps for non-zero values
+    - iio: adc: rockchip_saradc: reset saradc controller before programming it
+    - iio: adc: ti_am335x_adc: Protect FIFO1 from concurrent access
+    - iio: adc: ti_am335x_adc: Increase timeout value waiting for ADC sample
+    - iio: ad799x: Fix buffered capture for ad7991/ad7995/ad7999
+    - iio: adc: at91: unbreak channel adc channel 3
+    - iio: accel: bmc150: reset chip at init time
+    - iio: fix pressure data output unit in hid-sensor-attributes
+    - iio: accel: kxsd9: Fix scaling bug
+    - iio:core: fix IIO_VAL_FRACTIONAL sign handling
+    - iio: ensure ret is initialized to zero before entering do loop
+    - serial: 8250_mid: fix divide error bug if baud rate is 0
+    - serial: 8250: added acces i/o products quad and octal serial cards
+    - USB: serial: simple: add support for another Infineon flashloader
+    - usb: renesas_usbhs: fix clearing the {BRDY,BEMP}STS condition
+    - usb: chipidea: udc: fix NULL ptr dereference in isr_setup_status_phase
+    - ARM: dts: STiH410: Handle interconnect clock required by EHCI/OHCI (USB)
+    - USB: change bInterval default to 10 ms
+    - net: thunderx: Fix OOPs with ethtool --register-dump
+    - cpuset: make sure new tasks conform to the current config of the cpuset
+    - ARM: AM43XX: hwmod: Fix RSTST register offset for pruss
+    - ARM: imx6: add missing BM_CLPCR_BYP_MMDC_CH0_LPM_HS setting for imx6ul
+    - ARM: imx6: add missing BM_CLPCR_BYPASS_PMIC_READY setting for imx6sx
+    - ARM: kirkwood: ib62x0: fix size of u-boot environment partition
+    - ARM: OMAP3: hwmod data: Add sysc information for DSI
+    - ARM: dts: imx6qdl: Fix SPDIF regression
+    - ARM: dts: overo: fix gpmc nand cs0 range
+    - ARM: dts: overo: fix gpmc nand on boards with ethernet
+    - ARM: dts: STiH407-family: Provide interconnect clock for consumption in ST
+      SDHCI
+    - bus: arm-ccn: Fix PMU handling of MN
+    - bus: arm-ccn: Do not attempt to configure XPs for cycle counter
+    - bus: arm-ccn: Fix XP watchpoint settings bitmask
+    - dm log writes: fix check of kthread_run() return value
+    - dm log writes: move IO accounting earlier to fix error path
+    - dm crypt: fix error with too large bios
+    - pinctrl: pistachio: fix mfio pll_lock pinmux
+    - pinctrl: sunxi: fix uart1 CTS/RTS pins at PG on A23/A33
+    - arm64: spinlocks: implement smp_mb__before_spinlock() as smp_mb()
+    - crypto: cryptd - initialize child shash_desc on import
+    - Btrfs: remove root_log_ctx from ctx list before btrfs_sync_log returns
+    - fuse: direct-io: don't dirty ITER_BVEC pages
+    - xhci: fix null pointer dereference in stop command timeout function
+    - md-cluster: make md-cluster also can work when compiled into kernel
+    - ath9k: fix using sta->drv_priv before initializing it
+    - Revert "wext: Fix 32 bit iwpriv compatibility issue with 64 bit Kernel"
+    - sched/core: Fix a race between try_to_wake_up() and a woken up task
+    - ipv6: addrconf: fix dev refcont leak when DAD failed
+    - gma500: remove annoying deprecation warning
+    - mpssd: fix buffer overflow warning
+    - drm/i915: Avoid pointer arithmetic in calculating plane surface offset
+    - mmc: dw_mmc: use resource_size_t to store physical address
+    - pinctrl: at91-pio4: use %pr format string for resource
+    - soc: qcom/spm: shut up uninitialized variable warning
+    - kconfig: tinyconfig: provide whole choice blocks to avoid warnings
+    - net: simplify napi_synchronize() to avoid warnings
+    - drm: atmel-hlcdc: Fix vertical scaling
+    - drm: Only use compat ioctl for addfb2 on X86/IA64
+    - genirq: Provide irq_gc_{lock_irqsave,unlock_irqrestore}() helpers
+    - irqchip/atmel-aic: Fix potential deadlock in ->xlate()
+    - fix iov_iter_fault_in_readable()
+    - microblaze: fix __get_user()
+    - avr32: fix copy_from_user()
+    - microblaze: fix copy_from_user()
+    - fix minor infoleak in get_user_ex()
+    - mn10300: failing __get_user() and get_user() should zero
+    - m32r: fix __get_user()
+    - sh64: failing __get_user() should zero
+    - nios2: fix __get_user()
+    - score: fix __get_user/get_user
+    - s390: get_user() should zero on failure
+    - ARC: uaccess: get_user to zero out dest in cause of fault
+    - asm-generic: make get_user() clear the destination on errors
+    - frv: fix clear_user()
+    - cris: buggered copy_from_user/copy_to_user/clear_user
+    - blackfin: fix copy_from_user()
+    - score: fix copy_from_user() and friends
+    - sh: fix copy_from_user()
+    - hexagon: fix strncpy_from_user() error return
+    - mips: copy_from_user() must zero the destination on access_ok() failure
+    - asm-generic: make copy_from_user() zero the destination properly
+    - alpha: fix copy_from_user()
+    - metag: copy_from_user() should zero the destination on access_ok() failure
+    - parisc: fix copy_from_user()
+    - openrisc: fix copy_from_user()
+    - nios2: copy_from_user() should zero the tail of destination
+    - mn10300: copy_from_user() should zero on access_ok() failure...
+    - sparc32: fix copy_from_user()
+    - ppc32: fix copy_from_user()
+    - genirq/msi: Fix broken debug output
+    - ia64: copy_from_user() should zero the destination on access_ok() failure
+    - avr32: fix 'undefined reference to `___copy_from_user'
+    - openrisc: fix the fix of copy_from_user()
+    - Linux 4.4.22
+
+  * AES-XTS poor performance in Ubuntu 16.04 (LP: #1613295)
+    - crypto: vmx - fix null dereference in p8_aes_xts_crypt
+
+  * i40e/setting some ethtool features and remove module right after (modprobe
+    -r) lead to crash in systems with more than 127 CPUs (LP: #1626782)
+    - i40e: Fix errors resulted while turning off TSO
+
+  * STC860:alpine-pdq:alpdq5p03: kernel panic when adding vnic (LP: #1626222)
+    - ibmvnic: fix to use list_for_each_safe() when delete items
+
+  * Stratton: ISST-LTE:UbuntuKVM: Failed to hotplug virtual devices to guest
+    running Ubuntu 16.04.1 on UbuntuKVM16.04.1 #179 (LP: #1625986)
+    - PCI: rpaphp: Fix slot registration for multiple slots under a PHB
+
+  * nvme: Missing patch in Ubuntu-4.4.0-41.61 (LP: #1628520)
+    - nvme: Call pci_disable_device on the error path.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 20 Oct 2016 08:09:34 -0500
+
+linux (4.4.0-45.66) xenial; urgency=low
+
+  * CVE-2016-5195
+    - SAUCE: mm: remove gup_flags FOLL_WRITE games from __get_user_pages()
+
+  * srcname from mount rule corrupted under load (LP: #1634753)
+    - SAUCE: apparmor: fix sleep in critical section
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 19 Oct 2016 11:24:20 +0200
+
+linux (4.4.0-43.63) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1632375
+
+  * kswapd0 100% CPU usage (LP: #1518457)
+    - SAUCE: (no-up) If zone is so small that watermarks are the same, stop zone
+      balance.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 11 Oct 2016 07:54:56 -0500
+
+linux (4.4.0-42.62) xenial; urgency=low
+
+  * Fix GRO recursion overflow for tunneling protocols (LP: #1631287)
+    - tunnels: Don't apply GRO to multiple layers of encapsulation.
+    - gro: Allow tunnel stacking in the case of FOU/GUE
+
+  * CVE-2016-7039
+    - SAUCE: net: add recursion limit to GRO
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 07 Oct 2016 12:03:55 -0500
+
+linux (4.4.0-41.61) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1628204
+
+  * nvme drive probe failure (LP: #1626894)
+    - (fix) NVMe: Don't unmap controller registers on reset
+
+ -- Kamal Mostafa <kamal@canonical.com>  Tue, 27 Sep 2016 09:40:42 -0700
+
+linux (4.4.0-40.60) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1627074
+
+  * Permission denied in CIFS with kernel 4.4.0-38 (LP: #1626112)
+    - Fix memory leaks in cifs_do_mount()
+    - Compare prepaths when comparing superblocks
+    - SAUCE: Fix regression which breaks DFS mounting
+
+  * Backlight does not change when adjust it higher than 50% after S3
+    (LP: #1625932)
+    - SAUCE: i915_bpo: drm/i915/backlight: setup and cache pwm alternate
+      increment value
+    - SAUCE: i915_bpo: drm/i915/backlight: setup backlight pwm alternate
+      increment on backlight enable
+
+ -- Kamal Mostafa <kamal@canonical.com>  Fri, 23 Sep 2016 08:53:31 -0700
+
+linux (4.4.0-39.59) xenial; urgency=low
+
+  [ Joseph Salisbury ]
+
+  * Release Tracking Bug
+    - LP: #1625303
+
+  * thunder: chip errata w/ multiple CQEs for a TSO packet (LP: #1624569)
+    - net: thunderx: Fix for issues with multiple CQEs posted for a TSO packet
+
+  * thunder: faulty TSO padding (LP: #1623627)
+    - net: thunderx: Fix for HW issue while padding TSO packet
+
+  * CVE-2016-6828
+    - tcp: fix use after free in tcp_xmit_retransmit_queue()
+
+  * Sennheiser Officerunner - cannot get freq at ep 0x83 (LP: #1622763)
+    - SAUCE: (no-up) ALSA: usb-audio: Add quirk for sennheiser officerunner
+
+  * Backport E3 Skylake Support in ie31200_edac to Xenial (LP: #1619766)
+    - EDAC, ie31200_edac: Add Skylake support
+
+  * Ubuntu 16.04 - Full EEH Recovery Support for NVMe devices (LP: #1602724)
+    - SAUCE: nvme: Don't suspend admin queue that wasn't created
+
+  * ISST-LTE:pNV: system ben is hung during ST (nvme) (LP: #1620317)
+    - blk-mq: Allow timeouts to run while queue is freezing
+    - blk-mq: improve warning for running a queue on the wrong CPU
+    - blk-mq: don't overwrite rq->mq_ctx
+
+  * lsattr 32bit does not work on 64bit kernel (Inappropriate ioctl error)
+    (LP: #1619918)
+    - btrfs: bugfix: handle FS_IOC32_{GETFLAGS, SETFLAGS, GETVERSION} in
+      btrfs_ioctl
+
+  * radeon: monitor connected to onboard VGA doesn't work with Xenial
+    (LP: #1600092)
+    - drm/radeon/dp: add back special handling for NUTMEG
+
+  * initramfs includes qle driver, but not firmware (LP: #1623187)
+    - qed: add MODULE_FIRMWARE()
+
+  * [Hyper-V] Rebase Hyper-V to 4.7.2 (stable) (LP: #1616677)
+    - hv_netvsc: Implement support for VF drivers on Hyper-V
+    - hv_netvsc: Fix the list processing for network change event
+    - Drivers: hv: vmbus: Introduce functions for estimating room in the ring
+      buffer
+    - Drivers: hv: vmbus: Use READ_ONCE() to read variables that are volatile
+    - Drivers: hv: vmbus: Export the vmbus_set_event() API
+    - lcoking/barriers, arch: Use smp barriers in smp_store_release()
+    - asm-generic: guard smp_store_release/load_acquire
+    - x86: reuse asm-generic/barrier.h
+    - asm-generic: add __smp_xxx wrappers
+    - x86: define __smp_xxx
+    - asm-generic: implement virt_xxx memory barriers
+    - Drivers: hv: vmbus: Move some ring buffer functions to hyperv.h
+    - Drivers: hv: vmbus: Implement APIs to support "in place" consumption of
+      vmbus packets
+    - drivers:hv: Lock access to hyperv_mmio resource tree
+    - drivers:hv: Make a function to free mmio regions through vmbus
+    - drivers:hv: Track allocations of children of hv_vmbus in private resource
+      tree
+    - drivers:hv: Separate out frame buffer logic when picking MMIO range
+    - Drivers: hv: vmbus: handle various crash scenarios
+    - Drivers: hv: balloon: don't crash when memory is added in non-sorted order
+    - Drivers: hv: balloon: reset host_specified_ha_region
+    - tools: hv: lsvmbus: add pci pass-through UUID
+    - hv_netvsc: move start_remove flag to net_device_context
+    - hv_netvsc: use start_remove flag to protect netvsc_link_change()
+    - hv_netvsc: untangle the pointer mess
+    - hv_netvsc: get rid of struct net_device pointer in struct netvsc_device
+    - hv_netvsc: synchronize netvsc_change_mtu()/netvsc_set_channels() with
+      netvsc_remove()
+    - hv_netvsc: set nvdev link after populating chn_table
+    - hv_netvsc: Fix VF register on vlan devices
+    - hv_netvsc: remove redundant assignment in netvsc_recv_callback()
+    - hv_netvsc: introduce {net, hv}_device_to_netvsc_device() helpers
+    - hv_netvsc: pass struct netvsc_device to rndis_filter_{open, close}()
+    - hv_netvsc: pass struct net_device to rndis_filter_set_device_mac()
+    - hv_netvsc: pass struct net_device to rndis_filter_set_offload_params()
+    - netvsc: get rid of completion timeouts
+    - PCI: hv: Don't leak buffer in hv_pci_onchannelcallback()
+    - PCI: hv: Handle all pending messages in hv_pci_onchannelcallback()
+    - netvsc: Use the new in-place consumption APIs in the rx path
+    - x86/kernel: Audit and remove any unnecessary uses of module.h
+    - PCI: hv: Fix interrupt cleanup path
+    - hv_netvsc: Fix VF register on bonding devices
+    - hv_netvsc: don't lose VF information
+    - hv_netvsc: avoid deadlocks between rtnl lock and vf_use_cnt wait
+    - hv_netvsc: reset vf_inject on VF removal
+    - hv_netvsc: protect module refcount by checking net_device_ctx->vf_netdev
+    - hv_netvsc: fix bonding devices check in netvsc_netdev_event()
+    - Drivers: hv: vmbus: Use the new virt_xx barrier code
+    - ixgbevf: call ndo_stop() instead of dev_close() when running offline
+      selftest
+    - ixgbevf: fix error code path when setting MAC address
+    - ixgbevf: use bit operations for setting and checking resets
+    - ixgbevf: Add support for generic Tx checksums
+    - ixgbe/ixgbevf: Add support for bulk free in Tx cleanup & cleanup boolean
+      logic
+    - ixgbevf: refactor ethtool stats handling
+    - ixgbevf: add support for per-queue ethtool stats
+    - ixgbevf: make use of BIT() macro to avoid shift of signed values
+    - ixgbevf: Move API negotiation function into mac_ops
+    - ixgbevf: Add the device ID's presented while running on Hyper-V
+    - ixgbevf: Support Windows hosts (Hyper-V)
+    - ixgbevf: Change the relaxed order settings in VF driver for sparc
+    - ixgbevf: Use mac_ops instead of trying to identify NIC type
+
+  * New device ID for Kabypoint (LP: #1622469)
+    - mfd: lpss: Add Intel Kaby Lake PCH-H PCI IDs
+    - SAUCE: i2c: i801: Add support for Kaby Lake PCH-H
+
+  * Xenial update to v4.4.21 stable release (LP: #1624037)
+    - Revert "i40e: fix: do not sleep in netdev_ops"
+    - fs: Check for invalid i_uid in may_follow_link()
+    - netfilter: x_tables: check for size overflow
+    - ext4: validate that metadata blocks do not overlap superblock
+    - ext4: fix xattr shifting when expanding inodes
+    - ext4: fix xattr shifting when expanding inodes part 2
+    - ext4: properly align shifted xattrs when expanding inodes
+    - ext4: avoid deadlock when expanding inode size
+    - ext4: avoid modifying checksum fields directly during checksum verification
+    - block: Fix race triggered by blk_set_queue_dying()
+    - block: make sure a big bio is split into at most 256 bvecs
+    - cgroup: reduce read locked section of cgroup_threadgroup_rwsem during fork
+    - s390/sclp_ctl: fix potential information leak with /dev/sclp
+    - drm/radeon: fix radeon_move_blit on 32bit systems
+    - drm: Reject page_flip for !DRIVER_MODESET
+    - drm/msm: fix use of copy_from_user() while holding spinlock
+    - ASoC: atmel_ssc_dai: Don't unconditionally reset SSC on stream startup
+    - xfs: fix superblock inprogress check
+    - timekeeping: Cap array access in timekeeping_debug
+    - timekeeping: Avoid taking lock in NMI path with CONFIG_DEBUG_TIMEKEEPING
+    - lustre: remove unused declaration
+    - wrappers for ->i_mutex access
+    - ovl: don't copy up opaqueness
+    - ovl: remove posix_acl_default from workdir
+    - ovl: listxattr: use strnlen()
+    - ovl: fix workdir creation
+    - ubifs: Fix assertion in layout_in_gaps()
+    - bcache: RESERVE_PRIO is too small by one when prio_buckets() is a power of
+      two.
+    - vhost/scsi: fix reuse of &vq->iov[out] in response
+    - x86/apic: Do not init irq remapping if ioapic is disabled
+    - uprobes: Fix the memcg accounting
+    - crypto: caam - fix IV loading for authenc (giv)decryption
+    - ALSA: usb-audio: Add sample rate inquiry quirk for B850V3 CP2114
+    - ALSA: firewire-tascam: accessing to user space outside spinlock
+    - ALSA: fireworks: accessing to user space outside spinlock
+    - ALSA: rawmidi: Fix possible deadlock with virmidi registration
+    - ALSA: hda - Add headset mic quirk for Dell Inspiron 5468
+    - ALSA: hda - Enable subwoofer on Dell Inspiron 7559
+    - ALSA: timer: fix NULL pointer dereference in read()/ioctl() race
+    - ALSA: timer: fix division by zero after SNDRV_TIMER_IOCTL_CONTINUE
+    - ALSA: timer: fix NULL pointer dereference on memory allocation failure
+    - scsi: fix upper bounds check of sense key in scsi_sense_key_string()
+    - metag: Fix atomic_*_return inline asm constraints
+    - cpufreq: Fix GOV_LIMITS handling for the userspace governor
+    - hwrng: exynos - Disable runtime PM on probe failure
+    - regulator: anatop: allow regulator to be in bypass mode
+    - lib/mpi: mpi_write_sgl(): fix skipping of leading zero limbs
+    - Linux 4.4.21
+
+  * Headset mic detection on some variants of Dell Inspiron 5468 (LP: #1617900)
+    - ALSA: hda - Add headset mic quirk for Dell Inspiron 5468
+
+  * Xenial update to v4.4.20 stable release (LP: #1621113)
+    - hugetlb: fix nr_pmds accounting with shared page tables
+    - x86/mm: Disable preemption during CR3 read+write
+    - uprobes/x86: Fix RIP-relative handling of EVEX-encoded instructions
+    - tools/testing/nvdimm: fix SIGTERM vs hotplug crash
+    - SUNRPC: Handle EADDRNOTAVAIL on connection failures
+    - SUNRPC: allow for upcalls for same uid but different gss service
+    - powerpc/eeh: eeh_pci_enable(): fix checking of post-request state
+    - ALSA: usb-audio: Add a sample rate quirk for Creative Live! Cam Socialize HD
+      (VF0610)
+    - ALSA: usb-audio: Add quirk for ELP HD USB Camera
+    - arm64: Define AT_VECTOR_SIZE_ARCH for ARCH_DLINFO
+    - parisc: Fix order of EREFUSED define in errno.h
+    - virtio: fix memory leak in virtqueue_add()
+    - vfio/pci: Fix NULL pointer oops in error interrupt setup handling
+    - perf intel-pt: Fix occasional decoding errors when tracing system-wide
+    - libnvdimm, nd_blk: mask off reserved status bits
+    - ALSA: hda - Manage power well properly for resume
+    - NVMe: Don't unmap controller registers on reset
+    - PCI: Support PCIe devices with short cfg_size
+    - PCI: Add Netronome vendor and device IDs
+    - PCI: Limit config space size for Netronome NFP6000 family
+    - PCI: Add Netronome NFP4000 PF device ID
+    - PCI: Limit config space size for Netronome NFP4000
+    - mmc: sdhci-acpi: Reduce Baytrail eMMC/SD/SDIO hangs
+    - ACPI: CPPC: Return error if _CPC is invalid on a CPU
+    - ACPI / CPPC: Prevent cpc_desc_ptr points to the invalid data
+    - um: Don't discard .text.exit section
+    - genirq/msi: Remove unused MSI_FLAG_IDENTITY_MAP
+    - genirq/msi: Make sure PCI MSIs are activated early
+    - crypto: caam - fix non-hmac hashes
+    - crypto: caam - fix echainiv(authenc) encrypt shared descriptor
+    - crypto: caam - defer aead_set_sh_desc in case of zero authsize
+    - usb: ehci: change order of register cleanup during shutdown
+    - usb: misc: usbtest: add fix for driver hang
+    - usb: dwc3: pci: add Intel Kabylake PCI ID
+    - usb: dwc3: gadget: increment request->actual once
+    - usb: hub: Fix unbalanced reference count/memory leak/deadlocks
+    - USB: hub: fix up early-exit pathway in hub_activate
+    - USB: hub: change the locking in hub_activate
+    - usb: renesas_usbhs: clear the BRDYSTS in usbhsg_ep_enable()
+    - usb: renesas_usbhs: Use dmac only if the pipe type is bulk
+    - USB: validate wMaxPacketValue entries in endpoint descriptors
+    - usb: gadget: fsl_qe_udc: off by one in setup_received_handle()
+    - usb/gadget: fix gadgetfs aio support.
+    - xhci: always handle "Command Ring Stopped" events
+    - usb: xhci: Fix panic if disconnect
+    - xhci: don't dereference a xhci member after removing xhci
+    - USB: serial: fix memleak in driver-registration error path
+    - USB: serial: option: add D-Link DWM-156/A3
+    - USB: serial: option: add support for Telit LE920A4
+    - USB: serial: ftdi_sio: add device ID for WICED USB UART dev board
+    - USB: serial: ftdi_sio: add PIDs for Ivium Technologies devices
+    - iommu/dma: Don't put uninitialised IOVA domains
+    - iommu/arm-smmu: Fix CMDQ error handling
+    - iommu/arm-smmu: Don't BUG() if we find aborting STEs with disable_bypass
+    - pinctrl/amd: Remove the default de-bounce time
+    - EDAC: Increment correct counter in edac_inc_ue_error()
+    - s390/dasd: fix hanging device after clear subchannel
+    - mac80211: fix purging multicast PS buffer queue
+    - arm64: dts: rockchip: add reset saradc node for rk3368 SoCs
+    - of: fix reference counting in of_graph_get_endpoint_by_regs
+    - sched/cputime: Fix NO_HZ_FULL getrusage() monotonicity regression
+    - sched/nohz: Fix affine unpinned timers mess
+    - iio: fix sched WARNING "do not call blocking ops when !TASK_RUNNING"
+    - drm/amdgpu: Change GART offset to 64-bit
+    - drm/amdgpu: fix amdgpu_move_blit on 32bit systems
+    - drm/amdgpu: avoid a possible array overflow
+    - drm/amdgpu: skip TV/CV in display parsing
+    - drm/amd/amdgpu: sdma resume fail during S4 on CI
+    - drm/amdgpu: record error code when ring test failed
+    - drm/i915: fix aliasing_ppgtt leak
+    - ARC: build: Better way to detect ISA compatible toolchain
+    - ARC: use correct offset in pt_regs for saving/restoring user mode r25
+    - ARC: Call trace_hardirqs_on() before enabling irqs
+    - ARC: Elide redundant setup of DMA callbacks
+    - aacraid: Check size values after double-fetch from user
+    - mfd: cros_ec: Add cros_ec_cmd_xfer_status() helper
+    - i2c: cros-ec-tunnel: Fix usage of cros_ec_cmd_xfer()
+    - cdc-acm: fix wrong pipe type on rx interrupt xfers
+    - mpt3sas: Fix resume on WarpDrive flash cards
+    - megaraid_sas: Fix probing cards without io port
+    - usb: renesas_usbhs: gadget: fix return value check in
+      usbhs_mod_gadget_probe()
+    - gpio: Fix OF build problem on UM
+    - fs/seq_file: fix out-of-bounds read
+    - btrfs: waiting on qgroup rescan should not always be interruptible
+    - btrfs: properly track when rescan worker is running
+    - Input: tegra-kbc - fix inverted reset logic
+    - Input: i8042 - break load dependency between atkbd/psmouse and i8042
+    - Input: i8042 - set up shared ps2_cmd_mutex for AUX ports
+    - crypto: nx - off by one bug in nx_of_update_msc()
+    - crypto: qat - fix aes-xts key sizes
+    - dmaengine: usb-dmac: check CHCR.DE bit in usb_dmac_isr_channel()
+    - USB: avoid left shift by -1
+    - usb: chipidea: udc: don't touch DP when controller is in host mode
+    - USB: fix typo in wMaxPacketSize validation
+    - USB: serial: mos7720: fix non-atomic allocation in write path
+    - USB: serial: mos7840: fix non-atomic allocation in write path
+    - USB: serial: option: add WeTelecom WM-D200
+    - USB: serial: option: add WeTelecom 0x6802 and 0x6803 products
+    - staging: comedi: daqboard2000: bug fix board type matching code
+    - staging: comedi: comedi_test: fix timer race conditions
+    - staging: comedi: ni_mio_common: fix AO inttrig backwards compatibility
+    - staging: comedi: ni_mio_common: fix wrong insn_write handler
+    - ACPI / drivers: fix typo in ACPI_DECLARE_PROBE_ENTRY macro
+    - ACPI / drivers: replace acpi_probe_lock spinlock with mutex
+    - ACPI / sysfs: fix error code in get_status()
+    - ACPI / SRAT: fix SRAT parsing order with both LAPIC and X2APIC present
+    - ALSA: line6: Remove double line6_pcm_release() after failed acquire.
+    - ALSA: line6: Give up on the lock while URBs are released.
+    - ALSA: line6: Fix POD sysfs attributes segfault
+    - hwmon: (iio_hwmon) fix memory leak in name attribute
+    - sysfs: correctly handle read offset on PREALLOC attrs
+    - Linux 4.4.20
+
+  * Failed to acknowledge elog: /sys/firmware/opal/elog/0x5018d709/acknowledge
+    (2:No such file or directory) (LP: #1619552)
+    - powerpc/powernv : Drop reference added by kset_find_obj()
+
+  * backport support for userspace access of DP aux devices (LP: #1619756)
+    - drm/dp: Add a drm_aux-dev module for reading/writing dpcd registers.
+    - drm/dp: Allow signals to interrupt drm_aux-dev reads/writes
+    - [Config] CONFIG_DRM_DP_AUX_CHARDEV=y
+
+  * Enable virtual scsi server driver for Power (LP: #1615665)
+    - SAUCE: Ibmvscsis: Properly deregister target sessions
+    - SAUCE: Return TCMU-generated sense data to fabric module
+    - SAUCE: Ibmvscsis: Code cleanup of print statements
+    - SAUCE: Ibmvscsis: Fixed a bug reported by Dan Carpenter
+
+  * ISST-LTE: system dropped into xmon at pcibios_release_device+0x5c/0x80
+    during running dlpar test on monklp3 (LP: #1618151)
+    - powerpc/pseries: use pci_host_bridge.release_fn() to kfree(phb)
+
+  * Kernel Build Fails for Fuse Module (LP: #1617550)
+    - SAUCE: (namespace) userns: Export current_in_userns to modules
+
+  * boot-time kernel panic introduced in 4.4.0-18, not present in 4.4.0-15
+    (LP: #1572630)
+    - blk-mq: Reuse hardware context cpumask for tags
+    - blk-mq: Use proper cpumask iterator
+
+ -- Joseph Salisbury <joseph.salisbury@canonical.com>  Mon, 19 Sep 2016 14:23:10 -0400
+
+linux (4.4.0-38.57) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1620658
+
+  * CIFS client: access problems after updating to kernel 4.4.0-29-generic
+    (LP: #1612135)
+    - Revert "UBUNTU: SAUCE: (namespace) Bypass sget() capability check for nfs"
+    - fs: Call d_automount with the filesystems creds
+
+  * apt-key add fails in overlayfs (LP: #1618572)
+    - SAUCE: overlayfs: fix regression in whiteout detection
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 30 Aug 2016 12:24:30 -0600
+
+linux (4.4.0-37.56) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1618040
+
+  * [Feature] Instruction decoder support for new SKX instructions- AVX512
+    (LP: #1591655)
+    - x86/insn: perf tools: Fix vcvtph2ps instruction decoding
+    - x86/insn: Add AVX-512 support to the instruction decoder
+    - perf tools: Add AVX-512 support to the instruction decoder used by Intel PT
+    - perf tools: Add AVX-512 instructions to the new instructions test
+
+  * [Ubuntu 16.04] FCoE Lun not visible in OS with inbox driver - Issue with
+    ioremap() call on 32bit kernel (LP: #1608652)
+    - lpfc: Correct issue with ioremap() call on 32bit kernel
+
+  * [Feature] turbostat support for Skylake-SP server (LP: #1591802)
+    - tools/power turbostat: decode more CPUID fields
+    - tools/power turbostat: CPUID(0x16) leaf shows base, max, and bus frequency
+    - tools/power turbostat: decode HWP registers
+    - tools/power turbostat: Decode MSR_MISC_PWR_MGMT
+    - tools/power turbostat: allow sub-sec intervals
+    - tools/power turbostat: Intel Xeon x200: fix erroneous bclk value
+    - tools/power turbostat: Intel Xeon x200: fix turbo-ratio decoding
+    - tools/power turbostat: re-name "%Busy" field to "Busy%"
+    - tools/power turbostat: add --out option for saving output in a file
+    - tools/power turbostat: fix compiler warnings
+    - tools/power turbostat: make fewer systems calls
+    - tools/power turbostat: show IRQs per CPU
+    - tools/power turbostat: show GFXMHz
+    - tools/power turbostat: show GFX%rc6
+    - tools/power turbostat: detect and work around syscall jitter
+    - tools/power turbostat: indicate SMX and SGX support
+    - tools/power turbostat: call __cpuid() instead of __get_cpuid()
+    - tools/power turbostat: correct output for MSR_NHM_SNB_PKG_CST_CFG_CTL dump
+    - tools/power turbostat: bugfix: TDP MSRs print bits fixing
+    - tools/power turbostat: SGX state should print only if --debug
+    - tools/power turbostat: print IRTL MSRs
+    - tools/power turbostat: initial BXT support
+    - tools/power turbostat: decode BXT TSC frequency via CPUID
+    - tools/power turbostat: initial SKX support
+
+  * [BYT] display hotplug doesn't work on console (LP: #1616894)
+    - drm/i915/vlv: Make intel_crt_reset() per-encoder
+    - drm/i915/vlv: Reset the ADPA in vlv_display_power_well_init()
+    - drm/i915/vlv: Disable HPD in valleyview_crt_detect_hotplug()
+    - drm/i915: Enable polling when we don't have hpd
+
+  * [Feature]intel_idle enabling on Broxton-P (LP: #1520446)
+    - intel_idle: add BXT support
+
+  * [Feature] EDAC: Update driver for SKX-SP (LP: #1591815)
+    - [Config] CONFIG_EDAC_SKX=m
+    - EDAC, skx_edac: Add EDAC driver for Skylake
+
+  * [Feature] KBL: Sandy Peak(3168) WiFi/BT support (LP: #1591648)
+    - Bluetooth: Add support for Intel Bluetooth device 3168 [8087:0aa7]
+
+  * MacBookPro11,4 fails to poweroff or suspend (LP: #1587714)
+    - SAUCE: PCI: Workaround to enable poweroff on Mac Pro 11
+
+  * Support Edge Gateway's Bluetooth LED (LP: #1512999)
+    - SAUCE: Bluetooth: Support for LED on Edge Gateways
+    - SAUCE: Bluetooth: Use host bridge subsystem IDs to identify Edge Gateways
+
+  * Please add support for alps touchpad. (LP: #1616813)
+    - [Config] CONFIG_HID_ALPS=m
+    - HID: add Alps I2C HID Touchpad-Stick support
+    - HID: alps: struct u1_dev *priv is internal to the driver
+    - HID: alps: pass correct sizes to hid_hw_raw_request()
+    - HID: alps: match alps devices in core
+    - HID: alps: a few cleanups
+
+  * DINO2M - System hangs with a black screen during s4 stress test
+    (LP: #1616781)
+    - x86/power/64: Fix kernel text mapping corruption during image restoration
+
+  * Xenial update to v4.4.17 stable release (LP: #1611833)
+    - USB: OHCI: Don't mark EDs as ED_OPER if scheduling fails
+    - x86/quirks: Apply nvidia_bugs quirk only on root bus
+    - x86/quirks: Reintroduce scanning of secondary buses
+    - x86/quirks: Add early quirk to reset Apple AirPort card
+    - dmaengine: at_xdmac: align descriptors on 64 bits
+    - dmaengine: at_xdmac: fix residue corruption
+    - dmaengine: at_xdmac: double FIFO flush needed to compute residue
+    - mm, sl[au]b: add __GFP_ATOMIC to the GFP reclaim mask
+    - mm, compaction: abort free scanner if split fails
+    - fs/nilfs2: fix potential underflow in call to crc32_le
+    - mm, compaction: prevent VM_BUG_ON when terminating freeing scanner
+    - mm, meminit: always return a valid node from early_pfn_to_nid
+    - mm, meminit: ensure node is online before checking whether pages are
+      uninitialised
+    - vmlinux.lds: account for destructor sections
+    - pps: do not crash when failed to register
+    - kernel/sysrq, watchdog, sched/core: Reset watchdog on all CPUs while
+      processing sysrq-w
+    - arc: unwind: warn only once if DW2_UNWIND is disabled
+    - ARC: unwind: ensure that .debug_frame is generated (vs. .eh_frame)
+    - xen/pciback: Fix conf_space read/write overlap check.
+    - xenbus: don't BUG() on user mode induced condition
+    - xenbus: don't bail early from xenbus_dev_request_and_reply()
+    - Input: vmmouse - remove port reservation
+    - Input: elantech - add more IC body types to the list
+    - Input: xpad - fix oops when attaching an unknown Xbox One gamepad
+    - Input: wacom_w8001 - w8001_MAX_LENGTH should be 13
+    - Input: xpad - validate USB endpoint count during probe
+    - Input: tsc200x - report proper input_dev name
+    - pvclock: Add CPU barriers to get correct version value
+    - pinctrl: single: Fix missing flush of posted write for a wakeirq
+    - pinctrl: imx: Do not treat a PIN without MUX register as an error
+    - cgroup: set css->id to -1 during init
+    - power_supply: power_supply_read_temp only if use_cnt > 0
+    - locks: use file_inode()
+    - Revert "ecryptfs: forbid opening files without mmap handler"
+    - ecryptfs: don't allow mmap when the lower fs doesn't support it
+    - ext4: verify extent header depth
+    - 9p: use file_dentry()
+    - namespace: update event counter when umounting a deleted dentry
+    - spi: sunxi: fix transfer timeout
+    - spi: sun4i: fix FIFO limit
+    - clk: rockchip: initialize flags of clk_init_data in mmc-phase clock
+    - platform/chrome: cros_ec_dev - double fetch bug in ioctl
+    - block: fix use-after-free in sys_ioprio_get()
+    - mmc: block: fix packed command header endianness
+    - sched/fair: Fix effective_load() to consistently use smoothed load
+    - ovl: handle ATTR_KILL*
+    - perf/x86: fix PEBS issues on Intel Atom/Core2
+    - can: at91_can: RX queue could get stuck at high bus load
+    - can: c_can: Update D_CAN TX and RX functions to 32 bit - fix Altera Cyclone
+      access
+    - can: fix handling of unmodifiable configuration options fix
+    - can: fix oops caused by wrong rtnl dellink usage
+    - RDS: fix rds_tcp_init() error path
+    - SCSI: fix new bug in scsi_dev_info_list string matching
+    - ipr: Clear interrupt on croc/crocodile when running with LSI
+    - posix_cpu_timer: Exit early when process has been reaped
+    - i2c: mux: reg: wrong condition checked for of_address_to_resource return
+      value
+    - libata: LITE-ON CX1-JB256-HP needs lower max_sectors
+    - libceph: apply new_state before new_up_client on incrementals
+    - net: mvneta: set real interrupt per packet for tx_done
+    - intel_th: pci: Add Kaby Lake PCH-H support
+    - intel_th: Fix a deadlock in modprobing
+    - vfs: fix deadlock in file_remove_privs() on overlayfs
+    - Linux 4.4.17
+    - xenbus: don't look up transaction IDs for ordinary writes
+
+  * Enable virtual scsi server driver for Power (LP: #1615665)
+    - [Config] CONFIG_SCSI_IBMVSCSIS=m
+    - target: Add target_alloc_session() helper function
+    - ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
+
+  * AES-XTS poor performance in Ubuntu 16.04 (LP: #1613295)
+    - crypto: vmx: Only call enable_kernel_vsx()
+    - powerpc: Create disable_kernel_{fp,altivec,vsx,spe}()
+    - crypto: vmx - Adding asm subroutines for XTS
+    - crypto: xts - consolidate sanity check for keys
+    - crypto: vmx - Adding support for XTS
+    - crypto: vmx - Fix aes_p8_xts_decrypt build failure
+    - crypto: xts - fix compile errors
+
+  *  System hang when plug/pull USB 3.1 key via thunderbolt port over 5 times
+    (LP: #1616318)
+    - USB: don't free bandwidth_mutex too early
+
+  * Ubuntu 16.04 - Full EEH Recovery Support for NVMe devices (LP: #1602724)
+    - nvme: Suspend all queues before deletion
+
+  * change_hat is logging failures during expected hat probing (LP: #1615893)
+    - SAUCE: apparmor: Fix auditing behavior for change_hat probing
+
+  * deleted files outside of the namespace are not being treated as disconnected
+    (LP: #1615892)
+    - SAUCE: apparmor: deleted dentries can be disconnected
+
+  * stacking to unconfined in a child namespace confuses mediation
+    (LP: #1615890)
+    - SAUCE: apparmor: special case unconfined when determining the mode
+
+  * apparmor module parameters can be changed after the policy is locked
+    (LP: #1615895)
+    - SAUCE: apparmor: fix: parameters can be changed after policy is locked
+
+  * AppArmor profile reloading causes an intermittent kernel BUG (LP: #1579135)
+    - SAUCE: apparmor: fix vec_unique for vectors larger than 8
+
+  * label vec reductions can result in reference labels instead of direct access
+    to labels (LP: #1615889)
+    - SAUCE: apparmor: reduction of vec to single entry is just that entry
+
+  * profiles from different namespaces can block other namespaces from being
+    able to load a profile (LP: #1615887)
+    - SAUCE: apparmor: profiles in one ns can affect mediation in another ns
+
+  * vmalloc failure leads to null ptr dereference in aa_dfa_next (LP: #1592547)
+    - SAUCE: apparmor: oops in profile_unpack() when policy_db is not present
+
+  * vmalloc_addr is being checked on the failed return address of kvzalloc()
+    (LP: #1615885)
+    - SAUCE: apparmor: fix: don't check for vmalloc_addr if kvzalloc() failed
+
+  * dfa is missing a bounds check which can cause an oops (LP: #1615882)
+    - SAUCE: apparmor: Add missing id bounds check on dfa verification
+
+  * The label build for onexec when stacking is wrong (LP: #1615881)
+    - SAUCE: apparmor: Fix label build for onexec stacking.
+
+  * The inherit check for new to old label comparison for domain transitions is
+    wrong (LP: #1615880)
+    - SAUCE: apparmor: Fix new to old label comparison for domain transitions
+
+  * warning stack trace while playing with apparmor namespaces (LP: #1593874)
+    - SAUCE: apparmor: fix stack trace when removing namespace with profiles
+
+  * __label_update proxy comparison test is wrong (LP: #1615878)
+    - SAUCE: apparmor: Fix __label_update proxy comparison test
+
+  * Xenial update to v4.4.19 stable release (LP: #1615620)
+    - usb: gadget: avoid exposing kernel stack
+    - usb: f_fs: off by one bug in _ffs_func_bind()
+    - usb: renesas_usbhs: protect the CFIFOSEL setting in usbhsg_ep_enable()
+    - usb: dwc3: fix for the isoc transfer EP_BUSY flag
+    - USB: serial: option: add support for Telit LE910 PID 0x1206
+    - usb: renesas_usbhs: fix NULL pointer dereference in xfer_work()
+    - arm64: kernel: Save and restore UAO and addr_limit on exception entry
+    - arm64: debug: unmask PSTATE.D earlier
+    - arm64: Fix incorrect per-cpu usage for boot CPU
+    - tty: serial: msm: Don't read off end of tx fifo
+    - serial: samsung: Fix ERR pointer dereference on deferred probe
+    - tty/serial: atmel: fix RS485 half duplex with DMA
+    - gpio: pca953x: Fix NBANK calculation for PCA9536
+    - gpio: intel-mid: Remove potentially harmful code
+    - Bluetooth: hci_intel: Fix null gpio desc pointer dereference
+    - pinctrl: cherryview: prevent concurrent access to GPIO controllers
+    - arm64: dts: rockchip: fixes the gic400 2nd region size for rk3368
+    - arm64: mm: avoid fdt_check_header() before the FDT is fully mapped
+    - KVM: PPC: Book3S HV: Pull out TM state save/restore into separate procedures
+    - KVM: PPC: Book3S HV: Save/restore TM state in H_CEDE
+    - KVM: MTRR: fix kvm_mtrr_check_gfn_range_consistency page fault
+    - KVM: VMX: handle PML full VMEXIT that occurs during event delivery
+    - KVM: nVMX: Fix memory corruption when using VMCS shadowing
+    - intel_pstate: Fix MSR_CONFIG_TDP_x addressing in core_get_max_pstate()
+    - mfd: qcom_rpm: Fix offset error for msm8660
+    - mfd: qcom_rpm: Parametrize also ack selector size
+    - media: usbtv: prevent access to free'd resources
+    - media: dvb_ringbuffer: Add memory barriers
+    - vb2: core: Skip planes array verification if pb is NULL
+    - Fix RC5 decoding with Fintek CIR chipset
+    - sur40: lower poll interval to fix occasional FPS drops to ~56 FPS
+    - sur40: fix occasional oopses on device close
+    - dm: set DMF_SUSPENDED* _before_ clearing DMF_NOFLUSH_SUSPENDING
+    - hp-wmi: Fix wifi cannot be hard-unblocked
+    - s5p-mfc: Set device name for reserved memory region devs
+    - s5p-mfc: Add release callback for memory region devs
+    - i2c: efm32: fix a failure path in efm32_i2c_probe()
+    - spi: pxa2xx: Clear all RFT bits in reset_sccr1() on Intel Quark
+    - Bluetooth: Fix l2cap_sock_setsockopt() with optname BT_RCVMTU
+    - EDAC: Correct channel count limit
+    - HID: uhid: fix timeout when probe races with IO
+    - ovl: disallow overlayfs as upperdir
+    - remoteproc: Fix potential race condition in rproc_add
+    - ARC: mm: don't loose PTE_SPECIAL in pte_modify()
+    - jbd2: make journal y2038 safe
+    - fs/cifs: make share unaccessible at root level mountable
+    - cifs: Check for existing directory when opening file with O_CREAT
+    - cifs: fix crash due to race in hmac(md5) handling
+    - CIFS: Fix a possible invalid memory access in smb2_query_symlink()
+    - random: initialize the non-blocking pool via add_hwgenerator_randomness()
+    - random: print a warning for the first ten uninitialized random users
+    - random: add interrupt callback to VMBus IRQ handler
+    - MIPS: KVM: Fix mapped fault broken commpage handling
+    - MIPS: KVM: Add missing gfn range check
+    - MIPS: KVM: Fix gfn range check in kseg0 tlb faults
+    - MIPS: KVM: Propagate kseg0/mapped tlb fault errors
+    - nfs: don't create zero-length requests
+    - nfsd: Fix race between FREE_STATEID and LOCK
+    - nfsd: don't return an unhashed lock stateid after taking mutex
+    - drm/i915: Don't complain about lack of ACPI video bios
+    - iommu/exynos: Suppress unbinding to prevent system failure
+    - iommu/vt-d: Return error code in domain_context_mapping_one()
+    - iommu/amd: Handle IOMMU_DOMAIN_DMA in ops->domain_free call-back
+    - iommu/amd: Init unity mappings only for dma_ops domains
+    - iommu/amd: Update Alias-DTE in update_device_table()
+    - audit: fix a double fetch in audit_log_single_execve_arg()
+    - ARM: dts: sunxi: Add a startup delay for fixed regulator enabled phys
+    - netlabel: add address family checks to netlbl_{sock,req}_delattr()
+    - w1:omap_hdq: fix regression
+    - drm/amdgpu: add a delay after ATPX dGPU power off
+    - drm/amdgpu: Poll for both connect/disconnect on analog connectors
+    - drm/amdgpu: support backlight control for UNIPHY3
+    - drm/amdgpu: Disable RPM helpers while reprobing connectors on resume
+    - drm/amdgpu: fix firmware info version checks
+    - drm/amdgpu/gmc7: add missing mullins case
+    - drm/radeon: add a delay after ATPX dGPU power off
+    - drm/radeon: Poll for both connect/disconnect on analog connectors
+    - drm/radeon: fix firmware info version checks
+    - drm/radeon: support backlight control for UNIPHY3
+    - drm/nouveau/gr/nv3x: fix instobj write offsets in gr setup
+    - drm/nouveau/fbcon: fix font width not divisible by 8
+    - drm: Restore double clflush on the last partial cacheline
+    - drm/edid: Add 6 bpc quirk for display AEO model 0.
+    - drm/i915: Never fully mask the the EI up rps interrupt on SNB/IVB
+    - drm/i915/dp: Revert "drm/i915/dp: fall back to 18 bpp when sink capability
+      is unknown"
+    - balloon: check the number of available pages in leak balloon
+    - ftrace/recordmcount: Work around for addition of metag magic but not
+      relocations
+    - metag: Fix __cmpxchg_u32 asm constraint for CMP
+    - block: add missing group association in bio-cloning functions
+    - block: fix bdi vs gendisk lifetime mismatch
+    - mtd: nand: fix bug writing 1 byte less than page size
+    - mm/hugetlb: avoid soft lockup in set_max_huge_pages()
+    - ALSA: hda: Fix krealloc() with __GFP_ZERO usage
+    - ALSA: hda/realtek - Can't adjust speaker's volume on a Dell AIO
+    - ALSA: hda: add AMD Bonaire AZ PCI ID with proper driver caps
+    - ALSA: hda - Fix headset mic detection problem for two dell machines
+    - IB/mlx5: Fix MODIFY_QP command input structure
+    - IB/mlx5: Fix entries checks in mlx5_ib_create_cq
+    - IB/mlx5: Fix returned values of query QP
+    - IB/mlx5: Fix entries check in mlx5_ib_resize_cq
+    - IB/mlx5: Fix post send fence logic
+    - IB/mlx5: Return PORT_ERR in Active to Initializing tranisition
+    - IB/SA: Use correct free function
+    - IB/IPoIB: Don't update neigh validity for unresolved entries
+    - IB/IWPM: Fix a potential skb leak
+    - IB/mlx4: Fix the SQ size of an RC QP
+    - IB/mlx4: Fix error flow when sending mads under SRIOV
+    - IB/mlx4: Fix memory leak if QP creation failed
+    - of: fix memory leak related to safe_name()
+    - ubi: Make volume resize power cut aware
+    - ubi: Fix early logging
+    - ubi: Fix race condition between ubi device creation and udev
+    - iscsi-target: Fix panic when adding second TCP connection to iSCSI session
+    - target: Fix ordered task target_setup_cmd_from_cdb exception hang
+    - target: Fix missing complete during ABORT_TASK + CMD_T_FABRIC_STOP
+    - target: Fix race between iscsi-target connection shutdown + ABORT_TASK
+    - target: Fix max_unmap_lba_count calc overflow
+    - target: Fix ordered task CHECK_CONDITION early exception handling
+    - Input: elan_i2c - properly wake up touchpad on ASUS laptops
+    - SUNRPC: Don't allocate a full sockaddr_storage for tracing
+    - MIPS: mm: Fix definition of R6 cache instruction
+    - MIPS: Don't register r4k sched clock when CPUFREQ enabled
+    - MIPS: hpet: Increase HPET_MIN_PROG_DELTA and decrease HPET_MIN_CYCLES
+    - PCI: Mark Atheros AR9485 and QCA9882 to avoid bus reset
+    - x86/platform/intel_mid_pci: Rework IRQ0 workaround
+    - ACPI / EC: Work around method reentrancy limit in ACPICA for _Qxx
+    - rtc: s3c: Add s3c_rtc_{enable/disable}_clk in s3c_rtc_setfreq()
+    - dm flakey: error READ bios during the down_interval
+    - module: Invalidate signatures on force-loaded modules
+    - Documentation/module-signing.txt: Note need for version info if reusing a
+      key
+    - Linux 4.4.19
+
+  * xfrm: ipsec crash when updating spd thresholds (LP: #1613787)
+    - xfrm: Ignore socket policies when rebuilding hash tables
+
+  * ISST-LTE:pKVM311:lotg5:Ubutu16041:lotg5 crashed @
+    writeback_sb_inodes+0x30c/0x590 (LP: #1614565)
+    - writeback: Write dirty times for WB_SYNC_ALL writeback
+
+  * IBM Power 720 Ethernet Not Seen (LP: #1612725)
+    - [Config] CONFIG_IBMEBUS=y for powerpc
+
+  * CAPI: Update default setting for the psl_fir_cntl register (LP: #1612431)
+    - cxl: Set psl_fir_cntl to production environment value
+
+  * Xenial update to v4.4.18 stable release (LP: #1614560)
+    - tcp: enable per-socket rate limiting of all 'challenge acks'
+    - ipv4: reject RTNH_F_DEAD and RTNH_F_LINKDOWN from user space
+    - bonding: set carrier off for devices created through netlink
+    - net: bgmac: Fix infinite loop in bgmac_dma_tx_add()
+    - net/irda: fix NULL pointer dereference on memory allocation failure
+    - qed: Fix setting/clearing bit in completion bitmap
+    - tcp: consider recv buf for the initial window scale
+    - ipath: Restrict use of the write() interface
+    - scsi: ignore errors from scsi_dh_add_device()
+    - HID: sony: do not bail out when the sixaxis refuses the output report
+    - i2c: i801: Allow ACPI SystemIO OpRegion to conflict with PCI BAR
+    - arm: oabi compat: add missing access checks
+    - KEYS: 64-bit MIPS needs to use compat_sys_keyctl for 32-bit userspace
+    - Revert "s390/kdump: Clear subchannel ID to signal non-CCW/SCSI IPL"
+    - random: strengthen input validation for RNDADDTOENTCNT
+    - devpts: clean up interface to pty drivers
+    - x86/mm/pat: Add support of non-default PAT MSR setting
+    - x86/mm/pat: Add pat_disable() interface
+    - x86/mm/pat: Replace cpu_has_pat with boot_cpu_has()
+    - x86/mtrr: Fix Xorg crashes in Qemu sessions
+    - x86/mtrr: Fix PAT init handling when MTRR is disabled
+    - x86/xen, pat: Remove PAT table init code from Xen
+    - x86/pat: Document the PAT initialization sequence
+    - x86/mm/pat: Fix BUG_ON() in mmap_mem() on QEMU/i386
+    - drm/i915: Pretend cursor is always on for ILK-style WM calculations (v2)
+    - x86/syscalls/64: Add compat_sys_keyctl for 32-bit userspace
+    - block: fix use-after-free in seq file
+    - sysv, ipc: fix security-layer leaking
+    - fuse: fsync() did not return IO errors
+    - fuse: fuse_flush must check mapping->flags for errors
+    - fuse: fix wrong assignment of ->flags in fuse_send_init()
+    - fs/dcache.c: avoid soft-lockup in dput()
+    - crypto: gcm - Filter out async ghash if necessary
+    - crypto: scatterwalk - Fix test in scatterwalk_done
+    - ext4: check for extents that wrap around
+    - ext4: fix deadlock during page writeback
+    - ext4: don't call ext4_should_journal_data() on the journal inode
+    - ext4: validate s_reserved_gdt_blocks on mount
+    - ext4: short-cut orphan cleanup on error
+    - ext4: fix reference counting bug on block allocation error
+    - mm: memcontrol: fix cgroup creation failure after many small jobs
+    - mm: memcontrol: fix swap counter leak on swapout from offline cgroup
+    - mm: memcontrol: fix memcg id ref counter on swap charge move
+    - Linux 4.4.18
+
+  * Ubuntu16.10:installation fails on Brazos system (31TB and 192 cores) No
+    memory for flatten_device_tree (no room) (LP: #1614309)
+    - SAUCE: powerpc/pseries: Increase RMA size to 512MB.
+
+  * [SRU] xgene_enet: 10g performance only hits ~75% on multi-client tests
+    (LP: #1613157)
+    - drivers: net: xgene: Add support for Classifier engine
+    - drivers: net: xgene: Add support for RSS
+    - drivers: net: xgene: Add support for multiple queues
+
+  * [SRU] xgene_enet: an extra interrupt may be pending for an interrupt
+    controller that doesn't support irq_disable and hardware with level
+    interrupt (LP: #1611399)
+    - drivers: net: xgene: fix extra IRQ issue
+
+  * Mic mute hotkey does not work on usb keyboard [03f0:2f4a] (LP: #1609606)
+    - HID: input: add mic mute key on HP slim keyboard
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 12 Aug 2016 09:05:59 +0200
+
+linux (4.4.0-36.55) xenial; urgency=low
+
+  [ Stefan Bader ]
+
+  * Release Tracking Bug
+    - LP: #1612305
+
+  * I2C touchpad does not work on AMD platform (LP: #1612006)
+    - SAUCE: pinctrl/amd: Remove the default de-bounce time
+
+  * CVE-2016-5696
+    - tcp: make challenge acks less predictable
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 11 Aug 2016 17:34:14 +0200
+
+linux (4.4.0-35.54) xenial; urgency=low
+
+  [ Stefan Bader ]
+
+  * Release Tracking Bug
+    - LP: #1611215
+
+  * [i915_bpo] Sync with v4.7 (LP: #1609742)
+    - SAUCE: i915_bpo: Sync with v4.7
+
+  * s390/cio: fix reset of channel measurement block (LP: #1609415)
+    - s390/cio: allow to reset channel measurement block
+
+  * in Ubuntu16.10: Hit on Call traces  and system goes down when transactional
+    memory  tests are running in 32TB Brazos system (LP: #1606786)
+    - powerpc/tm: Avoid SLB faults in treclaim/trecheckpoint when RI=0
+    - powerpc/tm: Fix stack pointer corruption in __tm_recheckpoint()
+
+  *  Power Menu does not display after press the Power Button (LP: #1609204)
+    - intel-vbtn: new driver for Intel Virtual Button
+    - [config] enable CONFIG_INTEL_VBTN=m
+
+  * OptiPlex 7450 AIO hangs when rebooting (LP: #1608762)
+    - x86/reboot: Add Dell Optiplex 7450 AIO reboot quirk
+
+  * virtualbox+usb 3.0 breaks boot, -28 kernel works (LP: #1604058)
+    - SAUCE: xhci: Fix soft lockup in xhci_pci_probe path when XHCI_STATE_HALTED
+
+  * linux-kernel: Freeing IRQ from IRQ context (LP: #1597908)
+    - block: defer timeouts to a workqueue
+
+  * Tunnel offload indications not stripped from encapsulated packets, causing
+    performance overhead (LP: #1602755)
+    - tunnels: Remove encapsulation offloads on decap.
+
+  * lm-sensors is throwing "ERROR: Can't get value of subfeature temp1_input:
+    I/O error" for be2net driver (LP: #1607387)
+    - be2net: perform temperature query in adapter regardless of its interface
+      state
+
+  * Dell dock MAC Address pass through doesn't work in Ubuntu (LP: #1579984)
+    - r8152: Add support for setting pass through MAC address on RTL8153-AD
+
+  * vmxnet3 LRO IPv6 performance issues (stalling TCP) (LP: #1605494)
+    - Driver: Vmxnet3: set CHECKSUM_UNNECESSARY for IPv6 packets
+
+  * ISST-LTE:pVM:monklp5:Ubuntu16.04.1:system crashed at
+    lpfc_sli4_scmd_to_wqidx_distr (LP: #1597974)
+    - SAUCE: lpfc: fix oops in lpfc_sli4_scmd_to_wqidx_distr() from
+      lpfc_send_taskmgmt()
+
+  * Backport cxlflash shutdown patch to Xenial SRU (LP: #1605405)
+    - SAUCE: cxlflash: Verify problem state area is mapped before notifying
+      shutdown
+
+  * Xenial update to v4.4.16 stable release (LP: #1607404)
+    - mac80211: fix fast_tx header alignment
+    - mac80211: mesh: flush mesh paths unconditionally
+    - mac80211_hwsim: Add missing check for HWSIM_ATTR_SIGNAL
+    - mac80211: Fix mesh estab_plinks counting in STA removal case
+    - EDAC, sb_edac: Fix rank lookup on Broadwell
+    - IB/cm: Fix a recently introduced locking bug
+    - IB/mlx4: Properly initialize GRH TClass and FlowLabel in AHs
+    - powerpc/pseries: Fix IBM_ARCH_VEC_NRCORES_OFFSET since POWER8NVL was added
+    - powerpc/tm: Always reclaim in start_thread() for exec() class syscalls
+    - usb: dwc2: fix regression on big-endian PowerPC/ARM systems
+    - USB: EHCI: declare hostpc register as zero-length array
+    - usb: common: otg-fsm: add license to usb-otg-fsm
+    - mnt: fs_fully_visible test the proper mount for MNT_LOCKED
+    - mnt: Account for MS_RDONLY in fs_fully_visible
+    - mnt: If fs_fully_visible fails call put_filesystem.
+    - of: fix autoloading due to broken modalias with no 'compatible'
+    - of: irq: fix of_irq_get[_byname]() kernel-doc
+    - locking/ww_mutex: Report recursive ww_mutex locking early
+    - locking/qspinlock: Fix spin_unlock_wait() some more
+    - locking/static_key: Fix concurrent static_key_slow_inc()
+    - x86, build: copy ldlinux.c32 to image.iso
+    - kprobes/x86: Clear TF bit in fault on single-stepping
+    - x86/amd_nb: Fix boot crash on non-AMD systems
+    - Revert "gpiolib: Split GPIO flags parsing and GPIO configuration"
+    - uvc: Forward compat ioctls to their handlers directly
+    - thermal: cpu_cooling: fix improper order during initialization
+    - writeback: use higher precision calculation in domain_dirty_limits()
+    - nfsd4/rpc: move backchannel create logic into rpc code
+    - nfsd: Always lock state exclusively.
+    - nfsd: Extend the mutex holding region around in nfsd4_process_open2()
+    - posix_acl: Add set_posix_acl
+    - nfsd: check permissions when setting ACLs
+    - make nfs_atomic_open() call d_drop() on all ->open_context() errors.
+    - NFS: Fix another OPEN_DOWNGRADE bug
+    - ARM: imx6ul: Fix Micrel PHY mask
+    - ARM: 8578/1: mm: ensure pmd_present only checks the valid bit
+    - ARM: 8579/1: mm: Fix definition of pmd_mknotpresent
+    - MIPS: KVM: Fix modular KVM under QEMU
+    - mm: Export migrate_page_move_mapping and migrate_page_copy
+    - UBIFS: Implement ->migratepage()
+    - sched/fair: Fix cfs_rq avg tracking underflow
+    - packet: Use symmetric hash for PACKET_FANOUT_HASH.
+    - net_sched: fix mirrored packets checksum
+    - cdc_ncm: workaround for EM7455 "silent" data interface
+    - ipv6: Fix mem leak in rt6i_pcpu
+    - ARCv2: Check for LL-SC livelock only if LLSC is enabled
+    - ARCv2: LLSC: software backoff is NOT needed starting HS2.1c
+    - kvm: Fix irq route entries exceeding KVM_MAX_IRQ_ROUTES
+    - KVM: nVMX: VMX instructions: fix segment checks when L1 is in long mode.
+    - HID: elo: kill not flush the work
+    - HID: hiddev: validate num_values for HIDIOCGUSAGES, HIDIOCSUSAGES commands
+    - tracing: Handle NULL formats in hold_module_trace_bprintk_format()
+    - base: make module_create_drivers_dir race-free
+    - iommu/arm-smmu: Wire up map_sg for arm-smmu-v3
+    - iommu/vt-d: Enable QI on all IOMMUs before setting root entry
+    - iommu/amd: Fix unity mapping initialization race
+    - drm/mgag200: Black screen fix for G200e rev 4
+    - ipmi: Remove smi_msg from waiting_rcv_msgs list before handle_one_recv_msg()
+    - arm64: Rework valid_user_regs
+    - vfs: add d_real_inode() helper
+    - af_unix: fix hard linked sockets on overlay
+    - btrfs: account for non-CoW'd blocks in btrfs_abort_transaction
+    - drm/radeon: fix asic initialization for virtualized environments
+    - drm/amdgpu/gfx7: fix broken condition check
+    - ubi: Make recover_peb power cut aware
+    - drm/amdkfd: unbind only existing processes
+    - drm/amdkfd: destroy dbgmgr in notifier release
+    - drm/dp/mst: Always clear proposed vcpi table for port.
+    - drm/nouveau/disp/sor/gf119: both links use the same training register
+    - drm/nouveau/gr/gf100-: update sm error decoding from gk20a nvgpu headers
+    - drm/nouveau/fbcon: fix out-of-bounds memory accesses
+    - drm/nouveau: fix for disabled fbdev emulation
+    - drm/nouveau/disp/sor/gf119: select correct sor when poking training pattern
+    - drm/i915/ilk: Don't disable SSC source if it's in use
+    - drm/i915: Refresh cached DP port register value on resume
+    - drm/i915: Update ifdeffery for mutex->owner
+    - drm/i915: Update CDCLK_FREQ register on BDW after changing cdclk frequency
+    - drm: add missing drm_mode_set_crtcinfo call
+    - drm: make drm_atomic_set_mode_prop_for_crtc() more reliable
+    - drm: atmel-hlcdc: actually disable scaling when no scaling is required
+    - drm/ttm: Make ttm_bo_mem_compat available
+    - drm/vmwgfx: Add an option to change assumed FB bpp
+    - drm/vmwgfx: Work around mode set failure in 2D VMs
+    - drm/vmwgfx: Check pin count before attempting to move a buffer
+    - drm/vmwgfx: Delay pinning fbdev framebuffer until after mode set
+    - drm/vmwgfx: Fix error paths when mapping framebuffer
+    - memory: omap-gpmc: Fix omap gpmc EXTRADELAY timing
+    - perf/x86: Fix undefined shift on 32-bit kernels
+    - xen/balloon: Fix declared-but-not-defined warning
+    - iio: Fix error handling in iio_trigger_attach_poll_func
+    - iio:st_pressure: fix sampling gains (bring inline with ABI)
+    - iio: light apds9960: Add the missing dev.parent
+    - iio: proximity: as3935: correct IIO_CHAN_INFO_RAW output
+    - iio: proximity: as3935: remove triggered buffer processing
+    - iio: proximity: as3935: fix buffer stack trashing
+    - iio: humidity: hdc100x: correct humidity integration time mask
+    - iio: humidity: hdc100x: fix IIO_TEMP channel reporting
+    - iio: hudmidity: hdc100x: fix incorrect shifting and scaling
+    - staging: iio: accel: fix error check
+    - iio: accel: kxsd9: fix the usage of spi_w8r8()
+    - iio:ad7266: Fix broken regulator error handling
+    - iio:ad7266: Fix support for optional regulators
+    - iio:ad7266: Fix probe deferral for vref
+    - tty/vt/keyboard: fix OOB access in do_compute_shiftstate()
+    - hwmon: (dell-smm) Restrict fan control and serial number to CAP_SYS_ADMIN by
+      default
+    - hwmon: (dell-smm) Disallow fan_type() calls on broken machines
+    - hwmon: (dell-smm) Cache fan_type() calls and change fan detection
+    - ALSA: dummy: Fix a use-after-free at closing
+    - ALSA: hda - Fix the headset mic jack detection on Dell machine
+    - ALSA: hda / realtek - add two more Thinkpad IDs (5050,5053) for tpt460 fixup
+    - ALSA: au88x0: Fix calculation in vortex_wtdma_bufshift()
+    - ALSA: echoaudio: Fix memory allocation
+    - ALSA: timer: Fix negative queue usage by racy accesses
+    - ALSA: hda/realtek: Add Lenovo L460 to docking unit fixup
+    - ALSA: hda - Add PCI ID for Kabylake-H
+    - ALSA: hda - fix read before array start
+    - ALSA: hda/realtek - add new pin definition in alc225 pin quirk table
+    - ALSA: pcm: Free chmap at PCM free callback, too
+    - ALSA: ctl: Stop notification after disconnection
+    - ALSA: hda - fix use-after-free after module unload
+    - ALSA: hda: add AMD Stoney PCI ID with proper driver caps
+    - ARM: sunxi/dt: make the CHIP inherit from allwinner,sun5i-a13
+    - ARM: dts: armada-38x: fix MBUS_ID for crypto SRAM on Armada 385 Linksys
+    - ARM: mvebu: fix HW I/O coherency related deadlocks
+    - ovl: Copy up underlying inode's ->i_mode to overlay inode
+    - ovl: verify upper dentry in ovl_remove_and_whiteout()
+    - scsi: fix race between simultaneous decrements of ->host_failed
+    - 53c700: fix BUG on untagged commands
+    - Fix reconnect to not defer smb3 session reconnect long after socket
+      reconnect
+    - cifs: dynamic allocation of ntlmssp blob
+    - File names with trailing period or space need special case conversion
+    - xen/acpi: allow xen-acpi-processor driver to load on Xen 4.7
+    - crypto: qat - make qat_asym_algs.o depend on asn1 headers
+    - tmpfs: don't undo fallocate past its last page
+    - tmpfs: fix regression hang in fallocate undo
+    - drm/i915: Revert DisplayPort fast link training feature
+    - ovl: verify upper dentry before unlink and rename
+    - Linux 4.4.16
+
+  * Regression caused by `fuse: Add support for pid namespaces` in 4.4.0-6.21
+    (LP: #1605344)
+    - SAUCE: (namespace) fuse: Permit requests from other pid namespaces
+
+  * CVE-2016-5400
+    - media: fix airspy usb probe error path
+
+  * Cannot mount proc in unprivileged containers if /proc/xen is mounted
+    (LP: #1607374)
+    - SAUCE: xenbus: Use proc_create_mount_point() to create /proc/xen
+
+  * Mic mute key does not work for Ideapad laptops (LP: #1607153)
+    - ideapad_laptop: Add an event for mic mute hotkey
+
+  * NVMe stress test fails after 12 hours on Ubuntu 16.04 (LP: #1604995)
+    - block: atari: Return early for unsupported sector size
+
+  * Console extremely slow with 4.4 kernels for servers with Matrox G200er2 or
+    similar (LP: #1605662)
+    - SAUCE: vesafb: Set mtrr:3 (write-combining) as default
+
+  * Ubuntu 16.04 - Full EEH Recovery Support for NVMe devices (LP: #1602724)
+    - nvme: use a work item to submit async event requests
+    - nvme: don't poll the CQ from the kthread
+    - nvme: replace the kthread with a per-device watchdog timer
+    - NVMe: Fix reset/remove race
+    - nvme: Avoid reset work on watchdog timer function during error recovery
+    - NVMe: Always use MSI/MSI-x interrupts
+
+  * [LTC-Test] - NMI watchdog Bug and call traces when trinity is executed.
+    (LP: #1602524)
+    - ext4: factor out determining of hole size
+    - ext4: return hole from ext4_map_blocks()
+    - ext4: more efficient SEEK_DATA implementation
+
+  * changelog: add CVEs as first class citizens (LP: #1604344)
+    - avoid duplicate CVE numbers in changelog
+
+  * [LTCTest][Opal][OP820] Machine crashed with Oops: Kernel access of bad area,
+    sig: 11 [#1] while executing Froze PE Error injection (LP: #1603449)
+    - powerpc/eeh: Fix invalid cached PE primary bus
+
+  * Hotplug remove and re-add adds PCI adapter to next PCI domain (PCI)
+    (LP: #1603574)
+    - powerpc/pci: Assign fixed PHB number based on device-tree properties
+
+  * nvme - reset_controller is not working after adapter's firmware upgrade
+    (adapter quirk is needed) (LP: #1602726)
+    - NVMe: Create discard zero quirk white list
+    - nvme/quirk: Add a delay before checking for adapter readiness
+
+  * ovs nat: conntrack netlink event are missing (LP: #1603468)
+    - openvswitch: fix conntrack netlink event delivery
+
+  * FlashGT - In Tuleta 8284-22A with card in card slot P1-C9, system Fails to
+    boot operating system (LP: #1602785)
+    - cxl: Ignore CAPI adapters misplaced in switched slots
+
+  * CVE-2016-5728
+    - misc: mic: Fix for double fetch security bug in VOP driver
+
+  * CVE-2016-5244 (LP: #1589041)
+    - rds: fix an infoleak in rds_inc_info_copy
+
+  * Miscellaneous Ubuntu changes
+    - Added Snapcraft files
+    - SAUCE: snapcraft: cleanup and remove unnecessary elements
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 09 Aug 2016 15:11:33 +0200
+
+linux (4.4.0-34.53) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1606960
+
+  * [APL][SAUCE] Slow system response time due to a monitor bug (LP: #1606147)
+    - x86/cpu/intel: Introduce macros for Intel family numbers
+    - SAUCE: x86/cpu: Add workaround for MONITOR instruction erratum on Goldmont
+      based CPUs
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 27 Jul 2016 10:01:20 -0500
+
+linux (4.4.0-33.52) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1605709
+
+  * [regression] NFS client: access problems after updating to kernel
+    4.4.0-31-generic (LP: #1603719)
+    - SAUCE: (namespace) Bypass sget() capability check for nfs
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 22 Jul 2016 13:10:08 -0500
+
+linux (4.4.0-32.51) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1604443
+
+  * thinkpad yoga 260 wacom touchscreen not working (LP: #1603975)
+    - HID: wacom: break out parsing of device and registering of input
+    - HID: wacom: Initialize hid_data.inputmode to -1
+    - HID: wacom: Support switching from vendor-defined device mode on G9 and G11
+
+  * changelog: add CVEs as first class citizens (LP: #1604344)
+    - use CVE numbers in changelog
+
+  * [Xenial] Include Huawei PCIe SSD hio kernel driver (LP: #1603483)
+    - SAUCE: import Huawei ES3000_V2 (2.1.0.23)
+    - SAUCE: hio: bio_endio() no longer takes errors arg
+    - SAUCE: hio: blk_queue make_request_fn now returns a blk_qc_t
+    - SAUCE: hio: use alloc_cpumask_var to avoid -Wframe-larger-than
+    - SAUCE: hio: fix mask maybe-uninitialized warning
+    - [config] enable CONFIG_HIO (Huawei ES3000_V2 PCIe SSD driver)
+    - SAUCE: hio: Makefile and Kconfig
+
+  * CVE-2016-5243 (LP: #1589036)
+    - tipc: fix an infoleak in tipc_nl_compat_link_dump
+    - tipc: fix nl compat regression for link statistics
+
+  * CVE-2016-4470
+    - KEYS: potential uninitialized variable
+
+  * integer overflow in xt_alloc_table_info (LP: #1555353)
+    - netfilter: x_tables: check for size overflow
+
+  * CVE-2016-3135:
+    - Revert "UBUNTU: SAUCE: (noup) netfilter: x_tables: check for size overflow"
+
+  * CVE-2016-4440 (LP: #1584192)
+    - kvm:vmx: more complete state update on APICv on/off
+
+  * the system hangs in the dma driver when reboot or shutdown on a baytrail-m
+    laptop (LP: #1602579)
+    - dmaengine: dw: platform: power on device on shutdown
+    - ACPI / LPSS: override power state for LPSS DMA device
+
+  * Add proper  palm detection support for MS Precision Touchpad (LP: #1593124)
+    - Revert "HID: multitouch: enable palm rejection if device implements
+      confidence usage"
+    - HID: multitouch: enable palm rejection for Windows Precision Touchpad
+
+  * Add support for Intel 8265 Bluetooth ([8087:0A2B]) (LP: #1599068)
+    - Bluetooth: Add support for Intel Bluetooth device 8265 [8087:0a2b]
+
+  * CVE-2016-4794 (LP: #1581871)
+    - percpu: fix synchronization between chunk->map_extend_work and chunk
+      destruction
+    - percpu: fix synchronization between synchronous map extension and chunk
+      destruction
+
+  * Xenial update to v4.4.15 stable release (LP: #1601952)
+    - net_sched: fix pfifo_head_drop behavior vs backlog
+    - net: Don't forget pr_fmt on net_dbg_ratelimited for CONFIG_DYNAMIC_DEBUG
+    - sit: correct IP protocol used in ipip6_err
+    - esp: Fix ESN generation under UDP encapsulation
+    - netem: fix a use after free
+    - ipmr/ip6mr: Initialize the last assert time of mfc entries.
+    - Bridge: Fix ipv6 mc snooping if bridge has no ipv6 address
+    - sock_diag: do not broadcast raw socket destruction
+    - bpf, perf: delay release of BPF prog after grace period
+    - neigh: Explicitly declare RCU-bh read side critical section in neigh_xmit()
+    - net: macb: fix default configuration for GMAC on AT91
+    - net: alx: Work around the DMA RX overflow issue
+    - bpf: try harder on clones when writing into skb
+    - AX.25: Close socket connection on session completion
+    - crypto: ux500 - memmove the right size
+    - crypto: user - re-add size check for CRYPTO_MSG_GETALG
+    - USB: uas: Fix slave queue_depth not being set
+    - usb: quirks: Fix sorting
+    - usb: quirks: Add no-lpm quirk for Acer C120 LED Projector
+    - usb: musb: only restore devctl when session was set in backup
+    - usb: musb: Stop bulk endpoint while queue is rotated
+    - usb: musb: Ensure rx reinit occurs for shared_fifo endpoints
+    - usb: musb: host: correct cppi dma channel for isoch transfer
+    - usb: xhci-plat: properly handle probe deferral for devm_clk_get()
+    - USB: xhci: Add broken streams quirk for Frescologic device id 1009
+    - xhci: Fix handling timeouted commands on hosts in weird states.
+    - USB: mos7720: delete parport
+    - usb: gadget: fix spinlock dead lock in gadgetfs
+    - usb: host: ehci-tegra: Grab the correct UTMI pads reset
+    - usb: dwc3: exynos: Fix deferred probing storm.
+    - Linux 4.4.15
+
+  * qeth: delete napi struct when removing a qeth device (LP: #1601831)
+    - qeth: delete napi struct when removing a qeth device
+
+  * Adjust KBL PCI-ID's (LP: #1600124)
+    - drm/i915: Add more Kabylake PCI IDs.
+    - drm/i915: Removing PCI IDs that are no longer listed as Kabylake.
+
+  * [i915_bpo] Rebase driver to v4.7-rc6 + gen9 workarounds + KBP PCH support
+    (LP: #1599109)
+    - drm/kms_helper: Add a common place to call init and exit functions.
+    - drm: Add helper for DP++ adaptors
+    - GPU-DRM: Delete unnecessary checks before drm_property_unreference_blob()
+    - drm: introduce pipe color correction properties
+    - drm: fix blob pointer check
+    - drm: atomic helper: do not unreference error pointer
+    - drm: fix lut value extraction function
+    - drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
+    - SAUCE: drm: Introduce drm_malloc_gfp()
+    - SAUCE: i915_bpo: Rebase to v4.7-rc6
+    - SAUCE: i915_bpo: Add backported workarounds for gen9
+    - SAUCE: i915_bpo: Revert "drm/i915: Get panel_type from OpRegion panel
+      details"
+    - SAUCE: i915_bpo: Introduce Kabypoint PCH for Kabylake H/DT.
+
+  * Baytrail-I got black screen with HDMI output (LP: #1599379)
+    - drm/i915: Only ignore eDP ports that are connected
+    - drm/i915: Check VBT for port presence in addition to the strap on VLV/CHV
+
+  * [Hyper-V] storvsc messages for CD-ROM medium not present tray closed
+    (LP: #1590655)
+    - SAUCE: (no-up) scsi: storvsc: Filter out storvsc messages CD-ROM medium not
+      present
+
+  * Hotplug device addition issue - missing patches on Xenial kernel
+    (LP: #1599250)
+    - Revert "UBUNTU: SAUCE: powerpc/eeh: Validate arch in eeh_add_device_early()"
+    - Revert "powerpc/eeh: Fix crash in eeh_add_device_early() on Cell"
+    - powerpc/iommu: Remove the dependency on EEH struct in DDW mechanism
+    - powerpc/pseries: Fix PCI config address for DDW
+
+  * kernel: signal return with invalid floating-point control (LP: #1597971)
+    - s390: fix test_fp_ctl inline assembly contraints
+
+  * [Toshiba P50W-B00F] Touchscreen no longer working (LP: #1498667)
+    - SAUCE: (no-up) usb: quirks: Add no-lpm quirk for Elan Microelectronics
+      Touchpad
+
+  * [yakkety] d-i does not support (ehci_msm) Qualcomm  On-Chip EHCI Host
+    Controller (LP: #1599347)
+    - d-i: Add ehci_msm to usb-modules
+
+  * [Bug] Legacy audio couldn't work after S3 resume on Kabylake (LP: #1596871)
+    - ALSA: hda - Skip ELD notification during PM process
+    - ALSA: hda - hdmi add wmb barrier for audio component
+    - ALSA: hda - hdmi defer to register acomp eld notifier
+
+  * sync spl  0.6.5.6-0ubuntu4 changes into Xenial kernel source (LP: #1599257)
+    - SAUCE: (noup) Update spl to 0.6.5.6-0ubuntu4
+
+  * Config: missing AMD Seattle platform support (LP: #1597574)
+    - [Config] Enable the AMD Seattle platform
+
+  * Network installer fails to detect network on AMD Overdrive (ARM64)
+    (LP: #1597573)
+    - [Config] Add amd-xgbe to nic-modules udeb
+
+  * exercising ptys causes a kernel oops (LP: #1586418)
+    - devpts: fix null pointer dereference on failed memory allocation
+
+  * Regression (constant vibration of device) in xpad driver in Ubuntu 16.04
+    (LP: #1574102)
+    - Input: xpad - move pending clear to the correct location
+
+  * thunderx nics fail to establish link (LP: #1597867)
+    - net: thunderx: Fix link status reporting
+
+  * Xenial update to v4.4.14 stable release (LP: #1596575)
+    - scsi_lib: correctly retry failed zero length REQ_TYPE_FS commands
+    - scsi: Add QEMU CD-ROM to VPD Inquiry Blacklist
+    - netlink: Fix dump skb leak/double free
+    - tipc: fix nametable publication field in nl compat
+    - switchdev: pass pointer to fib_info instead of copy
+    - tuntap: correctly wake up process during uninit
+    - udp: prevent skbs lingering in tunnel socket queues
+    - uapi glibc compat: fix compilation when !__USE_MISC in glibc
+    - sfc: on MC reset, clear PIO buffer linkage in TXQs
+    - team: don't call netdev_change_features under team->lock
+    - vxlan: Accept user specified MTU value when create new vxlan link
+    - tcp: record TLP and ER timer stats in v6 stats
+    - bridge: Don't insert unnecessary local fdb entry on changing mac address
+    - l2tp: fix configuration passed to setup_udp_tunnel_sock()
+    - ipv6: Skip XFRM lookup if dst_entry in socket cache is valid
+    - vxlan: Relax MTU constraints
+    - geneve: Relax MTU constraints
+    - vxlan, gre, geneve: Set a large MTU on ovs-created tunnel devices
+    - KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS
+    - KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi
+    - ALSA: hda - Add PCI ID for Kabylake
+    - ALSA: hda - Fix headset mic detection problem for Dell machine
+    - ALSA: hda/realtek - ALC256 speaker noise issue
+    - ALSA: hda/realtek - Add support for new codecs ALC700/ALC701/ALC703
+    - ALSA: hda/realtek: Add T560 docking unit fixup
+    - ARM: fix PTRACE_SETVFPREGS on SMP systems
+    - gpio: bcm-kona: fix bcm_kona_gpio_reset() warnings
+    - s390/bpf: fix recache skb->data/hlen for skb_vlan_push/pop
+    - s390/bpf: reduce maximum program size to 64 KB
+    - irqchip/gic-v3: Fix ICC_SGI1R_EL1.INTID decoding mask
+    - crypto: public_key: select CRYPTO_AKCIPHER
+    - crypto: ccp - Fix AES XTS error for request sizes above 4096
+    - arm64: Provide "model name" in /proc/cpuinfo for PER_LINUX32 tasks
+    - arm64: mm: always take dirty state from new pte in ptep_set_access_flags
+    - powerpc/pseries/eeh: Handle RTAS delay requests in configure_bridge
+    - powerpc: Fix definition of SIAR and SDAR registers
+    - powerpc: Use privileged SPR number for MMCR2
+    - powerpc/pseries: Add POWER8NVL support to ibm,client-architecture-support
+      call
+    - pinctrl: mediatek: fix dual-edge code defect
+    - parisc: Fix pagefault crash in unaligned __get_user() call
+    - memcg: add RCU locking around css_for_each_descendant_pre() in
+      memcg_offline_kmem()
+    - wext: Fix 32 bit iwpriv compatibility issue with 64 bit Kernel
+    - x86/entry/traps: Don't force in_interrupt() to return true in IST handlers
+    - fix d_walk()/non-delayed __d_free() race
+    - sparc: Fix system call tracing register handling.
+    - sparc64: Fix bootup regressions on some Kconfig combinations.
+    - sparc64: Fix numa node distance initialization
+    - sparc64: Fix sparc64_set_context stack handling.
+    - sparc/PCI: Fix for panic while enabling SR-IOV
+    - sparc64: Reduce TLB flushes during hugepte changes
+    - sparc64: Take ctx_alloc_lock properly in hugetlb_setup().
+    - sparc: Harden signal return frame checks.
+    - sparc64: Fix return from trap window fill crashes.
+    - MIPS: Fix 64k page support for 32 bit kernels.
+    - crypto: qat - fix adf_ctl_drv.c:undefined reference to adf_init_pf_wq
+    - drm/core: Do not preserve framebuffer on rmfb, v4.
+    - Linux 4.4.14
+
+  * [Hyper-V] Rebase Hyper-V to 4.6 kernel (LP: #1583357)
+    - hv_netvsc: rework link status change handling
+    - hv_netvsc: Resize some of the variables in hv_netvsc_packet
+    - hv_netvsc: Rearrange the hv_negtvsc_packet to be space efficient
+    - hv_netvsc: Eliminate the channel field in hv_netvsc_packet structure
+    - hv_netvsc: Eliminate rndis_msg pointer from hv_netvsc_packet structure
+    - hv_netvsc: Eliminatte the data field from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate send_completion from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate send_completion_ctx from struct hv_netvsc_packet
+    - hv_netvsc: Don't ask for additional head room in the skb
+    - hv_netvsc: move subchannel existence check to netvsc_select_queue()
+    - hv_netvsc: remove locking in netvsc_send()
+    - hv_netvsc: Eliminate page_buf from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate send_completion_tid from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate is_data_pkt from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate completion_func from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate xmit_more from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate status from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate vlan_tci from struct hv_netvsc_packet
+    - storvsc: add logging for error/warning messages
+    - hv_netvsc: Fix race condition on Multi-Send Data field
+    - kvm/x86: split ioapic-handled and EOI exit bitmaps
+    - kvm/x86: per-vcpu apicv deactivation support
+    - kvm/x86: Hyper-V synthetic interrupt controller
+    - kvm/x86: Hyper-V kvm exit
+    - kvm/x86: Rearrange func's declarations inside Hyper-V header
+    - kvm/x86: Added Hyper-V vcpu_to_hv_vcpu()/hv_vcpu_to_vcpu() helpers
+    - kvm/x86: Hyper-V internal helper to read MSR HV_X64_MSR_TIME_REF_COUNT
+    - kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack
+    - kvm/x86: Hyper-V SynIC timers
+    - storvsc: Fix a bug in the layout of the hv_fc_wwn_packet
+    - storvsc: Properly support Fibre Channel devices
+    - storvsc: Refactor the code in storvsc_channel_init()
+    - storvsc: Tighten up the interrupt path
+    - storvsc: Fix typo in MODULE_PARM_DESC
+    - Revert "hv_netvsc: use skb_get_hash() instead of a homegrown implementation"
+    - hv_netvsc: use skb_get_hash() instead of a homegrown implementation
+    - hv_netvsc: Fix book keeping of skb during batching process
+    - storvsc: Install the storvsc specific timeout handler for FC devices
+    - storvsc: Use the specified target ID in device lookup
+    - Revert "Drivers: hv: vmbus: Cleanup vmbus_set_event()"
+    - Drivers: hv: vmbus: Cleanup vmbus_set_event()
+    - Revert "Drivers: hv: vmbus: Eliminate the spin lock on the read path"
+    - Drivers: hv: vmbus: Eliminate the spin lock on the read path
+    - Revert "hv_netvsc: cleanup netdev feature flags for netvsc"
+    - hv_netvsc: cleanup netdev feature flags for netvsc
+    - hv_netvsc: Restore needed_headroom request
+    - kvm/x86: Rename Hyper-V long spin wait hypercall
+    - hv_netvsc: add software transmit timestamp support
+    - hv_netvsc: add ethtool support for set and get of settings
+    - hv_netvsc: Fix accessing freed memory in netvsc_change_mtu()
+    - hv_netvsc: Fix the array sizes to be max supported channels
+    - hv_netvsc: Fix the order of num_sc_offered decrement
+    - x86/hyperv: Avoid reporting bogus NMI status for Gen2 instances
+    - Drivers: hv: vmbus: Fix signaling logic in hv_need_to_signal_on_read()
+    - Drivers: hv: kvp: fix IP Failover
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 19 Jul 2016 11:18:32 -0500
+
+linux (4.4.0-31.50) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1602449
+
+  * nouveau: boot hangs at blank screen with unsupported graphics cards
+    (LP: #1602340)
+    - SAUCE: drm: check for supported chipset before booting fbdev off the hw
+
+ -- Kamal Mostafa <kamal@canonical.com>  Tue, 12 Jul 2016 16:28:12 -0700
+
+linux (4.4.0-30.49) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1597897
+
+  * FCP devices are not detected correctly nor deterministically (LP: #1567602)
+    - scsi_dh_alua: Disable ALUA handling for non-disk devices
+    - scsi_dh_alua: Use vpd_pg83 information
+    - scsi_dh_alua: improved logging
+    - scsi_dh_alua: sanitze sense code handling
+    - scsi_dh_alua: use standard logging functions
+    - scsi_dh_alua: return standard SCSI return codes in submit_rtpg
+    - scsi_dh_alua: fixup description of stpg_endio()
+    - scsi_dh_alua: use flag for RTPG extended header
+    - scsi_dh_alua: use unaligned access macros
+    - scsi_dh_alua: rework alua_check_tpgs() to return the tpgs mode
+    - scsi_dh_alua: simplify sense code handling
+    - scsi: Add scsi_vpd_lun_id()
+    - scsi: Add scsi_vpd_tpg_id()
+    - scsi_dh_alua: use scsi_vpd_tpg_id()
+    - scsi_dh_alua: Remove stale variables
+    - scsi_dh_alua: Pass buffer as function argument
+    - scsi_dh_alua: separate out alua_stpg()
+    - scsi_dh_alua: Make stpg synchronous
+    - scsi_dh_alua: call alua_rtpg() if stpg fails
+    - scsi_dh_alua: switch to scsi_execute_req_flags()
+    - scsi_dh_alua: allocate RTPG buffer separately
+    - scsi_dh_alua: Use separate alua_port_group structure
+    - scsi_dh_alua: use unique device id
+    - scsi_dh_alua: simplify alua_initialize()
+    - revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should
+      succeed while TPG is transitioning")
+    - scsi_dh_alua: move optimize_stpg evaluation
+    - scsi_dh_alua: remove 'rel_port' from alua_dh_data structure
+    - scsi_dh_alua: Use workqueue for RTPG
+    - scsi_dh_alua: Allow workqueue to run synchronously
+    - scsi_dh_alua: Add new blacklist flag 'BLIST_SYNC_ALUA'
+    - scsi_dh_alua: Recheck state on unit attention
+    - scsi_dh_alua: update all port states
+    - scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
+    - scsi_dh_alua: do not fail for unknown VPD identification
+
+ -- Kamal Mostafa <kamal@canonical.com>  Thu, 30 Jun 2016 12:52:15 -0700
+
+linux (4.4.0-29.48) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1597015
+
+  * Wireless hotkey fails on Dell XPS 15 9550 (LP: #1589886)
+    - intel-hid: new hid event driver for hotkeys
+    - intel-hid: fix incorrect entries in intel_hid_keymap
+    - intel-hid: allocate correct amount of memory for private struct
+    - intel-hid: add a workaround to ignore an event after waking up from S4.
+    - [Config] CONFIG_INTEL_HID_EVENT=m
+
+  * cgroupfs mounts can hang (LP: #1588056)
+    - Revert "UBUNTU: SAUCE: (namespace) mqueue: Super blocks must be owned by the
+      user ns which owns the ipc ns"
+    - Revert "UBUNTU: SAUCE: kernfs: Do not match superblock in another user
+      namespace when mounting"
+    - Revert "UBUNTU: SAUCE: cgroup: Use a new super block when mounting in a
+      cgroup namespace"
+    - (namespace) bpf: Use mount_nodev not mount_ns to mount the bpf filesystem
+    - (namespace) bpf, inode: disallow userns mounts
+    - (namespace) ipc: Initialize ipc_namespace->user_ns early.
+    - (namespace) vfs: Pass data, ns, and ns->userns to mount_ns
+    - SAUCE: (namespace) Sync with upstream s_user_ns patches
+    - (namespace) kernfs: The cgroup filesystem also benefits from SB_I_NOEXEC
+    - (namespace) ipc/mqueue: The mqueue filesystem should never contain
+      executables
+
+  * KVM system crashes after starting guest (LP: #1596635)
+    - xhci: Cleanup only when releasing primary hcd
+
+  * Upstream patch "crypto: vmx - IV size failing on skcipher API" for Ubuntu
+    16.04 (LP: #1596557)
+    - crypto: vmx - IV size failing on skcipher API
+
+  * [Bug]tpm initialization fails on x86 (LP: #1596469)
+    - tpm_crb: drop struct resource res from struct crb_priv
+    - tpm_crb: fix mapping of the buffers
+
+  * Device shutdown notification for CAPI Flash cards (LP: #1592114)
+    - cxlflash: Fix regression issue with re-ordering patch
+    - cxlflash: Fix to drain operations from previous reset
+    - cxlflash: Add device dependent flags
+    - cxlflash: Shutdown notify support for CXL Flash cards
+
+  * scsi-modules udeb should include pm80xx (LP: #1595628)
+    - [Config] Add pm80xx scsi driver to d-i
+
+  * Sync up latest relevant upstream bug fixes (LP: #1594871)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu10
+
+  * Cannot compile module tda10071 (LP: #1592531)
+    - [media] tda10071: Fix dependency to REGMAP_I2C
+
+  * lsvpd doesn't show correct location code for devices attached to a CAPI card
+    (LP: #1594847)
+    - cxl: Make vPHB device node match adapter's
+
+  * enable CRC32 and AES ARM64 by default or as module (LP: #1594455)
+    - [Config] Enable arm64 AES and CRC32 crypto
+
+  * VMX kernel crypto module exhibits poor performance in Ubuntu 16.04
+    (LP: #1592481)
+    - crypto: vmx - comply with ABIs that specify vrsave as reserved.
+    - crypto: vmx - Fix ABI detection
+    - crypto: vmx - Increase priority of aes-cbc cipher
+
+  * build squashfs into xenial kernels by default (LP: #1593134)
+    - [Config] CONFIG_SQUASHFS=y
+
+  * Restore irqfd fast path for PPC (LP: #1592809)
+    - KVM: PPC: Book3S HV: Re-enable XICS fast path for irqfd-generated interrupts
+
+  * Unable to start guests with memballoon default. (LP: #1592042)
+    - virtio_balloon: fix PFN format for virtio-1
+
+  * Key 5 automatically pressed on some Logitech wireless keyboards
+    (LP: #1579190)
+    - HID: core: prevent out-of-bound readings
+
+  * ZFS: Running ztest repeatedly for long periods of time eventually results in
+    "zdb: can't open 'ztest': No such file or directory" (LP: #1587686)
+    - Fix ztest truncated cache file
+
+  * STC840.20:Alpine:alp7fp1:Ubuntu 16.04, BlueFin (SAN) EEH 6 times during boot
+    then disabled SRC BA188002:b0314a_1612.840 (LP: #1587316)
+    - lpfc: Fix DMA faults observed upon plugging loopback connector
+
+ -- Kamal Mostafa <kamal@canonical.com>  Tue, 28 Jun 2016 10:17:41 -0700
+
+linux (4.4.0-28.47) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1595874
+
+  * Linux netfilter local privilege escalation issues (LP: #1595350)
+    - netfilter: x_tables: don't move to non-existent next rule
+    - netfilter: x_tables: validate targets of jumps
+    - netfilter: x_tables: add and use xt_check_entry_offsets
+    - netfilter: x_tables: kill check_entry helper
+    - netfilter: x_tables: assert minimum target size
+    - netfilter: x_tables: add compat version of xt_check_entry_offsets
+    - netfilter: x_tables: check standard target size too
+    - netfilter: x_tables: check for bogus target offset
+    - netfilter: x_tables: validate all offsets and sizes in a rule
+    - netfilter: x_tables: don't reject valid target size on some architectures
+    - netfilter: arp_tables: simplify translate_compat_table args
+    - netfilter: ip_tables: simplify translate_compat_table args
+    - netfilter: ip6_tables: simplify translate_compat_table args
+    - netfilter: x_tables: xt_compat_match_from_user doesn't need a retval
+    - netfilter: x_tables: do compat validation via translate_table
+    - netfilter: x_tables: introduce and use xt_copy_counters_from_user
+
+  * Linux netfilter IPT_SO_SET_REPLACE memory corruption (LP: #1555338)
+    - netfilter: x_tables: validate e->target_offset early
+    - netfilter: x_tables: make sure e->next_offset covers remaining blob size
+    - netfilter: x_tables: fix unconditional helper
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Fri, 24 Jun 2016 09:57:21 +0100
+
+linux (4.4.0-27.46) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1594906
+
+  * Support Edge Gateway's Bluetooth LED (LP: #1512999)
+    - Revert "UBUNTU: SAUCE: Bluetooth: Support for LED on Marvell modules"
+
+ -- Kamal Mostafa <kamal@canonical.com>  Tue, 21 Jun 2016 10:17:00 -0700
+
+linux (4.4.0-26.45) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1594442
+
+  * linux: Implement secure boot state variables (LP: #1593075)
+    - SAUCE: UEFI: Add secure boot and MOK SB State disabled sysctl
+
+  * failures building userspace packages that include ethtool.h (LP: #1592930)
+    - ethtool.h: define INT_MAX for userland
+
+ -- Kamal Mostafa <kamal@canonical.com>  Mon, 20 Jun 2016 09:43:47 -0700
+
+linux (4.4.0-25.44) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1591289
+
+  * Xenial update to v4.4.13 stable release (LP: #1590455)
+    - MIPS64: R6: R2 emulation bugfix
+    - MIPS: math-emu: Fix jalr emulation when rd == $0
+    - MIPS: MSA: Fix a link error on `_init_msa_upper' with older GCC
+    - MIPS: Don't unwind to user mode with EVA
+    - MIPS: Avoid using unwind_stack() with usermode
+    - MIPS: Fix siginfo.h to use strict posix types
+    - MIPS: Fix uapi include in exported asm/siginfo.h
+    - MIPS: Fix watchpoint restoration
+    - MIPS: Flush highmem pages in __flush_dcache_page
+    - MIPS: Handle highmem pages in __update_cache
+    - MIPS: Sync icache & dcache in set_pte_at
+    - MIPS: ath79: make bootconsole wait for both THRE and TEMT
+    - MIPS: Reserve nosave data for hibernation
+    - MIPS: Loongson-3: Reserve 32MB for RS780E integrated GPU
+    - MIPS: Use copy_s.fmt rather than copy_u.fmt
+    - MIPS: Fix MSA ld_*/st_* asm macros to use PTR_ADDU
+    - MIPS: Prevent "restoration" of MSA context in non-MSA kernels
+    - MIPS: Disable preemption during prctl(PR_SET_FP_MODE, ...)
+    - MIPS: ptrace: Fix FP context restoration FCSR regression
+    - MIPS: ptrace: Prevent writes to read-only FCSR bits
+    - MIPS: Fix sigreturn via VDSO on microMIPS kernel
+    - MIPS: Build microMIPS VDSO for microMIPS kernels
+    - MIPS: lib: Mark intrinsics notrace
+    - MIPS: VDSO: Build with `-fno-strict-aliasing'
+    - affs: fix remount failure when there are no options changed
+    - ASoC: ak4642: Enable cache usage to fix crashes on resume
+    - Input: uinput - handle compat ioctl for UI_SET_PHYS
+    - ARM: mvebu: fix GPIO config on the Linksys boards
+    - ARM: dts: at91: fix typo in sama5d2 PIN_PD24 description
+    - ARM: dts: exynos: Add interrupt line to MAX8997 PMIC on exynos4210-trats
+    - ARM: dts: imx35: restore existing used clock enumeration
+    - ath9k: Add a module parameter to invert LED polarity.
+    - ath9k: Fix LED polarity for some Mini PCI AR9220 MB92 cards.
+    - ath10k: fix debugfs pktlog_filter write
+    - ath10k: fix firmware assert in monitor mode
+    - ath10k: fix rx_channel during hw reconfigure
+    - ath10k: fix kernel panic, move arvifs list head init before htt init
+    - ath5k: Change led pin configuration for compaq c700 laptop
+    - hwrng: exynos - Fix unbalanced PM runtime put on timeout error path
+    - rtlwifi: rtl8723be: Add antenna select module parameter
+    - rtlwifi: btcoexist: Implement antenna selection
+    - rtlwifi: Fix logic error in enter/exit power-save mode
+    - rtlwifi: pci: use dev_kfree_skb_irq instead of kfree_skb in
+      rtl_pci_reset_trx_ring
+    - aacraid: Relinquish CPU during timeout wait
+    - aacraid: Fix for aac_command_thread hang
+    - aacraid: Fix for KDUMP driver hang
+    - hwmon: (ads7828) Enable internal reference
+    - mfd: intel-lpss: Save register context on suspend
+    - mfd: intel_soc_pmic_core: Terminate panel control GPIO lookup table
+      correctly
+    - PM / Runtime: Fix error path in pm_runtime_force_resume()
+    - cpuidle: Indicate when a device has been unregistered
+    - cpuidle: Fix cpuidle_state_is_coupled() argument in cpuidle_enter()
+    - clk: bcm2835: Fix PLL poweron
+    - clk: at91: fix check of clk_register() returned value
+    - clk: bcm2835: pll_off should only update CM_PLL_ANARST
+    - clk: bcm2835: divider value has to be 1 or more
+    - pinctrl: exynos5440: Use off-stack memory for pinctrl_gpio_range
+    - PCI: Disable all BAR sizing for devices with non-compliant BARs
+    - media: v4l2-compat-ioctl32: fix missing reserved field copy in
+      put_v4l2_create32
+    - mm: use phys_addr_t for reserve_bootmem_region() arguments
+    - wait/ptrace: assume __WALL if the child is traced
+    - QE-UART: add "fsl,t1040-ucc-uart" to of_device_id
+    - powerpc/book3s64: Fix branching to OOL handlers in relocatable kernel
+    - powerpc/eeh: Don't report error in eeh_pe_reset_and_recover()
+    - powerpc/eeh: Restore initial state in eeh_pe_reset_and_recover()
+    - xen/events: Don't move disabled irqs
+    - xen: use same main loop for counting and remapping pages
+    - sunrpc: fix stripping of padded MIC tokens
+    - drm/gma500: Fix possible out of bounds read
+    - drm/vmwgfx: Enable SVGA_3D_CMD_DX_SET_PREDICATION
+    - drm/vmwgfx: use vmw_cmd_dx_cid_check for query commands.
+    - drm/vmwgfx: Fix order of operation
+    - drm/amdgpu: use drm_mode_vrefresh() rather than mode->vrefresh
+    - drm/amdgpu: Fix hdmi deep color support.
+    - drm/i915/fbdev: Fix num_connector references in intel_fb_initial_config()
+    - drm/fb_helper: Fix references to dev->mode_config.num_connector
+    - drm/atomic: Verify connector->funcs != NULL when clearing states
+    - drm/i915: Don't leave old junk in ilk active watermarks on readout
+    - drm/imx: Match imx-ipuv3-crtc components using device node in platform data
+    - ext4: fix hang when processing corrupted orphaned inode list
+    - ext4: clean up error handling when orphan list is corrupted
+    - ext4: fix oops on corrupted filesystem
+    - ext4: address UBSAN warning in mb_find_order_for_block()
+    - ext4: silence UBSAN in ext4_mb_init()
+    - PM / sleep: Handle failures in device_suspend_late() consistently
+    - dma-debug: avoid spinlock recursion when disabling dma-debug
+    - scripts/package/Makefile: rpmbuild add support of RPMOPTS
+    - gcov: disable tree-loop-im to reduce stack usage
+    - xfs: disallow rw remount on fs with unknown ro-compat features
+    - xfs: Don't wrap growfs AGFL indexes
+    - xfs: xfs_iflush_cluster fails to abort on error
+    - xfs: fix inode validity check in xfs_iflush_cluster
+    - xfs: skip stale inodes in xfs_iflush_cluster
+    - xfs: print name of verifier if it fails
+    - xfs: handle dquot buffer readahead in log recovery correctly
+    - Linux 4.4.13
+
+  * 168c:001c [HP Compaq Presario C700 Notebook PC] Wireless led button doesn't
+    switch colors (LP: #972604)
+    - ath5k: Change led pin configuration for compaq c700 laptop
+
+  * Extended statistics from balloon for proper memory management (LP: #1587091)
+    - mm/page_alloc.c: calculate 'available' memory in a separate function
+    - virtio_balloon: export 'available' memory to balloon statistics
+
+  * CAPI: CGZIP AFU contexts do not receive interrupts after heavy afu
+    open/close (LP: #1588468)
+    - misc: cxl: use kobj_to_dev()
+    - cxl: Move common code away from bare-metal-specific files
+    - cxl: Move bare-metal specific code to specialized files
+    - cxl: Define process problem state area at attach time only
+    - cxl: Introduce implementation-specific API
+    - cxl: Rename some bare-metal specific functions
+    - cxl: Isolate a few bare-metal-specific calls
+    - cxl: Update cxl_irq() prototype
+    - cxl: IRQ allocation for guests
+    - powerpc: New possible return value from hcall
+    - cxl: New hcalls to support cxl adapters
+    - cxl: Separate bare-metal fields in adapter and AFU data structures
+    - cxlflash: Simplify PCI registration
+    - cxlflash: Unmap problem state area before detaching master context
+    - cxlflash: Split out context initialization
+    - cxlflash: Simplify attach path error cleanup
+    - cxlflash: Reorder user context initialization
+    - cxl: Add guest-specific code
+    - cxl: sysfs support for guests
+    - cxl: Support to flash a new image on the adapter from a guest
+    - cxl: Parse device tree and create cxl device(s) at boot
+    - cxl: Support the cxl kernel API from a guest
+    - cxl: Adapter failure handling
+    - cxl: Add tracepoints around the cxl hcall
+    - cxlflash: Use new cxl_pci_read_adapter_vpd() API
+    - cxl: Remove cxl_get_phys_dev() kernel API
+    - cxl: Ignore probes for virtual afu pci devices
+    - cxl: Poll for outstanding IRQs when detaching a context
+
+  * NVMe max_segments queue parameter gets set to 1 (LP: #1588449)
+    - nvme: set queue limits for the admin queue
+    - nvme: fix max_segments integer truncation
+    - block: fix blk_rq_get_max_sectors for driver private requests
+
+  * workaround cavium thunderx silicon erratum 23144 (LP: #1589704)
+    - irqchip/gicv3-its: numa: Enable workaround for Cavium thunderx erratum 23144
+
+  * Xenial update to v4.4.12 stable release (LP: #1588945)
+    - Btrfs: don't use src fd for printk
+    - perf/x86/intel/pt: Generate PMI in the STOP region as well
+    - perf/core: Fix perf_event_open() vs. execve() race
+    - perf test: Fix build of BPF and LLVM on older glibc libraries
+    - ext4: iterate over buffer heads correctly in move_extent_per_page()
+    - arm64: Fix typo in the pmdp_huge_get_and_clear() definition
+    - arm64: Ensure pmd_present() returns false after pmd_mknotpresent()
+    - arm64: Implement ptep_set_access_flags() for hardware AF/DBM
+    - arm64: Implement pmdp_set_access_flags() for hardware AF/DBM
+    - arm64: cpuinfo: Missing NULL terminator in compat_hwcap_str
+    - arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables
+    - kvm: arm64: Fix EC field in inject_abt64
+    - remove directory incorrectly tries to set delete on close on non-empty
+      directories
+    - fs/cifs: correctly to anonymous authentication via NTLMSSP
+    - fs/cifs: correctly to anonymous authentication for the LANMAN authentication
+    - fs/cifs: correctly to anonymous authentication for the NTLM(v1)
+      authentication
+    - fs/cifs: correctly to anonymous authentication for the NTLM(v2)
+      authentication
+    - asix: Fix offset calculation in asix_rx_fixup() causing slow transmissions
+    - ring-buffer: Use long for nr_pages to avoid overflow failures
+    - ring-buffer: Prevent overflow of size in ring_buffer_resize()
+    - crypto: caam - fix caam_jr_alloc() ret code
+    - crypto: talitos - fix ahash algorithms registration
+    - crypto: sun4i-ss - Replace spinlock_bh by spin_lock_irq{save|restore}
+    - clk: qcom: msm8916: Fix crypto clock flags
+    - sched/loadavg: Fix loadavg artifacts on fully idle and on fully loaded
+      systems
+    - mfd: omap-usb-tll: Fix scheduling while atomic BUG
+    - Input: pwm-beeper - fix - scheduling while atomic
+    - irqchip/gic: Ensure ordering between read of INTACK and shared data
+    - irqchip/gic-v3: Configure all interrupts as non-secure Group-1
+    - can: fix handling of unmodifiable configuration options
+    - mmc: mmc: Fix partition switch timeout for some eMMCs
+    - mmc: sdhci-acpi: Remove MMC_CAP_BUS_WIDTH_TEST for Intel controllers
+    - ACPI / osi: Fix an issue that acpi_osi=!* cannot disable ACPICA internal
+      strings
+    - dell-rbtn: Ignore ACPI notifications if device is suspended
+    - mmc: longer timeout for long read time quirk
+    - mmc: sdhci-pci: Remove MMC_CAP_BUS_WIDTH_TEST for Intel controllers
+    - Bluetooth: vhci: fix open_timeout vs. hdev race
+    - Bluetooth: vhci: purge unhandled skbs
+    - Bluetooth: vhci: Fix race at creating hci device
+    - mei: fix NULL dereferencing during FW initiated disconnection
+    - mei: amthif: discard not read messages
+    - mei: bus: call mei_cl_read_start under device lock
+    - USB: serial: mxuport: fix use-after-free in probe error path
+    - USB: serial: keyspan: fix use-after-free in probe error path
+    - USB: serial: quatech2: fix use-after-free in probe error path
+    - USB: serial: io_edgeport: fix memory leaks in attach error path
+    - USB: serial: io_edgeport: fix memory leaks in probe error path
+    - USB: serial: option: add support for Cinterion PH8 and AHxx
+    - USB: serial: option: add more ZTE device ids
+    - USB: serial: option: add even more ZTE device ids
+    - usb: gadget: f_fs: Fix EFAULT generation for async read operations
+    - usb: f_mass_storage: test whether thread is running before starting another
+    - usb: misc: usbtest: fix pattern tests for scatterlists.
+    - usb: gadget: udc: core: Fix argument of dev_err() in
+      usb_gadget_map_request()
+    - staging: comedi: das1800: fix possible NULL dereference
+    - KVM: x86: fix ordering of cr0 initialization code in vmx_cpu_reset
+    - MIPS: KVM: Fix timer IRQ race when freezing timer
+    - MIPS: KVM: Fix timer IRQ race when writing CP0_Compare
+    - KVM: x86: mask CPUID(0xD,0x1).EAX against host value
+    - xen/x86: actually allocate legacy interrupts on PV guests
+    - tty: vt, return error when con_startup fails
+    - TTY: n_gsm, fix false positive WARN_ON
+    - tty/serial: atmel: fix hardware handshake selection
+    - Fix OpenSSH pty regression on close
+    - serial: 8250_pci: fix divide error bug if baud rate is 0
+    - serial: 8250_mid: use proper bar for DNV platform
+    - serial: 8250_mid: recognize interrupt source in handler
+    - serial: samsung: Reorder the sequence of clock control when call
+      s3c24xx_serial_set_termios()
+    - locking,qspinlock: Fix spin_is_locked() and spin_unlock_wait()
+    - clk: bcm2835: add locking to pll*_on/off methods
+    - mcb: Fixed bar number assignment for the gdd
+    - ALSA: hda/realtek - New codecs support for ALC234/ALC274/ALC294
+    - ALSA: hda - Fix headphone noise on Dell XPS 13 9360
+    - ALSA: hda/realtek - Add support for ALC295/ALC3254
+    - ALSA: hda - Fix headset mic detection problem for one Dell machine
+    - IB/srp: Fix a debug kernel crash
+    - thunderbolt: Fix double free of drom buffer
+    - SIGNAL: Move generic copy_siginfo() to signal.h
+    - UBI: Fix static volume checks when Fastmap is used
+    - hpfs: fix remount failure when there are no options changed
+    - hpfs: implement the show_options method
+    - scsi: Add intermediate STARGET_REMOVE state to scsi_target_state
+    - Revert "scsi: fix soft lockup in scsi_remove_target() on module removal"
+    - kbuild: move -Wunused-const-variable to W=1 warning level
+    - Linux 4.4.12
+
+  * [Hyper-V] fixes for kdump when running on a VM (LP: #1588965)
+    - clocksource: Allow unregistering the watchdog
+
+  * net_admin apparmor denial when using Go (LP: #1465724)
+    - SAUCE: kernel: Add noaudit variant of ns_capable()
+    - SAUCE: net: Use ns_capable_noaudit() when determining net sysctl permissions
+
+  * [Hyper-V] Put tools/hv/lsvmbus in /usr/sbin (LP: #1585311)
+    - [Debian] Install lsvmbus in cloud tools
+    - SAUCE: tools/hv/lsvmbus -- convert to python3
+    - SAUCE: tools/hv/lsvmbus -- add manual page
+
+  * btrfs: file write crashes with false ENOSPC during snapshot creation since
+    kernel 4.4 - fix available (LP: #1584052)
+    - btrfs: Continue write in case of can_not_nocow
+
+  * boot stalls on USB detection errors (LP: #1437492)
+    - usb: core: hub: hub_port_init lock controller instead of bus
+
+  * [Bug]KNL:Spread MWAIT cache lines over all nodes (LP: #1585850)
+    - kernek/fork.c: allocate idle task for a CPU always on its local node
+
+  * [Hyper-V] PCI Passthrough kernel hang and explicit barriers (LP: #1581243)
+    - PCI: hv: Report resources release after stopping the bus
+    - PCI: hv: Add explicit barriers to config space access
+
+  * Kernel 4.2.X and 4.4.X - Fix USB3.0 link power management (LPM)
+    claim/release logic in USBFS (LP: #1577024)
+    - USB: leave LPM alone if possible when binding/unbinding interface drivers
+
+  * STC840.20:tuleta:tul516p01 panic after injecting Leaf EEH (LP: #1581034)
+    - NVMe: Fix namespace removal deadlock
+    - NVMe: Requeue requests on suspended queues
+    - NVMe: Move error handling to failed reset handler
+    - blk-mq: End unstarted requests on dying queue
+
+  * conflicting modules in udebs - arc4.ko (LP: #1582991)
+    - [Config] Remove arc4 from nic-modules
+
+  * CVE-2016-4482 (LP: #1578493)
+    - USB: usbfs: fix potential infoleak in devio
+
+  * mlx5_core kexec fail  (LP: #1585978)
+    - net/mlx5: Add pci shutdown callback
+
+  * backport fix for /proc/net issues with containers (LP: #1584953)
+    - netfilter: Set /proc/net entries owner to root in namespace
+
+  * CVE-2016-4951 (LP: #1585365)
+    - tipc: check nl sock before parsing nested attributes
+
+  * CVE-2016-4578 (LP: #1581866)
+    - ALSA: timer: Fix leak in events via snd_timer_user_ccallback
+    - ALSA: timer: Fix leak in events via snd_timer_user_tinterrupt
+
+  * CVE-2016-4569 (LP: #1580379)
+    - ALSA: timer: Fix leak in SNDRV_TIMER_IOCTL_PARAMS
+
+  * s390/pci: fix use after free in dma_init (LP: #1584828)
+    - s390/pci: fix use after free in dma_init
+
+  * s390/mm: fix asce_bits handling with dynamic pagetable levels (LP: #1584827)
+    - s390/mm: fix asce_bits handling with dynamic pagetable levels
+
+  * CAPI: CGZIP Wrong CAPI MMIO timeout (256usec desired but 1usec default
+    setting in cxl.ko driver) (LP: #1584066)
+    - powerpc: Define PVR value for POWER8NVL processor
+    - cxl: Configure the PSL for two CAPI ports on POWER8NVL
+    - cxl: Increase timeout for detection of AFU mmio hang
+
+  * ThunderX: soft lockup in cursor_timer_handler() (LP: #1574814)
+    - SAUCE: tty: vt: Fix soft lockup in fbcon cursor blink timer.
+
+  * debian.master/.../getabis bogus warnings "inconsistant compiler versions"
+    and "not a git repository" (LP: #1584890)
+    - [debian] getabis: Only git add $abidir if running in local repo
+    - [debian] getabis: Fix inconsistent compiler versions check
+
+  * Backport cxlflash patch related to EEH recovery into Xenial SRU stream
+    (LP: #1584935)
+    - cxlflash: Fix to resolve dead-lock during EEH recovery
+
+  * Xenial update to 4.4.11 stable release (LP: #1584912)
+    - decnet: Do not build routes to devices without decnet private data.
+    - route: do not cache fib route info on local routes with oif
+    - packet: fix heap info leak in PACKET_DIAG_MCLIST sock_diag interface
+    - net: sched: do not requeue a NULL skb
+    - bpf/verifier: reject invalid LD_ABS | BPF_DW instruction
+    - cdc_mbim: apply "NDP to end" quirk to all Huawei devices
+    - net: use skb_postpush_rcsum instead of own implementations
+    - vlan: pull on __vlan_insert_tag error path and fix csum correction
+    - openvswitch: use flow protocol when recalculating ipv6 checksums
+    - ipv4/fib: don't warn when primary address is missing if in_dev is dead
+    - net/mlx4_en: fix spurious timestamping callbacks
+    - bpf: fix check_map_func_compatibility logic
+    - samples/bpf: fix trace_output example
+    - net: Implement net_dbg_ratelimited() for CONFIG_DYNAMIC_DEBUG case
+    - gre: do not pull header in ICMP error processing
+    - net_sched: introduce qdisc_replace() helper
+    - net_sched: update hierarchical backlog too
+    - sch_htb: update backlog as well
+    - sch_dsmark: update backlog as well
+    - netem: Segment GSO packets on enqueue
+    - net: fec: only clear a queue's work bit if the queue was emptied
+    - VSOCK: do not disconnect socket when peer has shutdown SEND only
+    - net: bridge: fix old ioctl unlocked net device walk
+    - bridge: fix igmp / mld query parsing
+    - uapi glibc compat: fix compile errors when glibc net/if.h included before
+      linux/if.h MIME-Version: 1.0
+    - net: fix a kernel infoleak in x25 module
+    - net: thunderx: avoid exposing kernel stack
+    - tcp: refresh skb timestamp at retransmit time
+    - net/route: enforce hoplimit max value
+    - ocfs2: revert using ocfs2_acl_chmod to avoid inode cluster lock hang
+    - ocfs2: fix posix_acl_create deadlock
+    - zsmalloc: fix zs_can_compact() integer overflow
+    - crypto: qat - fix invalid pf2vf_resp_wq logic
+    - crypto: hash - Fix page length clamping in hash walk
+    - crypto: testmgr - Use kmalloc memory for RSA input
+    - ALSA: usb-audio: Quirk for yet another Phoenix Audio devices (v2)
+    - ALSA: usb-audio: Yet another Phoneix Audio device quirk
+    - ALSA: hda - Fix subwoofer pin on ASUS N751 and N551
+    - ALSA: hda - Fix white noise on Asus UX501VW headset
+    - ALSA: hda - Fix broken reconfig
+    - spi: pxa2xx: Do not detect number of enabled chip selects on Intel SPT
+    - spi: spi-ti-qspi: Fix FLEN and WLEN settings if bits_per_word is overridden
+    - spi: spi-ti-qspi: Handle truncated frames properly
+    - pinctrl: at91-pio4: fix pull-up/down logic
+    - regmap: spmi: Fix regmap_spmi_ext_read in multi-byte case
+    - perf/core: Disable the event on a truncated AUX record
+    - vfs: add vfs_select_inode() helper
+    - vfs: rename: check backing inode being equal
+    - ARM: dts: at91: sam9x5: Fix the memory range assigned to the PMC
+    - workqueue: fix rebind bound workers warning
+    - regulator: s2mps11: Fix invalid selector mask and voltages for buck9
+    - regulator: axp20x: Fix axp22x ldo_io voltage ranges
+    - atomic_open(): fix the handling of create_error
+    - qla1280: Don't allocate 512kb of host tags
+    - tools lib traceevent: Do not reassign parg after collapse_tree()
+    - get_rock_ridge_filename(): handle malformed NM entries
+    - Input: max8997-haptic - fix NULL pointer dereference
+    - Revert "[media] videobuf2-v4l2: Verify planes array in buffer dequeueing"
+    - drm/radeon: fix PLL sharing on DCE6.1 (v2)
+    - drm/i915: Bail out of pipe config compute loop on LPT
+    - drm/i915/bdw: Add missing delay during L3 SQC credit programming
+    - drm/radeon: fix DP link training issue with second 4K monitor
+    - nf_conntrack: avoid kernel pointer value leak in slab name
+    - Linux 4.4.11
+
+  * Support Edge Gateway's Bluetooth LED (LP: #1512999)
+    - SAUCE: Bluetooth: Support for LED on Marvell modules
+
+  * Support Edge Gateway's WIFI LED (LP: #1512997)
+    - SAUCE: mwifiex: Switch WiFi LED state according to the device status
+
+  * Marvell wireless driver update for FCC regulation (LP: #1528910)
+    - mwifiex: parse adhoc start/join result
+    - mwifiex: handle start AP error paths correctly
+    - mwifiex: set regulatory info from EEPROM
+    - mwifiex: don't follow AP if country code received from EEPROM
+    - mwifiex: correction in region code to country mapping
+    - mwifiex: update region_code_index array
+    - mwifiex: use world for unidentified region code
+    - SAUCE: mwifiex: add iw vendor command support
+
+  * Kernel can be oopsed using remap_file_pages (LP: #1558120)
+    - Revert "UBUNTU: SAUCE: mm/mmap: fix oopsing on remap_file_pages"
+    - SAUCE: AUFS: mm/mmap: fix oopsing on remap_file_pages aufs mmap: bugfix,
+      mainly for linux-4.5-rc5, remap_file_pages(2) emulation
+
+  * cgroup namespace update (LP: #1584163)
+    - Revert "UBUNTU: SAUCE: cgroup mount: ignore nsroot="
+    - Revert "UBUNTU: SAUCE: (noup) cgroup namespaces: add a 'nsroot=' mountinfo
+      field"
+    - cgroup, kernfs: make mountinfo show properly scoped path for cgroup
+      namespaces
+    - kernfs: kernfs_sop_show_path: don't return 0 after seq_dentry call
+    - cgroup: fix compile warning
+
+  * Missing libunwind support in perf (LP: #1248289)
+    - [Config] add binutils-dev to the Build-Depends: to fix perf unwinding
+
+  * e1000 Tx Unit Hang  (LP: #1582328)
+    - e1000: Double Tx descriptors needed check for 82544
+    - e1000: Do not overestimate descriptor counts in Tx pre-check
+
+  * Unsharing user and ipc namespaces simultaneously makes mqueue unmountable
+    (LP: #1582378)
+    - SAUCE: (namespace) mqueue: Super blocks must be owned by the user ns which
+      owns the ipc ns
+
+  * Pull in the amdgpu/radeon code from Linux 4.5.3 (LP: #1580526)
+    - drm/radeon: rework fbdev handling on chips with no connectors
+    - drm/radeon/mst: fix regression in lane/link handling.
+    - drm/amd/powerplay: add uvd/vce dpm enabling flag to fix the performance
+      issue for CZ
+    - drm/amd/powerplay: fix segment fault issue in multi-display case.
+    - drm/ttm: fix kref count mess in ttm_bo_move_to_lru_tail
+
+  * aufs CONFIG_AUFS_EXPORT build option should be enabled (LP: #1121699)
+    - [Config] enable CONFIG_AUFS_EXPORT
+
+  * promote *_diag modules from linux-image-extra to linux-image (LP: #1580355)
+    - [Config] Update inclusion list for CRIU
+
+  * [Xenial] net: updates to ethtool and virtio_net for speed/duplex support
+    (LP: #1581132)
+    - ethtool: add speed/duplex validation functions
+    - ethtool: make validate_speed accept all speeds between 0 and INT_MAX
+    - virtio_net: add ethtool support for set and get of settings
+    - virtio_net: validate ethtool port setting and explain the user validation
+
+  * perf tool: Display event codes for Generic HW (PMU) events (LP: #1578211)
+    - powerpc/perf: Remove PME_ prefix for power7 events
+    - powerpc/perf: Export Power8 generic and cache events to sysfs
+
+  * Mellanox ConnectX4 MTU limits: max and min (LP: #1528466)
+    - net/mlx5: Introduce a new header file for physical port functions
+    - net/mlx5e: Device's mtu field is u16 and not int
+    - net/mlx5e: Fix minimum MTU
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_CAVIUM_ERRATUM_23144=y
+
+ -- Kamal Mostafa <kamal@canonical.com>  Fri, 10 Jun 2016 10:07:13 -0700
+
+linux (4.4.0-24.43) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * CVE-2016-1583 (LP: #1588871)
+    - ecryptfs: fix handling of directory opening
+    - SAUCE: proc: prevent stacking filesystems on top
+    - SAUCE: ecryptfs: forbid opening files without mmap handler
+    - SAUCE: sched: panic on corrupted stack end
+
+  * arm64: statically link rtc-efi (LP: #1583738)
+    - [Config] Link rtc-efi statically on arm64
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 08 Jun 2016 20:01:12 +0100
+
+linux (4.4.0-23.41) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1582431
+
+  * zfs: disable module checks for zfs when cross-compiling (LP: #1581127)
+    - [Packaging] disable zfs module checks when cross-compiling
+
+  * Xenial update to v4.4.10 stable release (LP: #1580754)
+    - Revert "UBUNTU: SAUCE: (no-up) ACPICA: Dispatcher: Update thread ID for
+      recursive method calls"
+    - Revert "UBUNTU: SAUCE: nbd: ratelimit error msgs after socket close"
+    - Revert: "powerpc/tm: Check for already reclaimed tasks"
+    - RDMA/iw_cxgb4: Fix bar2 virt addr calculation for T4 chips
+    - ipvs: handle ip_vs_fill_iph_skb_off failure
+    - ipvs: correct initial offset of Call-ID header search in SIP persistence
+      engine
+    - ipvs: drop first packet to redirect conntrack
+    - mfd: intel-lpss: Remove clock tree on error path
+    - nbd: ratelimit error msgs after socket close
+    - ata: ahci_xgene: dereferencing uninitialized pointer in probe
+    - mwifiex: fix corner case association failure
+    - CNS3xxx: Fix PCI cns3xxx_write_config()
+    - clk-divider: make sure read-only dividers do not write to their register
+    - soc: rockchip: power-domain: fix err handle while probing
+    - clk: rockchip: free memory in error cases when registering clock branches
+    - clk: meson: Fix meson_clk_register_clks() signature type mismatch
+    - clk: qcom: msm8960: fix ce3_core clk enable register
+    - clk: versatile: sp810: support reentrance
+    - clk: qcom: msm8960: Fix ce3_src register offset
+    - lpfc: fix misleading indentation
+    - ath9k: ar5008_hw_cmn_spur_mitigate: add missing mask_m & mask_p
+      initialisation
+    - mac80211: fix statistics leak if dev_alloc_name() fails
+    - tracing: Don't display trigger file for events that can't be enabled
+    - MD: make bio mergeable
+    - Minimal fix-up of bad hashing behavior of hash_64()
+    - mm, cma: prevent nr_isolated_* counters from going negative
+    - mm/zswap: provide unique zpool name
+    - ARM: EXYNOS: Properly skip unitialized parent clock in power domain on
+    - ARM: SoCFPGA: Fix secondary CPU startup in thumb2 kernel
+    - xen: Fix page <-> pfn conversion on 32 bit systems
+    - xen/balloon: Fix crash when ballooning on x86 32 bit PAE
+    - xen/evtchn: fix ring resize when binding new events
+    - HID: wacom: Add support for DTK-1651
+    - HID: Fix boot delay for Creative SB Omni Surround 5.1 with quirk
+    - Input: zforce_ts - fix dual touch recognition
+    - proc: prevent accessing /proc/<PID>/environ until it's ready
+    - mm: update min_free_kbytes from khugepaged after core initialization
+    - batman-adv: fix DAT candidate selection (must use vid)
+    - batman-adv: Check skb size before using encapsulated ETH+VLAN header
+    - batman-adv: Fix broadcast/ogm queue limit on a removed interface
+    - batman-adv: Reduce refcnt of removed router when updating route
+    - writeback: Fix performance regression in wb_over_bg_thresh()
+    - MAINTAINERS: Remove asterisk from EFI directory names
+    - x86/tsc: Read all ratio bits from MSR_PLATFORM_INFO
+    - ARM: cpuidle: Pass on arm_cpuidle_suspend()'s return value
+    - ARC: Add missing io barriers to io{read,write}{16,32}be()
+    - x86/sysfb_efi: Fix valid BAR address range check
+    - ACPICA: Dispatcher: Update thread ID for recursive method calls
+    - powerpc: Fix bad inline asm constraint in create_zero_mask()
+    - libahci: save port map for forced port map
+    - ata: ahci-platform: Add ports-implemented DT bindings.
+    - USB: serial: cp210x: add ID for Link ECU
+    - USB: serial: cp210x: add Straizona Focusers device ids
+    - nvmem: mxs-ocotp: fix buffer overflow in read
+    - gpu: ipu-v3: Fix imx-ipuv3-crtc module autoloading
+    - drm/amdgpu: make sure vertical front porch is at least 1
+    - drm/amdgpu: set metadata pointer to NULL after freeing.
+    - iio: ak8975: Fix NULL pointer exception on early interrupt
+    - iio: ak8975: fix maybe-uninitialized warning
+    - drm/radeon: make sure vertical front porch is at least 1
+    - drm/i915/ddi: Fix eDP VDD handling during booting and suspend/resume
+    - drm/i915: Fix eDP low vswing for Broadwell
+    - drm/i915: Make RPS EI/thresholds multiple of 25 on SNB-BDW
+    - drm/i915: Fake HDMI live status
+    - lib/test-string_helpers.c: fix and improve string_get_size() tests
+    - drm/i915/skl: Fix DMC load on Skylake J0 and K0
+    - Linux 4.4.10
+
+  * HDMI audio playback noise  observed on AMD Polaris 10/11 GPU (LP: #1577288)
+    - ALSA: hda: add AMD Polaris-10/11 AZ PCI IDs with proper driver caps
+
+  * [i915_bpo] Update i915 backport driver (LP: #1580114)
+    - SAUCE: i915_bpo: Drop is_preliminary from BXT/KBL.
+    - SAUCE: i915_bpo: Sync with v4.6-rc7
+
+  * CVE-2016-4486 (LP: #1578497)
+    - net: fix infoleak in rtnetlink
+
+  * CVE-2016-4485 (LP: #1578496)
+    - net: fix infoleak in llc
+
+  * drm.ko < kernel version 4.5 has a dead lock bug (LP: #1579610)
+    - drm: Balance error path for GEM handle allocation
+
+  * Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: -fstack-protector-strong not
+    supported by compiler (LP: #1574982)
+    - SAUCE: (no-up) disable -pie when gcc has it enabled by default
+
+  * system freeze after vt switching (LP: #1542939)
+    - drm/atomic: Add __drm_atomic_helper_connector_reset, v2.
+    - drm/atomic: Remove drm_atomic_connectors_for_crtc.
+
+  * CVE-2016-4558 (LP: #1579140)
+    - bpf: fix refcnt overflow
+
+  * Kernel Panic on EC2 After Upgrading from 14.04 to 16.04 via do-release-
+    upgrade -d (LP: #1573231)
+    - SAUCE: (no-up) x86/topology: Handle CPUID bogosity gracefully
+
+  * PCI Call Traces  hw csum failure in dmesg with  4.4.0-2-generic
+    (LP: #1544978)
+    - net/mlx4_en: Fix endianness bug in IPV6 csum calculation
+
+  * Missing libunwind support in perf (LP: #1248289)
+    - [Config] Add liblzma-dev to enable libunwind support in perf
+
+  * thunderbolt hotplug is broken (LP: #1577898)
+    - SAUCE: (no-up) ACPICA: Dispatcher: Update thread ID for recursive method
+      calls
+
+  * Kernel can be oopsed using remap_file_pages (LP: #1558120)
+    - SAUCE: mm/mmap: fix oopsing on remap_file_pages
+
+  * ZFS is confused by user namespaces (uid/gid mapping) when used with
+    acltype=posixac (LP: #1567558)
+    - zfs: Fix user namespaces uid/gid mapping
+
+  * oops when propagating mounts into containers - RIP:
+    0010:[<ffffffff8123cb3e>] [<ffffffff8123cb3e>] propagate_one+0xbe/0x1c0
+    (LP: #1572316)
+    - fs/pnode.c: treat zero mnt_group_id-s as unequal
+    - propogate_mnt: Handle the first propogated copy being a slave
+
+  * OOPS on wily+ for Haswell-ULT and Broadwell (LP: #1577748)
+    - PNP: Add Broadwell to Intel MCH size workaround
+    - PNP: Add Haswell-ULT to Intel MCH size workaround
+
+  * Xenial update to v4.4.9 stable release (LP: #1578798)
+    - block: loop: fix filesystem corruption in case of aio/dio
+    - x86/mce: Avoid using object after free in genpool
+    - kvm: x86: do not leak guest xcr0 into host interrupt handlers
+    - ARM: dts: AM43x-epos: Fix clk parent for synctimer
+    - ARM: mvebu: Correct unit address for linksys
+    - ARM: OMAP2: Fix up interconnect barrier initialization for DRA7
+    - ARM: OMAP2+: hwmod: Fix updating of sysconfig register
+    - assoc_array: don't call compare_object() on a node
+    - usb: xhci: applying XHCI_PME_STUCK_QUIRK to Intel BXT B0 host
+    - xhci: resume USB 3 roothub first
+    - usb: xhci: fix wild pointers in xhci_mem_cleanup
+    - xhci: fix 10 second timeout on removal of PCI hotpluggable xhci controllers
+    - usb: hcd: out of bounds access in for_each_companion
+    - usb: gadget: f_fs: Fix use-after-free
+    - dm cache metadata: fix READ_LOCK macros and cleanup WRITE_LOCK macros
+    - dm cache metadata: fix cmd_read_lock() acquiring write lock
+    - lib: lz4: fixed zram with lz4 on big endian machines
+    - debugfs: Make automount point inodes permanently empty
+    - dmaengine: dw: fix master selection
+    - dmaengine: hsu: correct use of channel status register
+    - dmaengine: pxa_dma: fix the maximum requestor line
+    - sched/cgroup: Fix/cleanup cgroup teardown/init
+    - x86/mm/xen: Suppress hugetlbfs in PV guests
+    - x86 EDAC, sb_edac.c: Repair damage introduced when "fixing" channel address
+    - ALSA: hda - Don't trust the reported actual power state
+    - ALSA: hda/realtek - Add ALC3234 headset mode for Optiplex 9020m
+    - ALSA: hda - Keep powering up ADCs on Cirrus codecs
+    - ALSA: hda - add PCI ID for Intel Broxton-T
+    - ALSA: pcxhr: Fix missing mutex unlock
+    - ALSA: hda - Add dock support for ThinkPad X260
+    - asm-generic/futex: Re-enable preemption in futex_atomic_cmpxchg_inatomic()
+    - futex: Handle unlock_pi race gracefully
+    - futex: Acknowledge a new waiter in counter before plist
+    - drm/nouveau/core: use vzalloc for allocating ramht
+    - drm/qxl: fix cursor position with non-zero hotspot
+    - drm/i915: Fix race condition in intel_dp_destroy_mst_connector()
+    - Revert "drm/radeon: disable runtime pm on PX laptops without dGPU power
+      control"
+    - Revert "drm/amdgpu: disable runtime pm on PX laptops without dGPU power
+      control"
+    - cpufreq: intel_pstate: Fix processing for turbo activation ratio
+    - iwlwifi: pcie: lower the debug level for RSA semaphore access
+    - iwlwifi: mvm: fix memory leak in paging
+    - crypto: ccp - Prevent information leakage on export
+    - crypto: sha1-mb - use corrcet pointer while completing jobs
+    - crypto: talitos - fix crash in talitos_cra_init()
+    - crypto: talitos - fix AEAD tcrypt tests
+    - powerpc: scan_features() updates incorrect bits for REAL_LE
+    - powerpc: Update cpu_user_features2 in scan_features()
+    - powerpc: Update TM user feature bits in scan_features()
+    - nl80211: check netlink protocol in socket release notification
+    - netlink: don't send NETLINK_URELEASE for unbound sockets
+    - Input: pmic8xxx-pwrkey - fix algorithm for converting trigger delay
+    - xen kconfig: don't "select INPUT_XEN_KBDDEV_FRONTEND"
+    - pinctrl: mediatek: correct debounce time unit in mtk_gpio_set_debounce
+    - pinctrl: single: Fix pcs_parse_bits_in_pinctrl_entry to use __ffs than ffs
+    - iommu/amd: Fix checking of pci dma aliases
+    - iommu/dma: Restore scatterlist offsets correctly
+    - drm/amdgpu: when suspending, if uvd/vce was running. need to cancel delay
+      work.
+    - drm/amdgpu: use defines for CRTCs and AMFT blocks
+    - drm/amdgpu: bump the afmt limit for CZ, ST, Polaris
+    - amdgpu/uvd: add uvd fw version for amdgpu
+    - drm/amdgpu: fix regression on CIK (v2)
+    - drm/radeon: add a quirk for a XFX R9 270X
+    - drm/radeon: fix initial connector audio value
+    - drm/radeon: forbid mapping of userptr bo through radeon device file
+    - drm/radeon: fix vertical bars appear on monitor (v2)
+    - drm: Loongson-3 doesn't fully support wc memory
+    - drm/nouveau/gr/gf100: select a stream master to fixup tfb offset queries
+    - drm/dp/mst: Validate port in drm_dp_payload_send_msg()
+    - drm/dp/mst: Restore primary hub guid on resume
+    - drm/dp/mst: Get validated port ref in drm_dp_update_payload_part1()
+    - pwm: brcmstb: Fix check of devm_ioremap_resource() return code
+    - drm/i915: Cleanup phys status page too
+    - drm/i915: skl_update_scaler() wants a rotation bitmask instead of bit number
+    - drm/amdkfd: uninitialized variable in dbgdev_wave_control_set_registers()
+    - drm/i915: Fixup the free space logic in ring_prepare
+    - drm/i915: Use fw_domains_put_with_fifo() on HSW
+    - perf intel-pt: Fix segfault tracing transactions
+    - i2c: cpm: Fix build break due to incompatible pointer types
+    - i2c: exynos5: Fix possible ABBA deadlock by keeping I2C clock prepared
+    - toshiba_acpi: Fix regression caused by hotkey enabling value
+    - EDAC: i7core, sb_edac: Don't return NOTIFY_BAD from mce_decoder callback
+    - ASoC: s3c24xx: use const snd_soc_component_driver pointer
+    - ASoC: ssm4567: Reset device before regcache_sync()
+    - ASoC: dapm: Make sure we have a card when displaying component widgets
+    - ASoC: rt5640: Correct the digital interface data select
+    - vb2-memops: Fix over allocation of frame vectors
+    - v4l2-dv-timings.h: fix polarity for 4k formats
+    - cxl: Keep IRQ mappings on context teardown
+    - IB/mlx5: Expose correct max_sge_rd limit
+    - IB/security: Restrict use of the write() interface
+    - efi: Fix out-of-bounds read in variable_matches()
+    - efi: Expose non-blocking set_variable() wrapper to efivars
+    - x86/apic: Handle zero vector gracefully in clear_vector_irq()
+    - workqueue: fix ghost PENDING flag while doing MQ IO
+    - slub: clean up code for kmem cgroup support to kmem_cache_free_bulk
+    - cgroup, cpuset: replace cpuset_post_attach_flush() with
+      cgroup_subsys->post_attach callback
+    - memcg: relocate charge moving from ->attach to ->post_attach
+    - mm/huge_memory: replace VM_NO_THP VM_BUG_ON with actual VMA check
+    - numa: fix /proc/<pid>/numa_maps for THP
+    - mm: vmscan: reclaim highmem zone if buffer_heads is over limit
+    - mm/hwpoison: fix wrong num_poisoned_pages accounting
+    - cgroup: make sure a parent css isn't freed before its children
+    - videobuf2-core: Check user space planes array in dqbuf
+    - videobuf2-v4l2: Verify planes array in buffer dequeueing
+    - Revert "regulator: core: Fix nested locking of supplies"
+    - regulator: core: fix regulator_lock_supply regression
+    - regulator: core: Ensure we lock all regulators
+    - regulator: core: Fix nested locking of supplies
+    - locking/mcs: Fix mcs_spin_lock() ordering
+    - spi/rockchip: Make sure spi clk is on in rockchip_spi_set_cs
+    - irqchip/sunxi-nmi: Fix error check of of_io_request_and_map()
+    - irqchip/mxs: Fix error check of of_io_request_and_map()
+    - regulator: s5m8767: fix get_register() error handling
+    - paride: make 'verbose' parameter an 'int' again
+    - scsi_dh: force modular build if SCSI is a module
+    - fbdev: da8xx-fb: fix videomodes of lcd panels
+    - misc/bmp085: Enable building as a module
+    - misc: mic/scif: fix wrap around tests
+    - PM / OPP: Initialize u_volt_min/max to a valid value
+    - PM / Domains: Fix removal of a subdomain
+    - rtc: hym8563: fix invalid year calculation
+    - rtc: vr41xx: Wire up alarm_irq_enable
+    - rtc: ds1685: passing bogus values to irq_restore
+    - rtc: rx8025: remove rv8803 id
+    - rtc: max77686: Properly handle regmap_irq_get_virq() error code
+    - drivers/misc/ad525x_dpot: AD5274 fix RDAC read back errors
+    - perf evlist: Reference count the cpu and thread maps at set_maps()
+    - x86/mm/kmmio: Fix mmiotrace for hugepages
+    - ext4: fix NULL pointer dereference in ext4_mark_inode_dirty()
+    - serial: sh-sci: Remove cpufreq notifier to fix crash/deadlock
+    - mtd: spi-nor: remove micron_quad_enable()
+    - mtd: brcmnand: Fix v7.1 register offsets
+    - mtd: nand: Drop mtd.owner requirement in nand_scan
+    - perf hists browser: Only offer symbol scripting when a symbol is under the
+      cursor
+    - perf tools: handle spaces in file names obtained from /proc/pid/maps
+    - perf stat: Document --detailed option
+    - ext4: fix races between page faults and hole punching
+    - ext4: move unlocked dio protection from ext4_alloc_file_blocks()
+    - ext4: fix races between buffered IO and collapse / insert range
+    - ext4: fix races of writeback with punch hole and zero range
+    - ARM: OMAP3: Add cpuidle parameters table for omap3430
+    - ARM: prima2: always enable reset controller
+    - ARM: EXYNOS: select THERMAL_OF
+    - ARM: dts: armada-375: use armada-370-sata for SATA
+    - ARM: dts: pxa: fix dma engine node to pxa3xx-nand
+    - bus: imx-weim: Take the 'status' property value into account
+    - jme: Do not enable NIC WoL functions on S0
+    - jme: Fix device PM wakeup API usage
+    - unbreak allmodconfig KCONFIG_ALLCONFIG=...
+    - thermal: rockchip: fix a impossible condition caused by the warning
+    - sunrpc/cache: drop reference when sunrpc_cache_pipe_upcall() detects a race
+    - megaraid_sas: add missing curly braces in ioctl handler
+    - stm class: Select CONFIG_SRCU
+    - extcon: max77843: Use correct size for reading the interrupt register
+    - Linux 4.4.9
+
+  * Stoney powerplay support (LP: #1578305)
+    - amdgpu/powerplay: Add Stoney to list of early init cases
+
+  * CVE-2016-2117 (LP: #1561403)
+    - atl2: Disable unimplemented scatter/gather feature
+
+  * CVE-2016-2187 (LP: #1575706)
+    - Input: gtco - fix crash on detecting device without endpoints
+
+  * zfs posix default permissions lost on reboot or unmount (LP: #1574801)
+    - Fix ZPL miswrite of default POSIX ACL
+
+  * WARNING: at /build/linux-aWXT0l/linux-4.4.0/drivers/pci/pci.c:1595
+    [travis3EN] (LP: #1574697)
+    - net/mlx4_core: Implement pci_resume callback
+    - net/mlx4_core: Avoid repeated calls to pci enable/disable
+
+  * Add support to thinkpad keyboard backlight (LP: #1574498)
+    - thinkpad_acpi: Add support for keyboard backlight
+
+  * Please enable kconfig X86_LEGACY_VM86 for i386 (LP: #1499089)
+    - [Config] CONFIG_VM86=y, CONFIG_X86_LEGACY_VM86=y
+
+  * Miscellaneous Ubuntu changes
+    - updateconfigs for Linux v4.4.9
+
+ -- Kamal Mostafa <kamal@canonical.com>  Mon, 16 May 2016 15:16:29 -0700
+
+linux (4.4.0-22.40) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * CVE-2016-3713 (LP: #1581201)
+    - SAUCE: KVM: MTRR: remove MSR 0x2f8
+
+  * CVE-2016-0758 (LP: #1581202)
+    - SAUCE: KEYS: Fix ASN.1 indefinite length object parsing
+
+ -- Kamal Mostafa <kamal@canonical.com>  Thu, 12 May 2016 13:38:45 -0700
+
+linux (4.4.0-22.39) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1578721
+
+  * LP: #1578705
+    - bpf: fix double-fdput in replace_map_fd_with_map_ptr()
+
+ -- Kamal Mostafa <kamal@canonical.com>  Thu, 05 May 2016 09:30:58 -0700
+
+linux (4.4.0-22.38) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1573817
+
+  * autoreconstruct: need to also generate extend-diff-ignore options for links
+    (LP: #1574362)
+    - [Packaging] autoreconstruct -- generate extend-diff-ignore for links
+
+  * tipc: missing linearization of sk_buff (LP: #1567064)
+    - tipc: move linearization of buffers to generic code
+
+  * [Hyper-V] In-flight PCI Passthrough Patches (LP: #1570124)
+    - SAUCE:(noup) drivers:hv: Lock access to hyperv_mmio resource tree
+    - SAUCE:(noup) drivers:hv: Call vmbus_mmio_free() to reverse
+      vmbus_mmio_allocate()
+    - SAUCE:(noup) drivers:hv: Reverse order of resources in hyperv_mmio
+    - SAUCE:(noup) drivers:hv: Track allocations of children of hv_vmbus in
+      private resource tree
+    - SAUCE:(noup) drivers:hv: Record MMIO range in use by frame buffer
+    - SAUCE:(noup) drivers:hv: Separate out frame buffer logic when picking MMIO
+      range
+
+  * vbox: resync with 5.0.18-dfsg-2build1 (LP: #1571156)
+    - ubuntu: vbox -- update to 5.0.18-dfsg-2build1
+
+  * CONFIG_AUFS_XATTR is not set (LP: #1557776)
+    - [Config] CONFIG_AUFS_XATTR=y
+
+  * CVE-2016-3672 (LP: #1568523)
+    - x86/mm/32: Enable full randomization on i386 and X86_32
+
+  * CVE-2016-3955 (LP: #1572666)
+    - USB: usbip: fix potential out-of-bounds write
+
+  * Xenial update to v4.4.8 stable release (LP: #1573034)
+    - hwmon: (max1111) Return -ENODEV from max1111_read_channel if not
+      instantiated
+    - PKCS#7: pkcs7_validate_trust(): initialize the _trusted output argument
+    - parisc: Avoid function pointers for kernel exception routines
+    - parisc: Fix kernel crash with reversed copy_from_user()
+    - parisc: Unbreak handling exceptions from kernel modules
+    - ALSA: timer: Use mod_timer() for rearming the system timer
+    - ALSA: hda - Asus N750JV external subwoofer fixup
+    - ALSA: hda - Fix white noise on Asus N750JV headphone
+    - ALSA: hda - Apply fix for white noise on Asus N550JV, too
+    - mm: fix invalid node in alloc_migrate_target()
+    - powerpc/mm: Fixup preempt underflow with huge pages
+    - libnvdimm: fix smart data retrieval
+    - libnvdimm, pfn: fix uuid validation
+    - compiler-gcc: disable -ftracer for __noclone functions
+    - arm64: opcodes.h: Add arm big-endian config options before including arm
+      header
+    - drm/dp: move hw_mutex up the call stack
+    - drm/udl: Use unlocked gem unreferencing
+    - drm/radeon: add a dpm quirk for sapphire Dual-X R7 370 2G D5
+    - drm/radeon: add another R7 370 quirk
+    - drm/radeon: add a dpm quirk for all R7 370 parts
+    - drm/amdgpu/gmc: move vram type fetching into sw_init
+    - drm/amdgpu/gmc: use proper register for vram type on Fiji
+    - xen/events: Mask a moving irq
+    - tcp: convert cached rtt from usec to jiffies when feeding initial rto
+    - tunnel: Clear IPCB(skb)->opt before dst_link_failure called
+    - net: jme: fix suspend/resume on JMC260
+    - net: vrf: Remove direct access to skb->data
+    - net: qca_spi: Don't clear IFF_BROADCAST
+    - net: qca_spi: clear IFF_TX_SKB_SHARING
+    - net: fix bridge multicast packet checksum validation
+    - sctp: lack the check for ports in sctp_v6_cmp_addr
+    - mld, igmp: Fix reserved tailroom calculation
+    - tipc: Revert "tipc: use existing sk_write_queue for outgoing packet chain"
+    - qmi_wwan: add Sierra Wireless EM74xx device ID
+    - ipv6: re-enable fragment header matching in ipv6_find_hdr
+    - vxlan: fix missing options_len update on RX with collect metadata
+    - cdc_ncm: toggle altsetting to force reset before setup
+    - udp6: fix UDP/IPv6 encap resubmit path
+    - tcp: fix tcpi_segs_in after connection establishment
+    - ppp: release rtnl mutex when interface creation fails
+    - net: validate variable length ll headers
+    - ax25: add link layer header validation function
+    - packet: validate variable length ll headers
+    - bpf: avoid copying junk bytes in bpf_get_current_comm()
+    - sh_eth: fix NULL pointer dereference in sh_eth_ring_format()
+    - sh_eth: advance 'rxdesc' later in sh_eth_ring_format()
+    - qlcnic: Remove unnecessary usage of atomic_t
+    - qlcnic: Fix mailbox completion handling during spurious interrupt
+    - macvtap: always pass ethernet header in linear
+    - mlxsw: spectrum: Check requested ageing time is valid
+    - rocker: set FDB cleanup timer according to lowest ageing time
+    - bridge: allow zero ageing time
+    - ipv4: Don't do expensive useless work during inetdev destroy.
+    - net: Fix use after free in the recvmmsg exit path
+    - mlx4: add missing braces in verify_qp_parameters
+    - farsync: fix off-by-one bug in fst_add_one
+    - ath9k: fix buffer overrun for ar9287
+    - ppp: ensure file->private_data can't be overridden
+    - tcp/dccp: remove obsolete WARN_ON() in icmp handlers
+    - qlge: Fix receive packets drop.
+    - net: bcmgenet: fix dma api length mismatch
+    - bonding: fix bond_get_stats()
+    - ipv4: fix broadcast packets reception
+    - ipv4: initialize flowi4_flags before calling fib_lookup()
+    - ppp: take reference on channels netns
+    - xfrm: Fix crash observed during device unregistration and decryption
+    - qmi_wwan: add "D-Link DWM-221 B1" device id
+    - ipv6: udp: fix UDP_MIB_IGNOREDMULTI updates
+    - bridge: Allow set bridge ageing time when switchdev disabled
+    - rtnl: fix msg size calculation in if_nlmsg_size()
+    - tun, bpf: fix suspicious RCU usage in tun_{attach, detach}_filter
+    - tuntap: restore default qdisc
+    - ipv4: l2tp: fix a potential issue in l2tp_ip_recv
+    - ipv6: l2tp: fix a potential issue in l2tp_ip6_recv
+    - ip6_tunnel: set rtnl_link_ops before calling register_netdevice
+    - ipv6: Count in extension headers in skb->network_header
+    - mpls: find_outdev: check for err ptr in addition to NULL check
+    - USB: uas: Limit qdepth at the scsi-host level
+    - USB: uas: Add a new NO_REPORT_LUNS quirk
+    - cdc-acm: fix NULL pointer reference
+    - KVM: x86: Inject pending interrupt even if pending nmi exist
+    - KVM: x86: reduce default value of halt_poll_ns parameter
+    - MIPS: Fix MSA ld unaligned failure cases
+    - pinctrl: pistachio: fix mfio84-89 function description and pinmux.
+    - pinctrl: sh-pfc: only use dummy states for non-DT platforms
+    - pinctrl: sunxi: Fix A33 external interrupts not working
+    - pinctrl: nomadik: fix pull debug print inversion
+    - pinctrl: freescale: imx: fix bogus check of of_iomap() return value
+    - au0828: fix au0828_v4l2_close() dev_state race condition
+    - au0828: Fix dev_state handling
+    - coda: fix error path in case of missing pdata on non-DT platform
+    - v4l: vsp1: Set the SRU CTRL0 register when starting the stream
+    - pcmcia: db1xxx_ss: fix last irq_to_gpio user
+    - rbd: use GFP_NOIO consistently for request allocations
+    - virtio: virtio 1.0 cs04 spec compliance for reset
+    - mac80211: properly deal with station hashtable insert errors
+    - mac80211: avoid excessive stack usage in sta_info
+    - mac80211: fix ibss scan parameters
+    - mac80211: fix unnecessary frame drops in mesh fwding
+    - mac80211: fix txq queue related crashes
+    - usb: renesas_usbhs: avoid NULL pointer derefernce in usbhsf_pkt_handler()
+    - usb: renesas_usbhs: disable TX IRQ before starting TX DMAC transfer
+    - usb: renesas_usbhs: fix to avoid using a disabled ep in usbhsg_queue_done()
+    - iio: st_magn: always define ST_MAGN_TRIGGER_SET_STATE
+    - iio: accel: bmc150: fix endianness when reading axes
+    - iio: gyro: bmg160: fix buffer read values
+    - iio: gyro: bmg160: fix endianness when reading axes
+    - sd: Fix excessive capacity printing on devices with blocks bigger than 512
+      bytes
+    - fs: add file_dentry()
+    - nfs: use file_dentry()
+    - btrfs: fix crash/invalid memory access on fsync when using overlayfs
+    - ext4: add lockdep annotations for i_data_sem
+    - ext4: ignore quota mount options if the quota feature is enabled
+    - iommu: Don't overwrite domain pointer when there is no default_domain
+    - Btrfs: fix file/data loss caused by fsync after rename and new inode
+    - arm64: replace read_lock to rcu lock in call_step_hook
+    - perf: Do not double free
+    - perf: Cure event->pending_disable race
+    - mmc: sdhci-pci: Add support and PCI IDs for more Broxton host controllers
+    - ALSA: hda - Fixup speaker pass-through control for nid 0x14 on ALC225
+    - ALSA: hda - Fix headset support and noise on HP EliteBook 755 G2
+    - ALSA: hda/realtek - Enable the ALC292 dock fixup on the Thinkpad T460s
+    - ALSA: usb-audio: Add a sample rate quirk for Phoenix Audio TMX320
+    - ALSA: usb-audio: Add a quirk for Plantronics BT300
+    - ALSA: usb-audio: Skip volume controls triggers hangup on Dell USB Dock
+    - HID: wacom: fix Bamboo ONE oops
+    - HID: usbhid: fix inconsistent reset/resume/reset-resume behavior
+    - Revert "x86/PCI: Don't alloc pcibios-irq when MSI is enabled"
+    - Revert "PCI: Add helpers to manage pci_dev->irq and pci_dev->irq_managed"
+    - Revert "PCI, x86: Implement pcibios_alloc_irq() and pcibios_free_irq()"
+    - staging: android: ion: Set the length of the DMA sg entries in buffer
+    - usbvision: fix crash on detecting device with invalid configuration
+    - Revert "usb: hub: do not clear BOS field during reset device"
+    - Linux 4.4.8
+
+  * Fix speaker volume on a Dell machine (LP: #1549660)
+    - ALSA: hda - Fixup speaker pass-through control for nid 0x14 on ALC225
+
+  * Xenial update to v4.4.7 stable release (LP: #1572722)
+    - regulator: core: avoid unused variable warning
+    - regulator: core: Fix nested locking of supplies
+    - ASoC: samsung: pass DMA channels as pointers
+    - mmc: sh_mmcif: rework dma channel handling
+    - mmc: sh_mmcif: Correct TX DMA channel allocation
+    - x86/microcode/intel: Make early loader look for builtin microcode too
+    - x86/microcode: Untangle from BLK_DEV_INITRD
+    - x86/entry/compat: Keep TS_COMPAT set during signal delivery
+    - perf/x86/intel: Add definition for PT PMI bit
+    - x86/PCI: Mark Broadwell-EP Home Agent & PCU as having non-compliant BARs
+    - KVM: i8254: change PIT discard tick policy
+    - KVM: fix spin_lock_init order on x86
+    - KVM: VMX: avoid guest hang on invalid invept instruction
+    - KVM: VMX: avoid guest hang on invalid invvpid instruction
+    - KVM: VMX: fix nested vpid for old KVM guests
+    - perf/core: Fix perf_sched_count derailment
+    - perf tools: Dont stop PMU parsing on alias parse error
+    - perf tools: Fix checking asprintf return value
+    - perf tools: Fix python extension build
+    - sched/cputime: Fix steal_account_process_tick() to always return jiffies
+    - sched/preempt, sh: kmap_coherent relies on disabled preemption
+    - EDAC, amd64_edac: Shift wrapping issue in f1x_get_norm_dct_addr()
+    - s390: fix floating pointer register corruption (again)
+    - s390/cpumf: add missing lpp magic initialization
+    - pinctrl-bcm2835: Fix cut-and-paste error in "pull" parsing
+    - PCI: Disable IO/MEM decoding for devices with non-compliant BARs
+    - PCI: ACPI: IA64: fix IO port generic range check
+    - x86/irq: Cure live lock in fixup_irqs()
+    - x86/apic: Fix suspicious RCU usage in smp_trace_call_function_interrupt()
+    - x86/iopl/64: Properly context-switch IOPL on Xen PV
+    - x86/iopl: Fix iopl capability check on Xen PV
+    - x86/mm: TLB_REMOTE_SEND_IPI should count pages
+    - sg: fix dxferp in from_to case
+    - aacraid: Fix RRQ overload
+    - aacraid: Fix memory leak in aac_fib_map_free
+    - aacraid: Set correct msix count for EEH recovery
+    - sd: Fix discard granularity when LBPRZ=1
+    - scsi: storvsc: fix SRB_STATUS_ABORTED handling
+    - be2iscsi: set the boot_kset pointer to NULL in case of failure
+    - aic7xxx: Fix queue depth handling
+    - libnvdimm: Fix security issue with DSM IOCTL.
+    - dm snapshot: disallow the COW and origin devices from being identical
+    - dm: fix excessive dm-mq context switching
+    - dm thin metadata: don't issue prefetches if a transaction abort has failed
+    - dm cache: make sure every metadata function checks fail_io
+    - dm: fix rq_end_stats() NULL pointer in dm_requeue_original_request()
+    - usb: retry reset if a device times out
+    - usb: hub: fix a typo in hub_port_init() leading to wrong logic
+    - USB: uas: Reduce can_queue to MAX_CMNDS
+    - USB: cdc-acm: more sanity checking
+    - USB: iowarrior: fix oops with malicious USB descriptors
+    - USB: usb_driver_claim_interface: add sanity checking
+    - USB: mct_u232: add sanity checking in probe
+    - USB: digi_acceleport: do sanity checking for the number of ports
+    - USB: cypress_m8: add endpoint sanity check
+    - USB: serial: cp210x: Adding GE Healthcare Device ID
+    - USB: serial: ftdi_sio: Add support for ICP DAS I-756xU devices
+    - USB: option: add "D-Link DWM-221 B1" device id
+    - pwc: Add USB id for Philips Spc880nc webcam
+    - Input: powermate - fix oops with malicious USB descriptors
+    - ALSA: usb-audio: Fix NULL dereference in create_fixed_stream_quirk()
+    - ALSA: usb-audio: Add sanity checks for endpoint accesses
+    - ALSA: usb-audio: add Microsoft HD-5001 to quirks
+    - ALSA: usb-audio: Minor code cleanup in create_fixed_stream_quirk()
+    - ALSA: usb-audio: Fix double-free in error paths after
+      snd_usb_add_audio_stream() call
+    - Bluetooth: btusb: Add new AR3012 ID 13d3:3395
+    - Bluetooth: btusb: Add a new AR3012 ID 04ca:3014
+    - Bluetooth: btusb: Add a new AR3012 ID 13d3:3472
+    - crypto: ccp - Add hash state import and export support
+    - crypto: ccp - Limit the amount of information exported
+    - crypto: ccp - Don't assume export/import areas are aligned
+    - crypto: ccp - memset request context to zero during import
+    - crypto: keywrap - memzero the correct memory
+    - crypto: atmel - fix checks of error code returned by devm_ioremap_resource()
+    - crypto: ux500 - fix checks of error code returned by devm_ioremap_resource()
+    - crypto: marvell/cesa - forward devm_ioremap_resource() error code
+    - X.509: Fix leap year handling again
+    - mei: bus: check if the device is enabled before data transfer
+    - HID: logitech: fix Dual Action gamepad support
+    - HID: i2c-hid: fix OOB write in i2c_hid_set_or_send_report()
+    - HID: multitouch: force retrieving of Win8 signature blob
+    - HID: fix hid_ignore_special_drivers module parameter
+    - staging: comedi: ni_tiocmd: change mistaken use of start_src for start_arg
+    - staging: android: ion_test: fix check of platform_device_register_simple()
+      error code
+    - staging: comedi: ni_mio_common: fix the ni_write[blw]() functions
+    - tty: Fix GPF in flush_to_ldisc(), part 2
+    - net: irda: Fix use-after-free in irtty_open()
+    - 8250: use callbacks to access UART_DLL/UART_DLM
+    - saa7134: Fix bytesperline not being set correctly for planar formats
+    - adv7511: TX_EDID_PRESENT is still 1 after a disconnect
+    - bttv: Width must be a multiple of 16 when capturing planar formats
+    - coda: fix first encoded frame payload
+    - media: v4l2-compat-ioctl32: fix missing length copy in put_v4l2_buffer32
+    - mtip32xx: Avoid issuing standby immediate cmd during FTL rebuild
+    - mtip32xx: Fix broken service thread handling
+    - mtip32xx: Remove unwanted code from taskfile error handler
+    - mtip32xx: Print exact time when an internal command is interrupted
+    - mtip32xx: Fix for rmmod crash when drive is in FTL rebuild
+    - mtip32xx: Handle safe removal during IO
+    - mtip32xx: Handle FTL rebuild failure state during device initialization
+    - mtip32xx: Implement timeout handler
+    - mtip32xx: Cleanup queued requests after surprise removal
+    - ALSA: pcm: Avoid "BUG:" string for warnings again
+    - ALSA: intel8x0: Add clock quirk entry for AD1981B on IBM ThinkPad X41.
+    - ALSA: hda - Don't handle ELD notify from invalid port
+    - ALSA: hda - fix the mic mute button and led problem for a Lenovo AIO
+    - ALSA: hda - Fix unconditional GPIO toggle via automute
+    - tools/hv: Use include/uapi with __EXPORTED_HEADERS__
+    - jbd2: fix FS corruption possibility in jbd2_journal_destroy() on umount path
+    - brd: Fix discard request processing
+    - IB/srpt: Simplify srpt_handle_tsk_mgmt()
+    - bcache: cleaned up error handling around register_cache()
+    - bcache: fix race of writeback thread starting before complete initialization
+    - bcache: fix cache_set_flush() NULL pointer dereference on OOM
+    - mm: memcontrol: reclaim when shrinking memory.high below usage
+    - mm: memcontrol: reclaim and OOM kill when shrinking memory.max below usage
+    - ia64: define ioremap_uc()
+    - watchdog: don't run proc_watchdog_update if new value is same as old
+    - watchdog: rc32434_wdt: fix ioctl error handling
+    - Bluetooth: Add new AR3012 ID 0489:e095
+    - Bluetooth: Fix potential buffer overflow with Add Advertising
+    - cgroup: ignore css_sets associated with dead cgroups during migration
+    - net: mvneta: enable change MAC address when interface is up
+    - of: alloc anywhere from memblock if range not specified
+    - vfs: show_vfsstat: do not ignore errors from show_devname method
+    - splice: handle zero nr_pages in splice_to_pipe()
+    - xtensa: ISS: don't hang if stdin EOF is reached
+    - xtensa: fix preemption in {clear,copy}_user_highpage
+    - xtensa: clear all DBREAKC registers on start
+    - ARC: [BE] readl()/writel() to work in Big Endian CPU configuration
+    - ARC: bitops: Remove non relevant comments
+    - quota: Fix possible GPF due to uninitialised pointers
+    - xfs: fix two memory leaks in xfs_attr_list.c error paths
+    - raid1: include bio_end_io_list in nr_queued to prevent freeze_array hang
+    - md/raid5: Compare apples to apples (or sectors to sectors)
+    - RAID5: check_reshape() shouldn't call mddev_suspend
+    - RAID5: revert e9e4c377e2f563 to fix a livelock
+    - raid10: include bio_end_io_list in nr_queued to prevent freeze_array hang
+    - md/raid5: preserve STRIPE_PREREAD_ACTIVE in break_stripe_batch_list
+    - md: multipath: don't hardcopy bio in .make_request path
+    - Revert "UBUNTU: SAUCE: (noup) fuse: Add reference counting for fuse_io_priv"
+    - Revert "UBUNTU: SAUCE: (noup) fuse: do not use iocb after it may have been
+      freed"
+    - fuse: do not use iocb after it may have been freed
+    - fuse: Add reference counting for fuse_io_priv
+    - fs/coredump: prevent fsuid=0 dumps into user-controlled directories
+    - rapidio/rionet: fix deadlock on SMP
+    - ipr: Fix out-of-bounds null overwrite
+    - ipr: Fix regression when loading firmware
+    - iwlwifi: mvm: Fix paging memory leak
+    - drm/radeon: disable runtime pm on PX laptops without dGPU power control
+    - drm/radeon: Don't drop DP 2.7 Ghz link setup on some cards.
+    - drm/amdgpu: disable runtime pm on PX laptops without dGPU power control
+    - drm/amdgpu: include the right version of gmc header files for iceland
+    - IB/ipoib: fix for rare multicast join race condition
+    - tracing: Have preempt(irqs)off trace preempt disabled functions
+    - tracing: Fix crash from reading trace_pipe with sendfile
+    - tracing: Fix trace_printk() to print when not using bprintk()
+    - bitops: Do not default to __clear_bit() for __clear_bit_unlock()
+    - scripts/coccinelle: modernize &
+    - scripts/kconfig: allow building with make 3.80 again
+    - kbuild/mkspec: fix grub2 installkernel issue
+    - MAINTAINERS: Update mailing list and web page for hwmon subsystem
+    - ideapad-laptop: Add ideapad Y700 (15) to the no_hw_rfkill DMI list
+    - mmc: block: fix ABI regression of mmc_blk_ioctl
+    - mmc: mmc_spi: Add Card Detect comments and fix CD GPIO case
+    - mmc: sdhci: fix data timeout (part 1)
+    - mmc: sdhci: fix data timeout (part 2)
+    - mmc: sdhci: Fix override of timeout clk wrt max_busy_timeout
+    - clk: rockchip: rk3368: fix cpuclk mux bit of big cpu-cluster
+    - clk: rockchip: rk3368: fix cpuclk core dividers
+    - clk: rockchip: rk3368: fix parents of video encoder/decoder
+    - clk: rockchip: rk3368: fix hdmi_cec gate-register
+    - clk: rockchip: add hclk_cpubus to the list of rk3188 critical clocks
+    - clk: bcm2835: Fix setting of PLL divider clock rates
+    - target: Fix target_release_cmd_kref shutdown comp leak
+    - iser-target: Fix identification of login rx descriptor type
+    - iser-target: Add new state ISER_CONN_BOUND to isert_conn
+    - iser-target: Separate flows for np listeners and connections cma events
+    - iser-target: Rework connection termination
+    - nfsd4: fix bad bounds checking
+    - nfsd: fix deadlock secinfo+readdir compound
+    - ARM: dts: at91: sama5d3 Xplained: don't disable hsmci regulator
+    - ARM: dts: at91: sama5d4 Xplained: don't disable hsmci regulator
+    - ACPI / PM: Runtime resume devices when waking from hibernate
+    - writeback, cgroup: fix premature wb_put() in
+      locked_inode_to_wb_and_lock_list()
+    - writeback, cgroup: fix use of the wrong bdi_writeback which mismatches the
+      inode
+    - Revert "UBUNTU: SAUCE: (noup) Input: synaptics - handle spurious release of
+      trackstick buttons, again"
+    - Input: synaptics - handle spurious release of trackstick buttons, again
+    - Input: ims-pcu - sanity check against missing interfaces
+    - Input: ati_remote2 - fix crashes on detecting device with invalid descriptor
+    - ocfs2/dlm: fix race between convert and recovery
+    - ocfs2/dlm: fix BUG in dlm_move_lockres_to_recovery_list
+    - mm/page_alloc: prevent merging between isolated and other pageblocks
+    - mtd: onenand: fix deadlock in onenand_block_markbad
+    - PM / sleep: Clear pm_suspend_global_flags upon hibernate
+    - scsi_common: do not clobber fixed sense information
+    - sched/cputime: Fix steal time accounting vs. CPU hotplug
+    - perf/x86/pebs: Add workaround for broken OVFL status on HSW+
+    - perf/x86/intel: Fix PEBS warning by only restoring active PMU in pmi
+    - perf/x86/intel: Fix PEBS data source interpretation on Nehalem/Westmere
+    - Linux 4.4.7
+
+  * QCA9565 / AR9565 bluetooth not work (LP: #1542944)
+    - Bluetooth: Add new AR3012 ID 0489:e095
+
+  * The mic mute key and led can't work on a Lenovo AIO machine (LP: #1555912)
+    - ALSA: hda - fix the mic mute button and led problem for a Lenovo AIO
+
+  * 13d3:3472 bluetooth not working, 4.2 low latency kernel 14.04.1 on asus ROG
+    gl552jx (LP: #1552925)
+    - Bluetooth: btusb: Add a new AR3012 ID 13d3:3472
+
+  * Bluetooth cannot detect other devices (Lite-on 3014 + Atheros AR9565)
+    (LP: #1546694)
+    - Bluetooth: btusb: Add a new AR3012 ID 04ca:3014
+
+  * Atheros AR9462 Bluetooth cannot detect other devices  (LP: #1542564)
+    - Bluetooth: btusb: Add new AR3012 ID 13d3:3395
+
+  * s390/pci: add extra padding to function measurement block (LP: #1572291)
+    - s390/pci: add extra padding to function measurement block
+
+  * CVE-2016-3951 (LP: #1567191)
+    - cdc_ncm: do not call usbnet_link_change from cdc_ncm_bind
+    - usbnet: cleanup after bind() in probe()
+
+  * linux: Add UEFI keyring for externally signed modules (LP: #1569924)
+    - efi: Remove redundant efi_set_variable_nonblocking() prototype
+    - efi/runtime-wrappers: Add a nonblocking version of QueryVariableInfo()
+    - efi: Add nonblocking option to efi_query_variable_store()
+    - efi: Add NV memory attribute
+    - efi: Reformat GUID tables to follow the format in UEFI spec
+    - efi: stub: implement efi_get_random_bytes() based on EFI_RNG_PROTOCOL
+    - SAUCE: (noup) Add EFI signature data types
+    - crypto: KEYS: convert public key and digsig asym to the akcipher api
+    - [Config] CONFIG_EFI_SIGNATURE_LIST_PARSER=y
+    - SAUCE: (noup) Add an EFI signature blob parser and key loader.
+    - [Config] CONFIG_IMA_MOK_KEYRING=y
+    - IMA: create machine owner and blacklist keyrings
+    - KEYS: Add an alloc flag to convey the builtinness of a key
+    - [Config] CONFIG_MODULE_SIG_UEFI=y, CONFIG_SYSTEM_BLACKLIST_KEYRING=y
+    - SAUCE: (noup) KEYS: Add a system blacklist keyring
+    - SAUCE: (noup) MODSIGN: Support not importing certs from db
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_PUBLIC_KEY_ALGO_RSA=y
+
+ -- Kamal Mostafa <kamal@canonical.com>  Sun, 24 Apr 2016 12:12:13 -0700
+
+linux (4.4.0-21.37) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1571791
+
+  * linux: MokSBState is ignored (LP: #1571691)
+    - SAUCE: (noup) MODSIGN: Import certificates from UEFI Secure Boot
+    - SAUCE: (noup) efi: Disable secure boot if shim is in insecure mode
+    - SAUCE: (noup) Display MOKSBState when disabled
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 18 Apr 2016 07:00:22 -0600
+
+linux (4.4.0-20.36) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1571069
+
+  * sysfs mount failure during stateful lxd snapshots (LP: #1570906)
+    - SAUCE: kernfs: Do not match superblock in another user namespace when
+      mounting
+
+  * Kernel Panic in Ubuntu 16.04 netboot installer (LP: #1570441)
+    - x86/topology: Fix logical package mapping
+    - x86/topology: Fix Intel HT disable
+    - x86/topology: Use total_cpus not nr_cpu_ids for logical packages
+    - xen/apic: Provide Xen-specific version of cpu_present_to_apicid APIC op
+    - x86/topology: Fix AMD core count
+
+  * [regression]: Failed to call clock_adjtime(): Invalid argument
+    (LP: #1566465)
+    - ntp: Fix ADJ_SETOFFSET being used w/ ADJ_NANO
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 14 Apr 2016 06:31:56 -0600
+
+linux (4.4.0-19.35) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1570348
+
+  * CVE-2016-2847 (LP: #1554260)
+    - pipe: limit the per-user amount of pages allocated in pipes
+
+  * xenial kernel crash on HP BL460c G7 (qla24xx problem?) (LP: #1554003)
+    - SAUCE: (noup) qla2xxx: Add irq affinity notification V2
+
+  * arm64: guest hangs when ntpd is running (LP: #1549494)
+    - SAUCE: (noup) KVM: arm/arm64: Handle forward time correction gracefully
+
+  * linux: Enforce signed module loading when UEFI secure boot (LP: #1566221)
+    - [Config] CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE=y
+
+  * s390/cpumf: Fix lpp detection (LP: #1555344)
+    - s390/facilities: use stfl mnemonic instead of insn magic
+    - s390/facilities: always use lowcore's stfle field for storing facility bits
+    - s390/cpumf: Fix lpp detection
+
+  * s390x kernel image needs weightwatchers (LP: #1536245)
+    - [Config] s390x: Use compressed kernel bzImage
+
+  * Surelock GA2 SP1: surelock02p05: Not seeing sgX devices for LUNs after
+    upgrading to Ubuntu 16.04 (LP: #1567581)
+    - Revert "UBUNTU: SAUCE: (noup) powerpc/pci: Assign fixed PHB number based on
+      device-tree properties"
+
+  * Backport upstream bugfixes to ubuntu-16.04 (LP: #1555765)
+    - cpufreq: powernv: Define per_cpu chip pointer to optimize hot-path
+    - Revert "cpufreq: postfix policy directory with the first CPU in related_cpus"
+    - cpufreq: powernv: Add sysfs attributes to show throttle stats
+
+  * systemd-modules-load.service: Failing due to missing module 'ib_iser' (LP: #1566468)
+    - [Config] Add ib_iser to generic inclusion list
+
+  * thunderx nic performance improvements (LP: #1567093)
+    - net: thunderx: Set recevie buffer page usage count in bulk
+    - net: thunderx: Adjust nicvf structure to reduce cache misses
+
+  * fixes for thunderx nic in multiqueue mode (LP: #1567091)
+    - net: thunderx: Fix for multiqset not configured upon interface toggle
+    - net: thunderx: Fix for HW TSO not enabled for secondary qsets
+    - net: thunderx: Fix receive packet stats
+
+  * Miscellaneous Ubuntu changes
+    - [Config] updateconfigs after CONFIG_DRM_I915_BPO_PRELIMINARY_HW_SUPPORT=n
+
+  * Miscellaneous upstream changes (LP: #1564901)
+    - Input: xpad - correctly handle concurrent LED and FF requests
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 07 Apr 2016 07:32:16 +0100
+
+linux (4.4.0-18.34) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1566868
+
+  * [i915_bpo] Fix RC6 on SKL GT3 & GT4 (LP: #1564759)
+    - SAUCE: i915_bpo: drm/i915/skl: Fix rc6 based gpu/system hang
+    - SAUCE: i915_bpo: drm/i915/skl: Fix spurious gpu hang with gt3/gt4 revs
+
+  * CONFIG_ARCH_ROCKCHIP not enabled in armhf generic kernel (LP: #1566283)
+    - [Config] CONFIG_ARCH_ROCKCHIP=y
+
+  * [Feature] Memory Bandwidth Monitoring (LP: #1397880)
+    - perf/x86/cqm: Fix CQM handling of grouping events into a cache_group
+    - perf/x86/cqm: Fix CQM memory leak and notifier leak
+    - x86/cpufeature: Carve out X86_FEATURE_*
+    - Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
+    - x86/topology: Create logical package id
+    - perf/x86/mbm: Add Intel Memory B/W Monitoring enumeration and init
+    - perf/x86/mbm: Add memory bandwidth monitoring event management
+    - perf/x86/mbm: Implement RMID recycling
+    - perf/x86/mbm: Add support for MBM counter overflow handling
+
+  * User namespace mount updates (LP: #1566505)
+    - SAUCE: quota: Require that qids passed to dqget() be valid and map into s_user_ns
+    - SAUCE: fs: Allow superblock owner to change ownership of inodes with unmappable ids
+    - SAUCE: fuse: Don't initialize user_id or group_id in mount options
+    - SAUCE: cgroup: Use a new super block when mounting in a cgroup namespace
+    - SAUCE: fs: fix a posible leak of allocated superblock
+
+  * [arm64] kernel BUG at /build/linux-StrpB2/linux-4.4.0/fs/ext4/inode.c:2394!
+    (LP: #1566518)
+    - arm64: Honour !PTE_WRITE in set_pte_at() for kernel mappings
+    - arm64: Update PTE_RDONLY in set_pte_at() for PROT_NONE permission
+
+  * [Feature]USB core and xHCI tasks for USB 3.1 SuperSpeedPlus (SSP) support
+    for Alpine Ridge on SKL (LP: #1519623)
+    - usb: define USB_SPEED_SUPER_PLUS speed for SuperSpeedPlus USB3.1 devices
+    - usb: set USB 3.1 roothub device speed to USB_SPEED_SUPER_PLUS
+    - usb: show speed "10000" in sysfs for USB 3.1 SuperSpeedPlus devices
+    - usb: add device descriptor for usb 3.1 root hub
+    - usb: Support USB 3.1 extended port status request
+    - xhci: Make sure xhci handles USB_SPEED_SUPER_PLUS devices.
+    - xhci: set roothub speed to USB_SPEED_SUPER_PLUS for USB3.1 capable controllers
+    - xhci: USB 3.1 add default Speed Attributes to SuperSpeedPlus device capability
+    - xhci: set slot context speed field to SuperSpeedPlus for USB 3.1 SSP devices
+    - usb: Add USB3.1 SuperSpeedPlus Isoc Endpoint Companion descriptor
+    - usb: Parse the new USB 3.1 SuperSpeedPlus Isoc endpoint companion descriptor
+    - usb: Add USB 3.1 Precision time measurement capability descriptor support
+    - xhci: refactor and cleanup endpoint initialization.
+    - xhci: Add SuperSpeedPlus high bandwidth isoc support to xhci endpoints
+    - xhci: cleanup isoc tranfers queuing code
+    - xhci: Support extended burst isoc TRB structure used by xhci 1.1 for USB 3.1
+    - SAUCE: (noup) usb: fix regression in SuperSpeed endpoint descriptor parsing
+
+  * wrong/missing permissions for device file /dev/prandom (prng.ko)
+    (LP: #1558275)
+    - s390/crypto: provide correct file mode at device register.
+
+  * The Front MIC jack can't work on a HP desktop machine (LP: #1564712)
+    - ALSA: hda - fix front mic problem for a HP desktop
+
+  * HP Notebook Probook 440 G3  HDA Intel PCH horrible sounds while booting
+    (LP: #1556228)
+    - ALSA: hda - Apply reboot D3 fix for CX20724 codec, too
+
+  * please provide mmc-modules udeb (LP: #1565765)
+    - [Config] Add mmc block drivers to d-i
+
+  * linux: Enforce signed module loading when UEFI secure boot (LP: #1566221)
+    - Add secure_modules() call
+    - PCI: Lock down BAR access when module security is enabled
+    - x86: Lock down IO port access when module security is enabled
+    - ACPI: Limit access to custom_method
+    - asus-wmi: Restrict debugfs interface when module loading is restricted
+    - Restrict /dev/mem and /dev/kmem when module loading is restricted
+    - acpi: Ignore acpi_rsdp kernel parameter when module loading is restricted
+    - kexec: Disable at runtime if the kernel enforces module loading restrictions
+    - x86: Restrict MSR access when module loading is restricted
+    - [Config] CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE=n
+    - Add option to automatically enforce module signatures when in Secure Boot mode
+    - efi: Make EFI_SECURE_BOOT_SIG_ENFORCE depend on EFI
+    - efi: Add EFI_SECURE_BOOT bit
+    - hibernate: Disable in a signed modules environment
+
+  * [Hyper-V] Additional PCI passthrough commits (LP: #1565967)
+    - PCI: Add fwnode_handle to x86 pci_sysdata
+    - PCI: Look up IRQ domain by fwnode_handle
+    - [Config] CONFIG_PCI_HYPERV=m
+    - PCI: hv: Add paravirtual PCI front-end for Microsoft Hyper-V VMs
+
+  * [Bug]Lenovo Yoga 260 and Carbon X1 4th gen freeze on HWP enable
+    (LP: #1559923)
+    - ACPI / processor: Request native thermal interrupt handling via _OSC
+
+  * Sync kernel zfs 0.6.5.6 - align with zfsutils-linux and spl packages
+    (LP: #1564591)
+    - SAUCE: (noup) Update spl to 0.6.5.6-0ubuntu1, zfs to 0.6.5.6-0ubuntu3
+
+  * [Ubuntu 16.04.1] RELEASE and ACQUIRE atomics on Power (LP: #1556096)
+    - atomics: Allow architectures to define their own __atomic_op_* helpers
+    - powerpc: atomic: Implement atomic{, 64}_*_return_* variants
+    - powerpc: atomic: Implement acquire/release/relaxed variants for xchg
+    - powerpc: atomic: Implement acquire/release/relaxed variants for cmpxchg
+
+  * fix for do_tools_cpupower when cross-compiling (LP: #1564206)
+    - [Debian] cpupower uses non-standard CROSS
+
+  * ISST:LTE: Regression: roselp2 Oops in kernel during setup io (LP: #1546439)
+    - SAUCE: block: partition: initialize percpuref before sending out KOBJ_ADD
+
+  * Unable to migrate container (LP: #1563921)
+    - SAUCE: cgroup mount: ignore nsroot=
+
+  * [Hyper-V] patch inclusion in 16.04 for NIC hot add/remove (LP: #1563688)
+    - hv_netvsc: Move subchannel waiting to rndis_filter_device_remove()
+
+  * /proc/$pid/maps performance regression (LP: #1547231)
+    - proc: revert /proc/<pid>/maps [stack:TID] annotation
+
+  * TPM2.0 trusted keys fixes (LP: #1398274)
+    - tpm: remove unneeded include of actbl2.h
+    - tpm: fix checks for policy digest existence in tpm2_seal_trusted()
+    - tpm_crb: Use the common ACPI definition of struct acpi_tpm2
+    - tpm_tis: Disable interrupt auto probing on a per-device basis
+    - tpm_tis: Do not fall back to a hardcoded address for TPM2
+    - tpm_tis: Use devm_ioremap_resource
+    - tpm_tis: Clean up the force=1 module parameter
+    - tpm_crb: Drop le32_to_cpu(ioread32(..))
+    - tpm_crb: Use devm_ioremap_resource
+    - tpm: fix the rollback in tpm_chip_register()
+    - tpm: fix the cleanup of struct tpm_chip
+    - tpm: fix: set continueSession attribute for the unseal operation
+    - tpm: fix: return rc when devm_add_action() fails
+    - tpm_eventlog.c: fix binary_bios_measurements
+    - tpm_crb/tis: fix: use dev_name() for /proc/iomem
+    - tpm_crb: tpm2_shutdown() must be called before tpm_chip_unregister()
+    - tpm_tis: fix build warning with tpm_tis_resume
+
+  * [Feature]intel_idle driver support for Knights Landing (LP: #1461365)
+    - intel_idle: Support for Intel Xeon Phi Processor x200 Product Family
+
+  * cxlflash: Backport upstream cxlflash commits and submitting a noup patch to
+    Xenial (LP: #1563485)
+    - cxlflash: Fix to avoid unnecessary scan with internal LUNs
+    - cxlflash: Increase cmd_per_lun for better throughput
+    - SAUCE: (noup) cxlflash: Move to exponential back-off when cmd_room is not available
+
+  * Miscellaneous Ubuntu changes
+    - [Config] do_zfs_powerpc64-smp  = true
+    - [Debian] fix linux_tools when cross-compiling
+    - [Config] do_zfs_powerpc64-smp use default value
+    - SAUCE: apparmor: Fix FTBFS due to bad include path
+    - SAUCE: i915_bpo: Disable preliminary hw support
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 29 Mar 2016 15:31:33 -0600
+
+linux (4.4.0-17.33) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1563441
+
+  * ISST-LTE: pVM:high cpus number need a high crashkernel value in kdump
+    (LP: #1560552)
+    - SAUCE: (noup) ppc64 boot: Wait for boot cpu to show up if nr_cpus limit is
+      about to hit.
+
+  * Predictable naming mechanism is leading to issues in DLPAR operations of
+    NICs (LP: #1560514)
+    - SAUCE: (noup) powerpc/pci: Assign fixed PHB number based on device-tree
+      properties
+
+  * ThunderX: support alternative phy implementations (LP: #1562968)
+    - net: thunderx: Cleanup PHY probing code.
+    - [Config] CONFIG_MDIO_CAVIUM=m
+    - phy: mdio-octeon: Refactor into two files/modules
+    - [Config] CONFIG_MDIO_THUNDER=m
+    - phy: mdio-thunder: Add driver for Cavium Thunder SoC MDIO buses.
+    - phy: mdio-cavium: Add missing MODULE_* annotations.
+    - net: cavium: For Kconfig THUNDER_NIC_BGX, select MDIO_THUNDER.
+    - phy: mdio-thunder: Fix some Kconfig typos
+    - [d-i] Add phy drivers for Cavium ThunderX to nic-modules udeb
+
+  * linux: exclude ZONE_DEVICE from GFP_ZONE_TABLE (LP: #1563293)
+    - Revert "mm: CONFIG_NR_ZONES_EXTENDED"
+    - mm: exclude ZONE_DEVICE from GFP_ZONE_TABLE
+
+  * lots of printk to serial console can hang system for long time
+    (LP: #1534216)
+    - printk: set may_schedule for some of console_trylock() callers
+
+  * [i915_bpo] Update i915 backport driver (LP: #1560395)
+    - SAUCE: i915_bpo: Update to drm-intel-next-fixes-2016-03-16
+    - PM / runtime: Add new helper for conditional usage count incrementation
+    - drm/core: Add drm_for_each_encoder_mask, v2.
+    - drm/atomic-helper: Implement subsystem-level suspend/resume
+
+  * [Hyper-V] VM Sockets (LP: #1541585)
+    - Drivers: hv: vmbus: Cleanup vmbus_set_event()
+    - Drivers: hv: vmbus: Add vendor and device atttributes
+    - Drivers: hv: vmbus: avoid infinite loop in init_vp_index()
+    - Drivers: hv: vmbus: avoid scheduling in interrupt context in vmbus_initiate_unload()
+    - Drivers: hv: vmbus: don't manipulate with clocksources on crash
+    - Drivers: hv: vmbus: add a helper function to set a channel's pending send size
+    - Drivers: hv: vmbus: define the new offer type for Hyper-V socket (hvsock)
+    - Drivers: hv: vmbus: vmbus_sendpacket_ctl: hvsock: avoid unnecessary signaling
+    - Drivers: hv: vmbus: define a new VMBus message type for hvsock
+    - Drivers: hv: vmbus: add a hvsock flag in struct hv_driver
+    - Drivers: hv: vmbus: add a per-channel rescind callback
+    - Drivers: hv: vmbus: add an API vmbus_hvsock_device_unregister()
+    - Drivers: hv: vmbus: Eliminate the spin lock on the read path
+    - Drivers: hv: vmbus: Give control over how the ring access is serialized
+    - drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header
+    - Drivers: hv: vmbus: don't loose HVMSG_TIMER_EXPIRED messages
+    - Drivers: hv: vmbus: avoid wait_for_completion() on crash
+    - Drivers: hv: vmbus: remove code duplication in message handling
+    - Drivers: hv: vmbus: avoid unneeded compiler optimizations in vmbus_wait_for_unload()
+    - Drivers: hv: util: Pass the channel information during the init call
+    - Drivers: hv: utils: Remove util transport handler from list if registration fails
+    - Revert "Drivers: hv: vmbus: Support handling messages on multiple CPUs"
+    - Drivers: hv: vmbus: Support handling messages on multiple CPUs
+
+  * [Bug]SKL-H boot hang when c8+c9+c10 enabled by intel_idle driver
+    (LP: #1559918)
+    - intel_idle: prevent SKL-H boot failure when C8+C9+C10 enabled
+
+  * ixgbe: Update to Fortville SW5 release (LP: #1562326)
+    - net: add tc offload feature flag
+    - net: tc: helper functions to query action types
+    - sctp: Rename NETIF_F_SCTP_CSUM to NETIF_F_SCTP_CRC
+    - net: rework ndo tc op to consume additional qdisc handle parameter
+    - net: rework setup_tc ndo op to consume general tc operand
+    - net: sched: add cls_u32 offload hooks for netdevs
+    - net: ixgbe: add support for tc_u32 offload
+    - net: ixgbe: abort with cls u32 divisor groups greater than 1
+
+  * Bring fm10k up to Fortville SW5 (LP: #1562310)
+    - net: add netif_is_team_master helper
+    - net: add netif_is_team_port helper
+    - net: add netif_is_lag_master helper
+    - net: add netif_is_lag_port helper
+    - ethtool: correctly ensure {GS}CHANNELS doesn't conflict with GS{RXFH}
+    - fm10k: don't reinitialize RSS flow table when RXFH configured
+
+  * [Feature]Always Running Timer (ART) to System Time translation
+    (LP: #1519625)
+    - time: Verify time values in adjtimex ADJ_SETOFFSET to avoid overflow
+    - timekeeping: Provide internal function __ktime_get_real_seconds
+    - timekeeping: Cap adjustments so they don't exceed the maxadj value
+    - clocksource: Make clocksource validation work for all clocksources
+    - time: Add cycles to nanoseconds translation
+    - time: Add timekeeping snapshot code capturing system time and counter
+    - time: Remove duplicated code in ktime_get_raw_and_real()
+    - time: Add driver cross timestamp interface for higher precision time synchronization
+    - time: Add history to cross timestamp interface supporting slower devices
+    - time/timekeeping: Work around false positive GCC warning
+    - x86/tsc: Always Running Timer (ART) correlated clocksource
+    - ptp: Add PTP_SYS_OFFSET_PRECISE for driver crosstimestamping
+    - [Config] CONFIG_E1000E_HWTS=y
+    - e1000e: Adds hardware supported cross timestamp on e1000e nic
+
+  * x-gene2: add SoC v2 support to clock (LP: #1561604)
+    - clk: xgene: Add SoC and PMD PLL clocks with v2 hardware
+
+  * [Bug]Disable multi-record PEBS on Merom (LP: #1559914)
+    - perf/x86: Move perf_event.c ............... => x86/events/core.c
+    - perf/x86: Move perf_event_amd.c ........... => x86/events/amd/core.c
+    - perf/x86: Move perf_event_amd_ibs.c ....... => x86/events/amd/ibs.c
+    - perf/x86: Move perf_event_amd_iommu.[ch] .. => x86/events/amd/iommu.[ch]
+    - perf/x86: Move perf_event_amd_uncore.c .... => x86/events/amd/uncore.c
+    - perf/x86: Move perf_event_intel_bts.c ........ => x86/events/intel/bts.c
+    - perf/x86: Move perf_event_intel.c ............ => x86/events/intel/core.c
+    - perf/x86: Move perf_event_intel_cqm.c ........ => x86/events/intel/cqm.c
+    - perf/x86: Move perf_event_intel_cstate.c ..... => x86/events/intel/cstate.c
+    - perf/x86: Move perf_event_intel_ds.c ......... => x86/events/intel/ds.c
+    - perf/x86: Move perf_event_intel_lbr.c ........ => x86/events/intel/lbr.c
+    - perf/x86: Move perf_event_intel_pt.[ch] ...... => x86/events/intel/pt.[ch]
+    - perf/x86: Move perf_event_intel_rapl.c ....... => x86/events/intel/rapl.c
+    - perf/x86: Move perf_event_intel_uncore.[ch] .. =>
+      x86/events/intel/uncore.[ch]
+    - perf/x86: Move perf_event_intel_uncore_nhmex.c =>
+      x86/events/intel/uncore_nmhex.c
+    - perf/x86: Move perf_event_intel_uncore_snb.c =>
+      x86/events/intel/uncore_snb.c
+    - perf/x86: Move perf_event_intel_uncore_snbep.c =>
+      x86/events/intel/uncore_snbep.c
+    - perf/x86: Move perf_event_knc.c .............. => x86/events/intel/knc.c
+    - perf/x86: Move perf_event_p4.c ............... => x86/events/intel/p4.c
+    - perf/x86: Move perf_event_p6.c ............... => x86/events/intel/p6.c
+    - perf/x86: Move perf_event_msr.c .............. => x86/events/msr.c
+    - perf/x86: Move perf_event.h to its new home
+    - perf/x86/intel: Use PAGE_SIZE for PEBS buffer size on Core2
+
+  * [Feature] Enable I2C on Broxton-P (LP: #1520139)
+    - mfd: intel-lpss: Pass I2C configuration via properties on BXT
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 24 Mar 2016 20:40:27 -0600
+
+linux (4.4.0-16.32) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1561727
+
+  * fix thermal throttling due to commit "Thermal: initialize thermal zone
+    device correctly"  (LP: #1561676)
+    - Thermal: Ignore invalid trip points
+
+  * Thinkpad T460: Trackpoint mouse buttons instantly generate "release" event
+    on press (LP: #1553811)
+    - SAUCE: (noup) Input: synaptics - handle spurious release of trackstick
+      buttons, again
+
+  * reading /sys/kernel/security/apparmor/profiles requires CAP_MAC_ADMIN
+    (LP: #1560583)
+    - SAUCE: apparmor: Allow ns_root processes to open profiles file
+    - SAUCE: apparmor: Consult sysctl when reading profiles in a user ns
+
+  * linux: sync virtualbox drivers to 5.0.16-dfsg-2 (LP: #1561492)
+    - ubuntu: vbox -- update to 5.0.16-dfsg-2
+
+  * s390/kconfig: CONFIG_NUMA without CONFIG_NUMA_EMU does not make any sense on
+    s390x (LP: #1557690)
+    - [Config] CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=n for s390x
+
+  * spl/zfs fails to build on s390x (LP: #1519814)
+    - [Config] s390x -- re-enable zfs
+    - [Config] zfs -- disable powerpc until the test failures can be resolved
+
+  * linux: sync to ZFS 0.6.5.6 stable release (LP: #1561483)
+    - SAUCE: (noup) Update spl to 0.6.5.6-0ubuntu1, zfs to 0.6.5.6-0ubuntu1
+
+  * zfs: enable zfs for 64bit powerpc kernels (LP: #1558871)
+    - [Packaging] zfs -- handle rprovides via dpkg-gencontrol
+    - [Config] powerpc -- convert zfs configuration to custom_override
+
+  * Memory arena corruption with FUSE (was Memory allocation failure crashes
+    kernel hard, presumably related to FUSE) (LP: #1505948)
+    - SAUCE: (noup) fuse: do not use iocb after it may have been freed
+    - SAUCE: (noup) fuse: Add reference counting for fuse_io_priv
+
+  * cgroup namespaces: add a 'nsroot=' mountinfo field (LP: #1560489)
+    - SAUCE: (noup) cgroup namespaces: add a 'nsroot=' mountinfo field
+
+  * linux packaging: clear remaining redundant delta (LP: #1560445)
+    - [Debian] Remove generated intermediate files on clean
+
+  * arm64: guest hangs when ntpd is running (LP: #1549494)
+    - Revert "hrtimer: Add support for CLOCK_MONOTONIC_RAW"
+    - Revert "hrtimer: Catch illegal clockids"
+    - Revert "KVM: arm/arm64: timer: Switch to CLOCK_MONOTONIC_RAW"
+
+  * Need enough contiguous memory to support GICv3 ITS table (LP: #1558828)
+    - [Config] CONFIG_FORCE_MAX_ZONEORDER=13 on arm64
+    - SAUCE: (no-up) arm64: gicv3: its: Increase FORCE_MAX_ZONEORDER for Cavium
+      ThunderX
+
+  * update arcmsr to version v1.30.00.22-20151126 to fix card timeouts
+    (LP: #1559609)
+    - arcmsr: fixed getting wrong configuration data
+    - arcmsr: fixes not release allocated resource
+    - arcmsr: make code more readable
+    - arcmsr: adds code to support new Areca adapter ARC1203
+    - arcmsr: changes driver version number
+    - arcmsr: more readability improvements
+    - arcmsr: Split dma resource allocation to a new function
+    - arcmsr: change driver version to v1.30.00.22-20151126
+
+  * server image has no keyboard, desktop image works (LP: #1559692)
+    - [Config] Rework input-modules (d-i) list
+
+  * PMU support for Cavium ThunderX (LP: #1559349)
+    - arm64: perf: Rename Cortex A57 events
+    - arm64/perf: Add Cavium ThunderX PMU support
+    - arm64: perf: Enable PMCR long cycle counter bit
+    - arm64: perf: Extend event mask for ARMv8.1
+    - arm64: dts: Add Cavium ThunderX specific PMU
+
+  * Show ARM PMU events in perf stat (LP: #1559350)
+    - drivers/perf: kill armpmu_register
+    - arm: perf: Convert event enums to #defines
+    - arm: perf: Add event descriptions
+    - arm64: perf: Convert event enums to #defines
+    - arm64: perf: Add event descriptions
+    - ARM: perf: add format entry to describe event -> config mapping
+    - arm64: perf: add format entry to describe event -> config mapping
+
+  * [Bug]HSW/BDW EDAC driver reports wrong DIMM (LP: #1559904)
+    - EDAC/sb_edac: Fix computation of channel address
+
+  * 5-10 second delay in kernel boot with kernel command line ip= (LP: #1259861)
+    - [Config] disable CONFIG_IP_PNP
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Silence the reconstruct script
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 21 Mar 2016 10:15:31 -0600
+
+linux (4.4.0-15.31) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1559252
+
+  * Xilinx KU3 Capi card does not show up in Ubuntu  16.04 (LP: #1557001)
+    - SAUCE: (noup) cxl: Allow initialization on timebase sync failures
+
+  * policy namespace stacking (LP: #1379535)
+    - Revert "UBUNTU: SAUCE: Move replacedby allocation into label_alloc"
+    - Revert "UBUNTU: SAUCE: Fixup: __label_update() still doesn't handle some cases correctly."
+    - Revert "UBUNTU: SAUCE: fix: audit "no_new_privs" case for exec failure"
+    - Revert "UBUNTU: SAUCE: fixup: warning about aa_label_vec_find_or_create not being static"
+    - Revert "UBUNTU: SAUCE: apparmor: fix refcount race when finding a child profile"
+    - Revert "UBUNTU: SAUCE: fixup: cast poison values to remove warnings"
+    - Revert "UBUNTU: SAUCE: fixup: get rid of unused var build warning"
+    - Revert "UBUNTU: SAUCE: fixup: 20/23 locking issue around in __label_update"
+    - Revert "UBUNTU: SAUCE: fixup: make __share_replacedby private to get rid of build warning"
+    - Revert "UBUNTU: SAUCE: fix: replacedby forwarding is not being properly update when ns is destroyed"
+    - Revert "UBUNTU: SAUCE: apparmor: fix log of apparmor audit message when kern_path() fails"
+    - Revert "UBUNTU: SAUCE: fixup: cleanup return handling of labels"
+    - Revert "UBUNTU: SAUCE: apparmor: fix: ref count leak when profile sha1 hash is read"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: query label file permission"
+    - Revert "UBUNTU: SAUCE: apparmor: Don't remove label on rcu callback if the label has already been removed"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: break circular refcount for label that is directly freed."
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: refcount bug when inserting label update that transitions ns"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: now that insert can force replacement use it instead of remove_and_insert"
+    - Revert "UBUNTU: SAUCE: apparmor Fix: refcount bug in pivotroot mediation"
+    - Revert "UBUNTU: SAUCE: apparmor: ensure that repacedby sharing is done correctly"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: update replacedby allocation to take a gfp parameter"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: convert replacedby update to be protected by the labelset lock"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: add required locking of __aa_update_replacedby on merge path"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: deadlock in aa_put_label() call chain"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: label_vec_merge insertion"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: ensure new labels resulting from merge have a replacedby"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: refcount leak in aa_label_merge"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: refcount race between locating in labelset and get"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: label merge handling of marking unconfined and stale"
+    - Revert "UBUNTU: SAUCE: apparmor: add underscores to indicate aa_label_next_not_in_set() use needs locking"
+    - Revert "UBUNTU: SAUCE: apparmor: debug: POISON label and replaceby pointer on free"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: ensure aa_get_newest will trip debugging if the replacedby is not setup"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: insert race between label_update and label_merge"
+    - Revert "UBUNTU: SAUCE: apparmor: rework retrieval of the current label in the profile update case"
+    - Revert "UBUNTU: SAUCE: apparmor: Disallow update of cred when then subjective != the objective cred"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: oops do to invalid null ptr deref in label print fns"
+    - Revert "UBUNTU: SAUCE: fix-up: kern_mount fail path should not be doing put_buffers()"
+    - Revert "UBUNTU: SAUCE: apparmor: fix sleep from invalid context"
+    - Revert "UBUNTU: SAUCE: (no-up): apparmor: fix for failed mediation of socket that is being shutdown"
+    - Revert "UBUNTU: SAUCE: (no-up) apparmor: Fix incompatible pointer type warnings"
+    - Revert "UBUNTU: SAUCE: (no-up) apparmor: fix mount not handling disconnected paths"
+    - Revert "UBUNTU: SAUCE: (no-up): apparmor: fix mediation of fs unix sockets"
+    - Revert "UBUNTU: apparmor -- follow change to this_cpu_ptr"
+    - Revert "UBUNTU: SAUCE: (no-up) fix: bad unix_addr_fs macro"
+    - Revert "UBUNTU: SAUCE: Revert: fix: only allow a single threaded process to ..."
+    - Revert "UBUNTU: SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot"
+    - Revert "UBUNTU: SAUCE: (no-up) apparmor: add parameter to control whether policy hashing is used"
+    - SAUCE: (no-up) apparmor: sync of apparmor3.5-beta1 snapshot
+    - SAUCE: add a sysctl to enable unprivileged user ns AppArmor policy loading
+
+  * Add arm64 NUMA support (LP: #1558765)
+    - SAUCE: (noup) efi: ARM/arm64: ignore DT memory nodes instead of removing them
+    - SAUCE: (noup) Documentation, dt, numa: dt bindings for NUMA.
+    - [Config] CONFIG_OF_NUMA=y
+    - SAUCE: (noup) of, numa: Add NUMA of binding implementation.
+    - SAUCE: (noup) arm64: Move unflatten_device_tree() call earlier.
+    - [Config] CONFIG_NUMA=y and CONFIG_NODES_SHIFT=2 on arm64
+    - SAUCE: (noup) arm64, numa: Add NUMA support for arm64 platforms.
+    - SAUCE: (noup) arm64, mm, numa: Add NUMA balancing support for arm64.
+
+  * vivid/linux: total ADT test failures (LP: #1558447)
+    - Revert "Revert "af_unix: Revert 'lock_interruptible' in stream receive code""
+
+  * [Hyper-V] patches to allow kdump crash through NMI (LP: #1558720)
+    - Drivers: hv: vmbus: Support handling messages on multiple CPUs
+    - Drivers: hv: vmbus: Support kexec on ws2012 r2 and above
+
+  * s390/pci: enforce fmb page boundary rule (LP: #1558625)
+    - s390/pci: enforce fmb page boundary rule
+
+  * s390/pci: backport upstream commits since v4.4 (LP: #1558624)
+    - s390/pci_dma: fix DMA table corruption with > 4 TB main memory
+    - page_to_phys() always returns a multiple of PAGE_SIZE
+    - s390/pci: provide ZPCI_ADDR macro
+    - s390/pci: improve ZPCI_* macros
+    - s390/pci: resize iomap
+    - s390/pci: fix bar check
+    - s390/pci: set error state for unusable functions
+    - s390/pci: remove iomap sanity checks
+    - s390/pci: remove pdev pointer from arch data
+    - s390/pci: add ioctl interface for CLP
+
+  * IMA-appraisal is unusable in Ubuntu 16.04 (LP: #1558553)
+    - [Config] CONFIG_SYSTEM_EXTRA_CERTIFICATE=y, CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE=4096
+    - KEYS: Use the symbol value for list size, updated by scripts/insert-sys-cert
+    - KEYS: Reserve an extra certificate symbol for inserting without recompiling
+    - SAUCE: (noup) KEYS: Support for inserting a certificate into x86 bzImage
+
+  * skb_warn_bad_offload Crash (LP: #1558025)
+    - ipv4: only create late gso-skb if skb is already set up with CHECKSUM_PARTIAL
+
+  * Add PCIe root complex to Cavium arm64 (LP: #1558342)
+    - [Config] CONFIG_PCI_HOST_COMMON=y
+    - [Config] CONFIG_PCI_HOST_THUNDER_PEM=y
+    - [Config] CONFIG_PCI_HOST_THUNDER_ECAM=y
+    - PCI: generic: Move structure definitions to separate header file
+    - PCI: generic: Add pci_host_common_probe(), based on gen_pci_probe()
+    - PCI: generic: Expose pci_host_common_probe() for use by other drivers
+    - PCI: thunder: Add PCIe host driver for ThunderX processors
+    - PCI: thunder: Add driver for ThunderX-pass{1,2} on-chip devices
+
+  * [Hyper-V] vmbus: Fix a bug in hv_need_to_signal_on_read() (LP: #1556264)
+    - SAUCE: (noup) Drivers: hv: vmbus: Fix a bug in hv_need_to_signal_on_read()
+
+  * Xenial update to v4.4.6 stable release (LP: #1558330)
+    - arm64: account for sparsemem section alignment when choosing vmemmap offset
+    - ARM: mvebu: fix overlap of Crypto SRAM with PCIe memory window
+    - ARM: dts: dra7: do not gate cpsw clock due to errata i877
+    - ARM: OMAP2+: hwmod: Introduce ti,no-idle dt property
+    - PCI: Allow a NULL "parent" pointer in pci_bus_assign_domain_nr()
+    - kvm: cap halt polling at exactly halt_poll_ns
+    - KVM: VMX: disable PEBS before a guest entry
+    - KVM: s390: correct fprs on SIGP (STOP AND) STORE STATUS
+    - KVM: PPC: Book3S HV: Sanitize special-purpose register values on guest exit
+    - KVM: MMU: fix ept=0/pte.u=1/pte.w=0/CR0.WP=0/CR4.SMEP=1/EFER.NX=0 combo
+    - KVM: MMU: fix reserved bit check for ept=0/CR0.WP=0/CR4.SMEP=1/EFER.NX=0
+    - s390/dasd: fix diag 0x250 inline assembly
+    - tracing: Fix check for cpu online when event is disabled
+    - dmaengine: at_xdmac: fix residue computation
+    - jffs2: reduce the breakage on recovery from halfway failed rename()
+    - ncpfs: fix a braino in OOM handling in ncp_fill_cache()
+    - ASoC: dapm: Fix ctl value accesses in a wrong type
+    - ASoC: samsung: Use IRQ safe spin lock calls
+    - ASoC: wm8994: Fix enum ctl accesses in a wrong type
+    - ASoC: wm8958: Fix enum ctl accesses in a wrong type
+    - ovl: ignore lower entries when checking purity of non-directory entries
+    - ovl: fix working on distributed fs as lower layer
+    - wext: fix message delay/ordering
+    - cfg80211/wext: fix message ordering
+    - can: gs_usb: fixed disconnect bug by removing erroneous use of kfree()
+    - iwlwifi: mvm: inc pending frames counter also when txing non-sta
+    - mac80211: minstrel: Change expected throughput unit back to Kbps
+    - mac80211: fix use of uninitialised values in RX aggregation
+    - mac80211: minstrel_ht: set default tx aggregation timeout to 0
+    - mac80211: minstrel_ht: fix a logic error in RTS/CTS handling
+    - mac80211: check PN correctly for GCMP-encrypted fragmented MPDUs
+    - mac80211: Fix Public Action frame RX in AP mode
+    - gpu: ipu-v3: Do not bail out on missing optional port nodes
+    - drm/amdgpu: Fix error handling in amdgpu_flip_work_func.
+    - drm/radeon: Fix error handling in radeon_flip_work_func.
+    - Revert "drm/radeon/pm: adjust display configuration after powerstate"
+    - userfaultfd: don't block on the last VM updates at exit time
+    - ovl: fix getcwd() failure after unsuccessful rmdir
+    - MIPS: Fix build error when SMP is used without GIC
+    - MIPS: smp.c: Fix uninitialised temp_foreign_map
+    - block: don't optimize for non-cloned bio in bio_get_last_bvec()
+    - target: Drop incorrect ABORT_TASK put for completed commands
+    - ld-version: Fix awk regex compile failure
+    - Linux 4.4.6
+
+  * linux fails to load x.509 built-in certificate (LP: #1557250)
+    - lib/mpi: Endianness fix
+
+  * s390/kconfig: setting for CONFIG...9P.... (LP: #1557994)
+    - [Config] CONFIG_NET_9P=m for s390x
+
+  * mlx5_core kernel trace after "ethtool -C eth1 adaptive-rx on" flow
+    (LP: #1557950)
+    - net/mlx5e: Don't try to modify CQ moderation if it is not supported
+    - net/mlx5e: Don't modify CQ before it was created
+
+  * [Feature]SD/SDIO/eMMC support for Broxton-P (LP: #1520454)
+    - mmc: sdhci: Do not BUG on invalid vdd
+    - mmc: enable MMC/SD/SDIO device to suspend/resume asynchronously
+    - mmc: It is not an error for the card to be removed while suspended
+
+  * s390/kconfig: disable CONFIG_VIRTIO_MMIO (LP: #1557689)
+    - [Config] CONFIG_VIRTIO_MMIO=n for s390x
+
+  * s390/kconfig: CONFIG_NUMA without CONFIG_NUMA_EMU does not make any sense on s390x (LP: #1557690)
+    - [Config] CONFIG_NUMA_EMU=y for s390x
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] git-ubuntu-log -- prevent bug references being split
+    - [Debian] git-ubuntu-log -- git log output is UTF-8
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Mar 2016 13:18:58 -0600
+
+linux (4.4.0-14.30) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1557508
+
+  * Current 4.4 kernel won't boot on powerpc (LP: #1557130)
+    - powerpc: Fix dedotify for binutils >= 2.26
+
+  * ZFS: send fails to transmit some holes [corruption] (LP: #1557151)
+    - Illumos 6370 - ZFS send fails to transmit some holes
+
+  * Request to cherry-pick uvcvideo patch for Xenial kernel support of RealSense
+    camera (LP: #1557138)
+    - UVC: Add support for ds4 depth camera
+
+  * use after free of task_struct->numa_faults in task_numa_find_cpu (LP: #1527643)
+    - sched/numa: Fix use-after-free bug in the task_numa_compare
+
+  * overlay fs regression: chmod fails with "Operation not permitted" on chowned
+    files (LP: #1555997)
+    - ovl: copy new uid/gid into overlayfs runtime inode
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Dump stack when X.509 certificates cannot be loaded
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 14 Mar 2016 07:16:19 -0600
+
+linux (4.4.0-13.29) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1556247
+
+  * s390/mm: four page table levels vs. fork (LP: #1556141)
+    - s390/mm: four page table levels vs. fork
+
+  * [Hyper-V] network performance patches for Xenial 16.04 (LP: #1556037)
+    - hv_netvsc: use skb_get_hash() instead of a homegrown implementation
+    - hv_netvsc: cleanup netdev feature flags for netvsc
+
+  * fails to boot on megaraid (LP: #1552903)
+    - SAUCE: (noup) megaraid_sas: Don't issue kill adapter for MFI controllers in
+      case of PD list DCMD failure
+
+  * ALSA: hda - add codec support for Kabylake display audio codec (LP: #1556002)
+    - ALSA: hda - add codec support for Kabylake display audio codec
+
+  * Backport upstream bugfixes to ubuntu-16.04 (LP: #1555765)
+    - cpufreq: powernv: Free 'chips' on module exit
+    - cpufreq: powernv: Hot-plug safe the kworker thread
+    - cpufreq: powernv: Remove cpu_to_chip_id() from hot-path
+    - cpufreq: powernv/tracing: Add powernv_throttle tracepoint
+    - cpufreq: powernv: Replace pr_info with trace print for throttle event
+    - SAUCE: (noup) cpufreq: powernv: Fix bugs in powernv_cpufreq_{init/exit}
+
+  * Linux netfilter IPT_SO_SET_REPLACE memory corruption (LP: #1555338)
+    - SAUCE: [nf,v2] netfilter: x_tables: don't rely on well-behaving userspace
+
+  * integer overflow in xt_alloc_table_info (LP: #1555353)
+    - SAUCE: (noup) netfilter: x_tables: check for size overflow
+
+  * linux: auto-generate the reconstruct information from the git tag (LP: #1555543)
+    - [Packaging] reconstruct -- automatically reconstruct against base tag
+    - [Config] reconstruct -- update to autoreconstruct output
+    - [Packaging] reconstruct -- update when inserting final changes
+
+  * Xenial update to v4.4.5 stable release (LP: #1555640)
+    - use ->d_seq to get coherency between ->d_inode and ->d_flags
+    - drivers: sh: Restore legacy clock domain on SuperH platforms
+    - Btrfs: fix deadlock running delayed iputs at transaction commit time
+    - btrfs: Fix no_space in write and rm loop
+    - btrfs: async-thread: Fix a use-after-free error for trace
+    - block: Initialize max_dev_sectors to 0
+    - PCI: keystone: Fix MSI code that retrieves struct pcie_port pointer
+    - parisc: Fix ptrace syscall number and return value modification
+    - mips/kvm: fix ioctl error handling
+    - kvm: x86: Update tsc multiplier on change.
+    - fbcon: set a default value to blink interval
+    - cifs: fix out-of-bounds access in lease parsing
+    - CIFS: Fix SMB2+ interim response processing for read requests
+    - Fix cifs_uniqueid_to_ino_t() function for s390x
+    - vfio: fix ioctl error handling
+    - KVM: x86: fix root cause for missed hardware breakpoints
+    - arm/arm64: KVM: Fix ioctl error handling
+    - iommu/amd: Apply workaround for ATS write permission check
+    - iommu/amd: Fix boot warning when device 00:00.0 is not iommu covered
+    - iommu/vt-d: Use BUS_NOTIFY_REMOVED_DEVICE in hotplug path
+    - target: Fix WRITE_SAME/DISCARD conversion to linux 512b sectors
+    - drm/ast: Fix incorrect register check for DRAM width
+    - drm/radeon/pm: update current crtc info after setting the powerstate
+    - drm/amdgpu/pm: update current crtc info after setting the powerstate
+    - drm/amdgpu: apply gfx_v8 fixes to gfx_v7 as well
+    - drm/amdgpu/gfx8: specify which engine to wait before vm flush
+    - drm/amdgpu: return from atombios_dp_get_dpcd only when error
+    - libata: fix HDIO_GET_32BIT ioctl
+    - libata: Align ata_device's id on a cacheline
+    - block: bio: introduce helpers to get the 1st and last bvec
+    - writeback: flush inode cgroup wb switches instead of pinning super_block
+    - Adding Intel Lewisburg device IDs for SATA
+    - arm64: vmemmap: use virtual projection of linear region
+    - PM / sleep / x86: Fix crash on graph trace through x86 suspend
+    - ata: ahci: don't mark HotPlugCapable Ports as external/removable
+    - tracing: Do not have 'comm' filter override event 'comm' field
+    - pata-rb532-cf: get rid of the irq_to_gpio() call
+    - Btrfs: fix loading of orphan roots leading to BUG_ON
+    - Revert "jffs2: Fix lock acquisition order bug in jffs2_write_begin"
+    - jffs2: Fix page lock / f->sem deadlock
+    - Fix directory hardlinks from deleted directories
+    - dmaengine: pxa_dma: fix cyclic transfers
+    - adv7604: fix tx 5v detect regression
+    - ALSA: usb-audio: Add a quirk for Plantronics DA45
+    - ALSA: ctl: Fix ioctls for X32 ABI
+    - ALSA: hda - Fix mic issues on Acer Aspire E1-472
+    - ALSA: rawmidi: Fix ioctls X32 ABI
+    - ALSA: timer: Fix ioctls for X32 ABI
+    - ALSA: pcm: Fix ioctls for X32 ABI
+    - ALSA: seq: oss: Don't drain at closing a client
+    - ALSA: hdspm: Fix wrong boolean ctl value accesses
+    - ALSA: hdsp: Fix wrong boolean ctl value accesses
+    - ALSA: hdspm: Fix zero-division
+    - ALSA: timer: Fix broken compat timer user status ioctl
+    - usb: chipidea: otg: change workqueue ci_otg as freezable
+    - USB: cp210x: Add ID for Parrot NMEA GPS Flight Recorder
+    - USB: qcserial: add Dell Wireless 5809e Gobi 4G HSPA+ (rev3)
+    - USB: qcserial: add Sierra Wireless EM74xx device ID
+    - USB: serial: option: add support for Telit LE922 PID 0x1045
+    - USB: serial: option: add support for Quectel UC20
+    - MIPS: scache: Fix scache init with invalid line size.
+    - MIPS: traps: Fix SIGFPE information leak from `do_ov' and `do_trap_or_bp'
+    - ubi: Fix out of bounds write in volume update code
+    - i2c: brcmstb: allocate correct amount of memory for regmap
+    - thermal: cpu_cooling: fix out of bounds access in time_in_idle
+    - block: check virt boundary in bio_will_gap()
+    - block: get the 1st and last bvec via helpers
+    - drm/i915: more virtual south bridge detection
+    - drm/i915: refine qemu south bridge detection
+    - modules: fix longstanding /proc/kallsyms vs module insertion race.
+    - drm/amdgpu: fix topaz/tonga gmc assignment in 4.4 stable
+    - Linux 4.4.5
+
+  * QEMU: causes vCPU steal time overflow on live migration (LP: #1494350)
+    - x86/mm: Fix slow_virt_to_phys() for X86_PAE again
+
+  * TPM2.0 trusted keys fixes (LP: #1398274)
+    - tpm_tis: further simplify calculation of ordinal duration
+    - tpm_tis: Use devm_free_irq not free_irq
+    - tpm_tis: Ensure interrupts are disabled when the driver starts
+    - tpm: rework tpm_get_timeouts()
+    - tpm_tis: Get rid of the duplicate IRQ probing code
+    - tpm_tis: Refactor the interrupt setup
+    - tpm_tis: Tighten IRQ auto-probing
+    - tpm_ibmvtpm: properly handle interrupted packet receptions
+
+  * linux: review all versioned depends/conflicts/replaces/breaks for validility (LP: #1555033)
+    - [Config] control.stub.in -- review versioned Build-Depends:
+    - [Config] control.stub.in -- review versioned
+      Depends/Breaks/Conflicts/Replaces
+    - [Config] flavour-control.stub -- review versioned Breaks/Conflicts/Replaces
+    - [Config] x86 vars.* -- review versioned Breaks/Conflicts/Replaces
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 09 Mar 2016 05:11:51 -0700
+
+linux (4.4.0-12.28) xenial; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - reconstruct: Work around orig tarball packaging limitiations
+      Fixes FTBS
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Mar 2016 13:26:08 -0700
+
+linux (4.4.0-12.27) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1554704
+
+  * Fails to detect (second) display (LP: #1543683)
+    - drm/i915: Fix hpd live status bits for g4x
+
+  * s390x -- various configuration changes (LP: #1543165)
+    - [Config] s390x -- enable CONFIG_NUMA
+    - [Config] s390x -- disable CONFIG_NET_VENDOR_EMULEX
+    - [Config] s390x -- disable CONFIG_NET_VENDOR_SYNOPSYS
+    - [Config] s390x -- disable CONFIG_NVMEM
+    - [Config] s390x -- switch preempt mode to none
+
+  * Radeon hybrid graphics problem on resume (LP: #1554608)
+    - Revert "drm/radeon: call hpd_irq_event on resume"
+
+  * Pull in upstream AMD code (amdgpu) in Xenial (LP: #1546572)
+    - [Config] CONFIG_DRM_AMD_POWERPLAY=y
+    - drm/amdgpu: use $(src) in Makefile (v2)
+    - drm/radeon: constify radeon_asic_ring structures
+    - drm/amdgpu: add a callback for reading the bios from the rom directly
+    - drm/amdgpu: add read_bios_from_rom callback for CI parts
+    - drm/amdgpu: add read_bios_from_rom callback for VI parts
+    - drm/amdgpu: Use new read bios from rom callback
+    - drm/amdgpu: Use unlocked gem unreferencing
+    - drm/radeon: Use unlocked gem unreferencing
+    - drm/amd: add new gfx8 register definitions for EDC
+    - drm/amdgpu: add EDC support for CZ (v3)
+    - drm/amd: abstract kernel rq and normal rq to priority of run queue
+    - drm/amdgpu/gfx8: Enable interrupt on ME1_PIPE3
+    - drm/amdgpu/gfx8: update PA_SC_RASTER_CONFIG:PKR_MAP only
+    - drm/amdgpu: update rev id register for VI
+    - drm/amdgpu: add more debugging output for driver failures
+    - drm/amdgpu: add entity only when first job come
+    - drm/amdgpu: handle error case for ctx
+    - drm/amdgpu: unify AMDGPU_CTX_MAX_CS_PENDING and amdgpu_sched_jobs
+    - drm/amdgpu: change default sched jobs to 32
+    - drm/amdgpu: limit visible vram if it's smaller than the BAR
+    - drm/amdgpu: restrict the sched jobs number to power of two
+    - drm/amdgpu: put VM page tables directly into duplicates list
+    - drm/amdgpu: split VM PD and PT handling during CS
+    - drm/amdgpu: keep the PTs validation list in the VM v2
+    - drm/radeon: Update radeon_get_vblank_counter_kms()
+    - drm/radeon: only increment sync_seq when a fence is really emitted
+    - drm/fb-helper: Use proper plane mask for fb cleanup
+    - drm/amdgpu: fix dp link rate selection (v2)
+    - drm/radeon: fix dp link rate selection (v2)
+    - drm/amdgpu: share struct amdgpu_pm_state_type with powerplay module
+    - drm/amdgpu: mv some definition from amdgpu_acpi.c to amdgpu_acpi.h
+    - drm/amdgpu: mv amdgpu_acpi.h to amd/include/amd_acpi.h
+    - drm/amdgpu: implement new cgs interface for acpi function
+    - drm/amdgpu: implement cgs interface to query system info
+    - drm/amdgpu: add new cgs interface to get display info (v2)
+    - drm/amd/powerplay: add basic powerplay framework
+    - drm/amdgpu: disable legacy path of firmware check if powerplay is enabled
+    - drm/amdgpu: export amd_powerplay_func to amdgpu and other ip block
+    - drm/amd/powerplay: add SMU manager sub-component
+    - drm/amd/powerplay: add hardware manager sub-component
+    - SAUCE: amd: Include errno.h
+    - drm/amd/powerplay: add Carrizo smu support
+    - drm/amd/powerplay: add Carrizo dpm support
+    - drm/amd/powerplay: add CG and PG support for carrizo
+    - drm/amd/powerplay: add event manager sub-component
+    - drm/amd/powerplay: implement functions of amd_powerplay_func
+    - drm/amd/powerplay: Add ixSWRST_COMMAND_1 in bif_5_0_d.h
+    - drm/amd/powerplay: Move smu7*.h from amdgpu to powerplay.
+    - drm/amd/powerplay: add header file for tonga smu and dpm
+    - drm/amd/powerplay: Add Tonga SMU support
+    - drm/amd/powerplay: add Tonga dpm support (v3)
+    - drm/amd/powerplay: add/update headers for Fiji SMU and DPM
+    - drm/amd/powerplay: update atomctrl for fiji
+    - drm/amd/powerplay: add Fiji SMU support.
+    - drm/amd/powerplay: add Fiji DPM support.
+    - drm/amdgpu: add amdgpu.powerplay module option
+    - drm/amd/amdgpu: enable powerplay and smc firmware loading for Fiji.
+    - drm/amdgpu/powerplay: add function point in hwmgr_funcs for program display gap
+    - drm/amdgpu/poweprlay: export program display gap function to eventmgr
+    - drm/amdgpu/powerplay: implement pem_task for display_configuration_change
+    - drm/amdgpu/powerplay: program display gap for tonga.
+    - drm/amdgpu: enable powerplay module by default for tonga.
+    - drm/amdgpu: enable powerplay module by default for fiji.
+    - drm/amdgpu/powerplay: add some definition for other ip block to update cg pg.
+    - drm/amd/powerplay: add new function point in hwmgr_func for CG/PG.
+    - drm/amd/powerplay: Add CG and PG support for tonga
+    - drm/amdgpu/powerplay: add new function point in hwmgr_funcs for thermal control
+    - drm/amdgpu/powerplay: mv ppinterrupt.h to inc folder to share with other submodule.
+    - drm/amdgpu/powerplay: add thermal control interface in hwmgr.
+    - drm/amdgpu/powerplay: enable thermal interrupt task in eventmgr.
+    - drm/amdgpu/powerplay: implement thermal control for tonga.
+    - drm/amdgpu/powerplay: implement fan control interface in amd_powerplay_funcs
+    - drm/amdgpu: export fan control functions to amdgpu
+    - drm/amdgpu: enable sysfs interface for powerplay
+    - drm/amdgpu: support per device powerplay enablement (v2)
+    - drm/amd/powerplay: add and export hwmgr interface to eventmgr to check hw states.
+    - drm/amd/powerplay: implement new funcs to check current states for tonga.
+    - drm/amd/powerplay: refine the logic of whether need to update power state.
+    - drm/amd/powerplay/tonga: enable pcie and mclk forcing for low
+    - drm/amd/powerplay/fiji: enable pcie and mclk forcing for low
+    - drm/amdgpu: extract pcie helpers to common header
+    - drm: add drm_pcie_get_max_link_width helper (v2)
+    - drm/amdgpu: store pcie gen mask and link width
+    - drm/amdgpu/cgs: add sys info query for pcie gen and link width
+    - drm/amdgpu/powerplay/tonga: query supported pcie info from cgs (v2)
+    - drm/amdgpu/powerplay/fiji: query supported pcie info from cgs (v2)
+    - drm/amd/powerplay: fix boolreturn.cocci warnings
+    - drm/amd/powerplay/tonga: Add UVD DPM init
+    - drm/amd/amdgpu: add gfx clock gating support for Fiji.
+    - drm/amd/amdgpu: add gmc clock gating support for Fiji.
+    - drm/amdgpu: add sdma clock gating support for Fiji.
+    - drm/amd/powerplay: add parts of system clock gating support for Fiji. (v2)
+    - drm/amd/powerplay: enable clock gating for Fiji.
+    - drm/amd/powerplay: add atomctrl function to calculate CZ sclk dividers
+    - drm/amd/powerplay: implement smc state upload for CZ
+    - drm/amd/powerplay: fix warning of cast to pointer from integer of different size.
+    - drm/amd/powerplay: fix warning of cast to pointer from integer of different size.
+    - drm/amd/powerplay: add new function point in hwmgr.
+    - drm/amd/powerplay: add smc msg for NB P-State switch
+    - drm/amd/powerplay: export interface to DAL to init/change display configuration.
+    - drm/amd/powerplay: enable set_cpu_power_state task. (v2)
+    - drm/amd/powerplay: enable/disable NB pstate feature for Carrizo.
+    - drm/amd/powerplay: Add PPLib debug print macro.
+    - drm/amdgpu: rename tonga_smumgr.h to tonga_smum.h
+    - drm/amdgpu: rename fiji_smumgr.h to fiji_smum.h
+    - drm/amd/powerplay: add multimedia power gating support for Fiji.
+    - drm/amd/amdgpu: add uvd6.0 clock gating support. (v2)
+    - drm/amd/amdgpu: add vce3.0 clock gating support. (v2)
+    - drm/amd/amdgpu: enable uvd&vce clock gating for Fiji.
+    - drm/amdgpu: Prepare DKMS build for powerplay module.
+    - drm/amd/powerplay: add display configeration changed function in hwmgr for Fiji.
+    - drm/amd/powerplay: Add thermal protection support for Fiji.
+    - drm/amd/powerplay: Fix a bug in fan control setting default mode for Tonga and Fiji.
+    - drm/amd/powerplay: add functions set/get_fan_control_mode in hwmgr for Tonga.
+    - drm/amd/powerplay: add functions set/get_fan_control_mode in hwmgr for Fiji.
+    - drm/amd/powerplay: fix boolreturn.cocci warnings
+    - drm/amd/powerplay: fix bug that dpm funcs in debugfs/sysfs missing.
+    - drm/amd/powerplay: check whether enable dpm in powerplay.
+    - drm/amd/powerplay: move shared function of vi to hwmgr. (v2)
+    - drm/amdgpu/powerplay: enable sysfs and debugfs interfaces late
+    - drm/amd/powerplay: display gpu load when print performance for tonga.
+    - drm/powerplay: add debugging output to tonga_processpptables.c
+    - drm/powerplay: add debugging output to processpptables.c
+    - drm/powerplay/hwmgr: log errors in tonga_hwmgr_backend_init
+    - drm/amd/powerplay: Don't return an error if fan table is missing
+    - amd\powerplay Implement get dal power level
+    - amd/powerplay: Fix get dal power level
+    - amd/powerplay: Add structures required to report configuration change
+    - drm/amdgpu/powerplay: Program a calculated value as Deep Sleep clock.
+    - drm/amd/powerplay: add point check to avoid NULL point hang.
+    - drm/amd/powerplay: check whether need to enable thermal control. (v2)
+    - drm/amd/powerplay: show gpu load when print gpu performance for Cz. (v2)
+    - drm: powerplay: use div64_s64 instead of do_div
+    - drm/amd/powerplay: fix a reversed condition
+    - drm/amdgpu/cgs: cleanup some indenting
+    - drm/amd/powerplay: precedence bug in init_non_clock_fields()
+    - drm/amdgpu: fix NULL in vm_grab_id while S3 back
+    - drm/amd/powerplay: fix bug that NULL checks are reversed.
+    - drm/amd/powerplay: fix Smatch static checker warnings with indenting (v2)
+    - drm/amd/powerplay: fix Smatch static checker warnings
+    - drm/amd/powerplay: add powerplay valid check to avoid null point. (v2)
+    - drm/amd/powerplay: Reload and initialize the smc firmware on powerplay resume.
+    - drm/amdgpu: Show gpu load when display gpu performance for Ci.
+    - drm/amdgpu: Show gpu load when display gpu performance for Fiji of VI.
+    - drm/amdgpu: fix hex/decimal bug when show gpu load.
+    - drm/amd/powerplay: add thermal control task when resume.
+    - drm/amd/powerplay: enable set boot state task
+    - drm/amd/powerplay: enable power down asic task. (v2)
+    - drm/amd/powerplay: implement power down asic task for CZ
+    - drm/amdgpu: add warning to amdgpu_bo_gpu_offset() v2
+    - drm/amdgpu/cgs: add an interface to access PCI resources
+    - drm/amdgpu: add irq domain support
+    - drm/amdgpu/powerplay: include asm/div64.h for do_div()
+    - drm/sysfs: use kobj_to_dev()
+    - drm/amd/powerplay: fix static checker warning for return meaningless value.
+    - drm/amdgpu/cz: add code to enable forcing UVD clocks
+    - drm/amdgpu/cz: add code to enable forcing VCE clocks
+    - drm/amdgpu/cz: force uvd clocks when sclks are forced
+    - drm/amdgpu/cz: force vce clocks when sclks are forced
+    - drm/amdgpu: use kobj_to_dev()
+    - drm/radeon: use kobj_to_dev()
+    - drm/ttm: fix adding foreign BOs to the LRU during init v2
+    - drm/ttm: fix adding foreign BOs to the swap LRU
+    - drm/ttm: add ttm_bo_move_to_lru_tail function v2
+    - drm/amdgpu: move VM page tables to the LRU end on CS v2
+    - drm/amdgpu: validate duplicates first
+    - drm/amdgpu: add missing irq.h include
+    - drm/fb_cma_helper: Remove implicit call to disable_unused_functions
+    - drm/amdgpu: Add some tweaks to gfx 8 soft reset
+    - amdkfd: don't open-code memdup_user()
+    - amdkfd: Copy from the proper user command pointer
+    - drm/amdgpu: Use drm_calloc_large for VM page_tables array
+    - amd/powerplay: disable powerplay by default initially
+    - drm/amdgpu: Allow the driver to load if amdgpu.powerplay=1 on asics without powerplay support
+    - drm/atomic-helper: Export framebuffer_changed()
+    - drm/amd/amdgpu: Improve amdgpu_dpm* macros to avoid unexpected result (v2)
+    - drm/amdgpu: add a message to indicate when powerplay is enabled (v2)
+    - drm/amdgpu: fix next_rptr handling for debugfs
+    - drm/radeon: Ensure radeon bo is unreserved in radeon_gem_va_ioctl
+    - drm/radeon: only init fbdev if we have connectors
+    - drm/amdgpu: don't init fbdev if we don't have any connectors
+    - drm/amd/powerplay: Update SMU firmware loading for Stoney
+    - drm/amdgpu: fix non-ANSI declaration of amdgpu_amdkfd_gfx_*_get_functions()
+    - drm/amdkfd: Remove unnecessary cast in kfree
+    - drm/amdgpu: only move pt bos in LRU list on success
+    - drm/amdgpu: mask out WC from BO on unsupported arches
+    - drm/amdgpu/gfx8: enable cp inst/reg error interrupts
+    - drm/amdgpu/gfx7: enable cp inst/reg error interrupts
+    - drm/amdgpu: load MEC ucode manually on iceland
+    - drm/amdgpu: disable uvd and vce clockgating on Fiji
+    - drm/amdgpu: add pcie cap module parameters (v2)
+    - drm/amdgpu/cik: don't mess with aspm if gpu is root bus
+    - drm/amdgpu/dpm/ci: switch over to the common pcie caps interface
+    - drm/amdgpu: handle uvd pg flags properly
+    - drm/amdgpu: handle vce pg flags properly
+    - drm/amdgpu: clean up vce pg flags for cz/st
+    - drm/amdgpu: be consistent with uvd cg flags
+    - drm/amd/powerplay/cz: disable uvd pg
+    - drm/amd/powerplay/cz: disable vce pg
+    - drm/amd/powerplay/tonga: disable uvd pg
+    - drm/amd/powerplay/tonga: disable vce pg
+    - drm/amdgpu: add a cgs interface to fetch cg and pg flags
+    - drm/amdgpu: remove unused cg defines
+    - drma/dmgpu: move cg and pg flags into shared headers
+    - drm/amdgpu/tonga: plumb pg flags through to powerplay
+    - drm/amdgpu/cz: plumb pg flags through to powerplay
+    - SAUCE: drm/amdgpu/cz: enable/disable vce dpm even if vce pg is disabled
+
+  * mlx4_core Set UAR page size to 4KB regardless of system page size (LP:
+    #1552632)
+    - net/mlx4_core: Set UAR page size to 4KB regardless of system page size
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_CAVIUM_ERRATUM_27456=y
+
+  * Miscellaneous upstream changes
+    - net: thunderx: Fix for Qset error due to CQ full
+    - ahci: Workaround for ThunderX Errata#22536
+    - arm64: Add workaround for Cavium erratum 27456
+    - tipc: fix nullptr crash during subscription cancel
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 07 Mar 2016 05:04:22 -0700
+
+linux (4.4.0-11.26) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1553391
+
+  * Xenial update to v4.4.4 stable release (LP: #1553179)
+    - af_iucv: Validate socket address length in iucv_sock_bind()
+    - gro: Make GRO aware of lightweight tunnels.
+    - net: dp83640: Fix tx timestamp overflow handling.
+    - tunnels: Allow IPv6 UDP checksums to be correctly controlled.
+    - lwt: fix rx checksum setting for lwt devices tunneling over ipv6
+    - tcp: fix NULL deref in tcp_v4_send_ack()
+    - af_unix: fix struct pid memory leak
+    - pptp: fix illegal memory access caused by multiple bind()s
+    - sctp: allow setting SCTP_SACK_IMMEDIATELY by the application
+    - net: dsa: fix mv88e6xxx switches
+    - tipc: fix connection abort during subscription cancel
+    - inet: frag: Always orphan skbs inside ip_defrag()
+    - switchdev: Require RTNL mutex to be held when sending FDB notifications
+    - tcp: beware of alignments in tcp_get_info()
+    - ipv6: enforce flowi6_oif usage in ip6_dst_lookup_tail()
+    - ipv6/udp: use sticky pktinfo egress ifindex on connect()
+    - ipv6: addrconf: Fix recursive spin lock call
+    - ipv6: fix a lockdep splat
+    - unix: correctly track in-flight fds in sending process user_struct
+    - tcp: do not drop syn_recv on all icmp reports
+    - net:Add sysctl_max_skb_frags
+    - tg3: Fix for tg3 transmit queue 0 timed out when too many gso_segs
+    - enic: increment devcmd2 result ring in case of timeout
+    - sctp: translate network order to host order when users get a hmacid
+    - net: Copy inner L3 and L4 headers as unaligned on GRE TEB
+    - flow_dissector: Fix unaligned access in __skb_flow_dissector when used by
+      eth_get_headlen
+    - bpf: fix branch offset adjustment on backjumps after patching ctx expansion
+    - bonding: Fix ARP monitor validation
+    - ipv4: fix memory leaks in ip_cmsg_send() callers
+    - af_unix: Don't set err in unix_stream_read_generic unless there was an error
+    - af_unix: Guard against other == sk in unix_dgram_sendmsg
+    - tipc: fix premature addition of node to lookup table
+    - tcp: md5: release request socket instead of listener
+    - qmi_wwan: add "4G LTE usb-modem U901"
+    - net/mlx4_en: Count HW buffer overrun only once
+    - net/mlx4_en: Avoid changing dev->features directly in run-time
+    - l2tp: Fix error creating L2TP tunnels
+    - pppoe: fix reference counting in PPPoE proxy
+    - net_sched fix: reclassification needs to consider ether protocol changes
+    - route: check and remove route cache when we get route
+    - tcp/dccp: fix another race at listener dismantle
+    - IFF_NO_QUEUE: Fix for drivers not calling ether_setup()
+    - rtnl: RTM_GETNETCONF: fix wrong return value
+    - tipc: unlock in error path
+    - unix_diag: fix incorrect sign extension in unix_lookup_by_ino
+    - sctp: Fix port hash table size computation
+    - ext4: fix bh->b_state corruption
+    - ARM: debug-ll: fix BCM63xx entry for multiplatform
+    - arm64: errata: Add -mpc-relative-literal-loads to build flags
+    - KVM: s390: fix guest fprs memory leak
+    - devm_memremap: Fix error value when memremap failed
+    - drm/gma500: Use correct unref in the gem bo create function
+    - ARM: 8457/1: psci-smp is built only for SMP
+    - lib/ucs2_string: Add ucs2 -> utf8 helper functions
+    - efi: Use ucs2_as_utf8 in efivarfs instead of open coding a bad version
+    - efi: Do variable name validation tests in utf8
+    - efi: Make our variable validation list include the guid
+    - efi: Make efivarfs entries immutable by default
+    - efi: Add pstore variables to the deletion whitelist
+    - lib/ucs2_string: Correct ucs2 -> utf8 conversion
+    - bcache: fix a livelock when we cause a huge number of cache misses
+    - bcache: Add a cond_resched() call to gc
+    - bcache: clear BCACHE_DEV_UNLINK_DONE flag when attaching a backing device
+    - bcache: fix a leak in bch_cached_dev_run()
+    - bcache: unregister reboot notifier if bcache fails to unregister device
+    - bcache: allows use of register in udev to avoid "device_busy" error.
+    - bcache: Change refill_dirty() to always scan entire disk if necessary
+    - dm thin: fix race condition when destroying thin pool workqueue
+    - can: ems_usb: Fix possible tx overflow
+    - usb: dwc3: Fix assignment of EP transfer resources
+    - USB: cp210x: add IDs for GE B650V3 and B850V3 boards
+    - USB: option: add support for SIM7100E
+    - USB: option: add "4G LTE usb-modem U901"
+    - drivers: android: correct the size of struct binder_uintptr_t for
+      BC_DEAD_BINDER_DONE
+    - spi: omap2-mcspi: Prevent duplicate gpio_request
+    - iw_cxgb3: Fix incorrectly returning error on success
+    - drm/i915: shut up gen8+ SDE irq dmesg noise
+    - ocfs2: unlock inode if deleting inode from orphan fails
+    - mm: thp: fix SMP race condition between THP page fault and MADV_DONTNEED
+    - mm: numa: quickly fail allocations for NUMA balancing on full nodes
+    - genirq: Validate action before dereferencing it in handle_irq_event_percpu()
+    - clocksource/drivers/vt8500: Increase the minimum delta
+    - s390/kvm: remove dependency on struct save_area definition
+    - KVM: s390: fix memory overwrites when vx is disabled
+    - Btrfs: add missing brelse when superblock checksum fails
+    - Btrfs: igrab inode in writepage
+    - btrfs: statfs: report zero available if metadata are exhausted
+    - Btrfs: send, don't BUG_ON() when an empty symlink is found
+    - Btrfs: fix number of transaction units required to create symlink
+    - Btrfs: fix transaction handle leak on failure to create hard link
+    - Btrfs: Initialize btrfs_root->highest_objectid when loading tree root and
+      subvolume roots
+    - btrfs: initialize the seq counter in struct btrfs_device
+    - s390: fix normalization bug in exception table sorting
+    - s390/dasd: prevent incorrect length error under z/VM after PAV changes
+    - s390/dasd: fix refcount for PAV reassignment
+    - s390/dasd: fix performance drop
+    - uml: flush stdout before forking
+    - uml: fix hostfs mknod()
+    - um: link with -lpthread
+    - locks: fix unlock when fcntl_setlk races with a close
+    - rtlwifi: rtl_pci: Fix kernel panic
+    - rtlwifi: rtl8192cu: Add missing parameter setup
+    - rtlwifi: rtl8192ce: Fix handling of module parameters
+    - rtlwifi: rtl8192de: Fix incorrect module parameter descriptions
+    - rtlwifi: rtl8723ae: Fix initialization of module parameters
+    - rtlwifi: rtl8192se: Fix module parameter initialization
+    - rtlwifi: rtl8188ee: Fix module parameter initialization
+    - rtlwifi: rtl8723be: Fix module parameter initialization
+    - mei: fix fasync return value on error
+    - mei: validate request value in client notify request ioctl
+    - namei: ->d_inode of a pinned dentry is stable only for positives
+    - rc: sunxi-cir: Initialize the spinlock properly
+    - media: dvb-core: Don't force CAN_INVERSION_AUTO in oneshot mode
+    - si2157: return -EINVAL if firmware blob is too big
+    - gspca: ov534/topro: prevent a division by 0
+    - vb2: fix a regression in poll() behavior for output,streams
+    - tda1004x: only update the frontend properties if locked
+    - dm space map metadata: remove unused variable in brb_pop()
+    - dm snapshot: fix hung bios when copy error occurs
+    - dm: fix dm_rq_target_io leak on faults with .request_fn DM w/ blk-mq paths
+    - coresight: checking for NULL string in coresight_name_match()
+    - irqchip/omap-intc: Add support for spurious irq handling
+    - irqchip/mxs: Add missing set_handle_irq()
+    - irqchip/atmel-aic: Fix wrong bit operation for IRQ priority
+    - irqchip/gic-v3-its: Fix double ICC_EOIR write for LPI in EOImode==1
+    - posix-clock: Fix return code on the poll method's error path
+    - clockevents/tcb_clksrc: Prevent disabling an already disabled clock
+    - mmc: usdhi6rol0: handle NULL data in timeout
+    - mmc: sdhci-pci: Do not default to 33 Ohm driver strength for Intel SPT
+    - mmc: sdio: Fix invalid vdd in voltage switch power cycle
+    - mmc: mmc: Fix incorrect use of driver strength switching HS200 and HS400
+    - mmc: sdhci: Fix sdhci_runtime_pm_bus_on/off()
+    - mmc: core: Enable tuning according to the actual timing
+    - mmc: mmci: fix an ages old detection error
+    - mmc: sdhci-acpi: Fix card detect race for Intel BXT/APL
+    - mmc: pxamci: fix again read-only gpio detection polarity
+    - mmc: sdhci-pci: Fix card detect race for Intel BXT/APL
+    - mmc: sdhci: Allow override of mmc host operations
+    - mmc: sdhci: Allow override of get_cd() called from sdhci_request()
+    - Bluetooth: Use continuous scanning when creating LE connections
+    - Bluetooth: Add support of Toshiba Broadcom based devices
+    - Bluetooth: Fix incorrect removing of IRKs
+    - Bluetooth: 6lowpan: Fix kernel NULL pointer dereferences
+    - Bluetooth: 6lowpan: Fix handling of uncompressed IPv6 packets
+    - time: Avoid signed overflow in timekeeping_get_ns()
+    - cputime: Prevent 32bit overflow in time[val|spec]_to_cputime()
+    - Revert "MIPS: Fix PAGE_MASK definition"
+    - MIPS: Loongson-3: Fix SMP_ASK_C0COUNT IPI handler
+    - MIPS: hpet: Choose a safe value for the ETIME check
+    - MIPS: Fix some missing CONFIG_CPU_MIPSR6 #ifdefs
+    - MIPS: Fix buffer overflow in syscall_get_arguments()
+    - EDAC: Robustify workqueues destruction
+    - EDAC, mc_sysfs: Fix freeing bus' name
+    - sparc64: fix incorrect sign extension in sys_sparc64_personality
+    - clk: exynos: use irqsave version of spin_lock to avoid deadlock with irqs
+    - regulator: axp20x: Fix GPIO LDO enable value for AXP22x
+    - regulator: mt6311: MT6311_REGULATOR needs to select REGMAP_I2C
+    - virtio_balloon: fix race by fill and leak
+    - virtio_balloon: fix race between migration and ballooning
+    - virtio_pci: fix use after free on release
+    - drm/vmwgfx: Fix an incorrect lock check
+    - drm/vmwgfx: Fix a width / pitch mismatch on framebuffer updates
+    - drm/vmwgfx: respect 'nomodeset'
+    - drm/amdgpu: Fix off-by-one errors in amdgpu_vm_bo_map
+    - drm/amdgpu: call hpd_irq_event on resume
+    - drm/amdgpu: fix lost sync_to if scheduler is enabled.
+    - drm/amdgpu: fix tonga smu resume
+    - drm/amdgpu: fix amdgpu_bo_pin_restricted VRAM placing v2
+    - drm/amdgpu: no need to load MC firmware on fiji
+    - drm/amdgpu: move gmc7 support out of CIK dependency
+    - drm/amdgpu: iceland use CI based MC IP
+    - drm/amdgpu: The VI specific EXE bit should only apply to GMC v8.0 above
+    - drm/amdgpu: pull topaz gmc bits into gmc_v7
+    - drm/amdgpu: drop topaz support from gmc8 module
+    - drm/amdgpu: don't load MEC2 on topaz
+    - drm/amdgpu: remove exp hardware support from iceland
+    - drm/amdgpu: fix s4 resume
+    - drm/amdgpu: remove unnecessary forward declaration
+    - drm/amdgpu: hold reference to fences in amdgpu_sa_bo_new (v2)
+    - drm/amdgpu: fix issue with overlapping userptrs
+    - drm/amdgpu: use post-decrement in error handling
+    - drm/amdgpu: Don't hang in amdgpu_flip_work_func on disabled crtc.
+    - drm/amdgpu/pm: adjust display configuration after powerstate
+    - drm/nouveau/kms: take mode_config mutex in connector hotplug path
+    - drm/nouveau/display: Enable vblank irqs after display engine is on again.
+    - drm/nouveau/disp/dp: ensure sink is powered up before attempting link
+      training
+    - drm/nouveau: platform: Fix deferred probe
+    - drm/dp/mst: process broadcast messages correctly
+    - drm/dp/mst: always send reply for UP request
+    - drm/dp/mst: fix in MSTB RAD initialization
+    - drm/dp/mst: fix in RAD element access
+    - drm: Add drm_fixp_from_fraction and drm_fixp2int_ceil
+    - drm/dp/mst: Calculate MST PBN with 31.32 fixed point
+    - drm/dp/mst: move GUID storage from mgr, port to only mst branch
+    - drm/dp/mst: Reverse order of MST enable and clearing VC payload table.
+    - drm/dp/mst: deallocate payload on port destruction
+    - drm/radeon: Fix off-by-one errors in radeon_vm_bo_set_addr
+    - drm/radeon: call hpd_irq_event on resume
+    - drm/radeon: Fix "slow" audio over DP on DCE8+
+    - drm/radeon: clean up fujitsu quirks
+    - drm/radeon: properly byte swap vce firmware setup
+    - drm/radeon: cleaned up VCO output settings for DP audio
+    - drm/radeon: Add a common function for DFS handling
+    - drm/radeon: fix DP audio support for APU with DCE4.1 display engine
+    - drm: add helper to check for wc memory support
+    - drm/radeon: mask out WC from BO on unsupported arches
+    - drm/radeon: hold reference to fences in radeon_sa_bo_new
+    - drm: fix missing reference counting decrease
+    - drm/i915: Restore inhibiting the load of the default context
+    - drm/i915: intel_hpd_init(): Fix suspend/resume reprobing
+    - drm/i915: Init power domains early in driver load
+    - drm/i915: Make sure DC writes are coherent on flush.
+    - drm/i915/dp: fall back to 18 bpp when sink capability is unknown
+    - drm/i915: Don't reject primary plane windowing with color keying enabled on
+      SKL+
+    - drm/i915/skl: Don't skip mst encoders in skl_ddi_pll_select()
+    - drm/i915/dsi: defend gpio table against out of bounds access
+    - drm/i915/dsi: don't pass arbitrary data to sideband
+    - drm/i915: fix error path in intel_setup_gmbus()
+    - drm/qxl: use kmalloc_array to alloc reloc_info in qxl_process_single_command
+    - drm/radeon: use post-decrement in error handling
+    - drm: No-Op redundant calls to drm_vblank_off() (v2)
+    - drm: Prevent vblank counter bumps > 1 with active vblank clients. (v2)
+    - drm: Fix drm_vblank_pre/post_modeset regression from Linux 4.4
+    - drm: Fix treatment of drm_vblank_offdelay in drm_vblank_on() (v2)
+    - drm/radeon: Don't hang in radeon_flip_work_func on disabled crtc. (v2)
+    - drm/radeon/pm: adjust display configuration after powerstate
+    - make sure that freeing shmem fast symlinks is RCU-delayed
+    - toshiba_acpi: Fix blank screen at boot if transflective backlight is
+      supported
+    - ideapad-laptop: Add Lenovo ideapad Y700-17ISK to no_hw_rfkill dmi list
+    - ideapad-laptop: Add Lenovo Yoga 700 to no_hw_rfkill dmi list
+    - uapi: update install list after nvme.h rename
+    - lib: sw842: select crc32
+    - ACPI / video: Add disable_backlight_sysfs_if quirk for the Toshiba Portege
+      R700
+    - ACPI / video: Add disable_backlight_sysfs_if quirk for the Toshiba Satellite
+      R830
+    - ACPI: Revert "ACPI / video: Add Dell Inspiron 5737 to the blacklist"
+    - ACPI / PCI / hotplug: unlock in error path in acpiphp_enable_slot()
+    - nfit: fix multi-interface dimm handling, acpi6.1 compatibility
+    - dmaengine: dw: fix cyclic transfer setup
+    - dmaengine: dw: fix cyclic transfer callbacks
+    - dmaengine: at_xdmac: fix resume for cyclic transfers
+    - dmaengine: dw: disable BLOCK IRQs for non-cyclic xfer
+    - IB/cm: Fix a recently introduced deadlock
+    - IB/qib: fix mcast detach when qp not attached
+    - IB/qib: Support creating qps with GFP_NOIO flag
+    - IB/mlx5: Expose correct maximum number of CQE capacity
+    - Thermal: initialize thermal zone device correctly
+    - Thermal: handle thermal zone device properly during system sleep
+    - Thermal: do thermal zone update after a cooling device registered
+    - hwmon: (dell-smm) Blacklist Dell Studio XPS 8000
+    - hwmon: (gpio-fan) Remove un-necessary speed_index lookup for thermal hook
+    - hwmon: (ads1015) Handle negative conversion values correctly
+    - cpufreq: pxa2xx: fix pxa_cpufreq_change_voltage prototype
+    - cpufreq: Fix NULL reference crash while accessing policy->governor_data
+    - seccomp: always propagate NO_NEW_PRIVS on tsync
+    - libceph: fix ceph_msg_revoke()
+    - libceph: don't bail early from try_read() when skipping a message
+    - libceph: use the right footer size when skipping a message
+    - libceph: don't spam dmesg with stray reply warnings
+    - sd: Optimal I/O size is in bytes, not sectors
+    - Staging: speakup: Fix getting port information
+    - Revert "Staging: panel: usleep_range is preferred over udelay"
+    - cdc-acm:exclude Samsung phone 04e8:685d
+    - perf stat: Do not clean event's private stats
+    - tick/nohz: Set the correct expiry when switching to nohz/lowres mode
+    - rfkill: fix rfkill_fop_read wait_event usage
+    - mac80211: Requeue work after scan complete for all VIF types.
+    - workqueue: handle NUMA_NO_NODE for unbound pool_workqueue lookup
+    - Revert "workqueue: make sure delayed work run in local cpu"
+    - ALSA: hda - Apply clock gate workaround to Skylake, too
+    - ALSA: hda - Fixing background noise on Dell Inspiron 3162
+    - target: Fix LUN_RESET active I/O handling for ACK_KREF
+    - target: Fix LUN_RESET active TMR descriptor handling
+    - target: Fix TAS handling for multi-session se_node_acls
+    - target: Fix remote-port TMR ABORT + se_cmd fabric stop
+    - target: Fix race with SCF_SEND_DELAYED_TAS handling
+    - spi: atmel: fix gpio chip-select in case of non-DT platform
+    - libata: fix sff host state machine locking while polling
+    - ARCv2: STAR 9000950267: Handle return from intr to Delay Slot #2
+    - ARCv2: SMP: Emulate IPI to self using software triggered interrupt
+    - PCI/AER: Flush workqueue on device remove to avoid use-after-free
+    - cpuset: make mm migration asynchronous
+    - cgroup: make sure a parent css isn't offlined before its children
+    - writeback: keep superblock pinned during cgroup writeback association
+      switches
+    - phy: core: fix wrong err handle for phy_power_on
+    - i2c: i801: Adding Intel Lewisburg support for iTCO
+    - bio: return EINTR if copying to user space got interrupted
+    - block: fix use-after-free in dio_bio_complete
+    - nfs: fix nfs_size_to_loff_t
+    - NFSv4: Fix a dentry leak on alias use
+    - of/irq: Fix msi-map calculation for nonzero rid-base
+    - KVM: async_pf: do not warn on page allocation failures
+    - KVM: arm/arm64: vgic: Ensure bitmaps are long enough
+    - KVM: x86: fix missed hardware breakpoints
+    - KVM: x86: MMU: fix ubsan index-out-of-range warning
+    - powerpc/eeh: Fix partial hotplug criterion
+    - tracing: Fix showing function event in available_events
+    - sunrpc/cache: fix off-by-one in qword_get()
+    - kernel/resource.c: fix muxed resource handling in __request_region()
+    - do_last(): don't let a bogus return value from ->open() et.al. to confuse us
+    - ARM: OMAP2+: Fix onenand initialization to avoid filesystem corruption
+    - ARM: at91/dt: fix typo in sama5d2 pinmux descriptions
+    - xen/arm: correctly handle DMA mapping of compound pages
+    - xen/scsiback: correct frontend counting
+    - xen/pciback: Check PF instead of VF for PCI_COMMAND_MEMORY
+    - xen/pciback: Save the number of MSI-X entries to be copied later.
+    - xen/pcifront: Fix mysterious crashes when NUMA locality information was
+      extracted.
+    - should_follow_link(): validate ->d_seq after having decided to follow
+    - do_last(): ELOOP failure exit should be done after leaving RCU mode
+    - hpfs: don't truncate the file when delete fails
+    - x86/irq: Call chip->irq_set_affinity in proper context
+    - x86/irq: Fix a race in x86_vector_free_irqs()
+    - x86/irq: Validate that irq descriptor is still active
+    - x86/irq: Do not use apic_chip_data.old_domain as temporary buffer
+    - x86/irq: Reorganize the return path in assign_irq_vector
+    - x86/irq: Reorganize the search in assign_irq_vector
+    - x86/irq: Check vector allocation early
+    - x86/irq: Copy vectormask instead of an AND operation
+    - x86/irq: Get rid of code duplication
+    - x86/irq: Remove offline cpus from vector cleanup
+    - x86/irq: Clear move_in_progress before sending cleanup IPI
+    - x86/irq: Remove the cpumask allocation from send_cleanup_vector()
+    - x86/irq: Remove outgoing CPU from vector cleanup mask
+    - x86/irq: Call irq_force_move_complete with irq descriptor
+    - x86/irq: Plug vector cleanup race
+    - IB/cma: Fix RDMA port validation for iWarp
+    - iwlwifi: dvm: fix WoWLAN
+    - iwlwifi: pcie: properly configure the debug buffer size for 8000
+    - iwlwifi: update and fix 7265 series PCI IDs
+    - iwlwifi: mvm: don't allow sched scans without matches to be started
+    - Revert "UBUNTU: SAUCE: bcache: prevent crash on changing writeback_running"
+    - bcache: prevent crash on changing writeback_running
+    - Linux 4.4.4
+
+  * mlx4_en didn't choose time-stamping shift value according to HW frequency
+    (LP: #1552627)
+    - net/mlx4_en: Choose time-stamping shift value according to HW frequency
+
+  * [Ubuntu 16.04] Help to flush kernel panics to console (LP: #1552332)
+    - target/transport: add flag to indicate CPU Affinity is observed
+    - powerpc/powernv: Add a kmsg_dumper that flushes console output on panic
+    - powerpc/powernv: Fix OPAL_CONSOLE_FLUSH prototype and usages
+
+  * [Ubuntu 16.04] Update qla2xxx driver for POWER (QLogic) (LP: #1541456)
+    - qla2xxx: Fix warning reported by static checker
+    - qla2xxx: Fix TMR ABORT interaction issue between qla2xxx and TCM
+    - qla2xxx: Fix stale pointer access.
+    - qla2xxx: Use ATIO type to send correct tmr response
+    - qla2xxx: use TARGET_SCF_USE_CPUID flag to indiate CPU Affinity
+
+  * [s390x] zfcp.ko missing from scsi-modules udeb (LP: #1552314)
+    - [Config] Add s390x zfcp to scsi-modules udeb
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 02 Mar 2016 08:08:16 -0700
+
+linux (4.4.0-10.25) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1552247
+
+  * linux:  4.4.0-9.X fails yama ptrace restrictions tests (LP: #1551894)
+    - security: let security modules use PTRACE_MODE_* with bitmasks
+
+  * [wily][regression] systemtap script compilation broken by new kernels (LP: #1545330)
+    - SAUCE: (noup) locking/qspinlock: Move __ARCH_SPIN_LOCK_UNLOCKED to qspinlock_types.h
+
+  * [Feature]SD/SDIO/eMMC support for Broxton-P (LP: #1520454)
+    - mmc: sdhci: 64-bit DMA actually has 4-byte alignment
+    - mmc: sdhci: Fix DMA descriptor with zero data length
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) cgroup: fix and restructure error handling in copy_cgroup_ns()
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 29 Feb 2016 13:04:14 -0700
+
+linux (4.4.0-9.24) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1551319
+
+  * AppArmor logs denial for when the device path is ENOENT (LP: #1482943)
+    - SAUCE: apparmor: fix log of apparmor audit message when kern_path() fails
+
+  * BUG: unable to handle kernel NULL pointer dereference (aa_label_merge) (LP:
+    #1448912)
+    - SAUCE: apparmor: Fix: insert race between label_update and label_merge
+    - SAUCE: apparmor: Fix: ensure aa_get_newest will trip debugging if the
+      replacedby is not setup
+    - SAUCE: apparmor: Fix: label merge handling of marking unconfined and stale
+    - SAUCE: apparmor: Fix: refcount race between locating in labelset and get
+    - SAUCE: apparmor: Fix: ensure new labels resulting from merge have a
+      replacedby
+    - SAUCE: apparmor: Fix: label_vec_merge insertion
+    - SAUCE: apparmor: Fix: deadlock in aa_put_label() call chain
+    - SAUCE: apparmor: Fix: add required locking of __aa_update_replacedby on
+      merge path
+    - SAUCE: apparmor: Fix: convert replacedby update to be protected by the
+      labelset lock
+    - SAUCE: apparmor: Fix: update replacedby allocation to take a gfp parameter
+
+  * apparmor kernel BUG kills firefox (LP: #1430546)
+    - SAUCE: apparmor: Disallow update of cred when then subjective != the
+      objective cred
+    - SAUCE: apparmor: rework retrieval of the current label in the profile update
+      case
+
+  * sleep from invalid context in aa_move_mount (LP: #1539349)
+    - SAUCE: apparmor: fix sleep from invalid context
+
+  * s390x: correct restore of high gprs on signal return (LP: #1550468)
+    - s390/compat: correct restore of high gprs on signal return
+
+  * missing SMAP support (LP: #1550517)
+    - x86/entry/compat: Add missing CLAC to entry_INT80_32
+
+  * Floating-point exception handler receives empty Data-Exception Code in
+    Floating Point Control register (LP: #1548414)
+    - s390/fpu: signals vs. floating point control register
+
+  * kvm fails to boot GNU Hurd kernels with 4.4 Xenial kernel (LP: #1550596)
+    - KVM: x86: fix conversion of addresses to linear in 32-bit protected mode
+
+  * Surelock GA2 SP1: capiredp01: cxl_init_adapter fails for CAPI devices
+    0000:01:00.0 and 0005:01:00.0 after upgrading to 840.10 Platform firmware
+    build fips840/b1208b_1604.840 (LP: #1532914)
+    - cxl: Fix PSL timebase synchronization detection
+
+  * [Feature]EDAC support for Knights Landing (LP: #1519631)
+    - EDAC, sb_edac: Set fixed DIMM width on Xeon Knights Landing
+
+  * Various failures of kernel_security suite on Xenial kernel on s390x arch
+    (LP: #1531327)
+    - [config] s390x -- CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+
+  * Unable to install VirtualBox Guest Service in 15.04 (LP: #1434579)
+    - [Config] Provides: virtualbox-guest-modules when appropriate
+
+  * linux is missing provides for virtualbox-guest-modules [i386 amd64 x32] (LP:
+    #1507588)
+    - [Config] Provides: virtualbox-guest-modules when appropriate
+
+  * Backport more recent driver for SKL, KBL and BXT graphics (LP: #1540390)
+    - SAUCE: i915_bpo: Provide a backport driver for SKL, KBL & BXT graphics
+    - SAUCE: i915_bpo: Update intel_ips.h file location
+    - SAUCE: i915_bpo: Rename the backport driver to i915_bpo
+    - SAUCE: i915_bpo: Add i915_bpo_*() calls for ubuntu/i915
+    - drm/i915: remove an extra level of indirection in PCI ID list
+    - drm/i915/kbl: Add Kabylake PCI ID
+    - drm/i915/kbl: Add Kabylake GT4 PCI ID
+    - mm: Export nr_swap_pages
+    - async: export current_is_async()
+    - drm: fix potential dangling else problems in for_each_ macros
+    - dp/mst: add SDP stream support
+    - drm: Implement drm_modeset_lock_all_ctx()
+    - drm: Add "prefix" parameter to drm_rect_debug_print()
+    - drm/i915: Set connector_state->connector using the helper.
+    - drm/atomic: add connector mask to drm_crtc_state.
+    - drm/i915: Report context GTT size
+    - drm/i915: Add get_eld audio component
+    - SAUCE: Backport I915_PARAM_HAS_EXEC_SOFTPIN and EXEC_OBJECT_PINNED
+    - SAUCE: i915_bpo: Revert passing plane/encoder name
+    - SAUCE: sound/hda: Load i915_bpo from the hda driver on SKL/KBL/BXT
+    - SAUCE: i915_bpo: Support only SKL, KBL and BXT with the backport driver
+    - drm/i915/bxt: update list of PCIIDs
+    - drm/i915/skl: Add missing SKL ids
+    - SAUCE: i915_bpo: Revert "drm/i915: Defer probe if gmux is present but its
+      driver isn't"
+    - SAUCE: uapi/drm/i915: Backport I915_EXEC_BSD_MASK
+    - drm/atomic: Do not unset crtc when an encoder is stolen
+    - drm/i915: Update connector_mask during readout, v2.
+    - drm/atomic: Add encoder_mask to crtc_state, v3.
+    - SAUCE: drm/core: Add drm_encoder_index.
+    - SAUCE: i915_bpo: Revert "drm/i915: Switch DDC when reading the EDID"
+    - i915_bpo: [Config] Enable CONFIG_DRM_I915_BPO=m
+
+  * arm64: guest hangs when ntpd is running (LP: #1549494)
+    - hrtimer: Add support for CLOCK_MONOTONIC_RAW
+    - hrtimer: Catch illegal clockids
+    - KVM: arm/arm64: timer: Switch to CLOCK_MONOTONIC_RAW
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] git-ubuntu-log -- wrap long bug and commit titles
+    - [Config] CONFIG_ARM_SMMU=y on arm64
+    - rebase to v4.4.3
+    - [Debian] git-ubuntu-log -- ensure we get the last commit
+    - [Config] fix up spelling of probably again
+    - [Debian] perf -- build in the context of the full generated local headers
+    - SAUCE: tools: lib/bpf -- add generated headers to search path
+    - SAUCE: proc: Always set super block owner to init_user_ns
+    - SAUCE: fix-up: kern_mount fail path should not be doing put_buffers()
+    - SAUCE: apparmor: Fix: oops do to invalid null ptr deref in label print fns
+    - SAUCE: apparmor: debug: POISON label and replaceby pointer on free
+    - SAUCE: apparmor: add underscores to indicate aa_label_next_not_in_set() use
+      needs locking
+    - SAUCE: apparmor: Fix: refcount leak in aa_label_merge
+    - SAUCE: apparmor: ensure that repacedby sharing is done correctly
+    - SAUCE: apparmor Fix: refcount bug in pivotroot mediation
+    - SAUCE: apparmor: Fix: now that insert can force replacement use it instead
+      of remove_and_insert
+    - SAUCE: apparmor: Fix: refcount bug when inserting label update that
+      transitions ns
+    - SAUCE: apparmor: Fix: break circular refcount for label that is directly
+      freed.
+    - SAUCE: apparmor: Don't remove label on rcu callback if the label has already
+      been removed
+    - SAUCE: apparmor: Fix: query label file permission
+    - SAUCE: apparmor: fix: ref count leak when profile sha1 hash is read
+    - SAUCE: fixup: cleanup return handling of labels
+    - SAUCE: fix: replacedby forwarding is not being properly update when ns is
+      destroyed
+    - SAUCE: fixup: make __share_replacedby private to get rid of build warning
+    - SAUCE: fixup: 20/23 locking issue around in __label_update
+    - SAUCE: fixup: get rid of unused var build warning
+    - SAUCE: fixup: cast poison values to remove warnings
+    - SAUCE: apparmor: fix refcount race when finding a child profile
+    - SAUCE: fixup: warning about aa_label_vec_find_or_create not being static
+    - SAUCE: fix: audit "no_new_privs" case for exec failure
+    - SAUCE: Fixup: __label_update() still doesn't handle some cases correctly.
+    - SAUCE: Move replacedby allocation into label_alloc
+    - [Debian] supply zfs dkms Provides: based on do_zfs
+    - [Config] supply zfs dkms Provides: based on do_zfs
+    - [Config] drop linux-image-3.0 provides
+
+  * Miscellaneous upstream changes
+    - x86/mpx: Fix off-by-one comparison with nr_registers
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4.3
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 25 Feb 2016 19:47:55 -0700
+
+linux (4.4.0-8.23) xenial; urgency=low
+
+  * cgroup namespace mounts broken in containers (LP: #1549398)
+    - SAUCE: kernfs: Always set super block owner to init_user_ns
+
+  * 4.4.0-7.22 no longer boots on arm64 (LP: #1547718)
+    - arm64: mm: avoid calling apply_to_page_range on empty range
+    - UBUNTU SAUCE: arm: mm: avoid calling apply_to_page_range on empty range
+
+  * kernel install failed /bin/cp: cannot stat ‘/boot/initrd.img-4.3.0-7-generic’: No such file or directory (LP: #1536810)
+    - [Config] postinst -- handle recreating symlinks when a real file is present
+
+  * insecure overlayfs xattrs handling in copy_up (LP: #1534961)
+    - SAUCE: cred: Add clone_cred() interface
+    - SAUCE: overlayfs: Use mounter's credentials instead of selectively raising caps
+    - SAUCE: overlayfs: Skip permission checking for trusted.overlayfs.* xattrs
+    - SAUCE: overlayfs: Be more careful about copying up sxid files
+    - SAUCE: overlayfs: Propogate nosuid from lower and upper mounts
+
+  * overlayfs over fuse should refuse copy_up of files if uid/gid not mapped (LP: #1535150)
+    - SAUCE: cred: Add clone_cred() interface
+    - SAUCE: overlayfs: Use mounter's credentials instead of selectively raising caps
+    - SAUCE: overlayfs: Skip permission checking for trusted.overlayfs.* xattrs
+    - SAUCE: overlayfs: Be more careful about copying up sxid files
+    - SAUCE: overlayfs: Propogate nosuid from lower and upper mounts
+
+  * overlay: mkdir fails if directory exists in lowerdir in a user namespace (LP: #1531747)
+    - SAUCE: cred: Add clone_cred() interface
+    - SAUCE: overlayfs: Use mounter's credentials instead of selectively raising caps
+    - SAUCE: overlayfs: Skip permission checking for trusted.overlayfs.* xattrs
+
+  * Update Intel ethernet drivers to Fortville SW5 (LP: #1547674)
+    - net: bulk free infrastructure for NAPI context, use napi_consume_skb
+    - net: Add eth_platform_get_mac_address() helper.
+    - i40e: Add mac_filter_element at the end of the list instead of HEAD
+    - i40e/i40evf: Fix RSS rx-flow-hash configuration through ethtool
+    - i40e: Replace X722 mac check in ethtool get_settings
+    - i40evf: allow channel bonding of VFs
+    - i40e: define function capabilities in only one place
+    - i40evf: null out ring pointers on free
+    - i40e: Cleanup the code with respect to restarting autoneg
+    - i40e: update features with right offload
+    - i40e: bump version to 1.4.10
+    - i40e: add new device IDs for X722
+    - i40e: Extend ethtool RSS hooks for X722
+    - i40e/i40evf: Fix for UDP/TCP RSS for X722
+    - i40evf: add new write-back mode
+    - i40e/i40evf: Use private workqueue
+    - i40e: add new proxy-wol bit for X722
+    - i40e: Limit DCB FW version checks to X710/XL710 devices
+    - i40e: AQ Add Run PHY Activity struct
+    - i40e: AQ Geneve cloud tunnel type
+    - i40e: AQ Add external power class to get link status
+    - i40e: add 100Mb ethtool reporting
+    - ixgbe: bulk free SKBs during TX completion cleanup cycle
+    - igb: Remove unnecessary flag setting in igb_set_flag_queue_pairs()
+    - igb: Unpair the queues when changing the number of queues
+    - igb/igbvf: don't give up
+    - igb: clean up code for setting MAC address
+    - igb: Refactor VFTA configuration
+    - igb: Allow asymmetric configuration of MTU versus Rx frame size
+    - igb: Do not factor VLANs into RLPML calculation
+    - igb: Always enable VLAN 0 even if 8021q is not loaded
+    - igb: Merge VLVF configuration into igb_vfta_set
+    - igb: Clean-up configuration of VF port VLANs
+    - igb: Add support for VLAN promiscuous with SR-IOV and NTUPLE
+    - igb: Drop unnecessary checks in transmit path
+    - igb: Enable use of "bridge fdb add" to set unicast table entries
+    - igb: Add workaround for VLAN tag stripping on 82576
+    - i40e: AQ Shared resource flags
+    - i40e: AQ Add set_switch_config
+    - i40e: AQ Add VXLAN-GPE tunnel type
+    - i40e: AQ thermal sensor control struct
+    - i40e: Bump AQ minor version to 1.5 for new FW features
+    - i40e: Store lan_vsi_idx and lan_vsi_id in the right size
+    - i40e: fix write-back-on-itr to work with legacy itr
+    - i40e: add counter for arq overflows
+    - i40e: add 20G speed for Tx bandwidth calculations
+    - i40e: refactor DCB function
+    - i40e: add a little more to an NVM update debug message
+    - i40evf: enable bus master after reset
+    - i40e: add netdev info to VSI dump
+    - i40e: remove VF device IDs from PF
+    - i40e: trivial: remove unnecessary local var
+    - i40e/i40evf: Bump i40e to 1.4.11 and i40evf to 1.4.7
+    - net: ixgbe: add minimal parser details for ixgbe
+    - i40e: trivial: drop duplicate definition
+    - i40e: trivial: fix missing space
+    - i40e: fix bug in dma sync
+    - i40e: do TSO only if CHECKSUM_PARTIAL is set
+    - i40e: allocate memory safer
+    - i40e: fix: do not sleep in netdev_ops
+    - i40e: APIs to Add/remove port mirroring rules
+    - i40e: negate PHY int mask bits
+    - i40e: drop unused function
+    - i40e: count allocation errors
+    - i40e: avoid large memcpy by assigning struct
+    - i40e/i40evf: bump version to 1.4.12/1.4.8
+    - i40e: Enable Geneve offload for FW API ver > 1.4 for XL710/X710 devices
+    - i40e: add priv flag for automatic rule eviction
+    - i40e: use eth_platform_get_mac_address()
+    - i40e: move sync_vsi_filters up in service_task
+    - i40e: Make the DCB firmware checks for X710/XL710 only
+    - i40e: set shared bit for multicast filters
+    - i40e: add VEB stat control and remove L2 cloud filter
+    - i40e: use new add_veb calling with VEB stats control
+    - i40e: Refactor force_wb and WB_ON_ITR functionality code
+    - i40evf: Change vf driver string to reflect all products i40evf supports
+    - i40e/i40evf: don't lose interrupts
+    - i40e/i40evf: try again after failure
+    - i40e: dump descriptor indexes in hex
+    - i40e/i40evf: use __GFP_NOWARN
+    - i40e/i40evf: use pages correctly in Rx
+    - i40e/i40evf: use logical operators, not bitwise
+    - i40e: properly show packet split status in debugfs
+    - i40e/i40evf: Bump version
+    - ixgbe: use u32 instead of __u32 in model header
+    - ixgbe: fix dates on header of ixgbe_model.h
+    - i40e: get rid of magic number
+    - i40e: drop unused debugfs file "dump"
+    - i40evf: support packet split receive
+    - i40e: trivial: cleanup use of pf->hw
+    - i40e: Add a SW workaround for lost interrupts
+    - i40e: Fix PROMISC mode for Multi-function per port (MFP) devices
+    - i40e: Removal of code which relies on BASE VEB SEID
+    - i40e/i40evf: avoid atomics
+    - i40e: Do not disable queues in the Legacy/MSI Interrupt handler
+    - i40e: expand comment
+    - i40e: better error reporting for nvmupdate
+    - i40evf: set adapter state on reset failure
+    - i40e: clean event descriptor before use
+    - i40e: When in promisc mode apply promisc mode to Tx Traffic as well
+    - i40e/i40evf: Bump i40e to 1.4.15 and i40evf to 1.4.11.
+    - i40e/i40evf: Drop outer checksum offload that was not requested
+    - i40e/i40evf: Use u64 values instead of casting them in TSO function
+    - i40e/i40evf: Factor out L4 header and checksum from L3 bits in TSO path
+    - i40e/i40evf: Consolidate all header changes into TSO function
+    - i40e/i40evf: Replace header pointers with unions of pointers in Tx checksum path
+    - i40e/i40evf: Add support for IPv4 encapsulated in IPv6
+    - i40e/i40evf: Handle IPv6 extension headers in checksum offload
+    - i40e/i40evf: Do not write to descriptor unless we complete
+    - i40e/i40evf: Add exception handling for Tx checksum
+    - i40e/i40evf: Clean-up Rx packet checksum handling
+    - i40e/i40evf: Enable support for SKB_GSO_UDP_TUNNEL_CSUM
+    - i40e: Fix ATR in relation to tunnels
+    - i40e: Do not drop support for IPv6 VXLAN or GENEVE tunnels
+    - i40e: Update feature flags to reflect newly enabled features
+    - i40evf: Update feature flags to reflect newly enabled features
+    - i40e: Add support for ATR w/ IPv6 extension headers
+    - i40e/i40evf: Break up xmit_descriptor_count from maybe_stop_tx
+    - i40e/i40evf: Rewrite logic for 8 descriptor per packet check
+    - i40e/i40evf: Move Tx checksum closer to TSO
+    - i40e: Add functions to blink led on 10GBaseT PHY
+    - i40e: Fix led blink capability for 10GBaseT PHY
+    - i40e: Increase timeout when checking GLGEN_RSTAT_DEVSTATE bit
+    - i40e: Do not wait for Rx queue disable in DCB reconfig
+    - i40e: Fix for unexpected messaging
+    - i40e: Expose some registers to program parser, FD and RSS logic
+    - i40e: add check for null VSI
+    - i40e: add adminq commands for Rx CTL registers
+    - i40e: implement and use Rx CTL helper functions
+    - i40e: Use the new rx ctl register helpers. Don't use AQ calls from clear_hw.
+    - i40e: suspend scheduling during driver unload
+    - i40e: let go of the past
+    - i40e/i40evf: Bump i40e to 1.4.25 and i40evf to 1.4.15
+
+  * MPT3SAS Driver update for next kernel release (LP: #1512221)
+    - mpt3sas: A correction in unmap_resources
+    - mpt3sas: Added support for high port count HBA variants.
+    - mpt3sas: Used IEEE SGL instead of MPI SGL while framing a SMP Passthrough request message.
+    - mpt3sas: Fix static analyzer(coverity) tool identified defects
+    - mpt3sas: Never block the Enclosure device
+    - mpt3sas: Make use of additional HighPriority credit message frames for sending SCSI IO's
+    - mpt3sas: Added smp_affinity_enable module parameter.
+    - mpt3sas: Add support for configurable Chain Frame Size
+    - mpt3sas: Updated MPI Header to 2.00.42
+    - mpt3sas: Fix for Asynchronous completion of timedout IO and task abort of timedout IO.
+    - mpt3sas: Updating mpt3sas driver version to 12.100.00.00
+    - mpt3sas: Remove cpumask_clear for zalloc_cpumask_var and don't free free_cpu_mask_var before reply_q
+
+  * /sys/class/scsi_host/hostN/partition_number and .../mad_version showing up BE on LE Ubuntu. (ibmvscsi) (LP: #1547153)
+    - ibmvscsi: Add endian conversions to sysfs attribute show functions
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] git-ubuntu-log -- output should be utf-8
+    - [Packaging] git-ubuntu-log -- handle invalid or private bugs
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 24 Feb 2016 20:34:49 +0000
+
+linux (4.4.0-7.22) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1547205
+
+  * need arm64 acpi parking protocol support in xenial (LP: #1547047)
+    - [Config] Enabled ARM64_ACPI_PARKING_PROTOCOL
+    - arm64: kernel: implement ACPI parking protocol
+
+  * Please pull cgroup namespaces (LP: #1546775)
+    - SAUCE: (noup) kernfs: Add API to generate relative kernfs path
+    - SAUCE: (noup) sched: new clone flag CLONE_NEWCGROUP for cgroup namespace
+    - SAUCE: (noup) cgroup: introduce cgroup namespaces
+    - SAUCE: (noup) cgroup: cgroup namespace setns support
+    - SAUCE: (noup) kernfs: define kernfs_node_dentry
+    - SAUCE: (noup) cgroup: mount cgroupns-root when inside non-init cgroupns
+    - SAUCE: (noup) Add FS_USERNS_FLAG to cgroup fs
+    - SAUCE: (noup) cgroup: Add documentation for cgroup namespaces
+
+  * [Feature]Pulse-Width Modulation enabling on Broxton-P (LP: #1520436)
+    - [Config] CONFIG_PWM_OMAP_DMTIMER=m
+    - pwm: lpss: Remove ->free() callback
+    - pwm: bcm2835: Calculate scaler in ->config()
+    - pwm: bcm2835: Prevent division by zero
+    - pwm: bcm2835: Fix email address specification
+    - pwm: lpss: Update PWM setting for Broxton
+    - pwm: lpss: Select core part automatically
+    - pwm: lpss: Rework the sequence of programming PWM_SW_UPDATE
+    - pwm: fsl-ftm: Fix clock enable/disable when using PM
+    - pwm: lpc32xx: correct number of PWM channels from 2 to 1
+    - pwm: lpc32xx: make device usable with common clock framework
+    - pwm: lpc32xx: fix and simplify duty cycle and period calculations
+    - pwm: lpc32xx: return ERANGE, if requested period is not supported
+    - pwm: rcar: Improve accuracy of frequency division setting
+    - pwm: Add PWM driver for OMAP using dual-mode timers
+    - pwm: add HAS_IOMEM dependency to PWM_FSL_FTM
+    - pwm: omap-dmtimer: Potential NULL dereference on error
+    - pwm: Mark all devices as "might sleep"
+
+  * [Hyper-V] Netmask value is not parsed by hv_set_ifconfig - IP injection (LP: #1540586)
+    - [Debian] hv: hv_set_ifconfig -- switch to approved indentation
+    - [Debian] hv: hv_set_ifconfig -- fix numerous parameter handling issues
+
+  * Update megaraid driver to MR6.10 (LP: #1544679)
+    - megaraid_sas: Do not allow PCI access during OCR
+    - megaraid_sas: MFI IO timeout handling
+    - megaraid_sas: Syncing request flags macro names with firmware
+    - megaraid_sas: Task management support
+    - megaraid_sas: Update device queue depth based on interface type
+    - megaraid_sas: Fastpath region lock bypass
+    - megaraid_sas: Reply Descriptor Post Queue (RDPQ) support
+    - megaraid_sas: Code optimization build_and_issue_cmd return-type
+    - megaraid_sas: Dual queue depth support
+    - megaraid_sas: IO throttling support
+    - megaraid_sas: Make adprecovery variable atomic
+    - megaraid_sas: MFI adapter OCR changes
+    - megaraid_sas: Introduce module parameter for SCSI command timeout
+    - megaraid_sas: SPERC OCR changes
+    - megaraid_sas: driver version upgrade
+    - megaraid: fix null pointer check in megasas_detach_one().
+    - megaraid_sas: Fix for IO failing post OCR in SRIOV environment
+    - megaraid_sas: Fix SMAP issue
+    - megaraid_sas: Add an i/o barrier
+
+  * Surelock-GA2:kernel panic @ cxl_configure_adapter+0x418/0x8b0 (LP: #1546145)
+    - powerpc/powernv: Fix stale PE primary bus
+
+  * In A Single Power VM LPAR : Network Configuration Fails in Ubuntu16.04 while installation (LP: #1544321)
+    - [Config] Update bnx2x d-i firmware to 7.12.30
+
+  * Miscellaneous Ubuntu changes
+    - rebase to v4.4.2
+
+  * Miscellaneous upstream changes
+    - openvswitch: allow management from inside user namespaces
+    - net: thunderx: nicvf_queues: nivc_*_intr: remove duplication
+    - net, thunderx: Remove unnecessary rcv buffer start address management
+    - net: thunderx: HW TSO support for pass-2 hardware
+    - net: thunderx: Enable CQE count threshold interrupt
+    - net: cavium: liquidio: use helpers ns_to_timespec64()
+    - irqchip/gic-v3: Make sure read from ICC_IAR1_EL1 is visible on redestributor
+    - arm64: KVM: Configure TCR_EL2.PS at runtime
+    - arm64: prefetch: don't provide spin_lock_prefetch with LSE
+    - arm64: prefetch: add alternative pattern for CPUs without a prefetcher
+    - arm64: lib: improve copy_page to deal with 128 bytes at a time
+    - arm64: lib: patch in prfm for copy_page if requested
+    - arm64: prefetch: add missing #include for spin_lock_prefetch
+    - net, thunderx: Add TX timeout and RX buffer alloc failure stats.
+    - net: thunderx: Use napi_schedule_irqoff()
+    - net: thunderx: Assign affinity hints to vf's interrupts
+    - net: thunderx: bgx: Use standard firmware node infrastructure.
+    - net: thunderx: bgx: Add log message when setting mac address
+    - net: thunderx: Alloc higher order pages when pagesize is small
+    - net: cavium: liquidio: Return correct error code
+    - net: cavium: liquidio: fix check for in progress flag
+    - livepatch: add old_sympos as disambiguator field to klp_func
+    - livepatch: add sympos as disambiguator field to klp_reloc
+    - livepatch: function,sympos scheme in livepatch sysfs directory
+    - module: Use the same logic for setting and unsetting RO/NX
+    - gcov: use within_module() helper.
+    - module: use a structure to encapsulate layout.
+    - module: clean up RO/NX handling.
+    - module: keep percpu symbols in module's symtab
+    - livepatch: Cleanup module page permission changes
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4.2
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 16 Feb 2016 14:24:45 -0700
+
+linux (4.4.0-6.21) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1546283
+
+  *  Naples/Zen, NTB Driver  (LP: #1542071)
+    - [Config] CONFIG_NTB_AMD=m
+    - NTB: Add support for AMD PCI-Express Non-Transparent Bridge
+
+  * [Hyper-V] kernel panic occurs when installing Ubuntu Server x32 (LP: #1495983)
+    - SAUCE: storvsc: use small sg_tablesize on x86
+
+  * Enable arm64 emulation of removed ARMv7 instructions (LP: #1545542)
+    - [Config] CONFIG_ARMV8_DEPRECATED=y
+
+  * Surelock-GA2:kernel panic/ exception @ pcibios_set_pcie_reset_state+0x118/0x280 + cxl_reset+0x5c/0xc0 (LP: #1545037)
+    - powerpc/eeh: Fix stale cached primary bus
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: fs: Add user namesapace member to struct super_block
+    - SAUCE: fs: Limit file caps to the user namespace of the super block
+    - SAUCE: Smack: Add support for unprivileged mounts from user namespaces
+    - SAUCE: block_dev: Support checking inode permissions in lookup_bdev()
+    - SAUCE: block_dev: Check permissions towards block device inode when mounting
+    - SAUCE: fs: Treat foreign mounts as nosuid
+    - SAUCE: selinux: Add support for unprivileged mounts from user namespaces
+    - SAUCE: userns: Replace in_userns with current_in_userns
+    - SAUCE: Smack: Handle labels consistently in untrusted mounts
+    - SAUCE: fs: Check for invalid i_uid in may_follow_link()
+    - SAUCE: cred: Reject inodes with invalid ids in set_create_file_as()
+    - SAUCE: fs: Refuse uid/gid changes which don't map into s_user_ns
+    - SAUCE: fs: Update posix_acl support to handle user namespace mounts
+    - SAUCE: fs: Ensure the mounter of a filesystem is privileged towards its inodes
+    - SAUCE: fs: Don't remove suid for CAP_FSETID in s_user_ns
+    - SAUCE: fs: Allow superblock owner to access do_remount_sb()
+    - SAUCE: capabilities: Allow privileged user in s_user_ns to set security.* xattrs
+    - SAUCE: fuse: Add support for pid namespaces
+    - SAUCE: fuse: Support fuse filesystems outside of init_user_ns
+    - SAUCE: fuse: Restrict allow_other to the superblock's namespace or a descendant
+    - SAUCE: fuse: Allow user namespace mounts
+    - SAUCE: mtd: Check permissions towards mtd block device inode when mounting
+    - SAUCE: fs: Update i_[ug]id_(read|write) to translate relative to s_user_ns
+    - SAUCE: quota: Convert ids relative to s_user_ns
+    - SAUCE: evm: Translate user/group ids relative to s_user_ns when computing HMAC
+    - SAUCE: fs: Allow CAP_SYS_ADMIN in s_user_ns to freeze and thaw filesystems
+    - SAUCE: quota: Treat superblock owner as privilged
+    - SAUCE: ima/evm: Allow root in s_user_ns to set xattrs
+    - SAUCE: block_dev: Forbid unprivileged mounting when device is opened for writing
+    - SAUCE: ext4: Add support for unprivileged mounts from user namespaces
+    - SAUCE: ext4: Add module parameter to enable user namespace mounts
+    - SAUCE: fuse: Add module parameter to enable user namespace mounts
+
+  * Miscellaneous upstream changes
+    - megaraid: Fix possible NULL pointer deference in mraid_mm_ioctl
+    - libahci: Implement the capability to override the generic ahci interrupt handler.
+    - ata: Remove the AHCI_HFLAG_EDGE_IRQ support from libahci.
+    - ahci_xgene: Implement the workaround to fix the missing of the edge interrupt for the HOST_IRQ_STAT.
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 12 Feb 2016 09:49:05 -0700
+
+linux (4.4.0-5.20) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1544637
+
+  * s390/cio: update measurement characteristics (LP: #1541534)
+    - s390/cio: fix measurement characteristics memleak
+    - s390/cio: ensure consistent measurement state
+    - s390/cio: update measurement characteristics
+
+  * qeth: layer2 reports unknown state to network tools. (LP: #1541907)
+    - qeth: initialize net_device with carrier off
+
+  * Collateral damage due to kernel configuration change enabling CONFIG_ZONE_DEVICE (Kernel 4.4 amd64) (LP: #1534647)
+    - [Config] CONFIG_ZONE_DMA=y
+    - mm: CONFIG_NR_ZONES_EXTENDED
+
+  * perf enahancements for ppc64 (LP: #1521678)
+    - perf kvm/{x86,s390}: Remove dependency on uapi/kvm_perf.h
+    - perf kvm/{x86,s390}: Remove const from kvm_events_tp
+    - perf kvm/powerpc: Port perf kvm stat to powerpc
+    - perf kvm/powerpc: Add support for HCALL reasons
+
+  * Soft lockup with "block nbdX: Attempted send on closed socket" spam (LP: #1505564)
+    - SAUCE: nbd: ratelimit error msgs after socket close
+
+  * sleep from invalid context in aa_move_mount (LP: #1539349)
+    - SAUCE: apparmor: fix sleep from invalid context
+
+  * Introducing ConnectX-4 Ethernet SRIOV (LP: #1540435)
+    - net/mlx5_core: Modify enable/disable hca functions
+    - net/mlx5_core: Add base sriov support
+    - net/mlx5: Add HW capabilities and structs for SR-IOV E-Switch
+    - net/mlx5: Update access functions to Query/Modify vport MAC address
+    - net/mlx5: Introduce access functions to modify/query vport mac lists
+    - net/mlx5: Introduce access functions to modify/query vport state
+    - net/mlx5: Introduce access functions to modify/query vport promisc mode
+    - net/mlx5: Introduce access functions to modify/query vport vlans
+    - net/mlx5e: Write UC/MC list and promisc mode into vport context
+    - net/mlx5e: Write vlan list into vport context
+    - net/mlx5: Introducing E-Switch and l2 table
+    - net/mlx5: E-Switch, Introduce FDB hardware capabilities
+    - net/mlx5: E-Switch, Add SR-IOV (FDB) support
+    - net/mlx5: E-Switch, Introduce Vport administration functions
+    - net/mlx5: E-Switch, Introduce HCA cap and E-Switch vport context
+    - net/mlx5: E-Switch, Introduce set vport vlan (VST mode)
+    - net/mlx5: E-Switch, Introduce get vf statistics
+    - net/mlx5e: Add support for SR-IOV ndos
+    - net/mlx5: Fix query E-Switch capabilities
+    - net/mlx5e: Assign random MAC address if needed
+
+  * make wacom_w8001 work well in xenial (LP: #1542771)
+    - Input: wacom_w8001 - use __set_bit for evbits
+    - Input: wacom_w8001 - set BTN_TOOL_DOUBLETAP if we have 2fg support
+    - Input: wacom_w8001 - handle touch error case correctly
+    - Input: wacom_w8001 - split pen and touch initialization up
+    - Input: wacom_w8001 - split the touch and pen devices into two devices
+    - Input: wacom_w8001 - drop use of ABS_MT_TOOL_TYPE
+
+  * virtualbox: update to 5.0.14-dfsg-2 (LP: #1542728)
+    - ubuntu: vbox -- update to 5.0.14-dfsg-2
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] git-ubuntu-log -- fix empty section formatting
+    - SAUCE: (noup) Update spl to 0.6.5.4-0ubuntu2, zfs to 0.6.5.4-0ubuntu2
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 06 Feb 2016 22:32:10 +0000
+
+linux (4.4.0-4.19) xenial; urgency=low
+
+  * update ZFS and SPL to 0.6.5.4 (LP: #1542296)
+    - [Config] update spl/zfs version
+    - SAUCE: (noup) Update spl to 0.6.5.4-0ubuntu2, zfs to 0.6.5.4-0ubuntu1
+    - [Config] reconstruct -- drop links for zfs userspace components
+    - [Config] reconstruct -- drop links for zfs userspace components -- restore spec links
+
+  * recvmsg() fails SCM_CREDENTIALS request with EOPNOTSUPP. (LP: #1540731)
+    - Revert "af_unix: Revert 'lock_interruptible' in stream receive code"
+
+  * lxc: ADT exercise test failing with linux-4.4.0-3.17  (LP: #1542049)
+    - Revert "UBUNTU: SAUCE: apparmor: fix sleep from invalid context"
+
+  * WARNING: at /build/linux-lts-wily-W0lTWH/linux-lts-wily-4.2.0/net/core/skbuff.c:4174 (Travis IB) (LP: #1541326)
+    - SAUCE: IB/IPoIB: Do not set skb truesize since using one linearskb
+
+  * backport Microsoft Precision Touchpad palm rejection patch (LP: #1541671)
+    - HID: multitouch: enable palm rejection if device implements confidence usage
+
+  * [Ubuntu 16.04] Update qla2xxx driver for POWER (QLogic) (LP: #1541456)
+    - qla2xxx: Remove unavailable firmware files
+    - qla2xxx: Enable Extended Logins support
+    - qla2xxx: Enable Exchange offload support.
+    - qla2xxx: Enable Target counters in DebugFS.
+    - qla2xxx: Add FW resource count in DebugFS.
+    - qla2xxx: Added interface to send explicit LOGO.
+    - qla2xxx: Delete session if initiator is gone from FW
+    - qla2xxx: Wait for all conflicts before ack'ing PLOGI
+    - qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit.
+    - qla2xxx: Remove dependency on hardware_lock to reduce lock contention.
+    - qla2xxx: Add irq affinity notification
+    - qla2xxx: Add selective command queuing
+    - qla2xxx: Move atioq to a different lock to reduce lock contention
+    - qla2xxx: Disable ZIO at start time.
+    - qla2xxx: Set all queues to 4k
+    - qla2xxx: Check for online flag instead of active reset when transmitting responses
+    - scsi: qla2xxxx: avoid type mismatch in comparison
+
+  * [Hyper-V] PCI Passthrough (LP: #1541120)
+    - x86/irq: Export functions to allow MSI domains in modules
+    - genirq/msi: Export functions to allow MSI domains in modules
+
+  * Update lpfc driver to 11.0.0.10 (LP: #1541592)
+    - lpfc: Fix FCF Infinite loop in lpfc_sli4_fcf_rr_next_index_get.
+    - lpfc: Fix the FLOGI discovery logic to comply with T11 standards
+    - lpfc: Fix RegLogin failed error seen on Lancer FC during port bounce
+    - lpfc: Fix driver crash when module parameter lpfc_fcp_io_channel set to 16
+    - lpfc: Fix crash in fcp command completion path.
+    - lpfc: Modularize and cleanup FDMI code in driver
+    - lpfc: Fix RDP Speed reporting.
+    - lpfc: Fix RDP ACC being too long.
+    - lpfc: Make write check error processing more resilient
+    - lpfc: Use new FDMI speed definitions for 10G, 25G and 40G FCoE.
+    - lpfc: Fix mbox reuse in PLOGI completion
+    - lpfc: Fix external loopback failure.
+    - lpfc: Add logging for misconfigured optics.
+    - lpfc: Delete unnecessary checks before the function call "mempool_destroy"
+    - lpfc: Use kzalloc instead of kmalloc
+    - lpfc: Update version to 11.0.0.10 for upstream patch set
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_ARM64_VA_BITS=48
+    - [Config] Fixed Vcs-Git
+
+  * Miscellaneous upstream changes
+    - cxl: Fix possible idr warning when contexts are released
+    - cxl: use correct operator when writing pcie config space values
+    - cxlflash: drop unlikely before IS_ERR_OR_NULL
+    - cxl: Fix DSI misses when the context owning task exits
+    - cxlflash: Removed driver date print
+    - cxlflash: Fix to resolve cmd leak after host reset
+    - cxlflash: Resolve oops in wait_port_offline
+    - cxlflash: Enable device id for future IBM CXL adapter
+    - cxl: fix build for GCC 4.6.x
+    - cxl: use -Werror only with CONFIG_PPC_WERROR
+    - cxl: Enable PCI device ID for future IBM CXL adapter
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Feb 2016 14:58:51 +0000
+
+linux (4.4.0-3.17) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1541058
+  * [Config] CONFIG_BLK_DEV_NVME_SCSI=y
+    - LP: #1531539
+  * SAUCE: nvme merge cleanup
+    - LP: #1531539
+  * rebase to v4.4.1
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: dm: introduce a target_ioctl op to allow target specific
+    ioctls"
+    - LP: #1538618
+  * postinst -- detect symlinks correctly
+    - LP: #1536810
+
+  [ John Johansen ]
+
+  * SAUCE: apparmor: fix sleep from invalid context
+    - LP: #1539349
+
+  [ Upstream Kernel Changes ]
+
+  * powerpc/eeh: Fix PE location code
+    - LP: #1538909
+  * powerpc/pseries: Limit EPOW reset event warnings
+    - LP: #1539102
+  * lightnvm: fix bio submission issue
+    - LP: #1531539
+  * lightnvm: fix incorrect nr_free_blocks stat
+    - LP: #1531539
+  * lightnvm: add check after mempool allocation
+    - LP: #1531539
+  * lightnvm: unlock rq and free ppa_list on submission fail
+    - LP: #1531539
+  * lightnvm: move ppa erase logic to core
+    - LP: #1531539
+  * lightnvm: refactor rqd ppa list into set/free
+    - LP: #1531539
+  * lightnvm: refactor end_io functions for sync
+    - LP: #1531539
+  * lightnvm: return the get_bb_tbl return value
+    - LP: #1531539
+  * lightnvm: check bi_error in gc
+    - LP: #1531539
+  * lightnvm: put block back to gc list on its reclaim fail
+    - LP: #1531539
+  * lightnvm: fix locking and mempool in rrpc_lun_gc
+    - LP: #1531539
+  * lightnvm: sectors first in ppa list
+    - LP: #1531539
+  * lightnvm: move the pages per block check out of the loop
+    - LP: #1531539
+  * lightnvm: support multiple ppas in nvm_erase_ppa
+    - LP: #1531539
+  * lightnvm: move rq->error to nvm_rq->error
+    - LP: #1531539
+  * lightnvm: introduce nvm_submit_ppa
+    - LP: #1531539
+  * lightnvm: reference rrpc lun in rrpc block
+    - LP: #1531539
+  * lightnvm: fix missing grown bad block type
+    - LP: #1531539
+  * lightnvm: manage open and closed blocks separately
+    - LP: #1531539
+  * lightnvm: add mccap support
+    - LP: #1531539
+  * lightnvm: introduce mlc lower page table mappings
+    - LP: #1531539
+  * lightnvm: core on-disk initialization
+    - LP: #1531539
+  * lightnvm: introduce ioctl to initialize device
+    - LP: #1531539
+  * lightnvm: use system block for mm initialization
+    - LP: #1531539
+  * lightnvm: introduce factory reset
+    - LP: #1531539
+  * lightnvm: ensure that nvm_dev_ops can be used without CONFIG_NVM
+    - LP: #1531539
+  * blk-mq: add a flags parameter to blk_mq_alloc_request
+    - LP: #1531539
+  * nvme: move struct nvme_iod to pci.c
+    - LP: #1531539
+  * nvme: split command submission helpers out of pci.c
+    - LP: #1531539
+  * nvme: use offset instead of a struct for registers
+    - LP: #1531539
+  * nvme: split nvme_trans_device_id_page
+    - LP: #1531539
+  * nvme: use vendor it from identify
+    - LP: #1531539
+  * nvme: split a new struct nvme_ctrl out of struct nvme_dev
+    - LP: #1531539
+  * nvme: simplify nvme_setup_prps calling convention
+    - LP: #1531539
+  * nvme: refactor nvme_queue_rq
+    - LP: #1531539
+  * nvme: factor out a nvme_unmap_data helper
+    - LP: #1531539
+  * nvme: move nvme_error_status to common code
+    - LP: #1531539
+  * nvme: move nvme_setup_flush and nvme_setup_rw to common code
+    - LP: #1531539
+  * nvme: split __nvme_submit_sync_cmd
+    - LP: #1531539
+  * nvme: use the block layer for userspace passthrough metadata
+    - LP: #1531539
+  * nvme: move block_device_operations and ns/ctrl freeing to common code
+    - LP: #1531539
+  * nvme: add explicit quirk handling
+    - LP: #1531539
+  * nvme: move remaining CC setup into nvme_enable_ctrl
+    - LP: #1531539
+  * nvme: move nvme_{enable,disable,shutdown}_ctrl to common code
+    - LP: #1531539
+  * nvme: add a common helper to read Identify Controller data
+    - LP: #1531539
+  * nvme: move the call to nvme_init_identify earlier
+    - LP: #1531539
+  * nvme: move namespace scanning to common code
+    - LP: #1531539
+  * nvme: move chardev and sysfs interface to common code
+    - LP: #1531539
+  * nvme: refactor set_queue_count
+    - LP: #1531539
+  * blk-integrity: empty implementation when disabled
+    - LP: #1531539
+  * NVMe: fix build with CONFIG_NVM enabled
+    - LP: #1531539
+  * nvme: fix another 32-bit build warning
+    - LP: #1531539
+  * nvme: precedence bug in nvme_pr_clear()
+    - LP: #1531539
+  * nvme: only ignore hardware errors in nvme_create_io_queues
+    - LP: #1531539
+  * nvme: only add a controller to dev_list after it's been fully
+    initialized
+    - LP: #1531539
+  * nvme: protect against simultaneous shutdown invocations
+    - LP: #1531539
+  * nvme: don't take the I/O queue q_lock in nvme_timeout
+    - LP: #1531539
+  * nvme: merge nvme_abort_req and nvme_timeout
+    - LP: #1531539
+  * nvme: add NVME_SC_CANCELLED
+    - LP: #1531539
+  * nvme: simplify resets
+    - LP: #1531539
+  * nvme: do not restart the request timeout if we're resetting the
+    controller
+    - LP: #1531539
+  * nvme: merge probe_work and reset_work
+    - LP: #1531539
+  * nvme: remove dead controllers from a work item
+    - LP: #1531539
+  * nvme: switch abort_limit to an atomic_t
+    - LP: #1531539
+  * NVMe: Implement namespace list scanning
+    - LP: #1531539
+  * NVMe: Use unbounded work queue for all work
+    - LP: #1531539
+  * NVMe: Remove device management handles on remove
+    - LP: #1531539
+  * NVMe: Simplify metadata setup
+    - LP: #1531539
+  * nvme: fix admin queue depth
+    - LP: #1531539
+  * nvme: factor out a few helpers from req_completion
+    - LP: #1531539
+  * nvme: switch delete SQ/CQ to blk_execute_rq_nowait
+    - LP: #1531539
+  * nvme: switch abort to blk_execute_rq_nowait
+    - LP: #1531539
+  * nvme: special case AEN requests
+    - LP: #1531539
+  * nvme: simplify completion handling
+    - LP: #1531539
+  * nvme: properly free resources for cancelled command
+    - LP: #1531539
+  * nvme: meta_sg doesn't have to be an array
+    - LP: #1531539
+  * nvme: merge iod and cmd_info
+    - LP: #1531539
+  * NVMe: Add pci error handlers
+    - LP: #1531539
+  * NVMe: Export namespace attributes to sysfs
+    - LP: #1531539
+  * nvme: Move nvme_freeze/unfreeze_queues to nvme core
+    - LP: #1531539
+  * nvme: synchronize access to ctrl->namespaces
+    - LP: #1531539
+  * nvme: fixes for NVME_IOCTL_IO_CMD on the char device
+    - LP: #1531539
+  * nvme: make SG_IO support optional
+    - LP: #1531539
+  * NVMe: Fix admin queue ring wrap
+    - LP: #1531539
+  * NVMe: Use a retryable error code on reset
+    - LP: #1531539
+  * NVMe: Remove queue freezing on resets
+    - LP: #1531539
+  * NVMe: IO queue deletion re-write
+    - LP: #1531539
+  * NVMe: Shutdown controller only for power-off
+    - LP: #1531539
+  * NVMe: Export NVMe attributes to sysfs group
+    - LP: #1531539
+  * i40e: fix build warnings
+  * net: i40e: shut up uninitialized variable warnings
+  * Drivers: hv: vmbus: fix build warning
+  * Drivers: hv: util: Increase the timeout for util services
+  * Drivers: hv: utils: run polling callback always in interrupt context
+  * tools: hv: report ENOSPC errors in hv_fcopy_daemon
+  * tools: hv: remove repeated HV_FCOPY string
+  * Drivers: hv: util: catch allocation errors
+  * Drivers: hv: utils: use memdup_user in hvt_op_write
+  * drivers/hv: cleanup synic msrs if vmbus connect failed
+  * drivers:hv: Export a function that maps Linux CPU num onto Hyper-V proc
+    num
+  * drivers:hv: Export the API to invoke a hypercall on Hyper-V
+  * drivers:hv: Define the channel type for Hyper-V PCI Express
+    pass-through
+  * Drivers: hv: vss: run only on supported host versions
+  * Drivers: hv: vmbus: Use uuid_le type consistently
+  * Drivers: hv: vmbus: Use uuid_le_cmp() for comparing GUIDs
+  * Drivers: hv: vmbus: Get rid of the unused macro
+  * Drivers: hv: vmbus: Get rid of the unused irq variable
+  * Drivers: hv: vmbus: serialize process_chn_event() and
+    vmbus_close_internal()
+  * Drivers: hv: vmbus: do sanity check of channel state in
+    vmbus_close_internal()
+  * Drivers: hv: vmbus: fix rescind-offer handling for device without a
+    driver
+  * Drivers: hv: vmbus: release relid on error in vmbus_process_offer()
+  * Drivers: hv: vmbus: channge vmbus_connection.channel_lock to mutex
+  * drivers:hv: Allow for MMIO claims that span ACPI _CRS records
+  * Drivers: hv: vmbus: Fix a Host signaling bug
+  * drivers/hv: correct tsc page sequence invalid value
+  * Drivers: hv: vmbus: Force all channel messages to be delivered on CPU 0
+  * Drivers: hv: utils: Invoke the poll function after handshake
+  * tools: hv: vss: fix the write()'s argument: error -> vss_msg
+  * Drivers: hv: utils: fix memory leak on on_msg() failure
+  * Drivers: hv: utils: rename outmsg_lock
+  * Drivers: hv: utils: introduce HVUTIL_TRANSPORT_DESTROY mode
+  * Drivers: hv: utils: fix crash when device is removed from host side
+  * Drivers: hv: ring_buffer.c: fix comment style
+  * Drivers: hv: ring_buffer: remove stray smp_read_barrier_depends()
+  * Drivers: hv: ring_buffer: remove code duplication from
+    hv_ringbuffer_peek/read()
+  * Drivers: hv: remove code duplication between
+    vmbus_recvpacket()/vmbus_recvpacket_raw()
+  * Drivers: hv: ring_buffer: eliminate hv_ringbuffer_peek()
+  * drivers/hv: replace enum hv_message_type by u32
+  * drivers/hv: Move HV_SYNIC_STIMER_COUNT into Hyper-V UAPI x86 header
+  * drivers/hv: Move struct hv_message into UAPI Hyper-V x86 header
+  * drivers/hv: Move struct hv_timer_message_payload into UAPI Hyper-V x86
+    header
+  * Drivers: hv: vmbus: fix the building warning with hyperv-keyboard
+  * Drivers: hv: utils: fix hvt_op_poll() return value on transport destroy
+  * Drivers: hv: vmbus: Treat Fibre Channel devices as performance critical
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4.1
+    - LP: #1533461
+    - LP: #1529624
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 29 Jan 2016 08:06:37 -0700
+
+linux (4.4.0-2.16) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1539090
+  * SAUCE: hv: hv_set_ifconfig -- convert to python3
+    - LP: #1506521
+  * SAUCE: dm: introduce a target_ioctl op to allow target specific ioctls
+    - LP: #1538618
+
+  [ Colin Ian King ]
+
+  * SAUCE: ACPI / tables: Add acpi_force_32bit_fadt_addr option to force 32
+    bit FADT addresses (LP: #1529381)
+    - LP: #1529381
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up): apparmor: fix for failed mediation of socket that is
+    being shutdown
+    - LP: #1446906
+
+  [ Mahesh Salgaonkar ]
+
+  * SAUCE: Powernv: Remove the usage of PACAR1 from opal wrappers
+    - LP: #1537881
+  * SAUCE: powerpc/book3s: Fix TB corruption in guest exit path on HMI
+    interrupt.
+    - LP: #1537881
+  * SAUCE: KVM: PPC: Book3S HV: Fix soft lockups in KVM on HMI for time
+    base errors
+    - LP: #1537881
+
+  [ Paolo Pisati ]
+
+  * SAUCE: arm64: errata: Add -mpc-relative-literal-loads to erratum
+    #843419 build flags
+    - LP: #1533009
+  * [Config] MFD_TPS65217=y && REGULATOR_TPS65217=y
+  * [Config] disable ARCH_ZX (ZTE ZX Soc)
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: (noup) cxlflash: a couple off by one bugs"
+  * SAUCE: (no-up) Update bnx2x firmware to 7.12.30.0
+    - LP: #1536719
+  * SAUCE: drop obsolete bnx2x firmware
+  * SAUCE: i40e: Silence 'may be used uninitialized' warnings
+    - LP: #1536474
+  * [Config] CONFIG_ZONE_DMA=y for amd64 lowlatency
+    - LP: #1534647
+  * [Config] Add pvpanic to virtual flavour
+    - LP: #1537923
+  * [Config] CONFIG_INTEL_PUNIT_IPC=m, CONFIG_INTEL_TELEMETRY=m
+    - LP: #1520457
+
+  [ Upstream Kernel Changes ]
+
+  * i40evf: fix compiler warning of unused variable
+    - LP: #1536474
+  * intel: i40e: fix confused code
+    - LP: #1536474
+  * i40e/i40evf: remove unused tunnel parameter
+    - LP: #1536474
+  * i40e: Change BUG_ON to WARN_ON in service event complete
+    - LP: #1536474
+  * i40e: remove BUG_ON from feature string building
+    - LP: #1536474
+  * i40e: remove BUG_ON from FCoE setup
+    - LP: #1536474
+  * i40e: Workaround fix for mss < 256 issue
+    - LP: #1536474
+  * i40e/i40evf: Add a stat to track how many times we have to do a force
+    WB
+    - LP: #1536474
+  * i40e: Move the saving of old link info from handle_link_event to
+    link_event
+    - LP: #1536474
+  * i40e/i40evf: Add comment to #endif
+    - LP: #1536474
+  * i40e/i40evf: clean up error messages
+    - LP: #1536474
+  * i40evf: handle many MAC filters correctly
+    - LP: #1536474
+  * i40e: return the number of enabled queues for ETHTOOL_GRXRINGS
+    - LP: #1536474
+  * i40e: rework the functions to configure RSS with similar parameters
+    - LP: #1536474
+  * i40e: create a generic configure rss function
+    - LP: #1536474
+  * i40e: Bump version to 1.4.2
+    - LP: #1536474
+  * i40e: add new fields to store user configuration
+    - LP: #1536474
+  * i40e: rename rss_size to alloc_rss_size in i40e_pf
+    - LP: #1536474
+  * i40e/i40evf: Fix RS bit update in Tx path and disable force WB
+    workaround
+    - LP: #1536474
+  * i40e/i40evf: prefetch skb data on transmit
+    - LP: #1536474
+  * i40evf: rename VF adapter specific RSS function
+    - LP: #1536474
+  * i40evf: create a generic config RSS function
+    - LP: #1536474
+  * i40evf: create a generic get RSS function
+    - LP: #1536474
+  * i40evf: add new fields to store user configuration of RSS
+    - LP: #1536474
+  * i40e: Update error messaging
+    - LP: #1536474
+  * i40e: fix confusing message
+    - LP: #1536474
+  * i40e: make error message more useful
+    - LP: #1536474
+  * i40evf: quoth the VF driver, Nevermore
+    - LP: #1536474
+  * i40evf: allocate queue vectors dynamically
+    - LP: #1536474
+  * i40evf: allocate ring structs dynamically
+    - LP: #1536474
+  * i40e/i40evf: Bump i40e version to 1.4.4 and i40evf to 1.4.1
+    - LP: #1536474
+  * i40e: fix: do not sleep in netdev_ops
+    - LP: #1536474
+  * i40e: remove unused argument
+    - LP: #1536474
+  * i40evf: increase max number of queues
+    - LP: #1536474
+  * i40evf: set real num queues
+    - LP: #1536474
+  * i40evf: remove duplicate string
+    - LP: #1536474
+  * i40e: Detection and recovery of TX queue hung logic moved to
+    service_task from tx_timeout
+    - LP: #1536474
+  * i40e: Fix memory leaks, sideband filter programming
+    - LP: #1536474
+  * i40evf: don't use atomic allocation
+    - LP: #1536474
+  * i40e: propagate properly
+    - LP: #1536474
+  * i40evf: use correct types
+    - LP: #1536474
+  * i40e: use priv flags to control packet split
+    - LP: #1536474
+  * i40e: Remove separate functions gathering XOFF Rx stats
+    - LP: #1536474
+  * i40e: fix whitespace
+    - LP: #1536474
+  * i40e/i40evf: use logical operator
+    - LP: #1536474
+  * i40e/i40evf: Bump version to 1.4.7 for i40e and 1.4.3 for i40evf
+    - LP: #1536474
+  * i40e: trivial fixes
+    - LP: #1536474
+  * i40e: Fix i40e_print_features() VEB mode output
+    - LP: #1536474
+  * i40e: chomp the BIT(_ULL)
+    - LP: #1536474
+  * i40e: properly delete VF MAC filters
+    - LP: #1536474
+  * i40e: don't add zero MAC filter
+    - LP: #1536474
+  * i40evf: check rings before freeing resources
+    - LP: #1536474
+  * i40e: use explicit cast from u16 to u8
+    - LP: #1536474
+  * i40e: Opcode and structures required by OEM Post Update AQ command and
+    add new NVM arq message
+    - LP: #1536474
+  * i40e: hush little warnings
+    - LP: #1536474
+  * i40e/i40evf: Add a new offload for RSS PCTYPE V2 for X722
+    - LP: #1536474
+  * i40e: clean whole mac filter list
+    - LP: #1536474
+  * i40evf: change version string generation
+    - LP: #1536474
+  * i40e/i40evf: Bump i40e to 1.4.8 and i40evf to 1.4.4
+    - LP: #1536474
+  * geneve: UDP checksum configuration via netlink
+    - LP: #1536474
+  * geneve: Add geneve udp port offload for ethernet devices
+    - LP: #1536474
+  * i40e: geneve tunnel offload support
+    - LP: #1536474
+  * geneve: Add geneve_get_rx_port support
+    - LP: #1536474
+  * i40e: Call geneve_get_rx_port to get the existing Geneve ports
+    - LP: #1536474
+  * i40e: change log messages and error returns
+    - LP: #1536474
+  * i40e: allow zero MAC address for VFs
+    - LP: #1536474
+  * i40e: Look up MAC address in Open Firmware or IDPROM
+    - LP: #1536474
+  * i40e: Fix Rx hash reported to the stack by our driver
+    - LP: #1536474
+  * i40e: remove forever unused ID
+    - LP: #1536474
+  * igb: add 88E1543 initialization code
+  * igb: don't unmap NULL hw_addr
+  * igb: use the correct i210 register for EEMNGCTL
+  * igb: fix NULL derefs due to skipped SR-IOV enabling
+  * igb: improve handling of disconnected adapters
+  * igb: Remove GS40G specific defines/functions
+  * igb: Don't add PHY address to PCDL address
+  * igb: Improve cable length function for I210, etc.
+  * igb: Explicitly label self-test result indices
+  * ixgbe: drop null test before destroy functions
+    - LP: #1536473
+  * ixgbe: Delete redundant include file
+    - LP: #1536473
+  * ixgbe: fix multiple kernel-doc errors
+    - LP: #1536473
+  * ixgbe: Fix handling of NAPI budget when multiple queues are enabled per
+    vector
+    - LP: #1536473
+  * ixgbe: Add KR mode support for CS4227 chip
+    - LP: #1536473
+  * ixgbevf: Limit lowest interrupt rate for adaptive interrupt moderation
+    to 12K
+    - LP: #1536473
+  * ixgbe/ixgbevf: use napi_schedule_irqoff()
+    - LP: #1536473
+  * ixgbe: Remove CS4227 diagnostic code
+    - LP: #1536473
+  * ixgbevf: use ether_addr_copy instead of memcpy
+    - LP: #1536473
+  * ixgbevf: fix spoofed packets with random MAC
+    - LP: #1536473
+  * ixgbe: Prevent KR PHY reset in ixgbe_init_phy_ops_x550em
+    - LP: #1536473
+  * ixgbe: Add support for newer thermal alarm
+    - LP: #1536473
+  * ixgbe: Use private workqueue to avoid certain possible hangs
+    - LP: #1536473
+  * ixgbevf: Use a private workqueue to avoid certain possible hangs
+    - LP: #1536473
+  * ixgbevf: Minor cleanups
+    - LP: #1536473
+  * ixgbe: Refactor MAC address configuration code
+    - LP: #1536473
+  * ixgbe: Use __dev_uc_sync and __dev_uc_unsync for unicast addresses
+    - LP: #1536473
+  * ixgbe: Allow FDB entries access to more RAR filters
+    - LP: #1536473
+  * ixgbe: Update PTP to support X550EM_x devices
+    - LP: #1536473
+  * ixgbe: Correct spec violations by waiting after reset
+    - LP: #1536473
+  * ixgbe: Wait for master disable to be set
+    - LP: #1536473
+  * ixgbe: Save VF info and take references
+    - LP: #1536473
+  * ixgbe: Handle extended IPv6 headers in Tx path
+    - LP: #1536473
+  * ixgbe: Always turn PHY power on when requested
+    - LP: #1536473
+  * ixgbevf: Handle extended IPv6 headers in Tx path
+    - LP: #1536473
+  * ixgbe: Return error on failure to allocate mac_table
+    - LP: #1536473
+  * ixgbe: Fix SR-IOV VLAN pool configuration
+    - LP: #1536473
+  * ixgbe: Simplify definitions for regidx and bit in set_vfta
+    - LP: #1536473
+  * ixgbe: Reduce VT code indent in set_vfta by introducing jump label
+    - LP: #1536473
+  * ixgbe: Simplify configuration of setting VLVF and VLVFB
+    - LP: #1536473
+  * ixgbe: Add support for adding/removing VLAN on PF bypassing the VLVF
+    - LP: #1536473
+  * ixgbe: Reorder search to work from the top down instead of bottom up
+    - LP: #1536473
+  * ixgbe: Add support for VLAN promiscuous with SR-IOV
+    - LP: #1536473
+  * ixgbe: Fix VLAN promisc in relation to SR-IOV
+    - LP: #1536473
+  * ixgbe: Clear stale pool mappings
+    - LP: #1536473
+  * ixgbe: Clean stale VLANs when changing port VLAN or resetting
+    - LP: #1536473
+  * ixgbe: do not report 2.5 Gbps as supported
+    - LP: #1536473
+  * ixgbevf: Fix handling of NAPI budget when multiple queues are enabled
+    per vector
+    - LP: #1536473
+  * ixgbevf: minor cleanups for ixgbevf_set_itr()
+    - LP: #1536473
+  * ixgbe: add support for QSFP PHY types in ixgbe_get_settings()
+    - LP: #1536473
+  * ixgbe: report correct media type for KR, KX and KX4 interfaces
+    - LP: #1536473
+  * ixgbe: Clean up redundancy in hw_enc_features
+    - LP: #1536473
+  * ixgbe: fix RSS limit for X550
+    - LP: #1536473
+  * ixgbe: Correct X550EM_x revision check
+    - LP: #1536473
+  * ixgbe: Fix bugs in ixgbe_clear_vf_vlans()
+    - LP: #1536473
+  * ixgbe: Fill at least min credits to a TC credit refills
+    - LP: #1536473
+  * ixgbe: use correct FCoE DDP max check
+    - LP: #1536473
+  * ixgbe: fix broken PFC with X550
+    - LP: #1536473
+  * ixgbe: do not call check_link for ethtool in ixgbe_get_settings()
+    - LP: #1536473
+  * ixgbe: Correct handling of any outer UDP checksum setting
+    - LP: #1536473
+  * ixgbe: Fix to get FDMI HBA attributes information with X550
+    - LP: #1536473
+  * ixgbe: Fix MDD events generated when FCoE+SRIOV are enabled
+    - LP: #1536473
+  * ixgbe: Make ATR recognize IPv6 extended headers
+    - LP: #1536473
+  * e1000: make eeprom read/write scheduler friendly
+  * e1000: fix data race between tx_ring->next_to_clean
+  * e1000: Remove checkpatch coding style errors
+  * e1000: clean up the checking logic
+  * e1000: fix a typo in the comment
+  * e1000e: clean up the local variable
+  * e1000: fix kernel-doc argument being missing
+  * e1000: get rid of duplicate exit path
+  * e1000: Elementary checkpatch warnings and checks removed
+  * e1000e: fix division by zero on jumbo MTUs
+  * e1000e: Increase timeout of polling bit RSPCIPHY
+  * e1000e: initial support for i219-LM (3)
+  * e1000e: Switch e1000e_up to void, drop code checking for error result
+  * e1000e: Remove unreachable code
+  * e1000e: Do not read ICR in Other interrupt
+  * e1000e: Do not write lsc to ics in msi-x mode
+  * e1000e: Fix msi-x interrupt automask
+  * acpi: pci: Setup MSI domain for ACPI based pci devices
+  * irqdomain: Introduce is_fwnode_irqchip helper
+  * irqchip/gic-v2m: Refactor to prepare for ACPI support
+  * irqchip/gic-v2m: acpi: Introducing GICv2m ACPI support
+  * clk: xgene: Fix divider with non-zero shift value
+  * i2c: designware: Do not require clock when SSCN and FFCN are provided
+  * fm10k: do not assume VF always has 1 queue
+    - LP: #1536475
+  * fm10k: Correct MTU for jumbo frames
+    - LP: #1536475
+  * fm10k: Fix handling of NAPI budget when multiple queues are enabled per
+    vector
+    - LP: #1536475
+  * fm10k: use napi_schedule_irqoff()
+    - LP: #1536475
+  * fm10k: set netdev features in one location
+    - LP: #1536475
+  * fm10k: reset max_queues on init_hw_vf failure
+    - LP: #1536475
+  * fm10k: always check init_hw for errors
+    - LP: #1536475
+  * fm10k: reinitialize queuing scheme after calling init_hw
+    - LP: #1536475
+  * fm10k: Correct typecast in fm10k_update_xc_addr_pf
+    - LP: #1536475
+  * fm10k: explicitly typecast vlan values to u16
+    - LP: #1536475
+  * fm10k: add statistics for actual DWORD count of mbmem mailbox
+    - LP: #1536475
+  * fm10k: rename mbx_tx_oversized statistic to mbx_tx_dropped
+    - LP: #1536475
+  * fm10k: Add support for ITR scaling based on PCIe link speed
+    - LP: #1536475
+  * fm10k: introduce ITR_IS_ADAPTIVE macro
+    - LP: #1536475
+  * fm10k: Update adaptive ITR algorithm
+    - LP: #1536475
+  * fm10k: use macro for default Tx and Rx ITR values
+    - LP: #1536475
+  * fm10k: change default Tx ITR to 25usec
+    - LP: #1536475
+  * fm10k: TRIVIAL fix typo of hardware
+    - LP: #1536475
+  * fm10k: TRIVIAL cleanup order at top of fm10k_xmit_frame
+    - LP: #1536475
+  * fm10k: use ether_addr_copy to copy MAC address
+    - LP: #1536475
+  * fm10k: do not use CamelCase
+    - LP: #1536475
+  * fm10k: remove unnecessary else block from if statements with return
+    - LP: #1536475
+  * fm10k: remove namespace pollution of fm10k_iov_msg_data_pf
+    - LP: #1536475
+  * fm10k: consistently refer to VLANs and VLAN IDs
+    - LP: #1536475
+  * fm10k: bump driver version
+    - LP: #1536475
+  * fm10k: conditionally compile DCB and DebugFS support
+    - LP: #1536475
+  * fm10k: Cleanup MSI-X interrupts in case of failure
+    - LP: #1536475
+  * fm10k: Cleanup exception handling for mailbox interrupt
+    - LP: #1536475
+  * fm10k: do not inline fm10k_iov_select_vid()
+    - LP: #1536475
+  * fm10k: whitespace cleanups
+    - LP: #1536475
+  * fm10k: use BIT() macro instead of open-coded bit-shifting
+    - LP: #1536475
+  * fm10k: cleanup namespace pollution
+    - LP: #1536475
+  * fm10k: cleanup overly long lines
+    - LP: #1536475
+  * fm10k: initialize xps at driver load
+    - LP: #1536475
+  * fm10k: don't initialize fm10k_workqueue at global level
+    - LP: #1536475
+  * fm10k: correctly pack TLV structures and explain reasoning
+    - LP: #1536475
+  * fm10k: Cleanup exception handling for changing queues
+    - LP: #1536475
+  * fm10k: use ether_addr_equal instead of memcmp
+    - LP: #1536475
+  * fm10k: address operator not needed when declaring function pointers
+    - LP: #1536475
+  * fm10k: constify fm10k_mac_ops, fm10k_iov_ops and fm10k_info structures
+    - LP: #1536475
+  * fm10k: remove unused struct element
+    - LP: #1536475
+  * fm10k: use true/false for boolean get_host_state
+    - LP: #1536475
+  * fm10k: cleanup mailbox code comments etc
+    - LP: #1536475
+  * fm10k: IS_ENABLED() is not appropriate for boolean kconfig option
+    - LP: #1536475
+  * device property: always check for fwnode type
+    - LP: #1533035
+  * device property: rename helper functions
+    - LP: #1533035
+  * device property: refactor built-in properties support
+    - LP: #1533035
+  * device property: keep single value inplace
+    - LP: #1533035
+  * device property: helper macros for property entry creation
+    - LP: #1533035
+  * device property: improve readability of macros
+    - LP: #1533035
+  * device property: return -EINVAL when property isn't found in ACPI
+    - LP: #1533035
+  * device property: Fallback to secondary fwnode if primary misses the
+    property
+    - LP: #1533035
+  * device property: Take a copy of the property set
+    - LP: #1533035
+  * driver core: platform: Add support for built-in device properties
+    - LP: #1533035
+  * driver core: Do not overwrite secondary fwnode with NULL if it is set
+    - LP: #1533035
+  * mfd: core: propagate device properties to sub devices drivers
+    - LP: #1533035
+  * mfd: intel-lpss: Add support for passing device properties
+    - LP: #1533035
+  * mfd: intel-lpss: Pass SDA hold time to I2C host controller driver
+    - LP: #1533035
+  * mfd: intel-lpss: Pass HSUART configuration via properties
+    - LP: #1533035
+  * i2c: designware: Convert to use unified device property API
+    - LP: #1533035
+  * keys, trusted: fix: *do not* allow duplicate key options
+    - LP: #1398274
+  * keys, trusted: select hash algorithm for TPM2 chips
+    - LP: #1398274
+  * keys, trusted: seal with a TPM2 authorization policy
+    - LP: #1398274
+  * perf/x86/intel: Add perf core PMU support for Intel Knights Landing
+    - LP: #1461360
+  * perf/x86/intel/uncore: Add Knights Landing uncore PMU support
+    - LP: #1461360
+  * perf/x86/intel/uncore: Remove hard coding of PMON box control MSR
+    offset
+    - LP: #1461360
+  * drm/i915: WaRsDisableCoarsePowerGating
+    - LP: #1527462
+  * drm/i915/skl: Add SKL GT4 PCI IDs
+    - LP: #1527462
+  * drm/i915/skl: Disable coarse power gating up until F0
+    - LP: #1527462
+  * platform:x86: add Intel P-Unit mailbox IPC driver
+    - LP: #1520457
+  * intel_punit_ipc: add NULL check for input parameters
+    - LP: #1520457
+  * platform/x86: Add Intel Telemetry Core Driver
+    - LP: #1520457
+  * intel_pmc_ipc: update acpi resource structure for Punit
+    - LP: #1520457
+  * platform:x86: Add Intel telemetry platform device
+    - LP: #1520457
+  * platform:x86: Add Intel telemetry platform driver
+    - LP: #1520457
+  * platform:x86: Add Intel Telemetry Debugfs interfaces
+    - LP: #1520457
+  * cxlflash: a couple off by one bugs
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 28 Jan 2016 13:56:00 +0000
+
+linux (4.4.0-1.15) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1536803
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[SCSI] libiscsi: Reduce locking contention in fast path"
+    - LP: #1517142
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 20 Jan 2016 07:41:40 -0700
+
+linux (4.4.0-0.14) xenial; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "powerpc/pci: Remove unused struct pci_dn.pcidev field"
+    - LP: #1522415
+  * powerpc: Add __raw_rm_writeq() function
+    - LP: #1522415
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 19 Jan 2016 11:24:26 -0700
+
+linux (4.4.0-0.13) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] s390x -- the kernel provides ppp-modules such as there are
+  * SAUCE: (no-up) add compat_uts_machine= kernel command line override
+
+  [ Tim Gardner ]
+
+  * [Config] Update annotations for VIRTIO_{NET,BLK}
+    - LP: #1533382
+
+  [ Upstream Kernel Changes ]
+
+  * powerpc/powernv: Add support for Nvlink NPUs
+    - LP: #1522415
+  * powerpc/powernv: Fix update of NVLink DMA mask
+    - LP: #1522415
+  * powerpc/powernv: Change NPU PE# assignment
+    - LP: #1522415
+  * powerpc/powernv: Reserve PE#0 on NPU
+    - LP: #1522415
+  * KEYS: Fix keyring ref leak in join_session_keyring()
+    - LP: #1534887
+    - CVE-2016-0728
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 19 Jan 2016 05:49:09 -0700
+
+linux (4.4.0-0.12) xenial; urgency=low
+
+  [ Eric Dumazet ]
+
+  * SAUCE: (no-up) udp: properly support MSG_PEEK with truncated buffers
+    - LP: #1527902
+
+  [ Guilherme G. Piccoli ]
+
+  * SAUCE: powerpc/eeh: Validate arch in eeh_add_device_early()
+    - LP: #1486180
+
+  [ Tim Gardner ]
+
+  * SAUCE: AUFS - update to aufs4.x-rcN 20160111
+  * [Config] CONFIG_VIRTIO_BLK=y, CONFIG_VIRTIO_NET=y for s390
+    - LP: #1532886
+  * [Config] nvme.ko moved to drivers/nvme/host
+  * [Config] scsi_dh morphed into 4 modules
+  * [Config] CONFIG_IBMVNIC=m
+  * [Config] Add DRM ast driver to udeb installer image
+    - LP: #1514711
+  * [Config] CONFIG_KVM=y for s390x
+    - LP: #1532886
+  * [Config] Install spl/zfs under the kernel modules directory
+    Fixes some errors in generic.inclusion-list.log
+
+  [ Upstream Kernel Changes ]
+
+  * perf/x86/intel/uncore: Add Broadwell-EP uncore support
+    - LP: #1524574
+  * EDAC: Add DDR4 flag
+    - LP: #1519631
+  * EDAC, sb_edac: Virtualize several hard-coded functions
+    - LP: #1519631
+  * EDAC, sb_edac: Add support for duplicate device IDs
+    - LP: #1519631
+  * EDAC, sb_edac: Add Knights Landing (Xeon Phi gen 2) support
+    - LP: #1519631
+  * Driver for IBM System i/p VNIC protocol
+    - LP: #1532303
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 11 Jan 2016 09:57:16 -0700
+
+linux (4.4.0-0.11) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Fix bogus reconstruct script
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 11 Jan 2016 07:29:17 -0700
+
+linux (4.4.0-0.10) xenial; urgency=low
+
+  [ Haren Myneni ]
+
+  * SAUCE: crypto: nx-842 - Mask XERS0 bit in return value
+    - LP: #1529666
+
+  [ Serge Hallyn ]
+
+  * SAUCE: add a sysctl to disable unprivileged user namespace unsharing
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_ZONE_DEVICE=y for amd64
+  * [Config] CONFIG_BLK_DEV_LOOP=y for s390x
+    - LP: #1526869
+  * SAUCE: (no-up) apparmor: Fix incompatible pointer type warnings
+  * SAUCE: radeon: r100: Silence 'may be used uninitialized' warnings
+  * SAUCE: dmaengine: ioatdma: Squelch framesize warnings
+  * rebase to v4.4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 04 Jan 2016 17:43:51 -0700
+
+linux (4.4.0-0.9) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v4.4-rc8
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc8
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 03 Jan 2016 18:50:33 -0700
+
+linux (4.4.0-0.8) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v4.4-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 28 Dec 2015 16:13:11 -0700
+
+linux (4.4.0-0.7) xenial; urgency=low
+
+  [ Hui Wang ]
+
+  * [Config] CONFIG_I2C_DESIGNWARE_BAYTRAIL=y, CONFIG_IOSF_MBI=y
+    - LP: #1527096
+
+  [ Jann Horn ]
+
+  * SAUCE: (noup) ptrace: being capable wrt a process requires mapped
+    uids/gids
+    - LP: #1527374
+
+  [ Tim Gardner ]
+
+  * rebase to v4.4-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc6
+    - LP: #1526330
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 17 Dec 2015 05:28:27 -0700
+
+linux (4.4.0-0.6) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] disable CONFIG_ARM64_LSE_ATOMICS to avoid issues with ARMv8.1
+    support in latest compilers
+  * [Config] disable CONFIG_CRYPTO_AES_ARM64_CE* to avoid issues with
+    ARMv8.1 support in latest compilers
+
+  [ Tim Gardner ]
+
+  * [Config] s390 -> s390x
+  * SAUCE: include/linux/mmdebug.h: #include <linux/bug.h>
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Dec 2015 06:46:26 -0700
+
+linux (4.4.0-0.5) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] s390x -- enable tools
+    - LP: #1524319
+  * [Config] s390x -- add architecture to getabis
+  * [Config] s390x -- add s390x ABI information
+  * [Config] s390x -- enable ABI checks
+
+  [ Tim Gardner ]
+
+  * [Debian] config-check and prepare using ${DEBIAN}/config/annotations
+  * [Config] Add s390 modules to nic-modules udeb
+    - LP: #1525297
+  * rebase to v4.4-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc5
+    - LP: #1523517
+    - LP: #1523232
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 14 Dec 2015 05:28:05 -0700
+
+linux (4.4.0-0.4) xenial; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * cgroup: make css_set pin its css's to avoid use-afer-free
+  * cgroup_freezer: simplify propagation of CGROUP_FROZEN clearing in
+    freezer_attach()
+  * cgroup: fix handling of multi-destination migration from
+    subtree_control enabling
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Dec 2015 11:20:41 -0700
+
+linux (4.4.0-0.3) xenial; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc4
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 06 Dec 2015 16:50:15 -0700
+
+linux (4.4.0-0.2) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Add spl/zfs provides to generic and powerpc64-smp
+  * [Config] Add zfs to d-i fs-core-modules
+  * [Config] Include all s390 specific drivers in linux-image
+    - LP: #1522210
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 03 Dec 2015 07:05:56 -0700
+
+linux (4.4.0-0.1) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Tests] gcc-multilib does not exist on ppc64el redux
+    - LP: #1515541
+  * [Config] libunwind8-dev is not available on s390x
+  * [Debian] Disable SPL/ZFS for cross compiling -- redux
+  * [Config] s390x -- add dasd udebs
+    - LP: #1519833
+  * [Config] s390x -- include dasd modules in linux-image
+    - LP: #1519833
+  * [Config] s390x -- disable ZFS temporarily
+    - LP: #1519820
+  * [Config] s390s -- disable ABI/module checks
+  * [Config] make IBMVETH consistent on powerpc/ppc64el
+    - LP: #1521712
+  * [Config] follow ibmvscsi name change
+    - LP: #1521712
+  * [Config] move ibm disk and ethernet drivers to linux-image
+    - LP: #1521712
+  * [Config] include ibmveth in nic-modules for ppc64el
+    - LP: #1521712
+  * [Config] s390x -- disable abi/module checks for s390x
+
+  [ Joseph Salisbury ]
+
+  * SAUCE: scsi_sysfs: protect against double execution of
+    __scsi_remove_device()
+    - LP: #1509029
+
+  [ Seth Forshee ]
+
+  * [Config] CONFIG_DRM_AMDGPU_CIK=n
+    - LP: #1510405
+
+  [ Tim Gardner ]
+
+  * [Debian] Disable SPL/ZFS for cross compiling
+  * [Config] CONFIG_SCSI_IBMVSCSI=m
+    - LP: #1515872
+  * rebase to v4.4-rc2
+  * [Config] updateconfigs
+  * [Config] CONFIG_WILC1000_DRIVER=n for FTBS
+  * SAUCE: do_zfs=false temporarily
+  * [Config] CONFIG_LUSTRE_FS=n
+  * [Debian] Disable udebs when cross compiling
+  * rebase to v4.4-rc3
+  * [Config] CONFIG_AUFS_FS=m
+  * SAUCE: AUFS
+
+  [ Upstream Kernel Changes ]
+
+  * ZFS: Update with 4.4 support
+  * SPL: Update with 4.4 support
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc3
+    - LP: #1519168
+  * rebase to v4.4-rc2
+    - LP: #1506615
+    - LP: #1502781
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 23 Nov 2015 13:22:37 -0700
+
+linux (4.3.0-0.8) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] re-enable OSS support and blacklist
+    - LP: #1434842
+  * [Config] enable CONFIG_CC_STACKPROTECTOR_STRONG=y
+  * [Packaging] config-check -- improve syntax diagnostics
+  * [Packaging] module-inclusion -- add dependency inclusion for a list
+  * [Packaging] config-check -- accumulate multi-line annotations correctly
+  * [Packaging] config-check -- handle V2 annotations format
+  * [Packaging] s390x -- add architecture to kernelconfig
+    - LP: #1488653
+  * [Config] s390x -- initial configuration
+  * [Config] s390x -- add initial binary image
+  * [Config] s390x -- initial configuration update
+  * [Config] s390x -- produce linux-image
+  * [Config] s390x -- d-i module exclusions
+  * [Config] apply Device Drivers >> LED Support >> LED Class Support
+  * [Config] apply File systems >> Miscellaneous filesystems >> SquashFS 4.0 - Squashed file system support
+  * [Config] apply Device Drivers >> Generic Driver Options >> Userspace firmware loading support
+  * SAUCE: leds: lp55xx -- do not force use of the fallback loader
+  * [Config] -- s390x -- configuration review updates
+  * [Config] annotations -- add review marks
+  * [Config] annotations -- config review 4.3 updates
+  * [Config] annotations -- expose reviews
+  * [Config] updateconfigs following incoporation of s390x configs
+  * [Tests] gcc-multilib does not exist on ppc64el
+    - LP: #1515541
+
+  [ Dan Carpenter ]
+
+  * SAUCE: (noup) cxlflash: a couple off by one bugs
+    - LP: #1499849
+
+  [ Haren Myneni ]
+
+  * Revert "SAUCE: (noup) crypto: 842 - Add CRC and validation support"
+
+  [ Jay Vosburgh ]
+
+  * SAUCE: fan: add VXLAN implementation
+
+  [ Manoj Kumar ]
+
+  * SAUCE: (noup) cxlflash: Fix to escalate LINK_RESET also on port 1
+    - LP: #1513583
+
+  [ Matthew R. Ochs ]
+
+  * SAUCE: (noup) cxlflash: Fix to avoid virtual LUN failover failure
+    - LP: #1513583
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_AUFS_EXPORT=y
+    - LP: #1121699
+
+  [ Upstream Kernel Changes ]
+
+  * misc/genwqe: get rid of atomic allocations
+  * crypto: 842 - Add CRC and validation support
+    - LP: #1497878
+  * cxlflash: Fix to avoid invalid port_sel value
+  * cxlflash: Replace magic numbers with literals
+  * cxlflash: Fix read capacity timeout
+  * cxlflash: Fix potential oops following LUN removal
+  * cxlflash: Fix data corruption when vLUN used over multiple cards
+  * cxlflash: Fix to avoid sizeof(bool)
+  * cxlflash: Fix context encode mask width
+  * cxlflash: Fix to avoid CXL services during EEH
+  * cxlflash: Correct naming of limbo state and waitq
+  * cxlflash: Make functions static
+  * cxlflash: Refine host/device attributes
+  * cxlflash: Fix to avoid spamming the kernel log
+  * cxlflash: Fix to avoid stall while waiting on TMF
+  * cxlflash: Fix location of setting resid
+  * cxlflash: Fix host link up event handling
+  * cxlflash: Fix async interrupt bypass logic
+  * cxlflash: Remove dual port online dependency
+  * cxlflash: Fix AFU version access/storage and add check
+  * cxlflash: Correct usage of scsi_host_put()
+  * cxlflash: Fix to prevent workq from accessing freed memory
+  * cxlflash: Correct behavior in device reset handler following EEH
+  * cxlflash: Remove unnecessary scsi_block_requests
+  * cxlflash: Fix function prolog parameters and return codes
+  * cxlflash: Fix MMIO and endianness errors
+  * cxlflash: Fix to prevent EEH recovery failure
+  * cxlflash: Correct spelling, grammar, and alignment mistakes
+  * cxlflash: Fix to prevent stale AFU RRQ
+  * cxlflash: Fix to double the delay each time
+  * cxlflash: Fix to avoid corrupting adapter fops
+  * cxlflash: Correct trace string
+  * cxlflash: Fix to avoid potential deadlock on EEH
+  * cxlflash: Fix to avoid leaving dangling interrupt resources
+  * cxlflash: Fix to escalate to LINK_RESET on login timeout
+  * cxlflash: Fix to avoid corrupting port selection mask
+  * cxlflash: Fix to avoid lock instrumentation rejection
+  * cxlflash: Fix to avoid bypassing context cleanup
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 06 Nov 2015 10:15:07 -0600
+
+linux (4.3.0-0.7) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Revert "Bypass spl/zfs config"
+    Causes unresolved symbols on load.
+  * [Config] Enable ZFS for powerpc64-smp
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 05 Nov 2015 11:42:37 -0600
+
+linux (4.3.0-0.6) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1512704
+  * UBUNTU: SAUCE: AUFS aufs4.x-rcN 20151102
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] add feature interlock with mainline builds
+  * apparmor -- follow change to this_cpu_ptr
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: add parameter to control whether policy hashing is used
+    - LP: #1383886
+  * SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot
+    - LP: #1362199
+  * SAUCE: Revert: fix: only allow a single threaded process to ...
+    - LP: #1371310
+  * SAUCE: (no-up) fix: bad unix_addr_fs macro
+    - LP: #1390223
+  * SAUCE: (no-up): apparmor: fix mediation of fs unix sockets
+    - LP: #1408833
+  * SAUCE: (no-up) apparmor: fix mount not handling disconnected paths
+    - LP: #1496430
+
+  [ Tim Gardner ]
+
+  * [Config] Add iscsi_ibft and iscsi_boot_sysfs to generic inclusion list
+    - LP: #1511006
+  * rebase to v4.3
+  * Bypass spl/zfs config
+  * SPL/ZFS: Add Makefiles in order to avoid the lengthy config
+  * [Config] Default AppArmor settings
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.3
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 29 Oct 2015 09:16:26 -0600
+
+linux (4.3.0-0.5) xenial; urgency=low
+
+  * Update spl to 0.6.5.3-0ubuntu1, zfs to 0.6.5.3-0ubuntu1
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.3-rc7
+    - LP: #1504778
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 23 Oct 2015 13:59:52 -0600
+
+linux (4.3.0-0.4) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Debian] Update to new signing key type and location
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 21 Oct 2015 13:07:30 -0600
+
+linux (4.3.0-0.3) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Debian] sign-file is now compiled
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 21 Oct 2015 09:26:34 -0600
+
+linux (4.3.0-0.2) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Added libssl-dev to Build-Depends
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 20 Oct 2015 14:01:55 -0600
+
+linux (4.3.0-0.1) wily; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.3-rc6
+  * rebase to v4.3-rc5
+  * rebase to v4.3-rc4
+  * rebase to v4.3-rc3
+  * rebase to v4.3-rc2
+  * rebase to v4.3-rc1
+    - LP: #1492132
+    - LP: #1481575
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 14 Sep 2015 07:30:36 -0600
+
+linux (4.2.0-10.11) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1495208
+  * No change rebuild to avoid issues with leading zero bytes on
+    internal module signing key.  (see launchpad bug 1494943)
+
+  [ Ming Lei ]
+
+  * [Config] SERIAL_8250_DW=y for arm64
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915: Move WaBarrierPerformanceFixDisable:skl to skl code from chv
+    code
+    - LP: #1484486
+  * drm/i915/gen8: Add infrastructure to initialize WA batch buffers
+    - LP: #1484486
+  * drm/i915/gen8: Re-order init pipe_control in lrc mode
+    - LP: #1484486
+  * drm/i915/gen8: Add WaDisableCtxRestoreArbitration workaround
+    - LP: #1484486
+  * drm/i915/gen8: Add WaFlushCoherentL3CacheLinesAtContextSwitch
+    workaround
+    - LP: #1484486
+  * drm/i915: Bail out early if WA batch is not available for given Gen
+    - LP: #1484486
+  * drm/i915/gen8: Add WaClearSlmSpaceAtContextSwitch workaround
+    - LP: #1484486
+  * drm/i915: Update WaFlushCoherentL3CacheLinesAtContextSwitch
+    - LP: #1484486
+  * drm/i915/gen9: Implement WaDisableKillLogic for gen 9
+    - LP: #1484486
+  * drm/i915: Enable WA batch buffers for Gen9
+    - LP: #1484486
+  * drm/i915/gen9: Add WaDisableCtxRestoreArbitration workaround
+    - LP: #1484486
+  * drm/i915: Update wa_ctx_emit() macro as per kernel coding guidelines
+    - LP: #1484486
+  * drm/i915/gen9: Add WaFlushCoherentL3CacheLinesAtContextSwitch
+    workaround
+    - LP: #1484486
+  * drm/i915/gen9: Add
+    WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken
+    - LP: #1484486
+  * drm/i915:skl: Add WaEnableGapsTsvCreditFix
+    - LP: #1484486
+  * drm/i915/skl: revert duplicated WaBarrierPerformanceFixDisable:skl
+    - LP: #1484486
+  * drm/i915/skl: Don't expose the top most plane on gen9 display
+    - LP: #1484486
+  * drm/i915/skl WaDisableSbeCacheDispatchPortSharing
+    - LP: #1484486
+  * drm/i915/skl: WaIgnoreDDIAStrap is forever, always init DDI A
+    - LP: #1484486
+  * drm/i915: reduce indent in i9xx_hpd_irq_handler
+    - LP: #1484531
+  * drm/i915: reduce duplicate conditions in i9xx_hpd_irq_handler
+    - LP: #1484531
+  * drm/i915: reduce indent in intel_hpd_irq_handler
+    - LP: #1484531
+  * drm/i915: group all hotplug related fields into a new struct in
+    dev_priv
+    - LP: #1484531
+  * drm/i915: add for_each_hpd_pin to iterate over hotplug pins
+    - LP: #1484531
+  * drm/i915: simplify conditions for skipping the 2nd hpd loop iterations
+    - LP: #1484531
+  * drm/i915: put back the indent in intel_hpd_irq_handler
+    - LP: #1484531
+  * drm/i915: merge the two hpd loops in intel_hpd_irq_handler to one
+    - LP: #1484531
+  * drm/i915: simplify condition for digital port
+    - LP: #1484531
+  * drm/i915: abstract away platform specific parts from hpd handling
+    - LP: #1484531
+  * drm/i915: Handle HPD when it has actually occurred
+    - LP: #1484531
+  * drm/i915: Set power domain for DDI-E
+    - LP: #1484531
+  * drm/i915: Set alternate aux for DDI-E
+    - LP: #1484531
+  * drm/i915/skl: enable DDI-E hotplug
+    - LP: #1484531
+  * drm/i915/bxt: fix DDI PHY vswing scale value setting
+    - LP: #1494163
+  * drm/i915/skl: Buffer translation improvements
+    - LP: #1494163
+  * drm/i915: Per-DDI I_boost override
+    - LP: #1494163
+  * drm/i915: fix VBT parsing for SDVO child device mapping
+    - LP: #1494163
+  * drm/i915/bxt: edp1.4 Intermediate Freq support
+    - LP: #1494163
+  * drm/i915: fix link rates reported for SKL
+    - LP: #1494163
+  * drm/i915: Allow parsing of variable size child device entries from VBT
+    - LP: #1494163
+  * drm/i915/skl: Update DDI buffer translation programming.
+    - LP: #1494163
+  * drm/i915: Enable HDMI on DDI-E
+    - LP: #1484531
+  * drm/i915/skl: Enable DDI-E
+    - LP: #1484531
+  * drm/i915: eDP can be present on DDI-E
+    - LP: #1484531
+  * drm/i915/skl: Adding DDI_E power well domain
+    - LP: #1484531
+  * drm/i915: set CDCLK if DPLL0 enabled during resuming from S3
+    - LP: #1490035
+  * drm/i915: Split atomic wm update to pre and post variants
+    - LP: #1493746
+  * drm/i915/skl: Drop the preliminary_hw_support flag
+    - LP: #1486868
+  * drm/i915: set FDI translations to NULL on SKL
+    - LP: #1494163
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 13 Sep 2015 11:32:02 +0100
+
+linux (4.2.0-9.9) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1493970
+  * [Config] CONFIG_MFD_INTEL_LPSS=m
+    - LP: #1397876
+
+  [ dann frazier ]
+
+  * [Config] Disable CONFIG_IPMI_SI_PROBE_DEFAULTS on armhf and arm64
+    - LP: #1388952
+
+  [ Michael Ellerman ]
+
+  * SAUCE: crypto: vmx - VMX crypto should depend on CONFIG_VSX
+    Fixes FTBS on 32 bit powerpc, patch sent upstream.
+
+  [ Upstream Kernel Changes ]
+
+  * thermal/powerclamp: add cpu id for skylake h/s
+    - LP: #1398269
+  * perf/x86/intel/uncore: Add Broadwell-DE uncore support
+    - LP: #1397852
+  * mfd: watchdog: iTCO_wdt: Expose watchdog properties using platform data
+    - LP: #1460905
+  * i2c: i801: Create iTCO device on newer Intel PCHs
+    - LP: #1460905
+  * watchdog: iTCO_wdt: Add support for TCO on Intel Sunrisepoint
+    - LP: #1460905
+  * perf/x86: Add a native_perf_sched_clock_from_tsc()
+    - LP: #1397867
+  * perf/x86/intel: Add support for PEBSv3 profiling
+    - LP: #1397867
+  * perf/x86/intel/lbr: Allow time stamp for free running PEBSv3
+    - LP: #1397867
+  * x86: Add new MSRs and MSR bits used for Intel Skylake PMU support
+    - LP: #1397867
+  * perf: Add cycles to branch_info
+    - LP: #1397867
+  * perf/x86/intel/lbr: Add support for LBRv5
+    - LP: #1397867
+  * perf/x86/intel: Handle new arch perfmon v4 status bits
+    - LP: #1397867
+  * perf/x86/intel: Move PMU ACK to after LBR read
+    - LP: #1397867
+  * perf/x86/intel/lbr: Optimize v4 LBR unfreezing
+    - LP: #1397867
+  * perf/x86/intel: Add Intel Skylake PMU support
+    - LP: #1397867
+  * perf/x86/intel/lbr: Use correct index to save/restore LBR_INFO with
+    call stack
+    - LP: #1397867
+  * perf/x86/intel/lbr: Limit LBR accesses to TOS in callstack mode
+    - LP: #1397867
+  * perf/x86: Make merge_attr() global to use from perf_event_intel
+    - LP: #1397867
+  * perf/x86/intel: Use 0x11 as extra reg test value
+    - LP: #1397867
+  * perf tools: Add support for cycles, weight branch_info field
+    - LP: #1397867
+  * perf report: Add flag for non ANY branch mode
+    - LP: #1397867
+  * perf report: Add infrastructure for a cycles histogram
+    - LP: #1397867
+  * perf report: Add processing for cycle histograms
+    - LP: #1397867
+  * perf annotate: Compute IPC and basic block cycles
+    - LP: #1397867
+  * perf annotate: Finally display IPC and cycle accounting
+    - LP: #1397867
+  * perf top: Add branch annotation code to top
+    - LP: #1397867
+  * perf report: Display cycles in branch sort mode
+    - LP: #1397867
+  * perf annotate: Fix 32-bit compilation error in util/annotate.c
+    - LP: #1397867
+  * PM / QoS: Make it possible to expose device latency tolerance to
+    userspace
+    - LP: #1460908
+  * ACPI / PM: Attach ACPI power domain only once
+    - LP: #1460908
+  * Driver core: wakeup the parent device before trying probe
+    - LP: #1460908
+  * klist: implement klist_prev()
+    - LP: #1460908
+  * driver core: implement device_for_each_child_reverse()
+    - LP: #1460908
+  * mfd: make mfd_remove_devices() iterate in reverse order
+    - LP: #1460908
+  * dmaengine: add a driver for Intel integrated DMA 64-bit
+    - LP: #1460908
+  * mfd: Add support for Intel Sunrisepoint LPSS devices
+    - LP: #1460908
+  * spi: pxa2xx: Add support for Intel Sunrisepoint
+    - LP: #1397876
+  * spi: spi-pxa2xx: Remove unused legacy PXA DMA API channel numbers
+    - LP: #1397876
+  * spi: pxa2xx: Add terminating entry for pxa2xx_spi_pci_compound_match
+    - LP: #1397876
+  * spi: spi-pxa2xx: Remove unused legacy null dma buffer and allocation
+    for it
+    - LP: #1397876
+  * intel_idle: Skylake Client Support
+    - LP: #1397877
+  * powerpc/kernel: Switch to using MAX_ERRNO
+    - LP: #1458876
+  * powerpc/kernel: Change the do_syscall_trace_enter() API
+    - LP: #1458876
+  * powerpc: Drop unused syscall_get_error()
+    - LP: #1458876
+  * powerpc: Don't negate error in syscall_set_return_value()
+    - LP: #1458876
+  * powerpc: Rework syscall_get_arguments() so there is only one loop
+    - LP: #1458876
+  * powerpc: Use orig_gpr3 in syscall_get_arguments()
+    - LP: #1458876
+  * powerpc: Change syscall_get_nr() to return int
+    - LP: #1458876
+  * powerpc/kernel: Add SIG_SYS support for compat tasks
+    - LP: #1458876
+  * powerpc/kernel: Enable seccomp filter
+    - LP: #1458876
+  * selftests/seccomp: Make seccomp tests work on big endian
+    - LP: #1458876
+  * selftests/seccomp: Add powerpc support
+    - LP: #1458876
+  * eCryptfs: Invalidate dcache entries when lower i_nlink is zero
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Sep 2015 19:17:57 -0600
+
+linux (4.2.0-8.8) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1493357
+  * [Config] CONFIG_CRYPTO_DEV_NX_COMPRESS_CRYPTO obsolete
+    - LP: #1488495
+  * [Config] CONFIG_CXLFLASH=m
+  * [Config] CONFIG_CXL_EEH=y for ppc64el, powerpc64-smp
+
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] standardise on stage1 for the bootstrap stage in line with debian
+  * [Packaging] mark up control for stage1
+  * [Config] kernel-versions -- clean up deps field
+  * [Config] s390x -- build linux-libc-dev
+    - LP: #1488653
+  * [Packaging] control -- prepare for new kernel-wedge semantics
+
+  [ Upstream Kernel Changes ]
+
+  * crypto: vmx - Fixing AES-CTR counter bug
+    - LP: #1484519
+  * crypto: vmx - Fixing GHASH Key issue on little endian
+    - LP: #1484519
+  * powerpc: Uncomment and make enable_kernel_vsx() routine available
+    - LP: #1484519
+  * crypto: vmx - Adding enable_kernel_vsx() to access VSX instructions
+    - LP: #1484519
+  * crypto: nx - nx842_OF_upd_status should return ENODEV if device is not
+    'okay'
+    - LP: #1488495
+  * crypto: nx - rename nx842_{init, exit} to nx842_pseries_{init, exit}
+    - LP: #1488495
+  * crypto: nx - do not emit extra output if status is disabled
+    - LP: #1488495
+  * crypto: nx - reduce chattiness of platform drivers
+    - LP: #1488495
+  * crypto: nx/842 - Fix context corruption
+    - LP: #1488495
+  * crypto: nx - remove __init/__exit from VIO functions
+    - LP: #1488495
+  * crypto: nx - remove pSeries NX 'status' field
+    - LP: #1488495
+  * crypto: nx - move kzalloc() out of spinlock
+    - LP: #1488495
+  * crypto: nx - don't register pSeries driver if ENODEV
+    - LP: #1488495
+  * crypto: nx - use common code for both NX decompress success cases
+    - LP: #1488495
+  * crypto: nx - merge nx-compress and nx-compress-crypto
+    - LP: #1488495
+  * crypto: nx - rename nx-842-crypto.c to nx-842.c
+    - LP: #1488495
+  * crypto: nx - make platform drivers directly register with crypto
+    - LP: #1488495
+  * cxlflash: Base support for IBM CXL Flash Adapter
+    - LP: #1449121
+  * cxlflash: Base error recovery support
+    - LP: #1449121
+  * cxlflash: Superpipe support
+    - LP: #1449121
+  * cxlflash: Virtual LUN support
+    - LP: #1449121
+  * cxlflash: off by one bug in cxlflash_show_port_status()
+    - LP: #1449121
+  * cxlflash: shift wrapping bug in afu_link_reset()
+    - LP: #1449121
+  * cxlflash: Remove unused variable from queuecommand
+    - LP: #1449121
+  * powerpc/powernv: move dma_get_required_mask from pnv_phb to
+    pci_controller_ops
+  * powerpc/eeh: Probe after unbalanced kref check
+  * misc: cxl: clean up afu_read_config()
+  * cxl: Add explicit precision specifiers
+  * cxl: use more common format specifier
+  * cxl: Destroy cxl_adapter_idr on module_exit
+  * cxl: Destroy afu->contexts_idr on release of an afu
+  * cxl: Don't ignore add_process_element() result when attaching context
+  * cxl: Compile with -Werror
+  * cxl: sparse: Make declarations static
+  * cxl: sparse: Silence iomem warning in debugfs file creation
+  * cxl: Convert MMIO read/write macros to inline functions
+  * cxl: Drop commands if the PCI channel is not in normal state
+  * cxl: Allocate and release the SPA with the AFU
+  * cxl: Make IRQ release idempotent
+  * cxl: Clean up adapter MMIO unmap path.
+  * cxl: Refactor adaptor init/teardown
+  * cxl: Refactor AFU init/teardown
+  * cxl: Don't remove AFUs/vPHBs in cxl_reset
+  * cxl: Allow the kernel to trust that an image won't change on PERST.
+  * cxl: EEH support
+  * cxl: Add CONFIG_CXL_EEH symbol
+  * cxl: Plug irq_bitmap getting leaked in cxl_context
+  * cxl: Add alternate MMIO error handling
+  * cxl: Allow release of contexts which have been OPENED but not STARTED
+  * cxl: Remove use of macro DEFINE_PCI_DEVICE_TABLE
+  * cxl: Release irqs if memory allocation fails
+  * cxl: Remove racy attempt to force EEH invocation in reset
+  * cxl: Fix + cleanup error paths in cxl_dev_context_init
+  * cxl: Fix force unmapping mmaps of contexts allocated through the kernel api
+  * cxl: Set up and enable PSL Timebase
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 01 Sep 2015 07:38:43 -0600
+
+linux (4.2.0-7.7) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1490564
+  * rebase to v4.2
+
+  [ Wen Xiong ]
+
+  * SAUCE: ipr: Byte swapping for device_id attribute in sysfs
+    - LP: #1453892
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2
+    - LP: #1487345
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 26 Aug 2015 07:06:10 -0600
+
+linux (4.2.0-6.6) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1488138
+
+  [ Andy Whitcroft ]
+
+  * rebase to v4.2-rc8
+
+  [ Shilpasri G Bhat ]
+
+  * SAUCE: cpufreq: powernv: Handle throttling due to Pmax capping at chip
+    level
+    - LP: #1480894
+  * SAUCE: powerpc/powernv: Add definition of OPAL_MSG_OCC message type
+    - LP: #1480894
+  * SAUCE: cpufreq: powernv: Register for OCC related opal_message
+    notification
+    - LP: #1480894
+  * SAUCE: cpufreq: powernv: Call throttle_check() on receiving
+    OCC_THROTTLE
+    - LP: #1480894
+  * SAUCE: cpufreq: powernv: Report Psafe only if PMSR.psafe_mode_active
+    bit is set
+    - LP: #1480894
+  * SAUCE: cpufreq: powernv: Restore cpu frequency to policy->cur on
+    unthrottling
+    - LP: #1480894
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc8
+    - LP: #1483440
+    - LP: #1484334
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 21 Aug 2015 07:12:11 -0600
+
+linux (4.2.0-5.5) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1487173
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] correct spelling of probabaly on the tools packages
+    - LP: #1256822
+  * rebase to v4.2-rc7
+
+  [ dann frazier ]
+
+  * d-i: Add nicpf and nicvf to nic-modules
+  * d-i: Enable usb modules on arm64
+
+  [ Mahesh Salgaonkar ]
+
+  * SAUCE: powerpc/powernv: display reason for Malfunction Alert HMI.
+    - LP: #1482343
+  * SAUCE: powerpc/powernv: Pull all HMI events before panic.
+    - LP: #1482343
+  * SAUCE: powerpc/powernv: Invoke opal_cec_reboot2() on unrecoverable
+    machine check errors.
+    - LP: #1482343
+  * SAUCE: powerpc/powernv: Invoke opal_cec_reboot2() on unrecoverable HMI.
+    - LP: #1482343
+
+  [ Vipin K Parashar ]
+
+  * SAUCE: powerpc/powernv: Add poweroff (EPOW, DPO) events support for
+    PowerNV platform
+    - LP: #1469771
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 11 Aug 2015 09:48:40 -0600
+
+linux (4.2.0-4.4) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1483677
+
+  [ Achiad Shochat ]
+
+  * SAUCE: net/mlx5e: Support TX packet copy into WQE
+  * SAUCE: net/mlx5e: TX latency optimization to save DMA reads
+  * SAUCE: net/mlx5e: Cosmetics: use BIT() instead of "1 <<", and others
+  * SAUCE: net/mlx5e: Input IPSEC.SPI into the RX RSS hash function
+
+  [ Adam Lee ]
+
+  * SAUCE: serial: 8250_pci: Add support for Pericom PI7C9X795[1248]
+    - LP: #1480142
+
+  [ dann frazier ]
+
+  * [Config] CONFIG_NR_CPUS=128 on arm64
+
+  [ Leann Ogasawara ]
+
+  * [Config] d-i -- Add sfc to nic-modules udeb
+    - LP: #1481490
+
+  [ Saeed Mahameed ]
+
+  * SAUCE: net/mlx5e: Support ETH_RSS_HASH_XOR
+  * SAUCE: net/mlx5e: Allocate DMA coherent memory on reader NUMA node
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_X86_INTEL_MPX=y
+    - LP: #1460902
+  * [Debian] change dependency on module-init-tools to kmod
+    - LP: #1481986
+  * rebase to v4.2-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 04 Aug 2015 16:59:45 -0600
+
+linux (4.2.0-3.3) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1481462
+  * SAUCE: workqueue: Make flush_workqueue() available again to non GPL modules
+    Fixes an FTBS for at least one DKMS package.
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 04 Aug 2015 11:26:53 -0600
+
+linux (4.2.0-2.2) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1481067
+  * rebase to v4.2-rc5
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] module-inclusion -- commonise copy code and simplify
+  * [Packaging] module-inclusion -- add manual command entries
+  * [Packaging] module blacklists -- add support for manual blacklists
+  * [Packaging] do_common_tools should always be on
+  * [Packaging] initscripts need installing when making the package
+  * [Packaging] initscripts work around bug in debhelper systemd support
+  * [Config] exclude oss modules from linux-image
+    - LP: #1434842
+  * hyper-v -- add hid and fb drivers to linux-virtual
+    - LP: #1444179
+  * ubuntu: (no-squash) vbox -- infrastructure and updater
+  * ubuntu: vbox -- elide the new symlinks and reconstruct on clean:
+    - LP: #1426113
+  * ubuntu: vbox -- update to 5.0.0-dfsg-1
+    - LP: #1480879
+  * SAUCE: vbox: follow v4.2 updates to follow_link()/put_link() API
+  * [Config] move vbox modules into linux-image
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc5
+    - LP: #1478497
+    - LP: #1477900
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 03 Aug 2015 12:20:10 +0100
+
+linux (4.2.0-1.1~rc1) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1479903
+  * Initial upload of v4.2 based kernel (currently v4.-rc4)
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc4
+    - LP: #1476987
+    - LP: #1476888
+  * rebase to v4.2-rc3
+  * rebase to v4.2-rc2
+  * rebase to v4.2-rc1
+    - LP: #1394368
+    - LP: #1427680
+    - LP: #1462614
+    - LP: #1397021
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 30 Jul 2015 18:42:46 +0100
+
+linux (4.1.0-3.3) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1478897
+
+  [ Colin Ian King ]
+
+  * SAUCE: KEYS: ensure we free the assoc array edit if edit is valid
+    - CVE-2015-1333
+
+  [ Seth Forshee ]
+
+  * SAUCE: overlayfs: Enable user namespace mounts for the "overlay" fstype
+    - LP: #1478578
+
+  [ Upstream Kernel Changes ]
+
+  * sched/stop_machine: Fix deadlock between multiple stop_two_cpus()
+    - LP: #1461620
+  * x86/nmi: Enable nested do_nmi() handling for 64-bit kernels
+  * x86/nmi/64: Remove asm code that saves cr2
+  * x86/nmi/64: Switch stacks on userspace NMI entry
+  * x86/nmi/64: Reorder nested NMI checks
+  * x86/nmi/64: Use DF to avoid userspace RSP confusing nested NMI
+    detection
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 28 Jul 2015 11:59:03 +0100
+
+linux (4.1.0-2.4) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: overlayfs: when copying up and reading directories ensure
+    mounter had permissions V2
+    - CVE-2015-1328
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1465419
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 15 Jun 2015 14:09:22 -0700
+
+linux (4.1.0-2.2) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v4.1.3
+  * [Config] Add i40e[vf] to d-i
+    - LP: #1476393
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.1.3
+    - LP: #1427680
+    - LP: #1462614
+    - LP: #1394368
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 22 Jul 2015 09:13:02 -0600
+
+linux (4.1.0-1.1) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: overlay: add backwards compatible overlayfs format support V3
+    - LP: #1395877, #1410480
+  * SAUCE: overlayfs: when copying up and reading directories ensure
+    mounter had permissions V2
+    - CVE-2015-1328
+  * [Packaging] fix up Vcs-Git: to point to launchpad
+  * [Config] correct linux-initramfs-tool virtual linkage
+    - LP: #1474810
+
+  [ Chris J Arges ]
+
+  * [Config] Add dm-service-time to multipath-modules
+    - LP: #1469240
+  * [Config] Add MTD_POWERNV_FLASH and OPAL_PRD
+    - LP: #1464560
+
+  [ Jay Vosburgh ]
+
+  * SAUCE: fan: Proof of concept implementation (v2)
+    - LP: #1439706
+  * SAUCE: fan: tunnel multiple mapping mode (v3)
+    - LP: #1470091
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: ext4: disable ext4_punch_hole for indirect filesystems"
+  * Revert "SAUCE: intel_pstate: inform user that thermald is worth
+    considering"
+  * Revert "SAUCE: Work around broken ACPI backlight on Dell Inspiron 5537"
+  * Revert "SAUCE: dm-crypt: never use write same"
+  * Release Tracking Bug
+    - LP: #1476333
+
+  [ Tim Gardner ]
+
+  * Rebase to v4.1
+    - LP: #1443371
+  * [Config] Enable Apparmor
+  * [Config] CONFIG_OVERLAY_FS_V1=y
+  * [Config] DEFAULT_IOSCHED="deadline" for ppc64el
+    - LP: #1469829
+  * [Config] CONFIG_VM86=n
+    - LP: #1473447
+  * [Config] ACORN_PARTITION=n
+    - LP: #1453117
+
+  [ Timo Aaltonen ]
+
+  * [Config] Disable CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT
+    - LP: #1473319
+
+  [ Upstream Kernel Changes ]
+
+  * efi: efivar_create_sysfs_entry() should return negative error codes
+  * efi: Add esrt support
+  * x86, doc: Remove cmdline_size from list of fields to be filled in for
+    EFI handover
+  * efi/esrt: Fix some compiler warnings
+  * efi: dmi: List SMBIOS3 table before SMBIOS table
+  * efi: Add 'systab' information to Documentation/ABI
+  * ALSA: hda - restore the MIC FIXUP for some Dell machines
+    - LP: #1473560
+  * mtd: powernv: Add powernv flash MTD abstraction driver
+    - LP: #1464560
+  * powerpc/powernv: Expose OPAL APIs required by PRD interface
+    - LP: #1464560
+  * powerpc/powernv: Add opal-prd channel
+    - LP: #1464560
+  * powerpc/powernv: fix construction of opal PRD messages
+    - LP: #1464560
+  * powerpc/include: Add opal-prd to installed uapi headers
+    - LP: #1464560
+  * powerpc/powernv: Fix vma page prot flags in opal-prd driver
+    - LP: #1464560
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 20 Jul 2015 10:16:06 -0700
+
+linux (4.0.0-2.4) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: overlayfs: when copying up and reading directories ensure
+    mounter had permissions V2
+    - CVE-2015-1328
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1465419
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 15 Jun 2015 14:09:22 -0700
+
+linux (4.0.0-1.2) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: overlay: add backwards compatible overlayfs format support V3
+    - LP: #1395877, #1410480
+  * [Config] enable CONFIG_OVERLAY_FS_V1
+
+  [ Tai Nguyen ]
+
+  * SAUCE: power: reset: Add syscon reboot device node for APM X-Gene platform
+    - LP: #1463211
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_HIBERNATION=n for ppc64el
+    - LP: #1463836
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 12 Jun 2015 06:11:53 -0600
+
+linux (4.0.0-1.1) wily; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Revert "md/raid0: fix bug with chunksize not a power of 2."
+    - LP: #1457510
+  * powerpc/powernv: Check image loaded or not before calling flash
+    - LP: #1461553
+
+  [ Tim Gardner ]
+
+  * [Config] armhf: CPUFREQ_DT=y
+    - LP: #1457781
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.0.5
+    - LP: #1429756
+    - LP: #1452175
+    - LP: #1454656
+    - LP: #1447909
+    - LP: #1446517
+    - LP: #1428947
+    - LP: #1410704
+    - LP: #1412800
+    - LP: #1400215
+    - LP: #1411193
+    - LP: #1412800
+    - LP: #1408295
+    - LP: #1436745
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 09 Jun 2015 05:58:46 -0700
+
+linux (3.19.0-10.10) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] control -- make element ordering deterministic
+  * [Config] allow dracult to support initramfs as well
+    - LP: #1109029
+  * [Packaging] generate live watchdog blacklists
+    - LP: #1432837
+
+  [ Leann Ogasawara ]
+
+  * [Config] CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
+    - LP: #1397860
+  * rebase to v3.19.2
+
+  [ Upstream Kernel Changes ]
+
+  * thinkpad_acpi: support new BIOS version string pattern
+    - LP: #1417915
+  * arm64: Invalidate the TLB corresponding to intermediate page table
+    levels
+    - LP: #1432546
+  * perf tools: Support parsing parameterized events
+    - LP: #1430341
+  * perf tools: Extend format_alias() to include event parameters
+    - LP: #1430341
+  * perf Documentation: Add event parameters
+    - LP: #1430341
+  * perf tools: Document parameterized and symbolic events
+    - LP: #1430341
+  * perf: provide sysfs_show for struct perf_pmu_events_attr
+    - LP: #1430341
+  * perf: add PMU_EVENT_ATTR_STRING() helper
+    - LP: #1430341
+  * perf: define EVENT_DEFINE_RANGE_FORMAT_LITE helper
+    - LP: #1430341
+  * powerpc/perf/hv-24x7: parse catalog and populate sysfs with events
+    - LP: #1430341
+  * powerpc/perf/{hv-gpci, hv-common}: generate requests with counters
+    annotated
+    - LP: #1430341
+  * powerpc/perf/hv-gpci: add the remaining gpci requests
+    - LP: #1430341
+  * powerpc/perf/hv-24x7: Document sysfs event description entries
+    - LP: #1430341
+  * powerpc/iommu: Remove IOMMU device references via bus notifier
+    - LP: #1425202
+  * powerpc/pseries: Fix endian problems with LE migration
+    - LP: #1428351
+  * intel_idle: support additional Broadwell model
+    - LP: #1400970
+  * tools/power turbostat: support additional Broadwell model
+    - LP: #1400970
+  * KVM: x86: flush TLB when D bit is manually changed.
+    - LP: #1397860
+  * Optimize TLB flush in kvm_mmu_slot_remove_write_access.
+    - LP: #1397860
+  * KVM: Add generic support for dirty page logging
+    - LP: #1397860
+  * KVM: x86: switch to kvm_get_dirty_log_protect
+    - LP: #1397860
+  * KVM: Rename kvm_arch_mmu_write_protect_pt_masked to be more generic for
+    log dirty
+    - LP: #1397860
+  * KVM: MMU: Add mmu help functions to support PML
+    - LP: #1397860
+  * KVM: MMU: Explicitly set D-bit for writable spte.
+    - LP: #1397860
+  * KVM: x86: Change parameter of kvm_mmu_slot_remove_write_access
+    - LP: #1397860
+  * KVM: x86: Add new dirty logging kvm_x86_ops for PML
+    - LP: #1397860
+  * KVM: VMX: Add PML support in VMX
+    - LP: #1397860
+  * HID: multitouch: add support of clickpads
+  * HID: multitouch: Add support for button type usage
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19.2
+    - LP: #1428947
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 23 Mar 2015 15:28:16 +0000
+
+linux (3.19.0-9.9) vivid; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1430930
+
+  [ Shachar Raindel ]
+
+  * SAUCE: IB/core: Prevent integer overflow in ib_umem_get address
+    arithmetic
+    - LP: #1413741
+    - CVE-2014-8159
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 11 Mar 2015 10:29:17 -0700
+
+linux (3.19.0-8.8) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: vbox -- elide the new symlinks and reconstruct on clean:
+    - LP: #1426113
+  * rebase to stable v3.19.1
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up): apparmor: fix mediation of fs unix sockets
+    - LP: #1408833
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1429940
+
+  [ Upstream Kernel Changes ]
+
+  * xen: correct bug in p2m list initialization
+  * net/mlx5_core: Fix configuration of log_uar_page_sz
+    - LP: #1419938
+  * tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send
+    - LP: #1420575
+  * net/mlx4_core: Maintain a persistent memory for mlx4 device
+    - LP: #1422481
+  * net/mlx4_core: Set device configuration data to be persistent across
+    reset
+    - LP: #1422481
+  * net/mlx4_core: Refactor the catas flow to work per device
+    - LP: #1422481
+  * net/mlx4_core: Enhance the catas flow to support device reset
+    - LP: #1422481
+  * net/mlx4_core: Activate reset flow upon fatal command cases
+    - LP: #1422481
+  * net/mlx4_core: Manage interface state for Reset flow cases
+    - LP: #1422481
+  * net/mlx4_core: Handle AER flow properly
+    - LP: #1422481
+  * net/mlx4_core: Enable device recovery flow with SRIOV
+    - LP: #1422481
+  * net/mlx4_core: Reset flow activation upon SRIOV fatal command cases
+    - LP: #1422481
+  * tg3: Hold tp->lock before calling tg3_halt() from tg3_init_one()
+    - LP: #1428111
+  * rebase to v3.19.1
+    - LP: #1410704
+    - LP: #1411193
+    - LP: #1400215
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 09 Mar 2015 10:08:29 -0700
+
+linux (3.19.0-7.7) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1426013
+
+  [ Upstream Kernel Changes ]
+
+  * x86/irq: Fix regression caused by commit b568b8601f05
+  * cxl: Fix leaking interrupts if attach process fails
+    - LP: #1415102
+  * cxl: Early return from cxl_handle_fault for a shut down context
+    - LP: #1415102
+  * cxl: Disable AFU debug flag
+    - LP: #1415102
+  * cxl: Disable SPAP register when freeing SPA
+    - LP: #1415102
+  * cxl: remove redundant increment of hwirq
+    - LP: #1415102
+  * cxl: Add tracepoints
+    - LP: #1415102
+  * cxl: Update CXL ABI documentation
+    - LP: #1415102
+  * cxl: Use image state defaults for reloading FPGA
+    - LP: #1415102
+  * cxl: Add image control to sysfs
+    - LP: #1415102
+  * cxl: Enable CAPP recovery
+    - LP: #1415102
+  * cxl: Add ability to reset the card
+    - LP: #1415102
+  * cxl: Fix device_node reference counting
+    - LP: #1415102
+  * cxl: Export optional AFU configuration record in sysfs
+    - LP: #1415102
+  * cxl: Fail AFU initialisation if an invalid configuration record is
+    found
+    - LP: #1415102
+  * cxl: Add missing return statement after handling AFU errror
+    - LP: #1415102
+  * powerpc/eeh: Introduce flag EEH_PE_REMOVED
+    - LP: #1415102
+  * powerpc/eeh: Allow to set maximal frozen times
+    - LP: #1415102
+  * HID: i2c-hid: Limit reads to wMaxInputLength bytes for input events
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 26 Feb 2015 16:00:18 +0000
+
+linux (3.19.0-6.6) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * systemd -- fix hyper-v units to be non-forking
+    - LP: #1401525
+  * [Config] move vbox modules into linux-image
+  * ubuntu: vbox -- update to 4.3.22-dfsg-1
+
+  [ Brad Figg ]
+
+  * SAUCE: DEP8 test to run our regression tests
+
+  [ Paolo Pisati ]
+
+  * [Config] I2C_CHARDEV=y
+    - LP: #1417032
+
+  [ Upstream Kernel Changes ]
+
+  * PCI: Fix infinite loop with ROM image of size 0
+  * tpm: Fix NULL return in tpm_ibmvtpm_get_desired_dma
+  * Bluetooth: ath3k: workaround the compatibility issue with xHCI
+    controller
+    - LP: #1400215
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 19 Feb 2015 12:44:43 +0000
+
+linux (3.19.0-5.5) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_FA_DUMP=y
+    - LP: #1415562
+  * ubuntu: (no-squash) vbox -- infrastructure and updater
+  * ubuntu: vbox -- update to 4.3.20-dfsg-1ubuntu1
+  * rebase to v3.19 final
+
+  [ Chris J Arges ]
+
+  * [Config] Add ibmvfc to d-i
+    - LP: #1416001
+  * SAUCE: ext4: disable ext4_punch_hole for indirect filesystems
+    - LP: #1292234
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 09 Feb 2015 10:41:11 +0000
+
+linux (3.19.0-4.4) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] apply Kernel hacking >> Tracers config defaults
+  * hyper-v -- fix comment handing in /etc/network/interfaces
+    - LP: #1413020
+  * rebase to v3.19-rc7
+  * updateconfigs following rebase to v3.19-rc7
+
+  [ Ben Hutchings ]
+
+  * SAUCE: rtsx_usb_ms: Use msleep_interruptible() in polling loop
+    - LP: #1413149
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19-rc7
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 02 Feb 2015 17:03:07 +0200
+
+linux (3.19.0-3.3) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Debian] arm64 -- build ubuntu drivers
+    - LP: #1411284
+  * [Packaging] config-check -- add support for enforced annotations
+  * [Config] annotations -- switch to ENFORCED annotations
+  * [Packaging] config-check -- drop support for enforce file
+  * [Packaging] enforce -- drop empty enforce file
+  * rebase to v3.19-rc5
+  * [Config] add modules removed due to tighter dependencies
+  * [Config] updateconfigs following rebase to v3.19-rc5
+  * [Config] enforce CONFIG_FHANDLE=y
+    - LP: #1412543
+  * [Packaging] hyper-v -- daemons now require -n for non-forking startup
+    - LP: #1408355
+  * [Config] CONFIG_DEBUG_INFO_SPLIT=n
+    - LP: #1413646
+  * [Config] apply Device Drivers >> Character devices >> IPMI top-level
+    message handler config defaults
+  * [Config] apply Device Drivers >> Character devices >> Serial drivers
+    config defaults
+  * [Config] apply Device Drivers >> GPIO Support config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Direct Rendering
+    Manager >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI
+    support) config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Frame buffer
+    Devices >> Support for frame buffer devices config defaults
+  * [Config] apply Device Drivers >> HID support >> HID bus support >>
+    Special HID drivers config defaults
+  * [Config] apply Device Drivers >> Hardware Monitoring support config
+    defaults
+  * [Config] apply Device Drivers >> I2C support >> I2C support >> I2C
+    Hardware Bus support config defaults
+  * [Config] apply Device Drivers >> Industrial I/O support >> Analog to
+    digital converters config defaults
+  * [Config] apply Device Drivers >> Industrial I/O support >> Humidity
+    sensors config defaults
+  * [Config] apply Device Drivers >> Industrial I/O support >> Pressure
+    sensors config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Mice config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Touchscreens config defaults
+  * [Config] apply Device Drivers >> LED Support >> LED Class Support
+    config defaults
+  * [Config] apply Device Drivers >> MMC/SD/SDIO card support config
+    defaults
+  * [Config] apply Device Drivers >> Multifunction device drivers config
+    defaults
+  * [Config] apply Device Drivers >> Multimedia support >> Cameras/video
+    grabbers support >> Media test drivers config defaults
+  * [Config] apply Device Drivers >> Multimedia support >> Media PCI
+    Adapters config defaults
+  * [Config] apply Device Drivers >> Multimedia support >> Remote
+    Controller devices config defaults
+  * [Config] apply Device Drivers >> Network device support >> Distributed
+    Switch Architecture drivers config defaults
+  * [Config] apply Device Drivers >> Network device support >> Network core
+    driver support config defaults
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    >> Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) config
+    defaults
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    >> Intel PRO/Wireless 2200BG and 2915ABG Network Connection config
+    defaults
+  * [Config] apply Device Drivers >> PHY Subsystem config defaults
+  * [Config] apply Device Drivers >> Pin controllers config defaults
+  * [Config] apply Device Drivers >> SPI support config defaults
+  * [Config] apply Device Drivers >> Sound card support >> Advanced Linux
+    Sound Architecture >> ALSA for SoC audio support config defaults
+  * [Config] apply Device Drivers >> Sound card support >> Advanced Linux
+    Sound Architecture >> FireWire sound devices config defaults
+  * [Config] apply Device Drivers >> Sound card support >> Advanced Linux
+    Sound Architecture >> HD-Audio config defaults
+  * [Config] apply Device Drivers >> Staging drivers >> Lustre file system
+    client support config defaults
+  * [Config] apply Device Drivers >> Staging drivers >> Media staging
+    drivers config defaults
+  * [Config] apply Device Drivers >> USB support >> USB Gadget Support >>
+    USB Gadget Drivers >> USB functions configurable through configfs
+    config defaults
+  * [Config] apply Device Drivers >> USB support >> USB Gadget Support >>
+    USB Peripheral Controller config defaults
+  * [Config] apply Networking support >> NFC subsystem support >> Near
+    Field Communication (NFC) devices config defaults
+  * [Config] apply Networking support >> Networking options >> Network
+    packet filtering framework (Netfilter) >> Core Netfilter Configuration
+    >> Netfilter nf_tables support config defaults
+  * [Config] apply Networking support >> Networking options >> QoS and/or
+    fair queueing >> Actions config defaults
+  * [Config] apply Networking support >> Networking options >> TCP/IP
+    networking config defaults
+  * [Config] apply Networking support >> Wireless >> Generic IEEE 802.11
+    Networking Stack (mac80211) config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Keyboards config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Mice config defaults
+  * [Config] apply Device Drivers >> Pulse-Width Modulation (PWM) Support
+    config defaults
+  * [Config] apply Networking support >> Networking options >> Network
+    packet filtering framework (Netfilter) >> IP: Netfilter Configuration
+    >> IPv4 NAT config defaults
+  * [Config] apply Networking support >> Networking options >> Network
+    packet filtering framework (Netfilter) >> IPv6: Netfilter Configuration
+    >> IPv6 NAT config defaults
+  * [Config] apply Kernel hacking >> Kernel debugging config defaults
+  * [Config] apply General setup >> Timers subsystem >> Timer tick handling
+    config defaults
+  * SAUCE: arm64 -- psci tell the compiler which registers we are needing
+    values in
+    - LP: #1414002
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    >> Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N
+    (iwlwifi) config defaults
+  * [Config] apply Device Drivers >> Real Time Clock config defaults
+  * [Config] apply Device Drivers >> SCSI device support >> SCSI device
+    support >> SCSI low-level drivers config defaults
+  * [Config] apply General setup >> CPU/Task time and stats accounting >>
+    Cputime accounting config defaults
+  * [Config] apply Device Drivers >> Mailbox Hardware Support config
+    defaults
+  * rebase to v3.19-rc6
+  * [Config] updateconfigs following rebase to v3.19-rc6
+
+  [ Kamal Mostafa ]
+
+  * [Packaging] force "dpkg-source -I -i" behavior
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_USB_OTG
+    - LP: #1411295
+
+  [ Upstream Kernel Changes ]
+
+  * overlay: add backwards compatible overlayfs format support (fixes)
+    - LP: #1410480
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19-rc5
+  * rebase to v3.19-rc6
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 26 Jan 2015 11:37:39 +0000
+
+linux (3.19.0-2.2) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.19-rc4
+  * [Config] updateconfigs following rebase to v3.19-rc4
+  * [Packaging] install all dtb files
+    - LP: #1408002
+  * [Config] switch on "all" dtbs
+    - LP: #1408002
+
+  [ Colin Ian King ]
+
+  * SAUCE: drivers/rtc/interface.c: ignore exprired times when enqueing new
+    timers
+    - LP: #1333569
+
+  [ Joseph Salisbury ]
+
+  * [Config] Enable CONFIG_N_GSM as module.
+    - LP: #1404670
+
+  [ K. Y. Srinivasan ]
+
+  * SAUCE: storvsc: force SPC-3 compliance on win8 and win8 r2 hosts
+    - LP: #1406867
+
+  [ Steve McIntyre ]
+
+  * SAUCE: efi: Expose underlying UEFI firmware platform size to userland
+    - LP: #1409750
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19-rc4
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 13 Jan 2015 12:35:58 +0000
+
+linux (3.19.0-1.1) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: AUFS -- aufs3-standalone.patch"
+  * Revert "SAUCE: AUFS -- aufs3-mmap.patch"
+  * Revert "SAUCE: AUFS -- aufs3-base.patch"
+  * ubuntu: AUFS3 -- follow switch to vfs_fallocate
+  * rebase to v3.19-rc1
+  * rebase to v3.19-rc2
+  * [Config] defaultconfigs following rebase to v3.19-rc2
+  * ubuntu: aufs3 -- follow rename of d_child
+  * ubuntu: aufs3 -- follow switch to d_splice_alias
+  * ubuntu: aufs3 -- follow switch to get_unused_fd_flags()
+  * ubuntu: aufs3 -- follow rename for d_alias
+  * apparmor -- follow change to this_cpu_ptr
+  * disable module checks for rebase
+  * ubuntu: AUFS -- substrate: aufs3-base.patch
+  * ubuntu: AUFS -- substrate: aufs3-mmap.patch
+  * ubuntu: AUFS -- substrate: aufs3-standalone.patch
+  * ubuntu: AUFS -- update to 92ad9cc8bd289bf8e59b6bd8d83137d8e1a58c1c
+  * [Configs] updateconfigs following aufs update
+  * v3.19 series start
+  * rebase to v3.19-rc3
+  * [Configs] updateconfigs following rebase to v3.19-rc3
+  * [Packaging] uploadnum should be the remainder of the version
+    - LP: #1407755
+  * [Packaging] handle dts directories
+    - LP: #1408004
+  * [Config] follow move of arm64 dts' into vendor directories
+
+  [ Upstream Kernel Changes ]
+
+  * arm64: optimized copy_to_user and copy_from_user assembly code
+    - LP: #1400349
+  * iommu/ipmmu-vmsa: follow flag switch to IOMMU_NOEXEC
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19-rc1
+    - LP: #1173681
+  * rebase to v3.19-rc2
+  * rebase to v3.19-rc3
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 06 Jan 2015 14:30:02 +0000
+
+linux (3.18.0-7.8) vivid; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1401590
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot
+    - LP: #1362199
+  * SAUCE: Revert: fix: only allow a single threaded process to ...
+    - LP: #1371310
+  * SAUCE: (no-up) fix: bad unix_addr_fs macro
+    - LP: #1390223
+  * SAUCE: (no-up) apparmor: add parameter to control whether policy
+    hashing is used
+    - LP: #1383886
+  * [config] set apparmor config options
+
+  [ Seth Forshee ]
+
+  * [Config] CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
+    - LP: #1398458
+
+  [ Upstream Kernel Changes ]
+
+  * mfd: rtsx: Fix PM suspend for 5227 & 5249
+    - LP: #1359052
+  * mmc: sdhci-pci-o2micro: Fix Dell E5440 issue
+    - LP: #1346067
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 11 Dec 2014 08:36:36 -0800
+
+linux (3.18.0-6.7) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) arm64: optimized copy_to_user and copy_from_user
+    assembly code"
+    - LP: #1398596
+  * rebase to v3.18
+
+  [ Chris J Arges ]
+
+  * [Config] CONFIG_PCIEASPM_DEBUG=y
+    - LP: #1398544
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: VIRTIO_[BALLOON|MMIO]=y
+    - LP: #1396470
+
+  [ Upstream Kernel Changes ]
+
+  * drivers:scsi:storvsc: Fix a bug in handling ring buffer failures that
+    may result in I/O freeze
+    - LP: #1400289
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 08 Dec 2014 09:15:17 -0800
+
+linux (3.18.0-5.6) vivid; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1398109
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_SCSI_MQ_DEFAULT=n
+    - LP: #1397061
+  * rebase to v3.18-rc7
+
+  [ Chris J Arges ]
+
+  * [Config] CONFIG_SCOM_DEBUGFS=y for powerpc/powerpc64-smp
+    ppc64el/generic
+    - LP: #1395855
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc7
+    - LP: #1389497
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 01 Dec 2014 10:09:09 -0800
+
+linux (3.18.0-4.5) vivid; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1395891
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.18-rc6
+  * [Config] update configs following rebase to v3.18-rc6
+  * [Config] enable overlayfs v1 support
+
+  [ Tim Gardner ]
+
+  * rebase to v3.18-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * overlay: add backwards compatible overlayfs format support
+    - LP: #1395877
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc5
+  * rebase to v3.18-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 24 Nov 2014 13:12:48 -0800
+
+linux (3.18.0-3.4) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] CONFIG_AUFS_FS=n for FTBS"
+  * Revert "SAUCE: AUFS -- update to
+    dcf336a754c86d5ee1c3d50699fd75c586d037cb"
+  * Revert "SAUCE: aufs3 -- (no-up) aufs3-standalone.patch"
+  * Revert "SAUCE: aufs3 -- (no-up) aufs3-base.patch"
+  * [Config] amd64 is now the indep architecture
+  * [Debian] basic hook support
+  * SAUCE: AUFS -- aufs3-base.patch
+  * SAUCE: AUFS -- aufs3-mmap.patch
+  * SAUCE: AUFS -- aufs3-standalone.patch
+  * ubuntu: AUFS -- update to 9d5c349d5c452170b8e813d86956f896a0aef170
+  * [Config] updateconfigs following aufs3 update
+  * SAUCE: AUFS (no-squash): basic framework and update machinary -- part 2
+
+  [ dann frazier ]
+
+  * [Config] Disable CONFIG_IPMI_SI_PROBE_DEFAULTS on armhf and arm64
+    - LP: #1388952
+  * [Config] disable CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET
+  * [Config] Disable CONFIG_RCU_USER_QS on arm64
+
+  [ Tim Gardner ]
+
+  * rebase to v3.18-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc4
+    - LP: #1389497
+    - LP: #1387128
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 11 Nov 2014 17:16:13 +0000
+
+linux (3.18.0-2.2) vivid; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: nft_reject_bridge.c: Include net/ip6_checksum.h
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc3
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 03 Nov 2014 06:09:06 -0700
+
+linux (3.18.0-1.1) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] Switch kernel to vmlinuz (from vmlinux) on ppc64el"
+  * [Config] tools -- only build common tools when enabled
+  * [Config] follow rename of DEB_BUILD_PROFILES
+  * [Config] linux-image-extra is additive to linux-image
+    - LP: #1375310
+  * [Config] linux-image-extra postrm is not needed on purge
+  * [Config] enable cloud tools on i386
+    - LP: #1367399
+
+  [ Marc Dietrich ]
+
+  * [Config] arm/tegra/d-i: framebuffer and usb support for Tegra SoCs
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: REGULATOR_TWL4030=y
+  * [Config] armhf: disable JUMP_LABEL
+    - LP: #1378856
+
+  [ Tim Gardner ]
+
+  * rebase to v3.17-rc2
+  * updateconfigs
+  * [Config] CONFIG_NFC_ST21NFCB=n
+  * [Config] Added net/6lowpan/* to generic inclusion list
+  * [Config] Add arm64 to enforcer CONFIG_CC_STACKPROTECTOR
+  * rebase to v3.17-rc3
+  * rebase to v3.17-rc4
+  * rebase to v3.17-rc5
+  * [Config] armhf: USB_[E|O]HCI_EXYNOS=y
+  * [Config] CONFIG_XMON=y
+    - LP: #1365655
+  * [Config] CONFIG_KVM_BOOK3S_64=m for ppc64el
+    - LP: #1362514
+  * [Config] CONFIG_KVM_BOOK3S_64_HV=m
+    - LP: #1362514
+  * [Config] CONFIG_DMA_CMA=n
+    - LP: #1362261
+  * [Config] Add mpt3sas to d-i
+    - LP: #1368907
+  * [Debian] set do_*_tools after stage1 or bootstrap is determined
+    - LP: #1370211
+  * [Config] CONFIG_USB_OHCI_HCD_PCI=y
+    - LP: #1244176
+  * rebase to v3.17-rc6
+  * SAUCE: usbip: Update include path
+  * [Debian] usbip tools packaging
+    - LP: #898003
+  * [Config] Enable usbip tools
+    - LP: #898003
+  * [Config] CONFIG_CRASH_DUMP=n for powerpc-smp
+    - LP: #1363180
+  * [Config] Correct annotation regarding CONFIG_DMA_CMA
+    - LP: #1362261
+  * [Config] CONFIG_SND_HDA_INTEL=n for ppc64el
+    - LP: #1374438
+  * [Config] CONFIG_HOTPLUG_PCI_SHPC=n for ppc64el
+    - LP: #1374440
+  * [Debian] Don't fail if a symlink already exists
+  * rebase to v3.17-rc7
+  * [Config] CONFIG_HOTPLUG_PCI_PCIE=n for ppc64el
+    - LP: #1374440
+  * rebase to v3.17
+  * rebase to v3.18-rc1
+  * [Config] CONFIG_AUFS_FS=n for FTBS
+  * Enable vivid
+  * [Config] CONFIG_SOUND_OSS_CORE_PRECLAIM=n
+    - LP: #1385510
+  * rebase to v3.18-rc2
+  * [Debian] Fix linux-doc dangling symlinks
+    - LP: #661306
+  * CONFIG_MODULE_COMPRESS=n
+  * [Config] dropped scsi_tgt from generic inclusion list
+  * [Config] Added drivers/uio to generic inclusion list
+  * [Config] CONFIG_PATA_MACIO=y
+    - LP: #1378894
+  * [Config] CONFIG_DRM_BOCHS=n
+  * [Debian] install usbipd
+    - LP: #898003
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc2
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc1
+    - LP: #1316518
+    - LP: #1371591
+    - LP: #1357928
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc2
+    - LP: #1358116
+    - LP: #1350148
+    - LP: #1334950
+    - LP: #1329580
+    - LP: #1329580
+    - LP: #1329580
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc2
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 26 Aug 2014 10:36:19 -0600
+
+linux (3.17.0-0.0) utopic; urgency=medium
+
+  * Empty entry
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 26 Aug 2014 10:34:44 -0600
+
+linux (3.16.0-11.16) utopic; urgency=low
+
+  [ Mauricio Faria de Oliveira ]
+
+  * [Config] Switch kernel to vmlinuz (from vmlinux) on ppc64el
+    - LP: #1358920
+
+  [ Peter Zijlstra ]
+
+  * SAUCE: (no-up) mmu_notifier: add call_srcu and sync function for listener to delay call and sync
+    - LP: #1361300
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_ZPOOL=y
+    - LP: #1360428
+  * Release Tracking Bug
+    - LP: #1361308
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "net/mlx4_en: Fix bad use of dev_id"
+    - LP: #1347012
+  * net/mlx4_en: Reduce memory consumption on kdump kernel
+    - LP: #1347012
+  * net/mlx4_en: Fix mac_hash database inconsistency
+    - LP: #1347012
+  * net/mlx4_en: Disable blueflame using ethtool private flags
+    - LP: #1347012
+  * net/mlx4_en: current_mac isn't updated in port up
+    - LP: #1347012
+  * net/mlx4_core: Use low memory profile on kdump kernel
+    - LP: #1347012
+  * Drivers: scsi: storvsc: Change the limits to reflect the values on the host
+    - LP: #1347169
+  * Drivers: scsi: storvsc: Set cmd_per_lun to reflect value supported by the Host
+    - LP: #1347169
+  * Drivers: scsi: storvsc: Filter commands based on the storage protocol version
+    - LP: #1347169
+  * Drivers: scsi: storvsc: Fix a bug in handling VMBUS protocol version
+    - LP: #1347169
+  * Drivers: scsi: storvsc: Implement a eh_timed_out handler
+    - LP: #1347169
+  * drivers: scsi: storvsc: Set srb_flags in all cases
+    - LP: #1347169
+  * drivers: scsi: storvsc: Correctly handle TEST_UNIT_READY failure
+    - LP: #1347169
+  * namespaces: Use task_lock and not rcu to protect nsproxy
+    - LP: #1328088
+  * net: xgene: Check negative return value of xgene_enet_get_ring_size()
+  * mm/zbud: change zbud_alloc size type to size_t
+    - LP: #1360428
+  * mm/zpool: implement common zpool api to zbud/zsmalloc
+    - LP: #1360428
+  * mm/zpool: zbud/zsmalloc implement zpool
+    - LP: #1360428
+  * mm/zpool: update zswap to use zpool
+    - LP: #1360428
+  * ideapad-laptop: Change Lenovo Yoga 2 series rfkill handling
+    - LP: #1341296
+  * iommu/amd: Fix for pasid initialization
+    - LP: #1361300
+  * iommu/amd: Moving PPR fault flags macros definitions
+    - LP: #1361300
+  * iommu/amd: Drop oprofile dependency
+    - LP: #1361300
+  * iommu/amd: Fix typo in amd_iommu_v2 driver
+    - LP: #1361300
+  * iommu/amd: Don't call mmu_notifer_unregister in __unbind_pasid
+    - LP: #1361300
+  * iommu/amd: Don't free pasid_state in mn_release path
+    - LP: #1361300
+  * iommu/amd: Get rid of __unbind_pasid
+    - LP: #1361300
+  * iommu/amd: Drop pasid_state reference in ppr_notifer error path
+    - LP: #1361300
+  * iommu/amd: Add pasid_state->invalid flag
+    - LP: #1361300
+  * iommu/amd: Don't hold a reference to mm_struct
+    - LP: #1361300
+  * iommu/amd: Don't hold a reference to task_struct
+    - LP: #1361300
+  * iommu/amd: Don't call the inv_ctx_cb when pasid is not set up
+    - LP: #1361300
+  * iommu/amd: Don't set pasid_state->mm to NULL in unbind_pasid
+    - LP: #1361300
+  * iommu/amd: Remove change_pte mmu_notifier call-back
+    - LP: #1361300
+  * iommu/amd: Fix device_state reference counting
+    - LP: #1361300
+  * iommu/amd: Fix 2 typos in comments
+    - LP: #1361300
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 22 Aug 2014 08:45:54 -0400
+
+linux (3.16.0-10.15) utopic; urgency=low
+
+  [ dann frazier ]
+
+  * [debian] Fix regression with ABI subversions and backport
+
+  [ Feng Kan ]
+
+  * SAUCE: (no-up) irqchip:gic: change access of gicc_ctrl register to read
+    modify write.
+    - LP: #1357527
+  * SAUCE: (no-up) arm64: optimized copy_to_user and copy_from_user
+    assembly code
+    - LP: #1358949
+
+  [ Stefan Bader ]
+
+  * SAUCE: bcache: prevent crash on changing writeback_running
+    - LP: #1357295
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_XFRM_STATISTICS=y
+  * [Config] CONFIG_SECURITY_NETWORK_XFRM=y
+  * [Config] CONFIG_SENSORS_IBMPOWERNV=m
+    - LP: #1353005
+  * Release Tracking Bug
+    - LP: #1359783
+
+  [ Upstream Kernel Changes ]
+
+  * intel_idle: Broadwell support
+    - LP: #1256170
+  * powerpc/book3s: Add basic infrastructure to handle HMI in Linux.
+    - LP: #1357108
+  * powerpc/powernv: Invoke opal call to handle hmi.
+    - LP: #1357108
+  * powerpc/book3s: handle HMIs for cpus in nap mode.
+    - LP: #1357108
+  * powerpc/book3s: Fix endianess issue for HMI handling on napping cpus.
+    - LP: #1357108
+  * powerpc: Add smp_mb() to arch_spin_is_locked()
+    - LP: #1358569
+  * powerpc: Add smp_mb()s to arch_spin_unlock_wait()
+    - LP: #1358569
+  * hwmon: (powerpc/powernv) hwmon driver for power, fan rpm, voltage and
+    temperature
+    - LP: #1353005
+  * tools/testing/selftests/ptrace/peeksiginfo.c: add PAGE_SIZE definition
+    - LP: #1358855
+  * printk: Add function to return log buffer address and size
+    - LP: #1359423
+  * powerpc/powernv: Interface to register/unregister opal dump region
+    - LP: #1359423
+  * bcache: fix crash on shutdown in passthrough mode
+    - LP: #1357295
+  * bcache: fix uninterruptible sleep in writeback thread
+    - LP: #1357295
+
+  [ Vinayak Kale ]
+
+  * SAUCE: (no-up) dt-bindings: Add Potenza PMU binding
+    - LP: #1357527
+  * SAUCE: (no-up) arm64: dts: Add PMU node for APM X-Gene Storm SOC
+    - LP: #1357527
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 15 Aug 2014 12:34:33 -0600
+
+linux (3.16.0-9.14) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1357370
+
+  [ Serge Hallyn ]
+
+  * SAUCE: Overlayfs: allow unprivileged mounts
+    - LP: #1357025
+
+  [ Upstream Kernel Changes ]
+
+  * MAINTAINERS: Add entry for APM X-Gene SoC ethernet driver
+  * Documentation: dts: Add bindings for APM X-Gene SoC ethernet driver
+  * dts: Add bindings for APM X-Gene SoC ethernet driver
+  * drivers: net: Add APM X-Gene SoC ethernet driver support.
+  * powerpc/thp: Add write barrier after updating the valid bit
+    - LP: #1357014
+  * powerpc/thp: Don't recompute vsid and ssize in loop on invalidate
+    - LP: #1357014
+  * powerpc/thp: Invalidate old 64K based hash page mapping before insert
+    of 4k pte
+    - LP: #1357014
+  * powerpc/thp: Handle combo pages in invalidate
+    - LP: #1357014
+  * powerpc/thp: Invalidate with vpn in loop
+    - LP: #1357014
+  * powerpc/thp: Use ACCESS_ONCE when loading pmdp
+    - LP: #1357014
+  * powerpc/mm: Use read barrier when creating real_pte
+    - LP: #1357014
+  * powerpc/thp: Add tracepoints to track hugepage invalidate
+    - LP: #1357014
+  * rebase to v3.16.1
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 14 Aug 2014 08:18:02 -0400
+
+linux (3.16.0-8.13) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1356403
+
+  [ dann frazier ]
+
+  * [debian] Allow for package revisions condusive for branching
+
+  [ Upstream Kernel Changes ]
+
+  * ahci_xgene: Fix the watermark threshold for the APM X-Gene SATA host controller driver.
+    - LP: #1350087
+  * ahci_xgene: Use correct OOB tunning parameters for APM X-Gene SoC AHCI SATA Host controller driver.
+    - LP: #1350087
+  * powerpc/powernv: Enable M64 aperatus for PHB3
+    - LP: #1355469
+  * powerpc: Fail remap_4k_pfn() if PFN doesn't fit inside PTE
+    - LP: #1352994
+  * powerpc: Add machine_early_initcall()
+    - LP: #1352640
+  * powerpc/powernv: Switch powernv drivers to use machine_xxx_initcall()
+    - LP: #1352640
+  * powerpc/eeh: Avoid event on passed PE
+    - LP: #1352640
+  * powerpc/eeh: EEH support for VFIO PCI device
+    - LP: #1352640
+  * powerpc/eeh: sysfs entries lost
+    - LP: #1352640
+  * powerpc/powernv: Fix IOMMU table for VFIO dev
+    - LP: #1352640
+  * powerpc/eeh: Fetch IOMMU table in reliable way
+    - LP: #1352640
+  * powerpc/eeh: Refactor EEH flag accessors
+    - LP: #1352640
+  * powerpc/eeh: Selectively enable IO for error log
+    - LP: #1352640
+  * powerpc/eeh: Reduce lines of log dump
+    - LP: #1352640
+  * powerpc/eeh: Replace pr_warning() with pr_warn()
+    - LP: #1352640
+  * powerpc/eeh: Make diag-data not endian dependent
+    - LP: #1352640
+  * powerpc/eeh: Aux PE data for error log
+    - LP: #1352640
+  * PCI: Support BAR sizes up to 128GB
+    - LP: #1352640
+  * powerpc/powernv: Allow to freeze PE
+    - LP: #1352640
+  * powerpc/powernv: Split ioda_eeh_get_state()
+    - LP: #1352640
+  * powerpc/powernv: Handle compound PE
+    - LP: #1352640
+  * powerpc/powernv: Handle compound PE for EEH
+    - LP: #1352640
+  * powerpc/powernv: Handle compound PE in config accessors
+    - LP: #1352640
+  * mnt: Only change user settable mount flags in remount
+    - LP: #1356318
+    - CVE-2014-5206
+  * mnt: Move the test for MNT_LOCK_READONLY from change_mount_flags into do_remount
+    - LP: #1356318
+    - CVE-2014-5206
+  * mnt: Correct permission checks in do_remount
+    - LP: #1356323
+    - CVE-2014-5207
+  * mnt: Change the default remount atime from relatime to the existing value
+    - LP: #1356323
+    - CVE-2014-5207
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 10 Aug 2014 09:10:51 -0600
+
+linux (3.16.0-7.12) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.16 final
+  * [Config] d-i -- add virtio_scsi to virtio-modules
+    - LP: #1342000
+
+  [ dann frazier ]
+
+  * [Packaging] Fix 'printchanges' to work with versions containing '+'
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_MICROCODE=y
+    - LP: #1084373
+  * [Config] CONFIG_CONTEXT_TRACKING_FORCE=n
+    - LP: #1349028
+  * [Config] Add hv_balloon to d-i virtio-modules
+    - LP: #1292216
+  * Release Tracking Bug
+    - LP: #1354530
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 29 Jul 2014 09:55:15 -0400
+
+linux (3.16.0-6.11) utopic; urgency=low
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: MXS_DMA=y && MTD_NAND_GPMI_NAND=m
+  * [Config] armhf: KEYBOARD_IMX=m
+  * [Config] armhf: build cubox & imx6 DTBs
+  * [Config] armhf: RTC_DRV_PCF8523=y
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_KEYS_DEBUG_PROC_KEYS=y
+    - LP: #1344405
+  * [Config] CONFIG_SCSI_IPR_TRACE=y, CONFIG_SCSI_IPR_DUMP=y
+    - LP: #1343109
+  * Release Tracking Bug
+    - LP: #1349196
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 24 Jul 2014 09:08:55 -0400
+
+linux (3.16.0-5.10) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1346298
+  * [Config] CONFIG_GPIO_SYSFS=y
+    - LP: #1342153
+  * rebase to v3.16-rc6
+
+  [ Paolo Pisati ]
+
+  * [Config] enable ARCH_MVEBU*
+  * [Config] AHCI_MVEBU=m
+  * [Config] ARMADA_THERMAL=y
+  * [Config] ARM_ARMADA_370_XP_CPUIDLE=y
+  * [Config] CRYPTO_DEV_MV_CESA=m
+  * [Config] I2C_MV64XXX=m
+  * [Config] MMC_MVSDIO=m
+  * [Config] MMC_SDHCI_DOVE=m
+  * [Config] MTD_NAND_ORION=m
+  * [Config] MTD_NAND_PXA3xx=m
+  * [Config] MVNETA=m
+  * [Config] MV_XOR=y
+  * [Config] ORION_WATCHDOG=m
+  * [Config] PCI_MVEBU=y
+  * [Config] RTC_DRV_MV=y
+  * [Config] SND_KIRKWOOD_SOC*=m
+  * [Config] SPI_ORION=m
+  * [Config] USB_XHCI_MVEBU=m
+  * [Config] armhf: build all Armada and Dove DTBs
+  * [Config] armhf: SERIAL_8250_DW=y
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Jul 2014 07:49:42 -0400
+
+linux (3.16.0-4.9) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1341543
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc5
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 13 Jul 2014 21:30:27 -0400
+
+linux (3.16.0-3.8) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1340091
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 10 Jul 2014 10:06:47 +0100
+
+linux (3.16.0-2.7) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: aufs3 -- avoid aufs3-mmap.patch include hell for arm64
+    ubuntu: aufs3 -- (no-up) aufs3-mmap.patch
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 09 Jul 2014 16:16:28 +0100
+
+linux (3.16.0-2.6) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: aufs3 -- (no-up) aufs3-mmap.patch"
+    Fixes FTBS.
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Jul 2014 17:29:26 +0100
+
+linux (3.16.0-2.5) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu -- fix basic format for ubuntu/Makefile
+  * ubuntu: AUFS (no-squash): basic framework and update machinary
+  * ubuntu: aufs3 -- update update scripting
+  * ubuntu: aufs3 -- (no-up) aufs3-base.patch
+  * ubuntu: aufs3 -- (no-up) aufs3-mmap.patch
+  * ubuntu: aufs3 -- (no-up) aufs3-standalone.patch
+  * ubuntu: AUFS -- update to dcf336a754c86d5ee1c3d50699fd75c586d037cb
+  * [Configs] AUFS configs
+  * ubuntu: aufs3 -- reenable
+
+  [ Tim Gardner ]
+
+  * CONFIG_LATENCYTOP=n
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Jul 2014 15:27:35 +0100
+
+linux (3.16.0-2.4) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] flip VIRTIO*=y
+  * [Config] commonise CONFIG_SWIOTLB=y
+  * [Config] apply Bus options (PCI etc.) >> PCI support config defaults
+  * [Config] apply Device Drivers >> ATA/ATAPI/MFM/RLL support (DEPRECATED)
+    config defaults
+  * [Config] apply Device Drivers >> Block devices config defaults
+  * [Config] apply Device Drivers >> Character devices config defaults
+  * [Config] apply Device Drivers >> DMA Engine support config defaults
+  * [Config] apply Device Drivers >> EDAC (Error Detection And Correction)
+    reporting config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Direct Rendering
+    Manager >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI
+    support) config defaults
+  * [Config] apply Device Drivers >> GPIO Support config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Console display
+    driver support config defaults
+  * [Config] apply Device Drivers >> IIO staging drivers >> Accelerometers
+    config defaults
+  * [Config] apply Device Drivers >> IOMMU Hardware Support config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Miscellaneous devices config
+    defaults
+  * [Config] apply Device Drivers >> Input device support >> Hardware I/O
+    ports config defaults
+  * [Config] apply Device Drivers >> LED Support >> LED Class Support
+    config defaults
+  * [Config] apply Device Drivers >> Hardware Spinlock drivers config
+    defaults
+  * [Config] apply Device Drivers >> Multimedia support >> Cameras/video
+    grabbers support config defaults
+  * [Config] apply Security options config defaults
+  * [Config] apply Networking options >> Network packet filtering framework
+    (Netfilter) >> Core Netfilter Configuration config defaults
+  * [Config] apply Device Drivers >> MMC/SD/SDIO card support config
+    defaults
+  * [Config] apply Device Drivers >> Graphics support >> Frame buffer
+    Devices >> Support for frame buffer devices config defaults
+  * [Config] apply Power management and ACPI options >> CPU Frequency
+    scaling config defaults
+  * [Config] apply Processor type and features config defaults
+  * [Config] apply Partition Types config defaults
+  * [Config] apply Power management and ACPI options config defaults
+  * [Config] apply Device Drivers >> InfiniBand support config defaults
+  * [Config] apply Device Drivers >> Misc devices config defaults
+  * [Config] apply Device Drivers >> Multifunction device drivers config
+    defaults
+  * [Config] apply Device Drivers >> SCSI device support >> SCSI device
+    support >> SCSI low-level drivers config defaults
+  * [Config] apply Device Drivers >> Network device support >> Ethernet
+    driver support config defaults
+  * [Config] apply Device Drivers >> Network device support >> Network core
+    driver support config defaults
+  * [Config] apply Device Drivers >> Network device support >> PHY Device
+    support and infrastructure config defaults
+  * [Config] apply File systems >> Network File Systems config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Touchscreens config defaults
+  * [Config] apply Device Drivers >> Memory Technology Device (MTD) support
+    >> NAND Device Support config defaults
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    >> Ralink driver support config defaults
+  * [Config] apply Device Drivers >> Staging drivers config defaults
+  * [Config] apply Cryptographic API >> Hardware crypto devices config
+    defaults
+  * [Config] apply Device Drivers >> Macintosh device drivers config
+    defaults
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    config defaults
+  * [Config] apply Device Drivers >> PPS support config defaults
+  * [Config] apply Device Drivers >> Sound card support config defaults
+  * [Config] apply Networking support >> RF switch subsystem support config
+    defaults
+  * [Config] apply Library routines config defaults
+  * [Config] apply Device Drivers >> CODEC drivers config defaults
+  * [Config] apply Device Drivers >> PHY Subsystem config defaults
+  * [Config] apply Device Drivers >> Pulse-Width Modulation (PWM) Support
+    config defaults
+  * [Config] apply Kernel hacking >> Tracers config defaults
+  * [Config] apply Kernel hacking >> Runtime Testing config defaults
+  * [Config] apply Kernel hacking >> Architecture: powerpc config defaults
+  * [Config] apply Device Drivers >> USB support config defaults
+  * [Config] apply Device Drivers >> Power supply class support config
+    defaults
+  * [Config] apply Device Drivers >> USB Network Adapters config defaults
+  * [Config] apply General setup >> IRQ subsystem config defaults
+  * [Config] apply General setup config defaults
+  * [Config] apply File systems >> Miscellaneous filesystems config
+    defaults
+  * [Config] apply File systems config defaults
+  * [Config] apply Device Drivers >> Userspace I/O drivers config defaults
+  * [Config] apply Device Drivers >> Virtio drivers config defaults
+  * [Config] apply Device Drivers >> USB Peripheral Controller config
+    defaults
+  * [Config] apply Device Drivers >> SCSI device support >> SCSI device
+    support >> SCSI Transports config defaults
+  * [Config] apply Device Drivers >> Real Time Clock config defaults
+  * [Config] apply Device Drivers >> Serial ATA and Parallel ATA drivers
+    (libata) config defaults
+  * [Config] apply Device Drivers >> SoC Audio for Freescale CPUs config
+    defaults
+  * [Config] apply Device Drivers >> Voltage and Current Regulator Support
+    config defaults
+  * [Config] apply Device Drivers >> USB Physical Layer drivers config
+    defaults
+  * [Config] apply Device Drivers >> Watchdog Timer Support config defaults
+  * [Config] powerpc-powerpc-e500mc FTBFS -- CONFIG_CRASH_DUMP=n
+  * [Config] powerpc-powerpc64-emb FTBFS -- CONFIG_IMA=n
+  * [Config] powerpc-powerpc64-emb FTBFS -- CONFIG_HIBERNATION=n
+    CONFIG_HOTPLUG_CPU=n
+  * [Config] ppc64el-generic FTBFS -- CONFIG_LUSTRE_FS=n
+  * [Config] drivers/message/fusion needs scsi_transport_spi in virtual
+  * [Config] drivers/acpi/acpi_ipmi.ko needs
+    drivers/char/ipmi/ipmi_msghandler.ko in virtual
+  * [Config] armhf-* FTBFS -- CONFIG_STACK_TRACER=n
+    CONFIG_FUNCTION_TRACER=n
+  * [Config] ignore modules changing following major config changes
+
+  [ Tim Gardner ]
+
+  * rebase to v3.16-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc4
+    - LP: #1297581
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 03 Jul 2014 11:00:43 +0100
+
+linux (3.16.0-1.3) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "Disable do_tools_perf for FTBS"
+  * SAUCE: fix perf_regs definitions for arm64
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: ARCH_EXYNOS5* support
+  * [Config] armhf: CPU_IDLE=y and ARM_EXYNOS_CPUIDLE=y
+  * [Config] armhf: EXYNOS_THERMAL=y
+  * [Config] armhf: EXYNOS_IOMMU=y
+  * [Config] armhf: EXYNOS_ADC=m
+  * [Config] armhf: EXYNOS_I2C_EXYNOS5=m
+  * [Config] armhf: MMC_SDHCI_S3C=m
+  * [Config] armhf: PCI_EXYNOS=y
+  * [Config] armhf: PHY_EXYNOS5250_SATA=y
+  * [Config] armhf: USB_[E|O]HCI_EXYNOS=y && SAMSUNG_USBPHY=y
+  * [Config] armhf: PWM_SAMSUNG=m
+  * [Config] armhf: RTC_DRV_S3C=y
+  * [Config] armhf: S3C2410_WATCHDOG=m
+  * [Config] armhf: MMC_DW_EXYNOS=m
+  * [Config] armhf: SERIAL_SAMSUNG=y
+  * [Config] armhf: SND_SOC_SAMSUNG=m
+  * [Config] armhf: SPI_S3C64XX=m
+  * [Config] armhf: EXYNOS_VIDEO=y and VIDEO_SAMSUNG*=m
+  * [Config] armhf: FB_S3C=m
+  * [Config] armhf: build all Exynos 5 DTBs
+  * [Config] armhf: disable CPUFREQ_EXYNOS
+
+  [ Tim Gardner ]
+
+  * rebase to v3.16-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc3
+    - LP: #1331915
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 24 Jun 2014 08:58:09 -0600
+
+linux (3.16.0-0.2) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: intel_pstate -- toggle default to disable"
+    - LP: #1333322
+  * CONFIG_BOOKE_WDT=y
+  * Disable do_tools_perf for FTBS (just until I can figure it out)
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 23 Jun 2014 13:37:53 -0600
+
+linux (3.16.0-0.1) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1333265
+
+  [ Andy Whitcroft ]
+
+  * [Config] cloud-tools -- add systemd units
+    - LP: #1329027
+
+  [ dann frazier ]
+
+  * [Config] CONFIG_RTC_DRV_XGENE=y for arm64
+  * [Config] CONFIG_NET_XGENE=m for arm64
+  * [Config] Restrict CONFIG_POWER_RESET_SYSCON to arm64 only
+
+  [ Feng Kan ]
+
+  * SAUCE: (no-up) arm64: dts: Add X-Gene reboot driver dts node
+  * SAUCE: (no-up) Add documentation for generic SYSCON reboot driver.
+  * SAUCE: (no-up) Select reboot driver for X-Gene platform.
+
+  [ Iyappan Subramanian ]
+
+  * SAUCE: (no-up) MAINTAINERS: Add entry for APM X-Gene SoC ethernet driver
+  * SAUCE: (no-up) Documentation: dts: Add bindings for APM X-Gene SoC ethernet driver
+  * SAUCE: (no-up) dts: Add bindings for APM X-Gene SoC ethernet driver
+  * SAUCE: (no-up) drivers: net: Add APM X-Gene SoC ethernet driver support.
+
+  [ Tim Gardner ]
+
+  * updateconfigs
+  * Fix arm64 crypto Makefile
+  * [Config] CONFIG_BOOKE_WDT=n for FTBS
+  * [Debian] Add UTS_UBUNTU_RELEASE_ABI to utsrelease.h
+    - LP: #1327619
+  * Disabled powerpc64-emb for FTBS
+  * [Config] CONFIG_DRM_TEGRA=m
+  * [Config] CONFIG_CMA_SIZE_MBYTES=64
+  * rebase to v3.16-rc2
+  * Clean up generic.inclusion-list warnings
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc2
+    - LP: #1328587
+    - LP: #1319291
+    - LP: #1310512
+    - LP: #1310512
+    - LP: #1305480
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 12 Jun 2014 12:26:09 +0000
+
+linux (3.15.0-6.11) utopic; urgency=low
+
+  [ Adam Conrad ]
+
+  * Enable building the sata-modules udeb on ppc64el.
+    - LP: #1323980
+  * [Packaging] Set bootloader and loader on ppc64el to grub
+
+  [ Adam Lee ]
+
+  * SAUCE: (no-up) rtlwifi: rtl8723be: disable MSI interrupts mode
+    - LP: #1310512, #1320070
+
+  [ Alex Hung ]
+
+  * SAUCE: (no-up) dell-led: add mic mute led interface
+    - LP: #1308297
+
+  [ Andy Whitcroft ]
+
+  * [Config] d-i -- add hyperv_keyboard to serial-modules udeb
+    - LP: #1285434
+  * [Config] tools -- enable cpupower on ppc64el
+  * [Config] ppc64el -- enable perf tools
+  * [Config] powerpc -- enable perf tools
+  * [Config] ppc64el -- reduce MAX_ORDER with 64k pages
+  * [Config] arm64 -- enable tools
+    - LP: #1326050
+  * [Config] switch hyper-keyboard to virtual
+    - LP: #1325306
+  * [Config] fix up Breaks/Replaces on linux-cloud-tools-common to fix
+    upgrades
+  * SAUCE: kvm: BIOS disabled kvm support should be a warning
+    - LP: #1300247
+  * SAUCE: nouveau: missing outputs should be warnings
+    - LP: #1300244
+  * [Config] d-i -- add nvme devices to block-modules udeb
+    - LP: #1303710
+
+  [ Anton Blanchard ]
+
+  * SAUCE: (no-up) powerpc: 64bit sendfile is capped at 2GB
+    - LP: #1328230
+
+  [ Colin Ian King ]
+
+  * SAUCE: intel_pstate: inform user that thermald is worth considering
+
+  [ Dave Chiluk ]
+
+  * [Config] Enable CONFIG_IP_VS_IPV6=y
+    - LP: #1300739
+
+  [ Paolo Pisati ]
+
+  * [Config] build vexpress a9 dtb
+    - LP: #1303657
+
+  [ Tetsuo Handa ]
+
+  * SAUCE: kthread: Do not leave kthread_create() immediately upon SIGKILL.
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1329045
+  * [Debian] Treat vdso install as an environment variable
+    - LP: #1325713
+  * [Config] Treat vdso install as an environment variable
+    - LP: #1325713
+  * [config] Set IPMI suppoort default to "y"
+  * [Config] powerpc -- CONFIG_SCSI_IBMVSCSI=y
+  * [Config] CONFIG_RT_GROUP_SCHED=n
+    - LP: #1284731
+  * [Config] ppc64el -- switch to 64K system pages
+  * [Config] CONFIG_MICROCODE_EARLY=y
+  * [Config] SND_DAVINCI_SOC && SND_AM33XX_SOC_EVM =m
+  * [Config] armhf: DRM_TILCDC=m
+  * SAUCE: (no-up) mei_me: Add module parameter to disable MSI
+  * [Config] arm64: KVM=y
+  * [Config] armhf: LEDS_TRIGGER_HEARTBEAT=y
+  * [Config] armhf: generic: disable CPU_IDLE
+  * [Config] armhf: CPU_FREQ=y
+  * [Config] Add new mlx modules to d-i
+  * [Config] Added Muti-Arch support for linux-headers-PKGVER-ABINUM, linux-tools-common, and linux-cloud-tools-common
+    - LP: #1295112
+  * [Config] CONFIG_EXYNOS_ADC=n, CONFIG_HW_RANDOM_EXYNOS=n, CONFIG_MMC_DW_EXYNOS=n, CONFIG_USB_DWC3_EXYNOS=n
+    - LP: #1294353
+  * [Config] CONFIG_ABX500_CORE=y for ppc64el
+  * [Config] CONFIG_ALX=m for powerpc
+  * [Config] CONFIG_ACENIC_OMIT_TIGON_I=n for ppc64el
+  * [Config] CONFIG_ACORN_PARTITION_*=n for ppc64el
+  * [Config] CONFIG_ANDROID=n for powerpc
+  * [Config] CONFIG_ASYNC_RAID6_TEST=m for ppc64el
+  * [Config] CONFIG_BIG_KEYS=y for ppc64el
+  * [Config] CONFIG_BSD_PROCESS_ACCT=y for ppc64el
+  * rebase to v3.15
+  * [Config] CONFIG_PHY_XGENE=y
+  * [Config] CONFIG_MLX4_DEBUG=y
+    - LP: #1328256
+  * [Config] CONFIG_POWERNV_CPUFREQ=y for powerpc, ppc64el
+    - LP: #1324571
+  * [Config] CONFIG_BLK_DEV_SR_VENDOR=n for ppc64el
+  * [Config] CONFIG_CFG80211=m for ppc64el
+  * [Config] CONFIG_CHARGER_BQ24190=m for powerpc
+  * [Config] CONFIG_CHARGER_BQ24735=m for powerpc
+  * [Config] CONFIG_EXPERT=y for ppc64el
+  * [Config] CONFIG_ATA_SFF=y on ppc64el
+  * [Config] CONFIG_ATA_GENERIC=y for ppc64el, powerpc
+  * [Config] CONFIG_CHR_DEV_ST=m for ppc64el
+  * [Config] CONFIG_CHECKPOINT_RESTORE=y for ppc64el
+  * [Config] CONFIG_CHELSIO_T1_1G=y for ppc64el
+  * [Config] CONFIG_CHR_DEV_OSST=m for ppc64el
+  * [Config] CONFIG_CHR_DEV_SCH=m for ppc64el
+  * [Config] CONFIG_CPU_FREQ_STAT=y for powerpc
+  * [Config] CONFIG_DDR=y for ppc64el
+  * [Config] CONFIG_DEBUG_BUGVERBOSE=y for powerpc
+  * [Config] CONFIG_E100=m, CONFIG_E1000=m, CONFIG_E1000E=m for ppc64el
+  * [Config] CONFIG_EZX_PCAP=n for all arches
+  * [Config] CONFIG_DYNAMIC_DEBUG=y for powerpc
+  * [Config] CONFIG_ENABLE_MUST_CHECK=n for ppc64el
+  * [Config] CONFIG_ENABLE_WARN_DEPRECATED=n for ppc64el
+  * [Config] CONFIG_FB_3DFX=m for all arches
+  * [Config] CONFIG_FB_MATROX=m for ppc64el
+  * [Config] CONFIG_FB_RADEON=m for ppc64el
+  * [Config] CONFIG_FB_SAVAGE_I2C=y for all arches
+  * [Config] CONFIG_FIREWIRE=m for ppc64el
+  * [Config] CONFIG_FTR_FIXUP_SELFTEST=n for ppc64el
+  * [Config] CONFIG_HAMRADIO=y for ppc64el
+  * [Config] CONFIG_I2C_CHARDEV=m for ppc64el
+  * [Config] CONFIG_I2C_MUX=m for ppc64el
+  * [Config] CONFIG_I2C_STUB=m for ppc64el
+  * [Config] CONFIG_I2O=m for ppc64el
+  * [Config] CONFIG_INET_XFRM_MODE_BEET=m, CONFIG_INET_XFRM_MODE_TRANSPORT=m, CONFIG_INET_XFRM_MODE_TUNNEL=m for ppc64el
+  * [Config] CONFIG_INFINIBAND_IPOIB_DEBUG=n, CONFIG_INFINIBAND_MTHCA_DEBUG=n for ppc64el
+  * [Config] CONFIG_INFINIBAND_NES=m, CONFIG_INFINIBAND_OCRDMA=m, CONFIG_INFINIBAND_QIB=m for ppc64el
+  * [Config] CONFIG_INPUT_FF_MEMLESS=m for ppc64el
+  * [Config] CONFIG_INTERVAL_TREE_TEST=m for ppc64el
+  * [Config] CONFIG_IPACK_BUS=m for ppc64el
+  * [Config] CONFIG_ISDN=y for ppc64el
+  * [Config] CONFIG_ISO9660_FS=m for ppc64el
+  * [Config] CONFIG_KGDB=y for ppc64el
+  * [Config] CONFIG_KVM_GUEST=y for ppc64el
+  * [Config] CONFIG_L2TP_V3=y for powerpc
+  * [Config] CONFIG_MAILBOX=y for ppc64el
+  * [Config] CONFIG_MD_LINEAR=m, CONFIG_MD_RAID0=m, CONFIG_MD_RAID1=m for ppc64el
+  * [Config] CONFIG_MEDIA_SUPPORT=m for ppc64el
+  * [Config] CONFIG_MEMORY=y for ppc64el
+  * [Config] CONFIG_MEMSTICK=m for ppc64el
+  * [Config] CONFIG_MFD_SM501_GPIO=n for ppc64el
+  * [Config] CONFIG_MMC_BLOCK=m for ppc64el
+  * [Config] CONFIG_MOUSE_PS2=m for ppc64el
+  * [Config] CONFIG_NET_9P=m for ppc64el
+  * [Config] CONFIG_MSDOS_FS=m for ppc64el
+  * [Config] CONFIG_MSI_BITMAP_SELFTEST=n for ppc64el
+  * [Config] CONFIG_MTD=m for arm64
+  * [Config] CONFIG_NETCONSOLE=m for ppc64el
+  * [Config] CONFIG_NETFILTER_XT_TARGET_NOTRACK=m for ppc64el
+  * [Config] CONFIG_NET_IPIP=m for ppc64el
+  * [Config] CONFIG_NET_TEAM=m for all arches
+  * [Config] CONFIG_NFC=m for ppc64el
+  * [Config] CONFIG_NL80211_TESTMODE=n for all arches
+  * [Config] CONFIG_NLS_CODEPAGE_437=y for powerpc
+  * [Config] CONFIG_NLS_ASCII=m, CONFIG_NLS_ISO8859_1=m, CONFIG_NLS_UTF8=m for ppc64el
+  * [Config] CONFIG_NOP_USB_XCEIV=m for ppc64el
+  * [Config] CONFIG_NOTIFIER_ERROR_INJECTION=m for ppc64el
+  * [Config] CONFIG_OPROFILE=m for ppc64el
+  * [Config] CONFIG_PARPORT_1284=y for ppc64el
+  * [Config] CONFIG_PARPORT_AX88796=m, CONFIG_PARPORT_PC_FIFO=y, CONFIG_PARPORT_SERIAL=m for ppc64el
+  * [Config] CONFIG_8723AU_P2P=n
+  * [Config] CONFIG_PCI_IOV=y, CONFIG_PCI_PASID=y, CONFIG_PCI_PRI=y, CONFIG_PCI_REALLOC_ENABLE_AUTO=y, CONFIG_PCI_STUB=m for ppc64el
+  * [Config] CONFIG_PCNET32=m for ppc64el
+  * [Config] CONFIG_SCSI_DH_EMC=m for ppc64el
+  * [Config] CONFIG_SCSI_DH_HP_SW=m for ppc64el
+  * [Config] CONFIG_SCSI_FC_ATTRS=m for ppc64el
+  * [Config] CONFIG_SCSI_IPR=m for ppc64el
+  * [Config] CONFIG_SCSI_LOGGING=y for ppc64el
+  * [Config] CONFIG_SCSI_OSD_INITIATOR=m for ppc64el
+  * [Config] CONFIG_SCSI_SCAN_ASYNC=y for ppc64el
+  * [Config] CONFIG_SCSI_SYM53C8XX_2=m for ppc64el
+  * [Config] CONFIG_XILINX_LL_TEMAC=m for powerpc
+  * [Config] CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y for ppc64el
+  * [Config] CONFIG_WLAN=y for arm64
+  * [Config] CONFIG_VORTEX=m for ppc64el
+  * [Config] CONFIG_WIMAX=m for ppc64el
+  * [Config] CONFIG_WATCHDOG=y for ppc64el
+  * [Config] CONFIG_VIRT_DRIVERS=y for ppc64el
+  * [Config] CONFIG_VERSION_SIGNATURE="" for powerpc64-emb
+  * [Config] CONFIG_UWB=m for ppc64el
+  * [Config] CONFIG_USB_STORAGE=y
+  * [Config] CONFIG_SATA_AHCI_PLATFORM=y for armhf
+  * [Config] CONFIG_HID_RMI=m
+  * [Config] CONFIG_HVC_DCC=n
+    - LP: #1303657
+
+  [ Upstream Kernel Changes ]
+
+  * mm/numa: Remove BUG_ON() in __handle_mm_fault()
+    - LP: #1323165
+  * powerpc/powernv: Add calls to support little endian host
+    - LP: #1327400
+  * HID: rmi: introduce RMI driver for Synaptics touchpads
+  * HID: rmi: do not stop the device at the end of probe
+  * HID: rmi: check for the existence of some optional queries before reading query 12
+  * HID: rmi: do not fetch more than 16 bytes in a query
+  * HID: rmi: fix wrong struct field name
+  * HID: rmi: fix masks for x and w_x data
+  * HID: rmi: do not handle touchscreens through hid-rmi
+  * ALSA: pcm: 'BUG:' message unnecessarily triggers kerneloops
+    - LP: #1305480
+  * rebase to v3.15
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 03 Jun 2014 17:02:49 +0000
+
+linux (3.15.0-5.10) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1325596
+  * [Config] CONFIG_POWERNV_CPUFREQ=y for ppc64el
+  * rebase to v3.15-rc8
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc8
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 02 Jun 2014 12:59:34 +0000
+
+linux (3.15.0-4.9) utopic; urgency=low
+
+  * no change rebuild to fix embeded debhelper.
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 29 May 2014 12:41:58 +0100
+
+linux (3.15.0-4.8) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1324107
+  * [Config] enable SECURITY_APPARMOR_UNCONFINED_INIT
+
+  [ Javier Martinez Canillas ]
+
+  * SAUCE: (no-up) apparmor: fix bug that constantly spam the console
+    - LP: #1323526
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor3 - alpha6 snapshot
+    - LP: #1323528
+  * SAUCE: (no-up) apparmor: fix apparmor spams log with warning message
+    - LP: #1308761
+  * SAUCE: (no-up) apparmor: fix refcount bug in apparmor pivotroot
+    - LP: #1308765
+  * SAUCE: (no-up): apparmor: fix apparmor refcount bug in apparmor_kill
+    - LP: #1308764
+  * SAUCE: (no-up): apparmor: use custom write_is_locked macro
+    - LP: #1323530
+
+  [ Kamal Mostafa ]
+
+  * [Config] add debian/gbp.conf
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_SATA_AHCI=m for ppc64el
+    - LP: #1323980
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 28 May 2014 12:47:17 +0100
+
+linux (3.15.0-3.7) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1323189
+
+  [ Andy Whitcroft ]
+
+  * [Config] autopkgtest -- need fakeroot for tests
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 26 May 2014 08:12:50 +0200
+
+linux (3.15.0-2.6) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] remove the kernel-image firmware list on clean
+
+  [ Martin Pitt ]
+
+  * [Config] autopkgtest -- switch to significantly faster rebuild
+
+  [ Stefan Bader ]
+
+  * [Config]: Add missing modules to inclusion list
+
+  [ Tim Gardner ]
+
+  * [debian] Dynamically generate the kernel-image udebs firmware list
+  * [d-i] firmware/kernel-image is generated
+  * rebase to v3.15-rc6
+  * Release Tracking Bug
+    - LP: #1322251
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc6
+    - LP: #1297581
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 21 May 2014 10:51:29 -0700
+
+linux (3.15.0-1.5) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Add apm-mustang.dtb to kernel-image udeb
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 19 May 2014 14:47:42 -0700
+
+linux (3.15.0-1.4) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) hv -- bodge hv_vss_daemon so it can use the
+    local linux/hyperv.h"
+  * Revert "SAUCE: (no-up) hv -- bodge hv_kvp_daemon so it can use the
+    local linux/hyperv.h"
+  * [Packaging] tools -- hv tools build correctly against the built headers
+  * [Packaging] cloud-tools -- add the hv_fcopy_daemon to the package
+  * cloud-tools -- pull in init scripts for Hyper-V daemons
+  * cloud-tools -- detect Hyper-V VM to avoid starting
+  * cloud-tools -- update IF_NAME to DEVICE in hv_* scripts
+    - LP: #1295401
+  * [Config] cloud-tools: reenable cloud-tools
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 18 May 2014 19:21:04 +0100
+
+linux (3.15.0-1.3) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] ppc64el is a powerpc kernel arch and needs its quirks
+    - LP: #1318848
+
+  [ Ben Collins ]
+
+  * [Config] Switch to grub-ieee1275 as recommended on book3e systems
+    - LP: #1318629
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_FSL_PAMU=n
+    - LP: #1311738
+  * Release Tracking Bug
+    - LP: #1320239
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 16 May 2014 07:37:07 -0600
+
+linux (3.15.0-1.2) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1318171
+  * Add rpcsec_gss_krb5 to generic inclusion list
+    - LP: #769527
+  * rebase to v3.15-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc5
+    - LP: #1297581
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 06 May 2014 15:20:10 -0500
+
+linux (3.15.0-0.1) utopic; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc4
+    - LP: #1297581
+    - LP: #1297581
+    - LP: #1305133
+    - LP: #1297581
+    - LP: #1297581
+    - LP: #871808
+    - LP: #1260303
+    - LP: #1268468
+    - LP: #1248116
+    - LP: #1211920
+    - LP: #1259790
+    - LP: #1259437
+    - LP: #1259435
+    - LP: #1268468
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 07 Feb 2014 09:35:13 -0700
+
+linux (3.15.0-0.0) utopic; urgency=low
+
+  * Initial version for 3.15.
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 02 May 2014 15:06:39 +0100
+
+linux (3.13.0-8.27) trusty; urgency=low
+
+  [ John Johansen ]
+
+  * SAUCE: Add config option to disable new apparmor 3 semantics
+    -LP: #1270215
+
+  [ Tim Gardner ]
+
+  * [debian] Fix indep_hdrs_pkg_name
+    - LP: #1134441
+  * Update lttng to 00808267d3ba7cdcddfed7bec7e62a40463c1307 Version 2.4.0-rc3
+  * Enabled lttng build
+  * Don't build lttng for armhf
+    lttng hates gcc-4.8 for armhf
+  * Release Tracking Bug
+    - LP: #1277309
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13.2
+    - LP: #1260303
+    - LP: #1260303
+    - LP: #1268468
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 06 Feb 2014 09:25:51 -0700
+
+linux (3.13.0-7.26) trusty; urgency=low
+
+  [ John Johansen ]
+
+  * SAUCE: apparmor: fix uninitialized lsm_audit membe
+    - LP: #1268727
+  * Add config option to optionally enable new apparmor 3 semantics
+
+  [ Tim Gardner ]
+
+  * [Config] Add lowlatency to getabis
+  * [Config] CONFIG_SECURITY_APPARMOR_AA3_SEMANTICS=y
+    - LP: #1270215
+  * Release Tracking Bug
+    - LP: #1276810
+
+  [ Upstream Kernel Changes ]
+
+  * x86, x32: Correct invalid use of user timespec in the kernel
+    - LP: #1274349
+    - CVE-2014-0038
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 05 Feb 2014 15:49:44 -0500
+
+linux (3.13.0-7.25) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: fix fmd headers"
+  * SAUCE: fix fmd headers
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 04 Feb 2014 09:36:09 +0000
+
+linux (3.13.0-7.24) trusty; urgency=low
+
+  [ Stefan Bader ]
+
+  * [Config] Make vmwgfx driver enable the framebuffer device
+
+  [ Tim Gardner ]
+
+  * rebase to v3.13.1
+  * [Config] CONFIG_NFS_FS=m for ppc64el
+  * [Config] CONFIG_X86_SYSFB=n
+    https://lists.ubuntu.com/archives/kernel-team/2014-February/038166.html
+  * Release Tracking Bug
+    - LP: #1275898
+
+  [ Upstream Kernel Changes ]
+
+  * i2c: piix4: Add support for AMD ML and CZ SMBus changes
+    - LP: #1272525
+  * i2c: piix4: Use different message for AMD Auxiliary SMBus Controller
+    - LP: #1272525
+  * mm: ignore VM_SOFTDIRTY on VMA merging
+    - LP: #1274917
+  * drm/radeon: disable dpm on BTC
+    - LP: #1266984
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13.1
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 30 Jan 2014 15:24:48 +0000
+
+linux (3.13.0-6.23) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] fix up architecture for linux-tools
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 30 Jan 2014 09:00:41 +0000
+
+linux (3.13.0-6.22) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] limit linux-udebs-<flavour> to matching arch
+  * [Config] powerpc -- disable perf to fix FTBFS
+  * [Config] ppc64el -- fix up missing udebs
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 29 Jan 2014 16:00:28 +0000
+
+linux (3.13.0-6.21) trusty; urgency=low
+
+  [ Andy Fleming ]
+
+  * SAUCE: net: Add support for handling queueing in hardware
+  * SAUCE: of_mdio: Add of_phy_attach function
+  * SAUCE: phylib: Add generic 10G driver
+  * SAUCE: phylib: Support attaching to gen10g_driver
+  * SAUCE: phylib: Add Clause 45 read/write functions
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: fix fmd headers
+  * [Packaging] lowlatency -- merge out of tree flavours
+  * SAUCE: allow IRQs to be irq-threaded by default via config
+  * [Config]: enable CONFIG_IRQ_FORCED_THREADING_DEFAULT for lowlatency
+  * [Config] powerpc -- fix up Build-depends:
+  * Release Tracking Bug
+    - LP: #1273747
+
+  [ Ben Collins ]
+
+  * SAUCE: PPC: PCI: Fix pcibios_io_space_offset() so it works for 32-bit
+    ptr/64-bit rsrcs
+  * SAUCE: Revert "phy: vitesse make vsc824x_add_skew static"
+  * SAUCE: Fixup freescale usb phy driver to work on ppc64
+  * SAUCE: xgmac_mdio: Silence read errors
+  * SAUCE: Provide booke stub for kvmppc_is_bigendian()
+  * SAUCE: Fix stack overflow on ppc32
+  * SAUCE: Use resource_size_t instead of long for PCI resource address
+  * SAUCE: net/phy: Export function for use by dpaa_eth
+  * [Packaging] powerpc -- merge out of tree powerpc arch
+
+  [ Bjorn Helgaas ]
+
+  * SAUCE: Revert "EISA: Log device resources in dmesg"
+    - LP: #1251816
+  * SAUCE: Revert "EISA: Initialize device before its resources"
+    - LP: #1251816
+
+  [ Emil Medve ]
+
+  * SAUCE: phylib: Minimum hack to get the generic 10G PHY driver to work
+    with 10G "fixed-link"s
+
+  [ Kumar Gala ]
+
+  * SAUCE: fsl_qbman: Add drivers for Freescale DPAA Qman & Bman
+  * SAUCE: fsl_pme2: Add support for DPAA PME
+  * SAUCE: fmd: FMD14 integration
+  * SAUCE: dpaa_eth: Ethernet driver for Freescale QorIQ DPA Architecture
+  * SAUCE: powerpc/85xx: Add DPAA/networking support for CoreNet
+
+  [ Madalin Bucur ]
+
+  * SAUCE: net/flow: remove sleeping and deferral mechanism from
+    flow_cache_flush
+  * SAUCE: net/phy: abort genphy_read_status when link changes during speed
+    and duplex reading
+
+  [ Stefan Bader ]
+
+  * [Config] move some VMWare related modules into main package
+    - LP: #1271669
+
+  [ Tim Gardner ]
+
+  * [Config] Add r815x to nic-modules
+    - LP: #1273735
+  * [Config] CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+    - LP: #239479
+
+  [ Upstream Kernel Changes ]
+
+  * mmc: sdhci-pci: break out definitions to header file
+    - LP: #1239938
+  * mmc: sdhci-pci: add support of O2Micro/BayHubTech SD hosts
+    - LP: #1239938
+  * powerpc/book3e: rename interrupt_end_book3e with __end_interrupts
+  * powerpc/book3e: support CONFIG_RELOCATABLE
+  * book3e/kexec/kdump: enable kexec for kernel
+  * book3e/kexec/kdump: create a 1:1 TLB mapping
+  * book3e/kexec/kdump: introduce a kexec kernel flag
+  * book3e/kexec/kdump: implement ppc64 kexec specfic
+  * book3e/kexec/kdump: redefine VIRT_PHYS_OFFSET
+  * book3e/kexec/kdump: recover "r4 = 0" to create the initial TLB
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 28 Jan 2014 22:59:46 +0000
+
+linux (3.13.0-5.20) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] tools -- do not make symlinks when not making packages
+  * [Packaging] tools -- tidy up control.stub.in ordering
+  * [Packaging] tools -- tools-common is shared and not conditional
+  * rebase to v3.13
+
+  [ Dirk Brandewie ]
+
+  * SAUCE: intel_pstate: Add setting voltage value for baytrail P states.
+
+  [ KY Srinivasan ]
+
+  * SAUCE: Drivers: hv: vmbus: Specify the target CPU that should receive
+    notification
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13
+   - LP: #1270603
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 17 Jan 2014 15:45:31 +0000
+
+linux (3.13.0-4.19) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] libunwind8-dev is now available for ppc64el
+  * [Packaging] tools -- make cpupower optional
+  * [Packaging] tools -- enable correctly for x86
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1269872
+
+  [ Upstream Kernel Changes ]
+
+  * SAUCE: ARM: OMAP: hwmod: Add SYSC offsets for AES IP
+  * SAUCE: ARM: OMAP4: hwmod: Add hwmod data for AES IP
+  * SAUCE: OMAP: AM33xx: hwmod: Correct AES module SYSC type
+  * SAUCE: crypto: omap-aes: add error check for pm_runtime_get_sync
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 85ce70fdf48aa290b4845311c2dd815d7f8d1fa5
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 15 Jan 2014 13:23:05 +0000
+
+linux (3.13.0-3.18) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.13-rc8
+  * [Packaging] efi -- allow EFI signatures on any arch
+
+  [ Tim Gardner ]
+
+  * [Config] Fix vcs-git path
+  * Release Tracking Bug
+    - LP: #1268683
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc8
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 12 Jan 2014 11:58:01 +0000
+
+linux (3.13.0-2.17) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1267809
+  * [Config] apply Platform support>>CPUIdle driver>>CPU Idle config
+    defaults
+  * [Config] apply Platform support>>CPU Frequency scaling config defaults
+  * [Config] CONFIG_PARIDE_EPATC8=y
+  * [Config] apply Device Drivers >> Broadcom specific AMBA config defaults
+  * [Config] apply Bus options >> PCI support >> RapidIO support >> RapidIO
+    Switch drivers config defaults
+  * [Config] apply Cryptographic API config defaults
+  * [Config] apply Device Drivers >> Common Clock Framework config defaults
+  * [Config] apply Device Drivers >> Distributed Switch Architecture
+    drivers config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Backlight & LCD
+    device support config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Support for frame
+    buffer devices >> Bootup logo config defaults
+  * annotations -- update in tree annotations
+  * [Config] apply Bus options >> PCI support >> RapidIO support config
+    defaults
+  * [Config] CONFIG_POWER_AVS=y CONFIG_RESET_CONTROLLER=y
+  * [Config] apply Device Drivers >> 1-wire Bus Masters config defaults
+  * [Config] apply CAN Device Drivers >> Platform CAN drivers with Netlink
+    support config defaults
+  * [Config] apply Device Drivers >> Character devices >> Serial drivers
+    config defaults
+  * [Config] apply Device Drivers >> Generic Thermal sysfs driver config
+    defaults
+  * [Config] apply Device Drivers >> Character devices >> TPM Hardware
+    Support config defaults
+  * [Config] apply Device Drivers >> Character devices config defaults
+  * [Config] apply Device Drivers >> HID support >> USB HID support >> USB
+    HID transport layer config defaults
+  * [Config] apply Device Drivers >> HID support >> HID bus support config
+    defaults
+  * [Config] apply Device Drivers >> HID support >> USB HID support config
+    defaults
+  * annotations -- update in tree annotations
+  * [Config] apply Device Drivers >> GPIO Support config defaults
+  * [Config] update configs for apparmour update
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 - alpha 4 snapshot
+  * SAUCE: apparmor: fix unix domain sockets to be mediated on connection
+    - LP: #1208988
+  * SAUCE: apparmor: allocate path lookup buffers during init
+    - LP: #1208988
+  * SAUCE: (no-up) apparmor: Fix tasks not subject to, reloaded policy
+    - LP: #1236455
+
+  [ Tim Gardner ]
+
+  * Revert "[Debian] getabis: Preface module with package name"
+  * [Config] Added ppc64el to getabis
+  * [packaging] Bump ABI for every new release
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 10 Jan 2014 11:48:39 +0000
+
+linux (3.13.0-1.16) trusty; urgency=low
+
+  * First 3.13 upload.
+  * Release tracker
+    - LP: #1266852
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 07 Jan 2014 09:21:26 -0700
+
+linux (3.13.0-0.15) trusty; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v3.13-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 05 Jan 2014 06:13:33 -0700
+
+linux (3.13.0-0.14) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to 7a262d2ed9fa42fad8c4f243f8025580b58cf2f6
+
+  [ Tim Gardner ]
+
+  * Remove ubuntu/dm-raid4-5 in favor of CONFIG_MD_RAID456
+  * Update lttng to Version 2.4.0-rc2
+  * lttng: Disabled trace_kvm_async_pf_completed
+  * [Config] CONFIG_IMA=y
+    - LP: #1244627
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 7a262d2ed9fa42fad8c4f243f8025580b58cf2f6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 02 Jan 2014 12:57:13 -0700
+
+linux (3.13.0-0.13) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: aufs3 -- (no-up) aufs3-base.patch
+  * ubuntu: aufs3 -- (no-up) aufs3-mmap.patch
+  * ubuntu: aufs3 -- (no-up) aufs3-standalone.patch
+  * ubuntu: AUFS (no-squash): basic framework and update machinary
+  * ubuntu: AUFS -- update to 7b136a27b021da9010d8b6c101939dd298e46be7
+  * ubuntu: aufs3 -- enable
+  * ubuntu: aufs3 -- update configs
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 02 Jan 2014 09:41:02 +0000
+
+linux (3.13.0-0.12) trusty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 31 Dec 2013 06:16:03 -0700
+
+linux (3.13.0-0.11) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: suspicious unlocked ->status reading and writing in ipc/sem.c
+  * [Config] ppc64el -- initial defconfig based -generic flavour
+  * [Config] initial defconfig for ppc64el
+  * [Config] ubuntuise ppc64el config
+  * [Config] ubuntuise ppc64el config part 2
+  * [Config] d-i -- update empty udebs list
+  * [Config] ppc64el -- split extras package
+
+  [ Anton Blanchard ]
+
+  * SAUCE: KVM: PPC: Book3S HV: Add little-endian guest support
+
+  [ Benjamin Herrenschmidt ]
+
+  * SAUCE: powerpc/powernv: Add calls to support little endian
+
+  [ Cédric Le Goater ]
+
+  * SAUCE: KVM: PPC: Book3S: add helper routine to load guest instructions
+  * SAUCE: KVM: PPC: Book3S: add helper routines to detect endian order
+  * SAUCE: KVM: PPC: Book3S: MMIO emulation support for little endian
+    guests
+
+  [ Paul E. McKenney ]
+
+  * SAUCE: powerpc: Make 64-bit non-VMX copy_tofrom_user() bi-endian
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 27 Dec 2013 16:48:55 +0000
+
+linux (3.13.0-0.10) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.13-rc5
+  * [Config] updateconfigs following rebase to v3.13-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc5
+    - LP: #1260303
+    - LP: #1260303
+    - LP: #1260225
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 23 Dec 2013 12:48:28 +0000
+
+linux (3.13.0-0.9) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] d-i -- allow missing firmware
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 20 Dec 2013 17:57:06 +0000
+
+linux (3.13.0-0.8) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] annotations -- first pass over entire config
+  * [Config] drop libunwind8-dev from Build-Depends for ppc64el
+
+  [ Tim Gardner ]
+
+  * [Config] Add arm64 device tree files
+    - LP: #1262901
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 19 Dec 2013 18:36:43 +0000
+
+linux (3.13.0-0.7) trusty; urgency=low
+
+  [ Rajesh B Prathipati ]
+
+  * SAUCE: powerpc: Make unaligned accesses endian-safe for powerpc
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_REGULATOR_S2MPS11=n for FTBS
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc4
+    - LP: #1259790
+    - LP: #1259437
+    - LP: #1259435
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 13 Dec 2013 07:56:34 -0700
+
+linux (3.13.0-0.6) trusty; urgency=low
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: arm64: VIRTIO_[BLK|MMIO|NET|CONSOLE|BALLOON]=y
+  * [Config] i386: amd64: VIRTIO_CONSOLE=y
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 08 Dec 2013 09:22:01 -0700
+
+linux (3.13.0-0.5) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * correct bug listing for v3.13-rc2 rebase
+  * [Config] ppc64el -- create linux-libc-dev
+  * [Debian] Improve tools version message
+    - LP: #1257715
+
+  [ Serge Hallyn ]
+
+  * SAUCE: fork: Allow CLONE_PARENT after setns(CLONE_NEWPID)]
+    - LP: #1248590
+  * SAUCE: vfs: Fix a regression in mounting proc
+
+  [ Tim Gardner ]
+
+  * [Config] Build-in ohci-pci
+    - LP: #1244176
+  * Rebase to v3.13-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Revert "fork: unify and tighten up CLONE_NEWUSER/CLONE_NEWPID
+    checks""
+    - LP: #1248590
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc3
+    - LP: #1256840
+    - LP: #1256212
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sat, 07 Dec 2013 07:55:39 -0700
+
+linux (3.13.0-0.4) trusty; urgency=low
+
+  [ Tim Gardner ]
+
+  * Rebase to v3.13-rc2
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc2
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 29 Nov 2013 23:54:05 -0500
+
+linux (3.13.0-0.3) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: Fix DocBook FTBS"
+
+  [ Tim Gardner ]
+
+  * [Debian] Re-sign modules after debug objcopy
+    - LP: #1253155
+  * [Config] CONFIG_EXT4_USE_FOR_EXT23=y
+
+  [ Upstream Kernel Changes ]
+
+  * doc: fix generation of device-drivers
+  * rebase to b975dc3689fc6a3718ad288ce080924f9cb7e176
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 26 Nov 2013 12:24:42 -0700
+
+linux (3.13.0-0.2) trusty; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: Fix DocBook FTBS
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 25 Nov 2013 13:24:15 -0700
+
+linux (3.13.0-0.1) trusty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 7e3528c3660a2e8602abc7858b0994d611f74bc3
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 12 Nov 2013 07:28:53 -0700
+
+linux (3.13.0-0.0) trusty; urgency=low
+
+  * Major release bump.
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 12 Nov 2013 21:37:52 +0000
+
+linux (3.12.0-2.7) trusty; urgency=low
+
+  * Fixed armhf ABI build failure.
+  * Release tracker
+    - LP: #1249477
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 08 Nov 2013 16:22:45 -0700
+
+linux (3.12.0-2.6) trusty; urgency=low
+
+  [ Joseph Salisbury ]
+
+  * SAUCE: tg3: Add support for new 57786 device id.
+    - LP: #1242610
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_OABI_COMPAT=n
+  * [Config] add the wandboard to shipped dtb
+    - LP: #1249421
+  * Release tracker
+    - LP: #1249477
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 08 Nov 2013 12:23:18 -0700
+
+linux (3.12.0-2.5) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to mainline v3.12
+  * [Config] updateconfigs following rebase to v3.12
+  * postinst -- improve relative symlink detection with missing files
+    - LP: #1248053
+  * postinst -- fix unchanged link detection
+  * [Config] update configs following addition of apparmor fixes
+
+  [ Anthony Wong ]
+
+  * SAUCE: Work around broken ACPI backlight on Dell Inspiron 5537
+    - LP: #1231305
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 - alpha 4 snapshot
+  * SAUCE: apparmor: fix unix domain sockets to be mediated on connection
+    - LP: #1208988
+  * SAUCE: apparmor: allocate path lookup buffers during init
+    - LP: #1208988
+
+  [ Tim Gardner ]
+
+  * [Config] Remove superfluous ubuntu/lttng-modules
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "fork: unify and tighten up CLONE_NEWUSER/CLONE_NEWPID checks"
+    - LP: #1248590
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.12
+    - LP: #1222850
+
+  [ Adam Conrad ]
+  * etc/getabis: Fetch arm64/generic abis as well
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 06 Nov 2013 21:00:21 +0000
+
+linux (3.12.0-1.3) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] arm64 -- add arch to the configuration handlers
+  * [Config] arm64 -- add generic flavour
+  * [Config] arm64 -- default config
+  * [Config] arm64 -- fix up various FTBFS config options
+  * SAUCE: arm64: export __copy_in_user to modules
+  * [Config] arm64 -- disable ABI/module checks
+  * [Config] arm64 -- enforcer -- add arm64 to the enforcer
+  * [Config] arm64 -- enable udebs for arm64
+
+  [ Colin Watson ]
+
+  * [Config] Clean up various udeb Provides
+
+  [ Paolo Pisati ]
+
+  * [Config] AHCI_IMX=y
+  * [Config] build imx*-wandboard dtbs
+
+  [ Serge Hallyn ]
+
+  * SAUCE: device_cgroup: remove can_attach
+
+  [ Tim Gardner ]
+
+  * rebase to v3.12-rc7
+  * SAUCE: KVM: Fix modprobe failure for kvm_intel/kvm_amd
+  * Release tracker
+    - LP: #1245932
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.12-rc7
+    - LP: #1180881
+    - LP: #1180881
+    - LP: #1217957
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 27 Oct 2013 22:08:55 -0600
+
+linux (3.12.0-0.2) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) scsi: hyper-v storage -- mark as preferring READ
+    CAPACITY (16) at SPC-2"
+  * Revert "SAUCE: (no-up) scsi: hyper-v storage -- mark as VPD capable at
+    SPC-2"
+  * Revert "SAUCE: (no-up) scsi: add scsi device flag to request READ
+    CAPACITY (16) be preferred"
+  * Revert "SAUCE: (no-up) scsi: add scsi device flag to request VPD pages
+    be used at SPC-2"
+  * Revert "overlayfs: Update to v19"
+  * Revert "ubuntu: overlayfs v18 -- -- overlayfs: implement show_options"
+  * Revert "ubuntu: overlayfs v18 -- -- overlayfs: add statfs support"
+  * Revert "ubuntu: overlayfs v18 -- -- overlay filesystem"
+  * Revert "ubuntu: overlayfs v18 -- -- vfs: introduce
+    clone_private_mount()"
+  * Revert "ubuntu: overlayfs v18 -- -- vfs: export do_splice_direct() to
+    modules"
+  * Revert "ubuntu: overlayfs v18 -- -- overlay: overlay filesystem
+    documentation"
+  * ubuntu: overlayfs v20 -- overlayfs: add statfs support
+  * [Config] fix linux-libc-dev generation for arm64
+  * [Config] fix linux-libc-dev generation for x32
+  * [Config] add linux-libc-dev generation for ppc64el
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs v20 -- overlayfs: implement show_options
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs v20 -- vfs: add i_op->dentry_open()
+  * ubuntu: overlayfs v20 -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs v20 -- vfs: export __inode_permission() to modules
+  * ubuntu: overlayfs v20 -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs v20 -- overlay filesystem
+  * ubuntu: overlayfs v20 -- fs: limit filesystem stacking depth
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs v20 -- overlay: overlay filesystem documentation
+
+  [ Paolo Pisati ]
+
+  * [Config] arm: VIRTIO_[BLK|NET|MMIO]=y
+
+  [ Seth Forshee ]
+
+  * SAUCE: (no-up) ACPI: Disable Windows 8 compatibility for some Lenovo
+    ThinkPads
+    - LP: #1183856
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_CRYPTO_CRCT10DIF=y, CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m
+  * rebase to v3.12-rc2
+  * updateconfigs
+  * [Config] disable CONFIG_FB_VESA enforcer check
+  * [Config] Disable lttng for FTBS
+  * rebase to v3.12-rc3
+  * rebase to v3.12-rc4
+  * [Config] CONFIG_ANDROID=n
+    - LP: #1235161
+  * [Config] CONFIG_L2TP_V3=y
+    - LP: #1235914
+  * [Config] CONFIG_USB_OTG=n for all arches
+  * Release tracker
+    - LP: #1242811
+
+  [ Upstream Kernel Changes ]
+
+  * scsi: hyper-v storsvc switch up to SPC-3
+
+  * rebase to v3.12-rc6
+    - LP: #1235977
+    - LP: #1235523
+    - LP: #1239392
+    - LP: #1227491
+
+  * rebase to v3.12-rc3
+    - LP: #1231931
+
+  * rebase to v3.12-rc2
+    - LP: #1213820
+    - LP: #1213055
+    - LP: #1198030
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 23 Sep 2013 07:41:07 -0600
+
+linux (3.11.0-8.15) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release tracker
+    - LP: #1227969
+
+  * Update lttng
+    Updated to git://git.lttng.org/lttng-modules.git 9998f5216f4641a79e158135
+    Version 2.3.0+
+
+  [ Upstream Kernel Changes ]
+
+  * igb: Add additional get_phy_id call for i354 devices
+    - LP: #1219619
+  * igb: Read flow control for i350 from correct EEPROM section
+    - LP: #1219619
+  * timekeeping: Fix HRTICK related deadlock from ntp lock changes
+    Required for lttng update.
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 19 Sep 2013 07:41:49 -0600
+
+linux (3.11.0-7.14) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] sort out linux-tools naming
+    - LP: #1205284
+  * [Packaging] linux-tools: switch to common generic version helper
+
+  [ Paolo Pisati ]
+
+  * [Config] highbank: ecx1000: CPU_IDLE causes instabilities, disable it
+
+  [ Tim Gardner ]
+
+  * Release tracker
+    - LP: #1226160
+
+  [ Tony Lindgren ]
+
+  * SAUCE: ARM: dts: Fix muxing and regulator for wl12xx on the SDIO bus
+    for pandaboard
+
+  [ Upstream Kernel Changes ]
+
+  * USB: handle LPM errors during device suspend correctly
+    - LP: #1011415
+  * usb: don't check pm qos NO_POWER_OFF flag in usb_port_suspend()
+    - LP: #1011415
+  * usb: Don't fail port power resume on device disconnect.
+    - LP: #1011415
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.11.1
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 11 Sep 2013 07:30:17 -0600
+
+linux (3.11.0-7.13) saucy; urgency=low
+
+  * Release tracker
+    - LP: #1223545
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: (no-up) scsi: add scsi device flag to request VPD pages be used at SPC-2
+    - LP: #1223499
+  * SAUCE: (no-up) scsi: add scsi device flag to request READ CAPACITY (16) be preferred
+    - LP: #1223499
+  * SAUCE: (no-up) scsi: hyper-v storage -- mark as VPD capable at SPC-2
+    - LP: #1223499
+  * SAUCE: (no-up) scsi: hyper-v storage -- mark as preferring READ CAPACITY (16) at SPC-2
+    - LP: #1223499
+
+  [ Maximiliano Curia ]
+
+  * SAUCE: (no-up) Only let characters through when there are active readers.
+    - LP: #1208740
+
+  [ Tim Gardner ]
+
+  * [Debian] getabis: Commit new ABI directory, remove the old
+  * [Config] CONFIG_EFIVAR_FS=y
+    - LP: #1223195
+  * [Config] CONFIG_EFI_VARS_PSTORE=m,
+    CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE=n
+  * SAUCE: (no-up) USB: input: cm109.c: Convert high volume dev_err() to dev_err_ratelimited()
+    - LP: #1222850
+
+  [ Upstream Kernel Changes ]
+
+  * Intel xhci: refactor EHCI/xHCI port switching
+    - LP: #1210858
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 10 Sep 2013 09:00:19 -0600
+
+linux (3.11.0-6.12) saucy; urgency=low
+
+  * Release tracker
+    - LP: #1222893
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: (no-squash) AUFS3 -- aufs3-standalone.patch"
+  * Revert "ubuntu: (no-squash) AUFS3 -- aufs3-base.patch"
+  * ubuntu: (no-squash) AUFS3 -- aufs3-base.patch
+  * ubuntu: (no-squash) AUFS3 -- aufs3-standalone.patch
+    - LP: #1222407
+
+  [ Paolo Pisati ]
+
+  * [Config] restore mmc boot on panda
+
+  [ Tyler Hicks ]
+
+  * SAUCE: apparmor: Use shash crypto API interface for profile hashes
+    - LP: #1216294
+
+  [ Upstream Kernel Changes ]
+
+  * net: calxedaxgmac: remove NETIF_F_FRAGLIST setting
+  * net: calxedaxgmac: read correct field in xgmac_desc_get_buf_len
+  * net: calxedaxgmac: fix race between xgmac_tx_complete and xgmac_tx_err
+  * net: calxedaxgmac: fix possible skb free before tx complete
+  * net: calxedaxgmac: update ring buffer tx_head after barriers
+  * net: calxedaxgmac: fix race with tx queue stop/wake
+  * net: calxedaxgmac: enable interrupts after napi_enable
+  * net: calxedaxgmac: fix various errors in xgmac_set_rx_mode
+  * net: calxedaxgmac: remove some unused statistic counters
+  * net: calxedaxgmac: fix rx DMA mapping API size mismatches
+  * net: calxedaxgmac: fix xgmac_xmit DMA mapping error handling
+  * mfd: rtsx: Read vendor setting from config space
+    - LP: #1201698
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 09 Sep 2013 07:21:06 -0600
+
+linux (3.11.0-5.11) saucy; urgency=low
+
+  * Release tracker
+    - LP: #1221886
+
+  [ Adam Lee ]
+
+  * SAUCE: Bluetooth: Add support for 04ca:2007
+    - LP: #1153448
+  * SAUCE: Bluetooth: Add support for 105b:e065
+    - LP: #1161261
+
+  [ Gavin Guo ]
+
+  * SAUCE: Bluetooth: Add support for Broadcom 413c:8143
+    - LP: #1166113
+
+  [ Upstream Kernel Changes ]
+
+  * igb: Reset the link when EEE setting changed
+    - LP: #1219619
+  * igb: Read register for latch_on without return value
+    - LP: #1219619
+  * igb: Added rcu_lock to avoid race
+    - LP: #1219619
+  * igb: don't allow SR-IOV without MSI-X
+    - LP: #1219619
+  * igb: Update MTU so that it is always at least a standard frame size
+    - LP: #1219619
+  * igb: Refactor of init_nvm_params
+    - LP: #1219619
+  * igb: Refactor NVM read functions to accommodate devices with no flash
+    - LP: #1219619
+  * igb: Add device support for flashless SKU of i210 device
+    - LP: #1219619
+  * igb: Fix get_fw_version function for all parts
+    - LP: #1219619
+  * igb: Add macro for size of RETA indirection table
+    - LP: #1219619
+  * igb: Expose RSS indirection table for ethtool
+    - LP: #1219619
+  * igb: Don't look for a PBA in the iNVM when flashless
+    - LP: #1219619
+  * igb: Implementation of 1-sec delay for i210 devices
+    - LP: #1219619
+  * igb: New PHY_ID for i354 device
+    - LP: #1219619
+  * igb: M88E1543 PHY downshift implementation
+    - LP: #1219619
+  * igb: No PHPM support in i354 devices
+    - LP: #1219619
+  * igb: Support to get 2_5G link status for appropriate media type
+    - LP: #1219619
+  * igb: Get speed and duplex for 1G non_copper devices
+    - LP: #1219619
+  * igb: Implementation to report advertised/supported link on i354 devices
+    - LP: #1219619
+  * igb: Update version number
+    - LP: #1219619
+  * Bluetooth: Take proper tty_struct references
+    - LP: #1189998
+  * Bluetooth: Remove the device from the list in the destructor
+    - LP: #1189998
+  * Bluetooth: Move the tty initialization and cleanup out of open/close
+    - LP: #1189998
+  * Bluetooth: Implement .activate, .shutdown and .carrier_raised methods
+    - LP: #1189998
+  * Bluetooth: Fix the reference counting of tty_port
+    - LP: #1189998
+  * Bluetooth: Purge the dlc->tx_queue to avoid circular dependency
+    - LP: #1189998
+
+  [ Wen-chien Jesse Sung ]
+
+  * SAUCE: Bluetooth: Support for loading broadcom patchram firmware
+    - LP: #1065400
+  * SAUCE: Bluetooth: Add support for 13d3:3388 and 13d3:3389
+    - LP: #1065400
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 05 Sep 2013 08:06:17 -0600
+
+linux (3.11.0-5.10) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release tracker
+    - LP: #1220222
+  * Revert "[Config] Fix ubuntu directoy Kbuilds"
+  * Revert "aufs update dropped some Kbuild files"
+  * Revert "ubuntu: AUFS -- follow rename of loop.h into drivers/block"
+  * Revert "ubuntu: AUFS -- update to
+    8e503d4142c189ed6c47a2177ad2cd058e8d340e"
+  * Revert "ubuntu: (no-squash) AUFS3 -- aufs3-standalone.patch"
+  * Revert "ubuntu: (no-squash) AUFS3 -- aufs3-base.patch"
+  * rebase to v3.11 final
+  * [Config] clean up ubuntu/Kconfig and ubuntu/Makefile
+  * ubuntu: AUFS (no-squash): basic framework and update machinary
+  * ubuntu: (no-squash) AUFS3 -- aufs3-base.patch
+  * ubuntu: (no-squash) AUFS3 -- aufs3-standalone.patch
+  * ubuntu: AUFS -- update to 5ac5fe26a90a818218310e208d17688fddb07622
+  * ubuntu: (no-squash) AUFS -- enable aufs
+  * ubuntu: AUFS -- fix remaining d_count references to use accessor
+  * ubuntu: lttng -- follow rename of pid_ns
+  * SAUCE: disable stack-protector for ARM compressed bootloader
+
+  [ Paolo Pisati ]
+
+  * [Config] ARM_ATAG_DTB_COMPAT=y
+
+  [ Rob Herring ]
+
+  * [Config] Enable KVM and virtio for armhf generic-lpae
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_ARPD=y
+  * [Config] CONFIG_ZSWAP=y
+    - LP: #1215379
+
+  [ Upstream Kernel Changes ]
+
+  * uvcvideo: quirk PROBE_DEF for Dell SP2008WFP monitor.
+    - LP: #1217957
+  * ARM: use phys_addr_t for DMA zone sizes
+  * ARM: highbank: enable DMA zone for LPAE
+  * ARM: highbank: select ARCH_HAS_HOLES_MEMORYMODEL
+  * ARM: highbank: select required errata work-arounds
+  * DMA: fix AMBA PL08x compilation issue with 64bit DMA address type
+  * DMA: fix printk warning in AMBA PL08x DMA driver
+  * ARM: highbank: select ARCH_DMA_ADDR_T_64BIT for LPAE
+  * ARM: move outer_cache declaration out of ifdef
+  * ARM: highbank: avoid L2 cache smc calls when PL310 is not present
+  * ARM: highbank: clean-up some unused includes
+  * ARM: xen: only set pm function ptrs for Xen guests
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.11
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 03 Sep 2013 17:08:06 +0100
+
+linux (3.11.0-4.9) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v3.11-rc7
+  * Release tracker
+    - LP: #1216962
+
+  [ Upstream Kernel Changes ]
+
+  * mwifiex: do not create AP and P2P interfaces upon driver loading
+    - LP: #1212720
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 26 Aug 2013 06:25:35 -0600
+
+linux (3.11.0-3.8) saucy; urgency=low
+
+  [ Johannes Berg ]
+
+  * SAUCE: mac80211: ignore (E)CSA in probe response frames
+    - LP: #1201470
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 23 Aug 2013 09:47:36 -0600
+
+linux (3.11.0-3.7) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: (no-up) hv_vss_daemon -- prevent self-daemonising to allow
+    upstart to track
+  * SAUCE: (no-up) hv -- bodge hv_vss_daemon so it can use the local
+    linux/hyperv.h
+  * SAUCE: hv: Add vss daemon to Makefile
+  * [Debian] Add hv_vss_daemon to tools package
+    - LP: #1213282
+  * [Config] Fix ubuntu directoy Kbuilds
+    - LP: #1181755
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 20 Aug 2013 08:34:05 -0600
+
+linux (3.11.0-3.6) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] tools: conditionalise x86 and hyper-v tools sensibly
+  * [Config] tools: enable x86 and hyper-v
+
+  [ John Johansen ]
+
+  * Revert "SAUCE: (no-up) apparmor: Sync to apparmor 3 dev stable
+    snapshot"
+  * Revert "SAUCE: (no-up) apparmor: fix apparmor module status for none
+    root users"
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 - alpha 4 snapshot
+
+  [ Joseph Salisbury ]
+
+  * SAUCE: (no-up) intel_ips: blacklist ASUSTek G60JX laptops
+    - LP: #1210848
+
+  [ Kamal Mostafa ]
+
+  * [debian] tools: ship 'cpupower' in linux-tools
+    - LP: #1158668
+  * [Config] Build-dep on libpci-dev for cpu tools
+    - LP: #1158668
+
+  [ Tim Gardner ]
+
+  * rebase to v3.11-rc6
+  * Release tracker
+    - LP: #1213941
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 16 Aug 2013 07:02:07 -0600
+
+linux (3.11.0-2.5) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_PM_DEBUG=y
+    - LP: #1210539
+  * rebase to v3.11-rc5
+  * Release tracker
+    - LP: #1211378
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 12 Aug 2013 06:10:39 -0600
+
+linux (3.11.0-1.4) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * Bump ABI when making changes to the inclusion list lest
+    you cause conflicts with existing installed kernel
+    packages.
+    - LP: #1210331
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 09 Aug 2013 03:03:51 +0100
+
+linux (3.11.0-0.3) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Include rbd and kvm in the virtual inclusion list
+    - LP: #1206961
+  * [Config] Removed obsolete inclusion list entries
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 06 Aug 2013 08:52:14 +0100
+
+linux (3.11.0-0.2) saucy; urgency=low
+
+  [ Bruce Allan ]
+
+  * SAUCE: (no-up) e1000e: fix I217/I218 PHY initialization flow
+    - LP: #1206757
+  * SAUCE: (no-up) e1000e: enable support for new device IDs
+    - LP: #1206757
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 dev stable snapshot
+
+  [ Paolo Pisati ]
+
+  * build vexpress a15 dtb
+  * [Config] disable Broadcom bcm support (ARCH_BCM)
+  * [Config] disable Allwinner a1x support (ARCH_SUNXI)
+  * [Config] disable WonderMedia WM8850 support (ARCH_WM8850)
+  * [Config] disable Rockchip support (ARCH_ROCKCHIP)
+  * [Config] disable STMicroelectronics STiH41x SOCs (ARCH_STI)
+  * [Config] disable TI Keystone, AM43xx and OMAP5 support
+  * [Config] ARM_APPENDED_DTB=y
+
+  [ Tim Gardner ]
+
+  * rebase to v3.11-rc4
+  * overlayfs: Update to v19
+  * [Config] Enable overlayfs
+  * SAUCE: Fix lttng compile errors
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.11-rc4
+    - LP: #1163720
+    - LP: #1162026
+    - LP: #1195636
+    - LP: #1195597
+    - LP: #1180409
+    - LP: #1168430
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 04 Aug 2013 03:45:31 -0600
+
+linux (3.11.0-0.1) saucy; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 64ccccf8525fee499625b517c0faadf784c79e93
+    - LP: #1163720
+    - LP: #1162026
+    - LP: #1195636
+    - LP: #1195597
+    - LP: #1180409
+    - LP: #1168430
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 08 Jul 2013 08:50:46 -0600
+
+linux (3.10.0-2.10) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_INTEL_MEI*=m
+    - LP: #1196155
+  * [Config] CONFIG_DEBUG_INFO=y
+
+  [ Stephen Warren ]
+
+  * [Config] fix Calxeda xgmac module filename
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "serial: 8250_pci: add support for another kind of NetMos
+    Technology PCI 9835 Multi-I/O Controller"
+    - LP: #1190967
+  * mfd: lpc_ich: Add support for Intel Avoton SoC
+    - LP: #1196658
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Jul 2013 18:08:02 +0100
+
+linux (3.10.0-2.9) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.10
+
+  [ John Johansen ]
+
+  * Revert "SAUCE: (no-up) apparmor: Fix quieting of audit messages for
+    network mediation"
+  * Revert "SAUCE: (no-up) apparmor: Fix compile warnings"
+  * Revert "SAUCE: (no-up) AppArmor: basic networking rules"
+  * Revert "SAUCE: (no-up) apparmor: Add the ability to mediate mount"
+  * Revert "SAUCE: (no-up) AppArmor: Add profile introspection file to
+    interface"
+  * Revert "SAUCE: (no-up) AppArmor: Disable Add PR_{GET,SET}_NO_NEW_PRIVS
+    to prevent execve from granting privs"
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 dev stable snapshot
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 01 Jul 2013 17:42:29 +0100
+
+linux (3.10.0-1.8) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1195717
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: overlayfs -- follow change to do_splice_direct
+    interface"
+  * Revert "ubuntu: overlayfs -- expose do_splice_direct prototype"
+  * Revert "SAUCE: ubuntu: overlayfs -- ovl_path_open should not take path
+    reference"
+  * Revert "ubuntu: overlayfs -- add FS_ALIAS"
+  * Revert "ubuntu: overlayfs --
+    overlayfs-copy-up-i_uid-i_gid-from-the-underlying-inode"
+  * Revert "ubuntu: overlayfs -- ovl-switch-to-inode_permission"
+  * Revert "ubuntu: overlayfs -- vfs-export-inode_permission-to-modules"
+  * Revert "ubuntu: overlayfs -- overlayfs-create-new-inode-in-ovl_link"
+  * Revert "ubuntu: overlayfs --
+    overlayfs-fix-possible-leak-in-ovl_new_inode"
+  * Revert "ubuntu: overlayfs -- fs-limit-filesystem-stacking-depth"
+  * Revert "ubuntu: overlayfs -- overlay-overlay-filesystem-documentation"
+  * Revert "ubuntu: overlayfs -- overlayfs-implement-show_options"
+  * Revert "ubuntu: overlayfs -- overlayfs-add-statfs-support"
+  * Revert "ubuntu: overlayfs -- overlay filesystem"
+  * Revert "ubuntu: overlayfs -- vfs-introduce-clone_private_mount"
+  * Revert "ubuntu: overlayfs -- vfs-export-do_splice_direct-to-modules"
+  * Revert "ubuntu: overlayfs -- vfs-add-i_op-dentry_open"
+  * ubuntu: overlayfs v18 -- -- overlayfs: add statfs support
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs v18 -- -- overlayfs: implement show_options
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs v18 -- -- vfs: add i_op->dentry_open()
+  * ubuntu: overlayfs v18 -- -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs v18 -- -- vfs: export __inode_permission() to modules
+  * ubuntu: overlayfs v18 -- -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs v18 -- -- overlay filesystem
+  * ubuntu: overlayfs v18 -- -- fs: limit filesystem stacking depth
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs v18 -- -- overlay: overlay filesystem documentation
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_SUNRPC_DEBUG=y
+    - LP: #1127319
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 28 Jun 2013 10:26:52 +0100
+
+linux (3.10.0-0.7) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * autopkgtest: switch Depends: to build-essential
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 25 Jun 2013 08:40:55 +0100
+
+linux (3.10.0-0.6) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_ARCH_TEGRA to fix FTBFS on armhf
+  * SAUCE: ubuntu: overlayfs -- ovl_path_open should not take path reference
+    - LP: #1098378
+  * ubuntu: AUFS -- update to 4f14cef47eb7c23eda7198931fbab1040866b6ee
+  * ubuntu: overlayfs -- expose do_splice_direct prototype
+  * ubuntu: overlayfs -- follow change to do_splice_direct interface
+  * [Config] flip CONFIG_NO_HZ_FULL_ALL off as it is overheating machines
+    - LP: #1192691
+
+  [ Stefan Bader ]
+
+  * (d-i) Add dm-snapshot to md-modules
+    - LP: #1191726
+
+  [ Tim Gardner ]
+
+  * Release tracker
+    - LP: #1194149
+  * [Config] CONFIG_WIL6210=n for armhf
+  * [Config] d-i: Add calxedaxgmac to nic-modules
+    - LP: #1192358
+  * [debian] Use dh_strip
+    - LP: #1192759
+  * [Config] Enable perf for armhf
+  * do_tools=false when cross compiling
+  * [Config] CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+    - LP: #1108082
+
+  [ Upstream Kernel Changes ]
+
+  * nsp32: switch reset delay to msleep() as it is tooo long
+  * alx: add a simple AR816x/AR817x device driver
+    Plucked from linux-next. replaces ubuntu/alx in favor of
+    'to be merged' version in 3.11.
+  * rebase to v3.10-rc7
+    - LP: #1189363
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sat, 22 Jun 2013 18:10:31 -0600
+
+linux (3.10.0-0.5) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.10-rc6
+  * [Config] updateconfigs following rebase to v3.10-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc6
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 17 Jun 2013 11:12:39 +0100
+
+linux (3.10.0-0.4) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] updateconfigs following rebase to v3.10-rc4
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 10 Jun 2013 11:42:28 +0100
+
+linux (3.10.0-0.3) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.10-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc5
+    - LP: #1186170
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 10 Jun 2013 09:23:31 +0100
+
+linux (3.10.0-0.2) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.10-rc4
+  * [Config] CONFIG_BINFMT_SCRIPT=y to fix booting initramfs scripts
+  * [Config] enable SND_PCM_DEBUG SND_PCM_XRUN_DEBUG
+    - LP: #1187744
+  * [Config] enforce CONFIG_BINFMT_SCRIPT=y
+
+  [ Dave Chiluk ]
+
+  * SAUCE: ncpfs: fix rmdir returns Device or resource busy
+    - LP: #1035226
+
+  [ Tim Gardner ]
+
+  * rebase to v3.10-rc3
+  * [Config] sparc be gone
+  * [Config] ia64 be gone
+  * d-i: block-modules provides nbd-modules
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc4
+  * rebase to v3.10-rc3
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 28 May 2013 06:16:46 -0600
+
+linux (3.10.0-0.1) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * UBUNTU: Disabled lttng
+  * UBUNTU: Disable aufs for FTBS
+  * UBUNTU: Disabled alx
+  * UBUNTU: alx: rename NETIF_F_HW_VLAN_* feature flags to NETIF_F_HW_VLAN_CTAG_*
+  * UBUNTU: rebase to v3.10-rc2
+  * UBUNTU: SAUCE: uvcvideo: quirk PROBE_DEF for Alienware X51 OmniVision webcam
+
+  [ Andy Whitcroft ]
+
+  * UBUNTU: [Config] update standards version to 3.9.4.0
+  * UBUNTU: [Config] squash duplicate package description (long and short)
+  * UBUNTU: [Config] fix up Vcs-git: to point to saucy
+  * UBUNTU: [Config] drop depenancy on util-linux as is Essential
+  * UBUNTU: [Config] drop redundant Build-Conficts:
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc2
+    - LP: #1180351
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc1
+    - LP: #1172151
+    - LP: #1089795
+    - LP: #1167270
+    - LP: #1128840
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 14 May 2013 13:41:07 -0600
+
+linux (3.10.0-0.0) saucy; urgency=low
+
+  * Dummy
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 09 May 2013 20:30:40 +0100
+
+linux (3.9.0-2.6) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v3.9.2
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 09 May 2013 20:30:40 +0100
+
+linux (3.9.0-1.5) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v3.9.1
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 08 May 2013 12:49:45 -0400
+
+linux (3.9.0-0.4) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: overlayfs -- add FS_ALIAS
+
+  [ Tim Gardner ]
+
+  * Added lttng
+    - LP: #1175784
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 02 May 2013 17:17:13 -0400
+
+linux (3.9.0-0.3) saucy; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 29 Apr 2013 18:20:00 -0400
+
+linux (3.9.0-0.2) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * Enable extras packaging for amd64/i386.
+    Fixes build depenencies with brittany and linux-meta.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 29 Apr 2013 05:37:01 -0600
+
+linux (3.9.0-0.1) saucy; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc8
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc7
+    - LP: #1128840
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc4
+    - LP: #1095315
+    - LP: #886975
+    - LP: #1086921
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc3
+    - LP: #1155016
+    - LP: #1103594
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc2
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc1
+    - LP: #901105
+    - LP: #961286
+    - LP: #1011792
+    - LP: #1128934
+    - LP: #886975
+    - LP: #978807
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 20 Feb 2013 09:12:39 -0700
+
+linux (3.8.0-7.14) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_RCU_USER_QS=n
+  * [Config] CONFIG_MTD_ONENAND_SIM=n
+  * annotations: add annotations for CONFIG_CC_STACKPROTECTOR
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1130111
+  * UBUNTU: SAUCE: rt2x00: rt2x00pci_regbusy_read() - only print register access failure once
+    - LP: #1128840
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 18 Feb 2013 09:25:56 -0700
+
+linux (3.8.0-6.13) raring; urgency=low
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1125364
+  * Add ahci modules to d-i
+    - LP: #1124415
+
+
+  [ Chris Wilson ]
+
+  * SAUCE: drm/i915: Wait for pending flips to complete before tearing down
+    the encoders
+    - LP: #1097315
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 13 Feb 2013 12:16:48 -0700
+
+linux (3.8.0-6.12) raring; urgency=low
+
+  [Tim Gardner]
+
+  * perf: NO_LIBPERL=1
+  * Fix linux-headers dependency
+  * Release Tracking Bug
+    - LP: #1124362
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_AUFS_EXPORT to allow nfs exports
+    - LP: #1121699
+
+  [ Daniel Vetter ]
+
+  * SAUCE: drm/i915: write backlight harder
+    - LP: #954661
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 13 Feb 2013 10:25:11 -0700
+
+linux (3.8.0-6.11) raring; urgency=low
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1122071
+  * rebase to v3.8-rc7
+  * Add libaudit-dev as a build dependency
+  * Build perf with NO_LIBPYTHON=1 to avoid a python build dependency.
+
+  [ Leann Ogasawara ]
+
+  * [Config] Remove CONFIG_SATA_AHCI annotation
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 08 Feb 2013 07:41:13 -0500
+
+linux (3.8.0-5.10) raring; urgency=low
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1118568
+
+  * Bump ABI to fix install issue with 3.8.0-4.8.
+    Moving drivers/ata/*ahci* to linux-image caused an
+    install conflict with linux-image-extras without an
+    ABI bump.
+
+  [ Jan Beulich ]
+
+  * SAUCE: xen-pciback: rate limit error messages from
+    xen_pcibk_enable_msi{, x}()
+    - LP: #1117336
+    - CVE-2013-0231
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 07 Feb 2013 05:38:12 -0700
+
+linux (3.8.0-4.9) raring; urgency=low
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * d-i: Add mellanox ethernet drivers to nic-modules
+    - LP: #1015339
+
+  [ Joseph Salisbury ]
+
+  * SAUCE: ACPI: Add DMI entry for Sony VGN-FW41E_H
+    - LP: #1113547
+
+  [ Kamal Mostafa ]
+
+  * SAUCE: alx driver import script
+
+  [ Qualcomm Atheros, Inc ]
+
+  * SAUCE: alx: Update to heads/master
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1117673
+
+  * [debian] Remove dangling symlink from headers package
+    - LP: #1112442
+  * [config] CONFIG_ALX=m
+  * [Config] Add alx to d-i nic-modules
+  * [Config] CONFIG_SATA_AHCI=m
+    - LP: #1056563
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 05 Feb 2013 05:54:32 -0800
+
+linux (3.8.0-4.8) raring; urgency=low
+
+  [ Allen Ibara ]
+
+  * SAUCE: imx6: dts: Add IMX6Q AHCI support
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.8-rc6
+  * updateconfigs following rebase to v3.8-rc6
+
+  [Leann Ogasawara]
+
+  * Release Tracking Bug
+    - LP: #1112573
+
+  [ Paolo Pisati ]
+
+  * SAUCE: imx6: enable sata clk if SATA_AHCI_PLATFORM
+  * [Config] SERIAL_AMBA_PL011=y (vexpress serial console)
+  * [Config] MMC_ARMMMCI=y (vexpress mmc)
+  * [Config] FB_ARMCLCD=y (vexpress framebuffer)
+
+  [ Seth Forshee ]
+
+  * [Config] CONFIG_MAC80211_MESSAGE_TRACING=y
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc6
+    - LP: #1107477
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 01 Feb 2013 07:20:59 -0800
+
+linux (3.8.0-3.7) raring; urgency=low
+
+  [ Andy Green ]
+
+  * SAUCE: ARM: OMAP2+: add cpu id register to MAC address helper
+  * SAUCE: ARM: omap2 add mac address allocation register api
+  * SAUCE: ARM: omap2 panda register ethernet and wlan for automatic mac
+    allocation
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.8-rc5
+  * Release Tracking Bug
+    - LP: #1111486
+
+  [ Paolo Pisati ]
+
+  * SAUCE: davinci: vpss: compilation fix
+  * [Config] enable TI OMAP4 support (Pandaboard/ES)
+  * [Config] OMAP_USB2=y (since TWL6030_USB depends on it)
+  * [Config] enable Freescale IMX6 support (SabreLite)
+  * [Config] SERIAL_IMX_CONSOLE=y
+  * [Config] MMC_*_IMX=y
+  * [Config] disable USB_SUSPEND
+  * [Config] USB_MXS_PHY=y
+  * [Config] USB_CHIPIDEA=y
+  * SAUCE: DTB: add support for multiple DTBs
+  * SAUCE: DTB: build imx6q-sabrelite
+  * SAUCE: DTB: build beaglexm
+  * SAUCE: DTB: build panda/panda es
+  * [Config] disable CPU_FREQ
+  * [Config] PANEL_TFP410=y (video DVI output)
+  * [Config] SND_OMAP_SOC*=y
+  * [Config] SND_IMX_SOC*=y
+  * [Config] I2C_IMX=y
+  * [Config] SPI_IMX=m
+
+  [ Stefan Bader ]
+
+  * [Config] Move 9p modules into generic package
+    - LP: #1107658
+
+  [ Tony Lindgren ]
+
+  * SAUCE: ARM: OMAP2+: Limit omap initcalls to omap only on multiplatform
+    kernels
+  * SAUCE: ARM: OMAP2+: Use omap initcalls
+  * SAUCE: ARM: OMAP: Fix i2c cmdline initcall for multiplatform
+  * SAUCE: ARM: OMAP: Fix dmaengine init for multiplatform
+  * SAUCE: ARM: OMAP2+: Add multiplatform debug_ll support
+  * SAUCE: ARM: OMAP2+: Disable code that currently does not work with
+    multiplaform
+  * SAUCE: ARM: OMAP2+: Enable ARCH_MULTIPLATFORM support
+  * SAUCE: ARM: OMAP2+: Add minimal support for booting vexpress
+  * SAUCE: ARM: OMAP2+: Remove now obsolete uncompress.h and debug-macro.S
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc5
+    - LP: #1096789
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 31 Jan 2013 06:44:52 -0800
+
+linux (3.8.0-2.6) raring; urgency=low
+
+  [ Adam Conrad ]
+
+  * Fix up linux-tools -> SRCPKGNAME-tools rename
+
+  [ Andy Whitcroft ]
+
+  * [Config] re-disable CONFIG_SOUND_OSS
+    - LP: #1105230
+
+  [ Arend van Spriel ]
+
+  * SAUCE: brcmsmac: fix tx status processing
+
+  [Leann Ogasawara]
+
+  * Release Tracking Bug
+    - LP: #1105104
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 25 Jan 2013 11:56:30 -0800
+
+linux (3.8.0-1.5) raring; urgency=low
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1101235
+
+  [ Dudley Du ]
+
+  * SAUCE: Input: add support for Cypress PS/2 Trackpads
+    - LP: #978807
+
+  [ Kamal Mostafa ]
+
+  * SAUCE: Input: increase struct ps2dev cmdbuf[] to 8 bytes
+  * SAUCE: Input: Cypress PS/2 Trackpad simulated multitouch
+  * [Config] Add CONFIG_PS2_CYPRESS
+
+  [ Tim Gardner ]
+
+  * rebase to v3.8-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc4
+    - LP: #1095315
+    - LP: #886975
+    - LP: #1086921
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 17 Jan 2013 10:50:22 -0800
+
+linux (3.8.0-0.4) raring; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Update CONFIG_TOUCHSCREEN_EGALAX build annotation
+  * [Config] Update CONFIG_IIO build annotation
+  * [Config] Update CONFIG_TOUCHSCREEN_EETI annotation
+  * [Config] Remove CONFIG_SPI_DW_MMIO annotation
+  * [Config] Remove CONFIG_SPI_PL022 annotation
+  * [Config] Update CONFIG_EZX_PCAP annotation
+  * [Config] Update CONFIG_SENSORS_AK8975 annotation
+  * [Config] Disable CONFIG_DRM_MGAG200
+    - LP: #1042903
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 14 Jan 2013 10:01:50 -0800
+
+linux (3.8.0-0.3) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) trace: add trace events for open(), exec() and
+    uselib()"
+
+  [ Scott James Remnant ]
+
+  * SAUCE: (no-up) trace: add trace events for open(), exec() and uselib()
+    (for v3.7+)
+    - LP: #1085766, #462111
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 11 Jan 2013 16:57:27 +0000
+
+linux (3.8.0-0.2) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [packaging] Add macro to selectively disable building perf
+  * [packaging] Cannot depend on universe package libaudit-dev
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 10 Jan 2013 12:43:24 -0700
+
+linux (3.8.0-0.1) raring; urgency=low
+
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc3
+    - LP: #1096789
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc2
+    - LP: #1082357
+    - LP: #1075882
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 17 Dec 2012 10:35:09 +0000
+
+linux (3.7.0-7.15) raring; urgency=low
+
+  [ Chris J Arges ]
+
+  * SAUCE: add eeprom_bad_csum_allow module parameter
+    - LP: #1070182
+
+  [ Leann Ogasawara ]
+
+  * Add ceph to linux-image for virtual instances
+    - LP: #1063784
+
+  [ Serge Hallyn ]
+
+  * SAUCE: net: dev_change_net_namespace: send a KOBJ_REMOVED/KOBJ_ADD
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_SLUB_DEBUG=y
+    - LP: #1090308
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[SCSI] sd: Implement support for WRITE SAME"
+    - LP: #1089818
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 12 Dec 2012 06:50:20 -0800
+
+linux (3.7.0-6.14) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] annotations: all new annotations scheme including defaults
+  * [Configs] apply annotation updates to main configs (top section)
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: include <linux/printk.h> and <stdarg.h> for mmc_core arm
+    build"
+  * Revert "SAUCE: [arm] fixup __aeabi_uldivmod undefined build error"
+  * Temporarily disable module check for build
+
+  [ Stefan Bader ]
+
+  * ubuntu: dm-raid45: Adapt to upstream interface changes
+  * Re-enable build of dm-raid45
+
+  [ Tim Gardner ]
+
+  * SAUCE: Moved scripts/fw-to-ihex.sh to debian/scripts/misc
+  * SAUCE: ACPICA: Fix ACPI mutex object allocation memory leak on error
+  * SAUCE: drm: Fix possible EDID memory allocation oops
+  * SAUCE: ttm: Fix possible _manager memory allocation oops
+  * SAUCE: iwlwifi: iwlagn_request_scan: Fix check for priv->scan_request
+  * SAUCE: i915: intel_set_mode: Reduce stack allocation from 500 bytes to
+    2 pointers
+
+  [ Tomas Hozza ]
+
+  * SAUCE: tools: hv: Netlink source address validation allows DoS
+    - LP: #1084777
+    - CVE-2012-5532
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 05 Dec 2012 14:11:12 -0800
+
+linux (3.7.0-5.13) raring; urgency=low
+
+  [ Lino Sanfilippo ]
+
+  * SAUCE: inotify, fanotify: replace fsnotify_put_group() with
+    fsnotify_destroy_group()
+    - LP: #922906
+  * SAUCE: fsnotify: introduce fsnotify_get_group()
+    - LP: #922906
+  * SAUCE: fsnotify: use reference counting for groups
+    - LP: #922906
+  * SAUCE: fsnotify: take groups mark_lock before mark lock
+    - LP: #922906
+  * SAUCE: fanotify: add an extra flag to mark_remove_from_mask that
+    indicates wheather a mark should be destroyed
+    - LP: #922906
+  * SAUCE: fsnotify: use a mutex instead of a spinlock to protect a groups
+    mark list
+    - LP: #922906
+  * SAUCE: fsnotify: pass group to fsnotify_destroy_mark()
+    - LP: #922906
+  * SAUCE: fsnotify: introduce locked versions of fsnotify_add_mark() and
+    fsnotify_remove_mark()
+    - LP: #922906
+  * SAUCE: fsnotify: dont put marks on temporary list when clearing marks
+    by group
+    - LP: #922906
+  * SAUCE: fsnotify: change locking order
+    - LP: #922906
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NFC_LLCP=y
+  * [Config] get-firmware: Filter new files through fwinfo
+  * [Config] CONFIG_MTD_NAND_DOCG4=m for all arches
+  * [Config] CONFIG_DRM_EXYNOS_HDMI=y
+  * [Config] CONFIG_XEN=y for all arches
+  * [Config] CONFIG_SND_OMAP_SOC_ZOOM2=m
+  * [Config] CONFIG_MMC_DW_EXYNOS=m
+  * [Config] CONFIG_GPIO_ADNP=m
+  * [Config] find-obsolete-firmware: Use correct path
+  * rebase to v3.7-rc8
+    - LP: #1084640
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "VFS: don't do protected {sym,hard}links by default"
+    - LP: #1084192
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 28 Nov 2012 16:07:08 +0000
+
+linux (3.7.0-4.12) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * Revert "[Config] Use -j1 for headers_install"
+  * Revert "[Config] install-arch-headers needs a valid config"
+    Strayed into the weeds in search of the root cause of the periodic
+    build failure.
+    Fixes powerpc FTBS introduced in -4.11.
+  * [Config] hmake -j1
+    The kernel makefile appears to have parallel dependency
+    problems for the install_headers target. This appears to be root
+    cause for a periodic build failure on N-way machines.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 27 Nov 2012 12:33:06 -0800
+
+linux (3.7.0-4.11) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Use -j1 for headers_install
+    Also fixes a powerpc FTBS introduced by
+    "[Config] install-arch-headers needs a valid config".
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 27 Nov 2012 10:19:30 -0700
+
+linux (3.7.0-4.10) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] add rebuild-test support for autopkgtest
+    - LP: #1081500
+  * [tests] move build tests out of the way
+    - LP: #1081500
+  * [tests] add an autopkgtest rebuild test
+    - LP: #1081500
+
+  [ Tim Gardner ]
+
+  * rebase to v3.7-rc7
+  * SAUCE: Remove emi62 files duplicated in linux-firmware
+  * SAUCE: Remove sb16 files duplicated in linux-firmware
+  * SAUCE: Remove whiteheat files duplicated in linux-firmware
+  * SAUCE: Remove yamaha files duplicated in linux-firmware
+  * SAUCE: Remove dsp56k files used only by m68k
+  * SAUCE: firmware: Remove last vestiges of dabusb
+  * SAUCE: Remove vicam files duplicated in linux-firmware
+  * [Config] install-arch-headers needs a valid config
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc7
+    - LP: #1076840
+    - LP: #1081466
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 21 Nov 2012 06:07:23 -0800
+
+linux (3.7.0-3.9) raring; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_X86_CPUFREQ_NFORCE2=y
+    - LP: #1079900
+  * Add nfsv3 to nfs-modules udeb
+
+  [ Paolo Pisati ]
+
+  * [Config] SND_OMAP_SOC*=y
+    - LP: #1019321
+
+  [ Stefan Bader ]
+
+  * SAUCE: (no-up) xen/netfront: handle compound page fragments on transmit
+    - LP: #1078926
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: SECCOMP: audit: always report seccomp violations"
+    - LP: #1079469
+  * Revert "SAUCE: omap3 clocks .dev_id = NULL"
+  * rebase to v3.7-rc6
+  * SAUCE: script to detect obsolete firmware
+  * SAUCE: Remove yam files duplicated in linux-firmware
+  * SAUCE: Remove tehuti files duplicated in linux-firmware
+  * SAUCE: Remove matrox files duplicated in linux-firmware
+  * SAUCE: Remove cxgb3 files duplicated in linux-firmware
+  * SAUCE: Remove r128 files duplicated in linux-firmware
+  * SAUCE: Remove acenic files duplicated in linux-firmware
+  * SAUCE: Remove keyspan files duplicated in linux-firmware
+  * SAUCE: Remove sun files duplicated in linux-firmware
+  * SAUCE: Remove radeon files duplicated in linux-firmware
+  * SAUCE: Update bnx2x firmware to 7.8.2.0
+  * [Config] generic.inclusion-list: econet has disappeared
+
+  [ Upstream Kernel Changes ]
+
+  * seccomp: forcing auditing of kill condition
+    - LP: #1079469
+  * rebase to v3.7-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 20 Nov 2012 12:28:55 -0800
+
+linux (3.7.0-2.8) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "overlayfs: disable until FTBS is fixed"
+  * Revert "ubuntu: overlayfs"
+  * Revert "ubuntu: AUFS"
+  * ubuntu: overlayfs -- overlayfs: add statfs support
+  * ubuntu: overlayfs -- ovl: switch to __inode_permission()
+  * ubuntu: overlayfs -- overlayfs: copy up i_uid/i_gid from the underlying
+    inode
+    - LP: #944386
+  * ubuntu: AUFS (no-squash): basic framework and update machinary
+  * ubuntu: AUFS (no-squash) -- aufs3-base.patch
+  * ubuntu: AUFS (no-squash) -- aufs3-standalone.patch
+  * ubuntu: AUFS: aufs-update -- follow the uapi header changes
+  * ubuntu: AUFS -- update to f2873474324d0a31af4340554b9715f51331bc7f
+  * ubuntu: AUFS (no-squash) -- reenable
+    - LP: #1079193
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs -- overlayfs: implement show_options
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs -- vfs: add i_op->dentry_open()
+  * ubuntu: overlayfs -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs -- overlay filesystem
+  * ubuntu: overlayfs -- fs: limit filesystem stacking depth
+  * ubuntu: overlayfs -- vfs: export __inode_permission() to modules
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs -- overlay: overlay filesystem documentation
+
+  [ Robin Dong ]
+
+  * ubuntu: overlayfs -- overlayfs: fix possible leak in ovl_new_inode
+  * ubuntu: overlayfs -- overlayfs: create new inode in ovl_link
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 15 Nov 2012 13:35:12 +0000
+
+linux (3.7.0-1.7) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Drop dependency on libaudit-dev
+    Its a universe package which causes an FTBS on the builders.
+    libaudit-dev is not strictly required for the perf tools build.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 14 Nov 2012 10:08:13 -0700
+
+linux (3.7.0-1.6) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enforce -- switch CONFIG_NVRAM to more readable form
+  * [Config] better encode the CONFIG_NVRAM constaint
+  * enforcer -- fix debugging output
+
+  [ Ben Collins ]
+
+  * [Config] Add custom_override rule to allow for alternate kernel
+    file/install
+  * [Config] Use SRCPKGNAME as prefix for indep linux headers package
+
+  [ Tim Gardner ]
+
+  * [Config] Dropped armel
+  * Drop highbank from ABI fetch list
+  * [Config] Use dh_prep instead of 'dh_clean -k'
+  * [Config] Build depend on libaudit-dev, libunwind8-dev for tools
+  * [Config] Document binary-indep dependency chain
+  * rebase to v3.7-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc5
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 13 Nov 2012 07:13:37 -0500
+
+linux (3.7.0-0.5) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_AMD_IOMMU_V2=m
+    - LP: #1071520
+  * [Config] CONFIG_MTD_ONENAND_SIM=n for armel
+    Fixes FTBS
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 08 Nov 2012 15:45:39 -0500
+
+linux (3.7.0-0.4) raring; urgency=low
+
+  [ Ben Collins ]
+
+  * [Config] Update enforce rule for CONFIG_NVRAM to better suit flavours
+
+  [ Tim Gardner ]
+
+  * [Config] do_tools=false for arm
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 08 Nov 2012 05:39:51 -0700
+
+linux (3.7.0-0.3) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_DRM_EXYNOS_HDMI=n for armhf
+  * [Config] CONFIG_MTD_NAND_DOCG4=n for armel/armhf
+  * [Config] Drop highbank harder
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 07 Nov 2012 18:11:45 +0000
+
+linux (3.7.0-0.2) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] add fs/udf to linux-image to support DVD/CD formats in virtual
+    instances
+    - LP: #1066921
+  * [Config] drop highbank builds
+
+  [ Jeremy Kerr ]
+
+  * SAUCE: efivarfs: Implement exclusive access for {get, set}_variable
+    - LP: #1063061
+
+  [ Leann Ogasawara ]
+
+  * Reinstate dropped.txt from Ubuntu-3.7.0-0.1-rc1
+
+  [ Tim Gardner ]
+
+  * [Config] Dropped powerpc/ppc64 in favour of the community kernel
+  * [Config] CONFIG_MODULE_SIG=y for amd64,i386, and highbank
+  * rebase to v3.7-rc4
+  * SAUCE: MODSIGN: Emit error for incorrectly signed module
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc4
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 05 Nov 2012 05:35:41 -0700
+
+linux (3.7.0-0.1) raring; urgency=low
+
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc3
+    - LP: #1056078
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc2
+    - LP: #1060729
+    - LP: #1059523
+    - LP: #1006690
+    - LP: #1049623
+    - LP: #1046512
+    - LP: #1052499
+    - LP: #1037642
+    - LP: #559939
+    - LP: #1052460
+    - LP: #939161
+    - LP: #1046734
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 02 Oct 2012 08:13:07 -0600
+
+linux (3.6.0-0.1) UNRELEASED; urgency=low
+
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc6
+    - LP: #1000424
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc5
+    - LP: #1040077
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc3
+    - LP: #1038651
+    - LP: #1034779
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 24 Jul 2012 06:37:09 -0700
+
+linux (3.5.0-6.6) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION enable IPv6
+    experimental features
+  * SAUCE: highbank -- export clock functions for modules
+  * [Config] highbank -- reenable CONFIG_TOUCHSCREEN_W90X900
+  * [Config] highbank -- renenable CONFIG_SERIO_AMBAKMI
+  * [Config] highbank -- reenable CONFIG_RFKILL_GPIO
+  * [Config] highbank -- reenable CONFIG_MMC_SDHCI_PXAV3
+  * [Config] highbank -- reenable CONFIG_MMC_SDHCI_PXAV3
+  * [Config] highbank -- reenable CONFIG_KEYBOARD_SAMSUNG
+  * [Config] highbank -- reenable CONFIG_FB_ARMCLCD
+  * [Config] highbank -- reenable CONFIG_DW_DMAC
+  * [Config] highbank -- reenable CONFIG_USB_R8A66597_HCD
+  * [Config] highbank -- reenable CONFIG_USB_MV_UDC
+  * [Config] highbank -- reenable CONFIG_USB_DWC3
+  * [Config] highbank -- reenable CONFIG_SATA_MV
+  * [Config] highbank -- reenable CONFIG_PATA_ARASAN_CF
+  * [Config] highbank -- CONFIG_CAN_C_CAN_PLATFORM
+  * [Config] highbank -- reenable CONFIG_MMC_ARMMMCI
+  * [Config] highbank -- reenable CONFIG_SERIAL_AMBA_PL010
+  * [Config] highbank -- reenable CONFIG_ATMEL_PWM
+  * [Config] highbank -- enable CONFIG_CHECKPOINT_RESTORE
+  * [Config] highbank -- enable CONFIG_EXPERT
+  * [Config] highbank -- enable CONFIG_CHECKPOINT_RESTORE
+  * [Config] enable CONFIG_USB_DYNAMIC_MINORS
+  * [Config] enable CONFIG_USB_EHCI_TT_NEWSCHED
+  * [Config] enable CONFIG_USB_ETH_EEM
+  * [Config] enable CONFIG_USB_HCD_BCMA/CONFIG_USB_HCD_SSB
+  * [Config] disable CONFIG_USB_M66592
+  * [Config] enable CONFIG_USB_NET2272
+  * [Config] enable CONFIG_USB_R8A66597
+  * [Config] annotate: CONFIG_USB_OMAP not required for our h/w
+  * [Config] set CONFIG_USB_MUSB_HDRC=m for omap
+  * [Config] annotate: CONFIG_USB_G_MULTI fix rule
+  * [Config] CONFIG_USB_GPIO_VBUS=m for OMAP
+  * [Config] Enable CONFIG_DRM_AST/_CIRRUS_QEMU/_MGAG200
+  * [Config] sync configuration armhf omap -> armel omap
+  * [Config] annotate: CONFIG_IIO triggers build failures on OMAP4
+  * [Config] disable CONFIG_OMAP_IOVMM is deprecated
+
+  [ Bryan Wu ]
+
+  * [Config] change default IO scheduler from CFQ to Deadline
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] Temporarily disable CONFIG_MV643XX_ETH on powerpc"
+  * [Config] Disable CONFIG_MOUSE_INPORT
+
+  [ Tim Gardner ]
+
+  * SAUCE: firmware: Update bnx2x to current firmware version 7.2.51
+  * [Config] Add bnx2x firmware to nic-modules udeb
+  * SAUCE: Add script to convert firmware to ihex format
+  * SAUCE: firmware: Upgrade bnx2 to current versions
+  * [Config] Add tigon firmware to nic-modules udeb
+  * [Config] CONFIG_EARLY_PRINTK_DBGP=y
+    - LP: #1026761
+  * SAUCE: Remove redundant cis firmware
+  * SAUCE: Remove redundant emi26 firmware
+  * SAUCE: Remove redundant ttusb-budget firmware
+  * SAUCE: Remove redundant sun/cassini firmware
+  * SAUCE: Remove redundant ositech/Xilinx7OD firmware
+  * SAUCE: Remove redundant 3com/typhoon.bin firmware
+  * SAUCE: Remove redundant yamaha/ds1 firmware
+  * SAUCE: Remove redundant keyspan_pda firmware
+  * rebase to v3.5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5
+    - LP: #1027828
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 23 Jul 2012 05:57:04 -0700
+
+linux (3.5.0-5.5) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] annotations: initial import of configuration annotations
+
+  [ Bryan Wu ]
+
+  * [Config] enforcer -- add CONFIG_I2C_DESIGNWARE_PLATFORM enforce checker
+
+  [ Leann Ogasawara ]
+
+  * Rebase to v3.5-rc7
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Bluetooth: btusb: Add vendor specific ID (0a5c:21f4) BCM20702A0
+    - LP: #1010281
+
+  [ Tim Gardner ]
+
+  * [Config] enable CONFIG_I2C_HELPER_AUTO for all flavours as policy
+    expects
+  * [Config] CONFIG_I2O_CONFIG_OLD_IOCTL=n
+  * [Config] CONFIG_BRIDGE_EBT_ULOG=n
+  * [Config] CONFIG_IP_NF_QUEUE=n
+  * [Config] CONFIG_MTD_DOC2000=n
+  * [Config] CONFIG_PRINT_QUOTA_WARNING=n
+  * [Config] CONFIG_PRISM54=n
+  * [Config] CONFIG_SCx200_I2C=n
+  * [Config] CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 16 Jul 2012 15:38:41 -0700
+
+linux (3.5.0-4.4) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] getabis should be extracting all packages
+    - LP: #1021174
+  * [Config] getabis -- series uses linux-image-extra
+    - LP: #1021174
+  * rebase to v3.5-rc6
+
+  [ Bryan Wu ]
+
+  * [Config] built-in CONFIG_MICREL_PHY as other PHY drivers for all
+    flavours
+  * [Config] sync CONFIG_MOUSE_PS2_ config for all flavours
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_RT2800USB_RT35XX and CONFIG_RT2800USB_RT53XX
+    - LP: #1019561
+
+  [ Paolo Pisati ]
+
+  * [Config] SND_OMAP_SOC, SND_OMAP_SOC_MCBSP and SND_OMAP_SOC_OMAP3_BEAGLE =y
+    - LP: #1019321
+
+  [ Stefan Bader ]
+
+  * SAUCE: (pre-up) net: dont use __netdev_alloc_skb for bounce buffer
+    - LP: #1018456
+  * (config) Disable ACPI_PROCFS_POWER
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_ACPI_BGRT=y
+  * Extract firmware module info during getabi
+    - LP: #1021174
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 09 Jul 2012 08:50:20 -0700
+
+linux (3.5.0-3.3) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_MEMTEST=y
+    - LP: #1004535
+  * [Config] config-check: add support for a cut operation
+  * [Config] enforcer -- switch to cut where appropriate
+
+  [ Leann Ogasawara ]
+
+  * Rebase to v3.5-rc5
+  * [Config] Updateconfigs after rebase to v3.5-rc5
+
+  [ Luis Henriques ]
+
+  * SAUCE: ocfs2: Fix NULL pointer dereferrence in
+    __ocfs2_change_file_space
+    - LP: #1006012
+
+  [ Seth Forshee ]
+
+  * SAUCE: (drop after 3.5) drm/i915: ignore pipe select bit when checking
+    for LVDS register initialization
+    - LP: #1012800
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc5
+    - LP: #1013183
+    - LP: #1017017
+    - LP: #884652
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 02 Jul 2012 06:41:58 -0700
+
+linux (3.5.0-2.2) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.5-rc4
+
+  [ Arend van Spriel ]
+
+  * SAUCE: (drop after 3.5) brcmsmac: fix NULL pointer crash in
+    brcms_c_regd_init()
+    - LP: #950320
+
+  [ Bryan Wu ]
+
+  * [Config] Sync CONFIG_CGROUP_MEM_RES_CTLR_SWAP for ARM
+
+  [ Chris J Arges ]
+
+  * PACKAGING: add .gnu_debuglink sections to .ko files
+    - LP: #669641
+
+  [ Leann Ogasawara ]
+
+  * d-i: Add hid-generic to input-modules
+    - LP: #1017879
+
+  [ Ming Lei ]
+
+  * SAUCE: Revert "mmc: omap_hsmmc: Enable Auto CMD12"
+    - LP: #1017717, #225
+
+  [ Paolo Pisati ]
+
+  * SAUCE: Revert "Fix OMAP EHCI suspend/resume failure (i693)"
+    - LP: #1017718
+  * [Config] Disable generic USB_EHCI_HCD_PLATFORM on omap3
+
+  [ Seth Forshee ]
+
+  * SAUCE: (drop after 3.5) brcm80211: smac: don't set up tx power limits
+    during initialization
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: always set channel specified
+    by mac80211
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: remove unused code for 40MHz
+    channels
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: clean up channel.c
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: inform mac80211 of the X2
+    regulatory domain
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: enable/disable radio on
+    regulatory updates
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: use mac80211 channel data for
+    tx power limits
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: don't validate channels
+    against internal regulatory data
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: use current regulatory domain
+    when checking whether OFDM is allowed
+    - LP: #950320
+
+  [ Tim Gardner ]
+
+  * [Config] Enable CONFIG_CGROUPS for highbank
+    - LP: #1014692
+  * [Config] FB_OMAP*=y and PANEL_TFP410=y
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 26 Jun 2012 06:21:05 -0700
+
+linux (3.5.0-1.1) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] highbank -- enable CONFIG_RFKILL=y and CONFIG_CAN=m
+
+  [ Leann Ogasawara ]
+
+  * Rebase to v3.5-rc1
+  * [Config] Remove USB_DEVICEFS from the config enforcer
+  * [Config] Updateconfigs after rebase to v3.5-rc1
+  * [Config] Temporarily disable CONFIG_MACH_NOKIA_RX51 on arm
+  * [Config] Temporarily disable CONFIG_TOUCHSCREEN_EETI on arm
+  * [Config] Temporarily disable CONFIG_TOUCHSCREEN_EGALAX on arm
+  * [Config] Temporarily disable CONFIG_EZX_PCAP on arm
+  * [Config] Temporarily disable CONFIG_LIS3L02DQ on arm
+  * [Config] Temporarily disable CONFIG_TI_CPSW on arm
+  * [Config] Temporarily disable CONFIG_GPIO_EM on arm
+  * [Config] Temporarily disable CONFIG_SERIAL_8250_EM on armhf
+  * [Config] Temporarily disable CONFIG_STMMAC_ETH on armhf
+  * [Config] Temporarily disable CONFIG_HW_RANDOM_ATMEL on armhf
+  * Rebase to v3.5-rc2
+  * [Config] Updateconfigs after rebase to v3.5-rc2
+  * [Config] Temporarily disable CONFIG_MV643XX_ETH on powerpc
+  * Rebase to v3.5-rc3
+  * [Config] Updateconfigs after rebase to v3.5-rc3
+
+  [ Paul Mundt ]
+
+  * SAUCE: fix bug.h's inclusion of kernel.h
+
+  [ Stefan Bader ]
+
+  * SAUCE: Fix compile failures of dm-raid45
+  * [Config] Enable dm-raid45
+  * Move dependency on crda to extra package
+    - LP: #657901
+  * SAUCE: Mask CR4 writes on older Xen hypervisors
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc3
+    - LP: #993162
+    - LP: #925577
+  * rebase to v3.5-rc2
+  * rebase to v3.5-rc1
+    - LP: #955892
+    - LP: #978038
+    - LP: #987371
+    - LP: #929545
+    - LP: #942316
+    - LP: #903853
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 08 Jun 2012 14:28:46 -0700
+
+linux (3.4.0-5.11) quantal-proposed; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_ARM_LPAE
+    - LP: #1009061
+
+  [ Oleksij Rempel ]
+
+  * SAUCE: b43: do not call ieee80211_unregister_hw if we are not registred
+    - LP: #1008905
+
+  [ Paolo Pisati ]
+
+  * [Config] omap3: MFD_OMAP_USB_HOST is usb host in omap2+.
+    - LP: #1009061
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 05 Jun 2012 08:06:28 -0700
+
+linux (3.4.0-4.10) quantal; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Temporarily disable ABI and module check
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 04 Jun 2012 20:27:31 -0700
+
+linux (3.4.0-4.9) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] fix config split to avoid the shared config
+  * [Config] updateconfigs following split config fix
+  * [Config] linux-image-extras needs full postinst
+  * [Config] CONFIG_BLK_DEV_NVME commonise across architectures
+  * [Config] CONFIG_HP_WATCHDOG enable as module
+  * [Config] CONFIG_PDC_ADMA is not boot essential
+  * [Config] CONFIG_XEN_ACPI_PROCESSOR should be enabled on x86
+  * [Config] CONFIG_VT6655/CONFIG_VT6656=m
+  * [Config] CONFIG_TRANZPORT=m commonise
+  * [Config] CONFIG_R3964=m commonise
+  * [Config] CONFIG_SCSI_DH=m commonise
+  * [Config] CONFIG_SCSI_IBMVSCSIS=m commonise
+  * [Config] CONFIG_AMD_PHY=y phys are not autoloadable
+  * [Config] CONFIG_SCSI_QLA_ISCSI=m commonise
+  * [Config] CONFIG_SCSI_SPI_ATTR=m commonise
+  * [Config] CONFIG_USB_SN9C102 is deprecated disable
+  * [Config] CONFIG_USB_SI470X=m commonise
+  * [Config] CONFIG_USB_ET61X251=m commonise
+  * [Config] CONFIG_RTS_PSTOR=m commonise
+  * [Config] CONFIG_SCANLOG=m commonise
+  * [Config] CONFIG_SCSI_SYM53C8XX_2=m commonise
+  * [Config] CONFIG_SM_FTL=m commonise
+  * [Config] CONFIG_SOLO6X10=m commonise
+  * [Config] CONFIG_SND_PCM_OSS=n using pulseaudio emulation instead
+  * [Config] CONFIG_SPI_DESIGNWARE=m commonise
+  * [Config] CONFIG_SPI_SPIDEV=m commonise
+  * [Config] CONFIG_TABLET_USB_WACOM=m commonise
+  * [Config] CONFIG_TPS65010=m commonise
+  * [Config] CONFIG_STE10XP=y commonise
+  * [Config] CONFIG_X25_ASY=m commonise
+  * [Config] CONFIG_USB_MON=m commonise
+  * [Config] CONFIG_VME_BUS=m commonise
+  * [Config] CONFIG_W35UND=m commonise
+  * [Config] -CONFIG_TCG_TPM=y commonise
+  * [Config] highbank -- commonise filesystems
+  * [Config] highbank -- commonise subsystems
+  * [Config] highbank -- commonise network protocols
+  * [Config] highbank -- commonise input drivers
+  * [Config] highbank -- commonise CRYPTO options
+  * [Config] highbank -- commonise HID options
+  * [Config] highbank -- commonise sensors options
+  * [Config] highbank -- commonise EXPORTFS/FHANDLE
+  * [Config] highbank -- commonise CONFIG_CRYPTO_LZO
+  * [Config] highbank -- commonise ENCRYPTED_KEYS
+  * [Config] highbank -- commonise CONFIG_ATALK
+  * [Config] highbank -- commonise INET/INET6
+  * [Config] highbank -- commonise NLS
+  * [Config] highbank -- commonise BLK/CHR
+  * [Config] highbank -- CONFIG_EXT2_FS=y boot essential on highbank
+  * [Config] highbank -- commonise INET/INET6 part 2
+  * [Config] highbank -- commonise PHY settings
+  * [Config] highbank -- commonise CRC settings
+  * [Config] highbank -- commonise BINFMT settings
+  * [Config] highbank -- commonise DM settings
+  * [Config] highbank -- commonise RTC_DRV settings
+  * [Config] highbank -- commonise KEYBOARD/MOUSE settings
+  * [Config] highbank -- commonise USB settings
+  * [Config] highbank -- commonise GPIO settings
+  * [Config] highbank -- commonise I2C settings
+  * [Config] highbank -- commonise numerous subsystem selectors
+  * [Config] highbank -- commonise A-C modules missmatches
+  * [Config] highbank -- commonise D-F modules missmatches
+  * [Config] CONFIG_AUDIT_LOGINUID_IMMUTABLE incompatible with upstart
+  * [Config] highbank -- commonise G-I modules missmatches
+  * [Config] highbank -- commonise J-L modules missmatches
+  * [Config] highbank -- commonise M modules missmatches
+  * [Config] highbank -- commonise N-P modules missmatches
+  * [Config] highbank -- commonise Q-R modules missmatches
+  * [Config] highbank -- commonise S modules missmatches -- part 1
+  * [Config] highbank -- commonise S modules missmatches -- part 2
+  * [Config] highbank -- commonise T modules missmatches
+  * [Config] highbank -- commonise U-Z modules missmatches
+
+  [ Ike Panhc ]
+
+  * [Config] add highbank flavour
+    - LP: #1000831
+
+  [ Mark Langsdorf ]
+
+  * SAUCE: arm highbank: add support for pl320-ipc driver
+    - LP: #1000831
+
+  [ Rob Herring ]
+
+  * SAUCE: input: add a key driver for highbank
+    - LP: #1000831
+  * SAUCE: ARM: highbank: Add smc calls to enable/disable the L2
+    - LP: #1000831
+  * SAUCE: force DMA buffers to non-bufferable on highbank
+    - LP: #1000831
+  * SAUCE: net: calxedaxgmac: fix net timeout recovery
+    - LP: #1000831
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_IWLWIFI_EXPERIMENTAL_MFP=n
+  * [Config] CONFIG_PCI_REALLOC_ENABLE_AUTO=y
+  * [Config] CONFIG_CIFS_EXPERIMENTAL has disappeared
+  * [Config] Homogenize CIFS configs across all arches
+  * [Config] armhf should not be skipabi or skipmodules
+    - LP: #1006913
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 04 Jun 2012 05:52:49 -0700
+
+linux (3.4.0-3.8) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] include include/generated/compile.h
+    - LP: #942569
+  * [Config] fix up postinst to ensure we know which error is which
+    - LP: #1002388
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: async_populate_rootfs: fix build warnings
+    - LP: #1003417
+
+  [ John Johansen ]
+
+  * Revert "SAUCE: AppArmor: Add the ability to mediate mount"
+  * SAUCE: apparmor: Add the ability to mediate mount
+  * SAUCE: AppArmor: basic networking rules
+  * SAUCE: apparmor: fix profile lookup for unconfined
+    - LP: #978038, #987371
+  * SAUCE: apparmor: fix long path failure due to disconnected path
+    - LP: #955892
+
+  [ Mario Limonciello ]
+
+  * SAUCE: dell-laptop: rfkill blacklist Dell XPS 13z, 15
+    - LP: #901410
+
+  [ Stefan Bader ]
+
+  * (config) Built-in xen-acpi-processor
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NET_DSA=m
+    - LP: #1004148
+  * [Config] Ensure CONFIG_XEN_ACPI_PROCESSOR=y for amd64
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 25 May 2012 11:38:33 -0700
+
+linux (3.4.0-3.7) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] drop the virtual flavour in favour of a split generic et al
+  * [Config] enforcer -- drop IDLE enforcement
+  * [Config] enable CONFIG_SCSI_VIRTIO=m for amd64
+  * [Config] updateconfigs following removal of -virtual
+
+  [ Leann Ogasawara ]
+
+  * Rebase to v3.4
+
+  [ Seth Forshee ]
+
+  * [Config] disable CONFIG_B43_BCMA_EXTRA
+
+  [ Tim Gardner ]
+
+  * [Config] Check for extras when building udebs
+  * [Config] Collapsed generic-pae into generic [i386]
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 21 May 2012 07:23:47 -0700
+
+linux (3.4.0-2.6) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: overlayfs -- overlayfs: update touch_atime() usage"
+  * Revert "ubuntu: overlayfs -- overlayfs: switch from d_alloc_root() to
+    d_make_root()"
+  * Revert "ubuntu: overlayfs -- overlayfs: follow header cleanup"
+  * Revert "ubuntu: overlayfs -- overlayfs: apply device cgroup and
+    security permissions to overlay files"
+  * Revert "ubuntu: overlayfs -- fs: limit filesystem stacking depth"
+  * Revert "ubuntu: overlayfs -- overlay: overlay filesystem documentation"
+  * Revert "ubuntu: overlayfs -- overlayfs: implement show_options"
+  * Revert "ubuntu: overlayfs -- overlayfs: add statfs support"
+  * Revert "ubuntu: overlayfs -- overlay filesystem"
+  * Revert "ubuntu: overlayfs -- vfs: introduce clone_private_mount()"
+  * Revert "ubuntu: overlayfs -- vfs: export do_splice_direct() to modules"
+  * Revert "ubuntu: overlayfs -- vfs: add i_op->open()"
+  * Revert "ubuntu: overlayfs -- vfs: pass struct path to __dentry_open()"
+  * ubuntu: overlayfs -- overlayfs: add statfs support
+  * ubuntu: overlayfs -- inode_only_permission: export inode level
+    permissions checks
+  * ubuntu: overlayfs -- overlayfs: switch to use inode_only_permissions
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs -- overlayfs: implement show_options
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs -- vfs: pass struct path to __dentry_open()
+  * ubuntu: overlayfs -- vfs: add i_op->open()
+  * ubuntu: overlayfs -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs -- overlay filesystem
+  * ubuntu: overlayfs -- fs: limit filesystem stacking depth
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs -- overlay: overlay filesystem documentation
+
+  [ Robin Dong ]
+
+  * ubuntu: overlayfs -- overlayfs: fix possible leak in ovl_new_inode
+  * ubuntu: overlayfs -- overlayfs: create new inode in ovl_link
+
+  [ Tim Gardner ]
+
+  * [Config] perarch and indep tools builds need separate build directories
+  * Prevent upgrading a non-PAE CPU
+  * perf is not parallel build safe
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 16 May 2012 08:43:18 -0700
+
+linux (3.4.0-2.5) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] perarch and indep tools builds need separate build directories
+
+  [ Tim Gardner ]
+
+  * Prevent upgrading a non-PAE CPU
+  * [Config] build debug
+  * [Config] perf tools are not parallel build safe
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 15 May 2012 11:37:53 -0700
+
+linux (3.4.0-2.4) quantal; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: fsam7400: use UMH_WAIT_PROC consistently"
+  * Revert "ubuntu: fsam7400 select CHECK_SIGNATURE and depend on X86"
+  * Revert "ubuntu: fsam7400: Depend on CHECK_SIGNATURE"
+  * Revert "ubuntu: fsam7400 -- Cleanup Makefile"
+  * Revert "ubuntu: fsam7400 -- kill switch for Fujitsu Siemens Amilo M
+    7400"
+  * Revert "ubuntu: omnibook: fix source file newline"
+  * Revert "ubuntu: omnibook -- update BOM"
+  * Revert "SAUCE: Make CONFIG_{OMNIBOOK, AVERATEC_5100P, PACKARDBELL_E5}
+    depend on X86"
+  * Revert "ubuntu: omnibook -- Added missing BOM file"
+  * Revert "ubuntu: omnibook -- support Toshiba (HP) netbooks"
+  * Revert "ubuntu: nx-emu - i386: mmap randomization for executable
+    mappings"
+  * Revert "SAUCE: disable_nx should not be in __cpuinitdata section for
+    X86_32"
+  * Revert "ubuntu: nx-emu - i386: NX emulation"
+  * Revert "ubuntu: rfkill drivers -- version 1.3"
+  * Temporarily disable module check
+  * [Config] Remove CONFIG_FSAM7400
+  * [Config] Remove CONFIG_OMNIBOOK
+  * [Config] Update configs
+  * Rebase to v3.4-rc7
+  * SAUCE: genirq: export handle_edge_irq() and irq_to_desc()
+
+  [ Tim Gardner ]
+
+  * Updated generic-pae description
+  * Rebase to v3.4-rc6
+  * install-tools depends on build targets
+
+  [ Upstream Kernel Changes ]
+
+  * kconfig: in debug mode some 0 length message prints occur
+  * rebase to v3.4-rc7
+  * rebase to v3.3-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 14 May 2012 08:22:56 -0700
+
+linux (3.4.0-1.3) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] control.stub is an intermediate product not a dependancy
+    - LP: #992414
+
+  [ Leann Ogasawara ]
+
+  * remove i386 generic from getabis
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) b43: only reload config after successful initialization
+    - LP: #950295
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 02 May 2012 09:48:14 -0700
+
+linux (3.4.0-1.2) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] add build depends for flex, bison and pkg-config
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 01 May 2012 13:15:41 +0100
+
+linux (3.4.0-1.1) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: overlayfs -- overlayfs: apply device cgroup and security
+    permissions to overlay files
+    - LP: #915941, #918212
+    - CVE-2012-0055
+
+  [ Leann Ogasawara ]
+
+  * Open Q
+  * Rebase to v3.4-rc5
+  * [Config] Temporarily disable CONFIG_TOUCHSCREEN_EETI on arm
+  * [Config] Temporarily disable CONFIG_TOUCHSCREEN_EGALAX on arm
+  * [Config] Temporarily disable CONFIG_EZX_PCAP on arm
+  * [Config] Temporarily disable CONFIG_MFD_OMAP_USB_HOST on arm
+  * [Config] Temporarily disable CONFIG_LIS3L02DQ on arm
+  * [Config] Temporarily disable CONFIG_USB_EHCI_HCD_PLATFORM on arm
+  * [Config] Temporarily disable CONFIG_TI_CPSW on arm
+  * [Config] Temporarily disable CONFIG_AX88796 on arm
+
+  [ Upstream Kernel Changes ]
+
+  * vfs: pass struct path to __dentry_open()
+  * vfs: add i_op->open()
+  * vfs: export do_splice_direct() to modules
+  * vfs: introduce clone_private_mount()
+  * overlay filesystem
+  * overlayfs: add statfs support
+  * overlayfs: implement show_options
+  * overlay: overlay filesystem documentation
+  * fs: limit filesystem stacking depth
+  * overlayfs: follow header cleanup
+  * overlayfs: switch from d_alloc_root() to d_make_root()
+  * overlayfs: update touch_atime() usage
+  * rebase to v3.4-rc5
+    - LP: #950490
+  * rebase to v3.4-rc4
+  * rebase to v3.4-rc3
+  * rebase to v3.4-rc2
+  * rebase to v3.4-rc1
+  * rebase to v3.3
+  * rebase to v3.3-rc7
+  * rebase to v3.3-rc6
+  * rebase to v3.3-rc5
+  * rebase to v3.3-rc4
+    - LP: #900802
+    - LP: #930842
+  * rebase to v3.3-rc3
+    - LP: #924320
+    - LP: #923316
+    - LP: #923409
+    - LP: #918254
+  * rebase to v3.3-rc2
+  * rebase to v3.3-rc1
+    - LP: #795823
+    - LP: #909419
+    - LP: #910792
+    - LP: #878701
+    - LP: #724831
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 25 Jan 2012 06:50:04 -0800
+
+linux (3.2.0-10.18) precise; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: ecryptfs: Print inode on metadata error
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "proc: enable writing to /proc/pid/mem"
+    - LP: #919115
+    - CVE-2012-0056
+  * (pre-stable) ALSA: HDA: Use LPIB position fix for Macbook Pro 7, 1
+    - LP: #909419
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 24 Jan 2012 10:15:12 +0000
+
+linux (3.2.0-10.17) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: overlayfs -- fs: limit filesystem stacking depth"
+  * Revert "SAUCE: overlayfs -- overlay: overlay filesystem documentation"
+  * Revert "SAUCE: overlayfs -- overlayfs: implement show_options"
+  * Revert "SAUCE: overlayfs -- overlayfs: add statfs support"
+  * Revert "SAUCE: overlayfs -- overlay filesystem"
+  * Revert "SAUCE: overlayfs -- vfs: introduce clone_private_mount()"
+  * Revert "SAUCE: overlayfs -- vfs: export do_splice_direct() to modules"
+  * Revert "SAUCE: overlayfs -- vfs: add i_op->open()"
+  * ensure debian/ is not excluded from git by default
+  * add new scripting to handle buglinks in rebases
+  * ubuntu: overlayfs -- overlayfs: add statfs support
+  * ubuntu: overlayfs -- overlayfs: apply device cgroup and security
+    permissions to overlay files
+    - LP: #915941, #918212
+    - CVE-2012-0055
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs -- overlayfs: implement show_options
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: dmar: disable if ricoh multifunction detected"
+  * [Config] Disable CONFIG_INTEL_IOMMU_DEFAULT_ON
+    - LP: #907377, #911236
+  * [Config] Enable CONFIG_IRQ_REMAP
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs -- vfs: pass struct path to __dentry_open()
+  * ubuntu: overlayfs -- vfs: add i_op->open()
+  * ubuntu: overlayfs -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs -- overlay filesystem
+  * ubuntu: overlayfs -- fs: limit filesystem stacking depth
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs -- overlay: overlay filesystem documentation
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) x86/PCI: amd: factor out MMCONFIG discovery
+    - LP: #647043
+  * (pre-stable) PNP: work around Dell 1536/1546 BIOS MMCONFIG bug that
+    breaks USB
+    - LP: #647043
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 16 Jan 2012 07:10:08 -0800
+
+linux (3.2.0-9.16) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] Enable numerous CONFIG_VIDEO_* cards on ARM
+  * [Config] pull ARM sound modules =m
+  * [Config] CONFIG_RTC_DRV_TEST is for testing only
+  * [Config] CONFIG_USB_DUMMY_HCD is testing only
+  * [Config] CONFIG_USB_FILE_STORAGE is deprecated
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] Temporarily disable CONFIG_CAN_TI_HECC on armel"
+  * [Config] Enable CONFIG_HW_RANDOM_PASEMI=m
+  * [Config] Enable CONFIG_MMC_TMIO=m
+  * [Config] Enable CONFIG_MTD_NAND_FSL_ELBC=m
+  * [Config] Enable CONFIG_ISI=m
+  * [Config] Enable CONFIG_MMC=y
+  * [Config] Enable CONFIG_LIRC_PARALLEL=m
+  * [Config] Enable CONFIG_MAC_EMUMOUSEBTN=m
+  * [Config] Enable CONFIG_CHR_DEV_SG=y
+  * [Config] Enable CONFIG_GPIO_PCA953X=m
+  * [Config] Enable CONFIG_GPIO_TWL4030=m
+  * [Config] Enable CONFIG_INET_DIAG=m
+  * [Config] Enable CONFIG_NLS_ISO8859_1=m
+  * [Config] Enable CONFIG_NVRAM=m
+  * [Config] Enable CONFIG_SLIP=m
+  * [Config] Enable CONFIG_PC300TOO=m
+  * [Config] Enable CONFIG_TUN=y
+  * [Config] Enable CONFIG_NET_CLS_CGROUP=m
+  * [Config] Enable CONFIG_THERMAL=y
+  * [Config] Enable CONFIG_PPP=y
+  * [Config] Enable CONFIG_PCI_STUB=m
+  * Rebase to v3.2.1
+  * [Config] Enable CONFIG_RTL8192E=m
+  * [Config] Enable CONFIG_RTS5139=m
+
+  [ Stefan Bader ]
+
+  * [Config] Make CONFIG_VIRTIO_(NET|BLK)=y
+
+  [ Upstream Kernel Changes ]
+
+  * ARM: restart: add restart hook to machine_desc record
+  * ARM: restart: allow platforms more flexibility specifying restart mode
+  * ARM: restart: move reboot failure handing into machine_restart()
+  * ARM: restart: remove argument to setup_mm_for_reboot()
+  * ARM: 7159/1: OMAP: Introduce local common.h files
+  * ARM: restart: only perform setup for restart when soft-restarting
+  * ARM: 7189/1: OMAP3: Fix build break in cpuidle34xx.c because of irq
+    function
+  * ARM: idmap: populate identity map pgd at init time using .init.text
+  * ARM: suspend: use idmap_pgd instead of suspend_pgd
+  * ARM: proc-*.S: place cpu_reset functions into .idmap.text section
+  * ARM: idmap: use idmap_pgd when setting up mm for reboot
+  * ARM: head.S: only include __turn_mmu_on in the initial identity mapping
+  * ARM: SMP: use idmap_pgd for mapping MMU enable during secondary booting
+  * ARM: 7194/1: OMAP: Fix build after a merge between v3.2-rc4 and ARM
+    restart changes
+  * ARM: lib: add call_with_stack function for safely changing stack
+  * ARM: reset: implement soft_restart for jumping to a physical address
+  * ARM: stop: execute platform callback from cpu_stop code
+  * ARM: kexec: use soft_restart for branching to the reboot buffer
+  * ARM: restart: omap: use new restart hook
+  * topdown mmap support
+    - LP: #861296
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v3.2.1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 13 Jan 2012 20:32:08 +0100
+
+linux (3.2.0-8.15) precise; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_ACPI_PROCFS
+  * Remove server from getabis
+  * Temporarily disable module check
+  * [Config] Disable CONFIG_MTD_TESTS
+  * [Config] Disable CONFIG_X86_E_POWERSAVER
+  * [Config] Set CONFIG_ARCNET=m
+  * [Config] Enable CONFIG_ATM_DUMMY=m
+  * [Config] Enable CONFIG_BLK_DEV_MD=y
+  * ubuntu: fsam7400 select CHECK_SIGNATURE and depend on X86
+  * [Config] Enable CONFIG_BLK_DEV_SD=y
+  * [Config] Enable CONFIG_BLK_DEV_SR=y
+  * [Config] Enable CONFIG_BLK_DEV_UB=m
+  * [Config] Enable CONFIG_COPS=m
+  * [Config] Enable CONFIG_DVB_USB_EC168=m
+  * [Config] Enable CONFIG_ENC28J60=m
+  * [Config] Enable CONFIG_FB_UVESA=m
+  * [Config] Enable CONFIG_FB_ATY=m
+  * [Config] Enable CONFIG_BROADCOM_PHY=y
+  * [Config] Enable CONFIG_CICADA_PHY=y
+  * [Config] Enable CONFIG_DAVICOM_PHY=y
+  * [Config] Enable CONFIG_ICPLUS_PHY=y
+  * [Config] Enable CONFIG_LSI_ET1011C_PHY=y
+  * [Config] Enable CONFIG_LXT_PHY=y
+  * [Config] Enable CONFIG_MARVELL_PHY=y
+  * [Config] Enable CONFIG_NATIONAL_PHY=y
+  * [Config] Enable CONFIG_QSEMI_PHY=y
+  * [Config] Enable CONFIG_SMSC_PHY=y
+  * [Config] Enable CONFIG_VITESSE_PHY=y
+  * Add 3w-sas to scsi-modules
+    - LP: #776542
+
+  [ Mathieu Trudel-Lapierre ]
+
+  * SAUCE: ipv6: make the net.ipv6.conf.all.use_tempaddr sysctl propagate
+    to interface settings
+
+  [ Paolo Pisati ]
+
+  * Revert "SAUCE: omap3: beagle: if rev unknown, assume xM revision C"
+    - LP: #912199
+  * Revert "SAUCE: omap3: beagle: detect new xM revision B"
+    - LP: #912199
+  * Revert "SAUCE: omap3: beaglexm: fix DVI initialization"
+    - LP: #912199
+
+  [ Upstream Kernel Changes ]
+
+  * Bluetooth: Add support for BCM20702A0 [0a5c:21e3]
+    - LP: #906832
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 06 Jan 2012 10:02:03 -0800
+
+linux (3.2.0-8.14) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_SND_USB_6FIRE
+    - LP: #912197
+  * rebase to mainline v3.2 final release
+  * updateconfigs following rebase to v3.2 final
+  * ubuntu: AUFS -- add BOM and automated update script
+  * ubuntu: AUFS -- include the aufs_types.h file in linux-libc-headers
+    - LP: #684666
+  * ubuntu: AUFS -- update aufs-update to track new locations of headers
+  * ubuntu: AUFS -- clean up the aufs updater and BOM
+  * ubuntu: AUFS -- documentation on updating aufs2
+  * ubuntu: AUFS -- aufs3-base.patch
+  * ubuntu: AUFS -- aufs3-standalone.patch
+  * ubuntu: AUFS -- fix undefined __devcgroup_inode_permission
+  * ubuntu: AUFS -- fix undefined security_path_link
+  * ubuntu: AUFS -- update to 4cf5db36bcd9748e8e7270022f295f84d1fc2245
+  * ubuntu: AUFS -- updateconfigs following update
+  * ubuntu: AUFS -- suppress benign plink warning messages
+    - LP: #621195
+  * ubuntu: AUFS -- enable in config and makefile
+  * ubuntu: AUFS -- disable in favor of overlayfs
+  * [Config] linux-virtual -- should include the extX modules
+    - LP: #912308
+
+  [ Tyler Hicks ]
+
+  * SAUCE: eCryptfs: Improve statfs reporting
+    - LP: #885744
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to upstream v3.2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 26 Dec 2011 20:24:30 -0800
+
+linux (3.2.0-7.13) precise; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to upstream 3.2-rc7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 19 Dec 2011 09:14:34 -0800
+
+linux (3.2.0-6.12) precise; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to upstream v3.2-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 16 Dec 2011 10:19:02 -0800
+
+linux (3.2.0-5.11) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * enforcer -- allow arch and flavour predicates to take lists
+  * enforcer -- simplify armel/armhf specific options
+  * enforcer -- fix incorrectly specified flavour matches
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable IRQ_REMAP
+  * [Config] Enable CONFIG_SENSORS_LM95245=m
+  * [Config] Enable CONFIG_SENSORS_MAX1668=m
+  * [Config] Enable CONFIG_SENSORS_NTC_THERMISTOR=m
+  * [Config] Enable CONFIG_SENSORS_MAX6639=m
+  * [Config] Enable CONFIG_SENSORS_MAX6642=m
+  * [Config] Enable CONFIG_SENSORS_LINEAGE=m
+  * [Config] Enable CONFIG_CRYPTO_SALSA20=m
+  * [Config] Enable CONFIG_PATA_TOSHIBA=m
+  * [Config] Enable CONFIG_POHMELFS=m
+  * [Config] Enable CONFIG_NET_PACKET_ENGINE=y
+  * [Config] Enable CONFIG_PATA_OPTI=m
+  * add overlayfs to virtual inclusion list
+    - LP: #903897
+  * add veth to virtual inclusion list
+    - LP: #903897
+  * SAUCE: resolve WARNING: at drivers/block/floppy.c:2929 do_fd_request
+
+  [ Paolo Pisati ]
+
+  * [Config] DEFAULT_MMAP_MIN_ADDR=32k on arm
+    - LP: #903346
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_LOCKUP_DETECTOR=y
+    - LP: #903615
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to upstream 55b02d2f
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 12 Dec 2011 07:08:10 -0800
+
+linux (3.2.0-4.10) precise; urgency=low
+
+  [ Kyle McMartin ]
+
+  * SAUCE: dmar: disable if ricoh multifunction detected
+    - LP: #894070
+
+  [ Seth Forshee ]
+
+  * SAUCE: dell-wmi: Demote unknown WMI event message to pr_debug
+    - LP: #581312
+
+  [ Tim Gardner ]
+
+  * Start new release, Bump ABI, rebase to 3.2-rc5
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_SENSORS_AK8975=m
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sat, 10 Dec 2011 08:57:04 -0700
+
+linux (3.2.0-3.9) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: ext4: correct partial write discard size calculation
+    - LP: #894768
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: x86, microcode, AMD: Restrict microcode reporting"
+    - LP: #892615
+
+  [ Matthew Garrett ]
+
+  * SAUCE: pci: Rework ASPM disable code
+
+  [ Upstream Kernel Changes ]
+
+  * x86: Fix boot failures on older AMD CPU's
+    - LP: #892615
+  * EHCI : Fix a regression in the ISO scheduler
+    - LP: #899165
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 05 Dec 2011 10:37:36 -0800
+
+linux (3.2.0-3.8) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * armhf -- add d-i configuration
+  * armhf -- disable ABI checks for armhf
+  * armhf -- add arch to getabis config
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 03 Dec 2011 14:22:52 +0000
+
+linux (3.2.0-3.7) precise; urgency=low
+
+  [ Stefan Bader ]
+
+  * SAUCE: x86/paravirt: PTE updates in k(un)map_atomic need to be
+    synchronous, regardless of lazy_mmu mode
+    - LP: #854050
+
+  [ Tim Gardner ]
+
+  * rebase to v3.2-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 02 Dec 2011 11:53:56 -0800
+
+linux (3.2.0-2.6) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * armhf -- fix omap flavour to build on armhf
+  * [Config] CONFIG_PATA_MACIO=y to fix MAC qemu boot
+
+  [ Borislav Petkov ]
+
+  * SAUCE: x86, microcode, AMD: Restrict microcode reporting
+    - LP: #892615
+
+  [ Colin Watson ]
+
+  * Add pata_macio to pata-modules
+
+  [ Tim Gardner ]
+
+  * [Config] Prefer crda over wireless-crda
+  * [Config] Fix virtual inclusion list.
+    - LP: #897795
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 30 Nov 2011 06:09:35 -0800
+
+linux (3.2.0-2.5) precise; urgency=low
+
+  [ Paolo Pisati ]
+
+  * [Config] PANEL_DVI=y
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 28 Nov 2011 09:13:24 -0800
+
+linux (3.2.0-2.4) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.2-rc3
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: xen: Do not use pv spinlocks on HVM"
+  * Revert "fix ERROR: __devcgroup_inode_permission undefined"
+  * Revert "olpc_dcon_xo_1_5 needs delay.h"
+  * Revert "olpc_dcon_xo_1 needs delay.h"
+  * rebase to 6fe4c6d4
+  * [Config] updateconfigs after rebase to 6fe4c6d4
+
+  [ Tim Gardner ]
+
+  * [Config] Replace wireless-crda with crda,wireless-regdb
+    - LP: #856421
+  * [Config] Relax the dependencies on crda
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) HID: bump maximum global item tag report size to 96 bytes
+    - LP: #724831
+  * Ubuntu: remove coreutils|fileutils package dependency
+    - LP: #892814
+  * iio: iio_event_getfd -- fix ev_int build failure
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v3.2-rc3
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 24 Nov 2011 16:20:45 +0000
+
+linux (3.2.0-1.3) precise; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * Ubuntu: Add ext2 to fs-core-modules
+    - LP: #893395
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 21 Nov 2011 20:42:33 -0800
+
+linux (3.2.0-1.2) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_NFC and associated devices
+  * SAUCE: allow brcmsmac and b43 to both build
+
+  [ Soren Hansen ]
+
+  * Add ixgbe driver to d-i
+    - LP: #891969
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 21 Nov 2011 08:33:46 -0800
+
+linux (3.2.0-1.1) precise; urgency=low
+  [ Andy Whitcroft ]
+
+  * armhf -- enable armhf and create the first flavours
+  * SAUCE: ensure root is ready before running usermodehelpers in it
+  * [Config] enforcer -- ensure CONFIG_FAT_FS is built-in on arm
+
+  [ Leann Ogasawara ]
+
+  * Temporarily ignore module check
+  * [Config] Enable PCI_IOV on powerpc
+  * [Config] Temporarily disable CONFIG_PASEMI_MAC on powerpc
+  * rebase to v3.2-rc2
+  * SAUCE: include <linux/export.h> for cpuidle34xx arm build
+  * SAUCE: include <linux/kernel.h> for linux/mtd/map.h arm build
+  * SAUCE: include <linux/printk.h> and <stdarg.h> for mmc_core arm build
+  * SAUCE: select ARM_AMBA if OMAP3_EMU
+  * [Config] updateconfigs after select ARM_AMBA
+  * [Config] Temporarily disable CONFIG_KVM_BOOK3S_32 on powerpc
+  * [Config] Enable CONFIG_EXT2_FS=m
+  * [Config] Build in CONFIG_SATA_AHCI=y
+  * Resolve linux-image-extra's install dependency
+
+  [ Seth Forshee ]
+
+  * [Config] Enable EVENT_POWER_TRACING_DEPRECATED=y for powertop
+  * SAUCE: (drop after 3.2) Input: ALPS - move protocol information to
+    Documentation
+  * SAUCE: (drop after 3.2) Input: ALPS - add protocol version field in
+    alps_model_info
+  * SAUCE: (drop after 3.2) Input: ALPS - remove assumptions about packet
+    size
+  * SAUCE: (drop after 3.2) Input: ALPS - add support for protocol versions
+    3 and 4
+  * SAUCE: (drop after 3.2) Input: ALPS - add semi-MT support for v3
+    protocol
+  * SAUCE: (drop after 3.2) Input: ALPS - add documentation for protocol
+    versions 3 and 4
+
+  [ Stefan Bader ]
+
+  * [Config] Built-in xen-netfront and xen-blkfront
+  * Fix build of dm-raid45 and re-enable it
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_USB_XHCI_HCD=y
+    - LP: #886167
+  * [Config] CONFIG_R6040=m
+    - LP: #650899
+  * SAUCE: Add a new entry (413c:8197) to Bluetooth USB device ID table
+    - LP: #854399
+  * [Config] Consolidated amd64 server flavour into generic
+  * [Config] updateconfigs after rebase to 3.2-rc1
+  * [Config] Disabled dm-raid4-5
+  * [Config] Disabled ndiswrapper
+  * [Config] Disable vt6656
+  * [Config] exclude ppp-modules for virtual flavour
+  * [Config] CONFIG_MEMSTICK_R592=m
+    - LP: #238208
+
+  [ Upstream Kernel Changes ]
+
+  * CHROMIUM: seccomp_filter: new mode with configurable syscall filters
+    - LP: #887780
+  * CHROMIUM: seccomp_filter: add process state reporting
+    - LP: #887780
+  * CHROMIUM: seccomp_filter: Document what seccomp_filter is and how it
+    works.
+    - LP: #887780
+  * CHROMIUM: x86: add HAVE_SECCOMP_FILTER and seccomp_execve
+    - LP: #887780
+  * CHROMIUM: arm: select HAVE_SECCOMP_FILTER
+    - LP: #887780
+  * CHROMIUM: seccomp_filters: move to btrees
+  * CHROMIUM: enable CONFIG_BTREE
+  * CHROMIUM: seccomp_filter: kill NR_syscall references
+  * CHROMIUM: seccomp_filters: guard all ftrace wrapper code
+  * CHROMIUM: seccomp_filters: clean up warnings; kref mistake
+  * CHROMIUM: seccomp_filter: remove "skip" from copy and add drop helper
+  * CHROMIUM: seccomp_filter: allow CAP_SYS_ADMIN management of execve
+  * CHROMIUM: seccomp_filter: inheritance documentation
+  * CHROMIUM: seccomp_filter: make inherited filters composable
+  * CHROMIUM: Fix seccomp_t compile error
+    - LP: #887780
+  * CHROMIUM: Fix kref usage
+    - LP: #887780
+  * CHROMIUM: enable CONFIG_SECCOMP_FILTER and CONFIG_HAVE_SECCOMP_FILTER
+  * rebase to v3.2-rc2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 31 Oct 2011 09:24:39 -0400
+
+linux (3.1.0-2.3) precise; urgency=low
+
+  [ Tim Gardner ]
+
+  * Add postinit and postrm scripts to the extras package
+    - LP: #882120
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 28 Oct 2011 12:48:33 -0700
+
+linux (3.1.0-2.2) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * debian: add locking to protect debian/files from parallel update
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.1
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 19 Oct 2011 07:12:38 -0700
+
+linux (3.1.0-1.1) precise; urgency=low
+
+  [ Andiry Xu ]
+
+  * SAUCE: (drop during 3.2 merge) xHCI: AMD isoc link TRB chain bit quirk
+    - LP: #872811
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: compcache -- follow changes to bd_claim/bd_release"
+    - LP: #832694
+  * Revert "ubuntu: compcache -- version 0.5.3"
+    - LP: #832694
+  * [Config] standardise CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+  * [Config] Enable CONFIG_MACVTAP=m
+    - LP: #822601
+  * record the compiler in the ABI and check for inconsistant builds
+  * [Config] move ECRYPT_FS back to =y for all architectures
+    - LP: #827197
+  * [Config] enable CONFIG_DRM_VMWGFX=m
+    - LP: #698009
+  * [Config] re-fix ECRYPT_FS=y
+    - LP: #827197
+  * enforcer -- ensure we have CONFIG_ECRYPT_FS=y
+    - LP: #827197
+  * [Config] dropping compcache configuration options
+  * [Config] standardise on HZ=250
+  * SAUCE: headers_install: fix #include "..." usage for userspace
+    - LP: #824377
+  * make module-inclusion selection retain the left overs
+  * add a new linux-image-extras package for virtual
+
+  [ Colin Watson ]
+
+  * Deliver more Atheros, Ralink, and iwlagn NIC drivers to d-i
+
+  [ edwin_rong ]
+
+  * SAUCE: Staging: add driver for Realtek RTS5139 cardreader
+    - LP: #824273
+
+  [ Greg Kroah-Hartman ]
+
+  * SAUCE: staging: rts5139: add vmalloc.h to some files to fix the build.
+    - LP: #824273
+
+  [ Jesse Sung ]
+
+  * SAUCE: Unregister input device only if it is registered
+    - LP: #839238
+
+  [ Jiri Kosina ]
+
+  * SAUCE: HID: add MacBookAir4, 2 to hid_have_special_driver[]
+
+  [ Joshua V. Dillon ]
+
+  * SAUCE: HID: add support for MacBookAir4,2 keyboard.
+
+  [ Kees Cook ]
+
+  * [Config] enable and enforce SECCOMP_FILTER on x86
+
+  [ Keng-Yu Lin ]
+
+  * [Config] Enable CONFIG_RTS5139=m on i386/amd64
+    - LP: #824273
+
+  [ Leann Ogasawara ]
+
+  * Revert "ubuntu: overlayfs -- ovl: make lower mount read-only"
+  * Revert "ubuntu: overlayfs -- fs: limit filesystem stacking depth"
+  * Revert "ubuntu: overlayfs -- ovl: improve stack use of lookup and
+    readdir"
+  * Revert "ubuntu: overlayfs -- ovl: fix overlayfs over overlayfs"
+  * Revert "ubuntu: overlayfs -- overlayfs: implement show_options"
+  * Revert "ubuntu: overlayfs -- overlayfs: add statfs support"
+  * Revert "ubuntu: overlayfs -- overlay filesystem"
+  * Revert "ubuntu: overlayfs -- overlay: overlay filesystem documentation"
+  * Revert "SAUCE: ARM: OMAP: Add macros for comparing silicon revision"
+  * Revert "SAUCE: OMAP: DSS2: check for both cpu type and revision, rather
+    than just revision"
+  * Revert "SAUCE: OMAP: DSS2: enable hsclk in dsi_pll_init for OMAP36XX"
+  * Revert "ubuntu: fsam7400 disable driver"
+    - LP: #876030
+  * rebase to v3.1-rc1
+  * [Config] updateconfigs after rebase to v3.1-rc1
+  * rebase to v3.1-rc2
+  * [Config] Updateconfigs after rebase to v3.1-rc2
+  * ubuntu: Yama - update calls to generic_permission() and
+    inode->i_op->permission()
+  * ubuntu: ndiswrapper -- remove netdev_priv macro
+  * ubuntu: aufs -- Temporarily disable due to build failure
+  * [Config] Diable INTEL_MID_PTI on armel
+  * [Config] Temporarily disable CONFIG_FTMAC100 on armel
+  * [Config] Temporarily disable CONFIG_FTGMAC100 on armel
+  * [Config] Temporarily disable CONFIG_CAN_TI_HECC on armel
+  * [Config] Temporarily disable CONFIG_VIDEO_OMAP2_VOUT on armel
+  * [Config] Set CONFIG_DM_MIRROR=m on amd64, i386, and arm
+  * [Config] Set CONFIG_DM_MULTIPATH=m on amd64, i386, and arm
+  * [Config] Set CONFIG_DM_SNAPSHOT=m on amd64, i386, and arm
+  * [Config] Enable CONFIG_EDAC_AMD8111=m on powerpc
+  * [Config] Enable CONFIG_EDAC_AMD8131=m on powerpc
+  * [Config] Enable CONFIG_EDAC_CPC925=m on powerpc
+  * [Config] Enable CONFIG_EDAC_PASEMI=m on powerpc
+  * [Config] Enable CONFIG_ECHO=m on powerpc
+  * [Config] Enable CONFIG_ET131X=m on powerpc
+  * [Config] Set CONFIG_FB_MATROX=m
+  * [Config] Enable CONFIG_FB_UDL=m on powerpc
+  * [Config] Set CONFIG_FB_VIRTUAL=n
+  * [Config] Enable CONFIG_FB_VGA16=m on powerpc
+  * [Config] Enable CONFIG_GPIO_MAX732X=m on arm
+  * [Config] Enable CONFIG_GPIO_PCF857X=m on arm
+  * [Config] Set CONFIG_HOTPLUG_PCI_FAKE=m
+  * [Config] Enable CONFIG_HOTPLUG_PCI=y on powerpc
+  * [Config] Enable CONFIG_HOTPLUG_PCI_CPCI=y on powerpc
+  * [Config] Enable CONFIG_HP_ILO=m on powerpc-smp
+  * [Config] Enable CONFIG_I2C_PASEMI=m on powerpc
+  * [Config] Enable CONFIG_IBM_BSR=m on powerpc
+  * [Config] Enable CONFIG_IBMVETH=m on powerpc
+  * [Config] Enable CONFIG_IDE_PHISON=m on powerpc
+  * [Config] Enable CONFIG_IGB=m on powerpc
+  * [Config] Enable CONFIG_IIO=m on powerpc
+  * [Config] Enable CONFIG_INFINIBAND_NES=m
+  * [Config] Enable CONFIG_IPMI_HANDLER=m on arm
+  * [Config] Enable CONFIG_IWL3945=m on powerpc
+  * [Config] Disable CONFIG_KVM_BOOK3S_64
+  * [Config] Enable CONFIG_LAPBETHER=m on arm
+  * [Config] Enable CONFIG_LEDS_GPIO=m on powerpc
+  * [Config] Enable CONFIG_LEDS_CLEVO_MAIL=m all arch's
+  * [Config] Enable CONFIG_LEDS_PCA9532=m on powerpc
+  * [Config] Enable CONFIG_LEDS_PCA955X=m on powerpc
+  * [Config] Enable CONFIG_LEDS_TRIGGER_DEFAULT_ON=m on powerpc
+  * [Config] Set CONFIG_LEDS_TRIGGER_HEARTBEAT=m on arm and powerpc
+  * [Config] Set CONFIG_LEDS_TRIGGER_TIMER=m on powerpc
+  * [Config] Enable CONFIG_LINE6_USB=m on arm and powerpc
+  * [Config] Enable CONFIG_MEMSTICK=m on arm
+  * [Config] Enable CONFIG_MTD_AFS_PARTS=m on arm
+  * [Config] Enable CONFIG_MTD_ALAUDA=m on arm
+  * [Config] Enable CONFIG_MTD_AR7_PARTS=m on arm
+  * [Config] Enable CONFIG_MTD_ARM_INTEGRATOR=m on arm
+  * [Config] Enable CONFIG_MOXA_SMARTIO=m on powerpc
+  * [Config] Enable CONFIG_MTD_DATAFLASH=m on arm
+  * [Config] Enable CONFIG_MTD_GPIO_ADDR=m on arm
+  * [Config] Enable CONFIG_MTD_IMPA7=m on arm
+  * [Config] Enable CONFIG_MTD_NAND_GPIO=m on arm
+  * [Config] Enable CONFIG_MTD_NAND_NANDSIM=m on arm
+  * [Config] Enable CONFIG_MTD_NAND_PASEMI=m on powerpc
+  * [Config] Enable CONFIG_MTD_NAND_PLATFORM=m on arm
+  * [Config] Enable CONFIG_MTD_NAND_TMIO=m on arm
+  * [Config] Enable CONFIG_MTD_SST25L=m on arm
+  * [Config] Enable CONFIG_NET_CLS_CGROUP=y on arm
+  * [Config] Enable CONFIG_NET_CLS_FLOW=m on arm
+  * [Config] Enable CONFIG_NET_CLS_U32=m on arm
+  * [Config] Enable CONFIG_NET_DCCPPROBE=m on arm
+  * [Config] Enable CONFIG_NET_SCH_INGRESS=m on arm
+  * [Config] Enable CONFIG_NET_TCPPROBE=m on arm
+  * [Config] Enable CONFIG_PASEMI_MAC=m on powerpc
+  * [Config] Enable CONFIG_PATA_NS87410=m on powerpc
+  * [Config] Enable CONFIG_I2C_GPIO=m on powerpc64-smp
+  * [Config] Enable CONFIG_PANEL=m on powerpc
+  * [Config] Enable CONFIG_PATA_CMD640_PCI=m on powerpc
+  * SAUCE: x86: reboot: Make Dell Latitude E6520 use reboot=pci
+    - LP: #833705
+  * [Config] Add CONFIG_EFI_VARS=y to the enforcer
+    - LP: #837332
+  * [Config] Update CONFIG_EFI_VARS enforcer check
+  * [Config] Add aufs to virtual flavor inclusion list
+    - LP: #844159
+  * SAUCE: x86: reboot: Make Dell Optiplex 790 use reboot=pci
+    - LP: #818933
+  * SAUCE: x86: reboot: Make Dell Optiplex 990 use reboot=pci
+    - LP: #768039
+  * SAUCE: x86: reboot: Make Dell Latitude E6220 use reboot=pci
+    - LP: #838402
+  * [Config] Add igbvf to the virtual flavor inclusion list
+    - LP: #794570
+  * [Config] Add ixgbevf to the virtual inclusion list
+    - LP: #872411
+  * [Config] Transition -generic and -server to be identical
+  * rebase to v3.1-rc10
+
+  [ Luke Yelavich ]
+
+  * [Config] Disable legacy IDE drivers on powerpc
+
+  [ Ming Lei ]
+
+  * SAUCE: fireware: add NO_MSI quirks for o2micro controller
+    - LP: #801719
+  * SAUCE: ata_piix: make DVD Drive recognisable on systems with Intel
+    Sandybridge chipsets(v2)
+    - LP: #737388, #782389, #794642
+
+  [ Paolo Pisati ]
+
+  * [Config] Compile-in vfat support for armel
+    - LP: #853783
+
+  [ Randy Dunlap ]
+
+  * SAUCE: staging: fix rts5139 depends & build
+    - LP: #824273
+
+  [ Rene Bolldorf ]
+
+  * SAUCE: (drop after 3.0) ideapad: Check if acpi already handle backlight
+    power in 'ideapad_backlight_notify_power' to avoid a page fault
+
+  [ Seth Forshee ]
+
+  * SAUCE: (no-up) Input: elantech - Add v3 hardware support
+    - LP: #681904
+  * SAUCE: (drop after 3.1) usb_storage: Don't freeze in usb-stor-scan
+    - LP: #810020
+
+  [ Stefan Bader ]
+
+  * (config) Package macvlan and macvtap for virtual
+  * [Config] Force perf to use libiberty for demangling
+    - LP: #783660
+  * SAUCE: xen: Do not use pv spinlocks on HVM
+    - LP: #838026
+
+  [ Tim Gardner ]
+
+  * [Config] Clean up tools rules
+  * [Config] Package x86_energy_perf_policy and turbostat
+    - LP: #797556
+  * rebase to v3.1-rc3
+  * [Config] Simplify binary-udebs dependencies
+  * [Config] kernel preparation cannot be parallelized
+  * [Config] Linearize module/abi checks
+  * [Config] Linearize and simplify tree preparation rules
+  * [Config] Build kernel image in parallel with modules
+  * [Config] Set concurrency for kmake invocations
+  * [Config] Improve install-arch-headers speed
+  * [Config] Fix binary-perarch dependencies
+  * [Config] Removed stamp-flavours target
+  * [Config] Serialize binary indep targets
+  * [Config] Use build stamp directly
+  * [Config] Restore prepare-% target
+  * rebase to v3.1-rc4
+  * rebase to v3.1-rc5
+  * [Config] Disable makedumpfile for i386/amd64
+  * rebase to v3.1-rc6
+  * [Config] Fix binary-% build target
+  * rebase to v3.1-rc7
+  * rebase to v3.1-rc8
+  * SAUCE: Add a new entry (413c:8197) to Bluetooth USB device ID table
+    - LP: #854399
+  * [Config] Enable ftrace support in the mac80211 layer
+    - LP: #865171
+  * rebase to v3.1-rc9
+  * SAUCE: usb/core/devio.c: Check for printer class specific request
+    - LP: #872711
+
+  [ Upstream Kernel Changes ]
+
+  * overlay filesystem
+  * overlayfs: add statfs support
+  * overlayfs: implement show_options
+  * overlay: overlay filesystem documentation
+  * fs: limit filesystem stacking depth
+
+  [ Will Drewry ]
+
+  * SAUCE: seccomp_filter: new mode with configurable syscall filters
+  * SAUCE: seccomp_filter: add process state reporting
+  * SAUCE: seccomp_filter: Document what seccomp_filter is and how it
+    works.
+  * SAUCE: seccomp_filter: add HAVE_SECCOMP_FILTER and seccomp_execve
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.1-rc1
+  * rebase to v3.1-rc2
+  * rebase to v3.1-rc3
+    +CONFIG_BLK_DEV_BSGLIB=y
+    +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+    -CONFIG_VIDEO_OMAP2_VOUT_VRFB=y
+  * rebase to v3.1-rc4
+  * rebase to v3.1-rc5
+  * rebase to v3.1-rc6
+  * rebase to v3.1-rc7
+  * rebase to v3.1-rc8
+  * rebase to v3.1-rc9
+  * rebase to v3.1-rc10
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 10 Aug 2011 15:43:38 -0700
+
+linux (3.1.0-1.0) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Open P-series
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 10 Aug 2011 13:42:40 -0700
+
+linux (3.0.0-8.10) oneiric; urgency=low
+
+  [ Adam Jackson ]
+
+  * SAUCE: drm/i915/pch: Fix integer math bugs in panel fitting
+    - LP: #753994
+
+  [ John Johansen ]
+
+  * [Config] Enable missing IPv6 options
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable config IWLWIFI_DEVICE_SVTOOL
+    - LP: #819925
+  * Rebase to 3.0.1
+
+  [ Upstream Kernel Changes ]
+
+  * x86, intel, power: Correct the MSR_IA32_ENERGY_PERF_BIAS message
+  * ALSA: hda - Turn on extra EAPDs on Conexant codecs
+    - LP: #783582
+  * KVM: Remove SMEP bit from CR4_RESERVED_BITS
+    - LP: #796476
+  * KVM: Add SMEP support when setting CR4
+    - LP: #796476
+  * KVM: Mask function7 ebx against host capability word9
+    - LP: #796476
+  * KVM: Add instruction fetch checking when walking guest page table
+    - LP: #796476
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.0.1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 05 Aug 2011 11:32:25 -0700
+
+linux (3.0.0-7.9) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Upstream] add local prefix to oss local change_bits"
+  * Revert "SAUCE: add tracing for user initiated readahead requests"
+  * Revert "SAUCE: vfs: Add a trace point in the mark_inode_dirty function"
+  * Revert "SAUCE: Input: ALPS - Enable Intellimouse mode for Lenovo
+    Zhaoyang E47"
+  * Revert "SAUCE: fix documentation strings for struct input_keymap_entry"
+  * Revert "SAUCE: vt -- fix handoff numbering to 1..n and add range checks
+    (grub)"
+  * Revert "SAUCE: vt -- fix handoff numbering to 1..n and add range
+    checks"
+  * Revert "SAUCE: vt -- allow grub to request automatic vt_handoff"
+  * Revert "SAUCE: vt -- maintain bootloader screen mode and content until
+    vt switch"
+  * [Config] enable CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
+    - LP: #816035
+  * ubuntu: Yama: if an underlying filesystem provides a permissions op use
+    it
+  * SAUCE: (no-up) add tracing for user initiated readahead requests
+  * SAUCE: vt -- maintain bootloader screen mode and content until vt
+    switch
+  * SAUCE: vt -- allow grub to request automatic vt_handoff
+
+  [ Arjan van de Ven ]
+
+  * SAUCE: (no-up) vfs: Add a trace point in the mark_inode_dirty function
+
+  [ Kees Cook ]
+
+  * Revert "SAUCE: (no-up) Disable building the ACPI debugfs source"
+  * [Config] enforce ACPI_CUSTOM_METHOD disabled
+
+  [ Keng-Yu Lin ]
+
+  * SAUCE: (no-up) Input: ALPS - Enable Intellimouse mode for Lenovo
+    Zhaoyang E47
+    - LP: #632884, #803005
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_BLK_DEV_CMD64X=m on powerpc
+    - LP: #513131
+  * [Config] Enable CONFIG_RT2800PCI_RT53XX=y
+    - LP: #815064
+
+  [ Rezwanul Kabir ]
+
+  * SAUCE: (no-up) Add support for Intellimouse Mode in ALPS touchpad on
+    Dell E2 series Laptops
+    - LP: #632884
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "yama: if an underlying filesystem provides a permissions op use
+    it"
+  * Revert "Add support for Intellimouse Mode in ALPS touchpad on Dell E2
+    series Laptops"
+  * Revert "tty: include linux/slab.h for kfree"
+  * Revert "gpio/ml_ioh_gpio: include linux/slab.h for kfree"
+  * Revert "pch_dma: add include/slab.h for kfree"
+  * mmc: Added quirks for Ricoh 1180:e823 lower base clock frequency
+    - LP: #773524
+  * oss: rename local change_bits to avoid powerpc bitsops.h definition
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 25 Jul 2011 09:08:01 -0700
+
+linux (3.0.0-7.8) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: overlayfs -- overlayfs: add statfs support
+  * [Config] enable CONFIG_OVERLAYFS
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs -- overlayfs: implement show_options
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_ALIM7101_WDT=m on powerpc
+  * [Config] Enable CONFIG_ASUS_OLED=m on powerpc
+  * [Config] Disable CONFIG_ATM_DUMMY on arm
+  * [Config] Enable CONFIG_BLK_DEV_DRBD=m on powerpc
+  * Temporarily disable module check on arm
+  * Rebase to 3.0 final
+  * [Config] Enable CONFIG_CAN_TI_HECC=m on arm
+  * [Config] Set CONFIG_CDROM_PKTCDVD=m on amd64 and i386
+  * [Config] Enable CONFIG_CRYPTO_CCM=m on powerpc
+  * [Config] Enable CONFIG_CRYPTO_DEV_HIFN_795X=m on powerpc
+  * [Config] Enable CONFIG_CRYPTO_GCM=m on powerpc
+  * [Config] Set CRYPTO_LZO=m on powerpc64-smp
+  * [Config] Enable CONFIG_DM9000=m on arm
+  * [Config] Set CONFIG_DISPLAY_SUPPORT=m on arm
+  * [Config] Enable CONFIG_DL2K=m on amd64 and i386
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs -- vfs: add i_op->open()
+  * ubuntu: overlayfs -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs -- overlay filesystem
+  * ubuntu: overlayfs -- ovl: fix overlayfs over overlayfs
+  * ubuntu: overlayfs -- ovl: improve stack use of lookup and readdir
+  * ubuntu: overlayfs -- fs: limit filesystem stacking depth
+  * ubuntu: overlayfs -- ovl: make lower mount read-only
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs -- overlay: overlay filesystem documentation
+
+  [ Tim Gardner ]
+
+  * [Config] Add enic/fnic to udebs
+    - LP: #801610
+
+  [ Upstream Kernel Changes ]
+
+  * yama: if an underlying filesystem provides a permissions op use it
+
+  [ Major Kernel Changes ]
+
+  * Rebase to 3.0 final
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 21 Jul 2011 07:01:32 -0700
+
+linux (3.0.0-6.7) oneiric; urgency=low
+
+  [ Eagon Yager ]
+
+  * [Config] Fix misspelled 'skipmodule' in arm makefile.
+
+  [ Keng-Yu Lin ]
+
+  * SAUCE: Input: ALPS - Enable Intellimouse mode for Lenovo Zhaoyang E47
+    - LP: #632884, #803005
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] Temporarily disable CONFIG_SMC91X on armel-omap"
+  * Revert "[Config] Temporarily Disable CONFIG_BRCMSMAC on arm"
+  * Revert "[Config] Temporarily Disable CONFIG_RTL8192SE on powerpc"
+  * Revert "[Config] Temporarily Disable CONFIG_RTL8192SE on arm"
+  * Revert "[Config] Temporarily disable CONFIG_BRCMSMAC on powerpc"
+  * [Config] Set CONFIG_ACPI_PCI_SLOT=m
+  * [Config] Set CONFIG_ACPI_SBS=m
+  * [Config] Set CONFIG_ACPI_WMI=m
+  * [Config] Set CONFIG_AD7150=m on arm
+  * [Config] Set CONFIG_AD7152=m on arm
+  * [Config] Drop CONFIG_GPIO_S5PV210
+  * [Config] Drop CONFIG_GPIO_S5PC100
+  * [Config] Drop CONFIG_GPIO_PLAT_SAMSUNG
+  * [Config] Drop CONFIG_GPIO_EXYNOS4
+
+  [ Stefan Bader ]
+
+  * SAUCE: Re-enable RODATA for i386 virtual
+    - LP: #809838
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Quirk to fix suspend/resume on Lenovo Edge 11,13,14,15"
+  * (drop after 3.0.0) acer-wmi: Add support for Aspire 1830 wlan hotkey
+    - LP: #771758
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 20 Jul 2011 06:36:02 -0700
+
+linux (3.0.0-5.6) oneiric; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_RTL8192CU=m
+  * Rebase to -rc7
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 11 Jul 2011 22:13:50 +0100
+
+linux (3.0.0-4.5) oneiric; urgency=low
+
+  [ Ming Lei ]
+
+  * SAUCE: fix yama_ptracer_del lockdep warning
+    - LP: #791019
+
+  [ Seth Forshee ]
+
+  * SAUCE: (drop after 3.0) asus-wmi: Add callback for hotkey filtering
+  * SAUCE: (drop after 3.0) eeepc-wmi: Add support for T101MT Home/Express Gate key
+  * SAUCE: (drop after 3.0) asus-wmi: Enable autorepeat for hotkey input device
+  * [Config] CONFIG_{ASUS,ASUS_NB,EEEPC}_WMI=m
+    - LP: #805218
+
+  [ Tim Gardner ]
+
+  * [Config] updateconfigs after rebase to -rc6+
+    Rebased against 4dd1b49c6d215dc41ce50c80b4868388b93f31a3
+  * Adopt a 3 digit verion, e.g., 3.0.0-x.x
+  * Revert "UBUNTU: add dependancies for module-init-tools"
+    This dependency is no longer required for a 3 digit version.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 05 Jul 2011 14:03:04 +0100
+
+linux (3.0-3.4) oneiric; urgency=low
+
+  [ Keng-Yu Lin ]
+
+  * SAUCE: Revert: "dell-laptop: Toggle the unsupported hardware
+    killswitch"
+    - LP: #775281
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc5
+  * [Config] updateconfigs after rebase to 3.0-rc5
+
+  [ Tim Gardner ]
+
+  * [Config] Remove ubuntu/rtl8192se
+  * [Config] Added armel ABI files
+  * [Config] Removed armel versatile flavour
+  * [Config] CONFIG_INTEL_MEI=m
+    - LP: #716867
+
+  [ Upstream Kernel Changes ]
+
+  * ALSA: hda - Enable auto-parser as default for Conexant codecs
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.0-rc5
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 30 Jun 2011 14:27:10 +0100
+
+linux (3.0-2.3) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- update to 0e2bafab74f0d1463383faeb93f9fc5eb8c2c54e
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc4
+  * [Config] updateconfigs after rebase to 3.0-rc4
+  * fix ERROR: __devcgroup_inode_permission undefined
+
+  [ Stefan Bader ]
+
+  * SAUCE: iscsitarget: Remove driver from the kernel
+
+  [ Tim Gardner ]
+
+  * SAUCE: rtl8192se: Force a build for a 2.6/3.0 kernel
+  * [Config] Add grub-efi as a recommended bootloader for server and
+    generic
+    - LP: #800910
+
+  [ Upstream Kernel Changes ]
+
+  * Fix node_start/end_pfn() definition for mm/page_cgroup.c
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 24 Jun 2011 11:51:12 -0700
+
+linux (3.0-1.2) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_CAN_CALC_BITTIMING
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc3
+  * [Config] updateconfigs after rebase to 3.0-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * perf: clear out make flags when calling kernel make kernelver
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc3
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 14 Jun 2011 07:25:35 -0700
+
+linux (3.0-0.1) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * use the packaging version in the kernel
+  * use the kernels idea of its version for version_signature
+  * add dependancies for module-init-tools
+  * update control files to version 3
+  * printchanges/insertchanges allow override of prev_release
+  * correct Vcs-Git: to point to oneiric
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc1
+  * [Config] updateconfigs after rebase to 3.0-rc1
+  * ubuntu: dm-raid4-5 fix up build failure
+  * [Config] Temporarily Disable CONFIG_GPIO_EXYNOS4 on arm
+  * [Config] Temporarily Disable CONFIG_GPIO_PLAT_SAMSUNG on arm
+  * [Config] Temporarily Disable CONFIG_GPIO_S5PC100 on arm
+  * [Config] Temporarily Disable CONFIG_GPIO_S5PV210 on arm
+  * [Config] Temporarily disable CONFIG_BRCMSMAC on powerpc
+  * [Config] Temporarily Disable CONFIG_BRCMSMAC on arm
+  * [Config] Temporarily Disable CONFIG_RTL8192SE on arm
+  * [Config] Temporarily Disable CONFIG_RTL8192SE on powerpc
+  * [Config] Temporarily disable CONFIG_SMC91X on armel-omap
+  * rebase to v3.0-rc2
+
+  [ Manoj Iyer ]
+
+  * SAUCE: mmc: Enable MMC card reader for RICOH [1180:e823]
+    - LP: #790754
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "x86 idle: EXPORT_SYMBOL(default_idle, pm_idle) only when APM
+    demands it"
+  * drm/i915: fix regression after clock gating init split
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39 to v3.0-rc1
+  * rebase from v3.0-rc1 to v3.0-rc2
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 09 Jun 2011 15:18:33 +0100
+
+linux (2.6.39-3.10) oneiric; urgency=low
+
+  [ Colin Ian King ]
+
+  * SAUCE: S3 early resume debug via keyboard LEDs
+
+  [ Ingo Molnar ]
+
+  * ubuntu: nx-emu - i386: NX emulation
+  * ubuntu: nx-emu - i386: mmap randomization for executable mappings
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] Disable CONFIG_FT1000 on powerpc64-smp"
+  * Revert "[Config] Disable CONFIG_DM_RAID45"
+  * [Config] enable CONFIG_BRCMFMAC=y
+  * [Config] enable CONFIG_MDIO_BITBANG=m across all arch's and flavors
+  * [Config] enable CONFIG_VIDEO_OUTPUT_CONTROL=m on armel-omap
+
+  [ Robert Nelson ]
+
+  * SAUCE: omap3: beagle: detect new xM revision B
+    - LP: #770679
+  * SAUCE: omap3: beagle: detect new xM revision C
+    - LP: #770679
+  * SAUCE: omap3: beagle: if rev unknown, assume xM revision C
+    - LP: #770679
+
+  [ Stefan Bader ]
+
+  * SAUCE: Convert dm-raid45 to new block plugging
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 23 May 2011 11:46:43 -0700
+
+linux (2.6.39-3.9) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_SCSI_LPFC_DEBUG_FS
+  * rebase to v2.6.39
+  * [Config] enable CONFIG_LLC2=m across all arch's and flavours
+  * [Config] enable CONFIG_INPUT_APANEL=m
+
+  [ Thomas Schlichter ]
+
+  * SAUCE: vesafb: mtrr module parameter is uint, not bool
+    - LP: #778043
+  * SAUCE: vesafb: enable mtrr WC by default
+    - LP: #778043
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc7 to v2.6.39
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 20 May 2011 09:52:32 +0100
+
+linux (2.6.39-2.8) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-37"
+  * Revert "ubuntu: AUFS -- aufs2-base.patch aufs2.1-37"
+  * Revert "[Config] Disable CONFIG_AUFS_FS"
+  * ubuntu: AUFS -- aufs2-base.patch aufs2.1-39
+  * ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-39
+  * ubuntu: AUFS -- update to c6b76974311efc5bf3eddf921cd015b6aae46935
+  * ubuntu: AUFS -- clean up the aufs updater and BOM
+  * ubuntu: AUFS -- documentation on updating aufs2
+
+  [ Kees Cook ]
+
+  * ubuntu: Yama - LSM hooks
+  * ubuntu: Yama - create task_free security callback
+  * ubuntu: Yama - add ptrace relationship tracking interface
+  * ubuntu: Yama - unconditionally chain to Yama LSM
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: Fix drivers/staging/easycap FTBS"
+  * Revert "[Config] Disable CONFIG_EASYCAP"
+  * ubuntu: fsam7400 disable driver
+  * ubuntu: omnibook disable driver
+  * ubuntu: rfkill disable driver
+
+  [ Tim Gardner ]
+
+  * SAUCE: Fix extra reference in fb_open()
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 16 May 2011 09:23:56 -0700
+
+linux (2.6.39-2.7) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc7
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc6 to v2.6.39-rc7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 10 May 2011 10:18:28 +0200
+
+linux (2.6.39-1.6) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc6
+  * SAUCE: [arm] fixup __aeabi_uldivmod undefined build error
+
+  [ Tim Gardner ]
+
+  * [Config] updateconfigs after rebase to 2.6.39-rc6
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc5 to v2.6.39-rc6
+    - LP: #740126
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 05 May 2011 09:46:12 -0700
+
+linux (2.6.39-0.5) oneiric; urgency=low
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: Revert "x86, hibernate: Initialize mmu_cr4_features during boot"
+    - LP: #764758
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc5
+  * [Config] updateconfigs following rebase to v2.6.39-rc5
+
+  [ Paolo Pisati ]
+
+  * [Config] s/USB_MUSB_TUSB6010/USB_MUSB_OMAP2PLUS/ on omap3 to get musb
+    - LP: #759913
+
+  [ Stefan Bader ]
+
+  * Include nls_iso8859-1 for virtual images
+    - LP: #732046
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc4 to v2.6.39-rc5
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 27 Apr 2011 06:39:42 -0700
+
+linux (2.6.39-0.4) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc4
+  * [Config] updateconfigs following rebase to v2.6.39-rc4
+  * fixup powerpc implicit declaration of function
+    'crash_kexec_wait_realmode'
+  * [Config] Disable CONFIG_FT1000 on powerpc64-smp
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_TRANSPARENT_HUGEPAGE=y
+    - LP: #769503
+  * [Config] Add cachefiles.ko to virtual flavour
+    - LP: #770430
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc3 to v2.6.39-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 19 Apr 2011 06:25:20 -0700
+
+linux (2.6.39-0.3) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc3
+  * crash_kexec_wait_realmode() undefined when !SMP
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_PM_ADVANCED_DEBUG=y for i386/amd64
+    - LP: #632327
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc2 to v2.6.39-rc3
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 12 Apr 2011 06:52:24 -0700
+
+linux (2.6.39-0.2) oneiric; urgency=low
+
+  [ Gustavo F. Padovan ]
+
+  * SAUCE: Revert "Bluetooth: Add new PID for Atheros 3011"
+    - LP: #720949
+
+  [ John Johansen ]
+
+  * AppArmor: Fix masking of capabilities in complain mode
+    - LP: #748656
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc2
+  * [Config] updateconfigs following rebase to v2.6.39-rc2
+  * hv_mouse needs delay.h
+  * olpc_dcon_xo_1 needs delay.h
+  * olpc_dcon_xo_1_5 needs delay.h
+  * Update dropped.txt for Oneiric
+
+  [ Steve Langasek ]
+
+  * [Config] Make linux-libc-dev coinstallable under multiarch
+    - LP: #750585
+
+  [ Upstream Kernel Changes ]
+
+  * x86, hibernate: Initialize mmu_cr4_features during boot
+    - LP: #752870
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc1 to v2.6.39-rc2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 06 Apr 2011 11:04:15 -0700
+
+linux (2.6.39-0.1) oneiric; urgency=low
+
+  [ Brad Figg ]
+
+  * [Config] Set CONFIG_NR_CPUS=256 for amd64 generic
+    - LP: #737124
+
+  [ Henrik Rydberg ]
+
+  * SAUCE: HID: hid-ntrig: add support for 1b96:0006 model
+  * SAUCE: HID: ntrig: fix suspend/resume on recent models
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: (drop after 2.6.39) v4l: make sure drivers supply a zeroed
+    struct v4l2_subdev
+    - LP: #745213
+
+  [ Kees Cook ]
+
+  * [Config] packaging: adjust perms on vmlinuz as well
+  * SAUCE: nx-emu: further clarify dmesg reporting
+    - LP: #745181
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc1
+  * [Config] updateconfigs following rebase to v2.6.39-rc1
+  * [Config] Disable CONFIG_DM_RAID45
+  * [Config] Disable CONFIG_SCSI_ISCSITARGET
+  * [Config] Disable CONFIG_EASYCAP
+  * [Config] Disable CONFIG_AUFS_FS
+  * update bnx2 firmware files in d-i/firmware/nic-modules
+  * xhci-pci.c resolve implicit declaration of kzalloc
+  * [Config] Enable CONFIG_DRM_PSB for only x86
+  * [Config] Enable CONFIG_RTS_PSTOR for only x86
+  * mfd/asic3: Fix typo, s/irq_data/data/
+
+  [ Luke Yelavich ]
+
+  * [Config] Disable CONFIG_CRASH_DUMP on 32-bit powerpc kernels
+    - LP: #745358
+  * [Config] Disable CONFIG_DRM_RADEON_KMS on powerpc kernels
+  * [Config] Build some framebuffer drivers as modules for powerpc kernels.
+
+  [ Manoj Iyer ]
+
+  * SAUCE: thinkpad-acpi: module autoloading for newer Lenovo ThinkPads.
+    - LP: #745217
+
+  [ Tim Gardner ]
+
+  * SAUCE: INR_OPEN=4096
+    - LP: #663090
+  * SAUCE: Increase the default hard limit for open FDs to 4096
+    - LP: #663090
+
+  [ Upstream Kernel Changes ]
+
+  * (drop after 2.6.39-rc1) arm: versatile : Fix typo introduced in irq
+    namespace cleanup
+  * (drop after 2.6.39-rc1) [media] staging: altera-jtag needs delay.h
+  * ALSA: pcm: fix infinite loop in snd_pcm_update_hw_ptr0()
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38 to v2.6.39-rc1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 31 Mar 2011 12:50:10 -0700
+
+linux (2.6.39-0.0) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Open Oneiric 
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 31 Mar 2011 12:29:23 -0700
+
+linux (2.6.38-7.39) natty; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No change upload.  This is just to rebuild with gcc-4.5.2-7ubuntu1.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 24 Mar 2011 09:27:45 -0700
+
+linux (2.6.38-7.38) natty; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No change upload take 2.  2.6.38-7.37 was accidentally uploaded before
+    gcc-4.5.2-6ubuntu5 finished building on all arches.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 22 Mar 2011 06:12:47 -0700
+
+linux (2.6.38-7.37) natty; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No change upload.  This is just to rebuild with gcc-4.5.2-6ubuntu5.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sun, 20 Mar 2011 16:02:48 -0700
+
+linux (2.6.38-7.36) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: KLUDGE: work around failed 'shrink-wrap' compiler
+    optimisation"
+  * purge last vestiges of maverick
+  * [Config] switch CONFIG_FB_VESA back to module
+
+  [ Chris Wilson ]
+
+  * SAUCE: drm/i915: Fix pipelined fencing
+    - LP: #717114
+
+  [ Loïc Minier ]
+
+  * Include nls_cp437 module in virtual for fat
+    - LP: #732046
+  * Support arch= cross-compilation for any arch
+  * Fix couple of typos in 0-common-vars.mk
+  * Enforce DEFAULT_MMAP_MIN_ADDR on armhf
+  * Add armhf to Debian -> Linux arch map
+  * Add initial armhf.mk
+  * Enable common packages for armhf
+
+  [ Upstream Kernel Changes ]
+
+  * Yama: fix default relationship to check thread group
+    - LP: #737676
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 18 Mar 2011 18:18:02 +0000
+
+linux (2.6.38-7.35) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to 2fbfac4e053861925fa3fffcdc327649b09af54c
+  * rebase fixes bug #715330
+  * [Config] disable CONFIG_SCSI_QLA_ISCSI for powerpc 32bit to fix FTBS
+  * rebase to v2.6.38 final
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: Apply OPTION_BLACKLIST_SENDSETUP also for ZTE MF626
+    - LP: #636091
+
+  [ Tim Gardner ]
+
+  * [Confg] CONFIG_BOOT_PRINTK_DELAY=y
+
+  [ Upstream Kernel Changes ]
+
+  * Yama: use thread group leader when creating match
+    - LP: #729839
+  * (drop after 2.6.38) ahci: AHCI mode SATA patch for Intel Patsburg SATA
+    RAID controller
+    - LP: #735240
+  * (drop after v2.6.38) x86, quirk: Fix SB600 revision check
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc8 to v2.6.38 final
+    - LP: #715330
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 15 Mar 2011 19:04:19 +0000
+
+linux (2.6.38-6.34) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] normalise CONFIG_INTEL_TXT
+  * SAUCE: KLUDGE: work around failed 'shrink-wrap' compiler optimisation
+    - LP: #730860
+  * rebase to mainline v2.6.38-rc8
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc7 + fb62c00a6d8942775abc23d1621db1252e2d93d1
+    to v2.6.38-rc8
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 08 Mar 2011 11:54:48 +0000
+
+linux (2.6.38-6.33) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * d-i -- enable speakup-modules udeb
+    - LP: #672699
+  * rebase to 493f3358cb289ccf716c5a14fa5bb52ab75943e5
+  * [Config] debian PPC64 configuration
+  * [Config] cleanup powerpc config fixing unexpected inconsistancies
+  * [Config] resync ppc64 configuration
+  * SAUCE: match up ENTRY/END naming for 32/64 bit
+  * rebase to fb62c00a6d8942775abc23d1621db1252e2d93d1
+  * [Config] update configs after rebase to
+    fb62c00a6d8942775abc23d1621db1252e2d93d1
+  * [Config] pps_gen_parport no longer built
+
+  [ Corentin Chary ]
+
+  * SAUCE: (drop after 2.6.38) eeepc-wmi: reorder keymap
+    - LP: #689393
+  * SAUCE: (drop after 2.6.38) eeepc-wmi: add wlan key found on 1015P
+    - LP: #689393
+
+  [ John Johansen ]
+
+  * SAUCE: Fix aufs calling of security_path_mknod
+    - LP: #724456
+
+  [ Kees Cook ]
+
+  * SAUCE: proc: hide kernel addresses via %pK in /proc/<pid>/stack
+
+  [ Tim Gardner ]
+
+  * rebase to 2.6.38-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "drm/i915: fix corruptions on i8xx due to relaxed fencing"
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc6 to v2.6.38-rc7 +
+    fb62c00a6d8942775abc23d1621db1252e2d93d1
+    - LP: #721389
+    - LP: #722925
+    - LP: #723672
+    - LP: #723676
+    - LP: #715318
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 07 Mar 2011 15:33:17 +0000
+
+linux (2.6.38-5.32) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to mainline 6f576d57f1fa0d6026b495d8746d56d949989161
+  * [Config] updateconfigs following rebase to v2.6.38-rc6
+  * [Config] enable CONFIG_DMAR
+    - LP: #552311
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915: skip FDI & PCH enabling for DP_A
+    - LP: #561802, #600453, #681877
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc5 to v2.6.38-rc6
+    - LP: #718402
+    - LP: #719524
+    - LP: #721126
+    - LP: #719691
+    - LP: #722689
+    - LP: #722310
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 22 Feb 2011 13:28:39 +0000
+
+linux (2.6.38-4.31) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * add in bugs closed by upstream patches pulled in by rebases
+  * rebase to 795abaf1e4e188c4171e3cd3dbb11a9fcacaf505
+  * [Config] enable CONFIG_VSX to allow use of vector instuctions
+  * resync with maverick 98defa1c5773a3d7e4c524967eb01d5bae035816
+  * rebase to mainline v2.6.38-rc5
+  * SAUCE: ecryptfs: read on a directory should return EISDIR if not
+    supported
+    - LP: #719691
+
+  [ Colin Ian King ]
+
+  * SAUCE: Dell All-In-One: Remove need for Dell module alias
+
+  [ Manoj Iyer ]
+
+  * SAUCE: (drop after 2.6.38) add ricoh 0xe823 pci id.
+    - LP: #717435
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_CRYPTO_CRC32C_INTEL=y
+
+  [ Upstream Kernel Changes ]
+
+  * Quirk to fix suspend/resume on Lenovo Edge 11,13,14,15
+    - LP: #702434
+  * vfs: fix BUG_ON() in fs/namei.c:1461
+
+  [ Vladislav P ]
+
+  * SAUCE: Release BTM while sleeping to avoid deadlock.
+    - LP: #713837
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc4 to v2.6.38-rc5
+    - LP: #579276
+    - LP: #715877
+    - LP: #713769
+    - LP: #716811
+  * resync with Maverick Ubuntu-2.6.35-27.47
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 11 Feb 2011 17:24:09 +0000
+
+linux (2.6.38-3.30) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.38-rc4
+  * ppc64 -- add basic architecture
+  * ubuntu: AUFS -- update to 65835da20b77c98fb538c9114fc31f5de1328230
+
+  [ Colin Ian King ]
+
+  * SAUCE: Add WMI hotkeys support for Dell All-In-One series
+    - LP: #676997
+  * SAUCE: Add WMI hotkeys support for another Dell All-In-One series
+    - LP: #701530
+  * SAUCE: Dell WMI: Use sparse keymaps and tidy up code.
+    - LP: #701530
+
+  [ Dan Rosenberg ]
+
+  * SAUCE: (drop after 2.6.38) Convert net %p usage %pK
+
+  [ Kees Cook ]
+
+  * Revert "SAUCE: kernel: make /proc/kallsyms mode 400 to reduce ease of
+    attacking"
+  * SAUCE: (drop after 2.6.38) use %pK for /proc/kallsyms and /proc/modules
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_BLK_CGROUP=y
+    - LP: #706394
+  * [Config] CONFIG_DELL_WMI_AIO=m
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915/lvds: Restore dithering on native modes for gen2/3
+    - LP: #711568
+
+  [ Upstream Kernel Changes ]
+
+  * rebase from v2.6.38-rc3 to v2.6.38-rc4.
+    - LP: #701271
+    - LP: #708521
+    - LP: #710371
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 08 Feb 2011 02:07:18 +0000
+
+linux (2.6.38-2.29) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to 1f0324caefd39985e9fe052fac97da31694db31e
+  * [Config] updateconfigs following rebase to
+    1f0324caefd39985e9fe052fac97da31694db31e
+  * rebase to 70d1f365568e0cdbc9f4ab92428e1830fdb09ab0
+  * [Config] reenable HIBERNATE
+    - LP: #710877
+  * rebase to v2.6.38-rc3
+  * [Config] reenable CONFIG_CRASH_DUMP
+
+  [ Kamal Mostafa ]
+
+  * SAUCE: rtl8192se: fix source file perms
+  * SAUCE: rtl8192se: fix source file newline
+  * SAUCE: omnibook: fix source file newline
+
+  [ Kees Cook ]
+
+  * [Config] packaging: really make System.map mode 0600
+
+  [ Ricardo Salveti de Araujo ]
+
+  * SAUCE: OMAP3630: PM: don't warn the user with a trace in case of
+    PM34XX_ERRATUM
+
+  [ Soren Hansen ]
+
+  * SAUCE: nbd: Remove module-level ioctl mutex
+
+  [ Tim Gardner ]
+
+  * SAUCE: Disable building the ACPI debugfs source
+
+  [ Upstream Kernel Changes ]
+
+  * Set physical start and alignment 1M for virtual i386
+    - LP: #710754
+
+  [ Upstream Kernel Changes ]
+
+  * rebase from v2.6.38-rc2 + c723fdab8aa728dc2bf0da6a0de8bb9c3f588d84
+    to v2.6.38-rc3
+    - LP: #707902
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 28 Jan 2011 16:30:32 +0000
+
+linux (2.6.38-1.28) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- update to b1cee06249dfa0ab30951e7f06490a75c155b620
+
+  [ Ricardo Salveti de Araujo ]
+
+  * SAUCE: omap3: beaglexm: fix DVI initialization
+  * [Config] omap: move CONFIG_PANEL_GENERIC_DPI to build in to make
+    display work at Beagle
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 28 Jan 2011 10:51:57 +0000
+
+linux (2.6.38-1.27) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- update aufs-update to track new locations of headers
+  * ubuntu: AUFS -- update to c5021514085a5d96364e096dbd34cadb2251abfd
+  * SAUCE: ensure root is ready before running usermodehelpers in it
+  * correct the Vcs linkage to point to natty
+  * rebase to linux tip e78bf5e6cbe837daa6ab628a5f679548742994d3
+  * [Config] update configs following rebase
+    e78bf5e6cbe837daa6ab628a5f679548742994d3
+  * SAUCE: Yama: follow changes to generic_permission
+  * ubuntu: compcache -- follow changes to bd_claim/bd_release
+  * ubuntu: iscsitarget -- follow changes to open_bdev_exclusive
+  * ubuntu: ndiswrapper -- fix interaction between __packed and packed
+  * ubuntu: AUFS -- update to 806051bcbeec27748aae2b7957726a4e63ff308e
+  * update package version to match payload version
+  * rebase to e6f597a1425b5af64917be3448b29e2d5a585ac8
+  * rebase to v2.6.38-rc1
+  * [Config] updateconfigs following rebase to v2.6.38-rc1
+  * SAUCE: x86 fix up jiffies/jiffies_64 handling
+  * rebase to linus tip 2b1caf6ed7b888c95a1909d343799672731651a5
+  * [Config] updateconfigs following rebase to
+    2b1caf6ed7b888c95a1909d343799672731651a5
+  * [Config] disable CONFIG_TRANSPARENT_HUGEPAGE to fix i386 boot crashes
+  * ubuntu: AUFS -- suppress benign plink warning messages
+    - LP: #621195
+  * [Config] CONFIG_NR_CPUS=256 for amd64 -server flavour
+  * rebase to v2.6.38-rc2
+  * rebase to mainline d315777b32a4696feb86f2a0c9e9f39c94683649
+  * rebase to c723fdab8aa728dc2bf0da6a0de8bb9c3f588d84
+  * [Config] update configs following rebase to
+    c723fdab8aa728dc2bf0da6a0de8bb9c3f588d84
+  * [Config] disable CONFIG_AD7152 to fix FTBS on armel versatile
+  * [Config] disable CONFIG_AD7150 to fix FTBS on armel versatile
+  * [Config] disable CONFIG_RTL8192CE to fix FTBS on armel omap
+  * [Config] disable CONFIG_MANTIS_CORE to fix FTBS on armel versatile
+
+  [ Kees Cook ]
+
+  * SAUCE: kernel: make /proc/kallsyms mode 400 to reduce ease of attacking
+
+  [ Stefan Bader ]
+
+  * Temporarily disable RODATA for virtual i386
+    - LP: #699828
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NLS_DEFAULT=utf8
+    - LP: #683690
+  * [Config] CONFIG_HIBERNATION=n
+  * update bnx2 firmware files in d-i/firmware/nic-modules
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "drm/radeon/bo: add some fallback placements for VRAM only
+    objects."
+  * packaging: make System.map mode 0600
+  * thinkpad_acpi: Always report scancodes for hotkeys
+    - LP: #702407
+  * sched: tg->se->load should be initialised to tg->shares
+  * Input: sysrq -- ensure sysrq_enabled and __sysrq_enabled are consistent
+  * brcm80211: include linux/slab.h for kfree
+  * pch_dma: add include/slab.h for kfree
+  * i2c-eg20t: include linux/slab.h for kfree
+  * gpio/ml_ioh_gpio: include linux/slab.h for kfree
+  * tty: include linux/slab.h for kfree
+  * winbond: include linux/delay.h for mdelay et al
+
+  [ Upstream Kernel Changes ]
+
+  * mark the start of v2.6.38 versioning
+  * rebase v2.6.37 to v2.6.38-rc2 + c723fdab8aa728dc2bf0da6a0de8bb9c3f588d84
+    - LP: #689886
+    - LP: #702125
+    - LP: #608775
+    - LP: #215802
+    - LP: #686333
+    - LP: #677830
+    - LP: #677652
+    - LP: #696493
+    - LP: #697240
+    - LP: #689036
+    - LP: #705323
+    - LP: #686692
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 09 Jan 2011 13:44:52 +0000
+
+linux (2.6.37-12.26) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.37-rc8
+  * [Config] armel -- reenable omap flavour
+  * [Config] disable CONFIG_MACH_OMAP3517EVM to fix FTBS on armel omap
+  * [Config] disable CONFIG_GPIO_VX855 to fix FTBS on omap armel
+  * [Config] disable CONFIG_WESTBRIDGE_ASTORIA to fix FTBS on omap armel
+  * [Config] disable CONFIG_TI_DAVINCI_EMAC to fix FTBS on omap armel
+  * rebase to mainline 989d873fc5b6a96695b97738dea8d9f02a60f8ab
+  * [Config] track missing modules
+  * rebase to v2.6.37 final
+
+  [ Chase Douglas ]
+
+  * SAUCE: (drop after 2.6.37) HID: magicmouse: Don't report REL_{X, Y} for
+    Magic Trackpad
+
+  [ Stefan Bader ]
+
+  * Revert "SAUCE: blkfront: default to sd devices"
+    - LP: #684875
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: (no-up) libata: Ignore HPA by default."
+    - LP: #380138
+  * [Config] Added autofs4.ko to -virtual flavour
+    - LP: #692917
+
+  [ Upstream Kernel Changes ]
+
+  * Add support for Intellimouse Mode in ALPS touchpad on Dell E2 series
+    Laptops
+    - LP: #632884
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.37-rc8
+  * rebase to mainline 989d873fc5b6a96695b97738dea8d9f02a60f8ab
+  * rebase to v2.6.37 final
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 23 Dec 2010 18:34:13 +0000
+
+linux (2.6.37-11.25) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] d-i -- add hpsa to the list of block devices
+    - LP: #684304
+  * [Config] add vmw-balloon driver to -virtual flavour
+    - LP: #592039
+  * rebase to v2.6.37-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.37-rc7
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 21 Dec 2010 13:35:28 +0000
+
+linux (2.6.37-10.24) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.37-rc6
+  * updateconfigs following rebase to v2.6.37-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.37-rc6
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 16 Dec 2010 12:34:19 +0000
+
+linux (2.6.37-9.23) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: vt -- fix handoff numbering to 1..n and add range checks
+    - LP: #689606
+  * SAUCE: vt -- fix handoff numbering to 1..n and add range checks (grub)
+    - LP: #689606
+
+  [ Kees Cook ]
+
+  * SAUCE: RO/NX protection for loadable kernel, fix ftrace
+    - LP: #690190
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 15 Dec 2010 19:29:57 +0000
+
+linux (2.6.37-9.22) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.35-rc5
+  * [Config] updateconfigs following rebase to v2.6.37-rc5
+  * (no-up) add support for installed header files to ubuntu directory
+    - LP: #684666
+  * ubuntu: AUFS -- include the aufs_types.h file in linux-libc-headers
+    - LP: #684666
+  * ubuntu: dm-raid4-5 -- follow changes to bio flags
+  * ubuntu: dm-raid4-5 -- re-enable
+  * ubuntu: omnibook -- update BOM
+  * ubuntu: ndiswrapper -- update BOM to match actual version
+  * ubuntu: ndiswrapper -- follow removal of the BKL and locked ioctl
+  * ubuntu: ndiswrapper -- re-enable
+  * ubuntu: iscsitarget -- re-instate copy_io_context
+  * ubuntu: iscsitarget -- follow changes to semaphore initialisation
+  * ubuntu: iscsitarget -- convert NIPQUAD to %pI4
+  * ubuntu: iscsitarget -- re-enable
+
+  [ Kees Cook ]
+
+  * [Config] update config for CONFIG_DEBUG_SET_MODULE_RONX
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Enable jack sense for Thinkpad Edge 13
+    - LP: #685015
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_9P_FSCACHE=y,CONFIG_9P_FS_POSIX_ACL=y
+  * [Config] CONFIG_CRYPTO_CRC32C=y
+    - LP: #681819
+  * [Config] CONFIG_9P_FSCACHE=n
+  * [Config] Add nfsd modules to -virtual flavour
+    - LP: #688070
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Staging: zram: work around oops due to startup ordering snafu"
+  * NFS: Fix panic after nfs_umount()
+    - LP: #683938
+  * x86: Add NX protection for kernel data
+  * x86: Add RO/NX protection for loadable kernel modules
+  * x86: Resume trampoline must be executable
+  * x86: RO/NX protection for loadable kernel, jump_table fix
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.37-rc5
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 09 Dec 2010 18:15:35 +0000
+
+linux (2.6.37-8.21) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- include the aufs_types.h file in
+    linux-libc-headers"
+  * Revert "(no-up) add support for installed header files to ubuntu
+    directory"
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 05 Dec 2010 17:33:28 +0000
+
+linux (2.6.37-8.20) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Upstream] drivers/serial/mfd.c: Fix ARM compile error"
+  * Revert "SAUCE: Nouveau: Disable acceleration on MacBook Pros"
+  * Revert "SAUCE: Nouveau: Add quirk framework to disable acceleration"
+  * Revert "SAUCE: i915 -- disable powersave by default"
+  * SAUCE: enable Marvell 9128 PCIe SATA controller
+    - LP: #658521
+  * [Config] evtchn has been renamed
+  * (no-up) add support for installed header files to ubuntu directory
+    - LP: #684666
+  * ubuntu: AUFS -- include the aufs_types.h file in linux-libc-headers
+    - LP: #684666
+
+  [ Tim Gardner ]
+
+  * [Config] MISS: evtchn, NEW : xen-evtchn
+  * rebase to v2.6.37-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915: Clean conflicting modesetting registers upon init
+    - LP: #683775
+  * rebase to v2.6.37-rc4
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 03 Dec 2010 18:42:07 +0000
+
+linux (2.6.37-7.19) natty; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Add bnx2 firmware to nic-modules udeb
+    - LP: #676245
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 26 Nov 2010 17:53:45 +0000
+
+linux (2.6.37-7.18) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Upstream] USB: option: Remove duplicate AMOI_VENDOR_ID"
+  * Revert "SAUCE: Add extra headers to linux-libc-dev"
+  * Revert "SAUCE: Enable speedstep for sonoma processors."
+  * [Config] enable CONFIG_BT_HCIUART_ATH3K
+  * [Config] enable CONFIG_IWLWIFI_DEBUGFS
+  * [Config] standardise CONFIG_MII
+  * [Config] standardise CONFIG_PRISM2_USB
+  * [Config] standardise CONFIG_SCSI_QLA_ISCSI
+  * [Config] build in CONFIG_AGP
+  * [Config] build in CONFIG_AGP_INTEL
+  * [Config] build in CONFIG_AGP_AMD
+  * [Config] build in CONFIG_AGP_AMD64
+  * [Config] build in CONFIG_AGP_NVIDIA
+  * [Config] build in CONFIG_AGP_VIA
+  * [Config] disable CONFIG_SCSI_QLA_ISCSI for FTBS (arm)
+  * (no-up): document the new ## scheme
+  * [Config] harmonise CONFIG_SERIAL_8250_NR_UARTS
+  * [Config] update CONFIG_SERIAL_8250_RUNTIME_UARTS=32
+    - LP: #675453
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: ARM: Adding vdd_sdi regulator supply to OMAP3EVM
+
+  [ Upstream Kernel Changes ]
+
+  * nx-emu: fix inverted report of disable_nx
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 23 Nov 2010 21:00:39 +0000
+
+linux (2.6.37-6.17) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- aufs2-standalone.patch
+    aufs2.1-36-UNRELEASED-20101103"
+  * Revert "ubuntu: AUFS -- aufs2-base.patch
+    aufs2.1-36-UNRELEASED-20101103"
+  * [Config] standardise CONFIG_BT
+  * [Config] standardise CONFIG_IRDA
+  * [Config] standardise CONFIG_LAPB
+  * [Config] standardise CONFIG_RDS
+  * [Config] standardise CONFIG_RFKILL
+  * [Config] standardise CONFIG_TIPC
+  * [Config] standardise CONFIG_X25
+  * [Config] standardise CONFIG_INPUT_EVDEV
+  * [Config] standardise CONFIG_INPUT_JOYDEV
+  * [Config] standardise CONFIG_INPUT_JOYSTICK
+  * [Config] standardise CONFIG_INPUT_TOUCHSCREEN
+  * [Config] CONFIG_INPUT_TOUCHSCREEN=n for FTBS (arm)
+  * [Config] CONFIG_IRDA=n for FTBS (arm)
+  * ubuntu: AUFS -- aufs2-base.patch aufs2.1-37
+  * ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-37
+  * ubuntu: AUFS -- update to 097bf62d6f49619359d34bf17f242df38562489a
+
+  [ Tim Gardner ]
+
+  * SAUCE: Fix drivers/staging/easycap FTBS
+  * [Config] CONFIG_EASYCAP=m after fixing FTBS
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "x86: Add NX protection for kernel data"
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 22 Nov 2010 18:09:10 +0000
+
+linux (2.6.37-6.16) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] update config for CONFIG_DEBUG_SET_MODULE_RONX"
+  * rebase to v2.6.37-rc3
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_SCHED_AUTOGROUP=y
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "x86: Add RO/NX protection for loadable kernel modules"
+  * sched: automated per session task groups
+  * rebase to v2.6.37-rc3
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 22 Nov 2010 10:11:13 +0000
+
+linux (2.6.37-6.15) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] standardise CONFIG_CEPH_FS
+  * [Config] standardise CONFIG_SCSI_LPFC_DEBUG_FS
+  * [Config] standardise CONFIG_SCSI_PROC_FS
+  * [Config] standardise CONFIG_UBIFS_FS
+  * [Config] standardise CONFIG_USB_GADGET_DEBUG_FS
+
+  [ Kees Cook ]
+
+  * [Config] update config for CONFIG_DEBUG_SET_MODULE_RONX
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Enable jack sense for Thinkpad Edge 11
+    - LP: #677210
+  * SAUCE: enable rfkill for rtl8192se driver
+    - LP: #640992
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_EASYCAP=n for FTBS
+  * Rebase to v2.6.32-rc2+git
+
+  [ Upstream Kernel Changes ]
+
+  * x86: Fix improper large page preservation
+  * x86: Add NX protection for kernel data
+  * x86: Add RO/NX protection for loadable kernel modules
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to Linus 2.6.37-rc2+git
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 20 Nov 2010 11:40:00 +0000
+
+linux (2.6.37-5.14) natty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * PCI: fix offset check for sysfs mmapped files
+    - LP: #676963
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 18 Nov 2010 18:12:27 +0000
+
+linux (2.6.37-5.13) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebased to v2.6.37-rc2
+  * updateconfigs following rebase to v2.6.37-rc2
+
+  [ Tim Gardner ]
+
+  * [Config] Added NFS and related modules to virtual flavour
+    - LP: #659084
+
+  [ Upstream Kernel Changes ]
+
+  * x86, cpu: Rename verify_cpu_64.S to verify_cpu.S
+  * x86, cpu: Clear XD_DISABLED flag on Intel to regain NX
+  * x86, cpu: Call verify_cpu during 32bit CPU startup
+  * x86, cpu: Only CPU features determine NX capabilities
+
+  [ Upstream Changes ]
+
+  * rebased to v2.67.37-rc2
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 16 Nov 2010 13:13:29 +0000
+
+linux (2.6.37-4.12) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Upstream] HID: magicmouse: add param for scroll speed"
+  * Revert "[Upstream] HID: magicmouse: properly account for scroll
+    movement in state"
+  * Revert "[Upstream] HID: magicmouse: disable and add module param for
+    scroll acceleration"
+  * Revert "[Upstream] HID: magicmouse: scroll on entire surface, not just
+    middle of mouse"
+
+  [ Henrik Rydberg ]
+
+  * SAUCE: hid: ntrig: remove sysfs nodes
+  * SAUCE: hid: ntrig: Setup input filtering manually
+  * SAUCE: hid: ntrig: New ghost-filtering event logic
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Added quirk to recognize GE0301 3G modem as an interface.
+    - LP: #348861
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "mmc: fix all hangs related to mmc/sd card insert/removal during
+    suspend/resume"
+  * Revert "[ARM] implement arch_randomize_brk()"
+  * Revert "ARM: stack protector: change the canary value per task"
+  * Revert "ARM: initial stack protector (-fstack-protector) support"
+  * Revert "ALSA: hda - Handle pin NID 0x1a on ALC259/269"
+  * Revert "ALSA: hda - Handle missing NID 0x1b on ALC259 codec"
+  * Revert "perf probe: Add kernel source path option"
+  * hid: ntrig: Support single-touch devices
+  * hid: ntrig: Mask pen switch events
+  * net: rtnetlink.h -- only include linux/netdevice.h when used by the
+    kernel
+    - LP: #673073
+  * Fix userspace build of linux/fs.h
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 15 Nov 2010 19:31:44 +0000
+
+linux (2.6.37-3.11) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- update to
+    b37c575759dc4535ccc03241c584ad5fe69e3b25"
+  * Revert "ubuntu: AUFS -- track changes to the arguements to fop fsync()"
+  * Revert "ubuntu: AUFS -- update to standalone 2.6.35-rcN as at 20100601"
+  * Revert "ubuntu: AUFS -- update to standalone 2.6.34 as at 20100601"
+  * Revert "ubuntu: AUFS -- aufs2 base patch for linux-2.6.34"
+  * [Config] Disable intel_idle for -virtual kernels
+    - LP: #651370
+  * [Config] enforcer -- ensure we never enable CONFIG_IMA
+  * debian -- pass the correct flavour name when checking configs
+  * [Config] enforcer -- ensure CONFIG_INTEL_IDLE is off for -virtual
+  * [Config] ensure CONFIG_IPV6=y for powerpc
+  * [Config] enforcer -- ensure CONFIG_IPV6=y
+  * ubuntu: AUFS -- aufs2-base.patch aufs2.1-36-UNRELEASED-20101103
+  * ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-36-UNRELEASED-20101103
+  * ubuntu: AUFS -- update to aufs2.1-36-UNRELEASED-20101103
+  * ubuntu: AUFS -- re-enable
+  * ubuntu: AUFS -- track changes to work queue initialisation
+  * ubuntu: AUFS -- track changes to llseek in v2.6.37-rc1
+  * SAUCE: fbcon -- fix race between open and removal of framebuffers
+  * SAUCE: fbcon -- fix OOPs triggered by race prevention fixes
+    - LP: #614008
+  * SAUCE: drm -- stop early access to drm devices
+
+  [ Jeremy Kerr ]
+
+  * [Config] Build-in powermac ZILOG serial driver
+    - LP: #673346
+
+  [ Kees Cook ]
+
+  * SAUCE: nx-emu: use upstream ASLR when possible
+
+  [ Tim Gardner ]
+
+  * [Config] Use correct be2iscsi module name in d-i/modules/scsi-modules
+    - LP: #628776
+
+  [ Upstream Kernel Changes ]
+
+  * i386: NX emulation
+  * nx-emu: drop exec-shield sysctl, merge with disable_nx
+  * nx-emu: standardize boottime message prefix
+  * mmap randomization for executable mappings on 32-bit
+  * exec-randomization: brk away from exec rand area
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 11 Nov 2010 23:46:37 +0000
+
+linux (2.6.37-2.10) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * reinstate armel config changes:
+   * [Config] CONFIG_GPIO_PCH=n for armel FTBS
+   * [Config] CONFIG_GPIO_VX855=n for armel FTBS
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 03 Nov 2010 22:20:35 +0000
+
+linux (2.6.37-2.9) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * config -- fix genportsconfig
+  * [Config] move powerpc over from ports to distro
+  * bump master version number to match contained kernel
+  * SAUCE: fix documentation strings for struct input_keymap_entry
+  * usb: gadget: goku_udc: add registered flag bit
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 02 Nov 2010 15:14:11 +0000
+
+linux (2.6.36-2.8) natty; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config]: fix changed CONFIG_SYSFS_DEPRECATED_V2 enforcement rules
+  * [Config]: TWL4030_CORE=n for FTBS
+  * [Config]: CONFIG_ATH6K_LEGACY=n for FTBS
+  * [Config]: CONFIG_SOLO6X10=n for FTBS
+  * [Config]: CONFIG_GPIO_PCH=n for armel FTBS
+  * [Config]: CONFIG_GPIO_VX855=n for armel FTBS
+  * [Config]: CONFIG_DRM_NOUVEAU=n for armel FTBS
+  * [Config]: CONFIG_LINE6_USB=n for armel FTBS
+  * [Config]: CONFIG_SENSORS_AK8975=n for armel FTBS
+  * [Config]: CONFIG_I2C_I801=n for armel FTBS
+  * UBUNTU: SAUCE: AppArmor: Fix unpack of network tables.
+  * AppArmor: compatibility patch for v5 interface
+  * AppArmor: compatibility patch for v5 network controll
+  * Dropped (pre-stable): input: Support Clickpad devices in ClickZone mode
+  * Dropped: UBUNTU: SAUCE: libata: Add ALPM power state accounting to the AHCI driver
+  * Dropped: UBUNTU: SAUCE: Added quirk to recognize GE0301 3G modem as an interface.
+  * Dropped: hid: 3m: Convert to MT slots
+  * Dropped: HID: magicmouse: don't allow hidinput to initialize the device
+  * Dropped: HID: magicmouse: simplify touch data bit manipulation
+  * Dropped: HID: magicmouse: simplify touch down logic
+  * Dropped: HID: magicmouse: enable Magic Trackpad support
+  * Dropped: UBUNTU: SAUCE: hid: ntrig: remove sysfs nodes
+  * Dropped: UBUNTU: SAUCE: hid: ntrig: Setup input filtering manually
+  * Dropped: UBUNTU: SAUCE: hid: ntrig: New ghost-filtering event logic
+  * Dropped: UBUNTU: SAUCE: hid: ntrig: identify firmware version (wiggled)
+  * Dropped: UBUNTU: (pre-stable): input: Support Clickpad devices in ClickZone mode
+  * Dropped: UBUNTU: SAUCE: KMS: cache the EDID information of the LVDS
+  * Dropped: UBUNTU: SAUCE: fbcon -- fix race between open and removal of framebuffers
+  * Dropped: UBUNTU: SAUCE: fbcon -- fix OOPs triggered by race prevention fixes
+  * Dropped: UBUNTU: SAUCE: x86: implement cs-limit nx-emulation for ia32
+  * Dropped: UBUNTU: SAUCE: x86: more tightly confine cs-limit nx-emulation to ia32 only
+  * Dropped: UBUNTU: SAUCE: [um] Don't use nx_enabled under UML
+  * Dropped: UBUNTU: SAUCE: x86: brk away from exec rand area
+
+  [ Upstream Kernel Changes ]
+
+  * rebased against 2.6.27-rc1
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 22 Oct 2010 19:35:05 -0600
+
+linux (2.6.36-1.7) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebased to v2.6.36 final
+  * [Config] update configs following rebase to v2.6.36 final
+  * [Config] update ports configs following rebase to v2.6.36 final
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to v2.6.36 final
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 21 Oct 2010 14:28:57 +0100
+
+linux (2.6.36-1.6) natty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * drop broadcom staging driver preview:
+   * Revert "Staging: Add initial release of brcm80211 - Broadcom 802.11n
+     wireless LAN driver."
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 20 Oct 2010 10:41:25 +0100
+
+linux (2.6.36-1.5) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.36-rc8
+  * updateconfigs following rebase to v2.6.36-rc8
+  * updateportsconfigs following rebase to v2.6.36-rc8
+  * config -- simplify the kernelconfig interface
+  * config -- add new config mode 'dumpconfigs'
+
+  [ Tim Gardner ]
+
+  * Simplify the use of CROSS_COMPILER
+
+  [ Upstream Kernel Changes ]
+
+  * drop broadcom staging driver preview:
+   * Revert "staging: brcm80211: Make compiling of brcm80211.ko and
+     brcmfmac.ko mutually exclusive."
+   * Revert "staging: brcm80211: Fix compile issue when BRCM80211_PCI is not
+     set."
+   * Revert "Staging: brcm80211: remove driver specific -W options"
+   * Revert "Staging: brcm80211: clean up makefile cflag lines"
+   * Revert "staging: brcm80211: add fullmac driver"
+   * Revert "staging: brcm80211: use string native library"
+   * Revert "staging: brcm80211: use native ctype library"
+   * Revert "staging: brcm80211: fix remaining checkpatch errors."
+   * Revert "staging: brcm80211: fix "ERROR: trailing whitespace.""
+   * Revert "staging: brcm80211: fix "ERROR: spaces required around that
+     ...""
+   * Revert "staging: brcm80211: fix "ERROR: spaces prohibited around that
+     ':' ...""
+   * Revert "staging: brcm80211: fix "ERROR: space required before that
+     ...""
+   * Revert "staging: brcm80211: fix "ERROR: space required after that ...""
+   * Revert "staging: brcm80211: fix "ERROR: space required after that close
+     brace""
+   * Revert "staging: brcm80211: fix "ERROR: space prohibited before
+     ...close square bracket""
+   * Revert "staging: brcm80211: fix "ERROR: space prohibited after that
+     ...""
+   * Revert "staging: brcm80211: fix "ERROR: need consistent spacing around
+     '*'""
+   * Revert "staging: brcm80211: fix 'ERROR: "(foo*)" should be "(foo *)"'"
+   * Revert "staging: brcm80211: fix "ERROR: Macros w/ mult. statements ...
+     do - while loop""
+   * Revert "staging: brcm80211: fix "ERROR: Macros w/ complex values ...
+     parenthesis""
+   * Revert "staging: brcm80211: fix "ERROR: do not initialise statics to 0
+     or NULL""
+   * Revert "staging: brcm80211: fix "ERROR: do not initialise globals to 0
+    or NULL""
+   * Revert "staging: brcm80211: fix "ERROR: while should follow close brace
+     '}'""
+   * Revert "staging: brcm80211: fix "ERROR: that open brace { ... prev
+     line""
+   * Revert "staging: brcm80211: fix "ERROR: trailing statements should be
+     on next line""
+   * Revert "staging: brcm80211: fix "ERROR: do not use assignment in if
+     condition""
+   * Revert "staging: brcm80211: fix "ERROR: return is not a function,
+     paren...""
+   * Revert "staging: brcm80211: fix "ERROR: open brace '{' following
+     function dec...""
+   * Revert "staging: brcm80211: fix 'ERROR: "foo * bar" should be "foo
+     *bar"'"
+   * Revert "staging: brcm80211: Fix URLs for firmware files."
+   * Revert "staging: brcm80211: use '%pM' format to print MAC address"
+   * Revert "staging: brcm80211: Add contact info to TODO list."
+   * Revert "staging: brcm80211: Fix some initialisation failure paths"
+  * Export dump_{write,seek} to binary loader modules
+  * rebase to v2.6.36-rc8.
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 19 Oct 2010 18:58:11 +0100
+
+linux (2.6.36-0.4) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: perf: increase stack footprint to avoid stack-protector warning
+    (fixes FTBS on powerpc)
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 14 Oct 2010 13:16:16 +0100
+
+linux (2.6.36-0.3) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] disable CONFIG_SCSI_QLA_ISCSI to fix FTBS on powerpc
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 14 Oct 2010 03:01:30 +0100
+
+linux (2.6.36-0.2) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] updateportsconfigs following rebase to 2.6.36-rc7
+    (fix FTBS on powerpc)
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 13 Oct 2010 23:25:12 +0100
+
+linux (2.6.36-0.1) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * reduce disk usage during buildd builds
+    - LP: #645653
+  * [Config] enforcer -- ensure CONFIG_INIT_PASS_ALL_PARAMS is y
+  * [Config] armel -- drop omap flavour
+
+  [ Tim Gardner ]
+
+  * Added dropped patch list
+  * more dropped patches
+  * [Config] Disable aufs, dmraid-4.5, ndis-wrapper
+  * [Config] Add support for cross compiling armel
+  * [Config] CONFIG_SCSI_QLA_ISCSI=n for armel
+  * [Upstream] drivers/serial/mfd.c: Fix ARM compile error
+  * [Config]: updateconfigs after adding brcm80211
+  * staging: brcm80211: Fix Makefile syntax error
+  * rebased to v2.6.36-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * (upstream) IPS driver: don't toggle CPU turbo on unsupported CPUs
+  * (upstream) IPS driver: verify BIOS provided limits
+  * intel_ips: Print MCP limit exceeded values.
+  * Staging: Add initial release of brcm80211 - Broadcom 802.11n wireless
+    LAN driver.
+  * staging: brcm80211: Fix some initialisation failure paths
+  * staging: brcm80211: Add contact info to TODO list.
+  * staging: brcm80211: use '%pM' format to print MAC address
+  * staging: brcm80211: Fix URLs for firmware files.
+  * staging: brcm80211: fix 'ERROR: "foo * bar" should be "foo *bar"'
+  * staging: brcm80211: fix "ERROR: open brace '{' following function
+    dec..."
+  * staging: brcm80211: fix "ERROR: return is not a function, paren..."
+  * staging: brcm80211: fix "ERROR: do not use assignment in if condition"
+  * staging: brcm80211: fix "ERROR: trailing statements should be on next
+    line"
+  * staging: brcm80211: fix "ERROR: that open brace { ... prev line"
+  * staging: brcm80211: fix "ERROR: while should follow close brace '}'"
+  * staging: brcm80211: fix "ERROR: do not initialise globals to 0 or NULL"
+  * staging: brcm80211: fix "ERROR: do not initialise statics to 0 or NULL"
+  * staging: brcm80211: fix "ERROR: Macros w/ complex values ...
+    parenthesis"
+  * staging: brcm80211: fix "ERROR: Macros w/ mult. statements ... do -
+    while loop"
+  * staging: brcm80211: fix 'ERROR: "(foo*)" should be "(foo *)"'
+  * staging: brcm80211: fix "ERROR: need consistent spacing around '*'"
+  * staging: brcm80211: fix "ERROR: space prohibited after that ..."
+  * staging: brcm80211: fix "ERROR: space prohibited before ...close square
+    bracket"
+  * staging: brcm80211: fix "ERROR: space required after that close brace"
+  * staging: brcm80211: fix "ERROR: space required after that ..."
+  * staging: brcm80211: fix "ERROR: space required before that ..."
+  * staging: brcm80211: fix "ERROR: spaces prohibited around that ':' ..."
+  * staging: brcm80211: fix "ERROR: spaces required around that ..."
+  * staging: brcm80211: fix "ERROR: trailing whitespace."
+  * staging: brcm80211: fix remaining checkpatch errors.
+  * staging: brcm80211: use native ctype library
+  * staging: brcm80211: use string native library
+  * staging: brcm80211: add fullmac driver
+  * Staging: brcm80211: clean up makefile cflag lines
+  * Staging: brcm80211: remove driver specific -W options
+  * staging: brcm80211: Fix compile issue when BRCM80211_PCI is not set.
+  * staging: brcm80211: Make compiling of brcm80211.ko and brcmfmac.ko
+    mutually exclusive.
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 12 Oct 2010 16:00:27 +0100
+
+linux (2.6.35-22.33) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: Add support for Intellimouse Mode in ALPS touchpad on
+    Dell E2 series Laptops"
+    - LP: #641320
+
+  [ Brian Rogers ]
+
+  * SAUCE: ir-core: Fix null dereferences in the protocols sysfs interface
+    - LP: #624701
+
+  [ Christopher James Halse Rogers ]
+
+  * SAUCE: Nouveau: Add quirk framework to disable acceleration
+    - LP: #544088, #546393
+  * SAUCE: Nouveau: Disable acceleration on MacBook Pros
+    - LP: #546393
+
+  [ John Johansen ]
+
+  * Revert "SAUCE: AppArmor: allow newer tools to load policy on older
+    kernels"
+  * SAUCE: AppArmor: allow newer tools to load policy on older kernels
+    - LP: #639758
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: Adding vdd_sdi regulator supply to OMAP3EVM
+
+  [ Upstream Kernel Changes ]
+
+  * ALSA: HDA: Enable internal speaker on Dell M101z
+    - LP: #640254
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 17 Sep 2010 13:21:28 -0700
+
+linux (2.6.35-22.32) maverick; urgency=low
+
+  [ Arjan van de Ven ]
+
+  * SAUCE: libata: Add ALPM power state accounting to the AHCI driver
+
+  [ David Henningsson ]
+
+  * SAUCE: ALSA: HDA: Enable internal mic on Dell E6410 and Dell E6510
+    - LP: #605047, #628961
+
+  [ John Johansen ]
+
+  * [Upstream] AppArmor: Fix splitting an fqname into separate namespace
+    and profile names
+    - LP: #615947
+  * [Upstream] AppArmor: Fix locking from removal of profile namespace
+    - LP: #615947
+  * SAUCE: AppArmor: allow newer tools to load policy on older kernels
+    - LP: #639758
+  * SAUCE: Improve Amazon EBS performance for EC2
+    - LP: #634316
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: i915 KMS -- blacklist i855"
+  * Revert "SAUCE: i915 KMS -- blacklist i845g"
+  * Revert "SAUCE: i915 KMS -- blacklist i830"
+  * Revert "SAUCE: i915 KMS -- support disabling KMS for known broken
+    devices"
+  * execute module-inclusion within a subshell
+    - LP: #621175
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) bounce: call flush_dcache_page() after bounce_copy_vec()
+    - LP: #633227
+  * (pre-stable) drm/i915: don't enable self-refresh on Ironlake
+    - LP: #629711
+  * (pre-stable) mm: Move vma_stack_continue into mm.h
+  * x86, hwmon: Fix unsafe smp_processor_id() in thermal_throttle_add_dev
+    - LP: #601073
+  * PM / Runtime: Make runtime_status attribute not debug-only (v. 2)
+  * PM / Runtime: Add runtime PM statistics (v3)
+  * compat: Make compat_alloc_user_space() incorporate the access_ok()
+    - CVE-2010-3081
+  * x86-64, compat: Test %rax for the syscall number, not %eax
+    - CVE-2010-3301
+  * x86-64, compat: Retruncate rax after ia32 syscall entry tracing
+    - CVE-2010-3301
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 14 Sep 2010 08:46:49 -0700
+
+linux (2.6.35-21.31) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * bodge linux-libc-dev package version due to ti-omap4 error
+  * linux-libc-dev -- ensure we can only build this on debian.master
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 13 Sep 2010 09:54:31 -0700
+
+linux (2.6.35-21.30) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: fbcon -- fix OOPs triggered by race prevention fixes
+    - LP: #614008
+
+  [ Daniel Lezcano ]
+
+  * SAUCE: fix compilation warning when CONFIG_SECURITY is not set
+
+  [ Henrik Rydberg ]
+
+  * SAUCE: Input: wacom - add fuzz parameters to features
+  * SAUCE: Input: wacom - collect device quirks into single function
+  * SAUCE: Input: wacom - add support for the Bamboo Touch trackpad
+  * SAUCE: Input: wacom - add a quirk for low resolution Bamboo devices
+  * SAUCE: hid: ntrig: Remove unused device ids
+  * SAUCE: hid: ntrig: remove sysfs nodes
+  * SAUCE: hid: ntrig: Correct logic for quirks
+  * SAUCE: hid: ntrig: zero-initialize ntrig struct
+  * SAUCE: hid: ntrig: Setup input filtering manually
+  * SAUCE: hid: ntrig: New ghost-filtering event logic
+
+  [ Leann Ogasawara ]
+
+  * SAUCE: ndiswrapper: Initialize buffer index and check its value
+    - LP: #613796
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Add support for Intellimouse Mode in ALPS touchpad on Dell E2
+    series Laptops
+    - LP: #632884
+
+  [ Ping Cheng ]
+
+  * SAUCE: Input: wacom - parse the Bamboo device family
+
+  [ Rafi Rubin ]
+
+  * SAUCE: hid: ntrig: identify firmware version (wiggled)
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NL80211_TESTMODE=n
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "input: mt: Add support for the Bamboo Touch trackpad"
+  * e1000e: initial support for 82579 LOMs
+  * e1000e: correct MAC-PHY interconnect register offset for 82579
+  * (pre-stable) ALSA: hda - Add a new hp-laptop model for Conexant 5066,
+    tested on HP G60
+    - LP: #587388
+  * DSS2: Don't power off a panel twice
+    - LP: #588243
+  * mmc: build fix: mmc_pm_notify is only available with CONFIG_PM=y
+  * Input: i8042 - reset keyboard controller wehen resuming from S2R
+    - LP: #86820
+  * ALSA: hda - Fix beep frequency on IDT 92HD73xx and 92HD71Bxx codecs
+    - LP: #414795
+  * agp/intel: Support the extended physical addressing bits on
+    Sandybridge.
+    - LP: #632488
+  * drm/i915,intel_agp: Add support for Sandybridge D0
+    - LP: #632488
+  * (pre-stable) intel_agp,i915: Add more sandybridge graphics device ids
+    - LP: #632488
+  * mmc: omap: fix for bus width which improves SD card's peformance.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 07 Sep 2010 09:58:52 -0700
+
+linux (2.6.35-20.29) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: i915 KMS -- support disabling KMS for known broken devices
+    - LP: #563277
+  * SAUCE: i915 KMS -- blacklist i830
+    - LP: #542208, #563277
+  * SAUCE: i915 KMS -- blacklist i845g
+    - LP: #541492, #563277
+  * SAUCE: i915 KMS -- blacklist i855
+    - LP: #511001, #541511, #563277
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_SENSORS_PKGTEMP=m
+    - LP: #601073
+  * ARM: Temporarily disable module check for armel
+  * rebase to v2.6.35.4
+  * [Config] update configs following rebase to v2.6.35.4
+
+  [ Ricardo Salveti de Araujo ]
+
+  * [Config] Change CONFIG_LEDS_TRIGGER_HEARTBEAT from module to built-in
+    in Omap
+
+  [ Tim Gardner ]
+
+  * [Config] Added be2net, be2scsi to udebs
+    - LP: #628776
+
+  [ Upstream Kernel Changes ]
+
+  * x86, cpu: Package Level Thermal Control, Power Limit Notification
+    definitions
+    - LP: #601073
+  * x86, hwmon: Package Level Thermal/Power: pkgtemp hwmon driver
+    - LP: #601073
+  * x86, hwmon: Package Level Thermal/Power: thermal throttling handler
+    - LP: #601073
+  * x86, hwmon: Package Level Thermal/Power: power limit
+    - LP: #601073
+  * x86, hwmon: Package Level Thermal/Power: pkgtemp documentation
+    - LP: #601073
+  * hid: 3m: Adjust to sequential MT HID protocol
+  * hid: 3m: Convert to MT slots
+  * hid: 3m: Correct touchscreen emulation
+  * hid: 3m: Adjust major / minor axes to scale
+  * input: bcm5974: Adjust major / minor to scale
+  * HID: magicmouse: don't allow hidinput to initialize the device
+  * HID: magicmouse: simplify multitouch feature request
+  * HID: magicmouse: simplify touch data bit manipulation
+  * HID: magicmouse: simplify touch down logic
+  * HID: magicmouse: remove timestamp logic
+  * HID: magicmouse: enable Magic Trackpad support
+  * HID: magicmouse: Adjust major / minor axes to scale
+  * mmc: fix all hangs related to mmc/sd card insert/removal during
+    suspend/resume
+    - LP: #477106
+  * drm/i915: fix VGA plane disable for Ironlake+
+    - LP: #602281
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 30 Aug 2010 08:38:01 -0700
+
+linux (2.6.35-19.28) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No changes from 2.6.35-19.27.  Some armel udebs were accidentally deleted
+    from the archive and a no-change rebuild was attempted.  However, the ABI
+    did not get bumped and resulted in build failures for 2.6.35-19.27.  Fix
+    up the ABI and re-upload.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sat, 28 Aug 2010 16:42:27 -0700
+
+linux (2.6.35-19.27) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No changes from 2.6.35-19.26.  Some armel udebs were accidentally deleted
+    from the archive.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 27 Aug 2010 08:58:35 -0700
+
+linux (2.6.35-19.26) maverick; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * ARM: OMAP: Beagle: revision detection
+  * ARM: OMAP: Beagle: only Cx boards use pin 23 for write protect
+  * ARM: OMAP: Beagle: no gpio_wp pin connection on xM
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 26 Aug 2010 09:15:09 -0700
+
+linux (2.6.35-19.25) maverick; urgency=low
+
+  [ Jarod Wilson ]
+
+  * SAUCE: Bring in staging/lirc from 2.6.36
+    - LP: #609234
+  * SAUCE: Update ir-core to linuxtv/other which should be merged for
+    2.6.36.
+    - LP: #609234
+  * SAUCE: Fix memleaks in imon and mceusb drivers
+    - LP: #609234
+  * SAUCE: Bring in streamzap support from linuxtv/other
+    - LP: #609234
+
+  [ Mario Limonciello ]
+
+  * Remove ubuntu/lirc in favor of staging/lirc from 2.6.36
+    - LP: #609234
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: ARM: adding i2c eeprom driver to read EDID
+    - LP: #608279
+
+  [ Upstream Kernel Changes ]
+
+  * intel_idle: disable module support
+    - LP: #615265
+  * (pre-stable) ALSA: hda - Ensure codec patch files are checked for the
+    correct codec ID
+  * (pre-stable) ALSA: hda - Rename iMic to Int Mic on Lenovo NB0763
+    - LP: #605101
+  * (pre-stable) ALSA: HDA: Use model=auto for LG R510
+    - LP: #495134
+  * (pre-stable) ALSA: HDA: Add Sony VAIO quirk for ALC269
+    - LP: #519066
+  * (pre-stable) ALSA: HDA: Fix front mic on Dell Precision M6500
+    - LP: #519066
+  * input: mt: Initialize slots to unused (rev2)
+  * input: mt: Add support for the Bamboo Touch trackpad
+  * hid: Add a hid quirk for input sync override
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 23 Aug 2010 12:42:52 -0700
+
+linux (2.6.35-18.24) maverick; urgency=low
+
+  [ Colin Watson ]
+
+  * Pass DEB_MAINT_PARAMS to hook scripts
+
+  [ Leann Ogasawara ]
+
+  * [Config] Add CONFIG_INPUT_UINPUT=y to config enforcer
+    - LP: #584812
+  * rebase to v2.6.35.3
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) dell-wmi: Add support for eject key on Dell Studio 1555
+    - LP: #609234
+  * can: add limit for nframes and clean up signed/unsigned variables
+    - CVE-2010-2959
+  * drm: Initialize ioctl struct when no user data is present
+    - CVE-2010-2803
+  * ARM: initial stack protector (-fstack-protector) support
+  * ARM: stack protector: change the canary value per task
+  * [ARM] implement arch_randomize_brk()
+  * [ARM] add address randomization to mmap()
+  * ARM: fix ASLR of PIE executables
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sun, 22 Aug 2010 19:22:04 -0700
+
+linux (2.6.35-17.23) maverick; urgency=low
+
+  [ Jeremy Kerr ]
+
+  * [Config] build-in uinput module
+    - LP: #584812
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] [FTBS] ia64: Temporarily disable CONFIG_CEPH_FS"
+  * Revert "[Config] [FTBS] ia64: Temporarily disable gpiolib"
+  * Revert "[Config] [FTBS] sparc: Temporarily disable
+    CONFIG_MTD_NAND_DENALI"
+  * Revert "[Config] [FTBS] sparc: Temporarily disable
+    CONFIG_MFD_JANZ_CMODIO"
+  * Revert "[Config] [FTBS] sparc: Temporarily disable
+    CONFIG_INFINIBAND_QIB"
+  * [Config] Enable INTEL_IPS
+    - LP: #601057
+  * Remove ia64 support
+  * [Config] Update portsconfigs after removing ia64 support
+  * Remove sparc support
+  * [Config] Update portsconfigs after removing sparc support
+
+  [ Linus Torvalds ]
+
+  * (pre-stable) mm: fix page table unmap for stack guard page properly
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: (no-up) ARM: Resetting power_mode to its original value.
+    - LP: #591941
+
+  [ Upstream Kernel Changes ]
+
+  * timer: add on-stack deferrable timer interfaces
+    - LP: #601057
+  * x86 platform driver: intelligent power sharing driver
+    - LP: #601057
+  * IPS driver: add GPU busy and turbo checking
+    - LP: #601057
+  * X86: intel_ips, check for kzalloc properly
+    - LP: #601057
+  * ips driver: make it less chatty
+    - LP: #601057
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 17 Aug 2010 09:38:08 -0700
+
+linux (2.6.35-16.22) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * debian -- more agressivly clean up after depmod on purge
+    - LP: #618591
+
+  [ Henrik Rydberg ]
+
+  * SAUCE: hid: 3m: Simplify touchsreen emulation logic
+
+  [ Leann Ogasawara ]
+
+  * ubuntu: iscsitarget -- version 1.4.20.2
+  * ubuntu: rtl8192se -- update to version 0017.0507.2010
+  * rebase to v2.6.35.2
+  * [Config] update configs following rebase to v2.6.35.2
+  * [Config] update ports configs following rebase to v2.6.35.2
+
+  [ Luke Yelavich ]
+
+  * [Config] Enable new firewire stack on powerpc
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: (drop after 2.6.35) ARM: Using gpmc function to init nand flash.
+    - LP: #608266
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 12 Aug 2010 09:58:01 -0700
+
+linux (2.6.35-15.21) maverick; urgency=low
+
+  [ Luke Yelavich ]
+
+  * [Config] CONFIG_SND_USB_UA101=m for all architectures
+
+  [ Upstream Kernel Changes ]
+
+  * Input: introduce MT event slots
+  * Input: document the MT event slot protocol
+  * (pre-stable) sched: Revert nohz_ratelimit() for now
+  * (pre-stable) drm/radeon/kms: add missing copy from user
+    - LP: #606081
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35.1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 09 Aug 2010 09:24:04 -0700
+
+linux (2.6.35-14.20) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * update Vcs-Git to point to maverick repo
+  * debian -- include the debian packaging in the -source package
+    - LP: #608674
+  * select debian source format 1.0
+  * add support for building selected stages of kernel
+    - LP: #603087
+  * cleanup conditional dependancy handling
+    - LP: #603087
+
+  [ Upstream Kernel Changes ]
+
+  * ALSA: hda - Handle missing NID 0x1b on ALC259 codec
+    - LP: #582199, #586418, #588031
+  * ALSA: hda - Handle pin NID 0x1a on ALC259/269
+    - LP: #582199, #586418, #588031
+  * sched: Revert nohz_ratelimit() for now
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 03 Aug 2010 08:46:47 -0700
+
+linux (2.6.35-14.19) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sun, 01 Aug 2010 10:35:56 -0700
+
+linux (2.6.35-13.18) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: (no-up) Modularize vesafb -- fix initialisation
+  * SAUCE: add tracing for user initiated readahead requests
+  * SAUCE: vt -- maintain bootloader screen mode and content until vt
+    switch
+  * SAUCE: vt -- allow grub to request automatic vt_handoff
+  * SAUCE: fbcon -- fix race between open and removal of framebuffers
+  * SAUCE: drm -- stop early access to drm devices
+
+  [ Bryan Wu ]
+
+  * CONFIG: compile in OTG driver and Transceiver driver
+    - LP: #566645
+  * remove OTG modules from modules list file
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: -- sync to AppArmor mainline 2010-07-27
+    - LP: #581525, #599450
+  * SAUCE: AppArmor: -- sync to AppArmor mainline 2010-07-29
+  * SAUCE: AppArmor 2.4 compatibility patch
+  * SAUCE: AppArmor: Allow dfa backward compatibility with broken userspace
+  * SAUCE: fix pv-ops for legacy Xen
+  * SAUCE: blkfront: default to sd devices
+  * [Config] Build in drivers required for Xen pv-ops
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Upstream] i915: Use the correct mask to detect i830 aperture
+    size."
+
+  [ Lee Jones ]
+
+  * SAUCE: ARM: OMAP: Add macros for comparing silicon revision
+    - LP: #608095
+  * SAUCE: OMAP: DSS2: check for both cpu type and revision, rather than
+    just revision
+    - LP: #608095
+  * SAUCE: OMAP: DSS2: enable hsclk in dsi_pll_init for OMAP36XX
+    - LP: #608095
+  * SAUCE: ARM: OMAP: Beagle: support twl gpio differences on xM
+    - LP: #608095
+
+  [ Upstream Kernel Changes ]
+
+  * agp/intel: Use the correct mask to detect i830 aperture size.
+    - LP: #597075
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 30 Jul 2010 15:46:59 -0700
+
+linux (2.6.35-12.17) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc6
+  * [Config] update configs following rebase to v2.6.35-rc6
+  * [Config] update ports configs following rebase to v2.6.35-rc6
+  * SAUCE: [FTBS] armel: define KEY_F10 and KEYF11
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 23 Jul 2010 16:16:38 +0200
+
+linux (2.6.35-11.16) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Bump ABI for new compiler update 
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 23 Jul 2010 10:24:58 +0200
+
+linux (2.6.35-10.15) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: ensure vga16fb loads if no other driver claims the VGA
+    device"
+  * [Config] Enable CONFIG_M686=y
+    - LP: #592495
+
+  [ Upstream Kernel Changes ]
+
+  * tracing: Add alignment to syscall metadata declarations
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 20 Jul 2010 18:18:49 +0200
+
+linux (2.6.35-9.14) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- add BOM and automated update script
+  * ubuntu: AUFS -- update to b37c575759dc4535ccc03241c584ad5fe69e3b25
+
+  [ John Johansen ]
+
+  * [Config] Enable DRBD as a module
+
+  [ Kees Cook ]
+
+  * SAUCE: Yama: verify inode is symlink to avoid bind mounts
+    - LP: #604407
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_DRM_VMWGFX (staging driver)
+    - LP: #606139
+  * [Config] ports: Disable CONFIG_DRM_VMWGFX (staging driver)
+    - LP: #606139
+  * [Config] Enable CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
+  * [Config] ports: Enable CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
+
+  [ Lee Jones ]
+
+  * Stop ARM boards crashing when CUPS is loaded
+    - LP: #601226
+
+  [ Upstream Kernel Changes ]
+
+  * perf probe: Support tracing an entry of array
+  * perf probe: Support static and global variables
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 16 Jul 2010 14:38:17 -0700
+
+linux (2.6.35-8.13) maverick; urgency=low
+
+  [ Kees Cook ]
+
+  * SAUCE: Yama: check PTRACE using thread group leader
+  * SAUCE: Yama: search for PTRACE exceptions via thread group leader
+    - LP: #603716
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc5
+  * [Config] update configs following rebase to v2.6.35-rc5
+
+  [ Nicolas Pitre ]
+
+  * SAUCE: make ndiswrapper available on X86 only
+
+  [ Tim Gardner ]
+
+  * [Config] Added ums-cypress to udeb
+    - LP: #576066
+  * SAUCE: fix build error with CONFIG_BLK_DEV_INITRD=n
+  * [Config] CONFIG_NDISWRAPPER=m across all configs
+
+  [ Upstream Kernel Changes ]
+
+  * HID: magicmouse: report last touch up
+  * rebase to 2.6.35-rc5
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 13 Jul 2010 18:57:59 -0700
+
+linux (2.6.35-7.12) maverick; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Upstream] i915: Use the correct mask to detect i830 aperture size.
+    - LP: #597075
+
+  [ Upstream Kernel Changes ]
+
+  * (drop after 2.6.35) drm/radeon/kms: add ioport register access
+    (squashed)
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 08 Jul 2010 09:53:13 -0600
+
+linux (2.6.35-7.11) maverick; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_X86_MRST=n
+
+  [ Upstream Kernel Changes ]
+
+  * (drop after 2.6.35-rc5) writeback: remove writeback_inodes_wbc
+  * (drop after 2.6.35-rc5) writeback: split writeback_inodes_wb
+  * (drop after 2.6.35-rc5) writeback: simplify the write back thread queue
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 06 Jul 2010 18:39:08 -0600
+
+linux (2.6.35-7.10) maverick; urgency=low
+
+  [ Kees Cook ]
+
+  * SAUCE: security: create task_free security callback
+  * SAUCE: Yama: add PTRACE exception tracking and interface
+  * SAUCE: security: unconditionally chain to Yama LSM
+  * Revert "SAUCE: ptrace: restrict ptrace scope to children"
+  * Revert "SAUCE: fs: block hardlinks to non-accessible sources"
+  * Revert "SAUCE: fs: block cross-uid sticky symlinks"
+  * [Upstream] security: Yama LSM
+  * [Config] Enable CONFIG_SECURITY_YAMA=y
+
+  [ Tim Gardner ]
+
+  * [Config] updateconfigs/updateportsconfigs after rebase to 2.6.35-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 2.6.35-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 01 Jul 2010 08:55:57 -0700
+
+linux (2.6.35-6.9) maverick; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Upstream] direct_splice_actor() should not use pos in sd
+    - LP: #588861
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 28 Jun 2010 12:35:49 -0700
+
+linux (2.6.35-6.8) maverick; urgency=low
+
+  [ Mathieu J. Poirier ]
+
+  * ARM: Adding regulator supply for vdds_sdi.
+    - LP: #597904
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sun, 27 Jun 2010 16:34:43 -0700
+
+linux (2.6.35-6.7) maverick; urgency=low
+
+  [ Alberto Milone ]
+
+  * [Upstream] Add support for the ATIF ACPI method to the radeon driver
+
+  [ Chase Douglas ]
+
+  * [Upstream] HID: magicmouse: scroll on entire surface, not just middle
+    of mouse
+  * [Upstream] HID: magicmouse: disable and add module param for scroll
+    acceleration
+  * [Upstream] HID: magicmouse: properly account for scroll movement in
+    state
+  * [Upstream] HID: magicmouse: add param for scroll speed
+  * [Upstream] HID: magicmouse: enable horizontal scrolling
+
+  [ Henrik Rydberg ]
+
+  * [Upstream] Input: evdev - convert to dynamic event buffer
+  * [Upstream] Input: evdev - use driver hint to compute size of event
+    buffer
+  * [Upstream] Input: bcm5974 - set the average number of events per MT
+    event packet
+  * [Upstream] Input: hid-input - use a larger event buffer for MT devices
+  * [Upstream] Input: evdev - never leave the client buffer empty after
+    write
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: -- mainline 2010-06-23
+  * SAUCE: AppArmor 2.4 compatibility patch
+  * SAUCE: fs: block hardlinks to non-accessible sources AppArmor portion
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_INTR_REMAP=y
+    - LP: #597091
+  * [Config] Enable CONFIG_X86_X2APIC
+    - LP: #597091
+
+  [ Mathieu J. Poirier ]
+
+  * [Config] ARM: Turning off CONFIG_CPU_IDLE on omap
+    - LP: #594382
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 24 Jun 2010 12:19:48 -0700
+
+linux (2.6.35-5.6) maverick; urgency=low
+
+  [ Amit Kucheria ]
+
+  * [Config] update omap flavour description
+
+  [ Andy Whitcroft ]
+
+  * update to ubuntu-debian:508b7aa34b578c0d1e51bfb571f2bfb824dc65ac
+    - LP: #570500, #576274
+  * SAUCE: add option to hand off all kernel parameters to init
+    - LP: #586386
+  * [Config] enable passing all kernel command line to init
+    - LP: #586386
+  * [Config] disable CONFIG_VMI
+    - LP: #537601
+  * [Config] enable CONFIG_IPV6_SIT_6RD
+    - LP: #591869
+  * [Config] enable CONFIG_VMWARE_BALOON as module
+    - LP: #592039
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: pm: Config option to disable handling of console during
+    suspend/resume"
+    - LP: #594885
+  * [Config] Remove CONFIG_PM_DISABLE_CONSOLE
+  * [Config] ports: enable passing all kernel command line to init
+    - LP: #586386
+  * [Config] Enable CONFIG_FB_VESA=y for x86
+  * [Config] Add CONFIG_FRAMEBUFFER_CONSOLE=y to config enforcer
+  * [Config] Add CONFIG_FB_VESA=y for x86 to config enforcer
+  * [Config] Enable CONFIG_TASK_DELAY_ACCT=y
+    - LP: #493156
+
+  [ Mathieu Poirier ]
+
+  * ARM: Adding MosChip MCS7830 to nic-usb
+    - LP: #584920
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[Upstream] docbook: need xmldoclinks for all doc types"
+  * docbook: need xmldoclinks for all doc types
+  * perf probe: Add kernel source path option
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 17 Jun 2010 08:05:29 -0700
+
+linux (2.6.35-4.5) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Upstream] (evdev) Use driver hint to compute the evdev buffer
+    size (rev2)"
+  * Revert "[Upstream] (evdev) Convert to dynamic event buffer (rev4)"
+  * Revert "[Upstream] (evdev) Use multi-reader buffer to save space
+    (rev4)"
+  * Revert "SAUCE: drivers: Remove some duplicate device entries in various
+    modules"
+  * [Upstream] USB: option: Remove duplicate AMOI_VENDOR_ID
+  * [Upstream] Revert "USB: Adding support for HTC Smartphones to ipaq"
+  * [Upstream] p54usb: Comment out duplicate Medion MD40900 device id
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NFS_FSCACHE=y
+    - LP: #440522
+  * [Config] CONFIG_FSCACHE_STATS=y, CONFIG_FSCACHE_HISTOGRAM=y
+    - LP: #440522
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 16 Jun 2010 08:43:07 -0700
+
+linux (2.6.35-3.4) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * debian -- ensure the version number is clean
+
+  [ Henrik Rydberg ]
+
+  * [Upstream] Introduce MT event slots (rev 5)
+  * [Upstream] Document the MT event slot protocol (rev5)
+  * [Upstream] (evdev) Use multi-reader buffer to save space (rev4)
+  * [Upstream] (evdev) Convert to dynamic event buffer (rev4)
+  * [Upstream] (evdev) Use driver hint to compute the evdev buffer size
+    (rev2)
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: Add MODULE_ALIAS for Dell WMI module"
+  * Revert "SAUCE: hostap: send events on data interface as well as master
+    interface"
+  * Revert "Fix webcam having USB ID 0ac8:303b"
+  * Revert "SAUCE: toshiba_acpi -- pull in current -dev version of driver"
+  * rebase to v2.6.35-rc3
+
+  [ Maxim Levitsky ]
+
+  * [Config] Enable new Smartmedia/xD translation layer
+    - LP: #202490
+
+  [ Upstream Kernel Changes ]
+
+  * net: fix deliver_no_wcard regression on loopback device
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.35-rc3
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 10 Jun 2010 16:15:22 -0700
+
+linux (2.6.35-2.3) maverick; urgency=low
+
+  [ Bryan Wu ]
+
+  * CONFIG: enforce -- make sure we disable CONFIG_LOCALVERSION_AUTO
+
+  [ Leann Ogasawara ]
+
+  * [Config] armel: Enable CONFIG_BNX2=m
+  * [Config] ports: Enable CONFIG_BNX2X=m
+  * SAUCE: armel: define get_dma_ops to fix FTBS
+
+  [ Tim Gardner ]
+
+  * [Upstream] net: Print num_rx_queues imbalance warning only when there
+    are allocated queues
+    - LP: #591416
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 09 Jun 2010 08:27:41 -0700
+
+linux (2.6.35-2.2) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] d-i: make armel configuration versatile flavour specific
+    - LP: #588805
+  * [Config] d-i: enable .udebs for omap flavour
+    - LP: #588805
+
+  [ Kees Cook ]
+
+  * ptrace: limit scope to attach only (allow read)
+    - LP: #589656
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc2
+  * [Config] update configs following rebase to v2.6.35-rc2
+  * [Config] update port configs following rebase to v2.6.35-rc2
+
+  [ Lee Jones ]
+
+  * Enable perf to be more helpful when perf_<version> does not exist.
+    - LP: #570500
+  * 'fdr editconfig' modification. Easily skip over unwanted menuconfigs.
+
+  [ Tim Gardner ]
+
+  * [Config] Update bnx2 udeb firmware files
+    - LP: #589304
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.35-rc2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 07 Jun 2010 09:45:04 -0700
+
+linux (2.6.35-1.1) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- update to standalone 2.6.35-rcN as at 20100601
+    - LP: #587888
+  * ubuntu: AUFS -- track changes to the arguements to fop fsync()
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc1
+  * [Config] update configs following rebase to v2.6.35-rc1
+  * [Config] update port configs following rebase to v2.6.35-rc1
+  * SAUCE: lirc: rename usb_buffer_alloc() and usb_buffer_free()
+  * SAUCE: ndiswrapper: rename usb_buffer_alloc() and usb_buffer_free()
+  * SAUCE: ndiswrapper: convert multicast list to list_head
+  * [Config] [FTBS] armel: Temporarily disable CONFIG_GPIO_JANZ_TTL
+  * [Config] [FTBS] ia64: Temporarily disable gpiolib
+  * [Config] [FTBS] ia64: Temporarily disable CONFIG_CEPH_FS
+  * [Config] [FTBS] sparc: Temporarily disable CONFIG_INFINIBAND_QIB
+  * [Config] [FTBS] sparc: Temporarily disable CONFIG_MFD_JANZ_CMODIO
+  * [Config] [FTBS] armel: Temporarily disable CONFIG_MFD_JANZ_CMODIO
+  * [Config] [FTBS] armel: Temporarily disable CONFIG_DT3155
+  * [Config] [FTBS] sparc: Temporarily disable CONFIG_MTD_NAND_DENALI
+  * [Config] [FTBS] armel: Temporarily disable bnx2
+  * [Config] [FTBS] armel: Temporarily disable CONFIG_SERIAL_UARTLITE
+  * SAUCE: [FTBS] armel: Don't include asm/agp.h for ttm
+  * SAUCE: [FTBS] armel: include linux/dma-mapping.h
+  * SAUCE: [FTBS] armel: replace omap_set_gpio_debounce with
+    gpio_set_debounce
+
+  [ Upstream Kernel Changes ]
+
+  * of/usb: fix build error due to of_node pointer move
+  * n2_crypto: Fix build after of_device/of_platform_driver changes.
+  * powerpc/fsl-booke: fix the case where we are not in the first page
+  * powerpc/fsl-booke: Move the entry setup code into a seperate file
+  * powerpc/kexec: Add support for FSL-BookE
+  * greth: Fix build after OF device conversions.
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.35-rc1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 04 Jun 2010 23:01:52 -0700
+
+linux (2.6.35-1.0) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Null entry.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 02 Jun 2010 15:17:41 -0700
+
+linux (2.6.34-5.14) maverick; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Added module inclusion support
+  * [Config] Added virtual flavour module inclusion list and d-i package
+    definitions
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 02 Jun 2010 12:58:14 -0700
+
+linux (2.6.34-5.13) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- aufs2 20091209"
+  * Revert "ubuntu: AUFS -- export various core functions
+    (aufs2-standalone.patch)"
+  * Revert "ubuntu: AUFS -- export various core functions
+    (aufs2-base.patch)"
+  * ubuntu: AUFS -- aufs2 base patch for linux-2.6.34
+    - LP: #587888
+  * ubuntu: AUFS -- aufs2 standalone patch for linux-2.6.34
+    - LP: #587888
+  * ubuntu: AUFS -- update to standalone 2.6.34 as at 20100601
+    - LP: #587888
+  * [Config] AUFS -- enable aufs options
+    - LP: #587888
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 01 Jun 2010 08:56:43 -0700
+
+linux (2.6.34-5.12) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * enforce -- ensure SYSFS compatibility is disabled
+
+  [ Chase Douglas ]
+
+  * build with libdw-dev for perf probe symbol support
+  * maverick ftrace configuration changes
+
+  [ Kees Cook ]
+
+  * Revert "SAUCE: x86: brk away from exec rand area"
+  * Revert "SAUCE: [um] Don't use nx_enabled under UML"
+  * Revert "SAUCE: [x86] implement cs-limit nx-emulation for ia32"
+  * SAUCE: x86: implement cs-limit nx-emulation for ia32
+    - LP: #369978
+  * SAUCE: x86: more tightly confine cs-limit nx-emulation to ia32 only
+  * SAUCE: x86: brk away from exec rand area
+    - LP: #452175
+  * SAUCE: ptrace: restrict ptrace scope to children
+
+  [ Leann Ogasawara ]
+
+  * Add new omap flavour to getabis
+  * [Config] Enable CONFIG_FRAMEBUFFER_CONSOLE=y for all archs
+    - LP: #585490
+  * build/modules: Temorarily add ignore.modules
+  * ubuntu: iscsitarget -- version 1.4.20.1
+
+  [ Loïc Minier ]
+
+  * SAUCE: [um] Don't use nx_enabled under UML
+    - LP: #524849
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 28 May 2010 08:27:17 -0700
+
+linux (2.6.34-4.11) maverick; urgency=low
+
+  [ Amit Kucheria ]
+
+  * SAUCE: omap: remove calls to usb_nop_xceiv_register from board files
+  * [Config] Add support for OMAP-mainline flavour
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: powerpc: fix compile error when ptrace.h is included from
+    userspace
+    - LP: #583733
+
+  [ Chase Douglas ]
+
+  * Revert "SAUCE: Don't register vga16fb framebuffer if other framebuffers
+    are present"
+  * Revert "SAUCE: Disable function tracing after hitting __schedule_bug"
+  * Revert "SAUCE: drm/i915: don't change DRM configuration when releasing
+    load detect pipe"
+
+  [ Kees Cook ]
+
+  * SAUCE: fs: block cross-uid sticky symlinks
+  * SAUCE: fs: block hardlinks to non-accessible sources
+
+  [ Koen Kooi ]
+
+  * SAUCE: board-omap3-beagle: add DSS2 support
+
+  [ Leann Ogasawara ]
+
+  * Revert "staging/go7007 -- disable"
+  * Revert "[Config] staging/winbond -- disable"
+  * Revert "Disable 4MB page tables for Atom, work around errata AAE44"
+  * Revert "SAUCE: sync before umount to reduce time taken by ext4 umount"
+  * Revert "SAUCE: Enable an e1000e Intel Corporation 82567 Gigabit
+    controller"
+  * Revert "SAUCE: Fix MODULE_IMPORT/MODULE_EXPORT"
+  * Revert "SAUCE: Created MODULE_EXPORT/MODULE_IMPORT macros"
+  * Revert "SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps"
+  * Revert "SAUCE: r8169: disable TSO by default for RTL8111/8168B
+    chipsets."
+  * Revert "[Upstream] b43: Declare all possible firmware files."
+  * Revert "add Breaks: against hardy lvm2"
+  * Revert "SAUCE: Guest OS does not recognize a lun with non zero target
+    id on Vmware ESX Server"
+  * Revert "SAUCE: Catch nonsense keycodes and silently ignore"
+  * [Config] Enable CONFIG_ECRYPT_FS=y for ports
+  * [Config] Enable CONFIG_USB=y for armel and sparc
+  * [Config] Enable CONFIG_SCSI=y for ia64 and sparc
+  * [Config] Enable CONFIG_RFKILL=y for ports
+  * [Config] Enable CONFIG_ATH9K_DEBUGFS=y
+  * [Config] Enable CONFIG_IWMC3200TOP_DEBUGFS=y
+  * [Config] Enable CONFIG_RCU_FAST_NO_HZ=y
+  * [Config] Enable CONFIG_IWLWIFI_DEVICE_TRACING=y
+  * [Config] Enable CONFIG_LIBERTAS_MESH=y
+  * [Config] Enable CONFIG_MMC_RICOH_MMC=y
+  * [Config] CONFIG_RT2800USB_UNKNOWN=y
+  * [Config] Enable CONFIG_VGA_SWITCHEROO=y
+  * [Config] Enable CONFIG_CEPH_FS=m
+  * [Config] Enable CONFIG_CRYPTO_PCRYPT=m
+  * [Config] Enable CONFIG_EEEPC_WMI=m
+  * [Config] Enable CONFIG_RT2800PCI=m
+  * [Config] Enable CONFIG_SCSI_HPSA=m
+  * [Config] Enable CONFIG_VHOST_NET=m
+  * [Config] Disable CONFIG_SND_HDA_INPUT_BEEP_MODE by default
+    - LP: #582350
+  * [Config] Disable CONFIG_SOUND_OSS* and CONFIG_SND_*OSS
+    - LP: #579300
+  * [Config] Enable CONFIG_PCIEASPM=y
+    - LP: #333990
+  * [Config] updateconfigs for OMAP flavour
+
+  [ Loïc Minier ]
+
+  * Enable perf tools on armel
+
+  [ Tim Gardner ]
+
+  * SAUCE: Updated ndiswrapper to 1.56
+    - LP: #582555
+  * [Config] Added virtual flavour
+  * [Config] Remove support for sub-flavours
+  * [Config] Removed amd64 preempt flavour
+  * [Config] updateconfigs, updateportsconfigs after flavour munging
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 25 May 2010 09:34:55 -0700
+
+linux (2.6.34-3.10) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 18 May 2010 17:35:35 -0700
+
+linux (2.6.34-2.9) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] [FTBS] Disable comedi for armel
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 13 May 2010 23:20:55 +0200
+
+linux (2.6.34-2.8) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Drop lpia
+  * [Config] [FTBS] disable KVM
+  * [Config] [FTBS] disable ipr for armel
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 13 May 2010 16:07:52 +0200
+
+linux (2.6.34-2.7) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] disable CONFIG_SCSI_IPR on powerpc
+  * [Config] Remove 386 flavour per UDS discussion
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 12 May 2010 18:26:43 +0200
+
+linux (2.6.34-1.6) maverick; urgency=low
+
+  [ Chase Douglas ]
+
+  * enforce CONFIG_TMPFS_POSIX_ACL=y
+    - LP: #575940
+  * don't force module dependency checking
+    - LP: #577029
+
+  [ Kees Cook ]
+
+  * SAUCE: mmap_min_addr check CAP_SYS_RAWIO only for write
+    - LP: #568844
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: ata: blacklist FUJITSU MHW2160BH PL"
+  * rebase to v2.6.34-rc7
+  * [Config] update configs following rebase to v2.6.34-rc7
+  * [Config] update port configs following rebase to v2.6.34-rc7
+  * Add btrfs to the udebs
+
+  [ Tim Gardner ]
+
+  * [Config] Add atl1c to nic-modules udeb
+    - LP: #557130
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 11 May 2010 11:29:08 +0200
+
+linux (2.6.34-1.5) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34-rc6
+  * [Config] update configs following rebase to v2.6.34-rc6
+  * [Config] update port configs following rebase to v2.6.34-rc6
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 30 Apr 2010 15:54:05 +0100
+
+linux (2.6.34-1.4) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34-rc5
+  * [Config] update ports configs following rebase to v2.6.34-rc5
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc5
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 22 Apr 2010 15:36:12 -0700
+
+linux (2.6.34-1.3) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34-rc4
+  * [Config] update configs following rebase to v2.6.34-rc4
+  * [Config] update port configs following rebase to v2.6.34-rc4
+  * ubuntu: dm-raid4-5 -- update to compile with 2.6.34-rc4
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 13 Apr 2010 18:33:44 -0700
+
+linux (2.6.34-1.2) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Temorarily disable building linux-doc
+  * rebase to v2.6.34-rc3
+  * [Config] update configs following rebase to v2.6.34-rc3
+  * [Config] update port configs following rebase to v2.6.34-rc3
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc3
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 30 Mar 2010 16:55:44 -0700
+
+linux (2.6.34-1.1) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34-rc2
+  * ubuntu: dm-raid4-5 -- update to compile with 2.6.34-rc2
+  * [Config] update port configs following rebase to v2.6.34-rc2
+  * [Config] update configs following rebase to v2.6.34-rc2
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 24 Mar 2010 23:00:39 -0700
+
+linux (2.6.33-1.1) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * ubuntu: dm-raid4-5 -- update to compile with 2.6.33
+  * ubuntu: lirc -- drop explicit include of linux/autoconf.h
+  * ubuntu: lirc -- pass kfifo to kfifo_alloc and move spinlock
+  * ubuntu: lirc -- rename kfifo_put and kfifo_get
+  * ubuntu: iscsitarget -- rename daddr inet_sock field
+  * rebased to v2.6.33
+  * [Config] update configs following rebase to v2.6.33
+  * [Config] update ports configs following rebase to v2.6.33
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.33
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 23 Mar 2010 03:55:46 -0700
+
+linux (2.6.33-0.0) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Null entry.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 17 Mar 2010 07:48:56 -0700
+
+linux (2.6.32-16.25) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * linux-tools -- move to Suggests: with explicit seeding
+    - LP: #534635
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_HID=m
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) sched: Fix SMT scheduler regression in
+    find_busiest_queue()
+  * KVM: introduce kvm_vcpu_on_spin
+  * KVM: VMX: Add support for Pause-Loop Exiting
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 09 Mar 2010 14:13:51 +0000
+
+linux (2.6.32-16.24) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * armel -- perf userspace does not support arm
+  * ia64 -- libelf-dev/binutils-dev to not provide necessary libraries
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 06 Mar 2010 11:42:12 +0000
+
+linux (2.6.32-16.23) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: PM report driver and device suspend/resume times -- move config
+  * update to standards version 3.8.4.0
+  * printenv -- expose all of the package selectors
+  * source package -- cleanup source content control
+  * doc package -- ensure we do build package content on buildd
+  * lintian -- correct the address in the debian/copyright
+  * lintian -- update debhelper package version dependancy
+  * lintian -- fix ghostscript dependancy
+  * lintian -- add required misc:Depends
+  * lintian -- move our debhelper compat level to debian/compat
+  * perf -- build the kernel carried tools
+  * perf -- add linux-tools carrying the version switches and manuals
+  * SAUCE: fix up Kconfig for staging drivers
+  * [Config] enable NOUVEAU etc following drm backport
+  * update DRM to mainline v2.6.33
+  * [Config] Remove AppArmor config options that no longer exist (ports)
+  * [Config] updateportsconfigs following drm update
+
+  [ John Johansen ]
+
+  * ubuntu: AppArmor -- update to mainline 2010-03-04
+  * SAUCE: AppArmor: Reintroduce AppArmor 2.4 compatibility
+  * SAUCE: AppArmor: replace strim with strstrip for 2.6.32 kernels
+  * [Config] Remove AppArmor config options that no longer exist
+
+  [ Manoj Iyer ]
+
+  * ubuntu: rtl8192se -- version 2010-0115,0014
+    - LP: #530275
+  * [Config] added CONFIG_RTL8192SE module.
+    - LP: #530275
+
+  [ Tim Gardner ]
+
+  * [Config] Added vmw_pvscsi to d-i/scsi-modules
+    - LP: #531017
+  * [Upstream] netfilter: xt_recent: Add an entry reaper
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "KVM: x86 emulator: Check CPL level during privilege instruction
+    emulation"
+  * Revert "KVM: x86 emulator: Fix popf emulation"
+  * Revert "KVM: x86 emulator: Check IOPL level during io instruction
+    emulation"
+  * Revert "KVM: x86 emulator: Add Virtual-8086 mode of emulation"
+  * Revert "KVM: fix memory access during x86 emulation."
+  * Add vlan (8021.Q) module package for d-i.
+  * (pre-stable) drm/i915: blacklist lid status: Sony VGN-BX196VP, Dell
+    Inspiron 700m
+    - LP: #515246
+  * [Upstream] docbook: need xmldoclinks for all doc types
+  * x86: set_personality_ia32() misses force_personality32
+  * lib: Introduce generic list_sort function
+  * drm/nv50: Implement ctxprog/state generation.
+  * drm/nv50: Remove redundant/incorrect ctxvals initialisation.
+  * (pre-stable) drm/i915: blacklist lid status: Sony VGN-BX196VP, Dell
+    Inspiron 700m
+    - LP: #515246
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Mar 2010 15:40:38 +0000
+
+linux (2.6.32-15.22) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] added new config option CONFIG_SR_REPORT_TIME_LIMIT"
+  * Revert "SAUCE: PM report driver and device suspend/resume times."
+  * [Config] set CONFIG_SR_REPORT_TIME_LIMIT
+
+  [ Manoj Iyer ]
+
+  * SAUCE: PM report driver and device suspend/resume times.
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 02 Mar 2010 01:35:37 +0000
+
+linux (2.6.32-15.21) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "(pre-stable) drm/i915: Increase fb alignment to 64k"
+  * Revert "[Config] lenovo-sl-laptop -- enable"
+  * Revert "ubuntu: lenovo-sl-laptop -- git tip (b19a08f81f)"
+  * armel -- cramfs module will no longer be built
+  * d-i -- make all modules optional
+  * rename the debug packages to match archive standard
+    - LP: #527837
+  * lenovo-sl-laptop is no longer built
+
+  [ Colin Ian King ]
+
+  * Disable 4MB page tables for Atom, work around errata AAE44
+    - LP: #523112
+
+  [ Colin Watson ]
+
+  * ubuntu: dm-raid4-5: Depend on XOR_BLOCKS
+  * ubuntu: fsam7400: Depend on CHECK_SIGNATURE
+
+  [ Jesse Barnes ]
+
+  * SAUCE: drm/i915: don't change DRM configuration when releasing load
+    detect pipe
+    - LP: #488328
+
+  [ Loïc Minier ]
+
+  * [Config] armel Update versatile initrd configs
+    - LP: #524893
+  * SAUCE: [um] Don't use nx_enabled under UML
+    - LP: #524849
+
+  [ Manoj Iyer ]
+
+  * [Config] added new config option CONFIG_SR_REPORT_TIME_LIMIT
+
+  [ Mario Limonciello ]
+
+  * SAUCE: v3 - Add Dell Business Class Netbook LED driver
+
+  [ Rafael J. Wysocki ]
+
+  * SAUCE: PM report driver and device suspend/resume times.
+
+  [ Surbhi Palande ]
+
+  * Revert "[Upstream] e1000e: enhance frame fragment detection"
+    - CVE-2009-4538
+  * Revert "[Upstream] e1000: enhance frame fragment detection"
+    - CVE-2009-4536
+
+  [ Tim Gardner ]
+
+  * [Config] Enabled CONFIG_LEDS_DELL_NETBOOKS=m
+  * SAUCE: (pre-stable) netfilter: xt_recent: fix buffer overflow
+  * SAUCE: (pre-stable) netfilter: xt_recent: fix false match
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "(pre-stable) eCryptfs: Add getattr function"
+  * Fix potential crash with sys_move_pages
+  * futex_lock_pi() key refcnt fix
+  * futex: Handle user space corruption gracefully
+  * futex: Handle futex value corruption gracefully
+  * Fix race in tty_fasync() properly
+  * hwmon: (w83781d) Request I/O ports individually for probing
+  * hwmon: (lm78) Request I/O ports individually for probing
+  * hwmon: (adt7462) Wrong ADT7462_VOLT_COUNT
+  * ALSA: ctxfi - fix PTP address initialization
+  * drm/i915: disable hotplug detect before Ironlake CRT detect
+  * drm/i915: enable self-refresh on 965
+  * drm/i915: Disable SR when more than one pipe is enabled
+  * drm/i915: Fix DDC on some systems by clearing BIOS GMBUS setup.
+  * drm/i915: Add HP nx9020/SamsungSX20S to ACPI LID quirk list
+  * drm/i915: Fix the incorrect DMI string for Samsung SX20S laptop
+  * drm/i915: Add MALATA PC-81005 to ACPI LID quirk list
+  * usb: r8a66597-hcd: Flush the D-cache for the pipe-in transfer buffers.
+  * i2c-tiny-usb: Fix on big-endian systems
+  * drm/i915: handle FBC and self-refresh better
+  * drm/i915: Increase fb alignment to 64k
+  * drm/i915: Update write_domains on active list after flush.
+  * regulator: Fix display of null constraints for regulators
+  * ALSA: hda-intel: Avoid divide by zero crash
+  * CPUFREQ: Fix use after free of struct powernow_k8_data
+  * freeze_bdev: don't deactivate successfully frozen MS_RDONLY sb
+  * cciss: Make cciss_seq_show handle holes in the h->drv[] array
+  * ioat: fix infinite timeout checking in ioat2_quiesce
+  * resource: add helpers for fetching rlimits
+  * fs/exec.c: restrict initial stack space expansion to rlimit
+  * cifs: fix length calculation for converted unicode readdir names
+  * NFS: Fix a reference leak in nfs_wb_cancel_page()
+  * NFS: Try to commit unstable writes in nfs_release_page()
+  * NFSv4: Don't allow posix locking against servers that don't support it
+  * NFSv4: Ensure that the NFSv4 locking can recover from stateid errors
+  * NFS: Fix an Oops when truncating a file
+  * NFS: Fix a umount race
+  * NFS: Fix a bug in nfs_fscache_release_page()
+  * NFS: Fix the mapping of the NFSERR_SERVERFAULT error
+  * md: fix 'degraded' calculation when starting a reshape.
+  * V4L/DVB: dvb-core: fix initialization of feeds list in demux filter
+  * Export the symbol of getboottime and mmonotonic_to_bootbased
+  * kvmclock: count total_sleep_time when updating guest clock
+  * KVM: PIT: control word is write-only
+  * tpm_infineon: fix suspend/resume handler for pnp_driver
+  * amd64_edac: Do not falsely trigger kerneloops
+  * netfilter: nf_conntrack: fix memory corruption with multiple namespaces
+  * netfilter: nf_conntrack: per netns nf_conntrack_cachep
+  * netfilter: nf_conntrack: restrict runtime expect hashsize modifications
+  * netfilter: xtables: compat out of scope fix
+  * netfilter: nf_conntrack: fix hash resizing with namespaces
+  * drm/i915: remove full registers dump debug
+  * drm/i915: add i915_lp_ring_sync helper
+  * drm/i915: Don't wait interruptible for possible plane buffer flush
+  * dasd: remove strings from s390dbf
+  * crypto: padlock-sha - Add import/export support
+  * wmi: Free the allocated acpi objects through wmi_get_event_data
+  * dell-wmi, hp-wmi, msi-wmi: check wmi_get_event_data() return value
+  * /dev/mem: introduce size_inside_page()
+  * devmem: check vmalloc address on kmem read/write
+  * devmem: fix kmem write bug on memory holes
+  * SCSI: mptfusion : mptscsih_abort return value should be SUCCESS instead
+    of value 0.
+  * sh: Couple kernel and user write page perm bits for CONFIG_X2TLB
+  * ALSA: hda - use WARN_ON_ONCE() for zero-division detection
+  * dst: call cond_resched() in dst_gc_task()
+  * ALSA: hda - Improved MacBook (Pro) 5,1 / 5,2 support
+  * befs: fix leak
+  * rtc-fm3130: add missing braces
+  * Call flush_dcache_page after PIO data transfers in libata-sff.c
+  * ahci: add Acer G725 to broken suspend list
+  * pktgen: Fix freezing problem
+  * x86/amd-iommu: Fix IOMMU-API initialization for iommu=pt
+  * x86/amd-iommu: Fix deassignment of a device from the pt_domain
+  * x86: Re-get cfg_new in case reuse/move irq_desc
+  * Staging: fix rtl8187se compilation errors with mac80211
+  * ALSA: usb-audio - Avoid Oops after disconnect
+  * serial: 8250: add serial transmitter fully empty test
+  * sysfs: sysfs_sd_setattr set iattrs unconditionally
+  * class: Free the class private data in class_release
+  * USB: usbfs: only copy the actual data received
+  * USB: usbfs: properly clean up the as structure on error paths
+  * rtl8187: Add new device ID
+  * ACPI: Add NULL pointer check in acpi_bus_start
+  * ACPI: fix High cpu temperature with 2.6.32
+  * drm/radeon/kms: use udelay for short delays
+  * NFS: Too many GETATTR and ACCESS calls after direct I/O
+  * eCryptfs: Add getattr function
+  * b43: Fix throughput regression
+  * ath9k: Fix sequence numbers for PAE frames
+  * mac80211: Fix probe request filtering in IBSS mode
+  * iwlwifi: Fix to set correct ht configuration
+  * dm stripe: avoid divide by zero with invalid stripe count
+  * dm log: userspace fix overhead_size calcuations
+  * Linux 2.6.32.9
+  * sfc: Fix SFE4002 initialisation
+  * sfc: Fix sign of efx_mcdi_poll_reboot() error in efx_mcdi_poll()
+  * sfc: SFE4002/SFN4112F: Widen temperature and voltage tolerances
+  * (pre-stable) HID: handle joysticks with large number of buttons
+    - LP: #492056
+  * (pre-stable) HID: extend mask for BUTTON usage page
+    - LP: #492056
+  * PM: Measure device suspend and resume times
+  * e1000: enhance frame fragment detection
+    - CVE-2009-4536
+  * e1000e: enhance frame fragment detection
+    - CVE-2009-4538
+  * KVM: fix memory access during x86 emulation.
+    - CVE-2010-0306
+  * KVM: x86 emulator: Add Virtual-8086 mode of emulation
+    - CVE-2010-0306
+  * KVM: x86 emulator: Check IOPL level during io instruction emulation
+    - CVE-2010-0306
+  * KVM: x86 emulator: Fix popf emulation
+    - CVE-2010-0306
+  * KVM: x86 emulator: Check CPL level during privilege instruction
+    emulation
+    - CVE-2010-0306
+  * Input: wacom - ensure the device is initialized properly upon resume
+  * Input: wacom - add defines for packet lengths of various devices
+  * Input: wacom - add support for new LCD tablets
+    - LP: #516777
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 01 Mar 2010 22:56:28 +0000
+
+linux (2.6.32-14.20) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebuild following the GCC update to match compiler for out of tree modules
+  * Revert "[Config] drbd -- enable"
+  * Revert "ubuntu: drbd -- version 8.3.1"
+  * SAUCE: khubd -- switch USB product/manufacturer/serial handling to RCU
+    - LP: #510937
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 19 Feb 2010 18:47:18 +0000
+
+linux (2.6.32-14.19) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ensure we build the source package contents when enabled
+    - LP: #522308
+  * [Config] enable CONFIG_X86_MCE_XEON75XX
+  * SAUCE: AppArmor -- add linux/kref.h for struct kref
+  * [Config] enable CONFIG_HID_ORTEK
+  * enable udeb generation for arm versatile flavour
+    - LP: #522515
+
+  [ John Johansen ]
+
+  * ubuntu: AppArmor -- update to mainline 2010-02-18
+    - LP: #439560, #496110, #507069
+
+  [ Johnathon Harris ]
+
+  * SAUCE: HID: add support for Ortek WKB-2000
+    - LP: #405390
+
+  [ Upstream Kernel Changes ]
+
+  * tpm_tis: TPM_STS_DATA_EXPECT workaround
+    - LP: #490487
+  * x86, mce: Xeon75xx specific interface to get corrected memory error
+    information
+  * x86, mce: Rename cpu_specific_poll to mce_cpu_specific_poll
+  * x86, mce: Make xeon75xx memory driver dependent on PCI
+  * drm/edid: Unify detailed block parsing between base and extension
+    blocks
+    - LP: #500999
+  * (pre-stable) eCryptfs: Add getattr function
+    - LP: #390833
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 18 Feb 2010 19:22:02 +0000
+
+linux (2.6.32-13.18) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "enforcer -- make the enforcement configuration common"
+  * Revert "(pre-stable) Input: ALPS - add interleaved protocol support
+    (Dell E6x00 series)"
+  * Revert "(pre-stable) driver-core: fix devtmpfs crash on s390"
+  * Revert "(pre-stable) Driver-Core: devtmpfs - set root directory mode to
+    0755"
+  * Revert "SAUCE: Adds support for COMPAL JHL90 webcam"
+  * Revert "SAUCE: fix kernel oops in VirtualBox during paravirt patching"
+  * Revert "SAUCE: make fc transport removal of target configurable"
+  * enforcer -- make the enforcement configuration common
+  * getabis -- add preempt flavour to the list
+  * [Config] enforce DEVTMPFS options
+  * [Config] armel -- cleanup to-be builtin modules
+  * [Config] cleanup ports configs
+  * [Config] enable CRYPTO_GHASH_CLMUL_NI_INTEL
+    - LP: #485536
+  * add printdebian target to find branch target
+  * distclean -- do not remove debian.env
+  * [Config] generic-pae switch to M586TSC
+    - LP: #519448
+  * git-ubuntu-log -- commonise duplicated log handling
+  * git-ubuntu-log -- tighten up Bug: NNNN matching
+  * git-ubuntu-log -- sort the bug numbers
+
+  [ Chris Wilson ]
+
+  * (pre-stable) drm/i915: Increase fb alignment to 64k
+    - LP: #404064
+
+  [ Eric Miao ]
+
+  * arm -- enable ubuntu/ directory
+
+  [ Huang Ying ]
+
+  * SAUCE: crypto: ghash - Add PCLMULQDQ accelerated implementation
+  * SAUCE: crypto: ghash-intel - Fix building failure on x86_32
+
+  [ Loïc Minier ]
+
+  * [Config] cleanup preempt configuration
+  * [Config] versatile: Fix video output
+    - LP: #517594
+  * [Config] armel DEFAULT_MMAP_MIN_ADDR=32768
+  * [Config] Large update to armel/versatile
+  * [Config] versatile: Add RTC support
+  * [Config] armel: Enable NEON
+  * [Config] versatile: Builtin MMC support
+  * [Config] versatile Builtin SCSI controller
+  * [Config] armel Disable dma_cache_sync callers
+  * [Config] armel Disable asm/time.h users
+  * [Config] armel Disable out of range udelay()
+  * [Config] armel Disable flush_cache_range() users
+  * [Config] armel -- Enable ubuntu/ drivers
+
+  [ Steve Conklin ]
+
+  * SAUCE: drm/i915: Add display hotplug event on Ironlake
+  * SAUCE: drm/i915: Add ACPI OpRegion support for Ironlake
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[Upstream]: oprofile/x86: add Xeon 7500 series support"
+  * Revert "Revert "[Bluetooth] Eliminate checks for impossible conditions
+    in IRQ handler""
+  * clockevent: Don't remove broadcast device when cpu is dead
+  * clockevents: Add missing include to pacify sparse
+  * ACPI: don't cond_resched if irq is disabled
+  * be2net: Add support for next generation of BladeEngine device.
+  * be2net: Add the new PCI IDs to PCI_DEVICE_TABLE.
+  * mpt2sas: New device SAS2208 support is added
+  * ar9170: Add support for D-Link DWA 160 A2
+  * powerpc/fsl: Add PCI device ids for new QoirQ chips
+  * davinci: dm646x: Add support for 3.x silicon revision
+  * Input: ALPS - add interleaved protocol support (Dell E6x00 series)
+  * Driver-Core: devtmpfs - set root directory mode to 0755
+  * driver-core: fix devtmpfs crash on s390
+  * vfs: get_sb_single() - do not pass options twice
+  * ALSA: hda - Add PCI IDs for Nvidia G2xx-series
+  * V4L/DVB (13569): smsusb: add autodetection support for five additional
+    Hauppauge USB IDs
+  * USB: mos7840: add device IDs for B&B electronics devices
+  * USB: ftdi_sio: add USB device ID's for B&B Electronics line
+  * V4L/DVB (13168): Add support for Asus Europa Hybrid DVB-T card (SAA7134
+    SubVendor ID: 0x1043 Device ID: 0x4847)
+  * iTCO_wdt: Add support for Intel Ibex Peak
+  * atl1c:use common_task instead of reset_task and link_chg_task
+  * atl1e:disable NETIF_F_TSO6 for hardware limit
+  * V4L/DVB (13680a): DocBook/media: copy images after building HTML
+  * V4L/DVB (13680b): DocBook/media: create links for included sources
+  * netfilter: xtables: fix conntrack match v1 ipt-save output
+  * partitions: read whole sector with EFI GPT header
+  * partitions: use sector size for EFI GPT
+  * ALSA: ice1724 - Patch for suspend/resume for ESI Juli@
+  * sched: Fix isolcpus boot option
+  * sched: Fix missing sched tunable recalculation on cpu add/remove
+  * nohz: Prevent clocksource wrapping during idle
+  * nfsd: Fix sort_pacl in fs/nfsd/nf4acl.c to actually sort groups
+  * timers, init: Limit the number of per cpu calibration bootup messages
+  * PCI: Always set prefetchable base/limit upper32 registers
+  * iscsi class: modify handling of replacement timeout
+  * NFS: Revert default r/wsize behavior
+  * HID: fixup quirk for NCR devices
+  * scsi_devinfo: update Hitachi entries (v2)
+  * scsi_dh: create sysfs file, dh_state for all SCSI disk devices
+  * scsi_transport_fc: remove invalid BUG_ON
+  * lpfc: fix hang on SGI ia64 platform
+  * libfc: fix typo in retry check on received PRLI
+  * libfc: fix ddp in fc_fcp for 0 xid
+  * fcoe: remove redundant checking of netdev->netdev_ops
+  * libfc: Fix wrong scsi return status under FC_DATA_UNDRUN
+  * libfc: lport: fix minor documentation errors
+  * libfc: don't WARN_ON in lport_timeout for RESET state
+  * fcoe: initialize return value in fcoe_destroy
+  * libfc: Fix frags in frame exceeding SKB_MAX_FRAGS in fc_fcp_send_data
+  * libfc: fix memory corruption caused by double frees and bad error
+    handling
+  * libfc: fix free of fc_rport_priv with timer pending
+  * libfc: remote port gets stuck in restart state without really
+    restarting
+  * fcoe, libfc: fix an libfc issue with queue ramp down in libfc
+  * fcoe: Fix checking san mac address
+  * fcoe: Fix getting san mac for VLAN interface
+  * qlge: Remove explicit setting of PCI Dev CTL reg.
+  * qlge: Set PCIE max read request size.
+  * qlge: Don't fail open when port is not initialized.
+  * qlge: Add handler for DCBX firmware event.
+  * qlge: Bonding fix for mode 6.
+  * PCI: AER: fix aer inject result in kernel oops
+  * DMI: allow omitting ident strings in DMI tables
+  * Input: i8042 - remove identification strings from DMI tables
+  * Input: i8042 - add Gigabyte M1022M to the noloop list
+  * Input: i8042 - add Dritek quirk for Acer Aspire 5610.
+  * ALSA: hda - select IbexPeak handler for Calpella
+  * ALSA: hda - Fix quirk for Maxdata obook4-1
+  * ALSA: hda - Add missing Line-Out and PCM switches as slave
+  * iTCO_wdt.c - cleanup chipset documentation
+  * iTCO_wdt: add PCI ID for the Intel EP80579 (Tolapai) SoC
+  * iTCO_wdt: Add Intel Cougar Point and PCH DeviceIDs
+  * ahci: disable SNotification capability for ich8
+  * ata_piix: fix MWDMA handling on PIIX3
+  * md: fix small irregularity with start_ro module parameter
+  * V4L/DVB (13826): uvcvideo: Fix controls blacklisting
+  * cio: fix double free in case of probe failure
+  * cio: dont panic in non-fatal conditions
+  * netiucv: displayed TX bytes value much too high
+  * ipc ns: fix memory leak (idr)
+  * ALSA: hda - Fix HP T5735 automute
+  * hwmon: (fschmd) Fix a memleak on multiple opens of /dev/watchdog
+  * UBI: fix memory leak in update path
+  * UBI: initialise update marker
+  * ASoC: fix a memory-leak in wm8903
+  * mac80211: check that ieee80211_set_power_mgmt only handles STA
+    interfaces.
+  * cfg80211: fix channel setting for wext
+  * KVM: S390: fix potential array overrun in intercept handling
+  * KVM: only allow one gsi per fd
+  * KVM: Fix race between APIC TMR and IRR
+  * KVM: MMU: bail out pagewalk on kvm_read_guest error
+  * KVM: x86: Fix host_mapping_level()
+  * KVM: x86: Fix probable memory leak of vcpu->arch.mce_banks
+  * KVM: x86: Fix leak of free lapic date in kvm_arch_vcpu_init()
+  * KVM: fix lock imbalance in kvm_*_irq_source_id()
+  * KVM: only clear irq_source_id if irqchip is present
+  * IPoIB: Clear ipoib_neigh.dgid in ipoib_neigh_alloc()
+  * x86: Reenable TSC sync check at boot, even with NONSTOP_TSC
+  * ACPI: enable C2 and Turbo-mode on Nehalem notebooks on A/C
+    - LP: #516325
+  * iwlwifi: Fix throughput stall issue in HT mode for 5000
+  * fnctl: f_modown should call write_lock_irqsave/restore
+  * x86, msr/cpuid: Pass the number of minors when unregistering MSR and
+    CPUID drivers.
+  * Linux 2.6.32.7
+  * scsi_lib: Fix bug in completion of bidi commands
+  * mptsas: Fix issue with chain pools allocation on katmai
+  * mm: add new 'read_cache_page_gfp()' helper function
+  * drm/i915: Selectively enable self-reclaim
+  * firewire: ohci: fix crashes with TSB43AB23 on 64bit systems
+  * S390: fix single stepped svcs with TRACE_IRQFLAGS=y
+  * x86: Set hotpluggable nodes in nodes_possible_map
+  * x86: Remove "x86 CPU features in debugfs" (CONFIG_X86_CPU_DEBUG)
+  * libata: retry FS IOs even if it has failed with AC_ERR_INVALID
+  * zcrypt: Do not remove coprocessor for error 8/72
+  * dasd: fix possible NULL pointer errors
+  * ACPI: Add a generic API for _OSC -v2
+  * ACPI: Add platform-wide _OSC support.
+  * ACPI: fix OSC regression that caused aer and pciehp not to load
+  * ACPI: Advertise to BIOS in _OSC: _OST on _PPC changes
+  * UBI: fix volume creation input checking
+  * e1000/e1000e: don't use small hardware rx buffers
+  * drm/i915: Reload hangcheck timer too for Ironlake
+  * Fix a leak in affs_fill_super()
+  * Fix failure exits in bfs_fill_super()
+  * fix oops in fs/9p late mount failure
+  * fix leak in romfs_fill_super()
+  * Fix remount races with symlink handling in affs
+  * fix affs parse_options()
+  * Fix failure exit in ipathfs
+  * mm: fix migratetype bug which slowed swapping
+  * FDPIC: Respect PT_GNU_STACK exec protection markings when creating
+    NOMMU stack
+  * Split 'flush_old_exec' into two functions
+  * sparc: TIF_ABI_PENDING bit removal
+  * x86: get rid of the insane TIF_ABI_PENDING bit
+  * Input: winbond-cir - remove dmesg spam
+  * x86: Disable HPET MSI on ATI SB700/SB800
+  * iwlwifi: set default aggregation frame count limit to 31
+  * drm/i915: only enable hotplug for detected outputs
+  * firewire: core: add_descriptor size check
+  * SECURITY: selinux, fix update_rlimit_cpu parameter
+  * regulator: Specify REGULATOR_CHANGE_STATUS for WM835x LED constraints
+  * x86: Add Dell OptiPlex 760 reboot quirk
+    - LP: #488319
+  * x86: Add quirk for Intel DG45FC board to avoid low memory corruption
+  * x86/amd-iommu: Fix possible integer overflow
+  * clocksource: fix compilation if no GENERIC_TIME
+  * tcp: update the netstamp_needed counter when cloning sockets
+  * sky2: Fix oops in sky2_xmit_frame() after TX timeout
+  * net: restore ip source validation
+  * af_packet: Don't use skb after dev_queue_xmit()
+  * ax25: netrom: rose: Fix timer oopses
+  * KVM: allow userspace to adjust kvmclock offset
+  * oprofile/x86: add Xeon 7500 series support
+  * oprofile/x86: fix crash when profiling more than 28 events
+  * libata: retry link resume if necessary
+  * mm: percpu-vmap fix RCU list walking
+  * mm: purge fragmented percpu vmap blocks
+  * block: fix bio_add_page for non trivial merge_bvec_fn case
+  * Fix 'flush_old_exec()/setup_new_exec()' split
+  * random: drop weird m_time/a_time manipulation
+  * random: Remove unused inode variable
+  * block: fix bugs in bio-integrity mempool usage
+  * usb: r8a66597-hdc disable interrupts fix
+  * connector: Delete buggy notification code.
+  * be2net: Bug fix to support newer generation of BE ASIC
+  * be2net: Fix memset() arg ordering.
+  * mm: flush dcache before writing into page to avoid alias
+  * mac80211: fix NULL pointer dereference when ftrace is enabled
+  * imxfb: correct location of callbacks in suspend and resume
+  * mx3fb: some debug and initialisation fixes
+  * starfire: clean up properly if firmware loading fails
+  * kernel/cred.c: use kmem_cache_free
+  * uartlite: fix crash when using as console
+  * pktcdvd: removing device does not remove its sysfs dir
+  * ath9k: fix eeprom INI values override for 2GHz-only cards
+  * ath9k: fix beacon slot/buffer leak
+  * powerpc: TIF_ABI_PENDING bit removal
+  * NET: fix oops at bootime in sysctl code
+  * Linux 2.6.32.8
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 10 Feb 2010 18:56:52 +0000
+
+linux (2.6.32-12.17) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * restore linux-image prefix -- master
+  * enforce -- we require SELINUX enabled -- master
+  * enforce -- ensure APPARMOR is our default LSM -- master
+  * make doc package completely optional -- master
+  * make source package completely optional -- master
+  * make linux-libc-dev completly optional -- master
+  * convert package disable to a deps list -- master
+  * allow common headers to switch from indep to arch -- master
+  * convert binary package disable to a deps list -- master
+  * add configuration option for a full source build tree -- master
+  * add support for uImage kernels in package control scripts
+  * getabis -- cleanup and parameterise repository list -- master
+  * getabis -- move configuration to etc/getabi -- master
+  * kernelconfig -- move configuration to etc -- master
+  * rules -- make debian/debian.env master for branch name
+  * set the current branch name -- master
+  * pull back common debian.master files into debian -- master
+  * enforcer -- make the enforcement configuration common
+  * insert-changes -- correctly link to debian/rules in DROOT
+
+  [ Colin Watson ]
+
+  * future-proof ddeb handling against buildd changes
+
+  [ Eric Miao ]
+
+  * SAUCE: Make CONFIG_{OMNIBOOK, AVERATEC_5100P, PACKARDBELL_E5} depend on
+    X86
+
+  [ Loïc Minier ]
+
+  * Add modules.builtin.bin to prerm rm list
+    - LP: #516584
+
+  [ Tim Gardner ]
+
+  * [Config] Implement the amd64 preempt flavour
+
+  [ Upstream Kernel Changes ]
+
+  * syslog: distinguish between /proc/kmsg and syscalls
+    - LP: #515623
+  * sfc: Fix polling for slow MCDI operations
+  * sfc: Fix conditions for MDIO self-test
+  * sfc: QT202x: Remove unreliable MMD check at initialisation
+  * sfc: Add workspace for GMAC bug workaround to MCDI MAC_STATS buffer
+  * sfc: Use fixed-size buffers for MCDI NVRAM requests
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Feb 2010 07:09:31 +0000
+
+linux (2.6.32-12.16) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: acpi battery -- delay first lookup of the battery until
+    first use"
+  * SAUCE: acpi battery -- move first lookup asynchronous
+    - LP: #507211
+  * [Config] update configs to cleanup generic configs
+  * [Config] disable CONFIG_X86_CPU_DEBUG for amd64
+  * [Config] enable USER_NS
+    - LP: #480739, #509808
+
+  [ Heiko Carstens ]
+
+  * (pre-stable) driver-core: fix devtmpfs crash on s390
+    - LP: #512370
+
+  [ John Johansen ]
+
+  * [Config] for server and virtual flavours make CONFIG_SCSI_SYM53C8XX_2=y
+    - LP: #494565
+  * [Config] VIRTIO=y for server/virtual flavours
+    - LP: #494565
+
+  [ Kay Sievers ]
+
+  * (pre-stable) Driver-Core: devtmpfs - set root directory mode to 0755
+    - LP: #512370
+
+  [ Kees Cook ]
+
+  * SAUCE: x86: brk away from exec rand area
+    - LP: #452175
+
+  [ Leann Ogasawara ]
+
+  * [Upstream] e1000: enhance frame fragment detection
+    - CVE-2009-4536
+  * [Upstream] e1000e: enhance frame fragment detection
+    - CVE-2009-4538
+
+  [ Sebastian Kapfer ]
+
+  * (pre-stable) Input: ALPS - add interleaved protocol support (Dell E6x00
+    series)
+    - LP: #296610
+
+  [ Upstream Kernel Changes ]
+
+  * inotify: do not reuse watch descriptors
+    - LP: #485556
+  * inotify: only warn once for inotify problems
+  * revert "drivers/video/s3c-fb.c: fix clock setting for Samsung SoC
+    Framebuffer"
+  * memcg: ensure list is empty at rmdir
+  * drm/i915: remove loop in Ironlake interrupt handler
+  * block: Fix incorrect reporting of partition alignment
+  * x86, mce: Thermal monitoring depends on APIC being enabled
+  * futexes: Remove rw parameter from get_futex_key()
+  * page allocator: update NR_FREE_PAGES only when necessary
+  * x86, apic: use physical mode for IBM summit platforms
+  * edac: i5000_edac critical fix panic out of bounds
+  * x86: SGI UV: Fix mapping of MMIO registers
+  * mfd: WM835x GPIO direction register is not locked
+  * mfd: Correct WM835x ISINK ramp time defines
+  * ALSA: hda - Fix missing capture mixer for ALC861/660 codecs
+  * V4L/DVB (13868): gspca - sn9c20x: Fix test of unsigned.
+  * reiserfs: truncate blocks not used by a write
+  * HID: add device IDs for new model of Apple Wireless Keyboard
+  * PCI/cardbus: Add a fixup hook and fix powerpc
+  * Input: pmouse - move Sentelic probe down the list
+  * asus-laptop: add Lenovo SL hotkey support
+  * sched: Fix cpu_clock() in NMIs, on !CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
+  * sparc64: Fix NMI programming when perf events are active.
+  * sparc64: Fix Niagara2 perf event handling.
+  * i2c: Do not use device name after device_unregister
+  * i2c/pca: Don't use *_interruptible
+  * serial/8250_pnp: add a new Fujitsu Wacom Tablet PC device
+  * sched: Fix task priority bug
+  * vfs: Fix vmtruncate() regression
+  * Linux 2.6.32.5
+  * x86, msr/cpuid: Register enough minors for the MSR and CPUID drivers
+  * V4L/DVB (13900): gspca - sunplus: Fix bridge exchanges.
+  * Staging: asus_oled: fix oops in 2.6.32.2
+  * Staging: hv: fix smp problems in the hyperv core code
+  * tty: fix race in tty_fasync
+  * ecryptfs: use after free
+  * ecryptfs: initialize private persistent file before dereferencing
+    pointer
+  * nozomi: quick fix for the close/close bug
+  * serial: 8250_pnp: use wildcard for serial Wacom tablets
+  * usb: serial: fix memory leak in generic driver
+  * USB: fix bitmask merge error
+  * USB: Don't use GFP_KERNEL while we cannot reset a storage device
+  * USB: EHCI: fix handling of unusual interrupt intervals
+  * USB: EHCI & UHCI: fix race between root-hub suspend and port resume
+  * USB: add missing delay during remote wakeup
+  * USB: add speed values for USB 3.0 and wireless controllers
+  * ACPI: EC: Accelerate query execution
+  * ACPI: EC: Add wait for irq storm
+  * SCSI: enclosure: fix oops while iterating enclosure_status array
+  * drm/i915: Read the response after issuing DDC bus switch command
+  * drm/i915: try another possible DDC bus for the SDVO device with
+    multiple outputs
+  * block: bdev_stack_limits wrapper
+  * DM: Fix device mapper topology stacking
+  * x86/PCI/PAT: return EINVAL for pci mmap WC request for !pat_enabled
+  * USB: fix usbstorage for 2770:915d delivers no FAT
+  * vmalloc: remove BUG_ON due to racy counting of VM_LAZY_FREE
+  * perf timechart: Use tid not pid for COMM change
+  * perf events: Dont report side-band events on each cpu for
+    per-task-per-cpu events
+  * perf: Honour event state for aux stream data
+  * Linux 2.6.32.6
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 27 Jan 2010 16:40:23 +0000
+
+linux (2.6.32-11.15) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "(pre-stable) drm/radeon/kms: fix crtc vblank update for r600"
+  * Revert "(pre-stable) sched: Fix balance vs hotplug race"
+  * Revert "[Upstream] acerhdf: Limit modalias matching to supported
+    boards"
+  * Revert "[Upstream] mmc: prevent dangling block device from accessing
+    stale queues"
+  * Revert "SAUCE: Fix nx_enable reporting"
+  * Revert "SAUCE: [x86] fix report of cs-limit nx-emulation"
+  * Revert "SAUCE: [x86] implement cs-limit nx-emulation for ia32"
+  * SAUCE: i915 -- disable powersave by default
+    - LP: #492392
+
+  [ Kees Cook ]
+
+  * SAUCE: [x86] implement cs-limit nx-emulation for ia32
+    - LP: #369978
+  * SAUCE: [x86] fix report of cs-limit nx-emulation
+    - LP: #454285
+  * SAUCE: Fix nx_enable reporting
+    - LP: #454285
+
+  [ Tim Gardner ]
+
+  * [Upstream] b43: Declare all possible firmware files.
+    - LP: #488636
+  * [Config] updateconfigs after adding pvscsi
+    - LP: #497156
+  * [Config] CONFIG_BT=m
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "x86: Side-step lguest problem by only building cmpxchg8b_emu
+    for pre-Pentium"
+  * SCSI: ipr: fix EEH recovery
+  * SCSI: qla2xxx: dpc thread can execute before scsi host has been added
+  * SCSI: st: fix mdata->page_order handling
+  * SCSI: fc class: fix fc_transport_init error handling
+  * sched: Fix task_hot() test order
+  * x86, cpuid: Add "volatile" to asm in native_cpuid()
+  * sched: Select_task_rq_fair() must honour SD_LOAD_BALANCE
+  * clockevents: Prevent clockevent_devices list corruption on cpu hotplug
+  * pata_hpt3x2n: fix clock turnaround
+  * pata_cmd64x: fix overclocking of UDMA0-2 modes
+  * ASoC: wm8974: fix a wrong bit definition
+  * sound: sgio2audio/pdaudiocf/usb-audio: initialize PCM buffer
+  * ALSA: hda - Fix missing capsrc_nids for ALC88x
+  * acerhdf: limit modalias matching to supported
+    - LP: #435958
+  * ACPI: EC: Fix MSI DMI detection
+  * ACPI: Use the return result of ACPI lid notifier chain correctly
+  * powerpc: Handle VSX alignment faults correctly in little-endian mode
+  * ASoC: Do not write to invalid registers on the wm9712.
+  * drm/radeon: fix build on 64-bit with some compilers.
+  * USB: emi62: fix crash when trying to load EMI 6|2 firmware
+  * USB: option: support hi speed for modem Haier CE100
+  * USB: Fix a bug on appledisplay.c regarding signedness
+  * USB: musb: gadget_ep0: avoid SetupEnd interrupt
+  * Bluetooth: Prevent ill-timed autosuspend in USB driver
+  * USB: rename usb_configure_device
+  * USB: fix bugs in usb_(de)authorize_device
+  * drivers/net/usb: Correct code taking the size of a pointer
+  * x86: SGI UV: Fix writes to led registers on remote uv hubs
+  * md: Fix unfortunate interaction with evms
+  * dma: at_hdmac: correct incompatible type for argument 1 of
+    'spin_lock_bh'
+  * dma-debug: Do not add notifier when dma debugging is disabled.
+  * dma-debug: Fix bug causing build warning
+  * cifs: NULL out tcon, pSesInfo, and srvTcp pointers when chasing DFS
+    referrals
+  * x86/amd-iommu: Fix initialization failure panic
+  * ioat3: fix p-disabled q-continuation
+  * ioat2,3: put channel hardware in known state at init
+  * KVM: MMU: remove prefault from invlpg handler
+  * KVM: LAPIC: make sure IRR bitmap is scanned after vm load
+  * Libertas: fix buffer overflow in lbs_get_essid()
+  * iwmc3200wifi: fix array out-of-boundary access
+  * mac80211: fix propagation of failed hardware reconfigurations
+  * mac80211: fix WMM AP settings application
+  * mac80211: Fix IBSS merge
+  * cfg80211: fix race between deauth and assoc response
+  * ath5k: fix SWI calibration interrupt storm
+  * ath9k: wake hardware for interface IBSS/AP/Mesh removal
+  * ath9k: Fix TX queue draining
+  * ath9k: fix missed error codes in the tx status check
+  * ath9k: wake hardware during AMPDU TX actions
+  * ath9k: fix suspend by waking device prior to stop
+  * ath9k_hw: Fix possible OOB array indexing in gen_timer_index[] on
+    64-bit
+  * ath9k_hw: Fix AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB and its shift value
+    in 0x4054
+  * iwl3945: disable power save
+  * iwl3945: fix panic in iwl3945 driver
+  * iwlwifi: fix EEPROM/OTP reading endian annotations and a bug
+  * iwlwifi: fix more eeprom endian bugs
+  * iwlwifi: fix 40MHz operation setting on cards that do not allow it
+  * mac80211: fix race with suspend and dynamic_ps_disable_work
+  * NOMMU: Optimise away the {dac_,}mmap_min_addr tests
+  * 'sysctl_max_map_count' should be non-negative
+  * kernel/sysctl.c: fix the incomplete part of
+    sysctl_max_map_count-should-be-non-negative.patch
+  * V4L/DVB (13596): ov511.c typo: lock => unlock
+  * x86/ptrace: make genregs[32]_get/set more robust
+  * memcg: avoid oom-killing innocent task in case of use_hierarchy
+  * e100: Fix broken cbs accounting due to missing memset.
+  * ipv6: reassembly: use seperate reassembly queues for conntrack and
+    local delivery
+  * netfilter: fix crashes in bridge netfilter caused by fragment jumps
+  * hwmon: (sht15) Off-by-one error in array index + incorrect constants
+  * b43: avoid PPC fault during resume
+  * Keys: KEYCTL_SESSION_TO_PARENT needs TIF_NOTIFY_RESUME architecture
+    support
+  * sched: Fix balance vs hotplug race
+  * drm/radeon/kms: fix crtc vblank update for r600
+  * drm: disable all the possible outputs/crtcs before entering KMS mode
+  * S390: dasd: support DIAG access for read-only devices
+  * xen: fix is_disconnected_device/exists_disconnected_device
+  * xen: improvement to wait_for_devices()
+  * xen: wait up to 5 minutes for device connetion
+  * orinoco: fix GFP_KERNEL in orinoco_set_key with interrupts disabled
+  * udf: Try harder when looking for VAT inode
+  * Add unlocked version of inode_add_bytes() function
+  * quota: decouple fs reserved space from quota reservation
+  * ext4: Convert to generic reserved quota's space management.
+  * ext4: fix sleep inside spinlock issue with quota and dealloc (#14739)
+  * x86, msr: Unify rdmsr_on_cpus/wrmsr_on_cpus
+  * cpumask: use modern cpumask style in drivers/edac/amd64_edac.c
+  * amd64_edac: unify MCGCTL ECC switching
+  * x86, msr: Add support for non-contiguous cpumasks
+  * x86, msr: msrs_alloc/free for CONFIG_SMP=n
+  * amd64_edac: fix driver instance freeing
+  * amd64_edac: make driver loading more robust
+  * amd64_edac: fix forcing module load/unload
+  * sched: Sched_rt_periodic_timer vs cpu hotplug
+  * ext4: Update documentation to correct the inode_readahead_blks option
+    name
+  * lguest: fix bug in setting guest GDT entry
+  * vmscan: do not evict inactive pages when skipping an active list scan
+  * ksm: fix mlockfreed to munlocked
+  * rt2x00: Disable powersaving for rt61pci and rt2800pci.
+  * generic_permission: MAY_OPEN is not write access
+  * Linux 2.6.32.3
+  * untangle the do_mremap() mess
+  * fasync: split 'fasync_helper()' into separate add/remove functions
+  * ASoC: fix params_rate() macro use in several codecs
+  * modules: Skip empty sections when exporting section notes
+  * exofs: simple_write_end does not mark_inode_dirty
+  * nfsd: make sure data is on disk before calling ->fsync
+  * sunrpc: fix peername failed on closed listener
+  * SUNRPC: Fix up an error return value in
+    gss_import_sec_context_kerberos()
+  * SUNRPC: Fix the return value in gss_import_sec_context()
+  * sunrpc: on successful gss error pipe write, don't return error
+  * drm/i915: Update LVDS connector status when receiving ACPI LID event
+  * drm/i915: fix order of fence release wrt flushing
+  * drm/i915: Permit pinning whilst the device is 'suspended'
+  * drm: remove address mask param for drm_pci_alloc()
+  * drm/i915: Enable/disable the dithering for LVDS based on VBT setting
+  * drm/i915: Make the BPC in FDI rx/transcoder be consistent with that in
+    pipeconf on Ironlake
+  * drm/i915: Select the correct BPC for LVDS on Ironlake
+  * drm/i915: fix unused var
+  * rtc_cmos: convert shutdown to new pnp_driver->shutdown
+  * drivers/cpuidle/governors/menu.c: fix undefined reference to
+    `__udivdi3'
+  * cgroups: fix 2.6.32 regression causing BUG_ON() in cgroup_diput()
+  * lib/rational.c needs module.h
+  * dma-debug: allow DMA_BIDIRECTIONAL mappings to be synced with
+    DMA_FROM_DEVICE and
+  * kernel/signal.c: fix kernel information leak with print-fatal-signals=1
+  * mmc_block: add dev_t initialization check
+  * mmc_block: fix probe error cleanup bug
+  * mmc_block: fix queue cleanup
+  * ALSA: hda - Fix ALC861-VD capture source mixer
+  * ALSA: ac97: Add Dell Dimension 2400 to Headphone/Line Jack Sense
+    blacklist
+  * ALSA: atiixp: Specify codec for Foxconn RC4107MA-RS2
+    - LP: #498863
+  * ASoC: Fix WM8350 DSP mode B configuration
+  * netfilter: ebtables: enforce CAP_NET_ADMIN
+  * netfilter: nf_ct_ftp: fix out of bounds read in update_nl_seq()
+  * hwmon: (coretemp) Fix TjMax for Atom N450/D410/D510 CPUs
+  * hwmon: (adt7462) Fix pin 28 monitoring
+  * quota: Fix dquot_transfer for filesystems different from ext4
+  * xen: fix hang on suspend.
+  * iwlwifi: fix iwl_queue_used bug when read_ptr == write_ptr
+  * ath5k: Fix eeprom checksum check for custom sized eeproms
+  * cfg80211: fix syntax error on user regulatory hints
+  * iwl: off by one bug
+  * mac80211: add missing sanity checks for action frames
+  * drm/i915: remove render reclock support
+  * libertas: Remove carrier signaling from the scan code
+  * kernel/sysctl.c: fix stable merge error in NOMMU mmap_min_addr
+  * mac80211: fix skb buffering issue (and fixes to that)
+  * fix braindamage in audit_tree.c untag_chunk()
+  * fix more leaks in audit_tree.c tag_chunk()
+  * module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y
+  * ipv6: skb_dst() can be NULL in ipv6_hop_jumbo().
+  * agp/intel-agp: Clear entire GTT on startup
+  * Linux 2.6.32.4
+  * ethtool: Add reset operation
+  * gro: Name the GRO result enumeration type
+  * gro: Change all receive functions to return GRO result codes
+  * sfc: 10Xpress: Initialise pause advertising flags
+  * sfc: 10Xpress: Report support for pause frames
+  * sfc: Remove redundant header gmii.h
+  * sfc: Remove redundant hardware initialisation
+  * sfc: Rename Falcon-specific board code and types
+  * sfc: Remove boards.h, moving last remaining declaration to falcon.h
+  * sfc: Remove versioned bitfield macros
+  * sfc: Move RX data FIFO thresholds out of struct efx_nic_type
+  * sfc: Update hardware definitions for Siena
+  * sfc: Rename register I/O header and functions used by both Falcon and
+    Siena
+  * sfc: Eliminate indirect lookups of queue size constants
+  * sfc: Define DMA address mask explicitly in terms of descriptor field
+    width
+  * sfc: Move all TX DMA length limiting into tx.c
+  * sfc: Change order of device removal to reverse of probe order
+  * sfc: Remove declarations of nonexistent functions
+  * sfc: Move efx_xmit_done() declaration into correct stanza
+  * sfc: Move shared members of struct falcon_nic_data into struct efx_nic
+  * sfc: Maintain interrupt moderation values in ticks, not microseconds
+  * sfc: Removed kernel-doc for nonexistent member of efx_phy_operations
+  * sfc: Remove pointless abstraction of memory BAR number
+  * sfc: Remove incorrect assertion from efx_pci_remove_main()
+  * sfc: Remove unnecessary tests of efx->membase
+  * sfc: Move MTD probe after netdev registration and name allocation
+  * sfc: Remove unused code for non-autoneg speed/duplex switching
+  * sfc: Rename 'xfp' file and functions to reflect reality
+  * sfc: Really allow RX checksum offload to be disabled
+  * sfc: Feed GRO result into RX allocation policy and interrupt moderation
+  * sfc: Enable heuristic selection between page and skb RX buffers
+  * sfc: Remove pointless abstraction of memory BAR number (2)
+  * sfc: Remove redundant gotos from __efx_rx_packet()
+  * sfc: Remove ridiculously paranoid assertions
+  * sfc: Move assertions and buffer cleanup earlier in efx_rx_packet_lro()
+  * sfc: Record RX queue number on GRO path
+  * sfc: SFT9001: Reset LED configuration correctly after blinking
+  * sfc: Use a single blink implementation
+  * sfc: Rename efx_board::init_leds to init_phy and use for SFN4111T
+  * sfc: Make board information explicitly Falcon-specific
+  * sfc: Move definition of struct falcon_nic_data into falcon.h
+  * sfc: Move struct falcon_board into struct falcon_nic_data
+  * sfc: Move all I2C stuff into struct falcon_board
+  * sfc: Gather link state fields in struct efx_nic into new struct
+    efx_link_state
+  * sfc: Remove unnecessary casts to struct sk_buff *
+  * sfc: Remove redundant efx_xmit() function
+  * sfc: Combine high-level header files
+  * sfc: Log interrupt and reset type names, not numbers
+  * sfc: Fix descriptor cache sizes
+  * sfc: Treat all MAC registers as 128-bit
+  * sfc: Strengthen EFX_ASSERT_RESET_SERIALISED
+  * sfc: Comment corrections
+  * sfc: Remove unused constant
+  * sfc: Clean up struct falcon_board and struct falcon_board_data
+  * sfc: Fix bugs in RX queue flushing
+  * sfc: Remove unused function efx_flush_queues()
+  * sfc: Only switch Falcon MAC clocks as necessary
+  * sfc: Hold MAC lock for longer in efx_init_port()
+  * sfc: Split MAC stats DMA initiation and completion
+  * sfc: Move Falcon board/PHY/MAC monitoring code to falcon.c
+  * sfc: Simplify XMAC link polling
+  * sfc: Change MAC promiscuity and multicast hash at the same time
+  * sfc: Move inline comment into kernel-doc
+  * sfc: Do not set net_device::trans_start in self-test
+  * sfc: Simplify PHY polling
+  * sfc: QT202x: Reset before reading PHY id
+  * sfc: Replace MDIO spinlock with mutex
+  * sfc: Always start Falcon using the XMAC
+  * sfc: Limit some hardware workarounds to Falcon
+  * sfc: Remove EFX_WORKAROUND_9141 macro
+  * sfc: Remove another unused workaround macro
+  * sfc: Remove some redundant whitespace
+  * sfc: Decouple NIC revision number from Falcon PCI revision number
+  * sfc: Move descriptor cache base addresses to struct efx_nic_type
+  * sfc: Clean up RX event handling
+  * sfc: Remove redundant writes to INT_ADR_KER
+  * sfc: Remove duplicate hardware structure definitions
+  * sfc: Turn pause frame generation on and off at the MAC, not the RX FIFO
+  * sfc: Move Falcon NIC operations to efx_nic_type
+  * sfc: Refactor link configuration
+  * sfc: Generalise link state monitoring
+  * sfc: Add power-management and wake-on-LAN support
+  * sfc: Implement ethtool reset operation
+  * sfc: Add efx_nic_type operation for register self-test
+  * sfc: Add efx_nic_type operation for NVRAM self-test
+  * sfc: Add efx_nic_type operation for identity LED control
+  * sfc: Separate shared NIC code from Falcon-specific and rename
+    accordingly
+  * sfc: Fold falcon_probe_nic_variant() into falcon_probe_nic()
+  * sfc: Extend loopback mode enumeration
+  * sfc: Remove static PHY data and enumerations
+  * sfc: Extend MTD driver for use with new NICs
+  * sfc: Allow for additional checksum offload features
+  * sfc: Rename falcon.h to nic.h
+  * sfc: Move shared NIC code from falcon.c to new source file nic.c
+  * sfc: Add firmware protocol definitions (MCDI)
+  * sfc: Add support for SFC9000 family (1)
+  * sfc: Add support for SFC9000 family (2)
+  * sfc: Implement TSO for TCP/IPv6
+  * sfc: Update version, copyright dates, authors
+  * drivers/net/sfc: Correct code taking the size of a pointer
+  * sfc: Move PHY software state initialisation from init() into probe()
+  * sfc: Include XGXS in XMAC link status check except in XGMII loopback
+  * sfc: Fix DMA mapping cleanup in case of an error in TSO
+  * sfc: QT2025C: Work around PHY bug
+  * sfc: QT2025C: Switch into self-configure mode when not in loopback
+  * sfc: QT2025C: Work around PHY firmware initialisation bug
+  * sfc: QT2025C: Add error message for suspected bad SFP+ cables
+  * sfc: Disable TX descriptor prefetch watchdog
+  * [SCSI] vmw_pvscsi: SCSI driver for VMware's virtual HBA.
+    - LP: #497156
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 19 Jan 2010 16:12:47 +0000
+
+linux (2.6.32-10.14) lucid; urgency=low
+
+  [ Alex Deucher ]
+
+  * SAUCE: drm/radeon/kms: fix LVDS setup on r4xx
+    - LP: #493795
+
+  [ Andy Whitcroft ]
+
+  * Revert "(pre-stable) acpi: Use the ARB_DISABLE for the CPU which model
+    id is less than 0x0f."
+  * config-check -- ensure the checks get run at build time
+  * config-check -- check the processed config during updateconfigs
+  * config-check -- CONFIG_SECCOMP may not be present
+  * TUN is now built in ignore
+  * SAUCE: acpi battery -- delay first lookup of the battery until first
+    use
+  * SAUCE: async_populate_rootfs: move rootfs init earlier
+  * ubuntu: AppArmor -- update to mainline 2010-01-06
+  * SAUCE: move RLIMIT_CORE pipe dumper marker to 1
+    - LP: #498525
+
+  [ Dave Airlie ]
+
+  * (pre-stable) drm/radeon/kms: fix crtc vblank update for r600
+
+  [ Leann Ogasawara ]
+
+  * Add asix to nic-usb-modules file
+    - LP: #499785
+
+  [ Peter Zijlstra ]
+
+  * (pre-stable) sched: Fix balance vs hotplug race
+
+  [ Tim Gardner ]
+
+  * [Config] Enable CONFIG_FUNCTION_TRACER
+    - LP: #497989
+  * [Config] Drop lpia from getabis
+  * [Config] Build in TUN/TAP driver
+    - LP: #499491
+  * [Config] DH_COMPAT=5
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "(pre-stable) drm/i915: Avoid NULL dereference with
+    component_only tv_modes"
+  * Revert "(pre-stable) drm/i915: Fix sync to vblank when VGA output is
+    turned off"
+  * USB: usb-storage: fix bug in fill_inquiry
+  * USB: option: add pid for ZTE
+  * firewire: ohci: handle receive packets with a data length of zero
+  * rcu: Prepare for synchronization fixes: clean up for non-NO_HZ handling
+    of ->completed counter
+  * rcu: Fix synchronization for rcu_process_gp_end() uses of ->completed
+    counter
+  * rcu: Fix note_new_gpnum() uses of ->gpnum
+  * rcu: Remove inline from forward-referenced functions
+  * perf_event: Fix invalid type in ioctl definition
+  * perf_event: Initialize data.period in perf_swevent_hrtimer()
+  * perf: Don't free perf_mmap_data until work has been done
+  * PM / Runtime: Fix lockdep warning in __pm_runtime_set_status()
+  * sched: Check for an idle shared cache in select_task_rq_fair()
+  * sched: Fix affinity logic in select_task_rq_fair()
+  * sched: Rate-limit newidle
+  * sched: Fix and clean up rate-limit newidle code
+  * x86/amd-iommu: attach devices to pre-allocated domains early
+  * x86/amd-iommu: un__init iommu_setup_msi
+  * x86, Calgary IOMMU quirk: Find nearest matching Calgary while walking
+    up the PCI tree
+  * x86: Fix iommu=nodac parameter handling
+  * x86: GART: pci-gart_64.c: Use correct length in strncmp
+  * x86: ASUS P4S800 reboot=bios quirk
+    - LP: #366682
+  * x86, apic: Enable lapic nmi watchdog on AMD Family 11h
+  * ssb: Fix range check in sprom write
+  * ath5k: allow setting txpower to 0
+  * ath5k: enable EEPROM checksum check
+  * hrtimer: Fix /proc/timer_list regression
+  * ALSA: hrtimer - Fix lock-up
+  * ALSA: hda - Terradici HDA controllers does not support 64-bit mode
+  * KVM: x86 emulator: limit instructions to 15 bytes
+  * KVM: s390: Fix prefix register checking in arch/s390/kvm/sigp.c
+  * KVM: s390: Make psw available on all exits, not just a subset
+  * KVM: fix irq_source_id size verification
+  * KVM: x86: include pvclock MSRs in msrs_to_save
+  * x86: Prevent GCC 4.4.x (pentium-mmx et al) function prologue wreckage
+  * x86: Use -maccumulate-outgoing-args for sane mcount prologues
+  * x86, mce: don't restart timer if disabled
+  * x86/mce: Set up timer unconditionally
+  * x86: SGI UV: Fix BAU initialization
+  * x86: Fix duplicated UV BAU interrupt vector
+  * x86: Add new Intel CPU cache size descriptors
+  * x86: Fix typo in Intel CPU cache size descriptor
+  * pata_hpt{37x|3x2n}: fix timing register masks (take 2)
+  * s390: clear high-order bits of registers after sam64
+  * V4L/DVB: Fix test in copy_reg_bits()
+  * bsdacct: fix uid/gid misreporting
+  * UBI: flush wl before clearing update marker
+  * jbd2: don't wipe the journal on a failed journal checksum
+  * USB: xhci: Add correct email and files to MAINTAINERS entry.
+  * USB: musb_gadget_ep0: fix unhandled endpoint 0 IRQs, again
+  * USB: option.c: add support for D-Link DWM-162-U5
+  * USB: usbtmc: repeat usb_bulk_msg until whole message is transfered
+  * USB: usb-storage: add BAD_SENSE flag
+  * USB: Close usb_find_interface race v3
+  * pxa/em-x270: fix usb hub power up/reset sequence
+  * hfs: fix a potential buffer overflow
+  * SUNRPC: IS_ERR/PTR_ERR confusion
+  * NFS: Fix nfs_migrate_page()
+  * md/bitmap: protect against bitmap removal while being updated.
+  * futex: Take mmap_sem for get_user_pages in fault_in_user_writeable
+  * devpts_get_tty() should validate inode
+  * debugfs: fix create mutex racy fops and private data
+  * Driver core: fix race in dev_driver_string
+  * Serial: Do not read IIR in serial8250_start_tx when UART_BUG_TXEN
+  * mac80211: Fix bug in computing crc over dynamic IEs in beacon
+  * mac80211: Fixed bug in mesh portal paths
+  * mac80211: Revert 'Use correct sign for mesh active path refresh'
+  * mac80211: fix scan abort sanity checks
+  * wireless: correctly report signal value for IEEE80211_HW_SIGNAL_UNSPEC
+  * rtl8187: Fix wrong rfkill switch mask for some models
+  * x86: Fix bogus warning in apic_noop.apic_write()
+  * mm: hugetlb: fix hugepage memory leak in mincore()
+  * mm: hugetlb: fix hugepage memory leak in walk_page_range()
+  * powerpc/windfarm: Add detection for second cpu pump
+  * powerpc/therm_adt746x: Record pwm invert bit at module load time]
+  * powerpc: Fix usage of 64-bit instruction in 32-bit altivec code
+  * drm/radeon/kms: Add quirk for HIS X1300 board
+  * drm/radeon/kms: handle vblanks properly with dpms on
+  * drm/radeon/kms: fix legacy crtc2 dpms
+  * drm/radeon/kms: fix vram setup on rs600
+  * drm/radeon/kms: rs6xx/rs740: clamp vram to aperture size
+  * drm/ttm: Fix build failure due to missing struct page
+  * drm/i915: Set the error code after failing to insert new offset into mm
+    ht.
+  * drm/i915: Add the missing clonemask for display port on Ironlake
+  * xen/xenbus: make DEVICE_ATTR()s static
+  * xen: re-register runstate area earlier on resume.
+  * xen: restore runstate_info even if !have_vcpu_info_placement
+  * xen: correctly restore pfn_to_mfn_list_list after resume
+  * xen: register timer interrupt with IRQF_TIMER
+  * xen: register runstate on secondary CPUs
+  * xen: don't call dpm_resume_noirq() with interrupts disabled.
+  * xen: register runstate info for boot CPU early
+  * xen: call clock resume notifier on all CPUs
+  * xen: improve error handling in do_suspend.
+  * xen: don't leak IRQs over suspend/resume.
+  * xen: use iret for return from 64b kernel to 32b usermode
+  * xen: explicitly create/destroy stop_machine workqueues outside
+    suspend/resume region.
+  * Xen balloon: fix totalram_pages counting.
+  * xen: try harder to balloon up under memory pressure.
+  * dm exception store: free tmp_store on persistent flag error
+  * dm snapshot: only take lock for statustype info not table
+  * dm crypt: move private iv fields to structs
+  * dm crypt: restructure essiv error path
+  * dm: avoid _hash_lock deadlock
+  * dm snapshot: cope with chunk size larger than origin
+  * dm crypt: separate essiv allocation from initialisation
+  * dm crypt: make wipe message also wipe essiv key
+  * slc90e66: fix UDMA handling
+  * tcp: Stalling connections: Fix timeout calculation routine
+  * ip_fragment: also adjust skb->truesize for packets not owned by a
+    socket
+  * b44 WOL setup: one-bit-off stack corruption kernel panic fix
+  * sparc64: Don't specify IRQF_SHARED for LDC interrupts.
+  * sparc64: Fix overly strict range type matching for PCI devices.
+  * sparc64: Fix stack debugging IRQ stack regression.
+  * sparc: Set UTS_MACHINE correctly.
+  * b43legacy: avoid PPC fault during resume
+  * tracing: Fix event format export
+  * ath9k: Fix TX hang poll routine
+  * ath9k: fix processing of TX PS null data frames
+  * ath9k: Fix maximum tx fifo settings for single stream devices
+  * ath9k: fix tx status reporting
+  * mac80211: Fix dynamic power save for scanning.
+  * drm/i915: Fix sync to vblank when VGA output is turned off
+  * memcg: fix memory.memsw.usage_in_bytes for root cgroup
+  * thinkpad-acpi: fix default brightness_mode for R50e/R51
+  * thinkpad-acpi: preserve rfkill state across suspend/resume
+  * ipw2100: fix rebooting hang with driver loaded
+  * matroxfb: fix problems with display stability
+  * acerhdf: add new BIOS versions
+  * asus-laptop: change light sens default values.
+  * vmalloc: conditionalize build of pcpu_get_vm_areas()
+  * ACPI: Use the ARB_DISABLE for the CPU which model id is less than 0x0f.
+  * net: Fix userspace RTM_NEWLINK notifications.
+  * ext3: Fix data / filesystem corruption when write fails to copy data
+  * V4L/DVB (13116): gspca - ov519: Webcam 041e:4067 added.
+  * bcm63xx_enet: fix compilation failure after get_stats_count removal
+  * x86: Under BIOS control, restore AP's APIC_LVTTHMR to the BSP value
+  * drm/i915: Avoid NULL dereference with component_only tv_modes
+  * drm/i915: PineView only has LVDS and CRT ports
+  * drm/i915: Fix LVDS stability issue on Ironlake
+  * mm: sigbus instead of abusing oom
+  * ipvs: zero usvc and udest
+  * jffs2: Fix long-standing bug with symlink garbage collection.
+  * intel-iommu: Detect DMAR in hyperspace at probe time.
+  * intel-iommu: Apply BIOS sanity checks for interrupt remapping too.
+  * intel-iommu: Check for an RMRR which ends before it starts.
+  * intel-iommu: Fix oops with intel_iommu=igfx_off
+  * intel-iommu: ignore page table validation in pass through mode
+  * netfilter: xtables: document minimal required version
+  * perf_event: Fix incorrect range check on cpu number
+  * implement early_io{re,un}map for ia64
+  * Linux 2.6.32.2
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 07 Jan 2010 15:28:43 +0000
+
+linux (2.6.32-9.13) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_B43_PHY_LP
+    - LP: #493059
+  * include modules.builtin in the binary debs
+  * config-check -- add a configuration enforcer
+  * config-check -- add a unit-test suite to the checker
+  * [Config] Enable CONFIG_SYN_COOKIES for versatile
+  * [Config] Enable CONFIG_SECURITY_SMACK for ports
+  * [Config] Enable CONFIG_SECURITY_FILE_CAPABILITIES for ports
+  * [Config] Disable CONFIG_COMPAT_BRK for ports
+  * getabis -- add armel versatile to the list
+
+  [ Brad Figg ]
+
+  * SAUCE: Increase the default prealloc buffer for HDA audio devices
+    (non-modem)
+
+  [ Manoj Iyer ]
+
+  * ubuntu: onmibook -- Added missing BOM file
+
+  [ Tim Gardner ]
+
+  * ubuntu: fsam7400 -- Cleanup Makefile
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "ext4: Fix insufficient checks in EXT4_IOC_MOVE_EXT"
+  * signal: Fix alternate signal stack check
+  * SCSI: scsi_lib_dma: fix bug with dma maps on nested scsi objects
+  * SCSI: osd_protocol.h: Add missing #include
+  * SCSI: megaraid_sas: fix 64 bit sense pointer truncation
+  * ext4: fix potential buffer head leak when add_dirent_to_buf() returns
+    ENOSPC
+  * ext4: avoid divide by zero when trying to mount a corrupted file system
+  * ext4: fix the returned block count if EXT4_IOC_MOVE_EXT fails
+  * ext4: fix lock order problem in ext4_move_extents()
+  * ext4: fix possible recursive locking warning in EXT4_IOC_MOVE_EXT
+  * ext4: plug a buffer_head leak in an error path of ext4_iget()
+  * ext4: make sure directory and symlink blocks are revoked
+  * ext4: fix i_flags access in ext4_da_writepages_trans_blocks()
+  * ext4: journal all modifications in ext4_xattr_set_handle
+  * ext4: don't update the superblock in ext4_statfs()
+  * ext4: fix uninit block bitmap initialization when s_meta_first_bg is
+    non-zero
+  * ext4: fix block validity checks so they work correctly with meta_bg
+  * ext4: avoid issuing unnecessary barriers
+  * ext4: fix error handling in ext4_ind_get_blocks()
+  * ext4: make trim/discard optional (and off by default)
+  * ext4: make "norecovery" an alias for "noload"
+  * ext4: Fix double-free of blocks with EXT4_IOC_MOVE_EXT
+  * ext4: initialize moved_len before calling ext4_move_extents()
+  * ext4: move_extent_per_page() cleanup
+  * jbd2: Add ENOMEM checking in and for
+    jbd2_journal_write_metadata_buffer()
+  * ext4: Return the PTR_ERR of the correct pointer in
+    setup_new_group_blocks()
+  * ext4: Avoid data / filesystem corruption when write fails to copy data
+  * ext4: wait for log to commit when umounting
+  * ext4: remove blocks from inode prealloc list on failure
+  * ext4: ext4_get_reserved_space() must return bytes instead of blocks
+  * ext4: quota macros cleanup
+  * ext4: fix incorrect block reservation on quota transfer.
+  * ext4: Wait for proper transaction commit on fsync
+  * ext4: Fix insufficient checks in EXT4_IOC_MOVE_EXT
+  * ext4: Fix potential fiemap deadlock (mmap_sem vs. i_data_sem)
+  * Linux 2.6.32.1
+  * kbuild: generate modules.builtin
+  * (pre-stable) drm/i915: Fix sync to vblank when VGA output is turned off
+    - LP: #494461
+  * (pre-stable) drm/i915: Avoid NULL dereference with component_only
+    tv_modes
+    - LP: #494045
+
+  [ Zhao Yakui ]
+
+  * (pre-stable) acpi: Use the ARB_DISABLE for the CPU which model id is
+    less than 0x0f.
+    - LP: #481765
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 17 Dec 2009 15:41:21 +0000
+
+linux (2.6.32-8.12) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: AppArmor -- add linux/err.h for ERR_PTR
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 12 Dec 2009 10:56:16 +0000
+
+linux (2.6.32-8.11) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: default ATI Radeon KMS to off until userspace catches
+    up"
+  * Revert "SAUCE: AppArmor: Fix oops there is no tracer and doing unsafe
+    transition."
+  * Revert "SAUCE: AppArmor: Fix refcounting bug causing leak of creds"
+  * Revert "SAUCE: AppArmor: Fix cap audit_caching preemption disabling"
+  * Revert "SAUCE: AppArmor: Fix Oops when in apparmor_bprm_set_creds"
+  * Revert "SAUCE: AppArmor: Fix oops after profile removal"
+  * Revert "SAUCE: AppArmor: AppArmor disallows truncate of deleted files."
+  * Revert "SAUCE: AppArmor: AppArmor fails to audit change_hat correctly"
+  * Revert "SAUCE: AppArmor: Policy load and replacement can fail to alloc
+    mem"
+  * Revert "SAUCE: AppArmor: AppArmor wrongly reports allow perms as
+    denied"
+  * Revert "SAUCE: AppArmor: Fix mediation of "deleted" paths"
+  * Revert "SAUCE: AppArmor: Fix off by 2 error in getprocattr mem
+    allocation"
+  * Revert "SAUCE: AppArmor: Set error code after structure
+    initialization."
+  * Revert "AppArmor -- fix pstrace_may_access rename"
+  * Revert "ubuntu: AppArmor security module"
+  * Revert "SAUCE: Add config option to set a default LSM"
+  * Revert "ubuntu: fsam7400 -- sw kill switch driver"
+  * Revert "[Config] fsam7400 -- enable"
+  * Revert "[Config] AUFS -- enable"
+  * Revert "ubuntu: AUFS -- aufs2-30 20090727"
+  * Revert "ubuntu: AUFS -- export various core functions -- fixes"
+  * Revert "ubuntu: AUFS -- export various core functions"
+  * Revert "[Config] ubuntu/iscsitarget -- disable"
+  * Revert "[Config] iscsitarget -- enable"
+  * Revert "ubuntu: iscsitarget -- SVN revision r214"
+  * update Vcs-Git to point to the correct repository
+    - LP: #493589
+  * update build environment overrides to lucid
+    - LP: #493589
+  * [Config] enable CONFIG_DEVTMPFS
+  * [Config] update all configs following AppArmor 2009-12-08 update
+  * SAUCE: isapnp_init: make isa PNP scans occur async
+  * [Config] fsam7400 -- enable
+  * [Config] omnibook -- enable
+  * [Config] cleanup CONFIG_AUDIT
+  * ubuntu: AUFS -- export various core functions (aufs2-base.patch)
+  * ubuntu: AUFS -- export various core functions (aufs2-standalone.patch)
+  * ubuntu: AUFS -- aufs2 20091209
+  * [Config] AUFS -- enable
+  * [Config] iscsitarget -- enable
+
+  [ Arjan van de Ven ]
+
+  * SAUCE: KMS: cache the EDID information of the LVDS
+
+  [ Colin Watson ]
+
+  * bnx2: update d-i firmware filenames
+    - LP: #494052
+  * add cdc_ether to nic-usb-modules udeb
+    - LP: #495060
+
+  [ John Johansen ]
+
+  * ubuntu: AppArmor -- mainline 2009-10-08
+
+  [ Manoj Iyer ]
+
+  * ubuntu: fsam7400 -- kill switch for Fujitsu Siemens Amilo M 7400
+  * ubuntu: omnibook -- support Toshiba (HP) netbooks
+  * ubuntu: iscsitarget --- version 1.4.19
+    - LP: #494693
+
+  [ Surbhi Palande ]
+
+  * SAUCE: Make populate_rootfs asynchronous
+
+  [ Tim Gardner ]
+
+  * Parallelize flavour builds and packaging
+  * [Config] Enable CONFIG_KSM
+
+  [ Upstream Kernel Changes ]
+
+  * Config option to set a default LSM
+  * LSM: Add security_path_chroot().
+  * LSM: Add security_path_chroot().
+  * LSM: Move security_path_chmod()/security_path_chown() to after
+    mutex_lock().
+  * ext4: Fix insufficient checks in EXT4_IOC_MOVE_EXT
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 11 Dec 2009 17:45:19 +0000
+
+linux (2.6.32-7.10) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] disable CONFIG_THUMB2_KERNEL to fix arm FTBFS
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 06 Dec 2009 12:56:48 +0000
+
+linux (2.6.32-7.9) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: set /proc/acpi/video/*/DOS to 4 by default
+    - LP: #458982
+  * SAUCE: ensure vga16fb loads if no other driver claims the VGA device
+  * [Config] update configs following versatile switch to V7
+  * rebased to v2.6.32
+  * [Config] update configs following rebase to v2.6.32
+  * [Config] update ports configs following rebase to v2.6.32
+  * SAUCE: default ATI Radeon KMS to off until userspace catches up
+
+  [ Arjan van de Ven ]
+
+  * SAUCE: vfs: Add a trace point in the mark_inode_dirty function
+
+  [ Leann Ogasawara ]
+
+  * [SCSI] megaraid_sas: remove sysfs poll_mode_io world writeable
+    permissions
+    - CVE-2009-3939
+
+  [ Loic Minier ]
+
+  * SAUCE: select a v7 CPU for versatile
+
+  [ Takashi Iwai ]
+
+  * SAUCE: ALSA: hda - Add power on/off counter
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.32
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 04 Dec 2009 10:44:50 +0000
+
+linux (2.6.32-6.8) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] disable SSB devices for armel
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 28 Nov 2009 12:16:40 +0000
+
+linux (2.6.32-6.7) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: default ATI Radeon KMS to off until userspace catches up"
+  * Revert "SAUCE: Dell XPS710 reboot quirk"
+  * Revert "SAUCE: Link acpi-cpufreq.o first"
+  * Revert "SAUCE: LPIA  Logical reset of USB port on resume"
+  * Revert "SAUCE: LPIA Reboot fix for Intel Crownbeach development boards"
+  * Revert "SAUCE: Enable HDMI audio codec on Studio XPS 1340"
+  * Revert "SAUCE: Dell laptop digital mic does not work, PCI 1028:0271"
+  * Revert "Add Dell Dimension 9200 reboot quirk"
+  * Revert "SAUCE: Correctly blacklist Thinkpad r40e in ACPI"
+  * Revert "SAUCE: tulip: Define ULI PCI ID's"
+  * Revert "SAUCE: Lower warning level of some PCI messages"
+  * Revert "mac80211: fix two issues in debugfs"
+    Drop a number of known redundant commits as identified in the Ubuntu
+    delta review blueprint.
+
+  * reenable armel versatile flavour
+  * [Config] disable CONFIG_USB_DEVICEFS
+
+  [ Tim Gardner ]
+
+  * [Config] udeb: Add squashfs to fs-core-modules
+    - LP: #352615
+  * [Config] Create a real squashfs udeb
+    - LP: #352615
+
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 27 Nov 2009 17:31:16 +0000
+
+linux (2.6.32-5.6) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.32-rc8
+  * update configs following rebase to v2.6.32-rc8
+  * update ports configs since rebase to v2.6.32-rc8
+  * [Config] enable cgroup options
+    - LP: #480739
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.32-rc8
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 23 Nov 2009 11:16:14 +0000
+
+linux (2.6.32-4.5) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] SERIO_LIBPS2 and SERIO_I8042 must match
+  * rebase to v2.6.32-rc7
+  * resync with Karmic proposed
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: Fix oops after profile removal
+    - LP: #475619
+  * SAUCE: AppArmor: Fix Oops when in apparmor_bprm_set_creds
+    - LP: #437258
+  * SAUCE: AppArmor: Fix cap audit_caching preemption disabling
+    - LP: #479102
+  * SAUCE: AppArmor: Fix refcounting bug causing leak of creds
+    - LP: #479115
+  * SAUCE: AppArmor: Fix oops there is no tracer and doing unsafe
+    transition.
+    - LP: #480112
+
+  [ Ubuntu Changes ]
+
+  * resync with Karmic proposed (ddbc670a86a3dee18541a3734149f250ff307adf)
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.32-rc7
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 13 Nov 2009 11:35:13 +0000
+
+linux (2.6.32-3.4) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] SERIO_LIBPS2 and SERIO_I8042 must match
+  * [Upstream] add local prefix to oss local change_bits
+
+  [ Upstream Kernel Changes ]
+
+  * mtd/maps: gpio-addr-flash: pull in linux/ headers rather than asm/
+  * mtd/maps: gpio-addr-flash: depend on GPIO arch support
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 11 Nov 2009 14:47:04 +0000
+
+linux (2.6.32-3.3) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.32-rc6
+  * [Config] update configs following rebase to v2.6.32-rc6
+  * [Config] update ports configs following rebase to v2.6.32-rc6
+  * resync with Karmic Ubuntu-2.6.31-15.49
+  * [Config] add module ignores for broken drivers
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: AppArmor wrongly reports allow perms as denied
+    - LP: #453335
+  * SAUCE: AppArmor: Policy load and replacement can fail to alloc mem
+    - LP: #458299
+  * SAUCE: AppArmor: AppArmor fails to audit change_hat correctly
+    - LP: #462824
+  * SAUCE: AppArmor: AppArmor disallows truncate of deleted files.
+    - LP: #451375
+
+  [ Kees Cook ]
+
+  * SAUCE: Fix nx_enable reporting
+    - LP: #454285
+
+  [ Scott James Remnant ]
+
+  * Revert "SAUCE: trace: add trace_event for the open() syscall"
+  * SAUCE: trace: add trace events for open(), exec() and uselib()
+    - LP: #462111
+
+  [ Stefan Bader ]
+
+  * SAUCE: Fix sub-flavour script to not stop on missing directories
+    - LP: #453073
+
+  [ Ubuntu Changes ]
+
+  * resync with Karmic Ubuntu-2.6.31-15.49
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.32-rc6
+    - LP: #464552
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 10 Nov 2009 15:00:57 +0000
+
+linux (2.6.32-2.2) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * install the full changelog with the binary package
+  * changelog -- explicitly note rebases and clean history
+  * reinstate armel.mk with no flavours
+    - LP: #449637
+  * [Upstream] block: silently error unsupported empty barriers too
+    - LP: #420423
+  * [Config] udate configs following karmic resync
+  * [Config] update ports configs following karmic resync
+  * [Upstream] lirc -- follow removal of .id element
+
+  [ Colin Watson ]
+
+  * Use section 'admin' rather than 'base'
+  * Add more e100 firmware to nic-modules
+    - LP: #451872
+  * Add qla1280 firmware to scsi-modules
+    - LP: #381037
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: Set error code after structure initialization.
+    - LP: #427948
+  * SAUCE: AppArmor: Fix off by 2 error in getprocattr mem allocation
+    - LP: #446595
+  * SAUCE: AppArmor: Fix mediation of "deleted" paths
+
+  [ Kees Cook ]
+
+  * SAUCE: [x86] fix report of cs-limit nx-emulation
+    - LP: #454285
+
+  [ Leann Ogasawara ]
+
+  * SAUCE: (drop after 2.6.31) input: Add support for filtering input
+    events
+    - LP: #430809
+  * SAUCE: (drop after 2.6.31) dell-laptop: Trigger rfkill updates on wifi
+    toggle switch press
+    - LP: #430809
+
+  [ Luke Yelavich ]
+
+  * SAUCE: Add sr_mod to the scsi-modules udeb for powerpc
+  * [Config] Add sd_mod to scsi-modules udeb for powerpc
+
+  [ Mario Limonciello ]
+
+  * SAUCE: Update to LIRC 0.8.6
+    - LP: #432678
+  * SAUCE: dell-laptop: Store the HW switch status internally rather than
+    requerying every time
+    - LP: #430809
+  * SAUCE: dell-laptop: Blacklist machines not supporting dell-laptop
+    - LP: #430809
+
+  [ Stefan Bader ]
+
+  * [Upstream] acerhdf: Limit modalias matching to supported boards
+    - LP: #435958
+
+  [ Tim Gardner ]
+
+  * [Upstream] i915: Fix i2c init message
+    - LP: #409361
+  * [Config] Add sym53c8xx.ko to virtual sub-flavour
+    - LP: #439415
+  * [Config] Add d101m_ucode.bin to d-i/firmware/nic-modules
+    - LP: #439456
+  * [Config] Set default I/O scheduler back to CFQ for desktop flavours
+    - LP: #381300
+  * SAUCE: Created MODULE_EXPORT/MODULE_IMPORT macros
+    - LP: #430694
+  * SAUCE: Use MODULE_IMPORT macro to tie intel_agp to i915
+    - LP: #430694
+  * [Config] CONFIG_GFS2_FS_LOCKING_DLM=y
+    - LP: #416325
+  * SAUCE: Fix MODULE_IMPORT/MODULE_EXPORT
+    - LP: #430694
+  * SAUCE: Raise the default console 'quiet' level to 2
+  * [Config] CONFIG_X86_PAT=y
+  * [Config] Add armel arch to linux-libc-dev arches.
+    - LP: #449637
+  * [Config] CONFIG_X86_MCE
+  * [Upstream] (drop after 2.6.31) Input: synaptics - add another Protege
+    M300 to rate blacklist
+    - LP: #433801
+
+  [ Upstream Kernel Changes ]
+
+  * sgi-gru: Fix kernel stack buffer overrun, CVE-2009-2584
+  * drm/i915: Fix FDI M/N setting according with correct color depth
+    - LP: #416792
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 22 Oct 2009 16:53:33 +0100
+
+linux (2.6.32-1.1) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.32-rc3
+  * [Config] update configs following rebase to 2.6.32-rc3
+  * [Config] update ports configs following rebase to 2.6.32-rc3
+  * AppArmor -- fix pstrace_may_access rename
+  * staging/android -- disable
+  * ubuntu: dm-raid-45 -- update to compile with 2.6.32
+  * ubuntu: drbd -- disable
+  * staging/comdi -- disable
+  * staging/go7007 -- disable
+  * [Config] staging/winbond -- disable
+  * [Config] ubuntu/iscsitarget -- disable
+  * [d-i] cbc and ecb are builtin make them optional in udebs
+  * rebase to v2.6.32-rc5
+  * [Config] update configs following rebase to v2.6.32-rc5
+  * [Config] update ports configs following rebase to v2.6.31-rc5
+
+  [ Tim Gardner ]
+
+  * [Config] Add cpio as a build dependency.
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.32-rc3
+  * rebase to v2.6.32-rc5
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 05 Oct 2009 15:48:58 +0100
+
+linux (2.6.31-11.37) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Increase kernel log buffer to 256K for amd64 flavours
+    - LP: #424810
+  * [Config] Set HZ=100 for amd64 flavours
+    - LP: #438234
+  * [Upstream] e1000e: Emit notice instead of an error when
+    pci_enable_pcie_error_reporting() fails
+    - LP: #436370
+
+  [ Upstream Kernel Changes ]
+
+  * n_tty: honor opost flag for echoes
+  * n_tty: move echoctl check and clean up logic
+    - LP: #438310
+
+  * Revert "[Upstream] drm/i915: Check that the relocation points to within
+    the target" - Use upstream cherry-pick.
+  * drm/i915: Check that the relocation points to within the target
+    - LP: #429241
+
+  * drm/i915: fix tiling on IGDNG
+  * drm/i915: add B43 chipset support
+  * agp/intel: Add B43 chipset support
+    Intel request from kernel team mailing list.
+
+  * HID: completely remove apple mightymouse from blacklist
+    - LP: #428111
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 28 Sep 2009 11:47:29 -0600
+
+linux (2.6.31-11.36) karmic; urgency=low
+
+  [ Brian Rogers ]
+
+  * SAUCE: (drop after 2.6.31) em28xx: ir-kbd-i2c init data needs a
+    persistent object
+  * SAUCE: (drop after 2.6.31) saa7134: ir-kbd-i2c init data needs a
+    persistent object
+
+  [ Takashi Iwai ]
+
+  * [Upstream] ALSA: hda - Add another entry for Nvidia HDMI device
+    - LP: #416482
+
+  [ Tyler Hicks ]
+
+  * SAUCE: (drop after 2.6.31) eCryptfs: Prevent lower dentry from going
+    negative during unlink
+
+  [ Upstream Kernel Changes ]
+
+  * sg: fix oops in the error path in sg_build_indirect()
+  * mpt2sas : Rescan topology from Interrupt context instead of work thread
+  * mpt2sas: Prevent sending command to FW while Host Reset
+  * mpt2sas: setting SDEV into RUNNING state from Interrupt context
+  * mpt2sas: Raid 10 Volume is showing as Raid 1E in dmesg
+  * SCSI: fix oops during scsi scanning
+  * SCSI: libsrp: fix memory leak in srp_ring_free()
+  * cfg80211: fix looping soft lockup in find_ie()
+  * ath5k: write PCU registers on initial reset
+  * binfmt_elf: fix PT_INTERP bss handling
+  * TPM: Fixup boot probe timeout for tpm_tis driver
+  * md: Fix "strchr" [drivers/md/dm-log-userspace.ko] undefined!
+  * x86/amd-iommu: fix broken check in amd_iommu_flush_all_devices
+  * fix undefined reference to user_shm_unlock
+  * perf_counter: Fix buffer overflow in perf_copy_attr()
+  * perf_counter: Start counting time enabled when group leader gets
+    enabled
+  * powerpc/perf_counters: Reduce stack usage of power_check_constraints
+  * powerpc: Fix bug where perf_counters breaks oprofile
+  * powerpc/ps3: Workaround for flash memory I/O error
+  * block: don't assume device has a request list backing in nr_requests
+    store
+  * agp/intel: remove restore in resume
+  * ALSA: cs46xx - Fix minimum period size
+  * ASoC: Fix WM835x Out4 capture enumeration
+  * sound: oxygen: work around MCE when changing volume
+  * mlx4_core: Allocate and map sufficient ICM memory for EQ context
+  * perf stat: Change noise calculation to use stddev
+  * x86: Fix x86_model test in es7000_apic_is_cluster()
+  * x86/i386: Make sure stack-protector segment base is cache aligned
+  * PCI: apply nv_msi_ht_cap_quirk on resume too
+  * x86, pat: Fix cacheflush address in change_page_attr_set_clr()
+  * ARM: 5691/1: fix cache aliasing issues between kmap() and kmap_atomic()
+    with highmem
+  * KVM guest: do not batch pte updates from interrupt context
+  * KVM: Fix coalesced interrupt reporting in IOAPIC
+  * KVM: VMX: Check cpl before emulating debug register access
+  * KVM guest: fix bogus wallclock physical address calculation
+  * KVM: x86: Disallow hypercalls for guest callers in rings > 0
+  * KVM: VMX: Fix cr8 exiting control clobbering by EPT
+  * KVM: x86 emulator: Implement zero-extended immediate decoding
+  * KVM: MMU: make __kvm_mmu_free_some_pages handle empty list
+  * KVM: x86 emulator: fix jmp far decoding (opcode 0xea)
+  * KVM: limit lapic periodic timer frequency
+  * libata: fix off-by-one error in ata_tf_read_block()
+  * PCI quirk: update 82576 device ids in SR-IOV quirks list
+  * PCI: Unhide the SMBus on the Compaq Evo D510 USDT
+  * powerpc/pseries: Fix to handle slb resize across migration
+  * Linux 2.6.31.1
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 24 Sep 2009 13:04:28 -0600
+
+linux (2.6.31-10.35) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * Disable CONFIG_UEVENT_HELPER_PATH
+
+  [ Andy Whitcroft ]
+
+  * [Config] Enable CONFIG_USB_GADGET_DUMMY_HCD
+  * remove the tlsup driver
+  * remove lmpcm logitech driver support
+
+  [ Bryan Wu ]
+
+  * Add 3 missing files to prerm remove file list
+    - LP: #345623, #415832
+
+  [ Chris Wilson ]
+
+  * [Upstream] drm/i915: Check that the relocation points to within the
+    target
+    - LP: #429241
+
+  [ Luke Yelavich ]
+
+  * [Config] Set CONFIG_EXT4_FS=y on ports architectures
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Added quirk to recognize GE0301 3G modem as an interface.
+    - LP: #348861
+
+  [ Tim Gardner ]
+
+  * Revert "[Upstream] ACPI: Add Thinkpad W500, W700, & W700ds to OSI(Linux) white-list"
+  * Revert "[Upstream] ACPI: Add Thinkpad R400 & Thinkpad R500 to OSI(Linux) white-list"
+  * Revert "[Upstream] ACPI: Add Thinkpad X300 & Thinkpad X301 to OSI(Linux) white-list"
+  * Revert "[Upstream] ACPI: Add Thinkpad X200, X200s, X200t to OSI(Linux) white-list"
+  * Revert "[Upstream] ACPI: Add Thinkpad T400 & Thinkpad T500 to OSI(Linux) white-list"
+    Upstream suggests that this is not the right approach.
+
+  * [Config] Set default I/O scheduler to DEADLINE
+    CFQ seems to have some load related problems which are often exacerbated by sreadahead.
+    - LP: #381300
+
+  [ ubuntu@tjworld.net ]
+
+  * SAUCE: ipw2200: Enable LED by default
+    - LP: #21367
+
+  [ Upstream Kernel Changes ]
+
+  * ALSA: hda - Add support for new AMD HD audio devices
+    - LP: #430564
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 16 Sep 2009 15:37:49 +0100
+
+linux (2.6.31-10.34) karmic; urgency=low
+
+  [ Ted Tso ]
+
+  * [Upstream] ext3: Don't update superblock write time when filesystem is
+    read-only
+    - LP: #427822
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Sep 2009 16:00:45 -0600
+
+linux (2.6.31-10.33) karmic; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Upstream] dvb-usb: fix tuning with Cinergy T2
+    - LP: #421258
+
+  [ Tim Gardner ]
+
+  * [Config] Unconditionally copy files from sub-flavours lists.
+    (really, really fix it this time)
+    - LP: #423426
+  * [Config] Set CONFIG_CACHEFILES=m for all flavours
+
+  [ Upstream Kernel Changes ]
+
+  * ext4: Don't update superblock write time when filesystem is read-only
+    - LP: #427822
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Sep 2009 07:50:21 -0600
+
+linux (2.6.31-10.32) karmic; urgency=low
+
+  [ Eric Miao ]
+
+  * [Config] enable module support for memory stick
+    - LP: #159951
+
+  [ Tim Gardner ]
+
+  * [Config] Unconditionally copy files from sub-flavours lists.
+    - LP: #423426
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 10 Sep 2009 15:57:55 -0600
+
+linux (2.6.31-10.31) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.31 final
+
+  [ Colin Watson ]
+
+  * [Config] Recommend grub-pc in linux-image
+    - LP: #385741
+
+  [ Ike Panhc ]
+
+  * [Upstream] Pull latest update of lenovo-sl-laptop
+
+  [ Peter Feuerer ]
+
+  * [Upstream] (drop after 2.6.31) acerhdf: fix fan control for AOA150
+    model
+    - LP: #426691
+
+  [ Tim Gardner ]
+
+  * [Config] De-macro some package names.
+
+  [ Upstream Changes ]
+
+  * rebase to 2.6.31 final.
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 10 Sep 2009 09:38:10 +0100
+
+linux (2.6.31-10.30) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * [Config] Enable CONFIG_USB_DEVICEFS
+    - LP: #417748
+  * [Config] Populate the config-update template a bit more
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.31-rc9
+  * [Config] update configs following rebase to v2.6.31-rc9
+  * [Config] update ports configs following rebase to v2.6.31-rc9
+
+  [ Colin Ian King ]
+
+  * SAUCE: wireless: hostap, fix oops due to early probing interrupt
+    - LP: #254837
+
+  [ Jerone Young ]
+
+  * [Upstream] ACPI: Add Thinkpad T400 & Thinkpad T500 to OSI(Linux)
+    white-list
+    - LP: #281732
+  * [Upstream] ACPI: Add Thinkpad X200, X200s, X200t to OSI(Linux)
+    white-list
+    - LP: #281732
+  * [Upstream] ACPI: Add Thinkpad X300 & Thinkpad X301 to OSI(Linux)
+    white-list
+    - LP: #281732
+  * [Upstream] ACPI: Add Thinkpad R400 & Thinkpad R500 to OSI(Linux)
+    white-list
+    - LP: #281732
+  * [Upstream] ACPI: Add Thinkpad W500, W700, & W700ds to OSI(Linux)
+    white-list
+    - LP: #281732
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: Fix profile attachment for regexp based profile names
+    - LP: #419308
+  * SAUCE: AppArmor: Return the correct error codes on profile
+    addition/removal
+    - LP: #408473
+  * SAUCE: AppArmor: Fix OOPS in profile listing, and display full list
+    - LP: #408454
+  * SAUCE: AppArmor: Fix mapping of pux to new internal permission format
+    - LP: #419222
+  * SAUCE: AppArmor: Fix change_profile failure
+    - LP: #401931
+  * SAUCE: AppArmor: Tell git to ignore generated include files
+    - LP: #419505
+
+  [ Stefan Bader ]
+
+  * [Upstream] acpi: video: Loosen strictness of video bus detection code
+    - LP: #333386
+  * SAUCE: Remove ov511 driver from ubuntu subdirectory
+
+  [ Tim Gardner ]
+
+  * [Config] Exclude char-modules from non-x86 udeb creation
+  * SAUCE: Notify the ACPI call chain of AC events
+  * [Config] CONFIG_SATA_VIA=m
+    - LP: #403385
+  * [Config] Build in all phylib support modules.
+  * [Config] Don't fail when sub-flavour files are missing
+    - LP: #423426
+  * [Config] Set CONFIG_LSM_MMAP_MIN_ADDR=0
+    - LP: #423513
+
+  [ Upstream ]
+
+  * Rebased against v2.6.31-rc9
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 07 Sep 2009 11:33:45 +0100
+
+linux (2.6.31-9.29) karmic; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Upstream] agp/intel: support for new chip variant of IGDNG mobile
+    - LP: #419993
+  * [Config] d-i/modules: Add new char-modules file, initialize with
+    intel-agp
+    - LP: #420605
+
+  [ Upstream ]
+
+  * Rebased against 2.6.31-rc8 plus some inotify regression patches:
+    up through git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+    adda766193ea1cf3137484a9521972d080d0b7af.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 28 Aug 2009 06:31:30 -0600
+
+linux (2.6.31-8.28) karmic; urgency=low
+
+  [ Ike Panhc ]
+
+  * [Config] Let nic-shared-modules depends on crypto-modules
+    - LP: #360966
+
+  [ Leann Ogasawara ]
+
+  * [Upstream] (drop after 2.6.31) drm/i915: increase default latency
+    constant
+    - LP: #412492
+
+  [ Mario Limonciello ]
+
+  * [Upstream]: (drop after 2.6.31) dell-laptop: don't change softblock
+    status if HW switch is disabled
+    - LP: #418721
+  * [Upstream]: (drop after 2.6.31) compal-laptop: Add support for known
+    Compal made Dell laptops
+  * [Upstream]: (drop after 2.6.31) compal-laptop: Replace sysfs support
+    with rfkill support
+
+  [ Tim Gardner ]
+
+  * [Config] Add acpiphp to virtual sub-flavour
+    - LP: #364916
+  * Drop KSM patch set for now because of instabilities with encrypted swap.
+    - LP: #418781
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 26 Aug 2009 08:14:26 -0600
+
+linux (2.6.31-7.27) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] updateconfigs updateportsconfigs after 2.6.31-rc7 rebase
+  * SAUCE: (drop after 2.6.31) Added KSM from mmotm-2009-08-20-19-18
+    Replaces previous ksm patches from 2.6.31-6.25
+  * [Config] KSM=y
+
+  [ Upstream ]
+
+  * Rebased against v2.6.31-rc7
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sat, 22 Aug 2009 20:32:11 -0600
+
+linux (2.6.31-6.26) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_AUFS_BR_RAMFS
+    - LP: #414738
+  * split out debian directory ready for abstraction
+  * add printdebian target to find branch target
+  * abstracted debian -- debian/files is not abstracted
+  * abstracted debian -- packages must be built in debian/<pkg>
+  * abstracted debian -- kernel-wedge needs to work in debian/
+  * abstracted debian -- ensure we install the copyright file
+  * abstracted-debian -- drop the debian directories from headers
+  * abstracted-debian -- drop the debian directories from headers part 2
+  * SAUCE: ubuntu-insert-changes -- follow abstracted debian
+  * [Upstream] aoe: ensure we initialise the request_queue correctly V2
+    - LP: #410198
+
+  [ Luke Yelavich ]
+
+  * [Config] Ports: Disable CONFIG_CPU_FREQ_DEBUG on powerpc-smp
+  * [Config] Ports: Re-enable windfarm modules on powerpc64-smp
+    - LP: #413150
+  * [Config] Ports: Build all cpu frequency scaling governors into ports
+    kernels
+  * [Config] Ports: Build ext2 and ext3 modules into ports kernels
+  * [Config] Ports: CONFIG_PACKET=y for all ports kernels
+  * [Config] Ports: Enable PS3 network driver
+
+  [ Stefan Bader ]
+
+  * abstracted debian -- call $(DEBIAN)/rules using make
+
+  [ Tim Gardner ]
+
+  * [Config] Abstract the debian directory
+  * SAUCE: Improve error reporting in postinst
+    - LP: #358564
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sun, 16 Aug 2009 20:33:28 -0600
+
+linux (2.6.31-6.25) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * script to generate Ubuntu changes from changelog
+  * [Config] standardise ANDROID options
+  * [Config] standardise CONFIG_ATM as module
+  * [Config] standardise CONFIG_LIB80211 as module
+  * [Config] disable CONFIG_PRINT_QUOTA_WARNING
+  * [Config] set CONFIG_CRAMFS as module
+  * [Config] enable CONFIG_DAB and modules
+  * [Config] set CONFIG_MAC80211_HWSIM as module
+  * [Config] set CONFIG_NET_CLS_FLOW as module
+  * [Config] set CONFIG_NF_CONNTRACK_SANE as module
+  * [Config] set CONFIG_NF_CT_PROTO_DCCP as module
+  * [Config] set CONFIG_RTC_DRV_DS1511 as module
+  * [Config] set CONFIG_RTC_DRV_R9701 as module
+  * [Config] set CONFIG_RTC_DRV_S35390A as module
+  * [Config] set CONFIG_TOIM3232_DONGLE as module
+  * [Config] standardise CONFIG_USB_MIDI_GADGET as module
+  * [Config] standardise CONFIG_USB_G_PRINTER as module
+  * [Config] standardise CONFIG_USB_SERIAL_IR as module
+  * [Config] set CONFIG_USB_SERIAL_IUU as module
+  * [Config] standardise CONFIG_USB_STORAGE_CYPRESS_ATACB as module
+  * [Config] standardise CONFIG_USB_STORAGE_ONETOUCH as module
+  * cleanup remains of dm-loop
+  * drop thinkpad ec and smapi support
+  * drop appleir
+  * [Config] update configs following rebase to v2.6.31-rc6
+  * rebase to v2.6.31-rc6
+
+  [ Hugh Dickins ]
+
+  * SAUCE: ksm patch 1, drop after 2.6.31
+  * SAUCE: ksm patch 2, drop after 2.6.31
+  * SAUCE: ksm patch 3, drop after 2.6.31
+  * SAUCE: ksm patch 4, drop after 2.6.31
+  * SAUCE: ksm patch 5, drop after 2.6.31
+  * SAUCE: ksm patch 7, drop after 2.6.31
+
+  [ Izik Eidus ]
+
+  * SAUCE: ksm patch 0, drop after 2.6.31
+  * SAUCE: ksm patch 6, drop after 2.6.31
+  * SAUCE: ksm patch 8, drop after 2.6.31
+  * SAUCE: ksm patch 9, drop after 2.6.31
+
+  [ Luke Yelavich ]
+
+  * [Config] Ports: Re-add PS3 modules to udebs
+
+  [ Michael Casadevall ]
+
+  * [Config] Update SPARC config and d-i files to reflect what can be built
+
+  [ Tim Gardner ]
+
+  * [Config] Removed armel package support
+  * [Config] Enabled CONFIG_KSM=y
+
+  [ Upstream Kernel Changes ]
+
+  * Rebased against v2.6.31-rc6
+  * ARM: Cleanup: Revert "ARM: Add more cache memory types macros"
+  * ARM: Cleanup: Revert "Do not use OOB with MLC NAND"
+  * ARM: Cleanup: Revert "ARM: Make ARM arch aware of ubuntu/ drivers"
+  * ARM: Cleanup: Revert "ARM: IMX51: Make video capture drivers compile"
+  * ARM: Cleanup: Revert "ARM: IMX51: Fix isl29003 HWMON driver for i2c
+    changes"
+  * ARM: Cleanup: Revert "ARM: IMX51: IPU irq handler deadlock fix"
+  * ARM: Cleanup: Revert "ARM: IMX51: Babbage 2.5 needs a different system
+    revision"
+  * ARM: Cleanup: Revert "ARM: IMX51: Compile-in the IMX51 cpufreq driver
+    by default"
+  * ARM: Cleanup: Revert "ARM: IMX51: Enable ZONE_DMA for ARCH_MXC"
+  * ARM: Cleanup: Revert "ARM: IMX51: Make ARCH_MXC auto-enable
+    ARCH_MXC_CANONICAL"
+  * ARM: Cleanup: Revert "ARM: IMX51: Unconditionally disable
+    CONFIG_GPIOLIB"
+  * ARM: Cleanup: Revert "ARM: IMX51: Minimal changes for USB to work on
+    2.6.31"
+  * ARM: Cleanup: Revert "ARM: IMX51: Fix plat-mxc/timer.c to handle imx51"
+  * ARM: Cleanup: Revert "ARM: IMX51: Make it compile."
+  * ARM: Cleanup: Revert "ARM: IMX51: Clean-up the craziness of including
+    mxc_uart.h _everywhere_"
+  * ARM: Cleanup: Revert "ARM: IMX51: Move board-mx51* header files to the
+    correct location"
+  * ARM: Cleanup: Revert "ARM: IMX51: Changed from snd_card_new to
+    snd_card_create"
+  * ARM: Cleanup: Revert "ARM: IMX51: Fix up merge error in Kconfig"
+  * ARM: Cleanup: Revert "ARM: IMX51: mxc_timer_init prototype"
+  * ARM: Cleanup: Revert "ARM: IMX51: Removed the mxc_gpio_port structure."
+  * ARM: Cleanup: Revert "ARM: IMX51: Added external declaration for
+    mxc_map_io."
+  * ARM: Cleanup: Revert "ARM: IMX51: Get to bus_id by calling dev_name."
+  * ARM: Cleanup: Revert "ARM: IMX51: Get to bus_id by calling dev_name."
+  * ARM: Cleanup: Revert "ARM: IMX51: snd_soc_machine structure replaced
+    with snd_soc_card."
+  * ARM: Cleanup: Revert "ARM: IMX51: codec structure was moved to the card
+    structure"
+  * ARM: Cleanup: Revert "ARM: IMX51: Hack to add defines for
+    DMA_MODE_READ/WRITE/MASK"
+  * ARM: Cleanup: Revert "ARM: IMX51: Add SoC and board support for
+    Freescale mx51 platform"
+  * Driver core: add new device to bus's list before probing
+  * [Upstream] (drop after 2.6.31) ALSA: hda - Reduce click noise at
+    power-saving
+    - LP: #381693, #399750, #380892
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 14 Aug 2009 11:32:23 +0100
+
+linux (2.6.31-5.24) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * ARM: IMX51: Make video capture drivers compile
+  * [Config] IMX51: Config updates
+
+  [ Andy Whitcroft ]
+
+  * remove leftovers of dm-bbr
+
+  [ Leann Ogasawara ]
+
+  * Add pata_cs5535 to pata-modules
+    - LP: #318805
+
+  [ Luke Yelavich ]
+
+  * [Config] CONFIG_PPC64=y for powerpc64-smp
+  * [Config] Set the maximum number of CPUs to 1024 for powerpc64-smp
+  * [Config] CONFIG_PPC_PS3=y for powerpc64-smp
+  * [Config] CONFIG_PPC_MAPLE=y on powerpc64-smp
+  * [Config] CONFIG_PPC_PASEMI=y on powerpc64-smp
+  * [Config] CONFIG_CPU_FREQ_PMAC64=y on powerpc64-smp
+  * [Config] Enable all PS3 drivers in powerpc64-smp
+
+  [ Mario Limonciello ]
+
+  * LIRC -- fix lirc-i2c 2.6.31 compilation
+
+  [ Matthew Garrett ]
+
+  * [Upstream] dell-laptop: Fix rfkill state queries
+
+  [ Tim Gardner ]
+
+  * [Config] Ignore armel ABI and module changes
+  * [Config] Update configs after rebase against 2.6.31-rc5
+
+  [ Upstream ]
+
+  * Rebased to 2.6.31-rc5
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 28 Jul 2009 10:10:09 +0100
+
+linux (2.6.31-4.23) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * AUFS -- update to aufs2-30 20090727
+  * [Config] enable AUFS FUSE support
+
+  [ Luke Yelavich ]
+
+  * [Config] CONFIG_JFS_FS=m on sparc
+
+  [ Tim Gardner ]
+
+  * [Upstream] dell-laptop: Fix rfkill state setting.
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 27 Jul 2009 11:11:47 +0100
+
+linux (2.6.31-4.22) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * ARM: IMX51: Add SoC and board support for Freescale mx51 platform
+  * ARM: IMX51: Move board-mx51* header files to the correct location
+  * ARM: IMX51: Clean-up the craziness of including mxc_uart.h _everywhere_
+  * ARM: IMX51: Make it compile.
+  * ARM: IMX51: Unconditionally disable CONFIG_GPIOLIB
+  * ARM: IMX51: Make ARCH_MXC auto-enable ARCH_MXC_CANONICAL
+  * ARM: IMX51: Enable ZONE_DMA for ARCH_MXC
+  * ARM: IMX51: Compile-in the IMX51 cpufreq driver by default
+  * ARM: IMX51: Fix isl29003 HWMON driver for i2c changes
+  * ARM: USB: musb: Refer to musb_otg_timer_func under correct #ifdef
+  * ARM: staging: udlfb: Add vmalloc.h include
+  * UBUNTU [Config]: Bring imx51 config upto date with other flavours
+
+  [ Brad Figg ]
+
+  * ARM: IMX51: Hack to add defines for DMA_MODE_READ/WRITE/MASK
+  * ARM: IMX51: codec structure was moved to the card structure
+  * ARM: IMX51: snd_soc_machine structure replaced with snd_soc_card.
+  * ARM: IMX51: Get to bus_id by calling dev_name.
+  * ARM: IMX51: Get to bus_id by calling dev_name.
+  * ARM: IMX51: Added external declaration for mxc_map_io.
+  * ARM: IMX51: Removed the mxc_gpio_port structure.
+  * ARM: IMX51: mxc_timer_init prototype
+  * ARM: IMX51: Fix up merge error in Kconfig
+  * ARM: IMX51: Changed from snd_card_new to snd_card_create
+
+  [ Dinh Nguyen ]
+
+  * ARM: IMX51: Fix plat-mxc/timer.c to handle imx51
+  * ARM: IMX51: Minimal changes for USB to work on 2.6.31
+  * ARM: IMX51: Babbage 2.5 needs a different system revision
+  * ARM: IMX51: IPU irq handler deadlock fix
+
+  [ Tim Gardner ]
+
+  * [Config] Enabled CONFIG_CAN=m
+    - LP: #327243
+  * [Config] Enabled CONFIG_SERIAL=m
+    - LP: #397189
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 24 Jul 2009 06:19:10 -0600
+
+linux (2.6.31-4.21) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * dm-raid-4-5: Add missing brackets around test_bit()
+
+  [ John Johansen ]
+
+  * AppArmor: Fix change_profile failing lpn401931
+  * AppArmor: Fix determination of forced AUDIT messages.
+  * AppArmor: Fix oops in auditing of the policy interface offset
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 23 Jul 2009 19:18:30 +0100
+
+linux (2.6.31-4.20) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: iscsitarget -- update to SVN revision r214
+  * SAUCE: iscsitarget -- renable driver
+  * [Config] consolidate lpia/lpia and i386/generic configs
+  * [Config] enable CRYPTO modules for all architectures
+  * [Config] enable cryptoloop
+  * [Config] enable various filesystems for armel
+  * [Config] sync i386 generic and generic-pae
+  * [Config] add the 386 (486 processors and above) flavour
+  * [Config] re-set DEFAULT_MMAP_MIN_ADDR
+    - LP: #399914
+  * add genconfigs/genportsconfigs to extract the built configs
+  * updateconfigs -- alter concatenation order allow easier updates
+  * intelfb -- INTELFB now conflicts with DRM_I915
+  * printchanges -- rebase tree does not have stable tags use changelog
+  * AppArmor: fix argument size missmatch on 64 bit builds
+
+  [ Ike Panhc ]
+
+  * Ship bnx2x firmware in nic-modules udeb
+    - LP: #360966
+
+  [ Jeff Mahoney ]
+
+  * AppArmor: fix build failure on ia64
+
+  [ John Johansen ]
+
+  * AppArmour: ensure apparmor enabled parmater is off if AppArmor fails to
+    initialize.
+  * AppArmour: fix auditing of domain transitions to include target profile
+    information
+  * AppArmor: fix C99 violation
+  * AppArmor: revert reporting of create to write permission.
+  * SAUCE: Add config option to set a default LSM
+  * [Config] enable AppArmor by default
+  * AppArmor: Fix NULL pointer dereference oops in profile attachment.
+
+  [ Keith Packard ]
+
+  * SAUCE: drm/i915: Allow frame buffers up to 4096x4096 on 915/945 class
+    hardware
+    - LP: #351756
+
+  [ Luke Yelavich ]
+
+  * [Config] add .o files found in arch/powerpc/lib to all powerpc kernel
+    header packages
+    - LP: #355344
+
+  [ Michael Casadevall ]
+
+  * [Config] update SPARC config files to allow success build
+
+  [ Scott James Remnant ]
+
+  * SAUCE: trace: add trace_event for the open() syscall
+
+  [ Stefan Bader ]
+
+  * SAUCE: jfs: Fix early release of acl in jfs_get_acl
+    - LP: #396780
+
+  [ Tim Gardner ]
+
+  * [Upstream] Fix Soltech TA12 volume hotkeys not sending key release
+    - LP: #397499
+  * [Upstream] USB Option driver - Add USB ID for Novatel MC727/U727/USB727
+    refresh
+    - LP: #365291
+  * [Config] SSB/B44 are common across all arches/flavours.
+
+  [ Upstream ]
+
+  * Rebased to 2.6.31-rc4
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 23 Jul 2009 08:41:39 +0100
+
+linux (2.6.31-3.19) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] Disabled NDISWRAPPER"
+  * ndiswrapper -- fix i386 compilation failures on cmpxchg8b
+  * AUFS -- export various core functions
+  * AUFS -- export various core functions -- fixes
+  * AUFS -- core filesystem
+  * AUFS -- track changes in v2.6.31
+  * [Config] Enable AUFS
+  * droppped 'iwl3945: do not send scan command if channel count zero' as it
+    is already upstream but failed to auto-drop on rebase.
+
+  [ Eric Paris ]
+
+  * SAUCE: fsnotify: use def_bool in kconfig instead of letting the user
+    choose
+  * SAUCE: inotify: check filename before dropping repeat events
+  * SAUCE: fsnotify: fix inotify tail drop check with path entries
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 14 Jul 2009 12:52:55 +0100
+
+linux (2.6.31-3.18) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "Add splice-2.6.23.patch from AUFS to export a symbol needed by
+    AUFS"
+  * Revert "Add put_filp.patch from AUFS to export a symbol needed by AUFS"
+  * Revert "Add sec_perm-2.6.24.patch from AUFS - export
+    security_inode_permission"
+  * clear out left over AUFS files and modifications
+
+  [ Luke Yelavich ]
+
+  * [Config] Enable CONFIG_USB_ISP116X_HCD on sparc
+  * SAUCE: Explicitly include header files to allow apparmor to build on
+    powerpc
+  * [Config] Enable CONFIG_BLK_DEV_IDECD on powerpc
+
+  [ Tim Gardner ]
+
+  * [Config] Dropped ubuntu/misc/wireless/acx
+  * [Config] Disabled NDISWRAPPER until the compile issues are fixed.
+
+  [ Upstream ]
+
+  * Rebased to 2.6.31-rc3
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 10 Jul 2009 18:59:33 +0100
+
+linux (2.6.31-2.17) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_BLK_DEV_CRYPTOLOOP=m for sparc
+  * compcache -- remove redundant Kconfig entries part 2
+  * compcache -- clean up CCFLAGS declarations
+  * [Config] enable AppArmor
+  * AppArmor: fix operator precidence issue in as_path_link
+
+  [ John Johansen ]
+
+  * AppArmor security module
+  * AppArmor: Correct mapping of file permissions.
+  * AppArmor: Turn auditing of ptrace on
+
+  [ Luke Yelavich ]
+
+  * [Config] disable CONFIG_DM_RAID45 on powerpc
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 10 Jul 2009 15:02:05 +0100
+
+linux (2.6.31-2.16) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * compcache -- remove redundant Kconfig entries
+    added ignore and ignore.modules for all arches since the compcache update
+    changes the modules names as well as some compcache ABI values.
+
+  [ Manoj Iyer ]
+
+  * SAUCE: updated dm-raid45 module version to 2009.04.24 (2.6.30-rc3)
+  * SAUCE: update compcache version to 0.5.3
+
+  [ Tim Gardner ]
+
+  * [Config]: Fix sparc FTBS by adding ignore.modules
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 06 Jul 2009 13:35:29 -0600
+
+linux (2.6.31-2.15) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: default ATI Radeon KMS to off until userspace catches up
+  * [Config] Update configs following rebase to 2.6.31-rc2
+  * [Config] update ports configs following update to 2.6.31-rc2
+
+  [ Luke Yelavich ]
+
+  * [Config] powerpc - Disable CONFIG_RDS
+
+  [ Matt Zimmerman ]
+
+  * Rename linux-doc-PKGVER to linux-doc and clean up its description
+    - LP: #382115
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to mainline 2.6.31-rc2
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 04 Jul 2009 17:39:13 +0100
+
+linux (2.6.31-1.14) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * update ndiswrapper to 1.55
+  * remove leftovers of gfs
+  * [Config] powerpc: enable CONFIG_PPC_DISABLE_WERROR
+
+  [ Luke Yelavich ]
+
+  * [Config] re-enable and build the ide-pmac driver into powerpc kernels
+  * [Config] Build the ServerWorks Frodo / Apple K2 SATA driver into the
+    kernel
+
+  [ Manoj Iyer ]
+
+  * Remove snd-bt-sco ubuntu driver
+
+  [ Michael Casadevall ]
+
+  * [Config] updates ia64 config and d-i folders to allow succesful build
+  * [Config] Update powerpc and sparc for 2.6.31
+
+  [ Upstream Kernel Changes ]
+
+  * intel-iommu: fix Identity Mapping to be arch independent
+    - LP: #384695
+  * ACPI: video: prevent NULL deref in acpi_get_pci_dev()
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 30 Jun 2009 17:47:32 +0100
+
+linux (2.6.31-1.13) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * REBASE: rebased to mainline 2.6.31-rc1
+    - "UBUNTU: SAUCE: UHCI USB quirk for resume"
+      no longer applies, using deprecated interfaces, LPIA only, dropped
+    - "UBUNTU: SAUCE: Mask off garbage in Dell WMI scan code data"
+      changes now upstream, dropped
+  * [Config] Update configs following rebase to 2.6.31-rc1
+  * [Config] update ports configs following update to 2.6.31-rc1
+
+  * [Config] disable broken staging driver CONFIG_STLC45XX
+  * SAUCE: fix compcache to use updates accessors
+  * [Config] disable staging driver CONFIG_VT6655
+  * SAUCE: fix DRDB to use updates accessors
+  * [Disable] ndiswrapper needs update
+  * [Disable] LIRC I2C needs update
+  * [Disable] CONFIG_LENOVO_SL_LAPTOP needs update
+  * [Config] disable I2C_DESIGNWARE does not compile
+  * [Config] disable CONFIG_TLSUP for lpia
+  * [Config] disable CONFIG_FB_UDL for arm
+  * SAUCE: disable adding scsi headers to linux-libc-dev
+
+  [ Mario Limonciello ]
+
+  * SAUCE: Add LIRC drivers
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 25 Jun 2009 12:06:22 +0100
+
+linux (2.6.30-10.12) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] split out the ports configs into their own family
+  * [Config] update configs following introduction of ports family
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Rename linux-doc-PKGVER to linux-doc and clean up its
+    description". Fixes linux-doc package name conflicts for now.
+    - LP: #382115
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 22 Jun 2009 09:17:14 -0600
+
+linux (2.6.30-10.11) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * [Config] Comment splitconfig.pl and misc cleanup
+  * [Config] Rename all configs to the new naming scheme
+  * [Config] Splitconfig rework
+  * [Config] Rename scripts/misc/oldconfig to kernelconfig
+  * [Config] Fix build system for new config split
+  * [Config] Run updateconfigs after the splitconfig rework
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: Default to i915.modeset=0 if CONFIG_DRM_I915_KMS=y"
+  * [Config] standardise CONFIG_STAGING=y
+  * [Config] standardise CONFIG_RD_LZMA=y
+  * [Config] CONFIG_PCI_IOV=y
+  * [Config] CONFIG_PCI_STUB=m
+  * [Config] merge kernel configs more agressively
+
+  [ Colin Watson ]
+
+  * [Config] Run kernel-wedge in $(builddir) rather than at the top level
+  * [Config] Add support for including firmware in udebs
+  * [Config] Ship bnx2 firmware in nic-modules udeb
+    - LP: #384861
+
+  [ Luke Yelavich ]
+
+  * [Config] ports - Import of ports architectures into kernel packaging
+    infrastructure
+  * [Config] ports - Do not update ports kernel configurations by default
+  * [Config] ports - Disable ABI checking for ports architectures
+  * [Config] ports - Build drivers in ubuntu sub-directory on powerpc
+  * [Config] ports - Add control.d/vars.* files for ports architectures
+  * [Config] ports - Add ports architectures for linux-libc-dev
+  * [Config] ports - Create powerpc specific message-modules and
+    block-modules udebs
+  * [Config] ports - Add configuration files for ports architectures
+
+  [ Manoj Iyer ]
+
+  * [Config] Enable CONFIG_BLK_DEV_AEC62XX=m for amd64 and i386
+    - LP: #329864
+
+  [ Michael Casadevall ]
+
+  * [Config] ports - Fix compression of kernels
+
+  [ Stefan Bader ]
+
+  * [Upstream] mmc: prevent dangling block device from accessing stale
+    queues
+    - LP: #383668
+
+  [ Tim Gardner ]
+
+  * [Config] Recommend grub-pc in linux-image
+    - LP: #385741
+  * [Config] Implement i386 generic and generic-pae flavours
+  * [Config] ports - Add control info after integrating ports arches
+  * [Config] Removed auto-generated files from git
+  * [Config] Added netxen_nic to nic-modules
+    - LP: #389603
+
+  [ Matt Zimmerman ]
+
+  * Rename linux-doc-PKGVER to linux-doc and clean up its description
+    - LP: #382115
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 15 Jun 2009 14:38:26 -0600
+
+linux (2.6.30-9.10) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_SECURITY_TOMOYO=y (amd64, i386, lpia)
+  * [Config] CONFIG_KEXEC_JUMP=y (amd64, lpia)
+  * [Config] CONFIG_LENOVO_SL_LAPTOP=m (amd64, lpia)
+  * [Config] CONFIG_POHMELFS_CRYPTO=y (i386, amd64)
+  * [Config] CONFIG_SERIAL_MAX3100=m (i386, amd64, lpia)
+  * [Config] CONFIG_VIDEO_GO7007=m (amd64, i386)
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30 final
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Jun 2009 11:42:53 +0100
+
+linux (2.6.30-8.9) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Config update removed the following options:
+        CONFIG_EDAC_AMD8111=m
+        CONFIG_EDAC_AMD8131=m
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc8
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 03 Jun 2009 09:21:13 +0100
+
+linux (2.6.30-7.8) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Enabled NEW configration options:
+      Paravirtualization layer for spinlocks (PARAVIRT_SPINLOCKS) [N/y/?] Y
+      Cisco FNIC Driver (FCOE_FNIC) [N/m/y/?] M
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc7
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 23 May 2009 23:47:24 +0100
+
+linux (2.6.30-6.7) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Dropped: UBUNTU: SAUCE: input: Blacklist digitizers from joydev.c (now
+    upstream)
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc6
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 18 May 2009 18:05:54 +0100
+
+linux (2.6.30-5.6) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Enable Keyspan USB serial device firmware in kernel module
+    - LP: #334285
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc5
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 11 May 2009 12:02:16 -0600
+
+linux (2.6.30-4.5) karmic; urgency=low
+
+  [ Colin Watson ]
+
+  * Build-Conflict with findutils (= 4.4.1-1ubuntu1), to avoid
+    /usr/include/asm/* going missing
+    - LP: #373214
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 08 May 2009 11:09:08 +0200
+
+linux (2.6.30-3.4) karmic; urgency=low
+
+  [ Kees Cook ]
+
+  * SAUCE: [x86] implement cs-limit nx-emulation for ia32
+    - LP: #369978
+
+  [ Stefan Bader ]
+
+  * SAUCE: input: Blacklist digitizers from joydev.c
+    - LP: #300143
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 01 May 2009 14:00:42 -0600
+
+linux (2.6.30-2.3) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Enabled CC_STACKPROTECTOR=y for all x86en
+    - LP: #369152
+  * SAUCE: Default to i915_modeset=0 if CONFIG_DRM_I915_KMS=y
+  * [Config] CONFIG_DRM_I915_KMS=y
+  * [Config] Set CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR to appropriate ARCH
+    minimums
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc4
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 30 Apr 2009 09:17:05 -0600
+
+linux (2.6.30-1.2) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] armel: disable staging drivers, fixes FTBS
+  * [Config] armel imx51: Disable CONFIG_MTD_NAND_MXC, fixes FTBS
+
+  [ Upstream Kernel Changes ]
+
+  * mpt2sas: Change reset_type enum to avoid namespace collision.
+    Submitted upstream.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 28 Apr 2009 16:54:41 -0600
+
+linux (2.6.30-1.1) karmic; urgency=low
+
+  * Initial release after rebasing against v2.6.30-rc3
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 12 Mar 2009 19:16:07 -0600
+
--- linux-4.4.0.orig/debian.master/changelog.historical
+++ linux-4.4.0/debian.master/changelog.historical
@@ -0,0 +1,4171 @@
+
+linux (2.6.28-9.31) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: cpufreq-nforce2: probe failures are not errors
+    - LP: #332170
+  * SAUCE: mmc: add MODALIAS linkage for MMC/SD devices
+    - LP: #30335
+  * remove test-suspend script
+    - LP: #333856
+
+  [ Kees Cook ]
+
+  * handle relative paths in modules.dep
+    Fixes 2.6.28-9.30 FTBS.
+
+  [ Upstream Kernel Changes ]
+
+  * ricoh_mmc: Handle newer models of Ricoh controllers
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 11 Mar 2009 08:19:24 -0600
+
+linux (2.6.28-9.30) jaunty; urgency=low
+
+  [ Amit Kucheria ]
+
+  * ARM:mx51 Add SoC and board support for mx51 platforms
+  * ARM:mx51 Add CONFIG_ARCH_MXC_CANONICAL to disable parts of Freescale's
+    code
+  * MMC: Add support for 8-bit cards
+  * Add ARM:MX51 SoC support to the build system
+  * ARM: Make ARM arch aware of ubuntu/ drivers
+  * ARM: Add imx51 configuration
+  * Disable d-i modules for imx51 and mv78xx0
+  * Disable Apparmor on boot for ARM
+  * Updating imx51 config
+
+  [ Jason Liu ]
+
+  * Do not use OOB with MLC NAND
+
+  [ Richard Zhu ]
+
+  * Support the eMMC4.3 card
+
+  [ Rob Herring ]
+
+  * ARM: Add more cache memory types macros
+
+  [ Tim Gardner ]
+
+  * Set CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y for i386/amd64/lpia
+
+  [ Manoj Iyer ]
+
+  * Enable CONFIG_RTL8187SE=m
+
+  [ Upstream Kernel Changes ]
+
+  * USB: EHCI: slow down ITD reuse
+    - LP: #329437
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sun, 08 Mar 2009 14:14:15 -0600
+
+linux (2.6.28-9.29) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * link-headers -- only link directories which do not already exist
+    - LP: #315252
+
+  [ Daniel Marjamäki ]
+
+  * SAUCE: (drop after 2.6.28) netxen: fix memory leak in
+    drivers/net/netxen_nic_init.c
+    - LP: #330813
+
+  [ Dhananjay Phadke ]
+
+  * SAUCE: (drop after 2.6.28) netxen: fix endianness in firmware commands
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: fix ipv6 offload and tx cleanup
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: fix link speed reporting for some
+    boards
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: firmware init fix
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: cleanup mac list on driver unload
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: hold tx lock while sending firmware
+    commands
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: handle dma mapping failures
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: avoid invalid iounmap
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: include ipv6.h (fixes build failure)
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: fix vlan tso/checksum offload
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: reduce memory footprint
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: revert jumbo ringsize
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: fix msi-x interrupt handling
+    - LP: #330813
+  * SAUCE: (drop after 2.6.28) netxen: remove pcie workaround
+    - LP: #330813
+
+  [ Hannes Eder ]
+
+  * SAUCE: (drop after 2.6.28) drivers/net/netxen: fix sparse warnings: use
+    NULL pointer instead of plain integer
+    - LP: #330813
+
+  [ Huaxu Wan ]
+
+  * SAUCE: report rfkill changes event if interface is down
+    - LP: #193970
+
+  [ Tim Gardner ]
+
+  * MV78XX0 must specify a target in the vars definition.
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "ext4: wait on all pending commits in ext4_sync_fs()"
+  * jbd2: Fix return value of jbd2_journal_start_commit()
+  * jbd2: Avoid possible NULL dereference in
+    jbd2_journal_begin_ordered_truncate()
+  * ext4: Fix to read empty directory blocks correctly in 64k
+  * ext4: Fix lockdep warning
+  * ext4: Initialize preallocation list_head's properly
+  * ext4: Implement range_cyclic in ext4_da_writepages instead of
+    write_cache_pages
+  * ext4: Fix NULL dereference in ext4_ext_migrate()'s error handling
+  * ext4: Add fallback for find_group_flex
+  * ext4: Fix deadlock in ext4_write_begin() and ext4_da_write_begin()
+  * Added mv78xx0 flavor
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 06 Mar 2009 06:13:31 -0700
+
+linux (2.6.28-8.28) jaunty; urgency=low
+
+  [ Alexey Starikovskiy ]
+
+  * SAUCE: ACPI: EC: Limit workaround for ASUS notebooks even more
+    - LP: #288385
+
+  [ Scott James Remnant ]
+
+  * SAUCE: Auto-load esp module when device opened.
+  * SAUCE: Auto-load bridge module when socket opened.
+  * SAUCE: Auto-load af_netlink module when socket opened.
+  * SAUCE: Auto-load wanrouter module when socket opened.
+  * SAUCE: Auto-load ip_queue module when socket opened.
+  * SAUCE: Auto-load ip6_queue module when socket opened.
+  * SAUCE: Auto-load cn module when socket opened.
+  * SAUCE: Auto-load scsi_transport_iscsi module when socket opened.
+  * SAUCE: Auto-load ftl module when device opened.
+  * SAUCE: Auto-load pcd module when device opened.
+  * SAUCE: Auto-load pf module when device opened.
+  * SAUCE: Auto-load nftl module when device opened.
+  * SAUCE: Auto-load mousedev module when psaux device opened.
+  * SAUCE: Auto-load mousedev module when /dev/input/mice opened.
+  * SAUCE: Auto-load rng-core module when device opened.
+  * SAUCE: Auto-load openprom module when device opened.
+  * SAUCE: Auto-load applicom module when device opened.
+  * SAUCE: Auto-load toshiba module when device opened.
+  * SAUCE: Auto-load cyclades module when device opened.
+  * SAUCE: Auto-load riscom8 module when device opened.
+  * SAUCE: Auto-load specialix module when device opened.
+  * SAUCE: Auto-load videodev module when device opened.
+  * SAUCE: Auto-load i2c_dev module when device opened.
+  * SAUCE: Auto-load mtdchar module when device opened.
+  * SAUCE: Auto-load pt module when device opened.
+  * SAUCE: Auto-load pg module when device opened.
+  * SAUCE: Auto-load cdc_acm module when device opened.
+  * SAUCE: Auto-load msr module when device opened.
+  * SAUCE: Auto-load cpuid module when device opened.
+  * SAUCE: quickcam: Enable double-buffering by default
+  * SAUCE: libata: Ignore HPA by default.
+  * SAUCE: hostap: Change initial operation mode to managed (infra)
+  * SAUCE: floppy: Provide a PnP device table in the module.
+    - LP: #255651
+  * SAUCE: Auto-load mwave module when device opened.
+  * Build CONFIG_FUSE_FS into kernel, not as module.
+
+  [ Stefan Bader ]
+
+  * Enable build of ext4 as a module on LPIA
+    - LP: #331848
+
+  [ Tim Gardner ]
+
+  * Update configs to fix LPIA FTBS
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 05 Mar 2009 10:43:24 -0700
+
+linux (2.6.28-8.27) jaunty; urgency=low
+
+  [ Amit Kucheria ]
+
+  * Updating configs (arm:ixp4xx)
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: enable Intel HDMI output
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Added quirk for Linksys WUSB600N USB wifi-n networking adapter
+    - LP: #323473
+
+  [ Steve Beattie ]
+
+  * fix apparmor memory leak on unlinked file ops
+    - LP: #329489
+
+  [ Tim Gardner ]
+
+  * SAUCE: Dell XPS710 reboot quirk
+    - LP: #323592
+  * SAUCE: (drop after 2.6.28) ieee80211: Add infrastructure to obsolete
+    scan results
+    - LP: #336055
+  * Add modules.order to the linux-image package.
+
+  [ Upstream Kernel Changes ]
+
+  * iwlwifi: fix time interval misuse in iwl_poll_{direct_}bit
+  * x86: only scan the root bus in early PCI quirks
+    - LP: #267295
+  * ALSA: hda - Intel HDMI audio support
+  * ALSA: hda - Fix unused function in patch_intelhdmi.c
+  * ALSA: handle SiI1392 HDMI codec in patch_intelhdmi.c
+  * ALSA: hda-intel: reorder HDMI audio enabling sequence
+  * ALSA: introduce snd_print_pcm_rates()
+  * ALSA: create hda_eld.c for ELD routines and proc interface
+  * ALSA: ELD proc interface for HDMI sinks
+  * ALSA: hda: make standalone hdmi_fill_audio_infoframe()
+  * ALSA: hda: make global snd_print_channel_allocation()
+  * ALSA: hda: HDMI channel allocations for audio infoframe
+  * ALSA: hda: HDMI channel mapping cleanups
+  * ALSA: hda: minor code cleanups
+  * ALSA: hda: rename sink_eld to hdmi_eld
+  * ALSA: hda - Release ELD proc file
+  * ALSA: hda - minor HDMI code cleanups
+  * ALSA: hda - report selected CA index for Audio InfoFrame
+  * ALSA: hda - Add Intel vendor id string
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 25 Feb 2009 14:23:46 -0700
+
+linux (2.6.28-8.26) jaunty; urgency=low
+
+  [ Amit Kucheria ]
+
+  * Updating configs (armel:ixp4xx)
+    - LP: #331510
+
+  [ Tim Gardner ]
+
+  * Add more missing modules
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 24 Feb 2009 06:58:53 -0700
+
+linux (2.6.28-8.25) jaunty; urgency=low
+
+  [ Scott James Remnant ]
+
+  * SAUCE: Prefer powernow-k8 to acpi-cpufreq
+  * Change CONFIG_X86_P4_CLOCKMOD to be a module again.
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Initialize the new
+    group descriptor when resizing the filesystem"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Add sanity check
+    to make_indexed_dir"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: only use
+    i_size_high for regular files"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Add sanity checks
+    for the superblock before mounting the filesystem"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Fix
+    s_dirty_blocks_counter if block allocation failed with nodelalloc"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Init the complete
+    page while building buddy cache"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Don't allow new
+    groups to be added during block allocation"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: mark the
+    blocks/inode bitmap beyond end of group as used"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Use new
+    buffer_head flag to check uninit group bitmaps initialization"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Fix the race
+    between read_inode_bitmap() and ext4_new_inode()"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Fix race between
+    read_block_bitmap() and mark_diskspace_used()"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: don't use blocks
+    freed but not yet committed in buddy cache init"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: cleanup mballoc
+    header files"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Use
+    EXT4_GROUP_INFO_NEED_INIT_BIT during resize"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Add blocks added
+    during resize to bitmap"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Don't overwrite
+    allocation_context ac_status"
+  * Revert "SAUCE: (revert before 2.6.28.y update) jbd2: Add barrier not
+    supported test to journal_wait_on_commit_record"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Widen type of
+    ext4_sb_info.s_mb_maxs[]"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: avoid ext4_error
+    when mounting a fs with a single bg"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Fix the delalloc
+    writepages to allocate blocks at the right offset."
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: tone down
+    ext4_da_writepages warnings"
+  * Revert "SAUCE: (revert before 2.6.28.y update) ext4: Add support for
+    non-native signed/unsigned htree hash algorithms"
+  * Enabled X86_ACPI_CPUFREQ=y
+
+  [ Upstream Kernel Changes ]
+
+  * ath9k: quiet harmless ForceXPAon messages
+    - LP: #321474
+  * [WATCHDOG] iTCO_wdt: fix SMI_EN regression 2
+    - LP: #314050
+  * pid: implement ns_of_pid
+  * mqueue: fix si_pid value in mqueue do_notify()
+  * powerpc/vsx: Fix VSX alignment handler for regs 32-63
+  * sata_nv: give up hardreset on nf2
+  * Fix Intel IOMMU write-buffer flushing
+  * SCSI: libiscsi: fix iscsi pool leak
+  * x86/cpa: make sure cpa is safe to call in lazy mmu mode
+  * sched: SCHED_OTHER vs SCHED_IDLE isolation
+  * x86, vm86: fix preemption bug
+  * Add support for VT6415 PCIE PATA IDE Host Controller
+  * ext2/xip: refuse to change xip flag during remount with busy inodes
+  * 3c505: do not set pcb->data.raw beyond its size
+  * Bluetooth: Fix TX error path in btsdio driver
+  * ext4: Add support for non-native signed/unsigned htree hash algorithms
+  * ext4: tone down ext4_da_writepages warnings
+  * ext4: Fix the delalloc writepages to allocate blocks at the right
+    offset.
+  * ext4: avoid ext4_error when mounting a fs with a single bg
+  * ext4: Widen type of ext4_sb_info.s_mb_maxs[]
+  * jbd2: Add barrier not supported test to journal_wait_on_commit_record
+  * ext4: Don't overwrite allocation_context ac_status
+  * ext4: Add blocks added during resize to bitmap
+  * ext4: Use EXT4_GROUP_INFO_NEED_INIT_BIT during resize
+  * ext4: cleanup mballoc header files
+  * ext4: don't use blocks freed but not yet committed in buddy cache init
+  * ext4: Fix race between read_block_bitmap() and mark_diskspace_used()
+  * ext4: Fix the race between read_inode_bitmap() and ext4_new_inode()
+  * ext4: Use new buffer_head flag to check uninit group bitmaps
+    initialization
+  * ext4: mark the blocks/inode bitmap beyond end of group as used
+  * ext4: Don't allow new groups to be added during block allocation
+  * ext4: Init the complete page while building buddy cache
+  * ext4: Fix s_dirty_blocks_counter if block allocation failed with
+    nodelalloc
+  * ext4: Add sanity checks for the superblock before mounting the
+    filesystem
+  * ext4: only use i_size_high for regular files
+  * ext4: Add sanity check to make_indexed_dir
+  * ext4: Initialize the new group descriptor when resizing the filesystem
+  * Fix longstanding "error: storage size of '__mod_dmi_device_table' isn't
+    known"
+  * Linux 2.6.28.7
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 19 Feb 2009 06:45:55 -0700
+
+linux (2.6.28-8.24) jaunty; urgency=low
+
+  [ Scott James Remnant ]
+
+  * Change CPU_FREQ_DEFAULT_GOV_ONDEMAND to y
+  * SAUCE: Link acpi-cpufreq.o first
+
+  [ Tim Gardner ]
+
+  * Build in CPU Frequency scaling drivers
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 18 Feb 2009 06:12:24 -0700
+
+linux (2.6.28-8.23) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * include the kernel configuration in the sub-flavour images
+    - LP: #328859
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: (drop after 2.6.28) [eCryptfs] Regression in unencrypted
+    filename symlinks" in favor of upstream commit.
+  * Fix compile issues with qc-usb
+  * SAUCE: (remove after 2.6.28) V4L/DVB (10216): saa7127: fix broken
+    S-Video with saa7129
+    - LP: #329267
+
+  [ Upstream Kernel Changes ]
+
+  * Subject:SAUCE: LP#193970 iwlagn: fix hw-rfkill while the interface is
+    down
+    - LP: #193970
+  * x86, vmi: put a missing paravirt_release_pmd in pgd_dtor
+  * nbd: fix I/O hang on disconnected nbds
+  * mac80211: restrict to AP in outgoing interface heuristic
+  * w1: w1 temp calculation overflow fix
+  * zd1211rw: adding 0ace:0xa211 as a ZD1211 device
+  * zd1211rw: treat MAXIM_NEW_RF(0x08) as UW2453_RF(0x09) for TP-Link
+    WN322/422G
+  * parport: parport_serial, don't bind netmos ibm 0299
+  * syscall define: fix uml compile bug
+  * kernel-doc: fix syscall wrapper processing
+  * Fix page writeback thinko, causing Berkeley DB slowdown
+  * write-back: fix nr_to_write counter
+  * writeback: fix break condition
+  * mm: rearrange exit_mmap() to unlock before arch_exit_mmap
+  * powerpc/fsl-booke: Fix mapping functions to use phys_addr_t
+  * lockd: fix regression in lockd's handling of blocked locks
+  * sctp: Fix crc32c calculations on big-endian arhes.
+  * sctp: Correctly start rtx timer on new packet transmissions.
+  * sctp: Properly timestamp outgoing data chunks for rtx purposes
+  * net: Fix frag_list handling in skb_seq_read
+  * net: Fix OOPS in skb_seq_read().
+  * drivers/net/skfp: if !capable(CAP_NET_ADMIN): inverted logic
+  * ipv4: fix infinite retry loop in IP-Config
+  * net: Fix userland breakage wrt. linux/if_tunnel.h
+  * net: packet socket packet_lookup_frame fix
+  * packet: Avoid lock_sock in mmap handler
+  * sungem: Soft lockup in sungem on Netra AC200 when switching interface
+    up
+  * udp: Fix UDP short packet false positive
+  * udp: increments sk_drops in __udp_queue_rcv_skb()
+  * ipv6: Disallow rediculious flowlabel option sizes.
+  * ipv6: Copy cork options in ip6_append_data
+  * net: 4 bytes kernel memory disclosure in SO_BSDCOMPAT gsopt try #2
+  * sky2: fix hard hang with netconsoling and iface going up
+  * tun: Add some missing TUN compat ioctl translations.
+  * tun: Fix unicast filter overflow
+  * virtio_net: Fix MAX_PACKET_LEN to support 802.1Q VLANs
+  * tcp: splice as many packets as possible at once
+  * tcp: Fix length tcp_splice_data_recv passes to skb_splice_bits.
+  * sparc: Enable syscall wrappers for 64-bit (CVE-2009-0029)
+  * sparc64: Annotate sparc64 specific syscalls with SYSCALL_DEFINEx()
+  * ALSA: hda - Add missing terminator in slave dig-out array
+  * ALSA: mtpav - Fix initial value for input hwport
+  * HID: adjust report descriptor fixup for MS 1028 receiver
+  * ide/libata: fix ata_id_is_cfa() (take 4)
+  * libata: fix EH device failure handling
+  * netfilter: fix tuple inversion for Node information request
+  * netfilter: xt_sctp: sctp chunk mapping doesn't work
+  * x86: microcode_amd: fix wrong handling of equivalent CPU id
+  * ide-cd: fix DMA for non bio-backed requests
+  * net: Fix data corruption when splicing from sockets.
+  * Linux 2.6.28.6
+  * eCryptfs: Regression in unencrypted filename symlinks
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 16 Feb 2009 06:43:51 -0700
+
+linux (2.6.28-8.22) jaunty; urgency=low
+
+  [ Amit Kucheria ]
+
+  * Remove perm-blacklist
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: psmouse/synaptics: ensure we reset the device on resume
+    - LP: #317270
+
+  [ Tim Gardner ]
+
+  * Add lpia to getabi script
+  * SAUCE: tracer for sreadahead
+
+ -- Amit Kucheria <amit.kucheria@ubuntu.com>  Fri, 13 Feb 2009 15:23:21 +0200
+
+linux (2.6.28-8.21) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: switch the Asus Pundit P1-AH2 to old acpi sleep ordering
+    - LP: #327267
+
+  [ Tim Gardner ]
+
+  * Added LPIA arch support
+  * Added libdrm-dev as a 'Replaces' to linux-libc-dev
+  * SAUCE: LPIA support for 9202 HDA Sigmatel codec
+  * SAUCE: Add an X86_LPIA Kconfig option
+  * SAUCE: UHCI USB quirk for resume
+  * SAUCE: LPIA Reboot fix for Intel Crownbeach development boards
+  * SAUCE: LPIA  Logical reset of USB port on resume
+  * Set CONFIG_WIRELESS_OLD_REGULATORY=n, added wireless-crda
+    as an install dependency.
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Revert "x86, early_ioremap: fix fencepost error""
+    - LP: #312554
+  * drm/i915: capture last_vblank count at IRQ uninstall time too
+    - LP: #320813
+  * drm/i915: add get_vblank_counter function for GM45
+    - LP: #320813
+  * Staging: comedi: fix Kbuild
+  * Staging: meilhaus: fix Kbuild
+  * Staging: android: binder: fix arm build errors
+  * Staging: android: timed_gpio: Fix build to build on kernels after
+    2.6.25.
+  * Staging: android: fix build error on 64bit boxes
+  * Staging: android: Add lowmemorykiller documentation.
+  * Staging: android: task_get_unused_fd_flags: fix the wrong usage of
+    tsk->signal
+  * staging: agnx: drivers/staging/agnx/agnx.h needs <linux/io.h>
+  * Staging: usbip: usbip_start_threads(): handle kernel_thread failure
+  * Staging: poch: fix verification of memory area
+  * Documentation: move DMA-mapping.txt to Doc/PCI/
+  * sgi-xp: fix writing past the end of kzalloc()'d space
+  * do_wp_page: fix regression with execute in place
+  * wait: prevent exclusive waiter starvation
+  * shm: fix shmctl(SHM_INFO) lockup with !CONFIG_SHMEM
+  * revert "rlimit: permit setting RLIMIT_NOFILE to RLIM_INFINITY"
+  * prevent kprobes from catching spurious page faults
+  * sound: usb-audio: handle wMaxPacketSize for FIXED_ENDPOINT devices
+  * md: Ensure an md array never has too many devices.
+  * md: Fix a bug in linear.c causing which_dev() to return the wrong
+    device.
+  * ACPI: Enable bit 11 in _PDC to advertise hw coord
+  * ACPI: dock: Don't eval _STA on every show_docked sysfs read
+  * ieee1394: ohci1394: increase AT req. retries, fix ack_busy_X from
+    Panasonic camcorders and others
+  * firewire: ohci: increase AT req. retries, fix ack_busy_X from Panasonic
+    camcorders and others
+  * firewire: sbp2: fix DMA mapping leak on the failure path
+  * firewire: sbp2: add workarounds for 2nd and 3rd generation iPods
+  * ieee1394: sbp2: add workarounds for 2nd and 3rd generation iPods
+  * module: remove over-zealous check in __module_get()
+  * x86: APIC: enable workaround on AMD Fam10h CPUs
+  * eeepc-laptop: fix oops when changing backlight brightness during
+    eeepc-laptop init
+  * eeepc-laptop: Add support for extended hotkeys
+  * e1000: fix bug with shared interrupt during reset
+  * e1000: Fix PCI enable to honor the need_ioport flag
+  * agp/intel: Fix broken ® symbol in device name.
+  * ALSA: hda - Add quirk for FSC Amilo Xi2550
+  * ALSA: hda - Add missing COEF initialization for ALC887
+  * ALSA: hda - Add missing initialization for ALC272
+  * asus_acpi: Add R1F support
+  * panasonic-laptop: fix X[ ARRAY_SIZE(X) ]
+  * ACPI: Skip the first two elements in the _BCL package
+  * ACPI: proc_dir_entry 'video/VGA' already registered
+  * ACPI: disable ACPI cleanly when bad RSDP found
+  * ACPICA: Fix table entry truncation calculation
+  * PCI: properly clean up ASPM link state on device remove
+  * PCI: return error on failure to read PCI ROMs
+  * seq_file: move traverse so it can be used from seq_read
+  * seq_file: fix big-enough lseek() + read()
+  * serial: set correct baud_base for Oxford Semiconductor Ltd EXSYS
+    EX-41092 Dual 16950 Serial adapter
+  * Add support for '8-port RS-232 MIC-3620 from advantech'
+  * mm: fix error case in mlock downgrade reversion
+  * elf core dump: fix get_user use
+  * ACPI: video: Fix reversed brightness behavior on ThinkPad SL series
+  * ipw2200: fix scanning while associated
+  * XFS: set b_error from bio error in xfs_buf_bio_end_io
+  * Revert USB: option: add Pantech cards
+  * USB: option: New mobile broadband modems to be supported
+  * USB: new id for ti_usb_3410_5052 driver
+  * USB: two more usb ids for ti_usb_3410_5052
+  * USB: usb-storage: add Pentax to the bad-vendor list
+  * sata_via: Add VT8261 support
+  * nbd: do not allow two clients at the same time
+  * sctp: Fix another socket race during accept/peeloff
+  * Linux 2.6.28.5
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 09 Feb 2009 16:11:28 -0700
+
+linux (2.6.28-7.20) jaunty; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: Input: atkbd - Samsung NC10 key repeat fix
+
+  [ Upstream Kernel Changes ]
+
+  * Manually revert "mlock: downgrade mmap sem while populating mlocked
+    regions"
+  * xen: make sysfs files behave as their names suggest
+  * sata_mv: fix 8-port timeouts on 508x/6081 chips
+  * m68knommu: set NO_DMA
+  * PCI/MSI: bugfix/utilize for msi_capability_init()
+  * x86: use early clobbers in usercopy*.c
+  * netfilter: ctnetlink: fix scheduling while atomic
+  * orinoco: move kmalloc(..., GFP_KERNEL) outside spinlock in
+    orinoco_ioctl_set_genie
+  * fbdev/atyfb: Fix DSP config on some PowerMacs & PowerBooks
+  * kmalloc: return NULL instead of link failure
+  * sata_nv: rename nv_nf2_hardreset()
+  * sata_nv: fix MCP5x reset
+  * sata_nv: ck804 has borked hardreset too
+  * Fix memory corruption in console selection
+  * Add enable_ms to jsm driver
+  * nfsd: only set file_lock.fl_lmops in nfsd4_lockt if a stateowner is
+    found
+  * nfsd: Ensure nfsv4 calls the underlying filesystem on LOCKT
+  * iwlwifi: fix rs_get_rate WARN_ON()
+  * p54: fix lm87 checksum endianness
+  * p54: fix p54_read_eeprom to cope with tx_hdr_len
+  * p54usb: rewriting rx/tx routines to make use of usb_anchor's facilities
+  * minstrel: fix warning if lowest supported rate index is not 0
+  * PCI: irq and pci_ids patch for Intel Tigerpoint DeviceIDs
+  * cpuidle: Add decaying history logic to menu idle predictor
+  * ACPI: Avoid array address overflow when _CST MWAIT hint bits are set
+  * video: always update the brightness when poking "brightness"
+  * Newly inserted battery might differ from one just removed, so update of
+    battery info fields is required.
+  * ACPI: Do not modify SCI_EN directly
+  * dlm: initialize file_lock struct in GETLK before copying conflicting
+    lock
+  * sata_mv: Fix chip type for Hightpoint RocketRaid 1740/1742
+  * ACPICA: Allow multiple backslash prefix in namepaths
+  * Linux 2.6.28.4
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sat, 07 Feb 2009 18:53:42 -0700
+
+linux (2.6.28-7.19) jaunty; urgency=low
+
+  * Fix missing modules FTBS
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 05 Feb 2009 15:28:15 -0700
+
+linux (2.6.28-7.18) jaunty; urgency=low
+
+  [ Alok Kataria ]
+
+  * SAUCE: (drop after 2.6.29) x86: add a synthetic TSC_RELIABLE feature
+    bit
+    - LP: #319945
+  * SAUCE: (drop after 2.6.29) x86: add X86_FEATURE_HYPERVISOR feature bit
+    - LP: #319945
+  * SAUCE: (drop after 2.6.29) x86: Hypervisor detection and get tsc_freq
+    from hypervisor
+    - LP: #319945
+  * SAUCE: (drop after 2.6.29) x86: Add a synthetic TSC_RELIABLE feature
+    bit.
+    - LP: #319945
+  * SAUCE: (drop after 2.6.29) x86: Skip verification by the watchdog for
+    TSC clocksource.
+    - LP: #319945
+  * SAUCE: (drop after 2.6.29) x86: VMware: Fix vmware_get_tsc code
+    - LP: #319945
+  * SAUCE: (drop after 2.6.29) x86: vmware: look for DMI string in the
+    product serial key
+    - LP: #319945
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: toshiba_acpi -- pull in current -dev version of driver
+    - LP: #269831
+  * SAUCE: toshiba_acpi -- add acpi hotkey kernel thread
+    - LP: #269831
+  * move toshiba laptops back from tlsup to toshiba_acpi
+    - LP: #269831
+
+  [ Aneesh Kumar K.V ]
+
+  * SAUCE: (revert before 2.6.28.y update) ext4: Fix the delalloc
+    writepages to allocate blocks at the right offset.
+  * SAUCE: (revert before 2.6.28.y update) ext4: avoid ext4_error when
+    mounting a fs with a single bg
+  * SAUCE: (revert before 2.6.28.y update) ext4: Don't overwrite
+    allocation_context ac_status
+  * SAUCE: (revert before 2.6.28.y update) ext4: Add blocks added during
+    resize to bitmap
+  * SAUCE: (revert before 2.6.28.y update) ext4: Use
+    EXT4_GROUP_INFO_NEED_INIT_BIT during resize
+  * SAUCE: (revert before 2.6.28.y update) ext4: cleanup mballoc header
+    files
+  * SAUCE: (revert before 2.6.28.y update) ext4: don't use blocks freed but
+    not yet committed in buddy cache init
+  * SAUCE: (revert before 2.6.28.y update) ext4: Fix race between
+    read_block_bitmap() and mark_diskspace_used()
+  * SAUCE: (revert before 2.6.28.y update) ext4: Fix the race between
+    read_inode_bitmap() and ext4_new_inode()
+  * SAUCE: (revert before 2.6.28.y update) ext4: Use new buffer_head flag
+    to check uninit group bitmaps initialization
+  * SAUCE: (revert before 2.6.28.y update) ext4: mark the blocks/inode
+    bitmap beyond end of group as used
+  * SAUCE: (revert before 2.6.28.y update) ext4: Don't allow new groups to
+    be added during block allocation
+  * SAUCE: (revert before 2.6.28.y update) ext4: Init the complete page
+    while building buddy cache
+  * SAUCE: (revert before 2.6.28.y update) ext4: Fix s_dirty_blocks_counter
+    if block allocation failed with nodelalloc
+
+  [ Hannes Eder ]
+
+  * SAUCE: (drop after 2.6.29) x86: vmware - fix sparse warnings
+    - LP: #319945
+
+  [ Luke Yelavich ]
+
+  * hid modules have hyphens instead of underscores in their names
+
+  [ Mark Fasheh ]
+
+  * SAUCE: (revert before 2.6.28.y update) jbd2: Add BH_JBDPrivateStart
+
+  [ Theodore Ts'o ]
+
+  * SAUCE: (revert before 2.6.28.y update) ext4: Add support for non-native
+    signed/unsigned htree hash algorithms
+  * SAUCE: (revert before 2.6.28.y update) ext4: tone down
+    ext4_da_writepages warnings
+  * SAUCE: (revert before 2.6.28.y update) jbd2: Add barrier not supported
+    test to journal_wait_on_commit_record
+  * SAUCE: (revert before 2.6.28.y update) ext4: Add sanity checks for the
+    superblock before mounting the filesystem
+  * SAUCE: (revert before 2.6.28.y update) ext4: only use i_size_high for
+    regular files
+  * SAUCE: (revert before 2.6.28.y update) ext4: Add sanity check to
+    make_indexed_dir
+  * SAUCE: (revert before 2.6.28.y update) jbd2: On a __journal_expect()
+    assertion failure printk "JBD2", not "EXT3-fs"
+  * SAUCE: (revert before 2.6.28.y update) ext4: Initialize the new group
+    descriptor when resizing the filesystem
+
+  [ Tyler Hicks ]
+
+  * SAUCE: (drop after 2.6.28) [eCryptfs] Regression in unencrypted
+    filename symlinks
+    - LP: #322532
+
+  [ Upstream Kernel Changes ]
+
+  * Input: atkbd - broaden the Dell DMI signatures
+    - LP: #261721
+  * ti_usb_3410_5052: support alternate firmware
+  * ath5k: fix mesh point operation
+  * mac80211: decrement ref count to netdev after launching mesh discovery
+  * inotify: clean up inotify_read and fix locking problems
+  * fuse: destroy bdi on umount
+  * fuse: fix missing fput on error
+  * fuse: fix NULL deref in fuse_file_alloc()
+  * x86, mm: fix pte_free()
+  * klist.c: bit 0 in pointer can't be used as flag
+  * sysfs: fix problems with binary files
+  * x86: fix page attribute corruption with cpa()
+  * USB: fix toggle mismatch in disable_endpoint paths
+  * sound: virtuoso: enable UART on Xonar HDAV1.3
+  * USB: usbmon: Implement compat_ioctl
+  * USB: fix char-device disconnect handling
+  * USB: storage: add unusual devs entry
+  * alpha: nautilus - fix compile failure with gcc-4.3
+  * alpha: fix vmalloc breakage
+  * resources: skip sanity check of busy resources
+  * rtl8187: Add termination packet to prevent stall
+  * it821x: Add ultra_mask quirk for Vortex86SX
+  * libata: pata_via: support VX855, future chips whose IDE controller use
+    0x0571
+  * serial_8250: support for Sealevel Systems Model 7803 COMM+8
+  * drm: stash AGP include under the do-we-have-AGP ifdef
+  * Fix OOPS in mmap_region() when merging adjacent VM_LOCKED file segments
+  * bnx2x: Block nvram access when the device is inactive
+  * ext3: Add sanity check to make_indexed_dir
+  * rtl8187: Fix error in setting OFDM power settings for RTL8187L
+  * epoll: drop max_user_instances and rely only on max_user_watches
+  * gpiolib: fix request related issue
+  * sgi-xpc: Remove NULL pointer dereference.
+  * sgi-xpc: ensure flags are updated before bte_copy
+  * include/linux: Add bsg.h to the Kernel exported headers
+  * ALSA: hda - Fix PCM reference NID for STAC/IDT analog outputs
+  * ALSA: hda - add another MacBook Pro 4, 1 subsystem ID
+  * ALSA: hda - Add quirk for HP DV6700 laptop
+  * crypto: authenc - Fix zero-length IV crash
+  * crypto: ccm - Fix handling of null assoc data
+  * x86, pat: fix reserve_memtype() for legacy 1MB range
+  * x86, pat: fix PTE corruption issue while mapping RAM using /dev/mem
+  * PCI hotplug: fix lock imbalance in pciehp
+  * dmaengine: fix dependency chaining
+  * NET: net_namespace, fix lock imbalance
+  * relay: fix lock imbalance in relay_late_setup_files
+  * Linux 2.6.28.3
+  * ALSA: Enable SPDIF output on ALC655
+  * ALSA: hda - Add ASUS V1Sn support
+  * ALSA: hda - support detecting HD Audio devices with PCI class code
+  * ALSA: hda: alc883 model for ASUS P5Q-EM boards
+  * ALSA: hda - Add quirk for MSI 7260 mobo
+  * ALSA: hda - Add quirk for Sony VAIO VGN-SR19XN
+  * ALSA: oxygen: add Claro halo support
+  * ALSA: hda - Add a new function to seek for a codec ID
+  * ALSA: patch_sigmatel: Add missing Gateway entries and autodetection
+  * ALSA: hda - More fixes on Gateway entries
+  * ALSA: hda - Add MCP67 HDMI support
+  * ALSA: hda - fix name for ALC1200
+  * LSA: hda - Add HP Acacia detection
+  * ALSA: hda - Add quirk for HP 2230s
+  * ALSA: hda - Add quirk for Dell Inspiron Mini9
+  * ALSA: hda - add support for Intel DX58SO board
+  * ALSA: hda - Fix silent headphone output on Panasonic CF-74
+  * ALSA: USB quirk for Logitech Quickcam Pro 9000 name
+  * ALSA: hda - add quirks for some 82801H variants to use ALC883_MITAC
+
+  [ Yasunori Goto ]
+
+  * SAUCE: (revert before 2.6.28.y update) ext4: Widen type of
+    ext4_sb_info.s_mb_maxs[]
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 02 Feb 2009 23:07:13 -0700
+
+linux (2.6.28-6.17) jaunty; urgency=low
+
+  [ Amit Kucheria ]
+
+  * Updating configs: ARMEL/versatile
+
+ -- Amit Kucheria <amit.kucheria@ubuntu.com>  Fri, 30 Jan 2009 13:36:59 +0200
+
+linux (2.6.28-6.16) jaunty; urgency=low
+
+  [ Luke Yelavich ]
+
+  * Add hid quirks to input-modules udeb
+
+  [ Tim Gardner ]
+
+  * Revert "[arm] Fix kexec on ARM by properly calling the relocation
+    function". This patch was deemed 'bogus' by Russell King on the
+    ARM mailing list.
+
+  [ Upstream Kernel Changes ]
+
+  * PCI: keep ASPM link state consistent throughout PCIe hierarchy
+  * security: introduce missing kfree
+  * rt2x00: add USB ID for the Linksys WUSB200.
+  * p54usb: Add USB ID for Thomson Speedtouch 121g
+  * lib/idr.c: use kmem_cache_zalloc() for the idr_layer cache
+  * sgi-xp: eliminate false detection of no heartbeat
+  * sched: fix update_min_vruntime
+  * IA64: Turn on CONFIG_HAVE_UNSTABLE_CLOCK
+  * sound: virtuoso: do not overwrite EEPROM on Xonar D2/D2X
+  * ALSA: hda - Add quirk for another HP dv5
+  * ALSA: hda - Fix HP dv5 mic input
+  * ALSA: hda - Don't reset HP pinctl in patch_sigmatel.c
+  * ALSA: hda - make laptop-eapd model back for AD1986A
+  * drivers/net/irda/irda-usb.c: fix buffer overflow
+  * usb-storage: add last-sector hacks
+  * usb-storage: set CAPACITY_HEURISTICS flag for bad vendors
+  * pkt_sched: sch_htb: Fix deadlock in hrtimers triggered by HTB
+  * ipv6: Fix fib6_dump_table walker leak
+  * sctp: Avoid memory overflow while FWD-TSN chunk is received with bad
+    stream ID
+  * pkt_sched: cls_u32: Fix locking in u32_change()
+  * r6040: fix wrong logic in mdio code
+  * r6040: save and restore MIER correctly in the interrupt routine
+  * r6040: bump release number to 0.19
+  * tcp: don't mask EOF and socket errors on nonblocking splice receive
+  * p54usb: fix traffic stalls / packet drop
+  * netfilter: x_tables: fix match/target revision lookup
+  * netfilter: ebtables: fix inversion in match code
+  * netfilter: nf_conntrack: fix ICMP/ICMPv6 timeout sysctls on big-endian
+  * dell_rbu: use scnprintf() instead of less secure sprintf()
+  * powerpc: is_hugepage_only_range() must account for both 4kB and 64kB
+    slices
+  * hwmon: (abituguru3) Fix CONFIG_DMI=n fallback to probe
+  * mm: write_cache_pages cyclic fix
+  * mm: write_cache_pages early loop termination
+  * mm: write_cache_pages writepage error fix
+  * mm: write_cache_pages integrity fix
+  * mm: write_cache_pages cleanups
+  * mm: write_cache_pages optimise page cleaning
+  * mm: write_cache_pages terminate quickly
+  * mm: write_cache_pages more terminate quickly
+  * mm: do_sync_mapping_range integrity fix
+  * mm: direct IO starvation improvement
+  * fs: remove WB_SYNC_HOLD
+  * fs: sync_sb_inodes fix
+  * fs: sys_sync fix
+  * Linux 2.6.28.2
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sun, 25 Jan 2009 13:36:16 -0700
+
+linux (2.6.28-5.15) jaunty; urgency=low
+
+  [ Tim Gardner ]
+
+  * Revert "Enabled CONFIG_PID_NS=y for i386/amd64"
+    Somehow this commit also reverted the 7 prior commits (which is bad).
+  * Enabled CONFIG_PID_NS=y for i386/amd64 (version 2)
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 22 Jan 2009 13:48:34 -0700
+
+linux (2.6.28-5.14) jaunty; urgency=low
+
+  [ Ben Collins ]
+
+  * lirc_gpio: Forward ported to current kernel (jaunty)
+  * configs: Enable LIRC_GPIO on 64-bit/32-bit x86
+    - LP: #298791
+
+  [ Jeff Layton ]
+
+  * SAUCE: cifs: make sure we allocate enough storage for socket address
+    - LP: #318565
+
+  [ Tim Gardner ]
+
+  * check-abi: Return success when ABI skip is requested and no ABI files exist.
+    This ought to fix the armel FTBS.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 22 Jan 2009 06:42:49 -0700
+
+linux (2.6.28-5.13) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: don't use buggy _BCL/_BCM/_BQC for backlight control"
+
+  [ Tim Gardner ]
+
+  * Fix udeb generation breakage caused by the previous armel versatile
+    flavour config update.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 21 Jan 2009 12:38:35 -0700
+
+linux (2.6.28-5.12) jaunty; urgency=low
+
+  [ Ante ]
+
+  * Update drbd to 8.3.0
+
+  [ Dave Airlie ]
+
+  * i915/drm: provide compat defines for userspace for certain struct
+
+  [ Eric Anholt ]
+
+  * drm/i915: Don't double-unpin buffers if we take a signal in
+  * drm/i915: Don't complain when interrupted while pinning in execbuffers.
+  * drm/i915: Don't allow objects to get bound while VT switched.
+
+  [ Jani Monoses ]
+
+  * Fix webcam having USB ID 0ac8:303b
+    - LP: #292086
+
+  [ Jesse Barnes ]
+
+  * drm/i915: set vblank enabled flag correctly across IRQ
+  * drm/i915: don't enable vblanks on disabled pipes
+
+  [ Michael Casadevall ]
+
+  * [arm] Fix kexec on ARM by properly calling the relocation function
+
+  [ Tim Gardner ]
+
+  * Enabled CONFIG_PID_NS=y for i386/amd64
+  * SAUCE: Increase ATA_TMOUT_PMP_SRST_WAIT to 5 seconds.
+    - LP: #318978
+  * Update armel versatile config
+    - LP: #314789
+  * Enabled CONFIG_RT2860=m for i386/amd64
+  * Enabled CONFIG_RT2870=m for i386/amd64
+
+  [ Upstream Kernel Changes ]
+
+  * Input: atkbd - add keyboard quirk for HP Pavilion ZV6100 laptop
+    - LP: #291878
+  * ALSA: hda - Add quirk for another HP dv7
+  * ALSA: hda - Add quirk for HP6730B laptop
+  * ALSA: caiaq - Fix Oops with MIDI
+  * ALSA: hda - Fix typos for AD1882 codecs
+  * x86: fix intel x86_64 llc_shared_map/cpu_llc_id anomolies
+  * x86: default to SWIOTLB=y on x86_64
+  * CIFS: make sure that DFS pathnames are properly formed
+  * ring-buffer: prevent false positive warning
+  * ring-buffer: fix dangling commit race
+  * iwlwifi: use GFP_KERNEL to allocate Rx SKB memory
+  * tx493[89]ide: Fix length for __ide_flush_dcache_range
+  * tx4939ide: Do not use zero count PRD entry
+  * SCSI: eata: fix the data buffer accessors conversion regression
+  * USB: emi26: fix oops on load
+  * x86, UV: remove erroneous BAU initialization
+  * x86: fix incorrect __read_mostly on _boot_cpu_pda
+  * vmalloc.c: fix flushing in vmap_page_range()
+  * fs: symlink write_begin allocation context fix
+  * cgroups: fix a race between cgroup_clone and umount
+  * dm raid1: fix error count
+  * dm log: fix dm_io_client leak on error paths
+  * minix: fix add link's wrong position calculation
+  * md: fix bitmap-on-external-file bug.
+  * sched_clock: prevent scd->clock from moving backwards, take #2
+  * devices cgroup: allow mkfifo
+  * SCSI: aha152x_cs: Fix regression that keeps driver from using shared
+    interrupts
+  * ioat: fix self test for multi-channel case
+  * USB: isp1760: use a specific PLX bridge instead of any bdridge
+  * USB: isp1760: Fix probe in PCI glue code
+  * USB: unusual_devs.h additions for Pentax K10D
+  * inotify: fix type errors in interfaces
+  * Move compat system call declarations to compat header file
+  * Convert all system calls to return a long
+  * Rename old_readdir to sys_old_readdir
+  * Remove __attribute__((weak)) from sys_pipe/sys_pipe2
+  * Make sys_pselect7 static
+  * Make sys_syslog a conditional system call
+  * System call wrapper infrastructure
+  * powerpc: Enable syscall wrappers for 64-bit
+  * s390: enable system call wrappers
+  * System call wrapper special cases
+  * System call wrappers part 01
+  * System call wrappers part 02
+  * System call wrappers part 03
+  * System call wrappers part 04
+  * System call wrappers part 05
+  * System call wrappers part 06
+  * System call wrappers part 07
+  * System call wrappers part 08
+  * System call wrappers part 09
+  * System call wrappers part 10
+  * System call wrappers part 11
+  * System call wrappers part 12
+  * System call wrappers part 13
+  * System call wrappers part 14
+  * System call wrappers part 15
+  * System call wrappers part 16
+  * System call wrappers part 17
+  * System call wrappers part 18
+  * System call wrappers part 19
+  * System call wrappers part 20
+  * System call wrappers part 21
+  * System call wrappers part 22
+  * System call wrappers part 23
+  * System call wrappers part 24
+  * System call wrappers part 25
+  * System call wrappers part 26
+  * System call wrappers part 27
+  * System call wrappers part 28
+  * System call wrappers part 29
+  * System call wrappers part 30
+  * System call wrappers part 31
+  * System call wrappers part 32
+  * System call wrappers part 33
+  * s390 specific system call wrappers
+  * x86: fix RIP printout in early_idt_handler
+  * Fix timeouts in sys_pselect7
+  * USB: another unusual_devs entry for another bad Argosy storage device
+  * USB: storage: extend unusual range for 067b:3507
+  * USB: storage: recognizing and enabling Nokia 5200 cell phoes
+  * HID: fix error condition propagation in hid-sony driver
+  * fix switch_names() breakage in short-to-short case
+  * nfs: remove redundant tests on reading new pages
+  * eCryptfs: check readlink result was not an error before using it
+  * mvsas: increase port type detection delay to suit Seagate's 10k6 drive ST3450856SS 0003
+  * x86: avoid theoretical vmalloc fault loop
+  * ath9k: enable RXing of beacons on STA/IBSS
+  * mm lockless pagecache barrier fix
+  * powerpc: Disable Collaborative Memory Manager for kdump
+  * ibmvfc: Delay NPIV login retry and add retries
+  * ibmvfc: Improve async event handling
+  * getrusage: RUSAGE_THREAD should return ru_utime and ru_stime
+  * ath5k: ignore the return value of ath5k_hw_noise_floor_calibration
+  * mm: fix assertion
+  * XFS: truncate readdir offsets to signed 32 bit values
+  * Linux 2.6.28.1
+  * eCryptfs: Filename Encryption: Tag 70 packets
+  * eCryptfs: Filename Encryption: Header updates
+  * eCryptfs: Filename Encryption: Encoding and encryption functions
+  * eCryptfs: Filename Encryption: filldir, lookup, and readlink
+  * eCryptfs: Filename Encryption: mount option
+  * eCryptfs: Replace %Z with %z
+  * eCryptfs: Fix data types (int/size_t)
+  * eCryptfs: kerneldoc for ecryptfs_parse_tag_70_packet()
+  * eCryptfs: Clean up ecryptfs_decode_from_filename()
+  * fs/ecryptfs/inode.c: cleanup kerneldoc
+  * staging-p80211: Kill directly reference of netdev->priv
+  * staging-slicoss: Kill directly reference of netdev->priv
+  * staging-winbond: Kill directly reference of netdev->priv
+  * Staging: go7007: fixes due to video_usercopy api change
+  * Staging: go7007: fixes due v4l2_file_operations api change
+  * staging: correct dubious use of !x & y
+  * Staging: w35und: make wb35_probe() and wb35_disconnect() funtions static
+  * Staging: w35und: remove unused wb35_open() and wb35_close() functions
+  * Staging: w35und: use msleep() and udelay()
+  * Staging: w35und: remove the no-op pa_stall_execution macro
+  * Staging: w35und: purb typedef removal
+  * Staging: w35und: reg queue struct typedef removal
+  * Staging: w35und: wb35reg struct typedef removal
+  * Staging: w35und: padapter struct typedef removal
+  * Staging: w35und: merge wblinux struct to adapter
+  * Staging: w35und: wb35_probe() cleanup
+  * Staging: w35und: remove usb_submit_urb wrapper function
+  * Staging: w35und: remove usb_alloc_urb wrapper function
+  * w35und: remove dead code from wbusb_f.h
+  * Staging: w35und: remove true/false boolean macros
+  * Staging: w35und: OS_MEMORY_ALLOC wrapper removal
+  * Staging: w35und: usb_put_dev() is missing from wb35_disconnect()
+  * Staging: w35und: remove macro magic from MLME_GetNextPacket()
+  * Staging: w35und: plug memory leak in wbsoft_tx()
+  * Staging: w35und: move supported band initialization out of wb35_probe()
+  * Staging: w35und: remove timer wrappers
+  * Staging: w35und: remove atomic op wrappers
+  * Staging: w35und: remove memcpy/memcmp wrappers
+  * Staging: w35und: remove abs() and BIT() macros
+  * Staging: w35und: remove unused macros from common.h
+  * Staging: w35und: remove unused link status code
+  * Staging: w35und: #include cleanup
+  * Staging: w35und: remove some dead code
+  * Staging: w35und: move source files to one directory
+  * Staging: w35und: move struct wbsoft_priv to core.h and use it
+  * Staging: w35und: remove ->adapter from struct _HW_DATA_T
+  * Staging: w35und: clean up adapter.h a bit
+  * Staging: w35und: merge struct wb35_adapter to struct wbsoft_priv
+  * Staging: w35und: remove global struct ieee80211_hw
+  * Staging: w35und: inline DRIVER_AUTHOR and DRIVER_DESC macros
+  * Staging: w35und: clean up wblinux.c a bit
+  * Staging: w35und: remove unused ->ShutDowned member from struct
+    LOCAL_PARA
+  * Staging: w35und: move global wbsoft_enabled to struct wbsoft_priv
+  * Staging: w35und: move packet_came() to wb35rx.c
+  * Staging: w35und: remove ->skb_array from struct wbsoft_priv
+  * Staging: w35und: remove ->shutdown from struct wbsoft_priv
+  * Staging: w35und: make functions local to mds.c static
+  * Staging: w35und: make functions local to mlmetxrx.c static
+  * Staging: w35und: remove dead code from mto.c
+  * Staging: w35und: make functions local to wb35rx.c static
+  * Staging: w35und: make functions local to wb35tx.c static
+  * Staging: w35und: remove dead code from wbhal.c
+  * Staging: w35und: remove rxisr.c as dead code
+  * Staging: w35und: fix Kconfig
+  * Staging: w35und: fix config build warnings
+  * Staging: wlan-ng: Remove PCI/PLX/PCMCIA files.
+  * Staging: wlan-ng: Update Help text to mention prism3 devices.
+  * Staging: wlan-ng: Delete PCI/PLX/PCMCIA-specific code.
+  * Staging: wlan-ng: Make wlan-ng use WEXT mode by default.
+  * Staging: wlan-ng: Eliminate more <2.6 kernel support.
+  * Staging: wlan-ng: Eliminate all backwards-compatibility for <2.6.13 kernels.
+  * Staging: wlan-ng: Eliminate a boatload of tertiaryAP-only code.
+  * Staging: wlan-ng: Remove AP-only code from MLME functions.
+  * Staging: wlan-ng: Get rid of the MTU tests in the rx conversion path.
+  * Staging: wlan-ng: Eliminate one more rx mtu test.
+  * Staging: wlan-ng: Eliminate local 'version.h'
+  * Staging: wlan-ng: Eliminate usage of procfs.
+  * Staging: wlan-ng: Use standard kernel integer (u32/s32/etc) types.
+  * Staging: wlan-ng: Eliminate all backwards-compatible kernel code.
+  * Staging: wlan-ng: Wireless Extension support is mandatory.
+  * Staging: wlan-ng: use WIRELESS_EXT, not CONFIG_WIRELESS_EXT
+  * Staging: wlan-ng: Delete a large pile of now-unused code.
+  * Staging: wlan-ng: Delete a pile of unused mibs. And fix WEXT SET_TXPOWER.
+  * Staging: wlan-ng: Consolidate wlan-ng into a single module.
+  * Staging: wlan-ng: Purge all MIBs not used internally.
+  * Staging: wlan-ng: p80211netdev.c fix netdev alloc to prevent oops on device start
+  * Staging: wlan-ng: prism2_usb.c always enable the card in probe_usb
+  * Staging: wlan-ng: hfa384x_usb.c use newest version of 384x_drvr_start
+  * Staging: wlan-ng: p80211wext.c add latest changes & remove extra nulls from wext_handlers
+  * Staging: wlan-ng: p80211wext don't set default key id twice
+  * Staging: wlan-ng: hfa384x_usbin_callback: check for hardware removed
+  * Staging: wlan-ng: p80211conv.c copy code from wlan-ng-devel branch to not drop packets
+  * Staging: wlan-ng: remove unused #include <version.h>
+  * Staging: wlan-ng: p80211wext.c: use ARRAY_SIZE
+  * Staging: wlan-ng: fix compiler warnings
+  * Staging: wlan-ng: skb_p80211_to_ether() - payload_length is unsigned, check before subtraction
+  * Staging: at76_usb: update drivers/staging/at76_usb w/ mac80211 port
+  * Staging: at76_usb: fix build breakage
+  * Staging: at76_usb: remove compiler warnings
+  * Staging: at76_usb: fix up all remaining checkpatch.pl warnings
+  * Staging: at76_usb: cleanup dma on stack issues
+  * Staging: poch: Block size bug fix
+  * Staging: poch: Update TODO list
+  * Staging: poch: Correct pages from bytes.
+  * Staging: poch: minor fixes
+  * Staging: poch: Fix build warnings
+  * Staging: poch: Rx control register init
+  * Staging: poch: Fix user space protocol syncing
+  * Staging: poch: Fine grained locking
+  * Staging: sxg: remove typedefs
+  * Staging: sxg: break the build in a cleaner way when !x86
+  * Staging: sxg: update README
+  * staging: struct device - replace bus_id with dev_name(), dev_set_name()
+  * Staging: echo: remove typedefs
+  * Staging: echo: Lindent drivers/staging/echo
+  * Staging: go7007: saa7134 updates
+  * Staging: go7007: add sensoray 2250/2251 support
+  * Staging: go7007: Convert driver to use video_ioctl2
+  * Staging: go7007: annotate code pointers
+  * Staging: go7007: fix minor build warnings
+  * Staging: go7007: small cleanup
+  * Staging: go7007: add some more v4l2 ioctls
+  * Staging: et131x: Cleanup et131x_debug.h defines
+  * Staging: et131x: fix build failure
+  * Staging: et131x: remove unused variable in et1310_tx.c
+  * Staging: usbip: cleanup kerneldoc
+  * Staging: slicoss: use kzalloc
+  * Staging: slicoss: use correct type for memory allcations
+  * Staging: slicoss: use request_firmware
+  * Staging: add agnx wireless driver
+  * Staging: agnx: fix build errors due to ssid removal
+  * Staging: agnx: fix build errors due to rate control API changes
+  * Staging: agnx: fix build warnings
+  * Staging: add otus Atheros wireless network driver
+  * Staging: otus: fix netdev->priv usage
+  * Staging: otus: fix name clash
+  * Staging: otus: fix urb callback function type
+  * Staging: otus: remove dependence on kernel version
+  * Staging: add rt2860 wireless driver
+  * Staging: rt2860: disable root hack for reading files
+  * Staging: rt2860: fix up netdev->priv usage
+  * Staging: rt2860: use standard bit-reverse function
+  * Staging: rt2860: Fix minor compiler warnings
+  * Staging: rt2860: enable WPA_SUPPLICANT support
+  * Staging: Add ServerEngines benet 10Gb ethernet driver
+  * Staging: benet: fix netif api breakage
+  * Staging: benet: fix up netdev->priv change
+  * Staging: benet: build is broken unless CONFIG_NETPOLL is enabled
+  * Staging: benet: patch to remove subdirectories
+  * Staging: benet: fix build errors when CONFIG_NETPOLL is off
+  * Staging: benet: fix build error.
+  * Staging: benet: patch to use offsetof() instead of AMAP_BYTE_OFFSET()
+  * Staging: benet: fix problems reported by checkpatch
+  * Staging: benet: cleanup a check while posting rx buffers
+  * Staging: add comedi core
+  * Staging: comedi: fix up a lot of checkpatch.pl warnings
+  * Staging: comedi: fix checkpatch.pl errors in comedi_fops.c
+  * Staging: comedi: fix build error in comedilib.h
+  * Staging: comedi: add kcomedilib to the tree
+  * Staging: comedi: set up infrastructure for individual drivers
+  * Staging: comedi: add local copy of interrupt.h
+  * Staging: comedi: add pci and usb wrapper header files
+  * Staging: comedi: comedi driver common function module
+  * Staging: comedi: add mite comedi pci driver
+  * Staging: comedi: add usb usbdux driver
+  * Staging: comedi: add usb usbduxfast driver
+  * Staging: comedi: add usb dt9812 driver
+  * Staging: comedi: add comedi_bond driver
+  * Staging: comedi: add comedi_test driver
+  * Staging: comedi: add comedi_parport driver
+  * Staging: comedi: dt9812: fix up a lot of coding style issues
+  * Staging: comedi: dt9812: remove dt9812.h
+  * Staging: comedi: dt9812: remove typedefs
+  * Staging: comedi: dt9812: fix sparse warnings
+  * Staging: comedi: usbdux: remove kernel version checks
+  * Staging: comedi: usbdux: code style cleanups
+  * Staging: comedi: usbdux: remove // comments
+  * Staging: comedi: usbdux: fix up printk calls
+  * Staging: comedi: usbdux: remove checkpatch.pl warnings
+  * Staging: comedi: usbdux: remove typedef
+  * Staging: comedi: usbdux: remove comedi usb wrappers
+  * Staging: comedi: usbduxfast: remove comedi usb wrappers
+  * Staging: comedi: dt9812: remove #ifdef that is not needed
+  * Staging: comedi: remove usb wrappers
+  * Staging: comedi: remove PCI wrappers
+  * Staging: comedi: add icp_multi driver
+  * Staging: comedi: add me4000 driver
+  * Staging: comedi: fix checkpatch.pl issues in comedi_bond.c
+  * Staging: comedi: fix checkpatch.pl issues in comedi_fc.c
+  * Staging: comedi: remove typedefs from comedi_bond.c
+  * Staging: comedi: fix sparse issues in comedi_bond.c
+  * Staging: comedi: fix checkpatch.pl issues in comedi_test.c
+  * Staging: comedi: fix sparse issues in comedi_test.c
+  * Staging: comedi: remove typedefs from comedi_test.c
+  * Staging: comedi: fix comedi_parport.c checkpatch.pl issues.
+  * Staging: comedi: fix comedi_fc.h checkpatch.pl issues.
+  * Staging: comedi: fix comedi_pci.h checkpatch.pl issues.
+  * Staging: comedi: comedi_pci.h: remove unneeded wrapper
+  * Staging: comedi: comedi_pci.h: remove comedi_pci_enable_no_regions
+  * Staging: comedi: comedi_pci.h: remove comedi_pci_disable_no_regions
+  * Staging: comedi: add s626 driver
+  * Staging: comedi: add rtd520 driver
+  * Staging: comedi: add me_daq driver
+  * Staging: comedi: me_daq: fix checkpatch.pl issues
+  * Staging: comedi: me_daq: remove typedefs
+  * Staging: comedi: me_daq: fix sparse issues
+  * Staging: comedi: fix checkpatch.pl warning in interrupt.h
+  * Staging: comedi: fix build if CONFIG_PROC_FS is not set
+  * Staging: add asus_oled driver
+  * Staging: asus_oled: fix build dependancy
+  * Staging: Add the Meilhaus ME-IDS driver package
+  * Staging: meilhaus: fix __symbol_get problems
+  * Staging: add lcd-panel driver
+  * Staging: panel: major checkpatch cleanup
+  * Staging: panel: remove ifdefs and code for pre-2.6 kernels
+  * Staging: panel: remove support for smartcards
+  * Staging: add Driver for Altera PCI Express Chaining DMA reference design
+  * Staging: add rtl8187se driver
+  * Staging: rtl8187se: remove unneeded files
+  * Staging: rtl8187se: make the built module be the proper name
+  * Staging: rtl8187se: remove duplicate pci ids
+  * Staging: me4000: switch to list_for_each*()
+  * Staging: usbip: switch to list_for_each_entry()
+  * Staging: add princeton instruments usb camera driver
+  * Staging: add mimio xi driver
+  * Staging: add rt2870 wireless driver
+  * Staging: rt2870: disable root hack for reading files
+  * Staging: rt2870: fix up netdev->priv usage
+  * Staging: add frontier tranzport and alphatrack drivers
+  * Staging: frontier: remove unused alphatrack_sysfs.c file
+  * Staging: frontier: fix compiler warnings
+  * Staging: add epl stack
+  * Staging: epl: run Lindent on all kernel/*.h files
+  * Staging: epl: run Lindent on all user/*.h files
+  * Staging: epl: run Lindent on *.h files
+  * Staging: epl: run Lindent on *.c files
+  * Staging: epl: hr timers all run in hard irq context now
+  * Staging: epl: fix netdev->priv b0rkage
+  * Staging: add android framework
+  * Staging: android: add binder driver
+  * Staging: android: binder: Fix gcc warnings about improper format specifiers for size_t in printk
+  * staging: android: binder: Fix use of euid
+  * Staging: android: add logging driver
+  * Staging: android: add ram_console driver
+  * Staging: android: add timed_gpio driver
+  * Staging: android: timed_gpio: Rename android_timed_gpio to timed_gpio
+  * Staging: android: remove dummy android.c driver
+  * Staging: android: add lowmemorykiller driver
+  * Staging: android: binder: fix build errors
+  * staging: __FUNCTION__ is gcc-specific, use __func__
+  * V4L/DVB (10176a): Switch remaining clear_user_page users over to
+    clear_user_highpage
+
+  [ Zhenyu Wang ]
+
+  * agp/intel: add support for G41 chipset
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sun, 18 Jan 2009 20:22:54 -0700
+
+linux (2.6.28-4.11) jaunty; urgency=low
+
+  [ Mario Limonciello ]
+
+  * SAUCE: Enable HDMI audio codec on Studio XPS 1340
+    - LP: #309508
+
+  [ Tim Gardner ]
+
+  * Fix armel d-i FTBSs
+
+  [ Upstream Kernel Changes ]
+
+  * USB: re-enable interface after driver unbinds
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 13 Jan 2009 16:33:08 -0700
+
+linux (2.6.28-4.10) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * update kernel bootloader recommends: to prefer grub
+    - LP: #314004
+  * SAUCE: don't use buggy _BCL/_BCM/_BQC for backlight control
+    - LP: #311716
+  * SAUCE: test-suspend -- add the suspend test scripts
+    - LP: #316419
+
+  [ Colin Watson ]
+
+  * Enable udebs for armel
+
+  [ Tim Gardner ]
+
+  * SAUCE: Dell laptop digital mic does not work, PCI 1028:0271
+    - LP: #309508
+  * Enable CIFS_XATTR=y and CONFIG_CIFS_POSIX=y
+    - LP: #220658
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 08 Jan 2009 10:38:22 -0700
+
+linux (2.6.28-4.9) jaunty; urgency=low
+
+  [ Tim Gardner ]
+
+  * Restore DM_CRYPT, AES, ECB, and CBC as modules. This fixes
+    some installer issues with encrypted /home and Private directories.
+  * Take one more stab at building armel without module or ABI errors.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 06 Jan 2009 08:38:23 -0700
+
+linux (2.6.28-4.8) jaunty; urgency=low
+
+  * Fix i386/amd64 FTBS by ignoring all module and ABI changes,
+    not something you would normally do, but I'm sure the ABI
+    has not changed. This will probably also allow the ARM builds to complete.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 05 Jan 2009 14:42:58 -0700
+
+linux (2.6.28-4.7) jaunty; urgency=low
+
+  [ Tim Gardner ]
+
+  * Enable CONFIG_ATH5K=m for i386/amd64
+    - LP: #306719
+  * Build all i386/amd64 AGP/DRM components as modules.
+    - LP: #312721
+  * git commands are now installed outside the default $PATH
+    Use 'git  CMD' instead of 'git-CMD'.
+  * Build in most PATA/SATA drivers. This should allow most i386/amd64 systems to boot
+    without an initramfs, though some support work is still required in initramfs-tools
+    and grub.
+    - LP: #311730
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 02 Jan 2009 07:33:09 -0700
+
+linux (2.6.28-4.6) jaunty; urgency=low
+
+  [ Tim Gardner ]
+
+  * Enable CONFIG_X86_E_POWERSAVER=m for i386 generic
+    - LP: #237405
+  * Build i386 AGP drivers as modules
+    - LP: #312721
+  * Build i386 DRM as a module
+    - LP: #312721
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915: Add missing userland definitions for gem init/execbuffer.
+    - LP: #308387
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 29 Dec 2008 09:16:47 -0700
+
+linux (2.6.28-4.5) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * clean up module dependancy information on package removal/purge
+    - LP: #300773
+
+  [ Tim Gardner ]
+
+  * Update iscsitarget to 0.4.17
+  * Build in ext{234}
+  * Build in Crypto modules AES, CBC, ECB
+  * Build in ACPI AC,BATTERY,BUTTON,FAN,PCI_SLOT,PROCESSOR,SBS,THERMAL,WMI
+  * Build in AGP intel,via,sis,ali,amd,amd64,efficeon,nvidia,sworks
+  * Build in ata,dev_dm,dev_loop,dev_md,dev_sd,dev_sr
+  * Build in BT l2cap,rfcomm,sco
+  * Reduce CONFIG_LEGACY_PTY_COUNT to 0
+  * Build in CDROM_PKTCDVD and CHR_DEV_SG
+  * Build in CPU_FREQ
+    GOV_CONSERVATIVE,GOV_ONDEMAND,GOV_POWERSAVE,GOV_USERSPACE,STAT,TABLE
+  * Build in DM CRYPT,MIRROR,MULTIPATH,SNAPSHOT
+  * Build in DRM
+  * Build in HID
+  * Build in HOTPLUG PCI,PCIE
+  * Build in I2C
+  * Build in IEEE1394 OHCI1394
+  * Build in INPUT EVDEV
+  * Build in IPV6
+  * Build in MMC
+  * Build in PACKET
+  * Enable both IEEE1394 (Firewire) stacks as modules
+    - LP: #276463
+  * Disable SUNRPC_REGISTER_V4
+    - LP: #306016
+  * Enable dm-raid4-5
+    - LP: #309378
+  * Build in PPP
+  * Build in RFKILL
+  * Build in USB SERIAL
+
+  [ Upstream Kernel Changes ]
+
+  * Rebased to v2.6.28
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 18 Dec 2008 21:18:44 -0700
+
+linux (2.6.28-3.4) jaunty; urgency=low
+
+  [ Tim Gardner ]
+
+  * Build ecryptfs into the kernel
+    - LP: #302870
+  * Deprecated gnbd
+
+  [ Upstream Kernel Changes ]
+
+  * Rebased to v2.6.28-rc8
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 10 Dec 2008 22:45:13 -0700
+
+linux (2.6.28-2.3) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * update the templates so that we have spaces following the title line
+
+  [ Tim Gardner ]
+
+  * Add upload number to kernel version signature. This has the side effect
+    of renaming kernel packages back to the original way, e.g., without '-ub'
+    in the name.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 04 Dec 2008 12:18:31 -0700
+
+linux (2.6.28-2.2) jaunty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) version: Implement version_signature proc file."
+  * SAUCE: (no-up) version: Implement version_signature proc file.
+  * SAUCE: serial: RS485 ioctl structure uses __u32 include linux/types.h
+    - LP: #303711
+
+  [ Tim Gardner ]
+
+  * UBUNTU: Removed CONFIG_DRM_VIA_CHROME9 since it is upstream.
+  * UBUNTU: Removed ubuntu/via_chrome9
+
+  [ Upstream Kernel Changes ]
+
+  * Rebased to v2.6.28-rc7
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 02 Dec 2008 07:33:32 -0700
+
+linux (2.6.28-1.1) jaunty; urgency=low
+
+  [ Amit Kucheria ]
+
+  * SAUCE: make fc transport removal of target configurable
+  * SAUCE: pm: Config option to disable handling of console during
+    suspend/resume
+  * SAUCE: Adds support for COMPAL JHL90 webcam
+  * Map armel to arm to all editconfigs to work correctly
+  * Add armel to getabis for completeness sake
+  * Add -ub to our versioning to allow kerneloops.org to identify us
+
+  [ Andy Whitcroft ]
+
+  * Fix Vcs-Git path for the kernel repository.
+    - LP: #296915
+
+  [ Ben Collins ]
+
+  * SAUCE: Lower warning level of some PCI messages
+    - LP: #159241
+  * SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps
+  * SAUCE: tulip: Let dmfe handle davicom on non-sparc
+  * SAUCE: tulip: Define ULI PCI ID's
+  * SAUCE: (no-up) version: Implement version_signature proc file.
+  * SAUCE: (no-up) connector.h: Add idx/val for drbd
+  * SAUCE: (no-up) swap: Add notify_swap_entry_free callback for compcache
+  * SAUCE: drivers: Remove some duplicate device entries in various modules
+  * SAUCE: (no-up) [AppArmor] merge with upstream subversion r1291
+  * SAUCE: (no-up) Enable ubuntu extra subdirectory
+  * SAUCE: (no-up) ACPI: initramfs DSDT override support
+  * ubuntu: Add drbd module
+  * ubuntu: Add iscsitarget module
+  * ubuntu: Add BOM for iscsitarget
+  * ubuntu: Add squashfs driver
+  * SAUCE: (no-up) Check for squashfs superblock in initramfs mounting.
+  * ubuntu: Add aufs module
+  * ubuntu: Added atl2 driver
+  * ubuntu: Added et131x driver
+  * ubuntu: Add dm-raid4-5 driver
+  * ubuntu: Add ndiswrapper driver
+  * ubuntu: Added ram backed compressed swap module (compcache)
+  * ubuntu: Add misc drivers from hardy lum
+  * ubuntu: Add heci driver 3.2.0.24
+  * ubuntu: Add ov511 and bt-sco drivers
+  * ubuntu: Add acx, prism2_usb wireless drivers
+  * ubuntu: Add at76 driver to build
+  * ubuntu: Add fsam7400 sw kill switch driver
+  * ubuntu: Added qc-usb driver
+  * ubuntu: e1000e: Upgraded module to 0.4.1.7
+  * ubuntu: Added rfkill drivers
+  * ubuntu: VIA - Add VIA DRM Chrome9 3D engine
+  * ubuntu: unionfs: Added v1.4 module from hardy
+  * ubuntu: Add LIRC driver
+  * ubuntu: Add GFS driver
+  * ubuntu: New tlsup driver for toshiba laptops
+  * SAUCE: (no-up) Export lookup_has for aufs
+  * SAUCE: (no-up) Modularize vesafb
+  * ubuntu: Config files
+  * Disable some modules that need porting to 2.6.28
+  * ubuntu: Fixup headers creation to include arch/*/include
+  * ubuntu/module-check: Ignore comment lines
+
+  [ Chuck Short ]
+
+  * SAUCE: ata: blacklist FUJITSU MHW2160BH PL
+
+  [ cking ]
+
+  * SAUCE: Enable speedstep for sonoma processors.
+
+  [ Colin Ian King ]
+
+  * ubuntu: Add dm-loop
+  * SAUCE: cx88: Support Leadtek WinFast DTV2000 H version J.
+  * SAUCE: fix kernel oops in VirtualBox during paravirt patching
+  * SAUCE: qc-usb: Enable Logitech QuickCam Messenger
+  * SAUCE: appleir: Enable driver for new MacBook Pro
+
+  [ Colin Watson ]
+
+  * Enable configfs, fuse, jfs, reiserfs, and xfs for armel
+  * Extend debian/d-i/ modules handling to make armel easier to support
+  * Create udebs for armel
+
+  [ Fabio M. Di Nitto ]
+
+  * ubuntu: update GFS Cluster File System
+
+  [ Kees Cook ]
+
+  * SAUCE: AppArmor: update to upstream subversion r1302
+
+  [ Leann Ogasawara ]
+
+  * Add automatic model setting for Samsung Q45
+  * Add Dell Dimension 9200 reboot quirk
+
+  [ Mackenzie Morgan ]
+
+  * SAUCE: Add quirk for ASUS Z37E to make sound audible after resume
+
+  [ Matthew Garrett ]
+
+  * SAUCE: hostap: send events on data interface as well as master
+    interface
+
+  [ Michael Frey (Senior Manager, MID ]
+
+  * SAUCE: Send HCI_RESET for Broadcomm 2046
+
+  [ Michael Haas ]
+
+  * add proper aufs source tree from 20080922
+  * Fix AUFS compilation in vfsub.c
+  * Add splice-2.6.23.patch from AUFS to export a symbol needed by AUFS
+  * Add put_filp.patch from AUFS to export a symbol needed by AUFS
+  * Add deny_write_access.patch from AUFS - export deny_write_access
+  * Add sec_perm-2.6.24.patch from AUFS - export security_inode_permission
+  * make sure TMPFS_MAGIC is defined in AUFS Makefile
+  * SAUCE: Revert aufs changes from AppArmor merge
+
+  [ Mohamed Abbas ]
+
+  * SAUCE: iwlagn -- fix rfkill when on when driver loaded
+
+  [ Phillip Lougher ]
+
+  * SAUCE: r8169: disable TSO by default for RTL8111/8168B chipsets.
+
+  [ Stefan Bader ]
+
+  * SAUCE: (no-up) Export dm_disk function of device-mapper
+  * SAUCE: Restore VT fonts on switch
+  * SAUCE: mmc: Increase power_up deleay to fix TI readers
+  * gfs1: GFS1 can't create more than 4kb file
+  * uvcvideo: Commit streaming parameters when enabling the video stream.
+
+  [ Tim Gardner ]
+
+  * SAUCE: Add extra headers to linux-libc-dev
+  * SAUCE: Catch nonsense keycodes and silently ignore
+  * SAUCE: Added support for HDAPS on various ThinkPads from Lenovo and IBM
+  * SAUCE: Guest OS does not recognize a lun with non zero target id on
+    Vmware ESX Server
+  * SAUCE: (no-up) Take care of orinoco_cs overlap with hostap_cs
+  * ubuntu: Add GNBD driver
+  * SAUCE: e1000e: Map NV RAM dynamically only when needed.
+  * SAUCE: Correctly blacklist Thinkpad r40e in ACPI
+  * SAUCE: Update Wacom tablet driver to 1.49
+  * SAUCE: Fix Wacom tablet 1.49 porting errors
+  * SAUCE: Enable an e1000e Intel Corporation 82567 Gigabit controller
+  * SAUCE: Fix Oops in wlan_setup
+  * SAUCE: ipw2200: change default policy for auto-associate
+  * Dell Wireless 365 needs BTUSB_RESET quirk.
+  * ndiswrapper remote buffer overflows on long ESSIDs (CVE 2008-4395)
+  * Disabled ubuntu/e1000e config
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[Bluetooth] Eliminate checks for impossible conditions in IRQ
+    handler"
+  * Revert "x86, early_ioremap: fix fencepost error"
+  * mac80211: fix two issues in debugfs
+  * iwl3945: do not send scan command if channel count zero
+
+ --  Ben Collins <ben.collins@canonical.com>  Fri, 07 Nov 2008 09:37:42 -0700
+
+linux (2.6.27-8.17) intrepid-proposed; urgency=low
+
+  [ John W. Linville ]
+
+  * SAUCE: iwlagn: avoid sleep in softirq context
+    -LP: #286285
+
+  [ Tim Gardner ]
+
+  * Dell Wireless 365 needs BTUSB_RESET quirk.
+    - LP: #293670
+  * SAUCE: ALSA: hda: make a STAC_DELL_EQ option (version 2)
+    - LP: #293271
+
+  [ Upstream Kernel Changes ]
+
+  * iwlagn: downgrade BUG_ON in interrupt
+  * Input: atkbd - expand Latitude's force release quirk to other Dells
+  * fbcon_set_all_vcs: fix kernel crash when switching the rotated consoles
+  * modules: fix module "notes" kobject leak
+  * Driver core: Fix cleanup in device_create_vargs().
+  * Driver core: Clarify device cleanup.
+  * ath9k/mac80211: disallow fragmentation in ath9k, report to userspace
+  * md: Fix rdev_size_store with size == 0
+  * xfs: fix remount rw with unrecognized options
+  * OHCI: Allow broken controllers to auto-stop
+  * USB: OHCI: fix endless polling behavior
+  * USB: Fix s3c2410_udc usb speed handling
+  * USB: EHCI: log a warning if ehci-hcd is not loaded first
+  * usb gadget: cdc ethernet notification bugfix
+  * usb: musb_hdrc build fixes
+  * drm/i915: fix ioremap of a user address for non-root (CVE-2008-3831)
+  * DVB: au0828: add support for another USB id for Hauppauge HVR950Q
+  * DVB: sms1xxx: support two new revisions of the Hauppauge WinTV
+    MiniStick
+  * security: avoid calling a NULL function pointer in
+    drivers/video/tvaudio.c
+  * Linux 2.6.27.3
+    -LP: #294152
+
+  * gpiolib: fix oops in gpio_get_value_cansleep()
+  * edac cell: fix incorrect edac_mode
+  * x86 ACPI: fix breakage of resume on 64-bit UP systems with SMP kernel
+  * sched: fix the wrong mask_len
+  * USB: cdc-wdm: make module autoload work
+  * USB: don't rebind drivers after failed resume or reset
+  * USB: fix memory leak in cdc-acm
+  * USB: Speedtouch: add pre_reset and post_reset routines
+  * dm kcopyd: avoid queue shuffle
+  * dm snapshot: fix primary_pe race
+  * amd_iommu: fix nasty bug that caused ILLEGAL_DEVICE_TABLE_ENTRY errors
+  * CIFS: fix saving of resume key before CIFSFindNext
+  * netfilter: xt_iprange: fix range inversion match
+  * netfilter: snmp nat leaks memory in case of failure
+  * netfilter: restore lost ifdef guarding defrag exception
+  * anon_vma_prepare: properly lock even newly allocated entries
+  * hvc_console: Fix free_irq in spinlocked section
+  * ACPI Suspend: Enable ACPI during resume if SCI_EN is not set
+  * ACPI suspend: Blacklist HP xw4600 Workstation for old code ordering
+  * ACPI suspend: Always use the 32-bit waking vector
+  * proc: fix vma display mismatch between /proc/pid/{maps,smaps}
+  * SCSI: scsi_dh: add Dell product information into rdac device handler
+  * PCI hotplug: cpqphp: fix kernel NULL pointer dereference
+  * V4L/DVB (9300): pvrusb2: Fix deadlock problem
+  * Linux 2.6.27.4
+    -LP: #294155
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 04 Nov 2008 12:16:07 -0700
+
+linux (2.6.27-7.16) intrepid-security; urgency=low
+
+  [ Tim Gardner ]
+
+  * ndiswrapper remote buffer overflows on long ESSIDs (CVE 2008-4395)
+    - LP: #275860
+
+  [ Upstream Kernel Changes ]
+
+  * ext[234]: Avoid printk floods in the face of directory corruption
+    (CVE-2008-3528)
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 03 Nov 2008 13:34:42 -0700
+
+linux (2.6.27-7.15) intrepid-security; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * tcp: Restore ordering of TCP options for the sake of inter-operability
+    - LP: #264019
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 27 Oct 2008 19:28:06 -0600
+
+linux (2.6.27-7.14) intrepid; urgency=low
+
+  [ Tim Gardner ]
+
+  * Disable ath5k in 2.6.27
+    - LP: #288148
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 23 Oct 2008 07:40:43 -0600
+
+linux (2.6.27-7.13) intrepid; urgency=low
+
+  [ Stefan Bader ]
+
+  * gfs1: GFS1 can't create more than 4kb file
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: x86: Reserve FIRST_DEVICE_VECTOR in used_vectors
+    bitmap.". Use upstream commit to avoid future conflicts.
+  * Revert "STABLE queue: mac80211: fix two issues in debugfs".
+    Use upstream commit to avoid future conflicts.
+  * Revert "x86, early_ioremap: fix fencepost error"
+    Use upstream commit to avoid future conflicts.
+
+  [ Upstream Kernel Changes ]
+
+  * sched_rt.c: resch needed in rt_rq_enqueue() for the root rt_rq
+  * x86: Reserve FIRST_DEVICE_VECTOR in used_vectors bitmap.
+  * mac80211: fix two issues in debugfs
+  * Fix barrier fail detection in XFS
+  * tty: Termios locking - sort out real_tty confusions and lock reads
+  * CIFS: make sure we have the right resume info before calling
+    CIFSFindNext
+  * rfkill: update LEDs for all state changes
+  * libertas: clear current command on card removal
+  * b43legacy: Fix failure in rate-adjustment mechanism
+  * x86, early_ioremap: fix fencepost error
+  * x86: SB450: skip IRQ0 override if it is not routed to INT2 of IOAPIC
+  * x86: improve UP kernel when CPU-hotplug and SMP is enabled
+  * sky2: Fix WOL regression
+  * netdrvr: atl1e: Don't take the mdio_lock in atl1e_probe
+  * Linux 2.6.27.2
+
+  [ Amit Kucheria ]
+
+  * Ubuntu: agp: Fix stolen memory counting on G4X.
+    -LP: 285572
+
+  [ Scott Remnant ]
+
+  * add MODULE_ALIAS to load ipmi_devintf with ipmi_si
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sun, 19 Oct 2008 10:06:21 -0600
+
+linux (2.6.27-7.12) intrepid; urgency=low
+
+  [ Chuck Short ]
+
+  * xen: Add xen modules to virtual flavours.
+
+  [ Mario Limonciello ]
+
+  * SAUCE: Add back in lost commit for Apple BT Wireless Keyboard
+    - LP: #162083
+
+  [ Tim Gardner ]
+
+  * Remove depmod created files from packages.
+    - LP: #250511
+  *  Changed default TCP congestion algorithm to 'cubic' (again)
+    - LP: #278801
+  * Update configs for 'disable CONFIG_DYNAMIC_FTRACE'
+    - LP: #263555
+
+  [ Upstream Kernel Changes ]
+
+  * x86: register a platform RTC device if PNP doesn't describe it
+  * disable CONFIG_DYNAMIC_FTRACE due to possible memory corruption on
+    module unload
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 17 Oct 2008 11:25:39 -0600
+
+linux (2.6.27-7.11) intrepid; urgency=low
+
+  [ Amit Kucheria ]
+
+  * STABLE queue: mac80211: fix two issues in debugfs
+    - LP: #275227
+  * SAUCE: Adds support for COMPAL JHL90 webcam
+
+  [ Ben Collins ]
+
+  * SAUCE: (no-up) x86: Quiet "Kernel alive" messages
+    - LP: #39985
+  * SAUCE: (no-up) Modularize vesafb
+  * build/config: Enable vesafb module
+  * build: Switch to vesafb as preferred.
+
+  [ Leann Ogasawara ]
+
+  * Add Dell Dimension 9200 reboot quirk
+    - LP: #271370
+
+  [ Michael Haas ]
+
+  * SAUCE: Revert aufs changes from AppArmor merge
+
+  [ Tim Gardner ]
+
+  * fix virtio udeb layout
+    - LP: #257739
+  * Enabled CONFIG_EXT4DEV_FS=m
+  * Changed default TCP congestion algorithm to 'cubic'
+    - LP: #278801
+  * SAUCE: ipw2200: change default policy for auto-associate
+    - LP: #264104
+
+  [ Upstream Kernel Changes ]
+
+  * x86, early_ioremap: fix fencepost error
+    - LP: #263543
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sat, 11 Oct 2008 08:07:42 -0600
+
+linux (2.6.27-7.10) intrepid; urgency=low
+
+  [ Alexey Starikovskiy ]
+
+  * SAUCE: ACPI: EC: do transaction from interrupt context
+    - LP: #277802
+
+  [ Ben Collins ]
+
+  * build/d-i: Change virtio-modules udeb to prio standard
+
+  [ Colin Ian King ]
+
+  * SAUCE: Blacklist IBM 2656 in serio/i8042
+    - LP: #21558
+
+  [ Henrik Rydberg ]
+
+  * Revert "SAUCE: applesmc: Add MacBookAir"
+  * SAUCE: [PATCH 1/5] hwmon: applesmc: Specified number of bytes to read
+    should match actual
+  * SAUCE: [PATCH 2/5] hwmon: applesmc: Fix the 'wait status failed: c !=
+    8' problem
+  * SAUCE: [PATCH 3/5] hwmon: applesmc: Prolong status wait
+  * SAUCE: [PATCH 4/5] hwmon: applesmc: Allow for variable ALV0 and ALV1
+    package length
+  * SAUCE: [PATCH 5/5] hwmon: applesmc: Add support for Macbook Air
+  * SAUCE: hwmon: applesmc: Add support for Macbook Pro 4
+  * SAUCE: hwmon: applesmc: Add support for Macbook Pro 3
+  * SAUCE: hwmon: applesmc: Lighter wait mechanism, drastic improvement
+
+  [ Leann Ogasawara ]
+
+  * Add automatic model setting for Samsung Q45
+    - LP: #200210
+
+  [ Tim Gardner ]
+
+  * SAUCE: Correctly blacklist Thinkpad r40e in ACPI
+    - LP: #278794
+  * SAUCE: Update Wacom tablet driver to 1.49
+    - LP: #260675
+  * SAUCE: ALPS touchpad for Dell Latitude E6500/E6400
+    - LP: #270643
+  * SAUCE: Fix Wacom tablet 1.49 porting errors
+  * SAUCE: Enable an e1000e Intel Corporation 82567 Gigabit controller
+  * SAUCE: Fix Oops in wlan_setup
+    - LP: #263309
+
+  [ Upstream Kernel Changes ]
+
+  * ath9k: fix oops on trying to hold the wrong spinlock
+  * [Bluetooth] Fix double frees on error paths of btusb and bpa10x drivers
+  * [Bluetooth] Add reset quirk for new Targus and Belkin dongles
+  * [Bluetooth] Add reset quirk for A-Link BlueUSB21 dongle
+  * Revert "ax25: Fix std timer socket destroy handling."
+  * ax25: Quick fix for making sure unaccepted sockets get destroyed.
+  * netrom: Fix sock_orphan() use in nr_release
+  * Revert "V4L/DVB (8904): cx88: add missing unlock_kernel"
+  * SLOB: fix bogus ksize calculation
+  * net: only invoke dev->change_rx_flags when device is UP
+  * tcp: Fix possible double-ack w/ user dma
+  * net: Fix netdev_run_todo dead-lock
+  * tcp: Fix tcp_hybla zero congestion window growth with small rho and large cwnd.
+  * [MIPS] Sibyte: Register PIO PATA device only for Swarm and Litte Sur
+  * eeepc-laptop: Fix hwmon interface
+  * hwmon: (it87) Prevent power-off on Shuttle SN68PT
+  * hwmon: Define sysfs interface for energy consumption register
+  * hwmon: (adt7473) Fix some bogosity in documentation file
+  * hwmon: (abituguru3) Enable reading from AUX3 fan on Abit AT8 32X
+  * hwmon: (abituguru3) Enable DMI probing feature on Abit AT8 32X
+  * [CPUFREQ] correct broken links and email addresses
+  * SLOB: fix bogus ksize calculation fix
+  * Don't allow splice() to files opened with O_APPEND
+  * Linux 2.6.27
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 08 Oct 2008 21:19:34 -0600
+
+linux (2.6.27-6.9) intrepid; urgency=low
+
+  [ Kees Cook ]
+
+  * SAUCE: AppArmor: update to upstream subversion r1302
+    - LP: #269921
+
+  [ Stefan Bader ]
+
+  * Update configuration files to be compliant to desktop specs
+    - LP: #279019
+
+  [ Tim Gardner ]
+
+  * Add support in e1000e for a couple of ICH10 PCI IDs
+  * Enable CONFIG_INPUT_PCSPKR=m
+    - LP: #275453
+
+  [ Upstream Kernel Changes ]
+
+  * V4L/DVB (8559a): Fix a merge conflict at gspca/sonixb
+  * V4L/DVB (8789): wm8739: remove wrong kfree
+  * V4L/DVB (8883): w9968cf: Fix order of usb_alloc_urb validation
+  * V4L/DVB (8884): em28xx-audio: fix memory leak
+  * V4L/DVB (8885): cpia2_usb: fix memory leak
+  * V4L/DVB (8886): ov511: fix memory leak
+  * V4L/DVB (8887): gspca: fix memory leak
+  * V4L/DVB (8892): pvrusb2: Handle USB ID 2040:2950 same as 2040:2900
+  * V4L/DVB (8904): cx88: add missing unlock_kernel
+  * V4L/DVB (8905): ov511: fix exposure sysfs attribute bug
+  * V4L/DVB (8909): gspca: PAC 7302 webcam 093a:262a added.
+  * hrtimer: migrate pending list on cpu offline
+  * hrtimer: fix migration of CB_IRQSAFE_NO_SOFTIRQ hrtimers
+  * hrtimer: mark migration state
+  * hrtimer: prevent migration of per CPU hrtimers
+  * [IA64] Put the space for cpu0 per-cpu area into .data section
+  * powerpc: Fix PCI in Holly device tree
+  * powerpc: Fix failure to shutdown with CPU hotplug
+  * mfd: Fix Kconfig accroding to the new gpiolib symbols
+  * mfd: Fix asic3 compilation
+  * x86: fix typo in enable_mtrr_cleanup early parameter
+  * ipsec: Fix pskb_expand_head corruption in xfrm_state_check_space
+  * iucv: Fix mismerge again.
+  * ALSA: ASoC: Fix cs4270 error path
+  * ALSA: hda - Fix model for Dell Inspiron 1525
+  * sctp: Fix kernel panic while process protocol violation parameter
+  * x86: Fix broken LDT access in VMI
+  * x86, vmi: fix broken LDT access
+  * tcp: Fix NULL dereference in tcp_4_send_ack()
+  * ipv6: NULL pointer dereferrence in tcp_v6_send_ack
+  * XFRM,IPv6: initialize ip6_dst_blackhole_ops.kmem_cachep
+  * af_key: Free dumping state on socket close
+  * dm: always allow one page in dm_merge_bvec
+  * dm: cope with access beyond end of device in dm_merge_bvec
+  * dm mpath: add missing path switching locking
+  * MN10300: Fix IRQ handling
+  * pxa2xx_spi: fix build breakage
+  * e1000e: write protect ICHx NVM to prevent malicious write/erase
+  * powerpc: Fix boot hang regression on MPC8544DS
+  * ASoC: Set correct name for WM8753 rec mixer output
+  * ALSA: snd-powermac: mixers for PowerMac G4 AGP
+  * ALSA: snd-powermac: HP detection for 1st iMac G3 SL
+  * fbcon: fix monochrome color value calculation
+  * inotify: fix lock ordering wrt do_page_fault's mmap_sem
+  * braille_console: only register notifiers when the braille console is used
+  * fix error-path NULL deref in alloc_posix_timer()
+  * memory hotplug: missing zone->lock in test_pages_isolated()
+  * mm: tiny-shmem nommu fix
+  * mm: handle initialising compound pages at orders greater than MAX_ORDER
+  * e1000e: reset swflag after resetting hardware
+  * e1000e: do not ever sleep in interrupt context
+  * e1000e: remove phy read from inside spinlock
+  * e1000e: drop stats lock
+  * e1000e: debug contention on NVM SWFLAG
+  * e1000e: update version from k4 to k6
+  * Check mapped ranges on sysfs resource files
+  * e1000e: Fix incorrect debug warning
+  * [MIPS] Build fix: Fix irq flags type
+  * [MIPS] SMTC: Build fix: Fix filename in Makefile
+  * [MIPS] SMTC: Fix holes in SMTC and FPU affinity support.
+  * [MIPS] SMTC: Close tiny holes in the SMTC IPI replay system.
+  * [MIPS] SMTC: Fix SMTC dyntick support.
+  * [S390] nohz: Fix __udelay.
+  * [S390] qdio: prevent stack clobber
+  * Fix init/main.c to use regular printk with '%pF' for initcall fn
+  * x86 setup: correct segfault in generation of 32-bit reloc kernel
+  * selinux: Fix an uninitialized variable BUG/panic in selinux_secattr_to_sid()
+  * rtc: fix kernel panic on second use of SIGIO nofitication
+  * fbdev: fix recursive notifier and locking when fbdev console is blanked
+  * orion_spi: fix handling of default transfer speed
+  * include/linux/stacktrace.h: declare struct task_struct
+  * cpusets: remove pj from cpuset maintainers
+  * MAINTAINERS: add mailing list for man-pages
+  * SubmitChecklist: interfaces changes should CC linux-api@
+  * Documentation/HOWTO: info about interface changes should CC linux-api@vger
+  * dw_dmac: fix copy/paste bug in tasklet
+  * leds-fsg: change order of initialization and deinitialization
+  * leds-pca955x: add proper error handling and fix bogus memory handling
+  * ACPI: Make /proc/acpi/wakeup interface handle PCI devices (again)
+  * clockevents: check broadcast tick device not the clock events device
+  * V4L/DVB (8919): cx18: Fix tuner audio input for Compro H900 cards
+  * V4L/DVB (8926): gspca: Bad fix of leak memory (changeset 43d2ead315b1).
+  * V4L/DVB (8933): gspca: Disable light frquency for zc3xx cs2102 Kokom.
+  * V4L/DVB (8935): em28xx-cards: Remove duplicate entry (EM2800_BOARD_KWORLD_USB2800)
+  * V4L/DVB (8955): bttv: Prevent NULL pointer dereference in radio_open
+  * V4L/DVB (8957): zr36067: Restore the default pixel format
+  * V4L/DVB (8958): zr36067: Return proper bytes-per-line value
+  * V4L/DVB (8960): drivers/media/video/cafe_ccic.c needs mm.h
+  * V4L/DVB (8961): zr36067: Fix RGBR pixel format
+  * V4L/DVB (8963): s2255drv field count fix
+  * V4L/DVB (8967): Use correct XC3028L firmware for AMD ATI TV Wonder 600
+  * V4L/DVB (8978): sms1xxx: fix product name for Hauppauge WinTV MiniStick
+  * V4L/DVB (8979): sms1xxx: Add new USB product ID for Hauppauge WinTV MiniStick
+  * V4L/DVB (9029): Fix deadlock in demux code
+  * V4L/DVB (9037): Fix support for Hauppauge Nova-S SE
+  * V4L/DVB (9043): S5H1420: Fix size of shadow-array to avoid overflow
+  * V4L/DVB (9053): fix buffer overflow in uvc-video
+  * V4L/DVB (9075): gspca: Bad check of returned status in i2c_read() spca561.
+  * V4L/DVB (9080): gspca: Add a delay after writing to the sonixj sensors.
+  * V4L/DVB (9092): gspca: Bad init values for sonixj ov7660.
+  * V4L/DVB (9099): em28xx: Add detection for K-WORLD DVB-T 310U
+  * V4L/DVB (9103): em28xx: HVR-900 B3C0 - fix audio clicking issue
+  * x86: gart iommu have direct mapping when agp is present too
+  * ide-cd: temporary tray close fix
+  * ide-dma: fix ide_build_dmatable() for TRM290
+  * IDE: Fix platform device registration in Swarm IDE driver (v2)
+  * ide-cd: Optiarc DVD RW AD-7200A does play audio
+  * ide: workaround for bogus gcc warning in ide_sysfs_register_port()
+  * [MIPS] Fix CMP Kconfig configuration and mark as broken.
+  * [MIPS] IP27: Fix build errors if CONFIG_MAPPED_KERNEL=y
+  * x86 ACPI: Blacklist two HP machines with buggy BIOSes
+  * kgdb, x86: Avoid invoking kgdb_nmicallback twice per NMI
+  * kgdb: call touch_softlockup_watchdog on resume
+  * atmel-mci: Initialize BLKR before sending data transfer command
+  * Marker depmod fix core kernel list
+  * Linux 2.6.27-rc9
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sun, 05 Oct 2008 21:27:49 -0600
+
+linux (2.6.27-5.8) intrepid; urgency=low
+
+  [ Amit Kucheria ]
+
+  * Update AUFS-related Kconfig
+    - LP: #264048
+
+  [ Michael Haas ]
+
+  * add proper aufs source tree from 20080922
+  * Fix AUFS compilation in vfsub.c
+  * Add splice-2.6.23.patch from AUFS to export a symbol needed by AUFS
+  * Add put_filp.patch from AUFS to export a symbol needed by AUFS
+  * apply (modified) lhash.patch from AUFS to export __lookup_hash()
+  * Add deny_write_access.patch from AUFS - export deny_write_access
+  * Add sec_perm-2.6.24.patch from AUFS - export security_inode_permission
+  * make sure TMPFS_MAGIC is defined in AUFS Makefile
+
+  [ Tim Gardner ]
+
+  * Enabled CONFIG_IPWIRELESS
+    - LP: #274748
+  * Enabled CONFIG_E1000E, disabled CONFIG_E1000E_NEW
+    This takes advantage of the upstream NVM protection fix in
+    commit 4a7703582836f55a1cbad0e2c1c6ebbee3f9b3a7.
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[Bluetooth] Eliminate checks for impossible conditions in IRQ
+    handler"
+  * [SCSI] qla2xxx: Defer enablement of RISC interrupts until ISP
+    initialization completes.
+  * PCI: Fix pcie_aspm=force
+  * PCI: fix compiler warnings in pci_get_subsys()
+  * UBIFS: create the name of the background thread in every case
+  * UBIFS: TNC / GC race fixes
+  * UBIFS: remove incorrect assert
+  * UBIFS: fix printk format warnings
+  * AMD IOMMU: set iommu sunc flag after command queuing
+  * AMD IOMMU: protect completion wait loop with iommu lock
+  * sparc64: Fix disappearing PCI devices on e3500.
+  * x86, oprofile: BUG scheduling while atomic
+  * ALSA: ASoC: Fix at32-pcm build breakage with PM enabled
+  * ath9k: connectivity is lost after Group rekeying is done
+  * wireless: zd1211rw: add device ID fix wifi dongle "trust nw-3100"
+  * [IA64] Ski simulator doesn't need check_sal_cache_flush
+  * [IA64] kexec fails on systems with blocks of uncached memory
+  * ath9k: Fix IRQ nobody cared issue with ath9k
+  * [Bluetooth] Fix I/O errors on MacBooks with Broadcom chips
+  * [Bluetooth] Fix wrong URB handling of btusb driver
+  * [Bluetooth] Fix USB disconnect handling of btusb driver
+  * sparc64: Fix missing devices due to PCI bridge test in
+    of_create_pci_dev().
+  * [WATCHDOG] ibmasr: remove unnecessary spin_unlock()
+  * [WATCHDOG] wdt285: fix sparse warnings
+  * [WATCHDOG] unlocked_ioctl changes
+  * x86: fix 27-rc crash on vsmp due to paravirt during module load
+  * sched: fix init_hrtick() section mismatch warning
+  * clockevents: prevent cpu online to interfere with nohz
+  * x86: prevent stale state of c1e_mask across CPU offline/online
+  * clockevents: prevent stale tick_next_period for onlining CPUs
+  * clockevents: check broadcast device not tick device
+  * clockevents: prevent mode mismatch on cpu online
+  * x86: prevent C-states hang on AMD C1E enabled machines
+  * x86: c1e_idle: don't mark TSC unstable if CPU has invariant TSC
+  * timers: fix build error in !oneshot case
+  * ALSA: ASoC: maintainers - update email address for Liam Girdwood
+  * ibmasr: remove unnecessary spin_unlock()
+  * smb.h: do not include linux/time.h in userspace
+  * kernel-doc: allow structs whose members are all private
+  * kexec: fix segmentation fault in kimage_add_entry
+  * Documentation/DMA-mapping.txt: update for pci_dma_mapping_error()
+    changes
+  * sys_paccept: disable paccept() until API design is resolved
+  * mm: tiny-shmem fix lock ordering: mmap_sem vs i_mutex
+  * Documentation/sysctl/kernel.txt: fix softlockup_thresh description
+  * memcg: check under limit at shrink_usage
+  * atmel_serial: update the powersave handler to match serial core
+  * [SCSI] Fix hang with split requests
+  * USB Storage: Sierra: Non-configurable TRU-Install
+  * USB Serial: Sierra: Device addition & version rev
+  * USB: ehci: fix some ehci hangs and crashes
+  * USB: Fix the Nokia 6300 storage-mode.
+  * USB: Correct Sierra Wireless USB EVDO Modem Device ID
+  * USB: fix hcd interrupt disabling
+  * USB: update of Documentation/usb/anchors.txt
+  * usb gadget: fix omap_udc DMA regression
+  * USB: Fixing Nokia 3310c in storage mode
+  * usb: musb: fix include path
+  * USB: fix EHCI periodic transfers
+  * usb-serial: Add Siemens EF81 to PL-2303 hack triggers
+  * USB: SERIAL CP2101 add device IDs
+  * USB: unusual_devs addition for RockChip MP3 player
+  * USB: fsl_usb2_udc: fix VDBG() format string
+  * usb serial: ti_usb_3410_5052 obviously broken by firmware changes
+  * USB: ftdi_sio: Add 0x5050/0x0900 USB IDs (Papouch Quido USB 4/4)
+  * USB: serial: add ZTE CDMA Tech id to option driver
+  * USB Serial: Sierra: Add MC8785 VID/PID
+  * USB: drivers/usb/musb/: disable it on SuperH
+  * usb: ftdi_sio: add support for Domintell devices
+  * usb: unusual devs patch for Nokia 5310 Music Xpress
+  * USB: revert recovery from transient errors
+  * [MIPS] au1000: Fix gpio direction
+  * [MIPS] Fixe the definition of PTRS_PER_PGD
+  * x86: prevent stale state of c1e_mask across CPU offline/online, fix
+  * x86: disable apm on the olpc
+  * i2c-powermac: Fix section for probe and remove functions
+  * i2c-dev: Return correct error code on class_create() failure
+  * i2c: Fix mailing lists in two MAINTAINERS entries
+  * ath9k: disable MIB interrupts to fix interrupt storm
+  * 9p: implement proper trans module refcounting and unregistration
+  * 9p-trans_fd: fix trans_fd::p9_conn_destroy()
+  * 9p-trans_fd: clean up p9_conn_create()
+  * 9p-trans_fd: don't do fs segment mangling in p9_fd_poll()
+  * 9p-trans_fd: fix and clean up module init/exit paths
+  * 9p: introduce missing kfree
+  * 9p: use an IS_ERR test rather than a NULL test
+  * 9p: fix put_data error handling
+  * netfilter: ip6t_{hbh,dst}: Rejects not-strict mode on rule insertion
+  * MN10300: Move asm-arm/cnt32_to_63.h to include/linux/
+  * MN10300: Make sched_clock() report time since boot
+  * ALSA: fix locking in snd_pcm_open*() and snd_rawmidi_open*()
+  * ALSA: remove unneeded power_mutex lock in snd_pcm_drop
+  * IPoIB: Fix crash when path record fails after path flush
+  * [XFS] Fix extent list corruption in xfs_iext_irec_compact_full().
+  * [XFS] Remove xfs_iext_irec_compact_full()
+  * kgdb: could not write to the last of valid memory with kgdb
+  * kgdb, x86, arm, mips, powerpc: ignore user space single stepping
+  * kgdb, x86_64: gdb serial has BX and DX reversed
+  * kgdb, x86_64: fix PS CS SS registers in gdb serial
+  * kgdboc,tty: Fix tty polling search to use name correctly
+  * ARM: Delete ARM's own cnt32_to_63.h
+  * m32r: remove the unused NOHIGHMEM option
+  * m32r: don't offer CONFIG_ISA
+  * m32r: export empty_zero_page
+  * m32r: export __ndelay
+  * m32r/kernel/: cleanups
+  * [MIPS] au1000: Make sure GPIO value is zero or one
+  * [MIPS] IP27: Switch to dynamic interrupt routing avoding panic on
+    error.
+  * [MIPS] BCM47xx: Fix build error due to missing PCI functions
+  * [SSB] Initialise dma_mask for SSB_BUSTYPE_SSB devices
+  * Swarm: Fix crash due to missing initialization
+  * ide-tape: fix vendor strings
+  * ide: note that IDE generic may prevent other drivers from attaching
+  * cdrom: update ioctl documentation
+  * [SCSI] qlogicpti: fix sg list traversal error in continuation entries
+  * sata_nv: reinstate nv_hardreset() for non generic controllers
+  * scsi: fix fall out of sg-chaining patch in qlogicpti
+  * ALSA: make the CS4270 driver a new-style I2C driver
+  * ALSA: ASoC: Fix another cs4270 error path
+  * Fix NULL pointer dereference in proc_sys_compare
+  * kconfig: fix silentoldconfig
+  * kconfig: readd lost change count
+  * mm owner: fix race between swapoff and exit
+  * Linux 2.6.27-rc8
+  * e1000e: write protect ICHx NVM to prevent malicious write/erase
+
+ -- Amit Kucheria <amit.kucheria@canonical.com>  Tue, 30 Sep 2008 18:22:35 +0300
+
+linux (2.6.27-4.7) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * build/abi: Add gfs1 to perm blacklist
+  * build/abi: Ignored changes in gfs2 symbols
+
+  [ Fabio M. Di Nitto ]
+
+  * Revert "SAUCE: Export gfs2 symbols required for gfs1 kernel module"
+  * ubuntu: update GFS Cluster File System
+
+  [ Stefan Bader ]
+
+  * SAUCE: x86: Reserve FIRST_DEVICE_VECTOR in used_vectors bitmap.
+    - LP: #276334
+
+  [ Tim Gardner ]
+
+  * Revert "Disable e1000e until the NVRAM corruption problem is found."
+  * Add atl1e and atl2 to Debian installer bits
+    - LP: #273904
+  * SAUCE: e1000e: Map NV RAM dynamically only when needed.
+    - LP: #263555
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 26 Sep 2008 20:51:22 -0600
+
+linux (2.6.27-4.6) intrepid; urgency=low
+
+  [ Tim Gardner ]
+
+  * Disable e1000e until the NVRAM corruption problem is found.
+    - LP: #263555
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[Bluetooth] Eliminate checks for impossible conditions in IRQ
+    handler"
+
+ -- Ben Collins <ben.collins@canonical.com>  Tue, 23 Sep 2008 09:53:57 -0400
+
+linux (2.6.27-4.5) intrepid; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "b43/b43legacy: add RFKILL_STATE_HARD_BLOCKED support"
+  * udf: Fix lock inversion between iprune_mutex and alloc_mutex (v2)
+  * udf: Fix error paths in udf_new_inode()
+  * [SCSI] sd: select CRC_T10DIF only when necessary
+  * [SCSI] zfcp: Fix request queue locking
+  * [SCSI] zfcp: Correctly query end flag in gpn_ft response
+  * [SCSI] zfcp: Simplify ccw notify handler
+  * [SCSI] zfcp: Fix reference counter for remote ports
+  * [SCSI] zfcp: channel cannot be detached due to refcount imbalance
+  * [SCSI] zfcp: Remove duplicated unlikely() macros.
+  * [SCSI] scsi_dh: make check_sense return ADD_TO_MLQUEUE
+  * [SCSI] make scsi_check_sense HARDWARE_ERROR return ADD_TO_MLQUEUE on
+    retry
+  * [SCSI] fix check of PQ and PDT bits for WLUNs
+  * pcm037: add rts/cts support for serial port
+  * i.MX serial: fix init failure
+  * imx serial: set RXD mux bit on i.MX27 and i.MX31
+  * imx serial: fix rts handling for non imx1 based hardware
+  * mlx4_core: Set RAE and init mtt_sz field in FRMR MPT entries
+  * udf: add llseek method
+  * PCI/iommu: blacklist DMAR on Intel G31/G33 chipsets
+  * PCI: Fix printk warnings in probe.c
+  * PCI: Fix printk warnings in setup-bus.c
+  * PCI Hotplug: fakephp: fix deadlock... again
+  * clockevents: remove WARN_ON which was used to gather information
+  * ocfs2: Fix a bug in direct IO read.
+  * arch/x86/kernel/kdebugfs.c: introduce missing kfree
+  * [IA64] fix compile failure with non modular builds
+  * [IA64] fix up bte.h
+  * [IA64] arch/ia64/sn/pci/tioca_provider.c: introduce missing kfree
+  * PCI: fix pciehp_free_irq()
+  * [IA64] prevent ia64 from invoking irq handlers on offline CPUs
+  * ide: Fix pointer arithmetic in hpt3xx driver code (3rd try)
+  * add deprecated ide-scsi to feature-removal-schedule.txt
+  * swiotlb: fix back-off path when memory allocation fails
+  * sparc64: Fix interrupt register calculations on Psycho and Sabre.
+  * VIDEO_SH_MOBILE_CEU should depend on HAS_DMA
+  * m68k: Update defconfigs for 2.6.27-rc6
+  * sparc32: Fix function signature of of_bus_sbus_get_flags().
+  * sched: fix 2.6.27-rc5 couldn't boot on tulsa machine randomly
+  * sched: fix deadlock in setting scheduler parameter to zero
+  * KVM: SVM: fix random segfaults with NPT enabled
+  * KVM: SVM: fix guest global tlb flushes with NPT
+  * KVM: VMX: Always return old for clear_flush_young() when using EPT
+  * clocksource, acpi_pm.c: fix check for monotonicity
+  * [ARM] OMAP: Fix MMC device data
+  * block: disable sysfs parts of the disk command filter
+  * ath9k: Assign seq# when mac80211 requests this
+  * sg: disable interrupts inside sg_copy_buffer
+  * MN10300: Change the fault handler to check in_atomic() not
+    in_interrupt()
+  * [Bluetooth] Fix regression from using default link policy
+  * netlink: fix overrun in attribute iteration
+  * x86: fix possible x86_64 and EFI regression
+  * sparc64: Fix PCI error interrupt registry on PSYCHO.
+  * sparc: Fix user_regset 'n' field values.
+  * niu: panic on reset
+  * PCI: re-add debug prints for unmodified BARs
+  * [ARM] 5245/1: Fix warning about unused return value in drivers/pcmcia
+  * [ARM] 5246/1: tosa: add proper clock alias for tc6393xb clock
+  * [ARM] 5247/1: tosa: SW_EAR_IN support
+  * [ARM] Fix PCI_DMA_BUS_IS_PHYS for ARM
+  * ata: duplicate variable sparse warning
+  * sata_inic162x: enable LED blinking
+  * [libata] LBA28/LBA48 off-by-one bug in ata.h
+  * proc: more debugging for "already registered" case
+  * include/linux/ioport.h: add missing macro argument for devm_release_*
+    family
+  * cpuset: avoid changing cpuset's cpus when -errno returned
+  * cpuset: hotplug documentation fix
+  * coredump_filter: add description of bit 4
+  * bfs: fix Lockdep warning
+  * mm: ifdef Quicklists in /proc/meminfo
+  * spi_mpc83xx: fix clockrate calculation for low speed
+  * spi_mpc83xx: reject invalid transfer sizes
+  * pxa2xx_spi: chipselect bugfixes
+  * pxa2xx_spi: dma bugfixes
+  * mm: mark the correct zone as full when scanning zonelists
+  * Documentation/ABI: /sys/class/gpio
+  * MAINTAINERS: fix USB VIDEO CLASS mail list address
+  * ia64: fix panic during `modprobe -r xpc'
+  * atmel_lcdfb: disable LCD and DMA engines when suspending
+  * spi_s3c24xx: fix section warning
+  * rescan_partitions(): make device capacity errors non-fatal
+  * memstick: fix MSProHG 8-bit interface mode support
+  * Add Uwe Kleine-König to .mailmap
+  * xen: fix for xen guest with mem > 3.7G
+  * x86/paravirt: Remove duplicate paravirt_pagetable_setup_{start, done}()
+  * crypto: talitos - Avoid consecutive packets going out with same IV
+  * slub: fixed uninitialized counter in struct kmem_cache_node
+  * udp: Fix rcv socket locking
+  * IB/mlx4: Fix up fast register page list format
+  * [MIPS] VR41xx: unsigned irq cannot be negative
+  * x86: completely disable NOPL on 32 bits
+  * [S390] cio: Fix driver_data handling for ccwgroup devices.
+  * [S390] cio: fix orb initialization in cio_start_key
+  * sparc64: Fix OOPS in psycho_pcierr_intr_other().
+  * sparc64: Fix SMP bootup with CONFIG_STACK_DEBUG or ftrace.
+  * RDMA/nes: Fix client side QP destroy
+  * IPoIB: Fix deadlock on RTNL between bcast join comp and ipoib_stop()
+  * clockevents: make device shutdown robust
+  * powerpc: Fix interrupt values for DMA2 in MPC8610 HPCD device tree
+  * hpplus: fix build regression
+  * Fix PNP build failure, bugzilla #11276
+  * warn: Turn the netdev timeout WARN_ON() into a WARN()
+  * [XFS] Move memory allocations for log tracing out of the critical path
+  * [XFS] Fix regression introduced by remount fixup
+  * [XFS] Prevent direct I/O from mapping extents beyond eof
+  * [XFS] Fix barrier status change detection.
+  * [XFS] Prevent lockdep false positives when locking two inodes.
+  * [XFS] Fix use-after-free with buffers
+  * [XFS] Don't do I/O beyond eof when unreserving space
+  * powerpc: Holly board needs dtbImage target
+  * Fix compile failure with non modular builds
+  * [ARM] 5249/1: davinci: remove redundant check in davinci_psc_config()
+  * [ARM] omap: back out 'internal_clock' support
+  * sctp: set the skb->ip_summed correctly when sending over loopback.
+  * [ARM] 5255/1: Update jornada ssp to remove build errors/warnings
+  * sctp: do not enable peer features if we can't do them.
+  * sctp: Fix oops when INIT-ACK indicates that peer doesn't support AUTH
+  * bnx2: Promote vector field in bnx2_irq structure from u16 to unsigned
+    int
+  * forcedeth: call restore mac addr in nv_shutdown path
+  * e1000: prevent corruption of EEPROM/NVM
+  * e100: Use pci_pme_active to clear PME_Status and disable PME#
+  * md: Don't wait UNINTERRUPTIBLE for other resync to finish
+  * atstk1000: fix build breakage with BOARD_ATSTK100X_SW2_CUSTOM=y
+  * avr32: add .gitignore files
+  * avr32: add generic_find_next_le_bit bit function
+  * avr32: fix sys_sync_file_range() call convention
+  * avr32: nmi_enter() without nmi_exit()
+  * KVM: ia64: 'struct fdesc' build fix
+  * hwmon: (atxp1) Fix device detection logic
+  * hwmon: (it87) Fix fan tachometer reading in IT8712F rev 0x7 (I)
+  * hwmon: (ad7414) Make ad7414_update_device() static
+  * tmio_mmc: fix compilation with debug enabled
+  * atmel-mci: debugfs: enable clock before dumping regs
+  * atmel-mci: Fix memory leak in atmci_regs_show
+  * atmel-mci: Fix bogus debugfs file size
+  * atmel-mci: Set MMC_CAP_NEEDS_POLL if no detect_pin
+  * mmc_block: handle error from mmc_register_driver()
+  * mmc_test: initialize mmc_test_lock statically
+  * [MIPS] Fix 64-bit IP checksum code
+  * [MIPS] SMTC: Clear TIF_FPUBOUND on clone / fork.
+  * [MIPS] Fix potential latency problem due to non-atomic cpu_wait.
+  * [MIPS] vmlinux.lds.S: handle .text.*
+  * MAINTAINERS: Trivial whitespace cleanups
+  * MAINTAINERS: Various fixes
+  * Linux 2.6.27-rc7
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sun, 21 Sep 2008 21:49:28 -0600
+
+linux (2.6.27-3.4) intrepid; urgency=low
+
+  [ Colin Ian King ]
+
+  * SAUCE: fix kernel oops in VirtualBox during paravirt patching
+    - LP: #246067
+  * SAUCE: qc-usb: Enable Logitech QuickCam Messenger
+    - LP: #209901
+  * SAUCE: appleir: Enable driver for new MacBook Pro
+    - LP: #157919
+
+  [ Tim Gardner ]
+
+  * Enabled CONFIG_DEBUG_RODATA=y
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "ALSA: hda - Added model selection for iMac 24""
+  * Revert "x86: fix HPET regression in 2.6.26 versus 2.6.25, check hpet
+    against BAR, v3"
+  * Revert "[ARM] use the new byteorder headers"
+  * Revert "mac80211: Use IWEVASSOCREQIE instead of IWEVCUSTOM"
+  * Revert "crypto: camellia - Use kernel-provided bitops, unaligned access
+    helpers"
+  * svcrdma: Fix race between svc_rdma_recvfrom thread and the dto_tasklet
+  * sched, cpuset: rework sched domains and CPU hotplug handling (v4)
+  * ACPI: Fix now signed module parameter.
+  * ACPI: Change package length error to warning
+  * ACPI: Fix now signed module parameter.
+  * ACPI: Fix typo in "Disable MWAIT via DMI on broken Compal board"
+  * acpi: add checking for NULL early param
+  * UBIFS: fix zero-length truncations
+  * Input: bcm5974 - add maintainer entry
+  * sh64: re-add the __strnlen_user() prototype
+  * sh: fix ptrace_64.c:user_disable_single_step()
+  * PNPACPI: ignore the producer/consumer bit for extended IRQ descriptors
+  * UBIFS: always read hashed-key nodes under TNC mutex
+  * UBIFS: allow for racing between GC and TNC
+  * [CIFS] Fix plaintext authentication
+  * sparc32: Implement smp_call_function_single().
+  * sh: crash kernel resource fix
+  * sh: fix kexec entry point for crash kernels
+  * sh: fix platform_resource_setup_memory() section mismatch
+  * sh: update Migo-R defconfig
+  * sh: update AP325RXA defconfig
+  * sh: fix semtimedop syscall
+  * cifs: fix O_APPEND on directio mounts
+  * [CIFS] update cifs change log
+  * [CIFS] Turn off Unicode during session establishment for plaintext
+    authentication
+  * ACPI: thinkpad-acpi: wan radio control is not experimental
+  * sparc: Fix resource flags for PCI children in OF device tree.
+  * remove blk_register_filter and blk_unregister_filter in gendisk
+  * ALSA: oxygen: fix distorted output on AK4396-based cards
+  * ipv6: When we droped a packet, we should return NET_RX_DROP instead of
+    0
+  * pkt_sched: Fix locking of qdisc_root with qdisc_root_sleeping_lock()
+  * net: Unbreak userspace usage of linux/mroute.h
+  * Don't trigger softlockup detector on network fs blocked tasks
+  * Resource handling: add 'insert_resource_expand_to_fit()' function
+  * sparc64: setup_valid_addr_bitmap_from_pavail() should be __init
+  * UBIFS: do not update min_idx_lebs in stafs
+  * UBIFS: push empty flash hack down
+  * UBIFS: remove incorrect index space check
+  * UBIFS: improve statfs reporting
+  * UBIFS: fix assertion
+  * UBIFS: add forgotten gc_idx_lebs component
+  * UBIFS: introduce LEB overhead
+  * UBIFS: improve statfs reporting even more
+  * UBIFS: fill f_fsid
+  * drm/radeon: downgrade debug message from info to debug.
+  * Remove invalidate_partition call from do_md_stop.
+  * Fix problem with waiting while holding rcu read lock in md/bitmap.c
+  * ALSA: hda: Distortion fix for dell_m6_core_init
+  * ALSA: ASoC: fix pxa2xx-i2s clk_get call
+  * block: restore original behavior of /proc/partition when there's no
+    partition
+  * debugobjects: fix lockdep warning
+  * avr32: Fix lockup after Java stack underflow in user mode
+  * avr32: pm_standby low-power ram bug fix
+  * nfsd: fix compound state allocation error handling
+  * sunrpc: fix possible overrun on read of /proc/sys/sunrpc/transports
+  * nfsd: fix buffer overrun decoding NFSv4 acl
+  * audit: Moved variable declaration to beginning of function
+  * Fix modules_install on RO nfs-exported trees.
+  * Remove '#include <stddef.h>' from mm/page_isolation.c
+  * dabusb_fpga_download(): fix a memory leak
+  * [MTD] mtdchar.c: Fix regression in MEMGETREGIONINFO ioctl()
+  * ALSA: hda - Fix ALC663 auto-probe
+  * ALSA: hda - Add mic-boost controls to ALC662/663 auto configuration
+  * Un-break printk strings in x86 PCI probing code
+  * kernel/resource.c: fix new kernel-doc warning
+  * softlockup: minor cleanup, don't check task->state twice
+  * fix typo in arch/parisc/hpux/fs.c
+  * m68k: atari_keyb_init operator precedence fix
+  * ACPI: Fix typo in "Disable MWAIT via DMI on broken Compal board"
+  * don't diff generated firmware files
+  * IDE: compile fix for sff_dma_ops
+  * IDE: palm_bk3710: fix compile warning for unused variable
+  * ide: fix hwif_to_node()
+  * palm_bk3710: improve IDE registration
+  * ide-disk: remove stale init_idedisk_capacity() documentation
+  * ide/Kconfig: mark ide-scsi as deprecated
+  * net/wireless/Kconfig: clarify the description for
+    CONFIG_WIRELESS_EXT_SYSFS
+  * iwlwifi: do not use GFP_DMA in iwl_tx_queue_init
+  * iwlwifi: workaround interrupt handling no some platforms
+  * iwlwifi: fix apm_stop (wrong bit polarity for FLAG_INIT_DONE)
+  * iwlwifi: fix 64bit platform firmware loading
+  * orinoco: Multicast to the specified addresses
+  * wireless/libertas/if_cs.c: fix memory leaks
+  * mac80211: Fix debugfs union misuse and pointer corruption
+  * rt2x00: Compiler warning unmasked by fix of BUILD_BUG_ON
+  * ath9k: Incorrect key used when group and pairwise ciphers are
+    different.
+  * ath9: Fix ath_rx_flush_tid() for IRQs disabled kernel warning message.
+  * net/xfrm: Use an IS_ERR test rather than a NULL test
+  * ipv: Re-enable IP when MTU > 68
+  * NTFS: update homepage
+  * mm: make setup_zone_migrate_reserve() aware of overlapping nodes
+  * VFS: fix dio write returning EIO when try_to_release_page fails
+  * acer-wmi: remove debugfs entries upon unloading
+  * mm/bootmem: silence section mismatch warning -
+    contig_page_data/bootmem_node_data
+  * MAINTAINERS: add a maintainer for the BCM5974 multitouch driver
+  * 8250: improve workaround for UARTs that don't re-assert THRE correctly
+  * mmc: at91_mci: don't use coherent dma buffers
+  * pid_ns: zap_pid_ns_processes: fix the ->child_reaper changing
+  * pid_ns: (BUG 11391) change ->child_reaper when init->group_leader exits
+  * cirrusfb: check_par fixes
+  * devcgroup: fix race against rmdir()
+  * mm: show quicklist usage in /proc/meminfo
+  * mm: size of quicklists shouldn't be proportional to the number of CPUs
+  * ipc: document the new auto_msgmni proc file
+  * hp-wmi: update to match current rfkill semantics
+  * hp-wmi: add proper hotkey support
+  * tdfxfb: fix SDRAM memory size detection
+  * tdfxfb: fix frame buffer name overrun
+  * rtc_time_to_tm: fix signed/unsigned arithmetic
+  * ibft: fix target info parsing in ibft module
+  * sysfs: document files in /sys/firmware/sgi_uv/
+  * rtc-cmos: wake again from S5
+  * pm_qos_requirement might sleep
+  * drivers/char/random.c: fix a race which can lead to a bogus BUG()
+  * ipsec: Fix deadlock in xfrm_state management.
+  * [x86] Fix TSC calibration issues
+  * tipc: Don't use structure names which easily globally conflict.
+  * sparc64: Fix IPI call locking.
+  * [ARM] omap: fix gpio.c build error
+  * sparc64: Prevent sparc64 from invoking irq handlers on offline CPUs
+  * powerpc: Fix uninitialised variable in VSX alignment code
+  * powerpc: Only make kernel text pages of linear mapping executable
+  * powerpc: Make sure _etext is after all kernel text
+  * powerpc: Work around gcc's -fno-omit-frame-pointer bug
+  * powerpc: Fix build error with 64K pages and !hugetlbfs
+  * powerpc: Fix for getting CPU number in power_save_ppc32_restore()
+  * UBIFS: amend f_fsid
+  * net/usb/pegasus: avoid hundreds of diagnostics
+  * ixgbe: initialize interrupt throttle rate
+  * pcnet-cs, axnet_cs: add new IDs, remove dup ID with less info
+  * netxen: Remove workaround for chipset quirk
+  * Split up PIT part of TSC calibration from native_calibrate_tsc
+  * iwlwifi: W/A for the TSF correction in IBSS
+  * iwlwifi: fix hidden ssid discovery in passive channels
+  * iwlwifi: remove false rxon if rx chain changes
+  * iwlwifi: fix station mimo power save values
+  * iwlwifi: fix rx_chain computation
+  * iwlwifi: fix Tx cmd memory allocation failure handling
+  * iwlwifi: call apm stop on exit
+  * iwlwifi: fix STATUS_EXIT_PENDING is not set on pci_remove
+  * ath9k: Fix TX status reporting
+  * ath9k: Fix TX control flag use for no ACK and RTS/CTS
+  * V4L/DVB (8555): au8522: add mechanism to configure IF frequency for vsb
+    and qam
+  * V4L/DVB (8556): au0828: add support for Hauppauge Woodbury
+  * V4L/DVB (8598): au8522: clean up function au8522_set_if
+  * V4L/DVB (8599): au8522: remove if frequency settings from vsb/qam
+    modulation tables
+  * V4L/DVB (8600): au0828: explicitly set 6 MHz IF frequency in
+    hauppauge_hvr950q_config
+  * V4L/DVB (8629): v4l2-ioctl: do not try to handle private V4L1 ioctls
+  * V4L/DVB (8633): ivtv: update ivtv version number
+  * V4L/DVB (8648): ivtv: improve CC support
+  * V4L/DVB (8660): gspca: Simplify the scan of URB packets in pac7311.
+  * V4L/DVB (8661): gspca: Bug in the previous changeset about pac7311.
+  * V4L/DVB (8663): gspca: Webcam 0c45:6128 added in sonixj.
+  * V4L/DVB (8664): gspca: The bridge/sensor of the webcam 093a:2621 is a
+    PAC 7302.
+  * V4L/DVB (8665): gspca: Fix the 640x480 resolution of the webcam
+    093a:2621.
+  * V4L/DVB (8666): gspca: Bad scanning of frames in pac7311.
+  * V4L/DVB (8667): gspca: Bad probe of Z-Star/Vimicro webcams with pas106
+    sensor.
+  * V4L/DVB (8668): gspca: Conflict GSPCA / ET61X251 for the webcam
+    102c:6251.
+  * V4L/DVB (8669): gspca: Add white balance control for spca561 rev 012A.
+  * V4L/DVB (8671): gspca: Remove the unused field 'dev_name' of the device
+    structure.
+  * V4L/DVB (8672): gspca: Big rewrite of spca561.
+  * V4L/DVB (8673): gspca: Bad frame scanning again and bad init in
+    pac7311.
+  * V4L/DVB (8674): gspca: Webcam 0c45:612e added in sonixj.
+  * V4L/DVB (8675): gspca: Pixmap PJPG (Pixart 73xx JPEG) added, generated
+    by pac7311.
+  * V4L/DVB (8678): Remove the dead CONFIG_RADIO_MIROPCM20{,_RDS} code
+  * V4L/DVB (8681): v4l2-ioctl.c: fix warning
+  * V4L/DVB (8682): V4L: fix return value of register video func
+  * V4L/DVB (8701): cx18: Add missing lock for when the irq handler
+    manipulates the queues
+  * V4L/DVB (8703): gspca: Do controls work for spca561 revision 12a.
+  * V4L/DVB (8705): gspca: Adjust some control limits in spca561.
+  * V4L/DVB (8706): Make contrast and brightness work for pac7302.
+  * V4L/DVB (8707): gspca: Colors, hflip and vflip controls added for
+    pac7302.
+  * V4L/DVB (8709): gspca: Fix initialization and controls of sn9x110 -
+    ov7630.
+  * V4L/DVB (8710): gspca: Bad color control in sonixj.
+  * V4L/DVB (8711): gspca: Bad controls and quantization table of pac7311.
+  * V4L/DVB (8712): gspca: Bad start of sonixj webcams since changeset
+    a8779025e7e8.
+  * V4L/DVB (8713): gspca: Bad color control again in sonixj.
+  * V4L/DVB (8714): gspca: Bad start of sn9c110 and sensor om6802.
+  * V4L/DVB (8715): gspca: Change the name of some webcam in the gspca doc.
+  * V4L/DVB (8716): gspca: Bad start of sn9c110 and sensor ov7630.
+  * V4L/DVB (8717): gspca: Frame buffer too small for small resolutions
+    (sonixj and t613).
+  * V4L/DVB (8718): gspca: suspend/resume added.
+  * V4L/DVB (8719): gspca: Have VIDIOC_QUERYCTRL more compliant to the
+    spec.
+  * V4L/DVB (8720): gspca: V4L2_CAP_SENSOR_UPSIDE_DOWN added as a cap for
+    some webcams.
+  * V4L/DVB (8722): sms1xxx: fix typo in license header
+  * V4L/DVB (8726): link tuner before saa7134
+  * V4L/DVB (8727): V4L1: make PMS not autoprobe when builtin.
+  * V4L/DVB (8728): 1-make-pms-not-autoprobe-when-builtin update
+  * V4L/DVB (8749): Fix error code, when camera is not turned on by sonypi
+  * V4L/DVB (8750): V4L: check inval in video_register_device_index()
+  * V4L/DVB (8751): vivi: Fix some issues at vivi register routine
+  * V4L/DVB (8757): v4l-dvb: fix a bunch of sparse warnings
+  * V4L/DVB (8769): cx18: Simplify queue flush logic to prevent oops in
+    cx18_flush_queues()
+  * V4L/DVB (8778): radio: fix incorrect video_register_device result check
+  * V4L/DVB (8779): v4l: fix more incorrect video_register_device result
+    checks
+  * V4L/DVB (8790): saa7115: call i2c_set_clientdata only when state !=
+    NULL
+  * V4L/DVB (8803): s5h1409: Enable QAM_AUTO mode
+  * V4L/DVB (8804): s5h1411: Enable QAM_AUTO mode
+  * V4L/DVB (8805): Steven Toth email address change
+  * V4L/DVB (8809): gspca: Revert commit
+    9a9335776548d01525141c6e8f0c12e86bbde982
+  * V4L/DVB (8810): gspca: Compile error when CONFIG_PM not defined.
+  * V4L/DVB (8812): gspca: Do pac73xx webcams work.
+  * V4L/DVB (8813): gspca: Adjust SOF detection for pac73xx.
+  * V4L/DVB (8814): gspca: Set DISABLED the disabled controls at query
+    control time.
+  * V4L/DVB (8815): gspca: Fix problems with disabled controls.
+  * V4L/DVB (8816): gspca: Set disabled ctrls and fix a register pb with
+    ovxxxx in sonixb.
+  * V4L/DVB (8817): gspca: LED and proble changes in sonixb.
+  * V4L/DVB (8818): gspca: Reinitialize the device on resume.
+  * V4L/DVB (8819): gspca: Initialize the ov519 at open time and source
+    cleanup.
+  * V4L/DVB (8820): gspca: Change initialization and gamma of zc3xx -
+    pas106.
+  * V4L/DVB (8822): gspca: Change some subdriver functions for
+    suspend/resume.
+  * V4L/DVB (8823): gspca: H and V flips work for ov7670 only in ov519.
+  * V4L/DVB (8824): gspca: Too much code removed in the suspend/resume
+    changeset.
+  * V4L/DVB (8825): gspca: More controls for pac73xx and new webcam
+    093a:2624.
+  * V4L/DVB (8826): gspca: Webcam Labtec 2200 (093a:2626) added in pac7311.
+  * V4L/DVB (8827): gspca: Stop pac7302 autogain oscillation.
+  * V4L/DVB (8828): gspca: Set the clock at the end of initialization in
+    sonixj.
+  * V4L/DVB (8829): gspca: Have a clean kmalloc-ated buffer for USB
+    exchanges.
+  * V4L/DVB (8830): gspca: Move some probe code to the new init function.
+  * V4L/DVB (8831): gspca: Resolve webcam conflicts between some drivers.
+  * V4L/DVB (8832): gspca: Bad pixelformat of vc0321 webcams.
+  * V4L/DVB (8833): gspca: Cleanup the sonixb code.
+  * V4L/DVB (8834): gspca: Have a bigger buffer for sn9c10x compressed
+    images.
+  * V4L/DVB (8835): gspca: Same pixfmt as the sn9c102 driver and raw Bayer
+    added in sonixb.
+  * V4L/DVB (8837): dvb: fix I2C adapters name size
+  * V4L/DVB (8839): dib0700: add comment to identify 35th USB id pair
+  * V4L/DVB (8840): dib0700: add basic support for Hauppauge Nova-TD-500
+    (84xxx)
+  * V4L/DVB (8842): vivi_release(): fix use-after-free
+  * V4L/DVB (8843): tda10048_firmware_upload(): fix a memory leak
+  * V4L/DVB (8844): dabusb_fpga_download(): fix a memory leak
+  * bnx2x: Accessing un-mapped page
+  * SELinux: memory leak in security_context_to_sid_core
+  * x86: add io delay quirk for Presario F700
+  * mmap: fix petty bug in anonymous shared mmap offset handling
+  * x86: Change warning message in TSC calibration.
+  * PCI: fix pbus_size_mem() resource alignment for CardBus controllers
+  * [ARM] omap: fix build error in ohci-omap.c
+  * [ARM] remove unused #include <version.h>
+  * ACPI: Make Len Brown the ACPI maintainer again
+  * fujitsu-laptop: fix regression for P8010 in 2.6.27-rc
+  * ACPI: Avoid bogus timeout about SMbus check
+  * acer-wmi: remove debugfs entries upon unloading
+  * forgotten refcount on sysctl root table
+  * V4L/DVB (8868): gspca: Support for vga modes with sif sensors in
+    sonixb.
+  * V4L/DVB (8869): gspca: Move the Sonix webcams with TAS5110C1B from
+    sn9c102 to gspca.
+  * V4L/DVB (8870): gspca: Fix dark room problem with sonixb.
+  * V4L/DVB (8872): gspca: Bad image format and offset with rev072a of
+    spca561.
+  * V4L/DVB (8873): gspca: Bad image offset with rev012a of spca561 and
+    adjust exposure.
+  * V4L/DVB (8874): gspca: Adjust hstart for sn9c103/ov7630 and update
+    usb-id's.
+  * [ARM] omap: fix virtual vs physical address space confusions
+  * V4L/DVB (8876): budget: udelay changed to mdelay
+  * V4L/DVB (8877): b2c2 and bt8xx: udelay to mdelay
+  * V4L/DVB (8880): PATCH: Fix parents on some webcam drivers
+  * V4L/DVB (8881): gspca: After 'while (retry--) {...}', retry will be -1
+    but not 0.
+  * powerpc/spufs: Fix multiple get_spu_context()
+  * powerpc/spufs: Fix race for a free SPU
+  * Input: bcm5974 - small formatting cleanup
+  * Input: bcm5974 - improve finger tracking and counting
+  * Input: bcm5974 - add BTN_TOUCH event for mousedev benefit
+  * Input: i8042 - make Lenovo 3000 N100 blacklist entry more specific
+  * sh: resume_kernel fix for kernel oops built with CONFIG_BKL_PREEMPT=y.
+  * sh64: resume_kernel fix for kernel oops built with
+    CONFIG_BKL_PREEMPT=y.
+  * i2c: fix i2c-sh_mobile timing issues
+  * clockevents: prevent clockevent event_handler ending up handler_noop
+  * clockevents: prevent endless loop in periodic broadcast handler
+  * clockevents: enforce reprogram in oneshot setup
+  * clockevents: prevent multiple init/shutdown
+  * clockevents: prevent endless loop lockup
+  * HPET: make minimum reprogramming delta useful
+  * [MTD] [NAND] tmio_nand: fix base address programming
+  * Fix conditional export of kvh.h and a.out.h to userspace.
+  * async_tx: fix the bug in async_tx_run_dependencies
+  * sched_clock: fix NOHZ interaction
+  * sched: fix process time monotonicity
+  * UBIFS: fix division by zero
+  * UBIFS: make minimum fanout 3
+  * [MIPS] Fix data bus error recovery
+  * [MIPS] Fix WARNING: at kernel/smp.c:290
+  * [MIPS] TXx9: Fix txx9_pcode initialization
+  * [MIPS] TX39xx: Add missing local_flush_icache_range initialization
+  * [MIPS] Probe initrd header only if explicitly specified
+  * res_counter: fix off-by-one bug in setting limit
+  * forcedeth: fix kexec regression
+  * atmel_lcdfb: fix oops in rmmod when framebuffer fails to register
+  * tracehook: comment pasto fixes
+  * drivers/mmc/card/block.c: fix refcount leak in mmc_block_open()
+  * x86: boot: stub out unimplemented CPU feature words
+  * x86: add NOPL as a synthetic CPU feature bit
+  * x86: use X86_FEATURE_NOPL in alternatives
+  * clockevents: broadcast fixup possible waiters
+  * x86: HPET fix moronic 32/64bit thinko
+  * x86: HPET: read back compare register before reading counter
+  * Fix CONFIG_AC97_BUS dependency
+  * [ARM] 5241/1: provide ioremap_wc()
+  * ntp: fix calculation of the next jiffie to trigger RTC sync
+  * clocksource, acpi_pm.c: use proper read function also in errata mode
+  * clocksource, acpi_pm.c: check for monotonicity
+  * x86: delay early cpu initialization until cpuid is done
+  * x86: move mtrr cpu cap setting early in early_init_xxxx
+  * sched: arch_reinit_sched_domains() must destroy domains to force
+    rebuild
+  * x86, xen: Use native_pte_flags instead of native_pte_val for .pte_flags
+  * x86: pda_init(): fix memory leak when using CPU hotplug
+  * x86: cpu_init(): fix memory leak when using CPU hotplug
+  * powerpc/spufs: Fix possible scheduling of a context to multiple SPEs
+  * netfilter: nf_conntrack_sip: de-static helper pointers
+  * netfilter: nf_conntrack_gre: more locking around keymap list
+  * netfilter: nf_conntrack_gre: nf_ct_gre_keymap_flush() fixlet
+  * netfilter: nf_conntrack_irc: make sure string is terminated before
+    calling simple_strtoul
+  * pkt_sched: Fix qdisc state in net_tx_action()
+  * powerpc: Fix rare boot build breakage
+  * ahci, pata_marvell: play nicely together
+  * sata_mv: add RocketRaid 1720 PCI ID to driver
+  * ahci: disable PMP for marvell ahcis
+  * sata_nv: disable hardreset for generic
+  * libata-sff: kill spurious WARN_ON() in ata_hsm_move()
+  * pata_sil680: remove duplicate pcim_enable_device
+  * ahci: RAID mode SATA patch for Intel Ibex Peak DeviceIDs
+  * [MIPS] IP22: Fix detection of second HPC3 on Challenge S
+  * xen: fix 2.6.27-rc5 xen balloon driver warnings
+  * x86: disable static NOPLs on 32 bits
+  * netns : fix kernel panic in timewait socket destruction
+  * bridge: don't allow setting hello time to zero
+  * NFS: Restore missing hunk in NFS mount option parser
+  * usb: fix null deferences in low level usb serial
+  * Fix format of MAINTAINERS
+  * sparc64: Disable timer interrupts in fixup_irqs().
+  * [Bluetooth] Fix reference counting during ACL config stage
+  * [Bluetooth] Enforce correct authentication requirements
+  * [Bluetooth] Reject L2CAP connections on an insecure ACL link
+  * [S390] CVE-2008-1514: prevent ptrace padding area read/write in 31-bit
+    mode
+  * [S390] cio: Correct cleanup on error.
+  * [S390] cio: handle ssch() return codes correctly.
+  * [S390] cio: allow offline processing for disconnected devices
+  * ipsec: Restore larval states and socket policies in dump
+  * update Documentation/filesystems/Locking for 2.6.27 changes
+  * MAINTAINERS: add Atheros maintainer for atlx
+  * lib: Correct printk %pF to work on all architectures
+  * x86: fix memmap=exactmap boot argument
+  * clockevents: remove WARN_ON which was used to gather information
+  * ipv6: Fix OOPS in ip6_dst_lookup_tail().
+  * Linux 2.6.27-rc6
+
+ -- Ben Collins <ben.collins@canonical.com>  Tue, 02 Sep 2008 12:45:56 -0400
+
+linux (2.6.27-2.3) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * build/retag: Make script save .orig of tags for later use
+  * ubuntu/lirc: Fix device_create call
+  * build/firmware: Put in-kernel firmware into version specific subdir
+    - LP: #262115
+  * Rebase on linux-2.6 git.
+  * ABI bump
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: (no-up) Apparmor warning fixes
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) Proper AppArmor ptrace updates for newer lsm API
+
+  [ Mackenzie Morgan ]
+
+  * SAUCE: Add quirk for ASUS Z37E to make sound audible after resume
+    - LP: #25896
+
+ -- Ben Collins <ben.collins@canonical.com>  Wed, 27 Aug 2008 14:03:05 -0400
+
+linux (2.6.27-1.2) intrepid; urgency=low
+
+  [ Amit Kucheria ]
+
+  * SAUCE: make fc transport removal of target configurable
+  * SAUCE: pm: Config option to disable handling of console during
+    suspend/resume
+
+  [ Ben Collins ]
+
+  * SAUCE: Lower warning level of some PCI messages
+  * SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps
+  * SAUCE: tulip: Let dmfe handle davicom on non-sparc
+  * SAUCE: tulip: Define ULI PCI ID's
+  * SAUCE: (no-up) version: Implement version_signature proc file.
+  * SAUCE: (no-up) connector.h: Add idx/val for drbd
+  * SAUCE: (no-up) swap: Add notify_swap_entry_free callback for compcache
+  * SAUCE: drivers: Remove some duplicate device entries in various modules
+  * SAUCE: (no-up) [AppArmor] merge with upstream subversion r1291
+  * SAUCE: apparmor: Update for changes to ptrace lsm hooks
+  * SAUCE: (no-up) Enable ubuntu extra subdirectory
+  * SAUCE: applesmc: Add MacBookAir
+  * SAUCE: (no-up) ACPI: initramfs DSDT override support
+  * ubuntu: Add drbd module
+  * ubuntu: Add iscsitarget module
+  * ubuntu: Add BOM for iscsitarget
+  * ubuntu: Add squashfs driver
+  * SAUCE: (no-up) Check for squashfs superblock in initramfs mounting.
+  * ubuntu: Add aufs module
+  * ubuntu: Added atl2 driver
+  * ubuntu: Added et131x driver
+  * ubuntu: Add dm-raid4-5 driver
+  * ubuntu: Add ndiswrapper driver
+  * ubuntu: Added ram backed compressed swap module (compcache)
+  * ubuntu: Add misc drivers from hardy lum
+  * ubuntu: Add heci driver 3.2.0.24
+  * ubuntu: Add ov511 and bt-sco drivers
+  * ubuntu: Add acx, prism2_usb wireless drivers
+  * ubuntu: Add at76 driver to build
+  * ubuntu: Add fsam7400 sw kill switch driver
+  * ubuntu: Added qc-usb driver
+  * ubuntu: e1000e: Upgraded module to 0.4.1.7
+  * ubuntu: Added rfkill drivers
+  * ubuntu: VIA - Add VIA DRM Chrome9 3D engine
+  * ubuntu: unionfs: Added v1.4 module from hardy
+  * ubuntu: Add LIRC driver
+  * ubuntu: Add GFS driver
+  * ubuntu: New tlsup driver for toshiba laptops
+  * Update config files
+  * build/d-i: Remove obsolete dm modules
+
+  [ Chuck Short ]
+
+  * SAUCE: ata: blacklist FUJITSU MHW2160BH PL
+
+  [ Colin Ian King ]
+
+  * ubuntu: Add dm-loop
+  * SAUCE: Enable speedstep for sonoma processors.
+
+  [ Dennis Noordsij ]
+
+  * SAUCE: Work around ACPI corruption upon suspend on some Dell machines.
+
+  [ Fabio M. Di Nitto ]
+
+  * SAUCE: Export gfs2 symbols required for gfs1 kernel module
+
+  [ Matthew Garrett ]
+
+  * SAUCE: hostap: send events on data interface as well as master
+    interface
+
+  [ Michael Frey (Senior Manager, MID ]
+
+  * SAUCE: Send HCI_RESET for Broadcomm 2046
+
+  [ Phillip Lougher ]
+
+  * SAUCE: r8169: disable TSO by default for RTL8111/8168B chipsets.
+
+  [ Stefan Bader ]
+
+  * SAUCE: (no-up) Export dm_disk function of device-mapper
+  * SAUCE: Restore VT fonts on switch
+  * SAUCE: mmc: Increase power_up deleay to fix TI readers
+
+  [ Tim Gardner ]
+
+  * SAUCE: Add extra headers to linux-libc-dev
+  * SAUCE: Catch nonsense keycodes and silently ignore
+  * SAUCE: Added support for HDAPS on various ThinkPads from Lenovo and IBM
+  * SAUCE: Guest OS does not recognize a lun with non zero target id on
+    Vmware ESX Server
+  * SAUCE: (no-up) Take care of orinoco_cs overlap with hostap_cs
+  * ubuntu: Add GNBD driver
+
+ -- Ben Collins <ben.collins@canonical.com>  Sat, 23 Aug 2008 15:48:35 -0400
+
+linux (2.6.27-0.0) intrepid; urgency=low
+
+  * Not uploaded, placeholder for new release
+
+ -- Ben Collins <ben.collins@canonical.com>  Sat, 23 Aug 2008 15:48:35 -0400
+
+linux (2.6.26-5.17) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * build/abi: Add tosh_smm symbol to blacklist
+
+ -- Ben Collins <ben.collins@canonical.com>  Fri, 15 Aug 2008 09:29:34 -0400
+
+linux (2.6.26-5.16) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * Revert "SAUCE: toshiba_acpi: Rewrote most of the proc entry bits."
+  * Revert "SAUCE: Update toshiba_acpi.c to version 0.19a"
+  * build/config: Disable in-kernel toshiba driver(s)
+  * ubuntu/tlsup: New driver for toshiba laptops
+  * build/config: Enable TLSUP driver
+  * SAUCE: e1000e: Fix E1000E_ENABLED logic to check for our E1000E_NEW
+    driver as well
+  * ubuntu/e1000e: Remove E1000E_ENABLED option in local config
+  * build/config: Update configs to have E1000E_ENABLED set
+  * ubuntu/prism2: Remove duplicate device
+
+  [ Fabio M. Di Nitto ]
+
+  * SAUCE: Export gfs2 symbols required for gfs1 kernel module
+
+  [ Stefan Bader ]
+
+  * SAUCE: x86: HPET rework for SB700
+    - LP: #255910
+
+  [ Tim Gardner ]
+
+  * Add GNBD driver
+  * Enable GNBD driver
+  * SAUCE: Add GFS driver
+  * SAUCE: Enable gfs driver configs
+  * b43: Linksys WMP54G (BCM4306/3) card in a PCI format has an SPROM
+    coding
+
+  [ Upstream Kernel Changes ]
+
+  * KVM: x86 emulator: emulate clflush
+  * USB: quirk PLL power down mode
+
+ -- Ben Collins <ben.collins@canonical.com>  Mon, 11 Aug 2008 13:19:28 -0400
+
+linux (2.6.26-5.15) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * Revert "SAUCE: Add blacklist support to fix Belkin bluetooth dongle."
+    - Superceded by upstream changes.
+  * build/config: New option enabled for uvcvideo
+  * build/control: Add Vcs-Git meta data to control file
+  * SAUCE: toshiba_acpi: Rewrote most of the new code
+  * abi/perm-blacklist: Add emu10k1 driver to blacklist
+
+  [ Upstream Kernel Changes ]
+
+  * pxamci: trivial fix of DMA alignment register bit clearing
+  * udplite: Protection against coverage value wrap-around
+  * ipv6: use timer pending
+  * ipv6: __KERNEL__ ifdef struct ipv6_devconf
+  * hdlcdrv: Fix CRC calculation.
+  * quota: fix possible infinite loop in quota code
+  * isofs: fix minor filesystem corruption
+  * KVM: VMX: Fix a wrong usage of vmcs_config
+  * KVM: SVM: fix suspend/resume support
+  * KVM: mmu_shrink: kvm_mmu_zap_page requires slots_lock to be held
+  * KVM: VMX: Add ept_sync_context in flush_tlb
+  * KVM: x86 emulator: Fix HLT instruction
+  * KVM: MMU: nuke shadowed pgtable pages and ptes on memslot destruction
+  * KVM: MMU: Fix potential race setting upper shadow ptes on nonpae hosts
+  * Patch Upstream: x86 ptrace: fix PTRACE_GETFPXREGS error
+  * rcu: fix rcu_try_flip_waitack_needed() to prevent grace-period stall
+  * Fix typos from signal_32/64.h merge
+  * x86 reboot quirks: add Dell Precision WorkStation T5400
+  * USB: fix usb serial pm counter decrement for disconnected interfaces
+  * x86, suspend, acpi: enter Big Real Mode
+  * markers: fix duplicate modpost entry
+  * Fix build on COMPAT platforms when CONFIG_EPOLL is disabled
+  * proc: fix /proc/*/pagemap some more
+  * cpusets: fix wrong domain attr updates
+  * x86: fix crash due to missing debugctlmsr on AMD K6-3
+  * ide-cd: fix oops when using growisofs
+  * rtc-at91rm9200: avoid spurious irqs
+  * vmlinux.lds: move __attribute__((__cold__)) functions back into final
+    .text section
+  * ARM: fix fls() for 64-bit arguments
+  * tcp: Clear probes_out more aggressively in tcp_ack().
+  * sparc64: Fix lockdep issues in LDC protocol layer.
+  * sparc64: Fix cpufreq notifier registry.
+  * sparc64: Do not define BIO_VMERGE_BOUNDARY.
+  * iop-adma: fix platform driver hotplug/coldplug
+  * myri10ge: do not forget to setup the single slice pointers
+  * myri10ge: do not use mgp->max_intr_slots before loading the firmware
+  * ALSA: trident - pause s/pdif output
+  * V4L: cx18: Upgrade to newer firmware & update documentation
+  * DVB: dib0700: add support for Hauppauge Nova-TD Stick 52009
+  * V4L: uvcvideo: Fix a buffer overflow in format descriptor parsing
+  * V4L: uvcvideo: Use GFP_NOIO when allocating memory during resume
+  * V4L: uvcvideo: Don't free URB buffers on suspend
+  * V4L: uvcvideo: Make input device support optional
+  * V4L: uvcvideo: Add support for Medion Akoya Mini E1210 integrated
+    webcam
+  * V4L: saa7134: Copy tuner data earlier to avoid overwriting manual tuner
+    type
+  * V4L: cx23885: Bugfix for concurrent use of /dev/video0 and /dev/video1
+  * DVB: cx23885: Ensure PAD_CTRL is always reset to a sensible default
+  * DVB: cx23885: DVB Transport cards using DVB port VIDB/TS1 did not
+    stream
+  * DVB: cx23885: Reallocated the sram to avoid concurrent VIDB/C issues
+  * DVB: cx23885: SRAM changes for the 885 and 887 silicon parts
+  * x86: fix kernel_physical_mapping_init() for large x86 systems
+  * eCryptfs: use page_alloc not kmalloc to get a page of memory
+  * UML - Fix boot crash
+  * ixgbe: remove device ID for unsupported device
+  * mpc52xx_psc_spi: fix block transfer
+  * tmpfs: fix kernel BUG in shmem_delete_inode
+  * markers: fix markers read barrier for multiple probes
+  * VFS: increase pseudo-filesystem block size to PAGE_SIZE
+  * cpufreq acpi: only call _PPC after cpufreq ACPI init funcs got called
+    already
+  * b43legacy: Release mutex in error handling code
+  * ath5k: don't enable MSI, we cannot handle it yet
+  * Fix off-by-one error in iov_iter_advance()
+  * Linux 2.6.26.1
+  * ftrace: remove unneeded documentation
+  * romfs_readpage: don't report errors for pages beyond i_size
+  * netfilter: nf_nat_sip: c= is optional for session
+  * SCSI: bsg: fix bsg_mutex hang with device removal
+  * x86: idle process - add checking for NULL early param
+  * x86: io delay - add checking for NULL early param
+  * Close race in md_probe
+  * Kprobe smoke test lockdep warning
+  * netfilter: xt_time: fix time's time_mt()'s use of do_div()
+  * linear: correct disk numbering error check
+  * SCSI: ch: fix ch_remove oops
+  * NFS: Ensure we zap only the access and acl caches when setting new acls
+  * jbd: fix race between free buffer and commit transaction
+  * Input: i8042 - add Intel D845PESV to nopnp list
+  * Input: i8042 - add Gericom Bellagio to nomux blacklist
+  * Input: i8042 - add Acer Aspire 1360 to nomux blacklist
+  * Bluetooth: Signal user-space for HIDP and BNEP socket errors
+  * Add compat handler for PTRACE_GETSIGINFO
+  * ALSA: hda - Fix wrong volumes in AD1988 auto-probe mode
+  * ALSA: hda - Fix DMA position inaccuracy
+  * ALSA: hda - Add missing Thinkpad Z60m support
+  * ALSA: emu10k1 - Fix inverted Analog/Digital mixer switch on Audigy2
+  * vfs: fix lookup on deleted directory
+  * Ath5k: fix memory corruption
+  * Ath5k: kill tasklets on shutdown
+  * sound: ensure device number is valid in snd_seq_oss_synth_make_info
+  * Linux 2.6.26.2
+
+ -- Ben Collins <ben.collins@canonical.com>  Sun, 03 Aug 2008 13:25:02 -0400
+
+linux (2.6.26-5.14) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * SAUCE: applesmc: Add MacBookAir
+  * build: Do not build ddeb unless we are on the buildd
+  * build: control: Consistency in arch fields.
+  * SAUCE: Update toshiba_acpi.c to version 0.19a
+    - LP: #77026
+  * build: Added perm blacklist support and per-module support to abi-check
+    - Blacklist p80211 module from abi checks
+  * ubuntu/lirc: Get rid of drivers symlink and use real include stuff
+
+
+  [ Colin Ian King ]
+
+  * SAUCE: acerhk module - add support for Amilo A1650g keyboard
+    - LP: #84159
+  * SAUCE: rt2x00: Fix OOPS on failed creation of rt2x00lib workqueue
+    - LP: #249242
+
+  [ Mario Limonciello ]
+
+  * Add LIRC back in
+
+  [ Tim Gardner ]
+
+  * Makefile race condition can lead to ndiswrapper build failure
+    - LP: #241547
+  * update linux-wlan-ng (prism2_usb) to upstream version 1861
+    - LP: #245026
+
+  [ Upstream Kernel Changes ]
+
+  * Fix typos from signal_32/64.h merge
+
+ -- Ben Collins <ben.collins@canonical.com>  Fri, 01 Aug 2008 00:05:01 -0400
+
+linux (2.6.26-5.13) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * build: Make makedumpfile an amd64/i386 only build-dep
+  * ubuntu/acerhk: Fixup assembly to compile with newer binutils
+
+ -- Ben Collins <ben.collins@canonical.com>  Sat, 26 Jul 2008 16:41:50 -0400
+
+linux (2.6.26-4.12) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * e1000e: Upgraded module to 0.4.1.7 upstream. Placed in ubuntu/,
+    in-kernel driver disabled
+  * config: Disable e1000e in-kernel, and enable newer driver in ubuntu/
+  * rfkill: Update to 1.3 drivers, and move to common location
+  * ubuntu: Actually link kconfig/kbuild into rfkill subdir
+  * config: Enable loading dsdt from initramfs
+    - LP: #246222
+  * ubuntu: [compcache] Update to fix crashes in improper BUG()
+  * build: Create a retag scripts to recover tags from rebases
+  * build: Updates for dbg pkg
+  * build: Make sure no empty lines show up in debian/files
+  * ubuntu: atl1e: Add new driver from 2.6.27-pre-rc1
+    - LP: #243894
+  * sys_getcwd: Fix some brokeness introduced by AppArmor __d_path
+    changes
+    - LP: #251223
+  * ubuntu: unionfs: Added v1.4 module from hardy
+  * build: Add sub-flavour infrastructure, and virtual subflav
+
+  [ Eric Piel ]
+
+  * ACPI: Allow custom DSDT tables to be loaded from initramfs
+
+  [ Kees Cook ]
+
+  * AppArmor: Smack VFS patches
+
+  [ Mario Limonciello ]
+
+  * Work around ACPI corruption upon suspend on some Dell machines.
+    - LP: #183033
+
+  [ Tim Gardner ]
+
+  * Export usbhid_modify_dquirk for LBM module bcm5974
+    - LP: #250838
+  * VIA - Add VIA DRM Chrome9 3D engine
+    - LP: #251862
+  * Define TRUE/FALSE for VIA DRM driver.
+
+ -- Ben Collins <ben.collins@canonical.com>  Tue, 15 Jul 2008 12:51:39 -0400
+
+linux (2.6.26-4.11) intrepid; urgency=low
+
+  [ Ben Collins ]
+
+  * config: Enable bcm5974 driver in all configs
+
+  [ 2.6.26-4.10 ]
+
+  [ Amit Kucheria ]
+
+  * Fix typo in GSPCA Makefile and make it compile
+
+  [ Ben Collins ]
+
+  * ubuntu: Remove UVC driver in favor of in-kernel one (-rc9)
+  * config: Updates for -rc9
+  * ubuntu: Add acx, prism2_usb wireless drivers
+  * config: Enable prism2_usb and acx drivers.
+  * ubuntu: Add at76 driver to build
+  * config: Enable at76_usb driver.
+  * iscsitarget: Fix prototype for bi_end_io callback.
+  * acx: Fix section type mismatch warnings
+  * fsam7400: Add sw kill switch driver
+  * config: Enable fsam7400 driver
+  * qc-usb: Added new driver
+  * config: Enable qc-usb driver
+  * drbd: Remove built-in connector usage
+  * drbd: Do not define idx/val for connector here
+  * connector.h: Add idx/val for drbd
+  * bcm5974: Added new driver
+
+  [ Kees Cook ]
+
+  * SAUCE: [AppArmor] merge with upstream subversion r1291
+  * SAUCE: [AppArmor] fix typo in selinux_inode_link
+  * SAUCE: [AppArmor] aufs patches
+
+  [ Michael Frey (Senior Manager, MID ]
+
+  * SAUCE: Send HCI_RESET for Broadcomm 2046
+    - LP: #241749
+
+  [ Tim Gardner ]
+
+  * SAUCE: Medion Akoya Mini E1210
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "BAST: Remove old IDE driver"
+  * ARM: OMAP: DMA: Don't mark channel active in omap_enable_channel_irq
+  * ARM: OMAP: Correcting the gpmc prefetch control register address
+  * debugobjects: fix lockdep warning
+  * [ARM] 5115/1: pxafb: fix ifdef for command line option handling
+  * [ARM] 5116/1: pxafb: cleanup and fix order of failure handling
+  * [ARM] 5109/1: Mark rtc sa1100 driver as wakeup source before
+    registering it
+  * [ARM] Export dma_sync_sg_for_device()
+  * fix cgroup-inflicted breakage in block_dev.c
+  * [patch for 2.6.26 2/4] vfs: utimensat(): be consistent with utime() for
+    immutable and append-only files
+  * [patch for 2.6.26 1/4] vfs: utimensat(): ignore tv_sec if tv_nsec ==
+    UTIME_OMIT or UTIME_NOW
+  * [patch for 2.6.26 3/4] vfs: utimensat(): fix error checking for
+    {UTIME_NOW,UTIME_OMIT} case
+  * [patch for 2.6.26 4/4] vfs: utimensat(): fix write access check for
+    futimens()
+  * [patch 1/4] vfs: path_{get,put}() cleanups
+  * [patch 2/4] fs: make struct file arg to d_path const
+  * [patch 3/4] vfs: fix ERR_PTR abuse in generic_readlink
+  * [patch 4/4] flock: remove unused fields from file_lock_operations
+  * [patch 3/3] vfs: make d_path() consistent across mount operations
+  * [patch 1/3] vfs: dcache sparse fixes
+  * [patch 2/3] vfs: dcache cleanups
+  * udf: Fix regression in UDF anchor block detection
+  * [SCSI] ses: Fix timeout
+  * netfilter: ip6table_mangle: don't reroute in LOCAL_IN
+  * [SCSI] esp: Fix OOPS in esp_reset_cleanup().
+  * kernel/audit.c: nlh->nlmsg_type is gotten more than once
+  * audit: fix kernel-doc parameter notation
+  * remove useless argument type in audit_filter_user()
+  * Blackfin arch: fix bug - kernel boot fails when Spinlock and rw-lock
+    debugging enabled
+  * Blackfin arch: fix up section mismatch warning
+  * mac80211: implement EU regulatory domain
+  * b43: Do not return TX_BUSY from op_tx
+  * b43legacy: Do not return TX_BUSY from op_tx
+  * b43: Fix possible MMIO access while device is down
+  * b43legacy: Fix possible NULL pointer dereference in DMA code
+  * rt2x00: Fix unbalanced mutex locking
+  * iwlwifi: improve scanning band selection management
+  * [SCSI] esp: tidy up target reference counting
+  * [ARM] 5117/1: pxafb: fix __devinit/exit annotations
+  * thermal: Create CONFIG_THERMAL_HWMON=n
+  * ACPI: don't walk tables if ACPI was disabled
+  * dock: bay: Don't call acpi_walk_namespace() when ACPI is disabled.
+  * x86: shift bits the right way in native_read_tscp
+  * x86: section/warning fixes
+  * V4L/DVB (8004): Fix INPUT dependency at budget-ci
+  * V4L/DVB (8005): Fix OOPS if frontend is null
+  * V4L/DVB (8007): cx18/cx25840: the S-Video LUMA input can use all
+    In1-In8 inputs
+  * V4L/DVB (8008): cx18: remove duplicate audio and video input enums
+  * V4L/DVB (8010): em28xx: Properly register extensions for already
+    attached devices
+  * V4L/DVB (8011): em28xx: enable DVB for HVR-900
+  * V4L/DVB (8012): gl861: sleep a little to avoid I2C errors
+  * V4L/DVB (8013): gl861: remove useless identify_state
+  * V4L/DVB (8015): gl861: replace non critical msleep(0) with msleep(1) to
+    be on the safe side
+  * V4L/DVB (8017): Ensure em28xx extensions only get run against devs that
+    support them
+  * V4L/DVB (8018): Add em2860 chip ID
+  * V4L/DVB (8020): Fix callbacks functions of saa7134_empress
+  * V4L/DVB (8022): saa7134: fix race between opening and closing the
+    device
+  * V4L/DVB (8026): Avoids an OOPS if dev struct can't be successfully
+    recovered
+  * V4L/DVB (8027): saa7134: Avermedia A700: only s-video and composite
+    input are working
+  * V4L/DVB (8028): Improve error messages for tda1004x attach
+  * V4L/DVB (8029): Improve error message at tda1004x_attach
+  * V4L/DVB (8034): tda18271: fix IF notch frequency handling
+  * V4L/DVB (8035): tda18271: dont touch EB14 if rf_cal lookup is out of
+    range
+  * V4L/DVB (8036): tda18271: toggle rf agc speed mode on TDA18271HD/C2
+    only
+  * V4L/DVB (8037): tda18271: ensure that the thermometer is off during
+    channel configuration
+  * V4L/DVB (8039): pxa-camera: fix platform_get_irq() error handling.
+  * V4L/DVB (8040): soc-camera: remove soc_camera_host_class class
+  * V4L/DVB (8042): DVB-USB UMT-010 channel scan oops
+  * V4L/DVB (8043): au0828: add support for additional USB device id's
+  * V4L/DVB (8044): au8522: tuning optimizations
+  * V4L/DVB (8048): saa7134: Fix entries for Avermedia A16d and Avermedia
+    E506
+  * V4L/DVB (8061): cx18: only select tuner / frontend modules if
+    !DVB_FE_CUSTOMISE
+  * V4L/DVB (8063): cx18: Fix unintended auto configurations in
+    cx18-av-core
+  * V4L/DVB (8066): cx18: Fix audio mux input definitions for HVR-1600 Line
+    In 2 and FM radio
+  * V4L/DVB (8067): cx18: Fix firmware load for case when digital capture
+    happens first
+  * V4L/DVB (8068): cx18: Add I2C slave reset via GPIO upon initialization
+  * V4L/DVB (8069): cx18: Fix S-Video and Compsite inputs for the Yuan
+    MPC718 and enable card entry
+  * V4L/DVB (8071): tda10023: Fix possible kernel oops during
+    initialisation
+  * V4L/DVB (8073): av7110: Catch another type of ARM crash
+  * V4L/DVB (8074): av7110: OSD transfers should not be interrupted
+  * V4L/DVB (8075): stv0299: Uncorrected block count and bit error rate
+    fixed
+  * V4L/DVB (8092): videodev: simplify and fix standard enumeration
+  * V4L/DVB (8096): au8522: prevent false-positive lock status
+  * V4L/DVB (8097): xc5000: check device hardware state to determine if
+    firmware download is needed
+  * V4L/DVB (8100): V4L/vivi: fix possible memory leak in vivi_fillbuff
+  * V4L/DVB (8108): Fix open/close race in saa7134
+  * s2io: fix documentation about intr_type
+  * tc35815: Mark carrier-off before starting PHY
+  * tc35815: Fix receiver hangup on Rx FIFO overflow
+  * ixgbe: fix EEH recovery during reset on PPC
+  * igb: fix EEH recovery during reset on PPC
+  * e1000e: fix EEH recovery during reset on PPC
+  * pcnet_cs, axnet_cs: clear bogus interrupt before request_irq
+  * drivers/net/r6040.c: Eliminate double sizeof
+  * ipg: fix jumbo frame compilation
+  * ipg: use NULL, not zero, for pointers
+  * [netdrvr] 3c59x: remove irqs_disabled warning from local_bh_enable
+  * [netdrvr] netxen: fix netxen_pci_tbl[] breakage
+  * e100: Do pci_dma_sync after skb_alloc for proper operation on ixp4xx
+  * e1000: only enable TSO6 via ethtool when using correct hardware
+  * [netdrvr] Fix IOMMU overflow checking in s2io.c
+  * qla3xxx: Hold RTNL while calling dev_close()
+  * Hold RTNL while calling dev_close()
+  * sata_uli: hardreset is broken
+  * rt2x00: Fix lock dependency errror
+  * prism: islpci_eth.c endianness fix
+  * mac80211: fix an oops in several failure paths in key allocation
+  * firewire: fw-sbp2: fix parsing of logical unit directories
+  * kbuild: fix a.out.h export to userspace with O= build.
+  * Ensure interrupted recovery completed properly (v1 metadata plus
+    bitmap)
+  * Don't acknowlege that stripe-expand is complete until it really is.
+  * Fix error paths if md_probe fails.
+  * hamradio: remove unused variable
+  * tcp: calculate tcp_mem based on low memory instead of all memory
+  * tcp: fix for splice receive when used with software LRO
+  * af_unix: fix 'poll for write'/connected DGRAM sockets
+  * netdevice: Fix typo of dev_unicast_add() comment
+  * pkt_sched: ERR_PTR() ususally encodes an negative errno, not positive.
+  * pkt_sched: Remove CONFIG_NET_SCH_RR
+  * include/linux/netdevice.h: don't export MAX_HEADER to userspace
+  * tcp: /proc/net/tcp rto,ato values not scaled properly (v2)
+  * netlink: Fix some doc comments in net/netlink/attr.c
+  * CONNECTOR: add a proc entry to list connectors
+  * inet fragments: fix race between inet_frag_find and
+    inet_frag_secret_rebuild
+  * net/inet_lro: remove setting skb->ip_summed when not LRO-able
+  * netlabel: Fix a problem when dumping the default IPv6 static labels
+  * ipv6 route: Convert rt6_device_match() to use RT6_LOOKUP_F_xxx flags.
+  * sched: fix cpu hotplug
+  * Fix and clean top .gitignore
+  * x86: fix cpu hotplug crash
+  * ptrace GET/SET FPXREGS broken
+  * Input: add KEY_MEDIA_REPEAT definition
+  * Input: fix locking in force-feedback core
+  * [ARM] 5131/1: Annotate platform_secondary_init with trace_hardirqs_off
+  * ide: fix /proc/ide/ide?/mate reporting
+  * netfilter: nf_conntrack_tcp: fixing to check the lower bound of valid
+    ACK
+  * textsearch: fix Boyer-Moore text search bug
+  * hostap: don't report useless WDS frames by default
+  * hostap: fix sparse warnings
+  * mac80211: don't accept WEP keys other than WEP40 and WEP104
+  * V4L/DVB (8145a): USB Video Class driver
+  * [IA64] Bugfix for system with 32 cpus
+  * [IA64] export account_system_vtime
+  * sched: fix divide error when trying to configure rt_period to zero
+  * x86: fix NODES_SHIFT Kconfig range
+  * block: Fix the starving writes bug in the anticipatory IO scheduler
+  * Properly notify block layer of sync writes
+  * rcu: fix hotplug vs rcu race
+  * I2C: S3C2410: Check ACK on byte transmission
+  * I2C: S3C2410: Fixup error codes returned rom a transfer.
+  * I2C: S3C2410: Add MODULE_ALIAS() for s3c2440 device.
+  * PCI: Restrict VPD read permission to root
+  * powerpc/bootwrapper: update for initrd with simpleImage
+  * i2c: Documentation: fix device matching description
+  * i2c: Fix bad hint about irqs in i2c.h
+  * powerpc/legacy_serial: Bail if reg-offset/shift properties are present
+  * powerpc/mpc5200: Fix lite5200b suspend/resume
+  * ipv4: fix sysctl documentation of time related values
+  * net-sched: change tcf_destroy_chain() to clear start of filter list
+  * net-sched: fix filter destruction in atm/hfsc qdisc destruction
+  * netlink: Unneeded local variable
+  * net: Tyop of sk_filter() comment
+  * netdevice: Fix wrong string handle in kernel command line parsing
+  * net: fib_rules: fix error code for unsupported families
+  * dm crypt: use cond_resched
+  * V4L/DVB (8178): uvc: Fix compilation breakage for the other drivers, if
+    uvc is selected
+  * PCI: Limit VPD read/write lengths for Broadcom 5706, 5708, 5709 rev.
+  * PCI: acpiphp: cleanup notify handler on all root bridges
+  * drivers/input/ff-core.c needs <linux/sched.h>
+  * DRM/i915: only use tiled blits on 965+
+  * tty: Fix inverted logic in send_break
+  * x86: fix Intel Mac booting with EFI
+  * arch/x86/mm/init_64.c: early_memtest(): fix types
+  * 9p: fix O_APPEND in legacy mode
+  * slub: Do not use 192 byte sized cache if minimum alignment is 128 byte
+  * Do not overwrite nr_zones on !NUMA when initialising zlcache_ptr
+  * [MIPS] IP32: Fix unexpected irq 71
+  * [MIPS] IP22: Fix crashes due to wrong L1_CACHE_BYTES
+  * [MIPS] cevt-txx9: Reset timer counter on initialization
+  * hrtimer: prevent migration for raising softirq
+  * svcrpc: fix handling of garbage args
+  * OHCI: Fix problem if SM501 and another platform driver is selected
+  * USB: fix cdc-acm resume()
+  * USB: ehci - fix timer regression
+  * USB: ohci - record data toggle after unlink
+  * USB: mass storage: new id for US_SC_CYP_ATACB
+  * sisusbvga: Fix oops on disconnect.
+  * USB: New device ID for ftdi_sio driver
+  * USB: fix interrupt disabling for HCDs with shared interrupt handlers
+  * USB: don't lose disconnections during suspend
+  * USB: another option device id
+  * USB: add a pl2303 device id
+  * USB: fix Oops on loading ipaq module since 2.6.26
+  * USB: adding comment for ipaq forcing number of ports
+  * [MIPS] Fix bug in atomic_sub_if_positive.
+  * xen: fix address truncation in pte mfn<->pfn conversion
+  * sata_sil24: add DID for another adaptec flavor
+  * ahci: always clear all bits in irq_stat
+  * libata-sff: improve HSM violation reporting
+  * sata_mv: safer logic for limit_warnings
+  * Update maintainers for powerpc
+  * Christoph has moved
+  * mm: dirty page accounting vs VM_MIXEDMAP
+  * rtc: rtc_read_alarm() handles wraparound
+  * firmware: fix the request_firmware() dummy
+  * serial: fix serial_match_port() for dynamic major tty-device numbers
+  * get_user_pages(): fix possible page leak on oom
+  * rtc-x1205: Fix alarm set
+  * rtc: fix CMOS time error after writing /proc/acpi/alarm
+  * pci: VT3336 can't do MSI either
+  * Miguel Ojeda has moved
+  * ext3: add missing unlock to error path in ext3_quota_write()
+  * ext4: add missing unlock to an error path in ext4_quota_write()
+  * reiserfs: add missing unlock to an error path in reiserfs_quota_write()
+  * ecryptfs: remove unnecessary mux from ecryptfs_init_ecryptfs_miscdev()
+  * lib: taint kernel in common report_bug() WARN path.
+  * gpio: pca953x (i2c) handles max7310 too
+  * fsl_diu_fb: fix build with CONFIG_PM=y, plus fix some warnings
+  * Update taskstats-struct document for scaled time accounting
+  * cciss: fix regression that no device nodes are created if no logical
+    drives are configured.
+  * delay accounting: maintainer update
+  * Doc*/kernel-parameters.txt: fix stale references
+  * hdaps: add support for various newer Lenovo thinkpads
+  * mn10300: export certain arch symbols required to build allmodconfig
+  * mn10300: provide __ucmpdi2() for MN10300
+  * Introduce rculist.h
+  * man-pages is supported
+  * ntfs: update help text
+  * add kernel-doc for simple_read_from_buffer and memory_read_from_buffer
+  * w100fb: do not depend on SHARPSL
+  * w100fb: add 80 MHz modeline
+  * MFD maintainer
+  * cgroups: document the effect of attaching PID 0 to a cgroup
+  * spi: fix the read path in spidev
+  * doc: doc maintainers
+  * security: filesystem capabilities: fix fragile setuid fixup code
+  * security: filesystem capabilities: fix CAP_SETPCAP handling
+  * Alpha Linux kernel fails with inconsistent kallsyms data
+  * cpusets: document proc status cpus and mems allowed lists
+  * MAINTAINERS: update the email address of Andreas Dilger
+  * cciss: read config to obtain max outstanding commands per controller
+  * olpc: sdhci: add quirk for the Marvell CaFe's vdd/powerup issue
+  * olpc: sdhci: add quirk for the Marvell CaFe's interrupt timeout
+  * cpumask: introduce new APIs
+  * mm: switch node meminfo Active & Inactive pages to Kbytes
+  * Update MAINTAINERS file for the TPM device driver
+  * devcgroup: fix odd behaviour when writing 'a' to devices.allow
+  * doc: document the relax_domain_level kernel boot argument
+  * mmc: don't use DMA on newer ENE controllers
+  * mempolicy: mask off internal flags for userspace API
+  * x86 ACPI: normalize segment descriptor register on resume
+  * x86 ACPI: fix resume from suspend to RAM on uniprocessor x86-64
+  * softlockup: print a module list on being stuck
+  * ide: fix hwif->gendev refcounting
+  * ide: ide_unregister() warm-plug bugfix
+  * ide: ide_unregister() locking bugfix
+  * ahci: give another shot at clearing all bits in irq_stat
+  * Fix clear_refs_write() use of struct mm_walk
+  * Move _RET_IP_ and _THIS_IP_ to include/linux/kernel.h
+  * Fix pagemap_read() use of struct mm_walk
+  * Linux 2.6.26-rc9
+  * Revert "USB: don't explicitly reenable root-hub status interrupts"
+  * Revert "PCI: Correct last two HP entries in the bfsort whitelist"
+  * iwlwifi: fix incorrect 5GHz rates reported in monitor mode
+  * iwlwifi: drop skb silently for Tx request in monitor mode
+  * libertas: support USB persistence on suspend/resume (resend)
+  * tcp: net/ipv4/tcp.c needs linux/scatterlist.h
+  * tcp: fix a size_t < 0 comparison in tcp_read_sock
+  * bridge: fix use-after-free in br_cleanup_bridges()
+  * Add missing skb->dev assignment in Frame Relay RX code
+  * forcedeth: fix lockdep warning on ethtool -s
+  * ehea: fix might sleep problem
+  * ehea: add MODULE_DEVICE_TABLE
+  * ehea: fix race condition
+  * ehea: Access iph->tot_len with correct endianness
+  * pasemi_mac: Access iph->tot_len with correct endianness
+  * ibm_newemac: Fixes kernel crashes when speed of cable connected changes
+  * ibm_newemac: Fixes entry of short packets
+  * fs_enet: restore promiscuous and multicast settings in restart()
+  * can: add sanity checks
+  * x86: KVM guest: Add memory clobber to hypercalls
+  * KVM: IOAPIC: Fix level-triggered irq injection hang
+  * [SCSI] erase invalid data returned by device
+  * pxamci: fix byte aligned DMA transfers
+  * vsprintf: split out '%s' handling logic
+  * vsprintf: split out '%p' handling logic
+  * vsprintf: add infrastructure support for extended '%p' specifiers
+  * vsprintf: add support for '%pS' and '%pF' pointer formats
+  * powerpc: Fix unterminated of_device_id array in legacy_serial.c
+  * [UML] fix gcc ICEs and unresolved externs
+  * ocfs2/dlm: Fixes oops in dlm_new_lockres()
+  * hostap_cs: correct poor NULL checks in suspend/resume routines
+  * drivers/net/wireless/iwlwifi/iwl-3945.c Fix type issue on 64bit
+  * mac80211: move netif_carrier_on to after
+    ieee80211_bss_info_change_notify
+  * mac80211: Only flush workqueue when last interface was removed
+  * zd1211rw: add ID for AirTies WUS-201
+  * ssb-pcicore: Fix IRQ-vector init on embedded devices
+  * mac80211: don't report selected IBSS when not found
+  * crypto: tcrypt - Fix memory leak in test_cipher
+  * sctp: Mark the tsn as received after all allocations finish
+  * [S390] protect _PAGE_SPECIAL bit against mprotect
+  * irda: via-ircc proper dma freeing
+  * irda: New device ID for nsc-ircc
+  * irda: Fix netlink error path return value
+  * [SCSI] mptspi: fix oops in mptspi_dv_renegotiate_work()
+  * Correct hash flushing from huge_ptep_set_wrprotect()
+  * ide: add __ide_default_irq() inline helper
+  * palm_bk3710: fix IDECLK period calculation
+  * it8213: fix return value in it8213_init_one()
+  * [MIPS] Atlas, decstation: Fix section mismatches triggered by
+    defconfigs
+  * [MIPS] Fix 32bit kernels on R4k with 128 byte cache line size
+  * NFS: Fix readdir cache invalidation
+  * SUNRPC: Fix a double-free in rpcbind
+  * SUNRPC: Fix an rpcbind breakage for the case of IPv6 lookups
+  * reiserfs: discard prealloc in reiserfs_delete_inode
+  * Fix broken fix for fsl-diu-db
+  * RDMA/cxgb3: Fix regression caused by class_device -> device conversion
+  * ipv6: fix race between ipv6_del_addr and DAD timer
+  * sctp: Add documentation for sctp sysctl variable
+  * kernel/printk.c: Made printk_recursion_bug_msg static.
+  * powerpc: Add missing reference to coherent_dma_mask
+  * rc80211_pid: Fix fast_start parameter handling
+  * rt2x00: Disable synchronization during initialization
+  * zd1211rw: stop beacons on remove_interface
+  * libertas: fix memory alignment problems on the blackfin
+  * netfilter: nf_conntrack_tcp: fix endless loop
+  * netfilter: nf_nat_snmp_basic: fix a range check in NAT for SNMP
+  * md: ensure all blocks are uptodate or locked when syncing
+  * sched: fix cpu hotplug
+  * x86: fix /dev/mem compatibility under PAT
+  * crypto: chainiv - Invoke completion function
+  * ocfs2: Fix flags in ocfs2_file_lock
+  * kernel/kprobes.c: Made kprobe_blacklist static.
+  * arch/x86/kernel/.gitignore: Added vmlinux.lds to .gitignore file
+    because it shouldn't be tracked.
+  * ftrace: Documentation
+  * Fix PREEMPT_RCU without HOTPLUG_CPU
+  * sched: fix cpu hotplug, cleanup
+  * exec: fix stack excutability without PT_GNU_STACK
+  * slub: Fix use-after-preempt of per-CPU data structure
+  * Documentation: clarify tcp_{r,w}mem sysctl docs
+  * ip: sysctl documentation cleanup
+  * tcp: correct kcalloc usage
+  * ipv4: fib_trie: Fix lookup error return
+  * netlabel: netlink_unicast calls kfree_skb on error path by itself
+  * ipv6: missed namespace context in ipv6_rthdr_rcv
+  * xfrm: Add a XFRM_STATE_AF_UNSPEC flag to xfrm_usersa_info
+  * tun: Persistent devices can get stuck in xoff state
+  * tpm: add Intel TPM TIS device HID
+  * rapidio: fix device reference counting
+  * Fix name of Russell King in various comments
+  * rtc: fix reported IRQ rate for when HPET is enabled
+  * libata-acpi: filter out DIPM enable
+  * Added Targa Visionary 1000 IDE adapter to pata_sis.c
+  * libata-acpi: don't call sleeping function from invalid context
+  * Fix reference counting race on log buffers
+  * [SCSI] ipr: Fix HDIO_GET_IDENTITY oops for SATA devices
+  * IPMI: return correct value from ipmi_write
+  * x86: fix ldt limit for 64 bit
+  * [SCSI] fusion: default MSI to disabled for SPI and FC controllers
+  * [SCSI] bsg: fix oops on remove
+  * drivers/char/pcmcia/ipwireless/hardware.c fix resource leak
+  * drivers/isdn/i4l/isdn_common.c fix small resource leak
+  * fbdev: bugfix for multiprocess defio
+  * serial8250: sanity check nr_uarts on all paths.
+  * ov7670: clean up ov7670_read semantics
+  * rtc-fm3130: fix chip naming
+  * rtc-pcf8563: add chip id
+  * OProfile kernel maintainership changes
+  * frv: fix irqs_disabled() to return an int, not an unsigned long
+  * cifs: fix inode leak in cifs_get_inode_info_unix
+  * cifs: fix wksidarr declaration to be big-endian friendly
+  * cpusets, hotplug, scheduler: fix scheduler domain breakage
+  * Documentation/HOWTO: correct wrong kernel bugzilla FAQ URL
+  * devcgroup: always show positive major/minor num
+  * devcgroup: fix permission check when adding entry to child cgroup
+  * Linux 2.6.26
+
+ -- Ben Collins <ben.collins@canonical.com>  Mon, 14 Jul 2008 13:41:50 -0400
+
+linux (2.6.26-3.9) intrepid; urgency=low
+
+  * abi: Add dca and ioatdma to modules.ignore
+
+  [ 2.6.26-3.8 ]
+
+  [ Ben Collins ]
+
+  * ubuntu: Add heci driver 3.2.0.24
+  * ubuntu: Add heci to kconfig/kbuild
+  * config: Enable heci module on all flavours
+  * dm-bbr: Update to get it to compile with 2.6.26
+  * config: Enable dm-bbr
+  * ubuntu: Add some media drivers
+  * config: Enable misc media drivers
+  * udeb: Switch to uvesafb in fb-modules
+  * abi: Add more modules to ignore (known)
+
+  [ 2.6.26-3.7 ]
+
+  [Amit Kucheria]
+
+  * SAUCE: make fc transport removal of target configurable
+     - LP: #163075
+  * SAUCE: pm: Config option to disable handling of console during
+    suspend/resume
+
+  [Ben Collins]
+
+  * SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps
+  * SAUCE: irda: Default to dongle type 9 on IBM hardware
+  * SAUCE: tulip: Let dmfe handle davicom on non-sparc
+  * SAUCE: tulip: Define ULI PCI ID's
+  * SAUCE: version: Implement version_signature proc file.
+  * build: Cleanup arches
+  * build: Remove remnants of unused binary-custom infrastructure
+  * build: Remove disable_d_i (not needed) and cleanup ppa build stuff
+  * ubuntu: New modules, acer-acpi
+  * build: Remove -virtual, and rebuild configs
+  * ubuntu: Add drbd module
+  * acer-acpi: Fix makefile
+  * x86/Kconfig: Fix missing quote for ubuntu Kconfig source
+  * ubuntu: Add iscsitarget module
+  * ubuntu: Added Amiga FS driver
+  * ubuntu: Add squashfs driver
+  * ubuntu: Remove asfs (Amiga FS). Need to be in linux-ports instead
+  * squashfs: Move headers to real include directory
+  * build/configs: The Great Config Consistency Check of 2008
+  * ubuntu: Move third-party includes to ubuntu/include
+  * ubuntu: Add aufs module
+  * ubuntu: Added atl2 driver
+  * ubuntu: Add dm-radi4-5 driver
+  * build: Add CONFIG_DEBUG_SECTION_MISMATCH=y to get old style warnings
+    from build
+  * ubuntu/Makefile: Fixup dm-raid4-5 and add kludge for kbuild
+  * squashfs: Fixes for VFS changes
+  * ubuntu/dm-raid4-5: Fixups for moved/renamed headers/functions in core
+    md
+  * ubuntu: Add ndiswrapper driver
+  * d-i: Update module listings
+  * build: Disable xd block device (ancient)
+  * ndiswrapper: Fixup makefile
+  * d-i: Remove efi-modules. The only module, efivars, is built-in
+  * build: Remove install-source, obsolete and caused build failure
+  * Ubuntu-2.6.26-1.3
+  * build: linux-doc rules got broken when disabling html side. Fixed now.
+  * Ubuntu-2.6.26-1.4
+  * x86: Update to -rc6 allows CONFIG_PCI_OLPC to work with PCI_GOANY
+  * d-i: Make virtio-ring optional (it's built-in on i386)
+  * Ubuntu-2.6.26-1.4
+  * Ubuntu-2.6.26-1.5
+  * config: Enable DVB devices
+  * ubuntu/aufs: Make aufs a bool config, since it needs to be built-in
+  * config: Build aufs into the kernels
+  * build: Fix arguments passed to link-headers script
+  * config: Disable early printk
+  * d-i: Move isofs to storage-core and kill st (scsi tape) from list
+  * config: Enable non-promiscuous access to /dev/mem
+  * x86: Add option to disable decompression info messages
+  * config: Enable no-bz-chatter config options
+  * build: Re-add linux-source package
+  * d-i: Re-add socket-modules. Accidentally removed
+    - LP: #241295
+  * Ubuntu-2.6.26-2.6
+  * Use makedumpfile to generate a vmcoreinfo file.
+  * build: Build-Depend on makedumpfile for vmcoreinfo generation
+  * build: Remove debug print from git-ubuntu-log
+  * Updated configs for -rc7
+  * build: postinst, do not call depmod with -F
+  * config: Enable rtc-cmos as a built-in driver.
+  * control: Provide ndiswrapper-modules-1.9
+  * build: Generate vmcoreinfo in image build for crashdumps without debug
+    image
+  * config: Disable vesafb, since we'll prefer uvesafb
+  * build: Copy uvesafb module to initrd mod directory
+  * abi-check: New, more robust script
+  * config: Enable heap randomization by default
+  * abi-check: Cleanup output and call with perl (not $SHELL)
+  * abi: Ignore missing vesafb (known)
+  * config: Disable pcspkr (in favor of snd-pcsp)
+  * swap: Add notify_swap_entry_free callback for compcache
+  * compcache: Added ram backed compressed swap module
+  * ubuntu: Enable kbuild and kconfig for compcache
+  * config: Enable compcache and tlsf allocator as modules
+  * config: Updated for -rc8. Disables XEN on i386
+  * config: Switch i386-server to 64G, enable PAE, 64-bit res, and XEN
+  * ubuntu: Add misc drivers from hardy lum
+  * ubuntu: Enable build of misc/ subdir
+  * config: Enable misc drivers
+  * aufs: Fix warning about single non-string-literal arg to printf style
+    function
+  * drivers: Remove some duplicate device entries in various modules
+  * config: Disable some duplicate drivers
+  * keyspan: Remove duplicate device ID's
+  * check-aliases: Cleanup output, and fix rolling checks
+  * ubuntu: Disable dm-bbr for now
+  * dm-bbr: First cut at forward portiong. Still needs work.
+  * ubuntu: Disable dm-bbr in kbuild/kconfig
+
+  [Chuck Short]
+
+  * SAUCE: ata: blacklist FUJITSU MHW2160BH PL
+     - LP: #175834
+  * SAUCE: [USB]: add ASUS LCM to the blacklist
+
+  [Colin Ian King]
+
+  * SAUCE: airprime.c supports more devices
+    - LP: #208250
+  * SAUCE: Enable speedstep for sonoma processors. 
+     - LP: #132271
+  * Add dm-loop
+  * Add dm-loop BOM
+
+  [Kyle McMartin]
+
+  * SAUCE: fix orinoco_cs oops
+
+  [Mario Limonciello]
+
+  * SAUCE: Enable Reset and SCO workaround on Dell 410 BT adapter
+
+  [Matthew Garrett]
+
+  * SAUCE: hostap: send events on data interface as well as master
+    interface
+
+  [Phillip Lougher]
+
+  * SAUCE: r8169: disable TSO by default for RTL8111/8168B chipsets.
+
+  [Stefan Bader]
+
+  * SAUCE: Export dm_disk function of device-mapper
+  * SAUCE: Restore VT fonts on switch
+  * SAUCE: Always use SCO protocol (disable eSCO support) Bug: #39414
+  * SAUCE: mmc: Increase power_up deleay to fix TI readers OriginalAuthor:
+    Pascal Terjan <pterjan@mandriva.com> Bug: #137686
+  * SAUCE: Add blacklist support to fix Belkin bluetooth dongle. Bug:
+    #140511
+  * SAUCE: Lower warning level of pci resource allocation messages. Bug:
+    159241
+  * SAUCE: Lower message level for PCI memory and I/O allocation.
+    - LP: #159241
+  * Modify log generation to catch bug numbers when adding with git-am.
+
+  [Tim Gardner]
+
+  * Added the debian directory. Ignore: yes
+  * Add support for UBUNTUINCLUDE Ignore: yes
+  * LUM headers go in /usr/src Ignore: yes
+  * First pass at 2.6.25 configs Ignore: yes
+  * i386 -generic builds. Ignore: yes
+  * SAUCE: Increase CONFIG_IDE_MAX_HWIFS to 8 (from 4)
+  * SAUCE: Add extra headers to linux-libc-dev OriginalAuthor: Soren Hansen
+    OriginalLocation:
+    https://lists.ubuntu.com/archives/kernel-team/2007-November/001891.html
+  * Set CONFIG_DEVKMEM=n Ignore: yes
+  * Enabled ALSA and CGROUPS for i386 Ignore: yes
+  * Enabled amd64 configs. Ignore: yes
+  * CONFIG_STANDALONE=n Ignore: yes
+  * CONFIG_BLK_DEV_4DRIVES=n for i386 Ignore: yes
+  * CONFIG: CONFIG_DEFAULT_RELATIME=y for all flavours. Ignore: yes
+  * Set CONFIG_EDD_OFF=y Ignore: yes
+  * SAUCE: Blacklist Bluetooth Dell Wireless 370 for SCO MTU
+    OriginalAuthor: Mario Limonciello <Mario_Limonciello@Dell.com> Bug:
+    #209715
+  * SAUCE: Catch nonsense keycodes and silently ignore
+  * SAUCE: frame buffer regression - screen blank except for blinking
+    cursor after fbcon vtswitch OriginalAuthor: Matthew Garrett
+    <mjg59@srcf.ucam.org> Bug: #201591
+  * SAUCE: Added support for HDAPS on various ThinkPads from Lenovo and IBM
+    OriginalAuthor: Klaus S. Madsen <ubuntu@hjernemadsen.org>
+    OriginalAuthor: Chuck Short <zulcss@ubuntu.com>
+  * SAUCE: Guest OS does not recognize a lun with non zero target id on
+    Vmware ESX Server
+  * SAUCE: orinoco_cs.ko missing
+  * Set CONFIG_FB_VESA=m for i386/amd64 Ignore: yes
+  * Set CONFIG_PM_DISABLE_CONSOLE=y for all flavours Ignore: yes
+  * Thorough review of amd64 -generic config Ignore: yes
+  * Build PPA packages for Hardy until the Intrepid archive is opened.
+  * Deleted obsolete flavours Ignore: yes
+  * Don't build docs for PPA Ignore: yes
+  * Build all standard packages in PPA. Ignore: yes
+  * Remove duplicate USB ids
+  * SAUCE: DVB-USB UMT-010 driver oops on install Bug: #115284
+  * Update configs after rebase to 2.6.26-rc1 Ignore: yes
+  * Update configs after rebase Ignore: yes
+  * Disable V4L until the build issues get ironed out. Ignore: yes
+  * Update configs after rebase. Ignore: yes
+  * Another device enable pass Ignore: yes
+  * Update configs after merge. Ignore: yes
+  * SAUCE: fn key doesn't work in hardy with macbook pro fourth generation
+    (4,1)
+    - LP: #207127
+  * Enabled CONFIG_CIFS_DFS_UPCALL=y and CONFIG_CIFS_UPCALL=y
+    - LP: #236830
+
+  [Upstream Kernel Changes]
+
+  * Revert "[WATCHDOG] hpwdt: Add CFLAGS to get driver working"
+  * mac80211: detect driver tx bugs
+  * hwmon: (lm85) Fix function RANGE_TO_REG()
+  * hwmon: (adt7473) Initialize max_duty_at_overheat before use
+  * hwmon: Update the sysfs interface documentation
+  * hwmon: (abituguru3) Identify Abit AW8D board as such
+  * hwmon: (w83791d) new maintainer
+  * hwmon: (abituguru3) update driver detection
+  * hwmon: (lm75) sensor reading bugfix
+  * ipv6: Remove options header when setsockopt's optlen is 0
+  * ipv6: Drop packets for loopback address from outside of the box.
+  * sched: rt: dont stop the period timer when there are tasks wanting to
+    run
+  * sched: fix wait_for_completion_timeout() spurious failure under heavy
+    load
+  * x86: fix NULL pointer deref in __switch_to
+  * xen: Use wmb instead of rmb in xen_evtchn_do_upcall().
+  * xen: mask unwanted pte bits in __supported_pte_mask
+  * xen: don't drop NX bit
+  * sched: refactor wait_for_completion_timeout()
+  * Ext4: Fix online resize block group descriptor corruption
+  * [IA64] SN2: security hole in sn2_ptc_proc_write
+  * alpha: fix module load failures on smp (bug #10926)
+  * alpha: link failure fix
+  * alpha: fix compile failures with gcc-4.3 (bug #10438)
+  * alpha: resurrect Cypress IDE quirk
+  * pppoe: warning fix
+  * sctp: Make sure N * sizeof(union sctp_addr) does not overflow.
+  * netns: Don't receive new packets in a dead network namespace.
+  * Add return value to reserve_bootmem_node()
+  * Slab: Fix memory leak in fallback_alloc()
+  * Fix performance regression on lmbench select benchmark
+  * ALSA: aw2 - Fix Oops at initialization
+  * ALSA: sb - Fix wrong assertions
+  * futexes: fix fault handling in futex_lock_pi
+  * IB/mthca: Clear ICM pages before handing to FW
+  * tty_driver: Update required method documentation
+  * removed unused var real_tty on n_tty_ioctl()
+  * Fix ZERO_PAGE breakage with vmware
+  * mm: fix race in COW logic
+  * NFS: Reduce the NFS mount code stack usage.
+  * NFS: Fix filehandle size comparisons in the mount code
+  * NFS: nfs_updatepage(): don't mark page as dirty if an error occurred
+  * alpha: fix compile error in arch/alpha/mm/init.c
+  * KVM: Fix race between timer migration and vcpu migration
+  * KVM: close timer injection race window in __vcpu_run
+  * KVM: MMU: Fix rmap_write_protect() hugepage iteration bug
+  * KVM: MMU: large page update_pte issue with non-PAE 32-bit guests
+    (resend)
+  * KVM: MMU: Fix oops on guest userspace access to guest pagetable
+  * KVM: ioapic: fix lost interrupt when changing a device's irq
+  * KVM: VMX: Fix host msr corruption with preemption enabled
+  * [GFS2] BUG: unable to handle kernel paging request at ffff81002690e000
+  * xen: remove support for non-PAE 32-bit
+  * kgdb: documentation update - remove kgdboe
+  * kgdb: sparse fix
+  * [IA64] Fix boot failure on ia64/sn2
+  * [IA64] Handle count==0 in sn2_ptc_proc_write()
+  * [IA64] Eliminate NULL test after alloc_bootmem in iosapic_alloc_rte()
+  * [GFS2] fix gfs2 block allocation (cleaned up)
+  * x86: Add structs and functions for paravirt clocksource
+  * x86: Make xen use the paravirt clocksource structs and functions
+  * KVM: Make kvm host use the paravirt clocksource structs
+  * x86: KVM guest: Use the paravirt clocksource structs and functions
+  * KVM: Remove now unused structs from kvm_para.h
+  * enable bus mastering on i915 at resume time
+  * Linux 2.6.26-rc8
+  * # Ubuntu external driver commit.
+  * # Ubuntu commit template.
+
+ -- Ben Collins <ben.collins@canonical.com>  Sat, 21 Jun 2008 09:05:15 -0400
+
+linux (2.6.26-2.6) intrepid; urgency=low
+
+  [Ben Collins]
+
+  * Revert "SAUCE: Export symbols for aufs (in lum) (not needed)
+  * config: Enable DVB devices
+  * ubuntu/aufs: Make aufs a bool config, since it needs to be built-in
+  * config: Build aufs into the kernels
+  * build: Fix arguments passed to link-headers script
+  * config: Disable early printk
+  * d-i: Move isofs to storage-core and kill st (scsi tape) from list
+  * config: Enable non-promiscuous access to /dev/mem
+  * x86: Add option to disable decompression info messages
+  * config: Enable no-bz-chatter config options
+  * build: Re-add linux-source package
+  * d-i: Re-add socket-modules. Accidentally removed
+    - LP: #241295
+
+  [Colin Ian King]
+
+  * Add dm-loop
+
+  [Tim Gardner]
+
+  * Revert "SAUCE: USB bluetooth device 0x0e5e:0x6622 floods errors to
+    syslog (merged upstream)
+
+ -- Ben Collins <ben.collins@canonical.com>  Mon, 16 Jun 2008 10:56:01 -0400
+
+linux (2.6.26-1.5) intrepid; urgency=low
+
+  * d-i: Make virtio-ring optional (it's built-in on i386)
+  * Rebased on 2.6.26-rc6
+
+  [Ubuntu-2.6.26-1.4 Changes below]
+
+  * build: linux-doc rules got broken when disabling html side. Fixed now.
+
+  [Ubuntu-2.6.26-1.3 Changes below]
+
+  * build: Remove install-source, obsolete and caused build failure
+
+  [Ubuntu-2.6.26-1.2 Changes below]
+
+  * Remove efi-modules from d-i module list (efivars is built-in). Caused a
+    build failure.
+  * Patch to arch/x86/xen/time.c to remove __divdi3 usage (build failure on
+    i386).
+
+  [Ubuntu-2.6.26-1.1 Changes below]
+
+  [Amit Kucheria]
+
+  * SAUCE: make fc transport removal of target configurable
+  * SAUCE: Add AGP support for Radeon Mobility 9000 chipset
+  * SAUCE: pm: Config option to disable handling of console during
+    suspend/resume
+
+  [Ben Collins]
+
+  * SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps
+  * SAUCE: irda: Default to dongle type 9 on IBM hardware
+  * SAUCE: tulip: Let dmfe handle davicom on non-sparc
+  * SAUCE: tulip: Define ULI PCI ID's
+  * SAUCE: version: Implement version_signature proc file.
+  * build: Remove remnants of unused binary-custom infrastructure
+  * mmc_block: Fix bad allocation on 64-bit (zero len array)
+  * ubuntu: New modules, acer-acpi
+  * build: Remove -virtual, and rebuild configs
+  * ubuntu: Add drbd module
+  * ubuntu: Add iscsitarget module
+  * ubuntu: Add squashfs driver
+  * build/configs: The Great Config Consistency Check of 2008
+  * ubuntu: Add aufs module
+  * ubuntu: Added atl2 driver
+  * ubuntu: Add dm-radi4-5 driver
+  * build: Add CONFIG_DEBUG_SECTION_MISMATCH=y to get old style warnings
+    from build
+  * squashfs: Fixes for VFS changes
+  * ubuntu/dm-raid4-5: Fixups for moved/renamed headers/functions in core
+    md
+  * ubuntu: Add ndiswrapper driver
+  * d-i: Update module listings
+
+  [Chuck Short]
+
+  * SAUCE: ata: blacklist FUJITSU MHW2160BH PL
+  * SAUCE: [USB]: add ASUS LCM to the blacklist
+
+  [Colin Ian King]
+
+  * SAUCE: Enable speedstep for sonoma processors.
+  * SAUCE: airprime.c supports more devices
+
+  [Kyle McMartin]
+
+  * SAUCE: fix orinoco_cs oops
+
+  [Mario Limonciello]
+
+  * SAUCE: Enable Reset and SCO workaround on Dell 410 BT adapter
+
+  [Matthew Garrett]
+
+  * SAUCE: hostap: send events on data interface as well as master
+    interface
+
+  [Phillip Lougher]
+
+  * SAUCE: r8169: disable TSO by default for RTL8111/8168B chipsets.
+
+  [Stefan Bader]
+
+  * SAUCE: Export dm_disk function of device-mapper
+  * SAUCE: Restore VT fonts on switch
+  * SAUCE: Always use SCO protocol (disable eSCO support) Bug: #39414
+  * SAUCE: mmc: Increase power_up deleay to fix TI readers
+  * SAUCE: Add blacklist support to fix Belkin bluetooth dongle.
+  * SAUCE: Lower warning level of pci resource allocation messages.
+  * SAUCE: Lower message level for PCI memory and I/O allocation.
+    - LP: #159241
+  * Modify log generation to catch bug numbers when adding with git-am.
+
+  [Tim Gardner]
+
+  * SAUCE: hdaps module does not load on Thinkpad T61P
+  * SAUCE: Add extra headers to linux-libc-dev
+  * SAUCE: Export symbols for aufs (in lum).
+  * SAUCE: USB bluetooth device 0x0e5e:0x6622 floods errors to syslog
+  * SAUCE: Blacklist Bluetooth Dell Wireless 370 for SCO MTU
+  * SAUCE: Catch nonsense keycodes and silently ignore
+  * SAUCE: frame buffer regression - screen blank except for blinking
+    cursor after fbcon vtswitch
+  * SAUCE: Added support for HDAPS on various ThinkPads from Lenovo and IBM
+  * SAUCE: Guest OS does not recognize a lun with non zero target id on
+    Vmware ESX Server
+  * SAUCE: Modualrize vesafb
+  * SAUCE: DVB-USB UMT-010 driver oops on install
+  * SAUCE: fn key doesn't work in hardy with macbook pro fourth generation
+    (4,1)
+    - LP: #207127
+
+ -- Ben Collins <ben.collins@canonical.com>  Wed, 11 Jun 2008 05:28:35 -0400
--- linux-4.4.0.orig/debian.master/config/amd64/config.common.amd64
+++ linux-4.4.0/debian.master/config/amd64/config.common.amd64
@@ -0,0 +1,359 @@
+#
+# Config options for config.common.amd64 automatically generated by splitconfig.pl
+#
+CONFIG_6LOWPAN=m
+CONFIG_ABX500_CORE=y
+# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_AIX_PARTITION=y
+CONFIG_ALIM7101_WDT=m
+CONFIG_ALTERA_TSE=m
+CONFIG_AMIGA_PARTITION=y
+CONFIG_APPLICOM=m
+CONFIG_ARCNET=m
+CONFIG_ATALK=m
+CONFIG_ATARI_PARTITION=y
+CONFIG_ATA_GENERIC=y
+CONFIG_ATA_OVER_ETH=m
+CONFIG_ATA_PIIX=y
+CONFIG_ATM=m
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_AUXDISPLAY=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BATMAN_ADV=m
+CONFIG_BCMA=m
+CONFIG_BCM_KONA_USB2_PHY=m
+CONFIG_BE2ISCSI=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_NVME=m
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
+CONFIG_BLK_DEV_RSXX=m
+CONFIG_BLK_DEV_SKD=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BOUNCE=y
+CONFIG_BPF_JIT_ALWAYS_ON=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_C2PORT=m
+CONFIG_CADENCE_WATCHDOG=m
+CONFIG_CAIF=m
+CONFIG_CAN=m
+CONFIG_CB710_CORE=m
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CMA=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_CRAMFS=m
+CONFIG_DECNET=m
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_DMADEVICES=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DMA_VIRTUAL_CHANNELS=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DNET=m
+CONFIG_DRM=m
+CONFIG_DUMMY_IRQ=m
+CONFIG_DW_WATCHDOG=m
+CONFIG_ECHO=m
+CONFIG_EEPROM_93CX6=m
+CONFIG_EFS_FS=m
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_ETHOC=m
+CONFIG_EXOFS_FS=m
+CONFIG_EXTCON=y
+CONFIG_F2FS_FS=m
+CONFIG_FB=y
+CONFIG_FB_BOOT_VESA_SUPPORT=y
+CONFIG_FDDI=y
+CONFIG_FEALNX=m
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_NOSY=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIXED_PHY=y
+CONFIG_FMC=m
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
+CONFIG_GENERIC_PHY=y
+CONFIG_GPIO_GENERIC=m
+CONFIG_GPIO_GENERIC_PLATFORM=m
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_BOOTMEM_INFO_NODE=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HFSPLUS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HIO=m
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_HPET=y
+CONFIG_HPFS_FS=m
+CONFIG_HP_ILO=m
+CONFIG_HSI=m
+CONFIG_HSR=m
+CONFIG_HTC_PASIC3=m
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+# CONFIG_HZ_100 is not set
+CONFIG_I2C=y
+CONFIG_I6300ESB_WDT=m
+CONFIG_IEEE802154=m
+CONFIG_IIO=m
+CONFIG_INFINIBAND_NES=m
+CONFIG_INFINIBAND_OCRDMA=m
+CONFIG_INFINIBAND_QIB=m
+CONFIG_INPUT=y
+CONFIG_IPACK_BUS=m
+CONFIG_IPMI_HANDLER=m
+CONFIG_IPMI_SI_PROBE_DEFAULTS=y
+CONFIG_IPX=m
+# CONFIG_IP_DCCP_CCID3 is not set
+CONFIG_JFS_FS=m
+CONFIG_JME=m
+CONFIG_KARMA_PARTITION=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+CONFIG_KVM=m
+CONFIG_LAPB=m
+CONFIG_LDM_PARTITION=y
+CONFIG_LIBNVDIMM=y
+CONFIG_LLC2=m
+CONFIG_LPC_ICH=m
+CONFIG_LPC_SCH=m
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+CONFIG_MAILBOX=y
+CONFIG_MAX63XX_WATCHDOG=m
+CONFIG_MCB=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_SAS=m
+CONFIG_MEMORY=y
+CONFIG_MEMSTICK=m
+CONFIG_MFD_CORE=y
+CONFIG_MFD_JANZ_CMODIO=m
+CONFIG_MFD_KEMPLD=m
+CONFIG_MFD_MT6397=m
+CONFIG_MFD_RDC321X=m
+CONFIG_MFD_RTSX_PCI=m
+CONFIG_MFD_SM501=m
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_TI_AM335X_TSCADC=m
+CONFIG_MFD_VX855=m
+CONFIG_MII=m
+CONFIG_MINIX_FS=m
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=m
+CONFIG_MTD=m
+CONFIG_NCP_FS=m
+CONFIG_NET_CADENCE=y
+CONFIG_NET_PACKET_ENGINE=y
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CAVIUM=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_SYNOPSYS=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NEW_LEDS=y
+CONFIG_NFC=m
+CONFIG_NODES_SHIFT=6
+CONFIG_NOZOMI=m
+CONFIG_NR_CPUS=512
+CONFIG_NTB=m
+# CONFIG_NTFS_RW is not set
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
+# CONFIG_NUMA_EMU is not set
+CONFIG_NVMEM=m
+CONFIG_N_GSM=m
+# CONFIG_OF is not set
+CONFIG_OMFS_FS=m
+CONFIG_OSF_PARTITION=y
+CONFIG_PARPORT=m
+CONFIG_PATA_SIS=y
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_PCI_PASID=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_PCMCIA=m
+CONFIG_PGTABLE_MAPPING=y
+CONFIG_PHANTOM=m
+CONFIG_PHONET=m
+CONFIG_PHYLIB=y
+CONFIG_PHY_PXA_28NM_HSIC=m
+CONFIG_PHY_PXA_28NM_USB2=m
+CONFIG_PM_DEBUG=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_POWERCAP=y
+CONFIG_POWER_AVS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPP=y
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PPS_CLIENT_LDISC=m
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PROBE_EVENTS=y
+CONFIG_PSTORE=y
+CONFIG_PWM=y
+CONFIG_QNX4FS_FS=m
+CONFIG_QNX6FS_FS=m
+CONFIG_RAW_DRIVER=m
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_REGULATOR=y
+CONFIG_REISERFS_FS=m
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFKILL=y
+CONFIG_ROMFS_FS=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC94XX=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_DPT_I2O=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_MVSAS=m
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_SNIC=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_UFSHCD=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_DW=m
+# CONFIG_SERIAL_8250_FSL is not set
+CONFIG_SERIAL_ALTERA_JTAGUART=m
+CONFIG_SERIAL_ALTERA_UART=m
+CONFIG_SERIAL_ARC=m
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_FSL_LPUART=m
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_SCCNXP=y
+CONFIG_SERIO=y
+CONFIG_SFC=m
+CONFIG_SGI_IOC4=m
+CONFIG_SGI_PARTITION=y
+CONFIG_SLIP=m
+# CONFIG_SND_SOC_RT5677_SPI is not set
+CONFIG_SOC_TI=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_SOUND=m
+CONFIG_SPI=y
+CONFIG_SPMI=m
+CONFIG_SRAM=y
+CONFIG_SSB=m
+CONFIG_STAGING=y
+# CONFIG_STANDALONE is not set
+CONFIG_STE_MODEM_RPROC=m
+CONFIG_SUN_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_SYSV_FS=m
+CONFIG_THERMAL=y
+CONFIG_THUNDERBOLT=m
+CONFIG_TIFM_CORE=m
+CONFIG_TRACE_SINK=m
+CONFIG_TTY_PRINTK=y
+CONFIG_UFS_FS=m
+CONFIG_UIO=m
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_UPROBES=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_SUPPORT=y
+CONFIG_UWB=m
+CONFIG_VGASTATE=m
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VME_BUS=y
+CONFIG_VMXNET3=m
+CONFIG_VXFS_FS=m
+CONFIG_W1=m
+CONFIG_WAN=y
+CONFIG_WDTPCI=m
+CONFIG_WIMAX=m
+CONFIG_X25=m
+CONFIG_XILINX_WATCHDOG=m
+CONFIG_XILLYBUS=m
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_XZ_DEC_X86=y
+CONFIG_ZLIB_DEFLATE=y
--- linux-4.4.0.orig/debian.master/config/amd64/config.flavour.generic
+++ linux-4.4.0/debian.master/config/amd64/config.flavour.generic
@@ -0,0 +1,10 @@
+#
+# Config options for config.flavour.generic automatically generated by splitconfig.pl
+#
+CONFIG_HZ=250
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ_250=y
+# CONFIG_IRQ_FORCED_THREADING_DEFAULT is not set
+CONFIG_OPENNSL=y
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_VOLUNTARY=y
--- linux-4.4.0.orig/debian.master/config/amd64/config.flavour.lowlatency
+++ linux-4.4.0/debian.master/config/amd64/config.flavour.lowlatency
@@ -0,0 +1,10 @@
+#
+# Config options for config.flavour.lowlatency automatically generated by splitconfig.pl
+#
+CONFIG_HZ=1000
+CONFIG_HZ_1000=y
+# CONFIG_HZ_250 is not set
+CONFIG_IRQ_FORCED_THREADING_DEFAULT=y
+# CONFIG_OPENNSL is not set
+CONFIG_PREEMPT=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
--- linux-4.4.0.orig/debian.master/config/annotations
+++ linux-4.4.0/debian.master/config/annotations
@@ -0,0 +1,10657 @@
+# Menu: HEADER
+# FORMAT: 2
+# ARCH: x86 arm arm64 powerpc s390
+
+# Mark debugging symbols.
+#  exceptions
+CONFIG_DEBUG_FS                                 note<required debug option>
+CONFIG_DEBUG_KERNEL                             note<required debug option>
+
+# Menu: ROOT
+CONFIG_LIVEPATCH                                policy<{'amd64': 'y', 's390x': 'y'}>
+CONFIG_RELOCATABLE                              policy<{'amd64': 'y', 'i386': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+
+# Menu: ACPI (Advanced Configuration and Power Interface) Support
+CONFIG_ACPI                                     policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_DEBUGGER                            policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_PROCFS_POWER                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_REV_OVERRIDE_POSSIBLE               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_EC_DEBUGFS                          policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_AC                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_BATTERY                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_BUTTON                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_VIDEO                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_FAN                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_DOCK                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_PROCESSOR                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_IPMI                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_PROCESSOR_AGGREGATOR                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_THERMAL                             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_NUMA                                policy<{'amd64': 'y'}>
+CONFIG_ACPI_CUSTOM_DSDT_FILE                    policy<{'amd64': '""', 'i386': '""'}>
+CONFIG_ACPI_INITRD_TABLE_OVERRIDE               policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_PCI_SLOT                            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_X86_PM_TIMER                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_CONTAINER                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_HOTPLUG_MEMORY                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_SBS                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_HED                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_CUSTOM_METHOD                       policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_BGRT                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_REDUCED_HARDWARE_ONLY               policy<{'amd64': 'n', 'arm64': 'y', 'i386': 'n'}>
+CONFIG_ACPI_NFIT                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_NFIT_DEBUG                          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_EXTLOG                              policy<{'amd64': 'm', 'i386': 'm'}>
+#
+CONFIG_ACPI_PROCFS_POWER                        flag<DEPRECATED>
+CONFIG_ACPI_CUSTOM_METHOD                       mark<ENFORCED> note<SECURITY: allows arbitrary execution>
+CONFIG_ACPI_CUSTOM_DSDT_FILE                    note<might allow hardware damage>
+
+# Menu: ACPI (Advanced Configuration and Power Interface) Support >> ACPI Platform Error Interface (APEI)
+CONFIG_ACPI_APEI                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_APEI_GHES                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_APEI_PCIEAER                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_APEI_MEMORY_FAILURE                 policy<{'amd64': 'y'}>
+CONFIG_ACPI_APEI_EINJ                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_APEI_ERST_DEBUG                     policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: ACPI (Advanced Configuration and Power Interface) Support >> PMIC (Power Management Integrated Circuit) operation region support
+CONFIG_PMIC_OPREGION                            policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+
+# Menu: ARM Accelerated Cryptographic Algorithms >> Architecture: arm
+CONFIG_ARM_CRYPTO                               policy<{'armhf': 'y'}>
+CONFIG_CRYPTO_SHA1_ARM                          policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA1_ARM_NEON                     policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA1_ARM_CE                       policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA2_ARM_CE                       policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA256_ARM                        policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA512_ARM                        policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_AES_ARM                           policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_AES_ARM_BS                        policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_AES_ARM_CE                        policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_GHASH_ARM_CE                      policy<{'armhf': 'm'}>
+
+# Menu: ARM64 Accelerated Cryptographic Algorithms >> Architecture: arm64
+CONFIG_ARM64_CRYPTO                             policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_SHA1_ARM64_CE                     policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_SHA2_ARM64_CE                     policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_GHASH_ARM64_CE                    policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_CE                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_CE_CCM                  policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_CE_BLK                  policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK                policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_CRC32_ARM64                       policy<{'arm64': 'm'}>
+
+# Menu: Advanced setup >> Architecture: powerpc
+
+# Menu: Advanced setup >> Prompt for advanced kernel configuration options
+CONFIG_PHYSICAL_START                           policy<{'amd64': '0x1000000', 'i386': '0x1000000', 'powerpc': '0x00000000', 'ppc64el': '0x00000000'}>
+
+# Menu: Advanced setup >> Prompt for advanced kernel configuration options >> Architecture: powerpc
+CONFIG_ADVANCED_OPTIONS                         policy<{'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_LOWMEM_SIZE                              policy<{'powerpc-powerpc-e500mc': '0x30000000', 'powerpc-powerpc-smp': '0x30000000'}>
+CONFIG_LOWMEM_CAM_NUM                           policy<{'powerpc-powerpc-e500mc': '3'}>
+CONFIG_PAGE_OFFSET                              policy<{'armhf': '0xC0000000', 'i386': '0xC0000000', 'powerpc-powerpc-e500mc': '0xc0000000', 'powerpc-powerpc-smp': '0xc0000000', 'powerpc-powerpc64-emb': '0xc000000000000000', 'powerpc-powerpc64-smp': '0xc000000000000000', 'ppc64el': '0xc000000000000000'}>
+CONFIG_KERNEL_START                             policy<{'powerpc-powerpc-e500mc': '0xc0000000', 'powerpc-powerpc-smp': '0xc0000000', 'powerpc-powerpc64-emb': '0xc000000000000000', 'powerpc-powerpc64-smp': '0xc000000000000000', 'ppc64el': '0xc000000000000000'}>
+CONFIG_TASK_SIZE                                policy<{'powerpc-powerpc-e500mc': '0xc0000000', 'powerpc-powerpc-smp': '0xc0000000'}>
+
+# Menu: Architecture: arm
+CONFIG_ARM_DMA_IOMMU_ALIGNMENT                  policy<{'armhf': '8'}>
+CONFIG_ARM_PATCH_PHYS_VIRT                      policy<{'armhf': 'y'}>
+
+# Menu: Architecture: powerpc
+CONFIG_PPC64                                    policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'y'}>
+CONFIG_NR_IRQS                                  policy<{'powerpc': '512', 'ppc64el': '512'}>
+CONFIG_SCOM_DEBUGFS                             policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+
+# Menu: Architecture: x86
+CONFIG_64BIT                                    policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'n', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Boot options
+CONFIG_CMDLINE                                  policy<{'arm64': '"console=ttyAMA0"', 'armhf': '""'}>
+CONFIG_CMDLINE_FORCE                            policy<{'arm64': 'n'}>
+CONFIG_EFI                                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_DMI                                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_KEXEC                                    policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRASH_DUMP                               policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_CRASH_DUMP                               mark<ENFORCED> note<LP:1363180>
+
+# Menu: Boot options >> Architecture: arm
+CONFIG_USE_OF                                   policy<{'armhf': 'y'}>
+CONFIG_ATAGS                                    policy<{'armhf': 'y'}>
+CONFIG_DEPRECATED_PARAM_STRUCT                  policy<{'armhf': 'n'}>
+CONFIG_ZBOOT_ROM_TEXT                           policy<{'armhf': '0x0'}>
+CONFIG_ZBOOT_ROM_BSS                            policy<{'armhf': '0x0'}>
+CONFIG_ARM_APPENDED_DTB                         policy<{'armhf': 'y'}>
+CONFIG_ARM_ATAG_DTB_COMPAT                      policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_ATAGS_PROC                               policy<{'armhf': 'y'}>
+CONFIG_AUTO_ZRELADDR                            policy<{'armhf': 'y'}>
+#
+CONFIG_ARM_ATAG_DTB_COMPAT                      flag<REVIEW>
+
+# Menu: Boot options >> Architecture: arm64
+CONFIG_ARM64_ACPI_PARKING_PROTOCOL              policy<{'arm64': 'y'}>
+
+# Menu: Boot options >> Kernel command line type
+
+# Menu: Boot options >> Kernel command line type >> Architecture: arm
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER policy<{'armhf-generic': 'n'}>
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND       policy<{'armhf-generic': 'y'}>
+
+# Menu: Bus options (PCI etc.)
+CONFIG_ISA                                      policy<{'i386': 'y', 'powerpc-powerpc-smp': 'n'}>
+
+# Menu: Bus options (PCI etc.) >> Architecture: arm
+
+# Menu: Bus options (PCI etc.) >> Architecture: arm64
+
+# Menu: Bus options (PCI etc.) >> Architecture: powerpc
+CONFIG_FSL_LBC                                  policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Bus options (PCI etc.) >> Architecture: s390
+CONFIG_QDIO                                     policy<{'s390x': 'm'}>
+CONFIG_CHSC_SCH                                 policy<{'s390x': 'm'}>
+CONFIG_SCM_BUS                                  policy<{'s390x': 'y'}>
+CONFIG_EADM_SCH                                 policy<{'s390x': 'm'}>
+
+# Menu: Bus options (PCI etc.) >> Architecture: x86
+CONFIG_ISA_DMA_API                              policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SCx200                                   policy<{'i386': 'm'}>
+CONFIG_SCx200HR_TIMER                           policy<{'i386': 'm'}>
+CONFIG_ALIX                                     policy<{'i386': 'y'}>
+CONFIG_NET5501                                  policy<{'i386': 'y'}>
+CONFIG_GEOS                                     policy<{'i386': 'y'}>
+CONFIG_X86_SYSFB                                policy<{'amd64': 'n', 'i386': 'n'}>
+#
+CONFIG_X86_SYSFB                                flag<REVIEW>
+
+# Menu: Bus options (PCI etc.) >> EISA support
+CONFIG_EISA_VLB_PRIMING                         policy<{'i386': 'y'}>
+CONFIG_EISA_PCI_EISA                            policy<{'i386': 'y'}>
+CONFIG_EISA_VIRTUAL_ROOT                        policy<{'i386': 'y'}>
+CONFIG_EISA_NAMES                               policy<{'i386': 'y'}>
+
+# Menu: Bus options (PCI etc.) >> EISA support >> Architecture: x86
+CONFIG_EISA                                     policy<{'i386': 'y'}>
+
+# Menu: Bus options (PCI etc.) >> PCCard (PCMCIA/CardBus) support
+CONFIG_PCCARD                                   policy<{'amd64': 'm', 'armhf': 'n', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'n'}>
+CONFIG_CARDBUS                                  policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+
+# Menu: Bus options (PCI etc.) >> PCCard (PCMCIA/CardBus) support >> 16-bit PCMCIA support
+CONFIG_PCMCIA                                   policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 's390x': 'n'}>
+CONFIG_PCMCIA_LOAD_CIS                          policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_PD6729                                   policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_I82092                                   policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_I82365                                   policy<{'i386': 'm'}>
+CONFIG_TCIC                                     policy<{'i386': 'm'}>
+CONFIG_ELECTRA_CF                               policy<{'powerpc-powerpc64-smp': 'm'}>
+
+# Menu: Bus options (PCI etc.) >> PCCard (PCMCIA/CardBus) support >> CardBus yenta-compatible bridge support
+CONFIG_YENTA                                    policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_YENTA_O2                                 policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_YENTA_RICOH                              policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_YENTA_TI                                 policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_YENTA_ENE_TUNE                           policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_YENTA_TOSHIBA                            policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support
+CONFIG_PCI                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_MSI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PCI_REALLOC_ENABLE_AUTO                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_STUB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XEN_PCIDEV_FRONTEND                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HT_IRQ                                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PCI_IOV                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_PRI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PCI_PASID                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PCI_HYPERV                               policy<{'amd64': 'm'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> Architecture: s390
+CONFIG_PCI_NR_FUNCTIONS                         policy<{'s390x': '64'}>
+CONFIG_PCI_NR_MSI                               policy<{'s390x': '256'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> Architecture: x86
+CONFIG_PCI_MMCONFIG                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PCI_CNB20LE_QUIRK                        policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> PCI Express Port Bus support
+CONFIG_PCIEPORTBUS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HOTPLUG_PCI_PCIE                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_PCIEAER                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCIE_ECRC                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PCIEAER_INJECT                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PCIEASPM                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCIEASPM_DEBUG                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_PCIEASPM_DEBUG                           note<LP#1398544>
+CONFIG_HOTPLUG_PCI_PCIE                         mark<ENFORCED> note<LP#1374440>
+CONFIG_PCIEAER_INJECT                           flag<TESTING>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> PCI Express Port Bus support >> Default ASPM policy
+CONFIG_PCIEASPM_DEFAULT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCIEASPM_POWERSAVE                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PCIEASPM_PERFORMANCE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_PCIEASPM_DEFAULT                         note<LP#1398544>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> PCI access mode >> Architecture: x86
+CONFIG_PCI_GOBIOS                               policy<{'i386': 'n'}>
+CONFIG_PCI_GOMMCONFIG                           policy<{'i386': 'n'}>
+CONFIG_PCI_GODIRECT                             policy<{'i386': 'n'}>
+CONFIG_PCI_GOANY                                policy<{'i386': 'y'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> PCI host controller drivers
+CONFIG_PCI_MVEBU                                policy<{'armhf': 'y'}>
+CONFIG_PCI_EXYNOS                               policy<{'armhf': 'y'}>
+CONFIG_PCI_IMX6                                 policy<{'armhf-generic': 'y'}>
+CONFIG_PCI_TEGRA                                policy<{'armhf-generic': 'y'}>
+CONFIG_PCI_RCAR_GEN2                            policy<{'armhf': 'y'}>
+CONFIG_PCI_RCAR_GEN2_PCIE                       policy<{'armhf': 'y'}>
+CONFIG_PCI_HOST_GENERIC                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCI_XGENE                                policy<{'arm64': 'y'}>
+CONFIG_PCI_XGENE_MSI                            policy<{'arm64': 'y'}>
+CONFIG_PCI_LAYERSCAPE                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCIE_IPROC                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PCIE_IPROC_PLATFORM                      policy<{'arm64': 'm'}>
+CONFIG_PCIE_ALTERA                              policy<{'armhf': 'y'}>
+CONFIG_PCIE_ALTERA_MSI                          policy<{'armhf': 'y'}>
+CONFIG_PCI_HISI                                 policy<{'arm64': 'y'}>
+CONFIG_PCI_HOST_THUNDER_PEM                     policy<{'arm64': 'y'}>
+CONFIG_PCI_HOST_THUNDER_ECAM                    policy<{'arm64': 'y'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> RapidIO support
+CONFIG_RAPIDIO                                  policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RAPIDIO_TSI721                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_DISC_TIMEOUT                     policy<{'amd64': '30', 'i386': '30', 'powerpc': '30', 'ppc64el': '30'}>
+CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS               policy<{'amd64': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RAPIDIO_DMA_ENGINE                       policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RAPIDIO_DEBUG                            policy<{'amd64': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> RapidIO support >> Architecture: powerpc
+CONFIG_FSL_RIO                                  policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> RapidIO support >> Enumeration method
+CONFIG_RAPIDIO_ENUM_BASIC                       policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> RapidIO support >> RapidIO Switch drivers
+CONFIG_RAPIDIO_TSI57X                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_CPS_XX                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_TSI568                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_CPS_GEN2                         policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Bus options (PCI etc.) >> PCI support >> Support for PCI Hotplug
+CONFIG_HOTPLUG_PCI                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HOTPLUG_PCI_COMPAQ                       policy<{'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM                 policy<{'i386': 'y'}>
+CONFIG_HOTPLUG_PCI_IBM                          policy<{'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_ACPI                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HOTPLUG_PCI_ACPI_IBM                     policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_CPCI                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HOTPLUG_PCI_CPCI_ZT5550                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_CPCI_GENERIC                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_SHPC                         policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HOTPLUG_PCI_RPA                          policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_HOTPLUG_PCI_RPA_DLPAR                    policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_HOTPLUG_PCI_S390                         policy<{'s390x': 'y'}>
+#
+CONFIG_HOTPLUG_PCI_SHPC                         note<LP#1374440>
+
+# Menu: Cryptographic API
+CONFIG_CRYPTO                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_RSA                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DH                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRYPTO_ECDH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_MANAGER                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_USER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_GF128MUL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_NULL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_PCRYPT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CRYPTD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_MCRYPTD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_AUTHENC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TEST                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CCM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_GCM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CHACHA20POLY1305                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SEQIV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ECHAINIV                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CBC                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_CTR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CTS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ECB                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_LRW                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_PCBC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_XTS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_KEYWRAP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CMAC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_HMAC                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_XCBC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_VMAC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CRC32C                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_CRC32C_INTEL                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CRYPTO_CRC32                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CRC32_PCLMUL                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_CRCT10DIF                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_CRCT10DIF_PCLMUL                  policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_GHASH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_POLY1305                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_POLY1305_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_MD4                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_MD5                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_MD5_PPC                           policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_MICHAEL_MIC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_RMD128                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_RMD160                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_RMD256                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_RMD320                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SHA1                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_SHA1_SSSE3                        policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SHA256_SSSE3                      policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SHA512_SSSE3                      policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SHA1_PPC                          policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_SHA1_MB                           policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SHA256                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_SHA512                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_TGR192                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_WP512                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL              policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_AES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_AES_586                           policy<{'i386': 'm'}>
+CONFIG_CRYPTO_AES_X86_64                        policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_AES_NI_INTEL                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_ANUBIS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ARC4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_BLOWFISH                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_BLOWFISH_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAMELLIA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CAMELLIA_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64         policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64        policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAST5                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CAST5_AVX_X86_64                  policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAST6                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CAST6_AVX_X86_64                  policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_DES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_DES3_EDE_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_FCRYPT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_KHAZAD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SALSA20                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SALSA20_586                       policy<{'i386': 'm'}>
+CONFIG_CRYPTO_SALSA20_X86_64                    policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CHACHA20                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CHACHA20_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SEED                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SERPENT                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SERPENT_SSE2_X86_64               policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SERPENT_SSE2_586                  policy<{'i386': 'm'}>
+CONFIG_CRYPTO_SERPENT_AVX_X86_64                policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SERPENT_AVX2_X86_64               policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_TEA                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TWOFISH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TWOFISH_586                       policy<{'i386': 'm'}>
+CONFIG_CRYPTO_TWOFISH_X86_64                    policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_TWOFISH_X86_64_3WAY               policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_TWOFISH_AVX_X86_64                policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_DEFLATE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ZLIB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_LZO                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_842                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_LZ4                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_LZ4HC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ANSI_CPRNG                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_JITTERENTROPY                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API_HASH                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API_SKCIPHER                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API_RNG                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API_AEAD                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+#
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS             flag<TESTING>
+CONFIG_CRYPTO_TEST                              flag<TESTING>
+CONFIG_CRYPTO_SHA512                            note<module signing>
+
+# Menu: Cryptographic API >> Asymmetric (public-key cryptographic) key type
+CONFIG_ASYMMETRIC_KEY_TYPE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PUBLIC_KEY_ALGO_RSA                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_X509_CERTIFICATE_PARSER                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PKCS7_MESSAGE_PARSER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PKCS7_TEST_KEY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SIGNED_PE_FILE_VERIFICATION              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EFI_SIGNATURE_LIST_PARSER                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+#
+CONFIG_ASYMMETRIC_KEY_TYPE                      note<module signing>
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE            note<module signing>
+CONFIG_PUBLIC_KEY_ALGO_RSA                      note<module signing>
+CONFIG_X509_CERTIFICATE_PARSER                  note<module signing>
+
+# Menu: Cryptographic API >> Certificates for signature checking
+CONFIG_MODULE_SIG_KEY                           policy<{'amd64': '"certs/signing_key.pem"', 'arm64': '"certs/signing_key.pem"', 'armhf': '"certs/signing_key.pem"', 'i386': '"certs/signing_key.pem"', 'powerpc': '"certs/signing_key.pem"', 'ppc64el': '"certs/signing_key.pem"', 's390x': '"certs/signing_key.pem"'}>
+CONFIG_SYSTEM_TRUSTED_KEYRING                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEM_TRUSTED_KEYS                      policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'powerpc': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_SYSTEM_EXTRA_CERTIFICATE                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE            policy<{'amd64': '4096', 'arm64': '4096', 'armhf': '4096', 'i386': '4096', 'powerpc': '4096', 'ppc64el': '4096', 's390x': '4096'}>
+
+# Menu: Cryptographic API >> Hardware crypto devices
+CONFIG_CRYPTO_HW                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DEV_PADLOCK                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CRYPTO_DEV_PADLOCK_AES                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_PADLOCK_SHA                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_GEODE                         policy<{'i386': 'm'}>
+CONFIG_ZCRYPT                                   policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_SHA1_S390                         policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_SHA256_S390                       policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_SHA512_S390                       policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_DES_S390                          policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_AES_S390                          policy<{'s390x': 'm'}>
+CONFIG_S390_PRNG                                policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_GHASH_S390                        policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_DEV_MV_CESA                       policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_MARVELL_CESA                  policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_HIFN_795X                     policy<{'armhf-generic': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_CRYPTO_DEV_HIFN_795X_RNG                 policy<{'armhf-generic': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM                      policy<{'armhf-generic': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG                policy<{'armhf-generic': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc64-emb': 'n'}>
+CONFIG_CRYPTO_DEV_TALITOS                       policy<{'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_CRYPTO_DEV_TALITOS2                      policy<{'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_CRYPTO_DEV_OMAP_SHAM                     policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_OMAP_AES                      policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_OMAP_DES                      policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_SAHARA                        policy<{'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_S5P                           policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_NX                            policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_CRYPTO_DEV_NX_ENCRYPT                    policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_CRYPTO_DEV_NX_COMPRESS                   policy<{'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES           policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV           policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_CCP                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_CRYPTO_DEV_CCP_DD                        policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_CCP_CRYPTO                    policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_MXS_DCP                       policy<{'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_QAT_DH895xCC                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_QAT_DH895xCCVF                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_QCE                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_VMX                           policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_CRYPTO_DEV_VMX_ENCRYPT                   policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+
+# Menu: Cryptographic API >> Hardware crypto devices >> Freescale CAAM Job Ring driver backend
+CONFIG_CRYPTO_DEV_FSL_CAAM_JR                   policy<{'armhf-generic': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE             policy<{'armhf-generic': '9', 'powerpc-powerpc64-emb': '9', 'powerpc-powerpc-e500mc': '9'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC                 policy<{'armhf-generic': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD      policy<{'armhf-generic': '255', 'powerpc-powerpc64-emb': '255', 'powerpc-powerpc-e500mc': '255'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD       policy<{'armhf-generic': '2048', 'powerpc-powerpc64-emb': '2048', 'powerpc-powerpc-e500mc': '2048'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API           policy<{'armhf-generic': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API            policy<{'armhf-generic': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API              policy<{'armhf-generic': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+
+# Menu: Cryptographic API >> NIST SP800-90A DRBG
+CONFIG_CRYPTO_DRBG_MENU                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_DRBG_HASH                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DRBG_CTR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Device Drivers
+CONFIG_TEGRA_AHB                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BLK_DEV_NVME                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_NVME_SCSI                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NVME_VENDOR_EXT_GOOGLE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RESET_CONTROLLER                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_THUNDERBOLT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_STM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STM_DUMMY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STM_SOURCE_CONSOLE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> ATA/ATAPI/MFM/RLL support (DEPRECATED)
+CONFIG_IDE                                      policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> ATA/ATAPI/MFM/RLL support (DEPRECATED) >> IDE Mode for AMD Alchemy Au1200
+
+# Menu: Device Drivers >> Accessibility support
+CONFIG_ACCESSIBILITY                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_ACCESSIBILITY                            flag<REVIEW>
+
+# Menu: Device Drivers >> Adaptive Voltage Scaling class support
+CONFIG_POWER_AVS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ROCKCHIP_IODOMAIN                        policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Android
+CONFIG_ANDROID                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Device Drivers >> Auxiliary Display support
+CONFIG_AUXDISPLAY                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+
+# Menu: Device Drivers >> Auxiliary Display support >> KS0108 LCD Controller
+CONFIG_KS0108                                   policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KS0108_PORT                              policy<{'amd64': '0x378', 'armhf': '0x378', 'i386': '0x378', 'powerpc': '0x378', 'ppc64el': '0x378'}>
+CONFIG_KS0108_DELAY                             policy<{'amd64': '2', 'armhf': '2', 'i386': '2', 'powerpc': '2', 'ppc64el': '2'}>
+CONFIG_CFAG12864B                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CFAG12864B_RATE                          policy<{'amd64': '20', 'i386': '20'}>
+
+# Menu: Device Drivers >> Block devices
+CONFIG_BLK_DEV                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_NULL_BLK                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_FD                               policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAC_FLOPPY                               policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ZRAM                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ZRAM_LZ4_COMPRESS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_CPQ_CISS_DA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CISS_SCSI_TAPE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BLK_DEV_DAC960                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_UMEM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_LOOP                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_LOOP_MIN_COUNT                   policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8', 's390x': '8'}>
+CONFIG_BLK_DEV_CRYPTOLOOP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_DRBD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DRBD_FAULT_INJECTION                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BLK_DEV_NBD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_SKD                              policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_OSD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_SX8                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CDROM_PKTCDVD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CDROM_PKTCDVD_BUFFERS                    policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8'}>
+CONFIG_CDROM_PKTCDVD_WCACHE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATA_OVER_ETH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MG_DISK                                  policy<{'armhf': 'm'}>
+CONFIG_MG_DISK_RES                              policy<{'armhf': '0'}>
+CONFIG_BLK_DEV_XPRAM                            policy<{'s390x': 'n'}>
+CONFIG_DCSSBLK                                  policy<{'s390x': 'm'}>
+CONFIG_SCM_BLOCK                                policy<{'s390x': 'm'}>
+CONFIG_SCM_BLOCK_CLUSTER_WRITE                  policy<{'s390x': 'y'}>
+CONFIG_XEN_BLKDEV_FRONTEND                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_BLKDEV_BACKEND                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_VIRTIO_BLK                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_HD                               policy<{'amd64': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_BLK_DEV_RBD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_RSXX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+#
+CONFIG_BLK_DEV_UMEM                             note<experimental NVRAM disk driver -- opt-in>
+CONFIG_CDROM_PKTCDVD_WCACHE                     mark<DANGEROUS>
+CONFIG_XEN_BLKDEV_FRONTEND                      note<not autoloadable -- XEN paravirt support>
+CONFIG_VIRTIO_BLK                               note<KVM paravirt support -- not autoloadable>
+CONFIG_BLK_DEV_HD                               note<very old disk device support> flag<ANCIENT>
+
+# Menu: Device Drivers >> Block devices >> Parallel port IDE device support
+CONFIG_PARIDE                                   policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PD                                policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PCD                               policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PF                                policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PT                                policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PG                                policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_ATEN                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_BPCK                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_BPCK6                             policy<{'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_PARIDE_COMM                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_DSTR                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_FIT2                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_FIT3                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_EPAT                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_EPATC8                            policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PARIDE_EPIA                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_FRIQ                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_FRPW                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_KBIC                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_KTTI                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_ON20                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_ON26                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Block devices >> RAM block device support
+CONFIG_BLK_DEV_RAM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_RAM_COUNT                        policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'powerpc': '16', 'ppc64el': '16', 's390x': '16'}>
+CONFIG_BLK_DEV_RAM_SIZE                         policy<{'amd64': '65536', 'arm64': '65536', 'armhf': '65536', 'i386': '65536', 'powerpc': '65536', 'ppc64el': '65536', 's390x': '65536'}>
+CONFIG_BLK_DEV_RAM_DAX                          policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_BLK_DEV_RAM				note<LP #1593293>
+CONFIG_BLK_DEV_RAM_SIZE                         mark<ENFORCED> note<Ramdisk size should be a minimum of 64M> flag<REVIEW>
+
+# Menu: Device Drivers >> Block devices >> Support for DASD devices
+CONFIG_DASD                                     policy<{'s390x': 'm'}>
+CONFIG_DASD_PROFILE                             policy<{'s390x': 'y'}>
+CONFIG_DASD_ECKD                                policy<{'s390x': 'm'}>
+CONFIG_DASD_FBA                                 policy<{'s390x': 'm'}>
+CONFIG_DASD_DIAG                                policy<{'s390x': 'm'}>
+CONFIG_DASD_EER                                 policy<{'s390x': 'y'}>
+
+# Menu: Device Drivers >> Broadcom specific AMBA
+CONFIG_BCMA_HOST_PCI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Broadcom specific AMBA >> BCMA support
+CONFIG_BCMA                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BCMA_HOST_SOC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_DRIVER_PCI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_DRIVER_GMAC_CMN                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_DRIVER_GPIO                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Bus devices
+CONFIG_ARM_CCI400_PMU                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CCI500_PMU                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CCN                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BRCMSTB_GISB_ARB                         policy<{'armhf': 'y'}>
+CONFIG_IMX_WEIM                                 policy<{'armhf-generic': 'y'}>
+CONFIG_OMAP_INTERCONNECT                        policy<{'armhf': 'y'}>
+CONFIG_OMAP_OCP2SCP                             policy<{'armhf': 'm'}>
+CONFIG_SIMPLE_PM_BUS                            policy<{'armhf': 'y'}>
+CONFIG_VEXPRESS_CONFIG                          policy<{'arm64': 'y', 'armhf': 'y'}>
+
+# Menu: Device Drivers >> Character devices
+CONFIG_DEVMEM                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEVKMEM                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TTY_PRINTK                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PRINTER                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LP_CONSOLE                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_PPDEV                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HVC_CONSOLE                              policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_HVC_OLD_HVSI                             policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_HVC_OPAL                                 policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_HVC_RTAS                                 policy<{'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_HVC_IUCV                                 policy<{'s390x': 'y'}>
+CONFIG_HVC_XEN                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HVC_XEN_FRONTEND                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HVC_UDBG                                 policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HVC_DCC                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_HVCS                                     policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_VIRTIO_CONSOLE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IBM_BSR                                  policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_NVRAM                                    policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_DTLK                                     policy<{'i386': 'm'}>
+CONFIG_APPLICOM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SONYPI                                   policy<{'i386': 'm'}>
+CONFIG_MWAVE                                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCx200_GPIO                              policy<{'i386': 'm'}>
+CONFIG_PC8736x_GPIO                             policy<{'i386': 'm'}>
+CONFIG_NSC_GPIO                                 policy<{'i386': 'm'}>
+CONFIG_RAW_DRIVER                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MAX_RAW_DEVS                             policy<{'amd64': '256', 'arm64': '256', 'armhf': '256', 'i386': '256', 'powerpc': '256', 'ppc64el': '256'}>
+CONFIG_HPET                                     policy<{'amd64': 'y', 'arm64': 'n', 'i386': 'y'}>
+CONFIG_HPET_MMAP                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HPET_MMAP_DEFAULT                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HANGCHECK_TIMER                          policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TELCLOCK                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DEVPORT                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TN3270                                   policy<{'s390x': 'y'}>
+CONFIG_TN3270_TTY                               policy<{'s390x': 'y'}>
+CONFIG_TN3270_FS                                policy<{'s390x': 'm'}>
+CONFIG_TN3270_CONSOLE                           policy<{'s390x': 'y'}>
+CONFIG_TN3215                                   policy<{'s390x': 'y'}>
+CONFIG_TN3215_CONSOLE                           policy<{'s390x': 'y'}>
+CONFIG_SCLP_TTY                                 policy<{'s390x': 'y'}>
+CONFIG_SCLP_CONSOLE                             policy<{'s390x': 'y'}>
+CONFIG_SCLP_VT220_TTY                           policy<{'s390x': 'y'}>
+CONFIG_SCLP_VT220_CONSOLE                       policy<{'s390x': 'y'}>
+CONFIG_SCLP_CPI                                 policy<{'s390x': 'm'}>
+CONFIG_SCLP_ASYNC                               policy<{'s390x': 'm'}>
+CONFIG_SCLP_ASYNC_ID                            policy<{'s390x': '"000000000"'}>
+CONFIG_HMC_DRV                                  policy<{'s390x': 'm'}>
+CONFIG_S390_TAPE                                policy<{'s390x': 'm'}>
+CONFIG_S390_TAPE_34XX                           policy<{'s390x': 'm'}>
+CONFIG_S390_TAPE_3590                           policy<{'s390x': 'm'}>
+CONFIG_VMLOGRDR                                 policy<{'s390x': 'm'}>
+CONFIG_VMCP                                     policy<{'s390x': 'y'}>
+CONFIG_MONREADER                                policy<{'s390x': 'm'}>
+CONFIG_MONWRITER                                policy<{'s390x': 'm'}>
+CONFIG_S390_VMUR                                policy<{'s390x': 'm'}>
+CONFIG_XILLYBUS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_XILLYBUS_PCIE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_XILLYBUS_OF                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_DEVKMEM                                  mark<ENFORCED> note</dev/kmem is a large attack vector>
+CONFIG_NVRAM                                    mark<ENFORCED> note<boot essential on powerpc LP:942193>
+
+# Menu: Device Drivers >> Character devices >> Enable TTY
+CONFIG_TTY                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VT                                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CONSOLE_TRANSLATIONS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VT_CONSOLE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VT_HW_CONSOLE_BINDING                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_UNIX98_PTYS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEVPTS_MULTIPLE_INSTANCES                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LEGACY_PTYS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LEGACY_PTY_COUNT                         policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_NOZOMI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_N_GSM                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TRACE_ROUTER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TRACE_SINK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PPC_EPAPR_HV_BYTECHAN                    policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_LDISC_AUTOLOAD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_N_GSM                                    note<LP#1404670>
+
+# Menu: Device Drivers >> Character devices >> Enable TTY >> Non-standard serial port support
+CONFIG_SERIAL_NONSTANDARD                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ROCKETPORT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CYCLADES                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CYZ_INTR                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MOXA_INTELLIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOXA_SMARTIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SYNCLINK                                 policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SYNCLINKMP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SYNCLINK_GT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISI                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_N_HDLC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Character devices >> Hardware Random Number Generator Core support
+CONFIG_HW_RANDOM                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HW_RANDOM_TIMERIOMEM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HW_RANDOM_INTEL                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HW_RANDOM_AMD                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc64-smp': 'm'}>
+CONFIG_HW_RANDOM_IPROC_RNG200                   policy<{'arm64': 'm'}>
+CONFIG_HW_RANDOM_GEODE                          policy<{'i386': 'm'}>
+CONFIG_HW_RANDOM_VIA                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HW_RANDOM_OMAP                           policy<{'armhf': 'm'}>
+CONFIG_HW_RANDOM_OMAP3_ROM                      policy<{'armhf-generic': 'm'}>
+CONFIG_HW_RANDOM_PASEMI                         policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_HW_RANDOM_VIRTIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_HW_RANDOM_PSERIES                        policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_HW_RANDOM_POWERNV                        policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_HW_RANDOM_EXYNOS                         policy<{'armhf': 'm'}>
+CONFIG_HW_RANDOM_TPM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_HW_RANDOM_MSM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HW_RANDOM_XGENE                          policy<{'arm64': 'm'}>
+#
+CONFIG_HW_RANDOM_ATMEL                          note<depends on CONFIG_ARCH_AT91SAM9G45>
+
+# Menu: Device Drivers >> Character devices >> IPMI top-level message handler
+CONFIG_IPMI_HANDLER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IPMI_PANIC_EVENT                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_IPMI_DEVICE_INTERFACE                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_SI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_SI_PROBE_DEFAULTS                   policy<{'amd64': 'y', 'arm64': 'n', 'armhf': 'n', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IPMI_SSIF                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_POWERNV                             policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_WATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_POWEROFF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Character devices >> PCMCIA character devices
+CONFIG_SYNCLINK_CS                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_CARDMAN_4000                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_CARDMAN_4040                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_IPWIRELESS                               policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> Character devices >> Serial drivers
+CONFIG_SERIAL_AMBA_PL010                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SERIAL_AMBA_PL011                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_AMBA_PL011_CONSOLE                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_KGDB_NMI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_MESON                             policy<{'armhf': 'm'}>
+CONFIG_SERIAL_SAMSUNG                           policy<{'armhf': 'm'}>
+CONFIG_SERIAL_TEGRA                             policy<{'armhf-generic': 'm'}>
+CONFIG_SERIAL_MAX3100                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_MAX310X                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_IMX                               policy<{'armhf-generic': 'y'}>
+CONFIG_SERIAL_IMX_CONSOLE                       policy<{'armhf-generic': 'y'}>
+CONFIG_SERIAL_PMACZILOG                         policy<{'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_SERIAL_PMACZILOG_TTYS                    policy<{'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_SERIAL_PMACZILOG_CONSOLE                 policy<{'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_SERIAL_CPM                               policy<{'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_SERIAL_ICOM                              policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_JSM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_MSM                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_MSM_CONSOLE                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_OF_PLATFORM                       policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_OMAP                              policy<{'armhf': 'y'}>
+CONFIG_SERIAL_OMAP_CONSOLE                      policy<{'armhf': 'y'}>
+CONFIG_SERIAL_SCCNXP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SERIAL_SCCNXP_CONSOLE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_SC16IS7XX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_SC16IS7XX_I2C                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_SC16IS7XX_SPI                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_TIMBERDALE                        policy<{'i386': 'm'}>
+CONFIG_SERIAL_BCM63XX                           policy<{'armhf': 'm'}>
+CONFIG_SERIAL_ALTERA_JTAGUART                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_IFX6X60                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SERIAL_PCH_UART                          policy<{'i386': 'm'}>
+CONFIG_SERIAL_XILINX_PS_UART                    policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_ARC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_ARC_NR_PORTS                      policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'powerpc': '1', 'ppc64el': '1'}>
+CONFIG_SERIAL_RP2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_RP2_NR_UARTS                      policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'powerpc': '32', 'ppc64el': '32'}>
+CONFIG_SERIAL_FSL_LPUART                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_CONEXANT_DIGICOLOR                policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_ST_ASC                            policy<{'armhf': 'm'}>
+CONFIG_SERIAL_MEN_Z135                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_SPRD                              policy<{'arm64': 'm'}>
+CONFIG_SERIAL_STM32                             policy<{'armhf': 'm'}>
+CONFIG_SERIAL_UARTLITE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> 8250/16550 and compatible serial support
+CONFIG_SERIAL_8250                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SERIAL_8250_PNP                          policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_SERIAL_8250_CONSOLE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_DMA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_PCI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_CS                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_SERIAL_8250_NR_UARTS                     policy<{'amd64': '48', 'arm64': '48', 'armhf': '48', 'i386': '48', 'powerpc': '48', 'ppc64el': '48'}>
+CONFIG_SERIAL_8250_RUNTIME_UARTS                policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'powerpc': '32', 'ppc64el': '32'}>
+CONFIG_SERIAL_8250_DW                           policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_8250_EM                           policy<{'armhf': 'n'}>
+CONFIG_SERIAL_8250_RT288X                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_OMAP                         policy<{'armhf': 'm'}>
+CONFIG_SERIAL_8250_FINTEK                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_SERIAL_8250_MT6577                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_8250_UNIPHIER                     policy<{'armhf': 'm'}>
+CONFIG_SERIAL_8250_INGENIC                      policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_MID                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_SERIAL_8250_DW                           note<Otherwise can't boot APM xgene2 via UEFI+ACPI>
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> 8250/16550 and compatible serial support >> Extended 8250/16550 serial driver options
+CONFIG_SERIAL_8250_EXTENDED                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_SHARE_IRQ                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_DETECT_IRQ                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SERIAL_8250_RSA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> 8250/16550 and compatible serial support >> Extended 8250/16550 serial driver options >> Support more than 4 legacy serial ports
+CONFIG_SERIAL_8250_MANY_PORTS                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_FOURPORT                     policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_ACCENT                       policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_BOCA                         policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_EXAR_ST16C554                policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_HUB6                         policy<{'i386': 'm'}>
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> AT91 / AT32 on-chip serial port support
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> Altera UART support
+CONFIG_SERIAL_ALTERA_UART                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_ALTERA_UART_MAXPORTS              policy<{'amd64': '4', 'arm64': '4', 'armhf': '4', 'i386': '4', 'powerpc': '4', 'ppc64el': '4'}>
+CONFIG_SERIAL_ALTERA_UART_BAUDRATE              policy<{'amd64': '115200', 'arm64': '115200', 'armhf': '115200', 'i386': '115200', 'powerpc': '115200', 'ppc64el': '115200'}>
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> Blackfin SPORT emulate UART
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> Blackfin serial port support
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> Blackfin serial port support >> UART Mode
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> SuperH SCI(F) serial port support
+CONFIG_SERIAL_SH_SCI                            policy<{'armhf': 'm'}>
+CONFIG_SERIAL_SH_SCI_NR_UARTS                   policy<{'armhf': '2'}>
+CONFIG_SERIAL_SH_SCI_DMA                        policy<{'armhf': 'y'}>
+
+# Menu: Device Drivers >> Character devices >> Serial drivers >> TMPTX39XX/49XX SIO support
+
+# Menu: Device Drivers >> Character devices >> TPM Hardware Support
+CONFIG_TCG_TPM                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TCG_TIS                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_TCG_TIS_I2C_ATMEL                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_TIS_I2C_INFINEON                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_TIS_I2C_NUVOTON                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_NSC                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TCG_ATMEL                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_INFINEON                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_TCG_IBMVTPM                              policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_TCG_XEN                                  policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_TCG_CRB                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_TCG_TIS_ST33ZP24                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_TIS_ST33ZP24_I2C                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_TIS_ST33ZP24_SPI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_TCG_TPM                                  note<needed for early validation>
+
+# Menu: Device Drivers >> Clock Source drivers
+CONFIG_CLKSRC_TI_32K                            policy<{'armhf': 'y'}>
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_TIMER_SP804                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SH_TIMER_CMT                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SH_TIMER_MTU2                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SH_TIMER_TMU                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_EM_TIMER_STI                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CLKSRC_VERSATILE                         policy<{'armhf': 'y'}>
+CONFIG_CLKSRC_IMX_GPT                           policy<{'armhf-generic': 'y'}>
+
+# Menu: Device Drivers >> Common Clock Framework
+CONFIG_COMMON_CLK_WM831X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_VERSATILE                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_SP810                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_VEXPRESS_OSC                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MAX77686                      policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_MAX77802                      policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_RK808                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_SCPI                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_SI5351                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_SI514                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_SI570                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_CDCE925                       policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_S2MPS11                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_CLK_TWL6040                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_CLK_QORIQ                                policy<{'arm64': 'y', 'armhf': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_COMMON_CLK_XGENE                         policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_PALMAS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_PWM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_CDCE706                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_COMMON_CLK_HI6220                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_STUB_CLK_HI6220                          policy<{'arm64': 'y', 'armhf': 'y'}>
+
+# Menu: Device Drivers >> Common Clock Framework >> Support for Qualcomm's clock controllers
+CONFIG_COMMON_CLK_QCOM                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_APQ_GCC_8084                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_APQ_MMCC_8084                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IPQ_GCC_806X                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IPQ_LCC_806X                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_GCC_8660                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_GCC_8916                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_GCC_8960                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_LCC_8960                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_MMCC_8960                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_GCC_8974                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_MMCC_8974                            policy<{'arm64': 'm', 'armhf': 'm'}>
+
+# Menu: Device Drivers >> Connector - unified userspace <-> kernelspace linker
+CONFIG_CONNECTOR                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_EVENTS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Device Drivers >> DMA Engine support
+CONFIG_DMADEVICES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_DMADEVICES_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_AMBA_PL08X                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DMA_OMAP                                 policy<{'armhf': 'y'}>
+CONFIG_FSL_DMA                                  policy<{'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_FSL_EDMA                                 policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IMX_DMA                                  policy<{'armhf-generic': 'm'}>
+CONFIG_IMX_SDMA                                 policy<{'armhf-generic': 'm'}>
+CONFIG_INTEL_IDMA64                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INTEL_IOATDMA                            policy<{'amd64': 'm'}>
+CONFIG_INTEL_MIC_X100_DMA                       policy<{'amd64': 'm'}>
+CONFIG_K3_DMA                                   policy<{'armhf': 'm'}>
+CONFIG_MV_XOR                                   policy<{'armhf': 'y'}>
+CONFIG_MXS_DMA                                  policy<{'armhf-generic': 'y'}>
+CONFIG_MX3_IPU                                  policy<{'armhf-generic': 'y'}>
+CONFIG_MX3_IPU_IRQS                             policy<{'armhf-generic': '4'}>
+CONFIG_NBPFAXI_DMA                              policy<{'armhf': 'm'}>
+CONFIG_PCH_DMA                                  policy<{'i386': 'm'}>
+CONFIG_PL330_DMA                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_BAM_DMA                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TEGRA20_APB_DMA                          policy<{'armhf-generic': 'y'}>
+CONFIG_TIMB_DMA                                 policy<{'i386': 'm'}>
+CONFIG_TI_CPPI41                                policy<{'armhf': 'm'}>
+CONFIG_TI_EDMA                                  policy<{'armhf': 'y'}>
+CONFIG_XGENE_DMA                                policy<{'arm64': 'm'}>
+CONFIG_DW_DMAC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DW_DMAC_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RCAR_DMAC                                policy<{'armhf': 'm'}>
+CONFIG_RENESAS_USB_DMAC                         policy<{'armhf': 'm'}>
+CONFIG_ASYNC_TX_DMA                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DMATEST                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_DMATEST                                  flag<TESTING>
+
+# Menu: Device Drivers >> DMA Engine support >> Renesas SuperH DMA Engine support
+CONFIG_SH_DMAE_BASE                             policy<{'armhf': 'y'}>
+CONFIG_SH_DMAE                                  policy<{'armhf': 'm'}>
+CONFIG_SUDMAC                                   policy<{'armhf': 'm'}>
+CONFIG_RCAR_HPB_DMAE                            policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Dallas's 1-wire support
+CONFIG_W1                                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_W1_CON                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Dallas's 1-wire support >> 1-wire Bus Masters
+CONFIG_W1_MASTER_MATROX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_DS2490                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_DS2482                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_MXC                            policy<{'armhf-generic': 'm'}>
+CONFIG_W1_MASTER_DS1WM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_GPIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDQ_MASTER_OMAP                          policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Dallas's 1-wire support >> 1-wire Slaves
+CONFIG_W1_SLAVE_THERM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_SMEM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2408                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2408_READBACK                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_W1_SLAVE_DS2413                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2406                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2423                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2431                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2433                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2433_CRC                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_W1_SLAVE_DS2760                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2780                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2781                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS28E04                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_BQ27000                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Device Tree and Open Firmware support
+CONFIG_OF                                       policy<{'amd64': 'n', 'arm64': 'y', 'armhf': 'y', 'i386': 'n', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_OF_UNITTEST                              policy<{'arm64': 'n', 'armhf': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_OF_DYNAMIC                               policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_OVERLAY                               policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_OF_UNITTEST                              flag<DEBUG>
+
+# Menu: Device Drivers >> EDAC (Error Detection And Correction) reporting
+CONFIG_EDAC                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_EDAC_LEGACY_SYSFS                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_EDAC_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_EDAC_DECODE_MCE                          policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> EDAC (Error Detection And Correction) reporting >> Main Memory EDAC (Error Detection And Correction) reporting
+CONFIG_EDAC_MM_EDAC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EDAC_AMD64                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_AMD64_ERROR_INJECTION               policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_EDAC_AMD76X                              policy<{'i386': 'm'}>
+CONFIG_EDAC_E7XXX                               policy<{'i386': 'm'}>
+CONFIG_EDAC_E752X                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I82875P                             policy<{'i386': 'm'}>
+CONFIG_EDAC_I82975X                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I3000                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I3200                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_IE31200                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_X38                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I5400                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I7CORE                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I82860                              policy<{'i386': 'm'}>
+CONFIG_EDAC_R82600                              policy<{'i386': 'm'}>
+CONFIG_EDAC_I5000                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I5100                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I7300                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_SBRIDGE                             policy<{'amd64': 'm'}>
+CONFIG_EDAC_SKX                                 policy<{'amd64': 'm'}>
+CONFIG_EDAC_MPC85XX                             policy<{'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_EDAC_PASEMI                              policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_EDAC_AMD8131                             policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_EDAC_AMD8111                             policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_EDAC_CPC925                              policy<{'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_EDAC_HIGHBANK_MC                         policy<{'armhf': 'm'}>
+CONFIG_EDAC_HIGHBANK_L2                         policy<{'armhf': 'm'}>
+CONFIG_EDAC_XGENE                               policy<{'arm64': 'm'}>
+
+# Menu: Device Drivers >> External Connector Class (extcon) support
+CONFIG_EXTCON                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_EXTCON_ADC_JACK                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_ARIZONA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_AXP288                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_GPIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_MAX14577                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_MAX77693                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_MAX77843                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_MAX8997                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_PALMAS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_RT8973A                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_SM5502                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_USB_GPIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> FMC support
+CONFIG_FMC                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FMC_FAKEDEV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FMC_TRIVIAL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FMC_WRITE_EEPROM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FMC_CHARDEV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> FPGA Configuration Support
+CONFIG_FPGA                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FPGA_MGR_ZYNQ_FPGA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> Fusion MPT device support
+CONFIG_FUSION                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FUSION_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_FC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_SAS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_MAX_SGE                           policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'powerpc': '128', 'ppc64el': '128'}>
+CONFIG_FUSION_CTL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_LAN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_LOGGING                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> GPIO Support
+CONFIG_GPIOLIB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DEBUG_GPIO                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_GPIO_SYSFS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_GPIO_SYSFS                               note<LP#1342153>
+
+# Menu: Device Drivers >> GPIO Support >> I2C GPIO expanders
+CONFIG_GPIO_ADP5588                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ADNP                                policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MAX7300                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MAX732X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_PCA953X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_PCF857X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_SX150X                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> GPIO Support >> MFD GPIO expanders
+CONFIG_GPIO_ADP5520                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ARIZONA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_CRYSTAL_COVE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_CS5535                              policy<{'i386': 'm'}>
+CONFIG_GPIO_DA9052                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_DA9055                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_DLN2                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_JANZ_TTL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_KEMPLD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_LP3943                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MSIC                                policy<{'i386': 'y'}>
+CONFIG_GPIO_PALMAS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_RC5T583                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_STMPE                               policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_TC3589X                             policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_TIMBERDALE                          policy<{'i386': 'y'}>
+CONFIG_GPIO_TPS6586X                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_TPS65910                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_TPS65912                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_TWL4030                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_TWL6040                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_UCB1400                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_WM831X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_WM8350                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_WM8994                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_GPIO_TWL4030                             mark<ENFORCED> note<LP:#921934>
+
+# Menu: Device Drivers >> GPIO Support >> Memory mapped GPIO drivers
+CONFIG_GPIO_74XX_MMIO                           policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ALTERA                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_AMDPT                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_DWAPB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_EM                                  policy<{'armhf': 'n'}>
+CONFIG_GPIO_GENERIC_PLATFORM                    policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_GRGPIO                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ICH                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_LYNXPOINT                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_GPIO_MPC8XXX                             policy<{'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_GPIO_OMAP                                policy<{'armhf': 'y'}>
+CONFIG_GPIO_PL061                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GPIO_RCAR                                policy<{'armhf': 'm'}>
+CONFIG_GPIO_SYSCON                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_VX855                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_XGENE                               policy<{'arm64': 'y'}>
+CONFIG_GPIO_XGENE_SB                            policy<{'arm64': 'm'}>
+CONFIG_GPIO_XILINX                              policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_ZEVIO                               policy<{'armhf': 'y'}>
+CONFIG_GPIO_ZYNQ                                policy<{'arm64': 'm'}>
+CONFIG_GPIO_ZX                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_GPIO_EM                                  note<h/w not encounted>
+
+# Menu: Device Drivers >> GPIO Support >> PCI GPIO expanders
+CONFIG_GPIO_AMD8111                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_INTEL_MID                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_GPIO_ML_IOH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_PCH                                 policy<{'i386': 'm'}>
+CONFIG_GPIO_RDC321X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> GPIO Support >> Port-mapped I/O GPIO drivers
+CONFIG_GPIO_104_IDIO_16                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_F7188X                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_IT87                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_SCH                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_SCH311X                             policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> GPIO Support >> SPI GPIO expanders
+CONFIG_GPIO_74X164                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MAX7301                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MC33880                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> GPIO Support >> SPI or I2C GPIO expanders
+CONFIG_GPIO_MCP23S08                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> GPIO Support >> USB GPIO expanders
+CONFIG_GPIO_VIPERBOARD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Generic Driver Options
+CONFIG_UEVENT_HELPER                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UEVENT_HELPER_PATH                       policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'powerpc': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_DEVTMPFS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEVTMPFS_MOUNT                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_STANDALONE                               policy<{'amd64': 'n', 'arm64': 'y', 'armhf': 'y', 'i386': 'n', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PREVENT_FIRMWARE_BUILD                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ALLOW_DEV_COREDUMP                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_DRIVER                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_DEVRES                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FENCE_TRACE                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_DEVTMPFS                                 note<ENFORCED> note<upstart requirement>
+CONFIG_DEVTMPFS_MOUNT                           note<ENFORCED> note<upstart requirement>
+CONFIG_FENCE_TRACE                              flag<DEBUG>
+
+# Menu: Device Drivers >> Generic Driver Options >> DMA Contiguous Memory Allocator
+CONFIG_DMA_CMA                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+#
+CONFIG_DMA_CMA                                  note<LP#1362261>
+
+# Menu: Device Drivers >> Generic Driver Options >> DMA Contiguous Memory Allocator >> Selected region size
+
+# Menu: Device Drivers >> Generic Driver Options >> Userspace firmware loading support
+CONFIG_FW_LOADER                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FIRMWARE_IN_KERNEL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_EXTRA_FIRMWARE                           policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'powerpc': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK           mark<ENFORCED> note<LP#1398458>
+
+# Menu: Device Drivers >> Generic Dynamic Voltage and Frequency Scaling (DVFS) support
+CONFIG_PM_DEVFREQ                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_GOV_PERFORMANCE                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_GOV_POWERSAVE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_GOV_USERSPACE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ARM_EXYNOS5_BUS_DEVFREQ                  policy<{'armhf': 'n'}>
+CONFIG_ARM_TEGRA_DEVFREQ                        policy<{'armhf-generic': 'm'}>
+
+# Menu: Device Drivers >> Generic Dynamic Voltage and Frequency Scaling (DVFS) support >> DEVFREQ-Event device Support
+CONFIG_PM_DEVFREQ_EVENT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU                policy<{'armhf': 'n'}>
+
+# Menu: Device Drivers >> Generic Target Core Mod (TCM) and ConfigFS Infrastructure
+CONFIG_TARGET_CORE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_IBLOCK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_FILEIO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_PSCSI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_USER2                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LOOPBACK_TARGET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_FC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ISCSI_TARGET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SBP_TARGET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Generic Thermal sysfs driver
+CONFIG_THERMAL                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_THERMAL_HWMON                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_OF                               policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_WRITABLE_TRIPS                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_FAIR_SHARE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_STEP_WISE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_BANG_BANG                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_USER_SPACE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CLOCK_THERMAL                            policy<{'arm64': 'n', 'armhf': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc64-emb': 'n'}>
+CONFIG_DEVFREQ_THERMAL                          policy<{'arm64': 'y', 'armhf': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_THERMAL_EMULATION                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ROCKCHIP_THERMAL                         policy<{'armhf': 'm'}>
+CONFIG_RCAR_THERMAL                             policy<{'armhf': 'm'}>
+CONFIG_DOVE_THERMAL                             policy<{'armhf': 'm'}>
+CONFIG_ARMADA_THERMAL                           policy<{'armhf': 'y'}>
+CONFIG_TEGRA_SOCTHERM                           policy<{'armhf-generic': 'n'}>
+CONFIG_INTEL_POWERCLAMP                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_PKG_TEMP_THERMAL                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SOC_DTS_THERMAL                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INT340X_THERMAL                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_PCH_THERMAL                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_QCOM_SPMI_TEMP_ALARM                     policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Generic Thermal sysfs driver >> Default Thermal governor
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Generic Thermal sysfs driver >> STMicroelectronics thermal drivers
+
+# Menu: Device Drivers >> Generic Thermal sysfs driver >> Samsung thermal drivers
+CONFIG_EXYNOS_THERMAL                           policy<{'armhf': 'y'}>
+
+# Menu: Device Drivers >> Generic Thermal sysfs driver >> Texas Instruments thermal drivers
+
+# Menu: Device Drivers >> Generic Thermal sysfs driver >> Texas Instruments thermal drivers >> Texas Instruments SoCs temperature sensor driver
+CONFIG_TI_SOC_THERMAL                           policy<{'armhf': 'm'}>
+CONFIG_TI_THERMAL                               policy<{'armhf': 'y'}>
+CONFIG_OMAP3_THERMAL                            policy<{'armhf-generic': 'y'}>
+CONFIG_OMAP4_THERMAL                            policy<{'armhf-generic': 'y'}>
+CONFIG_DRA752_THERMAL                           policy<{'armhf': 'y'}>
+
+# Menu: Device Drivers >> Generic Thermal sysfs driver >> generic cpu cooling support
+CONFIG_CPU_THERMAL                              policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISI_THERMAL                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX_THERMAL                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Generic powercap sysfs driver
+CONFIG_POWERCAP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INTEL_RAPL                               policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> Graphics support
+CONFIG_VGA_ARB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VGA_ARB_MAX_GPUS                         policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'powerpc': '16', 'ppc64el': '16'}>
+CONFIG_VGA_SWITCHEROO                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_TEGRA_HOST1X                             policy<{'armhf-generic': 'm'}>
+CONFIG_TEGRA_HOST1X_FIREWALL                    policy<{'armhf-generic': 'y'}>
+CONFIG_IMX_IPUV3_CORE                           policy<{'armhf': 'm'}>
+CONFIG_DRM_LOAD_EDID_FIRMWARE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> /dev/agpgart (AGP Support)
+CONFIG_AGP                                      policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_AGP_ALI                                  policy<{'i386': 'm'}>
+CONFIG_AGP_ATI                                  policy<{'i386': 'm'}>
+CONFIG_AGP_AMD                                  policy<{'i386': 'y'}>
+CONFIG_AGP_AMD64                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_AGP_INTEL                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_AGP_NVIDIA                               policy<{'i386': 'y'}>
+CONFIG_AGP_SIS                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_AGP_SWORKS                               policy<{'i386': 'm'}>
+CONFIG_AGP_VIA                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_AGP_UNINORTH                             policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_AGP_EFFICEON                             policy<{'i386': 'm'}>
+#
+CONFIG_AGP                                      note<not autoloadable> flag<REVIEW>
+
+# Menu: Device Drivers >> Graphics support >> Backlight & LCD device support
+CONFIG_BACKLIGHT_LCD_SUPPORT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+
+# Menu: Device Drivers >> Graphics support >> Backlight & LCD device support >> Lowlevel Backlight controls
+CONFIG_BACKLIGHT_CLASS_DEVICE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BACKLIGHT_GENERIC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LM3533                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_CARILLO_RANCH                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BACKLIGHT_PWM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_DA903X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_DA9052                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_MAX8925                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_APPLE                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BACKLIGHT_PM8941_WLED                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_SAHARA                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BACKLIGHT_WM831X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_ADP5520                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_ADP8860                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_ADP8870                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_88PM860X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_PCF50633                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_AAT2870                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LM3630A                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LM3639                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LP855X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LP8788                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_PANDORA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_SKY81452                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_TPS65217                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_AS3711                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_GPIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LV5207LP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_BD6107                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Backlight & LCD device support >> Lowlevel LCD controls
+CONFIG_LCD_CLASS_DEVICE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_L4F00242T03                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_LMS283GF05                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_LTV350QV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_ILI922X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_ILI9320                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_TDO24M                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_VGG2432A4                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_PLATFORM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_S6E63M0                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_LD9040                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_AMS369FG06                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_LMS501KF03                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_HX8357                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Bootup logo
+CONFIG_LOGO                                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Graphics support >> Console display driver support
+CONFIG_VGA_CONSOLE                              policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MDA_CONSOLE                              policy<{'i386': 'm'}>
+CONFIG_DUMMY_CONSOLE_COLUMNS                    policy<{'amd64': '80', 'arm64': '80', 'i386': '80', 'powerpc': '80', 'ppc64el': '80'}>
+CONFIG_DUMMY_CONSOLE_ROWS                       policy<{'amd64': '25', 'arm64': '25', 'i386': '25', 'powerpc': '25', 'ppc64el': '25'}>
+CONFIG_FRAMEBUFFER_CONSOLE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_FRAMEBUFFER_CONSOLE                      mark<ENFORCED> note<boot essential for grub2 console>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)
+CONFIG_DRM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_DP_AUX_CHARDEV                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_FBDEV_EMULATION                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_TDFX                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_R128                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_RADEON                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_RADEON_USERPTR                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DRM_RADEON_UMS                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DRM_I810                                 policy<{'amd64-generic': 'm', 'i386-generic': 'm'}>
+CONFIG_DRM_I915                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_MGA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_SIS                                  policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_VIA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_SAVAGE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_VGEM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_ROCKCHIP                             policy<{'armhf': 'm'}>
+CONFIG_ROCKCHIP_DW_HDMI                         policy<{'armhf': 'm'}>
+CONFIG_DRM_VMWGFX                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DRM_VMWGFX_FBCON                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_UDL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_AST                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_MGAG200                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DRM_CIRRUS_QEMU                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_ARMADA                               policy<{'armhf': 'm'}>
+CONFIG_DRM_ATMEL_HLCDC                          policy<{'armhf': 'm'}>
+CONFIG_DRM_RCAR_DU                              policy<{'armhf': 'm'}>
+CONFIG_DRM_RCAR_HDMI                            policy<{'armhf': 'y'}>
+CONFIG_DRM_RCAR_LVDS                            policy<{'armhf': 'y'}>
+CONFIG_DRM_SHMOBILE                             policy<{'armhf': 'm'}>
+CONFIG_DRM_OMAP                                 policy<{'armhf': 'n'}>
+CONFIG_DRM_TILCDC                               policy<{'armhf': 'm'}>
+CONFIG_DRM_TILCDC_SLAVE_COMPAT                  policy<{'armhf': 'y'}>
+CONFIG_DRM_QXL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_BOCHS                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DRM_VIRTIO_GPU                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_MSM                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_MSM_REGISTER_LOGGING                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_FSL_DCU                              policy<{'armhf': 'm'}>
+CONFIG_DRM_STI                                  policy<{'armhf': 'n'}>
+#
+CONFIG_DRM_MGAG200                              mark<ENFORCED> note<LP#1042903: CONFIG_DRM_MGAG200, experimental driver hangs boot on HP Proliant Gen8>
+CONFIG_DRM_BOCHS                                note<LP#1378648>
+CONFIG_DRM_STI                                  note<LP#1398458>
+CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT          note<LP:1473319>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> AMD GPU
+CONFIG_DRM_AMDGPU                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_AMDGPU_CIK                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DRM_AMDGPU_USERPTR                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_AMD_POWERPLAY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HSA_AMD                                  policy<{'amd64': 'm'}>
+#
+CONFIG_DRM_AMDGPU_CIK				note<LP:1510405>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> DRM Support for Freescale i.MX
+CONFIG_DRM_IMX                                  policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_FB_HELPER                        policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_PARALLEL_DISPLAY                 policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_TVE                              policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_LDB                              policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_HDMI                             policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> DRM Support for Samsung SoC EXYNOS Series
+CONFIG_DRM_EXYNOS                               policy<{'armhf': 'm'}>
+CONFIG_DRM_EXYNOS_FIMD                          policy<{'armhf': 'n'}>
+CONFIG_DRM_EXYNOS5433_DECON                     policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_VIDI                          policy<{'armhf': 'n'}>
+CONFIG_DRM_EXYNOS_G2D                           policy<{'armhf': 'n'}>
+CONFIG_DRM_EXYNOS_MIC                           policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS7_DECON                        policy<{'armhf': 'n'}>
+CONFIG_DRM_EXYNOS_DSI                           policy<{'armhf': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> DRM Support for Samsung SoC EXYNOS Series >> Image Post Processor
+CONFIG_DRM_EXYNOS_IPP                           policy<{'armhf': 'n'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> Display Interface Bridges
+CONFIG_DRM_DW_HDMI_AHB_AUDIO                    policy<{'armhf': 'm'}>
+CONFIG_DRM_NXP_PTN3460                          policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PARADE_PS8622                        policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> Display Panels
+CONFIG_DRM_PANEL_SIMPLE                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SAMSUNG_LD9040                 policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_LG_LG4573                      policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0                policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SHARP_LQ101R1SX01              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> Enable DSI support in MSM DRM driver
+CONFIG_DRM_MSM_DSI                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_PLL                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_28NM_PHY                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_20NM_PHY                     policy<{'arm64': 'y', 'armhf': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> I2C encoder or helper chips
+CONFIG_DRM_I2C_ADV7511                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_I2C_CH7006                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_I2C_SIL164                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_I2C_NXP_TDA998X                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> Intel GMA5/600 KMS Framebuffer
+CONFIG_DRM_GMA500                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DRM_GMA600                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_GMA3600                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_MEDFIELD                             policy<{'i386': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> NVIDIA Tegra DRM
+CONFIG_DRM_TEGRA                                policy<{'armhf-generic': 'm'}>
+CONFIG_DRM_TEGRA_FBDEV                          policy<{'armhf-generic': 'y'}>
+CONFIG_DRM_TEGRA_DEBUG                          policy<{'armhf-generic': 'n'}>
+CONFIG_DRM_TEGRA_STAGING                        policy<{'armhf-generic': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) >> Nouveau (NVIDIA) cards
+CONFIG_DRM_NOUVEAU                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NOUVEAU_PLATFORM_DRIVER                  policy<{'armhf-generic': 'y'}>
+CONFIG_NOUVEAU_DEBUG                            policy<{'amd64': '5', 'arm64': '5', 'armhf': '5', 'i386': '5', 'powerpc': '5', 'ppc64el': '5'}>
+CONFIG_NOUVEAU_DEBUG_DEFAULT                    policy<{'amd64': '3', 'arm64': '3', 'armhf': '3', 'i386': '3', 'powerpc': '3', 'ppc64el': '3'}>
+CONFIG_DRM_NOUVEAU_BACKLIGHT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices
+CONFIG_FB_SH_MOBILE_MERAM                       policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Exynos Video driver support
+CONFIG_EXYNOS_VIDEO                             policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_MIPI_DSI                          policy<{'armhf': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Marvell MMP Display Subsystem support
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> OMAP Display Device Drivers (new device model)
+CONFIG_DISPLAY_ENCODER_OPA362                   policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_ENCODER_TFP410                   policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_ENCODER_TPD12S015                policy<{'armhf': 'y'}>
+CONFIG_DISPLAY_CONNECTOR_DVI                    policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_CONNECTOR_HDMI                   policy<{'armhf': 'y'}>
+CONFIG_DISPLAY_CONNECTOR_ANALOG_TV              policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_PANEL_DPI                        policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_PANEL_DSI_CM                     policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_PANEL_SONY_ACX565AKM             policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02         policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01          policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1             policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1             policy<{'armhf': 'm'}>
+CONFIG_DISPLAY_PANEL_NEC_NL8048HL11             policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> OMAP2+ Display Subsystem support
+CONFIG_OMAP2_DSS                                policy<{'armhf': 'y'}>
+CONFIG_OMAP2_DSS_DEBUG                          policy<{'armhf': 'n'}>
+CONFIG_OMAP2_DSS_DEBUGFS                        policy<{'armhf': 'n'}>
+CONFIG_OMAP2_DSS_DPI                            policy<{'armhf': 'y'}>
+CONFIG_OMAP2_DSS_VENC                           policy<{'armhf': 'y'}>
+CONFIG_OMAP4_DSS_HDMI                           policy<{'armhf': 'y'}>
+CONFIG_OMAP5_DSS_HDMI                           policy<{'armhf': 'y'}>
+CONFIG_OMAP2_DSS_SDI                            policy<{'armhf': 'y'}>
+CONFIG_OMAP2_DSS_DSI                            policy<{'armhf': 'n'}>
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK                policy<{'armhf': '0'}>
+CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET         policy<{'armhf': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices
+CONFIG_FB                                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FIRMWARE_EDID                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MODE_HELPERS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_TILEBLITTING                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_CIRRUS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_PM2                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_PM2_FIFO_DISCONNECT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_ARMCLCD                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FB_IMX                                   policy<{'armhf-generic': 'm'}>
+CONFIG_FB_CYBER2000                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_CYBER2000_DDC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_ARC                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_OF                                    policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_CONTROL                               policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_FB_PLATINUM                              policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_FB_VALKYRIE                              policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_FB_CT65550                               policy<{'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_FB_ASILIANT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_IMSTT                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_VGA16                                 policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_UVESA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_VESA                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_FB_EFI                                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_FB_N411                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_HGA                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_OPENCORES                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_S1D13XXX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_I740                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_I810                                  policy<{'i386': 'm'}>
+CONFIG_FB_I810_GTF                              policy<{'i386': 'n'}>
+CONFIG_FB_LE80578                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_CARILLO_RANCH                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_INTEL                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_INTEL_DEBUG                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_FB_INTEL_I2C                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_FB_ATY128                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'y', 'ppc64el': 'm'}>
+CONFIG_FB_ATY128_BACKLIGHT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_S3                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_S3_DDC                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_SAVAGE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SAVAGE_I2C                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_SAVAGE_ACCEL                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_SIS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SIS_300                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_SIS_315                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_VIA                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_VIA_DIRECT_PROCFS                     policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_FB_VIA_X_COMPATIBILITY                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_FB_NEOMAGIC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_KYRO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_3DFX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_3DFX_ACCEL                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_3DFX_I2C                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_VOODOO1                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'y', 'ppc64el': 'm'}>
+CONFIG_FB_VT8623                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TRIDENT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_ARK                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_PM3                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_CARMINE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_FSL_DIU                               policy<{'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_FB_SH_MOBILE_LCDC                        policy<{'armhf': 'm'}>
+CONFIG_FB_TMIO                                  policy<{'armhf': 'm'}>
+CONFIG_FB_TMIO_ACCELL                           policy<{'armhf': 'y'}>
+CONFIG_FB_S3C                                   policy<{'armhf': 'm'}>
+CONFIG_FB_S3C_DEBUG_REGWRITE                    policy<{'armhf': 'n'}>
+CONFIG_FB_SM501                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SMSCUFX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_UDL                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'm', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_IBM_GXT4500                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'y'}>
+CONFIG_FB_PS3                                   policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_FB_PS3_DEFAULT_SIZE_M                    policy<{'powerpc-powerpc64-smp': '9'}>
+CONFIG_FB_DA8XX                                 policy<{'armhf-generic': 'm'}>
+CONFIG_FB_VIRTUAL                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_XEN_FBDEV_FRONTEND                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_FB_METRONOME                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_MB862XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_MB862XX_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MX3                                   policy<{'armhf-generic': 'y'}>
+CONFIG_FB_BROADSHEET                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_AUO_K190X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_AUO_K1900                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_AUO_K1901                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_MXS                                   policy<{'armhf-generic': 'm'}>
+CONFIG_FB_HYPERV                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_SIMPLE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_SSD1307                               policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SM712                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_FB_ATY128                                note<boot essential on powerpc>
+CONFIG_FB_VOODOO1                               note<boot essential on powerpc>
+CONFIG_FB_VIRTUAL                               flag<TESTING>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> AMD Geode family framebuffer support
+CONFIG_FB_GEODE                                 policy<{'i386': 'y'}>
+CONFIG_FB_GEODE_LX                              policy<{'i386': 'm'}>
+CONFIG_FB_GEODE_GX                              policy<{'i386': 'm'}>
+CONFIG_FB_GEODE_GX1                             policy<{'i386': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> ATI Mach64 display support
+CONFIG_FB_ATY                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_ATY_CT                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_ATY_GENERIC_LCD                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_ATY_GX                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_ATY_BACKLIGHT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> ATI Radeon display support
+CONFIG_FB_RADEON                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_RADEON_I2C                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_RADEON_BACKLIGHT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_RADEON_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> Amiga native chipset support
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> DRAM timing
+CONFIG_FB_CARMINE_DRAM_EVAL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CARMINE_DRAM_CUSTOM                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> Framebuffer foreign endianness support
+CONFIG_FB_FOREIGN_ENDIAN                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> Framebuffer foreign endianness support >> Choice endianness support
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> GDC variant
+CONFIG_FB_MB862XX_PCI_GDC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MB862XX_LIME                          policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> Matrox acceleration
+CONFIG_FB_MATROX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_MATROX_MILLENIUM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MATROX_MYSTIQUE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MATROX_G                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MATROX_I2C                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_MATROX_MAVEN                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> OMAP frame buffer support
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> OMAP2+ frame buffer support
+CONFIG_FB_OMAP2                                 policy<{'armhf': 'm'}>
+CONFIG_FB_OMAP2_DEBUG_SUPPORT                   policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_NUM_FBS                         policy<{'armhf': '3'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> PXA LCD framebuffer support
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> SBUS and UPA framebuffers
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> Size of ADV7393 frame buffer memory Single/Double Size
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> Video mode support
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> nVidia Framebuffer Support
+CONFIG_FB_NVIDIA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_NVIDIA_I2C                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_NVIDIA_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_NVIDIA_BACKLIGHT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices >> nVidia Riva support
+CONFIG_FB_RIVA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_RIVA_I2C                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_RIVA_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_RIVA_BACKLIGHT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> HID support
+
+# Menu: Device Drivers >> HID support >> HID bus support
+CONFIG_HID                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_BATTERY_STRENGTH                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HIDRAW                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_UHID                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GENERIC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> HID support >> HID bus support >> Special HID drivers
+CONFIG_HID_A4TECH                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ACRUX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ACRUX_FF                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_APPLE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_APPLEIR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_AUREAL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_BELKIN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_BETOP_FF                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CHERRY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CHICONY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CORSAIR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PRODIKEYS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CP2112                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CYPRESS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_DRAGONRISE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DRAGONRISE_FF                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_EMS_FF                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ELECOM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ELO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_EZKEY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GEMBIRD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GFRM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_HOLTEK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HOLTEK_FF                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_GT683R                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_KEYTOUCH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_KYE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_UCLOGIC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_WALTOP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GYRATION                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ICADE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_TWINHAN                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_KENSINGTON                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LCPOWER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LENOVO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MAGICMOUSE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MICROSOFT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MONTEREY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MULTITOUCH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_NTRIG                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ORTEK                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PANTHERLORD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PANTHERLORD_FF                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PENMOUNT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PETALYNX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PLANTRONICS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PRIMAX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ROCCAT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SAITEK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SAMSUNG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SONY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SONY_FF                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_SPEEDLINK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_STEELSERIES                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SUNPLUS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_RMI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GREENASIA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GREENASIA_FF                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_HYPERV_MOUSE                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HID_SMARTJOYPLUS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SMARTJOYPLUS_FF                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_TIVO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_TOPSEED                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_THINGM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_THRUSTMASTER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_THRUSTMASTER_FF                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_WACOM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_WIIMOTE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_XINMO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ZEROPLUS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ZEROPLUS_FF                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_ZYDACRON                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_HUB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_CUSTOM_SENSOR                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ALPS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> HID support >> HID bus support >> Special HID drivers >> Logitech devices
+CONFIG_HID_LOGITECH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LOGITECH_DJ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LOGITECH_HIDPP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LOGITECH_FF                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LOGIRUMBLEPAD2_FF                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LOGIG940_FF                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LOGIWHEELS_FF                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> HID support >> HID bus support >> Special HID drivers >> PicoLCD (graphic version)
+CONFIG_HID_PICOLCD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PICOLCD_FB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PICOLCD_BACKLIGHT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PICOLCD_LCD                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PICOLCD_LEDS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PICOLCD_CIR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> HID support >> I2C HID support
+CONFIG_I2C_HID                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> HID support >> USB HID support
+CONFIG_USB_HID                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PID                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_HIDDEV                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> HID support >> USB HID support >> USB HID Boot Protocol drivers
+CONFIG_USB_KBD                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MOUSE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> HSI support
+CONFIG_HSI                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_OMAP_SSI                                 policy<{'armhf-generic': 'm'}>
+CONFIG_NOKIA_MODEM                              policy<{'armhf-generic': 'm'}>
+CONFIG_CMT_SPEECH                               policy<{'armhf-generic': 'm'}>
+CONFIG_SSI_PROTOCOL                             policy<{'armhf-generic': 'm'}>
+CONFIG_HSI_CHAR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Hardware Monitoring support
+CONFIG_HWMON                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HWMON_DEBUG_CHIP                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SENSORS_ABITUGURU                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ABITUGURU3                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_AD7314                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_AD7414                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_AD7418                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1021                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1025                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1026                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1029                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1031                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM9240                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7310                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7410                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7411                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7462                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7470                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7475                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ASC7621                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_K8TEMP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_K10TEMP                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_FAM15H_POWER                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_APPLESMC                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ARM_SCPI                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SENSORS_ASB100                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ATXP1                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_DS620                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_DS1621                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_DELL_SMM                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_DA9052_ADC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_DA9055                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_I5K_AMB                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_F71805F                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_F71882FG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_F75375S                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MC13783_ADC                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_FSCHMD                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_GL518SM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_GL520SM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_G760A                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_G762                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_GPIO_FAN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_HIH6130                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IBMAEM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IBMPEX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IBMPOWERNV                       policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IIO_HWMON                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_I5500                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_CORETEMP                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_IT87                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_JC42                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_POWR1220                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LINEAGE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC2945                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4151                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4215                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4222                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4245                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4260                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4261                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX1111                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX16065                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX1619                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX1668                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX197                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6639                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6642                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6650                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6697                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX31790                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_HTU21                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MCP3021                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MENF21BMC_HWMON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADCXX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM63                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM70                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM73                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM75                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM77                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM78                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM80                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM83                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM85                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM87                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM90                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM92                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM93                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM95234                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM95241                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM95245                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_PC87360                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_PC87427                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_NTC_THERMISTOR                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_NCT6683                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_NCT6775                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_NCT7802                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_NCT7904                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_PCF8591                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_PWM_FAN                          policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SHT15                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SHT21                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SHTC1                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SIS5595                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_DME1737                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_EMC1403                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_EMC2103                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_EMC6W201                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SMSC47M1                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_SMSC47M192                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SMSC47B397                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_SCH5627                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_SCH5636                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_SMM665                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADC128D818                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADS1015                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADS7828                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADS7871                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_AMC6821                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_INA209                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_INA2XX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TC74                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_THMC50                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP102                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP103                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP401                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP421                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TWL4030_MADC                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_VEXPRESS                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SENSORS_VIA_CPUTEMP                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_VIA686A                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_VT1211                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_VT8231                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83781D                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83791D                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83792D                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83793                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83795                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83795_FANCTRL                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SENSORS_W83L785TS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83L786NG                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83627HF                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_W83627EHF                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_WM831X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_WM8350                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ACPI_POWER                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ATK0110                          policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> Hardware Monitoring support >> PMBus support
+CONFIG_PMBUS                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_PMBUS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1275                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM25066                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC2978                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC2978_REGULATOR                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SENSORS_MAX16064                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX20751                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX34440                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX8688                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TPS40422                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_UCD9000                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_UCD9200                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ZL6100                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Hardware Spinlock drivers
+CONFIG_HWSPINLOCK_OMAP                          policy<{'armhf': 'm'}>
+CONFIG_HWSPINLOCK_QCOM                          policy<{'arm64': 'm', 'armhf': 'm'}>
+
+# Menu: Device Drivers >> I2C support
+
+# Menu: Device Drivers >> I2C support >> I2C support
+CONFIG_I2C                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ACPI_I2C_OPREGION                        policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_I2C_COMPAT                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_I2C_CHARDEV                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_I2C_MUX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_HELPER_AUTO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_I2C_SMBUS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_STUB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SLAVE                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_I2C_SLAVE_EEPROM                         policy<{'armhf': 'm'}>
+CONFIG_I2C_DEBUG_CORE                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_I2C_DEBUG_ALGO                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_I2C_DEBUG_BUS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_I2C_CHARDEV                              note<LP:1417032>
+
+# Menu: Device Drivers >> I2C support >> I2C support >> I2C Algorithms
+CONFIG_I2C_ALGOBIT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_ALGOPCA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> I2C support >> I2C support >> I2C Hardware Bus support
+CONFIG_I2C_ALI1535                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_ALI1563                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_ALI15X3                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_AMD756                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_AMD756_S4882                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I2C_AMD8111                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_HIX5HD2                              policy<{'armhf': 'm'}>
+CONFIG_I2C_I801                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_ISCH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_ISMT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I2C_PIIX4                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_NFORCE2                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_NFORCE2_S4985                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I2C_SIS5595                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SIS630                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SIS96X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_VIA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_VIAPRO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SCMI                                 policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_I2C_HYDRA                                policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_I2C_POWERMAC                             policy<{'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y'}>
+CONFIG_I2C_AXXIA                                policy<{'armhf-generic-lpae': 'm'}>
+CONFIG_I2C_BCM_IPROC                            policy<{'arm64': 'm'}>
+CONFIG_I2C_CADENCE                              policy<{'arm64': 'm'}>
+CONFIG_I2C_CBUS_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_CPM                                  policy<{'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_I2C_DESIGNWARE_PLATFORM                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_DESIGNWARE_PCI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_DESIGNWARE_BAYTRAIL                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_I2C_EG20T                                policy<{'i386': 'm'}>
+CONFIG_I2C_EMEV2                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_I2C_EXYNOS5                              policy<{'armhf': 'm'}>
+CONFIG_I2C_GPIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_IMX                                  policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_I2C_KEMPLD                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MESON                                policy<{'armhf': 'm'}>
+CONFIG_I2C_MPC                                  policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MT65XX                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_MV64XXX                              policy<{'armhf': 'm'}>
+CONFIG_I2C_NOMADIK                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_OCORES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_OMAP                                 policy<{'armhf': 'y'}>
+CONFIG_I2C_PASEMI                               policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_I2C_PCA_PLATFORM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_QUP                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_RIIC                                 policy<{'armhf': 'm'}>
+CONFIG_I2C_RK3X                                 policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_I2C_S3C2410                              policy<{'armhf': 'y'}>
+CONFIG_I2C_SH_MOBILE                            policy<{'armhf': 'm'}>
+CONFIG_I2C_SIMTEC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_TEGRA                                policy<{'armhf-generic': 'm'}>
+CONFIG_I2C_UNIPHIER                             policy<{'armhf': 'm'}>
+CONFIG_I2C_UNIPHIER_F                           policy<{'armhf': 'm'}>
+CONFIG_I2C_VERSATILE                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_THUNDERX                             policy<{'arm64': 'm'}>
+CONFIG_I2C_XILINX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_RCAR                                 policy<{'armhf': 'm'}>
+CONFIG_I2C_DIOLAN_U2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_DLN2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_PARPORT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_PARPORT_LIGHT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_ROBOTFUZZ_OSIF                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_TAOS_EVM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_TINY_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_VIPERBOARD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_PCA_ISA                              policy<{'i386': 'm'}>
+CONFIG_I2C_CROS_EC_TUNNEL                       policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_I2C_XGENE_SLIMPRO                        policy<{'arm64': 'm'}>
+CONFIG_SCx200_ACB                               policy<{'i386': 'm'}>
+CONFIG_I2C_OPAL                                 policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_I2C_THUNDERX                             note<LP:1688132>
+
+# Menu: Device Drivers >> I2C support >> I2C support >> Multiplexer I2C Chip support
+CONFIG_I2C_ARB_GPIO_CHALLENGE                   policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MUX_GPIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MUX_PCA9541                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MUX_PCA954x                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MUX_PINCTRL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_I2C_MUX_REG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> IEEE 1394 (FireWire) support
+CONFIG_FIREWIRE_NOSY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+
+# Menu: Device Drivers >> IEEE 1394 (FireWire) support >> FireWire driver stack
+CONFIG_FIREWIRE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FIREWIRE_OHCI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FIREWIRE_SBP2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FIREWIRE_NET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> IOMMU Hardware Support
+CONFIG_IOMMU_SUPPORT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FSL_PAMU                                 policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_AMD_IOMMU                                policy<{'amd64': 'y'}>
+CONFIG_AMD_IOMMU_STATS                          policy<{'amd64': 'y'}>
+CONFIG_AMD_IOMMU_V2                             policy<{'amd64': 'm'}>
+CONFIG_IRQ_REMAP                                policy<{'amd64': 'y'}>
+CONFIG_OMAP_IOMMU                               policy<{'armhf': 'y'}>
+CONFIG_OMAP_IOMMU_DEBUG                         policy<{'armhf': 'n'}>
+CONFIG_ROCKCHIP_IOMMU                           policy<{'armhf': 'y'}>
+CONFIG_TEGRA_IOMMU_GART                         policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_IOMMU_SMMU                         policy<{'armhf-generic': 'y'}>
+CONFIG_EXYNOS_IOMMU                             policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_IOMMU_DEBUG                       policy<{'armhf': 'n'}>
+CONFIG_SHMOBILE_IOMMU                           policy<{'armhf': 'y'}>
+CONFIG_IPMMU_VMSA                               policy<{'armhf-generic-lpae': 'y'}>
+CONFIG_SPAPR_TCE_IOMMU                          policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_ARM_SMMU                                 policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_ARM_SMMU_V3                              policy<{'arm64': 'y'}>
+
+# Menu: Device Drivers >> IOMMU Hardware Support >> Generic IOMMU Pagetable Support
+CONFIG_IOMMU_IO_PGTABLE_LPAE                    policy<{'arm64': 'y', 'armhf-generic': 'n', 'armhf-generic-lpae': 'y'}>
+CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST           policy<{'arm64': 'n', 'armhf-generic-lpae': 'n'}>
+
+# Menu: Device Drivers >> IOMMU Hardware Support >> IPMMU/IPMMUI address space size
+CONFIG_SHMOBILE_IOMMU_ADDRSIZE_2048MB           policy<{'armhf': 'y'}>
+CONFIG_SHMOBILE_IOMMU_ADDRSIZE_1024MB           policy<{'armhf': 'n'}>
+CONFIG_SHMOBILE_IOMMU_ADDRSIZE_512MB            policy<{'armhf': 'n'}>
+CONFIG_SHMOBILE_IOMMU_ADDRSIZE_256MB            policy<{'armhf': 'n'}>
+CONFIG_SHMOBILE_IOMMU_ADDRSIZE_128MB            policy<{'armhf': 'n'}>
+CONFIG_SHMOBILE_IOMMU_ADDRSIZE_64MB             policy<{'armhf': 'n'}>
+CONFIG_SHMOBILE_IOMMU_ADDRSIZE_32MB             policy<{'armhf': 'n'}>
+
+# Menu: Device Drivers >> IOMMU Hardware Support >> Support for Intel IOMMU using DMA Remapping Devices
+CONFIG_INTEL_IOMMU                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_IOMMU_SVM                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_IOMMU_DEFAULT_ON                   policy<{'amd64': 'n', 'i386': 'n'}>
+#
+CONFIG_INTEL_IOMMU_DEFAULT_ON                   note<the IOMMU can trigger boot failures> flag<REVIEW>
+
+# Menu: Device Drivers >> ISDN support
+CONFIG_ISDN                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HYSDN                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HYSDN_CAPI                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> ISDN support >> CAPI 2.0 subsystem
+CONFIG_ISDN_CAPI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAPI_TRACE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_CAPI_CAPI20                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_CAPI_MIDDLEWARE                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_CAPI_CAPIDRV                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> ISDN support >> CAPI 2.0 subsystem >> Active AVM cards
+CONFIG_CAPI_AVM                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_DRV_AVMB1_B1ISA                     policy<{'i386': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_B1PCI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_DRV_AVMB1_T1ISA                     policy<{'i386': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA                  policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_AVM_CS                    policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_T1PCI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_C4                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> ISDN support >> CAPI 2.0 subsystem >> Active Eicon DIVA Server cards
+CONFIG_CAPI_EICON                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> ISDN support >> CAPI 2.0 subsystem >> Active Eicon DIVA Server cards >> Support Eicon DIVA Server cards
+CONFIG_ISDN_DIVAS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_DIVAS_BRIPCI                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_DIVAS_PRIPCI                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_DIVAS_DIVACAPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_DIVAS_USERIDI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_DIVAS_MAINT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> ISDN support >> Modular ISDN driver
+CONFIG_MISDN                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_DSP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_L1OIP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_HFCPCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_HFCMULTI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_HFCUSB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_AVMFRITZ                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_SPEEDFAX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_INFINEON                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_W6692                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_NETJET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> ISDN support >> Old ISDN4Linux (deprecated)
+CONFIG_ISDN_I4L                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_AUDIO                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_TTY_FAX                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_X25                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_ISDN_I4L                                 flag<REVIEW>
+
+# Menu: Device Drivers >> ISDN support >> Old ISDN4Linux (deprecated) >> Active cards
+CONFIG_ISDN_DRV_ICN                             policy<{'i386': 'm'}>
+CONFIG_ISDN_DRV_PCBIT                           policy<{'i386': 'm'}>
+CONFIG_ISDN_DRV_SC                              policy<{'i386': 'm'}>
+CONFIG_ISDN_DRV_ACT2000                         policy<{'i386': 'm'}>
+
+# Menu: Device Drivers >> ISDN support >> Old ISDN4Linux (deprecated) >> ISDN feature submodules
+CONFIG_ISDN_DIVERSION                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> ISDN support >> Old ISDN4Linux (deprecated) >> Passive cards
+
+# Menu: Device Drivers >> ISDN support >> Old ISDN4Linux (deprecated) >> Passive cards >> HiSax SiemensChipSet driver support
+CONFIG_ISDN_DRV_HISAX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HISAX_1TR6                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_NI1                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_MAX_CARDS                          policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8'}>
+CONFIG_HISAX_16_0                               policy<{'i386': 'y'}>
+CONFIG_HISAX_16_3                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_TELESPCI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_HISAX_S0BOX                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_AVM_A1                             policy<{'i386': 'y'}>
+CONFIG_HISAX_FRITZPCI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_HISAX_AVM_A1_PCMCIA                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_ELSA                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_IX1MICROR2                         policy<{'i386': 'y'}>
+CONFIG_HISAX_DIEHLDIVA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_ASUSCOM                            policy<{'i386': 'y'}>
+CONFIG_HISAX_TELEINT                            policy<{'i386': 'y'}>
+CONFIG_HISAX_HFCS                               policy<{'i386': 'y'}>
+CONFIG_HISAX_SEDLBAUER                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_SPORTSTER                          policy<{'i386': 'y'}>
+CONFIG_HISAX_MIC                                policy<{'i386': 'y'}>
+CONFIG_HISAX_NETJET                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HISAX_NETJET_U                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HISAX_NICCY                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_ISURF                              policy<{'i386': 'y'}>
+CONFIG_HISAX_HSTSAPHIR                          policy<{'i386': 'y'}>
+CONFIG_HISAX_BKM_A4T                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_SCT_QUADRO                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_GAZEL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_HFC_PCI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_HISAX_W6692                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_HFC_SX                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_ENTERNOW_PCI                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HISAX_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_HISAX_SEDLBAUER_CS                       policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_HISAX_ELSA_CS                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_HISAX_AVM_A1_CS                          policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_HISAX_TELES_CS                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_HISAX_ST5481                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HISAX_HFCUSB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HISAX_HFC4S8S                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HISAX_FRITZ_PCIPNP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> ISDN support >> Old ISDN4Linux (deprecated) >> Passive cards >> HiSax SiemensChipSet driver support >> HiSax Support for EURO/DSS1
+CONFIG_HISAX_EURO                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DE_AOC                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HISAX_NO_SENDCOMPLETE                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_HISAX_NO_LLC                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_HISAX_NO_KEYPAD                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> ISDN support >> Old ISDN4Linux (deprecated) >> Support synchronous PPP
+CONFIG_ISDN_PPP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_PPP_VJ                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_MPP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IPPP_FILTER                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_PPP_BSDCOMP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> ISDN support >> Siemens Gigaset support
+CONFIG_ISDN_DRV_GIGASET                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GIGASET_CAPI                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_GIGASET_BASE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GIGASET_M105                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GIGASET_M101                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GIGASET_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Industrial I/O support
+CONFIG_IIO                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IIO_BUFFER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IIO_BUFFER_CB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_KFIFO_BUF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_TRIGGER                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IIO_CONSUMERS_PER_TRIGGER                policy<{'amd64': '2', 'arm64': '2', 'armhf': '2', 'i386': '2', 'powerpc': '2', 'ppc64el': '2'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Accelerometers
+CONFIG_BMA180                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BMC150_ACCEL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_ACCEL_3D                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_ACCEL_3AXIS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KXSD9                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KXCJK1013                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA8452                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA9551                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA9553                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MXC4005                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_STK8312                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_STK8BA50                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Amplifiers
+CONFIG_AD8366                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Analog to digital converters
+CONFIG_AD7266                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7291                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7298                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7476                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7791                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7793                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7887                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7923                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD799X                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AXP288_ADC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BERLIN2_ADC                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CC10001_ADC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_DA9150_GPADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EXYNOS_ADC                               policy<{'armhf': 'm'}>
+CONFIG_HI8435                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LP8788_ADC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX1027                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX1363                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP320X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP3422                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEN_Z188_ADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NAU7802                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_SPMI_IADC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_SPMI_VADC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ROCKCHIP_SARADC                          policy<{'armhf': 'm'}>
+CONFIG_TI_ADC081C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADC128S052                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_AM335X_ADC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TWL4030_MADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TWL6030_GPADC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VF610_ADC                                policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIPERBOARD_ADC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Chemical Sensors
+CONFIG_VZ89X                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Digital gyroscope sensors
+CONFIG_ADIS16080                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16130                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16136                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16260                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADXRS450                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BMG160                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_GYRO_3D                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_GYRO_3AXIS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ITG3200                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Digital potentiometers
+CONFIG_MCP4531                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Digital to analog converters
+CONFIG_AD5064                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5360                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5380                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5421                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5446                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5449                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5592R                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5593R                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5504                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5624R_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5686                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5755                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5764                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5791                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7303                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_M62332                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX517                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX5821                                  policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP4725                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP4922                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Frequency Synthesizers DDS/PLL
+
+# Menu: Device Drivers >> Industrial I/O support >> Frequency Synthesizers DDS/PLL >> Clock Generator/Distribution
+CONFIG_AD9523                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Frequency Synthesizers DDS/PLL >> Phase-Locked Loop (PLL) frequency synthesizers
+CONFIG_ADF4350                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Hid Sensor IIO Common
+CONFIG_HID_SENSOR_IIO_COMMON                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_IIO_TRIGGER                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Humidity sensors
+CONFIG_DHT11                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDC100X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HTS221                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HTU21                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SI7005                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SI7020                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Inclinometer sensors
+CONFIG_HID_SENSOR_INCLINOMETER_3D               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_DEVICE_ROTATION               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Inertial measurement units
+CONFIG_ADIS16400                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16480                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KMX61                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INV_MPU6050_IIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Light sensors
+CONFIG_ACPI_ALS                                 policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ADJD_S311                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AL3320A                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_APDS9300                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_APDS9960                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BH1750                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CM32181                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CM3232                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CM3323                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CM36651                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GP2AP020A00F                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISL29125                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_ALS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_PROX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JSA1212                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RPR0521                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM3533                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LTR501                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_OPT3001                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PA12203001                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_STK3310                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TCS3414                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TCS3472                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TSL2563                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TSL4531                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_US5182D                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VCNL4000                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Lightning sensors
+CONFIG_AS3935                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Magnetometer sensors
+CONFIG_AK8975                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AK09911                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAG3110                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_MAGNETOMETER_3D               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC35240                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_MAGN_3AXIS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BMC150_MAGN                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Pressure sensors
+CONFIG_BMP280                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_PRESS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MPL115                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MPL3115                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MS5611                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MS5611_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MS5611_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MS5637                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_PRESS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_T5403                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Proximity sensors
+CONFIG_LIDAR_LITE_V2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SX9500                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> SSP Sensor Common
+CONFIG_IIO_SSP_SENSORS_COMMONS                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SSP_SENSORHUB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Temperature sensors
+CONFIG_MLX90614                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TMP006                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TSYS01                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TSYS02D                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Industrial I/O support >> Triggers - standalone
+CONFIG_IIO_INTERRUPT_TRIGGER                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SYSFS_TRIGGER                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> IndustryPack bus support
+CONFIG_IPACK_BUS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BOARD_TPCI200                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_IPOCTAL                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> InfiniBand support
+CONFIG_INFINIBAND                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_USER_MAD                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_USER_ACCESS                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_ON_DEMAND_PAGING              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INFINIBAND_MTHCA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_MTHCA_DEBUG                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INFINIBAND_QIB                           policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INFINIBAND_QIB_DCA                       policy<{'amd64': 'y'}>
+CONFIG_INFINIBAND_CXGB3                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_CXGB3_DEBUG                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_INFINIBAND_CXGB4                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MLX4_INFINIBAND                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX5_INFINIBAND                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_NES                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INFINIBAND_NES_DEBUG                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_INFINIBAND_OCRDMA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INFINIBAND_USNIC                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INFINIBAND_IPOIB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_IPOIB_CM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INFINIBAND_IPOIB_DEBUG                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INFINIBAND_SRP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_SRPT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_ISER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_ISERT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> Input device support
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...)
+CONFIG_INPUT                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INPUT_LEDS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_FF_MEMLESS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_POLLDEV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_SPARSEKMAP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MATRIXKMAP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_JOYDEV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_EVDEV                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_INPUT_EVBUG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_APMPOWER                           policy<{'powerpc-powerpc-smp': 'm'}>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Joysticks/Gamepads
+CONFIG_INPUT_JOYSTICK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JOYSTICK_ANALOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_A3D                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_ADI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_COBRA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GF2K                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GRIP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GRIP_MP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GUILLEMOT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_INTERACT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_SIDEWINDER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_TMDC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_IFORCE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_IFORCE_USB                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JOYSTICK_IFORCE_232                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JOYSTICK_WARRIOR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_MAGELLAN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_SPACEORB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_SPACEBALL                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_STINGER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_TWIDJOY                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_ZHENHUA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_DB9                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GAMECON                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_TURBOGRAFX                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_AS5011                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_JOYDUMP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_XPAD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_XPAD_FF                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JOYSTICK_XPAD_LEDS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JOYSTICK_WALKERA0701                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Keyboards
+CONFIG_INPUT_KEYBOARD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_KEYBOARD_ADP5520                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_ADP5588                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_ADP5589                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_ATKBD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_KEYBOARD_QT1070                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_QT2160                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_LKKBD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_GPIO_POLLED                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TCA6416                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TCA8418                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MATRIX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_LM8323                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_LM8333                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MAX7359                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MCS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MPR121                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_SNVS_PWRKEY                     policy<{'armhf-generic': 'm'}>
+CONFIG_KEYBOARD_IMX                             policy<{'armhf-generic': 'm'}>
+CONFIG_KEYBOARD_NEWTON                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TEGRA                           policy<{'armhf-generic': 'm'}>
+CONFIG_KEYBOARD_OPENCORES                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_PMIC8XXX                        policy<{'armhf': 'm'}>
+CONFIG_KEYBOARD_SAMSUNG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_KEYBOARD_STOWAWAY                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_SUNKBD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_SH_KEYSC                        policy<{'armhf': 'm'}>
+CONFIG_KEYBOARD_STMPE                           policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_OMAP4                           policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TC3589X                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TWL4030                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_XTKBD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_CROS_EC                         policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_KEYBOARD_CAP11XX                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_BCM                             policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Mice
+CONFIG_INPUT_MOUSE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_SERIAL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_APPLETOUCH                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_BCM5974                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_CYAPA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_ELAN_I2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_ELAN_I2C_I2C                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_ELAN_I2C_SMBUS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_INPORT                             policy<{'i386': 'n'}>
+CONFIG_MOUSE_LOGIBM                             policy<{'i386': 'm'}>
+CONFIG_MOUSE_PC110PAD                           policy<{'i386': 'm'}>
+CONFIG_MOUSE_VSXXXAA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_GPIO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_SYNAPTICS_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_SYNAPTICS_USB                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_MOUSE_INPORT                             note<very old ISA based mouse support>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Mice >> PS/2 mouse
+CONFIG_MOUSE_PS2                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_PS2_ALPS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_LOGIPS2PP                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_SYNAPTICS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_CYPRESS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_LIFEBOOK                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MOUSE_PS2_TRACKPOINT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_ELANTECH                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_SENTELIC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_TOUCHKIT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_FOCALTECH                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_VMMOUSE                        policy<{'amd64': 'y', 'i386': 'y'}>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Miscellaneous devices
+CONFIG_INPUT_MISC                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_INPUT_88PM860X_ONKEY                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_88PM80X_ONKEY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_AD714X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_AD714X_I2C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_AD714X_SPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ARIZONA_HAPTICS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_BMA150                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_E3X0_BUTTON                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PCSPKR                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PM8941_PWRKEY                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_INPUT_PM8XXX_VIBRATOR                    policy<{'armhf': 'm'}>
+CONFIG_INPUT_PMIC8XXX_PWRKEY                    policy<{'armhf': 'm'}>
+CONFIG_INPUT_MAX77693_HAPTIC                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MAX8925_ONKEY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MAX8997_HAPTIC                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MC13783_PWRBUTTON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MMA8450                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MPU3050                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_APANEL                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INPUT_GP2A                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_GPIO_BEEPER                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_GPIO_TILT_POLLED                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_WISTRON_BTNS                       policy<{'i386': 'm'}>
+CONFIG_INPUT_ATLAS_BTNS                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INPUT_ATI_REMOTE2                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_KEYSPAN_REMOTE                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_KXTJ9                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_KXTJ9_POLLED_MODE                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_INPUT_POWERMATE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_YEALINK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_CM109                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_REGULATOR_HAPTIC                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_RETU_PWRBUTTON                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_TPS65218_PWRBUTTON                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_AXP20X_PEK                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_TWL4030_PWRBUTTON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_TWL4030_VIBRA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_TWL6040_VIBRA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_UINPUT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_INPUT_PALMAS_PWRBUTTON                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PCF50633_PMU                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PCF8574                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PWM_BEEPER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_GPIO_ROTARY_ENCODER                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DA9052_ONKEY                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DA9055_ONKEY                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DA9063_ONKEY                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_WM831X_ON                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PCAP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ADXL34X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ADXL34X_I2C                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ADXL34X_SPI                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_IMS_PCU                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_CMA3000                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_CMA3000_I2C                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_XEN_KBDDEV_FRONTEND                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_INPUT_IDEAPAD_SLIDEBAR                   policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_SOC_BUTTON_ARRAY                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DRV260X_HAPTICS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DRV2665_HAPTICS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DRV2667_HAPTICS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_INPUT_UINPUT                             mark<ENFORCED> note<LP:584812>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Mouse interface
+CONFIG_INPUT_MOUSEDEV                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_INPUT_MOUSEDEV_PSAUX                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_INPUT_MOUSEDEV_SCREEN_X                  policy<{'amd64': '1024', 'arm64': '1024', 'armhf': '1024', 'i386': '1024', 'powerpc': '1024', 'ppc64el': '1024'}>
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y                  policy<{'amd64': '768', 'arm64': '768', 'armhf': '768', 'i386': '768', 'powerpc': '768', 'ppc64el': '768'}>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Tablets
+CONFIG_INPUT_TABLET                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TABLET_USB_ACECAD                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_AIPTEK                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_GTCO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_HANWANG                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_KBTAB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_SERIAL_WACOM4                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Touchscreens
+CONFIG_INPUT_TOUCHSCREEN                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_88PM860X                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ADS7846                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AD7877                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AD7879                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AD7879_I2C                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AD7879_SPI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AR1021_I2C                   policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ATMEL_MXT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AUO_PIXCIR                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_BU21013                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CHIPONE_ICN8318              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CY8CTMG110                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP_CORE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP_I2C                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP_SPI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP4_CORE                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP4_I2C                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP4_SPI                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_DA9034                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_DA9052                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_DYNAPRO                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_HAMPSHIRE                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EETI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EGALAX                       policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_FT6236                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_FUJITSU                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_GOODIX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ILI210X                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_IPROC                        policy<{'arm64': 'm'}>
+CONFIG_TOUCHSCREEN_GUNZE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ELAN                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_ELO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WACOM_W8001                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WACOM_I2C                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MAX11801                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MCS5000                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MMS114                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MTOUCH                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_IMX6UL_TSC                   policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_INEXIO                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_INTEL_MID                    policy<{'i386': 'm'}>
+CONFIG_TOUCHSCREEN_MK712                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_HTCPEN                       policy<{'i386': 'm'}>
+CONFIG_TOUCHSCREEN_PENMOUNT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EDT_FT5X06                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TOUCHRIGHT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TOUCHWIN                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TI_AM335X_TSC                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_UCB1400                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_PIXCIR                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WDT87XX_I2C                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WM831X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MC13783                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TOUCHIT213                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TSC_SERIO                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TSC2004                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TSC2005                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TSC2007                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_PCAP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ST1232                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_STMPE                        policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_SUR40                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_SX8654                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TPS6507X                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ZFORCE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_COLIBRI_VF50                 policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ROHM_BU21023                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Touchscreens >> Support for WM97xx AC97 touchscreen controllers
+CONFIG_TOUCHSCREEN_WM97XX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WM9705                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_WM9712                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_WM9713                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Touchscreens >> USB Touchscreen Driver
+CONFIG_TOUCHSCREEN_USB_COMPOSITE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_USB_EGALAX                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_PANJIT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_3M                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ITM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ETURBO                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_GUNZE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_DMC_TSC10                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_IRTOUCH                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_IDEALTEK                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_GOTOP                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_JASTEC                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ELO                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_E2I                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ZYTRONIC                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ETT_TC45USB              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_NEXIO                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_EASYTOUCH                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Input device support >> Hardware I/O ports
+
+# Menu: Device Drivers >> Input device support >> Hardware I/O ports >> Gameport support
+CONFIG_GAMEPORT                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GAMEPORT_NS558                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GAMEPORT_L4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GAMEPORT_EMU10K1                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GAMEPORT_FM801                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Input device support >> Hardware I/O ports >> Serial I/O support
+CONFIG_SERIO                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SERIO_I8042                              policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIO_SERPORT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_CT82C710                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SERIO_PARKBD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_AMBAKMI                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SERIO_PCIPS2                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_LIBPS2                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIO_RAW                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_XILINX_XPS_PS2                     policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_ALTERA_PS2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_PS2MULT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_ARC_PS2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_APBPS2                             policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HYPERV_KEYBOARD                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_USERIO                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Intel(R) Trace Hub controller
+CONFIG_INTEL_TH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_GTH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_STH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_MSU                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_PTI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Device Drivers >> LED Support
+CONFIG_NEW_LEDS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_LEDS_LP55XX_COMMON                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> LED Support >> LED Class Support
+CONFIG_LEDS_CLASS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_88PM860X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_BCM6328                             policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_BCM6358                             policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3530                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3533                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3642                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_NET48XX                             policy<{'i386': 'm'}>
+CONFIG_LEDS_WRAP                                policy<{'i386': 'm'}>
+CONFIG_LEDS_PCA9532                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_PCA9532_GPIO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_GPIO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP3944                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP5521                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP5523                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP5562                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP8501                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP8788                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP8860                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_CLEVO_MAIL                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LEDS_PCA955X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_PCA963X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_WM831X_STATUS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_WM8350                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_DA903X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_DA9052                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_DAC124S085                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_PWM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_REGULATOR                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_BD2802                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_INTEL_SS4200                        policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_LEDS_LT3593                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_ADP5520                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_DELL_NETBOOKS                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LEDS_MC13783                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_NS2                                 policy<{'armhf': 'm'}>
+CONFIG_LEDS_ASIC3                               policy<{'armhf': 'y'}>
+CONFIG_LEDS_TCA6507                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TLC591XX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_MAX8997                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM355x                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_OT200                               policy<{'i386': 'm'}>
+CONFIG_LEDS_MENF21BMC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_BLINKM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_POWERNV                             policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_SYSCON                              policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> LED Support >> LED Class Support >> LED Flash Class Support
+CONFIG_LEDS_CLASS_FLASH                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_AAT1290                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_LEDS_MAX77693                            policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_KTD2692                             policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> LED Support >> LED Class Support >> LED Trigger support
+CONFIG_LEDS_TRIGGERS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_TRIGGER_TIMER                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_ONESHOT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_HEARTBEAT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_BACKLIGHT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_CPU                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_TRIGGER_GPIO                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_DEFAULT_ON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_TRANSIENT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_CAMERA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> MCB support
+CONFIG_MCB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MCB_PCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> MIPS Platform Specific Device Drivers
+
+# Menu: Device Drivers >> MMC/SD/SDIO card support
+CONFIG_MMC                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MMC_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MMC_BLOCK                                policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_BLOCK_MINORS                         policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8'}>
+CONFIG_MMC_BLOCK_BOUNCE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SDIO_UART                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_TEST                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MMC_ARMMMCI                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_QCOM_DML                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_OMAP                                 policy<{'armhf': 'm'}>
+CONFIG_MMC_OMAP_HS                              policy<{'armhf': 'y'}>
+CONFIG_MMC_WBSD                                 policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_MXC                                  policy<{'armhf-generic': 'm'}>
+CONFIG_MMC_TIFM_SD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_MVSDIO                               policy<{'armhf': 'm'}>
+CONFIG_MMC_SPI                                  policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDRICOH_CS                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_MMC_TMIO                                 policy<{'armhf': 'm'}>
+CONFIG_MMC_SDHI                                 policy<{'armhf': 'm'}>
+CONFIG_MMC_CB710                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_VIA_SDMMC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SH_MMCIF                             policy<{'armhf': 'm'}>
+CONFIG_MMC_VUB300                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_USHC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_USDHI6ROL0                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_REALTEK_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_REALTEK_USB                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_TOSHIBA_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_MTK                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_MMC_BLOCK                                note<boot essential on armhf/arm64>
+CONFIG_MMC_TEST                                 flag<TESTING>
+CONFIG_MMC_OMAP_HS                              note<boot essential on arm>
+
+# Menu: Device Drivers >> MMC/SD/SDIO card support >> Samsung S3C SD/MMC transfer code
+
+# Menu: Device Drivers >> MMC/SD/SDIO card support >> Secure Digital Host Controller Interface support
+CONFIG_MMC_SDHCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_PCI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_RICOH_MMC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MMC_SDHCI_ACPI                           policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_MMC_SDHCI_S3C                            policy<{'armhf': 'm'}>
+CONFIG_MMC_SDHCI_S3C_DMA                        policy<{'armhf': 'y'}>
+#
+CONFIG_MMC_SDHCI                                note<installation essential on omap/highbank>
+
+# Menu: Device Drivers >> MMC/SD/SDIO card support >> Secure Digital Host Controller Interface support >> SDHCI platform and OF driver helper
+CONFIG_MMC_SDHCI_PLTFM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_OF_ARASAN                      policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_OF_AT91                        policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_OF_ESDHC                       policy<{'arm64': 'm', 'armhf-generic': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_OF_HLWD                        policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_ESDHC_IMX                      policy<{'armhf-generic': 'y'}>
+CONFIG_MMC_SDHCI_DOVE                           policy<{'armhf': 'm'}>
+CONFIG_MMC_SDHCI_TEGRA                          policy<{'armhf-generic': 'm'}>
+CONFIG_MMC_SDHCI_PXAV3                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SDHCI_F_SDH30                        policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_IPROC                          policy<{'arm64': 'm'}>
+CONFIG_MMC_SDHCI_MSM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+#
+CONFIG_MMC_SDHCI_PLTFM                          note<boot essential on highbank>
+
+# Menu: Device Drivers >> MMC/SD/SDIO card support >> Synopsys DesignWare Memory Card Interface
+CONFIG_MMC_DW                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_PLTFM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_EXYNOS                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_K3                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_PCI                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_ROCKCHIP                          policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Macintosh device drivers
+CONFIG_MACINTOSH_DRIVERS                        policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PMAC_SMU                                 policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PMAC_MEDIABAY                            policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_MAC_EMUMOUSEBTN                          policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_THERM_WINDTUNNEL                         policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_THERM_ADT746X                            policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_PMAC_RACKMETER                           policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+#
+CONFIG_THERM_ADT746X                            mark<ENFORCED> note<LP:#923094>
+
+# Menu: Device Drivers >> Macintosh device drivers >> Apple Desktop Bus (ADB) support
+CONFIG_ADB                                      policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_ADB_CUDA                                 policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_ADB_MACIO                                policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_INPUT_ADBHID                             policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_ANSLCD                                   policy<{'powerpc-powerpc-smp': 'm'}>
+
+# Menu: Device Drivers >> Macintosh device drivers >> New PowerMac thermal control infrastructure
+CONFIG_WINDFARM                                 policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WINDFARM_PM81                            policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_WINDFARM_PM72                            policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_WINDFARM_RM31                            policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_WINDFARM_PM91                            policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_WINDFARM_PM112                           policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_WINDFARM_PM121                           policy<{'powerpc-powerpc64-smp': 'm'}>
+
+# Menu: Device Drivers >> Macintosh device drivers >> Support for PMU  based PowerMacs
+CONFIG_ADB_PMU                                  policy<{'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_ADB_PMU_LED                              policy<{'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_PMAC_APM_EMU                             policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_PMAC_BACKLIGHT                           policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_PMAC_BACKLIGHT_LEGACY                    policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_SENSORS_AMS                              policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_SENSORS_AMS_PMU                          policy<{'powerpc-powerpc-smp': 'n'}>
+CONFIG_SENSORS_AMS_I2C                          policy<{'powerpc-powerpc-smp': 'n'}>
+
+# Menu: Device Drivers >> Mailbox Hardware Support
+CONFIG_MAILBOX                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ARM_MHU                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PL320_MBOX                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_OMAP2PLUS_MBOX                           policy<{'armhf': 'm'}>
+CONFIG_OMAP_MBOX_KFIFO_SIZE                     policy<{'armhf': '256'}>
+CONFIG_PCC                                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ALTERA_MBOX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAILBOX_TEST                             policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_XGENE_SLIMPRO_MBOX                       policy<{'arm64': 'm'}>
+
+# Menu: Device Drivers >> Memory Controller drivers
+CONFIG_MEMORY                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ARM_PL172_MPMC                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TI_EMIF                                  policy<{'armhf': 'm'}>
+CONFIG_OMAP_GPMC_DEBUG                          policy<{'armhf': 'n'}>
+CONFIG_MVEBU_DEVBUS                             policy<{'armhf': 'y'}>
+CONFIG_TEGRA20_MC                               policy<{'armhf-generic': 'y'}>
+CONFIG_FSL_CORENET_CF                           policy<{'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_TEGRA_MC                                 policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA124_EMC                             policy<{'armhf-generic': 'y'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support
+CONFIG_MTD                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MTD_TESTS                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_CMDLINE_PARTS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_AFS_PARTS                            policy<{'armhf': 'm'}>
+CONFIG_MTD_OF_PARTS                             policy<{'arm64': 'm', 'armhf': 'y', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_AR7_PARTS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_BLOCK                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_BLOCK_RO                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FTL                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFTL                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFTL_RW                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_INFTL                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RFD_FTL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SSFDC                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SM_FTL                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_OOPS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SWAP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PARTITIONED_MASTER                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_NAND_ECC_SMC                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_MTD                                      note<boot essential on arm>
+CONFIG_MTD_CMDLINE_PARTS                        flag<REVIEW>
+CONFIG_MTD_BLOCK                                note<boot essential on arm>
+CONFIG_MTD_OF_PARTS                             note<boot essential on arm>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> Enable UBI - Unsorted block images
+CONFIG_MTD_UBI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_UBI_WL_THRESHOLD                     policy<{'amd64': '4096', 'arm64': '4096', 'armhf': '4096', 'i386': '4096', 'powerpc': '4096', 'ppc64el': '4096'}>
+CONFIG_MTD_UBI_BEB_LIMIT                        policy<{'amd64': '20', 'arm64': '20', 'armhf': '20', 'i386': '20', 'powerpc': '20', 'ppc64el': '20'}>
+CONFIG_MTD_UBI_FASTMAP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_UBI_GLUEBI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_UBI_BLOCK                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> LPDDR & LPDDR2 PCM memory drivers
+CONFIG_MTD_LPDDR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_QINFO_PROBE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_LPDDR2_NVM                           policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> Mapping drivers for chip access
+CONFIG_MTD_PHYSMAP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PHYSMAP_OF                           policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SCx200_DOCFLASH                      policy<{'i386': 'm'}>
+CONFIG_MTD_AMD76XROM                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_ICHXROM                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_ESB2ROM                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_CK804XROM                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_SCB2_FLASH                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_NETtel                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_L440GX                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_IMPA7                                policy<{'armhf': 'm'}>
+CONFIG_MTD_INTEL_VR_NOR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PLATRAM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> Mapping drivers for chip access >> Maximum mappable memory available for flash IO
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> Mapping drivers for chip access >> Physmap compat support
+CONFIG_MTD_PHYSMAP_COMPAT                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> Mapping drivers for chip access >> Support non-linear mappings of flash chips
+CONFIG_MTD_COMPLEX_MAPPINGS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_SBC_GXX                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_PCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PCMCIA                               policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_MTD_PCMCIA_ANONYMOUS                     policy<{'amd64': 'n', 'i386': 'n', 'powerpc': 'n'}>
+CONFIG_MTD_GPIO_ADDR                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_LATCH_ADDR                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> NAND Device Support
+CONFIG_MTD_NAND                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_ECC_BCH                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_NAND_DENALI_PCI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_DENALI_DT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR         policy<{'amd64': '0xFF108018', 'arm64': '0xFF108018', 'armhf': '0xFF108018', 'i386': '0xFF108018', 'powerpc': '0xFF108018', 'ppc64el': '0xFF108018'}>
+CONFIG_MTD_NAND_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_OMAP2                           policy<{'armhf': 'y'}>
+CONFIG_MTD_NAND_OMAP_BCH                        policy<{'armhf': 'y'}>
+CONFIG_MTD_NAND_RICOH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_DISKONCHIP                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS        policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_NAND_DOCG4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_CAFE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_CS553X                          policy<{'i386': 'm'}>
+CONFIG_MTD_NAND_PXA3xx                          policy<{'armhf': 'm'}>
+CONFIG_MTD_NAND_PASEMI                          policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_MTD_NAND_TMIO                            policy<{'armhf': 'm'}>
+CONFIG_MTD_NAND_NANDSIM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_GPMI_NAND                       policy<{'armhf-generic': 'm'}>
+CONFIG_MTD_NAND_BRCMNAND                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_PLATFORM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_ORION                           policy<{'armhf': 'm'}>
+CONFIG_MTD_NAND_FSL_ELBC                        policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_FSL_IFC                         policy<{'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_MTD_NAND_FSL_UPM                         policy<{'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_MTD_NAND_VF610_NFC                       policy<{'armhf-generic': 'm'}>
+CONFIG_MTD_NAND_MXC                             policy<{'armhf-generic': 'm'}>
+CONFIG_MTD_NAND_SH_FLCTL                        policy<{'armhf': 'm'}>
+CONFIG_MTD_NAND_HISI504                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_MTD_NAND                                 note<boot essential on arm>
+CONFIG_MTD_NAND_OMAP2                           note<boot essential on arm>
+CONFIG_MTD_NAND_OMAP_BCH                        note<boot essential on arm>
+CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE             note<can be enabled at runtime>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> NAND Device Support >> NAND Flash support for Samsung S3C SoCs
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> OneNAND Device Support
+CONFIG_MTD_ONENAND                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_ONENAND_VERIFY_WRITE                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_ONENAND_GENERIC                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_ONENAND_OMAP2                        policy<{'armhf-generic': 'm'}>
+CONFIG_MTD_ONENAND_OTP                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_ONENAND_2X_PROGRAM                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_MTD_ONENAND_VERIFY_WRITE                 note<writes here are not checked in full without>
+CONFIG_MTD_ONENAND_OTP                          flag<REVIEW>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> RAM/ROM/Flash chip drivers
+CONFIG_MTD_CFI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_JEDECPROBE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CFI_INTELEXT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CFI_AMDSTD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CFI_STAA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_RAM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_ROM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_ABSENT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> RAM/ROM/Flash chip drivers >> Flash chip driver advanced configuration options
+CONFIG_MTD_CFI_ADV_OPTIONS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> RAM/ROM/Flash chip drivers >> Flash chip driver advanced configuration options >> Flash cmd/query data swapping
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> RAM/ROM/Flash chip drivers >> Flash chip driver advanced configuration options >> Specific CFI Flash geometry selection
+CONFIG_MTD_MAP_BANK_WIDTH_1                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_MAP_BANK_WIDTH_2                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_MAP_BANK_WIDTH_4                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_MAP_BANK_WIDTH_8                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_MAP_BANK_WIDTH_16                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_MAP_BANK_WIDTH_32                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_CFI_I1                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_CFI_I2                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_CFI_I4                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_CFI_I8                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> RedBoot partition table parsing
+CONFIG_MTD_REDBOOT_PARTS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK              policy<{'amd64': '-1', 'arm64': '-1', 'armhf': '-1', 'i386': '-1', 'powerpc': '-1', 'ppc64el': '-1'}>
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_REDBOOT_PARTS_READONLY               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> SPI-NOR device support
+CONFIG_MTD_SPI_NOR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_FSL_QUADSPI                          policy<{'armhf-generic': 'm'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> Self-contained MTD device drivers
+CONFIG_MTD_PMC551                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PMC551_BUGFIX                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_PMC551_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_DATAFLASH                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_DATAFLASH_WRITE_VERIFY               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_DATAFLASH_OTP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_M25P80                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SST25L                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SLRAM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PHRAM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_BLOCK2MTD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_POWERNV_FLASH                        policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_DOCG3                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Memory Technology Device (MTD) support >> Self-contained MTD device drivers >> Test driver using RAM
+CONFIG_MTD_MTDRAM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTDRAM_TOTAL_SIZE                        policy<{'amd64': '4096', 'arm64': '4096', 'armhf': '4096', 'i386': '4096', 'powerpc': '4096', 'ppc64el': '4096'}>
+CONFIG_MTDRAM_ERASE_SIZE                        policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'powerpc': '128', 'ppc64el': '128'}>
+
+# Menu: Device Drivers >> Microsoft Hyper-V guest support
+CONFIG_HYPERV                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_UTILS                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_BALLOON                           policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> Misc devices
+CONFIG_AD525X_DPOT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD525X_DPOT_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD525X_DPOT_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DUMMY_IRQ                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IBM_ASM                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PHANTOM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INTEL_MID_PTI                            policy<{'i386': 'm'}>
+CONFIG_SGI_IOC4                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TIFM_CORE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TIFM_7XX1                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ICS932S401                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ENCLOSURE_SERVICES                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CS5535_MFGPT                             policy<{'i386': 'n'}>
+CONFIG_HP_ILO                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_QCOM_COINCELL                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_APDS9802ALS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISL29003                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ISL29020                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TSL2550                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_BH1780                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_BH1770                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_APDS990X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HMC6352                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DS1682                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_DAC7512                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VMWARE_BALLOON                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ARM_CHARLCD                              policy<{'armhf': 'y'}>
+CONFIG_BMP085_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BMP085_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCH_PHUB                                 policy<{'i386': 'm'}>
+CONFIG_USB_SWITCH_FSA9480                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LATTICE_ECP3_CONFIG                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SRAM                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_VEXPRESS_SYSCFG                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CB710_CORE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CB710_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SENSORS_LIS3_SPI                         policy<{'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LIS3_I2C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ALTERA_STAPL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INTEL_MEI                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MEI_ME                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MEI_TXE                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VMWARE_VMCI                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MIC_BUS                            policy<{'amd64': 'm'}>
+CONFIG_ECHO                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CXL                                      policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_CS5535_MFGPT                             note<should be disabled by default>
+
+# Menu: Device Drivers >> Misc devices >> EEPROM support
+CONFIG_EEPROM_AT24                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EEPROM_AT25                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EEPROM_LEGACY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EEPROM_MAX6875                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EEPROM_93CX6                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EEPROM_93XX46                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Misc devices >> GenWQE PCIe Accelerator
+CONFIG_GENWQE                                   policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY           policy<{'amd64': '0', 'arm64': '0', 'powerpc-powerpc64-emb': '0', 'powerpc-powerpc64-smp': '0', 'ppc64el': '0', 's390x': '0'}>
+
+# Menu: Device Drivers >> Misc devices >> SCIF Bus Driver
+CONFIG_SCIF_BUS                                 policy<{'amd64': 'm'}>
+CONFIG_INTEL_MIC_HOST                           policy<{'amd64': 'm'}>
+CONFIG_INTEL_MIC_CARD                           policy<{'amd64': 'm'}>
+CONFIG_SCIF                                     policy<{'amd64': 'm'}>
+CONFIG_MIC_COSM                                 policy<{'amd64': 'm'}>
+
+# Menu: Device Drivers >> Misc devices >> Silicon Labs C2 port support
+CONFIG_C2PORT                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_C2PORT_DURAMAR_2150                      policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> Misc devices >> Texas Instruments shared transport line discipline
+CONFIG_TI_ST                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multifunction device drivers
+CONFIG_MFD_CS5535                               policy<{'i386': 'm'}>
+CONFIG_MFD_AS3711                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_AS3722                               policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PMIC_ADP5520                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_AAT2870_CORE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_ATMEL_FLEXCOM                        policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_ATMEL_HLCDC                          policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_BCM590XX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_AXP20X                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_CROS_EC                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MFD_CROS_EC_I2C                          policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MFD_CROS_EC_SPI                          policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MFD_ASIC3                                policy<{'armhf': 'y'}>
+CONFIG_PMIC_DA903X                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_DA9052_SPI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_DA9052_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_DA9055                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_DA9062                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_DA9063                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_DA9150                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_DLN2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_MC13XXX_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_MC13XXX_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_HI6421_PMIC                          policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HTC_EGPIO                                policy<{'armhf': 'y'}>
+CONFIG_HTC_PASIC3                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HTC_I2CPLD                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_INTEL_QUARK_I2C_GPIO                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LPC_ICH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_LPC_SCH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INTEL_SOC_PMIC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_INTEL_LPSS_ACPI                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MFD_INTEL_LPSS_PCI                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MFD_INTEL_MSIC                           policy<{'i386': 'y'}>
+CONFIG_MFD_JANZ_CMODIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_KEMPLD                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_88PM800                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_88PM805                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_88PM860X                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX14577                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX77686                             policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX77693                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX77843                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX8907                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_MAX8925                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX8997                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX8998                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MT6397                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_MENF21BMC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EZX_PCAP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_VIPERBOARD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_RETU                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_PCF50633                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCF50633_ADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCF50633_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UCB1400_CORE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_PM8921_CORE                          policy<{'armhf': 'm'}>
+CONFIG_MFD_QCOM_RPM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MFD_SPMI_PMIC                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MFD_RDC321X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_RTSX_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_RT5033                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_RTSX_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_RC5T583                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_RK808                                policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_RN5T618                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_SEC_CORE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_SI476X_CORE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_SM501                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_SM501_GPIO                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_SKY81452                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_SMSC                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ABX500_CORE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_AB3100_CORE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_AB3100_OTP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_STMPE                                policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_SYSCON                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MFD_TI_AM335X_TSCADC                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_LP3943                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_LP8788                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_OMAP_USB_HOST                        policy<{'armhf': 'y'}>
+CONFIG_MFD_PALMAS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TPS6105X                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TPS65010                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TPS6507X                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_TPS65090                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65217                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65218                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_TPS6586X                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65910                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65912                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65912_I2C                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65912_SPI                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS80031                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TWL4030_CORE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TWL4030_POWER                            policy<{'armhf': 'y'}>
+CONFIG_MFD_TWL4030_AUDIO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_TWL6040_CORE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WL1273_CORE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_LM3533                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_TIMBERDALE                           policy<{'i386': 'm'}>
+CONFIG_MFD_TC3589X                              policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_T7L66XB                              policy<{'armhf': 'y'}>
+CONFIG_MFD_TC6387XB                             policy<{'armhf': 'y'}>
+CONFIG_MFD_TC6393XB                             policy<{'armhf': 'y'}>
+CONFIG_MFD_VX855                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_ARIZONA_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_ARIZONA_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_WM5102                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM5110                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8997                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8998                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8400                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM831X_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM831X_SPI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8350_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8994                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_VEXPRESS_SYSREG                      policy<{'arm64': 'y', 'armhf': 'y'}>
+#
+CONFIG_MFD_SM501                                note<boot essential on OMAP4>
+
+# Menu: Device Drivers >> Multifunction device drivers >> Multimedia Capabilities Port drivers
+
+# Menu: Device Drivers >> Multifunction device drivers >> STMicroelectronics STMPE Interface Drivers
+CONFIG_STMPE_I2C                                policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_STMPE_SPI                                policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Multimedia support
+CONFIG_MEDIA_SUPPORT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MEDIA_ANALOG_TV_SUPPORT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_RADIO_SUPPORT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_SDR_SUPPORT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_RC_SUPPORT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_CONTROLLER                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_V4L2_SUBDEV_API                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_ADV_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_VIDEO_FIXED_MINOR_RANGES                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_V4L2_FLASH_LED_CLASS                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NET                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_MAX_ADAPTERS                         policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8'}>
+CONFIG_DVB_DYNAMIC_MINORS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RC_MAP                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SMS_SDIO_DRV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_FIREDTV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CYPRESS_FIRMWARE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SMS_SIANO_RC                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SMS_SIANO_DEBUGFS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_SUBDRV_AUTOSELECT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_IR_I2C                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Cameras/video grabbers support
+CONFIG_MEDIA_CAMERA_SUPPORT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Multimedia support >> Cameras/video grabbers support >> Media test drivers
+CONFIG_V4L_TEST_DRIVERS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_VIVID                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VIVID_MAX_DEVS                     policy<{'amd64': '64', 'arm64': '64', 'armhf': '64', 'i386': '64', 'powerpc': '64', 'ppc64el': '64'}>
+CONFIG_VIDEO_VIM2M                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Cameras/video grabbers support >> Memory-to-memory multimedia devices
+CONFIG_V4L_MEM2MEM_DRIVERS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_CODA                               policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_MEM2MEM_DEINTERLACE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_G2D                    policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_JPEG                   policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_MFC                    policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC                 policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SH_VEU                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_RENESAS_JPU                        policy<{'armhf': 'm'}>
+CONFIG_VIDEO_RENESAS_VSP1                       policy<{'armhf': 'm'}>
+CONFIG_VIDEO_TI_VPE                             policy<{'armhf': 'm'}>
+CONFIG_VIDEO_TI_VPE_DEBUG                       policy<{'armhf': 'n'}>
+
+# Menu: Device Drivers >> Multimedia support >> Cameras/video grabbers support >> V4L platform devices
+CONFIG_V4L_PLATFORM_DRIVERS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_CAFE_CCIC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VIA_CAMERA                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_OMAP2_VOUT                         policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_SH_VOU                             policy<{'armhf': 'm'}>
+CONFIG_VIDEO_TIMBERDALE                         policy<{'i386': 'm'}>
+CONFIG_VIDEO_OMAP3                              policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_OMAP3_DEBUG                        policy<{'armhf-generic': 'n'}>
+CONFIG_VIDEO_XILINX                             policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_XILINX_TPG                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_XILINX_VTC                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Cameras/video grabbers support >> V4L platform devices >> Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver
+CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS                 policy<{'armhf': 'n'}>
+
+# Menu: Device Drivers >> Multimedia support >> Cameras/video grabbers support >> V4L platform devices >> Samsung TV driver for S5P platform
+CONFIG_VIDEO_SAMSUNG_S5P_TV                     policy<{'armhf': 'y'}>
+CONFIG_VIDEO_SAMSUNG_S5P_HDMI                   policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG             policy<{'armhf': 'n'}>
+CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY                policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_SII9234                policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_SDO                    policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_MIXER                  policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG            policy<{'armhf': 'n'}>
+
+# Menu: Device Drivers >> Multimedia support >> Cameras/video grabbers support >> V4L platform devices >> SoC camera support
+CONFIG_SOC_CAMERA                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_PLATFORM                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MX3                                policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_RCAR_VIN                           policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SH_MOBILE_CSI2                     policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SH_MOBILE_CEU                      policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Customise DVB Frontends
+CONFIG_DVB_STB0899                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STB6100                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV090x                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV6110x                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_M88DS3103                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DRXK                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA18271C2DD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SI2165                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24110                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24123                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MT312                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ZL10036                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ZL10039                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S5H1420                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0288                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STB6000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0299                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV6110                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0900                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA8083                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10086                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA8261                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_VES1X93                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUNER_ITD1000                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUNER_CX24113                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA826X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUA6100                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24116                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24117                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24120                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SI21XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TS2020                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DS3000                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MB86A16                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10071                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SP8870                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SP887X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX22700                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX22702                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DRXD                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_L64781                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA1004X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NXT6000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MT352                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ZL10353                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB3000MB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB3000MC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB7000M                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB7000P                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10048                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AF9013                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_EC100                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0367                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CXD2820R                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CXD2841ER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_RTL2830                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_RTL2832                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_RTL2832_SDR                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SI2168                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_VES1820                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10021                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10023                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0297                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NXT200X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_OR51211                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_OR51132                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BCM3510                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGDT330X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGDT3305                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGDT3306A                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LG2160                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S5H1409                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AU8522_DTV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AU8522_V4L                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S5H1411                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S921                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB8000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MB86A20S                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TC90522                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_PLL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUNER_DIB0070                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUNER_DIB0090                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DRX39XYJ                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LNBH25                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LNBP21                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LNBP22                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ISL6405                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ISL6421                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ISL6423                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_A8293                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SP2                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGS8GXX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ATBM8830                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA665x                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_IX2505V                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_M88RS2000                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AF9033                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_HORUS3A                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ASCOT2E                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DUMMY_FE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_DVB_DUMMY_FE                             note<expert use only>
+
+# Menu: Device Drivers >> Multimedia support >> Customize TV tuners
+CONFIG_MEDIA_TUNER_SIMPLE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA8290                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA827X                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18271                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA9887                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TEA5761                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TEA5767                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MSI001                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT20XX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT2060                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT2063                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT2266                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT2131                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_QT1010                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_XC2028                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_XC5000                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_XC4000                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MXL5005S                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MXL5007T                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MC44S803                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MAX2165                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18218                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_FC0011                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_FC0012                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_FC0013                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18212                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_E4000                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_FC2580                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_M88RS6000T                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TUA9001                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_SI2157                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_IT913X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_R820T                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MXL301RF                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_QM1D1C0042                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> DVB platform devices
+CONFIG_DVB_PLATFORM_DRIVERS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_C8SECTPFE                            policy<{'armhf': 'n'}>
+#
+CONFIG_DVB_C8SECTPFE				flag<REVIEW>
+
+# Menu: Device Drivers >> Multimedia support >> Encoders, decoders, sensors and other helper chips
+CONFIG_VIDEO_TVAUDIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TDA7432                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TDA9840                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TEA6415C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TEA6420                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MSP3400                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CS5345                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CS53L32A                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_UDA1342                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_WM8775                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_WM8739                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VP27SMPX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SONY_BTF_MPX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA6588                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7180                            policy<{'i386': 'm'}>
+CONFIG_VIDEO_ADV7604                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7842                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_BT819                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_BT856                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_BT866                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_KS0127                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_SAA7110                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_SAA711X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TVP5150                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW2804                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW9903                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW9906                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VPX3220                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_SAA717X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX25840                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7127                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7185                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ADV7170                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ADV7175                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ADV7511                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV7640                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV7670                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9V011                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_UPD64031A                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_UPD64083                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA6752HS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_M52790                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media PCI Adapters
+CONFIG_MEDIA_PCI_SUPPORT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_MEYE                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_SOLO6X10                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW68                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ZORAN                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ZORAN_DC30                         policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_IVTV                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IVTV_ALSA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_FB_IVTV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_HEXIUM_GEMINI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_HEXIUM_ORION                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MXB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_DT3155                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX18                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX18_ALSA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX23885                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_ALTERA_CI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX25821                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX25821_ALSA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_BT848                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BT8XX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7164                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_COBALT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AV7110                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AV7110_OSD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_B2C2_FLEXCOP_PCI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_PLUTO2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DM1105                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_PT1                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_PT3                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MANTIS_CORE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MANTIS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_HOPPER                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NGENE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DDBRIDGE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SMIPCIE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NETUP_UNIDVB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media PCI Adapters >> Conexant 2388x (bt878 successor) support
+CONFIG_VIDEO_CX88                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_ALSA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_BLACKBIRD                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_DVB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_ENABLE_VP3054                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media PCI Adapters >> Philips SAA7134 support
+CONFIG_VIDEO_SAA7134                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7134_ALSA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7134_RC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_SAA7134_DVB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7134_GO7007                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media PCI Adapters >> SAA7146 DVB cards (aka Budget, Nova-PCI)
+CONFIG_DVB_BUDGET_CORE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET_CI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET_AV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET_PATCH                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media PCI Adapters >> Zoran ZR36060
+CONFIG_VIDEO_ZORAN_ZR36060                      policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ZORAN_BUZ                          policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ZORAN_DC10                         policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ZORAN_LML33                        policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ZORAN_LML33R10                     policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VIDEO_ZORAN_AVS6EYES                     policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media USB Adapters
+CONFIG_MEDIA_USB_SUPPORT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_VIDEO_CLASS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_PWC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_PWC_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_PWC_INPUT_EVDEV                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_CPIA2                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ZR364XX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STKWEBCAM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_S2255                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_USBTV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_PVRUSB2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_PVRUSB2_SYSFS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_PVRUSB2_DVB                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_PVRUSB2_DEBUGIFC                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_VIDEO_HDPVR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_USBVISION                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_STK1160_COMMON                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_STK1160_AC97                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_GO7007                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_GO7007_USB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_GO7007_LOADER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_AU0828                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_AU0828_V4L2                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_AU0828_RC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_TM6000                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TM6000_ALSA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TM6000_DVB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TTUSB_BUDGET                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TTUSB_DEC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SMS_USB_DRV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_B2C2_FLEXCOP_USB                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_AS102                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_AIRSPY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HACKRF                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MSI2500                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media USB Adapters >> Conexant cx231xx USB video capture support
+CONFIG_VIDEO_CX231XX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX231XX_RC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_CX231XX_ALSA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX231XX_DVB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media USB Adapters >> Empia EM28xx USB devices support
+CONFIG_VIDEO_EM28XX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX_V4L2                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX_ALSA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX_DVB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX_RC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media USB Adapters >> GSPCA based webcams
+CONFIG_USB_GSPCA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_M5602                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STV06XX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GL860                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_BENQ                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_CONEX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_CPIA1                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_DTCS033                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_ETOMS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_FINEPIX                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_JEILINJ                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_JL2005BCD                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_KINECT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_KONICA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_MARS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_MR97310A                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_NW80X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_OV519                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_OV534                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_OV534_9                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_PAC207                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_PAC7302                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_PAC7311                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SE401                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SN9C2028                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SN9C20X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SONIXB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SONIXJ                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA500                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA501                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA505                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA506                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA508                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA561                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA1528                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SQ905                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SQ905C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SQ930X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_STK014                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_STK1135                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_STV0680                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SUNPLUS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_T613                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_TOPRO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_TOUPTEK                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_TV8532                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_VC032X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_VICAM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_XIRLINK_CIT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_ZC3XX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media USB Adapters >> Support for various USB DVB devices
+CONFIG_DVB_USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_USB_A800                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DIBUSB_MB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_USB_DIBUSB_MC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DIB0700                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_UMT_010                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_CXUSB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_M920X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DIGITV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_VP7045                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_VP702X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_GP8PSK                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_NOVA_T_USB2                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_TTUSB2                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DTT200U                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_OPERA1                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AF9005                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AF9005_REMOTE                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_PCTV452E                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DW2102                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_CINERGY_T2                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DTV5100                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_FRIIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AZ6027                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_TECHNISAT_USB2                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Media USB Adapters >> Support for various USB DVB devices v2
+CONFIG_DVB_USB_V2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AF9015                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AF9035                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_ANYSEE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AU6610                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AZ6007                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_CE6230                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_EC168                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_GL861                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_LME2510                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_MXL111SF                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_RTL28XXU                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DVBSKY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Radio Adapters
+CONFIG_RADIO_ADAPTERS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RADIO_SI470X                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SI470X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SI470X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SI476X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MR800                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DSBR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_MAXIRADIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SHARK                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SHARK2                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_KEENE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RAREMONO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MA901                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_TEA5764                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SAA7706H                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_TEF6862                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_TIMBERDALE                         policy<{'i386': 'm'}>
+CONFIG_RADIO_WL1273                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Radio Adapters >> ISA radio devices
+CONFIG_V4L_RADIO_ISA_DRIVERS                    policy<{'i386': 'y'}>
+CONFIG_RADIO_CADET                              policy<{'i386': 'm'}>
+CONFIG_RADIO_RTRACK                             policy<{'i386': 'm'}>
+CONFIG_RADIO_RTRACK2                            policy<{'i386': 'm'}>
+CONFIG_RADIO_AZTECH                             policy<{'i386': 'm'}>
+CONFIG_RADIO_GEMTEK                             policy<{'i386': 'm'}>
+CONFIG_RADIO_MIROPCM20                          policy<{'i386': 'm'}>
+CONFIG_RADIO_SF16FMI                            policy<{'i386': 'm'}>
+CONFIG_RADIO_SF16FMR2                           policy<{'i386': 'm'}>
+CONFIG_RADIO_TERRATEC                           policy<{'i386': 'm'}>
+CONFIG_RADIO_TRUST                              policy<{'i386': 'm'}>
+CONFIG_RADIO_TYPHOON                            policy<{'i386': 'm'}>
+CONFIG_RADIO_ZOLTRIX                            policy<{'i386': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Radio Adapters >> Silicon Labs Si4713 FM Radio with RDS Transmitter support
+CONFIG_RADIO_SI4713                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SI4713                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PLATFORM_SI4713                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SI4713                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Radio Adapters >> Texas Instruments WL128x FM driver (ST based)
+CONFIG_RADIO_WL128X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Remote Controller devices
+CONFIG_RC_DEVICES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RC_ATI_REMOTE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_ENE                                   policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_IR_HIX5HD2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_IMON                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_MCEUSB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_ITE_CIR                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_IR_FINTEK                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_IR_MESON                                 policy<{'armhf': 'm'}>
+CONFIG_IR_NUVOTON                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_IR_REDRAT3                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_STREAMZAP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_WINBOND_CIR                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IR_IGORPLUGUSB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_IGUANA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_TTUSBIR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RC_LOOPBACK                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_GPIO_CIR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Remote Controller devices >> Hardware decoder
+
+# Menu: Device Drivers >> Multimedia support >> Remote controller decoders
+CONFIG_RC_DECODERS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LIRC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_LIRC_CODEC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_NEC_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_RC5_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_RC6_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_JVC_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SONY_DECODER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SANYO_DECODER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SHARP_DECODER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_MCE_KBD_DECODER                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_XMP_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multimedia support >> Sensors used on soc_camera driver
+CONFIG_SOC_CAMERA_IMX074                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_MT9M001                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_MT9M111                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_MT9T031                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_MT9T112                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_MT9V022                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_OV2640                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_OV5642                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_OV6650                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_OV772X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_OV9640                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_OV9740                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_RJ54N1                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SOC_CAMERA_TW9910                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Multiple devices driver support (RAID and LVM)
+CONFIG_MD                                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BCACHE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BCACHE_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BCACHE_CLOSURES_DEBUG                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DM_DEBUG_BLOCK_STACK_TRACING             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Device Drivers >> Multiple devices driver support (RAID and LVM) >> Device mapper support
+CONFIG_BLK_DEV_DM                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DM_MQ_DEFAULT                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DM_DEBUG                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_DM_CRYPT                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_SNAPSHOT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_THIN_PROVISIONING                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_ERA                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_MIRROR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_LOG_USERSPACE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_RAID                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_ZERO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_MULTIPATH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_MULTIPATH_QL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_MULTIPATH_ST                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_DELAY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_UEVENT                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DM_FLAKEY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_VERITY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_SWITCH                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_LOG_WRITES                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+#
+CONFIG_BLK_DEV_DM                               mark<ENFORCED> note<LP:#560717>
+
+# Menu: Device Drivers >> Multiple devices driver support (RAID and LVM) >> Device mapper support >> Cache target (EXPERIMENTAL)
+CONFIG_DM_CACHE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_CACHE_MQ                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_CACHE_SMQ                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_CACHE_CLEANER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> Multiple devices driver support (RAID and LVM) >> RAID support
+CONFIG_BLK_DEV_MD                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MD_AUTODETECT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MD_LINEAR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_RAID0                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_RAID1                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_RAID10                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_RAID456                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_MULTIPATH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'y'}>
+CONFIG_MD_FAULTY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_CLUSTER                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> NVDIMM (Non-Volatile Memory Device) Support
+CONFIG_LIBNVDIMM                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_BLK_DEV_PMEM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_ND_BLK                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_BTT                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_NVDIMM_PFN                               policy<{'amd64': 'y'}>
+
+# Menu: Device Drivers >> NVMEM Support
+CONFIG_NVMEM                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NVMEM_IMX_OCOTP                          policy<{'armhf-generic': 'm'}>
+CONFIG_QCOM_QFPROM                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ROCKCHIP_EFUSE                           policy<{'armhf': 'm'}>
+CONFIG_NVMEM_VF610_OCOTP                        policy<{'armhf-generic': 'm'}>
+#
+CONFIG_NVMEM					flag<REVIEW> note<Q: is this appropriate for s390x>
+
+# Menu: Device Drivers >> Network device support
+CONFIG_NETDEVICES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CAIF_TTY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAIF_SPI_SLAVE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAIF_SPI_SYNC                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CAIF_HSI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FDDI                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_DEFXX                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DEFXX_MMIO                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SKFP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HIPPI                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NET_SB1000                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_MICREL_KS8995MA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PLIP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_XEN_NETDEV_FRONTEND                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_NETDEV_BACKEND                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_VMXNET3                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 's390x': 'n'}>
+CONFIG_FUJITSU_ES                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_NET                               policy<{'amd64': 'm', 'i386': 'm'}>
+#
+CONFIG_HIPPI                                    flag<DEPRECATED>
+CONFIG_XEN_NETDEV_FRONTEND                      note<not autoloadable -- XEN paravirt support>
+CONFIG_VMXNET3					note<implicitly disabled by upstream stable change for ppc64el (64K pages)>
+CONFIG_DEFXX_MMIO                               flag<REVIEW>
+
+# Menu: Device Drivers >> Network device support >> ARCnet support
+CONFIG_ARCNET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ARCNET_1201                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_1051                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_RAW                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_CAP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_COM90xx                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_COM90xxIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_RIM_I                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> ARCnet support >> ARCnet COM20020 chipset driver
+CONFIG_ARCNET_COM20020                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_COM20020_ISA                      policy<{'i386': 'm'}>
+CONFIG_ARCNET_COM20020_PCI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_COM20020_CS                       policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> ATM drivers
+CONFIG_ATM_DRIVERS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATM_DUMMY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_TCP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_LANAI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_ENI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_ENI_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_FIRESTREAM                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_ATM_ZATM                                 policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_ATM_ZATM_DEBUG                           policy<{'amd64': 'n', 'i386': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_ATM_NICSTAR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_NICSTAR_USE_SUNI                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_NICSTAR_USE_IDT77105                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_IDT77252                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_IDT77252_DEBUG                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_IDT77252_RCV_ALL                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_AMBASSADOR                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_ATM_AMBASSADOR_DEBUG                     policy<{'amd64': 'n', 'i386': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_ATM_HORIZON                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_ATM_HORIZON_DEBUG                        policy<{'amd64': 'n', 'i386': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_ATM_IA                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_IA_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_HE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_HE_USE_SUNI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATM_SOLOS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_ATM_NICSTAR_USE_IDT77105                 flag<REVIEW>
+
+# Menu: Device Drivers >> Network device support >> ATM drivers >> FORE Systems 200E-series
+CONFIG_ATM_FORE200E                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_FORE200E_USE_TASKLET                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_FORE200E_TX_RETRY                    policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'powerpc': '16', 'ppc64el': '16'}>
+CONFIG_ATM_FORE200E_DEBUG                       policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+
+# Menu: Device Drivers >> Network device support >> ATM drivers >> Fine-tune burst settings
+CONFIG_ATM_ENI_TUNE_BURST                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> CAIF virtio transport driver
+CONFIG_CAIF_VIRTIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VHOST_NET                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VHOST_SCSI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VHOST_CROSS_ENDIAN_LEGACY                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Distributed Switch Architecture drivers
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support
+CONFIG_ETHERNET                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_ADAPTEC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ADAPTEC_STARFIRE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_AGERE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ET131X                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_ALTEON                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ACENIC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ACENIC_OMIT_TIGON_I                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ALTERA_TSE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NET_VENDOR_AMAZON                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ENA_ETHERNET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_XGENE                                policy<{'arm64': 'm'}>
+CONFIG_NET_VENDOR_ARC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ARC_EMAC                                 policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_EMAC_ROCKCHIP                            policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_AURORA                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AURORA_NB8800                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CADENCE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MACB                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_BROCADE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_BNA                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_CALXEDA_XGMAC                        policy<{'armhf': 'm'}>
+CONFIG_NET_VENDOR_CISCO                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ENIC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CX_ECAT                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DM9000                                   policy<{'armhf': 'm'}>
+CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL             policy<{'armhf': 'n'}>
+CONFIG_DNET                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NET_VENDOR_DEC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_DLINK                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_DL2K                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SUNDANCE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SUNDANCE_MMIO                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_NET_VENDOR_EMULEX                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_BE2NET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BE2NET_HWMON                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BE2NET_VXLAN                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_VENDOR_EZCHIP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_EZCHIP_NPS_MANAGEMENT_ENET               policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_EXAR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_S2IO                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VXGE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VXGE_DEBUG_TRACE_ALL                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_NET_VENDOR_FARADAY                       policy<{'armhf': 'y'}>
+CONFIG_FTMAC100                                 policy<{'armhf': 'm'}>
+CONFIG_FTGMAC100                                policy<{'armhf': 'm'}>
+CONFIG_NET_VENDOR_FUJITSU                       policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_PCMCIA_FMVJ18X                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_NET_VENDOR_HP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HP100                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JME                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NET_VENDOR_MICROCHIP                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ENC28J60                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ENC28J60_WRITEVERIFY                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ENCX24J600                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_MYRI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MYRI10GE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MYRI10GE_DCA                             policy<{'amd64': 'y'}>
+CONFIG_FEALNX                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NET_VENDOR_NVIDIA                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FORCEDETH                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_OKI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PCH_GBE                                  policy<{'i386': 'm'}>
+CONFIG_ETHOC                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NET_PACKET_ENGINE                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HAMACHI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_YELLOWFIN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_PASEMI                        policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PASEMI_MAC                               policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_NET_VENDOR_QUALCOMM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_QCA7000                                  policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_RENESAS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SH_ETH                                   policy<{'armhf': 'm'}>
+CONFIG_RAVB                                     policy<{'armhf': 'm'}>
+CONFIG_NET_VENDOR_RDC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_R6040                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_ROCKER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SAMSUNG                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SXGBE_ETH                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_SEEQ                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SILAN                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SC92031                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_SIS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SIS900                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SIS190                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_STMICRO                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_STMMAC_ETH                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_STMMAC_PCI                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_NET_VENDOR_SYNOPSYS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SYNOPSYS_DWC_ETH_QOS                     policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_TEHUTI                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_TEHUTI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_VIA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_VIA_RHINE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIA_RHINE_MMIO                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIA_VELOCITY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_WIZNET                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_WIZNET_W5100                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WIZNET_W5300                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_VENDOR_XIRCOM                        policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_PCMCIA_XIRC2PS                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> 3Com devices
+CONFIG_NET_VENDOR_3COM                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_EL3                                      policy<{'i386': 'm'}>
+CONFIG_3C515                                    policy<{'i386': 'm'}>
+CONFIG_PCMCIA_3C574                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_PCMCIA_3C589                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_VORTEX                                   policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPHOON                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> AMD devices
+CONFIG_NET_VENDOR_AMD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_AMD8111_ETH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LANCE                                    policy<{'i386': 'm'}>
+CONFIG_PCNET32                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCMCIA_NMCLAN                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_NI65                                     policy<{'i386': 'm'}>
+CONFIG_AMD_XGBE                                 policy<{'arm64': 'm'}>
+CONFIG_AMD_XGBE_DCB                             policy<{'arm64': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Apple devices
+CONFIG_NET_VENDOR_APPLE                         policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_MACE                                     policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_MACE_AAUI_PORT                           policy<{'powerpc-powerpc-smp': 'n'}>
+CONFIG_BMAC                                     policy<{'powerpc-powerpc-smp': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Atheros devices
+CONFIG_NET_VENDOR_ATHEROS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ATL2                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATL1                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATL1E                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATL1C                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ALX                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Blackfin on-chip MAC support
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Broadcom devices
+CONFIG_NET_VENDOR_BROADCOM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_B44                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BCMGENET                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BNX2                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CNIC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TIGON3                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'y'}>
+CONFIG_BNX2X                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BNX2X_SRIOV                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BNX2X_VXLAN                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SYSTEMPORT                               policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BNXT                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BNXT_SRIOV                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_TIGON3                                   flag<REVIEW>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Cavium ethernet drivers
+CONFIG_NET_VENDOR_CAVIUM                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_THUNDER_NIC_PF                           policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_THUNDER_NIC_VF                           policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_THUNDER_NIC_BGX                          policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_LIQUIDIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Chelsio devices
+CONFIG_NET_VENDOR_CHELSIO                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_CHELSIO_T1                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHELSIO_T1_1G                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CHELSIO_T3                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHELSIO_T4                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHELSIO_T4_DCB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CHELSIO_T4_FCOE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CHELSIO_T4VF                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Cirrus devices
+CONFIG_NET_VENDOR_CIRRUS                        policy<{'armhf': 'y', 'i386': 'y'}>
+CONFIG_CS89x0                                   policy<{'armhf': 'm', 'i386': 'm'}>
+CONFIG_CS89x0_PLATFORM                          policy<{'armhf': 'y', 'i386': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> DEC - Tulip devices
+CONFIG_NET_TULIP                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DE2104X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DE2104X_DSL                              policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+CONFIG_DE4X5                                    policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WINBOND_840                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DM9102                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ULI526X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCMCIA_XIRCOM                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> DEC - Tulip devices >> DECchip Tulip (dc2114x) PCI support
+CONFIG_TULIP                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TULIP_MWI                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_TULIP_MMIO                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_TULIP_NAPI                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_TULIP_NAPI                               flag<REVIEW>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Freescale devices
+CONFIG_NET_VENDOR_FREESCALE                     policy<{'arm64': 'y', 'armhf-generic': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_FEC                                      policy<{'armhf-generic': 'y'}>
+CONFIG_FSL_PQ_MDIO                              policy<{'arm64': 'm', 'armhf-generic': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_FSL_XGMAC_MDIO                           policy<{'arm64': 'y', 'armhf-generic': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_GIANFAR                                  policy<{'arm64': 'm', 'armhf-generic': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Freescale devices >> Freescale Ethernet Driver
+CONFIG_FS_ENET                                  policy<{'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_FS_ENET_HAS_SCC                          policy<{'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_FS_ENET_HAS_FCC                          policy<{'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_FS_ENET_MDIO_FCC                         policy<{'powerpc-powerpc-e500mc': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Hisilicon devices
+CONFIG_NET_VENDOR_HISILICON                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HIX5HD2_GMAC                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HIP04_ETH                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS                                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS_DSAF                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS_ENET                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> IBM devices
+CONFIG_NET_VENDOR_IBM                           policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_IBMVETH                                  policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_EHEA                                     policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_IBMVNIC                                  policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> IBM devices >> IBM EMAC Ethernet support
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Intel (82586/82593/82596) devices
+CONFIG_NET_VENDOR_I825XX                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Intel devices
+CONFIG_NET_VENDOR_INTEL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_E100                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_E1000                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_E1000E                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_E1000E_HWTS                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IGB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IGB_HWMON                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IGB_DCA                                  policy<{'amd64': 'y'}>
+CONFIG_IGBVF                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IXGB                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IXGBEVF                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I40EVF                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FM10K                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FM10K_VXLAN                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Intel devices >> Intel(R) 10GbE PCI Express adapters support
+CONFIG_IXGBE                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IXGBE_VXLAN                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IXGBE_HWMON                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IXGBE_DCA                                policy<{'amd64': 'y'}>
+CONFIG_IXGBE_DCB                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Intel devices >> Intel(R) Ethernet Controller XL710 Family support
+CONFIG_I40E                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_I40E_VXLAN                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_I40E_DCB                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_I40E_FCOE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Marvell devices
+CONFIG_NET_VENDOR_MARVELL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MV643XX_ETH                              policy<{'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_MVMDIO                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MVNETA                                   policy<{'armhf': 'm'}>
+CONFIG_MVPP2                                    policy<{'armhf': 'm'}>
+CONFIG_PXA168_ETH                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SKGE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SKGE_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SKGE_GENESIS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SKY2                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SKY2_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Mellanox devices
+CONFIG_NET_VENDOR_MELLANOX                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX4_EN                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX4_EN_DCB                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX4_EN_VXLAN                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX4_DEBUG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_CORE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX5_CORE_EN                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Mellanox devices >> Mellanox Technologies Switch ASICs support
+CONFIG_MLXSW_CORE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLXSW_PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Micrel devices
+CONFIG_NET_VENDOR_MICREL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_KS8842                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KS8851                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KS8851_MLL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KSZ884X_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> National Semi-conductor 8390 devices
+CONFIG_NET_VENDOR_8390                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PCMCIA_AXNET                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_AX88796                                  policy<{'armhf': 'm'}>
+CONFIG_AX88796_93CX6                            policy<{'armhf': 'n'}>
+CONFIG_NE2000                                   policy<{'i386': 'm'}>
+CONFIG_NE2K_PCI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCMCIA_PCNET                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_ULTRA                                    policy<{'i386': 'm'}>
+CONFIG_WD80x3                                   policy<{'i386': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> National Semi-conductor devices
+CONFIG_NET_VENDOR_NATSEMI                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NATSEMI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NS83820                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> QLogic devices
+CONFIG_NET_VENDOR_QLOGIC                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_QLA3XXX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_QLGE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NETXEN_NIC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_QED                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_QEDE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> QLogic devices >> QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support
+CONFIG_QLCNIC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_QLCNIC_SRIOV                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_QLCNIC_DCB                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_QLCNIC_VXLAN                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_QLCNIC_HWMON                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Realtek devices
+CONFIG_NET_VENDOR_REALTEK                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ATP                                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_8139CP                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_R8169                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Realtek devices >> RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support
+CONFIG_8139TOO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_8139TOO_PIO                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_8139TOO_TUNE_TWISTER                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_8139TOO_8129                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_8139_OLD_RX_RESET                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_8139TOO_TUNE_TWISTER                     flag<REVIEW>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> SMC (SMSC)/Western Digital devices
+CONFIG_NET_VENDOR_SMSC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SMC9194                                  policy<{'i386': 'm'}>
+CONFIG_SMC91X                                   policy<{'arm64': 'y', 'armhf': 'm'}>
+CONFIG_PCMCIA_SMC91C92                          policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_EPIC100                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SMC911X                                  policy<{'armhf': 'm'}>
+CONFIG_SMSC911X                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SMSC9420                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> STMMAC Platform bus support
+CONFIG_STMMAC_PLATFORM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_GENERIC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_IPQ806X                            policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_LPC18XX                            policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_MESON                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_ROCKCHIP                           policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_SOCFPGA                            policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_STI                                policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_SUNXI                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Solarflare SFC4000/SFC9000/SFC9100-family support
+CONFIG_SFC                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SFC_MTD                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SFC_MCDI_MON                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SFC_SRIOV                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SFC_MCDI_LOGGING                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Sun devices
+CONFIG_NET_VENDOR_SUN                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HAPPYMEAL                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SUNGEM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CASSINI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NIU                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Texas Instruments (TI) devices
+CONFIG_NET_VENDOR_TI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_TI_DAVINCI_EMAC                          policy<{'armhf-generic': 'm'}>
+CONFIG_TI_DAVINCI_MDIO                          policy<{'armhf': 'y'}>
+CONFIG_TI_DAVINCI_CPDMA                         policy<{'armhf': 'y'}>
+CONFIG_TI_CPSW_PHY_SEL                          policy<{'armhf': 'y'}>
+CONFIG_TI_CPSW_ALE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_CPSW                                  policy<{'armhf': 'y'}>
+CONFIG_TI_CPTS                                  policy<{'armhf': 'y'}>
+CONFIG_TLAN                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Toshiba devices
+CONFIG_NET_VENDOR_TOSHIBA                       policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_GELIC_NET                                policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_GELIC_WIRELESS                           policy<{'powerpc-powerpc64-smp': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> WIZnet interface mode
+CONFIG_WIZNET_BUS_DIRECT                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_WIZNET_BUS_INDIRECT                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_WIZNET_BUS_ANY                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Ethernet driver support >> Xilinx devices
+CONFIG_NET_VENDOR_XILINX                        policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_XILINX_EMACLITE                          policy<{'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_XILINX_LL_TEMAC                          policy<{'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> IEEE 802.15.4 drivers
+CONFIG_IEEE802154_DRIVERS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_FAKELB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_AT86RF230                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_AT86RF230_DEBUGFS             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IEEE802154_MRF24J40                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_CC2520                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_ATUSB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Network core driver support
+CONFIG_NET_CORE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BONDING                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DUMMY                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_EQUALIZER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_FC                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IFB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MACVLAN                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MACVTAP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPVLAN                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VXLAN                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GENEVE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETCONSOLE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETCONSOLE_DYNAMIC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NTB_NETDEV                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RIONET                                   policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RIONET_TX_SIZE                           policy<{'amd64': '128', 'i386': '128', 'powerpc': '128', 'ppc64el': '128'}>
+CONFIG_RIONET_RX_SIZE                           policy<{'amd64': '128', 'i386': '128', 'powerpc': '128', 'ppc64el': '128'}>
+CONFIG_TUN                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TUN_VNET_CROSS_LE                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_VETH                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VIRTIO_NET                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NLMON                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_VRF                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+#
+CONFIG_VIRTIO_NET                               note<KVM paravirt support -- not autoloadable> flag<REVIEW>
+
+# Menu: Device Drivers >> Network device support >> Network core driver support >> Ethernet team driver support
+CONFIG_NET_TEAM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_BROADCAST                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_ROUNDROBIN                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_RANDOM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_ACTIVEBACKUP               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_LOADBALANCE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> PHY Device support and infrastructure
+CONFIG_PHYLIB                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_AQUANTIA_PHY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AT803X_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AMD_PHY                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MARVELL_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DAVICOM_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_QSEMI_PHY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LXT_PHY                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CICADA_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VITESSE_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TERANETICS_PHY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SMSC_PHY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BROADCOM_PHY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BCM7XXX_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BCM87XX_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ICPLUS_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_REALTEK_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NATIONAL_PHY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STE10XP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LSI_ET1011C_PHY                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MICREL_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DP83848_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DP83867_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MICROCHIP_PHY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FIXED_PHY                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_MDIO_BITBANG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MDIO_GPIO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_OCTEON                              policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MDIO_THUNDER                             policy<{'amd64': 'm', 'arm64': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MDIO_BUS_MUX_GPIO                        policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_BUS_MUX_MMIOREG                     policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_BCM_UNIMAC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MDIO_BCM_IPROC                           policy<{'arm64': 'm'}>
+CONFIG_MDIO_XGENE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> PPP (point-to-point protocol) support
+CONFIG_PPP                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PPP_BSDCOMP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_DEFLATE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_FILTER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PPP_MPPE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_MULTILINK                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PPPOATM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPPOE                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPTP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPPOL2TP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_ASYNC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_SYNC_TTY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> S/390 network device drivers
+CONFIG_LCS                                      policy<{'s390x': 'm'}>
+CONFIG_CTCM                                     policy<{'s390x': 'm'}>
+CONFIG_NETIUCV                                  policy<{'s390x': 'm'}>
+CONFIG_SMSGIUCV                                 policy<{'s390x': 'y'}>
+CONFIG_SMSGIUCV_EVENT                           policy<{'s390x': 'm'}>
+CONFIG_QETH                                     policy<{'s390x': 'm'}>
+CONFIG_QETH_L2                                  policy<{'s390x': 'm'}>
+CONFIG_QETH_L3                                  policy<{'s390x': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> SLIP (serial line) support
+CONFIG_SLIP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SLIP_COMPRESSED                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SLIP_SMART                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SLIP_MODE_SLIP6                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> USB Network Adapters
+CONFIG_USB_NET_DRIVERS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CATC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_KAWETH                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_PEGASUS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RTL8150                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RTL8152                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LAN78XX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HSO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_IPHETH                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> USB Network Adapters >> Multi-purpose USB Networking Framework
+CONFIG_USB_CDC_PHONET                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_USBNET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_AX8817X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_AX88179_178A                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDCETHER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDC_EEM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDC_NCM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_HUAWEI_CDC_NCM                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDC_MBIM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_DM9601                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_SR9700                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_SR9800                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_SMSC75XX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_SMSC95XX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_GL620A                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_NET1080                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_PLUSB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_MCS7830                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_RNDIS_HOST                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_ZAURUS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CX82310_ETH                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_KALMIA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_QMI_WWAN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_INT51X1                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SIERRA_NET                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_VL600                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CH9200                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> USB Network Adapters >> Multi-purpose USB Networking Framework >> Simple USB Network Links (CDC Ethernet subset)
+CONFIG_USB_NET_CDC_SUBSET                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ALI_M5632                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_AN2720                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_BELKIN                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ARMLINUX                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EPSON2888                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_KC2190                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wan interfaces support
+CONFIG_WAN                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HOSTESS_SV11                             policy<{'i386': 'm'}>
+CONFIG_COSA                                     policy<{'i386': 'm'}>
+CONFIG_LANMEDIA                                 policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SEALEVEL_4021                            policy<{'i386': 'm'}>
+CONFIG_DLCI                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DLCI_MAX                                 policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8'}>
+CONFIG_SDLA                                     policy<{'i386': 'm'}>
+CONFIG_LAPBETHER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_X25_ASY                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SBNI                                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SBNI_MULTILINE                           policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wan interfaces support >> Generic HDLC layer
+CONFIG_HDLC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_RAW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_RAW_ETH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_CISCO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_FR                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_PPP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_X25                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCI200SYN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WANXL                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PC300TOO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_N2                                       policy<{'i386': 'm'}>
+CONFIG_C101                                     policy<{'i386': 'm'}>
+CONFIG_FARSYNC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DSCC4                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DSCC4_PCISYNC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_DSCC4_PCI_RST                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> WiMAX Wireless Broadband devices
+CONFIG_WIMAX_I2400M_USB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WIMAX_I2400M_DEBUG_LEVEL                 policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN
+CONFIG_WLAN                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PCMCIA_RAYCS                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_LIBERTAS_THINFIRM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_THINFIRM_DEBUG                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_LIBERTAS_THINFIRM_USB                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AIRO                                     policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATMEL                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCI_ATMEL                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCMCIA_ATMEL                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_AT76C50X_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AIRO_CS                                  policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_PCMCIA_WL3501                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_PRISM54                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_ZD1201                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_RNDIS_WLAN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADM8211                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8180                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8187                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAC80211_HWSIM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MWL8K                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_B43LEGACY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_B43LEGACY_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_BRCMSMAC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IPW2100                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IPW2100_MONITOR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2100_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_LIBIPW_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_IWL4965                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IWL3945                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8XXXU                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8XXXU_UNTESTED                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ZD1211RW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ZD1211RW_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CW1200                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CW1200_WLAN_SDIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CW1200_WLAN_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Atheros Wireless Cards
+CONFIG_ATH_CARDS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH5K_PCI                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_BTCOEX_SUPPORT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_HTC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH9K_HTC_DEBUGFS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_AR5523                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WIL6210                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WIL6210_ISR_COR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_WIL6210_TRACING                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_WCN36XX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WCN36XX_DEBUGFS                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Atheros Wireless Cards >> Atheros 5xxx wireless cards support
+CONFIG_ATH5K                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH5K_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH5K_TRACER                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Atheros Wireless Cards >> Atheros 802.11ac wireless cards support
+CONFIG_ATH10K                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH10K_PCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH10K_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH10K_DEBUGFS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH10K_TRACING                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Atheros Wireless Cards >> Atheros 802.11n wireless cards support
+CONFIG_ATH9K                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH9K_PCI                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_AHB                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_DEBUGFS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_STATION_STATISTICS                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_DYNACK                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH9K_WOW                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_RFKILL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_CHANNEL_CONTEXT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_PCOEM                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Atheros Wireless Cards >> Atheros mobile chipsets support
+CONFIG_ATH6KL                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH6KL_SDIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH6KL_USB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH6KL_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH6KL_TRACING                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Atheros Wireless Cards >> Linux Community AR9170 802.11n USB support
+CONFIG_CARL9170                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CARL9170_LEDS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CARL9170_DEBUGFS                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CARL9170_HWRNG                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Broadcom 43xx wireless support (mac80211 stack)
+CONFIG_B43                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_B43_SDIO                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_B43_PHY_G                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PHY_N                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PHY_LP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PHY_HT                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Broadcom 43xx wireless support (mac80211 stack) >> Supported bus types
+CONFIG_B43_BUSES_BCMA_AND_SSB                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_BUSES_BCMA                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_B43_BUSES_SSB                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Broadcom 43xx-legacy data transfer mode
+CONFIG_B43LEGACY_DMA_AND_PIO_MODE               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_B43LEGACY_DMA_MODE                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_B43LEGACY_PIO_MODE                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Broadcom IEEE802.11n embedded FullMAC WLAN driver
+CONFIG_BRCMFMAC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BRCMFMAC_SDIO                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCMFMAC_USB                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCMFMAC_PCIE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCM_TRACING                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCMDBG                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_BRCMDBG                                  flag<DEBUG>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)
+CONFIG_HERMES                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HERMES_PRISM                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_HERMES_CACHE_FW_ON_INIT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_APPLE_AIRPORT                            policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_PLX_HERMES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TMD_HERMES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NORTEL_HERMES                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCMCIA_HERMES                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_PCMCIA_SPECTRUM                          policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_ORINOCO_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)
+CONFIG_HOSTAP                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HOSTAP_FIRMWARE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HOSTAP_FIRMWARE_NVRAM                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_HOSTAP_PLX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HOSTAP_PCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HOSTAP_CS                                policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Intel PRO/Wireless 2200BG and 2915ABG Network Connection
+CONFIG_IPW2200                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IPW2200_MONITOR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2200_RADIOTAP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2200_PROMISCUOUS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2200_QOS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2200_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi)
+CONFIG_IWLWIFI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IWLDVM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IWLMVM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IWLWIFI_BCAST_FILTERING                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_IWLWIFI_UAPSD                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_IWLWIFI_UAPSD                            note<linus d6ca18de129fc4dd4374389561930b32820f35ff>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) >> Debugging Options
+CONFIG_IWLWIFI_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_IWLWIFI_DEBUGFS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IWLWIFI_DEVICE_TRACING                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Marvell 8xxx Libertas WLAN driver support
+CONFIG_LIBERTAS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_CS                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_LIBERTAS_SDIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_SPI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_LIBERTAS_MESH                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Marvell WiFi-Ex Driver
+CONFIG_MWIFIEX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MWIFIEX_SDIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MWIFIEX_PCIE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MWIFIEX_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Mediatek Wireless LAN support
+CONFIG_WL_MEDIATEK                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MT7601U                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Ralink driver support
+CONFIG_RT2X00                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2400PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2500PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RT61PCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2500USB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RT73USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2X00_LIB_DEBUGFS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RT2X00_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Ralink driver support >> Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support
+CONFIG_RT2800PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2800PCI_RT33XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800PCI_RT35XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800PCI_RT53XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800PCI_RT3290                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Ralink driver support >> Ralink rt27xx/rt28xx/rt30xx (USB) support
+CONFIG_RT2800USB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2800USB_RT33XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_RT35XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_RT3573                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_RT53XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_RT55XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_UNKNOWN                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Realtek rtlwifi family of devices
+CONFIG_RTL_CARDS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192CE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192SE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192DE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8723AE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8723BE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8188EE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192EE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8821AE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192CU                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLWIFI_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Redpine Signals Inc 91x WLAN driver support
+CONFIG_RSI_91X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RSI_DEBUGFS                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RSI_SDIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RSI_USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> Softmac Prism54 support
+CONFIG_P54_COMMON                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_P54_USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_P54_PCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_P54_SPI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_P54_SPI_DEFAULT_EEPROM                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> TI Wireless LAN support
+CONFIG_WL_TI                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_WL12XX                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WL18XX                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WLCORE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WLCORE_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WLCORE_SDIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WILINK_PLATFORM_DATA                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> TI Wireless LAN support >> TI wl1251 driver support
+CONFIG_WL1251                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WL1251_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WL1251_SDIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Network device support >> Wireless LAN >> iwl3945 / iwl4965 Debugging Options
+CONFIG_IWLEGACY_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_IWLEGACY_DEBUGFS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Non-Transparent Bridge support
+CONFIG_NTB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NTB_AMD                                  policy<{'amd64': 'm'}>
+CONFIG_NTB_INTEL                                policy<{'amd64': 'm'}>
+CONFIG_NTB_PINGPONG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NTB_TOOL                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NTB_TRANSPORT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Open-Channel SSD target support
+CONFIG_NVM                                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NVM_DEBUG                                policy<{'amd64': '-', 'arm64': '-', 'armhf': '-', 'i386': '-', 'powerpc': '-', 'ppc64el': '-', 's390x': '-'}>
+CONFIG_NVM_GENNVM                               policy<{'amd64': '-', 'arm64': '-', 'armhf': '-', 'i386': '-', 'powerpc': '-', 'ppc64el': '-', 's390x': '-'}>
+CONFIG_NVM_RRPC                                 policy<{'amd64': '-', 'arm64': '-', 'armhf': '-', 'i386': '-', 'powerpc': '-', 'ppc64el': '-', 's390x': '-'}>
+
+# Menu: Device Drivers >> PHY Subsystem
+CONFIG_GENERIC_PHY                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PHY_BERLIN_USB                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_BERLIN_SATA                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_DM816X_USB                           policy<{'armhf': 'm'}>
+CONFIG_PHY_EXYNOS_MIPI_VIDEO                    policy<{'armhf': 'y'}>
+CONFIG_PHY_PXA_28NM_HSIC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PHY_PXA_28NM_USB2                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PHY_RCAR_GEN2                            policy<{'armhf': 'm'}>
+CONFIG_OMAP_CONTROL_PHY                         policy<{'armhf': 'm'}>
+CONFIG_OMAP_USB2                                policy<{'armhf': 'm'}>
+CONFIG_TI_PIPE3                                 policy<{'armhf': 'm'}>
+CONFIG_TWL4030_USB                              policy<{'armhf': 'm'}>
+CONFIG_PHY_EXYNOS_DP_VIDEO                      policy<{'armhf': 'y'}>
+CONFIG_BCM_KONA_USB2_PHY                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PHY_EXYNOS5250_SATA                      policy<{'armhf': 'y'}>
+CONFIG_PHY_HIX5HD2_SATA                         policy<{'armhf': 'm'}>
+CONFIG_PHY_MT65XX_USB3                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_SAMSUNG_USB2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_EXYNOS5_USBDRD                       policy<{'armhf': 'm'}>
+CONFIG_PHY_QCOM_APQ8064_SATA                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_QCOM_IPQ806X_SATA                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_ROCKCHIP_USB                         policy<{'armhf': 'm'}>
+CONFIG_PHY_XGENE                                policy<{'arm64': 'y'}>
+CONFIG_PHY_QCOM_UFS                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_TUSB1210                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> PPS support
+
+# Menu: Device Drivers >> PPS support >> PPS support
+CONFIG_PPS                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_PPS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PPS_CLIENT_KTIMER                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PPS_CLIENT_LDISC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PPS_CLIENT_PARPORT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PPS_CLIENT_GPIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+#
+CONFIG_PPS_CLIENT_KTIMER                        flag<TESTING>
+CONFIG_PPS                                      flag<REVIEW>
+
+# Menu: Device Drivers >> PTP clock support
+CONFIG_PTP_1588_CLOCK                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_PTP_1588_CLOCK_GIANFAR                   policy<{'arm64': 'm', 'armhf-generic': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_PTP_1588_CLOCK_PCH                       policy<{'i386': 'm'}>
+#
+CONFIG_PTP_1588_CLOCK                           flag<REVIEW>
+
+# Menu: Device Drivers >> Parallel port support
+CONFIG_PARPORT                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PARPORT_AX88796                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARPORT_1284                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Parallel port support >> PC-style hardware
+CONFIG_PARPORT_PC                               policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARPORT_SERIAL                           policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PARPORT_PC_FIFO                          policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PARPORT_PC_SUPERIO                       policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_PARPORT_PC_PCMCIA                        policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> Performance monitor support
+CONFIG_ARM_PMU                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+
+# Menu: Device Drivers >> Pin controllers
+CONFIG_PINMUX                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PINCONF                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_DEBUG_PINCTRL                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_PINCTRL_AS3722                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_AMD                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PINCTRL_SINGLE                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_PALMAS                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_BERLIN_BG4CT                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_IMX50                            policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_IMX51                            policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_IMX6Q                            policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_IMX6SL                           policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_IMX6SX                           policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_IMX6UL                           policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_IMX7D                            policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_VF610                            policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_BAYTRAIL                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_PINCTRL_CHERRYVIEW                       policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_PINCTRL_BROXTON                          policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_SUNRISEPOINT                     policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_APQ8064                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_APQ8084                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_IPQ8064                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8660                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8960                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8X74                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8916                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_QDF2XXX                          policy<{'arm64': 'm'}>
+CONFIG_PINCTRL_QCOM_SPMI_PMIC                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_QCOM_SSBI_PMIC                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_EXYNOS                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_EXYNOS5440                       policy<{'armhf': 'y'}>
+CONFIG_GPIO_SH_PFC                              policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_PH1_LD4                 policy<{'armhf': 'm'}>
+CONFIG_PINCTRL_UNIPHIER_PH1_PRO4                policy<{'armhf': 'm'}>
+CONFIG_PINCTRL_UNIPHIER_PH1_SLD8                policy<{'armhf': 'm'}>
+CONFIG_PINCTRL_UNIPHIER_PH1_PRO5                policy<{'armhf': 'm'}>
+CONFIG_PINCTRL_UNIPHIER_PROXSTREAM2             policy<{'armhf': 'm'}>
+CONFIG_PINCTRL_UNIPHIER_PH1_LD6B                policy<{'armhf': 'm'}>
+CONFIG_PINCTRL_MT8135                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_PINCTRL_MT8127                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_PINCTRL_MT8173                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MT6397                           policy<{'arm64': 'y', 'armhf': 'y'}>
+#
+CONFIG_PINCTRL_MT8135                           flag<REVIEW>
+CONFIG_PINCTRL_MT8127                           flag<REVIEW>
+
+# Menu: Device Drivers >> Pin controllers >> Nomadik pin controller driver
+
+# Menu: Device Drivers >> Pin controllers >> ST-Ericsson ABx500 family Mixed Signal Circuit gpio functions
+
+# Menu: Device Drivers >> Platform support for Chrome hardware
+CONFIG_CHROME_PLATFORMS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_CHROMEOS_LAPTOP                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CHROMEOS_PSTORE                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_CHARDEV                          policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_LPC                              policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> Plug and Play support
+CONFIG_PNP                                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_PNP_DEBUG_MESSAGES                       policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_ISAPNP                                   policy<{'i386': 'y'}>
+CONFIG_PNPBIOS                                  policy<{'i386': 'y'}>
+CONFIG_PNPBIOS_PROC_FS                          policy<{'i386': 'y'}>
+
+# Menu: Device Drivers >> Power supply class support
+CONFIG_POWER_SUPPLY                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_POWER_SUPPLY_DEBUG                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_PDA_POWER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_APM_POWER                                policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_GENERIC_ADC_BATTERY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX8925_POWER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WM831X_BACKUP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WM831X_POWER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WM8350_POWER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TEST_POWER                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_88PM860X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DS2760                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DS2780                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DS2781                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DS2782                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_PMU                              policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_BATTERY_SBS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_BQ27XXX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_BQ27XXX_I2C                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BATTERY_BQ27XXX_PLATFORM                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BATTERY_DA9030                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DA9052                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_DA9150                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DA9150                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AXP288_CHARGER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AXP288_FUEL_GAUGE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_MAX17040                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_MAX17042                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_TWL4030_MADC                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_88PM860X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_PCF50633                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_INTEL_MID                        policy<{'i386': 'm'}>
+CONFIG_BATTERY_RX51                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_ISP1704                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX8903                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_TWL4030                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_LP8727                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_LP8788                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_GPIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MANAGER                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CHARGER_MAX14577                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX77693                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX8997                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX8998                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_QCOM_SMBB                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CHARGER_BQ2415X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ24190                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ24257                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ24735                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ25890                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_SMB347                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_TPS65090                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_TPS65217                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_GAUGE_LTC2941                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_RT5033                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_RT9455                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AXP20X_POWER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Power supply class support >> Board level reset or power off
+CONFIG_POWER_RESET                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_AS3722                       policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_AXXIA                        policy<{'armhf-generic-lpae': 'y'}>
+CONFIG_POWER_RESET_BRCMSTB                      policy<{'armhf': 'n'}>
+CONFIG_POWER_RESET_GPIO                         policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_GPIO_RESTART                 policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_HISI                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_POWER_RESET_IMX                          policy<{'armhf-generic': 'n'}>
+CONFIG_POWER_RESET_MSM                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_POWER_RESET_LTC2952                      policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_QNAP                         policy<{'armhf': 'n'}>
+CONFIG_POWER_RESET_RESTART                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_VERSATILE                    policy<{'armhf': 'y'}>
+CONFIG_POWER_RESET_VEXPRESS                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_POWER_RESET_XGENE                        policy<{'arm64': 'n'}>
+CONFIG_POWER_RESET_SYSCON                       policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_SYSCON_POWEROFF              policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_RMOBILE                      policy<{'armhf': 'm'}>
+CONFIG_POWER_RESET_ZX                           policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Pulse-Width Modulation (PWM) Support
+CONFIG_PWM                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PWM_ATMEL_HLCDC_PWM                      policy<{'arm64': 'm', 'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_PWM_BERLIN                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_CRC                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PWM_FSL_FTM                              policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PWM_IMX                                  policy<{'armhf-generic': 'm'}>
+CONFIG_PWM_LP3943                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PWM_LPSS_PCI                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PWM_LPSS_PLATFORM                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PWM_MTK_DISP                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_OMAP_DMTIMER                         policy<{'armhf': 'm'}>
+CONFIG_PWM_PCA9685                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PWM_RCAR                                 policy<{'armhf': 'm'}>
+CONFIG_PWM_RENESAS_TPU                          policy<{'armhf': 'm'}>
+CONFIG_PWM_ROCKCHIP                             policy<{'armhf': 'm'}>
+CONFIG_PWM_SAMSUNG                              policy<{'armhf': 'm'}>
+CONFIG_PWM_TEGRA                                policy<{'armhf-generic': 'm'}>
+CONFIG_PWM_TIECAP                               policy<{'armhf': 'm'}>
+CONFIG_PWM_TIEHRPWM                             policy<{'armhf': 'm'}>
+CONFIG_PWM_TWL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PWM_TWL_LED                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Real Time Clock
+CONFIG_RTC_CLASS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_HCTOSYS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_HCTOSYS_DEVICE                       policy<{'amd64': '"rtc0"', 'arm64': '"rtc0"', 'armhf': '"rtc0"', 'i386': '"rtc0"', 'powerpc': '"rtc0"', 'ppc64el': '"rtc0"'}>
+CONFIG_RTC_SYSTOHC                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_SYSTOHC_DEVICE                       policy<{'amd64': '"rtc0"', 'arm64': '"rtc0"', 'armhf': '"rtc0"', 'i386': '"rtc0"', 'powerpc': '"rtc0"', 'ppc64el': '"rtc0"'}>
+CONFIG_RTC_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_INTF_SYSFS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_INTF_PROC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_INTF_DEV                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_INTF_DEV_UIE_EMUL                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_TEST                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_88PM860X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_88PM80X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ABB5ZES3                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ABX80X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_AS3722                           policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1307                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1374                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1374_WDT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_DS1672                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS3232                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'm', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_HYM8563                          policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_LP8788                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX6900                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX8907                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX8925                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX8998                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX8997                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX77686                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RK808                            policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX77802                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RS5C372                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ISL1208                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ISL12022                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ISL12057                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_X1205                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PALMAS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF2127                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF8523                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF8563                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF85063                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF8583                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M41T80                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M41T80_WDT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_BQ32K                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_TWL4030                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_TPS6586X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_TPS65910                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_TPS80031                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RC5T583                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_S35390A                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_FM3130                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RX8581                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RX8025                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_EM3027                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RV3029C2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RV8803                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_S5M                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M41T93                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M41T94                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1305                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1343                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1347                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1390                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX6902                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_R9701                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RS5C348                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS3234                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF2123                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RX4581                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MCP795                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_CMOS                             policy<{'amd64': 'y', 'armhf': 'm', 'i386': 'y', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_VRTC                             policy<{'i386': 'm'}>
+CONFIG_RTC_DRV_DS1286                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1511                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1553                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1742                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS2404                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DA9052                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DA9055                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DA9063                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_EFI                              policy<{'arm64': 'y'}>
+CONFIG_RTC_DRV_STK17TA8                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M48T86                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M48T35                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M48T59                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MSM6242                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_BQ4802                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RP5C01                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_V3020                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_WM831X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_WM8350                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF50633                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_AB3100                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_OPAL                             policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_ZYNQMP                           policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_IMXDI                            policy<{'armhf-generic': 'm'}>
+CONFIG_RTC_DRV_OMAP                             policy<{'armhf': 'y'}>
+CONFIG_RTC_DRV_S3C                              policy<{'armhf': 'y'}>
+CONFIG_RTC_DRV_PL030                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_PL031                            policy<{'arm64': 'm', 'armhf': 'y'}>
+CONFIG_RTC_DRV_GENERIC                          policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MV                               policy<{'armhf': 'y'}>
+CONFIG_RTC_DRV_ARMADA38X                        policy<{'armhf': 'm'}>
+CONFIG_RTC_DRV_PS3                              policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_RTC_DRV_PCAP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MC13XXX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PM8XXX                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_TEGRA                            policy<{'armhf-generic': 'm'}>
+CONFIG_RTC_DRV_MXC                              policy<{'armhf-generic': 'm'}>
+CONFIG_RTC_DRV_SNVS                             policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MT6397                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_XGENE                            policy<{'arm64': 'y'}>
+CONFIG_RTC_DRV_HID_SENSOR_TIME                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_RTC_DRV_TEST                             flag<TESTING>
+CONFIG_RTC_DRV_CMOS                             note<boot essential on i386/amd64>
+CONFIG_RTC_DRV_EFI                              note<LP:#1583738>
+CONFIG_RTC_DRV_TWL4030                          note<boot essential on OMAP3/OMAP4>
+
+# Menu: Device Drivers >> Real Time Clock >> Dallas/Maxim DS1685 Family
+CONFIG_RTC_DRV_DS1685_FAMILY                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DS1685_PROC_REGS                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DS1685_SYSFS_REGS                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Real Time Clock >> Dallas/Maxim DS1685 Family >> Subtype
+CONFIG_RTC_DRV_DS1685                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_DS1689                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_DS17285                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_DS17485                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_DS17885                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Reliability, Availability and Serviceability (RAS) features
+CONFIG_RAS                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AMD_MCE_INJ                              policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> Remoteproc drivers
+CONFIG_OMAP_REMOTEPROC                          policy<{'armhf-generic': 'm'}>
+CONFIG_STE_MODEM_RPROC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_WKUP_M3_RPROC                            policy<{'armhf-generic': 'm'}>
+
+# Menu: Device Drivers >> SCSI device support
+CONFIG_RAID_ATTRS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support
+CONFIG_SCSI                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_MQ_DEFAULT                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SCSI_PROC_FS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_SD                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CHR_DEV_ST                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CHR_DEV_OSST                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_SR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_SR_VENDOR                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_CHR_DEV_SG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CHR_DEV_SCH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_ENCLOSURE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_CONSTANTS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_LOGGING                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_SCAN_ASYNC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_SCSI                                     flag<REVIEW>
+CONFIG_CHR_DEV_SG                               note<not autoloadable>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> OSD-Initiator library
+CONFIG_SCSI_OSD_INITIATOR                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_OSD_ULD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_OSD_DPRINT_SENSE                    policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'powerpc': '1', 'ppc64el': '1', 's390x': '1'}>
+CONFIG_SCSI_OSD_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> PCMCIA SCSI adapter support
+CONFIG_SCSI_LOWLEVEL_PCMCIA                     policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_PCMCIA_AHA152X                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_PCMCIA_FDOMAIN                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_PCMCIA_NINJA_SCSI                        policy<{'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_PCMCIA_QLOGIC                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_PCMCIA_SYM53C500                         policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI Device Handlers
+CONFIG_SCSI_DH                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_DH_RDAC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_DH_HP_SW                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_DH_EMC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_DH_ALUA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI Transports
+CONFIG_SCSI_SPI_ATTRS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_FC_ATTRS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_ISCSI_ATTRS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_SAS_ATTRS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_SAS_LIBSAS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_SAS_ATA                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_SAS_HOST_SMP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_SRP_ATTRS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI low-level drivers
+CONFIG_SCSI_LOWLEVEL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ISCSI_TCP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ISCSI_BOOT_SYSFS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_CXGB3_ISCSI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_CXGB4_ISCSI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_BNX2_ISCSI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_BNX2X_FCOE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BE2ISCSI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CXLFLASH                                 policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_BLK_DEV_3W_XXXX_RAID                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_HPSA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_3W_9XXX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_3W_SAS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_7000FASST                           policy<{'i386': 'm'}>
+CONFIG_SCSI_ACARD                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_AHA152X                             policy<{'i386': 'm'}>
+CONFIG_SCSI_AHA1542                             policy<{'i386': 'm'}>
+CONFIG_SCSI_AHA1740                             policy<{'i386': 'm'}>
+CONFIG_SCSI_AACRAID                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_AIC94XX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_AIC94XX_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_MVSAS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_MVSAS_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_MVSAS_TASKLET                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_MVUMI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_DPT_I2O                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm', 's390x': 'n'}>
+CONFIG_SCSI_ADVANSYS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_IN2000                              policy<{'i386': 'm'}>
+CONFIG_SCSI_ARCMSR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_ESAS2R                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MEGARAID_NEWGEN                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MEGARAID_MM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEGARAID_MAILBOX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEGARAID_LEGACY                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MEGARAID_SAS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_MPT3SAS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_MPT2SAS_MAX_SGE                     policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'powerpc': '128', 'ppc64el': '128', 's390x': '128'}>
+CONFIG_SCSI_MPT3SAS_MAX_SGE                     policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'powerpc': '128', 'ppc64el': '128', 's390x': '128'}>
+CONFIG_SCSI_MPT2SAS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_UFSHCD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_UFSHCD_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_UFSHCD_PLATFORM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_UFS_QCOM                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_HPTIOP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_BUSLOGIC                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SCSI_FLASHPOINT                          policy<{'amd64': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_VMWARE_PVSCSI                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_XEN_SCSI_FRONTEND                        policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_STORAGE                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LIBFC                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LIBFCOE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FCOE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FCOE_FNIC                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCSI_SNIC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_SNIC_DEBUG_FS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_DMX3191D                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_DTC3280                             policy<{'i386': 'm'}>
+CONFIG_SCSI_FUTURE_DOMAIN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_GDTH                                policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_ISCI                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCSI_GENERIC_NCR5380                     policy<{'i386': 'm'}>
+CONFIG_SCSI_GENERIC_NCR5380_MMIO                policy<{'i386': 'm'}>
+CONFIG_SCSI_GENERIC_NCR53C400                   policy<{'i386': 'y'}>
+CONFIG_SCSI_IPS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_IBMVSCSI                            policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_IBMVSCSIS                           policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_IBMVFC                              policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_IBMVFC_TRACE                        policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_INITIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_INIA100                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_PPA                                 policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_IMM                                 policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_IZIP_EPP16                          policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_IZIP_SLOW_CTR                       policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_NCR53C406A                          policy<{'i386': 'm'}>
+CONFIG_SCSI_STEX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_IPR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_IPR_TRACE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_IPR_DUMP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_PAS16                               policy<{'i386': 'm'}>
+CONFIG_SCSI_QLOGIC_FAS                          policy<{'i386': 'm'}>
+CONFIG_SCSI_QLOGIC_1280                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_QLA_FC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TCM_QLA2XXX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_QLA_ISCSI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_LPFC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_LPFC_DEBUG_FS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_SIM710                              policy<{'i386': 'm'}>
+CONFIG_SCSI_SYM53C416                           policy<{'i386': 'm'}>
+CONFIG_SCSI_DC395x                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_AM53C974                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_T128                                policy<{'i386': 'm'}>
+CONFIG_SCSI_ULTRASTOR                           policy<{'i386': 'm'}>
+CONFIG_SCSI_NSP32                               policy<{'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SCSI_WD719X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_DEBUG                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_MESH                                policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_SCSI_MESH_SYNC_RATE                      policy<{'powerpc-powerpc-smp': '5'}>
+CONFIG_SCSI_MESH_RESET_DELAY_MS                 policy<{'powerpc-powerpc-smp': '4000'}>
+CONFIG_SCSI_MAC53C94                            policy<{'powerpc-powerpc-smp': 'm'}>
+CONFIG_ZFCP                                     policy<{'s390x': 'm'}>
+CONFIG_SCSI_PMCRAID                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_PM8001                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_BFA_FC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_VIRTIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_CHELSIO_FCOE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+#
+CONFIG_SCSI_IPR_TRACE                           note<LP:1343109>
+CONFIG_SCSI_IPR_DUMP                            note<LP:1343109>
+CONFIG_SCSI_VIRTIO                              note<tech preview of new feature>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI low-level drivers >> Adaptec AIC79xx U320 support
+CONFIG_SCSI_AIC79XX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_AIC79XX_CMDS_PER_DEVICE                  policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'powerpc': '32', 'ppc64el': '32'}>
+CONFIG_AIC79XX_RESET_DELAY_MS                   policy<{'amd64': '5000', 'arm64': '5000', 'armhf': '5000', 'i386': '5000', 'powerpc': '5000', 'ppc64el': '5000'}>
+CONFIG_AIC79XX_DEBUG_ENABLE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_AIC79XX_DEBUG_MASK                       policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+CONFIG_AIC79XX_REG_PRETTY_PRINT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI low-level drivers >> Adaptec AIC7xxx Fast -> U160 support (New Driver)
+CONFIG_SCSI_AIC7XXX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_AIC7XXX_CMDS_PER_DEVICE                  policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8'}>
+CONFIG_AIC7XXX_RESET_DELAY_MS                   policy<{'amd64': '5000', 'arm64': '5000', 'armhf': '5000', 'i386': '5000', 'powerpc': '5000', 'ppc64el': '5000'}>
+CONFIG_AIC7XXX_DEBUG_ENABLE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_AIC7XXX_DEBUG_MASK                       policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+CONFIG_AIC7XXX_REG_PRETTY_PRINT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI low-level drivers >> EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support
+CONFIG_SCSI_EATA                                policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_EATA_TAGGED_QUEUE                   policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_EATA_LINKED_COMMANDS                policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_EATA_MAX_TAGS                       policy<{'amd64': '16', 'i386': '16', 'powerpc': '16', 'ppc64el': '16'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI low-level drivers >> NCR Quad 720 MCA SCSI support
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI low-level drivers >> SYM53C8XX Version 2 SCSI support
+CONFIG_SCSI_SYM53C8XX_2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE       policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'powerpc': '1', 'ppc64el': '1'}>
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS              policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'powerpc': '16', 'ppc64el': '16'}>
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS                  policy<{'amd64': '64', 'arm64': '64', 'armhf': '64', 'i386': '64', 'powerpc': '64', 'ppc64el': '64'}>
+CONFIG_SCSI_SYM53C8XX_MMIO                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> SCSI device support >> SCSI device support >> SCSI low-level drivers >> UltraStor 14F/34F support
+CONFIG_SCSI_U14_34F                             policy<{'i386': 'm'}>
+CONFIG_SCSI_U14_34F_TAGGED_QUEUE                policy<{'i386': 'y'}>
+CONFIG_SCSI_U14_34F_LINKED_COMMANDS             policy<{'i386': 'y'}>
+CONFIG_SCSI_U14_34F_MAX_TAGS                    policy<{'i386': '8'}>
+
+# Menu: Device Drivers >> SOC (System On Chip) specific Drivers
+CONFIG_SOC_BRCMSTB                              policy<{'armhf': 'y'}>
+CONFIG_MTK_INFRACFG                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MTK_PMIC_WRAP                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTK_SCPSYS                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_GSBI                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_PM                                  policy<{'armhf': 'y'}>
+CONFIG_QCOM_SMEM                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SMD                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SMD_RPM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ROCKCHIP_PM_DOMAINS                      policy<{'armhf': 'y'}>
+
+# Menu: Device Drivers >> SOC (System On Chip) specific Drivers >> TI SOC drivers support
+CONFIG_SOC_TI                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+#
+CONFIG_SOC_TI                                   flag<REVIEW>
+
+# Menu: Device Drivers >> SPI support
+CONFIG_SPI                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SPI_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SPI_ALTERA                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_BITBANG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_BUTTERFLY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_CADENCE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_DLN2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_GPIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_IMX                                  policy<{'armhf-generic': 'm'}>
+CONFIG_SPI_LM70_LLP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_FSL_SPI                              policy<{'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_FSL_DSPI                             policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SPI_FSL_ESPI                             policy<{'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_SPI_MESON_SPIFC                          policy<{'armhf': 'm'}>
+CONFIG_SPI_MT65XX                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_OC_TINY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_OMAP24XX                             policy<{'armhf': 'y'}>
+CONFIG_SPI_TI_QSPI                              policy<{'armhf': 'm'}>
+CONFIG_SPI_ORION                                policy<{'armhf': 'm'}>
+CONFIG_SPI_PL022                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_PXA2XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_ROCKCHIP                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_RSPI                                 policy<{'armhf': 'm'}>
+CONFIG_SPI_QUP                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_S3C64XX                              policy<{'armhf': 'm'}>
+CONFIG_SPI_SC18IS602                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_SH_MSIOF                             policy<{'armhf': 'm'}>
+CONFIG_SPI_SH_HSPI                              policy<{'armhf': 'm'}>
+CONFIG_SPI_TEGRA114                             policy<{'armhf-generic': 'm'}>
+CONFIG_SPI_TEGRA20_SFLASH                       policy<{'armhf-generic': 'm'}>
+CONFIG_SPI_TEGRA20_SLINK                        policy<{'armhf-generic': 'm'}>
+CONFIG_SPI_TOPCLIFF_PCH                         policy<{'i386': 'm'}>
+CONFIG_SPI_XCOMM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_XILINX                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SPI_ZYNQMP_GQSPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_DESIGNWARE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_DW_PCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_DW_MID_DMA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_DW_MMIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_SPIDEV                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_TLE62X0                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> SPMI support
+CONFIG_SPMI                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SPMI_MSM_PMIC_ARB                        policy<{'arm64': 'm', 'armhf': 'm'}>
+
+# Menu: Device Drivers >> Serial ATA and Parallel ATA drivers (libata)
+CONFIG_ATA                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATA_VERBOSE_ERROR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATA_ACPI                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_SATA_ZPODD                               policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_SATA_PMP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SATA_AHCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_AHCI_PLATFORM                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AHCI_IMX                                 policy<{'armhf-generic': 'y'}>
+CONFIG_AHCI_CEVA                                policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AHCI_MVEBU                               policy<{'armhf': 'm'}>
+CONFIG_AHCI_TEGRA                               policy<{'armhf-generic': 'm'}>
+CONFIG_AHCI_XGENE                               policy<{'arm64': 'm'}>
+CONFIG_AHCI_QORIQ                               policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_FSL                                 policy<{'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_SATA_INIC162X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_ACARD_AHCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_SIL24                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_SATA_AHCI_PLATFORM                       note<boot essential on highbank>
+
+# Menu: Device Drivers >> Serial ATA and Parallel ATA drivers (libata) >> ATA SFF support (for legacy IDE and PATA)
+CONFIG_ATA_SFF                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PDC_ADMA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_QSTOR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_SX4                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_CMD640_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ISAPNP                              policy<{'i386': 'm'}>
+CONFIG_PATA_MPIIX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_NS87410                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_OPTI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_PCMCIA                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_PATA_PLATFORM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_OF_PLATFORM                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_QDI                                 policy<{'i386': 'm'}>
+CONFIG_PATA_RZ1000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_WINBOND_VLB                         policy<{'i386': 'm'}>
+CONFIG_PATA_LEGACY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Serial ATA and Parallel ATA drivers (libata) >> ATA SFF support (for legacy IDE and PATA) >> ATA BMDMA support
+CONFIG_ATA_BMDMA                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ATA_PIIX                                 policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'y', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_HIGHBANK                            policy<{'armhf': 'y'}>
+CONFIG_SATA_MV                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_NV                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_PROMISE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_RCAR                                policy<{'armhf': 'm'}>
+CONFIG_SATA_SIL                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_SIS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_SVW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'y', 'ppc64el': 'm'}>
+CONFIG_SATA_ULI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_VIA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_VITESSE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ALI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_AMD                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ARTOP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ATIIXP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ATP867X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_CMD64X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_CS5520                              policy<{'i386': 'm'}>
+CONFIG_PATA_CS5530                              policy<{'i386': 'm'}>
+CONFIG_PATA_CS5535                              policy<{'i386': 'm'}>
+CONFIG_PATA_CS5536                              policy<{'i386': 'm'}>
+CONFIG_PATA_CYPRESS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_EFAR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT366                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT37X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT3X2N                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT3X3                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT3X3_DMA                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_PATA_IMX                                 policy<{'armhf-generic': 'm'}>
+CONFIG_PATA_IT8213                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_IT821X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_JMICRON                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_MACIO                               policy<{'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_PATA_MARVELL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_NETCELL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_NINJA32                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_NS87415                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_OLDPIIX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_OPTIDMA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_PDC2027X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_PDC_OLD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_RADISYS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_RDC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_SC1200                              policy<{'i386': 'm'}>
+CONFIG_PATA_SCH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_SERVERWORKS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_SIL680                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_SIS                                 policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'y', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_TOSHIBA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_TRIFLEX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_VIA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_WINBOND                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ACPI                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ATA_GENERIC                              policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'y', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_SATA_HIGHBANK                            mark<ENFORCED> note<LP:1703430>
+CONFIG_PATA_HPT3X3_DMA                          note<DMA mode is documented problematic>
+
+# Menu: Device Drivers >> Sonics Silicon Backplane
+CONFIG_SSB_PCIHOST                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_PCMCIAHOST                           policy<{'amd64': 'n', 'i386': 'n', 'powerpc': 'n'}>
+CONFIG_SSB_SDIOHOST                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_DRIVER_PCICORE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Sonics Silicon Backplane >> Sonics Silicon Backplane support
+CONFIG_SSB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SSB_HOST_SOC                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_SILENT                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SSB_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SSB_DRIVER_GPIO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Sony MemoryStick card support
+CONFIG_MEMSTICK                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MEMSTICK_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MEMSTICK_UNSAFE_RESUME                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MSPRO_BLOCK                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MS_BLOCK                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_TIFM_MS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_JMICRON_38X                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_R592                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_REALTEK_PCI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_REALTEK_USB                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Sound card support
+CONFIG_SOUND                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SOUND_OSS_CORE_PRECLAIM                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_SOUND                                    note<not autoloadable on omap>
+CONFIG_SOUND_OSS_CORE_PRECLAIM                  mark<ENFORCED> note<LP#1105230 LP#1385510>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture
+CONFIG_SND                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQUENCER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQ_DUMMY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MIXER_OSS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_PCM_OSS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_PCM_OSS_PLUGINS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_PCM_TIMER                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SEQUENCER_OSS                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_HRTIMER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQ_HRTIMER_DEFAULT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_DYNAMIC_MINORS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_MAX_CARDS                            policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'powerpc': '32', 'ppc64el': '32'}>
+CONFIG_SND_SUPPORT_OLD_API                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_PROC_FS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_VERBOSE_PROCFS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_VERBOSE_PRINTK                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_HDA_PREALLOC_SIZE                    policy<{'amd64': '64', 'arm64': '64', 'armhf': '64', 'i386': '64', 'powerpc': '64', 'ppc64el': '64'}>
+#
+CONFIG_SND                                      note<not autoloadable on omap>
+CONFIG_SND_PCM_OSS                              note<deprecated in favour of pulseaudio emulation>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support
+CONFIG_SND_SOC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_DESIGNWARE_I2S                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+CONFIG_SND_KIRKWOOD_SOC                         policy<{'armhf': 'm'}>
+CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB            policy<{'armhf': 'm'}>
+CONFIG_SND_MFLD_MACHINE                         policy<{'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_HASWELL_MACH               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BROADWELL_MACH             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYTCR_RT5660_MACH          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SKL_RT286_MACH             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_MEDIATEK                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT8173_MAX98090                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT8173_RT5650_RT5676             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QCOM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_STORM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_APQ8016_SBC                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_XTFPGA_I2S                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SIMPLE_CARD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_SND_SOC                                  note<not autoloadable on omap>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> ASoC support for Rockchip
+CONFIG_SND_SOC_ROCKCHIP                         policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_I2S                     policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_SPDIF                   policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_MAX98090                policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_RT5645                  policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> ASoC support for Samsung
+CONFIG_SND_SOC_SAMSUNG                          policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994              policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF               policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SMDK_WM8994_PCM                  policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SNOW                             policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_ODROIDX2                         policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631           policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> Allwinner SoC Audio support
+CONFIG_SND_SUN4I_CODEC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> CODEC drivers
+CONFIG_SND_SOC_AC97_CODEC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ADAU1701                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4104                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4554                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4613                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4642                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK5386                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ALC5623                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS35L32                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L51_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L52                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L56                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L73                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4265                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4270                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4271_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4271_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42XX8_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4349                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ES8328                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_GTM601                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM1681                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM1792A                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM512x_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM512x_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_RT5631                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SGTL5000                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SIRF_AUDIO_CODEC                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SPDIF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SSM2602_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SSM2602_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SSM4567                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_STA32X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_STA350                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_STI_SAS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TAS2552                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TAS5086                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TAS571X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TFA9879                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TLV320AIC23_I2C                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TLV320AIC23_SPI                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TLV320AIC31XX                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TLV320AIC3X                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TS3A227E                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8510                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8523                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8580                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8711                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8728                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8731                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8737                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8741                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8750                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8753                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8770                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8776                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8804_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8804_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8903                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8962                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8978                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TPA6130A2                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_SND_SOC_SGTL5000                         flag<REVIEW>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC AC97 Audio for the ADI BF5xx chip
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for Freescale CPUs
+CONFIG_SND_SOC_FSL_ASRC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_SAI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_SSI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_SPDIF                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_ESAI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMX_AUDMUX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_SND_SOC_FSL_SSI                          flag<REVIEW>
+CONFIG_SND_SOC_IMX_AUDMUX                       flag<REVIEW>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for Freescale CPUs >> SoC Audio for Freescale PowerPC CPUs
+CONFIG_SND_POWERPC_SOC                          policy<{'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for Freescale CPUs >> SoC Audio for Freescale i.MX CPUs
+CONFIG_SND_IMX_SOC                              policy<{'armhf-generic': 'y'}>
+CONFIG_SND_SOC_EUKREA_TLV320                    policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_IMX_WM8962                       policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_IMX_ES8328                       policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_IMX_SGTL5000                     policy<{'armhf-generic': 'y'}>
+CONFIG_SND_SOC_IMX_SPDIF                        policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_IMX_MC13783                      policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_FSL_ASOC_CARD                    policy<{'armhf-generic': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for Freescale MXS CPUs
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for Texas Instruments chips using eDMA
+CONFIG_SND_EDMA_SOC                             policy<{'armhf-generic': 'm'}>
+CONFIG_SND_DAVINCI_SOC_MCASP                    policy<{'armhf': 'm'}>
+CONFIG_SND_AM33XX_SOC_EVM                       policy<{'armhf-generic': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for Texas Instruments chips using eDMA >> DM365 codec select
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for the Atmel System-on-Chip
+CONFIG_SND_ATMEL_SOC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for the Intel PXA2xx chip
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for the Tegra System-on-Chip
+CONFIG_SND_SOC_TEGRA                            policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_RT5640                     policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_WM8753                     policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_WM8903                     policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_WM9712                     policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_TRIMSLICE                  policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_ALC5632                    policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_MAX98090                   policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_RT5677                     policy<{'armhf-generic': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio for the Texas Instruments OMAP chips
+CONFIG_SND_OMAP_SOC                             policy<{'armhf': 'y'}>
+CONFIG_SND_OMAP_SOC_HDMI_AUDIO                  policy<{'armhf': 'm'}>
+CONFIG_SND_OMAP_SOC_RX51                        policy<{'armhf': 'm'}>
+CONFIG_SND_OMAP_SOC_OMAP_TWL4030                policy<{'armhf': 'y'}>
+CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040            policy<{'armhf-generic': 'm'}>
+CONFIG_SND_OMAP_SOC_OMAP3_PANDORA               policy<{'armhf-generic': 'm'}>
+#
+CONFIG_SND_OMAP_SOC                             note<required for omap3 sound>
+CONFIG_SND_OMAP_SOC_OMAP_TWL4030                note<not autoloadable on omap>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio support for SuperH
+CONFIG_SND_SOC_SH4_FSI                          policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_RCAR                             policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_RSRC_CARD                        policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio support for Ux500 platform
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC Audio support for the Cirrus Logic EP93xx series
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support >> SoC I2S Audio for the ADI Blackfin chip
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ARM sound devices
+CONFIG_SND_ARM                                  policy<{'armhf': 'y'}>
+CONFIG_SND_ARMAACI                              policy<{'armhf': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> Apple Onboard Audio driver
+CONFIG_SND_AOA                                  policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SND_AOA_FABRIC_LAYOUT                    policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SND_AOA_ONYX                             policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SND_AOA_TAS                              policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SND_AOA_TOONIE                           policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SND_AOA_SOUNDBUS                         policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SND_AOA_SOUNDBUS_I2S                     policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> Atmel devices (AVR32 and AT91)
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> FireWire sound devices
+CONFIG_SND_FIREWIRE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_DICE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_OXFW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ISIGHT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SCS1X                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FIREWORKS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_BEBOB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FIREWIRE_DIGI00X                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FIREWIRE_TASCAM                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> GSC sound devices
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> Generic sound devices
+CONFIG_SND_DRIVERS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_PCSP                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_DUMMY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ALOOP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VIRMIDI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MTPAV                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MTS64                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SERIAL_U16550                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MPU401                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_PORTMAN2X4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AC97_POWER_SAVE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_AC97_POWER_SAVE_DEFAULT              policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> HD-Audio
+CONFIG_SND_HDA_INTEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_TEGRA                            policy<{'armhf-generic': 'm'}>
+CONFIG_SND_HDA_HWDEP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_RECONFIG                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_INPUT_BEEP                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_INPUT_BEEP_MODE                  policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+CONFIG_SND_HDA_PATCH_LOADER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_CODEC_REALTEK                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_ANALOG                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_SIGMATEL                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_VIA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_HDMI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CIRRUS                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CONEXANT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CA0110                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CA0132                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CA0132_DSP                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_CODEC_CMEDIA                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_SI3054                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_GENERIC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT               policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+#
+CONFIG_SND_HDA_RECONFIG                         note<allows fixes to be tested live>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ISA sound devices
+CONFIG_SND_ISA                                  policy<{'i386': 'y'}>
+CONFIG_SND_ADLIB                                policy<{'i386': 'm'}>
+CONFIG_SND_AD1816A                              policy<{'i386': 'm'}>
+CONFIG_SND_AD1848                               policy<{'i386': 'm'}>
+CONFIG_SND_ALS100                               policy<{'i386': 'm'}>
+CONFIG_SND_AZT1605                              policy<{'i386': 'm'}>
+CONFIG_SND_AZT2316                              policy<{'i386': 'm'}>
+CONFIG_SND_AZT2320                              policy<{'i386': 'm'}>
+CONFIG_SND_CMI8328                              policy<{'i386': 'm'}>
+CONFIG_SND_CMI8330                              policy<{'i386': 'm'}>
+CONFIG_SND_CS4231                               policy<{'i386': 'm'}>
+CONFIG_SND_CS4236                               policy<{'i386': 'm'}>
+CONFIG_SND_ES1688                               policy<{'i386': 'm'}>
+CONFIG_SND_ES18XX                               policy<{'i386': 'm'}>
+CONFIG_SND_SC6000                               policy<{'i386': 'm'}>
+CONFIG_SND_GUSCLASSIC                           policy<{'i386': 'm'}>
+CONFIG_SND_GUSEXTREME                           policy<{'i386': 'm'}>
+CONFIG_SND_GUSMAX                               policy<{'i386': 'm'}>
+CONFIG_SND_INTERWAVE                            policy<{'i386': 'm'}>
+CONFIG_SND_INTERWAVE_STB                        policy<{'i386': 'm'}>
+CONFIG_SND_JAZZ16                               policy<{'i386': 'm'}>
+CONFIG_SND_OPL3SA2                              policy<{'i386': 'm'}>
+CONFIG_SND_OPTI92X_AD1848                       policy<{'i386': 'm'}>
+CONFIG_SND_OPTI92X_CS4231                       policy<{'i386': 'm'}>
+CONFIG_SND_OPTI93X                              policy<{'i386': 'm'}>
+CONFIG_SND_MIRO                                 policy<{'i386': 'm'}>
+CONFIG_SND_SB8                                  policy<{'i386': 'm'}>
+CONFIG_SND_SB16                                 policy<{'i386': 'm'}>
+CONFIG_SND_SBAWE                                policy<{'i386': 'm'}>
+CONFIG_SND_SB16_CSP                             policy<{'i386': 'y'}>
+CONFIG_SND_SSCAPE                               policy<{'i386': 'm'}>
+CONFIG_SND_WAVEFRONT                            policy<{'i386': 'm'}>
+CONFIG_SND_MSND_PINNACLE                        policy<{'i386': 'm'}>
+CONFIG_SND_MSND_CLASSIC                         policy<{'i386': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> MIPS sound devices
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> PCI sound devices
+CONFIG_SND_PCI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_AD1889                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ALS300                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ALS4000                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ALI5451                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ASIHPI                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_ATIIXP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ATIIXP_MODEM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AU8810                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AU8820                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AU8830                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AW2                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AZT3328                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_BT87X                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_BT87X_OVERCLOCK                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_CA0106                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_CMIPCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_OXYGEN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_CS4281                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_CS46XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_CS46XX_NEW_DSP                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_CS5530                               policy<{'i386': 'm'}>
+CONFIG_SND_CS5535AUDIO                          policy<{'i386': 'm'}>
+CONFIG_SND_CTXFI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_DARLA20                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_GINA20                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_LAYLA20                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_DARLA24                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_GINA24                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_LAYLA24                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MONA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MIA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ECHO3G                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGOIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGODJ                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGOIOX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGODJX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_EMU10K1                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_EMU10K1X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ENS1370                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ENS1371                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ES1938                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ES1968                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ES1968_INPUT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_ES1968_RADIO                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_FM801                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FM801_TEA575X_BOOL                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDSP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDSPM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ICE1712                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ICE1724                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INTEL8X0                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INTEL8X0M                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_KORG1212                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_LOLA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_LX6464ES                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MAESTRO3                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MAESTRO3_INPUT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_MIXART                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_NM256                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_PCXHR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_RIPTIDE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_RME32                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_RME96                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_RME9652                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SIS7019                              policy<{'i386': 'm'}>
+CONFIG_SND_SONICVIBES                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_TRIDENT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VIA82XX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VIA82XX_MODEM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VIRTUOSO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VX222                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_YMFPCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> PCMCIA sound devices
+CONFIG_SND_PCMCIA                               policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y'}>
+CONFIG_SND_VXPOCKET                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_SND_PDAUDIOCF                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> PowerPC sound devices
+CONFIG_SND_PPC                                  policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_POWERMAC                             policy<{'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SND_POWERMAC_AUTO_DRC                    policy<{'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_SND_PS3                                  policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_SND_PS3_DEFAULT_START_DELAY              policy<{'powerpc-powerpc64-smp': '2000'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> SPI sound devices
+CONFIG_SND_SPI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> SUPERH sound devices
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> Sparc sound devices
+
+# Menu: Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> USB sound devices
+CONFIG_SND_USB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_USB_AUDIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_UA101                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_USX2Y                            policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_CAIAQ                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_CAIAQ_INPUT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_USB_US122L                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_USB_6FIRE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_HIFACE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_BCD2000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_POD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_PODHD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_TONEPORT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_VARIAX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Sound card support >> Open Sound System (DEPRECATED)
+CONFIG_SOUND_PRIME                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Sound card support >> Open Sound System (DEPRECATED) >> OSS sound modules
+
+# Menu: Device Drivers >> Sound card support >> Open Sound System (DEPRECATED) >> OSS sound modules >> SC-6600 based audio cards (new Audio Excel DSP 16)
+
+# Menu: Device Drivers >> Sound card support >> Open Sound System (DEPRECATED) >> Support for Turtle Beach MultiSound Classic, Tahiti, Monterey
+
+# Menu: Device Drivers >> Sound card support >> Open Sound System (DEPRECATED) >> Support for Turtle Beach MultiSound Pinnacle, Fiji
+
+# Menu: Device Drivers >> Sound card support >> Open Sound System (DEPRECATED) >> Support for Turtle Beach MultiSound Pinnacle, Fiji >> MSND Pinnacle non-PnP Mode
+
+# Menu: Device Drivers >> Staging drivers
+CONFIG_STAGING                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SLICOSS                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PRISM2_USB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192U                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_R8712U                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_R8188EU                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_88EU_AP_MODE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_R8723AU                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_8723AU_AP_MODE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_8723AU_BT_COEXIST                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RTS5208                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VT6655                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VT6656                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SM750                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_XGI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EMXX                                 policy<{'armhf': 'y'}>
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_STAGING_BOARD                            policy<{'arm64': 'n', 'armhf': 'n', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_LTE_GDM724X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FIREWIRE_SERIAL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FWTTY_MAX_TOTAL_PORTS                    policy<{'amd64': '64', 'arm64': '64', 'armhf': '64', 'i386': '64', 'powerpc': '64', 'ppc64el': '64'}>
+CONFIG_FWTTY_MAX_CARD_PORTS                     policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'powerpc': '32', 'ppc64el': '32'}>
+CONFIG_MTD_SPINAND_MT29F                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SPINAND_ONDIEECC                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LNET                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LNET_MAX_PAYLOAD                         policy<{'amd64': '1048576', 'arm64': '1048576', 'armhf': '1048576', 'i386': '1048576', 'powerpc': '1048576', 'ppc64el': '1048576'}>
+CONFIG_LNET_SELFTEST                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LNET_XPRT_IB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DGNC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DGAP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GS_FPGABOOT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_SKEIN                             policy<{'amd64': 'y'}>
+CONFIG_COMMON_CLK_XLNX_CLKWZRD                  policy<{'arm64': 'n', 'armhf': 'n', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_FSL_MC_BUS                               policy<{'arm64': 'm'}>
+#
+CONFIG_STAGING                                  flag<REVIEW>
+
+# Menu: Device Drivers >> Staging drivers >> Android
+
+# Menu: Device Drivers >> Staging drivers >> Android >> Ion Memory Manager
+
+# Menu: Device Drivers >> Staging drivers >> Data acquisition support (comedi)
+CONFIG_COMEDI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB               policy<{'amd64': '2048', 'arm64': '2048', 'armhf': '2048', 'i386': '2048', 'powerpc': '2048', 'ppc64el': '2048'}>
+CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB            policy<{'amd64': '20480', 'arm64': '20480', 'armhf': '20480', 'i386': '20480', 'powerpc': '20480', 'ppc64el': '20480'}>
+CONFIG_COMEDI_8255_SA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_KCOMEDILIB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Data acquisition support (comedi) >> Comedi ISA and PC/104 drivers
+CONFIG_COMEDI_ISA_DRIVERS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_COMEDI_PCL711                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL724                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL726                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL730                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL812                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL816                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL818                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCM3724                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_DIO200_ISA                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC236_ISA                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC263_ISA                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_RTI800                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_RTI802                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAC02                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS16M1                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS08_ISA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS16                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS800                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS1800                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS6402                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2801                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2811                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2814                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2815                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2817                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT282X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DMM32AT                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_FL512                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AIO_AIO12_8                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AIO_IIRO_16                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_II_PCI20KC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_C6XDIGIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_MPC624                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADQ12B                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_AT_A2150                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_AT_AO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_ATMIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_ATMIO16D                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_LABPC_ISA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCMAD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCMDA12                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCMMIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCMUIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_MULTIQ3                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_S526                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Data acquisition support (comedi) >> Comedi PCI drivers
+CONFIG_COMEDI_PCI_DRIVERS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_8255_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_1032                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_1500                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_1516                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_1564                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_16XX                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_2032                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_2200                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_3120                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_3501                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_3XXX                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI6208                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI7X3X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI8164                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI9111                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI9118                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI1710                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI1723                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI1724                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI_DIO                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_DIO200_PCI                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC236_PCI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC263_PCI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PCI224                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PCI230                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CONTEC_PCI_DIO                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS08_PCI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT3000                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DYNA_PCI10XX                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_GSC_HPDI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_MF6X4                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ICP_MULTI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAQBOARD2000                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_JR3_PCI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_KE_COUNTER                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIDAS64                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIDAS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIDDA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIMDAS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIMDDA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ME4000                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ME_DAQ                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_6527                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_65XX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_660X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_670X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_LABPC_PCI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_PCIDIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_PCIMIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_RTD520                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_S626                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Data acquisition support (comedi) >> Comedi PCMCIA drivers
+CONFIG_COMEDI_PCMCIA_DRIVERS                    policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_COMEDI_CB_DAS16_CS                       policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_COMEDI_DAS08_CS                          policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_COMEDI_NI_DAQ_700_CS                     policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_COMEDI_NI_DAQ_DIO24_CS                   policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_COMEDI_NI_LABPC_CS                       policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_COMEDI_NI_MIO_CS                         policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_COMEDI_QUATECH_DAQP_CS                   policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Data acquisition support (comedi) >> Comedi USB drivers
+CONFIG_COMEDI_USB_DRIVERS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT9812                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_USB6501                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_USBDUX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_USBDUXFAST                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_USBDUXSIGMA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_VMK80XX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Data acquisition support (comedi) >> Comedi misc drivers
+CONFIG_COMEDI_MISC_DRIVERS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_COMEDI_BOND                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_TEST                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PARPORT                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_SERIAL2002                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_SSV_DNP                           policy<{'i386': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> GCT GDM72xx WiMAX support
+CONFIG_WIMAX_GDM72XX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WIMAX_GDM72XX_QOS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_WIMAX_GDM72XX_K_MODE                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_WIMAX_GDM72XX_WIMAX2                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_WIMAX_GDM72XX_USB_PM                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> Staging drivers >> GCT GDM72xx WiMAX support >> Select interface
+CONFIG_WIMAX_GDM72XX_USB                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_WIMAX_GDM72XX_SDIO                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers
+CONFIG_IIO_PERIODIC_RTC_TRIGGER                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SIMPLE_DUMMY                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SIMPLE_DUMMY_EVENTS                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_IIO_SIMPLE_DUMMY_BUFFER                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_IIO_SIMPLE_DUMMY_EVENTS                  note<dummy driver>
+CONFIG_IIO_SIMPLE_DUMMY_BUFFER                  note<dummy driver>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Accelerometers
+CONFIG_ADIS16201                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16203                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16204                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16209                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16220                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16240                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIS3L02DQ                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCA3000                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Active energy metering IC
+CONFIG_ADE7753                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7754                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7758                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7759                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7854                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7854_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7854_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Analog digital bi-direction converters
+CONFIG_ADT7316                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADT7316_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ADT7316_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Analog to digital converters
+CONFIG_AD7606                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7606_IFACE_PARALLEL                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7606_IFACE_SPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7780                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7816                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7192                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7280                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Capacitance to digital converters
+CONFIG_AD7150                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7152                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7746                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Digital gyroscope sensors
+CONFIG_ADIS16060                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Direct Digital Synthesis
+CONFIG_AD9832                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD9834                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Light sensors
+CONFIG_SENSORS_ISL29018                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ISL29028                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TSL2583                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TSL2x7x                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Magnetometer sensors
+CONFIG_SENSORS_HMC5843_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_HMC5843_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Network Analyzer, Impedance Converters
+CONFIG_AD5933                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> IIO staging drivers >> Resolver to digital converters
+CONFIG_AD2S90                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD2S1200                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AD2S1210                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Lustre file system client support
+CONFIG_LUSTRE_FS                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_LUSTRE_FS                                flag<REVIEW>
+
+# Menu: Device Drivers >> Staging drivers >> MOST driver
+CONFIG_MOST                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MOSTCORE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AIM_CDEV                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AIM_NETWORK                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AIM_SOUND                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AIM_V4L2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDM_DIM2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDM_I2C                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HDM_USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Media staging drivers
+CONFIG_STAGING_MEDIA                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_I2C_BCM2048                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CXD2099                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MN88472                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MN88473                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Media staging drivers >> Linux Infrared Remote Control IR receiver/transmitter drivers
+CONFIG_LIRC_STAGING                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LIRC_BT829                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIRC_IMON                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIRC_PARALLEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIRC_SASEM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIRC_SERIAL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIRC_SERIAL_TRANSMITTER                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LIRC_SIR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LIRC_ZILOG                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> NV Tegra Embedded Controller SMBus Interface
+CONFIG_MFD_NVEC                                 policy<{'armhf-generic': 'm'}>
+CONFIG_KEYBOARD_NVEC                            policy<{'armhf-generic': 'm'}>
+CONFIG_SERIO_NVEC_PS2                           policy<{'armhf-generic': 'm'}>
+CONFIG_NVEC_POWER                               policy<{'armhf-generic': 'm'}>
+CONFIG_NVEC_PAZ00                               policy<{'armhf-generic': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Parallel port LCD/Keypad Panel support
+CONFIG_PANEL                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PANEL_PARPORT                            policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+CONFIG_PANEL_PROFILE                            policy<{'amd64': '5', 'arm64': '5', 'armhf': '5', 'i386': '5', 'powerpc': '5', 'ppc64el': '5'}>
+CONFIG_PANEL_CHANGE_MESSAGE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Staging drivers >> Parallel port LCD/Keypad Panel support >> LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)
+
+# Menu: Device Drivers >> Staging drivers >> Parallel port LCD/Keypad Panel support >> LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom) >> LCD communication mode (0=parallel 8 bits, 1=serial)
+
+# Menu: Device Drivers >> Staging drivers >> RDMA staging drivers
+CONFIG_STAGING_RDMA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_AMSO1100                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_AMSO1100_DEBUG                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_INFINIBAND_EHCA                          policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_IPATH                         policy<{'amd64': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> RDMA staging drivers >> Intel OPA Gen1 support
+CONFIG_INFINIBAND_HFI1                          policy<{'amd64': 'm'}>
+CONFIG_HFI1_DEBUG_SDMA_ORDER                    policy<{'amd64': 'n'}>
+CONFIG_HFI1_VERBS_31BIT_PSN                     policy<{'amd64': 'y'}>
+CONFIG_SDMA_VERBOSITY                           policy<{'amd64': 'n'}>
+CONFIG_PRESCAN_RXQ                              policy<{'amd64': 'n'}>
+
+# Menu: Device Drivers >> Staging drivers >> Speakup console speech
+
+# Menu: Device Drivers >> Staging drivers >> Speakup console speech >> Speakup core
+CONFIG_SPEAKUP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_ACNTSA                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_ACNTPC                     policy<{'i386': 'm'}>
+CONFIG_SPEAKUP_SYNTH_APOLLO                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_AUDPTR                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_BNS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DECTLK                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DECEXT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DECPC                      policy<{'i386': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DTLK                       policy<{'i386': 'm'}>
+CONFIG_SPEAKUP_SYNTH_KEYPC                      policy<{'i386': 'm'}>
+CONFIG_SPEAKUP_SYNTH_LTLK                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_SOFT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_SPKOUT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_TXPRT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DUMMY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Support for rtllib wireless devices
+CONFIG_RTLLIB                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLLIB_CRYPTO_CCMP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLLIB_CRYPTO_TKIP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLLIB_CRYPTO_WEP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192E                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Support for small TFT LCD display modules
+CONFIG_FB_TFT                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_AGM1264K_FL                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_BD663474                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_HX8340BN                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_HX8347D                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_HX8353D                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_HX8357D                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9163                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9320                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9325                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9340                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9341                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9481                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9486                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_PCD8544                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_RA8875                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_S6D02A1                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_S6D1121                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1289                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1306                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1331                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1351                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ST7735R                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ST7789V                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_TINYLCD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_TLS8204                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_UC1611                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_UC1701                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_UPD161704                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_WATTEROTT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_FLEX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_FBTFT_DEVICE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> Unisys SPAR driver support
+CONFIG_UNISYSSPAR                               policy<{'amd64': 'y'}>
+CONFIG_UNISYS_VISORBUS                          policy<{'amd64': 'm'}>
+CONFIG_UNISYS_VISORNIC                          policy<{'amd64': 'm'}>
+CONFIG_UNISYS_VISORINPUT                        policy<{'amd64': 'm'}>
+CONFIG_UNISYS_VISORHBA                          policy<{'amd64': 'm'}>
+
+# Menu: Device Drivers >> Staging drivers >> WILC1000 support (WiFi only)
+CONFIG_WILC1000_DRIVER                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> Staging drivers >> WILC1000 support (WiFi only) >> Bus Type
+
+# Menu: Device Drivers >> Staging drivers >> WILC1000 support (WiFi only) >> Memory Allocation
+
+# Menu: Device Drivers >> TI VLYNQ
+
+# Menu: Device Drivers >> USB support
+CONFIG_USB_SUPPORT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_USB_LED_TRIG                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> ChipIdea Highspeed Dual Role Controller
+CONFIG_USB_CHIPIDEA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CHIPIDEA_UDC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CHIPIDEA_HOST                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CHIPIDEA_DEBUG                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB
+#CONFIG_USB_MUSB_OMAP2PLUS			y
+CONFIG_USB                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ANNOUNCE_NEW_DEVICES                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DEFAULT_PERSIST                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DYNAMIC_MINORS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_OTG                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_OTG_WHITELIST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_OTG_BLACKLIST_HUB                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_OTG_FSM                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_ULPI_BUS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MON                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WUSB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WUSB_CBAF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WUSB_CBAF_DEBUG                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_C67X00_HCD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_OXU210HP_HCD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISP116X_HCD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISP1362_HCD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FOTG210_HCD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MAX3421_HCD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_UHCI_HCD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_U132_HCD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SL811_HCD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SL811_HCD_ISO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SL811_CS                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_USB_R8A66597_HCD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RENESAS_USBHS_HCD                    policy<{'armhf': 'm'}>
+CONFIG_USB_WHCI_HCD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HWA_HCD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_IMX21_HCD                            policy<{'armhf-generic': 'm'}>
+CONFIG_USB_HCD_BCMA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'n', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HCD_SSB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'n', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HCD_TEST_MODE                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_RENESAS_USBHS                        policy<{'armhf': 'm'}>
+CONFIG_USB_ACM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_PRINTER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WDM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_TMC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MDC800                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MICROTEK                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISP1760                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_USS720                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EMI62                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EMI26                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ADUTUX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SEVSEG                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LEGOTOWER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LCD                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LED                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CYPRESS_CY7C63                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CYTHERM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_IDMOUSE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FTDI_ELAN                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_APPLEDISPLAY                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SISUSBVGA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SISUSBVGA_CON                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_LD                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_TRANCEVIBRATOR                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_IOWARRIOR                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_TEST                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EHSET_TEST_FIXTURE                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISIGHTFW                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_YUREX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EZUSB_FX2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HSIC_USB3503                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LINK_LAYER_TEST                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CHAOSKEY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_USB_OTG                                  note<triggers breakage on x86 LP:1047527, LP:1411295>
+CONFIG_USB_OTG_WHITELIST                        note<OTG white/blacklists are disabled>
+CONFIG_USB_OTG_BLACKLIST_HUB                    note<OTG white/blacklists are disabled>
+CONFIG_USB_OTG_FSM                              note<selects USB_OTG LP:1047527, LP:1411295>>
+CONFIG_USB_UHCI_HCD                             note<ensures USB 2.0/1.1 probe ordering> flag<REVIEW>
+CONFIG_USB_HCD_BCMA                             note<USB_{O,E}HCI_HCD_PLATFORM must be off on omap>
+CONFIG_USB_HCD_SSB                              note<USB_{O,E}HCI_HCD_PLATFORM must be off on omap>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> DesignWare USB2 DRD Core Support
+CONFIG_USB_DWC2                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DWC2_PCI                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DWC2_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_DWC2_TRACK_MISSED_SOFS               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> DesignWare USB2 DRD Core Support >> DWC2 Mode Selection
+CONFIG_USB_DWC2_HOST                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DWC2_PERIPHERAL                      policy<{'armhf': 'n'}>
+CONFIG_USB_DWC2_DUAL_ROLE                       policy<{'armhf': 'n'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> DesignWare USB3 DRD Core Support
+CONFIG_USB_DWC3                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DWC3_ULPI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DWC3_OMAP                            policy<{'armhf': 'm'}>
+CONFIG_USB_DWC3_EXYNOS                          policy<{'armhf': 'm'}>
+CONFIG_USB_DWC3_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DWC3_QCOM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> DesignWare USB3 DRD Core Support >> DWC3 Mode Selection
+CONFIG_USB_DWC3_HOST                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_DWC3_GADGET                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_DWC3_DUAL_ROLE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> EHCI HCD (USB 2.0) support
+CONFIG_USB_EHCI_HCD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EHCI_ROOT_HUB_TT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EHCI_TT_NEWSCHED                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_XPS_USB_HCD_XILINX                       policy<{'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_USB_EHCI_FSL                             policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_USB_EHCI_MXC                             policy<{'armhf-generic': 'm'}>
+CONFIG_USB_EHCI_HCD_OMAP                        policy<{'armhf': 'm'}>
+CONFIG_USB_EHCI_HCD_ORION                       policy<{'armhf': 'y'}>
+CONFIG_USB_EHCI_MSM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_EHCI_TEGRA                           policy<{'armhf-generic': 'm'}>
+CONFIG_USB_EHCI_HCD_PPC_OF                      policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EHCI_EXYNOS                          policy<{'armhf': 'y'}>
+CONFIG_USB_EHCI_HCD_PLATFORM                    policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'n', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'm'}>
+#
+CONFIG_USB_EHCI_HCD_PLATFORM                    mark<ENFORCED> note<Don't use the generic ehci/ohci code on omap, it doesn't work> flag<REVIEW>
+CONFIG_USB_EHCI_HCD                             note<ensures USB 2.0/1.1 probe ordering> flag<REVIEW>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> ISP1760 Mode Selection
+CONFIG_USB_ISP1760_HOST_ROLE                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_ISP1760_GADGET_ROLE                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_ISP1760_DUAL_ROLE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)
+CONFIG_USB_MUSB_HDRC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MUSB_TUSB6010                        policy<{'armhf': 'm'}>
+CONFIG_USB_MUSB_OMAP2PLUS                       policy<{'armhf': 'm'}>
+CONFIG_USB_MUSB_AM35X                           policy<{'armhf': 'm'}>
+CONFIG_USB_MUSB_DSPS                            policy<{'armhf': 'm'}>
+#
+CONFIG_USB_MUSB_HDRC                            note<not autoloadable on omap> flag<REVIEW>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...) >> Disable DMA (always use PIO)
+CONFIG_USB_INVENTRA_DMA                         policy<{'armhf': 'n'}>
+CONFIG_USB_TI_CPPI41_DMA                        policy<{'armhf': 'n'}>
+CONFIG_MUSB_PIO_ONLY                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...) >> MUSB Mode Selection
+CONFIG_USB_MUSB_HOST                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_MUSB_GADGET                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_MUSB_DUAL_ROLE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> OHCI HCD (USB 1.1) support
+CONFIG_USB_OHCI_HCD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_OHCI_HCD_OMAP3                       policy<{'armhf-generic': 'm'}>
+CONFIG_USB_OHCI_HCD_PPC_OF_BE                   policy<{'powerpc': 'y', 'ppc64el': 'n'}>
+CONFIG_USB_OHCI_HCD_PPC_OF_LE                   policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_OHCI_HCD_PCI                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_OHCI_EXYNOS                          policy<{'armhf': 'y'}>
+CONFIG_USB_OHCI_HCD_PLATFORM                    policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'n', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'm'}>
+#
+CONFIG_USB_OHCI_HCD                             note<ensures USB 2.0/1.1 probe ordering>
+CONFIG_USB_OHCI_HCD_PPC_OF_LE                   flag<REVIEW>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> USB DSL modem support
+CONFIG_USB_ATM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SPEEDTOUCH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CXACRU                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_UEAGLEATM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_XUSBATM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> USB Mass Storage support
+CONFIG_USB_STORAGE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_DEBUG                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_STORAGE_REALTEK                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REALTEK_AUTOPM                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_STORAGE_DATAFAB                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_FREECOM                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_ISD200                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_USBAT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_SDDR09                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_SDDR55                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_JUMPSHOT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_ALAUDA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_ONETOUCH                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_KARMA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_CYPRESS_ATACB                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_ENE_UB6250                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_UAS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> USB Serial Converter support
+CONFIG_USB_SERIAL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_GENERIC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_SIMPLE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_AIRCABLE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_ARK3116                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_BELKIN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_CH341                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_WHITEHEAT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_CP210X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_CYPRESS_M8                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_EMPEG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_FTDI_SIO                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_VISOR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_IPAQ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_IR                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_EDGEPORT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_EDGEPORT_TI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_F81232                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_GARMIN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_IPW                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_IUU                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_KEYSPAN_PDA                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_KLSI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_KOBIL_SCT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_MCT_U232                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_METRO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_MOS7720                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_MOS7715_PARPORT               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_MOS7840                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_MXUPORT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_NAVMAN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_PL2303                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_OTI6858                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_QCAUX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_QUALCOMM                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SPCP8X5                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SAFE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SAFE_PADDED                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_SERIAL_SIERRAWIRELESS                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SYMBOL                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_TI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_CYBERJACK                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_XIRCOM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_OPTION                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_OMNINET                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_OPTICON                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_XSENS_MT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_WISHBONE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SSU100                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_QT2                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_DEBUG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_USB_SERIAL_DEBUG                         note<not actually debug>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> USB Serial Converter support >> USB Keyspan USA-xxx Serial Driver
+CONFIG_USB_SERIAL_KEYSPAN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_KEYSPAN_MPR                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA28                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA28X                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA19                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA18X                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA19W                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA49W                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> USB/IP support
+CONFIG_USBIP_CORE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USBIP_VHCI_HCD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USBIP_HOST                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USBIP_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Device Drivers >> USB support >> Support for Host-side USB >> xHCI HCD (USB 3.0) support
+CONFIG_USB_XHCI_HCD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_XHCI_PLATFORM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_XHCI_MVEBU                           policy<{'armhf': 'm'}>
+CONFIG_USB_XHCI_RCAR                            policy<{'armhf': 'm'}>
+#
+CONFIG_USB_XHCI_HCD                             note<ensures USB 2.0/1.1 probe ordering> flag<REVIEW>
+
+# Menu: Device Drivers >> USB support >> USB Gadget Support
+CONFIG_USB_GADGET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GADGET_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_GADGET_DEBUG_FILES                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_GADGET_DEBUG_FS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_GADGET_VBUS_DRAW                     policy<{'amd64': '2', 'arm64': '2', 'armhf': '2', 'i386': '2', 'powerpc': '2', 'ppc64el': '2'}>
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS           policy<{'amd64': '2', 'arm64': '2', 'armhf': '2', 'i386': '2', 'powerpc': '2', 'ppc64el': '2'}>
+
+# Menu: Device Drivers >> USB support >> USB Gadget Support >> USB Gadget Drivers
+CONFIG_USB_ZERO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_AUDIO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GADGET_UAC1                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ETH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ETH_RNDIS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ETH_EEM                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_G_NCM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GADGETFS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MASS_STORAGE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GADGET_TARGET                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_SERIAL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MIDI_GADGET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_PRINTER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CDC_COMPOSITE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_NOKIA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_ACM_MS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_MULTI                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'm', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_G_MULTI_RNDIS                        policy<{'armhf': 'y'}>
+CONFIG_USB_G_MULTI_CDC                          policy<{'armhf': 'y'}>
+CONFIG_USB_G_HID                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_DBGP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_WEBCAM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> USB support >> USB Gadget Support >> USB Gadget Drivers >> EHCI Debug Device mode
+CONFIG_USB_G_DBGP_PRINTK                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_G_DBGP_SERIAL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> USB Gadget Support >> USB Gadget Drivers >> Function Filesystem
+CONFIG_USB_FUNCTIONFS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FUNCTIONFS_ETH                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_FUNCTIONFS_RNDIS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_FUNCTIONFS_GENERIC                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> USB Gadget Support >> USB Gadget Drivers >> USB functions configurable through configfs
+CONFIG_USB_CONFIGFS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CONFIGFS_SERIAL                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_ACM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_OBEX                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_NCM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_ECM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_ECM_SUBSET                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_RNDIS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_EEM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_PHONET                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_MASS_STORAGE                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_LB_SS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_FS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_UAC1                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_UAC2                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_MIDI                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_HID                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_UVC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_PRINTER                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Device Drivers >> USB support >> USB Gadget Support >> USB Peripheral Controller
+CONFIG_USB_FSL_USB2                             policy<{'armhf-generic': 'm', 'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_USB_FUSB300                              policy<{'armhf-generic': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_USB_FOTG210_UDC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GR_UDC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_R8A66597                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RENESAS_USBHS_UDC                    policy<{'armhf': 'm'}>
+CONFIG_USB_PXA27X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MV_UDC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MV_U3D                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_M66592                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_BDC_UDC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_BDC_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_AMD5536UDC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FSL_QE                               policy<{'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_USB_NET2272                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET2272_DMA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_NET2280                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GOKU                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EG20T                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GADGET_XILINX                        policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DUMMY_HCD                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_USB_M66592                               note<gadget device>
+CONFIG_USB_DUMMY_HCD                            flag<TESTING>
+
+# Menu: Device Drivers >> USB support >> USB Physical Layer drivers
+CONFIG_NOP_USB_XCEIV                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_AM335X_PHY_USB                           policy<{'armhf': 'm'}>
+CONFIG_TWL6030_USB                              policy<{'armhf': 'm'}>
+CONFIG_USB_GPIO_VBUS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TAHVO_USB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TAHVO_USB_HOST_BY_DEFAULT                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ISP1301                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MSM_OTG                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_QCOM_8X16_PHY                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_MXS_PHY                              policy<{'armhf-generic': 'y'}>
+CONFIG_USB_RCAR_PHY                             policy<{'armhf': 'm'}>
+CONFIG_USB_ULPI                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+#
+CONFIG_NOP_USB_XCEIV                            note<boot essential on omap/highbank>
+
+# Menu: Device Drivers >> Ultra Wideband devices
+CONFIG_UWB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UWB_HWA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UWB_WHCI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UWB_I1480U                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Userspace I/O drivers
+CONFIG_UIO                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_CIF                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_PDRV_GENIRQ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_DMEM_GENIRQ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_AEC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_SERCOS3                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_PCI_GENERIC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_NETX                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_FSL_ELBC_GPCM                        policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_FSL_ELBC_GPCM_NETX5152               policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_UIO_PRUSS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UIO_MF624                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> VFIO Non-Privileged userspace driver framework
+CONFIG_VFIO                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_VFIO_PCI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_VFIO_PCI_VGA                             policy<{'amd64': 'y', 'i386': 'y'}>
+#
+CONFIG_VFIO					mark<ENFORCED>note<LP#1636733>
+CONFIG_VFIO_PCI					mark<ENFORCED>note<LP#1636733>
+
+# Menu: Device Drivers >> VFIO Non-Privileged userspace driver framework >> VFIO support for platform devices
+CONFIG_VFIO_PLATFORM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VFIO_AMBA                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VFIO_PLATFORM_CALXEDAXGMAC_RESET         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VFIO_PLATFORM_AMDXGBE_RESET              policy<{'arm64': 'm', 'armhf': 'm'}>
+
+# Menu: Device Drivers >> VME bridge support
+CONFIG_VME_BUS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_VME_CA91CX42                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_VME_TSI148                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VMIVME_7805                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VME_USER                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VME_PIO2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> Virtio drivers
+CONFIG_VIRTIO_PCI                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_PCI_LEGACY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_BALLOON                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_INPUT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIRTIO_MMIO                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_VIRTIO_MMIO				note<LP#1557689 CONFIG_VIRTIO_MMIO=n for s390x>
+CONFIG_VIRTIO_PCI                               flag<REVIEW>
+
+# Menu: Device Drivers >> Virtualization drivers
+CONFIG_VIRT_DRIVERS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FSL_HV_MANAGER                           policy<{'powerpc-powerpc64-emb': 'm', 'powerpc-powerpc-e500mc': 'm'}>
+
+# Menu: Device Drivers >> Voltage and Current Regulator Support
+CONFIG_REGULATOR                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_REGULATOR_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_REGULATOR_FIXED_VOLTAGE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_VIRTUAL_CONSUMER               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_USERSPACE_CONSUMER             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_88PM800                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_88PM8607                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ACT8865                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AD5398                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ANATOP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AAT2870                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AB3100                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ARIZONA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AS3711                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AS3722                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AXP20X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_BCM590XX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA903X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9052                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9055                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9062                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9063                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9210                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9211                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_FAN53555                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_GPIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_HI6421                         policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ISL9305                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ISL6271A                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP3971                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP3972                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP872X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP8755                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP8788                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LTC3589                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX14577                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX1586                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8649                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8660                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8907                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8925                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8952                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8973                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8997                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8998                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX77686                       policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX77693                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX77802                       policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MC13783                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MC13892                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MT6311                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MT6397                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PALMAS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PBIAS                          policy<{'armhf': 'm'}>
+CONFIG_REGULATOR_PCAP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PCF50633                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PFUZE100                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PWM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_QCOM_RPM                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_QCOM_SMD_RPM                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_QCOM_SPMI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_RC5T583                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_RK808                          policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_RN5T618                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_RT5033                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_S2MPA01                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_S2MPS11                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_S5M8767                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_SKY81452                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TI_ABB                         policy<{'armhf': 'y'}>
+CONFIG_REGULATOR_TPS51632                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS6105X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS62360                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65023                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS6507X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65090                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65217                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_REGULATOR_TPS65218                       policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS6524X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS6586X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65910                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65912                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS80031                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TWL4030                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_VEXPRESS                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_WM831X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_WM8350                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_WM8400                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_WM8994                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+#
+CONFIG_REGULATOR_FIXED_VOLTAGE                  note<boot essential on arm>
+CONFIG_REGULATOR_TWL4030                        mark<ENFORCED> note<boot requisite for omap4>
+
+# Menu: Device Drivers >> Watchdog Timer Support
+CONFIG_WATCHDOG                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WATCHDOG_CORE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WATCHDOG_NOWAYOUT                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SOFT_WATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DA9052_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9055_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9063_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9062_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_WATCHDOG                            policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MENF21BMC_WATCHDOG                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WM831X_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WM8350_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_XILINX_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ARM_SP805_WATCHDOG                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CADENCE_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_S3C2410_WATCHDOG                         policy<{'armhf': 'm'}>
+CONFIG_DW_WATCHDOG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_OMAP_WATCHDOG                            policy<{'armhf': 'm'}>
+CONFIG_ORION_WATCHDOG                           policy<{'armhf': 'm'}>
+CONFIG_RN5T618_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TWL4030_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX63XX_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IMX2_WDT                                 policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_RETU_WATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TEGRA_WATCHDOG                           policy<{'armhf-generic': 'm'}>
+CONFIG_QCOM_WDT                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MESON_WATCHDOG                           policy<{'armhf': 'm'}>
+CONFIG_MEDIATEK_WATCHDOG                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ACQUIRE_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ADVANTECH_WDT                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ALIM1535_WDT                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ALIM7101_WDT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_F71808E_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SP5100_TCO                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SBC_FITPC2_WATCHDOG                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EUROTECH_WDT                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IB700_WDT                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IBMASR                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_WAFER_WDT                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I6300ESB_WDT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IE6XX_WDT                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SCU_WATCHDOG                       policy<{'i386': 'y'}>
+CONFIG_INTEL_MID_WATCHDOG                       policy<{'i386': 'm'}>
+CONFIG_ITCO_WDT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ITCO_VENDOR_SUPPORT                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IT8712F_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IT87_WDT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HP_WATCHDOG                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_KEMPLD_WDT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_HPWDT_NMI_DECODING                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SC1200_WDT                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCx200_WDT                               policy<{'i386': 'm'}>
+CONFIG_PC87413_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NV_TCO                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_60XX_WDT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SBC8360_WDT                              policy<{'i386': 'm'}>
+CONFIG_SBC7240_WDT                              policy<{'i386': 'm'}>
+CONFIG_CPU5_WDT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SMSC_SCH311X_WDT                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SMSC37B787_WDT                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIA_WDT                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_W83627HF_WDT                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_W83877F_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_W83977F_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MACHZ_WDT                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SBC_EPX_C3_WATCHDOG                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BCM7038_WDT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BOOKE_WDT                                policy<{'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT                policy<{'powerpc-powerpc-e500mc': '38', 'powerpc-powerpc64-emb': '38'}>
+CONFIG_MEN_A21_WDT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WATCHDOG_RTAS                            policy<{'powerpc-powerpc-smp': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_DIAG288_WATCHDOG                         policy<{'s390x': 'm'}>
+CONFIG_XEN_WDT                                  policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_SPECTRE_BHI_AUTO                         policy<{'amd64': 'n'}>
+CONFIG_SPECTRE_BHI_OFF                          policy<{'amd64': 'n'}>
+CONFIG_SPECTRE_BHI_ON                           policy<{'amd64': 'y'}>
+CONFIG_PCWATCHDOG                               policy<{'i386': 'm'}>
+CONFIG_MIXCOMWD                                 policy<{'i386': 'm'}>
+CONFIG_WDT                                      policy<{'i386': 'm'}>
+CONFIG_PCIPCWATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_WDTPCI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_USBPCWATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Device Drivers >> X86 Platform Specific Device Drivers
+CONFIG_X86_PLATFORM_DEVICES                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACER_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACERHDF                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ALIENWARE_WMI                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ASUS_LAPTOP                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_LAPTOP                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_WMI_AIO                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_SMO8800                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_RBTN                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FUJITSU_LAPTOP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FUJITSU_LAPTOP_DEBUG                     policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_FUJITSU_TABLET                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_AMILO_RFKILL                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TC1100_WMI                               policy<{'i386': 'm'}>
+CONFIG_HP_ACCEL                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HP_WIRELESS                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HP_WMI                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MSI_LAPTOP                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PANASONIC_LAPTOP                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMPAL_LAPTOP                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SONY_LAPTOP                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SONYPI_COMPAT                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IDEAPAD_LAPTOP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_HDAPS                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MENLOW                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EEEPC_LAPTOP                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ASUS_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ASUS_NB_WMI                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EEEPC_WMI                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TOPSTAR_LAPTOP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TOSHIBA_BT_RFKILL                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TOSHIBA_HAPS                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_CMPC                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_HID_EVENT                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_VBTN                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MFLD_THERMAL                       policy<{'i386': 'm'}>
+CONFIG_INTEL_IPS                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IBM_RTL                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SAMSUNG_LAPTOP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_OAKTRAIL                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SAMSUNG_Q10                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_APPLE_GMUX                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_RST                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SMARTCONNECT                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PVPANIC                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_PMC_IPC                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SURFACE_PRO3_BUTTON                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_PUNIT_IPC                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_TELEMETRY                          policy<{'amd64': 'm'}>
+
+# Menu: Device Drivers >> X86 Platform Specific Device Drivers >> Intel SCU IPC Support
+CONFIG_INTEL_SCU_IPC                            policy<{'i386': 'y'}>
+CONFIG_INTEL_SCU_IPC_UTIL                       policy<{'i386': 'm'}>
+CONFIG_GPIO_INTEL_PMIC                          policy<{'i386': 'y'}>
+CONFIG_INTEL_MID_POWER_BUTTON                   policy<{'i386': 'm'}>
+
+# Menu: Device Drivers >> X86 Platform Specific Device Drivers >> ThinkPad ACPI Laptop Extras
+CONFIG_THINKPAD_ACPI                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_THINKPAD_ACPI_ALSA_SUPPORT               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_THINKPAD_ACPI_DEBUGFACILITIES            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_THINKPAD_ACPI_DEBUG                      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_THINKPAD_ACPI_UNSAFE_LEDS                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_THINKPAD_ACPI_VIDEO                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_THINKPAD_ACPI_HOTKEY_POLL                policy<{'amd64': 'y', 'i386': 'y'}>
+
+# Menu: Device Drivers >> X86 Platform Specific Device Drivers >> WMI
+CONFIG_ACPI_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MSI_WMI                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_TOSHIBA                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TOSHIBA_WMI                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MXM_WMI                                  policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Device Drivers >> Xen driver support
+CONFIG_XEN_DEV_EVTCHN                           policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_BACKEND                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XENFS                                    policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_COMPAT_XENFS                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_SYS_HYPERVISOR                       policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_GNTDEV                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_GRANT_DEV_ALLOC                      policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_PCIDEV_BACKEND                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_XEN_SCSI_BACKEND                         policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_ACPI_PROCESSOR                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_MCE_LOG                              policy<{'amd64': 'y'}>
+CONFIG_XEN_SYMS                                 policy<{'amd64': 'y', 'i386': 'y'}>
+#
+CONFIG_XEN_ACPI_PROCESSOR                       mark<ENFORCED> note<boot essential on XEN host>
+
+# Menu: Device Drivers >> Xen driver support >> Xen memory balloon driver
+CONFIG_XEN_BALLOON                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_SELFBALLOONING                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT         policy<{'amd64': '512', 'i386': '4'}>
+CONFIG_XEN_SCRUB_PAGES                          policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+
+# Menu: Dump support
+#
+
+# Menu: Dump support >> Architecture: s390
+
+# Menu: Enable loadable module support
+CONFIG_MODULES                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_FORCE_LOAD                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_UNLOAD                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_FORCE_UNLOAD                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODVERSIONS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_SRCVERSION_ALL                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_COMPRESS                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Enable loadable module support >> Compression algorithm
+
+# Menu: Enable loadable module support >> Module signature verification
+CONFIG_MODULE_SIG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_SIG_FORCE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_ALL                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_SIG_UEFI                          policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+
+# Menu: Enable loadable module support >> Module signature verification >> Which hash algorithm should modules be signed with?
+CONFIG_MODULE_SIG_SHA1                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_SHA224                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_SHA256                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_SHA384                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_SHA512                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Enable the block layer
+CONFIG_BLOCK                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LBDAF                                    policy<{'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_BLK_DEV_BSG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_BSGLIB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_INTEGRITY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_THROTTLING                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_CMDLINE_PARSER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_BLK_DEV_THROTTLING                       note<CGROUP disk consumption control>
+
+# Menu: Enable the block layer >> IO Schedulers
+CONFIG_IOSCHED_DEADLINE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IOSCHED_CFQ                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CFQ_GROUP_IOSCHED                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Enable the block layer >> IO Schedulers >> Default I/O scheduler
+CONFIG_DEFAULT_DEADLINE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEFAULT_CFQ                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_NOOP                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Enable the block layer >> Partition Types
+
+# Menu: Enable the block layer >> Partition Types >> Advanced partition selection
+CONFIG_PARTITION_ADVANCED                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AIX_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_OSF_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_AMIGA_PARTITION                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ATARI_PARTITION                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_IBM_PARTITION                            policy<{'s390x': 'y'}>
+CONFIG_MAC_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_LDM_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_LDM_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SGI_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ULTRIX_PARTITION                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SUN_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_KARMA_PARTITION                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_EFI_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSV68_PARTITION                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_CMDLINE_PARTITION                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+#
+CONFIG_PARTITION_ADVANCED                       flag<REVIEW>
+
+# Menu: Enable the block layer >> Partition Types >> Advanced partition selection >> Acorn partition support
+CONFIG_ACORN_PARTITION                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Enable the block layer >> Partition Types >> Advanced partition selection >> PC BIOS (MSDOS partition tables) support
+CONFIG_MSDOS_PARTITION                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BSD_DISKLABEL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MINIX_SUBPARTITION                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SOLARIS_X86_PARTITION                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_UNIXWARE_DISKLABEL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+
+# Menu: Endianness selection
+CONFIG_CPU_BIG_ENDIAN                           policy<{'arm64': 'n', 'armhf': 'n', 'powerpc': 'y', 'ppc64el': 'n'}>
+
+# Menu: Endianness selection >> Architecture: powerpc
+CONFIG_CPU_LITTLE_ENDIAN                        policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'y'}>
+
+# Menu: Executable file formats / Emulations
+CONFIG_BINFMT_ELF                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BINFMT_SCRIPT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BINFMT_AOUT                              policy<{'i386': 'n'}>
+CONFIG_BINFMT_MISC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_COREDUMP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECCOMP                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_COMPAT                                   policy<{'amd64': 'y', 'arm64': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_BINFMT_SCRIPT                            mark<ENFORCED> note<required if 'init' is a shell script such as in initramfs-tools>
+CONFIG_BINFMT_AOUT                              mark<ENFORCED> note<LP:#1818552>
+CONFIG_SECCOMP                                  mark<ENFORCED>
+
+# Menu: Executable file formats / Emulations >> Architecture: arm
+
+# Menu: Executable file formats / Emulations >> Architecture: arm64
+
+# Menu: Executable file formats / Emulations >> Architecture: s390
+CONFIG_KERNEL_NOBP                              policy<{'s390x': 'y'}>
+CONFIG_EXPOLINE                                 policy<{'s390x': 'y'}>
+
+# Menu: Executable file formats / Emulations >> Architecture: x86
+CONFIG_IA32_EMULATION                           policy<{'amd64': 'y'}>
+CONFIG_IA32_AOUT                                policy<{'amd64': 'n'}>
+CONFIG_X86_X32                                  policy<{'amd64': 'y'}>
+#
+CONFIG_IA32_AOUT                                mark<ENFORCED> note<LP:#1818552>
+
+# Menu: Executable file formats / Emulations >> Expoline default >> Architecture: s390
+CONFIG_EXPOLINE_OFF                             policy<{'s390x': 'n'}>
+CONFIG_EXPOLINE_AUTO                            policy<{'s390x': 'y'}>
+CONFIG_EXPOLINE_FULL                            policy<{'s390x': 'n'}>
+
+# Menu: File systems
+CONFIG_EXT2_FS                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_EXT3_FS                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_JBD2_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_GFS2_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GFS2_FS_LOCKING_DLM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NILFS2_FS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FS_DAX                                   policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FILE_LOCKING                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DNOTIFY                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INOTIFY_USER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FANOTIFY                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_QUOTA_NETLINK_INTERFACE                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUTOFS4_FS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'y'}>
+CONFIG_FUSE_FS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CUSE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OVERLAY_FS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OVERLAY_FS_V1                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_EXT2_FS                                  note<ext4 handling via EXT4_USE_FOR_EXT23>
+CONFIG_EXT3_FS                                  note<ext4 handling via EXT4_USE_FOR_EXT23>
+CONFIG_FUSE_FS                                  note<not autoloadable> flag<REVIEW>
+
+# Menu: File systems >> Btrfs filesystem support
+CONFIG_BTRFS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BTRFS_FS_POSIX_ACL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BTRFS_FS_CHECK_INTEGRITY                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BTRFS_FS_RUN_SANITY_TESTS                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BTRFS_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BTRFS_ASSERT                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> CD-ROM/DVD Filesystems
+CONFIG_ISO9660_FS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_JOLIET                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZISOFS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UDF_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: File systems >> Caches
+CONFIG_CACHEFILES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CACHEFILES_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CACHEFILES_HISTOGRAM                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> Caches >> General filesystem local caching manager
+CONFIG_FSCACHE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FSCACHE_STATS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FSCACHE_HISTOGRAM                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FSCACHE_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FSCACHE_OBJECT_LIST                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> DOS/FAT/NT Filesystems
+CONFIG_MSDOS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VFAT_FS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FAT_DEFAULT_CODEPAGE                     policy<{'amd64': '437', 'arm64': '437', 'armhf': '437', 'i386': '437', 'powerpc': '437', 'ppc64el': '437', 's390x': '437'}>
+CONFIG_FAT_DEFAULT_IOCHARSET                    policy<{'amd64': '"iso8859-1"', 'arm64': '"iso8859-1"', 'armhf': '"iso8859-1"', 'i386': '"iso8859-1"', 'powerpc': '"iso8859-1"', 'ppc64el': '"iso8859-1"', 's390x': '"iso8859-1"'}>
+CONFIG_NTFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NTFS_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NTFS_RW                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+#
+CONFIG_VFAT_FS                                  mark<ENFORCED> note<needed on arm to ensure we can write the kernel when replacing>
+
+# Menu: File systems >> Distributed Lock Manager (DLM)
+CONFIG_DLM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DLM_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> F2FS filesystem support
+CONFIG_F2FS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_F2FS_STAT_FS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_F2FS_CHECK_FS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_F2FS_IO_TRACE                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: File systems >> F2FS filesystem support >> F2FS extended attributes
+CONFIG_F2FS_FS_XATTR                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_F2FS_FS_POSIX_ACL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_F2FS_FS_SECURITY                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_F2FS_FS_ENCRYPTION                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: File systems >> JFS filesystem support
+CONFIG_JFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_JFS_POSIX_ACL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFS_SECURITY                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_JFS_STATISTICS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: File systems >> Miscellaneous filesystems
+CONFIG_MISC_FILESYSTEMS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ADFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ADFS_FS_RW                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_AFFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ECRYPT_FS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ECRYPT_FS_MESSAGING                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HFSPLUS_FS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HFSPLUS_FS_POSIX_ACL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BEFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BEFS_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_BFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UBIFS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_UBIFS_FS_ADVANCED_COMPR                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_UBIFS_FS_LZO                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_UBIFS_FS_ZLIB                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_UBIFS_ATIME_SUPPORT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LOGFS                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRAMFS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_VXFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MITIGATION_VMSCAPE                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MINIX_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_OMFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HPFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_QNX4FS_FS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_QNX6FS_FS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_QNX6FS_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ROMFS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SYSV_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UFS_FS_WRITE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_UFS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_EXOFS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EXOFS_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_ECRYPT_FS                                mark<ENFORCED> note<not autoloadable>
+CONFIG_LOGFS                                    note<highly discouraged for use>
+
+# Menu: File systems >> Miscellaneous filesystems >> Aufs (Advanced multi layered unification filesystem) support
+CONFIG_AUFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AUFS_HNOTIFY                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_EXPORT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUFS_XATTR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUFS_FHSM                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_RDU                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_SHWH                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BR_RAMFS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BR_FUSE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BR_HFSPLUS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_AUFS_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_AUFS_EXPORT                              note<LP:1121699>
+
+# Menu: File systems >> Miscellaneous filesystems >> Aufs (Advanced multi layered unification filesystem) support >> Maximum number of branches
+CONFIG_AUFS_BRANCH_MAX_127                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUFS_BRANCH_MAX_511                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BRANCH_MAX_1023                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BRANCH_MAX_32767                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> Miscellaneous filesystems >> Aufs (Advanced multi layered unification filesystem) support >> method
+
+# Menu: File systems >> Miscellaneous filesystems >> Journalling Flash File System v2 (JFFS2) support
+CONFIG_JFFS2_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_JFFS2_FS_DEBUG                           policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+CONFIG_JFFS2_FS_WRITEBUFFER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_FS_WBUF_VERIFY                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_SUMMARY                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_FS_XATTR                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_FS_POSIX_ACL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_FS_SECURITY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: File systems >> Miscellaneous filesystems >> Journalling Flash File System v2 (JFFS2) support >> Advanced compression options for JFFS2
+CONFIG_JFFS2_COMPRESSION_OPTIONS                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_ZLIB                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_LZO                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_RTIME                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_RUBIN                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: File systems >> Miscellaneous filesystems >> Journalling Flash File System v2 (JFFS2) support >> Advanced compression options for JFFS2 >> JFFS2 default compression mode
+CONFIG_JFFS2_CMODE_NONE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_CMODE_PRIORITY                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_CMODE_SIZE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_CMODE_FAVOURLZO                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: File systems >> Miscellaneous filesystems >> Persistent store support
+CONFIG_PSTORE                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PSTORE_CONSOLE                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_PMSG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_FTRACE                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_RAM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: File systems >> Miscellaneous filesystems >> RomFS backing stores
+CONFIG_ROMFS_BACKED_BY_BLOCK                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ROMFS_BACKED_BY_MTD                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ROMFS_BACKED_BY_BOTH                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: File systems >> Miscellaneous filesystems >> SquashFS 4.0 - Squashed file system support
+CONFIG_SQUASHFS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_XATTR                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_ZLIB                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_LZ4                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_LZO                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_XZ                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_4K_DEVBLK_SIZE                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_EMBEDDED                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE             policy<{'amd64': '3', 'arm64': '3', 'armhf': '3', 'i386': '3', 'powerpc': '3', 'ppc64el': '3', 's390x': '3'}>
+#
+CONFIG_SQUASHFS_4K_DEVBLK_SIZE                  note<non-default block size>
+CONFIG_SQUASHFS					mark<ENFORCED> note<LP#1593134>
+
+# Menu: File systems >> Miscellaneous filesystems >> SquashFS 4.0 - Squashed file system support >> Decompressor parallelisation options
+CONFIG_SQUASHFS_DECOMP_SINGLE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_DECOMP_MULTI                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> Miscellaneous filesystems >> SquashFS 4.0 - Squashed file system support >> File decompression options
+CONFIG_SQUASHFS_FILE_CACHE                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_FILE_DIRECT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: File systems >> Native language support
+CONFIG_NLS                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NLS_DEFAULT                              policy<{'amd64': '"utf8"', 'arm64': '"utf8"', 'armhf': '"utf8"', 'i386': '"utf8"', 'powerpc': '"utf8"', 'ppc64el': '"utf8"', 's390x': '"utf8"'}>
+CONFIG_NLS_CODEPAGE_437                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NLS_CODEPAGE_737                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_775                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_850                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_852                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_855                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_857                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_860                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_861                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_862                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_863                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_864                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_865                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_866                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_869                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_936                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_950                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_932                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_949                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_874                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_8                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_1250                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_1251                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ASCII                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_1                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NLS_ISO8859_2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_3                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_4                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_5                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_6                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_7                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_9                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_13                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_14                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_15                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_KOI8_R                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_KOI8_U                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_ROMAN                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_CELTIC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_CENTEURO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_CROATIAN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_CYRILLIC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_GAELIC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_GREEK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_ICELAND                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_INUIT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_ROMANIAN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_TURKISH                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_UTF8                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+#
+CONFIG_NLS                                      note<dependancy of boot essential>
+
+# Menu: File systems >> Network File Systems
+CONFIG_NETWORK_FILESYSTEMS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFSD_V3                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_V3_ACL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RPCSEC_GSS_KRB5                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SUNRPC_DEBUG                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SUNRPC_XPRT_RDMA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CEPH_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CEPH_FSCACHE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CEPH_FS_POSIX_ACL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CODA_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AFS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AFS_FSCACHE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: File systems >> Network File Systems >> CIFS support (advanced network filesystem, SMBFS successor)
+CONFIG_CIFS                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CIFS_STATS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_STATS2                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CIFS_WEAK_PW_HASH                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_UPCALL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_XATTR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_POSIX                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_ACL                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_DEBUG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_DEBUG2                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CIFS_DFS_UPCALL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_SMB2                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_SMB311                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_FSCACHE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: File systems >> Network File Systems >> NCP file system support (to mount NetWare volumes)
+CONFIG_NCP_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NCPFS_PACKET_SIGNING                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NCPFS_IOCTL_LOCKING                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NCPFS_STRONG                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NCPFS_NFS_NS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NCPFS_OS2_NS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NCPFS_SMALLDOS                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_NCPFS_NLS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NCPFS_EXTRAS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: File systems >> Network File Systems >> NFS client support
+CONFIG_NFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_V2                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_V3                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_V3_ACL                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_V4                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_SWAP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_FSCACHE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_USE_LEGACY_DNS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> Network File Systems >> NFS client support >> NFS client support for NFSv4.1
+CONFIG_NFS_V4_1                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_V4_2                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN        policy<{'amd64': '"kernel.org"', 'arm64': '"kernel.org"', 'armhf': '"kernel.org"', 'i386': '"kernel.org"', 'powerpc': '"kernel.org"', 'ppc64el': '"kernel.org"', 's390x': '"kernel.org"'}>
+CONFIG_NFS_V4_1_MIGRATION                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: File systems >> Network File Systems >> NFS server support for NFS version 4
+CONFIG_NFSD_V4                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_PNFS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_V4_SECURITY_LABEL                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_FAULT_INJECTION                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> Network File Systems >> Plan 9 Resource Sharing Support (9P2000)
+CONFIG_9P_FS                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_9P_FSCACHE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_9P_FS_POSIX_ACL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_9P_FS_SECURITY                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: File systems >> OCFS2 file system support
+CONFIG_OCFS2_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OCFS2_FS_O2CB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OCFS2_FS_USERSPACE_CLUSTER               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OCFS2_FS_STATS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OCFS2_DEBUG_MASKLOG                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OCFS2_DEBUG_FS                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> Pseudo filesystems
+CONFIG_PROC_CHILDREN                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSFS                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TMPFS                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TMPFS_POSIX_ACL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TMPFS_XATTR                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HUGETLBFS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CONFIGFS_FS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'y'}>
+CONFIG_EFIVAR_FS                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+#
+CONFIG_CONFIGFS_FS                              flag<REVIEW>
+CONFIG_EFIVAR_FS                                note<needed for variable EFI update>
+CONFIG_TMPFS_POSIX_ACL                          mark<ENFORCED> note<some /dev nodes require POSIX ACLs, like /dev/dsp>
+
+# Menu: File systems >> Pseudo filesystems >> /proc file system support
+CONFIG_PROC_FS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_KCORE                               policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_VMCORE                              policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_SYSCTL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_PAGE_MONITOR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: File systems >> Quota support
+CONFIG_QUOTA                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PRINT_QUOTA_WARNING                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_QUOTA_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_QFMT_V1                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_QFMT_V2                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: File systems >> Reiserfs support
+CONFIG_REISERFS_FS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_REISERFS_CHECK                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_REISERFS_PROC_INFO                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_REISERFS_FS_XATTR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_REISERFS_FS_POSIX_ACL                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_REISERFS_FS_SECURITY                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: File systems >> The Extended 4 (ext4) filesystem
+CONFIG_EXT4_FS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXT4_USE_FOR_EXT2                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXT4_FS_POSIX_ACL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXT4_FS_SECURITY                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXT4_ENCRYPTION                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_EXT4_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: File systems >> XFS filesystem support
+CONFIG_XFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XFS_QUOTA                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFS_POSIX_ACL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFS_RT                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFS_WARN                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_XFS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Firmware Drivers
+CONFIG_ARM_SCPI_PROTOCOL                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_EDD                                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EDD_OFF                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_FIRMWARE_MEMMAP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_DELL_RBU                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DCDBAS                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DMIID                                    policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_DMI_SYSFS                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ISCSI_IBFT_FIND                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ISCSI_IBFT                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_GOOGLE_FIRMWARE                          policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: Firmware Drivers >> EFI (Extensible Firmware Interface) Support
+CONFIG_EFI_VARS                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_EFI_VARS_PSTORE                          policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE          policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_EFI_RUNTIME_MAP                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EFI_FAKE_MEMMAP                          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_EFI_TEST                                 policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+#
+CONFIG_EFI_VARS                                 mark<ENFORCED> note<EFI boot requirement (d-i) LP:#837332>
+
+# Menu: Firmware Drivers >> Google Firmware Drivers
+
+# Menu: Floating point emulation >> Architecture: arm
+CONFIG_VFP                                      policy<{'armhf': 'y'}>
+CONFIG_NEON                                     policy<{'armhf': 'y'}>
+CONFIG_KERNEL_MODE_NEON                         policy<{'arm64': 'y', 'armhf': 'y'}>
+
+# Menu: General setup
+CONFIG_CROSS_COMPILE                            policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'powerpc': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_COMPILE_TEST                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOCALVERSION                             policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'powerpc': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_LOCALVERSION_AUTO                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_HOSTNAME                         policy<{'amd64': '"(none)"', 'arm64': '"(none)"', 'armhf': '"(none)"', 'i386': '"(none)"', 'powerpc': '"(none)"', 'ppc64el': '"(none)"', 's390x': '"(none)"'}>
+CONFIG_VERSION_SIGNATURE                        policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'powerpc': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_SWAP                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSVIPC                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_POSIX_MQUEUE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CROSS_MEMORY_ATTACH                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FHANDLE                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_USELIB                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUDIT                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUDITSYSCALL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IKCONFIG                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOG_BUF_SHIFT                            policy<{'amd64': '18', 'arm64': '18', 'armhf': '17', 'i386': '17', 'powerpc': '18', 'ppc64el': '18', 's390x': '18'}>
+CONFIG_LOG_CPU_MAX_BUF_SHIFT                    policy<{'amd64': '12', 'arm64': '12', 'armhf': '12', 'i386': '12', 'powerpc': '12', 'ppc64el': '12', 's390x': '12'}>
+CONFIG_NUMA_BALANCING                           policy<{'amd64': 'y', 'arm64': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED           policy<{'amd64': 'y', 'arm64': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_CHECKPOINT_RESTORE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_AUTOGROUP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSFS_DEPRECATED                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RELAY                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPF_SYSCALL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPF_JIT_ALWAYS_ON                        policy<{'amd64': 'y', 'arm64': 'n', 's390x': 'y'}>
+CONFIG_BPF_UNPRIV_DEFAULT_OFF                   policy<{'amd64': 'y', 'arm64': 'y', 's390x': 'y'}>
+CONFIG_USERFAULTFD                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EMBEDDED                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_COMPAT_BRK                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SLUB_CPU_PARTIAL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEM_BLACKLIST_KEYRING                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROFILING                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OPROFILE                                 policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPROFILE_EVENT_MULTIPLEX                 policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_KPROBES                                  policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_JUMP_LABEL                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_STATIC_KEYS_SELFTEST                     policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_FHANDLE                                  mark<ENFORCED> note<LP:1412543>
+CONFIG_SYSFS_DEPRECATED                         mark<ENFORCED> note<ensure nothing is using these deprecated interfaces>
+CONFIG_COMPAT_BRK                               mark<ENFORCED> note<disables brk ASLR>
+CONFIG_LOCALVERSION_AUTO                        mark<ENFORCED> note<triggers packaging failures>
+CONFIG_JUMP_LABEL                               flag<REVIEW>
+
+# Menu: General setup >> CPU/Task time and stats accounting
+CONFIG_BSD_PROCESS_ACCT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BSD_PROCESS_ACCT_V3                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TASKSTATS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TASK_DELAY_ACCT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TASK_XACCT                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TASK_IO_ACCOUNTING                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: General setup >> CPU/Task time and stats accounting >> Cputime accounting
+CONFIG_TICK_CPU_ACCOUNTING                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_VIRT_CPU_ACCOUNTING_NATIVE               policy<{'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_VIRT_CPU_ACCOUNTING_GEN                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n'}>
+CONFIG_IRQ_TIME_ACCOUNTING                      policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n'}>
+
+# Menu: General setup >> Choose SLAB allocator
+CONFIG_SLAB                                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SLUB                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLOB                                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: General setup >> Compiler optimization level
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_OPTIMIZE_FOR_SIZE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: General setup >> Configure standard kernel features (expert users)
+CONFIG_EXPERT                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UID16                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_MULTIUSER                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SGETMASK_SYSCALL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSFS_SYSCALL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSCTL_SYSCALL                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KALLSYMS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KALLSYMS_ALL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PRINTK                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BUG                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ELF_CORE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCSPKR_PLATFORM                          policy<{'amd64': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_BASE_FULL                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FUTEX                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EPOLL                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SIGNALFD                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TIMERFD                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVENTFD                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SHMEM                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AIO                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ADVISE_SYSCALLS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_QUIRKS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MEMBARRIER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VM_EVENT_COUNTERS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLUB_DEBUG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: General setup >> Control Group support
+CONFIG_CGROUPS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CGROUP_FREEZER                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_PIDS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_DEVICE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CPUSETS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_PID_CPUSET                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_CPUACCT                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMCG                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMCG_SWAP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMCG_SWAP_ENABLED                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MEMCG_KMEM                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_HUGETLB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_PERF                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_CGROUP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_BLK_CGROUP                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_DEBUG_BLK_CGROUP                         flag<DEBUG>
+
+# Menu: General setup >> Control Group support >> Group CPU scheduler
+CONFIG_CGROUP_SCHED                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FAIR_GROUP_SCHED                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CFS_BANDWIDTH                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RT_GROUP_SCHED                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_RT_GROUP_SCHED                           note<LP#1284731>
+
+# Menu: General setup >> GCOV-based kernel profiling
+CONFIG_GCOV_KERNEL                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: General setup >> GCOV-based kernel profiling >> Specify GCOV format
+
+# Menu: General setup >> IRQ subsystem
+CONFIG_IRQ_DOMAIN_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_IRQ_FORCED_THREADING_DEFAULT             policy<{'amd64-generic': 'n', 'amd64-lowlatency': 'y', 'arm64': 'n', 'armhf': 'n', 'i386-generic': 'n', 'i386-lowlatency': 'y', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_SPARSE_IRQ                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: General setup >> Initial RAM filesystem and RAM disk (initramfs/initrd) support
+CONFIG_BLK_DEV_INITRD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INITRAMFS_SOURCE                         policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'powerpc': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_RD_GZIP                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_BZIP2                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_LZMA                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_XZ                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_LZO                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_LZ4                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: General setup >> Kernel Performance Events And Counters
+CONFIG_PERF_EVENTS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_PERF_USE_VMALLOC                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+
+# Menu: General setup >> Kernel compression mode
+CONFIG_KERNEL_GZIP                              policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'n'}>
+CONFIG_KERNEL_BZIP2                             policy<{'amd64': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_KERNEL_LZMA                              policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_KERNEL_XZ                                policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'y'}>
+CONFIG_KERNEL_LZO                               policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_KERNEL_LZ4                               policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+#
+CONFIG_KERNEL_GZIP                              flag<REVIEW> note<does s390x care the format here?>
+
+# Menu: General setup >> Namespaces support
+CONFIG_NAMESPACES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UTS_NS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPC_NS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_USER_NS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PID_NS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_NS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: General setup >> RCU Subsystem
+# XXX
+CONFIG_CONTEXT_TRACKING_FORCE                   policy<{'amd64': '-', 'arm64': '-', 'armhf': '-', 'i386': '-', 'powerpc-powerpc64-emb': '-', 'powerpc-powerpc64-smp': '-', 'powerpc-powerpc-e500mc': '-', 'powerpc-powerpc-smp': '-', 'ppc64el': '-', 's390x': '-'}>
+#
+CONFIG_CONTEXT_TRACKING_FORCE                   note<LP:1349028> mark<ENFORCED>
+
+# Menu: General setup >> RCU Subsystem >> Make expert-level adjustments to RCU configuration
+CONFIG_RCU_NOCB_CPU                             policy<{'amd64': 'y', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RCU_EXPERT                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_RCU_EXPERT                               flag<REVIEW>
+
+# Menu: General setup >> RCU Subsystem >> Make expert-level adjustments to RCU configuration >> Build-forced no-CBs CPUs
+CONFIG_RCU_NOCB_CPU_NONE                        policy<{'amd64': 'n', 'powerpc-powerpc64-smp': 'n'}>
+CONFIG_RCU_NOCB_CPU_ZERO                        policy<{'amd64': 'n', 'powerpc-powerpc64-smp': 'n'}>
+CONFIG_RCU_NOCB_CPU_ALL                         policy<{'amd64': 'y', 'powerpc-powerpc64-smp': 'y'}>
+
+# Menu: General setup >> Stack Protector buffer overflow detection
+CONFIG_CC_STACKPROTECTOR_NONE                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_CC_STACKPROTECTOR_REGULAR                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_CC_STACKPROTECTOR_STRONG                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+#
+CONFIG_CC_STACKPROTECTOR_STRONG			mark<ENFORCED>
+
+# Menu: General setup >> Stack Protector buffer overflow detection >> Architecture: arm
+
+# Menu: General setup >> Stack Protector buffer overflow detection >> Architecture: arm64
+
+# Menu: General setup >> Stack Protector buffer overflow detection >> Architecture: powerpc
+
+# Menu: General setup >> Stack Protector buffer overflow detection >> Architecture: s390
+
+# Menu: General setup >> Stack Protector buffer overflow detection >> Architecture: x86
+
+# Menu: General setup >> Timers subsystem
+CONFIG_NO_HZ                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HIGH_RES_TIMERS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: General setup >> Timers subsystem >> Timer tick handling
+CONFIG_HZ_PERIODIC                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NO_HZ_IDLE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NO_HZ_FULL                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_NO_HZ_IDLE                               note<LP:1413968>
+
+# Menu: Kernel hacking
+CONFIG_MAGIC_SYSRQ                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE               policy<{'amd64': '0x1', 'arm64': '0x1', 'armhf': '0x1', 'i386': '0x1', 'powerpc': '0x1', 'ppc64el': '0x1', 's390x': '0x01b6'}>
+CONFIG_PANIC_ON_OOPS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PANIC_TIMEOUT                            policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '10', 's390x': '0'}>
+CONFIG_DEBUG_TIMEKEEPING                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_STACKTRACE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROVIDE_OHCI1394_DMA_INIT                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DMA_API_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_LKM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_USER_COPY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_BPF                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_FIRMWARE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_UDELAY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MEMTEST                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TEST_STATIC_KEYS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STRICT_DEVMEM                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PID_IN_CONTEXTIDR                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DEBUG_SET_MODULE_RONX                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_RODATA                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_EARLY_PRINTK                             policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_PANIC_ON_OOPS                            note<keep working if at all possible>
+CONFIG_STRICT_DEVMEM                            mark<ENFORCED>
+CONFIG_DEBUG_RODATA                             mark<ENFORCED>
+CONFIG_DEBUG_SET_MODULE_RONX                    mark<ENFORCED>
+
+# Menu: Kernel hacking >> Architecture: arm
+CONFIG_ARM_PTDUMP                               policy<{'armhf': 'n'}>
+CONFIG_ARM_UNWIND                               policy<{'armhf': 'y'}>
+CONFIG_DEBUG_USER                               policy<{'armhf': 'n'}>
+CONFIG_DEBUG_LL                                 policy<{'armhf': 'n'}>
+CONFIG_DEBUG_IMX_UART_PORT                      policy<{'armhf-generic': '1'}>
+CONFIG_DEBUG_VF_UART_PORT                       policy<{'armhf-generic': '1'}>
+CONFIG_ARM_KPROBES_TEST                         policy<{'armhf': 'm'}>
+
+# Menu: Kernel hacking >> Architecture: arm64
+CONFIG_ARM64_PTDUMP                             policy<{'arm64': 'n'}>
+CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET              policy<{'arm64': 'n'}>
+CONFIG_DEBUG_ALIGN_RODATA                       policy<{'arm64': 'n'}>
+
+# Menu: Kernel hacking >> Architecture: powerpc
+CONFIG_PPC_DISABLE_WERROR                       policy<{'powerpc': 'y', 'ppc64el': 'n'}>
+CONFIG_STRICT_MM_TYPECHECKS                     policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_PRINT_STACK_DEPTH                        policy<{'powerpc': '64', 'ppc64el': '64'}>
+CONFIG_HCALL_STATS                              policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n'}>
+CONFIG_PPC_EMULATED_STATS                       policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CODE_PATCHING_SELFTEST                   policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FTR_FIXUP_SELFTEST                       policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MSI_BITMAP_SELFTEST                      policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_XMON                                     policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_XMON_DEFAULT                             policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_XMON_DISASSEMBLY                         policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BDI_SWITCH                               policy<{'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_BOOTX_TEXT                               policy<{'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n'}>
+CONFIG_PPC_EARLY_DEBUG                          policy<{'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_PPC_DISABLE_WERROR                       flag<REVIEW>
+
+# Menu: Kernel hacking >> Architecture: s390
+CONFIG_S390_PTDUMP                              policy<{'s390x': 'y'}>
+
+# Menu: Kernel hacking >> Architecture: x86
+CONFIG_X86_VERBOSE_BOOTUP                       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_EARLY_PRINTK_DBGP                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EARLY_PRINTK_EFI                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_PTDUMP                               policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_EFI_PGT_DUMP                             policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_RODATA_TEST                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_WX                                 policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_NX_TEST                            policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DOUBLEFAULT                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DEBUG_TLBFLUSH                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_IOMMU_DEBUG                              policy<{'amd64': 'n'}>
+CONFIG_IOMMU_STRESS                             policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_DECODER_SELFTEST                     policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_BOOT_PARAMS                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_CPA_DEBUG                                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_OPTIMIZE_INLINING                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DEBUG_ENTRY                              policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_NMI_SELFTEST                       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_DEBUG_FPU                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PUNIT_ATOM_DEBUG                         policy<{'amd64': 'm', 'i386': 'm'}>
+#
+CONFIG_DEBUG_NX_TEST                            flag<TESTING>
+CONFIG_X86_DECODER_SELFTEST                     flag<TESTING>
+CONFIG_X86_DEBUG_FPU                            flag<REVIEW>
+CONFIG_PUNIT_ATOM_DEBUG                         flag<REVIEW>
+
+# Menu: Kernel hacking >> Compile-time checks and compiler options
+CONFIG_ENABLE_WARN_DEPRECATED                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_ENABLE_MUST_CHECK                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FRAME_WARN                               policy<{'amd64': '1024', 'arm64': '1024', 'armhf': '1024', 'i386': '1024', 'powerpc': '1024', 'ppc64el': '2048', 's390x': '1024'}>
+CONFIG_STRIP_ASM_SYMS                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_READABLE_ASM                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_UNUSED_SYMBOLS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PAGE_OWNER                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_FS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HEADERS_CHECK                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_SECTION_MISMATCH                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECTION_MISMATCH_WARN_ONLY               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FRAME_POINTER                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+
+# Menu: Kernel hacking >> Compile-time checks and compiler options >> Compile the kernel with debug info
+CONFIG_DEBUG_INFO                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_INFO_REDUCED                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_INFO_SPLIT                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_INFO_DWARF4                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GDB_SCRIPTS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_DEBUG_INFO                               mark<ENFORCED> note<required for debug packages>
+CONFIG_DEBUG_INFO_SPLIT                         note<LP:1413646 and LP:1413664>
+
+# Menu: Kernel hacking >> CoreSight Tracing Support
+CONFIG_CORESIGHT                                policy<{'arm64': 'n', 'armhf': 'n'}>
+
+# Menu: Kernel hacking >> CoreSight Tracing Support >> CoreSight Link and Sink drivers
+
+# Menu: Kernel hacking >> Debug Lockups and Hangs
+CONFIG_LOCKUP_DETECTOR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC               policy<{'amd64': 'n', 'i386': 'n', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n'}>
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_DETECT_HUNG_TASK                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT                policy<{'amd64': '120', 'arm64': '120', 'armhf': '120', 'i386': '120', 'powerpc': '120', 'ppc64el': '120', 's390x': '120'}>
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Kernel hacking >> Early debugging console >> Architecture: powerpc
+
+# Menu: Kernel hacking >> IO delay type >> Architecture: x86
+CONFIG_IO_DELAY_0X80                            policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_IO_DELAY_0XED                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IO_DELAY_UDELAY                          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_IO_DELAY_NONE                            policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: Kernel hacking >> Kernel debugging
+CONFIG_DEBUG_KERNEL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_SHIRQ                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SCHED_DEBUG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHEDSTATS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_STACK_END_CHECK                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_PREEMPT                            policy<{'amd64-lowlatency': 'n', 'i386-lowlatency': 'n'}>
+CONFIG_DEBUG_KOBJECT                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_BUGVERBOSE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_LIST                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_PI_LIST                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_SG                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_NOTIFIERS                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_CREDENTIALS                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_BLOCK_EXT_DEVT                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LATENCYTOP                               policy<{'amd64': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS            policy<{'amd64': 'n', 'i386': 'n', 's390x': 'n'}>
+#
+CONFIG_LATENCYTOP                               note<https://lists.ubuntu.com/archives/kernel-team/2014-July/045726.html>
+
+# Menu: Kernel hacking >> Kernel debugging >> Fault-injection framework
+CONFIG_FAULT_INJECTION                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Kernel hacking >> Kernel debugging >> KGDB: kernel debugger
+CONFIG_KGDB                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_KGDB_SERIAL_CONSOLE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_KGDB_TESTS                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_KGDB_LOW_LEVEL_TRAP                      policy<{'amd64': 'y', 'i386': 'y'}>
+#
+CONFIG_KGDB                                     flag<REVIEW>
+CONFIG_KGDB_SERIAL_CONSOLE                      note<early debugging support>
+
+# Menu: Kernel hacking >> Kernel debugging >> KGDB: kernel debugger >> KGDB_KDB: include kdb frontend for kgdb
+CONFIG_KGDB_KDB                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_KDB_DEFAULT_ENABLE                       policy<{'amd64': '0x1', 'arm64': '0x1', 'armhf': '0x1', 'i386': '0x1', 'powerpc': '0x1', 'ppc64el': '0x1'}>
+CONFIG_KDB_KEYBOARD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_KDB_CONTINUE_CATASTROPHIC                policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+
+# Menu: Kernel hacking >> Kernel debugging >> Notifier error injection
+CONFIG_NOTIFIER_ERROR_INJECTION                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CPU_NOTIFIER_ERROR_INJECT                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc-powerpc64-smp': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PM_NOTIFIER_ERROR_INJECT                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT        policy<{'arm64': 'n', 'armhf': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Kernel hacking >> Kernel low-level debugging port >> Architecture: arm
+
+# Menu: Kernel hacking >> Lock Debugging (spinlocks, mutexes, etc...)
+CONFIG_DEBUG_RT_MUTEXES                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_SPINLOCK                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_MUTEXES                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_WW_MUTEX_SLOWPATH                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_LOCK_ALLOC                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PROVE_LOCKING                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOCK_STAT                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_ATOMIC_SLEEP                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_LOCKING_API_SELFTESTS              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOCK_TORTURE_TEST                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Kernel hacking >> Memory Debugging
+CONFIG_PAGE_EXTENSION                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_PAGEALLOC                          policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n', 'powerpc-powerpc64-emb': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SLUB_DEBUG_ON                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SLUB_STATS                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_STACK_USAGE                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_VM                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_VIRTUAL                            policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_MEMORY_INIT                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MEMORY_NOTIFIER_ERROR_INJECT             policy<{'amd64': 'm', 'i386': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DEBUG_PER_CPU_MAPS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_HIGHMEM                            policy<{'armhf': 'n', 'i386': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_DEBUG_STACKOVERFLOW                      policy<{'amd64': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_KASAN                                    policy<{'amd64': 'n', 'arm64': 'n'}>
+
+# Menu: Kernel hacking >> Memory Debugging >> Debug object operations
+CONFIG_DEBUG_OBJECTS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Kernel hacking >> Memory Debugging >> Instrumentation type
+
+# Menu: Kernel hacking >> Memory Debugging >> Kernel memory leak detector
+CONFIG_DEBUG_KMEMLEAK                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Kernel hacking >> Memory Debugging >> kmemcheck: trap use of uninitialized memory
+
+# Menu: Kernel hacking >> Memory Debugging >> kmemcheck: trap use of uninitialized memory >> kmemcheck: default mode at boot
+
+# Menu: Kernel hacking >> RCU Debugging
+CONFIG_SPARSE_RCU_POINTER                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RCU_CPU_STALL_TIMEOUT                    policy<{'amd64': '60', 'arm64': '60', 'armhf': '60', 'i386': '60', 'powerpc': '21', 'ppc64el': '21', 's390x': '21'}>
+CONFIG_RCU_TRACE                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RCU_EQS_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_RCU_CPU_STALL_TIMEOUT                    flag<REVIEW>
+
+# Menu: Kernel hacking >> RCU Debugging >> torture tests for RCU
+CONFIG_RCU_TORTURE_TEST                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Kernel hacking >> Runtime Testing
+CONFIG_LKDTM                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_LIST_SORT                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_KPROBES_SANITY_TEST                      policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BACKTRACE_SELF_TEST                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RBTREE_TEST                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTERVAL_TREE_TEST                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PERCPU_TEST                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ATOMIC64_SELFTEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_ASYNC_RAID6_TEST                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_HEXDUMP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_STRING_HELPERS                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_KSTRTOX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_PRINTF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_RHASHTABLE                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_HASH                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_LKDTM                                    flag<TESTING> flag<REVIEW>
+CONFIG_TEST_LIST_SORT                           flag<TESTING>
+CONFIG_KPROBES_SANITY_TEST                      flag<TESTING>
+CONFIG_BACKTRACE_SELF_TEST                      flag<TESTING>
+CONFIG_ATOMIC64_SELFTEST                        flag<TESTING>
+CONFIG_TEST_RHASHTABLE                          flag<TESTING>
+
+# Menu: Kernel hacking >> Sample kernel code
+CONFIG_SAMPLES                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Kernel hacking >> Tracers
+CONFIG_FTRACE                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IRQSOFF_TRACER                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PREEMPT_TRACER                           policy<{'amd64-lowlatency': 'n', 'i386-lowlatency': 'n'}>
+CONFIG_SCHED_TRACER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FTRACE_SYSCALLS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACER_SNAPSHOT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_STACK_TRACER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_IO_TRACE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KPROBE_EVENT                             policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UPROBE_EVENT                             policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FTRACE_STARTUP_TEST                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MMIOTRACE                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MMIOTRACE_TEST                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_TRACEPOINT_BENCHMARK                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RING_BUFFER_BENCHMARK                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RING_BUFFER_STARTUP_TEST                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TRACE_ENUM_MAP_FILE                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TRACING_EVENTS_GPIO                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_FTRACE_STARTUP_TEST                      flag<TESTING>
+CONFIG_MMIOTRACE_TEST                           flag<TESTING>
+CONFIG_RING_BUFFER_BENCHMARK                    flag<TESTING>
+CONFIG_RING_BUFFER_STARTUP_TEST                 flag<TESTING>
+
+# Menu: Kernel hacking >> Tracers >> Branch Profiling
+CONFIG_BRANCH_PROFILE_NONE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROFILE_ANNOTATED_BRANCHES               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PROFILE_ALL_BRANCHES                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Kernel hacking >> Tracers >> Kernel Function Tracer
+CONFIG_FUNCTION_TRACER                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FUNCTION_GRAPH_TRACER                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DYNAMIC_FTRACE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FUNCTION_PROFILER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Kernel hacking >> printk and dmesg options
+CONFIG_PRINTK_TIME                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT                 policy<{'amd64': '4', 'arm64': '4', 'armhf': '4', 'i386': '4', 'powerpc': '4', 'ppc64el': '4', 's390x': '4'}>
+CONFIG_BOOT_PRINTK_DELAY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_DYNAMIC_DEBUG                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Library routines
+CONFIG_CRC_CCITT                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRC16                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC_T10DIF                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC_ITU_T                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRC32                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC32_SELFTEST                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRC7                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LIBCRC32C                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRC8                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RANDOM32_SELFTEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_GLOB_SELFTEST                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CORDIC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DDR                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DIMLIB                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Library routines >> CRC32 implementation
+CONFIG_CRC32_SLICEBY8                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC32_SLICEBY4                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRC32_SARWATE                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRC32_BIT                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Library routines >> Select compiled-in fonts
+CONFIG_FONTS                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FONT_8x8                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FONT_8x16                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FONT_6x11                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FONT_7x14                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FONT_PEARL_8x8                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FONT_ACORN_8x8                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FONT_MINI_4x6                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FONT_6x10                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_FONT_10x18                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FONT_SUN8x16                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FONT_SUN12x22                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_FONT_TER16x32                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Library routines >> XZ decompression support
+CONFIG_XZ_DEC                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XZ_DEC_X86                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_POWERPC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_IA64                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_ARM                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_ARMTHUMB                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_SPARC                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_TEST                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+#
+CONFIG_XZ_DEC                                   note<boot essential -- initramfs decompressor> flag<REVIEW>
+
+# Menu: Networking support
+CONFIG_NET                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AF_RXRPC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AF_RXRPC_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RXKAD                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CEPH_LIB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CEPH_LIB_PRETTYDEBUG                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CEPH_LIB_USE_DNS_RESOLVER                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LWTUNNEL                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Networking support >> Amateur Radio support
+CONFIG_HAMRADIO                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Networking support >> Amateur Radio support >> Amateur Radio AX.25 Level 2 protocol
+CONFIG_AX25                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_AX25_DAMA_SLAVE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_NETROM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ROSE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> Amateur Radio support >> Amateur Radio AX.25 Level 2 protocol >> AX.25 network device drivers
+CONFIG_MKISS                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_6PACK                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BPQETHER                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SCC                                      policy<{'i386': 'm'}>
+CONFIG_SCC_DELAY                                policy<{'i386': 'n'}>
+CONFIG_SCC_TRXECHO                              policy<{'i386': 'n'}>
+CONFIG_BAYCOM_SER_FDX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BAYCOM_SER_HDX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BAYCOM_PAR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BAYCOM_EPP                               policy<{'armhf': 'm', 'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_YAM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> Bluetooth subsystem support
+CONFIG_BT                                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_LE                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_6LOWPAN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_SELFTEST                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_BT_DEBUGFS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Networking support >> Bluetooth subsystem support >> Bluetooth Classic (BR/EDR) features
+CONFIG_BT_BREDR                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_RFCOMM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_RFCOMM_TTY                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_BNEP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_BNEP_MC_FILTER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_BNEP_PROTO_FILTER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_CMTP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HIDP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HS                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_BT_HS                                    mark<ENFORCED> note<https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00435.html>
+
+# Menu: Networking support >> Bluetooth subsystem support >> Bluetooth device drivers
+CONFIG_BT_HCIBTSDIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIBCM203X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIBFUSB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIDTL1                               policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_BT_HCIBT3C                               policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_BT_HCIBLUECARD                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_BT_HCIBTUART                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_BT_HCIVHCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_MRVL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_MRVL_SDIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_WILINK                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> Bluetooth subsystem support >> Bluetooth device drivers >> HCI UART driver
+CONFIG_BT_HCIBPA10X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIUART                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIUART_H4                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_BCSP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_ATH3K                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_LL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_3WIRE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_INTEL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_BCM                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_QCA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Networking support >> Bluetooth subsystem support >> Bluetooth device drivers >> HCI USB driver
+CONFIG_BT_HCIBTUSB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIBTUSB_BCM                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIBTUSB_RTL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_ATH3K                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> CAIF support
+CONFIG_CAIF                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CAIF_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CAIF_NETDEV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAIF_USB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> CAN bus subsystem support
+CONFIG_CAN                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CAN_RAW                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_BCM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_GW                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> CAN bus subsystem support >> CAN Device Drivers
+CONFIG_CAN_VCAN                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SLCAN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_DEBUG_DEVICES                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Networking support >> CAN bus subsystem support >> CAN Device Drivers >> Platform CAN drivers with Netlink support
+CONFIG_CAN_DEV                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_CALC_BITTIMING                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CAN_LEDS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CAN_TI_HECC                              policy<{'armhf': 'm'}>
+CONFIG_CAN_JANZ_ICAN3                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_FLEXCAN                              policy<{'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_PCH_CAN                                  policy<{'i386': 'm'}>
+CONFIG_CAN_GRCAN                                policy<{'arm64': 'm', 'armhf': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_RCAR                                 policy<{'armhf': 'm'}>
+CONFIG_CAN_XILINXCAN                            policy<{'arm64': 'm'}>
+CONFIG_CAN_MSCAN                                policy<{'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_M_CAN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SOFTING                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SOFTING_CS                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+
+# Menu: Networking support >> CAN bus subsystem support >> CAN Device Drivers >> Platform CAN drivers with Netlink support >> Bosch CC770 and Intel AN82527 devices
+CONFIG_CAN_CC770                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_CC770_ISA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_CC770_PLATFORM                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> CAN bus subsystem support >> CAN Device Drivers >> Platform CAN drivers with Netlink support >> Bosch C_CAN/D_CAN devices
+CONFIG_CAN_C_CAN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_C_CAN_PLATFORM                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_C_CAN_PCI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> CAN bus subsystem support >> CAN Device Drivers >> Platform CAN drivers with Netlink support >> CAN SPI interfaces
+CONFIG_CAN_MCP251X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> CAN bus subsystem support >> CAN Device Drivers >> Platform CAN drivers with Netlink support >> CAN USB interfaces
+CONFIG_CAN_EMS_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_ESD_USB2                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_GS_USB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_KVASER_USB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_PEAK_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_8DEV_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> CAN bus subsystem support >> CAN Device Drivers >> Platform CAN drivers with Netlink support >> Philips/NXP SJA1000 devices
+CONFIG_CAN_SJA1000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SJA1000_ISA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SJA1000_PLATFORM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_EMS_PCMCIA                           policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_CAN_EMS_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_PEAK_PCMCIA                          policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm'}>
+CONFIG_CAN_PEAK_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_PEAK_PCIEC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CAN_KVASER_PCI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_PLX_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_TSCAN1                               policy<{'i386': 'm'}>
+
+# Menu: Networking support >> IrDA (infrared) subsystem support
+CONFIG_IRDA                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IRLAN                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IRNET                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IRCOMM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IRDA_ULTRA                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IRDA_CACHE_LAST_LSAP                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IRDA_FAST_RR                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IRDA_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Networking support >> IrDA (infrared) subsystem support >> Infrared-port device drivers
+CONFIG_IRTTY_SIR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KINGSUN_DONGLE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KSDAZZLE_DONGLE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_KS959_DONGLE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_IRDA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SIGMATEL_FIR                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NSC_FIR                                  policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_WINBOND_FIR                              policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOSHIBA_FIR                              policy<{'i386': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_SMC_IRCC_FIR                             policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ALI_FIR                                  policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VLSI_FIR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_VIA_FIR                                  policy<{'amd64': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MCS_FIR                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_SH_IRDA                                  policy<{'armhf': 'm'}>
+
+# Menu: Networking support >> IrDA (infrared) subsystem support >> Infrared-port device drivers >> Blackfin SIR on UART
+
+# Menu: Networking support >> IrDA (infrared) subsystem support >> Infrared-port device drivers >> Blackfin SIR on UART >> SIR Mode
+
+# Menu: Networking support >> IrDA (infrared) subsystem support >> Infrared-port device drivers >> Serial dongle support
+CONFIG_DONGLE                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_ESI_DONGLE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ACTISYS_DONGLE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TEKRAM_DONGLE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_TOIM3232_DONGLE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LITELINK_DONGLE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MA600_DONGLE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_GIRBIL_DONGLE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP2120_DONGLE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_OLD_BELKIN_DONGLE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ACT200L_DONGLE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> NFC subsystem support
+CONFIG_NFC                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NFC_DIGITAL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NCI_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NCI_UART                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_HCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_SHDLC                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Networking support >> NFC subsystem support >> Near Field Communication (NFC) devices
+CONFIG_NFC_PN533                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_WILINK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_TRF7970A                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MEI_PHY                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NFC_SIM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PORT100                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_FDP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_FDP_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PN544_I2C                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PN544_MEI                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NFC_MICROREAD_I2C                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MICROREAD_MEI                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NFC_MRVL_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MRVL_UART                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MRVL_I2C                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MRVL_SPI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST21NFCA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST21NFCA_I2C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST_NCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST_NCI_I2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST_NCI_SPI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NXP_NCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NXP_NCI_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_S3FWRN5_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> Networking options
+CONFIG_PACKET                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PACKET_DIAG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_UNIX                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UNIX_DIAG                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XFRM_USER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XFRM_SUB_POLICY                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_XFRM_MIGRATE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_XFRM_STATISTICS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_KEY                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_KEY_MIGRATE                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IUCV                                     policy<{'s390x': 'y'}>
+CONFIG_AFIUCV                                   policy<{'s390x': 'm'}>
+CONFIG_NETWORK_SECMARK                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETWORK_PHY_TIMESTAMPING                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BRIDGE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_IGMP_SNOOPING                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BRIDGE_VLAN_FILTERING                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_DSA                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_VLAN_8021Q                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VLAN_8021Q_GVRP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VLAN_8021Q_MVRP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DECNET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DECNET_ROUTER                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_LLC2                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IPX                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IPX_INTERN                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATALK                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_X25                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_LAPB                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PHONET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MAC802154                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_DCB                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DNS_RESOLVER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VSOCKETS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VMWARE_VMCI_VSOCKETS                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NETLINK_DIAG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_HSR                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CGROUP_NET_PRIO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_NET_CLASSID                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPF_JIT                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'powerpc': 'y', 's390x': 'y'}>
+
+# Menu: Networking support >> Networking options >> 6LoWPAN Support
+CONFIG_6LOWPAN                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+
+# Menu: Networking support >> Networking options >> 6LoWPAN Support >> Next Header Compression Support
+CONFIG_6LOWPAN_NHC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_DEST                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_FRAGMENT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_HOP                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_IPV6                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_MOBILITY                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_ROUTING                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_UDP                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> Networking options >> Appletalk interfaces support
+CONFIG_DEV_APPLETALK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_LTPC                                     policy<{'i386': 'm'}>
+CONFIG_COPS                                     policy<{'i386': 'm'}>
+CONFIG_COPS_DAYNA                               policy<{'i386': 'y'}>
+CONFIG_COPS_TANGENT                             policy<{'i386': 'y'}>
+CONFIG_IPDDP                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IPDDP_ENCAP                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Networking support >> Networking options >> Asynchronous Transfer Mode (ATM)
+CONFIG_ATM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ATM_CLIP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_CLIP_NO_ICMP                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_LANE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_MPOA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_BR2684                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_BR2684_IPFILTER                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Networking support >> Networking options >> B.A.T.M.A.N. Advanced Meshing Protocol
+CONFIG_BATMAN_ADV                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BATMAN_ADV_BLA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_DAT                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_NC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_MCAST                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Networking support >> Networking options >> IEEE Std 802.15.4 Low-Rate Wireless Personal Area Networks support
+CONFIG_IEEE802154                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IEEE802154_NL802154_EXPERIMENTAL         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_IEEE802154_SOCKET                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_6LOWPAN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> Networking options >> MultiProtocol Label Switching
+CONFIG_MPLS                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_MPLS_GSO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MPLS_ROUTING                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MPLS_IPTUNNEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter)
+CONFIG_NETFILTER                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETFILTER_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NETFILTER_ADVANCED                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BRIDGE_NETFILTER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> Core Netfilter Configuration
+CONFIG_NETFILTER_INGRESS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETFILTER_NETLINK_ACCT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_NETLINK_QUEUE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_NETLINK_LOG                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> Core Netfilter Configuration >> Netfilter Xtables support (required for ip_tables)
+CONFIG_NETFILTER_XTABLES                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MARK                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_CONNMARK                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_SET                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_AUDIT                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CONNMARK             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_DSCP                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_HL                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_HMARK                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_LED                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_LOG                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_MARK                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_NAT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_NETMAP               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_NFLOG                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_NOTRACK              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NETFILTER_XT_TARGET_RATEEST              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_REDIRECT             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TEE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TPROXY               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TRACE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_SECMARK              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TCPMSS               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_BPF                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CGROUP                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CLUSTER               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_COMMENT               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNMARK              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CPU                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_DCCP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_DSCP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_ECN                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_ESP                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_HELPER                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_HL                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_IPCOMP                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_IPRANGE               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_IPVS                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_L2TP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_LENGTH                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_LIMIT                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_MAC                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_MARK                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_NFACCT                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_OSF                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_OWNER                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_POLICY                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_QUOTA                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_RATEEST               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_REALM                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_RECENT                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_SCTP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_SOCKET                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_STATE                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_STATISTIC             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_STRING                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_TCPMSS                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_TIME                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_U32                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> Core Netfilter Configuration >> Netfilter connection tracking support
+CONFIG_NF_CONNTRACK                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_MARK                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_SECMARK                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_ZONES                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_PROCFS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NF_CONNTRACK_EVENTS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_TIMEOUT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_TIMESTAMP                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CT_PROTO_DCCP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CT_PROTO_SCTP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CT_PROTO_UDPLITE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_AMANDA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_FTP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_H323                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_IRC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_NETBIOS_NS                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_SNMP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_PPTP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_SANE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_SIP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_TFTP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CT_NETLINK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CT_NETLINK_TIMEOUT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CT_NETLINK_HELPER                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_NETLINK_GLUE_CT                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_NAT_REDIRECT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+#
+CONFIG_NF_CONNTRACK_PROCFS                      flag<DEPRECATED>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> Core Netfilter Configuration >> Netfilter nf_tables support
+CONFIG_NF_TABLES                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TABLES_INET                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TABLES_NETDEV                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_EXTHDR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_META                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_CT                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_RBTREE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_HASH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_COUNTER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_LOG                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_LIMIT                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_MASQ                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REDIR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_NAT                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_QUEUE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REJECT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_COMPAT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> DECnet: Netfilter Configuration
+CONFIG_DECNET_NF_GRABULATOR                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> Ethernet Bridge nf_tables support
+CONFIG_NF_TABLES_BRIDGE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_BRIDGE_META                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_BRIDGE_REJECT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_BRIDGE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> Ethernet Bridge tables (ebtables) support
+CONFIG_BRIDGE_NF_EBTABLES                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_BROUTE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_T_FILTER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_T_NAT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_802_3                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_AMONG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_ARP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_IP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_IP6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_LIMIT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_MARK                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_PKTTYPE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_STP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_VLAN                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_ARPREPLY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_DNAT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_MARK_T                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_REDIRECT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_SNAT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_LOG                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_NFLOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IP set support
+CONFIG_IP_SET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_MAX                               policy<{'amd64': '256', 'arm64': '256', 'armhf': '256', 'i386': '256', 'powerpc': '256', 'ppc64el': '256', 's390x': '256'}>
+CONFIG_IP_SET_BITMAP_IP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_BITMAP_IPMAC                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_BITMAP_PORT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPMARK                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPPORT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPPORTIP                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPPORTNET                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_MAC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NETPORTNET                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NETNET                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NETPORT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NETIFACE                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_LIST_SET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IP virtual server support
+CONFIG_IP_VS                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_IPV6                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IP_VS_TAB_BITS                           policy<{'amd64': '12', 'arm64': '12', 'armhf': '12', 'i386': '12', 'powerpc': '12', 'ppc64el': '12', 's390x': '12'}>
+CONFIG_IP_VS_PROTO_TCP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_UDP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_ESP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_AH                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_SCTP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_RR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_WRR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_LC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_WLC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_FO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_OVF                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_LBLC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_LBLCR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_DH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_SH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_SED                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_NQ                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_SH_TAB_BITS                        policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8', 's390x': '8'}>
+CONFIG_IP_VS_FTP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_NFCT                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PE_SIP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IP: Netfilter Configuration
+CONFIG_NF_CONNTRACK_IPV4                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TABLES_IPV4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_CHAIN_ROUTE_IPV4                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_DUP_IPV4                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TABLES_ARP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_DUP_IPV4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_ARP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_IPV4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_REJECT_IPV4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_ARPTABLES                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_ARPFILTER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_ARP_MANGLE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IP: Netfilter Configuration >> IP tables support (required for filtering/masq/NAT)
+CONFIG_IP_NF_IPTABLES                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MATCH_AH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MATCH_ECN                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MATCH_RPFILTER                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MATCH_TTL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_FILTER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_REJECT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_SYNPROXY                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_RAW                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_SECURITY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IP: Netfilter Configuration >> IP tables support (required for filtering/masq/NAT) >> Packet mangling
+CONFIG_IP_NF_MANGLE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_CLUSTERIP                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_ECN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_TTL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IP: Netfilter Configuration >> IP tables support (required for filtering/masq/NAT) >> iptables NAT support
+CONFIG_IP_NF_NAT                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_MASQUERADE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_NETMAP                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_REDIRECT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IP: Netfilter Configuration >> IPv4 NAT
+CONFIG_NF_NAT_IPV4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_CHAIN_NAT_IPV4                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_MASQUERADE_IPV4                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_MASQ_IPV4                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REDIR_IPV4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_SNMP_BASIC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IPv6: Netfilter Configuration
+CONFIG_NF_CONNTRACK_IPV6                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TABLES_IPV6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_CHAIN_ROUTE_IPV6                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_DUP_IPV6                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_DUP_IPV6                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_REJECT_IPV6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_IPV6                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IPv6: Netfilter Configuration >> IP6 tables support (required for filtering)
+CONFIG_IP6_NF_IPTABLES                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_AH                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_EUI64                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_FRAG                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_OPTS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_HL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_IPV6HEADER                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_MH                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_RPFILTER                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_RT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_HL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_FILTER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_REJECT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_SYNPROXY                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MANGLE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_RAW                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_SECURITY                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_NAT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_MASQUERADE                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_NPT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IPv6: Netfilter Configuration >> IPv6 NAT
+CONFIG_NF_NAT_IPV6                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_CHAIN_NAT_IPV6                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_MASQUERADE_IPV6                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_MASQ_IPV6                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REDIR_IPV6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> Network testing
+CONFIG_NET_PKTGEN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TCPPROBE                             policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_DROP_MONITOR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+#
+CONFIG_NET_DROP_MONITOR				note<LP #1660634>
+
+# Menu: Networking support >> Networking options >> QoS and/or fair queueing
+CONFIG_NET_SCHED                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_SCH_CBQ                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_HTB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_HFSC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_ATM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_SCH_PRIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_MULTIQ                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_RED                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_SFB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_SFQ                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_TEQL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_TBF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_GRED                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_DSMARK                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_NETEM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_DRR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_MQPRIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_CHOKE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_QFQ                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_CODEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_FQ_CODEL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_FQ                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_HHF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_PIE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_INGRESS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_PLUG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_BASIC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_TCINDEX                          policy<{'amd64': '-', 'arm64': '-', 'armhf': '-', 'i386': '-', 'powerpc': '-', 'ppc64el': '-', 's390x': '-'}>
+CONFIG_NET_CLS_ROUTE4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_FW                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_FLOW                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_CGROUP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_BPF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_FLOWER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_MATCHALL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> QoS and/or fair queueing >> Actions
+CONFIG_NET_CLS_ACT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_ACT_POLICE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_GACT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GACT_PROB                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_ACT_MIRRED                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_IPT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_NAT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_PEDIT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_SIMP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_SKBEDIT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_CSUM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_VLAN                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_BPF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_CONNMARK                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> QoS and/or fair queueing >> Extended Matches
+CONFIG_NET_EMATCH                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_EMATCH_STACK                         policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'powerpc': '32', 'ppc64el': '32', 's390x': '32'}>
+CONFIG_NET_EMATCH_CMP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_NBYTE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_U32                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_META                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_TEXT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_CANID                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_EMATCH_IPSET                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> QoS and/or fair queueing >> Universal 32bit comparisons w/ hashing (U32)
+CONFIG_NET_CLS_U32                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CLS_U32_PERF                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CLS_U32_MARK                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_CLS_IND                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_NET_CLS_IND                              flag<DEPRECATED>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking
+CONFIG_INET                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_MULTICAST                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_IPIP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_IPGRE_DEMUX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_IPGRE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_IPGRE_BROADCAST                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYN_COOKIES                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_IPVTI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_FOU                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_FOU_IP_TUNNELS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INET_AH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_ESP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_IPCOMP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_XFRM_MODE_TRANSPORT                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_XFRM_MODE_TUNNEL                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_XFRM_MODE_BEET                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_LRO                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INET_DIAG                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_UDP_DIAG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_MD5SIG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETLABEL                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_SWITCHDEV                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NET_L3_MASTER_DEV                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_SYN_COOKIES                              mark<ENFORCED>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> IP: advanced router
+CONFIG_IP_ADVANCED_ROUTER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_FIB_TRIE_STATS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_MULTIPLE_TABLES                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_ROUTE_MULTIPATH                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_ROUTE_VERBOSE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> IP: kernel level autoconfiguration
+CONFIG_IP_PNP                                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_IP_PNP					note<LP:1259861>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> IP: multicast routing
+CONFIG_IP_MROUTE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_MROUTE_MULTIPLE_TABLES                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IP_PIMSM_V1                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_PIMSM_V2                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> Layer Two Tunneling Protocol (L2TP)
+CONFIG_L2TP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_L2TP_DEBUGFS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_L2TP_V3                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_L2TP_IP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_L2TP_ETH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> Open vSwitch
+CONFIG_OPENVSWITCH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPENVSWITCH_GRE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPENVSWITCH_VXLAN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPENVSWITCH_GENEVE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> TCP: advanced congestion control
+CONFIG_TCP_CONG_ADVANCED                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TCP_CONG_BIC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_CUBIC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TCP_CONG_WESTWOOD                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_HTCP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_HSTCP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_HYBLA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_VEGAS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_SCALABLE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_LP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_VENO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_YEAH                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_ILLINOIS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_DCTCP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_CDG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> TCP: advanced congestion control >> Default TCP congestion control
+CONFIG_DEFAULT_CUBIC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEFAULT_RENO                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> The DCCP Protocol
+CONFIG_IP_DCCP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> The DCCP Protocol >> DCCP CCIDs Configuration
+CONFIG_IP_DCCP_CCID2_DEBUG                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IP_DCCP_CCID3                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_IP_DCCP_CCID3_DEBUG                      policy<{'s390x': 'n'}>
+#
+CONFIG_IP_DCCP_CCID3                            flag<REVIEW>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> The DCCP Protocol >> DCCP Kernel Hacking
+CONFIG_IP_DCCP_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NET_DCCPPROBE                            policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> The IPv6 protocol
+CONFIG_IPV6                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_ROUTER_PREF                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_ROUTE_INFO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_OPTIMISTIC_DAD                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INET6_AH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_ESP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_IPCOMP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_MIP6                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_ILA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_XFRM_MODE_TRANSPORT                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_XFRM_MODE_TUNNEL                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_XFRM_MODE_BEET                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_VTI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_SIT                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_SIT_6RD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_TUNNEL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_GRE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_MULTIPLE_TABLES                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_SUBTREES                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_MROUTE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_PIMSM_V2                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_IPV6_OPTIMISTIC_DAD                      flag<EXPERIMENTAL>
+CONFIG_IPV6                                     mark<ENFORCED> note<if this is a module we get a module load for every ipv6 packet>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> The RDS Protocol
+CONFIG_RDS                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RDS_RDMA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RDS_TCP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RDS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> The SCTP Protocol
+CONFIG_IP_SCTP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCTPPROBE                            policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCTP_DBG_OBJCNT                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SCTP_COOKIE_HMAC_MD5                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCTP_COOKIE_HMAC_SHA1                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_SCTP_DBG_OBJCNT                          flag<DEBUG>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> The SCTP Protocol >> Default SCTP cookie HMAC encoding
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Networking support >> Networking options >> TCP/IP networking >> The TIPC Protocol
+CONFIG_TIPC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TIPC_MEDIA_IB                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TIPC_MEDIA_UDP                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Networking support >> Plan 9 Resource Sharing Support (9P2000)
+CONFIG_NET_9P                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_9P_VIRTIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_9P_RDMA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_9P_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_NET_9P                                   note<LP:1557994>
+
+# Menu: Networking support >> RF switch subsystem support
+CONFIG_RFKILL                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_RFKILL_INPUT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_RFKILL_REGULATOR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_RFKILL_GPIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+
+# Menu: Networking support >> WiMAX Wireless Broadband support
+CONFIG_WIMAX                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_WIMAX_DEBUG_LEVEL                        policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'powerpc': '8', 'ppc64el': '8'}>
+
+# Menu: Networking support >> Wireless
+CONFIG_WIRELESS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_LIB80211_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+
+# Menu: Networking support >> Wireless >> Generic IEEE 802.11 Networking Stack (mac80211)
+CONFIG_MAC80211                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_MAC80211_RC_MINSTREL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_RC_MINSTREL_HT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_RC_MINSTREL_VHT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_MESH                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_LEDS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_DEBUGFS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_MESSAGE_TRACING                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Networking support >> Wireless >> Generic IEEE 802.11 Networking Stack (mac80211) >> Default rate control algorithm
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Networking support >> Wireless >> Generic IEEE 802.11 Networking Stack (mac80211) >> Select mac80211 debugging features
+CONFIG_MAC80211_DEBUG_MENU                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_MAC80211_STA_HASH_MAX_SIZE               policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+
+# Menu: Networking support >> Wireless >> cfg80211 - wireless configuration API
+CONFIG_CFG80211                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_NL80211_TESTMODE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CFG80211_DEVELOPER_WARNINGS              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CFG80211_REG_DEBUG                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CFG80211_CERTIFICATION_ONUS              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CFG80211_DEFAULT_PS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_DEBUGFS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_INTERNAL_REGDB                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CFG80211_CRDA_SUPPORT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_WEXT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+#
+CONFIG_CFG80211_WEXT                            flag<REVIEW>
+
+# Menu: Platform selection
+CONFIG_ARCH_VEXPRESS                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_HISI                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_ROCKCHIP                            policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_ARCH_BERLIN                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_MEDIATEK                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_TEGRA                               policy<{'arm64': 'n', 'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_ARCH_QCOM                                policy<{'arm64': 'y', 'armhf': 'y'}>
+#
+CONFIG_ARCH_ROCKCHIP				note<LP:1566283>
+
+# Menu: Platform selection >> Architecture: arm64
+CONFIG_ARCH_BCM_IPROC                           policy<{'arm64': 'y'}>
+CONFIG_ARCH_EXYNOS7                             policy<{'arm64': 'n'}>
+CONFIG_ARCH_LAYERSCAPE                          policy<{'arm64': 'y'}>
+CONFIG_ARCH_SEATTLE                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_STRATIX10                           policy<{'arm64': 'y'}>
+CONFIG_ARCH_SPRD                                policy<{'arm64': 'y'}>
+CONFIG_ARCH_THUNDER                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_XGENE                               policy<{'arm64': 'y'}>
+CONFIG_ARCH_ZYNQMP                              policy<{'arm64': 'y'}>
+
+# Menu: Power management and ACPI options
+CONFIG_SUSPEND                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_SUSPEND_FREEZER                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_HIBERNATION                              policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_PM_STD_PARTITION                         policy<{'amd64': '""', 'armhf': '""', 'i386': '""', 'powerpc-powerpc64-smp': '""', 'powerpc-powerpc-e500mc': '""', 'powerpc-powerpc-smp': '""', 's390x': '""'}>
+CONFIG_PM_AUTOSLEEP                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PM_WAKELOCKS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PM_WAKELOCKS_LIMIT                       policy<{'amd64': '100', 'arm64': '100', 'armhf': '100', 'i386': '100', 'powerpc-powerpc64-smp': '100', 'powerpc-powerpc-e500mc': '100', 'powerpc-powerpc-smp': '100', 'ppc64el': '100'}>
+CONFIG_PM_WAKELOCKS_GC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_TRACE_RTC                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_KVM_GUEST                                policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_SFI                                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_IDLE                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SUSPEND_SKIP_SYNC                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_HIBERNATION                              flag<REVIEW>
+
+# Menu: Power management and ACPI options >> 512x-based boards >> Architecture: powerpc
+CONFIG_PPC_MPC512x                              policy<{'powerpc-powerpc-smp': 'n'}>
+
+# Menu: Power management and ACPI options >> 52xx-based boards >> Architecture: powerpc
+CONFIG_PPC_MPC52xx                              policy<{'powerpc-powerpc-smp': 'n'}>
+
+# Menu: Power management and ACPI options >> 82xx-based boards (PQ II) >> Architecture: powerpc
+CONFIG_PPC_82xx                                 policy<{'powerpc-powerpc-smp': 'n'}>
+
+# Menu: Power management and ACPI options >> 83xx-based boards >> Architecture: powerpc
+CONFIG_PPC_83xx                                 policy<{'powerpc-powerpc-smp': 'n'}>
+
+# Menu: Power management and ACPI options >> 86xx-based boards >> Architecture: powerpc
+CONFIG_PPC_86xx                                 policy<{'powerpc-powerpc-smp': 'n'}>
+
+# Menu: Power management and ACPI options >> 8xx Machine Type >> Architecture: powerpc
+
+# Menu: Power management and ACPI options >> ACPI (Advanced Configuration and Power Interface) Support
+#
+
+# Menu: Power management and ACPI options >> ACPI (Advanced Configuration and Power Interface) Support >> ACPI Platform Error Interface (APEI)
+
+# Menu: Power management and ACPI options >> ACPI (Advanced Configuration and Power Interface) Support >> PMIC (Power Management Integrated Circuit) operation region support
+
+# Menu: Power management and ACPI options >> APM (Advanced Power Management) BIOS support >> Architecture: x86
+CONFIG_APM                                      policy<{'i386': 'm'}>
+CONFIG_APM_IGNORE_USER_SUSPEND                  policy<{'i386': 'n'}>
+CONFIG_APM_DO_ENABLE                            policy<{'i386': 'n'}>
+CONFIG_APM_CPU_IDLE                             policy<{'i386': 'n'}>
+CONFIG_APM_DISPLAY_BLANK                        policy<{'i386': 'n'}>
+CONFIG_APM_ALLOW_INTS                           policy<{'i386': 'n'}>
+#
+CONFIG_APM                                      flag<REVIEW>
+
+# Menu: Power management and ACPI options >> Architecture: arm
+
+# Menu: Power management and ACPI options >> Architecture: arm64
+
+# Menu: Power management and ACPI options >> Architecture: powerpc
+CONFIG_PPC_POWERNV                              policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_OPAL_PRD                                 policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_PPC_CHRP                                 policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_PPC_PMAC                                 policy<{'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PPC_PMAC32_PSURGE                        policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_PPC_MAPLE                                policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PPC_PASEMI                               policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PPC_PS3                                  policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PPC_IBM_CELL_BLADE                       policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_PPC_CELL_QPACE                           policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_EPAPR_PARAVIRT                           policy<{'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PPC_OF_BOOT_TRAMPOLINE                   policy<{'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_UDBG_RTAS_CONSOLE                        policy<{'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'n'}>
+CONFIG_MPIC_TIMER                               policy<{'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc64-emb': 'n'}>
+CONFIG_MPIC_MSGR                                policy<{'powerpc': 'y', 'ppc64el': 'n'}>
+CONFIG_RTAS_PROC                                policy<{'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_RTAS_FLASH                               policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_IBMEBUS                                  policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_PPC601_SYNC_FIX                          policy<{'powerpc-powerpc-smp': 'n'}>
+CONFIG_TAU                                      policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_TAU_INT                                  policy<{'powerpc-powerpc-smp': 'n'}>
+CONFIG_TAU_AVERAGE                              policy<{'powerpc-powerpc-smp': 'n'}>
+CONFIG_QUICC_ENGINE                             policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_CPM2                                     policy<{'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_SIMPLE_GPIO                              policy<{'powerpc': 'y', 'ppc64el': 'n'}>
+
+# Menu: Power management and ACPI options >> Architecture: s390
+
+# Menu: Power management and ACPI options >> Architecture: x86
+
+# Menu: Power management and ACPI options >> CPU Frequency scaling
+
+# Menu: Power management and ACPI options >> CPU Frequency scaling >> CPU Frequency scaling
+CONFIG_CPU_FREQ                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_STAT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_STAT_DETAILS                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_PERFORMANCE                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_POWERSAVE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_USERSPACE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_ONDEMAND                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_X86_INTEL_PSTATE                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_PCC_CPUFREQ                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_SFI_CPUFREQ                          policy<{'i386': 'm'}>
+CONFIG_X86_POWERNOW_K6                          policy<{'i386': 'm'}>
+CONFIG_X86_POWERNOW_K7                          policy<{'i386': 'm'}>
+CONFIG_X86_GX_SUSPMOD                           policy<{'i386': 'm'}>
+CONFIG_X86_SPEEDSTEP_CENTRINO                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE             policy<{'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_ICH                        policy<{'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_SMI                        policy<{'i386': 'y'}>
+CONFIG_X86_P4_CLOCKMOD                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_CPUFREQ_NFORCE2                      policy<{'i386': 'y'}>
+CONFIG_X86_LONGRUN                              policy<{'i386': 'm'}>
+CONFIG_X86_LONGHAUL                             policy<{'i386': 'm'}>
+CONFIG_X86_E_POWERSAVER                         policy<{'i386': 'n'}>
+CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK          policy<{'i386': 'y'}>
+CONFIG_ARM_EXYNOS5440_CPUFREQ                   policy<{'armhf': 'n'}>
+CONFIG_ARM_IMX6Q_CPUFREQ                        policy<{'armhf-generic': 'm'}>
+CONFIG_ARM_MT8173_CPUFREQ                       policy<{'arm64': 'y'}>
+CONFIG_ARM_OMAP2PLUS_CPUFREQ                    policy<{'armhf': 'y'}>
+CONFIG_ARM_TEGRA20_CPUFREQ                      policy<{'armhf-generic': 'y'}>
+CONFIG_ACPI_CPPC_CPUFREQ                        policy<{'arm64': 'm'}>
+CONFIG_CPU_FREQ_MAPLE                           policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_CPU_FREQ_PMAC                            policy<{'powerpc-powerpc-smp': 'y'}>
+CONFIG_CPU_FREQ_PMAC64                          policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PPC_PASEMI_CPUFREQ                       policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_POWERNV_CPUFREQ                          policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_QORIQ_CPUFREQ                            policy<{'armhf': 'm', 'powerpc-powerpc-e500mc': 'm', 'powerpc-powerpc64-emb': 'm'}>
+#
+CONFIG_CPU_FREQ_STAT                            note<dependancy of boot essential>
+CONFIG_CPU_FREQ_GOV_PERFORMANCE                 note<not autoloadable>
+CONFIG_CPU_FREQ_GOV_POWERSAVE                   note<not autoloadable>
+CONFIG_CPU_FREQ_GOV_USERSPACE                   note<not autoloadable>
+CONFIG_CPU_FREQ_GOV_ONDEMAND                    note<not autoloadable>
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE                note<not autoloadable>
+CONFIG_X86_PCC_CPUFREQ                          note<not autoloadable>
+CONFIG_X86_SPEEDSTEP_CENTRINO                   note<not autoloadable>
+CONFIG_X86_SPEEDSTEP_ICH                        note<not autoloadable>
+CONFIG_X86_SPEEDSTEP_SMI                        note<not autoloadable>
+CONFIG_X86_CPUFREQ_NFORCE2                      note<not autoloadable>
+
+# Menu: Power management and ACPI options >> CPU Frequency scaling >> CPU Frequency scaling >> ACPI Processor P-States driver
+CONFIG_X86_ACPI_CPUFREQ                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_ACPI_CPUFREQ_CPB                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_POWERNOW_K8                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_AMD_FREQ_SENSITIVITY                 policy<{'amd64': 'm', 'i386': 'm'}>
+#
+CONFIG_X86_ACPI_CPUFREQ                         note<not autoloadable>
+CONFIG_X86_POWERNOW_K8                          note<not autoloadable>
+
+# Menu: Power management and ACPI options >> CPU Frequency scaling >> CPU Frequency scaling >> CPUfreq driver for Samsung S3C24XX series CPUs (EXPERIMENTAL)
+
+# Menu: Power management and ACPI options >> CPU Frequency scaling >> CPU Frequency scaling >> Default CPUFreq governor
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE         note<for bootspeed>
+
+# Menu: Power management and ACPI options >> CPU Frequency scaling >> CPU Frequency scaling >> Generic ARM big LITTLE CPUfreq driver
+CONFIG_ARM_BIG_LITTLE_CPUFREQ                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_DT_BL_CPUFREQ                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_VEXPRESS_SPC_CPUFREQ                 policy<{'armhf': 'm'}>
+CONFIG_ARM_SCPI_CPUFREQ                         policy<{'arm64': 'm', 'armhf': 'm'}>
+
+# Menu: Power management and ACPI options >> CPU Frequency scaling >> CPU Frequency scaling >> Generic DT based cpufreq driver
+CONFIG_CPUFREQ_DT                               policy<{'arm64': 'y', 'armhf': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_ARM_HIGHBANK_CPUFREQ                     policy<{'armhf': 'm'}>
+CONFIG_ARM_HISI_ACPU_CPUFREQ                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_TEGRA124_CPUFREQ                     policy<{'armhf-generic': 'm'}>
+#
+CONFIG_CPUFREQ_DT                               note<not autoloadable>
+
+# Menu: Power management and ACPI options >> CPU Idle
+
+# Menu: Power management and ACPI options >> CPU Idle >> CPU idle PM support
+CONFIG_CPU_IDLE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_IDLE_GOV_LADDER                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_IDLE_GOV_MENU                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+
+# Menu: Power management and ACPI options >> CPU Idle >> CPU idle PM support >> ARM CPU Idle Drivers
+CONFIG_ARM_CPUIDLE                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_BIG_LITTLE_CPUIDLE                   policy<{'armhf': 'y'}>
+CONFIG_ARM_HIGHBANK_CPUIDLE                     policy<{'armhf-generic': 'n', 'armhf-generic-lpae': 'y'}>
+CONFIG_ARM_EXYNOS_CPUIDLE                       policy<{'armhf': 'y'}>
+CONFIG_ARM_MVEBU_V7_CPUIDLE                     policy<{'armhf': 'y'}>
+#
+CONFIG_ARM_HIGHBANK_CPUIDLE                     note<broken on ecx-1000>
+
+# Menu: Power management and ACPI options >> CPU Idle >> CPU idle PM support >> MIPS CPU Idle Drivers
+
+# Menu: Power management and ACPI options >> CPU Idle >> CPU idle PM support >> POWERPC CPU Idle Drivers
+CONFIG_PSERIES_CPUIDLE                          policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_POWERNV_CPUIDLE                          policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+
+# Menu: Power management and ACPI options >> CPUIdle driver >> Architecture: powerpc
+
+# Menu: Power management and ACPI options >> CPUIdle driver >> CPU Idle
+
+# Menu: Power management and ACPI options >> CPUIdle driver >> CPU Idle >> CPU idle PM support
+
+# Menu: Power management and ACPI options >> CPUIdle driver >> CPU Idle >> CPU idle PM support >> ARM CPU Idle Drivers
+#
+
+# Menu: Power management and ACPI options >> CPUIdle driver >> CPU Idle >> CPU idle PM support >> MIPS CPU Idle Drivers
+
+# Menu: Power management and ACPI options >> CPUIdle driver >> CPU Idle >> CPU idle PM support >> POWERPC CPU Idle Drivers
+
+# Menu: Power management and ACPI options >> Cell Broadband Engine options >> Architecture: powerpc
+CONFIG_SPU_FS                                   policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_CBE_CPUFREQ_SPU_GOVERNOR                 policy<{'powerpc-powerpc64-smp': 'm'}>
+
+# Menu: Power management and ACPI options >> Device power management core functionality
+CONFIG_PM                                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_APM_EMULATION                            policy<{'armhf': 'n', 'powerpc-powerpc-smp': 'm'}>
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Power management and ACPI options >> Device power management core functionality >> Power Management Debug Support
+CONFIG_PM_DEBUG                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PM_ADVANCED_DEBUG                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_TEST_SUSPEND                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n'}>
+CONFIG_DPM_WATCHDOG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+#
+CONFIG_PM_DEBUG                                 flag<REVIEW>
+
+# Menu: Power management and ACPI options >> Embedded 6xx/7xx/7xxx-based boards >> Architecture: powerpc
+
+# Menu: Power management and ACPI options >> Freescale Book-E Machine Type >> Architecture: powerpc
+CONFIG_FSL_SOC_BOOKE                            policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_BSC9131_RDB                              policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_C293_PCIE                                policy<{'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_BSC9132_QDS                              policy<{'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_MPC8540_ADS                              policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_MPC8560_ADS                              policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_MPC85xx_CDS                              policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_MPC85xx_MDS                              policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_MPC8536_DS                               policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_MPC85xx_DS                               policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_MPC85xx_RDB                              policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_P1010_RDB                                policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_P1022_DS                                 policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_P1022_RDK                                policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_P1023_RDB                                policy<{'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_TWR_P102x                                policy<{'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_SOCRATES                                 policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_KSI8560                                  policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_XES_MPC85xx                              policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_STX_GP3                                  policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_TQM8540                                  policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_TQM8541                                  policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_TQM8548                                  policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_TQM8555                                  policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_TQM8560                                  policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_SBC8548                                  policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_PPA8548                                  policy<{'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_GE_IMP3A                                 policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_SGY_CTS1000                              policy<{'powerpc-powerpc-e500mc': 'm'}>
+CONFIG_MVME2500                                 policy<{'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_PPC_QEMU_E500                            policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_CORENET_GENERIC                          policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+
+# Menu: Power management and ACPI options >> Freescale Ethernet driver platform-specific options >> Architecture: powerpc
+
+# Menu: Power management and ACPI options >> Freescale Ethernet driver platform-specific options >> Second Ethernet channel >> Architecture: powerpc
+
+# Menu: Power management and ACPI options >> IBM pSeries & new (POWER5-based) iSeries
+CONFIG_CMM                                      policy<{'ppc64el': 'm', 's390x': 'y'}>
+#
+CONFIG_CMM                                      flag<REVIEW>
+
+# Menu: Power management and ACPI options >> IBM pSeries & new (POWER5-based) iSeries >> Architecture: powerpc
+CONFIG_PPC_PSERIES                              policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_PPC_SPLPAR                               policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'y'}>
+CONFIG_DTL                                      policy<{'ppc64el': 'y'}>
+CONFIG_PSERIES_ENERGY                           policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_SCANLOG                                  policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_IO_EVENT_IRQ                             policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_LPARCFG                                  policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'y'}>
+CONFIG_PPC_SMLPAR                               policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'y'}>
+CONFIG_HV_PERF_CTRS                             policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+
+# Menu: Power management and ACPI options >> MPC8xx CPM Options >> Architecture: powerpc
+
+# Menu: Power management and ACPI options >> MPC8xx CPM Options >> Microcode patch selection >> Architecture: powerpc
+
+# Menu: Power management and ACPI options >> Memory power savings
+CONFIG_I7300_IDLE                               policy<{'amd64': 'm'}>
+
+# Menu: Power management and ACPI options >> PA Semi PWRficient options >> Architecture: powerpc
+CONFIG_PPC_PASEMI_IOMMU                         policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE               policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_PPC_PASEMI_MDIO                          policy<{'powerpc-powerpc64-smp': 'm'}>
+
+# Menu: Power management and ACPI options >> PS3 Platform Options >> Architecture: powerpc
+CONFIG_PS3_DYNAMIC_DMA                          policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_PS3_DISK                                 policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_PS3_ROM                                  policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_PS3_FLASH                                policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_PS3_VRAM                                 policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_PS3_LPM                                  policy<{'powerpc-powerpc64-smp': 'm'}>
+CONFIG_PS3GELIC_UDBG                            policy<{'powerpc-powerpc64-smp': 'n'}>
+
+# Menu: Power management and ACPI options >> PS3 Platform Options >> PS3 Advanced configuration options >> Architecture: powerpc
+CONFIG_PS3_ADVANCED                             policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_PS3_HTAB_SIZE                            policy<{'powerpc-powerpc64-smp': '20'}>
+CONFIG_PS3_PS3AV                                policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PS3_SYS_MANAGER                          policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PS3_REPOSITORY_WRITE                     policy<{'powerpc-powerpc64-smp': 'n'}>
+
+# Menu: Processor support
+CONFIG_SMP                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NR_CPUS                                  policy<{'amd64': '512', 'arm64': '128', 'armhf': '4', 'i386': '8', 'powerpc-powerpc64-emb': '8', 'powerpc-powerpc64-smp': '1024', 'powerpc-powerpc-e500mc': '8', 'powerpc-powerpc-smp': '4', 'ppc64el': '2048', 's390x': '256'}>
+
+# Menu: Processor support >> Architecture: powerpc
+CONFIG_PPC_E500MC                               policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_FSL_EMB_PERFMON                          policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_PHYS_64BIT                               policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_ALTIVEC                                  policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_VSX                                      policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_PPC_ICSWX                                policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'n'}>
+CONFIG_PPC_ICSWX_PID                            policy<{'powerpc-powerpc64-smp': 'y'}>
+CONFIG_PPC_ICSWX_USE_SIGILL                     policy<{'powerpc-powerpc64-smp': 'n'}>
+#
+CONFIG_PPC_ICSWX                                flag<REVIEW>
+
+# Menu: Processor support >> CPU selection
+CONFIG_GENERIC_CPU                              policy<{'amd64': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y'}>
+
+# Menu: Processor support >> CPU selection >> Architecture: powerpc
+CONFIG_CELL_CPU                                 policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_POWER4_CPU                               policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_POWER5_CPU                               policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_POWER6_CPU                               policy<{'powerpc-powerpc64-smp': 'n'}>
+CONFIG_POWER7_CPU                               policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'y'}>
+CONFIG_POWER8_CPU                               policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n'}>
+CONFIG_E5500_CPU                                policy<{'powerpc-powerpc64-emb': 'n'}>
+CONFIG_E6500_CPU                                policy<{'powerpc-powerpc64-emb': 'n'}>
+
+# Menu: Processor support >> Processor Type >> Architecture: powerpc
+CONFIG_PPC_BOOK3S_32                            policy<{'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_PPC_85xx                                 policy<{'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_PPC_8xx                                  policy<{'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_40x                                      policy<{'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_44x                                      policy<{'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_E200                                     policy<{'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n'}>
+CONFIG_PPC_BOOK3S_64                            policy<{'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_PPC_BOOK3E_64                            policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n'}>
+
+# Menu: Processor type and features
+CONFIG_SPARSEMEM_VMEMMAP                        policy<{'amd64': 'y', 'arm64': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MOVABLE_NODE                             policy<{'amd64': 'y'}>
+CONFIG_MEMORY_HOTPLUG                           policy<{'amd64': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMORY_HOTREMOVE                         policy<{'amd64': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BALLOON_COMPACTION                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_COMPACTION                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MIGRATION                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BOUNCE                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_KSM                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEFAULT_MMAP_MIN_ADDR                    policy<{'amd64': '65536', 'arm64': '32768', 'armhf': '32768', 'i386': '65536', 'powerpc': '65536', 'ppc64el': '65536', 's390x': '65536'}>
+CONFIG_MEMORY_FAILURE                           policy<{'amd64': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_HWPOISON_INJECT                          policy<{'amd64': 'm', 'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_TRANSPARENT_HUGEPAGE                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CLEANCACHE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FRONTSWAP                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEM_SOFT_DIRTY                           policy<{'amd64': 'y', 's390x': 'y'}>
+CONFIG_ZSWAP                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZPOOL                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZBUD                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZSMALLOC                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PGTABLE_MAPPING                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ZSMALLOC_STAT                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFERRED_STRUCT_PAGE_INIT                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_IDLE_PAGE_TRACKING                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZONE_DEVICE                              policy<{'amd64': 'y'}>
+CONFIG_SCHED_MC                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_SCHED_SMT                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HOTPLUG_CPU                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NUMA                                     policy<{'amd64': 'y', 'arm64': 'y', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NODES_SHIFT                              policy<{'amd64': '6', 'arm64': '2', 'powerpc-powerpc64-smp': '8', 'ppc64el': '8', 's390x': '4'}>
+CONFIG_XEN                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y'}>
+CONFIG_HIGHPTE                                  policy<{'armhf': 'y', 'i386': 'y'}>
+CONFIG_MATH_EMULATION                           policy<{'i386': 'n', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y'}>
+CONFIG_CMDLINE_BOOL                             policy<{'amd64': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_HIGHMEM                                  policy<{'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y'}>
+CONFIG_FORCE_MAX_ZONEORDER                      policy<{'arm64': '13', 'armhf-generic': '12', 'armhf-generic-lpae': '11', 'powerpc-powerpc-e500mc': '11', 'powerpc-powerpc-smp': '11', 'powerpc-powerpc64-emb': '13', 'powerpc-powerpc64-smp': '13', 'ppc64el': '9', 's390x': '9'}>
+#
+CONFIG_DEFAULT_MMAP_MIN_ADDR                    mark<ENFORCED> note<LP:1418140>
+CONFIG_IDLE_PAGE_TRACKING			flag<REVIEW> note<is there a cost associated with this?>
+
+# Menu: Processor type and features >> ARM errata workarounds via the alternatives framework >> Architecture: arm64
+CONFIG_ARM64_ERRATUM_826319                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_827319                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_824069                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_819472                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_832075                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_834220                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_845719                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_843419                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_1024718                    policy<{'arm64': 'y'}>
+CONFIG_CAVIUM_ERRATUM_22375                     policy<{'arm64': 'y'}>
+CONFIG_CAVIUM_ERRATUM_23144                     policy<{'arm64': 'y'}>
+CONFIG_CAVIUM_ERRATUM_23154                     policy<{'arm64': 'y'}>
+CONFIG_CAVIUM_ERRATUM_27456                     policy<{'arm64': 'y'}>
+
+# Menu: Processor type and features >> ARMv8.1 architectural features >> Architecture: arm64
+CONFIG_ARM64_HW_AFDBM                           policy<{'arm64': 'y'}>
+CONFIG_ARM64_PAN                                policy<{'arm64': 'y'}>
+CONFIG_ARM64_LSE_ATOMICS                        policy<{'arm64': 'n'}>
+
+# Menu: Processor type and features >> Architecture: arm
+CONFIG_HAVE_ARM_ARCH_TIMER                      policy<{'armhf': 'y'}>
+CONFIG_ARM_PSCI                                 policy<{'armhf': 'y'}>
+CONFIG_THUMB2_KERNEL                            policy<{'armhf': 'n'}>
+CONFIG_AEABI                                    policy<{'armhf': 'y'}>
+CONFIG_OABI_COMPAT                              policy<{'armhf': 'n'}>
+CONFIG_CPU_SW_DOMAIN_PAN                        policy<{'armhf-generic': 'y'}>
+CONFIG_ARM_MODULE_PLTS                          policy<{'armhf': 'n'}>
+CONFIG_UACCESS_WITH_MEMCPY                      policy<{'armhf': 'n'}>
+
+# Menu: Processor type and features >> Architecture: arm64
+
+# Menu: Processor type and features >> Architecture: powerpc
+CONFIG_PPC_RTAS_FILTER                          policy<{'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_PPC_TRANSACTIONAL_MEM                    policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_SWIOTLB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_PPC64_SUPPORTS_MEMORY_FAILURE            policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_FA_DUMP                                  policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_IRQ_ALL_CPUS                             policy<{'powerpc': 'n', 'ppc64el': 'y'}>
+CONFIG_PPC_SUBPAGE_PROT                         policy<{'ppc64el': 'y'}>
+CONFIG_PPC_DENORMALISATION                      policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'y'}>
+CONFIG_EXTRA_TARGETS                            policy<{'powerpc': '""', 'ppc64el': '""'}>
+#
+CONFIG_PPC_RTAS_FILTER                          mark<ENFORCED> note<CVE-2020-27777>
+CONFIG_FA_DUMP                                  note<LP:1415562>
+
+# Menu: Processor type and features >> Architecture: s390
+CONFIG_PACK_STACK                               policy<{'s390x': 'y'}>
+CONFIG_CHECK_STACK                              policy<{'s390x': 'y'}>
+CONFIG_STACK_GUARD                              policy<{'s390x': '256'}>
+CONFIG_WARN_DYNAMIC_STACK                       policy<{'s390x': 'n'}>
+
+# Menu: Processor type and features >> Architecture: x86
+CONFIG_ZONE_DMA                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_X86_FEATURE_NAMES                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_FAST_FEATURE_TESTS                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_X2APIC                               policy<{'amd64': 'y'}>
+CONFIG_X86_MPPARSE                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_RETPOLINE                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_EXTENDED_PLATFORM                    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_INTEL_LPSS                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_AMD_PLATFORM_DEVICE                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IOSF_MBI                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IOSF_MBI_DEBUG                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_32_IRIS                              policy<{'i386': 'm'}>
+CONFIG_SCHED_OMIT_FRAME_POINTER                 policy<{'amd64': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_X86_GENERIC                              policy<{'i386': 'y'}>
+CONFIG_X86_PPRO_FENCE                           policy<{'i386': 'y'}>
+CONFIG_HPET_TIMER                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_GART_IOMMU                               policy<{'amd64': 'y'}>
+CONFIG_CALGARY_IOMMU                            policy<{'amd64': 'y'}>
+CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT         policy<{'amd64': 'y'}>
+CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_LEGACY_VM86                          policy<{'i386': 'y'}>
+CONFIG_X86_16BIT                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_VSYSCALL_EMULATION                   policy<{'amd64': 'y'}>
+CONFIG_TOSHIBA                                  policy<{'i386': 'n'}>
+CONFIG_I8K                                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_REBOOTFIXUPS                         policy<{'i386': 'y'}>
+CONFIG_MICROCODE                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MICROCODE_INTEL                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MICROCODE_AMD                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MSR                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_CPUID                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_PAE                                  policy<{'i386': 'y'}>
+CONFIG_ARCH_MEMORY_PROBE                        policy<{'amd64': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_X86_PMEM_LEGACY                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_CHECK_BIOS_CORRUPTION                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_RESERVE_LOW                          policy<{'amd64': '64', 'i386': '64'}>
+CONFIG_MTRR                                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MTRR_SANITIZER                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT            policy<{'amd64': '1', 'i386': '1'}>
+CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT      policy<{'amd64': '1', 'i386': '1'}>
+CONFIG_X86_PAT                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_RANDOM                              policy<{'amd64': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+CONFIG_X86_SMAP                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_INTEL_MPX                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EFI_STUB                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_EFI_MIXED                                policy<{'amd64': 'y'}>
+CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_KEXEC_FILE                               policy<{'amd64': 'y'}>
+CONFIG_KEXEC_VERIFY_SIG                         policy<{'amd64': 'y'}>
+CONFIG_KEXEC_BZIMAGE_VERIFY_SIG                 policy<{'amd64': 'y'}>
+CONFIG_KEXEC_JUMP                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_RANDOMIZE_BASE                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_RANDOMIZE_BASE_MAX_OFFSET                policy<{'amd64': '0x40000000', 'i386': '0x20000000'}>
+CONFIG_PHYSICAL_ALIGN                           policy<{'amd64': '0x1000000', 'i386': '0x1000000', 'powerpc-powerpc-e500mc': '0x04000000'}>
+CONFIG_BOOTPARAM_HOTPLUG_CPU0                   policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_HOTPLUG_CPU0                       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_COMPAT_VDSO                              policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_MODIFY_LDT_SYSCALL                       policy<{'amd64': 'y', 'i386': 'y'}>
+#
+CONFIG_COMPAT_VDSO                              mark<ENFORCED>
+CONFIG_X86_LEGACY_VM86				note<LP:1499089>
+CONFIG_KEXEC_BZIMAGE_VERIFY_SIG			flag<REVIEW> note<Q: check this is in sync with the kexec/kdump userspace>
+CONFIG_MODIFY_LDT_SYSCALL			flag<REVIEW> note<Q: check this with security>
+
+# Menu: Processor type and features >> Contiguous Memory Allocator
+CONFIG_CMA                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_CMA_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CMA_DEBUGFS                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_CMA_AREAS                                policy<{'amd64': '7', 'arm64': '7', 'armhf': '7', 'i386': '7', 'powerpc': '7', 'ppc64el': '7'}>
+
+# Menu: Processor type and features >> Device power management core functionality
+
+# Menu: Processor type and features >> Device power management core functionality >> Power Management Debug Support
+#
+
+# Menu: Processor type and features >> Emulate deprecated/obsolete ARMv8 instructions >> Architecture: arm64
+CONFIG_ARMV8_DEPRECATED                         policy<{'arm64': 'y'}>
+CONFIG_SWP_EMULATION                            policy<{'arm64': 'y'}>
+CONFIG_CP15_BARRIER_EMULATION                   policy<{'arm64': 'y'}>
+CONFIG_SETEND_EMULATION                         policy<{'arm64': 'y'}>
+
+# Menu: Processor type and features >> High Memory Support >> Architecture: x86
+CONFIG_NOHIGHMEM                                policy<{'i386': 'n'}>
+CONFIG_HIGHMEM4G                                policy<{'i386': 'n'}>
+CONFIG_HIGHMEM64G                               policy<{'i386': 'y'}>
+
+# Menu: Processor type and features >> Linux guest support >> Architecture: x86
+CONFIG_HYPERVISOR_GUEST                         policy<{'amd64': 'y', 'i386': 'y'}>
+
+# Menu: Processor type and features >> Linux guest support >> Enable paravirtualization code
+
+# Menu: Processor type and features >> Linux guest support >> Enable paravirtualization code >> Architecture: x86
+CONFIG_PARAVIRT                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PARAVIRT_DEBUG                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_PARAVIRT_SPINLOCKS                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_KVM_DEBUG_FS                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_LGUEST_GUEST                             policy<{'i386': 'n'}>
+CONFIG_PARAVIRT_TIME_ACCOUNTING                 policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: Processor type and features >> Linux guest support >> Enable paravirtualization code >> Xen guest support
+
+# Menu: Processor type and features >> Linux guest support >> Enable paravirtualization code >> Xen guest support >> Architecture: x86
+CONFIG_XEN_512GB                                policy<{'amd64': 'y'}>
+CONFIG_XEN_DEBUG_FS                             policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_XEN_PVH                                  policy<{'amd64': 'y'}>
+#
+CONFIG_XEN_512GB				flag<REVIEW> note<Q: is this related to the utlemming questions on memory size?>
+
+# Menu: Processor type and features >> Machine Check / overheating reporting >> Architecture: x86
+CONFIG_X86_MCE                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MCE_INTEL                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MCE_AMD                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_ANCIENT_MCE                          policy<{'i386': 'n'}>
+CONFIG_X86_MCE_INJECT                           policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Processor type and features >> Math emulation options >> Architecture: powerpc
+CONFIG_MATH_EMULATION_FULL                      policy<{'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_MATH_EMULATION_HW_UNIMPLEMENTED          policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+
+# Menu: Processor type and features >> Memory model
+CONFIG_FLATMEM_MANUAL                           policy<{'i386': 'n', 'powerpc-powerpc64-emb': 'n'}>
+CONFIG_SPARSEMEM_MANUAL                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Processor type and features >> Memory split
+CONFIG_VMSPLIT_3G                               policy<{'armhf': 'y', 'i386': 'y'}>
+CONFIG_VMSPLIT_3G_OPT                           policy<{'armhf': 'n'}>
+CONFIG_VMSPLIT_2G                               policy<{'armhf': 'n', 'i386': 'n'}>
+CONFIG_VMSPLIT_1G                               policy<{'armhf': 'n', 'i386': 'n'}>
+
+# Menu: Processor type and features >> Memory split >> Architecture: arm
+
+# Menu: Processor type and features >> Memory split >> Architecture: x86
+
+# Menu: Processor type and features >> Page size >> Architecture: arm64
+CONFIG_ARM64_4K_PAGES                           policy<{'arm64': 'y'}>
+CONFIG_ARM64_16K_PAGES                          policy<{'arm64': 'n'}>
+CONFIG_ARM64_64K_PAGES                          policy<{'arm64': 'n'}>
+
+# Menu: Processor type and features >> Page size >> Architecture: powerpc
+CONFIG_PPC_4K_PAGES                             policy<{'powerpc': 'y', 'ppc64el': 'n'}>
+CONFIG_PPC_64K_PAGES                            policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'y'}>
+
+# Menu: Processor type and features >> Preemption Model
+CONFIG_PREEMPT_NONE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_PREEMPT_VOLUNTARY                        policy<{'amd64-generic': 'y', 'amd64-lowlatency': 'n', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'i386-lowlatency': 'n', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PREEMPT                                  policy<{'amd64-generic': 'n', 'amd64-lowlatency': 'y', 'arm64': 'n', 'armhf': 'n', 'i386-generic': 'n', 'i386-lowlatency': 'y', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Processor type and features >> Processor family
+
+# Menu: Processor type and features >> Processor family >> Architecture: x86
+CONFIG_M486                                     policy<{'i386': 'n'}>
+CONFIG_M586                                     policy<{'i386': 'n'}>
+CONFIG_M586TSC                                  policy<{'i386': 'n'}>
+CONFIG_M586MMX                                  policy<{'i386': 'n'}>
+CONFIG_M686                                     policy<{'i386': 'y'}>
+CONFIG_MPENTIUMII                               policy<{'i386': 'n'}>
+CONFIG_MPENTIUMIII                              policy<{'i386': 'n'}>
+CONFIG_MPENTIUMM                                policy<{'i386': 'n'}>
+CONFIG_MPENTIUM4                                policy<{'i386': 'n'}>
+CONFIG_MK6                                      policy<{'i386': 'n'}>
+CONFIG_MK7                                      policy<{'i386': 'n'}>
+CONFIG_MK8                                      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_MCRUSOE                                  policy<{'i386': 'n'}>
+CONFIG_MEFFICEON                                policy<{'i386': 'n'}>
+CONFIG_MWINCHIPC6                               policy<{'i386': 'n'}>
+CONFIG_MWINCHIP3D                               policy<{'i386': 'n'}>
+CONFIG_MELAN                                    policy<{'i386': 'n'}>
+CONFIG_MGEODEGX1                                policy<{'i386': 'n'}>
+CONFIG_MGEODE_LX                                policy<{'i386': 'n'}>
+CONFIG_MCYRIXIII                                policy<{'i386': 'n'}>
+CONFIG_MVIAC3_2                                 policy<{'i386': 'n'}>
+CONFIG_MVIAC7                                   policy<{'i386': 'n'}>
+CONFIG_MPSC                                     policy<{'amd64': 'n'}>
+CONFIG_MCORE2                                   policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_MATOM                                    policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: Processor type and features >> Processor type >> Architecture: s390
+CONFIG_MARCH_Z900                               policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z990                               policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z9_109                             policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z10                                policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z196                               policy<{'s390x': 'n'}>
+CONFIG_MARCH_ZEC12                              policy<{'s390x': 'y'}>
+CONFIG_MARCH_Z13                                policy<{'s390x': 'n'}>
+
+# Menu: Processor type and features >> Support for extended (non-PC) x86 platforms >> Architecture: x86
+CONFIG_X86_NUMACHIP                             policy<{'amd64': 'y'}>
+CONFIG_X86_VSMP                                 policy<{'amd64': 'n'}>
+CONFIG_X86_UV                                   policy<{'amd64': 'n'}>
+CONFIG_X86_GOLDFISH                             policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_INTEL_MID                            policy<{'i386': 'y'}>
+CONFIG_X86_INTEL_QUARK                          policy<{'i386': 'n'}>
+CONFIG_X86_RDC321X                              policy<{'i386': 'n'}>
+CONFIG_X86_32_NON_STANDARD                      policy<{'i386': 'n'}>
+CONFIG_APB_TIMER                                policy<{'i386': 'y'}>
+
+# Menu: Processor type and features >> Supported processor vendors >> Architecture: x86
+CONFIG_PROCESSOR_SELECT                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SUP_INTEL                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SUP_CYRIX_32                         policy<{'i386': 'y'}>
+CONFIG_CPU_SUP_AMD                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SUP_CENTAUR                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SUP_TRANSMETA_32                     policy<{'i386': 'y'}>
+CONFIG_CPU_SUP_UMC_32                           policy<{'i386': 'y'}>
+
+# Menu: Processor type and features >> Symmetric Multi-Processing
+
+# Menu: Processor type and features >> Symmetric Multi-Processing >> Architecture: arm
+CONFIG_SMP_ON_UP                                policy<{'armhf': 'y'}>
+CONFIG_ARM_CPU_TOPOLOGY                         policy<{'armhf': 'y'}>
+CONFIG_MCPM                                     policy<{'armhf': 'y'}>
+CONFIG_BIG_LITTLE                               policy<{'armhf': 'y'}>
+CONFIG_BL_SWITCHER                              policy<{'armhf': 'y'}>
+CONFIG_BL_SWITCHER_DUMMY_IF                     policy<{'armhf': 'm'}>
+
+# Menu: Processor type and features >> Symmetric multi-processing support
+
+# Menu: Processor type and features >> Symmetric multi-processing support >> Architecture: s390
+CONFIG_SCHED_TOPOLOGY                           policy<{'s390x': 'y'}>
+
+# Menu: Processor type and features >> Symmetric multi-processing support >> Architecture: x86
+CONFIG_X86_BIGSMP                               policy<{'i386': 'n'}>
+CONFIG_MAXSMP                                   policy<{'amd64': 'n'}>
+
+# Menu: Processor type and features >> Symmetric multi-processing support >> Numa Memory Allocation and Scheduler Support
+CONFIG_NUMA_EMU                                 policy<{'amd64': 'n', 's390x': 'y'}>
+#
+CONFIG_NUMA_EMU                                 note<LP:1557690>
+
+# Menu: Processor type and features >> Symmetric multi-processing support >> Numa Memory Allocation and Scheduler Support >> Architecture: x86
+CONFIG_AMD_NUMA                                 policy<{'amd64': 'y'}>
+CONFIG_X86_64_ACPI_NUMA                         policy<{'amd64': 'y'}>
+
+# Menu: Processor type and features >> Symmetric multi-processing support >> Select NUMA modes
+#
+
+# Menu: Processor type and features >> Symmetric multi-processing support >> Select NUMA modes >> Architecture: s390
+CONFIG_EMU_SIZE                                 policy<{'s390x': '0x10000000'}>
+
+# Menu: Processor type and features >> TSX enable mode >> Architecture: x86
+CONFIG_X86_INTEL_TSX_MODE_OFF                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_INTEL_TSX_MODE_ON                    policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_INTEL_TSX_MODE_AUTO                  policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: Processor type and features >> Timer frequency
+CONFIG_HZ_100                                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_HZ_250                                   policy<{'amd64-generic': 'y', 'amd64-lowlatency': 'n', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'i386-lowlatency': 'n', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HZ_300                                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HZ_1000                                  policy<{'amd64-generic': 'n', 'amd64-lowlatency': 'y', 'arm64': 'n', 'armhf': 'n', 'i386-generic': 'n', 'i386-lowlatency': 'y', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Processor type and features >> Timer frequency >> Architecture: arm
+CONFIG_HZ_200                                   policy<{'armhf': 'n'}>
+CONFIG_HZ_500                                   policy<{'armhf': 'n'}>
+
+# Menu: Processor type and features >> Transparent Hugepage Support sysfs defaults
+CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS              policy<{'amd64': 'n', 'arm64': 'n', 'armhf-generic-lpae': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TRANSPARENT_HUGEPAGE_MADVISE             policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Processor type and features >> Tune code generation >> Architecture: s390
+CONFIG_TUNE_DEFAULT                             policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z900                                policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z990                                policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z9_109                              policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z10                                 policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z196                                policy<{'s390x': 'n'}>
+CONFIG_TUNE_ZEC12                               policy<{'s390x': 'y'}>
+CONFIG_TUNE_Z13                                 policy<{'s390x': 'n'}>
+
+# Menu: Processor type and features >> Virtual address space size >> Architecture: arm64
+CONFIG_ARM64_VA_BITS_39                         policy<{'arm64': 'n'}>
+CONFIG_ARM64_VA_BITS_48                         policy<{'arm64': 'y'}>
+#
+CONFIG_ARM64_VA_BITS_48                         mark<ENFORCED> note<Cavium ThunderX 2-socket needs a minimum of 41 bits of VA>
+
+# Menu: Processor type and features >> vsyscall table for legacy applications >> Architecture: x86
+CONFIG_LEGACY_VSYSCALL_NATIVE                   policy<{'amd64': 'n'}>
+CONFIG_LEGACY_VSYSCALL_EMULATE                  policy<{'amd64': 'y'}>
+CONFIG_LEGACY_VSYSCALL_NONE                     policy<{'amd64': 'n'}>
+
+# Menu: Security options
+CONFIG_SECURITY_DMESG_RESTRICT                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PAGE_TABLE_ISOLATION                     policy<{'amd64': 'y'}>
+CONFIG_SECURITYFS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEL_TXT                                policy<{'amd64': 'y', 'i386': 'y'}>
+
+# Menu: Security options >> Default security module
+CONFIG_DEFAULT_SECURITY_SELINUX                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_SECURITY_SMACK                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_SECURITY_TOMOYO                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_SECURITY_APPARMOR                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEFAULT_SECURITY_DAC                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_DEFAULT_SECURITY_APPARMOR                mark<ENFORCED>
+
+# Menu: Security options >> Enable access key retention support
+CONFIG_KEYS                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PERSISTENT_KEYRINGS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BIG_KEYS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRUSTED_KEYS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ENCRYPTED_KEYS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Security options >> Enable different security models
+CONFIG_SECURITY                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_NETWORK                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_NETWORK_XFRM                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_PATH                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LSM_MMAP_MIN_ADDR                        policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_SECURITY_SMACK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SMACK_BRINGUP                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_SMACK_NETFILTER                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_YAMA                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+#
+CONFIG_SECURITY                                 mark<ENFORCED>
+CONFIG_LSM_MMAP_MIN_ADDR                        mark<ENFORCED> flag<REVIEW>
+CONFIG_SECURITY_SMACK                           mark<ENFORCED>
+CONFIG_SECURITY_YAMA                            mark<ENFORCED>
+
+# Menu: Security options >> Enable different security models >> AppArmor support
+CONFIG_SECURITY_APPARMOR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE        policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'powerpc': '1', 'ppc64el': '1', 's390x': '1'}>
+CONFIG_SECURITY_APPARMOR_STATS                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_APPARMOR_UNCONFINED_INIT        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_APPARMOR_HASH                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_APPARMOR_HASH_DEFAULT           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Security options >> Enable different security models >> Integrity subsystem
+CONFIG_INTEGRITY                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEGRITY_SIGNATURE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEGRITY_ASYMMETRIC_KEYS                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEGRITY_AUDIT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVM                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVM_ATTR_FSUUID                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVM_EXTRA_SMACK_XATTRS                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+
+# Menu: Security options >> Enable different security models >> Integrity subsystem >> Integrity Measurement Architecture(IMA)
+CONFIG_IMA                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_APPRAISE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_TRUSTED_KEYRING                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_MOK_KEYRING                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_LOAD_X509                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Security options >> Enable different security models >> Integrity subsystem >> Integrity Measurement Architecture(IMA) >> Default integrity hash algorithm
+CONFIG_IMA_DEFAULT_HASH_SHA1                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_DEFAULT_HASH_SHA256                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_DEFAULT_HASH_SHA512                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_DEFAULT_HASH_WP512                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Security options >> Enable different security models >> Integrity subsystem >> Integrity Measurement Architecture(IMA) >> Default template
+CONFIG_IMA_TEMPLATE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_NG_TEMPLATE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc-powerpc64-smp': 'y', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_SIG_TEMPLATE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc-powerpc64-smp': 'n', 'powerpc-powerpc-e500mc': 'n', 'powerpc-powerpc-smp': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+
+# Menu: Security options >> Enable different security models >> NSA SELinux Support
+CONFIG_SECURITY_SELINUX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SELINUX_BOOTPARAM               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE         policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'powerpc': '0', 'ppc64el': '0'}>
+CONFIG_SECURITY_SELINUX_DISABLE                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SECURITY_SELINUX_DEVELOP                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SELINUX_AVC_STATS               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE      policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'powerpc': '1', 'ppc64el': '1', 's390x': '1'}>
+CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+#
+CONFIG_SECURITY_SELINUX                         mark<ENFORCED>
+
+# Menu: Security options >> Enable different security models >> TOMOYO Linux Support
+CONFIG_SECURITY_TOMOYO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY         policy<{'amd64': '2048', 'arm64': '2048', 'armhf': '2048', 'i386': '2048', 'powerpc': '2048', 'ppc64el': '2048', 's390x': '2048'}>
+CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG            policy<{'amd64': '1024', 'arm64': '1024', 'armhf': '1024', 'i386': '1024', 'powerpc': '1024', 'ppc64el': '1024', 's390x': '1024'}>
+CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_TOMOYO_POLICY_LOADER            policy<{'amd64': '"/sbin/tomoyo-init"', 'arm64': '"/sbin/tomoyo-init"', 'armhf': '"/sbin/tomoyo-init"', 'i386': '"/sbin/tomoyo-init"', 'powerpc': '"/sbin/tomoyo-init"', 'ppc64el': '"/sbin/tomoyo-init"', 's390x': '"/sbin/tomoyo-init"'}>
+CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER       policy<{'amd64': '"/sbin/init"', 'arm64': '"/sbin/init"', 'armhf': '"/sbin/init"', 'i386': '"/sbin/init"', 'powerpc': '"/sbin/init"', 'ppc64el': '"/sbin/init"', 's390x': '"/sbin/init"'}>
+
+# Menu: System Type
+#
+
+# Menu: System Type >> ARM Ltd. Versatile Express family
+
+# Menu: System Type >> ARM Ltd. Versatile Express family >> Architecture: arm
+CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA        policy<{'armhf': 'y'}>
+CONFIG_ARCH_VEXPRESS_DCSCB                      policy<{'armhf': 'y'}>
+CONFIG_ARCH_VEXPRESS_SPC                        policy<{'armhf': 'y'}>
+CONFIG_ARCH_VEXPRESS_TC2_PM                     policy<{'armhf': 'y'}>
+
+# Menu: System Type >> ARM system type >> Architecture: arm
+CONFIG_ARCH_MULTIPLATFORM                       policy<{'armhf': 'y'}>
+CONFIG_ARCH_REALVIEW                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_VERSATILE                           policy<{'armhf': 'n'}>
+CONFIG_ARCH_CLPS711X                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_GEMINI                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_EBSA110                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_EP93XX                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_FOOTBRIDGE                          policy<{'armhf': 'n'}>
+CONFIG_ARCH_NETX                                policy<{'armhf': 'n'}>
+CONFIG_ARCH_IOP13XX                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_IOP32X                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_IOP33X                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_IXP4XX                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_DOVE                                policy<{'armhf': 'n'}>
+CONFIG_ARCH_MV78XX0                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_ORION5X                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_MMP                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_KS8695                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_W90X900                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_LPC32XX                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_PXA                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_RPC                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_SA1100                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_S3C24XX                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_S3C64XX                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_DAVINCI                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_OMAP1                               policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Allwinner SoCs >> Architecture: arm
+CONFIG_ARCH_SUNXI                               policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Altera SOCFPGA family >> Architecture: arm
+CONFIG_ARCH_SOCFPGA                             policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Amlogic Meson SoCs >> Architecture: arm
+CONFIG_ARCH_MESON                               policy<{'armhf': 'y'}>
+CONFIG_MACH_MESON6                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MESON8                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MESON8B                             policy<{'armhf': 'y'}>
+
+# Menu: System Type >> Architecture: arm
+CONFIG_ARCH_VIRT                                policy<{'armhf': 'y'}>
+CONFIG_ARCH_ALPINE                              policy<{'armhf': 'y'}>
+CONFIG_ARCH_AXXIA                               policy<{'armhf-generic-lpae': 'y'}>
+CONFIG_ARCH_DIGICOLOR                           policy<{'armhf': 'n'}>
+CONFIG_ARCH_HIGHBANK                            policy<{'armhf': 'y'}>
+CONFIG_ARCH_KEYSTONE                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_S5PV210                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_UNIPHIER                            policy<{'armhf': 'y'}>
+CONFIG_ARCH_WM8850                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_ZX                                  policy<{'armhf': 'n'}>
+CONFIG_ARCH_ZYNQ                                policy<{'armhf': 'n'}>
+CONFIG_ARM_THUMB                                policy<{'armhf': 'y'}>
+CONFIG_HARDEN_BRANCH_PREDICTOR                  policy<{'armhf': 'y'}>
+CONFIG_CACHE_FEROCEON_L2                        policy<{'armhf': 'y'}>
+CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH           policy<{'armhf': 'n'}>
+CONFIG_CACHE_TAUROS2                            policy<{'armhf': 'y'}>
+CONFIG_CACHE_UNIPHIER                           policy<{'armhf': 'y'}>
+CONFIG_IWMMXT                                   policy<{'armhf': 'y'}>
+CONFIG_PJ4B_ERRATA_4742                         policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_430973                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_643719                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_720789                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_754322                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_754327                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_764369                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_775420                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_798181                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_773022                        policy<{'armhf': 'y'}>
+
+# Menu: System Type >> Atmel SoCs >> Architecture: arm
+CONFIG_ARCH_AT91                                policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Broadcom SoC Support >> Architecture: arm
+CONFIG_ARCH_BCM                                 policy<{'armhf': 'n'}>
+
+# Menu: System Type >> CLPS711X/EP721X/EP731X Implementations >> Architecture: arm
+
+# Menu: System Type >> CSR SiRF >> Architecture: arm
+CONFIG_ARCH_SIRF                                policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Cavium Networks CNS3XXX family >> Architecture: arm
+
+# Menu: System Type >> Cirrus EP93xx Implementation Options >> Architecture: arm
+
+# Menu: System Type >> Cortina Systems Gemini Implementations >> Architecture: arm
+
+# Menu: System Type >> Enable the L2x0 outer cache controller >> Architecture: arm
+CONFIG_CACHE_L2X0                               policy<{'armhf': 'y'}>
+CONFIG_PL310_ERRATA_588369                      policy<{'armhf': 'y'}>
+CONFIG_PL310_ERRATA_727915                      policy<{'armhf': 'y'}>
+CONFIG_PL310_ERRATA_753970                      policy<{'armhf': 'y'}>
+CONFIG_PL310_ERRATA_769419                      policy<{'armhf': 'y'}>
+
+# Menu: System Type >> Firmware options >> Architecture: arm
+CONFIG_TRUSTED_FOUNDATIONS                      policy<{'armhf-generic': 'y'}>
+
+# Menu: System Type >> Footbridge Implementations >> Architecture: arm
+
+# Menu: System Type >> Freescale i.MX family >> Architecture: arm
+CONFIG_ARCH_MXC                                 policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_SOC_IMX50                                policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX51                                policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX53                                policy<{'armhf-generic': 'n'}>
+CONFIG_SOC_IMX6Q                                policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX6SL                               policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX6SX                               policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX6UL                               policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX7D                                policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_LS1021A                              policy<{'armhf-generic': 'n'}>
+CONFIG_SOC_VF610                                policy<{'armhf-generic': 'y'}>
+
+# Menu: System Type >> Freescale i.MX family >> Clocksource for scheduler clock >> Architecture: arm
+CONFIG_VF_USE_ARM_GLOBAL_TIMER                  policy<{'armhf-generic': 'y'}>
+CONFIG_VF_USE_PIT_TIMER                         policy<{'armhf-generic': 'n'}>
+
+# Menu: System Type >> Hisilicon platform type >> Architecture: arm
+CONFIG_ARCH_HI3xxx                              policy<{'armhf': 'y'}>
+CONFIG_ARCH_HIP01                               policy<{'armhf': 'n'}>
+CONFIG_ARCH_HIP04                               policy<{'armhf': 'y'}>
+CONFIG_ARCH_HIX5HD2                             policy<{'armhf': 'y'}>
+
+# Menu: System Type >> IOP13XX Implementation Options >> Architecture: arm
+
+# Menu: System Type >> IOP32x Implementation Options >> Architecture: arm
+
+# Menu: System Type >> IOP33x Implementation Options >> Architecture: arm
+
+# Menu: System Type >> Integrator Options >> Architecture: arm
+
+# Menu: System Type >> Intel IXP4xx Implementation Options >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> Gumstix Carrier/Expansion Board >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> Motorola EZX Platform >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> PXA based Keith und Koep Trizeps DIMM-Modules >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> PXA based Keith und Koep Trizeps DIMM-Modules >> Select base board for Trizeps module >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> PXA based Palm PDAs >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> PXA based Toshiba e-series PDAs >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models >> Architecture: arm
+
+# Menu: System Type >> Intel PXA2xx/PXA3xx Implementations >> display on pcm990 >> Architecture: arm
+
+# Menu: System Type >> Kendin/Micrel KS8695 Implementations >> Architecture: arm
+
+# Menu: System Type >> MMU-based Paged Memory Management Support
+#
+
+# Menu: System Type >> MMU-based Paged Memory Management Support >> Architecture: arm
+CONFIG_MMU                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARM_LPAE                                 policy<{'armhf-generic': 'n', 'armhf-generic-lpae': 'y'}>
+CONFIG_CPU_ICACHE_DISABLE                       policy<{'armhf': 'n'}>
+CONFIG_KUSER_HELPERS                            policy<{'armhf': 'y'}>
+CONFIG_ARM_KERNMEM_PERMS                        policy<{'armhf': 'y'}>
+#
+CONFIG_ARM_KERNMEM_PERMS                        flag<REVIEW>
+
+# Menu: System Type >> MMU-based Paged Memory Management Support >> Renesas ARM SoCs >> Architecture: arm
+CONFIG_ARCH_R8A7778                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7779                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_SHMOBILE_MULTI                      policy<{'armhf': 'y'}>
+CONFIG_ARCH_EMEV2                               policy<{'armhf': 'y'}>
+CONFIG_ARCH_R7S72100                            policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A73A4                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_R8A7740                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7790                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7791                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7793                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7794                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_SH73A0                              policy<{'armhf': 'y'}>
+#
+CONFIG_ARCH_R8A73A4                             flag<REVIEW>
+
+# Menu: System Type >> MMU-based Paged Memory Management Support >> ST-Ericsson U300 Series >> Architecture: arm
+
+# Menu: System Type >> MMU-based Paged Memory Management Support >> ST-Ericsson U8500 Series >> Architecture: arm
+CONFIG_ARCH_U8500                               policy<{'armhf': 'n'}>
+
+# Menu: System Type >> MMU-based Paged Memory Management Support >> Set flash/sdram size and base addr >> Architecture: arm
+
+# Menu: System Type >> MOXA ART SoC >> Architecture: arm
+
+# Menu: System Type >> Marvell Berlin SoCs
+
+# Menu: System Type >> Marvell Berlin SoCs >> Architecture: arm
+CONFIG_MACH_BERLIN_BG2                          policy<{'armhf': 'y'}>
+CONFIG_MACH_BERLIN_BG2CD                        policy<{'armhf': 'y'}>
+CONFIG_MACH_BERLIN_BG2Q                         policy<{'armhf': 'y'}>
+
+# Menu: System Type >> Marvell Dove Implementations >> Architecture: arm
+
+# Menu: System Type >> Marvell Engineering Business Unit (MVEBU) SoCs >> Architecture: arm
+CONFIG_ARCH_MVEBU                               policy<{'armhf': 'y'}>
+CONFIG_MACH_ARMADA_370                          policy<{'armhf': 'y'}>
+CONFIG_MACH_ARMADA_375                          policy<{'armhf': 'y'}>
+CONFIG_MACH_ARMADA_38X                          policy<{'armhf': 'y'}>
+CONFIG_MACH_ARMADA_39X                          policy<{'armhf': 'y'}>
+CONFIG_MACH_ARMADA_XP                           policy<{'armhf': 'y'}>
+CONFIG_MACH_DOVE                                policy<{'armhf': 'y'}>
+
+# Menu: System Type >> Marvell MV78xx0 Implementations >> Architecture: arm
+
+# Menu: System Type >> Marvell PXA168/910/MMP2 Implmentations >> Architecture: arm
+
+# Menu: System Type >> Mediatek MT65xx & MT81xx SoC
+
+# Menu: System Type >> Mediatek MT65xx & MT81xx SoC >> Architecture: arm
+CONFIG_MACH_MT6589                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT6592                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT8127                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT8135                              policy<{'armhf': 'y'}>
+
+# Menu: System Type >> Multiple platform selection >> Architecture: arm
+CONFIG_ARCH_MULTI_V6                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_MULTI_V7                            policy<{'armhf': 'y'}>
+
+# Menu: System Type >> NUC950 Machines >> Architecture: arm
+
+# Menu: System Type >> NUC960 Machines >> Architecture: arm
+
+# Menu: System Type >> NVIDIA Tegra
+
+# Menu: System Type >> NVIDIA Tegra >> Architecture: arm
+CONFIG_ARCH_TEGRA_2x_SOC                        policy<{'armhf-generic': 'y'}>
+CONFIG_ARCH_TEGRA_3x_SOC                        policy<{'armhf-generic': 'y'}>
+CONFIG_ARCH_TEGRA_114_SOC                       policy<{'armhf-generic': 'y'}>
+CONFIG_ARCH_TEGRA_124_SOC                       policy<{'armhf-generic': 'y'}>
+
+# Menu: System Type >> NetX Implementations >> Architecture: arm
+
+# Menu: System Type >> Orion Implementations >> Architecture: arm
+
+# Menu: System Type >> Qualcomm Support
+
+# Menu: System Type >> Qualcomm Support >> Architecture: arm
+CONFIG_ARCH_MSM8X60                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_MSM8960                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_MSM8974                             policy<{'armhf': 'y'}>
+
+# Menu: System Type >> RealView platform type >> Architecture: arm
+
+# Menu: System Type >> SA11x0 Implementations >> Architecture: arm
+
+# Menu: System Type >> SA11x0 Implementations >> Cerf Flash available >> Architecture: arm
+
+# Menu: System Type >> SAMSUNG S3C24XX SoCs Support >> Architecture: arm
+
+# Menu: System Type >> SAMSUNG S3C24XX SoCs Support >> SAMSUNG S3C2410 >> Architecture: arm
+
+# Menu: System Type >> SAMSUNG S3C24XX SoCs Support >> SAMSUNG S3C2412 >> Architecture: arm
+
+# Menu: System Type >> SAMSUNG S3C24XX SoCs Support >> SAMSUNG S3C2440 >> Architecture: arm
+
+# Menu: System Type >> SMDK6410 >> Architecture: arm
+
+# Menu: System Type >> SMDK6410 >> SMDK6410 MMC/SD slot setup >> Architecture: arm
+
+# Menu: System Type >> ST SPEAr Family >> Architecture: arm
+CONFIG_PLAT_SPEAR                               policy<{'armhf': 'n'}>
+
+# Menu: System Type >> ST SPEAr Family >> ST SPEAr13xx >> Architecture: arm
+
+# Menu: System Type >> ST SPEAr Family >> ST SPEAr13xx >> ST SPEAr3xx >> Architecture: arm
+
+# Menu: System Type >> ST-Ericsson Nomadik >> Architecture: arm
+
+# Menu: System Type >> STMicroelectronics Consumer Electronics SOCs >> Architecture: arm
+CONFIG_ARCH_STI                                 policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Samsung Common options >> Architecture: arm
+CONFIG_SAMSUNG_PM_CHECK                         policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Samsung EXYNOS >> Architecture: arm
+CONFIG_ARCH_EXYNOS                              policy<{'armhf': 'y'}>
+CONFIG_ARCH_EXYNOS3                             policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Samsung EXYNOS >> SAMSUNG EXYNOS4 >> Architecture: arm
+CONFIG_ARCH_EXYNOS4                             policy<{'armhf': 'n'}>
+
+# Menu: System Type >> Samsung EXYNOS >> SAMSUNG EXYNOS5 >> Architecture: arm
+CONFIG_ARCH_EXYNOS5                             policy<{'armhf': 'y'}>
+CONFIG_SOC_EXYNOS5250                           policy<{'armhf': 'y'}>
+CONFIG_SOC_EXYNOS5260                           policy<{'armhf': 'y'}>
+CONFIG_SOC_EXYNOS5410                           policy<{'armhf': 'y'}>
+CONFIG_SOC_EXYNOS5420                           policy<{'armhf': 'y'}>
+CONFIG_SOC_EXYNOS5440                           policy<{'armhf': 'y'}>
+CONFIG_SOC_EXYNOS5800                           policy<{'armhf': 'y'}>
+CONFIG_EXYNOS5420_MCPM                          policy<{'armhf': 'y'}>
+
+# Menu: System Type >> Support ARM V7 processor >> Architecture: arm
+CONFIG_CPU_V7                                   policy<{'armhf': 'y'}>
+CONFIG_ARM_THUMBEE                              policy<{'armhf': 'y'}>
+CONFIG_SWP_EMULATE                              policy<{'armhf': 'y'}>
+CONFIG_CPU_BPREDICT_DISABLE                     policy<{'armhf': 'n'}>
+CONFIG_VDSO                                     policy<{'armhf': 'y'}>
+CONFIG_ARM_DMA_MEM_BUFFERABLE                   policy<{'armhf': 'y'}>
+
+# Menu: System Type >> TI DaVinci Implementations >> Architecture: arm
+
+# Menu: System Type >> TI DaVinci Implementations >> DA850/OMAP-L138/AM18x based system >> Architecture: arm
+
+# Menu: System Type >> TI DaVinci Implementations >> DA850/OMAP-L138/AM18x based system >> Select peripherals connected to expander on UI board >> Architecture: arm
+
+# Menu: System Type >> TI DaVinci Implementations >> DaVinci 644x based system >> Architecture: arm
+
+# Menu: System Type >> TI DaVinci Implementations >> Select DA830/OMAP-L137/AM17x UI board peripheral >> Architecture: arm
+
+# Menu: System Type >> TI OMAP Common Features >> Architecture: arm
+CONFIG_POWER_AVS_OMAP                           policy<{'armhf-generic': 'y'}>
+CONFIG_POWER_AVS_OMAP_CLASS3                    policy<{'armhf-generic': 'y'}>
+CONFIG_OMAP_RESET_CLOCKS                        policy<{'armhf': 'y'}>
+CONFIG_OMAP_32K_TIMER                           policy<{'armhf': 'y'}>
+CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE         policy<{'armhf-generic': 'n'}>
+CONFIG_OMAP_DM_TIMER                            policy<{'armhf': 'y'}>
+
+# Menu: System Type >> TI OMAP Common Features >> OMAP PM layer selection >> Architecture: arm
+CONFIG_OMAP_PM_NOOP                             policy<{'armhf': 'y'}>
+
+# Menu: System Type >> TI OMAP Common Features >> OMAP multiplexing support >> Architecture: arm
+CONFIG_OMAP_MUX                                 policy<{'armhf': 'y'}>
+CONFIG_OMAP_MUX_DEBUG                           policy<{'armhf': 'n'}>
+CONFIG_OMAP_MUX_WARNINGS                        policy<{'armhf': 'y'}>
+
+# Menu: System Type >> TI OMAP/AM/DM/DRA Family >> Architecture: arm
+CONFIG_ARCH_OMAP3                               policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_ARCH_OMAP4                               policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_SOC_OMAP5                                policy<{'armhf': 'n'}>
+CONFIG_SOC_AM33XX                               policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_SOC_AM43XX                               policy<{'armhf': 'n'}>
+CONFIG_SOC_DRA7XX                               policy<{'armhf': 'y'}>
+
+# Menu: System Type >> TI OMAP/AM/DM/DRA Family >> TI OMAP2/3/4 Specific Features >> Architecture: arm
+CONFIG_ARCH_OMAP2PLUS_TYPICAL                   policy<{'armhf': 'y'}>
+CONFIG_SOC_HAS_OMAP2_SDRC                       policy<{'armhf': 'y'}>
+CONFIG_SOC_HAS_REALTIME_COUNTER                 policy<{'armhf': 'y'}>
+CONFIG_SOC_OMAP3430                             policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_TI81XX                               policy<{'armhf-generic': 'y'}>
+CONFIG_MACH_OMAP_LDP                            policy<{'armhf-generic': 'y'}>
+CONFIG_MACH_OMAP3517EVM                         policy<{'armhf-generic': 'n'}>
+CONFIG_MACH_OMAP3_PANDORA                       policy<{'armhf-generic': 'y'}>
+CONFIG_MACH_NOKIA_RX51                          policy<{'armhf-generic': 'n'}>
+CONFIG_OMAP3_SDRC_AC_TIMING                     policy<{'armhf-generic': 'n'}>
+
+# Menu: System Type >> TI OMAP1 specific features >> Architecture: arm
+
+# Menu: System Type >> TI OMAP1 specific features >> OMAP15xx Based System >> Architecture: arm
+
+# Menu: System Type >> TI OMAP1 specific features >> OMAP16xx Based System >> Architecture: arm
+CONFIG_MACH_OMAP_GENERIC                        policy<{'armhf': 'y'}>
+
+# Menu: System Type >> Versatile platform type >> Architecture: arm
+
+# Menu: System Type >> W90P910 Machines >> Architecture: arm
+
+# Menu: Ubuntu Supplied Third-Party Device Drivers
+CONFIG_DRM_I915_BPO                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DRM_I915_BPO_PRELIMINARY_HW_SUPPORT      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_BPO_USERPTR                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HIO                                      policy<{'amd64': 'm', 'arm64': 'n', 'armhf': 'n', 'i386': 'm', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_WLAN_VENDOR_RSI                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_BNXT_BPO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_BNXT_BPO_SRIOV                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_BNXT_BPO_DCB                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
+CONFIG_CAN_HMS_USB                              policy<{'amd64': 'm', 'i386': 'm'}>
+
+# Menu: Ubuntu Supplied Third-Party Device Drivers >> OpenNSL options
+CONFIG_OPENNSL                                  policy<{'amd64-generic': 'y', 'amd64-lowlatency': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'powerpc': 'n', 'ppc64el': 'n'}>
+CONFIG_OPENNSL_KERNEL_BDE                       policy<{'amd64-generic': 'm'}>
+CONFIG_OPENNSL_BCM_KNET                         policy<{'amd64-generic': 'm'}>
+CONFIG_OPENNSL_USER_BDE                         policy<{'amd64-generic': 'm'}>
+
+# Menu: Ubuntu Supplied Third-Party Device Drivers >> Redpine Signals Inc 91x WLAN driver support
+CONFIG_VEN_RSI_91X                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VEN_RSI_DEBUGFS                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VEN_RSI_SDIO                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VEN_RSI_USB                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VEN_RSI_BT_ALONE                         policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_VEN_RSI_COEX                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VEN_RSI_WOW                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VEN_RSI_P2P                              policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_HW_SCAN_OFFLOAD                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CARACALLA_BOARD                          policy<{'amd64': 'y', 'i386': 'y'}>
+
+# Menu: Ubuntu Supplied Third-Party Device Drivers >> drm/i915 Debugging
+CONFIG_DRM_I915_BPO_WERROR                      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_BPO_DEBUG                       policy<{'amd64': 'n', 'i386': 'n'}>
+
+# Menu: Virtualization
+CONFIG_VIRTUALIZATION                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KVM                                      policy<{'amd64': 'm', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'm', 'powerpc-powerpc-e500mc': 'y', 'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LGUEST                                   policy<{'i386': 'n'}>
+#
+
+# Menu: Virtualization >> Architecture: powerpc
+CONFIG_KVM_BOOK3S_64                            policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_KVM_BOOK3S_64_HV                         policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_KVM_BOOK3S_64_PR                         policy<{'powerpc-powerpc64-smp': 'm', 'ppc64el': 'm'}>
+CONFIG_KVM_BOOK3S_HV_EXIT_TIMING                policy<{'powerpc-powerpc64-smp': 'n', 'ppc64el': 'n'}>
+CONFIG_KVM_EXIT_TIMING                          policy<{'powerpc-powerpc64-emb': 'n', 'powerpc-powerpc-e500mc': 'n'}>
+CONFIG_KVM_E500MC                               policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_KVM_MPIC                                 policy<{'powerpc-powerpc64-emb': 'y', 'powerpc-powerpc-e500mc': 'y'}>
+CONFIG_KVM_XICS                                 policy<{'powerpc-powerpc64-smp': 'y', 'ppc64el': 'y'}>
+
+# Menu: Virtualization >> Architecture: s390
+CONFIG_PFAULT                                   policy<{'s390x': 'y'}>
+CONFIG_CMM_IUCV                                 policy<{'s390x': 'y'}>
+CONFIG_S390_HYPFS_FS                            policy<{'s390x': 'y'}>
+CONFIG_S390_GUEST                               policy<{'s390x': 'y'}>
+
+# Menu: Virtualization >> KVM
+
+# Menu: Virtualization >> KVM >> Architecture: s390
+CONFIG_KVM_S390_UCONTROL                        policy<{'s390x': 'n'}>
+
+# Menu: Virtualization >> Kernel-based Virtual Machine (KVM) support
+
+# Menu: Virtualization >> Kernel-based Virtual Machine (KVM) support >> Architecture: x86
+CONFIG_KVM_INTEL                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_KVM_AMD                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_KVM_MMU_AUDIT                            policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_KVM_DEVICE_ASSIGNMENT                    policy<{'amd64': 'y', 'i386': 'y'}>
+
+# Menu: Virtualization >> Linux - VM Monitor Stream, base infrastructure >> Architecture: s390
+CONFIG_APPLDATA_BASE                            policy<{'s390x': 'y'}>
+CONFIG_APPLDATA_MEM                             policy<{'s390x': 'm'}>
+CONFIG_APPLDATA_OS                              policy<{'s390x': 'm'}>
+CONFIG_APPLDATA_NET_SUM                         policy<{'s390x': 'm'}>
+
+# Menu: FOOTER
+
+# temporarily disabled options -- build failures.
+#CONFIG_TI_CPSW					p policy<(arch armel armhf &/ value n) | value m> flag<BUILD FAILURE>
+#CONFIG_USB_MUSB_DSPS				p policy<(arch armel armhf &/ value n) | value m> flag<BUILD FAILURE>
+#CONFIG_LIS3L02DQ				p policy<(arch armhf &/ value n) | value m> flag<BUILD FAILURE>
+#CONFIG_EZX_PCAP					p policy<(arch armhf &/ value n) | value y> flag<BUILD FAILURE>
+#CONFIG_TOUCHSCREEN_EGALAX			p policy<(arch armel armhf &/ value n) | value m> flag<BUILD FAILURE> note<FTBS on ti-omap4>
+#CONFIG_TOUCHSCREEN_EETI				p policy<(arch armel armhf &/ value n) | value m> flag<BUILD FAILURE> note<FTBS on ti-omap4>
+#CONFIG_SENSORS_AK8975				p policy<(arch armel armhf &/ value n) | value m> flag<BUILD FAILURE> note<FTBS on ti-omap4>
+#CONFIG_PPC_EPAPR_HV_BYTECHAN			n flag<BUILD FAILURE> note<FTBFS on ppc64el>
--- linux-4.4.0.orig/debian.master/config/arm64/config.common.arm64
+++ linux-4.4.0/debian.master/config/arm64/config.common.arm64
@@ -0,0 +1,362 @@
+#
+# Config options for config.common.arm64 automatically generated by splitconfig.pl
+#
+CONFIG_6LOWPAN=m
+CONFIG_ABX500_CORE=y
+CONFIG_ACPI_REDUCED_HARDWARE_ONLY=y
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_AIX_PARTITION=y
+CONFIG_ALIM7101_WDT=m
+CONFIG_ALTERA_TSE=m
+CONFIG_AMIGA_PARTITION=y
+CONFIG_APPLICOM=m
+CONFIG_ARCNET=m
+CONFIG_ATALK=m
+CONFIG_ATARI_PARTITION=y
+CONFIG_ATA_GENERIC=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_ATA_PIIX=m
+CONFIG_ATM=m
+CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
+CONFIG_AUTOFS4_FS=m
+CONFIG_AUXDISPLAY=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BATMAN_ADV=m
+CONFIG_BCMA=m
+CONFIG_BCM_KONA_USB2_PHY=m
+CONFIG_BE2ISCSI=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_NVME=m
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
+CONFIG_BLK_DEV_RSXX=m
+CONFIG_BLK_DEV_SKD=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BOUNCE=y
+# CONFIG_BPF_JIT_ALWAYS_ON is not set
+CONFIG_BSD_DISKLABEL=y
+CONFIG_C2PORT=m
+CONFIG_CADENCE_WATCHDOG=m
+CONFIG_CAIF=m
+CONFIG_CAN=m
+CONFIG_CB710_CORE=m
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CMA=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_CRAMFS=m
+CONFIG_DECNET=m
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
+CONFIG_DMADEVICES=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+# CONFIG_DM_DEBUG is not set
+CONFIG_DNET=m
+CONFIG_DRM=m
+CONFIG_DUMMY_IRQ=m
+CONFIG_DW_WATCHDOG=m
+CONFIG_ECHO=m
+CONFIG_EEPROM_93CX6=m
+CONFIG_EFS_FS=m
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_ETHOC=m
+CONFIG_EXOFS_FS=m
+CONFIG_EXTCON=y
+CONFIG_F2FS_FS=m
+CONFIG_FB=y
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FDDI=y
+CONFIG_FEALNX=m
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_NOSY=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIXED_PHY=y
+CONFIG_FMC=m
+CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
+CONFIG_GENERIC_PHY=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_BITREVERSE=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HFSPLUS_FS=m
+CONFIG_HFS_FS=m
+# CONFIG_HIO is not set
+CONFIG_HOTPLUG_PCI_SHPC=m
+# CONFIG_HPET is not set
+CONFIG_HPFS_FS=m
+CONFIG_HP_ILO=m
+CONFIG_HSI=m
+CONFIG_HSR=m
+CONFIG_HTC_PASIC3=m
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ_250=y
+CONFIG_I2C=y
+CONFIG_I6300ESB_WDT=m
+CONFIG_IEEE802154=m
+CONFIG_IIO=m
+CONFIG_INFINIBAND_NES=m
+CONFIG_INFINIBAND_OCRDMA=m
+CONFIG_INFINIBAND_QIB=m
+CONFIG_INPUT=y
+CONFIG_IPACK_BUS=m
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_SI_PROBE_DEFAULTS is not set
+CONFIG_IPX=m
+# CONFIG_IP_DCCP_CCID3 is not set
+# CONFIG_IRQ_FORCED_THREADING_DEFAULT is not set
+CONFIG_JFS_FS=m
+CONFIG_JME=m
+CONFIG_KARMA_PARTITION=y
+CONFIG_KVM=y
+CONFIG_LAPB=m
+CONFIG_LDM_PARTITION=y
+CONFIG_LIBNVDIMM=y
+CONFIG_LLC2=m
+CONFIG_LPC_ICH=m
+CONFIG_LPC_SCH=m
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+CONFIG_MAILBOX=y
+CONFIG_MAX63XX_WATCHDOG=m
+CONFIG_MCB=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_SAS=m
+CONFIG_MEMORY=y
+CONFIG_MEMSTICK=m
+CONFIG_MFD_CORE=y
+CONFIG_MFD_JANZ_CMODIO=m
+CONFIG_MFD_KEMPLD=m
+CONFIG_MFD_MT6397=m
+CONFIG_MFD_RDC321X=m
+CONFIG_MFD_RTSX_PCI=m
+CONFIG_MFD_SM501=m
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_TI_AM335X_TSCADC=m
+CONFIG_MFD_VX855=m
+CONFIG_MII=y
+CONFIG_MINIX_FS=m
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MTD=m
+CONFIG_NCP_FS=m
+CONFIG_NET_CADENCE=y
+CONFIG_NET_PACKET_ENGINE=y
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CAVIUM=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_SYNOPSYS=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NEW_LEDS=y
+CONFIG_NFC=m
+CONFIG_NODES_SHIFT=2
+CONFIG_NOZOMI=m
+CONFIG_NR_CPUS=128
+CONFIG_NTB=m
+# CONFIG_NTFS_RW is not set
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
+CONFIG_NVMEM=m
+CONFIG_N_GSM=m
+CONFIG_OF=y
+CONFIG_OMFS_FS=m
+# CONFIG_OPENNSL is not set
+CONFIG_OSF_PARTITION=y
+CONFIG_PARPORT=m
+CONFIG_PATA_SIS=m
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_PCI_PASID=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_PGTABLE_MAPPING=y
+CONFIG_PHANTOM=m
+CONFIG_PHONET=m
+CONFIG_PHYLIB=y
+CONFIG_PHY_PXA_28NM_HSIC=m
+CONFIG_PHY_PXA_28NM_USB2=m
+CONFIG_PM_DEBUG=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_POWERCAP=y
+CONFIG_POWER_AVS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPP=y
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PPS_CLIENT_LDISC=m
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PROBE_EVENTS is not set
+CONFIG_PSTORE=y
+CONFIG_PWM=y
+CONFIG_QNX4FS_FS=m
+CONFIG_QNX6FS_FS=m
+CONFIG_RAW_DRIVER=m
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_REGULATOR=y
+CONFIG_REISERFS_FS=m
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFKILL=y
+CONFIG_ROMFS_FS=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC94XX=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_MVSAS=m
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_SNIC=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_UFSHCD=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_ALTERA_JTAGUART=m
+CONFIG_SERIAL_ALTERA_UART=m
+CONFIG_SERIAL_ARC=m
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_FSL_LPUART=m
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_SCCNXP=y
+CONFIG_SERIO=y
+CONFIG_SFC=m
+CONFIG_SGI_IOC4=m
+CONFIG_SGI_PARTITION=y
+CONFIG_SLIP=m
+CONFIG_SND_SOC_RT5677_SPI=m
+CONFIG_SOC_TI=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_SOUND=m
+CONFIG_SPI=y
+CONFIG_SPMI=m
+CONFIG_SRAM=y
+CONFIG_SSB=m
+CONFIG_STAGING=y
+CONFIG_STANDALONE=y
+CONFIG_STE_MODEM_RPROC=m
+CONFIG_SUN_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_SYSV_FS=m
+CONFIG_THERMAL=y
+CONFIG_THUNDERBOLT=m
+CONFIG_TIFM_CORE=m
+CONFIG_TRACE_SINK=m
+CONFIG_TTY_PRINTK=y
+CONFIG_UFS_FS=m
+CONFIG_UIO=m
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_UPROBES is not set
+CONFIG_USB_EHCI_HCD_PLATFORM=m
+CONFIG_USB_OHCI_HCD_PLATFORM=m
+CONFIG_USB_SUPPORT=y
+CONFIG_UWB=m
+CONFIG_VGASTATE=m
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VME_BUS=y
+CONFIG_VMXNET3=m
+CONFIG_VXFS_FS=m
+CONFIG_W1=m
+CONFIG_WAN=y
+CONFIG_WDTPCI=m
+CONFIG_WIMAX=m
+CONFIG_X25=m
+CONFIG_XILINX_WATCHDOG=m
+CONFIG_XILLYBUS=m
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_XZ_DEC_X86=y
+CONFIG_ZLIB_DEFLATE=y
--- linux-4.4.0.orig/debian.master/config/arm64/config.flavour.generic
+++ linux-4.4.0/debian.master/config/arm64/config.flavour.generic
@@ -0,0 +1,3 @@
+#
+# Config options for config.flavour.generic automatically generated by splitconfig.pl
+#
--- linux-4.4.0.orig/debian.master/config/armhf/config.common.armhf
+++ linux-4.4.0/debian.master/config/armhf/config.common.armhf
@@ -0,0 +1,459 @@
+#
+# Config options for config.common.armhf automatically generated by splitconfig.pl
+#
+CONFIG_6LOWPAN=m
+CONFIG_ABX500_CORE=y
+CONFIG_AC97_BUS=y
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_AIX_PARTITION=y
+CONFIG_ALIM7101_WDT=m
+CONFIG_ALTERA_TSE=m
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_APPLICOM=m
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED=y
+CONFIG_ARCH_ROCKCHIP=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCNET=m
+# CONFIG_ARM_SMMU is not set
+CONFIG_ATALK=m
+CONFIG_ATARI_PARTITION=y
+CONFIG_ATA_GENERIC=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_OVER_ETH=m
+CONFIG_ATA_PIIX=m
+CONFIG_ATM=m
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_AUXDISPLAY=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BATMAN_ADV=m
+CONFIG_BCH=y
+CONFIG_BCMA=m
+CONFIG_BCM_KONA_USB2_PHY=m
+CONFIG_BE2ISCSI=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_NVME=m
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
+CONFIG_BLK_DEV_RSXX=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BOUNCE=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_C2PORT=m
+CONFIG_CADENCE_WATCHDOG=m
+CONFIG_CAIF=m
+CONFIG_CAN=m
+CONFIG_CB710_CORE=m
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CMA=y
+CONFIG_CMDLINE=""
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_CONFIGFS_FS=m
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CRAMFS=m
+CONFIG_CRASH_DUMP=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_IMX=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_LE=y
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_KERNEL_API is not set
+CONFIG_DECNET=m
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
+CONFIG_DMADEVICES=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+# CONFIG_DM_DEBUG is not set
+CONFIG_DNET=m
+CONFIG_DRM=m
+CONFIG_DUMMY_IRQ=m
+CONFIG_DW_WATCHDOG=m
+CONFIG_ECHO=m
+CONFIG_EEPROM_93CX6=m
+CONFIG_EFS_FS=m
+CONFIG_EM_TIMER_STI=y
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_ETHOC=m
+CONFIG_EXOFS_FS=m
+CONFIG_EXTCON=y
+CONFIG_F2FS_FS=m
+CONFIG_FB=y
+CONFIG_FB_ATY128=m
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_IBM_GXT4500=m
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+CONFIG_FB_UDL=m
+CONFIG_FB_VOODOO1=m
+CONFIG_FDDI=y
+CONFIG_FEALNX=m
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_NOSY=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIXED_PHY=y
+CONFIG_FMC=m
+CONFIG_FRAME_WARN=1024
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
+CONFIG_GENERIC_PHY=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_GPIO_TWL4030=y
+CONFIG_GPIO_TWL6040=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_HAVE_ARCH_BITREVERSE=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HFSPLUS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HIBERNATION=y
+# CONFIG_HIO is not set
+CONFIG_HPFS_FS=m
+CONFIG_HP_ILO=m
+CONFIG_HSI=m
+CONFIG_HSR=m
+CONFIG_HTC_PASIC3=m
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ_250=y
+CONFIG_I2C=y
+CONFIG_I2C_SLAVE=y
+CONFIG_I6300ESB_WDT=m
+CONFIG_IEEE802154=m
+CONFIG_IIO=m
+CONFIG_IMA=y
+CONFIG_INFINIBAND_NES=m
+CONFIG_INFINIBAND_OCRDMA=m
+CONFIG_INPUT=y
+CONFIG_IPACK_BUS=m
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_SI_PROBE_DEFAULTS is not set
+CONFIG_IPX=m
+# CONFIG_IP_DCCP_CCID3 is not set
+CONFIG_IRQ_BYPASS_MANAGER=m
+# CONFIG_IRQ_FORCED_THREADING_DEFAULT is not set
+CONFIG_JFS_FS=m
+CONFIG_JME=m
+# CONFIG_JUMP_LABEL is not set
+CONFIG_KARMA_PARTITION=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+CONFIG_KVM=y
+CONFIG_LAPB=m
+CONFIG_LDM_PARTITION=y
+CONFIG_LIBNVDIMM=y
+CONFIG_LLC2=m
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LPC_ICH=m
+CONFIG_LPC_SCH=m
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+CONFIG_MAILBOX=y
+CONFIG_MAX63XX_WATCHDOG=m
+CONFIG_MCB=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_SAS=m
+CONFIG_MEMORY=y
+CONFIG_MEMSTICK=m
+CONFIG_MFD_CORE=y
+CONFIG_MFD_JANZ_CMODIO=m
+CONFIG_MFD_KEMPLD=m
+CONFIG_MFD_MT6397=m
+CONFIG_MFD_RDC321X=m
+CONFIG_MFD_RTSX_PCI=m
+CONFIG_MFD_SM501=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_TI_AM335X_TSCADC=m
+CONFIG_MFD_TMIO=y
+CONFIG_MFD_VX855=m
+CONFIG_MII=m
+CONFIG_MINIX_FS=m
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MTD=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_BCH=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_OMAP_BCH_BUILD=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_NCP_FS=m
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_CADENCE=y
+CONFIG_NET_PACKET_ENGINE=y
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CAVIUM=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_SYNOPSYS=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NEW_LEDS=y
+CONFIG_NFC=m
+CONFIG_NOZOMI=m
+CONFIG_NR_CPUS=4
+CONFIG_NTB=m
+# CONFIG_NTFS_RW is not set
+CONFIG_NVMEM=m
+CONFIG_NVRAM=m
+CONFIG_N_GSM=m
+CONFIG_OF=y
+CONFIG_OMFS_FS=m
+# CONFIG_OPENNSL is not set
+CONFIG_OSF_PARTITION=y
+CONFIG_PAGE_EXTENSION=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_PARPORT=m
+CONFIG_PATA_SIS=m
+# CONFIG_PCCARD is not set
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_PCI_PASID=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_PGTABLE_MAPPING=y
+CONFIG_PHANTOM=m
+CONFIG_PHONET=m
+CONFIG_PHYLIB=y
+CONFIG_PHY_EXYNOS5250_USB2=y
+CONFIG_PHY_PXA_28NM_HSIC=m
+CONFIG_PHY_PXA_28NM_USB2=m
+CONFIG_PINCTRL_BERLIN_BG2=y
+CONFIG_PINCTRL_BERLIN_BG2CD=y
+CONFIG_PINCTRL_BERLIN_BG2Q=y
+CONFIG_PINCTRL_MT8127=y
+CONFIG_PINCTRL_MT8135=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_POWERCAP=y
+CONFIG_POWER_AVS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPP=y
+CONFIG_PPS=y
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PPS_CLIENT_LDISC=m
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_PROBE_EVENTS=y
+CONFIG_PSTORE=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_RAM=y
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PWM=y
+CONFIG_QNX4FS_FS=m
+CONFIG_QNX6FS_FS=m
+CONFIG_RAW_DRIVER=m
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_REED_SOLOMON=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REISERFS_FS=m
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFKILL=y
+CONFIG_ROMFS_FS=m
+CONFIG_RTC_DRV_CMOS=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PL031=y
+CONFIG_RTC_DRV_TWL4030=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_SATA_SVW=m
+# CONFIG_SCHED_SMT is not set
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC94XX=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_MVSAS=m
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_SNIC=m
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_UFSHCD=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SENSORS_SCH56XX_COMMON=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_DW=m
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_ALTERA_JTAGUART=m
+CONFIG_SERIAL_ALTERA_UART=m
+CONFIG_SERIAL_ARC=m
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_FSL_LPUART=m
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_SCCNXP=y
+CONFIG_SERIO=y
+CONFIG_SFC=m
+CONFIG_SGI_IOC4=m
+CONFIG_SGI_PARTITION=y
+CONFIG_SH_TIMER_CMT=y
+CONFIG_SH_TIMER_MTU2=y
+CONFIG_SH_TIMER_TMU=y
+CONFIG_SLIP=m
+CONFIG_SMC91X=m
+CONFIG_SND=y
+CONFIG_SND_DMAENGINE_PCM=y
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+CONFIG_SND_PCM=y
+# CONFIG_SND_SBAWE_SEQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+CONFIG_SND_SOC_RT5677_SPI=m
+CONFIG_SND_TIMER=y
+CONFIG_SOC_TI=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_SOUND=y
+CONFIG_SPI=y
+CONFIG_SPI_PXA2XX_PCI=m
+CONFIG_SPMI=m
+CONFIG_SRAM=y
+CONFIG_SSB=m
+CONFIG_STAGING=y
+CONFIG_STANDALONE=y
+CONFIG_STE_MODEM_RPROC=m
+CONFIG_SUN_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_SYSV_FS=m
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_THERMAL=y
+CONFIG_THUNDERBOLT=m
+CONFIG_TIFM_CORE=m
+CONFIG_TIGON3=m
+CONFIG_TI_CPSW_ALE=y
+CONFIG_TRACE_SINK=m
+CONFIG_TTY_PRINTK=y
+CONFIG_UFS_FS=m
+CONFIG_UIO=m
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_UPROBES=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+CONFIG_USB_FSL_MPH_DR_OF=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_G_MULTI=m
+# CONFIG_USB_HCD_BCMA is not set
+# CONFIG_USB_HCD_SSB is not set
+CONFIG_USB_MUSB_HDRC=y
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_UWB=m
+CONFIG_VFIO=m
+# CONFIG_VFIO_IOMMU_TYPE1 is not set
+CONFIG_VFIO_PCI=m
+CONFIG_VFIO_VIRQFD=m
+CONFIG_VGASTATE=m
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VME_BUS=y
+CONFIG_VMXNET3=m
+CONFIG_VXFS_FS=m
+CONFIG_W1=m
+CONFIG_WAN=y
+CONFIG_WDTPCI=m
+CONFIG_WIMAX=m
+CONFIG_X25=m
+# CONFIG_XEN is not set
+CONFIG_XILINX_WATCHDOG=m
+CONFIG_XILLYBUS=m
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_XZ_DEC_X86=y
+CONFIG_ZLIB_DEFLATE=y
--- linux-4.4.0.orig/debian.master/config/armhf/config.flavour.generic
+++ linux-4.4.0/debian.master/config/armhf/config.flavour.generic
@@ -0,0 +1,25 @@
+#
+# Config options for config.flavour.generic automatically generated by splitconfig.pl
+#
+CONFIG_ARCH_MXC=y
+CONFIG_ARCH_OMAP3=y
+CONFIG_ARCH_OMAP4=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+# CONFIG_ARM_HIGHBANK_CPUIDLE is not set
+# CONFIG_ARM_LPAE is not set
+CONFIG_FB_CFB_REV_PIXELS_IN_BYTE=y
+CONFIG_FORCE_MAX_ZONEORDER=12
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
+CONFIG_PGTABLE_LEVELS=2
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_REGULATOR_TWL4030=y
+CONFIG_RTC_DRV_PCF8523=y
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_SOC_FSL_SSI=y
+CONFIG_SND_SOC_IMX_AUDMUX=y
+CONFIG_SND_SOC_SGTL5000=y
+CONFIG_SOC_AM33XX=y
+CONFIG_ZONE_DMA_FLAG=0
--- linux-4.4.0.orig/debian.master/config/armhf/config.flavour.generic-lpae
+++ linux-4.4.0/debian.master/config/armhf/config.flavour.generic-lpae
@@ -0,0 +1,25 @@
+#
+# Config options for config.flavour.generic-lpae automatically generated by splitconfig.pl
+#
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARM_ATAG_DTB_COMPAT is not set
+CONFIG_ARM_HIGHBANK_CPUIDLE=y
+CONFIG_ARM_LPAE=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_HUGETLB_PAGE=y
+CONFIG_IOMMU_IO_PGTABLE_LPAE=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_REGULATOR_TWL4030=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_SND_EMU10K1_SEQ=m
+CONFIG_SND_SOC_FSL_SSI=m
+CONFIG_SND_SOC_IMX_AUDMUX=m
+CONFIG_SND_SOC_SGTL5000=m
+# CONFIG_SOC_AM33XX is not set
+CONFIG_ZONE_DMA_FLAG=1
--- linux-4.4.0.orig/debian.master/config/config.common.ports
+++ linux-4.4.0/debian.master/config/config.common.ports
@@ -0,0 +1,3 @@
+#
+# Common config options automatically generated by splitconfig.pl
+#
--- linux-4.4.0.orig/debian.master/config/config.common.ubuntu
+++ linux-4.4.0/debian.master/config/config.common.ubuntu
@@ -0,0 +1,7632 @@
+#
+# Common config options automatically generated by splitconfig.pl
+#
+CONFIG_60XX_WDT=m
+CONFIG_64BIT=y
+CONFIG_6LOWPAN_NHC=m
+CONFIG_6LOWPAN_NHC_DEST=m
+CONFIG_6LOWPAN_NHC_FRAGMENT=m
+CONFIG_6LOWPAN_NHC_HOP=m
+CONFIG_6LOWPAN_NHC_IPV6=m
+CONFIG_6LOWPAN_NHC_MOBILITY=m
+CONFIG_6LOWPAN_NHC_ROUTING=m
+CONFIG_6LOWPAN_NHC_UDP=m
+CONFIG_6PACK=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_8129=y
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_842_COMPRESS=m
+CONFIG_842_DECOMPRESS=m
+CONFIG_8723AU_AP_MODE=y
+CONFIG_8723AU_BT_COEXIST=y
+CONFIG_88EU_AP_MODE=y
+CONFIG_9P_FS=m
+CONFIG_9P_FSCACHE=y
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_9P_FS_SECURITY=y
+CONFIG_AB3100_CORE=y
+CONFIG_AB3100_OTP=m
+CONFIG_AC97_BUS=m
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_ACERHDF=m
+CONFIG_ACER_WMI=m
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_AC=y
+CONFIG_ACPI_ALS=m
+CONFIG_ACPI_APEI=y
+CONFIG_ACPI_APEI_EINJ=m
+# CONFIG_ACPI_APEI_ERST_DEBUG is not set
+CONFIG_ACPI_APEI_GHES=y
+CONFIG_ACPI_APEI_MEMORY_FAILURE=y
+CONFIG_ACPI_APEI_PCIEAER=y
+CONFIG_ACPI_BATTERY=y
+CONFIG_ACPI_BGRT=y
+CONFIG_ACPI_BUTTON=y
+CONFIG_ACPI_CCA_REQUIRED=y
+CONFIG_ACPI_CMPC=m
+CONFIG_ACPI_CONTAINER=y
+CONFIG_ACPI_CPPC_CPUFREQ=m
+CONFIG_ACPI_CPPC_LIB=y
+CONFIG_ACPI_CPU_FREQ_PSS=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+CONFIG_ACPI_CUSTOM_DSDT_FILE=""
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+# CONFIG_ACPI_DEBUG is not set
+# CONFIG_ACPI_DEBUGGER is not set
+CONFIG_ACPI_DOCK=y
+CONFIG_ACPI_EC_DEBUGFS=m
+CONFIG_ACPI_EXTLOG=m
+CONFIG_ACPI_FAN=y
+CONFIG_ACPI_GENERIC_GSI=y
+CONFIG_ACPI_HED=y
+CONFIG_ACPI_HOTPLUG_CPU=y
+CONFIG_ACPI_HOTPLUG_IOAPIC=y
+CONFIG_ACPI_HOTPLUG_MEMORY=y
+CONFIG_ACPI_I2C_OPREGION=y
+# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
+CONFIG_ACPI_IPMI=m
+CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
+CONFIG_ACPI_MCFG=y
+CONFIG_ACPI_NFIT=m
+# CONFIG_ACPI_NFIT_DEBUG is not set
+CONFIG_ACPI_NUMA=y
+CONFIG_ACPI_PCI_SLOT=y
+CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_PROCESSOR_AGGREGATOR=m
+CONFIG_ACPI_PROCESSOR_IDLE=y
+# CONFIG_ACPI_PROCFS_POWER is not set
+CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
+CONFIG_ACPI_SBS=m
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_SPCR_TABLE=y
+CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
+CONFIG_ACPI_THERMAL=y
+CONFIG_ACPI_THERMAL_REL=m
+CONFIG_ACPI_TOSHIBA=m
+CONFIG_ACPI_VIDEO=m
+CONFIG_ACPI_WMI=m
+CONFIG_ACQUIRE_WDT=m
+CONFIG_ACT200L_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_AD2S1200=m
+CONFIG_AD2S1210=m
+CONFIG_AD2S90=m
+CONFIG_AD5064=m
+CONFIG_AD525X_DPOT=m
+CONFIG_AD525X_DPOT_I2C=m
+CONFIG_AD525X_DPOT_SPI=m
+CONFIG_AD5360=m
+CONFIG_AD5380=m
+CONFIG_AD5421=m
+CONFIG_AD5446=m
+CONFIG_AD5449=m
+CONFIG_AD5504=m
+CONFIG_AD5592R=m
+CONFIG_AD5592R_BASE=m
+CONFIG_AD5593R=m
+CONFIG_AD5624R_SPI=m
+CONFIG_AD5686=m
+CONFIG_AD5755=m
+CONFIG_AD5764=m
+CONFIG_AD5791=m
+CONFIG_AD5933=m
+CONFIG_AD7150=m
+CONFIG_AD7152=m
+CONFIG_AD7192=m
+CONFIG_AD7266=m
+CONFIG_AD7280=m
+CONFIG_AD7291=m
+CONFIG_AD7298=m
+CONFIG_AD7303=m
+CONFIG_AD7476=m
+CONFIG_AD7606=m
+CONFIG_AD7606_IFACE_PARALLEL=m
+CONFIG_AD7606_IFACE_SPI=m
+CONFIG_AD7746=m
+CONFIG_AD7780=m
+CONFIG_AD7791=m
+CONFIG_AD7793=m
+CONFIG_AD7816=m
+CONFIG_AD7887=m
+CONFIG_AD7923=m
+CONFIG_AD799X=m
+CONFIG_AD8366=m
+CONFIG_AD9523=m
+CONFIG_AD9832=m
+CONFIG_AD9834=m
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_ADE7753=m
+CONFIG_ADE7754=m
+CONFIG_ADE7758=m
+CONFIG_ADE7759=m
+CONFIG_ADE7854=m
+CONFIG_ADE7854_I2C=m
+CONFIG_ADE7854_SPI=m
+CONFIG_ADF4350=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_ADIS16060=m
+CONFIG_ADIS16080=m
+CONFIG_ADIS16130=m
+CONFIG_ADIS16136=m
+CONFIG_ADIS16201=m
+CONFIG_ADIS16203=m
+CONFIG_ADIS16204=m
+CONFIG_ADIS16209=m
+CONFIG_ADIS16220=m
+CONFIG_ADIS16240=m
+CONFIG_ADIS16260=m
+CONFIG_ADIS16400=m
+CONFIG_ADIS16480=m
+CONFIG_ADJD_S311=m
+CONFIG_ADM8211=m
+CONFIG_ADT7316=m
+CONFIG_ADT7316_I2C=m
+CONFIG_ADT7316_SPI=m
+CONFIG_ADVANTECH_WDT=m
+CONFIG_ADVISE_SYSCALLS=y
+CONFIG_ADXRS450=m
+CONFIG_AD_SIGMA_DELTA=m
+CONFIG_AFIUCV=m
+# CONFIG_AFS_DEBUG is not set
+CONFIG_AFS_FS=m
+CONFIG_AFS_FSCACHE=y
+CONFIG_AF_RXRPC=m
+# CONFIG_AF_RXRPC_DEBUG is not set
+CONFIG_AGP=y
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_SIS=m
+CONFIG_AGP_VIA=y
+CONFIG_AHCI_CEVA=m
+CONFIG_AHCI_QORIQ=m
+CONFIG_AHCI_XGENE=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+# CONFIG_AIC79XX_DEBUG_ENABLE is not set
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+CONFIG_AIC79XX_RESET_DELAY_MS=5000
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_AIC7XXX_RESET_DELAY_MS=5000
+# CONFIG_AIC94XX_DEBUG is not set
+CONFIG_AIM_CDEV=m
+CONFIG_AIM_NETWORK=m
+CONFIG_AIM_SOUND=m
+CONFIG_AIM_V4L2=m
+CONFIG_AIO=y
+CONFIG_AIRO=m
+CONFIG_AIRO_CS=m
+CONFIG_AK09911=m
+CONFIG_AK8975=m
+CONFIG_AL3320A=m
+CONFIG_ALIENWARE_WMI=m
+CONFIG_ALIM1535_WDT=m
+CONFIG_ALI_FIR=m
+CONFIG_ALLOW_DEV_COREDUMP=y
+CONFIG_ALTERA_MBOX=m
+CONFIG_ALTERA_STAPL=m
+CONFIG_ALX=m
+CONFIG_AMBA_PL08X=y
+CONFIG_AMD8111_ETH=m
+CONFIG_AMD_IOMMU=y
+CONFIG_AMD_IOMMU_STATS=y
+CONFIG_AMD_IOMMU_V2=m
+CONFIG_AMD_MCE_INJ=m
+CONFIG_AMD_NB=y
+CONFIG_AMD_NUMA=y
+CONFIG_AMD_PHY=m
+CONFIG_AMD_XGBE=m
+CONFIG_AMD_XGBE_DCB=y
+CONFIG_AMILO_RFKILL=m
+# CONFIG_ANDROID is not set
+CONFIG_ANON_INODES=y
+CONFIG_APDS9300=m
+CONFIG_APDS9802ALS=m
+CONFIG_APDS9960=m
+CONFIG_APPLDATA_BASE=y
+CONFIG_APPLDATA_MEM=m
+CONFIG_APPLDATA_NET_SUM=m
+CONFIG_APPLDATA_OS=m
+CONFIG_APPLE_GMUX=m
+CONFIG_APQ_GCC_8084=m
+CONFIG_APQ_MMCC_8084=m
+CONFIG_AQUANTIA_PHY=m
+CONFIG_AR5523=m
+CONFIG_ARCH_BCM_IPROC=y
+CONFIG_ARCH_BERLIN=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
+# CONFIG_ARCH_EXYNOS7 is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_ARCH_HAS_CPU_FINALIZE_INIT=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_MMIO_FLUSH=y
+CONFIG_ARCH_HAS_PMEM_API=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_ARCH_HIBERNATION_HEADER=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_HISI=y
+CONFIG_ARCH_INLINE_READ_LOCK=y
+CONFIG_ARCH_INLINE_READ_LOCK_BH=y
+CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y
+CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y
+CONFIG_ARCH_INLINE_READ_TRYLOCK=y
+CONFIG_ARCH_INLINE_READ_UNLOCK=y
+CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y
+CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y
+CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y
+CONFIG_ARCH_INLINE_SPIN_LOCK=y
+CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y
+CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y
+CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y
+CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y
+CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y
+CONFIG_ARCH_INLINE_SPIN_UNLOCK=y
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y
+CONFIG_ARCH_INLINE_WRITE_LOCK=y
+CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y
+CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y
+CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y
+CONFIG_ARCH_INLINE_WRITE_TRYLOCK=y
+CONFIG_ARCH_INLINE_WRITE_UNLOCK=y
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y
+CONFIG_ARCH_LAYERSCAPE=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_ARCH_MEMORY_PROBE=y
+CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_PROC_KCORE_TEXT=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_RANDOM=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_ROCKCHIP is not set
+CONFIG_ARCH_SAVE_PAGE_KEYS=y
+CONFIG_ARCH_SEATTLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPRD=y
+CONFIG_ARCH_STRATIX10=y
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT=y
+CONFIG_ARCH_SUPPORTS_INT128=y
+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARCH_TEGRA is not set
+CONFIG_ARCH_THUNDER=y
+CONFIG_ARCH_USES_PG_UNCACHED=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
+CONFIG_ARCH_VEXPRESS=y
+CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
+CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
+CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARCH_XGENE=y
+CONFIG_ARCH_ZYNQMP=y
+CONFIG_ARCNET_1051=m
+CONFIG_ARCNET_1201=m
+CONFIG_ARCNET_CAP=m
+CONFIG_ARCNET_COM20020=m
+CONFIG_ARCNET_COM20020_CS=m
+CONFIG_ARCNET_COM20020_PCI=m
+CONFIG_ARCNET_COM90xx=m
+CONFIG_ARCNET_COM90xxIO=m
+CONFIG_ARCNET_RAW=m
+CONFIG_ARCNET_RIM_I=m
+CONFIG_ARC_EMAC=m
+CONFIG_ARC_EMAC_CORE=m
+CONFIG_ARM64=y
+# CONFIG_ARM64_16K_PAGES is not set
+CONFIG_ARM64_4K_PAGES=y
+# CONFIG_ARM64_64K_PAGES is not set
+CONFIG_ARM64_ACPI_PARKING_PROTOCOL=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_ARM64_ERRATUM_1024718=y
+CONFIG_ARM64_ERRATUM_819472=y
+CONFIG_ARM64_ERRATUM_824069=y
+CONFIG_ARM64_ERRATUM_826319=y
+CONFIG_ARM64_ERRATUM_827319=y
+CONFIG_ARM64_ERRATUM_832075=y
+CONFIG_ARM64_ERRATUM_834220=y
+CONFIG_ARM64_ERRATUM_843419=y
+CONFIG_ARM64_ERRATUM_845719=y
+CONFIG_ARM64_HW_AFDBM=y
+# CONFIG_ARM64_LSE_ATOMICS is not set
+CONFIG_ARM64_PAN=y
+# CONFIG_ARM64_PTDUMP is not set
+# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set
+CONFIG_ARM64_VA_BITS=48
+# CONFIG_ARM64_VA_BITS_39 is not set
+CONFIG_ARM64_VA_BITS_48=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_BIG_LITTLE_CPUFREQ=m
+CONFIG_ARM_CCI=y
+CONFIG_ARM_CCI400_COMMON=y
+CONFIG_ARM_CCI400_PMU=y
+CONFIG_ARM_CCI500_PMU=y
+CONFIG_ARM_CCI_PMU=y
+CONFIG_ARM_CCN=y
+CONFIG_ARM_CPUIDLE=y
+CONFIG_ARM_DT_BL_CPUFREQ=m
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GIC_V2M=y
+CONFIG_ARM_GIC_V3=y
+CONFIG_ARM_GIC_V3_ITS=y
+CONFIG_ARM_HISI_ACPU_CPUFREQ=m
+# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
+CONFIG_ARM_MHU=m
+CONFIG_ARM_MT8173_CPUFREQ=y
+CONFIG_ARM_PL172_MPMC=m
+CONFIG_ARM_PMU=y
+CONFIG_ARM_PSCI_FW=y
+CONFIG_ARM_SCPI_CPUFREQ=m
+CONFIG_ARM_SCPI_PROTOCOL=m
+CONFIG_ARM_SMMU=y
+CONFIG_ARM_SMMU_V3=y
+CONFIG_ARM_SP805_WATCHDOG=m
+CONFIG_ARM_TIMER_SP804=y
+CONFIG_AS3935=m
+CONFIG_ASN1=y
+CONFIG_ASSOCIATIVE_ARRAY=y
+CONFIG_ASUS_LAPTOP=m
+CONFIG_ASUS_NB_WMI=m
+CONFIG_ASUS_WMI=m
+CONFIG_ASYMMETRIC_KEY_TYPE=y
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_PQ=m
+CONFIG_ASYNC_RAID6_RECOV=m
+CONFIG_ASYNC_RAID6_TEST=m
+CONFIG_ASYNC_TX_DMA=y
+CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=y
+CONFIG_ASYNC_XOR=m
+CONFIG_AT76C50X_USB=m
+CONFIG_AT803X_PHY=m
+CONFIG_ATA=y
+CONFIG_ATA_ACPI=y
+CONFIG_ATA_BMDMA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_SFF=y
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATH10K=m
+# CONFIG_ATH10K_DEBUG is not set
+CONFIG_ATH10K_DEBUGFS=y
+CONFIG_ATH10K_PCI=m
+CONFIG_ATH10K_TRACING=y
+CONFIG_ATH5K=m
+# CONFIG_ATH5K_DEBUG is not set
+CONFIG_ATH5K_PCI=y
+# CONFIG_ATH5K_TRACER is not set
+CONFIG_ATH6KL=m
+# CONFIG_ATH6KL_DEBUG is not set
+CONFIG_ATH6KL_SDIO=m
+# CONFIG_ATH6KL_TRACING is not set
+CONFIG_ATH6KL_USB=m
+CONFIG_ATH9K=m
+CONFIG_ATH9K_AHB=y
+CONFIG_ATH9K_BTCOEX_SUPPORT=y
+CONFIG_ATH9K_CHANNEL_CONTEXT=y
+CONFIG_ATH9K_COMMON=m
+CONFIG_ATH9K_DEBUGFS=y
+# CONFIG_ATH9K_DYNACK is not set
+CONFIG_ATH9K_HTC=m
+CONFIG_ATH9K_HTC_DEBUGFS=y
+CONFIG_ATH9K_HW=m
+CONFIG_ATH9K_PCI=y
+CONFIG_ATH9K_PCOEM=y
+CONFIG_ATH9K_RFKILL=y
+CONFIG_ATH9K_STATION_STATISTICS=y
+CONFIG_ATH9K_WOW=y
+CONFIG_ATH_CARDS=m
+CONFIG_ATH_COMMON=m
+# CONFIG_ATH_DEBUG is not set
+CONFIG_ATL1=m
+CONFIG_ATL1C=m
+CONFIG_ATL1E=m
+CONFIG_ATL2=m
+CONFIG_ATMEL=m
+# CONFIG_ATMEL_PIT is not set
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_DRIVERS=y
+CONFIG_ATM_DUMMY=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+CONFIG_ATM_FORE200E=m
+CONFIG_ATM_FORE200E_DEBUG=0
+CONFIG_ATM_FORE200E_TX_RETRY=16
+# CONFIG_ATM_FORE200E_USE_TASKLET is not set
+CONFIG_ATM_HE=m
+CONFIG_ATM_HE_USE_SUNI=y
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+CONFIG_ATM_IA=m
+# CONFIG_ATM_IA_DEBUG is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_NICSTAR=m
+# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set
+# CONFIG_ATM_NICSTAR_USE_SUNI is not set
+CONFIG_ATM_SOLOS=m
+CONFIG_ATM_TCP=m
+CONFIG_ATM_ZATM=m
+# CONFIG_ATM_ZATM_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+CONFIG_ATP=m
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_AUDIT_COMPAT_GENERIC=y
+CONFIG_AUDIT_GENERIC=y
+CONFIG_AUDIT_TREE=y
+CONFIG_AUDIT_WATCH=y
+CONFIG_AUFS_BDEV_LOOP=y
+# CONFIG_AUFS_BRANCH_MAX_1023 is not set
+CONFIG_AUFS_BRANCH_MAX_127=y
+# CONFIG_AUFS_BRANCH_MAX_32767 is not set
+# CONFIG_AUFS_BRANCH_MAX_511 is not set
+# CONFIG_AUFS_BR_FUSE is not set
+CONFIG_AUFS_BR_HFSPLUS=y
+# CONFIG_AUFS_BR_RAMFS is not set
+# CONFIG_AUFS_DEBUG is not set
+CONFIG_AUFS_EXPORT=y
+# CONFIG_AUFS_FHSM is not set
+CONFIG_AUFS_FS=m
+# CONFIG_AUFS_HNOTIFY is not set
+CONFIG_AUFS_INO_T_64=y
+# CONFIG_AUFS_RDU is not set
+CONFIG_AUFS_SBILIST=y
+# CONFIG_AUFS_SHWH is not set
+CONFIG_AUFS_XATTR=y
+CONFIG_AURORA_NB8800=m
+CONFIG_AX25=m
+CONFIG_AX25_DAMA_SLAVE=y
+CONFIG_AXP20X_POWER=m
+CONFIG_AXP288_ADC=m
+CONFIG_AXP288_CHARGER=m
+CONFIG_AXP288_FUEL_GAUGE=m
+CONFIG_B43=m
+CONFIG_B43LEGACY=m
+# CONFIG_B43LEGACY_DEBUG is not set
+CONFIG_B43LEGACY_DMA=y
+CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
+# CONFIG_B43LEGACY_DMA_MODE is not set
+CONFIG_B43LEGACY_HWRNG=y
+CONFIG_B43LEGACY_LEDS=y
+CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y
+CONFIG_B43LEGACY_PCI_AUTOSELECT=y
+CONFIG_B43LEGACY_PIO=y
+# CONFIG_B43LEGACY_PIO_MODE is not set
+CONFIG_B43_BCMA=y
+CONFIG_B43_BCMA_PIO=y
+# CONFIG_B43_BUSES_BCMA is not set
+CONFIG_B43_BUSES_BCMA_AND_SSB=y
+# CONFIG_B43_BUSES_SSB is not set
+# CONFIG_B43_DEBUG is not set
+CONFIG_B43_HWRNG=y
+CONFIG_B43_LEDS=y
+CONFIG_B43_PCICORE_AUTOSELECT=y
+CONFIG_B43_PCI_AUTOSELECT=y
+CONFIG_B43_PHY_G=y
+CONFIG_B43_PHY_HT=y
+CONFIG_B43_PHY_LP=y
+CONFIG_B43_PHY_N=y
+CONFIG_B43_PIO=y
+# CONFIG_B43_SDIO is not set
+CONFIG_B43_SSB=y
+CONFIG_B44=m
+CONFIG_B44_PCI=y
+CONFIG_B44_PCICORE_AUTOSELECT=y
+CONFIG_B44_PCI_AUTOSELECT=y
+CONFIG_BACKLIGHT_88PM860X=m
+CONFIG_BACKLIGHT_AAT2870=m
+CONFIG_BACKLIGHT_ADP5520=m
+CONFIG_BACKLIGHT_ADP8860=m
+CONFIG_BACKLIGHT_ADP8870=m
+CONFIG_BACKLIGHT_APPLE=m
+CONFIG_BACKLIGHT_AS3711=m
+CONFIG_BACKLIGHT_BD6107=m
+CONFIG_BACKLIGHT_CARILLO_RANCH=m
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DA903X=m
+CONFIG_BACKLIGHT_DA9052=m
+CONFIG_BACKLIGHT_GENERIC=m
+CONFIG_BACKLIGHT_GPIO=m
+CONFIG_BACKLIGHT_LM3533=m
+CONFIG_BACKLIGHT_LM3630A=m
+CONFIG_BACKLIGHT_LM3639=m
+CONFIG_BACKLIGHT_LP855X=m
+CONFIG_BACKLIGHT_LP8788=m
+CONFIG_BACKLIGHT_LV5207LP=m
+CONFIG_BACKLIGHT_MAX8925=m
+CONFIG_BACKLIGHT_PANDORA=m
+CONFIG_BACKLIGHT_PCF50633=m
+CONFIG_BACKLIGHT_PM8941_WLED=m
+CONFIG_BACKLIGHT_PWM=m
+CONFIG_BACKLIGHT_SAHARA=m
+CONFIG_BACKLIGHT_SKY81452=m
+CONFIG_BACKLIGHT_TPS65217=m
+CONFIG_BACKLIGHT_WM831X=m
+# CONFIG_BACKTRACE_SELF_TEST is not set
+CONFIG_BALLOON_COMPACTION=y
+CONFIG_BASE_FULL=y
+CONFIG_BASE_SMALL=0
+CONFIG_BATMAN_ADV_BLA=y
+CONFIG_BATMAN_ADV_DAT=y
+# CONFIG_BATMAN_ADV_DEBUG is not set
+CONFIG_BATMAN_ADV_MCAST=y
+CONFIG_BATMAN_ADV_NC=y
+CONFIG_BATTERY_88PM860X=m
+CONFIG_BATTERY_BQ27XXX=m
+CONFIG_BATTERY_BQ27XXX_I2C=y
+CONFIG_BATTERY_BQ27XXX_PLATFORM=y
+CONFIG_BATTERY_DA9030=m
+CONFIG_BATTERY_DA9052=m
+CONFIG_BATTERY_DA9150=m
+CONFIG_BATTERY_DS2760=m
+CONFIG_BATTERY_DS2780=m
+CONFIG_BATTERY_DS2781=m
+CONFIG_BATTERY_DS2782=m
+CONFIG_BATTERY_GAUGE_LTC2941=m
+CONFIG_BATTERY_MAX17040=m
+CONFIG_BATTERY_MAX17042=m
+CONFIG_BATTERY_RT5033=m
+CONFIG_BATTERY_RX51=m
+CONFIG_BATTERY_SBS=m
+CONFIG_BATTERY_TWL4030_MADC=m
+CONFIG_BAYCOM_PAR=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_BCACHE=m
+# CONFIG_BCACHE_CLOSURES_DEBUG is not set
+# CONFIG_BCACHE_DEBUG is not set
+CONFIG_BCH=m
+CONFIG_BCH_CONST_M=14
+CONFIG_BCH_CONST_PARAMS=y
+CONFIG_BCH_CONST_T=4
+CONFIG_BCM7038_WDT=m
+CONFIG_BCM7XXX_PHY=m
+CONFIG_BCM87XX_PHY=m
+CONFIG_BCMA_BLOCKIO=y
+# CONFIG_BCMA_DEBUG is not set
+CONFIG_BCMA_DRIVER_GMAC_CMN=y
+CONFIG_BCMA_DRIVER_GPIO=y
+CONFIG_BCMA_DRIVER_PCI=y
+CONFIG_BCMA_HOST_PCI=y
+CONFIG_BCMA_HOST_PCI_POSSIBLE=y
+CONFIG_BCMA_HOST_SOC=y
+CONFIG_BCMA_POSSIBLE=y
+CONFIG_BCMGENET=m
+CONFIG_BCM_NET_PHYLIB=m
+CONFIG_BE2NET=m
+CONFIG_BE2NET_HWMON=y
+CONFIG_BE2NET_VXLAN=y
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BERLIN2_ADC=m
+CONFIG_BH1750=m
+CONFIG_BIG_KEYS=y
+CONFIG_BINARY_PRINTF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BINFMT_SCRIPT=y
+CONFIG_BITREVERSE=y
+CONFIG_BLK_CGROUP=y
+CONFIG_BLK_CMDLINE_PARSER=y
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_BSGLIB=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_DM=y
+CONFIG_BLK_DEV_DM_BUILTIN=y
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+CONFIG_BLK_DEV_MD=y
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_NULL_BLK=m
+CONFIG_BLK_DEV_NVME_SCSI=y
+CONFIG_BLK_DEV_OSD=m
+CONFIG_BLK_DEV_PMEM=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_DAX=y
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_RBD=m
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_THROTTLING=y
+# CONFIG_BLK_DEV_XPRAM is not set
+CONFIG_BLOCK=y
+CONFIG_BLOCK_COMPAT=y
+CONFIG_BMA180=m
+CONFIG_BMC150_ACCEL=m
+CONFIG_BMC150_ACCEL_I2C=m
+CONFIG_BMC150_ACCEL_SPI=m
+CONFIG_BMC150_MAGN=m
+CONFIG_BMG160=m
+CONFIG_BMG160_I2C=m
+CONFIG_BMG160_SPI=m
+CONFIG_BMP085=m
+CONFIG_BMP085_I2C=m
+CONFIG_BMP085_SPI=m
+CONFIG_BMP280=m
+CONFIG_BNA=m
+CONFIG_BNX2=m
+CONFIG_BNX2X=m
+CONFIG_BNX2X_SRIOV=y
+CONFIG_BNX2X_VXLAN=y
+CONFIG_BNXT=m
+CONFIG_BNXT_BPO=m
+CONFIG_BNXT_BPO_DCB=y
+CONFIG_BNXT_BPO_SRIOV=y
+CONFIG_BNXT_SRIOV=y
+CONFIG_BOARD_TPCI200=m
+CONFIG_BONDING=m
+# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
+# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_BPF=y
+CONFIG_BPF_EVENTS=y
+CONFIG_BPF_JIT=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
+CONFIG_BPQETHER=m
+CONFIG_BQL=y
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_BRCMDBG is not set
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_PCIE=y
+CONFIG_BRCMFMAC_PROTO_BCDC=y
+CONFIG_BRCMFMAC_PROTO_MSGBUF=y
+CONFIG_BRCMFMAC_SDIO=y
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMSMAC=m
+CONFIG_BRCMUTIL=m
+CONFIG_BRCM_TRACING=y
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_VLAN_FILTERING=y
+CONFIG_BROADCOM_PHY=m
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_BT=m
+CONFIG_BTREE=y
+# CONFIG_BTRFS_ASSERT is not set
+# CONFIG_BTRFS_DEBUG is not set
+CONFIG_BTRFS_FS=m
+# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set
+CONFIG_BTRFS_FS_POSIX_ACL=y
+# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
+CONFIG_BTT=y
+CONFIG_BT_6LOWPAN=m
+CONFIG_BT_ATH3K=m
+CONFIG_BT_BCM=m
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_BREDR=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_DEBUGFS=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTUSB_BCM=y
+CONFIG_BT_HCIBTUSB_RTL=y
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_INTEL=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIUART_QCA=y
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_HIDP=m
+# CONFIG_BT_HS is not set
+CONFIG_BT_INTEL=m
+CONFIG_BT_LE=y
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_QCA=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_RTL=m
+# CONFIG_BT_SELFTEST is not set
+CONFIG_BT_WILINK=m
+CONFIG_BUG=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+CONFIG_BUILD_BIN2C=y
+CONFIG_C2PORT_DURAMAR_2150=m
+CONFIG_CACHEFILES=m
+# CONFIG_CACHEFILES_DEBUG is not set
+# CONFIG_CACHEFILES_HISTOGRAM is not set
+# CONFIG_CAIF_DEBUG is not set
+CONFIG_CAIF_HSI=m
+CONFIG_CAIF_NETDEV=m
+CONFIG_CAIF_SPI_SLAVE=m
+# CONFIG_CAIF_SPI_SYNC is not set
+CONFIG_CAIF_TTY=m
+CONFIG_CAIF_USB=m
+CONFIG_CAIF_VIRTIO=m
+CONFIG_CALGARY_IOMMU=y
+CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y
+CONFIG_CAN_8DEV_USB=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_CC770=m
+CONFIG_CAN_CC770_ISA=m
+CONFIG_CAN_CC770_PLATFORM=m
+CONFIG_CAN_C_CAN=m
+CONFIG_CAN_C_CAN_PCI=m
+CONFIG_CAN_C_CAN_PLATFORM=m
+# CONFIG_CAN_DEBUG_DEVICES is not set
+CONFIG_CAN_DEV=m
+CONFIG_CAN_EMS_PCI=m
+CONFIG_CAN_EMS_PCMCIA=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_ESD_USB2=m
+CONFIG_CAN_GRCAN=m
+CONFIG_CAN_GS_USB=m
+CONFIG_CAN_GW=m
+CONFIG_CAN_HMS_USB=m
+CONFIG_CAN_JANZ_ICAN3=m
+CONFIG_CAN_KVASER_PCI=m
+CONFIG_CAN_KVASER_USB=m
+CONFIG_CAN_LEDS=y
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_M_CAN=m
+CONFIG_CAN_PEAK_PCI=m
+CONFIG_CAN_PEAK_PCIEC=y
+CONFIG_CAN_PEAK_PCMCIA=m
+CONFIG_CAN_PEAK_USB=m
+CONFIG_CAN_PLX_PCI=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_SJA1000=m
+CONFIG_CAN_SJA1000_ISA=m
+CONFIG_CAN_SJA1000_PLATFORM=m
+CONFIG_CAN_SLCAN=m
+CONFIG_CAN_SOFTING=m
+CONFIG_CAN_SOFTING_CS=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_XILINXCAN=m
+CONFIG_CAPI_AVM=y
+CONFIG_CAPI_EICON=y
+CONFIG_CAPI_TRACE=y
+CONFIG_CARACALLA_BOARD=y
+CONFIG_CARDBUS=y
+CONFIG_CARDMAN_4000=m
+CONFIG_CARDMAN_4040=m
+CONFIG_CARL9170=m
+# CONFIG_CARL9170_DEBUGFS is not set
+CONFIG_CARL9170_HWRNG=y
+CONFIG_CARL9170_LEDS=y
+CONFIG_CARL9170_WPC=y
+# CONFIG_CARMINE_DRAM_CUSTOM is not set
+CONFIG_CASSINI=m
+CONFIG_CAVIUM_ERRATUM_22375=y
+CONFIG_CAVIUM_ERRATUM_23144=y
+CONFIG_CAVIUM_ERRATUM_23154=y
+CONFIG_CAVIUM_ERRATUM_27456=y
+# CONFIG_CB710_DEBUG is not set
+CONFIG_CB710_DEBUG_ASSUMPTIONS=y
+CONFIG_CC10001_ADC=m
+CONFIG_CCW=y
+CONFIG_CCWGROUP=m
+CONFIG_CCW_CONSOLE=y
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_CC_STACKPROTECTOR_NONE is not set
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_CEPH_FS=m
+CONFIG_CEPH_FSCACHE=y
+CONFIG_CEPH_FS_POSIX_ACL=y
+CONFIG_CEPH_LIB=m
+# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
+CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y
+CONFIG_CFAG12864B=m
+CONFIG_CFAG12864B_RATE=20
+CONFIG_CFG80211=m
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+CONFIG_CFG80211_CRDA_SUPPORT=y
+CONFIG_CFG80211_DEBUGFS=y
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_CFG80211_WEXT_EXPORT=y
+CONFIG_CFQ_GROUP_IOSCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_HUGETLB=y
+CONFIG_CGROUP_NET_CLASSID=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CGROUP_WRITEBACK=y
+CONFIG_CHARGER_88PM860X=m
+CONFIG_CHARGER_BQ2415X=m
+CONFIG_CHARGER_BQ24190=m
+CONFIG_CHARGER_BQ24257=m
+CONFIG_CHARGER_BQ24735=m
+CONFIG_CHARGER_BQ25890=m
+CONFIG_CHARGER_DA9150=m
+CONFIG_CHARGER_GPIO=m
+CONFIG_CHARGER_ISP1704=m
+CONFIG_CHARGER_LP8727=m
+CONFIG_CHARGER_LP8788=m
+CONFIG_CHARGER_MANAGER=y
+CONFIG_CHARGER_MAX14577=m
+CONFIG_CHARGER_MAX77693=m
+CONFIG_CHARGER_MAX8903=m
+CONFIG_CHARGER_MAX8997=m
+CONFIG_CHARGER_MAX8998=m
+CONFIG_CHARGER_PCF50633=m
+CONFIG_CHARGER_QCOM_SMBB=m
+CONFIG_CHARGER_RT9455=m
+CONFIG_CHARGER_SMB347=m
+CONFIG_CHARGER_TPS65090=m
+CONFIG_CHARGER_TPS65217=m
+CONFIG_CHARGER_TWL4030=m
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_CHECK_SIGNATURE=y
+CONFIG_CHECK_STACK=y
+CONFIG_CHELSIO_T1=m
+CONFIG_CHELSIO_T1_1G=y
+CONFIG_CHELSIO_T3=m
+CONFIG_CHELSIO_T4=m
+CONFIG_CHELSIO_T4VF=m
+CONFIG_CHELSIO_T4_DCB=y
+CONFIG_CHELSIO_T4_FCOE=y
+CONFIG_CHROMEOS_LAPTOP=m
+CONFIG_CHROMEOS_PSTORE=m
+CONFIG_CHROME_PLATFORMS=y
+CONFIG_CHR_DEV_OSST=m
+CONFIG_CHR_DEV_SCH=m
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHSC_SCH=m
+CONFIG_CICADA_PHY=m
+CONFIG_CIFS=m
+CONFIG_CIFS_ACL=y
+CONFIG_CIFS_DEBUG=y
+# CONFIG_CIFS_DEBUG2 is not set
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_SMB2=y
+CONFIG_CIFS_SMB311=y
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_CLEANCACHE=y
+CONFIG_CLKBLD_I8253=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKEVT_I8253=y
+CONFIG_CLKSRC_ACPI=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_CLK_QORIQ=y
+CONFIG_CLK_SP810=y
+CONFIG_CLK_TWL6040=m
+CONFIG_CLK_VEXPRESS_OSC=y
+CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+# CONFIG_CLOCK_THERMAL is not set
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CLONE_BACKWARDS2=y
+CONFIG_CLS_U32_MARK=y
+# CONFIG_CLS_U32_PERF is not set
+CONFIG_CLZ_TAB=y
+CONFIG_CM32181=m
+CONFIG_CM3232=m
+CONFIG_CM3323=m
+CONFIG_CM36651=m
+CONFIG_CMA_AREAS=7
+# CONFIG_CMA_DEBUG is not set
+# CONFIG_CMA_DEBUGFS is not set
+CONFIG_CMDLINE="console=ttyAMA0"
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_CMDLINE_FORCE is not set
+CONFIG_CMM=y
+CONFIG_CMM_IUCV=y
+CONFIG_CNIC=m
+CONFIG_CODA_FS=m
+CONFIG_COMEDI=m
+CONFIG_COMEDI_8254=m
+CONFIG_COMEDI_8255=m
+CONFIG_COMEDI_8255_PCI=m
+CONFIG_COMEDI_8255_SA=m
+CONFIG_COMEDI_ADDI_APCI_1032=m
+CONFIG_COMEDI_ADDI_APCI_1500=m
+CONFIG_COMEDI_ADDI_APCI_1516=m
+CONFIG_COMEDI_ADDI_APCI_1564=m
+CONFIG_COMEDI_ADDI_APCI_16XX=m
+CONFIG_COMEDI_ADDI_APCI_2032=m
+CONFIG_COMEDI_ADDI_APCI_2200=m
+CONFIG_COMEDI_ADDI_APCI_3120=m
+CONFIG_COMEDI_ADDI_APCI_3501=m
+CONFIG_COMEDI_ADDI_APCI_3XXX=m
+CONFIG_COMEDI_ADDI_WATCHDOG=m
+CONFIG_COMEDI_ADL_PCI6208=m
+CONFIG_COMEDI_ADL_PCI7X3X=m
+CONFIG_COMEDI_ADL_PCI8164=m
+CONFIG_COMEDI_ADL_PCI9111=m
+CONFIG_COMEDI_ADL_PCI9118=m
+CONFIG_COMEDI_ADQ12B=m
+CONFIG_COMEDI_ADV_PCI1710=m
+CONFIG_COMEDI_ADV_PCI1723=m
+CONFIG_COMEDI_ADV_PCI1724=m
+CONFIG_COMEDI_ADV_PCI_DIO=m
+CONFIG_COMEDI_AIO_AIO12_8=m
+CONFIG_COMEDI_AIO_IIRO_16=m
+CONFIG_COMEDI_AMPLC_DIO200=m
+CONFIG_COMEDI_AMPLC_DIO200_ISA=m
+CONFIG_COMEDI_AMPLC_DIO200_PCI=m
+CONFIG_COMEDI_AMPLC_PC236=m
+CONFIG_COMEDI_AMPLC_PC236_ISA=m
+CONFIG_COMEDI_AMPLC_PC236_PCI=m
+CONFIG_COMEDI_AMPLC_PC263_ISA=m
+CONFIG_COMEDI_AMPLC_PC263_PCI=m
+CONFIG_COMEDI_AMPLC_PCI224=m
+CONFIG_COMEDI_AMPLC_PCI230=m
+CONFIG_COMEDI_BOND=m
+CONFIG_COMEDI_C6XDIGIO=m
+CONFIG_COMEDI_CB_DAS16_CS=m
+CONFIG_COMEDI_CB_PCIDAS=m
+CONFIG_COMEDI_CB_PCIDAS64=m
+CONFIG_COMEDI_CB_PCIDDA=m
+CONFIG_COMEDI_CB_PCIMDAS=m
+CONFIG_COMEDI_CB_PCIMDDA=m
+CONFIG_COMEDI_CONTEC_PCI_DIO=m
+CONFIG_COMEDI_DAC02=m
+CONFIG_COMEDI_DAQBOARD2000=m
+CONFIG_COMEDI_DAS08=m
+CONFIG_COMEDI_DAS08_CS=m
+CONFIG_COMEDI_DAS08_ISA=m
+CONFIG_COMEDI_DAS08_PCI=m
+CONFIG_COMEDI_DAS16=m
+CONFIG_COMEDI_DAS16M1=m
+CONFIG_COMEDI_DAS1800=m
+CONFIG_COMEDI_DAS6402=m
+CONFIG_COMEDI_DAS800=m
+# CONFIG_COMEDI_DEBUG is not set
+CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB=20480
+CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB=2048
+CONFIG_COMEDI_DMM32AT=m
+CONFIG_COMEDI_DT2801=m
+CONFIG_COMEDI_DT2811=m
+CONFIG_COMEDI_DT2814=m
+CONFIG_COMEDI_DT2815=m
+CONFIG_COMEDI_DT2817=m
+CONFIG_COMEDI_DT282X=m
+CONFIG_COMEDI_DT3000=m
+CONFIG_COMEDI_DT9812=m
+CONFIG_COMEDI_DYNA_PCI10XX=m
+CONFIG_COMEDI_FL512=m
+CONFIG_COMEDI_GSC_HPDI=m
+CONFIG_COMEDI_ICP_MULTI=m
+CONFIG_COMEDI_II_PCI20KC=m
+CONFIG_COMEDI_ISADMA=m
+CONFIG_COMEDI_ISA_DRIVERS=y
+CONFIG_COMEDI_JR3_PCI=m
+CONFIG_COMEDI_KCOMEDILIB=m
+CONFIG_COMEDI_KE_COUNTER=m
+CONFIG_COMEDI_ME4000=m
+CONFIG_COMEDI_ME_DAQ=m
+CONFIG_COMEDI_MF6X4=m
+CONFIG_COMEDI_MISC_DRIVERS=y
+CONFIG_COMEDI_MITE=m
+CONFIG_COMEDI_MPC624=m
+CONFIG_COMEDI_MULTIQ3=m
+CONFIG_COMEDI_NI_6527=m
+CONFIG_COMEDI_NI_65XX=m
+CONFIG_COMEDI_NI_660X=m
+CONFIG_COMEDI_NI_670X=m
+CONFIG_COMEDI_NI_ATMIO=m
+CONFIG_COMEDI_NI_ATMIO16D=m
+CONFIG_COMEDI_NI_AT_A2150=m
+CONFIG_COMEDI_NI_AT_AO=m
+CONFIG_COMEDI_NI_DAQ_700_CS=m
+CONFIG_COMEDI_NI_DAQ_DIO24_CS=m
+CONFIG_COMEDI_NI_LABPC=m
+CONFIG_COMEDI_NI_LABPC_CS=m
+CONFIG_COMEDI_NI_LABPC_ISA=m
+CONFIG_COMEDI_NI_LABPC_ISADMA=m
+CONFIG_COMEDI_NI_LABPC_PCI=m
+CONFIG_COMEDI_NI_MIO_CS=m
+CONFIG_COMEDI_NI_PCIDIO=m
+CONFIG_COMEDI_NI_PCIMIO=m
+CONFIG_COMEDI_NI_TIO=m
+CONFIG_COMEDI_NI_TIOCMD=m
+CONFIG_COMEDI_NI_USB6501=m
+CONFIG_COMEDI_PARPORT=m
+CONFIG_COMEDI_PCI_DRIVERS=m
+CONFIG_COMEDI_PCL711=m
+CONFIG_COMEDI_PCL724=m
+CONFIG_COMEDI_PCL726=m
+CONFIG_COMEDI_PCL730=m
+CONFIG_COMEDI_PCL812=m
+CONFIG_COMEDI_PCL816=m
+CONFIG_COMEDI_PCL818=m
+CONFIG_COMEDI_PCM3724=m
+CONFIG_COMEDI_PCMAD=m
+CONFIG_COMEDI_PCMCIA_DRIVERS=m
+CONFIG_COMEDI_PCMDA12=m
+CONFIG_COMEDI_PCMMIO=m
+CONFIG_COMEDI_PCMUIO=m
+CONFIG_COMEDI_QUATECH_DAQP_CS=m
+CONFIG_COMEDI_RTD520=m
+CONFIG_COMEDI_RTI800=m
+CONFIG_COMEDI_RTI802=m
+CONFIG_COMEDI_S526=m
+CONFIG_COMEDI_S626=m
+CONFIG_COMEDI_SERIAL2002=m
+CONFIG_COMEDI_TEST=m
+CONFIG_COMEDI_USBDUX=m
+CONFIG_COMEDI_USBDUXFAST=m
+CONFIG_COMEDI_USBDUXSIGMA=m
+CONFIG_COMEDI_USB_DRIVERS=m
+CONFIG_COMEDI_VMK80XX=m
+CONFIG_COMMON_CLK=y
+CONFIG_COMMON_CLK_CDCE706=m
+CONFIG_COMMON_CLK_CDCE925=m
+CONFIG_COMMON_CLK_HI6220=y
+CONFIG_COMMON_CLK_MAX77686=m
+CONFIG_COMMON_CLK_MAX77802=m
+CONFIG_COMMON_CLK_MAX_GEN=y
+CONFIG_COMMON_CLK_PALMAS=m
+CONFIG_COMMON_CLK_PWM=m
+# CONFIG_COMMON_CLK_PXA is not set
+CONFIG_COMMON_CLK_QCOM=m
+CONFIG_COMMON_CLK_RK808=m
+CONFIG_COMMON_CLK_S2MPS11=m
+CONFIG_COMMON_CLK_SCPI=m
+CONFIG_COMMON_CLK_SI514=m
+CONFIG_COMMON_CLK_SI5351=m
+CONFIG_COMMON_CLK_SI570=m
+CONFIG_COMMON_CLK_VERSATILE=y
+CONFIG_COMMON_CLK_WM831X=m
+CONFIG_COMMON_CLK_XGENE=y
+# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
+CONFIG_COMPACTION=y
+CONFIG_COMPAL_LAPTOP=m
+CONFIG_COMPAT=y
+CONFIG_COMPAT_BINFMT_ELF=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
+CONFIG_COMPAT_OLD_SIGACTION=y
+# CONFIG_COMPAT_VDSO is not set
+# CONFIG_COMPILE_TEST is not set
+CONFIG_CONNECTOR=y
+CONFIG_CONSOLE_POLL=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_CORDIC=m
+CONFIG_COREDUMP=y
+# CONFIG_CORESIGHT is not set
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_CP15_BARRIER_EMULATION=y
+# CONFIG_CPA_DEBUG is not set
+CONFIG_CPU5_WDT=m
+CONFIG_CPUFREQ_DT=y
+CONFIG_CPUSETS=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_CRASH_DUMP=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+# CONFIG_CRC32_BIT is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_SELFTEST is not set
+# CONFIG_CRC32_SLICEBY4 is not set
+CONFIG_CRC32_SLICEBY8=y
+CONFIG_CRC7=m
+CONFIG_CRC8=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC_T10DIF=y
+CONFIG_CROSS_COMPILE=""
+CONFIG_CROSS_MEMORY_ATTACH=y
+CONFIG_CROS_EC_CHARDEV=m
+CONFIG_CROS_EC_LPC=m
+CONFIG_CROS_EC_PROTO=y
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_842=m
+CONFIG_CRYPTO_ABLK_HELPER=m
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_AES_ARM64_CE=m
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=m
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=m
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK=m
+CONFIG_CRYPTO_AES_NI_INTEL=m
+CONFIG_CRYPTO_AES_S390=m
+CONFIG_CRYPTO_AES_X86_64=m
+CONFIG_CRYPTO_AKCIPHER=y
+CONFIG_CRYPTO_AKCIPHER2=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_BLOWFISH_COMMON=m
+CONFIG_CRYPTO_BLOWFISH_X86_64=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=m
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64=m
+CONFIG_CRYPTO_CAMELLIA_X86_64=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST5_AVX_X86_64=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_CAST6_AVX_X86_64=m
+CONFIG_CRYPTO_CAST_COMMON=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_CHACHA20=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_CHACHA20_X86_64=m
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_CRC32=m
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_CRC32C_INTEL=y
+CONFIG_CRYPTO_CRC32_ARM64=m
+CONFIG_CRYPTO_CRC32_PCLMUL=m
+CONFIG_CRYPTO_CRCT10DIF=y
+CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_DES3_EDE_X86_64=m
+CONFIG_CRYPTO_DES_S390=m
+CONFIG_CRYPTO_DEV_CCP=y
+CONFIG_CRYPTO_DEV_CCP_CRYPTO=m
+CONFIG_CRYPTO_DEV_CCP_DD=m
+CONFIG_CRYPTO_DEV_PADLOCK=y
+CONFIG_CRYPTO_DEV_PADLOCK_AES=m
+CONFIG_CRYPTO_DEV_PADLOCK_SHA=m
+CONFIG_CRYPTO_DEV_QAT=m
+CONFIG_CRYPTO_DEV_QAT_DH895xCC=m
+CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m
+CONFIG_CRYPTO_DEV_QCE=m
+# CONFIG_CRYPTO_DH is not set
+CONFIG_CRYPTO_DRBG=m
+CONFIG_CRYPTO_DRBG_CTR=y
+CONFIG_CRYPTO_DRBG_HASH=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=m
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECHAINIV=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_GHASH_ARM64_CE=m
+CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m
+CONFIG_CRYPTO_GHASH_S390=m
+CONFIG_CRYPTO_GLUE_HELPER_X86=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_JITTERENTROPY=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_KPP2=y
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_LZ4HC=m
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_MCRYPTD=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_POLY1305=m
+CONFIG_CRYPTO_POLY1305_X86_64=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=m
+CONFIG_CRYPTO_RSA=y
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SALSA20_X86_64=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SEQIV=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_SERPENT_AVX2_X86_64=m
+CONFIG_CRYPTO_SERPENT_AVX_X86_64=m
+CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=m
+CONFIG_CRYPTO_SHA1_MB=m
+CONFIG_CRYPTO_SHA1_S390=m
+CONFIG_CRYPTO_SHA1_SSSE3=m
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA256_S390=m
+CONFIG_CRYPTO_SHA256_SSSE3=m
+CONFIG_CRYPTO_SHA2_ARM64_CE=m
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_SHA512_S390=m
+CONFIG_CRYPTO_SHA512_SSSE3=m
+CONFIG_CRYPTO_SKEIN=y
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+CONFIG_CRYPTO_TWOFISH_X86_64=m
+CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_USER_API=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CTCM=m
+CONFIG_CUSE=m
+CONFIG_CW1200=m
+CONFIG_CW1200_WLAN_SDIO=m
+CONFIG_CW1200_WLAN_SPI=m
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_KERNEL_API is not set
+CONFIG_CX_ECAT=m
+CONFIG_CYCLADES=m
+CONFIG_CYPRESS_FIRMWARE=m
+# CONFIG_CYZ_INTR is not set
+CONFIG_DA9052_WATCHDOG=m
+CONFIG_DA9055_WATCHDOG=m
+CONFIG_DA9062_WATCHDOG=m
+CONFIG_DA9063_WATCHDOG=m
+CONFIG_DA9150_GPADC=m
+CONFIG_DASD=m
+CONFIG_DASD_DIAG=m
+CONFIG_DASD_ECKD=m
+CONFIG_DASD_EER=y
+CONFIG_DASD_FBA=m
+CONFIG_DASD_PROFILE=y
+CONFIG_DAVICOM_PHY=m
+CONFIG_DCA=m
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DCB=y
+CONFIG_DCDBAS=m
+CONFIG_DCSSBLK=m
+CONFIG_DDR=y
+CONFIG_DE2104X=m
+CONFIG_DE2104X_DSL=0
+CONFIG_DE4X5=m
+# CONFIG_DEBUG_ALIGN_RODATA is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_BLK_CGROUP is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_BOOT_PARAMS is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_ENTRY is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_DEBUG_HOTPLUG_CPU0 is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF4=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
+# CONFIG_DEBUG_INFO_SPLIT is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_NMI_SELFTEST is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_NX_TEST is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_DEBUG_PINCTRL is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_RODATA=y
+# CONFIG_DEBUG_RODATA_TEST is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_SET_MODULE_RONX=y
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_TIMEKEEPING is not set
+# CONFIG_DEBUG_TLBFLUSH is not set
+# CONFIG_DEBUG_VIRTUAL is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_WX is not set
+CONFIG_DECNET_NF_GRABULATOR=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_LZ4=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_DECOMPRESS_XZ=y
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_CUBIC=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_DEFAULT_IO_DELAY_TYPE=1
+# CONFIG_DEFAULT_NOOP is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_SECURITY="apparmor"
+CONFIG_DEFAULT_SECURITY_APPARMOR=y
+# CONFIG_DEFAULT_SECURITY_DAC is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
+CONFIG_DEFXX=m
+# CONFIG_DEFXX_MMIO is not set
+CONFIG_DELL_LAPTOP=m
+CONFIG_DELL_RBTN=m
+CONFIG_DELL_RBU=m
+CONFIG_DELL_SMO8800=m
+CONFIG_DELL_WMI=m
+CONFIG_DELL_WMI_AIO=m
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEVFREQ_GOV_PERFORMANCE=y
+CONFIG_DEVFREQ_GOV_POWERSAVE=y
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_DEVFREQ_GOV_USERSPACE=y
+CONFIG_DEVFREQ_THERMAL=y
+# CONFIG_DEVKMEM is not set
+CONFIG_DEVMEM=y
+CONFIG_DEVPORT=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DEV_APPLETALK=m
+CONFIG_DEV_COREDUMP=y
+CONFIG_DE_AOC=y
+CONFIG_DGAP=m
+CONFIG_DGNC=m
+CONFIG_DHT11=m
+CONFIG_DIAG288_WATCHDOG=m
+CONFIG_DIMLIB=y
+CONFIG_DL2K=m
+CONFIG_DLCI=m
+CONFIG_DLCI_MAX=8
+CONFIG_DLM=m
+# CONFIG_DLM_DEBUG is not set
+CONFIG_DM9102=m
+# CONFIG_DMADEVICES_DEBUG is not set
+CONFIG_DMAR_TABLE=y
+# CONFIG_DMATEST is not set
+CONFIG_DMA_ACPI=y
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_CMA is not set
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_ENGINE_RAID=y
+CONFIG_DMA_OF=y
+CONFIG_DMI=y
+CONFIG_DMIID=y
+CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
+CONFIG_DMI_SYSFS=m
+CONFIG_DM_BIO_PRISON=m
+CONFIG_DM_BUFIO=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_CACHE_CLEANER=m
+CONFIG_DM_CACHE_MQ=m
+CONFIG_DM_CACHE_SMQ=m
+CONFIG_DM_CRYPT=m
+# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set
+CONFIG_DM_DELAY=m
+CONFIG_DM_ERA=m
+CONFIG_DM_FLAKEY=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_LOG_WRITES=m
+CONFIG_DM_MIRROR=m
+# CONFIG_DM_MQ_DEFAULT is not set
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_PERSISTENT_DATA=m
+CONFIG_DM_RAID=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_SWITCH=m
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=m
+CONFIG_DM_ZERO=m
+CONFIG_DNOTIFY=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_DONGLE=y
+CONFIG_DOUBLEFAULT=y
+CONFIG_DP83848_PHY=m
+CONFIG_DP83867_PHY=m
+# CONFIG_DPM_WATCHDOG is not set
+CONFIG_DQL=y
+CONFIG_DRAGONRISE_FF=y
+# CONFIG_DRBD_FAULT_INJECTION is not set
+CONFIG_DRM_AMDGPU=m
+# CONFIG_DRM_AMDGPU_CIK is not set
+CONFIG_DRM_AMDGPU_USERPTR=y
+CONFIG_DRM_AMD_POWERPLAY=y
+CONFIG_DRM_AST=m
+# CONFIG_DRM_BOCHS is not set
+CONFIG_DRM_BRIDGE=y
+CONFIG_DRM_CIRRUS_QEMU=m
+CONFIG_DRM_DP_AUX_CHARDEV=y
+CONFIG_DRM_FBDEV_EMULATION=y
+CONFIG_DRM_GMA3600=y
+CONFIG_DRM_GMA500=m
+CONFIG_DRM_GMA600=y
+CONFIG_DRM_I2C_ADV7511=m
+CONFIG_DRM_I2C_CH7006=m
+CONFIG_DRM_I2C_NXP_TDA998X=m
+CONFIG_DRM_I2C_SIL164=m
+CONFIG_DRM_I810=m
+CONFIG_DRM_I915=m
+CONFIG_DRM_I915_BPO=m
+# CONFIG_DRM_I915_BPO_DEBUG is not set
+# CONFIG_DRM_I915_BPO_PRELIMINARY_HW_SUPPORT is not set
+CONFIG_DRM_I915_BPO_USERPTR=y
+# CONFIG_DRM_I915_BPO_WERROR is not set
+# CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT is not set
+CONFIG_DRM_KMS_FB_HELPER=y
+CONFIG_DRM_KMS_HELPER=m
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_MGA=m
+# CONFIG_DRM_MGAG200 is not set
+CONFIG_DRM_MIPI_DSI=y
+CONFIG_DRM_MSM=m
+CONFIG_DRM_MSM_DSI=y
+CONFIG_DRM_MSM_DSI_20NM_PHY=y
+CONFIG_DRM_MSM_DSI_28NM_PHY=y
+CONFIG_DRM_MSM_DSI_PLL=y
+CONFIG_DRM_MSM_REGISTER_LOGGING=y
+CONFIG_DRM_NOUVEAU=m
+CONFIG_DRM_NOUVEAU_BACKLIGHT=y
+CONFIG_DRM_NXP_PTN3460=m
+CONFIG_DRM_PANEL=y
+CONFIG_DRM_PANEL_LG_LG4573=m
+CONFIG_DRM_PANEL_SAMSUNG_LD9040=m
+CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m
+CONFIG_DRM_PANEL_SHARP_LQ101R1SX01=m
+CONFIG_DRM_PANEL_SIMPLE=m
+CONFIG_DRM_PARADE_PS8622=m
+CONFIG_DRM_QXL=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+# CONFIG_DRM_RADEON_UMS is not set
+# CONFIG_DRM_RADEON_USERPTR is not set
+CONFIG_DRM_SAVAGE=m
+CONFIG_DRM_SIS=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_TTM=m
+CONFIG_DRM_UDL=m
+CONFIG_DRM_VGEM=m
+CONFIG_DRM_VIA=m
+CONFIG_DRM_VIRTIO_GPU=m
+CONFIG_DRM_VMWGFX=m
+CONFIG_DRM_VMWGFX_FBCON=y
+CONFIG_DS1682=m
+CONFIG_DSCC4=m
+CONFIG_DSCC4_PCISYNC=y
+CONFIG_DSCC4_PCI_RST=y
+CONFIG_DST_CACHE=y
+CONFIG_DTC=y
+CONFIG_DT_IDLE_STATES=y
+CONFIG_DUMMY=m
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+CONFIG_DVB_A8293=m
+CONFIG_DVB_AF9013=m
+CONFIG_DVB_AF9033=m
+CONFIG_DVB_AS102=m
+CONFIG_DVB_AS102_FE=m
+CONFIG_DVB_ASCOT2E=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_AU8522=m
+CONFIG_DVB_AU8522_DTV=m
+CONFIG_DVB_AU8522_V4L=m
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_IR=y
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_PCI=m
+# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_BT8XX=m
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_CORE=m
+CONFIG_DVB_BUDGET_PATCH=m
+CONFIG_DVB_CORE=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_CX24117=m
+CONFIG_DVB_CX24120=m
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_CXD2099=m
+CONFIG_DVB_CXD2820R=m
+CONFIG_DVB_CXD2841ER=m
+CONFIG_DVB_DDBRIDGE=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_DIB8000=m
+CONFIG_DVB_DM1105=m
+CONFIG_DVB_DRX39XYJ=m
+CONFIG_DVB_DRXD=m
+CONFIG_DVB_DRXK=m
+CONFIG_DVB_DS3000=m
+# CONFIG_DVB_DUMMY_FE is not set
+CONFIG_DVB_DYNAMIC_MINORS=y
+CONFIG_DVB_EC100=m
+CONFIG_DVB_FIREDTV=m
+CONFIG_DVB_FIREDTV_INPUT=y
+CONFIG_DVB_HOPPER=m
+CONFIG_DVB_HORUS3A=m
+CONFIG_DVB_ISL6405=m
+CONFIG_DVB_ISL6421=m
+CONFIG_DVB_ISL6423=m
+CONFIG_DVB_IX2505V=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_LG2160=m
+CONFIG_DVB_LGDT3305=m
+CONFIG_DVB_LGDT3306A=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_LNBH25=m
+CONFIG_DVB_LNBP21=m
+CONFIG_DVB_LNBP22=m
+CONFIG_DVB_M88DS3103=m
+CONFIG_DVB_M88RS2000=m
+CONFIG_DVB_MANTIS=m
+CONFIG_DVB_MAX_ADAPTERS=8
+CONFIG_DVB_MB86A16=m
+CONFIG_DVB_MB86A20S=m
+CONFIG_DVB_MN88472=m
+CONFIG_DVB_MN88473=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_NET=y
+CONFIG_DVB_NETUP_UNIDVB=m
+CONFIG_DVB_NGENE=m
+CONFIG_DVB_NXT200X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_OR51132=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_PLATFORM_DRIVERS=y
+CONFIG_DVB_PLL=m
+CONFIG_DVB_PLUTO2=m
+CONFIG_DVB_PT1=m
+CONFIG_DVB_PT3=m
+CONFIG_DVB_RTL2830=m
+CONFIG_DVB_RTL2832=m
+CONFIG_DVB_RTL2832_SDR=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_S5H1411=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_S921=m
+CONFIG_DVB_SI2165=m
+CONFIG_DVB_SI2168=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_SMIPCIE=m
+CONFIG_DVB_SP2=m
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_STB0899=m
+CONFIG_DVB_STB6000=m
+CONFIG_DVB_STB6100=m
+CONFIG_DVB_STV0288=m
+CONFIG_DVB_STV0297=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_STV0367=m
+CONFIG_DVB_STV0900=m
+CONFIG_DVB_STV090x=m
+CONFIG_DVB_STV6110=m
+CONFIG_DVB_STV6110x=m
+CONFIG_DVB_TC90522=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_TDA10048=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_TDA10071=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_TDA18271C2DD=m
+CONFIG_DVB_TDA665x=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA8261=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_TS2020=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_TUA6100=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TUNER_DIB0070=m
+CONFIG_DVB_TUNER_DIB0090=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_AF9035=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_AZ6007=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_CXUSB=m
+# CONFIG_DVB_USB_DEBUG is not set
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_DVBSKY=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_FRIIO=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_MXL111SF=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_PCTV452E=m
+CONFIG_DVB_USB_RTL28XXU=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_V2=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_ZL10036=m
+CONFIG_DVB_ZL10039=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DWMAC_GENERIC=m
+CONFIG_DWMAC_IPQ806X=m
+CONFIG_DWMAC_LPC18XX=m
+CONFIG_DWMAC_MESON=m
+CONFIG_DWMAC_ROCKCHIP=m
+CONFIG_DWMAC_SOCFPGA=m
+CONFIG_DWMAC_STI=m
+CONFIG_DWMAC_SUNXI=m
+CONFIG_DW_APB_ICTL=y
+CONFIG_DW_APB_TIMER=y
+CONFIG_DW_APB_TIMER_OF=y
+CONFIG_DW_DMAC=m
+CONFIG_DW_DMAC_CORE=m
+CONFIG_DW_DMAC_PCI=m
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DYNAMIC_FTRACE=y
+CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_E100=m
+CONFIG_E1000=m
+CONFIG_E1000E=m
+CONFIG_E1000E_HWTS=y
+CONFIG_EADM_SCH=m
+CONFIG_EARLY_PRINTK=y
+CONFIG_EARLY_PRINTK_DBGP=y
+CONFIG_EARLY_PRINTK_EFI=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_EDAC=y
+CONFIG_EDAC_AMD64=m
+# CONFIG_EDAC_AMD64_ERROR_INJECTION is not set
+CONFIG_EDAC_ATOMIC_SCRUB=y
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_DECODE_MCE=m
+CONFIG_EDAC_E752X=m
+CONFIG_EDAC_I3000=m
+CONFIG_EDAC_I3200=m
+CONFIG_EDAC_I5000=m
+CONFIG_EDAC_I5100=m
+CONFIG_EDAC_I5400=m
+CONFIG_EDAC_I7300=m
+CONFIG_EDAC_I7CORE=m
+CONFIG_EDAC_I82975X=m
+CONFIG_EDAC_IE31200=m
+# CONFIG_EDAC_LEGACY_SYSFS is not set
+CONFIG_EDAC_MM_EDAC=m
+CONFIG_EDAC_SBRIDGE=m
+CONFIG_EDAC_SKX=m
+CONFIG_EDAC_SUPPORT=y
+CONFIG_EDAC_X38=m
+CONFIG_EDAC_XGENE=m
+CONFIG_EDD=y
+CONFIG_EDD_OFF=y
+CONFIG_EEEPC_LAPTOP=m
+CONFIG_EEEPC_WMI=m
+CONFIG_EEPROM_93XX46=m
+CONFIG_EEPROM_AT24=m
+CONFIG_EEPROM_AT25=m
+CONFIG_EEPROM_LEGACY=m
+CONFIG_EEPROM_MAX6875=m
+CONFIG_EFI=y
+CONFIG_EFIVAR_FS=y
+CONFIG_EFI_ARMSTUB=y
+CONFIG_EFI_ESRT=y
+# CONFIG_EFI_FAKE_MEMMAP is not set
+CONFIG_EFI_MIXED=y
+CONFIG_EFI_PARAMS_FROM_FDT=y
+CONFIG_EFI_PARTITION=y
+# CONFIG_EFI_PGT_DUMP is not set
+CONFIG_EFI_RUNTIME_MAP=y
+CONFIG_EFI_RUNTIME_WRAPPERS=y
+CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE=y
+CONFIG_EFI_SIGNATURE_LIST_PARSER=y
+CONFIG_EFI_STUB=y
+CONFIG_EFI_TEST=m
+CONFIG_EFI_VARS=y
+CONFIG_EFI_VARS_PSTORE=m
+# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set
+CONFIG_ELFCORE=y
+CONFIG_ELF_CORE=y
+CONFIG_EMAC_ROCKCHIP=m
+# CONFIG_EMBEDDED is not set
+CONFIG_EMU_SIZE=0x10000000
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_ENA_ETHERNET=m
+CONFIG_ENC28J60=m
+# CONFIG_ENC28J60_WRITEVERIFY is not set
+CONFIG_ENCRYPTED_KEYS=y
+CONFIG_ENCX24J600=m
+CONFIG_ENIC=m
+CONFIG_EPIC100=m
+CONFIG_EPOLL=y
+CONFIG_EQUALIZER=m
+CONFIG_ESI_DONGLE=m
+CONFIG_ET131X=m
+CONFIG_ETHERNET=y
+CONFIG_EUROTECH_WDT=m
+CONFIG_EVENTFD=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EVM=y
+CONFIG_EVM_ATTR_FSUUID=y
+CONFIG_EVM_EXTRA_SMACK_XATTRS=y
+# CONFIG_EXOFS_DEBUG is not set
+CONFIG_EXPERT=y
+CONFIG_EXPOLINE=y
+CONFIG_EXPOLINE_AUTO=y
+# CONFIG_EXPOLINE_FULL is not set
+# CONFIG_EXPOLINE_OFF is not set
+CONFIG_EXPORTFS=y
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_EXT4_ENCRYPTION=m
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_USE_FOR_EXT2=y
+CONFIG_EXTCON_ADC_JACK=m
+CONFIG_EXTCON_ARIZONA=m
+CONFIG_EXTCON_AXP288=m
+CONFIG_EXTCON_GPIO=m
+CONFIG_EXTCON_MAX14577=m
+CONFIG_EXTCON_MAX77693=m
+CONFIG_EXTCON_MAX77843=m
+CONFIG_EXTCON_MAX8997=m
+CONFIG_EXTCON_PALMAS=m
+CONFIG_EXTCON_RT8973A=m
+CONFIG_EXTCON_SM5502=m
+CONFIG_EXTCON_USB_GPIO=m
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_EZCHIP_NPS_MANAGEMENT_ENET=m
+CONFIG_EZX_PCAP=y
+# CONFIG_F2FS_CHECK_FS is not set
+CONFIG_F2FS_FS_ENCRYPTION=y
+CONFIG_F2FS_FS_POSIX_ACL=y
+CONFIG_F2FS_FS_SECURITY=y
+CONFIG_F2FS_FS_XATTR=y
+# CONFIG_F2FS_IO_TRACE is not set
+CONFIG_F2FS_STAT_FS=y
+CONFIG_F71808E_WDT=m
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FANOTIFY=y
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
+CONFIG_FARSYNC=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_FAT_FS=y
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_ACCEL is not set
+# CONFIG_FB_3DFX_I2C is not set
+CONFIG_FB_ARC=m
+CONFIG_FB_ARK=m
+CONFIG_FB_ARMCLCD=y
+CONFIG_FB_ASILIANT=y
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY128_BACKLIGHT=y
+CONFIG_FB_ATY_BACKLIGHT=y
+CONFIG_FB_ATY_CT=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+CONFIG_FB_ATY_GX=y
+CONFIG_FB_AUO_K1900=m
+CONFIG_FB_AUO_K1901=m
+CONFIG_FB_AUO_K190X=m
+CONFIG_FB_BACKLIGHT=y
+CONFIG_FB_BROADSHEET=m
+CONFIG_FB_CARILLO_RANCH=m
+CONFIG_FB_CARMINE=m
+CONFIG_FB_CARMINE_DRAM_EVAL=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_CIRRUS=m
+CONFIG_FB_CMDLINE=y
+CONFIG_FB_CYBER2000=m
+CONFIG_FB_CYBER2000_DDC=y
+CONFIG_FB_DDC=m
+CONFIG_FB_DEFERRED_IO=y
+CONFIG_FB_EFI=y
+CONFIG_FB_FLEX=m
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_HECUBA=m
+CONFIG_FB_HGA=m
+CONFIG_FB_HYPERV=m
+CONFIG_FB_I740=m
+CONFIG_FB_IBM_GXT4500=m
+CONFIG_FB_IMSTT=y
+CONFIG_FB_INTEL=m
+# CONFIG_FB_INTEL_DEBUG is not set
+CONFIG_FB_INTEL_I2C=y
+CONFIG_FB_KYRO=m
+CONFIG_FB_LE80578=m
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MB862XX=m
+CONFIG_FB_MB862XX_I2C=y
+CONFIG_FB_MB862XX_PCI_GDC=y
+CONFIG_FB_METRONOME=m
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_N411=m
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_NVIDIA=m
+CONFIG_FB_NVIDIA_BACKLIGHT=y
+# CONFIG_FB_NVIDIA_DEBUG is not set
+CONFIG_FB_NVIDIA_I2C=y
+CONFIG_FB_OPENCORES=m
+CONFIG_FB_PM2=m
+CONFIG_FB_PM2_FIFO_DISCONNECT=y
+CONFIG_FB_PM3=m
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_BACKLIGHT=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_RADEON_I2C=y
+CONFIG_FB_RIVA=m
+CONFIG_FB_RIVA_BACKLIGHT=y
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_RIVA_I2C=y
+CONFIG_FB_S1D13XXX=m
+CONFIG_FB_S3=m
+CONFIG_FB_S3_DDC=y
+CONFIG_FB_SAVAGE=m
+# CONFIG_FB_SAVAGE_ACCEL is not set
+CONFIG_FB_SAVAGE_I2C=y
+CONFIG_FB_SIMPLE=y
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_SM501=m
+CONFIG_FB_SM712=m
+CONFIG_FB_SM750=m
+CONFIG_FB_SMSCUFX=m
+CONFIG_FB_SSD1307=m
+CONFIG_FB_SVGALIB=m
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_FBTFT_DEVICE=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_HX8357D=m
+CONFIG_FB_TFT_ILI9163=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_ST7789V=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1611=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_FB_TFT_WATTEROTT=m
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_UDL=m
+CONFIG_FB_UVESA=m
+CONFIG_FB_VESA=y
+CONFIG_FB_VGA16=m
+CONFIG_FB_VIA=m
+# CONFIG_FB_VIA_DIRECT_PROCFS is not set
+CONFIG_FB_VIA_X_COMPATIBILITY=y
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_VT8623=m
+CONFIG_FB_XGI=m
+CONFIG_FCOE=m
+CONFIG_FCOE_FNIC=m
+# CONFIG_FENCE_TRACE is not set
+CONFIG_FHANDLE=y
+CONFIG_FIB_RULES=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FIREWIRE_NET=m
+CONFIG_FIREWIRE_OHCI=m
+CONFIG_FIREWIRE_SBP2=m
+CONFIG_FIREWIRE_SERIAL=m
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FM10K=m
+CONFIG_FM10K_VXLAN=y
+CONFIG_FMC_CHARDEV=m
+CONFIG_FMC_FAKEDEV=m
+CONFIG_FMC_TRIVIAL=m
+CONFIG_FMC_WRITE_EEPROM=m
+CONFIG_FONTS=y
+# CONFIG_FONT_10x18 is not set
+CONFIG_FONT_6x10=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_ACORN_8x8=y
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_SUN8x16 is not set
+CONFIG_FONT_SUPPORT=y
+CONFIG_FONT_TER16x32=y
+CONFIG_FORCEDETH=m
+CONFIG_FPGA=m
+CONFIG_FPGA_MGR_ZYNQ_FPGA=m
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FRAME_VECTOR=y
+CONFIG_FRAME_WARN=1024
+CONFIG_FREEZER=y
+CONFIG_FRONTSWAP=y
+CONFIG_FSCACHE=m
+# CONFIG_FSCACHE_DEBUG is not set
+# CONFIG_FSCACHE_HISTOGRAM is not set
+# CONFIG_FSCACHE_OBJECT_LIST is not set
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSL_EDMA=m
+CONFIG_FSL_MC_BUS=m
+CONFIG_FSL_PQ_MDIO=m
+CONFIG_FSL_XGMAC_MDIO=y
+CONFIG_FSNOTIFY=y
+CONFIG_FS_DAX=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FTL=m
+CONFIG_FTRACE=y
+CONFIG_FTRACE_MCOUNT_RECORD=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_FUJITSU_ES=m
+CONFIG_FUJITSU_LAPTOP=m
+# CONFIG_FUJITSU_LAPTOP_DEBUG is not set
+CONFIG_FUJITSU_TABLET=m
+CONFIG_FUNCTION_GRAPH_TRACER=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_FUSE_FS=y
+CONFIG_FUSION_CTL=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_LAN=m
+CONFIG_FUSION_LOGGING=y
+CONFIG_FUSION_MAX_SGE=128
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_SPI=m
+CONFIG_FUTEX=y
+CONFIG_FWTTY_MAX_CARD_PORTS=32
+CONFIG_FWTTY_MAX_TOTAL_PORTS=64
+CONFIG_FW_LOADER=y
+CONFIG_FW_LOADER_USER_HELPER=y
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_GACT_PROB=y
+CONFIG_GADGET_UAC1=y
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GARP=m
+CONFIG_GART_IOMMU=y
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_GDB_SCRIPTS=y
+CONFIG_GENERIC_ADC_BATTERY=m
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_GENERIC_CPU_VULNERABILITIES=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_MIGRATION=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_GENEVE=m
+CONFIG_GENWQE=m
+CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY=0
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_GIANFAR=m
+CONFIG_GIGASET_BASE=m
+# CONFIG_GIGASET_CAPI is not set
+# CONFIG_GIGASET_DEBUG is not set
+# CONFIG_GIGASET_DUMMYLL is not set
+CONFIG_GIGASET_I4L=y
+CONFIG_GIGASET_M101=m
+CONFIG_GIGASET_M105=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_GLOB=y
+# CONFIG_GLOB_SELFTEST is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+CONFIG_GP2AP020A00F=m
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_104_IDIO_16=m
+CONFIG_GPIO_74X164=m
+CONFIG_GPIO_74XX_MMIO=m
+CONFIG_GPIO_ACPI=y
+CONFIG_GPIO_ADNP=m
+CONFIG_GPIO_ADP5520=m
+CONFIG_GPIO_ADP5588=m
+CONFIG_GPIO_ALTERA=m
+CONFIG_GPIO_AMD8111=m
+CONFIG_GPIO_AMDPT=m
+CONFIG_GPIO_ARIZONA=m
+CONFIG_GPIO_CRYSTAL_COVE=m
+CONFIG_GPIO_DA9052=m
+CONFIG_GPIO_DA9055=m
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_DLN2=m
+CONFIG_GPIO_DWAPB=m
+CONFIG_GPIO_F7188X=m
+CONFIG_GPIO_GRGPIO=m
+CONFIG_GPIO_ICH=m
+CONFIG_GPIO_INTEL_MID=y
+CONFIG_GPIO_IT87=m
+CONFIG_GPIO_JANZ_TTL=m
+CONFIG_GPIO_KEMPLD=m
+CONFIG_GPIO_LP3943=m
+CONFIG_GPIO_LYNXPOINT=y
+CONFIG_GPIO_MAX7300=m
+CONFIG_GPIO_MAX7301=m
+CONFIG_GPIO_MAX730X=m
+CONFIG_GPIO_MAX732X=m
+CONFIG_GPIO_MC33880=m
+CONFIG_GPIO_MCP23S08=m
+CONFIG_GPIO_ML_IOH=m
+CONFIG_GPIO_PALMAS=y
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_PL061=y
+CONFIG_GPIO_RC5T583=y
+CONFIG_GPIO_RDC321X=m
+CONFIG_GPIO_SCH=m
+CONFIG_GPIO_SCH311X=m
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_SX150X=y
+CONFIG_GPIO_SYSCON=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_TC3589X=y
+CONFIG_GPIO_TPS6586X=y
+CONFIG_GPIO_TPS65910=y
+CONFIG_GPIO_TPS65912=m
+CONFIG_GPIO_TWL4030=m
+CONFIG_GPIO_TWL6040=m
+CONFIG_GPIO_UCB1400=m
+CONFIG_GPIO_VIPERBOARD=m
+CONFIG_GPIO_VX855=m
+CONFIG_GPIO_WATCHDOG=m
+CONFIG_GPIO_WM831X=m
+CONFIG_GPIO_WM8350=m
+CONFIG_GPIO_WM8994=m
+CONFIG_GPIO_XGENE=y
+CONFIG_GPIO_XGENE_SB=m
+CONFIG_GPIO_XILINX=y
+CONFIG_GPIO_ZX=y
+CONFIG_GPIO_ZYNQ=m
+CONFIG_GRACE_PERIOD=m
+CONFIG_GREENASIA_FF=y
+CONFIG_GS_FPGABOOT=m
+CONFIG_HAMACHI=m
+CONFIG_HAMRADIO=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HANGCHECK_TIMER=m
+CONFIG_HAPPYMEAL=m
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HARDLOCKUP_DETECTOR=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAVE_ACPI_APEI=y
+CONFIG_HAVE_ACPI_APEI_NMI=y
+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
+# CONFIG_HAVE_AOUT is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KASAN=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_KMEMCHECK=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_SOFT_DIRTY=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_HAVE_ARM_SMCCC=y
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CMPXCHG_DOUBLE=y
+CONFIG_HAVE_CMPXCHG_LOCAL=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_COPY_THREAD_TLS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_BUGVERBOSE=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_HAVE_EBPF_JIT=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FENTRY=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUTEX_CMPXCHG=y
+CONFIG_HAVE_GENERIC_RCU_GUP=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_INTEL_TXT=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KPROBES_ON_FTRACE=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_KVM=y
+CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL=y
+CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y
+CONFIG_HAVE_KVM_EVENTFD=y
+CONFIG_HAVE_KVM_IRQCHIP=y
+CONFIG_HAVE_KVM_IRQFD=y
+CONFIG_HAVE_KVM_IRQ_BYPASS=y
+CONFIG_HAVE_KVM_IRQ_ROUTING=y
+CONFIG_HAVE_KVM_MSI=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_LIVEPATCH=y
+CONFIG_HAVE_MARCH_Z10_FEATURES=y
+# CONFIG_HAVE_MARCH_Z13_FEATURES is not set
+CONFIG_HAVE_MARCH_Z196_FEATURES=y
+CONFIG_HAVE_MARCH_Z900_FEATURES=y
+CONFIG_HAVE_MARCH_Z990_FEATURES=y
+CONFIG_HAVE_MARCH_Z9_109_FEATURES=y
+CONFIG_HAVE_MARCH_ZEC12_FEATURES=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MEMBLOCK_PHYS_MAP=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PATA_PLATFORM=y
+CONFIG_HAVE_PCSPKR_PLATFORM=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_EVENTS_NMI=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_RCU_TABLE_FREE=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HDC100X=m
+CONFIG_HDLC=m
+CONFIG_HDLC_CISCO=m
+CONFIG_HDLC_FR=m
+CONFIG_HDLC_PPP=m
+CONFIG_HDLC_RAW=m
+CONFIG_HDLC_RAW_ETH=m
+CONFIG_HDLC_X25=m
+CONFIG_HDMI=y
+CONFIG_HDM_DIM2=m
+CONFIG_HDM_I2C=m
+CONFIG_HDM_USB=m
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_HERMES=m
+CONFIG_HERMES_CACHE_FW_ON_INIT=y
+# CONFIG_HERMES_PRISM is not set
+# CONFIG_HFI1_DEBUG_SDMA_ORDER is not set
+CONFIG_HFI1_VERBS_31BIT_PSN=y
+CONFIG_HFSPLUS_FS_POSIX_ACL=y
+CONFIG_HI8435=m
+CONFIG_HIBERNATE_CALLBACKS=y
+CONFIG_HIBERNATION=y
+CONFIG_HID=m
+CONFIG_HIDRAW=y
+CONFIG_HID_A4TECH=m
+CONFIG_HID_ACRUX=m
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_ALPS=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_APPLEIR=m
+CONFIG_HID_AUREAL=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CORSAIR=m
+CONFIG_HID_CP2112=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_ELECOM=m
+CONFIG_HID_ELO=m
+CONFIG_HID_EMS_FF=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_GEMBIRD=m
+CONFIG_HID_GENERIC=m
+CONFIG_HID_GFRM=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_GT683R=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HID_HYPERV_MOUSE=m
+CONFIG_HID_ICADE=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KYE=m
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LENOVO=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_HID_LOGITECH_HIDPP=m
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PENMOUNT=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_PICOLCD_BACKLIGHT=y
+CONFIG_HID_PICOLCD_CIR=y
+CONFIG_HID_PICOLCD_FB=y
+CONFIG_HID_PICOLCD_LCD=y
+CONFIG_HID_PICOLCD_LEDS=y
+CONFIG_HID_PID=y
+CONFIG_HID_PLANTRONICS=m
+CONFIG_HID_PRIMAX=m
+CONFIG_HID_PRODIKEYS=m
+CONFIG_HID_RMI=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_SAITEK=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SENSOR_ACCEL_3D=m
+CONFIG_HID_SENSOR_ALS=m
+CONFIG_HID_SENSOR_CUSTOM_SENSOR=m
+CONFIG_HID_SENSOR_DEVICE_ROTATION=m
+CONFIG_HID_SENSOR_GYRO_3D=m
+CONFIG_HID_SENSOR_HUB=m
+CONFIG_HID_SENSOR_IIO_COMMON=m
+CONFIG_HID_SENSOR_IIO_TRIGGER=m
+CONFIG_HID_SENSOR_INCLINOMETER_3D=m
+CONFIG_HID_SENSOR_MAGNETOMETER_3D=m
+CONFIG_HID_SENSOR_PRESS=m
+CONFIG_HID_SENSOR_PROX=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_SONY=m
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_STEELSERIES=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_THINGM=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_TIVO=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WACOM=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_WIIMOTE=m
+CONFIG_HID_XINMO=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_HID_ZYDACRON=m
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_HIP04_ETH=m
+# CONFIG_HIPPI is not set
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_AVM_A1_CS=m
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_BKM_A4T=y
+# CONFIG_HISAX_DEBUG is not set
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_ELSA_CS=m
+CONFIG_HISAX_ENTERNOW_PCI=y
+CONFIG_HISAX_EURO=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_FRITZ_PCIPNP=m
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC4S8S=m
+CONFIG_HISAX_HFCUSB=m
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_HFC_SX=y
+CONFIG_HISAX_MAX_CARDS=8
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NETJET_U=y
+CONFIG_HISAX_NI1=y
+CONFIG_HISAX_NICCY=y
+# CONFIG_HISAX_NO_KEYPAD is not set
+# CONFIG_HISAX_NO_LLC is not set
+# CONFIG_HISAX_NO_SENDCOMPLETE is not set
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_SEDLBAUER_CS=m
+CONFIG_HISAX_ST5481=m
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_TELES_CS=m
+CONFIG_HISAX_W6692=y
+CONFIG_HISI_THERMAL=m
+CONFIG_HIX5HD2_GMAC=m
+CONFIG_HMC6352=m
+CONFIG_HMC_DRV=m
+CONFIG_HNS=m
+CONFIG_HNS_DSAF=m
+CONFIG_HNS_ENET=m
+CONFIG_HNS_MDIO=m
+CONFIG_HOLTEK_FF=y
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_CS=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_PCI=m
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
+CONFIG_HOTPLUG_PCI_ACPI_IBM=m
+CONFIG_HOTPLUG_PCI_CPCI=y
+CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m
+CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m
+CONFIG_HOTPLUG_PCI_PCIE=y
+CONFIG_HOTPLUG_PCI_S390=y
+CONFIG_HOTPLUG_SMT=y
+CONFIG_HP100=m
+CONFIG_HPET_EMULATE_RTC=y
+CONFIG_HPET_MMAP=y
+CONFIG_HPET_MMAP_DEFAULT=y
+CONFIG_HPET_TIMER=y
+CONFIG_HPWDT_NMI_DECODING=y
+CONFIG_HP_ACCEL=m
+CONFIG_HP_WATCHDOG=m
+CONFIG_HP_WIRELESS=m
+CONFIG_HP_WMI=m
+CONFIG_HSA_AMD=m
+CONFIG_HSI_BOARDINFO=y
+CONFIG_HSI_CHAR=m
+CONFIG_HSU_DMA=m
+CONFIG_HTC_I2CPLD=y
+CONFIG_HTS221=m
+CONFIG_HTS221_I2C=m
+CONFIG_HTS221_SPI=m
+CONFIG_HTU21=m
+CONFIG_HT_IRQ=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+# CONFIG_HVC_DCC is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_IRQ=y
+CONFIG_HVC_IUCV=y
+CONFIG_HVC_XEN=y
+CONFIG_HVC_XEN_FRONTEND=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_HWMON_VID=m
+CONFIG_HWPOISON_INJECT=m
+CONFIG_HWSPINLOCK=m
+CONFIG_HWSPINLOCK_QCOM=m
+CONFIG_HW_CONSOLE=y
+CONFIG_HW_PERF_EVENTS=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_AMD=m
+CONFIG_HW_RANDOM_INTEL=m
+CONFIG_HW_RANDOM_IPROC_RNG200=m
+CONFIG_HW_RANDOM_MSM=m
+CONFIG_HW_RANDOM_TPM=m
+CONFIG_HW_RANDOM_VIA=m
+CONFIG_HW_RANDOM_VIRTIO=m
+CONFIG_HW_RANDOM_XGENE=m
+CONFIG_HW_SCAN_OFFLOAD=y
+CONFIG_HYPERV=m
+CONFIG_HYPERVISOR_GUEST=y
+CONFIG_HYPERV_BALLOON=m
+CONFIG_HYPERV_KEYBOARD=m
+CONFIG_HYPERV_NET=m
+CONFIG_HYPERV_STORAGE=m
+CONFIG_HYPERV_UTILS=m
+CONFIG_HYSDN=m
+CONFIG_HYSDN_CAPI=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_PERIODIC is not set
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCA=m
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD756_S4882=m
+CONFIG_I2C_AMD8111=m
+CONFIG_I2C_ARB_GPIO_CHALLENGE=m
+CONFIG_I2C_BCM2048=m
+CONFIG_I2C_BCM_IPROC=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CADENCE=m
+CONFIG_I2C_CBUS_GPIO=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CROS_EC_TUNNEL=m
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+CONFIG_I2C_DESIGNWARE_BAYTRAIL=y
+CONFIG_I2C_DESIGNWARE_CORE=m
+CONFIG_I2C_DESIGNWARE_PCI=m
+CONFIG_I2C_DESIGNWARE_PLATFORM=m
+CONFIG_I2C_DIOLAN_U2C=m
+CONFIG_I2C_DLN2=m
+CONFIG_I2C_EMEV2=m
+CONFIG_I2C_GPIO=m
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_HID=m
+CONFIG_I2C_I801=m
+CONFIG_I2C_IMX=y
+CONFIG_I2C_ISCH=m
+CONFIG_I2C_ISMT=m
+CONFIG_I2C_KEMPLD=m
+CONFIG_I2C_MT65XX=m
+CONFIG_I2C_MUX=m
+CONFIG_I2C_MUX_GPIO=m
+CONFIG_I2C_MUX_PCA9541=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_MUX_REG=m
+CONFIG_I2C_NFORCE2=m
+CONFIG_I2C_NFORCE2_S4985=m
+CONFIG_I2C_NOMADIK=m
+CONFIG_I2C_OCORES=m
+CONFIG_I2C_PARPORT=m
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_PCA_PLATFORM=m
+CONFIG_I2C_PIIX4=m
+# CONFIG_I2C_PXA_PCI is not set
+CONFIG_I2C_QUP=m
+CONFIG_I2C_RK3X=m
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
+CONFIG_I2C_SCMI=m
+CONFIG_I2C_SI470X=m
+CONFIG_I2C_SI4713=m
+CONFIG_I2C_SIMTEC=m
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+# CONFIG_I2C_SLAVE is not set
+CONFIG_I2C_SMBUS=m
+CONFIG_I2C_STUB=m
+CONFIG_I2C_TAOS_EVM=m
+CONFIG_I2C_THUNDERX=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_I2C_VERSATILE=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VIPERBOARD=m
+CONFIG_I2C_XGENE_SLIMPRO=m
+CONFIG_I2C_XILINX=m
+CONFIG_I40E=m
+CONFIG_I40EVF=m
+CONFIG_I40E_DCB=y
+CONFIG_I40E_FCOE=y
+CONFIG_I40E_VXLAN=y
+CONFIG_I7300_IDLE=m
+CONFIG_I7300_IDLE_IOAT_CHANNEL=y
+CONFIG_I82092=m
+CONFIG_I8253_LOCK=y
+CONFIG_I8K=m
+# CONFIG_IA32_AOUT is not set
+CONFIG_IA32_EMULATION=y
+CONFIG_IB700_WDT=m
+CONFIG_IBMASR=m
+CONFIG_IBM_ASM=m
+CONFIG_IBM_PARTITION=y
+CONFIG_IBM_RTL=m
+CONFIG_ICPLUS_PHY=m
+CONFIG_ICS932S401=m
+# CONFIG_IDE is not set
+CONFIG_IDEAPAD_LAPTOP=m
+CONFIG_IDLE_PAGE_TRACKING=y
+CONFIG_IE6XX_WDT=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_AT86RF230_DEBUGFS=y
+CONFIG_IEEE802154_ATUSB=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_IEEE802154_DRIVERS=m
+CONFIG_IEEE802154_FAKELB=m
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_NL802154_EXPERIMENTAL=y
+CONFIG_IEEE802154_SOCKET=m
+CONFIG_IFB=m
+CONFIG_IGB=m
+CONFIG_IGBVF=m
+CONFIG_IGB_DCA=y
+CONFIG_IGB_HWMON=y
+CONFIG_IIO_ADIS_LIB=m
+CONFIG_IIO_ADIS_LIB_BUFFER=y
+CONFIG_IIO_BUFFER=y
+CONFIG_IIO_BUFFER_CB=m
+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
+CONFIG_IIO_INTERRUPT_TRIGGER=m
+CONFIG_IIO_KFIFO_BUF=m
+CONFIG_IIO_MS_SENSORS_I2C=m
+CONFIG_IIO_PERIODIC_RTC_TRIGGER=m
+CONFIG_IIO_SIMPLE_DUMMY=m
+# CONFIG_IIO_SIMPLE_DUMMY_BUFFER is not set
+# CONFIG_IIO_SIMPLE_DUMMY_EVENTS is not set
+CONFIG_IIO_SSP_SENSORHUB=m
+CONFIG_IIO_SSP_SENSORS_COMMONS=m
+CONFIG_IIO_ST_ACCEL_3AXIS=m
+CONFIG_IIO_ST_ACCEL_I2C_3AXIS=m
+CONFIG_IIO_ST_ACCEL_SPI_3AXIS=m
+CONFIG_IIO_ST_GYRO_3AXIS=m
+CONFIG_IIO_ST_GYRO_I2C_3AXIS=m
+CONFIG_IIO_ST_GYRO_SPI_3AXIS=m
+CONFIG_IIO_ST_MAGN_3AXIS=m
+CONFIG_IIO_ST_MAGN_I2C_3AXIS=m
+CONFIG_IIO_ST_MAGN_SPI_3AXIS=m
+CONFIG_IIO_ST_PRESS=m
+CONFIG_IIO_ST_PRESS_I2C=m
+CONFIG_IIO_ST_PRESS_SPI=m
+CONFIG_IIO_ST_SENSORS_CORE=m
+CONFIG_IIO_ST_SENSORS_I2C=m
+CONFIG_IIO_ST_SENSORS_SPI=m
+CONFIG_IIO_SYSFS_TRIGGER=m
+CONFIG_IIO_TRIGGER=y
+CONFIG_IIO_TRIGGERED_BUFFER=m
+CONFIG_IIO_TRIGGERED_EVENT=m
+# CONFIG_IKCONFIG is not set
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+CONFIG_IMA=y
+CONFIG_IMA_APPRAISE=y
+CONFIG_IMA_DEFAULT_HASH="sha1"
+CONFIG_IMA_DEFAULT_HASH_SHA1=y
+# CONFIG_IMA_DEFAULT_HASH_SHA256 is not set
+# CONFIG_IMA_DEFAULT_HASH_SHA512 is not set
+# CONFIG_IMA_DEFAULT_HASH_WP512 is not set
+CONFIG_IMA_DEFAULT_TEMPLATE="ima-ng"
+# CONFIG_IMA_LOAD_X509 is not set
+CONFIG_IMA_LSM_RULES=y
+CONFIG_IMA_MEASURE_PCR_IDX=10
+CONFIG_IMA_MOK_KEYRING=y
+CONFIG_IMA_NG_TEMPLATE=y
+# CONFIG_IMA_SIG_TEMPLATE is not set
+# CONFIG_IMA_TEMPLATE is not set
+CONFIG_IMA_TRUSTED_KEYRING=y
+CONFIG_IMX2_WDT=m
+CONFIG_IMX_THERMAL=m
+CONFIG_INET=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET_AH=m
+CONFIG_INET_DCCP_DIAG=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_LRO=y
+CONFIG_INET_TCP_DIAG=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_UDP_DIAG=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_ADDR_TRANS=y
+CONFIG_INFINIBAND_AMSO1100=m
+# CONFIG_INFINIBAND_AMSO1100_DEBUG is not set
+CONFIG_INFINIBAND_CXGB3=m
+# CONFIG_INFINIBAND_CXGB3_DEBUG is not set
+CONFIG_INFINIBAND_CXGB4=m
+CONFIG_INFINIBAND_HFI1=m
+CONFIG_INFINIBAND_IPATH=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_INFINIBAND_IPOIB_CM=y
+# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+CONFIG_INFINIBAND_ISER=m
+CONFIG_INFINIBAND_ISERT=m
+CONFIG_INFINIBAND_MTHCA=m
+# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
+# CONFIG_INFINIBAND_NES_DEBUG is not set
+CONFIG_INFINIBAND_ON_DEMAND_PAGING=y
+CONFIG_INFINIBAND_QIB_DCA=y
+CONFIG_INFINIBAND_SRP=m
+CONFIG_INFINIBAND_SRPT=m
+CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_USER_MAD=m
+CONFIG_INFINIBAND_USER_MEM=y
+CONFIG_INFINIBAND_USNIC=m
+CONFIG_INFTL=m
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_INLINE_READ_LOCK=y
+CONFIG_INLINE_READ_LOCK_BH=y
+CONFIG_INLINE_READ_LOCK_IRQ=y
+CONFIG_INLINE_READ_LOCK_IRQSAVE=y
+CONFIG_INLINE_READ_TRYLOCK=y
+CONFIG_INLINE_READ_UNLOCK=y
+CONFIG_INLINE_READ_UNLOCK_BH=y
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y
+CONFIG_INLINE_SPIN_LOCK=y
+CONFIG_INLINE_SPIN_LOCK_BH=y
+CONFIG_INLINE_SPIN_LOCK_IRQ=y
+CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y
+CONFIG_INLINE_SPIN_TRYLOCK=y
+CONFIG_INLINE_SPIN_TRYLOCK_BH=y
+CONFIG_INLINE_SPIN_UNLOCK_BH=y
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y
+CONFIG_INLINE_WRITE_LOCK=y
+CONFIG_INLINE_WRITE_LOCK_BH=y
+CONFIG_INLINE_WRITE_LOCK_IRQ=y
+CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y
+CONFIG_INLINE_WRITE_TRYLOCK=y
+CONFIG_INLINE_WRITE_UNLOCK=y
+CONFIG_INLINE_WRITE_UNLOCK_BH=y
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y
+CONFIG_INOTIFY_USER=y
+CONFIG_INPUT_88PM80X_ONKEY=m
+CONFIG_INPUT_88PM860X_ONKEY=m
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_AD714X_I2C=m
+CONFIG_INPUT_AD714X_SPI=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_ADXL34X_I2C=m
+CONFIG_INPUT_ADXL34X_SPI=m
+CONFIG_INPUT_APANEL=m
+CONFIG_INPUT_ARIZONA_HAPTICS=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_ATLAS_BTNS=m
+CONFIG_INPUT_AXP20X_PEK=m
+CONFIG_INPUT_BMA150=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_INPUT_CMA3000_I2C=m
+CONFIG_INPUT_DA9052_ONKEY=m
+CONFIG_INPUT_DA9055_ONKEY=m
+CONFIG_INPUT_DA9063_ONKEY=m
+CONFIG_INPUT_DRV260X_HAPTICS=m
+CONFIG_INPUT_DRV2665_HAPTICS=m
+CONFIG_INPUT_DRV2667_HAPTICS=m
+CONFIG_INPUT_E3X0_BUTTON=m
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_FF_MEMLESS=m
+CONFIG_INPUT_GP2A=m
+CONFIG_INPUT_GPIO_BEEPER=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_GPIO_TILT_POLLED=m
+CONFIG_INPUT_IDEAPAD_SLIDEBAR=m
+CONFIG_INPUT_IMS_PCU=m
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_KXTJ9=m
+# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set
+CONFIG_INPUT_LEDS=m
+CONFIG_INPUT_MATRIXKMAP=m
+CONFIG_INPUT_MAX77693_HAPTIC=m
+CONFIG_INPUT_MAX8925_ONKEY=m
+CONFIG_INPUT_MAX8997_HAPTIC=m
+CONFIG_INPUT_MC13783_PWRBUTTON=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_MMA8450=m
+CONFIG_INPUT_MOUSE=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_MPU3050=m
+CONFIG_INPUT_PALMAS_PWRBUTTON=m
+CONFIG_INPUT_PCAP=m
+CONFIG_INPUT_PCF50633_PMU=m
+CONFIG_INPUT_PCF8574=m
+CONFIG_INPUT_PCSPKR=m
+CONFIG_INPUT_PM8941_PWRKEY=m
+CONFIG_INPUT_POLLDEV=m
+CONFIG_INPUT_POWERMATE=m
+CONFIG_INPUT_PWM_BEEPER=m
+CONFIG_INPUT_REGULATOR_HAPTIC=m
+CONFIG_INPUT_RETU_PWRBUTTON=m
+CONFIG_INPUT_SOC_BUTTON_ARRAY=m
+CONFIG_INPUT_SPARSEKMAP=m
+CONFIG_INPUT_TABLET=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_TPS65218_PWRBUTTON=m
+CONFIG_INPUT_TWL4030_PWRBUTTON=m
+CONFIG_INPUT_TWL4030_VIBRA=m
+CONFIG_INPUT_TWL6040_VIBRA=m
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_WM831X_ON=m
+CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INSTRUCTION_DECODER=y
+CONFIG_INT340X_THERMAL=m
+CONFIG_INTEGRITY=y
+CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
+CONFIG_INTEGRITY_AUDIT=y
+CONFIG_INTEGRITY_SIGNATURE=y
+CONFIG_INTEL_GTT=y
+CONFIG_INTEL_HID_EVENT=m
+CONFIG_INTEL_IDLE=y
+CONFIG_INTEL_IDMA64=m
+CONFIG_INTEL_IOATDMA=m
+CONFIG_INTEL_IOMMU=y
+# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
+CONFIG_INTEL_IOMMU_FLOPPY_WA=y
+CONFIG_INTEL_IOMMU_SVM=y
+CONFIG_INTEL_IPS=m
+CONFIG_INTEL_MEI=m
+CONFIG_INTEL_MEI_ME=m
+CONFIG_INTEL_MEI_TXE=m
+CONFIG_INTEL_MENLOW=m
+CONFIG_INTEL_MIC_BUS=m
+CONFIG_INTEL_MIC_CARD=m
+CONFIG_INTEL_MIC_HOST=m
+CONFIG_INTEL_MIC_X100_DMA=m
+CONFIG_INTEL_OAKTRAIL=m
+CONFIG_INTEL_PCH_THERMAL=m
+CONFIG_INTEL_PMC_IPC=m
+CONFIG_INTEL_POWERCLAMP=m
+CONFIG_INTEL_PUNIT_IPC=m
+CONFIG_INTEL_RAPL=m
+CONFIG_INTEL_RST=m
+CONFIG_INTEL_SMARTCONNECT=m
+CONFIG_INTEL_SOC_DTS_IOSF_CORE=m
+CONFIG_INTEL_SOC_DTS_THERMAL=m
+CONFIG_INTEL_SOC_PMIC=y
+CONFIG_INTEL_TELEMETRY=m
+CONFIG_INTEL_TH=m
+# CONFIG_INTEL_TH_DEBUG is not set
+CONFIG_INTEL_TH_GTH=m
+CONFIG_INTEL_TH_MSU=m
+CONFIG_INTEL_TH_PCI=m
+CONFIG_INTEL_TH_PTI=m
+CONFIG_INTEL_TH_STH=m
+CONFIG_INTEL_TXT=y
+CONFIG_INTEL_VBTN=m
+CONFIG_INTERVAL_TREE=y
+CONFIG_INTERVAL_TREE_TEST=m
+CONFIG_INV_MPU6050_IIO=m
+CONFIG_IOMMU_API=y
+# CONFIG_IOMMU_DEBUG is not set
+CONFIG_IOMMU_DMA=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_IOMMU_IOVA=y
+CONFIG_IOMMU_IO_PGTABLE=y
+CONFIG_IOMMU_IO_PGTABLE_LPAE=y
+# CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST is not set
+# CONFIG_IOMMU_STRESS is not set
+CONFIG_IOMMU_SUPPORT=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSF_MBI=y
+CONFIG_IOSF_MBI_DEBUG=y
+# CONFIG_IO_DELAY_0X80 is not set
+CONFIG_IO_DELAY_0XED=y
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+# CONFIG_IO_DELAY_UDELAY is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IPC_NS=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPMI_DEVICE_INTERFACE=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_POWEROFF=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_SSIF=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPPP_FILTER=y
+CONFIG_IPQ_GCC_806X=m
+CONFIG_IPQ_LCC_806X=m
+CONFIG_IPV6=y
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_ILA=m
+CONFIG_IPV6_MIP6=m
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPVLAN=m
+CONFIG_IPW2100=m
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2100_MONITOR=y
+CONFIG_IPW2200=m
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_IPW2200_MONITOR=y
+CONFIG_IPW2200_PROMISCUOUS=y
+CONFIG_IPW2200_QOS=y
+CONFIG_IPW2200_RADIOTAP=y
+CONFIG_IPWIRELESS=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_DCCP=m
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+# CONFIG_IP_DCCP_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+CONFIG_IP_FIB_TRIE_STATS=y
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_SYNPROXY=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_IP_PNP is not set
+CONFIG_IP_ROUTE_CLASSID=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_SCTP=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPMARK=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_MAC=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_HASH_NETNET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_SET_MAX=256
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_FO=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_NFCT=y
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_OVF=m
+CONFIG_IP_VS_PE_SIP=m
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SH_TAB_BITS=8
+CONFIG_IP_VS_TAB_BITS=12
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA=m
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+# CONFIG_IRDA_DEBUG is not set
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRQCHIP=y
+# CONFIG_IRQSOFF_TRACER is not set
+CONFIG_IRQ_BYPASS_MANAGER=m
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_REMAP=y
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+CONFIG_IRQ_WORK=y
+CONFIG_IRTTY_SIR=m
+CONFIG_IR_ENE=m
+CONFIG_IR_FINTEK=m
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_HIX5HD2=m
+CONFIG_IR_IGORPLUGUSB=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_IMON=m
+CONFIG_IR_ITE_CIR=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_LIRC_CODEC=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_NUVOTON=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_IR_WINBOND_CIR=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_ISA_DMA_API=y
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_ISCSI_IBFT=m
+CONFIG_ISCSI_IBFT_FIND=y
+CONFIG_ISCSI_TARGET=m
+CONFIG_ISCSI_TCP=m
+CONFIG_ISDN=y
+CONFIG_ISDN_AUDIO=y
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIDRV=m
+# CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE is not set
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVERSION=m
+CONFIG_ISDN_DRV_AVMB1_AVM_CS=m
+CONFIG_ISDN_DRV_AVMB1_B1PCI=m
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m
+CONFIG_ISDN_DRV_AVMB1_C4=m
+CONFIG_ISDN_DRV_AVMB1_T1PCI=m
+CONFIG_ISDN_DRV_GIGASET=m
+CONFIG_ISDN_DRV_HISAX=m
+CONFIG_ISDN_HDLC=m
+CONFIG_ISDN_I4L=m
+CONFIG_ISDN_MPP=y
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_BSDCOMP=m
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_TTY_FAX=y
+CONFIG_ISDN_X25=y
+CONFIG_ISI=m
+CONFIG_ISL29003=m
+CONFIG_ISL29020=m
+CONFIG_ISL29125=m
+CONFIG_ISO9660_FS=m
+CONFIG_IT8712F_WDT=m
+CONFIG_IT87_WDT=m
+CONFIG_ITCO_VENDOR_SUPPORT=y
+CONFIG_ITCO_WDT=m
+CONFIG_ITG3200=m
+CONFIG_IUCV=y
+CONFIG_IWL3945=m
+CONFIG_IWL4965=m
+CONFIG_IWLDVM=m
+CONFIG_IWLEGACY=m
+# CONFIG_IWLEGACY_DEBUG is not set
+CONFIG_IWLEGACY_DEBUGFS=y
+CONFIG_IWLMVM=m
+CONFIG_IWLWIFI=m
+# CONFIG_IWLWIFI_BCAST_FILTERING is not set
+# CONFIG_IWLWIFI_DEBUG is not set
+CONFIG_IWLWIFI_DEBUGFS=y
+CONFIG_IWLWIFI_DEVICE_TRACING=y
+CONFIG_IWLWIFI_LEDS=y
+CONFIG_IWLWIFI_OPMODE_MODULAR=y
+# CONFIG_IWLWIFI_UAPSD is not set
+CONFIG_IXGB=m
+CONFIG_IXGBE=m
+CONFIG_IXGBEVF=m
+CONFIG_IXGBE_DCA=y
+CONFIG_IXGBE_DCB=y
+CONFIG_IXGBE_HWMON=y
+CONFIG_IXGBE_VXLAN=y
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_JFFS2_CMODE_FAVOURLZO=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+# CONFIG_JFFS2_CMODE_PRIORITY is not set
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_SUMMARY is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFS_DEBUG is not set
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_JFS_STATISTICS=y
+CONFIG_JOLIET=y
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_AS5011=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_JOYDUMP=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+CONFIG_JOYSTICK_TWIDJOY=m
+CONFIG_JOYSTICK_WALKERA0701=m
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_XPAD=m
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_JOYSTICK_ZHENHUA=m
+CONFIG_JSA1212=m
+CONFIG_JUMP_LABEL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KASAN is not set
+CONFIG_KDB_CONTINUE_CATASTROPHIC=0
+CONFIG_KDB_DEFAULT_ENABLE=0x1
+CONFIG_KDB_KEYBOARD=y
+CONFIG_KEMPLD_WDT=m
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZ4 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_KERNEL_NOBP=y
+CONFIG_KERNFS=y
+CONFIG_KEXEC=y
+CONFIG_KEXEC_BZIMAGE_VERIFY_SIG=y
+CONFIG_KEXEC_CORE=y
+CONFIG_KEXEC_FILE=y
+CONFIG_KEXEC_JUMP=y
+CONFIG_KEXEC_VERIFY_SIG=y
+CONFIG_KEYBOARD_ADP5520=m
+CONFIG_KEYBOARD_ADP5588=m
+CONFIG_KEYBOARD_ADP5589=m
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_BCM=m
+CONFIG_KEYBOARD_CAP11XX=m
+CONFIG_KEYBOARD_CROS_EC=m
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_GPIO_POLLED=m
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_LM8323=m
+CONFIG_KEYBOARD_LM8333=m
+CONFIG_KEYBOARD_MATRIX=m
+CONFIG_KEYBOARD_MAX7359=m
+CONFIG_KEYBOARD_MCS=m
+CONFIG_KEYBOARD_MPR121=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_KEYBOARD_OMAP4=m
+CONFIG_KEYBOARD_OPENCORES=m
+CONFIG_KEYBOARD_QT1070=m
+CONFIG_KEYBOARD_QT2160=m
+CONFIG_KEYBOARD_SAMSUNG=m
+CONFIG_KEYBOARD_STMPE=m
+CONFIG_KEYBOARD_STOWAWAY=m
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_TC3589X=m
+CONFIG_KEYBOARD_TCA6416=m
+CONFIG_KEYBOARD_TCA8418=m
+CONFIG_KEYBOARD_TWL4030=m
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYS=y
+CONFIG_KEYS_COMPAT=y
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+CONFIG_KGDB_LOW_LEVEL_TRAP=y
+CONFIG_KGDB_SERIAL_CONSOLE=y
+# CONFIG_KGDB_TESTS is not set
+CONFIG_KINGSUN_DONGLE=m
+CONFIG_KMX61=m
+CONFIG_KPROBES=y
+CONFIG_KPROBES_ON_FTRACE=y
+# CONFIG_KPROBES_SANITY_TEST is not set
+CONFIG_KPROBE_EVENT=y
+CONFIG_KRETPROBES=y
+CONFIG_KS0108=m
+CONFIG_KS0108_DELAY=2
+CONFIG_KS0108_PORT=0x378
+CONFIG_KS8842=m
+CONFIG_KS8851=m
+CONFIG_KS8851_MLL=m
+CONFIG_KS959_DONGLE=m
+CONFIG_KSDAZZLE_DONGLE=m
+CONFIG_KSM=y
+CONFIG_KSZ884X_PCI=m
+CONFIG_KVM_AMD=m
+CONFIG_KVM_APIC_ARCHITECTURE=y
+CONFIG_KVM_ARM_HOST=y
+CONFIG_KVM_ARM_VGIC_V3=y
+CONFIG_KVM_ASYNC_PF=y
+CONFIG_KVM_ASYNC_PF_SYNC=y
+CONFIG_KVM_COMPAT=y
+CONFIG_KVM_DEBUG_FS=y
+CONFIG_KVM_DEVICE_ASSIGNMENT=y
+CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
+CONFIG_KVM_GUEST=y
+CONFIG_KVM_INTEL=m
+CONFIG_KVM_MMIO=y
+# CONFIG_KVM_MMU_AUDIT is not set
+# CONFIG_KVM_S390_UCONTROL is not set
+CONFIG_KVM_VFIO=y
+CONFIG_KXCJK1013=m
+CONFIG_KXSD9=m
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_ETH=m
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_V3=y
+CONFIG_LANMEDIA=m
+CONFIG_LAPBETHER=m
+# CONFIG_LATENCYTOP is not set
+CONFIG_LATTICE_ECP3_CONFIG=m
+CONFIG_LCD_AMS369FG06=m
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_HX8357=m
+CONFIG_LCD_ILI922X=m
+CONFIG_LCD_ILI9320=m
+CONFIG_LCD_L4F00242T03=m
+CONFIG_LCD_LD9040=m
+CONFIG_LCD_LMS283GF05=m
+CONFIG_LCD_LMS501KF03=m
+CONFIG_LCD_LTV350QV=m
+CONFIG_LCD_PLATFORM=m
+CONFIG_LCD_S6E63M0=m
+CONFIG_LCD_TDO24M=m
+CONFIG_LCD_VGG2432A4=m
+CONFIG_LCS=m
+CONFIG_LDISC_AUTOLOAD=y
+# CONFIG_LDM_DEBUG is not set
+CONFIG_LEDS_88PM860X=m
+CONFIG_LEDS_AAT1290=m
+CONFIG_LEDS_ADP5520=m
+CONFIG_LEDS_BCM6328=m
+CONFIG_LEDS_BCM6358=m
+CONFIG_LEDS_BD2802=m
+CONFIG_LEDS_BLINKM=m
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_FLASH=m
+CONFIG_LEDS_CLEVO_MAIL=m
+CONFIG_LEDS_DA903X=m
+CONFIG_LEDS_DA9052=m
+CONFIG_LEDS_DAC124S085=m
+CONFIG_LEDS_DELL_NETBOOKS=m
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_INTEL_SS4200=m
+CONFIG_LEDS_KTD2692=m
+CONFIG_LEDS_LM3530=m
+CONFIG_LEDS_LM3533=m
+CONFIG_LEDS_LM355x=m
+CONFIG_LEDS_LM3642=m
+CONFIG_LEDS_LP3944=m
+CONFIG_LEDS_LP5521=m
+CONFIG_LEDS_LP5523=m
+CONFIG_LEDS_LP5562=m
+CONFIG_LEDS_LP55XX_COMMON=m
+CONFIG_LEDS_LP8501=m
+CONFIG_LEDS_LP8788=m
+CONFIG_LEDS_LP8860=m
+CONFIG_LEDS_LT3593=m
+CONFIG_LEDS_MAX77693=m
+CONFIG_LEDS_MAX8997=m
+CONFIG_LEDS_MC13783=m
+CONFIG_LEDS_MENF21BMC=m
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_PCA9532_GPIO=y
+CONFIG_LEDS_PCA955X=m
+CONFIG_LEDS_PCA963X=m
+CONFIG_LEDS_PWM=m
+CONFIG_LEDS_REGULATOR=m
+CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_TCA6507=m
+CONFIG_LEDS_TLC591XX=m
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_ONESHOT=m
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_WM831X_STATUS=m
+CONFIG_LEDS_WM8350=m
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=0
+CONFIG_LEGACY_VSYSCALL_EMULATE=y
+# CONFIG_LEGACY_VSYSCALL_NATIVE is not set
+# CONFIG_LEGACY_VSYSCALL_NONE is not set
+CONFIG_LIB80211=m
+CONFIG_LIB80211_CRYPT_CCMP=m
+CONFIG_LIB80211_CRYPT_TKIP=m
+CONFIG_LIB80211_CRYPT_WEP=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_LIBCRC32C=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_CS=m
+# CONFIG_LIBERTAS_DEBUG is not set
+CONFIG_LIBERTAS_MESH=y
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_SPI=m
+CONFIG_LIBERTAS_THINFIRM=m
+# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBFC=m
+CONFIG_LIBFCOE=m
+CONFIG_LIBFDT=y
+CONFIG_LIBIPW=m
+# CONFIG_LIBIPW_DEBUG is not set
+CONFIG_LIDAR_LITE_V2=m
+CONFIG_LIQUIDIO=m
+CONFIG_LIRC=m
+CONFIG_LIRC_BT829=m
+CONFIG_LIRC_IMON=m
+CONFIG_LIRC_PARALLEL=m
+CONFIG_LIRC_SASEM=m
+CONFIG_LIRC_SERIAL=m
+CONFIG_LIRC_SERIAL_TRANSMITTER=y
+CONFIG_LIRC_SIR=m
+CONFIG_LIRC_STAGING=y
+CONFIG_LIRC_ZILOG=m
+CONFIG_LIS3L02DQ=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_LIVEPATCH=y
+# CONFIG_LKDTM is not set
+CONFIG_LLC=m
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_LOCKD_V4=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+# CONFIG_LOCK_STAT is not set
+CONFIG_LOCK_TORTURE_TEST=m
+# CONFIG_LOGFS is not set
+CONFIG_LOGIG940_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIWHEELS_FF=y
+# CONFIG_LOGO is not set
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+CONFIG_LOOPBACK_TARGET=m
+CONFIG_LP8788_ADC=m
+# CONFIG_LP_CONSOLE is not set
+CONFIG_LRU_CACHE=m
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_LSM_MMAP_MIN_ADDR=0
+CONFIG_LTE_GDM724X=m
+CONFIG_LTR501=m
+# CONFIG_LUSTRE_FS is not set
+CONFIG_LWTUNNEL=y
+CONFIG_LXT_PHY=m
+CONFIG_LZ4HC_COMPRESS=m
+CONFIG_LZ4_COMPRESS=m
+CONFIG_LZ4_DECOMPRESS=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_M62332=m
+CONFIG_MA600_DONGLE=m
+CONFIG_MAC80211=m
+CONFIG_MAC80211_DEBUGFS=y
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_HWSIM=m
+CONFIG_MAC80211_LEDS=y
+CONFIG_MAC80211_MESH=y
+CONFIG_MAC80211_MESSAGE_TRACING=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_MINSTREL_VHT=y
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+CONFIG_MAC802154=m
+CONFIG_MACB=m
+CONFIG_MACHZ_WDT=m
+CONFIG_MACINTOSH_DRIVERS=y
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_MAC_EMUMOUSEBTN=m
+CONFIG_MAG3110=m
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAILBOX_TEST=m
+CONFIG_MANTIS_CORE=m
+# CONFIG_MARCH_Z10 is not set
+# CONFIG_MARCH_Z10_TUNE is not set
+# CONFIG_MARCH_Z13 is not set
+# CONFIG_MARCH_Z13_TUNE is not set
+# CONFIG_MARCH_Z196 is not set
+# CONFIG_MARCH_Z196_TUNE is not set
+# CONFIG_MARCH_Z900 is not set
+# CONFIG_MARCH_Z900_TUNE is not set
+# CONFIG_MARCH_Z990 is not set
+# CONFIG_MARCH_Z990_TUNE is not set
+# CONFIG_MARCH_Z9_109 is not set
+# CONFIG_MARCH_Z9_109_TUNE is not set
+CONFIG_MARCH_ZEC12=y
+CONFIG_MARCH_ZEC12_TUNE=y
+CONFIG_MARVELL_PHY=m
+# CONFIG_MATOM is not set
+CONFIG_MAX1027=m
+CONFIG_MAX1363=m
+CONFIG_MAX517=m
+CONFIG_MAX5821=m
+CONFIG_MAX8925_POWER=m
+# CONFIG_MAXSMP is not set
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_MCB_PCI=m
+# CONFIG_MCORE2 is not set
+CONFIG_MCP2120_DONGLE=m
+CONFIG_MCP320X=m
+CONFIG_MCP3422=m
+CONFIG_MCP4531=m
+CONFIG_MCP4725=m
+CONFIG_MCP4922=m
+CONFIG_MCS_FIR=m
+CONFIG_MD=y
+CONFIG_MDIO=m
+CONFIG_MDIO_BCM_IPROC=m
+CONFIG_MDIO_BCM_UNIMAC=m
+CONFIG_MDIO_BITBANG=m
+CONFIG_MDIO_BUS_MUX=m
+CONFIG_MDIO_BUS_MUX_GPIO=m
+CONFIG_MDIO_BUS_MUX_MMIOREG=m
+CONFIG_MDIO_CAVIUM=m
+CONFIG_MDIO_GPIO=m
+CONFIG_MDIO_OCTEON=m
+CONFIG_MDIO_THUNDER=m
+CONFIG_MDIO_XGENE=m
+CONFIG_MD_AUTODETECT=y
+CONFIG_MD_CLUSTER=m
+CONFIG_MD_FAULTY=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MEDIATEK_WATCHDOG=m
+CONFIG_MEDIA_ALTERA_CI=m
+CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_COMMON_OPTIONS=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
+CONFIG_MEDIA_PCI_SUPPORT=y
+CONFIG_MEDIA_RADIO_SUPPORT=y
+CONFIG_MEDIA_RC_SUPPORT=y
+CONFIG_MEDIA_SDR_SUPPORT=y
+CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
+CONFIG_MEDIA_TUNER=m
+CONFIG_MEDIA_TUNER_E4000=m
+CONFIG_MEDIA_TUNER_FC0011=m
+CONFIG_MEDIA_TUNER_FC0012=m
+CONFIG_MEDIA_TUNER_FC0013=m
+CONFIG_MEDIA_TUNER_FC2580=m
+CONFIG_MEDIA_TUNER_IT913X=m
+CONFIG_MEDIA_TUNER_M88RS6000T=m
+CONFIG_MEDIA_TUNER_MAX2165=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_MEDIA_TUNER_MSI001=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2063=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2131=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_MXL301RF=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_MEDIA_TUNER_MXL5007T=m
+CONFIG_MEDIA_TUNER_QM1D1C0042=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_R820T=m
+CONFIG_MEDIA_TUNER_SI2157=m
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA18212=m
+CONFIG_MEDIA_TUNER_TDA18218=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_TUA9001=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC4000=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_MM=m
+CONFIG_MEMBARRIER=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_MEMCG_SWAP=y
+# CONFIG_MEMCG_SWAP_ENABLED is not set
+CONFIG_MEMORY_BALLOON=y
+CONFIG_MEMORY_FAILURE=y
+CONFIG_MEMORY_HOTPLUG=y
+CONFIG_MEMORY_HOTPLUG_SPARSE=y
+CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
+# CONFIG_MEMSTICK_DEBUG is not set
+CONFIG_MEMSTICK_JMICRON_38X=m
+CONFIG_MEMSTICK_R592=m
+CONFIG_MEMSTICK_REALTEK_PCI=m
+CONFIG_MEMSTICK_REALTEK_USB=m
+CONFIG_MEMSTICK_TIFM_MS=m
+# CONFIG_MEMSTICK_UNSAFE_RESUME is not set
+CONFIG_MEMTEST=y
+CONFIG_MEM_SOFT_DIRTY=y
+CONFIG_MENF21BMC_WATCHDOG=m
+CONFIG_MEN_A21_WDT=m
+CONFIG_MEN_Z188_ADC=m
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+CONFIG_MFD_88PM800=m
+CONFIG_MFD_88PM805=m
+CONFIG_MFD_88PM860X=y
+CONFIG_MFD_AAT2870_CORE=y
+CONFIG_MFD_ARIZONA=y
+CONFIG_MFD_ARIZONA_I2C=m
+CONFIG_MFD_ARIZONA_SPI=m
+CONFIG_MFD_AS3711=y
+CONFIG_MFD_AS3722=y
+CONFIG_MFD_ATMEL_FLEXCOM=m
+CONFIG_MFD_ATMEL_HLCDC=m
+CONFIG_MFD_AXP20X=y
+CONFIG_MFD_BCM590XX=m
+CONFIG_MFD_CROS_EC=m
+CONFIG_MFD_CROS_EC_I2C=m
+CONFIG_MFD_CROS_EC_SPI=m
+CONFIG_MFD_DA9052_I2C=y
+CONFIG_MFD_DA9052_SPI=y
+CONFIG_MFD_DA9055=y
+CONFIG_MFD_DA9062=m
+CONFIG_MFD_DA9063=y
+CONFIG_MFD_DA9150=m
+CONFIG_MFD_DLN2=m
+CONFIG_MFD_HI6421_PMIC=m
+CONFIG_MFD_INTEL_LPSS=m
+CONFIG_MFD_INTEL_LPSS_ACPI=m
+CONFIG_MFD_INTEL_LPSS_PCI=m
+CONFIG_MFD_INTEL_QUARK_I2C_GPIO=m
+CONFIG_MFD_LM3533=m
+CONFIG_MFD_LP3943=m
+CONFIG_MFD_LP8788=y
+CONFIG_MFD_MAX14577=y
+CONFIG_MFD_MAX77686=y
+CONFIG_MFD_MAX77693=y
+CONFIG_MFD_MAX77843=y
+CONFIG_MFD_MAX8907=m
+CONFIG_MFD_MAX8925=y
+CONFIG_MFD_MAX8997=y
+CONFIG_MFD_MAX8998=y
+CONFIG_MFD_MC13XXX=m
+CONFIG_MFD_MC13XXX_I2C=m
+CONFIG_MFD_MC13XXX_SPI=m
+CONFIG_MFD_MENF21BMC=m
+CONFIG_MFD_PALMAS=y
+CONFIG_MFD_PCF50633=m
+CONFIG_MFD_QCOM_RPM=m
+CONFIG_MFD_RC5T583=y
+CONFIG_MFD_RETU=m
+CONFIG_MFD_RK808=m
+CONFIG_MFD_RN5T618=m
+CONFIG_MFD_RT5033=m
+CONFIG_MFD_RTSX_USB=m
+CONFIG_MFD_SEC_CORE=y
+CONFIG_MFD_SI476X_CORE=m
+CONFIG_MFD_SKY81452=m
+CONFIG_MFD_SM501_GPIO=y
+CONFIG_MFD_SMSC=y
+CONFIG_MFD_SPMI_PMIC=m
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_TC3589X=y
+# CONFIG_MFD_TMIO is not set
+CONFIG_MFD_TPS65090=y
+CONFIG_MFD_TPS65217=y
+CONFIG_MFD_TPS65218=m
+CONFIG_MFD_TPS6586X=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_TPS65912=y
+CONFIG_MFD_TPS65912_I2C=y
+CONFIG_MFD_TPS65912_SPI=y
+CONFIG_MFD_TPS80031=y
+CONFIG_MFD_TWL4030_AUDIO=y
+CONFIG_MFD_VEXPRESS_SYSREG=y
+CONFIG_MFD_VIPERBOARD=m
+CONFIG_MFD_WL1273_CORE=m
+CONFIG_MFD_WM5102=y
+CONFIG_MFD_WM5110=y
+CONFIG_MFD_WM831X=y
+CONFIG_MFD_WM831X_I2C=y
+CONFIG_MFD_WM831X_SPI=y
+CONFIG_MFD_WM8350=y
+CONFIG_MFD_WM8350_I2C=y
+CONFIG_MFD_WM8400=y
+CONFIG_MFD_WM8994=m
+CONFIG_MFD_WM8997=y
+CONFIG_MFD_WM8998=y
+CONFIG_MICREL_KS8995MA=m
+CONFIG_MICREL_PHY=m
+CONFIG_MICROCHIP_PHY=m
+CONFIG_MICROCODE=y
+CONFIG_MICROCODE_AMD=y
+CONFIG_MICROCODE_INTEL=y
+CONFIG_MICROCODE_OLD_INTERFACE=y
+CONFIG_MIC_COSM=m
+CONFIG_MIGRATION=y
+# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_MISDN=m
+CONFIG_MISDN_AVMFRITZ=m
+CONFIG_MISDN_DSP=m
+CONFIG_MISDN_HFCMULTI=m
+CONFIG_MISDN_HFCPCI=m
+CONFIG_MISDN_HFCUSB=m
+CONFIG_MISDN_INFINEON=m
+CONFIG_MISDN_IPAC=m
+CONFIG_MISDN_ISAR=m
+CONFIG_MISDN_L1OIP=m
+CONFIG_MISDN_NETJET=m
+CONFIG_MISDN_SPEEDFAX=m
+CONFIG_MISDN_W6692=m
+CONFIG_MITIGATION_VMSCAPE=y
+# CONFIG_MK8 is not set
+CONFIG_MKISS=m
+CONFIG_MLX4_CORE=m
+CONFIG_MLX4_DEBUG=y
+CONFIG_MLX4_EN=m
+CONFIG_MLX4_EN_DCB=y
+CONFIG_MLX4_EN_VXLAN=y
+CONFIG_MLX4_INFINIBAND=m
+CONFIG_MLX5_CORE=m
+CONFIG_MLX5_CORE_EN=y
+CONFIG_MLX5_INFINIBAND=m
+CONFIG_MLX90614=m
+CONFIG_MLXSW_CORE=m
+CONFIG_MLXSW_PCI=m
+CONFIG_MMA8452=m
+CONFIG_MMA9551=m
+CONFIG_MMA9551_CORE=m
+CONFIG_MMA9553=m
+CONFIG_MMC35240=m
+CONFIG_MMC_ARMMMCI=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_CB710=m
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_DW=m
+CONFIG_MMC_DW_EXYNOS=m
+CONFIG_MMC_DW_K3=m
+CONFIG_MMC_DW_PCI=m
+CONFIG_MMC_DW_PLTFM=m
+CONFIG_MMC_MTK=m
+CONFIG_MMC_QCOM_DML=m
+CONFIG_MMC_REALTEK_PCI=m
+CONFIG_MMC_REALTEK_USB=m
+CONFIG_MMC_RICOH_MMC=y
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_ACPI=m
+CONFIG_MMC_SDHCI_F_SDH30=m
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+CONFIG_MMC_SDHCI_IPROC=m
+CONFIG_MMC_SDHCI_MSM=m
+CONFIG_MMC_SDHCI_OF_ARASAN=m
+CONFIG_MMC_SDHCI_OF_AT91=m
+CONFIG_MMC_SDHCI_OF_ESDHC=m
+CONFIG_MMC_SDHCI_PCI=m
+CONFIG_MMC_SDHCI_PLTFM=m
+CONFIG_MMC_SDHCI_PXAV3=m
+CONFIG_MMC_SDRICOH_CS=m
+CONFIG_MMC_SPI=m
+# CONFIG_MMC_TEST is not set
+CONFIG_MMC_TIFM_SD=m
+CONFIG_MMC_TOSHIBA_PCI=m
+CONFIG_MMC_USDHI6ROL0=m
+CONFIG_MMC_USHC=m
+CONFIG_MMC_VIA_SDMMC=m
+CONFIG_MMC_VUB300=m
+CONFIG_MMC_WBSD=m
+CONFIG_MMIOTRACE=y
+# CONFIG_MMIOTRACE_TEST is not set
+CONFIG_MMU=y
+CONFIG_MMU_NOTIFIER=y
+CONFIG_MODIFY_LDT_SYSCALL=y
+CONFIG_MODULES=y
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_MODULES_USE_ELF_RELA=y
+# CONFIG_MODULE_COMPRESS is not set
+# CONFIG_MODULE_FORCE_LOAD is not set
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_ALL=y
+# CONFIG_MODULE_SIG_FORCE is not set
+CONFIG_MODULE_SIG_HASH="sha512"
+CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
+# CONFIG_MODULE_SIG_SHA1 is not set
+# CONFIG_MODULE_SIG_SHA224 is not set
+# CONFIG_MODULE_SIG_SHA256 is not set
+# CONFIG_MODULE_SIG_SHA384 is not set
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_MODULE_SIG_UEFI=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MONREADER=m
+CONFIG_MONWRITER=m
+CONFIG_MOST=m
+CONFIG_MOSTCORE=m
+CONFIG_MOUSE_APPLETOUCH=m
+CONFIG_MOUSE_BCM5974=m
+CONFIG_MOUSE_CYAPA=m
+CONFIG_MOUSE_ELAN_I2C=m
+CONFIG_MOUSE_ELAN_I2C_I2C=y
+CONFIG_MOUSE_ELAN_I2C_SMBUS=y
+CONFIG_MOUSE_GPIO=m
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_CYPRESS=y
+CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_PS2_FOCALTECH=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SENTELIC=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TOUCHKIT=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+CONFIG_MOUSE_PS2_VMMOUSE=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_SYNAPTICS_I2C=m
+CONFIG_MOUSE_SYNAPTICS_USB=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_MOVABLE_NODE=y
+CONFIG_MOXA_INTELLIO=m
+CONFIG_MOXA_SMARTIO=m
+CONFIG_MPILIB=y
+CONFIG_MPL115=m
+CONFIG_MPL3115=m
+CONFIG_MPLS=y
+CONFIG_MPLS_IPTUNNEL=m
+CONFIG_MPLS_ROUTING=m
+# CONFIG_MPSC is not set
+CONFIG_MRP=m
+CONFIG_MS5611=m
+CONFIG_MS5611_I2C=m
+CONFIG_MS5611_SPI=m
+CONFIG_MS5637=m
+CONFIG_MSDOS_FS=m
+CONFIG_MSDOS_PARTITION=y
+CONFIG_MSI_LAPTOP=m
+CONFIG_MSI_WMI=m
+CONFIG_MSM_GCC_8660=m
+CONFIG_MSM_GCC_8916=m
+CONFIG_MSM_GCC_8960=m
+CONFIG_MSM_GCC_8974=m
+CONFIG_MSM_LCC_8960=m
+CONFIG_MSM_MMCC_8960=m
+CONFIG_MSM_MMCC_8974=m
+CONFIG_MSPRO_BLOCK=m
+CONFIG_MS_BLOCK=m
+CONFIG_MT7601U=m
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTD_ABSENT=m
+CONFIG_MTD_AMD76XROM=m
+CONFIG_MTD_AR7_PARTS=m
+CONFIG_MTD_BLKDEVS=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_CK804XROM=m
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_DATAFLASH=m
+CONFIG_MTD_DATAFLASH_OTP=y
+# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set
+CONFIG_MTD_DOCG3=m
+CONFIG_MTD_ESB2ROM=m
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_GPIO_ADDR=m
+CONFIG_MTD_ICHXROM=m
+CONFIG_MTD_INTEL_VR_NOR=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_L440GX=m
+CONFIG_MTD_LATCH_ADDR=m
+CONFIG_MTD_LPDDR=m
+CONFIG_MTD_M25P80=m
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTD_NAND=m
+CONFIG_MTD_NAND_BCH=m
+CONFIG_MTD_NAND_BRCMNAND=m
+CONFIG_MTD_NAND_CAFE=m
+CONFIG_MTD_NAND_DENALI=m
+CONFIG_MTD_NAND_DENALI_DT=m
+CONFIG_MTD_NAND_DENALI_PCI=m
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018
+CONFIG_MTD_NAND_DISKONCHIP=m
+# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0
+# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set
+CONFIG_MTD_NAND_DOCG4=m
+CONFIG_MTD_NAND_ECC=m
+CONFIG_MTD_NAND_ECC_BCH=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND_GPIO=m
+CONFIG_MTD_NAND_HISI504=m
+CONFIG_MTD_NAND_IDS=m
+CONFIG_MTD_NAND_NANDSIM=m
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+CONFIG_MTD_NAND_PLATFORM=m
+CONFIG_MTD_NAND_RICOH=m
+CONFIG_MTD_NETtel=m
+CONFIG_MTD_OF_PARTS=m
+CONFIG_MTD_ONENAND=m
+CONFIG_MTD_ONENAND_2X_PROGRAM=y
+CONFIG_MTD_ONENAND_GENERIC=m
+# CONFIG_MTD_ONENAND_OTP is not set
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_OOPS=m
+# CONFIG_MTD_PARTITIONED_MASTER is not set
+CONFIG_MTD_PCI=m
+CONFIG_MTD_PCMCIA=m
+# CONFIG_MTD_PCMCIA_ANONYMOUS is not set
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_PHYSMAP=m
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+CONFIG_MTD_PHYSMAP_OF=m
+CONFIG_MTD_PLATRAM=m
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+CONFIG_MTD_QINFO_PROBE=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+CONFIG_MTD_REDBOOT_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+CONFIG_MTD_ROM=m
+CONFIG_MTD_SBC_GXX=m
+CONFIG_MTD_SCB2_FLASH=m
+CONFIG_MTD_SLRAM=m
+CONFIG_MTD_SM_COMMON=m
+CONFIG_MTD_SPINAND_MT29F=m
+CONFIG_MTD_SPINAND_ONDIEECC=y
+CONFIG_MTD_SPI_NOR=m
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+CONFIG_MTD_SST25L=m
+CONFIG_MTD_SWAP=m
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_MTD_UBI_FASTMAP=y
+CONFIG_MTD_UBI_GLUEBI=m
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTK_INFRACFG=y
+CONFIG_MTK_PMIC_WRAP=m
+CONFIG_MTK_SCPSYS=y
+CONFIG_MTRR=y
+CONFIG_MTRR_SANITIZER=y
+CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
+CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
+CONFIG_MULTIUSER=y
+CONFIG_MUSB_PIO_ONLY=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_MVMDIO=m
+CONFIG_MWAVE=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_PCIE=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MWIFIEX_USB=m
+CONFIG_MWL8K=m
+CONFIG_MXC4005=m
+CONFIG_MXM_WMI=m
+CONFIG_MYRI10GE=m
+CONFIG_MYRI10GE_DCA=y
+CONFIG_NAMESPACES=y
+CONFIG_NATIONAL_PHY=m
+CONFIG_NATSEMI=m
+CONFIG_NAU7802=m
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_PACKET_SIGNING=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_STRONG=y
+CONFIG_ND_BLK=m
+CONFIG_ND_BTT=m
+CONFIG_ND_CLAIM=y
+CONFIG_ND_PFN=m
+CONFIG_NE2K_PCI=m
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_NET=y
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NETDEVICES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_ADVANCED=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_INGRESS=y
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_ACCT=m
+CONFIG_NETFILTER_NETLINK_GLUE_CT=y
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_SYNPROXY=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CGROUP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ECN=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_L2TP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_NETFILTER_XT_NAT=m
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_AUDIT=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NETMAP=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETIUCV=m
+CONFIG_NETLABEL=y
+CONFIG_NETLINK_DIAG=m
+CONFIG_NETPOLL=y
+CONFIG_NETROM=m
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETXEN_NIC=m
+CONFIG_NET_9P=m
+# CONFIG_NET_9P_DEBUG is not set
+CONFIG_NET_9P_RDMA=m
+CONFIG_NET_9P_VIRTIO=m
+CONFIG_NET_ACT_BPF=m
+CONFIG_NET_ACT_CONNMARK=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_VLAN=m
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_BPF=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_FLOWER=m
+CONFIG_NET_CLS_FW=m
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_CLS_MATCHALL=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CORE=y
+CONFIG_NET_DCCPPROBE=m
+CONFIG_NET_DROP_MONITOR=m
+# CONFIG_NET_DSA is not set
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CANID=m
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_IPSET=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_FC=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_FOU=m
+CONFIG_NET_FOU_IP_TUNNELS=y
+CONFIG_NET_INGRESS=y
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPVTI=m
+CONFIG_NET_IP_TUNNEL=m
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_NET_L3_MASTER_DEV=y
+CONFIG_NET_MPLS_GSO=m
+CONFIG_NET_NS=y
+CONFIG_NET_PKTGEN=m
+CONFIG_NET_POLL_CONTROLLER=y
+CONFIG_NET_PTP_CLASSIFY=y
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_NET_SB1000=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_FIFO=y
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_PIE=m
+CONFIG_NET_SCH_PLUG=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCTPPROBE=m
+# CONFIG_NET_SWITCHDEV is not set
+CONFIG_NET_TCPPROBE=m
+CONFIG_NET_TEAM=m
+CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m
+CONFIG_NET_TEAM_MODE_BROADCAST=m
+CONFIG_NET_TEAM_MODE_LOADBALANCE=m
+CONFIG_NET_TEAM_MODE_RANDOM=m
+CONFIG_NET_TEAM_MODE_ROUNDROBIN=m
+CONFIG_NET_TULIP=y
+CONFIG_NET_UDP_TUNNEL=m
+CONFIG_NET_VENDOR_8390=y
+CONFIG_NET_VENDOR_AMAZON=y
+CONFIG_NET_VENDOR_AURORA=y
+CONFIG_NET_VENDOR_FREESCALE=y
+CONFIG_NET_VENDOR_FUJITSU=y
+CONFIG_NET_VENDOR_HISILICON=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_MELLANOX=y
+CONFIG_NET_VENDOR_MICROCHIP=y
+CONFIG_NET_VENDOR_XIRCOM=y
+CONFIG_NET_VRF=m
+CONFIG_NET_XGENE=m
+CONFIG_NFC_DIGITAL=m
+CONFIG_NFC_FDP=m
+CONFIG_NFC_FDP_I2C=m
+CONFIG_NFC_HCI=m
+CONFIG_NFC_MEI_PHY=m
+CONFIG_NFC_MICROREAD=m
+CONFIG_NFC_MICROREAD_I2C=m
+CONFIG_NFC_MICROREAD_MEI=m
+CONFIG_NFC_MRVL=m
+CONFIG_NFC_MRVL_I2C=m
+CONFIG_NFC_MRVL_SPI=m
+CONFIG_NFC_MRVL_UART=m
+CONFIG_NFC_MRVL_USB=m
+CONFIG_NFC_NCI=m
+CONFIG_NFC_NCI_SPI=m
+CONFIG_NFC_NCI_UART=m
+CONFIG_NFC_NXP_NCI=m
+CONFIG_NFC_NXP_NCI_I2C=m
+CONFIG_NFC_PN533=m
+CONFIG_NFC_PN544=m
+CONFIG_NFC_PN544_I2C=m
+CONFIG_NFC_PN544_MEI=m
+CONFIG_NFC_PORT100=m
+CONFIG_NFC_S3FWRN5=m
+CONFIG_NFC_S3FWRN5_I2C=m
+CONFIG_NFC_SHDLC=y
+CONFIG_NFC_SIM=m
+CONFIG_NFC_ST21NFCA=m
+CONFIG_NFC_ST21NFCA_I2C=m
+CONFIG_NFC_ST_NCI=m
+CONFIG_NFC_ST_NCI_I2C=m
+CONFIG_NFC_ST_NCI_SPI=m
+CONFIG_NFC_TRF7970A=m
+CONFIG_NFC_WILINK=m
+CONFIG_NFSD=m
+# CONFIG_NFSD_FAULT_INJECTION is not set
+CONFIG_NFSD_PNFS=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_V4_SECURITY_LABEL=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_NFS_DEBUG=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_V2=m
+CONFIG_NFS_V3=m
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=m
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
+CONFIG_NFS_V4_1_MIGRATION=y
+CONFIG_NFS_V4_2=y
+CONFIG_NFS_V4_SECURITY_LABEL=y
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_NFT_BRIDGE_META=m
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_MASQ_IPV4=m
+CONFIG_NFT_MASQ_IPV6=m
+CONFIG_NFT_META=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_REDIR_IPV4=m
+CONFIG_NFT_REDIR_IPV6=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_REJECT_INET=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_REJECT_IPV6=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_LABELS=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+# CONFIG_NF_CONNTRACK_PROCFS is not set
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_CT_NETLINK_HELPER=m
+CONFIG_NF_CT_NETLINK_TIMEOUT=m
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_DUP_IPV4=m
+CONFIG_NF_DUP_IPV6=m
+CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_LOG_COMMON=m
+CONFIG_NF_LOG_IPV4=m
+CONFIG_NF_LOG_IPV6=m
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_NF_NAT_IPV4=m
+CONFIG_NF_NAT_IPV6=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_MASQUERADE_IPV4=m
+CONFIG_NF_NAT_MASQUERADE_IPV6=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_PROTO_DCCP=m
+CONFIG_NF_NAT_PROTO_GRE=m
+CONFIG_NF_NAT_PROTO_SCTP=m
+CONFIG_NF_NAT_PROTO_UDPLITE=m
+CONFIG_NF_NAT_REDIRECT=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_REJECT_IPV4=m
+CONFIG_NF_REJECT_IPV6=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NF_TABLES_INET=m
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NF_TABLES_NETDEV=m
+CONFIG_NILFS2_FS=m
+CONFIG_NIU=m
+# CONFIG_NL80211_TESTMODE is not set
+CONFIG_NLATTR=y
+CONFIG_NLMON=m
+CONFIG_NLS=y
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_MAC_CELTIC=m
+CONFIG_NLS_MAC_CENTEURO=m
+CONFIG_NLS_MAC_CROATIAN=m
+CONFIG_NLS_MAC_CYRILLIC=m
+CONFIG_NLS_MAC_GAELIC=m
+CONFIG_NLS_MAC_GREEK=m
+CONFIG_NLS_MAC_ICELAND=m
+CONFIG_NLS_MAC_INUIT=m
+CONFIG_NLS_MAC_ROMAN=m
+CONFIG_NLS_MAC_ROMANIAN=m
+CONFIG_NLS_MAC_TURKISH=m
+CONFIG_NLS_UTF8=m
+CONFIG_NODES_SPAN_OTHER_NODES=y
+CONFIG_NOP_TRACER=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_NORTEL_HERMES=m
+CONFIG_NOTIFIER_ERROR_INJECTION=m
+CONFIG_NOUVEAU_DEBUG=5
+CONFIG_NOUVEAU_DEBUG_DEFAULT=3
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+# CONFIG_NO_HZ_FULL is not set
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_IOPORT_MAP=y
+CONFIG_NS83820=m
+CONFIG_NSC_FIR=m
+CONFIG_NTB_AMD=m
+CONFIG_NTB_INTEL=m
+CONFIG_NTB_NETDEV=m
+CONFIG_NTB_PINGPONG=m
+CONFIG_NTB_TOOL=m
+CONFIG_NTB_TRANSPORT=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_FS=m
+CONFIG_NUMA=y
+CONFIG_NUMA_BALANCING=y
+CONFIG_NVDIMM_PFN=y
+CONFIG_NVME_VENDOR_EXT_GOOGLE=y
+CONFIG_NVRAM=m
+CONFIG_NV_TCO=m
+CONFIG_N_HDLC=m
+# CONFIG_OCFS2_DEBUG_FS is not set
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+CONFIG_OCFS2_FS=m
+CONFIG_OCFS2_FS_O2CB=m
+CONFIG_OCFS2_FS_STATS=y
+CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_DYNAMIC=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IOMMU=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_NUMA=y
+CONFIG_OF_OVERLAY=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+# CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT is not set
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OF_RESOLVE=y
+# CONFIG_OF_UNITTEST is not set
+CONFIG_OID_REGISTRY=y
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OPENNSL_BCM_KNET=m
+CONFIG_OPENNSL_KERNEL_BDE=m
+CONFIG_OPENNSL_USER_BDE=m
+CONFIG_OPENVSWITCH=m
+CONFIG_OPENVSWITCH_GENEVE=m
+CONFIG_OPENVSWITCH_GRE=m
+CONFIG_OPENVSWITCH_VXLAN=m
+CONFIG_OPROFILE=m
+# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
+CONFIG_OPROFILE_NMI_TIMER=y
+CONFIG_OPT3001=m
+CONFIG_OPTIMIZE_INLINING=y
+CONFIG_OPTPROBES=y
+CONFIG_ORE=m
+CONFIG_ORINOCO_USB=m
+CONFIG_OUTPUT_FORMAT="elf64-x86-64"
+CONFIG_OVERLAY_FS=m
+CONFIG_OVERLAY_FS_V1=y
+CONFIG_P54_COMMON=m
+CONFIG_P54_LEDS=y
+CONFIG_P54_PCI=m
+CONFIG_P54_SPI=m
+# CONFIG_P54_SPI_DEFAULT_EEPROM is not set
+CONFIG_P54_USB=m
+CONFIG_PA12203001=m
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=m
+CONFIG_PACK_STACK=y
+CONFIG_PADATA=y
+CONFIG_PAGE_COUNTER=y
+# CONFIG_PAGE_EXTENSION is not set
+# CONFIG_PAGE_OWNER is not set
+CONFIG_PAGE_TABLE_ISOLATION=y
+CONFIG_PANASONIC_LAPTOP=m
+CONFIG_PANEL=m
+# CONFIG_PANEL_CHANGE_MESSAGE is not set
+CONFIG_PANEL_PARPORT=0
+CONFIG_PANEL_PROFILE=5
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_PANTHERLORD_FF=y
+CONFIG_PARAVIRT=y
+CONFIG_PARAVIRT_CLOCK=y
+# CONFIG_PARAVIRT_DEBUG is not set
+CONFIG_PARAVIRT_SPINLOCKS=y
+# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
+CONFIG_PARIDE=m
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_EPAT=m
+CONFIG_PARIDE_EPATC8=y
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PG=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARPORT_1284=y
+CONFIG_PARPORT_AX88796=m
+# CONFIG_PARPORT_GSC is not set
+CONFIG_PARPORT_NOT_PC=y
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_SERIAL=m
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PATA_ACPI=m
+CONFIG_PATA_ALI=m
+CONFIG_PATA_AMD=m
+CONFIG_PATA_ARTOP=m
+CONFIG_PATA_ATIIXP=m
+CONFIG_PATA_ATP867X=m
+CONFIG_PATA_CMD640_PCI=m
+CONFIG_PATA_CMD64X=m
+CONFIG_PATA_CYPRESS=m
+CONFIG_PATA_EFAR=m
+CONFIG_PATA_HPT366=m
+CONFIG_PATA_HPT37X=m
+CONFIG_PATA_HPT3X2N=m
+CONFIG_PATA_HPT3X3=m
+# CONFIG_PATA_HPT3X3_DMA is not set
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_IT821X=m
+CONFIG_PATA_JMICRON=m
+CONFIG_PATA_LEGACY=m
+CONFIG_PATA_MARVELL=m
+CONFIG_PATA_MPIIX=m
+CONFIG_PATA_NETCELL=m
+CONFIG_PATA_NINJA32=m
+CONFIG_PATA_NS87410=m
+CONFIG_PATA_NS87415=m
+CONFIG_PATA_OF_PLATFORM=m
+CONFIG_PATA_OLDPIIX=m
+CONFIG_PATA_OPTI=m
+CONFIG_PATA_OPTIDMA=m
+CONFIG_PATA_PCMCIA=m
+CONFIG_PATA_PDC2027X=m
+CONFIG_PATA_PDC_OLD=m
+CONFIG_PATA_PLATFORM=m
+CONFIG_PATA_RADISYS=m
+CONFIG_PATA_RDC=m
+CONFIG_PATA_RZ1000=m
+CONFIG_PATA_SCH=m
+CONFIG_PATA_SERVERWORKS=m
+CONFIG_PATA_SIL680=m
+CONFIG_PATA_TOSHIBA=m
+CONFIG_PATA_TRIFLEX=m
+CONFIG_PATA_VIA=m
+CONFIG_PATA_WINBOND=m
+CONFIG_PC300TOO=m
+CONFIG_PC87413_WDT=m
+CONFIG_PCC=y
+CONFIG_PCCARD=m
+CONFIG_PCCARD_NONSTATIC=y
+CONFIG_PCF50633_ADC=m
+CONFIG_PCF50633_GPIO=m
+CONFIG_PCI=y
+CONFIG_PCI200SYN=m
+CONFIG_PCIEAER=y
+# CONFIG_PCIEAER_INJECT is not set
+CONFIG_PCIEASPM=y
+CONFIG_PCIEASPM_DEBUG=y
+CONFIG_PCIEASPM_DEFAULT=y
+# CONFIG_PCIEASPM_PERFORMANCE is not set
+# CONFIG_PCIEASPM_POWERSAVE is not set
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIE_DW=y
+# CONFIG_PCIE_ECRC is not set
+CONFIG_PCIE_IPROC=m
+CONFIG_PCIE_IPROC_PLATFORM=m
+CONFIG_PCIE_PME=y
+CONFIG_PCI_ATMEL=m
+CONFIG_PCI_ATS=y
+CONFIG_PCI_BUS_ADDR_T_64BIT=y
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+# CONFIG_PCI_DEBUG is not set
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_ECAM=y
+CONFIG_PCI_HISI=y
+CONFIG_PCI_HOST_COMMON=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_PCI_HOST_THUNDER_ECAM=y
+CONFIG_PCI_HOST_THUNDER_PEM=y
+CONFIG_PCI_HYPERV=m
+CONFIG_PCI_IOV=y
+CONFIG_PCI_LABEL=y
+# CONFIG_PCI_LAYERSCAPE is not set
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PCI_NR_FUNCTIONS=64
+CONFIG_PCI_NR_MSI=256
+CONFIG_PCI_REALLOC_ENABLE_AUTO=y
+CONFIG_PCI_STUB=m
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCI_XEN=y
+CONFIG_PCI_XGENE=y
+CONFIG_PCI_XGENE_MSI=y
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_SPECTRUM=m
+CONFIG_PCMCIA_SYM53C500=m
+CONFIG_PCMCIA_WL3501=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_XIRCOM=m
+CONFIG_PCNET32=m
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_PD6729=m
+CONFIG_PDA_POWER=m
+CONFIG_PDC_ADMA=m
+CONFIG_PERCPU_TEST=m
+CONFIG_PERF_EVENTS=y
+CONFIG_PERF_EVENTS_INTEL_UNCORE=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PERSISTENT_KEYRINGS=y
+CONFIG_PFAULT=y
+CONFIG_PGSTE=y
+CONFIG_PGTABLE_LEVELS=4
+CONFIG_PHYSICAL_ALIGN=0x1000000
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PHY_BERLIN_SATA=m
+CONFIG_PHY_BERLIN_USB=m
+# CONFIG_PHY_EXYNOS4210_USB2 is not set
+# CONFIG_PHY_EXYNOS4X12_USB2 is not set
+# CONFIG_PHY_EXYNOS5250_USB2 is not set
+CONFIG_PHY_MT65XX_USB3=m
+CONFIG_PHY_QCOM_APQ8064_SATA=m
+CONFIG_PHY_QCOM_IPQ806X_SATA=m
+CONFIG_PHY_QCOM_UFS=m
+CONFIG_PHY_SAMSUNG_USB2=m
+CONFIG_PHY_TUSB1210=m
+CONFIG_PHY_XGENE=y
+# CONFIG_PID_IN_CONTEXTIDR is not set
+CONFIG_PID_NS=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_AMD=y
+CONFIG_PINCTRL_APQ8064=m
+CONFIG_PINCTRL_APQ8084=m
+CONFIG_PINCTRL_AS3722=y
+CONFIG_PINCTRL_BAYTRAIL=y
+CONFIG_PINCTRL_BERLIN=y
+# CONFIG_PINCTRL_BERLIN_BG2 is not set
+# CONFIG_PINCTRL_BERLIN_BG2CD is not set
+# CONFIG_PINCTRL_BERLIN_BG2Q is not set
+CONFIG_PINCTRL_BERLIN_BG4CT=y
+CONFIG_PINCTRL_BROXTON=m
+CONFIG_PINCTRL_CHERRYVIEW=y
+CONFIG_PINCTRL_INTEL=m
+CONFIG_PINCTRL_IPQ8064=m
+CONFIG_PINCTRL_MSM=y
+CONFIG_PINCTRL_MSM8660=m
+CONFIG_PINCTRL_MSM8916=m
+CONFIG_PINCTRL_MSM8960=m
+CONFIG_PINCTRL_MSM8X74=m
+CONFIG_PINCTRL_MT6397=y
+# CONFIG_PINCTRL_MT8127 is not set
+# CONFIG_PINCTRL_MT8135 is not set
+CONFIG_PINCTRL_MT8173=y
+CONFIG_PINCTRL_MTK_COMMON=y
+CONFIG_PINCTRL_PALMAS=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=m
+CONFIG_PINCTRL_QCOM_SSBI_PMIC=m
+CONFIG_PINCTRL_QDF2XXX=m
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_PINCTRL_SUNRISEPOINT=m
+CONFIG_PINMUX=y
+CONFIG_PKCS7_MESSAGE_PARSER=y
+CONFIG_PKCS7_TEST_KEY=m
+CONFIG_PL320_MBOX=y
+CONFIG_PL330_DMA=m
+CONFIG_PLATFORM_SI4713=m
+CONFIG_PLIP=m
+CONFIG_PLX_HERMES=m
+CONFIG_PM=y
+CONFIG_PMBUS=m
+CONFIG_PMC_ATOM=y
+CONFIG_PMIC_ADP5520=y
+CONFIG_PMIC_DA903X=y
+CONFIG_PMIC_DA9052=y
+# CONFIG_PMIC_OPREGION is not set
+CONFIG_PM_ADVANCED_DEBUG=y
+# CONFIG_PM_AUTOSLEEP is not set
+CONFIG_PM_CLK=y
+CONFIG_PM_DEVFREQ_EVENT=y
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
+CONFIG_PM_NOTIFIER_ERROR_INJECT=m
+CONFIG_PM_OPP=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_DEBUG=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_STD_PARTITION=""
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_PM_TRACE=y
+CONFIG_PM_TRACE_RTC=y
+CONFIG_PM_WAKELOCKS_GC=y
+CONFIG_PM_WAKELOCKS_LIMIT=100
+CONFIG_PNFS_BLOCK=m
+CONFIG_PNFS_FILE_LAYOUT=m
+CONFIG_PNFS_FLEXFILE_LAYOUT=m
+CONFIG_PNFS_OBJLAYOUT=m
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
+# CONFIG_PNP_DEBUG_MESSAGES is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_AS3722=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_RESET_GPIO_RESTART=y
+CONFIG_POWER_RESET_HISI=y
+CONFIG_POWER_RESET_LTC2952=y
+CONFIG_POWER_RESET_MSM=y
+CONFIG_POWER_RESET_RESTART=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+CONFIG_POWER_RESET_VEXPRESS=y
+# CONFIG_POWER_RESET_XGENE is not set
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+CONFIG_PPDEV=m
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPS=m
+# CONFIG_PPS_CLIENT_KTIMER is not set
+CONFIG_PPS_CLIENT_PARPORT=m
+# CONFIG_PPS_DEBUG is not set
+CONFIG_PPTP=m
+CONFIG_PREEMPT_COUNT=y
+CONFIG_PREEMPT_NOTIFIERS=y
+CONFIG_PREEMPT_RCU=y
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_PRESCAN_RXQ is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_PRINTER=m
+CONFIG_PRINTK=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_PRISM2_USB=m
+# CONFIG_PRISM54 is not set
+CONFIG_PROCESSOR_SELECT=y
+CONFIG_PROC_CHILDREN=y
+CONFIG_PROC_EVENTS=y
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_VMCORE=y
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+CONFIG_PROFILING=y
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_PROVE_RCU is not set
+# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
+# CONFIG_PSTORE_CONSOLE is not set
+# CONFIG_PSTORE_FTRACE is not set
+# CONFIG_PSTORE_PMSG is not set
+CONFIG_PSTORE_RAM=m
+CONFIG_PTP_1588_CLOCK=m
+CONFIG_PTP_1588_CLOCK_GIANFAR=m
+CONFIG_PUBLIC_KEY_ALGO_RSA=y
+CONFIG_PUNIT_ATOM_DEBUG=m
+CONFIG_PVPANIC=m
+CONFIG_PWM_ATMEL_HLCDC_PWM=m
+CONFIG_PWM_BERLIN=m
+CONFIG_PWM_CRC=y
+CONFIG_PWM_FSL_FTM=m
+CONFIG_PWM_LP3943=m
+CONFIG_PWM_LPSS=m
+CONFIG_PWM_LPSS_PCI=m
+CONFIG_PWM_LPSS_PLATFORM=m
+CONFIG_PWM_MTK_DISP=m
+CONFIG_PWM_PCA9685=m
+CONFIG_PWM_SYSFS=y
+CONFIG_PWM_TWL=m
+CONFIG_PWM_TWL_LED=m
+CONFIG_PXA168_ETH=m
+CONFIG_QCA7000=m
+CONFIG_QCOM_BAM_DMA=m
+CONFIG_QCOM_COINCELL=m
+CONFIG_QCOM_GDSC=y
+CONFIG_QCOM_GSBI=m
+CONFIG_QCOM_QFPROM=m
+CONFIG_QCOM_SCM=y
+CONFIG_QCOM_SCM_64=y
+CONFIG_QCOM_SMD=m
+CONFIG_QCOM_SMD_RPM=m
+CONFIG_QCOM_SMEM=m
+CONFIG_QCOM_SPMI_IADC=m
+CONFIG_QCOM_SPMI_TEMP_ALARM=m
+CONFIG_QCOM_SPMI_VADC=m
+CONFIG_QCOM_WDT=m
+CONFIG_QDIO=m
+CONFIG_QED=m
+CONFIG_QEDE=m
+CONFIG_QETH=m
+CONFIG_QETH_IPV6=y
+CONFIG_QETH_L2=m
+CONFIG_QETH_L3=m
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_QLA3XXX=m
+CONFIG_QLCNIC=m
+CONFIG_QLCNIC_DCB=y
+CONFIG_QLCNIC_HWMON=y
+CONFIG_QLCNIC_SRIOV=y
+CONFIG_QLCNIC_VXLAN=y
+CONFIG_QLGE=m
+# CONFIG_QNX6FS_DEBUG is not set
+CONFIG_QSEMI_PHY=m
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_QUOTA=y
+CONFIG_QUOTACTL=y
+CONFIG_QUOTACTL_COMPAT=y
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QUOTA_TREE=m
+CONFIG_R6040=m
+CONFIG_R8169=m
+CONFIG_R8188EU=m
+CONFIG_R8712U=m
+CONFIG_R8723AU=m
+CONFIG_RADIO_ADAPTERS=y
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_SAA7706H=m
+CONFIG_RADIO_SHARK=m
+CONFIG_RADIO_SHARK2=m
+CONFIG_RADIO_SI470X=y
+CONFIG_RADIO_SI4713=m
+CONFIG_RADIO_SI476X=m
+CONFIG_RADIO_TEA575X=m
+CONFIG_RADIO_TEA5764=m
+CONFIG_RADIO_TEF6862=m
+CONFIG_RADIO_WL1273=m
+CONFIG_RADIO_WL128X=m
+CONFIG_RAID6_PQ=m
+CONFIG_RAID_ATTRS=m
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_RANDOMIZE_BASE=y
+CONFIG_RANDOMIZE_BASE_MAX_OFFSET=0x40000000
+CONFIG_RAPIDIO=y
+CONFIG_RAPIDIO_CPS_GEN2=m
+CONFIG_RAPIDIO_CPS_XX=m
+# CONFIG_RAPIDIO_DEBUG is not set
+CONFIG_RAPIDIO_DISC_TIMEOUT=30
+CONFIG_RAPIDIO_DMA_ENGINE=y
+# CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS is not set
+CONFIG_RAPIDIO_ENUM_BASIC=m
+CONFIG_RAPIDIO_TSI568=m
+CONFIG_RAPIDIO_TSI57X=m
+CONFIG_RAPIDIO_TSI721=m
+CONFIG_RAS=y
+CONFIG_RATIONAL=y
+CONFIG_RBTREE_TEST=m
+# CONFIG_RCU_EQS_DEBUG is not set
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+# CONFIG_RCU_EXPERT is not set
+CONFIG_RCU_STALL_COMMON=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_RC_CORE=m
+CONFIG_RC_DECODERS=y
+CONFIG_RC_DEVICES=y
+CONFIG_RC_LOOPBACK=m
+CONFIG_RC_MAP=m
+CONFIG_RDS=m
+# CONFIG_RDS_DEBUG is not set
+CONFIG_RDS_RDMA=m
+CONFIG_RDS_TCP=m
+CONFIG_RD_BZIP2=y
+CONFIG_RD_GZIP=y
+CONFIG_RD_LZ4=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
+CONFIG_RD_XZ=y
+# CONFIG_READABLE_ASM is not set
+CONFIG_REALTEK_AUTOPM=y
+CONFIG_REALTEK_PHY=m
+CONFIG_REED_SOLOMON=m
+CONFIG_REED_SOLOMON_DEC16=y
+CONFIG_REED_SOLOMON_DEC8=y
+CONFIG_REED_SOLOMON_ENC8=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_SPI=y
+CONFIG_REGMAP_SPMI=m
+CONFIG_REGULATOR_88PM800=m
+CONFIG_REGULATOR_88PM8607=m
+CONFIG_REGULATOR_AAT2870=m
+CONFIG_REGULATOR_AB3100=m
+CONFIG_REGULATOR_ACT8865=m
+CONFIG_REGULATOR_AD5398=m
+CONFIG_REGULATOR_ANATOP=m
+CONFIG_REGULATOR_ARIZONA=m
+CONFIG_REGULATOR_AS3711=m
+CONFIG_REGULATOR_AS3722=m
+CONFIG_REGULATOR_AXP20X=m
+CONFIG_REGULATOR_BCM590XX=m
+CONFIG_REGULATOR_DA903X=m
+CONFIG_REGULATOR_DA9052=m
+CONFIG_REGULATOR_DA9055=m
+CONFIG_REGULATOR_DA9062=m
+CONFIG_REGULATOR_DA9063=m
+CONFIG_REGULATOR_DA9210=m
+CONFIG_REGULATOR_DA9211=m
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_FAN53555=m
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_GPIO=m
+CONFIG_REGULATOR_HI6421=m
+CONFIG_REGULATOR_ISL6271A=m
+CONFIG_REGULATOR_ISL9305=m
+CONFIG_REGULATOR_LP3971=m
+CONFIG_REGULATOR_LP3972=m
+CONFIG_REGULATOR_LP872X=m
+CONFIG_REGULATOR_LP8755=m
+CONFIG_REGULATOR_LP8788=m
+CONFIG_REGULATOR_LTC3589=m
+CONFIG_REGULATOR_MAX14577=m
+CONFIG_REGULATOR_MAX1586=m
+CONFIG_REGULATOR_MAX77686=m
+CONFIG_REGULATOR_MAX77693=m
+CONFIG_REGULATOR_MAX77802=m
+CONFIG_REGULATOR_MAX8649=m
+CONFIG_REGULATOR_MAX8660=m
+CONFIG_REGULATOR_MAX8907=m
+CONFIG_REGULATOR_MAX8925=m
+CONFIG_REGULATOR_MAX8952=m
+CONFIG_REGULATOR_MAX8973=m
+CONFIG_REGULATOR_MAX8997=m
+CONFIG_REGULATOR_MAX8998=m
+CONFIG_REGULATOR_MC13783=m
+CONFIG_REGULATOR_MC13892=m
+CONFIG_REGULATOR_MC13XXX_CORE=m
+CONFIG_REGULATOR_MT6311=m
+CONFIG_REGULATOR_MT6397=m
+CONFIG_REGULATOR_PALMAS=m
+CONFIG_REGULATOR_PCAP=m
+CONFIG_REGULATOR_PCF50633=m
+CONFIG_REGULATOR_PFUZE100=m
+CONFIG_REGULATOR_PWM=m
+CONFIG_REGULATOR_QCOM_RPM=m
+CONFIG_REGULATOR_QCOM_SMD_RPM=m
+CONFIG_REGULATOR_QCOM_SPMI=m
+CONFIG_REGULATOR_RC5T583=m
+CONFIG_REGULATOR_RK808=m
+CONFIG_REGULATOR_RN5T618=m
+CONFIG_REGULATOR_RT5033=m
+CONFIG_REGULATOR_S2MPA01=m
+CONFIG_REGULATOR_S2MPS11=m
+CONFIG_REGULATOR_S5M8767=m
+CONFIG_REGULATOR_SKY81452=m
+CONFIG_REGULATOR_TPS51632=m
+CONFIG_REGULATOR_TPS6105X=m
+CONFIG_REGULATOR_TPS62360=m
+CONFIG_REGULATOR_TPS65023=m
+CONFIG_REGULATOR_TPS6507X=m
+CONFIG_REGULATOR_TPS65090=m
+CONFIG_REGULATOR_TPS65217=y
+CONFIG_REGULATOR_TPS65218=m
+CONFIG_REGULATOR_TPS6524X=m
+CONFIG_REGULATOR_TPS6586X=m
+CONFIG_REGULATOR_TPS65910=m
+CONFIG_REGULATOR_TPS65912=m
+CONFIG_REGULATOR_TPS80031=m
+CONFIG_REGULATOR_TWL4030=m
+CONFIG_REGULATOR_USERSPACE_CONSUMER=m
+CONFIG_REGULATOR_VEXPRESS=m
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=m
+CONFIG_REGULATOR_WM831X=m
+CONFIG_REGULATOR_WM8350=m
+CONFIG_REGULATOR_WM8400=m
+CONFIG_REGULATOR_WM8994=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_REISERFS_FS_XATTR=y
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_RELAY=y
+CONFIG_RELOCATABLE=y
+CONFIG_REMOTEPROC=m
+CONFIG_RETPOLINE=y
+CONFIG_RETU_WATCHDOG=m
+CONFIG_RFD_FTL=m
+CONFIG_RFKILL_GPIO=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_REGULATOR=m
+CONFIG_RFS_ACCEL=y
+CONFIG_RING_BUFFER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+CONFIG_RIONET=m
+CONFIG_RIONET_RX_SIZE=128
+CONFIG_RIONET_TX_SIZE=128
+CONFIG_RN5T618_WATCHDOG=m
+CONFIG_ROCKETPORT=m
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+CONFIG_ROMFS_ON_BLOCK=y
+CONFIG_ROSE=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPR0521=m
+CONFIG_RPS=y
+CONFIG_RSI_91X=m
+# CONFIG_RSI_DEBUGFS is not set
+CONFIG_RSI_SDIO=m
+CONFIG_RSI_USB=m
+CONFIG_RT2400PCI=m
+CONFIG_RT2500PCI=m
+CONFIG_RT2500USB=m
+CONFIG_RT2800PCI=m
+CONFIG_RT2800PCI_RT3290=y
+CONFIG_RT2800PCI_RT33XX=y
+CONFIG_RT2800PCI_RT35XX=y
+CONFIG_RT2800PCI_RT53XX=y
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT33XX=y
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT35XX=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RT2800_LIB=m
+CONFIG_RT2800_LIB_MMIO=m
+CONFIG_RT2X00=m
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_CRYPTO=y
+# CONFIG_RT2X00_LIB_DEBUGFS is not set
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_LEDS=y
+CONFIG_RT2X00_LIB_MMIO=m
+CONFIG_RT2X00_LIB_PCI=m
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT61PCI=m
+CONFIG_RT73USB=m
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DEBUG is not set
+CONFIG_RTC_DRV_88PM80X=m
+CONFIG_RTC_DRV_88PM860X=m
+CONFIG_RTC_DRV_AB3100=m
+CONFIG_RTC_DRV_ABB5ZES3=m
+CONFIG_RTC_DRV_ABX80X=m
+CONFIG_RTC_DRV_AS3722=m
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_BQ4802=m
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_RTC_DRV_DA9052=m
+CONFIG_RTC_DRV_DA9055=m
+CONFIG_RTC_DRV_DA9063=m
+CONFIG_RTC_DRV_DS1286=m
+CONFIG_RTC_DRV_DS1305=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_DS1343=m
+CONFIG_RTC_DRV_DS1347=m
+CONFIG_RTC_DRV_DS1374=m
+CONFIG_RTC_DRV_DS1374_WDT=y
+CONFIG_RTC_DRV_DS1390=m
+CONFIG_RTC_DRV_DS1511=m
+CONFIG_RTC_DRV_DS1553=m
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_RTC_DRV_DS1685=y
+CONFIG_RTC_DRV_DS1685_FAMILY=m
+# CONFIG_RTC_DRV_DS1689 is not set
+# CONFIG_RTC_DRV_DS17285 is not set
+CONFIG_RTC_DRV_DS1742=m
+# CONFIG_RTC_DRV_DS17485 is not set
+# CONFIG_RTC_DRV_DS17885 is not set
+CONFIG_RTC_DRV_DS2404=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_DS3234=m
+CONFIG_RTC_DRV_EFI=y
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_FM3130=m
+CONFIG_RTC_DRV_HID_SENSOR_TIME=m
+CONFIG_RTC_DRV_HYM8563=m
+CONFIG_RTC_DRV_ISL12022=m
+CONFIG_RTC_DRV_ISL12057=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_LP8788=m
+CONFIG_RTC_DRV_M41T80=m
+CONFIG_RTC_DRV_M41T80_WDT=y
+CONFIG_RTC_DRV_M41T93=m
+CONFIG_RTC_DRV_M41T94=m
+CONFIG_RTC_DRV_M48T35=m
+CONFIG_RTC_DRV_M48T59=m
+CONFIG_RTC_DRV_M48T86=m
+CONFIG_RTC_DRV_MAX6900=m
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_RTC_DRV_MAX77686=m
+CONFIG_RTC_DRV_MAX77802=m
+CONFIG_RTC_DRV_MAX8907=m
+CONFIG_RTC_DRV_MAX8925=m
+CONFIG_RTC_DRV_MAX8997=m
+CONFIG_RTC_DRV_MAX8998=m
+CONFIG_RTC_DRV_MC13XXX=m
+CONFIG_RTC_DRV_MCP795=m
+CONFIG_RTC_DRV_MSM6242=m
+CONFIG_RTC_DRV_MT6397=m
+CONFIG_RTC_DRV_PALMAS=m
+CONFIG_RTC_DRV_PCAP=m
+CONFIG_RTC_DRV_PCF2123=m
+CONFIG_RTC_DRV_PCF2127=m
+CONFIG_RTC_DRV_PCF50633=m
+CONFIG_RTC_DRV_PCF85063=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_PL030=m
+CONFIG_RTC_DRV_PL031=m
+CONFIG_RTC_DRV_PM8XXX=m
+CONFIG_RTC_DRV_R9701=m
+CONFIG_RTC_DRV_RC5T583=m
+CONFIG_RTC_DRV_RK808=m
+CONFIG_RTC_DRV_RP5C01=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_RV3029C2=m
+CONFIG_RTC_DRV_RV8803=m
+CONFIG_RTC_DRV_RX4581=m
+CONFIG_RTC_DRV_RX8025=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_S5M=m
+CONFIG_RTC_DRV_SNVS=m
+CONFIG_RTC_DRV_STK17TA8=m
+# CONFIG_RTC_DRV_TEST is not set
+CONFIG_RTC_DRV_TPS6586X=m
+CONFIG_RTC_DRV_TPS65910=m
+CONFIG_RTC_DRV_TPS80031=m
+CONFIG_RTC_DRV_TWL4030=m
+CONFIG_RTC_DRV_V3020=m
+CONFIG_RTC_DRV_WM831X=m
+CONFIG_RTC_DRV_WM8350=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_RTC_DRV_XGENE=y
+CONFIG_RTC_DRV_ZYNQMP=m
+# CONFIG_RTC_DS1685_PROC_REGS is not set
+# CONFIG_RTC_DS1685_SYSFS_REGS is not set
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
+CONFIG_RTL8180=m
+CONFIG_RTL8187=m
+CONFIG_RTL8187_LEDS=y
+CONFIG_RTL8188EE=m
+CONFIG_RTL8192CE=m
+CONFIG_RTL8192CU=m
+CONFIG_RTL8192C_COMMON=m
+CONFIG_RTL8192DE=m
+CONFIG_RTL8192E=m
+CONFIG_RTL8192EE=m
+CONFIG_RTL8192SE=m
+CONFIG_RTL8192U=m
+CONFIG_RTL8723AE=m
+CONFIG_RTL8723BE=m
+CONFIG_RTL8723_COMMON=m
+CONFIG_RTL8821AE=m
+CONFIG_RTL8XXXU=m
+CONFIG_RTL8XXXU_UNTESTED=y
+CONFIG_RTLBTCOEXIST=m
+CONFIG_RTLLIB=m
+CONFIG_RTLLIB_CRYPTO_CCMP=m
+CONFIG_RTLLIB_CRYPTO_TKIP=m
+CONFIG_RTLLIB_CRYPTO_WEP=m
+CONFIG_RTLWIFI=m
+# CONFIG_RTLWIFI_DEBUG is not set
+CONFIG_RTLWIFI_PCI=m
+CONFIG_RTLWIFI_USB=m
+CONFIG_RTL_CARDS=m
+CONFIG_RTS5208=m
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_RXKAD=m
+CONFIG_S2IO=m
+CONFIG_S390=y
+CONFIG_S390_GUEST=y
+CONFIG_S390_HYPFS_FS=y
+CONFIG_S390_IOMMU=y
+CONFIG_S390_PRNG=m
+CONFIG_S390_PTDUMP=y
+CONFIG_S390_TAPE=m
+CONFIG_S390_TAPE_34XX=m
+CONFIG_S390_TAPE_3590=m
+CONFIG_S390_VMUR=m
+# CONFIG_SAMPLES is not set
+CONFIG_SAMSUNG_LAPTOP=m
+CONFIG_SAMSUNG_Q10=m
+CONFIG_SATA_ACARD_AHCI=m
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_AHCI_PLATFORM=m
+CONFIG_SATA_INIC162X=m
+CONFIG_SATA_MV=m
+CONFIG_SATA_NV=m
+CONFIG_SATA_PMP=y
+CONFIG_SATA_PROMISE=m
+CONFIG_SATA_QSTOR=m
+CONFIG_SATA_SIL=m
+CONFIG_SATA_SIL24=m
+CONFIG_SATA_SIS=m
+CONFIG_SATA_SVW=m
+CONFIG_SATA_SX4=m
+CONFIG_SATA_ULI=m
+CONFIG_SATA_VIA=m
+CONFIG_SATA_VITESSE=m
+CONFIG_SATA_ZPODD=y
+CONFIG_SBC_EPX_C3_WATCHDOG=m
+CONFIG_SBC_FITPC2_WATCHDOG=m
+CONFIG_SBNI=m
+# CONFIG_SBNI_MULTILINE is not set
+CONFIG_SBP_TARGET=m
+CONFIG_SC1200_WDT=m
+CONFIG_SC92031=m
+CONFIG_SCA3000=m
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_BOOK=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHED_HRTICK=y
+CONFIG_SCHED_INFO=y
+CONFIG_SCHED_MC=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_SCHED_TOPOLOGY=y
+CONFIG_SCHED_TRACER=y
+CONFIG_SCIF=m
+CONFIG_SCIF_BUS=m
+CONFIG_SCLP_ASYNC=m
+CONFIG_SCLP_ASYNC_ID="000000000"
+CONFIG_SCLP_CONSOLE=y
+CONFIG_SCLP_CPI=m
+CONFIG_SCLP_TTY=y
+CONFIG_SCLP_VT220_CONSOLE=y
+CONFIG_SCLP_VT220_TTY=y
+CONFIG_SCM_BLOCK=m
+CONFIG_SCM_BLOCK_CLUSTER_WRITE=y
+CONFIG_SCM_BUS=y
+CONFIG_SCSI=y
+CONFIG_SCSI_BUSLOGIC=m
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_ALUA=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_EATA=m
+CONFIG_SCSI_EATA_LINKED_COMMANDS=y
+CONFIG_SCSI_EATA_MAX_TAGS=16
+CONFIG_SCSI_EATA_TAGGED_QUEUE=y
+CONFIG_SCSI_ENCLOSURE=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_FLASHPOINT=y
+CONFIG_SCSI_GDTH=m
+CONFIG_SCSI_IMM=m
+CONFIG_SCSI_IPR=m
+CONFIG_SCSI_IPR_DUMP=y
+CONFIG_SCSI_IPR_TRACE=y
+CONFIG_SCSI_ISCI=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_LOWLEVEL=y
+CONFIG_SCSI_LOWLEVEL_PCMCIA=y
+# CONFIG_SCSI_LPFC_DEBUG_FS is not set
+CONFIG_SCSI_MOD=y
+CONFIG_SCSI_MPT2SAS=m
+CONFIG_SCSI_MPT2SAS_MAX_SGE=128
+CONFIG_SCSI_MPT3SAS=m
+CONFIG_SCSI_MPT3SAS_MAX_SGE=128
+# CONFIG_SCSI_MQ_DEFAULT is not set
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+# CONFIG_SCSI_MVSAS_TASKLET is not set
+CONFIG_SCSI_NETLINK=y
+# CONFIG_SCSI_OSD_DEBUG is not set
+CONFIG_SCSI_OSD_DPRINT_SENSE=1
+CONFIG_SCSI_OSD_INITIATOR=m
+CONFIG_SCSI_OSD_ULD=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_PROC_FS=y
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_SAS_ATTRS=m
+CONFIG_SCSI_SAS_HOST_SMP=y
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SCAN_ASYNC=y
+# CONFIG_SCSI_SNIC_DEBUG_FS is not set
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_SYM53C8XX_MMIO=y
+CONFIG_SCSI_UFSHCD_PCI=m
+CONFIG_SCSI_UFSHCD_PLATFORM=m
+# CONFIG_SCSI_UFS_QCOM is not set
+CONFIG_SCSI_VIRTIO=m
+CONFIG_SCTP_COOKIE_HMAC_MD5=y
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y
+CONFIG_SDIO_UART=m
+# CONFIG_SDMA_VERBOSITY is not set
+CONFIG_SECCOMP=y
+CONFIG_SECCOMP_FILTER=y
+CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
+CONFIG_SECURITY_APPARMOR_HASH=y
+CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y
+# CONFIG_SECURITY_APPARMOR_STATS is not set
+CONFIG_SECURITY_APPARMOR_UNCONFINED_INIT=y
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_PATH=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
+CONFIG_SECURITY_SMACK=y
+# CONFIG_SECURITY_SMACK_BRINGUP is not set
+CONFIG_SECURITY_SMACK_NETFILTER=y
+CONFIG_SECURITY_TOMOYO=y
+CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER="/sbin/init"
+CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY=2048
+CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG=1024
+# CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER is not set
+CONFIG_SECURITY_TOMOYO_POLICY_LOADER="/sbin/tomoyo-init"
+CONFIG_SECURITY_YAMA=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_SENSORS_ABITUGURU=m
+CONFIG_SENSORS_ABITUGURU3=m
+CONFIG_SENSORS_ACPI_POWER=m
+CONFIG_SENSORS_AD7314=m
+CONFIG_SENSORS_AD7414=m
+CONFIG_SENSORS_AD7418=m
+CONFIG_SENSORS_ADC128D818=m
+CONFIG_SENSORS_ADCXX=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1029=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ADM1275=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_ADS1015=m
+CONFIG_SENSORS_ADS7828=m
+CONFIG_SENSORS_ADS7871=m
+CONFIG_SENSORS_ADT7310=m
+CONFIG_SENSORS_ADT7410=m
+CONFIG_SENSORS_ADT7411=m
+CONFIG_SENSORS_ADT7462=m
+CONFIG_SENSORS_ADT7470=m
+CONFIG_SENSORS_ADT7475=m
+CONFIG_SENSORS_ADT7X10=m
+CONFIG_SENSORS_AMC6821=m
+CONFIG_SENSORS_APDS990X=m
+CONFIG_SENSORS_APPLESMC=m
+CONFIG_SENSORS_ARM_SCPI=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_ASC7621=m
+CONFIG_SENSORS_ATK0110=m
+CONFIG_SENSORS_ATXP1=m
+CONFIG_SENSORS_BH1770=m
+CONFIG_SENSORS_BH1780=m
+CONFIG_SENSORS_CORETEMP=m
+CONFIG_SENSORS_DA9052_ADC=m
+CONFIG_SENSORS_DA9055=m
+CONFIG_SENSORS_DELL_SMM=m
+CONFIG_SENSORS_DME1737=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_DS620=m
+CONFIG_SENSORS_EMC1403=m
+CONFIG_SENSORS_EMC2103=m
+CONFIG_SENSORS_EMC6W201=m
+CONFIG_SENSORS_F71805F=m
+CONFIG_SENSORS_F71882FG=m
+CONFIG_SENSORS_F75375S=m
+CONFIG_SENSORS_FAM15H_POWER=m
+CONFIG_SENSORS_FSCHMD=m
+CONFIG_SENSORS_G760A=m
+CONFIG_SENSORS_G762=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_GPIO_FAN=m
+CONFIG_SENSORS_HDAPS=m
+CONFIG_SENSORS_HIH6130=m
+CONFIG_SENSORS_HMC5843=m
+CONFIG_SENSORS_HMC5843_I2C=m
+CONFIG_SENSORS_HMC5843_SPI=m
+CONFIG_SENSORS_HTU21=m
+CONFIG_SENSORS_I5500=m
+CONFIG_SENSORS_I5K_AMB=m
+CONFIG_SENSORS_IBMAEM=m
+CONFIG_SENSORS_IBMPEX=m
+CONFIG_SENSORS_IIO_HWMON=m
+CONFIG_SENSORS_INA209=m
+CONFIG_SENSORS_INA2XX=m
+CONFIG_SENSORS_ISL29018=m
+CONFIG_SENSORS_ISL29028=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_K10TEMP=m
+CONFIG_SENSORS_K8TEMP=m
+CONFIG_SENSORS_LINEAGE=m
+CONFIG_SENSORS_LIS3LV02D=m
+CONFIG_SENSORS_LIS3_I2C=m
+CONFIG_SENSORS_LM25066=m
+CONFIG_SENSORS_LM3533=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM70=m
+CONFIG_SENSORS_LM73=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_LM93=m
+CONFIG_SENSORS_LM95234=m
+CONFIG_SENSORS_LM95241=m
+CONFIG_SENSORS_LM95245=m
+CONFIG_SENSORS_LTC2945=m
+CONFIG_SENSORS_LTC2978=m
+CONFIG_SENSORS_LTC2978_REGULATOR=y
+CONFIG_SENSORS_LTC4151=m
+CONFIG_SENSORS_LTC4215=m
+CONFIG_SENSORS_LTC4222=m
+CONFIG_SENSORS_LTC4245=m
+CONFIG_SENSORS_LTC4260=m
+CONFIG_SENSORS_LTC4261=m
+CONFIG_SENSORS_MAX1111=m
+CONFIG_SENSORS_MAX16064=m
+CONFIG_SENSORS_MAX16065=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_MAX1668=m
+CONFIG_SENSORS_MAX197=m
+CONFIG_SENSORS_MAX20751=m
+CONFIG_SENSORS_MAX31790=m
+CONFIG_SENSORS_MAX34440=m
+CONFIG_SENSORS_MAX6639=m
+CONFIG_SENSORS_MAX6642=m
+CONFIG_SENSORS_MAX6650=m
+CONFIG_SENSORS_MAX6697=m
+CONFIG_SENSORS_MAX8688=m
+CONFIG_SENSORS_MC13783_ADC=m
+CONFIG_SENSORS_MCP3021=m
+CONFIG_SENSORS_MENF21BMC_HWMON=m
+CONFIG_SENSORS_NCT6683=m
+CONFIG_SENSORS_NCT6775=m
+CONFIG_SENSORS_NCT7802=m
+CONFIG_SENSORS_NCT7904=m
+CONFIG_SENSORS_NTC_THERMISTOR=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_PC87427=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_PMBUS=m
+CONFIG_SENSORS_POWR1220=m
+CONFIG_SENSORS_PWM_FAN=m
+CONFIG_SENSORS_SCH5627=m
+CONFIG_SENSORS_SCH5636=m
+CONFIG_SENSORS_SCH56XX_COMMON=m
+CONFIG_SENSORS_SHT15=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_SMM665=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_SMSC47M192=m
+CONFIG_SENSORS_TC74=m
+CONFIG_SENSORS_THMC50=m
+CONFIG_SENSORS_TMP102=m
+CONFIG_SENSORS_TMP103=m
+CONFIG_SENSORS_TMP401=m
+CONFIG_SENSORS_TMP421=m
+CONFIG_SENSORS_TPS40422=m
+CONFIG_SENSORS_TSL2550=m
+CONFIG_SENSORS_TSL2563=m
+CONFIG_SENSORS_TWL4030_MADC=m
+CONFIG_SENSORS_UCD9000=m
+CONFIG_SENSORS_UCD9200=m
+CONFIG_SENSORS_VEXPRESS=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_VIA_CPUTEMP=m
+CONFIG_SENSORS_VT1211=m
+CONFIG_SENSORS_VT8231=m
+CONFIG_SENSORS_W83627EHF=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83791D=m
+CONFIG_SENSORS_W83792D=m
+CONFIG_SENSORS_W83793=m
+CONFIG_SENSORS_W83795=m
+# CONFIG_SENSORS_W83795_FANCTRL is not set
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83L786NG=m
+CONFIG_SENSORS_WM831X=m
+CONFIG_SENSORS_WM8350=m
+CONFIG_SENSORS_ZL6100=m
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_DMA=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_FINTEK=m
+CONFIG_SERIAL_8250_INGENIC=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_MID=m
+CONFIG_SERIAL_8250_MT6577=y
+CONFIG_SERIAL_8250_NR_UARTS=48
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_8250_RT288X=y
+CONFIG_SERIAL_8250_RUNTIME_UARTS=32
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_ALTERA_UART_BAUDRATE=115200
+CONFIG_SERIAL_ALTERA_UART_MAXPORTS=4
+CONFIG_SERIAL_AMBA_PL010=m
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_ARC_NR_PORTS=1
+CONFIG_SERIAL_CONEXANT_DIGICOLOR=m
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_EARLYCON=y
+CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST=y
+# CONFIG_SERIAL_IFX6X60 is not set
+CONFIG_SERIAL_IPOCTAL=m
+CONFIG_SERIAL_KGDB_NMI=y
+CONFIG_SERIAL_MAX3100=m
+CONFIG_SERIAL_MAX310X=y
+CONFIG_SERIAL_MEN_Z135=m
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_RP2_NR_UARTS=32
+CONFIG_SERIAL_SC16IS7XX=m
+CONFIG_SERIAL_SC16IS7XX_CORE=m
+CONFIG_SERIAL_SC16IS7XX_I2C=y
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_SERIAL_SCCNXP_CONSOLE=y
+CONFIG_SERIAL_SPRD=m
+CONFIG_SERIAL_UARTLITE=m
+CONFIG_SERIAL_XILINX_PS_UART=m
+CONFIG_SERIO_ALTERA_PS2=m
+CONFIG_SERIO_AMBAKMI=m
+CONFIG_SERIO_APBPS2=m
+CONFIG_SERIO_ARC_PS2=m
+CONFIG_SERIO_CT82C710=m
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_PS2MULT=m
+CONFIG_SERIO_RAW=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SETEND_EMULATION=y
+CONFIG_SFC_MCDI_LOGGING=y
+CONFIG_SFC_MCDI_MON=y
+CONFIG_SFC_MTD=y
+CONFIG_SFC_SRIOV=y
+CONFIG_SFI=y
+CONFIG_SGETMASK_SYSCALL=y
+# CONFIG_SG_SPLIT is not set
+CONFIG_SHMEM=y
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+CONFIG_SI7005=m
+CONFIG_SI7020=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_SIGNALFD=y
+CONFIG_SIGNATURE=y
+CONFIG_SIGNED_PE_FILE_VERIFICATION=y
+CONFIG_SIS190=m
+CONFIG_SIS900=m
+CONFIG_SKFP=m
+CONFIG_SKGE=m
+# CONFIG_SKGE_DEBUG is not set
+CONFIG_SKGE_GENESIS=y
+CONFIG_SKY2=m
+# CONFIG_SKY2_DEBUG is not set
+# CONFIG_SLAB is not set
+CONFIG_SLABINFO=y
+CONFIG_SLHC=y
+CONFIG_SLICOSS=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLOB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_CPU_PARTIAL=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_SMC91X=y
+CONFIG_SMC_IRCC_FIR=m
+CONFIG_SMP=y
+CONFIG_SMSC37B787_WDT=m
+CONFIG_SMSC911X=m
+# CONFIG_SMSC911X_ARCH_HOOKS is not set
+CONFIG_SMSC9420=m
+CONFIG_SMSC_PHY=m
+CONFIG_SMSC_SCH311X_WDT=m
+CONFIG_SMSGIUCV=y
+CONFIG_SMSGIUCV_EVENT=m
+CONFIG_SMS_SDIO_DRV=m
+CONFIG_SMS_SIANO_DEBUGFS=y
+CONFIG_SMS_SIANO_MDTV=m
+CONFIG_SMS_SIANO_RC=y
+CONFIG_SMS_USB_DRV=m
+CONFIG_SM_FTL=m
+CONFIG_SND=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_POWER_SAVE=y
+CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0
+CONFIG_SND_AD1889=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ALOOP=m
+CONFIG_SND_ALS300=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_ASIHPI=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_ATMEL_SOC=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AW2=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BCD2000=m
+CONFIG_SND_BEBOB=m
+CONFIG_SND_BT87X=m
+# CONFIG_SND_BT87X_OVERCLOCK is not set
+CONFIG_SND_CA0106=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_COMPRESS_OFFLOAD=m
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CTXFI=m
+CONFIG_SND_DARLA20=m
+CONFIG_SND_DARLA24=m
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DESIGNWARE_I2S=m
+CONFIG_SND_DICE=m
+CONFIG_SND_DMAENGINE_PCM=m
+CONFIG_SND_DMA_SGBUF=y
+CONFIG_SND_DRIVERS=y
+CONFIG_SND_DUMMY=m
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_ECHO3G=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_EMU10K1X=m
+CONFIG_SND_EMU10K1_SEQ=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_ES1968_INPUT=y
+CONFIG_SND_ES1968_RADIO=y
+CONFIG_SND_FIREWIRE=y
+CONFIG_SND_FIREWIRE_DIGI00X=m
+CONFIG_SND_FIREWIRE_LIB=m
+CONFIG_SND_FIREWIRE_TASCAM=m
+CONFIG_SND_FIREWORKS=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_GINA20=m
+CONFIG_SND_GINA24=m
+CONFIG_SND_HDA=m
+CONFIG_SND_HDA_CODEC_ANALOG=m
+CONFIG_SND_HDA_CODEC_CA0110=m
+CONFIG_SND_HDA_CODEC_CA0132=m
+CONFIG_SND_HDA_CODEC_CA0132_DSP=y
+CONFIG_SND_HDA_CODEC_CIRRUS=m
+CONFIG_SND_HDA_CODEC_CMEDIA=m
+CONFIG_SND_HDA_CODEC_CONEXANT=m
+CONFIG_SND_HDA_CODEC_HDMI=m
+CONFIG_SND_HDA_CODEC_REALTEK=m
+CONFIG_SND_HDA_CODEC_SI3054=m
+CONFIG_SND_HDA_CODEC_SIGMATEL=m
+CONFIG_SND_HDA_CODEC_VIA=m
+CONFIG_SND_HDA_CORE=m
+CONFIG_SND_HDA_DSP_LOADER=y
+CONFIG_SND_HDA_EXT_CORE=m
+CONFIG_SND_HDA_GENERIC=m
+CONFIG_SND_HDA_HWDEP=y
+CONFIG_SND_HDA_I915=y
+CONFIG_SND_HDA_INPUT_BEEP=y
+CONFIG_SND_HDA_INPUT_BEEP_MODE=0
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDA_PATCH_LOADER=y
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+CONFIG_SND_HDA_RECONFIG=y
+CONFIG_SND_HDSP=m
+CONFIG_SND_HDSPM=m
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INDIGO=m
+CONFIG_SND_INDIGODJ=m
+CONFIG_SND_INDIGODJX=m
+CONFIG_SND_INDIGOIO=m
+CONFIG_SND_INDIGOIOX=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_ISIGHT=m
+CONFIG_SND_JACK=y
+CONFIG_SND_KORG1212=m
+CONFIG_SND_LAYLA20=m
+CONFIG_SND_LAYLA24=m
+CONFIG_SND_LOLA=m
+CONFIG_SND_LX6464ES=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_MAESTRO3_INPUT=y
+CONFIG_SND_MAX_CARDS=32
+CONFIG_SND_MIA=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_MONA=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_MTS64=m
+CONFIG_SND_NM256=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_OPL3_LIB_SEQ=m
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_OXFW=m
+CONFIG_SND_OXYGEN=m
+CONFIG_SND_OXYGEN_LIB=m
+CONFIG_SND_PCI=y
+CONFIG_SND_PCM=m
+CONFIG_SND_PCMCIA=y
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_PCM_TIMER=y
+CONFIG_SND_PCSP=m
+CONFIG_SND_PCXHR=m
+CONFIG_SND_PDAUDIOCF=m
+CONFIG_SND_PORTMAN2X4=m
+CONFIG_SND_PROC_FS=y
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_RAWMIDI_SEQ=m
+CONFIG_SND_RIPTIDE=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+# CONFIG_SND_SBAWE_SEQ is not set
+CONFIG_SND_SB_COMMON=m
+CONFIG_SND_SCS1X=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_SOC_AC97_CODEC=m
+CONFIG_SND_SOC_ADAU1701=m
+CONFIG_SND_SOC_AK4104=m
+CONFIG_SND_SOC_AK4554=m
+CONFIG_SND_SOC_AK4613=m
+CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_AK5386=m
+CONFIG_SND_SOC_ALC5623=m
+CONFIG_SND_SOC_APQ8016_SBC=m
+CONFIG_SND_SOC_COMPRESS=y
+CONFIG_SND_SOC_CS35L32=m
+CONFIG_SND_SOC_CS4265=m
+CONFIG_SND_SOC_CS4270=m
+CONFIG_SND_SOC_CS4271=m
+CONFIG_SND_SOC_CS4271_I2C=m
+CONFIG_SND_SOC_CS4271_SPI=m
+CONFIG_SND_SOC_CS42L51=m
+CONFIG_SND_SOC_CS42L51_I2C=m
+CONFIG_SND_SOC_CS42L52=m
+CONFIG_SND_SOC_CS42L56=m
+CONFIG_SND_SOC_CS42L73=m
+CONFIG_SND_SOC_CS42XX8=m
+CONFIG_SND_SOC_CS42XX8_I2C=m
+CONFIG_SND_SOC_CS4349=m
+CONFIG_SND_SOC_DMIC=m
+CONFIG_SND_SOC_ES8328=m
+CONFIG_SND_SOC_FSL_ASRC=m
+CONFIG_SND_SOC_FSL_ESAI=m
+CONFIG_SND_SOC_FSL_SAI=m
+CONFIG_SND_SOC_FSL_SPDIF=m
+CONFIG_SND_SOC_FSL_SSI=m
+CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
+CONFIG_SND_SOC_GTM601=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+CONFIG_SND_SOC_IMX_AUDMUX=m
+CONFIG_SND_SOC_INTEL_BAYTRAIL=m
+CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m
+CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m
+CONFIG_SND_SOC_INTEL_BYTCR_RT5660_MACH=m
+CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH=m
+CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH=m
+CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH=m
+CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m
+CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m
+CONFIG_SND_SOC_INTEL_HASWELL=m
+CONFIG_SND_SOC_INTEL_HASWELL_MACH=m
+CONFIG_SND_SOC_INTEL_SKL_RT286_MACH=m
+CONFIG_SND_SOC_INTEL_SKYLAKE=m
+CONFIG_SND_SOC_INTEL_SST=m
+CONFIG_SND_SOC_INTEL_SST_ACPI=m
+CONFIG_SND_SOC_LPASS_APQ8016=m
+CONFIG_SND_SOC_LPASS_CPU=m
+CONFIG_SND_SOC_LPASS_IPQ806X=m
+CONFIG_SND_SOC_LPASS_PLATFORM=m
+CONFIG_SND_SOC_MAX98090=m
+CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_MEDIATEK=m
+CONFIG_SND_SOC_MT8173_MAX98090=m
+CONFIG_SND_SOC_MT8173_RT5650_RT5676=m
+CONFIG_SND_SOC_PCM1681=m
+CONFIG_SND_SOC_PCM1792A=m
+CONFIG_SND_SOC_PCM512x=m
+CONFIG_SND_SOC_PCM512x_I2C=m
+CONFIG_SND_SOC_PCM512x_SPI=m
+CONFIG_SND_SOC_QCOM=m
+CONFIG_SND_SOC_RL6231=m
+CONFIG_SND_SOC_RL6347A=m
+CONFIG_SND_SOC_RT286=m
+CONFIG_SND_SOC_RT5631=m
+CONFIG_SND_SOC_RT5640=m
+CONFIG_SND_SOC_RT5645=m
+CONFIG_SND_SOC_RT5660=m
+CONFIG_SND_SOC_RT5670=m
+CONFIG_SND_SOC_RT5677=m
+CONFIG_SND_SOC_SGTL5000=m
+CONFIG_SND_SOC_SI476X=m
+CONFIG_SND_SOC_SIGMADSP=m
+CONFIG_SND_SOC_SIGMADSP_I2C=m
+CONFIG_SND_SOC_SIRF_AUDIO_CODEC=m
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_SSM2602=m
+CONFIG_SND_SOC_SSM2602_I2C=m
+CONFIG_SND_SOC_SSM2602_SPI=m
+CONFIG_SND_SOC_SSM4567=m
+CONFIG_SND_SOC_STA32X=m
+CONFIG_SND_SOC_STA350=m
+CONFIG_SND_SOC_STI_SAS=m
+CONFIG_SND_SOC_STORM=m
+CONFIG_SND_SOC_TAS2552=m
+CONFIG_SND_SOC_TAS5086=m
+CONFIG_SND_SOC_TAS571X=m
+CONFIG_SND_SOC_TFA9879=m
+CONFIG_SND_SOC_TLV320AIC23=m
+CONFIG_SND_SOC_TLV320AIC23_I2C=m
+CONFIG_SND_SOC_TLV320AIC23_SPI=m
+CONFIG_SND_SOC_TLV320AIC31XX=m
+CONFIG_SND_SOC_TLV320AIC3X=m
+CONFIG_SND_SOC_TOPOLOGY=y
+CONFIG_SND_SOC_TPA6130A2=m
+CONFIG_SND_SOC_TS3A227E=m
+CONFIG_SND_SOC_WM8510=m
+CONFIG_SND_SOC_WM8523=m
+CONFIG_SND_SOC_WM8580=m
+CONFIG_SND_SOC_WM8711=m
+CONFIG_SND_SOC_WM8728=m
+CONFIG_SND_SOC_WM8731=m
+CONFIG_SND_SOC_WM8737=m
+CONFIG_SND_SOC_WM8741=m
+CONFIG_SND_SOC_WM8750=m
+CONFIG_SND_SOC_WM8753=m
+CONFIG_SND_SOC_WM8770=m
+CONFIG_SND_SOC_WM8776=m
+CONFIG_SND_SOC_WM8804=m
+CONFIG_SND_SOC_WM8804_I2C=m
+CONFIG_SND_SOC_WM8804_SPI=m
+CONFIG_SND_SOC_WM8903=m
+CONFIG_SND_SOC_WM8962=m
+CONFIG_SND_SOC_WM8978=m
+CONFIG_SND_SOC_XTFPGA_I2S=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_SPI=y
+CONFIG_SND_SST_IPC=m
+CONFIG_SND_SST_IPC_ACPI=m
+CONFIG_SND_SST_MFLD_PLATFORM=m
+CONFIG_SND_SUN4I_CODEC=m
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_TIMER=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_USB=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_HIFACE=m
+CONFIG_SND_USB_LINE6=m
+CONFIG_SND_USB_POD=m
+CONFIG_SND_USB_PODHD=m
+CONFIG_SND_USB_TONEPORT=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_US122L=m
+CONFIG_SND_USB_USX2Y=m
+CONFIG_SND_USB_VARIAX=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_VIRTUOSO=m
+CONFIG_SND_VMASTER=y
+CONFIG_SND_VX222=m
+CONFIG_SND_VXPOCKET=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SOC_CAMERA=m
+CONFIG_SOC_CAMERA_IMX074=m
+CONFIG_SOC_CAMERA_MT9M001=m
+CONFIG_SOC_CAMERA_MT9M111=m
+CONFIG_SOC_CAMERA_MT9T031=m
+CONFIG_SOC_CAMERA_MT9T112=m
+CONFIG_SOC_CAMERA_MT9V022=m
+CONFIG_SOC_CAMERA_OV2640=m
+CONFIG_SOC_CAMERA_OV5642=m
+CONFIG_SOC_CAMERA_OV6650=m
+CONFIG_SOC_CAMERA_OV772X=m
+CONFIG_SOC_CAMERA_OV9640=m
+CONFIG_SOC_CAMERA_OV9740=m
+CONFIG_SOC_CAMERA_PLATFORM=m
+CONFIG_SOC_CAMERA_RJ54N1=m
+CONFIG_SOC_CAMERA_TW9910=m
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_SONYPI_COMPAT=y
+CONFIG_SONY_FF=y
+CONFIG_SONY_LAPTOP=m
+CONFIG_SOUND_OSS_CORE=y
+# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_SP5100_TCO=m
+CONFIG_SPARSEMEM=y
+CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_SPARSE_RCU_POINTER is not set
+CONFIG_SPEAKUP=m
+CONFIG_SPEAKUP_SYNTH_ACNTSA=m
+CONFIG_SPEAKUP_SYNTH_APOLLO=m
+CONFIG_SPEAKUP_SYNTH_AUDPTR=m
+CONFIG_SPEAKUP_SYNTH_BNS=m
+CONFIG_SPEAKUP_SYNTH_DECEXT=m
+CONFIG_SPEAKUP_SYNTH_DECTLK=m
+CONFIG_SPEAKUP_SYNTH_DUMMY=m
+CONFIG_SPEAKUP_SYNTH_LTLK=m
+CONFIG_SPEAKUP_SYNTH_SOFT=m
+CONFIG_SPEAKUP_SYNTH_SPKOUT=m
+CONFIG_SPEAKUP_SYNTH_TXPRT=m
+# CONFIG_SPECTRE_BHI_AUTO is not set
+# CONFIG_SPECTRE_BHI_OFF is not set
+CONFIG_SPECTRE_BHI_ON=y
+CONFIG_SPI_ALTERA=m
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_BUTTERFLY=m
+CONFIG_SPI_CADENCE=m
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_DESIGNWARE=m
+CONFIG_SPI_DLN2=m
+CONFIG_SPI_DW_MID_DMA=y
+CONFIG_SPI_DW_MMIO=m
+CONFIG_SPI_DW_PCI=m
+CONFIG_SPI_DYNAMIC=y
+CONFIG_SPI_FSL_DSPI=m
+CONFIG_SPI_FSL_LIB=y
+CONFIG_SPI_FSL_SPI=y
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_LM70_LLP=m
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MT65XX=m
+CONFIG_SPI_OC_TINY=m
+CONFIG_SPI_PL022=m
+CONFIG_SPI_PXA2XX=m
+CONFIG_SPI_PXA2XX_DMA=y
+CONFIG_SPI_PXA2XX_PCI=m
+CONFIG_SPI_QUP=m
+CONFIG_SPI_ROCKCHIP=m
+CONFIG_SPI_SC18IS602=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPI_TLE62X0=m
+CONFIG_SPI_XCOMM=m
+# CONFIG_SPI_XILINX is not set
+CONFIG_SPI_ZYNQMP_GQSPI=m
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SPMI_MSM_PMIC_ARB=m
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_DECOMP_MULTI is not set
+# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
+CONFIG_SQUASHFS_DECOMP_SINGLE=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+# CONFIG_SQUASHFS_FILE_CACHE is not set
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_SQUASHFS_LZ4=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_ZLIB=y
+CONFIG_SRCU=y
+CONFIG_SSB_B43_PCI_BRIDGE=y
+CONFIG_SSB_BLOCKIO=y
+# CONFIG_SSB_DEBUG is not set
+CONFIG_SSB_DRIVER_GPIO=y
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_HOST_SOC=y
+CONFIG_SSB_PCIHOST=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+# CONFIG_SSB_PCMCIAHOST is not set
+CONFIG_SSB_PCMCIAHOST_POSSIBLE=y
+CONFIG_SSB_POSSIBLE=y
+CONFIG_SSB_SDIOHOST=y
+CONFIG_SSB_SDIOHOST_POSSIBLE=y
+# CONFIG_SSB_SILENT is not set
+CONFIG_SSB_SPROM=y
+CONFIG_SSFDC=m
+CONFIG_STACKTRACE=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_STACK_GUARD=256
+CONFIG_STACK_TRACER=y
+# CONFIG_STAGING_BOARD is not set
+CONFIG_STAGING_MEDIA=y
+CONFIG_STAGING_RDMA=m
+# CONFIG_STATIC_KEYS_SELFTEST is not set
+CONFIG_STE10XP=m
+CONFIG_STK3310=m
+CONFIG_STK8312=m
+CONFIG_STK8BA50=m
+CONFIG_STM=m
+CONFIG_STMMAC_ETH=m
+# CONFIG_STMMAC_PCI is not set
+CONFIG_STMMAC_PLATFORM=m
+CONFIG_STMPE_I2C=y
+CONFIG_STMPE_SPI=y
+CONFIG_STM_DUMMY=m
+CONFIG_STM_SOURCE_CONSOLE=m
+CONFIG_STP=m
+CONFIG_STRICT_DEVMEM=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_STUB_CLK_HI6220=y
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_SUNGEM=m
+CONFIG_SUNGEM_PHY=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_BACKCHANNEL=y
+CONFIG_SUNRPC_DEBUG=y
+CONFIG_SUNRPC_GSS=m
+CONFIG_SUNRPC_SWAP=y
+CONFIG_SUNRPC_XPRT_RDMA=m
+# CONFIG_SUNXI_SRAM is not set
+CONFIG_SURFACE_PRO3_BUTTON=m
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_SUSPEND_SKIP_SYNC is not set
+CONFIG_SWAP=y
+CONFIG_SWIOTLB=y
+CONFIG_SWIOTLB_XEN=y
+CONFIG_SWP_EMULATION=y
+CONFIG_SX9500=m
+CONFIG_SXGBE_ETH=m
+CONFIG_SYNCLINK=m
+CONFIG_SYNCLINKMP=m
+CONFIG_SYNCLINK_CS=m
+CONFIG_SYNCLINK_GT=m
+CONFIG_SYNOPSYS_DWC_ETH_QOS=m
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSCTL=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSFS=y
+# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_SYSFS_SYSCALL=y
+CONFIG_SYSTEMPORT=m
+CONFIG_SYSTEM_BLACKLIST_KEYRING=y
+CONFIG_SYSTEM_DATA_VERIFICATION=y
+CONFIG_SYSTEM_EXTRA_CERTIFICATE=y
+CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE=4096
+CONFIG_SYSTEM_TRUSTED_KEYRING=y
+CONFIG_SYSTEM_TRUSTED_KEYS=""
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_SYS_HYPERVISOR=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_T5403=m
+CONFIG_TABLET_SERIAL_WACOM4=m
+CONFIG_TABLET_USB_ACECAD=m
+CONFIG_TABLET_USB_AIPTEK=m
+CONFIG_TABLET_USB_GTCO=m
+CONFIG_TABLET_USB_HANWANG=m
+CONFIG_TABLET_USB_KBTAB=m
+CONFIG_TAHVO_USB=m
+CONFIG_TAHVO_USB_HOST_BY_DEFAULT=y
+CONFIG_TARGET_CORE=m
+CONFIG_TASKSTATS=y
+# CONFIG_TASKS_RCU is not set
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_TASK_XACCT=y
+CONFIG_TCG_ATMEL=m
+CONFIG_TCG_CRB=y
+CONFIG_TCG_INFINEON=m
+CONFIG_TCG_NSC=m
+CONFIG_TCG_TIS=y
+CONFIG_TCG_TIS_I2C_ATMEL=m
+CONFIG_TCG_TIS_I2C_INFINEON=m
+CONFIG_TCG_TIS_I2C_NUVOTON=m
+CONFIG_TCG_TIS_ST33ZP24=m
+CONFIG_TCG_TIS_ST33ZP24_I2C=m
+CONFIG_TCG_TIS_ST33ZP24_SPI=m
+CONFIG_TCG_TPM=y
+CONFIG_TCG_XEN=m
+CONFIG_TCM_FC=m
+CONFIG_TCM_FILEIO=m
+CONFIG_TCM_IBLOCK=m
+CONFIG_TCM_PSCSI=m
+CONFIG_TCM_QLA2XXX=m
+CONFIG_TCM_USER2=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CDG=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_DCTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_MD5SIG=y
+CONFIG_TCS3414=m
+CONFIG_TCS3472=m
+CONFIG_TEGRA_AHB=y
+CONFIG_TEHUTI=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_TELCLOCK=m
+CONFIG_TERANETICS_PHY=m
+CONFIG_TEST_BPF=m
+CONFIG_TEST_FIRMWARE=m
+# CONFIG_TEST_HASH is not set
+CONFIG_TEST_HEXDUMP=m
+CONFIG_TEST_KSTRTOX=m
+# CONFIG_TEST_LIST_SORT is not set
+CONFIG_TEST_LKM=m
+CONFIG_TEST_POWER=m
+CONFIG_TEST_PRINTF=m
+# CONFIG_TEST_RHASHTABLE is not set
+CONFIG_TEST_STATIC_KEYS=m
+CONFIG_TEST_STRING_HELPERS=m
+CONFIG_TEST_UDELAY=m
+CONFIG_TEST_USER_COPY=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_TEXTSEARCH_KMP=m
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+CONFIG_THERMAL_EMULATION=y
+CONFIG_THERMAL_GOV_BANG_BANG=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_OF=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THINKPAD_ACPI=m
+CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y
+# CONFIG_THINKPAD_ACPI_DEBUG is not set
+CONFIG_THINKPAD_ACPI_DEBUGFACILITIES=y
+CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y
+# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set
+CONFIG_THINKPAD_ACPI_VIDEO=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_THUNDER_NIC_BGX=m
+CONFIG_THUNDER_NIC_PF=m
+CONFIG_THUNDER_NIC_VF=m
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_TIFM_7XX1=m
+CONFIG_TIGON3=m
+CONFIG_TIMERFD=y
+CONFIG_TIPC=m
+CONFIG_TIPC_MEDIA_IB=y
+CONFIG_TIPC_MEDIA_UDP=y
+CONFIG_TI_ADC081C=m
+CONFIG_TI_ADC128S052=m
+CONFIG_TI_AM335X_ADC=m
+CONFIG_TI_CPSW_ALE=m
+CONFIG_TI_DAC7512=m
+CONFIG_TI_ST=m
+CONFIG_TLAN=m
+CONFIG_TMD_HERMES=m
+CONFIG_TMP006=m
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
+CONFIG_TN3270=y
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3270_FS=m
+CONFIG_TN3270_TTY=y
+CONFIG_TOIM3232_DONGLE=m
+CONFIG_TOPSTAR_LAPTOP=m
+CONFIG_TORTURE_TEST=m
+CONFIG_TOSHIBA_BT_RFKILL=m
+CONFIG_TOSHIBA_HAPS=m
+CONFIG_TOSHIBA_WMI=m
+CONFIG_TOUCHSCREEN_88PM860X=m
+CONFIG_TOUCHSCREEN_AD7877=m
+CONFIG_TOUCHSCREEN_AD7879=m
+CONFIG_TOUCHSCREEN_AD7879_I2C=m
+CONFIG_TOUCHSCREEN_AD7879_SPI=m
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_AR1021_I2C=m
+CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+CONFIG_TOUCHSCREEN_AUO_PIXCIR=m
+CONFIG_TOUCHSCREEN_BU21013=m
+CONFIG_TOUCHSCREEN_CHIPONE_ICN8318=m
+CONFIG_TOUCHSCREEN_COLIBRI_VF50=m
+CONFIG_TOUCHSCREEN_CY8CTMG110=m
+CONFIG_TOUCHSCREEN_CYTTSP4_CORE=m
+CONFIG_TOUCHSCREEN_CYTTSP4_I2C=m
+CONFIG_TOUCHSCREEN_CYTTSP4_SPI=m
+CONFIG_TOUCHSCREEN_CYTTSP_CORE=m
+CONFIG_TOUCHSCREEN_CYTTSP_I2C=m
+CONFIG_TOUCHSCREEN_CYTTSP_SPI=m
+CONFIG_TOUCHSCREEN_DA9034=m
+CONFIG_TOUCHSCREEN_DA9052=m
+CONFIG_TOUCHSCREEN_DYNAPRO=m
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_EETI=m
+CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_ELAN=y
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_FT6236=m
+CONFIG_TOUCHSCREEN_FUJITSU=m
+CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_TOUCHSCREEN_HAMPSHIRE=m
+CONFIG_TOUCHSCREEN_ILI210X=m
+CONFIG_TOUCHSCREEN_IMX6UL_TSC=m
+CONFIG_TOUCHSCREEN_INEXIO=m
+CONFIG_TOUCHSCREEN_IPROC=m
+CONFIG_TOUCHSCREEN_MAX11801=m
+CONFIG_TOUCHSCREEN_MC13783=m
+CONFIG_TOUCHSCREEN_MCS5000=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_TOUCHSCREEN_MMS114=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_PCAP=m
+CONFIG_TOUCHSCREEN_PENMOUNT=m
+CONFIG_TOUCHSCREEN_PIXCIR=m
+CONFIG_TOUCHSCREEN_PROPERTIES=y
+CONFIG_TOUCHSCREEN_ROHM_BU21023=m
+CONFIG_TOUCHSCREEN_ST1232=m
+CONFIG_TOUCHSCREEN_STMPE=m
+CONFIG_TOUCHSCREEN_SUR40=m
+CONFIG_TOUCHSCREEN_SX8654=m
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=m
+CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m
+CONFIG_TOUCHSCREEN_TOUCHIT213=m
+CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
+CONFIG_TOUCHSCREEN_TOUCHWIN=m
+CONFIG_TOUCHSCREEN_TPS6507X=m
+CONFIG_TOUCHSCREEN_TSC2004=m
+CONFIG_TOUCHSCREEN_TSC2005=m
+CONFIG_TOUCHSCREEN_TSC2007=m
+CONFIG_TOUCHSCREEN_TSC200X_CORE=m
+CONFIG_TOUCHSCREEN_TSC_SERIO=m
+CONFIG_TOUCHSCREEN_UCB1400=m
+CONFIG_TOUCHSCREEN_USB_3M=y
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y
+CONFIG_TOUCHSCREEN_USB_E2I=y
+CONFIG_TOUCHSCREEN_USB_EASYTOUCH=y
+CONFIG_TOUCHSCREEN_USB_EGALAX=y
+CONFIG_TOUCHSCREEN_USB_ELO=y
+CONFIG_TOUCHSCREEN_USB_ETT_TC45USB=y
+CONFIG_TOUCHSCREEN_USB_ETURBO=y
+CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y
+CONFIG_TOUCHSCREEN_USB_GOTOP=y
+CONFIG_TOUCHSCREEN_USB_GUNZE=y
+CONFIG_TOUCHSCREEN_USB_IDEALTEK=y
+CONFIG_TOUCHSCREEN_USB_IRTOUCH=y
+CONFIG_TOUCHSCREEN_USB_ITM=y
+CONFIG_TOUCHSCREEN_USB_JASTEC=y
+CONFIG_TOUCHSCREEN_USB_NEXIO=y
+CONFIG_TOUCHSCREEN_USB_PANJIT=y
+CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y
+CONFIG_TOUCHSCREEN_WACOM_I2C=m
+CONFIG_TOUCHSCREEN_WACOM_W8001=m
+CONFIG_TOUCHSCREEN_WDT87XX_I2C=m
+CONFIG_TOUCHSCREEN_WM831X=m
+CONFIG_TOUCHSCREEN_WM9705=y
+CONFIG_TOUCHSCREEN_WM9712=y
+CONFIG_TOUCHSCREEN_WM9713=y
+CONFIG_TOUCHSCREEN_WM97XX=m
+CONFIG_TOUCHSCREEN_ZFORCE=m
+CONFIG_TPS6105X=m
+CONFIG_TPS65010=m
+CONFIG_TPS6507X=m
+CONFIG_TRACEPOINTS=y
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+CONFIG_TRACER_MAX_TRACE=y
+CONFIG_TRACER_SNAPSHOT=y
+# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
+CONFIG_TRACE_CLOCK=y
+# CONFIG_TRACE_ENUM_MAP_FILE is not set
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_TRACE_ROUTER=m
+CONFIG_TRACING=y
+CONFIG_TRACING_EVENTS_GPIO=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+# CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS is not set
+CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_TRUSTED_KEYS=y
+CONFIG_TSL2583=m
+CONFIG_TSL2x7x=m
+CONFIG_TSL4531=m
+CONFIG_TSYS01=m
+CONFIG_TSYS02D=m
+CONFIG_TTPCI_EEPROM=m
+CONFIG_TTY=y
+CONFIG_TULIP=m
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_NAPI is not set
+CONFIG_TUN=y
+# CONFIG_TUNE_DEFAULT is not set
+# CONFIG_TUNE_Z10 is not set
+# CONFIG_TUNE_Z13 is not set
+# CONFIG_TUNE_Z196 is not set
+# CONFIG_TUNE_Z900 is not set
+# CONFIG_TUNE_Z990 is not set
+# CONFIG_TUNE_Z9_109 is not set
+CONFIG_TUNE_ZEC12=y
+# CONFIG_TUN_VNET_CROSS_LE is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_MADC=m
+CONFIG_TWL4030_WATCHDOG=m
+CONFIG_TWL6030_GPADC=m
+CONFIG_TWL6040_CORE=y
+CONFIG_TYPHOON=m
+CONFIG_UBIFS_ATIME_SUPPORT=y
+CONFIG_UBIFS_FS=m
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_UCB1400_CORE=m
+CONFIG_UCS2_STRING=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+CONFIG_UEFI_CPER=y
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_UFS_DEBUG is not set
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_UHID=m
+CONFIG_UID16=y
+CONFIG_UIO_AEC=m
+CONFIG_UIO_CIF=m
+CONFIG_UIO_DMEM_GENIRQ=m
+CONFIG_UIO_MF624=m
+CONFIG_UIO_NETX=m
+CONFIG_UIO_PCI_GENERIC=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_UIO_PRUSS=m
+CONFIG_UIO_SERCOS3=m
+CONFIG_ULI526X=m
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_UNISYSSPAR=y
+CONFIG_UNISYS_VISORBUS=m
+CONFIG_UNISYS_VISORHBA=m
+CONFIG_UNISYS_VISORINPUT=m
+CONFIG_UNISYS_VISORNIC=m
+CONFIG_UNIX=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX_DIAG=m
+CONFIG_UNIX_SCM=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_UPROBE_EVENT=y
+CONFIG_US5182D=m
+CONFIG_USB=y
+CONFIG_USBIP_CORE=m
+# CONFIG_USBIP_DEBUG is not set
+CONFIG_USBIP_HOST=m
+CONFIG_USBIP_VHCI_HCD=m
+CONFIG_USBPCWATCHDOG=m
+CONFIG_USB_ACM=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_AIRSPY=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AMD5536UDC=m
+CONFIG_USB_AN2720=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_ATM=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_BDC_UDC=m
+CONFIG_USB_BELKIN=y
+CONFIG_USB_C67X00_HCD=m
+CONFIG_USB_CATC=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_CDC_PHONET=m
+CONFIG_USB_CHAOSKEY=m
+CONFIG_USB_CHIPIDEA=m
+# CONFIG_USB_CHIPIDEA_DEBUG is not set
+CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_CHIPIDEA_OF=m
+CONFIG_USB_CHIPIDEA_PCI=m
+CONFIG_USB_CHIPIDEA_UDC=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_PRINTER=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_PHONET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CXACRU=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_DEFAULT_PERSIST=y
+CONFIG_USB_DSBR=m
+# CONFIG_USB_DUMMY_HCD is not set
+CONFIG_USB_DWC2=y
+# CONFIG_USB_DWC2_DEBUG is not set
+CONFIG_USB_DWC2_HOST=y
+CONFIG_USB_DWC2_PCI=y
+# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
+CONFIG_USB_DWC3=m
+CONFIG_USB_DWC3_DUAL_ROLE=y
+# CONFIG_USB_DWC3_GADGET is not set
+# CONFIG_USB_DWC3_HOST is not set
+CONFIG_USB_DWC3_PCI=m
+CONFIG_USB_DWC3_QCOM=m
+CONFIG_USB_DWC3_ULPI=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_EG20T=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=m
+CONFIG_USB_EHCI_PCI=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHSET_TEST_FIXTURE=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_EEM=y
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_EZUSB_FX2=m
+CONFIG_USB_FOTG210_HCD=m
+CONFIG_USB_FOTG210_UDC=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_FUNCTIONFS=m
+CONFIG_USB_FUNCTIONFS_ETH=y
+CONFIG_USB_FUNCTIONFS_GENERIC=y
+CONFIG_USB_FUNCTIONFS_RNDIS=y
+CONFIG_USB_F_ACM=m
+CONFIG_USB_F_ECM=m
+CONFIG_USB_F_EEM=m
+CONFIG_USB_F_FS=m
+CONFIG_USB_F_HID=m
+CONFIG_USB_F_MASS_STORAGE=m
+CONFIG_USB_F_MIDI=m
+CONFIG_USB_F_NCM=m
+CONFIG_USB_F_OBEX=m
+CONFIG_USB_F_PHONET=m
+CONFIG_USB_F_PRINTER=m
+CONFIG_USB_F_RNDIS=m
+CONFIG_USB_F_SERIAL=m
+CONFIG_USB_F_SS_LB=m
+CONFIG_USB_F_SUBSET=m
+CONFIG_USB_F_UAC1=m
+CONFIG_USB_F_UAC2=m
+CONFIG_USB_F_UVC=m
+CONFIG_USB_GADGET=m
+CONFIG_USB_GADGETFS=m
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+CONFIG_USB_GADGET_TARGET=m
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_XILINX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GOKU=m
+CONFIG_USB_GPIO_VBUS=m
+CONFIG_USB_GR_UDC=m
+CONFIG_USB_GSPCA=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TOUPTEK=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_DBGP=m
+# CONFIG_USB_G_DBGP_PRINTK is not set
+CONFIG_USB_G_DBGP_SERIAL=y
+CONFIG_USB_G_HID=m
+# CONFIG_USB_G_MULTI is not set
+CONFIG_USB_G_NCM=m
+CONFIG_USB_G_NOKIA=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_G_WEBCAM=m
+CONFIG_USB_HACKRF=m
+CONFIG_USB_HCD_BCMA=m
+CONFIG_USB_HCD_SSB=m
+# CONFIG_USB_HCD_TEST_MODE is not set
+CONFIG_USB_HID=m
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_HSIC_USB3503=m
+CONFIG_USB_HSO=m
+CONFIG_USB_HWA_HCD=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_IRDA=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_ISP1301=m
+CONFIG_USB_ISP1362_HCD=m
+CONFIG_USB_ISP1760=m
+CONFIG_USB_ISP1760_DUAL_ROLE=y
+# CONFIG_USB_ISP1760_GADGET_ROLE is not set
+CONFIG_USB_ISP1760_HCD=y
+# CONFIG_USB_ISP1760_HOST_ROLE is not set
+CONFIG_USB_ISP1761_UDC=y
+CONFIG_USB_KAWETH=m
+CONFIG_USB_KBD=m
+CONFIG_USB_KC2190=y
+CONFIG_USB_KEENE=m
+CONFIG_USB_LAN78XX=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LD=m
+CONFIG_USB_LED=m
+CONFIG_USB_LED_TRIG=y
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LIBCOMPOSITE=m
+CONFIG_USB_LINK_LAYER_TEST=m
+CONFIG_USB_M5602=m
+# CONFIG_USB_M66592 is not set
+CONFIG_USB_MA901=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_MAX3421_HCD=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_MON=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB_MR800=m
+CONFIG_USB_MSI2500=m
+CONFIG_USB_MSM_OTG=m
+CONFIG_USB_MUSB_DUAL_ROLE=y
+# CONFIG_USB_MUSB_GADGET is not set
+CONFIG_USB_MUSB_HDRC=m
+# CONFIG_USB_MUSB_HOST is not set
+CONFIG_USB_MV_U3D=m
+CONFIG_USB_MV_UDC=m
+CONFIG_USB_NET2272=m
+CONFIG_USB_NET2272_DMA=y
+CONFIG_USB_NET2280=m
+CONFIG_USB_NET_AX88179_178A=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_NET_CDC_SUBSET_ENABLE=m
+CONFIG_USB_NET_CH9200=m
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_DRIVERS=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_NET_KALMIA=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PCI=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_OXU210HP_HCD=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_PHY=y
+CONFIG_USB_PRINTER=m
+CONFIG_USB_PWC=m
+# CONFIG_USB_PWC_DEBUG is not set
+CONFIG_USB_PWC_INPUT_EVDEV=y
+CONFIG_USB_PXA27X=m
+CONFIG_USB_QCOM_8X16_PHY=m
+CONFIG_USB_R8A66597=m
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_RAREMONO=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_S2255=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_DEBUG=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7715_PARPORT=y
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MXUPORT=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SIMPLE=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_WWAN=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_SI470X=m
+CONFIG_USB_SI4713=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_SL811_CS=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_HCD_ISO=y
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_DATAFAB=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_SWITCH_FSA9480=m
+CONFIG_USB_TEST=m
+CONFIG_USB_TMC=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_U132_HCD=m
+CONFIG_USB_UAS=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_ULPI=y
+CONFIG_USB_ULPI_BUS=m
+CONFIG_USB_ULPI_VIEWPORT=y
+CONFIG_USB_USBNET=m
+CONFIG_USB_USS720=m
+CONFIG_USB_U_ETHER=m
+CONFIG_USB_U_SERIAL=m
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_VL600=m
+CONFIG_USB_WDM=m
+CONFIG_USB_WHCI_HCD=m
+CONFIG_USB_WUSB=m
+CONFIG_USB_WUSB_CBAF=m
+# CONFIG_USB_WUSB_CBAF_DEBUG is not set
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PCI=y
+CONFIG_USB_XHCI_PLATFORM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_USB_YUREX=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_ZERO=m
+CONFIG_USB_ZR364XX=m
+CONFIG_USELIB=y
+CONFIG_USERFAULTFD=y
+CONFIG_USERIO=m
+CONFIG_USER_NS=y
+CONFIG_USER_RETURN_NOTIFIER=y
+CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_USE_PERCPU_NUMA_NODE_ID=y
+CONFIG_UTS_NS=y
+CONFIG_UWB_HWA=m
+CONFIG_UWB_I1480U=m
+CONFIG_UWB_WHCI=m
+CONFIG_V4L2_FLASH_LED_CLASS=m
+CONFIG_V4L2_MEM2MEM_DEV=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_V4L_TEST_DRIVERS=y
+CONFIG_VCNL4000=m
+CONFIG_VEN_RSI_91X=m
+# CONFIG_VEN_RSI_BT_ALONE is not set
+CONFIG_VEN_RSI_COEX=y
+CONFIG_VEN_RSI_DEBUGFS=y
+# CONFIG_VEN_RSI_P2P is not set
+CONFIG_VEN_RSI_SDIO=m
+CONFIG_VEN_RSI_USB=m
+CONFIG_VEN_RSI_WOW=y
+CONFIG_VERSION_SIGNATURE=""
+CONFIG_VETH=m
+CONFIG_VEXPRESS_CONFIG=y
+CONFIG_VEXPRESS_SYSCFG=y
+CONFIG_VF610_ADC=m
+CONFIG_VFAT_FS=y
+CONFIG_VFIO=m
+CONFIG_VFIO_AMBA=m
+CONFIG_VFIO_IOMMU_TYPE1=m
+CONFIG_VFIO_PCI=m
+CONFIG_VFIO_PCI_INTX=y
+CONFIG_VFIO_PCI_MMAP=y
+CONFIG_VFIO_PCI_VGA=y
+CONFIG_VFIO_PLATFORM=m
+CONFIG_VFIO_PLATFORM_AMDXGBE_RESET=m
+CONFIG_VFIO_PLATFORM_CALXEDAXGMAC_RESET=m
+CONFIG_VFIO_VIRQFD=m
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+CONFIG_VGA_CONSOLE=y
+CONFIG_VGA_SWITCHEROO=y
+CONFIG_VHOST=m
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
+CONFIG_VHOST_NET=m
+CONFIG_VHOST_RING=m
+CONFIG_VHOST_SCSI=m
+CONFIG_VIA_FIR=m
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+CONFIG_VIA_VELOCITY=m
+CONFIG_VIA_WDT=m
+CONFIG_VIDEOBUF2_CORE=m
+CONFIG_VIDEOBUF2_DMA_CONTIG=m
+CONFIG_VIDEOBUF2_DMA_SG=m
+CONFIG_VIDEOBUF2_DVB=m
+CONFIG_VIDEOBUF2_MEMOPS=m
+CONFIG_VIDEOBUF2_VMALLOC=m
+CONFIG_VIDEOBUF_DMA_SG=m
+CONFIG_VIDEOBUF_DVB=m
+CONFIG_VIDEOBUF_GEN=m
+CONFIG_VIDEOBUF_VMALLOC=m
+CONFIG_VIDEOMODE_HELPERS=y
+CONFIG_VIDEO_ADV7170=m
+CONFIG_VIDEO_ADV7175=m
+CONFIG_VIDEO_ADV7511=m
+CONFIG_VIDEO_ADV7604=m
+CONFIG_VIDEO_ADV7842=m
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_AU0828=m
+CONFIG_VIDEO_AU0828_RC=y
+CONFIG_VIDEO_AU0828_V4L2=y
+CONFIG_VIDEO_BT819=m
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_BT856=m
+CONFIG_VIDEO_BT866=m
+CONFIG_VIDEO_CAFE_CCIC=m
+CONFIG_VIDEO_COBALT=m
+CONFIG_VIDEO_CPIA2=m
+CONFIG_VIDEO_CS5345=m
+CONFIG_VIDEO_CS53L32A=m
+CONFIG_VIDEO_CX18=m
+CONFIG_VIDEO_CX18_ALSA=m
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_VIDEO_CX231XX_RC=y
+CONFIG_VIDEO_CX2341X=m
+CONFIG_VIDEO_CX23885=m
+CONFIG_VIDEO_CX25821=m
+CONFIG_VIDEO_CX25821_ALSA=m
+CONFIG_VIDEO_CX25840=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_CX88_ALSA=m
+CONFIG_VIDEO_CX88_BLACKBIRD=m
+CONFIG_VIDEO_CX88_DVB=m
+CONFIG_VIDEO_CX88_ENABLE_VP3054=y
+CONFIG_VIDEO_CX88_MPEG=m
+CONFIG_VIDEO_CX88_VP3054=m
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_DT3155=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_VIDEO_EM28XX_RC=m
+CONFIG_VIDEO_EM28XX_V4L2=m
+CONFIG_VIDEO_FB_IVTV=m
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_LOADER=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_IR_I2C=m
+CONFIG_VIDEO_IVTV=m
+CONFIG_VIDEO_IVTV_ALSA=m
+CONFIG_VIDEO_KS0127=m
+CONFIG_VIDEO_M52790=m
+CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m
+CONFIG_VIDEO_MEYE=m
+CONFIG_VIDEO_MSP3400=m
+CONFIG_VIDEO_MT9V011=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_OV7640=m
+CONFIG_VIDEO_OV7670=m
+CONFIG_VIDEO_PVRUSB2=m
+# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
+CONFIG_VIDEO_PVRUSB2_DVB=y
+CONFIG_VIDEO_PVRUSB2_SYSFS=y
+CONFIG_VIDEO_SAA6588=m
+CONFIG_VIDEO_SAA6752HS=m
+CONFIG_VIDEO_SAA7110=m
+CONFIG_VIDEO_SAA711X=m
+CONFIG_VIDEO_SAA7127=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_SAA7134_ALSA=m
+CONFIG_VIDEO_SAA7134_DVB=m
+CONFIG_VIDEO_SAA7134_GO7007=m
+CONFIG_VIDEO_SAA7134_RC=y
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_SAA7164=m
+CONFIG_VIDEO_SAA717X=m
+CONFIG_VIDEO_SAA7185=m
+CONFIG_VIDEO_SH_VEU=m
+CONFIG_VIDEO_SOLO6X10=m
+CONFIG_VIDEO_SONY_BTF_MPX=m
+CONFIG_VIDEO_STK1160=m
+CONFIG_VIDEO_STK1160_AC97=y
+CONFIG_VIDEO_STK1160_COMMON=m
+CONFIG_VIDEO_TDA7432=m
+CONFIG_VIDEO_TDA9840=m
+CONFIG_VIDEO_TEA6415C=m
+CONFIG_VIDEO_TEA6420=m
+CONFIG_VIDEO_TM6000=m
+CONFIG_VIDEO_TM6000_ALSA=m
+CONFIG_VIDEO_TM6000_DVB=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_TVAUDIO=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_VIDEO_TVP5150=m
+CONFIG_VIDEO_TW2804=m
+CONFIG_VIDEO_TW68=m
+CONFIG_VIDEO_TW9903=m
+CONFIG_VIDEO_TW9906=m
+CONFIG_VIDEO_UDA1342=m
+CONFIG_VIDEO_UPD64031A=m
+CONFIG_VIDEO_UPD64083=m
+CONFIG_VIDEO_USBTV=m
+CONFIG_VIDEO_USBVISION=m
+CONFIG_VIDEO_V4L2=m
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_VIA_CAMERA=m
+CONFIG_VIDEO_VIM2M=m
+CONFIG_VIDEO_VIVID=m
+CONFIG_VIDEO_VIVID_MAX_DEVS=64
+CONFIG_VIDEO_VP27SMPX=m
+CONFIG_VIDEO_VPX3220=m
+CONFIG_VIDEO_WM8739=m
+CONFIG_VIDEO_WM8775=m
+CONFIG_VIDEO_XILINX=m
+CONFIG_VIDEO_XILINX_TPG=m
+CONFIG_VIDEO_XILINX_VTC=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_AVS6EYES=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_ZORAN_ZR36060=m
+CONFIG_VIPERBOARD_ADC=m
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_INPUT=m
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_VIRTIO_NET=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_VIRT_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+CONFIG_VIRT_CPU_ACCOUNTING_NATIVE=y
+CONFIG_VIRT_DRIVERS=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_VITESSE_PHY=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VLAN_8021Q_MVRP=y
+CONFIG_VLSI_FIR=m
+# CONFIG_VM86 is not set
+CONFIG_VMCP=y
+CONFIG_VME_CA91CX42=m
+CONFIG_VME_PIO2=m
+CONFIG_VME_TSI148=m
+CONFIG_VME_USER=m
+CONFIG_VMIVME_7805=m
+CONFIG_VMLOGRDR=m
+CONFIG_VMWARE_BALLOON=m
+CONFIG_VMWARE_PVSCSI=m
+CONFIG_VMWARE_VMCI=m
+CONFIG_VMWARE_VMCI_VSOCKETS=m
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_VORTEX=m
+CONFIG_VSOCKETS=m
+CONFIG_VT=y
+CONFIG_VT6655=m
+CONFIG_VT6656=m
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_VXGE=m
+# CONFIG_VXGE_DEBUG_TRACE_ALL is not set
+CONFIG_VXLAN=m
+CONFIG_VZ89X=m
+CONFIG_W1_CON=y
+CONFIG_W1_MASTER_DS1WM=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_MASTER_MATROX=m
+CONFIG_W1_SLAVE_BQ27000=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2408_READBACK=y
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+# CONFIG_W1_SLAVE_DS2433_CRC is not set
+CONFIG_W1_SLAVE_DS2760=m
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W83627HF_WDT=m
+CONFIG_W83877F_WDT=m
+CONFIG_W83977F_WDT=m
+CONFIG_WAFER_WDT=m
+CONFIG_WANT_DEV_COREDUMP=y
+CONFIG_WANXL=m
+# CONFIG_WARN_DYNAMIC_STACK is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WCN36XX=m
+# CONFIG_WCN36XX_DEBUGFS is not set
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PRIV=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WIL6210=m
+CONFIG_WIL6210_ISR_COR=y
+CONFIG_WIL6210_TRACING=y
+# CONFIG_WILC1000_DRIVER is not set
+CONFIG_WILINK_PLATFORM_DATA=y
+CONFIG_WIMAX_DEBUG_LEVEL=8
+CONFIG_WIMAX_GDM72XX=m
+CONFIG_WIMAX_GDM72XX_K_MODE=y
+CONFIG_WIMAX_GDM72XX_QOS=y
+# CONFIG_WIMAX_GDM72XX_SDIO is not set
+CONFIG_WIMAX_GDM72XX_USB=y
+CONFIG_WIMAX_GDM72XX_USB_PM=y
+CONFIG_WIMAX_GDM72XX_WIMAX2=y
+CONFIG_WIMAX_I2400M=m
+CONFIG_WIMAX_I2400M_DEBUG_LEVEL=8
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_WINBOND_840=m
+CONFIG_WINBOND_FIR=m
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIZNET_BUS_ANY=y
+# CONFIG_WIZNET_BUS_DIRECT is not set
+# CONFIG_WIZNET_BUS_INDIRECT is not set
+CONFIG_WIZNET_W5100=m
+CONFIG_WIZNET_W5300=m
+CONFIG_WL1251=m
+CONFIG_WL1251_SDIO=m
+CONFIG_WL1251_SPI=m
+CONFIG_WL12XX=m
+CONFIG_WL18XX=m
+CONFIG_WLAN=y
+CONFIG_WLAN_VENDOR_RSI=y
+CONFIG_WLCORE=m
+CONFIG_WLCORE_SDIO=m
+CONFIG_WLCORE_SPI=m
+CONFIG_WL_MEDIATEK=y
+CONFIG_WL_TI=y
+CONFIG_WM831X_BACKUP=m
+CONFIG_WM831X_POWER=m
+CONFIG_WM831X_WATCHDOG=m
+CONFIG_WM8350_POWER=m
+CONFIG_WM8350_WATCHDOG=m
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+CONFIG_X25_ASY=m
+CONFIG_X509_CERTIFICATE_PARSER=y
+CONFIG_X86=y
+CONFIG_X86_16BIT=y
+CONFIG_X86_64=y
+CONFIG_X86_64_ACPI_NUMA=y
+CONFIG_X86_64_SMP=y
+CONFIG_X86_ACPI_CPUFREQ=y
+CONFIG_X86_ACPI_CPUFREQ_CPB=y
+CONFIG_X86_AMD_FREQ_SENSITIVITY=m
+CONFIG_X86_AMD_PLATFORM_DEVICE=y
+CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
+CONFIG_X86_CHECK_BIOS_CORRUPTION=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_CPUID=m
+CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_X86_DEBUG_FPU=y
+# CONFIG_X86_DECODER_SELFTEST is not set
+CONFIG_X86_DEV_DMA_OPS=y
+CONFIG_X86_DIRECT_GBPAGES=y
+CONFIG_X86_ESPFIX64=y
+CONFIG_X86_EXTENDED_PLATFORM=y
+CONFIG_X86_FAST_FEATURE_TESTS=y
+CONFIG_X86_FEATURE_NAMES=y
+# CONFIG_X86_GOLDFISH is not set
+CONFIG_X86_INTEL_LPSS=y
+CONFIG_X86_INTEL_MPX=y
+CONFIG_X86_INTEL_PSTATE=y
+# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set
+CONFIG_X86_INTEL_TSX_MODE_OFF=y
+# CONFIG_X86_INTEL_TSX_MODE_ON is not set
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_MCE=y
+CONFIG_X86_MCE_AMD=y
+CONFIG_X86_MCE_INJECT=m
+CONFIG_X86_MCE_INTEL=y
+CONFIG_X86_MCE_THRESHOLD=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=64
+CONFIG_X86_MPPARSE=y
+CONFIG_X86_MSR=m
+CONFIG_X86_NEED_RELOCS=y
+CONFIG_X86_NUMACHIP=y
+CONFIG_X86_P4_CLOCKMOD=m
+CONFIG_X86_PAT=y
+CONFIG_X86_PCC_CPUFREQ=y
+CONFIG_X86_PKG_TEMP_THERMAL=m
+CONFIG_X86_PLATFORM_DEVICES=y
+CONFIG_X86_PMEM_LEGACY=y
+CONFIG_X86_PMEM_LEGACY_DEVICE=y
+CONFIG_X86_PM_TIMER=y
+CONFIG_X86_POWERNOW_K8=y
+# CONFIG_X86_PTDUMP is not set
+# CONFIG_X86_PTDUMP_CORE is not set
+CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
+CONFIG_X86_RESERVE_LOW=64
+CONFIG_X86_SMAP=y
+CONFIG_X86_SPEEDSTEP_CENTRINO=y
+CONFIG_X86_SPEEDSTEP_LIB=m
+CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
+# CONFIG_X86_SYSFB is not set
+CONFIG_X86_THERMAL_VECTOR=y
+CONFIG_X86_TSC=y
+# CONFIG_X86_UV is not set
+# CONFIG_X86_VERBOSE_BOOTUP is not set
+# CONFIG_X86_VSMP is not set
+CONFIG_X86_VSYSCALL_EMULATION=y
+CONFIG_X86_X2APIC=y
+CONFIG_X86_X32=y
+CONFIG_XEN=y
+CONFIG_XENFS=m
+CONFIG_XEN_512GB=y
+CONFIG_XEN_ACPI=y
+CONFIG_XEN_ACPI_PROCESSOR=y
+CONFIG_XEN_AUTO_XLATE=y
+CONFIG_XEN_BACKEND=y
+CONFIG_XEN_BALLOON=y
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG=y
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT=512
+CONFIG_XEN_BLKDEV_BACKEND=m
+CONFIG_XEN_BLKDEV_FRONTEND=y
+CONFIG_XEN_COMPAT_XENFS=y
+# CONFIG_XEN_DEBUG_FS is not set
+CONFIG_XEN_DEV_EVTCHN=m
+CONFIG_XEN_DOM0=y
+CONFIG_XEN_EFI=y
+CONFIG_XEN_FBDEV_FRONTEND=m
+CONFIG_XEN_GNTDEV=m
+CONFIG_XEN_GRANT_DEV_ALLOC=m
+CONFIG_XEN_HAVE_PVMMU=y
+CONFIG_XEN_HAVE_VPMU=y
+CONFIG_XEN_MCE_LOG=y
+CONFIG_XEN_NETDEV_BACKEND=m
+CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_PCIDEV_BACKEND=m
+CONFIG_XEN_PCIDEV_FRONTEND=m
+CONFIG_XEN_PRIVCMD=m
+CONFIG_XEN_PVH=y
+CONFIG_XEN_PVHVM=y
+CONFIG_XEN_SAVE_RESTORE=y
+CONFIG_XEN_SCRUB_PAGES=y
+CONFIG_XEN_SCSI_BACKEND=m
+CONFIG_XEN_SCSI_FRONTEND=m
+CONFIG_XEN_SELFBALLOONING=y
+CONFIG_XEN_SYMS=y
+CONFIG_XEN_SYS_HYPERVISOR=y
+CONFIG_XEN_TMEM=m
+CONFIG_XEN_WDT=m
+CONFIG_XEN_XENBUS_FRONTEND=y
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=m
+CONFIG_XFRM_IPCOMP=m
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_XFRM_STATISTICS=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_USER=m
+# CONFIG_XFS_DEBUG is not set
+CONFIG_XFS_FS=m
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_RT=y
+# CONFIG_XFS_WARN is not set
+CONFIG_XGENE_DMA=m
+CONFIG_XGENE_SLIMPRO_MBOX=m
+CONFIG_XILLYBUS_OF=m
+CONFIG_XILLYBUS_PCIE=m
+CONFIG_XOR_BLOCKS=m
+CONFIG_XPS=y
+CONFIG_XZ_DEC=y
+CONFIG_YAM=m
+CONFIG_YELLOWFIN=m
+CONFIG_YENTA=m
+CONFIG_YENTA_ENE_TUNE=y
+CONFIG_YENTA_O2=y
+CONFIG_YENTA_RICOH=y
+CONFIG_YENTA_TI=y
+CONFIG_YENTA_TOSHIBA=y
+CONFIG_ZBUD=y
+CONFIG_ZCRYPT=m
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+CONFIG_ZEROPLUS_FF=y
+CONFIG_ZFCP=m
+CONFIG_ZISOFS=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DEVICE=y
+CONFIG_ZONE_DMA=y
+CONFIG_ZONE_DMA32=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_ZPOOL=y
+CONFIG_ZRAM=m
+CONFIG_ZRAM_LZ4_COMPRESS=y
+CONFIG_ZSMALLOC=y
+# CONFIG_ZSMALLOC_STAT is not set
+CONFIG_ZSWAP=y
--- linux-4.4.0.orig/debian.master/config/i386/config.common.i386
+++ linux-4.4.0/debian.master/config/i386/config.common.i386
@@ -0,0 +1,471 @@
+#
+# Config options for config.common.i386 automatically generated by splitconfig.pl
+#
+# CONFIG_64BIT is not set
+CONFIG_6LOWPAN=m
+CONFIG_ABX500_CORE=y
+CONFIG_AC97_BUS=m
+# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_AIX_PARTITION=y
+CONFIG_ALIM7101_WDT=m
+CONFIG_ALTERA_TSE=m
+CONFIG_AMIGA_PARTITION=y
+CONFIG_APPLICOM=m
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_RANDOM=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCNET=m
+CONFIG_ATALK=m
+CONFIG_ATARI_PARTITION=y
+CONFIG_ATA_GENERIC=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_OVER_ETH=m
+CONFIG_ATA_PIIX=y
+CONFIG_ATM=m
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_AUXDISPLAY=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BATMAN_ADV=m
+CONFIG_BCH=m
+CONFIG_BCMA=m
+CONFIG_BCM_KONA_USB2_PHY=m
+CONFIG_BE2ISCSI=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_NVME=m
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
+CONFIG_BLK_DEV_RSXX=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BOUNCE=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_C2PORT=m
+CONFIG_CADENCE_WATCHDOG=m
+CONFIG_CAIF=m
+CONFIG_CAN=m
+CONFIG_CB710_CORE=m
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CMA=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_CRAMFS=m
+CONFIG_CRASH_DUMP=y
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_KERNEL_API is not set
+CONFIG_DECNET=m
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_DMADEVICES=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DMA_VIRTUAL_CHANNELS=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DNET=m
+CONFIG_DRM=m
+CONFIG_DUMMY_IRQ=m
+CONFIG_DW_WATCHDOG=m
+CONFIG_ECHO=m
+CONFIG_EEPROM_93CX6=m
+CONFIG_EFS_FS=m
+# CONFIG_EM_TIMER_STI is not set
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_ETHOC=m
+CONFIG_EXOFS_FS=m
+CONFIG_EXTCON=y
+CONFIG_F2FS_FS=m
+CONFIG_FB=y
+CONFIG_FB_ATY128=m
+CONFIG_FB_BOOT_VESA_SUPPORT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_IBM_GXT4500=m
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+CONFIG_FB_UDL=m
+CONFIG_FB_VOODOO1=m
+CONFIG_FDDI=y
+CONFIG_FEALNX=m
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_NOSY=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIXED_PHY=y
+CONFIG_FMC=m
+CONFIG_FRAME_WARN=1024
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
+CONFIG_GENERIC_PHY=y
+CONFIG_GPIO_GENERIC=m
+CONFIG_GPIO_GENERIC_PLATFORM=m
+CONFIG_GPIO_TWL4030=m
+CONFIG_GPIO_TWL6040=m
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HFSPLUS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HIBERNATION=y
+CONFIG_HIO=m
+CONFIG_HOTPLUG_PCI_PCIE=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_HPET=y
+CONFIG_HPFS_FS=m
+CONFIG_HP_ILO=m
+CONFIG_HSI=m
+CONFIG_HSR=m
+CONFIG_HTC_PASIC3=m
+CONFIG_HUGETLB_PAGE=y
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+# CONFIG_HZ_100 is not set
+CONFIG_I2C=y
+# CONFIG_I2C_SLAVE is not set
+CONFIG_I6300ESB_WDT=m
+CONFIG_IEEE802154=m
+CONFIG_IIO=m
+CONFIG_ILLEGAL_POINTER_VALUE=0
+CONFIG_IMA=y
+CONFIG_INFINIBAND_NES=m
+CONFIG_INFINIBAND_OCRDMA=m
+CONFIG_INPUT=y
+CONFIG_IPACK_BUS=m
+CONFIG_IPMI_HANDLER=m
+CONFIG_IPMI_SI_PROBE_DEFAULTS=y
+CONFIG_IPX=m
+# CONFIG_IP_DCCP_CCID3 is not set
+CONFIG_IRQ_BYPASS_MANAGER=m
+CONFIG_ISA=y
+CONFIG_JFS_FS=m
+CONFIG_JME=m
+CONFIG_JUMP_LABEL=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+CONFIG_KVM=m
+CONFIG_LAPB=m
+CONFIG_LDM_PARTITION=y
+CONFIG_LIBNVDIMM=y
+CONFIG_LLC2=m
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LPC_ICH=m
+CONFIG_LPC_SCH=m
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+CONFIG_MAILBOX=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_MAX63XX_WATCHDOG=m
+CONFIG_MCB=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_SAS=m
+CONFIG_MEMORY=y
+CONFIG_MEMSTICK=m
+CONFIG_MFD_CORE=y
+CONFIG_MFD_JANZ_CMODIO=m
+CONFIG_MFD_KEMPLD=m
+CONFIG_MFD_MT6397=m
+CONFIG_MFD_RDC321X=m
+CONFIG_MFD_RTSX_PCI=m
+CONFIG_MFD_SM501=m
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_TI_AM335X_TSCADC=m
+# CONFIG_MFD_TMIO is not set
+CONFIG_MFD_VX855=m
+CONFIG_MII=m
+CONFIG_MITIGATION_VMSCAPE=y
+CONFIG_MINIX_FS=m
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_PLTFM=m
+CONFIG_MTD=m
+CONFIG_MTD_BLKDEVS=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_NAND=m
+CONFIG_MTD_NAND_BCH=m
+CONFIG_MTD_NAND_ECC=m
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+CONFIG_NCP_FS=m
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NET_CADENCE=y
+CONFIG_NET_PACKET_ENGINE=y
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CAVIUM=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_SYNOPSYS=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NEW_LEDS=y
+CONFIG_NFC=m
+CONFIG_NOZOMI=m
+CONFIG_NR_CPUS=8
+CONFIG_NTB=m
+# CONFIG_NTFS_RW is not set
+CONFIG_NVMEM=m
+CONFIG_NVRAM=m
+CONFIG_N_GSM=m
+# CONFIG_OF is not set
+CONFIG_OMFS_FS=m
+# CONFIG_OPENNSL is not set
+CONFIG_OSF_PARTITION=y
+CONFIG_OUTPUT_FORMAT="elf32-i386"
+CONFIG_PAGE_EXTENSION=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_PARPORT=m
+CONFIG_PATA_SIS=y
+CONFIG_PCCARD=m
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_PCI_PASID=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_PCMCIA=m
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PGTABLE_MAPPING=y
+CONFIG_PHANTOM=m
+CONFIG_PHONET=m
+CONFIG_PHYLIB=y
+CONFIG_PHYSICAL_ALIGN=0x1000000
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PHY_EXYNOS5250_USB2 is not set
+CONFIG_PHY_PXA_28NM_HSIC=m
+CONFIG_PHY_PXA_28NM_USB2=m
+CONFIG_PM_DEBUG=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_POWERCAP=y
+CONFIG_POWER_AVS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPP=y
+CONFIG_PPS=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PPS_CLIENT_LDISC=m
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PROBE_EVENTS=y
+CONFIG_PSTORE=y
+# CONFIG_PSTORE_CONSOLE is not set
+CONFIG_PSTORE_RAM=m
+CONFIG_PTP_1588_CLOCK=m
+CONFIG_PWM=y
+CONFIG_QNX4FS_FS=m
+CONFIG_QNX6FS_FS=m
+CONFIG_RANDOMIZE_BASE_MAX_OFFSET=0x20000000
+CONFIG_RAW_DRIVER=m
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_REED_SOLOMON=m
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_TWL4030=m
+CONFIG_REISERFS_FS=m
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFKILL=y
+CONFIG_ROMFS_FS=m
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_TWL4030=m
+CONFIG_SATA_AHCI_PLATFORM=m
+CONFIG_SATA_SVW=m
+CONFIG_SCHED_SMT=y
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC94XX=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_DPT_I2O=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_MVSAS=m
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_SNIC=m
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_UFSHCD=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SENSORS_SCH56XX_COMMON=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_DW=m
+# CONFIG_SERIAL_8250_FSL is not set
+CONFIG_SERIAL_ALTERA_JTAGUART=m
+CONFIG_SERIAL_ALTERA_UART=m
+CONFIG_SERIAL_ARC=m
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_FSL_LPUART=m
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_SCCNXP=y
+CONFIG_SERIO=y
+CONFIG_SFC=m
+CONFIG_SGI_IOC4=m
+CONFIG_SGI_PARTITION=y
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+CONFIG_SLIP=m
+CONFIG_SND=m
+CONFIG_SND_DMAENGINE_PCM=m
+CONFIG_SND_EMU10K1_SEQ=m
+CONFIG_SND_OPL4_LIB_SEQ=m
+CONFIG_SND_PCM=m
+CONFIG_SND_SBAWE_SEQ=m
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_FSL_SSI=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+CONFIG_SND_SOC_IMX_AUDMUX=m
+# CONFIG_SND_SOC_RT5677_SPI is not set
+CONFIG_SND_SOC_SGTL5000=m
+CONFIG_SND_TIMER=m
+CONFIG_SOC_TI=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_SOUND=m
+CONFIG_SPI=y
+CONFIG_SPI_PXA2XX_PCI=m
+CONFIG_SPMI=m
+CONFIG_SRAM=y
+CONFIG_SSB=m
+CONFIG_STAGING=y
+# CONFIG_STANDALONE is not set
+CONFIG_STE_MODEM_RPROC=m
+CONFIG_SUN_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_SYSV_FS=m
+CONFIG_SYS_HYPERVISOR=y
+CONFIG_THERMAL=y
+CONFIG_THUNDERBOLT=m
+CONFIG_TIFM_CORE=m
+CONFIG_TIGON3=m
+CONFIG_TI_CPSW_ALE=m
+CONFIG_TRACE_SINK=m
+CONFIG_TTY_PRINTK=y
+CONFIG_UFS_FS=m
+CONFIG_UIO=m
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_UPROBES=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_GADGET=m
+# CONFIG_USB_G_MULTI is not set
+CONFIG_USB_HCD_BCMA=m
+CONFIG_USB_HCD_SSB=m
+CONFIG_USB_MUSB_HDRC=m
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_SUPPORT=y
+CONFIG_UWB=m
+CONFIG_VFIO=m
+CONFIG_VFIO_IOMMU_TYPE1=m
+CONFIG_VFIO_PCI=m
+CONFIG_VFIO_VIRQFD=m
+CONFIG_VGASTATE=m
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VM86=y
+CONFIG_VME_BUS=y
+CONFIG_VMXNET3=m
+CONFIG_VXFS_FS=m
+CONFIG_W1=m
+CONFIG_WAN=y
+CONFIG_WDTPCI=m
+CONFIG_WIMAX=m
+CONFIG_X25=m
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+CONFIG_X86_SPEEDSTEP_LIB=y
+CONFIG_XEN=y
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT=4
+CONFIG_XILINX_WATCHDOG=m
+CONFIG_XILLYBUS=m
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_XZ_DEC_X86=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZONE_DMA_FLAG=1
--- linux-4.4.0.orig/debian.master/config/i386/config.flavour.generic
+++ linux-4.4.0/debian.master/config/i386/config.flavour.generic
@@ -0,0 +1,9 @@
+#
+# Config options for config.flavour.generic automatically generated by splitconfig.pl
+#
+CONFIG_HZ=250
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ_250=y
+# CONFIG_IRQ_FORCED_THREADING_DEFAULT is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_VOLUNTARY=y
--- linux-4.4.0.orig/debian.master/config/i386/config.flavour.lowlatency
+++ linux-4.4.0/debian.master/config/i386/config.flavour.lowlatency
@@ -0,0 +1,9 @@
+#
+# Config options for config.flavour.lowlatency automatically generated by splitconfig.pl
+#
+CONFIG_HZ=1000
+CONFIG_HZ_1000=y
+# CONFIG_HZ_250 is not set
+CONFIG_IRQ_FORCED_THREADING_DEFAULT=y
+CONFIG_PREEMPT=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
--- linux-4.4.0.orig/debian.master/config/powerpc/config.common.powerpc
+++ linux-4.4.0/debian.master/config/powerpc/config.common.powerpc
@@ -0,0 +1,467 @@
+#
+# Config options for config.common.powerpc automatically generated by splitconfig.pl
+#
+CONFIG_64BIT=y
+CONFIG_6LOWPAN=m
+CONFIG_ABX500_CORE=y
+CONFIG_AC97_BUS=m
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_AIX_PARTITION=y
+CONFIG_ALIM7101_WDT=m
+CONFIG_ALTERA_TSE=m
+CONFIG_AMIGA_PARTITION=y
+CONFIG_APM_EMULATION=m
+CONFIG_APPLICOM=m
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCNET=m
+CONFIG_ATALK=m
+CONFIG_ATARI_PARTITION=y
+CONFIG_ATA_GENERIC=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_ATA_PIIX=m
+CONFIG_ATM=m
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_AUXDISPLAY=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BATMAN_ADV=m
+CONFIG_BCH=m
+CONFIG_BCMA=m
+CONFIG_BCM_KONA_USB2_PHY=m
+CONFIG_BE2ISCSI=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_NVME=m
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
+CONFIG_BLK_DEV_RSXX=m
+CONFIG_BLK_DEV_SKD=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BOUNCE=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_C2PORT=m
+CONFIG_CADENCE_WATCHDOG=m
+CONFIG_CAIF=m
+CONFIG_CAN=m
+CONFIG_CB710_CORE=m
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CMA=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CRAMFS=m
+# CONFIG_CRYPTO_DEV_FSL_CAAM_IMX is not set
+# CONFIG_CRYPTO_DEV_FSL_CAAM_LE is not set
+CONFIG_DECNET=m
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_DMADEVICES=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DMA_VIRTUAL_CHANNELS=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DNET=m
+CONFIG_DRM=m
+CONFIG_DUMMY_IRQ=m
+CONFIG_DW_WATCHDOG=m
+CONFIG_ECHO=m
+CONFIG_EEPROM_93CX6=m
+CONFIG_EFS_FS=m
+# CONFIG_EM_TIMER_STI is not set
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_ETHOC=m
+CONFIG_EXOFS_FS=m
+CONFIG_EXTCON=y
+CONFIG_F2FS_FS=m
+CONFIG_FB=y
+CONFIG_FB_ATY128=y
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_IBM_GXT4500=m
+CONFIG_FB_MACMODES=y
+CONFIG_FB_VOODOO1=y
+CONFIG_FDDI=y
+CONFIG_FEALNX=m
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_NOSY=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIXED_PHY=y
+CONFIG_FMC=m
+CONFIG_FRAME_WARN=1024
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
+# CONFIG_GENERIC_CSUM is not set
+CONFIG_GENERIC_PHY=y
+CONFIG_GPIO_GENERIC=m
+CONFIG_GPIO_GENERIC_PLATFORM=m
+CONFIG_GPIO_TWL4030=m
+CONFIG_GPIO_TWL6040=m
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HFSPLUS_FS=m
+CONFIG_HFS_FS=m
+# CONFIG_HIO is not set
+CONFIG_HOTPLUG_PCI_PCIE=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_HPFS_FS=m
+CONFIG_HP_ILO=m
+CONFIG_HSI=m
+CONFIG_HSR=m
+CONFIG_HTC_PASIC3=m
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ_250=y
+CONFIG_I2C=y
+# CONFIG_I2C_SLAVE is not set
+CONFIG_I6300ESB_WDT=m
+CONFIG_IEEE802154=m
+CONFIG_IIO=m
+CONFIG_INFINIBAND_NES=m
+CONFIG_INFINIBAND_OCRDMA=m
+CONFIG_INFINIBAND_QIB=m
+CONFIG_INPUT=y
+CONFIG_IPACK_BUS=m
+CONFIG_IPMI_HANDLER=m
+CONFIG_IPMI_SI_PROBE_DEFAULTS=y
+CONFIG_IPX=m
+# CONFIG_IP_DCCP_CCID3 is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_IRQ_BYPASS_MANAGER=m
+# CONFIG_IRQ_FORCED_THREADING_DEFAULT is not set
+# CONFIG_ISA is not set
+CONFIG_JFS_FS=m
+CONFIG_JME=m
+CONFIG_JUMP_LABEL=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_KVM=y
+CONFIG_LAPB=m
+CONFIG_LDM_PARTITION=y
+CONFIG_LIBNVDIMM=y
+CONFIG_LLC2=m
+CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_LPARCFG is not set
+CONFIG_LPC_ICH=m
+CONFIG_LPC_SCH=m
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+CONFIG_MAILBOX=y
+CONFIG_MATH_EMULATION=y
+CONFIG_MAX63XX_WATCHDOG=m
+CONFIG_MCB=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_SAS=m
+CONFIG_MEMORY=y
+CONFIG_MEMSTICK=m
+CONFIG_MFD_CORE=y
+CONFIG_MFD_JANZ_CMODIO=m
+CONFIG_MFD_KEMPLD=m
+CONFIG_MFD_MT6397=m
+CONFIG_MFD_RDC321X=m
+CONFIG_MFD_RTSX_PCI=m
+CONFIG_MFD_SM501=m
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_TI_AM335X_TSCADC=m
+# CONFIG_MFD_TMIO is not set
+CONFIG_MFD_VX855=m
+CONFIG_MII=m
+CONFIG_MINIX_FS=m
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_PLTFM=m
+CONFIG_MPIC_MSGR=y
+CONFIG_MTD=m
+CONFIG_MTD_BLKDEVS=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_NAND=m
+CONFIG_MTD_NAND_BCH=m
+CONFIG_MTD_NAND_ECC=m
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+CONFIG_MTD_OF_PARTS=m
+CONFIG_NCP_FS=m
+CONFIG_NET_CADENCE=y
+CONFIG_NET_PACKET_ENGINE=y
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CAVIUM=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_SYNOPSYS=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NEW_LEDS=y
+CONFIG_NFC=m
+CONFIG_NODES_SHIFT=8
+CONFIG_NOZOMI=m
+CONFIG_NTB=m
+# CONFIG_NTFS_RW is not set
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
+CONFIG_NVMEM=m
+CONFIG_NVRAM=y
+CONFIG_N_GSM=m
+CONFIG_OF=y
+CONFIG_OMFS_FS=m
+# CONFIG_OPENNSL is not set
+CONFIG_OSF_PARTITION=y
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_PARPORT=m
+CONFIG_PATA_SIS=m
+CONFIG_PCCARD=m
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_PCI_PASID=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_PCMCIA=m
+CONFIG_PGTABLE_MAPPING=y
+CONFIG_PHANTOM=m
+CONFIG_PHONET=m
+CONFIG_PHYLIB=y
+CONFIG_PHYSICAL_ALIGN=0x04000000
+CONFIG_PHYSICAL_START=0x00000000
+# CONFIG_PHY_EXYNOS5250_USB2 is not set
+CONFIG_PHY_PXA_28NM_HSIC=m
+CONFIG_PHY_PXA_28NM_USB2=m
+CONFIG_PM_DEBUG=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_PM_WAKELOCKS=y
+# CONFIG_POWER7_CPU is not set
+CONFIG_POWERCAP=y
+CONFIG_POWER_AVS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_DENORMALISATION is not set
+CONFIG_PPC_DISABLE_WERROR=y
+CONFIG_PPC_ICSWX=y
+# CONFIG_PPC_SMLPAR is not set
+# CONFIG_PPC_SPLPAR is not set
+CONFIG_PPP=y
+CONFIG_PPS=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PPS_CLIENT_LDISC=m
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_PROBE_EVENTS=y
+CONFIG_PSTORE=y
+# CONFIG_PSTORE_CONSOLE is not set
+CONFIG_PSTORE_RAM=m
+CONFIG_PTP_1588_CLOCK=m
+CONFIG_PWM=y
+CONFIG_QNX4FS_FS=m
+CONFIG_QNX6FS_FS=m
+CONFIG_RAW_DRIVER=m
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+CONFIG_REED_SOLOMON=m
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_TWL4030=m
+CONFIG_REISERFS_FS=m
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFKILL=y
+CONFIG_ROMFS_FS=m
+CONFIG_RTC_DRV_CMOS=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_TWL4030=m
+CONFIG_SATA_AHCI_PLATFORM=m
+CONFIG_SATA_SVW=y
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC94XX=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_DPT_I2O=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_MVSAS=m
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_SNIC=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_UFSHCD=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_DW=m
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_ALTERA_JTAGUART=m
+CONFIG_SERIAL_ALTERA_UART=m
+CONFIG_SERIAL_ARC=m
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_FSL_LPUART=m
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_SCCNXP=y
+CONFIG_SERIO=y
+CONFIG_SFC=m
+CONFIG_SGI_IOC4=m
+CONFIG_SGI_PARTITION=y
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+CONFIG_SIMPLE_GPIO=y
+CONFIG_SLIP=m
+CONFIG_SND=m
+CONFIG_SND_DMAENGINE_PCM=m
+CONFIG_SND_EMU10K1_SEQ=m
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+CONFIG_SND_PCM=m
+# CONFIG_SND_SBAWE_SEQ is not set
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_FSL_SSI=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+CONFIG_SND_SOC_IMX_AUDMUX=m
+# CONFIG_SND_SOC_RT5677_SPI is not set
+CONFIG_SND_SOC_SGTL5000=m
+CONFIG_SND_TIMER=m
+CONFIG_SOC_TI=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_SOUND=m
+CONFIG_SPI=y
+CONFIG_SPMI=m
+CONFIG_SRAM=y
+CONFIG_SSB=m
+CONFIG_STAGING=y
+CONFIG_STANDALONE=y
+CONFIG_STE_MODEM_RPROC=m
+CONFIG_SUN_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_SYSV_FS=m
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_THERMAL=y
+CONFIG_THUNDERBOLT=m
+CONFIG_TIFM_CORE=m
+CONFIG_TIGON3=m
+CONFIG_TI_CPSW_ALE=m
+CONFIG_TRACE_SINK=m
+CONFIG_TTY_PRINTK=y
+CONFIG_UDBG_RTAS_CONSOLE=y
+CONFIG_UFS_FS=m
+CONFIG_UIO=m
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_UPROBES=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_FSL_MPH_DR_OF=y
+CONFIG_USB_GADGET=m
+# CONFIG_USB_G_MULTI is not set
+CONFIG_USB_HCD_BCMA=m
+CONFIG_USB_HCD_SSB=m
+CONFIG_USB_MUSB_HDRC=m
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_UWB=m
+CONFIG_VFIO=m
+CONFIG_VFIO_IOMMU_SPAPR_TCE=m
+# CONFIG_VFIO_IOMMU_TYPE1 is not set
+CONFIG_VFIO_PCI=m
+CONFIG_VFIO_SPAPR_EEH=m
+CONFIG_VFIO_VIRQFD=m
+CONFIG_VGASTATE=m
+CONFIG_VIRTIO_MMIO=y
+# CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set
+CONFIG_VME_BUS=y
+CONFIG_VMXNET3=m
+CONFIG_VXFS_FS=m
+CONFIG_W1=m
+CONFIG_WAN=y
+CONFIG_WDTPCI=m
+CONFIG_WIMAX=m
+CONFIG_X25=m
+CONFIG_XILINX_WATCHDOG=m
+CONFIG_XILLYBUS=m
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_XZ_DEC_X86=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZONE_DMA_FLAG=1
--- linux-4.4.0.orig/debian.master/config/powerpc/config.flavour.powerpc-e500mc
+++ linux-4.4.0/debian.master/config/powerpc/config.flavour.powerpc-e500mc
@@ -0,0 +1,59 @@
+#
+# Config options for config.flavour.powerpc-e500mc automatically generated by splitconfig.pl
+#
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+# CONFIG_ARCH_RANDOM is not set
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_KERNEL_API is not set
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_EPAPR_BOOT is not set
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+CONFIG_FB_UDL=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_HAS_RAPIDIO=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_HIBERNATION=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_IMA=y
+CONFIG_KERNEL_START=0xc0000000
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_MPIC_U3_HT_IRQS is not set
+# CONFIG_NEED_DMA_MAP_STATE is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
+# CONFIG_NONSTATIC_KERNEL is not set
+CONFIG_NR_CPUS=8
+CONFIG_PAGE_EXTENSION=y
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PPC64 is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_BOOK3S_32 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_COPRO_BASE is not set
+CONFIG_PPC_DOORBELL=y
+CONFIG_PPC_EPAPR_HV_PIC=y
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_ICP_HV is not set
+# CONFIG_PPC_ICP_NATIVE is not set
+# CONFIG_PPC_ICS_RTAS is not set
+CONFIG_PPC_INDIRECT_PCI=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_P7_NAP is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_PPC_XICS is not set
+CONFIG_RTC_DRV_DS3232=y
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SPI_PXA2XX_PCI=m
+CONFIG_WORD_SIZE=32
--- linux-4.4.0.orig/debian.master/config/powerpc/config.flavour.powerpc-smp
+++ linux-4.4.0/debian.master/config/powerpc/config.flavour.powerpc-smp
@@ -0,0 +1,60 @@
+#
+# Config options for config.flavour.powerpc-smp automatically generated by splitconfig.pl
+#
+# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+# CONFIG_ARCH_RANDOM is not set
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_KERNEL_API is not set
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_EPAPR_BOOT is not set
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+CONFIG_FB_UDL=m
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_GENERIC_TBSYNC=y
+# CONFIG_HAS_RAPIDIO is not set
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_HIBERNATION=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_IMA=y
+CONFIG_KERNEL_START=0xc0000000
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_MPIC_U3_HT_IRQS is not set
+# CONFIG_NEED_DMA_MAP_STATE is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
+# CONFIG_NONSTATIC_KERNEL is not set
+CONFIG_NR_CPUS=4
+CONFIG_PAGE_EXTENSION=y
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_PGTABLE_LEVELS=2
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+# CONFIG_PPC64 is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_970_NAP is not set
+CONFIG_PPC_BOOK3S_32=y
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_COPRO_BASE is not set
+# CONFIG_PPC_DOORBELL is not set
+# CONFIG_PPC_EPAPR_HV_PIC is not set
+CONFIG_PPC_I8259=y
+# CONFIG_PPC_ICP_HV is not set
+# CONFIG_PPC_ICP_NATIVE is not set
+# CONFIG_PPC_ICS_RTAS is not set
+CONFIG_PPC_INDIRECT_PCI=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_MPC106=y
+CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
+# CONFIG_PPC_P7_NAP is not set
+CONFIG_PPC_RTAS=y
+# CONFIG_PPC_XICS is not set
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_SCSI_SRP_ATTRS=m
+# CONFIG_SPI_PXA2XX_PCI is not set
+CONFIG_WORD_SIZE=32
--- linux-4.4.0.orig/debian.master/config/powerpc/config.flavour.powerpc64-emb
+++ linux-4.4.0/debian.master/config/powerpc/config.flavour.powerpc64-emb
@@ -0,0 +1,63 @@
+#
+# Config options for config.flavour.powerpc64-emb automatically generated by splitconfig.pl
+#
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+# CONFIG_ARCH_RANDOM is not set
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_CRASH_DUMP=y
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_KERNEL_API is not set
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_EPAPR_BOOT is not set
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+CONFIG_FB_UDL=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_HAS_RAPIDIO=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+# CONFIG_HIBERNATION is not set
+CONFIG_HUGETLB_PAGE=y
+# CONFIG_IMA is not set
+CONFIG_KERNEL_START=0xc000000000000000
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_MPIC_U3_HT_IRQS is not set
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NONSTATIC_KERNEL=y
+CONFIG_NR_CPUS=8
+# CONFIG_NUMA is not set
+# CONFIG_PAGE_EXTENSION is not set
+CONFIG_PAGE_OFFSET=0xc000000000000000
+CONFIG_PGTABLE_LEVELS=4
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PPC64=y
+# CONFIG_PPC_970_NAP is not set
+CONFIG_PPC_BOOK3E_64=y
+# CONFIG_PPC_BOOK3S_64 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_COPRO_BASE is not set
+CONFIG_PPC_DOORBELL=y
+CONFIG_PPC_EPAPR_HV_PIC=y
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_ICP_HV is not set
+# CONFIG_PPC_ICP_NATIVE is not set
+# CONFIG_PPC_ICS_RTAS is not set
+CONFIG_PPC_INDIRECT_PCI=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
+# CONFIG_PPC_P7_NAP is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_PPC_XICS is not set
+CONFIG_RTC_DRV_DS3232=y
+# CONFIG_SCHED_SMT is not set
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SPI_PXA2XX_PCI=m
+# CONFIG_U3_DART is not set
+CONFIG_WORD_SIZE=64
--- linux-4.4.0.orig/debian.master/config/powerpc/config.flavour.powerpc64-smp
+++ linux-4.4.0/debian.master/config/powerpc/config.flavour.powerpc64-smp
@@ -0,0 +1,63 @@
+#
+# Config options for config.flavour.powerpc64-smp automatically generated by splitconfig.pl
+#
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_RANDOM=y
+CONFIG_ATA_NONSTANDARD=y
+CONFIG_CRASH_DUMP=y
+CONFIG_CXL_BASE=y
+CONFIG_CXL_EEH=y
+CONFIG_CXL_KERNEL_API=y
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_EPAPR_BOOT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+CONFIG_FB_UDL=m
+CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_GENERIC_TBSYNC=y
+# CONFIG_HAS_RAPIDIO is not set
+CONFIG_HAVE_BOOTMEM_INFO_NODE=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HIBERNATION=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_IMA=y
+CONFIG_KERNEL_START=0xc000000000000000
+CONFIG_MMIO_NVRAM=y
+CONFIG_MPIC_U3_HT_IRQS=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NONSTATIC_KERNEL=y
+CONFIG_NR_CPUS=1024
+CONFIG_NUMA=y
+# CONFIG_PAGE_EXTENSION is not set
+CONFIG_PAGE_OFFSET=0xc000000000000000
+CONFIG_PGTABLE_LEVELS=4
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PPC64=y
+CONFIG_PPC_970_NAP=y
+# CONFIG_PPC_BOOK3E_64 is not set
+CONFIG_PPC_BOOK3S_64=y
+CONFIG_PPC_CELL=y
+CONFIG_PPC_COPRO_BASE=y
+CONFIG_PPC_DOORBELL=y
+# CONFIG_PPC_EPAPR_HV_PIC is not set
+CONFIG_PPC_I8259=y
+CONFIG_PPC_ICP_HV=y
+CONFIG_PPC_ICP_NATIVE=y
+CONFIG_PPC_ICS_RTAS=y
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PPC_MM_SLICES=y
+# CONFIG_PPC_MPC106 is not set
+CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
+CONFIG_PPC_P7_NAP=y
+CONFIG_PPC_RTAS=y
+CONFIG_PPC_XICS=y
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_SCHED_SMT=y
+CONFIG_SCSI_SRP_ATTRS=y
+# CONFIG_SPI_PXA2XX_PCI is not set
+CONFIG_U3_DART=y
+CONFIG_WORD_SIZE=64
--- linux-4.4.0.orig/debian.master/config/ppc64el/config.common.ppc64el
+++ linux-4.4.0/debian.master/config/ppc64el/config.common.ppc64el
@@ -0,0 +1,517 @@
+#
+# Config options for config.common.ppc64el automatically generated by splitconfig.pl
+#
+CONFIG_64BIT=y
+CONFIG_6LOWPAN=m
+CONFIG_ABX500_CORE=y
+CONFIG_AC97_BUS=m
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_AIX_PARTITION=y
+CONFIG_ALIM7101_WDT=m
+CONFIG_ALTERA_TSE=m
+CONFIG_AMIGA_PARTITION=y
+CONFIG_APPLICOM=m
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_RANDOM=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCNET=m
+CONFIG_ATALK=m
+CONFIG_ATARI_PARTITION=y
+CONFIG_ATA_GENERIC=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_OVER_ETH=m
+CONFIG_ATA_PIIX=m
+CONFIG_ATM=m
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_AUXDISPLAY=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BATMAN_ADV=m
+CONFIG_BCH=m
+CONFIG_BCMA=m
+CONFIG_BCM_KONA_USB2_PHY=m
+CONFIG_BE2ISCSI=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_NVME=m
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
+CONFIG_BLK_DEV_RSXX=m
+CONFIG_BLK_DEV_SKD=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BOUNCE=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_C2PORT=m
+CONFIG_CADENCE_WATCHDOG=m
+CONFIG_CAIF=m
+CONFIG_CAN=m
+CONFIG_CB710_CORE=m
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CMA=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_CMM=m
+CONFIG_CONFIGFS_FS=m
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_CRAMFS=m
+CONFIG_CRASH_DUMP=y
+CONFIG_CXL_BASE=y
+CONFIG_CXL_EEH=y
+CONFIG_CXL_KERNEL_API=y
+CONFIG_DECNET=m
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_DMADEVICES=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DMA_VIRTUAL_CHANNELS=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DNET=m
+CONFIG_DRM=m
+CONFIG_DUMMY_IRQ=m
+CONFIG_DW_WATCHDOG=m
+CONFIG_ECHO=m
+CONFIG_EEPROM_93CX6=m
+CONFIG_EFS_FS=m
+# CONFIG_EM_TIMER_STI is not set
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_EPAPR_BOOT=y
+CONFIG_ETHOC=m
+CONFIG_EXOFS_FS=m
+CONFIG_EXTCON=y
+CONFIG_F2FS_FS=m
+CONFIG_FB=y
+CONFIG_FB_ATY128=m
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_IBM_GXT4500=y
+CONFIG_FB_MACMODES=y
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+CONFIG_FB_UDL=m
+CONFIG_FB_VOODOO1=m
+CONFIG_FDDI=y
+CONFIG_FEALNX=m
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_NOSY=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIXED_PHY=y
+CONFIG_FMC=m
+CONFIG_FORCE_MAX_ZONEORDER=9
+CONFIG_FRAME_WARN=2048
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_PHY=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_GPIO_GENERIC=m
+CONFIG_GPIO_GENERIC_PLATFORM=m
+CONFIG_GPIO_TWL4030=m
+CONFIG_GPIO_TWL6040=m
+# CONFIG_HAS_RAPIDIO is not set
+CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_BOOTMEM_INFO_NODE=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HFSPLUS_FS=m
+CONFIG_HFS_FS=m
+# CONFIG_HIBERNATION is not set
+# CONFIG_HIO is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+CONFIG_HPFS_FS=m
+CONFIG_HP_ILO=m
+CONFIG_HSI=m
+CONFIG_HSR=m
+CONFIG_HTC_PASIC3=m
+CONFIG_HUGETLB_PAGE=y
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ_250=y
+CONFIG_I2C=y
+# CONFIG_I2C_SLAVE is not set
+CONFIG_I6300ESB_WDT=m
+CONFIG_IEEE802154=m
+CONFIG_IIO=m
+CONFIG_IMA=y
+CONFIG_INFINIBAND_NES=m
+CONFIG_INFINIBAND_OCRDMA=m
+CONFIG_INFINIBAND_QIB=m
+CONFIG_INPUT=y
+CONFIG_IPACK_BUS=m
+CONFIG_IPMI_HANDLER=m
+CONFIG_IPMI_SI_PROBE_DEFAULTS=y
+CONFIG_IPX=m
+# CONFIG_IP_DCCP_CCID3 is not set
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_IRQ_BYPASS_MANAGER=y
+# CONFIG_IRQ_FORCED_THREADING_DEFAULT is not set
+CONFIG_JFS_FS=m
+CONFIG_JME=m
+CONFIG_JUMP_LABEL=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_KERNEL_START=0xc000000000000000
+CONFIG_KVM=y
+CONFIG_LAPB=m
+CONFIG_LDM_PARTITION=y
+CONFIG_LIBNVDIMM=y
+CONFIG_LLC2=m
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_LPARCFG=y
+CONFIG_LPC_ICH=m
+CONFIG_LPC_SCH=m
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+CONFIG_MAILBOX=y
+CONFIG_MAX63XX_WATCHDOG=m
+CONFIG_MCB=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_SAS=m
+CONFIG_MEMORY=y
+CONFIG_MEMSTICK=m
+CONFIG_MFD_CORE=y
+CONFIG_MFD_JANZ_CMODIO=m
+CONFIG_MFD_KEMPLD=m
+CONFIG_MFD_MT6397=m
+CONFIG_MFD_RDC321X=m
+CONFIG_MFD_RTSX_PCI=m
+CONFIG_MFD_SM501=m
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_TI_AM335X_TSCADC=m
+# CONFIG_MFD_TMIO is not set
+CONFIG_MFD_VX855=m
+CONFIG_MII=m
+CONFIG_MINIX_FS=m
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_PLTFM=m
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_MPIC_MSGR is not set
+# CONFIG_MPIC_U3_HT_IRQS is not set
+CONFIG_MTD=m
+CONFIG_MTD_BLKDEVS=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_NAND=m
+CONFIG_MTD_NAND_BCH=m
+CONFIG_MTD_NAND_ECC=m
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+CONFIG_MTD_OF_PARTS=m
+CONFIG_NCP_FS=m
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NET_CADENCE=y
+CONFIG_NET_PACKET_ENGINE=y
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CAVIUM=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_SYNOPSYS=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NEW_LEDS=y
+CONFIG_NFC=m
+CONFIG_NODES_SHIFT=8
+CONFIG_NONSTATIC_KERNEL=y
+CONFIG_NOZOMI=m
+CONFIG_NR_CPUS=2048
+CONFIG_NTB=m
+# CONFIG_NTFS_RW is not set
+CONFIG_NUMA=y
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
+CONFIG_NVMEM=m
+CONFIG_N_GSM=m
+CONFIG_OF=y
+CONFIG_OMFS_FS=m
+# CONFIG_OPENNSL is not set
+CONFIG_OSF_PARTITION=y
+# CONFIG_PAGE_EXTENSION is not set
+CONFIG_PAGE_OFFSET=0xc000000000000000
+CONFIG_PANIC_TIMEOUT=10
+CONFIG_PARPORT=m
+CONFIG_PATA_SIS=m
+# CONFIG_PCCARD is not set
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_PCI_PASID=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PGTABLE_MAPPING=y
+CONFIG_PHANTOM=m
+CONFIG_PHONET=m
+CONFIG_PHYLIB=y
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PHY_EXYNOS5250_USB2 is not set
+CONFIG_PHY_PXA_28NM_HSIC=m
+CONFIG_PHY_PXA_28NM_USB2=m
+CONFIG_PM_DEBUG=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_POWER7_CPU=y
+CONFIG_POWERCAP=y
+CONFIG_POWER_AVS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPC64=y
+# CONFIG_PPC_4K_PAGES is not set
+CONFIG_PPC_64K_PAGES=y
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_BOOK3E_64 is not set
+CONFIG_PPC_BOOK3S_64=y
+# CONFIG_PPC_CELL is not set
+CONFIG_PPC_COPRO_BASE=y
+CONFIG_PPC_DENORMALISATION=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_DOORBELL=y
+# CONFIG_PPC_EPAPR_HV_PIC is not set
+CONFIG_PPC_I8259=y
+CONFIG_PPC_ICP_HV=y
+CONFIG_PPC_ICP_NATIVE=y
+# CONFIG_PPC_ICSWX is not set
+CONFIG_PPC_ICS_RTAS=y
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PPC_MM_SLICES=y
+# CONFIG_PPC_MPC106 is not set
+CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
+CONFIG_PPC_P7_NAP=y
+CONFIG_PPC_RTAS=y
+CONFIG_PPC_SMLPAR=y
+CONFIG_PPC_SPLPAR=y
+CONFIG_PPC_XICS=y
+CONFIG_PPP=y
+CONFIG_PPS=y
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PPS_CLIENT_LDISC=m
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_PROBE_EVENTS=y
+CONFIG_PSTORE=y
+# CONFIG_PSTORE_CONSOLE is not set
+CONFIG_PSTORE_RAM=m
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PWM=y
+CONFIG_QNX4FS_FS=m
+CONFIG_QNX6FS_FS=m
+CONFIG_RAW_DRIVER=m
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+CONFIG_REED_SOLOMON=m
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_TWL4030=m
+CONFIG_REISERFS_FS=m
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFKILL=y
+CONFIG_ROMFS_FS=m
+CONFIG_RTC_DRV_CMOS=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_TWL4030=m
+CONFIG_SATA_AHCI_PLATFORM=m
+CONFIG_SATA_SVW=m
+CONFIG_SCHED_SMT=y
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC94XX=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_MVSAS=m
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_SNIC=m
+CONFIG_SCSI_SRP_ATTRS=y
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_UFSHCD=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_DW=m
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_ALTERA_JTAGUART=m
+CONFIG_SERIAL_ALTERA_UART=m
+CONFIG_SERIAL_ARC=m
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_FSL_LPUART=m
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_SCCNXP=y
+CONFIG_SERIO=y
+CONFIG_SFC=m
+CONFIG_SGI_IOC4=m
+CONFIG_SGI_PARTITION=y
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_SIMPLE_GPIO is not set
+CONFIG_SLIP=m
+CONFIG_SND=m
+CONFIG_SND_DMAENGINE_PCM=m
+CONFIG_SND_EMU10K1_SEQ=m
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+CONFIG_SND_PCM=m
+# CONFIG_SND_SBAWE_SEQ is not set
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_FSL_SSI=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+CONFIG_SND_SOC_IMX_AUDMUX=m
+# CONFIG_SND_SOC_RT5677_SPI is not set
+CONFIG_SND_SOC_SGTL5000=m
+CONFIG_SND_TIMER=m
+CONFIG_SOC_TI=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_SOUND=m
+CONFIG_SPI=y
+# CONFIG_SPI_PXA2XX_PCI is not set
+CONFIG_SPMI=m
+CONFIG_SRAM=y
+CONFIG_SSB=m
+CONFIG_STAGING=y
+CONFIG_STANDALONE=y
+CONFIG_STE_MODEM_RPROC=m
+CONFIG_SUN_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_SYSV_FS=m
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_THERMAL=y
+CONFIG_THUNDERBOLT=m
+CONFIG_TIFM_CORE=m
+CONFIG_TIGON3=y
+CONFIG_TI_CPSW_ALE=m
+CONFIG_TRACE_SINK=m
+CONFIG_TTY_PRINTK=y
+# CONFIG_U3_DART is not set
+# CONFIG_UDBG_RTAS_CONSOLE is not set
+CONFIG_UFS_FS=m
+CONFIG_UIO=m
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_UPROBES=y
+CONFIG_USB_EHCI_HCD_PLATFORM=m
+CONFIG_USB_GADGET=m
+# CONFIG_USB_G_MULTI is not set
+CONFIG_USB_HCD_BCMA=m
+CONFIG_USB_HCD_SSB=m
+CONFIG_USB_MUSB_HDRC=m
+CONFIG_USB_OHCI_HCD_PLATFORM=m
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_UWB=m
+CONFIG_VFIO=y
+CONFIG_VFIO_IOMMU_SPAPR_TCE=y
+# CONFIG_VFIO_IOMMU_TYPE1 is not set
+CONFIG_VFIO_PCI=y
+CONFIG_VFIO_SPAPR_EEH=y
+CONFIG_VFIO_VIRQFD=y
+CONFIG_VGASTATE=m
+CONFIG_VIRTIO_MMIO=y
+# CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set
+CONFIG_VME_BUS=y
+CONFIG_VXFS_FS=m
+CONFIG_W1=m
+CONFIG_WAN=y
+CONFIG_WDTPCI=m
+CONFIG_WIMAX=m
+CONFIG_WORD_SIZE=64
+CONFIG_X25=m
+CONFIG_XILINX_WATCHDOG=m
+CONFIG_XILLYBUS=m
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_XZ_DEC_X86=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZONE_DMA_FLAG=1
--- linux-4.4.0.orig/debian.master/config/ppc64el/config.flavour.generic
+++ linux-4.4.0/debian.master/config/ppc64el/config.flavour.generic
@@ -0,0 +1,3 @@
+#
+# Config options for config.flavour.generic automatically generated by splitconfig.pl
+#
--- linux-4.4.0.orig/debian.master/config/s390x/config.common.s390x
+++ linux-4.4.0/debian.master/config/s390x/config.common.s390x
@@ -0,0 +1,347 @@
+#
+# Config options for config.common.s390x automatically generated by splitconfig.pl
+#
+# CONFIG_6LOWPAN is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_ARCNET is not set
+# CONFIG_ATALK is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_ATM is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_BCMA is not set
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_DEV_RSXX is not set
+# CONFIG_BLK_DEV_SKD is not set
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BOUNCE is not set
+CONFIG_BPF_JIT_ALWAYS_ON=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_C2PORT is not set
+# CONFIG_CADENCE_WATCHDOG is not set
+# CONFIG_CAIF is not set
+# CONFIG_CAN is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_CMA is not set
+# CONFIG_CMDLINE_PARTITION is not set
+CONFIG_CONFIGFS_FS=y
+# CONFIG_CRAMFS is not set
+# CONFIG_DECNET is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+# CONFIG_DMADEVICES is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+CONFIG_DM_DEBUG=y
+# CONFIG_DNET is not set
+# CONFIG_DRM is not set
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_DW_WATCHDOG is not set
+# CONFIG_ECHO is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ETHOC is not set
+# CONFIG_EXOFS_FS is not set
+# CONFIG_EXTCON is not set
+# CONFIG_F2FS_FS is not set
+# CONFIG_FB is not set
+# CONFIG_FDDI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_FIXED_PHY=m
+# CONFIG_FMC is not set
+CONFIG_FORCE_MAX_ZONEORDER=9
+# CONFIG_FUSION is not set
+# CONFIG_GAMEPORT is not set
+# CONFIG_GENERIC_PHY is not set
+CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_HSI is not set
+# CONFIG_HSR is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HWMON is not set
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+CONFIG_HZ=100
+CONFIG_HZ_100=y
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_I2C is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_IIO is not set
+# CONFIG_INFINIBAND_NES is not set
+# CONFIG_INFINIBAND_OCRDMA is not set
+# CONFIG_INFINIBAND_QIB is not set
+# CONFIG_INPUT is not set
+# CONFIG_IPACK_BUS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPX is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_JFS_FS is not set
+# CONFIG_JME is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_KERNEL_GZIP is not set
+CONFIG_KERNEL_XZ=y
+CONFIG_KVM=y
+# CONFIG_LAPB is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_LIBNVDIMM is not set
+# CONFIG_LLC2 is not set
+# CONFIG_LPC_ICH is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6
+# CONFIG_MAILBOX is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_MCB is not set
+CONFIG_MD_MULTIPATH=y
+# CONFIG_MEDIA_SUPPORT is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_MEMORY is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_MT6397 is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_MMC is not set
+# CONFIG_MTD is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_AGERE is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CAVIUM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HP 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_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RENESAS is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_SYNOPSYS is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_NFC is not set
+CONFIG_NODES_SHIFT=4
+# CONFIG_NOZOMI is not set
+CONFIG_NR_CPUS=256
+# CONFIG_NTB is not set
+CONFIG_NTFS_RW=y
+# CONFIG_NUMA_BALANCING_DEFAULT_ENABLED is not set
+CONFIG_NUMA_EMU=y
+# CONFIG_NVMEM is not set
+# CONFIG_N_GSM is not set
+# CONFIG_OF is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_PCI_PASID is not set
+# CONFIG_PCI_PRI is not set
+# CONFIG_PCI_QUIRKS is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_PGTABLE_MAPPING is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_PHONET is not set
+CONFIG_PHYLIB=m
+# CONFIG_PHY_PXA_28NM_HSIC is not set
+# CONFIG_PHY_PXA_28NM_USB2 is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_PM_WAKELOCKS is not set
+# CONFIG_POWERCAP is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_PPP is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+# CONFIG_PPS_CLIENT_LDISC is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PROBE_EVENTS=y
+# CONFIG_PSTORE is not set
+# CONFIG_PWM is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_RAW_DRIVER is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+# CONFIG_REGULATOR is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_RESET_CONTROLLER is not set
+# CONFIG_RFKILL is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_CHELSIO_FCOE is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ESAS2R is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_MVUMI is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SNIC is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_UFSHCD is not set
+# CONFIG_SCSI_WD719X is not set
+# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set
+# CONFIG_SECURITY_SELINUX_DISABLE is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_ARC is not set
+CONFIG_SERIAL_CORE=m
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_RP2 is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIO is not set
+# CONFIG_SFC is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SLIP is not set
+# CONFIG_SOC_TI is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_SOUND is not set
+# CONFIG_SPI is not set
+# CONFIG_SPMI is not set
+# CONFIG_SRAM is not set
+# CONFIG_SSB is not set
+# CONFIG_STAGING is not set
+CONFIG_STANDALONE=y
+# CONFIG_STE_MODEM_RPROC is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THUNDERBOLT is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_TRACE_SINK is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UIO is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_UPROBES=y
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_UWB is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_VME_BUS is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_W1 is not set
+# CONFIG_WAN is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_WIMAX is not set
+# CONFIG_X25 is not set
+# CONFIG_XILINX_WATCHDOG is not set
+# CONFIG_XILLYBUS is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_BCJ is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_SPARC is not set
+# CONFIG_XZ_DEC_TEST is not set
+# CONFIG_XZ_DEC_X86 is not set
+CONFIG_ZLIB_DEFLATE=m
--- linux-4.4.0.orig/debian.master/config/s390x/config.flavour.generic
+++ linux-4.4.0/debian.master/config/s390x/config.flavour.generic
@@ -0,0 +1,3 @@
+#
+# Config options for config.flavour.generic automatically generated by splitconfig.pl
+#
--- linux-4.4.0.orig/debian.master/config/x32/config.common.x32
+++ linux-4.4.0/debian.master/config/x32/config.common.x32
@@ -0,0 +1 @@
+# nothing here yet
--- linux-4.4.0.orig/debian.master/config/x32/config.flavour.generic
+++ linux-4.4.0/debian.master/config/x32/config.flavour.generic
@@ -0,0 +1 @@
+# nothing here yet
--- linux-4.4.0.orig/debian.master/control.d/flavour-control.stub
+++ linux-4.4.0/debian.master/control.d/flavour-control.stub
@@ -0,0 +1,150 @@
+# Items that get replaced:
+# FLAVOUR
+# DESC
+# ARCH
+# SUPPORTED
+# TARGET
+# BOOTLOADER
+# =PROVIDES=
+#
+# Items marked with =FOO= are optional
+#
+# This file describes the template for packages that are created for each flavour
+# in debian/control.d/vars.*
+#
+# This file gets edited in a couple of places. See the debian/control.stub rule in
+# debian/rules. PGGVER, ABINUM, and SRCPKGNAME are all converted in the
+# process of creating debian/control.
+#
+# The flavour specific strings (ARCH, DESC, etc) are converted using values from the various
+# flavour files in debian/control.d/vars.*
+#
+# XXX: Leave the blank line before the first package!!
+
+Package: linux-image=SIGN-ME-PKG=-PKGVER-ABINUM-FLAVOUR
+Build-Profiles: <!stage1>
+Architecture: ARCH
+Section: kernel
+Priority: optional
+Provides: linux-image, fuse-module, =PROVIDES=${linux:rprovides}
+Depends: ${misc:Depends}, ${shlibs:Depends}, kmod, linux-base (>= 4.5ubuntu1~16.04.1), linux-modules-PKGVER-ABINUM-FLAVOUR
+Recommends: BOOTLOADER, initramfs-tools | linux-initramfs-tool
+Conflicts: linux-image=SIGN-PEER-PKG=-PKGVER-ABINUM-FLAVOUR
+Suggests: fdutils, SRCPKGNAME-doc-PKGVER | SRCPKGNAME-source-PKGVER, SRCPKGNAME-tools, linux-headers-PKGVER-ABINUM-FLAVOUR
+Description: Linux kernel image for version PKGVER on DESC
+ This package contains the=SIGN-ME-TXT= Linux kernel image for version PKGVER on
+ DESC.
+ .
+ Supports SUPPORTED processors.
+ .
+ TARGET
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-FLAVOUR meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-modules-PKGVER-ABINUM-FLAVOUR
+Build-Profiles: <!stage1>
+Architecture: ARCH
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Description: Linux kernel extra modules for version PKGVER on DESC
+ Contains the corresponding System.map file, the modules built by the
+ packager, and scripts that try to ensure that the system is not left in an
+ unbootable state after an update.
+ .
+ Supports SUPPORTED processors.
+ .
+ TARGET
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-FLAVOUR meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-modules-extra-PKGVER-ABINUM-FLAVOUR
+Build-Profiles: <!stage1>
+Architecture: ARCH
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-PKGVER-ABINUM-FLAVOUR | linux-image-unsigned-PKGVER-ABINUM-FLAVOUR, crda | wireless-crda
+Description: Linux kernel extra modules for version PKGVER on DESC
+ This package contains the Linux kernel extra modules for version PKGVER on
+ DESC.
+ .
+ Also includes the corresponding System.map file, the modules built by the
+ packager, and scripts that try to ensure that the system is not left in an
+ unbootable state after an update.
+ .
+ Supports SUPPORTED processors.
+ .
+ TARGET
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-FLAVOUR meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-headers-PKGVER-ABINUM-FLAVOUR
+Build-Profiles: <!stage1>
+Architecture: ARCH
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, SRCPKGNAME-headers-PKGVER-ABINUM, ${shlibs:Depends}
+Provides: linux-headers, linux-headers-3.0
+Description: Linux kernel headers for version PKGVER on DESC
+ This package provides kernel header files for version PKGVER on
+ DESC.
+ .
+ This is for sites that want the latest kernel headers.  Please read
+ /usr/share/doc/linux-headers-PKGVER-ABINUM/debian.README.gz for details.
+
+Package: linux-image=SIGN-ME-PKG=-PKGVER-ABINUM-FLAVOUR-dbgsym
+Build-Profiles: <!stage1>
+Architecture: ARCH
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}
+Provides: linux-debug
+Description: Linux kernel debug image for version PKGVER on DESC
+ This package provides the=SIGN-ME-TXT= kernel debug image for version PKGVER on
+ DESC.
+ .
+ This is for sites that wish to debug the kernel.
+ .
+ The kernel image contained in this package is NOT meant to boot from. It
+ is uncompressed, and unstripped. This package also includes the
+ unstripped modules.
+
+Package: linux-tools-PKGVER-ABINUM-FLAVOUR
+Build-Profiles: <!stage1>
+Architecture: ARCH
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, SRCPKGNAME-tools-PKGVER-ABINUM
+Description: Linux kernel version specific tools for version PKGVER-ABINUM
+ This package provides the architecture dependant parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version PKGVER-ABINUM on
+ =HUMAN=.
+
+Package: linux-cloud-tools-PKGVER-ABINUM-FLAVOUR
+Build-Profiles: <!stage1>
+Architecture: ARCH
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, SRCPKGNAME-cloud-tools-PKGVER-ABINUM
+Description: Linux kernel version specific cloud tools for version PKGVER-ABINUM
+ This package provides the architecture dependant parts for kernel
+ version locked tools for cloud for version PKGVER-ABINUM on
+ =HUMAN=.
+
+Package: linux-udebs-FLAVOUR
+Build-Profiles: <!stage1>
+XC-Package-Type: udeb
+Section: debian-installer
+Architecture: ARCH
+Depends: ${udeb:Depends}
+Description: Metapackage depending on kernel udebs
+ This package depends on the all udebs that the kernel build generated,
+ for easier version and migration tracking.
+
--- linux-4.4.0.orig/debian.master/control.d/generic.inclusion-list
+++ linux-4.4.0/debian.master/control.d/generic.inclusion-list
@@ -0,0 +1,238 @@
+arch/*/{crypto,kernel,oprofile}
+arch/*/kvm/kvm.ko
+arch/powerpc/kvm/kvm-hv.ko
+arch/powerpc/kvm/kvm-pr.ko
+arch/powerpc/platforms/powernv/opal-prd.ko
+arch/powerpc/kvm/vfio.ko
+arch/s390/*
+arch/x86/kvm/kvm-intel.ko
+arch/x86/kvm/kvm-amd.ko
+crypto/*
+drivers/acpi/*
+drivers/char/ipmi/ipmi_msghandler.ko
+drivers/ata/ahci_platform.ko
+drivers/ata/ahci.ko
+drivers/ata/acard-ahci.ko
+drivers/ata/libahci.ko
+drivers/ata/libahci_platform.ko
+drivers/block/brd.ko
+drivers/block/nbd.ko
+drivers/block/floppy.ko
+drivers/block/cryptoloop.ko
+drivers/block/rbd.ko
+drivers/char/hangcheck-timer.ko
+drivers/char/hw_random/virtio-rng.ko
+drivers/char/lp.ko
+drivers/char/nvram.ko
+drivers/char/hw_random/powernv-rng.ko
+drivers/char/ipmi/*
+drivers/char/ppdev.ko
+drivers/char/raw.ko
+drivers/crypto/nx/*
+drivers/crypto/vmx/vmx-crypto.ko
+drivers/firmware/iscsi_ibft.ko
+drivers/gpu/drm/ast/ast.ko
+drivers/gpu/drm/drm_kms_helper.ko
+drivers/gpu/drm/ttm/ttm.ko
+drivers/hid/hid.ko
+drivers/hid/hid-generic.ko
+drivers/hid/hid-hyperv.ko
+drivers/hid/usbhid/usbhid.ko
+drivers/hv/*
+drivers/hwmon/ibmpowernv.ko
+drivers/infiniband/core/ib_core.ko
+drivers/infiniband/core/ib_addr.ko
+drivers/infiniband/core/ib_cm.ko
+drivers/infiniband/core/ib_mad.ko
+drivers/infiniband/core/ib_sa.ko
+drivers/infiniband/core/iw_cm.ko
+drivers/infiniband/core/rdma_cm.ko
+drivers/infiniband/ulp/iser/ib_iser.ko
+drivers/infiniband/ulp/isert/ib_isert.ko
+drivers/input/evbug.ko
+drivers/input/gameport/gameport.ko
+drivers/input/input-leds.ko
+drivers/input/mouse/psmouse.ko
+drivers/input/serio/hyperv-keyboard.ko
+drivers/input/serio/serio_raw.ko
+drivers/input/serio/serport.ko
+drivers/input/joydev.ko
+drivers/input/touchscreen/usbtouchscreen.ko
+drivers/input/misc/xen-kbdfront.ko
+drivers/leds/leds-powernv.ko
+drivers/md/*
+drivers/message/fusion*
+drivers/misc/eeprom/at24.ko
+drivers/mtd/cmdlinepart.ko
+drivers/mtd/ofpart.ko
+drivers/mtd/devices/powernv_flash.ko
+drivers/nvme/host/nvme.ko
+drivers/nvmem/nvmem_core.ko
+drivers/s390/*
+drivers/scsi/scsi_transport_spi.ko
+drivers/misc/cxl/*
+drivers/misc/vmw_balloon.ko
+drivers/misc/vmw_vmci/vmw_vmci.ko
+drivers/net/caif/caif_virtio.ko
+drivers/net/mii.ko
+drivers/net/ethernet/8390/8390.ko
+drivers/net/ethernet/broadcom/bnx2x/*
+drivers/net/ethernet/emulex/benet/*
+drivers/net/ethernet/intel/i40e/*
+drivers/net/ethernet/intel/i40evf/*
+drivers/net/ethernet/intel/igb/*
+drivers/net/ethernet/intel/ixgbe/*
+drivers/net/ethernet/realtek/8139too.ko
+drivers/net/ethernet/realtek/8139cp.ko
+drivers/net/appletalk/ipddp.ko
+drivers/net/bonding/bonding.ko
+drivers/net/ppp/bsd_comp.ko
+drivers/net/dummy.ko
+drivers/net/ethernet/intel/e1000/e1000.ko
+drivers/net/ethernet/intel/e1000e/e1000e.ko
+drivers/net/eql.ko
+drivers/net/ethernet/ibm/*
+drivers/net/ifb.ko
+drivers/net/ethernet/intel/igbvf/igbvf.ko
+drivers/net/ethernet/intel/ixgbevf/ixgbevf.ko
+drivers/net/ethernet/amazon/ena/ena.ko
+drivers/net/geneve.ko
+drivers/net/macvlan.ko
+drivers/net/macvtap.ko
+drivers/net/ethernet/8390/ne2k-pci.ko
+drivers/net/netconsole.ko
+drivers/net/ethernet/amd/pcnet32.ko
+drivers/net/hyperv/hv_netvsc.ko
+drivers/net/ppp/*
+drivers/net/slip/*
+drivers/net/veth.ko
+drivers/net/vmxnet3/vmxnet3.ko
+drivers/net/vxlan.ko
+drivers/net/xen-netback/*
+drivers/net/ipvlan/*
+drivers/platform/x86/pvpanic.ko
+drivers/parport/parport.ko
+drivers/parport/parport_pc.ko
+drivers/pps/pps_core.ko
+drivers/ptp/ptp.ko
+drivers/net/ethernet/dec/tulip/*
+drivers/net/ethernet/mellanox/*
+drivers/scsi/aacraid/*
+drivers/scsi/BusLogic.ko
+drivers/scsi/cxlflash/*
+drivers/scsi/device_handler/scsi_dh_emc.ko
+drivers/scsi/device_handler/scsi_dh_alua.ko
+drivers/scsi/device_handler/scsi_dh_rdac.ko
+drivers/scsi/device_handler/scsi_dh_hp_sw.ko
+drivers/scsi/iscsi_boot_sysfs.ko
+drivers/scsi/iscsi_tcp.ko
+drivers/scsi/ipr.ko
+drivers/scsi/libiscsi.ko
+drivers/scsi/libiscsi_tcp.ko
+drivers/scsi/libsas/*
+drivers/scsi/lpfc/*
+drivers/scsi/megaraid/*
+drivers/scsi/mpt3sas/*
+drivers/scsi/osd/osd.ko
+drivers/scsi/osd/libosd.ko
+drivers/scsi/qla2xxx/*
+drivers/scsi/qla1280.ko
+drivers/scsi/raid_class.ko
+drivers/scsi/scsi_transport_fc.ko
+drivers/scsi/scsi_transport_iscsi.ko
+drivers/scsi/scsi_transport_sas.ko
+drivers/scsi/vmw_pvscsi.ko
+drivers/scsi/hv_storvsc.ko
+drivers/scsi/virtio_scsi.ko
+drivers/scsi/ibmvscsi/*
+drivers/target/target_core*.ko
+drivers/tty/serial/jsm/*
+drivers/uio/uio.ko
+drivers/uio/uio_pdrv_genirq.ko
+drivers/usb/host/*
+drivers/usb/storage/uas.ko
+drivers/usb/storage/usb-storage.ko
+drivers/vfio/*
+drivers/vhost/*
+drivers/video/fbdev/cirrusfb.ko
+drivers/video/fbdev/core/syscopyarea.ko
+drivers/video/fbdev/core/sysfillrect.ko
+drivers/video/fbdev/core/sysimgblt.ko
+drivers/video/fbdev/hyperv_fb.ko
+drivers/video/fbdev/vga16fb.ko
+drivers/video/vgastate.ko
+drivers/video/fbdev/xen-fbfront.ko
+drivers/video/fbdev/core/fb_sys_fops.ko
+drivers/watchdog/softdog.ko
+drivers/xen/*
+fs/9p/*
+fs/aufs/aufs.ko
+fs/binfmt_misc.ko
+fs/btrfs/*
+fs/cachefiles/cachefiles.ko
+fs/ceph/*
+fs/configfs/*
+fs/dlm/dlm.ko
+fs/exofs/libore.ko
+fs/fat/*
+fs/nls/nls_iso8859-1.ko
+fs/isofs/*
+fs/cifs/*
+fs/xfs/*
+fs/ufs/*
+fs/squashfs/*
+fs/nfs/*
+fs/nfsd/*
+fs/nfs_common/*
+fs/fscache/*
+fs/lockd/*
+fs/autofs4/autofs4.ko
+fs/overlayfs/*
+fs/udf/*
+lib/*
+net/6lowpan/*
+net/802/*
+net/8021q/*
+net/9p/*
+net/appletalk/*
+net/atm/*
+net/ax25/*
+net/bridge/*
+net/can/*
+net/core/*
+net/ceph/libceph.ko
+net/dccp/*
+net/decnet/*
+net/ieee802154/*
+net/ipv4/*
+net/ipv6/*
+net/ipx/*
+net/irda/*
+net/key/*
+net/lapb/*
+net/llc/*
+net/netfilter/*
+net/netlink/netlink_diag.ko
+net/netrom/*
+net/openvswitch/*
+net/packet/af_packet_diag.ko
+net/phonet/*
+net/rose/*
+net/rxrpc/*
+net/sched/*
+net/sctp/*
+net/tipc/*
+net/unix/unix_diag.ko
+net/vmw_vsock/*
+net/x25/*
+net/xfrm/*
+net/sunrpc/auth_gss/auth_rpcgss.ko
+net/sunrpc/auth_gss/rpcsec_gss_krb5.ko
+net/sunrpc/sunrpc.ko
+sound/soundcore.ko
+! find sound/core -name oss -prune -o -name *.ko -print
+sound/pci/snd-ens1370.ko
+sound/drivers/pcsp/snd-pcsp.ko
+ubuntu/vbox/vboxguest/vboxguest.ko
+ubuntu/vbox/vboxsf/vboxsf.ko
+zfs/*
--- linux-4.4.0.orig/debian.master/control.d/vars.generic
+++ linux-4.4.0/debian.master/control.d/vars.generic
@@ -0,0 +1,6 @@
+arch="amd64 arm64 s390x"
+supported="Generic"
+target="Geared toward desktop and server systems."
+desc="=HUMAN= SMP"
+bootloader="grub-pc [i386 amd64 x32] | grub-efi-amd64 [amd64 x32] | grub-efi-ia32 [i386 amd64 x32] | grub [i386 amd64 x32] | lilo [i386 amd64 x32] | flash-kernel [armhf arm64] | grub-ieee1275 [ppc64el]"
+provides="kvm-api-4, redhat-cluster-modules, ivtv-modules, virtualbox-guest-modules [i386 amd64 x32]"
--- linux-4.4.0.orig/debian.master/control.d/vars.lowlatency
+++ linux-4.4.0/debian.master/control.d/vars.lowlatency
@@ -0,0 +1,6 @@
+arch="amd64"
+supported="Lowlatency"
+target="Geared toward desktop and server systems."
+desc="=HUMAN= SMP"
+bootloader="grub-pc [i386 amd64 x32] | grub-efi-amd64 [amd64 x32] | grub-efi-ia32 [i386 amd64 x32] | grub [i386 amd64 x32] | lilo [i386 amd64 x32] | flash-kernel [armhf arm64]"
+provides="kvm-api-4, redhat-cluster-modules, ivtv-modules, virtualbox-guest-modules [i386 amd64 x32]"
--- linux-4.4.0.orig/debian.master/control.stub.in
+++ linux-4.4.0/debian.master/control.stub.in
@@ -0,0 +1,191 @@
+Source: linux
+Section: devel
+Priority: optional
+Maintainer: Ubuntu Kernel Team <kernel-team@lists.ubuntu.com>
+Standards-Version: 3.9.4.0
+Build-Depends:
+ debhelper (>= 9),
+ dh-systemd,
+ cpio,
+ kernel-wedge,
+ kmod <!stage1>,
+ makedumpfile [amd64 i386] <!stage1>,
+ libelf-dev <!stage1>,
+ libnewt-dev <!stage1>,
+ libiberty-dev <!stage1>,
+ rsync <!stage1>,
+ libdw-dev <!stage1>,
+ libpci-dev <!stage1>,
+ pkg-config <!stage1>,
+ flex <!stage1>,
+ bison <!stage1>,
+ libunwind8-dev [amd64 arm64 armhf i386 powerpc ppc64el] <!stage1>,
+ binutils-dev <!stage1>,
+ liblzma-dev <!stage1>,
+ openssl <!stage1>,
+ libssl-dev <!stage1>,
+ libaudit-dev <!stage1>,
+ bc <!stage1>,
+ python-dev <!stage1>,
+ gawk <!stage1>,
+ device-tree-compiler [powerpc] <!stage1>,
+ u-boot-tools [powerpc] <!stage1>,
+ libc6-dev-ppc64 [powerpc] <!stage1>,
+ libudev-dev <!stage1>,
+ autoconf <!stage1>,
+ automake <!stage1>,
+ libtool <!stage1>,
+ uuid-dev <!stage1>,
+ dkms <!stage1>,
+ curl <!stage1>,
+Build-Depends-Indep:
+ xmlto <!stage1>,
+ docbook-utils <!stage1>,
+ ghostscript <!stage1>,
+ transfig <!stage1>,
+ bzip2 <!stage1>,
+ sharutils <!stage1>,
+ asciidoc <!stage1>,
+Vcs-Git: git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/xenial
+XS-Testsuite: autopkgtest
+#XS-Testsuite-Depends: gcc-4.7 binutils
+
+Package: linux-source-PKGVER
+Build-Profiles: <!stage1>
+Architecture: all
+Section: devel
+Priority: optional
+Provides: linux-source, linux-source-3
+Depends: ${misc:Depends}, binutils, bzip2, coreutils
+Recommends: libc-dev, gcc, make
+Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-dev
+Description: Linux kernel source for version PKGVER with Ubuntu patches
+ This package provides the source code for the Linux kernel version
+ PKGVER.
+ .
+ This package is mainly meant for other packages to use, in order to build
+ custom flavours.
+ .
+ If you wish to use this package to create a custom Linux kernel, then it
+ is suggested that you investigate the package kernel-package, which has
+ been designed to ease the task of creating kernel image packages.
+ .
+ If you are simply trying to build third-party modules for your kernel,
+ you do not want this package. Install the appropriate linux-headers
+ package instead.
+
+Package: SRCPKGNAME-doc
+Build-Profiles: <!stage1>
+Architecture: all
+Section: doc
+Priority: optional
+Depends: ${misc:Depends}
+Description: Linux kernel specific documentation for version PKGVER
+ This package provides the various documents in the PKGVER kernel
+ Documentation/ subdirectory.  These document kernel subsystems, APIs, device
+ drivers, and so on.  See
+ /usr/share/doc/SRCPKGNAME-doc/00-INDEX for a list of what is
+ contained in each file.
+
+Package: SRCPKGNAME-headers-PKGVER-ABINUM
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, coreutils
+Breaks: iscsitarget-dkms (<< 1.4.20.3+svn502-2ubuntu4.3)
+Description: Header files related to Linux kernel version PKGVER
+ This package provides kernel header files for version PKGVER, for sites
+ that want the latest kernel headers. Please read
+ /usr/share/doc/SRCPKGNAME-headers-PKGVER-ABINUM/debian.README.gz for details
+
+Package: SRCPKGNAME-libc-dev
+Architecture: amd64 arm64 s390x
+Depends: ${misc:Depends}
+Conflicts: SRCPKGNAME-kernel-headers
+Replaces: SRCPKGNAME-kernel-headers
+Provides: SRCPKGNAME-kernel-headers
+Multi-Arch: same
+Description: Linux Kernel Headers for development
+ This package provides headers from the Linux kernel.  These headers
+ are used by the installed headers for GNU glibc and other system
+ libraries. They are NOT meant to be used to build third-party modules for
+ your kernel. Use SRCPKGNAME-headers-* packages for that.
+
+Package: SRCPKGNAME-tools-common
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: kernel
+Priority: optional
+Provides:
+ linux-aws-tools-common,
+ linux-gke-tools-common,
+Conflicts:
+ linux-aws-tools-common,
+ linux-gke-tools-common,
+Replaces:
+ linux-aws-tools-common,
+ linux-gke-tools-common,
+Depends: ${misc:Depends}, lsb-release
+Description: Linux kernel version specific tools for version PKGVER
+ This package provides the architecture independent parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version PKGVER.
+
+Package: SRCPKGNAME-tools-PKGVER-ABINUM
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, SRCPKGNAME-tools-common
+Description: Linux kernel version specific tools for version PKGVER-ABINUM
+ This package provides the architecture dependant parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version PKGVER-ABINUM on
+ =HUMAN=.
+ You probably want to install linux-tools-PKGVER-ABINUM-<flavour>.
+
+Package: SRCPKGNAME-cloud-tools-common
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: kernel
+Priority: optional
+Provides:
+ linux-aws-cloud-tools-common,
+ linux-gke-cloud-tools-common,
+Conflicts:
+ linux-aws-cloud-tools-common,
+ linux-gke-cloud-tools-common,
+Replaces:
+ linux-aws-cloud-tools-common,
+ linux-gke-cloud-tools-common,
+Depends: ${misc:Depends}
+Description: Linux kernel version specific cloud tools for version PKGVER
+ This package provides the architecture independent parts for kernel
+ version locked tools for cloud tools for version PKGVER.
+
+Package: SRCPKGNAME-cloud-tools-PKGVER-ABINUM
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, SRCPKGNAME-cloud-tools-common
+Description: Linux kernel version specific cloud tools for version PKGVER-ABINUM
+ This package provides the architecture dependant parts for kernel
+ version locked tools for cloud tools for version PKGVER-ABINUM on
+ =HUMAN=.
+ You probably want to install linux-cloud-tools-PKGVER-ABINUM-<flavour>.
+
+Package: SRCPKGNAME-tools-host
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, python3
+Description: Linux kernel VM host tools
+ This package provides kernel tools useful for VM hosts.
+
--- linux-4.4.0.orig/debian.master/copyright
+++ linux-4.4.0/debian.master/copyright
@@ -0,0 +1,60 @@
+This is the Ubuntu prepackaged version of the Linux kernel.
+Linux was written by Linus Torvalds <Linus.Torvalds@cs.Helsinki.FI>
+and others.
+
+This package was put together by the Ubuntu Kernel Team, from
+sources retrieved from upstream linux git.
+The sources may be found at most Linux ftp sites, including 
+ftp://ftp.kernel.org/pub/linux/kernel/
+
+This package is currently maintained by the
+Ubuntu Kernel Team <ubuntu-kernel@lists.ubuntu.com>
+
+Linux is copyrighted by Linus Torvalds and others.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 dated June, 1991.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You 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
+
+On Ubuntu Linux systems, the complete text of the GNU General
+Public License v2 can be found in `/usr/share/common-licenses/GPL-2'.
+
+Files: ubuntu/rsi/*
+Copyright (c) 2017 Redpine Signals Inc. All rights reserved.
+License: redpine-signals
+   Copyright (c) 2017 Redpine Signals Inc. All rights reserved.
+   
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+   
+   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.
+   
+   3. Neither the name of the copyright holder 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 HOLDER 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.
--- linux-4.4.0.orig/debian.master/d-i/exclude-firmware.armhf-generic
+++ linux-4.4.0/debian.master/d-i/exclude-firmware.armhf-generic
@@ -0,0 +1,2 @@
+nic-modules
+scsi-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-firmware.armhf-generic-lpae
+++ linux-4.4.0/debian.master/d-i/exclude-firmware.armhf-generic-lpae
@@ -0,0 +1,2 @@
+nic-modules
+scsi-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-modules.amd64-virtual
+++ linux-4.4.0/debian.master/d-i/exclude-modules.amd64-virtual
@@ -0,0 +1,14 @@
+pata-modules
+firewire-core-modules
+plip-modules
+usb-modules
+pcmcia-storage-modules
+input-modules
+nic-pcmcia-modules
+pcmcia-modules
+nic-usb-modules
+nfs-modules
+speakup-modules
+ppp-modules
+sata-modules
+ipmi-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-modules.arm64-generic
+++ linux-4.4.0/debian.master/d-i/exclude-modules.arm64-generic
@@ -0,0 +1,9 @@
+serial-modules
+pata-modules
+firewire-core-modules
+floppy-modules
+pcmcia-storage-modules
+fb-modules
+nic-pcmcia-modules
+pcmcia-modules
+message-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-modules.armhf-generic
+++ linux-4.4.0/debian.master/d-i/exclude-modules.armhf-generic
@@ -0,0 +1,10 @@
+serial-modules
+firewire-core-modules
+floppy-modules
+pcmcia-storage-modules
+fb-modules
+nic-pcmcia-modules
+pcmcia-modules
+pata-modules
+message-modules
+virtio-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-modules.armhf-generic-lpae
+++ linux-4.4.0/debian.master/d-i/exclude-modules.armhf-generic-lpae
@@ -0,0 +1,10 @@
+serial-modules
+firewire-core-modules
+floppy-modules
+pcmcia-storage-modules
+fb-modules
+nic-pcmcia-modules
+pcmcia-modules
+pata-modules
+message-modules
+virtio-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-modules.i386-virtual
+++ linux-4.4.0/debian.master/d-i/exclude-modules.i386-virtual
@@ -0,0 +1,14 @@
+pata-modules
+firewire-core-modules
+plip-modules
+usb-modules
+pcmcia-storage-modules
+input-modules
+nic-pcmcia-modules
+pcmcia-modules
+nic-usb-modules
+nfs-modules
+speakup-modules
+ppp-modules
+sata-modules
+ipmi-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-modules.powerpc
+++ linux-4.4.0/debian.master/d-i/exclude-modules.powerpc
@@ -0,0 +1,7 @@
+efi-modules
+fb-modules
+acpi-modules
+serial-modules
+nic-pcmcia-modules
+pcmcia-modules
+pcmcia-storage-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-modules.ppc64el-generic
+++ linux-4.4.0/debian.master/d-i/exclude-modules.ppc64el-generic
@@ -0,0 +1,11 @@
+serial-modules
+pata-modules
+fat-modules
+pcmcia-storage-modules
+nic-pcmcia-modules
+pcmcia-modules
+firewire-core-modules
+usb-modules
+mouse-modules
+irda-modules
+speakup-modules
--- linux-4.4.0.orig/debian.master/d-i/exclude-modules.s390x
+++ linux-4.4.0/debian.master/d-i/exclude-modules.s390x
@@ -0,0 +1,20 @@
+serial-modules
+ppp-modules
+pata-modules
+plip-modules
+floppy-modules
+pcmcia-storage-modules
+fb-modules
+mouse-modules
+irda-modules
+nic-pcmcia-modules
+pcmcia-modules
+sata-modules
+speakup-modules
+ipmi-modules
+usb-modules
+input-modules
+parport-modules
+nic-usb-modules
+firewire-core-modules
+message-modules
--- linux-4.4.0.orig/debian.master/d-i/firmware/README.txt
+++ linux-4.4.0/debian.master/d-i/firmware/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-4.4.0.orig/debian.master/d-i/firmware/nic-modules
+++ linux-4.4.0/debian.master/d-i/firmware/nic-modules
@@ -0,0 +1,14 @@
+e100/d101m_ucode.bin ?
+e100/d101s_ucode.bin ?
+e100/d102e_ucode.bin ?
+bnx2/bnx2-mips-09-6.2.1b.fw ?
+bnx2/bnx2-rv2p-06-6.0.15.fw ?
+bnx2/bnx2-mips-06-6.2.3.fw ?
+bnx2/bnx2-rv2p-09-6.0.17.fw ?
+bnx2/bnx2-rv2p-09ax-6.0.17.fw ?
+bnx2x/bnx2x-e1h-7.12.30.0.fw ?
+bnx2x/bnx2x-e1-7.12.30.0.fw ?
+bnx2x/bnx2x-e2-7.12.30.0.fw ?
+tigon/tg3_tso5.bin ?
+tigon/tg3_tso.bin ?
+tigon/tg3.bin ?
--- linux-4.4.0.orig/debian.master/d-i/firmware/scsi-modules
+++ linux-4.4.0/debian.master/d-i/firmware/scsi-modules
@@ -0,0 +1,3 @@
+qlogic/1040.bin ?
+qlogic/12160.bin ?
+qlogic/1280.bin ?
--- linux-4.4.0.orig/debian.master/d-i/kernel-versions.in
+++ linux-4.4.0/debian.master/d-i/kernel-versions.in
@@ -0,0 +1,19 @@
+# arch	version		flavour		installedname			suffix	bdep
+amd64	PKGVER-ABINUM	generic		PKGVER-ABINUM-generic		-	-
+
+i386	PKGVER-ABINUM	generic		PKGVER-ABINUM-generic		-	-
+
+armhf	PKGVER-ABINUM	generic		PKGVER-ABINUM-generic		-	-
+armhf	PKGVER-ABINUM	generic-lpae	PKGVER-ABINUM-generic-lpae	-	-
+
+arm64	PKGVER-ABINUM	generic		PKGVER-ABINUM-generic		-	-
+
+ppc64el	PKGVER-ABINUM	generic		PKGVER-ABINUM-generic		-	-
+
+s390x	PKGVER-ABINUM	generic		PKGVER-ABINUM-generic		-	-
+
+# Ports
+# arch	version		flavour		installedname			suffix	bdep
+powerpc	PKGVER-ABINUM	powerpc-smp	PKGVER-ABINUM-powerpc-smp	-	-
+powerpc	PKGVER-ABINUM	powerpc64-smp	PKGVER-ABINUM-powerpc64-smp	-	-
+powerpc PKGVER-ABINUM	powerpc-e500mc	PKGVER-ABINUM-powerpc-e500mc	-	-
--- linux-4.4.0.orig/debian.master/d-i/modules-powerpc/block-modules
+++ linux-4.4.0/debian.master/d-i/modules-powerpc/block-modules
@@ -0,0 +1,31 @@
+aoe
+aten
+bpck
+bpck6 ?
+cciss
+comm
+cpqarray ?
+DAC960
+dstr
+epat
+epia
+fit2
+fit3
+friq
+frpw
+kbic
+ktti
+nbd
+on20
+on26
+paride
+pcd
+pd
+pf
+pg
+ps3disk ?
+ps3vram ?
+pt
+sx8
+umem
+virtio_blk ?
--- linux-4.4.0.orig/debian.master/d-i/modules-powerpc/message-modules
+++ linux-4.4.0/debian.master/d-i/modules-powerpc/message-modules
@@ -0,0 +1,7 @@
+mptbase
+mptctl
+mptfc
+mptlan
+mptsas
+mptscsih
+mptspi
--- linux-4.4.0.orig/debian.master/d-i/modules-powerpc/nic-modules
+++ linux-4.4.0/debian.master/d-i/modules-powerpc/nic-modules
@@ -0,0 +1,152 @@
+3c359 ?
+3c501 ?
+3c503 ?
+3c505 ?
+3c507 ?
+3c509 ?
+3c515 ?
+3c523 ?
+3c527 ?
+3c59x ?
+8139cp ?
+8139too ?
+82596 ?
+abyss ?
+ac3200 ?
+adm8211 ?
+airo ?
+airport ?
+amd8111e ?
+arc4 ?
+arcnet ?
+arc-rawmode ?
+arc-rimi ?
+arlan ?
+at1700 ?
+atl1 ?
+atl1e ?
+atl2 ?
+atmel ?
+atmel_pci ?
+b44 ?
+bcm43xx ?
+bcm43xx-mac80211 ?
+bmac ?
+bnx2 ?
+bnx2x ?
+bonding ?
+cassini ?
+com20020 ?
+com20020-pci ?
+com90io ?
+com90xx ?
+cs89x0 ?
+de2104x ?
+de4x5 ?
+de600 ?
+de620 ?
+defxx ?
+depca ?
+dl2k ?
+dmfe ?
+dummy ?
+e100 ?
+e1000 ?
+e1000e ?
+e2100 ?
+eepro ?
+eepro100 ?
+eexpress ?
+epic100 ?
+eql ?
+es3210 ?
+eth16i ?
+ewrk3 ?
+fealnx ?
+forcedeth ?
+igb ?
+hamachi ?
+hermes ?
+hp ?
+hp100 ?
+hp-plus ?
+ibmtr ?
+ibmveth ?
+ipddp ?
+ipw2100 ?
+ipw2200 ?
+ipw3945 ?
+ixgb ?
+lance ?
+lanstreamer ?
+lasi_82596 ?
+lne390 ?
+lp486e ?
+mace ?
+mv643xx_eth ?
+myri_sbus ?
+natsemi ?
+ne ?
+ne2 ?
+ne2k-pci ?
+ne3210 ?
+netconsole ?
+netxen_nic ?
+ni5010 ?
+ni52 ?
+ni65 ?
+niu ?
+ns83820 ?
+olympic ?
+orinoco ?
+orinoco_pci ?
+orinoco_plx ?
+orinoco_tmd ?
+pcnet32 ?
+ps3_gelic ?
+r8169 ?
+rate_control ?
+rfc1051 ?
+rfc1201 ?
+rrunner ?
+rt2400 ?
+rt2500 ?
+rt61pci ?
+s2io ?
+shaper ?
+sis190 ?
+sis900 ?
+spidernet ?
+skfp ?
+skge ?
+sk98lin ?
+sky2 ?
+smc9194 ?
+smc-ultra ?
+smc-ultra32 ?
+starfire ?
+strip ?
+sunbmac ?
+sundance ?
+sungem ?
+sungem_phy ?
+sunhme ?
+sunlance ?
+sunqe ?
+sunvnet ?
+tg3 ?
+tlan ?
+tms380tr ?
+tmspci ?
+tulip ?
+tun ?
+typhoon ?
+uli526x ?
+via-rhine ?
+via-velocity ?
+virtio_net ?
+wavelan ?
+wd ?
+winbond-840 ?
+yellowfin ?
+znet ?
--- linux-4.4.0.orig/debian.master/d-i/modules-powerpc/scsi-modules
+++ linux-4.4.0/debian.master/d-i/modules-powerpc/scsi-modules
@@ -0,0 +1,118 @@
+# SCSI
+raid_class ?
+scsi_transport_spi ?
+scsi_transport_fc ?
+scsi_transport_iscsi ?
+scsi_transport_sas ?
+iscsi_tcp ?
+libiscsi ?
+amiga7xx ?
+a3000 ?
+a2091 ?
+gvp11 ?
+mvme147 ?
+sgiwd93 ?
+cyberstorm ?
+cyberstormII ?
+blz2060 ?
+blz1230 ?
+fastlane ?
+oktagon_esp_mod ?
+atari_scsi ?
+mac_scsi ?
+mac_esp ?
+sun3_scsi ?
+mvme16x ?
+bvme6000 ?
+sim710 ?
+advansys ?
+psi240i ?
+BusLogic ?
+dpt_i2o ?
+u14-34f ?
+ultrastor ?
+aha152x ?
+aha1542 ?
+aha1740 ?
+aic7xxx_old ?
+ips ?
+fd_mcs ?
+fdomain ?
+in2000 ?
+g_NCR5380 ?
+g_NCR5380_mmio ?
+NCR53c406a ?
+NCR_D700 ?
+NCR_Q720_mod ?
+sym53c416 ?
+qlogicfas408 ?
+qla1280 ?
+pas16 ?
+seagate ?
+seagate ?
+t128 ?
+dmx3191d ?
+dtc ?
+zalon7xx ?
+eata_pio ?
+wd7000 ?
+mca_53c9x ?
+ibmmca ?
+ibmvfc ?
+ibmvscsi ?
+eata ?
+dc395x ?
+tmscsim ?
+megaraid ?
+atp870u ?
+esp ?
+gdth ?
+initio ?
+a100u2w ?
+qlogicpti ?
+ide-scsi ?
+mesh ?
+mac53c94 ?
+pluto ?
+dec_esp ?
+3w-xxxx ?
+3w-9xxx ?
+ppa ?
+imm ?
+jazz_esp ?
+sun3x_esp ?
+fcal ?
+lasi700 ?
+nsp32 ?
+ipr ?
+hptiop ?
+stex ?
+osst ?
+sg ?
+ch ?
+scsi_debug ?
+aacraid ?
+aic7xxx ?
+aic79xx ?
+aic94xx ?
+arcmsr ?
+acornscsi_mod ?
+arxescsi ?
+cumana_1 ?
+cumana_2 ?
+ecoscsi ?
+oak ?
+powertec ?
+eesox ?
+ibmvscsic ?
+libsas ?
+lpfc ?
+megaraid_mm ?
+megaraid_mbox ?
+megaraid_sas ?
+qla2xxx ?
+sym53c8xx ?
+qla4xxx ?
+mvsas ?
+sr_mod ?
+sd_mod ?
--- linux-4.4.0.orig/debian.master/d-i/modules-powerpc/storage-core-modules
+++ linux-4.4.0/debian.master/d-i/modules-powerpc/storage-core-modules
@@ -0,0 +1,13 @@
+# Core stacks
+usb-storage ?
+
+# Block level
+
+# Loop modules
+cryptoloop
+
+# Needs to be here for better cdrom initrd layout
+isofs
+
+ps3stor_lib ?
+ps3rom ?
--- linux-4.4.0.orig/debian.master/d-i/modules-s390x/dasd-extra-modules
+++ linux-4.4.0/debian.master/d-i/modules-s390x/dasd-extra-modules
@@ -0,0 +1 @@
+dasd_diag_mod ?
--- linux-4.4.0.orig/debian.master/d-i/modules-s390x/dasd-modules
+++ linux-4.4.0/debian.master/d-i/modules-s390x/dasd-modules
@@ -0,0 +1,3 @@
+dasd_mod ?
+dasd_fba_mod ?
+dasd_eckd_mod ?
--- linux-4.4.0.orig/debian.master/d-i/modules/block-modules
+++ linux-4.4.0/debian.master/d-i/modules/block-modules
@@ -0,0 +1,42 @@
+aoe ?
+aten ?
+bpck ?
+bpck6 ?
+cciss ?
+comm ?
+cpqarray ?
+DAC960 ?
+dstr ?
+epat ?
+epia ?
+fit2 ?
+fit3 ?
+friq ?
+frpw ?
+hpsa ?
+hio ?
+kbic ?
+ktti ?
+nbd ?
+nvme ?
+on20 ?
+on26 ?
+paride ?
+pcd ?
+pd ?
+pf ?
+pg ?
+pt ?
+sdhci-tegra ?
+sx8 ?
+umem ?
+virtio_blk ?
+xen-blkfront ?
+mtip32xx ?
+mmc_block ?
+sdhci ?
+sdhci-pci ?
+sdhci-acpi ?
+tifm_sd ?
+dw_mmc ?
+dw_mmc_pltfm ?
--- linux-4.4.0.orig/debian.master/d-i/modules/crypto-modules
+++ linux-4.4.0/debian.master/d-i/modules/crypto-modules
@@ -0,0 +1,70 @@
+aesni-intel ?
+aes-x86_64 ?
+af_alg ?
+algif_hash ?
+algif_skcipher ?
+ansi_cprng ?
+anubis ?
+arc4 ?
+async_memcpy ?
+async_pq ?
+async_raid6_recov ?
+async_tx ?
+async_xor ?
+authenc ?
+authencesn ?
+blowfish_common ?
+blowfish_generic ?
+blowfish-x86_64 ?
+camellia ?
+cast5 ?
+cast6 ?
+ccm ?
+cryptd ?
+cryptoloop ?
+crypto_null ?
+crypto_user ?
+ctr ?
+cts ?
+deflate ?
+des_generic ?
+fcrypt ?
+gcm ?
+gf128mul ?
+ghash-clmulni-intel ?
+ghash-generic ?
+khazad ?
+lrw ?
+lzo ?
+md4 ?
+michael_mic ?
+padlock-aes ?
+padlock-sha ?
+pcbc ?
+pcrypt ?
+raid6test ?
+rmd128 ?
+rmd160 ?
+rmd256 ?
+rmd320 ?
+salsa20_generic ?
+salsa20-x86_64 ?
+seed ?
+seqiv ?
+serpent_generic ?
+serpent-sse2-x86_64 ?
+sha1-ssse3 ?
+sha512_generic ?
+tcrypt ?
+tea ?
+tgr192 ?
+twofish_common ?
+twofish_generic ?
+twofish-x86_64 ?
+twofish-x86_64-3way ?
+vmac ?
+wp512 ?
+xcbc ?
+xor ?
+xts ?
+zlib ?
--- linux-4.4.0.orig/debian.master/d-i/modules/fat-modules
+++ linux-4.4.0/debian.master/d-i/modules/fat-modules
@@ -0,0 +1,7 @@
+fat ?
+vfat ?
+
+# Supporting modules ?
+nls_cp437 ?
+nls_iso8859-1 ?
+nls_utf8 ?
--- linux-4.4.0.orig/debian.master/d-i/modules/fb-modules
+++ linux-4.4.0/debian.master/d-i/modules/fb-modules
@@ -0,0 +1,3 @@
+fbcon ?
+vesafb ?
+vga16fb ?
--- linux-4.4.0.orig/debian.master/d-i/modules/firewire-core-modules
+++ linux-4.4.0/debian.master/d-i/modules/firewire-core-modules
@@ -0,0 +1,4 @@
+firewire-core ?
+firewire-ohci ?
+firewire-sbp2 ?
+firewire-net ?
--- linux-4.4.0.orig/debian.master/d-i/modules/floppy-modules
+++ linux-4.4.0/debian.master/d-i/modules/floppy-modules
@@ -0,0 +1 @@
+floppy ?
--- linux-4.4.0.orig/debian.master/d-i/modules/fs-core-modules
+++ linux-4.4.0/debian.master/d-i/modules/fs-core-modules
@@ -0,0 +1,5 @@
+ext2 ?
+jfs ?
+reiserfs ?
+xfs ?
+zfs ?
--- linux-4.4.0.orig/debian.master/d-i/modules/fs-secondary-modules
+++ linux-4.4.0/debian.master/d-i/modules/fs-secondary-modules
@@ -0,0 +1,5 @@
+btrfs ?
+fuse ?
+ntfs ?
+hfs ?
+hfsplus ?
--- linux-4.4.0.orig/debian.master/d-i/modules/input-modules
+++ linux-4.4.0/debian.master/d-i/modules/input-modules
@@ -0,0 +1,71 @@
+hid ?
+hid-a4tech ?
+hid-apple ?
+hid-appleir ?
+hid-aureal ?
+hid-belkin ?
+hid-bright ?
+hid-cherry ?
+hid-chicony ?
+hid-corsair ?
+hid-cp2112 ?
+hid-cypress ?
+hid-dell ?
+hid-elecom ?
+hid-elo ?
+hid-ezkey ?
+hid-generic ?
+hid-gfrm ?
+hid-gt683r ?
+hid-gyration ?
+hid-holtek-kbd ?
+hid-holtek-mouse ?
+hid-hyperv ?
+hid-kensington ?
+hid-keytouch ?
+hid-kye ?
+hid-lcpower ?
+hid-lenovo ?
+hid-logitech ?
+hid-logitech-dj ?
+hid-logitech-hidpp ?
+hid-magicmouse ?
+hid-microsoft ?
+hid-monterey ?
+hid-multitouch ?
+hid-ntrig ?
+hid-ortek ?
+hid-penmount ?
+hid-petalynx ?
+hid-picolcd ?
+hid-pl ?
+hid-plantronics ?
+hid-primax ?
+hid-rmi ?
+hid-roccat ?
+hid-roccat-arvo ?
+hid-roccat-common ?
+hid-roccat-isku ?
+hid-roccat-kone ?
+hid-roccat-koneplus ?
+hid-roccat-konepure ?
+hid-roccat-kovaplus ?
+hid-roccat-lua ?
+hid-roccat-pyra ?
+hid-roccat-ryos ?
+hid-roccat-savu ?
+hid-samsung ?
+hid-sony ?
+hid-speedlink ?
+hid-sunplus ?
+hid-thingm ?
+hid-tivo ?
+hid-topseed ?
+hid-twinhan ?
+hid-uclogic ?
+hid-waltop ?
+hid-wiimote ?
+hid-xinmo ?
+hid-zydacron ?
+uhid ?
+usbhid ?
--- linux-4.4.0.orig/debian.master/d-i/modules/ipmi-modules
+++ linux-4.4.0/debian.master/d-i/modules/ipmi-modules
@@ -0,0 +1,5 @@
+ipmi_devintf ?
+ipmi_msghandler ?
+ipmi_poweroff ?
+ipmi_si ?
+ipmi_watchdog ?
--- linux-4.4.0.orig/debian.master/d-i/modules/irda-modules
+++ linux-4.4.0/debian.master/d-i/modules/irda-modules
@@ -0,0 +1,30 @@
+act200l-sir ?
+actisys-sir ?
+ali-ircc ?
+donauboe ?
+esi-sir ?
+girbil-sir ?
+ircomm ?
+ircomm-tty ?
+irda ?
+irda-usb ?
+irlan ?
+irnet ?
+irport ?
+irtty-sir ?
+kingsun-sir ?
+ks959-sir ?
+ksdazzle-sir ?
+litelink-sir ?
+ma600-sir ?
+mcp2120-sir ?
+mcs7780 ?
+nsc-ircc ?
+old_belkin-sir ?
+sir-dev ?
+smsc-ircc2 ?
+stir4200 ?
+tekram-sir ?
+via-ircc ?
+vlsi_ir ?
+w83977af_ir ?
--- linux-4.4.0.orig/debian.master/d-i/modules/kernel-image
+++ linux-4.4.0/debian.master/d-i/modules/kernel-image
@@ -0,0 +1,30 @@
+ast ?
+gpio-pca953x ?
+gpio-regulator ?
+i2c-mux ?
+i2c-mux-pinctrl ?
+i2c-tegra ?
+max8907 ?
+max8907-regulator ?
+nvec ?
+nvec_kbd ?
+nvec_paz00 ?
+nvec_power ?
+nvec_ps2 ?
+palmas-regulator ?
+rtc-em3027 ?
+rtc-max8907 ?
+rtc-palmas ?
+rtc-tps6586x ?
+rtc-tps65910 ?
+tps51632-regulator ?
+tps62360-regulator ?
+tps65090-charger ?
+tps65090-regulator ?
+tps6586x-regulator ?
+tps65910-regulator ?
+host1x ?
+tegra-drm ?
+pwm_bl ?
+pwm-tegra ?
+panel-simple ?
--- linux-4.4.0.orig/debian.master/d-i/modules/md-modules
+++ linux-4.4.0/debian.master/d-i/modules/md-modules
@@ -0,0 +1,16 @@
+dm-crypt ?
+dm-mirror ?
+dm-raid ?
+dm-snapshot ?
+dm-zero ?
+faulty ?
+linear ?
+multipath ?
+raid0 ?
+raid1 ?
+raid10 ?
+raid456 ?
+
+# Extras
+dm-raid45 ?
+dm-loop ?
--- linux-4.4.0.orig/debian.master/d-i/modules/message-modules
+++ linux-4.4.0/debian.master/d-i/modules/message-modules
@@ -0,0 +1,9 @@
+mptbase ?
+mptctl ?
+mptfc ?
+mptlan ?
+mptsas ?
+mpt2sas ?
+mpt3sas ?
+mptscsih ?
+mptspi ?
--- linux-4.4.0.orig/debian.master/d-i/modules/mouse-modules
+++ linux-4.4.0/debian.master/d-i/modules/mouse-modules
@@ -0,0 +1,2 @@
+psmouse ?
+usbmouse ?
--- linux-4.4.0.orig/debian.master/d-i/modules/multipath-modules
+++ linux-4.4.0/debian.master/d-i/modules/multipath-modules
@@ -0,0 +1,4 @@
+dm-multipath ?
+dm-round-robin ?
+dm-service-time ?
+dm-queue-length ?
--- linux-4.4.0.orig/debian.master/d-i/modules/nfs-modules
+++ linux-4.4.0/debian.master/d-i/modules/nfs-modules
@@ -0,0 +1,6 @@
+nfs ?
+nfs_acl ?
+nfsv3 ?
+lockd ?
+sunrpc ?
+cifs ?
--- linux-4.4.0.orig/debian.master/d-i/modules/nic-modules
+++ linux-4.4.0/debian.master/d-i/modules/nic-modules
@@ -0,0 +1,199 @@
+3c359 ?
+3c501 ?
+3c503 ?
+3c505 ?
+3c507 ?
+3c509 ?
+3c515 ?
+3c523 ?
+3c527 ?
+3c59x ?
+8139cp ?
+8139too ?
+82596 ?
+abyss ?
+ac3200 ?
+adm8211 ?
+airo ?
+airport ?
+alx ?
+amd8111e ?
+amd-xgbe ?
+aquantia ?
+arcnet ?
+arc-rawmode ?
+arc-rimi ?
+arlan ?
+at1700 ?
+ath5k ?
+ath9k ?
+ath9k_htc ?
+atl1 ?
+atl1c ?
+atl1e ?
+atl2 ?
+atmel ?
+atmel_pci ?
+b44 ?
+bcm87xx ?
+be2net ?
+bmac ?
+bnx2 ?
+bnx2x ?
+bnxt_en ?
+bnxt_en_bpo ?
+bonding ?
+brcmfmac ?
+brcmsmac ?
+broadcom ?
+xgmac ?
+cassini ?
+ccwgroup ?
+com20020 ?
+com20020-pci ?
+com90io ?
+com90xx ?
+cs89x0 ?
+ctcm ?
+de2104x ?
+de4x5 ?
+de600 ?
+de620 ?
+defxx ?
+depca ?
+dl2k ?
+dmfe ?
+dummy ?
+e100 ?
+e1000 ?
+e1000e ?
+e2100 ?
+eepro ?
+eepro100 ?
+eexpress ?
+enic ?
+epic100 ?
+eql ?
+es3210 ?
+eth16i ?
+ewrk3 ?
+fealnx ?
+forcedeth ?
+fsm ?
+ibmveth ?
+igb ?
+ps3_gelic ?
+hamachi ?
+hermes ?
+hp ?
+hp100 ?
+hp-plus ?
+i40e ?
+i40evf ?
+ibmtr ?
+ipddp ?
+ipw2100 ?
+ipw2200 ?
+iwl3945 ?
+iwl4965 ?
+iwl-legacy ?
+iwldvm ?
+iwlmvm ?
+iwlwifi ?
+ixgb ?
+ixgbe ?
+lance ?
+lanstreamer ?
+lcs ?
+lasi_82596 ?
+lne390 ?
+lp486e ?
+mace ?
+marvell ?
+mdio-thunder ?
+mlx4_core ?
+mlx4_en ?
+mlx5_core ?
+mv643xx_eth ?
+myri_sbus ?
+natsemi ?
+ne ?
+ne2 ?
+ne2k-pci ?
+ne3210 ?
+netconsole ?
+netiucv ?
+netxen_nic ?
+ni5010 ?
+ni52 ?
+ni65 ?
+nicpf ?
+nicvf ?
+niu ?
+ns83820 ?
+olympic ?
+orinoco ?
+orinoco_pci ?
+orinoco_plx ?
+orinoco_tmd ?
+pcnet32 ?
+qede ?
+qeth ?
+qeth_l2 ?
+qeth_l3 ?
+qlcnic ?
+r815x ?
+r8169 ?
+rate_control ?
+realtek ?
+rfc1051 ?
+rfc1201 ?
+rrunner ?
+rt2400 ?
+rt2400pci ?
+rt2500 ?
+rt2500pci ?
+rt2800pci ?
+rt61pci ?
+s2io ?
+sfc ?
+shaper ?
+sis190 ?
+sis900 ?
+spidernet ?
+skfp ?
+skge ?
+sk98lin ?
+sky2 ?
+smc9194 ?
+smc-ultra ?
+smc-ultra32 ?
+starfire ?
+strip ?
+sunbmac ?
+sundance ?
+sungem ?
+sungem_phy ?
+sunhme ?
+sunlance ?
+sunqe ?
+sunvnet ?
+tg3 ?
+tlan ?
+tms380tr ?
+tmspci ?
+tulip ?
+tun ?
+typhoon ?
+uli526x ?
+via-rhine ?
+via-velocity ?
+virtio_net ?
+wavelan ?
+wd ?
+winbond-840 ?
+yellowfin ?
+znet ?
+vmxnet3 ?
+xen-netfront ?
+xgene-enet ?
--- linux-4.4.0.orig/debian.master/d-i/modules/nic-pcmcia-modules
+++ linux-4.4.0/debian.master/d-i/modules/nic-pcmcia-modules
@@ -0,0 +1,19 @@
+3c574_cs ?
+3c589_cs ?
+airo_cs ?
+atmel_cs ?
+axnet_cs ?
+com20020_cs ?
+fmvj18x_cs ?
+ibmtr_cs ?
+netwave_cs ?
+nmclan_cs ?
+orinoco_cs ?
+pcnet_cs ?
+ray_cs ?
+smc91c92_cs ?
+wavelan_cs ?
+wl3501_cs ?
+xirc2ps_cs ?
+xircom_cb ?
+xircom_tulip_cb ?
--- linux-4.4.0.orig/debian.master/d-i/modules/nic-shared-modules
+++ linux-4.4.0/debian.master/d-i/modules/nic-shared-modules
@@ -0,0 +1,26 @@
+# PHY
+8390 ?
+mii ?
+
+# CRC modules
+crc-ccitt ?
+crc-itu-t ?
+libcrc32c ?
+
+# mac80211 stuff
+mac80211 ?
+cfg80211 ?
+
+# rt2x00 lib (since rt2x00 is split across usb/pci/cb
+rt2x00lib ?
+rt2800lib ?
+
+# Atheros library (since drivers are split across nic-modules/nic-usb-modules)
+ath ?
+
+# Wireless 802.11 modules
+lib80211 ?
+cfg80211 ?
+lib80211_crypt_ccmp ?
+lib80211_crypt_tkip ?
+lib80211_crypt_wep ?
--- linux-4.4.0.orig/debian.master/d-i/modules/nic-usb-modules
+++ linux-4.4.0/debian.master/d-i/modules/nic-usb-modules
@@ -0,0 +1,32 @@
+catc ?
+kaweth ?
+pegasus ?
+prism2_usb ?
+rtl8150 ?
+usbnet ?
+zd1211rw ?
+zd1201 ?
+rt2500usb ?
+rt73usb ?
+rt2570 ?
+rt2800usb ?
+rt2x00usb ?
+cdc_ether ?
+asix ?
+cdc_eem ?
+cdc_ether ?
+cdc-phonet ?
+cdc_subset ?
+dm9601 ?
+gl620a ?
+hso ?
+int51x1 ?
+mcs7830 ?
+net1080 ?
+plusb ?
+rndis_host ?
+smsc95xx ?
+zaurus ?
+carl9170 ?
+smsc75xx ?
+smsc95xx ?
--- linux-4.4.0.orig/debian.master/d-i/modules/parport-modules
+++ linux-4.4.0/debian.master/d-i/modules/parport-modules
@@ -0,0 +1,2 @@
+parport ?
+parport_pc ?
--- linux-4.4.0.orig/debian.master/d-i/modules/pata-modules
+++ linux-4.4.0/debian.master/d-i/modules/pata-modules
@@ -0,0 +1,47 @@
+pata_ali.ko ?
+pata_amd.ko ?
+pata_artop.ko ?
+pata_atiixp.ko ?
+pata_atp867x.ko ?
+pata_cmd640.ko ?
+pata_cmd64x.ko ?
+pata_cs5520.ko ?
+pata_cs5530.ko ?
+pata_cs5535.ko ?
+pata_cs5536.ko ?
+pata_cypress.ko ?
+pata_efar.ko ?
+pata_hpt366.ko ?
+pata_hpt37x.ko ?
+pata_hpt3x2n.ko ?
+pata_hpt3x3.ko ?
+pata_isapnp.ko ?
+pata_it8213.ko ?
+pata_it821x.ko ?
+pata_jmicron.ko ?
+pata_legacy.ko ?
+pata_macio.ko ?
+pata_marvell.ko ?
+pata_mpiix.ko ?
+pata_netcell.ko ?
+pata_ninja32.ko ?
+pata_ns87410.ko ?
+pata_ns87415.ko ?
+pata_oldpiix.ko ?
+pata_optidma.ko ?
+pata_opti.ko ?
+pata_pcmcia.ko ?
+pata_pdc2027x.ko ?
+pata_pdc202xx_old.ko ?
+pata_qdi.ko ?
+pata_radisys.ko ?
+pata_rdc.ko ?
+pata_rz1000.ko ?
+pata_sc1200.ko ?
+pata_sch.ko ?
+pata_serverworks.ko ?
+pata_sil680.ko ?
+pata_sl82c105.ko ?
+pata_triflex.ko ?
+pata_via.ko ?
+pata_winbond.ko ?
--- linux-4.4.0.orig/debian.master/d-i/modules/pcmcia-modules
+++ linux-4.4.0/debian.master/d-i/modules/pcmcia-modules
@@ -0,0 +1,8 @@
+i82092 ?
+i82365 ?
+pcmcia ?
+pcmcia_core ?
+pd6729 ?
+rsrc_nonstatic ?
+tcic ?
+yenta_socket ?
--- linux-4.4.0.orig/debian.master/d-i/modules/pcmcia-storage-modules
+++ linux-4.4.0/debian.master/d-i/modules/pcmcia-storage-modules
@@ -0,0 +1,6 @@
+pata_pcmcia ?
+qlogic_cs ?
+fdomain_cs ?
+aha152x_cs ?
+nsp_cs ?
+sym53c500_cs ?
--- linux-4.4.0.orig/debian.master/d-i/modules/plip-modules
+++ linux-4.4.0/debian.master/d-i/modules/plip-modules
@@ -0,0 +1 @@
+plip ?
--- linux-4.4.0.orig/debian.master/d-i/modules/ppp-modules
+++ linux-4.4.0/debian.master/d-i/modules/ppp-modules
@@ -0,0 +1,6 @@
+ppp_async ?
+ppp_deflate ?
+ppp_mppe ?
+pppoe ?
+pppox ?
+ppp_synctty ?
--- linux-4.4.0.orig/debian.master/d-i/modules/sata-modules
+++ linux-4.4.0/debian.master/d-i/modules/sata-modules
@@ -0,0 +1,18 @@
+sata_inic162x.ko ?
+sata_mv.ko ?
+sata_nv.ko ?
+sata_promise.ko ?
+sata_qstor.ko ?
+sata_sil24.ko ?
+sata_sil.ko ?
+sata_sis.ko ?
+sata_svw.ko ?
+sata_sx4.ko ?
+sata_uli.ko ?
+sata_via.ko ?
+sata_vsc.ko ?
+ahci_platform ?
+ahci ?
+acard-ahci ?
+libahci ?
+ahci_xgene ?
--- linux-4.4.0.orig/debian.master/d-i/modules/scsi-modules
+++ linux-4.4.0/debian.master/d-i/modules/scsi-modules
@@ -0,0 +1,131 @@
+# SCSI
+raid_class ?
+scsi_transport_spi ?
+scsi_transport_fc ?
+scsi_transport_iscsi ?
+scsi_transport_sas ?
+iscsi_tcp ?
+libiscsi ?
+amiga7xx ?
+a3000 ?
+a2091 ?
+gvp11 ?
+mvme147 ?
+sgiwd93 ?
+cyberstorm ?
+cyberstormII ?
+blz2060 ?
+blz1230 ?
+fastlane ?
+oktagon_esp_mod ?
+atari_scsi ?
+mac_scsi ?
+mac_esp ?
+sun3_scsi ?
+mvme16x ?
+bvme6000 ?
+sim710 ?
+advansys ?
+pm80xx ?
+psi240i ?
+BusLogic ?
+dpt_i2o ?
+u14-34f ?
+ultrastor ?
+aha152x ?
+aha1542 ?
+aha1740 ?
+aic7xxx_old ?
+ips ?
+fd_mcs ?
+fdomain ?
+fnic ?
+in2000 ?
+g_NCR5380 ?
+g_NCR5380_mmio ?
+NCR53c406a ?
+NCR_D700 ?
+NCR_Q720_mod ?
+sym53c416 ?
+qlogicfas408 ?
+qla1280 ?
+pas16 ?
+seagate ?
+seagate ?
+t128 ?
+dmx3191d ?
+dtc ?
+zalon7xx ?
+eata_pio ?
+wd7000 ?
+mca_53c9x ?
+ibmmca ?
+eata ?
+dc395x ?
+tmscsim ?
+megaraid ?
+atp870u ?
+esp ?
+gdth ?
+initio ?
+a100u2w ?
+qlogicpti ?
+ide-scsi ?
+mesh ?
+mac53c94 ?
+pluto ?
+dec_esp ?
+3w-xxxx ?
+3w-9xxx ?
+ppa ?
+imm ?
+jazz_esp ?
+sun3x_esp ?
+fcal ?
+lasi700 ?
+nsp32 ?
+ipr ?
+hptiop ?
+stex ?
+osst ?
+sg ?
+ch ?
+scsi_debug ?
+aacraid ?
+aic7xxx ?
+aic79xx ?
+aic94xx ?
+arcmsr ?
+acornscsi_mod ?
+arxescsi ?
+cumana_1 ?
+cumana_2 ?
+ecoscsi ?
+oak ?
+powertec ?
+eesox ?
+ibmvscsi ?
+ibmvfc ?
+libsas ?
+lpfc ?
+megaraid_mm ?
+megaraid_mbox ?
+megaraid_sas ?
+qla2xxx ?
+sym53c8xx ?
+qla4xxx ?
+mvsas ?
+vmw_pvscsi ?
+ums-cypress ?
+be2iscsi ?
+3w-sas ?
+isci ?
+mlx4_ib ?
+mlx5_ib ?
+zfcp ?
+
+# device handlers
+scsi_dh_alua ?
+scsi_dh_emc ?
+scsi_dh_rdac ?
+scsi_dh_hp_sw ?
--- linux-4.4.0.orig/debian.master/d-i/modules/serial-modules
+++ linux-4.4.0/debian.master/d-i/modules/serial-modules
@@ -0,0 +1,4 @@
+generic_serial ?
+serial_cs ?
+synclink_cs ?
+hyperv-keyboard ?
--- linux-4.4.0.orig/debian.master/d-i/modules/speakup-modules
+++ linux-4.4.0/debian.master/d-i/modules/speakup-modules
@@ -0,0 +1,16 @@
+speakup ?
+speakup_acntpc ?
+speakup_acntsa ?
+speakup_apollo ?
+speakup_audptr ?
+speakup_bns ?
+speakup_decext ?
+speakup_dectlk ?
+speakup_dtlk ?
+speakup_dummy ?
+speakup_keypc ?
+speakup_ltlk ?
+speakup_soft ?
+speakup_spkout ?
+speakup_txprt ?
+speakup_decpc ?
--- linux-4.4.0.orig/debian.master/d-i/modules/storage-core-modules
+++ linux-4.4.0/debian.master/d-i/modules/storage-core-modules
@@ -0,0 +1,10 @@
+# Core stacks
+usb-storage ?
+
+# Block level
+
+# Loop modules
+cryptoloop ?
+
+# Needs to be here for better cdrom initrd layout
+isofs ?
--- linux-4.4.0.orig/debian.master/d-i/modules/usb-modules
+++ linux-4.4.0/debian.master/d-i/modules/usb-modules
@@ -0,0 +1,14 @@
+ehci-hcd ?
+isp116x-hcd ?
+isp1760 ?
+ohci-hcd ?
+r8a66597-hcd ?
+sl811_cs ?
+sl811-hcd ?
+u132-hcd ?
+uhci-hcd ?
+xhci-hcd ?
+ehci-tegra ?
+ehci-msm ?
+uas ?
+xhci-plat-hcd ?
--- linux-4.4.0.orig/debian.master/d-i/modules/virtio-modules
+++ linux-4.4.0/debian.master/d-i/modules/virtio-modules
@@ -0,0 +1,11 @@
+virtio_balloon ?
+virtio_pci ?
+virtio_ring ?
+virtio-rng ?
+virtio_scsi ?
+hv_vmbus ?
+hv_utils ?
+hv_netvsc ?
+hv_mouse ?
+hv_storvsc ?
+hv_balloon ?
--- linux-4.4.0.orig/debian.master/d-i/modules/vlan-modules
+++ linux-4.4.0/debian.master/d-i/modules/vlan-modules
@@ -0,0 +1,3 @@
+slp ?
+garp ?
+8021q ?
--- linux-4.4.0.orig/debian.master/d-i/package-list
+++ linux-4.4.0/debian.master/d-i/package-list
@@ -0,0 +1,207 @@
+Package: kernel-image
+Provides: ext3-modules, ext4-modules
+Provides_amd64: efi-modules, ext3-modules, ext4-modules
+Provides_i386: efi-modules, ext3-modules, ext4-modules
+Provides_ppc64el: ext3-modules, ext4-modules, fat-modules
+Provides_s390x: ext3-modules, ext4-modules, ppp-modules
+
+Package: dasd-modules
+Depends: kernel-image, storage-core-modules
+Priority: standard
+Description: DASD storage support
+
+Package: dasd-extra-modules
+Depends: dasd-modules
+Priority: extra
+Description: DASD storage support -- extras
+
+Package: fat-modules
+Depends: kernel-image
+Priority: standard
+Description: FAT filesystem support
+ This includes Windows FAT and VFAT support.
+
+Package: fb-modules
+Depends: kernel-image
+Priority: standard
+Description: Framebuffer modules
+
+Package: firewire-core-modules
+Depends: kernel-image, storage-core-modules
+Priority: standard
+Description: Firewire (IEEE-1394) Support
+
+Package: floppy-modules
+Depends: kernel-image
+Priority: standard
+Description: Floppy driver support
+
+Package: fs-core-modules
+Depends: kernel-image
+Priority: standard
+Provides: ext2-modules, jfs-modules, reiserfs-modules, xfs-modules
+Description: Base filesystem modules
+ This includes jfs, reiserfs and xfs.
+
+Package: fs-secondary-modules
+Depends: kernel-image, fat-modules
+Priority: standard
+Provides: btrfs-modules, ntfs-modules, hfs-modules
+Description: Extra filesystem modules
+ This includes support for Windows NTFS and MacOS HFS/HFSPlus
+
+Package: input-modules
+Depends: kernel-image, usb-modules
+Priority: standard
+Description: Support for various input methods
+
+Package: irda-modules
+Depends: kernel-image, nic-shared-modules
+Priority: standard
+Description: Support for Infrared protocols
+
+Package: md-modules
+Depends: kernel-image
+Priority: standard
+Provides: crypto-dm-modules
+Description: Multi-device support (raid, device-mapper, lvm)
+
+Package: nic-modules
+Depends: kernel-image, nic-shared-modules, virtio-modules
+Priority: standard
+Description: Network interface support
+
+Package: nic-pcmcia-modules
+Depends: kernel-image, nic-shared-modules, nic-modules
+Priority: standard
+Description: PCMCIA network interface support
+
+Package: nic-usb-modules
+Depends: kernel-image, nic-shared-modules, usb-modules
+Priority: standard
+Description: USB network interface support
+
+Package: nic-shared-modules
+Depends: kernel-image, crypto-modules
+Priority: standard
+Description: nic shared modules
+  This package contains modules which support nic modules
+
+Package: parport-modules
+Depends: kernel-image
+Priority: standard
+Description: Parallel port support
+
+Package: pata-modules
+Depends: kernel-image, storage-core-modules
+Priority: standard
+Description: PATA support modules
+
+Package: pcmcia-modules
+Depends: kernel-image
+Priority: standard
+Description: PCMCIA Modules
+
+Package: pcmcia-storage-modules
+Depends: kernel-image, scsi-modules
+Priority: standard
+Description: PCMCIA storage support
+
+Package: plip-modules
+Depends: kernel-image, nic-shared-modules, parport-modules
+Priority: standard
+Description: PLIP (parallel port) networking support
+
+Package: ppp-modules
+Depends: kernel-image, nic-shared-modules, serial-modules
+Priority: standard
+Description: PPP (serial port) networking support
+
+Package: sata-modules
+Depends: kernel-image, storage-core-modules
+Priority: standard
+Description: SATA storage support
+
+Package: scsi-modules
+Depends: kernel-image, storage-core-modules
+Priority: standard
+Description: SCSI storage support
+
+Package: serial-modules
+Depends: kernel-image
+Priority: standard
+Description: Serial port support
+
+Package: storage-core-modules
+Depends: kernel-image
+Priority: standard
+Provides: loop-modules
+Description: Core storage support
+ Includes core SCSI, LibATA, USB-Storage. Also includes related block
+ devices for CD, Disk and Tape medium (and IDE Floppy).
+
+Package: usb-modules
+Depends: kernel-image, storage-core-modules
+Priority: standard
+Description: Core USB support
+
+Package: nfs-modules
+Priority: standard
+Depends: kernel-image
+Description: NFS filesystem drivers
+ Includes the NFS client driver, and supporting modules.
+
+Package: block-modules
+Priority: standard
+Provides: nbd-modules
+Depends: kernel-image, storage-core-modules, parport-modules, virtio-modules
+Description: Block storage devices
+ This package contains the block storage devices, including DAC960 and
+ paraide.
+
+Package: message-modules
+Priority: standard
+Depends: kernel-image, storage-core-modules, scsi-modules
+Description: Fusion and i2o storage modules
+ This package containes the fusion and i2o storage modules.
+
+Package: crypto-modules
+Priority: extra
+Depends: kernel-image
+Description: crypto modules
+ This package contains crypto modules.
+
+Package: virtio-modules
+Priority: standard
+Depends: kernel-image
+Description: VirtIO Modules
+ Includes modules for VirtIO (virtual machine, generally kvm guests)
+
+Package: socket-modules
+Depends: kernel-image
+Priority: standard
+Description: Unix socket support
+
+Package: mouse-modules
+Depends: kernel-image, input-modules, usb-modules
+Priority: extra
+Description: Mouse support
+ This package contains mouse drivers for the Linux kernel.
+
+Package: vlan-modules
+Depends: kernel-image
+Priority: extra
+Description: vlan modules
+ This package contains vlan (8021.Q) modules.
+
+Package: ipmi-modules
+Depends: kernel-image
+Priority: standard
+Description: ipmi modules
+
+Package: multipath-modules
+Depends: kernel-image
+Priority: extra
+Description: DM-Multipath support
+  This package contains modules for device-mapper multipath support.
+
--- linux-4.4.0.orig/debian.master/dkms-versions
+++ linux-4.4.0/debian.master/dkms-versions
@@ -0,0 +1 @@
+wireguard-linux-compat 1.0.20201112-1~16.04.1
--- linux-4.4.0.orig/debian.master/etc/kernelconfig
+++ linux-4.4.0/debian.master/etc/kernelconfig
@@ -0,0 +1,7 @@
+if [ "$variant" = "ports" ]; then
+	archs=""
+	family='ports'
+else
+	archs="amd64 arm64 s390x"
+	family='ubuntu'
+fi
--- linux-4.4.0.orig/debian.master/info/OVERRIDES
+++ linux-4.4.0/debian.master/info/OVERRIDES
@@ -0,0 +1,153 @@
+CONFIG_RCU_KTHREAD_PRIO=0
+CONFIG_X86_AMD_PLATFORM_DEVICE=y
+CONFIG_ZSMALLOC_STAT=N
+CONFIG_LIVEPATCH=y
+CONFIG_IEEE802154_SOCKET=m
+CONFIG_NET_ACT_BPF=m
+CONFIG_NET_ACT_CONNMARK=m
+# CONFIG_BT_SELFTEST is not set
+CONFIG_MTD_NAND_HISI504=m
+CONFIG_IXGBE_VXLAN=y
+CONFIG_TI_CPSW_ALE=m
+CONFIG_MOUSE_PS2_FOCALTECH=y
+CONFIG_INPUT_E3X0_BUTTON=m
+CONFIG_INPUT_REGULATOR_HAPTIC=m
+CONFIG_INPUT_TPS65218_PWRBUTTON=m
+CONFIG_INPUT_AXP20X_PEK=m
+# CONFIG_DEVMEM is not set
+CONFIG_TCG_TIS_I2C_ST33=m
+CONFIG_TCG_CRB=m
+CONFIG_SPI_DLN2=m
+CONFIG_CHARGER_MAX77693=m
+CONFIG_BATTERY_GAUGE_LTC2941=m
+CONFIG_MFD_DA9150=m
+CONFIG_MFD_RT5033=m
+CONFIG_REGULATOR_RT5033=m
+CONFIG_USB_GSPCA_TOUPTEK=m
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+CONFIG_SND_USB_POD=m
+CONFIG_SND_USB_PODHD=m
+CONFIG_SND_USB_TONEPORT=m
+CONFIG_SND_USB_VARIAX=m
+CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m
+CONFIG_SND_SOC_XTFPGA_I2S=m
+CONFIG_SND_SOC_STA32X=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_USB_ISP1760=m
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_LEDS_CLASS_FLASH=m
+CONFIG_RTC_DRV_ABB5ZES3=m
+CONFIG_RTC_DRV_DS1685_FAMILY=m
+# CONFIG_RTC_DS1685_PROC_REGS is not set
+# CONFIG_RTC_DS1685_SYSFS_REGS is not set
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_FB_SM7XX=m
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_FB_TFT_WATTEROTT=m
+CONFIG_FB_FLEX=m
+CONFIG_FB_TFT_FBTFT_DEVICE=m
+CONFIG_COMMON_CLK_CDCE706=m
+CONFIG_ALTERA_MBOX=m
+CONFIG_PM_DEVFREQ_EVENT=y
+CONFIG_MMA9551=m
+CONFIG_MMA9553=m
+CONFIG_CC10001_ADC=m
+CONFIG_QCOM_SPMI_VADC=m
+CONFIG_IIO_SSP_SENSORHUB=m
+CONFIG_KMX61=m
+CONFIG_CM3232=m
+CONFIG_JSA1212=m
+CONFIG_SX9500=m
+CONFIG_FS_DAX=y
+# CONFIG_PSTORE_PMSG is not set
+# CONFIG_F2FS_IO_TRACE is not set
+CONFIG_NFSD_PNFS=y
+CONFIG_GDB_SCRIPTS=y
+# CONFIG_KASAN is not set
+CONFIG_TEST_HEXDUMP=m
+CONFIG_SECURITY_SMACK_NETFILTER=y
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_BLK_DEV_RAM_DAX=y
+CONFIG_BATTERY_RT5033=m
+CONFIG_IIO_SSP_SENSORS_COMMONS=m
+# CONFIG_ZSMALLOC_STAT is not set
+# CONFIG_X86_INTEL_QUARK is not set
+# CONFIG_ZSMALLOC_STAT is not set
+CONFIG_X86_SFI_CPUFREQ=m
+# CONFIG_X86_INTEL_QUARK is not set
+# CONFIG_ZSMALLOC_STAT is not set
+CONFIG_X86_SFI_CPUFREQ=m
+# CONFIG_ARCH_DIGICOLOR is not set
+CONFIG_ARCH_HIP01=y
+CONFIG_MACH_MT6589=y
+CONFIG_MACH_MT6592=y
+CONFIG_MACH_MT8127=y
+CONFIG_MACH_MT8135=y
+# CONFIG_ARCH_R8A73A4 is not set
+# CONFIG_ZSMALLOC_STAT is not set
+CONFIG_ARM_EXYNOS_CPUFREQ=m
+# CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW is not set
+CONFIG_OF_OVERLAY=y
+CONFIG_HIP04_ETH=m
+CONFIG_SERIAL_CONEXANT_DIGICOLOR=m
+CONFIG_PINCTRL_MSM8916=m
+CONFIG_POWER_RESET_RMOBILE=m
+CONFIG_MEDIATEK_WATCHDOG=m
+CONFIG_MFD_QCOM_RPM=m
+CONFIG_REGULATOR_QCOM_RPM=m
+CONFIG_NOUVEAU_PLATFORM_DRIVER=y
+# CONFIG_DRM_EXYNOS7_DECON is not set
+CONFIG_DRM_ATMEL_HLCDC=m
+CONFIG_DISPLAY_ENCODER_OPA362=m
+CONFIG_SND_SOC_TEGRA_RT5677=m
+CONFIG_MMC_SDHCI_F_SDH30=m
+CONFIG_RTC_DRV_ARMADA38X=m
+CONFIG_RCAR_DMAC=m
+CONFIG_CLK_QORIQ=m
+CONFIG_IPQ_LCC_806X=m
+CONFIG_MSM_LCC_8960=m
+# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
+CONFIG_ARM_TEGRA_DEVFREQ=m
+# CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU is not set
+# CONFIG_ARCH_DIGICOLOR is not set
+# CONFIG_ARCH_HIP01 is not set
+CONFIG_MACH_MT6589=y
+CONFIG_MACH_MT6592=y
+CONFIG_MACH_MT8127=y
+CONFIG_MACH_MT8135=y
+# CONFIG_ARCH_R8A73A4 is not set
+# CONFIG_CLK_QORIQ is not set
+# CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST is not set
+# CONFIG_ARCH_EXYNOS7 is not set
+# CONFIG_ARCH_FSL_LS2085A is not set
+# CONFIG_ARCH_TEGRA is not set
+CONFIG_CAN_XILINXCAN=m
+CONFIG_GPIO_XGENE_SB=m
+# CONFIG_DEBUG_ALIGN_RODATA is not set
+CONFIG_UIO_FSL_ELBC_GPCM=m
+# CONFIG_UIO_FSL_ELBC_GPCM_NETX5152 is not set
--- linux-4.4.0.orig/debian.master/info/REBASE
+++ linux-4.4.0/debian.master/info/REBASE
@@ -0,0 +1,47 @@
+Could not apply b551f2a4439d2179b3732c2a28277d9245dbb150... NEEDED UBUNTU: SAUCE: xgmac_mdio: Silence read errors
+	commit 1fcf77c87ad659a92e1dcfb883388cb43baeaab6
+
+Could not apply 7cc84cf61b760725973c93b9c7e39d6f521bfe62... NEEDED Revert "net/mlx4_en: Fix bad use of dev_id"
+	commit ca9f9f703950e5cb300526549b4f1b0a6605a5c5
+
+error: could not apply ff7e372... overlay: add backwards compatible overlayfs format support
+Could not apply 3fd5011f880877a583b1ccefd06ad481452cdef7... NEEDED overlay: add backwards compatible overlayfs format support (fixes)
+	XXX: needed
+
+Could not apply 98c64db6cffd59a894d4a4492aea761fa6e6c51a... NEEDED UBUNTU: SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot
+Could not apply 892b8b7cfb14b9bdfbc9ac2fee8e751a67707542... NEEDED UBUNTU: SAUCE: Revert: fix: only allow a single threaded process to ...
+Could not apply e1b6a4b88bdb9cf858e068d0e3a6b7449d648513... NEEDED UBUNTU: SAUCE: (no-up) fix: bad unix_addr_fs macro
+Could not apply 9defa41f9126d026cd6a1ead03e6443e98e97108... NEEDED UBUNTU: apparmor -- follow change to this_cpu_ptr
+Could not apply 36ca906c4d4cf34bb5a750d1dbd3e4abe36a4684... NEEDED UBUNTU: SAUCE: (no-up): apparmor: fix mediation of fs unix sockets
+	XXX: needed (apparmor)
+	PORTED AND REAPPLIED
+
+Could not apply 4594c0a5b120fc92fb141c1cf9eef3e8d665e4e6... NEEDED UBUNTU: SAUCE: storvsc: force SPC-3 compliance on win8 and win8 r2 hosts
+	commit b0a93d96b2814c725161f91a4e35d0c29ec0f95b
+
+Could not apply d8db9694361b258427eab1846b211be332c4a1f9... NEEDED UBUNTU: SAUCE: efi: Expose underlying UEFI firmware platform size to userland
+	commit 2859dff97e54db4795b8b7d9606cb8efcec722ff
+
+Could not apply fe8ce4f67a26106dab3193b3515fe865e136ab4a... NEEDED UBUNTU: SAUCE: arm64 -- psci tell the compiler which registers we are needing values in
+	commit f5e0a12ca2d939e47995f73428d9bf1ad372b289
+
+Could not apply e9f926b44c895d39152d3f816ce9ff37780f77cb... NEEDED xen: correct bug in p2m list initialization
+	commit b8f05c8803fce899d79ca66f8d7f348cf15fb40e
+
+Could not apply 7ec323466d993094545e140cc44559cb1cccbd14... NEEDED tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send
+	commit 62dfd912ab3b5405b6fe72d0135c37e9648071f1
+
+Could not apply 6b610659f8b313644c0012a511c6381e9fe7d881... NEEDED net/mlx4_core: Maintain a persistent memory for mlx4 device
+	commit 872bf2fb69d90e3619befee842fc26db39d8e475
+
+Could not apply 7e9a6608ca11948dd0996b6db99e498ca043a0cd... NEEDED tools/power turbostat: support additional Broadwell model
+	commit 48a0631c891ab581cc010b44655ad49ff6eb3325
+
+Could not apply 9a9ab8a2348c722405964a0c785c4b2a613d8782... NEEDED KVM: Add generic support for dirty page logging
+	commit ba0513b5b8ffbcb0cc89e2f172c0bcb70497ba2e
+
+Could not apply 9a9ab8a2348c722405964a0c785c4b2a613d8782... NEEDED KVM: Add generic support for dirty page logging
+	commit 3b0f1d01e501792d8d89ab4371bc9e8cd2a10032
+
+Could not apply 0335b4283d02dcd6e7d6b54e175801099873852e... NEEDED KVM: VMX: Add PML support in VMX
+	commit 843e4330573cc5261ae260ce0b83dc570d8cdc05
--- linux-4.4.0.orig/debian.master/info/RECONCILE
+++ linux-4.4.0/debian.master/info/RECONCILE
@@ -0,0 +1,506 @@
+=== total: 505 ignored: 55 (upstreamed: 49 reverted: 6) needed: 450 (debian: 298 ubuntu: 14 sauce: 138) ===
+3377e17d83c8ce29dc0128c9785043b630e283f3 IGNORE:IN:7486341a98f26857f383aec88ffa10950087c3a1 x86/platform, acpi: Bypass legacy PIC and PIT in ACPI hardware reduced mode
+e826d2f5ee447384828473c249ef38c08b72ffc1 IGNORE:IN:d474a4d365aaa5c7aabcf11a74ea43aa23f6f2e9 powercap / RAPL: handle domains with different energy units
+27ba48b7bec5dc0c9b665b334bbea30fdb44160a NEEDED:debian UBUNTU: [Config] add nvme to linux-virtual as this is now used in GCE to expose disks
+0788d51a2a8d794eb1c8394154028cb593be7ee7 NEEDED:debian UBUNTU: Ubuntu-3.19.0-10.10
+eb97881b6320d127b354b8cb03937504683a7f18 NEEDED HID: multitouch: Add support for button type usage
+554fc470460c6c4d94f202a8a73f24491bc9f0f7 NEEDED HID: multitouch: add support of clickpads
+e098a93f8c11db119261d5c4791d4f9c62c666e8 NEEDED:debian UBUNTU: fix up changelog for rebase
+c0b0bccbe70c7d602c114871d1e1ce42c478f6dc NEEDED:debian UBUNTU: rebase to v3.19.2
+9e086fc3fb3d7f09d4dacfccab0784812ef78764 NEEDED:debian UBUNTU: [Config] CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
+0335b4283d02dcd6e7d6b54e175801099873852e NEEDED KVM: VMX: Add PML support in VMX
+9fa8950638aac15e1273204c9c76447524236345 IGNORE:IN:88178fd4f7187bbe290c5d373fd44aabec891934 KVM: x86: Add new dirty logging kvm_x86_ops for PML
+540b4deed1133b94ba9665ca1c5bdf692fc32c5b IGNORE:IN:1c91cad42366ce0799ca17e7ad6995418741d012 KVM: x86: Change parameter of kvm_mmu_slot_remove_write_access
+9cd0789cd13fe6ceb057b6ee0a9a8089e3d085d0 IGNORE:IN:9b51a63024bd759f97a12f50907b8af23b065b36 KVM: MMU: Explicitly set D-bit for writable spte.
+d06b40dc692080da03fd5fa3f19aa6c3d201cb38 IGNORE:IN:f4b4b1808690c37c7c703d43789c1988c5e7fdeb KVM: MMU: Add mmu help functions to support PML
+ec2347761088c13ec640886cb492e4d4f8aee759 NEEDED KVM: Rename kvm_arch_mmu_write_protect_pt_masked to be more generic for log dirty
+7b476333c9fd20d2be03eba64339df96a6d326d6 IGNORE:IN:e108ff2f8033a417ee3e517d9f8730f665646076 KVM: x86: switch to kvm_get_dirty_log_protect
+9a9ab8a2348c722405964a0c785c4b2a613d8782 NEEDED KVM: Add generic support for dirty page logging
+baddf7f579e3094b7b32c119fae9bb1b4ac557c5 IGNORE:IN:d91ffee9ec633c6523ef1ea39c36ace578760258 Optimize TLB flush in kvm_mmu_slot_remove_write_access.
+e824a2cfa15c76aefc09dcd0157ee31a565b2cb3 IGNORE:IN:7e71a59b250330fd52ee7293eb9d31952f16682e KVM: x86: flush TLB when D bit is manually changed.
+7e9a6608ca11948dd0996b6db99e498ca043a0cd NEEDED tools/power turbostat: support additional Broadwell model
+827aac896a47cdfbc19679d4e14dc269fd0ac846 IGNORE:IN:bea57077e44ec9c1e6d3a3c142c8a3c0289e290d intel_idle: support additional Broadwell model
+3057d6279a10157e6bd1ab7148ef4fc2ccb14d6d IGNORE:IN:3df76a9dcc74d5f012b94ea01ed6e7aaf8362c5a powerpc/pseries: Fix endian problems with LE migration
+dba28dfc35d65493b65d7d4bf382e09297ef9bb4 IGNORE:IN:4ad04e5987115ece5fa8a0cf1dc72fcd4707e33e powerpc/iommu: Remove IOMMU device references via bus notifier
+f9f283435213397957099d1a66a3a0d5bede3528 IGNORE:IN:5c65670c9bfa3be1234d29f36b742897c0360ef3 powerpc/perf/hv-24x7: Document sysfs event description entries
+179039e2ee295381d24a1832349100569ca96acb IGNORE:IN:97bf2640184f4fb2b2bf2c58ae3112768a6174fa powerpc/perf/hv-gpci: add the remaining gpci requests
+eb14eac49af21beac96d0933103b0e329ed4b2be IGNORE:IN:9e9f60108423f18a99c9cc93ef7f23490ecc709b powerpc/perf/{hv-gpci, hv-common}: generate requests with counters annotated
+23b8dd8e12de9f1268a1ecb18a1ec9d157444cfa IGNORE:IN:5c5cd7b502595f6b90509b8aa4bba6f81b69315c powerpc/perf/hv-24x7: parse catalog and populate sysfs with events
+0a72cae7a37a649fb997835c99a93711254210c9 IGNORE:IN:e08e52824e41fb42e46593450d378ad1b33caedb perf: define EVENT_DEFINE_RANGE_FORMAT_LITE helper
+06aa2a9afd745edcb3c3b80eec10c0cf6795cfc0 IGNORE:IN:f0405b816149665393cc62b9e5082fc2d79714df perf: add PMU_EVENT_ATTR_STRING() helper
+e38b3e25ccd090c3be55addc72746ffea85e26fd IGNORE:IN:fd979c0132074856975a6e79bc2226b99435ec5b perf: provide sysfs_show for struct perf_pmu_events_attr
+0512d012693ab7696fc390aa58e38623f774e8f0 IGNORE:IN:f9ab9c196d015f3bd8f6bd1c30785c5a49542323 perf tools: Document parameterized and symbolic events
+914c3ae025813d3868fddac5e7f63eef89a1f77c IGNORE:IN:98a43e0e9917059da32db89829b0eb95453a11ee perf Documentation: Add event parameters
+59c3fddc383e9d02e6ae04cbd9247d626f6acc90 IGNORE:IN:aaea36174991ff39c7a18044660db86527100c55 perf tools: Extend format_alias() to include event parameters
+7ee609fce3a1aa657c3613b985dc62f1a45acaf0 IGNORE:IN:688d4dfcdd624192cbf03c08402e444d1d11f294 perf tools: Support parsing parameterized events
+1d74db86f07ee680a466ae02b460e164aa58a38a NEEDED:debian UBUNTU: [Packaging] generate live watchdog blacklists
+6b5949d8cf32e576a5892472a7826545d94292a4 NEEDED:debian UBUNTU: Start new release
+a705b4e4855e7b484ed11831941fb7093a12d660 IGNORE:IN:285994a62c80f1d72c6924282bcb59608098d5ec arm64: Invalidate the TLB corresponding to intermediate page table levels
+fef4b02b6f20e9cbb50522916a4fd079ed821c07 IGNORE:IN:1b0eb5bc241354aa854671fdf02132d2d1452bdf thinkpad_acpi: support new BIOS version string pattern
+572a605fa5352dcb8a8cc982bbdb998f752aea07 NEEDED:debian UBUNTU: [Config] allow dracult to support initramfs as well
+727f017959487a34dd3c14659306b869545348a5 NEEDED:debian UBUNTU: [Packaging] control -- make element ordering deterministic
+6a501ec1a8e49e7b9869fed950bd1642dd1b68af NEEDED:debian UBUNTU: Ubuntu-3.19.0-9.9
+57165ece4262217e644bc0577bf9ccd5e452f2da NEEDED UBUNTU: SAUCE: IB/core: Prevent integer overflow in ib_umem_get address arithmetic
+4815357c48175b96d4bc67dfbd6c4fb30bb4d714 NEEDED:debian UBUNTU: Start new release
+03247c64299523710c3935227d1a7e28aeb34a97 NEEDED:debian UBUNTU: Ubuntu-3.19.0-8.8
+36ca906c4d4cf34bb5a750d1dbd3e4abe36a4684 NEEDED UBUNTU: SAUCE: (no-up): apparmor: fix mediation of fs unix sockets
+c34820ce1a87b536c2da84daf892e884de7f3067 IGNORE:IN:d0af71a3573f1217b140c60b66f1a9b335fb058b tg3: Hold tp->lock before calling tg3_halt() from tg3_init_one()
+420ed2b6622aa62d962e770422f887e38ede78ac IGNORE:IN:0cd9302734111abc0b5912b695336f2ee63cb22b net/mlx4_core: Reset flow activation upon SRIOV fatal command cases
+441e06e149e10acf3fa4497ae041f79f75a97c23 IGNORE:IN:55ad359225b2232b9b8f04a0dfa169bd3a7d86d2 net/mlx4_core: Enable device recovery flow with SRIOV
+6aa4bcac4501cbf723abbc1b49f22b113c7323f9 IGNORE:IN:2ba5fbd62b2534335f4e3b844ecc7860115525a3 net/mlx4_core: Handle AER flow properly
+a1b81382798563ef9092cad425cccc1e2fc2626e IGNORE:IN:c69453e294c9f16da977b68e658a8028b854c209 net/mlx4_core: Manage interface state for Reset flow cases
+da98e7467248aae377055c75b6380aa5f3f075ec IGNORE:IN:f5aef5aa35063f2b45c3605871cd525d0cb7fb7a net/mlx4_core: Activate reset flow upon fatal command cases
+9a583f4441d28f7b034a2eaaa3aeacdddc0ec65a IGNORE:IN:f6bc11e42646e661e699a5593cbd1e9dba7191d0 net/mlx4_core: Enhance the catas flow to support device reset
+5e52f6741b9fe61696f882effa83021eb013bb2e IGNORE:IN:ad9a0bf08ffbf32b8f292c3bb78ca0f24bb8f6b2 net/mlx4_core: Refactor the catas flow to work per device
+efee37c90fa0d7f1704ea59bcc47b8590b5cf7ca IGNORE:IN:dd0eefe3abbf47442db296bf68f27eb2860c1cdf net/mlx4_core: Set device configuration data to be persistent across reset
+6b610659f8b313644c0012a511c6381e9fe7d881 NEEDED net/mlx4_core: Maintain a persistent memory for mlx4 device
+7ec323466d993094545e140cc44559cb1cccbd14 NEEDED tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send
+dd82e0b3366c0583f66daa1e6fd229e24468d615 IGNORE:IN:de61390cb3e03186f85997fe08a11dcb9f7a01a3 net/mlx5_core: Fix configuration of log_uar_page_sz
+aa391baed594091165eefe21e759f0604dd66c0a NEEDED:debian UBUNTU: rebase to stable v3.19.1
+7eaea45f7109a1e769d5379352e40b13e1b5d6d6 NEEDED:debian UBUNTU: Start new release
+a1ab7786a77235d3fe40ef93e239d26ad095f8c6 NEEDED:ubuntu-driver UBUNTU: ubuntu: vbox -- elide the new symlinks and reconstruct on clean:
+e9f926b44c895d39152d3f816ce9ff37780f77cb NEEDED xen: correct bug in p2m list initialization
+e253864af74e9fd0dbb79c6a1b9ab117d335a006 NEEDED:debian UBUNTU: Ubuntu-3.19.0-7.7
+da9ed9fbcffe22ad779cd0f9e63cae8125870f4c NEEDED:debian UBUNTU: Start new release
+a3efc506086bfc1770015e3a1545d708464dccbc IGNORE:IN:1b28f170d99170a1fdd22818a9610a73196b391d powerpc/eeh: Allow to set maximal frozen times
+d2616b0dfec986efcea32f5a7907bb67334fee40 IGNORE:IN:432227e9077eec13b3caf3aec6087f94a2f4327f powerpc/eeh: Introduce flag EEH_PE_REMOVED
+0d7adce37648ab16e146c07998c86f929933ced2 IGNORE:IN:3d5be0392f52489b7572903d83f1f267f26e6b69 cxl: Fail AFU initialisation if an invalid configuration record is found
+4406598cf9db984056879f543a1dbd0580589fc5 IGNORE:IN:b087e6190ddcd9ae4e8ff2c788d2b32f193e946b cxl: Export optional AFU configuration record in sysfs
+9810a8574ecb496bdb6805df46ef040889279489 IGNORE:IN:62fa19d4b4fd781ad37c9155c6332f28a9e97a2c cxl: Add ability to reset the card
+e0479a12aa4aceb678db96257318102e165127dc IGNORE:IN:1212aa1c8c9ca34642f7737e1edaa96c9ce3d7dd cxl: Enable CAPP recovery
+047163114be9cf5d4fd9ad368b6c0f8f18c177d8 IGNORE:IN:95bc11bcd1428afdb48400ec84dc6d5a83926138 cxl: Add image control to sysfs
+211238b75962ee2b4ddcb1648b94fd2d11464b64 IGNORE:IN:49fd644c3b0014fb80c2b1db7d8c86a75c4c6b1f cxl: Update CXL ABI documentation
+ef2cf73ffe825cb6e5350972edb6ef989f7c019b IGNORE:IN:9bcf28cdb28e6a793c4e59f0a42c66fe241993a8 cxl: Add tracepoints
+bb463fd6632c70d258c46e08a49dbd8ed90b6662 IGNORE:IN:d3383aaae9800b9e13e25b71f70dff3814d10373 cxl: remove redundant increment of hwirq
+50419f397e513bb53fd3a43953ddf97e344b1f9e IGNORE:IN:db7933f392ac4d9719d41d3f203a5f6a1c40f300 cxl: Disable SPAP register when freeing SPA
+1a4659245b032feb290aa890a831fe6db8cce677 IGNORE:IN:d6a6af2c181400aade59417e698c7cd9bec8804e cxl: Disable AFU debug flag
+9e024f9abf9a7bb11c8812ad8f4baac2542b41a4 IGNORE:IN:13da704682471669685ccc3fe111fd6c0127b2eb cxl: Early return from cxl_handle_fault for a shut down context
+b745d4388fd7f150d8c27239a107acc4769c3a55 IGNORE:IN:456295e284beb7b61a55ead9500d30f94ab06d52 cxl: Fix leaking interrupts if attach process fails
+aa79645da2c295c7a54a38d727ba5424c56e8c78 NEEDED:debian UBUNTU: Ubuntu-3.19.0-6.6
+2506464009b6efd8886841fd42aa35dd276e1ae2 NEEDED:ubuntu-driver UBUNTU: ubuntu: vbox -- update to 4.3.22-dfsg-1
+0af35a1df1616ee3af688b8f6811ea980b4ba105 NEEDED:debian UBUNTU: [Config] move vbox modules into linux-image
+591572a04b2929501bfd944f0e1b5dc918d905c2 NEEDED:debian UBUNTU: Disable module check for I2C_CHARDEV=y config change
+ded3e335312faf2066f1a293bc34612f20c7075a NEEDED:debian UBUNTU: [Config] I2C_CHARDEV=y
+6d41878ad435f83f107290bd47da1cae88a5960e NEEDED:debian UBUNTU: Start new release
+af9f67abe58ef01a0e38809dbf9dc9b579d6f729 NEEDED:debian UBUNTU: systemd -- fix hyper-v units to be non-forking
+e06b795ba62bfe38b378a77df6aa1f4e4b4be003 NEEDED:debian UBUNTU: SAUCE: DEP8 test to run our regression tests
+a651bfbc176a850449052a44a8f99cb298cb49f0 NEEDED:debian UBUNTU: Ubuntu-3.19.0-5.5
+65c15025855e39b160ced2bfd9cee0233e9eb5bd NEEDED:debian UBUNTU: rebase to v3.19 final
+00b14848d0ba3d47a244bbe142f4aec6abc6ad8a NEEDED:debian UBUNTU: Start new release
+e3963bddd383dbb567b6e9a3b6d1229b335be7c9 NEEDED:ubuntu-driver UBUNTU: ubuntu: vbox -- update to 4.3.20-dfsg-1ubuntu1
+5dde1b4a9a0dcbff893ba69c97bc8e9af5aeced4 NEEDED:ubuntu-driver UBUNTU: ubuntu: (no-squash) vbox -- infrastructure and updater
+4ac4ed6aaaabccd3113d12d2aae4227eeed2a94d NEEDED UBUNTU: SAUCE: ext4: disable ext4_punch_hole for indirect filesystems
+20f73500aa3c6973b662d434ea994a067d2732ce NEEDED:debian UBUNTU: [Config] Add ibmvfc to d-i
+27016d13d7def2d932edabe10cda08551eb76af4 NEEDED:debian UBUNTU: [Config] CONFIG_FA_DUMP=y
+043037877a7de2b8e6b2dff0420efe45ecff2ff5 NEEDED:debian UBUNTU: Ubuntu-3.19.0-4.4
+5dacd4f7dba5435e1b960bdc491293c82ee3ec2f NEEDED:debian UBUNTU: updateconfigs following rebase to v3.19-rc7
+9eade02480702c9670f2bac1bd55d38545a312cf NEEDED:debian UBUNTU: rebase to v3.19-rc7
+28f33eab58fbe7473e6ef7273c82f6b46108bd19 NEEDED:debian UBUNTU: Start new release
+113ccff71d64d15da62001f597421ead251c70a8 NEEDED:debian UBUNTU: hyper-v -- fix comment handing in /etc/network/interfaces
+2df9364c2056a3043e10cd5a62ce9706b2f7d1d1 NEEDED UBUNTU: SAUCE: rtsx_usb_ms: Use msleep_interruptible() in polling loop
+88065e99f0f6bcf3dc4631a2ceec2f2708af8cef NEEDED:debian UBUNTU: [Config] apply Kernel hacking >> Tracers config defaults
+0d569c89d78dfe8145fbeebe5249f794a9d0f552 NEEDED:debian UBUNTU: Ubuntu-3.19.0-3.3
+c0a8e98a3847348d78a54c944d202137d068b94d NEEDED:debian UBUNTU: annotations -- pull in updated annotations
+25a4fc67cec440d3bb4bc7705449df08e6c51858 NEEDED:debian UBUNTU: [Config] updateconfigs following rebase to v3.19-rc6
+7c37badc321d561bbd2f178669119c919ff20522 NEEDED:debian UBUNTU: rebase to v3.19-rc6
+4b617281c437581c70f6cf2334398bb1ab1c0340 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Mailbox Hardware Support config defaults
+32d6900d5dc2578bdb1627edfeed21e631a31e60 NEEDED:debian UBUNTU: [Config] apply General setup >> CPU/Task time and stats accounting >> Cputime accounting config defaults
+cd6b5ebc39722a4e376e47f1d48a0e46286ff308 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> SCSI device support >> SCSI device support >> SCSI low-level drivers config defaults
+c8a2a8aae37f1474453bea69acbf95c396227e31 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Real Time Clock config defaults
+a74fa91f9105e69fd2b101d914ab503ef67dd227 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Network device support >> Wireless LAN >> Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) config defaults
+fe8ce4f67a26106dab3193b3515fe865e136ab4a NEEDED UBUNTU: SAUCE: arm64 -- psci tell the compiler which registers we are needing values in
+2f02ebe61ad44b1175700cc78a3ccd94bb07ff06 NEEDED:debian UBUNTU: [Packaging] force "dpkg-source -I -i" behavior
+5a6bf13232cd325e73e6ebae516cac9b0da4421c NEEDED:debian UBUNTU: [Config] apply General setup >> Timers subsystem >> Timer tick handling config defaults
+d3d0add00f0801e6823242d1c7bd41c990eb05bb NEEDED:debian UBUNTU: [Config] apply Kernel hacking >> Kernel debugging config defaults
+3b255c82446a97f59e59adb3bd320df4550c1381 NEEDED:debian UBUNTU: [Config] apply Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IPv6: Netfilter Configuration >> IPv6 NAT config defaults
+3549c0af6717159aa8a3b77864dde9b341476b1b NEEDED:debian UBUNTU: [Config] apply Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> IP: Netfilter Configuration >> IPv4 NAT config defaults
+76fb94fa938323cea755f08923c1699f857849a4 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Pulse-Width Modulation (PWM) Support config defaults
+91aa3e3c5f375fcda9802e0bf30743388db97809 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Mice config defaults
+7e28f1d5b0f539c2f315248d638d322cc1bed204 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Keyboards config defaults
+83d976c317bc7939457ba2b194ca9b20942b08e8 NEEDED:debian UBUNTU: [Config] apply Networking support >> Wireless >> Generic IEEE 802.11 Networking Stack (mac80211) config defaults
+a6ff3e7b7835019303b4df16c7d34e83f7bc432f NEEDED:debian UBUNTU: [Config] apply Networking support >> Networking options >> TCP/IP networking config defaults
+fff6ce5d257e3a55676ab2f32f7174648b48bd4d NEEDED:debian UBUNTU: [Config] apply Networking support >> Networking options >> QoS and/or fair queueing >> Actions config defaults
+3db2706fa00266f41b26ac6156b92cc92013c4b6 NEEDED:debian UBUNTU: [Config] apply Networking support >> Networking options >> Network packet filtering framework (Netfilter) >> Core Netfilter Configuration >> Netfilter nf_tables support config defaults
+d379025cb43c73ba0ba6b1e9ae7030ef3706acbb NEEDED:debian UBUNTU: [Config] apply Networking support >> NFC subsystem support >> Near Field Communication (NFC) devices config defaults
+d682b0866fdab7676efc02d7aca31ffba5af5ba9 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> USB support >> USB Gadget Support >> USB Peripheral Controller config defaults
+cc6d21036b39e6747f35992743390b46f490ef71 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> USB support >> USB Gadget Support >> USB Gadget Drivers >> USB functions configurable through configfs config defaults
+f38ce7164ddb54b46a19ed6e3640d5e21f968aff NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Staging drivers >> Media staging drivers config defaults
+f2e32d3fe36a5af721325ad09244872f55783932 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Staging drivers >> Lustre file system client support config defaults
+3fa3a6e3f9bc72ccf4050d5278d82c4f18fa614c NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> HD-Audio config defaults
+7483bb4ddb3800421bf67db6f57e9a2ad68aede9 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> FireWire sound devices config defaults
+bb035568140e5726260cbffc40900186503e066e NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Sound card support >> Advanced Linux Sound Architecture >> ALSA for SoC audio support config defaults
+5857964914cdeedb945ef65490afa1353f0e7d06 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> SPI support config defaults
+67356ed062d29becaaf27108aa8737fee13cab69 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Pin controllers config defaults
+fdab45aa9ebd2c87af7ad88b62c557a9ddaf06eb NEEDED:debian UBUNTU: [Config] apply Device Drivers >> PHY Subsystem config defaults
+be26a7664fe53b25132a1570e7cb572cdfaf8f03 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Network device support >> Wireless LAN >> Intel PRO/Wireless 2200BG and 2915ABG Network Connection config defaults
+664ad4582ac5f69f585defe21f75a44efdc5def9 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Network device support >> Wireless LAN >> Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) config defaults
+7abff1caa5b128105a095b294a4084d58eb4208a NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Network device support >> Network core driver support config defaults
+b85516a587125164e4fb6f40a937687859484278 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Network device support >> Distributed Switch Architecture drivers config defaults
+6eeec6ead3c181f9d305a5139a2af09ab02d25e2 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Multimedia support >> Remote Controller devices config defaults
+9bf5422ec87618ea0a9c158e2ee3ea763769635e NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Multimedia support >> Media PCI Adapters config defaults
+0062486c5f49ca81ce44c08483793cd28bd55d4e NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Multimedia support >> Cameras/video grabbers support >> Media test drivers config defaults
+a3cab812b888b76a1c6188d51837461f82579107 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Multifunction device drivers config defaults
+efce9b94895b00d4246281051a6f57abd556b593 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> MMC/SD/SDIO card support config defaults
+ba5f91a1915102862b13b8c73223662536b6ff51 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> LED Support >> LED Class Support config defaults
+5a655a22455c44e92b820d86de5f1eff080d44a1 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Touchscreens config defaults
+2dc2403265124b82af4a57da628cb21bafbab54a NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Input device support >> Generic input layer (needed for keyboard, mouse, ...) >> Mice config defaults
+9fe17395d411adbcfb323c915f84ea85f4c48ce8 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Industrial I/O support >> Pressure sensors config defaults
+5e7b068f32db503c6eb371a23ae2c2a16749578f NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Industrial I/O support >> Humidity sensors config defaults
+20e5409f0457d28d2abca5ef7c1630dc22d84813 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Industrial I/O support >> Analog to digital converters config defaults
+7ae44769248078c8d1ba362fcf3de16b8ab681ab NEEDED:debian UBUNTU: [Config] apply Device Drivers >> I2C support >> I2C support >> I2C Hardware Bus support config defaults
+581c6acbf122138da27108c2a13098d6815349df NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Hardware Monitoring support config defaults
+2e33cbcfe6451f61ae18aeec37fe1753d0a52cc2 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> HID support >> HID bus support >> Special HID drivers config defaults
+02139708b965f07a499593f9036750c30fbe6454 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Graphics support >> Frame buffer Devices >> Support for frame buffer devices config defaults
+a86fe195e825e37e694a5960f7af6ddfbf9f3673 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Graphics support >> Direct Rendering Manager >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) config defaults
+0d10ef98e5bb7c1fb144139e54e13d0051d6f5e4 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> GPIO Support config defaults
+0c423ad9c578e7596de1409cbfd2db4d5b988cd2 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Character devices >> Serial drivers config defaults
+58007d9583eaf94442bcaf472d4e69c8dc24cf61 NEEDED:debian UBUNTU: [Config] apply Device Drivers >> Character devices >> IPMI top-level message handler config defaults
+429394f5a6c855973e6027edbf8811d94f2e54d7 NEEDED:debian UBUNTU: [Config] Disable CONFIG_USB_OTG
+7676b5cebdfe24bebfe402c85ce7d232f76fe756 NEEDED:debian UBUNTU: [Config] CONFIG_DEBUG_INFO_SPLIT=n
+66857d56aa24e2eff079df005f0d189060d68645 NEEDED:debian UBUNTU: [Config] annotations: clean up CONFIG_FW_LOADER_USER_HELPER_FALLBACK and associates
+17fde7fa97d8da20c499e37ff9615895623adb8e NEEDED:debian UBUNTU: annotations: add new v3.19-rc5 options (and some returning options)
+3fd5011f880877a583b1ccefd06ad481452cdef7 NEEDED overlay: add backwards compatible overlayfs format support (fixes)
+7c3d7c6d8df09db4b2f6be809434232021d9305f NEEDED:debian UBUNTU: [Packaging] hyper-v -- daemons now require -n for non-forking startup
+e3defbff069c0d1afa9c30ecdb2cfbd3776c16eb NEEDED:debian UBUNTU: [Config] enforce CONFIG_FHANDLE=y
+b4d80bddacd59441e76e4f4b750154f1a95736a6 NEEDED:debian UBUNTU: annotations -- reorder pass
+ed8c877b843aeaa7fe38947d0bdbf15ef9405f27 NEEDED:debian UBUNTU: [Config] updateconfigs following rebase to v3.19-rc5
+9dd6f68702869ea7ee4219aeeba148bd11e9e211 NEEDED:debian UBUNTU: [Config] add modules removed due to tighter dependencies
+c3d1971989ed55f56aaa0bd882611d8c228cbc05 NEEDED:debian UBUNTU: rebase to v3.19-rc5
+07d995fd618003c3e4663f2e58b73318fa442c32 NEEDED:debian UBUNTU: Start new release
+610b443e33e236074875db94a42ed8d8190951f6 NEEDED:debian UBUNTU: [Packaging] enforce -- drop empty enforce file
+1dd97225d642eaa32460873d90a53c58aa11e243 NEEDED:debian UBUNTU: [Packaging] config-check -- drop support for enforce file
+129becf2ef8faffe61100ef5f6435d3bd396265c NEEDED:debian UBUNTU: [Config] annotations -- switch to ENFORCED annotations
+561c8f3a1941d2895a150b5780def64b5b8fa5b4 NEEDED:debian UBUNTU: [Packaging] config-check -- add support for enforced annotations
+33ea0bf33a842aa5d8f826f3be477a7b1fd7b8fa NEEDED:debian UBUNTU: annotations -- full v3.17/v3.18/v3.19 review pass
+eee1ca9895f0a19241010cea3ef7b5c87bbc3cc9 NEEDED:debian UBUNTU: annotations -- reorder to vivid menu layout
+57ccd817353c91a6b5ed620db15e86315251e1a9 NEEDED:debian UBUNTU: annotations -- utopic base
+5a62a2f9705b70bdf6a1a0870d15903016411c5c NEEDED UBUNTU: [Debian] arm64 -- build ubuntu drivers
+a58e808c17a895c7c3698bee63172114790a6d88 NEEDED:debian UBUNTU: Ubuntu-3.19.0-2.2
+d8db9694361b258427eab1846b211be332c4a1f9 NEEDED UBUNTU: SAUCE: efi: Expose underlying UEFI firmware platform size to userland
+c0b5915ac61b6c49e27fecf6ba8f62cc2d17297b NEEDED:debian UBUNTU: add missing buglink in unreleased versions
+80ac0a8626c33921522e59e258a0bcee0fac6620 NEEDED:debian UBUNTU: [Config] switch on "all" dtbs
+f5c5c728204613d98677cecfa499451a43c316d9 NEEDED:debian UBUNTU: [Packaging] install all dtb files
+4594c0a5b120fc92fb141c1cf9eef3e8d665e4e6 NEEDED UBUNTU: SAUCE: storvsc: force SPC-3 compliance on win8 and win8 r2 hosts
+2db975f991de109cb558a88b821aee4ab32294b9 NEEDED:debian UBUNTU: [Config] updateconfigs following rebase to v3.19-rc4
+efda5ea3e72181c54313960c4eb623cb9bf70184 NEEDED:debian UBUNTU: rebase to v3.19-rc4
+3ceca000c3f419e4ea82d5cc89b17788311e066a NEEDED:debian UBUNTU: [Config] Enable CONFIG_N_GSM as module.
+6d976353cda7b65cd3bccc025fd676a2b60be71e NEEDED UBUNTU: SAUCE: drivers/rtc/interface.c: ignore exprired times when enqueing new timers
+c2b14cbdd9db02c941b1a201ea7de7cbefd042a5 NEEDED:debian UBUNTU: Start new release
+7e4ee90affaec9dfd96c8c527e410e37e60e7cdd NEEDED:debian UBUNTU: Ubuntu-3.19.0-1.1
+07d5adb10aa7995e36b1c3fb063b1db97e0744bb NEEDED:debian UBUNTU: [Config] follow move of arm64 dts' into vendor directories
+c73a0ec29f0772426f60c0e5e4c660a5f49c2963 NEEDED:debian UBUNTU: [Packaging] handle dts directories
+c8f77b2dd48cc6a6bcce49411b546aefa08c799c NEEDED:debian UBUNTU: [Packaging] uploadnum should be the remainder of the version
+50a8041a37110aa8867a493b624aa6bf409acb93 NEEDED:debian UBUNTU: [Configs] updateconfigs following rebase to v3.19-rc3
+afa910e643c7b399c3cdd8312d84b65d1c64d197 NEEDED:debian UBUNTU: rebase to v3.19-rc3
+732f3e48b565abe6e7fd7f489edb3bc88e68581c NEEDED:debian UBUNTU: v3.19 series start
+ea0064b7d9878d01ec4653e528c9b998b4ae10b5 NEEDED:debian UBUNTU: [Configs] updateconfigs following aufs update
+13055ff9195392d6f1d8cc9065079147efd15b2e NEEDED:ubuntu-driver UBUNTU: ubuntu: AUFS -- update to 92ad9cc8bd289bf8e59b6bd8d83137d8e1a58c1c
+3df26820282895c299dffb25972f584721ea75c1 NEEDED:ubuntu-driver UBUNTU: ubuntu: AUFS -- substrate: aufs3-standalone.patch
+b9579ed6992d02cd55e4d94a13be89c32ce84ff5 NEEDED:ubuntu-driver UBUNTU: ubuntu: AUFS -- substrate: aufs3-mmap.patch
+b39b7e7301c7723004985b773bcfb74fbfb4eabb NEEDED:ubuntu-driver UBUNTU: ubuntu: AUFS -- substrate: aufs3-base.patch
+e08ec9211daa19f663ab406848b5df2271eac1d4 IGNORE:revert Revert "UBUNTU: SAUCE: AUFS -- aufs3-base.patch"
+4a9009a9ae4027ec12dd6313fd18a8bb56bf4918 IGNORE:revert Revert "UBUNTU: SAUCE: AUFS -- aufs3-mmap.patch"
+6ae8ad7291b70e01d11bf753e5e79d5b5aeee7fb IGNORE:revert Revert "UBUNTU: SAUCE: AUFS -- aufs3-standalone.patch"
+241d2270754f4ab7d90d52324a7c8a85be88aca7 NEEDED:debian UBUNTU: disable module checks for rebase
+9defa41f9126d026cd6a1ead03e6443e98e97108 NEEDED UBUNTU: apparmor -- follow change to this_cpu_ptr
+caae90a5781f1d312b91fe44839c56009f2e0eb3 NEEDED:ubuntu-driver UBUNTU: ubuntu: aufs3 -- follow rename for d_alias
+401119f392cb5bd61918659f9a20ab2ae54934e7 NEEDED:ubuntu-driver UBUNTU: ubuntu: aufs3 -- follow switch to get_unused_fd_flags()
+78df37e096365062f950d01f27dacf143ba57276 NEEDED:ubuntu-driver UBUNTU: ubuntu: aufs3 -- follow switch to d_splice_alias
+ca8d1a7503192dd5b9c1197eae4ea6be8f36ae81 NEEDED:ubuntu-driver UBUNTU: ubuntu: aufs3 -- follow rename of d_child
+388a35e8069f8657310c7f00d9062989da94b49d NEEDED:debian UBUNTU: [Config] defaultconfigs following rebase to v3.19-rc2
+e08b74c9afcc53d50a3c8ebe43e3b8cb60f2aa61 NEEDED:debian UBUNTU: rebase to v3.19-rc2
+a8d99914420de484583f3ef7327d603cce40fd3a NEEDED:debian UBUNTU: rebase to v3.19-rc1
+0373477d240b8de65a1b6f8596f1b55e61eb7871 NEEDED:ubuntu-driver UBUNTU: ubuntu: AUFS3 -- follow switch to vfs_fallocate
+817e01310fbcc1932419860833d9bba41e8d21a9 NEEDED:debian UBUNTU: Start new release
+685154a8fd43a024cc3f671d85c36158717c0f0c NEEDED arm64: optimized copy_to_user and copy_from_user assembly code
+980f00986e35f630c7bb18065836e3b2f518f7a2 NEEDED:debian UBUNTU: Ubuntu-3.18.0-7.8
+eef49554443cc3c5bf71b7f5aa500dce3ab3e0d0 NEEDED:debian UBUNTU: [config] set apparmor config options
+8a91a5705046dca1c9972ce2a76714edc837e367 NEEDED UBUNTU: SAUCE: (no-up) apparmor: add parameter to control whether policy hashing is used
+e1b6a4b88bdb9cf858e068d0e3a6b7449d648513 NEEDED UBUNTU: SAUCE: (no-up) fix: bad unix_addr_fs macro
+892b8b7cfb14b9bdfbc9ac2fee8e751a67707542 NEEDED UBUNTU: SAUCE: Revert: fix: only allow a single threaded process to ...
+98c64db6cffd59a894d4a4492aea761fa6e6c51a NEEDED UBUNTU: SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot
+178a99413c26c359c7ea63c23b70c14238c72c9e NEEDED:debian UBUNTU: [Config] CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
+0e7cd75372d106d02b3f03f9a2e6496782e39102 NEEDED:debian UBUNTU: Start new release
+354c399098d730724d47572411db3966640b886d NEEDED:debian UBUNTU: Ubuntu-3.18.0-6.7
+70f41850210ae054ddddd3cdb3c8c6b80d26fef9 NEEDED:debian UBUNTU: [Config] CONFIG_PCIEASPM_DEBUG=y
+69d6e475d4b184e691fde6bb6173b0b2a78f95ee NEEDED:debian UBUNTU: [Config] armhf: VIRTIO_[BALLOON|MMIO]=y
+e7248dea9798e37ed9136c0234e60c5d3724a09a NEEDED:debian UBUNTU: rebase to v3.18
+c08cb8bf95c2175a3c0d3916a3a95bb865516303 NEEDED:debian UBUNTU: Start new release
+5de9e13b14877580032ab92fb008417493ad5ab6 NEEDED:debian UBUNTU: Ubuntu-3.18.0-5.6
+f0c21c519145ef0374be78d7f3562691dae45800 NEEDED:debian UBUNTU: rebase to v3.18-rc7
+e74900777be8a73fd3d07669414bd103c385d2ce NEEDED:debian UBUNTU: [Config] CONFIG_SCSI_MQ_DEFAULT=n
+58dfe08f9155f1821f7a0659bcb9c869d4e5ac73 NEEDED:debian UBUNTU: Start new release
+10dd9a851640f6ab60c78594bbff79d76dbb2488 NEEDED:debian UBUNTU: [Config] CONFIG_SCOM_DEBUGFS=y for powerpc/powerpc64-smp ppc64el/generic
+9b1c8ecc6c86e71fab6d15bd84bd1628aae6cd2e NEEDED:debian UBUNTU: Ubuntu-3.18.0-4.5
+ea3282297f6f3af23009d7a400b35b73c3c10ac8 NEEDED:debian UBUNTU: [Config] enable overlayfs v1 support
+ff7e37255afb5b57b5e378e7aef2b4935cc3eb0f NEEDED overlay: add backwards compatible overlayfs format support
+47897ce32d62ea9af685c2a4b06734e76fbfcb1d NEEDED:debian UBUNTU: [Config] update configs following rebase to v3.18-rc6
+b9de0aaa58a863d277ac6141018e82d619d0a89c NEEDED:debian UBUNTU: rebase to v3.18-rc6
+f8bae137b946111d88cfd59cdb3501abc6072f7d NEEDED:debian UBUNTU: rebase to v3.18-rc5
+4550c44494ed6064b56dc746c1ca59cc42571292 NEEDED:debian UBUNTU: Start new release
+cb37df61a5a331fe0bf87d467f6938149b7be5f5 NEEDED:debian UBUNTU: Ubuntu-3.18.0-3.4
+394645d92e939afd7bad1e13d07367d8c077fe12 NEEDED UBUNTU: SAUCE: AUFS (no-squash): basic framework and update machinary -- part 2
+3a53bed921a6d5c0fb30fc8e02a06105fad9dcf7 NEEDED:debian UBUNTU: Ubuntu-3.18.0-3.3
+156d0481e2abded21be8e0a516f952d13cfd0ff5 NEEDED:debian UBUNTU: [Config] updateconfigs following aufs3 update
+4f0421c01639daf81bf6ccb3d5f4b8ff75e4552f NEEDED:ubuntu-driver UBUNTU: ubuntu: AUFS -- update to 9d5c349d5c452170b8e813d86956f896a0aef170
+6051ec34d1dbdcb54e4d8c5a9f2161793f85c99d IGNORE:reverted UBUNTU: SAUCE: AUFS -- aufs3-standalone.patch
+d85f1f5fbc58b6f338ed6172f1b281cf7d6cd638 IGNORE:reverted UBUNTU: SAUCE: AUFS -- aufs3-mmap.patch
+29946e18ae75d3ded766003caec2a3677a07a83f IGNORE:reverted UBUNTU: SAUCE: AUFS -- aufs3-base.patch
+57f696f01845322cb8c68804524bdd41a2ad1146 NEEDED:debian UBUNTU: rebase to v3.18-rc4
+11048583c75d357f740d6d2ba6b2285f2657d93f NEEDED:debian UBUNTU: [Config] Disable CONFIG_RCU_USER_QS on arm64
+a20ed54dbbda43450ec3bf5d3db536e2a9ef9000 NEEDED:debian UBUNTU: [Config] disable CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET
+d2dfee2ba64140dc875aa2de2db76326021cd349 NEEDED:debian UBUNTU: [Debian] basic hook support
+696ca2c9a87c9da383d1d0475cc4699e81cf67ba NEEDED:debian UBUNTU: [Config] amd64 is now the indep architecture
+f500e7dcda3dfecfa2175847ba31bf8dd5470ce0 NEEDED:debian UBUNTU: [Config] Disable CONFIG_IPMI_SI_PROBE_DEFAULTS on armhf and arm64
+baf3a88eca0a927579ba1f6cf805c2b49f7b8165 NEEDED:debian UBUNTU: Start new release
+c72e2fb77e36121ff538fe2b6a21354128cd8194 NEEDED:debian UBUNTU: Ubuntu-3.18.0-2.2
+714d582bfcfdb5091e472a15d2b1c4ab74383756 NEEDED:debian UBUNTU: rebase to v3.18-rc3
+68ed89d5098ecb26c3cf2ce31a197b60147accd9 NEEDED:debian UBUNTU: Start new release
+9ba3dda425ca839667062942e93529e75382531a NEEDED:debian UBUNTU: Ubuntu-3.18.0-1.1
+76d6207803e1b92f419126d507d5e790738bb580 NEEDED:debian UBUNTU: [Debian] install usbipd
+2a878f46cd018c9cb2e3f6a9bf436238522e4799 NEEDED:debian UBUNTU: [Config] armhf: disable JUMP_LABEL
+994e6de3dd2affbd3ec963597d7d8af8990627e7 NEEDED:debian UBUNTU: [Config] CONFIG_DRM_BOCHS=n
+0f87fe85382c852b2d5faf7d8b94fa994ae00461 NEEDED:debian UBUNTU: [Config] enable cloud tools on i386
+3aab9a4865e735ffc6aa1979e4d32929da66e317 NEEDED:debian UBUNTU: [Config] CONFIG_PATA_MACIO=y
+f54e18bd24b7362841b1902c1a0804bc1dd12e2d NEEDED:debian UBUNTU: [Config] linux-image-extra postrm is not needed on purge
+be3df8ea980f12fac4ed6e27c5948dc13c25c9d2 NEEDED:debian UBUNTU: [Config] linux-image-extra is additive to linux-image
+809a654eb28d8127dc89dd89d679d44aad7e4cd6 NEEDED:debian UBUNTU: [Config] Added drivers/uio to generic inclusion list
+bc189702109182682081057777e98beaff1200cc NEEDED:debian UBUNTU: [Config] dropped scsi_tgt from generic inclusion list
+2ac80c0acfef71084a8072d792534e3b2617bee9 NEEDED:debian UBUNTU: CONFIG_MODULE_COMPRESS=n
+f7103d518249e744a5c0aa004aca24a1f7d57706 NEEDED:debian UBUNTU: [Debian] Fix linux-doc dangling symlinks
+ba30c7ba905e7f8cc776669e07c2e0a770b1aabf NEEDED:debian UBUNTU: rebase to v3.18-rc2
+0f81052c41fb44d865aa1fdcaf349bd35b097a6f NEEDED:debian UBUNTU: [Config] CONFIG_SOUND_OSS_CORE_PRECLAIM=n
+99f88d003b04a94cdffb06292a131e4c9eaacb10 NEEDED:debian UBUNTU: Enable vivid
+816874fb757dc85e42d20af922290d6d55cf9fac NEEDED:split-debian UBUNTU: rebase to v3.18-rc1
+5774f4dab5e36642e243e03837f63e68c93dfacf NEEDED:debian UBUNTU: rebase to v3.17
+dbabd921800e97ff2a708b068f772ca1182157bc NEEDED:debian UBUNTU: [Config] CONFIG_HOTPLUG_PCI_PCIE=n for ppc64el
+59c659ef34502c3c6b5a0e8490bac9c7ffa9e042 NEEDED:debian UBUNTU: rebase to v3.17-rc7
+431e93cbc6a563ae15b4877810beb1b9f4edd976 NEEDED:debian UBUNTU: [Debian] Don't fail if a symlink already exists
+0794c4f5d47196aaa1c774fcaa2ef81bd7214141 NEEDED:debian UBUNTU: [Config] CONFIG_HOTPLUG_PCI_SHPC=n for ppc64el
+4790317b5007565da1299b35578135011bd9c6e9 NEEDED:debian UBUNTU: [Config] CONFIG_SND_HDA_INTEL=n for ppc64el
+e7971f95deafcac1b3f524645a68fe915344845d NEEDED:debian UBUNTU: [Config] Correct annotation regarding CONFIG_DMA_CMA
+f2d29260d449d918c5885aa6abc182dade506257 NEEDED:debian UBUNTU: [Config] CONFIG_CRASH_DUMP=n for powerpc-smp
+56a2eb988714b6a0bb0f6c0da9a313a8f439291e NEEDED:debian UBUNTU: [Config] Enable usbip tools
+dc7084c88863a69e70e90265485b6b51c01ccbad NEEDED:debian UBUNTU: [Debian] usbip tools packaging
+40504c7e778f0ad9f19180a39ddd9018910c705a NEEDED UBUNTU: SAUCE: usbip: Update include path
+122f035765feacfa15b09515c78af28f7092877c NEEDED:debian UBUNTU: rebase to v3.17-rc6
+d7be42a7599c483c2294e1122d9c4d5f0d347321 NEEDED:debian UBUNTU: [Config] CONFIG_USB_OHCI_HCD_PCI=y
+dd1e6e6bf5f6ffcd1436ad3fbe32c93da7a5ff30 NEEDED:debian UBUNTU: [Config] follow rename of DEB_BUILD_PROFILES
+dee5d182c3b180973d3a6fab11ac30af4513559b NEEDED:debian UBUNTU: [Config] tools -- only build common tools when enabled
+782d85880d33461406f5a288942e6dcc11770e47 NEEDED:debian UBUNTU: [Debian] set do_*_tools after stage1 or bootstrap is determined
+5b118bbb3a38dc3e5be0d5c921603f672fe1ab4c NEEDED:debian UBUNTU: [Config] Add mpt3sas to d-i
+6afad884eeffc67a53e5d11ffe61c9e40b64d26a NEEDED:debian UBUNTU: [Config] CONFIG_DMA_CMA=n
+aa4e526d8be91b593cd6d0a0e4ab949d26541fa0 NEEDED:debian UBUNTU: [Config] CONFIG_KVM_BOOK3S_64_HV=m
+519ac1677b339775493fc2a4cff55d9e54c28ce7 NEEDED:debian UBUNTU: [Config] CONFIG_KVM_BOOK3S_64=m for ppc64el
+dc9bcbd1592cfede67a2c5ccb5c59f26f0589260 NEEDED:debian UBUNTU: [Config] CONFIG_XMON=y
+e9173466e3323cb9c78cdc807c72e6838f5d7119 NEEDED:debian UBUNTU: [Config] armhf: USB_[E|O]HCI_EXYNOS=y
+4377933f12fbcb31006f23d0117d8a0d164adb80 NEEDED:debian UBUNTU: rebase to v3.17-rc5
+2d172824498ca976ec7e37ec373a248d49a0d5cc NEEDED:debian UBUNTU: rebase to v3.17-rc4
+6980242f0ab61eca03c77142ad4000fadfa022f7 NEEDED:debian UBUNTU: rebase to v3.17-rc3
+72e421db34ebf1bbe15649de2ab2132970f21872 NEEDED:debian UBUNTU: [Config] arm/tegra/d-i: framebuffer and usb support for Tegra SoCs
+3cf410f0b6b36de437c55e319bde033fe75cdb28 NEEDED:debian UBUNTU: [Config] Add arm64 to enforcer CONFIG_CC_STACKPROTECTOR
+e332b2967797d421575080f7b872c7b675e47629 NEEDED:debian UBUNTU: [Config] armhf: REGULATOR_TWL4030=y
+c37acf9c89fae66506d9875bdf758a5fee0233ed NEEDED:debian UBUNTU: [Config] Added net/6lowpan/* to generic inclusion list
+4dd073455ec2c021accdd97ee82b8091b17ea7b7 NEEDED:debian UBUNTU: [Config] CONFIG_NFC_ST21NFCB=n
+abc7908d4c71425c16718d40bbbea1515bc39204 NEEDED:debian UBUNTU: updateconfigs
+e09aab2c0d195125f71b50cdff0a858983953609 NEEDED:debian UBUNTU: rebase to v3.17-rc2
+9d32d8b674a700e342c5559d8e09e9590785d40a NEEDED:debian UBUNTU: Start new release
+18ffc6ce8fa107ac99b52f69a8107511c9d560c5 NEEDED:debian UBUNTU: Ubuntu-3.16.0-11.16
+06f6d00b1c7ae75b5988b2ef922cdd8308edacd1 NEEDED:debian UBUNTU: [Config] CONFIG_ZPOOL=y
+7cc84cf61b760725973c93b9c7e39d6f521bfe62 NEEDED Revert "net/mlx4_en: Fix bad use of dev_id"
+6ffe8179fc951ea6d1886f28b0742eb2744f033c NEEDED:debian UBUNTU: Bump ABI
+cc21629a6a5f6a3efdaf91b320508479af69e1fa NEEDED:debian UBUNTU: Start new release
+d1a2628d426406b61d1d46747da2815e7995d3c9 NEEDED:debian UBUNTU: Ubuntu-3.16.0-10.15
+90b44b74910b3c5e86cb05cfde5f67fee0ef2b75 NEEDED UBUNTU: SAUCE: bcache: prevent crash on changing writeback_running
+e3102a21978dd9c109856a48cd84837e708b7b29 NEEDED:debian UBUNTU: [Config] CONFIG_SENSORS_IBMPOWERNV=m
+2819061858516119133b736fdfa0c11d23cceccc NEEDED:debian UBUNTU: [Config] CONFIG_SECURITY_NETWORK_XFRM=y
+a30185ef8f2fa9dd925cf8b99399a72bc308a397 NEEDED:debian UBUNTU: [Config] CONFIG_XFRM_STATISTICS=y
+9d4a441eb46227e80b77e99ef15a4248ba2ddfcd NEEDED UBUNTU: SAUCE: (no-up) arm64: dts: Add PMU node for APM X-Gene Storm SOC
+e7e22f86dfc3e11d8f6eab08074ebb610a20c5ab NEEDED UBUNTU: SAUCE: (no-up) dt-bindings: Add Potenza PMU binding
+5ed1bfbfcc717aead960bf74940328285d3bf957 NEEDED:debian UBUNTU: [debian] Fix regression with ABI subversions and backport
+62f12ae8d9c08cc6496b60b330350a4dfcbca77f NEEDED:debian UBUNTU: Start new release
+ab212af17f1b9eaa43bffde42440598079044839 NEEDED:debian UBUNTU: Ubuntu-3.16.0-9.14
+c8a4d4970d0835d19ff2acd700d0ae94b877b3e7 NEEDED UBUNTU: SAUCE: Overlayfs: allow unprivileged mounts
+38d659d55bb8fab6f71934dd969a1ba8badeed79 NEEDED:debian UBUNTU: rebase to v3.16.1
+aefca49c0717ac60ba231a3b2e0cb62f0937113c NEEDED:debian UBUNTU: Start new release
+a9dc14c5056a82cfd44e3b098b252e52fe0b6925 NEEDED:debian UBUNTU: Ubuntu-3.16.0-8.13
+ab4880f5e96efda31c6b52136704c9eb0ccab87b NEEDED:debian UBUNTU: [debian] Allow for package revisions condusive for branching
+981bed5cd793ef69ac7377e9cbb6375ce70351f6 NEEDED:debian UBUNTU: Start new release
+74a7d62985f35ddef973776c3e31ff256f4a5859 NEEDED:debian UBUNTU: Ubuntu-3.16.0-7.12
+aeaada62d9efea9463bbcfc2a6549d18f023cdd5 NEEDED:debian UBUNTU: [Config] Add hv_balloon to d-i virtio-modules
+035036c87c216bfbb44109c963375f5f20dc05a1 NEEDED:debian UBUNTU: [Config] d-i -- add virtio_scsi to virtio-modules
+62317e97c6bbb5d8043e1fc3e26df6b905325c4c NEEDED:debian UBUNTU: rebase to v3.16 final
+250eb531089a04b95b698be6524ce4edbe15ddc5 NEEDED:debian UBUNTU: [Packaging] Fix 'printchanges' to work with versions containing '+'
+53647a9928a35d01e9f1b59c5d7b96ad3353048a NEEDED:debian UBUNTU: [Config] CONFIG_CONTEXT_TRACKING_FORCE=n
+e1b2b4a99edece7053725bc318f7f58e53767692 NEEDED:debian UBUNTU: [Config] CONFIG_MICROCODE=y
+a1f57fea081dbab4be712029e9b64c60d61935a0 NEEDED:debian UBUNTU: Start new release
+b342b70677fb9741dd3dc137f45e5ce3181223e9 NEEDED:debian UBUNTU: Ubuntu-3.16.0-6.11
+f0c937317763b38820a72a6b02b1fdb0ad9d285d NEEDED:debian UBUNTU: rebase to v3.16-rc7
+d4d6d5fc58a66d37821bbbf8561ac2a814c977d9 NEEDED:debian UBUNTU: [Config] CONFIG_SCSI_IPR_TRACE=y, CONFIG_SCSI_IPR_DUMP=y
+c9990e0b0998d728503f56ab9c7821d56a721a58 NEEDED:debian UBUNTU: [Config] armhf: RTC_DRV_PCF8523=y
+82fd2a6b5fff23ba504adfe2d18dc1d44f109445 NEEDED:debian UBUNTU: [Config] armhf: build cubox & imx6 DTBs
+7fdb1513964145758aefdf7a43b06a1d0b6b5811 NEEDED:debian UBUNTU: [Config] armhf: KEYBOARD_IMX=m
+7534c02766b9c2305e03cd5b5a117c3997863ff4 NEEDED:debian UBUNTU: [Config] armhf: MXS_DMA=y && MTD_NAND_GPMI_NAND=m
+43470d1ec8f5355be9c153b05088af5505ebd499 NEEDED:debian UBUNTU: [Config] CONFIG_KEYS_DEBUG_PROC_KEYS=y
+6f1d20b13ce5c137c86d1144eb82ab38f99e76cf NEEDED:debian UBUNTU: Start new release
+9d6defca20c389c1ff93e5802c71973b092e7a14 NEEDED:split-debian UBUNTU: Ubuntu-3.16.0-5.10
+1d693f78502686a992d2038c9896c3e6c2652ce2 NEEDED UBUNTU: SAUCE: aufs3 -- update update scripting
+53acc12981cc9883d9038fcac7ac86b9ad274f24 NEEDED UBUNTU: SAUCE: AUFS (no-squash): basic framework and update machinary
+87428d40577506cfdf31336368aa613ae0c54639 NEEDED UBUNTU: SAUCE: 85xx: Only use generic tbsync routines on PPC32
+ad006bb4d530a83f425ee836b7d8de7d5c93e3cf NEEDED UBUNTU: SAUCE: (no-up) Select reboot driver for X-Gene platform.
+5d2fc3d65465aac854036c9ca737eab59b608042 NEEDED UBUNTU: SAUCE: nouveau: missing outputs should be warnings
+b2648e043821b5866f8c863c4b928732228d3402 NEEDED UBUNTU: SAUCE: kvm: BIOS disabled kvm support should be a warning
+8c10fb1a7bf59170ed6fd059cb35e5017abcd05f NEEDED UBUNTU: SAUCE: kthread: Do not leave kthread_create() immediately upon SIGKILL.
+6d0ed555d8ae64794d2902f9c1b7e0da5c39d939 NEEDED UBUNTU: SAUCE: intel_pstate: inform user that thermald is worth considering
+594f6dbf60084fd5fc21bdcc0a99b154be76e76d NEEDED UBUNTU: SAUCE: (no-up) mei_me: Add module parameter to disable MSI
+e62b73418e9503b09d61a6dc8721f457bec967d0 NEEDED UBUNTU: SAUCE: Revert "drm/crtc-helpers: fix dpms on logic"
+6e2be9569f946dc74fec9f5f24a9d80689275343 NEEDED UBUNTU: SAUCE: book3e cleanups for CONFIG_RELOCATABLE
+69923caf98a546b30325ec486536633fddb7ff90 NEEDED UBUNTU: SAUCE: book3e/kexec/kdump: recover "r4 = 0" to create the initial TLB
+2df7602013328910b0c6fce7f411a5d1b25be301 NEEDED UBUNTU: SAUCE: book3e/kexec/kdump: redefine VIRT_PHYS_OFFSET
+3d13bd1d0394d80f6dccae2daafdd1ce887e8672 NEEDED UBUNTU: SAUCE: book3e/kexec/kdump: implement ppc64 kexec specfic
+219cc9dd30079c35ad74590b3808ff7e12f3dd39 NEEDED UBUNTU: SAUCE: book3e/kexec/kdump: introduce a kexec kernel flag
+9e138c3c7acc6975d0ac364254ae021592e2d096 NEEDED UBUNTU: SAUCE: book3e/kexec/kdump: create a 1:1 TLB mapping
+2d3b205cde4d3b8069b8d9bb97203de57726ea92 NEEDED UBUNTU: SAUCE: book3e/kexec/kdump: enable kexec for kernel
+32b8a9f39e22e0b54dbe78a1c179de7ca0dfd9cb NEEDED UBUNTU: SAUCE: powerpc/book3e: support CONFIG_RELOCATABLE
+aa396fc0fa2317a5b447e88bc46b352f0411307e NEEDED UBUNTU: SAUCE: vt -- maintain bootloader screen mode and content until vt switch
+0e50fbdb8e04609ddd667428f54d81fd17ffc232 NEEDED UBUNTU: SAUCE: export some symbols for powerpc
+272b7c0f6c6c380981101491d9ef26bd45ade5fe NEEDED UBUNTU: SAUCE: allow IRQs to be irq-threaded by default via config
+d5c3c89b86cfe6ce6dc5c67c462e563326940d44 NEEDED UBUNTU: SAUCE: Provide booke stub for kvmppc_is_bigendian()
+b551f2a4439d2179b3732c2a28277d9245dbb150 NEEDED UBUNTU: SAUCE: xgmac_mdio: Silence read errors
+285f1bd95dd079825af0d06e33af71a7583aeee9 NEEDED UBUNTU: SAUCE: Fixup freescale usb phy driver to work on ppc64
+c2361b23e7b757ffa4241a6ab427694f3be844cd NEEDED UBUNTU: SAUCE: Revert "phy: vitesse make vsc824x_add_skew static"
+f40baa6f375e1730970cebce0a14a7456d539ab2 NEEDED UBUNTU: SAUCE: PPC: PCI: Fix pcibios_io_space_offset() so it works for 32-bit ptr/64-bit rsrcs
+dc7dff6e417c8642ead4659e42e9b1b601db199c NEEDED UBUNTU: SAUCE: phylib: Minimum hack to get the generic 10G PHY driver to work with 10G "fixed-link"s
+0bd9175323dad194fcff7b450aa14d39ce710b3d NEEDED UBUNTU: SAUCE: OMAP: AM33xx: hwmod: Correct AES module SYSC type
+3a1228b27e425e24b6257c8af1e3ccebc1f9f809 NEEDED UBUNTU: SAUCE: ARM: OMAP4: hwmod: Add hwmod data for AES IP
+eff618d811a4b62462674a8bb05556a548f2c112 NEEDED UBUNTU: SAUCE: ARM: OMAP: hwmod: Add SYSC offsets for AES IP
+8418ceb9869d41a7ba4e6217c631bdb28e07c33b NEEDED UBUNTU: SAUCE: suspicious unlocked ->status reading and writing in ipc/sem.c
+fd4bcb1162b482eafc3fc3fe480698cc8d1cdfdb NEEDED UBUNTU: SAUCE: tg3: Add support for new 57786 device id.
+00b5fd7aaa231697512b50a7c80ed2a3c8c7e3b0 NEEDED UBUNTU: SAUCE: Work around broken ACPI backlight on Dell Inspiron 5537
+bf3a2dfe2f7f34c174a0a938c350912e319fe032 NEEDED UBUNTU: SAUCE: disable stack-protector for ARM compressed bootloader
+29fb264813de8f4bbd8c8577901630e6a547d503 NEEDED UBUNTU: SAUCE: uvcvideo: quirk PROBE_DEF for Alienware X51 OmniVision webcam
+cdf48be1c63b4a07cecf2a62617f7fb7b847fabb NEEDED UBUNTU: SAUCE: isapnp_init: make isa PNP scans occur async
+eedee9b0f515aa2793fccbbfd7d58db95b2490d1 NEEDED UBUNTU: SAUCE: dm-crypt: never use write same
+6eccf1ef86175928b723ca681c2ab851d112e7ac NEEDED UBUNTU: SAUCE: (no-up) ACPI: Disable Windows 8 compatibility for some Lenovo ThinkPads
+07419bbe0eb79097693cae2b7ed1b3f467fca642 NEEDED UBUNTU: SAUCE: (no-up) intel_ips: blacklist ASUSTek G60JX laptops
+5b2c0e070ec1b4d29178b320220c5388ec9f9c82 NEEDED UBUNTU: SAUCE: (no-up) Update bnx2x firmware to 7.8.17.0
+fdbf1af4b48970478c1ee25e1c620ecb8cd4035e NEEDED UBUNTU: SAUCE: (no-up) trace: add trace events for open(), exec() and uselib() (for v3.7+)
+1d4ec94ffcaca71994e520abe769ee6dcf4579ee NEEDED UBUNTU: SAUCE: (no-up) x86: reboot: Make Dell Optiplex 390 use reboot=pci
+f760d3c92097784cfda92f3f4c094ccf9fc2497c NEEDED UBUNTU: SAUCE: (no-up) PCI: fix system hang issue of Marvell SATA host controller
+f43492d5b2cf399039ca6914348d25aaee474e4f NEEDED UBUNTU: SAUCE: (no-up) Convert bnx2x firmware files to ihex format
+8b732f482e348d75ee9b433c574bcf88d0a8991b NEEDED UBUNTU: SAUCE: (no-up) Input: Cypress PS/2 Trackpad simulated multitouch
+7466874e8128bab355ddf3512171ae836348b7f7 NEEDED UBUNTU: SAUCE: (no-up) hv: Supply vendor ID and package ABI
+6a5fff41e536a612ddc1352d93a5b6db8ba68f39 NEEDED UBUNTU: SAUCE: (no-up) Revert "VFS: don't do protected {sym,hard}links by default"
+ae359c3e312669ebde46bc3817d6cea99a7f9bef NEEDED UBUNTU: SAUCE: (no-up) Remove vicam files duplicated in linux-firmware
+794523f01c1303be9d736acca7f016af31b7b416 NEEDED UBUNTU: SAUCE: (no-up) Remove dsp56k files used only by m68k
+db779e5d146cf4d34aee88cf9d2f71d00a9c926c NEEDED UBUNTU: SAUCE: (no-up) Update bnx2x firmware to 7.8.2.0
+588fe8f57dc07478c434afb332793b91ea896bc9 NEEDED UBUNTU: SAUCE: (no-up) Remove radeon files duplicated in linux-firmware
+c4e09c38991997926099d1fdac4bef85cbdc4d72 NEEDED UBUNTU: SAUCE: (no-up) Remove sun files duplicated in linux-firmware
+14b6b1d6c7c6b42d778c4aacc0a9d68a451e5ba8 NEEDED UBUNTU: SAUCE: (no-up) Remove keyspan files duplicated in linux-firmware
+8989c6225b5d8ef4bd42337382c3fe58c4448887 NEEDED UBUNTU: SAUCE: (no-up) Remove acenic files duplicated in linux-firmware
+e9347676137c6b05dd8d1db1de39230e677ada95 NEEDED UBUNTU: SAUCE: (no-up) Remove r128 files duplicated in linux-firmware
+8a8c10cf8ebc650ed0ae9bb94de9787321fcef5b NEEDED UBUNTU: SAUCE: (no-up) Remove cxgb3 files duplicated in linux-firmware
+da35e9ad8c83e4ecc8a73b68b8cc556e8723cdb3 NEEDED UBUNTU: SAUCE: (no-up) Remove matrox files duplicated in linux-firmware
+31f0ae2767b81565b1333630f9572a09df295a04 NEEDED UBUNTU: SAUCE: (no-up) Remove tehuti files duplicated in linux-firmware
+ea4588800ea937d2044723f497632e608e5a713e NEEDED UBUNTU: SAUCE: (no-up) Remove yam files duplicated in linux-firmware
+5fa5e5d023fa3ad67d4947710062440e0b92b6f3 NEEDED UBUNTU: SAUCE: (no-up) fix highbank include path
+bcd707780091a34cd1815b8ab6cf795e13433e65 NEEDED UBUNTU: SAUCE: (no-up) vxge: Declare MODULE_FIRMWARE usage
+dbc6280f6dc2988546dd6d35055741be0a5fcbe7 NEEDED UBUNTU: SAUCE: (no-up) rds_ib_send() -- prevent local pings triggering BUG_ON()
+a381ec9f409f2e71151194c647685826aadc97f3 NEEDED UBUNTU: SAUCE: (no-up) firmware: Upgrade bnx2 to current versions
+b08d030d87047591794e27a4d8cfc05c779f9fda NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove obsolete Myricom firmware
+c62121eeb1e43d1c1bee1161f0fce00506810966 NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove cpia2 files duplicated in linux-firmware
+6ca0baacfe0faa7d6265a283a378c7530f2b3286 NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove av7110 files duplicated in linux-firmware
+492d662a9f259fb958ad3025ff4989ebb1ae1801 NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove ambassador files duplicated in linux-firmware
+9d9677898ade658ad4c68a47c2dda3aea3a9caa6 NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove advansys files duplicated in linux-firmware
+0906f131cf4b10f377dc66818a01eaab485a61f4 NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove adaptec files duplicated in linux-firmware
+fc950a48545f49a2ab8e8a465c682a4a3d504f57 NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove ti_usb_3410_5052 duplicated in linux-firmware
+6d277f4ffe2a7e2754feac527955f4e948d276cf NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove edgeport files duplicated in linux-firmware
+6cd197c9e6ecc8a3d864d9547837ce9e2ad6a6c1 NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove kaweth files duplicated in linux-firmware
+6d4aea69136e4baaa70726361e5912a24b92ed1e NEEDED UBUNTU: SAUCE: (no-up) firmware: Remove ess files duplicated in linux-firmware
+264af3894a66b66b07162df0fb367836e76c9705 NEEDED UBUNTU: SAUCE: (no-up) Remove redundant keyspan_pda firmware
+dc000f4ec05b4b34c2c1dd9a67d0a87fe1faee22 NEEDED UBUNTU: SAUCE: (no-up) Remove redundant yamaha/ds1 firmware
+6f4b585535c0c28732c46bc12ba8dda042596f15 NEEDED UBUNTU: SAUCE: (no-up) Remove redundant ositech/Xilinx7OD firmware
+a879d556097343beda5c932144f61b5320916ae2 NEEDED UBUNTU: SAUCE: (no-up) Remove redundant ttusb-budget firmware
+ec8ca911878b3aae198cfcffaae02368f555f488 NEEDED UBUNTU: SAUCE: (no-up) Remove redundant cis firmware
+482038c4e6362498269ddf66b5fe21021f7e7fcd NEEDED UBUNTU: SAUCE: (no-up) firmware: Update bnx2x to current firmware version 7.2.51
+1c5fd21e2fe45eea97a41163273add224545ddae NEEDED UBUNTU: SAUCE: (no-up) kconfig: in debug mode some 0 length message prints occur
+0685b9c73aa31e52831400e053d37f2e438cfb1b NEEDED UBUNTU: SAUCE: (no-up) Allow filtering of cpufreq drivers
+bd58f8e98fd0c05bfe34b7d8b538f35a0864c8d4 NEEDED UBUNTU: SAUCE: (no-up) tools/hv: add basic manual pages
+08347031e66a781b7876584175c0bea0d0726788 NEEDED UBUNTU: SAUCE: (no-up) elide some ioctl warnings which are known benign
+9e07077485c5e5805517bc2f6272a251eb61211d NEEDED UBUNTU: SAUCE: (no-up) Input: synapticss - Set buttonpad property for all clickpads
+43644523536605f8c650aa46e420d59192fa230b NEEDED UBUNTU: SAUCE: (no-up) Input: synaptics - add second variant of two-button clickpad
+1224fcf60e5dbe150b446c0f36f55601e50b867b NEEDED UBUNTU: SAUCE: (no-up) x86: reboot: Make Dell Latitude E6220 use reboot=pci
+e08e98d5f3eaece0a55eca47eb31d2544561f1e0 NEEDED UBUNTU: SAUCE: (no-up) x86: reboot: Make Dell Optiplex 990 use reboot=pci
+710ae591a352831d514adfecde8cbb921ab72132 NEEDED UBUNTU: SAUCE: (no-up) x86: reboot: Make Dell Optiplex 790 use reboot=pci
+075dc4fd57b7523b7d1e64df09e8fbab2298a45c NEEDED UBUNTU: SAUCE: (no-up) x86: reboot: Make Dell Latitude E6520 use reboot=pci
+11f96bb408f15ceeef5f1c089f99d974f5cd93c5 NEEDED UBUNTU: SAUCE: (no-up) add support for installed header files to ubuntu directory
+83442377bb16b0007a304e1b5f81f35139abb29c NEEDED UBUNTU: SAUCE: (no-up) Added quirk to recognize GE0301 3G modem as an interface.
+84b3a7169b338740a70d22eb408e89619acfd9db NEEDED UBUNTU: SAUCE: (no-up) fix build error with CONFIG_BLK_DEV_INITRD=n
+6a2a16f3c9e9496523125c58f788055dede4495f NEEDED UBUNTU: SAUCE: (no-up) dma-mapping: Remove WARN_ON in dma_free_coherent
+35814b8981777d9781bcf9d1a3d068b502ce90f2 NEEDED UBUNTU: SAUCE: (no-up) cdrom -- default to not locking the tray when in use
+de67e5bc6fbe1fed74ec545291efc763ec91c2b3 NEEDED UBUNTU: SAUCE: (no-up) nbd: Change default partitions per device to 15
+a5263a89adad25c3cbec28d9ed6e35c83e8de677 NEEDED UBUNTU: SAUCE: (no-up) hostap: Change initial operation mode to managed (infra)
+aa48271e2f11700129d616010dca588d7a973a03 NEEDED UBUNTU: SAUCE: (no-up) version: Implement version_signature proc file.
+3dcb633bcdca132c4f3df40338a3b387f63f9271 NEEDED UBUNTU: SAUCE: (no-up) dm-raid45: Fix incompatible ptr assignments
+7d687b18ba73d86852971a9060380a3e5657d086 NEEDED UBUNTU: SAUCE: (no-up) ubuntu: dm-raid45
+4437f9d1f3c4c6f7820bd7162ad54002e740eda8 NEEDED:debian UBUNTU: [Debian] Cloud tools
+58244d3007f8256b8fd23b941a87c97b60e54f91 NEEDED:debian UBUNTU: [Debian] add debian/gbp.conf
+04e8205c37a0d4756b675ea2229bac647ca200af NEEDED:debian UBUNTU: [Debian] remove the kernel-image firmware list on clean
+a52ad698ad07262a8735801415c139789ae88cdb NEEDED:debian UBUNTU: [debian] Dynamically generate the kernel-image udebs firmware list
+fbaf6c736d49fd8cd3d6121ea26009fbf7acd301 NEEDED:debian UBUNTU: [debian] Fix indep_hdrs_pkg_name
+0588234eed4f92f77c24090f368bd9fc419e50e0 NEEDED:debian UBUNTU: [Debian] Improve tools version message
+442d458f2ab0669d904de435bc943ffdb20b42e1 NEEDED:debian UBUNTU: [Debian] Re-sign modules after debug objcopy
+a6e1d4fd0d9dc987991216b799e6dee2b7956ad7 NEEDED:debian UBUNTU: [Debian] sort out linux-tools naming
+5fee25691328f9d46874a824d8e75c3a25be05d2 NEEDED:debian UBUNTU: [Debian] linux-tools: switch to common generic version helper
+2d0634eb9debcc3197792e52f717e7f88352b835 NEEDED:debian UBUNTU: [Debian] postinst -- fix unchanged link detection
+66e7bf3df38ce1302a32baf8142dce56c0c81586 NEEDED:debian UBUNTU: [Debian] postinst -- improve relative symlink detection with missing files
+c5e7fa9208fbe047c329c124f4d4e1320321d34f NEEDED:debian UBUNTU: [Debian] getabis: Commit new ABI directory, remove the old
+f01e594cf5b3a0f05f19ac55e78589d93b06b8fa NEEDED:debian UBUNTU: [Debian] Add hv_vss_daemon to tools package
+687fa338e27867b855c77dd79860035dde626761 NEEDED:debian UBUNTU: [debian] tools: ship 'cpupower' in linux-tools
+23e6572a962df847252e07898a40174669e8f2a5 NEEDED:debian UBUNTU: [Debian] tools: enable x86 and hyper-v
+8bd69d23b91eee555b60a59e42a04201a7d0f1e7 NEEDED:debian UBUNTU: [Debian] autopkgtest: switch Depends: to build-essential
+2a6e95d999ee4efac165d88c8106a888fc9b5a8a NEEDED:debian UBUNTU: [Debian] supply perf with appropriate prefix to ensure use of local config
+81c56fe3b06596c30b9eae372008fe37ae20f3b7 NEEDED:debian UBUNTU: [Debian] Explicitly reference gawk in build rules awk in all and arch
+82429d09555509df1d684469d97dedc756ff11b8 NEEDED:debian UBUNTU: [Debian] fix SRCPKGNAME-udebs-FLAVOUR handling for complex flavours
+754e4d69262a59fff8c893b32f199d1fbec6905b NEEDED:debian UBUNTU: [Debian] Supply PKG_ABI in kmake
+d25ef28f3ab3ead424ce856ecc849d4bd8eff932 NEEDED:debian UBUNTU: [Debian] reduce udeb rules spew
+61ce255d6b166b9c48c8a4ff2176ea15089e381d NEEDED:debian UBUNTU: [Debian] Prepare to build using arch specific compiler
+9a9792eeae3e7ec48aed14e38a8cbb3e716d5e34 NEEDED:debian UBUNTU: [Debian] do_tools=false when cross compiling
+0ea3ee0721c59ddf26e95da242e5e9ead1e21278 NEEDED:debian UBUNTU: [Debian] generate a SRCPKGNAME-udebs-FLAVOUR-di depending on all built udebs
+553cbe477ce2085e1a249d629f268d62af484682 NEEDED:debian UBUNTU: [debian] Use dh_strip
+a418dffd68c2c8b88dc3e2fbaf09ead34cfc2fed NEEDED:debian UBUNTU: (debian) get-firmware: Be more selective about copies
+4c40a10a81f5cd9310b7b5766ff731db91224f3f NEEDED:debian UBUNTU: (debian) fix internal linkage for separated header packages
+b69a501e52aff469bc0e0b3ea7fcde5bfef63af1 NEEDED:debian UBUNTU: (debian) Abort build on unresolved symbols
+15bc58fd511b00f7703d2b5d8909af935b31c1d5 NEEDED UBUNTU: [debian] ensure debian/ is not excluded from git by default
+83f903be8906fc46d258124e64803590fa5a60ac NEEDED:debian UBUNTU: [debian] Specify python2.7 for perf tools build
+817c1f4144c1318dc2e5d62e8817979a7f721ff9 NEEDED:debian UBUNTU: [debian] do not use ../.$(series)-env file
+c00e4866e6e549618a43ae3928073f552cca12a5 NEEDED:debian UBUNTU: [debian] perf: NO_LIBPERL=1
+44e01631bcd442f4f61c264af78e193518daa683 NEEDED:debian UBUNTU: [debian] perf: NO_LIBPYTHON=1
+4ec3e6d91413db7e4ba6df1f8b069aee2e7ed216 NEEDED:debian UBUNTU: [debian] Build extras package only for specific arches
+6ea3c5606dfdac9dc0348d0eeafb17207cf1efbb NEEDED:debian UBUNTU: [debian] Remove dangling symlink from headers package
+9b0d5791d9345eb165fb26e8f80837209ed677f4 NEEDED:debian UBUNTU: [debian] DTB: add support for multiple DTBs
+fc9f46c418f454b138af5d810003db5e3d7eb582 NEEDED:debian UBUNTU: [debian] Add macro to selectively disable building perf
+c054564f4aeffa8baf045df5de9707140d3fd381 NEEDED:debian UBUNTU: [debian] insertchanges -- fix to work across major version changes
+2161b4265ed31268232cb4743f6201b1be7ce1a8 NEEDED:split-debian UBUNTU: [debian] Moved scripts/fw-to-ihex.sh to debian/scripts/misc
+187fb48b5107cf8714beb306cb24610e97101cee NEEDED:debian UBUNTU: [debian] find-obsolete-firmware: Use correct path
+6b259db6215d8e1d4a31c1ba46ed39d2dafe82f1 NEEDED:debian UBUNTU: [debian] get-firmware: Filter new files through fwinfo
+ba7c4f74efc87ea48be44992774a563151926bf7 NEEDED:debian UBUNTU: [debian] hmake -j1
+ff734a2a5e6dccf8e218115f0897c0296195408f NEEDED:debian UBUNTU: [debian] add an autopkgtest rebuild test
+8b92747ff62b53c7481de518a1d9e0dcc3efadc5 NEEDED:debian UBUNTU: [debian] move build tests out of the way
+65dc3834bd439e381e4a1319f47ba198ff59bfad NEEDED:debian UBUNTU: [debian] add rebuild-test support for autopkgtest
+85df5d081a0a1cf926bc1596fce86058a980957d NEEDED:debian UBUNTU: [debian] script to detect obsolete firmware
+0486170e5ff342ec83e3ad383d490ad9c4009012 NEEDED:debian UBUNTU: [debian] Use SRCPKGNAME as prefix for indep linux headers package
+4fecdbff008d99d5084ad220223d95f2a8b33430 NEEDED:debian UBUNTU: [debian] Document binary-indep dependency chain
+e31db9848498b37cec7974a7f55f3a0125ac98f7 NEEDED:debian UBUNTU: [debian] Use dh_prep instead of 'dh_clean -k'
+f97b9b22ffed7de7d3b2f0b79ffcbd74ae75af29 NEEDED:debian UBUNTU: [debian] enforcer -- fix debugging output
+97625cbcd6c760b92fcbd46b33127817abd3f5ec NEEDED:debian UBUNTU: [debian] Add custom_override rule to allow for alternate kernel file/install
+8dadbaaed08c1aba3f59d1f8cac96284420b422f NEEDED:debian UBUNTU: [debian] Update armhf comments.
+efd7c209638bec8871bdc80b05ac2678d98342f9 NEEDED:debian UBUNTU: [debian] drop manual headers copy
+a25e7161804d73bdc21933f8ce22dffc30737c4d NEEDED:debian UBUNTU: [debian] bootstrap: switch to the new DEB_BUILD_PROFILE
+5dedd7999df59975ea0faa207f5f8ed9c8d59e96 NEEDED:debian UBUNTU: [debian] do not fail secure copy on older kernels
+a6a3b1451ca57ca799e98ba62fb0d95cfec38c5d NEEDED:debian UBUNTU: [debian] allow us to select which builds have uefi signed versions
+a34c8331e9565c7af1a04c64bb6d1c57fc2c605e NEEDED:debian UBUNTU: [debian] we already have a valid src_pkg_name
+e606ba427f5f2abe7a4ec1ab18a4d5838345821c NEEDED:debian UBUNTU: [debian] add custom upload for the kernel binary package
+0ffed1cb10d43ba7d525fcc0af93e4eb9d88e8eb NEEDED:debian UBUNTU: [debian] note directory name changes
+a6d721352cbc862a3e31652e904311739b016727 NEEDED:split-debian UBUNTU: [debian] Initial debian and ubuntu directories
+b44d72ce530f51e7a882d23c66029a63b737231b NEEDED UBUNTU: [Debian] Prep for Ubuntu build infrastructure
--- linux-4.4.0.orig/debian.master/modprobe.d/common.conf
+++ linux-4.4.0/debian.master/modprobe.d/common.conf
@@ -0,0 +1,6 @@
+# LP:1434842 -- disable OSS drivers by default to allow pulseaudio to emulate
+blacklist snd-mixer-oss
+blacklist snd-pcm-oss
+# The Infiniband Connection Manager module was marked broken in 4.4.141
+# (LP: #1790620). Instead of that we blacklist by default.
+blacklist ib_ucm
--- linux-4.4.0.orig/debian.master/reconstruct
+++ linux-4.4.0/debian.master/reconstruct
@@ -0,0 +1,292 @@
+# Recreate any symlinks created since the orig.
+[ ! -L 'ubuntu/vbox/vboxguest/include' ] && ln -sf '../include' 'ubuntu/vbox/vboxguest/include'
+[ ! -L 'ubuntu/vbox/vboxguest/r0drv' ] && ln -sf '../r0drv' 'ubuntu/vbox/vboxguest/r0drv'
+[ ! -L 'ubuntu/vbox/vboxsf/include' ] && ln -sf '../include' 'ubuntu/vbox/vboxsf/include'
+[ ! -L 'ubuntu/vbox/vboxsf/r0drv' ] && ln -sf '../r0drv' 'ubuntu/vbox/vboxsf/r0drv'
+[ ! -L 'ubuntu/vbox/vboxvideo/include' ] && ln -sf '../include' 'ubuntu/vbox/vboxvideo/include'
+[ ! -L 'ubuntu/vbox/vboxvideo/r0drv' ] && ln -sf '../r0drv' 'ubuntu/vbox/vboxvideo/r0drv'
+# Remove any files deleted from the orig.
+rm -f 'Documentation/mic/Makefile'
+rm -f 'Documentation/mic/mpssd/.gitignore'
+rm -f 'Documentation/mic/mpssd/Makefile'
+rm -f 'Documentation/mic/mpssd/micctrl'
+rm -f 'Documentation/mic/mpssd/mpss'
+rm -f 'Documentation/mic/mpssd/mpssd.c'
+rm -f 'Documentation/mic/mpssd/mpssd.h'
+rm -f 'Documentation/mic/mpssd/sysfs.c'
+rm -f 'Documentation/networking/Makefile'
+rm -f 'Documentation/networking/netlink_mmap.txt'
+rm -f 'Documentation/networking/timestamping/.gitignore'
+rm -f 'Documentation/networking/timestamping/Makefile'
+rm -f 'Documentation/networking/timestamping/hwtstamp_config.c'
+rm -f 'Documentation/networking/timestamping/timestamping.c'
+rm -f 'Documentation/networking/timestamping/txtimestamp.c'
+rm -f 'Documentation/timers/timer_stats.txt'
+rm -f 'Documentation/usb/rio.txt'
+rm -f 'arch/alpha/include/asm/bugs.h'
+rm -f 'arch/alpha/kernel/alpha_ksyms.c'
+rm -f 'arch/arm/kernel/psci-call.S'
+rm -f 'arch/arm64/kernel/psci-call.S'
+rm -f 'arch/parisc/include/asm/bugs.h'
+rm -f 'arch/powerpc/include/asm/bugs.h'
+rm -f 'arch/sparc/lib/user_fixup.c'
+rm -f 'arch/um/include/asm/bugs.h'
+rm -f 'arch/x86/kernel/cpu/bugs_64.c'
+rm -f 'arch/x86/kernel/cpu/intel_pt.h'
+rm -f 'arch/x86/kernel/cpu/perf_event.c'
+rm -f 'arch/x86/kernel/cpu/perf_event.h'
+rm -f 'arch/x86/kernel/cpu/perf_event_amd.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_amd_ibs.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_amd_iommu.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_amd_iommu.h'
+rm -f 'arch/x86/kernel/cpu/perf_event_amd_uncore.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_bts.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_cqm.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_cstate.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_ds.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_lbr.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_pt.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_rapl.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_uncore.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_uncore.h'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_knc.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_msr.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_p4.c'
+rm -f 'arch/x86/kernel/cpu/perf_event_p6.c'
+rm -f 'arch/xtensa/include/asm/bugs.h'
+rm -f 'crypto/asymmetric_keys/public_key.h'
+rm -f 'crypto/asymmetric_keys/x509_rsakey.asn1'
+rm -f 'drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/fiji_ppsmc.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/fiji_smumgr.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/smu7.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/smu7_discrete.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/smu7_fusion.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/smu8.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/smu8_fusion.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_cz.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/tonga_ppsmc.h'
+rm -f 'drivers/gpu/drm/amd/amdgpu/tonga_smumgr.h'
+rm -f 'drivers/i2c/busses/i2c-octeon.c'
+rm -f 'drivers/media/i2c/adv7511.c'
+rm -f 'drivers/scsi/ibmvscsi/viosrp.h'
+rm -f 'drivers/usb/misc/rio500.c'
+rm -f 'drivers/usb/misc/rio500_usb.h'
+rm -f 'drivers/video/fbdev/sh_mobile_hdmi.c'
+rm -f 'firmware/acenic/tg1.bin.ihex'
+rm -f 'firmware/acenic/tg2.bin.ihex'
+rm -f 'firmware/adaptec/starfire_rx.bin.ihex'
+rm -f 'firmware/adaptec/starfire_tx.bin.ihex'
+rm -f 'firmware/advansys/3550.bin.ihex'
+rm -f 'firmware/advansys/38C0800.bin.ihex'
+rm -f 'firmware/advansys/38C1600.bin.ihex'
+rm -f 'firmware/advansys/mcode.bin.ihex'
+rm -f 'firmware/atmsar11.HEX'
+rm -f 'firmware/av7110/Boot.S'
+rm -f 'firmware/av7110/bootcode.bin.ihex'
+rm -f 'firmware/bnx2/bnx2-mips-06-6.2.1.fw.ihex'
+rm -f 'firmware/bnx2/bnx2-mips-09-6.2.1a.fw.ihex'
+rm -f 'firmware/bnx2x/bnx2x-e1-6.2.9.0.fw.ihex'
+rm -f 'firmware/bnx2x/bnx2x-e1h-6.2.9.0.fw.ihex'
+rm -f 'firmware/bnx2x/bnx2x-e2-6.2.9.0.fw.ihex'
+rm -f 'firmware/cis/3CCFEM556.cis.ihex'
+rm -f 'firmware/cis/3CXEM556.cis.ihex'
+rm -f 'firmware/cis/COMpad2.cis.ihex'
+rm -f 'firmware/cis/COMpad4.cis.ihex'
+rm -f 'firmware/cis/DP83903.cis.ihex'
+rm -f 'firmware/cis/LA-PCM.cis.ihex'
+rm -f 'firmware/cis/MT5634ZLX.cis.ihex'
+rm -f 'firmware/cis/NE2K.cis.ihex'
+rm -f 'firmware/cis/PCMLM28.cis.ihex'
+rm -f 'firmware/cis/PE-200.cis.ihex'
+rm -f 'firmware/cis/PE520.cis.ihex'
+rm -f 'firmware/cis/RS-COM-2P.cis.ihex'
+rm -f 'firmware/cis/SW_555_SER.cis.ihex'
+rm -f 'firmware/cis/SW_7xx_SER.cis.ihex'
+rm -f 'firmware/cis/SW_8xx_SER.cis.ihex'
+rm -f 'firmware/cis/tamarack.cis.ihex'
+rm -f 'firmware/cpia2/stv0672_vp4.bin.ihex'
+rm -f 'firmware/cxgb3/ael2005_opt_edc.bin.ihex'
+rm -f 'firmware/cxgb3/ael2005_twx_edc.bin.ihex'
+rm -f 'firmware/cxgb3/ael2020_twx_edc.bin.ihex'
+rm -f 'firmware/cxgb3/t3b_psram-1.1.0.bin.ihex'
+rm -f 'firmware/cxgb3/t3c_psram-1.1.0.bin.ihex'
+rm -f 'firmware/dsp56k/bootstrap.asm'
+rm -f 'firmware/dsp56k/bootstrap.bin.ihex'
+rm -f 'firmware/edgeport/boot.H16'
+rm -f 'firmware/edgeport/boot2.H16'
+rm -f 'firmware/edgeport/down.H16'
+rm -f 'firmware/edgeport/down2.H16'
+rm -f 'firmware/edgeport/down3.bin.ihex'
+rm -f 'firmware/ess/maestro3_assp_kernel.fw.ihex'
+rm -f 'firmware/ess/maestro3_assp_minisrc.fw.ihex'
+rm -f 'firmware/kaweth/new_code.bin.ihex'
+rm -f 'firmware/kaweth/new_code_fix.bin.ihex'
+rm -f 'firmware/kaweth/trigger_code.bin.ihex'
+rm -f 'firmware/kaweth/trigger_code_fix.bin.ihex'
+rm -f 'firmware/keyspan/mpr.HEX'
+rm -f 'firmware/keyspan/usa18x.HEX'
+rm -f 'firmware/keyspan/usa19.HEX'
+rm -f 'firmware/keyspan/usa19qi.HEX'
+rm -f 'firmware/keyspan/usa19qw.HEX'
+rm -f 'firmware/keyspan/usa19w.HEX'
+rm -f 'firmware/keyspan/usa28.HEX'
+rm -f 'firmware/keyspan/usa28x.HEX'
+rm -f 'firmware/keyspan/usa28xa.HEX'
+rm -f 'firmware/keyspan/usa28xb.HEX'
+rm -f 'firmware/keyspan/usa49w.HEX'
+rm -f 'firmware/keyspan/usa49wlc.HEX'
+rm -f 'firmware/keyspan_pda/keyspan_pda.HEX'
+rm -f 'firmware/keyspan_pda/keyspan_pda.S'
+rm -f 'firmware/keyspan_pda/xircom_pgs.HEX'
+rm -f 'firmware/keyspan_pda/xircom_pgs.S'
+rm -f 'firmware/matrox/g200_warp.H16'
+rm -f 'firmware/matrox/g400_warp.H16'
+rm -f 'firmware/mts_cdma.fw.ihex'
+rm -f 'firmware/mts_edge.fw.ihex'
+rm -f 'firmware/mts_gsm.fw.ihex'
+rm -f 'firmware/myricom/lanai.bin.ihex'
+rm -f 'firmware/ositech/Xilinx7OD.bin.ihex'
+rm -f 'firmware/r128/r128_cce.bin.ihex'
+rm -f 'firmware/radeon/R100_cp.bin.ihex'
+rm -f 'firmware/radeon/R200_cp.bin.ihex'
+rm -f 'firmware/radeon/R300_cp.bin.ihex'
+rm -f 'firmware/radeon/R420_cp.bin.ihex'
+rm -f 'firmware/radeon/R520_cp.bin.ihex'
+rm -f 'firmware/radeon/R600_me.bin.ihex'
+rm -f 'firmware/radeon/R600_pfp.bin.ihex'
+rm -f 'firmware/radeon/RS600_cp.bin.ihex'
+rm -f 'firmware/radeon/RS690_cp.bin.ihex'
+rm -f 'firmware/radeon/RS780_me.bin.ihex'
+rm -f 'firmware/radeon/RS780_pfp.bin.ihex'
+rm -f 'firmware/radeon/RV610_me.bin.ihex'
+rm -f 'firmware/radeon/RV610_pfp.bin.ihex'
+rm -f 'firmware/radeon/RV620_me.bin.ihex'
+rm -f 'firmware/radeon/RV620_pfp.bin.ihex'
+rm -f 'firmware/radeon/RV630_me.bin.ihex'
+rm -f 'firmware/radeon/RV630_pfp.bin.ihex'
+rm -f 'firmware/radeon/RV635_me.bin.ihex'
+rm -f 'firmware/radeon/RV635_pfp.bin.ihex'
+rm -f 'firmware/radeon/RV670_me.bin.ihex'
+rm -f 'firmware/radeon/RV670_pfp.bin.ihex'
+rm -f 'firmware/radeon/RV710_me.bin.ihex'
+rm -f 'firmware/radeon/RV710_pfp.bin.ihex'
+rm -f 'firmware/radeon/RV730_me.bin.ihex'
+rm -f 'firmware/radeon/RV730_pfp.bin.ihex'
+rm -f 'firmware/radeon/RV770_me.bin.ihex'
+rm -f 'firmware/radeon/RV770_pfp.bin.ihex'
+rm -f 'firmware/sun/cassini.bin.ihex'
+rm -f 'firmware/tehuti/bdx.bin.ihex'
+rm -f 'firmware/ti_3410.fw.ihex'
+rm -f 'firmware/ti_5052.fw.ihex'
+rm -f 'firmware/ttusb-budget/dspbootcode.bin.ihex'
+rm -f 'firmware/vicam/firmware.H16'
+rm -f 'firmware/yam/1200.bin.ihex'
+rm -f 'firmware/yam/9600.bin.ihex'
+rm -f 'firmware/yamaha/ds1_ctrl.fw.ihex'
+rm -f 'firmware/yamaha/ds1_dsp.fw.ihex'
+rm -f 'firmware/yamaha/ds1e_ctrl.fw.ihex'
+rm -f 'include/asm-generic/bugs.h'
+rm -f 'include/crypto/vmac.h'
+rm -f 'include/linux/kd.h'
+rm -f 'include/video/sh_mobile_hdmi.h'
+rm -f 'kernel/elfcore.c'
+rm -f 'kernel/futex_compat.c'
+rm -f 'kernel/time/timer_stats.c'
+rm -f 'net/bluetooth/ecc.c'
+rm -f 'net/bluetooth/ecc.h'
+rm -f 'net/sched/cls_rsvp.c'
+rm -f 'net/sched/cls_rsvp.h'
+rm -f 'net/sched/cls_rsvp6.c'
+rm -f 'net/sched/cls_tcindex.c'
+rm -f 'tools/perf/util/include/asm/alternative-asm.h'
+rm -f 'tools/perf/util/include/asm/unistd_32.h'
+rm -f 'tools/perf/util/include/asm/unistd_64.h'
+chmod +x 'Documentation/mic/mpssd/micctrl'
+chmod +x 'Documentation/mic/mpssd/mpss'
+chmod +x 'debian/cloud-tools/hv_get_dhcp_info'
+chmod +x 'debian/cloud-tools/hv_get_dns_info'
+chmod +x 'debian/cloud-tools/hv_set_ifconfig'
+chmod +x 'debian/rules'
+chmod +x 'debian/scripts/build-fit'
+chmod +x 'debian/scripts/config-check'
+chmod +x 'debian/scripts/control-create'
+chmod +x 'debian/scripts/dkms-build'
+chmod +x 'debian/scripts/file-downloader'
+chmod +x 'debian/scripts/link-headers'
+chmod +x 'debian/scripts/misc/final-checks'
+chmod +x 'debian/scripts/misc/find-obsolete-firmware'
+chmod +x 'debian/scripts/misc/fw-to-ihex.sh'
+chmod +x 'debian/scripts/misc/gen-auto-reconstruct'
+chmod +x 'debian/scripts/misc/get-firmware'
+chmod +x 'debian/scripts/misc/git-ubuntu-log'
+chmod +x 'debian/scripts/misc/insert-changes.pl'
+chmod +x 'debian/scripts/misc/insert-mainline-changes'
+chmod +x 'debian/scripts/misc/insert-ubuntu-changes'
+chmod +x 'debian/scripts/misc/kernelconfig'
+chmod +x 'debian/scripts/misc/retag'
+chmod +x 'debian/scripts/misc/splitconfig.pl'
+chmod +x 'debian/scripts/misc/update-aufs.sh'
+chmod +x 'debian/scripts/misc/update-zfs.sh'
+chmod +x 'debian/scripts/module-inclusion'
+chmod +x 'debian/scripts/retpoline-extract'
+chmod +x 'debian/scripts/retpoline-extract-one'
+chmod +x 'debian/templates/extra.postinst.in'
+chmod +x 'debian/templates/extra.postrm.in'
+chmod +x 'debian/templates/headers.postinst.in'
+chmod +x 'debian/templates/image.postinst.in'
+chmod +x 'debian/templates/image.postrm.in'
+chmod +x 'debian/templates/image.preinst.in'
+chmod +x 'debian/templates/image.prerm.in'
+chmod +x 'debian/tests-build/check-aliases'
+chmod +x 'debian/tests/rebuild'
+chmod +x 'debian/tests/ubuntu-regression-suite'
+chmod +x 'spl/autogen.sh'
+chmod +x 'spl/config/compile'
+chmod +x 'spl/config/config.guess'
+chmod +x 'spl/config/config.sub'
+chmod +x 'spl/config/depcomp'
+chmod +x 'spl/config/install-sh'
+chmod +x 'spl/config/missing'
+chmod +x 'spl/configure'
+chmod +x 'spl/copy-builtin'
+chmod +x 'spl/cp'
+chmod +x 'spl/scripts/check.sh'
+chmod +x 'spl/scripts/dkms.mkconf'
+chmod +x 'spl/scripts/dkms.postbuild'
+chmod +x 'tools/hv/bondvf.sh'
+chmod +x 'tools/testing/selftests/net/in_netns.sh'
+chmod +x 'ubuntu/i915/intel_hdmi.c'
+chmod +x 'ubuntu/opennsl/OpenNSL/include/sal/commdefs.h'
+chmod +x 'ubuntu/opennsl/OpenNSL/include/shared/gport.h'
+chmod +x 'ubuntu/opennsl/OpenNSL/include/shared/phyconfig.h'
+chmod +x 'ubuntu/opennsl/OpenNSL/include/shared/phyreg.h'
+chmod +x 'ubuntu/opennsl/OpenNSL/include/shared/port.h'
+chmod +x 'ubuntu/opennsl/OpenNSL/include/shared/types.h'
+chmod +x 'ubuntu/opennsl/OpenNSL/include/shared/util.h'
+chmod +x 'ubuntu/vbox-update'
+chmod +x 'ubuntu/vbox/vboxguest/do_Module.symvers'
+chmod +x 'ubuntu/vbox/vboxsf/do_Module.symvers'
+chmod +x 'ubuntu/vbox/vboxvideo/do_Module.symvers'
+chmod +x 'zfs/autogen.sh'
+chmod +x 'zfs/config/compile'
+chmod +x 'zfs/config/config.guess'
+chmod +x 'zfs/config/config.sub'
+chmod +x 'zfs/config/depcomp'
+chmod +x 'zfs/config/install-sh'
+chmod +x 'zfs/config/missing'
+chmod +x 'zfs/configure'
+chmod +x 'zfs/contrib/dracut/90zfs/export-zfs.sh.in'
+chmod +x 'zfs/contrib/dracut/90zfs/module-setup.sh.in'
+chmod +x 'zfs/contrib/dracut/90zfs/mount-zfs.sh.in'
+chmod +x 'zfs/contrib/dracut/90zfs/parse-zfs.sh.in'
+chmod +x 'zfs/contrib/dracut/90zfs/zfs-lib.sh.in'
+chmod +x 'zfs/contrib/initramfs/hooks/zfs'
+chmod +x 'zfs/copy-builtin'
+chmod +x 'zfs/cp'
+exit 0
--- linux-4.4.0.orig/debian.master/rules.d/amd64.mk
+++ linux-4.4.0/debian.master/rules.d/amd64.mk
@@ -0,0 +1,21 @@
+human_arch	= 64 bit x86
+build_arch	= x86_64
+header_arch	= $(build_arch)
+defconfig	= defconfig
+flavours	= generic lowlatency
+build_image	= bzImage
+kernel_file	= arch/$(build_arch)/boot/bzImage
+install_file	= vmlinuz
+loader		= grub
+vdso		= vdso_install
+no_dumpfile	= true
+uefi_signed     = true
+do_tools_usbip  = true
+do_tools_cpupower = true
+do_tools_perf   = true
+do_tools_x86	= true
+do_tools_hyperv	= true
+do_extras_package = true
+do_tools_common = true
+do_zfs		= true
+do_dkms_wireguard = true
--- linux-4.4.0.orig/debian.master/rules.d/arm64.mk
+++ linux-4.4.0/debian.master/rules.d/arm64.mk
@@ -0,0 +1,20 @@
+human_arch	= ARMv8
+build_arch	= arm64
+header_arch	= arm64
+defconfig	= defconfig
+flavours	= generic
+build_image	= Image
+kernel_file	= arch/$(build_arch)/boot/Image
+install_file	= vmlinuz
+no_dumpfile = true
+
+loader		= grub
+vdso		= vdso_install
+
+do_tools_usbip  = true
+do_tools_cpupower = true
+do_tools_perf   = true
+
+do_dtbs		= true
+do_zfs		= true
+do_dkms_wireguard = true
--- linux-4.4.0.orig/debian.master/rules.d/s390x.mk
+++ linux-4.4.0/debian.master/rules.d/s390x.mk
@@ -0,0 +1,20 @@
+human_arch      = System 390x
+build_arch      = s390
+header_arch     = $(build_arch)
+defconfig       = defconfig
+flavours        = generic
+build_image	= bzImage
+kernel_file	= arch/$(build_arch)/boot/bzImage
+install_file	= vmlinuz
+
+vdso		= vdso_install
+no_dumpfile	= true
+
+do_extras_package = true
+
+do_tools_usbip    = true
+do_tools_cpupower = true
+do_tools_perf     = true
+
+do_zfs		= true
+do_dkms_wireguard = true
--- linux-4.4.0.orig/debian.master/rules.d/x32.mk
+++ linux-4.4.0/debian.master/rules.d/x32.mk
@@ -0,0 +1,14 @@
+human_arch	= 64 bit x86 (32 bit userspace)
+build_arch	= x86_64
+header_arch	= $(build_arch)
+defconfig	= defconfig
+flavours	= 
+build_image	= bzImage
+kernel_file	= arch/$(build_arch)/boot/bzImage
+install_file	= vmlinuz
+loader		= grub
+vdso		= vdso_install
+no_dumpfile	= true
+uefi_signed     = true
+
+do_flavour_image_package = false
--- linux-4.4.0.orig/debian.master/tracking-bug
+++ linux-4.4.0/debian.master/tracking-bug
@@ -0,0 +1 @@
+2144095 s2026.02.09-1
--- linux-4.4.0.orig/debian.master/upstream-stable
+++ linux-4.4.0/debian.master/upstream-stable
@@ -0,0 +1,3 @@
+# The following upstream stable releases have been ported:
+[upstream-stable]
+    linux-4.4.y = v4.4.262
--- linux-4.4.0.orig/debian.master/variants
+++ linux-4.4.0/debian.master/variants
@@ -0,0 +1,2 @@
+-4.4
+--
--- linux-4.4.0.orig/debian/changelog
+++ linux-4.4.0/debian/changelog
@@ -0,0 +1,42623 @@
+linux (4.4.0-279.313) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-279.313 -proposed tracker (LP: #2144095)
+
+  * CVE-2021-47254
+    - gfs2: Fix use-after-free in gfs2_glock_shrink_scan
+
+  * CVE-2024-46777
+    - udf: Avoid excessive partition lengths
+
+  * CVE-2021-47145
+    - btrfs: do not BUG_ON in link_to_fixup_dir
+
+  * CVE-2025-21735
+    - NFC: nci: Add bounds checking in nci_hci_create_pipe()
+
+  * CVE-2021-47142
+    - drm/amdgpu: Fix a use-after-free
+
+  * CVE-2026-23074
+    - net/sched: Enforce that teql can only be used as root qdisc
+
+  * CVE-2026-23060
+    - crypto: authencesn - reject too-short AAD (assoclen<8) to match ESP/ESN
+      spec
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 13 Mar 2026 10:13:30 +0100
+
+linux (4.4.0-278.312) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-278.312 -proposed tracker (LP: #2140783)
+
+  * CVE-2024-47659
+    - smack: tcp: ipv4, fix incorrect labeling
+
+  * CVE-2025-21704
+    - cdc-acm: reassemble fragmented notifications
+    - usb: cdc-acm: Check control transfer buffer size before access
+    - usb: cdc-acm: Fix handling of oversized fragments
+    - USB: cdc-acm: rework notification_buffer resizing
+
+  * CVE-2022-48875
+    - wifi: mac80211: sdata can be NULL during AMPDU start
+
+  * CVE-2024-56593
+    - wifi: brcmfmac: Fix oops due to NULL pointer dereference in
+      brcmf_sdiod_sglist_rw()
+
+  * CVE-2024-56548
+    - hfsplus: don't query the device logical block size multiple times
+
+  * CVE-2022-49267
+    - mmc: core: use sysfs_emit() instead of sprintf()
+
+  * CVE-2024-49927
+    - x86/ioapic: Handle allocation failures gracefully
+
+  * CVE-2025-40256
+    - xfrm: also call xfrm_state_delete_tunnel at destroy time for states that
+      were never added
+
+  * CVE-2025-40215
+    - xfrm: delete x->tunnel as we delete x
+
+  * CVE-2021-47599
+    - btrfs: use RCU in btrfs_show_devname for device list traversal
+    - btrfs: convert latest_bdev type to btrfs_device and rename
+    - btrfs: use latest_dev in btrfs_show_devname
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 06 Feb 2026 18:49:47 +0100
+
+linux (4.4.0-277.311) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-277.311 -proposed tracker (LP: #2137920)
+
+  * CVE-2024-49959
+    - jbd2: stop waiting for space when jbd2_cleanup_journal_tail() returns
+      error
+
+  * CVE-2024-56606
+    - af_packet: avoid erroring out after sock_init_data() in packet_create()
+
+  * CVE-2021-47104
+    - IB/qib: Fix memory leak in qib_user_sdma_queue_pkts()
+
+  * CVE-2021-47485
+    - IB/qib: Protect from buffer overflow in struct qib_user_sdma_pkt fields
+
+  * CVE-2024-53164
+    - net: sched: fix ordering of qlen adjustment
+
+  * CVE-2025-39993
+    - media: imon: reorganize serialization
+    - media: rc: fix races with imon_disconnect()
+
+  * CVE-2024-50195
+    - posix-clock: Fix missing timespec64 check in pc_clock_settime()
+    - posix-clock: posix-clock: Fix unbalanced locking in pc_clock_settime()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 09 Jan 2026 17:17:07 +0100
+
+linux (4.4.0-276.310) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-276.310 -proposed tracker (LP: #2131920)
+
+  * crypto: af_alg: sendmsg() on AF_ALG sockets for skcipher fails with EBUSY
+    (LP: #2131904)
+    - crypto: algif_aead - fix uninitialized ctx->init
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Wed, 19 Nov 2025 15:58:58 +0100
+
+linux (4.4.0-275.309) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-275.309 -proposed tracker (LP: #2131305)
+
+  * CVE-2025-21855
+    - ibmvnic: Don't reference skb after sending to VIOS
+
+  * CVE-2024-53112
+    - ocfs2: uncache inode which has failed entering the group
+
+  * CVE-2021-47269
+    - usb: dwc3: ep0: fix NULL pointer exception
+
+  * CVE-2021-47146
+    - mld: fix panic in mld_newpack()
+
+  * CVE-2021-47385
+    - hwmon: (w83792d) Fix NULL pointer dereference by removing unnecessary
+      structure field
+
+  * CVE-2025-40018
+    - ipvs: Defer ip_vs_ftp unregister during netns cleanup
+
+  * CVE-2024-50179
+    - ceph: remove the incorrect Fw reference check when dirtying pages
+
+  * CVE-2021-47634
+    - ubi: Fix race condition between ctrl_cdev_ioctl and ubi_cdev_ioctl
+
+  * CVE-2025-21722
+    - nilfs2: do not force clear folio if buffer is referenced
+    - nilfs2: protect access to buffers with no active references
+
+  * CVE-2022-49026
+    - e100: Fix possible use after free in e100_xmit_prepare
+
+  * CVE-2025-21715
+    - net: davicom: fix UAF in dm9000_drv_remove
+
+  * CVE-2025-39964
+    - crypto: af_alg - Disallow concurrent writes in af_alg_sendmsg
+    - crypto: af_alg - Fix incorrect boolean values in af_alg_ctx
+
+  * CVE-2025-38666
+    - net: appletalk: fix kerneldoc warnings
+    - net: appletalk: Fix use-after-free in AARP proxy probe
+
+  * CVE-2024-53217
+    - nfsd: restore callback functionality for NFSv4.0
+
+  * CVE-2024-49935
+    - ACPI: PAD: fix crash in exit_round_robin()
+
+  * CVE-2024-50095
+    - IB/mad: pass ib_mad_send_buf explicitly to the recv_handler
+    - IB/mad: Issue complete whenever decrements agent refcount
+    - RDMA/mad: Improve handling of timed out WRs of mad agent
+
+  * CVE-2024-50067
+    - uprobes: encapsulate preparation of uprobe args buffer
+    - uprobe: avoid out-of-bounds memory access of fetching args
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 14 Nov 2025 17:44:16 +0100
+
+linux (4.4.0-274.308) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-274.308 -proposed tracker (LP: #2127262)
+
+  * VMSCAPE CVE-2025-40300 (LP: #2124105) // CVE-2025-40300
+    - Documentation/hw-vuln: Add VMSCAPE documentation
+    - x86/vmscape: Enumerate VMSCAPE bug
+    - x86/vmscape: Add conditional IBPB mitigation
+    - x86/vmscape: Enable the mitigation
+    - x86/bugs: Move cpu_bugs_smt_update() down
+    - x86/vmscape: Warn when STIBP is disabled with SMT
+    - x86/cpu: Add old Intel CPUs to affected list
+    - [Config] enable CONFIG_MITIGATION_VMSCAPE
+
+  * CVE-2023-52574
+    - team: fix null-ptr-deref when team device type is changed
+
+  * CVE-2024-53124
+    - net: fix data-races around sk->sk_forward_alloc
+
+  * CVE-2024-50006
+    - ext4: fix i_data_sem unlock order in ext4_ind_migrate()
+
+  * CVE-2024-53150
+    - ALSA: usb-audio: Fix out of bounds reads when finding clock sources
+
+  * CVE-2025-37838
+    - HSI: ssi_protocol: Fix use after free vulnerability in ssi_protocol
+      Driver Due to Race Condition
+
+  * CVE-2021-47294 // CVE-2024-41006
+    - netrom: Fix a memory leak in nr_heartbeat_expiry()
+
+  * CVE-2021-47294
+    - netrom: Decrease sock refcount when sock timers expire
+    - netrom: Fix use-after-free of a listening socket.
+
+  * CVE-2024-50299
+    - sctp: properly validate chunk size in sctp_sf_ootb()
+
+  * CVE-2024-56767
+    - dmaengine: at_xdmac: avoid null_prt_deref in at_xdmac_prep_dma_memset
+
+  * CVE-2023-52650
+    - drm/tegra: dsi: Add missing check for of_find_device_by_node
+
+  * CVE-2021-47330
+    - tty: serial: 8250: serial_cs: Fix a memory leak in error handling path
+
+  * CVE-2025-38352
+    - posix-cpu-timers: fix race between handle_posix_cpu_timers() and
+      posix_cpu_timer_del()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 10 Oct 2025 22:32:44 +0200
+
+linux (4.4.0-273.307) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-273.307 -proposed tracker (LP: #2124194)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * CVE-2024-49924
+    - fbdev: pxafb: Fix possible use after free in pxafb_task()
+
+  * CVE-2025-37785
+    - ext4: optimize __ext4_check_dir_entry()
+    - ext4: fix OOB read when checking dotdot dir
+
+  * CVE-2021-47319
+    - virtio-blk: Fix memory leak among suspend/resume procedure
+
+  * CVE-2025-21796
+    - nfsd: clear acl_access/acl_default after releasing them
+
+  * CVE-2024-27078
+    - media: v4l2-tpg: fix some memleaks in tpg_alloc
+
+  * CVE-2025-38617
+    - net/packet: fix a race in packet_set_ring() and packet_notifier()
+
+  * CVE-2025-38618
+    - vsock: Do not allow binding to VMADDR_PORT_ANY
+
+  * CVE-2024-35849
+    - btrfs: fix information leak in btrfs_ioctl_logical_to_ino()
+
+  * CVE-2021-47589
+    - igbvf: fix double free in `igbvf_probe`
+
+  * CVE-2021-47149
+    - net: fujitsu: fix potential null-ptr-deref
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Wed, 17 Sep 2025 21:22:09 +0200
+
+linux (4.4.0-272.306) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-272.306 -proposed tracker (LP: #2119753)
+
+  * CVE-2024-27074
+    - media: go7007: fix a memleak in go7007_load_encoder
+
+  * CVE-2024-50051
+    - spi: mpc52xx: Add cancel_work_sync before module remove
+
+  * CVE-2024-53130
+    - nilfs2: fix null-ptr-deref in block_dirty_buffer tracepoint
+
+  * CVE-2024-53131
+    - nilfs2: fix null-ptr-deref in block_touch_buffer tracepoint
+
+  * CVE-2023-52477
+    - usb: hub: Guard against accesses to uninitialized BOS descriptors
+
+  * CVE-2021-47345
+    - RDMA/cma: Fix rdma_resolve_route() memory leak
+
+  * CVE-2024-50202
+    - make ext2_get_page() and friends work without external serialization
+    - nilfs2: Remove check for PageError
+    - nilfs2: return the mapped address from nilfs_get_page()
+    - nilfs2: propagate directory read errors from nilfs_find_entry()
+
+  * CVE-2024-57996 // CVE-2025-37752
+    - net_sched: sch_sfq: move the limit validation
+
+  * CVE-2024-47685
+    - skbuff/mac80211: introduce and use skb_put_zero()
+    - netfilter: nf_reject_ipv6: fix nf_reject_ip6_tcphdr_put()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Thu, 07 Aug 2025 16:51:14 +0200
+
+linux (4.4.0-271.305) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-271.305 -proposed tracker (LP: #2116540)
+
+  * CVE-2023-52975
+    - scsi: libiscsi: Fix use-after-free race during iscsi_session_teardown
+    - scsi: iscsi: Move pool freeing
+    - scsi: iscsi_tcp: Fix UAF during logout when accessing the shost
+      ipaddress
+
+  * CVE-2024-49883
+    - ext4: aovid use-after-free in ext4_ext_insert_extent()
+
+  * CVE-2024-53239
+    - ALSA: 6fire: Use common error handling code in usb6fire_chip_probe()
+    - ALSA: 6fire: Release resources at card release
+
+  * CVE-2024-49950
+    - Bluetooth: L2CAP: Fix uaf in l2cap_connect
+    - Bluetooth: hci_core: Fix calling mgmt_device_connected
+
+  * CVE-2024-50073
+    - tty: n_gsm: Fix use-after-free in gsm_cleanup_mux
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 11 Jul 2025 14:38:45 +0200
+
+linux (4.4.0-270.304) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-270.304 -proposed tracker (LP: #2114482)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update variants
+
+  * CVE-2021-47260
+    - NFS: Fix a potential NULL dereference in nfs_get_client()
+
+  * CVE-2024-53197
+    - ALSA: usb-audio: Fix potential out-of-bound accesses for Extigy and Mbox
+      devices
+    - ALSA: usb-audio: Fix a DMA to stack memory bug
+
+  * CVE-2021-47576
+    - scsi: scsi_debug: Sanity check block descriptor length in
+      resp_mode_select()
+
+  * CVE-2024-46787
+    - userfaultfd: fix checks for huge PMDs
+
+  * CVE-2025-37798
+    - net_sched: call qlen_notify only if child qdisc is empty
+    - sch_htb: make htb_qlen_notify() idempotent
+    - sch_htb: make htb_deactivate() idempotent
+    - sch_drr: make drr_qlen_notify() idempotent
+    - sch_hfsc: make hfsc_qlen_notify() idempotent
+    - sch_qfq: make qfq_qlen_notify() idempotent
+    - codel: remove sch->q.qlen check before qdisc_tree_reduce_backlog()
+
+  * CVE-2022-49909
+    - Bluetooth: L2CAP: fix use-after-free in l2cap_conn_del()
+
+  * CVE-2024-50116
+    - nilfs2: fix kernel bug due to missing clearing of buffer delay flag
+
+  * CVE-2024-49958
+    - ocfs2: reserve space for inline xattr before attaching reflink tree
+
+  * CVE-2021-47195
+    - spi: fix use-after-free of the add_lock mutex
+
+  * CVE-2021-47469
+    - spi: Fix deadlock when adding SPI controllers on SPI buses
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 13 Jun 2025 18:47:34 +0200
+
+linux (4.4.0-269.303) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-269.303 -proposed tracker (LP: #2110969)
+
+  * CVE-2024-56596
+    - jfs: fix array-index-out-of-bounds in jfs_readdir
+
+  * CVE-2024-53168
+    - sock: Change the netns_core member name.
+    - sock: Move the socket inuse to namespace.
+    - sock: Hide unused variable when !CONFIG_PROC_FS.
+    - sock: fix /proc/net/sockstat underflow in sk_clone_lock()
+    - net: make sock_inuse_add() available
+    - sunrpc: fix one UAF issue caused by sunrpc kernel tcp socket
+
+  * CVE-2024-42301
+    - dev/parport: fix the array out-of-bounds risk
+    - parport: Proper fix for array out-of-bounds access
+
+  * CVE-2021-47211
+    - ALSA: usb-audio: fix null pointer dereference on pointer cs_desc
+
+  * CVE-2024-47701
+    - ext4: avoid OOB when system.data xattr changes underneath the filesystem
+
+  * CVE-2024-57850
+    - jffs2: Prevent rtime decompress memory corruption
+    - jffs2: Fix rtime decompressor
+
+  * CVE-2023-52458
+    - block: check partition alignment
+    - block: add check that partition length needs to be aligned with block size
+
+  * CVE-2021-47353
+    - udf: Fix NULL pointer dereference in udf_symlink function
+
+  * CVE-2024-26966
+    - clk: qcom: mmcc-apq8084: fix terminating of frequency table arrays
+
+  * CVE-2024-56551
+    - drm/amdgpu: fix usage slab after free
+
+  * CVE-2024-53155
+    - ocfs2: fix uninitialized value in ocfs2_file_read_iter()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 16 May 2025 14:27:44 +0200
+
+linux (4.4.0-268.302) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-268.302 -proposed tracker (LP: #2107200)
+
+  * CVE-2021-46959
+    - spi: Fix use-after-free with devm_spi_alloc_*
+
+  * CVE-2021-47245
+    - netfilter: synproxy: Fix out of bounds when parsing TCP options
+
+  * CVE-2023-52741
+    - cifs: Fix use-after-free in rdata->read_into_pages()
+
+  * CVE-2024-47709
+    - can: bcm: Clear bo->bcm_proc_read after remove_proc_entry().
+
+  * CVE-2024-46771
+    - can: bcm: Remove proc entry when dev is unregistered.
+
+  * CVE-2021-47506
+    - nfsd: fix use-after-free due to delegation race
+
+  * CVE-2025-21971
+    - net_sched: Prevent creation of classes with TC_H_ROOT
+
+  * CVE-2024-53140
+    - netlink: terminate outstanding dump on socket close
+
+  * CVE-2021-47150
+    - net: fec: fix the potential memory leak in fec_enet_init()
+
+  * CVE-2021-47587
+    - net: systemport: Add global locking for descriptor lifecycle
+
+  * CVE-2024-53063
+    - media: dvbdev: prevent the risk of out of memory access
+    - media: dvbdev: fix the logic when DVB_DYNAMIC_MINORS is not set
+
+  * CVE-2024-39493
+    - crypto: qat - Fix ADF_DEV_RESET_SYNC memory leak
+
+  * CVE-2024-26974
+    - crypto: qat - fix double free during reset
+    - crypto: qat - resolve race condition during AER recovery
+
+  * CVE-2024-26996
+    - usb: gadget: f_ncm: Fix UAF ncm object at re-bind after usb ep transport
+      error
+
+  * CVE-2024-46780
+    - nilfs2: protect references to superblock parameters exposed in sysfs
+
+  * CVE-2024-50237
+    - wifi: mac80211: do not pass a stopped vif to the driver in .get_txpower
+
+  * CVE-2024-26689
+    - ceph: prevent use-after-free in encode_cap_msg()
+
+  * CVE-2024-49944
+    - sctp: set sk_state back to CLOSED if autobind fails in sctp_listen_start
+
+  * CVE-2024-53066
+    - nfs: Fix KMSAN warning in decode_getfattr_attrs()
+
+  * CVE-2021-47191
+    - scsi: scsi_debug: Fix out-of-bound read in resp_readcap16()
+
+  * CVE-2024-56598
+    - jfs: array-index-out-of-bounds fix in dtReadFirst
+
+  * CVE-2024-56650
+    - netfilter: x_tables: fix LED ID check in led_tg_check()
+
+  * CVE-2024-53173
+    - NFSv4.0: Fix a use-after-free problem in the asynchronous open()
+
+  * CVE-2024-56631
+    - scsi: sg: Fix slab-use-after-free read in sg_release()
+
+  * CVE-2024-50256
+    - netfilter: nf_reject_ipv6: fix potential crash in nf_send_reset6()
+
+  * CVE-2024-56770
+    - net/sched: netem: account for backlog updates from child qdisc
+    - netem: Update sch->q.qlen before qdisc_tree_reduce_backlog()
+
+  * CVE-2024-35864
+    - smb: client: fix potential UAF in cifs_debug_files_proc_show()
+    - smb: client: fix potential UAF in smb2_is_valid_lease_break()
+
+  * CVE-2021-47219
+    - scsi: scsi_debug: Fix out-of-bound read in resp_report_tgtpgs()
+
+  * CVE-2024-26915
+    - drm/amdgpu: Add check to prevent IH overflow
+    - drm/amdgpu: Reset IH OVERFLOW_CLEAR bit
+
+  * CVE-2024-56661
+    - tipc: fix NULL deref in cleanup_bearer()
+
+  * CVE-2024-56642
+    - tipc: Fix use-after-free of kernel socket in cleanup_bearer().
+
+  * CVE-2021-47163
+    - tipc: wait and exit until all work queues are done
+
+  * CVE-2021-47500
+    - iio: mma8452: Fix trigger reference couting
+
+  * CVE-2022-23041
+    - xen/grant-table: add gnttab_try_end_foreign_access()
+    - xen/gnttab: fix gnttab_end_foreign_access() without page specified
+
+  * CVE-2024-36934
+    - bna: ensure the copied buf is NUL terminated
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 11 Apr 2025 22:33:33 +0200
+
+linux (4.4.0-267.301) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-267.301 -proposed tracker (LP: #2102293)
+
+  * CVE-2024-27397 (LP: #2090990)
+    - netfilter: nf_tables: fix inconsistent element expiration calculation
+    - time: Introduce jiffies64_to_nsecs()
+    - netfilter: nf_tables: support timeouts larger than 23 days
+    - netfilter: nft_dynset: fix timeout updates on 32bit
+    - netfilter: nf_tables: elements with timeout below CONFIG_HZ never expire
+
+  * CVE-2024-50302
+    - HID: core: zero-initialize the report buffer
+
+  * CVE-2021-47602
+    - mac80211: track only QoS data frames for admission control
+
+  * CVE-2024-49948
+    - net: add more sanity checks to qdisc_pkt_len_init()
+
+  * CVE-2021-47320
+    - nfs: fix acl memory leak of posix_acl_create()
+
+  * CVE-2024-49952
+    - netfilter: nf_tables: prevent nf_skb_duplicated corruption
+
+  * CVE-2024-50167
+    - be2net: fix potential memory leak in be_xmit()
+
+  * CVE-2025-21702
+    - pfifo_tail_enqueue: Drop new packet when sch->limit == 0
+
+  * CVE-2025-21700
+    - net: sched: Disallow replacing of child qdisc from one parent to another
+
+  * CVE-2021-47483
+    - regmap: Fix possible double-free in regcache_rbtree_exit()
+
+  * CVE-2024-56595
+    - jfs: add a check to prevent array-index-out-of-bounds in dbAdjTree
+
+  * CVE-2021-47119
+    - ext4: fix memory leak in ext4_fill_super
+
+  * CVE-2021-47122
+    - net: caif: add proper error handling
+    - net: caif: added cfserl_release function
+    - net: caif: fix memory leak in caif_device_notify
+
+  * CVE-2024-46826
+    - ELF: fix kernel.randomize_va_space double read
+
+  * CVE-2024-56600
+    - net: inet6: do not leave a dangling sk pointer in inet6_create()
+
+  * CVE-2024-56658
+    - net: defer final 'struct net' free in netns dismantle
+
+  * CVE-2024-53227
+    - scsi: bfa: Fix use-after-free in bfad_im_module_exit()
+
+  * CVE-2024-53165
+    - sh: intc: Fix use-after-free bug in register_intc_controller()
+
+  * CVE-2024-50265
+    - ocfs2: remove entry once instead of null-ptr-dereference in
+      ocfs2_xa_remove()
+
+  * CVE-2021-47235
+    - net: ethernet: fix potential use-after-free in ec_bhf_remove
+
+  * CVE-2024-26921
+    - ipv4: ipv6: netfilter: Adjust the frag mem limit when truesize changes
+    - net: IP defrag: encapsulate rbtree defrag code into callable functions
+    - ipv4: remove unnecessary type castings
+    - netfilter: ipv6: nf_defrag: avoid/free clone operations
+    - inet: kill unused skb_free op
+    - netfilter: ipv6: avoid nf_iterate recursion
+    - netfilter: ipv6: nf_defrag: fix NULL deref panic
+    - openvswitch: Orphan skbs before IPv6 defrag
+    - openvswitch: Fix skb leak in IPv6 reassembly.
+    - netfilter: ipv6: nf_defrag: drop mangled skb on ream error
+    - netfilter: ipv6: nf_defrag: Pass on packets to stack per RFC2460
+    - netfilter: ipv6: nf_defrag: Kill frag queue on RFC2460 failure
+    - net: IP6 defrag: use rbtrees in nf_conntrack_reasm.c
+    - netfilter: ipv6: nf_defrag: fix leakage of unqueued fragments
+    - netfilter: ipv6: nf_defrag: accept duplicate fragments again
+    - net: add __sock_wfree() helper
+    - inet: inet_defrag: prevent sk release while still in use
+
+  * CVE-2024-26863
+    - hsr: Fix uninit-value access in hsr_get_node()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 14 Mar 2025 19:16:58 +0100
+
+linux (4.4.0-266.300) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-266.300 -proposed tracker (LP: #2098709)
+
+  * Xenial backport of upstream patch breaks arm64 boot (LP: #2098704)
+    - Revert "bpf: Take return from set_memory_ro() into account with
+      bpf_prog_lock_ro()"
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Mon, 17 Feb 2025 19:57:36 +0100
+
+linux (4.4.0-265.299) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-265.299 -proposed tracker (LP: #2097857)
+
+  * CVE-2024-41063
+    - Bluetooth: fix power_on vs close race
+    - Bluetooth: hci_core: cancel all works upon hci_unregister_dev()
+
+  * CVE-2024-53104
+    - media: uvcvideo: Skip parsing frames of type UVC_VS_UNDEFINED in
+      uvc_parse_format
+
+  * CVE-2024-53156
+    - wifi: ath9k: add range check for conn_rsp_epid in htc_connect_service()
+
+  * CVE-2021-47606
+    - net: netlink: af_netlink: Prevent empty skb by adding a check on len.
+
+  * CVE-2024-49902
+    - jfs: check if leafidx greater than num leaves per dmap tree
+
+  * CVE-2023-52799 // CVE-2024-49902
+    - jfs: fix array-index-out-of-bounds in dbFindLeaf
+
+  * CVE-2023-52818
+    - drm/amd: Fix UBSAN array-index-out-of-bounds for SMU7
+
+  * CVE-2024-50117
+    - drm/amd: Guard against bad data for ATIF ACPI method
+
+  * CVE-2024-50148
+    - Bluetooth: bnep: fix wild-memory-access in proto_unregister
+
+  * CVE-2024-44938
+    - jfs: Fix shift-out-of-bounds in dbDiscardAG
+
+  * CVE-2022-48994
+    - ALSA: seq: Fix function prototype mismatch in snd_seq_expand_var_event
+
+  * CVE-2024-50233
+    - staging: iio: frequency: ad9832: fix division by zero in
+      ad9832_calc_freqreg()
+
+  * CVE-2023-52880
+    - tty: n_gsm: require CAP_NET_ADMIN to attach N_GSM0710 ldisc
+
+  * CVE-2024-50171
+    - net: systemport: fix potential memory leak in bcm_sysport_xmit()
+
+  * CVE-2024-43900
+    - media: xc2028: avoid use-after-free in load_firmware_cb()
+
+  * CVE-2024-40981
+    - batman-adv: bypass empty buckets in batadv_purge_orig_ref()
+
+  * CVE-2024-43893
+    - serial: core: check uartclk for zero to avoid divide by zero
+
+  * CVE-2024-36886
+    - tipc: fix UAF in error path
+
+  * CVE-2024-40943
+    - ocfs2: fix races between hole punching and AIO+DIO
+
+  * CVE-2024-38567
+    - USB: core: add helpers to retrieve endpoints in reverse order
+    - USB: core: Add routines for endpoint checks in old drivers
+    - wifi: carl9170: add a proper sanity check for endpoints
+
+  * CVE-2024-44931
+    - gpio: prevent potential speculation leaks in gpio_device_get_desc()
+
+  * CVE-2024-43863
+    - drm/vmwgfx: Fix a deadlock in dma buf fence polling
+
+  * CVE-2024-43892
+    - memcg: remove memcg_cgroup::id from IDR on mem_cgroup_css_alloc() failure
+    - memcg: protect concurrent access to mem_cgroup_idr
+
+  * CVE-2024-43854
+    - block: initialize integrity buffer to zero before writing it to media
+
+  * CVE-2024-40911
+    - wifi: cfg80211: Lock wiphy in cfg80211_get_station
+
+  * CVE-2024-41064
+    - powerpc/eeh: avoid possible crash when edev->pdev changes
+
+  * CVE-2024-36964
+    - fs/9p: only translate RWX permissions for plain 9P2000
+
+  * CVE-2024-35896
+    - netfilter: validate user input for expected length
+    - netfilter: complete validation of user input
+
+  * CVE-2024-26685
+    - nilfs2: fix potential bug in end_buffer_async_write
+
+  * CVE-2024-36952
+    - scsi: lpfc: Move NPIV's transport unregistration to after resource clean up
+
+  * CVE-2024-40910
+    - ax25: Fix refcount imbalance on inbound connections
+
+  * CVE-2021-47103
+    - inet: fully convert sk->sk_rx_dst to RCU rules
+
+  * CVE-2023-52488
+    - regmap: Add regmap_noinc_read API
+    - regmap: Add regmap_noinc_write API
+    - regmap: fix page selection for noinc writes
+    - regmap: fix page selection for noinc reads
+    - regmap: prevent noinc writes from clobbering cache
+    - serial: sc16is7xx: convert from _raw_ to _noinc_ regmap functions for FIFO
+
+  * CVE-2024-42068
+    - bpf: Take return from set_memory_ro() into account with bpf_prog_lock_ro()
+
+  * CVE-2024-42070
+    - netfilter: nf_tables: fully validate NFT_DATA_VALUE on store to data
+      registers
+
+  * CVE-2023-52522
+    - net: fix possible store tearing in neigh_periodic_work()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Wed, 12 Feb 2025 18:42:15 +0100
+
+linux (4.4.0-264.298) xenial; urgency=medium
+
+  * CVE-2025-0927
+    - SAUCE: fs: hfs/hfsplus: add key_len boundary check to hfs_bnode_read_key
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 07 Feb 2025 17:41:14 +0100
+
+linux (4.4.0-263.297) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-263.297 -proposed tracker (LP: #2093447)
+
+  * CVE-2024-53141
+    - netfilter: ipset: add missing range check in bitmap_ip_uadt
+
+  * CVE-2024-42311
+    - hfs: fix to initialize fields of hfs_inode_info after hfs_alloc_inode()
+
+  * CVE-2024-40982
+    - ssb: Fix potential NULL pointer dereference in ssb_device_uevent()
+
+  * CVE-2024-41012
+    - filelock: Remove locks reliably when fcntl/close race is detected
+    - filelock: Fix fcntl/close race recovery compat path
+    - filelock: Correct the filelock owner in fcntl_setlk/fcntl_setlk64
+
+  * CVE-2024-41066
+    - ibmvnic: Add tx check to prevent skb leak
+
+  * CVE-2024-43914
+    - md/raid5: avoid BUG_ON() while continue reshape after reassembling
+
+  * CVE-2024-42252
+    - closures: Change BUG_ON() to WARN_ON()
+
+  * CVE-2024-38553
+    - net: fec: remove .ndo_poll_controller to avoid deadlocks
+
+  * CVE-2024-38597
+    - eth: sungem: remove .ndo_poll_controller to avoid deadlocks
+
+  * CVE-2024-38553 // CVE-2024-38597
+    - netpoll: make ndo_poll_controller() optional
+    - bonding: use netpoll_poll_dev() helper
+    - netpoll: do not test NAPI_STATE_SCHED in poll_one_napi()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 10 Jan 2025 17:09:31 +0100
+
+linux (4.4.0-262.296) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-262.296 -proposed tracker (LP: #2089998)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * CVE-2024-53057
+    - net/sched: stop qdisc_tree_reduce_backlog on TC_H_ROOT
+
+  * CVE-2024-38619
+    - usb-storage: alauda: Check whether the media is initialized
+
+  * CVE-2024-42153
+    - i2c: img-scb: use setup_timer
+    - i2c/busses: Convert timers to use timer_setup()
+    - i2c: pnx: Fix potential deadlock warning from del_timer_sync() call in isr
+
+  * CVE-2024-44944
+    - netfilter: ctnetlink: use helper function to calculate expect ID
+
+  * CVE-2024-44947
+    - fuse: Initialize beyond-EOF page contents before setting uptodate
+
+  * CVE-2024-45021
+    - memcg_write_event_control(): fix a user-triggerable oops
+
+  * CVE-2024-49967
+    - ext4: no need to continue when the number of entries is 1
+
+  * CVE-2020-12351 // CVE-2020-12352 // CVE-2020-24490
+    - [Config] Disable BlueZ highspeed support
+
+  * CVE-2024-36270
+    - netfilter: tproxy: bail out if IP has been disabled on the device
+
+  * CVE-2024-40912
+    - wifi: mac80211: Fix deadlock in ieee80211_sta_ps_deliver_wakeup()
+
+  * CVE-2024-43856
+    - dma: fix call order in dmam_free_coherent
+
+  * CVE-2024-43884
+    - Bluetooth: MGMT: Add error handling to pair_device()
+
+  * CVE-2024-40959
+    - xfrm6: check ip6_dst_idev() return value in xfrm6_get_saddr()
+
+  * CVE-2024-42090
+    - pinctrl: fix deadlock in create_pinctrl() when handling -EPROBE_DEFER
+
+  * CVE-2024-39301
+    - net/9p: fix uninit-value in p9_client_rpc()
+
+  * CVE-2024-38633
+    - serial: max3100: Update uart_driver_registered on driver removal
+
+  * CVE-2024-36941
+    - wifi: nl80211: don't free NULL coalescing rule
+
+  * CVE-2024-26777
+    - fbdev: sis: Error out if pixclock equals zero
+
+  * CVE-2024-26625
+    - llc: call sock_orphan() at release time
+
+  * CVE-2021-47501
+    - i40e: Fix NULL pointer dereference in i40e_dbg_dump_desc
+
+  * CVE-2024-36946
+    - phonet: fix rtm_phonet_notify() skb allocation
+
+  * CVE-2021-47086
+    - phonet/pep: refuse to enable an unbound pipe
+
+  * CVE-2023-52594
+    - wifi: ath9k: Fix potential array-index-out-of-bounds read in
+      ath9k_htc_txstatus()
+
+  * CVE-2021-47118
+    - pid: take a reference when initializing `cad_pid`
+
+  * CVE-2024-42101
+    - drm/nouveau: fix null pointer dereference in nouveau_connector_get_modes
+
+  * CVE-2024-36968
+    - Bluetooth: L2CAP: Fix div-by-zero in l2cap_le_flowctl_init()
+
+  * CVE-2023-52507
+    - nfc: nci: assert requested protocol is valid
+
+  * CVE-2023-52509
+    - ravb: Fix use-after-free issue in ravb_tx_timeout_work()
+
+  * CVE-2024-35886
+    - ipv6: Fix infinite recursion in fib6_dump_done().
+
+  * CVE-2022-36402
+    - drm/vmwgfx: Use enum to represent graphics context capabilities
+    - drm/vmwgfx: Fix shader stage validation
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 29 Nov 2024 18:11:49 +0100
+
+linux (4.4.0-261.295) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-261.295 -proposed tracker (LP: #2086155)
+
+  * CVE-2024-26633
+    - ip6_tunnel: fix NEXTHDR_FRAGMENT handling in ip6_tnl_parse_tlv_enc_lim()
+
+  * CVE-2023-52502
+    - net: nfc: fix races in nfc_llcp_sock_get() and nfc_llcp_sock_get_sn()
+
+  * CVE-2024-41095
+    - drm/nouveau/dispnv04: fix null pointer dereference in nv17_tv_get_ld_modes
+
+  * CVE-2022-48938
+    - CDC-NCM: avoid overflow in sanity checking
+
+  * CVE-2024-42309
+    - drm/gma500: fix null pointer dereference in psb_intel_lvds_get_modes
+
+  * CVE-2022-24448
+    - NFSv4: Handle case where the lookup of a directory fails
+    - NFS: LOOKUP_DIRECTORY is also ok with symlinks
+
+  * CVE-2024-38560
+    - new helper: memdup_user_nul()
+    - scsi: bfa: Ensure the copied buf is NUL terminated
+
+  * CVE-2021-47055
+    - mtd: require write permissions for locking and badblock ioctls
+
+  * CVE-2024-42310
+    - drm/gma500: fix null pointer dereference in cdv_intel_lvds_get_modes
+
+  * CVE-2024-42240
+    - x86/bhi: Avoid warning in #DB handler due to BHI mitigation
+
+  * CVE-2024-41089
+    - drm/nouveau/dispnv04: fix null pointer dereference in nv17_tv_get_hd_modes
+
+  * CVE-2024-46743
+    - of: irq: use of_property_read_u32()
+    - of/irq: use of_property_read_u32_index to parse interrupts property
+    - of/irq: Prevent device address out-of-bounds read in interrupt map walk
+
+  * CVE-2024-46757
+    - hwmon: (nct6775-core) Fix underflows seen when writing limit attributes
+
+  * CVE-2024-42244
+    - USB: serial: mos7840: fix crash on resume
+
+  * CVE-2024-46756
+    - hwmon: (w83627ehf) Fix underflows seen when writing limit attributes
+
+  * CVE-2024-46758
+    - hwmon: (lm95234) Fix underflows seen when writing limit attributes
+
+  * CVE-2024-46759
+    - hwmon: (adc128d818) Fix underflows seen when writing limit attributes
+
+  * CVE-2024-46723
+    - drm/amdgpu: fix ucode out-of-bounds read warning
+
+  * CVE-2024-46800
+    - sch/netem: fix use after free in netem_dequeue
+
+  * CVE-2024-46722
+    - drm/amdgpu: fix mc_data out-of-bounds read warning
+
+  * CVE-2024-46738
+    - VMCI: Fix use-after-free when removing resource in vmci_resource_remove()
+
+  * CVE-2023-52578
+    - net/core: relax BUILD_BUG_ON in netdev_stats_to_stats64
+    - net: core: Fix slab-out-of-bounds in netdev_stats_to_stats64
+    - net: add atomic_long_t to net_device_stats fields
+    - net: Fix unwanted sign extension in netdev_stats_to_stats64()
+    - net: bridge: use DEV_STATS_INC()
+
+  * CVE-2023-52599
+    - jfs: fix array-index-out-of-bounds in diNewExt
+
+  * CVE-2024-26636
+    - llc: make llc_ui_sendmsg() more robust against bonding changes
+
+  * CVE-2024-44942
+    - f2fs: fix to do sanity check on F2FS_INLINE_DATA flag in inode during GC
+
+  * CVE-2024-26675
+    - ppp_async: limit MRU to 64K
+
+  * CVE-2024-44998
+    - atm: idt77252: prevent use after free in dequeue_rx()
+
+  * CVE-2022-48733
+    - btrfs: fix use-after-free after failure to create a snapshot
+
+  * CVE-2024-35877
+    - x86/mm/pat: fix VM_PAT handling in COW mappings
+
+  * CVE-2022-48943
+    - KVM: x86/mmu: make apf token non-zero to fix bug
+
+  * CVE-2024-41059
+    - hfsplus: fix uninit-value in copy_name
+
+  * CVE-2024-42104
+    - nilfs2: add missing check for inode numbers on directory entries
+
+  * CVE-2024-43882
+    - exec: Fix ToCToU between perm check and set-uid/gid usage
+
+  * CVE-2024-44987
+    - ipv6: prevent UAF in ip6_send_skb()
+
+  * CVE-2023-52531
+    - wifi: iwlwifi: mvm: Fix a memory corruption issue
+
+  * CVE-2024-26668
+    - compiler.h: enable builtin overflow checkers and add fallback code
+    - netfilter: nft_limit: reject configurations that cause integer overflow
+
+  * CVE-2024-38538
+    - net: bridge: xmit: make sure we have at least eth header len bytes
+
+  * CVE-2024-41071
+    - wifi: mac80211: Avoid address calculations via out of bounds array indexing
+
+  * CVE-2023-52614
+    - PM / devfreq: Fix buffer overflow in trans_stat_show
+
+  * CVE-2024-27397
+    - netfilter: nf_tables: use timestamp to check for set element timeout
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 01 Nov 2024 11:36:54 +0100
+
+linux (4.4.0-260.294) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-260.294 -proposed tracker (LP: #2082326)
+
+  * CVE-2024-44940
+    - fou: remove warn in gue_gro_receive on unsupported protocol
+
+  * CVE-2024-46673
+    - scsi: aacraid: Fix double-free on probe failure
+
+  * CVE-2024-26812
+    - vfio/pci: Fix ordering of eventfd vs virqfd shutdown
+    - vfio: Introduce interface to flush virqfd inject workqueue
+    - vfio/pci: Create persistent INTx handler
+
+  * CVE-2024-26810
+    - vfio/pci: Lock external INTx masking ops
+
+  * CVE-2024-42284
+    - tipc: Return non-zero value from tipc_udp_addr2str() on error
+
+  * CVE-2024-38602
+    - ax25: Fix reference count leak issues of ax25_dev
+
+  * CVE-2024-38627
+    - stm class: Fix a double free in stm_register_device()
+
+  * CVE-2024-39487
+    - bonding: Fix out-of-bounds read in bond_option_arp_ip_targets_set()
+
+  * CVE-2024-42280
+    - mISDN: Fix a use after free in hfcmulti_tx()
+
+  * CVE-2024-42271
+    - net/iucv: fix use after free in iucv_sock_close()
+
+  * CVE-2024-43858
+    - jfs: Fix array-index-out-of-bounds in diFree
+
+  * CVE-2024-42229
+    - crypto: aead,cipher - zeroize key buffer after use
+
+  * CVE-2024-38621
+    - media: stk1160: fix bounds checking in stk1160_copy_video()
+
+  * CVE-2024-27436
+    - ALSA: usb-audio: Stop parsing channels bits when all channels are found.
+
+  * CVE-2024-41097
+    - usb: atm: cxacru: fix endpoint checking in cxacru_bind()
+
+  * CVE-2024-38630
+    - watchdog: cpu5wdt.c: Fix use-after-free bug caused by cpu5wdt_trigger
+
+  * CVE-2024-42089
+    - ASoC: fsl-asoc-card: set priv->pdev before using it
+
+  * CVE-2024-39494
+    - constify ima_d_path()
+    - ima: fix ima_d_path() possible race with rename
+    - ima: pass filename to ima_rdwr_violation_check()
+    - include/linux/dcache.h: use unsigned chars in struct name_snapshot
+    - ovl_lookup_real_one(): don't bother with strlen()
+    - ima: Fix use-after-free on a dentry's dname.name
+
+  * CVE-2024-42223
+    - media: dvb-frontends: tda10048: Fix integer overflow
+
+  * CVE-2023-52528
+    - usbnet/smsc75xx: silence uninitialized variable warning
+    - net: usb: smsc75xx: Fix uninit-value access in __smsc75xx_read_reg
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 27 Sep 2024 16:50:34 +0200
+
+linux (4.4.0-259.293) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-259.293 -proposed tracker (LP: #2078241)
+
+  * CVE-2024-26851
+    - netfilter: nf_conntrack_h323: Add protection for bmp length out of range
+
+  * CVE-2024-26880
+    - dm: call the resume method on internal suspend
+
+  * CVE-2024-38583
+    - timer: Prepare to change timer callback argument type
+    - um/time: Fixup namespace collision
+    - timer: Provide wrappers safe for use with LOCKDEP
+    - fs/nilfs2: convert timers to use timer_setup()
+    - nilfs2: fix use-after-free of timer for log writer thread
+
+  * CVE-2024-42228
+    - drm/amdgpu: Using uninitialized value *size when calling amdgpu_vce_cs_reloc
+
+  * CVE-2022-48850
+    - net-sysfs: add check for netdevice being present to speed_show
+
+  * CVE-2024-26733
+    - arp: Prevent overflow in arp_req_get().
+
+  * CVE-2024-40902
+    - jfs: xattr: fix buffer overflow for invalid xattr
+
+  * CVE-2021-47181
+    - usb: musb: tusb6010: check return value after calling
+      platform_get_resource()
+
+  * CVE-2022-48791
+    - scsi: pm80xx: Fix TMF task completion race condition
+    - scsi: pm8001: Fix use-after-free for aborted TMF sas_task
+
+  * CVE-2024-38570
+    - GFS2: Reintroduce a timeout in function gfs2_gl_hash_clear
+    - gfs2: Rename sd_{ glock => kill }_wait
+    - gfs2: Fix potential glock use-after-free on unmount
+
+  * CVE-2023-52527
+    - ipv4, ipv6: Fix handling of transhdrlen in __ip{,6}_append_data()
+
+  * CVE-2024-27437
+    - genirq: Add IRQF_NO_AUTOEN for request_irq/nmi()
+    - vfio/pci: Disable auto-enable of exclusive INTx IRQ
+
+  * CVE-2024-26651
+    - sr9800: Add check for usbnet_get_endpoints
+
+  * CVE-2024-42154
+    - tcp_metrics: validate source addr length
+
+  * CVE-2022-48863
+    - mISDN: Fix memory leak in dsp_pipeline_build()
+
+  * CVE-2024-26677
+    - rxrpc: Fix delayed ACKs to not set the reference serial number
+
+  * CVE-2022-48836
+    - Input: aiptek - properly check endpoint type
+
+  * CVE-2022-48838
+    - usb: gadget: Fix use-after-free bug by not setting udc->dev.driver
+
+  * CVE-2022-48851
+    - staging: gdm724x: fix use after free in gdm_lte_rx()
+
+  * CVE-2021-47188
+    - scsi: ufs: core: Improve SCSI abort handling
+
+  * CVE-2023-52809
+    - scsi: libfc: Fix potential NULL pointer dereference in fc_lport_ptp_setup()
+
+  * CVE-2022-48857
+    - NFC: port100: fix use-after-free in port100_send_complete
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Thu, 29 Aug 2024 13:45:03 +0200
+
+linux (4.4.0-258.292) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-258.292 -proposed tracker (LP: #2075816)
+
+  * CVE-2021-46906
+    - HID: usbhid: fix info leak in hid_submit_ctrl
+
+  * CVE-2021-47239
+    - net: usb: fix possible use-after-free in smsc75xx_bind
+
+  * CVE-2021-47171
+    - net: usb: fix memory leak in smsc75xx_bind
+
+  * CVE-2024-27013
+    - tun: limit printing rate when illegal packet received by tun dev
+
+  * CVE-2021-47518
+    - nfc: fix potential NULL pointer deref in nfc_genl_dump_ses_done
+
+  * CVE-2023-52806
+    - ALSA: hda: Fix possible null-ptr-deref when assigning a stream
+
+  * CVE-2021-46905
+    - net: hso: fix NULL-deref on disconnect regression
+
+  * CVE-2021-46904
+    - net: hso: fix null-ptr-deref during tty device unregistration
+
+  * CVE-2021-47542
+    - net: qlogic: qlcnic: Fix a NULL pointer dereference in
+      qlcnic_83xx_add_rings()
+
+  * CVE-2024-26679
+    - inet: read sk->sk_family once in inet_recv_error()
+
+  * CVE-2024-39484
+    - mmc: davinci: Don't strip remove function when driver is builtin
+
+  * CVE-2021-46924
+    - NFC: st21nfca: Fix memory leak in device probe and remove
+
+  * CVE-2024-26929
+    - scsi: qla2xxx: Fix double free of fcport
+
+  * CVE-2022-48659
+    - mm/slub: fix to return errno if kmalloc() fails
+
+  * CVE-2023-52470
+    - drm/radeon: Remove deprecated create_singlethread_workqueue
+    - drm/radeon: check the alloc_workqueue return value in radeon_crtc_init()
+
+  * CVE-2021-47173
+    - misc/uss720: fix memory leak in uss720_probe
+    - usb: misc: uss720: remove redundant pointer usbdev
+    - usb: misc: fix improper handling of refcount in uss720_probe()
+
+  * CVE-2021-47521
+    - can: sja1000: fix use after free in ems_pcmcia_add_card()
+
+  * CVE-2024-26654
+    - ALSA: sh: aica: Remove deprecated create_workqueue
+    - ALSA: sh: aica: Convert timers to use timer_setup()
+    - ALSA: aica: Fix a long-time build breakage
+    - ALSA: sh: aica: reorder cleanup operations to avoid UAF bugs
+
+  * CVE-2024-26600
+    - phy: ti: phy-omap-usb2: Fix NULL pointer dereference for SRP
+
+  * CVE-2024-39292
+    - um: Add winch to winch_handlers before registering winch IRQ
+
+  * CVE-2024-26687
+    - xen/events: close evtchn after mapping cleanup
+
+  * CVE-2023-52760
+    - gfs2: Fix slab-use-after-free in gfs2_qd_dealloc
+
+  * CVE-2024-36901
+    - ipv6: prevent NULL dereference in ip6_output()
+
+  * CVE-2023-52644
+    - b43: dma: Fix use true/false for bool type variable
+    - wifi: b43: Stop/wake correct queue in DMA Tx path when QoS is disabled
+
+  * CVE-2024-24860
+    - Bluetooth: Fix atomicity violation in {min,max}_key_size_set
+
+  * CVE-2023-52629
+    - sh: push-switch: Reorder cleanup operations to avoid use-after-free bug
+
+  * CVE-2024-22099 // CVE-2024-26903
+    - Bluetooth: rfcomm: Fix null-ptr-deref in rfcomm_check_security
+
+  * CVE-2021-47571
+    - staging: rtl8192e: Fix use after free in _rtl92e_pci_disconnect()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 02 Aug 2024 18:05:35 +0200
+
+linux (4.4.0-257.291) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-257.291 -proposed tracker (LP: #2072141)
+
+  * CVE-2024-26886
+    - Bluetooth: af_bluetooth: Fix deadlock
+
+  * CVE-2023-52620
+    - netfilter: nf_tables: disallow timeout for anonymous sets
+
+  * CVE-2021-46960
+    - cifs: Return correct error code from smb2_get_enc_key
+
+  * CVE-2024-36902
+    - net/ipv6: Refactor fib6_rule_action
+    - ipv6: fib6_rules: avoid possible NULL dereference in fib6_rule_action()
+
+  * CVE-2024-26840
+    - cachefiles: fix memory leak in cachefiles_add_cache()
+
+  * CVE-2024-26857
+    - geneve: implement geneve_get_sk_family helper
+    - geneve: move geneve device lookup before iptunnel_pull_header
+    - geneve: make sure to pull inner header in geneve_rx()
+
+  * CVE-2024-35978
+    - Bluetooth: Fix memory leak in hci_req_sync_complete()
+
+  * CVE-2023-52752
+    - smb: client: fix use-after-free bug in cifs_debug_data_proc_show()
+
+  * CVE-2024-26934
+    - USB: core: Fix deadlock in usb_deauthorize_interface()
+
+  * CVE-2024-35984
+    - i2c: add param sanity check to i2c_transfer()
+    - i2c: smbus: fix NULL function pointer dereference
+
+  * CVE-2024-35982
+    - batman-adv: Avoid infinite loop trying to resize local TT
+
+  * CVE-2024-35997
+    - HID: i2c-hid: remove I2C_HID_READ_PENDING flag to prevent lock-up
+
+  * CVE-2024-26882
+    - net: ip_tunnel: make sure to pull inner header in ip_tunnel_rcv()
+
+  * CVE-2024-26901
+    - do_sys_name_to_handle(): use kzalloc() to fix kernel-infoleak
+
+  * CVE-2024-26884
+    - bpf: Fix hashtab overflow check on 32-bit arches
+
+  * CVE-2024-36016
+    - tty: n_gsm: fix possible out-of-bounds in gsm0_receive()
+
+  * CVE-2023-52436
+    - f2fs: explicitly null-terminate the xattr list
+
+  * CVE-2023-52469
+    - drivers/amd/pm: fix a use-after-free in kv_parse_power_table
+
+  * CVE-2024-27020
+    - netfilter: nf_tables: __nft_expr_type_get() selects specific family type
+    - netfilter: nf_tables: Fix potential data-race in __nft_expr_type_get()
+
+  * CVE-2024-24857 // CVE-2024-24858
+    - Bluetooth: Fix TOCTOU in HCI debugfs implementation
+
+  * CVE-2021-47194
+    - cfg80211: call cfg80211_stop_ap when switch from P2P_GO type
+
+  * CVE-2021-46933
+    - usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.
+
+  * CVE-2024-25739
+    - ubi: Check for too small LEB size in VTBL code
+
+  * CVE-2021-46932
+    - Input: appletouch - initialize work before device registration
+
+  * CVE-2023-52444
+    - f2fs: fix to avoid dirent corruption
+
+  * CVE-2023-52449
+    - mtd: Fix gluebi NULL pointer dereference caused by ftl notifier
+
+  * CVE-2023-46343
+    - nfc: nci: fix possible NULL pointer dereference in send_acknowledge()
+
+  * CVE-2022-48619
+    - Input: add bounds checking to input_set_capability()
+
+  * CVE-2024-26923
+    - af_unix: annote lockless accesses to unix_tot_inflight & gc_in_progress
+    - af_unix: Do not use atomic ops for unix_sk(sk)->inflight.
+    - af_unix: Fix garbage collector racing against connect()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 05 Jul 2024 14:21:12 +0200
+
+linux (4.4.0-256.290) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-256.290 -proposed tracker (LP: #2069738)
+
+  * CVE-2024-2201
+    - x86/cpufeatures: Add new word for scattered features
+    - x86/cpufeatures: Add CPUID_LNX_5 to track recently added Linux-defined word
+    - x86/bugs: Change commas to semicolons in 'spectre_v2' sysfs file
+    - x86/bhi: Add support for clearing branch history at syscall entry
+    - x86/bhi: Define SPEC_CTRL_BHI_DIS_S
+    - x86/bhi: Enumerate Branch History Injection (BHI) bug
+    - x86/bhi: Add BHI mitigation knob
+    - x86/bhi: Mitigate KVM by default
+    - [Config] updateconfigs for CONFIG_BHI_{AUTO|OFF|ON}
+    - x86/bugs: Make sure MSR_SPEC_CTRL is updated properly upon resume from S3
+    - x86/bugs: Fix BHI documentation
+    - x86/bugs: Cache the value of MSR_IA32_ARCH_CAPABILITIES
+    - x86/bugs: Rename various 'ia32_cap' variables to 'x86_arch_cap_msr'
+    - x86/bugs: Fix BHI handling of RRSBA
+    - x86/bugs: Clarify that syscall hardening isn't a BHI mitigation
+    - x86/bugs: Fix BHI retpoline check
+
+  * CVE-2024-23307
+    - md/raid5: fix atomicity violation in raid5_cache_count
+
+  * CVE-2024-26642
+    - netfilter: nf_tables: disallow anonymous set with timeout flag
+
+  * CVE-2024-26720
+    - mm/writeback: fix possible divide-by-zero in wb_dirty_limits(), again
+
+  * CVE-2024-24861
+    - media: xc4000: Fix atomicity violation in xc4000_get_frequency
+
+  * CVE-2023-6270
+    - aoe: fix the potential use-after-free problem in aoecmd_cfg_pkts
+
+  * CVE-2021-33631
+    - ext4: fix kernel BUG in 'ext4_write_inline_data_end()'
+
+  * CVE-2023-52615
+    - hwrng: core - Fix page fault dead lock on mmap-ed hwrng
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Wed, 19 Jun 2024 13:23:18 +0200
+
+linux (4.4.0-254.288) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-254.288 -proposed tracker (LP: #2064637)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] debian.master/dkms-versions -- update from kernel-versions
+      (main/s2024.04.01)
+
+  * CVE-2023-52566
+    - nilfs2: fix potential use after free in nilfs_gccache_submit_read_data()
+
+  * CVE-2023-52530
+    - wifi: mac80211: fix potential key use-after-free
+
+  * CVE-2024-26805
+    - netlink: Fix kernel-infoleak-after-free in __skb_datagram_iter
+
+  * CVE-2024-26635
+    - llc: Drop support for ETH_P_TR_802_2.
+
+  * CVE-2024-26622
+    - tomoyo: fix UAF write bug in tomoyo_write_control()
+
+  * CVE-2024-26614
+    - tcp: make sure init the accept_queue's spinlocks once
+    - ipv6: init the accept_queue's spinlocks in inet6_create
+
+  * CVE-2023-52602
+    - jfs: fix slab-out-of-bounds Read in dtSearch
+
+  * CVE-2023-52601
+    - FS:JFS:UBSAN:array-index-out-of-bounds in dbAdjTree
+    - jfs: Fix memleak in dbAdjCtl
+    - jfs: fix array-index-out-of-bounds in dbAdjTree
+
+  * CVE-2023-52524
+    - net: nfc: llcp: Add lock when modifying device list
+
+  * CVE-2023-47233
+    - wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach
+
+  * CVE-2021-46939
+    - tracing: Restructure trace_clock_global() to never block
+    - tracing: Do no increment trace_clock_global() by one
+
+  * CVE-2024-26801
+    - Bluetooth: Avoid potential use-after-free in hci_error_reset
+
+  * CVE-2024-26704
+    - ext4: fix double-free of blocks due to wrong extents moved_len
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 02 May 2024 16:45:40 +0200
+
+linux (4.4.0-253.287) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-253.287 -proposed tracker (LP: #2059563)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+
+  * CVE-2021-46990
+    - powerpc/64s: Fix crashes when toggling entry flush barrier
+
+  * CVE-2023-52603
+    - UBSAN: array-index-out-of-bounds in dtSplitRoot
+
+  * CVE-2022-20422
+    - arm64: fix oops in concurrently setting insn_emulation sysctls
+
+  * CVE-2023-52451
+    - powerpc/pseries/memhp: Fix access beyond end of drmem array
+
+  * CVE-2023-52600
+    - JFS: fix memleak in jfs_mount
+    - jfs: fix uaf in jfs_evict_inode
+
+  * CVE-2023-51043
+    - drm/atomic: Fix potential use-after-free in nonblocking commits
+
+  * CVE-2024-23851
+    - dm ioctl: log an error if the ioctl structure is corrupted
+    - dm: limit the number of targets and parameter size area
+
+  * Cranky update-dkms-versions rollout (LP: #2055685)
+    - Move debian/dkms-versions to debian.master/dkms-versions
+    - [Packaging] Replace debian/dkms-versions with $(DEBIAN)/dkms-versions
+
+  * Remove getabis scripts (LP: #2059143)
+    - [Packaging] Remove getabis
+
+  * CVE-2019-25162
+    - i2c: Fix a potential use after free
+
+  * CVE-2023-24023
+    - Bluetooth: Add debug setting for changing minimum encryption key size
+    - Bluetooth: Add more enc key size check
+
+  * CVE-2021-46955
+    - openvswitch: fix stack OOB read while fragmenting IPv4 packets
+
+  * CVE-2021-46936
+    - net: fix use-after-free in tw_timer_handler
+
+  * CVE-2021-46966
+    - ACPI: custom_method: fix potential use-after-free issue
+
+  * CVE-2023-52445
+    - media: pvrusb2: fix use after free on context disconnection
+
+  * CVE-2023-1998
+    - x86/speculation: Allow enabling STIBP with legacy IBRS
+
+  * CVE-2023-51779
+    - Bluetooth: af_bluetooth: Fix Use-After-Free in bt_sock_recvmsg
+
+  * CVE-2023-1382
+    - tipc: set con sock in tipc_conn_alloc
+    - tipc: add an extra conn_get in tipc_conn_alloc
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Thu, 28 Mar 2024 16:45:31 +0100
+
+linux (4.4.0-252.286) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-252.286 -proposed tracker (LP: #2055907)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop ABI data
+
+  * CVE-2022-20567
+    - l2tp: don't use inet_shutdown on ppp session destroy
+    - l2tp: fix race in pppol2tp_release with session object destroy
+    - l2tp: fix refcount leakage on PPPoL2TP sockets
+
+  * CVE-2023-51781
+    - appletalk: Fix Use-After-Free in atalk_ioctl
+
+  * CVE-2024-1086
+    - netfilter: nf_tables: reject QUEUE/DROP verdict parameters
+
+  * CVE-2023-39197
+    - netfilter: conntrack: dccp: copy entire header to stack buffer, not just
+      basic one
+
+  * CVE-2023-34256
+    - ext4: avoid a potential slab-out-of-bounds in ext4_group_desc_csum
+
+  * CVE-2024-24855
+    - scsi: lpfc: Fix a possible data race in lpfc_unregister_fcf_rescan()
+
+  * CVE-2024-0775
+    - ext4: improve error recovery code paths in __ext4_remount()
+
+  * Drop ABI checks from kernel build (LP: #2055686)
+    - [Packaging] Remove in-tree abi checks
+    - [Packaging] Bring back install-<flavour> prerequisite for checks-<flavour>
+    - [Packaging] Remove abi-check from final-checks
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Tue, 05 Mar 2024 21:37:05 +0100
+
+linux (4.4.0-251.285) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-251.285 -proposed tracker (LP: #2052153)
+
+  * CVE-2023-51782
+    - net/rose: Fix Use-After-Free in rose_ioctl
+
+  * CVE-2023-51780
+    - atm: Fix Use-After-Free in do_vcc_ioctl
+
+  * CVE-2023-7192
+    - netfilter: ctnetlink: fix possible refcount leak in
+      ctnetlink_create_conntrack()
+
+ -- Manuel Diewald <manuel.diewald@canonical.com>  Fri, 02 Feb 2024 22:16:53 +0100
+
+linux (4.4.0-250.284) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-250.284 -proposed tracker (LP: #2049044)
+
+  * CVE-2023-6932
+    - ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
+
+  * CVE-2023-6931
+    - perf: Allow perf_release() with !event->ctx
+    - perf: Fix perf_event_validate_size()
+    - perf: Fix perf_event_validate_size() lockdep splat
+
+  * CVE-2023-6606
+    - smb: client: fix OOB in smbCalcSize()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 15 Jan 2024 06:58:39 -0300
+
+linux (4.4.0-249.283) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-249.283 -proposed tracker (LP: #2046291)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] remove helper scripts
+
+  * CVE-2023-45863
+    - kobject: Fix slab-out-of-bounds in fill_kobj_path()
+
+  * CVE-2023-20588
+    - x86/bugs: Increase the x86 bugs vector size to two u32s
+    - x86/CPU/AMD: Do not leak quotient data after a division by 0
+    - x86/CPU/AMD: Fix the DIV(0) initial fix attempt
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 13 Dec 2023 17:18:19 -0300
+
+linux (4.4.0-248.282) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-248.282 -proposed tracker (LP: #2044347)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * CVE-2023-20593
+    - jump_label: Make it possible for arches to invoke jump_label_init() earlier
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 23 Nov 2023 07:33:23 -0300
+
+linux (4.4.0-247.281) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-247.281 -proposed tracker (LP: #2042032)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * CVE-2023-45871
+    - SAUCE: igb: do not allow bad packets when using RX-ALL
+
+  * CVE-2023-20593
+    - x86/cpu/amd: Move the errata checking functionality up
+    - x86/microcode/AMD: Add a @cpu parameter to the reloading functions
+    - x86/jump_label: Initialize static branching early
+    - x86/CPU: Call detect_nopl() only on the BSP
+    - x86/cpu/amd: Add a Zenbleed fix
+
+  * CVE-2023-39189
+    - netfilter: nfnetlink_osf: avoid OOB read
+
+  * CVE-2023-5717
+    - perf/core: Fix __perf_read_group_add() locking
+    - perf: Disallow mis-matched inherited group reads
+
+  * CVE-2023-31085
+    - ubi: Refuse attaching if mtd's erasesize is 0
+
+  * CVE-2023-39194
+    - net: xfrm: Fix xfrm_address_filter OOB read
+
+  * CVE-2023-39193
+    - netfilter: xt_sctp: validate the flag_info count
+
+  * CVE-2023-39192
+    - netfilter: xt_u32: validate user space input
+
+  * CVE-2023-45862
+    - USB: ene_usb6250: Allocate enough memory for full object
+
+  * CVE-2023-42754
+    - ipv4: fix null-deref in ipv4_link_failure
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 14 Nov 2023 11:39:37 -0300
+
+linux (4.4.0-246.280) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-246.280 -proposed tracker (LP: #2038362)
+
+  * CVE-2023-42755
+    - net/sched: Retire rsvp classifier
+    - [Config] remove NET_CLS_RSVP and NET_CLS_RSVP6
+
+  * CVE-2023-42752
+    - igmp: limit igmpv3_newpack() packet size to IP_MAX_MTU
+
+  * CVE-2023-42753
+    - netfilter: ipset: add the missing IP_SET_HASH_WITH_NET0 macro for
+      ip_set_hash_netportnet.c
+
+  * CVE-2023-4921
+    - net: sched: sch_qfq: Fix UAF in qfq_dequeue()
+
+  * CVE-2023-4623
+    - net/sched: sch_hfsc: Ensure inner classes have fsc curve
+
+  * CVE-2023-34319
+    - xen/netback: Fix buffer overrun triggered by unusual packet
+
+  * CVE-2023-4881
+    - netfilter: nftables: exthdr: fix 4-byte stack OOB write
+
+  * CVE-2023-4622
+    - af_unix: Fix null-ptr-deref in unix_stream_sendpage().
+
+  * CVE-2023-31083
+    - Bluetooth: hci_ldisc: check HCI_UART_PROTO_READY flag in HCIUARTGETPROTO
+
+  * CVE-2023-3772
+    - xfrm: add NULL check in xfrm_update_ae_params
+
+  * CVE-2023-1206
+    - tcp: Reduce chance of collisions in inet6_hashfn().
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 05 Oct 2023 16:59:51 -0300
+
+linux (4.4.0-245.279) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-245.279 -proposed tracker (LP: #2035275)
+
+  * CVE-2022-40982
+    - x86/speculation: Identify processors vulnerable to SMT RSB predictions
+    - init: Provide arch_cpu_finalize_init()
+    - cpu/hotplug: Fix "SMT disabled by BIOS" detection for KVM
+    - x86/cpu: Switch to arch_cpu_finalize_init()
+    - ARM: cpu: Switch to arch_cpu_finalize_init()
+    - um/cpu: Switch to arch_cpu_finalize_init()
+    - init: Remove check_bugs() leftovers
+    - x86/cpu: Add Tiger Lake to Intel family
+    - x86/speculation: Add Gather Data Sampling mitigation
+    - KVM: Add GDS_NO support to KVM
+    - [Config]: Enable CONFIG_ARCH_HAS_CPU_FINALIZE_INIT
+
+  * CVE-2023-4459
+    - net: vmxnet3: fix possible NULL pointer dereference in vmxnet3_rq_cleanup()
+
+  * CVE-2023-4385
+    - fs: jfs: fix possible NULL pointer dereference in dbFree()
+
+  * CVE-2023-4387
+    - net: vmxnet3: fix possible use-after-free bugs in vmxnet3_rq_alloc_rx_buf()
+
+  * CVE-2023-3863
+    - nfc: llcp: simplify llcp_sock_connect() error paths
+    - net: nfc: Fix use-after-free caused by nfc_llcp_find_local
+
+  * CVE-2023-32269
+    - netrom: Fix use-after-free caused by accept on already connected socket
+
+  * CVE-2023-40283
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb
+
+  * CVE-2023-4128
+    - net/sched: cls_u32: No longer copy tcf_result on update to avoid use-after-
+      free
+    - net/sched: cls_fw: No longer copy tcf_result on update to avoid use-after-
+      free
+    - net/sched: cls_route: No longer copy tcf_result on update to avoid use-
+      after-free
+
+  * CVE-2023-3212
+    - gfs2: Don't deref jdesc in evict
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 12 Sep 2023 15:45:45 -0300
+
+linux (4.4.0-244.278) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-244.278 -proposed tracker (LP: #2030665)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+  * CVE-2023-3567
+    - vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF
+
+  * CVE-2023-2985
+    - fs: hfsplus: fix UAF issue in hfsplus_put_super
+
+  * CVE-2023-31084 // CVE-2023-31084 was assigned to this bug.
+    - media: dvb-core: Fix kernel WARNING for blocking operation in wait_event*()
+
+  * CVE-2023-3776
+    - net/sched: cls_fw: Fix improper refcount update leads to use-after-free
+
+  * CVE-2023-3611
+    - net/sched: cls_matchall: fix crash when used with classful qdisc
+    - net/sched: sch_qfq: account for stab overhead in qfq_enqueue
+
+  * CVE-2023-2269
+    - dm ioctl: fix nested locking in table_clear() to remove deadlock concern
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 16 Aug 2023 15:09:02 -0300
+
+linux (4.4.0-243.277) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-243.277 -proposed tracker (LP: #2026875)
+
+  * CVE-2023-2162
+    - scsi: iscsi_tcp: Fix UAF during login when accessing the shost ipaddress
+
+  * CVE-2023-3268
+    - kernel/relay.c: fix read_pos error when multiple readers
+    - relayfs: fix out-of-bounds access in relay_file_read
+
+  * CVE-2023-35001
+    - netfilter: nf_tables: prevent OOB access in nft_byteorder_eval
+
+  * CVE-2023-3390
+    - netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE
+
+  * CVE-2023-3090
+    - ipvlan:Fix out-of-bounds caused by unclear skb->cb
+
+  * CVE-2023-1611
+    - btrfs: fix race between quota disable and quota assign ioctls
+
+  * CVE-2023-3141
+    - memstick: r592: Fix UAF bug in r592_remove due to race condition
+
+  * CVE-2023-3159
+    - firewire: fix potential uaf in outbound_phy_packet_callback()
+
+  * CVE-2023-3161
+    - fbcon: Check font dimension limits
+
+  * CVE-2023-2513
+    - ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h
+    - ext4: fix use-after-free in ext4_xattr_set_entry
+
+  * CVE-2023-0458
+    - prlimit: do_prlimit needs to have a speculation check
+
+  * CVE-2023-2124
+    - xfs: verify buffer contents when we skip log replay
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 13 Jul 2023 11:50:51 -0300
+
+linux (4.4.0-242.276) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-242.276 -proposed tracker (LP: #2024572)
+
+  * CVE-2023-3111
+    - btrfs: unset reloc control if transaction commit fails in
+      prepare_to_relocate()
+
+  * CVE-2023-1990
+    - nfc: st-nci: Fix use after free bug in ndlc_remove due to race condition
+
+  * CVE-2021-3753
+    - vt_kdsetmode: extend console locking
+
+  * CVE-2022-1184
+    - ext4: avoid cycles in directory h-tree
+    - ext4: verify dir block before splitting it
+    - ext4: check if directory block is within i_size
+    - ext4: make sure ext4_append() always allocates new block
+    - ext4: fix check for block being out of directory size
+
+  * CVE-2021-20321
+    - ovl: fix missing negative dentry check in ovl_rename()
+
+  * Bionic update: upstream stable patchset 2022-12-01 (LP: #1998542) //
+    CVE-2022-29901
+    - SAUCE: Fix kernel IBRS implementation
+
+  * CVE-2022-29901
+    - intel_idle: Add SKX support
+    - Revert "x86/cpu: Add a steppings field to struct x86_cpu_id"
+    - x86/cpufeature: Add facility to check for min microcode revisions
+    - x86/cpufeature: Fix various quality problems in the <asm/cpu_device_hd.h>
+      header
+    - x86/devicetable: Move x86 specific macro out of generic code
+    - x86/cpu: Add consistent CPU match macros
+    - x86/cpu: Add a steppings field to struct x86_cpu_id
+    - x86/entry: Remove skip_r11rcx
+    - x86/cpufeatures: Move RETPOLINE flags to word 11
+    - x86/bugs: Report AMD retbleed vulnerability
+    - x86/bugs: Add AMD retbleed= boot parameter
+    - x86/bugs: Keep a per-CPU IA32_SPEC_CTRL value
+    - x86/entry: Add kernel IBRS implementation
+    - x86/bugs: Optimize SPEC_CTRL MSR writes
+    - x86/speculation: Add spectre_v2=ibrs option to support Kernel IBRS
+    - x86/bugs: Split spectre_v2_select_mitigation() and
+      spectre_v2_user_select_mitigation()
+    - x86/bugs: Report Intel retbleed vulnerability
+    - entel_idle: Disable IBRS during long idle
+    - x86/speculation: Change FILL_RETURN_BUFFER to work with objtool
+    - x86/speculation: Add LFENCE to RSB fill sequence
+    - x86/speculation: Fix RSB filling with CONFIG_RETPOLINE=n
+    - x86/speculation: Fix firmware entry SPEC_CTRL handling
+    - x86/speculation: Fix SPEC_CTRL write on SMT state change
+    - x86/speculation: Use cached host SPEC_CTRL value for guest entry/exit
+    - x86/speculation: Remove x86_spec_ctrl_mask
+    - KVM: VMX: Prevent guest RSB poisoning attacks with eIBRS
+    - KVM: VMX: Fix IBRS handling after vmexit
+    - x86/speculation: Fill RSB on vmexit for IBRS
+    - x86/common: Stamp out the stepping madness
+    - x86/cpu/amd: Enumerate BTC_NO
+    - x86/bugs: Add Cannon lake to RETBleed affected CPU list
+    - x86/speculation: Disable RRSBA behavior
+    - x86/speculation: Use DECLARE_PER_CPU for x86_spec_ctrl_current
+    - x86/bugs: Warn when "ibrs" mitigation is selected on Enhanced IBRS parts
+    - x86/speculation: Add RSB VM Exit protections
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 23 Jun 2023 16:35:33 -0300
+
+linux (4.4.0-241.275) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-241.275 -proposed tracker (LP: #2019719)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+
+  * CVE-2023-1073
+    - HID: check empty report_list in hid_validate_values()
+
+  * CVE-2023-31436
+    - net: sched: sch_qfq: prevent slab-out-of-bounds in qfq_activate_agg
+
+  * CVE-2023-1380
+    - wifi: brcmfmac: slab-out-of-bounds read in brcmf_get_assoc_ies()
+
+  * CVE-2023-32233
+    - netfilter: nf_tables: add generic macros to check for generation mask
+    - netfilter: nf_tables: remove check against removal of inactive objects
+    - netfilter: cttimeout: add netns support
+    - netfilter: nfnetlink: pass down netns pointer to call() and call_rcu()
+    - netfilter: nf_tables: add generation mask to tables
+    - netfilter: nf_tables: add generation mask to chains
+    - netfilter: nf_tables: fix update chain error
+    - netfilter: nf_tables: add generation mask to sets
+    - netfilter: nf_tables: check msg_type before nft_trans_set(trans)
+    - netfilter: nf_tables: really skip inactive sets when allocating name
+    - netfilter: nf_tables: add nft_set_is_anonymous() helper
+    - netfilter: nf_tables: reject loops from set element jump to chain
+    - netfilter: nf_tables: fix wrong destroy anonymous sets if binding fails
+    - netfilter: nf_tables: fix *leak* when expr clone fail
+    - netfilter: nf_tables: missing sanitization in data from userspace
+    - netfilter: nf_tables: revisit chain/object refcounting from elements
+    - netfilter: nf_tables: bogus EBUSY in chain deletions
+    - netfilter: nf_tables: can't fail after linking rule into active rule list
+    - netfilter: nf_tables: deactivate expressions in rule replecement routine
+    - netfilter: nf_tables: reverse order in rule replacement expansion
+    - netfilter: nf_tables: split set destruction in deactivate and destroy phase
+    - netfilter: nf_tables: unbind set in rule from commit path
+    - netfilter: nf_tables: fix set double-free in abort path
+    - netfilter: nf_tables: bogus EBUSY when deleting set after flush
+    - netfilter: nf_tables: use-after-free in failing rule with bound set
+    - netfilter: nf_tables: deactivate anonymous set from preparation phase
+
+  * CVE-2023-30456
+    - KVM: nVMX: add missing consistency checks for CR0 and CR4
+
+  * CVE-2023-28328
+    - media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 01 Jun 2023 17:38:33 -0300
+
+linux (4.4.0-240.274) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-240.274 -proposed tracker (LP: #2017289)
+
+  * CVE-2023-1829
+    - net/sched: Retire tcindex classifier
+    - [Config]: Make sure CONFIG_NET_CLS_TCINDEX is not available
+
+  * CVE-2023-1670
+    - xirc2ps_cs: Fix use after free bug in xirc2ps_detach
+
+  * net: sched: Fix use after free in red_enqueue() (LP: #2017013)
+    - net: sched: Fix use after free in red_enqueue()
+
+  * CVE-2022-3586
+    - sch_sfb: Don't assume the skb is still around after enqueueing to child
+    - sch_sfb: Also store skb len before calling child enqueue
+
+  * CVE-2022-4095
+    - staging: rtl8712: fix use after free bugs
+
+  * CVE-2023-1390
+    - tipc: fix NULL deref in tipc_link_xmit()
+    - tipc: Fix backport of b77413446408fdd256599daf00d5be72b5f3e7c6
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Sat, 22 Apr 2023 09:37:14 -0300
+
+linux (4.4.0-239.273) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-239.273 -proposed tracker (LP: #2012774)
+
+  * CVE-2022-2991
+    - lightnvm: disable the subsystem
+    - [Config]: disable CONFIG_NVM as it is broken
+
+  * CVE-2023-23455
+    - net: sched: atm: dont intepret cls results when asked to drop
+
+  * CVE-2022-20132
+    - HID: introduce hid_is_using_ll_driver
+    - HID: add hid_is_usb() function to make it simpler for USB detection
+    - HID: wacom: fix problems when device is not a valid USB device
+    - HID: check for valid USB device for many HID drivers
+    - HID: holtek: fix mouse probing
+
+  * CVE-2022-1205
+    - ax25: Fix UAF bugs in ax25 timers
+    - ax25: Fix NULL pointer dereferences in ax25 timers
+    - ax25: Fix ax25 session cleanup problems
+
+  * CVE-2022-39188
+    - mm: Force TLB flush for PFNMAP mappings before unlink_file_vma()
+    - mm: Fix TLB flush for not-first PFNMAP mappings in unmap_region()
+
+  * CVE-2022-1195
+    - net: hamradio: fix memory leak in mkiss_close
+    - hamradio: defer ax25 kfree after unregister_netdev
+    - hamradio: improve the incomplete fix to avoid NPD
+    - hamradio: defer 6pack kfree after unregister_netdev
+    - hamradio: remove needs_free_netdev to avoid UAF
+
+  * CVE-2023-26607
+    - ntfs: fix use-after-free in ntfs_ucsncmp()
+    - ntfs: fix out-of-bounds read in ntfs_attr_find()
+
+  * CVE-2022-1974
+    - NFC: reorder the logic in nfc_{un,}register_device
+    - nfc: replace improper check device_is_registered() in netlink related
+      functions
+    - NFC: NULL out the dev->rfkill to prevent UAF
+
+  * CVE-2022-3303
+    - ALSA: pcm: oss: Fix race at SNDCTL_DSP_SYNC
+
+  * CVE-2022-4662
+    - USB: core: Prevent nested device-reset calls
+
+  * CVE-2022-2380
+    - video: fbdev: sm712fb: Fix crash in smtcfb_read()
+
+  * CVE-2023-1095
+    - netfilter: nf_tables: fix null deref due to zeroed list head
+
+  * CVE-2023-1074
+    - sctp: fail if no bound addresses can be used for a given scope
+
+  * CVE-2022-0617
+    - udf: Fix NULL ptr deref when converting from inline format
+    - udf: Restore i_lenAlloc when inode expansion fails
+
+  * CVE-2022-1462
+    - tty: fix deadlock caused by calling printk() under tty_port->lock
+    - tty: extract tty_flip_buffer_commit() from tty_flip_buffer_push()
+    - tty: use new tty_insert_flip_string_and_push_buffer() in pty_write()
+
+  * CVE-2023-1118
+    - media: rc: Fix use-after-free bugs caused by ene_tx_irqsim()
+
+  * CVE-2022-41218
+    - media: dvb-core: Fix UAF due to refcount races at releasing
+
+  * CVE-2023-26545
+    - net: mpls: fix stale pointer if allocation fails during device rename
+
+  * CVE-2022-41849
+    - fbdev: smscufx: Fix use-after-free in ufx_ops_open()
+
+  * CVE-2022-3111
+    - power: supply: wm8350-power: Add missing free in free_charger_irq
+
+  * CVE-2021-45868
+    - quota: check block number when reading the block in quota file
+
+  * CVE-2021-4203
+    - cred: allow get_cred() and put_cred() to be given NULL.
+    - af_unix: fix races in sk_peer_pid and sk_peer_cred accesses
+    - net/af_unix: fix a data-race in unix_dgram_poll
+    - net/af_unix: fix a data-race in unix_dgram_sendmsg / unix_release_sock
+
+  * CVE-2021-3772
+    - sctp: use init_tag from inithdr for ABORT chunk
+    - sctp: fix the processing for INIT chunk
+    - sctp: fix the processing for INIT_ACK chunk
+    - sctp: fix the processing for COOKIE_ECHO chunk
+    - sctp: add vtag check in sctp_sf_violation
+    - sctp: add vtag check in sctp_sf_do_8_5_1_E_sa
+    - sctp: add vtag check in sctp_sf_ootb
+
+  * CVE-2022-1516
+    - net/x25: Fix null-ptr-deref caused by x25_disconnect
+
+  * CVE-2022-2318
+    - net: rose: fix UAF bugs caused by timer handler
+
+  * CVE-2022-1975
+    - NFC: netlink: fix sleep in atomic bug when firmware download timeout
+
+  * CVE-2022-3903
+    - USB: move snd_usb_pipe_sanity_check into the USB core
+    - USB: add usb_control_msg_send() and usb_control_msg_recv()
+    - USB: correct API of usb_control_msg_send/recv
+    - media: mceusb: Use new usb_control_msg_*() routines
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 24 Mar 2023 19:42:51 -0300
+
+linux (4.4.0-238.272) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-238.272 -proposed tracker (LP: #2009941)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * CVE-2021-3428
+    - ext4: don't allow overlapping system zones
+    - ext4: check journal inode extents more carefully
+
+  * CVE-2022-47929
+    - net: sched: disallow noqueue for qdisc classes
+
+  * CVE-2020-36516
+    - ipv4: avoid using shared IP generator for connected sockets
+
+  * CVE-2023-0394
+    - ipv6: raw: Deduct extension header length in rawv6_push_pending_frames
+
+  * CVE-2022-36280
+    - drm/vmwgfx: Validate the box size for the snooped cursor
+
+  * CVE-2022-41850
+    - HID: roccat: Fix use-after-free in roccat_read()
+
+  * CVE-2022-3061
+    - video: fbdev: i740fb: Error out if 'pixclock' equals zero
+
+  * CVE-2022-3628
+    - wifi: brcmfmac: Fix potential buffer overflow in brcmf_fweh_event_worker()
+
+  * CVE-2021-3732
+    - ovl: prevent private clone if bind mount is not allowed
+
+  * CVE-2021-28713
+    - xen/console: harden hvc_xen against event channel storms
+
+  * CVE-2021-28712
+    - xen/netfront: read response from backend only once
+    - xen/netfront: disentangle tx_skb_freelist
+    - xen/netfront: don't trust the backend response data blindly
+    - xen/netfront: harden netfront against event channel storms
+
+  * CVE-2021-28711
+    - xen: sync include/xen/interface/io/ring.h with Xen's newest version
+    - xen/blkfront: don't take local copy of a request from the ring page
+    - xen/blkfront: read response from backend only once
+    - xen/blkfront: don't trust the backend response data blindly
+    - xen/blkfront: harden blkfront against event channel storms
+    - xen/blkfront: fix bug in backported patch
+
+  * CVE-2022-20572 // CVE-2022-2503
+    - dm verity: set DM_TARGET_IMMUTABLE feature flag
+
+  * CVE-2022-0487
+    - mmc: moxart: remove unneeded check for drvdata
+    - moxart: fix potential use-after-free on remove path
+
+  * CVE-2021-4149
+    - btrfs: unlock newly allocated extent buffer after error
+
+  * CVE-2022-3646
+    - nilfs2: fix leak of nilfs_root in case of writer thread creation failure
+
+  * CVE-2021-26401
+    - x86/speculation: Use generic retpoline by default on AMD
+
+  * CVE-2021-3659
+    - net: mac802154: Fix general protection fault
+
+  * CVE-2021-3669
+    - ipc: replace costly bailout check in sysvipc_find_ipc()
+
+  * CVE-2022-2663
+    - netfilter: nf_conntrack_irc: Fix forged IP logic
+    - netfilter: nf_conntrack_irc: Tighten matching on DCC message
+
+  * CVE-2022-1016
+    - netfilter: nf_tables: initialize registers in nft_do_chain()
+
+  * CVE-2022-0494
+    - block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern
+
+  * rtcpie in timers from ubuntu_kernel_selftests randomly failing
+    (LP: #1814234)
+    - SAUCE: selftest: rtctest: Force passing unreliable subtest
+
+  * CVE-2022-36879
+    - xfrm: xfrm_policy: fix a possible double xfrm_pols_put() in
+      xfrm_bundle_lookup()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Sat, 11 Mar 2023 06:18:13 -0300
+
+linux (4.4.0-237.271) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-237.271 -proposed tracker (LP: #2007452)
+
+  * CVE-2021-4155
+    - xfs: map unwritten blocks in XFS_IOC_{ALLOC,FREE}SP just like fallocate
+
+  * CVE-2023-0045
+    - x86/bugs: Flush IBP in ib_prctl_set()
+
+  * CVE-2023-23559
+    - wifi: rndis_wlan: Prevent buffer overflow in rndis_query_oid
+
+  * CVE-2022-20566
+    - Bluetooth: L2CAP: Fix use-after-free caused by l2cap_chan_put
+
+  * CVE-2022-41858
+    - drivers: net: slip: fix NPD bug in sl_tx_timeout()
+
+  * 5.15.0-58.64 breaks xen bridge networking (pvh domU) (LP: #2002889)
+    - xen/netback: fix build warning
+
+  * CVE-2022-42895
+    - Bluetooth: L2CAP: Fix attempting to access uninitialized memory
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 15 Feb 2023 20:56:04 -0300
+
+linux (4.4.0-236.270) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-236.270 -proposed tracker (LP: #2000934)
+
+  * CVE-2022-45934
+    - Bluetooth: L2CAP: Fix u8 overflow
+
+  * CVE-2022-42896
+    - Bluetooth: L2CAP: Introduce proper defines for PSM ranges
+    - Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM
+    - Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm
+
+  * CVE-2022-3643
+    - xen-netback: support multiple extra info fragments passed from frontend
+    - xen-netback: fix extra_info handling in xenvif_tx_err()
+    - xen/netback: Ensure protocol headers don't fall in the non-linear area
+
+  * CVE-2022-43945
+    - NFSD: Cap rsize_bop result based on send buffer size
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 03 Jan 2023 09:30:47 -0300
+
+linux (4.4.0-235.269) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-235.269 -proposed tracker (LP: #1997020)
+
+  * CVE-2022-42703
+    - mm/rmap.c: don't reuse anon_vma if we just want a copy
+    - mm: rmap: explicitly reset vma->anon_vma in unlink_anon_vmas()
+    - mm, rmap: handle anon_vma_prepare() common case inline
+    - mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse
+
+  * CVE-2022-3565
+    - mISDN: fix use-after-free bugs in l1oip timer handlers
+
+  * CVE-2022-43750
+    - usb: mon: make mmapped memory read only
+
+  * CVE-2022-3566
+    - tcp: Fix data races around icsk->icsk_af_ops.
+
+  * CVE-2022-3567
+    - ipv6: annotate some data-races around sk->sk_prot
+    - ipv6: Fix data races around sk->sk_prot.
+
+  * CVE-2022-3621
+    - nilfs2: fix NULL pointer dereference at nilfs_bmap_lookup_at_level()
+
+  * CVE-2022-3564
+    - Bluetooth: remove unneeded variable in l2cap_stream_rx
+    - Bluetooth: L2CAP: Fix use-after-free caused by l2cap_reassemble_sdu
+
+  * CVE-2022-3524
+    - tcp/udp: Fix memory leak in ipv6_renew_options().
+
+  * CVE-2022-3635
+    - atm: idt77252: fix use-after-free bugs caused by tst_timer
+
+  * CVE-2022-40768
+    - scsi: stex: Properly zero out the passthrough command structure
+
+  * CVE-2022-3239
+    - media: em28xx: initialize refcount before kref_get
+
+  * CVE-2022-3649
+    - nilfs2: fix use-after-free bug of struct nilfs_root
+
+  * CVE-2022-3594
+    - r8152: Rate limit overflow messages
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 18 Nov 2022 14:42:01 -0300
+
+linux (4.4.0-234.268) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-234.268 -proposed tracker (LP: #1990413)
+
+  * CVE-2022-1729
+    - perf: Fix sys_perf_event_open() race against self
+
+  * CVE-2022-2964
+    - ax88179_178a: Merge memcpy + le32_to_cpus to get_unaligned_le32
+    - net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup
+
+  * CVE-2022-1204
+    - ax25: add refcount in ax25_dev to avoid UAF bugs
+    - ax25: fix reference count leaks of ax25_dev
+    - ax25: fix UAF bugs of net_device caused by rebinding operation
+    - ax25: Fix refcount leaks caused by ax25_cb_del()
+    - ax25: fix UAF bug in ax25_send_control()
+
+  * CVE-2022-1199
+    - ax25: NPD bug when detaching AX25 device
+    - ax25: improve the incomplete fix to avoid UAF and NPD bugs
+    - ax25: Fix NULL pointer dereference in ax25_kill_by_device
+    - ax25: fix NPD bug in ax25_disconnect
+
+  * CVE-2022-0850
+    - ext4: fix kernel infoleak via ext4_extent_header
+
+  * CVE-2022-3202
+    - jfs: fix GPF in diFree
+    - jfs: prevent NULL deref in diFree
+
+  * CVE-2022-2978
+    - SAUCE: fs: fix UAF/GPF bug in nilfs_mdt_destroy
+
+  * CVE-2022-3028
+    - af_key: Do not call xfrm_probe_algs in parallel
+
+  * CVE-2022-2639
+    - openvswitch: fix OOB access in reserve_sfa_size()
+
+  * CVE-2021-4037
+    - xfs: fix up non-directory creation in SGID directories
+
+  * CVE-2022-20368
+    - net/packet: fix slab-out-of-bounds access in packet_recvmsg()
+
+  * CVE-2022-36946
+    - netfilter: nf_queue: do not allow packet truncation below transport header
+      offset
+
+  * CVE-2021-33655
+    - fbcon: Disallow setting font bigger than screen size
+    - fbcon: Prevent that screen size is smaller than font size
+    - fbmem: Check virtual screen sizes in fb_set_var()
+
+  * CVE-2021-33656
+    - vt: drop old FONT ioctls
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 21 Sep 2022 12:36:48 -0300
+
+linux (4.4.0-233.267) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-233.267 -proposed tracker (LP: #1985080)
+
+  * xen blkfront leaks memory when disconnecting devices (LP: #1985527)
+    - Revert "xen/blkfront: force data bouncing when backend is untrusted"
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 11 Aug 2022 19:00:44 -0300
+
+linux (4.4.0-232.266) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-232.266 -proposed tracker (LP: #1985080)
+
+  * CVE-2022-33742
+    - xen/blkfront: force data bouncing when backend is untrusted
+
+  * CVE-2022-33741
+    - net: Rename and export copy_skb_header
+    - xen-netfront: avoid packet loss when ethernet header crosses page boundary
+    - xen/netfront: force data bouncing when backend is untrusted
+
+  * CVE-2022-33740
+    - xen/netfront: fix leaking data in shared pages
+
+  * CVE-2022-26365
+    - xen/blkfront: fix leaking data in shared pages
+
+  * Kernel fails to boot on some AMD systems (LP: #1983030)
+    - x86/tlb: Flush global mappings when KAISER is disabled
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 11 Aug 2022 13:55:53 -0300
+
+linux (4.4.0-231.265) xenial; urgency=medium
+
+  * CVE-2022-2586
+    - SAUCE: netfilter: nf_tables: do not allow SET_ID to refer to another table
+
+  * CVE-2022-2588
+    - SAUCE: net_sched: cls_route: remove from list when handle is 0
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 05 Aug 2022 05:42:26 -0300
+
+linux (4.4.0-230.264) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-230.264 -proposed tracker (LP: #1982029)
+
+  * CVE-2022-34918
+    - netfilter: nf_tables: stricter validation of element data
+
+  * CVE-2022-25258
+    - USB: gadget: validate interface OS descriptor requests
+
+  * CVE-2022-25375
+    - usb: gadget: rndis: check size of RNDIS_MSG_SET command
+    - usb: gadget: rndis: prevent integer overflow in rndis_set_response()
+
+  * CVE-2022-20141
+    - igmp: Add ip_mc_list lock in ip_check_mc_rcu
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 18 Jul 2022 16:27:36 -0300
+
+linux (4.4.0-229.263) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-229.263 -proposed tracker (LP: #1980112)
+
+  * CVE-2022-1679
+    - SAUCE: ath9k: fix use-after-free in ath9k_hif_usb_rx_cb
+
+  * CVE-2022-1419
+    - drm/vgem: Reclassify buffer creation debug message
+    - drm/vgem: Close use-after-free race in vgem_gem_create
+
+  * CVE-2022-1652
+    - floppy: use a statically allocated error counter
+
+  * CVE-2022-1734
+    - nfc: nfcmrvl: main: reorder destructive operations in
+      nfcmrvl_nci_unregister_dev to avoid bugs
+
+  * CVE-2022-1353
+    - af_key: add __GFP_ZERO flag for compose_sadb_supported in function
+      pfkey_register
+
+  * CVE-2021-4202
+    - NFC: reorganize the functions in nci_request
+    - NFC: add NCI_UNREG flag to eliminate the race
+
+  * CVE-2021-4197
+    - cgroup: Use open-time credentials for process migraton perm checks
+
+  * CVE-2022-28356
+    - llc: fix netdevice reference leaks in llc_ui_bind()
+    - netdevice: add the case if dev is NULL
+    - llc: only change llc->dev when bind() succeeds
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 28 Jun 2022 15:33:29 -0300
+
+linux (4.4.0-228.262) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-228.262 -proposed tracker (LP: #1979228)
+
+  * CVE-2021-39714
+    - staging: ion: Prevent incorrect reference counting behavour
+
+  * CVE-2021-3752
+    - Bluetooth: fix use-after-free error in lock_sock_nested()
+
+  * CVE-2021-3609
+    - can: bcm: delay release of struct bcm_op after synchronize_rcu()
+
+  * CVE-2022-21123 // CVE-2022-21125 // CVE-2022-21166
+    - x86/cpu: Add Elkhart Lake to Intel family
+    - cpu/speculation: Add prototype for cpu_show_srbds()
+    - x86/cpu: Add Jasper Lake to Intel family
+    - x86/cpu: Add Cannonlake to Intel family
+    - x86/CPU: Add Icelake model number
+    - x86/CPU: Add more Icelake model numbers
+    - x86/cpu: Add Comet Lake to the Intel CPU models header
+    - x86/cpu: Add Lakefield, Alder Lake and Rocket Lake models to the to Intel
+      CPU family
+    - x86/cpu: Add another Alder Lake CPU to the Intel family
+    - Documentation: Add documentation for Processor MMIO Stale Data
+    - x86/speculation/mmio: Enumerate Processor MMIO Stale Data bug
+    - SAUCE: x86: fixup mds_select_mitigation
+    - x86/speculation: Add a common function for MD_CLEAR mitigation update
+    - x86/speculation/mmio: Add mitigation for Processor MMIO Stale Data
+    - x86/bugs: Group MDS, TAA & Processor MMIO Stale Data mitigations
+    - x86/speculation/mmio: Enable CPU Fill buffer clearing on idle
+    - x86/speculation/mmio: Add sysfs reporting for Processor MMIO Stale Data
+    - x86/speculation/srbds: Update SRBDS mitigation selection
+    - x86/speculation/mmio: Reuse SRBDS mitigation for SBDS
+    - KVM: x86/speculation: Disable Fill buffer clear within guests
+    - x86/speculation/mmio: Print SMT warning
+
+  * CVE-2022-0330
+    - drm/i915: Flush TLBs before releasing backing store
+
+  * CVE-2021-3760
+    - nfc: nci: fix the UAF of rf_conn_info object
+
+  * CVE-2021-39685
+    - USB: gadget: detect too-big endpoint 0 requests
+    - USB: gadget: zero allocate endpoint 0 buffers
+    - USB: gadget: bRequestType is a bitfield, not a enum
+
+  * CVE-2022-24958
+    - usb: gadget: don't release an existing dev->buf
+    - usb: gadget: clear related members when goto fail
+
+  * CVE-2022-28388
+    - can: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error
+      path
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 20 Jun 2022 17:04:22 -0300
+
+linux (4.4.0-227.261) xenial; urgency=medium
+
+  * CVE-2022-1966
+    - netfilter: nf_tables: fix memory leak if expr init fails
+    - netfilter: nf_tables: disallow non-stateful expression in sets earlier
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 03 Jun 2022 09:07:19 -0300
+
+linux (4.4.0-225.258) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-225.258 -proposed tracker (LP: #1975710)
+
+  * CVE-2022-21499
+    - SAUCE: debug: Lock down kgdb
+
+  * Unprivileged users may use PTRACE_SEIZE to set PTRACE_O_SUSPEND_SECCOMP
+    option (LP: #1972740)
+    - ptrace: Check PTRACE_O_SUSPEND_SECCOMP permission on PTRACE_SEIZE
+
+  * ext4: limit length to bitmap_maxbytes (LP: #1972281)
+    - ext4: limit length to bitmap_maxbytes - blocksize in punch_hole
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 25 May 2022 14:40:35 -0300
+
+linux (4.4.0-224.257) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-224.257 -proposed tracker (LP: #1971450)
+
+  * CVE-2021-39713
+    - SAUCE: net: sched: prevent UAF on tc_ctl_tfilter when temporarily dropping
+      rtnl_lock
+
+  * CVE-2022-28390
+    - can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path
+
+  * CVE-2021-4157
+    - pNFS/flexfiles: fix incorrect size check in decode_nfs_fh()
+
+  * Xenial: kernel BUG/Oops/crash in fuse_readdir() due to CVE-2020-36322
+    backport (LP: #1970482)
+    - SAUCE: fuse: fix bad !inode in fuse_direntplus_link()
+
+  * Use kernel-testing repo from launchpad for ADT tests (LP: #1968016)
+    - [Debian] Use kernel-testing repo from launchpad
+
+  * CVE-2022-27223
+    - USB: gadget: validate endpoint index for xilinx udc
+
+  * CVE-2022-26490
+    - nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION
+
+  * CVE-2020-27820
+    - SAUCE: drm/nouveau: disallow manual bind/unbind operations
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 03 May 2022 13:21:01 -0300
+
+linux (4.4.0-223.256) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-223.256 -proposed tracker (LP: #1966469)
+
+  * CVE-2021-0920
+    - net: split out functions related to registering inflight socket files
+    - af_unix: fix garbage collect vs MSG_PEEK
+    - [Config]: Enable new option CONFIG_UNIX_SCM
+
+  * CVE-2021-0935
+    - l2tp: fix races with ipv4-mapped ipv6 addresses
+    - net: ipv6: reset daddr and dport in sk if connect() fails
+    - net: ipv6: keep sk status consistent after datagram connect failure
+
+  * CVE-2020-12888
+    - vfio/type1: Support faulting PFNMAP vmas
+    - vfio-pci: Fault mmaps to enable vma tracking
+    - vfio-pci: Invalidate mmaps and block MMIO access on disabled memory
+    - vfio/pci: Fix SR-IOV VF handling with MMIO blocking
+    - vfio-pci: Use io_remap_pfn_range() for PCI IO memory
+    - vfio/pci: zap_vma_ptes() needs MMU
+
+  * xenial upgrade of lockdown patches dropped ioport denial (LP: #1962315)
+    - Resurect ioport.c portions of "x86: Lock down IO port access when module
+      security is enabled"
+
+  * CVE-2021-4083
+    - fs: add fget_many() and fput_many()
+    - fget: check that the fd still exists after getting a ref to it
+
+  * CVE-2021-28964
+    - btrfs: fix race when cloning extent buffer during rewind of an old root
+    - btrfs: fix race when picking most recent mod log operation for an old root
+
+  * CVE-2021-45486
+    - mm: zero hash tables in allocator
+    - inet: use bigger hash table for IP ID generation
+
+  * CVE-2021-39636
+    - xtables: add xt_match, xt_target and data copy_to_user functions
+    - iptables: use match, target and data copy_to_user helpers
+    - ip6tables: use match, target and data copy_to_user helpers
+    - xtables: extend matches and targets with .usersize
+    - netfilter: x_tables: fix pointer leaks to userspace
+    - netfilter: xtables: zero padding in data_to_user
+
+  * CVE-2021-37159
+    - net: usb: hso: don't print error when allocating urb fails
+    - net: hso: register netdev later to avoid a race condition
+    - usb: hso: fix error handling code of hso_create_net_device
+
+  * linux: Fix failure in ubuntu_boot:log_check test (LP: #1965160)
+    - dmaengine: Replace WARN_TAINT_ONCE() with pr_warn_once()
+
+  * CVE-2020-3702
+    - ath: Use safer key clearing with key cache entries
+    - ath9k: Clear key cache explicitly on disabling hardware
+    - ath: Export ath_hw_keysetmac()
+    - ath: Modify ath_key_delete() to not need full key entry
+    - ath9k: Postpone key cache entry deletion for TXQ frames reference it
+
+  * CVE-2021-43976
+    - mwifiex: Fix skb_over_panic in mwifiex_usb_recv()
+
+  * CVE-2021-42739
+    - media: firewire: firedtv-avc: fix a buffer overflow in avc_ca_pmt()
+
+  * CVE-2020-26141
+    - ath10k: Fix TKIP Michael MIC verification for PCIe
+
+  * CVE-2020-26145
+    - mac80211: add get TID helper
+    - ath10k: add struct for high latency PN replay protection
+    - ath10k: add CCMP PN replay protection for fragmented frames for PCIe
+    - ath10k: drop fragments with multicast DA for PCIe
+
+  * CVE-2021-31916
+    - dm ioctl: fix out of bounds array access when no devices
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 28 Mar 2022 11:14:03 -0300
+
+linux (4.4.0-222.255) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-222.255 -proposed tracker (LP: #1964253)
+
+  * CVE-2021-38208
+    - nfc: fix NULL ptr dereference in llcp_sock_getname() after failed connect
+
+  * CVE-2020-26139
+    - mac80211: do not accept/forward invalid EAPOL frames
+    - mac80211: fix memory corruption in EAPOL handling
+
+  * CVE-2020-36322
+    - fuse: fix bad inode
+    - fuse: fix live lock in fuse_iget()
+
+  * CVE-2021-38198
+    - KVM: nVMX: fix EPT permissions as reported in exit qualification
+    - KVM: X86: MMU: Use the correct inherited permissions to get shadow page
+
+  * linux-4.4 scheduling while atomic on azure (LP: #1960059)
+    - PCI: hv: Do not sleep in compose_msi_msg()
+
+  * CVE-2016-2854
+    - aufs: bugfix, set ACL too in copy-up and chmod
+    - aufs: tiny, extract a part of copy-up dir
+    - aufs: security bugfix, copy-up resets ACL
+
+  * CVE-2016-2853
+    - aufs: security bugfix, test mnt_ns in open(2) for fuse branch
+
+  * CVE-2022-0492
+    - cgroup-v1: Require capabilities to set release_agent
+
+  * CVE-2021-28688
+    - xen-blkback: don't leak persistent grants from xen_blkbk_map()
+
+  * CVE-2020-25673
+    - nfc: Avoid endless loops caused by repeated llcp_sock_connect()
+
+  * CVE-2021-20292
+    - drm/ttm/nouveau: don't call tt destroy callback on alloc failure.
+
+  * CVE-2021-33098
+    - ixgbe: fix large MTU request from VF
+
+  * CVE-2018-5995
+    - percpu: stop printing kernel addresses
+
+  * CVE-2020-12655
+    - xfs: add agf freeblocks verify in xfs_agf_verify
+
+  * CVE-2021-3573
+    - Bluetooth: use correct lock to prevent UAF of hdev object
+    - Bluetooth: defer cleanup of resources in hci_unregister_dev()
+
+  * CVE-2021-20317
+    - rbtree: cache leftmost node internally
+    - lib/timerqueue: Rely on rbtree semantics for next timer
+
+  * CVE-2021-43389
+    - isdn: cpai: check ctr->cnr to avoid array index out of bound
+
+  * CVE-2021-45095
+    - phonet: refcount leak in pep_sock_accep
+
+  * CVE-2021-39648
+    - usb: gadget: configfs: Fix use-after-free issue with udc_name
+
+  * CVE-2021-29650
+    - netfilter: x_tables: Use correct memory barriers.
+
+  * CVE-2021-32399
+    - bluetooth: eliminate the potential race condition when removing the HCI
+      controller
+
+  * CVE-2021-38160
+    - virtio_console: Assure used length from device is limited
+
+  * CVE-2021-33033
+    - cipso,calipso: resolve a number of problems with the DOI refcounts
+
+  * CVE-2021-23134
+    - net/nfc: fix use-after-free llcp_sock_bind/connect
+
+  * CVE-2020-25672
+    - nfc: fix memory leak in llcp_sock_connect()
+
+  * CVE-2020-25671
+    - nfc: fix refcount leak in llcp_sock_connect()
+
+  * CVE-2020-25670
+    - nfc: fix refcount leak in llcp_sock_bind()
+
+  * CVE-2021-40490
+    - ext4: fix race writing to an inline_data file while its xattrs are changing
+
+  * CVE-2021-45469
+    - f2fs: fix to do sanity check on last xattr entry in __f2fs_setxattr()
+
+  * CVE-2021-3506
+    - f2fs: fix to avoid out-of-bounds memory access
+
+  * CVE-2019-19449
+    - f2fs: fix wrong total_sections check and fsmeta check
+    - f2fs: fix to do sanity check on segment/section count
+
+  * CVE-2020-36385
+    - RDMA/ucma: Put a lock around every call to the rdma_cm layer
+    - RDMA/cma: Add missing locking to rdma_accept()
+    - RDMA/ucma: Fix the locking of ctx->file
+    - RDMA/ucma: Rework ucma_migrate_id() to avoid races with destroy
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 09 Mar 2022 11:48:53 +0100
+
+linux (4.4.0-221.254) xenial; urgency=medium
+
+  * CVE-2022-0001
+    - cpu/SMT: create and export cpu_smt_possible()
+    - x86/speculation: Merge one test in spectre_v2_user_select_mitigation()
+    - x86,bugs: Unconditionally allow spectre_v2=retpoline,amd
+    - SAUCE: x86/speculation: Rename RETPOLINE_AMD to RETPOLINE_LFENCE
+    - SAUCE: x86/speculation: Add eIBRS + Retpoline options
+    - SAUCE: Documentation/hw-vuln: Update spectre doc
+
+  * Disable unprivileged BPF by default (LP: #1961338)
+    - bpf: Add kconfig knob for disabling unpriv bpf by default
+    - [Config] set CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 28 Feb 2022 19:10:43 -0300
+
+linux (4.4.0-219.252) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-219.252 -proposed tracker (LP: #1959777)
+
+  * CVE-2021-28972
+    - PCI: rpadlpar: Fix potential drc_name corruption in store functions
+
+  * CVE-2021-0129
+    - Bluetooth: SMP: Fail if remote and local public keys are identical
+
+  * CVE-2021-34693
+    - can: bcm: fix infoleak in struct bcm_msg_head
+
+  * CVE-2021-3564
+    - Bluetooth: fix the erroneous flush_work() order
+
+  * CVE-2020-26147
+    - mac80211: assure all fragments are encrypted
+
+  * CVE-2021-38204
+    - usb: max-3421: Prevent corruption of freed memory
+
+  * CVE-2021-3679
+    - tracing: Fix bug in rb_per_cpu_empty() that might cause deadloop.
+
+  * CVE-2021-3483
+    - firewire: nosy: Fix a use-after-free bug in nosy_ioctl()
+
+  * CVE-2021-33034
+    - Bluetooth: verify AMP hci_chan before amp_destroy
+
+  * CVE-2021-3612
+    - Input: joydev - prevent use of not validated data in JSIOCSBTNMAP ioctl
+
+  * CVE-2021-45485
+    - ipv6: use prandom_u32() for ID generation
+
+  * CVE-2021-42008
+    - net: 6pack: fix slab-out-of-bounds in decode_data
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 03 Feb 2022 14:45:52 -0300
+
+linux (4.4.0-218.251) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-218.251 -proposed tracker (LP: #1952442)
+
+  * CVE-2021-4002
+    - hugetlbfs: flush TLBs correctly after huge_pmd_unshare
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update Ubuntu.md
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 02 Dec 2021 09:53:31 +0100
+
+linux (4.4.0-217.250) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-217.250 -proposed tracker (LP: #1944538)
+
+  * memory leaking when removing a profile (LP: #1939915)
+    - security/apparmor/label.c: Clean code by removing redundant instructions
+    - apparmor: Fix memory leak of profile proxy
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 22 Sep 2021 10:56:53 +0200
+
+linux (4.4.0-216.249) xenial; urgency=medium
+
+  * s390x BPF JIT vulnerabilities (LP: #1943960)
+    - SAUCE: s390/bpf: Fix 64-bit subtraction of the -0x80000000 constant
+    - SAUCE: s390/bpf: Fix optimizing out zero-extensions
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 17 Sep 2021 11:07:39 -0300
+
+linux (4.4.0-214.246) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-214.246 -proposed tracker (LP: #1941638)
+
+  * CVE-2021-3653
+    - KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
+      (CVE-2021-3653)
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 25 Aug 2021 20:42:34 -0300
+
+linux (4.4.0-213.245) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-213.245 -proposed tracker (LP: #1938186)
+
+  * CVE-2021-22555
+    - netfilter: x_tables: fix compat match/target pad out-of-bound write
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 28 Jul 2021 09:31:47 +0200
+
+linux (4.4.0-212.244) xenial; urgency=medium
+
+  * CVE-2021-33909
+    - SAUCE: seq_file: Disallow extremely large seq buffer allocations
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 08 Jul 2021 09:13:34 -0300
+
+linux (4.4.0-211.243) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-211.243 -proposed tracker (LP: #1926472)
+
+  * Taking a memory dump of user mode process on Xenial hosts causes
+    bugcheck/kernel panic and core dump (LP: #1921211)
+    - mm: check VMA flags to avoid invalid PROT_NONE NUMA balancing
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 29 Apr 2021 10:13:40 +0200
+
+linux (4.4.0-210.242) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-210.242 -proposed tracker (LP: #1924644)
+
+  * setting extended attribute may cause memory leak (LP: #1924611)
+    - SAUCE: vfs_setxattr: free converted value if xattr_permission returns error
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 16 Apr 2021 11:33:09 +0200
+
+linux (4.4.0-209.241) xenial; urgency=medium
+
+  * overlayfs calls vfs_setxattr without cap_convert_nscap
+    - vfs: move cap_convert_nscap() call into vfs_setxattr()
+
+  * CVE-2021-29154
+    - SAUCE: bpf, x86: Validate computation of branch displacements for x86-64
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 12 Apr 2021 19:27:28 -0300
+
+linux (4.4.0-208.240) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-208.240 -proposed tracker (LP: #1922069)
+
+  * linux ADT test failure with linux/4.4.0-207.239 -
+    ubuntu_qrt_kernel_security.test-kernel-security.py (LP: #1922200) //
+    CVE-2018-5953 // CVE-2018-5995 // CVE-2018-7754
+    - SAUCE: Revert "printk: hash addresses printed with %p"
+
+  * lxd 2.0.11-0ubuntu1~16.04.4 ADT test failure with linux 4.4.0-207.239
+    (LP: #1921969)
+    - SAUCE: Fix fuse regression in 4.4.0-207.239
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 01 Apr 2021 12:57:17 +0200
+
+linux (4.4.0-207.239) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-207.239 -proposed tracker (LP: #1919558)
+
+  * Xenial update: v4.4.262 upstream stable release (LP: #1920221)
+    - uapi: nfnetlink_cthelper.h: fix userspace compilation error
+    - ath9k: fix transmitting to stations in dynamic SMPS mode
+    - net: Fix gro aggregation for udp encaps with zero csum
+    - can: skb: can_skb_set_owner(): fix ref counting if socket was closed before
+      setting skb ownership
+    - can: flexcan: assert FRZ bit in flexcan_chip_freeze()
+    - can: flexcan: enable RX FIFO after FRZ/HALT valid
+    - netfilter: x_tables: gpf inside xt_find_revision()
+    - cifs: return proper error code in statfs(2)
+    - floppy: fix lock_fdc() signal handling
+    - Revert "mm, slub: consider rest of partial list if acquire_slab() fails"
+    - futex: Change locking rules
+    - futex: Cure exit race
+    - futex: fix dead code in attach_to_pi_owner()
+    - net/mlx4_en: update moderation when config reset
+    - net: lapbether: Remove netif_start_queue / netif_stop_queue
+    - net: davicom: Fix regulator not turned off on failed probe
+    - net: davicom: Fix regulator not turned off on driver removal
+    - media: usbtv: Fix deadlock on suspend
+    - mmc: mxs-mmc: Fix a resource leak in an error handling path in
+      'mxs_mmc_probe()'
+    - mmc: mediatek: fix race condition between msdc_request_timeout and irq
+    - powerpc/perf: Record counter overflow always if SAMPLE_IP is unset
+    - PCI: xgene-msi: Fix race in installing chained irq handler
+    - s390/smp: __smp_rescan_cpus() - move cpumask away from stack
+    - scsi: libiscsi: Fix iscsi_prep_scsi_cmd_pdu() error handling
+    - ALSA: hda/hdmi: Cancel pending works before suspend
+    - ALSA: hda: Avoid spurious unsol event handling during S3/S4
+    - ALSA: usb-audio: Fix "cannot get freq eq" errors on Dell AE515 sound bar
+    - s390/dasd: fix hanging DASD driver unbind
+    - mmc: core: Fix partition switch time for eMMC
+    - scripts/recordmcount.{c,pl}: support -ffunction-sections .text.* section
+      names
+    - Goodix Fingerprint device is not a modem
+    - usb: gadget: f_uac2: always increase endpoint max_packet_size by one audio
+      slot
+    - usb: renesas_usbhs: Clear PIPECFG for re-enabling pipe with other EPNUM
+    - xhci: Improve detection of device initiated wake signal.
+    - USB: serial: io_edgeport: fix memory leak in edge_startup
+    - USB: serial: ch341: add new Product ID
+    - USB: serial: cp210x: add ID for Acuity Brands nLight Air Adapter
+    - USB: serial: cp210x: add some more GE USB IDs
+    - usbip: fix stub_dev to check for stream socket
+    - usbip: fix vhci_hcd to check for stream socket
+    - usbip: fix stub_dev usbip_sockfd_store() races leading to gpf
+    - staging: rtl8192u: fix ->ssid overflow in r8192_wx_set_scan()
+    - staging: rtl8188eu: prevent ->ssid overflow in rtw_wx_set_scan()
+    - staging: rtl8712: unterminated string leads to read overflow
+    - staging: rtl8188eu: fix potential memory corruption in
+      rtw_check_beacon_data()
+    - staging: rtl8712: Fix possible buffer overflow in r8712_sitesurvey_cmd
+    - staging: rtl8192e: Fix possible buffer overflow in _rtl92e_wx_set_scan
+    - staging: comedi: addi_apci_1032: Fix endian problem for COS sample
+    - staging: comedi: addi_apci_1500: Fix endian problem for command sample
+    - staging: comedi: adv_pci1710: Fix endian problem for AI command data
+    - staging: comedi: das6402: Fix endian problem for AI command data
+    - staging: comedi: das800: Fix endian problem for AI command data
+    - staging: comedi: dmm32at: Fix endian problem for AI command data
+    - staging: comedi: me4000: Fix endian problem for AI command data
+    - staging: comedi: pcl711: Fix endian problem for AI command data
+    - staging: comedi: pcl818: Fix endian problem for AI command data
+    - NFSv4.2: fix return value of _nfs4_get_security_label()
+    - block: rsxx: fix error return code of rsxx_pci_probe()
+    - alpha: add $(src)/ rather than $(obj)/ to make source file path
+    - alpha: merge build rules of division routines
+    - alpha: make short build log available for division routines
+    - alpha: Package string routines together
+    - alpha: move exports to actual definitions
+    - alpha: get rid of tail-zeroing in __copy_user()
+    - alpha: switch __copy_user() and __do_clean_user() to normal calling
+      conventions
+    - powerpc/64s: Fix instruction encoding for lis in ppc_function_entry()
+    - media: hdpvr: Fix an error handling path in hdpvr_probe()
+    - KVM: arm64: Fix exclusive limit for IPA size
+    - xen/events: reset affinity of 2-level event when tearing it down
+    - xen/events: don't unmask an event channel when an eoi is pending
+    - xen/events: avoid handling the same event on two cpus at the same time
+    - Linux 4.4.262
+
+  * Xenial update: v4.4.261 upstream stable release (LP: #1920218)
+    - futex: fix irq self-deadlock and satisfy assertion
+    - futex: fix spin_lock() / spin_unlock_irq() imbalance
+    - ALSA: ctxfi: cthw20k2: fix mask on conf to allow 4 bits
+    - rsxx: Return -EFAULT if copy_to_user() fails
+    - dm table: fix iterate_devices based device capability checks
+    - platform/x86: acer-wmi: Add new force_caps module parameter
+    - PCI: Add function 1 DMA alias quirk for Marvell 9215 SATA controller
+    - Linux 4.4.261
+
+  * CVE-2019-19061
+    - iio: imu: adis16400: fix memory leak
+
+  * CVE-2018-5953 // CVE-2018-5995 // CVE-2018-7754
+    - printk: hash addresses printed with %p
+
+  * CVE-2017-5967
+    - time: Remove CONFIG_TIMER_STATS
+    - [Config] Dropped CONFIG_TIMER_STATS
+
+  * CVE-2019-16232
+    - libertas: fix a potential NULL pointer dereference
+
+  * CVE-2015-1350
+    - xfs: Propagate dentry down to inode_change_ok()
+    - fuse: Propagate dentry down to inode_change_ok()
+    - fs: Give dentry to inode_change_ok() instead of inode
+    - fs: Avoid premature clearing of capabilities
+
+  * CVE-2018-13095
+    - xfs: More robust inode extent count validation
+
+  * i40e PF reset due to incorrect MDD event (LP: #1772675)
+    - i40e: change behavior on PF in response to MDD event
+
+  * Xenial update: v4.4.260 upstream stable release (LP: #1918184)
+    - futex: Ensure the correct return value from futex_lock_pi()
+    - net: usb: qmi_wwan: support ZTE P685M modem
+    - iwlwifi: pcie: fix to correct null check
+    - mmc: sdhci-esdhc-imx: fix kernel panic when remove module
+    - scripts: use pkg-config to locate libcrypto
+    - scripts: set proper OpenSSL include dir also for sign-file
+    - hugetlb: fix update_and_free_page contig page struct assumption
+    - JFS: more checks for invalid superblock
+    - xfs: Fix assert failure in xfs_setattr_size()
+    - net: fix up truesize of cloned skb in skb_prepare_for_shift()
+    - mm/hugetlb.c: fix unnecessary address expansion of pmd sharing
+    - staging: fwserial: Fix error handling in fwserial_create
+    - x86/reboot: Add Zotac ZBOX CI327 nano PCI reboot quirk
+    - vt/consolemap: do font sum unsigned
+    - wlcore: Fix command execute failure 19 for wl12xx
+    - pktgen: fix misuse of BUG_ON() in pktgen_thread_worker()
+    - ath10k: fix wmi mgmt tx queue full due to race condition
+    - x86/build: Treat R_386_PLT32 relocation as R_386_PC32
+    - Bluetooth: Fix null pointer dereference in amp_read_loc_assoc_final_data
+    - staging: most: sound: add sanity check for function argument
+    - media: uvcvideo: Allow entities with no pads
+    - Xen/gnttab: handle p2m update errors on a per-slot basis
+    - xen-netback: respect gnttab_map_refs()'s return value
+    - zsmalloc: account the number of compacted pages correctly
+    - swap: fix swapfile read/write offset
+    - media: v4l: ioctl: Fix memory leak in video_usercopy
+    - Linux 4.4.260
+
+  * Xenial update: v4.4.259 upstream stable release (LP: #1918182)
+    - HID: make arrays usage and value to be the same
+    - usb: quirks: add quirk to start video capture on ELMO L-12F document camera
+      reliable
+    - xen-netback: delete NAPI instance when queue fails to initialize
+    - ntfs: check for valid standard information attribute
+    - igb: Remove incorrect "unexpected SYS WRAP" log message
+    - scripts/recordmcount.pl: support big endian for ARCH sh
+    - kdb: Make memory allocations more robust
+    - MIPS: vmlinux.lds.S: add missing PAGE_ALIGNED_DATA() section
+    - Bluetooth: Fix initializing response id after clearing struct
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Spring
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Arndale Octa
+    - Bluetooth: drop HCI device reference before return
+    - Bluetooth: Put HCI device if inquiry procedure interrupts
+    - usb: dwc2: Abort transaction after errors with unknown reason
+    - usb: dwc2: Make "trimming xfer length" a debug message
+    - ARM: s3c: fix fiq for clang IAS
+    - bnxt_en: reverse order of TX disable and carrier off
+    - xen/netback: fix spurious event detection for common event case
+    - b43: N-PHY: Fix the update of coef for the PHY revision >= 3case
+    - fbdev: aty: SPARC64 requires FB_ATY_CT
+    - drm/gma500: Fix error return code in psb_driver_load()
+    - gma500: clean up error handling in init
+    - MIPS: c-r4k: Fix section mismatch for loongson2_sc_init
+    - MIPS: lantiq: Explicitly compare LTQ_EBU_PCC_ISTAT against 0
+    - media: media/pci: Fix memleak in empress_init
+    - media: tm6000: Fix memleak in tm6000_start_stream
+    - ASoC: cs42l56: fix up error handling in probe
+    - media: lmedm04: Fix misuse of comma
+    - media: cx25821: Fix a bug when reallocating some dma memory
+    - media: uvcvideo: Accept invalid bFormatIndex and bFrameIndex values
+    - btrfs: clarify error returns values in __load_free_space_cache
+    - fs/jfs: fix potential integer overflow on shift of a int
+    - jffs2: fix use after free in jffs2_sum_write_data()
+    - clk: meson: clk-pll: fix initializing the old rate (fallback) for a PLL
+    - HID: core: detect and skip invalid inputs to snto32()
+    - dmaengine: fsldma: Fix a resource leak in the remove function
+    - dmaengine: fsldma: Fix a resource leak in an error handling path of the
+      probe function
+    - clocksource/drivers/mxs_timer: Add missing semicolon when DEBUG is defined
+    - regulator: axp20x: Fix reference cout leak
+    - isofs: release buffer head before return
+    - IB/umad: Return EIO in case of when device disassociated
+    - powerpc/47x: Disable 256k page size
+    - mmc: usdhi6rol0: Fix a resource leak in the error handling path of the probe
+    - ARM: 9046/1: decompressor: Do not clear SCTLR.nTLSMD for ARMv7+ cores
+    - amba: Fix resource leak for drivers without .remove
+    - tracepoint: Do not fail unregistering a probe due to memory failure
+    - mfd: wm831x-auxadc: Prevent use after free in wm831x_auxadc_read_irq()
+    - powerpc/pseries/dlpar: handle ibm, configure-connector delay status
+    - perf intel-pt: Fix missing CYC processing in PSB
+    - perf test: Fix unaligned access in sample parsing test
+    - Input: elo - fix an error code in elo_connect()
+    - sparc64: only select COMPAT_BINFMT_ELF if BINFMT_ELF is set
+    - misc: eeprom_93xx46: Fix module alias to enable module autoprobe
+    - misc: eeprom_93xx46: Add module alias to avoid breaking support for non
+      device tree users
+    - VMCI: Use set_page_dirty_lock() when unregistering guest memory
+    - PCI: Align checking of syscall user config accessors
+    - mm/memory.c: fix potential pte_unmap_unlock pte error
+    - mm/hugetlb: fix potential double free in hugetlb_register_node() error path
+    - i2c: brcmstb: Fix brcmstd_send_i2c_cmd condition
+    - scsi: bnx2fc: Fix Kconfig warning & CNIC build errors
+    - block: Move SECTOR_SIZE and SECTOR_SHIFT definitions into <linux/blkdev.h>
+    - blk-settings: align max_sectors on "logical_block_size" boundary
+    - Input: xpad - add support for PowerA Enhanced Wired Controller for Xbox
+      Series X|S
+    - Input: joydev - prevent potential read overflow in ioctl
+    - Input: i8042 - add ASUS Zenbook Flip to noselftest list
+    - USB: serial: option: update interface mapping for ZTE P685M
+    - USB: serial: mos7840: fix error code in mos7840_write()
+    - USB: serial: mos7720: fix error code in mos7720_write()
+    - usb: dwc3: gadget: Fix setting of DEPCFG.bInterval_m1
+    - usb: dwc3: gadget: Fix dep->interval for fullspeed interrupt
+    - KEYS: trusted: Fix migratable=1 failing
+    - btrfs: fix reloc root leak with 0 ref reloc roots on recovery
+    - drivers/misc/vmw_vmci: restrict too big queue size in qp_host_alloc_queue
+    - staging: rtl8188eu: Add Edimax EW-7811UN V2 to device table
+    - x86/reboot: Force all cpus to exit VMX root if VMX is supported
+    - floppy: reintroduce O_NDELAY fix
+    - mm: hugetlb: fix a race between freeing and dissolving the page
+    - usb: renesas_usbhs: Clear pipe running flag in usbhs_pkt_pop()
+    - libnvdimm/dimm: Avoid race between probe and available_slots_show()
+    - module: Ignore _GLOBAL_OFFSET_TABLE_ when warning for undefined symbols
+    - gpio: pcf857x: Fix missing first interrupt
+    - f2fs: fix out-of-repair __setattr_copy()
+    - sparc32: fix a user-triggerable oops in clear_user()
+    - gfs2: Don't skip dlm unlock if glock has an lvb
+    - dm era: Recover committed writeset after crash
+    - dm era: Verify the data block size hasn't changed
+    - dm era: Fix bitset memory leaks
+    - dm era: Use correct value size in equality function of writeset tree
+    - dm era: Reinitialize bitset cache before digesting a new writeset
+    - dm era: only resize metadata in preresume
+    - futex: Fix OWNER_DEAD fixup
+    - dm era: Update in-core bitset after committing the metadata
+    - Linux 4.4.259
+
+  * CVE-2019-16231
+    - fjes: Handle workqueue allocation failure
+
+  * Xenial update: v4.4.258 upstream stable release (LP: #1916661)
+    - tracing: Do not count ftrace events in top level enable output
+    - fgraph: Initialize tracing_graph_pause at task creation
+    - af_key: relax availability checks for skb size calculation
+    - iwlwifi: pcie: add a NULL check in iwl_pcie_txq_unmap
+    - iwlwifi: mvm: guard against device removal in reprobe
+    - SUNRPC: Move simple_get_bytes and simple_get_netobj into private header
+    - SUNRPC: Handle 0 length opaque XDR object data properly
+    - lib/string: Add strscpy_pad() function
+    - include/trace/events/writeback.h: fix -Wstringop-truncation warnings
+    - memcg: fix a crash in wb_workfn when a device disappears
+    - squashfs: add more sanity checks in id lookup
+    - squashfs: add more sanity checks in inode lookup
+    - squashfs: add more sanity checks in xattr id lookup
+    - memblock: do not start bottom-up allocations with kernel_end
+    - netfilter: xt_recent: Fix attempt to update deleted entry
+    - h8300: fix PREEMPTION build, TI_PRE_COUNT undefined
+    - usb: dwc3: ulpi: fix checkpatch warning
+    - usb: dwc3: ulpi: Replace CPU-based busyloop with Protocol-based one
+    - net: watchdog: hold device global xmit lock during tx disable
+    - vsock: fix locking in vsock_shutdown()
+    - x86/build: Disable CET instrumentation in the kernel for 32-bit too
+    - trace: Use -mcount-record for dynamic ftrace
+    - tracing: Fix SKIP_STACK_VALIDATION=1 build due to bad merge with -mrecord-
+      mcount
+    - tracing: Avoid calling cc-option -mrecord-mcount for every Makefile
+    - Xen/x86: don't bail early from clear_foreign_p2m_mapping()
+    - Xen/x86: also check kernel mapping in set_foreign_p2m_mapping()
+    - Xen/gntdev: correct dev_bus_addr handling in gntdev_map_grant_pages()
+    - Xen/gntdev: correct error checking in gntdev_map_grant_pages()
+    - xen/arm: don't ignore return errors from set_phys_to_machine
+    - xen-blkback: don't "handle" error by BUG()
+    - xen-netback: don't "handle" error by BUG()
+    - xen-scsiback: don't "handle" error by BUG()
+    - xen-blkback: fix error handling in xen_blkbk_map()
+    - scsi: qla2xxx: Fix crash during driver load on big endian machines
+    - kvm: check tlbs_dirty directly
+    - Linux 4.4.258
+
+  * Xenial update: v4.4.257 upstream stable release (LP: #1916660)
+    - net_sched: reject silly cell_log in qdisc_get_rtab()
+    - futex,rt_mutex: Provide futex specific rt_mutex API
+    - futex: Remove rt_mutex_deadlock_account_*()
+    - futex: Rework inconsistent rt_mutex/futex_q state
+    - futex: Avoid violating the 10th rule of futex
+    - futex: Replace pointless printk in fixup_owner()
+    - futex: Provide and use pi_state_update_owner()
+    - rtmutex: Remove unused argument from rt_mutex_proxy_unlock()
+    - futex: Use pi_state_update_owner() in put_pi_state()
+    - futex: Simplify fixup_pi_state_owner()
+    - futex: Handle faults correctly for PI futexes
+    - usb: udc: core: Use lock when write to soft_connect
+    - scsi: libfc: Avoid invoking response handler twice if ep is already
+      completed
+    - scsi: ibmvfc: Set default timeout to avoid crash during migration
+    - stable: clamp SUBLEVEL in 4.4 and 4.9
+    - USB: serial: cp210x: add pid/vid for WSDA-200-USB
+    - USB: serial: cp210x: add new VID/PID for supporting Teraoka AD2000
+    - USB: serial: option: Adding support for Cinterion MV31
+    - net: lapb: Copy the skb before sending a packet
+    - [Config] updateconfigs for ELFCORE
+    - ELF/MIPS build fix
+    - elfcore: fix building with clang
+    - USB: gadget: legacy: fix an error code in eth_bind()
+    - USB: usblp: don't call usb_set_interface if there's a single alt
+    - usb: dwc2: Fix endpoint direction check in ep_from_windex
+    - mac80211: fix station rate table updates on assoc
+    - kretprobe: Avoid re-registration of the same kretprobe earlier
+    - cifs: report error instead of invalid when revalidating a dentry fails
+    - mmc: core: Limit retries when analyse of SDIO tuples fails
+    - ARM: footbridge: fix dc21285 PCI configuration accessors
+    - mm: hugetlbfs: fix cannot migrate the fallocated HugeTLB page
+    - mm: hugetlb: fix a race between isolating and freeing page
+    - mm: hugetlb: remove VM_BUG_ON_PAGE from page_huge_active
+    - x86/build: Disable CET instrumentation in the kernel
+    - x86/apic: Add extra serialization for non-serializing MSRs
+    - Input: xpad - sync supported devices with fork on GitHub
+    - ACPI: thermal: Do not call acpi_thermal_check() directly
+    - ALSA: hda/realtek - Fix typo of pincfg for Dell quirk
+    - Linux 4.4.257
+
+  * Xenial update: v4.4.256 upstream stable release (LP: #1916657)
+    - Linux 4.4.256
+
+  * Xenial update: v4.4.255 upstream stable release (LP: #1916656)
+    - ACPI: sysfs: Prefer "compatible" modalias
+    - wext: fix NULL-ptr-dereference with cfg80211's lack of commit()
+    - net: usb: qmi_wwan: added support for Thales Cinterion PLSx3 modem family
+    - KVM: x86/pmu: Fix HW_REF_CPU_CYCLES event pseudo-encoding in
+      intel_arch_events[]
+    - mt7601u: fix kernel crash unplugging the device
+    - mt7601u: fix rx buffer refcounting
+    - y2038: futex: Move compat implementation into futex.c
+    - futex: Move futex exit handling into futex code
+    - futex: Replace PF_EXITPIDONE with a state
+    - exit/exec: Seperate mm_release()
+    - futex: Split futex_mm_release() for exit/exec
+    - futex: Set task::futex_state to DEAD right after handling futex exit
+    - futex: Mark the begin of futex exit explicitly
+    - futex: Sanitize exit state handling
+    - futex: Provide state handling for exec() as well
+    - futex: Add mutex around futex exit
+    - futex: Provide distinct return value when owner is exiting
+    - futex: Prevent exit livelock
+    - ARM: imx: build suspend-imx6.S with arm instruction set
+    - netfilter: nft_dynset: add timeout extension to template
+    - xfrm: Fix oops in xfrm_replay_advance_bmp
+    - RDMA/cxgb4: Fix the reported max_recv_sge value
+    - mac80211: pause TX while changing interface type
+    - can: dev: prevent potential information leak in can_fill_info()
+    - iommu/vt-d: Gracefully handle DMAR units with no supported address widths
+    - iommu/vt-d: Don't dereference iommu_device if IOMMU_API is not built
+    - NFC: fix resource leak when target index is invalid
+    - NFC: fix possible resource leak
+    - Linux 4.4.255
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Wed, 24 Mar 2021 18:17:36 -0600
+
+linux (4.4.0-206.238) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-206.238 -proposed tracker (LP: #1919242)
+
+  * CVE-2021-27365
+    - sysfs: Add sysfs_emit and sysfs_emit_at to format sysfs output
+    - scsi: iscsi: Ensure sysfs attributes are limited to PAGE_SIZE
+    - scsi: iscsi: Verify lengths on passthrough PDUs
+
+  * CVE-2021-27363 // CVE-2021-27364
+    - scsi: iscsi: Restrict sessions and handles to admin capabilities
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 16 Mar 2021 08:21:57 +0100
+
+linux (4.4.0-204.236) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-204.236 -proposed tracker (LP: #1916222)
+
+  * Xenial update: v4.4.254 upstream stable release (LP: #1914648)
+    - ALSA: seq: oss: Fix missing error check in snd_seq_oss_synth_make_info()
+    - ALSA: hda/via: Add minimum mute flag
+    - ACPI: scan: Make acpi_bus_get_device() clear return pointer on error
+    - dm: avoid filesystem lookup in dm_get_dev_t()
+    - ASoC: Intel: haswell: Add missing pm_ops
+    - scsi: ufs: Correct the LUN used in eh_device_reset_handler() callback
+    - drm/nouveau/bios: fix issue shadowing expansion ROMs
+    - drm/nouveau/i2c/gm200: increase width of aux semaphore owner fields
+    - can: dev: can_restart: fix use after free bug
+    - iio: ad5504: Fix setting power-down state
+    - ehci: fix EHCI host controller initialization sequence
+    - usb: bdc: Make bdc pci driver depend on BROKEN
+    - [Config] updateconfigs for USB_BDC_PCI
+    - xhci: make sure TRB is fully written before giving it to the controller
+    - compiler.h: Raise minimum version of GCC to 5.1 for arm64
+    - netfilter: rpfilter: mask ecn bits before fib lookup
+    - sh: dma: fix kconfig dependency for G2_DMA
+    - sh_eth: Fix power down vs. is_opened flag ordering
+    - skbuff: back tiny skbs with kmalloc() in __netdev_alloc_skb() too
+    - ipv6: create multicast route with RTPROT_KERNEL
+    - net_sched: avoid shift-out-of-bounds in tcindex_set_parms()
+    - Revert "mm/slub: fix a memory leak in sysfs_slab_add()"
+    - tracing: Fix race in trace_open and buffer resize call
+    - xen-blkback: set ring->xenblkd to NULL after kthread_stop()
+    - x86/boot/compressed: Disable relocation relaxation
+    - Linux 4.4.254
+
+  * Xenial update: v4.4.253 upstream stable release (LP: #1914647)
+    - ASoC: dapm: remove widget from dirty list on free
+    - mm/hugetlb: fix potential missing huge page size info
+    - ext4: fix bug for rename with RENAME_WHITEOUT
+    - ARC: build: add boot_targets to PHONY
+    - ethernet: ucc_geth: fix definition and size of ucc_geth_tx_global_pram
+    - arch/arc: add copy_user_page() to <asm/page.h> to fix build error on ARC
+    - misdn: dsp: select CONFIG_BITREVERSE
+    - net: ethernet: fs_enet: Add missing MODULE_LICENSE
+    - ACPI: scan: add stub acpi_create_platform_device() for !CONFIG_ACPI
+    - ARM: picoxcell: fix missing interrupt-parent properties
+    - Input: uinput - avoid FF flush when destroying device
+    - dump_common_audit_data(): fix racy accesses to ->d_name
+    - NFS: nfs_igrab_and_active must first reference the superblock
+    - ext4: fix superblock checksum failure when setting password salt
+    - RDMA/usnic: Fix memleak in find_free_vf_and_create_qp_grp
+    - mm, slub: consider rest of partial list if acquire_slab() fails
+    - net: sunrpc: interpret the return value of kstrtou32 correctly
+    - usb: ohci: Make distrust_firmware param default to false
+    - iio: buffer: Fix demux update
+    - nfsd4: readdirplus shouldn't return parent of export
+    - net: cdc_ncm: correct overhead in delayed_ndp_size
+    - netxen_nic: fix MSI/MSI-x interrupts
+    - rndis_host: set proper input size for OID_GEN_PHYSICAL_MEDIUM request
+    - net: dcb: Validate netlink message in DCB handler
+    - net: dcb: Accept RTM_GETDCB messages carrying set-like DCB commands
+    - net: sit: unregister_netdevice on newlink's error path
+    - rxrpc: Fix handling of an unsupported token type in rxrpc_read()
+    - net: avoid 32 x truesize under-estimation for tiny skbs
+    - spi: cadence: cache reference clock rate during probe
+    - Linux 4.4.253
+
+  * Xenial update: v4.4.252 upstream stable release (LP: #1913479)
+    - Revert "UBUNTU: SAUCE: target: fix XCOPY NAA identifier lookup"
+    - target: add XCOPY target/segment desc sense codes
+    - target: bounds check XCOPY segment descriptor list
+    - target: use XCOPY segment descriptor CSCD IDs
+    - xcopy: loop over devices using idr helper
+    - scsi: target: Fix XCOPY NAA identifier lookup
+    - powerpc: Fix incorrect stw{, ux, u, x} instructions in __set_pte_at
+    - net: ip: always refragment ip defragmented packets
+    - net: fix pmtu check in nopmtudisc mode
+    - vmlinux.lds.h: Add PGO and AutoFDO input sections
+    - ubifs: wbuf: Don't leak kernel memory to flash
+    - spi: pxa2xx: Fix use-after-free on unbind
+    - cpufreq: powernow-k8: pass policy rather than use cpufreq_cpu_get()
+    - wil6210: select CONFIG_CRC32
+    - block: rsxx: select CONFIG_CRC32
+    - iommu/intel: Fix memleak in intel_irq_remapping_alloc
+    - block: fix use-after-free in disk_part_iter_next
+    - net: drop bogus skb with CHECKSUM_PARTIAL and offset beyond end of trimmed
+      packet
+    - Linux 4.4.252
+
+  * Xenial update: v4.4.251 upstream stable release (LP: #1913478)
+    - kbuild: don't hardcode depmod path
+    - workqueue: Kick a worker based on the actual activation of delayed works
+    - lib/genalloc: fix the overflow when size is too big
+    - depmod: handle the case of /sbin/depmod without /sbin in PATH
+    - atm: idt77252: call pci_disable_device() on error path
+    - ipv4: Ignore ECN bits for fib lookups in fib_compute_spec_dst()
+    - net: hns: fix return value check in __lb_other_process()
+    - net: hdlc_ppp: Fix issues when mod_timer is called while timer is running
+    - CDC-NCM: remove "connected" log message
+    - vhost_net: fix ubuf refcount incorrectly when sendmsg fails
+    - net: sched: prevent invalid Scell_log shift count
+    - virtio_net: Fix recursive call to cpus_read_lock()
+    - ethernet: ucc_geth: fix use-after-free in ucc_geth_remove()
+    - video: hyperv_fb: Fix the mmap() regression for v5.4.y and older
+    - usb: gadget: enable super speed plus
+    - USB: cdc-acm: blacklist another IR Droid device
+    - usb: chipidea: ci_hdrc_imx: add missing put_device() call in
+      usbmisc_get_init_data()
+    - USB: xhci: fix U1/U2 handling for hardware with XHCI_INTEL_HOST quirk set
+    - usb: uas: Add PNY USB Portable SSD to unusual_uas
+    - USB: serial: iuu_phoenix: fix DMA from stack
+    - USB: serial: option: add LongSung M5710 module support
+    - USB: yurex: fix control-URB timeout handling
+    - USB: usblp: fix DMA to stack
+    - ALSA: usb-audio: Fix UBSAN warnings for MIDI jacks
+    - usb: gadget: select CONFIG_CRC32
+    - usb: gadget: f_uac2: reset wMaxPacketSize
+    - usb: gadget: function: printer: Fix a memory leak for interface descriptor
+    - USB: gadget: legacy: fix return error code in acm_ms_bind()
+    - usb: gadget: Fix spinlock lockup on usb_function_deactivate
+    - usb: gadget: configfs: Preserve function ordering after bind failure
+    - USB: serial: keyspan_pda: remove unused variable
+    - x86/mm: Fix leak of pmd ptlock
+    - ALSA: hda/conexant: add a new hda codec CX11970
+    - Revert "device property: Keep secondary firmware node secondary by type"
+    - netfilter: ipset: fix shift-out-of-bounds in htable_bits()
+    - netfilter: xt_RATEEST: reject non-null terminated string from userspace
+    - x86/mtrr: Correct the range check before performing MTRR type lookups
+    - Linux 4.4.251
+
+  * Xenial update: v4.4.250 upstream stable release (LP: #1912679)
+    - ALSA: hda/ca0132 - Fix work handling in delayed HP detection
+    - ALSA: usb-audio: simplify set_sync_ep_implicit_fb_quirk
+    - ALSA: usb-audio: fix sync-ep altsetting sanity check
+    - ALSA: hda/realtek - Support Dell headset mode for ALC3271
+    - ALSA: hda - Fix a wrong FIXUP for alc289 on Dell machines
+    - ALSA: hda/realtek - Dell headphone has noise on unmute for ALC236
+    - s390/dasd: fix hanging device offline processing
+    - USB: serial: digi_acceleport: fix write-wakeup deadlocks
+    - uapi: move constants from <linux/kernel.h> to <linux/const.h>
+    - of: fix linker-section match-table corruption
+    - reiserfs: add check for an invalid ih_entry_count
+    - misc: vmw_vmci: fix kernel info-leak by initializing dbells in
+      vmci_ctx_get_chkpt_doorbells()
+    - media: gp8psk: initialize stats at power control logic
+    - ALSA: seq: Use bool for snd_seq_queue internal flags
+    - module: set MODULE_STATE_GOING state when a module fails to load
+    - quota: Don't overflow quota file offsets
+    - powerpc: sysdev: add missing iounmap() on error in mpic_msgr_probe()
+    - module: delay kobject uevent until after module init call
+    - iio:magnetometer:mag3110: Fix alignment and data leak issues.
+    - mwifiex: Fix possible buffer overflows in mwifiex_cmd_802_11_ad_hoc_start
+    - Linux 4.4.250
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 19 Feb 2021 11:48:11 +0100
+
+linux (4.4.0-203.235) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-203.235 -proposed tracker (LP: #1914140)
+
+  * Ubuntu 16.04 kernel 4.4.0-202 basic commands hanging (LP: #1913853)
+    - SAUCE: Revert "mm: check that mm is still valid in madvise()"
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Mon, 01 Feb 2021 17:38:49 -0700
+
+linux (4.4.0-202.234) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-202.234 -proposed tracker (LP: #1913086)
+
+  * DMI entry syntax fix for Pegatron / ByteSpeed C15B (LP: #1910639)
+    - Input: i8042 - unbreak Pegatron C15B
+
+  * CVE-2020-29372
+    - mm: check that mm is still valid in madvise()
+
+  * errinjct open fails on IBM POWER LPAR (LP: #1908710)
+    - powerpc/rtas: Fix typo of ibm, open-errinjct in RTAS filter
+
+  * 4.4 kernel panics in kvm wake_up() handler (LP: #1908428)
+    - kvm: vmx: rename vmx_pre/post_block to pi_pre/post_block
+    - KVM: VMX: extract __pi_post_block
+    - KVM: VMX: avoid double list add with VT-d posted interrupts
+
+  * restore reverted commit "crypto: arm64/sha - avoid non-standard inline asm
+    tricks" (LP: #1907489)
+    - crypto: arm64/sha - avoid non-standard inline asm tricks
+
+  * CVE-2020-29374
+    - gup: document and work around "COW can break either way" issue
+
+  * Xenial update: v4.4.249 upstream stable release (LP: #1910139)
+    - spi: bcm2835aux: Fix use-after-free on unbind
+    - spi: bcm2835aux: Restore err assignment in bcm2835aux_spi_probe
+    - ARC: stack unwinding: don't assume non-current task is sleeping
+    - platform/x86: acer-wmi: add automatic keyboard background light toggle key
+      as KEY_LIGHTS_TOGGLE
+    - Input: cm109 - do not stomp on control URB
+    - Input: i8042 - add Acer laptops to the i8042 reset list
+    - [Config] updateconfigs for SPI_DYNAMIC
+    - spi: Prevent adding devices below an unregistering controller
+    - net/mlx4_en: Avoid scheduling restart task if it is already running
+    - tcp: fix cwnd-limited bug for TSO deferral where we send nothing
+    - net: stmmac: delete the eee_ctrl_timer after napi disabled
+    - net: bridge: vlan: fix error return code in __vlan_add()
+    - USB: dummy-hcd: Fix uninitialized array use in init()
+    - USB: add RESET_RESUME quirk for Snapscan 1212
+    - ALSA: usb-audio: Fix potential out-of-bounds shift
+    - ALSA: usb-audio: Fix control 'access overflow' errors from chmap
+    - xhci: Give USB2 ports time to enter U3 in bus suspend
+    - USB: sisusbvga: Make console support depend on BROKEN
+    - [Config] updateconfigs for USB_SISUSBVGA_CON
+    - ALSA: pcm: oss: Fix potential out-of-bounds shift
+    - serial: 8250_omap: Avoid FIFO corruption caused by MDR1 access
+    - USB: serial: cp210x: enable usb generic throttle/unthrottle
+    - scsi: bnx2i: Requires MMU
+    - can: softing: softing_netdev_open(): fix error handling
+    - RDMA/cm: Fix an attempt to use non-valid pointer when cleaning timewait
+    - dm table: Remove BUG_ON(in_interrupt())
+    - soc/tegra: fuse: Fix index bug in get_process_id
+    - USB: serial: option: add interface-number sanity check to flag handling
+    - USB: gadget: f_rndis: fix bitrate for SuperSpeed and above
+    - usb: chipidea: ci_hdrc_imx: Pass DISABLE_DEVICE_STREAMING flag to imx6ul
+    - media: msi2500: assign SPI bus number dynamically
+    - Bluetooth: Fix slab-out-of-bounds read in hci_le_direct_adv_report_evt()
+    - drm/gma500: fix double free of gma_connector
+    - ARM: p2v: fix handling of LPAE translation in BE mode
+    - crypto: talitos - Fix return type of current_desc_hdr()
+    - spi: img-spfi: fix reference leak in img_spfi_resume
+    - ASoC: pcm: DRAIN support reactivation
+    - Bluetooth: Fix null pointer dereference in hci_event_packet()
+    - spi: spi-ti-qspi: fix reference leak in ti_qspi_setup
+    - spi: tegra20-slink: fix reference leak in slink ops of tegra20
+    - spi: tegra20-sflash: fix reference leak in tegra_sflash_resume
+    - spi: tegra114: fix reference leak in tegra spi ops
+    - RDMa/mthca: Work around -Wenum-conversion warning
+    - MIPS: BCM47XX: fix kconfig dependency bug for BCM47XX_BCMA
+    - media: solo6x10: fix missing snd_card_free in error handling case
+    - drm/omap: dmm_tiler: fix return error code in omap_dmm_probe()
+    - Input: ads7846 - fix integer overflow on Rt calculation
+    - Input: ads7846 - fix unaligned access on 7845
+    - powerpc/feature: Fix CPU_FTRS_ALWAYS by removing CPU_FTRS_GENERIC_32
+    - soc: ti: knav_qmss: fix reference leak in knav_queue_probe
+    - soc: ti: Fix reference imbalance in knav_dma_probe
+    - drivers: soc: ti: knav_qmss_queue: Fix error return code in knav_queue_probe
+    - memstick: fix a double-free bug in memstick_check
+    - ARM: dts: at91: sama5d4_xplained: add pincontrol for USB Host
+    - ARM: dts: at91: sama5d3_xplained: add pincontrol for USB Host
+    - orinoco: Move context allocation after processing the skb
+    - cw1200: fix missing destroy_workqueue() on error in cw1200_init_common
+    - mips: cdmm: fix use-after-free in mips_cdmm_bus_discover
+    - NFSv4.2: condition READDIR's mask for security label based on LSM state
+    - lockd: don't use interval-based rebinding over TCP
+    - NFS: switch nfsiod to be an UNBOUND workqueue.
+    - media: saa7146: fix array overflow in vidioc_s_audio()
+    - pinctrl: falcon: add missing put_device() call in pinctrl_falcon_probe()
+    - memstick: r592: Fix error return in r592_probe()
+    - ASoC: jz4740-i2s: add missed checks for clk_get()
+    - dm ioctl: fix error return code in target_message
+    - clocksource/drivers/arm_arch_timer: Correct fault programming of
+      CNTKCTL_EL1.EVNTI
+    - cpufreq: highbank: Add missing MODULE_DEVICE_TABLE
+    - cpufreq: loongson1: Add missing MODULE_ALIAS
+    - cpufreq: scpi: Add missing MODULE_ALIAS
+    - scsi: pm80xx: Fix error return in pm8001_pci_probe()
+    - seq_buf: Avoid type mismatch for seq_buf_init
+    - scsi: fnic: Fix error return code in fnic_probe()
+    - powerpc/pseries/hibernation: drop pseries_suspend_begin() from suspend ops
+    - usb: ehci-omap: Fix PM disable depth umbalance in ehci_hcd_omap_probe
+    - usb: oxu210hp-hcd: Fix memory leak in oxu_create
+    - speakup: fix uninitialized flush_lock
+    - nfs_common: need lock during iterate through the list
+    - x86/kprobes: Restore BTF if the single-stepping is cancelled
+    - extcon: max77693: Fix modalias string
+    - ASoC: wm_adsp: remove "ctl" from list on error in wm_adsp_create_control()
+    - um: chan_xterm: Fix fd leak
+    - nfc: s3fwrn5: Release the nfc firmware
+    - powerpc/ps3: use dma_mapping_error()
+    - checkpatch: fix unescaped left brace
+    - net: bcmgenet: Fix a resource leak in an error handling path in the probe
+      functin
+    - net: allwinner: Fix some resources leak in the error handling path of the
+      probe and in the remove function
+    - net: korina: fix return value
+    - clk: ti: Fix memleak in ti_fapll_synth_setup
+    - perf record: Fix memory leak when using '--user-regs=?' to list registers
+    - qlcnic: Fix error code in probe
+    - clk: s2mps11: Fix a resource leak in error handling paths in the probe
+      function
+    - cfg80211: initialize rekey_data
+    - Input: cros_ec_keyb - send 'scancodes' in addition to key events
+    - Input: goodix - add upside-down quirk for Teclast X98 Pro tablet
+    - media: gspca: Fix memory leak in probe
+    - media: sunxi-cir: ensure IR is handled when it is continuous
+    - media: netup_unidvb: Don't leak SPI master in probe error path
+    - Input: cyapa_gen6 - fix out-of-bounds stack access
+    - Revert "ACPI / resources: Use AE_CTRL_TERMINATE to terminate resources
+      walks"
+    - ACPI: PNP: compare the string length in the matching_id()
+    - ALSA: pcm: oss: Fix a few more UBSAN fixes
+    - s390/dasd: fix list corruption of pavgroup group list
+    - s390/dasd: fix list corruption of lcu list
+    - staging: comedi: mf6x4: Fix AI end-of-conversion detection
+    - powerpc/perf: Exclude kernel samples while counting events in user space.
+    - USB: serial: mos7720: fix parallel-port state restore
+    - USB: serial: keyspan_pda: fix dropped unthrottle interrupts
+    - USB: serial: keyspan_pda: fix write deadlock
+    - USB: serial: keyspan_pda: fix stalled writes
+    - USB: serial: keyspan_pda: fix write-wakeup use-after-free
+    - USB: serial: keyspan_pda: fix tx-unthrottle use-after-free
+    - USB: serial: keyspan_pda: fix write unthrottling
+    - btrfs: quota: Set rescan progress to (u64)-1 if we hit last leaf
+    - btrfs: scrub: Don't use inode page cache in scrub_handle_errored_block()
+    - Btrfs: fix selftests failure due to uninitialized i_mode in test inodes
+    - btrfs: fix return value mixup in btrfs_get_extent
+    - ext4: fix a memory leak of ext4_free_data
+    - ceph: fix race in concurrent __ceph_remove_cap invocations
+    - jffs2: Fix GC exit abnormally
+    - jfs: Fix array index bounds check in dbAdjTree
+    - spi: rb4xx: Don't leak SPI master in probe error path
+    - mtd: parser: cmdline: Fix parsing of part-names with colons
+    - iio: adc: rockchip_saradc: fix missing clk_disable_unprepare() on error in
+      rockchip_saradc_resume
+    - iio:pressure:mpl3115: Force alignment of buffer
+    - xen/xenbus: Allow watches discard events before queueing
+    - xen/xenbus: Add 'will_handle' callback support in xenbus_watch_path()
+    - xen/xenbus/xen_bus_type: Support will_handle watch callback
+    - xen/xenbus: Count pending messages for each watch
+    - xenbus/xenbus_backend: Disallow pending watch messages
+    - PCI: Fix pci_slot_release() NULL pointer dereference
+    - Linux 4.4.249
+
+  * MSFT Touchpad not working on Lenovo Legion-5 15ARH05 (LP: #1887190) //
+    Xenial update: v4.4.249 upstream stable release (LP: #1910139)
+    - pinctrl: amd: remove debounce filter setting in IRQ type setting
+
+  * Xenial update: v4.4.248 upstream stable release (LP: #1910137)
+    - net/af_iucv: set correct sk_protocol for child sockets
+    - rose: Fix Null pointer dereference in rose_send_frame()
+    - usbnet: ipheth: fix connectivity with iOS 14
+    - bonding: wait for sysfs kobject destruction before freeing struct slave
+    - netfilter: bridge: reset skb->pkt_type after NF_INET_POST_ROUTING traversal
+    - net/x25: prevent a couple of overflows
+    - cxgb3: fix error return code in t3_sge_alloc_qset()
+    - net: pasemi: fix error return code in pasemi_mac_open()
+    - dt-bindings: net: correct interrupt flags in examples
+    - Input: xpad - support Ardwiino Controllers
+    - powerpc: Stop exporting __clear_user which is now inlined.
+    - btrfs: sysfs: init devices outside of the chunk_mutex
+    - vlan: consolidate VLAN parsing code and limit max parsing depth
+    - usb: gadget: f_fs: Use local copy of descriptors for userspace copy
+    - USB: serial: kl5kusb105: fix memleak on open
+    - USB: serial: ch341: add new Product ID for CH341A
+    - USB: serial: ch341: sort device-id entries
+    - USB: serial: option: add Fibocom NL668 variants
+    - USB: serial: option: add support for Thales Cinterion EXS82
+    - tty: Fix ->pgrp locking in tiocspgrp()
+    - ALSA: hda/realtek - Add new codec supported for ALC897
+    - ALSA: hda/generic: Add option to enforce preferred_dacs pairs
+    - tty: Fix ->session locking
+    - cifs: fix potential use-after-free in cifs_echo_request()
+    - i2c: imx: Fix reset of I2SR_IAL flag
+    - i2c: imx: Check for I2SR_IAL after every byte
+    - arm64: assembler: make adr_l work in modules under KASLR
+    - iommu/amd: Set DTE[IntTabLen] to represent 512 IRTEs
+    - spi: Introduce device-managed SPI controller allocation
+    - spi: bcm2835: Fix use-after-free on unbind
+    - spi: bcm2835: Release the DMA channel if probe fails after dma_init
+    - tracing: Fix userstacktrace option for instances
+    - btrfs: cleanup cow block on error
+    - mm/userfaultfd: do not access vma->vm_mm after calling handle_userfault()
+    - gfs2: check for empty rgrp tree in gfs2_ri_update
+    - Input: i8042 - fix error return code in i8042_setup_aux()
+    - x86/uprobes: Do not use prefixes.nbytes when looping over prefixes.bytes
+    - Linux 4.4.248
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Wed, 27 Jan 2021 16:23:17 -0700
+
+linux (4.4.0-201.233) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-201.233 -proposed tracker (LP: #1911265)
+
+  * Touchpad not detected on ByteSpeed C15B laptop (LP: #1906128)
+    - Input: i8042 - add ByteSpeed touchpad to noloop table
+
+  * stack trace in kernel (LP: #1903596)
+    - net: napi: remove useless stack trace
+
+  * CVE-2020-27777
+    - powerpc/rtas: Restrict RTAS requests from userspace
+    - [Config]: Set CONFIG_PPC_RTAS_FILTER
+
+  * Xenial update: v4.4.247 upstream stable release (LP: #1906703)
+    - btrfs: tree-checker: Enhance chunk checker to validate chunk profile
+    - btrfs: inode: Verify inode mode to avoid NULL pointer dereference
+    - HID: cypress: Support Varmilo Keyboards' media hotkeys
+    - Input: i8042 - allow insmod to succeed on devices without an i8042
+      controller
+    - HID: hid-sensor-hub: Fix issue with devices with no report ID
+    - x86/xen: don't unbind uninitialized lock_kicker_irq
+    - proc: don't allow async path resolution of /proc/self components
+    - dmaengine: pl330: _prep_dma_memcpy: Fix wrong burst size
+    - scsi: libiscsi: Fix NOP race condition
+    - scsi: target: iscsi: Fix cmd abort fabric stop race
+    - scsi: ufs: Fix race between shutdown and runtime resume flow
+    - bnxt_en: fix error return code in bnxt_init_board()
+    - video: hyperv_fb: Fix the cache type when mapping the VRAM
+    - bnxt_en: Release PCI regions when DMA mask setup fails during probe.
+    - IB/mthca: fix return value of error branch in mthca_init_cq()
+    - nfc: s3fwrn5: use signed integer for parsing GPIO numbers
+    - efivarfs: revert "fix memory leak in efivarfs_create()"
+    - perf probe: Fix to die_entrypc() returns error correctly
+    - USB: core: Change %pK for __user pointers to %px
+    - x86/speculation: Fix prctl() when spectre_v2_user={seccomp,prctl},ibpb
+    - USB: core: add endpoint-blacklist quirk
+    - USB: core: Fix regression in Hercules audio card
+    - btrfs: fix lockdep splat when reading qgroup config on mount
+    - Linux 4.4.247
+
+  * Xenial update: v4.4.246 upstream stable release (LP: #1906700)
+    - ah6: fix error return code in ah6_input()
+    - atm: nicstar: Unmap DMA on send error
+    - net: b44: fix error return code in b44_init_one()
+    - net: bridge: add missing counters to ndo_get_stats64 callback
+    - netlabel: fix our progress tracking in netlbl_unlabel_staticlist()
+    - netlabel: fix an uninitialized warning in netlbl_unlabel_staticlist()
+    - net/mlx4_core: Fix init_hca fields offset
+    - net: x25: Increase refcnt of "struct x25_neigh" in x25_rx_call_request
+    - qlcnic: fix error return code in qlcnic_83xx_restart_hw()
+    - sctp: change to hold/put transport for proto_unreach_timer
+    - net: usb: qmi_wwan: Set DTR quirk for MR400
+    - net: Have netpoll bring-up DSA management interface
+    - pinctrl: rockchip: enable gpio pclk for rockchip_gpio_to_irq
+    - arm64: psci: Avoid printing in cpu_psci_cpu_die()
+    - MIPS: Fix BUILD_ROLLBACK_PROLOGUE for microMIPS
+    - Input: adxl34x - clean up a data type in adxl34x_probe()
+    - arm: dts: imx6qdl-udoo: fix rgmii phy-mode for ksz9031 phy
+    - ARM: dts: imx50-evk: Fix the chip select 1 IOMUX
+    - perf lock: Don't free "lock_seq_stat" if read_count isn't zero
+    - can: dev: can_restart(): post buffer from the right context
+    - can: peak_usb: fix potential integer overflow on shift of a int
+    - can: m_can: m_can_handle_state_change(): fix state change
+    - MIPS: Alchemy: Fix memleak in alchemy_clk_setup_cpu
+    - regulator: ti-abb: Fix array out of bound read access on the first
+      transition
+    - libfs: fix error cast of negative value in simple_attr_write()
+    - ALSA: ctl: fix error path at adding user-defined element set
+    - ALSA: mixart: Fix mutex deadlock
+    - tty: serial: imx: keep console clocks always on
+    - efivarfs: fix memory leak in efivarfs_create()
+    - ext4: fix bogus warning in ext4_update_dx_flag()
+    - xtensa: disable preemption around cache alias management calls
+    - mac80211: minstrel: remove deferred sampling code
+    - mac80211: minstrel: fix tx status processing corner case
+    - mac80211: allow driver to prevent two stations w/ same address
+    - mac80211: free sta in sta_info_insert_finish() on errors
+    - s390/cpum_sf.c: fix file permission for cpum_sfb_size
+    - x86/microcode/intel: Check patch signature before saving microcode for early
+      loading
+    - Linux 4.4.246
+
+  * Xenial update: v4.4.245 upstream stable release (LP: #1906698)
+    - i2c: imx: Fix external abort on interrupt in exit paths
+    - xfs: catch inode allocation state mismatch corruption
+    - xfs: validate cached inodes are free when allocated
+    - powerpc/8xx: Always fault when _PAGE_ACCESSED is not set
+    - Input: sunkbd - avoid use-after-free in teardown paths
+    - mac80211: always wind down STA state
+    - KVM: x86: clflushopt should be treated as a no-op by emulation
+    - Linux 4.4.245
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Wed, 13 Jan 2021 17:48:34 -0700
+
+linux (4.4.0-200.232) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-200.232 -proposed tracker (LP: #1911151)
+
+  * CVE-2020-28374
+    - target: simplify XCOPY wwn->se_dev lookup helper
+    - SAUCE: target: fix XCOPY NAA identifier lookup
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 13 Jan 2021 10:30:27 +0100
+
+linux (4.4.0-198.230) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-198.230 -proposed tracker (LP: #1906052)
+
+  * Xenial update: v4.4.244 upstream stable release (LP: #1904914)
+    - ring-buffer: Fix recursion protection transitions between interrupt context
+    - gfs2: Wake up when sd_glock_disposal becomes zero
+    - mm: mempolicy: fix potential pte_unmap_unlock pte error
+    - time: Prevent undefined behaviour in timespec64_to_ns()
+    - btrfs: reschedule when cloning lots of extents
+    - net: xfrm: fix a race condition during allocing spi
+    - perf tools: Add missing swap for ino_generation
+    - ALSA: hda: prevent undefined shift in snd_hdac_ext_bus_get_link()
+    - can: dev: can_get_echo_skb(): prevent call to kfree_skb() in hard IRQ
+      context
+    - can: dev: __can_get_echo_skb(): fix real payload length return value for RTR
+      frames
+    - can: can_create_echo_skb(): fix echo skb generation: always use skb_clone()
+    - can: peak_usb: add range checking in decode operations
+    - can: peak_usb: peak_usb_get_ts_time(): fix timestamp wrapping
+    - Btrfs: fix missing error return if writeback for extent buffer never started
+    - i40e: Wrong truncation from u16 to u8
+    - i40e: Fix of memory leak and integer truncation in i40e_virtchnl.c
+    - ath9k_htc: Use appropriate rs_datalen type
+    - usb: gadget: goku_udc: fix potential crashes in probe
+    - gfs2: Free rd_bits later in gfs2_clear_rgrpd to fix use-after-free
+    - gfs2: check for live vs. read-only file system in gfs2_fitrim
+    - drm/amdgpu: perform srbm soft reset always on SDMA resume
+    - mac80211: fix use of skb payload instead of header
+    - cfg80211: regulatory: Fix inconsistent format argument
+    - iommu/amd: Increase interrupt remapping table limit to 512 entries
+    - xfs: fix a missing unlock on error in xfs_fs_map_blocks
+    - of/address: Fix of_node memory leak in of_dma_is_coherent
+    - cosa: Add missing kfree in error path of cosa_write
+    - perf: Fix get_recursion_context()
+    - ext4: correctly report "not supported" for {usr,grp}jquota when
+      !CONFIG_QUOTA
+    - ext4: unlock xattr_sem properly in ext4_inline_data_truncate()
+    - usb: cdc-acm: Add DISABLE_ECHO for Renesas USB Download mode
+    - mei: protect mei_cl_mtu from null dereference
+    - ocfs2: initialize ip_next_orphan
+    - don't dump the threads that had been already exiting when zapped.
+    - drm/gma500: Fix out-of-bounds access to struct drm_device.vblank[]
+    - pinctrl: amd: use higher precision for 512 RtcClk
+    - pinctrl: amd: fix incorrect way to disable debounce filter
+    - swiotlb: fix "x86: Don't panic if can not alloc buffer for swiotlb"
+    - IPv6: Set SIT tunnel hard_header_len to zero
+    - net/af_iucv: fix null pointer dereference on shutdown
+    - net/x25: Fix null-ptr-deref in x25_connect
+    - net: Update window_clamp if SOCK_RCVBUF is set
+    - random32: make prandom_u32() output unpredictable
+    - x86/speculation: Allow IBPB to be conditionally enabled on CPUs with always-
+      on STIBP
+    - xen/events: avoid removing an event channel while handling it
+    - xen/events: add a proper barrier to 2-level uevent unmasking
+    - xen/events: fix race in evtchn_fifo_unmask()
+    - xen/events: add a new "late EOI" evtchn framework
+    - xen/blkback: use lateeoi irq binding
+    - xen/netback: use lateeoi irq binding
+    - xen/scsiback: use lateeoi irq binding
+    - xen/pciback: use lateeoi irq binding
+    - xen/events: switch user event channels to lateeoi model
+    - xen/events: use a common cpu hotplug hook for event channels
+    - xen/events: defer eoi in case of excessive number of events
+    - xen/events: block rogue events for some time
+    - Revert "kernel/reboot.c: convert simple_strtoul to kstrtoint"
+    - reboot: fix overflow parsing reboot cpu number
+    - ext4: fix leaking sysfs kobject after failed mount
+    - Convert trailing spaces and periods in path components
+    - Linux 4.4.244
+
+  * Xenial update: v4.4.243 upstream stable release (LP: #1904904)
+    - Linux 4.4.243
+
+  * Xenial update: v4.4.242 upstream stable release (LP: #1903750)
+    - SUNRPC: ECONNREFUSED should cause a rebind.
+    - scripts/setlocalversion: make git describe output more reliable
+    - ravb: Fix bit fields checking in ravb_hwtstamp_get()
+    - tipc: fix memory leak caused by tipc_buf_append()
+    - mtd: lpddr: Fix bad logic in print_drs_error
+    - ata: sata_rcar: Fix DMA boundary mask
+    - fscrypt: return -EXDEV for incompatible rename or link into encrypted dir
+    - f2fs crypto: avoid unneeded memory allocation in ->readdir
+    - powerpc/powernv/smp: Fix spurious DBG() warning
+    - sparc64: remove mm_cpumask clearing to fix kthread_use_mm race
+    - f2fs: fix to check segment boundary during SIT page readahead
+    - um: change sigio_spinlock to a mutex
+    - xfs: fix realtime bitmap/summary file truncation when growing rt volume
+    - video: fbdev: pvr2fb: initialize variables
+    - ath10k: fix VHT NSS calculation when STBC is enabled
+    - mmc: via-sdmmc: Fix data race bug
+    - printk: reduce LOG_BUF_SHIFT range for H8300
+    - kgdb: Make "kgdbcon" work properly with "kgdb_earlycon"
+    - USB: adutux: fix debugging
+    - drivers/net/wan/hdlc_fr: Correctly handle special skb->protocol values
+    - power: supply: test_power: add missing newlines when printing parameters by
+      sysfs
+    - md/bitmap: md_bitmap_get_counter returns wrong blocks
+    - clk: ti: clockdomain: fix static checker warning
+    - net: 9p: initialize sun_server.sun_path to have addr's value only when addr
+      is valid
+    - drivers: watchdog: rdc321x_wdt: Fix race condition bugs
+    - ext4: Detect already used quota file early
+    - gfs2: add validation checks for size of superblock
+    - memory: emif: Remove bogus debugfs error handling
+    - ARM: dts: s5pv210: move PMU node out of clock controller
+    - ARM: dts: s5pv210: remove dedicated 'audio-subsystem' node
+    - md/raid5: fix oops during stripe resizing
+    - leds: bcm6328, bcm6358: use devres LED registering function
+    - NFS: fix nfs_path in case of a rename retry
+    - ACPI / extlog: Check for RDMSR failure
+    - acpi-cpufreq: Honor _PSD table setting on new AMD CPUs
+    - w1: mxc_w1: Fix timeout resolution problem leading to bus error
+    - scsi: mptfusion: Fix null pointer dereferences in mptscsih_remove()
+    - btrfs: reschedule if necessary when logging directory items
+    - vt: keyboard, simplify vt_kdgkbsent
+    - vt: keyboard, extend func_buf_lock to readers
+    - dmaengine: dma-jz4780: Fix race in jz4780_dma_tx_status
+    - iio:gyro:itg3200: Fix timestamp alignment and prevent data leak.
+    - powerpc/powernv/elog: Fix race while processing OPAL error log event.
+    - ubifs: dent: Fix some potential memory leaks while iterating entries
+    - ubi: check kthread_should_stop() after the setting of task state
+    - ia64: fix build error with !COREDUMP
+    - ceph: promote to unsigned long long before shifting
+    - libceph: clear con->out_msg on Policy::stateful_server faults
+    - 9P: Cast to loff_t before multiplying
+    - ring-buffer: Return 0 on success from ring_buffer_resize()
+    - vringh: fix __vringh_iov() when riov and wiov are different
+    - tty: make FONTX ioctl use the tty pointer they were actually passed
+    - arm64: berlin: Select DW_APB_TIMER_OF
+    - cachefiles: Handle readpage error correctly
+    - hil/parisc: Disable HIL driver when it gets stuck
+    - ARM: samsung: fix PM debug build with DEBUG_LL but !MMU
+    - ARM: s3c24xx: fix missing system reset
+    - device property: Keep secondary firmware node secondary by type
+    - device property: Don't clear secondary pointer for shared primary firmware
+      node
+    - staging: comedi: cb_pcidas: Allow 2-channel commands for AO subdevice
+    - Revert "Revert "XEN uses irqdesc::irq_data_common::handler_data to store a
+      per interrupt XEN data pointer which contains XEN specific information.""
+    - xen/events: don't use chip_data for legacy IRQs
+    - tipc: fix use-after-free in tipc_bcast_get_mode
+    - gianfar: Replace skb_realloc_headroom with skb_cow_head for PTP
+    - gianfar: Account for Tx PTP timestamp in the skb headroom
+    - Fonts: Replace discarded const qualifier
+    - ALSA: usb-audio: Add implicit feedback quirk for Qu-16
+    - ftrace: Fix recursion check for NMI test
+    - ftrace: Handle tracing when switching between context
+    - ARM: dts: sun4i-a10: fix cpu_alert temperature
+    - x86/kexec: Use up-to-dated screen_info copy to fill boot params
+    - of: Fix reserved-memory overlap detection
+    - scsi: core: Don't start concurrent async scan on same host
+    - vsock: use ns_capable_noaudit() on socket create
+    - vt: Disable KD_FONT_OP_COPY
+    - fork: fix copy_process(CLONE_PARENT) race with the exiting ->real_parent
+    - serial: 8250_mtk: Fix uart_get_baud_rate warning
+    - serial: txx9: add missing platform_driver_unregister() on error in
+      serial_txx9_init
+    - USB: serial: cyberjack: fix write-URB completion race
+    - USB: serial: option: add LE910Cx compositions 0x1203, 0x1230, 0x1231
+    - USB: serial: option: add Telit FN980 composition 0x1055
+    - USB: Add NO_LPM quirk for Kingston flash drive
+    - ARC: stack unwinding: avoid indefinite looping
+    - Revert "ARC: entry: fix potential EFA clobber when TIF_SYSCALL_TRACE"
+    - Linux 4.4.242
+
+  * [HP 635] Radeon 6310 brightness control does not work (LP: #1894667) //
+    Xenial update: v4.4.242 upstream stable release (LP: #1903750)
+    - ACPI: video: use ACPI backlight for HP 635 Notebook
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Fri, 27 Nov 2020 16:22:59 -0700
+
+linux (4.4.0-197.229) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-197.229 -proposed tracker (LP: #1905489)
+
+  * sha1_ce and sha2_ce modules no longer load on arm64 (LP: #1905336)
+    - SAUCE: Revert "crypto: arm64/sha - avoid non-standard inline asm tricks"
+
+  * Fails to build on powerpc (LP: #1905475)
+    - powerpc/uaccess-flush: fix corenet64_smp_defconfig build
+    - SAUCE: powerpc/uaccess: only include kup-radix.h on PPC_BOOK3S_64
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 25 Nov 2020 06:36:47 -0300
+
+linux (4.4.0-196.228) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-196.228 -proposed tracker (LP: #1905309)
+
+  * CVE-2020-4788
+    - SAUCE: powerpc/64s: Define MASKABLE_RELON_EXCEPTION_PSERIES_OOL
+    - SAUCE: powerpc/64s: move some exception handlers out of line
+    - powerpc/64s: flush L1D on kernel entry
+    - SAUCE: powerpc: Add a framework for user access tracking
+    - powerpc: Implement user_access_begin and friends
+    - powerpc: Fix __clear_user() with KUAP enabled
+    - powerpc/uaccess: Evaluate macro arguments once, before user access is
+      allowed
+    - powerpc/64s: flush L1D after user accesses
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 23 Nov 2020 15:06:11 -0300
+
+linux (4.4.0-195.227) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-195.227 -proposed tracker (LP: #1903107)
+
+  * Update kernel packaging to support forward porting kernels (LP: #1902957)
+    - [Debian] Update for leader included in BACKPORT_SUFFIX
+
+  * Avoid double newline when running insertchanges (LP: #1903293)
+    - [Packaging] insertchanges: avoid double newline
+
+  * EFI: Fails when BootCurrent entry does not exist (LP: #1899993)
+    - efivarfs: Replace invalid slashes with exclamation marks in dentries.
+
+  * CVE-2020-14351
+    - perf/core: Fix race in the perf_mmap_close() function
+
+  * CVE-2020-25645
+    - geneve: add transport ports in route lookup for geneve
+
+  * Xenial update: v4.4.241 upstream stable release (LP: #1902097)
+    - ibmveth: Identify ingress large send packets.
+    - tipc: fix the skb_unshare() in tipc_buf_append()
+    - net/ipv4: always honour route mtu during forwarding
+    - r8169: fix data corruption issue on RTL8402
+    - ALSA: bebob: potential info leak in hwdep_read()
+    - mm/kasan: print name of mem[set,cpy,move]() caller in report
+    - mm/kasan: add API to check memory regions
+    - compiler.h, kasan: Avoid duplicating __read_once_size_nocheck()
+    - compiler.h: Add read_word_at_a_time() function.
+    - lib/strscpy: Shut up KASAN false-positives in strscpy()
+    - x86/mm/ptdump: Fix soft lockup in page table walker
+    - net: hdlc: In hdlc_rcv, check to make sure dev is an HDLC device
+    - net: hdlc_raw_eth: Clear the IFF_TX_SKB_SHARING flag after calling
+      ether_setup
+    - nfc: Ensure presence of NFC_ATTR_FIRMWARE_NAME attribute in
+      nfc_genl_fw_download()
+    - tcp: fix to update snd_wl1 in bulk receiver fast path
+    - icmp: randomize the global rate limiter
+    - cifs: remove bogus debug code
+    - ima: Don't ignore errors from crypto_shash_update()
+    - EDAC/i5100: Fix error handling order in i5100_init_one()
+    - crypto: ixp4xx - Fix the size used in a 'dma_free_coherent()' call
+    - media: Revert "media: exynos4-is: Add missed check for
+      pinctrl_lookup_state()"
+    - media: m5mols: Check function pointer in m5mols_sensor_power
+    - media: omap3isp: Fix memleak in isp_probe
+    - crypto: omap-sham - fix digcnt register handling with export/import
+    - media: tc358743: initialize variable
+    - media: ti-vpe: Fix a missing check and reference count leak
+    - ath6kl: prevent potential array overflow in ath6kl_add_new_sta()
+    - ath9k: Fix potential out of bounds in ath9k_htc_txcompletion_cb()
+    - wcn36xx: Fix reported 802.11n rx_highest rate wcn3660/wcn3680
+    - mwifiex: Do not use GFP_KERNEL in atomic context
+    - drm/gma500: fix error check
+    - scsi: qla4xxx: Fix an error handling path in 'qla4xxx_get_host_stats()'
+    - scsi: csiostor: Fix wrong return value in csio_hw_prep_fw()
+    - backlight: sky81452-backlight: Fix refcount imbalance on error
+    - VMCI: check return value of get_user_pages_fast() for errors
+    - tty: serial: earlycon dependency
+    - pty: do tty_flip_buffer_push without port->lock in pty_write
+    - drivers/virt/fsl_hypervisor: Fix error handling path
+    - video: fbdev: vga16fb: fix setting of pixclock because a pass-by-value error
+    - video: fbdev: sis: fix null ptr dereference
+    - HID: roccat: add bounds checking in kone_sysfs_write_settings()
+    - ath6kl: wmi: prevent a shift wrapping bug in ath6kl_wmi_delete_pstream_cmd()
+    - misc: mic: scif: Fix error handling path
+    - ALSA: seq: oss: Avoid mutex lock for a long-time ioctl
+    - quota: clear padding in v2r1_mem2diskdqb()
+    - net: enic: Cure the enic api locking trainwreck
+    - mfd: sm501: Fix leaks in probe()
+    - usb: gadget: u_ether: enable qmult on SuperSpeed Plus as well
+    - nl80211: fix non-split wiphy information
+    - mwifiex: fix double free
+    - net: korina: fix kfree of rx/tx descriptor array
+    - IB/mlx4: Adjust delayed work when a dup is observed
+    - powerpc/pseries: Fix missing of_node_put() in rng_init()
+    - powerpc/icp-hv: Fix missing of_node_put() in success path
+    - mtd: lpddr: fix excessive stack usage with clang
+    - mtd: mtdoops: Don't write panic data twice
+    - ARM: 9007/1: l2c: fix prefetch bits init in L2X0_AUX_CTRL using DT values
+    - powerpc/tau: Use appropriate temperature sample interval
+    - powerpc/tau: Remove duplicated set_thresholds() call
+    - powerpc/tau: Disable TAU between measurements
+    - perf intel-pt: Fix "context_switch event has no tid" error
+    - kdb: Fix pager search for multi-line strings
+    - powerpc/perf/hv-gpci: Fix starting index value
+    - cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_reboot_notifier
+    - lib/crc32.c: fix trivial typo in preprocessor condition
+    - vfio/pci: Clear token on bypass registration failure
+    - Input: imx6ul_tsc - clean up some errors in imx6ul_tsc_resume()
+    - Input: ep93xx_keypad - fix handling of platform_get_irq() error
+    - Input: omap4-keypad - fix handling of platform_get_irq() error
+    - Input: sun4i-ps2 - fix handling of platform_get_irq() error
+    - KVM: x86: emulating RDPID failure shall return #UD rather than #GP
+    - memory: omap-gpmc: Fix a couple off by ones
+    - memory: fsl-corenet-cf: Fix handling of platform_get_irq() error
+    - arm64: dts: zynqmp: Remove additional compatible string for i2c IPs
+    - powerpc/powernv/opal-dump : Use IRQ_HANDLED instead of numbers in interrupt
+      handler
+    - powerpc/powernv/dump: Fix race while processing OPAL dump
+    - media: firewire: fix memory leak
+    - media: ati_remote: sanity check for both endpoints
+    - media: exynos4-is: Fix several reference count leaks due to
+      pm_runtime_get_sync
+    - media: exynos4-is: Fix a reference count leak due to pm_runtime_get_sync
+    - media: exynos4-is: Fix a reference count leak
+    - media: bdisp: Fix runtime PM imbalance on error
+    - media: media/pci: prevent memory leak in bttv_probe
+    - media: uvcvideo: Ensure all probed info is returned to v4l2
+    - mmc: sdio: Check for CISTPL_VERS_1 buffer size
+    - media: saa7134: avoid a shift overflow
+    - ntfs: add check for mft record size in superblock
+    - PM: hibernate: remove the bogus call to get_gendisk() in software_resume()
+    - scsi: mvumi: Fix error return in mvumi_io_attach()
+    - scsi: target: core: Add CONTROL field for trace events
+    - usb: gadget: function: printer: fix use-after-free in __lock_acquire
+    - udf: Limit sparing table size
+    - udf: Avoid accessing uninitialized data on failed inode read
+    - ath9k: hif_usb: fix race condition between usb_get_urb() and
+      usb_kill_anchored_urbs()
+    - misc: rtsx: Fix memory leak in rtsx_pci_probe
+    - reiserfs: only call unlock_new_inode() if I_NEW
+    - xfs: make sure the rt allocator doesn't run off the end
+    - usb: ohci: Default to per-port over-current protection
+    - Bluetooth: Only mark socket zapped after unlocking
+    - scsi: ibmvfc: Fix error return in ibmvfc_probe()
+    - brcmsmac: fix memory leak in wlc_phy_attach_lcnphy
+    - rtl8xxxu: prevent potential memory leak
+    - Fix use after free in get_capset_info callback.
+    - tty: ipwireless: fix error handling
+    - ipvs: Fix uninit-value in do_ip_vs_set_ctl()
+    - reiserfs: Fix memory leak in reiserfs_parse_options()
+    - brcm80211: fix possible memleak in brcmf_proto_msgbuf_attach
+    - usb: core: Solve race condition in anchor cleanup functions
+    - ath10k: check idx validity in __ath10k_htt_rx_ring_fill_n()
+    - net: korina: cast KSEG0 address to pointer in kfree
+    - usb: cdc-acm: add quirk to blacklist ETAS ES58X devices
+    - USB: cdc-wdm: Make wdm_flush() interruptible and add wdm_fsync().
+    - Linux 4.4.241
+
+  * Xenial update: v4.4.240 upstream stable release (LP: #1902096)
+    - Bluetooth: MGMT: Fix not checking if BT_HS is enabled
+    - Bluetooth: fix kernel oops in store_pending_adv_report
+    - Bluetooth: Consolidate encryption handling in hci_encrypt_cfm
+    - Bluetooth: Fix update of connection state in `hci_encrypt_cfm`
+    - Bluetooth: Disconnect if E0 is used for Level 4
+    - media: usbtv: Fix refcounting mixup
+    - USB: serial: option: add Cellient MPL200 card
+    - USB: serial: option: Add Telit FT980-KS composition
+    - staging: comedi: check validity of wMaxPacketSize of usb endpoints found
+    - USB: serial: pl2303: add device-id for HP GC device
+    - USB: serial: ftdi_sio: add support for FreeCalypso JTAG+UART adapters
+    - reiserfs: Initialize inode keys properly
+    - reiserfs: Fix oops during mount
+    - spi: unbinding slave before calling spi_destroy_queue
+    - crypto: qat - check cipher length for aead AES-CBC-HMAC-SHA
+    - Linux 4.4.240
+
+  * Xenial update: v4.4.239 upstream stable release (LP: #1902095)
+    - gpio: tc35894: fix up tc35894 interrupt configuration
+    - Input: i8042 - add nopnp quirk for Acer Aspire 5 A515
+    - drm/amdgpu: restore proper ref count in amdgpu_display_crtc_set_config
+    - net: dec: de2104x: Increase receive ring size for Tulip
+    - rndis_host: increase sleep time in the query-response loop
+    - drivers/net/wan/lapbether: Make skb->protocol consistent with the header
+    - drivers/net/wan/hdlc: Set skb->protocol before transmitting
+    - nfs: Fix security label length not being reset
+    - clk: samsung: exynos4: mark 'chipid' clock as CLK_IGNORE_UNUSED
+    - iommu/exynos: add missing put_device() call in exynos_iommu_of_xlate()
+    - i2c: cpm: Fix i2c_ram structure
+    - epoll: do not insert into poll queues until all sanity checks are done
+    - epoll: replace ->visited/visited_list with generation count
+    - epoll: EPOLL_CTL_ADD: close the race in decision to take fast path
+    - ep_create_wakeup_source(): dentry name can change under you...
+    - netfilter: ctnetlink: add a range check for l3/l4 protonum
+    - fbdev, newport_con: Move FONT_EXTRA_WORDS macros into linux/font.h
+    - Fonts: Support FONT_EXTRA_WORDS macros for built-in fonts
+    - Revert "ravb: Fixed to be able to unload modules"
+    - fbcon: Fix global-out-of-bounds read in fbcon_get_font()
+    - net: wireless: nl80211: fix out-of-bounds access in nl80211_del_key()
+    - usermodehelper: reset umask to default before executing user process
+    - platform/x86: thinkpad_acpi: initialize tp_nvram_state variable
+    - platform/x86: thinkpad_acpi: re-initialize ACPI buffer size when reuse
+    - driver core: Fix probe_count imbalance in really_probe()
+    - perf top: Fix stdio interface input handling with glibc 2.28+
+    - sctp: fix sctp_auth_init_hmacs() error path
+    - team: set dev->needed_headroom in team_setup_by_port()
+    - net: team: fix memory leak in __team_options_register
+    - mtd: nand: Provide nand_cleanup() function to free NAND related resources
+    - xfrm: clone XFRMA_REPLAY_ESN_VAL in xfrm_do_migrate
+    - xfrm: clone whole liftime_cur structure in xfrm_do_migrate
+    - net: stmmac: removed enabling eee in EEE set callback
+    - xfrm: Use correct address family in xfrm_state_find
+    - bonding: set dev->needed_headroom in bond_setup_by_slave()
+    - rxrpc: Fix rxkad token xdr encoding
+    - rxrpc: Downgrade the BUG() for unsupported token type in rxrpc_read()
+    - rxrpc: Fix server keyring leak
+    - net: usb: rtl8150: set random MAC address when set_ethernet_addr() fails
+    - Linux 4.4.239
+
+  * CVE-2020-12352
+    - Bluetooth: A2MP: Fix not initializing all members
+
+  * CVE-2020-0427
+    - pinctrl: devicetree: Avoid taking direct reference to device name string
+
+  * Xenial update: v4.4.238 upstream stable release (LP: #1899506)
+    - af_key: pfkey_dump needs parameter validation
+    - KVM: fix memory leak in kvm_io_bus_unregister_dev()
+    - kprobes: fix kill kprobe which has been marked as gone
+    - ftrace: Setup correct FTRACE_FL_REGS flags for module
+    - RDMA/ucma: ucma_context reference leak in error path
+    - mtd: Fix comparison in map_word_andequal()
+    - hdlc_ppp: add range checks in ppp_cp_parse_cr()
+    - tipc: use skb_unshare() instead in tipc_buf_append()
+    - net: add __must_check to skb_put_padto()
+    - ip: fix tos reflection in ack and reset packets
+    - serial: 8250: Avoid error message on reprobe
+    - scsi: aacraid: fix illegal IO beyond last LBA
+    - m68k: q40: Fix info-leak in rtc_ioctl
+    - gma/gma500: fix a memory disclosure bug due to uninitialized bytes
+    - ASoC: kirkwood: fix IRQ error handling
+    - PM / devfreq: tegra30: Fix integer overflow on CPU's freq max out
+    - mtd: cfi_cmdset_0002: don't free cfi->cfiq in error path of
+      cfi_amdstd_setup()
+    - mfd: mfd-core: Protect against NULL call-back function pointer
+    - tracing: Adding NULL checks for trace_array descriptor pointer
+    - bcache: fix a lost wake-up problem caused by mca_cannibalize_lock
+    - xfs: fix attr leaf header freemap.size underflow
+    - kernel/sys.c: avoid copying possible padding bytes in copy_to_user
+    - neigh_stat_seq_next() should increase position index
+    - rt_cpu_seq_next should increase position index
+    - seqlock: Require WRITE_ONCE surrounding raw_seqcount_barrier
+    - ACPI: EC: Reference count query handlers under lock
+    - tracing: Set kernel_stack's caller size properly
+    - ar5523: Add USB ID of SMCWUSBT-G2 wireless adapter
+    - Bluetooth: Fix refcount use-after-free issue
+    - mm: pagewalk: fix termination condition in walk_pte_range()
+    - Bluetooth: prefetch channel before killing sock
+    - skbuff: fix a data race in skb_queue_len()
+    - audit: CONFIG_CHANGE don't log internal bookkeeping as an event
+    - selinux: sel_avc_get_stat_idx should increase position index
+    - scsi: lpfc: Fix RQ buffer leakage when no IOCBs available
+    - drm/omap: fix possible object reference leak
+    - dmaengine: tegra-apb: Prevent race conditions on channel's freeing
+    - media: go7007: Fix URB type for interrupt handling
+    - Bluetooth: guard against controllers sending zero'd events
+    - drm/amdgpu: increase atombios cmd timeout
+    - Bluetooth: L2CAP: handle l2cap config request during open state
+    - media: tda10071: fix unsigned sign extension overflow
+    - tpm: ibmvtpm: Wait for buffer to be set before proceeding
+    - tracing: Use address-of operator on section symbols
+    - serial: 8250_omap: Fix sleeping function called from invalid context during
+      probe
+    - SUNRPC: Fix a potential buffer overflow in 'svc_print_xprts()'
+    - ubifs: Fix out-of-bounds memory access caused by abnormal value of node_len
+    - ALSA: usb-audio: Fix case when USB MIDI interface has more than one extra
+      endpoint descriptor
+    - mm/filemap.c: clear page error before actual read
+    - mm/mmap.c: initialize align_offset explicitly for vm_unmapped_area
+    - KVM: Remove CREATE_IRQCHIP/SET_PIT2 race
+    - bdev: Reduce time holding bd_mutex in sync in blkdev_close()
+    - drivers: char: tlclk.c: Avoid data race between init and interrupt handler
+    - dt-bindings: sound: wm8994: Correct required supplies based on actual
+      implementaion
+    - atm: fix a memory leak of vcc->user_back
+    - phy: samsung: s5pv210-usb2: Add delay after reset
+    - Bluetooth: Handle Inquiry Cancel error after Inquiry Complete
+    - USB: EHCI: ehci-mv: fix error handling in mv_ehci_probe()
+    - tty: serial: samsung: Correct clock selection logic
+    - ALSA: hda: Fix potential race in unsol event handler
+    - fuse: don't check refcount after stealing page
+    - USB: EHCI: ehci-mv: fix less than zero comparison of an unsigned int
+    - e1000: Do not perform reset in reset_task if we are already down
+    - printk: handle blank console arguments passed in.
+    - vfio/pci: fix memory leaks of eventfd ctx
+    - perf kcore_copy: Fix module map when there are no modules loaded
+    - mtd: rawnand: omap_elm: Fix runtime PM imbalance on error
+    - ceph: fix potential race in ceph_check_caps
+    - mtd: parser: cmdline: Support MTD names containing one or more colons
+    - x86/speculation/mds: Mark mds_user_clear_cpu_buffers() __always_inline
+    - vfio/pci: Clear error and request eventfd ctx after releasing
+    - vfio/pci: fix racy on error and request eventfd ctx
+    - s390/init: add missing __init annotations
+    - batman-adv: bla: fix type misuse for backbone_gw hash indexing
+    - atm: eni: fix the missed pci_disable_device() for eni_init_one()
+    - batman-adv: mcast/TT: fix wrongly dropped or rerouted packets
+    - ALSA: asihpi: fix iounmap in error handler
+    - MIPS: Add the missing 'CPU_1074K' into __get_cpu_type()
+    - tty: vt, consw->con_scrolldelta cleanup
+    - kprobes: Fix to check probe enabled before disarm_kprobe_ftrace()
+    - lib/string.c: implement stpcpy
+    - ata: define AC_ERR_OK
+    - ata: make qc_prep return ata_completion_errors
+    - ata: sata_mv, avoid trigerrable BUG_ON
+    - Linux 4.4.238
+
+  * *-tools-common packages descriptions have typo "PGKVER" (LP: #1898903)
+    - [Packaging] Fix typo in -tools template s/PGKVER/PKGVER/
+
+  * Xenial update: v4.4.237 upstream stable release (LP: #1897602)
+    - ARM: dts: socfpga: fix register entry for timer3 on Arria10
+    - scsi: libsas: Set data_dir as DMA_NONE if libata marks qc as NODATA
+    - drivers/net/wan/lapbether: Added needed_tailroom
+    - firestream: Fix memleak in fs_open
+    - drivers/net/wan/lapbether: Set network_header before transmitting
+    - xfs: initialize the shortform attr header padding entry
+    - drivers/net/wan/hdlc_cisco: Add hard_header_len
+    - ALSA: hda: fix a runtime pm issue in SOF when integrated GPU is disabled
+    - gcov: Disable gcov build with GCC 10
+    - iio: adc: mcp3422: fix locking scope
+    - iio: adc: mcp3422: fix locking on error path
+    - iio:light:ltr501 Fix timestamp alignment issue.
+    - iio:accel:bmc150-accel: Fix timestamp alignment and prevent data leak.
+    - iio:accel:mma8452: Fix timestamp alignment and prevent data leak.
+    - USB: core: add helpers to retrieve endpoints
+    - staging: wlan-ng: fix out of bounds read in prism2sta_probe_usb()
+    - btrfs: fix wrong address when faulting in pages in the search ioctl
+    - scsi: target: iscsi: Fix hang in iscsit_access_np() when getting
+      tpg->np_login_sem
+    - rbd: require global CAP_SYS_ADMIN for mapping and unmapping
+    - fbcon: remove soft scrollback code
+    - fbcon: remove now unusued 'softback_lines' cursor() argument
+    - vgacon: remove software scrollback support
+    - [Config] updateconfigs for VGACON_SOFT_SCROLLBACK
+    - KVM: VMX: Don't freeze guest when event delivery causes an APIC-access exit
+    - video: fbdev: fix OOB read in vga_8planes_imageblit()
+    - USB: serial: ftdi_sio: add IDs for Xsens Mti USB converter
+    - USB: serial: option: add support for SIM7070/SIM7080/SIM7090 modules
+    - usb: Fix out of sync data toggle if a configured device is reconfigured
+    - gcov: add support for GCC 10.1
+    - NFSv4.1 handle ERR_DELAY error reclaiming locking state on delegation recall
+    - scsi: pm8001: Fix memleak in pm8001_exec_internal_task_abort
+    - scsi: lpfc: Fix FLOGI/PLOGI receive race condition in pt2pt discovery
+    - SUNRPC: stop printk reading past end of string
+    - rapidio: Replace 'select' DMAENGINES 'with depends on'
+    - i2c: algo: pca: Reapply i2c bus settings after reset
+    - MIPS: SNI: Fix MIPS_L1_CACHE_SHIFT
+    - perf test: Free formats for perf pmu parse test
+    - fbcon: Fix user font detection test at fbcon_resize().
+    - MIPS: SNI: Fix spurious interrupts
+    - USB: quirks: Add USB_QUIRK_IGNORE_REMOTE_WAKEUP quirk for BYD zhaoxin
+      notebook
+    - USB: UAS: fix disconnect by unplugging a hub
+    - usblp: fix race between disconnect() and read()
+    - Input: i8042 - add Entroware Proteus EL07R4 to nomux and reset lists
+    - serial: 8250_pci: Add Realtek 816a and 816b
+    - ehci-hcd: Move include to keep CRC stable
+    - powerpc/dma: Fix dma_map_ops::get_required_mask
+    - x86/defconfig: Enable CONFIG_USB_XHCI_HCD=y
+    - Linux 4.4.237
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 09 Nov 2020 11:42:59 +0100
+
+linux (4.4.0-194.226) xenial; urgency=medium
+
+  * CVE-2020-8694
+    - powercap: make attributes only readable by root
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 21 Oct 2020 11:31:44 +0200
+
+linux (4.4.0-193.224) xenial; urgency=medium
+
+  * CVE-2020-16119
+    - SAUCE: dccp: avoid double free of ccid on child socket
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 06 Oct 2020 12:24:31 -0300
+
+linux (4.4.0-192.222) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-192.222 -proposed tracker (LP: #1897734)
+
+  * mwifiex stops working after kernel upgrade (LP: #1897299)
+    - mwifiex: Increase AES key storage size to 256 bits
+
+  * xenial 4.4.0-191-generic in -proposed has a regression (LP: #1896725)
+    - Revert "XEN uses irqdesc::irq_data_common::handler_data to store a per
+      interrupt XEN data pointer which contains XEN specific information."
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 29 Sep 2020 16:43:40 +0200
+
+linux (4.4.0-191.221) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-191.221 -proposed tracker (LP: #1896067)
+
+  * Novalink (mkvterm command failure) (LP: #1892546)
+    - tty: hvcs: Don't NULL tty->driver_data until hvcs_cleanup()
+
+  * Xenial update: v4.4.236 upstream stable release (LP: #1895891)
+    - HID: core: Correctly handle ReportSize being zero
+    - HID: core: Sanitize event code and type when mapping input
+    - perf record/stat: Explicitly call out event modifiers in the documentation
+    - mm, page_alloc: remove unnecessary variable from free_pcppages_bulk
+    - hwmon: (applesmc) check status earlier.
+    - ceph: don't allow setlease on cephfs
+    - s390: don't trace preemption in percpu macros
+    - xen/xenbus: Fix granting of vmalloc'd memory
+    - dmaengine: of-dma: Fix of_dma_router_xlate's of_dma_xlate handling
+    - batman-adv: Avoid uninitialized chaddr when handling DHCP
+    - batman-adv: bla: use netif_rx_ni when not in interrupt context
+    - dmaengine: at_hdmac: check return value of of_find_device_by_node() in
+      at_dma_xlate()
+    - netfilter: nf_tables: incorrect enum nft_list_attributes definition
+    - netfilter: nf_tables: fix destination register zeroing
+    - dmaengine: pl330: Fix burst length if burst size is smaller than bus width
+    - bnxt_en: Check for zero dir entries in NVRAM.
+    - fix regression in "epoll: Keep a reference on files added to the check list"
+    - tg3: Fix soft lockup when tg3_reset_task() fails.
+    - iommu/vt-d: Serialize IOMMU GCMD register modifications
+    - thermal: ti-soc-thermal: Fix bogus thermal shutdowns for omap4430
+    - include/linux/log2.h: add missing () around n in roundup_pow_of_two()
+    - btrfs: drop path before adding new uuid tree entry
+    - btrfs: Remove redundant extent_buffer_get in get_old_root
+    - btrfs: Remove extraneous extent_buffer_get from tree_mod_log_rewind
+    - btrfs: set the lockdep class for log tree extent buffers
+    - uaccess: Add non-pagefault user-space read functions
+    - uaccess: Add non-pagefault user-space write function
+    - btrfs: fix potential deadlock in the search ioctl
+    - net: qmi_wwan: MDM9x30 specific power management
+    - net: qmi_wwan: support "raw IP" mode
+    - net: qmi_wwan: should hold RTNL while changing netdev type
+    - net: qmi_wwan: ignore bogus CDC Union descriptors
+    - Add Dell Wireless 5809e Gobi 4G HSPA+ Mobile Broadband Card (rev3) to
+      qmi_wwan
+    - qmi_wwan: Added support for Gemalto's Cinterion PHxx WWAN interface
+    - qmi_wwan: add support for Quectel EC21 and EC25
+    - NET: usb: qmi_wwan: add support for Telit LE922A PID 0x1040
+    - drivers: net: usb: qmi_wwan: add QMI_QUIRK_SET_DTR for Telit PID 0x1201
+    - usb: qmi_wwan: add D-Link DWM-222 A2 device ID
+    - net: usb: qmi_wwan: add Telit ME910 support
+    - net: usb: qmi_wwan: add Telit 0x1050 composition
+    - ALSA: ca0106: fix error code handling
+    - ALSA: pcm: oss: Remove superfluous WARN_ON() for mulaw sanity check
+    - dm cache metadata: Avoid returning cmd->bm wild pointer on error
+    - dm thin metadata: Avoid returning cmd->bm wild pointer on error
+    - net: refactor bind_bucket fastreuse into helper
+    - net: initialize fastreuse on inet_inherit_port
+    - checkpatch: fix the usage of capture group ( ... )
+    - mm/hugetlb: fix a race between hugetlb sysctl handlers
+    - cfg80211: regulatory: reject invalid hints
+    - net: usb: Fix uninit-was-stored issue in asix_read_phy_addr()
+    - ALSA: firewire-digi00x: add support for console models of Digi00x series
+    - ALSA: firewire-digi00x: exclude Avid Adrenaline from detection
+    - ALSA; firewire-tascam: exclude Tascam FE-8 from detection
+    - fs/affs: use octal for permissions
+    - affs: fix basic permission bits to actually work
+    - ravb: Fixed to be able to unload modules
+    - net: ethernet: mlx4: Fix memory allocation in mlx4_buddy_init()
+    - bnxt_en: Failure to update PHY is not fatal condition.
+    - bnxt: don't enable NAPI until rings are ready
+    - net: usb: dm9601: Add USB ID of Keenetic Plus DSL
+    - sctp: not disable bh in the whole sctp_get_port_local()
+    - net: disable netpoll on fresh napis
+    - Linux 4.4.236
+
+  * clock: overriding the clocksource should select the requested clocksource
+    (LP: #1894591)
+    - clocksource: Defer override invalidation unless clock is unstable
+
+  * alsa/hdmi: the hdmi audio stops working from Ubuntu-4.4.0-155.182
+    (LP: #1895603)
+    - ALSA: hda/hdmi - Read the pin sense from register when repolling
+    - SAUCE: ALSA: hda/hdmi - Check pin_eld->monitor_present
+
+  * Xenial update: v4.4.235 upstream stable release (LP: #1895031)
+    - net: Fix potential wrong skb->protocol in skb_vlan_untag()
+    - tipc: fix uninit skb->data in tipc_nl_compat_dumpit()
+    - ipvlan: fix device features
+    - bonding: show saner speed for broadcast mode
+    - bonding: fix a potential double-unregister
+    - powerpc/pseries: Do not initiate shutdown when system is running on UPS
+    - ALSA: pci: delete repeated words in comments
+    - ASoC: tegra: Fix reference count leaks.
+    - media: pci: ttpci: av7110: fix possible buffer overflow caused by bad DMA
+      value in debiirq()
+    - scsi: target: tcmu: Fix crash on ARM during cmd completion
+    - drm/amdkfd: Fix reference count leaks.
+    - drm/radeon: fix multiple reference count leak
+    - drm/amdgpu: fix ref count leak in amdgpu_driver_open_kms
+    - drm/amd/display: fix ref count leak in amdgpu_drm_ioctl
+    - drm/amdgpu: fix ref count leak in amdgpu_display_crtc_set_config
+    - drm/amdgpu/display: fix ref count leak when pm_runtime_get_sync fails
+    - scsi: lpfc: Fix shost refcount mismatch when deleting vport
+    - selftests/powerpc: Purge extra count_pmc() calls of ebb selftests
+    - PCI: Fix pci_create_slot() reference count leak
+    - rtlwifi: rtl8192cu: Prevent leaking urb
+    - mips/vdso: Fix resource leaks in genvdso.c
+    - drm/nouveau/drm/noveau: fix reference count leak in nouveau_fbcon_open
+    - drm/nouveau: Fix reference count leak in nouveau_connector_detect
+    - locking/lockdep: Fix overflow in presentation of average lock-time
+    - scsi: iscsi: Do not put host in iscsi_set_flashnode_param()
+    - ceph: fix potential mdsc use-after-free crash
+    - scsi: fcoe: Memory leak fix in fcoe_sysfs_fcf_del()
+    - EDAC/ie31200: Fallback if host bridge device is already initialized
+    - media: davinci: vpif_capture: fix potential double free
+    - powerpc/spufs: add CONFIG_COREDUMP dependency
+    - USB: sisusbvga: Fix a potential UB casued by left shifting a negative value
+    - Revert "ath10k: fix DMA related firmware crashes on multiple devices"
+    - i2c: rcar: in slave mode, clear NACK earlier
+    - jbd2: make sure jh have b_transaction set in refile/unfile_buffer
+    - jbd2: abort journal if free a async write error metadata buffer
+    - s390/cio: add cond_resched() in the slow_eval_known_fn() loop
+    - scsi: ufs: Fix possible infinite loop in ufshcd_hold
+    - net: gianfar: Add of_node_put() before goto statement
+    - fbcon: prevent user font height or width change from causing potential out-
+      of-bounds access
+    - USB: lvtest: return proper error code in probe
+    - vt: defer kfree() of vc_screenbuf in vc_do_resize()
+    - vt_ioctl: change VT_RESIZEX ioctl to check for error return from vc_resize()
+    - serial: samsung: Removes the IRQ not found warning
+    - serial: pl011: Don't leak amba_ports entry on driver register error
+    - serial: 8250: change lock order in serial8250_do_startup()
+    - writeback: Protect inode->i_io_list with inode->i_lock
+    - writeback: Avoid skipping inode writeback
+    - writeback: Fix sync livelock due to b_dirty_time processing
+    - XEN uses irqdesc::irq_data_common::handler_data to store a per interrupt XEN
+      data pointer which contains XEN specific information.
+    - xhci: Do warm-reset when both CAS and XDEV_RESUME are set
+    - PM: sleep: core: Fix the handling of pending runtime resume requests
+    - device property: Fix the secondary firmware node handling in
+      set_primary_fwnode()
+    - USB: yurex: Fix bad gfp argument
+    - usb: uas: Add quirk for PNY Pro Elite
+    - USB: Ignore UAS for JMicron JMS567 ATA/ATAPI Bridge
+    - usb: host: ohci-exynos: Fix error handling in exynos_ohci_probe()
+    - usb: storage: Add unusual_uas entry for Sony PSZ drives
+    - btrfs: check the right error variable in btrfs_del_dir_entries_in_log
+    - HID: hiddev: Fix slab-out-of-bounds write in hiddev_ioctl_usage()
+    - ALSA: usb-audio: Update documentation comment for MS2109 quirk
+    - Linux 4.4.235
+
+  * DELL LATITUDE 5491 touchscreen doesn't work (LP: #1889446) // Xenial update:
+    v4.4.235 upstream stable release (LP: #1895031)
+    - USB: quirks: Add no-lpm quirk for another Raydium touchscreen
+
+  * Xenial update: v4.4.234 upstream stable release (LP: #1893248)
+    - cxl: Fix kobject memleak
+    - drm/imx: imx-ldb: Disable both channels for split mode in enc->disable()
+    - perf probe: Fix memory leakage when the probe point is not found
+    - net/compat: Add missing sock updates for SCM_RIGHTS
+    - watchdog: f71808e_wdt: indicate WDIOF_CARDRESET support in
+      watchdog_info.options
+    - watchdog: f71808e_wdt: remove use of wrong watchdog_info option
+    - coredump: fix race condition between collapse_huge_page() and core dumping
+    - khugepaged: khugepaged_test_exit() check mmget_still_valid()
+    - khugepaged: adjust VM_BUG_ON_MM() in __khugepaged_enter()
+    - btrfs: export helpers for subvolume name/id resolution
+    - btrfs: don't show full path of bind mounts in subvol=
+    - romfs: fix uninitialized memory leak in romfs_dev_read()
+    - mm: include CMA pages in lowmem_reserve at boot
+    - mm, page_alloc: fix core hung in free_pcppages_bulk()
+    - ext4: clean up ext4_match() and callers
+    - ext4: fix checking of directory entry validity for inline directories
+    - media: budget-core: Improve exception handling in budget_register()
+    - media: vpss: clean up resources in init
+    - Input: psmouse - add a newline when printing 'proto' by sysfs
+    - m68knommu: fix overwriting of bits in ColdFire V3 cache control
+    - xfs: fix inode quota reservation checks
+    - jffs2: fix UAF problem
+    - scsi: libfc: Free skb in fc_disc_gpn_id_resp() for valid cases
+    - virtio_ring: Avoid loop when vq is broken in virtqueue_poll
+    - xfs: Fix UBSAN null-ptr-deref in xfs_sysfs_init
+    - alpha: fix annotation of io{read,write}{16,32}be()
+    - ext4: fix potential negative array index in do_split()
+    - ASoC: intel: Fix memleak in sst_media_open
+    - powerpc: Allow 4224 bytes of stack expansion for the signal frame
+    - epoll: Keep a reference on files added to the check list
+    - do_epoll_ctl(): clean the failure exits up a bit
+    - mm/hugetlb: fix calculation of adjust_range_if_pmd_sharing_possible
+    - xen: don't reschedule in preemption off sections
+    - omapfb: dss: Fix max fclk divider for omap36xx
+    - KVM: arm/arm64: Don't reschedule in unmap_stage2_range()
+    - Linux 4.4.234
+
+  * CVE-2018-10322
+    - libxfs: synchronize dinode_verify with userspace
+    - xfs: sanity check directory inode di_size
+    - xfs: move inode fork verifiers to xfs_dinode_verify
+    - xfs: enhance dinode verifier
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 18 Sep 2020 11:37:51 +0200
+
+linux (4.4.0-190.220) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-190.220 -proposed tracker (LP: #1893431)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  *  [Hyper-V] VSS and File Copy daemons intermittently fails to start
+    (LP: #1891224)
+    - [Packaging] Bind hv_vss_daemon startup to hv_vss device
+    - [Packaging] bind hv_fcopy_daemon startup to hv_fcopy device
+
+  * CVE-2019-20811
+    - net-sysfs: call dev_hold if kobject_init_and_add success
+
+  * CVE-2020-0067
+    - f2fs: fix to avoid memory leakage in f2fs_listxattr
+
+  * CVE-2019-9453
+    - f2fs: fix to avoid accessing xattr across the boundary
+
+  * Xenial update: 4.4.233 upstream stable release (LP: #1892822)
+    - media: rc: prevent memory leak in cx23888_ir_probe
+    - ath9k_htc: release allocated buffer if timed out
+    - ath9k: release allocated buffer if timed out
+    - nfs: Move call to security_inode_listsecurity into nfs_listxattr
+    - PCI/ASPM: Disable ASPM on ASMedia ASM1083/1085 PCIe-to-PCI bridge
+    - drm/amdgpu: Prevent kernel-infoleak in amdgpu_info_ioctl()
+    - drm: hold gem reference until object is no longer accessed
+    - f2fs: check memory boundary by insane namelen
+    - f2fs: check if file namelen exceeds max value
+    - ARM: 8986/1: hw_breakpoint: Don't invoke overflow handler on uaccess
+      watchpoints
+    - fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins.
+    - rds: Prevent kernel-infoleak in rds_notify_queue_get()
+    - net/x25: Fix x25_neigh refcnt leak when x25 disconnect
+    - net/x25: Fix null-ptr-deref in x25_disconnect
+    - sh: Fix validation of system call number
+    - net: lan78xx: add missing endpoint sanity check
+    - net: lan78xx: fix transfer-buffer memory leak
+    - mlxsw: core: Increase scope of RCU read-side critical section
+    - mac80211: mesh: Free ie data when leaving mesh
+    - nfc: s3fwrn5: add missing release on skb in s3fwrn5_recv_frame
+    - net: ethernet: ravb: exit if re-initialization fails in tx timeout
+    - Revert "i2c: cadence: Fix the hold bit setting"
+    - xen-netfront: fix potential deadlock in xennet_remove()
+    - x86/i8259: Use printk_deferred() to prevent deadlock
+    - random32: update the net random state on interrupt and activity
+    - ARM: percpu.h: fix build error
+    - random: fix circular include dependency on arm64 after addition of percpu.h
+    - random32: remove net_rand_state from the latent entropy gcc plugin
+    - random32: move the pseudo-random 32-bit definitions to prandom.h
+    - ext4: fix direct I/O read error
+    - USB: serial: qcserial: add EM7305 QDL product ID
+    - ALSA: seq: oss: Serialize ioctls
+    - Bluetooth: Fix slab-out-of-bounds read in hci_extended_inquiry_result_evt()
+    - Bluetooth: Prevent out-of-bounds read in hci_inquiry_result_evt()
+    - Bluetooth: Prevent out-of-bounds read in hci_inquiry_result_with_rssi_evt()
+    - vgacon: Fix for missing check in scrollback handling
+    - mtd: properly check all write ioctls for permissions
+    - net/9p: validate fds in p9_fd_open
+    - drm/nouveau/fbcon: fix module unload when fbcon init has failed for some
+      reason
+    - cfg80211: check vendor command doit pointer before use
+    - igb: reinit_locked() should be called with rtnl_lock
+    - atm: fix atm_dev refcnt leaks in atmtcp_remove_persistent
+    - tools lib traceevent: Fix memory leak in process_dynamic_array_len
+    - binder: Prevent context manager from incrementing ref 0
+    - ipv4: Silence suspicious RCU usage warning
+    - ipv6: fix memory leaks on IPV6_ADDRFORM path
+    - Revert "vxlan: fix tos value before xmit"
+    - net: lan78xx: replace bogus endpoint lookup
+    - usb: hso: check for return value in hso_serial_common_create()
+    - vxlan: Ensure FDB dump is performed under RCU
+    - Smack: fix use-after-free in smk_write_relabel_self()
+    - tracepoint: Mark __tracepoint_string's __used
+    - udp: drop corrupt packets earlier to avoid data corruption
+    - gpio: fix oops resulting from calling of_get_named_gpio(NULL, ...)
+    - EDAC: Fix reference count leaks
+    - m68k: mac: Don't send IOP message until channel is idle
+    - m68k: mac: Fix IOP status/control register writes
+    - ARM: at91: pm: add missing put_device() call in at91_pm_sram_init()
+    - ARM: socfpga: PM: add missing put_device() call in
+      socfpga_setup_ocram_self_refresh()
+    - drm/tilcdc: fix leak & null ref in panel_connector_get_modes
+    - Bluetooth: add a mutex lock to avoid UAF in do_enale_set
+    - fs/btrfs: Add cond_resched() for try_release_extent_mapping() stalls
+    - drm/radeon: Fix reference count leaks caused by pm_runtime_get_sync
+    - video: fbdev: neofb: fix memory leak in neo_scan_monitor()
+    - drm/nouveau: fix multiple instances of reference count leaks
+    - drm/debugfs: fix plain echo to connector "force" attribute
+    - mm/mmap.c: Add cond_resched() for exit_mmap() CPU stalls
+    - brcmfmac: To fix Bss Info flag definition Bug
+    - iwlegacy: Check the return value of pcie_capability_read_*()
+    - usb: gadget: net2280: fix memory leak on probe error handling paths
+    - bdc: Fix bug causing crash after multiple disconnects
+    - dyndbg: fix a BUG_ON in ddebug_describe_flags
+    - bcache: fix super block seq numbers comparision in register_cache_set()
+    - ACPICA: Do not increment operation_region reference counts for field units
+    - agp/intel: Fix a memory leak on module initialisation failure
+    - video: fbdev: sm712fb: fix an issue about iounmap for a wrong address
+    - console: newport_con: fix an issue about leak related system resources
+    - iio: improve IIO_CONCENTRATION channel type description
+    - leds: lm355x: avoid enum conversion warning
+    - media: omap3isp: Add missed v4l2_ctrl_handler_free() for
+      preview_init_entities()
+    - scsi: cumana_2: Fix different dev_id between request_irq() and free_irq()
+    - drm/radeon: fix array out-of-bounds read and write issues
+    - scsi: powertec: Fix different dev_id between request_irq() and free_irq()
+    - scsi: eesox: Fix different dev_id between request_irq() and free_irq()
+    - media: firewire: Using uninitialized values in node_probe()
+    - media: exynos4-is: Add missed check for pinctrl_lookup_state()
+    - drm: panel: simple: Fix bpc for LG LB070WV8 panel
+    - mwifiex: Prevent memory corruption handling keys
+    - powerpc/vdso: Fix vdso cpu truncation
+    - PCI/ASPM: Add missing newline in sysfs 'policy'
+    - usb: dwc2: Fix error path in gadget registration
+    - scsi: mesh: Fix panic after host or bus reset
+    - Smack: fix another vsscanf out of bounds
+    - Smack: prevent underflow in smk_set_cipso()
+    - power: supply: check if calc_soc succeeded in pm860x_init_battery
+    - s390/qeth: don't process empty bridge port events
+    - wl1251: fix always return 0 error
+    - net: spider_net: Fix the size used in a 'dma_free_coherent()' call
+    - dlm: Fix kobject memleak
+    - pinctrl-single: fix pcs_parse_pinconf() return value
+    - drivers/net/wan/lapbether: Added needed_headroom and a skb->len check
+    - net/nfc/rawsock.c: add CAP_NET_RAW check.
+    - net: Set fput_needed iff FDPUT_FPUT is set
+    - ALSA: usb-audio: Creative USB X-Fi Pro SB1095 volume knob support
+    - ALSA: usb-audio: fix overeager device match for MacroSilicon MS2109
+    - ALSA: usb-audio: add quirk for Pioneer DDJ-RB
+    - crypto: qat - fix double free in qat_uclo_create_batch_init_list
+    - fs/minix: check return value of sb_getblk()
+    - fs/minix: don't allow getting deleted inodes
+    - fs/minix: reject too-large maximum file size
+    - ALSA: usb-audio: work around streaming quirk for MacroSilicon MS2109
+    - 9p: Fix memory leak in v9fs_mount
+    - parisc: mask out enable and reserved bits from sba imask
+    - ARM: 8992/1: Fix unwind_frame for clang-built kernels
+    - xen/balloon: fix accounting in alloc_xenballooned_pages error path
+    - xen/balloon: make the balloon wait interruptible
+    - PCI: hotplug: ACPI: Fix context refcounting in acpiphp_grab_context()
+    - btrfs: only search for left_info if there is no right_info in
+      try_merge_free_space
+    - btrfs: fix memory leaks after failure to lookup checksums during inode
+      logging
+    - powerpc: Fix circular dependency between percpu.h and mmu.h
+    - net: ethernet: stmmac: Disable hardware multicast filter
+    - net: stmmac: dwmac1000: provide multicast filter fallback
+    - md/raid5: Fix Force reconstruct-write io stuck in degraded raid5
+    - bcache: allocate meta data pages as compound pages
+    - mac80211: fix misplaced while instead of if
+    - MIPS: CPU#0 is not hotpluggable
+    - ext2: fix missing percpu_counter_inc
+    - ocfs2: change slot number type s16 to u16
+    - kprobes: Fix NULL pointer dereference at kprobe_ftrace_handler
+    - pseries: Fix 64 bit logical memory block panic
+    - USB: serial: ftdi_sio: make process-packet buffer unsigned
+    - USB: serial: ftdi_sio: clean up receive processing
+    - iommu/omap: Check for failure of a call to omap_iommu_dump_ctx
+    - iommu/vt-d: Enforce PASID devTLB field mask
+    - i2c: rcar: slave: only send STOP event when we have been addressed
+    - clk: clk-atlas6: fix return value check in atlas6_clk_init()
+    - Input: sentelic - fix error return when fsp_reg_write fails
+    - drm/vmwgfx: Fix two list_for_each loop exit tests
+    - nfs: Fix getxattr kernel panic and memory overflow
+    - fs/ufs: avoid potential u32 multiplication overflow
+    - mfd: dln2: Run event handler loop under spinlock
+    - ALSA: echoaudio: Fix potential Oops in snd_echo_resume()
+    - sh: landisk: Add missing initialization of sh_io_port_base
+    - ipv6: check skb->protocol before lookup for nexthop
+    - Linux 4.4.233
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Sat, 29 Aug 2020 00:39:55 +0200
+
+linux (4.4.0-189.219) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-189.219 -proposed tracker (LP: #1891057)
+
+  * Build and ship a signed wireguard.ko (LP: #1861284)
+    - [Packaging] autoreconstruct -- manage executable debian files
+    - [Packaging] dkms -- dkms package build packaging support
+    - [Packaging] wireguard -- add support for building signed .ko
+    - [Packaging] ignore wireguard modules when wireguard is disabled
+    - [Config] update dkms package versions
+    - [Config] wireguard -- enable for all architectures
+
+  * ipsec: policy priority management is broken (LP: #1890796)
+    - xfrm: policy: match with both mark and mask on user interfaces
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 11 Aug 2020 12:02:46 +0200
+
+linux (4.4.0-188.218) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-188.218 -proposed tracker (LP: #1890670)
+
+  * Xenial update: v4.4.232 upstream stable release (LP: #1889928)
+    - pinctrl: amd: fix npins for uart0 in kerncz_groups
+    - mac80211: allow rx of mesh eapol frames with default rx key
+    - scsi: scsi_transport_spi: Fix function pointer check
+    - xtensa: fix __sync_fetch_and_{and,or}_4 declarations
+    - xtensa: update *pos in cpuinfo_op.next
+    - drivers/net/wan/lapbether: Fixed the value of hard_header_len
+    - net: sky2: initialize return of gm_phy_read
+    - drm/nouveau/i2c/g94-: increase NV_PMGR_DP_AUXCTL_TRANSACTREQ timeout
+    - SUNRPC reverting d03727b248d0 ("NFSv4 fix CLOSE not waiting for direct IO
+      compeletion")
+    - perf/core: Fix locking for children siblings group read
+    - uprobes: Change handle_swbp() to send SIGTRAP with si_code=SI_KERNEL, to fix
+      GDB regression
+    - ALSA: info: Drop WARN_ON() from buffer NULL sanity check
+    - ASoC: rt5670: Correct RT5670_LDO_SEL_MASK
+    - btrfs: fix double free on ulist after backref resolution failure
+    - x86/fpu: Disable bottom halves while loading FPU registers
+    - btrfs: fix mount failure caused by race with umount
+    - hippi: Fix a size used in a 'pci_free_consistent()' in an error handling
+      path
+    - ax88172a: fix ax88172a_unbind() failures
+    - net: dp83640: fix SIOCSHWTSTAMP to update the struct with actual
+      configuration
+    - net: smc91x: Fix possible memory leak in smc_drv_probe()
+    - scripts/decode_stacktrace: strip basepath from all paths
+    - regmap: dev_get_regmap_match(): fix string comparison
+    - usb: gadget: udc: gr_udc: fix memleak on error handling path in gr_ep_init()
+    - arm64: Use test_tsk_thread_flag() for checking TIF_SINGLESTEP
+    - x86: math-emu: Fix up 'cmp' insn for clang ias
+    - Revert "cifs: Fix the target file was deleted when rename failed."
+    - staging: wlan-ng: properly check endpoint types
+    - staging: comedi: addi_apci_1032: check INSN_CONFIG_DIGITAL_TRIG shift
+    - staging: comedi: ni_6527: fix INSN_CONFIG_DIGITAL_TRIG support
+    - staging: comedi: addi_apci_1500: check INSN_CONFIG_DIGITAL_TRIG shift
+    - staging: comedi: addi_apci_1564: check INSN_CONFIG_DIGITAL_TRIG shift
+    - serial: 8250: fix null-ptr-deref in serial8250_start_tx()
+    - serial: 8250_mtk: Fix high-speed baud rates clamping
+    - mm/memcg: fix refcount error while moving and swapping
+    - parisc: Add atomic64_set_release() define to avoid CPU soft lockups
+    - ath9k: Fix general protection fault in ath9k_hif_usb_rx_cb
+    - ath9k: Fix regression with Atheros 9271
+    - AX.25: Fix out-of-bounds read in ax25_connect()
+    - AX.25: Prevent out-of-bounds read in ax25_sendmsg()
+    - net-sysfs: add a newline when printing 'tx_timeout' by sysfs
+    - net: udp: Fix wrong clean up for IS_UDPLITE macro
+    - AX.25: Prevent integer overflows in connect and sendmsg
+    - tcp: allow at most one TLP probe per flight
+    - rxrpc: Fix sendmsg() returning EPIPE due to recvmsg() returning ENODATA
+    - ip6_gre: fix null-ptr-deref in ip6gre_init_net()
+    - drivers/net/wan/x25_asy: Fix to make it work
+    - Makefile: Fix GCC_TOOLCHAIN_DIR prefix for Clang cross compilation
+    - regmap: debugfs: check count when read regmap file
+    - xfs: set format back to extents if xfs_bmap_extents_to_btree
+    - tools/lib/subcmd/pager.c: do not alias select() params
+    - perf: Make perf able to build with latest libbfd
+    - perf tools: Fix snprint warnings for gcc 8
+    - perf annotate: Use asprintf when formatting objdump command line
+    - perf probe: Fix to check blacklist address correctly
+    - Linux 4.4.232
+
+  * Xenial update: v4.4.231 upstream stable release (LP: #1888690)
+    - KVM: s390: reduce number of IO pins to 1
+    - spi: spidev: fix a race between spidev_release and spidev_remove
+    - spi: spidev: fix a potential use-after-free in spidev_release()
+    - scsi: mptscsih: Fix read sense data size
+    - net: cxgb4: fix return error value in t4_prep_fw
+    - smsc95xx: check return value of smsc95xx_reset
+    - smsc95xx: avoid memory leak in smsc95xx_bind
+    - ALSA: compress: fix partial_drain completion state
+    - arm64: kgdb: Fix single-step exception handling oops
+    - ALSA: opl3: fix infoleak in opl3
+    - ALSA: hda - let hs_mic be picked ahead of hp_mic
+    - ALSA: usb-audio: add quirk for MacroSilicon MS2109
+    - KVM: x86: bit 8 of non-leaf PDPEs is not reserved
+    - Revert "ath9k: Fix general protection fault in ath9k_hif_usb_rx_cb"
+    - btrfs: fix fatal extent_buffer readahead vs releasepage race
+    - drm/radeon: fix double free
+    - ARC: entry: fix potential EFA clobber when TIF_SYSCALL_TRACE
+    - ARC: elf: use right ELF_ARCH
+    - bnxt_en: fix NULL dereference in case SR-IOV configuration fails
+    - ipv4: fill fl4_icmp_{type,code} in ping_v4_sendmsg
+    - l2tp: remove skb_dst_set() from l2tp_xmit_skb()
+    - llc: make sure applications use ARPHRD_ETHER
+    - net: Added pointer check for dst->ops->neigh_lookup in dst_neigh_lookup_skb
+    - genetlink: remove genl_bind
+    - tcp: make sure listeners don't initialize congestion-control state
+    - tcp: md5: add missing memory barriers in tcp_md5_do_add()/tcp_md5_hash_key()
+    - tcp: md5: refine tcp_md5_do_add()/tcp_md5_hash_key() barriers
+    - tcp: md5: allow changing MD5 keys in all socket states
+    - i2c: eg20t: Load module automatically if ID matches
+    - Revert "usb/ehci-platform: Set PM runtime as active on resume"
+    - Revert "usb/xhci-plat: Set PM runtime as active on resume"
+    - Revert "usb/ohci-platform: Fix a warning when hibernating"
+    - usb: gadget: udc: atmel: fix uninitialized read in debug printk
+    - staging: comedi: verify array index is correct before using it
+    - perf stat: Zero all the 'ena' and 'run' array slot stats for interval mode
+    - mtd: rawnand: brcmnand: fix CS0 layout
+    - HID: magicmouse: do not set up autorepeat
+    - usb: core: Add a helper function to check the validity of EP type in URB
+    - ALSA: line6: Perform sanity check for each URB creation
+    - ALSA: usb-audio: Fix race against the error recovery URB submission
+    - USB: c67x00: fix use after free in c67x00_giveback_urb
+    - usb: chipidea: core: add wakeup support for extcon
+    - usb: gadget: function: fix missing spinlock in f_uac1_legacy
+    - USB: serial: iuu_phoenix: fix memory corruption
+    - USB: serial: cypress_m8: enable Simply Automated UPB PIM
+    - USB: serial: ch341: add new Product ID for CH340
+    - USB: serial: option: add GosunCn GM500 series
+    - USB: serial: option: add Quectel EG95 LTE modem
+    - virtio: virtio_console: add missing MODULE_DEVICE_TABLE() for rproc serial
+    - fuse: Fix parameter for FS_IOC_{GET,SET}FLAGS
+    - mei: bus: don't clean driver pointer
+    - Input: i8042 - add Lenovo XiaoXin Air 12 to i8042 nomux list
+    - uio_pdrv_genirq: fix use without device tree and no interrupt
+    - MIPS: Fix build for LTS kernel caused by backporting lpj adjustment
+    - hwmon: (emc2103) fix unable to change fan pwm1_enable attribute
+    - dmaengine: fsl-edma: Fix NULL pointer exception in fsl_edma_tx_handler
+    - misc: atmel-ssc: lock with mutex instead of spinlock
+    - sched/fair: handle case of task_h_load() returning 0
+    - Linux 4.4.231
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sun, 09 Aug 2020 01:05:44 -0400
+
+linux (4.4.0-187.217) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-187.217 -proposed tracker (LP: #1888274)
+
+  * Regression in kernel 4.15.0-91 causes kernel panic with Bcache
+    (LP: #1867916)
+    - bcache: check and adjust logical block size for backing devices
+
+  * Xenial update: v4.4.230 upstream stable release (LP: #1887011)
+    - btrfs: cow_file_range() num_bytes and disk_num_bytes are same
+    - btrfs: fix data block group relocation failure due to concurrent scrub
+    - mm: fix swap cache node allocation mask
+    - EDAC/amd64: Read back the scrub rate PCI register on F15h
+    - mm/slub: fix stack overruns with SLUB_STATS
+    - usb: usbtest: fix missing kfree(dev->buf) in usbtest_disconnect
+    - kgdb: Avoid suspicious RCU usage warning
+    - crypto: af_alg - fix use-after-free in af_alg_accept() due to bh_lock_sock()
+    - sched/rt: Show the 'sched_rr_timeslice' SCHED_RR timeslice tuning knob in
+      milliseconds
+    - hwmon: (max6697) Make sure the OVERT mask is set correctly
+    - hwmon: (acpi_power_meter) Fix potential memory leak in
+      acpi_power_meter_add()
+    - virtio-blk: free vblk-vqs in error path of virtblk_probe()
+    - i2c: algo-pca: Add 0x78 as SCL stuck low status for PCA9665
+    - Revert "ALSA: usb-audio: Improve frames size computation"
+    - SMB3: Honor 'seal' flag for multiuser mounts
+    - SMB3: Honor persistent/resilient handle flags for multiuser mounts
+    - cifs: Fix the target file was deleted when rename failed.
+    - MIPS: Add missing EHB in mtc0 -> mfc0 sequence for DSPen
+    - netfilter: nf_conntrack_h323: lost .data_len definition for Q.931/ipv6
+    - Linux 4.4.230
+
+  * Xenial update: v4.4.229 upstream stable release (LP: #1885932)
+    - s390: fix syscall_get_error for compat processes
+    - clk: sunxi: Fix incorrect usage of round_down()
+    - i2c: piix4: Detect secondary SMBus controller on AMD AM4 chipsets
+    - clk: qcom: msm8916: Fix the address location of pll->config_reg
+    - ALSA: isa/wavefront: prevent out of bounds write in ioctl
+    - scsi: qla2xxx: Fix issue with adapter's stopping state
+    - i2c: pxa: clear all master action bits in i2c_pxa_stop_message()
+    - usblp: poison URBs upon disconnect
+    - ps3disk: use the default segment boundary
+    - vfio/pci: fix memory leaks in alloc_perm_bits()
+    - mfd: wm8994: Fix driver operation if loaded as modules
+    - scsi: lpfc: Fix lpfc_nodelist leak when processing unsolicited event
+    - nfsd: Fix svc_xprt refcnt leak when setup callback client failed
+    - powerpc/crashkernel: Take "mem=" option into account
+    - yam: fix possible memory leak in yam_init_driver
+    - mksysmap: Fix the mismatch of '.L' symbols in System.map
+    - scsi: sr: Fix sr_probe() missing deallocate of device minor
+    - scsi: ibmvscsi: Don't send host info in adapter info MAD after LPM
+    - ALSA: usb-audio: Improve frames size computation
+    - s390/qdio: put thinint indicator after early error
+    - tty: hvc: Fix data abort due to race in hvc_open
+    - staging: sm750fb: add missing case while setting FB_VISUAL
+    - i2c: pxa: fix i2c_pxa_scream_blue_murder() debug output
+    - serial: amba-pl011: Make sure we initialize the port.lock spinlock
+    - drivers: base: Fix NULL pointer exception in __platform_driver_probe() if a
+      driver developer is foolish
+    - PCI/ASPM: Allow ASPM on links to PCIe-to-PCI/PCI-X Bridges
+    - power: supply: smb347-charger: IRQSTAT_D is volatile
+    - scsi: mpt3sas: Fix double free warnings
+    - dlm: remove BUG() before panic()
+    - clk: ti: composite: fix memory leak
+    - tty: n_gsm: Fix SOF skipping
+    - tty: n_gsm: Fix waking up upper tty layer when room available
+    - powerpc/pseries/ras: Fix FWNMI_VALID off by one
+    - powerpc/ps3: Fix kexec shutdown hang
+    - vfio-pci: Mask cap zero
+    - usb/ohci-platform: Fix a warning when hibernating
+    - USB: host: ehci-mxc: Add error handling in ehci_mxc_drv_probe()
+    - tty: n_gsm: Fix bogus i++ in gsm_data_kick
+    - clk: samsung: exynos5433: Add IGNORE_UNUSED flag to sclk_i2s1
+    - watchdog: da9062: No need to ping manually before setting timeout
+    - usb: dwc2: gadget: move gadget resume after the core is in L0 state
+    - USB: gadget: udc: s3c2410_udc: Remove pointless NULL check in
+      s3c2410_udc_nuke
+    - usb: gadget: lpc32xx_udc: don't dereference ep pointer before null check
+    - usb: gadget: fix potential double-free in m66592_probe.
+    - net: sunrpc: Fix off-by-one issues in 'rpc_ntop6'
+    - ASoC: fsl_asrc_dma: Fix dma_chan leak when config DMA channel failed
+    - openrisc: Fix issue with argument clobbering for clone/fork
+    - gfs2: Allow lock_nolock mount to specify jid=X
+    - scsi: iscsi: Fix reference count leak in iscsi_boot_create_kobj
+    - lib/zlib: remove outdated and incorrect pre-increment optimization
+    - include/linux/bitops.h: avoid clang shift-count-overflow warnings
+    - elfnote: mark all .note sections SHF_ALLOC
+    - selftests/net: in timestamping, strncpy needs to preserve null byte
+    - scsi: acornscsi: Fix an error handling path in acornscsi_probe()
+    - usb/xhci-plat: Set PM runtime as active on resume
+    - usb/ehci-platform: Set PM runtime as active on resume
+    - perf report: Fix NULL pointer dereference in
+      hists__fprintf_nr_sample_events()
+    - bcache: fix potential deadlock problem in btree_gc_coalesce
+    - block: Fix use-after-free in blkdev_get()
+    - drm: encoder_slave: fix refcouting error for modules
+    - drm/dp_mst: Reformat drm_dp_check_act_status() a bit
+    - drm/qxl: Use correct notify port address when creating cursor ring
+    - selinux: fix double free
+    - ext4: fix partial cluster initialization when splitting extent
+    - drm/dp_mst: Increase ACT retry timeout to 3s
+    - sparc64: fix misuses of access_process_vm() in genregs32_[sg]et()
+    - block: nr_sects_write(): Disable preemption on seqcount write
+    - crypto: algboss - don't wait during notifier callback
+    - kprobes: Fix to protect kick_kprobe_optimizer() by kprobe_mutex
+    - powerpc/kprobes: Fixes for kprobe_lookup_name() on BE
+    - x86/kprobes: Avoid kretprobe recursion bug
+    - kretprobe: Prevent triggering kretprobe from within kprobe_flush_task
+    - e1000e: Do not wake up the system via WOL if device wakeup is disabled
+    - sched/rt, net: Use CONFIG_PREEMPTION.patch
+    - net: core: device_rename: Use rwsem instead of a seqcount
+    - net: Revert "pkt_sched: fq: use proper locking in fq_dump_stats()"
+    - scsi: scsi_devinfo: handle non-terminated strings
+    - l2tp: Allow duplicate session creation with UDP
+    - net: sched: export __netdev_watchdog_up()
+    - fix a braino in "sparc32: fix register window handling in
+      genregs32_[gs]et()"
+    - net: fix memleak in register_netdevice()
+    - net: usb: ax88179_178a: fix packet alignment padding
+    - tg3: driver sleeps indefinitely when EEH errors exceed eeh_max_freezes
+    - ip_tunnel: fix use-after-free in ip_tunnel_lookup()
+    - tcp_cubic: fix spurious HYSTART_DELAY exit upon drop in min RTT
+    - ip6_gre: fix use-after-free in ip6gre_tunnel_lookup()
+    - tcp: grow window for OOO packets only for SACK flows
+    - sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
+    - net: Fix the arp error in some cases
+    - net: Do not clear the sock TX queue in sk_set_socket()
+    - net: core: reduce recursion limit value
+    - mld: fix memory leak in ipv6_mc_destroy_dev()
+    - USB: ohci-sm501: Add missed iounmap() in remove
+    - usb: dwc2: Postponed gadget registration to the udc class driver
+    - usb: add USB_QUIRK_DELAY_INIT for Logitech C922
+    - PCI: Disable MSI for HiSilicon Hip06/Hip07 Root Ports
+    - USB: ehci: reopen solution for Synopsys HC bug
+    - usb: host: ehci-exynos: Fix error check in exynos_ehci_probe()
+    - ALSA: usb-audio: add quirk for Denon DCD-1500RE
+    - xhci: Fix incorrect EP_STATE_MASK
+    - xhci: Fix enumeration issue when setting max packet size for FS devices.
+    - cdc-acm: Add DISABLE_ECHO quirk for Microchip/SMSC chip
+    - ALSA: usb-audio: uac1: Invalidate ctl on interrupt
+    - ALSA: usb-audio: allow clock source validity interrupts
+    - ALSA: usb-audio: Clean up mixer element list traverse
+    - ALSA: usb-audio: Fix OOB access of mixer element list
+    - xhci: Poll for U0 after disabling USB2 LPM
+    - cifs/smb3: Fix data inconsistent when punch hole
+    - cifs/smb3: Fix data inconsistent when zero file range
+    - efi/esrt: Fix reference count leak in esre_create_sysfs_entry.
+    - RDMA/mad: Fix possible memory leak in ib_mad_post_receive_mads()
+    - ARM: imx5: add missing put_device() call in imx_suspend_alloc_ocram()
+    - usb: gadget: udc: Potential Oops in error handling code
+    - netfilter: ipset: fix unaligned atomic access
+    - sched/core: Fix PI boosting between RT and DEADLINE tasks
+    - net: alx: fix race condition in alx_remove
+    - kbuild: improve cc-option to clean up all temporary files
+    - blktrace: break out of blktrace setup on concurrent calls
+    - ACPI: sysfs: Fix pm_profile_attr type
+    - KVM: X86: Fix MSR range of APIC registers in X2APIC mode
+    - mm/slab: use memzero_explicit() in kzfree()
+    - ocfs2: load global_inode_alloc
+    - ocfs2: fix value of OCFS2_INVALID_SLOT
+    - ocfs2: fix panic on nfs server over ocfs2
+    - arm64: perf: Report the PC value in REGS_ABI_32 mode
+    - tracing: Fix event trigger to accept redundant spaces
+    - drm/radeon: fix fb_div check in ni_init_smc_spll_table()
+    - sunrpc: fixed rollback in rpc_gssd_dummy_populate()
+    - SUNRPC: Properly set the @subbuf parameter of xdr_buf_subsegment()
+    - pNFS/flexfiles: Fix list corruption if the mirror count changes
+    - NFSv4 fix CLOSE not waiting for direct IO compeletion
+    - PCI: Disable MSI for HiSilicon Hip06/Hip07 only in Root Port mode
+    - ALSA: usb-audio: Fix invalid NULL check in snd_emuusb_set_samplerate()
+    - Linux 4.4.229
+
+  * Computer is frozen after suspend (LP: #1867983) // Xenial update: v4.4.229
+    upstream stable release (LP: #1885932)
+    - libata: Use per port sync for detach
+
+ -- Ian May <ian.may@canonical.com>  Mon, 20 Jul 2020 14:24:05 -0500
+
+linux (4.4.0-186.216) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-186.216 -proposed tracker (LP: #1885514)
+
+  * Xenial update: v4.4.228 upstream stable release (LP: #1884564)
+    - ipv6: fix IPV6_ADDRFORM operation logic
+    - vxlan: Avoid infinite loop when suppressing NS messages with invalid options
+    - scsi: return correct blkprep status code in case scsi_init_io() fails.
+    - net: phy: marvell: Limit 88m1101 autoneg errata to 88E1145 as well.
+    - pwm: fsl-ftm: Use flat regmap cache
+    - ARM: 8977/1: ptrace: Fix mask for thumb breakpoint hook
+    - sched/fair: Don't NUMA balance for kthreads
+    - ath9k_htc: Silence undersized packet warnings
+    - x86_64: Fix jiffies ODR violation
+    - x86/speculation: Prevent rogue cross-process SSBD shutdown
+    - x86/reboot/quirks: Add MacBook6,1 reboot quirk
+    - efi/efivars: Add missing kobject_put() in sysfs entry creation error path
+    - ALSA: es1688: Add the missed snd_card_free()
+    - ALSA: usb-audio: Fix inconsistent card PM state after resume
+    - ACPI: sysfs: Fix reference count leak in acpi_sysfs_add_hotplug_profile()
+    - ACPI: PM: Avoid using power resources if there are none for D0
+    - cgroup, blkcg: Prepare some symbols for module and !CONFIG_CGROUP usages
+    - nilfs2: fix null pointer dereference at nilfs_segctor_do_construct()
+    - spi: bcm2835aux: Fix controller unregister order
+    - ALSA: pcm: disallow linking stream to itself
+    - x86/speculation: Change misspelled STIPB to STIBP
+    - x86/speculation: Add support for STIBP always-on preferred mode
+    - x86/speculation: Avoid force-disabling IBPB based on STIBP and enhanced
+      IBRS.
+    - x86/speculation: PR_SPEC_FORCE_DISABLE enforcement for indirect branches.
+    - spi: dw: fix possible race condition
+    - spi: dw: Fix controller unregister order
+    - spi: No need to assign dummy value in spi_unregister_controller()
+    - spi: Fix controller unregister order
+    - spi: pxa2xx: Fix controller unregister order
+    - spi: bcm2835: Fix controller unregister order
+    - ovl: initialize error in ovl_copy_xattr
+    - proc: Use new_inode not new_inode_pseudo
+    - video: fbdev: w100fb: Fix a potential double free.
+    - KVM: nSVM: leave ASID aside in copy_vmcb_control_area
+    - KVM: nVMX: Consult only the "basic" exit reason when routing nested exit
+    - KVM: arm64: Make vcpu_cp1x() work on Big Endian hosts
+    - ath9k: Fix use-after-free Read in ath9k_wmi_ctrl_rx
+    - ath9k: Fix use-after-free Write in ath9k_htc_rx_msg
+    - ath9x: Fix stack-out-of-bounds Write in ath9k_hif_usb_rx_cb
+    - ath9k: Fix general protection fault in ath9k_hif_usb_rx_cb
+    - Smack: slab-out-of-bounds in vsscanf
+    - mm/slub: fix a memory leak in sysfs_slab_add()
+    - fat: don't allow to mount if the FAT length == 0
+    - can: kvaser_usb: kvaser_usb_leaf: Fix some info-leaks to USB devices
+    - spi: dw: Zero DMA Tx and Rx configurations on stack
+    - Bluetooth: Add SCO fallback for invalid LMP parameters error
+    - kgdb: Prevent infinite recursive entries to the debugger
+    - spi: dw: Enable interrupts in accordance with DMA xfer mode
+    - clocksource: dw_apb_timer_of: Fix missing clockevent timers
+    - btrfs: do not ignore error from btrfs_next_leaf() when inserting checksums
+    - ARM: 8978/1: mm: make act_mm() respect THREAD_SIZE
+    - net: vmxnet3: fix possible buffer overflow caused by bad DMA value in
+      vmxnet3_get_rss()
+    - staging: android: ion: use vmap instead of vm_map_ram
+    - e1000: Distribute switch variables for initialization
+    - media: dvb: return -EREMOTEIO on i2c transfer failure.
+    - MIPS: Make sparse_init() using top-down allocation
+    - netfilter: nft_nat: return EOPNOTSUPP if type or flags are not supported
+    - lib/mpi: Fix 64-bit MIPS build with Clang
+    - net: lpc-enet: fix error return code in lpc_mii_init()
+    - net: allwinner: Fix use correct return type for ndo_start_xmit()
+    - powerpc/spufs: fix copy_to_user while atomic
+    - mips: cm: Fix an invalid error code of INTVN_*_ERR
+    - kgdb: Fix spurious true from in_dbg_master()
+    - md: don't flush workqueue unconditionally in md_open
+    - mwifiex: Fix memory corruption in dump_station
+    - mips: Add udelay lpj numbers adjustment
+    - x86/mm: Stop printing BRK addresses
+    - m68k: mac: Don't call via_flush_cache() on Mac IIfx
+    - macvlan: Skip loopback packets in RX handler
+    - PCI: Don't disable decoding when mmio_always_on is set
+    - MIPS: Fix IRQ tracing when call handle_fpe() and handle_msa_fpe()
+    - ixgbe: fix signed-integer-overflow warning
+    - spi: dw: Return any value retrieved from the dma_transfer callback
+    - cpuidle: Fix three reference count leaks
+    - ima: Fix ima digest hash table key calculation
+    - ext4: fix EXT_MAX_EXTENT/INDEX to check for zeroed eh_max
+    - Btrfs: fix unreplayable log after snapshot delete + parent dir fsync
+    - btrfs: send: emit file capabilities after chown
+    - btrfs: fix error handling when submitting direct I/O bio
+    - ima: Directly assign the ima_default_policy pointer to ima_rules
+    - PCI: Program MPS for RCiEP devices
+    - e1000e: Relax condition to trigger reset for ME workaround
+    - carl9170: remove P2P_GO support
+    - media: go7007: fix a miss of snd_card_free
+    - b43legacy: Fix case where channel status is corrupted
+    - b43: Fix connection problem with WPA3
+    - b43_legacy: Fix connection problem with WPA3
+    - igb: Report speed and duplex as unknown when device is runtime suspended
+    - power: vexpress: add suppress_bind_attrs to true
+    - pinctrl: samsung: Save/restore eint_mask over suspend for EINT_TYPE GPIOs
+    - sparc32: fix register window handling in genregs32_[gs]et()
+    - kernel/cpu_pm: Fix uninitted local in cpu_pm
+    - ARM: tegra: Correct PL310 Auxiliary Control Register initialization
+    - drivers/macintosh: Fix memleak in windfarm_pm112 driver
+    - kbuild: force to build vmlinux if CONFIG_MODVERSION=y
+    - sunrpc: svcauth_gss_register_pseudoflavor must reject duplicate
+      registrations.
+    - sunrpc: clean up properly in gss_mech_unregister()
+    - w1: omap-hdq: cleanup to add missing newline for some dev_dbg
+    - perf probe: Do not show the skipped events
+    - perf symbols: Fix debuginfo search for Ubuntu
+    - Linux 4.4.228
+
+  * Update lockdown patches (LP: #1884159)
+    - acpi: Disable ACPI table override if the kernel is locked down
+    - SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the testmmiotrace module
+    - Revert "Restrict /dev/mem and /dev/kmem when module loading is restricted"
+    - Revert "x86: Lock down IO port access when module security is enabled"
+    - SAUCE: (efi-lockdown) Restrict /dev/{mem, kmem, port} when the kernel is
+      locked down
+    - Annotate module params that specify hardware parameters (eg. ioport)
+    - Annotate hardware config module parameters in arch/x86/mm/
+    - Annotate hardware config module parameters in drivers/char/ipmi/
+    - Annotate hardware config module parameters in drivers/char/mwave/
+    - Annotate hardware config module parameters in drivers/char/
+    - Annotate hardware config module parameters in drivers/clocksource/
+    - Annotate hardware config module parameters in drivers/cpufreq/
+    - Annotate hardware config module parameters in drivers/gpio/
+    - Annotate hardware config module parameters in drivers/i2c/
+    - Annotate hardware config module parameters in drivers/input/
+    - Annotate hardware config module parameters in drivers/isdn/
+    - Annotate hardware config module parameters in drivers/media/
+    - Annotate hardware config module parameters in drivers/misc/
+    - Annotate hardware config module parameters in drivers/mmc/host/
+    - Annotate hardware config module parameters in drivers/net/appletalk/
+    - Annotate hardware config module parameters in drivers/net/arcnet/
+    - Annotate hardware config module parameters in drivers/net/can/
+    - Annotate hardware config module parameters in drivers/net/ethernet/
+    - Annotate hardware config module parameters in drivers/net/hamradio/
+    - Annotate hardware config module parameters in drivers/net/irda/
+    - Annotate hardware config module parameters in drivers/net/wan/
+    - Annotate hardware config module parameters in drivers/net/wireless/
+    - Annotate hardware config module parameters in drivers/parport/
+    - Annotate hardware config module parameters in drivers/pci/hotplug/
+    - Annotate hardware config module parameters in drivers/pcmcia/
+    - Annotate hardware config module parameters in drivers/scsi/
+    - Annotate hardware config module parameters in drivers/staging/media/
+    - Annotate hardware config module parameters in drivers/staging/speakup/
+    - Annotate hardware config module parameters in drivers/staging/vme/
+    - Annotate hardware config module parameters in drivers/tty/
+    - Annotate hardware config module parameters in drivers/video/
+    - Annotate hardware config module parameters in drivers/watchdog/
+    - Annotate hardware config module parameters in fs/pstore/
+    - Annotate hardware config module parameters in sound/drivers/
+    - Annotate hardware config module parameters in sound/isa/
+    - Annotate hardware config module parameters in sound/oss/
+    - Annotate hardware config module parameters in sound/pci/
+    - SAUCE: (efi-lockdown) Lock down module params that specify hardware
+      parameters (eg. ioport)
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) kexec_file: Disable at runtime if the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - efi/efi_test: Lock down /dev/efi_test and require CAP_SYS_ADMIN
+    - debugfs: prevent access to possibly dead file_operations at file open
+    - debugfs: prevent access to removed files' private data
+    - debugfs: add support for self-protecting attribute file fops
+    - debugfs: unproxify integer attribute files
+    - debugfs: unproxify files created through debugfs_create_bool()
+    - debugfs: unproxify files created through debugfs_create_blob()
+    - debugfs: unproxify files created through debugfs_create_u32_array()
+    - debugfs: full_proxy_open(): free proxy on ->open() failure
+    - debugfs: open_proxy_open(): avoid double fops release
+    - SAUCE: (efi-lockdown) debugfs: Disallow use of debugfs files when the kernel
+      is locked down
+
+  * Xenial update: v4.4.227 upstream stable release (LP: #1883918)
+    - scsi: scsi_devinfo: fixup string compare
+    - usb: gadget: f_uac2: fix error handling in afunc_bind (again)
+    - platform/x86: acer-wmi: setup accelerometer when ACPI device was found
+    - esp6: fix memleak on error path in esp6_input
+    - IB/mlx4: Fix an error handling path in 'mlx4_ib_rereg_user_mr()'
+    - ALSA: hda - No loopback on ALC299 codec
+    - spi: dw: use "smp_mb()" to avoid sending spi data error
+    - s390/ftrace: save traced function caller
+    - ARC: Fix ICCM & DCCM runtime size checks
+    - x86/mmiotrace: Use cpumask_available() for cpumask_var_t variables
+    - net: bmac: Fix read of MAC address from ROM
+    - net/ethernet/freescale: rework quiesce/activate for ucc_geth
+    - net: ethernet: stmmac: Enable interface clocks on probe for IPQ806x
+    - pppoe: only process PADT targeted at local interfaces
+    - mmc: fix compilation of user API
+    - slcan: Fix double-free on slcan_open() error path
+    - slip: not call free_netdev before rtnl_unlock in slip_open
+    - scsi: ufs: Release clock if DMA map fails
+    - devinet: fix memleak in inetdev_init()
+    - NFC: st21nfca: add missed kfree_skb() in an error path
+    - vsock: fix timeout in vsock_accept()
+    - l2tp: add sk_family checks to l2tp_validate_socket
+    - l2tp: do not use inet_hash()/inet_unhash()
+    - USB: serial: qcserial: add DW5816e QDL support
+    - USB: serial: usb_wwan: do not resubmit rx urb on fatal errors
+    - USB: serial: option: add Telit LE910C1-EUX compositions
+    - vt: keyboard: avoid signed integer overflow in k_ascii
+    - staging: rtl8712: Fix IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK
+    - x86/cpu: Rename cpu_data.x86_mask to cpu_data.x86_stepping
+    - x86/speculation: Add SRBDS vulnerability and mitigation documentation
+    - x86/speculation: Add Ivy Bridge to affected list
+    - iio: vcnl4000: Fix i2c swapped word reading.
+    - uprobes: ensure that uprobe->offset and ->ref_ctr_offset are properly
+      aligned
+    - Linux 4.4.227
+
+  * Xenial update: v4.4.226 upstream stable release (LP: #1883917)
+    - ax25: fix setsockopt(SO_BINDTODEVICE)
+    - net: revert "net: get rid of an signed integer overflow in
+      ip_idents_reserve()"
+    - sctp: Start shutdown on association restart if in SHUTDOWN-SENT state and
+      socket is closed
+    - net/mlx5: Add command entry handling completion
+    - net: sun: fix missing release regions in cas_init_one().
+    - net/mlx4_core: fix a memory leak bug.
+    - uapi: fix linux/if_pppol2tp.h userspace compilation errors
+    - IB/cma: Fix reference count leak when no ipv4 addresses are set
+    - cachefiles: Fix race between read_waiter and read_copier involving op->to_do
+    - usb: gadget: legacy: fix redundant initialization warnings
+    - cifs: Fix null pointer check in cifs_read
+    - Input: usbtouchscreen - add support for BonXeon TP
+    - Input: evdev - call input_flush_device() on release(), not flush()
+    - Input: xpad - add custom init packet for Xbox One S controllers
+    - Input: i8042 - add ThinkPad S230u to i8042 reset list
+    - IB/qib: Call kobject_put() when kobject_init_and_add() fails
+    - ALSA: hwdep: fix a left shifting 1 by 31 UB bug
+    - ALSA: usb-audio: mixer: volume quirk for ESS Technology Asus USB DAC
+    - exec: Always set cap_ambient in cap_bprm_set_creds
+    - fs/binfmt_elf.c: allocate initialized memory in fill_thread_core_info()
+    - include/asm-generic/topology.h: guard cpumask_of_node() macro argument
+    - iommu: Fix reference count leak in iommu_group_alloc.
+    - parisc: Fix kernel panic in mem_init()
+    - x86/dma: Fix max PFN arithmetic overflow on 32 bit systems
+    - xfrm: allow to accept packets with ipv6 NEXTHDR_HOP in xfrm_input
+    - xfrm: fix a warning in xfrm_policy_insert_list
+    - xfrm: fix a NULL-ptr deref in xfrm_local_error
+    - vti4: eliminated some duplicate code.
+    - ip_vti: receive ipip packet by calling ip_tunnel_rcv
+    - netfilter: nft_reject_bridge: enable reject with bridge vlan
+    - netfilter: ipset: Fix subcounter update skip
+    - netfilter: nf_conntrack_pptp: prevent buffer overflows in debug code
+    - qlcnic: fix missing release in qlcnic_83xx_interrupt_test.
+    - bonding: Fix reference count leak in bond_sysfs_slave_add.
+    - netfilter: nf_conntrack_pptp: fix compilation warning with W=1 build
+    - mm: remove VM_BUG_ON(PageSlab()) from page_mapcount()
+    - genirq/generic_pending: Do not lose pending affinity update
+    - usb: renesas_usbhs: gadget: fix spin_lock_init() for &uep->lock
+    - mac80211: fix memory leak
+    - net: rtnl_configure_link: fix dev flags changes arg to __dev_notify_flags
+    - mm/vmalloc.c: don't dereference possible NULL pointer in __vunmap()
+    - asm-prototypes: Clear any CPP defines before declaring the functions
+    - sc16is7xx: move label 'err_spi' to correct section
+    - drm/msm: Fix possible null dereference on failure of get_pages()
+    - printk: help pr_debug and pr_devel to optimize out arguments
+    - scsi: zfcp: fix request object use-after-free in send path causing wrong
+      traces
+    - Linux 4.4.226
+
+  * Xenial update: v4.4.225 upstream stable release (LP: #1883916)
+    - igb: use igb_adapter->io_addr instead of e1000_hw->hw_addr
+    - padata: Remove unused but set variables
+    - padata: get_next is never NULL
+    - padata: ensure the reorder timer callback runs on the correct CPU
+    - padata: ensure padata_do_serial() runs on the correct CPU
+    - evm: Check also if *tfm is an error pointer in init_desc()
+    - fix multiplication overflow in copy_fdtable()
+    - HID: multitouch: add eGalaxTouch P80H84 support
+    - ceph: fix double unlock in handle_cap_export()
+    - USB: core: Fix misleading driver bug report
+    - platform/x86: asus-nb-wmi: Do not load on Asus T100TA and T200TA
+    - ARM: futex: Address build warning
+    - media: Fix media_open() to clear filp->private_data in error leg
+    - drivers/media/media-devnode: clear private_data before put_device()
+    - media-devnode: add missing mutex lock in error handler
+    - media-devnode: fix namespace mess
+    - media-device: dynamically allocate struct media_devnode
+    - media: fix use-after-free in cdev_put() when app exits after driver unbind
+    - media: fix media devnode ioctl/syscall and unregister race
+    - i2c: dev: switch from register_chrdev to cdev API
+    - i2c: dev: don't start function name with 'return'
+    - i2c: dev: use after free in detach
+    - i2c-dev: don't get i2c adapter via i2c_dev
+    - i2c: dev: Fix the race between the release of i2c_dev and cdev
+    - padata: set cpu_index of unused CPUs to -1
+    - sched/fair, cpumask: Export for_each_cpu_wrap()
+    - padata: Replace delayed timer with immediate workqueue in padata_reorder
+    - padata: initialize pd->cpu with effective cpumask
+    - padata: purge get_cpu and reorder_via_wq from padata_do_serial
+    - ALSA: pcm: fix incorrect hw_base increase
+    - platform/x86: alienware-wmi: fix kfree on potentially uninitialized pointer
+    - libnvdimm/btt: Remove unnecessary code in btt_freelist_init
+    - l2tp: lock socket before checking flags in connect()
+    - l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
+    - l2tp: hold session while sending creation notifications
+    - l2tp: take a reference on sessions used in genetlink handlers
+    - l2tp: don't use l2tp_tunnel_find() in l2tp_ip and l2tp_ip6
+    - net: l2tp: export debug flags to UAPI
+    - net: l2tp: deprecate PPPOL2TP_MSG_* in favour of L2TP_MSG_*
+    - net: l2tp: ppp: change PPPOL2TP_MSG_* => L2TP_MSG_*
+    - New kernel function to get IP overhead on a socket.
+    - L2TP:Adjust intf MTU, add underlay L3, L2 hdrs.
+    - l2tp: remove useless duplicate session detection in l2tp_netlink
+    - l2tp: remove l2tp_session_find()
+    - l2tp: define parameters of l2tp_session_get*() as "const"
+    - l2tp: define parameters of l2tp_tunnel_find*() as "const"
+    - l2tp: initialise session's refcount before making it reachable
+    - l2tp: hold tunnel while looking up sessions in l2tp_netlink
+    - l2tp: hold tunnel while processing genl delete command
+    - l2tp: hold tunnel while handling genl tunnel updates
+    - l2tp: hold tunnel while handling genl TUNNEL_GET commands
+    - l2tp: hold tunnel used while creating sessions with netlink
+    - l2tp: prevent creation of sessions on terminated tunnels
+    - l2tp: fix l2tp_eth module loading
+    - l2tp: don't register sessions in l2tp_session_create()
+    - l2tp: initialise l2tp_eth sessions before registering them
+    - l2tp: protect sock pointer of struct pppol2tp_session with RCU
+    - l2tp: initialise PPP sessions before registering them
+    - Revert "gfs2: Don't demote a glock until its revokes are written"
+    - staging: iio: ad2s1210: Fix SPI reading
+    - mei: release me_cl object reference
+    - iio: sca3000: Remove an erroneous 'get_device()'
+    - l2tp: device MTU setup, tunnel socket needs a lock
+    - cpumask: Make for_each_cpu_wrap() available on UP as well
+    - Linux 4.4.225
+
+  * smpboot: don't call topology_sane() when Sub-NUMA-Clustering is enabled
+    (LP: #1882478)
+    - x86, sched: Allow topologies where NUMA nodes share an LLC
+
+  * CVE-2020-11935
+    - SAUCE: aufs: do not call i_readcount_inc()
+    - SAUCE: aufs: bugfix, IMA i_readcount
+
+  * CVE-2019-12380
+    - efi/x86/Add missing error handling to old_memmap 1:1 mapping code
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 01 Jul 2020 00:39:42 -0400
+
+linux (4.4.0-185.215) xenial; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * CVE-2020-0543
+    - UBUNTU/SAUCE: x86/speculation/srbds: do not try to turn mitigation off when
+      not supported
+
+  * Xenial update: 4.4.224 upstream stable release (LP: #1881356)
+    - USB: serial: qcserial: Add DW5816e support
+    - Revert "net: phy: Avoid polling PHY with PHY_IGNORE_INTERRUPTS"
+    - dp83640: reverse arguments to list_add_tail
+    - net/mlx4_core: Fix use of ENOSPC around mlx4_counter_alloc()
+    - sch_sfq: validate silly quantum values
+    - sch_choke: avoid potential panic in choke_reset()
+    - enic: do not overwrite error code
+    - ipv6: fix cleanup ordering for ip6_mr failure
+    - binfmt_elf: move brk out of mmap when doing direct loader exec
+    - x86/apm: Don't access __preempt_count with zeroed fs
+    - Revert "IB/ipoib: Update broadcast object if PKey value was changed in index
+      0"
+    - USB: uas: add quirk for LaCie 2Big Quadra
+    - USB: serial: garmin_gps: add sanity checking for data length
+    - batman-adv: fix batadv_nc_random_weight_tq
+    - scripts/decodecode: fix trapping instruction formatting
+    - phy: micrel: Ensure interrupts are reenabled on resume
+    - binfmt_elf: Do not move brk for INTERP-less ET_EXEC
+    - ext4: add cond_resched() to ext4_protect_reserved_inode
+    - blktrace: Fix potential deadlock between delete & sysfs ops
+    - blktrace: fix unlocked access to init/start-stop/teardown
+    - blktrace: fix trace mutex deadlock
+    - ptp: do not explicitly set drvdata in ptp_clock_register()
+    - ptp: use is_visible method to hide unused attributes
+    - ptp: create "pins" together with the rest of attributes
+    - chardev: add helper function to register char devs with a struct device
+    - ptp: Fix pass zero to ERR_PTR() in ptp_clock_register
+    - ptp: fix the race between the release of ptp_clock and cdev
+    - ptp: free ptp device pin descriptors properly
+    - net: handle no dst on skb in icmp6_send
+    - net/sonic: Fix a resource leak in an error handling path in
+      'jazz_sonic_probe()'
+    - net: moxa: Fix a potential double 'free_irq()'
+    - drop_monitor: work around gcc-10 stringop-overflow warning
+    - scsi: sg: add sg_remove_request in sg_write
+    - cifs: Check for timeout on Negotiate stage
+    - cifs: Fix a race condition with cifs_echo_request
+    - dmaengine: pch_dma.c: Avoid data race between probe and irq handler
+    - dmaengine: mmp_tdma: Reset channel error on release
+    - drm/qxl: lost qxl_bo_kunmap_atomic_page in qxl_image_init_helper()
+    - ipc/util.c: sysvipc_find_ipc() incorrectly updates position index
+    - net: openvswitch: fix csum updates for MPLS actions
+    - gre: do not keep the GRE header around in collect medata mode
+    - mm/memory_hotplug.c: fix overflow in test_pages_in_a_zone()
+    - scsi: qla2xxx: Avoid double completion of abort command
+    - i40e: avoid NVM acquire deadlock during NVM update
+    - net/mlx5: Fix driver load error flow when firmware is stuck
+    - netfilter: conntrack: avoid gcc-10 zero-length-bounds warning
+    - IB/mlx4: Test return value of calls to ib_get_cached_pkey
+    - pnp: Use list_for_each_entry() instead of open coding
+    - gcc-10 warnings: fix low-hanging fruit
+    - kbuild: compute false-positive -Wmaybe-uninitialized cases in Kconfig
+    - Stop the ad-hoc games with -Wno-maybe-initialized
+    - gcc-10: disable 'zero-length-bounds' warning for now
+    - gcc-10: disable 'array-bounds' warning for now
+    - gcc-10: disable 'stringop-overflow' warning for now
+    - gcc-10: disable 'restrict' warning for now
+    - blk-mq: sync the update nr_hw_queues with blk_mq_queue_tag_busy_iter
+    - blk-mq: Allow blocking queue tag iter callbacks
+    - x86/paravirt: Remove the unused irq_enable_sysexit pv op
+    - gcc-10: avoid shadowing standard library 'free()' in crypto
+    - net: fix a potential recursive NETDEV_FEAT_CHANGE
+    - net: ipv4: really enforce backoff for redirects
+    - ALSA: hda/realtek - Limit int mic boost for Thinkpad T530
+    - ALSA: rawmidi: Fix racy buffer resize under concurrent accesses
+    - ALSA: rawmidi: Initialize allocated buffers
+    - ARM: dts: imx27-phytec-phycard-s-rdk: Fix the I2C1 pinctrl entries
+    - x86: Fix early boot crash on gcc-10, third try
+    - exec: Move would_dump into flush_old_exec
+    - usb: gadget: net2272: Fix a memory leak in an error handling path in
+      'net2272_plat_probe()'
+    - usb: gadget: audio: Fix a missing error return value in audio_bind()
+    - usb: gadget: legacy: fix error return code in gncm_bind()
+    - usb: gadget: legacy: fix error return code in cdc_bind()
+    - ARM: dts: r8a7740: Add missing extal2 to CPG node
+    - KVM: x86: Fix off-by-one error in kvm_vcpu_ioctl_x86_setup_mce
+    - Makefile: disallow data races on gcc-10 as well
+    - scsi: iscsi: Fix a potential deadlock in the timeout handler
+    - Linux 4.4.224
+
+  * upgrading to 4.15.0-99-generic breaks the sound and the trackpad
+    (LP: #1875916) // Xenial update: 4.4.224 upstream stable release
+    (LP: #1881356)
+    - Revert "ALSA: hda/realtek: Fix pop noise on ALC225"
+
+  * CVE-2020-10711
+    - netlabel: cope with NULL catmap
+
+  * CVE-2020-13143
+    - USB: gadget: fix illegal array access in binding with UDC
+
+  * ext2 build failure on 4.4.0-180.210 (LP: #1880213)
+    - ext2: fix debug reference to ext2_xattr_cache
+
+  * test_bpf of ubuntu_kernel_selftests.net ADT test failure with linux
+    4.4.0-180.210 (LP: #1879752)
+    - bpf, test: fix ld_abs + vlan push/pop stress test
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Mon, 08 Jun 2020 14:45:12 -0300
+
+linux (4.4.0-184.214) xenial; urgency=medium
+
+  * CVE-2020-0543
+    - SAUCE: x86/cpu: Add a steppings field to struct x86_cpu_id
+    - SAUCE: x86/cpu: Add 'table' argument to cpu_matches()
+    - SAUCE: x86/speculation: Add Special Register Buffer Data Sampling (SRBDS)
+      mitigation
+    - SAUCE: x86/speculation: Add SRBDS vulnerability and mitigation documentation
+    - SAUCE: x86/speculation: Add Ivy Bridge to affected list
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 03 Jun 2020 12:51:31 +0200
+
+linux (4.4.0-181.211) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-181.211 -proposed tracker (LP: #1881170)
+
+  * CVE-2020-12769
+    - spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls
+
+  * I2C bus on Dell Edge Gateway stops working after upgrading to
+    Ubuntu-4.4.0-180.210 (LP: #1881124)
+    - SAUCE: Revert: Revert "ACPI / LPSS: allow to use specific PM domain during
+      ->probe()"
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Fri, 29 May 2020 02:56:23 -0400
+
+linux (4.4.0-180.210) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-180.210 -proposed tracker (LP: #1878873)
+
+  * Xenial update: 4.4.223 upstream stable release (LP: #1878232)
+    - mwifiex: fix PCIe register information for 8997 chipset
+    - drm/qxl: qxl_release use after free
+    - drm/qxl: qxl_release leak in qxl_draw_dirty_fb()
+    - staging: rtl8192u: Fix crash due to pointers being "confusing"
+    - usb: gadget: f_acm: Fix configfs attr name
+    - usb: gadged: pch_udc: get rid of redundant assignments
+    - usb: gadget: pch_udc: reorder spin_[un]lock to avoid deadlock
+    - usb: gadget: udc: core: don't starve DMA resources
+    - MIPS: Fix macro typo
+    - MIPS: ptrace: Drop cp0_tcstatus from regoffset_table[]
+    - MIPS: BMIPS: Fix PRID_IMP_BMIPS5000 masking for BMIPS5200
+    - MIPS: smp-cps: Stop printing EJTAG exceptions to UART
+    - MIPS: scall: Handle seccomp filters which redirect syscalls
+    - MIPS: BMIPS: BMIPS5000 has I cache filing from D cache
+    - MIPS: BMIPS: Clear MIPS_CACHE_ALIASES earlier
+    - MIPS: BMIPS: local_r4k___flush_cache_all needs to blast S-cache
+    - MIPS: BMIPS: Pretty print BMIPS5200 processor name
+    - MIPS: Fix HTW config on XPA kernel without LPA enabled
+    - MIPS: BMIPS: Adjust mips-hpt-frequency for BCM7435
+    - MIPS: math-emu: Fix BC1{EQ,NE}Z emulation
+    - MIPS: Fix BC1{EQ,NE}Z return offset calculation
+    - MIPS: perf: Fix I6400 event numbers
+    - MIPS: KVM: Fix translation of MFC0 ErrCtl
+    - MIPS: SMP: Update cpu_foreign_map on CPU disable
+    - MIPS: c-r4k: Fix protected_writeback_scache_line for EVA
+    - MIPS: Octeon: Off by one in octeon_irq_gpio_map()
+    - bpf, mips: fix off-by-one in ctx offset allocation
+    - MIPS: RM7000: Double locking bug in rm7k_tc_disable()
+    - MIPS: Define AT_VECTOR_SIZE_ARCH for ARCH_DLINFO
+    - mips/panic: replace smp_send_stop() with kdump friendly version in panic
+      path
+    - ARM: dts: armadillo800eva Correct extal1 frequency to 24 MHz
+    - ARM: imx: select SRC for i.MX7
+    - ARM: dts: kirkwood: gpio pin fixes for linkstation ls-wxl/wsxl
+    - ARM: dts: kirkwood: gpio pin fixes for linkstation ls-wvl/vl
+    - ARM: dts: kirkwood: gpio-leds fixes for linkstation ls-wxl/wsxl
+    - ARM: dts: kirkwood: gpio-leds fixes for linkstation ls-wvl/vl
+    - ARM: dts: orion5x: gpio pin fixes for linkstation lswtgl
+    - ARM: dts: orion5x: fix the missing mtd flash on linkstation lswtgl
+    - ARM: dts: kirkwood: use unique machine name for ds112
+    - ARM: dts: kirkwood: add kirkwood-ds112.dtb to Makefile
+    - ARM: OMAP2+: hwmod: fix _idle() hwmod state sanity check sequence
+    - perf/x86: Fix filter_events() bug with event mappings
+    - x86/LDT: Print the real LDT base address
+    - x86/apic/uv: Silence a shift wrapping warning
+    - ALSA: fm801: explicitly free IRQ line
+    - ALSA: fm801: propagate TUNER_ONLY bit when autodetected
+    - ALSA: fm801: detect FM-only card earlier
+    - netfilter: nfnetlink: use original skbuff when acking batches
+    - xfrm: fix crash in XFRM_MSG_GETSA netlink handler
+    - mwifiex: fix IBSS data path issue.
+    - mwifiex: add missing check for PCIe8997 chipset
+    - iwlwifi: set max firmware version of 7265 to 17
+    - Bluetooth: btmrvl: fix hung task warning dump
+    - dccp: limit sk_filter trim to payload
+    - net/mlx4_core: Do not BUG_ON during reset when PCI is offline
+    - mlxsw: pci: Correctly determine if descriptor queue is full
+    - PCI: Supply CPU physical address (not bus address) to iomem_is_exclusive()
+    - alpha/PCI: Call iomem_is_exclusive() for IORESOURCE_MEM, but not
+      IORESOURCE_IO
+    - vfio/pci: Allow VPD short read
+    - mlxsw: Treat local port 64 as valid
+    - IB/mlx4: Initialize hop_limit when creating address handle
+    - GRE: Disable segmentation offloads w/ CSUM and we are encapsulated via FOU
+    - powerpc/pci/of: Parse unassigned resources
+    - firmware: actually return NULL on failed request_firmware_nowait()
+    - c8sectpfe: Rework firmware loading mechanism
+    - net/mlx5: Avoid passing dma address 0 to firmware
+    - IB/mlx5: Fix RC transport send queue overhead computation
+    - net/mlx5: Make command timeout way shorter
+    - IB/mlx5: Fix FW version diaplay in sysfs
+    - net/mlx5e: Fix MLX5E_100BASE_T define
+    - net/mlx5: Fix the size of modify QP mailbox
+    - net/mlx5: Fix masking of reserved bits in XRCD number
+    - net/mlx5e: Fix blue flame quota logic
+    - net/mlx5: use mlx5_buf_alloc_node instead of mlx5_buf_alloc in
+      mlx5_wq_ll_create
+    - net/mlx5: Avoid calling sleeping function by the health poll thread
+    - net/mlx5: Fix wait_vital for VFs and remove fixed sleep
+    - net/mlx5: Fix potential deadlock in command mode change
+    - net/mlx5: Add timeout handle to commands with callback
+    - net/mlx5: Fix pci error recovery flow
+    - net/mlx5e: Copy all L2 headers into inline segment
+    - net_sched: keep backlog updated with qlen
+    - sch_drr: update backlog as well
+    - sch_hfsc: always keep backlog updated
+    - sch_prio: update backlog as well
+    - sch_qfq: keep backlog updated with qlen
+    - sch_sfb: keep backlog updated with qlen
+    - sch_tbf: update backlog as well
+    - btrfs: cleaner_kthread() doesn't need explicit freeze
+    - irda: Free skb on irda_accept error path.
+    - phy: fix device reference leaks
+    - bonding: prevent out of bound accesses
+    - mtd: nand: fix ONFI parameter page layout
+    - ath10k: free cached fw bin contents when get board id fails
+    - xprtrdma: checking for NULL instead of IS_ERR()
+    - xprtrdma: Fix additional uses of spin_lock_irqsave(rb_lock)
+    - xprtrdma: xprt_rdma_free() must not release backchannel reqs
+    - xprtrdma: rpcrdma_bc_receive_call() should init rq_private_buf.len
+    - RDMA/cxgb3: device driver frees DMA memory with different size
+    - mlxsw: spectrum: Don't forward packets when STP state is DISABLED
+    - mlxsw: spectrum: Disable learning according to STP state
+    - mlxsw: spectrum: Don't count internal TX header bytes to stats
+    - mlxsw: spectrum: Indicate support for autonegotiation
+    - mlxsw: spectrum: Fix misuse of hard_header_len
+    - net: tcp_memcontrol: properly detect ancestor socket pressure
+    - tcp: do not set rtt_min to 1
+    - RDS:TCP: Synchronize rds_tcp_accept_one with rds_send_xmit when resetting
+      t_sock
+    - net: ipv6: tcp reset, icmp need to consider L3 domain
+    - batman-adv: Fix lockdep annotation of batadv_tlv_container_remove
+    - batman-adv: replace WARN with rate limited output on non-existing VLAN
+    - tty: serial: msm: Support more bauds
+    - serial: samsung: Fix possible out of bounds access on non-DT platform
+    - isa: Call isa_bus_init before dependent ISA bus drivers register
+    - Btrfs: clean up an error code in btrfs_init_space_info()
+    - Input: gpio-keys - fix check for disabling unsupported keys
+    - Input: edt-ft5x06 - fix setting gain, offset, and threshold via device tree
+    - net/xfrm_input: fix possible NULL deref of tunnel.ip6->parms.i_key
+    - xfrm_user: propagate sec ctx allocation errors
+    - xfrm: Fix memory leak of aead algorithm name
+    - mac80211: fix mgmt-tx abort cookie and leak
+    - mac80211: TDLS: always downgrade invalid chandefs
+    - mac80211: TDLS: change BW calculation for WIDER_BW peers
+    - mac80211: Fix BW upgrade for TDLS peers
+    - NFS: Fix an LOCK/OPEN race when unlinking an open file
+    - net: get rid of an signed integer overflow in ip_idents_reserve()
+    - mtd: nand: denali: add missing nand_release() call in denali_remove()
+    - ASoC: Intel: pass correct parameter in sst_alloc_stream_mrfld()
+    - ASoC: tegra_alc5632: check return value
+    - ASoC: fsl_ssi: mark SACNT register volatile
+    - Revert "ACPI / LPSS: allow to use specific PM domain during ->probe()"
+    - mmc: sdhci: restore behavior when setting VDD via external regulator
+    - mmc: sd: limit SD card power limit according to cards capabilities
+    - mmc: debugfs: correct wrong voltage value
+    - mmc: block: return error on failed mmc_blk_get()
+    - clk: rockchip: Revert "clk: rockchip: reset init state before mmc card
+      initialization"
+    - mmc: dw_mmc: rockchip: Set the drive phase properly
+    - mmc: moxart: fix wait_for_completion_interruptible_timeout return variable
+      type
+    - mmc: sdhci: Fix regression setting power on Trats2 board
+    - perf tools: Fix perf regs mask generation
+    - powerpc/book3s: Fix MCE console messages for unrecoverable MCE.
+    - sctp: fix the transports round robin issue when init is retransmitted
+    - sunrpc: Update RPCBIND_MAXNETIDLEN
+    - NFC: nci: memory leak in nci_core_conn_create()
+    - net: phy: Avoid polling PHY with PHY_IGNORE_INTERRUPTS
+    - net: phy: Fix phy_mac_interrupt()
+    - net: phy: bcm7xxx: Fix shadow mode 2 disabling
+    - of_mdio: fix node leak in of_phy_register_fixed_link error path
+    - phy: micrel: Fix finding PHY properties in MAC node for KSZ9031.
+    - net: dsa: slave: fix of-node leak and phy priority
+    - drivers: net: cpsw: don't ignore phy-mode if phy-handle is used
+    - iommu/dma: Respect IOMMU aperture when allocating
+    - mdio-sun4i: oops in error handling in probe
+    - iio:ad7797: Use correct attribute_group
+    - selftests/ipc: Fix test failure seen after initial test run
+    - wimax/i2400m: Fix potential urb refcnt leak
+    - cifs: protect updating server->dstaddr with a spinlock
+    - scripts/config: allow colons in option strings for sed
+    - lib/mpi: Fix building for powerpc with clang
+    - net: bcmgenet: suppress warnings on failed Rx SKB allocations
+    - net: systemport: suppress warnings on failed Rx SKB allocations
+    - rc: allow rc modules to be loaded if rc-main is not a module
+    - lirc_imon: do not leave imon_probe() with mutex held
+    - am437x-vpfe: fix an uninitialized variable bug
+    - cx23885: uninitialized variable in cx23885_av_work_handler()
+    - ath9k_htc: check for underflow in ath9k_htc_rx_msg()
+    - VFIO: platform: reset: fix a warning message condition
+    - net: moxa: fix an error code
+    - mfd: lp8788-irq: Uninitialized variable in irq handler
+    - ethernet: micrel: fix some error codes
+    - power: ipaq-micro-battery: freeing the wrong variable
+    - i40e: fix an uninitialized variable bug
+    - qede: uninitialized variable in qede_start_xmit()
+    - qlcnic: potential NULL dereference in qlcnic_83xx_get_minidump_template()
+    - qlcnic: use the correct ring in qlcnic_83xx_process_rcv_ring_diag()
+    - target: Fix a memory leak in target_dev_lba_map_store()
+    - memory/tegra: Add number of TLB lines for Tegra124
+    - pinctrl: bcm2835: Fix memory leak in error path
+    - be2net: Don't leak iomapped memory on removal.
+    - ipv4: Fix memory leak in exception case for splitting tries
+    - flow_dissector: Check for IP fragmentation even if not using IPv4 address
+    - ipv4: fix checksum annotation in udp4_csum_init
+    - ipv4: do not abuse GFP_ATOMIC in inet_netconf_notify_devconf()
+    - ipv4: accept u8 in IP_TOS ancillary data
+    - net: vrf: Fix dev refcnt leak due to IPv6 prefix route
+    - ipv6: fix checksum annotation in udp6_csum_init
+    - ipv6: do not abuse GFP_ATOMIC in inet6_netconf_notify_devconf()
+    - ipv6: add missing netconf notif when 'all' is updated
+    - net: ipv6: Fix processing of RAs in presence of VRF
+    - netfilter: nf_tables: fix a wrong check to skip the inactive rules
+    - netfilter: nft_dynset: fix panic if NFT_SET_HASH is not enabled
+    - netfilter: nf_tables: destroy the set if fail to add transaction
+    - netfilter: nft_dup: do not use sreg_dev if the user doesn't specify it
+    - udp: restore UDPlite many-cast delivery
+    - clk: st: avoid uninitialized variable use
+    - clk: gpio: handle error codes for of_clk_get_parent_count()
+    - clk: ti: omap3+: dpll: use non-locking version of clk_get_rate
+    - clk: multiplier: Prevent the multiplier from under / over flowing
+    - clk: imx: clk-pllv3: fix incorrect handle of enet powerdown bit
+    - clk: xgene: Don't call __pa on ioremaped address
+    - cls_bpf: reset class and reuse major in da
+    - arm64: bpf: jit JMP_JSET_{X,K}
+    - bpf, trace: check event type in bpf_perf_event_read
+    - bpf: fix map not being uncharged during map creation failure
+    - net/mlx4_core: Fix potential corruption in counters database
+    - net/mlx4_core: Fix access to uninitialized index
+    - net/mlx4_en: Fix the return value of a failure in VLAN VID add/kill
+    - net/mlx4_core: Check device state before unregistering it
+    - net/mlx4_core: Fix the resource-type enum in res tracker to conform to FW
+      spec
+    - net/mlx4_en: Process all completions in RX rings after port goes up
+    - net/mlx4_core: Do not access comm channel if it has not yet been initialized
+    - net/mlx4_en: Fix potential deadlock in port statistics flow
+    - net/mlx4: Fix uninitialized fields in rule when adding promiscuous mode to
+      device managed flow steering
+    - net/mlx4_core: Fix QUERY FUNC CAP flags
+    - mlxsw: switchx2: Fix misuse of hard_header_len
+    - mlxsw: switchx2: Fix ethernet port initialization
+    - sched/fair: Fix calc_cfs_shares() fixed point arithmetics width confusion
+    - net_sched: flower: Avoid dissection of unmasked keys
+    - pkt_sched: fq: use proper locking in fq_dump_stats()
+    - sched/preempt: Fix preempt_count manipulations
+    - power: bq27xxx: fix reading for bq27000 and bq27010
+    - power: bq27xxx: fix register numbers of bq27500
+    - power: test_power: correctly handle empty writes
+    - power: bq27xxx_battery: Fix bq27541 AveragePower register address
+    - power_supply: tps65217-charger: Fix NULL deref during property export
+    - net: vrf: Fix dst reference counting
+    - net: Don't delete routes in different VRFs
+    - vti6: fix input path
+    - ipv4: Fix table id reference in fib_sync_down_addr
+    - mlx4: do not call napi_schedule() without care
+    - xprtrdma: Fix backchannel allocation of extra rpcrdma_reps
+    - ALSA: fm801: Initialize chip after IRQ handler is registered
+    - bonding: fix length of actor system
+    - MIPS: perf: Remove incorrect odd/even counter handling for I6400
+    - Revert "cpufreq: Drop rwsem lock around CPUFREQ_GOV_POLICY_EXIT"
+    - net: dsa: mv88e6xxx: unlock DSA and CPU ports
+    - gfs2: fix flock panic issue
+    - blk-mq: fix undefined behaviour in order_to_size()
+    - dm: fix second blk_delay_queue() parameter to be in msec units not jiffies
+    - dmaengine: edma: Add probe callback to edma_tptc_driver
+    - openvswitch: update checksum in {push,pop}_mpls
+    - cxgb4/cxgb4vf: Fixes regression in perf when tx vlan offload is disabled
+    - net: bcmgenet: fix skb_len in bcmgenet_xmit_single()
+    - net: bcmgenet: device stats are unsigned long
+    - gre: do not assign header_ops in collect metadata mode
+    - gre: build header correctly for collect metadata tunnels
+    - gre: reject GUE and FOU in collect metadata mode
+    - sfc: fix potential stack corruption from running past stat bitmask
+    - sfc: clear napi_hash state when copying channels
+    - net: bcmsysport: Device stats are unsigned long
+    - cxgbi: fix uninitialized flowi6
+    - net: macb: add missing free_netdev() on error in macb_probe()
+    - macvtap: segmented packet is consumed
+    - tipc: fix the error handling in tipc_udp_enable()
+    - net: icmp6_send should use dst dev to determine L3 domain
+    - et131x: Fix logical vs bitwise check in et131x_tx_timeout()
+    - net: ethernet: stmmac: dwmac-sti: fix probe error path
+    - rtnl: reset calcit fptr in rtnl_unregister()
+    - net: ethernet: stmmac: dwmac-rk: fix probe error path
+    - fq_codel: return non zero qlen in class dumps
+    - net: ethernet: stmmac: dwmac-generic: fix probe error path
+    - bnxt: add a missing rcu synchronization
+    - qdisc: fix a module refcount leak in qdisc_create_dflt()
+    - net: axienet: Fix return value check in axienet_probe()
+    - bnxt_en: Remove locking around txr->dev_state
+    - net: ethernet: davinci_emac: Fix devioctl while in fixed link
+    - net: ethernet: mvneta: Remove IFF_UNICAST_FLT which is not implemented
+    - net: ethernet: ti: cpsw: fix device and of_node leaks
+    - net: ethernet: ti: cpsw: fix secondary-emac probe error path
+    - net: hns: fix device reference leaks
+    - net: bridge: don't increment tx_dropped in br_do_proxy_arp
+    - net: dsa: mv88e6xxx: enable SA learning on DSA ports
+    - net: ehea: avoid null pointer dereference
+    - l2tp: fix use-after-free during module unload
+    - hwrng: exynos - Disable runtime PM on driver unbind
+    - net: icmp_route_lookup should use rt dev to determine L3 domain
+    - net: mvneta: fix trivial cut-off issue in mvneta_ethtool_update_stats
+    - net: macb: replace macb_writel() call by queue_writel() to update queue ISR
+    - ravb: Add missing free_irq() call to ravb_close()
+    - mvpp2: use correct size for memset
+    - net: vxlan: lwt: Fix vxlan local traffic.
+    - net: ethoc: Fix early error paths
+    - net: mv643xx_eth: fix packet corruption with TSO and tiny unaligned packets.
+    - regulator: core: Rely on regulator_dev_release to free constraints
+    - net: dsa: mv88e6xxx: fix port VLAN maps
+    - at803x: fix reset handling
+    - cxl: Fix DAR check & use REGION_ID instead of opencoding
+    - net: ethernet: davinci_emac: Fix platform_data overwrite
+    - ata: sata_dwc_460ex: remove incorrect locking
+    - pinctrl: tegra: Correctly check the supported configuration
+    - brcmfmac: add fallback for devices that do not report per-chain values
+    - brcmfmac: restore stopping netdev queue when bus clogs up
+    - bridge: Fix problems around fdb entries pointing to the bridge device
+    - bna: add missing per queue ethtool stat
+    - net: skbuff: Remove errornous length validation in skb_vlan_pop()
+    - net: ep93xx_eth: Do not crash unloading module
+    - macvlan: Fix potential use-after free for broadcasts
+    - sctp: Fix SHUTDOWN CTSN Ack in the peer restart case
+    - ALSA: hda: Match both PCI ID and SSID for driver blacklist
+    - mac80211: add ieee80211_is_any_nullfunc()
+    - Linux 4.4.223
+
+  * Xenial update: 4.4.222 upstream stable release (LP: #1878246)
+    - ext4: fix special inode number checks in __ext4_iget()
+    - drm/qxl: qxl_release leak in qxl_hw_surface_alloc()
+    - ALSA: pcm: oss: Place the plugin buffer overflow checks correctly
+    - PM: ACPI: Output correct message on target power state
+    - RDMA/mlx4: Initialize ib_spec on the stack
+    - vfio/type1: Fix VA->PA translation for PFNMAP VMAs in vaddr_get_pfn()
+    - ALSA: opti9xx: shut up gcc-10 range warning
+    - nfs: Fix potential posix_acl refcnt leak in nfs3_set_acl
+    - dmaengine: dmatest: Fix iteration non-stop logic
+    - i2c: designware-pci: use IRQF_COND_SUSPEND flag
+    - perf hists: Fix HISTC_MEM_DCACHELINE width setting
+    - powerpc/perf: Remove PPMU_HAS_SSLOT flag for Power8
+    - perf/x86: Fix uninitialized value usage
+    - exynos4-is: fix a format string bug
+    - ASoC: wm8960: Fix WM8960_SYSCLK_PLL mode
+    - ASoC: imx-spdif: Fix crash on suspend
+    - ipv6: use READ_ONCE() for inet->hdrincl as in ipv4
+    - selinux: properly handle multiple messages in selinux_netlink_send()
+    - Linux 4.4.222
+
+  * Xenial update: 4.4.221 upstream stable release (LP: #1878098)
+    - ext4: fix extent_status fragmentation for plain files
+    - ALSA: hda - Fix incorrect usage of IS_REACHABLE()
+    - net: ipv4: emulate READ_ONCE() on ->hdrincl bit-field in raw_sendmsg()
+    - net: ipv4: avoid unused variable warning for sysctl
+    - crypto: mxs-dcp - make symbols 'sha1_null_hash' and 'sha256_null_hash'
+      static
+    - vti4: removed duplicate log message.
+    - scsi: lpfc: Fix kasan slab-out-of-bounds error in lpfc_unreg_login
+    - ceph: return ceph_mdsc_do_request() errors from __get_parent()
+    - ceph: don't skip updating wanted caps when cap is stale
+    - pwm: rcar: Fix late Runtime PM enablement
+    - scsi: iscsi: Report unbind session event when the target has been removed
+    - ASoC: Intel: atom: Take the drv->lock mutex before calling
+      sst_send_slot_map()
+    - kernel/gcov/fs.c: gcov_seq_next() should increase position index
+    - ipc/util.c: sysvipc_find_ipc() should increase position index
+    - s390/cio: avoid duplicated 'ADD' uevents
+    - pwm: renesas-tpu: Fix late Runtime PM enablement
+    - pwm: bcm2835: Dynamically allocate base
+    - ipv6: fix restrict IPV6_ADDRFORM operation
+    - macvlan: fix null dereference in macvlan_device_event()
+    - net: netrom: Fix potential nr_neigh refcnt leak in nr_add_node
+    - net/x25: Fix x25_neigh refcnt leak when receiving frame
+    - tcp: cache line align MAX_TCP_HEADER
+    - team: fix hang in team_mode_get()
+    - xfrm: Always set XFRM_TRANSFORMED in xfrm{4,6}_output_finish
+    - ALSA: hda: Remove ASUS ROG Zenith from the blacklist
+    - iio: xilinx-xadc: Fix ADC-B powerdown
+    - iio: xilinx-xadc: Fix clearing interrupt when enabling trigger
+    - iio: xilinx-xadc: Fix sequencer configuration for aux channels in
+      simultaneous mode
+    - fs/namespace.c: fix mountpoint reference counter race
+    - USB: sisusbvga: Change port variable from signed to unsigned
+    - USB: Add USB_QUIRK_DELAY_CTRL_MSG and USB_QUIRK_DELAY_INIT for Corsair K70
+      RGB RAPIDFIRE
+    - drivers: usb: core: Don't disable irqs in usb_sg_wait() during URB submit.
+    - drivers: usb: core: Minimize irq disabling in usb_sg_cancel()
+    - USB: core: Fix free-while-in-use bug in the USB S-Glibrary
+    - USB: hub: Fix handling of connect changes during sleep
+    - ALSA: usx2y: Fix potential NULL dereference
+    - ALSA: usb-audio: Fix usb audio refcnt leak when getting spdif
+    - ALSA: usb-audio: Filter out unsupported sample rates on Focusrite devices
+    - KVM: Check validity of resolved slot when searching memslots
+    - KVM: VMX: Enable machine check support for 32bit targets
+    - tty: hvc: fix buffer overflow during hvc_alloc().
+    - tty: rocket, avoid OOB access
+    - usb-storage: Add unusual_devs entry for JMicron JMS566
+    - audit: check the length of userspace generated audit records
+    - ASoC: dapm: fixup dapm kcontrol widget
+    - ARM: imx: provide v7_cpu_resume() only on ARM_CPU_SUSPEND=y
+    - staging: comedi: dt2815: fix writing hi byte of analog output
+    - staging: comedi: Fix comedi_device refcnt leak in comedi_open
+    - staging: vt6656: Fix drivers TBTT timing counter.
+    - staging: vt6656: Power save stop wake_up_count wrap around.
+    - UAS: no use logging any details in case of ENODEV
+    - UAS: fix deadlock in error handling and PM flushing work
+    - usb: f_fs: Clear OS Extended descriptor counts to zero in ffs_data_reset()
+    - remoteproc: Fix wrong rvring index computation
+    - sctp: use right member as the param of list_for_each_entry
+    - fuse: fix possibly missed wake-up after abort
+    - mtd: cfi: fix deadloop in cfi_cmdset_0002.c do_write_buffer
+    - usb: gadget: udc: bdc: Remove unnecessary NULL checks in bdc_req_complete
+    - net/cxgb4: Check the return from t4_query_params properly
+    - perf/core: fix parent pid/tid in task exit events
+    - bpf, x86: Fix encoding for lower 8-bit registers in BPF_STX BPF_B
+    - scsi: target: fix PR IN / READ FULL STATUS for FC
+    - xen/xenbus: ensure xenbus_map_ring_valloc() returns proper grant status
+    - ext4: convert BUG_ON's to WARN_ON's in mballoc.c
+    - ext4: avoid declaring fs inconsistent due to invalid file handles
+    - ext4: protect journal inode's blocks using block_validity
+    - ext4: don't perform block validity checks on the journal inode
+    - ext4: fix block validity checks for journal inodes using indirect blocks
+    - ext4: unsigned int compared against zero
+    - propagate_one(): mnt_set_mountpoint() needs mount_lock
+    - Linux 4.4.221
+
+  * Xenial update: 4.4.220 upstream stable release (LP: #1875905)
+    - bus: sunxi-rsb: Return correct data when mixing 16-bit and 8-bit reads
+    - net: vxge: fix wrong __VA_ARGS__ usage
+    - qlcnic: Fix bad kzalloc null test
+    - i2c: st: fix missing struct parameter description
+    - irqchip/versatile-fpga: Handle chained IRQs properly
+    - selftests/x86/ptrace_syscall_32: Fix no-vDSO segfault
+    - libata: Remove extra scsi_host_put() in ata_scsi_add_hosts()
+    - gfs2: Don't demote a glock until its revokes are written
+    - x86/boot: Use unsigned comparison for addresses
+    - locking/lockdep: Avoid recursion in lockdep_count_{for,back}ward_deps()
+    - btrfs: remove a BUG_ON() from merge_reloc_roots()
+    - btrfs: track reloc roots based on their commit root bytenr
+    - misc: rtsx: set correct pcr_ops for rts522A
+    - ASoC: fix regwmask
+    - ASoC: dapm: connect virtual mux with default value
+    - ASoC: dpcm: allow start or stop during pause for backend
+    - ASoC: topology: use name_prefix for new kcontrol
+    - usb: gadget: f_fs: Fix use after free issue as part of queue failure
+    - usb: gadget: composite: Inform controller driver of self-powered
+    - ALSA: usb-audio: Add mixer workaround for TRX40 and co
+    - ALSA: hda: Add driver blacklist
+    - ALSA: hda: Fix potential access overflow in beep helper
+    - ALSA: ice1724: Fix invalid access for enumerated ctl items
+    - ALSA: pcm: oss: Fix regression by buffer overflow fix
+    - acpi/x86: ignore unspecified bit positions in the ACPI global lock field
+    - thermal: devfreq_cooling: inline all stubs for CONFIG_DEVFREQ_THERMAL=n
+    - irqchip/versatile-fpga: Apply clear-mask earlier
+    - MIPS: OCTEON: irq: Fix potential NULL pointer dereference
+    - ath9k: Handle txpower changes even when TPC is disabled
+    - signal: Extend exec_id to 64bits
+    - x86/entry/32: Add missing ASM_CLAC to general_protection entry
+    - KVM: x86: Allocate new rmap and large page tracking when moving memslot
+    - crypto: mxs-dcp - fix scatterlist linearization for hash
+    - futex: futex_wake_op, do not fail on invalid op
+    - xen-netfront: Rework the fix for Rx stall during OOM and network stress
+    - ALSA: hda: Initialize power_state field properly
+    - Btrfs: incremental send, fix invalid memory access
+    - IB/ipoib: Fix lockdep issue found on ipoib_ib_dev_heavy_flush
+    - scsi: zfcp: fix missing erp_lock in port recovery trigger for point-to-point
+    - arm64: armv8_deprecated: Fix undef_hook mask for thumb setend
+    - ext4: fix a data race at inode->i_blocks
+    - ocfs2: no need try to truncate file beyond i_size
+    - s390/diag: fix display of diagnose call statistics
+    - Input: i8042 - add Acer Aspire 5738z to nomux list
+    - kmod: make request_module() return an error when autoloading is disabled
+    - hfsplus: fix crash and filesystem corruption when deleting files
+    - powerpc/64/tm: Don't let userspace set regs->trap via sigreturn
+    - Btrfs: fix crash during unmount due to race with delayed inode workers
+    - drm/dp_mst: Fix clearing payload state on topology disable
+    - ipmi: fix hung processes in __get_guid()
+    - powerpc/fsl_booke: Avoid creating duplicate tlb1 entry
+    - misc: echo: Remove unnecessary parentheses and simplify check for zero
+    - mfd: dln2: Fix sanity checking for endpoints
+    - net: ipv4: devinet: Fix crash when add/del multicast IP with autojoin
+    - net: ipv6: do not consider routes via gateways for anycast address check
+    - scsi: ufs: Fix ufshcd_hold() caused scheduling while atomic
+    - jbd2: improve comments about freeing data buffers whose page mapping is NULL
+    - ext4: fix incorrect group count in ext4_fill_super error message
+    - ext4: fix incorrect inodes per group in error message
+    - ASoC: Intel: mrfld: fix incorrect check on p->sink
+    - ASoC: Intel: mrfld: return error codes when an error occurs
+    - ALSA: usb-audio: Don't override ignore_ctl_error value from the map
+    - mac80211_hwsim: Use kstrndup() in place of kasprintf()
+    - ext4: do not zeroout extents beyond i_disksize
+    - dm flakey: check for null arg_name in parse_features()
+    - kvm: x86: Host feature SSBD doesn't imply guest feature SPEC_CTRL_SSBD
+    - x86/mitigations: Clear CPU buffers on the SYSCALL fast path
+    - tracing: Fix the race between registering 'snapshot' event trigger and
+      triggering 'snapshot' operation
+    - scsi: sg: add sg_remove_request in sg_common_write
+    - ALSA: hda: Don't release card at firmware loading error
+    - video: fbdev: sis: Remove unnecessary parentheses and commented code
+    - drm: NULL pointer dereference [null-pointer-deref] (CWE 476) problem
+    - wil6210: increase firmware ready timeout
+    - wil6210: fix temperature debugfs
+    - scsi: ufs: ufs-qcom: remove broken hci version quirk
+    - wil6210: rate limit wil_rx_refill error
+    - rtc: pm8xxx: Fix issue in RTC write path
+    - soc: qcom: smem: Use le32_to_cpu for comparison
+    - of: fix missing kobject init for !SYSFS && OF_DYNAMIC config
+    - of: unittest: kmemleak in of_unittest_platform_populate()
+    - clk: at91: usb: continue if clk_hw_round_rate() return zero
+    - clk: tegra: Fix Tegra PMC clock out parents
+    - NFS: direct.c: Fix memory leak of dreq when nfs_get_lock_context fails
+    - ext4: do not commit super on read-only bdev
+    - percpu_counter: fix a data race at vm_committed_as
+    - compiler.h: fix error in BUILD_BUG_ON() reporting
+    - NFS: Fix memory leaks in nfs_pageio_stop_mirroring()
+    - ext2: fix empty body warnings when -Wextra is used
+    - iommu/amd: Fix the configuration of GCR3 table root pointer
+    - fbdev: potential information leak in do_fb_ioctl()
+    - tty: evh_bytechan: Fix out of bounds accesses
+    - locktorture: Print ratio of acquisitions, not failures
+    - mtd: lpddr: Fix a double free in probe()
+    - mtd: phram: fix a double free issue in error path
+    - x86/CPU: Add native CPUID variants returning a single datum
+    - x86/microcode/intel: replace sync_core() with native_cpuid_reg(eax)
+    - x86/vdso: Fix lsl operand order
+    - Linux 4.4.220
+
+  * Panic on suspend/resume Kernel panic - not syncing: stack-protector: Kernel
+    stack is corrupted in: sata_pmp_eh_recover+0xa2b/0xa40 (LP: #1821434) //
+    Xenial update: 4.4.220 upstream stable release (LP: #1875905)
+    - libata: Return correct status in sata_pmp_eh_recover_pm() when
+      ATA_DFLAG_DETACH is set
+
+  * psock_tpacket from the net test in ubuntu_kernel_selftests failed on KVM
+    kernels (LP: #1812176)
+    - selftests/net: skip psock_tpacket test if KALLSYMS was not enabled
+
+  * tunnels over IPv6 are unencrypted when using IPsec (LP: #1876982) //
+    CVE-2020-1749
+    - net: ipv6: add net argument to ip6_dst_lookup_flow
+    - net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup
+
+  * Bionic ubuntu ethtool doesn't check ring parameters boundaries
+    (LP: #1874444)
+    - ethtool: Ensure new ring parameters are within bounds during SRINGPARAM
+
+  * Improve TSC refinement (and calibration) reliability (LP: #1877858)
+    - x86/tsc: Make calibration refinement more robust
+
+  * Do not treat unresolved test case in ftrace from ubuntu_kernel_selftests as
+    failure (LP: #1877958)
+    - ftrace/selftest: make unresolved cases cause failure if --fail-unresolved
+      set
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 15 May 2020 18:03:36 +0200
+
+linux (4.4.0-179.209) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-179.209 -proposed tracker (LP: #1874804)
+
+  * Add debian/rules targets to compile/run kernel selftests (LP: #1874286)
+    - [Packaging] add support to compile/run selftests
+
+  * getitimer returns it_value=0 erroneously (LP: #1349028)
+    - [Config] CONTEXT_TRACKING_FORCE policy should be unset
+
+  * CVE-2020-11608
+    - media: ov519: add missing endpoint sanity checks
+
+  * CVE-2019-19060
+    - iio: imu: adis16400: release allocated memory on failure
+
+  * Xenial update: 4.4.219 upstream stable release (LP: #1874045)
+    - drm/bochs: downgrade pci_request_region failure from error to warning
+    - ipv4: fix a RCU-list lock in fib_triestat_seq_show
+    - net, ip_tunnel: fix interface lookup with no key
+    - sctp: fix possibly using a bad saddr with a given dst
+    - l2tp: Correctly return -EBADF from pppol2tp_getname.
+    - net: l2tp: Make l2tp_ip6 namespace aware
+    - l2tp: fix race in l2tp_recv_common()
+    - l2tp: ensure session can't get removed during pppol2tp_session_ioctl()
+    - l2tp: fix duplicate session creation
+    - l2tp: Refactor the codes with existing macros instead of literal number
+    - l2tp: ensure sessions are freed after their PPPOL2TP socket
+    - l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall()
+    - usb: gadget: uac2: Drop unused device qualifier descriptor
+    - usb: gadget: printer: Drop unused device qualifier descriptor
+    - padata: always acquire cpu_hotplug_lock before pinst->lock
+    - mm: mempolicy: require at least one nodeid for MPOL_PREFERRED
+    - net: stmmac: dwmac1000: fix out-of-bounds mac address reg setting
+    - random: always use batched entropy for get_random_u{32,64}
+    - tools/accounting/getdelays.c: fix netlink attribute length
+    - power: supply: axp288_charger: Fix unchecked return value
+    - ASoC: jz4740-i2s: Fix divider written at incorrect offset in register
+    - IB/hfi1: Call kobject_put() when kobject_init_and_add() fails
+    - Bluetooth: RFCOMM: fix ODEBUG bug in rfcomm_dev_ioctl
+    - RDMA/cm: Update num_paths in cma_resolve_iboe_route error flow
+    - clk: qcom: rcg: Return failure for RCG update
+    - drm_dp_mst_topology: fix broken drm_dp_sideband_parse_remote_dpcd_read()
+    - Linux 4.4.219
+
+  * Xenial update: 4.4.218 upstream stable release (LP: #1873852)
+    - spi: qup: call spi_qup_pm_resume_runtime before suspending
+    - powerpc: Include .BTF section
+    - ARM: dts: dra7: Add "dma-ranges" property to PCIe RC DT nodes
+    - spi/zynqmp: remove entry that causes a cs glitch
+    - drm/exynos: dsi: propagate error value and silence meaningless warning
+    - drm/exynos: dsi: fix workaround for the legacy clock name
+    - altera-stapl: altera_get_note: prevent write beyond end of 'key'
+    - USB: Disable LPM on WD19's Realtek Hub
+    - usb: quirks: add NO_LPM quirk for RTL8153 based ethernet adapters
+    - USB: serial: option: add ME910G1 ECM composition 0x110b
+    - usb: host: xhci-plat: add a shutdown
+    - USB: serial: pl2303: add device-id for HP LD381
+    - ALSA: line6: Fix endless MIDI read loop
+    - ALSA: seq: virmidi: Fix running status after receiving sysex
+    - ALSA: seq: oss: Fix running status after receiving sysex
+    - ALSA: pcm: oss: Avoid plugin buffer overflow
+    - ALSA: pcm: oss: Remove WARNING from snd_pcm_plug_alloc() checks
+    - staging: rtl8188eu: Add device id for MERCUSYS MW150US v2
+    - staging/speakup: fix get_word non-space look-ahead
+    - intel_th: Fix user-visible error codes
+    - rtc: max8907: add missing select REGMAP_IRQ
+    - memcg: fix NULL pointer dereference in __mem_cgroup_usage_unregister_event
+    - mm: slub: be more careful about the double cmpxchg of freelist
+    - mm, slub: prevent kmalloc_node crashes and memory leaks
+    - x86/mm: split vmalloc_sync_all()
+    - USB: cdc-acm: fix close_delay and closing_wait units in TIOCSSERIAL
+    - USB: cdc-acm: fix rounding error in TIOCSSERIAL
+    - kbuild: Disable -Wpointer-to-enum-cast
+    - futex: Fix inode life-time issue
+    - futex: Unbreak futex hashing
+    - arm64: smp: fix smp_send_stop() behaviour
+    - Revert "drm/dp_mst: Skip validating ports during destruction, just ref"
+    - hsr: fix general protection fault in hsr_addr_is_self()
+    - net: dsa: Fix duplicate frames flooded by learning
+    - net_sched: cls_route: remove the right filter from hashtable
+    - net_sched: keep alloc_hash updated after hash allocation
+    - NFC: fdp: Fix a signedness bug in fdp_nci_send_patch()
+    - slcan: not call free_netdev before rtnl_unlock in slcan_open
+    - vxlan: check return value of gro_cells_init()
+    - hsr: use rcu_read_lock() in hsr_get_node_{list/status}()
+    - hsr: add restart routine into hsr_get_node_list()
+    - hsr: set .netnsok flag
+    - vhost: Check docket sk_family instead of call getname
+    - IB/ipoib: Do not warn if IPoIB debugfs doesn't exist
+    - uapi glibc compat: fix outer guard of net device flags enum
+    - KVM: VMX: Do not allow reexecute_instruction() when skipping MMIO instr
+    - drivers/hwspinlock: use correct radix tree API
+    - net: ipv4: don't let PMTU updates increase route MTU
+    - cpupower: avoid multiple definition with gcc -fno-common
+    - dt-bindings: net: FMan erratum A050385
+    - scsi: ipr: Fix softlockup when rescanning devices in petitboot
+    - mac80211: Do not send mesh HWMP PREQ if HWMP is disabled
+    - sxgbe: Fix off by one in samsung driver strncpy size arg
+    - i2c: hix5hd2: add missed clk_disable_unprepare in remove
+    - perf probe: Do not depend on dwfl_module_addrsym()
+    - scripts/dtc: Remove redundant YYLOC global declaration
+    - scsi: sd: Fix optimal I/O size for devices that change reported values
+    - mac80211: mark station unauthorized before key removal
+    - genirq: Fix reference leaks on irq affinity notifiers
+    - vti[6]: fix packet tx through bpf_redirect() in XinY cases
+    - xfrm: fix uctx len check in verify_sec_ctx_len
+    - xfrm: add the missing verify_sec_ctx_len check in xfrm_add_acquire
+    - xfrm: policy: Fix doulbe free in xfrm_policy_timer
+    - vti6: Fix memory leak of skb if input policy check fails
+    - tools: Let O= makes handle a relative path with -C option
+    - USB: serial: option: add support for ASKEY WWHC050
+    - USB: serial: option: add BroadMobi BM806U
+    - USB: serial: option: add Wistron Neweb D19Q1
+    - USB: cdc-acm: restore capability check order
+    - USB: serial: io_edgeport: fix slab-out-of-bounds read in
+      edge_interrupt_callback
+    - usb: musb: fix crash with highmen PIO and usbmon
+    - media: flexcop-usb: fix endpoint sanity check
+    - media: usbtv: fix control-message timeouts
+    - staging: rtl8188eu: Add ASUS USB-N10 Nano B1 to device table
+    - staging: wlan-ng: fix use-after-free Read in hfa384x_usbin_callback
+    - libfs: fix infoleak in simple_attr_read()
+    - media: ov519: add missing endpoint sanity checks
+    - media: dib0700: fix rc endpoint lookup
+    - media: stv06xx: add missing descriptor sanity checks
+    - media: xirlink_cit: add missing descriptor sanity checks
+    - vt: selection, introduce vc_is_sel
+    - vt: ioctl, switch VT_IS_IN_USE and VT_BUSY to inlines
+    - vt: switch vt_dont_switch to bool
+    - vt: vt_ioctl: remove unnecessary console allocation checks
+    - vt: vt_ioctl: fix VT_DISALLOCATE freeing in-use virtual console
+    - locking/atomic, kref: Add kref_read()
+    - vt: vt_ioctl: fix use-after-free in vt_in_use()
+    - bpf: Explicitly memset the bpf_attr structure
+    - net: ks8851-ml: Fix IO operations, again
+    - perf map: Fix off by one in strncpy() size argument
+    - Linux 4.4.218
+
+  * Pop sound from build-in speaker during cold boot and resume from S3
+    (LP: #1866357) // Xenial update: 4.4.218 upstream stable release
+    (LP: #1873852)
+    - ALSA: hda/realtek: Fix pop noise on ALC225
+
+  * CVE-2020-11494
+    - slcan: Don't transmit uninitialized stack data in padding
+
+  * add_key05 from ubuntu_ltp_syscalls failed (LP: #1869644)
+    - KEYS: reaching the keys quotas correctly
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 24 Apr 2020 19:06:47 +0200
+
+linux (4.4.0-178.208) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-178.208 -proposed tracker (LP: #1870660)
+
+  * CVE-2019-19768
+    - blktrace: Protect q->blk_trace with RCU
+    - blktrace: fix dereference after null check
+
+  * Multiple Kexec in AWS Nitro instances fail (LP: #1869948)
+    - net: ena: Add PCI shutdown handler to allow safe kexec
+
+  * Insert test_bpf module will report 4 failures for ubuntu_bpf_jit on X s390x
+    (LP: #1768452)
+    - test_bpf: flag tests that cannot be jited on s390
+
+  * Mounting LVM snapshots with xfs can hit kernel BUG in nvme driver
+    (LP: #1869229)
+    - block: fix bio_will_gap() for first bvec with offset
+
+  * Xenial update: 4.4.217 upstream stable release (LP: #1868629)
+    - NFS: Remove superfluous kmap in nfs_readdir_xdr_to_array
+    - r8152: check disconnect status after long sleep
+    - net: nfc: fix bounds checking bugs on "pipe"
+    - bnxt_en: reinitialize IRQs when MTU is modified
+    - fib: add missing attribute validation for tun_id
+    - nl802154: add missing attribute validation
+    - nl802154: add missing attribute validation for dev_type
+    - team: add missing attribute validation for port ifindex
+    - team: add missing attribute validation for array index
+    - nfc: add missing attribute validation for SE API
+    - nfc: add missing attribute validation for vendor subcommand
+    - ipvlan: add cond_resched_rcu() while processing muticast backlog
+    - ipvlan: do not add hardware address of master to its unicast filter list
+    - ipvlan: egress mcast packets are not exceptional
+    - ipvlan: do not use cond_resched_rcu() in ipvlan_process_multicast()
+    - ipvlan: don't deref eth hdr before checking it's set
+    - macvlan: add cond_resched() during multicast processing
+    - net: fec: validate the new settings in fec_enet_set_coalesce()
+    - slip: make slhc_compress() more robust against malicious packets
+    - bonding/alb: make sure arp header is pulled before accessing it
+    - net: fq: add missing attribute validation for orphan mask
+    - iommu/vt-d: quirk_ioat_snb_local_iommu: replace WARN_TAINT with pr_warn +
+      add_taint
+    - drm/amd/display: remove duplicated assignment to grph_obj_type
+    - gfs2_atomic_open(): fix O_EXCL|O_CREAT handling on cold dcache
+    - KVM: x86: clear stale x86_emulate_ctxt->intercept value
+    - ARC: define __ALIGN_STR and __ALIGN symbols for ARC
+    - efi: Fix a race and a buffer overflow while reading efivars via sysfs
+    - iommu/vt-d: dmar: replace WARN_TAINT with pr_warn + add_taint
+    - iommu/vt-d: Fix a bug in intel_iommu_iova_to_phys() for huge page
+    - nl80211: add missing attribute validation for critical protocol indication
+    - nl80211: add missing attribute validation for channel switch
+    - netfilter: cthelper: add missing attribute validation for cthelper
+    - iommu/vt-d: Fix the wrong printing in RHSA parsing
+    - iommu/vt-d: Ignore devices with out-of-spec domain number
+    - ipv6: restrict IPV6_ADDRFORM operation
+    - efi: Add a sanity check to efivar_store_raw()
+    - batman-adv: Fix invalid read while copying bat_iv.bcast_own
+    - batman-adv: Only put gw_node list reference when removed
+    - batman-adv: Only put orig_node_vlan list reference when removed
+    - batman-adv: Avoid endless loop in bat-on-bat netdevice check
+    - batman-adv: Fix unexpected free of bcast_own on add_if error
+    - batman-adv: Fix integer overflow in batadv_iv_ogm_calc_tq
+    - batman-adv: init neigh node last seen field
+    - batman-adv: Deactivate TO_BE_ACTIVATED hardif on shutdown
+    - batman-adv: Drop reference to netdevice on last reference
+    - batman-adv: Fix reference counting of vlan object for tt_local_entry
+    - batman-adv: Avoid duplicate neigh_node additions
+    - batman-adv: fix skb deref after free
+    - batman-adv: Fix use-after-free/double-free of tt_req_node
+    - batman-adv: Fix ICMP RR ethernet access after skb_linearize
+    - batman-adv: Clean up untagged vlan when destroying via rtnl-link
+    - batman-adv: Avoid nullptr dereference in bla after vlan_insert_tag
+    - batman-adv: Avoid nullptr dereference in dat after vlan_insert_tag
+    - batman-adv: Fix orig_node_vlan leak on orig_node_release
+    - batman-adv: lock crc access in bridge loop avoidance
+    - batman-adv: Fix non-atomic bla_claim::backbone_gw access
+    - batman-adv: Fix reference leak in batadv_find_router
+    - batman-adv: Free last_bonding_candidate on release of orig_node
+    - batman-adv: Fix speedy join in gateway client mode
+    - batman-adv: Add missing refcnt for last_candidate
+    - batman-adv: Fix double free during fragment merge error
+    - batman-adv: Fix transmission of final, 16th fragment
+    - batman-adv: Fix rx packet/bytes stats on local ARP reply
+    - batman-adv: fix TT sync flag inconsistencies
+    - batman-adv: Fix lock for ogm cnt access in batadv_iv_ogm_calc_tq
+    - batman-adv: Fix internal interface indices types
+    - batman-adv: update data pointers after skb_cow()
+    - batman-adv: Fix skbuff rcsum on packet reroute
+    - batman-adv: Avoid race in TT TVLV allocator helper
+    - batman-adv: Fix TT sync flags for intermediate TT responses
+    - batman-adv: prevent TT request storms by not sending inconsistent TT TLVLs
+    - batman-adv: Fix debugfs path for renamed hardif
+    - batman-adv: Fix debugfs path for renamed softif
+    - batman-adv: Avoid storing non-TT-sync flags on singular entries too
+    - batman-adv: Prevent duplicated gateway_node entry
+    - batman-adv: Prevent duplicated nc_node entry
+    - batman-adv: Prevent duplicated global TT entry
+    - batman-adv: Prevent duplicated tvlv handler
+    - batman-adv: Reduce claim hash refcnt only for removed entry
+    - batman-adv: Reduce tt_local hash refcnt only for removed entry
+    - batman-adv: Reduce tt_global hash refcnt only for removed entry
+    - batman-adv: Only read OGM tvlv_len after buffer len check
+    - batman-adv: Avoid free/alloc race when handling OGM buffer
+    - batman-adv: Don't schedule OGM for disabled interface
+    - perf/amd/uncore: Replace manual sampling check with CAP_NO_INTERRUPT flag
+    - net: ks8851-ml: Fix IRQ handling and locking
+    - signal: avoid double atomic counter increments for user accounting
+    - jbd2: fix data races at struct journal_head
+    - ARM: 8957/1: VDSO: Match ARMv8 timer in cntvct_functional()
+    - ARM: 8958/1: rename missed uaccess .fixup section
+    - mm: slub: add missing TID bump in kmem_cache_alloc_bulk()
+    - ipv4: ensure rcu_read_lock() in cipso_v4_error()
+    - Linux 4.4.217
+
+  * Xenial update: 4.4.216 upstream stable release (LP: #1868628)
+    - iwlwifi: pcie: fix rb_allocator workqueue allocation
+    - ext4: fix potential race between online resizing and write operations
+    - ext4: fix potential race between s_flex_groups online resizing and access
+    - ext4: fix potential race between s_group_info online resizing and access
+    - ipmi:ssif: Handle a possible NULL pointer reference
+    - mac80211: consider more elements in parsing CRC
+    - cfg80211: check wiphy driver existence for drvinfo report
+    - cifs: Fix mode output in debugging statements
+    - cfg80211: add missing policy for NL80211_ATTR_STATUS_CODE
+    - sysrq: Restore original console_loglevel when sysrq disabled
+    - sysrq: Remove duplicated sysrq message
+    - net: fib_rules: Correctly set table field when table number exceeds 8 bits
+    - net: phy: restore mdio regs in the iproc mdio driver
+    - ipv6: Fix nlmsg_flags when splitting a multipath route
+    - ipv6: Fix route replacement with dev-only route
+    - sctp: move the format error check out of __sctp_sf_do_9_1_abort
+    - nfc: pn544: Fix occasional HW initialization failure
+    - net: sched: correct flower port blocking
+    - ext4: potential crash on allocation error in ext4_alloc_flex_bg_array()
+    - audit: fix error handling in audit_data_to_entry()
+    - HID: core: fix off-by-one memset in hid_report_raw_event()
+    - HID: core: increase HID report buffer size to 8KiB
+    - HID: hiddev: Fix race in in hiddev_disconnect()
+    - MIPS: VPE: Fix a double free and a memory leak in 'release_vpe()'
+    - i2c: jz4780: silence log flood on txabrt
+    - ecryptfs: Fix up bad backport of fe2e082f5da5b4a0a92ae32978f81507ef37ec66
+    - net: netlink: cap max groups which will be considered in netlink_bind()
+    - namei: only return -ECHILD from follow_dotdot_rcu()
+    - KVM: Check for a bad hva before dropping into the ghc slow path
+    - slip: stop double free sl->dev in slip_open
+    - mm: make page ref count overflow check tighter and more explicit
+    - mm, gup: remove broken VM_BUG_ON_PAGE compound check for hugepages
+    - audit: always check the netlink payload length in audit_receive_msg()
+    - serial: ar933x_uart: set UART_CS_{RX,TX}_READY_ORIDE
+    - usb: gadget: ffs: ffs_aio_cancel(): Save/restore IRQ flags
+    - usb: gadget: serial: fix Tx stall after buffer overflow
+    - drm: msm: Fix return type of dsi_mgr_connector_mode_valid for kCFI
+    - drm/msm/dsi: save pll state before dsi host is powered off
+    - net: ks8851-ml: Remove 8-bit bus accessors
+    - net: ks8851-ml: Fix 16-bit data access
+    - net: ks8851-ml: Fix 16-bit IO operation
+    - watchdog: da9062: do not ping the hw during stop()
+    - s390/cio: cio_ignore_proc_seq_next should increase position index
+    - cifs: don't leak -EAGAIN for stat() during reconnect
+    - usb: storage: Add quirk for Samsung Fit flash
+    - usb: quirks: add NO_LPM quirk for Logitech Screen Share
+    - usb: core: hub: do error out if usb_autopm_get_interface() fails
+    - usb: core: port: do error out if usb_autopm_get_interface() fails
+    - vgacon: Fix a UAF in vgacon_invert_region
+    - fat: fix uninit-memory access for partial initialized inode
+    - vt: selection, close sel_buffer race
+    - vt: selection, push console lock down
+    - vt: selection, push sel_lock up
+    - dmaengine: tegra-apb: Fix use-after-free
+    - dmaengine: tegra-apb: Prevent race conditions of tasklet vs free list
+    - ASoC: pcm: Fix possible buffer overflow in dpcm state sysfs output
+    - ASoC: pcm512x: Fix unbalanced regulator enable call in probe error path
+    - ASoC: dapm: Correct DAPM handling of active widgets during shutdown
+    - RDMA/iwcm: Fix iwcm work deallocation
+    - RMDA/cm: Fix missing ib_cm_destroy_id() in ib_cm_insert_listen()
+    - ARM: imx: build v7_cpu_resume() unconditionally
+    - hwmon: (adt7462) Fix an error return in ADT7462_REG_VOLT()
+    - dmaengine: coh901318: Fix a double lock bug in dma_tc_handle()
+    - powerpc: fix hardware PMU exception bug on PowerVM compatibility mode
+      systems
+    - dm cache: fix a crash due to incorrect work item cancelling
+    - crypto: algif_skcipher - use ZERO_OR_NULL_PTR in skcipher_recvmsg_async
+    - Linux 4.4.216
+
+  * Xenial update: 4.4.215 upstream stable release (LP: #1868627)
+    - ALSA: hda: Use scnprintf() for printing texts for sysfs/procfs
+    - ecryptfs: fix a memory leak bug in parse_tag_1_packet()
+    - ecryptfs: fix a memory leak bug in ecryptfs_init_messaging()
+    - ALSA: usb-audio: Apply sample rate quirk for Audioengine D1
+    - ubifs: Fix deadlock in concurrent bulk-read and writepage
+    - ext4: fix checksum errors with indexed dirs
+    - Btrfs: fix race between using extent maps and merging them
+    - btrfs: log message when rw remount is attempted with unclean tree-log
+    - padata: Remove broken queue flushing
+    - s390/time: Fix clk type in get_tod_clock
+    - hwmon: (pmbus/ltc2978) Fix PMBus polling of MFR_COMMON definitions.
+    - jbd2: move the clearing of b_modified flag to the journal_unmap_buffer()
+    - jbd2: do not clear the BH_Mapped flag when forgetting a metadata buffer
+    - btrfs: print message when tree-log replay starts
+    - scsi: qla2xxx: fix a potential NULL pointer dereference
+    - Revert "KVM: VMX: Add non-canonical check on writes to RTIT address MSRs"
+    - drm/gma500: Fixup fbdev stolen size usage evaluation
+    - brcmfmac: Fix use after free in brcmf_sdio_readframes()
+    - gianfar: Fix TX timestamping with a stacked DSA driver
+    - pinctrl: sh-pfc: sh7264: Fix CAN function GPIOs
+    - media: i2c: mt9v032: fix enum mbus codes and frame sizes
+    - media: sti: bdisp: fix a possible sleep-in-atomic-context bug in
+      bdisp_device_run()
+    - efi/x86: Map the entire EFI vendor string before copying it
+    - MIPS: Loongson: Fix potential NULL dereference in loongson3_platform_init()
+    - uio: fix a sleep-in-atomic-context bug in uio_dmem_genirq_irqcontrol()
+    - usb: gadget: udc: fix possible sleep-in-atomic-context bugs in gr_probe()
+    - nfs: NFS_SWAP should depend on SWAP
+    - jbd2: clear JBD2_ABORT flag before journal_reset to update log tail info
+      when load journal
+    - tracing: Fix very unlikely race of registering two stat tracers
+    - ext4, jbd2: ensure panic when aborting with zero errno
+    - kconfig: fix broken dependency in randconfig-generated .config
+    - clk: qcom: rcg2: Don't crash if our parent can't be found; return an error
+    - drm/amdgpu: remove 4 set but not used variable in
+      amdgpu_atombios_get_connector_info_from_object_table
+    - regulator: rk808: Lower log level on optional GPIOs being not available
+    - NFC: port100: Convert cpu_to_le16(le16_to_cpu(E1) + E2) to use
+      le16_add_cpu().
+    - reiserfs: Fix spurious unlock in reiserfs_fill_super() error handling
+    - ALSA: usx2y: Adjust indentation in snd_usX2Y_hwdep_dsp_status
+    - b43legacy: Fix -Wcast-function-type
+    - ipw2x00: Fix -Wcast-function-type
+    - iwlegacy: Fix -Wcast-function-type
+    - rtlwifi: rtl_pci: Fix -Wcast-function-type
+    - orinoco: avoid assertion in case of NULL pointer
+    - ACPICA: Disassembler: create buffer fields in ACPI_PARSE_LOAD_PASS1
+    - scsi: aic7xxx: Adjust indentation in ahc_find_syncrate
+    - ARM: dts: r8a7779: Add device node for ARM global timer
+    - x86/vdso: Provide missing include file
+    - pinctrl: sh-pfc: sh7269: Fix CAN function GPIOs
+    - ALSA: sh: Fix compile warning wrt const
+    - tools lib api fs: Fix gcc9 stringop-truncation compilation error
+    - usbip: Fix unsafe unaligned pointer usage
+    - soc/tegra: fuse: Correct straps' address for older Tegra124 device trees
+    - rcu: Use WRITE_ONCE() for assignments to ->pprev for hlist_nulls
+    - Input: edt-ft5x06 - work around first register access error
+    - wan: ixp4xx_hss: fix compile-testing on 64-bit
+    - ASoC: atmel: fix build error with CONFIG_SND_ATMEL_SOC_DMA=m
+    - PCI: Don't disable bridge BARs when assigning bus resources
+    - driver core: Print device when resources present in really_probe()
+    - drm/nouveau: Fix copy-paste error in nouveau_fence_wait_uevent_handler
+    - drm/vmwgfx: prevent memory leak in vmw_cmdbuf_res_add
+    - iommu/arm-smmu-v3: Use WRITE_ONCE() when changing validity of an STE
+    - scsi: iscsi: Don't destroy session if there are outstanding connections
+    - cmd64x: potential buffer overflow in cmd64x_program_timings()
+    - ide: serverworks: potential overflow in svwks_set_pio_mode()
+    - remoteproc: Initialize rproc_class before use
+    - s390/ftrace: generate traced function stack frame
+    - ALSA: hda - Add docking station support for Lenovo Thinkpad T420s
+    - jbd2: switch to use jbd2_journal_abort() when failed to submit the commit
+      record
+    - ARM: 8951/1: Fix Kexec compilation issue.
+    - hostap: Adjust indentation in prism2_hostapd_add_sta
+    - iwlegacy: ensure loop counter addr does not wrap and cause an infinite loop
+    - drm/nouveau/disp/nv50-: prevent oops when no channel method map provided
+    - trigger_next should increase position index
+    - radeon: insert 10ms sleep in dce5_crtc_load_lut
+    - ocfs2: fix a NULL pointer dereference when call
+      ocfs2_update_inode_fsync_trans()
+    - lib/scatterlist.c: adjust indentation in __sg_alloc_table
+    - reiserfs: prevent NULL pointer dereference in reiserfs_insert_item()
+    - bcache: explicity type cast in bset_bkey_last()
+    - irqchip/gic-v3-its: Reference to its_invall_cmd descriptor when building
+      INVALL
+    - microblaze: Prevent the overflow of the start
+    - brd: check and limit max_part par
+    - selinux: ensure we cleanup the internal AVC counters on error in
+      avc_update()
+    - enic: prevent waking up stopped tx queues over watchdog reset
+    - floppy: check FDC index for errors before assigning it
+    - staging: android: ashmem: Disallow ashmem memory from being remapped
+    - staging: vt6656: fix sign of rx_dbm to bb_pre_ed_rssi.
+    - usb: uas: fix a plug & unplug racing
+    - USB: Fix novation SourceControl XL after suspend
+    - USB: hub: Don't record a connect-change event during reset-resume
+    - staging: rtl8188eu: Fix potential security hole
+    - staging: rtl8188eu: Fix potential overuse of kernel memory
+    - x86/mce/amd: Fix kobject lifetime
+    - tty: serial: imx: setup the correct sg entry for tx dma
+    - xhci: apply XHCI_PME_STUCK_QUIRK to Intel Comet Lake platforms
+    - VT_RESIZEX: get rid of field-by-field copyin
+    - vt: vt_ioctl: fix race in VT_RESIZEX
+    - netfilter: xt_bpf: add overflow checks
+    - ext4: fix a data race in EXT4_I(inode)->i_disksize
+    - ext4: add cond_resched() to __ext4_find_entry()
+    - KVM: apic: avoid calculating pending eoi from an uninitialized val
+    - Btrfs: fix btrfs_wait_ordered_range() so that it waits for all ordered
+      extents
+    - scsi: Revert "RDMA/isert: Fix a recently introduced regression related to
+      logout"
+    - scsi: Revert "target: iscsi: Wait for all commands to finish before freeing
+      a session"
+    - ecryptfs: replace BUG_ON with error handling code
+    - ALSA: rawmidi: Avoid bit fields for state flags
+    - ALSA: seq: Avoid concurrent access to queue flags
+    - ALSA: seq: Fix concurrent access to queue current tick/time
+    - xen: Enable interrupts when calling _cond_resched()
+    - Linux 4.4.215
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sun, 05 Apr 2020 18:51:07 -0400
+
+linux (4.4.0-177.207) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-177.207 -proposed tracker (LP: #1867243)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+
+  * Xenial update: 4.4.214 upstream stable release (LP: #1864775)
+    - media: iguanair: fix endpoint sanity check
+    - x86/cpu: Update cached HLE state on write to TSX_CTRL_CPUID_CLEAR
+    - sparc32: fix struct ipc64_perm type definition
+    - ASoC: qcom: Fix of-node refcount unbalance to link->codec_of_node
+    - cls_rsvp: fix rsvp_policy
+    - net: hsr: fix possible NULL deref in hsr_handle_frame()
+    - net_sched: fix an OOB access in cls_tcindex
+    - tcp: clear tp->total_retrans in tcp_disconnect()
+    - tcp: clear tp->segs_{in|out} in tcp_disconnect()
+    - media: uvcvideo: Avoid cyclic entity chains due to malformed USB descriptors
+    - mfd: dln2: More sanity checking for endpoints
+    - brcmfmac: Fix memory leak in brcmf_usbdev_qinit
+    - usb: gadget: legacy: set max_speed to super-speed
+    - usb: gadget: f_ncm: Use atomic_t to track in-flight request
+    - usb: gadget: f_ecm: Use atomic_t to track in-flight request
+    - ALSA: dummy: Fix PCM format loop in proc output
+    - lib/test_kasan.c: fix memory leak in kmalloc_oob_krealloc_more()
+    - powerpc/pseries: Advance pfn if section is not present in lmb_is_removable()
+    - mmc: spi: Toggle SPI polarity, do not hardcode it
+    - PCI: keystone: Fix link training retries initiation
+    - crypto: api - Check spawn->alg under lock in crypto_drop_spawn
+    - scsi: qla2xxx: Fix mtcp dump collection failure
+    - power: supply: ltc2941-battery-gauge: fix use-after-free
+    - of: Add OF_DMA_DEFAULT_COHERENT & select it on powerpc
+    - dm space map common: fix to ensure new block isn't already in use
+    - crypto: pcrypt - Do not clear MAY_SLEEP flag in original request
+    - crypto: api - Fix race condition in crypto_spawn_alg
+    - crypto: picoxcell - adjust the position of tasklet_init and fix missed
+      tasklet_kill
+    - btrfs: set trans->drity in btrfs_commit_transaction
+    - ARM: tegra: Enable PLLP bypass during Tegra124 LP1
+    - mwifiex: fix unbalanced locking in mwifiex_process_country_ie()
+    - sunrpc: expiry_time should be seconds not timeval
+    - KVM: x86: Refactor prefix decoding to prevent Spectre-v1/L1TF attacks
+    - KVM: x86: Protect DR-based index computations from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF
+      attacks
+    - KVM: x86: Protect ioapic_write_indirect() from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect MSR-based index computations in pmu.h from Spectre-v1/L1TF
+      attacks
+    - KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect MSR-based index computations from Spectre-v1/L1TF attacks
+      in x86.c
+    - KVM: x86: Protect x86_decode_insn from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect MSR-based index computations in fixed_msr_to_seg_unit()
+      from Spectre-v1/L1TF attacks
+    - KVM: PPC: Book3S HV: Uninit vCPU if vcore creation fails
+    - KVM: PPC: Book3S PR: Free shared page if mmu initialization fails
+    - KVM: x86: Free wbinvd_dirty_mask if vCPU creation fails
+    - scsi: qla2xxx: Fix the endianness of the qla82xx_get_fw_size() return type
+    - scsi: csiostor: Adjust indentation in csio_device_reset
+    - scsi: qla4xxx: Adjust indentation in qla4xxx_mem_free
+    - ext2: Adjust indentation in ext2_fill_super
+    - powerpc/44x: Adjust indentation in ibm4xx_denali_fixup_memsize
+    - NFC: pn544: Adjust indentation in pn544_hci_check_presence
+    - ppp: Adjust indentation into ppp_async_input
+    - net: smc911x: Adjust indentation in smc911x_phy_configure
+    - net: tulip: Adjust indentation in {dmfe, uli526x}_init_module
+    - mfd: da9062: Fix watchdog compatible string
+    - mfd: rn5t618: Mark ADC control register volatile
+    - net: systemport: Avoid RBUF stuck in Wake-on-LAN mode
+    - bonding/alb: properly access headers in bond_alb_xmit()
+    - NFS: Fix memory leaks and corruption in readdir
+    - NFS: Fix bool initialization/comparison
+    - NFS: Directory page cache pages need to be locked when read
+    - Btrfs: fix assertion failure on fsync with NO_HOLES enabled
+    - btrfs: remove trivial locking wrappers of tree mod log
+    - Btrfs: fix race between adding and putting tree mod seq elements and nodes
+    - drm: atmel-hlcdc: enable clock before configuring timing engine
+    - KVM: x86: drop picdev_in_range()
+    - KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks
+    - KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect kvm_lapic_reg_write() from Spectre-v1/L1TF attacks
+    - btrfs: flush write bio if we loop in extent_write_cache_pages
+    - KVM: x86/mmu: Apply max PA check for MMIO sptes to 32-bit KVM
+    - KVM: VMX: Add non-canonical check on writes to RTIT address MSRs
+    - KVM: nVMX: vmread should not set rflags to specify success in case of #PF
+    - cifs: fail i/o on soft mounts if sessionsetup errors out
+    - clocksource: Prevent double add_timer_on() for watchdog_timer
+    - perf/core: Fix mlock accounting in perf_mmap()
+    - ASoC: pcm: update FE/BE trigger order based on the command
+    - scsi: ufs: Fix ufshcd_probe_hba() reture value in case
+      ufshcd_scsi_add_wlus() fails
+    - rtc: hym8563: Return -EINVAL if the time is known to be invalid
+    - ARC: [plat-axs10x]: Add missing multicast filter number to GMAC node
+    - ARM: dts: at91: sama5d3: fix maximum peripheral clock rates
+    - ARM: dts: at91: sama5d3: define clock rate range for tcb1
+    - powerpc/pseries: Allow not having ibm, hypertas-functions::hcall-multi-tce
+      for DDW
+    - pinctrl: sh-pfc: r8a7778: Fix duplicate SDSELF_B and SD1_CLK_B
+    - mwifiex: Fix possible buffer overflows in mwifiex_ret_wmm_get_status()
+    - mwifiex: Fix possible buffer overflows in mwifiex_cmd_append_vsie_tlv()
+    - libertas: don't exit from lbs_ibss_join_existing() with RCU read lock held
+    - libertas: make lbs_ibss_join_existing() return error code on rates overflow
+    - Linux 4.4.214
+
+  * 5.4.0-11 crash on cryptsetup open (LP: #1860231) // Xenial update: 4.4.214
+    upstream stable release (LP: #1864775)
+    - dm: fix potential for q->make_request_fn NULL pointer
+
+  * Xenial update: 4.4.213 upstream stable release (LP: #1864774)
+    - ALSA: pcm: Add missing copy ops check before clearing buffer
+    - orinoco_usb: fix interface sanity check
+    - rsi_91x_usb: fix interface sanity check
+    - USB: serial: ir-usb: add missing endpoint sanity check
+    - USB: serial: ir-usb: fix link-speed handling
+    - USB: serial: ir-usb: fix IrLAP framing
+    - staging: most: net: fix buffer overflow
+    - staging: wlan-ng: ensure error return is actually returned
+    - staging: vt6656: correct packet types for CTS protect, mode.
+    - staging: vt6656: use NULLFUCTION stack on mac80211
+    - staging: vt6656: Fix false Tx excessive retries reporting.
+    - ath9k: fix storage endpoint lookup
+    - brcmfmac: fix interface sanity check
+    - rtl8xxxu: fix interface sanity check
+    - zd1211rw: fix storage endpoint lookup
+    - watchdog: rn5t618_wdt: fix module aliases
+    - drivers/net/b44: Change to non-atomic bit operations on pwol_mask
+    - net: wan: sdla: Fix cast from pointer to integer of different size
+    - atm: eni: fix uninitialized variable warning
+    - usb-storage: Disable UAS on JMicron SATA enclosure
+    - net_sched: ematch: reject invalid TCF_EM_SIMPLE
+    - crypto: af_alg - Use bh_lock_sock in sk_destruct
+    - crypto: pcrypt - Fix user-after-free on module unload
+    - arm64: kbuild: remove compressed images on 'make ARCH=arm64 (dist)clean'
+    - mm/mempolicy.c: fix out of bounds write in mpol_parse_str()
+    - reiserfs: Fix memory leak of journal device string
+    - media: digitv: don't continue if remote control state can't be read
+    - media: gspca: zero usb_buf
+    - media: dvb-usb/dvb-usb-urb.c: initialize actlen to 0
+    - ttyprintk: fix a potential deadlock in interrupt context issue
+    - usb: dwc3: turn off VBUS when leaving host mode
+    - media: si470x-i2c: Move free() past last use of 'radio'
+    - clk: mmp2: Fix the order of timer mux parents
+    - ixgbevf: Remove limit of 10 entries for unicast filter list
+    - ixgbe: Fix calculation of queue with VFs and flow director on interface flap
+    - wireless: wext: avoid gcc -O3 warning
+    - vti[6]: fix packet tx through bpf_redirect()
+    - scsi: fnic: do not queue commands during fwreset
+    - airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE
+    - airo: Add missing CAP_NET_ADMIN check in AIROOLDIOCTL/SIOCDEVPRIVATE
+    - r8152: get default setting of WOL before initializing
+    - qlcnic: Fix CPU soft lockup while collecting firmware dump
+    - net/fsl: treat fsl,erratum-a011043
+    - net/sonic: Add mutual exclusion for accessing shared state
+    - net/sonic: Use MMIO accessors
+    - net/sonic: Fix receive buffer handling
+    - net/sonic: Quiesce SONIC before re-initializing descriptor memory
+    - seq_tab_next() should increase position index
+    - l2t_seq_next should increase position index
+    - net: Fix skb->csum update in inet_proto_csum_replace16().
+    - btrfs: fix mixed block count of available space
+    - btrfs: do not zero f_bavail if we have available space
+    - Linux 4.4.213
+
+  * Xenial update: 4.4.212 upstream stable release (LP: #1864773)
+    - powerpc/archrandom: fix arch_get_random_seed_int()
+    - mt7601u: fix bbp version check in mt7601u_wait_bbp_ready
+    - drm/virtio: fix bounds check in virtio_gpu_cmd_get_capset()
+    - ALSA: hda: fix unused variable warning
+    - ALSA: usb-audio: update quirk for B&W PX to remove microphone
+    - staging: comedi: ni_mio_common: protect register write overflow
+    - pcrypt: use format specifier in kobject_add
+    - exportfs: fix 'passing zero to ERR_PTR()' warning
+    - drm/dp_mst: Skip validating ports during destruction, just ref
+    - pinctrl: sh-pfc: r8a7740: Add missing REF125CK pin to gether_gmii group
+    - pinctrl: sh-pfc: r8a7740: Add missing LCD0 marks to lcd0_data24_1 group
+    - pinctrl: sh-pfc: r8a7791: Remove bogus ctrl marks from qspi_data4_b group
+    - pinctrl: sh-pfc: r8a7791: Remove bogus marks from vin1_b_data18 group
+    - pinctrl: sh-pfc: sh73a0: Add missing TO pin to tpu4_to3 group
+    - pinctrl: sh-pfc: r8a7794: Remove bogus IPSR9 field
+    - pinctrl: sh-pfc: sh7734: Add missing IPSR11 field
+    - pinctrl: sh-pfc: sh7269: Add missing PCIOR0 field
+    - pinctrl: sh-pfc: sh7734: Remove bogus IPSR10 value
+    - Input: nomadik-ske-keypad - fix a loop timeout test
+    - clk: highbank: fix refcount leak in hb_clk_init()
+    - clk: qoriq: fix refcount leak in clockgen_init()
+    - clk: socfpga: fix refcount leak
+    - clk: samsung: exynos4: fix refcount leak in exynos4_get_xom()
+    - clk: imx6q: fix refcount leak in imx6q_clocks_init()
+    - clk: imx6sx: fix refcount leak in imx6sx_clocks_init()
+    - clk: imx7d: fix refcount leak in imx7d_clocks_init()
+    - clk: vf610: fix refcount leak in vf610_clocks_init()
+    - clk: armada-370: fix refcount leak in a370_clk_init()
+    - clk: kirkwood: fix refcount leak in kirkwood_clk_init()
+    - clk: armada-xp: fix refcount leak in axp_clk_init()
+    - IB/usnic: Fix out of bounds index check in query pkey
+    - RDMA/ocrdma: Fix out of bounds index check in query pkey
+    - media: s5p-jpeg: Correct step and max values for
+      V4L2_CID_JPEG_RESTART_INTERVAL
+    - crypto: tgr192 - fix unaligned memory access
+    - ASoC: imx-sgtl5000: put of nodes if finding codec fails
+    - rtc: cmos: ignore bogus century byte
+    - tty: ipwireless: Fix potential NULL pointer dereference
+    - rtc: ds1672: fix unintended sign extension
+    - rtc: 88pm860x: fix unintended sign extension
+    - rtc: 88pm80x: fix unintended sign extension
+    - rtc: pm8xxx: fix unintended sign extension
+    - fbdev: chipsfb: remove set but not used variable 'size'
+    - pinctrl: sh-pfc: emev2: Add missing pinmux functions
+    - pinctrl: sh-pfc: r8a7791: Fix scifb2_data_c pin group
+    - pinctrl: sh-pfc: sh73a0: Fix fsic_spdif pin groups
+    - block: don't use bio->bi_vcnt to figure out segment number
+    - vfio_pci: Enable memory accesses before calling pci_map_rom
+    - cdc-wdm: pass return value of recover_from_urb_loss
+    - drm/nouveau/bios/ramcfg: fix missing parentheses when calculating RON
+    - drm/nouveau/pmu: don't print reply values if exec is false
+    - ASoC: qcom: Fix of-node refcount unbalance in apq8016_sbc_parse_of()
+    - fs/nfs: Fix nfs_parse_devname to not modify it's argument
+    - clocksource/drivers/sun5i: Fail gracefully when clock rate is unavailable
+    - ARM: 8847/1: pm: fix HYP/SVC mode mismatch when MCPM is used
+    - regulator: wm831x-dcdc: Fix list of wm831x_dcdc_ilim from mA to uA
+    - nios2: ksyms: Add missing symbol exports
+    - scsi: megaraid_sas: reduce module load time
+    - xen, cpu_hotplug: Prevent an out of bounds access
+    - net: sh_eth: fix a missing check of of_get_phy_mode
+    - media: ivtv: update *pos correctly in ivtv_read_pos()
+    - media: cx18: update *pos correctly in cx18_read_pos()
+    - media: wl128x: Fix an error code in fm_download_firmware()
+    - media: cx23885: check allocation return
+    - jfs: fix bogus variable self-initialization
+    - m68k: mac: Fix VIA timer counter accesses
+    - ARM: OMAP2+: Fix potentially uninitialized return value for _setup_reset()
+    - media: davinci-isif: avoid uninitialized variable use
+    - spi: tegra114: clear packed bit for unpacked mode
+    - spi: tegra114: fix for unpacked mode transfers
+    - soc/fsl/qe: Fix an error code in qe_pin_request()
+    - spi: bcm2835aux: fix driver to not allow 65535 (=-1) cs-gpios
+    - ehea: Fix a copy-paste err in ehea_init_port_res
+    - scsi: qla2xxx: Unregister chrdev if module initialization fails
+    - ARM: pxa: ssp: Fix "WARNING: invalid free of devm_ allocated data"
+    - hwmon: (w83627hf) Use request_muxed_region for Super-IO accesses
+    - tipc: set sysctl_tipc_rmem and named_timeout right range
+    - powerpc: vdso: Make vdso32 installation conditional in vdso_install
+    - media: ov2659: fix unbalanced mutex_lock/unlock
+    - 6lowpan: Off by one handling ->nexthdr
+    - dmaengine: axi-dmac: Don't check the number of frames for alignment
+    - ALSA: usb-audio: Handle the error from snd_usb_mixer_apply_create_quirk()
+    - packet: in recvmsg msg_name return at least sizeof sockaddr_ll
+    - ASoC: fix valid stream condition
+    - IB/mlx5: Add missing XRC options to QP optional params mask
+    - iommu/vt-d: Make kernel parameter igfx_off work with vIOMMU
+    - media: omap_vout: potential buffer overflow in vidioc_dqbuf()
+    - media: davinci/vpbe: array underflow in vpbe_enum_outputs()
+    - platform/x86: alienware-wmi: printing the wrong error code
+    - netfilter: ebtables: CONFIG_COMPAT: reject trailing data after last rule
+    - ARM: riscpc: fix lack of keyboard interrupts after irq conversion
+    - kdb: do a sanity check on the cpu in kdb_per_cpu()
+    - backlight: lm3630a: Return 0 on success in update_status functions
+    - thermal: cpu_cooling: Actually trace CPU load in thermal_power_cpu_get_power
+    - spi: spi-fsl-spi: call spi_finalize_current_message() at the end
+    - misc: sgi-xp: Properly initialize buf in xpc_get_rsvd_page_pa
+    - iommu: Use right function to get group for device
+    - signal/cifs: Fix cifs_put_tcp_session to call send_sig instead of force_sig
+    - inet: frags: call inet_frags_fini() after unregister_pernet_subsys()
+    - media: vivid: fix incorrect assignment operation when setting video mode
+    - powerpc/cacheinfo: add cacheinfo_teardown, cacheinfo_rebuild
+    - drm/msm/mdp5: Fix mdp5_cfg_init error return
+    - net/af_iucv: always register net_device notifier
+    - ASoC: ti: davinci-mcasp: Fix slot mask settings when using multiple AXRs
+    - rtc: pcf8563: Clear event flags and disable interrupts before requesting irq
+    - drm/msm/a3xx: remove TPL1 regs from snapshot
+    - iommu/amd: Make iommu_disable safer
+    - mfd: intel-lpss: Release IDA resources
+    - devres: allow const resource arguments
+    - net: pasemi: fix an use-after-free in pasemi_mac_phy_init()
+    - scsi: libfc: fix null pointer dereference on a null lport
+    - libertas_tf: Use correct channel range in lbtf_geo_init
+    - usb: host: xhci-hub: fix extra endianness conversion
+    - mic: avoid statically declaring a 'struct device'.
+    - x86/kgbd: Use NMI_VECTOR not APIC_DM_NMI
+    - ALSA: aoa: onyx: always initialize register read value
+    - cifs: fix rmmod regression in cifs.ko caused by force_sig changes
+    - crypto: caam - free resources in case caam_rng registration failed
+    - ext4: set error return correctly when ext4_htree_store_dirent fails
+    - ASoC: es8328: Fix copy-paste error in es8328_right_line_controls
+    - ASoC: cs4349: Use PM ops 'cs4349_runtime_pm'
+    - ASoC: wm8737: Fix copy-paste error in wm8737_snd_controls
+    - signal: Allow cifs and drbd to receive their terminating signals
+    - dmaengine: dw: platform: Switch to acpi_dma_controller_register()
+    - mac80211: minstrel_ht: fix per-group max throughput rate initialization
+    - mips: avoid explicit UB in assignment of mips_io_port_base
+    - ahci: Do not export local variable ahci_em_messages
+    - Partially revert "kfifo: fix kfifo_alloc() and kfifo_init()"
+    - power: supply: Init device wakeup after device_add()
+    - x86, perf: Fix the dependency of the x86 insn decoder selftest
+    - bcma: fix incorrect update of BCMA_CORE_PCI_MDIO_DATA
+    - iio: dac: ad5380: fix incorrect assignment to val
+    - ath9k: dynack: fix possible deadlock in ath_dynack_node_{de}init
+    - net: sonic: return NETDEV_TX_OK if failed to map buffer
+    - Btrfs: fix hang when loading existing inode cache off disk
+    - hwmon: (shtc1) fix shtc1 and shtw1 id mask
+    - net: sonic: replace dev_kfree_skb in sonic_send_packet
+    - net/rds: Fix 'ib_evt_handler_call' element in 'rds_ib_stat_names'
+    - iommu/amd: Wait for completion of IOTLB flush in attach_device
+    - net: hisilicon: Fix signedness bug in hix5hd2_dev_probe()
+    - net: broadcom/bcmsysport: Fix signedness in bcm_sysport_probe()
+    - net: ethernet: stmmac: Fix signedness bug in ipq806x_gmac_of_parse()
+    - mac80211: accept deauth frames in IBSS mode
+    - llc: fix another potential sk_buff leak in llc_ui_sendmsg()
+    - llc: fix sk_buff refcounting in llc_conn_state_process()
+    - net: stmmac: fix length of PTP clock's name string
+    - drm/msm/dsi: Implement reset correctly
+    - dmaengine: imx-sdma: fix size check for sdma script_number
+    - net: qca_spi: Move reset_count to struct qcaspi
+    - media: ov6650: Fix incorrect use of JPEG colorspace
+    - media: ov6650: Fix some format attributes not under control
+    - media: ov6650: Fix .get_fmt() V4L2_SUBDEV_FORMAT_TRY support
+    - MIPS: Loongson: Fix return value of loongson_hwmon_init
+    - net: neigh: use long type to store jiffies delta
+    - packet: fix data-race in fanout_flow_is_huge()
+    - dmaengine: ti: edma: fix missed failure handling
+    - drm/radeon: fix bad DMA from INTERRUPT_CNTL2
+    - arm64: dts: juno: Fix UART frequency
+    - m68k: Call timer_interrupt() with interrupts disabled
+    - firestream: fix memory leaks
+    - net: cxgb3_main: Add CAP_NET_ADMIN check to CHELSIO_GET_MEM
+    - net, ip_tunnel: fix namespaces move
+    - net_sched: fix datalen for ematch
+    - net: usb: lan78xx: Add .ndo_features_check
+    - hwmon: (adt7475) Make volt2reg return same reg as reg2volt input
+    - Input: keyspan-remote - fix control-message timeouts
+    - ARM: 8950/1: ftrace/recordmcount: filter relocation types
+    - mmc: sdhci: fix minimum clock rate for v3 controller
+    - Input: sur40 - fix interface sanity checks
+    - Input: gtco - fix endpoint sanity check
+    - Input: aiptek - fix endpoint sanity check
+    - hwmon: (nct7802) Fix voltage limits to wrong registers
+    - scsi: RDMA/isert: Fix a recently introduced regression related to logout
+    - tracing: xen: Ordered comparison of function pointers
+    - iio: buffer: align the size of scan bytes to size of the largest element
+    - scsi: iscsi: Avoid potential deadlock in iscsi_if_rx func
+    - md: Avoid namespace collision with bitmap API
+    - bitmap: Add bitmap_alloc(), bitmap_zalloc() and bitmap_free()
+    - netfilter: ipset: use bitmap infrastructure completely
+    - net/x25: fix nonblocking connect
+    - Revert "UBUNTU: SAUCE: libertas: Fix two buffer overflows at parsing bss
+      descriptor"
+    - libertas: Fix two buffer overflows at parsing bss descriptor
+    - Linux 4.4.212
+
+  * CVE-2020-8428
+    - do_last(): fetch directory ->i_mode and ->i_uid before it's too late
+    - vfs: fix do_last() regression
+
+  * xfs fill_fs test in fallocate06 from ubuntu_ltp_syscalls failed
+    (LP: #1865967)
+    - xfs: Fix tail rounding in xfs_alloc_file_space()
+
+  * ipc/sem.c : process loops infinitely in exit_sem() (LP: #1858834)
+    - Revert "ipc, sem: remove uneeded sem_undo_list lock usage in exit_sem()"
+
+  * quotactl07 from ubuntu_ltp_syscalls failed (LP: #1864092)
+    - xfs: Sanity check flags of Q_XQUOTARM call
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sun, 15 Mar 2020 19:16:50 -0400
+
+linux (4.4.0-176.206) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-176.206 -proposed tracker (LP: #1865106)
+
+  * CVE-2020-2732
+    - x86/vdso: Use RDPID in preference to LSL when available
+    - KVM: x86: emulate RDPID
+    - KVM: nVMX: Don't emulate instructions in guest mode
+    - KVM: nVMX: Refactor IO bitmap checks into helper function
+    - KVM: nVMX: Check IO instruction VM-exit conditions
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Thu, 27 Feb 2020 23:41:44 -0500
+
+linux (4.4.0-175.205) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-175.205 -proposed tracker (LP: #1863338)
+
+  * run_afpackettests in ubuntu_kernel_selftests failed with "./in_netns.sh:
+    Permission denied" (LP: #1861973)
+    - [Debian] autoreconstruct - add resoration of execute permissions
+
+  * pty03 from pty in ubuntu_ltp failed on Eoan (LP: #1862114)
+    - can, slip: Protect tty->disc_data in write_wakeup and close with RCU
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Fri, 14 Feb 2020 16:27:12 -0300
+
+linux (4.4.0-174.204) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-174.204 -proposed tracker (LP: #1861122)
+
+  * Xenial update: 4.4.211 upstream stable release (LP: #1860681)
+    - hidraw: Return EPOLLOUT from hidraw_poll
+    - HID: hidraw: Fix returning EPOLLOUT from hidraw_poll
+    - HID: hidraw, uhid: Always report EPOLLOUT
+    - cfg80211/mac80211: make ieee80211_send_layer2_update a public function
+    - mac80211: Do not send Layer 2 Update frame before authorization
+    - media: usb:zr364xx:Fix KASAN:null-ptr-deref Read in zr364xx_vidioc_querycap
+    - p54usb: Fix race between disconnect and firmware loading
+    - ALSA: line6: Fix write on zero-sized buffer
+    - ALSA: line6: Fix memory leak at line6_init_pcm() error path
+    - xen: let alloc_xenballooned_pages() fail if not enough memory free
+    - wimax: i2400: fix memory leak
+    - wimax: i2400: Fix memory leak in i2400m_op_rfkill_sw_toggle
+    - ext4: fix use-after-free race with debug_want_extra_isize
+    - ext4: add more paranoia checking in ext4_expand_extra_isize handling
+    - rtc: mt6397: fix alarm register overwrite
+    - iommu: Remove device link to group on failure
+    - gpio: Fix error message on out-of-range GPIO in lookup table
+    - hsr: reset network header when supervision frame is created
+    - cifs: Adjust indentation in smb2_open_file
+    - RDMA/srpt: Report the SCSI residual to the initiator
+    - scsi: enclosure: Fix stale device oops with hot replug
+    - scsi: sd: Clear sdkp->protection_type if disk is reformatted without PI
+    - platform/x86: asus-wmi: Fix keyboard brightness cannot be set to 0
+    - iio: imu: adis16480: assign bias value only if operation succeeded
+    - mei: fix modalias documentation
+    - clk: samsung: exynos5420: Preserve CPU clocks configuration during
+      suspend/resume
+    - compat_ioctl: handle SIOCOUTQNSD
+    - tty: serial: imx: use the sg count from dma_map_sg
+    - tty: serial: pch_uart: correct usage of dma_unmap_sg
+    - media: exynos4-is: Fix recursive locking in isp_video_release()
+    - spi: atmel: fix handling of cs_change set on non-last xfer
+    - rtlwifi: Remove unnecessary NULL check in rtl_regd_init
+    - rtc: msm6242: Fix reading of 10-hour digit
+    - rseq/selftests: Turn off timeout setting
+    - hexagon: work around compiler crash
+    - ocfs2: call journal flush to mark journal as empty after journal recovery
+      when mount
+    - ALSA: seq: Fix racy access for queue timer in proc read
+    - Fix built-in early-load Intel microcode alignment
+    - block: fix an integer overflow in logical block size
+    - USB: serial: simple: Add Motorola Solutions TETRA MTP3xxx and MTP85xx
+    - USB: serial: opticon: fix control-message timeouts
+    - USB: serial: suppress driver bind attributes
+    - USB: serial: ch341: handle unbound port at reset_resume
+    - USB: serial: io_edgeport: add missing active-port sanity check
+    - USB: serial: quatech2: handle unbound ports
+    - scsi: mptfusion: Fix double fetch bug in ioctl
+    - usb: core: hub: Improved device recognition on remote wakeup
+    - x86/efistub: Disable paging at mixed mode entry
+    - mm/page-writeback.c: avoid potential division by zero in wb_min_max_ratio()
+    - net: stmmac: 16KB buffer must be 16 byte aligned
+    - net: stmmac: Enable 16KB buffer size
+    - USB: serial: io_edgeport: use irqsave() in USB's complete callback
+    - USB: serial: io_edgeport: handle unbound ports on URB completion
+    - USB: serial: keyspan: handle unbound ports
+    - scsi: fnic: use kernel's '%pM' format option to print MAC
+    - scsi: fnic: fix invalid stack access
+    - arm64: dts: agilex/stratix10: fix pmu interrupt numbers
+    - netfilter: fix a use-after-free in mtype_destroy()
+    - batman-adv: Fix DAT candidate selection on little endian systems
+    - macvlan: use skb_reset_mac_header() in macvlan_queue_xmit()
+    - r8152: add missing endpoint sanity check
+    - tcp: fix marked lost packets not being retransmitted
+    - net: usb: lan78xx: limit size of local TSO packets
+    - xen/blkfront: Adjust indentation in xlvbd_alloc_gendisk
+    - cw1200: Fix a signedness bug in cw1200_load_firmware()
+    - cfg80211: check for set_wiphy_params
+    - scsi: esas2r: unlock on error in esas2r_nvram_read_direct()
+    - scsi: qla4xxx: fix double free bug
+    - scsi: bnx2i: fix potential use after free
+    - scsi: target: core: Fix a pr_debug() argument
+    - scsi: core: scsi_trace: Use get_unaligned_be*()
+    - perf probe: Fix wrong address verification
+    - regulator: ab8500: Remove SYSCLKREQ from enum ab8505_regulator_id
+    - Linux 4.4.211
+
+  * Xenial update: 4.4.210 upstream stable release (LP: #1859865)
+    - chardev: Avoid potential use-after-free in 'chrdev_open()'
+    - usb: chipidea: host: Disable port power only if previously enabled
+    - ALSA: usb-audio: Apply the sample rate quirk for Bose Companion 5
+    - kernel/trace: Fix do not unregister tracepoints when register
+      sched_migrate_task fail
+    - tracing: Have stack tracer compile when MCOUNT_INSN_SIZE is not defined
+    - HID: Fix slab-out-of-bounds read in hid_field_extract
+    - HID: uhid: Fix returning EPOLLOUT from uhid_char_poll
+    - HID: hid-input: clear unmapped usages
+    - Input: add safety guards to input_set_keycode()
+    - drm/dp_mst: correct the shifting in DP_REMOTE_I2C_READ
+    - can: gs_usb: gs_usb_probe(): use descriptors of current altsetting
+    - can: mscan: mscan_rx_poll(): fix rx path lockup when returning from polling
+      to irq mode
+    - can: can_dropped_invalid_skb(): ensure an initialized headroom in outgoing
+      CAN sk_buffs
+    - staging: vt6656: set usb_set_intfdata on driver fail.
+    - USB: serial: option: add ZLP support for 0x1bc7/0x9010
+    - usb: musb: Disable pullup at init
+    - usb: musb: dma: Correct parameter passed to IRQ handler
+    - staging: rtl8188eu: Add device code for TP-Link TL-WN727N v5.21
+    - tty: link tty and port before configuring it as console
+    - tty: always relink the port
+    - mwifiex: pcie: Fix memory leak in mwifiex_pcie_alloc_cmdrsp_buf
+    - scsi: bfa: release allocated memory in case of error
+    - rtl8xxxu: prevent leaking urb
+    - USB: Fix: Don't skip endpoint descriptors with maxpacket=0
+    - netfilter: arp_tables: init netns pointer in xt_tgchk_param struct
+    - netfilter: ipset: avoid null deref when IPSET_ATTR_LINENO is present
+    - Linux 4.4.210
+
+  * Xenial update: 4.4.209 upstream stable release (LP: #1859640)
+    - PM / devfreq: Don't fail devfreq_dev_release if not in list
+    - RDMA/cma: add missed unregister_pernet_subsys in init failure
+    - scsi: lpfc: Fix memory leak on lpfc_bsg_write_ebuf_set func
+    - scsi: qla2xxx: Don't call qlt_async_event twice
+    - scsi: iscsi: qla4xxx: fix double free in probe
+    - scsi: libsas: stop discovering if oob mode is disconnected
+    - usb: gadget: fix wrong endpoint desc
+    - md: raid1: check rdev before reference in raid1_sync_request func
+    - s390/cpum_sf: Adjust sampling interval to avoid hitting sample limits
+    - s390/cpum_sf: Avoid SBD overflow condition in irq handler
+    - xen/balloon: fix ballooned page accounting without hotplug enabled
+    - xfs: fix mount failure crash on invalid iclog memory access
+    - taskstats: fix data-race
+    - ALSA: ice1724: Fix sleep-in-atomic in Infrasonic Quartet support code
+    - MIPS: Avoid VDSO ABI breakage due to global register variable
+    - locks: print unsigned ino in /proc/locks
+    - dmaengine: Fix access to uninitialized dma_slave_caps
+    - compat_ioctl: block: handle Persistent Reservations
+    - gpiolib: fix up emulated open drain outputs
+    - ALSA: cs4236: fix error return comparison of an unsigned integer
+    - ftrace: Avoid potential division by zero in function profiler
+    - Bluetooth: btusb: fix PM leak in error case of setup
+    - Bluetooth: delete a stray unlock
+    - tty: serial: msm_serial: Fix lockup for sysrq and oops
+    - drm/mst: Fix MST sideband up-reply failure handling
+    - powerpc/pseries/hvconsole: Fix stack overread via udbg
+    - ath9k_htc: Modify byte order for an error message
+    - ath9k_htc: Discard undersized packets
+    - net: add annotations on hh->hh_len lockless accesses
+    - s390/smp: fix physical to logical CPU map for SMT
+    - locking/x86: Remove the unused atomic_inc_short() methd
+    - pstore/ram: Write new dumps to start of recycled zones
+    - locking/spinlock/debug: Fix various data races
+    - netfilter: ctnetlink: netns exit must wait for callbacks
+    - ARM: vexpress: Set-up shared OPP table instead of individual for each CPU
+    - netfilter: uapi: Avoid undefined left-shift in xt_sctp.h
+    - ARM: dts: am437x-gp/epos-evm: fix panel compatible
+    - powerpc: Ensure that swiotlb buffer is allocated from low memory
+    - bnx2x: Do not handle requests from VFs after parity
+    - bnx2x: Fix logic to get total no. of PFs per engine
+    - net: usb: lan78xx: Fix error message format specifier
+    - rfkill: Fix incorrect check to avoid NULL pointer dereference
+    - ASoC: wm8962: fix lambda value
+    - regulator: rn5t618: fix module aliases
+    - kconfig: don't crash on NULL expressions in expr_eq()
+    - parisc: Fix compiler warnings in debug_core.c
+    - llc2: Fix return statement of llc_stat_ev_rx_null_dsap_xid_c (and _test_c)
+    - net: stmmac: dwmac-sunxi: Allow all RGMII modes
+    - net: usb: lan78xx: fix possible skb leak
+    - pkt_sched: fq: do not accept silly TCA_FQ_QUANTUM
+    - sctp: free cmd->obj.chunk for the unprocessed SCTP_CMD_REPLY
+    - tcp: fix "old stuff" D-SACK causing SACK to be treated as D-SACK
+    - vlan: vlan_changelink() should propagate errors
+    - vlan: fix memory leak in vlan_dev_set_egress_priority
+    - vxlan: fix tos value before xmit
+    - macvlan: do not assume mac_header is set in macvlan_broadcast()
+    - USB: core: fix check for duplicate endpoints
+    - USB: serial: option: add Telit ME910G1 0x110a composition
+    - Linux 4.4.209
+
+  * overlayfs : broken access to r/w files (LP: #1851243)
+    - SAUCE: Revert "ovl: modify ovl_permission() to do checks on two inodes"
+
+  * net selftest psock_fanout fails on xenial s390x due to incorrect queue
+    lengths (LP: #1853375)
+    - selftests/net: cleanup unused parameter in psock_fanout
+    - selftests/net: ignore background traffic in psock_fanout
+
+  * multi-zone raid0 corruption (LP: #1850540)
+    - md/raid0: avoid RAID0 data corruption due to layout confusion.
+    - md: add feature flag MD_FEATURE_RAID0_LAYOUT
+    - md/raid0: fix warning message for parameter default_layout
+    - md/raid0: Fix an error message in raid0_make_request()
+    - SAUCE: md/raid0: Link to wiki with guidance on multi-zone RAID0 layout
+      migration
+    - SAUCE: md/raid0: Use kernel specific layout
+
+  * CVE-2019-20096
+    - dccp: Fix memleak in __feat_register_sp
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 29 Jan 2020 00:47:22 -0500
+
+linux (4.4.0-173.203) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-173.203 -proposed tracker (LP: #1859718)
+
+  * CVE-2019-14615
+    - drm/i915/gen9: Clear residual context state on context switch
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Tue, 14 Jan 2020 22:02:26 -0300
+
+linux (4.4.0-172.202) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-172.202 -proposed tracker (LP: #1858594)
+
+  * tools/perf fails to build after Xenial update to 4.4.208 upstream stable
+    release (LP: #1858798)
+    - Revert "perf report: Add warning when libunwind not compiled in"
+
+  * CVE-2019-18885
+    - btrfs: refactor btrfs_find_device() take fs_devices as argument
+    - btrfs: merge btrfs_find_device and find_device
+
+  *  Integrate Intel SGX driver into linux-azure (LP: #1844245)
+    - [Packaging] Add systemd service to load intel_sgx
+
+  * Xenial update: 4.4.208 upstream stable release (LP: #1858462)
+    - btrfs: do not leak reloc root if we fail to read the fs root
+    - btrfs: handle ENOENT in btrfs_uuid_tree_iterate
+    - ALSA: hda/ca0132 - Keep power on during processing DSP response
+    - ALSA: hda/ca0132 - Avoid endless loop
+    - drm: mst: Fix query_payload ack reply struct
+    - iio: light: bh1750: Resolve compiler warning and make code more readable
+    - spi: Add call to spi_slave_abort() function when spidev driver is released
+    - staging: rtl8188eu: fix possible null dereference
+    - rtlwifi: prevent memory leak in rtl_usb_probe
+    - IB/iser: bound protection_sg size by data_sg size
+    - media: am437x-vpfe: Setting STD to current value is not an error
+    - media: i2c: ov2659: fix s_stream return value
+    - media: i2c: ov2659: Fix missing 720p register config
+    - media: ov6650: Fix stored frame format not in sync with hardware
+    - tools/power/cpupower: Fix initializer override in hsw_ext_cstates
+    - usb: renesas_usbhs: add suspend event support in gadget mode
+    - hwrng: omap3-rom - Call clk_disable_unprepare() on exit only if not idled
+    - regulator: max8907: Fix the usage of uninitialized variable in
+      max8907_regulator_probe()
+    - media: flexcop-usb: fix NULL-ptr deref in flexcop_usb_transfer_init()
+    - samples: pktgen: fix proc_cmd command result check logic
+    - mwifiex: pcie: Fix memory leak in mwifiex_pcie_init_evt_ring
+    - media: ti-vpe: vpe: fix a v4l2-compliance warning about invalid pixel format
+    - media: ti-vpe: vpe: fix a v4l2-compliance failure about frame sequence
+      number
+    - media: ti-vpe: vpe: Make sure YUYV is set as default format
+    - extcon: sm5502: Reset registers during initialization
+    - x86/mm: Use the correct function type for native_set_fixmap()
+    - perf report: Add warning when libunwind not compiled in
+    - iio: adc: max1027: Reset the device at probe time
+    - Bluetooth: hci_core: fix init for HCI_USER_CHANNEL
+    - drm/gma500: fix memory disclosures due to uninitialized bytes
+    - x86/ioapic: Prevent inconsistent state when moving an interrupt
+    - arm64: psci: Reduce the waiting time for cpu_psci_cpu_kill()
+    - libata: Ensure ata_port probe has completed before detach
+    - pinctrl: sh-pfc: sh7734: Fix duplicate TCLK1_B
+    - bnx2x: Fix PF-VF communication over multi-cos queues.
+    - spi: img-spfi: fix potential double release
+    - rtlwifi: fix memory leak in rtl92c_set_fw_rsvdpagepkt()
+    - perf probe: Fix to find range-only function instance
+    - perf probe: Fix to list probe event with correct line number
+    - perf probe: Walk function lines in lexical blocks
+    - perf probe: Fix to probe an inline function which has no entry pc
+    - perf probe: Fix to show ranges of variables in functions without entry_pc
+    - perf probe: Fix to show inlined function callsite without entry_pc
+    - perf probe: Skip overlapped location on searching variables
+    - perf probe: Return a better scope DIE if there is no best scope
+    - perf probe: Fix to show calling lines of inlined functions
+    - perf probe: Skip end-of-sequence and non statement lines
+    - perf probe: Filter out instances except for inlined subroutine and
+      subprogram
+    - ath10k: fix get invalid tx rate for Mesh metric
+    - media: pvrusb2: Fix oops on tear-down when radio support is not present
+    - media: si470x-i2c: add missed operations in remove
+    - EDAC/ghes: Fix grain calculation
+    - spi: pxa2xx: Add missed security checks
+    - ASoC: rt5677: Mark reg RT5677_PWR_ANLG2 as volatile
+    - parport: load lowlevel driver if ports not found
+    - cpufreq: Register drivers only after CPU devices have been registered
+    - x86/crash: Add a forward declaration of struct kimage
+    - spi: tegra20-slink: add missed clk_unprepare
+    - btrfs: don't prematurely free work in end_workqueue_fn()
+    - iwlwifi: check kasprintf() return value
+    - fbtft: Make sure string is NULL terminated
+    - crypto: sun4i-ss - Fix 64-bit size_t warnings on sun4i-ss-hash.c
+    - crypto: vmx - Avoid weird build failures
+    - libtraceevent: Fix memory leakage in copy_filter_type
+    - net: phy: initialise phydev speed and duplex sanely
+    - Revert "mmc: sdhci: Fix incorrect switch to HS mode"
+    - usb: xhci: Fix build warning seen with CONFIG_PM=n
+    - btrfs: do not call synchronize_srcu() in inode_tree_del
+    - btrfs: return error pointer from alloc_test_extent_buffer
+    - btrfs: abort transaction after failed inode updates in create_subvol
+    - Btrfs: fix removal logic of the tree mod log that leads to use-after-free
+      issues
+    - ALSA: pcm: Avoid possible info leaks from PCM stream buffers
+    - af_packet: set defaule value for tmo
+    - fjes: fix missed check in fjes_acpi_add
+    - mod_devicetable: fix PHY module format
+    - net: hisilicon: Fix a BUG trigered by wrong bytes_compl
+    - net: nfc: nci: fix a possible sleep-in-atomic-context bug in
+      nci_uart_tty_receive()
+    - net: qlogic: Fix error paths in ql_alloc_large_buffers()
+    - net: usb: lan78xx: Fix suspend/resume PHY register access error
+    - sctp: fully initialize v4 addr in some functions
+    - net: dst: Force 4-byte alignment of dst_metrics
+    - usbip: Fix error path of vhci_recv_ret_submit()
+    - USB: EHCI: Do not return -EPIPE when hub is disconnected
+    - platform/x86: hp-wmi: Make buffer for HPWMI_FEATURE2_QUERY 128 bytes
+    - staging: comedi: gsc_hpdi: check dma_alloc_coherent() return value
+    - ext4: check for directory entries too close to block end
+    - powerpc/irq: fix stack overflow verification
+    - mmc: sdhci-of-esdhc: fix P2020 errata handling
+    - perf probe: Fix to show function entry line as probe-able
+    - scsi: mpt3sas: Fix clear pending bit in ioctl status
+    - scsi: lpfc: Fix locking on mailbox command completion
+    - Input: atmel_mxt_ts - disable IRQ across suspend
+    - iommu/tegra-smmu: Fix page tables in > 4 GiB memory
+    - scsi: target: compare full CHAP_A Algorithm strings
+    - scsi: lpfc: Fix SLI3 hba in loop mode not discovering devices
+    - scsi: csiostor: Don't enable IRQs too early
+    - powerpc/pseries: Mark accumulate_stolen_time() as notrace
+    - dma-debug: add a schedule point in debug_dma_dump_mappings()
+    - clocksource/drivers/asm9260: Add a check for of_clk_get
+    - powerpc/security/book3s64: Report L1TF status in sysfs
+    - jbd2: Fix statistics for the number of logged blocks
+    - scsi: tracing: Fix handling of TRANSFER LENGTH == 0 for READ(6) and WRITE(6)
+    - scsi: lpfc: Fix duplicate unreg_rpi error in port offline flow
+    - clk: qcom: Allow constant ratio freq tables for rcg
+    - irqchip/irq-bcm7038-l1: Enable parent IRQ if necessary
+    - irqchip: ingenic: Error out if IRQ domain creation failed
+    - fs/quota: handle overflows of sysctl fs.quota.* and report as unsigned long
+    - scsi: lpfc: fix: Coverity: lpfc_cmpl_els_rsp(): Null pointer dereferences
+    - scsi: ufs: fix potential bug which ends in system hang
+    - powerpc/pseries/cmm: Implement release() function for sysfs device
+    - powerpc/security: Fix wrong message when RFI Flush is disable
+    - clk: pxa: fix one of the pxa RTC clocks
+    - bcache: at least try to shrink 1 node in bch_mca_scan()
+    - HID: Improve Windows Precision Touchpad detection.
+    - ext4: work around deleting a file with i_nlink == 0 safely
+    - scsi: pm80xx: Fix for SATA device discovery
+    - scsi: target: iscsi: Wait for all commands to finish before freeing a
+      session
+    - gpio: mpc8xxx: Don't overwrite default irq_set_type callback
+    - scripts/kallsyms: fix definitely-lost memory leak
+    - cdrom: respect device capabilities during opening action
+    - perf regs: Make perf_reg_name() return "unknown" instead of NULL
+    - libfdt: define INT32_MAX and UINT32_MAX in libfdt_env.h
+    - s390/cpum_sf: Check for SDBT and SDB consistency
+    - ocfs2: fix passing zero to 'PTR_ERR' warning
+    - kernel: sysctl: make drop_caches write-only
+    - ALSA: hda - Downgrade error message for single-cmd fallback
+    - Make filldir[64]() verify the directory entry filename is valid
+    - filldir[64]: remove WARN_ON_ONCE() for bad directory entries
+    - net: davinci_cpdma: use dma_addr_t for DMA address
+    - netfilter: ebtables: compat: reject all padding in matches/watchers
+    - 6pack,mkiss: fix possible deadlock
+    - netfilter: bridge: make sure to pull arp header in br_nf_forward_arp()
+    - net: icmp: fix data-race in cmp_global_allow()
+    - hrtimer: Annotate lockless access to timer->state
+    - mmc: sdhci: Update the tuning failed messages to pr_debug level
+    - tcp: do not send empty skb from tcp_write_xmit()
+    - Linux 4.4.208
+
+  * Xenial update: 4.4.207 upstream stable release (LP: #1858489)
+    - x86/apic/32: Avoid bogus LDR warnings
+    - usb: gadget: u_serial: add missing port entry locking
+    - tty: serial: msm_serial: Fix flow control
+    - x86/PCI: Avoid AMD FCH XHCI USB PME# from D0 defect
+    - serial: serial_core: Perform NULL checks for break_ctl ops
+    - serial: ifx6x60: add missed pm_runtime_disable
+    - autofs: fix a leak in autofs_expire_indirect()
+    - NFC: nxp-nci: Fix NULL pointer dereference after I2C communication error
+    - Input: cyttsp4_core - fix use after free bug
+    - ALSA: pcm: Fix stream lock usage in snd_pcm_period_elapsed()
+    - rsxx: add missed destroy_workqueue calls in remove
+    - net: ep93xx_eth: fix mismatch of request_mem_region in remove
+    - serial: core: Allow processing sysrq at port unlock time
+    - iwlwifi: mvm: Send non offchannel traffic via AP sta
+    - ARM: 8813/1: Make aligned 2-byte getuser()/putuser() atomic on ARMv6+
+    - extcon: max8997: Fix lack of path setting in USB device mode
+    - clk: rockchip: fix rk3188 sclk_smc gate data
+    - clk: rockchip: fix rk3188 sclk_mac_lbtest parameter ordering
+    - dlm: fix missing idr_destroy for recover_idr
+    - MIPS: SiByte: Enable ZONE_DMA32 for LittleSur
+    - scsi: zfcp: drop default switch case which might paper over missing case
+    - pinctrl: qcom: ssbi-gpio: fix gpio-hog related boot issues
+    - Staging: iio: adt7316: Fix i2c data reading, set the data field
+    - regulator: Fix return value of _set_load() stub
+    - MIPS: OCTEON: octeon-platform: fix typing
+    - math-emu/soft-fp.h: (_FP_ROUND_ZERO) cast 0 to void to fix warning
+    - rtc: max8997: Fix the returned value in case of error in
+      'max8997_rtc_read_alarm()'
+    - rtc: dt-binding: abx80x: fix resistance scale
+    - ARM: dts: exynos: Use Samsung SoC specific compatible for DWC2 module
+    - dmaengine: coh901318: Fix a double-lock bug
+    - dmaengine: coh901318: Remove unused variable
+    - ACPI: fix acpi_find_child_device() invocation in acpi_preset_companion()
+    - dma-mapping: fix return type of dma_set_max_seg_size()
+    - altera-stapl: check for a null key before strcasecmp'ing it
+    - serial: imx: fix error handling in console_setup
+    - i2c: imx: don't print error message on probe defer
+    - dlm: NULL check before kmem_cache_destroy is not needed
+    - nfsd: fix a warning in __cld_pipe_upcall()
+    - ARM: OMAP1/2: fix SoC name printing
+    - net/x25: fix called/calling length calculation in x25_parse_address_block
+    - net/x25: fix null_x25_address handling
+    - ARM: dts: mmp2: fix the gpio interrupt cell number
+    - tcp: fix off-by-one bug on aborting window-probing socket
+    - modpost: skip ELF local symbols during section mismatch check
+    - kbuild: fix single target build for external module
+    - ARM: dts: pxa: clean up USB controller nodes
+    - dlm: fix invalid cluster name warning
+    - powerpc/math-emu: Update macros from GCC
+    - MIPS: OCTEON: cvmx_pko_mem_debug8: use oldest forward compatible definition
+    - nfsd: Return EPERM, not EACCES, in some SETATTR cases
+    - mlx4: Use snprintf instead of complicated strcpy
+    - ARM: dts: sunxi: Fix PMU compatible strings
+    - sched/fair: Scale bandwidth quota and period without losing quota/period
+      ratio precision
+    - fuse: verify nlink
+    - fuse: verify attributes
+    - ALSA: pcm: oss: Avoid potential buffer overflows
+    - Input: goodix - add upside-down quirk for Teclast X89 tablet
+    - CIFS: Fix SMB2 oplock break processing
+    - tty: vt: keyboard: reject invalid keycodes
+    - can: slcan: Fix use-after-free Read in slcan_open
+    - jbd2: Fix possible overflow in jbd2_log_space_left()
+    - drm/i810: Prevent underflow in ioctl
+    - KVM: x86: do not modify masked bits of shared MSRs
+    - KVM: x86: fix presentation of TSX feature in ARCH_CAPABILITIES
+    - crypto: crypto4xx - fix double-free in crypto4xx_destroy_sdr
+    - spi: atmel: Fix CS high support
+    - RDMA/qib: Validate ->show()/store() callbacks before calling them
+    - thermal: Fix deadlock in thermal thermal_zone_device_check
+    - Revert "KVM: x86: fix out-of-bounds write in KVM_GET_EMULATED_CPUID
+      (CVE-2019-19332)"
+    - KVM: x86: fix out-of-bounds write in KVM_GET_EMULATED_CPUID (CVE-2019-19332)
+    - appletalk: Fix potential NULL pointer dereference in unregister_snap_client
+    - appletalk: Set error code if register_snap_client failed
+    - ALSA: hda - Fix pending unsol events at shutdown
+    - sched/core: Allow putting thread_info into task_struct
+    - sched/core: Add try_get_task_stack() and put_task_stack()
+    - sched/core, x86: Make struct thread_info arch specific again
+    - fs/proc: Stop reporting eip and esp in /proc/PID/stat
+    - fs/proc: Report eip/esp in /prod/PID/stat for coredumping
+    - proc: fix coredump vs read /proc/*/stat race
+    - fs/proc/array.c: allow reporting eip/esp for all coredumping threads
+    - usb: gadget: configfs: Fix missing spin_lock_init()
+    - usb: Allow USB device to be warm reset in suspended state
+    - staging: rtl8188eu: fix interface sanity check
+    - staging: rtl8712: fix interface sanity check
+    - staging: gigaset: fix general protection fault on probe
+    - staging: gigaset: fix illegal free on probe errors
+    - staging: gigaset: add endpoint-type sanity check
+    - xhci: Increase STS_HALT timeout in xhci_suspend()
+    - iio: humidity: hdc100x: fix IIO_HUMIDITYRELATIVE channel reporting
+    - USB: atm: ueagle-atm: add missing endpoint check
+    - USB: idmouse: fix interface sanity checks
+    - USB: serial: io_edgeport: fix epic endpoint lookup
+    - USB: adutux: fix interface sanity check
+    - usb: core: urb: fix URB structure initialization function
+    - usb: mon: Fix a deadlock in usbmon between mmap and read
+    - mtd: spear_smi: Fix Write Burst mode
+    - virtio-balloon: fix managed page counts when migrating pages between zones
+    - btrfs: check page->mapping when loading free space cache
+    - btrfs: Remove btrfs_bio::flags member
+    - rtlwifi: rtl8192de: Fix missing code to retrieve RX buffer address
+    - rtlwifi: rtl8192de: Fix missing callback that tests for hw release of buffer
+    - rtlwifi: rtl8192de: Fix missing enable interrupt flag
+    - lib: raid6: fix awk build warnings
+    - workqueue: Fix spurious sanity check failures in destroy_workqueue()
+    - workqueue: Fix pwq ref leak in rescuer_thread()
+    - ASoC: Jack: Fix NULL pointer dereference in snd_soc_jack_report
+    - blk-mq: avoid sysfs buffer overflow with too many CPU cores
+    - cgroup: pids: use atomic64_t for pids->limit
+    - ar5523: check NULL before memcpy() in ar5523_cmd()
+    - media: bdisp: fix memleak on release
+    - media: radio: wl1273: fix interrupt masking on release
+    - cpuidle: Do not unset the driver if it is there already
+    - ACPI: OSL: only free map once in osl.c
+    - ACPI: bus: Fix NULL pointer check in acpi_bus_get_private_data()
+    - ACPI: PM: Avoid attaching ACPI PM domain to certain devices
+    - pinctrl: samsung: Fix device node refcount leaks in S3C24xx wakeup
+      controller init
+    - pinctrl: samsung: Fix device node refcount leaks in init code
+    - powerpc: Allow 64bit VDSO __kernel_sync_dicache to work across ranges >4GB
+    - video/hdmi: Fix AVI bar unpack
+    - quota: Check that quota is not dirty before release
+    - quota: fix livelock in dquot_writeback_dquots
+    - scsi: zfcp: trace channel log even for FCP command responses
+    - usb: xhci: only set D3hot for pci device
+    - xhci: Fix memory leak in xhci_add_in_port()
+    - xhci: make sure interrupts are restored to correct state
+    - iio: adis16480: Add debugfs_reg_access entry
+    - Btrfs: fix negative subv_writers counter and data space leak after buffered
+      write
+    - scsi: lpfc: Cap NPIV vports to 256
+    - e100: Fix passing zero to 'PTR_ERR' warning in e100_load_ucode_wait
+    - x86/MCE/AMD: Turn off MC4_MISC thresholding on all family 0x15 models
+    - ARM: dts: omap3-tao3530: Fix incorrect MMC card detection GPIO polarity
+    - pinctrl: samsung: Fix device node refcount leaks in S3C64xx wakeup
+      controller init
+    - scsi: qla2xxx: Fix DMA unmap leak
+    - scsi: qla2xxx: Fix qla24xx_process_bidir_cmd()
+    - scsi: qla2xxx: Always check the qla2x00_wait_for_hba_online() return value
+    - powerpc: Fix vDSO clock_getres()
+    - mm/shmem.c: cast the type of unmap_start to u64
+    - blk-mq: make sure that line break can be printed
+    - workqueue: Fix missing kfree(rescuer) in destroy_workqueue()
+    - sunrpc: fix crash when cache_head become valid before update
+    - kernel/module.c: wakeup processes in module_wq on module unload
+    - net: bridge: deny dev_set_mac_address() when unregistering
+    - tcp: md5: fix potential overestimation of TCP option space
+    - tipc: fix ordering of tipc module init and exit routine
+    - inet: protect against too small mtu values.
+    - tcp: fix rejected syncookies due to stale timestamps
+    - tcp: tighten acceptance of ACKs not matching a child socket
+    - tcp: Protect accesses to .ts_recent_stamp with {READ,WRITE}_ONCE()
+    - net: ethernet: ti: cpsw: fix extra rx interrupt
+    - PCI: Fix Intel ACS quirk UPDCR register address
+    - PCI/MSI: Fix incorrect MSI-X masking on resume
+    - xtensa: fix TLB sanity checker
+    - CIFS: Respect O_SYNC and O_DIRECT flags during reconnect
+    - ARM: dts: s3c64xx: Fix init order of clock providers
+    - ARM: tegra: Fix FLOW_CTLR_HALT register clobbering by tegra_resume()
+    - vfio/pci: call irq_bypass_unregister_producer() before freeing irq
+    - dm btree: increase rebalance threshold in __rebalance2()
+    - drm/radeon: fix r1xx/r2xx register checker for POT textures
+    - xhci: fix USB3 device initiated resume race with roothub autosuspend
+    - net: stmmac: use correct DMA buffer size in the RX descriptor
+    - net: stmmac: don't stop NAPI processing when dropping a packet
+    - Linux 4.4.207
+
+  * efivarfs test in ubuntu_kernel_selftest failed on the second run
+    (LP: #1809704)
+    - selftests: efivarfs: return Kselftest Skip code for skipped tests
+    - selftests/efivarfs: clean up test files from test_create*()
+
+  * cifs: kernel NULL pointer dereference, address: 0000000000000038
+    (LP: #1856949)
+    - CIFS: Fix NULL-pointer dereference in smb2_push_mandatory_locks
+
+  * CVE-2019-19332
+    - KVM: x86: fix out-of-bounds write in KVM_GET_EMULATED_CPUID (CVE-2019-19332)
+
+  * CVE-2019-19062
+    - crypto: user - fix memory leak in crypto_report
+
+  * [Hyper-V] KVP daemon fails to start on first boot of disco VM (LP: #1820063)
+    - [Packaging] bind hv_kvp_daemon startup to hv_kvp device
+
+  * False positive test result in run_afpackettests from net in
+    ubuntu_kernel_selftest  (LP: #1825778)
+    - selftests/net: correct the return value for run_afpackettests
+
+  * Xenial update: 4.4.206 upstream stable release (LP: #1855313)
+    - ASoC: compress: fix unsigned integer overflow check
+    - ASoC: kirkwood: fix external clock probe defer
+    - clk: samsung: exynos5420: Preserve PLL configuration during suspend/resume
+    - reset: fix reset_control_ops kerneldoc comment
+    - can: peak_usb: report bus recovery as well
+    - can: c_can: D_CAN: c_can_chip_config(): perform a sofware reset on open
+    - scripts/gdb: fix debugging modules compiled with hot/cold partitioning
+    - block: drbd: remove a stray unlock in __drbd_send_protocol()
+    - scsi: lpfc: Fix dif and first burst use in write commands
+    - ARM: debug-imx: only define DEBUG_IMX_UART_PORT if needed
+    - ARM: dts: imx53-voipac-dmm-668: Fix memory node duplication
+    - parisc: Fix serio address output
+    - parisc: Fix HP SDC hpa address output
+    - arm64: smp: Handle errors reported by the firmware
+    - PM / AVS: SmartReflex: NULL check before some freeing functions is not
+      needed
+    - ARM: ks8695: fix section mismatch warning
+    - ACPI / LPSS: Ignore acpi_device_fix_up_power() return value
+    - crypto: user - support incremental algorithm dumps
+    - mwifiex: fix potential NULL dereference and use after free
+    - mwifiex: debugfs: correct histogram spacing, formatting
+    - rtl818x: fix potential use after free
+    - xfs: require both realtime inodes to mount
+    - ubi: Put MTD device after it is not used
+    - ubi: Do not drop UBI device reference before using
+    - microblaze: adjust the help to the real behavior
+    - microblaze: move "... is ready" messages to arch/microblaze/Makefile
+    - gpiolib: Fix return value of gpio_to_desc() stub if !GPIOLIB
+    - VSOCK: bind to random port for VMADDR_PORT_ANY
+    - btrfs: only track ref_heads in delayed_ref_updates
+    - xen/pciback: Check dev_data before using it
+    - KVM: s390: unregister debug feature on failing arch init
+    - pinctrl: sh-pfc: sh7264: Fix PFCR3 and PFCR0 register configuration
+    - pinctrl: sh-pfc: sh7734: Fix shifted values in IPSR10
+    - HID: doc: fix wrong data structure reference for UHID_OUTPUT
+    - gfs2: take jdata unstuff into account in do_grow
+    - xfs: Align compat attrlist_by_handle with native implementation.
+    - IB/qib: Fix an error code in qib_sdma_verbs_send()
+    - powerpc/book3s/32: fix number of bats in p/v_block_mapped()
+    - powerpc/xmon: fix dump_segments()
+    - drivers/regulator: fix a missing check of return value
+    - serial: max310x: Fix tx_empty() callback
+    - openrisc: Fix broken paths to arch/or32
+    - RDMA/srp: Propagate ib_post_send() failures to the SCSI mid-layer
+    - scsi: qla2xxx: deadlock by configfs_depend_item
+    - scsi: csiostor: fix incorrect dma device in case of vport
+    - ath6kl: Only use match sets when firmware supports it
+    - ath6kl: Fix off by one error in scan completion
+    - powerpc/prom: fix early DEBUG messages
+    - powerpc/mm: Make NULL pointer deferences explicit on bad page faults.
+    - powerpc/44x/bamboo: Fix PCI range
+    - drbd: reject attach of unsuitable uuids even if connected
+    - drbd: fix print_st_err()'s prototype to match the definition
+    - regulator: tps65910: fix a missing check of return value
+    - net/net_namespace: Check the return value of register_pernet_subsys()
+    - um: Make GCOV depend on !KCOV
+    - net: stmicro: fix a missing check of clk_prepare
+    - atl1e: checking the status of atl1e_write_phy_reg
+    - tipc: fix a missing check of genlmsg_put
+    - ocfs2: clear journal dirty flag after shutdown journal
+    - lib/genalloc.c: use vzalloc_node() to allocate the bitmap
+    - lib/genalloc.c: include vmalloc.h
+    - mtd: Check add_mtd_device() ret code
+    - tipc: fix memory leak in tipc_nl_compat_publ_dump
+    - net/core/neighbour: tell kmemleak about hash tables
+    - net/core/neighbour: fix kmemleak minimal reference count for hash tables
+    - sfc: suppress duplicate nvmem partition types in efx_ef10_mtd_probe
+    - decnet: fix DN_IFREQ_SIZE
+    - tipc: fix skb may be leaky in tipc_link_input
+    - sfc: initialise found bitmap in efx_ef10_mtd_probe
+    - net: fix possible overflow in __sk_mem_raise_allocated()
+    - net: dev: Use unsigned integer as an argument to left-shift
+    - scsi: libsas: Support SATA PHY connection rate unmatch fixing during
+      discovery
+    - ACPI / APEI: Switch estatus pool to use vmalloc memory
+    - scsi: libsas: Check SMP PHY control function result
+    - mtd: Remove a debug trace in mtdpart.c
+    - staging: rtl8192e: fix potential use after free
+    - USB: serial: ftdi_sio: add device IDs for U-Blox C099-F9P
+    - mei: bus: prefix device names on bus with the bus name
+    - media: v4l2-ctrl: fix flags for DO_WHITE_BALANCE
+    - net: macb: fix error format in dev_err()
+    - pwm: Clear chip_data in pwm_put()
+    - macvlan: schedule bc_work even if error
+    - openvswitch: fix flow command message size
+    - slip: Fix use-after-free Read in slip_open
+    - openvswitch: drop unneeded BUG_ON() in ovs_flow_cmd_build_info()
+    - openvswitch: remove another BUG_ON()
+    - tipc: fix link name length check
+    - net: sched: fix `tc -s class show` no bstats on class with nolock subqueues
+    - HID: core: check whether Usage Page item is after Usage ID items
+    - hwrng: stm32 - fix unbalanced pm_runtime_enable
+    - platform/x86: hp-wmi: Fix ACPI errors caused by too small buffer
+    - Linux 4.4.206
+    - [Config] updateconfigs for 4.4.206
+
+  * Xenial update: 4.4.205 upstream stable release (LP: #1854857)
+    - Revert "sock: Reset dst when changing sk_mark via setsockopt"
+    - Linux 4.4.205
+
+  * Xenial update: 4.4.204 upstream stable release (LP: #1854855)
+    - net/mlx4_en: fix mlx4 ethtool -N insertion
+    - sfc: Only cancel the PPS workqueue if it exists
+    - net/sched: act_pedit: fix WARN() in the traffic path
+    - net: rtnetlink: prevent underflows in do_setvfinfo()
+    - Revert "fs: ocfs2: fix possible null-pointer dereferences in
+      ocfs2_xa_prepare_entry()"
+    - mm/ksm.c: don't WARN if page is still mapped in remove_stable_node()
+    - asus-wmi: Create quirk for airplane_mode LED
+    - asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UF
+    - asus-wmi: Add quirk_no_rfkill for the Asus N552VW
+    - asus-wmi: Add quirk_no_rfkill for the Asus U303LB
+    - asus-wmi: Add quirk_no_rfkill for the Asus Z550MA
+    - platform/x86: asus-wmi: Filter buggy scan codes on ASUS Q500A
+    - platform/x86: asus-wmi: fix asus ux303ub brightness issue
+    - platform/x86: asus-wmi: Set specified XUSB2PR value for X550LB
+    - asus-wmi: provide access to ALS control
+    - platform/x86: asus-wmi: try to set als by default
+    - platform/x86: asus-nb-wmi: Support ALS on the Zenbook UX430UQ
+    - platform/x86: asus-wmi: add SERIO_I8042 dependency
+    - mwifiex: Fix NL80211_TX_POWER_LIMITED
+    - ALSA: isight: fix leak of reference to firewire unit in error path of .probe
+      callback
+    - printk: fix integer overflow in setup_log_buf()
+    - gfs2: Fix marking bitmaps non-full
+    - synclink_gt(): fix compat_ioctl()
+    - powerpc: Fix signedness bug in update_flash_db()
+    - powerpc/eeh: Fix use of EEH_PE_KEEP on wrong field
+    - brcmsmac: AP mode: update beacon when TIM changes
+    - spi: sh-msiof: fix deferred probing
+    - mmc: mediatek: fix cannot receive new request when msdc_cmd_is_ready fail
+    - btrfs: handle error of get_old_root
+    - gsmi: Fix bug in append_to_eventlog sysfs handler
+    - misc: mic: fix a DMA pool free failure
+    - amiflop: clean up on errors during setup
+    - scsi: ips: fix missing break in switch
+    - KVM/x86: Fix invvpid and invept register operand size in 64-bit mode
+    - scsi: isci: Use proper enumerated type in atapi_d2h_reg_frame_handler
+    - scsi: isci: Change sci_controller_start_task's return type to sci_status
+    - scsi: iscsi_tcp: Explicitly cast param in iscsi_sw_tcp_host_get_param
+    - clk: mmp2: fix the clock id for sdh2_clk and sdh3_clk
+    - scsi: dc395x: fix dma API usage in srb_done
+    - scsi: dc395x: fix DMA API usage in sg_update_list
+    - net: fix warning in af_unix
+    - kprobes, x86/ptrace.h: Make regs_get_kernel_stack_nth() not fault on bad
+      stack
+    - ALSA: i2c/cs8427: Fix int to char conversion
+    - macintosh/windfarm_smu_sat: Fix debug output
+    - USB: misc: appledisplay: fix backlight update_status return code
+    - SUNRPC: Fix a compile warning for cmpxchg64()
+    - atm: zatm: Fix empty body Clang warnings
+    - s390/perf: Return error when debug_register fails
+    - spi: omap2-mcspi: Set FIFO DMA trigger level to word length
+    - sparc: Fix parport build warnings.
+    - ceph: fix dentry leak in ceph_readdir_prepopulate
+    - rtc: s35390a: Change buf's type to u8 in s35390a_init
+    - mISDN: Fix type of switch control variable in ctrl_teimanager
+    - qlcnic: fix a return in qlcnic_dcb_get_capability()
+    - mfd: mc13xxx-core: Fix PMIC shutdown when reading ADC values
+    - mfd: max8997: Enale irq-wakeup unconditionally
+    - selftests/ftrace: Fix to test kprobe $comm arg only if available
+    - thermal: rcar_thermal: Prevent hardware access during system suspend
+    - sparc64: Rework xchg() definition to avoid warnings.
+    - fs/ocfs2/dlm/dlmdebug.c: fix a sleep-in-atomic-context bug in
+      dlm_print_one_mle()
+    - mm/page-writeback.c: fix range_cyclic writeback vs writepages deadlock
+    - um: Make line/tty semantics use true write IRQ
+    - linux/bitmap.h: handle constant zero-size bitmaps correctly
+    - linux/bitmap.h: fix type of nbits in bitmap_shift_right()
+    - hfsplus: fix BUG on bnode parent update
+    - hfs: fix BUG on bnode parent update
+    - hfsplus: prevent btree data loss on ENOSPC
+    - hfs: prevent btree data loss on ENOSPC
+    - hfsplus: fix return value of hfsplus_get_block()
+    - hfs: fix return value of hfs_get_block()
+    - fs/hfs/extent.c: fix array out of bounds read of array extent
+    - igb: shorten maximum PHC timecounter update interval
+    - ntb_netdev: fix sleep time mismatch
+    - ntb: intel: fix return value for ndev_vec_mask()
+    - ocfs2: don't put and assigning null to bh allocated outside
+    - ocfs2: fix clusters leak in ocfs2_defrag_extent()
+    - net: do not abort bulk send on BQL status
+    - sched/fair: Don't increase sd->balance_interval on newidle balance
+    - audit: print empty EXECVE args
+    - wlcore: Fix the return value in case of error in
+      'wlcore_vendor_cmd_smart_config_start()'
+    - rtl8xxxu: Fix missing break in switch
+    - brcmsmac: never log "tid x is not agg'able" by default
+    - wireless: airo: potential buffer overflow in sprintf()
+    - rtlwifi: rtl8192de: Fix misleading REG_MCUFWDL information
+    - scsi: mpt3sas: Fix Sync cache command failure during driver unload
+    - scsi: mpt3sas: Fix driver modifying persistent data in Manufacturing page11
+    - scsi: megaraid_sas: Fix msleep granularity
+    - scsi: lpfc: fcoe: Fix link down issue after 1000+ link bounces
+    - dlm: fix invalid free
+    - dlm: don't leak kernel pointer to userspace
+    - net: bcmgenet: return correct value 'ret' from bcmgenet_power_down
+    - sock: Reset dst when changing sk_mark via setsockopt
+    - pinctrl: qcom: spmi-gpio: fix gpio-hog related boot issues
+    - pinctrl: zynq: Use define directive for PIN_CONFIG_IO_STANDARD
+    - PCI: keystone: Use quirk to limit MRRS for K2G
+    - spi: omap2-mcspi: Fix DMA and FIFO event trigger size mismatch
+    - IB/hfi1: Ensure full Gen3 speed in a Gen4 system
+    - Bluetooth: Fix invalid-free in bcsp_close()
+    - ath9k_hw: fix uninitialized variable data
+    - dm: use blk_set_queue_dying() in __dm_destroy()
+    - arm64: fix for bad_mode() handler to always result in panic
+    - cpufreq: Skip cpufreq resume if it's not suspended
+    - ocfs2: remove ocfs2_is_o2cb_active()
+    - mmc: block: Fix tag condition with packed writes
+    - ARC: perf: Accommodate big-endian CPU
+    - x86/insn: Fix awk regexp warnings
+    - x86/speculation: Fix incorrect MDS/TAA mitigation status
+    - x86/speculation: Fix redundant MDS mitigation message
+    - media: vivid: Set vid_cap_streaming and vid_out_streaming to true
+    - media: vivid: Fix wrong locking that causes race conditions on streaming
+      stop
+    - cpufreq: Add NULL checks to show() and store() methods of cpufreq
+    - media: b2c2-flexcop-usb: add sanity checking
+    - media: cxusb: detect cxusb_ctrl_msg error in query
+    - media: imon: invalid dereference in imon_touch_event
+    - virtio_console: reset on out of memory
+    - virtio_console: don't tie bufs to a vq
+    - virtio_console: allocate inbufs in add_port() only if it is needed
+    - virtio_console: fix uninitialized variable use
+    - virtio_console: drop custom control queue cleanup
+    - virtio_console: move removal code
+    - usb-serial: cp201x: support Mark-10 digital force gauge
+    - appledisplay: fix error handling in the scheduled work
+    - USB: serial: mos7840: add USB ID to support Moxa UPort 2210
+    - USB: serial: mos7720: fix remote wakeup
+    - USB: serial: mos7840: fix remote wakeup
+    - USB: serial: option: add support for DW5821e with eSIM support
+    - USB: serial: option: add support for Foxconn T77W968 LTE modules
+    - staging: comedi: usbduxfast: usbduxfast_ai_cmdtest rounding error
+    - Linux 4.4.204
+
+ -- Connor Kuehl <connor.kuehl@canonical.com>  Wed, 08 Jan 2020 09:26:38 -0800
+
+linux (4.4.0-171.200) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-171.200 -proposed tracker (LP: #1854835)
+
+  * CVE-2019-14901
+    - SAUCE: mwifiex: Fix heap overflow in mmwifiex_process_tdls_action_frame()
+
+  * CVE-2019-14896 // CVE-2019-14897
+    - SAUCE: libertas: Fix two buffer overflows at parsing bss descriptor
+
+  * CVE-2019-14895
+    - SAUCE: mwifiex: fix possible heap overflow in mwifiex_process_country_ie()
+
+  * CVE-2019-18660: patches for Ubuntu (LP: #1853142) // CVE-2019-18660
+    - powerpc/64s: support nospectre_v2 cmdline option
+    - powerpc/book3s64: Fix link stack flush on context switch
+    - KVM: PPC: Book3S HV: Flush link stack on guest exit to host kernel
+
+  * cloudimg: no iavf/i40evf module so no network available with SR-IOV enabled
+    cloud (LP: #1848481)
+    - [Packaging]: include i40evf in generic
+
+  * update ENA driver for DIMLIB dynamic interrupt moderation (LP: #1853180)
+    - net: ena: fix bug that might cause hang after consecutive open/close
+      interface.
+    - net: ena: add intr_moder_rx_interval to struct ena_com_dev and use it
+    - net: ena: switch to dim algorithm for rx adaptive interrupt moderation
+    - net: ena: reimplement set/get_coalesce()
+    - net: ena: enable the interrupt_moderation in driver_supported_features
+    - net: ena: remove code duplication in
+      ena_com_update_nonadaptive_moderation_interval _*()
+    - net: ena: remove old adaptive interrupt moderation code from ena_netdev
+    - net: ena: remove ena_restore_ethtool_params() and relevant fields
+    - net: ena: remove all old adaptive rx interrupt moderation code from ena_com
+    - net: ena: fix update of interrupt moderation register
+    - net: ena: fix retrieval of nonadaptive interrupt moderation intervals
+    - net: ena: fix incorrect update of intr_delay_resolution
+    - net: ena: Select DIMLIB for ENA_ETHERNET
+    - SAUCE: net: ena: fix issues in setting interrupt moderation params in
+      ethtool
+    - SAUCE: net: ena: fix too long default tx interrupt moderation interval
+
+  * backport DIMLIB (lib/dim/) to pre-5.2 kernels (LP: #1852637)
+    - include/linux/bitops.h: introduce BITS_PER_TYPE
+    - linux/kernel.h: move DIV_ROUND_DOWN_ULL() macro
+    - [Config] enable DIMLIB
+    - linux/dim: import DIMLIB (lib/dim/)
+    - SAUCE: linux/dim: avoid library object filename clash
+
+  * Enable framebuffer fonts auto selection for HighDPI screen (LP: #1851623)
+    - fonts: Fix coding style
+    - fonts: Prefer a bigger font for high resolution screens
+
+  * Xenial update: 4.4.203 upstream stable release (LP: #1853881)
+    - slip: Fix memory leak in slip_open error path
+    - ax88172a: fix information leak on short answers
+    - ALSA: usb-audio: Fix missing error check at mixer resolution test
+    - ALSA: usb-audio: not submit urb for stopped endpoint
+    - Input: ff-memless - kill timer in destroy()
+    - ecryptfs_lookup_interpose(): lower_dentry->d_inode is not stable
+    - ecryptfs_lookup_interpose(): lower_dentry->d_parent is not stable either
+    - iommu/vt-d: Fix QI_DEV_IOTLB_PFSID and QI_DEV_EIOTLB_PFSID macros
+    - mm: memcg: switch to css_tryget() in get_mem_cgroup_from_mm()
+    - mm: hugetlb: switch to css_tryget() in hugetlb_cgroup_charge_cgroup()
+    - mmc: sdhci-of-at91: fix quirk2 overwrite
+    - iio: dac: mcp4922: fix error handling in mcp4922_write_raw
+    - ALSA: pcm: signedness bug in snd_pcm_plug_alloc()
+    - ARM: dts: at91/trivial: Fix USART1 definition for at91sam9g45
+    - ALSA: seq: Do error checks at creating system ports
+    - gfs2: Don't set GFS2_RDF_UPTODATE when the lvb is updated
+    - ASoC: dpcm: Properly initialise hw->rate_max
+    - MIPS: BCM47XX: Enable USB power on Netgear WNDR3400v3
+    - ARM: dts: exynos: Fix sound in Snow-rev5 Chromebook
+    - i40e: use correct length for strncpy
+    - i40e: hold the rtnl lock on clearing interrupt scheme
+    - i40e: Prevent deleting MAC address from VF when set by PF
+    - ARM: dts: pxa: fix power i2c base address
+    - rtl8187: Fix warning generated when strncpy() destination length matches the
+      sixe argument
+    - net: lan78xx: Bail out if lan78xx_get_endpoints fails
+    - ASoC: sgtl5000: avoid division by zero if lo_vag is zero
+    - ath10k: wmi: disable softirq's while calling ieee80211_rx
+    - mips: txx9: fix iounmap related issue
+    - of: make PowerMac cache node search conditional on CONFIG_PPC_PMAC
+    - ARM: dts: omap3-gta04: give spi_lcd node a label so that we can overwrite in
+      other DTS files
+    - ARM: dts: omap3-gta04: tvout: enable as display1 alias
+    - ARM: dts: omap3-gta04: make NAND partitions compatible with recent U-Boot
+    - ARM: dts: omap3-gta04: keep vpll2 always on
+    - dmaengine: dma-jz4780: Further residue status fix
+    - signal: Always ignore SIGKILL and SIGSTOP sent to the global init
+    - signal: Properly deliver SIGILL from uprobes
+    - signal: Properly deliver SIGSEGV from x86 uprobes
+    - scsi: sym53c8xx: fix NULL pointer dereference panic in sym_int_sir()
+    - ARM: imx6: register pm_power_off handler if "fsl,pmic-stby-poweroff" is set
+    - scsi: pm80xx: Corrected dma_unmap_sg() parameter
+    - scsi: pm80xx: Fixed system hang issue during kexec boot
+    - kprobes: Don't call BUG_ON() if there is a kprobe in use on free list
+    - nvmem: core: return error code instead of NULL from nvmem_device_get
+    - media: fix: media: pci: meye: validate offset to avoid arbitrary access
+    - ALSA: intel8x0m: Register irq handler after register initializations
+    - pinctrl: at91-pio4: fix has_config check in atmel_pctl_dt_subnode_to_map()
+    - llc: avoid blocking in llc_sap_close()
+    - powerpc/vdso: Correct call frame information
+    - ARM: dts: socfpga: Fix I2C bus unit-address error
+    - pinctrl: at91: don't use the same irqchip with multiple gpiochips
+    - cxgb4: Fix endianness issue in t4_fwcache()
+    - power: supply: ab8500_fg: silence uninitialized variable warnings
+    - power: supply: max8998-charger: Fix platform data retrieval
+    - kernfs: Fix range checks in kernfs_get_target_path
+    - s390/qeth: invoke softirqs after napi_schedule()
+    - PCI/ACPI: Correct error message for ASPM disabling
+    - serial: mxs-auart: Fix potential infinite loop
+    - powerpc/iommu: Avoid derefence before pointer check
+    - powerpc/64s/hash: Fix stab_rr off by one initialization
+    - powerpc/pseries: Disable CPU hotplug across migrations
+    - libfdt: Ensure INT_MAX is defined in libfdt_env.h
+    - power: supply: twl4030_charger: fix charging current out-of-bounds
+    - power: supply: twl4030_charger: disable eoc interrupt on linear charge
+    - net: toshiba: fix return type of ndo_start_xmit function
+    - net: xilinx: fix return type of ndo_start_xmit function
+    - net: broadcom: fix return type of ndo_start_xmit function
+    - net: amd: fix return type of ndo_start_xmit function
+    - usb: chipidea: Fix otg event handler
+    - ARM: dts: am335x-evm: fix number of cpsw
+    - ARM: dts: ux500: Correct SCU unit address
+    - ARM: dts: ux500: Fix LCDA clock line muxing
+    - ARM: dts: ste: Fix SPI controller node names
+    - cpufeature: avoid warning when compiling with clang
+    - bnx2x: Ignore bandwidth attention in single function mode
+    - net: micrel: fix return type of ndo_start_xmit function
+    - x86/CPU: Use correct macros for Cyrix calls
+    - MIPS: kexec: Relax memory restriction
+    - media: pci: ivtv: Fix a sleep-in-atomic-context bug in ivtv_yuv_init()
+    - media: davinci: Fix implicit enum conversion warning
+    - usb: gadget: uvc: configfs: Drop leaked references to config items
+    - usb: gadget: uvc: configfs: Prevent format changes after linking header
+    - usb: gadget: uvc: Factor out video USB request queueing
+    - usb: gadget: uvc: Only halt video streaming endpoint in bulk mode
+    - misc: kgdbts: Fix restrict error
+    - misc: genwqe: should return proper error value.
+    - vfio/pci: Fix potential memory leak in vfio_msi_cap_len
+    - scsi: libsas: always unregister the old device if going to discover new
+    - ARM: dts: tegra30: fix xcvr-setup-use-fuses
+    - ARM: tegra: apalis_t30: fix mmc1 cmd pull-up
+    - net: smsc: fix return type of ndo_start_xmit function
+    - EDAC: Raise the maximum number of memory controllers
+    - Bluetooth: L2CAP: Detect if remote is not able to use the whole MPS
+    - arm64: dts: amd: Fix SPI bus warnings
+    - fuse: use READ_ONCE on congestion_threshold and max_background
+    - Bluetooth: hci_ldisc: Fix null pointer derefence in case of early data
+    - Bluetooth: hci_ldisc: Postpone HCI_UART_PROTO_READY bit set in
+      hci_uart_set_proto()
+    - memfd: Use radix_tree_deref_slot_protected to avoid the warning.
+    - slcan: Fix memory leak in error path
+    - net: cdc_ncm: Signedness bug in cdc_ncm_set_dgram_size()
+    - x86/atomic: Fix smp_mb__{before,after}_atomic()
+    - kprobes/x86: Prohibit probing on exception masking instructions
+    - uprobes/x86: Prohibit probing on MOV SS instruction
+    - [Config] Remove unused SH-Mobile HDMI driver
+    - fbdev: Remove unused SH-Mobile HDMI driver
+    - fbdev: Ditch fb_edid_add_monspecs
+    - block: introduce blk_rq_is_passthrough
+    - libata: have ata_scsi_rw_xlat() fail invalid passthrough requests
+    - net: ovs: fix return type of ndo_start_xmit function
+    - f2fs: return correct errno in f2fs_gc
+    - SUNRPC: Fix priority queue fairness
+    - ath10k: fix vdev-start timeout on error
+    - ath9k: fix reporting calculated new FFT upper max
+    - usb: gadget: udc: fotg210-udc: Fix a sleep-in-atomic-context bug in
+      fotg210_get_status()
+    - nl80211: Fix a GET_KEY reply attribute
+    - dmaengine: ep93xx: Return proper enum in ep93xx_dma_chan_direction
+    - dmaengine: timb_dma: Use proper enum in td_prep_slave_sg
+    - mei: samples: fix a signedness bug in amt_host_if_call()
+    - cxgb4: Use proper enum in cxgb4_dcb_handle_fw_update
+    - cxgb4: Use proper enum in IEEE_FAUX_SYNC
+    - powerpc/pseries: Fix DTL buffer registration
+    - powerpc/pseries: Fix how we iterate over the DTL entries
+    - mtd: rawnand: sh_flctl: Use proper enum for flctl_dma_fifo0_transfer
+    - ixgbe: Fix crash with VFs and flow director on interface flap
+    - IB/mthca: Fix error return code in __mthca_init_one()
+    - ata: ep93xx: Use proper enums for directions
+    - ALSA: hda/sigmatel - Disable automute for Elo VuPoint
+    - KVM: PPC: Book3S PR: Exiting split hack mode needs to fixup both PC and LR
+    - USB: serial: cypress_m8: fix interrupt-out transfer length
+    - mtd: physmap_of: Release resources on error
+    - brcmfmac: fix full timeout waiting for action frame on-channel tx
+    - NFSv4.x: fix lock recovery during delegation recall
+    - dmaengine: ioat: fix prototype of ioat_enumerate_channels
+    - Input: st1232 - set INPUT_PROP_DIRECT property
+    - x86/olpc: Fix build error with CONFIG_MFD_CS5535=m
+    - crypto: mxs-dcp - Fix SHA null hashes and output length
+    - crypto: mxs-dcp - Fix AES issues
+    - ACPI / SBS: Fix rare oops when removing modules
+    - fbdev: sbuslib: use checked version of put_user()
+    - fbdev: sbuslib: integer overflow in sbusfb_ioctl_helper()
+    - bcache: recal cached_dev_sectors on detach
+    - proc/vmcore: Fix i386 build error of missing copy_oldmem_page_encrypted()
+    - backlight: lm3639: Unconditionally call led_classdev_unregister
+    - printk: Give error on attempt to set log buffer length to over 2G
+    - media: isif: fix a NULL pointer dereference bug
+    - GFS2: Flush the GFS2 delete workqueue before stopping the kernel threads
+    - media: cx231xx: fix potential sign-extension overflow on large shift
+    - x86/kexec: Correct KEXEC_BACKUP_SRC_END off-by-one error
+    - gpio: syscon: Fix possible NULL ptr usage
+    - spi: spidev: Fix OF tree warning logic
+    - ARM: 8802/1: Call syscall_trace_exit even when system call skipped
+    - hwmon: (pwm-fan) Silence error on probe deferral
+    - mac80211: minstrel: fix CCK rate group streams value
+    - spi: rockchip: initialize dma_slave_config properly
+    - arm64: uaccess: Ensure PAN is re-enabled after unhandled uaccess fault
+    - Linux 4.4.203
+
+  * Xenial update: 4.4.202 upstream stable release (LP: #1853177)
+    - kvm: mmu: Don't read PDPTEs when paging is not enabled
+    - MIPS: BCM63XX: fix switch core reset on BCM6368
+    - powerpc/Makefile: Use cflags-y/aflags-y for setting endian options
+    - powerpc: Fix compiling a BE kernel with a powerpc64le toolchain
+    - powerpc/boot: Request no dynamic linker for boot wrapper
+    - x86/speculation/taa: Fix printing of TAA_MSG_SMT on IBRS_ALL CPUs
+    - Linux 4.4.202
+
+  * Xenial update: 4.4.201 upstream stable release (LP: #1852335)
+    - CDC-NCM: handle incomplete transfer of MTU
+    - net: fix data-race in neigh_event_send()
+    - NFC: fdp: fix incorrect free object
+    - NFC: st21nfca: fix double free
+    - qede: fix NULL pointer deref in __qede_remove()
+    - nfc: netlink: fix double device reference drop
+    - ALSA: bebob: fix to detect configured source of sampling clock for Focusrite
+      Saffire Pro i/o series
+    - ALSA: hda/ca0132 - Fix possible workqueue stall
+    - mm, vmstat: hide /proc/pagetypeinfo from normal users
+    - dump_stack: avoid the livelock of the dump_lock
+    - perf tools: Fix time sorting
+    - drm/radeon: fix si_enable_smc_cac() failed issue
+    - ceph: fix use-after-free in __ceph_remove_cap()
+    - iio: imu: adis16480: make sure provided frequency is positive
+    - netfilter: nf_tables: Align nft_expr private data to 64-bit
+    - netfilter: ipset: Fix an error code in ip_set_sockfn_get()
+    - can: usb_8dev: fix use-after-free on disconnect
+    - can: c_can: c_can_poll(): only read status register after status IRQ
+    - can: peak_usb: fix a potential out-of-sync while decoding packets
+    - can: gs_usb: gs_can_open(): prevent memory leak
+    - can: peak_usb: fix slab info leak
+    - drivers: usb: usbip: Add missing break statement to switch
+    - configfs: fix a deadlock in configfs_symlink()
+    - PCI: tegra: Enable Relaxed Ordering only for Tegra20 & Tegra30
+    - scsi: qla2xxx: fixup incorrect usage of host_byte
+    - scsi: lpfc: Honor module parameter lpfc_use_adisc
+    - ipvs: move old_secure_tcp into struct netns_ipvs
+    - bonding: fix unexpected IFF_BONDING bit unset
+    - usb: fsl: Check memory resource before releasing it
+    - usb: gadget: udc: atmel: Fix interrupt storm in FIFO mode.
+    - usb: gadget: composite: Fix possible double free memory bug
+    - usb: gadget: configfs: fix concurrent issue between composite APIs
+    - perf/x86/amd/ibs: Fix reading of the IBS OpData register and thus precise
+      RIP validity
+    - USB: Skip endpoints with 0 maxpacket length
+    - scsi: qla2xxx: stop timer in shutdown path
+    - net: hisilicon: Fix "Trying to free already-free IRQ"
+    - NFSv4: Don't allow a cached open with a revoked delegation
+    - igb: Fix constant media auto sense switching when no cable is connected
+    - e1000: fix memory leaks
+    - can: flexcan: disable completely the ECC mechanism
+    - mm/filemap.c: don't initiate writeback if mapping has no dirty pages
+    - cgroup,writeback: don't switch wbs immediately on dead wbs if the memcg is
+      dead
+    - net: prevent load/store tearing on sk->sk_stamp
+    - Linux 4.4.201
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 03 Dec 2019 11:20:54 +0100
+
+linux (4.4.0-170.199) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-170.199 -proposed tracker (LP: #1852306)
+
+  * update ENA driver to version 2.1.0 (LP: #1850175)
+    - net: ena: fix: set freed objects to NULL to avoid failing future allocations
+    - net: ena: fix swapped parameters when calling
+      ena_com_indirect_table_fill_entry
+    - net: ena: fix: Free napi resources when ena_up() fails
+    - net: ena: fix incorrect test of supported hash function
+    - net: ena: fix return value of ena_com_config_llq_info()
+    - net: ena: improve latency by disabling adaptive interrupt moderation by
+      default
+    - net: ena: fix ena_com_fill_hash_function() implementation
+    - net: ena: add handling of llq max tx burst size
+    - net: ena: ethtool: add extra properties retrieval via get_priv_flags
+    - net: ena: replace free_tx/rx_ids union with single free_ids field in
+      ena_ring
+    - net: ena: arrange ena_probe() function variables in reverse christmas tree
+    - net: ena: add newline at the end of pr_err prints
+    - net: ena: allow automatic fallback to polling mode
+    - net: ena: add support for changing max_header_size in LLQ mode
+    - net: ena: optimise calculations for CQ doorbell
+    - net: ena: add good checksum counter
+    - net: ena: use dev_info_once instead of static variable
+    - net: ena: add MAX_QUEUES_EXT get feature admin command
+    - net: ena: enable negotiating larger Rx ring size
+    - net: ena: make ethtool show correct current and max queue sizes
+    - net: ena: allow queue allocation backoff when low on memory
+    - net: ena: add ethtool function for changing io queue sizes
+    - net: ena: remove inline keyword from functions in *.c
+    - net: ena: update driver version from 2.0.3 to 2.1.0
+    - net: ena: Fix bug where ring allocation backoff stopped too late
+    - Revert "net: ena: ethtool: add extra properties retrieval via
+      get_priv_flags"
+    - net: ena: don't wake up tx queue when down
+    - net: ena: clean up indentation issue
+
+  * Bionic update: upstream stable patchset 2019-08-01 (LP: #1838700) // update
+    ENA driver to version 2.1.0 (LP: #1850175)
+    - net: ena: gcc 8: fix compilation warning
+
+  * Skip frame when buffer overflow on UVC camera (LP: #1849871)
+    - media: uvcvideo: Mark buffer error where overflow
+
+  * CVE-2018-20784
+    - sched/fair: Fix infinite loop in update_blocked_averages() by reverting
+      a9e7f6544b9c
+    - sched/fair: Fix hierarchical order in rq->leaf_cfs_rq_list
+    - sched/fair: Add tmp_alone_branch assertion
+    - sched/fair: Fix insertion in rq->leaf_cfs_rq_list
+    - sched/fair: Optimize update_blocked_averages()
+    - sched/fair: Fix O(nr_cgroups) in the load balancing path
+
+  * Xenial update: 4.4.200 upstream stable release (LP: #1852110)
+    - kbuild: add -fcf-protection=none when using retpoline flags
+    - regulator: ti-abb: Fix timeout in ti_abb_wait_txdone/ti_abb_clear_all_txdone
+    - regulator: pfuze100-regulator: Variable "val" in pfuze100_regulator_probe()
+      could be uninitialized
+    - ASoc: rockchip: i2s: Fix RPM imbalance
+    - ARM: dts: logicpd-torpedo-som: Remove twl_keypad
+    - ARM: mm: fix alignment handler faults under memory pressure
+    - scsi: sni_53c710: fix compilation error
+    - scsi: fix kconfig dependency warning related to 53C700_LE_ON_BE
+    - perf kmem: Fix memory leak in compact_gfp_flags()
+    - scsi: target: core: Do not overwrite CDB byte 1
+    - of: unittest: fix memory leak in unittest_data_add
+    - MIPS: bmips: mark exception vectors as char arrays
+    - cifs: Fix cifsInodeInfo lock_sem deadlock when reconnect occurs
+    - dccp: do not leak jiffies on the wire
+    - net: fix sk_page_frag() recursion from memory reclaim
+    - net: hisilicon: Fix ping latency when deal with high throughput
+    - SAUCE: Revert "net: Zeroing the structure ethtool_wolinfo in
+      ethtool_get_wol()"
+    - net: Zeroing the structure ethtool_wolinfo in ethtool_get_wol()
+    - net: add READ_ONCE() annotation in __skb_wait_for_more_packets()
+    - vxlan: check tun_info options_len properly
+    - net/mlx4_core: Dynamically set guaranteed amount of counters per VF
+    - inet: stop leaking jiffies on the wire
+    - net/flow_dissector: switch to siphash
+    - dmaengine: qcom: bam_dma: Fix resource leak
+    - ARM: 8051/1: put_user: fix possible data corruption in put_user
+    - ARM: 8478/2: arm/arm64: add arm-smccc
+    - ARM: 8479/2: add implementation for arm-smccc
+    - ARM: 8480/2: arm64: add implementation for arm-smccc
+    - ARM: 8481/2: drivers: psci: replace psci firmware calls
+    - ARM: uaccess: remove put_user() code duplication
+    - ARM: Move system register accessors to asm/cp15.h
+    - arm/arm64: KVM: Advertise SMCCC v1.1
+    - arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support
+    - firmware/psci: Expose PSCI conduit
+    - firmware/psci: Expose SMCCC version through psci_ops
+    - arm/arm64: smccc: Make function identifiers an unsigned quantity
+    - arm/arm64: smccc: Implement SMCCC v1.1 inline primitive
+    - arm/arm64: smccc: Add SMCCC-specific return codes
+    - arm/arm64: smccc-1.1: Make return values unsigned long
+    - arm/arm64: smccc-1.1: Handle function result as parameters
+    - ARM: add more CPU part numbers for Cortex and Brahma B15 CPUs
+    - ARM: bugs: prepare processor bug infrastructure
+    - ARM: bugs: hook processor bug checking into SMP and suspend paths
+    - ARM: bugs: add support for per-processor bug checking
+    - ARM: spectre: add Kconfig symbol for CPUs vulnerable to Spectre
+    - ARM: spectre-v2: harden branch predictor on context switches
+    - ARM: spectre-v2: add Cortex A8 and A15 validation of the IBE bit
+    - ARM: spectre-v2: harden user aborts in kernel space
+    - ARM: spectre-v2: add firmware based hardening
+    - ARM: spectre-v2: warn about incorrect context switching functions
+    - ARM: spectre-v1: add speculation barrier (csdb) macros
+    - ARM: spectre-v1: add array_index_mask_nospec() implementation
+    - ARM: spectre-v1: fix syscall entry
+    - ARM: signal: copy registers using __copy_from_user()
+    - ARM: vfp: use __copy_from_user() when restoring VFP state
+    - ARM: oabi-compat: copy semops using __copy_from_user()
+    - ARM: use __inttype() in get_user()
+    - ARM: spectre-v1: use get_user() for __get_user()
+    - ARM: spectre-v1: mitigate user accesses
+    - ARM: 8789/1: signal: copy registers using __copy_to_user()
+    - ARM: 8791/1: vfp: use __copy_to_user() when saving VFP state
+    - ARM: 8792/1: oabi-compat: copy oabi events using __copy_to_user()
+    - ARM: 8793/1: signal: replace __put_user_error with __put_user
+    - ARM: 8794/1: uaccess: Prevent speculative use of the current addr_limit
+    - ARM: 8795/1: spectre-v1.1: use put_user() for __put_user()
+    - ARM: 8796/1: spectre-v1,v1.1: provide helpers for address sanitization
+    - ARM: 8810/1: vfp: Fix wrong assignement to ufp_exc
+    - ARM: make lookup_processor_type() non-__init
+    - ARM: split out processor lookup
+    - ARM: clean up per-processor check_bugs method call
+    - ARM: add PROC_VTABLE and PROC_TABLE macros
+    - ARM: spectre-v2: per-CPU vtables to work around big.Little systems
+    - ARM: ensure that processor vtables is not lost after boot
+    - ARM: fix the cockup in the previous patch
+    - alarmtimer: Change remaining ENOTSUPP to EOPNOTSUPP
+    - fs/dcache: move security_d_instantiate() behind attaching dentry to inode
+    - Linux 4.4.200
+    - updateconfigs for Linux v4.4.200
+
+  * Xenial update: 4.4.199 upstream stable release (LP: #1851549)
+    - dm snapshot: use mutex instead of rw_semaphore
+    - dm snapshot: introduce account_start_copy() and account_end_copy()
+    - dm snapshot: rework COW throttling to fix deadlock
+    - dm: Use kzalloc for all structs with embedded biosets/mempools
+    - sc16is7xx: Fix for "Unexpected interrupt: 8"
+    - x86/cpu: Add Atom Tremont (Jacobsville)
+    - scripts/setlocalversion: Improve -dirty check with git-status --no-optional-
+      locks
+    - usb: handle warm-reset port requests on hub resume
+    - exec: load_script: Do not exec truncated interpreter path
+    - iio: fix center temperature of bmc150-accel-core
+    - perf map: Fix overlapped map handling
+    - RDMA/iwcm: Fix a lock inversion issue
+    - fs: cifs: mute -Wunused-const-variable message
+    - serial: mctrl_gpio: Check for NULL pointer
+    - efi/cper: Fix endianness of PCIe class code
+    - efi/x86: Do not clean dummy variable in kexec path
+    - fs: ocfs2: fix possible null-pointer dereferences in
+      ocfs2_xa_prepare_entry()
+    - fs: ocfs2: fix a possible null-pointer dereference in
+      ocfs2_info_scan_inode_alloc()
+    - MIPS: fw: sni: Fix out of bounds init of o32 stack
+    - NFSv4: Fix leak of clp->cl_acceptor string
+    - tracing: Initialize iter->seq after zeroing in tracing_read_pipe()
+    - USB: legousbtower: fix a signedness bug in tower_probe()
+    - thunderbolt: Use 32-bit writes when writing ring producer/consumer
+    - fuse: flush dirty data/metadata before non-truncate setattr
+    - fuse: truncate pending writes on O_TRUNC
+    - ALSA: bebob: Fix prototype of helper function to return negative value
+    - UAS: Revert commit 3ae62a42090f ("UAS: fix alignment of scatter/gather
+      segments")
+    - USB: gadget: Reject endpoints with 0 maxpacket value
+    - USB: ldusb: fix ring-buffer locking
+    - USB: ldusb: fix control-message timeout
+    - USB: serial: whiteheat: fix potential slab corruption
+    - USB: serial: whiteheat: fix line-speed endianness
+    - HID: Fix assumption that devices have inputs
+    - HID: fix error message in hid_open_report()
+    - nl80211: fix validation of mesh path nexthop
+    - s390/cmm: fix information leak in cmm_timeout_handler()
+    - llc: fix sk_buff leak in llc_sap_state_process()
+    - llc: fix sk_buff leak in llc_conn_service()
+    - bonding: fix potential NULL deref in bond_update_slave_arr
+    - net: usb: sr9800: fix uninitialized local variable
+    - sch_netem: fix rcu splat in netem_enqueue()
+    - sctp: fix the issue that flags are ignored when using kernel_connect
+    - sctp: not bind the socket in sctp_connect
+    - xfs: Correctly invert xfs_buftarg LRU isolation logic
+    - Revert "ALSA: hda: Flush interrupts on disabling"
+    - Linux 4.4.199
+
+  * libmbim-proxy using 100% CPU on a Dell Edge Gateway 3002 (LP: #1851347)
+    - USB: cdc-wdm: ignore -EPIPE from GetEncapsulatedResponse
+
+  * Xenial update: v4.4.198 upstream stable release (LP: #1850454)
+    - scsi: ufs: skip shutdown if hba is not powered
+    - scsi: megaraid: disable device when probe failed after enabled device
+    - scsi: qla2xxx: Fix unbound sleep in fcport delete path.
+    - ARM: OMAP2+: Fix missing reset done flag for am3 and am43
+    - ARM: dts: am4372: Set memory bandwidth limit for DISPC
+    - nl80211: fix null pointer dereference
+    - mips: Loongson: Fix the link time qualifier of 'serial_exit()'
+    - net: hisilicon: Fix usage of uninitialized variable in function
+      mdio_sc_cfg_reg_write()
+    - namespace: fix namespace.pl script to support relative paths
+    - loop: Add LOOP_SET_DIRECT_IO to compat ioctl
+    - net: bcmgenet: Fix RGMII_MODE_EN value for GENET v1/2/3
+    - net: bcmgenet: Set phydev->dev_flags only for internal PHYs
+    - sctp: change sctp_prot .no_autobind with true
+    - net: avoid potential infinite loop in tc_ctl_action()
+    - ipv4: Return -ENETUNREACH if we can't create route but saddr is valid
+    - memfd: Fix locking when tagging pins
+    - USB: legousbtower: fix memleak on disconnect
+    - usb: udc: lpc32xx: fix bad bit shift operation
+    - USB: serial: ti_usb_3410_5052: fix port-close races
+    - USB: ldusb: fix memleak on disconnect
+    - USB: usblp: fix use-after-free on disconnect
+    - USB: ldusb: fix read info leaks
+    - scsi: core: try to get module before removing device
+    - ASoC: rsnd: Reinitialize bit clock inversion flag for every format setting
+    - cfg80211: wext: avoid copying malformed SSIDs
+    - mac80211: Reject malformed SSID elements
+    - scsi: zfcp: fix reaction on bit error threshold notification
+    - mm/slub: fix a deadlock in show_slab_objects()
+    - xtensa: drop EXPORT_SYMBOL for outs*/ins*
+    - parisc: Fix vmap memory leak in ioremap()/iounmap()
+    - CIFS: avoid using MID 0xFFFF
+    - btrfs: block-group: Fix a memory leak due to missing btrfs_put_block_group()
+    - memstick: jmb38x_ms: Fix an error handling path in 'jmb38x_ms_probe()'
+    - cpufreq: Avoid cpufreq_suspend() deadlock on system shutdown
+    - xen/netback: fix error path of xenvif_connect_data()
+    - PCI: PM: Fix pci_power_up()
+    - net: sched: Fix memory exposure from short TCA_U32_SEL
+    - RDMA/cxgb4: Do not dma memory off of the stack
+    - Linux 4.4.198
+
+  * Colour banding in Lenovo G50-80 laptop display (i915) (LP: #1819968) //
+    Xenial update: v4.4.198 upstream stable release (LP: #1850454)
+    - drm/edid: Add 6 bpc quirk for SDC panel in Lenovo G50
+
+ -- Connor Kuehl <connor.kuehl@canonical.com>  Wed, 13 Nov 2019 11:18:48 -0800
+
+linux (4.4.0-169.198) xenial; urgency=medium
+
+  * Incomplete i915 fix for 64-bit x86 kernels (LP: #1852141) // CVE-2019-0155
+    - SAUCE: drm/i915/cmdparser: Fix jump whitelist clearing
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 12 Nov 2019 11:19:22 +0100
+
+linux (4.4.0-168.197) xenial; urgency=medium
+
+  * CVE-2018-12207
+    - KVM: x86: MMU: Encapsulate the type of rmap-chain head in a new struct
+    - KVM: x86: MMU: Consolidate quickly_check_mmio_pf() and is_mmio_page_fault()
+    - KVM: x86: MMU: Move handle_mmio_page_fault() call to kvm_mmu_page_fault()
+    - KVM: MMU: rename has_wrprotected_page to mmu_gfn_lpage_is_disallowed
+    - KVM: MMU: introduce kvm_mmu_gfn_{allow,disallow}_lpage
+    - KVM: x86: MMU: Make mmu_set_spte() return emulate value
+    - KVM: x86: MMU: Move initialization of parent_ptes out from
+      kvm_mmu_alloc_page()
+    - KVM: x86: MMU: always set accessed bit in shadow PTEs
+    - KVM: x86: MMU: Move parent_pte handling from kvm_mmu_get_page() to
+      link_shadow_page()
+    - KVM: x86: MMU: Remove unused parameter parent_pte from kvm_mmu_get_page()
+    - KVM: x86: simplify ept_misconfig
+    - KVM: x86: extend usage of RET_MMIO_PF_* constants
+    - KVM: MMU: drop vcpu param in gpte_access
+    - kvm: Convert kvm_lock to a mutex
+    - kvm: x86: Do not release the page inside mmu_set_spte()
+    - KVM: x86: make FNAME(fetch) and __direct_map more similar
+    - KVM: x86: remove now unneeded hugepage gfn adjustment
+    - KVM: x86: change kvm_mmu_page_get_gfn BUG_ON to WARN_ON
+    - KVM: x86: add tracepoints around __direct_map and FNAME(fetch)
+    - SAUCE: KVM: vmx, svm: always run with EFER.NXE=1 when shadow paging is
+      active
+    - SAUCE: x86: Add ITLB_MULTIHIT bug infrastructure
+    - SAUCE: kvm: mmu: ITLB_MULTIHIT mitigation
+    - SAUCE: kvm: Add helper function for creating VM worker threads
+    - SAUCE: kvm: x86: mmu: Recovery of shattered NX large pages
+    - SAUCE: cpu/speculation: Uninline and export CPU mitigations helpers
+    - SAUCE: kvm: x86: mmu: Apply global mitigations knob to ITLB_MULTIHIT
+
+  * CVE-2019-11135
+    - KVM: x86: Emulate MSR_IA32_ARCH_CAPABILITIES on AMD hosts
+    - KVM: x86: use Intel speculation bugs and features as derived in generic x86
+      code
+    - x86/msr: Add the IA32_TSX_CTRL MSR
+    - x86/cpu: Add a helper function x86_read_arch_cap_msr()
+    - x86/cpu: Add a "tsx=" cmdline option with TSX disabled by default
+    - x86/speculation/taa: Add mitigation for TSX Async Abort
+    - x86/speculation/taa: Add sysfs reporting for TSX Async Abort
+    - kvm/x86: Export MDS_NO=0 to guests when TSX is enabled
+    - x86/tsx: Add "auto" option to the tsx= cmdline parameter
+    - x86/speculation/taa: Add documentation for TSX Async Abort
+    - x86/tsx: Add config options to set tsx=on|off|auto
+    - SAUCE: x86/speculation/taa: Call tsx_init()
+    - SAUCE: x86/cpu: Include cpu header from bugs.c
+    - [Config] Disable TSX by default when possible
+
+  * CVE-2019-0154
+    - SAUCE: i915_bpo: drm/i915: Lower RM timeout to avoid DSI hard hangs
+    - SAUCE: i915_bpo: drm/i915/gen8+: Add RC6 CTX corruption WA
+    - SAUCE: drm/i915/gen8+: Add RC6 CTX corruption WA
+
+  * CVE-2019-0155
+    - SAUCE: i915_bpo: drm/i915/gtt: Add read only pages to gen8_pte_encode
+    - SAUCE: i915_bpo: drm/i915/gtt: Read-only pages for insert_entries on bdw+
+    - SAUCE: i915_bpo: drm/i915/gtt: Disable read-only support under GVT
+    - SAUCE: i915_bpo: drm/i915: Rename gen7 cmdparser tables
+    - SAUCE: i915_bpo: drm/i915: Disable Secure Batches for gen6+
+    - SAUCE: i915_bpo: drm/i915/cmdparser: Use binary search for faster register
+      lookup
+    - SAUCE: i915_bpo: drm/i915/cmdparser: Check reg_table_count before
+      derefencing.
+    - SAUCE: i915_bpo: drm/i915: Remove Master tables from cmdparser
+    - SAUCE: i915_bpo: drm/i915: Add support for mandatory cmdparsing
+    - SAUCE: i915_bpo: drm/i915: Support ro ppgtt mapped cmdparser shadow buffers
+    - SAUCE: i915_bpo: drm/i915: Allow parsing of unsized batches
+    - SAUCE: i915_bpo: drm/i915: Add gen9 BCS cmdparsing
+    - SAUCE: i915_bpo: drm/i915/cmdparser: Add support for backward jumps
+    - SAUCE: i915_bpo: drm/i915/cmdparser: Ignore Length operands during command
+      matching
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 06 Nov 2019 09:50:06 +0100
+
+linux (4.4.0-167.196) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-167.196 -proposed tracker (LP: #1849051)
+
+  * Xenial update: 4.4.197 upstream stable release (LP: #1848780)
+    - KVM: s390: Test for bad access register and size at the start of S390_MEM_OP
+    - s390/topology: avoid firing events before kobjs are created
+    - s390/cio: avoid calling strlen on null pointer
+    - s390/cio: exclude subchannels with no parent from pseudo check
+    - KVM: nVMX: handle page fault in vmread fix
+    - ASoC: Define a set of DAPM pre/post-up events
+    - powerpc/powernv: Restrict OPAL symbol map to only be readable by root
+    - can: mcp251x: mcp251x_hw_reset(): allow more time after a reset
+    - crypto: qat - Silence smp_processor_id() warning
+    - ieee802154: atusb: fix use-after-free at disconnect
+    - cfg80211: initialize on-stack chandefs
+    - ima: always return negative code for error
+    - fs: nfs: Fix possible null-pointer dereferences in encode_attrs()
+    - 9p: avoid attaching writeback_fid on mmap with type PRIVATE
+    - xen/pci: reserve MCFG areas earlier
+    - ceph: fix directories inode i_blkbits initialization
+    - drm/amdgpu: Check for valid number of registers to read
+    - thermal: Fix use-after-free when unregistering thermal zone device
+    - fuse: fix memleak in cuse_channel_open
+    - kernel/elfcore.c: include proper prototypes
+    - tools lib traceevent: Do not free tep->cmdlines in add_new_comm() on failure
+    - perf stat: Fix a segmentation fault when using repeat forever
+    - crypto: caam - fix concurrency issue in givencrypt descriptor
+    - cfg80211: add and use strongly typed element iteration macros
+    - cfg80211: Use const more consistently in for_each_element macros
+    - nl80211: validate beacon head
+    - ASoC: sgtl5000: Improve VAG power and mute control
+    - panic: ensure preemption is disabled during panic()
+    - [Config] updateconfigs for USB_RIO500
+    - USB: rio500: Remove Rio 500 kernel driver
+    - USB: yurex: Don't retry on unexpected errors
+    - USB: yurex: fix NULL-derefs on disconnect
+    - USB: usb-skeleton: fix runtime PM after driver unbind
+    - USB: usb-skeleton: fix NULL-deref on disconnect
+    - xhci: Prevent device initiated U1/U2 link pm if exit latency is too long
+    - xhci: Check all endpoints for LPM timeout
+    - usb: xhci: wait for CNR controller not ready bit in xhci resume
+    - USB: adutux: remove redundant variable minor
+    - USB: adutux: fix use-after-free on disconnect
+    - USB: adutux: fix NULL-derefs on disconnect
+    - USB: adutux: fix use-after-free on release
+    - USB: iowarrior: fix use-after-free on disconnect
+    - USB: iowarrior: fix use-after-free on release
+    - USB: iowarrior: fix use-after-free after driver unbind
+    - USB: usblp: fix runtime PM after driver unbind
+    - USB: chaoskey: fix use-after-free on release
+    - USB: ldusb: fix NULL-derefs on driver unbind
+    - serial: uartlite: fix exit path null pointer
+    - USB: serial: keyspan: fix NULL-derefs on open() and write()
+    - USB: serial: ftdi_sio: add device IDs for Sienna and Echelon PL-20
+    - USB: serial: option: add Telit FN980 compositions
+    - USB: serial: option: add support for Cinterion CLS8 devices
+    - USB: serial: fix runtime PM after driver unbind
+    - USB: usblcd: fix I/O after disconnect
+    - USB: microtek: fix info-leak at probe
+    - USB: dummy-hcd: fix power budget for SuperSpeed mode
+    - usb: renesas_usbhs: gadget: Do not discard queues in
+      usb_ep_set_{halt,wedge}()
+    - usb: renesas_usbhs: gadget: Fix usb_ep_set_{halt,wedge}() behavior
+    - USB: legousbtower: fix slab info leak at probe
+    - USB: legousbtower: fix deadlock on disconnect
+    - USB: legousbtower: fix potential NULL-deref on disconnect
+    - USB: legousbtower: fix open after failed reset request
+    - USB: legousbtower: fix use-after-free on release
+    - staging: vt6655: Fix memory leak in vt6655_probe
+    - iio: adc: ad799x: fix probe error handling
+    - iio: light: opt3001: fix mutex unlock race
+    - perf llvm: Don't access out-of-scope array
+    - CIFS: Gracefully handle QueryInfo errors during open
+    - CIFS: Force reval dentry if LOOKUP_REVAL flag is set
+    - kernel/sysctl.c: do not override max_threads provided by userspace
+    - arm64: capabilities: Handle sign of the feature bit
+    - arm64: Rename cpuid_feature field extract routines
+    - Staging: fbtft: fix memory leak in fbtft_framebuffer_alloc
+    - cifs: Check uniqueid for SMB2+ and return -ESTALE if necessary
+    - CIFS: Force revalidate inode when dentry is stale
+    - media: stkwebcam: fix runtime PM after driver unbind
+    - tracing: Get trace_array reference for available_tracers files
+    - x86/asm: Fix MWAITX C-state hint value
+    - Linux 4.4.197
+    - [Config] updateconfigs for USB_RIO500
+
+  * CVE-2019-17666
+    - SAUCE: rtlwifi: Fix potential overflow on P2P code
+
+  * Suspend stopped working from 4.4.0-157 onwards (LP: #1844021) // Xenial
+    update: 4.4.197 upstream stable release (LP: #1848780)
+    - xhci: Increase STS_SAVE timeout in xhci_suspend()
+
+  * Ubuntu 16.04.6 - Shared CEX7C cards defined in z/VM guest not established by
+    zcrypt device driver (LP: #1848173)
+    - SAUCE: s390/zcrypt: CEX7 toleration support
+
+  * Xenial update: 4.4.196 upstream stable release (LP: #1848598)
+    - video: ssd1307fb: Start page range at page_offset
+    - gpu: drm: radeon: Fix a possible null-pointer dereference in
+      radeon_connector_set_property()
+    - ipmi_si: Only schedule continuously in the thread in maintenance mode
+    - clk: qoriq: Fix -Wunused-const-variable
+    - clk: sirf: Don't reference clk_init_data after registration
+    - powerpc/rtas: use device model APIs and serialization during LPM
+    - powerpc/futex: Fix warning: 'oldval' may be used uninitialized in this
+      function
+    - powerpc/pseries/mobility: use cond_resched when updating device tree
+    - pinctrl: tegra: Fix write barrier placement in pmx_writel
+    - vfio_pci: Restore original state on release
+    - powerpc/64s/exception: machine check use correct cfar for late handler
+    - powerpc/pseries: correctly track irq state in default idle
+    - scsi: core: Reduce memory required for SCSI logging
+    - mfd: intel-lpss: Remove D3cold delay
+    - ARM: 8898/1: mm: Don't treat faults reported from cache maintenance as
+      writes
+    - HID: apple: Fix stuck function keys when using FN
+    - security: smack: Fix possible null-pointer dereferences in
+      smack_socket_sock_rcv_skb()
+    - fat: work around race with userspace's read via blockdev while mounting
+    - hypfs: Fix error number left in struct pointer member
+    - ocfs2: wait for recovering done after direct unlock request
+    - kmemleak: increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE default to 16K
+    - ANDROID: binder: remove waitqueue when thread exits.
+    - ANDROID: binder: synchronize_rcu() when using POLLFREE.
+    - hso: fix NULL-deref on tty open
+    - ipv6: drop incoming packets having a v4mapped source address
+    - net: ipv4: avoid mixed n_redirects and rate_tokens usage
+    - net: qlogic: Fix memory leak in ql_alloc_large_buffers
+    - nfc: fix memory leak in llcp_sock_bind()
+    - sch_dsmark: fix potential NULL deref in dsmark_init()
+    - xen-netfront: do not use ~0U as error return value for xennet_fill_frags()
+    - net/rds: Fix error handling in rds_ib_add_one()
+    - sch_cbq: validate TCA_CBQ_WRROPT to avoid crash
+    - Smack: Don't ignore other bprm->unsafe flags if LSM_UNSAFE_PTRACE is set
+    - smack: use GFP_NOFS while holding inode_smack::smk_lock
+    - NFC: fix attrs checks in netlink interface
+    - Linux 4.4.196
+
+  * Xenial update: 4.4.195 upstream stable release (LP: #1848589)
+    - Revert "Bluetooth: validate BLE connection interval updates"
+    - HID: prodikeys: Fix general protection fault during probe
+    - HID: lg: make transfer buffers DMA capable
+    - HID: logitech: Fix general protection fault caused by Logitech driver
+    - HID: hidraw: Fix invalid read in hidraw_ioctl
+    - mtd: cfi_cmdset_0002: Use chip_good() to retry in do_write_oneword()
+    - crypto: talitos - fix missing break in switch statement
+    - net: rds: Fix NULL ptr use in rds_tcp_kill_sock
+    - ASoC: fsl: Fix of-node refcount unbalance in fsl_ssi_probe_from_dt()
+    - ALSA: hda - Add laptop imic fixup for ASUS M9V laptop
+    - SAUCE: Revert "mac80211: handle deauthentication/disassociation from TDLS
+      peer"
+    - mac80211: Print text for disassociation reason
+    - mac80211: handle deauthentication/disassociation from TDLS peer
+    - locking/lockdep: Add debug_locks check in __lock_downgrade()
+    - irqchip/gic-v3-its: Fix LPI release for Multi-MSI devices
+    - f2fs: check all the data segments against all node ones
+    - Revert "f2fs: avoid out-of-range memory access"
+    - f2fs: fix to do sanity check on segment bitmap of LFS curseg
+    - drm: Flush output polling on shutdown
+    - Bluetooth: btrtl: Additional Realtek 8822CE Bluetooth devices
+    - arcnet: provide a buffer big enough to actually receive packets
+    - cdc_ncm: fix divide-by-zero caused by invalid wMaxPacketSize
+    - net/phy: fix DP83865 10 Mbps HDX loopback disable function
+    - openvswitch: change type of UPCALL_PID attribute to NLA_UNSPEC
+    - sch_netem: fix a divide by zero in tabledist()
+    - skge: fix checksum byte order
+    - usbnet: ignore endpoints with invalid wMaxPacketSize
+    - usbnet: sanity checking of packet sizes and device mtu
+    - ALSA: hda: Flush interrupts on disabling
+    - ASoC: sgtl5000: Fix charge pump source assignment
+    - dmaengine: bcm2835: Print error in case setting DMA mask fails
+    - leds: leds-lp5562 allow firmware files up to the maximum length
+    - media: dib0700: fix link error for dibx000_i2c_set_speed
+    - media: hdpvr: Add device num check and handling
+    - sched/fair: Fix imbalance due to CPU affinity
+    - sched/core: Fix CPU controller for !RT_GROUP_SCHED
+    - x86/reboot: Always use NMI fallback when shutdown via reboot vector IPI
+      fails
+    - x86/apic: Soft disable APIC before initializing it
+    - ALSA: hda - Show the fatal CORB/RIRB error more clearly
+    - ALSA: i2c: ak4xxx-adda: Fix a possible null pointer dereference in
+      build_adc_controls()
+    - media: iguanair: add sanity checks
+    - base: soc: Export soc_device_register/unregister APIs
+    - ALSA: usb-audio: Skip bSynchAddress endpoint check if it is invalid
+    - ia64:unwind: fix double free for mod->arch.init_unw_table
+    - md: don't call spare_active in md_reap_sync_thread if all member devices
+      can't work
+    - md: don't set In_sync if array is frozen
+    - efi: cper: print AER info of PCIe fatal error
+    - media: gspca: zero usb_buf on error
+    - dmaengine: iop-adma: use correct printk format strings
+    - media: omap3isp: Don't set streaming state on random subdevs
+    - net: lpc-enet: fix printk format strings
+    - media: radio/si470x: kill urb on error
+    - media: hdpvr: add terminating 0 at end of string
+    - media: saa7146: add cleanup in hexium_attach()
+    - media: cpia2_usb: fix memory leaks
+    - media: saa7134: fix terminology around saa7134_i2c_eeprom_md7134_gate()
+    - media: ov9650: add a sanity check
+    - ACPI / CPPC: do not require the _PSD method
+    - libtraceevent: Change users plugin directory
+    - ACPI: custom_method: fix memory leaks
+    - hwmon: (acpi_power_meter) Change log level for 'unsafe software power cap'
+    - md/raid1: fail run raid1 array when active disk less than one
+    - dmaengine: ti: edma: Do not reset reserved paRAM slots
+    - kprobes: Prohibit probing on BUG() and WARN() address
+    - ASoC: dmaengine: Make the pcm->name equal to pcm->id if the name is not set
+    - mmc: sdhci: Fix incorrect switch to HS mode
+    - libertas: Add missing sentinel at end of if_usb.c fw_table
+    - media: ttusb-dec: Fix info-leak in ttusb_dec_send_command()
+    - ALSA: hda/realtek - Blacklist PC beep for Lenovo ThinkCentre M73/93
+    - btrfs: extent-tree: Make sure we only allocate extents from block groups
+      with the same type
+    - media: omap3isp: Set device on omap3isp subdevs
+    - ALSA: firewire-tascam: handle error code when getting current source of
+      clock
+    - ALSA: firewire-tascam: check intermediate state of clock status and retry
+    - printk: Do not lose last line in kmsg buffer dump
+    - fuse: fix missing unlock_page in fuse_writepage()
+    - parisc: Disable HP HSC-PCI Cards to prevent kernel crash
+    - KVM: x86: always stop emulation on page fault
+    - KVM: x86: set ctxt->have_exception in x86_decode_insn()
+    - KVM: x86: Manually calculate reserved bits when loading PDPTRS
+    - media: sn9c20x: Add MSI MS-1039 laptop to flip_dmi_table
+    - ASoC: Intel: Fix use of potentially uninitialized variable
+    - ARM: zynq: Use memcpy_toio instead of memcpy on smp bring-up
+    - alarmtimer: Use EOPNOTSUPP instead of ENOTSUPP
+    - md/raid6: Set R5_ReadError when there is read failure on parity disk
+    - cfg80211: Purge frame registrations on iftype change
+    - /dev/mem: Bail out upon SIGKILL.
+    - ext4: fix punch hole for inline_data file systems
+    - quota: fix wrong condition in is_quota_modification()
+    - hwrng: core - don't wait on add_early_randomness()
+    - i2c: riic: Clear NACK in tend isr
+    - CIFS: Fix oplock handling for SMB 2.1+ protocols
+    - ovl: filter of trusted xattr results in audit
+    - Btrfs: fix use-after-free when using the tree modification log
+    - btrfs: Relinquish CPUs in btrfs_compare_trees
+    - Btrfs: fix race setting up and completing qgroup rescan workers
+    - Linux 4.4.195
+
+  * [Packaging] Support building Flattened Image Tree (FIT) kernels
+    (LP: #1847969)
+    - [Packaging] add rules to build FIT image
+    - [Packaging] force creation of headers directory
+
+  * bcache: Performance degradation when querying priority_stats (LP: #1840043)
+    - bcache: add cond_resched() in __bch_cache_cmp()
+
+  * Add installer support for iwlmvm adapters (LP: #1848236)
+    - d-i: Add iwlmvm to nic-modules
+
+  * Bad posix clock speculation mitigation backport (LP: #1847189)
+    - SAUCE: Fix posix clock speculation mitigation backport
+
+  * PM / hibernate: fix potential memory corruption (LP: #1847118)
+    - PM / hibernate: memory_bm_find_bit -- tighten node optimisation
+
+  * CVE-2019-17056
+    - nfc: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-17055
+    - mISDN: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-17054
+    - appletalk: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-17053
+    - ieee802154: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-17052
+    - ax25: enforce CAP_NET_RAW for raw sockets
+
+  * CVE-2019-15098
+    - ath6kl: fix a NULL-ptr-deref bug in ath6kl_usb_alloc_urb_from_pipe()
+
+  * arm64: sigaltstack fails with MINSIGSTKSZ for 32-bit processes
+    (LP: #1844155)
+    - signal: Introduce COMPAT_SIGMINSTKSZ for use in compat_sys_sigaltstack
+    - arm64: compat: Provide definition for COMPAT_SIGMINSTKSZ
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Mon, 21 Oct 2019 14:56:55 -0400
+
+linux (4.4.0-166.195) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-166.195 -proposed tracker (LP: #1846069)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * CVE-2017-18232
+    - scsi: libsas: direct call probe and destruct
+
+  * CVE-2018-21008
+    - rsi: add fix for crash during assertions
+
+  * Xenial update: 4.4.194 upstream stable release (LP: #1845405)
+    - bridge/mdb: remove wrong use of NLM_F_MULTI
+    - cdc_ether: fix rndis support for Mediatek based smartphones
+    - ipv6: Fix the link time qualifier of 'ping_v6_proc_exit_net()'
+    - isdn/capi: check message length in capi_write()
+    - net: Fix null de-reference of device refcount
+    - sch_hhf: ensure quantum and hhf_non_hh_weight are non-zero
+    - sctp: Fix the link time qualifier of 'sctp_ctrlsock_exit()'
+    - sctp: use transport pf_retrans in sctp_do_8_2_transport_strike
+    - tcp: fix tcp_ecn_withdraw_cwr() to clear TCP_ECN_QUEUE_CWR
+    - tipc: add NULL pointer check before calling kfree_rcu
+    - tun: fix use-after-free when register netdev failed
+    - Revert "MIPS: SiByte: Enable swiotlb for SWARM, LittleSur and BigSur"
+    - Btrfs: fix assertion failure during fsync and use of stale transaction
+    - genirq: Prevent NULL pointer dereference in resend_irqs()
+    - KVM: s390: Do not leak kernel stack data in the KVM_S390_INTERRUPT ioctl
+    - KVM: x86: work around leak of uninitialized stack contents
+    - KVM: nVMX: handle page fault in vmread
+    - MIPS: VDSO: Prevent use of smp_processor_id()
+    - MIPS: VDSO: Use same -m%-float cflag as the kernel proper
+    - clk: rockchip: Don't yell about bad mmc phases when getting
+    - driver core: Fix use-after-free and double free on glue directory
+    - crypto: talitos - check AES key size
+    - crypto: talitos - check data blocksize in ablkcipher.
+    - x86/build: Add -Wnoaddress-of-packed-member to REALMODE_CFLAGS, to silence
+      GCC9 build warning
+    - MIPS: netlogic: xlr: Remove erroneous check in nlm_fmn_send()
+    - ARC: configs: Remove CONFIG_INITRAMFS_SOURCE from defconfigs
+    - USB: usbcore: Fix slab-out-of-bounds bug during device reset
+    - media: tm6000: double free if usb disconnect while streaming
+    - x86/boot: Add missing bootparam that breaks boot on some platforms
+    - xen-netfront: do not assume sk_buff_head list is empty in error handling
+    - serial: sprd: correct the wrong sequence of arguments
+    - tty/serial: atmel: reschedule TX after RX was started
+    - mwifiex: Fix three heap overflow at parsing element in cfg80211_ap_settings
+    - s390/bpf: fix lcgr instruction encoding
+    - ARM: OMAP2+: Fix omap4 errata warning on other SoCs
+    - s390/bpf: use 32-bit index for tail calls
+    - NFSv4: Fix return values for nfs4_file_open()
+    - NFS: Fix initialisation of I/O result struct in nfs_pgio_rpcsetup
+    - Kconfig: Fix the reference to the IDT77105 Phy driver in the description of
+      ATM_NICSTAR_USE_IDT77105
+    - ARM: 8874/1: mm: only adjust sections of valid mm structures
+    - r8152: Set memory to all 0xFFs on failed reg reads
+    - x86/apic: Fix arch_dynirq_lower_bound() bug for DT enabled machines
+    - netfilter: nf_conntrack_ftp: Fix debug output
+    - NFSv2: Fix eof handling
+    - NFSv2: Fix write regression
+    - cifs: set domainName when a domain-key is used in multiuser
+    - cifs: Use kzfree() to zero out the password
+    - sky2: Disable MSI on yet another ASUS boards (P6Xxxx)
+    - tools/power turbostat: fix buffer overrun
+    - net: seeq: Fix the function used to release some memory in an error handling
+      path
+    - dmaengine: ti: omap-dma: Add cleanup in omap_dma_probe()
+    - keys: Fix missing null pointer check in request_key_auth_describe()
+    - floppy: fix usercopy direction
+    - media: technisat-usb2: break out of loop at end of buffer
+    - ARC: export "abort" for modules
+    - net_sched: let qdisc_put() accept NULL pointer
+    - Linux 4.4.194
+
+  * CVE-2019-14821
+    - KVM: coalesced_mmio: add bounds checking
+
+  * Xenial update: 4.4.193 upstream stable release (LP: #1845395)
+    - ALSA: hda - Fix potential endless loop at applying quirks
+    - ALSA: hda/realtek - Fix overridden device-specific initialization
+    - xfrm: clean up xfrm protocol checks
+    - vhost/test: fix build for vhost test
+    - scripts/decode_stacktrace: match basepath using shell prefix operator, not
+      regex
+    - clk: s2mps11: Add used attribute to s2mps11_dt_match
+    - x86, boot: Remove multiple copy of static function sanitize_boot_params()
+    - af_packet: tone down the Tx-ring unsupported spew.
+    - Linux 4.4.193
+
+  * Xenial update: 4.4.192 upstream stable release (LP: #1845374)
+    - net: tundra: tsi108: use spin_lock_irqsave instead of spin_lock_irq in IRQ
+      context
+    - net: tc35815: Explicitly check NET_IP_ALIGN is not zero in tc35815_rx
+    - Bluetooth: btqca: Add a short delay before downloading the NVM
+    - ibmveth: Convert multicast list size for little-endian system
+    - gpio: Fix build error of function redefinition
+    - cxgb4: fix a memory leak bug
+    - net: myri10ge: fix memory leaks
+    - cx82310_eth: fix a memory leak bug
+    - net: kalmia: fix memory leaks
+    - wimax/i2400m: fix a memory leak bug
+    - ravb: Fix use-after-free ravb_tstamp_skb
+    - Tools: hv: kvp: eliminate 'may be used uninitialized' warning
+    - IB/mlx4: Fix memory leaks
+    - ceph: fix buffer free while holding i_ceph_lock in __ceph_setxattr()
+    - KVM: arm/arm64: Only skip MMIO insn once
+    - libceph: allow ceph_buffer_put() to receive a NULL ceph_buffer
+    - spi: bcm2835aux: ensure interrupts are enabled for shared handler
+    - spi: bcm2835aux: unifying code between polling and interrupt driven code
+    - spi: bcm2835aux: remove dangerous uncontrolled read of fifo
+    - spi: bcm2835aux: fix corruptions for longer spi transfers
+    - Revert "x86/apic: Include the LDR when clearing out APIC registers"
+    - net: fix skb use after free in netpoll
+    - net: stmmac: dwmac-rk: Don't fail if phy regulator is absent
+    - Linux 4.4.192
+
+  * Xenial update: 4.4.191 upstream stable release (LP: #1845036)
+    - HID: Add 044f:b320 ThrustMaster, Inc. 2 in 1 DT
+    - MIPS: kernel: only use i8253 clocksource with periodic clockevent
+    - netfilter: ebtables: fix a memory leak bug in compat
+    - bonding: Force slave speed check after link state recovery for 802.3ad
+    - can: dev: call netif_carrier_off() in register_candev()
+    - st21nfca_connectivity_event_received: null check the allocation
+    - st_nci_hci_connectivity_event_received: null check the allocation
+    - ASoC: ti: davinci-mcasp: Correct slot_width posed constraint
+    - net: usb: qmi_wwan: Add the BroadMobi BM818 card
+    - isdn: mISDN: hfcsusb: Fix possible null-pointer dereferences in
+      start_isoc_chain()
+    - isdn: hfcsusb: Fix mISDN driver crash caused by transfer buffer on the stack
+    - perf bench numa: Fix cpu0 binding
+    - can: sja1000: force the string buffer NULL-terminated
+    - can: peak_usb: force the string buffer NULL-terminated
+    - NFSv4: Fix a potential sleep while atomic in nfs4_do_reclaim()
+    - net: cxgb3_main: Fix a resource leak in a error path in 'init_one()'
+    - net: hisilicon: make hip04_tx_reclaim non-reentrant
+    - net: hisilicon: fix hip04-xmit never return TX_BUSY
+    - net: hisilicon: Fix dma_map_single failed on arm64
+    - libata: add SG safety checks in SFF pio transfers
+    - selftests: kvm: Adding config fragments
+    - HID: wacom: correct misreported EKR ring values
+    - Revert "dm bufio: fix deadlock with loop device"
+    - userfaultfd_release: always remove uffd flags and clear vm_userfaultfd_ctx
+    - x86/retpoline: Don't clobber RFLAGS during CALL_NOSPEC on i386
+    - x86/apic: Handle missing global clockevent gracefully
+    - x86/boot: Save fields explicitly, zero out everything else
+    - x86/boot: Fix boot regression caused by bootparam sanitizing
+    - dm btree: fix order of block initialization in btree_split_beneath
+    - dm space map metadata: fix missing store of apply_bops() return value
+    - dm table: fix invalid memory accesses with too high sector number
+    - cgroup: Disable IRQs while holding css_set_lock
+    - net: arc_emac: fix koops caused by sk_buff free
+    - siphash: implement HalfSipHash1-3 for hash tables
+    - netfilter: ctnetlink: don't use conntrack/expect object addresses as id
+    - netfilter: conntrack: Use consistent ct id hash calculation
+    - x86/pm: Introduce quirk framework to save/restore extra MSR registers around
+      suspend/resume
+    - x86/CPU/AMD: Clear RDRAND CPUID bit on AMD family 15h/16h
+    - scsi: ufs: Fix NULL pointer dereference in ufshcd_config_vreg_hpm()
+    - dmaengine: ste_dma40: fix unneeded variable warning
+    - usb: gadget: composite: Clear "suspended" on reset/disconnect
+    - usb: host: fotg2: restart hcd after port reset
+    - tools: hv: fix KVP and VSS daemons exit code
+    - watchdog: bcm2835_wdt: Fix module autoload
+    - tcp: fix tcp_rtx_queue_tail in case of empty retransmit queue
+    - ALSA: usb-audio: Fix a stack buffer overflow bug in check_input_term
+    - ALSA: usb-audio: Fix an OOB bug in parse_audio_mixer_unit
+    - tcp: make sure EPOLLOUT wont be missed
+    - ALSA: seq: Fix potential concurrent access to the deleted pool
+    - KVM: x86: Don't update RIP or do single-step on faulting emulation
+    - x86/apic: Do not initialize LDR and DFR for bigsmp
+    - x86/apic: Include the LDR when clearing out APIC registers
+    - usb-storage: Add new JMS567 revision to unusual_devs
+    - USB: cdc-wdm: fix race between write and disconnect due to flag abuse
+    - usb: host: ohci: fix a race condition between shutdown and irq
+    - USB: storage: ums-realtek: Update module parameter description for
+      auto_delink_en
+    - ptrace,x86: Make user_64bit_mode() available to 32-bit builds
+    - uprobes/x86: Fix detection of 32-bit user mode
+    - mmc: sdhci-of-at91: add quirk for broken HS200
+    - mmc: core: Fix init of SD cards reporting an invalid VDD range
+    - stm class: Fix a double free of stm_source_device
+    - VMCI: Release resource if the work is already queued
+    - Revert "cfg80211: fix processing world regdomain when non modular"
+    - mac80211: fix possible sta leak
+    - x86/ptrace: fix up botched merge of spectrev1 fix
+    - Linux 4.4.191
+
+  * New ID in ums-realtek module breaks cardreader (LP: #1838886) // Xenial
+    update: 4.4.191 upstream stable release (LP: #1845036)
+    - USB: storage: ums-realtek: Whitelist auto-delink support
+
+  * Xenial update: 4.4.190 upstream stable release (LP: #1845038)
+    - usb: iowarrior: fix deadlock on disconnect
+    - sound: fix a memory leak bug
+    - x86/mm: Check for pfn instead of page in vmalloc_sync_one()
+    - x86/mm: Sync also unmappings in vmalloc_sync_all()
+    - mm/vmalloc: Sync unmappings in __purge_vmap_area_lazy()
+    - perf db-export: Fix thread__exec_comm()
+    - usb: yurex: Fix use-after-free in yurex_delete
+    - can: peak_usb: fix potential double kfree_skb()
+    - netfilter: nfnetlink: avoid deadlock due to synchronous request_module
+    - iscsi_ibft: make ISCSI_IBFT dependson ACPI instead of ISCSI_IBFT_FIND
+    - mac80211: don't warn about CW params when not using them
+    - hwmon: (nct6775) Fix register address and added missed tolerance for nct6106
+    - cpufreq/pasemi: fix use-after-free in pas_cpufreq_cpu_init()
+    - s390/qdio: add sanity checks to the fast-requeue path
+    - ALSA: compress: Fix regression on compressed capture streams
+    - ALSA: compress: Prevent bypasses of set_params
+    - ALSA: compress: Be more restrictive about when a drain is allowed
+    - perf probe: Avoid calling freeing routine multiple times for same pointer
+    - ARM: davinci: fix sleep.S build error on ARMv4
+    - scsi: megaraid_sas: fix panic on loading firmware crashdump
+    - scsi: ibmvfc: fix WARN_ON during event pool release
+    - tty/ldsem, locking/rwsem: Add missing ACQUIRE to read_failed sleep loop
+    - perf/core: Fix creating kernel counters for PMUs that override event->cpu
+    - can: peak_usb: pcan_usb_pro: Fix info-leaks to USB devices
+    - can: peak_usb: pcan_usb_fd: Fix info-leaks to USB devices
+    - hwmon: (nct7802) Fix wrong detection of in4 presence
+    - ALSA: firewire: fix a memory leak bug
+    - mac80211: don't WARN on short WMM parameters from AP
+    - SMB3: Fix deadlock in validate negotiate hits reconnect
+    - smb3: send CAP_DFS capability during session setup
+    - mwifiex: fix 802.11n/WPA detection
+    - scsi: mpt3sas: Use 63-bit DMA addressing on SAS35 HBA
+    - sh: kernel: hw_breakpoint: Fix missing break in switch statement
+    - mm/memcontrol.c: fix use after free in mem_cgroup_iter()
+    - ALSA: hda - Fix a memory leak bug
+    - HID: holtek: test for sanity of intfdata
+    - HID: hiddev: avoid opening a disconnected device
+    - HID: hiddev: do cleanup in failure of opening a device
+    - Input: kbtab - sanity check for endpoint type
+    - Input: iforce - add sanity checks
+    - net: usb: pegasus: fix improper read if get_registers() fail
+    - xen/pciback: remove set but not used variable 'old_state'
+    - irqchip/irq-imx-gpcv2: Forward irq type to parent
+    - perf header: Fix divide by zero error if f_header.attr_size==0
+    - perf header: Fix use of unitialized value warning
+    - libata: zpodd: Fix small read overflow in zpodd_get_mech_type()
+    - scsi: hpsa: correct scsi command status issue after reset
+    - ata: libahci: do not complain in case of deferred probe
+    - kbuild: modpost: handle KBUILD_EXTRA_SYMBOLS only for external modules
+    - IB/core: Add mitigation for Spectre V1
+    - ocfs2: remove set but not used variable 'last_hash'
+    - asm-generic: fix -Wtype-limits compiler warnings
+    - staging: comedi: dt3000: Fix signed integer overflow 'divider * base'
+    - staging: comedi: dt3000: Fix rounding up of timer divisor
+    - USB: core: Fix races in character device registration and deregistraion
+    - usb: cdc-acm: make sure a refcount is taken early enough
+    - USB: serial: option: add D-Link DWM-222 device ID
+    - USB: serial: option: Add support for ZTE MF871A
+    - USB: serial: option: add the BroadMobi BM818 card
+    - USB: serial: option: Add Motorola modem UARTs
+    - Backport minimal compiler_attributes.h to support GCC 9
+    - include/linux/module.h: copy __init/__exit attrs to init/cleanup_module
+    - arm64: compat: Allow single-byte watchpoints on all addresses
+    - Input: psmouse - fix build error of multiple definition
+    - asm-generic: default BUG_ON(x) to if(x)BUG()
+    - scsi: fcoe: Embed fc_rport_priv in fcoe_rport structure
+    - RDMA: Directly cast the sockaddr union to sockaddr
+    - IB/mlx5: Make coding style more consistent
+    - x86/vdso: Remove direct HPET access through the vDSO
+    - iommu/amd: Move iommu_init_pci() to .init section
+    - x86/boot: Disable the address-of-packed-member compiler warning
+    - net/packet: fix race in tpacket_snd()
+    - xen/netback: Reset nr_frags before freeing skb
+    - net/mlx5e: Only support tx/rx pause setting for port owner
+    - sctp: fix the transport error_count check
+    - bonding: Add vlan tx offload to hw_enc_features
+    - Linux 4.4.190
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 01 Oct 2019 10:23:59 +0200
+
+linux (4.4.0-165.193) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-165.193 -proposed tracker (LP: #1844416)
+
+  * Xenial update: 4.4.187 upstream stable release (LP: #1840081)
+    - MIPS: ath79: fix ar933x uart parity mode
+    - MIPS: fix build on non-linux hosts
+    - dmaengine: imx-sdma: fix use-after-free on probe error path
+    - ath10k: Do not send probe response template for mesh
+    - ath9k: Check for errors when reading SREV register
+    - ath6kl: add some bounds checking
+    - ath: DFS JP domain W56 fixed pulse type 3 RADAR detection
+    - batman-adv: fix for leaked TVLV handler.
+    - media: dvb: usb: fix use after free in dvb_usb_device_exit
+    - crypto: talitos - fix skcipher failure due to wrong output IV
+    - media: marvell-ccic: fix DMA s/g desc number calculation
+    - media: vpss: fix a potential NULL pointer dereference
+    - net: stmmac: dwmac1000: Clear unused address entries
+    - signal/pid_namespace: Fix reboot_pid_ns to use send_sig not force_sig
+    - af_key: fix leaks in key_pol_get_resp and dump_sp.
+    - xfrm: Fix xfrm sel prefix length validation
+    - media: staging: media: davinci_vpfe: - Fix for memory leak if decoder
+      initialization fails.
+    - net: phy: Check against net_device being NULL
+    - tua6100: Avoid build warnings.
+    - locking/lockdep: Fix merging of hlocks with non-zero references
+    - media: wl128x: Fix some error handling in fm_v4l2_init_video_device()
+    - cpupower : frequency-set -r option misses the last cpu in related cpu list
+    - net: fec: Do not use netdev messages too early
+    - net: axienet: Fix race condition causing TX hang
+    - s390/qdio: handle PENDING state for QEBSM devices
+    - perf test 6: Fix missing kvm module load for s390
+    - gpio: omap: fix lack of irqstatus_raw0 for OMAP4
+    - gpio: omap: ensure irq is enabled before wakeup
+    - regmap: fix bulk writes on paged registers
+    - bpf: silence warning messages in core
+    - rcu: Force inlining of rcu_read_lock()
+    - xfrm: fix sa selector validation
+    - perf evsel: Make perf_evsel__name() accept a NULL argument
+    - vhost_net: disable zerocopy by default
+    - EDAC/sysfs: Fix memory leak when creating a csrow object
+    - media: i2c: fix warning same module names
+    - ntp: Limit TAI-UTC offset
+    - timer_list: Guard procfs specific code
+    - acpi/arm64: ignore 5.1 FADTs that are reported as 5.0
+    - media: coda: fix mpeg2 sequence number handling
+    - media: coda: increment sequence offset for the last returned frame
+    - mt7601u: do not schedule rx_tasklet when the device has been disconnected
+    - x86/build: Add 'set -e' to mkcapflags.sh to delete broken capflags.c
+    - mt7601u: fix possible memory leak when the device is disconnected
+    - ath10k: fix PCIE device wake up failed
+    - rslib: Fix decoding of shortened codes
+    - rslib: Fix handling of of caller provided syndrome
+    - ixgbe: Check DDM existence in transceiver before access
+    - EDAC: Fix global-out-of-bounds write when setting edac_mc_poll_msec
+    - bcache: check c->gc_thread by IS_ERR_OR_NULL in cache_set_flush()
+    - Bluetooth: hci_bcsp: Fix memory leak in rx_skb
+    - Bluetooth: 6lowpan: search for destination address in all peers
+    - Bluetooth: Check state in l2cap_disconnect_rsp
+    - Bluetooth: validate BLE connection interval updates
+    - crypto: ghash - fix unaligned memory access in ghash_setkey()
+    - crypto: arm64/sha1-ce - correct digest for empty data in finup
+    - crypto: arm64/sha2-ce - correct digest for empty data in finup
+    - Input: gtco - bounds check collection indent level
+    - regulator: s2mps11: Fix buck7 and buck8 wrong voltages
+    - tracing/snapshot: Resize spare buffer if size changed
+    - NFSv4: Handle the special Linux file open access mode
+    - lib/scatterlist: Fix mapping iterator when sg->offset is greater than
+      PAGE_SIZE
+    - ALSA: seq: Break too long mutex context in the write loop
+    - media: v4l2: Test type instead of cfg->type in v4l2_ctrl_new_custom()
+    - media: coda: Remove unbalanced and unneeded mutex unlock
+    - KVM: x86/vPMU: refine kvm_pmu err msg when event creation failed
+    - drm/nouveau/i2c: Enable i2c pads & busses during preinit
+    - padata: use smp_mb in padata_reorder to avoid orphaned padata jobs
+    - 9p/virtio: Add cleanup path in p9_virtio_init
+    - PCI: Do not poll for PME if the device is in D3cold
+    - take floppy compat ioctls to sodding floppy.c
+    - floppy: fix out-of-bounds read in next_valid_format
+    - floppy: fix invalid pointer dereference in drive_name
+    - coda: pass the host file in vma->vm_file on mmap
+    - gpu: ipu-v3: ipu-ic: Fix saturation bit offset in TPMEM
+    - parisc: Fix kernel panic due invalid values in IAOQ0 or IAOQ1
+    - powerpc/32s: fix suspend/resume when IBATs 4-7 are used
+    - powerpc/watchpoint: Restore NV GPRs while returning from exception
+    - eCryptfs: fix a couple type promotion bugs
+    - intel_th: msu: Fix single mode with disabled IOMMU
+    - Bluetooth: Add SMP workaround Microsoft Surface Precision Mouse bug
+    - usb: Handle USB3 remote wakeup for LPM enabled devices correctly
+    - dm bufio: fix deadlock with loop device
+    - bnx2x: Prevent load reordering in tx completion processing
+    - caif-hsi: fix possible deadlock in cfhsi_exit_module()
+    - ipv4: don't set IPv6 only flags to IPv4 addresses
+    - net: bcmgenet: use promisc for unsupported filters
+    - net: neigh: fix multiple neigh timer scheduling
+    - nfc: fix potential illegal memory access
+    - sky2: Disable MSI on ASUS P6T
+    - netrom: fix a memory leak in nr_rx_frame()
+    - netrom: hold sock when setting skb->destructor
+    - tcp: Reset bytes_acked and bytes_received when disconnecting
+    - bonding: validate ip header before check IPPROTO_IGMP
+    - net: bridge: mcast: fix stale nsrcs pointer in igmp3/mld2 report handling
+    - net: bridge: mcast: fix stale ipv6 hdr pointer when handling v6 query
+    - net: bridge: stp: don't cache eth dest pointer before skb pull
+    - elevator: fix truncation of icq_cache_name
+    - NFSv4: Fix open create exclusive when the server reboots
+    - nfsd: increase DRC cache limit
+    - nfsd: give out fewer session slots as limit approaches
+    - nfsd: fix performance-limiting session calculation
+    - nfsd: Fix overflow causing non-working mounts on 1 TB machines
+    - drm/panel: simple: Fix panel_simple_dsi_probe
+    - usb: core: hub: Disable hub-initiated U1/U2
+    - tty: max310x: Fix invalid baudrate divisors calculator
+    - pinctrl: rockchip: fix leaked of_node references
+    - tty: serial: cpm_uart - fix init when SMC is relocated
+    - memstick: Fix error cleanup path of memstick_init
+    - tty/serial: digicolor: Fix digicolor-usart already registered warning
+    - tty: serial: msm_serial: avoid system lockup condition
+    - drm/virtio: Add memory barriers for capset cache.
+    - phy: renesas: rcar-gen2: Fix memory leak at error paths
+    - usb: gadget: Zero ffs_io_data
+    - powerpc/pci/of: Fix OF flags parsing for 64bit BARs
+    - PCI: sysfs: Ignore lockdep for remove attribute
+    - iio: iio-utils: Fix possible incorrect mask calculation
+    - recordmcount: Fix spurious mcount entries on powerpc
+    - mfd: core: Set fwnode for created devices
+    - mfd: arizona: Fix undefined behavior
+    - um: Silence lockdep complaint about mmap_sem
+    - powerpc/4xx/uic: clear pending interrupt after irq type/pol change
+    - serial: sh-sci: Fix TX DMA buffer flushing and workqueue races
+    - kallsyms: exclude kasan local symbols on s390
+    - perf test mmap-thread-lookup: Initialize variable to suppress memory
+      sanitizer warning
+    - f2fs: avoid out-of-range memory access
+    - mailbox: handle failed named mailbox channel request
+    - powerpc/eeh: Handle hugepages in ioremap space
+    - sh: prevent warnings when using iounmap
+    - mm/kmemleak.c: fix check for softirq context
+    - 9p: pass the correct prototype to read_cache_page
+    - mm/mmu_notifier: use hlist_add_head_rcu()
+    - locking/lockdep: Fix lock used or unused stats error
+    - locking/lockdep: Hide unused 'class' variable
+    - usb: wusbcore: fix unbalanced get/put cluster_id
+    - usb: pci-quirks: Correct AMD PLL quirk detection
+    - x86/sysfb_efi: Add quirks for some devices with swapped width and height
+    - x86/speculation/mds: Apply more accurate check on hypervisor platform
+    - hpet: Fix division by zero in hpet_time_div()
+    - ALSA: hda - Add a conexant codec entry to let mute led work
+    - access: avoid the RCU grace period for the temporary subjective credentials
+    - vmstat: Remove BUG_ON from vmstat_update
+    - mm, vmstat: make quiet_vmstat lighter
+    - ipv6: check sk sk_type and protocol early in ip_mroute_set/getsockopt
+    - tcp: reset sk_send_head in tcp_write_queue_purge
+    - ISDN: hfcsusb: checking idx of ep configuration
+    - media: cpia2_usb: first wake up, then free in disconnect
+    - media: radio-raremono: change devm_k*alloc to k*alloc
+    - Bluetooth: hci_uart: check for missing tty operations
+    - sched/fair: Don't free p->numa_faults with concurrent readers
+    - drivers/pps/pps.c: clear offset flags in PPS_SETPARAMS ioctl
+    - ceph: hold i_ceph_lock when removing caps for freeing inode
+    - Linux 4.4.187
+    - perf tests: Add valid callback for parse-events test
+    - SAUCE: Fix perf test 6: Fix missing kvm module load for s390
+
+  * CVE-2018-20976
+    - xfs: clear sb->s_fs_info on mount failure
+
+  * Xenial update: 4.4.189 upstream stable release (LP: #1840335)
+    - arm64: cpufeature: Fix CTR_EL0 field definitions
+    - arm64: cpufeature: Fix feature comparison for CTR_EL0.{CWG,ERG}
+    - netfilter: nfnetlink_acct: validate NFACCT_QUOTA parameter
+    - HID: Add quirk for HP X1200 PIXART OEM mouse
+    - tcp: be more careful in tcp_fragment()
+    - atm: iphase: Fix Spectre v1 vulnerability
+    - net: bridge: delete local fdb on device init failure
+    - net: fix ifindex collision during namespace removal
+    - tipc: compat: allow tipc commands without arguments
+    - net: sched: Fix a possible null-pointer dereference in dequeue_func()
+    - net/mlx5: Use reversed order when unregister devices
+    - bnx2x: Disable multi-cos feature.
+    - compat_ioctl: pppoe: fix PPPOEIOCSFWD handling
+    - spi: bcm2835: Fix 3-wire mode if DMA is enabled
+    - x86: cpufeatures: Sort feature word 7
+    - x86/entry/64: Fix context tracking state warning when load_gs_index fails
+    - Linux 4.4.189
+
+  * CVE-2019-0136
+    - mac80211: handle deauthentication/disassociation from TDLS peer
+
+  * skb_warn_bad_offload kernel splat due to CHECKSUM target not compatible with
+    GSO skbs (LP: #1840619)
+    - netfilter: xt_checksum: ignore gso skbs
+
+  * CVE-2018-20961
+    - usb: gadget: f_midi: fail if set_alt fails to allocate requests
+    - USB: gadget: f_midi: fixing a possible double-free in f_midi
+
+  * CVE-2019-11487
+    - pipe: add pipe_buf_get() helper
+    - mm: add 'try_get_page()' helper function
+    - fs: prevent page refcount overflow in pipe_buf_get
+    - mm: make page ref count overflow check tighter and more explicit
+    - mm, gup: ensure real head page is ref-counted when using hugepages
+    - mm: prevent get_user_pages() from overflowing page refcount
+
+  * Xenial update: 4.4.188 upstream stable release (LP: #1840289)
+    - ARM: riscpc: fix DMA
+    - ARM: dts: rockchip: Mark that the rk3288 timer might stop in suspend
+    - kernel/module.c: Only return -EEXIST for modules that have finished loading
+    - MIPS: lantiq: Fix bitfield masking
+    - dmaengine: rcar-dmac: Reject zero-length slave DMA requests
+    - fs/adfs: super: fix use-after-free bug
+    - btrfs: fix minimum number of chunk errors for DUP
+    - ceph: fix improper use of smp_mb__before_atomic()
+    - scsi: zfcp: fix GCC compiler warning emitted with -Wmaybe-uninitialized
+    - ACPI: fix false-positive -Wuninitialized warning
+    - be2net: Signal that the device cannot transmit during reconfiguration
+    - x86/apic: Silence -Wtype-limits compiler warnings
+    - x86: math-emu: Hide clang warnings for 16-bit overflow
+    - mm/cma.c: fail if fixed declaration can't be honored
+    - coda: add error handling for fget
+    - coda: fix build using bare-metal toolchain
+    - uapi linux/coda_psdev.h: move upc_req definition from uapi to kernel side
+      headers
+    - ipc/mqueue.c: only perform resource calculation if user valid
+    - x86/kvm: Don't call kvm_spurious_fault() from .fixup
+    - selinux: fix memory leak in policydb_init()
+    - s390/dasd: fix endless loop after read unit address configuration
+    - xen/swiotlb: fix condition for calling xen_destroy_contiguous_region()
+    - Linux 4.4.188
+
+  * Line 6 POD HD500 driver fault (LP: #1790595) // Xenial update: 4.4.187
+    upstream stable release (LP: #1840081)
+    - ALSA: line6: Fix wrong altsetting for LINE6_PODHD500_1
+
+  * CVE-2016-10905
+    - GFS2: don't set rgrp gl_object until it's inserted into rgrp tree
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 17 Sep 2019 18:24:13 +0200
+
+linux (4.4.0-164.192) xenial; urgency=medium
+
+  * CVE-2019-14835
+    - SAUCE: vhost: make sure log_num < in_num
+
+ -- Juerg Haefliger <juergh@canonical.com>  Fri, 13 Sep 2019 12:55:05 +0200
+
+linux (4.4.0-161.189) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-161.189 -proposed tracker (LP: #1841544)
+
+  * flock not mediated by 'k' (LP: 1658219)
+    - Revert "UBUNTU: SAUCE: apparmor: flock mediation is not being, enforced on
+      cache check"
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 27 Aug 2019 09:49:19 +0200
+
+linux (4.4.0-160.188) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-160.188 -proposed tracker (LP: #1840021)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * EeePC 1005px laptop backlight is off after system boot up (LP: #1837117)
+    - platform/x86: asus-wmi: Only Tell EC the OS will handle display hotkeys from
+      asus_nb_wmi
+
+  * CVE-2019-10638
+    - [Config] CONFIG_TEST_HASH=n
+    - siphash: add cryptographically secure PRF
+    - inet: switch IP ID generator to siphash
+
+  * Stacked onexec transitions fail when under NO NEW PRIVS restrictions
+    (LP: #1839037)
+    - SAUCE: apparmor: fix nnp subset check failure, when stacking
+
+  * AppArmor onexec transition causes WARN kernel stack trace (LP: #1838627)
+    - SAUCE: apparmor: fix audit failures when performing profile transitions
+
+  * flock not mediated by 'k' (LP: 1658219) // Ubuntu 16.04: read access
+    incorrectly implies 'm' rule (LP: 1838090)
+    - SAUCE: apparmor: flock mediation is not being, enforced on cache check
+
+  * bcache: bch_allocator_thread(): hung task timeout (LP: #1784665) // Tight
+    timeout for bcache removal causes spurious failures (LP: #1796292)
+    - SAUCE: bcache: fix deadlock in bcache_allocator
+
+  * bcache: bch_allocator_thread(): hung task timeout (LP: #1784665)
+    - bcache: improve bcache_reboot()
+    - bcache: add journal statistic
+    - bcache: fix high CPU occupancy during journal
+    - bcache: fix incorrect sysfs output value of strip size
+    - bcache: fix error return value in memory shrink
+    - bcache: fix using of loop variable in memory shrink
+    - bcache: Fix indentation
+    - bcache: Add __printf annotation to __bch_check_keys()
+    - bcache: Annotate switch fall-through
+    - bcache: Fix kernel-doc warnings
+    - bcache: Remove an unused variable
+    - bcache: Suppress more warnings about set-but-not-used variables
+    - bcache: Reduce the number of sparse complaints about lock imbalances
+    - bcache: Move couple of functions to sysfs.c
+
+  * CVE-2019-3900
+    - vhost: introduce vhost_vq_avail_empty()
+    - vhost_net: tx batching
+    - vhost_net: do not stall on zerocopy depletion
+    - vhost-net: set packet weight of tx polling to 2 * vq size
+    - vhost_net: use packet weight for rx handler, too
+    - vhost_net: introduce vhost_exceeds_weight()
+    - vhost: introduce vhost_exceeds_weight()
+    - vhost_net: fix possible infinite loop
+    - vhost: scsi: add weight support
+
+  * Xenial: ZFS deadlock in shrinker path with xattrs (LP: #1839521)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu28
+
+  * CVE-2019-13648
+    - powerpc/tm: Fix oops on sigreturn on systems without TM
+
+  * CVE-2018-20856
+    - block: blk_init_allocated_queue() set q->fq as NULL in the fail case
+
+  * CVE-2019-14283
+    - floppy: fix out-of-bounds read in copy_buffer
+
+  * CVE-2019-14284
+    - floppy: fix div-by-zero in setup_format_params
+
+  * Xenial update: 4.4.186 upstream stable release (LP: #1838467)
+    - Input: elantech - enable middle button support on 2 ThinkPads
+    - samples, bpf: fix to change the buffer size for read()
+    - mac80211: mesh: fix RCU warning
+    - dt-bindings: can: mcp251x: add mcp25625 support
+    - can: mcp251x: add support for mcp25625
+    - Input: imx_keypad - make sure keyboard can always wake up system
+    - ARM: davinci: da850-evm: call regulator_has_full_constraints()
+    - ARM: davinci: da8xx: specify dma_coherent_mask for lcdc
+    - md: fix for divide error in status_resync
+    - bnx2x: Check if transceiver implements DDM before access
+    - udf: Fix incorrect final NOT_ALLOCATED (hole) extent length
+    - x86/ptrace: Fix possible spectre-v1 in ptrace_get_debugreg()
+    - x86/tls: Fix possible spectre-v1 in do_get_thread_area()
+    - mwifiex: Abort at too short BSS descriptor element
+    - fscrypt: don't set policy for a dead directory
+    - mwifiex: Don't abort on small, spec-compliant vendor IEs
+    - USB: serial: ftdi_sio: add ID for isodebug v1
+    - USB: serial: option: add support for GosunCn ME3630 RNDIS mode
+    - usb: gadget: ether: Fix race between gether_disconnect and rx_submit
+    - usb: renesas_usbhs: add a workaround for a race condition of workqueue
+    - staging: comedi: dt282x: fix a null pointer deref on interrupt
+    - staging: comedi: amplc_pci230: fix null pointer deref on interrupt
+    - carl9170: fix misuse of device driver API
+    - VMCI: Fix integer overflow in VMCI handle arrays
+    - MIPS: Remove superfluous check for __linux__
+    - e1000e: start network tx queue only when link is up
+    - perf/core: Fix perf_sample_regs_user() mm check
+    - ARM: omap2: remove incorrect __init annotation
+    - be2net: fix link failure after ethtool offline test
+    - ppp: mppe: Add softdep to arc4
+    - sis900: fix TX completion
+    - dm verity: use message limit for data block corruption message
+    - kvm: x86: avoid warning on repeated KVM_SET_TSS_ADDR
+    - ARC: hide unused function unw_hdr_alloc
+    - s390: fix stfle zero padding
+    - s390/qdio: (re-)initialize tiqdio list entries
+    - s390/qdio: don't touch the dsci in tiqdio_add_input_queues()
+    - KVM: x86: protect KVM_CREATE_PIT/KVM_CREATE_PIT2 with kvm->lock
+    - Linux 4.4.186
+
+ -- Connor Kuehl <connor.kuehl@canonical.com>  Tue, 13 Aug 2019 14:54:45 -0700
+
+linux (4.4.0-159.187) xenial; urgency=medium
+
+  * CVE-2019-1125
+    - x86/cpufeatures: Carve out CQM features retrieval
+    - x86/cpufeatures: Combine word 11 and 12 into a new scattered features word
+    - x86/speculation: Prepare entry code for Spectre v1 swapgs mitigations
+    - x86/speculation: Enable Spectre v1 swapgs mitigations
+    - x86/entry/64: Use JMP instead of JMPQ
+    - x86/speculation/swapgs: Exclude ATOMs from speculation through SWAPGS
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 01 Aug 2019 17:22:24 +0200
+
+linux (4.4.0-158.186) xenial; urgency=medium
+
+  * xenial/linux: 4.4.0-158.186 -proposed tracker (LP: #1837609)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] update helper scripts
+
+  * ixgbe{vf} - Physical Function gets IRQ when VF checks link state
+    (LP: #1836760)
+    - ixgbevf: Use cached link state instead of re-reading the value for ethtool
+
+  * CVE-2018-5383
+    - crypto: kpp - Key-agreement Protocol Primitives API (KPP)
+    - crypto: dh - Add DH software implementation
+    - crypto: ecdh - Add ECDH software support
+    - crypto: ecdh - make ecdh_shared_secret unique
+    - crypto: doc - add KPP documentation
+    - crypto: kpp, (ec)dh - fix typos
+    - crypto: ecc - remove unused function arguments
+    - crypto: ecc - remove unnecessary casts
+    - crypto: ecc - rename ecdh_make_pub_key()
+    - crypto: ecdh - add privkey generation support
+    - crypto: ecc - Fix NULL pointer deref. on no default_rng
+    - [Config] CRYPTO_ECDH=m
+    - Bluetooth: convert smp and selftest to crypto kpp API
+    - crypto: ecdh - add public key verification test
+
+  * Xenial update: 4.4.185 upstream stable release (LP: #1836668)
+    - fs/binfmt_flat.c: make load_flat_shared_library() work
+    - scsi: vmw_pscsi: Fix use-after-free in pvscsi_queue_lck()
+    - tracing: Silence GCC 9 array bounds warning
+    - gcc-9: silence 'address-of-packed-member' warning
+    - usb: chipidea: udc: workaround for endpoint conflict issue
+    - Input: uinput - add compat ioctl number translation for UI_*_FF_UPLOAD
+    - apparmor: enforce nullbyte at end of tag string
+    - parport: Fix mem leak in parport_register_dev_model
+    - parisc: Fix compiler warnings in float emulation code
+    - IB/hfi1: Insure freeze_work work_struct is canceled on shutdown
+    - MIPS: uprobes: remove set but not used variable 'epc'
+    - net: hns: Fix loopback test failed at copper ports
+    - sparc: perf: fix updated event period in response to PERF_EVENT_IOC_PERIOD
+    - scripts/checkstack.pl: Fix arm64 wrong or unknown architecture
+    - scsi: ufs: Check that space was properly alloced in copy_query_response
+    - s390/qeth: fix VLAN attribute in bridge_hostnotify udev event
+    - hwmon: (pmbus/core) Treat parameters as paged if on multiple pages
+    - Btrfs: fix race between readahead and device replace/removal
+    - btrfs: start readahead also in seed devices
+    - can: flexcan: fix timeout when set small bitrate
+    - can: purge socket error queue on sock destruct
+    - ARM: imx: cpuidle-imx6sx: Restrict the SW2ISO increase to i.MX6SX
+    - Bluetooth: Align minimum encryption key size for LE and BR/EDR connections
+    - Bluetooth: Fix regression with minimum encryption key size alignment
+    - SMB3: retry on STATUS_INSUFFICIENT_RESOURCES instead of failing write
+    - cfg80211: fix memory leak of wiphy device name
+    - mac80211: drop robust management frames from unknown TA
+    - perf ui helpline: Use strlcpy() as a shorter form of strncpy() + explicit
+      set nul
+    - perf help: Remove needless use of strncpy()
+    - 9p/rdma: do not disconnect on down_interruptible EAGAIN
+    - 9p: acl: fix uninitialized iattr access
+    - 9p/rdma: remove useless check in cm_event_handler
+    - 9p: p9dirent_read: check network-provided name length
+    - net/9p: include trans_common.h to fix missing prototype warning.
+    - ovl: modify ovl_permission() to do checks on two inodes
+    - x86/speculation: Allow guests to use SSBD even if host does not
+    - cpu/speculation: Warn on unsupported mitigations= parameter
+    - sctp: change to hold sk after auth shkey is created successfully
+    - tipc: change to use register_pernet_device
+    - tipc: check msg->req data len in tipc_nl_compat_bearer_disable
+    - team: Always enable vlan tx offload
+    - ipv4: Use return value of inet_iif() for __raw_v4_lookup in the while loop
+    - bonding: Always enable vlan tx offload
+    - net: check before dereferencing netdev_ops during busy poll
+    - Bluetooth: Fix faulty expression for minimum encryption key size check
+    - um: Compile with modern headers
+    - ASoC : cs4265 : readable register too low
+    - spi: bitbang: Fix NULL pointer dereference in spi_unregister_master
+    - ASoC: max98090: remove 24-bit format support if RJ is 0
+    - usb: gadget: fusb300_udc: Fix memory leak of fusb300->ep[i]
+    - usb: gadget: udc: lpc32xx: allocate descriptor with GFP_ATOMIC
+    - scsi: hpsa: correct ioaccel2 chaining
+    - ARC: Assume multiplier is always present
+    - ARC: fix build warning in elf.h
+    - MIPS: math-emu: do not use bools for arithmetic
+    - mfd: omap-usb-tll: Fix register offsets
+    - swiotlb: Make linux/swiotlb.h standalone includible
+    - bug.h: work around GCC PR82365 in BUG()
+    - MIPS: Workaround GCC __builtin_unreachable reordering bug
+    - ptrace: Fix ->ptracer_cred handling for PTRACE_TRACEME
+    - crypto: user - prevent operating on larval algorithms
+    - ALSA: seq: fix incorrect order of dest_client/dest_ports arguments
+    - ALSA: firewire-lib/fireworks: fix miss detection of received MIDI messages
+    - ALSA: usb-audio: fix sign unintended sign extension on left shifts
+    - lib/mpi: Fix karactx leak in mpi_powm
+    - btrfs: Ensure replaced device doesn't have pending chunk allocation
+    - tty: rocket: fix incorrect forward declaration of 'rp_init()'
+    - ARC: handle gcc generated __builtin_trap for older compiler
+    - arm64, vdso: Define vdso_{start,end} as array
+    - KVM: x86: degrade WARN to pr_warn_ratelimited
+    - dmaengine: imx-sdma: remove BD_INTR for channel0
+    - Linux 4.4.185
+
+  * Xenial update: 4.4.184 upstream stable release (LP: #1836667)
+    - Linux 4.4.184
+
+  * Xenial update: 4.4.183 upstream stable release (LP: #1836666)
+    - fs/fat/file.c: issue flush after the writeback of FAT
+    - sysctl: return -EINVAL if val violates minmax
+    - ipc: prevent lockup on alloc_msg and free_msg
+    - hugetlbfs: on restore reserve error path retain subpool reservation
+    - mm/cma.c: fix crash on CMA allocation if bitmap allocation fails
+    - mm/cma_debug.c: fix the break condition in cma_maxchunk_get()
+    - kernel/sys.c: prctl: fix false positive in validate_prctl_map()
+    - mfd: intel-lpss: Set the device in reset state when init
+    - mfd: twl6040: Fix device init errors for ACCCTL register
+    - perf/x86/intel: Allow PEBS multi-entry in watermark mode
+    - drm/bridge: adv7511: Fix low refresh rate selection
+    - ntp: Allow TAI-UTC offset to be set to zero
+    - f2fs: fix to avoid panic in do_recover_data()
+    - f2fs: fix to do sanity check on valid block count of segment
+    - iommu/vt-d: Set intel_iommu_gfx_mapped correctly
+    - ALSA: hda - Register irq handler after the chip initialization
+    - nvmem: core: fix read buffer in place
+    - fuse: retrieve: cap requested size to negotiated max_write
+    - nfsd: allow fh_want_write to be called twice
+    - x86/PCI: Fix PCI IRQ routing table memory leak
+    - platform/chrome: cros_ec_proto: check for NULL transfer function
+    - soc: mediatek: pwrap: Zero initialize rdata in pwrap_init_cipher
+    - clk: rockchip: Turn on "aclk_dmac1" for suspend on rk3288
+    - ARM: dts: imx6sx: Specify IMX6SX_CLK_IPG as "ahb" clock to SDMA
+    - ARM: dts: imx6sx: Specify IMX6SX_CLK_IPG as "ipg" clock to SDMA
+    - ARM: dts: imx6qdl: Specify IMX6QDL_CLK_IPG as "ipg" clock to SDMA
+    - PCI: rpadlpar: Fix leaked device_node references in add/remove paths
+    - PCI: rcar: Fix a potential NULL pointer dereference
+    - video: hgafb: fix potential NULL pointer dereference
+    - video: imsttfb: fix potential NULL pointer dereferences
+    - PCI: xilinx: Check for __get_free_pages() failure
+    - gpio: gpio-omap: add check for off wake capable gpios
+    - dmaengine: idma64: Use actual device for DMA transfers
+    - pwm: tiehrpwm: Update shadow register for disabling PWMs
+    - ARM: dts: exynos: Always enable necessary APIO_1V8 and ABB_1V8 regulators on
+      Arndale Octa
+    - pwm: Fix deadlock warning when removing PWM device
+    - ARM: exynos: Fix undefined instruction during Exynos5422 resume
+    - futex: Fix futex lock the wrong page
+    - ALSA: seq: Cover unsubscribe_port() in list_mutex
+    - libata: Extend quirks for the ST1000LM024 drives with NOLPM quirk
+    - mm/list_lru.c: fix memory leak in __memcg_init_list_lru_node
+    - fs/ocfs2: fix race in ocfs2_dentry_attach_lock()
+    - signal/ptrace: Don't leak unitialized kernel memory with PTRACE_PEEK_SIGINFO
+    - ptrace: restore smp_rmb() in __ptrace_may_access()
+    - i2c: acorn: fix i2c warning
+    - bcache: fix stack corruption by PRECEDING_KEY()
+    - cgroup: Use css_tryget() instead of css_tryget_online() in task_get_css()
+    - ASoC: cs42xx8: Add regcache mask dirty
+    - Drivers: misc: fix out-of-bounds access in function param_set_kgdbts_var
+    - scsi: lpfc: add check for loss of ndlp when sending RRQ
+    - scsi: bnx2fc: fix incorrect cast to u64 on shift operation
+    - usbnet: ipheth: fix racing condition
+    - KVM: x86/pmu: do not mask the value that is written to fixed PMUs
+    - KVM: s390: fix memory slot handling for KVM_SET_USER_MEMORY_REGION
+    - drm/vmwgfx: integer underflow in vmw_cmd_dx_set_shader() leading to an
+      invalid read
+    - drm/vmwgfx: NULL pointer dereference from vmw_cmd_dx_view_define()
+    - USB: Fix chipmunk-like voice when using Logitech C270 for recording audio.
+    - USB: usb-storage: Add new ID to ums-realtek
+    - USB: serial: pl2303: add Allied Telesis VT-Kit3
+    - USB: serial: option: add support for Simcom SIM7500/SIM7600 RNDIS mode
+    - USB: serial: option: add Telit 0x1260 and 0x1261 compositions
+    - ax25: fix inconsistent lock state in ax25_destroy_timer
+    - be2net: Fix number of Rx queues used for flow hashing
+    - ipv6: flowlabel: fl6_sock_lookup() must use atomic_inc_not_zero
+    - lapb: fixed leak of control-blocks.
+    - neigh: fix use-after-free read in pneigh_get_next
+    - sunhv: Fix device naming inconsistency between sunhv_console and sunhv_reg
+    - mISDN: make sure device name is NUL terminated
+    - x86/CPU/AMD: Don't force the CPB cap when running under a hypervisor
+    - perf/ring_buffer: Fix exposing a temporarily decreased data_head
+    - perf/ring_buffer: Add ordering to rb->nest increment
+    - gpio: fix gpio-adp5588 build errors
+    - net: tulip: de4x5: Drop redundant MODULE_DEVICE_TABLE()
+    - i2c: dev: fix potential memory leak in i2cdev_ioctl_rdwr
+    - configfs: Fix use-after-free when accessing sd->s_dentry
+    - ia64: fix build errors by exporting paddr_to_nid()
+    - KVM: PPC: Book3S: Use new mutex to synchronize access to rtas token list
+    - net: sh_eth: fix mdio access in sh_eth_close() for R-Car Gen2 and RZ/A1 SoCs
+    - scsi: libcxgbi: add a check for NULL pointer in cxgbi_check_route()
+    - scsi: libsas: delete sas port if expander discover failed
+    - Revert "crypto: crypto4xx - properly set IV after de- and encrypt"
+    - coredump: fix race condition between mmget_not_zero()/get_task_mm() and core
+      dumping
+    - Abort file_remove_privs() for non-reg. files
+    - Linux 4.4.183
+
+  * CVE-2019-12614
+    - powerpc/pseries/dlpar: Fix a missing check in dlpar_parse_cc_property()
+
+  * bnx2x driver causes 100% CPU load (LP: #1832082)
+    - bnx2x: Prevent ptp_task to be rescheduled indefinitely
+
+  * Xenial update: 4.4.182 upstream stable release (LP: #1836665)
+    - Linux 4.4.182
+
+  * Xenial kernel 4.4.0-155.182 fails to build perf with libnuma (LP: #1836585)
+    - Revert "UBUNTU: SAUCE: perf/bench: Drop definition of BIT in numa.c"
+
+  * CVE-2019-10126
+    - mwifiex: Fix heap overflow in mwifiex_uap_parse_tail_ies()
+
+  * CVE-2019-3846
+    - mwifiex: Fix possible buffer overflows at parsing bss descriptor
+
+ -- Sultan Alsawaf <sultan.alsawaf@canonical.com>  Mon, 29 Jul 2019 09:53:03 -0600
+
+linux (4.4.0-157.185) xenial; urgency=medium
+
+  * linux: 4.4.0-157.185 -proposed tracker (LP: #1837476)
+
+  * systemd 229-4ubuntu21.22 ADT test failure with linux 4.4.0-156.183 (storage)
+    (LP: #1837235)
+    - Revert "block/bio: Do not zero user pages"
+    - Revert "block: Clear kernel memory before copying to user"
+    - Revert "bio_copy_from_iter(): get rid of copying iov_iter"
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 23 Jul 2019 10:55:25 +0200
+
+linux (4.4.0-156.183) xenial; urgency=medium
+
+  * linux: 4.4.0-156.183 -proposed tracker (LP: #1836880)
+
+  * BCM43602 802.11ac Wireless regression - PCI ID 14e4:43ba (LP: #1836801)
+    - brcmfmac: add eth_type_trans back for PCIe full dongle
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 17 Jul 2019 13:06:26 +0200
+
+linux (4.4.0-155.182) xenial; urgency=medium
+
+  * linux: 4.4.0-155.182 -proposed tracker (LP: #1834918)
+
+  * Geneve tunnels don't work when ipv6 is disabled (LP: #1794232)
+    - geneve: correctly handle ipv6.disable module parameter
+
+  * Kernel modules generated incorrectly when system is localized to a non-
+    English language (LP: #1828084)
+    - scripts: override locale from environment when running recordmcount.pl
+
+  * Handle overflow in proc_get_long of sysctl (LP: #1833935)
+    - sysctl: handle overflow in proc_get_long
+
+  * Xenial update: 4.4.181 upstream stable release (LP: #1832661)
+    - x86/speculation/mds: Revert CPU buffer clear on double fault exit
+    - x86/speculation/mds: Improve CPU buffer clear documentation
+    - ARM: exynos: Fix a leaked reference by adding missing of_node_put
+    - crypto: vmx - fix copy-paste error in CTR mode
+    - crypto: crct10dif-generic - fix use via crypto_shash_digest()
+    - crypto: x86/crct10dif-pcl - fix use via crypto_shash_digest()
+    - ALSA: usb-audio: Fix a memory leak bug
+    - ALSA: hda/hdmi - Consider eld_valid when reporting jack event
+    - ALSA: hda/realtek - EAPD turn on later
+    - ASoC: max98090: Fix restore of DAPM Muxes
+    - ASoC: RT5677-SPI: Disable 16Bit SPI Transfers
+    - mm/mincore.c: make mincore() more conservative
+    - ocfs2: fix ocfs2 read inode data panic in ocfs2_iget
+    - mfd: da9063: Fix OTP control register names to match datasheets for
+      DA9063/63L
+    - tty/vt: fix write/write race in ioctl(KDSKBSENT) handler
+    - ext4: actually request zeroing of inode table after grow
+    - ext4: fix ext4_show_options for file systems w/o journal
+    - Btrfs: do not start a transaction at iterate_extent_inodes()
+    - bcache: fix a race between cache register and cacheset unregister
+    - bcache: never set KEY_PTRS of journal key to 0 in journal_reclaim()
+    - ipmi:ssif: compare block number correctly for multi-part return messages
+    - crypto: gcm - Fix error return code in crypto_gcm_create_common()
+    - crypto: gcm - fix incompatibility between "gcm" and "gcm_base"
+    - crypto: chacha20poly1305 - set cra_name correctly
+    - crypto: salsa20 - don't access already-freed walk.iv
+    - crypto: arm/aes-neonbs - don't access already-freed walk.iv
+    - writeback: synchronize sync(2) against cgroup writeback membership switches
+    - fs/writeback.c: use rcu_barrier() to wait for inflight wb switches going
+      into workqueue when umount
+    - ALSA: hda/realtek - Fix for Lenovo B50-70 inverted internal microphone bug
+    - KVM: x86: Skip EFER vs. guest CPUID checks for host-initiated writes
+    - net: avoid weird emergency message
+    - net/mlx4_core: Change the error print to info print
+    - ppp: deflate: Fix possible crash in deflate_init
+    - tipc: switch order of device registration to fix a crash
+    - tipc: fix modprobe tipc failed after switch order of device registration
+    - stm class: Fix channel free in stm output free path
+    - md: add mddev->pers to avoid potential NULL pointer dereference
+    - intel_th: msu: Fix single mode with IOMMU
+    - of: fix clang -Wunsequenced for be32_to_cpu()
+    - cifs: fix strcat buffer overflow and reduce raciness in
+      smb21_set_oplock_level()
+    - media: ov6650: Fix sensor possibly not detected on probe
+    - NFS4: Fix v4.0 client state corruption when mount
+    - clk: tegra: Fix PLLM programming on Tegra124+ when PMC overrides divider
+    - fuse: fix writepages on 32bit
+    - fuse: honor RLIMIT_FSIZE in fuse_file_fallocate
+    - iommu/tegra-smmu: Fix invalid ASID bits on Tegra30/114
+    - ceph: flush dirty inodes before proceeding with remount
+    - tracing: Fix partial reading of trace event's id file
+    - memory: tegra: Fix integer overflow on tick value calculation
+    - perf intel-pt: Fix instructions sampling rate
+    - perf intel-pt: Fix improved sample timestamp
+    - perf intel-pt: Fix sample timestamp wrt non-taken branches
+    - fbdev: sm712fb: fix brightness control on reboot, don't set SR30
+    - fbdev: sm712fb: fix VRAM detection, don't set SR70/71/74/75
+    - fbdev: sm712fb: fix white screen of death on reboot, don't set CR3B-CR3F
+    - fbdev: sm712fb: fix boot screen glitch when sm712fb replaces VGA
+    - fbdev: sm712fb: fix crashes during framebuffer writes by correctly mapping
+      VRAM
+    - fbdev: sm712fb: fix support for 1024x768-16 mode
+    - fbdev: sm712fb: use 1024x768 by default on non-MIPS, fix garbled display
+    - fbdev: sm712fb: fix crashes and garbled display during DPMS modesetting
+    - PCI: Mark Atheros AR9462 to avoid bus reset
+    - dm delay: fix a crash when invalid device is specified
+    - xfrm: policy: Fix out-of-bound array accesses in __xfrm_policy_unlink
+    - xfrm6_tunnel: Fix potential panic when unloading xfrm6_tunnel module
+    - vti4: ipip tunnel deregistration fixes.
+    - xfrm4: Fix uninitialized memory read in _decode_session4
+    - KVM: arm/arm64: Ensure vcpu target is unset on reset failure
+    - power: supply: sysfs: prevent endless uevent loop with
+      CONFIG_POWER_SUPPLY_DEBUG
+    - ufs: fix braino in ufs_get_inode_gid() for solaris UFS flavour
+    - perf bench numa: Add define for RUSAGE_THREAD if not present
+    - Revert "Don't jump to compute_result state from check_result state"
+    - md/raid: raid5 preserve the writeback action after the parity check
+    - btrfs: Honour FITRIM range constraints during free space trim
+    - fbdev: sm712fb: fix memory frequency by avoiding a switch/case fallthrough
+    - ext4: do not delete unlinked inode from orphan list on failed truncate
+    - KVM: x86: fix return value for reserved EFER
+    - bio: fix improper use of smp_mb__before_atomic()
+    - Revert "scsi: sd: Keep disk read-only when re-reading partition"
+    - crypto: vmx - CTR: always increment IV as quadword
+    - gfs2: Fix sign extension bug in gfs2_update_stats
+    - Btrfs: fix race between ranged fsync and writeback of adjacent ranges
+    - btrfs: sysfs: don't leak memory when failing add fsid
+    - fbdev: fix divide error in fb_var_to_videomode
+    - hugetlb: use same fault hash key for shared and private mappings
+    - fbdev: fix WARNING in __alloc_pages_nodemask bug
+    - media: cpia2: Fix use-after-free in cpia2_exit
+    - media: vivid: use vfree() instead of kfree() for dev->bitmap_cap
+    - ssb: Fix possible NULL pointer dereference in ssb_host_pcmcia_exit
+    - at76c50x-usb: Don't register led_trigger if usb_register_driver failed
+    - perf tools: No need to include bitops.h in util.h
+    - gfs2: Fix lru_count going negative
+    - cxgb4: Fix error path in cxgb4_init_module
+    - mmc: core: Verify SD bus width
+    - powerpc/boot: Fix missing check of lseek() return value
+    - ASoC: imx: fix fiq dependencies
+    - spi: pxa2xx: fix SCR (divisor) calculation
+    - brcm80211: potential NULL dereference in
+      brcmf_cfg80211_vndr_cmds_dcmd_handler()
+    - rtc: 88pm860x: prevent use-after-free on device remove
+    - w1: fix the resume command API
+    - dmaengine: pl330: _stop: clear interrupt status
+    - mac80211/cfg80211: update bss channel on channel switch
+    - ASoC: fsl_sai: Update is_slave_mode with correct value
+    - mwifiex: prevent an array overflow
+    - net: cw1200: fix a NULL pointer dereference
+    - bcache: return error immediately in bch_journal_replay()
+    - bcache: fix failure in journal relplay
+    - bcache: add failure check to run_cache_set() for journal replay
+    - bcache: avoid clang -Wunintialized warning
+    - x86/build: Move _etext to actual end of .text
+    - smpboot: Place the __percpu annotation correctly
+    - x86/mm: Remove in_nmi() warning from 64-bit implementation of
+      vmalloc_fault()
+    - mm/uaccess: Use 'unsigned long' to placate UBSAN warnings on older GCC
+      versions
+    - HID: logitech-hidpp: use RAP instead of FAP to get the protocol version
+    - pinctrl: pistachio: fix leaked of_node references
+    - dmaengine: at_xdmac: remove BUG_ON macro in tasklet
+    - media: coda: clear error return value before picture run
+    - media: ov6650: Move v4l2_clk_get() to ov6650_video_probe() helper
+    - media: au0828: stop video streaming only when last user stops
+    - media: ov2659: make S_FMT succeed even if requested format doesn't match
+    - audit: fix a memory leak bug
+    - media: au0828: Fix NULL pointer dereference in au0828_analog_stream_enable()
+    - media: pvrusb2: Prevent a buffer overflow
+    - powerpc/numa: improve control of topology updates
+    - sched/core: Check quota and period overflow at usec to nsec conversion
+    - sched/core: Handle overflow in cpu_shares_write_u64
+    - USB: core: Don't unbind interfaces following device reset failure
+    - x86/irq/64: Limit IST stack overflow check to #DB stack
+    - i40e: don't allow changes to HW VLAN stripping on active port VLANs
+    - RDMA/cxgb4: Fix null pointer dereference on alloc_skb failure
+    - hwmon: (vt1211) Use request_muxed_region for Super-IO accesses
+    - hwmon: (smsc47m1) Use request_muxed_region for Super-IO accesses
+    - hwmon: (smsc47b397) Use request_muxed_region for Super-IO accesses
+    - hwmon: (pc87427) Use request_muxed_region for Super-IO accesses
+    - hwmon: (f71805f) Use request_muxed_region for Super-IO accesses
+    - scsi: libsas: Do discovery on empty PHY to update PHY info
+    - mmc_spi: add a status check for spi_sync_locked
+    - mmc: sdhci-of-esdhc: add erratum eSDHC5 support
+    - mmc: sdhci-of-esdhc: add erratum eSDHC-A001 and A-008358 support
+    - PM / core: Propagate dev->power.wakeup_path when no callbacks
+    - extcon: arizona: Disable mic detect if running when driver is removed
+    - s390: cio: fix cio_irb declaration
+    - cpufreq: ppc_cbe: fix possible object reference leak
+    - cpufreq/pasemi: fix possible object reference leak
+    - cpufreq: pmac32: fix possible object reference leak
+    - x86/build: Keep local relocations with ld.lld
+    - iio: ad_sigma_delta: Properly handle SPI bus locking vs CS assertion
+    - iio: hmc5843: fix potential NULL pointer dereferences
+    - iio: common: ssp_sensors: Initialize calculated_time in
+      ssp_common_process_data
+    - rtlwifi: fix a potential NULL pointer dereference
+    - brcmfmac: fix missing checks for kmemdup
+    - b43: shut up clang -Wuninitialized variable warning
+    - brcmfmac: convert dev_init_lock mutex to completion
+    - brcmfmac: fix race during disconnect when USB completion is in progress
+    - scsi: ufs: Fix regulator load and icc-level configuration
+    - scsi: ufs: Avoid configuring regulator with undefined voltage range
+    - arm64: cpu_ops: fix a leaked reference by adding missing of_node_put
+    - x86/ia32: Fix ia32_restore_sigcontext() AC leak
+    - chardev: add additional check for minor range overlap
+    - HID: core: move Usage Page concatenation to Main item
+    - ASoC: eukrea-tlv320: fix a leaked reference by adding missing of_node_put
+    - ASoC: fsl_utils: fix a leaked reference by adding missing of_node_put
+    - cxgb3/l2t: Fix undefined behaviour
+    - spi: tegra114: reset controller on probe
+    - media: wl128x: prevent two potential buffer overflows
+    - virtio_console: initialize vtermno value for ports
+    - tty: ipwireless: fix missing checks for ioremap
+    - rcutorture: Fix cleanup path for invalid torture_type strings
+    - usb: core: Add PM runtime calls to usb_hcd_platform_shutdown
+    - scsi: qla4xxx: avoid freeing unallocated dma memory
+    - media: m88ds3103: serialize reset messages in m88ds3103_set_frontend
+    - media: go7007: avoid clang frame overflow warning with KASAN
+    - media: saa7146: avoid high stack usage with clang
+    - scsi: lpfc: Fix SLI3 commands being issued on SLI4 devices
+    - spi : spi-topcliff-pch: Fix to handle empty DMA buffers
+    - spi: rspi: Fix sequencer reset during initialization
+    - spi: Fix zero length xfer bug
+    - ASoC: davinci-mcasp: Fix clang warning without CONFIG_PM
+    - ipv6: Consider sk_bound_dev_if when binding a raw socket to an address
+    - llc: fix skb leak in llc_build_and_send_ui_pkt()
+    - net-gro: fix use-after-free read in napi_gro_frags()
+    - net: stmmac: fix reset gpio free missing
+    - usbnet: fix kernel crash after disconnect
+    - tipc: Avoid copying bytes beyond the supplied data
+    - bnxt_en: Fix aggregation buffer leak under OOM condition.
+    - net: mvpp2: fix bad MVPP2_TXQ_SCHED_TOKEN_CNTR_REG queue value
+    - crypto: vmx - ghash: do nosimd fallback manually
+    - xen/pciback: Don't disable PCI_COMMAND on PCI device reset.
+    - Revert "tipc: fix modprobe tipc failed after switch order of device
+      registration"
+    - tipc: fix modprobe tipc failed after switch order of device registration -v2
+    - sparc64: Fix regression in non-hypervisor TLB flush xcall
+    - include/linux/bitops.h: sanitize rotate primitives
+    - xhci: Convert xhci_handshake() to use readl_poll_timeout_atomic()
+    - usb: xhci: avoid null pointer deref when bos field is NULL
+    - USB: Fix slab-out-of-bounds write in usb_get_bos_descriptor
+    - USB: sisusbvga: fix oops in error path of sisusb_probe
+    - USB: Add LPM quirk for Surface Dock GigE adapter
+    - USB: rio500: refuse more than one device at a time
+    - USB: rio500: fix memory leak in close after disconnect
+    - media: usb: siano: Fix general protection fault in smsusb
+    - media: usb: siano: Fix false-positive "uninitialized variable" warning
+    - media: smsusb: better handle optional alignment
+    - scsi: zfcp: fix missing zfcp_port reference put on -EBUSY from port_remove
+    - scsi: zfcp: fix to prevent port_remove with pure auto scan LUNs (only sdevs)
+    - Btrfs: fix race updating log root item during fsync
+    - ALSA: hda/realtek - Set default power save node to 0
+    - drm/nouveau/i2c: Disable i2c bus access after ->fini()
+    - tty: serial: msm_serial: Fix XON/XOFF
+    - tty: max310x: Fix external crystal register setup
+    - memcg: make it work on sparse non-0-node systems
+    - kernel/signal.c: trace_signal_deliver when signal_group_exit
+    - CIFS: cifs_read_allocate_pages: don't iterate through whole page array on
+      ENOMEM
+    - binder: Replace "%p" with "%pK" for stable
+    - binder: replace "%p" with "%pK"
+    - brcmfmac: Add length checks on firmware events
+    - brcmfmac: screening firmware event packet
+    - brcmfmac: revise handling events in receive path
+    - brcmfmac: fix incorrect event channel deduction
+    - brcmfmac: add length checks in scheduled scan result handler
+    - brcmfmac: add subtype check for event handling in data path
+    - userfaultfd: don't pin the user memory in userfaultfd_file_create()
+    - Revert "x86/build: Move _etext to actual end of .text"
+    - net: cdc_ncm: GetNtbFormat endian fix
+    - usb: gadget: fix request length error for isoc transfer
+    - media: uvcvideo: Fix uvc_alloc_entity() allocation alignment
+    - ethtool: fix potential userspace buffer overflow
+    - neighbor: Call __ipv4_neigh_lookup_noref in neigh_xmit
+    - net/mlx4_en: ethtool, Remove unsupported SFP EEPROM high pages query
+    - net: rds: fix memory leak in rds_ib_flush_mr_pool
+    - pktgen: do not sleep with the thread lock held.
+    - rcu: locking and unlocking need to always be at least barriers
+    - parisc: Use implicit space register selection for loading the coherence
+      index of I/O pdirs
+    - fuse: fallocate: fix return with locked inode
+    - MIPS: pistachio: Build uImage.gz by default
+    - genwqe: Prevent an integer overflow in the ioctl
+    - drm/gma500/cdv: Check vbt config bits when detecting lvds panels
+    - fs: stream_open - opener for stream-like files so that read and write can
+      run simultaneously without deadlock
+    - fuse: Add FOPEN_STREAM to use stream_open()
+    - ipv4: Define __ipv4_neigh_lookup_noref when CONFIG_INET is disabled
+    - ethtool: check the return value of get_regs_len
+    - Linux 4.4.181
+
+  * CVE-2019-2054
+    - arm/ptrace: run seccomp after ptrace
+
+  * CVE-2018-12126 // CVE-2018-12127 // CVE-2018-12130
+    - x86/speculation: Remove redundant arch_smt_update() invocation
+
+  * Revert x86/vdso linker changes from #1830890 as this causes glibc
+    2.29-0ubuntu3 FTBFS on eoan (LP: #1834315)
+    - Revert "x86/vdso: Pass --eh-frame-hdr to the linker"
+    - Revert "x86: vdso: Use $LD instead of $CC to link"
+
+  * CONFIG_LOG_BUF_SHIFT set to 14 is too low on arm64 (LP: #1824864)
+    - [Config] CONFIG_LOG_BUF_SHIFT=18 on all 64bit arches
+
+  * CVE-2019-11833
+    - ext4: zero out the unused memory region in the extent tree block
+
+  * idle-page oopses when accessing page frames that are out of range
+    (LP: #1833410)
+    - mm/page_idle.c: fix oops because end_pfn is larger than max_pfn
+
+  * Performance degradation when copying from LVM snapshot backed by NVMe disk
+    (LP: #1833319)
+    - NVMe: Allow request merges
+
+  * Bluetooth regressions with Xenial kernel 4.4.0-152.179 (LP: #1833698)
+    - Revert "Bluetooth: Align minimum encryption key size for LE and BR/EDR
+      connections"
+
+  * 4.4.0-145-generic Kernel Panic  ip6_expire_frag_queue (LP: #1824687)
+    - SAUCE: ipv6: frags: fix skb extraction in ip6_expire_frag_queue()
+
+  * [Xenial] Customer can not SSH to Linux VM due to "VSC State Unhealthy"
+    (LP: #1826416)
+    - vmbus: fix missing signaling in hv_signal_on_read()
+
+  * Xenial update: 4.4.180 upstream stable release (LP: #1830176)
+    - kbuild: simplify ld-option implementation
+    - KVM: fail KVM_SET_VCPU_EVENTS with invalid exception number
+    - cifs: do not attempt cifs operation on smb2+ rename error
+    - MIPS: scall64-o32: Fix indirect syscall number load
+    - trace: Fix preempt_enable_no_resched() abuse
+    - sched/numa: Fix a possible divide-by-zero
+    - ceph: ensure d_name stability in ceph_dentry_hash()
+    - ceph: fix ci->i_head_snapc leak
+    - nfsd: Don't release the callback slot unless it was actually held
+    - sunrpc: don't mark uninitialised items as VALID.
+    - USB: Add new USB LPM helpers
+    - USB: Consolidate LPM checks to avoid enabling LPM twice
+    - powerpc/xmon: Add RFI flush related fields to paca dump
+    - powerpc/64s: Improve RFI L1-D cache flush fallback
+    - powerpc/64s: Fix section mismatch warnings from setup_rfi_flush()
+    - Revert "UBUNTU: SAUCE: powerpc/64s: Add support for a store forwarding
+      barrier at kernel entry/exit"
+    - powerpc/64s: Add support for a store forwarding barrier at kernel entry/exit
+    - powerpc/64s: Add barrier_nospec
+    - powerpc/64s: Add support for ori barrier_nospec patching
+    - powerpc/64s: Patch barrier_nospec in modules
+    - powerpc/64s: Enable barrier_nospec based on firmware settings
+    - powerpc/64: Use barrier_nospec in syscall entry
+    - powerpc: Use barrier_nospec in copy_from_user()
+    - powerpc/64s: Enhance the information in cpu_show_spectre_v1()
+    - powerpc64s: Show ori31 availability in spectre_v1 sysfs file not v2
+    - powerpc/64: Disable the speculation barrier from the command line
+    - powerpc/64: Make stf barrier PPC_BOOK3S_64 specific.
+    - powerpc/64: Add CONFIG_PPC_BARRIER_NOSPEC
+    - powerpc/64: Call setup_barrier_nospec() from setup_arch()
+    - powerpc/64: Make meltdown reporting Book3S 64 specific
+    - powerpc/fsl: Add barrier_nospec implementation for NXP PowerPC Book3E
+    - powerpc/asm: Add a patch_site macro & helpers for patching instructions
+    - powerpc/64s: Add new security feature flags for count cache flush
+    - powerpc/64s: Add support for software count cache flush
+    - powerpc/pseries: Query hypervisor for count cache flush settings
+    - powerpc/powernv: Query firmware for count cache flush settings
+    - powerpc: Avoid code patching freed init sections
+    - powerpc/fsl: Add infrastructure to fixup branch predictor flush
+    - powerpc/fsl: Add macro to flush the branch predictor
+    - powerpc/fsl: Fix spectre_v2 mitigations reporting
+    - powerpc/fsl: Add nospectre_v2 command line argument
+    - powerpc/fsl: Flush the branch predictor at each kernel entry (64bit)
+    - powerpc/fsl: Update Spectre v2 reporting
+    - powerpc/security: Fix spectre_v2 reporting
+    - powerpc/fsl: Fix the flush of branch predictor.
+    - tipc: handle the err returned from cmd header function
+    - slip: make slhc_free() silently accept an error pointer
+    - intel_th: gth: Fix an off-by-one in output unassigning
+    - fs/proc/proc_sysctl.c: Fix a NULL pointer dereference
+    - NFS: Forbid setting AF_INET6 to "struct sockaddr_in"->sin_family.
+    - netfilter: ebtables: CONFIG_COMPAT: drop a bogus WARN_ON
+    - tipc: check bearer name with right length in tipc_nl_compat_bearer_enable
+    - tipc: check link name with right length in tipc_nl_compat_link_set
+    - bpf: reject wrong sized filters earlier
+    - Revert "block/loop: Use global lock for ioctl() operation."
+    - ipv4: add sanity checks in ipv4_link_failure()
+    - team: fix possible recursive locking when add slaves
+    - net: stmmac: move stmmac_check_ether_addr() to driver probe
+    - ipv4: set the tcp_min_rtt_wlen range from 0 to one day
+    - powerpc/fsl: Enable runtime patching if nospectre_v2 boot arg is used
+    - powerpc/fsl: Flush branch predictor when entering KVM
+    - powerpc/fsl: Emulate SPRN_BUCSR register
+    - powerpc/fsl: Flush the branch predictor at each kernel entry (32 bit)
+    - powerpc/fsl: Sanitize the syscall table for NXP PowerPC 32 bit platforms
+    - powerpc/fsl: Fixed warning: orphan section `__btb_flush_fixup'
+    - powerpc/fsl: Add FSL_PPC_BOOK3E as supported arch for nospectre_v2 boot arg
+    - Documentation: Add nospectre_v1 parameter
+    - usbnet: ipheth: prevent TX queue timeouts when device not ready
+    - usbnet: ipheth: fix potential null pointer dereference in ipheth_carrier_set
+    - qlcnic: Avoid potential NULL pointer dereference
+    - netfilter: bridge: set skb transport_header before entering
+      NF_INET_PRE_ROUTING
+    - sc16is7xx: missing unregister/delete driver on error in sc16is7xx_init()
+    - usb: gadget: net2280: Fix overrun of OUT messages
+    - usb: gadget: net2280: Fix net2280_dequeue()
+    - usb: gadget: net2272: Fix net2272_dequeue()
+    - ARM: dts: pfla02: increase phy reset duration
+    - net: ks8851: Dequeue RX packets explicitly
+    - net: ks8851: Reassert reset pin if chip ID check fails
+    - net: ks8851: Delay requesting IRQ until opened
+    - net: ks8851: Set initial carrier state to down
+    - net: xilinx: fix possible object reference leak
+    - net: ibm: fix possible object reference leak
+    - net: ethernet: ti: fix possible object reference leak
+    - scsi: qla4xxx: fix a potential NULL pointer dereference
+    - usb: u132-hcd: fix resource leak
+    - ceph: fix use-after-free on symlink traversal
+    - scsi: zfcp: reduce flood of fcrscn1 trace records on multi-element RSCN
+    - libata: fix using DMA buffers on stack
+    - kconfig/[mn]conf: handle backspace (^H) key
+    - ALSA: line6: use dynamic buffers
+    - ipv4: ip_do_fragment: Preserve skb_iif during fragmentation
+    - ipv6/flowlabel: wait rcu grace period before put_pid()
+    - ipv6: invert flowlabel sharing check in process and user mode
+    - bnxt_en: Improve multicast address setup logic.
+    - packet: validate msg_namelen in send directly
+    - USB: yurex: Fix protection fault after device removal
+    - USB: w1 ds2490: Fix bug caused by improper use of altsetting array
+    - USB: core: Fix unterminated string returned by usb_string()
+    - USB: core: Fix bug caused by duplicate interface PM usage counter
+    - HID: debug: fix race condition with between rdesc_show() and device removal
+    - rtc: sh: Fix invalid alarm warning for non-enabled alarm
+    - bonding: show full hw address in sysfs for slave entries
+    - jffs2: fix use-after-free on symlink traversal
+    - debugfs: fix use-after-free on symlink traversal
+    - rtc: da9063: set uie_unsupported when relevant
+    - vfio/pci: use correct format characters
+    - scsi: storvsc: Fix calculation of sub-channel count
+    - net: hns: Use NAPI_POLL_WEIGHT for hns driver
+    - net: hns: Fix WARNING when remove HNS driver with SMMU enabled
+    - hugetlbfs: fix memory leak for resv_map
+    - xsysace: Fix error handling in ace_setup
+    - ARM: orion: don't use using 64-bit DMA masks
+    - ARM: iop: don't use using 64-bit DMA masks
+    - usb: usbip: fix isoc packet num validation in get_pipe
+    - staging: iio: adt7316: allow adt751x to use internal vref for all dacs
+    - staging: iio: adt7316: fix the dac read calculation
+    - staging: iio: adt7316: fix the dac write calculation
+    - Input: snvs_pwrkey - initialize necessary driver data before enabling IRQ
+    - selinux: never allow relabeling on context mounts
+    - x86/mce: Improve error message when kernel cannot recover, p2
+    - media: v4l2: i2c: ov7670: Fix PLL bypass register values
+    - scsi: libsas: fix a race condition when smp task timeout
+    - ASoC:soc-pcm:fix a codec fixup issue in TDM case
+    - ASoC: cs4270: Set auto-increment bit for register writes
+    - ASoC: tlv320aic32x4: Fix Common Pins
+    - perf/x86/intel: Fix handling of wakeup_events for multi-entry PEBS
+    - scsi: csiostor: fix missing data copy in csio_scsi_err_handler()
+    - iommu/amd: Set exclusion range correctly
+    - genirq: Prevent use-after-free and work list corruption
+    - usb: dwc3: Fix default lpm_nyet_threshold value
+    - scsi: qla2xxx: Fix incorrect region-size setting in optrom SYSFS routines
+    - Bluetooth: hidp: fix buffer overflow
+    - Bluetooth: Align minimum encryption key size for LE and BR/EDR connections
+    - UAS: fix alignment of scatter/gather segments
+    - ipv6: fix a potential deadlock in do_ipv6_setsockopt()
+    - ASoC: Intel: avoid Oops if DMA setup fails
+    - timer/debug: Change /proc/timer_stats from 0644 to 0600
+    - netfilter: compat: initialize all fields in xt_init
+    - platform/x86: sony-laptop: Fix unintentional fall-through
+    - iio: adc: xilinx: fix potential use-after-free on remove
+    - HID: input: add mapping for Expose/Overview key
+    - HID: input: add mapping for keyboard Brightness Up/Down/Toggle keys
+    - libnvdimm/btt: Fix a kmemdup failure check
+    - s390/dasd: Fix capacity calculation for large volumes
+    - s390/3270: fix lockdep false positive on view->lock
+    - KVM: x86: avoid misreporting level-triggered irqs as edge-triggered in
+      tracing
+    - tools lib traceevent: Fix missing equality check for strcmp
+    - init: initialize jump labels before command line option parsing
+    - ipvs: do not schedule icmp errors from tunnels
+    - s390: ctcm: fix ctcm_new_device error return code
+    - gpu: ipu-v3: dp: fix CSC handling
+    - cw1200: fix missing unlock on error in cw1200_hw_scan()
+    - Don't jump to compute_result state from check_result state
+    - x86/microcode/intel: Add a helper which gives the microcode revision
+    - x86: stop exporting msr-index.h to userland
+    - x86/microcode/intel: Check microcode revision before updating sibling
+      threads
+    - x86/MCE: Save microcode revision in machine check records
+    - x86/bugs: Add AMD's variant of SSB_NO
+    - x86/bugs: Add AMD's SPEC_CTRL MSR usage
+    - x86/bugs: Switch the selection of mitigation from CPU vendor to CPU features
+    - x86/bugs: Fix the AMD SSBD usage of the SPEC_CTRL MSR
+    - x86/microcode: Make sure boot_cpu_data.microcode is up-to-date
+    - x86/microcode: Update the new microcode revision unconditionally
+    - x86/mm: Use WRITE_ONCE() when setting PTEs
+    - x86/speculation: Apply IBPB more strictly to avoid cross-process data leak
+    - x86/speculation: Enable cross-hyperthread spectre v2 STIBP mitigation
+    - x86/speculation: Propagate information about RSB filling mitigation to sysfs
+    - x86/speculation: Update the TIF_SSBD comment
+    - x86/speculation: Clean up spectre_v2_parse_cmdline()
+    - x86/speculation: Move STIPB/IBPB string conditionals out of
+      cpu_show_common()
+    - x86/speculation: Disable STIBP when enhanced IBRS is in use
+    - x86/speculation: Rename SSBD update functions
+    - x86/speculation: Reorganize speculation control MSRs update
+    - x86/Kconfig: Select SCHED_SMT if SMP enabled
+    - x86/speculation: Mark string arrays const correctly
+    - x86/speculataion: Mark command line parser data __initdata
+    - x86/speculation: Add command line control for indirect branch speculation
+    - x86/speculation: Prepare for per task indirect branch speculation control
+    - x86/process: Consolidate and simplify switch_to_xtra() code
+    - x86/speculation: Avoid __switch_to_xtra() calls
+    - x86/speculation: Prepare for conditional IBPB in switch_mm()
+    - x86/speculation: Split out TIF update
+    - x86/speculation: Prepare arch_smt_update() for PRCTL mode
+    - x86/speculation: Prevent stale SPEC_CTRL msr content
+    - x86/speculation: Add prctl() control for indirect branch speculation
+    - x86/speculation: Enable prctl mode for spectre_v2_user
+    - x86/speculation: Add seccomp Spectre v2 user space protection mode
+    - x86/speculation: Provide IBPB always command line options
+    - x86/cpu/bugs: Use __initconst for 'const' init data
+    - USB: serial: use variable for status
+    - USB: serial: fix unthrottle races
+    - bridge: Fix error path for kobject_init_and_add()
+    - net: ucc_geth - fix Oops when changing number of buffers in the ring
+    - packet: Fix error path in packet_init
+    - vlan: disable SIOCSHWTSTAMP in container
+    - vrf: sit mtu should not be updated when vrf netdev is the link
+    - ipv4: Fix raw socket lookup for local traffic
+    - bonding: fix arp_validate toggling in active-backup mode
+    - drivers/virt/fsl_hypervisor.c: dereferencing error pointers in ioctl
+    - drivers/virt/fsl_hypervisor.c: prevent integer overflow in ioctl
+    - powerpc/booke64: set RI in default MSR
+    - powerpc/lib: fix book3s/32 boot failure due to code patching
+    - Linux 4.4.180
+    - SAUCE: Clarify IBRS/IBPB runtime state change messages
+    - SAUCE: x86/speculation: Move STIBP hunks
+    - SAUCE: powerpc/speculation: Support 'mitigations=' cmdline option
+    - SAUCE: x86/speculation: Update 'mitigations=' documentation
+    - SAUCE: Show 'pti' instead of 'kaiser' in /proc/cpuinfo
+    - SAUCE: perf/bench: Drop definition of BIT in numa.c
+    - SAUCE: x86/speculation: Fix SSB command line documentation
+
+  * CVE-2018-12126 // CVE-2018-12127 // CVE-2018-12130 // CVE-2019-11091
+    - SAUCE: Synchronize MDS mitigations with upstream
+    - Documentation: Correct the possible MDS sysfs values
+    - x86/speculation/mds: Fix documentation typo
+
+  * CVE-2019-11091
+    - x86/mds: Add MDSUM variant to the MDS documentation
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 02 Jul 2019 13:53:41 +0200
+
+linux (4.4.0-154.181) xenial; urgency=medium
+
+  * linux: 4.4.0-154.181 -proposed tracker (LP: #1834030)
+
+  * CVE-2019-11478
+    - tcp: refine memory limit test in tcp_fragment()
+
+  * CVE-2019-11479
+    - SAUCE: tcp: add tcp_min_snd_mss sysctl
+    - SAUCE: tcp: enforce tcp_min_snd_mss in tcp_mtu_probing()
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Tue, 25 Jun 2019 00:36:38 -0400
+
+linux (4.4.0-151.178) xenial; urgency=medium
+
+  * Remote denial of service (system crash) caused by integer overflow in TCP
+    SACK handling (LP: #1831637)
+    - SAUCE: tcp: limit payload size of sacked skbs
+    - SAUCE: tcp: fix fack_count accounting on tcp_shift_skb_data()
+
+  * Remote denial of service (resource exhaustion) caused by TCP SACK scoreboard
+    manipulation (LP: #1831638)
+    - SAUCE: tcp: tcp_fragment() should apply sane memory limits
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 11 Jun 2019 09:36:19 +0200
+
+linux (4.4.0-150.176) xenial; urgency=medium
+
+  * linux: 4.4.0-150.176 -proposed tracker (LP: #1830941)
+
+  * glibc 2.23-0ubuntu11 ADT test failure with linux 4.4.0-149.175
+    (LP: #1830890)
+    - x86/vdso: Pass --eh-frame-hdr to the linker
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 29 May 2019 14:23:25 -0400
+
+linux (4.4.0-149.175) xenial; urgency=medium
+
+  * linux: 4.4.0-149.175 -proposed tracker (LP: #1829209)
+
+  * disable a.out support (LP: #1818552)
+    - [Config] Disable a.out support
+
+  * autopkgtests run too often, too much and don't skip enough (LP: #1823056)
+    - [Debian] Set +x on rebuild testcase.
+    - [Debian] Skip rebuild test, for regression-suite deps.
+    - [Debian] Make ubuntu-regression-suite skippable on unbootable kernels.
+    - [Debian] make rebuild use skippable error codes when skipping.
+    - [Debian] Only run regression-suite, if requested to.
+
+  * Xenial update: 4.4.179 upstream stable release (LP: #1828420)
+    - arm64: debug: Don't propagate UNKNOWN FAR into si_code for debug signals
+    - arm64: debug: Ensure debug handlers check triggering exception level
+    - ext4: cleanup bh release code in ext4_ind_remove_space()
+    - lib/int_sqrt: optimize initial value compute
+    - tty/serial: atmel: Add is_half_duplex helper
+    - mm: mempolicy: make mbind() return -EIO when MPOL_MF_STRICT is specified
+    - i2c: core-smbus: prevent stack corruption on read I2C_BLOCK_DATA
+    - Bluetooth: Fix decrementing reference count twice in releasing socket
+    - tty/serial: atmel: RS485 HD w/DMA: enable RX after TX is stopped
+    - CIFS: fix POSIX lock leak and invalid ptr deref
+    - h8300: use cc-cross-prefix instead of hardcoding h8300-unknown-linux-
+    - tracing: kdb: Fix ftdump to not sleep
+    - gpio: gpio-omap: fix level interrupt idling
+    - sysctl: handle overflow for file-max
+    - enic: fix build warning without CONFIG_CPUMASK_OFFSTACK
+    - mm/cma.c: cma_declare_contiguous: correct err handling
+    - mm/page_ext.c: fix an imbalance with kmemleak
+    - mm/vmalloc.c: fix kernel BUG at mm/vmalloc.c:512!
+    - mm/slab.c: kmemleak no scan alien caches
+    - ocfs2: fix a panic problem caused by o2cb_ctl
+    - f2fs: do not use mutex lock in atomic context
+    - fs/file.c: initialize init_files.resize_wait
+    - cifs: use correct format characters
+    - dm thin: add sanity checks to thin-pool and external snapshot creation
+    - cifs: Fix NULL pointer dereference of devname
+    - fs: fix guard_bio_eod to check for real EOD errors
+    - tools lib traceevent: Fix buffer overflow in arg_eval
+    - usb: chipidea: Grab the (legacy) USB PHY by phandle first
+    - scsi: core: replace GFP_ATOMIC with GFP_KERNEL in scsi_scan.c
+    - coresight: etm4x: Add support to enable ETMv4.2
+    - ARM: 8840/1: use a raw_spinlock_t in unwind
+    - mmc: omap: fix the maximum timeout setting
+    - e1000e: Fix -Wformat-truncation warnings
+    - IB/mlx4: Increase the timeout for CM cache
+    - scsi: megaraid_sas: return error when create DMA pool failed
+    - perf test: Fix failure of 'evsel-tp-sched' test on s390
+    - SoC: imx-sgtl5000: add missing put_device()
+    - media: sh_veu: Correct return type for mem2mem buffer helpers
+    - media: s5p-jpeg: Correct return type for mem2mem buffer helpers
+    - media: s5p-g2d: Correct return type for mem2mem buffer helpers
+    - media: mx2_emmaprp: Correct return type for mem2mem buffer helpers
+    - leds: lp55xx: fix null deref on firmware load failure
+    - kprobes: Prohibit probing on bsearch()
+    - ARM: 8833/1: Ensure that NEON code always compiles with Clang
+    - ALSA: PCM: check if ops are defined before suspending PCM
+    - bcache: fix input overflow to cache set sysfs file io_error_halflife
+    - bcache: fix input overflow to sequential_cutoff
+    - bcache: improve sysfs_strtoul_clamp()
+    - fbdev: fbmem: fix memory access if logo is bigger than the screen
+    - cdrom: Fix race condition in cdrom_sysctl_register
+    - ASoC: fsl-asoc-card: fix object reference leaks in fsl_asoc_card_probe
+    - soc: qcom: gsbi: Fix error handling in gsbi_probe()
+    - mt7601u: bump supported EEPROM version
+    - ARM: avoid Cortex-A9 livelock on tight dmb loops
+    - tty: increase the default flip buffer limit to 2*640K
+    - media: mt9m111: set initial frame size other than 0x0
+    - hwrng: virtio - Avoid repeated init of completion
+    - soc/tegra: fuse: Fix illegal free of IO base address
+    - hpet: Fix missing '=' character in the __setup() code of hpet_mmap_enable
+    - dmaengine: imx-dma: fix warning comparison of distinct pointer types
+    - netfilter: physdev: relax br_netfilter dependency
+    - media: s5p-jpeg: Check for fmt_ver_flag when doing fmt enumeration
+    - regulator: act8865: Fix act8600_sudcdc_voltage_ranges setting
+    - wlcore: Fix memory leak in case wl12xx_fetch_firmware failure
+    - x86/build: Mark per-CPU symbols as absolute explicitly for LLD
+    - dmaengine: tegra: avoid overflow of byte tracking
+    - drm/dp/mst: Configure no_stop_bit correctly for remote i2c xfers
+    - binfmt_elf: switch to new creds when switching to new mm
+    - kbuild: clang: choose GCC_TOOLCHAIN_DIR not on LD
+    - x86/build: Specify elf_i386 linker emulation explicitly for i386 objects
+    - x86: vdso: Use $LD instead of $CC to link
+    - x86/vdso: Drop implicit common-page-size linker flag
+    - lib/string.c: implement a basic bcmp
+    - tty: mark Siemens R3964 line discipline as BROKEN
+    - [Config]: remove CONFIG_R3964
+    - [Config]: add CONFIG_LDISC_AUTOLOAD=y
+    - tty: ldisc: add sysctl to prevent autoloading of ldiscs
+    - ipv6: Fix dangling pointer when ipv6 fragment
+    - ipv6: sit: reset ip header pointer in ipip6_rcv
+    - net: rds: force to destroy connection if t_sock is NULL in
+      rds_tcp_kill_sock().
+    - qmi_wwan: add Olicard 600
+    - sctp: initialize _pad of sockaddr_in before copying to user memory
+    - tcp: Ensure DCTCP reacts to losses
+    - netns: provide pure entropy for net_hash_mix()
+    - net: ethtool: not call vzalloc for zero sized memory request
+    - ip6_tunnel: Match to ARPHRD_TUNNEL6 for dev type
+    - ALSA: seq: Fix OOB-reads from strlcpy
+    - include/linux/bitrev.h: fix constant bitrev
+    - ASoC: fsl_esai: fix channel swap issue when stream starts
+    - block: do not leak memory in bio_copy_user_iov()
+    - genirq: Respect IRQCHIP_SKIP_SET_WAKE in irq_chip_set_wake_parent()
+    - ARM: dts: at91: Fix typo in ISC_D0 on PC9
+    - arm64: futex: Fix FUTEX_WAKE_OP atomic ops with non-zero result value
+    - xen: Prevent buffer overflow in privcmd ioctl
+    - sched/fair: Do not re-read ->h_load_next during hierarchical load
+      calculation
+    - xtensa: fix return_address
+    - PCI: Add function 1 DMA alias quirk for Marvell 9170 SATA controller
+    - perf/core: Restore mmap record type correctly
+    - ext4: add missing brelse() in add_new_gdb_meta_bg()
+    - ext4: report real fs size after failed resize
+    - ALSA: echoaudio: add a check for ioremap_nocache
+    - ALSA: sb8: add a check for request_region
+    - IB/mlx4: Fix race condition between catas error reset and aliasguid flows
+    - mmc: davinci: remove extraneous __init annotation
+    - ALSA: opl3: fix mismatch between snd_opl3_drum_switch definition and
+      declaration
+    - thermal/int340x_thermal: Add additional UUIDs
+    - thermal/int340x_thermal: fix mode setting
+    - tools/power turbostat: return the exit status of a command
+    - perf top: Fix error handling in cmd_top()
+    - perf evsel: Free evsel->counts in perf_evsel__exit()
+    - perf tests: Fix a memory leak of cpu_map object in the
+      openat_syscall_event_on_all_cpus test
+    - perf tests: Fix a memory leak in test__perf_evsel__tp_sched_test()
+    - x86/hpet: Prevent potential NULL pointer dereference
+    - x86/cpu/cyrix: Use correct macros for Cyrix calls on Geode processors
+    - iommu/vt-d: Check capability before disabling protected memory
+    - x86/hw_breakpoints: Make default case in hw_breakpoint_arch_parse() return
+      an error
+    - fix incorrect error code mapping for OBJECTID_NOT_FOUND
+    - ext4: prohibit fstrim in norecovery mode
+    - rsi: improve kernel thread handling to fix kernel panic
+    - 9p: do not trust pdu content for stat item size
+    - 9p locks: add mount option for lock retry interval
+    - f2fs: fix to do sanity check with current segment number
+    - serial: uartps: console_setup() can't be placed to init section
+    - ARM: samsung: Limit SAMSUNG_PM_CHECK config option to non-Exynos platforms
+    - ACPI / SBS: Fix GPE storm on recent MacBookPro's
+    - cifs: fallback to older infolevels on findfirst queryinfo retry
+    - crypto: sha256/arm - fix crash bug in Thumb2 build
+    - crypto: sha512/arm - fix crash bug in Thumb2 build
+    - iommu/dmar: Fix buffer overflow during PCI bus notification
+    - ARM: 8839/1: kprobe: make patch_lock a raw_spinlock_t
+    - appletalk: Fix use-after-free in atalk_proc_exit
+    - lib/div64.c: off by one in shift
+    - include/linux/swap.h: use offsetof() instead of custom __swapoffset macro
+    - tpm/tpm_crb: Avoid unaligned reads in crb_recv()
+    - ovl: fix uid/gid when creating over whiteout
+    - appletalk: Fix compile regression
+    - bonding: fix event handling for stacked bonds
+    - net: atm: Fix potential Spectre v1 vulnerabilities
+    - net: bridge: multicast: use rcu to access port list from
+      br_multicast_start_querier
+    - net: fou: do not use guehdr after iptunnel_pull_offloads in gue_udp_recv
+    - tcp: tcp_grow_window() needs to respect tcp_space()
+    - ipv4: recompile ip options in ipv4_link_failure
+    - ipv4: ensure rcu_read_lock() in ipv4_link_failure()
+    - crypto: crypto4xx - properly set IV after de- and encrypt
+    - modpost: file2alias: go back to simple devtable lookup
+    - modpost: file2alias: check prototype of handler
+    - tpm/tpm_i2c_atmel: Return -E2BIG when the transfer is incomplete
+    - KVM: x86: Don't clear EFER during SMM transitions for 32-bit vCPU
+    - iio/gyro/bmg160: Use millidegrees for temperature scale
+    - iio: ad_sigma_delta: select channel when reading register
+    - iio: adc: at91: disable adc channel interrupt in timeout case
+    - io: accel: kxcjk1013: restore the range after resume.
+    - staging: comedi: vmk80xx: Fix use of uninitialized semaphore
+    - staging: comedi: vmk80xx: Fix possible double-free of ->usb_rx_buf
+    - staging: comedi: ni_usb6501: Fix use of uninitialized mutex
+    - staging: comedi: ni_usb6501: Fix possible double-free of ->usb_rx_buf
+    - ALSA: core: Fix card races between register and disconnect
+    - crypto: x86/poly1305 - fix overflow during partial reduction
+    - arm64: futex: Restore oldval initialization to work around buggy compilers
+    - x86/kprobes: Verify stack frame on kretprobe
+    - kprobes: Mark ftrace mcount handler functions nokprobe
+    - kprobes: Fix error check when reusing optimized probes
+    - mac80211: do not call driver wake_tx_queue op during reconfig
+    - Revert "kbuild: use -Oz instead of -Os when using clang"
+    - sched/fair: Limit sched_cfs_period_timer() loop to avoid hard lockup
+    - device_cgroup: fix RCU imbalance in error case
+    - mm/vmstat.c: fix /proc/vmstat format for CONFIG_DEBUG_TLBFLUSH=y
+      CONFIG_SMP=n
+    - ALSA: info: Fix racy addition/deletion of nodes
+    - Revert "locking/lockdep: Add debug_locks check in __lock_downgrade()"
+    - kernel/sysctl.c: fix out-of-bounds access when setting file-max
+    - Linux 4.4.179
+
+  * Xenial update: 4.4.178 upstream stable release (LP: #1826212)
+    - mmc: pxamci: fix enum type confusion
+    - drm/vmwgfx: Don't double-free the mode stored in par->set_mode
+    - udf: Fix crash on IO error during truncate
+    - mips: loongson64: lemote-2f: Add IRQF_NO_SUSPEND to "cascade" irqaction.
+    - MIPS: Fix kernel crash for R6 in jump label branch function
+    - futex: Ensure that futex address is aligned in handle_futex_death()
+    - ext4: fix NULL pointer dereference while journal is aborted
+    - ext4: fix data corruption caused by unaligned direct AIO
+    - ext4: brelse all indirect buffer in ext4_ind_remove_space()
+    - mmc: tmio_mmc_core: don't claim spurious interrupts
+    - media: v4l2-ctrls.c/uvc: zero v4l2_event
+    - locking/lockdep: Add debug_locks check in __lock_downgrade()
+    - ALSA: hda - Record the current power state before suspend/resume calls
+    - ALSA: hda - Enforces runtime_resume after S3 and S4 for each codec
+    - mmc: pwrseq_simple: Make reset-gpios optional to match doc
+    - mmc: debugfs: Add a restriction to mmc debugfs clock setting
+    - mmc: make MAN_BKOPS_EN message a debug
+    - mmc: sanitize 'bus width' in debug output
+    - mmc: core: shut up "voltage-ranges unspecified" pr_info()
+    - usb: dwc3: gadget: Fix suspend/resume during device mode
+    - arm64: mm: Add trace_irqflags annotations to do_debug_exception()
+    - mmc: core: fix using wrong io voltage if mmc_select_hs200 fails
+    - mm/rmap: replace BUG_ON(anon_vma->degree) with VM_WARN_ON
+    - extcon: usb-gpio: Don't miss event during suspend/resume
+    - kbuild: setlocalversion: print error to STDERR
+    - usb: gadget: composite: fix dereference after null check coverify warning
+    - usb: gadget: Add the gserial port checking in gs_start_tx()
+    - tcp/dccp: drop SYN packets if accept queue is full
+    - serial: sprd: adjust TIMEOUT to a big value
+    - Hang/soft lockup in d_invalidate with simultaneous calls
+    - arm64: traps: disable irq in die()
+    - usb: renesas_usbhs: gadget: fix unused-but-set-variable warning
+    - serial: sprd: clear timeout interrupt only rather than all interrupts
+    - lib/int_sqrt: optimize small argument
+    - USB: core: only clean up what we allocated
+    - rtc: Fix overflow when converting time64_t to rtc_time
+    - ath10k: avoid possible string overflow
+    - mmc: block: Allow more than 8 partitions per card
+    - arm64: fix COMPAT_SHMLBA definition for large pages
+    - efi: stub: define DISABLE_BRANCH_PROFILING for all architectures
+    - ARM: 8458/1: bL_switcher: add GIC dependency
+    - ARM: 8494/1: mm: Enable PXN when running non-LPAE kernel on LPAE processor
+    - android: unconditionally remove callbacks in sync_fence_free()
+    - vmstat: make vmstat_updater deferrable again and shut down on idle
+    - hid-sensor-hub.c: fix wrong do_div() usage
+    - arm64: hide __efistub_ aliases from kallsyms
+    - perf: Synchronously free aux pages in case of allocation failure
+    - net: diag: support v4mapped sockets in inet_diag_find_one_icsk()
+    - Revert "mmc: block: don't use parameter prefix if built as module"
+    - writeback: initialize inode members that track writeback history
+    - coresight: fixing lockdep error
+    - coresight: coresight_unregister() function cleanup
+    - coresight: release reference taken by 'bus_find_device()'
+    - coresight: remove csdev's link from topology
+    - stm class: Fix locking in unbinding policy path
+    - stm class: Fix link list locking
+    - stm class: Prevent user-controllable allocations
+    - stm class: Support devices with multiple instances
+    - stm class: Fix unlocking braino in the error path
+    - stm class: Guard output assignment against concurrency
+    - stm class: Fix unbalanced module/device refcounting
+    - stm class: Fix a race in unlinking
+    - coresight: "DEVICE_ATTR_RO" should defined as static.
+    - coresight: etm4x: Check every parameter used by dma_xx_coherent.
+    - asm-generic: Fix local variable shadow in __set_fixmap_offset
+    - staging: ashmem: Avoid deadlock with mmap/shrink
+    - staging: ashmem: Add missing include
+    - staging: ion: Set minimum carveout heap allocation order to PAGE_SHIFT
+    - staging: goldfish: audio: fix compiliation on arm
+    - ARM: 8510/1: rework ARM_CPU_SUSPEND dependencies
+    - arm64/kernel: fix incorrect EL0 check in inv_entry macro
+    - mac80211: fix "warning: ‘target_metric’ may be used uninitialized"
+    - perf/ring_buffer: Refuse to begin AUX transaction after rb->aux_mmap_count
+      drops
+    - arm64: kernel: Include _AC definition in page.h
+    - PM / Hibernate: Call flush_icache_range() on pages restored in-place
+    - stm class: Do not leak the chrdev in error path
+    - stm class: Fix stm device initialization order
+    - ipv6: fix endianness error in icmpv6_err
+    - usb: gadget: configfs: add mutex lock before unregister gadget
+    - usb: gadget: rndis: free response queue during REMOTE_NDIS_RESET_MSG
+    - cpu/hotplug: Handle unbalanced hotplug enable/disable
+    - video: fbdev: Set pixclock = 0 in goldfishfb
+    - arm64: kconfig: drop CONFIG_RTC_LIB dependency
+    - mmc: mmc: fix switch timeout issue caused by jiffies precision
+    - cfg80211: size various nl80211 messages correctly
+    - stmmac: copy unicast mac address to MAC registers
+    - dccp: do not use ipv6 header for ipv4 flow
+    - mISDN: hfcpci: Test both vendor & device ID for Digium HFC4S
+    - net/packet: Set __GFP_NOWARN upon allocation in alloc_pg_vec
+    - net: rose: fix a possible stack overflow
+    - Add hlist_add_tail_rcu() (Merge
+      git://git.kernel.org/pub/scm/linux/kernel/git/davem/net)
+    - packets: Always register packet sk in the same order
+    - tcp: do not use ipv6 header for ipv4 flow
+    - vxlan: Don't call gro_cells_destroy() before device is unregistered
+    - sctp: get sctphdr by offset in sctp_compute_cksum
+    - mac8390: Fix mmio access size probe
+    - btrfs: remove WARN_ON in log_dir_items
+    - ARM: imx6q: cpuidle: fix bug that CPU might not wake up at expected time
+    - ALSA: compress: add support for 32bit calls in a 64bit kernel
+    - ALSA: pcm: Fix possible OOB access in PCM oss plugins
+    - ALSA: pcm: Don't suspend stream in unrecoverable PCM state
+    - scsi: sd: Fix a race between closing an sd device and sd I/O
+    - scsi: zfcp: fix rport unblock if deleted SCSI devices on Scsi_Host
+    - scsi: zfcp: fix scsi_eh host reset with port_forced ERP for non-NPIV FCP
+      devices
+    - tty: atmel_serial: fix a potential NULL pointer dereference
+    - staging: vt6655: Remove vif check from vnt_interrupt
+    - staging: vt6655: Fix interrupt race condition on device start up.
+    - serial: max310x: Fix to avoid potential NULL pointer dereference
+    - serial: sh-sci: Fix setting SCSCR_TIE while transferring data
+    - USB: serial: cp210x: add new device id
+    - USB: serial: ftdi_sio: add additional NovaTech products
+    - USB: serial: mos7720: fix mos_parport refcount imbalance on error path
+    - USB: serial: option: set driver_info for SIM5218 and compatibles
+    - USB: serial: option: add Olicard 600
+    - Disable kgdboc failed by echo space to /sys/module/kgdboc/parameters/kgdboc
+    - fs/proc/proc_sysctl.c: fix NULL pointer dereference in put_links
+    - gpio: adnp: Fix testing wrong value in adnp_gpio_direction_input
+    - perf intel-pt: Fix TSC slip
+    - x86/smp: Enforce CONFIG_HOTPLUG_CPU when SMP=y
+    - KVM: Reject device ioctls from processes other than the VM's creator
+    - xhci: Fix port resume done detection for SS ports with LPM enabled
+    - Revert "USB: core: only clean up what we allocated"
+    - arm64: support keyctl() system call in 32-bit mode
+    - coresight: removing bind/unbind options from sysfs
+    - stm class: Hide STM-specific options if STM is disabled
+    - Linux 4.4.178
+
+  * Kprobe event string type argument failed in ftrace from
+    ubuntu_kernel_selftests on B/C i386 (LP: #1825780)
+    - selftests/ftrace: Fix kprobe string testcase to not probe notrace function
+
+  * False positive test result in run_netsocktests from net in
+    ubuntu_kernel_selftest (LP: #1825777)
+    - selftests/net: correct the return value for run_netsocktests
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 15 May 2019 14:39:49 +0200
+
+linux (4.4.0-148.174) xenial; urgency=medium
+
+  * CVE-2018-12126 // CVE-2018-12127 // CVE-2018-12130
+    - Documentation/l1tf: Fix small spelling typo
+    - perf/x86/intel: Add model number for Skylake Server to perf
+    - perf/x86: Add model numbers for Kabylake CPUs
+    - perf/x86/intel: Use Intel family macros for core perf events
+    - perf/x86/msr: Use Intel family macros for MSR events code
+    - perf/x86/msr: Add missing Intel models
+    - SAUCE: perf/x86/{cstate,rapl,uncore}: Use Intel Model name macros
+    - perf/x86/msr: Add missing CPU IDs
+    - x86/speculation: Simplify the CPU bug detection logic
+    - x86/cpu: Sanitize FAM6_ATOM naming
+    - kvm: x86: Report STIBP on GET_SUPPORTED_CPUID
+    - bitops: avoid integer overflow in GENMASK(_ULL)
+    - locking/atomics, asm-generic: Move some macros from <linux/bitops.h> to a
+      new <linux/bits.h> file
+    - tools include: Adopt linux/bits.h
+    - x86/msr-index: Cleanup bit defines
+    - x86/speculation: Consolidate CPU whitelists
+    - x86/speculation/mds: Add basic bug infrastructure for MDS
+    - x86/speculation/mds: Add BUG_MSBDS_ONLY
+    - x86/kvm: Expose X86_FEATURE_MD_CLEAR to guests
+    - x86/speculation/mds: Add mds_clear_cpu_buffers()
+    - locking/static_keys: Provide DECLARE and well as DEFINE macros
+    - x86/speculation/mds: Clear CPU buffers on exit to user
+    - x86/kvm/vmx: Add MDS protection when L1D Flush is not active
+    - x86/speculation/mds: Conditionally clear CPU buffers on idle entry
+    - SAUCE: sched/smt: Introduce sched_smt_{active,present}
+    - SAUCE: Rename the Ubuntu-only spec_ctrl_mutex mutex
+    - SAUCE: x86/speculation: Introduce arch_smt_update()
+    - x86/speculation: Rework SMT state change
+    - x86/speculation: Reorder the spec_v2 code
+    - x86/speculation: Unify conditional spectre v2 print functions
+    - x86/speculation/mds: Add mitigation control for MDS
+    - x86/speculation/mds: Add sysfs reporting for MDS
+    - x86/speculation/mds: Add mitigation mode VMWERV
+    - Documentation: Move L1TF to separate directory
+    - Documentation: Add MDS vulnerability documentation
+    - x86/speculation/mds: Add mds=full,nosmt cmdline option
+    - x86/speculation: Move arch_smt_update() call to after mitigation decisions
+    - x86/speculation/mds: Add SMT warning message
+    - x86/speculation/mds: Fix comment
+    - x86/speculation/mds: Print SMT vulnerable on MSBDS with mitigations off
+    - x86/speculation/mds: Add 'mitigations=' support for MDS
+
+  * CVE-2017-5715 // CVE-2017-5753
+    - s390/speculation: Support 'mitigations=' cmdline option
+
+  * CVE-2017-5715 // CVE-2017-5753 // CVE-2017-5754 // CVE-2018-3639
+    - powerpc/speculation: Support 'mitigations=' cmdline option
+
+  * CVE-2017-5715 // CVE-2017-5754 // CVE-2018-3620 // CVE-2018-3639 //
+    CVE-2018-3646
+    - cpu/speculation: Add 'mitigations=' cmdline option
+    - x86/speculation: Support 'mitigations=' cmdline option
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 07 May 2019 11:35:48 +0200
+
+linux (4.4.0-147.173) xenial; urgency=medium
+
+  * linux: 4.4.0-147.173 -proposed tracker (LP: #1826036)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * Xenial: Sync to upstream v4.9 (Spectre) (LP: #1820872)
+    - SAUCE: cpu/hotplug: Fix Documentation/kernel-parameters.txt
+    - SAUCE: Fix typo in Documentation/kernel-parameters.txt
+    - SAUCE: x86: Move hunks and sync to upstream stable 4.9
+    - Revert "module: Add retpoline tag to VERMAGIC"
+
+  * CVE-2017-5753
+    - posix-timers: Protect posix clock array access against speculation
+    - arm64: fix possible spectre-v1 in ptrace_hbp_get_event()
+    - sched/autogroup: Fix possible Spectre-v1 indexing for sched_prio_to_weight[]
+    - media: dvb_ca_en50221: prevent using slot_info for Spectre attacs
+    - s390/keyboard: sanitize array index in do_kdsk_ioctl
+    - arm64: fix possible spectre-v1 write in ptrace_hbp_set_event()
+    - pktcdvd: Fix possible Spectre-v1 for pkt_devs
+    - net: socket: Fix potential spectre v1 gadget in sock_is_registered
+    - net: sock_diag: Fix spectre v1 gadget in __sock_diag_cmd()
+    - hwmon: (nct6775) Fix potential Spectre v1
+    - mac80211_hwsim: Fix possible Spectre-v1 for hwsim_world_regdom_custom
+    - nl80211: Fix possible Spectre-v1 for NL80211_TXRATE_HT
+    - ipmi: msghandler: Fix potential Spectre v1 vulnerabilities
+    - powerpc/ptrace: Mitigate potential Spectre v1
+    - cfg80211: prevent speculation on cfg80211_classify8021d() return
+    - ALSA: rawmidi: Fix potential Spectre v1 vulnerability
+    - ALSA: seq: oss: Fix Spectre v1 vulnerability
+
+  * CVE-2019-3874
+    - sctp: fix the issue that a __u16 variable may overflow in sctp_ulpq_renege
+    - sctp: use sk_wmem_queued to check for writable space
+    - sctp: implement memory accounting on tx path
+    - sctp: implement memory accounting on rx path
+
+  * Kprobe event argument syntax in ftrace from ubuntu_kernel_selftests failed
+    on B PowerPC (LP: #1812809)
+    - selftests/ftrace: Add ppc support for kprobe args tests
+
+  * CVE-2019-3882
+    - vfio/type1: Limit DMA mappings per container
+
+  * Intel I210 Ethernet card not working after hotplug [8086:1533]
+    (LP: #1818490)
+    - igb: Fix WARN_ONCE on runtime suspend
+
+  * TSC clocksource not available in nested guests (LP: #1822821)
+    - x86/tsc: Add X86_FEATURE_TSC_KNOWN_FREQ flag
+    - kvmclock: fix TSC calibration for nested guests
+
+  * Remove btrfs module after a failed fallocate attempt will cause error on 4.4
+    i386 (LP: #1822579)
+    - Btrfs: fix extent map leak during fallocate error path
+
+  * systemd cause kernel trace "BUG: unable to handle kernel paging request at
+    6db23a14" on Cosmic i386 (LP: #1813244) // systemd cause kernel trace "BUG:
+    unable to handle kernel paging request at 6db23a14" on Cosmic i386
+    (LP: #1813244)
+    - openvswitch: fix flow actions reallocation
+
+ -- Connor Kuehl <connor.kuehl@canonical.com>  Tue, 23 Apr 2019 11:51:25 -0700
+
+linux (4.4.0-146.172) xenial; urgency=medium
+
+  * linux: 4.4.0-146.172 -proposed tracker (LP: #1822834)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - [Packaging] resync retpoline extraction
+
+  * 3b080b2564287be91605bfd1d5ee985696e61d3c in ubuntu_btrfs_kernel_fixes
+    triggers system hang on i386 (LP: #1812845)
+    - btrfs: raid56: properly unmap parity page in finish_parity_scrub()
+
+  * Xenial update: 4.4.177 upstream stable release (LP: #1822271)
+    - ceph: avoid repeatedly adding inode to mdsc->snap_flush_list
+    - numa: change get_mempolicy() to use nr_node_ids instead of MAX_NUMNODES
+    - KEYS: allow reaching the keys quotas exactly
+    - mfd: ti_am335x_tscadc: Use PLATFORM_DEVID_AUTO while registering mfd cells
+    - mfd: twl-core: Fix section annotations on {,un}protect_pm_master
+    - mfd: db8500-prcmu: Fix some section annotations
+    - mfd: ab8500-core: Return zero in get_register_interruptible()
+    - mfd: qcom_rpm: write fw_version to CTRL_REG
+    - mfd: wm5110: Add missing ASRC rate register
+    - mfd: mc13xxx: Fix a missing check of a register-read failure
+    - net: hns: Fix use after free identified by SLUB debug
+    - MIPS: ath79: Enable OF serial ports in the default config
+    - scsi: qla4xxx: check return code of qla4xxx_copy_from_fwddb_param
+    - scsi: isci: initialize shost fully before calling scsi_add_host()
+    - MIPS: jazz: fix 64bit build
+    - isdn: i4l: isdn_tty: Fix some concurrency double-free bugs
+    - atm: he: fix sign-extension overflow on large shift
+    - leds: lp5523: fix a missing check of return value of lp55xx_read
+    - isdn: avm: Fix string plus integer warning from Clang
+    - RDMA/srp: Rework SCSI device reset handling
+    - KEYS: user: Align the payload buffer
+    - KEYS: always initialize keyring_index_key::desc_len
+    - batman-adv: fix uninit-value in batadv_interface_tx()
+    - net/packet: fix 4gb buffer limit due to overflow check
+    - team: avoid complex list operations in team_nl_cmd_options_set()
+    - sit: check if IPv6 enabled before calling ip6_err_gen_icmpv6_unreach()
+    - net/mlx4_en: Force CHECKSUM_NONE for short ethernet frames
+    - ARCv2: Enable unaligned access in early ASM code
+    - Revert "bridge: do not add port to router list when receives query with
+      source 0.0.0.0"
+    - libceph: handle an empty authorize reply
+    - drm/msm: Unblock writer if reader closes file
+    - ASoC: Intel: Haswell/Broadwell: fix setting for .dynamic field
+    - ALSA: compress: prevent potential divide by zero bugs
+    - thermal: int340x_thermal: Fix a NULL vs IS_ERR() check
+    - usb: dwc3: gadget: Fix the uninitialized link_state when udc starts
+    - usb: gadget: Potential NULL dereference on allocation error
+    - ASoC: dapm: change snprintf to scnprintf for possible overflow
+    - ASoC: imx-audmux: change snprintf to scnprintf for possible overflow
+    - ARC: fix __ffs return value to avoid build warnings
+    - mac80211: fix miscounting of ttl-dropped frames
+    - serial: fsl_lpuart: fix maximum acceptable baud rate with over-sampling
+    - scsi: csiostor: fix NULL pointer dereference in csio_vport_set_state()
+    - net: altera_tse: fix connect_local_phy error path
+    - ibmveth: Do not process frames after calling napi_reschedule
+    - mac80211: don't initiate TDLS connection if station is not associated to AP
+    - cfg80211: extend range deviation for DMG
+    - KVM: nSVM: clear events pending from svm_complete_interrupts() when exiting
+      to L1
+    - arm/arm64: KVM: Feed initialized memory to MMIO accesses
+    - KVM: arm/arm64: Fix MMIO emulation data handling
+    - powerpc: Always initialize input array when calling epapr_hypercall()
+    - mmc: spi: Fix card detection during probe
+    - x86/uaccess: Don't leak the AC flag into __put_user() value evaluation
+    - USB: serial: option: add Telit ME910 ECM composition
+    - USB: serial: cp210x: add ID for Ingenico 3070
+    - USB: serial: ftdi_sio: add ID for Hjelmslund Electronics USB485
+    - cpufreq: Use struct kobj_attribute instead of struct global_attr
+    - sockfs: getxattr: Fail with -EOPNOTSUPP for invalid attribute names
+    - ncpfs: fix build warning of strncpy
+    - isdn: isdn_tty: fix build warning of strncpy
+    - staging: lustre: fix buffer overflow of string buffer
+    - net-sysfs: Fix mem leak in netdev_register_kobject
+    - team: Free BPF filter when unregistering netdev
+    - bnxt_en: Drop oversize TX packets to prevent errors.
+    - net: nfc: Fix NULL dereference on nfc_llcp_build_tlv fails
+    - xen-netback: fix occasional leak of grant ref mappings under memory pressure
+    - net: Add __icmp_send helper.
+    - net: avoid use IPCB in cipso_v4_error
+    - net: phy: Micrel KSZ8061: link failure after cable connect
+    - x86/CPU/AMD: Set the CPB bit unconditionally on F17h
+    - applicom: Fix potential Spectre v1 vulnerabilities
+    - MIPS: irq: Allocate accurate order pages for irq stack
+    - hugetlbfs: fix races and page leaks during migration
+    - netlabel: fix out-of-bounds memory accesses
+    - net: dsa: mv88e6xxx: Fix u64 statistics
+    - ip6mr: Do not call __IP6_INC_STATS() from preemptible context
+    - media: uvcvideo: Fix 'type' check leading to overflow
+    - vti4: Fix a ipip packet processing bug in 'IPCOMP' virtual tunnel
+    - perf tools: Handle TOPOLOGY headers with no CPU
+    - IB/{hfi1, qib}: Fix WC.byte_len calculation for UD_SEND_WITH_IMM
+    - ipvs: Fix signed integer overflow when setsockopt timeout
+    - iommu/amd: Fix IOMMU page flush when detach device from a domain
+    - xtensa: SMP: fix ccount_timer_shutdown
+    - xtensa: SMP: fix secondary CPU initialization
+    - xtensa: smp_lx200_defconfig: fix vectors clash
+    - xtensa: SMP: mark each possible CPU as present
+    - xtensa: SMP: limit number of possible CPUs by NR_CPUS
+    - net: altera_tse: fix msgdma_tx_completion on non-zero fill_level case
+    - net: hns: Fix wrong read accesses via Clause 45 MDIO protocol
+    - net: stmmac: dwmac-rk: fix error handling in rk_gmac_powerup()
+    - gpio: vf610: Mask all GPIO interrupts
+    - nfs: Fix NULL pointer dereference of dev_name
+    - scsi: libfc: free skb when receiving invalid flogi resp
+    - platform/x86: Fix unmet dependency warning for SAMSUNG_Q10
+    - cifs: fix computation for MAX_SMB2_HDR_SIZE
+    - x86/kexec: Don't setup EFI info if EFI runtime is not enabled
+    - x86_64: increase stack size for KASAN_EXTRA
+    - mm, memory_hotplug: is_mem_section_removable do not pass the end of a zone
+    - mm, memory_hotplug: test_pages_in_a_zone do not pass the end of zone
+    - fs/drop_caches.c: avoid softlockups in drop_pagecache_sb()
+    - autofs: drop dentry reference only when it is never used
+    - autofs: fix error return in autofs_fill_super()
+    - ARM: pxa: ssp: unneeded to free devm_ allocated data
+    - irqchip/mmp: Only touch the PJ4 IRQ & FIQ bits on enable/disable
+    - dmaengine: at_xdmac: Fix wrongfull report of a channel as in use
+    - dmaengine: dmatest: Abort test in case of mapping error
+    - s390/qeth: fix use-after-free in error path
+    - perf symbols: Filter out hidden symbols from labels
+    - MIPS: Remove function size check in get_frame_info()
+    - Input: wacom_serial4 - add support for Wacom ArtPad II tablet
+    - Input: elan_i2c - add id for touchpad found in Lenovo s21e-20
+    - iscsi_ibft: Fix missing break in switch statement
+    - futex,rt_mutex: Restructure rt_mutex_finish_proxy_lock()
+    - ARM: dts: exynos: Add minimal clkout parameters to Exynos3250 PMU
+    - Revert "x86/platform/UV: Use efi_runtime_lock to serialise BIOS calls"
+    - ARM: dts: exynos: Do not ignore real-world fuse values for thermal zone 0 on
+      Exynos5420
+    - udplite: call proper backlog handlers
+    - netfilter: x_tables: enforce nul-terminated table name from getsockopt
+      GET_ENTRIES
+    - netfilter: nfnetlink_log: just returns error for unknown command
+    - netfilter: nfnetlink_acct: validate NFACCT_FILTER parameters
+    - netfilter: nf_conntrack_tcp: Fix stack out of bounds when parsing TCP
+      options
+    - KEYS: restrict /proc/keys by credentials at open time
+    - l2tp: fix infoleak in l2tp_ip6_recvmsg()
+    - net: hsr: fix memory leak in hsr_dev_finalize()
+    - net: sit: fix UBSAN Undefined behaviour in check_6rd
+    - net/x25: fix use-after-free in x25_device_event()
+    - net/x25: reset state in x25_connect()
+    - pptp: dst_release sk_dst_cache in pptp_sock_destruct
+    - ravb: Decrease TxFIFO depth of Q3 and Q2 to one
+    - route: set the deleted fnhe fnhe_daddr to 0 in ip_del_fnhe to fix a race
+    - tcp: handle inet_csk_reqsk_queue_add() failures
+    - net/mlx4_core: Fix reset flow when in command polling mode
+    - net/mlx4_core: Fix qp mtt size calculation
+    - net/x25: fix a race in x25_bind()
+    - mdio_bus: Fix use-after-free on device_register fails
+    - net: Set rtm_table to RT_TABLE_COMPAT for ipv6 for tables > 255
+    - missing barriers in some of unix_sock ->addr and ->path accesses
+    - ipvlan: disallow userns cap_net_admin to change global mode/flags
+    - vxlan: test dev->flags & IFF_UP before calling gro_cells_receive()
+    - vxlan: Fix GRO cells race condition between receive and link delete
+    - net/hsr: fix possible crash in add_timer()
+    - gro_cells: make sure device is up in gro_cells_receive()
+    - tcp/dccp: remove reqsk_put() from inet_child_forget()
+    - ALSA: bebob: use more identical mod_alias for Saffire Pro 10 I/O against
+      Liquid Saffire 56
+    - fs/9p: use fscache mutex rather than spinlock
+    - It's wrong to add len to sector_nr in raid10 reshape twice
+    - media: videobuf2-v4l2: drop WARN_ON in vb2_warn_zero_bytesused()
+    - 9p: use inode->i_lock to protect i_size_write() under 32-bit
+    - 9p/net: fix memory leak in p9_client_create
+    - ASoC: fsl_esai: fix register setting issue in RIGHT_J mode
+    - stm class: Fix an endless loop in channel allocation
+    - crypto: caam - fixed handling of sg list
+    - crypto: ahash - fix another early termination in hash walk
+    - gpu: ipu-v3: Fix i.MX51 CSI control registers offset
+    - gpu: ipu-v3: Fix CSI offsets for imx53
+    - s390/dasd: fix using offset into zero size array error
+    - ARM: OMAP2+: Variable "reg" in function omap4_dsi_mux_pads() could be
+      uninitialized
+    - Input: matrix_keypad - use flush_delayed_work()
+    - i2c: cadence: Fix the hold bit setting
+    - Input: st-keyscan - fix potential zalloc NULL dereference
+    - ARM: 8824/1: fix a migrating irq bug when hotplug cpu
+    - assoc_array: Fix shortcut creation
+    - net: systemport: Fix reception of BPDUs
+    - pinctrl: meson: meson8b: fix the sdxc_a data 1..3 pins
+    - net: mv643xx_eth: disable clk on error path in mv643xx_eth_shared_probe()
+    - ASoC: topology: free created components in tplg load error
+    - arm64: Relax GIC version check during early boot
+    - tmpfs: fix link accounting when a tmpfile is linked in
+    - ARC: uacces: remove lp_start, lp_end from clobber list
+    - phonet: fix building with clang
+    - mac80211_hwsim: propagate genlmsg_reply return code
+    - net: set static variable an initial value in atl2_probe()
+    - tmpfs: fix uninitialized return value in shmem_link
+    - stm class: Prevent division by zero
+    - crypto: arm64/aes-ccm - fix logical bug in AAD MAC handling
+    - CIFS: Fix read after write for files with read caching
+    - tracing: Do not free iter->trace in fail path of tracing_open_pipe()
+    - ACPI / device_sysfs: Avoid OF modalias creation for removed device
+    - regulator: s2mps11: Fix steps for buck7, buck8 and LDO35
+    - regulator: s2mpa01: Fix step values for some LDOs
+    - clocksource/drivers/exynos_mct: Move one-shot check from tick clear to ISR
+    - clocksource/drivers/exynos_mct: Clear timer interrupt when shutdown
+    - s390/virtio: handle find on invalid queue gracefully
+    - scsi: virtio_scsi: don't send sc payload with tmfs
+    - scsi: target/iscsi: Avoid iscsit_release_commands_from_conn() deadlock
+    - m68k: Add -ffreestanding to CFLAGS
+    - btrfs: ensure that a DUP or RAID1 block group has exactly two stripes
+    - Btrfs: fix corruption reading shared and compressed extents after hole
+      punching
+    - crypto: pcbc - remove bogus memcpy()s with src == dest
+    - cpufreq: tegra124: add missing of_node_put()
+    - cpufreq: pxa2xx: remove incorrect __init annotation
+    - ext4: fix crash during online resizing
+    - ext2: Fix underflow in ext2_max_size()
+    - clk: ingenic: Fix round_rate misbehaving with non-integer dividers
+    - dmaengine: usb-dmac: Make DMAC system sleep callbacks explicit
+    - mm/vmalloc: fix size check for remap_vmalloc_range_partial()
+    - kernel/sysctl.c: add missing range check in do_proc_dointvec_minmax_conv
+    - intel_th: Don't reference unassigned outputs
+    - parport_pc: fix find_superio io compare code, should use equal test.
+    - i2c: tegra: fix maximum transfer size
+    - perf bench: Copy kernel files needed to build mem{cpy,set} x86_64 benchmarks
+    - serial: 8250_pci: Fix number of ports for ACCES serial cards
+    - serial: 8250_pci: Have ACCES cards that use the four port Pericom PI7C9X7954
+      chip use the pci_pericom_setup()
+    - jbd2: clear dirty flag when revoking a buffer from an older transaction
+    - jbd2: fix compile warning when using JBUFFER_TRACE
+    - powerpc/32: Clear on-stack exception marker upon exception return
+    - powerpc/wii: properly disable use of BATs when requested.
+    - powerpc/powernv: Make opal log only readable by root
+    - powerpc/83xx: Also save/restore SPRG4-7 during suspend
+    - ARM: s3c24xx: Fix boolean expressions in osiris_dvs_notify
+    - dm: fix to_sector() for 32bit
+    - NFS41: pop some layoutget errors to application
+    - perf intel-pt: Fix CYC timestamp calculation after OVF
+    - perf auxtrace: Define auxtrace record alignment
+    - perf intel-pt: Fix overlap calculation for padding
+    - md: Fix failed allocation of md_register_thread
+    - NFS: Fix an I/O request leakage in nfs_do_recoalesce
+    - NFS: Don't recoalesce on error in nfs_pageio_complete_mirror()
+    - nfsd: fix memory corruption caused by readdir
+    - nfsd: fix wrong check in write_v4_end_grace()
+    - PM / wakeup: Rework wakeup source timer cancellation
+    - rcu: Do RCU GP kthread self-wakeup from softirq and interrupt
+    - media: uvcvideo: Avoid NULL pointer dereference at the end of streaming
+    - drm/radeon/evergreen_cs: fix missing break in switch statement
+    - KVM: nVMX: Sign extend displacements of VMX instr's mem operands
+    - KVM: nVMX: Ignore limit checks on VMX instructions using flat segments
+    - KVM: X86: Fix residual mmio emulation request to userspace
+    - Linux 4.4.177
+
+  * sky2 ethernet card doesn't work after returning from suspend
+    (LP: #1807259) // sky2 ethernet card link not up after suspend
+    (LP: #1809843) // Xenial update: 4.4.177 upstream stable release
+    (LP: #1822271)
+    - sky2: Disable MSI on Dell Inspiron 1545 and Gateway P-79
+
+  * [CONFIG] please enable highdpi font FONT_TER16x32 (LP: #1819881)
+    - lib/fonts/Kconfig: keep non-Sparc fonts listed together
+    - Fonts: New Terminus large console font
+    - [Config]: enable highdpi Terminus 16x32 font support
+
+  * Hard lockup in 2 CPUs due to deadlock in cpu_stoppers (LP: #1821259)
+    - stop_machine, sched: Fix migrate_swap() vs. active_balance() deadlock
+    - stop_machine: Disable preemption when waking two stopper threads
+    - stop_machine: Disable preemption after queueing stopper threads
+    - stop_machine: Atomically queue and wake stopper threads
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Tue, 02 Apr 2019 23:03:42 -0400
+
+linux (4.4.0-145.171) xenial; urgency=medium
+
+  * linux: 4.4.0-145.171 -proposed tracker (LP: #1821724)
+
+  * linux-generic should depend on linux-base >=4.1 (LP: #1820419)
+    - [Packaging] Fix linux-base dependency
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 26 Mar 2019 13:27:29 +0100
+
+linux (4.4.0-144.170) xenial; urgency=medium
+
+  * linux: 4.4.0-144.170 -proposed tracker (LP: #1819660)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+    - [Packaging] resync retpoline extraction
+
+  * C++ demangling support missing from perf (LP: #1396654)
+    - [Packaging] fix a mistype
+
+  * CVE-2019-9213
+    - mm: enforce min addr even if capable() in expand_downwards()
+
+  * CVE-2019-3460
+    - Bluetooth: Check L2CAP option sizes returned from l2cap_get_conf_opt
+
+  * Xenial update: 4.4.176 upstream stable release (LP: #1818815)
+    - net: fix IPv6 prefix route residue
+    - vsock: cope with memory allocation failure at socket creation time
+    - hwmon: (lm80) Fix missing unlock on error in set_fan_div()
+    - net: Fix for_each_netdev_feature on Big endian
+    - net: Add header for usage of fls64()
+    - tcp: tcp_v4_err() should be more careful
+    - net: Do not allocate page fragments that are not skb aligned
+    - tcp: clear icsk_backoff in tcp_write_queue_purge()
+    - vxlan: test dev->flags & IFF_UP before calling netif_rx()
+    - net: stmmac: Fix a race in EEE enable callback
+    - net: ipv4: use a dedicated counter for icmp_v4 redirect packets
+    - x86: livepatch: Treat R_X86_64_PLT32 as R_X86_64_PC32
+    - mfd: as3722: Handle interrupts on suspend
+    - mfd: as3722: Mark PM functions as __maybe_unused
+    - net/x25: do not hold the cpu too long in x25_new_lci()
+    - mISDN: fix a race in dev_expire_timer()
+    - ax25: fix possible use-after-free
+    - Linux 4.4.176
+
+  * sky2 ethernet card don't work after returning from suspension
+    (LP: #1798921) // Xenial update: 4.4.176 upstream stable release
+    (LP: #1818815)
+    - sky2: Increase D3 delay again
+
+  * Xenial update: 4.4.175 upstream stable release (LP: #1818813)
+    - drm/bufs: Fix Spectre v1 vulnerability
+    - staging: iio: adc: ad7280a: handle error from __ad7280_read32()
+    - ASoC: Intel: mrfld: fix uninitialized variable access
+    - scsi: lpfc: Correct LCB RJT handling
+    - ARM: 8808/1: kexec:offline panic_smp_self_stop CPU
+    - dlm: Don't swamp the CPU with callbacks queued during recovery
+    - x86/PCI: Fix Broadcom CNB20LE unintended sign extension (redux)
+    - powerpc/pseries: add of_node_put() in dlpar_detach_node()
+    - serial: fsl_lpuart: clear parity enable bit when disable parity
+    - ptp: check gettime64 return code in PTP_SYS_OFFSET ioctl
+    - staging:iio:ad2s90: Make probe handle spi_setup failure
+    - staging: iio: ad7780: update voltage on read
+    - ARM: OMAP2+: hwmod: Fix some section annotations
+    - modpost: validate symbol names also in find_elf_symbol
+    - perf tools: Add Hygon Dhyana support
+    - soc/tegra: Don't leak device tree node reference
+    - f2fs: move dir data flush to write checkpoint process
+    - f2fs: fix wrong return value of f2fs_acl_create
+    - sunvdc: Do not spin in an infinite loop when vio_ldc_send() returns EAGAIN
+    - nfsd4: fix crash on writing v4_end_grace before nfsd startup
+    - arm64: ftrace: don't adjust the LR value
+    - ARM: dts: mmp2: fix TWSI2
+    - x86/fpu: Add might_fault() to user_insn()
+    - media: DaVinci-VPBE: fix error handling in vpbe_initialize()
+    - smack: fix access permissions for keyring
+    - usb: hub: delay hub autosuspend if USB3 port is still link training
+    - timekeeping: Use proper seqcount initializer
+    - ARM: dts: Fix OMAP4430 SDP Ethernet startup
+    - mips: bpf: fix encoding bug for mm_srlv32_op
+    - iommu/arm-smmu-v3: Use explicit mb() when moving cons pointer
+    - sata_rcar: fix deferred probing
+    - clk: imx6sl: ensure MMDC CH0 handshake is bypassed
+    - cpuidle: big.LITTLE: fix refcount leak
+    - i2c-axxia: check for error conditions first
+    - udf: Fix BUG on corrupted inode
+    - ARM: pxa: avoid section mismatch warning
+    - ASoC: fsl: Fix SND_SOC_EUKREA_TLV320 build error on i.MX8M
+    - memstick: Prevent memstick host from getting runtime suspended during card
+      detection
+    - tty: serial: samsung: Properly set flags in autoCTS mode
+    - arm64: KVM: Skip MMIO insn after emulation
+    - powerpc/uaccess: fix warning/error with access_ok()
+    - mac80211: fix radiotap vendor presence bitmap handling
+    - xfrm6_tunnel: Fix spi check in __xfrm6_tunnel_alloc_spi
+    - Bluetooth: Fix unnecessary error message for HCI request completion
+    - cw1200: Fix concurrency use-after-free bugs in cw1200_hw_scan()
+    - drbd: narrow rcu_read_lock in drbd_sync_handshake
+    - drbd: disconnect, if the wrong UUIDs are attached on a connected peer
+    - drbd: skip spurious timeout (ping-timeo) when failing promote
+    - drbd: Avoid Clang warning about pointless switch statment
+    - video: clps711x-fb: release disp device node in probe()
+    - fbdev: fbmem: behave better with small rotated displays and many CPUs
+    - fbdev: fbcon: Fix unregister crash when more than one framebuffer
+    - KVM: x86: svm: report MSR_IA32_MCG_EXT_CTL as unsupported
+    - NFS: nfs_compare_mount_options always compare auth flavors.
+    - hwmon: (lm80) fix a missing check of the status of SMBus read
+    - hwmon: (lm80) fix a missing check of bus read in lm80 probe
+    - seq_buf: Make seq_buf_puts() null-terminate the buffer
+    - crypto: ux500 - Use proper enum in cryp_set_dma_transfer
+    - crypto: ux500 - Use proper enum in hash_set_dma_transfer
+    - cifs: check ntwrk_buf_start for NULL before dereferencing it
+    - um: Avoid marking pages with "changed protection"
+    - niu: fix missing checks of niu_pci_eeprom_read
+    - scripts/decode_stacktrace: only strip base path when a prefix of the path
+    - ocfs2: don't clear bh uptodate for block read
+    - isdn: hisax: hfc_pci: Fix a possible concurrency use-after-free bug in
+      HFCPCI_l1hw()
+    - gdrom: fix a memory leak bug
+    - block/swim3: Fix -EBUSY error when re-opening device after unmount
+    - HID: lenovo: Add checks to fix of_led_classdev_register
+    - kernel/hung_task.c: break RCU locks based on jiffies
+    - fs/epoll: drop ovflist branch prediction
+    - exec: load_script: don't blindly truncate shebang string
+    - thermal: hwmon: inline helpers when CONFIG_THERMAL_HWMON is not set
+    - test_hexdump: use memcpy instead of strncpy
+    - tipc: use destination length for copy string
+    - string: drop __must_check from strscpy() and restore strscpy() usages in
+      cgroup
+    - dccp: fool proof ccid_hc_[rt]x_parse_options()
+    - enic: fix checksum validation for IPv6
+    - net: dp83640: expire old TX-skb
+    - skge: potential memory corruption in skge_get_regs()
+    - net: systemport: Fix WoL with password after deep sleep
+    - net: dsa: slave: Don't propagate flag changes on down slave interfaces
+    - ALSA: compress: Fix stop handling on compressed capture streams
+    - ALSA: hda - Serialize codec registrations
+    - fuse: call pipe_buf_release() under pipe lock
+    - fuse: decrement NR_WRITEBACK_TEMP on the right page
+    - fuse: handle zero sized retrieve correctly
+    - dmaengine: imx-dma: fix wrong callback invoke
+    - usb: phy: am335x: fix race condition in _probe
+    - usb: gadget: udc: net2272: Fix bitwise and boolean operations
+    - perf/x86/intel/uncore: Add Node ID mask
+    - x86/MCE: Initialize mce.bank in the case of a fatal error in
+      mce_no_way_out()
+    - perf/core: Don't WARN() for impossible ring-buffer sizes
+    - perf tests evsel-tp-sched: Fix bitwise operator
+    - mtd: rawnand: gpmi: fix MX28 bus master lockup problem
+    - signal: Always notice exiting tasks
+    - signal: Better detection of synchronous signals
+    - misc: vexpress: Off by one in vexpress_syscfg_exec()
+    - debugfs: fix debugfs_rename parameter checking
+    - mips: cm: reprime error cause
+    - MIPS: OCTEON: don't set octeon_dma_bar_type if PCI is disabled
+    - MIPS: VDSO: Include $(ccflags-vdso) in o32,n32 .lds builds
+    - ARM: iop32x/n2100: fix PCI IRQ mapping
+    - mac80211: ensure that mgmt tx skbs have tailroom for encryption
+    - drm/modes: Prevent division by zero htotal
+    - drm/vmwgfx: Fix setting of dma masks
+    - drm/vmwgfx: Return error code from vmw_execbuf_copy_fence_user
+    - HID: debug: fix the ring buffer implementation
+    - NFC: nxp-nci: Include unaligned.h instead of access_ok.h
+    - Revert "cifs: In Kconfig CONFIG_CIFS_POSIX needs depends on legacy (insecure
+      cifs)"
+    - Revert "UBUNTU: [Config] Remove CONFIG_CIFS_POSIX=y"
+    - libceph: avoid KEEPALIVE_PENDING races in ceph_con_keepalive()
+    - xfrm: refine validation of template and selector families
+    - batman-adv: Avoid WARN on net_device without parent in netns
+    - batman-adv: Force mac header to start of data on xmit
+    - Revert "exec: load_script: don't blindly truncate shebang string"
+    - uapi/if_ether.h: prevent redefinition of struct ethhdr
+    - ARM: dts: da850-evm: Correct the sound card name
+    - ARM: dts: kirkwood: Fix polarity of GPIO fan lines
+    - gpio: pl061: handle failed allocations
+    - cifs: Limit memory used by lock request calls to a page
+    - Documentation/network: reword kernel version reference
+    - Revert "Input: elan_i2c - add ACPI ID for touchpad in ASUS Aspire F5-573G"
+    - Input: elan_i2c - add ACPI ID for touchpad in Lenovo V330-15ISK
+    - perf/core: Fix impossible ring-buffer sizes warning
+    - ALSA: hda - Add quirk for HP EliteBook 840 G5
+    - ALSA: usb-audio: Fix implicit fb endpoint setup by quirk
+    - Input: bma150 - register input device after setting private data
+    - Input: elantech - enable 3rd button support on Fujitsu CELSIUS H780
+    - alpha: fix page fault handling for r16-r18 targets
+    - alpha: Fix Eiger NR_IRQS to 128
+    - tracing/uprobes: Fix output for multiple string arguments
+    - x86/platform/UV: Use efi_runtime_lock to serialise BIOS calls
+    - signal: Restore the stop PTRACE_EVENT_EXIT
+    - x86/a.out: Clear the dump structure initially
+    - dm thin: fix bug where bio that overwrites thin block ignores FUA
+    - smsc95xx: Use skb_cow_head to deal with cloned skbs
+    - ch9200: use skb_cow_head() to deal with cloned skbs
+    - kaweth: use skb_cow_head() to deal with cloned skbs
+    - usb: dwc2: Remove unnecessary kfree
+    - pinctrl: msm: fix gpio-hog related boot issues
+    - uapi/if_ether.h: move __UAPI_DEF_ETHHDR libc define
+    - Linux 4.4.175
+
+  * Xenial update: 4.4.174 upstream stable release (LP: #1818806)
+    - inet: frags: change inet_frags_init_net() return value
+    - inet: frags: add a pointer to struct netns_frags
+    - inet: frags: refactor ipfrag_init()
+    - inet: frags: refactor ipv6_frag_init()
+    - inet: frags: refactor lowpan_net_frag_init()
+    - rhashtable: add rhashtable_lookup_get_insert_key()
+    - rhashtable: Add rhashtable_lookup()
+    - rhashtable: add schedule points
+    - inet: frags: use rhashtables for reassembly units
+    - net: ieee802154: 6lowpan: fix frag reassembly
+    - ipfrag: really prevent allocation on netns exit
+    - inet: frags: remove some helpers
+    - inet: frags: get rif of inet_frag_evicting()
+    - inet: frags: remove inet_frag_maybe_warn_overflow()
+    - inet: frags: break the 2GB limit for frags storage
+    - inet: frags: do not clone skb in ip_expire()
+    - ipv6: frags: rewrite ip6_expire_frag_queue()
+    - rhashtable: reorganize struct rhashtable layout
+    - inet: frags: reorganize struct netns_frags
+    - inet: frags: get rid of ipfrag_skb_cb/FRAG_CB
+    - inet: frags: fix ip6frag_low_thresh boundary
+    - ip: discard IPv4 datagrams with overlapping segments.
+    - net: modify skb_rbtree_purge to return the truesize of all purged skbs.
+    - ipv6: defrag: drop non-last frags smaller than min mtu
+    - net: pskb_trim_rcsum() and CHECKSUM_COMPLETE are friends
+    - ip: use rb trees for IP frag queue.
+    - ip: add helpers to process in-order fragments faster.
+    - ip: process in-order fragments efficiently
+    - ip: frags: fix crash in ip_do_fragment()
+    - ipv4: frags: precedence bug in ip_expire()
+    - inet: frags: better deal with smp races
+    - net: fix pskb_trim_rcsum_slow() with odd trim offset
+    - net: ipv4: do not handle duplicate fragments as overlapping
+    - rcu: Force boolean subscript for expedited stall warnings
+    - Linux 4.4.174
+
+  * Xenial update: 4.4.173 upstream stable release (LP: #1818803)
+    - net: Fix usage of pskb_trim_rcsum
+    - openvswitch: Avoid OOB read when parsing flow nlattrs
+    - net: ipv4: Fix memory leak in network namespace dismantle
+    - net_sched: refetch skb protocol for each filter
+    - net: bridge: Fix ethernet header pointer before check skb forwardable
+    - USB: serial: simple: add Motorola Tetra TPG2200 device id
+    - USB: serial: pl2303: add new PID to support PL2303TB
+    - ASoC: atom: fix a missing check of snd_pcm_lib_malloc_pages
+    - ARC: perf: map generic branches to correct hardware condition
+    - s390/early: improve machine detection
+    - s390/smp: fix CPU hotplug deadlock with CPU rescan
+    - char/mwave: fix potential Spectre v1 vulnerability
+    - staging: rtl8188eu: Add device code for D-Link DWA-121 rev B1
+    - tty: Handle problem if line discipline does not have receive_buf
+    - tty/n_hdlc: fix __might_sleep warning
+    - CIFS: Fix possible hang during async MTU reads and writes
+    - Input: xpad - add support for SteelSeries Stratus Duo
+    - KVM: x86: Fix single-step debugging
+    - x86/kaslr: Fix incorrect i8254 outb() parameters
+    - can: dev: __can_get_echo_skb(): fix bogous check for non-existing skb by
+      removing it
+    - can: bcm: check timer values before ktime conversion
+    - vt: invoke notifier on screen size change
+    - perf unwind: Unwind with libdw doesn't take symfs into account
+    - perf unwind: Take pgoff into account when reporting elf to libdwfl
+    - irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size
+    - arm64: mm: remove page_mapping check in __sync_icache_dcache
+    - f2fs: read page index before freeing
+    - Revert "loop: Fix double mutex_unlock(&loop_ctl_mutex) in
+      loop_control_ioctl()"
+    - Revert "loop: Get rid of loop_index_mutex"
+    - Revert "loop: Fold __loop_release into loop_release"
+    - s390/smp: Fix calling smp_call_ipl_cpu() from ipl CPU
+    - fs: add the fsnotify call to vfs_iter_write
+    - ipv6: Consider sk_bound_dev_if when binding a socket to an address
+    - l2tp: copy 4 more bytes to linear part if necessary
+    - net/mlx4_core: Add masking for a few queries on HCA caps
+    - netrom: switch to sock timer API
+    - net/rose: fix NULL ax25_cb kernel panic
+    - ucc_geth: Reset BQL queue when stopping device
+    - l2tp: remove l2specific_len dependency in l2tp_core
+    - l2tp: fix reading optional fields of L2TPv3
+    - CIFS: Do not count -ENODATA as failure for query directory
+    - fs/dcache: Fix incorrect nr_dentry_unused accounting in shrink_dcache_sb()
+    - ARM: cns3xxx: Fix writing to wrong PCI config registers after alignment
+    - arm64: hyp-stub: Forbid kprobing of the hyp-stub
+    - gfs2: Revert "Fix loop in gfs2_rbm_find"
+    - platform/x86: asus-nb-wmi: Map 0x35 to KEY_SCREENLOCK
+    - platform/x86: asus-nb-wmi: Drop mapping of 0x33 and 0x34 scan codes
+    - mmc: sdhci-iproc: handle mmc_of_parse() errors during probe
+    - kernel/exit.c: release ptraced tasks before zap_pid_ns_processes
+    - mm, oom: fix use-after-free in oom_kill_process
+    - cifs: Always resolve hostname before reconnecting
+    - drivers: core: Remove glue dirs from sysfs earlier
+    - mm: migrate: don't rely on __PageMovable() of newpage after unlocking it
+    - fs: don't scan the inode cache before SB_BORN is set
+    - Linux 4.4.173
+
+  * Xenial update: 4.4.172 upstream stable release (LP: #1818797)
+    - tty/ldsem: Wake up readers after timed out down_write()
+    - can: gw: ensure DLC boundaries after CAN frame modification
+    - f2fs: clean up argument of recover_data
+    - f2fs: cover more area with nat_tree_lock
+    - f2fs: move sanity checking of cp into get_valid_checkpoint
+    - f2fs: fix to convert inline directory correctly
+    - f2fs: give -EINVAL for norecovery and rw mount
+    - f2fs: remove an obsolete variable
+    - f2fs: factor out fsync inode entry operations
+    - f2fs: fix inode cache leak
+    - f2fs: fix to avoid reading out encrypted data in page cache
+    - f2fs: not allow to write illegal blkaddr
+    - f2fs: avoid unneeded loop in build_sit_entries
+    - f2fs: use crc and cp version to determine roll-forward recovery
+    - f2fs: introduce get_checkpoint_version for cleanup
+    - f2fs: put directory inodes before checkpoint in roll-forward recovery
+    - f2fs: fix to determine start_cp_addr by sbi->cur_cp_pack
+    - f2fs: detect wrong layout
+    - f2fs: free meta pages if sanity check for ckpt is failed
+    - f2fs: fix race condition in between free nid allocator/initializer
+    - f2fs: return error during fill_super
+    - f2fs: check blkaddr more accuratly before issue a bio
+    - f2fs: sanity check on sit entry
+    - f2fs: enhance sanity_check_raw_super() to avoid potential overflow
+    - f2fs: clean up with is_valid_blkaddr()
+    - f2fs: introduce and spread verify_blkaddr
+    - f2fs: fix to do sanity check with secs_per_zone
+    - f2fs: fix to do sanity check with user_block_count
+    - f2fs: Add sanity_check_inode() function
+    - f2fs: fix to do sanity check with node footer and iblocks
+    - f2fs: fix to do sanity check with reserved blkaddr of inline inode
+    - f2fs: fix to do sanity check with block address in main area
+    - f2fs: fix to do sanity check with block address in main area v2
+    - f2fs: fix to do sanity check with cp_pack_start_sum
+    - f2fs: fix invalid memory access
+    - f2fs: fix missing up_read
+    - f2fs: fix validation of the block count in sanity_check_raw_super
+    - media: em28xx: Fix misplaced reset of dev->v4l::field_count
+    - arm64/kvm: consistently handle host HCR_EL2 flags
+    - arm64: Don't trap host pointer auth use to EL2
+    - ipv6: fix kernel-infoleak in ipv6_local_error()
+    - net: bridge: fix a bug on using a neighbour cache entry without checking its
+      state
+    - packet: Do not leak dev refcounts on error exit
+    - ip: on queued skb use skb_header_pointer instead of pskb_may_pull
+    - crypto: authencesn - Avoid twice completion call in decrypt path
+    - crypto: authenc - fix parsing key with misaligned rta_len
+    - btrfs: wait on ordered extents on abort cleanup
+    - Yama: Check for pid death before checking ancestry
+    - scsi: sd: Fix cache_type_store()
+    - mips: fix n32 compat_ipc_parse_version
+    - mfd: tps6586x: Handle interrupts on suspend
+    - Disable MSI also when pcie-octeon.pcie_disable on
+    - omap2fb: Fix stack memory disclosure
+    - media: vivid: fix error handling of kthread_run
+    - media: vivid: set min width/height to a value > 0
+    - LSM: Check for NULL cred-security on free
+    - media: vb2: vb2_mmap: move lock up
+    - sunrpc: handle ENOMEM in rpcb_getport_async
+    - selinux: fix GPF on invalid policy
+    - sctp: allocate sctp_sockaddr_entry with kzalloc
+    - tipc: fix uninit-value in tipc_nl_compat_link_reset_stats
+    - tipc: fix uninit-value in tipc_nl_compat_bearer_enable
+    - tipc: fix uninit-value in tipc_nl_compat_link_set
+    - tipc: fix uninit-value in tipc_nl_compat_name_table_dump
+    - tipc: fix uninit-value in tipc_nl_compat_doit
+    - block/loop: Use global lock for ioctl() operation.
+    - loop: Fold __loop_release into loop_release
+    - loop: Get rid of loop_index_mutex
+    - loop: Fix double mutex_unlock(&loop_ctl_mutex) in loop_control_ioctl()
+    - drm/fb-helper: Ignore the value of fb_var_screeninfo.pixclock
+    - media: vb2: be sure to unlock mutex on errors
+    - r8169: Add support for new Realtek Ethernet
+    - ipv6: Consider sk_bound_dev_if when binding a socket to a v4 mapped address
+    - ipv6: Take rcu_read_lock in __inet6_bind for mapped addresses
+    - platform/x86: asus-wmi: Tell the EC the OS will handle the display off
+      hotkey
+    - e1000e: allow non-monotonic SYSTIM readings
+    - writeback: don't decrement wb->refcnt if !wb->bdi
+    - MIPS: SiByte: Enable swiotlb for SWARM, LittleSur and BigSur
+    - arm64: perf: set suppress_bind_attrs flag to true
+    - jffs2: Fix use of uninitialized delayed_work, lockdep breakage
+    - pstore/ram: Do not treat empty buffers as valid
+    - powerpc/pseries/cpuidle: Fix preempt warning
+    - media: firewire: Fix app_info parameter type in avc_ca{,_app}_info
+    - net: call sk_dst_reset when set SO_DONTROUTE
+    - scsi: target: use consistent left-aligned ASCII INQUIRY data
+    - clk: imx6q: reset exclusive gates on init
+    - kconfig: fix file name and line number of warn_ignored_character()
+    - kconfig: fix memory leak when EOF is encountered in quotation
+    - mmc: atmel-mci: do not assume idle after atmci_request_end
+    - perf intel-pt: Fix error with config term "pt=0"
+    - perf svghelper: Fix unchecked usage of strncpy()
+    - perf parse-events: Fix unchecked usage of strncpy()
+    - dm kcopyd: Fix bug causing workqueue stalls
+    - dm snapshot: Fix excessive memory usage and workqueue stalls
+    - ALSA: bebob: fix model-id of unit for Apogee Ensemble
+    - sysfs: Disable lockdep for driver bind/unbind files
+    - scsi: megaraid: fix out-of-bound array accesses
+    - ocfs2: fix panic due to unrecovered local alloc
+    - mm/page-writeback.c: don't break integrity writeback on ->writepage() error
+    - mm, proc: be more verbose about unstable VMA flags in /proc/<pid>/smaps
+    - net: speed up skb_rbtree_purge()
+    - ipmi:ssif: Fix handling of multi-part return messages
+    - Linux 4.4.172
+
+  * Xenial update: 4.4.171 upstream stable release (LP: #1818237)
+    - ALSA: hda/realtek - Disable headset Mic VREF for headset mode of ALC225
+    - btrfs: cleanup, stop casting for extent_map->lookup everywhere
+    - btrfs: Enhance chunk validation check
+    - Btrfs: add validadtion checks for chunk loading
+    - Btrfs: check inconsistence between chunk and block group
+    - Btrfs: fix em leak in find_first_block_group
+    - Btrfs: detect corruption when non-root leaf has zero item
+    - Btrfs: check btree node's nritems
+    - Btrfs: fix BUG_ON in btrfs_mark_buffer_dirty
+    - Btrfs: memset to avoid stale content in btree node block
+    - Btrfs: improve check_node to avoid reading corrupted nodes
+    - Btrfs: kill BUG_ON in run_delayed_tree_ref
+    - Btrfs: memset to avoid stale content in btree leaf
+    - Btrfs: fix emptiness check for dirtied extent buffers at check_leaf()
+    - btrfs: struct-funcs, constify readers
+    - btrfs: Refactor check_leaf function for later expansion
+    - btrfs: Check if item pointer overlaps with the item itself
+    - btrfs: Add sanity check for EXTENT_DATA when reading out leaf
+    - btrfs: Add checker for EXTENT_CSUM
+    - btrfs: Move leaf and node validation checker to tree-checker.c
+    - btrfs: tree-checker: Enhance btrfs_check_node output
+    - btrfs: tree-checker: Fix false panic for sanity test
+    - btrfs: tree-checker: Add checker for dir item
+    - btrfs: tree-checker: use %zu format string for size_t
+    - btrfs: tree-check: reduce stack consumption in check_dir_item
+    - btrfs: tree-checker: Verify block_group_item
+    - btrfs: tree-checker: Detect invalid and empty essential trees
+    - btrfs: validate type when reading a chunk
+    - btrfs: Check that each block group has corresponding chunk at mount time
+    - btrfs: Verify that every chunk has corresponding block group at mount time
+    - btrfs: tree-checker: Check level for leaves and nodes
+    - btrfs: tree-checker: Fix misleading group system information
+    - CIFS: Do not hide EINTR after sending network packets
+    - cifs: Fix potential OOB access of lock element array
+    - usb: cdc-acm: send ZLP for Telit 3G Intel based modems
+    - USB: storage: don't insert sane sense for SPC3+ when bad sense specified
+    - USB: storage: add quirk for SMI SM3350
+    - USB: Add USB_QUIRK_DELAY_CTRL_MSG quirk for Corsair K70 RGB
+    - slab: alien caches must not be initialized if the allocation of the alien
+      cache failed
+    - PCI: altera: Fix altera_pcie_link_is_up()
+    - PCI: altera: Reorder read/write functions
+    - PCI: altera: Check link status before retrain link
+    - PCI: altera: Poll for link up status after retraining the link
+    - PCI: altera: Poll for link training status after retraining the link
+    - PCI: altera: Rework config accessors for use without a struct pci_bus
+    - PCI: altera: Move retrain from fixup to altera_pcie_host_init()
+    - ACPI: power: Skip duplicate power resource references in _PRx
+    - i2c: dev: prevent adapter retries and timeout being set as minus value
+    - crypto: cts - fix crash on short inputs
+    - ext4: fix a potential fiemap/page fault deadlock w/ inline_data
+    - sunrpc: use-after-free in svc_process_common()
+    - Linux 4.4.171
+
+  * [Packaging] Allow overlay of config annotations (LP: #1752072)
+    - [Packaging] config-check: Add an include directive
+
+  * CVE-2018-9517
+    - l2tp: pass tunnel pointer to ->session_create()
+
+  * squashfs hardening (LP: #1816756)
+    - squashfs metadata 2: electric boogaloo
+    - Squashfs: Compute expected length from inode size rather than block length
+
+  * Update ENA driver to version 2.0.3K (LP: #1816806)
+    - net: ena: update driver version from 2.0.2 to 2.0.3
+    - net: ena: fix race between link up and device initalization
+    - net: ena: fix crash during failed resume from hibernation
+
+  * bnxt_en_po: TX timed out triggering Netdev Watchdog Timer (LP: #1814095)
+    - SAUCE: bnxt_en_bpo: Fix TX timeout during netpoll
+
+  * CVE-2019-3459
+    - Bluetooth: Verify that l2cap_get_conf_opt provides large enough buffer
+
+  * CVE-2019-7222
+    - KVM: x86: work around leak of uninitialized stack contents (CVE-2019-7222)
+
+  * CVE-2019-7221
+    - KVM: nVMX: unconditionally cancel preemption timer in free_nested
+      (CVE-2019-7221)
+
+  * CVE-2019-6974
+    - kvm: fix kvm_ioctl_create_device() reference counting (CVE-2019-6974)
+
+  * Regular D-state processes impacting LXD containers (LP: #1817628)
+    - mm: do not stall register_shrinker()
+
+  * libsas disks can have non-unique by-path names (LP: #1817784)
+    - scsi: libsas: Fix rphy phy_identifier for PHYs with end devices attached
+
+  * Hard lockups due to unrestricted lapic timer delay (LP: #1817918)
+    - KVM: x86: move nsec_to_cycles from x86.c to x86.h
+    - KVM: LAPIC: cap __delay at lapic_timer_advance_ns
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 14 Mar 2019 10:01:49 +0100
+
+linux (4.4.0-143.169) xenial; urgency=medium
+
+  * linux: 4.4.0-143.169 -proposed tracker (LP: #1814647)
+
+  * x86/kvm: Backport fixup and missing commits (LP: #1811646)
+    - KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID
+    - kvm: nVMX: VMCLEAR an active shadow VMCS after last use
+    - X86/nVMX: Properly set spec_ctrl and pred_cmd before merging MSRs
+    - KVM/VMX: Optimize vmx_vcpu_run() and svm_vcpu_run() by marking the RDMSR
+      path as unlikely()
+    - kvm: x86: IA32_ARCH_CAPABILITIES is always supported
+    - KVM: SVM: Add MSR-based feature support for serializing LFENCE
+    - KVM: X86: Allow userspace to define the microcode version
+    - KVM: x86: SVM: Call x86_spec_ctrl_set_guest/host() with interrupts disabled
+    - KVM: VMX: fixes for vmentry_l1d_flush module parameter
+    - kvm: svm: Ensure an IBPB on all affected CPUs when freeing a vmcb
+    - kvm: vmx: Scrub hardware GPRs at VM-exit
+    - SAUCE: [Fix] x86/KVM/VMX: Add L1D flush logic
+    - SAUCE: KVM: Move code fragments, cleanup and re-indent
+
+  * linux-buildinfo: pull out ABI information into its own package
+    (LP: #1806380)
+    - [Packaging] limit preparation to linux-libc-dev in headers
+    - [Packaging] commonise debhelper invocation
+    - [Packaging] ABI -- accumulate abi information at the end of the build
+    - [Packaging] buildinfo -- add basic build information
+    - [Packaging] buildinfo -- add firmware information to the flavour ABI
+    - [Packaging] buildinfo -- add compiler information to the flavour ABI
+    - [Packaging] buildinfo -- add buildinfo support to getabis
+    - [Config] buildinfo -- add retpoline version markers
+    - [Packaging] getabis -- handle all known package combinations
+    - [Packaging] getabis -- support parsing a simple version
+
+  * signing: only install a signed kernel (LP: #1764794)
+    - [Packaging] update to Debian like control scripts
+    - [Packaging] switch to triggers for postinst.d postrm.d handling
+    - [Packaging] signing -- switch to raw-signing tarballs
+    - [Packaging] signing -- switch to linux-image as signed when available
+    - [Packaging] printenv -- add signing options
+    - [Packaging] fix invocation of header postinst hooks
+    - [Packaging] signing -- add support for signing Opal kernel binaries
+    - [Debian] Use src_pkg_name when constructing udeb control files
+    - [Debian] Dynamically determine linux udebs package name
+    - [Packaging] handle both linux-lts* and linux-hwe* as backports
+    - [Config] linux-source-* is in the primary linux namespace
+    - [Packaging] lookup the upstream tag
+    - [Packaging] zfs/spl -- enhance provides information
+    - [Packaging] switch up to debhelper 9
+    - [Packaging] autopkgtest -- disable d-i when dropping flavours
+    - [debian] support for ship_extras_package=false
+    - [Debian] do_common_tools should always be on
+    - [debian] do not force do_tools_common
+    - [Packaging] Add linux-tools-host package for VM host tools
+    - [Packaging] signing should be conditional
+    - [Packaging] skip cloud tools packaging when not building package
+    - [Packaging] add acpidbg
+    - [debian] prep linux-libc-dev only if do_libc_dev_package=true
+    - [Packaging] Only install cloud init files when do_tools_common=true
+
+  * Redpine: Driver crash with network-manager 1.10 and above (LP: #1813869)
+    - SAUCE: Redpine: enhancement for MAC spoofing to avoid kernel crash
+
+  * Guests using IBRS incur a large performance penalty (LP: #1764956)
+    - SAUCE: Restore the IBRS host state on VMEXIT
+
+  * Xenial update: 4.4.170 upstream stable release (LP: #1811647)
+    - USB: hso: Fix OOB memory access in hso_probe/hso_get_config_data
+    - xhci: Don't prevent USB2 bus suspend in state check intended for USB3 only
+    - USB: serial: option: add GosunCn ZTE WeLink ME3630
+    - USB: serial: option: add HP lt4132
+    - USB: serial: option: add Simcom SIM7500/SIM7600 (MBIM mode)
+    - USB: serial: option: add Fibocom NL668 series
+    - USB: serial: option: add Telit LN940 series
+    - mmc: core: Reset HPI enabled state during re-init and in case of errors
+    - mmc: omap_hsmmc: fix DMA API warning
+    - gpio: max7301: fix driver for use with CONFIG_VMAP_STACK
+    - Drivers: hv: vmbus: Return -EINVAL for the sys files for unopened channels
+    - x86/mtrr: Don't copy uninitialized gentry fields back to userspace
+    - drm/ioctl: Fix Spectre v1 vulnerabilities
+    - ip6mr: Fix potential Spectre v1 vulnerability
+    - ipv4: Fix potential Spectre v1 vulnerability
+    - ax25: fix a use-after-free in ax25_fillin_cb()
+    - ibmveth: fix DMA unmap error in ibmveth_xmit_start error path
+    - ieee802154: lowpan_header_create check must check daddr
+    - ipv6: explicitly initialize udp6_addr in udp_sock_create6()
+    - isdn: fix kernel-infoleak in capi_unlocked_ioctl
+    - netrom: fix locking in nr_find_socket()
+    - packet: validate address length
+    - packet: validate address length if non-zero
+    - sctp: initialize sin6_flowinfo for ipv6 addrs in sctp_inet6addr_event
+    - vhost: make sure used idx is seen before log in vhost_add_used_n()
+    - VSOCK: Send reset control packet when socket is partially bound
+    - xen/netfront: tolerate frags with no data
+    - gro_cell: add napi_disable in gro_cells_destroy
+    - sock: Make sock->sk_stamp thread-safe
+    - ALSA: rme9652: Fix potential Spectre v1 vulnerability
+    - ALSA: emu10k1: Fix potential Spectre v1 vulnerabilities
+    - ALSA: pcm: Fix potential Spectre v1 vulnerability
+    - ALSA: emux: Fix potential Spectre v1 vulnerabilities
+    - ALSA: hda: add mute LED support for HP EliteBook 840 G4
+    - ALSA: hda/tegra: clear pending irq handlers
+    - USB: serial: pl2303: add ids for Hewlett-Packard HP POS pole displays
+    - USB: serial: option: add Fibocom NL678 series
+    - usb: r8a66597: Fix a possible concurrency use-after-free bug in
+      r8a66597_endpoint_disable()
+    - Input: elan_i2c - add ACPI ID for touchpad in ASUS Aspire F5-573G
+    - KVM: x86: Use jmp to invoke kvm_spurious_fault() from .fixup
+    - perf pmu: Suppress potential format-truncation warning
+    - ext4: fix possible use after free in ext4_quota_enable
+    - ext4: missing unlock/put_page() in ext4_try_to_write_inline_data()
+    - ext4: fix EXT4_IOC_GROUP_ADD ioctl
+    - ext4: force inode writes when nfsd calls commit_metadata()
+    - spi: bcm2835: Fix race on DMA termination
+    - spi: bcm2835: Fix book-keeping of DMA termination
+    - spi: bcm2835: Avoid finishing transfer prematurely in IRQ mode
+    - cdc-acm: fix abnormal DATA RX issue for Mediatek Preloader.
+    - media: vivid: free bitmap_cap when updating std/timings/etc.
+    - MIPS: Ensure pmd_present() returns false after pmd_mknotpresent()
+    - MIPS: Align kernel load address to 64KB
+    - CIFS: Fix error mapping for SMB2_LOCK command which caused OFD lock problem
+    - x86/kvm/vmx: do not use vm-exit instruction length for fast MMIO when
+      running nested
+    - spi: bcm2835: Unbreak the build of esoteric configs
+    - powerpc: Fix COFF zImage booting on old powermacs
+    - ARM: imx: update the cpu power up timing setting on i.mx6sx
+    - Input: restore EV_ABS ABS_RESERVED
+    - checkstack.pl: fix for aarch64
+    - xfrm: Fix bucket count reported to userspace
+    - scsi: bnx2fc: Fix NULL dereference in error handling
+    - Input: omap-keypad - fix idle configuration to not block SoC idle states
+    - scsi: zfcp: fix posting too many status read buffers leading to adapter
+      shutdown
+    - hwpoison, memory_hotplug: allow hwpoisoned pages to be offlined
+    - mm, devm_memremap_pages: mark devm_memremap_pages() EXPORT_SYMBOL_GPL
+    - mm, devm_memremap_pages: kill mapping "System RAM" support
+    - sunrpc: fix cache_head leak due to queued request
+    - sunrpc: use SVC_NET() in svcauth_gss_* functions
+    - crypto: x86/chacha20 - avoid sleeping with preemption disabled
+    - ALSA: cs46xx: Potential NULL dereference in probe
+    - ALSA: usb-audio: Avoid access before bLength check in build_audio_procunit()
+    - ALSA: usb-audio: Fix an out-of-bound read in create_composite_quirks
+    - dlm: fixed memory leaks after failed ls_remove_names allocation
+    - dlm: possible memory leak on error path in create_lkb()
+    - dlm: lost put_lkb on error path in receive_convert() and receive_unlock()
+    - dlm: memory leaks on error path in dlm_user_request()
+    - gfs2: Fix loop in gfs2_rbm_find
+    - b43: Fix error in cordic routine
+    - 9p/net: put a lower bound on msize
+    - iommu/vt-d: Handle domain agaw being less than iommu agaw
+    - ceph: don't update importing cap's mseq when handing cap export
+    - genwqe: Fix size check
+    - intel_th: msu: Fix an off-by-one in attribute store
+    - power: supply: olpc_battery: correct the temperature units
+    - Linux 4.4.170
+
+  * Xenial update: 4.4.169 upstream stable release (LP: #1811252)
+    - lib/interval_tree_test.c: make test options module parameters
+    - lib/interval_tree_test.c: allow full tree search
+    - lib/rbtree_test.c: make input module parameters
+    - lib/rbtree-test: lower default params
+    - lib/interval_tree_test.c: allow users to limit scope of endpoint
+    - timer/debug: Change /proc/timer_list from 0444 to 0400
+    - powerpc/boot: Fix random libfdt related build errors
+    - pinctrl: sunxi: a83t: Fix IRQ offset typo for PH11
+    - aio: fix spectre gadget in lookup_ioctx
+    - MMC: OMAP: fix broken MMC on OMAP15XX/OMAP5910/OMAP310
+    - tracing: Fix memory leak in set_trigger_filter()
+    - tracing: Fix memory leak of instance function hash filters
+    - powerpc/msi: Fix NULL pointer access in teardown code
+    - Revert "drm/rockchip: Allow driver to be shutdown on reboot/kexec"
+    - f2fs: fix a panic caused by NULL flush_cmd_control
+    - mac80211: don't WARN on bad WMM parameters from buggy APs
+    - mac80211: Fix condition validating WMM IE
+    - mac80211_hwsim: fix module init error paths for netlink
+    - scsi: libiscsi: Fix NULL pointer dereference in iscsi_eh_session_reset
+    - scsi: vmw_pscsi: Rearrange code to avoid multiple calls to free_irq during
+      unload
+    - x86/earlyprintk/efi: Fix infinite loop on some screen widths
+    - drm/msm: Grab a vblank reference when waiting for commit_done
+    - ARC: io.h: Implement reads{x}()/writes{x}()
+    - bonding: fix 802.3ad state sent to partner when unbinding slave
+    - SUNRPC: Fix a potential race in xprt_connect()
+    - sbus: char: add of_node_put()
+    - drivers/sbus/char: add of_node_put()
+    - drivers/tty: add missing of_node_put()
+    - ide: pmac: add of_node_put()
+    - clk: mmp: Off by one in mmp_clk_add()
+    - Input: omap-keypad - fix keyboard debounce configuration
+    - libata: whitelist all SAMSUNG MZ7KM* solid-state disks
+    - mv88e6060: disable hardware level MAC learning
+    - ARM: 8814/1: mm: improve/fix ARM v7_dma_inv_range() unaligned address
+      handling
+    - cifs: In Kconfig CONFIG_CIFS_POSIX needs depends on legacy (insecure cifs)
+    - [Config] Remove CONFIG_CIFS_POSIX=y
+    - i2c: axxia: properly handle master timeout
+    - i2c: scmi: Fix probe error on devices with an empty SMB0001 ACPI device node
+    - rtc: snvs: add a missing write sync
+    - rtc: snvs: Add timeouts to avoid kernel lockups
+    - ALSA: isa/wavefront: prevent some out of bound writes
+    - Linux 4.4.169
+
+  * Xenial update: 4.4.168 upstream stable release (LP: #1811080)
+    - ipv6: Check available headroom in ip6_xmit() even without options
+    - net: 8139cp: fix a BUG triggered by changing mtu with network traffic
+    - net: phy: don't allow __set_phy_supported to add unsupported modes
+    - net: Prevent invalid access to skb->prev in __qdisc_drop_all
+    - rtnetlink: ndo_dflt_fdb_dump() only work for ARPHRD_ETHER devices
+    - tcp: fix NULL ref in tail loss probe
+    - tun: forbid iface creation with rtnl ops
+    - neighbour: Avoid writing before skb->head in neigh_hh_output()
+    - ARM: OMAP2+: prm44xx: Fix section annotation on
+      omap44xx_prm_enable_io_wakeup
+    - ARM: OMAP1: ams-delta: Fix possible use of uninitialized field
+    - sysv: return 'err' instead of 0 in __sysv_write_inode
+    - s390/cpum_cf: Reject request for sampling in event initialization
+    - hwmon: (ina2xx) Fix current value calculation
+    - ASoC: dapm: Recalculate audio map forcely when card instantiated
+    - hwmon: (w83795) temp4_type has writable permission
+    - Btrfs: send, fix infinite loop due to directory rename dependencies
+    - ASoC: omap-mcpdm: Add pm_qos handling to avoid under/overruns with CPU_IDLE
+    - ASoC: omap-dmic: Add pm_qos handling to avoid overruns with CPU_IDLE
+    - exportfs: do not read dentry after free
+    - bpf: fix check of allowed specifiers in bpf_trace_printk
+    - USB: omap_udc: use devm_request_irq()
+    - USB: omap_udc: fix crashes on probe error and module removal
+    - USB: omap_udc: fix omap_udc_start() on 15xx machines
+    - USB: omap_udc: fix USB gadget functionality on Palm Tungsten E
+    - KVM: x86: fix empty-body warnings
+    - net: thunderx: fix NULL pointer dereference in nic_remove
+    - ixgbe: recognize 1000BaseLX SFP modules as 1Gbps
+    - net: hisilicon: remove unexpected free_netdev
+    - drm/ast: fixed reading monitor EDID not stable issue
+    - xen: xlate_mmu: add missing header to fix 'W=1' warning
+    - fscache: fix race between enablement and dropping of object
+    - fscache, cachefiles: remove redundant variable 'cache'
+    - ocfs2: fix deadlock caused by ocfs2_defrag_extent()
+    - hfs: do not free node before using
+    - hfsplus: do not free node before using
+    - debugobjects: avoid recursive calls with kmemleak
+    - ocfs2: fix potential use after free
+    - pstore: Convert console write to use ->write_buf
+    - ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO internal command
+    - KVM: nVMX: fix msr bitmaps to prevent L2 from accessing L0 x2APIC
+    - KVM: nVMX: mark vmcs12 pages dirty on L2 exit
+    - KVM: nVMX: Eliminate vmcs02 pool
+    - KVM: VMX: introduce alloc_loaded_vmcs
+    - KVM: VMX: make MSR bitmaps per-VCPU
+    - KVM/x86: Add IBPB support
+    - KVM/VMX: Allow direct access to MSR_IA32_SPEC_CTRL
+    - KVM/SVM: Allow direct access to MSR_IA32_SPEC_CTRL
+    - KVM/x86: Remove indirect MSR op calls from SPEC_CTRL
+    - x86/uaccess: Use __uaccess_begin_nospec() and uaccess_try_nospec
+    - KVM: SVM: Implement VIRT_SPEC_CTRL support for SSBD
+    - bpf: support 8-byte metafield access
+    - bpf/verifier: Add spi variable to check_stack_write()
+    - bpf/verifier: Pass instruction index to check_mem_access() and check_xadd()
+    - bpf: Prevent memory disambiguation attack
+    - wil6210: missing length check in wmi_set_ie
+    - mm/hugetlb.c: don't call region_abort if region_chg fails
+    - hugetlbfs: fix offset overflow in hugetlbfs mmap
+    - hugetlbfs: check for pgoff value overflow
+    - hugetlbfs: fix bug in pgoff overflow checking
+    - swiotlb: clean up reporting
+    - sr: pass down correctly sized SCSI sense buffer
+    - mm: remove write/force parameters from __get_user_pages_locked()
+    - mm: remove write/force parameters from __get_user_pages_unlocked()
+    - mm/nommu.c: Switch __get_user_pages_unlocked() to use __get_user_pages()
+    - mm: replace get_user_pages_unlocked() write/force parameters with gup_flags
+    - mm: replace get_user_pages_locked() write/force parameters with gup_flags
+    - mm: replace get_vaddr_frames() write/force parameters with gup_flags
+    - mm: replace get_user_pages() write/force parameters with gup_flags
+    - mm: replace __access_remote_vm() write parameter with gup_flags
+    - mm: replace access_remote_vm() write parameter with gup_flags
+    - proc: don't use FOLL_FORCE for reading cmdline and environment
+    - proc: do not access cmdline nor environ from file-backed areas
+    - media: dvb-frontends: fix i2c access helpers for KASAN
+    - matroxfb: fix size of memcpy
+    - staging: speakup: Replace strncpy with memcpy
+    - rocker: fix rocker_tlv_put_* functions for KASAN
+    - selftests: Move networking/timestamping from Documentation
+    - Linux 4.4.168
+
+  * kernel oops in bcache module (LP: #1793901)
+    - SAUCE: bcache: never writeback a discard operation
+
+  * Userspace break as a result of missing patch backport (LP: #1813873)
+    - tty: Don't hold ldisc lock in tty_reopen() if ldisc present
+
+  * CVE-2019-6133
+    - fork: record start_time late
+
+  * Crash on "ip link add foo type ipip" (LP: #1811803)
+    - SAUCE: fan: Fix NULL pointer dereference
+
+ -- Juerg Haefliger <juergh@canonical.com>  Wed, 06 Feb 2019 10:39:59 +0000
+
+linux (4.4.0-142.168) xenial; urgency=medium
+
+  * linux: 4.4.0-142.168 -proposed tracker (LP: #1811846)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * iptables connlimit allows more connections than the limit when using
+    multiple CPUs (LP: #1811094)
+    - netfilter: xt_connlimit: don't store address in the conn nodes
+    - SAUCE: netfilter: xt_connlimit: remove the 'addr' parameter in add_hlist()
+    - netfilter: nf_conncount: expose connection list interface
+    - netfilter: nf_conncount: Fix garbage collection with zones
+    - netfilter: nf_conncount: fix garbage collection confirm race
+    - netfilter: nf_conncount: don't skip eviction when age is negative
+
+  * CVE-2017-5715
+    - SAUCE: x86/speculation: Cleanup IBPB runtime control handling
+    - SAUCE: x86/speculation: Cleanup IBRS runtime control handling
+    - SAUCE: x86/speculation: Use x86_spec_ctrl_base in entry/exit code
+    - SAUCE: x86/speculation: Move RSB_CTXSW hunk
+
+  * Xenial update: 4.4.167 upstream stable release (LP: #1811077)
+    - media: em28xx: Fix use-after-free when disconnecting
+    - Revert "wlcore: Add missing PM call for
+      wlcore_cmd_wait_for_event_or_timeout()"
+    - rapidio/rionet: do not free skb before reading its length
+    - s390/qeth: fix length check in SNMP processing
+    - usbnet: ipheth: fix potential recvmsg bug and recvmsg bug 2
+    - kvm: mmu: Fix race in emulated page table writes
+    - xtensa: enable coprocessors that are being flushed
+    - xtensa: fix coprocessor context offset definitions
+    - Btrfs: ensure path name is null terminated at btrfs_control_ioctl
+    - ALSA: wss: Fix invalid snd_free_pages() at error path
+    - ALSA: ac97: Fix incorrect bit shift at AC97-SPSA control write
+    - ALSA: control: Fix race between adding and removing a user element
+    - ALSA: sparc: Fix invalid snd_free_pages() at error path
+    - ext2: fix potential use after free
+    - dmaengine: at_hdmac: fix memory leak in at_dma_xlate()
+    - dmaengine: at_hdmac: fix module unloading
+    - btrfs: release metadata before running delayed refs
+    - USB: usb-storage: Add new IDs to ums-realtek
+    - usb: core: quirks: add RESET_RESUME quirk for Cherry G230 Stream series
+    - misc: mic/scif: fix copy-paste error in scif_create_remote_lookup
+    - Kbuild: suppress packed-not-aligned warning for default setting only
+    - exec: avoid gcc-8 warning for get_task_comm
+    - disable stringop truncation warnings for now
+    - kobject: Replace strncpy with memcpy
+    - unifdef: use memcpy instead of strncpy
+    - kernfs: Replace strncpy with memcpy
+    - ip_tunnel: Fix name string concatenate in __ip_tunnel_create()
+    - drm: gma500: fix logic error
+    - scsi: bfa: convert to strlcpy/strlcat
+    - staging: rts5208: fix gcc-8 logic error warning
+    - kdb: use memmove instead of overlapping memcpy
+    - iser: set sector for ambiguous mr status errors
+    - uprobes: Fix handle_swbp() vs. unregister() + register() race once more
+    - MIPS: ralink: Fix mt7620 nd_sd pinmux
+    - mips: fix mips_get_syscall_arg o32 check
+    - drm/ast: Fix incorrect free on ioregs
+    - scsi: scsi_devinfo: cleanly zero-pad devinfo strings
+    - ALSA: trident: Suppress gcc string warning
+    - scsi: csiostor: Avoid content leaks and casts
+    - kgdboc: Fix restrict error
+    - kgdboc: Fix warning with module build
+    - leds: call led_pwm_set() in leds-pwm to enforce default LED_OFF
+    - leds: turn off the LED and wait for completion on unregistering LED class
+      device
+    - leds: leds-gpio: Fix return value check in create_gpio_led()
+    - Input: xpad - quirk all PDP Xbox One gamepads
+    - Input: matrix_keypad - check for errors from of_get_named_gpio()
+    - Input: elan_i2c - add ELAN0620 to the ACPI table
+    - Input: elan_i2c - add ACPI ID for Lenovo IdeaPad 330-15ARR
+    - Input: elan_i2c - add support for ELAN0621 touchpad
+    - btrfs: Always try all copies when reading extent buffers
+    - Btrfs: fix use-after-free when dumping free space
+    - ARC: change defconfig defaults to ARCv2
+    - arc: [devboards] Add support of NFSv3 ACL
+    - mm: cleancache: fix corruption on missed inode invalidation
+    - usb: gadget: dummy: fix nonsensical comparisons
+    - iommu/vt-d: Fix NULL pointer dereference in prq_event_thread()
+    - iommu/ipmmu-vmsa: Fix crash on early domain free
+    - can: rcar_can: Fix erroneous registration
+    - batman-adv: Expand merged fragment buffer for full packet
+    - bnx2x: Assign unique DMAE channel number for FW DMAE transactions.
+    - qed: Fix PTT leak in qed_drain()
+    - qed: Fix reading wrong value in loop condition
+    - net/mlx4_core: Zero out lkey field in SW2HW_MPT fw command
+    - net/mlx4_core: Fix uninitialized variable compilation warning
+    - net/mlx4: Fix UBSAN warning of signed integer overflow
+    - net: faraday: ftmac100: remove netif_running(netdev) check before disabling
+      interrupts
+    - iommu/vt-d: Use memunmap to free memremap
+    - net: amd: add missing of_node_put()
+    - usb: quirk: add no-LPM quirk on SanDisk Ultra Flair device
+    - usb: appledisplay: Add 27" Apple Cinema Display
+    - USB: check usb_get_extra_descriptor for proper size
+    - ALSA: usb-audio: Fix UAF decrement if card has no live interfaces in card.c
+    - ALSA: hda: Add support for AMD Stoney Ridge
+    - ALSA: pcm: Fix starvation on down_write_nonblock()
+    - ALSA: pcm: Call snd_pcm_unlink() conditionally at closing
+    - ALSA: pcm: Fix interval evaluation with openmin/max
+    - virtio/s390: avoid race on vcdev->config
+    - virtio/s390: fix race in ccw_io_helper()
+    - SUNRPC: Fix leak of krb5p encode pages
+    - xhci: Prevent U1/U2 link pm states if exit latency is too long
+    - Staging: lustre: remove two build warnings
+    - cifs: Fix separator when building path from dentry
+    - tty: serial: 8250_mtk: always resume the device in probe.
+    - kgdboc: fix KASAN global-out-of-bounds bug in param_set_kgdboc_var()
+    - mac80211_hwsim: Timer should be initialized before device registered
+    - mac80211: Clear beacon_int in ieee80211_do_stop
+    - mac80211: ignore tx status for PS stations in ieee80211_tx_status_ext
+    - mac80211: fix reordering of buffered broadcast packets
+    - mac80211: ignore NullFunc frames in the duplicate detection
+    - Linux 4.4.167
+
+  * CVE-2018-19407
+    - KVM: X86: Fix scan ioapic use-before-initialization
+
+  * cpu-hotplug test in ubuntu_kernel_selftest always return 0 on Xenial
+    (LP: #1809699)
+    - selftests/cpu-hotplug: exit with failure when test occured unexpected
+      behaviors
+
+  * iommu - need to effectively disable iommu if "intel_iommu=off" is passed as
+    a kernel parameter (LP: #1810328)
+    - iommu/vt-d: Make sure IOMMUs are off when intel_iommu=off
+
+  * ldisc crash on reopened tty (LP: #1791758)
+    - tty: fix data race between tty_init_dev and flush of buf
+    - tty: Drop tty->count on tty_reopen() failure
+    - tty: Hold tty_ldisc_lock() during tty_reopen()
+    - tty: Don't block on IO when ldisc change is pending
+    - tty: Simplify tty->count math in tty_reopen()
+
+  * Xenial update: 4.4.166 upstream stable release (LP: #1810967)
+    - usb: core: Fix hub port connection events lost
+    - usb: xhci: fix timeout for transition from RExit to U0
+    - MAINTAINERS: Add Sasha as a stable branch maintainer
+    - iwlwifi: mvm: support sta_statistics() even on older firmware
+    - v9fs_dir_readdir: fix double-free on p9stat_read error
+    - bfs: add sanity check at bfs_fill_super()
+    - sctp: clear the transport of some out_chunk_list chunks in
+      sctp_assoc_rm_peer
+    - gfs2: Don't leave s_fs_info pointing to freed memory in init_sbd
+    - llc: do not use sk_eat_skb()
+    - drm/ast: change resolution may cause screen blurred
+    - drm/ast: fixed cursor may disappear sometimes
+    - can: dev: can_get_echo_skb(): factor out non sending code to
+      __can_get_echo_skb()
+    - can: dev: __can_get_echo_skb(): replace struct can_frame by canfd_frame to
+      access frame length
+    - can: dev: __can_get_echo_skb(): Don't crash the kernel if can_priv::echo_skb
+      is accessed out of bounds
+    - can: dev: __can_get_echo_skb(): print error message, if trying to echo non
+      existing skb
+    - usb: xhci: Prevent bus suspend if a port connect change or polling state is
+      detected
+    - KVM: PPC: Move and undef TRACE_INCLUDE_PATH/FILE
+    - cpufreq: imx6q: add return value check for voltage scale
+    - SUNRPC: Fix a bogus get/put in generic_key_to_expire()
+    - kdb: Use strscpy with destination buffer size
+    - powerpc/numa: Suppress "VPHN is not supported" messages
+    - tmpfs: make lseek(SEEK_DATA/SEK_HOLE) return ENXIO with a negative offset
+    - of: add helper to lookup compatible child node
+    - NFC: nfcmrvl_uart: fix OF child-node lookup
+    - net: bcmgenet: fix OF child-node lookup
+    - x86/entry: spell EBX register correctly in documentation
+    - x86/entry/64: Remove %ebx handling from error_entry/exit
+    - arm64: remove no-op -p linker flag
+    - ath10k: fix kernel panic due to race in accessing arvif list
+    - Input: xpad - remove spurious events of wireless xpad 360 controller
+    - Input: xpad - handle "present" and "gone" correctly
+    - Input: xpad - update Xbox One Force Feedback Support
+    - Input: xpad - workaround dead irq_out after suspend/ resume
+    - Input: xpad - use LED API when identifying wireless controllers
+    - Input: xpad - correct xbox one pad device name
+    - Input: xpad - remove unused function
+    - Input: xpad - add Mad Catz FightStick TE 2 VID/PID
+    - Input: xpad - prevent spurious input from wired Xbox 360 controllers
+    - Input: xpad - add more third-party controllers
+    - Input: xpad - xbox one elite controller support
+    - Input: xpad - fix rumble on Xbox One controllers with 2015 firmware
+    - Input: xpad - power off wireless 360 controllers on suspend
+    - Input: xpad - add product ID for Xbox One S pad
+    - Input: xpad - fix Xbox One rumble stopping after 2.5 secs
+    - Input: xpad - correctly sort vendor id's
+    - Input: xpad - move reporting xbox one home button to common function
+    - Input: xpad - simplify error condition in init_output
+    - Input: xpad - don't depend on endpoint order
+    - Input: xpad - fix stuck mode button on Xbox One S pad
+    - Input: xpad - restore LED state after device resume
+    - Input: xpad - support some quirky Xbox One pads
+    - Input: xpad - sort supported devices by USB ID
+    - Input: xpad - sync supported devices with xboxdrv
+    - Input: xpad - add USB IDs for Mad Catz Brawlstick and Razer Sabertooth
+    - Input: xpad - sync supported devices with 360Controller
+    - Input: xpad - sync supported devices with XBCD
+    - Input: xpad - constify usb_device_id
+    - Input: xpad - fix PowerA init quirk for some gamepad models
+    - Input: xpad - validate USB endpoint type during probe
+    - Input: xpad - add support for PDP Xbox One controllers
+    - Input: xpad - add PDP device id 0x02a4
+    - Input: xpad - fix some coding style issues
+    - Input: xpad - avoid using __set_bit() for capabilities
+    - Input: xpad - add GPD Win 2 Controller USB IDs
+    - Input: xpad - fix GPD Win 2 controller name
+    - Input: xpad - add support for Xbox1 PDP Camo series gamepad
+    - cw1200: Don't leak memory if krealloc failes
+    - mwifiex: Fix NULL pointer dereference in skb_dequeue()
+    - mwifiex: fix p2p device doesn't find in scan problem
+    - netfilter: nf_tables: fix oops when inserting an element into a verdict map
+    - scsi: ufs: fix bugs related to null pointer access and array size
+    - scsi: ufshcd: Fix race between clk scaling and ungate work
+    - scsi: ufs: fix race between clock gating and devfreq scaling work
+    - scsi: ufshcd: release resources if probe fails
+    - scsi: qla2xxx: do not queue commands when unloading
+    - iwlwifi: mvm: fix regulatory domain update when the firmware starts
+    - tty: wipe buffer.
+    - tty: wipe buffer if not echoing data
+    - usb: xhci: fix uninitialized completion when USB3 port got wrong status
+    - btrfs: Ensure btrfs_trim_fs can trim the whole filesystem
+    - sched/core: Allow __sched_setscheduler() in interrupts when PI is not used
+    - s390/mm: Check for valid vma before zapping in gmap_discard
+    - drm/ast: Remove existing framebuffers before loading driver
+    - Linux 4.4.166
+
+  * Xenial update: 4.4.166 upstream stable release (LP: #1810967) //
+    CVE-2000-1134 // CVE-2007-3852 // CVE-2008-0525 // CVE-2009-0416 //
+    CVE-2011-4834 // CVE-2015-1838 // CVE-2015-7442 // CVE-2016-7489
+    - namei: allow restricted O_CREAT of FIFOs and regular files
+
+  * Xenial update: 4.4.165 upstream stable release (LP: #1810958)
+    - flow_dissector: do not dissect l4 ports for fragments
+    - ip_tunnel: don't force DF when MTU is locked
+    - net-gro: reset skb->pkt_type in napi_reuse_skb()
+    - tg3: Add PHY reset for 5717/5719/5720 in change ring and flow control paths
+    - ipv6: Fix PMTU updates for UDP/raw sockets in presence of VRF
+    - kbuild: Add better clang cross build support
+    - kbuild: clang: add -no-integrated-as to KBUILD_[AC]FLAGS
+    - kbuild: Consolidate header generation from ASM offset information
+    - kbuild: consolidate redundant sed script ASM offset generation
+    - kbuild: fix asm-offset generation to work with clang
+    - kbuild: drop -Wno-unknown-warning-option from clang options
+    - kbuild, LLVMLinux: Add -Werror to cc-option to support clang
+    - kbuild: use -Oz instead of -Os when using clang
+    - kbuild: Add support to generate LLVM assembly files
+    - modules: mark __inittest/__exittest as __maybe_unused
+    - kbuild: clang: Disable 'address-of-packed-member' warning
+    - crypto: arm64/sha - avoid non-standard inline asm tricks
+    - efi/libstub/arm64: Force 'hidden' visibility for section markers
+    - efi/libstub/arm64: Set -fpie when building the EFI stub
+    - kbuild: fix linker feature test macros when cross compiling with Clang
+    - kbuild: Set KBUILD_CFLAGS before incl. arch Makefile
+    - kbuild: move cc-option and cc-disable-warning after incl. arch Makefile
+    - kbuild: clang: fix build failures with sparse check
+    - kbuild: clang: remove crufty HOSTCFLAGS
+    - kbuild: clang: disable unused variable warnings only when constant
+    - kbuild: set no-integrated-as before incl. arch Makefile
+    - kbuild: allow to use GCC toolchain not in Clang search path
+    - arm64: Disable asm-operand-width warning for clang
+    - x86/kbuild: Use cc-option to enable -falign-{jumps/loops}
+    - crypto, x86: aesni - fix token pasting for clang
+    - x86/mm/kaslr: Use the _ASM_MUL macro for multiplication to work around Clang
+      incompatibility
+    - kbuild: Add __cc-option macro
+    - x86/build: Use __cc-option for boot code compiler options
+    - x86/build: Specify stack alignment for clang
+    - x86/boot: #undef memcpy() et al in string.c
+    - x86/build: Fix stack alignment for CLang
+    - x86/build: Use cc-option to validate stack alignment parameter
+    - reiserfs: propagate errors from fill_with_dentries() properly
+    - hfs: prevent btree data loss on root split
+    - hfsplus: prevent btree data loss on root split
+    - um: Give start_idle_thread() a return code
+    - fs/exofs: fix potential memory leak in mount option parsing
+    - clk: samsung: exynos5420: Enable PERIS clocks for suspend
+    - platform/x86: acerhdf: Add BIOS entry for Gateway LT31 v1.3307
+    - arm64: percpu: Initialize ret in the default case
+    - s390/vdso: add missing FORCE to build targets
+    - netfilter: ipset: actually allow allowable CIDR 0 in hash:net,port,net
+    - s390/mm: Fix ERROR: "__node_distance" undefined!
+    - netfilter: ipset: Correct rcu_dereference() call in ip_set_put_comment()
+    - netfilter: xt_IDLETIMER: add sysfs filename checking routine
+    - hwmon: (ibmpowernv) Remove bogus __init annotations
+    - lib/raid6: Fix arm64 test build
+    - zram: close udev startup race condition as default groups
+    - SUNRPC: drop pointless static qualifier in xdr_get_next_encode_buffer()
+    - gfs2: Put bitmap buffers in put_super
+    - btrfs: fix pinned underflow after transaction aborted
+    - Revert "media: videobuf2-core: don't call memop 'finish' when queueing"
+    - media: v4l: event: Add subscription to list before calling "add" operation
+    - uio: Fix an Oops on load
+    - usb: cdc-acm: add entry for Hiro (Conexant) modem
+    - USB: quirks: Add no-lpm quirk for Raydium touchscreens
+    - usb: quirks: Add delay-init quirk for Corsair K70 LUX RGB
+    - misc: atmel-ssc: Fix section annotation on atmel_ssc_get_driver_data
+    - USB: misc: appledisplay: add 20" Apple Cinema Display
+    - drivers/misc/sgi-gru: fix Spectre v1 vulnerability
+    - ACPI / platform: Add SMB0001 HID to forbidden_id_list
+    - new helper: uaccess_kernel()
+    - HID: uhid: forbid UHID_CREATE under KERNEL_DS or elevated privileges
+    - xhci: Fix USB3 NULL pointer dereference at logical disconnect.
+    - Linux 4.4.165
+
+  * Xenial update: 4.4.164 upstream stable release (LP: #1810947)
+    - bcache: fix miss key refill->end in writeback
+    - hwmon: (pmbus) Fix page count auto-detection.
+    - jffs2: free jffs2_sb_info through jffs2_kill_sb()
+    - pcmcia: Implement CLKRUN protocol disabling for Ricoh bridges
+    - ipmi: Fix timer race with module unload
+    - parisc: Fix address in HPMC IVA
+    - parisc: Fix map_pages() to not overwrite existing pte entries
+    - ALSA: hda - Add mic quirk for the Lenovo G50-30 (17aa:3905)
+    - ALSA: ca0106: Disable IZD on SB0570 DAC to fix audio pops
+    - x86/corruption-check: Fix panic in memory_corruption_check() when boot
+      option without value is provided
+    - x86/kconfig: Fall back to ticket spinlocks
+    - [Config] Remove CONFIG{,_ARCH_USE}_QUEUED_SPINLOCKS
+    - sparc: Fix single-pcr perf event counter management.
+    - x86/fpu: Remove second definition of fpu in __fpu__restore_sig()
+    - net: qla3xxx: Remove overflowing shift statement
+    - selftests: ftrace: Add synthetic event syntax testcase
+    - locking/lockdep: Fix debug_locks off performance problem
+    - ataflop: fix error handling during setup
+    - swim: fix cleanup on setup error
+    - tun: Consistently configure generic netdev params via rtnetlink
+    - perf tools: Free temporary 'sys' string in read_event_files()
+    - perf tools: Cleanup trace-event-info 'tdata' leak
+    - mmc: sdhci-pci-o2micro: Add quirk for O2 Micro dev 0x8620 rev 0x01
+    - Bluetooth: btbcm: Add entry for BCM4335C0 UART bluetooth
+    - x86: boot: Fix EFI stub alignment
+    - pinctrl: qcom: spmi-mpp: Fix err handling of pmic_mpp_set_mux
+    - kprobes: Return error if we fail to reuse kprobe instead of BUG_ON()
+    - ACPI / LPSS: Add alternative ACPI HIDs for Cherry Trail DMA controllers
+    - pinctrl: qcom: spmi-mpp: Fix drive strength setting
+    - pinctrl: spmi-mpp: Fix pmic_mpp_config_get() to be compliant
+    - pinctrl: ssbi-gpio: Fix pm8xxx_pin_config_get() to be compliant
+    - ath10k: schedule hardware restart if WMI command times out
+    - scsi: esp_scsi: Track residual for PIO transfers
+    - scsi: megaraid_sas: fix a missing-check bug
+    - tpm: suppress transmit cmd error logs when TPM 1.2 is disabled/deactivated
+    - ext4: fix argument checking in EXT4_IOC_MOVE_EXT
+    - MD: fix invalid stored role for a disk
+    - usb: chipidea: Prevent unbalanced IRQ disable
+    - driver/dma/ioat: Call del_timer_sync() without holding prep_lock
+    - uio: ensure class is registered before devices
+    - scsi: lpfc: Correct soft lockup when running mds diagnostics
+    - signal: Always deliver the kernel's SIGKILL and SIGSTOP to a pid namespace
+      init
+    - dmaengine: dma-jz4780: Return error if not probed from DT
+    - ALSA: hda: Check the non-cached stream buffers more explicitly
+    - xen-swiotlb: use actually allocated size on check physical continuous
+    - tpm: Restore functionality to xen vtpm driver.
+    - xen: fix race in xen_qlock_wait()
+    - xen: make xen_qlock_wait() nestable
+    - net/ipv4: defensive cipso option parsing
+    - libnvdimm: Hold reference on parent while scheduling async init
+    - jbd2: fix use after free in jbd2_log_do_checkpoint()
+    - gfs2_meta: ->mount() can get NULL dev_name
+    - ext4: initialize retries variable in ext4_da_write_inline_data_begin()
+    - HID: hiddev: fix potential Spectre v1
+    - PCI: Add Device IDs for Intel GPU "spurious interrupt" quirk
+    - signal/GenWQE: Fix sending of SIGKILL
+    - crypto: lrw - Fix out-of bounds access on counter overflow
+    - ima: fix showing large 'violations' or 'runtime_measurements_count'
+    - hugetlbfs: dirty pages as they are added to pagecache
+    - kbuild: fix kernel/bounds.c 'W=1' warning
+    - iio: adc: at91: fix acking DRDY irq on simple conversions
+    - iio: adc: at91: fix wrong channel number in triggered buffer mode
+    - w1: omap-hdq: fix missing bus unregister at removal
+    - smb3: allow stats which track session and share reconnects to be reset
+    - smb3: do not attempt cifs operation in smb3 query info error path
+    - smb3: on kerberos mount if server doesn't specify auth type use krb5
+    - printk: Fix panic caused by passing log_buf_len to command line
+    - genirq: Fix race on spurious interrupt detection
+    - NFSv4.1: Fix the r/wsize checking
+    - nfsd: Fix an Oops in free_session()
+    - lockd: fix access beyond unterminated strings in prints
+    - dm ioctl: harden copy_params()'s copy_from_user() from malicious users
+    - powerpc/msi: Fix compile error on mpc83xx
+    - MIPS: OCTEON: fix out of bounds array access on CN68XX
+    - TC: Set DMA masks for devices
+    - kgdboc: Passing ekgdboc to command line causes panic
+    - xen: fix xen_qlock_wait()
+    - media: em28xx: use a default format if TRY_FMT fails
+    - media: em28xx: fix input name for Terratec AV 350
+    - media: em28xx: make v4l2-compliance happier by starting sequence on zero
+    - ext4: avoid running out of journal credits when appending to an inline file
+    - Cramfs: fix abad comparison when wrap-arounds occur
+    - arm64: dts: stratix10: Correct System Manager register size
+    - soc/tegra: pmc: Fix child-node lookup
+    - btrfs: Handle owner mismatch gracefully when walking up tree
+    - btrfs: locking: Add extra check in btrfs_init_new_buffer() to avoid deadlock
+    - btrfs: iterate all devices during trim, instead of fs_devices::alloc_list
+    - btrfs: don't attempt to trim devices that don't support it
+    - btrfs: wait on caching when putting the bg cache
+    - btrfs: reset max_extent_size on clear in a bitmap
+    - btrfs: make sure we create all new block groups
+    - Btrfs: fix wrong dentries after fsync of file that got its parent replaced
+    - btrfs: qgroup: Dirty all qgroups before rescan
+    - Btrfs: fix null pointer dereference on compressed write path error
+    - btrfs: set max_extent_size properly
+    - MD: fix invalid stored role for a disk - try2
+    - tty: check name length in tty_find_polling_driver()
+    - powerpc/nohash: fix undefined behaviour when testing page size support
+    - drm/omap: fix memory barrier bug in DMM driver
+    - media: pci: cx23885: handle adding to list failure
+    - MIPS: kexec: Mark CPU offline before disabling local IRQ
+    - powerpc/boot: Ensure _zimage_start is a weak symbol
+    - sc16is7xx: Fix for multi-channel stall
+    - media: tvp5150: fix width alignment during set_selection()
+    - 9p locks: fix glock.client_id leak in do_lock
+    - 9p: clear dangling pointers in p9stat_free
+    - scsi: qla2xxx: Fix incorrect port speed being set for FC adapters
+    - fuse: Fix use-after-free in fuse_dev_do_read()
+    - fuse: Fix use-after-free in fuse_dev_do_write()
+    - fuse: fix blocked_waitq wakeup
+    - fuse: set FR_SENT while locked
+    - mm, elf: handle vm_brk error
+    - binfmt_elf: fix calculations for bss padding
+    - mm: refuse wrapped vm_brk requests
+    - fs, elf: make sure to page align bss in load_elf_library
+    - mm: do not bug_on on incorrect length in __mm_populate()
+    - e1000: avoid null pointer dereference on invalid stat type
+    - e1000: fix race condition between e1000_down() and e1000_watchdog
+    - bna: ethtool: Avoid reading past end of buffer
+    - MIPS: Loongson-3: Fix CPU UART irq delivery problem
+    - MIPS: Loongson-3: Fix BRIDGE irq delivery problem
+    - xtensa: add NOTES section to the linker script
+    - xtensa: make sure bFLT stack is 16 byte aligned
+    - xtensa: fix boot parameters address translation
+    - clk: s2mps11: Fix matching when built as module and DT node contains
+      compatible
+    - libceph: bump CEPH_MSG_MAX_DATA_LEN
+    - mach64: fix display corruption on big endian machines
+    - mach64: fix image corruption due to reading accelerator registers
+    - vhost/scsi: truncate T10 PI iov_iter to prot_bytes
+    - ocfs2: fix a misuse a of brelse after failing ocfs2_check_dir_entry
+    - mm: thp: relax __GFP_THISNODE for MADV_HUGEPAGE mappings
+    - mtd: docg3: don't set conflicting BCH_CONST_PARAMS option
+    - termios, tty/tty_baudrate.c: fix buffer overrun
+    - arch/alpha, termios: implement BOTHER, IBSHIFT and termios2
+    - Btrfs: fix data corruption due to cloning of eof block
+    - clockevents/drivers/i8253: Add support for PIT shutdown quirk
+    - ext4: add missing brelse() update_backups()'s error path
+    - ext4: add missing brelse() in set_flexbg_block_bitmap()'s error path
+    - ext4: add missing brelse() add_new_gdb_meta_bg()'s error path
+    - ext4: avoid potential extra brelse in setup_new_flex_group_blocks()
+    - ext4: fix possible inode leak in the retry loop of ext4_resize_fs()
+    - ext4: avoid buffer leak in ext4_orphan_add() after prior errors
+    - ext4: fix missing cleanup if ext4_alloc_flex_bg_array() fails while resizing
+    - ext4: avoid possible double brelse() in add_new_gdb() on error path
+    - ext4: fix possible leak of sbi->s_group_desc_leak in error path
+    - ext4: release bs.bh before re-using in ext4_xattr_block_find()
+    - ext4: fix buffer leak in ext4_xattr_move_to_block() on error path
+    - ext4: fix buffer leak in __ext4_read_dirblock() on error path
+    - mount: Prevent MNT_DETACH from disconnecting locked mounts
+    - sunrpc: correct the computation for page_ptr when truncating
+    - rtc: hctosys: Add missing range error reporting
+    - fuse: fix leaked notify reply
+    - configfs: replace strncpy with memcpy
+    - hugetlbfs: fix kernel BUG at fs/hugetlbfs/inode.c:444!
+    - mm: migration: fix migration of huge PMD shared pages
+    - drm/rockchip: Allow driver to be shutdown on reboot/kexec
+    - drm/dp_mst: Check if primary mstb is null
+    - drm/i915/hdmi: Add HDMI 2.0 audio clock recovery N values
+    - Linux 4.4.164
+
+  * Xenial update: 4.4.163 upstream stable release (LP: #1810807)
+    - xfrm: Validate address prefix lengths in the xfrm selector.
+    - xfrm6: call kfree_skb when skb is toobig
+    - mac80211: Always report TX status
+    - cfg80211: reg: Init wiphy_idx in regulatory_hint_core()
+    - ARM: 8799/1: mm: fix pci_ioremap_io() offset check
+    - xfrm: validate template mode
+    - mac80211_hwsim: do not omit multicast announce of first added radio
+    - Bluetooth: SMP: fix crash in unpairing
+    - pxa168fb: prepare the clock
+    - asix: Check for supported Wake-on-LAN modes
+    - ax88179_178a: Check for supported Wake-on-LAN modes
+    - lan78xx: Check for supported Wake-on-LAN modes
+    - sr9800: Check for supported Wake-on-LAN modes
+    - r8152: Check for supported Wake-on-LAN Modes
+    - smsc75xx: Check for Wake-on-LAN modes
+    - smsc95xx: Check for Wake-on-LAN modes
+    - perf/ring_buffer: Prevent concurent ring buffer access
+    - net: cxgb3_main: fix a missing-check bug
+    - KEYS: put keyring if install_session_keyring_to_cred() fails
+    - ipv6: suppress sparse warnings in IP6_ECN_set_ce()
+    - net: drop write-only stack variable
+    - ser_gigaset: use container_of() instead of detour
+    - tracing: Skip more functions when doing stack tracing of events
+    - ARM: dts: apq8064: add ahci ports-implemented mask
+    - x86/mm/pat: Prevent hang during boot when mapping pages
+    - radix-tree: fix radix_tree_iter_retry() for tagged iterators.
+    - af_iucv: Move sockaddr length checks to before accessing sa_family in bind
+      and connect handlers
+    - net/mlx4_en: Resolve dividing by zero in 32-bit system
+    - ipv6: orphan skbs in reassembly unit
+    - um: Avoid longjmp/setjmp symbol clashes with libpthread.a
+    - sched/cgroup: Fix cgroup entity load tracking tear-down
+    - btrfs: don't create or leak aliased root while cleaning up orphans
+    - thermal: allow spear-thermal driver to be a module
+    - thermal: allow u8500-thermal driver to be a module
+    - x86/PCI: Mark Broadwell-EP Home Agent 1 as having non-compliant BARs
+    - aacraid: Start adapter after updating number of MSIX vectors
+    - perf/core: Don't leak event in the syscall error path
+    - usbvision: revert commit 588afcc1
+    - MIPS: Fix FCSR Cause bit handling for correct SIGFPE issue
+    - ASoC: ak4613: Enable cache usage to fix crashes on resume
+    - ASoC: wm8940: Enable cache usage to fix crashes on resume
+    - CIFS: handle guest access errors to Windows shares
+    - arm64: Fix potential race with hardware DBM in ptep_set_access_flags()
+    - xfrm: Clear sk_dst_cache when applying per-socket policy.
+    - scsi: Add STARGET_CREATED_REMOVE state to scsi_target_state
+    - sparc/pci: Refactor dev_archdata initialization into pci_init_dev_archdata
+    - sch_red: update backlog as well
+    - usb-storage: fix bogus hardware error messages for ATA pass-thru devices
+    - bpf: generally move prog destruction to RCU deferral
+    - drm/nouveau/fbcon: fix oops without fbdev emulation
+    - fuse: Dont call set_page_dirty_lock() for ITER_BVEC pages for async_dio
+    - net/mlx5e: Fix LRO modify
+    - net/mlx5e: Correctly handle RSS indirection table when changing number of
+      channels
+    - ALSA: timer: Fix zero-division by continue of uninitialized instance
+    - vti6: flush x-netns xfrm cache when vti interface is removed
+    - brcmfmac: Fix glom_skb leak in brcmf_sdiod_recv_chain
+    - l2tp: hold socket before dropping lock in l2tp_ip{, 6}_recv()
+    - tty: serial: sprd: fix error return code in sprd_probe()
+    - video: fbdev: pxa3xx_gcu: fix error return code in pxa3xx_gcu_probe()
+    - sparc64 mm: Fix more TSB sizing issues
+    - gpu: host1x: fix error return code in host1x_probe()
+    - sparc64: Fix exception handling in UltraSPARC-III memcpy.
+    - gpio: msic: fix error return code in platform_msic_gpio_probe()
+    - usb: imx21-hcd: fix error return code in imx21_probe()
+    - usb: ehci-omap: fix error return code in ehci_hcd_omap_probe()
+    - usb: dwc3: omap: fix error return code in dwc3_omap_probe()
+    - spi/bcm63xx-hspi: fix error return code in bcm63xx_hsspi_probe()
+    - MIPS: Handle non word sized instructions when examining frame
+    - spi/bcm63xx: fix error return code in bcm63xx_spi_probe()
+    - spi: xlp: fix error return code in xlp_spi_probe()
+    - ASoC: spear: fix error return code in spdif_in_probe()
+    - PM / devfreq: tegra: fix error return code in tegra_devfreq_probe()
+    - bonding: avoid defaulting hard_header_len to ETH_HLEN on slave removal
+    - scsi: aacraid: Fix typo in blink status
+    - MIPS: microMIPS: Fix decoding of swsp16 instruction
+    - igb: Remove superfluous reset to PHY and page 0 selection
+    - MIPS: DEC: Fix an int-handler.S CPU_DADDI_WORKAROUNDS regression
+    - ARM: dts: imx53-qsb: disable 1.2GHz OPP
+    - fs/fat/fatent.c: add cond_resched() to fat_count_free_clusters()
+    - mtd: spi-nor: Add support for is25wp series chips
+    - perf tools: Disable parallelism for 'make clean'
+    - bridge: do not add port to router list when receives query with source
+      0.0.0.0
+    - net: bridge: remove ipv6 zero address check in mcast queries
+    - ipv6: mcast: fix a use-after-free in inet6_mc_check
+    - ipv6/ndisc: Preserve IPv6 control buffer if protocol error handlers are
+      called
+    - net/ipv6: Fix index counter for unicast addresses in in6_dump_addrs
+    - net: sched: gred: pass the right attribute to gred_change_table_def()
+    - net: socket: fix a missing-check bug
+    - net: stmmac: Fix stmmac_mdio_reset() when building stmmac as modules
+    - r8169: fix NAPI handling under high load
+    - sctp: fix race on sctp_id2asoc
+    - net: drop skb on failure in ip_check_defrag()
+    - vhost: Fix Spectre V1 vulnerability
+    - rtnetlink: Disallow FDB configuration for non-Ethernet device
+    - mremap: properly flush TLB before releasing the page
+    - crypto: shash - Fix a sleep-in-atomic bug in shash_setkey_unaligned
+    - ahci: don't ignore result code of ahci_reset_controller()
+    - cachefiles: fix the race between cachefiles_bury_object() and rmdir(2)
+    - ptp: fix Spectre v1 vulnerability
+    - RDMA/ucma: Fix Spectre v1 vulnerability
+    - IB/ucm: Fix Spectre v1 vulnerability
+    - cdc-acm: correct counting of UART states in serial state notification
+    - usb: gadget: storage: Fix Spectre v1 vulnerability
+    - USB: fix the usbfs flag sanitization for control transfers
+    - Input: elan_i2c - add ACPI ID for Lenovo IdeaPad 330-15IGM
+    - sched/fair: Fix throttle_list starvation with low CFS quota
+    - x86/percpu: Fix this_cpu_read()
+    - cpuidle: Do not access cpuidle_devices when !CONFIG_CPU_IDLE
+    - l2tp: hold tunnel socket when handling control frames in l2tp_ip and
+      l2tp_ip6
+    - x86/time: Correct the attribute on jiffies' definition
+    - Linux 4.4.163
+
+  * nvme - Polling on timeout (LP: #1807393)
+    - nvme/pci: Poll CQ on timeout
+
+  * Xenial: data corruption when using i40e with iommu (LP: #1802421)
+    - i40e: Drop packet split receive routine
+
+  * Fix Intel I210 doesn't work when ethernet cable gets plugged (LP: #1806818)
+    - igb: Fix an issue that PME is not enabled during runtime suspend
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 16 Jan 2019 17:35:06 +0100
+
+linux (4.4.0-141.167) xenial; urgency=medium
+
+  * linux: 4.4.0-141.167 -proposed tracker (LP: #1806569)
+
+  *  Redpine: firmware assert upon assoc   timeout (LP: #1804360)
+    - SAUCE: Redpine: fix for firmware assert upon assoc timeout
+
+  * CVE-2018-12896
+    - posix-timers: Sanitize overrun handling
+
+  * CVE-2017-5753
+    - ALSA: opl3: Hardening for potential Spectre v1
+    - ALSA: asihpi: Hardening for potential Spectre v1
+    - ALSA: hdspm: Hardening for potential Spectre v1
+    - ALSA: rme9652: Hardening for potential Spectre v1
+    - ALSA: control: Hardening for potential Spectre v1
+    - usbip: vhci_sysfs: fix potential Spectre v1
+    - libahci: Fix possible Spectre-v1 pmp indexing in ahci_led_store()
+
+  * CVE-2018-18710
+    - cdrom: fix improper type cast, which can leat to information leak.
+
+  * CVE-2018-18690
+    - xfs: don't fail when converting shortform attr to long form during
+      ATTR_REPLACE
+
+  * CVE-2017-18174
+    - pinctrl: Add devm_ apis for pinctrl_{register, unregister}
+    - pinctrl: amd: Use devm_pinctrl_register() for pinctrl registration
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 05 Dec 2018 06:11:33 +0000
+
+linux (4.4.0-140.166) xenial; urgency=medium
+
+  * linux: 4.4.0-140.166 -proposed tracker (LP: #1802776)
+
+  * Bypass of mount visibility through userns + mount propagation (LP: #1789161)
+    - mount: Retest MNT_LOCKED in do_umount
+    - mount: Don't allow copying MNT_UNBINDABLE|MNT_LOCKED mounts
+
+  * kdump fail due to an IRQ storm (LP: #1797990)
+    - SAUCE: x86/PCI: Export find_cap() to be used in early PCI code
+    - SAUCE: x86/quirks: Add parameter to clear MSIs early on boot
+    - SAUCE: x86/quirks: Scan all busses for early PCI quirks
+
+  * crash in ENA driver on removing an interface (LP: #1802341)
+    - SAUCE: net: ena: fix crash during ena_remove()
+
+  * xenial guest on arm64 drops to busybox under openstack bionic-rocky
+    (LP: #1797092)
+    - [Config] CONFIG_PCI_ECAM=y
+    - PCI: Provide common functions for ECAM mapping
+    - PCI: generic, thunder: Use generic ECAM API
+    - PCI, of: Move PCI I/O space management to PCI core code
+    - PCI: Move ecam.h to linux/include/pci-ecam.h
+    - PCI: Add parent device field to ECAM struct pci_config_window
+    - PCI: Add pci_unmap_iospace() to unmap I/O resources
+    - PCI/ACPI: Support I/O resources when parsing host bridge resources
+    - [Config] CONFIG_ACPI_MCFG=y
+    - PCI/ACPI: Add generic MCFG table handling
+    - PCI: Refactor pci_bus_assign_domain_nr() for CONFIG_PCI_DOMAINS_GENERIC
+    - PCI: Factor DT-specific pci_bus_find_domain_nr() code out
+    - ARM64: PCI: Add acpi_pci_bus_find_domain_nr()
+    - ARM64: PCI: ACPI support for legacy IRQs parsing and consolidation with DT
+      code
+    - ARM64: PCI: Support ACPI-based PCI host controller
+
+  * [GLK/CLX] Enhanced IBRS (LP: #1786139)
+    - x86/speculation: Remove SPECTRE_V2_IBRS in enum spectre_v2_mitigation
+    - x86/speculation: Support Enhanced IBRS on future CPUs
+
+  * Update ENA driver to version 2.0.1K (LP: #1798182)
+    - net: ena: remove ndo_poll_controller
+    - net: ena: fix warning in rmmod caused by double iounmap
+    - net: ena: fix rare bug when failed restart/resume is followed by driver
+      removal
+    - net: ena: fix NULL dereference due to untimely napi initialization
+    - net: ena: fix auto casting to boolean
+    - net: ena: minor performance improvement
+    - net: ena: complete host info to match latest ENA spec
+    - net: ena: introduce Low Latency Queues data structures according to ENA spec
+    - net: ena: add functions for handling Low Latency Queues in ena_com
+    - net: ena: add functions for handling Low Latency Queues in ena_netdev
+    - net: ena: use CSUM_CHECKED device indication to report skb's checksum status
+    - net: ena: explicit casting and initialization, and clearer error handling
+    - net: ena: limit refill Rx threshold to 256 to avoid latency issues
+    - net: ena: change rx copybreak default to reduce kernel memory pressure
+    - net: ena: remove redundant parameter in ena_com_admin_init()
+    - net: ena: update driver version to 2.0.1
+    - net: ena: fix indentations in ena_defs for better readability
+    - net: ena: Fix Kconfig dependency on X86
+    - net: ena: enable Low Latency Queues
+    - net: ena: fix compilation error in xtensa architecture
+
+  * Xenial update: 4.4.162 upstream stable release (LP: #1801900)
+    - ASoC: wm8804: Add ACPI support
+    - ASoC: sigmadsp: safeload should not have lower byte limit
+    - selftests/efivarfs: add required kernel configs
+    - mfd: omap-usb-host: Fix dts probe of children
+    - sound: enable interrupt after dma buffer initialization
+    - stmmac: fix valid numbers of unicast filter entries
+    - net: macb: disable scatter-gather for macb on sama5d3
+    - ARM: dts: at91: add new compatibility string for macb on sama5d3
+    - drm/amdgpu: Fix SDMA HQD destroy error on gfx_v7
+    - ext4: add corruption check in ext4_xattr_set_entry()
+    - mm/vmstat.c: fix outdated vmstat_text
+    - mach64: detect the dot clock divider correctly on sparc
+    - perf script python: Fix export-to-postgresql.py occasional failure
+    - i2c: i2c-scmi: fix for i2c_smbus_write_block_data
+    - xhci: Don't print a warning when setting link state for disabled ports
+    - jffs2: return -ERANGE when xattr buffer is too small
+    - bnxt_en: Fix TX timeout during netpoll.
+    - bonding: avoid possible dead-lock
+    - ip6_tunnel: be careful when accessing the inner header
+    - ip_tunnel: be careful when accessing the inner header
+    - ipv4: fix use-after-free in ip_cmsg_recv_dstaddr()
+    - net: ipv4: update fnhe_pmtu when first hop's MTU changes
+    - net/ipv6: Display all addresses in output of /proc/net/if_inet6
+    - netlabel: check for IPV4MASK in addrinfo_get
+    - net/usb: cancel pending work when unbinding smsc75xx
+    - qlcnic: fix Tx descriptor corruption on 82xx devices
+    - team: Forbid enslaving team device to itself
+    - net: mvpp2: Extract the correct ethtype from the skb for tx csum offload
+    - net: systemport: Fix wake-up interrupt race during resume
+    - rtnl: limit IFLA_NUM_TX_QUEUES and IFLA_NUM_RX_QUEUES to 4096
+    - KVM: x86: remove eager_fpu field of struct kvm_vcpu_arch
+    - x86/fpu: Remove use_eager_fpu()
+    - x86/fpu: Remove struct fpu::counter
+    - x86/fpu: Finish excising 'eagerfpu'
+    - media: af9035: prevent buffer overflow on write
+    - clocksource/drivers/ti-32k: Add CLOCK_SOURCE_SUSPEND_NONSTOP flag for non-
+      am43 SoCs
+    - Input: atakbd - fix Atari keymap
+    - Input: atakbd - fix Atari CapsLock behaviour
+    - net/mlx4: Use cpumask_available for eq->affinity_mask
+    - powerpc/tm: Fix userspace r13 corruption
+    - powerpc/tm: Avoid possible userspace r1 corruption on reclaim
+    - ARC: build: Get rid of toolchain check
+    - usb: gadget: serial: fix oops when data rx'd after close
+    - HV: properly delay KVP packets when negotiation is in progress
+    - Linux 4.4.162
+
+  * Xenial update: 4.4.161 upstream stable release (LP: #1801893)
+    - mm/vmstat.c: skip NR_TLB_REMOTE_FLUSH* properly
+    - fbdev/omapfb: fix omapfb_memory_read infoleak
+    - x86/vdso: Fix asm constraints on vDSO syscall fallbacks
+    - x86/vdso: Fix vDSO syscall fallback asm constraint regression
+    - PCI: Reprogram bridge prefetch registers on resume
+    - mac80211: fix setting IEEE80211_KEY_FLAG_RX_MGMT for AP mode keys
+    - PM / core: Clear the direct_complete flag on errors
+    - dm cache: fix resize crash if user doesn't reload cache table
+    - xhci: Add missing CAS workaround for Intel Sunrise Point xHCI
+    - USB: serial: simple: add Motorola Tetra MTP6550 id
+    - of: unittest: Disable interrupt node tests for old world MAC systems
+    - ext4: always verify the magic number in xattr blocks
+    - cgroup: Fix deadlock in cpu hotplug path
+    - ath10k: fix use-after-free in ath10k_wmi_cmd_send_nowait
+    - ARC: clone syscall to setp r25 as thread pointer
+    - ucma: fix a use-after-free in ucma_resolve_ip()
+    - ubifs: Check for name being NULL while mounting
+    - tcp: increment sk_drops for dropped rx packets
+    - tcp: use an RB tree for ooo receive queue
+    - tcp: fix a stale ooo_last_skb after a replace
+    - tcp: free batches of packets in tcp_prune_ofo_queue()
+    - tcp: call tcp_drop() from tcp_data_queue_ofo()
+    - tcp: add tcp_ooo_try_coalesce() helper
+    - ath10k: fix scan crash due to incorrect length calculation
+    - ebtables: arpreply: Add the standard target sanity check
+    - Linux 4.4.161
+
+  * mlock203 test in ubuntu_ltp_syscalls failed with Xenial kernel
+    (LP: #1793451)
+    - mm: mlock: avoid increase mm->locked_vm on mlock() when already mlock2(,
+      MLOCK_ONFAULT)
+
+  * execveat03 in ubuntu_ltp_syscalls failed on X/B (LP: #1786729)
+    - cap_inode_getsecurity: use d_find_any_alias() instead of d_find_alias()
+
+  * [Ubuntu] net/af_iucv: fix skb leaks for HiperTransport (LP: #1800639)
+    - net/af_iucv: drop inbound packets with invalid flags
+    - net/af_iucv: fix skb handling on HiperTransport xmit error
+
+  * NULL pointer dereference at 0000000000000020 when access
+    dst_orig->ops->family in function  xfrm_lookup_with_ifid() (LP: #1801878)
+    - xfrm: Fix NULL pointer dereference when skb_dst_force clears the dst_entry.
+
+  * [Ubuntu] qeth: Fix potential array overrun in cmd/rc lookup (LP: #1800641)
+    - s390: qeth_core_mpc: Use ARRAY_SIZE instead of reimplementing its function
+    - s390: qeth: Fix potential array overrun in cmd/rc lookup
+
+  * Packaging resync (LP: #1786013)
+    - [Package] add support for specifying the primary makefile
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Tue, 13 Nov 2018 16:55:46 -0500
+
+linux (4.4.0-139.165) xenial; urgency=medium
+
+  * linux: 4.4.0-139.165 -proposed tracker (LP: #1799401)
+
+  * Kernel panic after the ubuntu_nbd_smoke_test on Xenial kernel (LP: #1793464)
+    - nbd: Remove signal usage
+    - nbd: Timeouts are not user requested disconnects
+    - nbd: Cleanup reset of nbd and bdev after a disconnect
+    - nbd: don't shutdown sock with irq's disabled
+    - nbd: fix race in ioctl
+
+  * fscache: bad refcounting in fscache_op_complete leads to OOPS (LP: #1797314)
+    - SAUCE: fscache: Fix race in decrementing refcount of op->npages
+
+  * xenial: virtio-scsi: CPU soft lockup due to loop in
+    virtscsi_target_destroy() (LP: #1798110)
+    - SAUCE: (no-up) virtio-scsi: Decrement reqs counter before SCSI command
+      requeue
+
+  * Error reported when creating ZFS pool with "-t" option, despite successful
+    pool creation (LP: #1769937)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu26
+
+  * Xenial update: 4.4.160 upstream stable release (LP: #1798770)
+    - crypto: skcipher - Fix -Wstringop-truncation warnings
+    - tsl2550: fix lux1_input error in low light
+    - vmci: type promotion bug in qp_host_get_user_memory()
+    - x86/numa_emulation: Fix emulated-to-physical node mapping
+    - staging: rts5208: fix missing error check on call to rtsx_write_register
+    - uwb: hwa-rc: fix memory leak at probe
+    - power: vexpress: fix corruption in notifier registration
+    - Bluetooth: Add a new Realtek 8723DE ID 0bda:b009
+    - USB: serial: kobil_sct: fix modem-status error handling
+    - 6lowpan: iphc: reset mac_header after decompress to fix panic
+    - md-cluster: clear another node's suspend_area after the copy is finished
+    - media: exynos4-is: Prevent NULL pointer dereference in __isp_video_try_fmt()
+    - powerpc/kdump: Handle crashkernel memory reservation failure
+    - media: fsl-viu: fix error handling in viu_of_probe()
+    - x86/tsc: Add missing header to tsc_msr.c
+    - x86/entry/64: Add two more instruction suffixes
+    - scsi: target/iscsi: Make iscsit_ta_authentication() respect the output
+      buffer size
+    - scsi: klist: Make it safe to use klists in atomic context
+    - scsi: ibmvscsi: Improve strings handling
+    - usb: wusbcore: security: cast sizeof to int for comparison
+    - powerpc/powernv/ioda2: Reduce upper limit for DMA window size
+    - alarmtimer: Prevent overflow for relative nanosleep
+    - s390/extmem: fix gcc 8 stringop-overflow warning
+    - ALSA: snd-aoa: add of_node_put() in error path
+    - media: s3c-camif: ignore -ENOIOCTLCMD from v4l2_subdev_call for s_power
+    - media: soc_camera: ov772x: correct setting of banding filter
+    - media: omap3isp: zero-initialize the isp cam_xclk{a,b} initial data
+    - staging: android: ashmem: Fix mmap size validation
+    - drivers/tty: add error handling for pcmcia_loop_config
+    - media: tm6000: add error handling for dvb_register_adapter
+    - ALSA: hda: Add AZX_DCAPS_PM_RUNTIME for AMD Raven Ridge
+    - ath10k: protect ath10k_htt_rx_ring_free with rx_ring.lock
+    - rndis_wlan: potential buffer overflow in rndis_wlan_auth_indication()
+    - wlcore: Add missing PM call for wlcore_cmd_wait_for_event_or_timeout()
+    - ARM: mvebu: declare asm symbols as character arrays in pmsu.c
+    - HID: hid-ntrig: add error handling for sysfs_create_group
+    - scsi: bnx2i: add error handling for ioremap_nocache
+    - EDAC, i7core: Fix memleaks and use-after-free on probe and remove
+    - ASoC: dapm: Fix potential DAI widget pointer deref when linking DAIs
+    - module: exclude SHN_UNDEF symbols from kallsyms api
+    - nfsd: fix corrupted reply to badly ordered compound
+    - ARM: dts: dra7: fix DCAN node addresses
+    - serial: cpm_uart: return immediately from console poll
+    - spi: tegra20-slink: explicitly enable/disable clock
+    - spi: sh-msiof: Fix invalid SPI use during system suspend
+    - spi: sh-msiof: Fix handling of write value for SISTR register
+    - spi: rspi: Fix invalid SPI use during system suspend
+    - spi: rspi: Fix interrupted DMA transfers
+    - USB: fix error handling in usb_driver_claim_interface()
+    - USB: handle NULL config in usb_find_alt_setting()
+    - slub: make ->cpu_partial unsigned int
+    - Revert "UBUNTU: SAUCE: media: uvcvideo: Support realtek's UVC 1.5 device"
+    - media: uvcvideo: Support realtek's UVC 1.5 device
+    - USB: usbdevfs: sanitize flags more
+    - USB: usbdevfs: restore warning for nonsensical flags
+    - Revert "usb: cdc-wdm: Fix a sleep-in-atomic-context bug in
+      service_outstanding_interrupt()"
+    - USB: remove LPM management from usb_driver_claim_interface()
+    - Input: elantech - enable middle button of touchpad on ThinkPad P72
+    - IB/srp: Avoid that sg_reset -d ${srp_device} triggers an infinite loop
+    - scsi: target: iscsi: Use bin2hex instead of a re-implementation
+    - serial: imx: restore handshaking irq for imx1
+    - arm64: KVM: Tighten guest core register access from userspace
+    - ext4: never move the system.data xattr out of the inode body
+    - thermal: of-thermal: disable passive polling when thermal zone is disabled
+    - net: hns: fix length and page_offset overflow when CONFIG_ARM64_64K_PAGES
+    - e1000: check on netif_running() before calling e1000_up()
+    - e1000: ensure to free old tx/rx rings in set_ringparam()
+    - hwmon: (ina2xx) fix sysfs shunt resistor read access
+    - hwmon: (adt7475) Make adt7475_read_word() return errors
+    - i2c: i801: Allow ACPI AML access I/O ports not reserved for SMBus
+    - arm64: cpufeature: Track 32bit EL0 support
+    - arm64: KVM: Sanitize PSTATE.M when being set from userspace
+    - media: v4l: event: Prevent freeing event subscriptions while accessed
+    - KVM: PPC: Book3S HV: Don't truncate HPTE index in xlate function
+    - mac80211: correct use of IEEE80211_VHT_CAP_RXSTBC_X
+    - mac80211_hwsim: correct use of IEEE80211_VHT_CAP_RXSTBC_X
+    - gpio: adp5588: Fix sleep-in-atomic-context bug
+    - mac80211: mesh: fix HWMP sequence numbering to follow standard
+    - cfg80211: nl80211_update_ft_ies() to validate NL80211_ATTR_IE
+    - RAID10 BUG_ON in raise_barrier when force is true and conf->barrier is 0
+    - i2c: uniphier: issue STOP only for last message or I2C_M_STOP
+    - i2c: uniphier-f: issue STOP only for last message or I2C_M_STOP
+    - net: cadence: Fix a sleep-in-atomic-context bug in macb_halt_tx()
+    - fs/cifs: don't translate SFM_SLASH (U+F026) to backslash
+    - cfg80211: fix a type issue in ieee80211_chandef_to_operating_class()
+    - mac80211: fix a race between restart and CSA flows
+    - mac80211: Fix station bandwidth setting after channel switch
+    - mac80211: shorten the IBSS debug messages
+    - tools/vm/slabinfo.c: fix sign-compare warning
+    - tools/vm/page-types.c: fix "defined but not used" warning
+    - mm: madvise(MADV_DODUMP): allow hugetlbfs pages
+    - usb: gadget: fotg210-udc: Fix memory leak of fotg210->ep[i]
+    - perf probe powerpc: Ignore SyS symbols irrespective of endianness
+    - RDMA/ucma: check fd type in ucma_migrate_id()
+    - USB: yurex: Check for truncation in yurex_read()
+    - drm/nouveau/TBDdevinit: don't fail when PMU/PRE_OS is missing from VBIOS
+    - fs/cifs: suppress a string overflow warning
+    - dm thin metadata: try to avoid ever aborting transactions
+    - arch/hexagon: fix kernel/dma.c build warning
+    - hexagon: modify ffs() and fls() to return int
+    - arm64: jump_label.h: use asm_volatile_goto macro instead of "asm goto"
+    - r8169: Clear RTL_FLAG_TASK_*_PENDING when clearing RTL_FLAG_TASK_ENABLED
+    - s390/qeth: don't dump past end of unknown HW header
+    - cifs: read overflow in is_valid_oplock_break()
+    - xen/manage: don't complain about an empty value in control/sysrq node
+    - xen: avoid crash in disable_hotplug_cpu
+    - xen: fix GCC warning and remove duplicate EVTCHN_ROW/EVTCHN_COL usage
+    - smb2: fix missing files in root share directory listing
+    - crypto: mxs-dcp - Fix wait logic on chan threads
+    - proc: restrict kernel stack dumps to root
+    - ocfs2: fix locking for res->tracking and dlm->tracking_list
+    - dm thin metadata: fix __udivdi3 undefined on 32-bit
+    - Linux 4.4.160
+
+  * Volume control not working Dell XPS 27 (7760) (LP: #1775068) // Xenial
+    update: 4.4.160 upstream stable release (LP: #1798770)
+    - ALSA: hda/realtek - Cannot adjust speaker's volume on Dell XPS 27 7760
+
+  * Xenial update: 4.4.160 upstream stable release (LP: #1798770) //
+    CVE-2018-7755
+    - floppy: Do not copy a kernel pointer to user memory in FDGETPRM ioctl
+
+  * Xenial update: 4.4.159 upstream stable release (LP: #1798617)
+    - NFC: Fix possible memory corruption when handling SHDLC I-Frame commands
+    - NFC: Fix the number of pipes
+    - ASoC: cs4265: fix MMTLR Data switch control
+    - ALSA: bebob: use address returned by kmalloc() instead of kernel stack for
+      streaming DMA mapping
+    - ALSA: emu10k1: fix possible info leak to userspace on
+      SNDRV_EMU10K1_IOCTL_INFO
+    - platform/x86: alienware-wmi: Correct a memory leak
+    - xen/netfront: don't bug in case of too many frags
+    - xen/x86/vpmu: Zero struct pt_regs before calling into sample handling code
+    - ring-buffer: Allow for rescheduling when removing pages
+    - mm: shmem.c: Correctly annotate new inodes for lockdep
+    - gso_segment: Reset skb->mac_len after modifying network header
+    - ipv6: fix possible use-after-free in ip6_xmit()
+    - net/appletalk: fix minor pointer leak to userspace in SIOCFINDIPDDPRT
+    - net: hp100: fix always-true check for link up state
+    - neighbour: confirm neigh entries when ARP packet is received
+    - ocfs2: fix ocfs2 read block panic
+    - drm/nouveau/drm/nouveau: Use pm_runtime_get_noresume() in connector_detect()
+    - tty: vt_ioctl: fix potential Spectre v1
+    - ext4: avoid divide by zero fault when deleting corrupted inline directories
+    - ext4: recalucate superblock checksum after updating free blocks/inodes
+    - ext4: fix online resize's handling of a too-small final block group
+    - ext4: fix online resizing for bigalloc file systems with a 1k block size
+    - ext4: don't mark mmp buffer head dirty
+    - arm64: Add trace_hardirqs_off annotation in ret_to_user
+    - HID: sony: Update device ids
+    - HID: sony: Support DS4 dongle
+    - iw_cxgb4: only allow 1 flush on user qps
+    - Linux 4.4.159
+
+  * Xenial update: 4.4.158 upstream stable release (LP: #1798587)
+    - iommu/arm-smmu-v3: sync the OVACKFLG to PRIQ consumer register
+    - ALSA: msnd: Fix the default sample sizes
+    - ALSA: usb-audio: Fix multiple definitions in AU0828_DEVICE() macro
+    - xfrm: fix 'passing zero to ERR_PTR()' warning
+    - gfs2: Special-case rindex for gfs2_grow
+    - clk: imx6ul: fix missing of_node_put()
+    - kbuild: add .DELETE_ON_ERROR special target
+    - dmaengine: pl330: fix irq race with terminate_all
+    - MIPS: ath79: fix system restart
+    - media: videobuf2-core: check for q->error in vb2_core_qbuf()
+    - mtd/maps: fix solutionengine.c printk format warnings
+    - fbdev: omapfb: off by one in omapfb_register_client()
+    - video: goldfishfb: fix memory leak on driver remove
+    - fbdev/via: fix defined but not used warning
+    - perf powerpc: Fix callchain ip filtering when return address is in a
+      register
+    - fbdev: Distinguish between interlaced and progressive modes
+    - ARM: exynos: Clear global variable on init error path
+    - perf powerpc: Fix callchain ip filtering
+    - powerpc/powernv: opal_put_chars partial write fix
+    - MIPS: jz4740: Bump zload address
+    - mac80211: restrict delayed tailroom needed decrement
+    - xen-netfront: fix queue name setting
+    - arm64: dts: qcom: db410c: Fix Bluetooth LED trigger
+    - s390/qeth: fix race in used-buffer accounting
+    - s390/qeth: reset layer2 attribute on layer switch
+    - platform/x86: toshiba_acpi: Fix defined but not used build warnings
+    - crypto: sharah - Unregister correct algorithms for SAHARA 3
+    - xen-netfront: fix warn message as irq device name has '/'
+    - RDMA/cma: Protect cma dev list with lock
+    - pstore: Fix incorrect persistent ram buffer mapping
+    - xen/netfront: fix waiting for xenbus state change
+    - IB/ipoib: Avoid a race condition between start_xmit and cm_rep_handler
+    - Tools: hv: Fix a bug in the key delete code
+    - misc: hmc6352: fix potential Spectre v1
+    - usb: Don't die twice if PCI xhci host is not responding in resume
+    - USB: Add quirk to support DJI CineSSD
+    - usb: Avoid use-after-free by flushing endpoints early in usb_set_interface()
+    - usb: host: u132-hcd: Fix a sleep-in-atomic-context bug in u132_get_frame()
+    - USB: add quirk for WORLDE Controller KS49 or Prodipe MIDI 49C USB controller
+    - USB: net2280: Fix erroneous synchronization change
+    - USB: serial: io_ti: fix array underflow in completion handler
+    - usb: misc: uss720: Fix two sleep-in-atomic-context bugs
+    - USB: yurex: Fix buffer over-read in yurex_write()
+    - usb: cdc-wdm: Fix a sleep-in-atomic-context bug in
+      service_outstanding_interrupt()
+    - cifs: prevent integer overflow in nxt_dir_entry()
+    - CIFS: fix wrapping bugs in num_entries()
+    - binfmt_elf: Respect error return from `regset->active'
+    - audit: fix use-after-free in audit_add_watch
+    - mtdchar: fix overflows in adjustment of `count`
+    - MIPS: loongson64: cs5536: Fix PCI_OHCI_INT_REG reads
+    - ARM: hisi: handle of_iomap and fix missing of_node_put
+    - ARM: hisi: fix error handling and missing of_node_put
+    - ARM: hisi: check of_iomap and fix missing of_node_put
+    - drm/nouveau: tegra: Detach from ARM DMA/IOMMU mapping
+    - parport: sunbpp: fix error return code
+    - coresight: Handle errors in finding input/output ports
+    - coresight: tpiu: Fix disabling timeouts
+    - gpiolib: Mark gpio_suffixes array with __maybe_unused
+    - drm/amdkfd: Fix error codes in kfd_get_process
+    - rtc: bq4802: add error handling for devm_ioremap
+    - ALSA: pcm: Fix snd_interval_refine first/last with open min/max
+    - selftest: timers: Tweak raw_skew to SKIP when ADJ_OFFSET/other clock
+      adjustments are in progress
+    - drm/panel: type promotion bug in s6e8aa0_read_mtp_id()
+    - pinctrl: qcom: spmi-gpio: Fix pmic_gpio_config_get() to be compliant
+    - USB: serial: ti_usb_3410_5052: fix array underflow in completion handler
+    - mei: bus: type promotion bug in mei_nfc_if_version()
+    - drivers: net: cpsw: fix segfault in case of bad phy-handle
+    - MIPS: VDSO: Match data page cache colouring when D$ aliases
+    - Linux 4.4.158
+
+  * Xenial update: 4.4.157 upstream stable release (LP: #1798539)
+    - i2c: xiic: Make the start and the byte count write atomic
+    - i2c: i801: fix DNV's SMBCTRL register offset
+    - ALSA: hda - Fix cancel_work_sync() stall from jackpoll work
+    - cfq: Give a chance for arming slice idle timer in case of group_idle
+    - kthread: Fix use-after-free if kthread fork fails
+    - kthread: fix boot hang (regression) on MIPS/OpenRISC
+    - staging: rt5208: Fix a sleep-in-atomic bug in xd_copy_page
+    - staging/rts5208: Fix read overflow in memcpy
+    - block,blkcg: use __GFP_NOWARN for best-effort allocations in blkcg
+    - locking/rwsem-xadd: Fix missed wakeup due to reordering of load
+    - selinux: use GFP_NOWAIT in the AVC kmem_caches
+    - locking/osq_lock: Fix osq_lock queue corruption
+    - ARC: [plat-axs*]: Enable SWAP
+    - misc: mic: SCIF Fix scif_get_new_port() error handling
+    - ethtool: Remove trailing semicolon for static inline
+    - gpio: tegra: Move driver registration to subsys_init level
+    - scsi: target: fix __transport_register_session locking
+    - md/raid5: fix data corruption of replacements after originals dropped
+    - misc: ti-st: Fix memory leak in the error path of probe()
+    - uio: potential double frees if __uio_register_device() fails
+    - tty: rocket: Fix possible buffer overwrite on register_PCI
+    - f2fs: do not set free of current section
+    - perf tools: Allow overriding MAX_NR_CPUS at compile time
+    - NFSv4.0 fix client reference leak in callback
+    - macintosh/via-pmu: Add missing mmio accessors
+    - ath10k: prevent active scans on potential unusable channels
+    - MIPS: Fix ISA virt/bus conversion for non-zero PHYS_OFFSET
+    - ata: libahci: Correct setting of DEVSLP register
+    - scsi: 3ware: fix return 0 on the error path of probe
+    - ath10k: disable bundle mgmt tx completion event support
+    - Bluetooth: hidp: Fix handling of strncpy for hid->name information
+    - x86/mm: Remove in_nmi() warning from vmalloc_fault()
+    - gpio: ml-ioh: Fix buffer underwrite on probe error path
+    - net: mvneta: fix mtu change on port without link
+    - MIPS: Octeon: add missing of_node_put()
+    - net: dcb: For wild-card lookups, use priority -1, not 0
+    - Input: atmel_mxt_ts - only use first T9 instance
+    - iommu/ipmmu-vmsa: Fix allocation in atomic context
+    - mfd: ti_am335x_tscadc: Fix struct clk memory leak
+    - f2fs: fix to do sanity check with {sit,nat}_ver_bitmap_bytesize
+    - MIPS: WARN_ON invalid DMA cache maintenance, not BUG_ON
+    - RDMA/cma: Do not ignore net namespace for unbound cm_id
+    - xhci: Fix use-after-free in xhci_free_virt_device
+    - vmw_balloon: include asm/io.h
+    - netfilter: x_tables: avoid stack-out-of-bounds read in
+      xt_copy_counters_from_user
+    - drivers: net: cpsw: fix parsing of phy-handle DT property in dual_emac
+      config
+    - net: ethernet: ti: cpsw: fix mdio device reference leak
+    - ethernet: ti: davinci_emac: add missing of_node_put after calling
+      of_parse_phandle
+    - crypto: vmx - Fix sleep-in-atomic bugs
+    - mtd: ubi: wl: Fix error return code in ubi_wl_init()
+    - autofs: fix autofs_sbi() does not check super block type
+    - Linux 4.4.157
+
+  * Xenial update: 4.4.156 upstream stable release (LP: #1797563)
+    - staging: android: ion: fix ION_IOC_{MAP,SHARE} use-after-free
+    - net: bcmgenet: use MAC link status for fixed phy
+    - qlge: Fix netdev features configuration.
+    - tcp: do not restart timewait timer on rst reception
+    - vti6: remove !skb->ignore_df check from vti6_xmit()
+    - cifs: check if SMB2 PDU size has been padded and suppress the warning
+    - hfsplus: don't return 0 when fill_super() failed
+    - hfs: prevent crash on exit from failed search
+    - fork: don't copy inconsistent signal handler state to child
+    - reiserfs: change j_timestamp type to time64_t
+    - hfsplus: fix NULL dereference in hfsplus_lookup()
+    - fat: validate ->i_start before using
+    - scripts: modpost: check memory allocation results
+    - mm/fadvise.c: fix signed overflow UBSAN complaint
+    - fs/dcache.c: fix kmemcheck splat at take_dentry_name_snapshot()
+    - ipvs: fix race between ip_vs_conn_new() and ip_vs_del_dest()
+    - mfd: sm501: Set coherent_dma_mask when creating subdevices
+    - platform/x86: asus-nb-wmi: Add keymap entry for lid flip action on UX360
+    - irqchip/bcm7038-l1: Hide cpu offline callback when building for !SMP
+    - net/9p: fix error path of p9_virtio_probe
+    - powerpc: Fix size calculation using resource_size()
+    - s390/dasd: fix hanging offline processing due to canceled worker
+    - scsi: aic94xx: fix an error code in aic94xx_init()
+    - PCI: mvebu: Fix I/O space end address calculation
+    - dm kcopyd: avoid softlockup in run_complete_job
+    - staging: comedi: ni_mio_common: fix subdevice flags for PFI subdevice
+    - selftests/powerpc: Kill child processes on SIGINT
+    - smb3: fix reset of bytes read and written stats
+    - SMB3: Number of requests sent should be displayed for SMB3 not just CIFS
+    - powerpc/pseries: Avoid using the size greater than RTAS_ERROR_LOG_MAX.
+    - btrfs: replace: Reset on-disk dev stats value after replace
+    - btrfs: relocation: Only remove reloc rb_trees if reloc control has been
+      initialized
+    - btrfs: Don't remove block group that still has pinned down bytes
+    - debugobjects: Make stack check warning more informative
+    - x86/pae: use 64 bit atomic xchg function in native_ptep_get_and_clear
+    - kbuild: make missing $DEPMOD a Warning instead of an Error
+    - Revert "ARM: imx_v6_v7_defconfig: Select ULPI support"
+    - enic: do not call enic_change_mtu in enic_probe
+    - Fixes: Commit cdbf92675fad ("mm: numa: avoid waiting on freed migrated
+      pages")
+    - genirq: Delay incrementing interrupt count if it's disabled/pending
+    - irqchip/gic-v3-its: Recompute the number of pages on page size change
+    - irqchip/gicv3-its: Fix memory leak in its_free_tables()
+    - irqchip/gicv3-its: Avoid cache flush beyond ITS_BASERn memory size
+    - irqchip/gic-v3: Add missing barrier to 32bit version of gic_read_iar()
+    - irqchip/gic: Make interrupt ID 1020 invalid
+    - ovl: rename is_merge to is_lowest
+    - ovl: override creds with the ones from the superblock mounter
+    - ovl: proper cleanup of workdir
+    - sch_htb: fix crash on init failure
+    - sch_multiq: fix double free on init failure
+    - sch_hhf: fix null pointer dereference on init failure
+    - sch_netem: avoid null pointer deref on init failure
+    - sch_tbf: fix two null pointer dereferences on init failure
+    - mei: me: allow runtime pm for platform with D0i3
+    - ASoC: wm8994: Fix missing break in switch
+    - btrfs: use correct compare function of dirty_metadata_bytes
+    - Linux 4.4.156
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 24 Oct 2018 09:57:17 +0000
+
+linux (4.4.0-138.164) xenial; urgency=medium
+
+  * linux: 4.4.0-138.164 -proposed tracker (LP: #1795582)
+
+  * Linux 4.4.155 stable release build is broken on ppc64 (LP: #1795662)
+    - powerpc/fadump: Return error when fadump registration fails
+
+  * Kernel hang on drive pull caused by regression introduced by commit
+    287922eb0b18 (LP: #1791790)
+    - block: Fix a race between blk_cleanup_queue() and timeout handling
+
+  * qeth: use vzalloc for QUERY OAT buffer (LP: #1793086)
+    - s390/qeth: use vzalloc for QUERY OAT buffer
+
+  * Page leaking in cachefiles_read_backing_file while vmscan is active
+    (LP: #1793430)
+    - SAUCE: cachefiles: Page leaking in cachefiles_read_backing_file while vmscan
+      is active
+
+  * Bugfix for handling of shadow doorbell buffer (LP: #1788222)
+    - nvme-pci: add a memory barrier to nvme_dbbuf_update_and_check_event
+
+  * Xenial update to 4.4.155 stable release (LP: #1792419)
+    - net: 6lowpan: fix reserved space for single frames
+    - net: mac802154: tx: expand tailroom if necessary
+    - 9p/net: Fix zero-copy path in the 9p virtio transport
+    - net: lan78xx: Fix misplaced tasklet_schedule() call
+    - spi: davinci: fix a NULL pointer dereference
+    - drm/i915/userptr: reject zero user_size
+    - powerpc/fadump: handle crash memory ranges array index overflow
+    - powerpc/pseries: Fix endianness while restoring of r3 in MCE handler.
+    - fs/9p/xattr.c: catch the error of p9_client_clunk when setting xattr failed
+    - 9p/virtio: fix off-by-one error in sg list bounds check
+    - net/9p/client.c: version pointer uninitialized
+    - net/9p/trans_fd.c: fix race-condition by flushing workqueue before the
+      kfree()
+    - dm cache metadata: save in-core policy_hint_size to on-disk superblock
+    - iio: ad9523: Fix displayed phase
+    - iio: ad9523: Fix return value for ad952x_store()
+    - vmw_balloon: fix inflation of 64-bit GFNs
+    - vmw_balloon: do not use 2MB without batching
+    - vmw_balloon: VMCI_DOORBELL_SET does not check status
+    - vmw_balloon: fix VMCI use when balloon built into kernel
+    - tracing: Do not call start/stop() functions when tracing_on does not change
+    - tracing/blktrace: Fix to allow setting same value
+    - kthread, tracing: Don't expose half-written comm when creating kthreads
+    - uprobes: Use synchronize_rcu() not synchronize_sched()
+    - 9p: fix multiple NULL-pointer-dereferences
+    - PM / sleep: wakeup: Fix build error caused by missing SRCU support
+    - pnfs/blocklayout: off by one in bl_map_stripe()
+    - ARM: tegra: Fix Tegra30 Cardhu PCA954x reset
+    - mm/tlb: Remove tlb_remove_table() non-concurrent condition
+    - iommu/vt-d: Add definitions for PFSID
+    - iommu/vt-d: Fix dev iotlb pfsid use
+    - osf_getdomainname(): use copy_to_user()
+    - sys: don't hold uts_sem while accessing userspace memory
+    - userns: move user access out of the mutex
+    - ubifs: Fix memory leak in lprobs self-check
+    - Revert "UBIFS: Fix potential integer overflow in allocation"
+    - ubifs: Check data node size before truncate
+    - ubifs: Fix synced_i_size calculation for xattr inodes
+    - pwm: tiehrpwm: Fix disabling of output of PWMs
+    - fb: fix lost console when the user unplugs a USB adapter
+    - udlfb: set optimal write delay
+    - getxattr: use correct xattr length
+    - bcache: release dc->writeback_lock properly in bch_writeback_thread()
+    - perf auxtrace: Fix queue resize
+    - fs/quota: Fix spectre gadget in do_quotactl
+    - x86/io: add interface to reserve io memtype for a resource range. (v1.1)
+    - drm/drivers: add support for using the arch wc mapping API.
+    - Linux 4.4.155
+
+  * Xenial update to 4.4.154 stable release (LP: #1792392)
+    - sched/sysctl: Check user input value of sysctl_sched_time_avg
+    - Cipso: cipso_v4_optptr enter infinite loop
+    - vti6: fix PMTU caching and reporting on xmit
+    - xfrm: fix missing dst_release() after policy blocking lbcast and multicast
+    - xfrm: free skb if nlsk pointer is NULL
+    - mac80211: add stations tied to AP_VLANs during hw reconfig
+    - nl80211: Add a missing break in parse_station_flags
+    - drm/bridge: adv7511: Reset registers on hotplug
+    - scsi: libiscsi: fix possible NULL pointer dereference in case of TMF
+    - drm/imx: imx-ldb: disable LDB on driver bind
+    - drm/imx: imx-ldb: check if channel is enabled before printing warning
+    - usb: gadget: r8a66597: Fix two possible sleep-in-atomic-context bugs in
+      init_controller()
+    - usb: gadget: r8a66597: Fix a possible sleep-in-atomic-context bugs in
+      r8a66597_queue()
+    - usb/phy: fix PPC64 build errors in phy-fsl-usb.c
+    - tools: usb: ffs-test: Fix build on big endian systems
+    - usb: gadget: f_uac2: fix endianness of 'struct cntrl_*_lay3'
+    - tools/power turbostat: fix -S on UP systems
+    - net: caif: Add a missing rcu_read_unlock() in caif_flow_cb
+    - qed: Fix possible race for the link state value.
+    - atl1c: reserve min skb headroom
+    - net: prevent ISA drivers from building on PPC32
+    - can: mpc5xxx_can: check of_iomap return before use
+    - i2c: davinci: Avoid zero value of CLKH
+    - media: staging: omap4iss: Include asm/cacheflush.h after generic includes
+    - bnx2x: Fix invalid memory access in rss hash config path.
+    - net: axienet: Fix double deregister of mdio
+    - selftests/ftrace: Add snapshot and tracing_on test case
+    - zswap: re-check zswap_is_full() after do zswap_shrink()
+    - tools/power turbostat: Read extended processor family from CPUID
+    - Revert "MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum"
+    - enic: handle mtu change for vf properly
+    - arc: fix build errors in arc/include/asm/delay.h
+    - arc: fix type warnings in arc/mm/cache.c
+    - drivers: net: lmc: fix case value for target abort error
+    - scsi: fcoe: drop frames in ELS LOGO error path
+    - scsi: vmw_pvscsi: Return DID_RESET for status SAM_STAT_COMMAND_TERMINATED
+    - mm/memory.c: check return value of ioremap_prot
+    - cifs: add missing debug entries for kconfig options
+    - cifs: check kmalloc before use
+    - smb3: Do not send SMB3 SET_INFO if nothing changed
+    - smb3: don't request leases in symlink creation and query
+    - btrfs: don't leak ret from do_chunk_alloc
+    - s390/kvm: fix deadlock when killed by oom
+    - ext4: check for NUL characters in extended attribute's name
+    - ext4: sysfs: print ext4_super_block fields as little-endian
+    - ext4: reset error code in ext4_find_entry in fallback
+    - arm64: mm: check for upper PAGE_SHIFT bits in pfn_valid()
+    - KVM: arm/arm64: Skip updating PTE entry if no change
+    - KVM: arm/arm64: Skip updating PMD entry if no change
+    - x86/speculation/l1tf: Suggest what to do on systems with too much RAM
+    - x86/process: Re-export start_thread()
+    - fuse: Don't access pipe->buffers without pipe_lock()
+    - fuse: fix double request_end()
+    - fuse: fix unlocked access to processing queue
+    - fuse: umount should wait for all requests
+    - fuse: Fix oops at process_init_reply()
+    - fuse: Add missed unlock_page() to fuse_readpages_fill()
+    - udl-kms: change down_interruptible to down
+    - udl-kms: handle allocation failure
+    - udl-kms: fix crash due to uninitialized memory
+    - ASoC: dpcm: don't merge format from invalid codec dai
+    - ASoC: sirf: Fix potential NULL pointer dereference
+    - pinctrl: freescale: off by one in imx1_pinconf_group_dbg_show()
+    - x86/irqflags: Mark native_restore_fl extern inline
+    - s390: fix br_r1_trampoline for machines without exrl
+    - s390/qdio: reset old sbal_state flags
+    - kprobes: Make list and blacklist root user read only
+    - MIPS: Correct the 64-bit DSP accumulator register size
+    - MIPS: lib: Provide MIPS64r6 __multi3() for GCC < 7
+    - scsi: sysfs: Introduce sysfs_{un,}break_active_protection()
+    - scsi: core: Avoid that SCSI device removal through sysfs triggers a deadlock
+    - iscsi target: fix session creation failure handling
+    - cdrom: Fix info leak/OOB read in cdrom_ioctl_drive_status
+    - Linux 4.4.154
+
+  * Xenial update to 4.4.153 stable release (LP: #1792383)
+    - x86/mm: Fix use-after-free of ldt_struct
+    - ovl: Ensure upper filesystem supports d_type
+    - ovl: Do d_type check only if work dir creation was successful
+    - ovl: warn instead of error if d_type is not supported
+    - Linux 4.4.153
+
+  * Xenial update to 4.4.152 stable release (LP: #1792377)
+    - ARC: Explicitly add -mmedium-calls to CFLAGS
+    - netfilter: ipv6: nf_defrag: reduce struct net memory waste
+    - selftests: pstore: return Kselftest Skip code for skipped tests
+    - selftests: static_keys: return Kselftest Skip code for skipped tests
+    - selftests: user: return Kselftest Skip code for skipped tests
+    - selftests: zram: return Kselftest Skip code for skipped tests
+    - selftests: sync: add config fragment for testing sync framework
+    - ARM: dts: Cygnus: Fix I2C controller interrupt type
+    - usb: dwc2: fix isoc split in transfer with no data
+    - usb: gadget: composite: fix delayed_status race condition when set_interface
+    - usb: gadget: dwc2: fix memory leak in gadget_init()
+    - scsi: xen-scsifront: add error handling for xenbus_printf
+    - arm64: make secondary_start_kernel() notrace
+    - qed: Add sanity check for SIMD fastpath handler.
+    - enic: initialize enic->rfs_h.lock in enic_probe
+    - net: hamradio: use eth_broadcast_addr
+    - net: propagate dev_get_valid_name return code
+    - ARC: Enable machine_desc->init_per_cpu for !CONFIG_SMP
+    - net: davinci_emac: match the mdio device against its compatible if possible
+    - locking/lockdep: Do not record IRQ state within lockdep code
+    - ipv6: mcast: fix unsolicited report interval after receiving querys
+    - Smack: Mark inode instant in smack_task_to_inode
+    - cxgb4: when disabling dcb set txq dcb priority to 0
+    - brcmfmac: stop watchdog before detach and free everything
+    - ARM: dts: am437x: make edt-ft5x06 a wakeup source
+    - usb: xhci: increase CRS timeout value
+    - perf test session topology: Fix test on s390
+    - perf report powerpc: Fix crash if callchain is empty
+    - selftests/x86/sigreturn/64: Fix spurious failures on AMD CPUs
+    - ARM: dts: da850: Fix interrups property for gpio
+    - dmaengine: k3dma: Off by one in k3_of_dma_simple_xlate()
+    - md/raid10: fix that replacement cannot complete recovery after reassemble
+    - drm/exynos: gsc: Fix support for NV16/61, YUV420/YVU420 and YUV422 modes
+    - drm/exynos: decon5433: Fix per-plane global alpha for XRGB modes
+    - drm/exynos: decon5433: Fix WINCONx reset value
+    - bnx2x: Fix receiving tx-timeout in error or recovery state.
+    - m68k: fix "bad page state" oops on ColdFire boot
+    - HID: wacom: Correct touch maximum XY of 2nd-gen Intuos
+    - ARM: imx_v6_v7_defconfig: Select ULPI support
+    - ARM: imx_v4_v5_defconfig: Select ULPI support
+    - tracing: Use __printf markup to silence compiler
+    - kasan: fix shadow_size calculation error in kasan_module_alloc
+    - smsc75xx: Add workaround for gigabit link up hardware errata.
+    - netfilter: x_tables: set module owner for icmp(6) matches
+    - ARM: pxa: irq: fix handling of ICMR registers in suspend/resume
+    - ieee802154: at86rf230: switch from BUG_ON() to WARN_ON() on problem
+    - ieee802154: at86rf230: use __func__ macro for debug messages
+    - ieee802154: fakelb: switch from BUG_ON() to WARN_ON() on problem
+    - drm/armada: fix colorkey mode property
+    - bnxt_en: Fix for system hang if request_irq fails
+    - perf llvm-utils: Remove bashism from kernel include fetch script
+    - ARM: 8780/1: ftrace: Only set kernel memory back to read-only after boot
+    - ARM: dts: am3517.dtsi: Disable reference to OMAP3 OTG controller
+    - ixgbe: Be more careful when modifying MAC filters
+    - packet: reset network header if packet shorter than ll reserved space
+    - qlogic: check kstrtoul() for errors
+    - tcp: remove DELAYED ACK events in DCTCP
+    - drm/nouveau/gem: off by one bugs in nouveau_gem_pushbuf_reloc_apply()
+    - net/ethernet/freescale/fman: fix cross-build error
+    - net: usb: rtl8150: demote allmulti message to dev_dbg()
+    - net: qca_spi: Avoid packet drop during initial sync
+    - net: qca_spi: Make sure the QCA7000 reset is triggered
+    - net: qca_spi: Fix log level if probe fails
+    - tcp: identify cryptic messages as TCP seq # bugs
+    - staging: android: ion: check for kref overflow
+    - KVM: irqfd: fix race between EPOLLHUP and irq_bypass_register_consumer
+    - ext4: fix spectre gadget in ext4_mb_regular_allocator()
+    - parisc: Remove ordered stores from syscall.S
+    - xfrm_user: prevent leaking 2 bytes of kernel memory
+    - netfilter: conntrack: dccp: treat SYNC/SYNCACK as invalid if no prior state
+    - packet: refine ring v3 block size test to hold one frame
+    - bridge: Propagate vlan add failure to user
+    - parisc: Remove unnecessary barriers from spinlock.h
+    - PCI: hotplug: Don't leak pci_slot on registration failure
+    - PCI: Skip MPS logic for Virtual Functions (VFs)
+    - PCI: pciehp: Fix use-after-free on unplug
+    - i2c: imx: Fix race condition in dma read
+    - reiserfs: fix broken xattr handling (heap corruption, bad retval)
+    - Linux 4.4.152
+
+  * Xenial update to 4.4.151 stable release (LP: #1792340)
+    - dccp: fix undefined behavior with 'cwnd' shift in ccid2_cwnd_restart()
+    - l2tp: use sk_dst_check() to avoid race on sk->sk_dst_cache
+    - llc: use refcount_inc_not_zero() for llc_sap_find()
+    - net_sched: Fix missing res info when create new tc_index filter
+    - vsock: split dwork to avoid reinitializations
+    - net_sched: fix NULL pointer dereference when delete tcindex filter
+    - ALSA: hda - Sleep for 10ms after entering D3 on Conexant codecs
+    - ALSA: hda - Turn CX8200 into D3 as well upon reboot
+    - ALSA: vx222: Fix invalid endian conversions
+    - ALSA: virmidi: Fix too long output trigger loop
+    - ALSA: cs5535audio: Fix invalid endian conversion
+    - ALSA: hda: Correct Asrock B85M-ITX power_save blacklist entry
+    - ALSA: memalloc: Don't exceed over the requested size
+    - ALSA: vxpocket: Fix invalid endian conversions
+    - USB: serial: sierra: fix potential deadlock at close
+    - USB: option: add support for DW5821e
+    - ACPI: save NVS memory for Lenovo G50-45
+    - ACPI / PM: save NVS memory for ASUS 1025C laptop
+    - serial: 8250_dw: always set baud rate in dw8250_set_termios
+    - Bluetooth: avoid killing an already killed socket
+    - isdn: Disable IIOCDBGVAR
+    - Linux 4.4.151
+
+  * Xenial update to 4.4.150 stable release (LP: #1792336)
+    - x86/speculation/l1tf: Exempt zeroed PTEs from inversion
+    - Linux 4.4.150
+
+  * Xenial update to 4.4.149 stable release (LP: #1792310)
+    - x86/mm: Disable ioremap free page handling on x86-PAE
+    - tcp: Fix missing range_truesize enlargement in the backport
+    - kasan: don't emit builtin calls when sanitization is off
+    - i2c: ismt: fix wrong device address when unmap the data buffer
+    - kbuild: verify that $DEPMOD is installed
+    - crypto: vmac - require a block cipher with 128-bit block size
+    - crypto: vmac - separate tfm and request context
+    - crypto: blkcipher - fix crash flushing dcache in error path
+    - crypto: ablkcipher - fix crash flushing dcache in error path
+    - ASoC: Intel: cht_bsw_max98090_ti: Fix jack initialization
+    - ioremap: Update pgtable free interfaces with addr
+    - x86/mm: Add TLB purge to free pmd/pte page interfaces
+    - Linux 4.4.149
+
+  * Xenial update to 4.4.149 stable release (LP: #1792310) // CVE-2018-9363
+    - Bluetooth: hidp: buffer overflow in hidp_process_report
+
+  * Xenial update to 4.4.148 stable release (LP: #1792174)
+    - ext4: fix check to prevent initializing reserved inodes
+    - tpm: fix race condition in tpm_common_write()
+    - ipv4+ipv6: Make INET*_ESP select CRYPTO_ECHAINIV
+    - fork: unconditionally clear stack on fork
+    - parisc: Enable CONFIG_MLONGCALLS by default
+    - parisc: Define mb() and add memory barriers to assembler unlock sequences
+    - xen/netfront: don't cache skb_shinfo()
+    - ACPI / LPSS: Add missing prv_offset setting for byt/cht PWM devices
+    - scsi: sr: Avoid that opening a CD-ROM hangs with runtime power management
+      enabled
+    - root dentries need RCU-delayed freeing
+    - fix mntput/mntput race
+    - fix __legitimize_mnt()/mntput() race
+    - IB/core: Make testing MR flags for writability a static inline function
+    - IB/mlx4: Mark user MR as writable if actual virtual memory is writable
+    - IB/ocrdma: fix out of bounds access to local buffer
+    - ARM: dts: imx6sx: fix irq for pcie bridge
+    - kprobes/x86: Fix %p uses in error messages
+    - x86/irqflags: Provide a declaration for native_save_fl
+    - SAUCE: Sync pgtable_64.h with upstream stable
+    - mm: x86: move _PAGE_SWP_SOFT_DIRTY from bit 7 to bit 1
+    - SAUCE: Sync pgtable-3level.h with upstream stable
+    - SAUCE: Sync pgtable.h with upstream stable
+    - mm: Add vm_insert_pfn_prot()
+    - mm: fix cache mode tracking in vm_insert_mixed()
+    - x86/mm/kmmio: Make the tracer robust against L1TF
+    - x86/init: fix build with CONFIG_SWAP=n
+    - Linux 4.4.148
+
+  * Xenial update to 4.4.147 stable release (LP: #1792109)
+    - scsi: qla2xxx: Fix ISP recovery on unload
+    - scsi: qla2xxx: Return error when TMF returns
+    - genirq: Make force irq threading setup more robust
+    - nohz: Fix local_timer_softirq_pending()
+    - netlink: Do not subscribe to non-existent groups
+    - netlink: Don't shift with UB on nlk->ngroups
+    - netlink: Don't shift on 64 for ngroups
+    - ACPI / PCI: Bail early in acpi_pci_add_bus() if there is no ACPI handle
+    - ring_buffer: tracing: Inherit the tracing setting to next ring buffer
+    - i2c: imx: Fix reinit_completion() use
+    - Linux 4.4.147
+
+  * Xenial update to 4.4.146 stable release (LP: #1791953)
+    - MIPS: Fix off-by-one in pci_resource_to_user()
+    - Input: elan_i2c - add ACPI ID for lenovo ideapad 330
+    - Input: i8042 - add Lenovo LaVie Z to the i8042 reset list
+    - Input: elan_i2c - add another ACPI ID for Lenovo Ideapad 330-15AST
+    - tracing: Fix double free of event_trigger_data
+    - tracing: Fix possible double free in event_enable_trigger_func()
+    - tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure
+    - tracing: Quiet gcc warning about maybe unused link variable
+    - xen/netfront: raise max number of slots in xennet_get_responses()
+    - ALSA: emu10k1: add error handling for snd_ctl_add
+    - ALSA: fm801: add error handling for snd_ctl_add
+    - nfsd: fix potential use-after-free in nfsd4_decode_getdeviceinfo
+    - mm: vmalloc: avoid racy handling of debugobjects in vunmap
+    - mm/slub.c: add __printf verification to slab_err()
+    - rtc: ensure rtc_set_alarm fails when alarms are not supported
+    - netfilter: ipset: List timing out entries with "timeout 1" instead of zero
+    - infiniband: fix a possible use-after-free bug
+    - hvc_opal: don't set tb_ticks_per_usec in udbg_init_opal_common()
+    - powerpc/64s: Fix compiler store ordering to SLB shadow area
+    - RDMA/mad: Convert BUG_ONs to error flows
+    - disable loading f2fs module on PAGE_SIZE > 4KB
+    - f2fs: fix to don't trigger writeback during recovery
+    - usbip: usbip_detach: Fix memory, udev context and udev leak
+    - perf/x86/intel/uncore: Correct fixed counter index check in generic code
+    - perf/x86/intel/uncore: Correct fixed counter index check for NHM
+    - iwlwifi: pcie: fix race in Rx buffer allocator
+    - Bluetooth: hci_qca: Fix "Sleep inside atomic section" warning
+    - Bluetooth: btusb: Add a new Realtek 8723DE ID 2ff8:b011
+    - ASoC: dpcm: fix BE dai not hw_free and shutdown
+    - mfd: cros_ec: Fail early if we cannot identify the EC
+    - mwifiex: handle race during mwifiex_usb_disconnect
+    - wlcore: sdio: check for valid platform device data before suspend
+    - media: videobuf2-core: don't call memop 'finish' when queueing
+    - btrfs: add barriers to btrfs_sync_log before log_commit_wait wakeups
+    - btrfs: qgroup: Finish rescan when hit the last leaf of extent tree
+    - PCI: Prevent sysfs disable of device while driver is attached
+    - ath: Add regulatory mapping for FCC3_ETSIC
+    - ath: Add regulatory mapping for ETSI8_WORLD
+    - ath: Add regulatory mapping for APL13_WORLD
+    - ath: Add regulatory mapping for APL2_FCCA
+    - ath: Add regulatory mapping for Uganda
+    - ath: Add regulatory mapping for Tanzania
+    - ath: Add regulatory mapping for Serbia
+    - ath: Add regulatory mapping for Bermuda
+    - ath: Add regulatory mapping for Bahamas
+    - powerpc/32: Add a missing include header
+    - powerpc/chrp/time: Make some functions static, add missing header include
+    - powerpc/powermac: Add missing prototype for note_bootable_part()
+    - powerpc/powermac: Mark variable x as unused
+    - powerpc/8xx: fix invalid register expression in head_8xx.S
+    - pinctrl: at91-pio4: add missing of_node_put
+    - PCI: pciehp: Request control of native hotplug only if supported
+    - mwifiex: correct histogram data with appropriate index
+    - scsi: ufs: fix exception event handling
+    - ALSA: emu10k1: Rate-limit error messages about page errors
+    - regulator: pfuze100: add .is_enable() for pfuze100_swb_regulator_ops
+    - md: fix NULL dereference of mddev->pers in remove_and_add_spares()
+    - media: smiapp: fix timeout checking in smiapp_read_nvm
+    - ALSA: usb-audio: Apply rate limit to warning messages in URB complete
+      callback
+    - HID: hid-plantronics: Re-resend Update to map button for PTT products
+    - drm/radeon: fix mode_valid's return type
+    - powerpc/embedded6xx/hlwd-pic: Prevent interrupts from being handled by
+      Starlet
+    - HID: i2c-hid: check if device is there before really probing
+    - tty: Fix data race in tty_insert_flip_string_fixed_flag
+    - dma-iommu: Fix compilation when !CONFIG_IOMMU_DMA
+    - media: rcar_jpu: Add missing clk_disable_unprepare() on error in jpu_open()
+    - libata: Fix command retry decision
+    - media: saa7164: Fix driver name in debug output
+    - mtd: rawnand: fsl_ifc: fix FSL NAND driver to read all ONFI parameter pages
+    - brcmfmac: Add support for bcm43364 wireless chipset
+    - s390/cpum_sf: Add data entry sizes to sampling trailer entry
+    - perf: fix invalid bit in diagnostic entry
+    - scsi: 3w-9xxx: fix a missing-check bug
+    - scsi: 3w-xxxx: fix a missing-check bug
+    - scsi: megaraid: silence a static checker bug
+    - thermal: exynos: fix setting rising_threshold for Exynos5433
+    - bpf: fix references to free_bpf_prog_info() in comments
+    - media: siano: get rid of __le32/__le16 cast warnings
+    - drm/atomic: Handling the case when setting old crtc for plane
+    - ALSA: hda/ca0132: fix build failure when a local macro is defined
+    - memory: tegra: Do not handle spurious interrupts
+    - memory: tegra: Apply interrupts mask per SoC
+    - drm/gma500: fix psb_intel_lvds_mode_valid()'s return type
+    - ipconfig: Correctly initialise ic_nameservers
+    - rsi: Fix 'invalid vdd' warning in mmc
+    - audit: allow not equal op for audit by executable
+    - microblaze: Fix simpleImage format generation
+    - usb: hub: Don't wait for connect state at resume for powered-off ports
+    - crypto: authencesn - don't leak pointers to authenc keys
+    - crypto: authenc - don't leak pointers to authenc keys
+    - media: omap3isp: fix unbalanced dma_iommu_mapping
+    - scsi: scsi_dh: replace too broad "TP9" string with the exact models
+    - scsi: megaraid_sas: Increase timeout by 1 sec for non-RAID fastpath IOs
+    - media: si470x: fix __be16 annotations
+    - drm: Add DP PSR2 sink enable bit
+    - random: mix rdrand with entropy sent in from userspace
+    - squashfs: be more careful about metadata corruption
+    - ext4: fix inline data updates with checksums enabled
+    - ext4: check for allocation block validity with block group locked
+    - dmaengine: pxa_dma: remove duplicate const qualifier
+    - ASoC: pxa: Fix module autoload for platform drivers
+    - ipv4: remove BUG_ON() from fib_compute_spec_dst
+    - net: fix amd-xgbe flow-control issue
+    - net: lan78xx: fix rx handling before first packet is send
+    - xen-netfront: wait xenbus state change when load module manually
+    - NET: stmmac: align DMA stuff to largest cache line length
+    - tcp: do not force quickack when receiving out-of-order packets
+    - tcp: add max_quickacks param to tcp_incr_quickack and
+      tcp_enter_quickack_mode
+    - tcp: do not aggressively quick ack after ECN events
+    - tcp: refactor tcp_ecn_check_ce to remove sk type cast
+    - tcp: add one more quick ack after after ECN events
+    - inet: frag: enforce memory limits earlier
+    - net: dsa: Do not suspend/resume closed slave_dev
+    - netlink: Fix spectre v1 gadget in netlink_create()
+    - squashfs: more metadata hardening
+    - squashfs: more metadata hardenings
+    - can: ems_usb: Fix memory leak on ems_usb_disconnect()
+    - net: socket: fix potential spectre v1 gadget in socketcall
+    - virtio_balloon: fix another race between migration and ballooning
+    - kvm: x86: vmx: fix vpid leak
+    - crypto: padlock-aes - Fix Nano workaround data corruption
+    - scsi: sg: fix minor memory leak in error path
+    - Linux 4.4.146
+
+  * Xenial update to 4.4.145 stable release (LP: #1791942)
+    - MIPS: ath79: fix register address in ath79_ddr_wb_flush()
+    - ip: hash fragments consistently
+    - net/mlx4_core: Save the qpn from the input modifier in RST2INIT wrapper
+    - rtnetlink: add rtnl_link_state check in rtnl_configure_link
+    - tcp: fix dctcp delayed ACK schedule
+    - tcp: helpers to send special DCTCP ack
+    - tcp: do not cancel delay-AcK on DCTCP special ACK
+    - tcp: do not delay ACK in DCTCP upon CE status change
+    - ip: in cmsg IP(V6)_ORIGDSTADDR call pskb_may_pull
+    - usb: cdc_acm: Add quirk for Castles VEGA3000
+    - usb: core: handle hub C_PORT_OVER_CURRENT condition
+    - usb: gadget: f_fs: Only return delayed status when len is 0
+    - driver core: Partially revert "driver core: correct device's shutdown order"
+    - can: xilinx_can: fix RX loop if RXNEMP is asserted without RXOK
+    - can: xilinx_can: fix recovery from error states not being propagated
+    - can: xilinx_can: fix device dropping off bus on RX overrun
+    - can: xilinx_can: keep only 1-2 frames in TX FIFO to fix TX accounting
+    - can: xilinx_can: fix incorrect clear of non-processed interrupts
+    - can: xilinx_can: fix RX overflow interrupt not being enabled
+    - turn off -Wattribute-alias
+    - ARM: fix put_user() for gcc-8
+    - Linux 4.4.145
+
+  * kernel panic - null pointer dereference on ipset operations (LP: #1793753)
+    - netfilter: ipset: fix race condition in ipset save, swap and delete
+    - netfilter: ipset: Fix race between dump and swap
+
+  * Improvements to the kernel source package preparation (LP: #1793461)
+    - [Packaging] startnewrelease: add support for backport kernels
+
+  * update ENA driver to latest mainline version (LP: #1792044)
+    - net: ena: Remove redundant unlikely()
+    - net: ena: reduce the severity of some printouts
+    - net: ena: fix rare kernel crash when bar memory remap fails
+    - net: ena: fix wrong max Tx/Rx queues on ethtool
+    - net: ena: improve ENA driver boot time.
+    - net: ena: remove legacy suspend suspend/resume support
+    - net: ena: add power management ops to the ENA driver
+    - net: ena: add statistics for missed tx packets
+    - net: ena: add new admin define for future support of IPv6 RSS
+    - net: ena: increase ena driver version to 1.3.0
+    - net: ena: fix race condition between device reset and link up setup
+    - net: ena: add detection and recovery mechanism for handling missed/misrouted
+      MSI-X
+    - net: ena: increase ena driver version to 1.5.0
+    - net: ena: fix error handling in ena_down() sequence
+    - net: ena: Eliminate duplicate barriers on weakly-ordered archs
+    - SAUCE: ena: devm_kzalloc() -> devm_kcalloc()
+    - net: ena: Fix use of uninitialized DMA address bits field
+    - net: ena: fix surprise unplug NULL dereference kernel crash
+    - net: ena: fix driver when PAGE_SIZE == 64kB
+    - net: ena: fix device destruction to gracefully free resources
+    - net: ena: fix potential double ena_destroy_device()
+    - net: ena: fix missing lock during device destruction
+    - net: ena: fix missing calls to READ_ONCE
+    - net: ena: fix incorrect usage of memory barriers
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 02 Oct 2018 14:39:36 +0000
+
+linux (4.4.0-137.163) xenial; urgency=medium
+
+  * CVE-2018-14633
+    - iscsi target: Use hex2bin instead of a re-implementation
+
+  * CVE-2018-17182
+    - mm: get rid of vmacache_flush_all() entirely
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 24 Sep 2018 13:39:05 +0200
+
+linux (4.4.0-136.162) xenial; urgency=medium
+
+  * linux: 4.4.0-136.162 -proposed tracker (LP: #1791745)
+
+  * CVE-2017-5753
+    - bpf: properly enforce index mask to prevent out-of-bounds speculation
+    - Revert "UBUNTU: SAUCE: bpf: Use barrier_nospec() instead of osb()"
+    - Revert "bpf: prevent speculative execution in eBPF interpreter"
+
+  * L1TF mitigation not effective in some CPU and RAM combinations
+    (LP: #1788563) // CVE-2018-3620 // CVE-2018-3646
+    - x86/speculation/l1tf: Fix overflow in l1tf_pfn_limit() on 32bit
+    - x86/speculation/l1tf: Fix off-by-one error when warning that system has too
+      much RAM
+    - x86/speculation/l1tf: Increase l1tf memory limit for Nehalem+
+
+  * CVE-2018-15594
+    - x86/paravirt: Fix spectre-v2 mitigations for paravirt guests
+
+  * Xenial update to 4.4.144 stable release (LP: #1791080)
+    - KVM/Eventfd: Avoid crash when assign and deassign specific eventfd in
+      parallel.
+    - x86/MCE: Remove min interval polling limitation
+    - fat: fix memory allocation failure handling of match_strdup()
+    - ALSA: rawmidi: Change resized buffers atomically
+    - ARC: Fix CONFIG_SWAP
+    - ARC: mm: allow mprotect to make stack mappings executable
+    - mm: memcg: fix use after free in mem_cgroup_iter()
+    - ipv4: Return EINVAL when ping_group_range sysctl doesn't map to user ns
+    - ipv6: fix useless rol32 call on hash
+    - lib/rhashtable: consider param->min_size when setting initial table size
+    - net/ipv4: Set oif in fib_compute_spec_dst
+    - net: phy: fix flag masking in __set_phy_supported
+    - ptp: fix missing break in switch
+    - tg3: Add higher cpu clock for 5762.
+    - net: Don't copy pfmemalloc flag in __copy_skb_header()
+    - skbuff: Unconditionally copy pfmemalloc in __skb_clone()
+    - xhci: Fix perceived dead host due to runtime suspend race with event handler
+    - x86/paravirt: Make native_save_fl() extern inline
+    - SAUCE: Add missing CPUID_7_EDX defines
+    - SAUCE: x86/speculation: Expose indirect_branch_prediction_barrier()
+    - x86/pti: Mark constant arrays as __initconst
+    - x86/asm/entry/32: Simplify pushes of zeroed pt_regs->REGs
+    - x86/entry/64/compat: Clear registers for compat syscalls, to reduce
+      speculation attack surface
+    - x86/speculation: Clean up various Spectre related details
+    - x86/speculation: Fix up array_index_nospec_mask() asm constraint
+    - x86/xen: Zero MSR_IA32_SPEC_CTRL before suspend
+    - x86/mm: Factor out LDT init from context init
+    - x86/mm: Give each mm TLB flush generation a unique ID
+    - SAUCE: x86/speculation: Use Indirect Branch Prediction Barrier in context
+      switch
+    - x86/speculation: Use IBRS if available before calling into firmware
+    - x86/speculation: Move firmware_restrict_branch_speculation_*() from C to CPP
+    - selftest/seccomp: Fix the seccomp(2) signature
+    - xen: set cpu capabilities from xen_start_kernel()
+    - x86/amd: don't set X86_BUG_SYSRET_SS_ATTRS when running under Xen
+    - SAUCE: Preserve SPEC_CTRL MSR in new inlines
+    - SAUCE: Add Knights Mill to NO SSB list
+    - x86/process: Correct and optimize TIF_BLOCKSTEP switch
+    - x86/process: Optimize TIF_NOTSC switch
+    - Revert "x86/cpufeatures: Add FEATURE_ZEN"
+    - Revert "x86/cpu/AMD: Fix erratum 1076 (CPB bit)"
+    - x86/cpu/AMD: Fix erratum 1076 (CPB bit)
+    - x86/cpufeatures: Add FEATURE_ZEN
+    - x86/xen: Add call of speculative_store_bypass_ht_init() to PV paths
+    - x86/cpu: Re-apply forced caps every time CPU caps are re-read
+    - block: do not use interruptible wait anywhere
+    - clk: tegra: Fix PLL_U post divider and initial rate on Tegra30
+    - ubi: Introduce vol_ignored()
+    - ubi: Rework Fastmap attach base code
+    - ubi: Be more paranoid while seaching for the most recent Fastmap
+    - ubi: Fix races around ubi_refill_pools()
+    - ubi: Fix Fastmap's update_vol()
+    - ubi: fastmap: Erase outdated anchor PEBs during attach
+    - Linux 4.4.144
+
+  * CVE-2017-5715 (Spectre v2 s390x)
+    - s390: detect etoken facility
+    - s390/lib: use expoline for all bcr instructions
+    - SAUCE: s390: use expoline thunks for all branches generated by the BPF JIT
+
+  * Xenial update to 4.4.143 stable release (LP: #1790884)
+    - compiler, clang: suppress warning for unused static inline functions
+    - compiler, clang: properly override 'inline' for clang
+    - compiler, clang: always inline when CONFIG_OPTIMIZE_INLINING is disabled
+    - compiler-gcc.h: Add __attribute__((gnu_inline)) to all inline declarations
+    - x86/asm: Add _ASM_ARG* constants for argument registers to <asm/asm.h>
+    - ocfs2: subsystem.su_mutex is required while accessing the item->ci_parent
+    - bcm63xx_enet: correct clock usage
+    - bcm63xx_enet: do not write to random DMA channel on BCM6345
+    - crypto: crypto4xx - remove bad list_del
+    - crypto: crypto4xx - fix crypto4xx_build_pdr, crypto4xx_build_sdr leak
+    - atm: zatm: Fix potential Spectre v1
+    - net: dccp: avoid crash in ccid3_hc_rx_send_feedback()
+    - net: dccp: switch rx_tstamp_last_feedback to monotonic clock
+    - net/mlx5: Fix incorrect raw command length parsing
+    - net: sungem: fix rx checksum support
+    - qed: Limit msix vectors in kdump kernel to the minimum required count.
+    - r8152: napi hangup fix after disconnect
+    - tcp: fix Fast Open key endianness
+    - tcp: prevent bogus FRTO undos with non-SACK flows
+    - vhost_net: validate sock before trying to put its fd
+    - net_sched: blackhole: tell upper qdisc about dropped packets
+    - net/mlx5: Fix command interface race in polling mode
+    - net: cxgb3_main: fix potential Spectre v1
+    - rtlwifi: rtl8821ae: fix firmware is not ready to run
+    - MIPS: Call dump_stack() from show_regs()
+    - MIPS: Use async IPIs for arch_trigger_cpumask_backtrace()
+    - netfilter: ebtables: reject non-bridge targets
+    - KEYS: DNS: fix parsing multiple options
+    - rds: avoid unenecessary cong_update in loop transport
+    - net/nfc: Avoid stalls when nfc_alloc_send_skb() returned NULL.
+    - Linux 4.4.143
+
+  * Xenial update to 4.4.142 stable release (LP: #1790883)
+    - Kbuild: fix # escaping in .cmd files for future Make
+    - perf tools: Move syscall number fallbacks from perf-sys.h to
+      tools/arch/x86/include/asm/
+    - Linux 4.4.142
+
+  * Xenial update to 4.4.141 stable release (LP: #1790620)
+    - MIPS: Fix ioremap() RAM check
+    - ibmasm: don't write out of bounds in read handler
+    - vmw_balloon: fix inflation with batching
+    - ahci: Disable LPM on Lenovo 50 series laptops with a too old BIOS
+    - USB: serial: ch341: fix type promotion bug in ch341_control_in()
+    - USB: serial: cp210x: add another USB ID for Qivicon ZigBee stick
+    - USB: serial: keyspan_pda: fix modem-status error handling
+    - USB: yurex: fix out-of-bounds uaccess in read handler
+    - USB: serial: mos7840: fix status-register error handling
+    - usb: quirks: add delay quirks for Corsair Strafe
+    - xhci: xhci-mem: off by one in xhci_stream_id_to_ring()
+    - HID: usbhid: add quirk for innomedia INNEX GENESIS/ATARI adapter
+    - tools build: fix # escaping in .cmd files for future Make
+    - iw_cxgb4: correctly enforce the max reg_mr depth
+    - x86/cpufeature: Move some of the scattered feature bits to x86_capability
+    - x86/cpu: Provide a config option to disable static_cpu_has
+    - x86/fpu: Add an XSTATE_OP() macro
+    - x86/fpu: Get rid of xstate_fault()
+    - x86/headers: Don't include asm/processor.h in asm/atomic.h
+    - x86/cpufeature: Replace the old static_cpu_has() with safe variant
+    - x86/cpufeature: Get rid of the non-asm goto variant
+    - x86/alternatives: Add an auxilary section
+    - x86/alternatives: Discard dynamic check after init
+    - x86/vdso: Use static_cpu_has()
+    - x86/boot: Simplify kernel load address alignment check
+    - x86/cpufeature: Speed up cpu_feature_enabled()
+    - x86/cpufeature, x86/mm/pkeys: Add protection keys related CPUID definitions
+    - x86/mm/pkeys: Fix mismerge of protection keys CPUID bits
+    - x86/cpu: Add detection of AMD RAS Capabilities
+    - x86/cpufeature, x86/mm/pkeys: Fix broken compile-time disabling of pkeys
+    - x86/cpufeature: Make sure DISABLED/REQUIRED macros are updated
+    - x86/cpufeature: Add helper macro for mask check macros
+    - uprobes/x86: Remove incorrect WARN_ON() in uprobe_init_insn()
+    - netfilter: nf_queue: augment nfqa_cfg_policy
+    - netfilter: x_tables: initialise match/target check parameter struct
+    - loop: add recursion validation to LOOP_CHANGE_FD
+    - PM / hibernate: Fix oops at snapshot_write()
+    - SAUCE: RDMA/ucm: Blacklist UCM module
+    - loop: remember whether sysfs_create_group() was done
+    - Linux 4.4.141
+    - [Config] Refresh configs for 4.4.141
+
+  * regression with EXT4 file systems and meta_bg flag (LP: #1789653)
+    - ext4: fix false negatives *and* false positives in ext4_check_descriptors()
+
+  * CVE-2018-15572
+    - x86/speculation: Protect against userspace-userspace spectreRSB
+
+  * random oopses on s390 systems using NVMe devices (LP: #1790480)
+    - s390/pci: fix out of bounds access during irq setup
+
+  * CVE-2018-6555
+    - SAUCE: irda: Only insert new objects into the global database via setsockopt
+
+  * CVE-2018-6554
+    - SAUCE: irda: Fix memory leak caused by repeated binds of irda socket
+
+  * errors when scanning partition table of corrupted AIX disk (LP: #1787281)
+    - partitions/aix: fix usage of uninitialized lv_info and lvname structures
+    - partitions/aix: append null character to print data from disk
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 11 Sep 2018 15:50:12 +0200
+
+linux (4.4.0-135.161) xenial; urgency=medium
+
+  * linux: 4.4.0-135.161 -proposed tracker (LP: #1788766)
+
+  * [Regression] APM Merlin boards fail to recover link after interface down/up
+    (LP: #1785739)
+    - net: phylib: fix interrupts re-enablement in phy_start
+    - net: phy: fix phy_start to consider PHY_IGNORE_INTERRUPT
+
+  * qeth: don't clobber buffer on async TX completion (LP: #1786057)
+    - s390/qeth: don't clobber buffer on async TX completion
+
+  * nvme: avoid cqe corruption (LP: #1788035)
+    - nvme: avoid cqe corruption when update at the same time as read
+
+  * CacheFiles: Error: Overlong wait for old active object to go away.
+    (LP: #1776254)
+    - cachefiles: Fix missing clear of the CACHEFILES_OBJECT_ACTIVE flag
+    - cachefiles: Wait rather than BUG'ing on "Unexpected object collision"
+
+  * fscache cookie refcount updated incorrectly during fscache object allocation
+    (LP: #1776277) // fscache cookie refcount updated incorrectly during fscache
+    object allocation (LP: #1776277)
+    - fscache: Fix reference overput in fscache_attach_object() error handling
+
+  * FS-Cache: Assertion failed: FS-Cache: 6 == 5 is false (LP: #1774336)
+    - Revert "UBUNTU: SAUCE: CacheFiles: fix a read_waiter/read_copier race"
+    - fscache: Allow cancelled operations to be enqueued
+    - cachefiles: Fix refcounting bug in backing-file read monitoring
+
+  * linux-cloud-tools-common: Ensure hv-kvp-daemon.service starts before
+    walinuxagent.service (LP: #1739107)
+    - [Debian] hyper-v -- Ensure that hv-kvp-daemon.service starts before
+      walinuxagent.service
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sun, 26 Aug 2018 23:56:50 -0400
+
+linux (4.4.0-134.160) xenial; urgency=medium
+
+  * linux: 4.4.0-134.160 -proposed tracker (LP: #1787177)
+
+  * locking sockets broken due to missing AppArmor socket mediation patches
+    (LP: #1780227)
+    - UBUNTU SAUCE: apparmor: fix apparmor mediating locking non-fs, unix sockets
+
+  * Backport namespaced fscaps to xenial 4.4 (LP: #1778286)
+    - Introduce v3 namespaced file capabilities
+    - commoncap: move assignment of fs_ns to avoid null pointer dereference
+    - capabilities: fix buffer overread on very short xattr
+    - commoncap: Handle memory allocation failure.
+
+  * Xenial update to 4.4.140 stable release (LP: #1784409)
+    - usb: cdc_acm: Add quirk for Uniden UBC125 scanner
+    - USB: serial: cp210x: add CESINEL device ids
+    - USB: serial: cp210x: add Silicon Labs IDs for Windows Update
+    - n_tty: Fix stall at n_tty_receive_char_special().
+    - staging: android: ion: Return an ERR_PTR in ion_map_kernel
+    - n_tty: Access echo_* variables carefully.
+    - x86/boot: Fix early command-line parsing when matching at end
+    - ath10k: fix rfc1042 header retrieval in QCA4019 with eth decap mode
+    - i2c: rcar: fix resume by always initializing registers before transfer
+    - ipv4: Fix error return value in fib_convert_metrics()
+    - kprobes/x86: Do not modify singlestep buffer while resuming
+    - nvme-pci: initialize queue memory before interrupts
+    - netfilter: nf_tables: use WARN_ON_ONCE instead of BUG_ON in nft_do_chain()
+    - ARM: dts: imx6q: Use correct SDMA script for SPI5 core
+    - ubi: fastmap: Correctly handle interrupted erasures in EBA
+    - mm: hugetlb: yield when prepping struct pages
+    - tracing: Fix missing return symbol in function_graph output
+    - scsi: sg: mitigate read/write abuse
+    - s390: Correct register corruption in critical section cleanup
+    - drbd: fix access after free
+    - cifs: Fix infinite loop when using hard mount option
+    - jbd2: don't mark block as modified if the handle is out of credits
+    - ext4: make sure bitmaps and the inode table don't overlap with bg
+      descriptors
+    - ext4: always check block group bounds in ext4_init_block_bitmap()
+    - ext4: only look at the bg_flags field if it is valid
+    - ext4: verify the depth of extent tree in ext4_find_extent()
+    - ext4: include the illegal physical block in the bad map ext4_error msg
+    - ext4: clear i_data in ext4_inode_info when removing inline data
+    - ext4: add more inode number paranoia checks
+    - ext4: add more mount time checks of the superblock
+    - ext4: check superblock mapped prior to committing
+    - HID: i2c-hid: Fix "incomplete report" noise
+    - HID: hiddev: fix potential Spectre v1
+    - HID: debug: check length before copy_to_user()
+    - x86/mce: Detect local MCEs properly
+    - x86/mce: Fix incorrect "Machine check from unknown source" message
+    - media: cx25840: Use subdev host data for PLL override
+    - mm, page_alloc: do not break __GFP_THISNODE by zonelist reset
+    - dm bufio: avoid sleeping while holding the dm_bufio lock
+    - dm bufio: drop the lock when doing GFP_NOIO allocation
+    - mtd: rawnand: mxc: set spare area size register explicitly
+    - dm bufio: don't take the lock in dm_bufio_shrink_count
+    - mtd: cfi_cmdset_0002: Change definition naming to retry write operation
+    - mtd: cfi_cmdset_0002: Change erase functions to retry for error
+    - mtd: cfi_cmdset_0002: Change erase functions to check chip good only
+    - netfilter: nf_log: don't hold nf_log_mutex during user access
+    - staging: comedi: quatech_daqp_cs: fix no-op loop daqp_ao_insn_write()
+    - Linux 4.4.140
+
+  * Xenial update to 4.4.139 stable release (LP: #1784382)
+    - xfrm6: avoid potential infinite loop in _decode_session6()
+    - netfilter: ebtables: handle string from userspace with care
+    - ipvs: fix buffer overflow with sync daemon and service
+    - atm: zatm: fix memcmp casting
+    - net: qmi_wwan: Add Netgear Aircard 779S
+    - net/sonic: Use dma_mapping_error()
+    - Revert "Btrfs: fix scrub to repair raid6 corruption"
+    - tcp: do not overshoot window_clamp in tcp_rcv_space_adjust()
+    - Btrfs: make raid6 rebuild retry more
+    - usb: musb: fix remote wakeup racing with suspend
+    - bonding: re-evaluate force_primary when the primary slave name changes
+    - tcp: verify the checksum of the first data segment in a new connection
+    - ext4: update mtime in ext4_punch_hole even if no blocks are released
+    - ext4: fix fencepost error in check for inode count overflow during resize
+    - driver core: Don't ignore class_dir_create_and_add() failure.
+    - btrfs: scrub: Don't use inode pages for device replace
+    - ALSA: hda - Handle kzalloc() failure in snd_hda_attach_pcm_stream()
+    - ALSA: hda: add dock and led support for HP EliteBook 830 G5
+    - ALSA: hda: add dock and led support for HP ProBook 640 G4
+    - cpufreq: Fix new policy initialization during limits updates via sysfs
+    - libata: zpodd: make arrays cdb static, reduces object code size
+    - libata: zpodd: small read overflow in eject_tray()
+    - libata: Drop SanDisk SD7UB3Q*G1001 NOLPM quirk
+    - w1: mxc_w1: Enable clock before calling clk_get_rate() on it
+    - x86/spectre_v1: Disable compiler optimizations over
+      array_index_mask_nospec()
+    - m68k/mm: Adjust VM area to be unmapped by gap size for __iounmap()
+    - serial: sh-sci: Use spin_{try}lock_irqsave instead of open coding version
+    - signal/xtensa: Consistenly use SIGBUS in do_unaligned_user
+    - usb: do not reset if a low-speed or full-speed device timed out
+    - 1wire: family module autoload fails because of upper/lower case mismatch.
+    - ASoC: dapm: delete dapm_kcontrol_data paths list before freeing it
+    - ASoC: cirrus: i2s: Fix LRCLK configuration
+    - ASoC: cirrus: i2s: Fix {TX|RX}LinCtrlData setup
+    - lib/vsprintf: Remove atomic-unsafe support for %pCr
+    - mips: ftrace: fix static function graph tracing
+    - branch-check: fix long->int truncation when profiling branches
+    - ipmi:bt: Set the timeout before doing a capabilities check
+    - Bluetooth: hci_qca: Avoid missing rampatch failure with userspace fw loader
+    - fuse: atomic_o_trunc should truncate pagecache
+    - fuse: don't keep dead fuse_conn at fuse_fill_super().
+    - fuse: fix control dir setup and teardown
+    - powerpc/mm/hash: Add missing isync prior to kernel stack SLB switch
+    - powerpc/ptrace: Fix setting 512B aligned breakpoints with
+      PTRACE_SET_DEBUGREG
+    - powerpc/ptrace: Fix enforcement of DAWR constraints
+    - cpuidle: powernv: Fix promotion from snooze if next state disabled
+    - powerpc/fadump: Unregister fadump on kexec down path.
+    - ARM: 8764/1: kgdb: fix NUMREGBYTES so that gdb_regs[] is the correct size
+    - of: unittest: for strings, account for trailing \0 in property length field
+    - IB/qib: Fix DMA api warning with debug kernel
+    - RDMA/mlx4: Discard unknown SQP work requests
+    - mtd: cfi_cmdset_0002: Change write buffer to check correct value
+    - mtd: cfi_cmdset_0002: Use right chip in do_ppb_xxlock()
+    - mtd: cfi_cmdset_0002: fix SEGV unlocking multiple chips
+    - mtd: cfi_cmdset_0002: Fix unlocking requests crossing a chip boudary
+    - mtd: cfi_cmdset_0002: Avoid walking all chips when unlocking.
+    - MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum
+    - PCI: pciehp: Clear Presence Detect and Data Link Layer Status Changed on
+      resume
+    - MIPS: io: Add barrier after register read in inX()
+    - time: Make sure jiffies_to_msecs() preserves non-zero time periods
+    - Btrfs: fix clone vs chattr NODATASUM race
+    - iio:buffer: make length types match kfifo types
+    - scsi: qla2xxx: Fix setting lower transfer speed if GPSC fails
+    - scsi: zfcp: fix missing SCSI trace for result of eh_host_reset_handler
+    - scsi: zfcp: fix missing SCSI trace for retry of abort / scsi_eh TMF
+    - scsi: zfcp: fix misleading REC trigger trace where erp_action setup failed
+    - scsi: zfcp: fix missing REC trigger trace on terminate_rport_io early return
+    - scsi: zfcp: fix missing REC trigger trace on terminate_rport_io for
+      ERP_FAILED
+    - scsi: zfcp: fix missing REC trigger trace for all objects in ERP_FAILED
+    - scsi: zfcp: fix missing REC trigger trace on enqueue without ERP thread
+    - linvdimm, pmem: Preserve read-only setting for pmem devices
+    - md: fix two problems with setting the "re-add" device state.
+    - ubi: fastmap: Cancel work upon detach
+    - UBIFS: Fix potential integer overflow in allocation
+    - xfrm: skip policies marked as dead while rehashing
+    - backlight: as3711_bl: Fix Device Tree node lookup
+    - backlight: max8925_bl: Fix Device Tree node lookup
+    - backlight: tps65217_bl: Fix Device Tree node lookup
+    - mfd: intel-lpss: Program REMAP register in PIO mode
+    - perf tools: Fix symbol and object code resolution for vdso32 and vdsox32
+    - perf intel-pt: Fix sync_switch INTEL_PT_SS_NOT_TRACING
+    - perf intel-pt: Fix decoding to accept CBR between FUP and corresponding TIP
+    - perf intel-pt: Fix MTC timing after overflow
+    - perf intel-pt: Fix "Unexpected indirect branch" error
+    - perf intel-pt: Fix packet decoding of CYC packets
+    - media: v4l2-compat-ioctl32: prevent go past max size
+    - media: dvb_frontend: fix locking issues at dvb_frontend_get_event()
+    - nfsd: restrict rd_maxcount to svc_max_payload in nfsd_encode_readdir
+    - NFSv4: Fix possible 1-byte stack overflow in
+      nfs_idmap_read_and_verify_message
+    - video: uvesafb: Fix integer overflow in allocation
+    - Input: elan_i2c - add ELAN0618 (Lenovo v330 15IKB) ACPI ID
+    - xen: Remove unnecessary BUG_ON from __unbind_from_irq()
+    - udf: Detect incorrect directory size
+    - Input: elan_i2c_smbus - fix more potential stack buffer overflows
+    - Input: elantech - enable middle button of touchpads on ThinkPad P52
+    - Input: elantech - fix V4 report decoding for module with middle key
+    - ALSA: hda/realtek - Add a quirk for FSC ESPRIMO U9210
+    - Btrfs: fix unexpected cow in run_delalloc_nocow
+    - spi: Fix scatterlist elements size in spi_map_buf
+    - block: Fix transfer when chunk sectors exceeds max
+    - dm thin: handle running out of data space vs concurrent discard
+    - cdc_ncm: avoid padding beyond end of skb
+    - Bluetooth: Fix connection if directed advertising and privacy is used
+    - Linux 4.4.139
+
+  * Support AverMedia DVD EZMaker 7 USB video capture dongle (LP: #1620762) //
+    Xenial update to 4.4.139 stable release (LP: #1784382)
+    - media: cx231xx: Add support for AverMedia DVD EZMaker 7
+
+  * vfio/pci: cannot assign a i40e pf device to a vm using vfio-pci
+    (LP: #1779830)
+    - vfio/pci: Hide broken INTx support from user
+
+  * Kernel error "task zfs:pid blocked for more than 120 seconds" (LP: #1781364)
+    - SAUCE: (noup) zfs to 0.6.5.6-0ubuntu25
+
+  * Allow multiple mounts of zfs datasets (LP: #1759848)
+    - SAUCE: Allow mounting datasets more than once (LP: #1759848)
+
+  * CVE-2018-12233
+    - jfs: Fix inconsistency between memory allocation and ea_buf->max_size
+
+  * Redpine: Observed kernel panic while running wireless tests in regression
+    mode (LP: #1773410) // Redpine: Observed kernel panic while running soft-ap
+    tests (LP: #1777850)
+    - SAUCE: Redpine: improve cancel_hw_scan handling to fix kernel panic
+
+  * [HMS] Upgrades to Support SocketCAN over USB on Dell IoT 300x Gateways
+    (LP: #1783241)
+    - SAUCE: (no-up) upgrade IXXAT USB SocketCAN driver
+
+  * CVE-2018-13094
+    - xfs: don't call xfs_da_shrink_inode with NULL bp
+
+  * other users' coredumps can be read via setgid directory and killpriv bypass
+    (LP: #1779923) // CVE-2018-13405
+    - Fix up non-directory creation in SGID directories
+
+  * snapcraft.yaml: missing ubuntu-retpoline-extract-one script breaks the build
+    (LP: #1782116)
+    - snapcraft.yaml: copy retpoline-extract-one to scripts before build
+
+  * Enable basic support for Solarflare 8000 series NIC (LP: #1783152)
+    - sfc: make TSO version a per-queue parameter
+    - sfc: Add PCI ID for Solarflare 8000 series 10/40G NIC
+
+  * Redpine: Observed kernel panic while running wireless regressions tests
+    (LP: #1777858)
+    - SAUCE: Redpine: improve kernel thread handling to fix kernel panic
+
+  * Xenial update to 4.4.138 stable release (LP: #1777389)
+    - x86: Remove unused function cpu_has_ht_siblings()
+    - x86/cpufeature: Remove unused and seldomly used cpu_has_xx macros
+    - x86/fpu: Disable AVX when eagerfpu is off
+    - x86/fpu: Revert ("x86/fpu: Disable AVX when eagerfpu is off")
+    - x86/fpu: Hard-disable lazy FPU mode
+    - af_key: Always verify length of provided sadb_key
+    - x86/crypto, x86/fpu: Remove X86_FEATURE_EAGER_FPU #ifdef from the crc32c
+      code
+    - gpio: No NULL owner
+    - Clarify (and fix) MAX_LFS_FILESIZE macros
+    - serial: samsung: fix maxburst parameter for DMA transactions
+    - vmw_balloon: fixing double free when batching mode is off
+    - Input: goodix - add new ACPI id for GPD Win 2 touch screen
+    - crypto: vmx - Remove overly verbose printk from AES init routines
+    - Linux 4.4.138
+
+  * Redpine: wifi-ap stopped working after restart (LP: #1773400)
+    - SAUCE: Redpine: fix soft-ap invisible issue
+
+  * Xenial update to 4.4.137 stable release (LP: #1777063)
+    - tpm: do not suspend/resume if power stays on
+    - tpm: self test failure should not cause suspend to fail
+    - mmap: introduce sane default mmap limits
+    - mmap: relax file size limit for regular files
+    - kconfig: Avoid format overflow warning from GCC 8.1
+    - xfs: fix incorrect log_flushed on fsync
+    - drm: set FMODE_UNSIGNED_OFFSET for drm files
+    - brcmfmac: Fix check for ISO3166 code
+    - bnx2x: use the right constant
+    - dccp: don't free ccid2_hc_tx_sock struct in dccp_disconnect()
+    - enic: set DMA mask to 47 bit
+    - ip6mr: only set ip6mr_table from setsockopt when ip6mr_new_table succeeds
+    - ipv4: remove warning in ip_recv_error
+    - isdn: eicon: fix a missing-check bug
+    - netdev-FAQ: clarify DaveM's position for stable backports
+    - net/packet: refine check for priv area size
+    - net: usb: cdc_mbim: add flag FLAG_SEND_ZLP
+    - packet: fix reserve calculation
+    - qed: Fix mask for physical address in ILT entry
+    - net/mlx4: Fix irq-unsafe spinlock usage
+    - team: use netdev_features_t instead of u32
+    - rtnetlink: validate attributes in do_setlink()
+    - net: phy: broadcom: Fix bcm_write_exp()
+    - net: metrics: add proper netlink validation
+    - Linux 4.4.137
+
+  * Xenial update to 4.4.136 stable release (LP: #1776177)
+    - arm64: lse: Add early clobbers to some input/output asm operands
+    - powerpc/64s: Clear PCR on boot
+    - USB: serial: cp210x: use tcflag_t to fix incompatible pointer type
+    - sh: New gcc support
+    - xfs: detect agfl count corruption and reset agfl
+    - Input: elan_i2c_smbus - fix corrupted stack
+    - tracing: Fix crash when freeing instances with event triggers
+    - selinux: KASAN: slab-out-of-bounds in xattr_getsecurity
+    - cfg80211: further limit wiphy names to 64 bytes
+    - rtlwifi: rtl8192cu: Remove variable self-assignment in rf.c
+    - ASoC: Intel: sst: remove redundant variable dma_dev_name
+    - irda: fix overly long udelay()
+    - tcp: avoid integer overflows in tcp_rcv_space_adjust()
+    - i2c: rcar: make sure clocks are on when doing clock calculation
+    - i2c: rcar: rework hw init
+    - i2c: rcar: remove unused IOERROR state
+    - i2c: rcar: remove spinlock
+    - i2c: rcar: refactor setup of a msg
+    - i2c: rcar: init new messages in irq
+    - i2c: rcar: don't issue stop when HW does it automatically
+    - i2c: rcar: check master irqs before slave irqs
+    - i2c: rcar: revoke START request early
+    - dmaengine: usb-dmac: fix endless loop in usb_dmac_chan_terminate_all()
+    - iio:kfifo_buf: check for uint overflow
+    - MIPS: ptrace: Fix PTRACE_PEEKUSR requests for 64-bit FGRs
+    - MIPS: prctl: Disallow FRE without FR with PR_SET_FP_MODE requests
+    - scsi: scsi_transport_srp: Fix shost to rport translation
+    - stm class: Use vmalloc for the master map
+    - hwtracing: stm: fix build error on some arches
+    - drm/i915: Disable LVDS on Radiant P845
+    - Kbuild: change CC_OPTIMIZE_FOR_SIZE definition
+    - [Config] Add CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+    - fix io_destroy()/aio_complete() race
+    - mm: fix the NULL mapping case in __isolate_lru_page()
+    - sparc64: Fix build warnings with gcc 7.
+    - Linux 4.4.136
+
+  * Xenial update to 4.4.135 stable release (LP: #1776158)
+    - Revert "vti4: Don't override MTU passed on link creation via IFLA_MTU"
+    - Linux 4.4.135
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 15 Aug 2018 13:51:11 +0000
+
+linux (4.4.0-133.159) xenial; urgency=medium
+
+  * CVE-2018-5390
+    - tcp: avoid collapses in tcp_prune_queue() if possible
+    - tcp: detect malicious patterns in tcp_collapse_ofo_queue()
+
+  * CVE-2018-5391
+    - Revert "net: increase fragment memory usage limits"
+
+  * CVE-2018-3620 // CVE-2018-3646
+    - KVM: x86: introduce linear_{read,write}_system
+    - KVM: x86: pass kvm_vcpu to kvm_read_guest_virt and
+      kvm_write_guest_virt_system
+    - kvm: x86: use correct privilege level for sgdt/sidt/fxsave/fxrstor access
+    - x86/speculation/l1tf: Increase 32bit PAE __PHYSICAL_PAGE_SHIFT
+    - x86/speculation/l1tf: Change order of offset/type in swap entry
+    - x86/speculation/l1tf: Protect swap entries against L1TF
+    - x86/mm: Simplify p[g4um]d_page() macros
+    - x86/speculation/l1tf: Protect PROT_NONE PTEs against speculation
+    - x86/speculation/l1tf: Make sure the first page is always reserved
+    - SAUCE: x86/cpu: Add Knights Mill/Gemini Lake
+    - x86/speculation/l1tf: Add sysfs reporting for l1tf
+    - x86/speculation/l1tf: Disallow non privileged high MMIO PROT_NONE mappings
+    - x86/speculation/l1tf: Limit swap file size to MAX_PA/2
+    - x86/smp: Provide topology_is_primary_thread()
+    - x86/topology: Provide topology_smt_supported()
+    - cpu/hotplug: Split do_cpu_down()
+    - x86/topology: Add topology_max_smt_threads()
+    - cpu/hotplug: Provide knobs to control SMT
+    - x86/CPU: Modify detect_extended_topology() to return result
+    - x86/cpu: Remove the pointless CPU printout
+    - x86/cpu/AMD: Remove the pointless detect_ht() call
+    - x86/cpu/common: Provide detect_ht_early()
+    - x86/cpu/topology: Provide detect_extended_topology_early()
+    - x86/cpu/intel: Evaluate smp_num_siblings early
+    - x86/cpu/AMD: Evaluate smp_num_siblings early
+    - x86/apic: Ignore secondary threads if nosmt=force
+    - x86/speculation/l1tf: Extend 64bit swap file size limit
+    - x86/CPU/AMD: Move TOPOEXT reenablement before reading smp_num_siblings
+    - x86/cpufeatures: Add detection of L1D cache flush support.
+    - x86/speculation/l1tf: Protect PAE swap entries against L1TF
+    - x86/speculation/l1tf: Fix up pte->pfn conversion for PAE
+    - Revert "x86/apic: Ignore secondary threads if nosmt=force"
+    - SAUCE: x86/mce: register mce notifier earlier
+    - cpu/hotplug: Boot HT siblings at least once
+    - KVM: x86: Introducing kvm_x86_ops VM init/destroy hooks
+    - x86/KVM: Warn user if KVM is loaded SMT and L1TF CPU bug being present.
+    - x86/KVM/VMX: Add module argument for L1TF mitigation
+    - x86/KVM/VMX: Add L1D flush algorithm
+    - x86/KVM/VMX: Add L1D MSR based flush
+    - x86/KVM/VMX: Add L1D flush logic
+    - x86/KVM/VMX: Split the VMX MSR LOAD structures to have an host/guest numbers
+    - x86/KVM/VMX: Add find_msr() helper function
+    - x86/KVM/VMX: Seperate the VMX AUTOLOAD guest/host number accounting.
+    - x86/KVM/VMX: Extend add_atomic_switch_msr() to allow VMENTER only MSRs
+    - x86/KVM/VMX: Use MSR save list for IA32_FLUSH_CMD if required
+    - cpu/hotplug: Online siblings when SMT control is turned on
+    - x86/litf: Introduce vmx status variable
+    - x86/kvm: Drop L1TF MSR list approach
+    - x86/l1tf: Handle EPT disabled state proper
+    - x86/kvm: Move l1tf setup function
+    - x86/kvm: Add static key for flush always
+    - x86/kvm: Serialize L1D flush parameter setter
+    - x86/kvm: Allow runtime control of L1D flush
+    - cpu/hotplug: Expose SMT control init function
+    - cpu/hotplug: Set CPU_SMT_NOT_SUPPORTED early
+    - x86/bugs, kvm: Introduce boot-time control of L1TF mitigations
+    - Documentation: Add section about CPU vulnerabilities
+    - x86/speculation/l1tf: Unbreak !__HAVE_ARCH_PFN_MODIFY_ALLOWED architectures
+    - x86/KVM/VMX: Initialize the vmx_l1d_flush_pages' content
+    - Documentation/l1tf: Fix typos
+    - cpu/hotplug: detect SMT disabled by BIOS
+    - x86/KVM/VMX: Don't set l1tf_flush_l1d to true from vmx_l1d_flush()
+    - x86/KVM/VMX: Replace 'vmx_l1d_flush_always' with 'vmx_l1d_flush_cond'
+    - x86/KVM/VMX: Move the l1tf_flush_l1d test to vmx_l1d_flush()
+    - x86/irq: Demote irq_cpustat_t::__softirq_pending to u16
+    - x86/KVM/VMX: Introduce per-host-cpu analogue of l1tf_flush_l1d
+    - x86: Don't include linux/irq.h from asm/hardirq.h
+    - x86/apic: Order irq_enter/exit() calls correctly vs. ack_APIC_irq()
+    - x86/irq: Let interrupt handlers set kvm_cpu_l1tf_flush_l1d
+    - x86/KVM/VMX: Don't set l1tf_flush_l1d from vmx_handle_external_intr()
+    - Documentation/l1tf: Remove Yonah processors from not vulnerable list
+    - x86/speculation: Simplify sysfs report of VMX L1TF vulnerability
+    - x86/speculation: Use ARCH_CAPABILITIES to skip L1D flush on vmentry
+    - KVM/VMX: Emulate MSR_IA32_ARCH_CAPABILITIES
+    - KVM: x86: Add a framework for supporting MSR-based features
+    - KVM: X86: Introduce kvm_get_msr_feature()
+    - KVM: VMX: support MSR_IA32_ARCH_CAPABILITIES as a feature MSR
+    - KVM: VMX: Tell the nested hypervisor to skip L1D flush on vmentry
+    - cpu/hotplug: Fix SMT supported evaluation
+    - x86/speculation/l1tf: Invert all not present mappings
+    - x86/speculation/l1tf: Make pmd/pud_mknotpresent() invert
+    - x86/mm/pat: Ensure cpa->pfn only contains page frame numbers
+    - SAUCE: Add pfn_pud() and pud_mkhuge()
+    - x86/mm/pat: Make set_memory_np() L1TF safe
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 08 Aug 2018 12:04:38 +0200
+
+linux (4.4.0-131.157) xenial; urgency=medium
+
+  * linux: 4.4.0-131.157 -proposed tracker (LP: #1779376)
+
+  * Cannot set MTU higher than 1500 in Xen instance (LP: #1781413)
+    - xen-netfront: Fix mismatched rtnl_unlock
+    - xen-netfront: Update features after registering netdev
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 18 Jun 2018 17:00:46 +0200
+
+linux (4.4.0-130.156) xenial; urgency=medium
+
+  * linux: 4.4.0-130.156 -proposed tracker (LP: #1776822)
+
+  * CVE-2018-3665 (x86)
+    - x86/fpu: Fix early FPU command-line parsing
+    - x86/fpu: Fix 'no387' regression
+    - x86/fpu: Disable MPX when eagerfpu is off
+    - x86/fpu: Default eagerfpu=on on all CPUs
+    - x86/fpu: Fix FNSAVE usage in eagerfpu mode
+    - x86/fpu: Fix math emulation in eager fpu mode
+    - x86/fpu: Fix eager-FPU handling on legacy FPU machines
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 14 Jun 2018 06:53:41 +0200
+
+linux (4.4.0-129.155) xenial; urgency=medium
+
+  * linux: 4.4.0-129.155 -proposed tracker (LP: #1776352)
+
+  * Xenial update to 4.4.134 stable release (LP: #1775771)
+    - MIPS: ptrace: Expose FIR register through FP regset
+    - MIPS: Fix ptrace(2) PTRACE_PEEKUSR and PTRACE_POKEUSR accesses to o32 FGRs
+    - KVM: Fix spelling mistake: "cop_unsuable" -> "cop_unusable"
+    - affs_lookup(): close a race with affs_remove_link()
+    - aio: fix io_destroy(2) vs. lookup_ioctx() race
+    - ALSA: timer: Fix pause event notification
+    - mmc: sdhci-iproc: fix 32bit writes for TRANSFER_MODE register
+    - libata: Blacklist some Sandisk SSDs for NCQ
+    - libata: blacklist Micron 500IT SSD with MU01 firmware
+    - xen-swiotlb: fix the check condition for xen_swiotlb_free_coherent
+    - Revert "ipc/shm: Fix shmat mmap nil-page protection"
+    - ipc/shm: fix shmat() nil address after round-down when remapping
+    - kasan: fix memory hotplug during boot
+    - kernel/sys.c: fix potential Spectre v1 issue
+    - kernel/signal.c: avoid undefined behaviour in kill_something_info
+    - xfs: remove racy hasattr check from attr ops
+    - do d_instantiate/unlock_new_inode combinations safely
+    - firewire-ohci: work around oversized DMA reads on JMicron controllers
+    - NFSv4: always set NFS_LOCK_LOST when a lock is lost.
+    - ALSA: hda - Use IS_REACHABLE() for dependency on input
+    - ASoC: au1x: Fix timeout tests in au1xac97c_ac97_read()
+    - kvm: x86: fix KVM_XEN_HVM_CONFIG ioctl
+    - tracing/hrtimer: Fix tracing bugs by taking all clock bases and modes into
+      account
+    - PCI: Add function 1 DMA alias quirk for Marvell 9128
+    - tools lib traceevent: Simplify pointer print logic and fix %pF
+    - perf callchain: Fix attr.sample_max_stack setting
+    - tools lib traceevent: Fix get_field_str() for dynamic strings
+    - dm thin: fix documentation relative to low water mark threshold
+    - nfs: Do not convert nfs_idmap_cache_timeout to jiffies
+    - watchdog: sp5100_tco: Fix watchdog disable bit
+    - kconfig: Don't leak main menus during parsing
+    - kconfig: Fix automatic menu creation mem leak
+    - kconfig: Fix expr_free() E_NOT leak
+    - ipmi/powernv: Fix error return code in ipmi_powernv_probe()
+    - Btrfs: set plug for fsync
+    - btrfs: Fix out of bounds access in btrfs_search_slot
+    - Btrfs: fix scrub to repair raid6 corruption
+    - scsi: fas216: fix sense buffer initialization
+    - HID: roccat: prevent an out of bounds read in kovaplus_profile_activated()
+    - jffs2: Fix use-after-free bug in jffs2_iget()'s error handling path
+    - powerpc/numa: Use ibm,max-associativity-domains to discover possible nodes
+    - powerpc/numa: Ensure nodes initialized for hotplug
+    - RDMA/mlx5: Avoid memory leak in case of XRCD dealloc failure
+    - ntb_transport: Fix bug with max_mw_size parameter
+    - ocfs2: return -EROFS to mount.ocfs2 if inode block is invalid
+    - ocfs2/acl: use 'ip_xattr_sem' to protect getting extended attribute
+    - ocfs2: return error when we attempt to access a dirty bh in jbd2
+    - mm/mempolicy: fix the check of nodemask from user
+    - mm/mempolicy: add nodes_empty check in SYSC_migrate_pages
+    - asm-generic: provide generic_pmdp_establish()
+    - mm: pin address_space before dereferencing it while isolating an LRU page
+    - IB/ipoib: Fix for potential no-carrier state
+    - x86/power: Fix swsusp_arch_resume prototype
+    - firmware: dmi_scan: Fix handling of empty DMI strings
+    - ACPI: processor_perflib: Do not send _PPC change notification if not ready
+    - MIPS: TXx9: use IS_BUILTIN() for CONFIG_LEDS_CLASS
+    - xen-netfront: Fix race between device setup and open
+    - xen/grant-table: Use put_page instead of free_page
+    - RDS: IB: Fix null pointer issue
+    - arm64: spinlock: Fix theoretical trylock() A-B-A with LSE atomics
+    - proc: fix /proc/*/map_files lookup
+    - cifs: silence compiler warnings showing up with gcc-8.0.0
+    - bcache: properly set task state in bch_writeback_thread()
+    - bcache: fix for allocator and register thread race
+    - bcache: fix for data collapse after re-attaching an attached device
+    - bcache: return attach error when no cache set exist
+    - tools/libbpf: handle issues with bpf ELF objects containing .eh_frames
+    - locking/qspinlock: Ensure node->count is updated before initialising node
+    - irqchip/gic-v3: Change pr_debug message to pr_devel
+    - scsi: ufs: Enable quirk to ignore sending WRITE_SAME command
+    - scsi: bnx2fc: Fix check in SCSI completion handler for timed out request
+    - scsi: sym53c8xx_2: iterator underflow in sym_getsync()
+    - scsi: mptfusion: Add bounds check in mptctl_hp_targetinfo()
+    - scsi: qla2xxx: Avoid triggering undefined behavior in
+      qla2x00_mbx_completion()
+    - ARC: Fix malformed ARC_EMUL_UNALIGNED default
+    - usb: gadget: f_uac2: fix bFirstInterface in composite gadget
+    - usb: gadget: fsl_udc_core: fix ep valid checks
+    - usb: dwc2: Fix dwc2_hsotg_core_init_disconnected()
+    - selftests: memfd: add config fragment for fuse
+    - scsi: storvsc: Increase cmd_per_lun for higher speed devices
+    - scsi: aacraid: fix shutdown crash when init fails
+    - scsi: qla4xxx: skip error recovery in case of register disconnect.
+    - ARM: OMAP2+: timer: fix a kmemleak caused in omap_get_timer_dt
+    - ARM: OMAP3: Fix prm wake interrupt for resume
+    - ARM: OMAP1: clock: Fix debugfs_create_*() usage
+    - NFC: llcp: Limit size of SDP URI
+    - mac80211: round IEEE80211_TX_STATUS_HEADROOM up to multiple of 4
+    - md raid10: fix NULL deference in handle_write_completed()
+    - drm/exynos: fix comparison to bitshift when dealing with a mask
+    - usb: musb: fix enumeration after resume
+    - locking/xchg/alpha: Add unconditional memory barrier to cmpxchg()
+    - md: raid5: avoid string overflow warning
+    - kernel/relay.c: limit kmalloc size to KMALLOC_MAX_SIZE
+    - powerpc/bpf/jit: Fix 32-bit JIT for seccomp_data access
+    - s390/cio: fix return code after missing interrupt
+    - s390/cio: clear timer when terminating driver I/O
+    - ARM: OMAP: Fix dmtimer init for omap1
+    - smsc75xx: fix smsc75xx_set_features()
+    - regulatory: add NUL to request alpha2
+    - locking/xchg/alpha: Fix xchg() and cmpxchg() memory ordering bugs
+    - x86/topology: Update the 'cpu cores' field in /proc/cpuinfo correctly across
+      CPU hotplug operations
+    - media: dmxdev: fix error code for invalid ioctls
+    - md/raid1: fix NULL pointer dereference
+    - batman-adv: fix packet checksum in receive path
+    - batman-adv: invalidate checksum on fragment reassembly
+    - netfilter: ebtables: convert BUG_ONs to WARN_ONs
+    - nvme-pci: Fix nvme queue cleanup if IRQ setup fails
+    - clocksource/drivers/fsl_ftm_timer: Fix error return checking
+    - r8152: fix tx packets accounting
+    - virtio-gpu: fix ioctl and expose the fixed status to userspace.
+    - dmaengine: rcar-dmac: fix max_chunk_size for R-Car Gen3
+    - bcache: fix kcrashes with fio in RAID5 backend dev
+    - sit: fix IFLA_MTU ignored on NEWLINK
+    - gianfar: Fix Rx byte accounting for ndev stats
+    - net/tcp/illinois: replace broken algorithm reference link
+    - xen/pirq: fix error path cleanup when binding MSIs
+    - Btrfs: send, fix issuing write op when processing hole in no data mode
+    - selftests/powerpc: Skip the subpage_prot tests if the syscall is unavailable
+    - KVM: PPC: Book3S HV: Fix VRMA initialization with 2MB or 1GB memory backing
+    - watchdog: f71808e_wdt: Fix magic close handling
+    - e1000e: Fix check_for_link return value with autoneg off
+    - e1000e: allocate ring descriptors with dma_zalloc_coherent
+    - usb: musb: call pm_runtime_{get,put}_sync before reading vbus registers
+    - scsi: mpt3sas: Do not mark fw_event workqueue as WQ_MEM_RECLAIM
+    - scsi: sd: Keep disk read-only when re-reading partition
+    - fbdev: Fixing arbitrary kernel leak in case FBIOGETCMAP_SPARC in
+      sbusfb_ioctl_helper().
+    - xen: xenbus: use put_device() instead of kfree()
+    - USB: OHCI: Fix NULL dereference in HCDs using HCD_LOCAL_MEM
+    - netfilter: ebtables: fix erroneous reject of last rule
+    - bnxt_en: Check valid VNIC ID in bnxt_hwrm_vnic_set_tpa().
+    - workqueue: use put_device() instead of kfree()
+    - ipv4: lock mtu in fnhe when received PMTU < net.ipv4.route.min_pmtu
+    - sunvnet: does not support GSO for sctp
+    - net: Fix vlan untag for bridge and vlan_dev with reorder_hdr off
+    - batman-adv: fix header size check in batadv_dbg_arp()
+    - vti4: Don't count header length twice on tunnel setup
+    - vti4: Don't override MTU passed on link creation via IFLA_MTU
+    - perf/cgroup: Fix child event counting bug
+    - RDMA/ucma: Correct option size check using optlen
+    - mm/mempolicy.c: avoid use uninitialized preferred_node
+    - selftests: ftrace: Add probe event argument syntax testcase
+    - selftests: ftrace: Add a testcase for string type with kprobe_event
+    - selftests: ftrace: Add a testcase for probepoint
+    - batman-adv: fix multicast-via-unicast transmission with AP isolation
+    - batman-adv: fix packet loss for broadcasted DHCP packets to a server
+    - ARM: 8748/1: mm: Define vdso_start, vdso_end as array
+    - net: qmi_wwan: add BroadMobi BM806U 2020:2033
+    - net/usb/qmi_wwan.c: Add USB id for lt4120 modem
+    - net-usb: add qmi_wwan if on lte modem wistron neweb d18q1
+    - llc: properly handle dev_queue_xmit() return value
+    - mm/kmemleak.c: wait for scan completion before disabling free
+    - net: Fix untag for vlan packets without ethernet header
+    - net: mvneta: fix enable of all initialized RXQs
+    - sh: fix debug trap failure to process signals before return to user
+    - x86/pgtable: Don't set huge PUD/PMD on non-leaf entries
+    - fs/proc/proc_sysctl.c: fix potential page fault while unregistering sysctl
+      table
+    - swap: divide-by-zero when zero length swap file on ssd
+    - sr: get/drop reference to device in revalidate and check_events
+    - Force log to disk before reading the AGF during a fstrim
+    - cpufreq: CPPC: Initialize shared perf capabilities of CPUs
+    - scsi: aacraid: Insure command thread is not recursively stopped
+    - dp83640: Ensure against premature access to PHY registers after reset
+    - mm/ksm: fix interaction with THP
+    - mm: fix races between address_space dereference and free in page_evicatable
+    - Btrfs: bail out on error during replay_dir_deletes
+    - Btrfs: fix NULL pointer dereference in log_dir_items
+    - btrfs: Fix possible softlock on single core machines
+    - ocfs2/dlm: don't handle migrate lockres if already in shutdown
+    - sched/rt: Fix rq->clock_update_flags < RQCF_ACT_SKIP warning
+    - KVM: VMX: raise internal error for exception during invalid protected mode
+      state
+    - fscache: Fix hanging wait on page discarded by writeback
+    - sparc64: Make atomic_xchg() an inline function rather than a macro.
+    - rtc: snvs: Fix usage of snvs_rtc_enable
+    - net: bgmac: Fix endian access in bgmac_dma_tx_ring_free()
+    - Bluetooth: btusb: Add USB ID 7392:a611 for Edimax EW-7611ULB
+    - btrfs: tests/qgroup: Fix wrong tree backref level
+    - Btrfs: fix copy_items() return value when logging an inode
+    - btrfs: fix lockdep splat in btrfs_alloc_subvolume_writers
+    - xen/acpi: off by one in read_acpi_id()
+    - ACPI: acpi_pad: Fix memory leak in power saving threads
+    - powerpc/mpic: Check if cpu_possible() in mpic_physmask()
+    - m68k: set dma and coherent masks for platform FEC ethernets
+    - parisc/pci: Switch LBA PCI bus from Hard Fail to Soft Fail mode
+    - hwmon: (nct6775) Fix writing pwmX_mode
+    - rtc: hctosys: Ensure system time doesn't overflow time_t
+    - powerpc/perf: Prevent kernel address leak to userspace via BHRB buffer
+    - powerpc/perf: Fix kernel address leak via sampling registers
+    - tools/thermal: tmon: fix for segfault
+    - selftests: Print the test we're running to /dev/kmsg
+    - net/mlx5: Protect from command bit overflow
+    - ath10k: Fix kernel panic while using worker (ath10k_sta_rc_update_wk)
+    - ima: Fix Kconfig to select TPM 2.0 CRB interface
+    - [Config] CONFIG_TCG_CRB=y
+    - ima: Fallback to the builtin hash algorithm
+    - arm: dts: socfpga: fix GIC PPI warning
+    - usb: dwc3: Update DWC_usb31 GTXFIFOSIZ reg fields
+    - cpufreq: cppc_cpufreq: Fix cppc_cpufreq_init() failure path
+    - clk: Don't show the incorrect clock phase
+    - zorro: Set up z->dev.dma_mask for the DMA API
+    - bcache: quit dc->writeback_thread when BCACHE_DEV_DETACHING is set
+    - ACPICA: Events: add a return on failure from acpi_hw_register_read
+    - ACPICA: acpi: acpica: fix acpi operand cache leak in nseval.c
+    - i2c: mv64xxx: Apply errata delay only in standard mode
+    - KVM: lapic: stop advertising DIRECTED_EOI when in-kernel IOAPIC is in use
+    - xhci: zero usb device slot_id member when disabling and freeing a xhci slot
+    - MIPS: ath79: Fix AR724X_PLL_REG_PCIE_CONFIG offset
+    - PCI: Restore config space on runtime resume despite being unbound
+    - ipmi_ssif: Fix kernel panic at msg_done_handler
+    - usb: dwc2: Fix interval type issue
+    - usb: gadget: ffs: Let setup() return USB_GADGET_DELAYED_STATUS
+    - usb: gadget: ffs: Execute copy_to_user() with USER_DS set
+    - powerpc: Add missing prototype for arch_irq_work_raise()
+    - ASoC: topology: create TLV data for dapm widgets
+    - perf/core: Fix perf_output_read_group()
+    - hwmon: (pmbus/max8688) Accept negative page register values
+    - hwmon: (pmbus/adm1275) Accept negative page register values
+    - cdrom: do not call check_disk_change() inside cdrom_open()
+    - gfs2: Fix fallocate chunk size
+    - usb: gadget: udc: change comparison to bitshift when dealing with a mask
+    - usb: gadget: composite: fix incorrect handling of OS desc requests
+    - x86/devicetree: Initialize device tree before using it
+    - x86/devicetree: Fix device IRQ settings in DT
+    - ALSA: vmaster: Propagate slave error
+    - media: cx23885: Override 888 ImpactVCBe crystal frequency
+    - media: cx23885: Set subdev host data to clk_freq pointer
+    - media: s3c-camif: fix out-of-bounds array access
+    - dmaengine: pl330: fix a race condition in case of threaded irqs
+    - media: em28xx: USB bulk packet size fix
+    - clk: rockchip: Prevent calculating mmc phase if clock rate is zero
+    - enic: enable rq before updating rq descriptors
+    - hwrng: stm32 - add reset during probe
+    - staging: rtl8192u: return -ENOMEM on failed allocation of priv->oldaddr
+    - rtc: tx4939: avoid unintended sign extension on a 24 bit shift
+    - serial: xuartps: Fix out-of-bounds access through DT alias
+    - serial: samsung: Fix out-of-bounds access through serial port index
+    - serial: mxs-auart: Fix out-of-bounds access through serial port index
+    - serial: imx: Fix out-of-bounds access through serial port index
+    - serial: fsl_lpuart: Fix out-of-bounds access through DT alias
+    - serial: arc_uart: Fix out-of-bounds access through DT alias
+    - PCI: Add function 1 DMA alias quirk for Marvell 88SE9220
+    - udf: Provide saner default for invalid uid / gid
+    - media: cx25821: prevent out-of-bounds read on array card
+    - clk: samsung: s3c2410: Fix PLL rates
+    - clk: samsung: exynos5260: Fix PLL rates
+    - clk: samsung: exynos5433: Fix PLL rates
+    - clk: samsung: exynos5250: Fix PLL rates
+    - clk: samsung: exynos3250: Fix PLL rates
+    - crypto: sunxi-ss - Add MODULE_ALIAS to sun4i-ss
+    - audit: return on memory error to avoid null pointer dereference
+    - MIPS: Octeon: Fix logging messages with spurious periods after newlines
+    - drm/rockchip: Respect page offset for PRIME mmap calls
+    - x86/apic: Set up through-local-APIC mode on the boot CPU if 'noapic'
+      specified
+    - perf tests: Use arch__compare_symbol_names to compare symbols
+    - perf report: Fix memory corruption in --branch-history mode --branch-history
+    - selftests/net: fixes psock_fanout eBPF test case
+    - netlabel: If PF_INET6, check sk_buff ip header version
+    - scsi: lpfc: Fix issue_lip if link is disabled
+    - scsi: lpfc: Fix soft lockup in lpfc worker thread during LIP testing
+    - scsi: lpfc: Fix frequency of Release WQE CQEs
+    - regulator: of: Add a missing 'of_node_put()' in an error handling path of
+      'of_regulator_match()'
+    - ASoC: samsung: i2s: Ensure the RCLK rate is properly determined
+    - Bluetooth: btusb: Add device ID for RTL8822BE
+    - kdb: make "mdr" command repeat
+    - s390/ftrace: use expoline for indirect branches
+    - Linux 4.4.134
+
+  * Support SocketCAN over USB on Dell IoT 300x Gateways (LP: #1774563)
+    - [Config] CONFIG_CAN_HMS_USB=m
+    - SAUCE: (no-up) Support IXXAT USB SocketCAN device
+    - i386/amd64 -- Add new module ixx_usb
+
+  * Ubuntu 16.04 (4.4.0-127) hangs on boot with virtio-scsi MQ enabled
+    (LP: #1775235)
+    - SAUCE: (no-up) virtio-scsi: Increment reqs counter.
+
+  * register on binfmt_misc may overflow and crash the system (LP: #1775856)
+    - fs/binfmt_misc.c: do not allow offset overflow
+
+  * The kernel NULL pointer dereference happens when accessing the task_struct
+    by task_cpu() in function cpuacct_charge() (LP: #1775326)
+    - sched/cpuacct: Simplify the cpuacct code
+
+  * Xenial update to 4.4.133 stable release (LP: #1775477)
+    - 8139too: Use disable_irq_nosync() in rtl8139_poll_controller()
+    - bridge: check iface upper dev when setting master via ioctl
+    - dccp: fix tasklet usage
+    - ipv4: fix memory leaks in udp_sendmsg, ping_v4_sendmsg
+    - llc: better deal with too small mtu
+    - net: ethernet: sun: niu set correct packet size in skb
+    - net/mlx4_en: Verify coalescing parameters are in range
+    - net_sched: fq: take care of throttled flows before reuse
+    - net: support compat 64-bit time in {s,g}etsockopt
+    - openvswitch: Don't swap table in nlattr_set() after OVS_ATTR_NESTED is found
+    - qmi_wwan: do not steal interfaces from class drivers
+    - r8169: fix powering up RTL8168h
+    - sctp: handle two v4 addrs comparison in sctp_inet6_cmp_addr
+    - sctp: use the old asoc when making the cookie-ack chunk in dupcook_d
+    - tg3: Fix vunmap() BUG_ON() triggered from tg3_free_consistent().
+    - bonding: do not allow rlb updates to invalid mac
+    - tcp: ignore Fast Open on repair mode
+    - sctp: fix the issue that the cookie-ack with auth can't get processed
+    - sctp: delay the authentication for the duplicated cookie-echo chunk
+    - ALSA: timer: Call notifier in the same spinlock
+    - audit: move calcs after alloc and check when logging set loginuid
+    - arm64: introduce mov_q macro to move a constant into a 64-bit register
+    - [Config] Add CONFIG_ARM64_ERRATUM_1024718=y
+    - arm64: Add work around for Arm Cortex-A55 Erratum 1024718
+    - futex: Remove unnecessary warning from get_futex_key
+    - futex: Remove duplicated code and fix undefined behaviour
+    - xfrm: fix xfrm_do_migrate() with AEAD e.g(AES-GCM)
+    - lockd: lost rollback of set_grace_period() in lockd_down_net()
+    - Revert "ARM: dts: imx6qdl-wandboard: Fix audio channel swap"
+    - l2tp: revert "l2tp: fix missing print session offset info"
+    - pipe: cap initial pipe capacity according to pipe-max-size limit
+    - futex: futex_wake_op, fix sign_extend32 sign bits
+    - kernel/exit.c: avoid undefined behaviour when calling wait4()
+    - usbip: usbip_host: refine probe and disconnect debug msgs to be useful
+    - usbip: usbip_host: delete device from busid_table after rebind
+    - usbip: usbip_host: run rebind from exit when module is removed
+    - usbip: usbip_host: fix NULL-ptr deref and use-after-free errors
+    - usbip: usbip_host: fix bad unlock balance during stub_probe()
+    - ALSA: usb: mixer: volume quirk for CM102-A+/102S+
+    - ALSA: hda: Add Lenovo C50 All in one to the power_save blacklist
+    - ALSA: control: fix a redundant-copy issue
+    - spi: pxa2xx: Allow 64-bit DMA
+    - powerpc/powernv: panic() on OPAL < V3
+    - powerpc/powernv: Remove OPALv2 firmware define and references
+    - powerpc/powernv: remove FW_FEATURE_OPALv3 and just use FW_FEATURE_OPAL
+    - cpuidle: coupled: remove unused define cpuidle_coupled_lock
+    - powerpc: Don't preempt_disable() in show_cpuinfo()
+    - vmscan: do not force-scan file lru if its absolute size is small
+    - mm: filemap: remove redundant code in do_read_cache_page
+    - mm: filemap: avoid unnecessary calls to lock_page when waiting for IO to
+      complete during a read
+    - signals: avoid unnecessary taking of sighand->siglock
+    - tracing/x86/xen: Remove zero data size trace events
+      trace_xen_mmu_flush_tlb{_all}
+    - proc read mm's {arg,env}_{start,end} with mmap semaphore taken.
+    - powerpc/powernv: Fix NVRAM sleep in invalid context when crashing
+    - mm: don't allow deferred pages with NEED_PER_CPU_KM
+    - s390/qdio: fix access to uninitialized qdio_q fields
+    - s390/qdio: don't release memory in qdio_setup_irq()
+    - s390: remove indirect branch from do_softirq_own_stack
+    - efi: Avoid potential crashes, fix the 'struct efi_pci_io_protocol_32'
+      definition for mixed mode
+    - ARM: 8771/1: kprobes: Prohibit kprobes on do_undefinstr
+    - tick/broadcast: Use for_each_cpu() specially on UP kernels
+    - ARM: 8769/1: kprobes: Fix to use get_kprobe_ctlblk after irq-disabed
+    - ARM: 8770/1: kprobes: Prohibit probing on optimized_callback
+    - ARM: 8772/1: kprobes: Prohibit kprobes on get_user functions
+    - Btrfs: fix xattr loss after power failure
+    - btrfs: fix crash when trying to resume balance without the resume flag
+    - btrfs: fix reading stale metadata blocks after degraded raid1 mounts
+    - net: test tailroom before appending to linear skb
+    - packet: in packet_snd start writing at link layer allocation
+    - sock_diag: fix use-after-free read in __sk_free
+    - tcp: purge write queue in tcp_connect_init()
+    - ext2: fix a block leak
+    - s390: add assembler macros for CPU alternatives
+    - s390: move expoline assembler macros to a header
+    - s390/lib: use expoline for indirect branches
+    - s390/kernel: use expoline for indirect branches
+    - s390: move spectre sysfs attribute code
+    - s390: extend expoline to BC instructions
+    - s390: use expoline thunks in the BPF JIT
+    - scsi: libsas: defer ata device eh commands to libata
+    - scsi: sg: allocate with __GFP_ZERO in sg_build_indirect()
+    - scsi: zfcp: fix infinite iteration on ERP ready list
+    - dmaengine: ensure dmaengine helpers check valid callback
+    - time: Fix CLOCK_MONOTONIC_RAW sub-nanosecond accounting
+    - gpio: rcar: Add Runtime PM handling for interrupts
+    - cfg80211: limit wiphy names to 128 bytes
+    - hfsplus: stop workqueue when fill_super() failed
+    - x86/kexec: Avoid double free_page() upon do_kexec_load() failure
+    - Linux 4.4.133
+
+  * vmxnet3: update to latest ToT (LP: #1768143)
+    - vmxnet3: avoid xmit reset due to a race in vmxnet3
+    - vmxnet3: use correct flag to indicate LRO feature
+    - vmxnet3: fix incorrect dereference when rxvlan is disabled
+
+  * Prevent speculation on user controlled pointer (LP: #1775137)
+    - x86: reorganize SMAP handling in user space accesses
+    - x86: fix SMAP in 32-bit environments
+    - x86: Introduce __uaccess_begin_nospec() and uaccess_try_nospec
+    - x86/usercopy: Replace open coded stac/clac with __uaccess_{begin, end}
+    - x86/uaccess: Use __uaccess_begin_nospec() and uaccess_try_nospec
+
+  * Xenial update to 4.4.132 stable release (LP: #1774173)
+    - perf/core: Fix the perf_cpu_time_max_percent check
+    - bpf: map_get_next_key to return first key on NULL
+    - percpu: include linux/sched.h for cond_resched()
+    - mac80211: allow not sending MIC up from driver for HW crypto
+    - mac80211: allow same PN for AMSDU sub-frames
+    - mac80211: Add RX flag to indicate ICV stripped
+    - ath10k: fix rfc1042 header retrieval in QCA4019 with eth decap mode
+    - ath10k: rebuild crypto header in rx data frames
+    - gpmi-nand: Handle ECC Errors in erased pages
+    - USB: serial: option: Add support for Quectel EP06
+    - ALSA: pcm: Check PCM state at xfern compat ioctl
+    - ALSA: seq: Fix races at MIDI encoding in snd_virmidi_output_trigger()
+    - ALSA: aloop: Mark paused device as inactive
+    - ALSA: aloop: Add missing cable lock to ctl API callbacks
+    - tracepoint: Do not warn on ENOMEM
+    - Input: leds - fix out of bound access
+    - Input: atmel_mxt_ts - add touchpad button mapping for Samsung Chromebook Pro
+    - xfs: prevent creating negative-sized file via INSERT_RANGE
+    - RDMA/ucma: Allow resolving address w/o specifying source address
+    - RDMA/mlx5: Protect from shift operand overflow
+    - NET: usb: qmi_wwan: add support for ublox R410M PID 0x90b2
+    - IB/mlx5: Use unlimited rate when static rate is not supported
+    - drm/vmwgfx: Fix a buffer object leak
+    - test_firmware: fix setting old custom fw path back on exit, second try
+    - USB: serial: visor: handle potential invalid device configuration
+    - USB: Accept bulk endpoints with 1024-byte maxpacket
+    - USB: serial: option: reimplement interface masking
+    - USB: serial: option: adding support for ublox R410M
+    - usb: musb: host: fix potential NULL pointer dereference
+    - ipvs: fix rtnl_lock lockups caused by start_sync_thread
+    - crypto: af_alg - fix possible uninit-value in alg_bind()
+    - netlink: fix uninit-value in netlink_sendmsg
+    - net: fix rtnh_ok()
+    - net: initialize skb->peeked when cloning
+    - net: fix uninit-value in __hw_addr_add_ex()
+    - dccp: initialize ireq->ir_mark
+    - soreuseport: initialise timewait reuseport field
+    - perf: Remove superfluous allocation error check
+    - tcp: fix TCP_REPAIR_QUEUE bound checking
+    - bdi: Fix oops in wb_workfn()
+    - f2fs: fix a dead loop in f2fs_fiemap()
+    - xfrm_user: fix return value from xfrm_user_rcv_msg
+    - rfkill: gpio: fix memory leak in probe error path
+    - libata: Apply NOLPM quirk for SanDisk SD7UB3Q*G1001 SSDs
+    - tracing: Fix regex_match_front() to not over compare the test string
+    - can: kvaser_usb: Increase correct stats counter in kvaser_usb_rx_can_msg()
+    - net: atm: Fix potential Spectre v1
+    - atm: zatm: Fix potential Spectre v1
+    - Revert "Bluetooth: btusb: Fix quirk for Atheros 1525/QCA6174"
+    - tracing/uprobe_event: Fix strncpy corner case
+    - perf/x86: Fix possible Spectre-v1 indexing for hw_perf_event cache_*
+    - perf/x86/cstate: Fix possible Spectre-v1 indexing for pkg_msr
+    - perf/x86/msr: Fix possible Spectre-v1 indexing in the MSR driver
+    - perf/core: Fix possible Spectre-v1 indexing for ->aux_pages[]
+    - perf/x86: Fix possible Spectre-v1 indexing for x86_pmu::event_map()
+    - Linux 4.4.132
+
+  * Update to upstream's implementation of Spectre v1 mitigation (LP: #1774181)
+    - Documentation: Document array_index_nospec
+    - array_index_nospec: Sanitize speculative array de-references
+    - x86: Implement array_index_mask_nospec
+    - x86: Introduce barrier_nospec
+    - x86/get_user: Use pointer masking to limit speculation
+    - x86/syscall: Sanitize syscall table de-references under speculation
+    - vfs, fdtable: Prevent bounds-check bypass via speculative execution
+    - nl80211: Sanitize array index in parse_txq_params
+    - x86/spectre: Report get_user mitigation for spectre_v1
+    - x86/kvm: Update spectre-v1 mitigation
+    - nospec: Allow index argument to have const-qualified type
+    - x86/syscall: Sanitize syscall table de-references under speculation fix
+    - mpls, nospec: Sanitize array index in mpls_label_ok()
+    - nospec: Include <asm/barrier.h> dependency
+    - nospec: Move array_index_nospec() parameter checking into separate macro
+    - nospec: Kill array_index_nospec_mask_check()
+    - ALSA: seq: oss: Hardening for potential Spectre v1
+    - ALSA: hda: Hardening for potential Spectre v1
+    - SAUCE: Replace osb() calls with array_index_nospec()
+    - SAUCE: Rename osb() to barrier_nospec()
+    - SAUCE: bpf: Use barrier_nospec() instead of osb()
+
+  * CVE-2018-3639 (x86)
+    - KVM: x86: remove magic number with enum cpuid_leafs
+    - SAUCE: x86/cpufeatures: Move CPUID_7_EDX CPUID bits to word 18
+    - SAUCE: x86: Remove double include
+    - SAUCE: x86/pti: Evaluate X86_BUG_CPU_MELTDOWN when pti=auto
+    - SAUCE: x86/speculation: Query individual feature flags when reloading
+      microcode
+
+  * cpum_sf: ensure sample freq is non-zero (LP: #1772593)
+    - s390/cpum_sf: ensure sample frequency of perf event attributes is non-zero
+
+  * ELANPAD ELAN0612 does not work, patch available (LP: #1773509)
+    - SAUCE: Input: elan_i2c - add ELAN0612 to the ACPI table
+
+  * FS-Cache: Assertion failed: FS-Cache: 6 == 5 is false (LP: #1774336)
+    - SAUCE: CacheFiles: fix a read_waiter/read_copier race
+
+  * Kernel 4.4 NBD size overflow with image size exceeding 1TB (LP: #1772575)
+    - nbd: use loff_t for blocksize and nbd_set_size args
+    - nbd: fix 64-bit division
+
+  * 4.4.0-127.153 generates many "sit: non-ECT" messages (LP: #1772775)
+    - Revert "sit: reload iphdr in ipip6_rcv"
+
+  * Creation of IMA file hashes fails when appraisal is enabled (LP: #1771826)
+    - Revert "ima: limit file hash setting by user to fix and log modes"
+
+  * Setting ipv6.disable=1 prevents both IPv4 and IPv6 socket opening for VXLAN
+    tunnels (LP: #1771301)
+    - vxlan: correctly handle ipv6.disable module parameter
+
+  * CVE-2018-7755
+    - SAUCE: floppy: Do not copy a kernel pointer to user memory in FDGETPRM ioctl
+
+  * Support UVC1.5 Camera for Xenial (LP: #1773905)
+    - uvcvideo: Enable UVC 1.5 device detection
+
+  * Kernel produces empty lines in /proc/PID/status (LP: #1772671)
+    - SAUCE: seccomp: Remove double newline sequence in /proc/PID/status
+
+  * rfi-flush: Switch to new linear fallback flush (LP: #1744173)
+    - powerpc/64s: Improve RFI L1-D cache flush fallback
+    - SAUCE: rfi-flush: Make it possible to call setup_rfi_flush() again
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Tue, 12 Jun 2018 04:10:32 -0400
+
+linux (4.4.0-128.154) xenial; urgency=medium
+
+  * linux: 4.4.0-128.154 -proposed tracker (LP: #1772960)
+
+  * CVE-2018-3639 (x86)
+    - x86/cpu: Make alternative_msr_write work for 32-bit code
+    - x86/bugs: Fix the parameters alignment and missing void
+    - KVM: SVM: Move spec control call after restore of GS
+    - x86/speculation: Use synthetic bits for IBRS/IBPB/STIBP
+    - x86/cpufeatures: Disentangle MSR_SPEC_CTRL enumeration from IBRS
+    - x86/cpufeatures: Disentangle SSBD enumeration
+    - x86/cpu/AMD: Fix erratum 1076 (CPB bit)
+    - x86/cpufeatures: Add FEATURE_ZEN
+    - x86/speculation: Handle HT correctly on AMD
+    - x86/bugs, KVM: Extend speculation control for VIRT_SPEC_CTRL
+    - x86/speculation: Add virtualized speculative store bypass disable support
+    - x86/speculation: Rework speculative_store_bypass_update()
+    - x86/bugs: Unify x86_spec_ctrl_{set_guest,restore_host}
+    - x86/bugs: Expose x86_spec_ctrl_base directly
+    - x86/bugs: Remove x86_spec_ctrl_set()
+    - x86/bugs: Rework spec_ctrl base and mask logic
+    - x86/speculation, KVM: Implement support for VIRT_SPEC_CTRL/LS_CFG
+    - KVM: SVM: Implement VIRT_SPEC_CTRL support for SSBD
+    - x86/bugs: Rename SSBD_NO to SSB_NO
+    - KVM: VMX: Expose SSBD properly to guests.
+
+  * [i915_bpo] Fix flickering issue after panel change (LP: #1770565)
+    - drm/i915: Fix iboost setting for DDI with 4 lanes on SKL
+    - drm/i915: Name the "iboost bit"
+    - drm/i915: Program iboost settings for HDMI/DVI on SKL
+    - drm/i915: Move bxt_ddi_vswing_sequence() call into intel_ddi_pre_enable()
+      for HDMI
+    - drm/i915: Explicitly use ddi buf trans entry 9 for hdmi
+    - drm/i915: Split DP/eDP/FDI and HDMI/DVI DDI buffer programming apart
+    - drm/i915: Get the iboost setting based on the port type
+    - drm/i915: Simplify intel_ddi_get_encoder_port()
+    - drm/i915: Fix iboost setting for SKL Y/U DP DDI buffer translation entry 2
+    - drm/i915: KBL - Recommended buffer translation programming for DisplayPort
+    - drm/i915: Ignore OpRegion panel type except on select machines
+
+  * [SRU][Bionic/Artful] fix false positives in W+X checking (LP: #1769696)
+    - init: fix false positives in W+X checking
+
+  * [Ubuntu 16.04] kernel: fix rwlock implementation (LP: #1761674)
+    - SAUCE: (no-up) s390: fix rwlock implementation
+
+  * linux < 4.11: unable to use netfilter logging from non-init namespaces
+    (LP: #1766573)
+    - netfilter: allow logging from non-init namespaces
+
+  * [LTC Test] Ubuntu 18.04:  tm_sigreturn failed on P8 compat mode 16.04.04
+    guest (LP: #1771439)
+    - powerpc: signals: Discard transaction state from signal frames
+
+  * QCA9377 requires more IRAM banks for its new firmware (LP: #1748345)
+    - ath10k: update the IRAM bank number for QCA9377
+
+  * i915/kbl_dmc_ver1.bin failed with error -2 package 1.157.17 kernel
+    4.4.0-116-generic (LP: #1752536)
+    - ubuntu: i915_bpo - Add MODULE_FIRMWARE for Geminilake's DMC
+
+  * Xenial update to 4.4.131 stable release (LP: #1768825)
+    - ext4: prevent right-shifting extents beyond EXT_MAX_BLOCKS
+    - ext4: set h_journal if there is a failure starting a reserved handle
+    - ext4: add validity checks for bitmap block numbers
+    - ext4: fix bitmap position validation
+    - usbip: usbip_host: fix to hold parent lock for device_attach() calls
+    - usbip: vhci_hcd: Fix usb device and sockfd leaks
+    - USB: serial: simple: add libtransistor console
+    - USB: serial: ftdi_sio: use jtag quirk for Arrow USB Blaster
+    - USB: serial: cp210x: add ID for NI USB serial console
+    - usb: core: Add quirk for HP v222w 16GB Mini
+    - USB: Increment wakeup count on remote wakeup.
+    - ALSA: usb-audio: Skip broken EU on Dell dock USB-audio
+    - virtio: add ability to iterate over vqs
+    - virtio_console: free buffers after reset
+    - drm/virtio: fix vq wait_event condition
+    - tty: Don't call panic() at tty_ldisc_init()
+    - tty: n_gsm: Fix long delays with control frame timeouts in ADM mode
+    - tty: n_gsm: Fix DLCI handling for ADM mode if debug & 2 is not set
+    - tty: Use __GFP_NOFAIL for tty_ldisc_get()
+    - ALSA: core: Report audio_tstamp in snd_pcm_sync_ptr
+    - ALSA: seq: oss: Fix unbalanced use lock for synth MIDI device
+    - ALSA: hda/realtek - Add some fixes for ALC233
+    - mtd: cfi: cmdset_0001: Do not allow read/write to suspend erase block.
+    - mtd: cfi: cmdset_0001: Workaround Micron Erase suspend bug.
+    - mtd: cfi: cmdset_0002: Do not allow read/write to suspend erase block.
+    - kobject: don't use WARN for registration failures
+    - scsi: sd: Defer spinning up drive while SANITIZE is in progress
+    - ARM: amba: Make driver_override output consistent with other buses
+    - ARM: amba: Fix race condition with driver_override
+    - ARM: amba: Don't read past the end of sysfs "driver_override" buffer
+    - ASoC: fsl_esai: Fix divisor calculation failure at lower ratio
+    - libceph: validate con->state at the top of try_write()
+    - x86/ipc: Fix x32 version of shmid64_ds and msqid64_ds
+    - x86/smpboot: Don't use mwait_play_dead() on AMD systems
+    - serial: mctrl_gpio: export mctrl_gpio_disable_ms and mctrl_gpio_init
+    - serial: mctrl_gpio: Add missing module license
+    - Linux 4.4.131
+
+  * Xenial update to 4.4.130 stable release (LP: #1768474) // CVE-2017-5715 //
+    CVE-2017-5753
+    - SAUCE: s390: print messages for gmb and nobp
+
+  * Xenial update to 4.4.130 stable release (LP: #1768474)
+    - cifs: do not allow creating sockets except with SMB1 posix exensions
+    - x86/tsc: Prevent 32bit truncation in calc_hpet_ref()
+    - perf: Return proper values for user stack errors
+    - staging: ion : Donnot wakeup kswapd in ion system alloc
+    - r8152: add Linksys USB3GIGV1 id
+    - Input: drv260x - fix initializing overdrive voltage
+    - ath9k_hw: check if the chip failed to wake up
+    - jbd2: fix use after free in kjournald2()
+    - Revert "ath10k: send (re)assoc peer command when NSS changed"
+    - Revert "UBUNTU: SAUCE: s390: print messages for gmb and nobp"
+    - Revert "UBUNTU: SAUCE: s390: improve cpu alternative handling for gmb and
+      nobp"
+    - Revert "s390: add ppa to kernel entry / exit"
+    - Revert "s390: introduce CPU alternatives"
+    - s390: introduce CPU alternatives
+    - s390: enable CPU alternatives unconditionally
+    - s390/alternative: use a copy of the facility bit mask
+    - s390: add options to change branch prediction behaviour for the kernel
+    - s390: scrub registers on kernel entry and KVM exit
+    - s390: add optimized array_index_mask_nospec
+    - s390: run user space and KVM guests with modified branch prediction
+    - s390: introduce execute-trampolines for branches
+    - s390: Replace IS_ENABLED(EXPOLINE_*) with IS_ENABLED(CONFIG_EXPOLINE_*)
+    - s390: do not bypass BPENTER for interrupt system calls
+    - s390/entry.S: fix spurious zeroing of r0
+    - s390: move nobp parameter functions to nospec-branch.c
+    - s390: add automatic detection of the spectre defense
+    - [Config] Add CONFIG_EXPOLINE=y and CONFIG_EXPOLINE_AUTO=y
+    - s390: report spectre mitigation via syslog
+    - s390: add sysfs attributes for spectre
+    - s390: correct nospec auto detection init order
+    - s390: correct module section names for expoline code revert
+    - bonding: do not set slave_dev npinfo before slave_enable_netpoll in
+      bond_enslave
+    - KEYS: DNS: limit the length of option strings
+    - l2tp: check sockaddr length in pppol2tp_connect()
+    - net: validate attribute sizes in neigh_dump_table()
+    - llc: delete timers synchronously in llc_sk_free()
+    - tcp: don't read out-of-bounds opsize
+    - team: avoid adding twice the same option to the event list
+    - team: fix netconsole setup over team
+    - packet: fix bitfield update race
+    - pppoe: check sockaddr length in pppoe_connect()
+    - vlan: Fix reading memory beyond skb->tail in skb_vlan_tagged_multi
+    - sctp: do not check port in sctp_inet6_cmp_addr
+    - llc: hold llc_sap before release_sock()
+    - llc: fix NULL pointer deref for SOCK_ZAPPED
+    - tipc: add policy for TIPC_NLA_NET_ADDR
+    - net: fix deadlock while clearing neighbor proxy table
+    - tcp: md5: reject TCP_MD5SIG or TCP_MD5SIG_EXT on established sockets
+    - net: af_packet: fix race in PACKET_{R|T}X_RING
+    - ipv6: add RTA_TABLE and RTA_PREFSRC to rtm_ipv6_policy
+    - scsi: mptsas: Disable WRITE SAME
+    - cdrom: information leak in cdrom_ioctl_media_changed()
+    - s390/cio: update chpid descriptor after resource accessibility event
+    - s390/uprobes: implement arch_uretprobe_is_alive()
+    - Linux 4.4.130
+    - SAUCE: s390: Add 'nogmb' kernel parameter
+
+  * Xenial update to 4.4.129 stable release (LP: #1768429)
+    - media: v4l2-compat-ioctl32: don't oops on overlay
+    - parisc: Fix out of array access in match_pci_device()
+    - perf intel-pt: Fix overlap detection to identify consecutive buffers
+      correctly
+    - perf intel-pt: Fix sync_switch
+    - perf intel-pt: Fix error recovery from missing TIP packet
+    - perf intel-pt: Fix timestamp following overflow
+    - radeon: hide pointless #warning when compile testing
+    - block/loop: fix deadlock after loop_set_status
+    - s390/qdio: don't retry EQBS after CCQ 96
+    - s390/qdio: don't merge ERROR output buffers
+    - s390/ipl: ensure loadparm valid flag is set
+    - getname_kernel() needs to make sure that ->name != ->iname in long case
+    - rtl8187: Fix NULL pointer dereference in priv->conf_mutex
+    - hwmon: (ina2xx) Fix access to uninitialized mutex
+    - cdc_ether: flag the Cinterion AHS8 modem by gemalto as WWAN
+    - slip: Check if rstate is initialized before uncompressing
+    - lan78xx: Correctly indicate invalid OTP
+    - x86/hweight: Get rid of the special calling convention
+    - [Config] Remove ARCH_HWEIGHT_CFLAGS
+    - x86/hweight: Don't clobber %rdi
+    - tty: make n_tty_read() always abort if hangup is in progress
+    - ubifs: Check ubifs_wbuf_sync() return code
+    - ubi: fastmap: Don't flush fastmap work on detach
+    - ubi: Fix error for write access
+    - ubi: Reject MLC NAND
+    - fs/reiserfs/journal.c: add missing resierfs_warning() arg
+    - resource: fix integer overflow at reallocation
+    - ipc/shm: fix use-after-free of shm file via remap_file_pages()
+    - mm, slab: reschedule cache_reap() on the same CPU
+    - usb: musb: gadget: misplaced out of bounds check
+    - ARM: dts: at91: at91sam9g25: fix mux-mask pinctrl property
+    - ARM: dts: at91: sama5d4: fix pinctrl compatible string
+    - xen-netfront: Fix hang on device removal
+    - regmap: Fix reversed bounds check in regmap_raw_write()
+    - ACPI / video: Add quirk to force acpi-video backlight on Samsung 670Z5E
+    - ACPI / hotplug / PCI: Check presence of slot itself in get_slot_status()
+    - USB:fix USB3 devices behind USB3 hubs not resuming at hibernate thaw
+    - usb: dwc3: pci: Properly cleanup resource
+    - HID: i2c-hid: fix size check and type usage
+    - powerpc/powernv: Handle unknown OPAL errors in opal_nvram_write()
+    - powerpc/64: Fix smp_wmb barrier definition use use lwsync consistently
+    - powerpc/powernv: define a standard delay for OPAL_BUSY type retry loops
+    - powerpc/powernv: Fix OPAL NVRAM driver OPAL_BUSY loops
+    - HID: Fix hid_report_len usage
+    - HID: core: Fix size as type u32
+    - ASoC: ssm2602: Replace reg_default_raw with reg_default
+    - thunderbolt: Resume control channel after hibernation image is created
+    - random: use a tighter cap in credit_entropy_bits_safe()
+    - jbd2: if the journal is aborted then don't allow update of the log tail
+    - ext4: don't update checksum of new initialized bitmaps
+    - ext4: fail ext4_iget for root directory if unallocated
+    - RDMA/ucma: Don't allow setting RDMA_OPTION_IB_PATH without an RDMA device
+    - ALSA: pcm: Fix UAF at PCM release via PCM timer access
+    - IB/srp: Fix srp_abort()
+    - IB/srp: Fix completion vector assignment algorithm
+    - dmaengine: at_xdmac: fix rare residue corruption
+    - um: Use POSIX ucontext_t instead of struct ucontext
+    - iommu/vt-d: Fix a potential memory leak
+    - mmc: jz4740: Fix race condition in IRQ mask update
+    - clk: mvebu: armada-38x: add support for 1866MHz variants
+    - clk: mvebu: armada-38x: add support for missing clocks
+    - clk: bcm2835: De-assert/assert PLL reset signal when appropriate
+    - thermal: imx: Fix race condition in imx_thermal_probe()
+    - watchdog: f71808e_wdt: Fix WD_EN register read
+    - ALSA: oss: consolidate kmalloc/memset 0 call to kzalloc
+    - ALSA: pcm: Use ERESTARTSYS instead of EINTR in OSS emulation
+    - ALSA: pcm: Avoid potential races between OSS ioctls and read/write
+    - ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams
+    - ALSA: pcm: Fix mutex unbalance in OSS emulation ioctls
+    - ALSA: pcm: Fix endless loop for XRUN recovery in OSS emulation
+    - vfio-pci: Virtualize PCIe & AF FLR
+    - vfio/pci: Virtualize Maximum Payload Size
+    - vfio/pci: Virtualize Maximum Read Request Size
+    - ext4: don't allow r/w mounts if metadata blocks overlap the superblock
+    - drm/radeon: Fix PCIe lane width calculation
+    - ext4: fix crashes in dioread_nolock mode
+    - ext4: fix deadlock between inline_data and ext4_expand_extra_isize_ea()
+    - ALSA: line6: Use correct endpoint type for midi output
+    - ALSA: rawmidi: Fix missing input substream checks in compat ioctls
+    - ALSA: hda - New VIA controller suppor no-snoop path
+    - HID: hidraw: Fix crash on HIDIOCGFEATURE with a destroyed device
+    - MIPS: uaccess: Add micromips clobbers to bzero invocation
+    - MIPS: memset.S: EVA & fault support for small_memset
+    - MIPS: memset.S: Fix return of __clear_user from Lpartial_fixup
+    - MIPS: memset.S: Fix clobber of v1 in last_fixup
+    - powerpc/eeh: Fix enabling bridge MMIO windows
+    - powerpc/lib: Fix off-by-one in alternate feature patching
+    - jffs2_kill_sb(): deal with failed allocations
+    - hypfs_kill_super(): deal with failed allocations
+    - rpc_pipefs: fix double-dput()
+    - Don't leak MNT_INTERNAL away from internal mounts
+    - autofs: mount point create should honour passed in mode
+    - mm: allow GFP_{FS,IO} for page_cache_read page cache allocation
+    - mm/filemap.c: fix NULL pointer in page_cache_tree_insert()
+    - ext4: bugfix for mmaped pages in mpage_release_unused_pages()
+    - fanotify: fix logic of events on child
+    - writeback: safer lock nesting
+    - Linux 4.4.129
+
+  * CVE-2018-8087
+    - mac80211_hwsim: fix possible memory leak in hwsim_new_radio_nl()
+
+  * Integrated Webcam Realtek Integrated_Webcam_HD (0bda:58f4) not working in
+    DELL XPS 13 9370 with firmware 1.50 (LP: #1763748)
+    - SAUCE: media: uvcvideo: Support realtek's UVC 1.5 device
+
+  * [Xenial] Kernels OOPS when mwifiex is in AP mode (LP: #1769671)
+    - Revert "UBUNTU: SAUCE: mwifiex: do not dereference invalid pointer"
+    - Revert "UBUNTU: SAUCE: net/wireless: do not dereference invalid pointer"
+    - mwifiex: cfg80211: do not change virtual interface during scan processing
+
+  * user space process hung in 'D' state waiting for disk io to complete
+    (LP: #1750038)
+    - NFS: Use GFP_NOIO for two allocations in writeback
+
+  * Acer Swift sf314-52 power button not managed  (LP: #1766054)
+    - SAUCE: platform/x86: acer-wmi: add another KEY_POWER keycode
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 25 May 2018 15:58:45 +0200
+
+linux (4.4.0-127.153) xenial; urgency=medium
+
+  * CVE-2018-3639 (powerpc)
+    - powerpc/pseries: Support firmware disable of RFI flush
+    - powerpc/powernv: Support firmware disable of RFI flush
+    - powerpc/rfi-flush: Move the logic to avoid a redo into the debugfs code
+    - powerpc/rfi-flush: Make it possible to call setup_rfi_flush() again
+    - powerpc/rfi-flush: Always enable fallback flush on pseries
+    - powerpc/rfi-flush: Differentiate enabled and patched flush types
+    - powerpc/rfi-flush: Call setup_rfi_flush() after LPM migration
+    - powerpc/pseries: Add new H_GET_CPU_CHARACTERISTICS flags
+    - powerpc: Add security feature flags for Spectre/Meltdown
+    - powerpc/pseries: Set or clear security feature flags
+    - powerpc/powernv: Set or clear security feature flags
+    - powerpc/64s: Move cpu_show_meltdown()
+    - powerpc/64s: Enhance the information in cpu_show_meltdown()
+    - powerpc/powernv: Use the security flags in pnv_setup_rfi_flush()
+    - powerpc/pseries: Use the security flags in pseries_setup_rfi_flush()
+    - powerpc/64s: Wire up cpu_show_spectre_v1()
+    - powerpc/64s: Wire up cpu_show_spectre_v2()
+    - powerpc/pseries: Fix clearing of security feature flags
+    - powerpc: Move default security feature flags
+    - powerpc/pseries: Restore default security feature flags on setup
+    - SAUCE: powerpc/64s: Add support for a store forwarding barrier at kernel
+      entry/exit
+
+  * CVE-2018-3639 (x86)
+    - SAUCE: Clean up IBPB and IBRS control functions and macros
+    - SAUCE: Fix up IBPB and IBRS kernel parameters documentation
+    - SAUCE: Remove #define X86_FEATURE_PTI
+    - x86/cpufeature: Move some of the scattered feature bits to x86_capability
+    - x86/cpufeature: Cleanup get_cpu_cap()
+    - x86/cpu: Probe CPUID leaf 6 even when cpuid_level == 6
+    - x86/cpufeatures: Add CPUID_7_EDX CPUID leaf
+    - x86/cpufeatures: Add Intel feature bits for Speculation Control
+    - SAUCE: x86/kvm: Expose SPEC_CTRL from the leaf
+    - x86/cpufeatures: Add AMD feature bits for Speculation Control
+    - x86/msr: Add definitions for new speculation control MSRs
+    - SAUCE: x86/msr: Rename MSR spec control feature bits
+    - x86/pti: Do not enable PTI on CPUs which are not vulnerable to Meltdown
+    - x86/cpufeature: Blacklist SPEC_CTRL/PRED_CMD on early Spectre v2 microcodes
+    - x86/speculation: Add basic IBPB (Indirect Branch Prediction Barrier) support
+    - x86/speculation: Add <asm/msr-index.h> dependency
+    - x86/cpufeatures: Clean up Spectre v2 related CPUID flags
+    - x86/cpuid: Fix up "virtual" IBRS/IBPB/STIBP feature bits on Intel
+    - SAUCE: x86/speculation: Move vendor specific IBRS/IBPB control code
+    - SAUCE: x86: Add alternative_msr_write
+    - SAUCE: x86/nospec: Simplify alternative_msr_write()
+    - SAUCE: x86/bugs: Concentrate bug detection into a separate function
+    - SAUCE: x86/bugs: Concentrate bug reporting into a separate function
+    - arch: Introduce post-init read-only memory
+    - SAUCE: x86/bugs: Read SPEC_CTRL MSR during boot and re-use reserved bits
+    - SAUCE: x86/bugs, KVM: Support the combination of guest and host IBRS
+    - SAUCE: x86/bugs: Expose /sys/../spec_store_bypass
+    - SAUCE: x86/cpufeatures: Add X86_FEATURE_RDS
+    - SAUCE: x86/bugs: Provide boot parameters for the spec_store_bypass_disable
+      mitigation
+    - SAUCE: x86/bugs/intel: Set proper CPU features and setup RDS
+    - SAUCE: x86/bugs: Whitelist allowed SPEC_CTRL MSR values
+    - SAUCE: x86/bugs/AMD: Add support to disable RDS on Fam[15,16,17]h if
+      requested
+    - SAUCE: x86/KVM/VMX: Expose SPEC_CTRL Bit(2) to the guest
+    - SAUCE: x86/speculation: Create spec-ctrl.h to avoid include hell
+    - SAUCE: prctl: Add speculation control prctls
+    - x86/process: Optimize TIF checks in __switch_to_xtra()
+    - SAUCE: x86/process: Allow runtime control of Speculative Store Bypass
+    - SAUCE: x86/speculation: Add prctl for Speculative Store Bypass mitigation
+    - SAUCE: nospec: Allow getting/setting on non-current task
+    - SAUCE: proc: Provide details on speculation flaw mitigations
+    - SAUCE: seccomp: Enable speculation flaw mitigations
+    - SAUCE: x86/bugs: Honour SPEC_CTRL default
+    - SAUCE: x86/bugs: Make boot modes __ro_after_init
+    - SAUCE: prctl: Add force disable speculation
+    - SAUCE: seccomp: Use PR_SPEC_FORCE_DISABLE
+    - selftest/seccomp: Fix the flag name SECCOMP_FILTER_FLAG_TSYNC
+    - SAUCE: seccomp: Add filter flag to opt-out of SSB mitigation
+    - SAUCE: seccomp: Move speculation migitation control to arch code
+    - SAUCE: x86/speculation: Make "seccomp" the default mode for Speculative
+      Store Bypass
+    - SAUCE: x86/bugs: Rename _RDS to _SSBD
+    - SAUCE: proc: Use underscores for SSBD in 'status'
+    - SAUCE: Documentation/spec_ctrl: Do some minor cleanups
+    - SAUCE: x86/bugs: Fix __ssb_select_mitigation() return type
+    - SAUCE: x86/bugs: Make cpu_show_common() static
+    - x86/entry: define _TIF_ALLWORK_MASK flags explicitly
+    - Revert "x86/cpufeature: Blacklist SPEC_CTRL/PRED_CMD on early Spectre v2
+      microcodes"
+    - SAUCE: kvm/cpuid: Fix CPUID_7_0.EDX handling
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Sat, 19 May 2018 11:58:02 +0200
+
+linux (4.4.0-125.150) xenial; urgency=medium
+
+  * linux: 4.4.0-125.150 -proposed tracker (LP: #1770011)
+
+  * Unable to insert test_bpf module on Xenial (LP: #1765698)
+    - bpf: fix selftests/bpf test_kmod.sh failure when CONFIG_BPF_JIT_ALWAYS_ON=y
+    - test_bpf: Fix testing with CONFIG_BPF_JIT_ALWAYS_ON=y on other arches
+
+  * virtio_scsi race can corrupt memory, panic kernel (LP: #1765241)
+    - SAUCE: (no-up) virtio-scsi: Fix race in target free
+
+  * bpf_map_lookup_elem: BUG: unable to handle kernel paging request
+    (LP: #1763454) // CVE-2017-17862
+    - SAUCE: Add missing hunks from "bpf: fix branch pruning logic"
+
+  * Xenial: rfkill: fix missing return on rfkill_init  (LP: #1764810)
+    - rfkill: fix missing return on rfkill_init
+
+  * "ip a" command on a guest VM shows UNKNOWN status (LP: #1761534)
+    - virtio-net: Fix operstate for virtio when no VIRTIO_NET_F_STATUS
+
+  * Xenial update to 4.4.128 stable release (LP: #1765010)
+    - cfg80211: make RATE_INFO_BW_20 the default
+    - md/raid5: make use of spin_lock_irq over local_irq_disable + spin_lock
+    - rtc: snvs: fix an incorrect check of return value
+    - x86/asm: Don't use RBP as a temporary register in
+      csum_partial_copy_generic()
+    - NFSv4.1: RECLAIM_COMPLETE must handle NFS4ERR_CONN_NOT_BOUND_TO_SESSION
+    - IB/srpt: Fix abort handling
+    - af_key: Fix slab-out-of-bounds in pfkey_compile_policy.
+    - mac80211: bail out from prep_connection() if a reconfig is ongoing
+    - bna: Avoid reading past end of buffer
+    - qlge: Avoid reading past end of buffer
+    - ipmi_ssif: unlock on allocation failure
+    - net: cdc_ncm: Fix TX zero padding
+    - net: ethernet: ti: cpsw: adjust cpsw fifos depth for fullduplex flow control
+    - lockd: fix lockd shutdown race
+    - drivers/misc/vmw_vmci/vmci_queue_pair.c: fix a couple integer overflow tests
+    - pidns: disable pid allocation if pid_ns_prepare_proc() is failed in
+      alloc_pid()
+    - s390: move _text symbol to address higher than zero
+    - net/mlx4_en: Avoid adding steering rules with invalid ring
+    - NFSv4.1: Work around a Linux server bug...
+    - CIFS: silence lockdep splat in cifs_relock_file()
+    - net: qca_spi: Fix alignment issues in rx path
+    - netxen_nic: set rcode to the return status from the call to netxen_issue_cmd
+    - Input: elan_i2c - check if device is there before really probing
+    - Input: elantech - force relative mode on a certain module
+    - KVM: PPC: Book3S PR: Check copy_to/from_user return values
+    - vmxnet3: ensure that adapter is in proper state during force_close
+    - SMB2: Fix share type handling
+    - bus: brcmstb_gisb: Use register offsets with writes too
+    - bus: brcmstb_gisb: correct support for 64-bit address output
+    - PowerCap: Fix an error code in powercap_register_zone()
+    - ARM: dts: imx53-qsrb: Pulldown PMIC IRQ pin
+    - staging: wlan-ng: prism2mgmt.c: fixed a double endian conversion before
+      calling hfa384x_drvr_setconfig16, also fixes relative sparse warning
+    - x86/tsc: Provide 'tsc=unstable' boot parameter
+    - ARM: dts: imx6qdl-wandboard: Fix audio channel swap
+    - ipv6: avoid dad-failures for addresses with NODAD
+    - async_tx: Fix DMA_PREP_FENCE usage in do_async_gen_syndrome()
+    - usb: dwc3: keystone: check return value
+    - btrfs: fix incorrect error return ret being passed to mapping_set_error
+    - ata: libahci: properly propagate return value of platform_get_irq()
+    - neighbour: update neigh timestamps iff update is effective
+    - arp: honour gratuitous ARP _replies_
+    - usb: chipidea: properly handle host or gadget initialization failure
+    - USB: ene_usb6250: fix first command execution
+    - net: x25: fix one potential use-after-free issue
+    - USB: ene_usb6250: fix SCSI residue overwriting
+    - serial: 8250: omap: Disable DMA for console UART
+    - serial: sh-sci: Fix race condition causing garbage during shutdown
+    - sh_eth: Use platform device for printing before register_netdev()
+    - scsi: csiostor: fix use after free in csio_hw_use_fwconfig()
+    - powerpc/mm: Fix virt_addr_valid() etc. on 64-bit hash
+    - ath5k: fix memory leak on buf on failed eeprom read
+    - selftests/powerpc: Fix TM resched DSCR test with some compilers
+    - xfrm: fix state migration copy replay sequence numbers
+    - iio: hi8435: avoid garbage event at first enable
+    - iio: hi8435: cleanup reset gpio
+    - ext4: handle the rest of ext4_mb_load_buddy() ENOMEM errors
+    - md-cluster: fix potential lock issue in add_new_disk
+    - ARM: davinci: da8xx: Create DSP device only when assigned memory
+    - ray_cs: Avoid reading past end of buffer
+    - leds: pca955x: Correct I2C Functionality
+    - sched/numa: Use down_read_trylock() for the mmap_sem
+    - net/mlx5: Tolerate irq_set_affinity_hint() failures
+    - selinux: do not check open permission on sockets
+    - block: fix an error code in add_partition()
+    - mlx5: fix bug reading rss_hash_type from CQE
+    - net: ieee802154: fix net_device reference release too early
+    - libceph: NULL deref on crush_decode() error path
+    - netfilter: ctnetlink: fix incorrect nf_ct_put during hash resize
+    - pNFS/flexfiles: missing error code in ff_layout_alloc_lseg()
+    - ASoC: rsnd: SSI PIO adjust to 24bit mode
+    - scsi: bnx2fc: fix race condition in bnx2fc_get_host_stats()
+    - fix race in drivers/char/random.c:get_reg()
+    - ext4: fix off-by-one on max nr_pages in ext4_find_unwritten_pgoff()
+    - tcp: better validation of received ack sequences
+    - net: move somaxconn init from sysctl code
+    - Input: elan_i2c - clear INT before resetting controller
+    - bonding: Don't update slave->link until ready to commit
+    - KVM: nVMX: Fix handling of lmsw instruction
+    - net: llc: add lock_sock in llc_ui_bind to avoid a race condition
+    - ARM: dts: ls1021a: add "fsl,ls1021a-esdhc" compatible string to esdhc node
+    - thermal: power_allocator: fix one race condition issue for thermal_instances
+      list
+    - perf probe: Add warning message if there is unexpected event name
+    - l2tp: fix missing print session offset info
+    - rds; Reset rs->rs_bound_addr in rds_add_bound() failure path
+    - hwmon: (ina2xx) Make calibration register value fixed
+    - media: videobuf2-core: don't go out of the buffer range
+    - ASoC: Intel: cht_bsw_rt5645: Analog Mic support
+    - scsi: mpt3sas: Proper handling of set/clear of "ATA command pending" flag.
+    - vfb: fix video mode and line_length being set when loaded
+    - gpio: label descriptors using the device name
+    - ASoC: Intel: sst: Fix the return value of 'sst_send_byte_stream_mrfld()'
+    - wl1251: check return from call to wl1251_acx_arp_ip_filter
+    - hdlcdrv: Fix divide by zero in hdlcdrv_ioctl
+    - ovl: filter trusted xattr for non-admin
+    - powerpc/[booke|4xx]: Don't clobber TCR[WP] when setting TCR[DIE]
+    - dmaengine: imx-sdma: Handle return value of clk_prepare_enable
+    - arm64: futex: Fix undefined behaviour with FUTEX_OP_OPARG_SHIFT usage
+    - net/mlx5: avoid build warning for uniprocessor
+    - cxgb4: FW upgrade fixes
+    - rtc: opal: Handle disabled TPO in opal_get_tpo_time()
+    - rtc: interface: Validate alarm-time before handling rollover
+    - SUNRPC: ensure correct error is reported by xs_tcp_setup_socket()
+    - net: freescale: fix potential null pointer dereference
+    - KVM: SVM: do not zero out segment attributes if segment is unusable or not
+      present
+    - clk: scpi: fix return type of __scpi_dvfs_round_rate
+    - clk: Fix __set_clk_rates error print-string
+    - powerpc/spufs: Fix coredump of SPU contexts
+    - perf trace: Add mmap alias for s390
+    - qlcnic: Fix a sleep-in-atomic bug in qlcnic_82xx_hw_write_wx_2M and
+      qlcnic_82xx_hw_read_wx_2M
+    - mISDN: Fix a sleep-in-atomic bug
+    - drm/omap: fix tiled buffer stride calculations
+    - cxgb4: fix incorrect cim_la output for T6
+    - Fix serial console on SNI RM400 machines
+    - bio-integrity: Do not allocate integrity context for bio w/o data
+    - skbuff: return -EMSGSIZE in skb_to_sgvec to prevent overflow
+    - sit: reload iphdr in ipip6_rcv
+    - net/mlx4: Fix the check in attaching steering rules
+    - net/mlx4: Check if Granular QoS per VF has been enabled before updating QP
+      qos_vport
+    - perf header: Set proper module name when build-id event found
+    - perf report: Ensure the perf DSO mapping matches what libdw sees
+    - tags: honor COMPILED_SOURCE with apart output directory
+    - e1000e: fix race condition around skb_tstamp_tx()
+    - cx25840: fix unchecked return values
+    - mceusb: sporadic RX truncation corruption fix
+    - net: phy: avoid genphy_aneg_done() for PHYs without clause 22 support
+    - ARM: imx: Add MXC_CPU_IMX6ULL and cpu_is_imx6ull
+    - e1000e: Undo e1000e_pm_freeze if __e1000_shutdown fails
+    - perf/core: Correct event creation with PERF_FORMAT_GROUP
+    - MIPS: mm: fixed mappings: correct initialisation
+    - MIPS: mm: adjust PKMAP location
+    - MIPS: kprobes: flush_insn_slot should flush only if probe initialised
+    - Fix loop device flush before configure v3
+    - net: emac: fix reset timeout with AR8035 phy
+    - skbuff: only inherit relevant tx_flags
+    - xen: avoid type warning in xchg_xen_ulong
+    - bnx2x: Allow vfs to disable txvlan offload
+    - sctp: fix recursive locking warning in sctp_do_peeloff
+    - sparc64: ldc abort during vds iso boot
+    - iio: magnetometer: st_magn_spi: fix spi_device_id table
+    - Bluetooth: Send HCI Set Event Mask Page 2 command only when needed
+    - cpuidle: dt: Add missing 'of_node_put()'
+    - ACPICA: Events: Add runtime stub support for event APIs
+    - ACPICA: Disassembler: Abort on an invalid/unknown AML opcode
+    - s390/dasd: fix hanging safe offline
+    - vxlan: dont migrate permanent fdb entries during learn
+    - bcache: stop writeback thread after detaching
+    - bcache: segregate flash only volume write streams
+    - scsi: libsas: fix memory leak in sas_smp_get_phy_events()
+    - scsi: libsas: fix error when getting phy events
+    - scsi: libsas: initialize sas_phy status according to response of DISCOVER
+    - blk-mq: fix kernel oops in blk_mq_tag_idle()
+    - tty: n_gsm: Allow ADM response in addition to UA for control dlci
+    - EDAC, mv64x60: Fix an error handling path
+    - cxgb4vf: Fix SGE FL buffer initialization logic for 64K pages
+    - perf tools: Fix copyfile_offset update of output offset
+    - ipsec: check return value of skb_to_sgvec always
+    - rxrpc: check return value of skb_to_sgvec always
+    - virtio_net: check return value of skb_to_sgvec always
+    - virtio_net: check return value of skb_to_sgvec in one more location
+    - random: use lockless method of accessing and updating f->reg_idx
+    - futex: Remove requirement for lock_page() in get_futex_key()
+    - Kbuild: provide a __UNIQUE_ID for clang
+    - arp: fix arp_filter on l3slave devices
+    - net: fix possible out-of-bound read in skb_network_protocol()
+    - net/ipv6: Fix route leaking between VRFs
+    - netlink: make sure nladdr has correct size in netlink_connect()
+    - net/sched: fix NULL dereference in the error path of tcf_bpf_init()
+    - pptp: remove a buggy dst release in pptp_connect()
+    - sctp: do not leak kernel memory to user space
+    - sctp: sctp_sockaddr_af must check minimal addr length for AF_INET6
+    - vhost: correctly remove wait queue during poll failure
+    - vlan: also check phy_driver ts_info for vlan's real device
+    - bonding: fix the err path for dev hwaddr sync in bond_enslave
+    - bonding: move dev_mc_sync after master_upper_dev_link in bond_enslave
+    - bonding: process the err returned by dev_set_allmulti properly in
+      bond_enslave
+    - net: fool proof dev_valid_name()
+    - ip_tunnel: better validate user provided tunnel names
+    - ipv6: sit: better validate user provided tunnel names
+    - ip6_gre: better validate user provided tunnel names
+    - ip6_tunnel: better validate user provided tunnel names
+    - vti6: better validate user provided tunnel names
+    - r8169: fix setting driver_data after register_netdev
+    - net sched actions: fix dumping which requires several messages to user space
+    - net/ipv6: Increment OUTxxx counters after netfilter hook
+    - ipv6: the entire IPv6 header chain must fit the first fragment
+    - vrf: Fix use after free and double free in vrf_finish_output
+    - Revert "xhci: plat: Register shutdown for xhci_plat"
+    - Linux 4.4.128
+
+  * sky2 gigabit ethernet driver sometimes stops working after lid-open resume
+    from sleep (88E8055) (LP: #1758507) // Xenial update to 4.4.128 stable
+    release (LP: #1765010)
+    - sky2: Increase D3 delay to sky2 stops working after suspend
+
+  * Xenial update to 4.4.127 stable release (LP: #1765007)
+    - mtd: jedec_probe: Fix crash in jedec_read_mfr()
+    - ALSA: pcm: Use dma_bytes as size parameter in dma_mmap_coherent()
+    - ALSA: pcm: potential uninitialized return values
+    - partitions/msdos: Unable to mount UFS 44bsd partitions
+    - usb: gadget: define free_ep_req as universal function
+    - usb: gadget: change len to size_t on alloc_ep_req()
+    - usb: gadget: fix usb_ep_align_maybe endianness and new usb_ep_align
+    - usb: gadget: align buffer size when allocating for OUT endpoint
+    - usb: gadget: f_hid: fix: Prevent accessing released memory
+    - kprobes/x86: Fix to set RWX bits correctly before releasing trampoline
+    - ACPI, PCI, irq: remove redundant check for null string pointer
+    - writeback: fix the wrong congested state variable definition
+    - PCI: Make PCI_ROM_ADDRESS_MASK a 32-bit constant
+    - dm ioctl: remove double parentheses
+    - Input: mousedev - fix implicit conversion warning
+    - netfilter: nf_nat_h323: fix logical-not-parentheses warning
+    - genirq: Use cpumask_available() for check of cpumask variable
+    - cpumask: Add helper cpumask_available()
+    - selinux: Remove unnecessary check of array base in selinux_set_mapping()
+    - fs: compat: Remove warning from COMPATIBLE_IOCTL
+    - jiffies.h: declare jiffies and jiffies_64 with ____cacheline_aligned_in_smp
+    - frv: declare jiffies to be located in the .data section
+    - audit: add tty field to LOGIN event
+    - tty: provide tty_name() even without CONFIG_TTY
+    - netfilter: ctnetlink: Make some parameters integer to avoid enum mismatch
+    - selinux: Remove redundant check for unknown labeling behavior
+    - arm64: avoid overflow in VA_START and PAGE_OFFSET
+    - xfrm_user: uncoditionally validate esn replay attribute struct
+    - RDMA/ucma: Check AF family prior resolving address
+    - RDMA/ucma: Fix use-after-free access in ucma_close
+    - RDMA/ucma: Ensure that CM_ID exists prior to access it
+    - RDMA/ucma: Check that device is connected prior to access it
+    - RDMA/ucma: Check that device exists prior to accessing it
+    - RDMA/ucma: Don't allow join attempts for unsupported AF family
+    - RDMA/ucma: Introduce safer rdma_addr_size() variants
+    - net: xfrm: use preempt-safe this_cpu_read() in ipcomp_alloc_tfms()
+    - xfrm: Refuse to insert 32 bit userspace socket policies on 64 bit systems
+    - netfilter: bridge: ebt_among: add more missing match size checks
+    - netfilter: x_tables: add and use xt_check_proc_name
+    - Bluetooth: Fix missing encryption refresh on Security Request
+    - llist: clang: introduce member_address_is_nonnull()
+    - scsi: virtio_scsi: always read VPD pages for multiqueue too
+    - usb: dwc2: Improve gadget state disconnection handling
+    - USB: serial: ftdi_sio: add RT Systems VX-8 cable
+    - USB: serial: ftdi_sio: add support for Harman FirmwareHubEmulator
+    - USB: serial: cp210x: add ELDAT Easywave RX09 id
+    - mei: remove dev_err message on an unsupported ioctl
+    - media: usbtv: prevent double free in error case
+    - parport_pc: Add support for WCH CH382L PCI-E single parallel port card.
+    - crypto: ahash - Fix early termination in hash walk
+    - crypto: x86/cast5-avx - fix ECB encryption when long sg follows short one
+    - fs/proc: Stop trying to report thread stacks
+    - staging: comedi: ni_mio_common: ack ai fifo error interrupts.
+    - Input: i8042 - add Lenovo ThinkPad L460 to i8042 reset list
+    - Input: i8042 - enable MUX on Sony VAIO VGN-CS series to fix touchpad
+    - vt: change SGR 21 to follow the standards
+    - Documentation: pinctrl: palmas: Add ti,palmas-powerhold-override property
+      definition
+    - ARM: dts: dra7: Add power hold and power controller properties to palmas
+    - ARM: dts: am57xx-beagle-x15-common: Add overide powerhold property
+    - md/raid10: reset the 'first' at the end of loop
+    - net: hns: Fix ethtool private flags
+    - Revert "PCI/MSI: Stop disabling MSI/MSI-X in pci_device_shutdown()"
+    - Revert "ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin"
+    - Revert "ARM: dts: omap3-n900: Fix the audio CODEC's reset pin"
+    - Revert "cpufreq: Fix governor module removal race"
+    - Revert "mtip32xx: use runtime tag to initialize command header"
+    - spi: davinci: fix up dma_mapping_error() incorrect patch
+    - net: cavium: liquidio: fix up "Avoid dma_unmap_single on uninitialized
+      ndata"
+    - Revert "ip6_vti: adjust vti mtu according to mtu of lower device"
+    - Linux 4.4.127
+
+  * Xenial update to 4.4.126 stable release (LP: #1764999)
+    - scsi: sg: don't return bogus Sg_requests
+    - Revert "genirq: Use irqd_get_trigger_type to compare the trigger type for
+      shared IRQs"
+    - net: Fix hlist corruptions in inet_evict_bucket()
+    - dccp: check sk for closed state in dccp_sendmsg()
+    - ipv6: fix access to non-linear packet in ndisc_fill_redirect_hdr_option()
+    - l2tp: do not accept arbitrary sockets
+    - net: ethernet: arc: Fix a potential memory leak if an optional regulator is
+      deferred
+    - net: ethernet: ti: cpsw: add check for in-band mode setting with RGMII PHY
+      interface
+    - net/iucv: Free memory obtained by kzalloc
+    - netlink: avoid a double skb free in genlmsg_mcast()
+    - net: Only honor ifindex in IP_PKTINFO if non-0
+    - skbuff: Fix not waking applications when errors are enqueued
+    - team: Fix double free in error path
+    - s390/qeth: free netdevice when removing a card
+    - s390/qeth: when thread completes, wake up all waiters
+    - s390/qeth: lock read device while queueing next buffer
+    - s390/qeth: on channel error, reject further cmd requests
+    - ieee802154: 6lowpan: fix possible NULL deref in lowpan_device_event()
+    - net: fec: Fix unbalanced PM runtime calls
+    - net: systemport: Rewrite __bcm_sysport_tx_reclaim()
+    - Linux 4.4.126
+
+  * Xenial update to 4.4.125 stable release (LP: #1764973)
+    - MIPS: ralink: Remove ralink_halt()
+    - iio: st_pressure: st_accel: pass correct platform data to init
+    - ALSA: usb-audio: Fix parsing descriptor of UAC2 processing unit
+    - ALSA: aloop: Sync stale timer before release
+    - ALSA: aloop: Fix access to not-yet-ready substream via cable
+    - ALSA: hda/realtek - Always immediately update mute LED with pin VREF
+    - mmc: dw_mmc: fix falling from idmac to PIO mode when dw_mci_reset occurs
+    - PCI: Add function 1 DMA alias quirk for Highpoint RocketRAID 644L
+    - ahci: Add PCI-id for the Highpoint Rocketraid 644L card
+    - clk: bcm2835: Protect sections updating shared registers
+    - Bluetooth: btusb: Fix quirk for Atheros 1525/QCA6174
+    - libata: fix length validation of ATAPI-relayed SCSI commands
+    - libata: remove WARN() for DMA or PIO command without data
+    - libata: Apply NOLPM quirk to Crucial MX100 512GB SSDs
+    - libata: Enable queued TRIM for Samsung SSD 860
+    - libata: Apply NOLPM quirk to Crucial M500 480 and 960GB SSDs
+    - libata: Make Crucial BX100 500GB LPM quirk apply to all firmware versions
+    - libata: Modify quirks for MX100 to limit NCQ_TRIM quirk to MU01 version
+    - mm/vmalloc: add interfaces to free unmapped page table
+    - x86/mm: implement free pmd/pte page interfaces
+    - drm/vmwgfx: Fix a destoy-while-held mutex problem.
+    - drm/radeon: Don't turn off DP sink when disconnected
+    - drm: udl: Properly check framebuffer mmap offsets
+    - acpi, numa: fix pxm to online numa node associations
+    - brcmfmac: fix P2P_DEVICE ethernet address generation
+    - rtlwifi: rtl8723be: Fix loss of signal
+    - tracing: probeevent: Fix to support minus offset from symbol
+    - mtd: nand: fsl_ifc: Fix nand waitfunc return value
+    - staging: ncpfs: memory corruption in ncp_read_kernel()
+    - can: cc770: Fix stalls on rt-linux, remove redundant IRQ ack
+    - can: cc770: Fix queue stall & dropped RTR reply
+    - can: cc770: Fix use after free in cc770_tx_interrupt()
+    - tty: vt: fix up tabstops properly
+    - x86/build/64: Force the linker to use 2MB page size
+    - x86/boot/64: Verify alignment of the LOAD segment
+    - perf/x86/intel: Don't accidentally clear high bits in bdw_limit_period()
+    - staging: lustre: ptlrpc: kfree used instead of kvfree
+    - kbuild: disable clang's default use of -fmerge-all-constants
+    - bpf: skip unnecessary capability check
+    - bpf, x64: increase number of passes
+    - Linux 4.4.125
+
+  * System fails to start (boot) on battery due to read-only root file-system
+    (LP: #1726930) // Xenial update to 4.4.125 stable release (LP: #1764973)
+    - libata: disable LPM for Crucial BX100 SSD 500GB drive
+
+  * Xenial update to 4.4.124 stable release (LP: #1764762)
+    - tpm: fix potential buffer overruns caused by bit glitches on the bus
+    - tpm_tis: fix potential buffer overruns caused by bit glitches on the bus
+    - staging: android: ashmem: Fix possible deadlock in ashmem_ioctl
+    - platform/x86: asus-nb-wmi: Add wapf4 quirk for the X302UA
+    - regulator: anatop: set default voltage selector for pcie
+    - x86: i8259: export legacy_pic symbol
+    - rtc: cmos: Do not assume irq 8 for rtc when there are no legacy irqs
+    - Input: ar1021_i2c - fix too long name in driver's device table
+    - time: Change posix clocks ops interfaces to use timespec64
+    - ACPI/processor: Fix error handling in __acpi_processor_start()
+    - ACPI/processor: Replace racy task affinity logic
+    - cpufreq/sh: Replace racy task affinity logic
+    - genirq: Use irqd_get_trigger_type to compare the trigger type for shared
+      IRQs
+    - i2c: i2c-scmi: add a MS HID
+    - net: ipv6: send unsolicited NA on admin up
+    - media/dvb-core: Race condition when writing to CAM
+    - spi: dw: Disable clock after unregistering the host
+    - ath: Fix updating radar flags for coutry code India
+    - clk: ns2: Correct SDIO bits
+    - scsi: virtio_scsi: Always try to read VPD pages
+    - KVM: PPC: Book3S PR: Exit KVM on failed mapping
+    - ARM: 8668/1: ftrace: Fix dynamic ftrace with DEBUG_RODATA and !FRAME_POINTER
+    - iommu/omap: Register driver before setting IOMMU ops
+    - md/raid10: wait up frozen array in handle_write_completed
+    - NFS: Fix missing pg_cleanup after nfs_pageio_cond_complete()
+    - tcp: remove poll() flakes with FastOpen
+    - e1000e: fix timing for 82579 Gigabit Ethernet controller
+    - ALSA: hda - Fix headset microphone detection for ASUS N551 and N751
+    - IB/ipoib: Fix deadlock between ipoib_stop and mcast join flow
+    - IB/ipoib: Update broadcast object if PKey value was changed in index 0
+    - HSI: ssi_protocol: double free in ssip_pn_xmit()
+    - IB/mlx4: Take write semaphore when changing the vma struct
+    - IB/mlx4: Change vma from shared to private
+    - ASoC: Intel: Skylake: Uninitialized variable in probe_codec()
+    - Fix driver usage of 128B WQEs when WQ_CREATE is V1.
+    - netfilter: xt_CT: fix refcnt leak on error path
+    - openvswitch: Delete conntrack entry clashing with an expectation.
+    - mmc: host: omap_hsmmc: checking for NULL instead of IS_ERR()
+    - wan: pc300too: abort path on failure
+    - qlcnic: fix unchecked return value
+    - scsi: mac_esp: Replace bogus memory barrier with spinlock
+    - infiniband/uverbs: Fix integer overflows
+    - NFS: don't try to cross a mountpount when there isn't one there.
+    - Revert "UBUNTU: SAUCE: (no-up) iio: st_pressure: st_accel: Initialise sensor
+      platform data properly"
+    - iio: st_pressure: st_accel: Initialise sensor platform data properly
+    - mt7601u: check return value of alloc_skb
+    - rndis_wlan: add return value validation
+    - Btrfs: send, fix file hole not being preserved due to inline extent
+    - mac80211: don't parse encrypted management frames in ieee80211_frame_acked
+    - mfd: palmas: Reset the POWERHOLD mux during power off
+    - mtip32xx: use runtime tag to initialize command header
+    - staging: unisys: visorhba: fix s-Par to boot with option CONFIG_VMAP_STACK
+      set to y
+    - staging: wilc1000: fix unchecked return value
+    - mmc: sdhci-of-esdhc: limit SD clock for ls1012a/ls1046a
+    - ARM: DRA7: clockdomain: Change the CLKTRCTRL of CM_PCIE_CLKSTCTRL to SW_WKUP
+    - ipmi/watchdog: fix wdog hang on panic waiting for ipmi response
+    - ACPI / PMIC: xpower: Fix power_table addresses
+    - drm/nouveau/kms: Increase max retries in scanout position queries.
+    - bnx2x: Align RX buffers
+    - power: supply: pda_power: move from timer to delayed_work
+    - Input: twl4030-pwrbutton - use correct device for irq request
+    - md/raid10: skip spare disk as 'first' disk
+    - ia64: fix module loading for gcc-5.4
+    - tcm_fileio: Prevent information leak for short reads
+    - video: fbdev: udlfb: Fix buffer on stack
+    - sm501fb: don't return zero on failure path in sm501fb_start()
+    - net: hns: fix ethtool_get_strings overflow in hns driver
+    - cifs: small underflow in cnvrtDosUnixTm()
+    - rtc: ds1374: wdt: Fix issue with timeout scaling from secs to wdt ticks
+    - rtc: ds1374: wdt: Fix stop/start ioctl always returning -EINVAL
+    - perf tests kmod-path: Don't fail if compressed modules aren't supported
+    - Bluetooth: hci_qca: Avoid setup failure on missing rampatch
+    - media: c8sectpfe: fix potential NULL pointer dereference in
+      c8sectpfe_timer_interrupt
+    - drm/msm: fix leak in failed get_pages
+    - RDMA/iwpm: Fix uninitialized error code in iwpm_send_mapinfo()
+    - rtlwifi: rtl_pci: Fix the bug when inactiveps is enabled.
+    - media: bt8xx: Fix err 'bt878_probe()'
+    - media: [RESEND] media: dvb-frontends: Add delay to Si2168 restart
+    - cros_ec: fix nul-termination for firmware build info
+    - platform/chrome: Use proper protocol transfer function
+    - mmc: avoid removing non-removable hosts during suspend
+    - IB/ipoib: Avoid memory leak if the SA returns a different DGID
+    - RDMA/cma: Use correct size when writing netlink stats
+    - IB/umem: Fix use of npages/nmap fields
+    - vgacon: Set VGA struct resource types
+    - drm/omap: DMM: Check for DMM readiness after successful transaction commit
+    - pty: cancel pty slave port buf's work in tty_release
+    - coresight: Fix disabling of CoreSight TPIU
+    - pinctrl: Really force states during suspend/resume
+    - iommu/vt-d: clean up pr_irq if request_threaded_irq fails
+    - ip6_vti: adjust vti mtu according to mtu of lower device
+    - RDMA/ocrdma: Fix permissions for OCRDMA_RESET_STATS
+    - nfsd4: permit layoutget of executable-only files
+    - clk: si5351: Rename internal plls to avoid name collisions
+    - dmaengine: ti-dma-crossbar: Fix event mapping for TPCC_EVT_MUX_60_63
+    - RDMA/ucma: Fix access to non-initialized CM_ID object
+    - Linux 4.4.124
+
+  * Xenial update to 4.4.123 stable release (LP: #1764666)
+    - blkcg: fix double free of new_blkg in blkcg_init_queue
+    - Input: tsc2007 - check for presence and power down tsc2007 during probe
+    - staging: speakup: Replace BUG_ON() with WARN_ON().
+    - staging: wilc1000: add check for kmalloc allocation failure.
+    - HID: reject input outside logical range only if null state is set
+    - drm: qxl: Don't alloc fbdev if emulation is not supported
+    - ath10k: fix a warning during channel switch with multiple vaps
+    - PCI/MSI: Stop disabling MSI/MSI-X in pci_device_shutdown()
+    - selinux: check for address length in selinux_socket_bind()
+    - perf sort: Fix segfault with basic block 'cycles' sort dimension
+    - i40e: Acquire NVM lock before reads on all devices
+    - i40e: fix ethtool to get EEPROM data from X722 interface
+    - perf tools: Make perf_event__synthesize_mmap_events() scale
+    - drivers: net: xgene: Fix hardware checksum setting
+    - drm: Defer disabling the vblank IRQ until the next interrupt (for instant-
+      off)
+    - ath10k: disallow DFS simulation if DFS channel is not enabled
+    - perf probe: Return errno when not hitting any event
+    - HID: clamp input to logical range if no null state
+    - net/8021q: create device with all possible features in wanted_features
+    - ARM: dts: Adjust moxart IRQ controller and flags
+    - batman-adv: handle race condition for claims between gateways
+    - of: fix of_device_get_modalias returned length when truncating buffers
+    - solo6x10: release vb2 buffers in solo_stop_streaming()
+    - scsi: ipr: Fix missed EH wakeup
+    - media: i2c/soc_camera: fix ov6650 sensor getting wrong clock
+    - timers, sched_clock: Update timeout for clock wrap
+    - sysrq: Reset the watchdog timers while displaying high-resolution timers
+    - Input: qt1070 - add OF device ID table
+    - sched: act_csum: don't mangle TCP and UDP GSO packets
+    - ASoC: rcar: ssi: don't set SSICR.CKDV = 000 with SSIWSR.CONT
+    - spi: omap2-mcspi: poll OMAP2_MCSPI_CHSTAT_RXS for PIO transfer
+    - tcp: sysctl: Fix a race to avoid unexpected 0 window from space
+    - dmaengine: imx-sdma: add 1ms delay to ensure SDMA channel is stopped
+    - driver: (adm1275) set the m,b and R coefficients correctly for power
+    - mm: Fix false-positive VM_BUG_ON() in page_cache_{get,add}_speculative()
+    - blk-throttle: make sure expire time isn't too big
+    - f2fs: relax node version check for victim data in gc
+    - bonding: refine bond_fold_stats() wrap detection
+    - braille-console: Fix value returned by _braille_console_setup
+    - drm/vmwgfx: Fixes to vmwgfx_fb
+    - vxlan: vxlan dev should inherit lowerdev's gso_max_size
+    - NFC: nfcmrvl: Include unaligned.h instead of access_ok.h
+    - NFC: nfcmrvl: double free on error path
+    - ARM: dts: r8a7790: Correct parent of SSI[0-9] clocks
+    - ARM: dts: r8a7791: Correct parent of SSI[0-9] clocks
+    - powerpc: Avoid taking a data miss on every userspace instruction miss
+    - net/faraday: Add missing include of of.h
+    - ARM: dts: koelsch: Correct clock frequency of X2 DU clock input
+    - reiserfs: Make cancel_old_flush() reliable
+    - ALSA: firewire-digi00x: handle all MIDI messages on streaming packets
+    - fm10k: correctly check if interface is removed
+    - apparmor: Make path_max parameter readonly
+    - iommu/iova: Fix underflow bug in __alloc_and_insert_iova_range
+    - video: ARM CLCD: fix dma allocation size
+    - drm/radeon: Fail fb creation from imported dma-bufs.
+    - drm/amdgpu: Fail fb creation from imported dma-bufs. (v2)
+    - coresight: Fixes coresight DT parse to get correct output port ID.
+    - MIPS: BPF: Quit clobbering callee saved registers in JIT code.
+    - MIPS: BPF: Fix multiple problems in JIT skb access helpers.
+    - MIPS: r2-on-r6-emu: Fix BLEZL and BGTZL identification
+    - MIPS: r2-on-r6-emu: Clear BLTZALL and BGEZALL debugfs counters
+    - regulator: isl9305: fix array size
+    - md/raid6: Fix anomily when recovering a single device in RAID6.
+    - usb: dwc2: Make sure we disconnect the gadget state
+    - usb: gadget: dummy_hcd: Fix wrong power status bit clear/reset in
+      dummy_hub_control()
+    - drivers/perf: arm_pmu: handle no platform_device
+    - perf inject: Copy events when reordering events in pipe mode
+    - perf session: Don't rely on evlist in pipe mode
+    - scsi: sg: check for valid direction before starting the request
+    - scsi: sg: close race condition in sg_remove_sfp_usercontext()
+    - kprobes/x86: Fix kprobe-booster not to boost far call instructions
+    - kprobes/x86: Set kprobes pages read-only
+    - pwm: tegra: Increase precision in PWM rate calculation
+    - wil6210: fix memory access violation in wil_memcpy_from/toio_32
+    - drm/edid: set ELD connector type in drm_edid_to_eld()
+    - video/hdmi: Allow "empty" HDMI infoframes
+    - HID: elo: clear BTN_LEFT mapping
+    - ARM: dts: exynos: Correct Trats2 panel reset line
+    - sched: Stop switched_to_rt() from sending IPIs to offline CPUs
+    - sched: Stop resched_cpu() from sending IPIs to offline CPUs
+    - test_firmware: fix setting old custom fw path back on exit
+    - net: xfrm: allow clearing socket xfrm policies.
+    - mtd: nand: fix interpretation of NAND_CMD_NONE in nand_command[_lp]()
+    - ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin
+    - ARM: dts: omap3-n900: Fix the audio CODEC's reset pin
+    - ath10k: update tdls teardown state to target
+    - cpufreq: Fix governor module removal race
+    - clk: qcom: msm8916: fix mnd_width for codec_digcodec
+    - ath10k: fix invalid STS_CAP_OFFSET_MASK
+    - tools/usbip: fixes build with musl libc toolchain
+    - spi: sun6i: disable/unprepare clocks on remove
+    - scsi: core: scsi_get_device_flags_keyed(): Always return device flags
+    - scsi: devinfo: apply to HP XP the same flags as Hitachi VSP
+    - scsi: dh: add new rdac devices
+    - media: cpia2: Fix a couple off by one bugs
+    - veth: set peer GSO values
+    - drm/amdkfd: Fix memory leaks in kfd topology
+    - agp/intel: Flush all chipset writes after updating the GGTT
+    - mac80211_hwsim: enforce PS_MANUAL_POLL to be set after PS_ENABLED
+    - mac80211: remove BUG() when interface type is invalid
+    - ASoC: nuc900: Fix a loop timeout test
+    - ipvlan: add L2 check for packets arriving via virtual devices
+    - rcutorture/configinit: Fix build directory error message
+    - ima: relax requiring a file signature for new files with zero length
+    - selftests/x86/entry_from_vm86: Exit with 1 if we fail
+    - selftests/x86: Add tests for User-Mode Instruction Prevention
+    - selftests/x86: Add tests for the STR and SLDT instructions
+    - selftests/x86/entry_from_vm86: Add test cases for POPF
+    - x86/vm86/32: Fix POPF emulation
+    - x86/mm: Fix vmalloc_fault to use pXd_large
+    - ALSA: pcm: Fix UAF in snd_pcm_oss_get_formats()
+    - ALSA: hda - Revert power_save option default value
+    - ALSA: seq: Fix possible UAF in snd_seq_check_queue()
+    - ALSA: seq: Clear client entry before deleting else at closing
+    - drm/amdgpu/dce: Don't turn off DP sink when disconnected
+    - fs: Teach path_connected to handle nfs filesystems with multiple roots.
+    - lock_parent() needs to recheck if dentry got __dentry_kill'ed under it
+    - fs/aio: Add explicit RCU grace period when freeing kioctx
+    - fs/aio: Use RCU accessors for kioctx_table->table[]
+    - irqchip/gic-v3-its: Ensure nr_ites >= nr_lpis
+    - scsi: sg: fix SG_DXFER_FROM_DEV transfers
+    - scsi: sg: fix static checker warning in sg_is_valid_dxfer
+    - scsi: sg: only check for dxfer_len greater than 256M
+    - ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux
+    - btrfs: alloc_chunk: fix DUP stripe size handling
+    - btrfs: Fix use-after-free when cleaning up fs_devs with a single stale
+      device
+    - USB: gadget: udc: Add missing platform_device_put() on error in
+      bdc_pci_probe()
+    - usb: gadget: bdc: 64-bit pointer capability check
+    - Linux 4.4.123
+
+  * Xenial update to 4.4.123 stable release (LP: #1764666) // CVE-2017-16995
+    - Revert "bpf: fix incorrect sign extension in check_alu_op()"
+    - bpf: fix incorrect sign extension in check_alu_op()
+
+  * Xenial update to 4.4.122 stable release (LP: #1764627)
+    - RDMA/ucma: Limit possible option size
+    - RDMA/ucma: Check that user doesn't overflow QP state
+    - RDMA/mlx5: Fix integer overflow while resizing CQ
+    - scsi: qla2xxx: Fix NULL pointer crash due to active timer for ABTS
+    - workqueue: Allow retrieval of current task's work struct
+    - drm: Allow determining if current task is output poll worker
+    - drm/nouveau: Fix deadlock on runtime suspend
+    - drm/radeon: Fix deadlock on runtime suspend
+    - drm/amdgpu: Fix deadlock on runtime suspend
+    - drm/amdgpu: Notify sbios device ready before send request
+    - drm/radeon: fix KV harvesting
+    - drm/amdgpu: fix KV harvesting
+    - MIPS: BMIPS: Do not mask IPIs during suspend
+    - MIPS: ath25: Check for kzalloc allocation failure
+    - MIPS: OCTEON: irq: Check for null return on kzalloc allocation
+    - Input: matrix_keypad - fix race when disabling interrupts
+    - loop: Fix lost writes caused by missing flag
+    - kbuild: Handle builtin dtb file names containing hyphens
+    - bcache: don't attach backing with duplicate UUID
+    - x86/MCE: Serialize sysfs changes
+    - ALSA: hda/realtek - Fix dock line-out volume on Dell Precision 7520
+    - ALSA: seq: More protection for concurrent write and ioctl races
+    - ALSA: hda: add dock and led support for HP EliteBook 820 G3
+    - ALSA: hda: add dock and led support for HP ProBook 640 G2
+    - watchdog: hpwdt: SMBIOS check
+    - watchdog: hpwdt: Check source of NMI
+    - watchdog: hpwdt: fix unused variable warning
+    - netfilter: nfnetlink_queue: fix timestamp attribute
+    - Input: tca8418_keypad - remove double read of key event register
+    - tc358743: fix register i2c_rd/wr function fix
+    - netfilter: add back stackpointer size checks
+    - netfilter: x_tables: fix missing timer initialization in xt_LED
+    - netfilter: nat: cope with negative port range
+    - netfilter: IDLETIMER: be syzkaller friendly
+    - netfilter: ebtables: CONFIG_COMPAT: don't trust userland offsets
+    - netfilter: bridge: ebt_among: add missing match size checks
+    - netfilter: ipv6: fix use-after-free Write in nf_nat_ipv6_manip_pkt
+    - netfilter: use skb_to_full_sk in ip_route_me_harder
+    - ext4: inplace xattr block update fails to deduplicate blocks
+    - ubi: Fix race condition between ubi volume creation and udev
+    - scsi: qla2xxx: Replace fcport alloc with qla2x00_alloc_fcport
+    - NFS: Fix an incorrect type in struct nfs_direct_req
+    - Revert "ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux"
+    - x86/module: Detect and skip invalid relocations
+    - x86: Treat R_X86_64_PLT32 as R_X86_64_PC32
+    - serial: sh-sci: prevent lockup on full TTY buffers
+    - tty/serial: atmel: add new version check for usart
+    - uas: fix comparison for error code
+    - staging: comedi: fix comedi_nsamples_left.
+    - staging: android: ashmem: Fix lockdep issue during llseek
+    - USB: storage: Add JMicron bridge 152d:2567 to unusual_devs.h
+    - usb: quirks: add control message delay for 1b1c:1b20
+    - USB: usbmon: remove assignment from IS_ERR argument
+    - usb: usbmon: Read text within supplied buffer size
+    - usb: gadget: f_fs: Fix use-after-free in ffs_fs_kill_sb()
+    - serial: 8250_pci: Add Brainboxes UC-260 4 port serial device
+    - fixup: sctp: verify size of a new chunk in _sctp_make_chunk()
+    - Linux 4.4.122
+
+  * Xenial update to 4.4.122 stable release (LP: #1764627) // CVE-2018-1000004.
+    - ALSA: seq: Don't allow resizing pool in use
+
+  * Xenial update to 4.4.121 stable release (LP: #1764367)
+    - tpm: st33zp24: fix potential buffer overruns caused by bit glitches on the
+      bus
+    - tpm_i2c_infineon: fix potential buffer overruns caused by bit glitches on
+      the bus
+    - tpm_i2c_nuvoton: fix potential buffer overruns caused by bit glitches on the
+      bus
+    - ALSA: usb-audio: Add a quirck for B&W PX headphones
+    - ALSA: hda: Add a power_save blacklist
+    - cpufreq: s3c24xx: Fix broken s3c_cpufreq_init()
+    - media: m88ds3103: don't call a non-initalized function
+    - ARM: mvebu: Fix broken PL310_ERRATA_753970 selects
+    - KVM: mmu: Fix overlap between public and private memslots
+    - btrfs: Don't clear SGID when inheriting ACLs
+    - ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux
+    - x86/apic/vector: Handle legacy irq data correctly
+    - leds: do not overflow sysfs buffer in led_trigger_show
+    - x86/spectre: Fix an error message
+    - bridge: check brport attr show in brport_show
+    - fib_semantics: Don't match route with mismatching tclassid
+    - hdlc_ppp: carrier detect ok, don't turn off negotiation
+    - ipv6 sit: work around bogus gcc-8 -Wrestrict warning
+    - net: fix race on decreasing number of TX queues
+    - net: ipv4: don't allow setting net.ipv4.route.min_pmtu below 68
+    - netlink: ensure to loop over all netns in genlmsg_multicast_allns()
+    - ppp: prevent unregistered channels from connecting to PPP units
+    - udplite: fix partial checksum initialization
+    - sctp: fix dst refcnt leak in sctp_v4_get_dst
+    - sctp: fix dst refcnt leak in sctp_v6_get_dst()
+    - s390/qeth: fix SETIP command handling
+    - s390/qeth: fix IPA command submission race
+    - sctp: verify size of a new chunk in _sctp_make_chunk()
+    - net: mpls: Pull common label check into helper
+    - dm io: fix duplicate bio completion due to missing ref count
+    - bpf, x64: implement retpoline for tail call
+    - btrfs: preserve i_mode if __btrfs_set_acl() fails
+    - Linux 4.4.121
+
+  * Xenial update to 4.4.120 stable release (LP: #1764316)
+    - hrtimer: Ensure POSIX compliance (relative CLOCK_REALTIME hrtimers)
+    - f2fs: fix a bug caused by NULL extent tree
+    - mtd: nand: gpmi: Fix failure when a erased page has a bitflip at BBM
+    - ipv6: icmp6: Allow icmp messages to be looped back
+    - ARM: 8731/1: Fix csum_partial_copy_from_user() stack mismatch
+    - sget(): handle failures of register_shrinker()
+    - drm/nouveau/pci: do a msi rearm on init
+    - spi: atmel: fixed spin_lock usage inside atmel_spi_remove
+    - net: arc_emac: fix arc_emac_rx() error paths
+    - scsi: storvsc: Fix scsi_cmd error assignments in storvsc_handle_error
+    - ARM: dts: ls1021a: fix incorrect clock references
+    - lib/mpi: Fix umul_ppmm() for MIPS64r6
+    - tg3: Add workaround to restrict 5762 MRRS to 2048
+    - tg3: Enable PHY reset in MTU change path for 5720
+    - bnx2x: Improve reliability in case of nested PCI errors
+    - s390/dasd: fix wrongly assigned configuration data
+    - IB/mlx4: Fix mlx4_ib_alloc_mr error flow
+    - IB/ipoib: Fix race condition in neigh creation
+    - xfs: quota: fix missed destroy of qi_tree_lock
+    - xfs: quota: check result of register_shrinker()
+    - e1000: fix disabling already-disabled warning
+    - drm/ttm: check the return value of kzalloc
+    - mac80211: mesh: drop frames appearing to be from us
+    - can: flex_can: Correct the checking for frame length in flexcan_start_xmit()
+    - bnxt_en: Fix the 'Invalid VF' id check in bnxt_vf_ndo_prep routine.
+    - xen-netfront: enable device after manual module load
+    - mdio-sun4i: Fix a memory leak
+    - SolutionEngine771x: fix Ether platform data
+    - xen/gntdev: Fix off-by-one error when unmapping with holes
+    - xen/gntdev: Fix partial gntdev_mmap() cleanup
+    - sctp: make use of pre-calculated len
+    - net: gianfar_ptp: move set_fipers() to spinlock protecting area
+    - MIPS: Implement __multi3 for GCC7 MIPS64r6 builds
+    - Linux 4.4.120
+
+  * Xenial update to 4.4.119 stable release (LP: #1762453)
+    - netfilter: drop outermost socket lock in getsockopt()
+    - powerpc/64s: Fix RFI flush dependency on HARDLOCKUP_DETECTOR
+    - PCI: keystone: Fix interrupt-controller-node lookup
+    - ip_tunnel: replace dst_cache with generic implementation
+    - ip_tunnel: fix preempt warning in ip tunnel creation/updating
+    - scsi: ibmvfc: fix misdefined reserved field in ibmvfc_fcp_rsp_info
+    - cfg80211: fix cfg80211_beacon_dup
+    - iio: buffer: check if a buffer has been set up when poll is called
+    - iio: adis_lib: Initialize trigger before requesting interrupt
+    - x86/oprofile: Fix bogus GCC-8 warning in nmi_setup()
+    - irqchip/gic-v3: Use wmb() instead of smb_wmb() in gic_raise_softirq()
+    - usb: ohci: Proper handling of ed_rm_list to handle race condition between
+      usb_kill_urb() and finish_unlinks()
+    - arm64: Disable unhandled signal log messages by default
+    - Add delay-init quirk for Corsair K70 RGB keyboards
+    - usb: dwc3: gadget: Set maxpacket size for ep0 IN
+    - usb: ldusb: add PIDs for new CASSY devices supported by this driver
+    - usb: gadget: f_fs: Process all descriptors during bind
+    - usb: renesas_usbhs: missed the "running" flag in usb_dmac with rx path
+    - drm/amdgpu: Avoid leaking PM domain on driver unbind (v2)
+    - binder: add missing binder_unlock()
+    - Linux 4.4.119
+
+  * [regression] Colour banding and artefacts appear system-wide on an Asus
+    Zenbook UX303LA with Intel HD 4400 graphics (LP: #1749420) // Xenial update
+    to 4.4.119 stable release (LP: #1762453)
+    - drm/edid: Add 6 bpc quirk for CPT panel in Asus UX303LA
+
+  * Xenial update to 4.4.118 stable release (LP: #1756866)
+    - net: add dst_cache support
+    - [Config] Add CONFIG_DST_CACHE=y
+    - net: replace dst_cache ip6_tunnel implementation with the generic one
+    - cfg80211: check dev_set_name() return value
+    - mm,vmscan: Make unregister_shrinker() no-op if register_shrinker() failed.
+    - xfrm: Fix stack-out-of-bounds read on socket policy lookup.
+    - xfrm: check id proto in validate_tmpl()
+    - blktrace: fix unlocked registration of tracepoints
+    - drm: Require __GFP_NOFAIL for the legacy drm_modeset_lock_all
+    - Provide a function to create a NUL-terminated string from unterminated data
+    - selinux: ensure the context is NUL terminated in
+      security_context_to_sid_core()
+    - selinux: skip bounded transition processing if the policy isn't loaded
+    - crypto: x86/twofish-3way - Fix %rbp usage
+    - KVM: x86: fix escape of guest dr6 to the host
+    - netfilter: x_tables: fix int overflow in xt_alloc_table_info()
+    - netfilter: x_tables: avoid out-of-bounds reads in
+      xt_request_find_{match|target}
+    - netfilter: ipt_CLUSTERIP: fix out-of-bounds accesses in clusterip_tg_check()
+    - netfilter: on sockopt() acquire sock lock only in the required scope
+    - netfilter: xt_RATEEST: acquire xt_rateest_mutex for hash insert
+    - net: avoid skb_warn_bad_offload on IS_ERR
+    - ASoC: ux500: add MODULE_LICENSE tag
+    - video: fbdev/mmp: add MODULE_LICENSE
+    - arm64: dts: add #cooling-cells to CPU nodes
+    - Make DST_CACHE a silent config option
+    - dn_getsockoptdecnet: move nf_{get/set}sockopt outside sock lock
+    - staging: android: ashmem: Fix a race condition in pin ioctls
+    - binder: check for binder_thread allocation failure in binder_poll()
+    - staging: iio: adc: ad7192: fix external frequency setting
+    - usbip: keep usbip_device sockfd state in sync with tcp_socket
+    - usb: build drivers/usb/common/ when USB_SUPPORT is set
+    - ARM: OMAP2+: Fix SRAM virt to phys translation for save_secure_ram_context
+    - ARM: AM33xx: PRM: Remove am33xx_pwrdm_read_prev_pwrst function
+    - ARM: dts: Fix omap4 hang with GPS connected to USB by using wakeupgen
+    - ARM: dts: am4372: Correct the interrupts_properties of McASP
+    - perf top: Fix window dimensions change handling
+    - perf bench numa: Fixup discontiguous/sparse numa nodes
+    - media: s5k6aa: describe some function parameters
+    - pinctrl: sunxi: Fix A80 interrupt pin bank
+    - RDMA/cma: Make sure that PSN is not over max allowed
+    - scripts/kernel-doc: Don't fail with status != 0 if error encountered with
+      -none
+    - ipvlan: Add the skb->mark as flow4's member to lookup route
+    - powerpc/perf: Fix oops when grouping different pmu events
+    - s390/dasd: prevent prefix I/O error
+    - gianfar: fix a flooded alignment reports because of padding issue.
+    - net_sched: red: Avoid devision by zero
+    - net_sched: red: Avoid illegal values
+    - btrfs: Fix possible off-by-one in btrfs_search_path_in_tree
+    - 509: fix printing uninitialized stack memory when OID is empty
+    - dmaengine: ioat: Fix error handling path
+    - dmaengine: at_hdmac: fix potential NULL pointer dereference in
+      atc_prep_dma_interleaved
+    - clk: fix a panic error caused by accessing NULL pointer
+    - ASoC: rockchip: disable clock on error
+    - spi: sun4i: disable clocks in the remove function
+    - xfrm: Fix stack-out-of-bounds with misconfigured transport mode policies.
+    - drm/armada: fix leak of crtc structure
+    - dmaengine: jz4740: disable/unprepare clk if probe fails
+    - mm/early_ioremap: Fix boot hang with earlyprintk=efi,keep
+    - x86/mm/kmmio: Fix mmiotrace for page unaligned addresses
+    - xen: XEN_ACPI_PROCESSOR is Dom0-only
+    - hippi: Fix a Fix a possible sleep-in-atomic bug in rr_close
+    - virtio_balloon: prevent uninitialized variable use
+    - isdn: icn: remove a #warning
+    - vmxnet3: prevent building with 64K pages
+    - [Config] ppc64el: Drop vmxnet3 module
+    - gpio: intel-mid: Fix build warning when !CONFIG_PM
+    - platform/x86: intel_mid_thermal: Fix suspend handlers unused warning
+    - video: fbdev: via: remove possibly unused variables
+    - scsi: advansys: fix build warning for PCI=n
+    - x86/ras/inject: Make it depend on X86_LOCAL_APIC=y
+    - arm64: define BUG() instruction without CONFIG_BUG
+    - x86/fpu/math-emu: Fix possible uninitialized variable use
+    - tools build: Add tools tree support for 'make -s'
+    - x86/build: Silence the build with "make -s"
+    - thermal: fix INTEL_SOC_DTS_IOSF_CORE dependencies
+    - x86: add MULTIUSER dependency for KVM
+    - x86/platform: Add PCI dependency for PUNIT_ATOM_DEBUG
+    - scsi: advansys: fix uninitialized data access
+    - arm64: Kconfig: select COMPAT_BINFMT_ELF only when BINFMT_ELF is set
+    - ALSA: hda/ca0132 - fix possible NULL pointer use
+    - reiserfs: avoid a -Wmaybe-uninitialized warning
+    - ssb: mark ssb_bus_register as __maybe_unused
+    - thermal: spear: use __maybe_unused for PM functions
+    - x86/boot: Avoid warning for zero-filling .bss
+    - scsi: sim710: fix build warning
+    - drivers/net: fix eisa_driver probe section mismatch
+    - dpt_i2o: fix build warning
+    - profile: hide unused functions when !CONFIG_PROC_FS
+    - md: avoid warning for 32-bit sector_t
+    - mtd: ichxrom: maybe-uninitialized with gcc-4.9
+    - mtd: maps: add __init attribute
+    - mptfusion: hide unused seq_mpt_print_ioc_summary function
+    - scsi: fdomain: drop fdomain_pci_tbl when built-in
+    - video: fbdev: sis: remove unused variable
+    - staging: ste_rmi4: avoid unused function warnings
+    - fbdev: sis: enforce selection of at least one backend
+    - video: Use bool instead int pointer for get_opt_bool() argument
+    - scsi: mvumi: use __maybe_unused to hide pm functions
+    - SCSI: initio: remove duplicate module device table
+    - pwc: hide unused label
+    - usb: musb/ux500: remove duplicate check for dma_is_compatible
+    - tty: hvc_xen: hide xen_console_remove when unused
+    - target/user: Fix cast from pointer to phys_addr_t
+    - driver-core: use 'dev' argument in dev_dbg_ratelimited stub
+    - fbdev: auo_k190x: avoid unused function warnings
+    - amd-xgbe: Fix unused suspend handlers build warning
+    - mtd: sh_flctl: pass FIFO as physical address
+    - mtd: cfi: enforce valid geometry configuration
+    - fbdev: s6e8ax0: avoid unused function warnings
+    - modsign: hide openssl output in silent builds
+    - fbdev: sm712fb: avoid unused function warnings
+    - hwrng: exynos - use __maybe_unused to hide pm functions
+    - USB: cdc_subset: only build when one driver is enabled
+    - [Config] Add CONFIG_USB_NET_CDC_SUBSET_ENABLE=m
+    - rtlwifi: fix gcc-6 indentation warning
+    - staging: wilc1000: fix kbuild test robot error
+    - x86/platform/olpc: Fix resume handler build warning
+    - netfilter: ipvs: avoid unused variable warnings
+    - ipv4: ipconfig: avoid unused ic_proto_used symbol
+    - tc1100-wmi: fix build warning when CONFIG_PM not enabled
+    - tlan: avoid unused label with PCI=n
+    - drm/vmwgfx: use *_32_bits() macros
+    - tty: cyclades: cyz_interrupt is only used for PCI
+    - genirq/msi: Add stubs for get_cached_msi_msg/pci_write_msi_msg
+    - ASoC: mediatek: add i2c dependency
+    - iio: adc: axp288: remove redundant duplicate const on axp288_adc_channels
+    - infiniband: cxgb4: use %pR format string for printing resources
+    - b2c2: flexcop: avoid unused function warnings
+    - i2c: remove __init from i2c_register_board_info()
+    - staging: unisys: visorinput depends on INPUT
+    - tc358743: fix register i2c_rd/wr functions
+    - drm/nouveau: hide gcc-4.9 -Wmaybe-uninitialized
+    - Input: tca8418_keypad - hide gcc-4.9 -Wmaybe-uninitialized warning
+    - KVM: add X86_LOCAL_APIC dependency
+    - go7007: add MEDIA_CAMERA_SUPPORT dependency
+    - em28xx: only use mt9v011 if camera support is enabled
+    - ISDN: eicon: reduce stack size of sig_ind function
+    - ASoC: rockchip: use __maybe_unused to hide st_irq_syscfg_resume
+    - serial: 8250_mid: fix broken DMA dependency
+    - drm/gma500: Sanity-check pipe index
+    - hdpvr: hide unused variable
+    - v4l: remove MEDIA_TUNER dependency for VIDEO_TUNER
+    - cw1200: fix bogus maybe-uninitialized warning
+    - wireless: cw1200: use __maybe_unused to hide pm functions_
+    - perf/x86: Shut up false-positive -Wmaybe-uninitialized warning
+    - dmaengine: zx: fix build warning
+    - net: hp100: remove unnecessary #ifdefs
+    - gpio: xgene: mark PM functions as __maybe_unused
+    - ncpfs: fix unused variable warning
+    - Revert "power: bq27xxx_battery: Remove unneeded dependency in Kconfig"
+    - power: bq27xxx_battery: mark some symbols __maybe_unused
+    - isdn: sc: work around type mismatch warning
+    - binfmt_elf: compat: avoid unused function warning
+    - idle: i7300: add PCI dependency
+    - usb: phy: msm add regulator dependency
+    - ncr5380: shut up gcc indentation warning
+    - ARM: tegra: select USB_ULPI from EHCI rather than platform
+    - ASoC: Intel: Kconfig: fix build when ACPI is not enabled
+    - netlink: fix nla_put_{u8,u16,u32} for KASAN
+    - dell-wmi, dell-laptop: depends DMI
+    - genksyms: Fix segfault with invalid declarations
+    - x86/microcode/AMD: Change load_microcode_amd()'s param to bool to fix
+      preemptibility bug
+    - drm/gma500: remove helper function
+    - kasan: rework Kconfig settings
+    - KVM: async_pf: Fix #DF due to inject "Page not Present" and "Page Ready"
+      exceptions simultaneously
+    - x86/retpoline: Remove the esp/rsp thunk
+    - module/retpoline: Warn about missing retpoline in module
+    - x86/nospec: Fix header guards names
+    - x86/bugs: Drop one "mitigation" from dmesg
+    - x86/cpu/bugs: Make retpoline module warning conditional
+    - x86/spectre: Check CONFIG_RETPOLINE in command line parser
+    - x86/spectre: Fix spelling mistake: "vunerable"-> "vulnerable"
+    - x86/paravirt: Remove 'noreplace-paravirt' cmdline option
+    - x86/retpoline: Avoid retpolines for built-in __init functions
+    - x86/spectre: Simplify spectre_v2 command line parsing
+    - x86/speculation: Fix typo IBRS_ATT, which should be IBRS_ALL
+    - KVM: nVMX: kmap() can't fail
+    - KVM: nVMX: vmx_complete_nested_posted_interrupt() can't fail
+    - kvm: nVMX: Fix kernel panics induced by illegal INVEPT/INVVPID types
+    - KVM: VMX: clean up declaration of VPID/EPT invalidation types
+    - KVM: nVMX: invvpid handling improvements
+    - crypto: s5p-sss - Fix kernel Oops in AES-ECB mode
+    - net: dst_cache_per_cpu_dst_set() can be static
+    - ARM: omap2: hide omap3_save_secure_ram on non-OMAP3 builds
+    - Linux 4.4.118
+
+  * ibrs/ibpb fixes result in excessive kernel logging  (LP: #1755627)
+    - SAUCE: remove ibrs_dump sysctl interface
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 07 May 2018 09:23:29 +0200
+
+linux (4.4.0-124.148) xenial; urgency=medium
+
+  * CVE-2018-8897
+    - x86/entry/64: Don't use IST entry for #BP stack
+
+  * CVE-2018-1087
+    - kvm/x86: fix icebp instruction handling
+
+  * CVE-2018-1000199
+    - perf/hwbp: Simplify the perf-hwbp code, fix documentation
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 02 May 2018 11:37:20 +0200
+
+linux (4.4.0-122.146) xenial; urgency=medium
+
+  * linux: 4.4.0-122.146 -proposed tracker (LP: #1766264)
+
+  * Redpine: WiFi scan stopping issue observed with BLE (LP: #1757435)
+    - SAUCE: Redpine: resolve wifi scan stop issue in stress tests
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 23 Apr 2018 16:25:01 +0200
+
+linux (4.4.0-121.145) xenial; urgency=medium
+
+  * linux: 4.4.0-121.145 -proposed tracker (LP: #1763687)
+
+  * Ubuntu-4.4.0-120.144 fails to boot on arm64* hardware (LP: #1763644)
+    - [Config] arm64: disable BPF_JIT_ALWAYS_ON
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 13 Apr 2018 14:42:14 +0200
+
+linux (4.4.0-120.144) xenial; urgency=medium
+
+  * linux: 4.4.0-120.144 -proposed tracker (LP: #1761438)
+
+  * intel-microcode 3.20180312.0 causes lockup at login screen(w/ linux-
+    image-4.13.0-37-generic) (LP: #1759920) // CVE-2017-5715 (Spectre v2 Intel)
+    - Revert "x86/mm: Only set IBPB when the new thread cannot ptrace current
+      thread"
+    - x86/speculation: Use Indirect Branch Prediction Barrier in context switch
+
+  * DKMS driver builds fail with: Cannot use CONFIG_STACK_VALIDATION=y, please
+    install libelf-dev, libelf-devel or elfutils-libelf-devel (LP: #1760876)
+    - [Packaging] include the retpoline extractor in the headers
+
+  * retpoline hints: primary infrastructure and initial hints (LP: #1758856)
+    - [Packaging] retpoline-extract: flag *0xNNN(%reg) branches
+    - x86/speculation, objtool: Annotate indirect calls/jumps for objtool
+    - x86/speculation, objtool: Annotate indirect calls/jumps for objtool on 32bit
+    - x86/paravirt, objtool: Annotate indirect calls
+    - x86/asm: Stop depending on ptrace.h in alternative.h
+    - [Packaging] retpoline -- add safe usage hint support
+    - [Packaging] retpoline-check -- only report additions
+    - [Packaging] retpoline -- widen indirect call/jmp detection
+    - [Packaging] retpoline -- elide %rip relative indirections
+    - [Packaging] retpoline -- clear hint information from packages
+    - SAUCE: modpost: add discard to non-allocatable whitelist
+    - KVM: x86: Make indirect calls in emulator speculation safe
+    - KVM: VMX: Make indirect call speculation safe
+    - x86/boot, objtool: Annotate indirect jump in secondary_startup_64()
+    - SAUCE: early/late -- annotate indirect calls in early/late initialisation
+      code
+    - SAUCE: vga_set_mode -- avoid jump tables
+    - [Config] retpoline -- switch to new format
+    - [Packaging] final-checks -- remove check for empty retpoline files
+
+  * Xenial update to 4.4.117 stable release (LP: #1756860)
+    - IB/mlx4: Fix incorrectly releasing steerable UD QPs when have only ETH ports
+    - PM / devfreq: Propagate error from devfreq_add_device()
+    - s390: fix handling of -1 in set{,fs}[gu]id16 syscalls
+    - ARM: dts: STi: Add gpio polarity for "hdmi,hpd-gpio" property
+    - arm: spear600: Add missing interrupt-parent of rtc
+    - arm: spear13xx: Fix dmas cells
+    - arm: spear13xx: Fix spics gpio controller's warning
+    - ALSA: seq: Fix regression by incorrect ioctl_mutex usages
+    - KVM/x86: Reduce retpoline performance impact in slot_handle_level_range(),
+      by always inlining iterator helper methods
+    - x86/cpu: Change type of x86_cache_size variable to unsigned int
+    - drm/radeon: adjust tested variable
+    - rtc-opal: Fix handling of firmware error codes, prevent busy loops
+    - ext4: save error to disk in __ext4_grp_locked_error()
+    - ext4: correct documentation for grpid mount option
+    - mm: hide a #warning for COMPILE_TEST
+    - video: fbdev: atmel_lcdfb: fix display-timings lookup
+    - console/dummy: leave .con_font_get set to NULL
+    - rtlwifi: rtl8821ae: Fix connection lost problem correctly
+    - Btrfs: fix deadlock in run_delalloc_nocow
+    - Btrfs: fix crash due to not cleaning up tree log block's dirty bits
+    - Btrfs: fix unexpected -EEXIST when creating new inode
+    - ALSA: hda - Fix headset mic detection problem for two Dell machines
+    - ALSA: usb-audio: Fix UAC2 get_ctl request with a RANGE attribute
+    - ALSA: hda/realtek: PCI quirk for Fujitsu U7x7
+    - ALSA: usb-audio: add implicit fb quirk for Behringer UFX1204
+    - ALSA: seq: Fix racy pool initializations
+    - mvpp2: fix multicast address filter
+    - dm: correctly handle chained bios in dec_pending()
+    - x86: fix build warnign with 32-bit PAE
+    - vfs: don't do RCU lookup of empty pathnames
+    - ARM: pxa/tosa-bt: add MODULE_LICENSE tag
+    - ARM: dts: s5pv210: add interrupt-parent for ohci
+    - media: r820t: fix r820t_write_reg for KASAN
+    - Linux 4.4.117
+
+  * zfs system process hung on container stop/delete (LP: #1754584)
+    - SAUCE: (noup) zfs to 0.6.5.6-0ubuntu19
+    - SAUCE: Fix non-prefaulted page deadlock (LP: #1754584)
+
+  * apparmor: fix bad __initdata tagging on, apparmor_initialized (LP: #1758471)
+    - SAUCE: apparmor: fix bad __initdata tagging on, apparmor_initialized
+
+  * Xenial update to 4.4.116 stable release (LP: #1756121)
+    - powerpc/bpf/jit: Disable classic BPF JIT on ppc64le
+    - powerpc/64: Fix flush_(d|i)cache_range() called from modules
+    - powerpc: Fix VSX enabling/flushing to also test MSR_FP and MSR_VEC
+    - powerpc: Simplify module TOC handling
+    - ASoC: pcm512x: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - usbip: vhci_hcd: clear just the USB_PORT_STAT_POWER bit
+    - usbip: fix 3eee23c3ec14 tcp_socket address still in the status file
+    - net: cdc_ncm: initialize drvflags before usage
+    - ASoC: simple-card: Fix misleading error message
+    - ASoC: rsnd: don't call free_irq() on Parent SSI
+    - ASoC: rsnd: avoid duplicate free_irq()
+    - drm: rcar-du: Use the VBK interrupt for vblank events
+    - drm: rcar-du: Fix race condition when disabling planes at CRTC stop
+    - x86/asm: Fix inline asm call constraints for GCC 4.4
+    - ip6mr: fix stale iterator
+    - net: igmp: add a missing rcu locking section
+    - qlcnic: fix deadlock bug
+    - r8169: fix RTL8168EP take too long to complete driver initialization.
+    - tcp: release sk_frag.page in tcp_disconnect
+    - vhost_net: stop device during reset owner
+    - media: soc_camera: soc_scale_crop: add missing
+      MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - KEYS: encrypted: fix buffer overread in valid_master_desc()
+    - don't put symlink bodies in pagecache into highmem
+    - crypto: tcrypt - fix S/G table for test_aead_speed()
+    - x86/microcode: Do the family check first
+    - powerpc/pseries: include linux/types.h in asm/hvcall.h
+    - cifs: Fix missing put_xid in cifs_file_strict_mmap
+    - cifs: Fix autonegotiate security settings mismatch
+    - CIFS: zero sensitive data when freeing
+    - dmaengine: dmatest: fix container_of member in dmatest_callback
+    - x86/kaiser: fix build error with KASAN && !FUNCTION_GRAPH_TRACER
+    - kaiser: fix compile error without vsyscall
+    - netfilter: nf_queue: Make the queue_handler pernet
+    - posix-timer: Properly check sigevent->sigev_notify
+    - usb: gadget: uvc: Missing files for configfs interface
+    - sched/rt: Use container_of() to get root domain in rto_push_irq_work_func()
+    - sched/rt: Up the root domain ref count when passing it around via IPIs
+    - media: dvb-usb-v2: lmedm04: Improve logic checking of warm start
+    - media: dvb-usb-v2: lmedm04: move ts2020 attach to dm04_lme2510_tuner
+    - mtd: cfi: convert inline functions to macros
+    - mtd: nand: brcmnand: Disable prefetch by default
+    - mtd: nand: Fix nand_do_read_oob() return value
+    - mtd: nand: sunxi: Fix ECC strength choice
+    - ubi: block: Fix locking for idr_alloc/idr_remove
+    - nfs/pnfs: fix nfs_direct_req ref leak when i/o falls back to the mds
+    - NFS: Add a cond_resched() to nfs_commit_release_pages()
+    - NFS: commit direct writes even if they fail partially
+    - NFS: reject request for id_legacy key without auxdata
+    - kernfs: fix regression in kernfs_fop_write caused by wrong type
+    - ahci: Annotate PCI ids for mobile Intel chipsets as such
+    - ahci: Add PCI ids for Intel Bay Trail, Cherry Trail and Apollo Lake AHCI
+    - ahci: Add Intel Cannon Lake PCH-H PCI ID
+    - crypto: hash - introduce crypto_hash_alg_has_setkey()
+    - crypto: cryptd - pass through absence of ->setkey()
+    - crypto: poly1305 - remove ->setkey() method
+    - nsfs: mark dentry with DCACHE_RCUACCESS
+    - media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
+    - vb2: V4L2_BUF_FLAG_DONE is set after DQBUF
+    - media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
+    - media: v4l2-compat-ioctl32.c: fix the indentation
+    - media: v4l2-compat-ioctl32.c: move 'helper' functions to
+      __get/put_v4l2_format32
+    - media: v4l2-compat-ioctl32.c: avoid sizeof(type)
+    - media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
+    - media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
+    - media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
+    - media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
+    - media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
+    - media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
+    - media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
+    - media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
+    - crypto: caam - fix endless loop when DECO acquire fails
+    - arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
+    - KVM: nVMX: Fix races when sending nested PI while dest enters/leaves L2
+    - watchdog: imx2_wdt: restore previous timeout after suspend+resume
+    - media: ts2020: avoid integer overflows on 32 bit machines
+    - media: cxusb, dib0700: ignore XC2028_I2C_FLUSH
+    - kernel/async.c: revert "async: simplify lowest_in_progress()"
+    - HID: quirks: Fix keyboard + touchpad on Toshiba Click Mini not working
+    - Bluetooth: btsdio: Do not bind to non-removable BCM43341
+    - Bluetooth: btusb: Restore QCA Rome suspend/resume fix with a "rewritten"
+      version
+    - signal/openrisc: Fix do_unaligned_access to send the proper signal
+    - signal/sh: Ensure si_signo is initialized in do_divide_error
+    - alpha: fix crash if pthread_create races with signal delivery
+    - alpha: fix reboot on Avanti platform
+    - xtensa: fix futex_atomic_cmpxchg_inatomic
+    - EDAC, octeon: Fix an uninitialized variable warning
+    - pktcdvd: Fix pkt_setup_dev() error path
+    - btrfs: Handle btrfs_set_extent_delalloc failure in fixup worker
+    - ACPI: sbshc: remove raw pointer from printk() message
+    - ovl: fix failure to fsync lower dir
+    - mn10300/misalignment: Use SIGSEGV SEGV_MAPERR to report a failed user copy
+    - ftrace: Remove incorrect setting of glob search field
+    - Linux 4.4.116
+
+  * Xenial update to 4.4.116 stable release (LP: #1756121) // CVE-2017-5754
+    - Revert "UBUNTU: SAUCE: UBUNTU: [Config] Disable CONFIG_PPC_DEBUG_RFI"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fix some RFI conversions in the KVM code"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fix the 32-bit KVM build"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fallback flush add load dependency"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Use rfi-flush in printks"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Add no_rfi_flush and nopti comandline
+      options"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Refactor the macros so the nops are
+      defined once"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fix HRFI_TO_UNKNOWN"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Fix the fallback flush to actually
+      activate"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Rework pseries logic to be more cautious"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Rework powernv logic to be more cautious"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Add barriers to the fallback L1D flushing"
+    - Revert "UBUNTU: SAUCE: Fix compilation errors for arch/powerpc/lib/feature-
+      fixups.c"
+    - Revert "UBUNTU: SAUCE: Remove setup.h include file otherwise compilation
+      complains about missing header file."
+    - Revert "UBUNTU: SAUCE: powerpc/asm: Allow including ppc_asm.h in asm files"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Add speculation barrier before ori 30,30,0
+      flush"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Allow HV to advertise multiple flush
+      types"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Support more than one flush type at once"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Expand the RFI section to two nop slots"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Push the instruction selection down to the
+      patching routine"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Make l1d_flush_type bit flags"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Implement congruence-first fallback flush"
+    - Revert "UBUNTU: SAUCE: KVM: Revert the implementation of
+      H_GET_CPU_CHARACTERISTICS"
+    - Revert "UBUNTU: SAUCE: rfi-flush: kvmppc_skip_(H)interrupt returns to host"
+    - Revert "UBUNTU: SAUCE: Fixup rfid in kvmppc_skip_Hinterrupt should be hrfid"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Add HRFI_TO_UNKNOWN and use it in denorm"
+    - Revert "UBUNTU: SAUCE: rfi-flush: Make DEBUG_RFI a CONFIG option"
+    - Revert "UBUNTU: SAUCE: powerpc: Secure memory rfi flush"
+    - powerpc/pseries: Add H_GET_CPU_CHARACTERISTICS flags & wrapper
+    - powerpc/64: Add macros for annotating the destination of rfid/hrfid
+    - powerpc/64s: Simple RFI macro conversions
+    - powerpc/64: Convert fast_exception_return to use RFI_TO_USER/KERNEL
+    - powerpc/64: Convert the syscall exit path to use RFI_TO_USER/KERNEL
+    - powerpc/64s: Convert slb_miss_common to use RFI_TO_USER/KERNEL
+    - powerpc/64s: Add support for RFI flush of L1-D cache
+    - powerpc/64s: Support disabling RFI flush with no_rfi_flush and nopti
+    - powerpc/pseries: Query hypervisor for RFI flush settings
+    - powerpc/powernv: Check device-tree for RFI flush settings
+    - powerpc/64s: Wire up cpu_show_meltdown()
+    - powerpc/64s: Allow control of RFI flush via debugfs
+
+  * Intel i40e PF reset due to incorrect MDD detection (continues...)
+    (LP: #1723127)
+    - i40e/i40evf: Account for frags split over multiple descriptors in check
+      linearize
+    - i40e/i40evf: Allow up to 12K bytes of data per Tx descriptor instead of 8K
+
+  * Xenial update to 4.4.115 stable release (LP: #1755509)
+    - x86: bpf_jit: small optimization in emit_bpf_tail_call()
+    - bpf: fix bpf_tail_call() x64 JIT
+    - [Config] CONFIG_BPF_JIT_ALWAYS_ON=y
+    - bpf: introduce BPF_JIT_ALWAYS_ON config
+    - bpf: arsh is not supported in 32 bit alu thus reject it
+    - bpf: avoid false sharing of map refcount with max_entries
+    - bpf: fix divides by zero
+    - bpf: fix 32-bit divide by zero
+    - bpf: reject stores into ctx via st and xadd
+    - x86/pti: Make unpoison of pgd for trusted boot work for real
+    - kaiser: fix intel_bts perf crashes
+    - ALSA: seq: Make ioctls race-free
+    - crypto: aesni - handle zero length dst buffer
+    - crypto: af_alg - whitelist mask and type
+    - power: reset: zx-reboot: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - gpio: iop: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - gpio: ath79: add missing MODULE_DESCRIPTION/LICENSE
+    - mtd: nand: denali_pci: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - igb: Free IRQs when device is hotplugged
+    - KVM: x86: emulator: Return to user-mode on L1 CPL=0 emulation failure
+    - KVM: x86: Don't re-execute instruction when not passing CR2 value
+    - KVM: X86: Fix operand/address-size during instruction decoding
+    - KVM: x86: ioapic: Fix level-triggered EOI and IOAPIC reconfigure race
+    - KVM: x86: ioapic: Clear Remote IRR when entry is switched to edge-triggered
+    - KVM: x86: ioapic: Preserve read-only values in the redirection table
+    - ACPI / bus: Leave modalias empty for devices which are not present
+    - cpufreq: Add Loongson machine dependencies
+    - bcache: check return value of register_shrinker
+    - drm/amdgpu: Fix SDMA load/unload sequence on HWS disabled mode
+    - drm/amdkfd: Fix SDMA ring buffer size calculation
+    - drm/amdkfd: Fix SDMA oversubsription handling
+    - openvswitch: fix the incorrect flow action alloc size
+    - mac80211: fix the update of path metric for RANN frame
+    - btrfs: fix deadlock when writing out space cache
+    - KVM: VMX: Fix rflags cache during vCPU reset
+    - xen-netfront: remove warning when unloading module
+    - nfsd: CLOSE SHOULD return the invalid special stateid for NFSv4.x (x>0)
+    - nfsd: Ensure we check stateid validity in the seqid operation checks
+    - grace: replace BUG_ON by WARN_ONCE in exit_net hook
+    - nfsd: check for use of the closed special stateid
+    - lockd: fix "list_add double add" caused by legacy signal interface
+    - hwmon: (pmbus) Use 64bit math for DIRECT format values
+    - powerpc/ppc64el -- Remove ll_temac module from 64-bit builds
+    - net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit
+    - quota: Check for register_shrinker() failure.
+    - SUNRPC: Allow connect to return EHOSTUNREACH
+    - kmemleak: add scheduling point to kmemleak_scan()
+    - drm/omap: Fix error handling path in 'omap_dmm_probe()'
+    - xfs: ubsan fixes
+    - scsi: aacraid: Prevent crash in case of free interrupt during scsi EH path
+    - scsi: ufs: ufshcd: fix potential NULL pointer dereference in
+      ufshcd_config_vreg
+    - media: usbtv: add a new usbid
+    - usb: gadget: don't dereference g until after it has been null checked
+    - staging: rtl8188eu: Fix incorrect response to SIOCGIWESSID
+    - usb: option: Add support for FS040U modem
+    - USB: serial: pl2303: new device id for Chilitag
+    - USB: cdc-acm: Do not log urb submission errors on disconnect
+    - CDC-ACM: apply quirk for card reader
+    - USB: serial: io_edgeport: fix possible sleep-in-atomic
+    - usbip: prevent bind loops on devices attached to vhci_hcd
+    - usbip: list: don't list devices attached to vhci_hcd
+    - USB: serial: simple: add Motorola Tetra driver
+    - usb: f_fs: Prevent gadget unbind if it is already unbound
+    - usb: uas: unconditionally bring back host after reset
+    - selinux: general protection fault in sock_has_perm
+    - serial: imx: Only wakeup via RTSDEN bit if the system has RTS/CTS
+    - spi: imx: do not access registers while clocks disabled
+    - Linux 4.4.115
+
+  * retpoline: ignore %cs:0xNNN constant indirections (LP: #1752655)
+    - [Packaging] retpoline -- elide %cs:0xNNNN constants on i386
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 05 Apr 2018 15:03:15 +0200
+
+linux (4.4.0-119.143) xenial; urgency=medium
+
+  * linux: 4.4.0-119.143 -proposed tracker (LP: #1760327)
+
+  * Dell XPS 13 9360 bluetooth scan can not detect any device (LP: #1759821)
+    - Revert "Bluetooth: btusb: fix QCA Rome suspend/resume"
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sat, 31 Mar 2018 17:09:19 +0000
+
+linux (4.4.0-118.142) xenial; urgency=medium
+
+  * linux: 4.4.0-118.142 -proposed tracker (LP: #1759607)
+
+  * Kernel panic with AWS 4.4.0-1053 / 4.4.0-1015 (Trusty) (LP: #1758869)
+    - x86/microcode/AMD: Do not load when running on a hypervisor
+
+  * CVE-2018-8043
+    - net: phy: mdio-bcm-unimac: fix potential NULL dereference in
+      unimac_mdio_probe()
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 28 Mar 2018 14:15:10 -0400
+
+linux (4.4.0-117.141) xenial; urgency=medium
+
+  * linux: 4.4.0-117.141 -proposed tracker (LP: #1755208)
+
+  * Xenial update to 4.4.114 stable release (LP: #1754592)
+    - x86/asm/32: Make sync_core() handle missing CPUID on all 32-bit kernels
+    - usbip: prevent vhci_hcd driver from leaking a socket pointer address
+    - usbip: Fix implicit fallthrough warning
+    - usbip: Fix potential format overflow in userspace tools
+    - x86/microcode/intel: Fix BDW late-loading revision check
+    - x86/retpoline: Fill RSB on context switch for affected CPUs
+    - sched/deadline: Use the revised wakeup rule for suspending constrained dl
+      tasks
+    - can: af_can: can_rcv(): replace WARN_ONCE by pr_warn_once
+    - can: af_can: canfd_rcv(): replace WARN_ONCE by pr_warn_once
+    - PM / sleep: declare __tracedata symbols as char[] rather than char
+    - time: Avoid undefined behaviour in ktime_add_safe()
+    - timers: Plug locking race vs. timer migration
+    - Prevent timer value 0 for MWAITX
+    - drivers: base: cacheinfo: fix x86 with CONFIG_OF enabled
+    - drivers: base: cacheinfo: fix boot error message when acpi is enabled
+    - PCI: layerscape: Add "fsl,ls2085a-pcie" compatible ID
+    - PCI: layerscape: Fix MSG TLP drop setting
+    - mmc: sdhci-of-esdhc: add/remove some quirks according to vendor version
+    - fs/select: add vmalloc fallback for select(2)
+    - hwpoison, memcg: forcibly uncharge LRU pages
+    - cma: fix calculation of aligned offset
+    - mm, page_alloc: fix potential false positive in __zone_watermark_ok
+    - ipc: msg, make msgrcv work with LONG_MIN
+    - x86/ioapic: Fix incorrect pointers in ioapic_setup_resources()
+    - ACPI / processor: Avoid reserving IO regions too early
+    - ACPI / scan: Prefer devices without _HID/_CID for _ADR matching
+    - ACPICA: Namespace: fix operand cache leak
+    - netfilter: x_tables: speed up jump target validation
+    - netfilter: arp_tables: fix invoking 32bit "iptable -P INPUT ACCEPT" failed
+      in 64bit kernel
+    - netfilter: nf_dup_ipv6: set again FLOWI_FLAG_KNOWN_NH at flowi6_flags
+    - netfilter: nf_ct_expect: remove the redundant slash when policy name is
+      empty
+    - netfilter: nfnetlink_queue: reject verdict request from different portid
+    - netfilter: restart search if moved to other chain
+    - netfilter: nf_conntrack_sip: extend request line validation
+    - netfilter: use fwmark_reflect in nf_send_reset
+    - ext2: Don't clear SGID when inheriting ACLs
+    - reiserfs: fix race in prealloc discard
+    - reiserfs: don't preallocate blocks for extended attributes
+    - reiserfs: Don't clear SGID when inheriting ACLs
+    - fs/fcntl: f_setown, avoid undefined behaviour
+    - scsi: libiscsi: fix shifting of DID_REQUEUE host byte
+    - Input: trackpoint - force 3 buttons if 0 button is reported
+    - usb: usbip: Fix possible deadlocks reported by lockdep
+    - usbip: fix stub_rx: get_pipe() to validate endpoint number
+    - usbip: fix stub_rx: harden CMD_SUBMIT path to handle malicious input
+    - usbip: prevent leaking socket pointer address in messages
+    - um: link vmlinux with -no-pie
+    - vsyscall: Fix permissions for emulate mode with KAISER/PTI
+    - eventpoll.h: add missing epoll event masks
+    - x86/microcode/intel: Extend BDW late-loading further with LLC size check
+    - hrtimer: Reset hrtimer cpu base proper on CPU hotplug
+    - dccp: don't restart ccid2_hc_tx_rto_expire() if sk in closed state
+    - ipv6: Fix getsockopt() for sockets with default IPV6_AUTOFLOWLABEL
+    - ipv6: fix udpv6 sendmsg crash caused by too small MTU
+    - ipv6: ip6_make_skb() needs to clear cork.base.dst
+    - lan78xx: Fix failure in USB Full Speed
+    - net: igmp: fix source address check for IGMPv3 reports
+    - tcp: __tcp_hdrlen() helper
+    - net: qdisc_pkt_len_init() should be more robust
+    - pppoe: take ->needed_headroom of lower device into account on xmit
+    - r8169: fix memory corruption on retrieval of hardware statistics.
+    - sctp: do not allow the v4 socket to bind a v4mapped v6 address
+    - sctp: return error if the asoc has been peeled off in sctp_wait_for_sndbuf
+    - vmxnet3: repair memory leak
+    - net: Allow neigh contructor functions ability to modify the primary_key
+    - ipv4: Make neigh lookup keys for loopback/point-to-point devices be
+      INADDR_ANY
+    - flow_dissector: properly cap thoff field
+    - net: tcp: close sock if net namespace is exiting
+    - nfsd: auth: Fix gid sorting when rootsquash enabled
+    - Linux 4.4.114
+
+  * Xenial update to 4.4.113 stable release (LP: #1754375)
+    - gcov: disable for COMPILE_TEST
+    - scsi: sg: disable SET_FORCE_LOW_DMA
+    - futex: Prevent overflow by strengthen input validation
+    - ALSA: pcm: Remove yet superfluous WARN_ON()
+    - ALSA: hda - Apply headphone noise quirk for another Dell XPS 13 variant
+    - ALSA: hda - Apply the existing quirk to iMac 14,1
+    - af_key: fix buffer overread in verify_address_len()
+    - af_key: fix buffer overread in parse_exthdrs()
+    - scsi: hpsa: fix volume offline state
+    - sched/deadline: Zero out positive runtime after throttling constrained tasks
+    - pipe: avoid round_pipe_size() nr_pages overflow on 32-bit
+    - x86/apic/vector: Fix off by one in error path
+    - Input: 88pm860x-ts - fix child-node lookup
+    - Input: twl6040-vibra - fix DT node memory management
+    - Input: twl6040-vibra - fix child-node lookup
+    - Input: twl4030-vibra - fix sibling-node lookup
+    - tracing: Fix converting enum's from the map in trace_event_eval_update()
+    - phy: work around 'phys' references to usb-nop-xceiv devices
+    - ARM: dts: kirkwood: fix pin-muxing of MPP7 on OpenBlocks A7
+    - can: peak: fix potential bug in packet fragmentation
+    - dm btree: fix serious bug in btree_split_beneath()
+    - dm thin metadata: THIN_MAX_CONCURRENT_LOCKS should be 6
+    - arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
+    - kbuild: modversions for EXPORT_SYMBOL() for asm
+    - x86/pti: Document fix wrong index
+    - MIPS: AR7: ensure the port type's FCR value is used
+    - Linux 4.4.113
+
+  * Xenial update to 4.4.113 stable release (LP: #1754375) // CVE-2017-5753
+    (Spectre v1 Intel -> upstream)
+    - Revert "x86/cpu/AMD: Make the LFENCE instruction serialized"
+    - x86/cpu/AMD: Make LFENCE a serializing instruction
+    - x86/cpu/AMD: Use LFENCE_RDTSC in preference to MFENCE_RDTSC
+
+  * i2c-thunderx: erroneous error message "unhandled state: 0" (LP: #1754076)
+    - i2c: octeon: Prevent error message on bus error
+
+  * qeth: fix calculation of required buffer elements for skb (LP: #1750810)
+    - s390/qeth: fix underestimated count of buffer elements
+
+  * Support rfkill-any led trigger for Fujitsu u727 (LP: #1745130)
+    - rfkill: Add rfkill-any LED trigger
+
+  * Redpine: Sometimes Wi-Fi connection shows "unavailable" after resume from
+    WoWLAN S4. WLAN can be recover after reboot or reloading WIFI driver.
+    (LP: #1753438) // Redpine: BLE scanning for nearby beacons per second is too
+    low and result high loss rate. (LP: #1753439)
+    - SAUCE: Redpine: resolve race while resuming from S4
+    - SAUCE: Redpine: Fix card write failure issue at S4 restore
+    - SAUCE: Redpine: Add deep sleep enable before connection
+    - SAUCE: Redpine: resolve power save issue after S4 resume
+
+  * qeth: check not more than 16 SBALEs on the completion queue (LP: #1750568)
+    - qeth: check not more than 16 SBALEs on the completion queue
+
+  * qeth: fix L3 next-hop im xmit qeth hdr (LP: #1750813)
+    - s390/qeth: fix L3 next-hop in xmit qeth hdr
+
+  * qemu-efi-aarch64 in >= artful can't boot xenial cloud images (LP: #1744754)
+    - irqchip/gic-v3: Refactor gic_of_init() for GICv3 driver
+    - irqchip/gic-v3: Add ACPI support for GICv3/4 initialization
+    - irqchip/gic-v3: ACPI: Add redistributor support via GICC structures
+    - irqchip/gic-v3: Remove gic_root_node variable from the ITS code
+    - irqchip/gic-v3-its: Mark its_init() and its children as __init
+    - ACPICA: Headers: Add new constants for the DBG2 ACPI table
+    - of/serial: move earlycon early_param handling to serial
+    - ACPI: parse SPCR and enable matching console
+    - [Config] CONFIG_ACPI_SPCR_TABLE=y
+    - ARM64: ACPI: enable ACPI_SPCR_TABLE
+    - serial: pl011: add console matching function
+
+  * OOM and High CPU utilization in update_blocked_averages because of too many
+    cfs_rqs in rq->leaf_cfs_rq_list (LP: #1747896)
+    - sched/fair: Fix O(nr_cgroups) in load balance path
+
+  * linux-tools: perf incorrectly linking libbfd (LP: #1748922)
+    - SAUCE: tools -- add ability to disable libbfd
+    - [Packaging] correct disablement of libbfd
+
+  * retpoline abi files are empty on i386 (LP: #1751021)
+    - [Packaging] retpoline-extract -- instantiate retpoline files for i386
+    - [Packaging] final-checks -- sanity checking ABI contents
+    - [Packaging] final-checks -- check for empty retpoline files
+
+  * bnx2x_attn_int_deasserted3:4323 MC assert! (LP: #1715519) //
+    CVE-2018-1000026
+    - net: create skb_gso_validate_mac_len()
+    - bnx2x: disable GSO where gso_size is too big for hardware
+
+  * CVE-2017-17448
+    - netfilter: nfnetlink_cthelper: Add missing permission checks
+
+  * TB16 dock ethernet corrupts data with hw checksum silently failing
+    (LP: #1729674)
+    - r8152: disable RX aggregation on Dell TB16 dock
+
+  * linux < 4.8: x-netns vti is broken (LP: #1744078)
+    - net: l3mdev: Add master device lookup by index
+    - xfrm: Only add l3mdev oif to dst lookups
+
+  * Xenial update to 4.4.112 stable release (LP: #1745266)
+    - dm bufio: fix shrinker scans when (nr_to_scan < retain_target)
+    - can: gs_usb: fix return value of the "set_bittiming" callback
+    - IB/srpt: Disable RDMA access by the initiator
+    - MIPS: Validate PR_SET_FP_MODE prctl(2) requests against the ABI of the task
+    - MIPS: Factor out NT_PRFPREG regset access helpers
+    - MIPS: Guard against any partial write attempt with PTRACE_SETREGSET
+    - MIPS: Consistently handle buffer counter with PTRACE_SETREGSET
+    - MIPS: Fix an FCSR access API regression with NT_PRFPREG and MSA
+    - MIPS: Also verify sizeof `elf_fpreg_t' with PTRACE_SETREGSET
+    - MIPS: Disallow outsized PTRACE_SETREGSET NT_PRFPREG regset accesses
+    - net/mac80211/debugfs.c: prevent build failure with CONFIG_UBSAN=y
+    - x86/vsdo: Fix build on PARAVIRT_CLOCK=y, KVM_GUEST=n
+    - x86/acpi: Handle SCI interrupts above legacy space gracefully
+    - iommu/arm-smmu-v3: Don't free page table ops twice
+    - ALSA: pcm: Remove incorrect snd_BUG_ON() usages
+    - ALSA: pcm: Add missing error checks in OSS emulation plugin builder
+    - ALSA: pcm: Abort properly at pending signal in OSS read/write loops
+    - ALSA: pcm: Allow aborting mutex lock at OSS read/write loops
+    - ALSA: aloop: Release cable upon open error path
+    - ALSA: aloop: Fix inconsistent format due to incomplete rule
+    - ALSA: aloop: Fix racy hw constraints adjustment
+    - x86/acpi: Reduce code duplication in mp_override_legacy_irq()
+    - mm/compaction: fix invalid free_pfn and compact_cached_free_pfn
+    - mm/compaction: pass only pageblock aligned range to pageblock_pfn_to_page
+    - mm/page-writeback: fix dirty_ratelimit calculation
+    - mm/zswap: use workqueue to destroy pool
+    - zswap: don't param_set_charp while holding spinlock
+    - locks: don't check for race with close when setting OFD lock
+    - futex: Replace barrier() in unqueue_me() with READ_ONCE()
+    - locking/mutex: Allow next waiter lockless wakeup
+    - usbvision fix overflow of interfaces array
+    - usb: musb: ux500: Fix NULL pointer dereference at system PM
+    - r8152: fix the wake event
+    - r8152: use test_and_clear_bit
+    - r8152: adjust ALDPS function
+    - lan78xx: use skb_cow_head() to deal with cloned skbs
+    - sr9700: use skb_cow_head() to deal with cloned skbs
+    - smsc75xx: use skb_cow_head() to deal with cloned skbs
+    - cx82310_eth: use skb_cow_head() to deal with cloned skbs
+    - x86/mm/pat, /dev/mem: Remove superfluous error message
+    - hwrng: core - sleep interruptible in read
+    - sysrq: Fix warning in sysrq generated crash.
+    - xhci: Fix ring leak in failure path of xhci_alloc_virt_device()
+    - Revert "userfaultfd: selftest: vm: allow to build in vm/ directory"
+    - x86/pti/efi: broken conversion from efi to kernel page table
+    - 8021q: fix a memory leak for VLAN 0 device
+    - ip6_tunnel: disable dst caching if tunnel is dual-stack
+    - net: core: fix module type in sock_diag_bind
+    - RDS: Heap OOB write in rds_message_alloc_sgs()
+    - sh_eth: fix TSU resource handling
+    - sh_eth: fix SH7757 GEther initialization
+    - net: stmmac: enable EEE in MII, GMII or RGMII only
+    - ipv6: fix possible mem leaks in ipv6_make_skb()
+    - crypto: algapi - fix NULL dereference in crypto_remove_spawns()
+    - rbd: set max_segments to USHRT_MAX
+    - x86/microcode/intel: Extend BDW late-loading with a revision check
+    - KVM: x86: Add memory barrier on vmcs field lookup
+    - drm/vmwgfx: Potential off by one in vmw_view_add()
+    - kaiser: Set _PAGE_NX only if supported
+    - bpf: don't (ab)use instructions to store state
+    - bpf: move fixup_bpf_calls() function
+    - bpf: refactor fixup_bpf_calls()
+    - bpf: adjust insn_aux_data when patching insns
+    - bpf: prevent out-of-bounds speculation
+    - bpf, array: fix overflow in max_entries and undefined behavior in index_mask
+    - iscsi-target: Make TASK_REASSIGN use proper se_cmd->cmd_kref
+    - target: Avoid early CMD_T_PRE_EXECUTE failures during ABORT_TASK
+    - USB: serial: cp210x: add IDs for LifeScan OneTouch Verio IQ
+    - USB: serial: cp210x: add new device ID ELV ALC 8xxx
+    - usb: misc: usb3503: make sure reset is low for at least 100us
+    - USB: fix usbmon BUG trigger
+    - usbip: remove kernel addresses from usb device and urb debug msgs
+    - staging: android: ashmem: fix a race condition in ASHMEM_SET_SIZE ioctl
+    - Bluetooth: Prevent stack info leak from the EFS element.
+    - uas: ignore UAS for Norelsys NS1068(X) chips
+    - e1000e: Fix e1000_check_for_copper_link_ich8lan return value.
+    - x86/Documentation: Add PTI description
+    - sysfs/cpu: Fix typos in vulnerability documentation
+    - x86/alternatives: Fix optimize_nops() checking
+    - selftests/x86: Add test_vsyscall
+    - Linux 4.4.112
+
+  * Xenial update to 4.4.111 stable release (LP: #1745263)
+    - x86/kasan: Write protect kasan zero shadow
+    - kernel/acct.c: fix the acct->needcheck check in check_free_space()
+    - crypto: n2 - cure use after free
+    - crypto: chacha20poly1305 - validate the digest size
+    - crypto: pcrypt - fix freeing pcrypt instances
+    - sunxi-rsb: Include OF based modalias in device uevent
+    - fscache: Fix the default for fscache_maybe_release_page()
+    - kernel: make groups_sort calling a responsibility group_info allocators
+    - kernel/signal.c: protect the traced SIGNAL_UNKILLABLE tasks from SIGKILL
+    - kernel/signal.c: protect the SIGNAL_UNKILLABLE tasks from !sig_kernel_only()
+      signals
+    - kernel/signal.c: remove the no longer needed SIGNAL_UNKILLABLE check in
+      complete_signal()
+    - ARC: uaccess: dont use "l" gcc inline asm constraint modifier
+    - parisc: Fix alignment of pa_tlb_lock in assembly on 32-bit SMP kernel
+    - genksyms: Handle string literals with spaces in reference files
+    - module: Issue warnings when tainting kernel
+    - proc: much faster /proc/vmstat
+    - Fix build error in vma.c
+    - Linux 4.4.111
+
+  * x86/net/bpf: return statement missing value (LP: #1745364)
+    - SAUCE: (no-up) arch/x86/bpf: Fix missed return statement
+
+  * Ubuntu 16.04 - s390/cpuinfo: show facilities as reported by stfle
+    (LP: #1744736)
+    - s390/bitops: add for_each_set_bit_inv helper
+    - s390/cpuinfo: show facilities as reported by stfle
+
+  * Xenial update to 4.4.110 stable release (LP: #1745071)
+    - KPTI: Rename to PAGE_TABLE_ISOLATION
+    - SAUCE: Replace CONFIG_KAISER with CONFIG_PAGE_TABLE_ISOLATION
+    - Linux 4.4.110
+
+  * Xenial update to 4.4.109 stable release (LP: #1745069)
+    - ACPI: APEI / ERST: Fix missing error handling in erst_reader()
+    - crypto: mcryptd - protect the per-CPU queue with a lock
+    - mfd: cros ec: spi: Don't send first message too soon
+    - mfd: twl4030-audio: Fix sibling-node lookup
+    - mfd: twl6040: Fix child-node lookup
+    - ALSA: rawmidi: Avoid racy info ioctl via ctl device
+    - ALSA: usb-audio: Fix the missing ctl name suffix at parsing SU
+    - PCI / PM: Force devices to D0 in pci_pm_thaw_noirq()
+    - parisc: Hide Diva-built-in serial aux and graphics card
+    - spi: xilinx: Detect stall with Unknown commands
+    - KVM: X86: Fix load RFLAGS w/o the fixed bit
+    - powerpc/perf: Dereference BHRB entries safely
+    - net: mvneta: clear interface link status on port disable
+    - tracing: Remove extra zeroing out of the ring buffer page
+    - tracing: Fix possible double free on failure of allocating trace buffer
+    - tracing: Fix crash when it fails to alloc ring buffer
+    - ring-buffer: Mask out the info bits when returning buffer page length
+    - iw_cxgb4: Only validate the MSN for successful completions
+    - ASoC: fsl_ssi: AC'97 ops need regmap, clock and cleaning up on failure
+    - ASoC: twl4030: fix child-node lookup
+    - ALSA: hda: Drop useless WARN_ON()
+    - ALSA: hda - fix headset mic detection issue on a Dell machine
+    - x86/vm86/32: Switch to flush_tlb_mm_range() in mark_screen_rdonly()
+    - x86/mm: Remove flush_tlb() and flush_tlb_current_task()
+    - x86/mm: Make flush_tlb_mm_range() more predictable
+    - x86/mm: Reimplement flush_tlb_page() using flush_tlb_mm_range()
+    - x86/mm: Remove the UP asm/tlbflush.h code, always use the (formerly) SMP
+      code
+    - x86/mm: Add the 'nopcid' boot option to turn off PCID
+    - x86/mm/64: Fix reboot interaction with CR4.PCIDE
+    - kbuild: add '-fno-stack-check' to kernel build options
+    - ipv4: igmp: guard against silly MTU values
+    - ipv6: mcast: better catch silly mtu values
+    - net: igmp: Use correct source address on IGMPv3 reports
+    - netlink: Add netns check on taps
+    - net: qmi_wwan: add Sierra EM7565 1199:9091
+    - net: reevalulate autoflowlabel setting after sysctl setting
+    - tcp md5sig: Use skb's saddr when replying to an incoming segment
+    - tg3: Fix rx hang on MTU change with 5717/5719
+    - net: mvmdio: disable/unprepare clocks in EPROBE_DEFER case
+    - sctp: Replace use of sockets_allocated with specified macro.
+    - ipv4: Fix use-after-free when flushing FIB tables
+    - net: bridge: fix early call to br_stp_change_bridge_id and plug newlink
+      leaks
+    - net: phy: micrel: ksz9031: reconfigure autoneg after phy autoneg workaround
+    - sock: free skb in skb_complete_tx_timestamp on error
+    - usbip: fix usbip bind writing random string after command in match_busid
+    - usbip: stub: stop printing kernel pointer addresses in messages
+    - usbip: vhci: stop printing kernel pointer addresses in messages
+    - USB: serial: ftdi_sio: add id for Airbus DS P8GR
+    - USB: serial: qcserial: add Sierra Wireless EM7565
+    - USB: serial: option: add support for Telit ME910 PID 0x1101
+    - USB: serial: option: adding support for YUGA CLM920-NC5
+    - usb: Add device quirk for Logitech HD Pro Webcam C925e
+    - usb: add RESET_RESUME for ELSA MicroLink 56K
+    - USB: Fix off by one in type-specific length check of BOS SSP capability
+    - usb: xhci: Add XHCI_TRUST_TX_LENGTH for Renesas uPD720201
+    - nohz: Prevent a timer interrupt storm in tick_nohz_stop_sched_tick()
+    - x86/smpboot: Remove stale TLB flush invocations
+    - n_tty: fix EXTPROC vs ICANON interaction with TIOCINQ (aka FIONREAD)
+    - mm/vmstat: Make NR_TLB_REMOTE_FLUSH_RECEIVED available even on UP
+    - Linux 4.4.109
+
+  * Xenial update to 4.4.108 stable release (LP: #1745054)
+    - arm64: Initialise high_memory global variable earlier
+    - cxl: Check if vphb exists before iterating over AFU devices
+    - x86/mm: Fix INVPCID asm constraint
+    - x86/mm: Add a 'noinvpcid' boot option to turn off INVPCID
+    - mm/rmap: batched invalidations should use existing api
+    - mm/mmu_context, sched/core: Fix mmu_context.h assumption
+    - sched/core: Add switch_mm_irqs_off() and use it in the scheduler
+    - x86/mm, sched/core: Turn off IRQs in switch_mm()
+    - ARM: Hide finish_arch_post_lock_switch() from modules
+    - sched/core: Idle_task_exit() shouldn't use switch_mm_irqs_off()
+    - x86/irq: Do not substract irq_tlb_count from irq_call_count
+    - ALSA: hda - add support for docking station for HP 820 G2
+    - ALSA: hda - add support for docking station for HP 840 G3
+    - arm: kprobes: Fix the return address of multiple kretprobes
+    - arm: kprobes: Align stack to 8-bytes in test code
+    - cpuidle: Validate cpu_dev in cpuidle_add_sysfs()
+    - crypto: deadlock between crypto_alg_sem/rtnl_mutex/genl_mutex
+    - sch_dsmark: fix invalid skb_cow() usage
+    - bna: integer overflow bug in debugfs
+    - net: qmi_wwan: Add USB IDs for MDM6600 modem on Motorola Droid 4
+    - usb: gadget: f_uvc: Sanity check wMaxPacketSize for SuperSpeed
+    - usb: gadget: udc: remove pointer dereference after free
+    - netfilter: nfnl_cthelper: fix runtime expectation policy updates
+    - netfilter: nfnl_cthelper: Fix memory leak
+    - inet: frag: release spinlock before calling icmp_send()
+    - pinctrl: st: add irq_request/release_resources callbacks
+    - scsi: lpfc: Fix PT2PT PRLI reject
+    - KVM: x86: correct async page present tracepoint
+    - KVM: VMX: Fix enable VPID conditions
+    - ARM: dts: ti: fix PCI bus dtc warnings
+    - hwmon: (asus_atk0110) fix uninitialized data access
+    - HID: xinmo: fix for out of range for THT 2P arcade controller.
+    - r8152: prevent the driver from transmitting packets with carrier off
+    - s390/qeth: no ETH header for outbound AF_IUCV
+    - bna: avoid writing uninitialized data into hw registers
+    - net: Do not allow negative values for busy_read and busy_poll sysctl
+      interfaces
+    - i40e: Do not enable NAPI on q_vectors that have no rings
+    - RDMA/iser: Fix possible mr leak on device removal event
+    - irda: vlsi_ir: fix check for DMA mapping errors
+    - netfilter: nfnl_cthelper: fix a race when walk the nf_ct_helper_hash table
+    - netfilter: nf_nat_snmp: Fix panic when snmp_trap_helper fails to register
+    - ARM: dts: am335x-evmsk: adjust mmc2 param to allow suspend
+    - KVM: pci-assign: do not map smm memory slot pages in vt-d page tables
+    - isdn: kcapi: avoid uninitialized data
+    - xhci: plat: Register shutdown for xhci_plat
+    - netfilter: nfnetlink_queue: fix secctx memory leak
+    - ARM: dma-mapping: disallow dma_get_sgtable() for non-kernel managed memory
+    - cpuidle: powernv: Pass correct drv->cpumask for registration
+    - bnxt_en: Fix NULL pointer dereference in reopen failure path
+    - backlight: pwm_bl: Fix overflow condition
+    - crypto: crypto4xx - increase context and scatter ring buffer elements
+    - rtc: pl031: make interrupt optional
+    - net: phy: at803x: Change error to EINVAL for invalid MAC
+    - PCI: Avoid bus reset if bridge itself is broken
+    - scsi: cxgb4i: fix Tx skb leak
+    - scsi: mpt3sas: Fix IO error occurs on pulling out a drive from RAID1 volume
+      created on two SATA drive
+    - PCI: Create SR-IOV virtfn/physfn links before attaching driver
+    - igb: check memory allocation failure
+    - ixgbe: fix use of uninitialized padding
+    - PCI/AER: Report non-fatal errors only to the affected endpoint
+    - scsi: lpfc: Fix secure firmware updates
+    - scsi: lpfc: PLOGI failures during NPIV testing
+    - fm10k: ensure we process SM mbx when processing VF mbx
+    - tcp: fix under-evaluated ssthresh in TCP Vegas
+    - rtc: set the alarm to the next expiring timer
+    - cpuidle: fix broadcast control when broadcast can not be entered
+    - thermal: hisilicon: Handle return value of clk_prepare_enable
+    - MIPS: math-emu: Fix final emulation phase for certain instructions
+    - Revert "Bluetooth: btusb: driver to enable the usb-wakeup feature"
+    - ALSA: hda - Clear the leftover component assignment at snd_hdac_i915_exit()
+    - ALSA: hda - Degrade i915 binding failure message
+    - ALSA: hda - Fix yet another i915 pointer leftover in error path
+    - alpha: fix build failures
+    - Linux 4.4.108
+
+  * Xenial update to 4.4.107 stable release (LP: #1745052)
+    - crypto: hmac - require that the underlying hash algorithm is unkeyed
+    - crypto: salsa20 - fix blkcipher_walk API usage
+    - autofs: fix careless error in recent commit
+    - tracing: Allocate mask_str buffer dynamically
+    - USB: uas and storage: Add US_FL_BROKEN_FUA for another JMicron JMS567 ID
+    - USB: core: prevent malicious bNumInterfaces overflow
+    - usbip: fix stub_send_ret_submit() vulnerability to null transfer_buffer
+    - ceph: drop negative child dentries before try pruning inode's alias
+    - Bluetooth: btusb: driver to enable the usb-wakeup feature
+    - xhci: Don't add a virt_dev to the devs array before it's fully allocated
+    - sched/rt: Do not pull from current CPU if only one CPU to pull
+    - dmaengine: dmatest: move callback wait queue to thread context
+    - ext4: fix fdatasync(2) after fallocate(2) operation
+    - ext4: fix crash when a directory's i_size is too small
+    - KEYS: add missing permission check for request_key() destination
+    - mac80211: Fix addition of mesh configuration element
+    - usb: phy: isp1301: Add OF device ID table
+    - md-cluster: free md_cluster_info if node leave cluster
+    - userfaultfd: shmem: __do_fault requires VM_FAULT_NOPAGE
+    - userfaultfd: selftest: vm: allow to build in vm/ directory
+    - net: initialize msg.msg_flags in recvfrom
+    - net: bcmgenet: correct the RBUF_OVFL_CNT and RBUF_ERR_CNT MIB values
+    - net: bcmgenet: correct MIB access of UniMAC RUNT counters
+    - net: bcmgenet: reserved phy revisions must be checked first
+    - net: bcmgenet: power down internal phy if open or resume fails
+    - net: bcmgenet: Power up the internal PHY before probing the MII
+    - NFSD: fix nfsd_minorversion(.., NFSD_AVAIL)
+    - NFSD: fix nfsd_reset_versions for NFSv4.
+    - Input: i8042 - add TUXEDO BU1406 (N24_25BU) to the nomux list
+    - drm/omap: fix dmabuf mmap for dma_alloc'ed buffers
+    - netfilter: bridge: honor frag_max_size when refragmenting
+    - writeback: fix memory leak in wb_queue_work()
+    - net: wimax/i2400m: fix NULL-deref at probe
+    - dmaengine: Fix array index out of bounds warning in __get_unmap_pool()
+    - net: Resend IGMP memberships upon peer notification.
+    - mlxsw: reg: Fix SPVM max record count
+    - mlxsw: reg: Fix SPVMLR max record count
+    - intel_th: pci: Add Gemini Lake support
+    - openrisc: fix issue handling 8 byte get_user calls
+    - scsi: hpsa: update check for logical volume status
+    - scsi: hpsa: limit outstanding rescans
+    - fjes: Fix wrong netdevice feature flags
+    - drm/radeon/si: add dpm quirk for Oland
+    - sched/deadline: Make sure the replenishment timer fires in the next period
+    - sched/deadline: Throttle a constrained deadline task activated after the
+      deadline
+    - sched/deadline: Use deadline instead of period when calculating overflow
+    - mmc: mediatek: Fixed bug where clock frequency could be set wrong
+    - drm/radeon: reinstate oland workaround for sclk
+    - afs: Fix missing put_page()
+    - afs: Populate group ID from vnode status
+    - afs: Adjust mode bits processing
+    - afs: Flush outstanding writes when an fd is closed
+    - afs: Migrate vlocation fields to 64-bit
+    - afs: Prevent callback expiry timer overflow
+    - afs: Fix the maths in afs_fs_store_data()
+    - afs: Populate and use client modification time
+    - afs: Fix page leak in afs_write_begin()
+    - afs: Fix afs_kill_pages()
+    - perf symbols: Fix symbols__fixup_end heuristic for corner cases
+    - efi/esrt: Cleanup bad memory map log messages
+    - NFSv4.1 respect server's max size in CREATE_SESSION
+    - btrfs: add missing memset while reading compressed inline extents
+    - target: Use system workqueue for ALUA transitions
+    - target: fix ALUA transition timeout handling
+    - target: fix race during implicit transition work flushes
+    - sfc: don't warn on successful change of MAC
+    - fbdev: controlfb: Add missing modes to fix out of bounds access
+    - video: udlfb: Fix read EDID timeout
+    - video: fbdev: au1200fb: Release some resources if a memory allocation fails
+    - video: fbdev: au1200fb: Return an error code if a memory allocation fails
+    - rtc: pcf8563: fix output clock rate
+    - dmaengine: ti-dma-crossbar: Correct am335x/am43xx mux value type
+    - PCI/PME: Handle invalid data when reading Root Status
+    - powerpc/powernv/cpufreq: Fix the frequency read by /proc/cpuinfo
+    - netfilter: ipvs: Fix inappropriate output of procfs
+    - powerpc/opal: Fix EBUSY bug in acquiring tokens
+    - powerpc/ipic: Fix status get and status clear
+    - target/iscsi: Fix a race condition in iscsit_add_reject_from_cmd()
+    - iscsi-target: fix memory leak in lio_target_tiqn_addtpg()
+    - target:fix condition return in core_pr_dump_initiator_port()
+    - target/file: Do not return error for UNMAP if length is zero
+    - arm-ccn: perf: Prevent module unload while PMU is in use
+    - crypto: tcrypt - fix buffer lengths in test_aead_speed()
+    - mm: Handle 0 flags in _calc_vm_trans() macro
+    - clk: mediatek: add the option for determining PLL source clock
+    - clk: imx6: refine hdmi_isfr's parent to make HDMI work on i.MX6 SoCs w/o VPU
+    - clk: tegra: Fix cclk_lp divisor register
+    - ppp: Destroy the mutex when cleanup
+    - thermal/drivers/step_wise: Fix temperature regulation misbehavior
+    - GFS2: Take inode off order_write list when setting jdata flag
+    - bcache: explicitly destroy mutex while exiting
+    - bcache: fix wrong cache_misses statistics
+    - l2tp: cleanup l2tp_tunnel_delete calls
+    - xfs: fix log block underflow during recovery cycle verification
+    - xfs: fix incorrect extent state in xfs_bmap_add_extent_unwritten_real
+    - PCI: Detach driver before procfs & sysfs teardown on device remove
+    - scsi: hpsa: cleanup sas_phy structures in sysfs when unloading
+    - scsi: hpsa: destroy sas transport properties before scsi_host
+    - powerpc/perf/hv-24x7: Fix incorrect comparison in memord
+    - tty fix oops when rmmod 8250
+    - usb: musb: da8xx: fix babble condition handling
+    - pinctrl: adi2: Fix Kconfig build problem
+    - raid5: Set R5_Expanded on parity devices as well as data.
+    - scsi: scsi_devinfo: Add REPORTLUN2 to EMC SYMMETRIX blacklist entry
+    - vt6655: Fix a possible sleep-in-atomic bug in vt6655_suspend
+    - scsi: sd: change manage_start_stop to bool in sysfs interface
+    - scsi: sd: change allow_restart to bool in sysfs interface
+    - scsi: bfa: integer overflow in debugfs
+    - udf: Avoid overflow when session starts at large offset
+    - macvlan: Only deliver one copy of the frame to the macvlan interface
+    - RDMA/cma: Avoid triggering undefined behavior
+    - IB/ipoib: Grab rtnl lock on heavy flush when calling ndo_open/stop
+    - ath9k: fix tx99 potential info leak
+    - Linux 4.4.107
+
+  * Xenial update to 4.4.106 stable release (LP: #1745047)
+    - can: ti_hecc: Fix napi poll return value for repoll
+    - can: kvaser_usb: free buf in error paths
+    - can: kvaser_usb: Fix comparison bug in kvaser_usb_read_bulk_callback()
+    - can: kvaser_usb: ratelimit errors if incomplete messages are received
+    - can: kvaser_usb: cancel urb on -EPIPE and -EPROTO
+    - can: ems_usb: cancel urb on -EPIPE and -EPROTO
+    - can: esd_usb2: cancel urb on -EPIPE and -EPROTO
+    - can: usb_8dev: cancel urb on -EPIPE and -EPROTO
+    - virtio: release virtio index when fail to device_register
+    - hv: kvp: Avoid reading past allocated blocks from KVP file
+    - isa: Prevent NULL dereference in isa_bus driver callbacks
+    - scsi: libsas: align sata_device's rps_resp on a cacheline
+    - efi: Move some sysfs files to be read-only by root
+    - ASN.1: fix out-of-bounds read when parsing indefinite length item
+    - ASN.1: check for error from ASN1_OP_END__ACT actions
+    - X.509: reject invalid BIT STRING for subjectPublicKey
+    - x86/PCI: Make broadcom_postcore_init() check acpi_disabled
+    - ALSA: pcm: prevent UAF in snd_pcm_info
+    - ALSA: seq: Remove spurious WARN_ON() at timer check
+    - ALSA: usb-audio: Fix out-of-bound error
+    - ALSA: usb-audio: Add check return value for usb_string()
+    - iommu/vt-d: Fix scatterlist offset handling
+    - s390: fix compat system call table
+    - kdb: Fix handling of kallsyms_symbol_next() return value
+    - drm: extra printk() wrapper macros
+    - drm/exynos: gem: Drop NONCONTIG flag for buffers allocated without IOMMU
+    - media: dvb: i2c transfers over usb cannot be done from stack
+    - arm64: KVM: fix VTTBR_BADDR_MASK BUG_ON off-by-one
+    - KVM: VMX: remove I/O port 0x80 bypass on Intel hosts
+    - arm64: fpsimd: Prevent registers leaking from dead tasks
+    - ARM: BUG if jumping to usermode address in kernel mode
+    - ARM: avoid faulting on qemu
+    - thp: reduce indentation level in change_huge_pmd()
+    - thp: fix MADV_DONTNEED vs. numa balancing race
+    - mm: drop unused pmdp_huge_get_and_clear_notify()
+    - Revert "drm/armada: Fix compile fail"
+    - Revert "spi: SPI_FSL_DSPI should depend on HAS_DMA"
+    - Revert "s390/kbuild: enable modversions for symbols exported from asm"
+    - vti6: Don't report path MTU below IPV6_MIN_MTU.
+    - ARM: OMAP2+: gpmc-onenand: propagate error on initialization failure
+    - x86/hpet: Prevent might sleep splat on resume
+    - selftest/powerpc: Fix false failures for skipped tests
+    - module: set __jump_table alignment to 8
+    - ARM: OMAP2+: Fix device node reference counts
+    - ARM: OMAP2+: Release device node after it is no longer needed.
+    - gpio: altera: Use handle_level_irq when configured as a level_high
+    - HID: chicony: Add support for another ASUS Zen AiO keyboard
+    - usb: gadget: configs: plug memory leak
+    - USB: gadgetfs: Fix a potential memory leak in 'dev_config()'
+    - kvm: nVMX: VMCLEAR should not cause the vCPU to shut down
+    - libata: drop WARN from protocol error in ata_sff_qc_issue()
+    - workqueue: trigger WARN if queue_delayed_work() is called with NULL @wq
+    - scsi: lpfc: Fix crash during Hardware error recovery on SLI3 adapters
+    - irqchip/crossbar: Fix incorrect type of register size
+    - KVM: nVMX: reset nested_run_pending if the vCPU is going to be reset
+    - arm: KVM: Survive unknown traps from guests
+    - arm64: KVM: Survive unknown traps from guests
+    - spi_ks8995: fix "BUG: key accdaa28 not in .data!"
+    - bnx2x: prevent crash when accessing PTP with interface down
+    - bnx2x: fix possible overrun of VFPF multicast addresses array
+    - bnx2x: do not rollback VF MAC/VLAN filters we did not configure
+    - ipv6: reorder icmpv6_init() and ip6_mr_init()
+    - crypto: s5p-sss - Fix completing crypto request in IRQ handler
+    - i2c: riic: fix restart condition
+    - zram: set physical queue limits to avoid array out of bounds accesses
+    - netfilter: don't track fragmented packets
+    - axonram: Fix gendisk handling
+    - drm/amd/amdgpu: fix console deadlock if late init failed
+    - powerpc/powernv/ioda2: Gracefully fail if too many TCE levels requested
+    - EDAC, i5000, i5400: Fix use of MTR_DRAM_WIDTH macro
+    - EDAC, i5000, i5400: Fix definition of NRECMEMB register
+    - kbuild: pkg: use --transform option to prefix paths in tar
+    - mac80211_hwsim: Fix memory leak in hwsim_new_radio_nl()
+    - route: also update fnhe_genid when updating a route cache
+    - route: update fnhe_expires for redirect when the fnhe exists
+    - lib/genalloc.c: make the avail variable an atomic_long_t
+    - dynamic-debug-howto: fix optional/omitted ending line number to be LARGE
+      instead of 0
+    - NFS: Fix a typo in nfs_rename()
+    - sunrpc: Fix rpc_task_begin trace point
+    - block: wake up all tasks blocked in get_request()
+    - sparc64/mm: set fields in deferred pages
+    - sctp: do not free asoc when it is already dead in sctp_sendmsg
+    - sctp: use the right sk after waking up from wait_buf sleep
+    - atm: horizon: Fix irq release error
+    - jump_label: Invoke jump_label_test() via early_initcall()
+    - xfrm: Copy policy family in clone_policy
+    - IB/mlx4: Increase maximal message size under UD QP
+    - IB/mlx5: Assign send CQ and recv CQ of UMR QP
+    - afs: Connect up the CB.ProbeUuid
+    - ipvlan: fix ipv6 outbound device
+    - audit: ensure that 'audit=1' actually enables audit for PID 1
+    - ipmi: Stop timers before cleaning up the module
+    - s390: always save and restore all registers on context switch
+    - tipc: fix memory leak in tipc_accept_from_sock()
+    - rds: Fix NULL pointer dereference in __rds_rdma_map
+    - sit: update frag_off info
+    - packet: fix crash in fanout_demux_rollover()
+    - net/packet: fix a race in packet_bind() and packet_notifier()
+    - Revert "x86/efi: Build our own page table structures"
+    - Revert "x86/efi: Hoist page table switching code into efi_call_virt()"
+    - Revert "x86/mm/pat: Ensure cpa->pfn only contains page frame numbers"
+    - arm: KVM: Fix VTTBR_BADDR_MASK BUG_ON off-by-one
+    - usb: gadget: ffs: Forbid usb_ep_alloc_request from sleeping
+    - Linux 4.4.106
+
+  * Xenial update to 4.4.105 stable release (LP: #1745046)
+    - bcache: only permit to recovery read error when cache device is clean
+    - bcache: recover data from backing when data is clean
+    - uas: Always apply US_FL_NO_ATA_1X quirk to Seagate devices
+    - usb: quirks: Add no-lpm quirk for KY-688 USB 3.1 Type-C Hub
+    - serial: 8250_pci: Add Amazon PCI serial device ID
+    - s390/runtime instrumentation: simplify task exit handling
+    - USB: serial: option: add Quectel BG96 id
+    - ima: fix hash algorithm initialization
+    - s390/pci: do not require AIS facility
+    - selftests/x86/ldt_get: Add a few additional tests for limits
+    - serial: 8250_fintek: Fix rs485 disablement on invalid ioctl()
+    - spi: sh-msiof: Fix DMA transfer size check
+    - usb: phy: tahvo: fix error handling in tahvo_usb_probe()
+    - serial: 8250: Preserve DLD[7:4] for PORT_XR17V35X
+    - x86/entry: Use SYSCALL_DEFINE() macros for sys_modify_ldt()
+    - EDAC, sb_edac: Fix missing break in switch
+    - sysrq : fix Show Regs call trace on ARM
+    - perf test attr: Fix ignored test case result
+    - kprobes/x86: Disable preemption in ftrace-based jprobes
+    - net: systemport: Utilize skb_put_padto()
+    - net: systemport: Pad packet before inserting TSB
+    - ARM: OMAP1: DMA: Correct the number of logical channels
+    - vti6: fix device register to report IFLA_INFO_KIND
+    - net/appletalk: Fix kernel memory disclosure
+    - ravb: Remove Rx overflow log messages
+    - nfs: Don't take a reference on fl->fl_file for LOCK operation
+    - KVM: arm/arm64: Fix occasional warning from the timer work function
+    - NFSv4: Fix client recovery when server reboots multiple times
+    - drm/exynos/decon5433: set STANDALONE_UPDATE_F on output enablement
+    - net: sctp: fix array overrun read on sctp_timer_tbl
+    - tipc: fix cleanup at module unload
+    - dmaengine: pl330: fix double lock
+    - tcp: correct memory barrier usage in tcp_check_space()
+    - mm: avoid returning VM_FAULT_RETRY from ->page_mkwrite handlers
+    - xen-netfront: Improve error handling during initialization
+    - net: fec: fix multicast filtering hardware setup
+    - Revert "ocfs2: should wait dio before inode lock in ocfs2_setattr()"
+    - usb: hub: Cycle HUB power when initialization fails
+    - usb: xhci: fix panic in xhci_free_virt_devices_depth_first
+    - usb: ch9: Add size macro for SSP dev cap descriptor
+    - USB: core: Add type-specific length check of BOS descriptors
+    - USB: Increase usbfs transfer limit
+    - USB: devio: Prevent integer overflow in proc_do_submiturb()
+    - USB: usbfs: Filter flags passed in from user space
+    - usb: host: fix incorrect updating of offset
+    - xen-netfront: avoid crashing on resume after a failure in talk_to_netback()
+    - Linux 4.4.105
+
+  * Xenial update to 4.4.104 stable release (LP: #1745043)
+    - x86/mm/pat: Ensure cpa->pfn only contains page frame numbers
+    - x86/efi: Hoist page table switching code into efi_call_virt()
+    - x86/efi: Build our own page table structures
+    - ARM: dts: omap3: logicpd-torpedo-37xx-devkit: Fix MMC1 cd-gpio
+    - x86/efi-bgrt: Fix kernel panic when mapping BGRT data
+    - x86/efi-bgrt: Replace early_memremap() with memremap()
+    - mm/madvise.c: fix madvise() infinite loop under special circumstances
+    - btrfs: clear space cache inode generation always
+    - KVM: x86: pvclock: Handle first-time write to pvclock-page contains random
+      junk
+    - KVM: x86: Exit to user-mode on #UD intercept when emulator requires
+    - KVM: x86: inject exceptions produced by x86_decode_insn
+    - mmc: core: Do not leave the block driver in a suspended state
+    - eeprom: at24: check at24_read/write arguments
+    - bcache: Fix building error on MIPS
+    - Revert "drm/radeon: dont switch vt on suspend"
+    - drm/radeon: fix atombios on big endian
+    - drm/panel: simple: Add missing panel_simple_unprepare() calls
+    - mtd: nand: Fix writing mtdoops to nand flash.
+    - NFS: revalidate "." etc correctly on "open".
+    - drm/i915: Don't try indexed reads to alternate slave addresses
+    - drm/i915: Prevent zero length "index" write
+    - nfsd: Make init_open_stateid() a bit more whole
+    - nfsd: Fix stateid races between OPEN and CLOSE
+    - nfsd: Fix another OPEN stateid race
+    - Linux 4.4.104
+
+  * Xenial update to 4.4.103 stable release (LP: #1744873)
+    - s390: fix transactional execution control register handling
+    - s390/runtime instrumention: fix possible memory corruption
+    - s390/disassembler: add missing end marker for e7 table
+    - s390/disassembler: increase show_code buffer size
+    - AF_VSOCK: Shrink the area influenced by prepare_to_wait
+    - vsock: use new wait API for vsock_stream_sendmsg()
+    - sched: Make resched_cpu() unconditional
+    - lib/mpi: call cond_resched() from mpi_powm() loop
+    - x86/decoder: Add new TEST instruction pattern
+    - ARM: 8722/1: mm: make STRICT_KERNEL_RWX effective for LPAE
+    - ARM: 8721/1: mm: dump: check hardware RO bit for LPAE
+    - MIPS: ralink: Fix MT7628 pinmux
+    - MIPS: ralink: Fix typo in mt7628 pinmux function
+    - ALSA: hda: Add Raven PCI ID
+    - dm bufio: fix integer overflow when limiting maximum cache size
+    - dm: fix race between dm_get_from_kobject() and __dm_destroy()
+    - MIPS: Fix an n32 core file generation regset support regression
+    - MIPS: BCM47XX: Fix LED inversion for WRT54GSv1
+    - autofs: don't fail mount for transient error
+    - nilfs2: fix race condition that causes file system corruption
+    - eCryptfs: use after free in ecryptfs_release_messaging()
+    - bcache: check ca->alloc_thread initialized before wake up it
+    - isofs: fix timestamps beyond 2027
+    - NFS: Fix typo in nomigration mount option
+    - nfs: Fix ugly referral attributes
+    - nfsd: deal with revoked delegations appropriately
+    - rtlwifi: rtl8192ee: Fix memory leak when loading firmware
+    - rtlwifi: fix uninitialized rtlhal->last_suspend_sec time
+    - ata: fixes kernel crash while tracing ata_eh_link_autopsy event
+    - ext4: fix interaction between i_size, fallocate, and delalloc after a crash
+    - ALSA: pcm: update tstamp only if audio_tstamp changed
+    - ALSA: usb-audio: Add sanity checks to FE parser
+    - ALSA: usb-audio: Fix potential out-of-bound access at parsing SU
+    - ALSA: usb-audio: Add sanity checks in v2 clock parsers
+    - ALSA: timer: Remove kernel warning at compat ioctl error paths
+    - ALSA: hda/realtek - Fix ALC700 family no sound issue
+    - fix a page leak in vhost_scsi_iov_to_sgl() error recovery
+    - fs/9p: Compare qid.path in v9fs_test_inode
+    - iscsi-target: Fix non-immediate TMR reference leak
+    - target: Fix QUEUE_FULL + SCSI task attribute handling
+    - KVM: nVMX: set IDTR and GDTR limits when loading L1 host state
+    - KVM: SVM: obey guest PAT
+    - SUNRPC: Fix tracepoint storage issues with svc_recv and svc_rqst_status
+    - clk: ti: dra7-atl-clock: Fix of_node reference counting
+    - clk: ti: dra7-atl-clock: fix child-node lookups
+    - libnvdimm, namespace: fix label initialization to use valid seq numbers
+    - libnvdimm, namespace: make 'resource' attribute only readable by root
+    - IB/srpt: Do not accept invalid initiator port names
+    - IB/srp: Avoid that a cable pull can trigger a kernel crash
+    - NFC: fix device-allocation error return
+    - i40e: Use smp_rmb rather than read_barrier_depends
+    - igb: Use smp_rmb rather than read_barrier_depends
+    - igbvf: Use smp_rmb rather than read_barrier_depends
+    - ixgbevf: Use smp_rmb rather than read_barrier_depends
+    - i40evf: Use smp_rmb rather than read_barrier_depends
+    - fm10k: Use smp_rmb rather than read_barrier_depends
+    - ixgbe: Fix skb list corruption on Power systems
+    - parisc: Fix validity check of pointer size argument in new CAS
+      implementation
+    - powerpc/signal: Properly handle return value from uprobe_deny_signal()
+    - media: Don't do DMA on stack for firmware upload in the AS102 driver
+    - media: rc: check for integer overflow
+    - cx231xx-cards: fix NULL-deref on missing association descriptor
+    - media: v4l2-ctrl: Fix flags field on Control events
+    - sched/rt: Simplify the IPI based RT balancing logic
+    - fscrypt: lock mutex before checking for bounce page pool
+    - net/9p: Switch to wait_event_killable()
+    - PM / OPP: Add missing of_node_put(np)
+    - e1000e: Fix error path in link detection
+    - e1000e: Fix return value test
+    - RDS: RDMA: return appropriate error on rdma map failures
+    - PCI: Apply _HPX settings only to relevant devices
+    - dmaengine: zx: set DMA_CYCLIC cap_mask bit
+    - net: Allow IP_MULTICAST_IF to set index to L3 slave
+    - net: 3com: typhoon: typhoon_init_one: make return values more specific
+    - net: 3com: typhoon: typhoon_init_one: fix incorrect return values
+    - drm/armada: Fix compile fail
+    - ath10k: fix incorrect txpower set by P2P_DEVICE interface
+    - ath10k: ignore configuring the incorrect board_id
+    - ath10k: fix potential memory leak in ath10k_wmi_tlv_op_pull_fw_stats()
+    - ath10k: set CTS protection VDEV param only if VDEV is up
+    - ALSA: hda - Apply ALC269_FIXUP_NO_SHUTUP on HDA_FIXUP_ACT_PROBE
+    - drm: Apply range restriction after color adjustment when allocation
+    - mac80211: Remove invalid flag operations in mesh TSF synchronization
+    - mac80211: Suppress NEW_PEER_CANDIDATE event if no room
+    - iio: light: fix improper return value
+    - staging: iio: cdc: fix improper return value
+    - spi: SPI_FSL_DSPI should depend on HAS_DMA
+    - netfilter: nft_queue: use raw_smp_processor_id()
+    - netfilter: nf_tables: fix oob access
+    - ASoC: rsnd: don't double free kctrl
+    - btrfs: return the actual error value from from btrfs_uuid_tree_iterate
+    - ASoC: wm_adsp: Don't overrun firmware file buffer when reading region data
+    - s390/kbuild: enable modversions for symbols exported from asm
+    - xen: xenbus driver must not accept invalid transaction ids
+    - Revert "sctp: do not peel off an assoc from one netns to another one"
+    - Linux 4.4.103
+
+  * ppc64el: Do not call ibm,os-term on panic (LP: #1736954)
+    - powerpc: Do not call ppc_md.panic in fadump panic notifier
+
+  * Xenial update to 4.4.102 stable release (LP: #1744870)
+    - mm, hwpoison: fixup "mm: check the return value of lookup_page_ext for all
+      call sites"
+    - Linux 4.4.102
+
+  * Xenial update to 4.4.101 stable release (LP: #1744794)
+    - tcp: do not mangle skb->cb[] in tcp_make_synack()
+    - netfilter/ipvs: clear ipvs_property flag when SKB net namespace changed
+    - bonding: discard lowest hash bit for 802.3ad layer3+4
+    - vlan: fix a use-after-free in vlan_device_event()
+    - af_netlink: ensure that NLMSG_DONE never fails in dumps
+    - sctp: do not peel off an assoc from one netns to another one
+    - fealnx: Fix building error on MIPS
+    - net/sctp: Always set scope_id in sctp_inet6_skb_msgname
+    - ima: do not update security.ima if appraisal status is not INTEGRITY_PASS
+    - serial: omap: Fix EFR write on RTS deassertion
+    - arm64: fix dump_instr when PAN and UAO are in use
+    - ocfs2: should wait dio before inode lock in ocfs2_setattr()
+    - ipmi: fix unsigned long underflow
+    - mm/page_alloc.c: broken deferred calculation
+    - coda: fix 'kernel memory exposure attempt' in fsync
+    - mm: check the return value of lookup_page_ext for all call sites
+    - mm/page_ext.c: check if page_ext is not prepared
+    - mm/pagewalk.c: report holes in hugetlb ranges
+    - Linux 4.4.101
+
+  * Xenial update to 4.4.100 stable release (LP: #1744639)
+    - media: imon: Fix null-ptr-deref in imon_probe
+    - media: dib0700: fix invalid dvb_detach argument
+    - KVM: x86: fix singlestepping over syscall
+    - net: cdc_ether: fix divide by 0 on bad descriptors
+    - net: qmi_wwan: fix divide by 0 on bad descriptors
+    - arm: crypto: reduce priority of bit-sliced AES cipher
+    - Bluetooth: btusb: fix QCA Rome suspend/resume
+    - dmaengine: dmatest: warn user when dma test times out
+    - extcon: palmas: Check the parent instance to prevent the NULL
+    - fm10k: request reset when mbx->state changes
+    - ARM: dts: Fix compatible for ti81xx uarts for 8250
+    - ARM: dts: Fix am335x and dm814x scm syscon to probe children
+    - ARM: OMAP2+: Fix init for multiple quirks for the same SoC
+    - ARM: dts: Fix omap3 off mode pull defines
+    - ata: ATA_BMDMA should depend on HAS_DMA
+    - ata: SATA_HIGHBANK should depend on HAS_DMA
+    - ata: SATA_MV should depend on HAS_DMA
+    - drm/sti: sti_vtg: Handle return NULL error from devm_ioremap_nocache
+    - igb: reset the PHY before reading the PHY ID
+    - igb: close/suspend race in netif_device_detach
+    - igb: Fix hw_dbg logging in igb_update_flash_i210
+    - scsi: ufs-qcom: Fix module autoload
+    - scsi: ufs: add capability to keep auto bkops always enabled
+    - staging: rtl8188eu: fix incorrect ERROR tags from logs
+    - scsi: lpfc: FCoE VPort enable-disable does not bring up the VPort
+    - scsi: lpfc: Correct host name in symbolic_name field
+    - scsi: lpfc: Correct issue leading to oops during link reset
+    - scsi: lpfc: Clear the VendorVersion in the PLOGI/PLOGI ACC payload
+    - ALSA: vx: Don't try to update capture stream before running
+    - ALSA: vx: Fix possible transfer overflow
+    - backlight: lcd: Fix race condition during register
+    - backlight: adp5520: Fix error handling in adp5520_bl_probe()
+    - gpu: drm: mgag200: mgag200_main:- Handle error from pci_iomap
+    - ALSA: hda/realtek - Add new codec ID ALC299
+    - arm64: dts: NS2: reserve memory for Nitro firmware
+    - ixgbe: fix AER error handling
+    - ixgbe: handle close/suspend race with netif_device_detach/present
+    - ixgbe: Reduce I2C retry count on X550 devices
+    - ixgbe: add mask for 64 RSS queues
+    - ixgbe: do not disable FEC from the driver
+    - staging: rtl8712: fixed little endian problem
+    - MIPS: End asm function prologue macros with .insn
+    - mm: add PHYS_PFN, use it in __phys_to_pfn()
+    - MIPS: init: Ensure bootmem does not corrupt reserved memory
+    - MIPS: init: Ensure reserved memory regions are not added to bootmem
+    - MIPS: Netlogic: Exclude netlogic,xlp-pic code from XLR builds
+    - Revert "crypto: xts - Add ECB dependency"
+    - Revert "uapi: fix linux/rds.h userspace compilation errors"
+    - uapi: fix linux/rds.h userspace compilation error
+    - uapi: fix linux/rds.h userspace compilation errors
+    - USB: usbfs: compute urb->actual_length for isochronous
+    - USB: Add delay-init quirk for Corsair K70 LUX keyboards
+    - USB: serial: qcserial: add pid/vid for Sierra Wireless EM7355 fw update
+    - USB: serial: garmin_gps: fix I/O after failed probe and remove
+    - USB: serial: garmin_gps: fix memory leak on probe errors
+    - Linux 4.4.100
+
+  * Xenial update to 4.4.99 stable release (LP: #1744636)
+    - mac80211: accept key reinstall without changing anything
+    - mac80211: use constant time comparison with keys
+    - mac80211: don't compare TKIP TX MIC key in reinstall prevention
+    - usb: usbtest: fix NULL pointer dereference
+    - Input: ims-psu - check if CDC union descriptor is sane
+    - ALSA: seq: Cancel pending autoload work at unbinding device
+    - tun/tap: sanitize TUNSETSNDBUF input
+    - tcp: fix tcp_mtu_probe() vs highest_sack
+    - l2tp: check ps->sock before running pppol2tp_session_ioctl()
+    - tun: call dev_get_valid_name() before register_netdevice()
+    - sctp: add the missing sock_owned_by_user check in sctp_icmp_redirect
+    - packet: avoid panic in packet_getsockopt()
+    - ipv6: flowlabel: do not leave opt->tot_len with garbage
+    - net/unix: don't show information about sockets from other namespaces
+    - ip6_gre: only increase err_count for some certain type icmpv6 in ip6gre_err
+    - tun: allow positive return values on dev_get_valid_name() call
+    - sctp: reset owner sk for data chunks on out queues when migrating a sock
+    - ppp: fix race in ppp device destruction
+    - ipip: only increase err_count for some certain type icmp in ipip_err
+    - tcp/dccp: fix ireq->opt races
+    - tcp/dccp: fix lockdep splat in inet_csk_route_req()
+    - tcp/dccp: fix other lockdep splats accessing ireq_opt
+    - security/keys: add CONFIG_KEYS_COMPAT to Kconfig
+    - tipc: fix link attribute propagation bug
+    - brcmfmac: remove setting IBSS mode when stopping AP
+    - target/iscsi: Fix iSCSI task reassignment handling
+    - target: Fix node_acl demo-mode + uncached dynamic shutdown regression
+    - misc: panel: properly restore atomic counter on error path
+    - Linux 4.4.99
+
+  * elantech touchpad of Lenovo L480/580 failed to detect hw_version
+    (LP: #1733605)
+    - Input: elantech - add new icbody type 15
+
+  * Disabling zfs does not always disable module checks for the zfs modules
+    (LP: #1737176)
+    - [Packaging] disable zfs module checks when zfs is disabled
+
+  * Using asymmetric key for IMA appraisal crashes the system in Ubuntu 16.04
+    (LP: #1735977)
+    - integrity: convert digsig to akcipher api
+
+  * CVE-2017-17450
+    - netfilter: xt_osf: Add missing permission checks
+
+  * CVE-2017-15129
+    - net: Fix double free and memory corruption in get_net_ns_by_id()
+
+  * CVE-2018-5344
+    - loop: fix concurrent lo_open/lo_release
+
+  * [KVM] Lower the default for halt_poll_ns to 200000 ns (LP: #1724614)
+    - KVM: x86: lower default for halt_poll_ns
+
+  * $(LOCAL_ENV_CC) and $(LOCAL_ENV_DISTCC_HOSTS) should be properly quoted
+    (LP: #1744077)
+    - [Debian] pass LOCAL_ENV_CC and LOCAL_ENV_DISTCC_HOSTS properly
+
+  * Redpine: Wifi/BT not functioning after s3 resume (LP: #1742090) //
+    [16.04][classic] Redpine: wowlan feature doesn't work (LP: #1742094)
+    - SAUCE: Redpine: fix for wowlan wakeup failure
+    - SAUCE: Redpine: fix data issue with non-uapsd APs
+    - SAUCE: Redpine: fix reset card issue
+    - SAUCE: Redpine: fix wowlan issue
+
+  * Using an NVMe drive causes huge power drain (LP: #1664602) // Samsung SSD
+    960 EVO 500GB refused to change power state (LP: #1705748)
+    - nvme-pci: disable APST on Samsung SSD 960 EVO + ASUS PRIME B350M-A
+
+  * Using an NVMe drive causes huge power drain (LP: #1664602)
+    - nvme/scsi: Remove power management support
+    - nvme: return the whole CQE through the request passthrough interface
+    - nvme: factor out a add nvme_is_write helper
+    - nvme: Modify and export sync command submission for fabrics
+    - nvme: Fix nvme_get/set_features() with a NULL result pointer
+    - nvme: Pass pointers, not dma addresses, to nvme_get/set_features()
+    - nvme: Add a quirk mechanism that uses identify_ctrl
+    - nvme: Enable autonomous power state transitions
+    - nvme: Adjust the Samsung APST quirk
+    - nvme: Quirk APST off on "THNSF5256GPUK TOSHIBA"
+    - nvme: only consider exit latency when choosing useful non-op power states
+    - nvme: relax APST default max latency to 100ms
+    - nvme: Quirk APST on Intel 600P/P3100 devices
+
+  * CVE-2017-17862
+    - bpf: fix branch pruning logic
+
+  * CVE-2017-16995
+    - bpf: fix incorrect sign extension in check_alu_op()
+
+  * CVE-2017-17741
+    - KVM: Fix stack-out-of-bounds read in write_mmio
+
+  * CVE-2018-5333
+    - RDS: null pointer dereference in rds_atomic_free_op
+
+  * the kernel is blackholing IPv6 packets to linkdown nexthops (LP: #1738219)
+    - ipv6: Do not consider linkdown nexthops during multipath
+
+  * /dev/bcache/by-uuid links not created after reboot (LP: #1729145)
+    - SAUCE: (no-up) bcache: decouple emitting a cached_dev CHANGE uevent
+
+  * e1000e in 4.4.0-97-generic breaks 82574L under heavy load. (LP: #1730550)
+    - e1000e: Avoid receiver overrun interrupt bursts
+    - e1000e: Separate signaling for link check/link up
+
+  * ath10k: enhance rf signal strength (LP: #1736317)
+    - ath10k: add max_tx_power for QCA6174 WLAN.RM.2.0 firmware
+
+  * User reports excessive ALUA retry messages (LP: #1720228)
+    - scsi_dh_alua: uninitialized variable in alua_rtpg()
+
+  * Add installer support for new Broadcom network drivers.  (LP: #1734757)
+    - d-i: Add bnxt_en_bpo to nic-modules.
+
+  * Transparent hugepages should default to enabled=madvise (LP: #1703742)
+    - SAUCE: use CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y as default
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 13 Mar 2018 11:55:32 +0100
+
+linux (4.4.0-116.140) xenial; urgency=medium
+
+  * linux: 4.4.0-116.140 -proposed tracker (LP: #1748990)
+
+  * BUG: unable to handle kernel NULL pointer dereference at 0000000000000009
+    (LP: #1748671)
+    - SAUCE: net: ipv4: fix for a race condition in raw_sendmsg -- fix backport
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Mon, 12 Feb 2018 20:17:57 +0000
+
+linux (4.4.0-115.139) xenial; urgency=medium
+
+  * linux: 4.4.0-115.138 -proposed tracker (LP: #1748745)
+
+  * CVE-2017-5715 (Spectre v2 Intel)
+    - Revert "UBUNTU: SAUCE: turn off IBPB when full retpoline is present"
+    - SAUCE: turn off IBRS when full retpoline is present
+    - [Packaging] retpoline files must be sorted
+    - [Packaging] pull in retpoline files
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 11 Feb 2018 11:52:42 +0000
+
+linux (4.4.0-114.137) xenial; urgency=medium
+
+  * linux: 4.4.0-114.137 -proposed tracker (LP: #1748484)
+
+  * ALSA backport missing NVIDIA GPU codec IDs to patch table to
+    Ubuntu 16.04 LTS Kernel (LP: #1744117)
+    - ALSA: hda - Add missing NVIDIA GPU codec IDs to patch table
+
+  * Shutdown hang on 16.04 with iscsi targets (LP: #1569925)
+    - scsi: libiscsi: Allow sd_shutdown on bad transport
+
+  * libata: apply MAX_SEC_1024 to all LITEON EP1 series devices (LP: #1743053)
+    - libata: apply MAX_SEC_1024 to all LITEON EP1 series devices
+
+  * KVM patches for s390x to provide facility bits 81 (ppa15) and 82 (bpb)
+    (LP: #1747090)
+    - KVM: s390: wire up bpb feature
+    - KVM: s390: Enable all facility bits that are known good for passthrough
+
+  * CVE-2017-5715 (Spectre v2 Intel)
+    - SAUCE: drop lingering gmb() macro
+    - x86/feature: Enable the x86 feature to control Speculation
+    - x86/feature: Report presence of IBPB and IBRS control
+    - x86/enter: MACROS to set/clear IBRS and set IBPB
+    - x86/enter: Use IBRS on syscall and interrupts
+    - x86/idle: Disable IBRS entering idle and enable it on wakeup
+    - x86/idle: Disable IBRS when offlining cpu and re-enable on wakeup
+    - x86/mm: Set IBPB upon context switch
+    - x86/mm: Only set IBPB when the new thread cannot ptrace current thread
+    - x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm
+    - x86/kvm: Set IBPB when switching VM
+    - x86/kvm: Toggle IBRS on VM entry and exit
+    - x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature
+    - x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb control
+    - x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR
+    - x86/cpu/AMD: Add speculative control support for AMD
+    - x86/microcode: Extend post microcode reload to support IBPB feature
+    - KVM: SVM: Do not intercept new speculative control MSRs
+    - x86/svm: Set IBRS value on VM entry and exit
+    - x86/svm: Set IBPB when running a different VCPU
+    - KVM: x86: Add speculative control CPUID support for guests
+    - SAUCE: Fix spec_ctrl support in KVM
+    - SAUCE: turn off IBPB when full retpoline is present
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Fri, 09 Feb 2018 20:20:45 +0000
+
+linux (4.4.0-113.136) xenial; urgency=low
+
+  * linux: 4.4.0-113.136 -proposed tracker (LP: #1746936)
+
+  [ Stefan Bader ]
+  * Missing install-time driver for QLogic QED 25/40/100Gb Ethernet NIC
+    (LP: #1743638)
+    - [d-i] Add qede to nic-modules udeb
+
+  * CVE-2017-5753 (Spectre v1 Intel)
+    - x86/cpu/AMD: Make the LFENCE instruction serialized
+    - x86/cpu/AMD: Remove now unused definition of MFENCE_RDTSC feature
+    - SAUCE: reinstate MFENCE_RDTSC feature definition
+    - locking/barriers: introduce new observable speculation barrier
+    - bpf: prevent speculative execution in eBPF interpreter
+    - x86, bpf, jit: prevent speculative execution when JIT is enabled
+    - SAUCE: FIX: x86, bpf, jit: prevent speculative execution when JIT is enabled
+    - carl9170: prevent speculative execution
+    - qla2xxx: prevent speculative execution
+    - Thermal/int340x: prevent speculative execution
+    - ipv4: prevent speculative execution
+    - ipv6: prevent speculative execution
+    - fs: prevent speculative execution
+    - net: mpls: prevent speculative execution
+    - udf: prevent speculative execution
+    - userns: prevent speculative execution
+    - SAUCE: claim mitigation via observable speculation barrier
+    - SAUCE: powerpc: add osb barrier
+    - SAUCE: s390/spinlock: add osb memory barrier
+    - SAUCE: arm64: no osb() implementation yet
+    - SAUCE: arm: no osb() implementation yet
+
+  * CVE-2017-5715 (Spectre v2 retpoline)
+    - x86/cpuid: Provide get_scattered_cpuid_leaf()
+    - x86/cpu: Factor out application of forced CPU caps
+    - x86/cpufeatures: Make CPU bugs sticky
+    - x86/cpufeatures: Add X86_BUG_CPU_INSECURE
+    - x86/cpu, x86/pti: Do not enable PTI on AMD processors
+    - x86/pti: Rename BUG_CPU_INSECURE to BUG_CPU_MELTDOWN
+    - x86/cpufeatures: Add X86_BUG_SPECTRE_V[12]
+    - x86/cpu: Merge bugs.c and bugs_64.c
+    - sysfs/cpu: Add vulnerability folder
+    - x86/cpu: Implement CPU vulnerabilites sysfs functions
+    - x86/alternatives: Add missing '\n' at end of ALTERNATIVE inline asm
+    - x86/mm/32: Move setup_clear_cpu_cap(X86_FEATURE_PCID) earlier
+    - x86/asm: Use register variable to get stack pointer value
+    - x86/kbuild: enable modversions for symbols exported from asm
+    - x86/asm: Make asm/alternative.h safe from assembly
+    - EXPORT_SYMBOL() for asm
+    - kconfig.h: use __is_defined() to check if MODULE is defined
+    - x86/retpoline: Add initial retpoline support
+    - x86/spectre: Add boot time option to select Spectre v2 mitigation
+    - x86/retpoline/crypto: Convert crypto assembler indirect jumps
+    - x86/retpoline/entry: Convert entry assembler indirect jumps
+    - x86/retpoline/ftrace: Convert ftrace assembler indirect jumps
+    - x86/retpoline/hyperv: Convert assembler indirect jumps
+    - x86/retpoline/xen: Convert Xen hypercall indirect jumps
+    - x86/retpoline/checksum32: Convert assembler indirect jumps
+    - x86/retpoline/irq32: Convert assembler indirect jumps
+    - x86/retpoline: Fill return stack buffer on vmexit
+    - x86/retpoline: Remove compile time warning
+    - x86/retpoline: Add LFENCE to the retpoline/RSB filling RSB macros
+    - module: Add retpoline tag to VERMAGIC
+    - x86/mce: Make machine check speculation protected
+    - retpoline: Introduce start/end markers of indirect thunk
+    - kprobes/x86: Blacklist indirect thunk functions for kprobes
+    - kprobes/x86: Disable optimizing on the function jumps to indirect thunk
+    - x86/retpoline: Optimize inline assembler for vmexit_fill_RSB
+    - [Config] CONFIG_RETPOLINE=y
+    - [Packaging] retpoline -- add call site validation
+    - [Config] disable retpoline checks for first upload
+
+  * CVE-2017-5715 (revert embargoed) // CVE-2017-5753 (revert embargoed)
+    - Revert "UBUNTU: SAUCE: Fix spec_ctrl support in KVM"
+    - Revert "x86/cpuid: Provide get_scattered_cpuid_leaf()"
+    - Revert "kvm: vmx: Scrub hardware GPRs at VM-exit"
+    - Revert "Revert "x86/svm: Add code to clear registers on VM exit""
+    - Revert "UBUNTU: SAUCE: x86/microcode: Extend post microcode reload to
+      support IBPB feature -- repair missmerge"
+    - Revert "arm: no gmb() implementation yet"
+    - Revert "arm64: no gmb() implementation yet"
+    - Revert "UBUNTU: SAUCE: x86/kvm: Fix stuff_RSB() for 32-bit"
+    - Revert "s390/spinlock: add gmb memory barrier"
+    - Revert "powerpc: add gmb barrier"
+    - Revert "x86/cpu/AMD: Remove now unused definition of MFENCE_RDTSC feature"
+    - Revert "x86/cpu/AMD: Make the LFENCE instruction serialized"
+    - Revert "x86/svm: Add code to clear registers on VM exit"
+    - Revert "x86/svm: Add code to clobber the RSB on VM exit"
+    - Revert "KVM: x86: Add speculative control CPUID support for guests"
+    - Revert "x86/svm: Set IBPB when running a different VCPU"
+    - Revert "x86/svm: Set IBRS value on VM entry and exit"
+    - Revert "KVM: SVM: Do not intercept new speculative control MSRs"
+    - Revert "x86/microcode: Extend post microcode reload to support IBPB feature"
+    - Revert "x86/cpu/AMD: Add speculative control support for AMD"
+    - Revert "x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR"
+    - Revert "x86/entry: Use retpoline for syscall's indirect calls"
+    - Revert "x86/syscall: Clear unused extra registers on 32-bit compatible
+      syscall entrance"
+    - Revert "x86/syscall: Clear unused extra registers on syscall entrance"
+    - Revert "x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb
+      control"
+    - Revert "x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature"
+    - Revert "x86/kvm: Pad RSB on VM transition"
+    - Revert "x86/kvm: Toggle IBRS on VM entry and exit"
+    - Revert "x86/kvm: Set IBPB when switching VM"
+    - Revert "x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm"
+    - Revert "x86/entry: Stuff RSB for entry to kernel for non-SMEP platform"
+    - Revert "x86/mm: Only set IBPB when the new thread cannot ptrace current
+      thread"
+    - Revert "x86/mm: Set IBPB upon context switch"
+    - Revert "x86/idle: Disable IBRS when offlining cpu and re-enable on wakeup"
+    - Revert "x86/idle: Disable IBRS entering idle and enable it on wakeup"
+    - Revert "x86/enter: Use IBRS on syscall and interrupts"
+    - Revert "x86/enter: MACROS to set/clear IBRS and set IBPB"
+    - Revert "x86/feature: Report presence of IBPB and IBRS control"
+    - Revert "x86/feature: Enable the x86 feature to control Speculation"
+    - Revert "udf: prevent speculative execution"
+    - Revert "net: mpls: prevent speculative execution"
+    - Revert "fs: prevent speculative execution"
+    - Revert "ipv6: prevent speculative execution"
+    - Revert "userns: prevent speculative execution"
+    - Revert "Thermal/int340x: prevent speculative execution"
+    - Revert "qla2xxx: prevent speculative execution"
+    - Revert "carl9170: prevent speculative execution"
+    - Revert "uvcvideo: prevent speculative execution"
+    - Revert "x86, bpf, jit: prevent speculative execution when JIT is enabled"
+    - Revert "bpf: prevent speculative execution in eBPF interpreter"
+
+  * CVE-2017-17712
+    - net: ipv4: fix for a race condition in raw_sendmsg
+
+  * upload urgency should be medium by default (LP: #1745338)
+    - [Packaging] update urgency to medium by default
+
+  * CVE-CVE-2017-12190
+    - more bio_map_user_iov() leak fixes
+
+  * CVE-2015-8952
+    - mbcache2: reimplement mbcache
+    - ext2: convert to mbcache2
+    - ext4: convert to mbcache2
+    - mbcache2: limit cache size
+    - mbcache2: Use referenced bit instead of LRU
+    - ext4: kill ext4_mballoc_ready
+    - ext4: shortcut setting of xattr to the same value
+    - mbcache: remove mbcache
+    - mbcache2: rename to mbcache
+    - mbcache: get rid of _e_hash_list_head
+    - mbcache: add reusable flag to cache entries
+
+  * CVE-2017-15115
+    - sctp: do not peel off an assoc from one netns to another one
+
+  * CVE-2017-8824
+    - dccp: CVE-2017-8824: use-after-free in DCCP code
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 07 Feb 2018 16:05:50 +0000
+
+linux (4.4.0-112.135) xenial; urgency=low
+
+  * linux: 4.4.0-112.135 -proposed tracker (LP: #1744244)
+
+  * CVE-2017-5715 // CVE-2017-5753
+    - x86/cpuid: Provide get_scattered_cpuid_leaf()
+    - SAUCE: Fix spec_ctrl support in KVM
+    - SAUCE: s390: improve cpu alternative handling for gmb and nobp
+    - SAUCE: s390: print messages for gmb and nobp
+    - [Config] KERNEL_NOBP=y
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 19 Jan 2018 11:03:51 +0100
+
+linux (4.4.0-111.134) xenial; urgency=low
+
+  * linux: 4.4.0-111.134 -proposed tracker (LP: #1743362)
+
+  * Do not duplicate changelog entries assigned to more than one bug or CVE
+    (LP: #1743383)
+    - [Packaging] git-ubuntu-log -- handle multiple bugs/cves better
+
+  * CVE-2017-5715 // CVE-2017-5753
+    - SAUCE: x86/microcode: Extend post microcode reload to support IBPB feature
+      -- repair missmerge
+    - Revert "x86/svm: Add code to clear registers on VM exit"
+    - kvm: vmx: Scrub hardware GPRs at VM-exit
+
+  * CVE-2017-5754
+    - SAUCE: powerpc: use sync instead of hwsync mnemonic
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 15 Jan 2018 15:05:02 +0100
+
+linux (4.4.0-110.133) xenial; urgency=low
+
+  * linux: 4.4.0-110.133 -proposed tracker (LP: #1742995)
+
+  * CVE-2017-5753
+    - x86/microcode/AMD: Add support for fam17h microcode loading
+    - bpf: add bpf_patch_insn_single helper
+    - bpf: prepare bpf_int_jit_compile/bpf_prog_select_runtime apis
+    - bpf: add generic constant blinding for use in jits
+    - locking/barriers: introduce new memory barrier gmb()
+    - bpf: prevent speculative execution in eBPF interpreter
+    - x86, bpf, jit: prevent speculative execution when JIT is enabled
+    - uvcvideo: prevent speculative execution
+    - carl9170: prevent speculative execution
+    - qla2xxx: prevent speculative execution
+    - Thermal/int340x: prevent speculative execution
+    - userns: prevent speculative execution
+    - ipv6: prevent speculative execution
+    - fs: prevent speculative execution
+    - net: mpls: prevent speculative execution
+    - udf: prevent speculative execution
+    - x86/feature: Enable the x86 feature to control Speculation
+    - x86/feature: Report presence of IBPB and IBRS control
+    - x86/enter: MACROS to set/clear IBRS and set IBPB
+    - x86/enter: Use IBRS on syscall and interrupts
+    - x86/idle: Disable IBRS entering idle and enable it on wakeup
+    - x86/idle: Disable IBRS when offlining cpu and re-enable on wakeup
+    - x86/mm: Set IBPB upon context switch
+    - x86/mm: Only set IBPB when the new thread cannot ptrace current thread
+    - x86/entry: Stuff RSB for entry to kernel for non-SMEP platform
+    - x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm
+    - x86/kvm: Set IBPB when switching VM
+    - x86/kvm: Toggle IBRS on VM entry and exit
+    - x86/kvm: Pad RSB on VM transition
+    - x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature
+    - x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb control
+    - x86/syscall: Clear unused extra registers on syscall entrance
+    - x86/syscall: Clear unused extra registers on 32-bit compatible syscall
+      entrance
+    - x86/entry: Use retpoline for syscall's indirect calls
+    - x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR
+    - x86/cpu/AMD: Add speculative control support for AMD
+    - x86/microcode: Extend post microcode reload to support IBPB feature
+    - KVM: SVM: Do not intercept new speculative control MSRs
+    - x86/svm: Set IBRS value on VM entry and exit
+    - x86/svm: Set IBPB when running a different VCPU
+    - KVM: x86: Add speculative control CPUID support for guests
+    - x86/svm: Add code to clobber the RSB on VM exit
+    - x86/svm: Add code to clear registers on VM exit
+    - x86/cpu/AMD: Make the LFENCE instruction serialized
+    - x86/cpu/AMD: Remove now unused definition of MFENCE_RDTSC feature
+    - powerpc: add gmb barrier
+    - s390/spinlock: add gmb memory barrier
+    - SAUCE: x86/kvm: Fix stuff_RSB() for 32-bit
+    - arm64: no gmb() implementation yet
+    - arm: no gmb() implementation yet
+
+  * CVE-2017-5715
+    - x86/microcode/AMD: Add support for fam17h microcode loading
+    - bpf: add bpf_patch_insn_single helper
+    - bpf: prepare bpf_int_jit_compile/bpf_prog_select_runtime apis
+    - bpf: add generic constant blinding for use in jits
+    - locking/barriers: introduce new memory barrier gmb()
+    - bpf: prevent speculative execution in eBPF interpreter
+    - x86, bpf, jit: prevent speculative execution when JIT is enabled
+    - uvcvideo: prevent speculative execution
+    - carl9170: prevent speculative execution
+    - qla2xxx: prevent speculative execution
+    - Thermal/int340x: prevent speculative execution
+    - userns: prevent speculative execution
+    - ipv6: prevent speculative execution
+    - fs: prevent speculative execution
+    - net: mpls: prevent speculative execution
+    - udf: prevent speculative execution
+    - x86/feature: Enable the x86 feature to control Speculation
+    - x86/feature: Report presence of IBPB and IBRS control
+    - x86/enter: MACROS to set/clear IBRS and set IBPB
+    - x86/enter: Use IBRS on syscall and interrupts
+    - x86/idle: Disable IBRS entering idle and enable it on wakeup
+    - x86/idle: Disable IBRS when offlining cpu and re-enable on wakeup
+    - x86/mm: Set IBPB upon context switch
+    - x86/mm: Only set IBPB when the new thread cannot ptrace current thread
+    - x86/entry: Stuff RSB for entry to kernel for non-SMEP platform
+    - x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm
+    - x86/kvm: Set IBPB when switching VM
+    - x86/kvm: Toggle IBRS on VM entry and exit
+    - x86/kvm: Pad RSB on VM transition
+    - x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature
+    - x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb control
+    - x86/syscall: Clear unused extra registers on syscall entrance
+    - x86/syscall: Clear unused extra registers on 32-bit compatible syscall
+      entrance
+    - x86/entry: Use retpoline for syscall's indirect calls
+    - x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR
+    - x86/cpu/AMD: Add speculative control support for AMD
+    - x86/microcode: Extend post microcode reload to support IBPB feature
+    - KVM: SVM: Do not intercept new speculative control MSRs
+    - x86/svm: Set IBRS value on VM entry and exit
+    - x86/svm: Set IBPB when running a different VCPU
+    - KVM: x86: Add speculative control CPUID support for guests
+    - x86/svm: Add code to clobber the RSB on VM exit
+    - x86/svm: Add code to clear registers on VM exit
+    - x86/cpu/AMD: Make the LFENCE instruction serialized
+    - x86/cpu/AMD: Remove now unused definition of MFENCE_RDTSC feature
+    - powerpc: add gmb barrier
+    - s390/spinlock: add gmb memory barrier
+    - SAUCE: x86/kvm: Fix stuff_RSB() for 32-bit
+    - arm64: no gmb() implementation yet
+    - arm: no gmb() implementation yet
+
+  * powerpc: flush L1D on return to use (LP: #1742772)
+    - SAUCE: powerpc: Secure memory rfi flush
+    - SAUCE: rfi-flush: Make DEBUG_RFI a CONFIG option
+    - SAUCE: rfi-flush: Add HRFI_TO_UNKNOWN and use it in denorm
+    - SAUCE: Fixup rfid in kvmppc_skip_Hinterrupt should be hrfid
+    - SAUCE: rfi-flush: kvmppc_skip_(H)interrupt returns to host
+    - SAUCE: KVM: Revert the implementation of H_GET_CPU_CHARACTERISTICS
+    - SAUCE: rfi-flush: Implement congruence-first fallback flush
+    - SAUCE: rfi-flush: Make l1d_flush_type bit flags
+    - SAUCE: rfi-flush: Push the instruction selection down to the patching
+      routine
+    - SAUCE: rfi-flush: Expand the RFI section to two nop slots
+    - SAUCE: rfi-flush: Support more than one flush type at once
+    - SAUCE: rfi-flush: Allow HV to advertise multiple flush types
+    - SAUCE: rfi-flush: Add speculation barrier before ori 30,30,0 flush
+    - SAUCE: powerpc/asm: Allow including ppc_asm.h in asm files
+    - SAUCE: Remove setup.h include file otherwise compilation complains about
+      missing header file.
+    - SAUCE: Fix compilation errors for arch/powerpc/lib/feature-fixups.c
+    - SAUCE: rfi-flush: Add barriers to the fallback L1D flushing
+    - SAUCE: rfi-flush: Rework powernv logic to be more cautious
+    - SAUCE: rfi-flush: Rework pseries logic to be more cautious
+    - SAUCE: rfi-flush: Fix the fallback flush to actually activate
+    - SAUCE: rfi-flush: Fix HRFI_TO_UNKNOWN
+    - SAUCE: rfi-flush: Refactor the macros so the nops are defined once
+    - SAUCE: rfi-flush: Add no_rfi_flush and nopti comandline options
+    - SAUCE: rfi-flush: Use rfi-flush in printks
+    - SAUCE: rfi-flush: Fallback flush add load dependency
+    - SAUCE: rfi-flush: Fix the 32-bit KVM build
+    - SAUCE: rfi-flush: Fix some RFI conversions in the KVM code
+    - SAUCE: UBUNTU: [Config] Disable CONFIG_PPC_DEBUG_RFI
+
+  * s390: add ppa to kernel entry/exit (LP: #1742771)
+    - s390: introduce CPU alternatives
+    - s390: add ppa to kernel entry / exit
+
+  * CVE-2017-5754
+    - x86/tlb: Drop the _GPL from the cpu_tlbstate export
+    - Map the vsyscall page with _PAGE_USER
+    - s390: introduce CPU alternatives
+    - s390: add ppa to kernel entry / exit
+    - SAUCE: powerpc: Secure memory rfi flush
+    - SAUCE: rfi-flush: Make DEBUG_RFI a CONFIG option
+    - SAUCE: rfi-flush: Add HRFI_TO_UNKNOWN and use it in denorm
+    - SAUCE: Fixup rfid in kvmppc_skip_Hinterrupt should be hrfid
+    - SAUCE: rfi-flush: kvmppc_skip_(H)interrupt returns to host
+    - SAUCE: KVM: Revert the implementation of H_GET_CPU_CHARACTERISTICS
+    - SAUCE: rfi-flush: Implement congruence-first fallback flush
+    - SAUCE: rfi-flush: Make l1d_flush_type bit flags
+    - SAUCE: rfi-flush: Push the instruction selection down to the patching
+      routine
+    - SAUCE: rfi-flush: Expand the RFI section to two nop slots
+    - SAUCE: rfi-flush: Support more than one flush type at once
+    - SAUCE: rfi-flush: Allow HV to advertise multiple flush types
+    - SAUCE: rfi-flush: Add speculation barrier before ori 30,30,0 flush
+    - SAUCE: powerpc/asm: Allow including ppc_asm.h in asm files
+    - SAUCE: Remove setup.h include file otherwise compilation complains about
+      missing header file.
+    - SAUCE: Fix compilation errors for arch/powerpc/lib/feature-fixups.c
+    - SAUCE: rfi-flush: Add barriers to the fallback L1D flushing
+    - SAUCE: rfi-flush: Rework powernv logic to be more cautious
+    - SAUCE: rfi-flush: Rework pseries logic to be more cautious
+    - SAUCE: rfi-flush: Fix the fallback flush to actually activate
+    - SAUCE: rfi-flush: Fix HRFI_TO_UNKNOWN
+    - SAUCE: rfi-flush: Refactor the macros so the nops are defined once
+    - SAUCE: rfi-flush: Add no_rfi_flush and nopti comandline options
+    - SAUCE: rfi-flush: Use rfi-flush in printks
+    - SAUCE: rfi-flush: Fallback flush add load dependency
+    - SAUCE: rfi-flush: Fix the 32-bit KVM build
+    - SAUCE: rfi-flush: Fix some RFI conversions in the KVM code
+    - SAUCE: UBUNTU: [Config] Disable CONFIG_PPC_DEBUG_RFI
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Fri, 12 Jan 2018 14:47:54 -0200
+
+linux (4.4.0-109.132) xenial; urgency=low
+
+  * linux: 4.4.0-109.132 -proposed tracker (LP: #1742252)
+
+  * Kernel trace with xenial 4.4  (4.4.0-108.131, Candidate kernels for PTI fix)
+    (LP: #1741934)
+    - SAUCE: kaiser: fix perf crashes - fix to original commit
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Tue, 09 Jan 2018 15:56:26 -0200
+
+linux (4.4.0-108.131) xenial; urgency=low
+
+  * linux: 4.4.0-108.131 -proposed tracker (LP: #1741727)
+
+  * CVE-2017-5754
+    - x86/mm: Disable PCID on 32-bit kernels
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Sun, 07 Jan 2018 11:46:05 -0200
+
+linux (4.4.0-107.130) xenial; urgency=low
+
+  * linux: 4.4.0-107.130 -proposed tracker (LP: #1741643)
+
+  * CVE-2017-5754
+    - Revert "UBUNTU: SAUCE: arch/x86/entry/vdso: temporarily disable vdso"
+    - KPTI: Report when enabled
+    - x86, vdso, pvclock: Simplify and speed up the vdso pvclock reader
+    - x86/vdso: Get pvclock data from the vvar VMA instead of the fixmap
+    - x86/kasan: Clear kasan_zero_page after TLB flush
+    - kaiser: Set _PAGE_NX only if supported
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Sat, 06 Jan 2018 17:13:03 +0100
+
+linux (4.4.0-106.129) xenial; urgency=low
+
+  * linux: 4.4.0-106.129 -proposed tracker (LP: #1741528)
+
+  * CVE-2017-5754
+    - KAISER: Kernel Address Isolation
+    - kaiser: merged update
+    - kaiser: do not set _PAGE_NX on pgd_none
+    - kaiser: stack map PAGE_SIZE at THREAD_SIZE-PAGE_SIZE
+    - kaiser: fix build and FIXME in alloc_ldt_struct()
+    - kaiser: KAISER depends on SMP
+    - kaiser: fix regs to do_nmi() ifndef CONFIG_KAISER
+    - kaiser: fix perf crashes
+    - kaiser: ENOMEM if kaiser_pagetable_walk() NULL
+    - kaiser: tidied up asm/kaiser.h somewhat
+    - kaiser: tidied up kaiser_add/remove_mapping slightly
+    - kaiser: kaiser_remove_mapping() move along the pgd
+    - kaiser: cleanups while trying for gold link
+    - kaiser: name that 0x1000 KAISER_SHADOW_PGD_OFFSET
+    - kaiser: delete KAISER_REAL_SWITCH option
+    - kaiser: vmstat show NR_KAISERTABLE as nr_overhead
+    - x86/mm: Enable CR4.PCIDE on supported systems
+    - x86/mm: Build arch/x86/mm/tlb.c even on !SMP
+    - x86/mm, sched/core: Uninline switch_mm()
+    - x86/mm: Add INVPCID helpers
+    - x86/mm: If INVPCID is available, use it to flush global mappings
+    - kaiser: enhanced by kernel and user PCIDs
+    - kaiser: load_new_mm_cr3() let SWITCH_USER_CR3 flush user
+    - kaiser: PCID 0 for kernel and 128 for user
+    - kaiser: x86_cr3_pcid_noflush and x86_cr3_pcid_user
+    - kaiser: paranoid_entry pass cr3 need to paranoid_exit
+    - kaiser: _pgd_alloc() without __GFP_REPEAT to avoid stalls
+    - kaiser: fix unlikely error in alloc_ldt_struct()
+    - kaiser: add "nokaiser" boot option, using ALTERNATIVE
+    - x86/kaiser: Rename and simplify X86_FEATURE_KAISER handling
+    - x86/boot: Add early cmdline parsing for options with arguments
+    - x86/kaiser: Check boottime cmdline params
+    - kaiser: use ALTERNATIVE instead of x86_cr3_pcid_noflush
+    - kaiser: drop is_atomic arg to kaiser_pagetable_walk()
+    - kaiser: asm/tlbflush.h handle noPGE at lower level
+    - kaiser: kaiser_flush_tlb_on_return_to_user() check PCID
+    - x86/paravirt: Dont patch flush_tlb_single
+    - x86/kaiser: Reenable PARAVIRT
+    - kaiser: disabled on Xen PV
+    - x86/kaiser: Move feature detection up
+    - kvm: x86: fix RSM when PCID is non-zero
+    - SAUCE: arch/x86/entry/vdso: temporarily disable vdso
+    - [Config]: CONFIG_KAISER=y
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 05 Jan 2018 19:53:41 +0100
+
+linux (4.4.0-104.127) xenial; urgency=low
+
+  * linux: 4.4.0-104.127 -proposed tracker (LP: #1737511)
+
+  * upgrading linux-image package to 4.4.0-103.126 breaks Ceph network file
+    system connection (LP: #1737033)
+    - Revert "libceph: MOSDOpReply v7 encoding"
+    - Revert "libceph: advertise support for TUNABLES5"
+    - Revert "crush: decode and initialize chooseleaf_stable"
+    - Revert "crush: add chooseleaf_stable tunable"
+    - Revert "crush: ensure take bucket value is valid"
+    - Revert "crush: ensure bucket id is valid before indexing buckets array"
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 11 Dec 2017 12:20:36 +0100
+
+linux (4.4.0-103.126) xenial; urgency=low
+
+  * linux: 4.4.0-103.126 -proposed tracker (LP: #1736181)
+
+  * CVE-2017-1000405
+    - mm, thp: Do not make page table dirty unconditionally in touch_p[mu]d()
+
+  * CVE-2017-16939
+    - netlink: add a start callback for starting a netlink dump
+    - ipsec: Fix aborted xfrm policy dump crash
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 04 Dec 2017 16:50:53 +0100
+
+linux (4.4.0-102.125) xenial; urgency=low
+
+  * linux: 4.4.0-102.125 -proposed tracker (LP: #1733541)
+
+  * tar -x sometimes fails on overlayfs (LP: #1728489)
+    - ovl: check if all layers are on the same fs
+    - ovl: persistent inode number for directories
+
+  * NVMe timeout is too short (LP: #1729119)
+    - nvme: update timeout module parameter type
+
+  * Set PANIC_TIMEOUT=10 on Power Systems (LP: #1730660)
+    - [Config]: Set PANIC_TIMEOUT=10 on ppc64el
+
+  * Cannot pair BLE remote devices when using combo BT SoC (LP: #1731467)
+    - Bluetooth: increase timeout for le auto connections
+
+  * CIFS errors on 4.4.0-98, but not on 4.4.0-97 with same config (LP: #1729337)
+    - SMB3: Validate negotiate request must always be signed
+
+  * Plantronics P610 does not support sample rate reading (LP: #1719853)
+    - ALSA: usb-audio: Add sample rate quirk for Plantronics P610
+
+  * Invalid btree pointer causes the kernel NULL pointer dereference
+    (LP: #1729256)
+    - xfs: reinit btree pointer on attr tree inactivation walk
+
+  * Samba mount/umount in docker container triggers kernel Oops (LP: #1729637)
+    - ipv6: only call ip6_route_dev_notify() once for NETDEV_UNREGISTER
+    - ipv6: fix NULL dereference in ip6_route_dev_notify()
+
+  * [kernel] tty/hvc: Use opal irqchip interface if available (LP: #1728098)
+    - tty/hvc: Use opal irqchip interface if available
+
+  * Device hotplugging with MPT SAS cannot work for VMWare ESXi (LP: #1730852)
+    - scsi: mptsas: Fixup device hotplug for VMWare ESXi
+
+  * NMI watchdog: BUG: soft lockup on Guest upon boot (KVM) (LP: #1727331)
+    - KVM: PPC: Book3S: Treat VTB as a per-subcore register, not per-thread
+
+  * Attempt to map rbd image from ceph jewel/luminous hangs (LP: #1728739)
+    - crush: ensure bucket id is valid before indexing buckets array
+    - crush: ensure take bucket value is valid
+    - crush: add chooseleaf_stable tunable
+    - crush: decode and initialize chooseleaf_stable
+    - libceph: advertise support for TUNABLES5
+    - libceph: MOSDOpReply v7 encoding
+
+  * Xenial update to 4.4.98 stable release (LP: #1732698)
+    - adv7604: Initialize drive strength to default when using DT
+    - video: fbdev: pmag-ba-fb: Remove bad `__init' annotation
+    - PCI: mvebu: Handle changes to the bridge windows while enabled
+    - xen/netback: set default upper limit of tx/rx queues to 8
+    - drm: drm_minor_register(): Clean up debugfs on failure
+    - KVM: PPC: Book 3S: XICS: correct the real mode ICP rejecting counter
+    - iommu/arm-smmu-v3: Clear prior settings when updating STEs
+    - powerpc/corenet: explicitly disable the SDHC controller on kmcoge4
+    - ARM: omap2plus_defconfig: Fix probe errors on UARTs 5 and 6
+    - crypto: vmx - disable preemption to enable vsx in aes_ctr.c
+    - iio: trigger: free trigger resource correctly
+    - phy: increase size of MII_BUS_ID_SIZE and bus_id
+    - serial: sh-sci: Fix register offsets for the IRDA serial port
+    - usb: hcd: initialize hcd->flags to 0 when rm hcd
+    - netfilter: nft_meta: deal with PACKET_LOOPBACK in netdev family
+    - IPsec: do not ignore crypto err in ah4 input
+    - Input: mpr121 - handle multiple bits change of status register
+    - Input: mpr121 - set missing event capability
+    - IB/ipoib: Change list_del to list_del_init in the tx object
+    - s390/qeth: issue STARTLAN as first IPA command
+    - (config) Add NET_DSA=n
+    - net: dsa: select NET_SWITCHDEV
+    - platform/x86: hp-wmi: Fix detection for dock and tablet mode
+    - cdc_ncm: Set NTB format again after altsetting switch for Huawei devices
+    - KEYS: trusted: sanitize all key material
+    - KEYS: trusted: fix writing past end of buffer in trusted_read()
+    - platform/x86: hp-wmi: Fix error value for hp_wmi_tablet_state
+    - platform/x86: hp-wmi: Do not shadow error values
+    - x86/uaccess, sched/preempt: Verify access_ok() context
+    - workqueue: Fix NULL pointer dereference
+    - crypto: x86/sha1-mb - fix panic due to unaligned access
+    - KEYS: fix NULL pointer dereference during ASN.1 parsing [ver #2]
+    - ARM: 8720/1: ensure dump_instr() checks addr_limit
+    - ALSA: seq: Fix OSS sysex delivery in OSS emulation
+    - ALSA: seq: Avoid invalid lockdep class warning
+    - MIPS: microMIPS: Fix incorrect mask in insn_table_MM
+    - MIPS: Fix CM region target definitions
+    - MIPS: SMP: Use a completion event to signal CPU up
+    - MIPS: Fix race on setting and getting cpu_online_mask
+    - MIPS: SMP: Fix deadlock & online race
+    - test: firmware_class: report errors properly on failure
+    - selftests: firmware: add empty string and async tests
+    - selftests: firmware: send expected errors to /dev/null
+    - tools: firmware: check for distro fallback udev cancel rule
+    - MIPS: AR7: Defer registration of GPIO
+    - MIPS: AR7: Ensure that serial ports are properly set up
+    - Input: elan_i2c - add ELAN060C to the ACPI table
+    - drm/vmwgfx: Fix Ubuntu 17.10 Wayland black screen issue
+    - rbd: use GFP_NOIO for parent stat and data requests
+    - can: sun4i: handle overrun in RX FIFO
+    - can: c_can: don't indicate triple sampling support for D_CAN
+    - x86/oprofile/ppro: Do not use __this_cpu*() in preemptible context
+    - PKCS#7: fix unitialized boolean 'want'
+    - Linux 4.4.98
+
+  * ELANTECH Touchpad is not detected in 'Lenovo Ideapad 320 14AST' after fresh
+    install (LP: #1727544)
+    - Input: elan_i2c - add ELAN060C to the ACPI table
+
+  * Xenial update to 4.4.97 stable release (LP: #1731915)
+    - ALSA: timer: Add missing mutex lock for compat ioctls
+    - ALSA: seq: Fix nested rwsem annotation for lockdep splat
+    - cifs: check MaxPathNameComponentLength != 0 before using it
+    - KEYS: return full count in keyring_read() if buffer is too small
+    - KEYS: fix out-of-bounds read during ASN.1 parsing
+    - ASoC: adau17x1: Workaround for noise bug in ADC
+    - arm64: ensure __dump_instr() checks addr_limit
+    - ARM: dts: mvebu: pl310-cache disable double-linefill
+    - ARM: 8715/1: add a private asm/unaligned.h
+    - ocfs2: fstrim: Fix start offset of first cluster group during fstrim
+    - perf tools: Fix build failure on perl script context
+    - drm/msm: Fix potential buffer overflow issue
+    - drm/msm: fix an integer overflow test
+    - tracing/samples: Fix creation and deletion of simple_thread_fn creation
+    - Fix tracing sample code warning.
+    - PM / wakeirq: report a wakeup_event on dedicated wekup irq
+    - mmc: s3cmci: include linux/interrupt.h for tasklet_struct
+    - ARM: pxa: Don't rely on public mmc header to include leds.h
+    - mfd: ab8500-sysctrl: Handle probe deferral
+    - mfd: axp20x: Fix axp288 PEK_DBR and PEK_DBF irqs being swapped
+    - staging: rtl8712u: Fix endian settings for structs describing network
+      packets
+    - ext4: fix stripe-unaligned allocations
+    - ext4: do not use stripe_width if it is not set
+    - i2c: riic: correctly finish transfers
+    - drm/amdgpu: when dpm disabled, also need to stop/start vce.
+    - perf tools: Only increase index if perf_evsel__new_idx() succeeds
+    - cx231xx: Fix I2C on Internal Master 3 Bus
+    - xen/manage: correct return value check on xenbus_scanf()
+    - scsi: aacraid: Process Error for response I/O
+    - platform/x86: intel_mid_thermal: Fix module autoload
+    - staging: lustre: llite: don't invoke direct_IO for the EOF case
+    - staging: lustre: hsm: stack overrun in hai_dump_data_field
+    - staging: lustre: ptlrpc: skip lock if export failed
+    - exynos4-is: fimc-is: Unmap region obtained by of_iomap()
+    - mei: return error on notification request to a disconnected client
+    - s390/dasd: check for device error pointer within state change interrupts
+    - bt8xx: fix memory leak
+    - xen: don't print error message in case of missing Xenstore entry
+    - staging: r8712u: Fix Sparse warning in rtl871x_xmit.c
+    - Linux 4.4.97
+
+  * Xenial update to 4.4.96 stable release (LP: #1731882)
+    - workqueue: replace pool->manager_arb mutex with a flag
+    - ALSA: hda/realtek - Add support for ALC236/ALC3204
+    - ALSA: hda - fix headset mic problem for Dell machines with alc236
+    - ceph: unlock dangling spinlock in try_flush_caps()
+    - usb: xhci: Handle error condition in xhci_stop_device()
+    - spi: uapi: spidev: add missing ioctl header
+    - fuse: fix READDIRPLUS skipping an entry
+    - xen/gntdev: avoid out of bounds access in case of partial gntdev_mmap()
+    - Input: elan_i2c - add ELAN0611 to the ACPI table
+    - Input: gtco - fix potential out-of-bound access
+    - assoc_array: Fix a buggy node-splitting case
+    - scsi: zfcp: fix erp_action use-before-initialize in REC action trace
+    - scsi: sg: Re-fix off by one in sg_fill_request_table()
+    - can: sun4i: fix loopback mode
+    - can: kvaser_usb: Correct return value in printout
+    - can: kvaser_usb: Ignore CMD_FLUSH_QUEUE_REPLY messages
+    - regulator: fan53555: fix I2C device ids
+    - x86/microcode/intel: Disable late loading on model 79
+    - ecryptfs: fix dereference of NULL user_key_payload
+    - Revert "drm: bridge: add DT bindings for TI ths8135"
+    - Linux 4.4.96
+
+  * Touchpad not detected - Lenovo ideapad 320-15IKB (LP: #1723736)
+    - Input: elan_i2c - add ELAN0611 to the ACPI table
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 21 Nov 2017 15:37:52 +0100
+
+linux (4.4.0-101.124) xenial; urgency=low
+
+  * linux: 4.4.0-101.124 -proposed tracker (LP: #1731264)
+
+  * s390/mm: fix write access check in gup_huge_pmd() (LP: #1730596)
+    - s390/mm: fix write access check in gup_huge_pmd()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 10 Nov 2017 08:24:10 -0200
+
+linux (4.4.0-100.123) xenial; urgency=low
+
+  * linux: 4.4.0-100.123 -proposed tracker (LP: #1729273)
+
+  * Xenial update to 4.4.95 stable release (LP: #1729107)
+    - USB: devio: Revert "USB: devio: Don't corrupt user memory"
+    - USB: core: fix out-of-bounds access bug in usb_get_bos_descriptor()
+    - USB: serial: metro-usb: add MS7820 device id
+    - usb: cdc_acm: Add quirk for Elatec TWN3
+    - usb: quirks: add quirk for WORLDE MINI MIDI keyboard
+    - usb: hub: Allow reset retry for USB2 devices on connect bounce
+    - ALSA: usb-audio: Add native DSD support for Pro-Ject Pre Box S2 Digital
+    - can: gs_usb: fix busy loop if no more TX context is available
+    - usb: musb: sunxi: Explicitly release USB PHY on exit
+    - usb: musb: Check for host-mode using is_host_active() on reset interrupt
+    - can: esd_usb2: Fix can_dlc value for received RTR, frames
+    - drm/nouveau/bsp/g92: disable by default
+    - drm/nouveau/mmu: flush tlbs before deleting page tables
+    - ALSA: seq: Enable 'use' locking in all configurations
+    - ALSA: hda: Remove superfluous '-' added by printk conversion
+    - i2c: ismt: Separate I2C block read from SMBus block read
+    - brcmsmac: make some local variables 'static const' to reduce stack size
+    - bus: mbus: fix window size calculation for 4GB windows
+    - clockevents/drivers/cs5535: Improve resilience to spurious interrupts
+    - rtlwifi: rtl8821ae: Fix connection lost problem
+    - KEYS: encrypted: fix dereference of NULL user_key_payload
+    - lib/digsig: fix dereference of NULL user_key_payload
+    - KEYS: don't let add_key() update an uninstantiated key
+    - pkcs7: Prevent NULL pointer dereference, since sinfo is not always set.
+    - parisc: Avoid trashing sr2 and sr3 in LWS code
+    - parisc: Fix double-word compare and exchange in LWS code on 32-bit kernels
+    - sched/autogroup: Fix autogroup_move_group() to never skip sched_move_task()
+    - f2fs crypto: replace some BUG_ON()'s with error checks
+    - f2fs crypto: add missing locking for keyring_key access
+    - fscrypt: fix dereference of NULL user_key_payload
+    - KEYS: Fix race between updating and finding a negative key
+    - fscrypto: require write access to mount to set encryption policy
+    - FS-Cache: fix dereference of NULL user_key_payload
+    - Linux 4.4.95
+
+  * Xenial update to 4.4.94 stable release (LP: #1729105)
+    - percpu: make this_cpu_generic_read() atomic w.r.t. interrupts
+    - drm/dp/mst: save vcpi with payloads
+    - MIPS: Fix minimum alignment requirement of IRQ stack
+    - sctp: potential read out of bounds in sctp_ulpevent_type_enabled()
+    - bpf/verifier: reject BPF_ALU64|BPF_END
+    - udpv6: Fix the checksum computation when HW checksum does not apply
+    - ip6_gre: skb_push ipv6hdr before packing the header in ip6gre_header
+    - net: emac: Fix napi poll list corruption
+    - packet: hold bind lock when rebinding to fanout hook
+    - bpf: one perf event close won't free bpf program attached by another perf
+      event
+    - isdn/i4l: fetch the ppp_write buffer in one shot
+    - vti: fix use after free in vti_tunnel_xmit/vti6_tnl_xmit
+    - l2tp: Avoid schedule while atomic in exit_net
+    - l2tp: fix race condition in l2tp_tunnel_delete
+    - tun: bail out from tun_get_user() if the skb is empty
+    - packet: in packet_do_bind, test fanout with bind_lock held
+    - packet: only test po->has_vnet_hdr once in packet_snd
+    - net: Set sk_prot_creator when cloning sockets to the right proto
+    - tipc: use only positive error codes in messages
+    - Revert "bsg-lib: don't free job in bsg_prepare_job"
+    - locking/lockdep: Add nest_lock integrity test
+    - watchdog: kempld: fix gcc-4.3 build
+    - irqchip/crossbar: Fix incorrect type of local variables
+    - mac80211_hwsim: check HWSIM_ATTR_RADIO_NAME length
+    - mac80211: fix power saving clients handling in iwlwifi
+    - net/mlx4_en: fix overflow in mlx4_en_init_timestamp()
+    - netfilter: nf_ct_expect: Change __nf_ct_expect_check() return value.
+    - iio: adc: xilinx: Fix error handling
+    - Btrfs: send, fix failure to rename top level inode due to name collision
+    - f2fs: do not wait for writeback in write_begin
+    - md/linear: shutup lockdep warnning
+    - sparc64: Migrate hvcons irq to panicked cpu
+    - net/mlx4_core: Fix VF overwrite of module param which disables DMFS on new
+      probed PFs
+    - crypto: xts - Add ECB dependency
+    - ocfs2/dlmglue: prepare tracking logic to avoid recursive cluster lock
+    - slub: do not merge cache if slub_debug contains a never-merge flag
+    - scsi: scsi_dh_emc: return success in clariion_std_inquiry()
+    - net: mvpp2: release reference to txq_cpu[] entry after unmapping
+    - i2c: at91: ensure state is restored after suspending
+    - ceph: clean up unsafe d_parent accesses in build_dentry_path
+    - uapi: fix linux/rds.h userspace compilation errors
+    - uapi: fix linux/mroute6.h userspace compilation errors
+    - target/iscsi: Fix unsolicited data seq_end_offset calculation
+    - nfsd/callback: Cleanup callback cred on shutdown
+    - cpufreq: CPPC: add ACPI_PROCESSOR dependency
+    - Revert "tty: goldfish: Fix a parameter of a call to free_irq"
+    - Linux 4.4.94
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 01 Nov 2017 16:54:28 -0200
+
+linux (4.4.0-99.122) xenial; urgency=low
+
+  * linux: 4.4.0-99.122 -proposed tracker (LP: #1728945)
+
+  * Remove vmbus-rdma driver from Xenial kernel (LP: #1721538)
+    - SAUCE: remove hv_network_direct driver
+    - [Config]: Remove hv_network_direct driver
+
+  * usb 3-1: 2:1: cannot get freq at ep 0x1 (LP: #1708499)
+    - ALSA: usb-audio: Add sample rate quirk for Plantronics C310/C520-M
+
+  * Plantronics Blackwire C520-M - Cannot get freq at ep 0x1, 0x81
+    (LP: #1709282)
+    - ALSA: usb-audio: Add sample rate quirk for Plantronics C310/C520-M
+
+  * wait-for-root fails to detect nbd root (LP: #696435)
+    - nbd: Create size change events for userspace
+
+  * Fix OpenNSL GPL bugs found by CoverityScan static analysis (LP: #1718388)
+    - SAUCE: opennsl: bcm-knet: check for null sinfo to avoid a null pointer
+      dereference
+    - SAUCE: opennsl: bcm-knet: remove redundant null checks on dev->name
+    - SAUCE: opennsl: bde: check for out-of-bounds index io.dev
+
+  * HID: multitouch: Correct ALPS PTP Stick and Touchpad devices ID
+    (LP: #1722719)
+    - Revert "HID: multitouch: Support ALPS PTP stick with pid 0x120A"
+
+  * Xenial update to 4.4.93 stable release (LP: #1724836)
+    - brcmfmac: add length check in brcmf_cfg80211_escan_handler()
+    - ext4: in ext4_seek_{hole,data}, return -ENXIO for negative offsets
+    - CIFS: Reconnect expired SMB sessions
+    - nl80211: Define policy for packet pattern attributes
+    - iwlwifi: mvm: use IWL_HCMD_NOCOPY for MCAST_FILTER_CMD
+    - rcu: Allow for page faults in NMI handlers
+    - USB: dummy-hcd: Fix deadlock caused by disconnect detection
+    - MIPS: math-emu: Remove pr_err() calls from fpu_emu()
+    - dmaengine: edma: Align the memcpy acnt array size with the transfer
+    - HID: usbhid: fix out-of-bounds bug
+    - crypto: shash - Fix zero-length shash ahash digest crash
+    - KVM: nVMX: fix guest CR4 loading when emulating L2 to L1 exit
+    - usb: renesas_usbhs: Fix DMAC sequence for receiving zero-length packet
+    - iommu/amd: Finish TLB flush in amd_iommu_unmap()
+    - ALSA: usb-audio: Kill stray URB at exiting
+    - ALSA: seq: Fix use-after-free at creating a port
+    - ALSA: seq: Fix copy_from_user() call inside lock
+    - ALSA: caiaq: Fix stray URB at probe error path
+    - ALSA: line6: Fix leftover URB at error-path during probe
+    - usb: gadget: composite: Fix use-after-free in
+      usb_composite_overwrite_options
+    - direct-io: Prevent NULL pointer access in submit_page_section
+    - fix unbalanced page refcounting in bio_map_user_iov
+    - USB: serial: ftdi_sio: add id for Cypress WICED dev board
+    - USB: serial: cp210x: add support for ELV TFD500
+    - USB: serial: option: add support for TP-Link LTE module
+    - Revert "UBUNTU: SAUCE: USB: serial: qcserial: add Dell DW5818, DW5819"
+    - USB: serial: qcserial: add Dell DW5818, DW5819
+    - USB: serial: console: fix use-after-free after failed setup
+    - x86/alternatives: Fix alt_max_short macro to really be a max()
+    - Linux 4.4.93
+
+  * NULL pointer dereference in tty_write() in kernel 4.4.0-93.116+
+    (LP: #1721065)
+    - tty: Prepare for destroying line discipline on hangup
+
+  * Xenial update to 4.4.92 stable release (LP: #1724783)
+    - usb: gadget: inode.c: fix unbalanced spin_lock in ep0_write
+    - USB: gadgetfs: Fix crash caused by inadequate synchronization
+    - USB: gadgetfs: fix copy_to_user while holding spinlock
+    - usb: gadget: udc: atmel: set vbus irqflags explicitly
+    - usb-storage: unusual_devs entry to fix write-access regression for Seagate
+      external drives
+    - usb: renesas_usbhs: fix the BCLR setting condition for non-DCP pipe
+    - usb: renesas_usbhs: fix usbhsf_fifo_clear() for RX direction
+    - ALSA: usb-audio: Check out-of-bounds access by corrupted buffer descriptor
+    - usb: pci-quirks.c: Corrected timeout values used in handshake
+    - USB: dummy-hcd: fix connection failures (wrong speed)
+    - USB: dummy-hcd: fix infinite-loop resubmission bug
+    - USB: dummy-hcd: Fix erroneous synchronization change
+    - USB: devio: Don't corrupt user memory
+    - usb: gadget: mass_storage: set msg_registered after msg registered
+    - USB: g_mass_storage: Fix deadlock when driver is unbound
+    - lsm: fix smack_inode_removexattr and xattr_getsecurity memleak
+    - ALSA: compress: Remove unused variable
+    - ALSA: usx2y: Suppress kernel warning at page allocation failures
+    - driver core: platform: Don't read past the end of "driver_override" buffer
+    - Drivers: hv: fcopy: restore correct transfer length
+    - stm class: Fix a use-after-free
+    - ftrace: Fix kmemleak in unregister_ftrace_graph
+    - HID: i2c-hid: allocate hid buffers for real worst case
+    - iwlwifi: add workaround to disable wide channels in 5GHz
+    - scsi: sd: Do not override max_sectors_kb sysfs setting
+    - USB: uas: fix bug in handling of alternate settings
+    - USB: core: harden cdc_parse_cdc_header
+    - usb: Increase quirk delay for USB devices
+    - USB: fix out-of-bounds in usb_set_configuration
+    - xhci: fix finding correct bus_state structure for USB 3.1 hosts
+    - iio: adc: twl4030: Fix an error handling path in 'twl4030_madc_probe()'
+    - iio: adc: twl4030: Disable the vusb3v1 rugulator in the error handling path
+      of 'twl4030_madc_probe()'
+    - iio: ad_sigma_delta: Implement a dedicated reset function
+    - staging: iio: ad7192: Fix - use the dedicated reset function avoiding dma
+      from stack.
+    - iio: core: Return error for failed read_reg
+    - iio: ad7793: Fix the serial interface reset
+    - iio: adc: mcp320x: Fix readout of negative voltages
+    - iio: adc: mcp320x: Fix oops on module unload
+    - uwb: properly check kthread_run return value
+    - uwb: ensure that endpoint is interrupt
+    - brcmfmac: setup passive scan if requested by user-space
+    - drm/i915/bios: ignore HDMI on port A
+    - sched/cpuset/pm: Fix cpuset vs. suspend-resume bugs
+    - ext4: fix data corruption for mmap writes
+    - ext4: Don't clear SGID when inheriting ACLs
+    - ext4: don't allow encrypted operations without keys
+    - Linux 4.4.92
+
+  * Xenial update to 4.4.91 stable release (LP: #1724772)
+    - drm_fourcc: Fix DRM_FORMAT_MOD_LINEAR #define
+    - drm: bridge: add DT bindings for TI ths8135
+    - GFS2: Fix reference to ERR_PTR in gfs2_glock_iter_next
+    - RDS: RDMA: Fix the composite message user notification
+    - ARM: dts: r8a7790: Use R-Car Gen 2 fallback binding for msiof nodes
+    - MIPS: Ensure bss section ends on a long-aligned address
+    - MIPS: ralink: Fix incorrect assignment on ralink_soc
+    - igb: re-assign hw address pointer on reset after PCI error
+    - extcon: axp288: Use vbus-valid instead of -present to determine cable
+      presence
+    - sh_eth: use correct name for ECMR_MPDE bit
+    - hwmon: (gl520sm) Fix overflows and crash seen when writing into limit
+      attributes
+    - iio: adc: axp288: Drop bogus AXP288_ADC_TS_PIN_CTRL register modifications
+    - iio: adc: hx711: Add DT binding for avia,hx711
+    - ARM: 8635/1: nommu: allow enabling REMAP_VECTORS_TO_RAM
+    - tty: goldfish: Fix a parameter of a call to free_irq
+    - IB/ipoib: Fix deadlock over vlan_mutex
+    - IB/ipoib: rtnl_unlock can not come after free_netdev
+    - IB/ipoib: Replace list_del of the neigh->list with list_del_init
+    - drm/amdkfd: fix improper return value on error
+    - USB: serial: mos7720: fix control-message error handling
+    - USB: serial: mos7840: fix control-message error handling
+    - partitions/efi: Fix integer overflow in GPT size calculation
+    - ASoC: dapm: handle probe deferrals
+    - audit: log 32-bit socketcalls
+    - usb: chipidea: vbus event may exist before starting gadget
+    - ASoC: dapm: fix some pointer error handling
+    - MIPS: Lantiq: Fix another request_mem_region() return code check
+    - net: core: Prevent from dereferencing null pointer when releasing SKB
+    - net/packet: check length in getsockopt() called with PACKET_HDRLEN
+    - team: fix memory leaks
+    - usb: plusb: Add support for PL-27A1
+    - mmc: sdio: fix alignment issue in struct sdio_func
+    - bridge: netlink: register netdevice before executing changelink
+    - netfilter: invoke synchronize_rcu after set the _hook_ to NULL
+    - MIPS: IRQ Stack: Unwind IRQ stack onto task stack
+    - exynos-gsc: Do not swap cb/cr for semi planar formats
+    - netfilter: nfnl_cthelper: fix incorrect helper->expect_class_max
+    - parisc: perf: Fix potential NULL pointer dereference
+    - iommu/io-pgtable-arm: Check for leaf entry before dereferencing it
+    - rds: ib: add error handle
+    - md/raid10: submit bio directly to replacement disk
+    - i2c: meson: fix wrong variable usage in meson_i2c_put_data
+    - xfs: remove kmem_zalloc_greedy
+    - libata: transport: Remove circular dependency at free time
+    - drivers: firmware: psci: drop duplicate const from psci_of_match
+    - IB/qib: fix false-postive maybe-uninitialized warning
+    - ARM: remove duplicate 'const' annotations'
+    - ALSA: au88x0: avoid theoretical uninitialized access
+    - ttpci: address stringop overflow warning
+    - Linux 4.4.91
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 31 Oct 2017 11:49:30 -0200
+
+linux (4.4.0-98.121) xenial; urgency=low
+
+  * linux: 4.4.0-98.121 -proposed tracker (LP: #1722299)
+
+  * Controller lockup detected on ProLiant DL380 Gen9 with P440 Controller
+    (LP: #1720359)
+    - scsi: hpsa: limit transfer length to 1MB
+
+  * [Dell Docking IE][0bda:8153] Realtek USB Ethernet leads to system hang
+    (LP: #1720977)
+    - r8152: fix the list rx_done may be used without initialization
+
+  * Add installer support for Broadcom BCM573xx network drivers. (LP: #1720466)
+    - d-i: Add bnxt_en to nic-modules.
+
+  * snapcraft.yaml: add dpkg-dev to the build deps (LP: #1718886)
+    - snapcraft.yaml: add dpkg-dev to the build deps
+
+  * Support setting I2C_TIMEOUT via ioctl for i2c-designware (LP: #1718578)
+    - i2c: designware: Use transfer timeout from ioctl I2C_TIMEOUT
+
+  * 5U84 - ses driver isn't binding right - cannot blink lights on 1 of the 2
+    5u84 (LP: #1693369)
+    - scsi_transport_sas: add function to get SAS endpoint address
+    - ses: fix discovery of SATA devices in SAS enclosures
+    - scsi: sas: provide stub implementation for scsi_is_sas_rphy
+    - scsi: ses: Fix SAS device detection in enclosure
+
+  * multipath -ll is not showing the disks which are actually multipath
+    (LP: #1718397)
+    - fs: aio: fix the increment of aio-nr and counting against aio-max-nr
+
+  * Support Dell Wireless DW5819/5818 WWAN devices (LP: #1721455)
+    - SAUCE: USB: serial: qcserial: add Dell DW5818, DW5819
+
+  * CVE-2017-10911
+    - xen-blkback: don't leak stack data via response ring
+
+  * implement 'complain mode' in seccomp for developer mode with snaps
+    (LP: #1567597)
+    - seccomp: Provide matching filter for introspection
+    - seccomp: Sysctl to display available actions
+    - seccomp: Operation for checking if an action is available
+    - seccomp: Sysctl to configure actions that are allowed to be logged
+    - seccomp: Selftest for detection of filter flag support
+    - seccomp: Action to log before allowing
+
+  * implement errno action logging in seccomp for strict mode with snaps
+    (LP: #1721676)
+    - seccomp: Provide matching filter for introspection
+    - seccomp: Sysctl to display available actions
+    - seccomp: Operation for checking if an action is available
+    - seccomp: Sysctl to configure actions that are allowed to be logged
+    - seccomp: Selftest for detection of filter flag support
+    - seccomp: Filter flag to log all actions except SECCOMP_RET_ALLOW
+
+  * [Xenial] update OpenNSL kernel modules to 6.5.10 (LP: #1721511)
+    - SAUCE: update OpenNSL kernel modules to 6.5.10
+
+  * Xenial update to 4.4.90 stable release (LP: #1721550)
+    - cifs: release auth_key.response for reconnect.
+    - mac80211: flush hw_roc_start work before cancelling the ROC
+    - KVM: PPC: Book3S: Fix race and leak in kvm_vm_ioctl_create_spapr_tce()
+    - tracing: Fix trace_pipe behavior for instance traces
+    - tracing: Erase irqsoff trace with empty write
+    - md/raid5: fix a race condition in stripe batch
+    - md/raid5: preserve STRIPE_ON_UNPLUG_LIST in break_stripe_batch_list
+    - scsi: scsi_transport_iscsi: fix the issue that iscsi_if_rx doesn't parse
+      nlmsg properly
+    - crypto: talitos - Don't provide setkey for non hmac hashing algs.
+    - crypto: talitos - fix sha224
+    - KEYS: fix writing past end of user-supplied buffer in keyring_read()
+    - KEYS: prevent creating a different user's keyrings
+    - KEYS: prevent KEYCTL_READ on negative key
+    - powerpc/pseries: Fix parent_dn reference leak in add_dt_node()
+    - Fix SMB3.1.1 guest authentication to Samba
+    - SMB: Validate negotiate (to protect against downgrade) even if signing off
+    - SMB3: Don't ignore O_SYNC/O_DSYNC and O_DIRECT flags
+    - vfs: Return -ENXIO for negative SEEK_HOLE / SEEK_DATA offsets
+    - nl80211: check for the required netlink attributes presence
+    - bsg-lib: don't free job in bsg_prepare_job
+    - seccomp: fix the usage of get/put_seccomp_filter() in seccomp_get_filter()
+    - arm64: Make sure SPsel is always set
+    - arm64: fault: Route pte translation faults via do_translation_fault
+    - KVM: VMX: Do not BUG() on out-of-bounds guest IRQ
+    - kvm: nVMX: Don't allow L2 to access the hardware CR8
+    - PCI: Fix race condition with driver_override
+    - btrfs: fix NULL pointer dereference from free_reloc_roots()
+    - btrfs: propagate error to btrfs_cmp_data_prepare caller
+    - btrfs: prevent to set invalid default subvolid
+    - x86/fpu: Don't let userspace set bogus xcomp_bv
+    - gfs2: Fix debugfs glocks dump
+    - timer/sysclt: Restrict timer migration sysctl values to 0 and 1
+    - KVM: VMX: do not change SN bit in vmx_update_pi_irte()
+    - KVM: VMX: remove WARN_ON_ONCE in kvm_vcpu_trigger_posted_interrupt
+    - cxl: Fix driver use count
+    - dmaengine: mmp-pdma: add number of requestors
+    - ARM: pxa: add the number of DMA requestor lines
+    - ARM: pxa: fix the number of DMA requestor lines
+    - KVM: VMX: use cmpxchg64
+    - video: fbdev: aty: do not leak uninitialized padding in clk to userspace
+    - swiotlb-xen: implement xen_swiotlb_dma_mmap callback
+    - fix xen_swiotlb_dma_mmap prototype
+    - Linux 4.4.90
+
+  * Xenial update to 4.4.89 stable release (LP: #1721477)
+    - ipv6: accept 64k - 1 packet length in ip6_find_1stfragopt()
+    - ipv6: add rcu grace period before freeing fib6_node
+    - ipv6: fix sparse warning on rt6i_node
+    - qlge: avoid memcpy buffer overflow
+    - Revert "net: phy: Correctly process PHY_HALTED in phy_stop_machine()"
+    - Revert "net: use lib/percpu_counter API for fragmentation mem accounting"
+    - Revert "net: fix percpu memory leaks"
+    - gianfar: Fix Tx flow control deactivation
+    - ipv6: fix memory leak with multiple tables during netns destruction
+    - ipv6: fix typo in fib6_net_exit()
+    - f2fs: check hot_data for roll-forward recovery
+    - x86/fsgsbase/64: Report FSBASE and GSBASE correctly in core dumps
+    - md/raid5: release/flush io in raid5_do_work()
+    - nfsd: Fix general protection fault in release_lock_stateid()
+    - mm: prevent double decrease of nr_reserved_highatomic
+    - tty: improve tty_insert_flip_char() fast path
+    - tty: improve tty_insert_flip_char() slow path
+    - tty: fix __tty_insert_flip_char regression
+    - Input: i8042 - add Gigabyte P57 to the keyboard reset table
+    - MIPS: math-emu: <MAX|MAXA|MIN|MINA>.<D|S>: Fix quiet NaN propagation
+    - MIPS: math-emu: <MAX|MAXA|MIN|MINA>.<D|S>: Fix cases of both inputs zero
+    - MIPS: math-emu: <MAX|MIN>.<D|S>: Fix cases of both inputs negative
+    - MIPS: math-emu: <MAXA|MINA>.<D|S>: Fix cases of input values with opposite
+      signs
+    - MIPS: math-emu: <MAXA|MINA>.<D|S>: Fix cases of both infinite inputs
+    - MIPS: math-emu: MINA.<D|S>: Fix some cases of infinity and zero inputs
+    - crypto: AF_ALG - remove SGL terminator indicator when chaining
+    - ext4: fix incorrect quotaoff if the quota feature is enabled
+    - ext4: fix quota inconsistency during orphan cleanup for read-only mounts
+    - powerpc: Fix DAR reporting when alignment handler faults
+    - block: Relax a check in blk_start_queue()
+    - md/bitmap: disable bitmap_resize for file-backed bitmaps.
+    - skd: Avoid that module unloading triggers a use-after-free
+    - skd: Submit requests to firmware before triggering the doorbell
+    - scsi: zfcp: fix queuecommand for scsi_eh commands when DIX enabled
+    - scsi: zfcp: add handling for FCP_RESID_OVER to the fcp ingress path
+    - scsi: zfcp: fix capping of unsuccessful GPN_FT SAN response trace records
+    - scsi: zfcp: fix passing fsf_req to SCSI trace on TMF to correlate with HBA
+    - scsi: zfcp: fix missing trace records for early returns in TMF eh handlers
+    - scsi: zfcp: fix payload with full FCP_RSP IU in SCSI trace records
+    - scsi: zfcp: trace HBA FSF response by default on dismiss or timedout late
+      response
+    - scsi: zfcp: trace high part of "new" 64 bit SCSI LUN
+    - scsi: megaraid_sas: Check valid aen class range to avoid kernel panic
+    - scsi: megaraid_sas: Return pended IOCTLs with cmd_status
+      MFI_STAT_WRONG_STATE in case adapter is dead
+    - scsi: storvsc: fix memory leak on ring buffer busy
+    - scsi: sg: remove 'save_scat_len'
+    - scsi: sg: use standard lists for sg_requests
+    - scsi: sg: off by one in sg_ioctl()
+    - scsi: sg: factor out sg_fill_request_table()
+    - scsi: sg: fixup infoleak when using SG_GET_REQUEST_TABLE
+    - scsi: qla2xxx: Fix an integer overflow in sysfs code
+    - ftrace: Fix selftest goto location on error
+    - tracing: Apply trace_clock changes to instance max buffer
+    - ARC: Re-enable MMU upon Machine Check exception
+    - PCI: shpchp: Enable bridge bus mastering if MSI is enabled
+    - media: v4l2-compat-ioctl32: Fix timespec conversion
+    - media: uvcvideo: Prevent heap overflow when accessing mapped controls
+    - bcache: initialize dirty stripes in flash_dev_run()
+    - bcache: Fix leak of bdev reference
+    - bcache: do not subtract sectors_to_gc for bypassed IO
+    - bcache: correct cache_dirty_target in __update_writeback_rate()
+    - bcache: Correct return value for sysfs attach errors
+    - bcache: fix for gc and write-back race
+    - bcache: fix bch_hprint crash and improve output
+    - ftrace: Fix memleak when unregistering dynamic ops when tracing disabled
+    - Linux 4.4.89
+
+  * ETPS/2 Elantech Touchpad inconsistently detected (Gigabyte P57W laptop)
+    (LP: #1594214)
+    - Input: i8042 - add Gigabyte P57 to the keyboard reset table
+
+  * Xenial update to 4.4.88 stable release (LP: #1718195)
+    - usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard
+    - USB: serial: option: add support for D-Link DWM-157 C1
+    - usb: Add device quirk for Logitech HD Pro Webcam C920-C
+    - usb:xhci:Fix regression when ATI chipsets detected
+    - USB: core: Avoid race of async_completed() w/ usbdev_release()
+    - staging/rts5208: fix incorrect shift to extract upper nybble
+    - driver core: bus: Fix a potential double free
+    - intel_th: pci: Add Cannon Lake PCH-H support
+    - intel_th: pci: Add Cannon Lake PCH-LP support
+    - ath10k: fix memory leak in rx ring buffer allocation
+    - rtlwifi: rtl_pci_probe: Fix fail path of _rtl_pci_find_adapter
+    - Bluetooth: Add support of 13d3:3494 RTL8723BE device
+    - dlm: avoid double-free on error path in dlm_device_{register,unregister}
+    - mwifiex: correct channel stat buffer overflows
+    - drm/nouveau/pci/msi: disable MSI on big-endian platforms by default
+    - workqueue: Fix flag collision
+    - cs5536: add support for IDE controller variant
+    - scsi: sg: protect against races between mmap() and SG_SET_RESERVED_SIZE
+    - scsi: sg: recheck MMAP_IO request length with lock held
+    - drm: adv7511: really enable interrupts for EDID detection
+    - drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled
+    - drm/bridge: adv7511: Use work_struct to defer hotplug handing to out of irq
+      context
+    - drm/bridge: adv7511: Switch to using drm_kms_helper_hotplug_event()
+    - drm/bridge: adv7511: Re-write the i2c address before EDID probing
+    - btrfs: resume qgroup rescan on rw remount
+    - locktorture: Fix potential memory leak with rw lock test
+    - ALSA: msnd: Optimize / harden DSP and MIDI loops
+    - ARM: 8692/1: mm: abort uaccess retries upon fatal signal
+    - NFS: Fix 2 use after free issues in the I/O code
+    - xfs: XFS_IS_REALTIME_INODE() should be false if no rt device present
+    - Linux 4.4.88
+
+  * Kernel has troule recognizing Corsair Strafe RGB keyboard (LP: #1678477)
+    - usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 10 Oct 2017 08:52:24 -0300
+
+linux (4.4.0-97.120) xenial; urgency=low
+
+  * linux: 4.4.0-97.120 -proposed tracker (LP: #1718149)
+
+  * blk-mq: possible deadlock on CPU hot(un)plug (LP: #1670634)
+    - [Config] s390x -- disable CONFIG_{DM, SCSI}_MQ_DEFAULT
+
+  * Xenial update to 4.4.87 stable release (LP: #1715678)
+    - irqchip: mips-gic: SYNC after enabling GIC region
+    - i2c: ismt: Don't duplicate the receive length for block reads
+    - i2c: ismt: Return EMSGSIZE for block reads with bogus length
+    - ceph: fix readpage from fscache
+    - cpumask: fix spurious cpumask_of_node() on non-NUMA multi-node configs
+    - cpuset: Fix incorrect memory_pressure control file mapping
+    - alpha: uapi: Add support for __SANE_USERSPACE_TYPES__
+    - CIFS: remove endian related sparse warning
+    - wl1251: add a missing spin_lock_init()
+    - xfrm: policy: check policy direction value
+    - drm/ttm: Fix accounting error when fail to get pages for pool
+    - kvm: arm/arm64: Fix race in resetting stage2 PGD
+    - kvm: arm/arm64: Force reading uncached stage2 PGD
+    - epoll: fix race between ep_poll_callback(POLLFREE) and ep_free()/ep_remove()
+    - crypto: algif_skcipher - only call put_page on referenced and used pages
+    - Linux 4.4.87
+
+  * Xenial update to 4.4.86 stable release (LP: #1715430)
+    - scsi: isci: avoid array subscript warning
+    - ALSA: au88x0: Fix zero clear of stream->resources
+    - btrfs: remove duplicate const specifier
+    - i2c: jz4780: drop superfluous init
+    - gcov: add support for gcc version >= 6
+    - gcov: support GCC 7.1
+    - lightnvm: initialize ppa_addr in dev_to_generic_addr()
+    - p54: memset(0) whole array
+    - lpfc: Fix Device discovery failures during switch reboot test.
+    - arm64: mm: abort uaccess retries upon fatal signal
+    - x86/io: Add "memory" clobber to insb/insw/insl/outsb/outsw/outsl
+    - arm64: fpsimd: Prevent registers leaking across exec
+    - scsi: sg: protect accesses to 'reserved' page array
+    - scsi: sg: reset 'res_in_use' after unlinking reserved array
+    - drm/i915: fix compiler warning in drivers/gpu/drm/i915/intel_uncore.c
+    - Linux 4.4.86
+
+  * Xenial update to 4.4.85 stable release (LP: #1714298)
+    - af_key: do not use GFP_KERNEL in atomic contexts
+    - dccp: purge write queue in dccp_destroy_sock()
+    - dccp: defer ccid_hc_tx_delete() at dismantle time
+    - ipv4: fix NULL dereference in free_fib_info_rcu()
+    - net_sched/sfq: update hierarchical backlog when drop packet
+    - ipv4: better IP_MAX_MTU enforcement
+    - sctp: fully initialize the IPv6 address in sctp_v6_to_addr()
+    - tipc: fix use-after-free
+    - ipv6: reset fn->rr_ptr when replacing route
+    - ipv6: repair fib6 tree in failure case
+    - tcp: when rearming RTO, if RTO time is in past then fire RTO ASAP
+    - irda: do not leak initialized list.dev to userspace
+    - net: sched: fix NULL pointer dereference when action calls some targets
+    - net_sched: fix order of queue length updates in qdisc_replace()
+    - mei: me: add broxton pci device ids
+    - mei: me: add lewisburg device ids
+    - Input: trackpoint - add new trackpoint firmware ID
+    - Input: elan_i2c - add ELAN0602 ACPI ID to support Lenovo Yoga310
+    - ALSA: core: Fix unexpected error at replacing user TLV
+    - ALSA: hda - Add stereo mic quirk for Lenovo G50-70 (17aa:3978)
+    - ARCv2: PAE40: Explicitly set MSB counterpart of SLC region ops addresses
+    - i2c: designware: Fix system suspend
+    - drm: Release driver tracking before making the object available again
+    - drm/atomic: If the atomic check fails, return its value first
+    - drm: rcar-du: lvds: Fix PLL frequency-related configuration
+    - drm: rcar-du: lvds: Rename PLLEN bit to PLLON
+    - drm: rcar-du: Fix crash in encoder failure error path
+    - drm: rcar-du: Fix display timing controller parameter
+    - drm: rcar-du: Fix H/V sync signal polarity configuration
+    - tracing: Fix freeing of filter in create_filter() when set_str is false
+    - cifs: Fix df output for users with quota limits
+    - cifs: return ENAMETOOLONG for overlong names in cifs_open()/cifs_lookup()
+    - nfsd: Limit end of page list when decoding NFSv4 WRITE
+    - perf/core: Fix group {cpu,task} validation
+    - Bluetooth: hidp: fix possible might sleep error in hidp_session_thread
+    - Bluetooth: cmtp: fix possible might sleep error in cmtp_session
+    - Bluetooth: bnep: fix possible might sleep error in bnep_session
+    - binder: use group leader instead of open thread
+    - binder: Use wake up hint for synchronous transactions.
+    - ANDROID: binder: fix proc->tsk check.
+    - iio: imu: adis16480: Fix acceleration scale factor for adis16480
+    - iio: hid-sensor-trigger: Fix the race with user space powering up sensors
+    - staging: rtl8188eu: add RNX-N150NUB support
+    - ASoC: simple-card: don't fail if sysclk setting is not supported
+    - ASoC: rsnd: disable SRC.out only when stop timing
+    - ASoC: rsnd: avoid pointless loop in rsnd_mod_interrupt()
+    - ASoC: rsnd: Add missing initialization of ADG req_rate
+    - ASoC: rsnd: ssi: 24bit data needs right-aligned settings
+    - ASoC: rsnd: don't call update callback if it was NULL
+    - ntb_transport: fix qp count bug
+    - ntb_transport: fix bug calculating num_qps_mw
+    - ACPI: ioapic: Clear on-stack resource before using it
+    - ACPI / APEI: Add missing synchronize_rcu() on NOTIFY_SCI removal
+    - Linux 4.4.85
+
+  * Xenial update to 4.4.84 stable release (LP: #1713729)
+    - audit: Fix use after free in audit_remove_watch_rule()
+    - parisc: pci memory bar assignment fails with 64bit kernels on dino/cujo
+    - crypto: x86/sha1 - Fix reads beyond the number of blocks passed
+    - Input: elan_i2c - Add antoher Lenovo ACPI ID for upcoming Lenovo NB
+    - ALSA: seq: 2nd attempt at fixing race creating a queue
+    - Revert "UBUNTU: SAUCE: (no-up) ALSA: usb-audio: Add quirk for sennheiser
+      officerunner"
+    - ALSA: usb-audio: Apply sample rate quirk to Sennheiser headset
+    - ALSA: usb-audio: Add mute TLV for playback volumes on C-Media devices
+    - mm/mempolicy: fix use after free when calling get_mempolicy
+    - xen: fix bio vec merging
+    - x86/asm/64: Clear AC on NMI entries
+    - irqchip/atmel-aic: Fix unbalanced of_node_put() in aic_common_irq_fixup()
+    - irqchip/atmel-aic: Fix unbalanced refcount in aic_common_rtc_irq_fixup()
+    - Sanitize 'move_pages()' permission checks
+    - pids: make task_tgid_nr_ns() safe
+    - perf/x86: Fix LBR related crashes on Intel Atom
+    - usb: optimize acpi companion search for usb port devices
+    - usb: qmi_wwan: add D-Link DWM-222 device ID
+    - Linux 4.4.84
+
+  * Intel i40e PF reset due to incorrect MDD detection (LP: #1713553)
+    - i40e: Limit TX descriptor count in cases where frag size is greater than 16K
+
+  * Neighbour confirmation broken, breaks ARP cache aging (LP: #1715812)
+    - sock: add sk_dst_pending_confirm flag
+    - net: add dst_pending_confirm flag to skbuff
+    - sctp: add dst_pending_confirm flag
+    - tcp: replace dst_confirm with sk_dst_confirm
+    - net: add confirm_neigh method to dst_ops
+    - net: use dst_confirm_neigh for UDP, RAW, ICMP, L2TP
+    - net: pending_confirm is not used anymore
+
+  * CVE-2017-14106
+    - tcp: initialize rcv_mss to TCP_MIN_MSS instead of 0
+
+  * [CIFS] Fix maximum SMB2 header size (LP: #1713884)
+    - CIFS: Fix maximum SMB2 header size
+
+  * Middle button of trackpoint doesn't work (LP: #1715271)
+    - Input: trackpoint - assume 3 buttons when buttons detection fails
+
+  * kernel BUG at /build/linux-lts-xenial-_hWfOZ/linux-lts-
+    xenial-4.4.0/security/apparmor/include/context.h:69! (LP: #1626984)
+    - SAUCE: fix oops when disabled and module parameters, are accessed
+
+  * Touchpad not detected (LP: #1708852)
+    - Input: elan_i2c - add ELAN0608 to the ACPI table
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 19 Sep 2017 17:55:11 +0200
+
+linux (4.4.0-96.119) xenial; urgency=low
+
+  * linux: 4.4.0-96.119 -proposed tracker (LP: #1716613)
+
+  * kernel panic -not syncing: Fatal exception: panic_on_oops (LP: #1708399)
+    - s390/mm: no local TLB flush for clearing-by-ASCE IDTE
+    - SAUCE: s390/mm: fix local TLB flushing vs. detach of an mm address space
+    - SAUCE: s390/mm: fix race on mm->context.flush_mm
+
+  * CVE-2017-1000251
+    - Bluetooth: Properly check L2CAP config option output buffer length
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 12 Sep 2017 15:40:01 +0200
+
+linux (4.4.0-95.118) xenial; urgency=low
+
+  * linux: 4.4.0-95.118 -proposed tracker (LP: #1715651)
+
+  * Xenial update to 4.4.78 stable release broke Address Sanitizer
+    (LP: #1715636)
+    - mm: revert x86_64 and arm64 ELF_ET_DYN_BASE base changes
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 07 Sep 2017 17:26:15 +0200
+
+linux (4.4.0-94.117) xenial; urgency=low
+
+  * linux: 4.4.0-94.117 -proposed tracker (LP: #1713462)
+
+  * mwifiex causes kernel oops when AP mode is enabled (LP: #1712746)
+    - SAUCE: net/wireless: do not dereference invalid pointer
+    - SAUCE: mwifiex: do not dereference invalid pointer
+
+  * Backport more recent Broadcom bnxt_en driver (LP: #1711056)
+    - SAUCE: bnxt_en_bpo: Import bnxt_en driver version 1.8.1
+    - SAUCE: bnxt_en_bpo: Drop distro out-of-tree detection logic
+    - SAUCE: bnxt_en_bpo: Remove unnecessary compile flags
+    - SAUCE: bnxt_en_bpo: Move config settings to Kconfig
+    - SAUCE: bnxt_en_bpo: Remove PCI_IDs handled by the regular driver
+    - SAUCE: bnxt_en_bpo: Rename the backport driver to bnxt_en_bpo
+    - bnxt_en_bpo: [Config] Enable CONFIG_BNXT_BPO=m
+
+  * HID: multitouch: Support ALPS PTP Stick and Touchpad devices (LP: #1712481)
+    - HID: multitouch: Support PTP Stick and Touchpad device
+    - SAUCE: HID: multitouch: Support ALPS PTP stick with pid 0x120A
+
+  * igb: Support using Broadcom 54616 as PHY (LP: #1712024)
+    - SAUCE: igb: add support for using Broadcom 54616 as PHY
+
+  * IPR driver causes multipath to fail paths/stuck IO on Medium Errors
+    (LP: #1682644)
+    - scsi: ipr: do not set DID_PASSTHROUGH on CHECK CONDITION
+
+  * accessing /dev/hvc1 with stress-ng on Ubuntu xenial causes crash
+    (LP: #1711401)
+    - tty/hvc: Use IRQF_SHARED for OPAL hvc consoles
+
+  * memory-hotplug test needs to be fixed (LP: #1710868)
+    - selftests: typo correction for memory-hotplug test
+    - selftests: check hot-pluggagble memory for memory-hotplug test
+    - selftests: check percentage range for memory-hotplug test
+    - selftests: add missing test name in memory-hotplug test
+    - selftests: fix memory-hotplug test
+
+  * HP lt4132 LTE/HSPA+ 4G Module (03f0:a31d) does not work (LP: #1707643)
+    - net: cdc_mbim: apply "NDP to end" quirk to HP lt4132
+
+  * Migrating KSM page causes the VM lock up as the KSM page merging list is too
+    large (LP: #1680513)
+    - ksm: introduce ksm_max_page_sharing per page deduplication limit
+    - ksm: fix use after free with merge_across_nodes = 0
+    - ksm: cleanup stable_node chain collapse case
+    - ksm: swap the two output parameters of chain/chain_prune
+    - ksm: optimize refile of stable_node_dup at the head of the chain
+
+  * sort ABI files with C.UTF-8 locale (LP: #1712345)
+    - [Packaging] sort ABI files with C.UTF-8 locale
+
+  * Include Broadcom GPL modules in Xenial Kernel (LP: #1665783)
+    - [Config] OpenNSL Kconfig/Makefile
+    - Import OpenNSL v3.1.0.17
+    - [Config] CONFIG_OPENNSL=y for amd64
+    - OpenNSL: Enable Kconfig and build
+    - SAUCE: opennsl: add proper CFLAGS
+
+  * Xenial update to 4.4.83 stable release (LP: #1711557)
+    - cpuset: fix a deadlock due to incomplete patching of cpusets_enabled()
+    - mm: ratelimit PFNs busy info message
+    - iscsi-target: fix memory leak in iscsit_setup_text_cmd()
+    - iscsi-target: Fix iscsi_np reset hung task during parallel delete
+    - fuse: initialize the flock flag in fuse_file on allocation
+    - nfs/flexfiles: fix leak of nfs4_ff_ds_version arrays
+    - USB: serial: option: add D-Link DWM-222 device ID
+    - USB: serial: cp210x: add support for Qivicon USB ZigBee dongle
+    - USB: serial: pl2303: add new ATEN device id
+    - usb: musb: fix tx fifo flush handling again
+    - USB: hcd: Mark secondary HCD as dead if the primary one died
+    - staging:iio:resolver:ad2s1210 fix negative IIO_ANGL_VEL read
+    - iio: accel: bmc150: Always restore device to normal mode after suspend-
+      resume
+    - iio: light: tsl2563: use correct event code
+    - uas: Add US_FL_IGNORE_RESIDUE for Initio Corporation INIC-3069
+    - USB: Check for dropped connection before switching to full speed
+    - usb: core: unlink urbs from the tail of the endpoint's urb_list
+    - usb: quirks: Add no-lpm quirk for Moshi USB to Ethernet Adapter
+    - usb:xhci:Add quirk for Certain failing HP keyboard on reset after resume
+    - iio: adc: vf610_adc: Fix VALT selection value for REFSEL bits
+    - pnfs/blocklayout: require 64-bit sector_t
+    - pinctrl: sunxi: add a missing function of A10/A20 pinctrl driver
+    - pinctrl: samsung: Remove bogus irq_[un]mask from resource management
+    - Linux 4.4.83
+
+  * Xenial update to 4.4.82 stable release (LP: #1711535)
+    - tcp: avoid setting cwnd to invalid ssthresh after cwnd reduction states
+    - net: fix keepalive code vs TCP_FASTOPEN_CONNECT
+    - bpf, s390: fix jit branch offset related to ldimm64
+    - net: sched: set xt_tgchk_param par.nft_compat as 0 in ipt_init_target
+    - tcp: fastopen: tcp_connect() must refresh the route
+    - net: avoid skb_warn_bad_offload false positives on UFO
+    - sparc64: Prevent perf from running during super critical sections
+    - KVM: arm/arm64: Handle hva aging while destroying the vm
+    - mm/mempool: avoid KASAN marking mempool poison checks as use-after-free
+    - Linux 4.4.82
+
+  * Xenial update to 4.4.81 stable release (LP: #1711526)
+    - libata: array underflow in ata_find_dev()
+    - workqueue: restore WQ_UNBOUND/max_active==1 to be ordered
+    - ALSA: hda - Fix speaker output from VAIO VPCL14M1R
+    - ASoC: do not close shared backend dailink
+    - KVM: async_pf: make rcu irq exit if not triggered from idle task
+    - mm/page_alloc: Remove kernel address exposure in free_reserved_area()
+    - ext4: fix SEEK_HOLE/SEEK_DATA for blocksize < pagesize
+    - ext4: fix overflow caused by missing cast in ext4_resize_fs()
+    - ARM: dts: armada-38x: Fix irq type for pca955
+    - media: platform: davinci: return -EINVAL for VPFE_CMD_S_CCDC_RAW_PARAMS
+      ioctl
+    - target: Avoid mappedlun symlink creation during lun shutdown
+    - iscsi-target: Always wait for kthread_should_stop() before kthread exit
+    - iscsi-target: Fix early sk_data_ready LOGIN_FLAGS_READY race
+    - iscsi-target: Fix initial login PDU asynchronous socket close OOPs
+    - iscsi-target: Fix delayed logout processing greater than
+      SECONDS_FOR_LOGOUT_COMP
+    - iser-target: Avoid isert_conn->cm_id dereference in isert_login_recv_done
+    - mm, mprotect: flush TLB if potentially racing with a parallel reclaim
+      leaving stale TLB entries
+    - media: lirc: LIRC_GET_REC_RESOLUTION should return microseconds
+    - f2fs: sanity check checkpoint segno and blkoff
+    - drm: rcar-du: fix backport bug
+    - saa7164: fix double fetch PCIe access condition
+    - ipv4: ipv6: initialize treq->txhash in cookie_v[46]_check()
+    - net: Zero terminate ifr_name in dev_ifname().
+    - ipv6: avoid overflow of offset in ip6_find_1stfragopt
+    - ipv4: initialize fib_trie prior to register_netdev_notifier call.
+    - rtnetlink: allocate more memory for dev_set_mac_address()
+    - mcs7780: Fix initialization when CONFIG_VMAP_STACK is enabled
+    - openvswitch: fix potential out of bound access in parse_ct
+    - packet: fix use-after-free in prb_retire_rx_blk_timer_expired()
+    - ipv6: Don't increase IPSTATS_MIB_FRAGFAILS twice in ip6_fragment()
+    - net: ethernet: nb8800: Handle all 4 RGMII modes identically
+    - dccp: fix a memleak that dccp_ipv6 doesn't put reqsk properly
+    - dccp: fix a memleak that dccp_ipv4 doesn't put reqsk properly
+    - dccp: fix a memleak for dccp_feat_init err process
+    - sctp: don't dereference ptr before leaving _sctp_walk_{params, errors}()
+    - sctp: fix the check for _sctp_walk_params and _sctp_walk_errors
+    - net/mlx5: Fix command bad flow on command entry allocation failure
+    - net: phy: Correctly process PHY_HALTED in phy_stop_machine()
+    - net: phy: Fix PHY unbind crash
+    - xen-netback: correctly schedule rate-limited queues
+    - sparc64: Measure receiver forward progress to avoid send mondo timeout
+    - wext: handle NULL extra data in iwe_stream_add_point better
+    - sh_eth: R8A7740 supports packet shecksumming
+    - net: phy: dp83867: fix irq generation
+    - tg3: Fix race condition in tg3_get_stats64().
+    - x86/boot: Add missing declaration of string functions
+    - phy state machine: failsafe leave invalid RUNNING state
+    - scsi: qla2xxx: Get mutex lock before checking optrom_state
+    - drm/virtio: fix framebuffer sparse warning
+    - virtio_blk: fix panic in initialization error path
+    - ARM: 8632/1: ftrace: fix syscall name matching
+    - mm, slab: make sure that KMALLOC_MAX_SIZE will fit into MAX_ORDER
+    - lib/Kconfig.debug: fix frv build failure
+    - signal: protect SIGNAL_UNKILLABLE from unintentional clearing.
+    - mm: don't dereference struct page fields of invalid pages
+    - workqueue: implicit ordered attribute should be overridable
+    - Linux 4.4.81
+
+  * Xenial update to 4.4.80 stable release (LP: #1710646)
+    - af_key: Add lock to key dump
+    - pstore: Make spinlock per zone instead of global
+    - powerpc/pseries: Fix of_node_put() underflow during reconfig remove
+    - crypto: authencesn - Fix digest_null crash
+    - md/raid5: add thread_group worker async_tx_issue_pending_all
+    - drm/vmwgfx: Fix gcc-7.1.1 warning
+    - drm/nouveau/bar/gf100: fix access to upper half of BAR2
+    - KVM: PPC: Book3S HV: Context-switch EBB registers properly
+    - KVM: PPC: Book3S HV: Restore critical SPRs to host values on guest exit
+    - KVM: PPC: Book3S HV: Reload HTM registers explicitly
+    - KVM: PPC: Book3S HV: Save/restore host values of debug registers
+    - Revert "powerpc/numa: Fix percpu allocations to be NUMA aware"
+    - Staging: comedi: comedi_fops: Avoid orphaned proc entry
+    - drm/rcar: Nuke preclose hook
+    - drm: rcar-du: Perform initialization/cleanup at probe/remove time
+    - drm: rcar-du: Simplify and fix probe error handling
+    - perf intel-pt: Fix ip compression
+    - perf intel-pt: Fix last_ip usage
+    - perf intel-pt: Use FUP always when scanning for an IP
+    - perf intel-pt: Ensure never to set 'last_ip' when packet 'count' is zero
+    - xfs: don't BUG() on mixed direct and mapped I/O
+    - nfc: fdp: fix NULL pointer dereference
+    - net: phy: Do not perform software reset for Generic PHY
+    - isdn: Fix a sleep-in-atomic bug
+    - isdn/i4l: fix buffer overflow
+    - ath10k: fix null deref on wmi-tlv when trying spectral scan
+    - wil6210: fix deadlock when using fw_no_recovery option
+    - mailbox: always wait in mbox_send_message for blocking Tx mode
+    - mailbox: skip complete wait event if timer expired
+    - mailbox: handle empty message in tx_tick
+    - mpt3sas: Don't overreach ioc->reply_post[] during initialization
+    - kaweth: fix firmware download
+    - kaweth: fix oops upon failed memory allocation
+    - sched/cgroup: Move sched_online_group() back into css_online() to fix crash
+    - PM / Domains: defer dev_pm_domain_set() until genpd->attach_dev succeeds if
+      present
+    - RDMA/uverbs: Fix the check for port number
+    - libnvdimm, btt: fix btt_rw_page not returning errors
+    - ipmi/watchdog: fix watchdog timeout set on reboot
+    - v4l: s5c73m3: fix negation operator
+    - pstore: Allow prz to control need for locking
+    - pstore: Correctly initialize spinlock and flags
+    - pstore: Use dynamic spinlock initializer
+    - net: skb_needs_check() accepts CHECKSUM_NONE for tx
+    - sched/cputime: Fix prev steal time accouting during CPU hotplug
+    - xen/blkback: don't free be structure too early
+    - xen/blkback: don't use xen_blkif_get() in xen-blkback kthread
+    - tpm: fix a kernel memory leak in tpm-sysfs.c
+    - tpm: Replace device number bitmap with IDR
+    - x86/mce/AMD: Make the init code more robust
+    - r8169: add support for RTL8168 series add-on card.
+    - ARM: dts: n900: Mark eMMC slot with no-sdio and no-sd flags
+    - net/mlx4: Remove BUG_ON from ICM allocation routine
+    - drm/msm: Ensure that the hardware write pointer is valid
+    - drm/msm: Verify that MSM_SUBMIT_BO_FLAGS are set
+    - vfio-pci: use 32-bit comparisons for register address for gcc-4.5
+    - irqchip/keystone: Fix "scheduling while atomic" on rt
+    - ASoC: tlv320aic3x: Mark the RESET register as volatile
+    - spi: dw: Make debugfs name unique between instances
+    - ASoC: nau8825: fix invalid configuration in Pre-Scalar of FLL
+    - irqchip/mxs: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND
+    - openrisc: Add _text symbol to fix ksym build error
+    - dmaengine: ioatdma: Add Skylake PCI Dev ID
+    - dmaengine: ioatdma: workaround SKX ioatdma version
+    - dmaengine: ti-dma-crossbar: Add some 'of_node_put()' in error path.
+    - ARM64: zynqmp: Fix W=1 dtc 1.4 warnings
+    - ARM64: zynqmp: Fix i2c node's compatible string
+    - ARM: s3c2410_defconfig: Fix invalid values for NF_CT_PROTO_*
+    - ACPI / scan: Prefer devices without _HID/_CID for _ADR matching
+    - usb: gadget: Fix copy/pasted error message
+    - Btrfs: adjust outstanding_extents counter properly when dio write is split
+    - tools lib traceevent: Fix prev/next_prio for deadline tasks
+    - xfrm: Don't use sk_family for socket policy lookups
+    - perf tools: Install tools/lib/traceevent plugins with install-bin
+    - perf symbols: Robustify reading of build-id from sysfs
+    - video: fbdev: cobalt_lcdfb: Handle return NULL error from devm_ioremap
+    - vfio-pci: Handle error from pci_iomap
+    - arm64: mm: fix show_pte KERN_CONT fallout
+    - nvmem: imx-ocotp: Fix wrong register size
+    - sh_eth: enable RX descriptor word 0 shift on SH7734
+    - ALSA: usb-audio: test EP_FLAG_RUNNING at urb completion
+    - HID: ignore Petzl USB headlamp
+    - scsi: fnic: Avoid sending reset to firmware when another reset is in
+      progress
+    - scsi: snic: Return error code on memory allocation failure
+    - ASoC: dpcm: Avoid putting stream state to STOP when FE stream is paused
+    - Linux 4.4.80
+
+  * Please only recommend or suggest initramfs-tools | linux-initramfs-tool for
+    kernels able to boot without initramfs (LP: #1700972)
+    - [Debian] Don't depend on initramfs-tools
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 28 Aug 2017 17:07:08 +0200
+
+linux (4.4.0-93.116) xenial; urgency=low
+
+  * linux: 4.4.0-93.116 -proposed tracker (LP: #1709296)
+
+  * Creating conntrack entry failure with kernel 4.4.0-89 (LP: #1709032)
+    - Revert "Revert "netfilter: synproxy: fix conntrackd interaction""
+    - netfilter: nf_ct_ext: fix possible panic after nf_ct_extend_unregister
+
+  * CVE-2017-1000112
+    - Revert "udp: consistently apply ufo or fragmentation"
+    - udp: consistently apply ufo or fragmentation
+
+  * CVE-2017-1000111
+    - Revert "net-packet: fix race in packet_set_ring on PACKET_RESERVE"
+    - packet: fix tp_reserve race in packet_set_ring
+
+  * kernel BUG at [tty_ldisc_reinit] mm/slub.c! (LP: #1709126)
+    - tty: Simplify tty_set_ldisc() exit handling
+    - tty: Reset c_line from driver's init_termios
+    - tty: Handle NULL tty->ldisc
+    - tty: Move tty_ldisc_kill()
+    - tty: Use 'disc' for line discipline index name
+    - tty: Refactor tty_ldisc_reinit() for reuse
+    - tty: Destroy ldisc instance on hangup
+
+  * atheros bt failed after S3 (LP: #1706833)
+    - SAUCE: Bluetooth: Make request workqueue freezable
+
+  * The Precision Touchpad(PTP) button sends incorrect event code (LP: #1708372)
+    - HID: multitouch: handle external buttons for Precision Touchpads
+
+  * Set CONFIG_SATA_HIGHBANK=y on armhf (LP: #1703430)
+    - [Config] CONFIG_SATA_HIGHBANK=y
+
+  * xfs slab objects (memory) leak when xfs shutdown is called (LP: #1706132)
+    - xfs: fix xfs_log_ticket leak in xfs_end_io() after fs shutdown
+
+  * Adt tests of src:linux time out often on armhf lxc containers (LP: #1705495)
+    - [Packaging] tests -- reduce rebuild test to one flavour
+
+  * CVE-2017-7495
+    - ext4: fix data exposure after a crash
+
+  * ubuntu/rsi driver downlink wifi throughput drops to 5-6 Mbps when BT
+    keyboard is connected (LP: #1706991)
+    - SAUCE: Redpine: enable power save by default for coex mode
+    - SAUCE: Redpine: uapsd configuration changes
+
+  * [Hyper-V] hv_netvsc: Exclude non-TCP port numbers from vRSS hashing
+    (LP: #1690174)
+    - hv_netvsc: Exclude non-TCP port numbers from vRSS hashing
+
+  * ath10k doesn't report full RSSI information (LP: #1706531)
+    - ath10k: add per chain RSSI reporting
+
+  * ideapad_laptop don't support v310-14isk (LP: #1705378)
+    - platform/x86: ideapad-laptop: Add several models to no_hw_rfkill
+
+  * [8087:0a2b] Failed to load bluetooth firmware(might affect some other Intel
+    bt devices) (LP: #1705633)
+    - Bluetooth: btintel: Create common Intel Version Read function
+    - Bluetooth: Use switch statement for Intel hardware variants
+    - Bluetooth: Replace constant hw_variant from Intel Bluetooth firmware
+      filename
+    - Bluetooth: hci_intel: Fix firmware file name to use hw_variant
+    - Bluetooth: btintel: Add MODULE_FIRMWARE entries for iBT 3.5 controllers
+
+  * xhci_hcd: ERROR Transfer event TRB DMA ptr not part of current TD ep_index 2
+    comp_code 13 (LP: #1667750)
+    - xhci: Bad Ethernet performance plugged in ASM1042A host
+
+  * OpenPower: Some multipaths temporarily have only a single path
+    (LP: #1696445)
+    - scsi: ses: don't get power status of SES device slot on probe
+
+  * Hotkeys on new Thinkpad systems aren't working (LP: #1705169)
+    - platform/x86: thinkpad_acpi: Adding new hotkey ID for Lenovo thinkpad
+    - platform/x86: thinkpad_acpi: guard generic hotkey case
+    - platform/x86: thinkpad_acpi: add mapping for new hotkeys
+
+  * CVE-2015-7837
+    - SAUCE: (no-up) kexec/uefi: copy secure_boot flag in boot params across kexec
+      reboot
+
+  * misleading kernel warning skb_warn_bad_offload during checksum calculation
+    (LP: #1705447)
+    - net: reduce skb_warn_bad_offload() noise
+
+  * bonding: stack dump when unregistering a netdev (LP: #1704102)
+    - bonding: avoid NETDEV_CHANGEMTU event when unregistering slave
+
+  * Ubuntu 16.04 IOB Error when the Mustang board rebooted (LP: #1693673)
+    - drivers: net: xgene: Fix redundant prefetch buffer cleanup
+
+  * Ubuntu16.04: NVMe 4K+T10 DIF/DIX format returns I/O error on dd with split
+    op (LP: #1689946)
+    - blk-mq: NVMe 512B/4K+T10 DIF/DIX format returns I/O error on dd with split
+      op
+
+  * linux >= 4.2: bonding 802.3ad does not work with 5G, 25G and 50G link speeds
+    (LP: #1697892)
+    - bonding: add 802.3ad support for 100G speeds
+    - bonding: fix 802.3ad aggregator reselection
+    - bonding: add 802.3ad support for 25G speeds
+    - bonding: fix 802.3ad support for 5G and 50G speeds
+
+  * Xenial update to 4.4.79 stable release (LP: #1707233)
+    - disable new gcc-7.1.1 warnings for now
+    - ir-core: fix gcc-7 warning on bool arithmetic
+    - s5p-jpeg: don't return a random width/height
+    - thermal: cpu_cooling: Avoid accessing potentially freed structures
+    - ath9k: fix tx99 use after free
+    - ath9k: fix tx99 bus error
+    - NFC: fix broken device allocation
+    - NFC: nfcmrvl_uart: add missing tty-device sanity check
+    - NFC: nfcmrvl: do not use device-managed resources
+    - NFC: nfcmrvl: use nfc-device for firmware download
+    - NFC: nfcmrvl: fix firmware-management initialisation
+    - nfc: Ensure presence of required attributes in the activate_target handler
+    - nfc: Fix the sockaddr length sanitization in llcp_sock_connect
+    - NFC: Add sockaddr length checks before accessing sa_family in bind handlers
+    - perf intel-pt: Move decoder error setting into one condition
+    - perf intel-pt: Improve sample timestamp
+    - perf intel-pt: Fix missing stack clear
+    - perf intel-pt: Ensure IP is zero when state is INTEL_PT_STATE_NO_IP
+    - perf intel-pt: Clear FUP flag on error
+    - Bluetooth: use constant time memory comparison for secret values
+    - wlcore: fix 64K page support
+    - ASoC: compress: Derive substream from stream based on direction
+    - PM / Domains: Fix unsafe iteration over modified list of device links
+    - PM / Domains: Fix unsafe iteration over modified list of domain providers
+    - scsi: ses: do not add a device to an enclosure if enclosure_add_links()
+      fails.
+    - iscsi-target: Add login_keys_workaround attribute for non RFC initiators
+    - powerpc/64: Fix atomic64_inc_not_zero() to return an int
+    - powerpc: Fix emulation of mcrf in emulate_step()
+    - powerpc: Fix emulation of mfocrf in emulate_step()
+    - powerpc/asm: Mark cr0 as clobbered in mftb()
+    - af_key: Fix sadb_x_ipsecrequest parsing
+    - PCI/PM: Restore the status of PCI devices across hibernation
+    - ipvs: SNAT packet replies only for NATed connections
+    - xhci: fix 20000ms port resume timeout
+    - xhci: Fix NULL pointer dereference when cleaning up streams for removed host
+    - usb: storage: return on error to avoid a null pointer dereference
+    - USB: cdc-acm: add device-id for quirky printer
+    - usb: renesas_usbhs: fix usbhsc_resume() for !USBHSF_RUNTIME_PWCTRL
+    - usb: renesas_usbhs: gadget: disable all eps when the driver stops
+    - md: don't use flush_signals in userspace processes
+    - x86/xen: allow userspace access during hypercalls
+    - cx88: Fix regression in initial video standard setting
+    - Raid5 should update rdev->sectors after reshape
+    - s390/syscalls: Fix out of bounds arguments access
+    - drm/amd/amdgpu: Return error if initiating read out of range on vram
+    - drm/radeon/ci: disable mclk switching for high refresh rates (v2)
+    - drm/radeon: Fix eDP for single-display iMac10,1 (v2)
+    - ipmi: use rcu lock around call to intf->handlers->sender()
+    - ipmi:ssif: Add missing unlock in error branch
+    - f2fs: Don't clear SGID when inheriting ACLs
+    - vfio: Fix group release deadlock
+    - vfio: New external user group/file match
+    - ftrace: Fix uninitialized variable in match_records()
+    - MIPS: Fix mips_atomic_set() retry condition
+    - MIPS: Fix mips_atomic_set() with EVA
+    - MIPS: Negate error syscall return in trace
+    - x86/acpi: Prevent out of bound access caused by broken ACPI tables
+    - x86/ioapic: Pass the correct data to unmask_ioapic_irq()
+    - MIPS: Fix MIPS I ISA /proc/cpuinfo reporting
+    - MIPS: Save static registers before sysmips
+    - MIPS: Actually decode JALX in `__compute_return_epc_for_insn'
+    - MIPS: Fix unaligned PC interpretation in `compute_return_epc'
+    - MIPS: math-emu: Prevent wrong ISA mode instruction emulation
+    - MIPS: Send SIGILL for BPOSGE32 in `__compute_return_epc_for_insn'
+    - MIPS: Rename `sigill_r6' to `sigill_r2r6' in `__compute_return_epc_for_insn'
+    - MIPS: Send SIGILL for linked branches in `__compute_return_epc_for_insn'
+    - MIPS: Fix a typo: s/preset/present/ in r2-to-r6 emulation error message
+    - Input: i8042 - fix crash at boot time
+    - NFS: only invalidate dentrys that are clearly invalid.
+    - udf: Fix deadlock between writeback and udf_setsize()
+    - target: Fix COMPARE_AND_WRITE caw_sem leak during se_cmd quiesce
+    - perf annotate: Fix broken arrow at row 0 connecting jmp instruction to its
+      target
+    - Revert "perf/core: Drop kernel samples even though :u is specified"
+    - staging: rtl8188eu: add TL-WN722N v2 support
+    - ceph: fix race in concurrent readdir
+    - RDMA/core: Initialize port_num in qp_attr
+    - drm/mst: Fix error handling during MST sideband message reception
+    - drm/mst: Avoid dereferencing a NULL mstb in drm_dp_mst_handle_up_req()
+    - drm/mst: Avoid processing partially received up/down message transactions
+    - of: device: Export of_device_{get_modalias, uvent_modalias} to modules
+    - spmi: Include OF based modalias in device uevent
+    - tracing: Fix kmemleak in instance_rmdir
+    - alarmtimer: don't rate limit one-shot timers
+    - Linux 4.4.79
+
+  * Xenial update to 4.4.78 stable release (LP: #1705707)
+    - net_sched: fix error recovery at qdisc creation
+    - net: sched: Fix one possible panic when no destroy callback
+    - net/phy: micrel: configure intterupts after autoneg workaround
+    - ipv6: avoid unregistering inet6_dev for loopback
+    - net: dp83640: Avoid NULL pointer dereference.
+    - tcp: reset sk_rx_dst in tcp_disconnect()
+    - net: prevent sign extension in dev_get_stats()
+    - bpf: prevent leaking pointer via xadd on unpriviledged
+    - net: handle NAPI_GRO_FREE_STOLEN_HEAD case also in napi_frags_finish()
+    - ipv6: dad: don't remove dynamic addresses if link is down
+    - net: ipv6: Compare lwstate in detecting duplicate nexthops
+    - vrf: fix bug_on triggered by rx when destroying a vrf
+    - rds: tcp: use sock_create_lite() to create the accept socket
+    - brcmfmac: fix possible buffer overflow in brcmf_cfg80211_mgmt_tx()
+    - cfg80211: Define nla_policy for NL80211_ATTR_LOCAL_MESH_POWER_MODE
+    - cfg80211: Validate frequencies nested in NL80211_ATTR_SCAN_FREQUENCIES
+    - cfg80211: Check if PMKID attribute is of expected size
+    - irqchip/gic-v3: Fix out-of-bound access in gic_set_affinity
+    - parisc: Report SIGSEGV instead of SIGBUS when running out of stack
+    - parisc: use compat_sys_keyctl()
+    - parisc: DMA API: return error instead of BUG_ON for dma ops on non dma devs
+    - parisc/mm: Ensure IRQs are off in switch_mm()
+    - tools/lib/lockdep: Reduce MAX_LOCK_DEPTH to avoid overflowing lock_chain/:
+      Depth
+    - kernel/extable.c: mark core_kernel_text notrace
+    - mm/list_lru.c: fix list_lru_count_node() to be race free
+    - fs/dcache.c: fix spin lockup issue on nlru->lock
+    - checkpatch: silence perl 5.26.0 unescaped left brace warnings
+    - binfmt_elf: use ELF_ET_DYN_BASE only for PIE
+    - arm: move ELF_ET_DYN_BASE to 4MB
+    - arm64: move ELF_ET_DYN_BASE to 4GB / 4MB
+    - powerpc: move ELF_ET_DYN_BASE to 4GB / 4MB
+    - s390: reduce ELF_ET_DYN_BASE
+    - exec: Limit arg stack to at most 75% of _STK_LIM
+    - vt: fix unchecked __put_user() in tioclinux ioctls
+    - mnt: In umount propagation reparent in a separate pass
+    - mnt: In propgate_umount handle visiting mounts in any order
+    - mnt: Make propagate_umount less slow for overlapping mount propagation trees
+    - selftests/capabilities: Fix the test_execve test
+    - tpm: Get rid of chip->pdev
+    - tpm: Provide strong locking for device removal
+    - Add "shutdown" to "struct class".
+    - tpm: Issue a TPM2_Shutdown for TPM2 devices.
+    - mm: fix overflow check in expand_upwards()
+    - crypto: talitos - Extend max key length for SHA384/512-HMAC and AEAD
+    - crypto: atmel - only treat EBUSY as transient if backlog
+    - crypto: sha1-ssse3 - Disable avx2
+    - crypto: caam - fix signals handling
+    - sched/topology: Fix overlapping sched_group_mask
+    - sched/topology: Optimize build_group_mask()
+    - PM / wakeirq: Convert to SRCU
+    - PM / QoS: return -EINVAL for bogus strings
+    - tracing: Use SOFTIRQ_OFFSET for softirq dectection for more accurate results
+    - KVM: x86: disable MPX if host did not enable MPX XSAVE features
+    - kvm: vmx: Do not disable intercepts for BNDCFGS
+    - kvm: x86: Guest BNDCFGS requires guest MPX support
+    - kvm: vmx: Check value written to IA32_BNDCFGS
+    - kvm: vmx: allow host to access guest MSR_IA32_BNDCFGS
+    - Linux 4.4.78
+
+  * Xenial update to 4.4.77 stable release (LP: #1705238)
+    - fs: add a VALID_OPEN_FLAGS
+    - fs: completely ignore unknown open flags
+    - driver core: platform: fix race condition with driver_override
+    - bgmac: reset & enable Ethernet core before using it
+    - mm: fix classzone_idx underflow in shrink_zones()
+    - tracing/kprobes: Allow to create probe with a module name starting with a
+      digit
+    - usb: dwc3: replace %p with %pK
+    - USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick
+    - Add USB quirk for HVR-950q to avoid intermittent device resets
+    - usb: usbip: set buffer pointers to NULL after free
+    - usb: Fix typo in the definition of Endpoint[out]Request
+    - mac80211_hwsim: Replace bogus hrtimer clockid
+    - sysctl: don't print negative flag for proc_douintvec
+    - sysctl: report EINVAL if value is larger than UINT_MAX for proc_douintvec
+    - pinctrl: sh-pfc: r8a7791: Fix SCIF2 pinmux data
+    - pinctrl: meson: meson8b: fix the NAND DQS pins
+    - pinctrl: sunxi: Fix SPDIF function name for A83T
+    - pinctrl: mxs: atomically switch mux and drive strength config
+    - pinctrl: sh-pfc: Update info pointer after SoC-specific init
+    - USB: serial: option: add two Longcheer device ids
+    - USB: serial: qcserial: new Sierra Wireless EM7305 device ID
+    - gfs2: Fix glock rhashtable rcu bug
+    - x86/tools: Fix gcc-7 warning in relocs.c
+    - x86/uaccess: Optimize copy_user_enhanced_fast_string() for short strings
+    - ath10k: override CE5 config for QCA9377
+    - KEYS: Fix an error code in request_master_key()
+    - RDMA/uverbs: Check port number supplied by user verbs cmds
+    - mqueue: fix a use-after-free in sys_mq_notify()
+    - tools include: Add a __fallthrough statement
+    - tools string: Use __fallthrough in perf_atoll()
+    - tools strfilter: Use __fallthrough
+    - perf top: Use __fallthrough
+    - perf intel-pt: Use __fallthrough
+    - perf thread_map: Correctly size buffer used with dirent->dt_name
+    - perf scripting perl: Fix compile error with some perl5 versions
+    - perf tests: Avoid possible truncation with dirent->d_name + snprintf
+    - perf bench numa: Avoid possible truncation when using snprintf()
+    - perf tools: Use readdir() instead of deprecated readdir_r()
+    - perf thread_map: Use readdir() instead of deprecated readdir_r()
+    - perf script: Use readdir() instead of deprecated readdir_r()
+    - perf tools: Remove duplicate const qualifier
+    - perf annotate browser: Fix behaviour of Shift-Tab with nothing focussed
+    - perf pmu: Fix misleadingly indented assignment (whitespace)
+    - perf dwarf: Guard !x86_64 definitions under #ifdef else clause
+    - perf trace: Do not process PERF_RECORD_LOST twice
+    - perf tests: Remove wrong semicolon in while loop in CQM test
+    - perf tools: Use readdir() instead of deprecated readdir_r() again
+    - md: fix incorrect use of lexx_to_cpu in does_sb_need_changing
+    - md: fix super_offset endianness in super_1_rdev_size_change
+    - tcp: fix tcp_mark_head_lost to check skb len before fragmenting
+    - staging: vt6556: vnt_start Fix missing call to vnt_key_init_table.
+    - staging: comedi: fix clean-up of comedi_class in comedi_init()
+    - ext4: check return value of kstrtoull correctly in reserved_clusters_store
+    - x86/mm/pat: Don't report PAT on CPUs that don't support it
+    - saa7134: fix warm Medion 7134 EEPROM read
+    - Linux 4.4.77
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 11 Aug 2017 16:51:50 +0200
+
+linux (4.4.0-92.115) xenial; urgency=low
+
+  * linux: 4.4.0-92.115 -proposed tracker (LP: #1709812)
+
+  * Creating conntrack entry failure with kernel 4.4.0-89 (LP: #1709032)
+    - Revert "netfilter: synproxy: fix conntrackd interaction"
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 10 Aug 2017 10:29:51 +0200
+
+linux (4.4.0-91.114) xenial; urgency=low
+
+  * CVE-2017-1000112
+    - ipv4: Should use consistent conditional judgement for ip fragment in
+      __ip_append_data and ip_finish_output
+    - ipv6: Don't use ufo handling on later transformed packets
+    - udp: avoid ufo handling on IP payload compression packets
+    - ipv6: Should use consistent conditional judgement for ip6 fragment between
+      __ip6_append_data and ip6_finish_output
+    - net: account for current skb length when deciding about UFO
+    - udp: consistently apply ufo or fragmentation
+
+  * CVE-2017-1000111
+    - net-packet: fix race in packet_set_ring on PACKET_RESERVE
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 07 Aug 2017 13:14:36 +0200
+
+linux (4.4.0-89.112) xenial; urgency=low
+
+  * CVE-2017-7533
+    - dentry name snapshots
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 31 Jul 2017 14:50:32 -0300
+
+linux (4.4.0-88.111) xenial; urgency=low
+
+  * linux: 4.4.0-88.111 -proposed tracker (LP: #1705270)
+
+  * [Xenial] nvme: Quirks for PM1725 controllers (LP: #1704435)
+    - nvme: Quirks for PM1725 controllers
+
+  * Upgrade Redpine WLAN/BT driver to ver. 1.2 (production release)
+    (LP: #1697829)
+    - SAUCE: Redpine: Upgrade to ver. 1.2 production release
+
+  * ubuntu/rsi driver has several issues as picked up by static analysis
+    (LP: #1694733)
+    - SAUCE: Redpine: Upgrade to ver. 1.2 production release
+
+  * Redpine vendor driver - Switching to AP mode causes kernel panic
+    (LP: #1700941)
+    - SAUCE: Redpine: Upgrade to ver. 1.2 production release
+
+  * CVE-2017-10810
+    - drm/virtio: don't leak bo on drm_gem_object_init failure
+
+  * Ath10k to read different board data file if specify in SMBIOS (LP: #1666742)
+    - ath10k: search SMBIOS for OEM board file extension
+
+  * make snap-pkg support (LP: #1700747)
+    - SAUCE: make snap-pkg support
+
+  * ISST-LTE: Briggs:Stratton:UbuntuKVM:  ics_opal_set_affinity on host kernel
+    log using Intel X710 (i40e driver) (LP: #1703663)
+    - i40e: use valid online CPU on q_vector initialization
+
+  * Update snapcraft.yaml (LP: #1700480)
+    - snapcraft.yaml: various improvements
+
+  * Xenial update to 4.4.76 stable release (LP: #1702863)
+    - ipv6: release dst on error in ip6_dst_lookup_tail
+    - net: don't call strlen on non-terminated string in dev_set_alias()
+    - decnet: dn_rtmsg: Improve input length sanitization in
+      dnrmg_receive_user_skb
+    - net: Zero ifla_vf_info in rtnl_fill_vfinfo()
+    - af_unix: Add sockaddr length checks before accessing sa_family in bind and
+      connect handlers
+    - Fix an intermittent pr_emerg warning about lo becoming free.
+    - net: caif: Fix a sleep-in-atomic bug in cfpkt_create_pfx
+    - igmp: acquire pmc lock for ip_mc_clear_src()
+    - igmp: add a missing spin_lock_init()
+    - ipv6: fix calling in6_ifa_hold incorrectly for dad work
+    - net/mlx5: Wait for FW readiness before initializing command interface
+    - decnet: always not take dst->__refcnt when inserting dst into hash table
+    - net: 8021q: Fix one possible panic caused by BUG_ON in free_netdev
+    - sfc: provide dummy definitions of vswitch functions
+    - ipv6: Do not leak throw route references
+    - rtnetlink: add IFLA_GROUP to ifla_policy
+    - netfilter: xt_TCPMSS: add more sanity tests on tcph->doff
+    - netfilter: synproxy: fix conntrackd interaction
+    - NFSv4: fix a reference leak caused WARNING messages
+    - drm/ast: Handle configuration without P2A bridge
+    - mm, swap_cgroup: reschedule when neeed in swap_cgroup_swapoff()
+    - MIPS: Avoid accidental raw backtrace
+    - MIPS: pm-cps: Drop manual cache-line alignment of ready_count
+    - MIPS: Fix IRQ tracing & lockdep when rescheduling
+    - ALSA: hda - Fix endless loop of codec configure
+    - ALSA: hda - set input_path bitmap to zero after moving it to new place
+    - drm/vmwgfx: Free hash table allocated by cmdbuf managed res mgr
+    - usb: gadget: f_fs: Fix possibe deadlock
+    - sysctl: enable strict writes
+    - mm: numa: avoid waiting on freed migrated pages
+    - KVM: x86: fix fixing of hypercalls
+    - scsi: sd: Fix wrong DPOFUA disable in sd_read_cache_type
+    - scsi: lpfc: Set elsiocb contexts to NULL after freeing it
+    - qla2xxx: Fix erroneous invalid handle message
+    - ARM: dts: BCM5301X: Correct GIC_PPI interrupt flags
+    - net: mvneta: Fix for_each_present_cpu usage
+    - MIPS: ath79: fix regression in PCI window initialization
+    - net: korina: Fix NAPI versus resources freeing
+    - MIPS: ralink: MT7688 pinmux fixes
+    - MIPS: ralink: fix USB frequency scaling
+    - MIPS: ralink: Fix invalid assignment of SoC type
+    - MIPS: ralink: fix MT7628 pinmux typos
+    - MIPS: ralink: fix MT7628 wled_an pinmux gpio
+    - mtd: bcm47xxpart: limit scanned flash area on BCM47XX (MIPS) only
+    - bgmac: fix a missing check for build_skb
+    - mtd: bcm47xxpart: don't fail because of bit-flips
+    - bgmac: Fix reversed test of build_skb() return value.
+    - net: bgmac: Fix SOF bit checking
+    - net: bgmac: Start transmit queue in bgmac_open
+    - net: bgmac: Remove superflous netif_carrier_on()
+    - powerpc/eeh: Enable IO path on permanent error
+    - gianfar: Do not reuse pages from emergency reserve
+    - Btrfs: fix truncate down when no_holes feature is enabled
+    - virtio_console: fix a crash in config_work_handler
+    - swiotlb-xen: update dev_addr after swapping pages
+    - xen-netfront: Fix Rx stall during network stress and OOM
+    - scsi: virtio_scsi: Reject commands when virtqueue is broken
+    - platform/x86: ideapad-laptop: handle ACPI event 1
+    - amd-xgbe: Check xgbe_init() return code
+    - net: dsa: Check return value of phy_connect_direct()
+    - drm/amdgpu: check ring being ready before using
+    - vfio/spapr: fail tce_iommu_attach_group() when iommu_data is null
+    - virtio_net: fix PAGE_SIZE > 64k
+    - vxlan: do not age static remote mac entries
+    - ibmveth: Add a proper check for the availability of the checksum features
+    - kernel/panic.c: add missing \n
+    - HID: i2c-hid: Add sleep between POWER ON and RESET
+    - scsi: lpfc: avoid double free of resource identifiers
+    - spi: davinci: use dma_mapping_error()
+    - mac80211: initialize SMPS field in HT capabilities
+    - x86/mpx: Use compatible types in comparison to fix sparse error
+    - coredump: Ensure proper size of sparse core files
+    - swiotlb: ensure that page-sized mappings are page-aligned
+    - s390/ctl_reg: make __ctl_load a full memory barrier
+    - be2net: fix status check in be_cmd_pmac_add()
+    - perf probe: Fix to show correct locations for events on modules
+    - net/mlx4_core: Eliminate warning messages for SRQ_LIMIT under SRIOV
+    - sctp: check af before verify address in sctp_addr_id2transport
+    - ravb: Fix use-after-free on `ifconfig eth0 down`
+    - jump label: fix passing kbuild_cflags when checking for asm goto support
+    - xfrm: fix stack access out of bounds with CONFIG_XFRM_SUB_POLICY
+    - xfrm: NULL dereference on allocation failure
+    - xfrm: Oops on error in pfkey_msg2xfrm_state()
+    - watchdog: bcm281xx: Fix use of uninitialized spinlock.
+    - sched/loadavg: Avoid loadavg spikes caused by delayed NO_HZ accounting
+    - ARM64/ACPI: Fix BAD_MADT_GICC_ENTRY() macro implementation
+    - ARM: 8685/1: ensure memblock-limit is pmd-aligned
+    - x86/mpx: Correctly report do_mpx_bt_fault() failures to user-space
+    - x86/mm: Fix flush_tlb_page() on Xen
+    - ocfs2: o2hb: revert hb threshold to keep compatible
+    - iommu/vt-d: Don't over-free page table directories
+    - iommu: Handle default domain attach failure
+    - iommu/amd: Fix incorrect error handling in amd_iommu_bind_pasid()
+    - cpufreq: s3c2416: double free on driver init error path
+    - KVM: x86: fix emulation of RSM and IRET instructions
+    - KVM: x86/vPMU: fix undefined shift in intel_pmu_refresh()
+    - KVM: x86: zero base3 of unusable segments
+    - KVM: nVMX: Fix exception injection
+    - Linux 4.4.76
+
+  * Xenial update to 4.4.75 stable release (LP: #1702118)
+    - fs/exec.c: account for argv/envp pointers
+    - autofs: sanity check status reported with AUTOFS_DEV_IOCTL_FAIL
+    - lib/cmdline.c: fix get_options() overflow while parsing ranges
+    - KVM: PPC: Book3S HV: Preserve userspace HTM state properly
+    - CIFS: Improve readdir verbosity
+    - HID: Add quirk for Dell PIXART OEM mouse
+    - signal: Only reschedule timers on signals timers have sent
+    - powerpc/kprobes: Pause function_graph tracing during jprobes handling
+    - Input: i8042 - add Fujitsu Lifebook AH544 to notimeout list
+    - time: Fix clock->read(clock) race around clocksource changes
+    - target: Fix kref->refcount underflow in transport_cmd_finish_abort
+    - iscsi-target: Reject immediate data underflow larger than SCSI transfer
+      length
+    - drm/radeon: add a PX quirk for another K53TK variant
+    - drm/radeon: add a quirk for Toshiba Satellite L20-183
+    - drm/amdgpu/atom: fix ps allocation size for EnableDispPowerGating
+    - drm/amdgpu: adjust default display clock
+    - USB: usbip: fix nonconforming hub descriptor
+    - rxrpc: Fix several cases where a padded len isn't checked in ticket decode
+    - of: Add check to of_scan_flat_dt() before accessing initial_boot_params
+    - mtd: spi-nor: fix spansion quad enable
+    - powerpc/slb: Force a full SLB flush when we insert for a bad EA
+    - usb: gadget: f_fs: avoid out of bounds access on comp_desc
+    - net: phy: Initialize mdio clock at probe function
+    - net: phy: fix marvell phy status reading
+    - Linux 4.4.75
+
+  * Xenial update to 4.4.74 stable release (LP: #1702104)
+    - configfs: Fix race between create_link and configfs_rmdir
+    - can: gs_usb: fix memory leak in gs_cmd_reset()
+    - cpufreq: conservative: Allow down_threshold to take values from 1 to 10
+    - vb2: Fix an off by one error in 'vb2_plane_vaddr'
+    - mac80211: don't look at the PM bit of BAR frames
+    - mac80211/wpa: use constant time memory comparison for MACs
+    - mac80211: fix CSA in IBSS mode
+    - mac80211: fix IBSS presp allocation size
+    - serial: efm32: Fix parity management in 'efm32_uart_console_get_options()'
+    - x86/mm/32: Set the '__vmalloc_start_set' flag in initmem_init()
+    - mfd: omap-usb-tll: Fix inverted bit use for USB TLL mode
+    - staging: rtl8188eu: prevent an underflow in rtw_check_beacon_data()
+    - iio: proximity: as3935: recalibrate RCO after resume
+    - USB: hub: fix SS max number of ports
+    - usb: core: fix potential memory leak in error path during hcd creation
+    - pvrusb2: reduce stack usage pvr2_eeprom_analyze()
+    - USB: gadget: dummy_hcd: fix hub-descriptor removable fields
+    - usb: r8a66597-hcd: select a different endpoint on timeout
+    - usb: r8a66597-hcd: decrease timeout
+    - drivers/misc/c2port/c2port-duramar2150.c: checking for NULL instead of
+      IS_ERR()
+    - usb: xhci: ASMedia ASM1042A chipset need shorts TX quirk
+    - USB: gadgetfs, dummy-hcd, net2280: fix locking for callbacks
+    - mm/memory-failure.c: use compound_head() flags for huge pages
+    - swap: cond_resched in swap_cgroup_prepare()
+    - genirq: Release resources in __setup_irq() error path
+    - alarmtimer: Prevent overflow of relative timers
+    - usb: dwc3: exynos fix axius clock error path to do cleanup
+    - MIPS: Fix bnezc/jialc return address calculation
+    - alarmtimer: Rate limit periodic intervals
+    - Linux 4.4.74
+
+  * Side Button (Display Toggle) fails on Dell AIO systems (LP: #1702541)
+    - dell-wmi: Add a WMI event code for display on/off
+
+  * Intel i40e PF reset under load (LP: #1700834)
+    - i40e/i40evf: Limit TSO to 7 descriptors for payload instead of 8 per packet
+
+  * update ENA driver to 1.2.0k from net-next (LP: #1701575)
+    - net: ena: remove superfluous check in ena_remove()
+    - net: ena: fix rare uncompleted admin command false alarm
+    - net: ena: add missing return when ena_com_get_io_handlers() fails
+    - net: ena: fix race condition between submit and completion admin command
+    - net: ena: add missing unmap bars on device removal
+    - net: ena: fix theoretical Rx hang on low memory systems
+    - net: ena: disable admin msix while working in polling mode
+    - net: ena: bug fix in lost tx packets detection mechanism
+    - net: ena: update ena driver to version 1.1.7
+    - net: ena: change return value for unsupported features unsupported return
+      value
+    - net: ena: add hardware hints capability to the driver
+    - net: ena: change sizeof() argument to be the type pointer
+    - net: ena: add reset reason for each device FLR
+    - net: ena: add support for out of order rx buffers refill
+    - net: ena: use napi_schedule_irqoff when possible
+    - net: ena: separate skb allocation to dedicated function
+    - net: ena: use lower_32_bits()/upper_32_bits() to split dma address
+    - net: ena: update driver's rx drop statistics
+    - net: ena: update ena driver to version 1.2.0
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 20 Jul 2017 09:25:21 +0200
+
+linux (4.4.0-87.110) xenial; urgency=low
+
+  * linux: 4.4.0-87.110 -proposed tracker (LP: #1704982)
+
+  * CVE-2017-1000364
+    - mm/mmap.c: do not blow on PROT_NONE MAP_FIXED holes in the stack
+    - mm/mmap.c: expand_downwards: don't require the gap if !vm_prev
+
+  * CIFS causes oops (LP: #1704857)
+    - CIFS: Fix null pointer deref during read resp processing
+    - CIFS: Fix some return values in case of error in 'crypt_message'
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 18 Jul 2017 13:58:43 +0200
+
+linux (4.4.0-86.109) xenial; urgency=low
+
+  * linux: 4.4.0-86.109 -proposed tracker (LP: #1703995)
+
+  * sock_recvmsg has dropped size argument (LP: #1701697)
+    - Packaging: Breaks unfixed iscsitarget versions
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 12 Jul 2017 18:23:18 -0300
+
+linux (4.4.0-85.108) xenial; urgency=low
+
+  * linux: 4.4.0-85.108 -proposed tracker (LP: #1702103)
+
+  * [Hyper-V] Implement Hyper-V PTP Source (LP: #1676635)
+    - SAUCE: hv: make clocksource available for PTP device supporting
+    - Drivers: hv: util: Use hv_get_current_tick() to get current tick
+    - hv_util: switch to using timespec64
+    - hv_utils: implement Hyper-V PTP source
+    - Drivers: hv: util: Fix a typo
+    - Drivers: hv: util: don't forget to init host_ts.lock
+    - hv_utils: drop .getcrosststamp() support from PTP driver
+    - hv_utils: fix TimeSync work on pre-TimeSync-v4 hosts
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 03 Jul 2017 10:50:09 -0300
+
+linux (4.4.0-84.107) xenial; urgency=low
+
+  * linux: 4.4.0-84.107 -proposed tracker (LP: #1701024)
+
+  * Can't disable USB port from BIOS (LP: #1695216)
+    - SAUCE: xhci: AMD Promontory USB disable port support
+
+  * KILLER1435-S[0489:e0a2] BT cannot search BT 4.0 device (LP: #1699651)
+    - Bluetooth: btusb: Add support for 0489:e0a2 QCA_ROME device
+
+  * CIFS: Enable encryption for SMB3 (LP: #1670508)
+    - Revert "Handle mismatched open calls"
+    - Revert "Call echo service immediately after socket reconnect"
+    - cifs: Make echo interval tunable
+    - Prepare for encryption support (first part). Add decryption and encryption
+      key generation. Thanks to Metze for helping with this.
+    - [net] drop 'size' argument of sock_recvmsg()
+    - cifs: merge the hash calculation helpers
+    - cifs: no need to wank with copying and advancing iovec on recvmsg side
+      either
+    - cifs: don't bother with kmap on read_pages side
+    - cifs_readv_receive: use cifs_read_from_socket()
+    - Fix memory leaks in cifs_do_mount()
+    - SMB3: Add mount parameter to allow user to override max credits
+    - SMB2: Separate Kerberos authentication from SMB2_sess_setup
+    - SMB2: Separate RawNTLMSSP authentication from SMB2_sess_setup
+    - SMB3: parsing for new snapshot timestamp mount parm
+    - cifs: Simplify SMB2 and SMB311 dependencies
+    - cifs: Only select the required crypto modules
+    - cifs: Add soft dependencies
+    - CIFS: Separate SMB2 header structure
+    - CIFS: Make SendReceive2() takes resp iov
+    - CIFS: Make send_cancel take rqst as argument
+    - CIFS: Send RFC1001 length in a separate iov
+    - CIFS: Separate SMB2 sync header processing
+    - CIFS: Separate RFC1001 length processing for SMB2 read
+    - CIFS: Add capability to transform requests before sending
+    - CIFS: Enable encryption during session setup phase
+    - CIFS: Encrypt SMB3 requests before sending
+    - CIFS: Add transform header handling callbacks
+    - CIFS: Add mid handle callback
+    - CIFS: Add copy into pages callback for a read operation
+    - CIFS: Decrypt and process small encrypted packets
+    - CIFS: Add capability to decrypt big read responses
+    - CIFS: Allow to switch on encryption with seal mount option
+    - CIFS: Fix possible use after free in demultiplex thread
+    - Call echo service immediately after socket reconnect
+    - Handle mismatched open calls
+
+  * CVE-2017-9150
+    - bpf: don't let ldimm64 leak map addresses on unprivileged
+
+  * CVE-2015-8944
+    - Make file credentials available to the seqfile interfaces
+    - /proc/iomem: only expose physical resource addresses to privileged users
+
+  * Xenial update to 4.4.73 stable release (LP: #1698817)
+    - s390/vmem: fix identity mapping
+    - partitions/msdos: FreeBSD UFS2 file systems are not recognized
+    - ARM: dts: imx6dl: Fix the VDD_ARM_CAP voltage for 396MHz operation
+    - staging: rtl8192e: rtl92e_fill_tx_desc fix write to mapped out memory.
+    - net: xilinx_emaclite: fix freezes due to unordered I/O
+    - net: xilinx_emaclite: fix receive buffer overflow
+    - ipv6: Handle IPv4-mapped src to in6addr_any dst.
+    - ipv6: Inhibit IPv4-mapped src address on the wire.
+    - NET: Fix /proc/net/arp for AX.25
+    - NET: mkiss: Fix panic
+    - net: hns: Fix the device being used for dma mapping during TX
+    - sierra_net: Skip validating irrelevant fields for IDLE LSIs
+    - sierra_net: Add support for IPv6 and Dual-Stack Link Sense Indications
+    - i2c: piix4: Fix request_region size
+    - ipv6: Fix IPv6 packet loss in scenarios involving roaming + snooping
+      switches
+    - PM / runtime: Avoid false-positive warnings from might_sleep_if()
+    - jump label: pass kbuild_cflags when checking for asm goto support
+    - kasan: respect /proc/sys/kernel/traceoff_on_warning
+    - log2: make order_base_2() behave correctly on const input value zero
+    - ethtool: do not vzalloc(0) on registers dump
+    - fscache: Fix dead object requeue
+    - fscache: Clear outstanding writes when disabling a cookie
+    - FS-Cache: Initialise stores_lock in netfs cookie
+    - ipv6: fix flow labels when the traffic class is non-0
+    - drm/nouveau: prevent userspace from deleting client object
+    - drm/nouveau/fence/g84-: protect against concurrent access to semaphore
+      buffers
+    - gianfar: synchronize DMA API usage by free_skb_rx_queue w/ gfar_new_page
+    - pinctrl: berlin-bg4ct: fix the value for "sd1a" of pin SCRD0_CRD_PRES
+    - net: adaptec: starfire: add checks for dma mapping errors
+    - parisc, parport_gsc: Fixes for printk continuation lines
+    - drm/nouveau: Don't enabling polling twice on runtime resume
+    - drm/ast: Fixed system hanged if disable P2A
+    - ravb: unmap descriptors when freeing rings
+    - nfs: Fix "Don't increment lock sequence ID after NFS4ERR_MOVED"
+    - r8152: re-schedule napi for tx
+    - r8152: fix rtl8152_post_reset function
+    - r8152: avoid start_xmit to schedule napi when napi is disabled
+    - sctp: sctp_addr_id2transport should verify the addr before looking up assoc
+    - romfs: use different way to generate fsid for BLOCK or MTD
+    - proc: add a schedule point in proc_pid_readdir()
+    - tipc: ignore requests when the connection state is not CONNECTED
+    - xtensa: don't use linux IRQ #0
+    - s390/kvm: do not rely on the ILC on kvm host protection fauls
+    - sparc64: make string buffers large enough
+    - Linux 4.4.73
+
+  * Xenial update to 4.4.72 stable release (LP: #1698799)
+    - bnx2x: Fix Multi-Cos
+    - ipv6: xfrm: Handle errors reported by xfrm6_find_1stfragopt()
+    - cxgb4: avoid enabling napi twice to the same queue
+    - tcp: disallow cwnd undo when switching congestion control
+    - vxlan: fix use-after-free on deletion
+    - ipv6: Fix leak in ipv6_gso_segment().
+    - net: ping: do not abuse udp_poll()
+    - net: ethoc: enable NAPI before poll may be scheduled
+    - net: bridge: start hello timer only if device is up
+    - sparc64: mm: fix copy_tsb to correctly copy huge page TSBs
+    - sparc: Machine description indices can vary
+    - sparc64: reset mm cpumask after wrap
+    - sparc64: combine activate_mm and switch_mm
+    - sparc64: redefine first version
+    - sparc64: add per-cpu mm of secondary contexts
+    - sparc64: new context wrap
+    - sparc64: delete old wrap code
+    - arch/sparc: support NR_CPUS = 4096
+    - serial: ifx6x60: fix use-after-free on module unload
+    - ptrace: Properly initialize ptracer_cred on fork
+    - KEYS: fix dereferencing NULL payload with nonzero length
+    - KEYS: fix freeing uninitialized memory in key_update()
+    - crypto: gcm - wait for crypto op not signal safe
+    - drm/amdgpu/ci: disable mclk switching for high refresh rates (v2)
+    - nfsd4: fix null dereference on replay
+    - nfsd: Fix up the "supattr_exclcreat" attributes
+    - kvm: async_pf: fix rcu_irq_enter() with irqs enabled
+    - KVM: cpuid: Fix read/write out-of-bounds vulnerability in cpuid emulation
+    - arm: KVM: Allow unaligned accesses at HYP
+    - KVM: async_pf: avoid async pf injection when in guest mode
+    - dmaengine: usb-dmac: Fix DMAOR AE bit definition
+    - dmaengine: ep93xx: Always start from BASE0
+    - xen/privcmd: Support correctly 64KB page granularity when mapping memory
+    - xen-netfront: do not cast grant table reference to signed short
+    - xen-netfront: cast grant table reference first to type int
+    - ext4: fix SEEK_HOLE
+    - ext4: keep existing extra fields when inode expands
+    - ext4: fix fdatasync(2) after extent manipulation operations
+    - usb: gadget: f_mass_storage: Serialize wake and sleep execution
+    - usb: chipidea: udc: fix NULL pointer dereference if udc_start failed
+    - usb: chipidea: debug: check before accessing ci_role
+    - staging/lustre/lov: remove set_fs() call from lov_getstripe()
+    - iio: light: ltr501 Fix interchanged als/ps register field
+    - iio: proximity: as3935: fix AS3935_INT mask
+    - drivers: char: random: add get_random_long()
+    - random: properly align get_random_int_hash
+    - stackprotector: Increase the per-task stack canary's random range from 32
+      bits to 64 bits on 64-bit platforms
+    - cpufreq: cpufreq_register_driver() should return -ENODEV if init fails
+    - target: Re-add check to reject control WRITEs with overflow data
+    - drm/msm: Expose our reservation object when exporting a dmabuf.
+    - Input: elantech - add Fujitsu Lifebook E546/E557 to force crc_enabled
+    - cpuset: consider dying css as offline
+    - fs: add i_blocksize()
+    - ufs: restore proper tail allocation
+    - fix ufs_isblockset()
+    - ufs: restore maintaining ->i_blocks
+    - ufs: set correct ->s_maxsize
+    - ufs_extend_tail(): fix the braino in calling conventions of
+      ufs_new_fragments()
+    - ufs_getfrag_block(): we only grab ->truncate_mutex on block creation path
+    - cxl: Fix error path on bad ioctl
+    - btrfs: use correct types for page indices in btrfs_page_exists_in_range
+    - btrfs: fix memory leak in update_space_info failure path
+    - KVM: arm/arm64: Handle possible NULL stage2 pud when ageing pages
+    - scsi: qla2xxx: don't disable a not previously enabled PCI device
+    - powerpc/eeh: Avoid use after free in eeh_handle_special_event()
+    - powerpc/numa: Fix percpu allocations to be NUMA aware
+    - powerpc/hotplug-mem: Fix missing endian conversion of aa_index
+    - perf/core: Drop kernel samples even though :u is specified
+    - drm/vmwgfx: Handle vmalloc() failure in vmw_local_fifo_reserve()
+    - drm/vmwgfx: Make sure backup_handle is always valid
+    - drm/nouveau/tmr: fully separate alarm execution/pending lists
+    - ALSA: timer: Fix race between read and ioctl
+    - ALSA: timer: Fix missing queue indices reset at SNDRV_TIMER_IOCTL_SELECT
+    - ASoC: Fix use-after-free at card unregistration
+    - drivers: char: mem: Fix wraparound check to allow mappings up to the end
+    - tty: Drop krefs for interrupted tty lock
+    - serial: sh-sci: Fix panic when serial console and DMA are enabled
+    - mm: consider memblock reservations for deferred memory initialization sizing
+    - NFS: Ensure we revalidate attributes before using execute_ok()
+    - NFSv4: Don't perform cached access checks before we've OPENed the file
+    - Make __xfs_xattr_put_listen preperly report errors.
+    - arm64: hw_breakpoint: fix watchpoint matching for tagged pointers
+    - arm64: entry: improve data abort handling of tagged pointers
+    - RDMA/qib,hfi1: Fix MR reference count leak on write with immediate
+    - usercopy: Adjust tests to deal with SMAP/PAN
+    - arm64: armv8_deprecated: ensure extension of addr
+    - arm64: ensure extension of smp_store_release value
+    - Linux 4.4.72
+
+  * Xenial update to 4.4.71 stable release (LP: #1697001)
+    - sparc: Fix -Wstringop-overflow warning
+    - s390/qeth: handle sysfs error during initialization
+    - s390/qeth: unbreak OSM and OSN support
+    - s390/qeth: avoid null pointer dereference on OSN
+    - tcp: avoid fragmenting peculiar skbs in SACK
+    - sctp: fix src address selection if using secondary addresses for ipv6
+    - tcp: eliminate negative reordering in tcp_clean_rtx_queue
+    - net: Improve handling of failures on link and route dumps
+    - bridge: netlink: check vlan_default_pvid range
+    - qmi_wwan: add another Lenovo EM74xx device ID
+    - bridge: start hello_timer when enabling KERNEL_STP in br_stp_start
+    - be2net: Fix offload features for Q-in-Q packets
+    - virtio-net: enable TSO/checksum offloads for Q-in-Q vlans
+    - tcp: avoid fastopen API to be used on AF_UNSPEC
+    - sctp: fix ICMP processing if skb is non-linear
+    - ipv4: add reference counting to metrics
+    - netem: fix skb_orphan_partial()
+    - net: phy: marvell: Limit errata to 88m1101
+    - vlan: Fix tcp checksum offloads in Q-in-Q vlans
+    - i2c: i2c-tiny-usb: fix buffer not being DMA capable
+    - mmc: sdhci-iproc: suppress spurious interrupt with Multiblock read
+    - HID: wacom: Have wacom_tpc_irq guard against possible NULL dereference
+    - scsi: mpt3sas: Force request partial completion alignment
+    - drm/radeon/ci: disable mclk switching for high refresh rates (v2)
+    - drm/radeon: Unbreak HPD handling for r600+
+    - pcmcia: remove left-over %Z format
+    - ALSA: hda - apply STAC_9200_DELL_M22 quirk for Dell Latitude D430
+    - slub/memcg: cure the brainless abuse of sysfs attributes
+    - drm/gma500/psb: Actually use VBT mode when it is found
+    - mm/migrate: fix refcount handling when !hugepage_migration_supported()
+    - mlock: fix mlock count can not decrease in race condition
+    - xfs: Fix missed holes in SEEK_HOLE implementation
+    - xfs: fix off-by-one on max nr_pages in xfs_find_get_desired_pgoff()
+    - xfs: fix over-copying of getbmap parameters from userspace
+    - xfs: handle array index overrun in xfs_dir2_leaf_readbuf()
+    - xfs: prevent multi-fsb dir readahead from reading random blocks
+    - xfs: fix up quotacheck buffer list error handling
+    - xfs: support ability to wait on new inodes
+    - xfs: update ag iterator to support wait on new inodes
+    - xfs: wait on new inodes during quotaoff dquot release
+    - xfs: fix indlen accounting error on partial delalloc conversion
+    - xfs: bad assertion for delalloc an extent that start at i_size
+    - xfs: fix unaligned access in xfs_btree_visit_blocks
+    - xfs: in _attrlist_by_handle, copy the cursor back to userspace
+    - xfs: only return -errno or success from attr ->put_listent
+    - Linux 4.4.71
+
+  * CVE-2017-7346
+    - drm/vmwgfx: limit the number of mip levels in vmw_gb_surface_define_ioctl()
+
+  * Power button does not work on Latitude 7480 (LP: #1697116)
+    - intel-hid: Remove duplicated acpi_remove_notify_handler
+    - platform/x86: intel-hid: Support 5 button array
+
+  * CVE-2017-9074
+    - ipv6: Check ip6_find_1stfragopt() return value properly.
+
+  * CVE-2014-9900
+    - net: Zeroing the structure ethtool_wolinfo in ethtool_get_wol()
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 28 Jun 2017 14:47:02 -0300
+
+linux (4.4.0-83.106) xenial; urgency=low
+
+  * linux: 4.4.0-83.106 -proposed tracker (LP: #1700541)
+
+  * CVE-2017-1000364
+    - Revert "UBUNTU: SAUCE: mm: Only expand stack if guard area is hit"
+    - Revert "mm: do not collapse stack gap into THP"
+    - Revert "mm: enlarge stack guard gap"
+    - mm: vma_adjust: remove superfluous confusing update in remove_next == 1 case
+    - mm: larger stack guard gap, between vmas
+    - mm: fix new crash in unmapped_area_topdown()
+    - Allow stack to grow up to address space limit
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 26 Jun 2017 12:27:55 -0300
+
+linux (4.4.0-82.105) xenial; urgency=low
+
+  * linux: 4.4.0-82.105 -proposed tracker (LP: #1699064)
+
+  * CVE-2017-1000364
+    - SAUCE: mm: Only expand stack if guard area is hit
+
+  * linux-aws/linux-gke incorrectly producing and using linux-*-tools-
+    common/linux-*-cloud-tools-common (LP: #1688579)
+    - [Config] make linux-tools-common and linux-cloud-tools-common protection
+      consistent
+
+  * CVE-2017-9242
+    - ipv6: fix out of bound writes in __ip6_append_data()
+
+  * CVE-2017-9075
+    - sctp: do not inherit ipv6_{mc|ac|fl}_list from parent
+
+  * CVE-2017-9074
+    - ipv6: Prevent overrun when parsing v6 header options
+
+  * CVE-2017-9076
+    - ipv6/dccp: do not inherit ipv6_mc_list from parent
+
+  * CVE-2017-9077
+    - ipv6/dccp: do not inherit ipv6_mc_list from parent
+
+  * CVE-2017-8890
+    - dccp/tcp: do not inherit mc_list from parent
+
+  * Module signing exclusion for staging drivers does not work properly
+    (LP: #1690908)
+    - SAUCE: Fix module signing exclusion in package builds
+
+  * extend-diff-ignore should use exact matches (LP: #1693504)
+    - [Packaging] exact extend-diff-ignore matches
+
+  * Dell XPS 9360 wifi 5G performance is poor (LP: #1692836)
+    - SAUCE: ath10k: fix the wifi speed issue for kill 1535
+
+  *  Upgrade Redpine WLAN/BT driver to ver. 1.2.RC12 (LP: #1694607)
+    - SAUCE: Redpine: Upgrade to ver. 1.2.RC12
+
+  * [DP MST] No audio output through HDMI/DP/mDP ports in Dell WD15 and TB15
+    docking stations (LP: #1694665)
+    - drm/i915: Store port enum in intel_encoder
+    - drm/i915: Eliminate redundant local variable definition
+    - drm/i915: Switch to using port stored in intel_encoder
+    - drm/i915: Move audio_connector to intel_encoder
+    - drm/i915/dp: DP audio API changes for MST
+    - drm/i915: abstract ddi being audio enabled
+    - drm/i915/audio: extend get_saved_enc() to support more scenarios
+    - drm/i915: enable dp mst audio
+
+  * Xenial update to 4.4.70 stable release (LP: #1694621)
+    - usb: misc: legousbtower: Fix buffers on stack
+    - usb: misc: legousbtower: Fix memory leak
+    - USB: ene_usb6250: fix DMA to the stack
+    - watchdog: pcwd_usb: fix NULL-deref at probe
+    - char: lp: fix possible integer overflow in lp_setup()
+    - USB: core: replace %p with %pK
+    - ARM: tegra: paz00: Mark panel regulator as enabled on boot
+    - tpm_crb: check for bad response size
+    - infiniband: call ipv6 route lookup via the stub interface
+    - dm btree: fix for dm_btree_find_lowest_key()
+    - dm raid: select the Kconfig option CONFIG_MD_RAID0
+    - dm bufio: avoid a possible ABBA deadlock
+    - dm bufio: check new buffer allocation watermark every 30 seconds
+    - dm cache metadata: fail operations if fail_io mode has been established
+    - dm bufio: make the parameter "retain_bytes" unsigned long
+    - dm thin metadata: call precommit before saving the roots
+    - dm space map disk: fix some book keeping in the disk space map
+    - md: update slab_cache before releasing new stripes when stripes resizing
+    - rtlwifi: rtl8821ae: setup 8812ae RFE according to device type
+    - mwifiex: pcie: fix cmd_buf use-after-free in remove/reset
+    - ima: accept previously set IMA_NEW_FILE
+    - KVM: x86: Fix load damaged SSEx MXCSR register
+    - KVM: X86: Fix read out-of-bounds vulnerability in kvm pio emulation
+    - regulator: tps65023: Fix inverted core enable logic.
+    - s390/kdump: Add final note
+    - s390/cputime: fix incorrect system time
+    - ath9k_htc: Add support of AirTies 1eda:2315 AR9271 device
+    - ath9k_htc: fix NULL-deref at probe
+    - drm/amdgpu: Avoid overflows/divide-by-zero in latency_watermark
+      calculations.
+    - drm/amdgpu: Make display watermark calculations more accurate
+    - drm/nouveau/therm: remove ineffective workarounds for alarm bugs
+    - drm/nouveau/tmr: ack interrupt before processing alarms
+    - drm/nouveau/tmr: fix corruption of the pending list when rescheduling an
+      alarm
+    - drm/nouveau/tmr: avoid processing completed alarms when adding a new one
+    - drm/nouveau/tmr: handle races with hw when updating the next alarm time
+    - cdc-acm: fix possible invalid access when processing notification
+    - proc: Fix unbalanced hard link numbers
+    - of: fix sparse warning in of_pci_range_parser_one
+    - iio: dac: ad7303: fix channel description
+    - pid_ns: Sleep in TASK_INTERRUPTIBLE in zap_pid_ns_processes
+    - pid_ns: Fix race between setns'ed fork() and zap_pid_ns_processes()
+    - USB: serial: ftdi_sio: fix setting latency for unprivileged users
+    - USB: serial: ftdi_sio: add Olimex ARM-USB-TINY(H) PIDs
+    - ext4 crypto: don't let data integrity writebacks fail with ENOMEM
+    - ext4 crypto: fix some error handling
+    - net: qmi_wwan: Add SIMCom 7230E
+    - fscrypt: fix context consistency check when key(s) unavailable
+    - f2fs: check entire encrypted bigname when finding a dentry
+    - fscrypt: avoid collisions when presenting long encrypted filenames
+    - usb: host: xhci-plat: propagate return value of platform_get_irq()
+    - xhci: apply PME_STUCK_QUIRK and MISSING_CAS quirk for Denverton
+    - usb: host: xhci-mem: allocate zeroed Scratchpad Buffer
+    - net: irda: irda-usb: fix firmware name on big-endian hosts
+    - usbvision: fix NULL-deref at probe
+    - mceusb: fix NULL-deref at probe
+    - ttusb2: limit messages to buffer size
+    - usb: musb: tusb6010_omap: Do not reset the other direction's packet size
+    - USB: iowarrior: fix info ioctl on big-endian hosts
+    - usb: serial: option: add Telit ME910 support
+    - USB: serial: qcserial: add more Lenovo EM74xx device IDs
+    - USB: serial: mct_u232: fix big-endian baud-rate handling
+    - USB: serial: io_ti: fix div-by-zero in set_termios
+    - USB: hub: fix SS hub-descriptor handling
+    - USB: hub: fix non-SS hub-descriptor handling
+    - ipx: call ipxitf_put() in ioctl error path
+    - iio: proximity: as3935: fix as3935_write
+    - ceph: fix recursion between ceph_set_acl() and __ceph_setattr()
+    - gspca: konica: add missing endpoint sanity check
+    - s5p-mfc: Fix unbalanced call to clock management
+    - dib0700: fix NULL-deref at probe
+    - zr364xx: enforce minimum size when reading header
+    - dvb-frontends/cxd2841er: define symbol_rate_min/max in T/C fe-ops
+    - cx231xx-audio: fix init error path
+    - cx231xx-audio: fix NULL-deref at probe
+    - cx231xx-cards: fix NULL-deref at probe
+    - powerpc/book3s/mce: Move add_taint() later in virtual mode
+    - powerpc/pseries: Fix of_node_put() underflow during DLPAR remove
+    - powerpc/64e: Fix hang when debugging programs with relocated kernel
+    - ARM: dts: at91: sama5d3_xplained: fix ADC vref
+    - ARM: dts: at91: sama5d3_xplained: not all ADC channels are available
+    - arm64: xchg: hazard against entire exchange variable
+    - arm64: uaccess: ensure extension of access_ok() addr
+    - arm64: documentation: document tagged pointer stack constraints
+    - xc2028: Fix use-after-free bug properly
+    - Revert "UBUNTU: SAUCE: mm: Respect FOLL_FORCE/FOLL_COW for thp"
+    - mm/huge_memory.c: respect FOLL_FORCE/FOLL_COW for thp
+    - staging: rtl8192e: fix 2 byte alignment of register BSSIDR.
+    - staging: rtl8192e: rtl92e_get_eeprom_size Fix read size of EPROM_CMD.
+    - iommu/vt-d: Flush the IOTLB to get rid of the initial kdump mappings
+    - metag/uaccess: Fix access_ok()
+    - metag/uaccess: Check access_ok in strncpy_from_user
+    - uwb: fix device quirk on big-endian hosts
+    - genirq: Fix chained interrupt data ordering
+    - osf_wait4(): fix infoleak
+    - tracing/kprobes: Enforce kprobes teardown after testing
+    - PCI: Fix pci_mmap_fits() for HAVE_PCI_RESOURCE_TO_USER platforms
+    - PCI: Freeze PME scan before suspending devices
+    - drm/edid: Add 10 bpc quirk for LGD 764 panel in HP zBook 17 G2
+    - nfsd: encoders mustn't use unitialized values in error cases
+    - drivers: char: mem: Check for address space wraparound with mmap()
+    - Linux 4.4.70
+
+  * Xenial update to 4.4.69 stable release (LP: #1692900)
+    - xen: adjust early dom0 p2m handling to xen hypervisor behavior
+    - target: Fix compare_and_write_callback handling for non GOOD status
+    - target/fileio: Fix zero-length READ and WRITE handling
+    - target: Convert ACL change queue_depth se_session reference usage
+    - iscsi-target: Set session_fall_back_to_erl0 when forcing reinstatement
+    - usb: host: xhci: print correct command ring address
+    - USB: serial: ftdi_sio: add device ID for Microsemi/Arrow SF2PLUS Dev Kit
+    - USB: Proper handling of Race Condition when two USB class drivers try to
+      call init_usb_class simultaneously
+    - staging: vt6656: use off stack for in buffer USB transfers.
+    - staging: vt6656: use off stack for out buffer USB transfers.
+    - staging: gdm724x: gdm_mux: fix use-after-free on module unload
+    - staging: comedi: jr3_pci: fix possible null pointer dereference
+    - staging: comedi: jr3_pci: cope with jiffies wraparound
+    - usb: misc: add missing continue in switch
+    - usb: Make sure usb/phy/of gets built-in
+    - usb: hub: Fix error loop seen after hub communication errors
+    - usb: hub: Do not attempt to autosuspend disconnected devices
+    - x86/boot: Fix BSS corruption/overwrite bug in early x86 kernel startup
+    - selftests/x86/ldt_gdt_32: Work around a glibc sigaction() bug
+    - x86, pmem: Fix cache flushing for iovec write < 8 bytes
+    - um: Fix PTRACE_POKEUSER on x86_64
+    - KVM: x86: fix user triggerable warning in kvm_apic_accept_events()
+    - KVM: arm/arm64: fix races in kvm_psci_vcpu_on
+    - block: fix blk_integrity_register to use template's interval_exp if not 0
+    - crypto: algif_aead - Require setkey before accept(2)
+    - dm era: save spacemap metadata root after the pre-commit
+    - vfio/type1: Remove locked page accounting workqueue
+    - IB/core: Fix sysfs registration error flow
+    - IB/IPoIB: ibX: failed to create mcg debug file
+    - IB/mlx4: Fix ib device initialization error flow
+    - IB/mlx4: Reduce SRIOV multicast cleanup warning message to debug level
+    - ext4: evict inline data when writing to memory map
+    - fs/xattr.c: zero out memory copied to userspace in getxattr
+    - ceph: fix memory leak in __ceph_setxattr()
+    - fs/block_dev: always invalidate cleancache in invalidate_bdev()
+    - Set unicode flag on cifs echo request to avoid Mac error
+    - SMB3: Work around mount failure when using SMB3 dialect to Macs
+    - CIFS: fix mapping of SFM_SPACE and SFM_PERIOD
+    - cifs: fix CIFS_IOC_GET_MNT_INFO oops
+    - CIFS: add misssing SFM mapping for doublequote
+    - padata: free correct variable
+    - arm64: KVM: Fix decoding of Rt/Rt2 when trapping AArch32 CP accesses
+    - serial: samsung: Use right device for DMA-mapping calls
+    - serial: omap: fix runtime-pm handling on unbind
+    - serial: omap: suspend device on probe errors
+    - tty: pty: Fix ldisc flush after userspace become aware of the data already
+    - Bluetooth: Fix user channel for 32bit userspace on 64bit kernel
+    - Bluetooth: hci_bcm: add missing tty-device sanity check
+    - Bluetooth: hci_intel: add missing tty-device sanity check
+    - mac80211: pass RX aggregation window size to driver
+    - mac80211: pass block ack session timeout to to driver
+    - mac80211: RX BA support for sta max_rx_aggregation_subframes
+    - wlcore: Pass win_size taken from ieee80211_sta to FW
+    - wlcore: Add RX_BA_WIN_SIZE_CHANGE_EVENT event
+    - ipmi: Fix kernel panic at ipmi_ssif_thread()
+    - Linux 4.4.69
+
+  * Support IPMI system interface on Cavium ThunderX (LP: #1688132)
+    - i2c: octeon: Cleanup kerneldoc comments
+    - i2c: octeon: Cleanup i2c-octeon driver
+    - i2c: octeon: Cleanup resource allocation code
+    - i2c: octeon: Support I2C_M_RECV_LEN
+    - i2c: octeon: Increase retry default and use fixed timeout value
+    - i2c: octeon: Move set-clock and init-lowlevel upward
+    - i2c: octeon: Rename [read|write]_sw to reg_[read|write]
+    - i2c: octeon: Introduce helper functions for register access
+    - i2c: octeon: Remove superfluous check in octeon_i2c_test_iflg
+    - i2c: octeon: Improve error status checking
+    - i2c: octeon: Use i2c recovery framework
+    - i2c: octeon: Add flush writeq helper function
+    - i2c: octeon: Enable High-Level Controller
+    - i2c: octeon: Add support for cn78xx chips
+    - i2c: octeon: Remove zero-length message support
+    - i2c: octeon: Improve performance if interrupt is early
+    - i2c: octeon: Add workaround for broken irqs on CN3860
+    - i2c: octeon: Missing AAK flag in case of I2C_M_RECV_LEN
+    - i2c: octeon: Avoid printk after too long SMBUS message
+    - i2c: octeon: Rename driver to prepare for split
+    - i2c: octeon: Split the driver into two parts
+    - [Config] CONFIG_I2C_THUNDERX=m
+    - i2c: thunderx: Add i2c driver for ThunderX SOC
+    - i2c: thunderx: Add SMBUS alert support
+    - i2c: octeon,thunderx: Move register offsets to struct
+    - i2c: octeon: Sort include files alphabetically
+    - i2c: octeon: Use booleon values for booleon variables
+    - i2c: octeon: thunderx: Add MAINTAINERS entry
+    - i2c: octeon: Fix set SCL recovery function
+    - i2c: octeon: Avoid sending STOP during recovery
+    - i2c: octeon: Fix high-level controller status check
+    - i2c: octeon: thunderx: TWSI software reset in recovery
+    - i2c: octeon: thunderx: Remove double-check after interrupt
+    - i2c: octeon: thunderx: Limit register access retries
+    - i2c: thunderx: Enable HWMON class probing
+
+  * Xenial update to 4.4.68 stable release (LP: #1691418)
+    - 9p: fix a potential acl leak
+    - ARM: 8452/3: PJ4: make coprocessor access sequences buildable in Thumb2 mode
+    - cpupower: Fix turbo frequency reporting for pre-Sandy Bridge cores
+    - powerpc/powernv: Fix opal_exit tracepoint opcode
+    - power: supply: bq24190_charger: Fix irq trigger to IRQF_TRIGGER_FALLING
+    - power: supply: bq24190_charger: Call set_mode_host() on pm_resume()
+    - power: supply: bq24190_charger: Install irq_handler_thread() at end of
+      probe()
+    - power: supply: bq24190_charger: Call power_supply_changed() for relevant
+      component
+    - power: supply: bq24190_charger: Don't read fault register outside
+      irq_handle_thread()
+    - power: supply: bq24190_charger: Handle fault before status on interrupt
+    - leds: ktd2692: avoid harmless maybe-uninitialized warning
+    - ARM: OMAP5 / DRA7: Fix HYP mode boot for thumb2 build
+    - mwifiex: debugfs: Fix (sometimes) off-by-1 SSID print
+    - mwifiex: remove redundant dma padding in AMSDU
+    - mwifiex: Avoid skipping WEP key deletion for AP
+    - x86/ioapic: Restore IO-APIC irq_chip retrigger callback
+    - x86/pci-calgary: Fix iommu_free() comparison of unsigned expression >= 0
+    - clk: Make x86/ conditional on CONFIG_COMMON_CLK
+    - kprobes/x86: Fix kernel panic when certain exception-handling addresses are
+      probed
+    - x86/platform/intel-mid: Correct MSI IRQ line for watchdog device
+    - Revert "KVM: nested VMX: disable perf cpuid reporting"
+    - KVM: nVMX: initialize PML fields in vmcs02
+    - KVM: nVMX: do not leak PML full vmexit to L1
+    - usb: host: ehci-exynos: Decrese node refcount on exynos_ehci_get_phy() error
+      paths
+    - usb: host: ohci-exynos: Decrese node refcount on exynos_ehci_get_phy() error
+      paths
+    - usb: chipidea: Only read/write OTGSC from one place
+    - usb: chipidea: Handle extcon events properly
+    - USB: serial: keyspan_pda: fix receive sanity checks
+    - USB: serial: digi_acceleport: fix incomplete rx sanity check
+    - USB: serial: ssu100: fix control-message error handling
+    - USB: serial: io_edgeport: fix epic-descriptor handling
+    - USB: serial: ti_usb_3410_5052: fix control-message error handling
+    - USB: serial: ark3116: fix open error handling
+    - USB: serial: ftdi_sio: fix latency-timer error handling
+    - USB: serial: quatech2: fix control-message error handling
+    - USB: serial: mct_u232: fix modem-status error handling
+    - USB: serial: io_edgeport: fix descriptor error handling
+    - phy: qcom-usb-hs: Add depends on EXTCON
+    - serial: 8250_omap: Fix probe and remove for PM runtime
+    - scsi: mac_scsi: Fix MAC_SCSI=m option when SCSI=m
+    - MIPS: R2-on-R6 MULTU/MADDU/MSUBU emulation bugfix
+    - brcmfmac: Ensure pointer correctly set if skb data location changes
+    - brcmfmac: Make skb header writable before use
+    - staging: wlan-ng: add missing byte order conversion
+    - staging: emxx_udc: remove incorrect __init annotations
+    - ALSA: hda - Fix deadlock of controller device lock at unbinding
+    - tcp: do not underestimate skb->truesize in tcp_trim_head()
+    - bpf, arm64: fix jit branch offset related to ldimm64
+    - tcp: fix wraparound issue in tcp_lp
+    - tcp: do not inherit fastopen_req from parent
+    - ipv4, ipv6: ensure raw socket message is big enough to hold an IP header
+    - rtnetlink: NUL-terminate IFLA_PHYS_PORT_NAME string
+    - ipv6: initialize route null entry in addrconf_init()
+    - ipv6: reorder ip6_route_dev_notifier after ipv6_dev_notf
+    - bnxt_en: allocate enough space for ->ntp_fltr_bmap
+    - f2fs: sanity check segment count
+    - drm/ttm: fix use-after-free races in vm fault handling
+    - block: get rid of blk_integrity_revalidate()
+    - Linux 4.4.68
+
+  * Keyboard backlight control does not work on some dell laptops.
+    (LP: #1693126)
+    - platform/x86: dell-laptop: Add Latitude 7480 and others to the DMI whitelist
+    - platform/x86: dell-laptop: Add keyboard backlight timeout AC settings
+
+  * Upgrade Redpine WLAN/BT driver to ver. 1.2.RC9 (LP: #1690498)
+    - SAUCE: Redpine: Upgrade to ver. 1.2.RC9
+
+  * exec'ing a setuid binary from a threaded program sometimes fails to setuid
+    (LP: #1672819)
+    - SAUCE: exec: ensure file system accounting in check_unsafe_exec is correct
+
+  * attempts to rename vlans / vlans have addr_assign_type of 0 on kernel 4.4
+    (LP: #1682871)
+    - vlan: Propagate MAC address to VLANs
+
+  * Exar usb-serial doesn't restore baud rate after resume from S3/S4
+    (LP: #1690362)
+    - SAUCE: xr-usb-serial: re-initialise baudrate after resume from S3/S4
+
+  * st_pressure, st_accel IIO drivers fail to detect sensors after reloading
+    kernel modules (LP: #1690310)
+    - SAUCE: (no-up) iio: st_pressure: st_accel: Initialise sensor platform data
+      properly
+
+  * nvidia-docker on ppc64le-ubuntu16.04  issue due to cross-thread naming if
+    !PR_DUMPABLE (LP: #1690225)
+    - procfs: fix pthread cross-thread naming if !PR_DUMPABLE
+
+  * linux xenial derivatives fail to build (LP: #1691814)
+    - [Packaging] Set do_tools_common in common vars
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 20 Jun 2017 15:47:03 +0200
+
+linux (4.4.0-81.104) xenial; urgency=low
+
+  * CVE-2017-1000364
+    - mm: enlarge stack guard gap
+    - mm: do not collapse stack gap into THP
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 08 Jun 2017 15:19:41 +0200
+
+linux (4.4.0-79.100) xenial; urgency=low
+
+  * linux: 4.4.0-79.100 -proposed tracker (LP: #1691180)
+
+  * linux-aws/linux-gke incorrectly producing and using linux-*-tools-
+    common/linux-*-cloud-tools-common (LP: #1688579)
+    - [Config] make linux-tools-common and linux-cloud-tools-common provide linux-
+      gke versions
+    - [Config] make linux-tools-common and linux-cloud-tools-common provide linux-
+      aws versions
+    - [Packaging] prevent linux-*-tools-common from being produced from non linux
+      packages
+
+  * CVE-2017-0605
+    - tracing: Use strlcpy() instead of strcpy() in __trace_find_cmdline()
+
+  * i915-bpo crashes on external hdmi input (LP: #1580272)
+    - SAUCE: i915_bpo: Silence the warning about watermark entries not changing
+
+  * Kernel panics on Xenial when using cgroups and strict CFS limits
+    (LP: #1687512)
+    - sched/fair: Initialize throttle_count for new task-groups lazily
+    - sched/fair: Do not announce throttled next buddy in dequeue_task_fair()
+
+  * bonding - mlx5 - speed changed to 0 after changing ring size  (LP: #1687877)
+    - bonding: allow notifications for bond_set_slave_link_state
+
+  * Xenial update to 4.4.67 stable release (LP: #1689296)
+    - timerfd: Protect the might cancel mechanism proper
+    - Handle mismatched open calls
+    - ASoC: intel: Fix PM and non-atomic crash in bytcr drivers
+    - ALSA: ppc/awacs: shut up maybe-uninitialized warning
+    - drbd: avoid redefinition of BITS_PER_PAGE
+    - mtd: avoid stack overflow in MTD CFI code
+    - net: tg3: avoid uninitialized variable warning
+    - netlink: Allow direct reclaim for fallback allocation
+    - IB/qib: rename BITS_PER_PAGE to RVT_BITS_PER_PAGE
+    - IB/ehca: fix maybe-uninitialized warnings
+    - ext4: require encryption feature for EXT4_IOC_SET_ENCRYPTION_POLICY
+    - ext4 crypto: revalidate dentry after adding or removing the key
+    - ext4 crypto: use dget_parent() in ext4_d_revalidate()
+    - ext4/fscrypto: avoid RCU lookup in d_revalidate
+    - nfsd4: minor NFSv2/v3 write decoding cleanup
+    - nfsd: stricter decoding of write-like NFSv2/v3 ops
+    - dm ioctl: prevent stack leak in dm ioctl call
+    - Linux 4.4.67
+
+  * Precision Rack failed to resume from S4 (LP: #1686061)
+    - x86 / hibernate: Use hlt_play_dead() when resuming from hibernation
+    - x86/boot: Split out kernel_ident_mapping_init()
+    - x86/power/64: Always create temporary identity mapping correctly
+
+  * Xenial update to 4.4.66 stable release (LP: #1688505)
+    - f2fs: do more integrity verification for superblock
+    - xc2028: unlock on error in xc2028_set_config()
+    - ARM: OMAP2+: timer: add probe for clocksources
+    - clk: sunxi: Add apb0 gates for H3
+    - crypto: testmgr - fix out of bound read in __test_aead()
+    - drm/amdgpu: fix array out of bounds
+    - ext4: check if in-inode xattr is corrupted in ext4_expand_extra_isize_ea()
+    - md:raid1: fix a dead loop when read from a WriteMostly disk
+    - MIPS: Fix crash registers on non-crashing CPUs
+    - net: cavium: liquidio: Avoid dma_unmap_single on uninitialized ndata
+    - net_sched: close another race condition in tcf_mirred_release()
+    - RDS: Fix the atomicity for congestion map update
+    - regulator: core: Clear the supply pointer if enabling fails
+    - usb: gadget: f_midi: Fixed a bug when buflen was smaller than wMaxPacketSize
+    - xen/x86: don't lose event interrupts
+    - sparc64: kern_addr_valid regression
+    - sparc64: Fix kernel panic due to erroneous #ifdef surrounding pmd_write()
+    - net: neigh: guard against NULL solicit() method
+    - net: phy: handle state correctly in phy_stop_machine
+    - l2tp: purge socket queues in the .destruct() callback
+    - l2tp: take reference on sessions being dumped
+    - l2tp: fix PPP pseudo-wire auto-loading
+    - net: ipv4: fix multipath RTM_GETROUTE behavior when iif is given
+    - sctp: listen on the sock only when it's state is listening or closed
+    - tcp: clear saved_syn in tcp_disconnect()
+    - dp83640: don't recieve time stamps twice
+    - net: ipv6: RTF_PCPU should not be settable from userspace
+    - netpoll: Check for skb->queue_mapping
+    - ip6mr: fix notification device destruction
+    - macvlan: Fix device ref leak when purging bc_queue
+    - ipv6: check skb->protocol before lookup for nexthop
+    - ipv6: check raw payload size correctly in ioctl
+    - ALSA: firewire-lib: fix inappropriate assignment between signed/unsigned
+      type
+    - ALSA: seq: Don't break snd_use_lock_sync() loop by timeout
+    - MIPS: KGDB: Use kernel context for sleeping threads
+    - MIPS: Avoid BUG warning in arch_check_elf
+    - p9_client_readdir() fix
+    - Input: i8042 - add Clevo P650RS to the i8042 reset list
+    - nfsd: check for oversized NFSv2/v3 arguments
+    - ARCv2: save r30 on kernel entry as gcc uses it for code-gen
+    - ftrace/x86: Fix triple fault with graph tracing and suspend-to-ram
+    - Linux 4.4.66
+
+  * Xenial update to 4.4.65 stable release (LP: #1688483)
+    - tipc: make sure IPv6 header fits in skb headroom
+    - tipc: make dist queue pernet
+    - tipc: re-enable compensation for socket receive buffer double counting
+    - tipc: correct error in node fsm
+    - tty: nozomi: avoid a harmless gcc warning
+    - hostap: avoid uninitialized variable use in hfa384x_get_rid
+    - gfs2: avoid uninitialized variable warning
+    - tipc: fix random link resets while adding a second bearer
+    - tipc: fix socket timer deadlock
+    - xc2028: avoid use after free
+    - netfilter: nfnetlink: correctly validate length of batch messages
+    - tipc: check minimum bearer MTU
+    - vfio/pci: Fix integer overflows, bitmask check
+    - staging/android/ion : fix a race condition in the ion driver
+    - ping: implement proper locking
+    - perf/core: Fix concurrent sys_perf_event_open() vs. 'move_group' race
+    - Linux 4.4.65
+
+  * Xenial update to 4.4.64 stable release (LP: #1687638)
+    - KEYS: Disallow keyrings beginning with '.' to be joined as session keyrings
+    - KEYS: Change the name of the dead type to ".dead" to prevent user access
+    - KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings
+    - tracing: Allocate the snapshot buffer before enabling probe
+    - ring-buffer: Have ring_buffer_iter_empty() return true when empty
+    - cifs: Do not send echoes before Negotiate is complete
+    - CIFS: remove bad_network_name flag
+    - s390/mm: fix CMMA vs KSM vs others
+    - VSOCK: Detach QP check should filter out non matching QPs.
+    - Input: elantech - add Fujitsu Lifebook E547 to force crc_enabled
+    - ACPI / power: Avoid maybe-uninitialized warning
+    - mmc: sdhci-esdhc-imx: increase the pad I/O drive strength for DDR50 card
+    - mac80211: reject ToDS broadcast data frames
+    - ubi/upd: Always flush after prepared for an update
+    - powerpc/kprobe: Fix oops when kprobed on 'stdu' instruction
+    - x86/mce/AMD: Give a name to MCA bank 3 when accessed with legacy MSRs
+    - kvm: arm/arm64: Fix locking for kvm_free_stage2_pgd
+    - x86, pmem: fix broken __copy_user_nocache cache-bypass assumptions
+    - block: fix del_gendisk() vs blkdev_ioctl crash
+    - tipc: fix crash during node removal
+    - Linux 4.4.64
+
+  * Xenial update to 4.4.63 stable release (LP: #1687629)
+    - cgroup, kthread: close race window where new kthreads can be migrated to
+      non-root cgroups
+    - thp: fix MADV_DONTNEED vs clear soft dirty race
+    - drm/nouveau/mpeg: mthd returns true on success now
+    - drm/nouveau/mmu/nv4a: use nv04 mmu rather than the nv44 one
+    - CIFS: store results of cifs_reopen_file to avoid infinite wait
+    - Input: xpad - add support for Razer Wildcat gamepad
+    - perf/x86: Avoid exposing wrong/stale data in intel_pmu_lbr_read_32()
+    - x86/vdso: Ensure vdso32_enabled gets set to valid values only
+    - x86/vdso: Plug race between mapping and ELF header setup
+    - acpi, nfit, libnvdimm: fix interleave set cookie calculation (64-bit
+      comparison)
+    - iscsi-target: Fix TMR reference leak during session shutdown
+    - iscsi-target: Drop work-around for legacy GlobalSAN initiator
+    - scsi: sr: Sanity check returned mode data
+    - scsi: sd: Consider max_xfer_blocks if opt_xfer_blocks is unusable
+    - scsi: sd: Fix capacity calculation with 32-bit sector_t
+    - xen, fbfront: fix connecting to backend
+    - libnvdimm: fix reconfig_mutex, mmap_sem, and jbd2_handle lockdep splat
+    - irqchip/irq-imx-gpcv2: Fix spinlock initialization
+    - ftrace: Fix removing of second function probe
+    - char: Drop bogus dependency of DEVPORT on !M68K
+    - char: lack of bool string made CONFIG_DEVPORT always on
+    - Revert "MIPS: Lantiq: Fix cascaded IRQ setup"
+    - kvm: fix page struct leak in handle_vmon
+    - zram: do not use copy_page with non-page aligned address
+    - powerpc: Disable HFSCR[TM] if TM is not supported
+    - crypto: ahash - Fix EINPROGRESS notification callback
+    - ath9k: fix NULL pointer dereference
+    - dvb-usb-v2: avoid use-after-free
+    - ext4: fix inode checksum calculation problem if i_extra_size is small
+    - platform/x86: acer-wmi: setup accelerometer when machine has appropriate
+      notify event
+    - rtc: tegra: Implement clock handling
+    - mm: Tighten x86 /dev/mem with zeroing reads
+    - dvb-usb: don't use stack for firmware load
+    - dvb-usb-firmware: don't do DMA on stack
+    - virtio-console: avoid DMA from stack
+    - pegasus: Use heap buffers for all register access
+    - rtl8150: Use heap buffers for all register access
+    - catc: Combine failure cleanup code in catc_probe()
+    - catc: Use heap buffer for memory size test
+    - tty/serial: atmel: RS485 half duplex w/DMA: enable RX after TX is done
+    - net: ipv6: check route protocol when deleting routes
+    - MIPS: fix Select HAVE_IRQ_EXIT_ON_IRQ_STACK patch.
+    - Linux 4.4.63
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 17 May 2017 16:44:58 +0200
+
+linux (4.4.0-78.99) xenial; urgency=low
+
+  * linux: 4.4.0-78.99 -proposed tracker (LP: #1686645)
+
+  * Please backport fix to reference leak in cgroup blkio throttle
+    (LP: #1683976)
+    - block: fix module reference leak on put_disk() call for cgroups throttle
+
+  * UbuntuKVM guest crashed while running I/O stress test with Ubuntu kernel
+    4.4.0-47-generic (LP: #1659111)
+    - block: Unhash block device inodes on gendisk destruction
+    - block: Use pointer to backing_dev_info from request_queue
+    - block: Dynamically allocate and refcount backing_dev_info
+    - block: Make blk_get_backing_dev_info() safe without open bdev
+    - block: Get rid of blk_get_backing_dev_info()
+    - block: Move bdev_unhash_inode() after invalidate_partition()
+    - block: Unhash also block device inode for the whole device
+    - block: Revalidate i_bdev reference in bd_aquire()
+    - block: Initialize bd_bdi on inode initialization
+    - block: Move bdi_unregister() to del_gendisk()
+    - block: Allow bdi re-registration
+    - bdi: Fix use-after-free in wb_congested_put()
+    - block: Make del_gendisk() safer for disks without queues
+    - block: Fix bdi assignment to bdev inode when racing with disk delete
+    - bdi: Mark congested->bdi as internal
+    - bdi: Make wb->bdi a proper reference
+    - bdi: Unify bdi->wb_list handling for root wb_writeback
+    - bdi: Shutdown writeback on all cgwbs in cgwb_bdi_destroy()
+    - bdi: Do not wait for cgwbs release in bdi_unregister()
+    - bdi: Rename cgwb_bdi_destroy() to cgwb_bdi_unregister()
+    - block: Fix oops in locked_inode_to_wb_and_lock_list()
+    - kobject: Export kobject_get_unless_zero()
+    - block: Fix oops scsi_disk_get()
+
+  * Touchpad not working correctly after kernel upgrade (LP: #1662589)
+    - Input: ALPS - fix V8+ protocol handling (73 03 28)
+
+  * Xenial update to v4.4.62 stable release (LP: #1683728)
+    - drm/i915: Avoid tweaking evaluation thresholds on Baytrail v3
+    - drm/i915: Stop using RP_DOWN_EI on Baytrail
+    - usb: dwc3: gadget: delay unmap of bounced requests
+    - mtd: bcm47xxpart: fix parsing first block after aligned TRX
+    - MIPS: Introduce irq_stack
+    - MIPS: Stack unwinding while on IRQ stack
+    - MIPS: Only change $28 to thread_info if coming from user mode
+    - MIPS: Switch to the irq_stack in interrupts
+    - MIPS: Select HAVE_IRQ_EXIT_ON_IRQ_STACK
+    - MIPS: IRQ Stack: Fix erroneous jal to plat_irq_dispatch
+    - crypto: caam - fix RNG deinstantiation error checking
+    - Linux 4.4.62
+
+  * ifup service of network device stay active after driver stop (LP: #1672144)
+    - net: use net->count to check whether a netns is alive or not
+
+  * [Hyper-V] mkfs regression in kernel 4.4+ (LP: #1682215)
+    - block: relax check on sg gap
+
+  * [Feature] KBL: intel_powerclamp driver support (LP: #1591641)
+    - thermal/powerclamp: remove cpu whitelist
+    - thermal/powerclamp: correct cpu support check
+    - thermal/powerclamp: add back module device table
+
+  * sysfs channel reads of lps22hb pressure sensor are stale (LP: #1682103)
+    - iio: st_pressure: initialize lps22hb bootime
+
+  * Backlight control does not work and there are no entries in
+    /sys/class/backlight (LP: #1667323)
+    - Revert "ACPI / video: Add force_native quirk for HP Pavilion dv6"
+
+  * [Feature] KBL: intel_rapl driver support (LP: #1591640)
+    - powercap/intel_rapl: Add support for Kabylake
+
+  * Xenial update to v4.4.61 stable release (LP: #1682140)
+    - drm/vmwgfx: Type-check lookups of fence objects
+    - drm/vmwgfx: NULL pointer dereference in vmw_surface_define_ioctl()
+    - drm/vmwgfx: avoid calling vzalloc with a 0 size in vmw_get_cap_3d_ioctl()
+    - drm/ttm, drm/vmwgfx: Relax permission checking when opening surfaces
+    - drm/vmwgfx: Remove getparam error message
+    - drm/vmwgfx: fix integer overflow in vmw_surface_define_ioctl()
+    - sysfs: be careful of error returns from ops->show()
+    - staging: android: ashmem: lseek failed due to no FMODE_LSEEK.
+    - arm/arm64: KVM: Take mmap_sem in stage2_unmap_vm
+    - arm/arm64: KVM: Take mmap_sem in kvm_arch_prepare_memory_region
+    - iio: bmg160: reset chip when probing
+    - Reset TreeId to zero on SMB2 TREE_CONNECT
+    - ptrace: fix PTRACE_LISTEN race corrupting task->state
+    - ring-buffer: Fix return value check in test_ringbuffer()
+    - metag/usercopy: Drop unused macros
+    - metag/usercopy: Fix alignment error checking
+    - metag/usercopy: Add early abort to copy_to_user
+    - metag/usercopy: Zero rest of buffer from copy_from_user
+    - metag/usercopy: Set flags before ADDZ
+    - metag/usercopy: Fix src fixup in from user rapf loops
+    - metag/usercopy: Add missing fixups
+    - powerpc/mm: Add missing global TLB invalidate if cxl is active
+    - powerpc: Don't try to fix up misaligned load-with-reservation instructions
+    - nios2: reserve boot memory for device tree
+    - s390/decompressor: fix initrd corruption caused by bss clear
+    - s390/uaccess: get_user() should zero on failure (again)
+    - MIPS: Force o32 fp64 support on 32bit MIPS64r6 kernels
+    - MIPS: ralink: Fix typos in rt3883 pinctrl
+    - MIPS: End spinlocks with .insn
+    - MIPS: Lantiq: fix missing xbar kernel panic
+    - MIPS: Flush wrong invalid FTLB entry for huge page
+    - mm/mempolicy.c: fix error handling in set_mempolicy and mbind.
+    - Linux 4.4.61
+
+  * Xenial update to v4.4.60 stable release (LP: #1681862)
+    - libceph: force GFP_NOIO for socket allocations
+    - xen/setup: Don't relocate p2m over existing one
+    - scsi: mpt3sas: fix hang on ata passthrough commands
+    - scsi: sg: check length passed to SG_NEXT_CMD_LEN
+    - scsi: libsas: fix ata xfer length
+    - ALSA: seq: Fix race during FIFO resize
+    - ALSA: hda - fix a problem for lineout on a Dell AIO machine
+    - ASoC: atmel-classd: fix audio clock rate
+    - ACPI: Fix incompatibility with mcount-based function graph tracing
+    - ACPI: Do not create a platform_device for IOAPIC/IOxAPIC
+    - tty/serial: atmel: fix race condition (TX+DMA)
+    - tty/serial: atmel: fix TX path in atmel_console_write()
+    - USB: fix linked-list corruption in rh_call_control()
+    - KVM: x86: clear bus pointer when destroyed
+    - drm/radeon: Override fpfn for all VRAM placements in radeon_evict_flags
+    - mm, hugetlb: use pte_present() instead of pmd_present() in follow_huge_pmd()
+    - MIPS: Lantiq: Fix cascaded IRQ setup
+    - rtc: s35390a: fix reading out alarm
+    - rtc: s35390a: make sure all members in the output are set
+    - rtc: s35390a: implement reset routine as suggested by the reference
+    - rtc: s35390a: improve irq handling
+    - KVM: kvm_io_bus_unregister_dev() should never fail
+    - power: reset: at91-poweroff: timely shutdown LPDDR memories
+    - blk: improve order of bio handling in generic_make_request()
+    - blk: Ensure users for current->bio_list can see the full list.
+    - padata: avoid race in reordering
+    - Linux 4.4.60
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 27 Apr 2017 10:24:08 -0300
+
+linux (4.4.0-77.98) xenial; urgency=low
+
+  * linux: 4.4.0-77.98 -proposed tracker (LP: #1686040)
+
+  * [Hyper-V][SAUCE] pci-hyperv: Use only 16 bit integer for PCI domain
+    (LP: #1684971)
+    - SAUCE: pci-hyperv: Use only 16 bit integer for PCI domain
+
+  * Upgrade Redpine WLAN/BT driver to ver. 1.2.RC4 (LP: #1669672)
+    - SAUCE: sdhci: use PCI ID to identify Dell IoT gateways
+    - SAUCE: Redpine: Upgrade to ver. 1.2.RC4
+    - [Config] Update CONFIG_VEN_RSI_* configs
+    - SAUCE: Redpine: add copyright to kernel packages
+
+  * Fix RX fail issue on Exar USB serial driver after resume from S3/S4
+    (LP: #1685133)
+    - SAUCE: xr-usb-serial: Update driver for Exar USB serial ports
+
+  * Miscellaneous Ubuntu changes
+    - [Config] updating configs to match redpine driver changes
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 25 Apr 2017 19:32:01 +0200
+
+linux (4.4.0-75.96) xenial; urgency=low
+
+  * linux: 4.4.0-75.96 -proposed tracker (LP: #1684441)
+
+  * [Hyper-V] hv: util: move waiting for release to hv_utils_transport itself
+    (LP: #1682561)
+    - Drivers: hv: util: move waiting for release to hv_utils_transport itself
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 19 Apr 2017 17:14:23 +0200
+
+linux (4.4.0-74.95) xenial; urgency=low
+
+  * linux: 4.4.0-74.95 -proposed tracker (LP: #1682041)
+
+  * [Hyper-V] hv: vmbus: Raise retry/wait limits in vmbus_post_msg()
+    (LP: #1681893)
+    - Drivers: hv: vmbus: Raise retry/wait limits in vmbus_post_msg()
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 12 Apr 2017 10:30:01 +0200
+
+linux (4.4.0-73.94) xenial; urgency=low
+
+  * linux: 4.4.0-73.94 -proposed tracker (LP: #1680416)
+
+  * CVE-2017-6353
+    - sctp: deny peeloff operation on asocs with threads sleeping on it
+
+  * vfat: missing iso8859-1 charset (LP: #1677230)
+    - [Config] NLS_ISO8859_1=y
+
+  * Regression: KVM modules should be on main kernel package (LP: #1678099)
+    - [Config] powerpc: Add kvm-hv and kvm-pr to the generic inclusion list
+
+  * linux-lts-xenial 4.4.0-63.84~14.04.2 ADT test failure with linux-lts-xenial
+    4.4.0-63.84~14.04.2 (LP: #1664912)
+    - SAUCE: apparmor: fix link auditing failure due to, uninitialized var
+
+  * regession tests failing after stackprofile test is run (LP: #1661030)
+    - SAUCE: fix regression with domain change in complain mode
+
+  * Permission denied and inconsistent behavior in complain mode with 'ip netns
+    list' command (LP: #1648903)
+    - SAUCE: fix regression with domain change in complain mode
+
+  * unexpected errno=13 and disconnected path when trying to open /proc/1/ns/mnt
+    from a unshared mount namespace (LP: #1656121)
+    - SAUCE: apparmor: null profiles should inherit parent control flags
+
+  * apparmor refcount leak of profile namespace when removing profiles
+    (LP: #1660849)
+    - SAUCE: apparmor: fix ns ref count link when removing profiles from policy
+
+  * tor in lxd: apparmor="DENIED" operation="change_onexec"
+    namespace="root//CONTAINERNAME_<var-lib-lxd>" profile="unconfined"
+    name="system_tor" (LP: #1648143)
+    - SAUCE: apparmor: Fix no_new_privs blocking change_onexec when using stacked
+      namespaces
+
+  * apparmor oops in bind_mnt when dev_path lookup fails (LP: #1660840)
+    - SAUCE: apparmor: fix oops in bind_mnt when dev_path lookup fails
+
+  * apparmor  auditing denied access of special apparmor .null fi\ le
+    (LP: #1660836)
+    - SAUCE: apparmor: Don't audit denied access of special apparmor .null file
+
+  * apparmor label leak when new label is unused (LP: #1660834)
+    - SAUCE: apparmor: fix label leak when new label is unused
+
+  * apparmor reference count bug in label_merge_insert() (LP: #1660833)
+    - SAUCE: apparmor: fix reference count bug in label_merge_insert()
+
+  * apparmor's raw_data file in securityfs is sometimes truncated (LP: #1638996)
+    - SAUCE: apparmor: fix replacement race in reading rawdata
+
+  * unix domain socket cross permission check failing with nested namespaces
+    (LP: #1660832)
+    - SAUCE: apparmor: fix cross ns perm of unix domain sockets
+
+  * Xenial update to v4.4.59 stable release (LP: #1678960)
+    - xfrm: policy: init locks early
+    - virtio_balloon: init 1st buffer in stats vq
+    - pinctrl: qcom: Don't clear status bit on irq_unmask
+    - c6x/ptrace: Remove useless PTRACE_SETREGSET implementation
+    - h8300/ptrace: Fix incorrect register transfer count
+    - mips/ptrace: Preserve previous registers for short regset write
+    - sparc/ptrace: Preserve previous registers for short regset write
+    - metag/ptrace: Preserve previous registers for short regset write
+    - metag/ptrace: Provide default TXSTATUS for short NT_PRSTATUS
+    - metag/ptrace: Reject partial NT_METAG_RPIPE writes
+    - fscrypt: remove broken support for detecting keyring key revocation
+    - sched/rt: Add a missing rescheduling point
+    - Linux 4.4.59
+
+  * Update ENA driver to 1.1.2 from net-next (LP: #1664312)
+    - net: ena: Remove unnecessary pci_set_drvdata()
+    - net: ena: Fix error return code in ena_device_init()
+    - net: ena: change the return type of ena_set_push_mode() to be void.
+    - net: ena: use setup_timer() and mod_timer()
+    - net/ena: remove ntuple filter support from device feature list
+    - net/ena: fix queues number calculation
+    - net/ena: fix ethtool RSS flow configuration
+    - net/ena: fix RSS default hash configuration
+    - net/ena: fix NULL dereference when removing the driver after device reset
+      failed
+    - net/ena: refactor ena_get_stats64 to be atomic context safe
+    - net/ena: fix potential access to freed memory during device reset
+    - net/ena: use READ_ONCE to access completion descriptors
+    - net/ena: reduce the severity of ena printouts
+    - net/ena: change driver's default timeouts
+    - net/ena: change condition for host attribute configuration
+    - net/ena: update driver version to 1.1.2
+
+  * Xenial update to v4.4.58 stable release (LP: #1677600)
+    - net/openvswitch: Set the ipv6 source tunnel key address attribute correctly
+    - net: bcmgenet: Do not suspend PHY if Wake-on-LAN is enabled
+    - net: properly release sk_frag.page
+    - amd-xgbe: Fix jumbo MTU processing on newer hardware
+    - net: unix: properly re-increment inflight counter of GC discarded candidates
+    - net/mlx5: Increase number of max QPs in default profile
+    - net/mlx5e: Count LRO packets correctly
+    - net: bcmgenet: remove bcmgenet_internal_phy_setup()
+    - ipv4: provide stronger user input validation in nl_fib_input()
+    - socket, bpf: fix sk_filter use after free in sk_clone_lock
+    - tcp: initialize icsk_ack.lrcvtime at session start time
+    - Input: elan_i2c - add ASUS EeeBook X205TA special touchpad fw
+    - Input: i8042 - add noloop quirk for Dell Embedded Box PC 3000
+    - Input: iforce - validate number of endpoints before using them
+    - Input: ims-pcu - validate number of endpoints before using them
+    - Input: hanwang - validate number of endpoints before using them
+    - Input: yealink - validate number of endpoints before using them
+    - Input: cm109 - validate number of endpoints before using them
+    - Input: kbtab - validate number of endpoints before using them
+    - Input: sur40 - validate number of endpoints before using them
+    - ALSA: seq: Fix racy cell insertions during snd_seq_pool_done()
+    - ALSA: ctxfi: Fix the incorrect check of dma_set_mask() call
+    - ALSA: hda - Adding a group of pin definition to fix headset problem
+    - USB: serial: option: add Quectel UC15, UC20, EC21, and EC25 modems
+    - USB: serial: qcserial: add Dell DW5811e
+    - ACM gadget: fix endianness in notifications
+    - usb: gadget: f_uvc: Fix SuperSpeed companion descriptor's wBytesPerInterval
+    - usb-core: Add LINEAR_FRAME_INTR_BINTERVAL USB quirk
+    - USB: uss720: fix NULL-deref at probe
+    - USB: lvtest: fix NULL-deref at probe
+    - USB: idmouse: fix NULL-deref at probe
+    - USB: wusbcore: fix NULL-deref at probe
+    - usb: musb: cppi41: don't check early-TX-interrupt for Isoch transfer
+    - usb: hub: Fix crash after failure to read BOS descriptor
+    - uwb: i1480-dfu: fix NULL-deref at probe
+    - uwb: hwa-rc: fix NULL-deref at probe
+    - mmc: ushc: fix NULL-deref at probe
+    - iio: adc: ti_am335x_adc: fix fifo overrun recovery
+    - iio: hid-sensor-trigger: Change get poll value function order to avoid
+      sensor properties losing after resume from S3
+    - parport: fix attempt to write duplicate procfiles
+    - ext4: mark inode dirty after converting inline directory
+    - mmc: sdhci: Do not disable interrupts while waiting for clock
+    - xen/acpi: upload PM state from init-domain to Xen
+    - iommu/vt-d: Fix NULL pointer dereference in device_to_iommu
+    - ARM: at91: pm: cpu_idle: switch DDR to power-down mode
+    - ARM: dts: at91: sama5d2: add dma properties to UART nodes
+    - cpufreq: Restore policy min/max limits on CPU online
+    - raid10: increment write counter after bio is split
+    - libceph: don't set weight to IN when OSD is destroyed
+    - xfs: don't allow di_size with high bit set
+    - xfs: fix up xfs_swap_extent_forks inline extent handling
+    - nl80211: fix dumpit error path RTNL deadlocks
+    - USB: usbtmc: add missing endpoint sanity check
+    - xfs: clear _XBF_PAGES from buffers when readahead page
+    - igb: add i211 to i210 PHY workaround
+    - vfio/spapr: Postpone allocation of userspace version of TCE table
+    - block: allow WRITE_SAME commands with the SG_IO ioctl
+    - fbcon: Fix vc attr at deinit
+    - crypto: algif_hash - avoid zero-sized array
+    - Linux 4.4.58
+
+  * PS/2 mouse does not work on Dell embedded computer (LP: #1591053)
+    - Input: i8042 - add noloop quirk for Dell Embedded Box PC 3000
+
+  * Xenial update to v4.4.57 stable release (LP: #1676424)
+    - give up on gcc ilog2() constant optimizations
+    - perf/core: Fix event inheritance on fork()
+    - cpufreq: Fix and clean up show_cpuinfo_cur_freq()
+    - powerpc/boot: Fix zImage TOC alignment
+    - md/raid1/10: fix potential deadlock
+    - target/pscsi: Fix TYPE_TAPE + TYPE_MEDIMUM_CHANGER export
+    - scsi: lpfc: Add shutdown method for kexec
+    - scsi: libiscsi: add lock around task lists to fix list corruption regression
+    - target: Fix VERIFY_16 handling in sbc_parse_cdb
+    - isdn/gigaset: fix NULL-deref at probe
+    - gfs2: Avoid alignment hole in struct lm_lockname
+    - percpu: acquire pcpu_lock when updating pcpu_nr_empty_pop_pages
+    - ext4: fix fencepost in s_first_meta_bg validation
+    - Linux 4.4.57
+
+  * Xenial update to v4.4.56 stable release (LP: #1675789)
+    - netlink: remove mmapped netlink support
+    - [Config] CONFIG_NETLINK_MMAP disappeared
+    - vxlan: correctly validate VXLAN ID against VXLAN_N_VID
+    - vti6: return GRE_KEY for vti6
+    - ipv4: mask tos for input route
+    - l2tp: avoid use-after-free caused by l2tp_ip_backlog_recv
+    - net: don't call strlen() on the user buffer in packet_bind_spkt()
+    - net: net_enable_timestamp() can be called from irq contexts
+    - dccp: Unlock sock before calling sk_free()
+    - tcp: fix various issues for sockets morphing to listen state
+    - net: fix socket refcounting in skb_complete_wifi_ack()
+    - net: fix socket refcounting in skb_complete_tx_timestamp()
+    - dccp: fix use-after-free in dccp_feat_activate_values
+    - vrf: Fix use-after-free in vrf_xmit
+    - uapi: fix linux/packet_diag.h userspace compilation error
+    - act_connmark: avoid crashing on malformed nlattrs with null parms
+    - mpls: Send route delete notifications when router module is unloaded
+    - ipv6: make ECMP route replacement less greedy
+    - ipv6: avoid write to a possibly cloned skb
+    - dccp/tcp: fix routing redirect race
+    - dccp: fix memory leak during tear-down of unsuccessful connection request
+    - net sched actions: decrement module reference count after table flush.
+    - fscrypt: fix renaming and linking special files
+    - fscrypto: lock inode while setting encryption policy
+    - x86/kasan: Fix boot with KASAN=y and PROFILE_ANNOTATED_BRANCHES=y
+    - x86/perf: Fix CR4.PCE propagation to use active_mm instead of mm
+    - futex: Fix potential use-after-free in FUTEX_REQUEUE_PI
+    - futex: Add missing error handling to FUTEX_REQUEUE_PI
+    - Linux 4.4.56
+
+  * Kernel linux-image-4.4.0-67-generic prevent the boot on Microsoft Hyper-v
+    2012r2 Gen2 VM (LP: #1674635)
+    - scsi: storvsc: Workaround for virtual DVD SCSI version
+
+  * [Hyper-V][Mellanox] net/mlx4_core: Avoid delays during VF driver device
+    shutdown (LP: #1672785)
+    - net/mlx4_core: Avoid delays during VF driver device shutdown
+
+  * Channel data values for IIO based st_sensors (st_accel, st_pressure) are
+    incorrect (LP: #1676356)
+    - iio: core: added support for IIO_VAL_INT
+    - iio: st_sensors: simplify buffer address handling
+    - iio: st_sensors: read each channel individually
+    - iio:st_sensors: emulate SMBus block read if needed
+    - iio:st_sensors: align on storagebits boundaries
+    - iio:st_pressure: temperature triggered buffering
+    - iio:st_pressure: clean useless static channel initializers
+    - iio: st_pressure: Fix data sign
+
+  * Enable lspcon on i915 (LP: #1676747)
+    - drm: Helper for lspcon in drm_dp_dual_mode
+    - drm/i915: Add lspcon support for I915 driver
+    - drm/i915: Parse VBT data for lspcon
+    - drm/i915: Enable lspcon initialization
+    - drm/i915: Add lspcon resume function
+
+  * stress_smoke_test passing and exiting rc=9 (linux 4.9.0-12.13 ADT test
+    failure with linux 4.9.0-12.13) (LP: #1658633)
+    - ext4: lock the xattr block before checksuming it
+
+  * Fix line-out port noise on Baytrail-I with RT5660 based sound card
+    (LP: #1675327)
+    - SAUCE: (no-up): ASoC: Intel: bytcr-rt5660: Fix noise in line-out
+
+  * Kernel 4.4.0-67 Defaults to ACPI-cpufreq rather than P-State - Dell
+    Precision 5520  (LP: #1674390)
+    - cpufreq: intel_pstate: Enable HWP by default
+
+  * ip_rcv_finish() NULL pointer kernel panic (LP: #1672470)
+    - bridge: drop netfilter fake rtable unconditionally
+
+  * dm-queue-length module is not included in installer/initramfs (LP: #1673350)
+    - d-i: Also add dm-queue-length to multipath modules
+
+  * Broadcom bluetooth modules sometimes fail to initialize (LP: #1483101)
+    - Bluetooth: btbcm: Add a delay for module reset
+
+  * Need support of Broadcom bluetooth device [413c:8143] (LP: #1166113)
+    - Bluetooth: btusb: Add support for 413c:8143
+
+  * i40e Intel X710 error during device probe prevents link set up and ip
+    association (LP: #1672550)
+    - i40e: check for and deal with non-contiguous TCs
+
+  * CIFS: Call echo service immediately after socket reconnect (LP: #1669941)
+    - Call echo service immediately after socket reconnect
+
+  * FC Adapter (LPe32000-based) prints "iotag out of range", goes offline, and
+    delays boot a lot (Ubuntu17.04/Emulex/lpfc)) (LP: #1670490)
+    - scsi: lpfc: Add missing memory barrier
+
+  * No C-State Deeper than C3 utilized by Kaby Lake 7820HQ in Precision 5520
+    (LP: #1672439)
+    - intel_idle: Add KBL support
+
+  * [Hyper-V] Missing PCI patches breaking SR-IOV hot remove (LP: #1670518)
+    - PCI: hv: Fix hv_pci_remove() for hot-remove
+    - PCI: hv: Delete the device earlier from hbus->children for hot-remove
+    - PCI: hv: Make unnecessarily global IRQ masking functions static
+    - PCI: hv: Allocate physically contiguous hypercall params buffer
+
+  * Xenial update to v4.4.55 stable release (LP: #1674292)
+    - USB: serial: digi_acceleport: fix OOB data sanity check
+    - USB: serial: digi_acceleport: fix OOB-event processing
+    - crypto: improve gcc optimization flags for serpent and wp512
+    - MIPS: Update defconfigs for NF_CT_PROTO_DCCP/UDPLITE change
+    - MIPS: ip27: Disable qlge driver in defconfig
+    - MIPS: Update ip27_defconfig for SCSI_DH change
+    - MIPS: ip22: Fix ip28 build for modern gcc
+    - MIPS: Update lemote2f_defconfig for CPU_FREQ_STAT change
+    - mtd: pmcmsp: use kstrndup instead of kmalloc+strncpy
+    - MIPS: ralink: Cosmetic change to prom_init().
+    - MIPS: ralink: Remove unused rt*_wdt_reset functions
+    - cpmac: remove hopeless #warning
+    - mm: memcontrol: avoid unused function warning
+    - MIPS: DEC: Avoid la pseudo-instruction in delay slots
+    - MIPS: Netlogic: Fix CP0_EBASE redefinition warnings
+    - tracing: Add #undef to fix compile error
+    - powerpc: Emulation support for load/store instructions on LE
+    - usb: gadget: dummy_hcd: clear usb_gadget region before registration
+    - usb: dwc3: gadget: make Set Endpoint Configuration macros safe
+    - usb: gadget: function: f_fs: pass companion descriptor along
+    - usb: host: xhci-dbg: HCIVERSION should be a binary number
+    - usb: host: xhci-plat: Fix timeout on removal of hot pluggable xhci
+      controllers
+    - USB: serial: safe_serial: fix information leak in completion handler
+    - USB: serial: omninet: fix reference leaks at open
+    - USB: iowarrior: fix NULL-deref at probe
+    - USB: iowarrior: fix NULL-deref in write
+    - USB: serial: io_ti: fix NULL-deref in interrupt callback
+    - USB: serial: io_ti: fix information leak in completion handler
+    - serial: samsung: Continue to work if DMA request fails
+    - mvsas: fix misleading indentation
+    - KVM: s390: Fix guest migration for huge guests resulting in panic
+    - s390/kdump: Use "LINUX" ELF note name instead of "CORE"
+    - nfit, libnvdimm: fix interleave set cookie calculation
+    - dm: flush queued bios when process blocks to avoid deadlock
+    - ext4: don't BUG when truncating encrypted inodes on the orphan list
+    - Linux 4.4.55
+
+  * Xenial update to v4.4.54 stable release (LP: #1673541)
+    - serial: 8250_pci: Add MKS Tenta SCOM-0800 and SCOM-0801 cards
+    - KVM: s390: Disable dirty log retrieval for UCONTROL guests
+    - KVM: VMX: use correct vmcs_read/write for guest segment selector/base
+    - Bluetooth: Add another AR3012 04ca:3018 device
+    - s390/qdio: clear DSCI prior to scanning multiple input queues
+    - s390/dcssblk: fix device size calculation in dcssblk_direct_access()
+    - s390: TASK_SIZE for kernel threads
+    - s390: make setup_randomness work
+    - s390: use correct input data address for setup_randomness
+    - net: mvpp2: fix DMA address calculation in mvpp2_txq_inc_put()
+    - mnt: Tuck mounts under others instead of creating shadow/side mounts.
+    - IB/ipoib: Fix deadlock between rmmod and set_mode
+    - IB/IPoIB: Add destination address when re-queue packet
+    - IB/srp: Avoid that duplicate responses trigger a kernel bug
+    - IB/srp: Fix race conditions related to task management
+    - ktest: Fix child exit code processing
+    - ceph: remove req from unsafe list when unregistering it
+    - target: Fix NULL dereference during LUN lookup + active I/O shutdown
+    - nlm: Ensure callback code also checks that the files match
+    - pwm: pca9685: Fix period change with same duty cycle
+    - xtensa: move parse_tag_fdt out of #ifdef CONFIG_BLK_DEV_INITRD
+    - mac80211: flush delayed work when entering suspend
+    - drm/amdgpu: add more cases to DCE11 possible crtc mask setup
+    - drm/ast: Fix test for VGA enabled
+    - drm/ast: Call open_key before enable_mmio in POST code
+    - drm/ast: Fix AST2400 POST failure without BMC FW or VBIOS
+    - drm/edid: Add EDID_QUIRK_FORCE_8BPC quirk for Rotel RSX-1058
+    - drm/ttm: Make sure BOs being swapped out are cacheable
+    - drm/atomic: fix an error code in mode_fixup()
+    - fakelb: fix schedule while atomic
+    - drm/i915/dsi: Do not clear DPOUNIT_CLOCK_GATE_DISABLE from
+      vlv_init_display_clock_gating
+    - libceph: use BUG() instead of BUG_ON(1)
+    - fat: fix using uninitialized fields of fat_inode/fsinfo_inode
+    - drivers: hv: Turn off write permission on the hypercall page
+    - Linux 4.4.54
+
+  * Xenial update to v4.4.53 stable release (LP: #1673538)
+    - samples: move mic/mpssd example code from Documentation
+    - MIPS: Fix special case in 64 bit IP checksumming.
+    - MIPS: BCM47XX: Fix button inversion for Asus WL-500W
+    - MIPS: OCTEON: Fix copy_from_user fault handling for large buffers
+    - MIPS: Lantiq: Keep ethernet enabled during boot
+    - MIPS: Clear ISA bit correctly in get_frame_info()
+    - MIPS: Prevent unaligned accesses during stack unwinding
+    - MIPS: Fix get_frame_info() handling of microMIPS function size
+    - MIPS: Fix is_jump_ins() handling of 16b microMIPS instructions
+    - MIPS: Calculate microMIPS ra properly when unwinding the stack
+    - MIPS: Handle microMIPS jumps in the same way as MIPS32/MIPS64 jumps
+    - am437x-vpfe: always assign bpp variable
+    - uvcvideo: Fix a wrong macro
+    - media: fix dm1105.c build error
+    - ARM: at91: define LPDDR types
+    - ARM: dts: at91: Enable DMA on sama5d4_xplained console
+    - ARM: dts: at91: Enable DMA on sama5d2_xplained console
+    - ALSA: hda/realtek - Cannot adjust speaker's volume on a Dell AIO
+    - ALSA: hda - fix Lewisburg audio issue
+    - ALSA: timer: Reject user params with too small ticks
+    - ALSA: ctxfi: Fallback DMA mask to 32bit
+    - ALSA: seq: Fix link corruption by event error handling
+    - ALSA: hda - Add subwoofer support for Dell Inspiron 17 7000 Gaming
+    - ALSA: hda - Fix micmute hotkey problem for a lenovo AIO machine
+    - staging: rtl: fix possible NULL pointer dereference
+    - regulator: Fix regulator_summary for deviceless consumers
+    - iommu/vt-d: Fix some macros that are incorrectly specified in intel-iommu
+    - iommu/vt-d: Tylersburg isoch identity map check is done too late.
+    - mm/page_alloc: fix nodes for reclaim in fast path
+    - mm: vmpressure: fix sending wrong events on underflow
+    - mm: do not access page->mapping directly on page_endio
+    - ipc/shm: Fix shmat mmap nil-page protection
+    - dm cache: fix corruption seen when using cache > 2TB
+    - dm stats: fix a leaked s->histogram_boundaries array
+    - Revert "scsi: storvsc: properly set residual data length on errors"
+    - scsi: storvsc: properly set residual data length on errors
+    - scsi: aacraid: Reorder Adapter status check
+    - scsi: use 'scsi_device_from_queue()' for scsi_dh
+    - sd: get disk reference in sd_check_events()
+    - Fix: Disable sys_membarrier when nohz_full is enabled
+    - jbd2: don't leak modified metadata buffers on an aborted journal
+    - block/loop: fix race between I/O and set_status
+    - loop: fix LO_FLAGS_PARTSCAN hang
+    - ext4: Include forgotten start block on fallocate insert range
+    - ext4: do not polute the extents cache while shifting extents
+    - ext4: trim allocation requests to group size
+    - ext4: fix data corruption in data=journal mode
+    - ext4: fix inline data error paths
+    - ext4: preserve the needs_recovery flag when the journal is aborted
+    - ext4: return EROFS if device is r/o and journal replay is needed
+    - samples/seccomp: fix 64-bit comparison macros
+    - target: Obtain se_node_acl->acl_kref during get_initiator_node_acl
+    - target: Fix multi-session dynamic se_node_acl double free OOPs
+    - ath5k: drop bogus warning on drv_set_key with unsupported cipher
+    - ath9k: fix race condition in enabling/disabling IRQs
+    - ath9k: use correct OTP register offsets for the AR9340 and AR9550
+    - crypto: testmgr - Pad aes_ccm_enc_tv_template vector
+    - fuse: add missing FR_FORCE
+    - arm/arm64: KVM: Enforce unconditional flush to PoC when mapping to stage-2
+    - iio: pressure: mpl115: do not rely on structure field ordering
+    - iio: pressure: mpl3115: do not rely on structure field ordering
+    - can: usb_8dev: Fix memory leak of priv->cmd_msg_buffer
+    - w1: don't leak refcount on slave attach failure in w1_attach_slave_device()
+    - w1: ds2490: USB transfer buffers need to be DMAable
+    - usb: musb: da8xx: Remove CPPI 3.0 quirk and methods
+    - usb: host: xhci: plat: check hcc_params after add hcd
+    - usb: gadget: udc: fsl: Add missing complete function.
+    - hv: allocate synic pages for all present CPUs
+    - hv: init percpu_list in hv_synic_alloc()
+    - Drivers: hv: util: kvp: Fix a rescind processing issue
+    - Drivers: hv: util: Fcopy: Fix a rescind processing issue
+    - Drivers: hv: util: Backup: Fix a rescind processing issue
+    - RDMA/core: Fix incorrect structure packing for booleans
+    - rdma_cm: fail iwarp accepts w/o connection params
+    - gfs2: Add missing rcu locking for glock lookup
+    - rtlwifi: Fix alignment issues
+    - rtlwifi: rtl8192c-common: Fix "BUG: KASAN:
+    - nfsd: minor nfsd_setattr cleanup
+    - nfsd: special case truncates some more
+    - NFSv4: Fix memory and state leak in _nfs4_open_and_get_state
+    - NFSv4: fix getacl head length estimation
+    - NFSv4: fix getacl ERANGE for some ACL buffer sizes
+    - rtc: sun6i: Add some locking
+    - rtc: sun6i: Switch to the external oscillator
+    - md linear: fix a race between linear_add() and linear_congested()
+    - bcma: use (get|put)_device when probing/removing device driver
+    - dmaengine: ipu: Make sure the interrupt routine checks all interrupts.
+    - powerpc/xmon: Fix data-breakpoint
+    - MIPS: IP22: Reformat inline assembler code to modern standards.
+    - MIPS: IP22: Fix build error due to binutils 2.25 uselessnes.
+    - scsi: lpfc: Correct WQ creation for pagesize
+    - Linux 4.4.53
+
+  * move aufs.ko from -extra to linux-image package (LP: #1673498)
+    - [config] aufs.ko moved to linux-image package
+
+  * [Xenial] net: better skb->sender_cpu and skb->napi_id cohabitation
+    (LP: #1673303)
+    - net: better skb->sender_cpu and skb->napi_id cohabitation
+
+  * lsattr 32bit does not work on 64bit kernel (Inappropriate ioctl error)
+    (LP: #1619918)
+    - btrfs: fix btrfs_compat_ioctl failures on non-compat ioctls
+
+  * linux-tools-common should Depends: lsb-release (LP: #1667571)
+    - [Config] linux-tools-common depends on lsb-release
+
+  * Add Use-After-Free Patch for Ubuntu16.10 - EEH on BELL3 adapter fails to
+    recover (serial/tty) (LP: #1669153)
+    - 8250_pci: Fix potential use-after-free in error path
+
+  * [Hyper-V] pci-hyperv: Use device serial number as PCI domain (LP: #1667527)
+    - net/mlx4_core: Use cq quota in SRIOV when creating completion EQs
+    - PCI: hv: Use device serial number as PCI domain
+
+  * [Xenial - 16.04 ]Bonding driver - stack corruption when trying to copy 20
+    bytes to a sockaddr (LP: #1668042)
+    - net/bonding: Enforce active-backup policy for IPoIB bonds
+
+  * Request to backport cxlflash patches to Xenial SRU stream (LP: #1623750)
+    - scsi: cxlflash: Scan host only after the port is ready for I/O
+    - scsi: cxlflash: Remove the device cleanly in the system shutdown path
+    - scsi: cxlflash: Fix to avoid EEH and host reset collisions
+    - scsi: cxlflash: Improve EEH recovery time
+
+  * Xenial update to v4.4.52 stable release (LP: #1669016)
+    - net/llc: avoid BUG_ON() in skb_orphan()
+    - packet: fix races in fanout_add()
+    - packet: Do not call fanout_release from atomic contexts
+    - irda: Fix lockdep annotations in hashbin_delete().
+    - ip: fix IP_CHECKSUM handling
+    - net: socket: fix recvmmsg not returning error from sock_error
+    - tty: serial: msm: Fix module autoload
+    - USB: serial: mos7840: fix another NULL-deref at open
+    - USB: serial: cp210x: add new IDs for GE Bx50v3 boards
+    - USB: serial: ftdi_sio: fix modem-status error handling
+    - USB: serial: ftdi_sio: fix extreme low-latency setting
+    - USB: serial: ftdi_sio: fix line-status over-reporting
+    - USB: serial: spcp8x5: fix modem-status handling
+    - USB: serial: opticon: fix CTS retrieval at open
+    - USB: serial: ark3116: fix register-accessor error handling
+    - x86/platform/goldfish: Prevent unconditional loading
+    - goldfish: Sanitize the broken interrupt handler
+    - block: fix double-free in the failure path of cgwb_bdi_init()
+    - rtlwifi: rtl_usb: Fix for URB leaking when doing ifconfig up/down
+    - Revert "usb: chipidea: imx: enable CI_HDRC_SET_NON_ZERO_TTHA"
+    - kvm: vmx: ensure VMCS is current while enabling PML
+    - Linux 4.4.52
+
+  * Xenial update to v4.4.51 stable release (LP: #1669015)
+    - vfs: fix uninitialized flags in splice_to_pipe()
+    - siano: make it work again with CONFIG_VMAP_STACK
+    - fuse: fix use after free issue in fuse_dev_do_read()
+    - scsi: don't BUG_ON() empty DMA transfers
+    - Fix missing sanity check in /dev/sg
+    - Input: elan_i2c - add ELAN0605 to the ACPI table
+    - drm/radeon: Use mode h/vdisplay fields to hide out of bounds HW cursor
+    - drm/dp/mst: fix kernel oops when turning off secondary monitor
+    - futex: Move futex_init() to core_initcall
+    - ARM: 8658/1: uaccess: fix zeroing of 64-bit get_user()
+    - printk: use rcuidle console tracepoint
+    - NTB: ntb_transport: fix debugfs_remove_recursive
+    - ntb_transport: Pick an unused queue
+    - bcache: Make gc wakeup sane, remove set_task_state()
+    - mmc: core: fix multi-bit bus width without high-speed mode
+    - Linux 4.4.51
+
+  * Xenial update to v4.4.50 stable release (LP: #1666324)
+    - can: Fix kernel panic at security_sock_rcv_skb
+    - ipv6: fix ip6_tnl_parse_tlv_enc_lim()
+    - ipv6: pointer math error in ip6_tnl_parse_tlv_enc_lim()
+    - tcp: fix 0 divide in __tcp_select_window()
+    - net: use a work queue to defer net_disable_timestamp() work
+    - ipv4: keep skb->dst around in presence of IP options
+    - netlabel: out of bound access in cipso_v4_validate()
+    - ip6_gre: fix ip6gre_err() invalid reads
+    - ipv6: tcp: add a missing tcp_v6_restore_cb()
+    - tcp: avoid infinite loop in tcp_splice_read()
+    - tun: read vnet_hdr_sz once
+    - macvtap: read vnet_hdr_size once
+    - mlx4: Invoke softirqs after napi_reschedule
+    - sctp: avoid BUG_ON on sctp_wait_for_sndbuf
+    - sit: fix a double free on error path
+    - net: introduce device min_header_len
+    - packet: round up linear to header len
+    - ping: fix a null pointer dereference
+    - l2tp: do not use udp_ioctl()
+    - Linux 4.4.50
+
+  * FlashGT Integration and Setup: fsbmc30: After 17th reboot of soft bootme,
+    HTX & Linux errors seen with 256 virtual LUNs (LP: #1667239)
+    - cxl: Fix coredump generation when cxl_get_fd() is used
+
+  * [Hyper-V] Ubuntu 14.04.2 LTS Generation 2 SCSI Errors on VSS Based Backups
+    (LP: #1470250)
+    - Drivers: hv: vss: Operation timeouts should match host expectation
+    - SAUCE: Tools: hv: vss: Thaw the filesystem and continue after freeze fails
+
+  * kernel 4.4.0-63 with USB WLAN RTL8192CU freezes desktop (LP: #1666421)
+    - rtlwifi: rtl_usb: Fix missing entry in USB driver's private data
+
+  * Export symbol "dev_pm_qos_update_user_latency_tolerance" (LP: #1666401)
+    - PM / QoS: Export dev_pm_qos_update_user_latency_tolerance
+
+  * Linux ZFS port doesn't respect RLIMIT_FSIZE (LP: #1656259)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu16
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 06 Apr 2017 09:34:27 +0100
+
+linux (4.4.0-72.93) xenial; urgency=low
+
+  * linux: 4.4.0-72.93 -proposed tracker (LP: #1678078)
+
+  * Fix CVE-2017-7308 (LP: #1678009)
+    - net/packet: fix overflow in check for priv area size
+    - net/packet: fix overflow in check for tp_frame_nr
+    - net/packet: fix overflow in check for tp_reserve
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 31 Mar 2017 09:20:03 +0200
+
+linux (4.4.0-71.92) xenial; urgency=low
+
+  * CVE-2017-7184
+    - xfrm_user: validate XFRM_MSG_NEWAE XFRMA_REPLAY_ESN_VAL replay_window
+    - xfrm_user: validate XFRM_MSG_NEWAE incoming ESN size harder
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 24 Mar 2017 09:32:49 -0300
+
+linux (4.4.0-70.91) xenial; urgency=low
+
+  * linux: 4.4.0-70.91 -proposed tracker (LP: #1674938)
+
+  * snaps with classic + jailmode confinement started to fail on zesty
+    (LP: #1666897)
+    - Revert "UBUNTU: SAUCE: apparmor: fix link auditing failure due to,
+      uninitialized var"
+    - Revert "UBUNTU: SAUCE: fix regression with domain change in complain mode"
+    - Revert "UBUNTU: SAUCE: apparmor: flock mediation is not being enforced on
+      cache check"
+    - Revert "UBUNTU: SAUCE: apparmor: null profiles should inherit parent control
+      flags"
+    - Revert "UBUNTU: SAUCE: apparmor: fix ns ref count link when removing
+      profiles from policy"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix no_new_privs blocking change_onexec
+      when using stacked namespaces"
+    - Revert "UBUNTU: SAUCE: apparmor: fix oops in bind_mnt when dev_path lookup
+      fails"
+    - Revert "UBUNTU: SAUCE: apparmor: Don't audit denied access of special
+      apparmor .null file"
+    - Revert "UBUNTU: SAUCE: apparmor: fix label leak when new label is unused"
+    - Revert "UBUNTU: SAUCE: apparmor: fix reference count bug in
+      label_merge_insert()"
+    - Revert "UBUNTU: SAUCE: apparmor: fix replacement race in reading rawdata"
+    - Revert "UBUNTU: SAUCE: apparmor: fix cross ns perm of unix domain sockets"
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 22 Mar 2017 09:28:43 +0100
+
+linux (4.4.0-67.88) xenial; urgency=low
+
+  * linux: 4.4.0-67.88 -proposed tracker (LP: #1667052)
+
+  * Recent KVM RTC cherry-picks break (some) Windows Live-Migrations
+    (LP: #1668594)
+    - kvm: x86: correctly reset dest_map->vector when restoring LAPIC state
+
+  * Regression in 4.4.0-65-generic causes very frequent system crashes
+    (LP: #1669611)
+    - Revert "UBUNTU: SAUCE: apparmor: fix lock ordering for mkdir"
+    - Revert "UBUNTU: SAUCE: apparmor: fix leak on securityfs pin count"
+    - Revert "UBUNTU: SAUCE: apparmor: fix reference count leak when
+      securityfs_setup_d_inode() fails"
+    - Revert "UBUNTU: SAUCE: apparmor: fix not handling error case when
+      securityfs_pin_fs() fails"
+
+  * Upgrade Redpine RS9113 driver to support AP mode (LP: #1665211)
+    - SAUCE: Redpine driver to support Host AP mode
+
+  * NFS client : permission denied when trying to access subshare, since kernel
+    4.4.0-31 (LP: #1649292)
+    - fs: Better permission checking for submounts
+
+  * [Hyper-V] SAUCE: pci-hyperv fixes for SR-IOV on Azure (LP: #1665097)
+    - SAUCE: PCI: hv: Fix wslot_to_devfn() to fix warnings on device removal
+    - SAUCE: pci-hyperv: properly handle pci bus remove
+    - SAUCE: pci-hyperv: lock pci bus on device eject
+
+  * [Hyper-V/Azure] Please include Mellanox OFED drivers in Azure kernel and
+    image (LP: #1650058)
+    - net/mlx4_en: Fix bad WQE issue
+    - net/mlx4_core: Fix racy CQ (Completion Queue) free
+    - net/mlx4_core: Fix when to save some qp context flags for dynamic VST to VGT
+      transitions
+    - net/mlx4_core: Avoid command timeouts during VF driver device shutdown
+
+  * Xenial update to v4.4.49 stable release (LP: #1664960)
+    - ARC: [arcompact] brown paper bag bug in unaligned access delay slot fixup
+    - selinux: fix off-by-one in setprocattr
+    - Revert "x86/ioapic: Restore IO-APIC irq_chip retrigger callback"
+    - cpumask: use nr_cpumask_bits for parsing functions
+    - hns: avoid stack overflow with CONFIG_KASAN
+    - ARM: 8643/3: arm/ptrace: Preserve previous registers for short regset write
+    - target: Don't BUG_ON during NodeACL dynamic -> explicit conversion
+    - target: Use correct SCSI status during EXTENDED_COPY exception
+    - target: Fix early transport_generic_handle_tmr abort scenario
+    - target: Fix COMPARE_AND_WRITE ref leak for non GOOD status
+    - ARM: 8642/1: LPAE: catch pending imprecise abort on unmask
+    - mac80211: Fix adding of mesh vendor IEs
+    - netvsc: Set maximum GSO size in the right place
+    - scsi: zfcp: fix use-after-free by not tracing WKA port open/close on failed
+      send
+    - scsi: aacraid: Fix INTx/MSI-x issue with older controllers
+    - scsi: mpt3sas: disable ASPM for MPI2 controllers
+    - xen-netfront: Delete rx_refill_timer in xennet_disconnect_backend()
+    - ALSA: seq: Fix race at creating a queue
+    - ALSA: seq: Don't handle loop timeout at snd_seq_pool_done()
+    - drm/i915: fix use-after-free in page_flip_completed()
+    - Linux 4.4.49
+
+  * NFS client : kernel 4.4.0-57 crash with nfsv4 enries in /etc/fstab
+    (LP: #1650336)
+    - SUNRPC: fix refcounting problems with auth_gss messages.
+
+  * [0bda:0328] Card reader failed after S3 (LP: #1664809)
+    - usb: hub: Wait for connection to be reestablished after port reset
+
+  * linux-lts-xenial 4.4.0-63.84~14.04.2 ADT test failure with linux-lts-xenial
+    4.4.0-63.84~14.04.2 (LP: #1664912)
+    - SAUCE: apparmor: fix link auditing failure due to, uninitialized var
+
+  * ibmvscsis: Add SGL LIMIT (LP: #1662551)
+    - ibmvscsis: Add SGL limit
+
+  * [Hyper-V] Bug fixes for storvsc (tagged queuing, error conditions)
+    (LP: #1663687)
+    - scsi: storvsc: Enable tracking of queue depth
+    - scsi: storvsc: Remove the restriction on max segment size
+    - scsi: storvsc: Enable multi-queue support
+    - scsi: storvsc: use tagged SRB requests if supported by the device
+    - scsi: storvsc: properly handle SRB_ERROR when sense message is present
+    - scsi: storvsc: properly set residual data length on errors
+
+  * ISST-LTE:pNV: ppc64_cpu command is hung w HDs, SSDs and NVMe (LP: #1662666)
+    - blk-mq: Avoid memory reclaim when remapping queues
+    - blk-mq: Fix failed allocation path when mapping queues
+
+  * Possible missing firmware /lib/firmware/i915/kbl_dmc_ver1.bin for module
+    i915_bpo (LP: #1624164)
+    - SAUCE: i915_bpo: Remove MODULE_FIRMWARE statement for i915/kbl_dmc_ver1.bin
+
+  *  Intel I210 ethernet does not work both after S3 (LP: #1662763)
+    - igb: implement igb_ptp_suspend
+    - igb: call igb_ptp_suspend during suspend/resume cycle
+
+  * [Hyper-V] Fix ring buffer handling to avoid host throttling (LP: #1661430)
+    - Drivers: hv: vmbus: On write cleanup the logic to interrupt the host
+    - Drivers: hv: vmbus: On the read path cleanup the logic to interrupt the host
+    - Drivers: hv: vmbus: finally fix hv_need_to_signal_on_read()
+
+  * brd module compiled as built-in (LP: #1593293)
+    - [Config] CONFIG_BLK_DEV_RAM=m
+
+  * regession tests failing after stackprofile test is run (LP: #1661030)
+    - SAUCE: fix regression with domain change in complain mode
+
+  * Permission denied and inconsistent behavior in complain mode with 'ip netns
+    list' command (LP: #1648903)
+    - SAUCE: fix regression with domain change in complain mode
+
+  * flock not mediated by 'k' (LP: #1658219)
+    - SAUCE: apparmor: flock mediation is not being enforced on cache check
+
+  * unexpected errno=13 and disconnected path when trying to open /proc/1/ns/mnt
+    from a unshared mount namespace (LP: #1656121)
+    - SAUCE: apparmor: null profiles should inherit parent control flags
+
+  * apparmor refcount leak of profile namespace when removing profiles
+    (LP: #1660849)
+    - SAUCE: apparmor: fix ns ref count link when removing profiles from policy
+
+  * tor in lxd: apparmor="DENIED" operation="change_onexec"
+    namespace="root//CONTAINERNAME_<var-lib-lxd>" profile="unconfined"
+    name="system_tor" (LP: #1648143)
+    - SAUCE: apparmor: Fix no_new_privs blocking change_onexec when using stacked
+      namespaces
+
+  * apparmor_parser hangs indefinitely when called by multiple threads
+    (LP: #1645037)
+    - SAUCE: apparmor: fix lock ordering for mkdir
+
+  * apparmor leaking securityfs pin count (LP: #1660846)
+    - SAUCE: apparmor: fix leak on securityfs pin count
+
+  * apparmor reference count leak when securityfs_setup_d_inode\ () fails
+    (LP: #1660845)
+    - SAUCE: apparmor: fix reference count leak when securityfs_setup_d_inode()
+      fails
+
+  * apparmor not checking error if security_pin_fs() fails (LP: #1660842)
+    - SAUCE: apparmor: fix not handling error case when securityfs_pin_fs() fails
+
+  * apparmor oops in bind_mnt when dev_path lookup fails (LP: #1660840)
+    - SAUCE: apparmor: fix oops in bind_mnt when dev_path lookup fails
+
+  * apparmor  auditing denied access of special apparmor .null fi\ le
+    (LP: #1660836)
+    - SAUCE: apparmor: Don't audit denied access of special apparmor .null file
+
+  * apparmor label leak when new label is unused (LP: #1660834)
+    - SAUCE: apparmor: fix label leak when new label is unused
+
+  * apparmor reference count bug in label_merge_insert() (LP: #1660833)
+    - SAUCE: apparmor: fix reference count bug in label_merge_insert()
+
+  * apparmor's raw_data file in securityfs is sometimes truncated (LP: #1638996)
+    - SAUCE: apparmor: fix replacement race in reading rawdata
+
+  * unix domain socket cross permission check failing with nested namespaces
+    (LP: #1660832)
+    - SAUCE: apparmor: fix cross ns perm of unix domain sockets
+
+  * docker permission issues with overlay2 storage driver (LP: #1659417)
+    - SAUCE: overlayfs: Replace ovl_prepare_creds() with ovl_override_creds()
+    - Revert "UBUNTU: SAUCE: cred: Add clone_cred() interface"
+    - ovl: check mounter creds on underlying lookup
+
+  * Enable CONFIG_NET_DROP_MONITOR=m in Ubuntu Kernel (LP: #1660634)
+    - [Config] CONFIG_NET_DROP_MONITOR=m
+
+  * Xenial update to v4.4.48 stable release (LP: #1663657)
+    - PCI/ASPM: Handle PCI-to-PCIe bridges as roots of PCIe hierarchies
+    - ext4: validate s_first_meta_bg at mount time
+    - drm/nouveau/disp/gt215: Fix HDA ELD handling (thus, HDMI audio) on gt215
+    - drm/nouveau/nv1a,nv1f/disp: fix memory clock rate retrieval
+    - crypto: api - Clear CRYPTO_ALG_DEAD bit before registering an alg
+    - crypto: arm64/aes-blk - honour iv_out requirement in CBC and CTR modes
+    - perf/core: Fix PERF_RECORD_MMAP2 prot/flags for anonymous memory
+    - ata: sata_mv:- Handle return value of devm_ioremap.
+    - libata: apply MAX_SEC_1024 to all CX1-JB*-HP devices
+    - powerpc/eeh: Fix wrong flag passed to eeh_unfreeze_pe()
+    - powerpc: Add missing error check to prom_find_boot_cpu()
+    - NFSD: Fix a null reference case in find_or_create_lock_stateid()
+    - svcrpc: fix oops in absence of krb5 module
+    - zswap: disable changing params if init fails
+    - cifs: initialize file_info_lock
+    - mm/memory_hotplug.c: check start_pfn in test_pages_in_a_zone()
+    - mm, fs: check for fatal signals in do_generic_file_read()
+    - can: bcm: fix hrtimer/tasklet termination in bcm op removal
+    - mmc: sdhci: Ignore unexpected CARD_INT interrupts
+    - percpu-refcount: fix reference leak during percpu-atomic transition
+    - HID: wacom: Fix poor prox handling in 'wacom_pl_irq'
+    - KVM: x86: do not save guest-unsupported XSAVE state
+    - USB: serial: qcserial: add Dell DW5570 QDL
+    - USB: serial: pl2303: add ATEN device ID
+    - USB: Add quirk for WORLDE easykey.25 MIDI keyboard
+    - usb: gadget: f_fs: Assorted buffer overflow checks.
+    - USB: serial: option: add device ID for HP lt2523 (Novatel E371)
+    - x86/irq: Make irq activate operations symmetric
+    - base/memory, hotplug: fix a kernel oops in show_valid_zones()
+    - Linux 4.4.48
+
+  * Xenial update to v4.4.47 stable release (LP: #1662507)
+    - r8152: fix the sw rx checksum is unavailable
+    - mlxsw: spectrum: Fix memory leak at skb reallocation
+    - mlxsw: switchx2: Fix memory leak at skb reallocation
+    - mlxsw: pci: Fix EQE structure definition
+    - net: lwtunnel: Handle lwtunnel_fill_encap failure
+    - net: ipv4: fix table id in getroute response
+    - net: systemport: Decouple flow control from __bcm_sysport_tx_reclaim
+    - tcp: fix tcp_fastopen unaligned access complaints on sparc
+    - openvswitch: maintain correct checksum state in conntrack actions
+    - ravb: do not use zero-length alignment DMA descriptor
+    - ax25: Fix segfault after sock connection timeout
+    - net: fix harmonize_features() vs NETIF_F_HIGHDMA
+    - net: phy: bcm63xx: Utilize correct config_intr function
+    - ipv6: addrconf: Avoid addrconf_disable_change() using RCU read-side lock
+    - tcp: initialize max window for a new fastopen socket
+    - bridge: netlink: call br_changelink() during br_dev_newlink()
+    - r8152: don't execute runtime suspend if the tx is not empty
+    - af_unix: move unix_mknod() out of bindlock
+    - qmi_wwan/cdc_ether: add device ID for HP lt2523 (Novatel E371) WWAN card
+    - net: dsa: Bring back device detaching in dsa_slave_suspend()
+    - Linux 4.4.47
+
+  * Xenial update to v4.4.46 stable release (LP: #1660994)
+    - fbdev: color map copying bounds checking
+    - tile/ptrace: Preserve previous registers for short regset write
+    - drm: Fix broken VT switch with video=1366x768 option
+    - mm/mempolicy.c: do not put mempolicy before using its nodemask
+    - sysctl: fix proc_doulongvec_ms_jiffies_minmax()
+    - ISDN: eicon: silence misleading array-bounds warning
+    - RDMA/cma: Fix unknown symbol when CONFIG_IPV6 is not enabled
+    - s390/ptrace: Preserve previous registers for short regset write
+    - can: c_can_pci: fix null-pointer-deref in c_can_start() - set device pointer
+    - can: ti_hecc: add missing prepare and unprepare of the clock
+    - ARC: udelay: fix inline assembler by adding LP_COUNT to clobber list
+    - ARC: [arcompact] handle unaligned access delay slot corner case
+    - parisc: Don't use BITS_PER_LONG in userspace-exported swab.h header
+    - nfs: Don't increment lock sequence ID after NFS4ERR_MOVED
+    - NFSv4.0: always send mode in SETATTR after EXCLUSIVE4
+    - SUNRPC: cleanup ida information when removing sunrpc module
+    - drm/i915: Don't leak edid in intel_crt_detect_ddc()
+    - IB/ipoib: move back IB LL address into the hard header
+    - IB/umem: Release pid in error and ODP flow
+    - s5k4ecgx: select CRC32 helper
+    - pinctrl: broxton: Use correct PADCFGLOCK offset
+    - platform/x86: intel_mid_powerbtn: Set IRQ_ONESHOT
+    - mm, memcg: do not retry precharge charges
+    - Linux 4.4.46
+
+  * Xenial update to v4.4.45 stable release (LP: #1660993)
+    - ftrace/x86: Set ftrace_stub to weak to prevent gcc from using short jumps to
+      it
+    - IB/mlx5: Wait for all async command completions to complete
+    - IB/mlx4: Set traffic class in AH
+    - IB/mlx4: Fix out-of-range array index in destroy qp flow
+    - IB/mlx4: Fix port query for 56Gb Ethernet links
+    - IB/mlx4: When no DMFS for IPoIB, don't allow NET_IF QPs
+    - IB/IPoIB: Remove can't use GFP_NOIO warning
+    - perf scripting: Avoid leaking the scripting_context variable
+    - ARM: dts: imx31: fix clock control module interrupts description
+    - ARM: dts: imx31: move CCM device node to AIPS2 bus devices
+    - ARM: dts: imx31: fix AVIC base address
+    - tmpfs: clear S_ISGID when setting posix ACLs
+    - x86/PCI: Ignore _CRS on Supermicro X8DTH-i/6/iF/6F
+    - svcrpc: don't leak contexts on PROC_DESTROY
+    - fuse: clear FR_PENDING flag when moving requests out of pending queue
+    - PCI: Enumerate switches below PCI-to-PCIe bridges
+    - HID: corsair: fix DMA buffers on stack
+    - HID: corsair: fix control-transfer error handling
+    - mmc: mxs-mmc: Fix additional cycles after transmission stop
+    - ieee802154: atusb: do not use the stack for buffers to make them DMA able
+    - mtd: nand: xway: disable module support
+    - x86/ioapic: Restore IO-APIC irq_chip retrigger callback
+    - qla2xxx: Fix crash due to null pointer access
+    - ubifs: Fix journal replay wrt. xattr nodes
+    - clocksource/exynos_mct: Clear interrupt when cpu is shut down
+    - svcrdma: avoid duplicate dma unmapping during error recovery
+    - ARM: 8634/1: hw_breakpoint: blacklist Scorpion CPUs
+    - ceph: fix bad endianness handling in parse_reply_info_extra
+    - ARM: dts: da850-evm: fix read access to SPI flash
+    - arm64/ptrace: Preserve previous registers for short regset write
+    - arm64/ptrace: Preserve previous registers for short regset write - 2
+    - arm64/ptrace: Preserve previous registers for short regset write - 3
+    - arm64/ptrace: Avoid uninitialised struct padding in fpr_set()
+    - arm64/ptrace: Reject attempts to set incomplete hardware breakpoint fields
+    - ARM: dts: imx6qdl-nitrogen6_max: fix sgtl5000 pinctrl init
+    - ARM: ux500: fix prcmu_is_cpu_in_wfi() calculation
+    - ARM: 8613/1: Fix the uaccess crash on PB11MPCore
+    - blackfin: check devm_pinctrl_get() for errors
+    - ite-cir: initialize use_demodulator before using it
+    - dmaengine: pl330: Fix runtime PM support for terminated transfers
+    - selftest/powerpc: Wrong PMC initialized in pmc56_overflow test
+    - arm64: avoid returning from bad_mode
+    - Linux 4.4.45
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 08 Mar 2017 11:47:26 -0300
+
+linux (4.4.0-66.87) xenial; urgency=low
+
+  * CVE-2017-2636
+    - TTY: n_hdlc, fix lockdep false positive
+    - tty: n_hdlc: get rid of racy n_hdlc.tbuf
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 03 Mar 2017 12:01:27 +0100
+
+linux (4.4.0-64.85) xenial; urgency=low
+
+  * CVE-2017-6074 (LP: #1665935)
+    - dccp: fix freeing skb too early for IPV6_RECVPKTINFO
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 20 Feb 2017 11:06:47 +0100
+
+linux (4.4.0-63.84) xenial; urgency=low
+
+  [ Thadeu Lima de Souza Cascardo ]
+
+  * Release Tracking Bug
+    - LP: #1660704
+
+  * Backport Dirty COW patch to prevent wineserver freeze (LP: #1658270)
+    - SAUCE: mm: Respect FOLL_FORCE/FOLL_COW for thp
+
+  * Kdump through NMI SMP and single core not working on Ubuntu16.10
+    (LP: #1630924)
+    - x86/hyperv: Handle unknown NMIs on one CPU when unknown_nmi_panic
+    - SAUCE: hv: don't reset hv_context.tsc_page on crash
+
+  * [regression 4.8.0-14 -> 4.8.0-17] keyboard and touchscreen lost on Acer
+    Chromebook R11 (LP: #1630238)
+    - [Config] CONFIG_PINCTRL_CHERRYVIEW=y
+
+  * Call trace when testing fstat stressor on ppc64el with virtual  keyboard and
+    mouse present (LP: #1652132)
+    - SAUCE: HID: usbhid: Quirk a AMI virtual mouse and keyboard with ALWAYS_POLL
+
+  * VLAN SR-IOV regression for IXGBE driver (LP: #1658491)
+    - ixgbe: Force VLNCTRL.VFE to be set in all VMDq paths
+
+  * "Out of memory" errors after upgrade to 4.4.0-59 (LP: #1655842)
+    - mm, page_alloc: convert alloc_flags to unsigned
+    - mm, compaction: change COMPACT_ constants into enum
+    - mm, compaction: distinguish COMPACT_DEFERRED from COMPACT_SKIPPED
+    - mm, compaction: simplify __alloc_pages_direct_compact feedback interface
+    - mm, compaction: distinguish between full and partial COMPACT_COMPLETE
+    - mm, compaction: abstract compaction feedback to helpers
+    - mm, oom: protect !costly allocations some more
+    - mm: consider compaction feedback also for costly allocation
+    - mm, oom, compaction: prevent from should_compact_retry looping for ever for
+      costly orders
+    - mm, oom: protect !costly allocations some more for !CONFIG_COMPACTION
+    - mm, oom: prevent premature OOM killer invocation for high order request
+
+  * Backport 3 patches to fix bugs with AIX clients using IBMVSCSI Target Driver
+    (LP: #1657194)
+    - SAUCE: ibmvscsis: Fix max transfer length
+    - SAUCE: ibmvscsis: fix sleeping in interrupt context
+    - SAUCE: ibmvscsis: Fix srp_transfer_data fail return code
+
+  * NVMe: adapter is missing after abnormal shutdown followed by quick reboot,
+    quirk needed (LP: #1656913)
+    - nvme: apply DELAY_BEFORE_CHK_RDY quirk at probe time too
+
+  * Ubuntu 16.10 KVM SRIOV: if enable sriov while ping flood is running ping
+    will stop working (LP: #1625318)
+    - PCI: Do any VF BAR updates before enabling the BARs
+    - PCI: Ignore BAR updates on virtual functions
+    - PCI: Update BARs using property bits appropriate for type
+    - PCI: Separate VF BAR updates from standard BAR updates
+    - PCI: Don't update VF BARs while VF memory space is enabled
+    - PCI: Remove pci_resource_bar() and pci_iov_resource_bar()
+    - PCI: Decouple IORESOURCE_ROM_ENABLE and PCI_ROM_ADDRESS_ENABLE
+    - PCI: Add comments about ROM BAR updating
+
+  * Linux rtc self test fails in a VM under xenial (LP: #1649718)
+    - kvm: x86: Convert ioapic->rtc_status.dest_map to a struct
+    - kvm: x86: Track irq vectors in ioapic->rtc_status.dest_map
+    - kvm: x86: Check dest_map->vector to match eoi signals for rtc
+
+  * Xenial update to v4.4.44 stable release (LP: #1658091)
+    - Input: xpad - use correct product id for x360w controllers
+    - Input: i8042 - add Pegatron touchpad to noloop table
+    - selftests: do not require bash to run netsocktests testcase
+    - selftests: do not require bash for the generated test
+    - mm: fix devm_memremap_pages crash, use mem_hotplug_{begin, done}
+    - ocfs2: fix crash caused by stale lvb with fsdlm plugin
+    - mm/hugetlb.c: fix reservation race when freeing surplus pages
+    - KVM: x86: fix emulation of "MOV SS, null selector"
+    - KVM: eventfd: fix NULL deref irqbypass consumer
+    - jump_labels: API for flushing deferred jump label updates
+    - KVM: x86: flush pending lapic jump label updates on module unload
+    - KVM: x86: add Align16 instruction flag
+    - KVM: x86: add asm_safe wrapper
+    - KVM: x86: emulate FXSAVE and FXRSTOR
+    - KVM: x86: Introduce segmented_write_std
+    - nl80211: fix sched scan netlink socket owner destruction
+    - USB: serial: kl5kusb105: fix line-state error handling
+    - USB: serial: ch341: fix initial modem-control state
+    - USB: serial: ch341: fix open error handling
+    - USB: serial: ch341: fix control-message error handling
+    - USB: serial: ch341: fix open and resume after B0
+    - Input: elants_i2c - avoid divide by 0 errors on bad touchscreen data
+    - i2c: print correct device invalid address
+    - i2c: fix kernel memory disclosure in dev interface
+    - xhci: fix deadlock at host remove by running watchdog correctly
+    - vme: Fix wrong pointer utilization in ca91cx42_slave_get
+    - mnt: Protect the mountpoint hashtable with mount_lock
+    - tty/serial: atmel_serial: BUG: stop DMA from transmitting in stop_tx
+    - sysrq: attach sysrq handler correctly for 32-bit kernel
+    - sysctl: Drop reference added by grab_header in proc_sys_readdir
+    - drm/radeon: drop verde dpm quirks
+    - USB: serial: ch341: fix resume after reset
+    - USB: serial: ch341: fix modem-control and B0 handling
+    - x86/cpu: Fix bootup crashes by sanitizing the argument of the 'clearcpuid='
+      command-line option
+    - btrfs: fix locking when we put back a delayed ref that's too new
+    - btrfs: fix error handling when run_delayed_extent_op fails
+    - pinctrl: meson: fix gpio request disabling other modes
+    - pNFS: Fix race in pnfs_wait_on_layoutreturn
+    - NFS: Fix a performance regression in readdir
+    - NFSv4.1: nfs4_fl_prepare_ds must be careful about reporting success.
+    - cpufreq: powernv: Disable preemption while checking CPU throttling state
+    - block: cfq_cpd_alloc() should use @gfp
+    - ACPI / APEI: Fix NMI notification handling
+    - blk-mq: Always schedule hctx->next_cpu
+    - bus: vexpress-config: fix device reference leak
+    - powerpc/ibmebus: Fix further device reference leaks
+    - powerpc/ibmebus: Fix device reference leaks in sysfs interface
+    - pinctrl: sh-pfc: Do not unconditionally support PIN_CONFIG_BIAS_DISABLE
+    - Linux 4.4.44
+
+  * Add support for RT5660 codec based sound cards on Baytrail (LP: #1657674)
+    - ASoC: rt5660: add rt5660 codec driver
+    - ASoC: rt5660: enable MCLK detection
+    - ASoC: Intel: Atom: flip logic for gain Switch
+    - SAUCE: (no-up) ASoC: rt5660: Add ACPI support
+    - SAUCE: (no-up) ASoC: Intel: Support machine driver for RT5660 on Baytrail
+    - [Config] CONFIG_SND_SOC_INTEL_BYTCR_RT5660_MACH=m, CONFIG_SND_SOC_RT5660=m
+
+  * Support latest Redpine WLAN/BT RS9113 driver (LP: #1657682)
+    - SAUCE: Support Redpine RS9113 WLAN/BT
+    - SAUCE: Separate Redpine RS9113 WLAN/BT vendor and kernel drivers
+    - SAUCE: Redpine RS9113 WLAN/BT driver ver. 0.9.7
+    - SAUCE: RS9113: Use vendor driver to support WLAN/BT card on Caracalla HW
+      only
+    - SAUCE: RS9113: Comment out IDs from upstream driver
+    - [Config] Enable CONFIG_VEN_RSI_* configs
+
+  * [Hyper-V] netvsc: add rcu_read locked to netvsc callback (LP: #1657540)
+    - netvsc: add rcu_read locking to netvsc callback
+
+  * [Hyper-V] Rebase Hyper-V in 16.04 and 16.10 to the the upstream 4.9 kernel
+    (LP: #1650059)
+    - memory-hotplug: add automatic onlining policy for the newly added memory
+    - hv_netvsc: Add query for initial physical link speed
+    - hv_netvsc: Add handler for physical link speed change
+    - hv_netvsc: Implement batching of receive completions
+    - PCI: hv: Use list_move_tail() instead of list_del() + list_add_tail()
+    - hv_netvsc: fix rtnl locking in callback
+    - hv_netvsc: make RSS hash key static
+    - hv_netvsc: use kcalloc
+    - hv_netvsc: style cleanups
+    - hv_netvsc: make inline functions static
+    - hv_netvsc: use ARRAY_SIZE() for NDIS versions
+    - hv_netvsc: make device_remove void
+    - hv_netvsc: init completion during alloc
+    - hv_netvsc: rearrange start_xmit
+    - hv_netvsc: refactor completion function
+    - hv_netvsc: make netvsc_destroy_buf void
+    - hv_netvsc: make variable local
+    - hv_netvsc: report vmbus name in ethtool
+    - hv_netvsc: add ethtool statistics for tx packet issues
+    - Drivers: hv: get rid of redundant messagecount in create_gpadl_header()
+    - Drivers: hv: don't leak memory in vmbus_establish_gpadl()
+    - Drivers: hv: get rid of timeout in vmbus_open()
+    - Drivers: hv: utils: fix a race on userspace daemons registration
+    - Drivers: hv: vmbus: fix the race when querying & updating the percpu list
+    - Drivers: hv: vmbus: Enable explicit signaling policy for NIC channels
+    - Drivers: hv: vmbus: Reduce the delay between retries in vmbus_post_msg()
+    - Drivers: hv: vmbus: Implement a mechanism to tag the channel for low latency
+    - Tools: hv: kvp: ensure kvp device fd is closed on exec
+    - Drivers: hv: balloon: keep track of where ha_region starts
+    - Drivers: hv: balloon: account for gaps in hot add regions
+    - Drivers: hv: balloon: don't wait for ol_waitevent when memhp_auto_online is
+      enabled
+    - Drivers: hv: balloon: replace ha_region_mutex with spinlock
+    - Drivers: hv: balloon: Use available memory value in pressure report
+    - Drivers: hv: cleanup vmbus_open() for wrap around mappings
+    - Drivers: hv: ring_buffer: wrap around mappings for ring buffers
+    - Drivers: hv: ring_buffer: use wrap around mappings in hv_copy{from,
+      to}_ringbuffer()
+    - Drivers: hv: ring_buffer: count on wrap around mappings in
+      get_next_pkt_raw()
+    - Drivers: hv: Introduce a policy for controlling channel affinity
+    - Drivers: hv: utils: Continue to poll VSS channel after handling requests.
+    - Drivers: hv: utils: Check VSS daemon is listening before a hot backup
+    - PCI: hv: Use zero-length array in struct pci_packet
+    - PCI: hv: Use pci_function_description[0] in struct definitions
+    - PCI: hv: Remove the unused 'wrk' in struct hv_pcibus_device
+    - PCI: hv: Handle vmbus_sendpacket() failure in hv_compose_msi_msg()
+    - PCI: hv: Handle hv_pci_generic_compl() error case
+    - Revert "Drivers: hv: ring_buffer: count on wrap around mappings in
+      get_next_pkt_raw()"
+    - Driver: hv: vmbus: Make mmio resource local
+    - Drivers: hv: vmbus: suppress some "hv_vmbus: Unknown GUID" warnings
+    - Drivers: hv: utils: Rename version definitions to reflect protocol version.
+    - Drivers: hv: utils: Use TimeSync samples to adjust the clock after boot.
+    - Drivers: hv: utils: Support TimeSync version 4.0 protocol samples.
+    - Drivers: hv: hv_util: Avoid dynamic allocation in time synch
+    - Revert "hv_netvsc: make inline functions static"
+    - hv_netvsc: use consume_skb
+    - hv_netvsc: dev hold/put reference to VF
+    - hv_netvsc: simplify callback event code
+    - hv_netvsc: improve VF device matching
+    - hv_netvsc: use RCU to protect vf_netdev
+    - hv_netvsc: remove VF in flight counters
+    - hv_netvsc: count multicast packets received
+    - hv_netvsc: fix comments
+    - Drivers: hv: make VMBus bus ids persistent
+    - Drivers: hv: get rid of id in struct vmbus_channel
+    - netvsc: fix checksum on UDP IPV6
+    - netvsc: Remove mistaken udp.h inclusion.
+    - net/hyperv: avoid uninitialized variable
+    - Revert "hv_netvsc: report vmbus name in ethtool"
+    - vmbus: make sysfs names consistent with PCI
+    - netvsc: reduce maximum GSO size
+    - Drivers: hv: vmbus: Base host signaling strictly on the ring state
+    - tools: hv: Add a script to help bonding synthetic and VF NICs
+
+  * Ubuntu - ibmveth: abnormally large TCP MSS value caused a TCP session to
+    hang with a zero window (LP: #1655420)
+    - ibmveth: set correct gso_size and gso_type
+    - ibmveth: calculate gso_segs for large packets
+
+  * netfilter regression introducing a performance slowdown in binary
+    arp/ip/ip6tables (LP: #1640786)
+    - netfilter: x_tables: pass xt_counters struct instead of packet counter
+    - netfilter: x_tables: pass xt_counters struct to counter allocator
+    - netfilter: x_tables: pack percpu counter allocations
+
+  * Move some kernel modules to the main kernel package (part 2) (LP: #1655002)
+    - [Config] Add IBM power drivers to the inclusion list
+
+  * Xenial update to v4.4.43 stable release (LP: #1656876)
+    - netvsc: reduce maximum GSO size
+    - ser_gigaset: return -ENOMEM on error instead of success
+    - net: vrf: Drop conntrack data after pass through VRF device on Tx
+    - ipv6: handle -EFAULT from skb_copy_bits
+    - net, sched: fix soft lockup in tc_classify
+    - net: stmmac: Fix race between stmmac_drv_probe and stmmac_open
+    - net/mlx5: Check FW limitations on log_max_qp before setting it
+    - net/mlx5: Avoid shadowing numa_node
+    - drop_monitor: add missing call to genlmsg_end
+    - drop_monitor: consider inserted data in genlmsg_end
+    - igmp: Make igmp group member RFC 3376 compliant
+    - ipv4: Do not allow MAIN to be alias for new LOCAL w/ custom rules
+    - r8152: split rtl8152_suspend function
+    - r8152: fix rx issue for runtime suspend
+    - gro: Enter slow-path if there is no tailroom
+    - gro: use min_t() in skb_gro_reset_offset()
+    - gro: Disable frag0 optimization on IPv6 ext headers
+    - net: ipv4: Fix multipath selection with vrf
+    - net: vrf: do not allow table id 0
+    - HID: hid-cypress: validate length of report
+    - ALSA: firewire-tascam: Fix to handle error from initialization of stream
+      data
+    - powerpc: Fix build warning on 32-bit PPC
+    - ARM: zynq: Reserve correct amount of non-DMA RAM
+    - ARM: OMAP4+: Fix bad fallthrough for cpuidle
+    - spi: mvebu: fix baudrate calculation for armada variant
+    - ALSA: usb-audio: Add a quirk for Plantronics BT600
+    - mm/init: fix zone boundary creation
+    - Linux 4.4.43
+
+  * Xenial update to v4.4.42 stable release (LP: #1655969)
+    - ALSA: hda - Fix up GPIO for ASUS ROG Ranger
+    - ALSA: hda - Apply asus-mode8 fixup to ASUS X71SL
+    - ALSA: usb-audio: Fix irq/process data synchronization
+    - ARM: davinci: da850: don't add emac clock to lookup table twice
+    - mac80211: initialize fast-xmit 'info' later
+    - KVM: x86: reset MMU on KVM_SET_VCPU_EVENTS
+    - KVM: MIPS: Flush KVM entry code from icache globally
+    - usb: musb: core: add clear_ep_rxintr() to musb_platform_ops
+    - usb: musb: dsps: implement clear_ep_rxintr() callback
+    - usb: storage: unusual_uas: Add JMicron JMS56x to unusual device
+    - usb: gadgetfs: restrict upper bound on device configuration size
+    - USB: gadgetfs: fix unbounded memory allocation bug
+    - USB: gadgetfs: fix use-after-free bug
+    - USB: gadgetfs: fix checks of wTotalLength in config descriptors
+    - USB: fix problems with duplicate endpoint addresses
+    - USB: dummy-hcd: fix bug in stop_activity (handle ep0)
+    - usb: gadget: composite: Test get_alt() presence instead of set_alt()
+    - usb: dwc3: core: avoid Overflow events
+    - usb: xhci: fix possible wild pointer
+    - xhci: workaround for hosts missing CAS bit
+    - usb: xhci: apply XHCI_PME_STUCK_QUIRK to Intel Apollo Lake
+    - xhci: free xhci virtual devices with leaf nodes first
+    - usb: xhci: fix return value of xhci_setup_device()
+    - usb: host: xhci: Fix possible wild pointer when handling abort command
+    - xhci: Handle command completion and timeout race
+    - usb: xhci: hold lock over xhci_abort_cmd_ring()
+    - USB: serial: omninet: fix NULL-derefs at open and disconnect
+    - USB: serial: quatech2: fix sleep-while-atomic in close
+    - USB: serial: pl2303: fix NULL-deref at open
+    - USB: serial: keyspan_pda: verify endpoints at probe
+    - USB: serial: spcp8x5: fix NULL-deref at open
+    - USB: serial: io_ti: fix NULL-deref at open
+    - USB: serial: io_ti: fix another NULL-deref at open
+    - USB: serial: io_ti: fix I/O after disconnect
+    - USB: serial: iuu_phoenix: fix NULL-deref at open
+    - USB: serial: garmin_gps: fix memory leak on failed URB submit
+    - USB: serial: ti_usb_3410_5052: fix NULL-deref at open
+    - USB: serial: io_edgeport: fix NULL-deref at open
+    - USB: serial: oti6858: fix NULL-deref at open
+    - USB: serial: cyberjack: fix NULL-deref at open
+    - USB: serial: kobil_sct: fix NULL-deref in write
+    - USB: serial: mos7840: fix NULL-deref at open
+    - USB: serial: mos7720: fix NULL-deref at open
+    - USB: serial: mos7720: fix use-after-free on probe errors
+    - USB: serial: mos7720: fix parport use-after-free on probe errors
+    - USB: serial: mos7720: fix parallel probe
+    - usb: xhci-mem: use passed in GFP flags instead of GFP_KERNEL
+    - xhci: Use delayed_work instead of timer for command timeout
+    - xhci: Fix race related to abort operation
+    - usb: dwc3: pci: add Intel Gemini Lake PCI ID
+    - usb: musb: Fix trying to free already-free IRQ 4
+    - usb: hub: Move hub_port_disable() to fix warning if PM is disabled
+    - usb: musb: blackfin: add bfin_fifo_offset in bfin_ops
+    - ALSA: usb-audio: Fix bogus error return in snd_usb_create_stream()
+    - USB: serial: kl5kusb105: abort on open exception path
+    - ARM: dts: r8a7794: Correct hsusb parent clock
+    - USB: phy: am335x-control: fix device and of_node leaks
+    - USB: serial: io_ti: bind to interface after fw download
+    - mei: bus: fix mei_cldev_enable KDoc
+    - staging: iio: ad7606: fix improper setting of oversampling pins
+    - usb: dwc3: gadget: always unmap EP0 requests
+    - usb: dwc3: ep0: add dwc3_ep0_prepare_one_trb()
+    - usb: dwc3: ep0: explicitly call dwc3_ep0_prepare_one_trb()
+    - stable-fixup: hotplug: fix unused function warning
+    - ath10k: use the right length of "background"
+    - cris: Only build flash rescue image if CONFIG_ETRAX_AXISFLASHMAP is selected
+    - hwmon: (scpi) Fix module autoload
+    - hwmon: (amc6821) sign extension temperature
+    - hwmon: (ds620) Fix overflows seen when writing temperature limits
+    - hwmon: (nct7802) Fix overflows seen when writing into limit attributes
+    - hwmon: (g762) Fix overflows and crash seen when writing limit attributes
+    - clk: clk-wm831x: fix a logic error
+    - clk: imx31: fix rewritten input argument of mx31_clocks_init()
+    - iommu/amd: Missing error code in amd_iommu_init_device()
+    - iommu/amd: Fix the left value check of cmd buffer
+    - iommu/vt-d: Fix pasid table size encoding
+    - iommu/vt-d: Flush old iommu caches for kdump when the device gets context
+      mapped
+    - ASoC: samsung: i2s: Fixup last IRQ unsafe spin lock call
+    - scsi: mvsas: fix command_active typo
+    - target/iscsi: Fix double free in lio_target_tiqn_addtpg()
+    - irqchip/bcm7038-l1: Implement irq_cpu_offline() callback
+    - PM / wakeirq: Fix dedicated wakeirq for drivers not using autosuspend
+    - mmc: mmc_test: Uninitialized return value
+    - s390/crypto: unlock on error in prng_tdes_read()
+    - crypto: arm64/sha2-ce - fix for big endian
+    - crypto: arm64/ghash-ce - fix for big endian
+    - crypto: arm/aes-ce - fix for big endian
+    - crypto: arm64/aes-ccm-ce: fix for big endian
+    - crypto: arm64/aes-neon - fix for big endian
+    - crypto: arm64/sha1-ce - fix for big endian
+    - crypto: arm64/aes-xts-ce: fix for big endian
+    - crypto: arm64/aes-ce - fix for big endian
+    - md: MD_RECOVERY_NEEDED is set for mddev->recovery
+    - powerpc/pci/rpadlpar: Fix device reference leaks
+    - staging: comedi: dt282x: tidy up register bit defines
+    - cred/userns: define current_user_ns() as a function
+    - net: ti: cpmac: Fix compiler warning due to type confusion
+    - net: vxge: avoid unused function warnings
+    - cx23885-dvb: move initialization of a8293_pdata
+    - drm/radeon: Always store CRTC relative radeon_crtc->cursor_x/y values
+    - tick/broadcast: Prevent NULL pointer dereference
+    - Revert "usb: gadget: composite: always set ep->mult to a sensible value"
+    - usb: gadget: composite: always set ep->mult to a sensible value
+    - Linux 4.4.42
+
+  * Xenial update to v4.4.41 stable release (LP: #1655041)
+    - ssb: Fix error routine when fallback SPROM fails
+    - rtlwifi: Fix enter/exit power_save
+    - cfg80211/mac80211: fix BSS leaks when abandoning assoc attempts
+    - ath9k: Really fix LED polarity for some Mini PCI AR9220 MB92 cards.
+    - mmc: sdhci: Fix recovery from tuning timeout
+    - regulator: stw481x-vmmc: fix ages old enable error
+    - timekeeping_Force_unsigned_clocksource_to_nanoseconds_conversion
+    - clk: bcm2835: Avoid overwriting the div info when disabling a pll_div clk
+    - thermal: hwmon: Properly report critical temperature in sysfs
+    - staging: comedi: ni_mio_common: fix M Series ni_ai_insn_read() data mask
+    - staging: comedi: ni_mio_common: fix E series ni_ai_insn_read() data
+    - ACPI / video: Add force_native quirk for Dell XPS 17 L702X
+    - ACPI / video: Add force_native quirk for HP Pavilion dv6
+    - drm/nouveau/kms: lvds panel strap moved again on maxwell
+    - drm/nouveau/bios: require checksum to match for fast acpi shadow method
+    - drm/nouveau/ltc: protect clearing of comptags with mutex
+    - drm/nouveau/fifo/gf100-: protect channel preempt with subdev mutex
+    - drm/nouveau/i2c/gk110b,gm10x: use the correct implementation
+    - drm/radeon: Also call cursor_move_locked when the cursor size changes
+    - drm/radeon: Hide the HW cursor while it's out of bounds
+    - drm/radeon: add additional pci revision to dpm workaround
+    - drm/gma500: Add compat ioctl
+    - drivers/gpu/drm/ast: Fix infinite loop if read fails
+    - mei: request async autosuspend at the end of enumeration
+    - block: protect iterate_bdevs() against concurrent close
+    - vt: fix Scroll Lock LED trigger name
+    - scsi: megaraid_sas: For SRIOV enabled firmware, ensure VF driver waits for
+      30secs before reset
+    - scsi: megaraid_sas: Do not set MPI2_TYPE_CUDA for JBOD FP path for FW which
+      does not support JBOD sequence map
+    - scsi: zfcp: fix use-after-"free" in FC ingress path after TMF
+    - scsi: zfcp: do not trace pure benign residual HBA responses at default level
+    - scsi: zfcp: fix rport unblock race with LUN recovery
+    - scsi: avoid a permanent stop of the scsi device's request queue
+    - ARC: mm: arc700: Don't assume 2 colours for aliasing VIPT dcache
+    - firmware: fix usermode helper fallback loading
+    - s390/vmlogrdr: fix IUCV buffer allocation
+    - sc16is7xx: Drop bogus use of IRQF_ONESHOT
+    - md/raid5: limit request size according to implementation limits
+    - KVM: PPC: Book3S HV: Save/restore XER in checkpointed register state
+    - KVM: PPC: Book3S HV: Don't lose hardware R/C bit updates in H_PROTECT
+    - kvm: nVMX: Allow L1 to intercept software exceptions (#BP and #OF)
+    - platform/x86: asus-nb-wmi.c: Add X45U quirk
+    - fgraph: Handle a case where a tracer ignores set_graph_notrace
+    - IB/mad: Fix an array index check
+    - IPoIB: Avoid reading an uninitialized member variable
+    - IB/multicast: Check ib_find_pkey() return value
+    - IB/cma: Fix a race condition in iboe_addr_get_sgid()
+    - media: solo6x10: fix lockup by avoiding delayed register write
+    - Input: drv260x - fix input device's parent assignment
+    - PCI: Check for PME in targeted sleep state
+    - libceph: verify authorize reply on connect
+    - nfs_write_end(): fix handling of short copies
+    - powerpc/ps3: Fix system hang with GCC 5 builds
+    - powerpc: Convert cmp to cmpd in idle enter sequence
+    - kconfig/nconf: Fix hang when editing symbol with a long prompt
+    - sg_write()/bsg_write() is not fit to be called under KERNEL_DS
+    - net: mvpp2: fix dma unmapping of TX buffers for fragments
+    - Linux 4.4.41
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 01 Feb 2017 14:00:35 -0200
+
+linux (4.4.0-62.83) xenial; urgency=low
+
+  [ Thadeu Lima de Souza Cascardo ]
+
+  * Release Tracking Bug
+    - LP: #1657430
+
+  * Backport DP MST fixes to i915 (LP: #1657353)
+    - SAUCE: i915_bpo: Fix DP link rate math
+    - SAUCE: i915_bpo: Validate mode against max. link data rate for DP MST
+
+  * Ubuntu xenial - 4.4.0-59-generic i3 I/O performance issue (LP: #1657281)
+    - blk-mq: really fix plug list flushing for nomerge queues
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 18 Jan 2017 09:34:07 -0200
+
+linux (4.4.0-61.82) xenial; urgency=low
+
+  [ Thadeu Lima de Souza Cascardo ]
+
+  * Release Tracking Bug
+    - LP: #1656810
+
+  * Xen MSI setup code incorrectly re-uses cached pirq (LP: #1656381)
+    - SAUCE: xen: do not re-use pirq number cached in pci device msi msg data
+
+  * nvme drive probe failure (LP: #1626894)
+    - nvme: revert NVMe: only setup MSIX once
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 16 Jan 2017 10:30:12 -0200
+
+linux (4.4.0-60.81) xenial; urgency=low
+
+  [ John Donnelly ]
+
+  * Release Tracking Bug
+    - LP: #1656084
+
+  * Couldn't emulate instruction 0x7813427c (LP: #1634129)
+    - KVM: PPC: Book3S PR: Fix illegal opcode emulation
+
+  * perf: 24x7: Eliminate domain name suffix in event names (LP: #1560482)
+    - powerpc/perf/hv-24x7: Fix usage with chip events.
+    - powerpc/perf/hv-24x7: Display change in counter values
+    - powerpc/perf/hv-24x7: Display domain indices in sysfs
+    - powerpc/perf/24x7: Eliminate domain suffix in event names
+
+  * i386 ftrace tests hang on ADT testing (LP: #1655040)
+    - ftrace/x86_32: Set ftrace_stub to weak to prevent gcc from using short jumps
+      to it
+
+  * VMX module autoloading if available (LP: #1651322)
+    - powerpc: Add module autoloading based on CPU features
+    - crypto: vmx - Convert to CPU feature based module autoloading
+
+  * ACPI probe support for AD5592/3 configurable multi-channel converter
+    (LP: #1654497)
+    - SAUCE: iio: dac: ad5592r: Add ACPI support
+    - SAUCE: iio: dac: ad5593r: Add ACPI support
+
+  * Xenial update to v4.4.40 stable release (LP: #1654602)
+    - btrfs: limit async_work allocation and worker func duration
+    - Btrfs: fix tree search logic when replaying directory entry deletes
+    - btrfs: store and load values of stripes_min/stripes_max in balance status
+      item
+    - Btrfs: fix qgroup rescan worker initialization
+    - USB: serial: option: add support for Telit LE922A PIDs 0x1040, 0x1041
+    - USB: serial: option: add dlink dwm-158
+    - USB: serial: kl5kusb105: fix open error path
+    - USB: cdc-acm: add device id for GW Instek AFG-125
+    - usb: hub: Fix auto-remount of safely removed or ejected USB-3 devices
+    - usb: gadget: f_uac2: fix error handling at afunc_bind
+    - usb: gadget: composite: correctly initialize ep->maxpacket
+    - USB: UHCI: report non-PME wakeup signalling for Intel hardware
+    - ALSA: usb-audio: Add QuickCam Communicate Deluxe/S7500 to
+      volume_control_quirks
+    - ALSA: hiface: Fix M2Tech hiFace driver sampling rate change
+    - ALSA: hda/ca0132 - Add quirk for Alienware 15 R2 2016
+    - ALSA: hda - ignore the assoc and seq when comparing pin configurations
+    - ALSA: hda - fix headset-mic problem on a Dell laptop
+    - ALSA: hda - Gate the mic jack on HP Z1 Gen3 AiO
+    - ALSA: hda: when comparing pin configurations, ignore assoc in addition to
+      seq
+    - clk: ti: omap36xx: Work around sprz319 advisory 2.1
+    - Btrfs: fix memory leak in reading btree blocks
+    - Btrfs: bail out if block group has different mixed flag
+    - Btrfs: return gracefully from balance if fs tree is corrupted
+    - Btrfs: don't leak reloc root nodes on error
+    - Btrfs: fix memory leak in do_walk_down
+    - Btrfs: don't BUG() during drop snapshot
+    - btrfs: make file clone aware of fatal signals
+    - block_dev: don't test bdev->bd_contains when it is not stable
+    - ptrace: Capture the ptracer's creds not PT_PTRACE_CAP
+    - crypto: caam - fix AEAD givenc descriptors
+    - ext4: fix mballoc breakage with 64k block size
+    - ext4: fix stack memory corruption with 64k block size
+    - ext4: use more strict checks for inodes_per_block on mount
+    - ext4: fix in-superblock mount options processing
+    - ext4: add sanity checking to count_overhead()
+    - ext4: reject inodes with negative size
+    - ext4: return -ENOMEM instead of success
+    - ext4: do not perform data journaling when data is encrypted
+    - f2fs: set ->owner for debugfs status file's file_operations
+    - loop: return proper error from loop_queue_rq()
+    - mm/vmscan.c: set correct defer count for shrinker
+    - fs: exec: apply CLOEXEC before changing dumpable task flags
+    - exec: Ensure mm->user_ns contains the execed files
+    - usb: gadget: composite: always set ep->mult to a sensible value
+    - blk-mq: Do not invoke .queue_rq() for a stopped queue
+    - dm flakey: return -EINVAL on interval bounds error in flakey_ctr()
+    - dm crypt: mark key as invalid until properly loaded
+    - dm space map metadata: fix 'struct sm_metadata' leak on failed create
+    - ASoC: intel: Fix crash at suspend/resume without card registration
+    - CIFS: Fix a possible memory corruption during reconnect
+    - CIFS: Fix missing nls unload in smb2_reconnect()
+    - CIFS: Fix a possible memory corruption in push locks
+    - kernel/watchdog: use nmi registers snapshot in hardlockup handler
+    - kernel/debug/debug_core.c: more properly delay for secondary CPUs
+    - tpm xen: Remove bogus tpm_chip_unregister
+    - xen/gntdev: Use VM_MIXEDMAP instead of VM_IO to avoid NUMA balancing
+    - arm/xen: Use alloc_percpu rather than __alloc_percpu
+    - xfs: set AGI buffer type in xlog_recover_clear_agi_bucket
+    - driver core: fix race between creating/querying glue dir and its cleanup
+    - ppp: defer netns reference release for ppp channel
+    - Linux 4.4.40
+
+  * igb i210 probe of pci device failed with error -2 (LP: #1639810)
+    - SAUCE: igb: Workaround for igb i210 firmware issue.
+    - SAUCE: igb: add i211 to i210 PHY workaround
+
+  * PowerNV: PCI Slot is invalid after fencedPHB Error injection (LP: #1652018)
+    - powerpc/powernv: Call opal_pci_poll() if needed
+
+  * mfd: intel-lpss: Add default I2C device properties for Apollo Lake
+    (LP: #1635177)
+    - mfd: intel-lpss: Add default I2C device properties for Apollo Lake
+
+  * Xenial update to v4.4.39 stable release (LP: #1650609)
+    - powerpc/eeh: Fix deadlock when PE frozen state can't be cleared
+    - parisc: Purge TLB before setting PTE
+    - parisc: Remove unnecessary TLB purges from flush_dcache_page_asm and
+      flush_icache_page_asm
+    - parisc: Fix TLB related boot crash on SMP machines
+    - zram: restrict add/remove attributes to root only
+    - locking/rtmutex: Prevent dequeue vs. unlock race
+    - locking/rtmutex: Use READ_ONCE() in rt_mutex_owner()
+    - perf/x86: Fix full width counter, counter overflow
+    - crypto: mcryptd - Check mcryptd algorithm compatibility
+    - can: raw: raw_setsockopt: limit number of can_filter that can be set
+    - can: peak: fix bad memory access and free sequence
+    - arm64: futex.h: Add missing PAN toggling
+    - m68k: Fix ndelay() macro
+    - batman-adv: Check for alloc errors when preparing TT local data
+    - hotplug: Make register and unregister notifier API symmetric
+    - crypto: rsa - Add Makefile dependencies to fix parallel builds
+    - Linux 4.4.39
+
+  * Xenial update to v4.4.38 stable release (LP: #1650607)
+    - virtio-net: add a missing synchronize_net()
+    - net: check dead netns for peernet2id_alloc()
+    - ip6_tunnel: disable caching when the traffic class is inherited
+    - net: sky2: Fix shutdown crash
+    - af_unix: conditionally use freezable blocking calls in read
+    - rtnetlink: fix FDB size computation
+    - l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()
+    - net: dsa: bcm_sf2: Ensure we re-negotiate EEE during after link change
+    - net, sched: respect rcu grace period on cls destruction
+    - net/sched: pedit: make sure that offset is valid
+    - netlink: Call cb->done from a worker thread
+    - netlink: Do not schedule work from sk_destruct
+    - net/dccp: fix use-after-free in dccp_invalid_packet
+    - net: bcmgenet: Utilize correct struct device for all DMA operations
+    - sh_eth: remove unchecked interrupts for RZ/A1
+    - geneve: avoid use-after-free of skb->data
+    - net: ping: check minimum size on ICMP header length
+    - sparc32: Fix inverted invalid_frame_pointer checks on sigreturns
+    - sparc64: Fix find_node warning if numa node cannot be found
+    - sparc64: fix compile warning section mismatch in find_node()
+    - constify iov_iter_count() and iter_is_iovec()
+    - Don't feed anything but regular iovec's to blk_rq_map_user_iov
+    - ipv6: Set skb->protocol properly for local output
+    - ipv4: Set skb->protocol properly for local output
+    - esp4: Fix integrity verification when ESN are used
+    - esp6: Fix integrity verification when ESN are used
+    - Linux 4.4.38
+
+  * Xenial update to v4.4.37 stable release (LP: #1650604)
+    - ARC: Don't use "+l" inline asm constraint
+    - zram: fix unbalanced idr management at hot removal
+    - kasan: update kasan_global for gcc 7
+    - x86/traps: Ignore high word of regs->cs in early_fixup_exception()
+    - rcu: Fix soft lockup for rcu_nocb_kthread
+    - PCI: Export pcie_find_root_port
+    - PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)
+    - mwifiex: printk() overflow with 32-byte SSIDs
+    - pwm: Fix device reference leak
+    - arm64: cpufeature: Schedule enable() calls instead of calling them via IPI
+    - arm64: mm: Set PSTATE.PAN from the cpu_enable_pan() call
+    - arm64: suspend: Reconfigure PSTATE after resume from idle
+    - Linux 4.4.37
+
+  * Xenial update to v4.4.36 stable release (LP: #1650601)
+    - iommu/vt-d: Fix PASID table allocation
+    - iommu/vt-d: Fix IOMMU lookup for SR-IOV Virtual Functions
+    - KVM: x86: check for pic and ioapic presence before use
+    - usb: chipidea: move the lock initialization to core file
+    - USB: serial: cp210x: add ID for the Zone DPMX
+    - USB: serial: ftdi_sio: add support for TI CC3200 LaunchPad
+    - Fix USB CB/CBI storage devices with CONFIG_VMAP_STACK=y
+    - scsi: mpt3sas: Fix secure erase premature termination
+    - tile: avoid using clocksource_cyc2ns with absolute cycle count
+    - cfg80211: limit scan results cache size
+    - NFSv4.x: hide array-bounds warning
+    - parisc: Fix races in parisc_setup_cache_timing()
+    - parisc: Fix race in pci-dma.c
+    - parisc: Also flush data TLB in flush_icache_page_asm
+    - mpi: Fix NULL ptr dereference in mpi_powm() [ver #3]
+    - drm/radeon: Ensure vblank interrupt is enabled on DPMS transition to on
+    - mei: me: disable driver on SPT SPS firmware
+    - mei: me: fix place for kaby point device ids.
+    - mei: fix return value on disconnection
+    - scsi: mpt3sas: Unblock device after controller reset
+    - Linux 4.4.36
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] consider renames in gen-auto-reconstruct
+
+ -- John Donnelly <john.donnelly@canonical.com>  Fri, 13 Jan 2017 08:54:11 +0000
+
+linux (4.4.0-59.80) xenial; urgency=low
+
+  [ John Donnelly ]
+
+  * Release Tracking Bug
+    - LP: #1654282
+
+  * [2.1.1] MAAS has nvme0n1 set as boot disk, curtin fails (LP: #1651602)
+    - (fix) nvme: only require 1 interrupt vector, not 2+
+
+ -- John Donnelly <john.donnelly@canonical.com>  Thu, 05 Jan 2017 12:49:16 +0000
+
+linux (4.4.0-58.79) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1651402
+
+  * Support ACPI probe for IIO sensor drivers from ST Micro (LP: #1650123)
+    - SAUCE: iio: st_sensors: match sensors using ACPI handle
+    - SAUCE: iio: st_accel: Support sensor i2c probe using acpi
+    - SAUCE: iio: st_pressure: Support i2c probe using acpi
+    - [Config] CONFIG_HTS221=m, CONFIG_HTS221_I2C=m, CONFIG_HTS221_SPI=m
+
+  * Fix channel data parsing in ST Micro sensor IIO drivers (LP: #1650189)
+    - SAUCE: iio: common: st_sensors: fix channel data parsing
+
+  * ST Micro lng2dm 3-axis "femto" accelerometer support (LP: #1650112)
+    - SAUCE: iio: st-accel: add support for lis2dh12
+    - SAUCE: iio: st_sensors: support active-low interrupts
+    - SAUCE: iio: accel: Add support for the h3lis331dl accelerometer
+    - SAUCE: iio: st_sensors: verify interrupt event to status
+    - SAUCE: iio: st_sensors: support open drain mode
+    - SAUCE: iio:st_sensors: fix power regulator usage
+    - SAUCE: iio: st_sensors: switch to a threaded interrupt
+    - SAUCE: iio: accel: st_accel: Add lis3l02dq support
+    - SAUCE: iio: st_sensors: fix scale configuration for h3lis331dl
+    - SAUCE: iio: accel: st_accel: add support to lng2dm
+    - SAUCE: iio: accel: st_accel: inline per-sensor data
+    - SAUCE: Documentation: dt: iio: accel: add lng2dm sensor device binding
+
+  * ST Micro hts221 relative humidity sensor support (LP: #1650116)
+    - SAUCE: iio: humidity: add support to hts221 rh/temp combo device
+    - SAUCE: Documentation: dt: iio: humidity: add hts221 sensor device binding
+    - SAUCE: iio: humidity: remove
+    - SAUCE: iio: humidity: Support acpi probe for hts211
+
+  * crypto : tolerate new crypto hardware for z Systems (LP: #1644557)
+    - s390/zcrypt: Introduce CEX6 toleration
+
+  * Acer, Inc ID 5986:055a is useless after 14.04.2 installed. (LP: #1433906)
+    - uvcvideo: uvc_scan_fallback() for webcams with broken chain
+
+  * vmxnet3 driver could causes kernel panic with v4.4 if LRO enabled.
+    (LP: #1650635)
+    - vmxnet3: segCnt can be 1 for LRO packets
+
+  * system freeze when swapping to encrypted swap partition (LP: #1647400)
+    - mm, oom: rework oom detection
+    - mm: throttle on IO only when there are too many dirty and writeback pages
+
+  * Kernel Fixes to get TCMU File Backed Optical to work (LP: #1646204)
+    - target/user: Use sense_reason_t in tcmu_queue_cmd_ring
+    - target/user: Return an error if cmd data size is too large
+    - target/user: Fix comments to not refer to data ring
+    - SAUCE: (no-up) target/user: Fix use-after-free of tcmu_cmds if they are
+      expired
+
+  * CVE-2016-9756
+    - KVM: x86: drop error recovery in em_jmp_far and em_ret_far
+
+  * Dell Precision 5520 & 3520 freezes at login screent (LP: #1650054)
+    - ACPI / blacklist: add _REV quirks for Dell Precision 5520 and 3520
+
+  * CVE-2016-9794
+    - ALSA: pcm : Call kill_fasync() in stream lock
+
+  * Allow fuse user namespace mounts by default in xenial (LP: #1634964)
+    - (namespace) mnt: Move the FS_USERNS_MOUNT check into sget_userns
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Refuse uid/gid changes which don't
+      map into s_user_ns"
+    - (namespace) fs: Refuse uid/gid changes which don't map into s_user_ns
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Update posix_acl support to handle
+      user namespace mounts"
+    - (namespace) vfs: Verify acls are valid within superblock's s_user_ns.
+    - SAUCE: (namespace) posix_acl: Export posix_acl_fix_xattr_userns() to modules
+    - SAUCE: (namespace) fuse: Translate ids in posix acl xattrs
+    - (namespace) vfs: Don't modify inodes with a uid or gid unknown to the vfs
+    - (namespace) vfs: Don't create inodes with a uid or gid unknown to the vfs
+    - (namespace) Revert "UBUNTU: SAUCE: quota: Require that qids passed to
+      dqget() be valid and map into s_user_ns"
+    - (namespace) Revert "UBUNTU: SAUCE: quota: Convert ids relative to s_user_ns"
+    - (namespace) quota: Ensure qids map to the filesystem
+    - (namespace) quota: Handle quota data stored in s_user_ns in quota_setxquota
+    - (namespace) dquot: For now explicitly don't support filesystems outside of
+      init_user_ns
+    - (namespace) Revert "UBUNTU: SAUCE: ima/evm: Allow root in s_user_ns to set
+      xattrs"
+    - SAUCE: (namespace) security/integrity: Harden against malformed xattrs
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Allow superblock owner to change
+      ownership of inodes with unmappable ids"
+    - SAUCE: (namespace) fs: Allow superblock owner to change ownership of inodes
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Don't remove suid for CAP_FSETID in
+      s_user_ns"
+    - SAUCE: (namespace) fs: Don't remove suid for CAP_FSETID for userns root
+    - SAUCE: (namespace) fuse: Allow user namespace mounts by default
+
+  * Boot crash in xen_send_IPI_one (LP: #1649821)
+    - xen/qspinlock: Don't kick CPU if IRQ is not initialized
+
+  * linux: Staging modules should be unsigned (LP: #1642368)
+    - [Debian] Suppress module signing for staging drivers
+    - SAUCE: Add rtl drivers to signature inclusion list
+
+  * Ethernet not work after upgrade from kernel 3.19 to 4.4 [10ec:8168]
+    (LP: #1648279)
+    - ACPI / blacklist: Make Dell Latitude 3350 ethernet work
+
+  * CVE-2016-9793
+    - net: avoid signed overflows for SO_{SND|RCV}BUFFORCE
+
+  * [Hyper-V] Kernel panic not functional on 32bit Ubuntu 14.10, 15.04, and
+    15.10 (LP: #1400319)
+    - Drivers: hv: avoid vfree() on crash
+
+  * [Hyper-V] netvsc: fix incorrect receive checksum offloading (LP: #1636656)
+    - netvsc: fix incorrect receive checksum offloading
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Tue, 20 Dec 2016 10:54:41 +0000
+
+linux (4.4.0-57.78) xenial; urgency=low
+
+  * Release Tracking Bug
+    - LP: #1648867
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Do not build the xr-usb-serial driver for s390
+
+ -- Brad Figg <brad.figg@canonical.com>  Fri, 09 Dec 2016 10:51:16 -0800
+
+linux (4.4.0-56.77) xenial; urgency=low
+
+  * Release Tracking Bug
+    - LP: #1648867
+
+  * Release Tracking Bug
+    - LP: #1648579
+
+  * CONFIG_NR_CPUS=256 is too low (LP: #1579205)
+    - [Config] Increase the NR_CPUS to 512 for amd64 to support systems with a
+      large number of cores.
+
+  * NVMe drives in Amazon AWS instance fail to initialize (LP: #1648449)
+    - SAUCE: (no-up) NVMe: only setup MSIX once
+
+ -- Brad Figg <brad.figg@canonical.com>  Thu, 08 Dec 2016 10:50:49 -0800
+
+linux (4.4.0-55.76) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1648503
+
+  * NVMe driver accidentally reverted to use GSI instead of MSIX (LP: #1647887)
+    - (fix) NVMe: restore code to always use MSI/MSI-x interrupts
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Thu, 08 Dec 2016 14:34:40 +0000
+
+linux (4.4.0-54.75) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1648017
+
+  * Update hio driver to 2.1.0.28 (LP: #1646643)
+    - SAUCE: hio: update to Huawei ES3000_V2 (2.1.0.28)
+
+  * linux: Enable live patching for all supported architectures (LP: #1633577)
+    - [Config] CONFIG_LIVEPATCH=y for s390x
+
+  * Botched backport breaks level triggered EOIs in QEMU guests with --machine
+    kernel_irqchip=split (LP: #1644394)
+    - kvm/irqchip: kvm_arch_irq_routing_update renaming split
+
+  * Xenial update to v4.4.35 stable release (LP: #1645453)
+    - x86/cpu/AMD: Fix cpu_llc_id for AMD Fam17h systems
+    - KVM: x86: fix missed SRCU usage in kvm_lapic_set_vapic_addr
+    - KVM: Disable irq while unregistering user notifier
+    - fuse: fix fuse_write_end() if zero bytes were copied
+    - mfd: intel-lpss: Do not put device in reset state on suspend
+    - can: bcm: fix warning in bcm_connect/proc_register
+    - i2c: mux: fix up dependencies
+    - kbuild: add -fno-PIE
+    - scripts/has-stack-protector: add -fno-PIE
+    - x86/kexec: add -fno-PIE
+    - kbuild: Steal gcc's pie from the very beginning
+    - ext4: sanity check the block and cluster size at mount time
+    - crypto: caam - do not register AES-XTS mode on LP units
+    - drm/amdgpu: Attach exclusive fence to prime exported bo's. (v5)
+    - clk: mmp: pxa910: fix return value check in pxa910_clk_init()
+    - clk: mmp: pxa168: fix return value check in pxa168_clk_init()
+    - clk: mmp: mmp2: fix return value check in mmp2_clk_init()
+    - rtc: omap: Fix selecting external osc
+    - iwlwifi: pcie: fix SPLC structure parsing
+    - mfd: core: Fix device reference leak in mfd_clone_cell
+    - uwb: fix device reference leaks
+    - PM / sleep: fix device reference leak in test_suspend
+    - PM / sleep: don't suspend parent when async child suspend_{noirq, late}
+      fails
+    - IB/mlx4: Check gid_index return value
+    - IB/mlx4: Fix create CQ error flow
+    - IB/mlx5: Use cache line size to select CQE stride
+    - IB/mlx5: Fix fatal error dispatching
+    - IB/core: Avoid unsigned int overflow in sg_alloc_table
+    - IB/uverbs: Fix leak of XRC target QPs
+    - IB/cm: Mark stale CM id's whenever the mad agent was unregistered
+    - netfilter: nft_dynset: fix element timeout for HZ != 1000
+    - Linux 4.4.35
+
+  * Upstream stable 4.4.34 and 4.8.10 regression (LP: #1645278)
+    - flow_dissect: call init_default_flow_dissectors() earlier
+
+  * AD5593R configurable multi-channel converter support (LP: #1644726)
+    - iio: dac: Add support for the AD5592R/AD5593R ADCs/DACs
+    - iio: dac: ad5592r: Off by one bug in ad5592r_alloc_channels()
+    - [Config] CONFIG_AD5592R/AD5593R=m
+
+  * ST Micro lps22hb pressure sensor support (LP: #1642258)
+    - iio:st_pressure:initial lps22hb sensor support
+    - iio:st_pressure: align storagebits on power of 2
+    - iio:st_pressure: document sampling gains
+    - iio:st_pressure:lps22hb: temperature support
+
+  * Fix Kernel Crashing under IBM Virtual Scsi Driver (LP: #1642299)
+    - SAUCE: ibmvscsis: Rearrange functions for future patches
+    - SAUCE: ibmvscsis: Synchronize cmds at tpg_enable_store time
+    - SAUCE: ibmvscsis: Synchronize cmds at remove time
+    - SAUCE: ibmvscsis: Clean up properly if target_submit_cmd/tmr fails
+    - SAUCE: ibmvscsis: Return correct partition name/# to client
+    - SAUCE: ibmvscsis: Issues from Dan Carpenter/Smatch
+
+  * System stalls when creating device node on booting (LP: #1643797)
+    - sched/fair: Fix new task's load avg removed from source CPU in
+      wake_up_new_task()
+
+  * nvme: improve performance for virtual Google NVMe devices (LP: #1637565)
+    - blk-mq: add blk_mq_alloc_request_hctx
+    - nvme.h: add NVMe over Fabrics definitions
+    - [Config] CONFIG_NVME_VENDOR_EXT_GOOGLE=y
+    - SAUCE: nvme: improve performance for virtual NVMe devices
+
+  * Move some kernel modules to the main kernel package (LP: #1642228)
+    - [Config] Move some powerpc kernel modules to the main kernel package
+
+  * sched: Match-all classifier is missing in xenial (LP: #1642514)
+    - [Config] CONFIG_NET_CLS_MATCHALL=m
+    - net/sched: introduce Match-all classifier
+
+  * Xenial update to 4.4.34 stable release (LP: #1643637)
+    - dctcp: avoid bogus doubling of cwnd after loss
+    - net: clear sk_err_soft in sk_clone_lock()
+    - net: mangle zero checksum in skb_checksum_help()
+    - bgmac: stop clearing DMA receive control register right after it is set
+    - ip6_tunnel: Clear IP6CB in ip6tunnel_xmit()
+    - tcp: fix potential memory corruption
+    - dccp: do not send reset to already closed sockets
+    - dccp: fix out of bound access in dccp_v4_err()
+    - ipv6: dccp: fix out of bound access in dccp_v6_err()
+    - ipv6: dccp: add missing bind_conflict to dccp_ipv6_mapped
+    - sctp: assign assoc_id earlier in __sctp_connect
+    - fib_trie: Correct /proc/net/route off by one error
+    - sock: fix sendmmsg for partial sendmsg
+    - net: __skb_flow_dissect() must cap its return value
+    - ipv4: use new_gw for redirect neigh lookup
+    - tcp: take care of truncations done by sk_filter()
+    - tty: Prevent ldisc drivers from re-using stale tty fields
+    - sparc: Don't leak context bits into thread->fault_address
+    - sparc: serial: sunhv: fix a double lock bug
+    - sparc64 mm: Fix base TSB sizing when hugetlb pages are used
+    - sparc: Handle negative offsets in arch_jump_label_transform
+    - sparc64: Handle extremely large kernel TSB range flushes sanely.
+    - sparc64: Fix illegal relative branches in hypervisor patched TLB code.
+    - sparc64: Fix instruction count in comment for
+      __hypervisor_flush_tlb_pending.
+    - sparc64: Fix illegal relative branches in hypervisor patched TLB cross-call
+      code.
+    - sparc64: Handle extremely large kernel TLB range flushes more gracefully.
+    - sparc64: Delete __ret_efault.
+    - sparc64: Prepare to move to more saner user copy exception handling.
+    - sparc64: Convert copy_in_user to accurate exception reporting.
+    - sparc64: Convert GENcopy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert U1copy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert NG4copy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert NGcopy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert NG2copy_{from,to}_user to accurate exception reporting.
+    - sparc64: Convert U3copy_{from,to}_user to accurate exception reporting.
+    - sparc64: Delete now unused user copy assembler helpers.
+    - sparc64: Delete now unused user copy fixup functions.
+    - Linux 4.4.34
+
+  * Xenial update to v4.4.33 stable release (LP: #1642968)
+    - ALSA: info: Return error for invalid read/write
+    - ALSA: info: Limit the proc text input size
+    - ASoC: cs4270: fix DAPM stream name mismatch
+    - dib0700: fix nec repeat handling
+    - swapfile: fix memory corruption via malformed swapfile
+    - coredump: fix unfreezable coredumping task
+    - s390/hypfs: Use get_free_page() instead of kmalloc to ensure page alignment
+    - ARC: timer: rtc: implement read loop in "C" vs. inline asm
+    - pinctrl: cherryview: Serialize register access in suspend/resume
+    - pinctrl: cherryview: Prevent possible interrupt storm on resume
+    - staging: iio: ad5933: avoid uninitialized variable in error case
+    - drivers: staging: nvec: remove bogus reset command for PS/2 interface
+    - Revert "staging: nvec: ps2: change serio type to passthrough"
+    - staging: nvec: remove managed resource from PS2 driver
+    - USB: cdc-acm: fix TIOCMIWAIT
+    - usb: gadget: u_ether: remove interrupt throttling
+    - drbd: Fix kernel_sendmsg() usage - potential NULL deref
+    - toshiba-wmi: Fix loading the driver on non Toshiba laptops
+    - clk: qoriq: Don't allow CPU clocks higher than starting value
+    - iio: hid-sensors: Increase the precision of scale to fix wrong reading
+      interpretation.
+    - iio: orientation: hid-sensor-rotation: Add PM function (fix non working
+      driver)
+    - scsi: qla2xxx: Fix scsi scan hang triggered if adapter fails during init
+    - scsi: mpt3sas: Fix for block device of raid exists even after deleting raid
+      disk
+    - KVM: MIPS: Precalculate MMIO load resume PC
+    - drm/i915: Respect alternate_ddc_pin for all DDI ports
+    - dmaengine: at_xdmac: fix spurious flag status for mem2mem transfers
+    - tty/serial: at91: fix hardware handshake on Atmel platforms
+    - iommu/amd: Free domain id when free a domain of struct dma_ops_domain
+    - iommu/vt-d: Fix dead-locks in disable_dmar_iommu() path
+    - mei: bus: fix received data size check in NFC fixup
+    - lib/genalloc.c: start search from start of chunk
+    - hwrng: core - Don't use a stack buffer in add_early_randomness()
+    - i40e: fix call of ndo_dflt_bridge_getlink()
+    - ACPI / APEI: Fix incorrect return value of ghes_proc()
+    - ASoC: sun4i-codec: return error code instead of NULL when create_card fails
+    - mmc: mxs: Initialize the spinlock prior to using it
+    - btrfs: qgroup: Prevent qgroup->reserved from going subzero
+    - netfilter: fix namespace handling in nf_log_proc_dostring
+    - Linux 4.4.33
+
+  * Xenial update to 4.4.32 stable release (LP: #1642573)
+    - tcp: fix overflow in __tcp_retransmit_skb()
+    - net: avoid sk_forward_alloc overflows
+    - tcp: fix wrong checksum calculation on MTU probing
+    - tcp: fix a compile error in DBGUNDO()
+    - ip6_gre: fix flowi6_proto value in ip6gre_xmit_other()
+    - ipmr, ip6mr: fix scheduling while atomic and a deadlock with ipmr_get_route
+    - tg3: Avoid NULL pointer dereference in tg3_io_error_detected()
+    - net: fec: set mac address unconditionally
+    - net: pktgen: fix pkt_size
+    - net/sched: act_vlan: Push skb->data to mac_header prior calling skb_vlan_*()
+      functions
+    - net: Add netdev all_adj_list refcnt propagation to fix panic
+    - packet: call fanout_release, while UNREGISTERING a netdev
+    - netlink: do not enter direct reclaim from netlink_dump()
+    - ipv6: tcp: restore IP6CB for pktoptions skbs
+    - ip6_tunnel: fix ip6_tnl_lookup
+    - net: pktgen: remove rcu locking in pktgen_change_name()
+    - bridge: multicast: restore perm router ports on multicast enable
+    - rtnetlink: Add rtnexthop offload flag to compare mask
+    - net: add recursion limit to GRO
+    - ipv4: disable BH in set_ping_group_range()
+    - ipv4: use the right lock for ping_group_range
+    - net: sctp, forbid negative length
+    - udp: fix IP_CHECKSUM handling
+    - net sched filters: fix notification of filter delete with proper handle
+    - sctp: validate chunk len before actually using it
+    - packet: on direct_xmit, limit tso and csum to supported devices
+    - of: silence warnings due to max() usage
+    - Revert KVM: MIPS: Drop other CPU ASIDs on guest MMU changes
+    - KVM: MIPS: Drop other CPU ASIDs on guest MMU changes
+    - drm/amdgpu/dp: add back special handling for NUTMEG
+    - drm/amdgpu: fix DP mode validation
+    - drm/radeon: fix DP mode validation
+    - scsi: megaraid_sas: fix macro MEGASAS_IS_LOGICAL to avoid regression
+    - Linux 4.4.32
+
+  * Xenial update to 4.4.31 stable release (LP: #1642572)
+    - i2c: xgene: Avoid dma_buffer overrun
+    - i2c: core: fix NULL pointer dereference under race condition
+    - drm/dp/mst: Clear port->pdt when tearing down the i2c adapter
+    - h8300: fix syscall restarting
+    - libxfs: clean up _calc_dquots_per_chunk
+    - mm/list_lru.c: avoid error-path NULL pointer deref
+    - mm: memcontrol: do not recurse in direct reclaim
+    - ALSA: usb-audio: Add quirk for Syntek STK1160
+    - ALSA: hda - Merge RIRB_PRE_DELAY into CTX_WORKAROUND caps
+    - ALSA: hda - Raise AZX_DCAPS_RIRB_DELAY handling into top drivers
+    - ALSA: hda - allow 40 bit DMA mask for NVidia devices
+    - ALSA: hda - Adding a new group of pin cfg into ALC295 pin quirk table
+    - ALSA: hda - Fix headset mic detection problem for two Dell laptops
+    - ANDROID: binder: Add strong ref checks
+    - ANDROID: binder: Clear binder and cookie when setting handle in flat binder
+      struct
+    - btrfs: fix races on root_log_ctx lists
+    - ubifs: Abort readdir upon error
+    - ubifs: Fix regression in ubifs_readdir()
+    - mei: txe: don't clean an unprocessed interrupt cause.
+    - usb: gadget: function: u_ether: don't starve tx request queue
+    - USB: serial: fix potential NULL-dereference at probe
+    - USB: serial: ftdi_sio: add support for Infineon TriBoard TC2X7
+    - xhci: use default USB_RESUME_TIMEOUT when resuming ports.
+    - usb: increase ohci watchdog delay to 275 msec
+    - Fix potential infoleak in older kernels
+    - vt: clear selection before resizing
+    - xhci: add restart quirk for Intel Wildcatpoint PCH
+    - tty: limit terminal size to 4M chars
+    - USB: serial: cp210x: fix tiocmget error handling
+    - dm: free io_barrier after blk_cleanup_queue call
+    - KVM: x86: fix wbinvd_dirty_mask use-after-free
+    - KVM: MIPS: Make ERET handle ERL before EXL
+    - ovl: fsync after copy-up
+    - parisc: Ensure consistent state when switching to kernel stack at syscall
+      entry
+    - virtio_ring: Make interrupt suppression spec compliant
+    - virtio: console: Unlock vqs while freeing buffers
+    - dm mirror: fix read error on recovery after default leg failure
+    - Input: i8042 - add XMG C504 to keyboard reset table
+    - firewire: net: guard against rx buffer overflows
+    - firewire: net: fix fragmented datagram_size off-by-one
+    - mac80211: discard multicast and 4-addr A-MSDUs
+    - scsi: megaraid_sas: Fix data integrity failure for JBOD (passthrough)
+      devices
+    - scsi: scsi_debug: Fix memory leak if LBP enabled and module is unloaded
+    - scsi: arcmsr: Send SYNCHRONIZE_CACHE command to firmware
+    - mmc: dw_mmc-pltfm: fix the potential NULL pointer dereference
+    - Revert "drm/radeon: fix DP link training issue with second 4K monitor"
+    - drm/radeon/si_dpm: Limit clocks on HD86xx part
+    - drm/radeon/si_dpm: workaround for SI kickers
+    - drm/radeon: drop register readback in cayman_cp_int_cntl_setup
+    - drm/dp/mst: Check peer device type before attempting EDID read
+    - perf build: Fix traceevent plugins build race
+    - x86/xen: fix upper bound of pmd loop in xen_cleanhighmap()
+    - powerpc/ptrace: Fix out of bounds array access warning
+    - ARM: 8584/1: floppy: avoid gcc-6 warning
+    - mm/cma: silence warnings due to max() usage
+    - drm/exynos: fix error handling in exynos_drm_subdrv_open
+    - cgroup: avoid false positive gcc-6 warning
+    - smc91x: avoid self-comparison warning
+    - Disable "frame-address" warning
+    - UBI: fastmap: scrub PEB when bitflips are detected in a free PEB EC header
+    - pwm: Unexport children before chip removal
+    - usb: dwc3: Fix size used in dma_free_coherent()
+    - tty: vt, fix bogus division in csi_J
+    - kvm: x86: Check memopp before dereference (CVE-2016-8630)
+    - ubi: fastmap: Fix add_vol() return value test in ubi_attach_fastmap()
+    - HID: usbhid: add ATEN CS962 to list of quirky devices
+    - Linux 4.4.31
+
+  * CVE-2016-6213
+    - mnt: Add a per mount namespace limit on the number of mounts
+
+  * ThinkPad T460 hotkeys stop working in Ubuntu 16.04 (LP: #1642114)
+    - thinkpad_acpi: Add support for HKEY version 0x200
+
+  * CVE-2016-4568
+    - videobuf2-v4l2: Verify planes array in buffer dequeueing
+
+  * [SRU] Add 0cf3:e009 to btusb (LP: #1641562)
+    - Bluetooth: btusb: Add support for 0cf3:e009
+
+  * Fix resource leak in btusb (LP: #1641569)
+    - SAUCE: Bluetooth: decrease refcount after use
+
+  * WiFi LED doesn't work on some Edge Gateway units (LP: #1640418)
+    - SAUCE: mwifiex: Use PCI ID instead of DMI ID to identify Edge Gateways
+
+  * [Hyper-V] do not lose pending heartbeat vmbus packets (LP: #1632786)
+    - hv: do not lose pending heartbeat vmbus packets
+
+  * ipv6: connected routes are missing after a down/up cycle on the loopback
+    (LP: #1634545)
+    - ipv6: correctly add local routes when lo goes up
+
+  * audit: prevent a new auditd to stop an old auditd still alive (LP: #1633404)
+    - audit: stop an old auditd being starved out by a new auditd
+
+  * hv_set_ifconfig script parsing fails for certain configuration
+    (LP: #1640109)
+    - hv_set_ifconfig -- handle DHCP interfaces correctly
+    - hv_set_ifconfig -- ensure we include the last stanza
+
+  * CVE-2016-7039 and CVE-2016-8666 (LP: #1631287)
+    - Revert "UBUNTU: SAUCE: net: add recursion limit to GRO"
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Wed, 07 Dec 2016 10:13:50 +0000
+
+linux (4.4.0-53.74) xenial; urgency=low
+
+  * CVE-2016-8655 (LP: #1646318)
+    - packet: fix race condition in packet_set_ring
+
+ -- Brad Figg <brad.figg@canonical.com>  Thu, 01 Dec 2016 10:54:01 -0800
+
+linux (4.4.0-51.72) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1644611
+
+  * 4.4.0-1037-snapdragon #41: kernel panic on boot (LP: #1644596)
+    - Revert "dma-mapping: introduce the DMA_ATTR_NO_WARN attribute"
+    - Revert "powerpc: implement the DMA_ATTR_NO_WARN attribute"
+    - Revert "nvme: use the DMA_ATTR_NO_WARN attribute"
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Thu, 24 Nov 2016 17:56:21 +0000
+
+linux (4.4.0-50.71) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1644169
+
+  * xenial 4.4.0-49.70 kernel breaks LXD userspace (LP: #1644165)
+    - Revert "UBUNTU: SAUCE: (namespace) fuse: Allow user namespace mounts by
+      default"
+    - Revert "UBUNTU: SAUCE: (namespace) fs: Don't remove suid for CAP_FSETID for
+      userns root"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: fs: Don't remove suid for
+      CAP_FSETID in s_user_ns""
+    - Revert "UBUNTU: SAUCE: (namespace) fs: Allow superblock owner to change
+      ownership of inodes"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: fs: Allow superblock owner to
+      change ownership of inodes with unmappable ids""
+    - Revert "UBUNTU: SAUCE: (namespace) security/integrity: Harden against
+      malformed xattrs"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: ima/evm: Allow root in s_user_ns
+      to set xattrs""
+    - Revert "(namespace) dquot: For now explicitly don't support filesystems
+      outside of init_user_ns"
+    - Revert "(namespace) quota: Handle quota data stored in s_user_ns in
+      quota_setxquota"
+    - Revert "(namespace) quota: Ensure qids map to the filesystem"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: quota: Convert ids relative to
+      s_user_ns""
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: quota: Require that qids passed
+      to dqget() be valid and map into s_user_ns""
+    - Revert "(namespace) vfs: Don't create inodes with a uid or gid unknown to
+      the vfs"
+    - Revert "(namespace) vfs: Don't modify inodes with a uid or gid unknown to
+      the vfs"
+    - Revert "UBUNTU: SAUCE: (namespace) fuse: Translate ids in posix acl xattrs"
+    - Revert "UBUNTU: SAUCE: (namespace) posix_acl: Export
+      posix_acl_fix_xattr_userns() to modules"
+    - Revert "(namespace) vfs: Verify acls are valid within superblock's
+      s_user_ns."
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: fs: Update posix_acl support to
+      handle user namespace mounts""
+    - Revert "(namespace) fs: Refuse uid/gid changes which don't map into
+      s_user_ns"
+    - Revert "(namespace) Revert "UBUNTU: SAUCE: fs: Refuse uid/gid changes which
+      don't map into s_user_ns""
+    - Revert "(namespace) mnt: Move the FS_USERNS_MOUNT check into sget_userns"
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Wed, 23 Nov 2016 10:16:31 +0000
+
+linux (4.4.0-49.70) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1640921
+
+  * Infiniband driver (kernel module) needed for Azure (LP: #1641139)
+    - SAUCE: RDMA Infiniband for Windows Azure
+    - [Config] CONFIG_HYPERV_INFINIBAND_ND=m
+    - SAUCE: Makefile RDMA infiniband driver for Windows Azure
+    - [Config] Add hv_network_direct.ko to generic inclusion list
+    - SAUCE: RDMA Infiniband for Windows Azure is dependent on amd64
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Fri, 11 Nov 2016 15:36:20 +0000
+
+linux (4.4.0-48.69) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1640758
+
+  * lxc-attach to malicious container allows access to host (LP: #1639345)
+    - Revert "UBUNTU: SAUCE: (noup) ptrace: being capable wrt a process requires
+      mapped uids/gids"
+    - (upstream) mm: Add a user_ns owner to mm_struct and fix ptrace permission
+      checks
+
+  * take 'P' command from upstream xmon (LP: #1637978)
+    - powerpc/xmon: Add xmon command to dump process/task similar to ps(1)
+
+  * zfs: importing zpool with vdev on zvol hangs kernel (LP: #1636517)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu15
+
+  * I2C touchpad does not work on AMD platform (LP: #1612006)
+    - pinctrl/amd: Configure GPIO register using BIOS settings
+    - pinctrl/amd: switch to using a bool for level
+
+  * [LTCTest] vfio_pci not loaded on Ubuntu 16.10 by default (LP: #1636733)
+    - [Config] CONFIG_VFIO_PCI=y for ppc64el
+
+  * QEMU throws failure msg while booting guest with SRIOV VF (LP: #1630554)
+    - KVM: PPC: Always select KVM_VFIO, plus Makefile cleanup
+
+  * Allow fuse user namespace mounts by default in xenial (LP: #1634964)
+    - (namespace) mnt: Move the FS_USERNS_MOUNT check into sget_userns
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Refuse uid/gid changes which don't
+      map into s_user_ns"
+    - (namespace) fs: Refuse uid/gid changes which don't map into s_user_ns
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Update posix_acl support to handle
+      user namespace mounts"
+    - (namespace) vfs: Verify acls are valid within superblock's s_user_ns.
+    - SAUCE: (namespace) posix_acl: Export posix_acl_fix_xattr_userns() to modules
+    - SAUCE: (namespace) fuse: Translate ids in posix acl xattrs
+    - (namespace) vfs: Don't modify inodes with a uid or gid unknown to the vfs
+    - (namespace) vfs: Don't create inodes with a uid or gid unknown to the vfs
+    - (namespace) Revert "UBUNTU: SAUCE: quota: Require that qids passed to
+      dqget() be valid and map into s_user_ns"
+    - (namespace) Revert "UBUNTU: SAUCE: quota: Convert ids relative to s_user_ns"
+    - (namespace) quota: Ensure qids map to the filesystem
+    - (namespace) quota: Handle quota data stored in s_user_ns in quota_setxquota
+    - (namespace) dquot: For now explicitly don't support filesystems outside of
+      init_user_ns
+    - (namespace) Revert "UBUNTU: SAUCE: ima/evm: Allow root in s_user_ns to set
+      xattrs"
+    - SAUCE: (namespace) security/integrity: Harden against malformed xattrs
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Allow superblock owner to change
+      ownership of inodes with unmappable ids"
+    - SAUCE: (namespace) fs: Allow superblock owner to change ownership of inodes
+    - (namespace) Revert "UBUNTU: SAUCE: fs: Don't remove suid for CAP_FSETID in
+      s_user_ns"
+    - SAUCE: (namespace) fs: Don't remove suid for CAP_FSETID for userns root
+    - SAUCE: (namespace) fuse: Allow user namespace mounts by default
+
+  * [Feature] KBL - New device ID for Kabypoint(KbP) (LP: #1591618)
+    - SAUCE: mfd: lpss: Fix Intel Kaby Lake PCH-H properties
+
+  * hio: SSD data corruption under stress test (LP: #1638700)
+    - SAUCE: hio: set bi_error field to signal an I/O error on a BIO
+    - SAUCE: hio: splitting bio in the entry of .make_request_fn
+
+  * Module sha1-mb fails to load (LP: #1637165)
+    - crypto: sha-mb - Fix load failure
+    - crypto: mcryptd - Fix load failure
+
+  * please include mlx5_core modules in linux-image-generic package
+    (LP: #1635223)
+    - [Config] Include mlx5 in main package
+
+  * xgene i2c slimpro driver fails to load (LP: #1625232)
+    - mailbox: Add support for APM X-Gene platform mailbox driver
+    - mailbox/xgene-slimpro: Checking for IS_ERR instead of NULL
+    - mailbox: xgene-slimpro: Fix wrong test for devm_kzalloc
+    - [Config] Enabled XGENE_SLIMPRO_MBOX as a module
+
+  * [Dell][XPS]Touchscreen fails to function after resume from s3 by Lid
+    close/open (LP: #1632527)
+    - gpio/pinctrl: sunxi: stop poking around in private vars
+    - pinctrl: intel: Only restore pins that are used by the driver
+
+  * Xenial update to v4.4.30 stable release (LP: #1638272)
+    - Revert "x86/mm: Expand the exception table logic to allow new handling
+      options"
+    - Revert "fix minor infoleak in get_user_ex()"
+    - Linux 4.4.30
+
+  * Xenial update to v4.4.29 stable release (LP: #1638267)
+    - drm/prime: Pass the right module owner through to dma_buf_export()
+    - drm/amdgpu: fix IB alignment for UVD
+    - drm/amdgpu/dce10: disable hpd on local panels
+    - drm/amdgpu/dce8: disable hpd on local panels
+    - drm/amdgpu/dce11: disable hpd on local panels
+    - drm/amdgpu/dce11: add missing drm_mode_config_cleanup call
+    - drm/amdgpu: change vblank_time's calculation method to reduce computational
+      error.
+    - drm/radeon: narrow asic_init for virtualization
+    - drm/radeon/si/dpm: fix phase shedding setup
+    - drm/radeon: change vblank_time's calculation method to reduce computational
+      error.
+    - drm/vmwgfx: Limit the user-space command buffer size
+    - drm/i915/gen9: fix the WaWmMemoryReadLatency implementation
+    - Revert "drm/i915: Check live status before reading edid"
+    - drm/i915: Account for TSEG size when determining 865G stolen base
+    - drm/i915: Unalias obj->phys_handle and obj->userptr
+    - mm/hugetlb: fix memory offline with hugepage size > memory block size
+    - posix_acl: Clear SGID bit when setting file permissions
+    - ipip: Properly mark ipip GRO packets as encapsulated.
+    - powerpc/eeh: Null check uses of eeh_pe_bus_get
+    - perf stat: Fix interval output values
+    - genirq/generic_chip: Add irq_unmap callback
+    - uio: fix dmem_region_start computation
+    - ARM: clk-imx35: fix name for ckil clk
+    - spi: spi-fsl-dspi: Drop extra spi_master_put in device remove function
+    - mwifiex: correct aid value during tdls setup
+    - crypto: gcm - Fix IV buffer size in crypto_gcm_setkey
+    - crypto: arm/ghash-ce - add missing async import/export
+    - hwrng: omap - Only fail if pm_runtime_get_sync returns < 0
+    - ASoC: topology: Fix error return code in soc_tplg_dapm_widget_create()
+    - ASoC: dapm: Fix possible uninitialized variable in snd_soc_dapm_get_volsw()
+    - ASoC: dapm: Fix value setting for _ENUM_DOUBLE MUX's second channel
+    - ASoC: dapm: Fix kcontrol creation for output driver widget
+    - staging: r8188eu: Fix scheduling while atomic splat
+    - power: bq24257: Fix use of uninitialized pointer bq->charger
+    - dmaengine: ipu: remove bogus NO_IRQ reference
+    - x86/mm: Expand the exception table logic to allow new handling options
+    - s390/cio: fix accidental interrupt enabling during resume
+    - s390/con3270: fix use of uninitialised data
+    - s390/con3270: fix insufficient space padding
+    - clk: qoriq: fix a register offset error
+    - clk: divider: Fix clk_divider_round_rate() to use clk_readl()
+    - perf hists browser: Fix event group display
+    - perf symbols: Check symbol_conf.allow_aliases for kallsyms loading too
+    - perf symbols: Fixup symbol sizes before picking best ones
+    - mpt3sas: Don't spam logs if logging level is 0
+    - powerpc/nvram: Fix an incorrect partition merge
+    - ARM: pxa: pxa_cplds: fix interrupt handling
+    - Linux 4.4.29
+
+  * KVM: PPC: Book3S HV: Migrate pinned pages out of CMA (LP: #1632045)
+    - KVM: PPC: Book3S HV: Migrate pinned pages out of CMA
+
+  * Xenial update to v4.4.28 stable release (LP: #1637510)
+    - gpio: mpc8xxx: Correct irq handler function
+    - mei: me: add kaby point device ids
+    - regulator: tps65910: Work around silicon erratum SWCZ010
+    - clk: imx6: initialize GPU clocks
+    - PM / devfreq: event: remove duplicate devfreq_event_get_drvdata()
+    - rtlwifi: Fix missing country code for Great Britain
+    - mmc: block: don't use CMD23 with very old MMC cards
+    - mmc: sdhci: cast unsigned int to unsigned long long to avoid unexpeted error
+    - PCI: Mark Atheros AR9580 to avoid bus reset
+    - platform: don't return 0 from platform_get_irq[_byname]() on error
+    - cpufreq: intel_pstate: Fix unsafe HWP MSR access
+    - parisc: Increase KERNEL_INITIAL_SIZE for 32-bit SMP kernels
+    - parisc: Fix kernel memory layout regarding position of __gp
+    - parisc: Increase initial kernel mapping size
+    - pstore/ramoops: fixup driver removal
+    - pstore/core: drop cmpxchg based updates
+    - pstore/ram: Use memcpy_toio instead of memcpy
+    - pstore/ram: Use memcpy_fromio() to save old buffer
+    - perf intel-pt: Fix snapshot overlap detection decoder errors
+    - perf intel-pt: Fix estimated timestamps for cycle-accurate mode
+    - perf intel-pt: Fix MTC timestamp calculation for large MTC periods
+    - dm: mark request_queue dead before destroying the DM device
+    - dm: return correct error code in dm_resume()'s retry loop
+    - dm mpath: check if path's request_queue is dying in activate_path()
+    - dm crypt: fix crash on exit
+    - powerpc/vdso64: Use double word compare on pointers
+    - powerpc/powernv: Pass CPU-endian PE number to opal_pci_eeh_freeze_clear()
+    - powerpc/powernv: Use CPU-endian hub diag-data type in
+      pnv_eeh_get_and_dump_hub_diag()
+    - powerpc/powernv: Use CPU-endian PEST in pnv_pci_dump_p7ioc_diag_data()
+    - ubi: Deal with interrupted erasures in WL
+    - zfcp: fix fc_host port_type with NPIV
+    - zfcp: fix ELS/GS request&response length for hardware data router
+    - zfcp: close window with unblocked rport during rport gone
+    - zfcp: retain trace level for SCSI and HBA FSF response records
+    - zfcp: restore: Dont use 0 to indicate invalid LUN in rec trace
+    - zfcp: trace on request for open and close of WKA port
+    - zfcp: restore tracing of handle for port and LUN with HBA records
+    - zfcp: fix D_ID field with actual value on tracing SAN responses
+    - zfcp: fix payload trace length for SAN request&response
+    - zfcp: trace full payload of all SAN records (req,resp,iels)
+    - scsi: zfcp: spin_lock_irqsave() is not nestable
+    - fbdev/efifb: Fix 16 color palette entry calculation
+    - ovl: Fix info leak in ovl_lookup_temp()
+    - ovl: copy_up_xattr(): use strnlen
+    - mb86a20s: fix the locking logic
+    - mb86a20s: fix demod settings
+    - cx231xx: don't return error on success
+    - cx231xx: fix GPIOs for Pixelview SBTVD hybrid
+    - ALSA: hda - Fix a failure of micmute led when having multi adcs
+    - MIPS: Fix -mabi=64 build of vdso.lds
+    - MIPS: ptrace: Fix regs_return_value for kernel context
+    - lib: move strtobool() to kstrtobool()
+    - lib: update single-char callers of strtobool()
+    - lib: add "on"/"off" support to kstrtobool
+    - Input: i8042 - skip selftest on ASUS laptops
+    - Input: elantech - force needed quirks on Fujitsu H760
+    - Input: elantech - add Fujitsu Lifebook E556 to force crc_enabled
+    - sunrpc: fix write space race causing stalls
+    - NFSv4: Don't report revoked delegations as valid in nfs_have_delegation()
+    - NFSv4: nfs4_copy_delegation_stateid() must fail if the delegation is invalid
+    - NFSv4: Open state recovery must account for file permission changes
+    - NFSv4.2: Fix a reference leak in nfs42_proc_layoutstats_generic
+    - scsi: Fix use-after-free
+    - metag: Only define atomic_dec_if_positive conditionally
+    - mm: filemap: don't plant shadow entries without radix tree node
+    - ipc/sem.c: fix complex_count vs. simple op race
+    - arc: don't leak bits of kernel stack into coredump
+    - fs/super.c: fix race between freeze_super() and thaw_super()
+    - cifs: Limit the overall credit acquired
+    - fs/cifs: keep guid when assigning fid to fileinfo
+    - Clarify locking of cifs file and tcon structures and make more granular
+    - Display number of credits available
+    - Set previous session id correctly on SMB3 reconnect
+    - SMB3: GUIDs should be constructed as random but valid uuids
+    - Do not send SMB3 SET_INFO request if nothing is changing
+    - Cleanup missing frees on some ioctls
+    - blkcg: Unlock blkcg_pol_mutex only once when cpd == NULL
+    - x86/e820: Don't merge consecutive E820_PRAM ranges
+    - kvm: x86: memset whole irq_eoi
+    - irqchip/gicv3: Handle loop timeout proper
+    - sd: Fix rw_max for devices that report an optimal xfer size
+    - hpsa: correct skipping masked peripherals
+    - PKCS#7: Don't require SpcSpOpusInfo in Authenticode pkcs7 signatures
+    - bnx2x: Prevent false warning for lack of FC NPIV
+    - net/mlx4_core: Allow resetting VF admin mac to zero
+    - acpi, nfit: check for the correct event code in notifications
+    - mm: workingset: fix crash in shadow node shrinker caused by
+      replace_page_cache_page()
+    - mm: filemap: fix mapping->nrpages double accounting in fuse
+    - Using BUG_ON() as an assert() is _never_ acceptable
+    - s390/mm: fix gmap tlb flush issues
+    - irqchip/gic-v3-its: Fix entry size mask for GITS_BASER
+    - isofs: Do not return EACCES for unknown filesystems
+    - memstick: rtsx_usb_ms: Runtime resume the device when polling for cards
+    - memstick: rtsx_usb_ms: Manage runtime PM when accessing the device
+    - arm64: percpu: rewrite ll/sc loops in assembly
+    - arm64: kernel: Init MDCR_EL2 even in the absence of a PMU
+    - ceph: fix error handling in ceph_read_iter
+    - powerpc/mm: Prevent unlikely crash in copro_calculate_slb()
+    - mmc: core: Annotate cmd_hdr as __le32
+    - mmc: rtsx_usb_sdmmc: Avoid keeping the device runtime resumed when unused
+    - mmc: rtsx_usb_sdmmc: Handle runtime PM while changing the led
+    - ext4: do not advertise encryption support when disabled
+    - jbd2: fix incorrect unlock on j_list_lock
+    - ubifs: Fix xattr_names length in exit paths
+    - target: Re-add missing SCF_ACK_KREF assignment in v4.1.y
+    - target: Make EXTENDED_COPY 0xe4 failure return COPY TARGET DEVICE NOT
+      REACHABLE
+    - target: Don't override EXTENDED_COPY xcopy_pt_cmd SCSI status code
+    - Linux 4.4.28
+
+  * Xenial update to v4.4.27 stable release (LP: #1637501)
+    - serial: 8250_dw: Check the data->pclk when get apb_pclk
+    - btrfs: assign error values to the correct bio structs
+    - drivers: base: dma-mapping: page align the size when unmap_kernel_range
+    - fuse: listxattr: verify xattr list
+    - fuse: invalidate dir dentry after chmod
+    - fuse: fix killing s[ug]id in setattr
+    - i40e: avoid NULL pointer dereference and recursive errors on early PCI error
+    - brcmfmac: fix memory leak in brcmf_fill_bss_param
+    - ASoC: Intel: Atom: add a missing star in a memcpy call
+    - reiserfs: Unlock superblock before calling reiserfs_quota_on_mount()
+    - reiserfs: switch to generic_{get,set,remove}xattr()
+    - async_pq_val: fix DMA memory leak
+    - scsi: arcmsr: Simplify user_len checking
+    - ext4: enforce online defrag restriction for encrypted files
+    - ext4: reinforce check of i_dtime when clearing high fields of uid and gid
+    - ext4: fix memory leak in ext4_insert_range()
+    - ext4: allow DAX writeback for hole punch
+    - ext4: release bh in make_indexed_dir
+    - dlm: free workqueues after the connections
+    - vfs: move permission checking into notify_change() for utimes(NULL)
+    - cfq: fix starvation of asynchronous writes
+    - Linux 4.4.27
+
+  * Xenial update to v4.4.26 stable release (LP: #1637500)
+    - x86/build: Build compressed x86 kernels as PIE
+    - Linux 4.4.26
+
+  * ISST-LTE:pVM nvme 0000:a0:00.0: iommu_alloc failed on NVMe card
+    (LP: #1633128)
+    - dma-mapping: introduce the DMA_ATTR_NO_WARN attribute
+    - powerpc: implement the DMA_ATTR_NO_WARN attribute
+    - nvme: use the DMA_ATTR_NO_WARN attribute
+
+  * CVE-2016-8658
+    - brcmfmac: avoid potential stack overflow in brcmf_cfg80211_start_ap()
+
+  * Hotkey doesn't work on HP x360 (LP: #1620979)
+    - gpiolib: Make it possible to exclude GPIOs from IRQ domain
+    - pinctrl: cherryview: Do not mask all interrupts in probe
+    - pinctrl: cherryview: Do not add all southwest and north GPIOs to IRQ domain
+
+  * Bad page state in process genwqe_gunzip pfn:3c275 in the genwqe device
+    driver (LP: #1559194)
+    - SAUCE: (noup) Bad page state in process genwqe_gunzip pfn:3c275 in the
+      genwqe device driver
+
+  * CVE-2016-7425
+    - scsi: arcmsr: Buffer overflow in arcmsr_iop_message_xfer()
+
+  * Add ipvlan module to 16.04 kernel (LP: #1634705)
+    - [Config] Add ipvlan to the generic inclusion list
+
+  * kernel generates ACPI Exception: AE_NOT_FOUND, Evaluating _DOD incorrectly
+    (LP: #1634607)
+    - ACPI / video: skip evaluating _DOD when it does not exist
+
+  * BT still shows off after resume by wireless hotkey (LP: #1634380)
+    - Bluetooth: btusb: Fix atheros firmware download error
+
+  * ghash-clmulni-intel module fails to load (LP: #1633058)
+    - crypto: ghash-clmulni - Fix load failure
+    - crypto: cryptd - Assign statesize properly
+
+  * Xenial update to v4.4.25 stable release (LP: #1634153)
+    - timekeeping: Fix __ktime_get_fast_ns() regression
+    - ALSA: ali5451: Fix out-of-bound position reporting
+    - ALSA: usb-audio: Extend DragonFly dB scale quirk to cover other variants
+    - ALSA: usb-line6: use the same declaration as definition in header for MIDI
+      manufacturer ID
+    - mfd: rtsx_usb: Avoid setting ucr->current_sg.status
+    - mfd: atmel-hlcdc: Do not sleep in atomic context
+    - mfd: 88pm80x: Double shifting bug in suspend/resume
+    - mfd: wm8350-i2c: Make sure the i2c regmap functions are compiled
+    - KVM: PPC: Book3s PR: Allow access to unprivileged MMCR2 register
+    - KVM: MIPS: Drop other CPU ASIDs on guest MMU changes
+    - KVM: PPC: BookE: Fix a sanity check
+    - x86/boot: Fix kdump, cleanup aborted E820_PRAM max_pfn manipulation
+    - x86/irq: Prevent force migration of irqs which are not in the vector domain
+    - x86/dumpstack: Fix x86_32 kernel_stack_pointer() previous stack access
+    - ARM: dts: mvebu: armada-390: add missing compatibility string and bracket
+    - ARM: dts: MSM8064 remove flags from SPMI/MPP IRQs
+    - ARM: cpuidle: Fix error return code
+    - ima: use file_dentry()
+    - tpm: fix a race condition in tpm2_unseal_trusted()
+    - tpm_crb: fix crb_req_canceled behavior
+    - Linux 4.4.25
+
+  * backport fwts UEFI test driver to Xenial (LP: #1633506)
+    - efi: Add efi_test driver for exporting UEFI runtime service interfaces
+    - [Config] CONFIG_EFI_TEST=m
+
+  * Fix alps driver for multitouch function. (LP: #1633321)
+    - HID: alps: fix multitouch cursor issue
+
+  * xgene merlin crashes when running as iperf server (LP: #1632739)
+    - drivers: net: xgene: optimizing the code
+    - xgene: get_phy_device() doesn't return NULL anymore
+    - drivers: net: xgene: Get channel number from device binding
+    - drivers: net: xgene: constify xgene_cle_ops structure
+    - drivers: net: xgene: Fix error handling
+    - drivers: net: xgene: fix IPv4 forward crash
+    - drivers: net: xgene: fix sharing of irqs
+    - drivers: net: xgene: fix ununiform latency across queues
+    - drivers: net: xgene: fix statistics counters race condition
+    - drivers: net: xgene: fix register offset
+    - drivers: net: xgene: Separate set_speed from mac_init
+    - drivers: net: xgene: Fix module unload crash - hw resource cleanup
+    - drivers: net: xgene: Fix module unload crash - change sw sequence
+    - drivers: net: xgene: Fix module unload crash - clkrst sequence
+    - drivers: net: phy: xgene: Add MDIO driver
+    - drivers: net: xgene: Add backward compatibility
+    - drivers: net: xgene: Enable MDIO driver
+    - drivers: net: xgene: Use exported functions
+    - drivers: net: xgene: ethtool: Use phy_ethtool_gset and sset
+    - dtb: xgene: Add MDIO node
+    - MAINTAINERS: xgene: Add driver and documentation path
+    - [Config] Enable MDIO_XGENE as a modules
+
+  * Add support for KabeLake i219-LOM chips (LP: #1632578)
+    - e1000e: Initial support for KabeLake
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Thu, 10 Nov 2016 11:08:11 +0000
+
+linux (4.4.0-47.68) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1636941
+
+  * Add a driver for Amazon Elastic Network Adapters (ENA) (LP: #1635721)
+    - lib/bitmap.c: conversion routines to/from u32 array
+    - net: ethtool: add new ETHTOOL_xLINKSETTINGS API
+    - net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)
+    - [config] enable CONFIG_ENA_ETHERNET=m (Amazon ENA driver)
+
+  * unexpectedly large memory usage of mounted snaps (LP: #1636847)
+    - [Config] switch squashfs to single threaded decode
+
+ -- Kamal Mostafa <kamal@canonical.com>  Wed, 26 Oct 2016 10:47:55 -0700
+
+linux (4.4.0-46.67) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1635242
+
+  * proc_keys_show crash when reading /proc/keys (LP: #1634496)
+    - SAUCE: KEYS: ensure xbuf is large enough to fix buffer overflow in
+      proc_keys_show (LP: #1634496)
+
+  * [Trusty->Yakkety] powerpc/64: Fix incorrect return value from
+    __copy_tofrom_user (LP: #1632462)
+    - SAUCE: (no-up) powerpc/64: Fix incorrect return value from
+      __copy_tofrom_user
+
+  * Ubuntu 16.10: Oops panic in move_page_tables/page_remove_rmap after running
+    memory_stress_ng. (LP: #1628976)
+    - SAUCE: (no-up) powerpc/pseries: Fix stack corruption in htpe code
+
+  * Paths not failed properly when unmapping virtual FC ports in VIOS (using
+    ibmvfc) (LP: #1632116)
+    - scsi: ibmvfc: Fix I/O hang when port is not mapped
+
+  * PSL data cache should be flushed before resetting CAPI adapter
+    (LP: #1632049)
+    - cxl: Flush PSL cache before resetting the adapter
+
+  * thunder nic: avoid link delays due to RX_PACKET_DIS (LP: #1630038)
+    - net: thunderx: Don't set RX_PACKET_DIS while initializing
+
+  * Support snaps inside of lxd containers (LP: #1611078)
+    - Revert "UBUNTU: SAUCE: apparmor: fix sleep in critical section"
+    - SAUCE: (no-up) apparmor: sync of apparmor 3.6 (from Ubuntu 16.10)
+
+  * crypto/vmx/p8_ghash memory corruption (LP: #1630970)
+    - crypto: ghash-generic - move common definitions to a new header file
+    - crypto: vmx - Fix memory corruption caused by p8_ghash
+    - crypto: vmx - Ensure ghash-generic is enabled
+
+  * Xenial update to v4.4.24 stable release (LP: #1631468)
+    - cpuset: handle race between CPU hotplug and cpuset_hotplug_work
+    - mtd: nand: davinci: Reinitialize the HW ECC engine in 4bit hwctl
+    - mm,ksm: fix endless looping in allocating memory when ksm enable
+    - can: dev: fix deadlock reported after bus-off
+    - x86/init: Fix cr4_init_shadow() on CR4-less machines
+    - x86/boot: Initialize FPU and X86_FEATURE_ALWAYS even if we don't have CPUID
+    - drm/nouveau/fifo/nv04: avoid ramht race against cookie insertion
+    - drm/radeon/si/dpm: add workaround for for Jet parts
+    - ARM: 8616/1: dt: Respect property size when parsing CPUs
+    - ARM: 8617/1: dma: fix dma_max_pfn()
+    - usb: musb: Fix DMA desired mode for Mentor DMA engine
+    - usb: musb: fix DMA for host mode
+    - iwlwifi: mvm: fix a few firmware capability checks
+    - perf/core: Fix pmu::filter_match for SW-led groups
+    - i40e: avoid null pointer dereference
+    - pinctrl: uniphier: fix .pin_dbg_show() callback
+    - pinctrl: Flag strict is a field in struct pinmux_ops
+    - drivers/perf: arm_pmu: Fix leak in error path
+    - mmc: pxamci: fix potential oops
+    - tools/vm/slabinfo: fix an unintentional printf
+    - ipvs: fix bind to link-local mcast IPv6 address in backup
+    - nvmem: Declare nvmem_cell_read() consistently
+    - hwmon: (adt7411) set bit 3 in CFG1 register
+    - spi: sh-msiof: Avoid invalid clock generator parameters
+    - iwlwifi: pcie: fix access to scratch buffer
+    - iwlwifi: mvm: don't use ret when not initialised
+    - ceph: fix race during filling readdir cache
+    - usb: gadget: fsl_qe_udc: signedness bug in qe_get_frame()
+    - gpio: sa1100: fix irq probing for ucb1x00
+    - irqchip/gicv3: Silence noisy DEBUG_PER_CPU_MAPS warning
+    - ARM: 8618/1: decompressor: reset ttbcr fields to use TTBR0 on ARMv7
+    - arm64: debug: avoid resetting stepping state machine when TIF_SINGLESTEP
+    - MIPS: uprobes: remove incorrect set_orig_insn
+    - MIPS: fix uretprobe implementation
+    - MIPS: Malta: Fix IOCU disable switch read for MIPS64
+    - MIPS: uprobes: fix use of uninitialised variable
+    - printk: fix parsing of "brl=" option
+    - tpm: fix byte-order for the value read by tpm2_get_tpm_pt
+    - regulator: qcom_spmi: Add support for S4 supply on pm8941
+    - regulator: qcom_spmi: Add support for get_mode/set_mode on switches
+    - regulator: qcom_spmi: Update mvs1/mvs2 switches on pm8941
+    - regulator: qcom_smd: Fix voltage ranges for pm8x41
+    - ARM: sun5i: Fix typo in trip point temperature
+    - ARM: sa1100: register clocks early
+    - ARM: sa1100: fix 3.6864MHz clock
+    - ARM: sa1100: clear reset status prior to reboot
+    - ARM: shmobile: fix regulator quirk for Gen2
+    - ARM: sa1111: fix pcmcia suspend/resume
+    - hwrng: omap - Fix assumption that runtime_get_sync will always succeed
+    - blk-mq: actually hook up defer list when running requests
+    - pstore: drop file opened reference count
+    - tile: Define AT_VECTOR_SIZE_ARCH for ARCH_DLINFO
+    - iwlmvm: mvm: set correct state in smart-fifo configuration
+    - NFC: fdp: Detect errors from fdp_nci_create_conn()
+    - em28xx-i2c: rt_mutex_trylock() returns zero on failure
+    - gspca: avoid unused variable warnings
+    - ath9k: Fix programming of minCCA power threshold
+    - avr32: off by one in at32_init_pio()
+    - fnic: pci_dma_mapping_error() doesn't return an error code
+    - dmaengine: at_xdmac: fix debug string
+    - svc: Avoid garbage replies when pc_func() returns rpc_drop_reply
+    - NFS: Don't drop CB requests with invalid principals
+    - pNFS/files: Fix layoutcommit after a commit to DS
+    - pNFS/flexfiles: Fix layoutcommit after a commit to DS
+    - ASoC: Intel: Skylake: Fix error return code in skl_probe()
+    - brcmfmac: Fix glob_skb leak in brcmf_sdiod_recv_chain
+    - brcmsmac: Free packet if dma_mapping_error() fails in dma_rxfill
+    - brcmsmac: Initialize power in brcms_c_stf_ss_algo_channel_get()
+    - powerpc/prom: Fix sub-processor option passed to ibm, client-architecture-
+      support
+    - sysctl: handle error writing UINT_MAX to u32 fields
+    - ASoC: omap-mcpdm: Fix irq resource handling
+    - kernel/fork: fix CLONE_CHILD_CLEARTID regression in nscd
+    - dmaengine: at_xdmac: fix to pass correct device identity to free_irq()
+    - KVM: nVMX: postpone VMCS changes on MSR_IA32_APICBASE write
+    - IB/ipoib: Fix memory corruption in ipoib cm mode connect flow
+    - IB/core: Fix use after free in send_leave function
+    - IB/ipoib: Don't allow MC joins during light MC flush
+    - IB/mlx4: Fix incorrect MC join state bit-masking on SR-IOV
+    - IB/mlx4: Fix code indentation in QP1 MAD flow
+    - IB/mlx4: Use correct subnet-prefix in QP1 mads under SR-IOV
+    - batman-adv: remove unused callback from batadv_algo_ops struct
+    - aio: mark AIO pseudo-fs noexec
+    - clk: xgene: Add missing parenthesis when clearing divider value
+    - dm log writes: fix bug with too large bios
+    - USB: serial: cp210x: fix hardware flow-control disable
+    - usb: misc: legousbtower: Fix NULL pointer deference
+    - Staging: fbtft: Fix bug in fbtft-core
+    - USB: serial: cp210x: Add ID for a Juniper console
+    - Revert "usbtmc: convert to devm_kzalloc"
+    - ALSA: hda - Adding one more ALC255 pin definition for headset problem
+    - ACPICA: acpi_get_sleep_type_data: Reduce warnings
+    - ALSA: hda - Fix headset mic detection problem for several Dell laptops
+    - ALSA: hda - Add the top speaker pin config for HP Spectre x360
+    - Linux 4.4.24
+
+  * sha1-powerpc returning wrong results (LP: #1629977)
+    - crypto: sha1-powerpc - little-endian support
+
+  *  Dell Precision Trackpoint not working after suspend (LP: #1630857)
+    - HID: alps: fix stick device not working after resume
+
+  * OOPS on beaglebone on boot of 4.4.0-36-generic under snappy ubuntu core
+    xenial (LP: #1625177)
+    - net: ethernet: ti: cpdma: fix lockup in cpdma_ctlr_destroy()
+    - drivers: net: cpsw: fix wrong regs access in cpsw_remove
+    - drivers: net: cpsw: use of_platform_depopulate()
+    - ARM: OMAP2+: omap_device: fix crash on omap_device removal
+    - ARM: OMAP2+: Fix omap_device for module reload on PM runtime forbid
+    - ARM: OMAP2+: Fix typo in omap_device.c
+    - drivers: net: cpsw: fix suspend when all ethX devices are down
+    - drivers: net: cpsw: fix wrong regs access in cpsw_ndo_open
+    - drivers: net: cpsw: check return code from pm runtime calls
+    - drivers: net: cpsw: remove pm runtime calls from suspend callbacks
+    - drivers: net: cpsw: ethtool: fix accessing to suspended device
+    - drivers: net: cpsw: ndev: fix accessing to suspended device
+    - drivers: net: cpsw: fix kmemleak false-positive reports for sk buffers
+
+  * Autofs parameter substitution broken in kernel 4.4.0-38 and 4.4.0-40
+    (LP: #1629204)
+    - SAUCE: (namespace) autofs4: Use real_cred for requestor's ids
+
+  * Xenial update to v4.4.23 stable release (LP: #1629386)
+    - include/linux/kernel.h: change abs() macro so it uses consistent return type
+    - Fix build warning in kernel/cpuset.c
+    - reiserfs: fix "new_insert_key may be used uninitialized ..."
+    - ipv4: panic in leaf_walk_rcu due to stale node pointer
+    - ipv6: release dst in ping_v6_sendmsg
+    - tcp: cwnd does not increase in TCP YeAH
+    - tcp: properly scale window in tcp_v[46]_reqsk_send_ack()
+    - crypto: arm64/aes-ctr - fix NULL dereference in tail processing
+    - crypto: arm/aes-ctr - fix NULL dereference in tail processing
+    - crypto: skcipher - Fix blkcipher walk OOM crash
+    - crypto: echainiv - Replace chaining with multiplication
+    - ocfs2/dlm: fix race between convert and migration
+    - ocfs2: fix start offset to ocfs2_zero_range_for_truncate()
+    - kbuild: Do not run modules_install and install in paralel
+    - Makefile: revert "Makefile: Document ability to make file.lst and file.S"
+      partially
+    - tools: Support relative directory path for 'O='
+    - kbuild: forbid kernel directory to contain spaces and colons
+    - Kbuild: disable 'maybe-uninitialized' warning for
+      CONFIG_PROFILE_ALL_BRANCHES
+    - gcov: disable -Wmaybe-uninitialized warning
+    - Disable "maybe-uninitialized" warning globally
+    - Disable "frame-address" warning
+    - Makefile: Mute warning for __builtin_return_address(>0) for tracing only
+    - net: caif: fix misleading indentation
+    - Add braces to avoid "ambiguous ‘else’" compiler warnings
+    - am437x-vfpe: fix typo in vpfe_get_app_input_index
+    - ath9k: fix misleading indentation
+    - iwlegacy: avoid warning about missing braces
+    - Staging: iio: adc: fix indent on break statement
+    - nouveau: fix nv40_perfctr_next() cleanup regression
+    - bonding: Fix bonding crash
+    - Revert "af_unix: Fix splice-bind deadlock"
+    - af_unix: split 'u->readlock' into two: 'iolock' and 'bindlock'
+    - vti: flush x-netns xfrm cache when vti interface is removed
+    - net/irda: handle iriap_register_lsap() allocation failure
+    - tipc: fix NULL pointer dereference in shutdown()
+    - net/mlx5: Added missing check of msg length in verifying its signature
+    - net: dsa: bcm_sf2: Fix race condition while unmasking interrupts
+    - Revert "phy: IRQ cannot be shared"
+    - net: smc91x: fix SMC accesses
+    - bridge: re-introduce 'fix parsing of MLDv2 reports'
+    - autofs races
+    - autofs: use dentry flags to block walks during expire
+    - xfs: prevent dropping ioend completions during buftarg wait
+    - fsnotify: add a way to stop queueing events on group shutdown
+    - fanotify: fix list corruption in fanotify_get_response()
+    - fix fault_in_multipages_...() on architectures with no-op access_ok()
+    - mtd: maps: sa1100-flash: potential NULL dereference
+    - mtd: pmcmsp-flash: Allocating too much in init_msp_flash()
+    - power: reset: hisi-reboot: Unmap region obtained by of_iomap
+    - fix memory leaks in tracing_buffers_splice_read()
+    - tracing: Move mutex to protect against resetting of seq data
+    - mm: delete unnecessary and unsafe init_tlb_ubc()
+    - can: flexcan: fix resume function
+    - nl80211: validate number of probe response CSA counters
+    - btrfs: ensure that file descriptor used with subvol ioctls is a dir
+    - i2c-eg20t: fix race between i2c init and interrupt enable
+    - i2c: qup: skip qup_i2c_suspend if the device is already runtime suspended
+    - MIPS: Fix pre-r6 emulation FPU initialisation
+    - MIPS: SMP: Fix possibility of deadlock when bringing CPUs online
+    - MIPS: vDSO: Fix Malta EVA mapping to vDSO page structs
+    - MIPS: Remove compact branch policy Kconfig entries
+    - MIPS: Avoid a BUG warning during prctl(PR_SET_FP_MODE, ...)
+    - MIPS: Add a missing ".set pop" in an early commit
+    - MIPS: paravirt: Fix undefined reference to smp_bootstrap
+    - PM / hibernate: Restore processor state before using per-CPU variables
+    - PM / hibernate: Fix rtree_next_node() to avoid walking off list ends
+    - power_supply: tps65217-charger: fix missing platform_set_drvdata()
+    - power: supply: max17042_battery: fix model download bug.
+    - qxl: check for kmap failures
+    - hostfs: Freeing an ERR_PTR in hostfs_fill_sb_common()
+    - Linux 4.4.23
+
+  * Xenial update to v4.4.22 stable release (LP: #1627730)
+    - ext4: use __GFP_NOFAIL in ext4_free_blocks()
+    - fscrypto: add authorization check for setting encryption policy
+    - clocksource/drivers/sun4i: Clear interrupts after stopping timer in probe
+      function
+    - MIPS: KVM: Check for pfn noslot case
+    - fscrypto: require write access to mount to set encryption policy
+    - lightnvm: put bio before return
+    - powerpc/tm: do not use r13 for tabort_syscall
+    - powerpc/mm: Don't alias user region to other regions below PAGE_OFFSET
+    - kernfs: don't depend on d_find_any_alias() when generating notifications
+    - pNFS: The client must not do I/O to the DS if it's lease has expired
+    - NFSv4.x: Fix a refcount leak in nfs_callback_up_net
+    - nfsd: Close race between nfsd4_release_lockowner and nfsd4_lock
+    - pNFS: Ensure LAYOUTGET and LAYOUTRETURN are properly serialised
+    - NFSv4.1: Fix the CREATE_SESSION slot number accounting
+    - kexec: fix double-free when failing to relocate the purgatory
+    - mm: introduce get_task_exe_file
+    - audit: fix exe_file access in audit_exe_compare
+    - dm flakey: fix reads to be issued if drop_writes configured
+    - IB/uverbs: Fix race between uverbs_close and remove_one
+    - ARC: mm: fix build breakage with STRICT_MM_TYPECHECKS
+    - x86/paravirt: Do not trace _paravirt_ident_*() functions
+    - x86/AMD: Apply erratum 665 on machines without a BIOS fix
+    - kvm-arm: Unmap shadow pagetables properly
+    - iio: accel: kxsd9: Fix raw read return
+    - iio: proximity: as3935: set up buffer timestamps for non-zero values
+    - iio: adc: rockchip_saradc: reset saradc controller before programming it
+    - iio: adc: ti_am335x_adc: Protect FIFO1 from concurrent access
+    - iio: adc: ti_am335x_adc: Increase timeout value waiting for ADC sample
+    - iio: ad799x: Fix buffered capture for ad7991/ad7995/ad7999
+    - iio: adc: at91: unbreak channel adc channel 3
+    - iio: accel: bmc150: reset chip at init time
+    - iio: fix pressure data output unit in hid-sensor-attributes
+    - iio: accel: kxsd9: Fix scaling bug
+    - iio:core: fix IIO_VAL_FRACTIONAL sign handling
+    - iio: ensure ret is initialized to zero before entering do loop
+    - serial: 8250_mid: fix divide error bug if baud rate is 0
+    - serial: 8250: added acces i/o products quad and octal serial cards
+    - USB: serial: simple: add support for another Infineon flashloader
+    - usb: renesas_usbhs: fix clearing the {BRDY,BEMP}STS condition
+    - usb: chipidea: udc: fix NULL ptr dereference in isr_setup_status_phase
+    - ARM: dts: STiH410: Handle interconnect clock required by EHCI/OHCI (USB)
+    - USB: change bInterval default to 10 ms
+    - net: thunderx: Fix OOPs with ethtool --register-dump
+    - cpuset: make sure new tasks conform to the current config of the cpuset
+    - ARM: AM43XX: hwmod: Fix RSTST register offset for pruss
+    - ARM: imx6: add missing BM_CLPCR_BYP_MMDC_CH0_LPM_HS setting for imx6ul
+    - ARM: imx6: add missing BM_CLPCR_BYPASS_PMIC_READY setting for imx6sx
+    - ARM: kirkwood: ib62x0: fix size of u-boot environment partition
+    - ARM: OMAP3: hwmod data: Add sysc information for DSI
+    - ARM: dts: imx6qdl: Fix SPDIF regression
+    - ARM: dts: overo: fix gpmc nand cs0 range
+    - ARM: dts: overo: fix gpmc nand on boards with ethernet
+    - ARM: dts: STiH407-family: Provide interconnect clock for consumption in ST
+      SDHCI
+    - bus: arm-ccn: Fix PMU handling of MN
+    - bus: arm-ccn: Do not attempt to configure XPs for cycle counter
+    - bus: arm-ccn: Fix XP watchpoint settings bitmask
+    - dm log writes: fix check of kthread_run() return value
+    - dm log writes: move IO accounting earlier to fix error path
+    - dm crypt: fix error with too large bios
+    - pinctrl: pistachio: fix mfio pll_lock pinmux
+    - pinctrl: sunxi: fix uart1 CTS/RTS pins at PG on A23/A33
+    - arm64: spinlocks: implement smp_mb__before_spinlock() as smp_mb()
+    - crypto: cryptd - initialize child shash_desc on import
+    - Btrfs: remove root_log_ctx from ctx list before btrfs_sync_log returns
+    - fuse: direct-io: don't dirty ITER_BVEC pages
+    - xhci: fix null pointer dereference in stop command timeout function
+    - md-cluster: make md-cluster also can work when compiled into kernel
+    - ath9k: fix using sta->drv_priv before initializing it
+    - Revert "wext: Fix 32 bit iwpriv compatibility issue with 64 bit Kernel"
+    - sched/core: Fix a race between try_to_wake_up() and a woken up task
+    - ipv6: addrconf: fix dev refcont leak when DAD failed
+    - gma500: remove annoying deprecation warning
+    - mpssd: fix buffer overflow warning
+    - drm/i915: Avoid pointer arithmetic in calculating plane surface offset
+    - mmc: dw_mmc: use resource_size_t to store physical address
+    - pinctrl: at91-pio4: use %pr format string for resource
+    - soc: qcom/spm: shut up uninitialized variable warning
+    - kconfig: tinyconfig: provide whole choice blocks to avoid warnings
+    - net: simplify napi_synchronize() to avoid warnings
+    - drm: atmel-hlcdc: Fix vertical scaling
+    - drm: Only use compat ioctl for addfb2 on X86/IA64
+    - genirq: Provide irq_gc_{lock_irqsave,unlock_irqrestore}() helpers
+    - irqchip/atmel-aic: Fix potential deadlock in ->xlate()
+    - fix iov_iter_fault_in_readable()
+    - microblaze: fix __get_user()
+    - avr32: fix copy_from_user()
+    - microblaze: fix copy_from_user()
+    - fix minor infoleak in get_user_ex()
+    - mn10300: failing __get_user() and get_user() should zero
+    - m32r: fix __get_user()
+    - sh64: failing __get_user() should zero
+    - nios2: fix __get_user()
+    - score: fix __get_user/get_user
+    - s390: get_user() should zero on failure
+    - ARC: uaccess: get_user to zero out dest in cause of fault
+    - asm-generic: make get_user() clear the destination on errors
+    - frv: fix clear_user()
+    - cris: buggered copy_from_user/copy_to_user/clear_user
+    - blackfin: fix copy_from_user()
+    - score: fix copy_from_user() and friends
+    - sh: fix copy_from_user()
+    - hexagon: fix strncpy_from_user() error return
+    - mips: copy_from_user() must zero the destination on access_ok() failure
+    - asm-generic: make copy_from_user() zero the destination properly
+    - alpha: fix copy_from_user()
+    - metag: copy_from_user() should zero the destination on access_ok() failure
+    - parisc: fix copy_from_user()
+    - openrisc: fix copy_from_user()
+    - nios2: copy_from_user() should zero the tail of destination
+    - mn10300: copy_from_user() should zero on access_ok() failure...
+    - sparc32: fix copy_from_user()
+    - ppc32: fix copy_from_user()
+    - genirq/msi: Fix broken debug output
+    - ia64: copy_from_user() should zero the destination on access_ok() failure
+    - avr32: fix 'undefined reference to `___copy_from_user'
+    - openrisc: fix the fix of copy_from_user()
+    - Linux 4.4.22
+
+  * AES-XTS poor performance in Ubuntu 16.04 (LP: #1613295)
+    - crypto: vmx - fix null dereference in p8_aes_xts_crypt
+
+  * i40e/setting some ethtool features and remove module right after (modprobe
+    -r) lead to crash in systems with more than 127 CPUs (LP: #1626782)
+    - i40e: Fix errors resulted while turning off TSO
+
+  * STC860:alpine-pdq:alpdq5p03: kernel panic when adding vnic (LP: #1626222)
+    - ibmvnic: fix to use list_for_each_safe() when delete items
+
+  * Stratton: ISST-LTE:UbuntuKVM: Failed to hotplug virtual devices to guest
+    running Ubuntu 16.04.1 on UbuntuKVM16.04.1 #179 (LP: #1625986)
+    - PCI: rpaphp: Fix slot registration for multiple slots under a PHB
+
+  * nvme: Missing patch in Ubuntu-4.4.0-41.61 (LP: #1628520)
+    - nvme: Call pci_disable_device on the error path.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 20 Oct 2016 08:09:34 -0500
+
+linux (4.4.0-45.66) xenial; urgency=low
+
+  * CVE-2016-5195
+    - SAUCE: mm: remove gup_flags FOLL_WRITE games from __get_user_pages()
+
+  * srcname from mount rule corrupted under load (LP: #1634753)
+    - SAUCE: apparmor: fix sleep in critical section
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 19 Oct 2016 11:24:20 +0200
+
+linux (4.4.0-43.63) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1632375
+
+  * kswapd0 100% CPU usage (LP: #1518457)
+    - SAUCE: (no-up) If zone is so small that watermarks are the same, stop zone
+      balance.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 11 Oct 2016 07:54:56 -0500
+
+linux (4.4.0-42.62) xenial; urgency=low
+
+  * Fix GRO recursion overflow for tunneling protocols (LP: #1631287)
+    - tunnels: Don't apply GRO to multiple layers of encapsulation.
+    - gro: Allow tunnel stacking in the case of FOU/GUE
+
+  * CVE-2016-7039
+    - SAUCE: net: add recursion limit to GRO
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 07 Oct 2016 12:03:55 -0500
+
+linux (4.4.0-41.61) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1628204
+
+  * nvme drive probe failure (LP: #1626894)
+    - (fix) NVMe: Don't unmap controller registers on reset
+
+ -- Kamal Mostafa <kamal@canonical.com>  Tue, 27 Sep 2016 09:40:42 -0700
+
+linux (4.4.0-40.60) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1627074
+
+  * Permission denied in CIFS with kernel 4.4.0-38 (LP: #1626112)
+    - Fix memory leaks in cifs_do_mount()
+    - Compare prepaths when comparing superblocks
+    - SAUCE: Fix regression which breaks DFS mounting
+
+  * Backlight does not change when adjust it higher than 50% after S3
+    (LP: #1625932)
+    - SAUCE: i915_bpo: drm/i915/backlight: setup and cache pwm alternate
+      increment value
+    - SAUCE: i915_bpo: drm/i915/backlight: setup backlight pwm alternate
+      increment on backlight enable
+
+ -- Kamal Mostafa <kamal@canonical.com>  Fri, 23 Sep 2016 08:53:31 -0700
+
+linux (4.4.0-39.59) xenial; urgency=low
+
+  [ Joseph Salisbury ]
+
+  * Release Tracking Bug
+    - LP: #1625303
+
+  * thunder: chip errata w/ multiple CQEs for a TSO packet (LP: #1624569)
+    - net: thunderx: Fix for issues with multiple CQEs posted for a TSO packet
+
+  * thunder: faulty TSO padding (LP: #1623627)
+    - net: thunderx: Fix for HW issue while padding TSO packet
+
+  * CVE-2016-6828
+    - tcp: fix use after free in tcp_xmit_retransmit_queue()
+
+  * Sennheiser Officerunner - cannot get freq at ep 0x83 (LP: #1622763)
+    - SAUCE: (no-up) ALSA: usb-audio: Add quirk for sennheiser officerunner
+
+  * Backport E3 Skylake Support in ie31200_edac to Xenial (LP: #1619766)
+    - EDAC, ie31200_edac: Add Skylake support
+
+  * Ubuntu 16.04 - Full EEH Recovery Support for NVMe devices (LP: #1602724)
+    - SAUCE: nvme: Don't suspend admin queue that wasn't created
+
+  * ISST-LTE:pNV: system ben is hung during ST (nvme) (LP: #1620317)
+    - blk-mq: Allow timeouts to run while queue is freezing
+    - blk-mq: improve warning for running a queue on the wrong CPU
+    - blk-mq: don't overwrite rq->mq_ctx
+
+  * lsattr 32bit does not work on 64bit kernel (Inappropriate ioctl error)
+    (LP: #1619918)
+    - btrfs: bugfix: handle FS_IOC32_{GETFLAGS, SETFLAGS, GETVERSION} in
+      btrfs_ioctl
+
+  * radeon: monitor connected to onboard VGA doesn't work with Xenial
+    (LP: #1600092)
+    - drm/radeon/dp: add back special handling for NUTMEG
+
+  * initramfs includes qle driver, but not firmware (LP: #1623187)
+    - qed: add MODULE_FIRMWARE()
+
+  * [Hyper-V] Rebase Hyper-V to 4.7.2 (stable) (LP: #1616677)
+    - hv_netvsc: Implement support for VF drivers on Hyper-V
+    - hv_netvsc: Fix the list processing for network change event
+    - Drivers: hv: vmbus: Introduce functions for estimating room in the ring
+      buffer
+    - Drivers: hv: vmbus: Use READ_ONCE() to read variables that are volatile
+    - Drivers: hv: vmbus: Export the vmbus_set_event() API
+    - lcoking/barriers, arch: Use smp barriers in smp_store_release()
+    - asm-generic: guard smp_store_release/load_acquire
+    - x86: reuse asm-generic/barrier.h
+    - asm-generic: add __smp_xxx wrappers
+    - x86: define __smp_xxx
+    - asm-generic: implement virt_xxx memory barriers
+    - Drivers: hv: vmbus: Move some ring buffer functions to hyperv.h
+    - Drivers: hv: vmbus: Implement APIs to support "in place" consumption of
+      vmbus packets
+    - drivers:hv: Lock access to hyperv_mmio resource tree
+    - drivers:hv: Make a function to free mmio regions through vmbus
+    - drivers:hv: Track allocations of children of hv_vmbus in private resource
+      tree
+    - drivers:hv: Separate out frame buffer logic when picking MMIO range
+    - Drivers: hv: vmbus: handle various crash scenarios
+    - Drivers: hv: balloon: don't crash when memory is added in non-sorted order
+    - Drivers: hv: balloon: reset host_specified_ha_region
+    - tools: hv: lsvmbus: add pci pass-through UUID
+    - hv_netvsc: move start_remove flag to net_device_context
+    - hv_netvsc: use start_remove flag to protect netvsc_link_change()
+    - hv_netvsc: untangle the pointer mess
+    - hv_netvsc: get rid of struct net_device pointer in struct netvsc_device
+    - hv_netvsc: synchronize netvsc_change_mtu()/netvsc_set_channels() with
+      netvsc_remove()
+    - hv_netvsc: set nvdev link after populating chn_table
+    - hv_netvsc: Fix VF register on vlan devices
+    - hv_netvsc: remove redundant assignment in netvsc_recv_callback()
+    - hv_netvsc: introduce {net, hv}_device_to_netvsc_device() helpers
+    - hv_netvsc: pass struct netvsc_device to rndis_filter_{open, close}()
+    - hv_netvsc: pass struct net_device to rndis_filter_set_device_mac()
+    - hv_netvsc: pass struct net_device to rndis_filter_set_offload_params()
+    - netvsc: get rid of completion timeouts
+    - PCI: hv: Don't leak buffer in hv_pci_onchannelcallback()
+    - PCI: hv: Handle all pending messages in hv_pci_onchannelcallback()
+    - netvsc: Use the new in-place consumption APIs in the rx path
+    - x86/kernel: Audit and remove any unnecessary uses of module.h
+    - PCI: hv: Fix interrupt cleanup path
+    - hv_netvsc: Fix VF register on bonding devices
+    - hv_netvsc: don't lose VF information
+    - hv_netvsc: avoid deadlocks between rtnl lock and vf_use_cnt wait
+    - hv_netvsc: reset vf_inject on VF removal
+    - hv_netvsc: protect module refcount by checking net_device_ctx->vf_netdev
+    - hv_netvsc: fix bonding devices check in netvsc_netdev_event()
+    - Drivers: hv: vmbus: Use the new virt_xx barrier code
+    - ixgbevf: call ndo_stop() instead of dev_close() when running offline
+      selftest
+    - ixgbevf: fix error code path when setting MAC address
+    - ixgbevf: use bit operations for setting and checking resets
+    - ixgbevf: Add support for generic Tx checksums
+    - ixgbe/ixgbevf: Add support for bulk free in Tx cleanup & cleanup boolean
+      logic
+    - ixgbevf: refactor ethtool stats handling
+    - ixgbevf: add support for per-queue ethtool stats
+    - ixgbevf: make use of BIT() macro to avoid shift of signed values
+    - ixgbevf: Move API negotiation function into mac_ops
+    - ixgbevf: Add the device ID's presented while running on Hyper-V
+    - ixgbevf: Support Windows hosts (Hyper-V)
+    - ixgbevf: Change the relaxed order settings in VF driver for sparc
+    - ixgbevf: Use mac_ops instead of trying to identify NIC type
+
+  * New device ID for Kabypoint (LP: #1622469)
+    - mfd: lpss: Add Intel Kaby Lake PCH-H PCI IDs
+    - SAUCE: i2c: i801: Add support for Kaby Lake PCH-H
+
+  * Xenial update to v4.4.21 stable release (LP: #1624037)
+    - Revert "i40e: fix: do not sleep in netdev_ops"
+    - fs: Check for invalid i_uid in may_follow_link()
+    - netfilter: x_tables: check for size overflow
+    - ext4: validate that metadata blocks do not overlap superblock
+    - ext4: fix xattr shifting when expanding inodes
+    - ext4: fix xattr shifting when expanding inodes part 2
+    - ext4: properly align shifted xattrs when expanding inodes
+    - ext4: avoid deadlock when expanding inode size
+    - ext4: avoid modifying checksum fields directly during checksum verification
+    - block: Fix race triggered by blk_set_queue_dying()
+    - block: make sure a big bio is split into at most 256 bvecs
+    - cgroup: reduce read locked section of cgroup_threadgroup_rwsem during fork
+    - s390/sclp_ctl: fix potential information leak with /dev/sclp
+    - drm/radeon: fix radeon_move_blit on 32bit systems
+    - drm: Reject page_flip for !DRIVER_MODESET
+    - drm/msm: fix use of copy_from_user() while holding spinlock
+    - ASoC: atmel_ssc_dai: Don't unconditionally reset SSC on stream startup
+    - xfs: fix superblock inprogress check
+    - timekeeping: Cap array access in timekeeping_debug
+    - timekeeping: Avoid taking lock in NMI path with CONFIG_DEBUG_TIMEKEEPING
+    - lustre: remove unused declaration
+    - wrappers for ->i_mutex access
+    - ovl: don't copy up opaqueness
+    - ovl: remove posix_acl_default from workdir
+    - ovl: listxattr: use strnlen()
+    - ovl: fix workdir creation
+    - ubifs: Fix assertion in layout_in_gaps()
+    - bcache: RESERVE_PRIO is too small by one when prio_buckets() is a power of
+      two.
+    - vhost/scsi: fix reuse of &vq->iov[out] in response
+    - x86/apic: Do not init irq remapping if ioapic is disabled
+    - uprobes: Fix the memcg accounting
+    - crypto: caam - fix IV loading for authenc (giv)decryption
+    - ALSA: usb-audio: Add sample rate inquiry quirk for B850V3 CP2114
+    - ALSA: firewire-tascam: accessing to user space outside spinlock
+    - ALSA: fireworks: accessing to user space outside spinlock
+    - ALSA: rawmidi: Fix possible deadlock with virmidi registration
+    - ALSA: hda - Add headset mic quirk for Dell Inspiron 5468
+    - ALSA: hda - Enable subwoofer on Dell Inspiron 7559
+    - ALSA: timer: fix NULL pointer dereference in read()/ioctl() race
+    - ALSA: timer: fix division by zero after SNDRV_TIMER_IOCTL_CONTINUE
+    - ALSA: timer: fix NULL pointer dereference on memory allocation failure
+    - scsi: fix upper bounds check of sense key in scsi_sense_key_string()
+    - metag: Fix atomic_*_return inline asm constraints
+    - cpufreq: Fix GOV_LIMITS handling for the userspace governor
+    - hwrng: exynos - Disable runtime PM on probe failure
+    - regulator: anatop: allow regulator to be in bypass mode
+    - lib/mpi: mpi_write_sgl(): fix skipping of leading zero limbs
+    - Linux 4.4.21
+
+  * Headset mic detection on some variants of Dell Inspiron 5468 (LP: #1617900)
+    - ALSA: hda - Add headset mic quirk for Dell Inspiron 5468
+
+  * Xenial update to v4.4.20 stable release (LP: #1621113)
+    - hugetlb: fix nr_pmds accounting with shared page tables
+    - x86/mm: Disable preemption during CR3 read+write
+    - uprobes/x86: Fix RIP-relative handling of EVEX-encoded instructions
+    - tools/testing/nvdimm: fix SIGTERM vs hotplug crash
+    - SUNRPC: Handle EADDRNOTAVAIL on connection failures
+    - SUNRPC: allow for upcalls for same uid but different gss service
+    - powerpc/eeh: eeh_pci_enable(): fix checking of post-request state
+    - ALSA: usb-audio: Add a sample rate quirk for Creative Live! Cam Socialize HD
+      (VF0610)
+    - ALSA: usb-audio: Add quirk for ELP HD USB Camera
+    - arm64: Define AT_VECTOR_SIZE_ARCH for ARCH_DLINFO
+    - parisc: Fix order of EREFUSED define in errno.h
+    - virtio: fix memory leak in virtqueue_add()
+    - vfio/pci: Fix NULL pointer oops in error interrupt setup handling
+    - perf intel-pt: Fix occasional decoding errors when tracing system-wide
+    - libnvdimm, nd_blk: mask off reserved status bits
+    - ALSA: hda - Manage power well properly for resume
+    - NVMe: Don't unmap controller registers on reset
+    - PCI: Support PCIe devices with short cfg_size
+    - PCI: Add Netronome vendor and device IDs
+    - PCI: Limit config space size for Netronome NFP6000 family
+    - PCI: Add Netronome NFP4000 PF device ID
+    - PCI: Limit config space size for Netronome NFP4000
+    - mmc: sdhci-acpi: Reduce Baytrail eMMC/SD/SDIO hangs
+    - ACPI: CPPC: Return error if _CPC is invalid on a CPU
+    - ACPI / CPPC: Prevent cpc_desc_ptr points to the invalid data
+    - um: Don't discard .text.exit section
+    - genirq/msi: Remove unused MSI_FLAG_IDENTITY_MAP
+    - genirq/msi: Make sure PCI MSIs are activated early
+    - crypto: caam - fix non-hmac hashes
+    - crypto: caam - fix echainiv(authenc) encrypt shared descriptor
+    - crypto: caam - defer aead_set_sh_desc in case of zero authsize
+    - usb: ehci: change order of register cleanup during shutdown
+    - usb: misc: usbtest: add fix for driver hang
+    - usb: dwc3: pci: add Intel Kabylake PCI ID
+    - usb: dwc3: gadget: increment request->actual once
+    - usb: hub: Fix unbalanced reference count/memory leak/deadlocks
+    - USB: hub: fix up early-exit pathway in hub_activate
+    - USB: hub: change the locking in hub_activate
+    - usb: renesas_usbhs: clear the BRDYSTS in usbhsg_ep_enable()
+    - usb: renesas_usbhs: Use dmac only if the pipe type is bulk
+    - USB: validate wMaxPacketValue entries in endpoint descriptors
+    - usb: gadget: fsl_qe_udc: off by one in setup_received_handle()
+    - usb/gadget: fix gadgetfs aio support.
+    - xhci: always handle "Command Ring Stopped" events
+    - usb: xhci: Fix panic if disconnect
+    - xhci: don't dereference a xhci member after removing xhci
+    - USB: serial: fix memleak in driver-registration error path
+    - USB: serial: option: add D-Link DWM-156/A3
+    - USB: serial: option: add support for Telit LE920A4
+    - USB: serial: ftdi_sio: add device ID for WICED USB UART dev board
+    - USB: serial: ftdi_sio: add PIDs for Ivium Technologies devices
+    - iommu/dma: Don't put uninitialised IOVA domains
+    - iommu/arm-smmu: Fix CMDQ error handling
+    - iommu/arm-smmu: Don't BUG() if we find aborting STEs with disable_bypass
+    - pinctrl/amd: Remove the default de-bounce time
+    - EDAC: Increment correct counter in edac_inc_ue_error()
+    - s390/dasd: fix hanging device after clear subchannel
+    - mac80211: fix purging multicast PS buffer queue
+    - arm64: dts: rockchip: add reset saradc node for rk3368 SoCs
+    - of: fix reference counting in of_graph_get_endpoint_by_regs
+    - sched/cputime: Fix NO_HZ_FULL getrusage() monotonicity regression
+    - sched/nohz: Fix affine unpinned timers mess
+    - iio: fix sched WARNING "do not call blocking ops when !TASK_RUNNING"
+    - drm/amdgpu: Change GART offset to 64-bit
+    - drm/amdgpu: fix amdgpu_move_blit on 32bit systems
+    - drm/amdgpu: avoid a possible array overflow
+    - drm/amdgpu: skip TV/CV in display parsing
+    - drm/amd/amdgpu: sdma resume fail during S4 on CI
+    - drm/amdgpu: record error code when ring test failed
+    - drm/i915: fix aliasing_ppgtt leak
+    - ARC: build: Better way to detect ISA compatible toolchain
+    - ARC: use correct offset in pt_regs for saving/restoring user mode r25
+    - ARC: Call trace_hardirqs_on() before enabling irqs
+    - ARC: Elide redundant setup of DMA callbacks
+    - aacraid: Check size values after double-fetch from user
+    - mfd: cros_ec: Add cros_ec_cmd_xfer_status() helper
+    - i2c: cros-ec-tunnel: Fix usage of cros_ec_cmd_xfer()
+    - cdc-acm: fix wrong pipe type on rx interrupt xfers
+    - mpt3sas: Fix resume on WarpDrive flash cards
+    - megaraid_sas: Fix probing cards without io port
+    - usb: renesas_usbhs: gadget: fix return value check in
+      usbhs_mod_gadget_probe()
+    - gpio: Fix OF build problem on UM
+    - fs/seq_file: fix out-of-bounds read
+    - btrfs: waiting on qgroup rescan should not always be interruptible
+    - btrfs: properly track when rescan worker is running
+    - Input: tegra-kbc - fix inverted reset logic
+    - Input: i8042 - break load dependency between atkbd/psmouse and i8042
+    - Input: i8042 - set up shared ps2_cmd_mutex for AUX ports
+    - crypto: nx - off by one bug in nx_of_update_msc()
+    - crypto: qat - fix aes-xts key sizes
+    - dmaengine: usb-dmac: check CHCR.DE bit in usb_dmac_isr_channel()
+    - USB: avoid left shift by -1
+    - usb: chipidea: udc: don't touch DP when controller is in host mode
+    - USB: fix typo in wMaxPacketSize validation
+    - USB: serial: mos7720: fix non-atomic allocation in write path
+    - USB: serial: mos7840: fix non-atomic allocation in write path
+    - USB: serial: option: add WeTelecom WM-D200
+    - USB: serial: option: add WeTelecom 0x6802 and 0x6803 products
+    - staging: comedi: daqboard2000: bug fix board type matching code
+    - staging: comedi: comedi_test: fix timer race conditions
+    - staging: comedi: ni_mio_common: fix AO inttrig backwards compatibility
+    - staging: comedi: ni_mio_common: fix wrong insn_write handler
+    - ACPI / drivers: fix typo in ACPI_DECLARE_PROBE_ENTRY macro
+    - ACPI / drivers: replace acpi_probe_lock spinlock with mutex
+    - ACPI / sysfs: fix error code in get_status()
+    - ACPI / SRAT: fix SRAT parsing order with both LAPIC and X2APIC present
+    - ALSA: line6: Remove double line6_pcm_release() after failed acquire.
+    - ALSA: line6: Give up on the lock while URBs are released.
+    - ALSA: line6: Fix POD sysfs attributes segfault
+    - hwmon: (iio_hwmon) fix memory leak in name attribute
+    - sysfs: correctly handle read offset on PREALLOC attrs
+    - Linux 4.4.20
+
+  * Failed to acknowledge elog: /sys/firmware/opal/elog/0x5018d709/acknowledge
+    (2:No such file or directory) (LP: #1619552)
+    - powerpc/powernv : Drop reference added by kset_find_obj()
+
+  * backport support for userspace access of DP aux devices (LP: #1619756)
+    - drm/dp: Add a drm_aux-dev module for reading/writing dpcd registers.
+    - drm/dp: Allow signals to interrupt drm_aux-dev reads/writes
+    - [Config] CONFIG_DRM_DP_AUX_CHARDEV=y
+
+  * Enable virtual scsi server driver for Power (LP: #1615665)
+    - SAUCE: Ibmvscsis: Properly deregister target sessions
+    - SAUCE: Return TCMU-generated sense data to fabric module
+    - SAUCE: Ibmvscsis: Code cleanup of print statements
+    - SAUCE: Ibmvscsis: Fixed a bug reported by Dan Carpenter
+
+  * ISST-LTE: system dropped into xmon at pcibios_release_device+0x5c/0x80
+    during running dlpar test on monklp3 (LP: #1618151)
+    - powerpc/pseries: use pci_host_bridge.release_fn() to kfree(phb)
+
+  * Kernel Build Fails for Fuse Module (LP: #1617550)
+    - SAUCE: (namespace) userns: Export current_in_userns to modules
+
+  * boot-time kernel panic introduced in 4.4.0-18, not present in 4.4.0-15
+    (LP: #1572630)
+    - blk-mq: Reuse hardware context cpumask for tags
+    - blk-mq: Use proper cpumask iterator
+
+ -- Joseph Salisbury <joseph.salisbury@canonical.com>  Mon, 19 Sep 2016 14:23:10 -0400
+
+linux (4.4.0-38.57) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1620658
+
+  * CIFS client: access problems after updating to kernel 4.4.0-29-generic
+    (LP: #1612135)
+    - Revert "UBUNTU: SAUCE: (namespace) Bypass sget() capability check for nfs"
+    - fs: Call d_automount with the filesystems creds
+
+  * apt-key add fails in overlayfs (LP: #1618572)
+    - SAUCE: overlayfs: fix regression in whiteout detection
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 30 Aug 2016 12:24:30 -0600
+
+linux (4.4.0-37.56) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1618040
+
+  * [Feature] Instruction decoder support for new SKX instructions- AVX512
+    (LP: #1591655)
+    - x86/insn: perf tools: Fix vcvtph2ps instruction decoding
+    - x86/insn: Add AVX-512 support to the instruction decoder
+    - perf tools: Add AVX-512 support to the instruction decoder used by Intel PT
+    - perf tools: Add AVX-512 instructions to the new instructions test
+
+  * [Ubuntu 16.04] FCoE Lun not visible in OS with inbox driver - Issue with
+    ioremap() call on 32bit kernel (LP: #1608652)
+    - lpfc: Correct issue with ioremap() call on 32bit kernel
+
+  * [Feature] turbostat support for Skylake-SP server (LP: #1591802)
+    - tools/power turbostat: decode more CPUID fields
+    - tools/power turbostat: CPUID(0x16) leaf shows base, max, and bus frequency
+    - tools/power turbostat: decode HWP registers
+    - tools/power turbostat: Decode MSR_MISC_PWR_MGMT
+    - tools/power turbostat: allow sub-sec intervals
+    - tools/power turbostat: Intel Xeon x200: fix erroneous bclk value
+    - tools/power turbostat: Intel Xeon x200: fix turbo-ratio decoding
+    - tools/power turbostat: re-name "%Busy" field to "Busy%"
+    - tools/power turbostat: add --out option for saving output in a file
+    - tools/power turbostat: fix compiler warnings
+    - tools/power turbostat: make fewer systems calls
+    - tools/power turbostat: show IRQs per CPU
+    - tools/power turbostat: show GFXMHz
+    - tools/power turbostat: show GFX%rc6
+    - tools/power turbostat: detect and work around syscall jitter
+    - tools/power turbostat: indicate SMX and SGX support
+    - tools/power turbostat: call __cpuid() instead of __get_cpuid()
+    - tools/power turbostat: correct output for MSR_NHM_SNB_PKG_CST_CFG_CTL dump
+    - tools/power turbostat: bugfix: TDP MSRs print bits fixing
+    - tools/power turbostat: SGX state should print only if --debug
+    - tools/power turbostat: print IRTL MSRs
+    - tools/power turbostat: initial BXT support
+    - tools/power turbostat: decode BXT TSC frequency via CPUID
+    - tools/power turbostat: initial SKX support
+
+  * [BYT] display hotplug doesn't work on console (LP: #1616894)
+    - drm/i915/vlv: Make intel_crt_reset() per-encoder
+    - drm/i915/vlv: Reset the ADPA in vlv_display_power_well_init()
+    - drm/i915/vlv: Disable HPD in valleyview_crt_detect_hotplug()
+    - drm/i915: Enable polling when we don't have hpd
+
+  * [Feature]intel_idle enabling on Broxton-P (LP: #1520446)
+    - intel_idle: add BXT support
+
+  * [Feature] EDAC: Update driver for SKX-SP (LP: #1591815)
+    - [Config] CONFIG_EDAC_SKX=m
+    - EDAC, skx_edac: Add EDAC driver for Skylake
+
+  * [Feature] KBL: Sandy Peak(3168) WiFi/BT support (LP: #1591648)
+    - Bluetooth: Add support for Intel Bluetooth device 3168 [8087:0aa7]
+
+  * MacBookPro11,4 fails to poweroff or suspend (LP: #1587714)
+    - SAUCE: PCI: Workaround to enable poweroff on Mac Pro 11
+
+  * Support Edge Gateway's Bluetooth LED (LP: #1512999)
+    - SAUCE: Bluetooth: Support for LED on Edge Gateways
+    - SAUCE: Bluetooth: Use host bridge subsystem IDs to identify Edge Gateways
+
+  * Please add support for alps touchpad. (LP: #1616813)
+    - [Config] CONFIG_HID_ALPS=m
+    - HID: add Alps I2C HID Touchpad-Stick support
+    - HID: alps: struct u1_dev *priv is internal to the driver
+    - HID: alps: pass correct sizes to hid_hw_raw_request()
+    - HID: alps: match alps devices in core
+    - HID: alps: a few cleanups
+
+  * DINO2M - System hangs with a black screen during s4 stress test
+    (LP: #1616781)
+    - x86/power/64: Fix kernel text mapping corruption during image restoration
+
+  * Xenial update to v4.4.17 stable release (LP: #1611833)
+    - USB: OHCI: Don't mark EDs as ED_OPER if scheduling fails
+    - x86/quirks: Apply nvidia_bugs quirk only on root bus
+    - x86/quirks: Reintroduce scanning of secondary buses
+    - x86/quirks: Add early quirk to reset Apple AirPort card
+    - dmaengine: at_xdmac: align descriptors on 64 bits
+    - dmaengine: at_xdmac: fix residue corruption
+    - dmaengine: at_xdmac: double FIFO flush needed to compute residue
+    - mm, sl[au]b: add __GFP_ATOMIC to the GFP reclaim mask
+    - mm, compaction: abort free scanner if split fails
+    - fs/nilfs2: fix potential underflow in call to crc32_le
+    - mm, compaction: prevent VM_BUG_ON when terminating freeing scanner
+    - mm, meminit: always return a valid node from early_pfn_to_nid
+    - mm, meminit: ensure node is online before checking whether pages are
+      uninitialised
+    - vmlinux.lds: account for destructor sections
+    - pps: do not crash when failed to register
+    - kernel/sysrq, watchdog, sched/core: Reset watchdog on all CPUs while
+      processing sysrq-w
+    - arc: unwind: warn only once if DW2_UNWIND is disabled
+    - ARC: unwind: ensure that .debug_frame is generated (vs. .eh_frame)
+    - xen/pciback: Fix conf_space read/write overlap check.
+    - xenbus: don't BUG() on user mode induced condition
+    - xenbus: don't bail early from xenbus_dev_request_and_reply()
+    - Input: vmmouse - remove port reservation
+    - Input: elantech - add more IC body types to the list
+    - Input: xpad - fix oops when attaching an unknown Xbox One gamepad
+    - Input: wacom_w8001 - w8001_MAX_LENGTH should be 13
+    - Input: xpad - validate USB endpoint count during probe
+    - Input: tsc200x - report proper input_dev name
+    - pvclock: Add CPU barriers to get correct version value
+    - pinctrl: single: Fix missing flush of posted write for a wakeirq
+    - pinctrl: imx: Do not treat a PIN without MUX register as an error
+    - cgroup: set css->id to -1 during init
+    - power_supply: power_supply_read_temp only if use_cnt > 0
+    - locks: use file_inode()
+    - Revert "ecryptfs: forbid opening files without mmap handler"
+    - ecryptfs: don't allow mmap when the lower fs doesn't support it
+    - ext4: verify extent header depth
+    - 9p: use file_dentry()
+    - namespace: update event counter when umounting a deleted dentry
+    - spi: sunxi: fix transfer timeout
+    - spi: sun4i: fix FIFO limit
+    - clk: rockchip: initialize flags of clk_init_data in mmc-phase clock
+    - platform/chrome: cros_ec_dev - double fetch bug in ioctl
+    - block: fix use-after-free in sys_ioprio_get()
+    - mmc: block: fix packed command header endianness
+    - sched/fair: Fix effective_load() to consistently use smoothed load
+    - ovl: handle ATTR_KILL*
+    - perf/x86: fix PEBS issues on Intel Atom/Core2
+    - can: at91_can: RX queue could get stuck at high bus load
+    - can: c_can: Update D_CAN TX and RX functions to 32 bit - fix Altera Cyclone
+      access
+    - can: fix handling of unmodifiable configuration options fix
+    - can: fix oops caused by wrong rtnl dellink usage
+    - RDS: fix rds_tcp_init() error path
+    - SCSI: fix new bug in scsi_dev_info_list string matching
+    - ipr: Clear interrupt on croc/crocodile when running with LSI
+    - posix_cpu_timer: Exit early when process has been reaped
+    - i2c: mux: reg: wrong condition checked for of_address_to_resource return
+      value
+    - libata: LITE-ON CX1-JB256-HP needs lower max_sectors
+    - libceph: apply new_state before new_up_client on incrementals
+    - net: mvneta: set real interrupt per packet for tx_done
+    - intel_th: pci: Add Kaby Lake PCH-H support
+    - intel_th: Fix a deadlock in modprobing
+    - vfs: fix deadlock in file_remove_privs() on overlayfs
+    - Linux 4.4.17
+    - xenbus: don't look up transaction IDs for ordinary writes
+
+  * Enable virtual scsi server driver for Power (LP: #1615665)
+    - [Config] CONFIG_SCSI_IBMVSCSIS=m
+    - target: Add target_alloc_session() helper function
+    - ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
+
+  * AES-XTS poor performance in Ubuntu 16.04 (LP: #1613295)
+    - crypto: vmx: Only call enable_kernel_vsx()
+    - powerpc: Create disable_kernel_{fp,altivec,vsx,spe}()
+    - crypto: vmx - Adding asm subroutines for XTS
+    - crypto: xts - consolidate sanity check for keys
+    - crypto: vmx - Adding support for XTS
+    - crypto: vmx - Fix aes_p8_xts_decrypt build failure
+    - crypto: xts - fix compile errors
+
+  *  System hang when plug/pull USB 3.1 key via thunderbolt port over 5 times
+    (LP: #1616318)
+    - USB: don't free bandwidth_mutex too early
+
+  * Ubuntu 16.04 - Full EEH Recovery Support for NVMe devices (LP: #1602724)
+    - nvme: Suspend all queues before deletion
+
+  * change_hat is logging failures during expected hat probing (LP: #1615893)
+    - SAUCE: apparmor: Fix auditing behavior for change_hat probing
+
+  * deleted files outside of the namespace are not being treated as disconnected
+    (LP: #1615892)
+    - SAUCE: apparmor: deleted dentries can be disconnected
+
+  * stacking to unconfined in a child namespace confuses mediation
+    (LP: #1615890)
+    - SAUCE: apparmor: special case unconfined when determining the mode
+
+  * apparmor module parameters can be changed after the policy is locked
+    (LP: #1615895)
+    - SAUCE: apparmor: fix: parameters can be changed after policy is locked
+
+  * AppArmor profile reloading causes an intermittent kernel BUG (LP: #1579135)
+    - SAUCE: apparmor: fix vec_unique for vectors larger than 8
+
+  * label vec reductions can result in reference labels instead of direct access
+    to labels (LP: #1615889)
+    - SAUCE: apparmor: reduction of vec to single entry is just that entry
+
+  * profiles from different namespaces can block other namespaces from being
+    able to load a profile (LP: #1615887)
+    - SAUCE: apparmor: profiles in one ns can affect mediation in another ns
+
+  * vmalloc failure leads to null ptr dereference in aa_dfa_next (LP: #1592547)
+    - SAUCE: apparmor: oops in profile_unpack() when policy_db is not present
+
+  * vmalloc_addr is being checked on the failed return address of kvzalloc()
+    (LP: #1615885)
+    - SAUCE: apparmor: fix: don't check for vmalloc_addr if kvzalloc() failed
+
+  * dfa is missing a bounds check which can cause an oops (LP: #1615882)
+    - SAUCE: apparmor: Add missing id bounds check on dfa verification
+
+  * The label build for onexec when stacking is wrong (LP: #1615881)
+    - SAUCE: apparmor: Fix label build for onexec stacking.
+
+  * The inherit check for new to old label comparison for domain transitions is
+    wrong (LP: #1615880)
+    - SAUCE: apparmor: Fix new to old label comparison for domain transitions
+
+  * warning stack trace while playing with apparmor namespaces (LP: #1593874)
+    - SAUCE: apparmor: fix stack trace when removing namespace with profiles
+
+  * __label_update proxy comparison test is wrong (LP: #1615878)
+    - SAUCE: apparmor: Fix __label_update proxy comparison test
+
+  * Xenial update to v4.4.19 stable release (LP: #1615620)
+    - usb: gadget: avoid exposing kernel stack
+    - usb: f_fs: off by one bug in _ffs_func_bind()
+    - usb: renesas_usbhs: protect the CFIFOSEL setting in usbhsg_ep_enable()
+    - usb: dwc3: fix for the isoc transfer EP_BUSY flag
+    - USB: serial: option: add support for Telit LE910 PID 0x1206
+    - usb: renesas_usbhs: fix NULL pointer dereference in xfer_work()
+    - arm64: kernel: Save and restore UAO and addr_limit on exception entry
+    - arm64: debug: unmask PSTATE.D earlier
+    - arm64: Fix incorrect per-cpu usage for boot CPU
+    - tty: serial: msm: Don't read off end of tx fifo
+    - serial: samsung: Fix ERR pointer dereference on deferred probe
+    - tty/serial: atmel: fix RS485 half duplex with DMA
+    - gpio: pca953x: Fix NBANK calculation for PCA9536
+    - gpio: intel-mid: Remove potentially harmful code
+    - Bluetooth: hci_intel: Fix null gpio desc pointer dereference
+    - pinctrl: cherryview: prevent concurrent access to GPIO controllers
+    - arm64: dts: rockchip: fixes the gic400 2nd region size for rk3368
+    - arm64: mm: avoid fdt_check_header() before the FDT is fully mapped
+    - KVM: PPC: Book3S HV: Pull out TM state save/restore into separate procedures
+    - KVM: PPC: Book3S HV: Save/restore TM state in H_CEDE
+    - KVM: MTRR: fix kvm_mtrr_check_gfn_range_consistency page fault
+    - KVM: VMX: handle PML full VMEXIT that occurs during event delivery
+    - KVM: nVMX: Fix memory corruption when using VMCS shadowing
+    - intel_pstate: Fix MSR_CONFIG_TDP_x addressing in core_get_max_pstate()
+    - mfd: qcom_rpm: Fix offset error for msm8660
+    - mfd: qcom_rpm: Parametrize also ack selector size
+    - media: usbtv: prevent access to free'd resources
+    - media: dvb_ringbuffer: Add memory barriers
+    - vb2: core: Skip planes array verification if pb is NULL
+    - Fix RC5 decoding with Fintek CIR chipset
+    - sur40: lower poll interval to fix occasional FPS drops to ~56 FPS
+    - sur40: fix occasional oopses on device close
+    - dm: set DMF_SUSPENDED* _before_ clearing DMF_NOFLUSH_SUSPENDING
+    - hp-wmi: Fix wifi cannot be hard-unblocked
+    - s5p-mfc: Set device name for reserved memory region devs
+    - s5p-mfc: Add release callback for memory region devs
+    - i2c: efm32: fix a failure path in efm32_i2c_probe()
+    - spi: pxa2xx: Clear all RFT bits in reset_sccr1() on Intel Quark
+    - Bluetooth: Fix l2cap_sock_setsockopt() with optname BT_RCVMTU
+    - EDAC: Correct channel count limit
+    - HID: uhid: fix timeout when probe races with IO
+    - ovl: disallow overlayfs as upperdir
+    - remoteproc: Fix potential race condition in rproc_add
+    - ARC: mm: don't loose PTE_SPECIAL in pte_modify()
+    - jbd2: make journal y2038 safe
+    - fs/cifs: make share unaccessible at root level mountable
+    - cifs: Check for existing directory when opening file with O_CREAT
+    - cifs: fix crash due to race in hmac(md5) handling
+    - CIFS: Fix a possible invalid memory access in smb2_query_symlink()
+    - random: initialize the non-blocking pool via add_hwgenerator_randomness()
+    - random: print a warning for the first ten uninitialized random users
+    - random: add interrupt callback to VMBus IRQ handler
+    - MIPS: KVM: Fix mapped fault broken commpage handling
+    - MIPS: KVM: Add missing gfn range check
+    - MIPS: KVM: Fix gfn range check in kseg0 tlb faults
+    - MIPS: KVM: Propagate kseg0/mapped tlb fault errors
+    - nfs: don't create zero-length requests
+    - nfsd: Fix race between FREE_STATEID and LOCK
+    - nfsd: don't return an unhashed lock stateid after taking mutex
+    - drm/i915: Don't complain about lack of ACPI video bios
+    - iommu/exynos: Suppress unbinding to prevent system failure
+    - iommu/vt-d: Return error code in domain_context_mapping_one()
+    - iommu/amd: Handle IOMMU_DOMAIN_DMA in ops->domain_free call-back
+    - iommu/amd: Init unity mappings only for dma_ops domains
+    - iommu/amd: Update Alias-DTE in update_device_table()
+    - audit: fix a double fetch in audit_log_single_execve_arg()
+    - ARM: dts: sunxi: Add a startup delay for fixed regulator enabled phys
+    - netlabel: add address family checks to netlbl_{sock,req}_delattr()
+    - w1:omap_hdq: fix regression
+    - drm/amdgpu: add a delay after ATPX dGPU power off
+    - drm/amdgpu: Poll for both connect/disconnect on analog connectors
+    - drm/amdgpu: support backlight control for UNIPHY3
+    - drm/amdgpu: Disable RPM helpers while reprobing connectors on resume
+    - drm/amdgpu: fix firmware info version checks
+    - drm/amdgpu/gmc7: add missing mullins case
+    - drm/radeon: add a delay after ATPX dGPU power off
+    - drm/radeon: Poll for both connect/disconnect on analog connectors
+    - drm/radeon: fix firmware info version checks
+    - drm/radeon: support backlight control for UNIPHY3
+    - drm/nouveau/gr/nv3x: fix instobj write offsets in gr setup
+    - drm/nouveau/fbcon: fix font width not divisible by 8
+    - drm: Restore double clflush on the last partial cacheline
+    - drm/edid: Add 6 bpc quirk for display AEO model 0.
+    - drm/i915: Never fully mask the the EI up rps interrupt on SNB/IVB
+    - drm/i915/dp: Revert "drm/i915/dp: fall back to 18 bpp when sink capability
+      is unknown"
+    - balloon: check the number of available pages in leak balloon
+    - ftrace/recordmcount: Work around for addition of metag magic but not
+      relocations
+    - metag: Fix __cmpxchg_u32 asm constraint for CMP
+    - block: add missing group association in bio-cloning functions
+    - block: fix bdi vs gendisk lifetime mismatch
+    - mtd: nand: fix bug writing 1 byte less than page size
+    - mm/hugetlb: avoid soft lockup in set_max_huge_pages()
+    - ALSA: hda: Fix krealloc() with __GFP_ZERO usage
+    - ALSA: hda/realtek - Can't adjust speaker's volume on a Dell AIO
+    - ALSA: hda: add AMD Bonaire AZ PCI ID with proper driver caps
+    - ALSA: hda - Fix headset mic detection problem for two dell machines
+    - IB/mlx5: Fix MODIFY_QP command input structure
+    - IB/mlx5: Fix entries checks in mlx5_ib_create_cq
+    - IB/mlx5: Fix returned values of query QP
+    - IB/mlx5: Fix entries check in mlx5_ib_resize_cq
+    - IB/mlx5: Fix post send fence logic
+    - IB/mlx5: Return PORT_ERR in Active to Initializing tranisition
+    - IB/SA: Use correct free function
+    - IB/IPoIB: Don't update neigh validity for unresolved entries
+    - IB/IWPM: Fix a potential skb leak
+    - IB/mlx4: Fix the SQ size of an RC QP
+    - IB/mlx4: Fix error flow when sending mads under SRIOV
+    - IB/mlx4: Fix memory leak if QP creation failed
+    - of: fix memory leak related to safe_name()
+    - ubi: Make volume resize power cut aware
+    - ubi: Fix early logging
+    - ubi: Fix race condition between ubi device creation and udev
+    - iscsi-target: Fix panic when adding second TCP connection to iSCSI session
+    - target: Fix ordered task target_setup_cmd_from_cdb exception hang
+    - target: Fix missing complete during ABORT_TASK + CMD_T_FABRIC_STOP
+    - target: Fix race between iscsi-target connection shutdown + ABORT_TASK
+    - target: Fix max_unmap_lba_count calc overflow
+    - target: Fix ordered task CHECK_CONDITION early exception handling
+    - Input: elan_i2c - properly wake up touchpad on ASUS laptops
+    - SUNRPC: Don't allocate a full sockaddr_storage for tracing
+    - MIPS: mm: Fix definition of R6 cache instruction
+    - MIPS: Don't register r4k sched clock when CPUFREQ enabled
+    - MIPS: hpet: Increase HPET_MIN_PROG_DELTA and decrease HPET_MIN_CYCLES
+    - PCI: Mark Atheros AR9485 and QCA9882 to avoid bus reset
+    - x86/platform/intel_mid_pci: Rework IRQ0 workaround
+    - ACPI / EC: Work around method reentrancy limit in ACPICA for _Qxx
+    - rtc: s3c: Add s3c_rtc_{enable/disable}_clk in s3c_rtc_setfreq()
+    - dm flakey: error READ bios during the down_interval
+    - module: Invalidate signatures on force-loaded modules
+    - Documentation/module-signing.txt: Note need for version info if reusing a
+      key
+    - Linux 4.4.19
+
+  * xfrm: ipsec crash when updating spd thresholds (LP: #1613787)
+    - xfrm: Ignore socket policies when rebuilding hash tables
+
+  * ISST-LTE:pKVM311:lotg5:Ubutu16041:lotg5 crashed @
+    writeback_sb_inodes+0x30c/0x590 (LP: #1614565)
+    - writeback: Write dirty times for WB_SYNC_ALL writeback
+
+  * IBM Power 720 Ethernet Not Seen (LP: #1612725)
+    - [Config] CONFIG_IBMEBUS=y for powerpc
+
+  * CAPI: Update default setting for the psl_fir_cntl register (LP: #1612431)
+    - cxl: Set psl_fir_cntl to production environment value
+
+  * Xenial update to v4.4.18 stable release (LP: #1614560)
+    - tcp: enable per-socket rate limiting of all 'challenge acks'
+    - ipv4: reject RTNH_F_DEAD and RTNH_F_LINKDOWN from user space
+    - bonding: set carrier off for devices created through netlink
+    - net: bgmac: Fix infinite loop in bgmac_dma_tx_add()
+    - net/irda: fix NULL pointer dereference on memory allocation failure
+    - qed: Fix setting/clearing bit in completion bitmap
+    - tcp: consider recv buf for the initial window scale
+    - ipath: Restrict use of the write() interface
+    - scsi: ignore errors from scsi_dh_add_device()
+    - HID: sony: do not bail out when the sixaxis refuses the output report
+    - i2c: i801: Allow ACPI SystemIO OpRegion to conflict with PCI BAR
+    - arm: oabi compat: add missing access checks
+    - KEYS: 64-bit MIPS needs to use compat_sys_keyctl for 32-bit userspace
+    - Revert "s390/kdump: Clear subchannel ID to signal non-CCW/SCSI IPL"
+    - random: strengthen input validation for RNDADDTOENTCNT
+    - devpts: clean up interface to pty drivers
+    - x86/mm/pat: Add support of non-default PAT MSR setting
+    - x86/mm/pat: Add pat_disable() interface
+    - x86/mm/pat: Replace cpu_has_pat with boot_cpu_has()
+    - x86/mtrr: Fix Xorg crashes in Qemu sessions
+    - x86/mtrr: Fix PAT init handling when MTRR is disabled
+    - x86/xen, pat: Remove PAT table init code from Xen
+    - x86/pat: Document the PAT initialization sequence
+    - x86/mm/pat: Fix BUG_ON() in mmap_mem() on QEMU/i386
+    - drm/i915: Pretend cursor is always on for ILK-style WM calculations (v2)
+    - x86/syscalls/64: Add compat_sys_keyctl for 32-bit userspace
+    - block: fix use-after-free in seq file
+    - sysv, ipc: fix security-layer leaking
+    - fuse: fsync() did not return IO errors
+    - fuse: fuse_flush must check mapping->flags for errors
+    - fuse: fix wrong assignment of ->flags in fuse_send_init()
+    - fs/dcache.c: avoid soft-lockup in dput()
+    - crypto: gcm - Filter out async ghash if necessary
+    - crypto: scatterwalk - Fix test in scatterwalk_done
+    - ext4: check for extents that wrap around
+    - ext4: fix deadlock during page writeback
+    - ext4: don't call ext4_should_journal_data() on the journal inode
+    - ext4: validate s_reserved_gdt_blocks on mount
+    - ext4: short-cut orphan cleanup on error
+    - ext4: fix reference counting bug on block allocation error
+    - mm: memcontrol: fix cgroup creation failure after many small jobs
+    - mm: memcontrol: fix swap counter leak on swapout from offline cgroup
+    - mm: memcontrol: fix memcg id ref counter on swap charge move
+    - Linux 4.4.18
+
+  * Ubuntu16.10:installation fails on Brazos system (31TB and 192 cores) No
+    memory for flatten_device_tree (no room) (LP: #1614309)
+    - SAUCE: powerpc/pseries: Increase RMA size to 512MB.
+
+  * [SRU] xgene_enet: 10g performance only hits ~75% on multi-client tests
+    (LP: #1613157)
+    - drivers: net: xgene: Add support for Classifier engine
+    - drivers: net: xgene: Add support for RSS
+    - drivers: net: xgene: Add support for multiple queues
+
+  * [SRU] xgene_enet: an extra interrupt may be pending for an interrupt
+    controller that doesn't support irq_disable and hardware with level
+    interrupt (LP: #1611399)
+    - drivers: net: xgene: fix extra IRQ issue
+
+  * Mic mute hotkey does not work on usb keyboard [03f0:2f4a] (LP: #1609606)
+    - HID: input: add mic mute key on HP slim keyboard
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 12 Aug 2016 09:05:59 +0200
+
+linux (4.4.0-36.55) xenial; urgency=low
+
+  [ Stefan Bader ]
+
+  * Release Tracking Bug
+    - LP: #1612305
+
+  * I2C touchpad does not work on AMD platform (LP: #1612006)
+    - SAUCE: pinctrl/amd: Remove the default de-bounce time
+
+  * CVE-2016-5696
+    - tcp: make challenge acks less predictable
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 11 Aug 2016 17:34:14 +0200
+
+linux (4.4.0-35.54) xenial; urgency=low
+
+  [ Stefan Bader ]
+
+  * Release Tracking Bug
+    - LP: #1611215
+
+  * [i915_bpo] Sync with v4.7 (LP: #1609742)
+    - SAUCE: i915_bpo: Sync with v4.7
+
+  * s390/cio: fix reset of channel measurement block (LP: #1609415)
+    - s390/cio: allow to reset channel measurement block
+
+  * in Ubuntu16.10: Hit on Call traces  and system goes down when transactional
+    memory  tests are running in 32TB Brazos system (LP: #1606786)
+    - powerpc/tm: Avoid SLB faults in treclaim/trecheckpoint when RI=0
+    - powerpc/tm: Fix stack pointer corruption in __tm_recheckpoint()
+
+  *  Power Menu does not display after press the Power Button (LP: #1609204)
+    - intel-vbtn: new driver for Intel Virtual Button
+    - [config] enable CONFIG_INTEL_VBTN=m
+
+  * OptiPlex 7450 AIO hangs when rebooting (LP: #1608762)
+    - x86/reboot: Add Dell Optiplex 7450 AIO reboot quirk
+
+  * virtualbox+usb 3.0 breaks boot, -28 kernel works (LP: #1604058)
+    - SAUCE: xhci: Fix soft lockup in xhci_pci_probe path when XHCI_STATE_HALTED
+
+  * linux-kernel: Freeing IRQ from IRQ context (LP: #1597908)
+    - block: defer timeouts to a workqueue
+
+  * Tunnel offload indications not stripped from encapsulated packets, causing
+    performance overhead (LP: #1602755)
+    - tunnels: Remove encapsulation offloads on decap.
+
+  * lm-sensors is throwing "ERROR: Can't get value of subfeature temp1_input:
+    I/O error" for be2net driver (LP: #1607387)
+    - be2net: perform temperature query in adapter regardless of its interface
+      state
+
+  * Dell dock MAC Address pass through doesn't work in Ubuntu (LP: #1579984)
+    - r8152: Add support for setting pass through MAC address on RTL8153-AD
+
+  * vmxnet3 LRO IPv6 performance issues (stalling TCP) (LP: #1605494)
+    - Driver: Vmxnet3: set CHECKSUM_UNNECESSARY for IPv6 packets
+
+  * ISST-LTE:pVM:monklp5:Ubuntu16.04.1:system crashed at
+    lpfc_sli4_scmd_to_wqidx_distr (LP: #1597974)
+    - SAUCE: lpfc: fix oops in lpfc_sli4_scmd_to_wqidx_distr() from
+      lpfc_send_taskmgmt()
+
+  * Backport cxlflash shutdown patch to Xenial SRU (LP: #1605405)
+    - SAUCE: cxlflash: Verify problem state area is mapped before notifying
+      shutdown
+
+  * Xenial update to v4.4.16 stable release (LP: #1607404)
+    - mac80211: fix fast_tx header alignment
+    - mac80211: mesh: flush mesh paths unconditionally
+    - mac80211_hwsim: Add missing check for HWSIM_ATTR_SIGNAL
+    - mac80211: Fix mesh estab_plinks counting in STA removal case
+    - EDAC, sb_edac: Fix rank lookup on Broadwell
+    - IB/cm: Fix a recently introduced locking bug
+    - IB/mlx4: Properly initialize GRH TClass and FlowLabel in AHs
+    - powerpc/pseries: Fix IBM_ARCH_VEC_NRCORES_OFFSET since POWER8NVL was added
+    - powerpc/tm: Always reclaim in start_thread() for exec() class syscalls
+    - usb: dwc2: fix regression on big-endian PowerPC/ARM systems
+    - USB: EHCI: declare hostpc register as zero-length array
+    - usb: common: otg-fsm: add license to usb-otg-fsm
+    - mnt: fs_fully_visible test the proper mount for MNT_LOCKED
+    - mnt: Account for MS_RDONLY in fs_fully_visible
+    - mnt: If fs_fully_visible fails call put_filesystem.
+    - of: fix autoloading due to broken modalias with no 'compatible'
+    - of: irq: fix of_irq_get[_byname]() kernel-doc
+    - locking/ww_mutex: Report recursive ww_mutex locking early
+    - locking/qspinlock: Fix spin_unlock_wait() some more
+    - locking/static_key: Fix concurrent static_key_slow_inc()
+    - x86, build: copy ldlinux.c32 to image.iso
+    - kprobes/x86: Clear TF bit in fault on single-stepping
+    - x86/amd_nb: Fix boot crash on non-AMD systems
+    - Revert "gpiolib: Split GPIO flags parsing and GPIO configuration"
+    - uvc: Forward compat ioctls to their handlers directly
+    - thermal: cpu_cooling: fix improper order during initialization
+    - writeback: use higher precision calculation in domain_dirty_limits()
+    - nfsd4/rpc: move backchannel create logic into rpc code
+    - nfsd: Always lock state exclusively.
+    - nfsd: Extend the mutex holding region around in nfsd4_process_open2()
+    - posix_acl: Add set_posix_acl
+    - nfsd: check permissions when setting ACLs
+    - make nfs_atomic_open() call d_drop() on all ->open_context() errors.
+    - NFS: Fix another OPEN_DOWNGRADE bug
+    - ARM: imx6ul: Fix Micrel PHY mask
+    - ARM: 8578/1: mm: ensure pmd_present only checks the valid bit
+    - ARM: 8579/1: mm: Fix definition of pmd_mknotpresent
+    - MIPS: KVM: Fix modular KVM under QEMU
+    - mm: Export migrate_page_move_mapping and migrate_page_copy
+    - UBIFS: Implement ->migratepage()
+    - sched/fair: Fix cfs_rq avg tracking underflow
+    - packet: Use symmetric hash for PACKET_FANOUT_HASH.
+    - net_sched: fix mirrored packets checksum
+    - cdc_ncm: workaround for EM7455 "silent" data interface
+    - ipv6: Fix mem leak in rt6i_pcpu
+    - ARCv2: Check for LL-SC livelock only if LLSC is enabled
+    - ARCv2: LLSC: software backoff is NOT needed starting HS2.1c
+    - kvm: Fix irq route entries exceeding KVM_MAX_IRQ_ROUTES
+    - KVM: nVMX: VMX instructions: fix segment checks when L1 is in long mode.
+    - HID: elo: kill not flush the work
+    - HID: hiddev: validate num_values for HIDIOCGUSAGES, HIDIOCSUSAGES commands
+    - tracing: Handle NULL formats in hold_module_trace_bprintk_format()
+    - base: make module_create_drivers_dir race-free
+    - iommu/arm-smmu: Wire up map_sg for arm-smmu-v3
+    - iommu/vt-d: Enable QI on all IOMMUs before setting root entry
+    - iommu/amd: Fix unity mapping initialization race
+    - drm/mgag200: Black screen fix for G200e rev 4
+    - ipmi: Remove smi_msg from waiting_rcv_msgs list before handle_one_recv_msg()
+    - arm64: Rework valid_user_regs
+    - vfs: add d_real_inode() helper
+    - af_unix: fix hard linked sockets on overlay
+    - btrfs: account for non-CoW'd blocks in btrfs_abort_transaction
+    - drm/radeon: fix asic initialization for virtualized environments
+    - drm/amdgpu/gfx7: fix broken condition check
+    - ubi: Make recover_peb power cut aware
+    - drm/amdkfd: unbind only existing processes
+    - drm/amdkfd: destroy dbgmgr in notifier release
+    - drm/dp/mst: Always clear proposed vcpi table for port.
+    - drm/nouveau/disp/sor/gf119: both links use the same training register
+    - drm/nouveau/gr/gf100-: update sm error decoding from gk20a nvgpu headers
+    - drm/nouveau/fbcon: fix out-of-bounds memory accesses
+    - drm/nouveau: fix for disabled fbdev emulation
+    - drm/nouveau/disp/sor/gf119: select correct sor when poking training pattern
+    - drm/i915/ilk: Don't disable SSC source if it's in use
+    - drm/i915: Refresh cached DP port register value on resume
+    - drm/i915: Update ifdeffery for mutex->owner
+    - drm/i915: Update CDCLK_FREQ register on BDW after changing cdclk frequency
+    - drm: add missing drm_mode_set_crtcinfo call
+    - drm: make drm_atomic_set_mode_prop_for_crtc() more reliable
+    - drm: atmel-hlcdc: actually disable scaling when no scaling is required
+    - drm/ttm: Make ttm_bo_mem_compat available
+    - drm/vmwgfx: Add an option to change assumed FB bpp
+    - drm/vmwgfx: Work around mode set failure in 2D VMs
+    - drm/vmwgfx: Check pin count before attempting to move a buffer
+    - drm/vmwgfx: Delay pinning fbdev framebuffer until after mode set
+    - drm/vmwgfx: Fix error paths when mapping framebuffer
+    - memory: omap-gpmc: Fix omap gpmc EXTRADELAY timing
+    - perf/x86: Fix undefined shift on 32-bit kernels
+    - xen/balloon: Fix declared-but-not-defined warning
+    - iio: Fix error handling in iio_trigger_attach_poll_func
+    - iio:st_pressure: fix sampling gains (bring inline with ABI)
+    - iio: light apds9960: Add the missing dev.parent
+    - iio: proximity: as3935: correct IIO_CHAN_INFO_RAW output
+    - iio: proximity: as3935: remove triggered buffer processing
+    - iio: proximity: as3935: fix buffer stack trashing
+    - iio: humidity: hdc100x: correct humidity integration time mask
+    - iio: humidity: hdc100x: fix IIO_TEMP channel reporting
+    - iio: hudmidity: hdc100x: fix incorrect shifting and scaling
+    - staging: iio: accel: fix error check
+    - iio: accel: kxsd9: fix the usage of spi_w8r8()
+    - iio:ad7266: Fix broken regulator error handling
+    - iio:ad7266: Fix support for optional regulators
+    - iio:ad7266: Fix probe deferral for vref
+    - tty/vt/keyboard: fix OOB access in do_compute_shiftstate()
+    - hwmon: (dell-smm) Restrict fan control and serial number to CAP_SYS_ADMIN by
+      default
+    - hwmon: (dell-smm) Disallow fan_type() calls on broken machines
+    - hwmon: (dell-smm) Cache fan_type() calls and change fan detection
+    - ALSA: dummy: Fix a use-after-free at closing
+    - ALSA: hda - Fix the headset mic jack detection on Dell machine
+    - ALSA: hda / realtek - add two more Thinkpad IDs (5050,5053) for tpt460 fixup
+    - ALSA: au88x0: Fix calculation in vortex_wtdma_bufshift()
+    - ALSA: echoaudio: Fix memory allocation
+    - ALSA: timer: Fix negative queue usage by racy accesses
+    - ALSA: hda/realtek: Add Lenovo L460 to docking unit fixup
+    - ALSA: hda - Add PCI ID for Kabylake-H
+    - ALSA: hda - fix read before array start
+    - ALSA: hda/realtek - add new pin definition in alc225 pin quirk table
+    - ALSA: pcm: Free chmap at PCM free callback, too
+    - ALSA: ctl: Stop notification after disconnection
+    - ALSA: hda - fix use-after-free after module unload
+    - ALSA: hda: add AMD Stoney PCI ID with proper driver caps
+    - ARM: sunxi/dt: make the CHIP inherit from allwinner,sun5i-a13
+    - ARM: dts: armada-38x: fix MBUS_ID for crypto SRAM on Armada 385 Linksys
+    - ARM: mvebu: fix HW I/O coherency related deadlocks
+    - ovl: Copy up underlying inode's ->i_mode to overlay inode
+    - ovl: verify upper dentry in ovl_remove_and_whiteout()
+    - scsi: fix race between simultaneous decrements of ->host_failed
+    - 53c700: fix BUG on untagged commands
+    - Fix reconnect to not defer smb3 session reconnect long after socket
+      reconnect
+    - cifs: dynamic allocation of ntlmssp blob
+    - File names with trailing period or space need special case conversion
+    - xen/acpi: allow xen-acpi-processor driver to load on Xen 4.7
+    - crypto: qat - make qat_asym_algs.o depend on asn1 headers
+    - tmpfs: don't undo fallocate past its last page
+    - tmpfs: fix regression hang in fallocate undo
+    - drm/i915: Revert DisplayPort fast link training feature
+    - ovl: verify upper dentry before unlink and rename
+    - Linux 4.4.16
+
+  * Regression caused by `fuse: Add support for pid namespaces` in 4.4.0-6.21
+    (LP: #1605344)
+    - SAUCE: (namespace) fuse: Permit requests from other pid namespaces
+
+  * CVE-2016-5400
+    - media: fix airspy usb probe error path
+
+  * Cannot mount proc in unprivileged containers if /proc/xen is mounted
+    (LP: #1607374)
+    - SAUCE: xenbus: Use proc_create_mount_point() to create /proc/xen
+
+  * Mic mute key does not work for Ideapad laptops (LP: #1607153)
+    - ideapad_laptop: Add an event for mic mute hotkey
+
+  * NVMe stress test fails after 12 hours on Ubuntu 16.04 (LP: #1604995)
+    - block: atari: Return early for unsupported sector size
+
+  * Console extremely slow with 4.4 kernels for servers with Matrox G200er2 or
+    similar (LP: #1605662)
+    - SAUCE: vesafb: Set mtrr:3 (write-combining) as default
+
+  * Ubuntu 16.04 - Full EEH Recovery Support for NVMe devices (LP: #1602724)
+    - nvme: use a work item to submit async event requests
+    - nvme: don't poll the CQ from the kthread
+    - nvme: replace the kthread with a per-device watchdog timer
+    - NVMe: Fix reset/remove race
+    - nvme: Avoid reset work on watchdog timer function during error recovery
+    - NVMe: Always use MSI/MSI-x interrupts
+
+  * [LTC-Test] - NMI watchdog Bug and call traces when trinity is executed.
+    (LP: #1602524)
+    - ext4: factor out determining of hole size
+    - ext4: return hole from ext4_map_blocks()
+    - ext4: more efficient SEEK_DATA implementation
+
+  * changelog: add CVEs as first class citizens (LP: #1604344)
+    - avoid duplicate CVE numbers in changelog
+
+  * [LTCTest][Opal][OP820] Machine crashed with Oops: Kernel access of bad area,
+    sig: 11 [#1] while executing Froze PE Error injection (LP: #1603449)
+    - powerpc/eeh: Fix invalid cached PE primary bus
+
+  * Hotplug remove and re-add adds PCI adapter to next PCI domain (PCI)
+    (LP: #1603574)
+    - powerpc/pci: Assign fixed PHB number based on device-tree properties
+
+  * nvme - reset_controller is not working after adapter's firmware upgrade
+    (adapter quirk is needed) (LP: #1602726)
+    - NVMe: Create discard zero quirk white list
+    - nvme/quirk: Add a delay before checking for adapter readiness
+
+  * ovs nat: conntrack netlink event are missing (LP: #1603468)
+    - openvswitch: fix conntrack netlink event delivery
+
+  * FlashGT - In Tuleta 8284-22A with card in card slot P1-C9, system Fails to
+    boot operating system (LP: #1602785)
+    - cxl: Ignore CAPI adapters misplaced in switched slots
+
+  * CVE-2016-5728
+    - misc: mic: Fix for double fetch security bug in VOP driver
+
+  * CVE-2016-5244 (LP: #1589041)
+    - rds: fix an infoleak in rds_inc_info_copy
+
+  * Miscellaneous Ubuntu changes
+    - Added Snapcraft files
+    - SAUCE: snapcraft: cleanup and remove unnecessary elements
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 09 Aug 2016 15:11:33 +0200
+
+linux (4.4.0-34.53) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1606960
+
+  * [APL][SAUCE] Slow system response time due to a monitor bug (LP: #1606147)
+    - x86/cpu/intel: Introduce macros for Intel family numbers
+    - SAUCE: x86/cpu: Add workaround for MONITOR instruction erratum on Goldmont
+      based CPUs
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 27 Jul 2016 10:01:20 -0500
+
+linux (4.4.0-33.52) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1605709
+
+  * [regression] NFS client: access problems after updating to kernel
+    4.4.0-31-generic (LP: #1603719)
+    - SAUCE: (namespace) Bypass sget() capability check for nfs
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 22 Jul 2016 13:10:08 -0500
+
+linux (4.4.0-32.51) xenial; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1604443
+
+  * thinkpad yoga 260 wacom touchscreen not working (LP: #1603975)
+    - HID: wacom: break out parsing of device and registering of input
+    - HID: wacom: Initialize hid_data.inputmode to -1
+    - HID: wacom: Support switching from vendor-defined device mode on G9 and G11
+
+  * changelog: add CVEs as first class citizens (LP: #1604344)
+    - use CVE numbers in changelog
+
+  * [Xenial] Include Huawei PCIe SSD hio kernel driver (LP: #1603483)
+    - SAUCE: import Huawei ES3000_V2 (2.1.0.23)
+    - SAUCE: hio: bio_endio() no longer takes errors arg
+    - SAUCE: hio: blk_queue make_request_fn now returns a blk_qc_t
+    - SAUCE: hio: use alloc_cpumask_var to avoid -Wframe-larger-than
+    - SAUCE: hio: fix mask maybe-uninitialized warning
+    - [config] enable CONFIG_HIO (Huawei ES3000_V2 PCIe SSD driver)
+    - SAUCE: hio: Makefile and Kconfig
+
+  * CVE-2016-5243 (LP: #1589036)
+    - tipc: fix an infoleak in tipc_nl_compat_link_dump
+    - tipc: fix nl compat regression for link statistics
+
+  * CVE-2016-4470
+    - KEYS: potential uninitialized variable
+
+  * integer overflow in xt_alloc_table_info (LP: #1555353)
+    - netfilter: x_tables: check for size overflow
+
+  * CVE-2016-3135:
+    - Revert "UBUNTU: SAUCE: (noup) netfilter: x_tables: check for size overflow"
+
+  * CVE-2016-4440 (LP: #1584192)
+    - kvm:vmx: more complete state update on APICv on/off
+
+  * the system hangs in the dma driver when reboot or shutdown on a baytrail-m
+    laptop (LP: #1602579)
+    - dmaengine: dw: platform: power on device on shutdown
+    - ACPI / LPSS: override power state for LPSS DMA device
+
+  * Add proper  palm detection support for MS Precision Touchpad (LP: #1593124)
+    - Revert "HID: multitouch: enable palm rejection if device implements
+      confidence usage"
+    - HID: multitouch: enable palm rejection for Windows Precision Touchpad
+
+  * Add support for Intel 8265 Bluetooth ([8087:0A2B]) (LP: #1599068)
+    - Bluetooth: Add support for Intel Bluetooth device 8265 [8087:0a2b]
+
+  * CVE-2016-4794 (LP: #1581871)
+    - percpu: fix synchronization between chunk->map_extend_work and chunk
+      destruction
+    - percpu: fix synchronization between synchronous map extension and chunk
+      destruction
+
+  * Xenial update to v4.4.15 stable release (LP: #1601952)
+    - net_sched: fix pfifo_head_drop behavior vs backlog
+    - net: Don't forget pr_fmt on net_dbg_ratelimited for CONFIG_DYNAMIC_DEBUG
+    - sit: correct IP protocol used in ipip6_err
+    - esp: Fix ESN generation under UDP encapsulation
+    - netem: fix a use after free
+    - ipmr/ip6mr: Initialize the last assert time of mfc entries.
+    - Bridge: Fix ipv6 mc snooping if bridge has no ipv6 address
+    - sock_diag: do not broadcast raw socket destruction
+    - bpf, perf: delay release of BPF prog after grace period
+    - neigh: Explicitly declare RCU-bh read side critical section in neigh_xmit()
+    - net: macb: fix default configuration for GMAC on AT91
+    - net: alx: Work around the DMA RX overflow issue
+    - bpf: try harder on clones when writing into skb
+    - AX.25: Close socket connection on session completion
+    - crypto: ux500 - memmove the right size
+    - crypto: user - re-add size check for CRYPTO_MSG_GETALG
+    - USB: uas: Fix slave queue_depth not being set
+    - usb: quirks: Fix sorting
+    - usb: quirks: Add no-lpm quirk for Acer C120 LED Projector
+    - usb: musb: only restore devctl when session was set in backup
+    - usb: musb: Stop bulk endpoint while queue is rotated
+    - usb: musb: Ensure rx reinit occurs for shared_fifo endpoints
+    - usb: musb: host: correct cppi dma channel for isoch transfer
+    - usb: xhci-plat: properly handle probe deferral for devm_clk_get()
+    - USB: xhci: Add broken streams quirk for Frescologic device id 1009
+    - xhci: Fix handling timeouted commands on hosts in weird states.
+    - USB: mos7720: delete parport
+    - usb: gadget: fix spinlock dead lock in gadgetfs
+    - usb: host: ehci-tegra: Grab the correct UTMI pads reset
+    - usb: dwc3: exynos: Fix deferred probing storm.
+    - Linux 4.4.15
+
+  * qeth: delete napi struct when removing a qeth device (LP: #1601831)
+    - qeth: delete napi struct when removing a qeth device
+
+  * Adjust KBL PCI-ID's (LP: #1600124)
+    - drm/i915: Add more Kabylake PCI IDs.
+    - drm/i915: Removing PCI IDs that are no longer listed as Kabylake.
+
+  * [i915_bpo] Rebase driver to v4.7-rc6 + gen9 workarounds + KBP PCH support
+    (LP: #1599109)
+    - drm/kms_helper: Add a common place to call init and exit functions.
+    - drm: Add helper for DP++ adaptors
+    - GPU-DRM: Delete unnecessary checks before drm_property_unreference_blob()
+    - drm: introduce pipe color correction properties
+    - drm: fix blob pointer check
+    - drm: atomic helper: do not unreference error pointer
+    - drm: fix lut value extraction function
+    - drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
+    - SAUCE: drm: Introduce drm_malloc_gfp()
+    - SAUCE: i915_bpo: Rebase to v4.7-rc6
+    - SAUCE: i915_bpo: Add backported workarounds for gen9
+    - SAUCE: i915_bpo: Revert "drm/i915: Get panel_type from OpRegion panel
+      details"
+    - SAUCE: i915_bpo: Introduce Kabypoint PCH for Kabylake H/DT.
+
+  * Baytrail-I got black screen with HDMI output (LP: #1599379)
+    - drm/i915: Only ignore eDP ports that are connected
+    - drm/i915: Check VBT for port presence in addition to the strap on VLV/CHV
+
+  * [Hyper-V] storvsc messages for CD-ROM medium not present tray closed
+    (LP: #1590655)
+    - SAUCE: (no-up) scsi: storvsc: Filter out storvsc messages CD-ROM medium not
+      present
+
+  * Hotplug device addition issue - missing patches on Xenial kernel
+    (LP: #1599250)
+    - Revert "UBUNTU: SAUCE: powerpc/eeh: Validate arch in eeh_add_device_early()"
+    - Revert "powerpc/eeh: Fix crash in eeh_add_device_early() on Cell"
+    - powerpc/iommu: Remove the dependency on EEH struct in DDW mechanism
+    - powerpc/pseries: Fix PCI config address for DDW
+
+  * kernel: signal return with invalid floating-point control (LP: #1597971)
+    - s390: fix test_fp_ctl inline assembly contraints
+
+  * [Toshiba P50W-B00F] Touchscreen no longer working (LP: #1498667)
+    - SAUCE: (no-up) usb: quirks: Add no-lpm quirk for Elan Microelectronics
+      Touchpad
+
+  * [yakkety] d-i does not support (ehci_msm) Qualcomm  On-Chip EHCI Host
+    Controller (LP: #1599347)
+    - d-i: Add ehci_msm to usb-modules
+
+  * [Bug] Legacy audio couldn't work after S3 resume on Kabylake (LP: #1596871)
+    - ALSA: hda - Skip ELD notification during PM process
+    - ALSA: hda - hdmi add wmb barrier for audio component
+    - ALSA: hda - hdmi defer to register acomp eld notifier
+
+  * sync spl  0.6.5.6-0ubuntu4 changes into Xenial kernel source (LP: #1599257)
+    - SAUCE: (noup) Update spl to 0.6.5.6-0ubuntu4
+
+  * Config: missing AMD Seattle platform support (LP: #1597574)
+    - [Config] Enable the AMD Seattle platform
+
+  * Network installer fails to detect network on AMD Overdrive (ARM64)
+    (LP: #1597573)
+    - [Config] Add amd-xgbe to nic-modules udeb
+
+  * exercising ptys causes a kernel oops (LP: #1586418)
+    - devpts: fix null pointer dereference on failed memory allocation
+
+  * Regression (constant vibration of device) in xpad driver in Ubuntu 16.04
+    (LP: #1574102)
+    - Input: xpad - move pending clear to the correct location
+
+  * thunderx nics fail to establish link (LP: #1597867)
+    - net: thunderx: Fix link status reporting
+
+  * Xenial update to v4.4.14 stable release (LP: #1596575)
+    - scsi_lib: correctly retry failed zero length REQ_TYPE_FS commands
+    - scsi: Add QEMU CD-ROM to VPD Inquiry Blacklist
+    - netlink: Fix dump skb leak/double free
+    - tipc: fix nametable publication field in nl compat
+    - switchdev: pass pointer to fib_info instead of copy
+    - tuntap: correctly wake up process during uninit
+    - udp: prevent skbs lingering in tunnel socket queues
+    - uapi glibc compat: fix compilation when !__USE_MISC in glibc
+    - sfc: on MC reset, clear PIO buffer linkage in TXQs
+    - team: don't call netdev_change_features under team->lock
+    - vxlan: Accept user specified MTU value when create new vxlan link
+    - tcp: record TLP and ER timer stats in v6 stats
+    - bridge: Don't insert unnecessary local fdb entry on changing mac address
+    - l2tp: fix configuration passed to setup_udp_tunnel_sock()
+    - ipv6: Skip XFRM lookup if dst_entry in socket cache is valid
+    - vxlan: Relax MTU constraints
+    - geneve: Relax MTU constraints
+    - vxlan, gre, geneve: Set a large MTU on ovs-created tunnel devices
+    - KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS
+    - KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi
+    - ALSA: hda - Add PCI ID for Kabylake
+    - ALSA: hda - Fix headset mic detection problem for Dell machine
+    - ALSA: hda/realtek - ALC256 speaker noise issue
+    - ALSA: hda/realtek - Add support for new codecs ALC700/ALC701/ALC703
+    - ALSA: hda/realtek: Add T560 docking unit fixup
+    - ARM: fix PTRACE_SETVFPREGS on SMP systems
+    - gpio: bcm-kona: fix bcm_kona_gpio_reset() warnings
+    - s390/bpf: fix recache skb->data/hlen for skb_vlan_push/pop
+    - s390/bpf: reduce maximum program size to 64 KB
+    - irqchip/gic-v3: Fix ICC_SGI1R_EL1.INTID decoding mask
+    - crypto: public_key: select CRYPTO_AKCIPHER
+    - crypto: ccp - Fix AES XTS error for request sizes above 4096
+    - arm64: Provide "model name" in /proc/cpuinfo for PER_LINUX32 tasks
+    - arm64: mm: always take dirty state from new pte in ptep_set_access_flags
+    - powerpc/pseries/eeh: Handle RTAS delay requests in configure_bridge
+    - powerpc: Fix definition of SIAR and SDAR registers
+    - powerpc: Use privileged SPR number for MMCR2
+    - powerpc/pseries: Add POWER8NVL support to ibm,client-architecture-support
+      call
+    - pinctrl: mediatek: fix dual-edge code defect
+    - parisc: Fix pagefault crash in unaligned __get_user() call
+    - memcg: add RCU locking around css_for_each_descendant_pre() in
+      memcg_offline_kmem()
+    - wext: Fix 32 bit iwpriv compatibility issue with 64 bit Kernel
+    - x86/entry/traps: Don't force in_interrupt() to return true in IST handlers
+    - fix d_walk()/non-delayed __d_free() race
+    - sparc: Fix system call tracing register handling.
+    - sparc64: Fix bootup regressions on some Kconfig combinations.
+    - sparc64: Fix numa node distance initialization
+    - sparc64: Fix sparc64_set_context stack handling.
+    - sparc/PCI: Fix for panic while enabling SR-IOV
+    - sparc64: Reduce TLB flushes during hugepte changes
+    - sparc64: Take ctx_alloc_lock properly in hugetlb_setup().
+    - sparc: Harden signal return frame checks.
+    - sparc64: Fix return from trap window fill crashes.
+    - MIPS: Fix 64k page support for 32 bit kernels.
+    - crypto: qat - fix adf_ctl_drv.c:undefined reference to adf_init_pf_wq
+    - drm/core: Do not preserve framebuffer on rmfb, v4.
+    - Linux 4.4.14
+
+  * [Hyper-V] Rebase Hyper-V to 4.6 kernel (LP: #1583357)
+    - hv_netvsc: rework link status change handling
+    - hv_netvsc: Resize some of the variables in hv_netvsc_packet
+    - hv_netvsc: Rearrange the hv_negtvsc_packet to be space efficient
+    - hv_netvsc: Eliminate the channel field in hv_netvsc_packet structure
+    - hv_netvsc: Eliminate rndis_msg pointer from hv_netvsc_packet structure
+    - hv_netvsc: Eliminatte the data field from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate send_completion from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate send_completion_ctx from struct hv_netvsc_packet
+    - hv_netvsc: Don't ask for additional head room in the skb
+    - hv_netvsc: move subchannel existence check to netvsc_select_queue()
+    - hv_netvsc: remove locking in netvsc_send()
+    - hv_netvsc: Eliminate page_buf from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate send_completion_tid from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate is_data_pkt from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate completion_func from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate xmit_more from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate status from struct hv_netvsc_packet
+    - hv_netvsc: Eliminate vlan_tci from struct hv_netvsc_packet
+    - storvsc: add logging for error/warning messages
+    - hv_netvsc: Fix race condition on Multi-Send Data field
+    - kvm/x86: split ioapic-handled and EOI exit bitmaps
+    - kvm/x86: per-vcpu apicv deactivation support
+    - kvm/x86: Hyper-V synthetic interrupt controller
+    - kvm/x86: Hyper-V kvm exit
+    - kvm/x86: Rearrange func's declarations inside Hyper-V header
+    - kvm/x86: Added Hyper-V vcpu_to_hv_vcpu()/hv_vcpu_to_vcpu() helpers
+    - kvm/x86: Hyper-V internal helper to read MSR HV_X64_MSR_TIME_REF_COUNT
+    - kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack
+    - kvm/x86: Hyper-V SynIC timers
+    - storvsc: Fix a bug in the layout of the hv_fc_wwn_packet
+    - storvsc: Properly support Fibre Channel devices
+    - storvsc: Refactor the code in storvsc_channel_init()
+    - storvsc: Tighten up the interrupt path
+    - storvsc: Fix typo in MODULE_PARM_DESC
+    - Revert "hv_netvsc: use skb_get_hash() instead of a homegrown implementation"
+    - hv_netvsc: use skb_get_hash() instead of a homegrown implementation
+    - hv_netvsc: Fix book keeping of skb during batching process
+    - storvsc: Install the storvsc specific timeout handler for FC devices
+    - storvsc: Use the specified target ID in device lookup
+    - Revert "Drivers: hv: vmbus: Cleanup vmbus_set_event()"
+    - Drivers: hv: vmbus: Cleanup vmbus_set_event()
+    - Revert "Drivers: hv: vmbus: Eliminate the spin lock on the read path"
+    - Drivers: hv: vmbus: Eliminate the spin lock on the read path
+    - Revert "hv_netvsc: cleanup netdev feature flags for netvsc"
+    - hv_netvsc: cleanup netdev feature flags for netvsc
+    - hv_netvsc: Restore needed_headroom request
+    - kvm/x86: Rename Hyper-V long spin wait hypercall
+    - hv_netvsc: add software transmit timestamp support
+    - hv_netvsc: add ethtool support for set and get of settings
+    - hv_netvsc: Fix accessing freed memory in netvsc_change_mtu()
+    - hv_netvsc: Fix the array sizes to be max supported channels
+    - hv_netvsc: Fix the order of num_sc_offered decrement
+    - x86/hyperv: Avoid reporting bogus NMI status for Gen2 instances
+    - Drivers: hv: vmbus: Fix signaling logic in hv_need_to_signal_on_read()
+    - Drivers: hv: kvp: fix IP Failover
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 19 Jul 2016 11:18:32 -0500
+
+linux (4.4.0-31.50) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1602449
+
+  * nouveau: boot hangs at blank screen with unsupported graphics cards
+    (LP: #1602340)
+    - SAUCE: drm: check for supported chipset before booting fbdev off the hw
+
+ -- Kamal Mostafa <kamal@canonical.com>  Tue, 12 Jul 2016 16:28:12 -0700
+
+linux (4.4.0-30.49) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1597897
+
+  * FCP devices are not detected correctly nor deterministically (LP: #1567602)
+    - scsi_dh_alua: Disable ALUA handling for non-disk devices
+    - scsi_dh_alua: Use vpd_pg83 information
+    - scsi_dh_alua: improved logging
+    - scsi_dh_alua: sanitze sense code handling
+    - scsi_dh_alua: use standard logging functions
+    - scsi_dh_alua: return standard SCSI return codes in submit_rtpg
+    - scsi_dh_alua: fixup description of stpg_endio()
+    - scsi_dh_alua: use flag for RTPG extended header
+    - scsi_dh_alua: use unaligned access macros
+    - scsi_dh_alua: rework alua_check_tpgs() to return the tpgs mode
+    - scsi_dh_alua: simplify sense code handling
+    - scsi: Add scsi_vpd_lun_id()
+    - scsi: Add scsi_vpd_tpg_id()
+    - scsi_dh_alua: use scsi_vpd_tpg_id()
+    - scsi_dh_alua: Remove stale variables
+    - scsi_dh_alua: Pass buffer as function argument
+    - scsi_dh_alua: separate out alua_stpg()
+    - scsi_dh_alua: Make stpg synchronous
+    - scsi_dh_alua: call alua_rtpg() if stpg fails
+    - scsi_dh_alua: switch to scsi_execute_req_flags()
+    - scsi_dh_alua: allocate RTPG buffer separately
+    - scsi_dh_alua: Use separate alua_port_group structure
+    - scsi_dh_alua: use unique device id
+    - scsi_dh_alua: simplify alua_initialize()
+    - revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should
+      succeed while TPG is transitioning")
+    - scsi_dh_alua: move optimize_stpg evaluation
+    - scsi_dh_alua: remove 'rel_port' from alua_dh_data structure
+    - scsi_dh_alua: Use workqueue for RTPG
+    - scsi_dh_alua: Allow workqueue to run synchronously
+    - scsi_dh_alua: Add new blacklist flag 'BLIST_SYNC_ALUA'
+    - scsi_dh_alua: Recheck state on unit attention
+    - scsi_dh_alua: update all port states
+    - scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
+    - scsi_dh_alua: do not fail for unknown VPD identification
+
+ -- Kamal Mostafa <kamal@canonical.com>  Thu, 30 Jun 2016 12:52:15 -0700
+
+linux (4.4.0-29.48) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1597015
+
+  * Wireless hotkey fails on Dell XPS 15 9550 (LP: #1589886)
+    - intel-hid: new hid event driver for hotkeys
+    - intel-hid: fix incorrect entries in intel_hid_keymap
+    - intel-hid: allocate correct amount of memory for private struct
+    - intel-hid: add a workaround to ignore an event after waking up from S4.
+    - [Config] CONFIG_INTEL_HID_EVENT=m
+
+  * cgroupfs mounts can hang (LP: #1588056)
+    - Revert "UBUNTU: SAUCE: (namespace) mqueue: Super blocks must be owned by the
+      user ns which owns the ipc ns"
+    - Revert "UBUNTU: SAUCE: kernfs: Do not match superblock in another user
+      namespace when mounting"
+    - Revert "UBUNTU: SAUCE: cgroup: Use a new super block when mounting in a
+      cgroup namespace"
+    - (namespace) bpf: Use mount_nodev not mount_ns to mount the bpf filesystem
+    - (namespace) bpf, inode: disallow userns mounts
+    - (namespace) ipc: Initialize ipc_namespace->user_ns early.
+    - (namespace) vfs: Pass data, ns, and ns->userns to mount_ns
+    - SAUCE: (namespace) Sync with upstream s_user_ns patches
+    - (namespace) kernfs: The cgroup filesystem also benefits from SB_I_NOEXEC
+    - (namespace) ipc/mqueue: The mqueue filesystem should never contain
+      executables
+
+  * KVM system crashes after starting guest (LP: #1596635)
+    - xhci: Cleanup only when releasing primary hcd
+
+  * Upstream patch "crypto: vmx - IV size failing on skcipher API" for Ubuntu
+    16.04 (LP: #1596557)
+    - crypto: vmx - IV size failing on skcipher API
+
+  * [Bug]tpm initialization fails on x86 (LP: #1596469)
+    - tpm_crb: drop struct resource res from struct crb_priv
+    - tpm_crb: fix mapping of the buffers
+
+  * Device shutdown notification for CAPI Flash cards (LP: #1592114)
+    - cxlflash: Fix regression issue with re-ordering patch
+    - cxlflash: Fix to drain operations from previous reset
+    - cxlflash: Add device dependent flags
+    - cxlflash: Shutdown notify support for CXL Flash cards
+
+  * scsi-modules udeb should include pm80xx (LP: #1595628)
+    - [Config] Add pm80xx scsi driver to d-i
+
+  * Sync up latest relevant upstream bug fixes (LP: #1594871)
+    - SAUCE: (noup) Update zfs to 0.6.5.6-0ubuntu10
+
+  * Cannot compile module tda10071 (LP: #1592531)
+    - [media] tda10071: Fix dependency to REGMAP_I2C
+
+  * lsvpd doesn't show correct location code for devices attached to a CAPI card
+    (LP: #1594847)
+    - cxl: Make vPHB device node match adapter's
+
+  * enable CRC32 and AES ARM64 by default or as module (LP: #1594455)
+    - [Config] Enable arm64 AES and CRC32 crypto
+
+  * VMX kernel crypto module exhibits poor performance in Ubuntu 16.04
+    (LP: #1592481)
+    - crypto: vmx - comply with ABIs that specify vrsave as reserved.
+    - crypto: vmx - Fix ABI detection
+    - crypto: vmx - Increase priority of aes-cbc cipher
+
+  * build squashfs into xenial kernels by default (LP: #1593134)
+    - [Config] CONFIG_SQUASHFS=y
+
+  * Restore irqfd fast path for PPC (LP: #1592809)
+    - KVM: PPC: Book3S HV: Re-enable XICS fast path for irqfd-generated interrupts
+
+  * Unable to start guests with memballoon default. (LP: #1592042)
+    - virtio_balloon: fix PFN format for virtio-1
+
+  * Key 5 automatically pressed on some Logitech wireless keyboards
+    (LP: #1579190)
+    - HID: core: prevent out-of-bound readings
+
+  * ZFS: Running ztest repeatedly for long periods of time eventually results in
+    "zdb: can't open 'ztest': No such file or directory" (LP: #1587686)
+    - Fix ztest truncated cache file
+
+  * STC840.20:Alpine:alp7fp1:Ubuntu 16.04, BlueFin (SAN) EEH 6 times during boot
+    then disabled SRC BA188002:b0314a_1612.840 (LP: #1587316)
+    - lpfc: Fix DMA faults observed upon plugging loopback connector
+
+ -- Kamal Mostafa <kamal@canonical.com>  Tue, 28 Jun 2016 10:17:41 -0700
+
+linux (4.4.0-28.47) xenial; urgency=low
+
+  [ Luis Henriques ]
+
+  * Release Tracking Bug
+    - LP: #1595874
+
+  * Linux netfilter local privilege escalation issues (LP: #1595350)
+    - netfilter: x_tables: don't move to non-existent next rule
+    - netfilter: x_tables: validate targets of jumps
+    - netfilter: x_tables: add and use xt_check_entry_offsets
+    - netfilter: x_tables: kill check_entry helper
+    - netfilter: x_tables: assert minimum target size
+    - netfilter: x_tables: add compat version of xt_check_entry_offsets
+    - netfilter: x_tables: check standard target size too
+    - netfilter: x_tables: check for bogus target offset
+    - netfilter: x_tables: validate all offsets and sizes in a rule
+    - netfilter: x_tables: don't reject valid target size on some architectures
+    - netfilter: arp_tables: simplify translate_compat_table args
+    - netfilter: ip_tables: simplify translate_compat_table args
+    - netfilter: ip6_tables: simplify translate_compat_table args
+    - netfilter: x_tables: xt_compat_match_from_user doesn't need a retval
+    - netfilter: x_tables: do compat validation via translate_table
+    - netfilter: x_tables: introduce and use xt_copy_counters_from_user
+
+  * Linux netfilter IPT_SO_SET_REPLACE memory corruption (LP: #1555338)
+    - netfilter: x_tables: validate e->target_offset early
+    - netfilter: x_tables: make sure e->next_offset covers remaining blob size
+    - netfilter: x_tables: fix unconditional helper
+
+ -- Luis Henriques <luis.henriques@canonical.com>  Fri, 24 Jun 2016 09:57:21 +0100
+
+linux (4.4.0-27.46) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1594906
+
+  * Support Edge Gateway's Bluetooth LED (LP: #1512999)
+    - Revert "UBUNTU: SAUCE: Bluetooth: Support for LED on Marvell modules"
+
+ -- Kamal Mostafa <kamal@canonical.com>  Tue, 21 Jun 2016 10:17:00 -0700
+
+linux (4.4.0-26.45) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1594442
+
+  * linux: Implement secure boot state variables (LP: #1593075)
+    - SAUCE: UEFI: Add secure boot and MOK SB State disabled sysctl
+
+  * failures building userspace packages that include ethtool.h (LP: #1592930)
+    - ethtool.h: define INT_MAX for userland
+
+ -- Kamal Mostafa <kamal@canonical.com>  Mon, 20 Jun 2016 09:43:47 -0700
+
+linux (4.4.0-25.44) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1591289
+
+  * Xenial update to v4.4.13 stable release (LP: #1590455)
+    - MIPS64: R6: R2 emulation bugfix
+    - MIPS: math-emu: Fix jalr emulation when rd == $0
+    - MIPS: MSA: Fix a link error on `_init_msa_upper' with older GCC
+    - MIPS: Don't unwind to user mode with EVA
+    - MIPS: Avoid using unwind_stack() with usermode
+    - MIPS: Fix siginfo.h to use strict posix types
+    - MIPS: Fix uapi include in exported asm/siginfo.h
+    - MIPS: Fix watchpoint restoration
+    - MIPS: Flush highmem pages in __flush_dcache_page
+    - MIPS: Handle highmem pages in __update_cache
+    - MIPS: Sync icache & dcache in set_pte_at
+    - MIPS: ath79: make bootconsole wait for both THRE and TEMT
+    - MIPS: Reserve nosave data for hibernation
+    - MIPS: Loongson-3: Reserve 32MB for RS780E integrated GPU
+    - MIPS: Use copy_s.fmt rather than copy_u.fmt
+    - MIPS: Fix MSA ld_*/st_* asm macros to use PTR_ADDU
+    - MIPS: Prevent "restoration" of MSA context in non-MSA kernels
+    - MIPS: Disable preemption during prctl(PR_SET_FP_MODE, ...)
+    - MIPS: ptrace: Fix FP context restoration FCSR regression
+    - MIPS: ptrace: Prevent writes to read-only FCSR bits
+    - MIPS: Fix sigreturn via VDSO on microMIPS kernel
+    - MIPS: Build microMIPS VDSO for microMIPS kernels
+    - MIPS: lib: Mark intrinsics notrace
+    - MIPS: VDSO: Build with `-fno-strict-aliasing'
+    - affs: fix remount failure when there are no options changed
+    - ASoC: ak4642: Enable cache usage to fix crashes on resume
+    - Input: uinput - handle compat ioctl for UI_SET_PHYS
+    - ARM: mvebu: fix GPIO config on the Linksys boards
+    - ARM: dts: at91: fix typo in sama5d2 PIN_PD24 description
+    - ARM: dts: exynos: Add interrupt line to MAX8997 PMIC on exynos4210-trats
+    - ARM: dts: imx35: restore existing used clock enumeration
+    - ath9k: Add a module parameter to invert LED polarity.
+    - ath9k: Fix LED polarity for some Mini PCI AR9220 MB92 cards.
+    - ath10k: fix debugfs pktlog_filter write
+    - ath10k: fix firmware assert in monitor mode
+    - ath10k: fix rx_channel during hw reconfigure
+    - ath10k: fix kernel panic, move arvifs list head init before htt init
+    - ath5k: Change led pin configuration for compaq c700 laptop
+    - hwrng: exynos - Fix unbalanced PM runtime put on timeout error path
+    - rtlwifi: rtl8723be: Add antenna select module parameter
+    - rtlwifi: btcoexist: Implement antenna selection
+    - rtlwifi: Fix logic error in enter/exit power-save mode
+    - rtlwifi: pci: use dev_kfree_skb_irq instead of kfree_skb in
+      rtl_pci_reset_trx_ring
+    - aacraid: Relinquish CPU during timeout wait
+    - aacraid: Fix for aac_command_thread hang
+    - aacraid: Fix for KDUMP driver hang
+    - hwmon: (ads7828) Enable internal reference
+    - mfd: intel-lpss: Save register context on suspend
+    - mfd: intel_soc_pmic_core: Terminate panel control GPIO lookup table
+      correctly
+    - PM / Runtime: Fix error path in pm_runtime_force_resume()
+    - cpuidle: Indicate when a device has been unregistered
+    - cpuidle: Fix cpuidle_state_is_coupled() argument in cpuidle_enter()
+    - clk: bcm2835: Fix PLL poweron
+    - clk: at91: fix check of clk_register() returned value
+    - clk: bcm2835: pll_off should only update CM_PLL_ANARST
+    - clk: bcm2835: divider value has to be 1 or more
+    - pinctrl: exynos5440: Use off-stack memory for pinctrl_gpio_range
+    - PCI: Disable all BAR sizing for devices with non-compliant BARs
+    - media: v4l2-compat-ioctl32: fix missing reserved field copy in
+      put_v4l2_create32
+    - mm: use phys_addr_t for reserve_bootmem_region() arguments
+    - wait/ptrace: assume __WALL if the child is traced
+    - QE-UART: add "fsl,t1040-ucc-uart" to of_device_id
+    - powerpc/book3s64: Fix branching to OOL handlers in relocatable kernel
+    - powerpc/eeh: Don't report error in eeh_pe_reset_and_recover()
+    - powerpc/eeh: Restore initial state in eeh_pe_reset_and_recover()
+    - xen/events: Don't move disabled irqs
+    - xen: use same main loop for counting and remapping pages
+    - sunrpc: fix stripping of padded MIC tokens
+    - drm/gma500: Fix possible out of bounds read
+    - drm/vmwgfx: Enable SVGA_3D_CMD_DX_SET_PREDICATION
+    - drm/vmwgfx: use vmw_cmd_dx_cid_check for query commands.
+    - drm/vmwgfx: Fix order of operation
+    - drm/amdgpu: use drm_mode_vrefresh() rather than mode->vrefresh
+    - drm/amdgpu: Fix hdmi deep color support.
+    - drm/i915/fbdev: Fix num_connector references in intel_fb_initial_config()
+    - drm/fb_helper: Fix references to dev->mode_config.num_connector
+    - drm/atomic: Verify connector->funcs != NULL when clearing states
+    - drm/i915: Don't leave old junk in ilk active watermarks on readout
+    - drm/imx: Match imx-ipuv3-crtc components using device node in platform data
+    - ext4: fix hang when processing corrupted orphaned inode list
+    - ext4: clean up error handling when orphan list is corrupted
+    - ext4: fix oops on corrupted filesystem
+    - ext4: address UBSAN warning in mb_find_order_for_block()
+    - ext4: silence UBSAN in ext4_mb_init()
+    - PM / sleep: Handle failures in device_suspend_late() consistently
+    - dma-debug: avoid spinlock recursion when disabling dma-debug
+    - scripts/package/Makefile: rpmbuild add support of RPMOPTS
+    - gcov: disable tree-loop-im to reduce stack usage
+    - xfs: disallow rw remount on fs with unknown ro-compat features
+    - xfs: Don't wrap growfs AGFL indexes
+    - xfs: xfs_iflush_cluster fails to abort on error
+    - xfs: fix inode validity check in xfs_iflush_cluster
+    - xfs: skip stale inodes in xfs_iflush_cluster
+    - xfs: print name of verifier if it fails
+    - xfs: handle dquot buffer readahead in log recovery correctly
+    - Linux 4.4.13
+
+  * 168c:001c [HP Compaq Presario C700 Notebook PC] Wireless led button doesn't
+    switch colors (LP: #972604)
+    - ath5k: Change led pin configuration for compaq c700 laptop
+
+  * Extended statistics from balloon for proper memory management (LP: #1587091)
+    - mm/page_alloc.c: calculate 'available' memory in a separate function
+    - virtio_balloon: export 'available' memory to balloon statistics
+
+  * CAPI: CGZIP AFU contexts do not receive interrupts after heavy afu
+    open/close (LP: #1588468)
+    - misc: cxl: use kobj_to_dev()
+    - cxl: Move common code away from bare-metal-specific files
+    - cxl: Move bare-metal specific code to specialized files
+    - cxl: Define process problem state area at attach time only
+    - cxl: Introduce implementation-specific API
+    - cxl: Rename some bare-metal specific functions
+    - cxl: Isolate a few bare-metal-specific calls
+    - cxl: Update cxl_irq() prototype
+    - cxl: IRQ allocation for guests
+    - powerpc: New possible return value from hcall
+    - cxl: New hcalls to support cxl adapters
+    - cxl: Separate bare-metal fields in adapter and AFU data structures
+    - cxlflash: Simplify PCI registration
+    - cxlflash: Unmap problem state area before detaching master context
+    - cxlflash: Split out context initialization
+    - cxlflash: Simplify attach path error cleanup
+    - cxlflash: Reorder user context initialization
+    - cxl: Add guest-specific code
+    - cxl: sysfs support for guests
+    - cxl: Support to flash a new image on the adapter from a guest
+    - cxl: Parse device tree and create cxl device(s) at boot
+    - cxl: Support the cxl kernel API from a guest
+    - cxl: Adapter failure handling
+    - cxl: Add tracepoints around the cxl hcall
+    - cxlflash: Use new cxl_pci_read_adapter_vpd() API
+    - cxl: Remove cxl_get_phys_dev() kernel API
+    - cxl: Ignore probes for virtual afu pci devices
+    - cxl: Poll for outstanding IRQs when detaching a context
+
+  * NVMe max_segments queue parameter gets set to 1 (LP: #1588449)
+    - nvme: set queue limits for the admin queue
+    - nvme: fix max_segments integer truncation
+    - block: fix blk_rq_get_max_sectors for driver private requests
+
+  * workaround cavium thunderx silicon erratum 23144 (LP: #1589704)
+    - irqchip/gicv3-its: numa: Enable workaround for Cavium thunderx erratum 23144
+
+  * Xenial update to v4.4.12 stable release (LP: #1588945)
+    - Btrfs: don't use src fd for printk
+    - perf/x86/intel/pt: Generate PMI in the STOP region as well
+    - perf/core: Fix perf_event_open() vs. execve() race
+    - perf test: Fix build of BPF and LLVM on older glibc libraries
+    - ext4: iterate over buffer heads correctly in move_extent_per_page()
+    - arm64: Fix typo in the pmdp_huge_get_and_clear() definition
+    - arm64: Ensure pmd_present() returns false after pmd_mknotpresent()
+    - arm64: Implement ptep_set_access_flags() for hardware AF/DBM
+    - arm64: Implement pmdp_set_access_flags() for hardware AF/DBM
+    - arm64: cpuinfo: Missing NULL terminator in compat_hwcap_str
+    - arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables
+    - kvm: arm64: Fix EC field in inject_abt64
+    - remove directory incorrectly tries to set delete on close on non-empty
+      directories
+    - fs/cifs: correctly to anonymous authentication via NTLMSSP
+    - fs/cifs: correctly to anonymous authentication for the LANMAN authentication
+    - fs/cifs: correctly to anonymous authentication for the NTLM(v1)
+      authentication
+    - fs/cifs: correctly to anonymous authentication for the NTLM(v2)
+      authentication
+    - asix: Fix offset calculation in asix_rx_fixup() causing slow transmissions
+    - ring-buffer: Use long for nr_pages to avoid overflow failures
+    - ring-buffer: Prevent overflow of size in ring_buffer_resize()
+    - crypto: caam - fix caam_jr_alloc() ret code
+    - crypto: talitos - fix ahash algorithms registration
+    - crypto: sun4i-ss - Replace spinlock_bh by spin_lock_irq{save|restore}
+    - clk: qcom: msm8916: Fix crypto clock flags
+    - sched/loadavg: Fix loadavg artifacts on fully idle and on fully loaded
+      systems
+    - mfd: omap-usb-tll: Fix scheduling while atomic BUG
+    - Input: pwm-beeper - fix - scheduling while atomic
+    - irqchip/gic: Ensure ordering between read of INTACK and shared data
+    - irqchip/gic-v3: Configure all interrupts as non-secure Group-1
+    - can: fix handling of unmodifiable configuration options
+    - mmc: mmc: Fix partition switch timeout for some eMMCs
+    - mmc: sdhci-acpi: Remove MMC_CAP_BUS_WIDTH_TEST for Intel controllers
+    - ACPI / osi: Fix an issue that acpi_osi=!* cannot disable ACPICA internal
+      strings
+    - dell-rbtn: Ignore ACPI notifications if device is suspended
+    - mmc: longer timeout for long read time quirk
+    - mmc: sdhci-pci: Remove MMC_CAP_BUS_WIDTH_TEST for Intel controllers
+    - Bluetooth: vhci: fix open_timeout vs. hdev race
+    - Bluetooth: vhci: purge unhandled skbs
+    - Bluetooth: vhci: Fix race at creating hci device
+    - mei: fix NULL dereferencing during FW initiated disconnection
+    - mei: amthif: discard not read messages
+    - mei: bus: call mei_cl_read_start under device lock
+    - USB: serial: mxuport: fix use-after-free in probe error path
+    - USB: serial: keyspan: fix use-after-free in probe error path
+    - USB: serial: quatech2: fix use-after-free in probe error path
+    - USB: serial: io_edgeport: fix memory leaks in attach error path
+    - USB: serial: io_edgeport: fix memory leaks in probe error path
+    - USB: serial: option: add support for Cinterion PH8 and AHxx
+    - USB: serial: option: add more ZTE device ids
+    - USB: serial: option: add even more ZTE device ids
+    - usb: gadget: f_fs: Fix EFAULT generation for async read operations
+    - usb: f_mass_storage: test whether thread is running before starting another
+    - usb: misc: usbtest: fix pattern tests for scatterlists.
+    - usb: gadget: udc: core: Fix argument of dev_err() in
+      usb_gadget_map_request()
+    - staging: comedi: das1800: fix possible NULL dereference
+    - KVM: x86: fix ordering of cr0 initialization code in vmx_cpu_reset
+    - MIPS: KVM: Fix timer IRQ race when freezing timer
+    - MIPS: KVM: Fix timer IRQ race when writing CP0_Compare
+    - KVM: x86: mask CPUID(0xD,0x1).EAX against host value
+    - xen/x86: actually allocate legacy interrupts on PV guests
+    - tty: vt, return error when con_startup fails
+    - TTY: n_gsm, fix false positive WARN_ON
+    - tty/serial: atmel: fix hardware handshake selection
+    - Fix OpenSSH pty regression on close
+    - serial: 8250_pci: fix divide error bug if baud rate is 0
+    - serial: 8250_mid: use proper bar for DNV platform
+    - serial: 8250_mid: recognize interrupt source in handler
+    - serial: samsung: Reorder the sequence of clock control when call
+      s3c24xx_serial_set_termios()
+    - locking,qspinlock: Fix spin_is_locked() and spin_unlock_wait()
+    - clk: bcm2835: add locking to pll*_on/off methods
+    - mcb: Fixed bar number assignment for the gdd
+    - ALSA: hda/realtek - New codecs support for ALC234/ALC274/ALC294
+    - ALSA: hda - Fix headphone noise on Dell XPS 13 9360
+    - ALSA: hda/realtek - Add support for ALC295/ALC3254
+    - ALSA: hda - Fix headset mic detection problem for one Dell machine
+    - IB/srp: Fix a debug kernel crash
+    - thunderbolt: Fix double free of drom buffer
+    - SIGNAL: Move generic copy_siginfo() to signal.h
+    - UBI: Fix static volume checks when Fastmap is used
+    - hpfs: fix remount failure when there are no options changed
+    - hpfs: implement the show_options method
+    - scsi: Add intermediate STARGET_REMOVE state to scsi_target_state
+    - Revert "scsi: fix soft lockup in scsi_remove_target() on module removal"
+    - kbuild: move -Wunused-const-variable to W=1 warning level
+    - Linux 4.4.12
+
+  * [Hyper-V] fixes for kdump when running on a VM (LP: #1588965)
+    - clocksource: Allow unregistering the watchdog
+
+  * net_admin apparmor denial when using Go (LP: #1465724)
+    - SAUCE: kernel: Add noaudit variant of ns_capable()
+    - SAUCE: net: Use ns_capable_noaudit() when determining net sysctl permissions
+
+  * [Hyper-V] Put tools/hv/lsvmbus in /usr/sbin (LP: #1585311)
+    - [Debian] Install lsvmbus in cloud tools
+    - SAUCE: tools/hv/lsvmbus -- convert to python3
+    - SAUCE: tools/hv/lsvmbus -- add manual page
+
+  * btrfs: file write crashes with false ENOSPC during snapshot creation since
+    kernel 4.4 - fix available (LP: #1584052)
+    - btrfs: Continue write in case of can_not_nocow
+
+  * boot stalls on USB detection errors (LP: #1437492)
+    - usb: core: hub: hub_port_init lock controller instead of bus
+
+  * [Bug]KNL:Spread MWAIT cache lines over all nodes (LP: #1585850)
+    - kernek/fork.c: allocate idle task for a CPU always on its local node
+
+  * [Hyper-V] PCI Passthrough kernel hang and explicit barriers (LP: #1581243)
+    - PCI: hv: Report resources release after stopping the bus
+    - PCI: hv: Add explicit barriers to config space access
+
+  * Kernel 4.2.X and 4.4.X - Fix USB3.0 link power management (LPM)
+    claim/release logic in USBFS (LP: #1577024)
+    - USB: leave LPM alone if possible when binding/unbinding interface drivers
+
+  * STC840.20:tuleta:tul516p01 panic after injecting Leaf EEH (LP: #1581034)
+    - NVMe: Fix namespace removal deadlock
+    - NVMe: Requeue requests on suspended queues
+    - NVMe: Move error handling to failed reset handler
+    - blk-mq: End unstarted requests on dying queue
+
+  * conflicting modules in udebs - arc4.ko (LP: #1582991)
+    - [Config] Remove arc4 from nic-modules
+
+  * CVE-2016-4482 (LP: #1578493)
+    - USB: usbfs: fix potential infoleak in devio
+
+  * mlx5_core kexec fail  (LP: #1585978)
+    - net/mlx5: Add pci shutdown callback
+
+  * backport fix for /proc/net issues with containers (LP: #1584953)
+    - netfilter: Set /proc/net entries owner to root in namespace
+
+  * CVE-2016-4951 (LP: #1585365)
+    - tipc: check nl sock before parsing nested attributes
+
+  * CVE-2016-4578 (LP: #1581866)
+    - ALSA: timer: Fix leak in events via snd_timer_user_ccallback
+    - ALSA: timer: Fix leak in events via snd_timer_user_tinterrupt
+
+  * CVE-2016-4569 (LP: #1580379)
+    - ALSA: timer: Fix leak in SNDRV_TIMER_IOCTL_PARAMS
+
+  * s390/pci: fix use after free in dma_init (LP: #1584828)
+    - s390/pci: fix use after free in dma_init
+
+  * s390/mm: fix asce_bits handling with dynamic pagetable levels (LP: #1584827)
+    - s390/mm: fix asce_bits handling with dynamic pagetable levels
+
+  * CAPI: CGZIP Wrong CAPI MMIO timeout (256usec desired but 1usec default
+    setting in cxl.ko driver) (LP: #1584066)
+    - powerpc: Define PVR value for POWER8NVL processor
+    - cxl: Configure the PSL for two CAPI ports on POWER8NVL
+    - cxl: Increase timeout for detection of AFU mmio hang
+
+  * ThunderX: soft lockup in cursor_timer_handler() (LP: #1574814)
+    - SAUCE: tty: vt: Fix soft lockup in fbcon cursor blink timer.
+
+  * debian.master/.../getabis bogus warnings "inconsistant compiler versions"
+    and "not a git repository" (LP: #1584890)
+    - [debian] getabis: Only git add $abidir if running in local repo
+    - [debian] getabis: Fix inconsistent compiler versions check
+
+  * Backport cxlflash patch related to EEH recovery into Xenial SRU stream
+    (LP: #1584935)
+    - cxlflash: Fix to resolve dead-lock during EEH recovery
+
+  * Xenial update to 4.4.11 stable release (LP: #1584912)
+    - decnet: Do not build routes to devices without decnet private data.
+    - route: do not cache fib route info on local routes with oif
+    - packet: fix heap info leak in PACKET_DIAG_MCLIST sock_diag interface
+    - net: sched: do not requeue a NULL skb
+    - bpf/verifier: reject invalid LD_ABS | BPF_DW instruction
+    - cdc_mbim: apply "NDP to end" quirk to all Huawei devices
+    - net: use skb_postpush_rcsum instead of own implementations
+    - vlan: pull on __vlan_insert_tag error path and fix csum correction
+    - openvswitch: use flow protocol when recalculating ipv6 checksums
+    - ipv4/fib: don't warn when primary address is missing if in_dev is dead
+    - net/mlx4_en: fix spurious timestamping callbacks
+    - bpf: fix check_map_func_compatibility logic
+    - samples/bpf: fix trace_output example
+    - net: Implement net_dbg_ratelimited() for CONFIG_DYNAMIC_DEBUG case
+    - gre: do not pull header in ICMP error processing
+    - net_sched: introduce qdisc_replace() helper
+    - net_sched: update hierarchical backlog too
+    - sch_htb: update backlog as well
+    - sch_dsmark: update backlog as well
+    - netem: Segment GSO packets on enqueue
+    - net: fec: only clear a queue's work bit if the queue was emptied
+    - VSOCK: do not disconnect socket when peer has shutdown SEND only
+    - net: bridge: fix old ioctl unlocked net device walk
+    - bridge: fix igmp / mld query parsing
+    - uapi glibc compat: fix compile errors when glibc net/if.h included before
+      linux/if.h MIME-Version: 1.0
+    - net: fix a kernel infoleak in x25 module
+    - net: thunderx: avoid exposing kernel stack
+    - tcp: refresh skb timestamp at retransmit time
+    - net/route: enforce hoplimit max value
+    - ocfs2: revert using ocfs2_acl_chmod to avoid inode cluster lock hang
+    - ocfs2: fix posix_acl_create deadlock
+    - zsmalloc: fix zs_can_compact() integer overflow
+    - crypto: qat - fix invalid pf2vf_resp_wq logic
+    - crypto: hash - Fix page length clamping in hash walk
+    - crypto: testmgr - Use kmalloc memory for RSA input
+    - ALSA: usb-audio: Quirk for yet another Phoenix Audio devices (v2)
+    - ALSA: usb-audio: Yet another Phoneix Audio device quirk
+    - ALSA: hda - Fix subwoofer pin on ASUS N751 and N551
+    - ALSA: hda - Fix white noise on Asus UX501VW headset
+    - ALSA: hda - Fix broken reconfig
+    - spi: pxa2xx: Do not detect number of enabled chip selects on Intel SPT
+    - spi: spi-ti-qspi: Fix FLEN and WLEN settings if bits_per_word is overridden
+    - spi: spi-ti-qspi: Handle truncated frames properly
+    - pinctrl: at91-pio4: fix pull-up/down logic
+    - regmap: spmi: Fix regmap_spmi_ext_read in multi-byte case
+    - perf/core: Disable the event on a truncated AUX record
+    - vfs: add vfs_select_inode() helper
+    - vfs: rename: check backing inode being equal
+    - ARM: dts: at91: sam9x5: Fix the memory range assigned to the PMC
+    - workqueue: fix rebind bound workers warning
+    - regulator: s2mps11: Fix invalid selector mask and voltages for buck9
+    - regulator: axp20x: Fix axp22x ldo_io voltage ranges
+    - atomic_open(): fix the handling of create_error
+    - qla1280: Don't allocate 512kb of host tags
+    - tools lib traceevent: Do not reassign parg after collapse_tree()
+    - get_rock_ridge_filename(): handle malformed NM entries
+    - Input: max8997-haptic - fix NULL pointer dereference
+    - Revert "[media] videobuf2-v4l2: Verify planes array in buffer dequeueing"
+    - drm/radeon: fix PLL sharing on DCE6.1 (v2)
+    - drm/i915: Bail out of pipe config compute loop on LPT
+    - drm/i915/bdw: Add missing delay during L3 SQC credit programming
+    - drm/radeon: fix DP link training issue with second 4K monitor
+    - nf_conntrack: avoid kernel pointer value leak in slab name
+    - Linux 4.4.11
+
+  * Support Edge Gateway's Bluetooth LED (LP: #1512999)
+    - SAUCE: Bluetooth: Support for LED on Marvell modules
+
+  * Support Edge Gateway's WIFI LED (LP: #1512997)
+    - SAUCE: mwifiex: Switch WiFi LED state according to the device status
+
+  * Marvell wireless driver update for FCC regulation (LP: #1528910)
+    - mwifiex: parse adhoc start/join result
+    - mwifiex: handle start AP error paths correctly
+    - mwifiex: set regulatory info from EEPROM
+    - mwifiex: don't follow AP if country code received from EEPROM
+    - mwifiex: correction in region code to country mapping
+    - mwifiex: update region_code_index array
+    - mwifiex: use world for unidentified region code
+    - SAUCE: mwifiex: add iw vendor command support
+
+  * Kernel can be oopsed using remap_file_pages (LP: #1558120)
+    - Revert "UBUNTU: SAUCE: mm/mmap: fix oopsing on remap_file_pages"
+    - SAUCE: AUFS: mm/mmap: fix oopsing on remap_file_pages aufs mmap: bugfix,
+      mainly for linux-4.5-rc5, remap_file_pages(2) emulation
+
+  * cgroup namespace update (LP: #1584163)
+    - Revert "UBUNTU: SAUCE: cgroup mount: ignore nsroot="
+    - Revert "UBUNTU: SAUCE: (noup) cgroup namespaces: add a 'nsroot=' mountinfo
+      field"
+    - cgroup, kernfs: make mountinfo show properly scoped path for cgroup
+      namespaces
+    - kernfs: kernfs_sop_show_path: don't return 0 after seq_dentry call
+    - cgroup: fix compile warning
+
+  * Missing libunwind support in perf (LP: #1248289)
+    - [Config] add binutils-dev to the Build-Depends: to fix perf unwinding
+
+  * e1000 Tx Unit Hang  (LP: #1582328)
+    - e1000: Double Tx descriptors needed check for 82544
+    - e1000: Do not overestimate descriptor counts in Tx pre-check
+
+  * Unsharing user and ipc namespaces simultaneously makes mqueue unmountable
+    (LP: #1582378)
+    - SAUCE: (namespace) mqueue: Super blocks must be owned by the user ns which
+      owns the ipc ns
+
+  * Pull in the amdgpu/radeon code from Linux 4.5.3 (LP: #1580526)
+    - drm/radeon: rework fbdev handling on chips with no connectors
+    - drm/radeon/mst: fix regression in lane/link handling.
+    - drm/amd/powerplay: add uvd/vce dpm enabling flag to fix the performance
+      issue for CZ
+    - drm/amd/powerplay: fix segment fault issue in multi-display case.
+    - drm/ttm: fix kref count mess in ttm_bo_move_to_lru_tail
+
+  * aufs CONFIG_AUFS_EXPORT build option should be enabled (LP: #1121699)
+    - [Config] enable CONFIG_AUFS_EXPORT
+
+  * promote *_diag modules from linux-image-extra to linux-image (LP: #1580355)
+    - [Config] Update inclusion list for CRIU
+
+  * [Xenial] net: updates to ethtool and virtio_net for speed/duplex support
+    (LP: #1581132)
+    - ethtool: add speed/duplex validation functions
+    - ethtool: make validate_speed accept all speeds between 0 and INT_MAX
+    - virtio_net: add ethtool support for set and get of settings
+    - virtio_net: validate ethtool port setting and explain the user validation
+
+  * perf tool: Display event codes for Generic HW (PMU) events (LP: #1578211)
+    - powerpc/perf: Remove PME_ prefix for power7 events
+    - powerpc/perf: Export Power8 generic and cache events to sysfs
+
+  * Mellanox ConnectX4 MTU limits: max and min (LP: #1528466)
+    - net/mlx5: Introduce a new header file for physical port functions
+    - net/mlx5e: Device's mtu field is u16 and not int
+    - net/mlx5e: Fix minimum MTU
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_CAVIUM_ERRATUM_23144=y
+
+ -- Kamal Mostafa <kamal@canonical.com>  Fri, 10 Jun 2016 10:07:13 -0700
+
+linux (4.4.0-24.43) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * CVE-2016-1583 (LP: #1588871)
+    - ecryptfs: fix handling of directory opening
+    - SAUCE: proc: prevent stacking filesystems on top
+    - SAUCE: ecryptfs: forbid opening files without mmap handler
+    - SAUCE: sched: panic on corrupted stack end
+
+  * arm64: statically link rtc-efi (LP: #1583738)
+    - [Config] Link rtc-efi statically on arm64
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 08 Jun 2016 20:01:12 +0100
+
+linux (4.4.0-23.41) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1582431
+
+  * zfs: disable module checks for zfs when cross-compiling (LP: #1581127)
+    - [Packaging] disable zfs module checks when cross-compiling
+
+  * Xenial update to v4.4.10 stable release (LP: #1580754)
+    - Revert "UBUNTU: SAUCE: (no-up) ACPICA: Dispatcher: Update thread ID for
+      recursive method calls"
+    - Revert "UBUNTU: SAUCE: nbd: ratelimit error msgs after socket close"
+    - Revert: "powerpc/tm: Check for already reclaimed tasks"
+    - RDMA/iw_cxgb4: Fix bar2 virt addr calculation for T4 chips
+    - ipvs: handle ip_vs_fill_iph_skb_off failure
+    - ipvs: correct initial offset of Call-ID header search in SIP persistence
+      engine
+    - ipvs: drop first packet to redirect conntrack
+    - mfd: intel-lpss: Remove clock tree on error path
+    - nbd: ratelimit error msgs after socket close
+    - ata: ahci_xgene: dereferencing uninitialized pointer in probe
+    - mwifiex: fix corner case association failure
+    - CNS3xxx: Fix PCI cns3xxx_write_config()
+    - clk-divider: make sure read-only dividers do not write to their register
+    - soc: rockchip: power-domain: fix err handle while probing
+    - clk: rockchip: free memory in error cases when registering clock branches
+    - clk: meson: Fix meson_clk_register_clks() signature type mismatch
+    - clk: qcom: msm8960: fix ce3_core clk enable register
+    - clk: versatile: sp810: support reentrance
+    - clk: qcom: msm8960: Fix ce3_src register offset
+    - lpfc: fix misleading indentation
+    - ath9k: ar5008_hw_cmn_spur_mitigate: add missing mask_m & mask_p
+      initialisation
+    - mac80211: fix statistics leak if dev_alloc_name() fails
+    - tracing: Don't display trigger file for events that can't be enabled
+    - MD: make bio mergeable
+    - Minimal fix-up of bad hashing behavior of hash_64()
+    - mm, cma: prevent nr_isolated_* counters from going negative
+    - mm/zswap: provide unique zpool name
+    - ARM: EXYNOS: Properly skip unitialized parent clock in power domain on
+    - ARM: SoCFPGA: Fix secondary CPU startup in thumb2 kernel
+    - xen: Fix page <-> pfn conversion on 32 bit systems
+    - xen/balloon: Fix crash when ballooning on x86 32 bit PAE
+    - xen/evtchn: fix ring resize when binding new events
+    - HID: wacom: Add support for DTK-1651
+    - HID: Fix boot delay for Creative SB Omni Surround 5.1 with quirk
+    - Input: zforce_ts - fix dual touch recognition
+    - proc: prevent accessing /proc/<PID>/environ until it's ready
+    - mm: update min_free_kbytes from khugepaged after core initialization
+    - batman-adv: fix DAT candidate selection (must use vid)
+    - batman-adv: Check skb size before using encapsulated ETH+VLAN header
+    - batman-adv: Fix broadcast/ogm queue limit on a removed interface
+    - batman-adv: Reduce refcnt of removed router when updating route
+    - writeback: Fix performance regression in wb_over_bg_thresh()
+    - MAINTAINERS: Remove asterisk from EFI directory names
+    - x86/tsc: Read all ratio bits from MSR_PLATFORM_INFO
+    - ARM: cpuidle: Pass on arm_cpuidle_suspend()'s return value
+    - ARC: Add missing io barriers to io{read,write}{16,32}be()
+    - x86/sysfb_efi: Fix valid BAR address range check
+    - ACPICA: Dispatcher: Update thread ID for recursive method calls
+    - powerpc: Fix bad inline asm constraint in create_zero_mask()
+    - libahci: save port map for forced port map
+    - ata: ahci-platform: Add ports-implemented DT bindings.
+    - USB: serial: cp210x: add ID for Link ECU
+    - USB: serial: cp210x: add Straizona Focusers device ids
+    - nvmem: mxs-ocotp: fix buffer overflow in read
+    - gpu: ipu-v3: Fix imx-ipuv3-crtc module autoloading
+    - drm/amdgpu: make sure vertical front porch is at least 1
+    - drm/amdgpu: set metadata pointer to NULL after freeing.
+    - iio: ak8975: Fix NULL pointer exception on early interrupt
+    - iio: ak8975: fix maybe-uninitialized warning
+    - drm/radeon: make sure vertical front porch is at least 1
+    - drm/i915/ddi: Fix eDP VDD handling during booting and suspend/resume
+    - drm/i915: Fix eDP low vswing for Broadwell
+    - drm/i915: Make RPS EI/thresholds multiple of 25 on SNB-BDW
+    - drm/i915: Fake HDMI live status
+    - lib/test-string_helpers.c: fix and improve string_get_size() tests
+    - drm/i915/skl: Fix DMC load on Skylake J0 and K0
+    - Linux 4.4.10
+
+  * HDMI audio playback noise  observed on AMD Polaris 10/11 GPU (LP: #1577288)
+    - ALSA: hda: add AMD Polaris-10/11 AZ PCI IDs with proper driver caps
+
+  * [i915_bpo] Update i915 backport driver (LP: #1580114)
+    - SAUCE: i915_bpo: Drop is_preliminary from BXT/KBL.
+    - SAUCE: i915_bpo: Sync with v4.6-rc7
+
+  * CVE-2016-4486 (LP: #1578497)
+    - net: fix infoleak in rtnetlink
+
+  * CVE-2016-4485 (LP: #1578496)
+    - net: fix infoleak in llc
+
+  * drm.ko < kernel version 4.5 has a dead lock bug (LP: #1579610)
+    - drm: Balance error path for GEM handle allocation
+
+  * Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: -fstack-protector-strong not
+    supported by compiler (LP: #1574982)
+    - SAUCE: (no-up) disable -pie when gcc has it enabled by default
+
+  * system freeze after vt switching (LP: #1542939)
+    - drm/atomic: Add __drm_atomic_helper_connector_reset, v2.
+    - drm/atomic: Remove drm_atomic_connectors_for_crtc.
+
+  * CVE-2016-4558 (LP: #1579140)
+    - bpf: fix refcnt overflow
+
+  * Kernel Panic on EC2 After Upgrading from 14.04 to 16.04 via do-release-
+    upgrade -d (LP: #1573231)
+    - SAUCE: (no-up) x86/topology: Handle CPUID bogosity gracefully
+
+  * PCI Call Traces  hw csum failure in dmesg with  4.4.0-2-generic
+    (LP: #1544978)
+    - net/mlx4_en: Fix endianness bug in IPV6 csum calculation
+
+  * Missing libunwind support in perf (LP: #1248289)
+    - [Config] Add liblzma-dev to enable libunwind support in perf
+
+  * thunderbolt hotplug is broken (LP: #1577898)
+    - SAUCE: (no-up) ACPICA: Dispatcher: Update thread ID for recursive method
+      calls
+
+  * Kernel can be oopsed using remap_file_pages (LP: #1558120)
+    - SAUCE: mm/mmap: fix oopsing on remap_file_pages
+
+  * ZFS is confused by user namespaces (uid/gid mapping) when used with
+    acltype=posixac (LP: #1567558)
+    - zfs: Fix user namespaces uid/gid mapping
+
+  * oops when propagating mounts into containers - RIP:
+    0010:[<ffffffff8123cb3e>] [<ffffffff8123cb3e>] propagate_one+0xbe/0x1c0
+    (LP: #1572316)
+    - fs/pnode.c: treat zero mnt_group_id-s as unequal
+    - propogate_mnt: Handle the first propogated copy being a slave
+
+  * OOPS on wily+ for Haswell-ULT and Broadwell (LP: #1577748)
+    - PNP: Add Broadwell to Intel MCH size workaround
+    - PNP: Add Haswell-ULT to Intel MCH size workaround
+
+  * Xenial update to v4.4.9 stable release (LP: #1578798)
+    - block: loop: fix filesystem corruption in case of aio/dio
+    - x86/mce: Avoid using object after free in genpool
+    - kvm: x86: do not leak guest xcr0 into host interrupt handlers
+    - ARM: dts: AM43x-epos: Fix clk parent for synctimer
+    - ARM: mvebu: Correct unit address for linksys
+    - ARM: OMAP2: Fix up interconnect barrier initialization for DRA7
+    - ARM: OMAP2+: hwmod: Fix updating of sysconfig register
+    - assoc_array: don't call compare_object() on a node
+    - usb: xhci: applying XHCI_PME_STUCK_QUIRK to Intel BXT B0 host
+    - xhci: resume USB 3 roothub first
+    - usb: xhci: fix wild pointers in xhci_mem_cleanup
+    - xhci: fix 10 second timeout on removal of PCI hotpluggable xhci controllers
+    - usb: hcd: out of bounds access in for_each_companion
+    - usb: gadget: f_fs: Fix use-after-free
+    - dm cache metadata: fix READ_LOCK macros and cleanup WRITE_LOCK macros
+    - dm cache metadata: fix cmd_read_lock() acquiring write lock
+    - lib: lz4: fixed zram with lz4 on big endian machines
+    - debugfs: Make automount point inodes permanently empty
+    - dmaengine: dw: fix master selection
+    - dmaengine: hsu: correct use of channel status register
+    - dmaengine: pxa_dma: fix the maximum requestor line
+    - sched/cgroup: Fix/cleanup cgroup teardown/init
+    - x86/mm/xen: Suppress hugetlbfs in PV guests
+    - x86 EDAC, sb_edac.c: Repair damage introduced when "fixing" channel address
+    - ALSA: hda - Don't trust the reported actual power state
+    - ALSA: hda/realtek - Add ALC3234 headset mode for Optiplex 9020m
+    - ALSA: hda - Keep powering up ADCs on Cirrus codecs
+    - ALSA: hda - add PCI ID for Intel Broxton-T
+    - ALSA: pcxhr: Fix missing mutex unlock
+    - ALSA: hda - Add dock support for ThinkPad X260
+    - asm-generic/futex: Re-enable preemption in futex_atomic_cmpxchg_inatomic()
+    - futex: Handle unlock_pi race gracefully
+    - futex: Acknowledge a new waiter in counter before plist
+    - drm/nouveau/core: use vzalloc for allocating ramht
+    - drm/qxl: fix cursor position with non-zero hotspot
+    - drm/i915: Fix race condition in intel_dp_destroy_mst_connector()
+    - Revert "drm/radeon: disable runtime pm on PX laptops without dGPU power
+      control"
+    - Revert "drm/amdgpu: disable runtime pm on PX laptops without dGPU power
+      control"
+    - cpufreq: intel_pstate: Fix processing for turbo activation ratio
+    - iwlwifi: pcie: lower the debug level for RSA semaphore access
+    - iwlwifi: mvm: fix memory leak in paging
+    - crypto: ccp - Prevent information leakage on export
+    - crypto: sha1-mb - use corrcet pointer while completing jobs
+    - crypto: talitos - fix crash in talitos_cra_init()
+    - crypto: talitos - fix AEAD tcrypt tests
+    - powerpc: scan_features() updates incorrect bits for REAL_LE
+    - powerpc: Update cpu_user_features2 in scan_features()
+    - powerpc: Update TM user feature bits in scan_features()
+    - nl80211: check netlink protocol in socket release notification
+    - netlink: don't send NETLINK_URELEASE for unbound sockets
+    - Input: pmic8xxx-pwrkey - fix algorithm for converting trigger delay
+    - xen kconfig: don't "select INPUT_XEN_KBDDEV_FRONTEND"
+    - pinctrl: mediatek: correct debounce time unit in mtk_gpio_set_debounce
+    - pinctrl: single: Fix pcs_parse_bits_in_pinctrl_entry to use __ffs than ffs
+    - iommu/amd: Fix checking of pci dma aliases
+    - iommu/dma: Restore scatterlist offsets correctly
+    - drm/amdgpu: when suspending, if uvd/vce was running. need to cancel delay
+      work.
+    - drm/amdgpu: use defines for CRTCs and AMFT blocks
+    - drm/amdgpu: bump the afmt limit for CZ, ST, Polaris
+    - amdgpu/uvd: add uvd fw version for amdgpu
+    - drm/amdgpu: fix regression on CIK (v2)
+    - drm/radeon: add a quirk for a XFX R9 270X
+    - drm/radeon: fix initial connector audio value
+    - drm/radeon: forbid mapping of userptr bo through radeon device file
+    - drm/radeon: fix vertical bars appear on monitor (v2)
+    - drm: Loongson-3 doesn't fully support wc memory
+    - drm/nouveau/gr/gf100: select a stream master to fixup tfb offset queries
+    - drm/dp/mst: Validate port in drm_dp_payload_send_msg()
+    - drm/dp/mst: Restore primary hub guid on resume
+    - drm/dp/mst: Get validated port ref in drm_dp_update_payload_part1()
+    - pwm: brcmstb: Fix check of devm_ioremap_resource() return code
+    - drm/i915: Cleanup phys status page too
+    - drm/i915: skl_update_scaler() wants a rotation bitmask instead of bit number
+    - drm/amdkfd: uninitialized variable in dbgdev_wave_control_set_registers()
+    - drm/i915: Fixup the free space logic in ring_prepare
+    - drm/i915: Use fw_domains_put_with_fifo() on HSW
+    - perf intel-pt: Fix segfault tracing transactions
+    - i2c: cpm: Fix build break due to incompatible pointer types
+    - i2c: exynos5: Fix possible ABBA deadlock by keeping I2C clock prepared
+    - toshiba_acpi: Fix regression caused by hotkey enabling value
+    - EDAC: i7core, sb_edac: Don't return NOTIFY_BAD from mce_decoder callback
+    - ASoC: s3c24xx: use const snd_soc_component_driver pointer
+    - ASoC: ssm4567: Reset device before regcache_sync()
+    - ASoC: dapm: Make sure we have a card when displaying component widgets
+    - ASoC: rt5640: Correct the digital interface data select
+    - vb2-memops: Fix over allocation of frame vectors
+    - v4l2-dv-timings.h: fix polarity for 4k formats
+    - cxl: Keep IRQ mappings on context teardown
+    - IB/mlx5: Expose correct max_sge_rd limit
+    - IB/security: Restrict use of the write() interface
+    - efi: Fix out-of-bounds read in variable_matches()
+    - efi: Expose non-blocking set_variable() wrapper to efivars
+    - x86/apic: Handle zero vector gracefully in clear_vector_irq()
+    - workqueue: fix ghost PENDING flag while doing MQ IO
+    - slub: clean up code for kmem cgroup support to kmem_cache_free_bulk
+    - cgroup, cpuset: replace cpuset_post_attach_flush() with
+      cgroup_subsys->post_attach callback
+    - memcg: relocate charge moving from ->attach to ->post_attach
+    - mm/huge_memory: replace VM_NO_THP VM_BUG_ON with actual VMA check
+    - numa: fix /proc/<pid>/numa_maps for THP
+    - mm: vmscan: reclaim highmem zone if buffer_heads is over limit
+    - mm/hwpoison: fix wrong num_poisoned_pages accounting
+    - cgroup: make sure a parent css isn't freed before its children
+    - videobuf2-core: Check user space planes array in dqbuf
+    - videobuf2-v4l2: Verify planes array in buffer dequeueing
+    - Revert "regulator: core: Fix nested locking of supplies"
+    - regulator: core: fix regulator_lock_supply regression
+    - regulator: core: Ensure we lock all regulators
+    - regulator: core: Fix nested locking of supplies
+    - locking/mcs: Fix mcs_spin_lock() ordering
+    - spi/rockchip: Make sure spi clk is on in rockchip_spi_set_cs
+    - irqchip/sunxi-nmi: Fix error check of of_io_request_and_map()
+    - irqchip/mxs: Fix error check of of_io_request_and_map()
+    - regulator: s5m8767: fix get_register() error handling
+    - paride: make 'verbose' parameter an 'int' again
+    - scsi_dh: force modular build if SCSI is a module
+    - fbdev: da8xx-fb: fix videomodes of lcd panels
+    - misc/bmp085: Enable building as a module
+    - misc: mic/scif: fix wrap around tests
+    - PM / OPP: Initialize u_volt_min/max to a valid value
+    - PM / Domains: Fix removal of a subdomain
+    - rtc: hym8563: fix invalid year calculation
+    - rtc: vr41xx: Wire up alarm_irq_enable
+    - rtc: ds1685: passing bogus values to irq_restore
+    - rtc: rx8025: remove rv8803 id
+    - rtc: max77686: Properly handle regmap_irq_get_virq() error code
+    - drivers/misc/ad525x_dpot: AD5274 fix RDAC read back errors
+    - perf evlist: Reference count the cpu and thread maps at set_maps()
+    - x86/mm/kmmio: Fix mmiotrace for hugepages
+    - ext4: fix NULL pointer dereference in ext4_mark_inode_dirty()
+    - serial: sh-sci: Remove cpufreq notifier to fix crash/deadlock
+    - mtd: spi-nor: remove micron_quad_enable()
+    - mtd: brcmnand: Fix v7.1 register offsets
+    - mtd: nand: Drop mtd.owner requirement in nand_scan
+    - perf hists browser: Only offer symbol scripting when a symbol is under the
+      cursor
+    - perf tools: handle spaces in file names obtained from /proc/pid/maps
+    - perf stat: Document --detailed option
+    - ext4: fix races between page faults and hole punching
+    - ext4: move unlocked dio protection from ext4_alloc_file_blocks()
+    - ext4: fix races between buffered IO and collapse / insert range
+    - ext4: fix races of writeback with punch hole and zero range
+    - ARM: OMAP3: Add cpuidle parameters table for omap3430
+    - ARM: prima2: always enable reset controller
+    - ARM: EXYNOS: select THERMAL_OF
+    - ARM: dts: armada-375: use armada-370-sata for SATA
+    - ARM: dts: pxa: fix dma engine node to pxa3xx-nand
+    - bus: imx-weim: Take the 'status' property value into account
+    - jme: Do not enable NIC WoL functions on S0
+    - jme: Fix device PM wakeup API usage
+    - unbreak allmodconfig KCONFIG_ALLCONFIG=...
+    - thermal: rockchip: fix a impossible condition caused by the warning
+    - sunrpc/cache: drop reference when sunrpc_cache_pipe_upcall() detects a race
+    - megaraid_sas: add missing curly braces in ioctl handler
+    - stm class: Select CONFIG_SRCU
+    - extcon: max77843: Use correct size for reading the interrupt register
+    - Linux 4.4.9
+
+  * Stoney powerplay support (LP: #1578305)
+    - amdgpu/powerplay: Add Stoney to list of early init cases
+
+  * CVE-2016-2117 (LP: #1561403)
+    - atl2: Disable unimplemented scatter/gather feature
+
+  * CVE-2016-2187 (LP: #1575706)
+    - Input: gtco - fix crash on detecting device without endpoints
+
+  * zfs posix default permissions lost on reboot or unmount (LP: #1574801)
+    - Fix ZPL miswrite of default POSIX ACL
+
+  * WARNING: at /build/linux-aWXT0l/linux-4.4.0/drivers/pci/pci.c:1595
+    [travis3EN] (LP: #1574697)
+    - net/mlx4_core: Implement pci_resume callback
+    - net/mlx4_core: Avoid repeated calls to pci enable/disable
+
+  * Add support to thinkpad keyboard backlight (LP: #1574498)
+    - thinkpad_acpi: Add support for keyboard backlight
+
+  * Please enable kconfig X86_LEGACY_VM86 for i386 (LP: #1499089)
+    - [Config] CONFIG_VM86=y, CONFIG_X86_LEGACY_VM86=y
+
+  * Miscellaneous Ubuntu changes
+    - updateconfigs for Linux v4.4.9
+
+ -- Kamal Mostafa <kamal@canonical.com>  Mon, 16 May 2016 15:16:29 -0700
+
+linux (4.4.0-22.40) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * CVE-2016-3713 (LP: #1581201)
+    - SAUCE: KVM: MTRR: remove MSR 0x2f8
+
+  * CVE-2016-0758 (LP: #1581202)
+    - SAUCE: KEYS: Fix ASN.1 indefinite length object parsing
+
+ -- Kamal Mostafa <kamal@canonical.com>  Thu, 12 May 2016 13:38:45 -0700
+
+linux (4.4.0-22.39) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1578721
+
+  * LP: #1578705
+    - bpf: fix double-fdput in replace_map_fd_with_map_ptr()
+
+ -- Kamal Mostafa <kamal@canonical.com>  Thu, 05 May 2016 09:30:58 -0700
+
+linux (4.4.0-22.38) xenial; urgency=low
+
+  [ Kamal Mostafa ]
+
+  * Release Tracking Bug
+    - LP: #1573817
+
+  * autoreconstruct: need to also generate extend-diff-ignore options for links
+    (LP: #1574362)
+    - [Packaging] autoreconstruct -- generate extend-diff-ignore for links
+
+  * tipc: missing linearization of sk_buff (LP: #1567064)
+    - tipc: move linearization of buffers to generic code
+
+  * [Hyper-V] In-flight PCI Passthrough Patches (LP: #1570124)
+    - SAUCE:(noup) drivers:hv: Lock access to hyperv_mmio resource tree
+    - SAUCE:(noup) drivers:hv: Call vmbus_mmio_free() to reverse
+      vmbus_mmio_allocate()
+    - SAUCE:(noup) drivers:hv: Reverse order of resources in hyperv_mmio
+    - SAUCE:(noup) drivers:hv: Track allocations of children of hv_vmbus in
+      private resource tree
+    - SAUCE:(noup) drivers:hv: Record MMIO range in use by frame buffer
+    - SAUCE:(noup) drivers:hv: Separate out frame buffer logic when picking MMIO
+      range
+
+  * vbox: resync with 5.0.18-dfsg-2build1 (LP: #1571156)
+    - ubuntu: vbox -- update to 5.0.18-dfsg-2build1
+
+  * CONFIG_AUFS_XATTR is not set (LP: #1557776)
+    - [Config] CONFIG_AUFS_XATTR=y
+
+  * CVE-2016-3672 (LP: #1568523)
+    - x86/mm/32: Enable full randomization on i386 and X86_32
+
+  * CVE-2016-3955 (LP: #1572666)
+    - USB: usbip: fix potential out-of-bounds write
+
+  * Xenial update to v4.4.8 stable release (LP: #1573034)
+    - hwmon: (max1111) Return -ENODEV from max1111_read_channel if not
+      instantiated
+    - PKCS#7: pkcs7_validate_trust(): initialize the _trusted output argument
+    - parisc: Avoid function pointers for kernel exception routines
+    - parisc: Fix kernel crash with reversed copy_from_user()
+    - parisc: Unbreak handling exceptions from kernel modules
+    - ALSA: timer: Use mod_timer() for rearming the system timer
+    - ALSA: hda - Asus N750JV external subwoofer fixup
+    - ALSA: hda - Fix white noise on Asus N750JV headphone
+    - ALSA: hda - Apply fix for white noise on Asus N550JV, too
+    - mm: fix invalid node in alloc_migrate_target()
+    - powerpc/mm: Fixup preempt underflow with huge pages
+    - libnvdimm: fix smart data retrieval
+    - libnvdimm, pfn: fix uuid validation
+    - compiler-gcc: disable -ftracer for __noclone functions
+    - arm64: opcodes.h: Add arm big-endian config options before including arm
+      header
+    - drm/dp: move hw_mutex up the call stack
+    - drm/udl: Use unlocked gem unreferencing
+    - drm/radeon: add a dpm quirk for sapphire Dual-X R7 370 2G D5
+    - drm/radeon: add another R7 370 quirk
+    - drm/radeon: add a dpm quirk for all R7 370 parts
+    - drm/amdgpu/gmc: move vram type fetching into sw_init
+    - drm/amdgpu/gmc: use proper register for vram type on Fiji
+    - xen/events: Mask a moving irq
+    - tcp: convert cached rtt from usec to jiffies when feeding initial rto
+    - tunnel: Clear IPCB(skb)->opt before dst_link_failure called
+    - net: jme: fix suspend/resume on JMC260
+    - net: vrf: Remove direct access to skb->data
+    - net: qca_spi: Don't clear IFF_BROADCAST
+    - net: qca_spi: clear IFF_TX_SKB_SHARING
+    - net: fix bridge multicast packet checksum validation
+    - sctp: lack the check for ports in sctp_v6_cmp_addr
+    - mld, igmp: Fix reserved tailroom calculation
+    - tipc: Revert "tipc: use existing sk_write_queue for outgoing packet chain"
+    - qmi_wwan: add Sierra Wireless EM74xx device ID
+    - ipv6: re-enable fragment header matching in ipv6_find_hdr
+    - vxlan: fix missing options_len update on RX with collect metadata
+    - cdc_ncm: toggle altsetting to force reset before setup
+    - udp6: fix UDP/IPv6 encap resubmit path
+    - tcp: fix tcpi_segs_in after connection establishment
+    - ppp: release rtnl mutex when interface creation fails
+    - net: validate variable length ll headers
+    - ax25: add link layer header validation function
+    - packet: validate variable length ll headers
+    - bpf: avoid copying junk bytes in bpf_get_current_comm()
+    - sh_eth: fix NULL pointer dereference in sh_eth_ring_format()
+    - sh_eth: advance 'rxdesc' later in sh_eth_ring_format()
+    - qlcnic: Remove unnecessary usage of atomic_t
+    - qlcnic: Fix mailbox completion handling during spurious interrupt
+    - macvtap: always pass ethernet header in linear
+    - mlxsw: spectrum: Check requested ageing time is valid
+    - rocker: set FDB cleanup timer according to lowest ageing time
+    - bridge: allow zero ageing time
+    - ipv4: Don't do expensive useless work during inetdev destroy.
+    - net: Fix use after free in the recvmmsg exit path
+    - mlx4: add missing braces in verify_qp_parameters
+    - farsync: fix off-by-one bug in fst_add_one
+    - ath9k: fix buffer overrun for ar9287
+    - ppp: ensure file->private_data can't be overridden
+    - tcp/dccp: remove obsolete WARN_ON() in icmp handlers
+    - qlge: Fix receive packets drop.
+    - net: bcmgenet: fix dma api length mismatch
+    - bonding: fix bond_get_stats()
+    - ipv4: fix broadcast packets reception
+    - ipv4: initialize flowi4_flags before calling fib_lookup()
+    - ppp: take reference on channels netns
+    - xfrm: Fix crash observed during device unregistration and decryption
+    - qmi_wwan: add "D-Link DWM-221 B1" device id
+    - ipv6: udp: fix UDP_MIB_IGNOREDMULTI updates
+    - bridge: Allow set bridge ageing time when switchdev disabled
+    - rtnl: fix msg size calculation in if_nlmsg_size()
+    - tun, bpf: fix suspicious RCU usage in tun_{attach, detach}_filter
+    - tuntap: restore default qdisc
+    - ipv4: l2tp: fix a potential issue in l2tp_ip_recv
+    - ipv6: l2tp: fix a potential issue in l2tp_ip6_recv
+    - ip6_tunnel: set rtnl_link_ops before calling register_netdevice
+    - ipv6: Count in extension headers in skb->network_header
+    - mpls: find_outdev: check for err ptr in addition to NULL check
+    - USB: uas: Limit qdepth at the scsi-host level
+    - USB: uas: Add a new NO_REPORT_LUNS quirk
+    - cdc-acm: fix NULL pointer reference
+    - KVM: x86: Inject pending interrupt even if pending nmi exist
+    - KVM: x86: reduce default value of halt_poll_ns parameter
+    - MIPS: Fix MSA ld unaligned failure cases
+    - pinctrl: pistachio: fix mfio84-89 function description and pinmux.
+    - pinctrl: sh-pfc: only use dummy states for non-DT platforms
+    - pinctrl: sunxi: Fix A33 external interrupts not working
+    - pinctrl: nomadik: fix pull debug print inversion
+    - pinctrl: freescale: imx: fix bogus check of of_iomap() return value
+    - au0828: fix au0828_v4l2_close() dev_state race condition
+    - au0828: Fix dev_state handling
+    - coda: fix error path in case of missing pdata on non-DT platform
+    - v4l: vsp1: Set the SRU CTRL0 register when starting the stream
+    - pcmcia: db1xxx_ss: fix last irq_to_gpio user
+    - rbd: use GFP_NOIO consistently for request allocations
+    - virtio: virtio 1.0 cs04 spec compliance for reset
+    - mac80211: properly deal with station hashtable insert errors
+    - mac80211: avoid excessive stack usage in sta_info
+    - mac80211: fix ibss scan parameters
+    - mac80211: fix unnecessary frame drops in mesh fwding
+    - mac80211: fix txq queue related crashes
+    - usb: renesas_usbhs: avoid NULL pointer derefernce in usbhsf_pkt_handler()
+    - usb: renesas_usbhs: disable TX IRQ before starting TX DMAC transfer
+    - usb: renesas_usbhs: fix to avoid using a disabled ep in usbhsg_queue_done()
+    - iio: st_magn: always define ST_MAGN_TRIGGER_SET_STATE
+    - iio: accel: bmc150: fix endianness when reading axes
+    - iio: gyro: bmg160: fix buffer read values
+    - iio: gyro: bmg160: fix endianness when reading axes
+    - sd: Fix excessive capacity printing on devices with blocks bigger than 512
+      bytes
+    - fs: add file_dentry()
+    - nfs: use file_dentry()
+    - btrfs: fix crash/invalid memory access on fsync when using overlayfs
+    - ext4: add lockdep annotations for i_data_sem
+    - ext4: ignore quota mount options if the quota feature is enabled
+    - iommu: Don't overwrite domain pointer when there is no default_domain
+    - Btrfs: fix file/data loss caused by fsync after rename and new inode
+    - arm64: replace read_lock to rcu lock in call_step_hook
+    - perf: Do not double free
+    - perf: Cure event->pending_disable race
+    - mmc: sdhci-pci: Add support and PCI IDs for more Broxton host controllers
+    - ALSA: hda - Fixup speaker pass-through control for nid 0x14 on ALC225
+    - ALSA: hda - Fix headset support and noise on HP EliteBook 755 G2
+    - ALSA: hda/realtek - Enable the ALC292 dock fixup on the Thinkpad T460s
+    - ALSA: usb-audio: Add a sample rate quirk for Phoenix Audio TMX320
+    - ALSA: usb-audio: Add a quirk for Plantronics BT300
+    - ALSA: usb-audio: Skip volume controls triggers hangup on Dell USB Dock
+    - HID: wacom: fix Bamboo ONE oops
+    - HID: usbhid: fix inconsistent reset/resume/reset-resume behavior
+    - Revert "x86/PCI: Don't alloc pcibios-irq when MSI is enabled"
+    - Revert "PCI: Add helpers to manage pci_dev->irq and pci_dev->irq_managed"
+    - Revert "PCI, x86: Implement pcibios_alloc_irq() and pcibios_free_irq()"
+    - staging: android: ion: Set the length of the DMA sg entries in buffer
+    - usbvision: fix crash on detecting device with invalid configuration
+    - Revert "usb: hub: do not clear BOS field during reset device"
+    - Linux 4.4.8
+
+  * Fix speaker volume on a Dell machine (LP: #1549660)
+    - ALSA: hda - Fixup speaker pass-through control for nid 0x14 on ALC225
+
+  * Xenial update to v4.4.7 stable release (LP: #1572722)
+    - regulator: core: avoid unused variable warning
+    - regulator: core: Fix nested locking of supplies
+    - ASoC: samsung: pass DMA channels as pointers
+    - mmc: sh_mmcif: rework dma channel handling
+    - mmc: sh_mmcif: Correct TX DMA channel allocation
+    - x86/microcode/intel: Make early loader look for builtin microcode too
+    - x86/microcode: Untangle from BLK_DEV_INITRD
+    - x86/entry/compat: Keep TS_COMPAT set during signal delivery
+    - perf/x86/intel: Add definition for PT PMI bit
+    - x86/PCI: Mark Broadwell-EP Home Agent & PCU as having non-compliant BARs
+    - KVM: i8254: change PIT discard tick policy
+    - KVM: fix spin_lock_init order on x86
+    - KVM: VMX: avoid guest hang on invalid invept instruction
+    - KVM: VMX: avoid guest hang on invalid invvpid instruction
+    - KVM: VMX: fix nested vpid for old KVM guests
+    - perf/core: Fix perf_sched_count derailment
+    - perf tools: Dont stop PMU parsing on alias parse error
+    - perf tools: Fix checking asprintf return value
+    - perf tools: Fix python extension build
+    - sched/cputime: Fix steal_account_process_tick() to always return jiffies
+    - sched/preempt, sh: kmap_coherent relies on disabled preemption
+    - EDAC, amd64_edac: Shift wrapping issue in f1x_get_norm_dct_addr()
+    - s390: fix floating pointer register corruption (again)
+    - s390/cpumf: add missing lpp magic initialization
+    - pinctrl-bcm2835: Fix cut-and-paste error in "pull" parsing
+    - PCI: Disable IO/MEM decoding for devices with non-compliant BARs
+    - PCI: ACPI: IA64: fix IO port generic range check
+    - x86/irq: Cure live lock in fixup_irqs()
+    - x86/apic: Fix suspicious RCU usage in smp_trace_call_function_interrupt()
+    - x86/iopl/64: Properly context-switch IOPL on Xen PV
+    - x86/iopl: Fix iopl capability check on Xen PV
+    - x86/mm: TLB_REMOTE_SEND_IPI should count pages
+    - sg: fix dxferp in from_to case
+    - aacraid: Fix RRQ overload
+    - aacraid: Fix memory leak in aac_fib_map_free
+    - aacraid: Set correct msix count for EEH recovery
+    - sd: Fix discard granularity when LBPRZ=1
+    - scsi: storvsc: fix SRB_STATUS_ABORTED handling
+    - be2iscsi: set the boot_kset pointer to NULL in case of failure
+    - aic7xxx: Fix queue depth handling
+    - libnvdimm: Fix security issue with DSM IOCTL.
+    - dm snapshot: disallow the COW and origin devices from being identical
+    - dm: fix excessive dm-mq context switching
+    - dm thin metadata: don't issue prefetches if a transaction abort has failed
+    - dm cache: make sure every metadata function checks fail_io
+    - dm: fix rq_end_stats() NULL pointer in dm_requeue_original_request()
+    - usb: retry reset if a device times out
+    - usb: hub: fix a typo in hub_port_init() leading to wrong logic
+    - USB: uas: Reduce can_queue to MAX_CMNDS
+    - USB: cdc-acm: more sanity checking
+    - USB: iowarrior: fix oops with malicious USB descriptors
+    - USB: usb_driver_claim_interface: add sanity checking
+    - USB: mct_u232: add sanity checking in probe
+    - USB: digi_acceleport: do sanity checking for the number of ports
+    - USB: cypress_m8: add endpoint sanity check
+    - USB: serial: cp210x: Adding GE Healthcare Device ID
+    - USB: serial: ftdi_sio: Add support for ICP DAS I-756xU devices
+    - USB: option: add "D-Link DWM-221 B1" device id
+    - pwc: Add USB id for Philips Spc880nc webcam
+    - Input: powermate - fix oops with malicious USB descriptors
+    - ALSA: usb-audio: Fix NULL dereference in create_fixed_stream_quirk()
+    - ALSA: usb-audio: Add sanity checks for endpoint accesses
+    - ALSA: usb-audio: add Microsoft HD-5001 to quirks
+    - ALSA: usb-audio: Minor code cleanup in create_fixed_stream_quirk()
+    - ALSA: usb-audio: Fix double-free in error paths after
+      snd_usb_add_audio_stream() call
+    - Bluetooth: btusb: Add new AR3012 ID 13d3:3395
+    - Bluetooth: btusb: Add a new AR3012 ID 04ca:3014
+    - Bluetooth: btusb: Add a new AR3012 ID 13d3:3472
+    - crypto: ccp - Add hash state import and export support
+    - crypto: ccp - Limit the amount of information exported
+    - crypto: ccp - Don't assume export/import areas are aligned
+    - crypto: ccp - memset request context to zero during import
+    - crypto: keywrap - memzero the correct memory
+    - crypto: atmel - fix checks of error code returned by devm_ioremap_resource()
+    - crypto: ux500 - fix checks of error code returned by devm_ioremap_resource()
+    - crypto: marvell/cesa - forward devm_ioremap_resource() error code
+    - X.509: Fix leap year handling again
+    - mei: bus: check if the device is enabled before data transfer
+    - HID: logitech: fix Dual Action gamepad support
+    - HID: i2c-hid: fix OOB write in i2c_hid_set_or_send_report()
+    - HID: multitouch: force retrieving of Win8 signature blob
+    - HID: fix hid_ignore_special_drivers module parameter
+    - staging: comedi: ni_tiocmd: change mistaken use of start_src for start_arg
+    - staging: android: ion_test: fix check of platform_device_register_simple()
+      error code
+    - staging: comedi: ni_mio_common: fix the ni_write[blw]() functions
+    - tty: Fix GPF in flush_to_ldisc(), part 2
+    - net: irda: Fix use-after-free in irtty_open()
+    - 8250: use callbacks to access UART_DLL/UART_DLM
+    - saa7134: Fix bytesperline not being set correctly for planar formats
+    - adv7511: TX_EDID_PRESENT is still 1 after a disconnect
+    - bttv: Width must be a multiple of 16 when capturing planar formats
+    - coda: fix first encoded frame payload
+    - media: v4l2-compat-ioctl32: fix missing length copy in put_v4l2_buffer32
+    - mtip32xx: Avoid issuing standby immediate cmd during FTL rebuild
+    - mtip32xx: Fix broken service thread handling
+    - mtip32xx: Remove unwanted code from taskfile error handler
+    - mtip32xx: Print exact time when an internal command is interrupted
+    - mtip32xx: Fix for rmmod crash when drive is in FTL rebuild
+    - mtip32xx: Handle safe removal during IO
+    - mtip32xx: Handle FTL rebuild failure state during device initialization
+    - mtip32xx: Implement timeout handler
+    - mtip32xx: Cleanup queued requests after surprise removal
+    - ALSA: pcm: Avoid "BUG:" string for warnings again
+    - ALSA: intel8x0: Add clock quirk entry for AD1981B on IBM ThinkPad X41.
+    - ALSA: hda - Don't handle ELD notify from invalid port
+    - ALSA: hda - fix the mic mute button and led problem for a Lenovo AIO
+    - ALSA: hda - Fix unconditional GPIO toggle via automute
+    - tools/hv: Use include/uapi with __EXPORTED_HEADERS__
+    - jbd2: fix FS corruption possibility in jbd2_journal_destroy() on umount path
+    - brd: Fix discard request processing
+    - IB/srpt: Simplify srpt_handle_tsk_mgmt()
+    - bcache: cleaned up error handling around register_cache()
+    - bcache: fix race of writeback thread starting before complete initialization
+    - bcache: fix cache_set_flush() NULL pointer dereference on OOM
+    - mm: memcontrol: reclaim when shrinking memory.high below usage
+    - mm: memcontrol: reclaim and OOM kill when shrinking memory.max below usage
+    - ia64: define ioremap_uc()
+    - watchdog: don't run proc_watchdog_update if new value is same as old
+    - watchdog: rc32434_wdt: fix ioctl error handling
+    - Bluetooth: Add new AR3012 ID 0489:e095
+    - Bluetooth: Fix potential buffer overflow with Add Advertising
+    - cgroup: ignore css_sets associated with dead cgroups during migration
+    - net: mvneta: enable change MAC address when interface is up
+    - of: alloc anywhere from memblock if range not specified
+    - vfs: show_vfsstat: do not ignore errors from show_devname method
+    - splice: handle zero nr_pages in splice_to_pipe()
+    - xtensa: ISS: don't hang if stdin EOF is reached
+    - xtensa: fix preemption in {clear,copy}_user_highpage
+    - xtensa: clear all DBREAKC registers on start
+    - ARC: [BE] readl()/writel() to work in Big Endian CPU configuration
+    - ARC: bitops: Remove non relevant comments
+    - quota: Fix possible GPF due to uninitialised pointers
+    - xfs: fix two memory leaks in xfs_attr_list.c error paths
+    - raid1: include bio_end_io_list in nr_queued to prevent freeze_array hang
+    - md/raid5: Compare apples to apples (or sectors to sectors)
+    - RAID5: check_reshape() shouldn't call mddev_suspend
+    - RAID5: revert e9e4c377e2f563 to fix a livelock
+    - raid10: include bio_end_io_list in nr_queued to prevent freeze_array hang
+    - md/raid5: preserve STRIPE_PREREAD_ACTIVE in break_stripe_batch_list
+    - md: multipath: don't hardcopy bio in .make_request path
+    - Revert "UBUNTU: SAUCE: (noup) fuse: Add reference counting for fuse_io_priv"
+    - Revert "UBUNTU: SAUCE: (noup) fuse: do not use iocb after it may have been
+      freed"
+    - fuse: do not use iocb after it may have been freed
+    - fuse: Add reference counting for fuse_io_priv
+    - fs/coredump: prevent fsuid=0 dumps into user-controlled directories
+    - rapidio/rionet: fix deadlock on SMP
+    - ipr: Fix out-of-bounds null overwrite
+    - ipr: Fix regression when loading firmware
+    - iwlwifi: mvm: Fix paging memory leak
+    - drm/radeon: disable runtime pm on PX laptops without dGPU power control
+    - drm/radeon: Don't drop DP 2.7 Ghz link setup on some cards.
+    - drm/amdgpu: disable runtime pm on PX laptops without dGPU power control
+    - drm/amdgpu: include the right version of gmc header files for iceland
+    - IB/ipoib: fix for rare multicast join race condition
+    - tracing: Have preempt(irqs)off trace preempt disabled functions
+    - tracing: Fix crash from reading trace_pipe with sendfile
+    - tracing: Fix trace_printk() to print when not using bprintk()
+    - bitops: Do not default to __clear_bit() for __clear_bit_unlock()
+    - scripts/coccinelle: modernize &
+    - scripts/kconfig: allow building with make 3.80 again
+    - kbuild/mkspec: fix grub2 installkernel issue
+    - MAINTAINERS: Update mailing list and web page for hwmon subsystem
+    - ideapad-laptop: Add ideapad Y700 (15) to the no_hw_rfkill DMI list
+    - mmc: block: fix ABI regression of mmc_blk_ioctl
+    - mmc: mmc_spi: Add Card Detect comments and fix CD GPIO case
+    - mmc: sdhci: fix data timeout (part 1)
+    - mmc: sdhci: fix data timeout (part 2)
+    - mmc: sdhci: Fix override of timeout clk wrt max_busy_timeout
+    - clk: rockchip: rk3368: fix cpuclk mux bit of big cpu-cluster
+    - clk: rockchip: rk3368: fix cpuclk core dividers
+    - clk: rockchip: rk3368: fix parents of video encoder/decoder
+    - clk: rockchip: rk3368: fix hdmi_cec gate-register
+    - clk: rockchip: add hclk_cpubus to the list of rk3188 critical clocks
+    - clk: bcm2835: Fix setting of PLL divider clock rates
+    - target: Fix target_release_cmd_kref shutdown comp leak
+    - iser-target: Fix identification of login rx descriptor type
+    - iser-target: Add new state ISER_CONN_BOUND to isert_conn
+    - iser-target: Separate flows for np listeners and connections cma events
+    - iser-target: Rework connection termination
+    - nfsd4: fix bad bounds checking
+    - nfsd: fix deadlock secinfo+readdir compound
+    - ARM: dts: at91: sama5d3 Xplained: don't disable hsmci regulator
+    - ARM: dts: at91: sama5d4 Xplained: don't disable hsmci regulator
+    - ACPI / PM: Runtime resume devices when waking from hibernate
+    - writeback, cgroup: fix premature wb_put() in
+      locked_inode_to_wb_and_lock_list()
+    - writeback, cgroup: fix use of the wrong bdi_writeback which mismatches the
+      inode
+    - Revert "UBUNTU: SAUCE: (noup) Input: synaptics - handle spurious release of
+      trackstick buttons, again"
+    - Input: synaptics - handle spurious release of trackstick buttons, again
+    - Input: ims-pcu - sanity check against missing interfaces
+    - Input: ati_remote2 - fix crashes on detecting device with invalid descriptor
+    - ocfs2/dlm: fix race between convert and recovery
+    - ocfs2/dlm: fix BUG in dlm_move_lockres_to_recovery_list
+    - mm/page_alloc: prevent merging between isolated and other pageblocks
+    - mtd: onenand: fix deadlock in onenand_block_markbad
+    - PM / sleep: Clear pm_suspend_global_flags upon hibernate
+    - scsi_common: do not clobber fixed sense information
+    - sched/cputime: Fix steal time accounting vs. CPU hotplug
+    - perf/x86/pebs: Add workaround for broken OVFL status on HSW+
+    - perf/x86/intel: Fix PEBS warning by only restoring active PMU in pmi
+    - perf/x86/intel: Fix PEBS data source interpretation on Nehalem/Westmere
+    - Linux 4.4.7
+
+  * QCA9565 / AR9565 bluetooth not work (LP: #1542944)
+    - Bluetooth: Add new AR3012 ID 0489:e095
+
+  * The mic mute key and led can't work on a Lenovo AIO machine (LP: #1555912)
+    - ALSA: hda - fix the mic mute button and led problem for a Lenovo AIO
+
+  * 13d3:3472 bluetooth not working, 4.2 low latency kernel 14.04.1 on asus ROG
+    gl552jx (LP: #1552925)
+    - Bluetooth: btusb: Add a new AR3012 ID 13d3:3472
+
+  * Bluetooth cannot detect other devices (Lite-on 3014 + Atheros AR9565)
+    (LP: #1546694)
+    - Bluetooth: btusb: Add a new AR3012 ID 04ca:3014
+
+  * Atheros AR9462 Bluetooth cannot detect other devices  (LP: #1542564)
+    - Bluetooth: btusb: Add new AR3012 ID 13d3:3395
+
+  * s390/pci: add extra padding to function measurement block (LP: #1572291)
+    - s390/pci: add extra padding to function measurement block
+
+  * CVE-2016-3951 (LP: #1567191)
+    - cdc_ncm: do not call usbnet_link_change from cdc_ncm_bind
+    - usbnet: cleanup after bind() in probe()
+
+  * linux: Add UEFI keyring for externally signed modules (LP: #1569924)
+    - efi: Remove redundant efi_set_variable_nonblocking() prototype
+    - efi/runtime-wrappers: Add a nonblocking version of QueryVariableInfo()
+    - efi: Add nonblocking option to efi_query_variable_store()
+    - efi: Add NV memory attribute
+    - efi: Reformat GUID tables to follow the format in UEFI spec
+    - efi: stub: implement efi_get_random_bytes() based on EFI_RNG_PROTOCOL
+    - SAUCE: (noup) Add EFI signature data types
+    - crypto: KEYS: convert public key and digsig asym to the akcipher api
+    - [Config] CONFIG_EFI_SIGNATURE_LIST_PARSER=y
+    - SAUCE: (noup) Add an EFI signature blob parser and key loader.
+    - [Config] CONFIG_IMA_MOK_KEYRING=y
+    - IMA: create machine owner and blacklist keyrings
+    - KEYS: Add an alloc flag to convey the builtinness of a key
+    - [Config] CONFIG_MODULE_SIG_UEFI=y, CONFIG_SYSTEM_BLACKLIST_KEYRING=y
+    - SAUCE: (noup) KEYS: Add a system blacklist keyring
+    - SAUCE: (noup) MODSIGN: Support not importing certs from db
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_PUBLIC_KEY_ALGO_RSA=y
+
+ -- Kamal Mostafa <kamal@canonical.com>  Sun, 24 Apr 2016 12:12:13 -0700
+
+linux (4.4.0-21.37) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1571791
+
+  * linux: MokSBState is ignored (LP: #1571691)
+    - SAUCE: (noup) MODSIGN: Import certificates from UEFI Secure Boot
+    - SAUCE: (noup) efi: Disable secure boot if shim is in insecure mode
+    - SAUCE: (noup) Display MOKSBState when disabled
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 18 Apr 2016 07:00:22 -0600
+
+linux (4.4.0-20.36) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1571069
+
+  * sysfs mount failure during stateful lxd snapshots (LP: #1570906)
+    - SAUCE: kernfs: Do not match superblock in another user namespace when
+      mounting
+
+  * Kernel Panic in Ubuntu 16.04 netboot installer (LP: #1570441)
+    - x86/topology: Fix logical package mapping
+    - x86/topology: Fix Intel HT disable
+    - x86/topology: Use total_cpus not nr_cpu_ids for logical packages
+    - xen/apic: Provide Xen-specific version of cpu_present_to_apicid APIC op
+    - x86/topology: Fix AMD core count
+
+  * [regression]: Failed to call clock_adjtime(): Invalid argument
+    (LP: #1566465)
+    - ntp: Fix ADJ_SETOFFSET being used w/ ADJ_NANO
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 14 Apr 2016 06:31:56 -0600
+
+linux (4.4.0-19.35) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1570348
+
+  * CVE-2016-2847 (LP: #1554260)
+    - pipe: limit the per-user amount of pages allocated in pipes
+
+  * xenial kernel crash on HP BL460c G7 (qla24xx problem?) (LP: #1554003)
+    - SAUCE: (noup) qla2xxx: Add irq affinity notification V2
+
+  * arm64: guest hangs when ntpd is running (LP: #1549494)
+    - SAUCE: (noup) KVM: arm/arm64: Handle forward time correction gracefully
+
+  * linux: Enforce signed module loading when UEFI secure boot (LP: #1566221)
+    - [Config] CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE=y
+
+  * s390/cpumf: Fix lpp detection (LP: #1555344)
+    - s390/facilities: use stfl mnemonic instead of insn magic
+    - s390/facilities: always use lowcore's stfle field for storing facility bits
+    - s390/cpumf: Fix lpp detection
+
+  * s390x kernel image needs weightwatchers (LP: #1536245)
+    - [Config] s390x: Use compressed kernel bzImage
+
+  * Surelock GA2 SP1: surelock02p05: Not seeing sgX devices for LUNs after
+    upgrading to Ubuntu 16.04 (LP: #1567581)
+    - Revert "UBUNTU: SAUCE: (noup) powerpc/pci: Assign fixed PHB number based on
+      device-tree properties"
+
+  * Backport upstream bugfixes to ubuntu-16.04 (LP: #1555765)
+    - cpufreq: powernv: Define per_cpu chip pointer to optimize hot-path
+    - Revert "cpufreq: postfix policy directory with the first CPU in related_cpus"
+    - cpufreq: powernv: Add sysfs attributes to show throttle stats
+
+  * systemd-modules-load.service: Failing due to missing module 'ib_iser' (LP: #1566468)
+    - [Config] Add ib_iser to generic inclusion list
+
+  * thunderx nic performance improvements (LP: #1567093)
+    - net: thunderx: Set recevie buffer page usage count in bulk
+    - net: thunderx: Adjust nicvf structure to reduce cache misses
+
+  * fixes for thunderx nic in multiqueue mode (LP: #1567091)
+    - net: thunderx: Fix for multiqset not configured upon interface toggle
+    - net: thunderx: Fix for HW TSO not enabled for secondary qsets
+    - net: thunderx: Fix receive packet stats
+
+  * Miscellaneous Ubuntu changes
+    - [Config] updateconfigs after CONFIG_DRM_I915_BPO_PRELIMINARY_HW_SUPPORT=n
+
+  * Miscellaneous upstream changes (LP: #1564901)
+    - Input: xpad - correctly handle concurrent LED and FF requests
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 07 Apr 2016 07:32:16 +0100
+
+linux (4.4.0-18.34) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1566868
+
+  * [i915_bpo] Fix RC6 on SKL GT3 & GT4 (LP: #1564759)
+    - SAUCE: i915_bpo: drm/i915/skl: Fix rc6 based gpu/system hang
+    - SAUCE: i915_bpo: drm/i915/skl: Fix spurious gpu hang with gt3/gt4 revs
+
+  * CONFIG_ARCH_ROCKCHIP not enabled in armhf generic kernel (LP: #1566283)
+    - [Config] CONFIG_ARCH_ROCKCHIP=y
+
+  * [Feature] Memory Bandwidth Monitoring (LP: #1397880)
+    - perf/x86/cqm: Fix CQM handling of grouping events into a cache_group
+    - perf/x86/cqm: Fix CQM memory leak and notifier leak
+    - x86/cpufeature: Carve out X86_FEATURE_*
+    - Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
+    - x86/topology: Create logical package id
+    - perf/x86/mbm: Add Intel Memory B/W Monitoring enumeration and init
+    - perf/x86/mbm: Add memory bandwidth monitoring event management
+    - perf/x86/mbm: Implement RMID recycling
+    - perf/x86/mbm: Add support for MBM counter overflow handling
+
+  * User namespace mount updates (LP: #1566505)
+    - SAUCE: quota: Require that qids passed to dqget() be valid and map into s_user_ns
+    - SAUCE: fs: Allow superblock owner to change ownership of inodes with unmappable ids
+    - SAUCE: fuse: Don't initialize user_id or group_id in mount options
+    - SAUCE: cgroup: Use a new super block when mounting in a cgroup namespace
+    - SAUCE: fs: fix a posible leak of allocated superblock
+
+  * [arm64] kernel BUG at /build/linux-StrpB2/linux-4.4.0/fs/ext4/inode.c:2394!
+    (LP: #1566518)
+    - arm64: Honour !PTE_WRITE in set_pte_at() for kernel mappings
+    - arm64: Update PTE_RDONLY in set_pte_at() for PROT_NONE permission
+
+  * [Feature]USB core and xHCI tasks for USB 3.1 SuperSpeedPlus (SSP) support
+    for Alpine Ridge on SKL (LP: #1519623)
+    - usb: define USB_SPEED_SUPER_PLUS speed for SuperSpeedPlus USB3.1 devices
+    - usb: set USB 3.1 roothub device speed to USB_SPEED_SUPER_PLUS
+    - usb: show speed "10000" in sysfs for USB 3.1 SuperSpeedPlus devices
+    - usb: add device descriptor for usb 3.1 root hub
+    - usb: Support USB 3.1 extended port status request
+    - xhci: Make sure xhci handles USB_SPEED_SUPER_PLUS devices.
+    - xhci: set roothub speed to USB_SPEED_SUPER_PLUS for USB3.1 capable controllers
+    - xhci: USB 3.1 add default Speed Attributes to SuperSpeedPlus device capability
+    - xhci: set slot context speed field to SuperSpeedPlus for USB 3.1 SSP devices
+    - usb: Add USB3.1 SuperSpeedPlus Isoc Endpoint Companion descriptor
+    - usb: Parse the new USB 3.1 SuperSpeedPlus Isoc endpoint companion descriptor
+    - usb: Add USB 3.1 Precision time measurement capability descriptor support
+    - xhci: refactor and cleanup endpoint initialization.
+    - xhci: Add SuperSpeedPlus high bandwidth isoc support to xhci endpoints
+    - xhci: cleanup isoc tranfers queuing code
+    - xhci: Support extended burst isoc TRB structure used by xhci 1.1 for USB 3.1
+    - SAUCE: (noup) usb: fix regression in SuperSpeed endpoint descriptor parsing
+
+  * wrong/missing permissions for device file /dev/prandom (prng.ko)
+    (LP: #1558275)
+    - s390/crypto: provide correct file mode at device register.
+
+  * The Front MIC jack can't work on a HP desktop machine (LP: #1564712)
+    - ALSA: hda - fix front mic problem for a HP desktop
+
+  * HP Notebook Probook 440 G3  HDA Intel PCH horrible sounds while booting
+    (LP: #1556228)
+    - ALSA: hda - Apply reboot D3 fix for CX20724 codec, too
+
+  * please provide mmc-modules udeb (LP: #1565765)
+    - [Config] Add mmc block drivers to d-i
+
+  * linux: Enforce signed module loading when UEFI secure boot (LP: #1566221)
+    - Add secure_modules() call
+    - PCI: Lock down BAR access when module security is enabled
+    - x86: Lock down IO port access when module security is enabled
+    - ACPI: Limit access to custom_method
+    - asus-wmi: Restrict debugfs interface when module loading is restricted
+    - Restrict /dev/mem and /dev/kmem when module loading is restricted
+    - acpi: Ignore acpi_rsdp kernel parameter when module loading is restricted
+    - kexec: Disable at runtime if the kernel enforces module loading restrictions
+    - x86: Restrict MSR access when module loading is restricted
+    - [Config] CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE=n
+    - Add option to automatically enforce module signatures when in Secure Boot mode
+    - efi: Make EFI_SECURE_BOOT_SIG_ENFORCE depend on EFI
+    - efi: Add EFI_SECURE_BOOT bit
+    - hibernate: Disable in a signed modules environment
+
+  * [Hyper-V] Additional PCI passthrough commits (LP: #1565967)
+    - PCI: Add fwnode_handle to x86 pci_sysdata
+    - PCI: Look up IRQ domain by fwnode_handle
+    - [Config] CONFIG_PCI_HYPERV=m
+    - PCI: hv: Add paravirtual PCI front-end for Microsoft Hyper-V VMs
+
+  * [Bug]Lenovo Yoga 260 and Carbon X1 4th gen freeze on HWP enable
+    (LP: #1559923)
+    - ACPI / processor: Request native thermal interrupt handling via _OSC
+
+  * Sync kernel zfs 0.6.5.6 - align with zfsutils-linux and spl packages
+    (LP: #1564591)
+    - SAUCE: (noup) Update spl to 0.6.5.6-0ubuntu1, zfs to 0.6.5.6-0ubuntu3
+
+  * [Ubuntu 16.04.1] RELEASE and ACQUIRE atomics on Power (LP: #1556096)
+    - atomics: Allow architectures to define their own __atomic_op_* helpers
+    - powerpc: atomic: Implement atomic{, 64}_*_return_* variants
+    - powerpc: atomic: Implement acquire/release/relaxed variants for xchg
+    - powerpc: atomic: Implement acquire/release/relaxed variants for cmpxchg
+
+  * fix for do_tools_cpupower when cross-compiling (LP: #1564206)
+    - [Debian] cpupower uses non-standard CROSS
+
+  * ISST:LTE: Regression: roselp2 Oops in kernel during setup io (LP: #1546439)
+    - SAUCE: block: partition: initialize percpuref before sending out KOBJ_ADD
+
+  * Unable to migrate container (LP: #1563921)
+    - SAUCE: cgroup mount: ignore nsroot=
+
+  * [Hyper-V] patch inclusion in 16.04 for NIC hot add/remove (LP: #1563688)
+    - hv_netvsc: Move subchannel waiting to rndis_filter_device_remove()
+
+  * /proc/$pid/maps performance regression (LP: #1547231)
+    - proc: revert /proc/<pid>/maps [stack:TID] annotation
+
+  * TPM2.0 trusted keys fixes (LP: #1398274)
+    - tpm: remove unneeded include of actbl2.h
+    - tpm: fix checks for policy digest existence in tpm2_seal_trusted()
+    - tpm_crb: Use the common ACPI definition of struct acpi_tpm2
+    - tpm_tis: Disable interrupt auto probing on a per-device basis
+    - tpm_tis: Do not fall back to a hardcoded address for TPM2
+    - tpm_tis: Use devm_ioremap_resource
+    - tpm_tis: Clean up the force=1 module parameter
+    - tpm_crb: Drop le32_to_cpu(ioread32(..))
+    - tpm_crb: Use devm_ioremap_resource
+    - tpm: fix the rollback in tpm_chip_register()
+    - tpm: fix the cleanup of struct tpm_chip
+    - tpm: fix: set continueSession attribute for the unseal operation
+    - tpm: fix: return rc when devm_add_action() fails
+    - tpm_eventlog.c: fix binary_bios_measurements
+    - tpm_crb/tis: fix: use dev_name() for /proc/iomem
+    - tpm_crb: tpm2_shutdown() must be called before tpm_chip_unregister()
+    - tpm_tis: fix build warning with tpm_tis_resume
+
+  * [Feature]intel_idle driver support for Knights Landing (LP: #1461365)
+    - intel_idle: Support for Intel Xeon Phi Processor x200 Product Family
+
+  * cxlflash: Backport upstream cxlflash commits and submitting a noup patch to
+    Xenial (LP: #1563485)
+    - cxlflash: Fix to avoid unnecessary scan with internal LUNs
+    - cxlflash: Increase cmd_per_lun for better throughput
+    - SAUCE: (noup) cxlflash: Move to exponential back-off when cmd_room is not available
+
+  * Miscellaneous Ubuntu changes
+    - [Config] do_zfs_powerpc64-smp  = true
+    - [Debian] fix linux_tools when cross-compiling
+    - [Config] do_zfs_powerpc64-smp use default value
+    - SAUCE: apparmor: Fix FTBFS due to bad include path
+    - SAUCE: i915_bpo: Disable preliminary hw support
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 29 Mar 2016 15:31:33 -0600
+
+linux (4.4.0-17.33) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1563441
+
+  * ISST-LTE: pVM:high cpus number need a high crashkernel value in kdump
+    (LP: #1560552)
+    - SAUCE: (noup) ppc64 boot: Wait for boot cpu to show up if nr_cpus limit is
+      about to hit.
+
+  * Predictable naming mechanism is leading to issues in DLPAR operations of
+    NICs (LP: #1560514)
+    - SAUCE: (noup) powerpc/pci: Assign fixed PHB number based on device-tree
+      properties
+
+  * ThunderX: support alternative phy implementations (LP: #1562968)
+    - net: thunderx: Cleanup PHY probing code.
+    - [Config] CONFIG_MDIO_CAVIUM=m
+    - phy: mdio-octeon: Refactor into two files/modules
+    - [Config] CONFIG_MDIO_THUNDER=m
+    - phy: mdio-thunder: Add driver for Cavium Thunder SoC MDIO buses.
+    - phy: mdio-cavium: Add missing MODULE_* annotations.
+    - net: cavium: For Kconfig THUNDER_NIC_BGX, select MDIO_THUNDER.
+    - phy: mdio-thunder: Fix some Kconfig typos
+    - [d-i] Add phy drivers for Cavium ThunderX to nic-modules udeb
+
+  * linux: exclude ZONE_DEVICE from GFP_ZONE_TABLE (LP: #1563293)
+    - Revert "mm: CONFIG_NR_ZONES_EXTENDED"
+    - mm: exclude ZONE_DEVICE from GFP_ZONE_TABLE
+
+  * lots of printk to serial console can hang system for long time
+    (LP: #1534216)
+    - printk: set may_schedule for some of console_trylock() callers
+
+  * [i915_bpo] Update i915 backport driver (LP: #1560395)
+    - SAUCE: i915_bpo: Update to drm-intel-next-fixes-2016-03-16
+    - PM / runtime: Add new helper for conditional usage count incrementation
+    - drm/core: Add drm_for_each_encoder_mask, v2.
+    - drm/atomic-helper: Implement subsystem-level suspend/resume
+
+  * [Hyper-V] VM Sockets (LP: #1541585)
+    - Drivers: hv: vmbus: Cleanup vmbus_set_event()
+    - Drivers: hv: vmbus: Add vendor and device atttributes
+    - Drivers: hv: vmbus: avoid infinite loop in init_vp_index()
+    - Drivers: hv: vmbus: avoid scheduling in interrupt context in vmbus_initiate_unload()
+    - Drivers: hv: vmbus: don't manipulate with clocksources on crash
+    - Drivers: hv: vmbus: add a helper function to set a channel's pending send size
+    - Drivers: hv: vmbus: define the new offer type for Hyper-V socket (hvsock)
+    - Drivers: hv: vmbus: vmbus_sendpacket_ctl: hvsock: avoid unnecessary signaling
+    - Drivers: hv: vmbus: define a new VMBus message type for hvsock
+    - Drivers: hv: vmbus: add a hvsock flag in struct hv_driver
+    - Drivers: hv: vmbus: add a per-channel rescind callback
+    - Drivers: hv: vmbus: add an API vmbus_hvsock_device_unregister()
+    - Drivers: hv: vmbus: Eliminate the spin lock on the read path
+    - Drivers: hv: vmbus: Give control over how the ring access is serialized
+    - drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header
+    - Drivers: hv: vmbus: don't loose HVMSG_TIMER_EXPIRED messages
+    - Drivers: hv: vmbus: avoid wait_for_completion() on crash
+    - Drivers: hv: vmbus: remove code duplication in message handling
+    - Drivers: hv: vmbus: avoid unneeded compiler optimizations in vmbus_wait_for_unload()
+    - Drivers: hv: util: Pass the channel information during the init call
+    - Drivers: hv: utils: Remove util transport handler from list if registration fails
+    - Revert "Drivers: hv: vmbus: Support handling messages on multiple CPUs"
+    - Drivers: hv: vmbus: Support handling messages on multiple CPUs
+
+  * [Bug]SKL-H boot hang when c8+c9+c10 enabled by intel_idle driver
+    (LP: #1559918)
+    - intel_idle: prevent SKL-H boot failure when C8+C9+C10 enabled
+
+  * ixgbe: Update to Fortville SW5 release (LP: #1562326)
+    - net: add tc offload feature flag
+    - net: tc: helper functions to query action types
+    - sctp: Rename NETIF_F_SCTP_CSUM to NETIF_F_SCTP_CRC
+    - net: rework ndo tc op to consume additional qdisc handle parameter
+    - net: rework setup_tc ndo op to consume general tc operand
+    - net: sched: add cls_u32 offload hooks for netdevs
+    - net: ixgbe: add support for tc_u32 offload
+    - net: ixgbe: abort with cls u32 divisor groups greater than 1
+
+  * Bring fm10k up to Fortville SW5 (LP: #1562310)
+    - net: add netif_is_team_master helper
+    - net: add netif_is_team_port helper
+    - net: add netif_is_lag_master helper
+    - net: add netif_is_lag_port helper
+    - ethtool: correctly ensure {GS}CHANNELS doesn't conflict with GS{RXFH}
+    - fm10k: don't reinitialize RSS flow table when RXFH configured
+
+  * [Feature]Always Running Timer (ART) to System Time translation
+    (LP: #1519625)
+    - time: Verify time values in adjtimex ADJ_SETOFFSET to avoid overflow
+    - timekeeping: Provide internal function __ktime_get_real_seconds
+    - timekeeping: Cap adjustments so they don't exceed the maxadj value
+    - clocksource: Make clocksource validation work for all clocksources
+    - time: Add cycles to nanoseconds translation
+    - time: Add timekeeping snapshot code capturing system time and counter
+    - time: Remove duplicated code in ktime_get_raw_and_real()
+    - time: Add driver cross timestamp interface for higher precision time synchronization
+    - time: Add history to cross timestamp interface supporting slower devices
+    - time/timekeeping: Work around false positive GCC warning
+    - x86/tsc: Always Running Timer (ART) correlated clocksource
+    - ptp: Add PTP_SYS_OFFSET_PRECISE for driver crosstimestamping
+    - [Config] CONFIG_E1000E_HWTS=y
+    - e1000e: Adds hardware supported cross timestamp on e1000e nic
+
+  * x-gene2: add SoC v2 support to clock (LP: #1561604)
+    - clk: xgene: Add SoC and PMD PLL clocks with v2 hardware
+
+  * [Bug]Disable multi-record PEBS on Merom (LP: #1559914)
+    - perf/x86: Move perf_event.c ............... => x86/events/core.c
+    - perf/x86: Move perf_event_amd.c ........... => x86/events/amd/core.c
+    - perf/x86: Move perf_event_amd_ibs.c ....... => x86/events/amd/ibs.c
+    - perf/x86: Move perf_event_amd_iommu.[ch] .. => x86/events/amd/iommu.[ch]
+    - perf/x86: Move perf_event_amd_uncore.c .... => x86/events/amd/uncore.c
+    - perf/x86: Move perf_event_intel_bts.c ........ => x86/events/intel/bts.c
+    - perf/x86: Move perf_event_intel.c ............ => x86/events/intel/core.c
+    - perf/x86: Move perf_event_intel_cqm.c ........ => x86/events/intel/cqm.c
+    - perf/x86: Move perf_event_intel_cstate.c ..... => x86/events/intel/cstate.c
+    - perf/x86: Move perf_event_intel_ds.c ......... => x86/events/intel/ds.c
+    - perf/x86: Move perf_event_intel_lbr.c ........ => x86/events/intel/lbr.c
+    - perf/x86: Move perf_event_intel_pt.[ch] ...... => x86/events/intel/pt.[ch]
+    - perf/x86: Move perf_event_intel_rapl.c ....... => x86/events/intel/rapl.c
+    - perf/x86: Move perf_event_intel_uncore.[ch] .. =>
+      x86/events/intel/uncore.[ch]
+    - perf/x86: Move perf_event_intel_uncore_nhmex.c =>
+      x86/events/intel/uncore_nmhex.c
+    - perf/x86: Move perf_event_intel_uncore_snb.c =>
+      x86/events/intel/uncore_snb.c
+    - perf/x86: Move perf_event_intel_uncore_snbep.c =>
+      x86/events/intel/uncore_snbep.c
+    - perf/x86: Move perf_event_knc.c .............. => x86/events/intel/knc.c
+    - perf/x86: Move perf_event_p4.c ............... => x86/events/intel/p4.c
+    - perf/x86: Move perf_event_p6.c ............... => x86/events/intel/p6.c
+    - perf/x86: Move perf_event_msr.c .............. => x86/events/msr.c
+    - perf/x86: Move perf_event.h to its new home
+    - perf/x86/intel: Use PAGE_SIZE for PEBS buffer size on Core2
+
+  * [Feature] Enable I2C on Broxton-P (LP: #1520139)
+    - mfd: intel-lpss: Pass I2C configuration via properties on BXT
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 24 Mar 2016 20:40:27 -0600
+
+linux (4.4.0-16.32) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1561727
+
+  * fix thermal throttling due to commit "Thermal: initialize thermal zone
+    device correctly"  (LP: #1561676)
+    - Thermal: Ignore invalid trip points
+
+  * Thinkpad T460: Trackpoint mouse buttons instantly generate "release" event
+    on press (LP: #1553811)
+    - SAUCE: (noup) Input: synaptics - handle spurious release of trackstick
+      buttons, again
+
+  * reading /sys/kernel/security/apparmor/profiles requires CAP_MAC_ADMIN
+    (LP: #1560583)
+    - SAUCE: apparmor: Allow ns_root processes to open profiles file
+    - SAUCE: apparmor: Consult sysctl when reading profiles in a user ns
+
+  * linux: sync virtualbox drivers to 5.0.16-dfsg-2 (LP: #1561492)
+    - ubuntu: vbox -- update to 5.0.16-dfsg-2
+
+  * s390/kconfig: CONFIG_NUMA without CONFIG_NUMA_EMU does not make any sense on
+    s390x (LP: #1557690)
+    - [Config] CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=n for s390x
+
+  * spl/zfs fails to build on s390x (LP: #1519814)
+    - [Config] s390x -- re-enable zfs
+    - [Config] zfs -- disable powerpc until the test failures can be resolved
+
+  * linux: sync to ZFS 0.6.5.6 stable release (LP: #1561483)
+    - SAUCE: (noup) Update spl to 0.6.5.6-0ubuntu1, zfs to 0.6.5.6-0ubuntu1
+
+  * zfs: enable zfs for 64bit powerpc kernels (LP: #1558871)
+    - [Packaging] zfs -- handle rprovides via dpkg-gencontrol
+    - [Config] powerpc -- convert zfs configuration to custom_override
+
+  * Memory arena corruption with FUSE (was Memory allocation failure crashes
+    kernel hard, presumably related to FUSE) (LP: #1505948)
+    - SAUCE: (noup) fuse: do not use iocb after it may have been freed
+    - SAUCE: (noup) fuse: Add reference counting for fuse_io_priv
+
+  * cgroup namespaces: add a 'nsroot=' mountinfo field (LP: #1560489)
+    - SAUCE: (noup) cgroup namespaces: add a 'nsroot=' mountinfo field
+
+  * linux packaging: clear remaining redundant delta (LP: #1560445)
+    - [Debian] Remove generated intermediate files on clean
+
+  * arm64: guest hangs when ntpd is running (LP: #1549494)
+    - Revert "hrtimer: Add support for CLOCK_MONOTONIC_RAW"
+    - Revert "hrtimer: Catch illegal clockids"
+    - Revert "KVM: arm/arm64: timer: Switch to CLOCK_MONOTONIC_RAW"
+
+  * Need enough contiguous memory to support GICv3 ITS table (LP: #1558828)
+    - [Config] CONFIG_FORCE_MAX_ZONEORDER=13 on arm64
+    - SAUCE: (no-up) arm64: gicv3: its: Increase FORCE_MAX_ZONEORDER for Cavium
+      ThunderX
+
+  * update arcmsr to version v1.30.00.22-20151126 to fix card timeouts
+    (LP: #1559609)
+    - arcmsr: fixed getting wrong configuration data
+    - arcmsr: fixes not release allocated resource
+    - arcmsr: make code more readable
+    - arcmsr: adds code to support new Areca adapter ARC1203
+    - arcmsr: changes driver version number
+    - arcmsr: more readability improvements
+    - arcmsr: Split dma resource allocation to a new function
+    - arcmsr: change driver version to v1.30.00.22-20151126
+
+  * server image has no keyboard, desktop image works (LP: #1559692)
+    - [Config] Rework input-modules (d-i) list
+
+  * PMU support for Cavium ThunderX (LP: #1559349)
+    - arm64: perf: Rename Cortex A57 events
+    - arm64/perf: Add Cavium ThunderX PMU support
+    - arm64: perf: Enable PMCR long cycle counter bit
+    - arm64: perf: Extend event mask for ARMv8.1
+    - arm64: dts: Add Cavium ThunderX specific PMU
+
+  * Show ARM PMU events in perf stat (LP: #1559350)
+    - drivers/perf: kill armpmu_register
+    - arm: perf: Convert event enums to #defines
+    - arm: perf: Add event descriptions
+    - arm64: perf: Convert event enums to #defines
+    - arm64: perf: Add event descriptions
+    - ARM: perf: add format entry to describe event -> config mapping
+    - arm64: perf: add format entry to describe event -> config mapping
+
+  * [Bug]HSW/BDW EDAC driver reports wrong DIMM (LP: #1559904)
+    - EDAC/sb_edac: Fix computation of channel address
+
+  * 5-10 second delay in kernel boot with kernel command line ip= (LP: #1259861)
+    - [Config] disable CONFIG_IP_PNP
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Silence the reconstruct script
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 21 Mar 2016 10:15:31 -0600
+
+linux (4.4.0-15.31) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1559252
+
+  * Xilinx KU3 Capi card does not show up in Ubuntu  16.04 (LP: #1557001)
+    - SAUCE: (noup) cxl: Allow initialization on timebase sync failures
+
+  * policy namespace stacking (LP: #1379535)
+    - Revert "UBUNTU: SAUCE: Move replacedby allocation into label_alloc"
+    - Revert "UBUNTU: SAUCE: Fixup: __label_update() still doesn't handle some cases correctly."
+    - Revert "UBUNTU: SAUCE: fix: audit "no_new_privs" case for exec failure"
+    - Revert "UBUNTU: SAUCE: fixup: warning about aa_label_vec_find_or_create not being static"
+    - Revert "UBUNTU: SAUCE: apparmor: fix refcount race when finding a child profile"
+    - Revert "UBUNTU: SAUCE: fixup: cast poison values to remove warnings"
+    - Revert "UBUNTU: SAUCE: fixup: get rid of unused var build warning"
+    - Revert "UBUNTU: SAUCE: fixup: 20/23 locking issue around in __label_update"
+    - Revert "UBUNTU: SAUCE: fixup: make __share_replacedby private to get rid of build warning"
+    - Revert "UBUNTU: SAUCE: fix: replacedby forwarding is not being properly update when ns is destroyed"
+    - Revert "UBUNTU: SAUCE: apparmor: fix log of apparmor audit message when kern_path() fails"
+    - Revert "UBUNTU: SAUCE: fixup: cleanup return handling of labels"
+    - Revert "UBUNTU: SAUCE: apparmor: fix: ref count leak when profile sha1 hash is read"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: query label file permission"
+    - Revert "UBUNTU: SAUCE: apparmor: Don't remove label on rcu callback if the label has already been removed"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: break circular refcount for label that is directly freed."
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: refcount bug when inserting label update that transitions ns"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: now that insert can force replacement use it instead of remove_and_insert"
+    - Revert "UBUNTU: SAUCE: apparmor Fix: refcount bug in pivotroot mediation"
+    - Revert "UBUNTU: SAUCE: apparmor: ensure that repacedby sharing is done correctly"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: update replacedby allocation to take a gfp parameter"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: convert replacedby update to be protected by the labelset lock"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: add required locking of __aa_update_replacedby on merge path"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: deadlock in aa_put_label() call chain"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: label_vec_merge insertion"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: ensure new labels resulting from merge have a replacedby"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: refcount leak in aa_label_merge"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: refcount race between locating in labelset and get"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: label merge handling of marking unconfined and stale"
+    - Revert "UBUNTU: SAUCE: apparmor: add underscores to indicate aa_label_next_not_in_set() use needs locking"
+    - Revert "UBUNTU: SAUCE: apparmor: debug: POISON label and replaceby pointer on free"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: ensure aa_get_newest will trip debugging if the replacedby is not setup"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: insert race between label_update and label_merge"
+    - Revert "UBUNTU: SAUCE: apparmor: rework retrieval of the current label in the profile update case"
+    - Revert "UBUNTU: SAUCE: apparmor: Disallow update of cred when then subjective != the objective cred"
+    - Revert "UBUNTU: SAUCE: apparmor: Fix: oops do to invalid null ptr deref in label print fns"
+    - Revert "UBUNTU: SAUCE: fix-up: kern_mount fail path should not be doing put_buffers()"
+    - Revert "UBUNTU: SAUCE: apparmor: fix sleep from invalid context"
+    - Revert "UBUNTU: SAUCE: (no-up): apparmor: fix for failed mediation of socket that is being shutdown"
+    - Revert "UBUNTU: SAUCE: (no-up) apparmor: Fix incompatible pointer type warnings"
+    - Revert "UBUNTU: SAUCE: (no-up) apparmor: fix mount not handling disconnected paths"
+    - Revert "UBUNTU: SAUCE: (no-up): apparmor: fix mediation of fs unix sockets"
+    - Revert "UBUNTU: apparmor -- follow change to this_cpu_ptr"
+    - Revert "UBUNTU: SAUCE: (no-up) fix: bad unix_addr_fs macro"
+    - Revert "UBUNTU: SAUCE: Revert: fix: only allow a single threaded process to ..."
+    - Revert "UBUNTU: SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot"
+    - Revert "UBUNTU: SAUCE: (no-up) apparmor: add parameter to control whether policy hashing is used"
+    - SAUCE: (no-up) apparmor: sync of apparmor3.5-beta1 snapshot
+    - SAUCE: add a sysctl to enable unprivileged user ns AppArmor policy loading
+
+  * Add arm64 NUMA support (LP: #1558765)
+    - SAUCE: (noup) efi: ARM/arm64: ignore DT memory nodes instead of removing them
+    - SAUCE: (noup) Documentation, dt, numa: dt bindings for NUMA.
+    - [Config] CONFIG_OF_NUMA=y
+    - SAUCE: (noup) of, numa: Add NUMA of binding implementation.
+    - SAUCE: (noup) arm64: Move unflatten_device_tree() call earlier.
+    - [Config] CONFIG_NUMA=y and CONFIG_NODES_SHIFT=2 on arm64
+    - SAUCE: (noup) arm64, numa: Add NUMA support for arm64 platforms.
+    - SAUCE: (noup) arm64, mm, numa: Add NUMA balancing support for arm64.
+
+  * vivid/linux: total ADT test failures (LP: #1558447)
+    - Revert "Revert "af_unix: Revert 'lock_interruptible' in stream receive code""
+
+  * [Hyper-V] patches to allow kdump crash through NMI (LP: #1558720)
+    - Drivers: hv: vmbus: Support handling messages on multiple CPUs
+    - Drivers: hv: vmbus: Support kexec on ws2012 r2 and above
+
+  * s390/pci: enforce fmb page boundary rule (LP: #1558625)
+    - s390/pci: enforce fmb page boundary rule
+
+  * s390/pci: backport upstream commits since v4.4 (LP: #1558624)
+    - s390/pci_dma: fix DMA table corruption with > 4 TB main memory
+    - page_to_phys() always returns a multiple of PAGE_SIZE
+    - s390/pci: provide ZPCI_ADDR macro
+    - s390/pci: improve ZPCI_* macros
+    - s390/pci: resize iomap
+    - s390/pci: fix bar check
+    - s390/pci: set error state for unusable functions
+    - s390/pci: remove iomap sanity checks
+    - s390/pci: remove pdev pointer from arch data
+    - s390/pci: add ioctl interface for CLP
+
+  * IMA-appraisal is unusable in Ubuntu 16.04 (LP: #1558553)
+    - [Config] CONFIG_SYSTEM_EXTRA_CERTIFICATE=y, CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE=4096
+    - KEYS: Use the symbol value for list size, updated by scripts/insert-sys-cert
+    - KEYS: Reserve an extra certificate symbol for inserting without recompiling
+    - SAUCE: (noup) KEYS: Support for inserting a certificate into x86 bzImage
+
+  * skb_warn_bad_offload Crash (LP: #1558025)
+    - ipv4: only create late gso-skb if skb is already set up with CHECKSUM_PARTIAL
+
+  * Add PCIe root complex to Cavium arm64 (LP: #1558342)
+    - [Config] CONFIG_PCI_HOST_COMMON=y
+    - [Config] CONFIG_PCI_HOST_THUNDER_PEM=y
+    - [Config] CONFIG_PCI_HOST_THUNDER_ECAM=y
+    - PCI: generic: Move structure definitions to separate header file
+    - PCI: generic: Add pci_host_common_probe(), based on gen_pci_probe()
+    - PCI: generic: Expose pci_host_common_probe() for use by other drivers
+    - PCI: thunder: Add PCIe host driver for ThunderX processors
+    - PCI: thunder: Add driver for ThunderX-pass{1,2} on-chip devices
+
+  * [Hyper-V] vmbus: Fix a bug in hv_need_to_signal_on_read() (LP: #1556264)
+    - SAUCE: (noup) Drivers: hv: vmbus: Fix a bug in hv_need_to_signal_on_read()
+
+  * Xenial update to v4.4.6 stable release (LP: #1558330)
+    - arm64: account for sparsemem section alignment when choosing vmemmap offset
+    - ARM: mvebu: fix overlap of Crypto SRAM with PCIe memory window
+    - ARM: dts: dra7: do not gate cpsw clock due to errata i877
+    - ARM: OMAP2+: hwmod: Introduce ti,no-idle dt property
+    - PCI: Allow a NULL "parent" pointer in pci_bus_assign_domain_nr()
+    - kvm: cap halt polling at exactly halt_poll_ns
+    - KVM: VMX: disable PEBS before a guest entry
+    - KVM: s390: correct fprs on SIGP (STOP AND) STORE STATUS
+    - KVM: PPC: Book3S HV: Sanitize special-purpose register values on guest exit
+    - KVM: MMU: fix ept=0/pte.u=1/pte.w=0/CR0.WP=0/CR4.SMEP=1/EFER.NX=0 combo
+    - KVM: MMU: fix reserved bit check for ept=0/CR0.WP=0/CR4.SMEP=1/EFER.NX=0
+    - s390/dasd: fix diag 0x250 inline assembly
+    - tracing: Fix check for cpu online when event is disabled
+    - dmaengine: at_xdmac: fix residue computation
+    - jffs2: reduce the breakage on recovery from halfway failed rename()
+    - ncpfs: fix a braino in OOM handling in ncp_fill_cache()
+    - ASoC: dapm: Fix ctl value accesses in a wrong type
+    - ASoC: samsung: Use IRQ safe spin lock calls
+    - ASoC: wm8994: Fix enum ctl accesses in a wrong type
+    - ASoC: wm8958: Fix enum ctl accesses in a wrong type
+    - ovl: ignore lower entries when checking purity of non-directory entries
+    - ovl: fix working on distributed fs as lower layer
+    - wext: fix message delay/ordering
+    - cfg80211/wext: fix message ordering
+    - can: gs_usb: fixed disconnect bug by removing erroneous use of kfree()
+    - iwlwifi: mvm: inc pending frames counter also when txing non-sta
+    - mac80211: minstrel: Change expected throughput unit back to Kbps
+    - mac80211: fix use of uninitialised values in RX aggregation
+    - mac80211: minstrel_ht: set default tx aggregation timeout to 0
+    - mac80211: minstrel_ht: fix a logic error in RTS/CTS handling
+    - mac80211: check PN correctly for GCMP-encrypted fragmented MPDUs
+    - mac80211: Fix Public Action frame RX in AP mode
+    - gpu: ipu-v3: Do not bail out on missing optional port nodes
+    - drm/amdgpu: Fix error handling in amdgpu_flip_work_func.
+    - drm/radeon: Fix error handling in radeon_flip_work_func.
+    - Revert "drm/radeon/pm: adjust display configuration after powerstate"
+    - userfaultfd: don't block on the last VM updates at exit time
+    - ovl: fix getcwd() failure after unsuccessful rmdir
+    - MIPS: Fix build error when SMP is used without GIC
+    - MIPS: smp.c: Fix uninitialised temp_foreign_map
+    - block: don't optimize for non-cloned bio in bio_get_last_bvec()
+    - target: Drop incorrect ABORT_TASK put for completed commands
+    - ld-version: Fix awk regex compile failure
+    - Linux 4.4.6
+
+  * linux fails to load x.509 built-in certificate (LP: #1557250)
+    - lib/mpi: Endianness fix
+
+  * s390/kconfig: setting for CONFIG...9P.... (LP: #1557994)
+    - [Config] CONFIG_NET_9P=m for s390x
+
+  * mlx5_core kernel trace after "ethtool -C eth1 adaptive-rx on" flow
+    (LP: #1557950)
+    - net/mlx5e: Don't try to modify CQ moderation if it is not supported
+    - net/mlx5e: Don't modify CQ before it was created
+
+  * [Feature]SD/SDIO/eMMC support for Broxton-P (LP: #1520454)
+    - mmc: sdhci: Do not BUG on invalid vdd
+    - mmc: enable MMC/SD/SDIO device to suspend/resume asynchronously
+    - mmc: It is not an error for the card to be removed while suspended
+
+  * s390/kconfig: disable CONFIG_VIRTIO_MMIO (LP: #1557689)
+    - [Config] CONFIG_VIRTIO_MMIO=n for s390x
+
+  * s390/kconfig: CONFIG_NUMA without CONFIG_NUMA_EMU does not make any sense on s390x (LP: #1557690)
+    - [Config] CONFIG_NUMA_EMU=y for s390x
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] git-ubuntu-log -- prevent bug references being split
+    - [Debian] git-ubuntu-log -- git log output is UTF-8
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Mar 2016 13:18:58 -0600
+
+linux (4.4.0-14.30) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1557508
+
+  * Current 4.4 kernel won't boot on powerpc (LP: #1557130)
+    - powerpc: Fix dedotify for binutils >= 2.26
+
+  * ZFS: send fails to transmit some holes [corruption] (LP: #1557151)
+    - Illumos 6370 - ZFS send fails to transmit some holes
+
+  * Request to cherry-pick uvcvideo patch for Xenial kernel support of RealSense
+    camera (LP: #1557138)
+    - UVC: Add support for ds4 depth camera
+
+  * use after free of task_struct->numa_faults in task_numa_find_cpu (LP: #1527643)
+    - sched/numa: Fix use-after-free bug in the task_numa_compare
+
+  * overlay fs regression: chmod fails with "Operation not permitted" on chowned
+    files (LP: #1555997)
+    - ovl: copy new uid/gid into overlayfs runtime inode
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Dump stack when X.509 certificates cannot be loaded
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 14 Mar 2016 07:16:19 -0600
+
+linux (4.4.0-13.29) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1556247
+
+  * s390/mm: four page table levels vs. fork (LP: #1556141)
+    - s390/mm: four page table levels vs. fork
+
+  * [Hyper-V] network performance patches for Xenial 16.04 (LP: #1556037)
+    - hv_netvsc: use skb_get_hash() instead of a homegrown implementation
+    - hv_netvsc: cleanup netdev feature flags for netvsc
+
+  * fails to boot on megaraid (LP: #1552903)
+    - SAUCE: (noup) megaraid_sas: Don't issue kill adapter for MFI controllers in
+      case of PD list DCMD failure
+
+  * ALSA: hda - add codec support for Kabylake display audio codec (LP: #1556002)
+    - ALSA: hda - add codec support for Kabylake display audio codec
+
+  * Backport upstream bugfixes to ubuntu-16.04 (LP: #1555765)
+    - cpufreq: powernv: Free 'chips' on module exit
+    - cpufreq: powernv: Hot-plug safe the kworker thread
+    - cpufreq: powernv: Remove cpu_to_chip_id() from hot-path
+    - cpufreq: powernv/tracing: Add powernv_throttle tracepoint
+    - cpufreq: powernv: Replace pr_info with trace print for throttle event
+    - SAUCE: (noup) cpufreq: powernv: Fix bugs in powernv_cpufreq_{init/exit}
+
+  * Linux netfilter IPT_SO_SET_REPLACE memory corruption (LP: #1555338)
+    - SAUCE: [nf,v2] netfilter: x_tables: don't rely on well-behaving userspace
+
+  * integer overflow in xt_alloc_table_info (LP: #1555353)
+    - SAUCE: (noup) netfilter: x_tables: check for size overflow
+
+  * linux: auto-generate the reconstruct information from the git tag (LP: #1555543)
+    - [Packaging] reconstruct -- automatically reconstruct against base tag
+    - [Config] reconstruct -- update to autoreconstruct output
+    - [Packaging] reconstruct -- update when inserting final changes
+
+  * Xenial update to v4.4.5 stable release (LP: #1555640)
+    - use ->d_seq to get coherency between ->d_inode and ->d_flags
+    - drivers: sh: Restore legacy clock domain on SuperH platforms
+    - Btrfs: fix deadlock running delayed iputs at transaction commit time
+    - btrfs: Fix no_space in write and rm loop
+    - btrfs: async-thread: Fix a use-after-free error for trace
+    - block: Initialize max_dev_sectors to 0
+    - PCI: keystone: Fix MSI code that retrieves struct pcie_port pointer
+    - parisc: Fix ptrace syscall number and return value modification
+    - mips/kvm: fix ioctl error handling
+    - kvm: x86: Update tsc multiplier on change.
+    - fbcon: set a default value to blink interval
+    - cifs: fix out-of-bounds access in lease parsing
+    - CIFS: Fix SMB2+ interim response processing for read requests
+    - Fix cifs_uniqueid_to_ino_t() function for s390x
+    - vfio: fix ioctl error handling
+    - KVM: x86: fix root cause for missed hardware breakpoints
+    - arm/arm64: KVM: Fix ioctl error handling
+    - iommu/amd: Apply workaround for ATS write permission check
+    - iommu/amd: Fix boot warning when device 00:00.0 is not iommu covered
+    - iommu/vt-d: Use BUS_NOTIFY_REMOVED_DEVICE in hotplug path
+    - target: Fix WRITE_SAME/DISCARD conversion to linux 512b sectors
+    - drm/ast: Fix incorrect register check for DRAM width
+    - drm/radeon/pm: update current crtc info after setting the powerstate
+    - drm/amdgpu/pm: update current crtc info after setting the powerstate
+    - drm/amdgpu: apply gfx_v8 fixes to gfx_v7 as well
+    - drm/amdgpu/gfx8: specify which engine to wait before vm flush
+    - drm/amdgpu: return from atombios_dp_get_dpcd only when error
+    - libata: fix HDIO_GET_32BIT ioctl
+    - libata: Align ata_device's id on a cacheline
+    - block: bio: introduce helpers to get the 1st and last bvec
+    - writeback: flush inode cgroup wb switches instead of pinning super_block
+    - Adding Intel Lewisburg device IDs for SATA
+    - arm64: vmemmap: use virtual projection of linear region
+    - PM / sleep / x86: Fix crash on graph trace through x86 suspend
+    - ata: ahci: don't mark HotPlugCapable Ports as external/removable
+    - tracing: Do not have 'comm' filter override event 'comm' field
+    - pata-rb532-cf: get rid of the irq_to_gpio() call
+    - Btrfs: fix loading of orphan roots leading to BUG_ON
+    - Revert "jffs2: Fix lock acquisition order bug in jffs2_write_begin"
+    - jffs2: Fix page lock / f->sem deadlock
+    - Fix directory hardlinks from deleted directories
+    - dmaengine: pxa_dma: fix cyclic transfers
+    - adv7604: fix tx 5v detect regression
+    - ALSA: usb-audio: Add a quirk for Plantronics DA45
+    - ALSA: ctl: Fix ioctls for X32 ABI
+    - ALSA: hda - Fix mic issues on Acer Aspire E1-472
+    - ALSA: rawmidi: Fix ioctls X32 ABI
+    - ALSA: timer: Fix ioctls for X32 ABI
+    - ALSA: pcm: Fix ioctls for X32 ABI
+    - ALSA: seq: oss: Don't drain at closing a client
+    - ALSA: hdspm: Fix wrong boolean ctl value accesses
+    - ALSA: hdsp: Fix wrong boolean ctl value accesses
+    - ALSA: hdspm: Fix zero-division
+    - ALSA: timer: Fix broken compat timer user status ioctl
+    - usb: chipidea: otg: change workqueue ci_otg as freezable
+    - USB: cp210x: Add ID for Parrot NMEA GPS Flight Recorder
+    - USB: qcserial: add Dell Wireless 5809e Gobi 4G HSPA+ (rev3)
+    - USB: qcserial: add Sierra Wireless EM74xx device ID
+    - USB: serial: option: add support for Telit LE922 PID 0x1045
+    - USB: serial: option: add support for Quectel UC20
+    - MIPS: scache: Fix scache init with invalid line size.
+    - MIPS: traps: Fix SIGFPE information leak from `do_ov' and `do_trap_or_bp'
+    - ubi: Fix out of bounds write in volume update code
+    - i2c: brcmstb: allocate correct amount of memory for regmap
+    - thermal: cpu_cooling: fix out of bounds access in time_in_idle
+    - block: check virt boundary in bio_will_gap()
+    - block: get the 1st and last bvec via helpers
+    - drm/i915: more virtual south bridge detection
+    - drm/i915: refine qemu south bridge detection
+    - modules: fix longstanding /proc/kallsyms vs module insertion race.
+    - drm/amdgpu: fix topaz/tonga gmc assignment in 4.4 stable
+    - Linux 4.4.5
+
+  * QEMU: causes vCPU steal time overflow on live migration (LP: #1494350)
+    - x86/mm: Fix slow_virt_to_phys() for X86_PAE again
+
+  * TPM2.0 trusted keys fixes (LP: #1398274)
+    - tpm_tis: further simplify calculation of ordinal duration
+    - tpm_tis: Use devm_free_irq not free_irq
+    - tpm_tis: Ensure interrupts are disabled when the driver starts
+    - tpm: rework tpm_get_timeouts()
+    - tpm_tis: Get rid of the duplicate IRQ probing code
+    - tpm_tis: Refactor the interrupt setup
+    - tpm_tis: Tighten IRQ auto-probing
+    - tpm_ibmvtpm: properly handle interrupted packet receptions
+
+  * linux: review all versioned depends/conflicts/replaces/breaks for validility (LP: #1555033)
+    - [Config] control.stub.in -- review versioned Build-Depends:
+    - [Config] control.stub.in -- review versioned
+      Depends/Breaks/Conflicts/Replaces
+    - [Config] flavour-control.stub -- review versioned Breaks/Conflicts/Replaces
+    - [Config] x86 vars.* -- review versioned Breaks/Conflicts/Replaces
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 09 Mar 2016 05:11:51 -0700
+
+linux (4.4.0-12.28) xenial; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - reconstruct: Work around orig tarball packaging limitiations
+      Fixes FTBS
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Mar 2016 13:26:08 -0700
+
+linux (4.4.0-12.27) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1554704
+
+  * Fails to detect (second) display (LP: #1543683)
+    - drm/i915: Fix hpd live status bits for g4x
+
+  * s390x -- various configuration changes (LP: #1543165)
+    - [Config] s390x -- enable CONFIG_NUMA
+    - [Config] s390x -- disable CONFIG_NET_VENDOR_EMULEX
+    - [Config] s390x -- disable CONFIG_NET_VENDOR_SYNOPSYS
+    - [Config] s390x -- disable CONFIG_NVMEM
+    - [Config] s390x -- switch preempt mode to none
+
+  * Radeon hybrid graphics problem on resume (LP: #1554608)
+    - Revert "drm/radeon: call hpd_irq_event on resume"
+
+  * Pull in upstream AMD code (amdgpu) in Xenial (LP: #1546572)
+    - [Config] CONFIG_DRM_AMD_POWERPLAY=y
+    - drm/amdgpu: use $(src) in Makefile (v2)
+    - drm/radeon: constify radeon_asic_ring structures
+    - drm/amdgpu: add a callback for reading the bios from the rom directly
+    - drm/amdgpu: add read_bios_from_rom callback for CI parts
+    - drm/amdgpu: add read_bios_from_rom callback for VI parts
+    - drm/amdgpu: Use new read bios from rom callback
+    - drm/amdgpu: Use unlocked gem unreferencing
+    - drm/radeon: Use unlocked gem unreferencing
+    - drm/amd: add new gfx8 register definitions for EDC
+    - drm/amdgpu: add EDC support for CZ (v3)
+    - drm/amd: abstract kernel rq and normal rq to priority of run queue
+    - drm/amdgpu/gfx8: Enable interrupt on ME1_PIPE3
+    - drm/amdgpu/gfx8: update PA_SC_RASTER_CONFIG:PKR_MAP only
+    - drm/amdgpu: update rev id register for VI
+    - drm/amdgpu: add more debugging output for driver failures
+    - drm/amdgpu: add entity only when first job come
+    - drm/amdgpu: handle error case for ctx
+    - drm/amdgpu: unify AMDGPU_CTX_MAX_CS_PENDING and amdgpu_sched_jobs
+    - drm/amdgpu: change default sched jobs to 32
+    - drm/amdgpu: limit visible vram if it's smaller than the BAR
+    - drm/amdgpu: restrict the sched jobs number to power of two
+    - drm/amdgpu: put VM page tables directly into duplicates list
+    - drm/amdgpu: split VM PD and PT handling during CS
+    - drm/amdgpu: keep the PTs validation list in the VM v2
+    - drm/radeon: Update radeon_get_vblank_counter_kms()
+    - drm/radeon: only increment sync_seq when a fence is really emitted
+    - drm/fb-helper: Use proper plane mask for fb cleanup
+    - drm/amdgpu: fix dp link rate selection (v2)
+    - drm/radeon: fix dp link rate selection (v2)
+    - drm/amdgpu: share struct amdgpu_pm_state_type with powerplay module
+    - drm/amdgpu: mv some definition from amdgpu_acpi.c to amdgpu_acpi.h
+    - drm/amdgpu: mv amdgpu_acpi.h to amd/include/amd_acpi.h
+    - drm/amdgpu: implement new cgs interface for acpi function
+    - drm/amdgpu: implement cgs interface to query system info
+    - drm/amdgpu: add new cgs interface to get display info (v2)
+    - drm/amd/powerplay: add basic powerplay framework
+    - drm/amdgpu: disable legacy path of firmware check if powerplay is enabled
+    - drm/amdgpu: export amd_powerplay_func to amdgpu and other ip block
+    - drm/amd/powerplay: add SMU manager sub-component
+    - drm/amd/powerplay: add hardware manager sub-component
+    - SAUCE: amd: Include errno.h
+    - drm/amd/powerplay: add Carrizo smu support
+    - drm/amd/powerplay: add Carrizo dpm support
+    - drm/amd/powerplay: add CG and PG support for carrizo
+    - drm/amd/powerplay: add event manager sub-component
+    - drm/amd/powerplay: implement functions of amd_powerplay_func
+    - drm/amd/powerplay: Add ixSWRST_COMMAND_1 in bif_5_0_d.h
+    - drm/amd/powerplay: Move smu7*.h from amdgpu to powerplay.
+    - drm/amd/powerplay: add header file for tonga smu and dpm
+    - drm/amd/powerplay: Add Tonga SMU support
+    - drm/amd/powerplay: add Tonga dpm support (v3)
+    - drm/amd/powerplay: add/update headers for Fiji SMU and DPM
+    - drm/amd/powerplay: update atomctrl for fiji
+    - drm/amd/powerplay: add Fiji SMU support.
+    - drm/amd/powerplay: add Fiji DPM support.
+    - drm/amdgpu: add amdgpu.powerplay module option
+    - drm/amd/amdgpu: enable powerplay and smc firmware loading for Fiji.
+    - drm/amdgpu/powerplay: add function point in hwmgr_funcs for program display gap
+    - drm/amdgpu/poweprlay: export program display gap function to eventmgr
+    - drm/amdgpu/powerplay: implement pem_task for display_configuration_change
+    - drm/amdgpu/powerplay: program display gap for tonga.
+    - drm/amdgpu: enable powerplay module by default for tonga.
+    - drm/amdgpu: enable powerplay module by default for fiji.
+    - drm/amdgpu/powerplay: add some definition for other ip block to update cg pg.
+    - drm/amd/powerplay: add new function point in hwmgr_func for CG/PG.
+    - drm/amd/powerplay: Add CG and PG support for tonga
+    - drm/amdgpu/powerplay: add new function point in hwmgr_funcs for thermal control
+    - drm/amdgpu/powerplay: mv ppinterrupt.h to inc folder to share with other submodule.
+    - drm/amdgpu/powerplay: add thermal control interface in hwmgr.
+    - drm/amdgpu/powerplay: enable thermal interrupt task in eventmgr.
+    - drm/amdgpu/powerplay: implement thermal control for tonga.
+    - drm/amdgpu/powerplay: implement fan control interface in amd_powerplay_funcs
+    - drm/amdgpu: export fan control functions to amdgpu
+    - drm/amdgpu: enable sysfs interface for powerplay
+    - drm/amdgpu: support per device powerplay enablement (v2)
+    - drm/amd/powerplay: add and export hwmgr interface to eventmgr to check hw states.
+    - drm/amd/powerplay: implement new funcs to check current states for tonga.
+    - drm/amd/powerplay: refine the logic of whether need to update power state.
+    - drm/amd/powerplay/tonga: enable pcie and mclk forcing for low
+    - drm/amd/powerplay/fiji: enable pcie and mclk forcing for low
+    - drm/amdgpu: extract pcie helpers to common header
+    - drm: add drm_pcie_get_max_link_width helper (v2)
+    - drm/amdgpu: store pcie gen mask and link width
+    - drm/amdgpu/cgs: add sys info query for pcie gen and link width
+    - drm/amdgpu/powerplay/tonga: query supported pcie info from cgs (v2)
+    - drm/amdgpu/powerplay/fiji: query supported pcie info from cgs (v2)
+    - drm/amd/powerplay: fix boolreturn.cocci warnings
+    - drm/amd/powerplay/tonga: Add UVD DPM init
+    - drm/amd/amdgpu: add gfx clock gating support for Fiji.
+    - drm/amd/amdgpu: add gmc clock gating support for Fiji.
+    - drm/amdgpu: add sdma clock gating support for Fiji.
+    - drm/amd/powerplay: add parts of system clock gating support for Fiji. (v2)
+    - drm/amd/powerplay: enable clock gating for Fiji.
+    - drm/amd/powerplay: add atomctrl function to calculate CZ sclk dividers
+    - drm/amd/powerplay: implement smc state upload for CZ
+    - drm/amd/powerplay: fix warning of cast to pointer from integer of different size.
+    - drm/amd/powerplay: fix warning of cast to pointer from integer of different size.
+    - drm/amd/powerplay: add new function point in hwmgr.
+    - drm/amd/powerplay: add smc msg for NB P-State switch
+    - drm/amd/powerplay: export interface to DAL to init/change display configuration.
+    - drm/amd/powerplay: enable set_cpu_power_state task. (v2)
+    - drm/amd/powerplay: enable/disable NB pstate feature for Carrizo.
+    - drm/amd/powerplay: Add PPLib debug print macro.
+    - drm/amdgpu: rename tonga_smumgr.h to tonga_smum.h
+    - drm/amdgpu: rename fiji_smumgr.h to fiji_smum.h
+    - drm/amd/powerplay: add multimedia power gating support for Fiji.
+    - drm/amd/amdgpu: add uvd6.0 clock gating support. (v2)
+    - drm/amd/amdgpu: add vce3.0 clock gating support. (v2)
+    - drm/amd/amdgpu: enable uvd&vce clock gating for Fiji.
+    - drm/amdgpu: Prepare DKMS build for powerplay module.
+    - drm/amd/powerplay: add display configeration changed function in hwmgr for Fiji.
+    - drm/amd/powerplay: Add thermal protection support for Fiji.
+    - drm/amd/powerplay: Fix a bug in fan control setting default mode for Tonga and Fiji.
+    - drm/amd/powerplay: add functions set/get_fan_control_mode in hwmgr for Tonga.
+    - drm/amd/powerplay: add functions set/get_fan_control_mode in hwmgr for Fiji.
+    - drm/amd/powerplay: fix boolreturn.cocci warnings
+    - drm/amd/powerplay: fix bug that dpm funcs in debugfs/sysfs missing.
+    - drm/amd/powerplay: check whether enable dpm in powerplay.
+    - drm/amd/powerplay: move shared function of vi to hwmgr. (v2)
+    - drm/amdgpu/powerplay: enable sysfs and debugfs interfaces late
+    - drm/amd/powerplay: display gpu load when print performance for tonga.
+    - drm/powerplay: add debugging output to tonga_processpptables.c
+    - drm/powerplay: add debugging output to processpptables.c
+    - drm/powerplay/hwmgr: log errors in tonga_hwmgr_backend_init
+    - drm/amd/powerplay: Don't return an error if fan table is missing
+    - amd\powerplay Implement get dal power level
+    - amd/powerplay: Fix get dal power level
+    - amd/powerplay: Add structures required to report configuration change
+    - drm/amdgpu/powerplay: Program a calculated value as Deep Sleep clock.
+    - drm/amd/powerplay: add point check to avoid NULL point hang.
+    - drm/amd/powerplay: check whether need to enable thermal control. (v2)
+    - drm/amd/powerplay: show gpu load when print gpu performance for Cz. (v2)
+    - drm: powerplay: use div64_s64 instead of do_div
+    - drm/amd/powerplay: fix a reversed condition
+    - drm/amdgpu/cgs: cleanup some indenting
+    - drm/amd/powerplay: precedence bug in init_non_clock_fields()
+    - drm/amdgpu: fix NULL in vm_grab_id while S3 back
+    - drm/amd/powerplay: fix bug that NULL checks are reversed.
+    - drm/amd/powerplay: fix Smatch static checker warnings with indenting (v2)
+    - drm/amd/powerplay: fix Smatch static checker warnings
+    - drm/amd/powerplay: add powerplay valid check to avoid null point. (v2)
+    - drm/amd/powerplay: Reload and initialize the smc firmware on powerplay resume.
+    - drm/amdgpu: Show gpu load when display gpu performance for Ci.
+    - drm/amdgpu: Show gpu load when display gpu performance for Fiji of VI.
+    - drm/amdgpu: fix hex/decimal bug when show gpu load.
+    - drm/amd/powerplay: add thermal control task when resume.
+    - drm/amd/powerplay: enable set boot state task
+    - drm/amd/powerplay: enable power down asic task. (v2)
+    - drm/amd/powerplay: implement power down asic task for CZ
+    - drm/amdgpu: add warning to amdgpu_bo_gpu_offset() v2
+    - drm/amdgpu/cgs: add an interface to access PCI resources
+    - drm/amdgpu: add irq domain support
+    - drm/amdgpu/powerplay: include asm/div64.h for do_div()
+    - drm/sysfs: use kobj_to_dev()
+    - drm/amd/powerplay: fix static checker warning for return meaningless value.
+    - drm/amdgpu/cz: add code to enable forcing UVD clocks
+    - drm/amdgpu/cz: add code to enable forcing VCE clocks
+    - drm/amdgpu/cz: force uvd clocks when sclks are forced
+    - drm/amdgpu/cz: force vce clocks when sclks are forced
+    - drm/amdgpu: use kobj_to_dev()
+    - drm/radeon: use kobj_to_dev()
+    - drm/ttm: fix adding foreign BOs to the LRU during init v2
+    - drm/ttm: fix adding foreign BOs to the swap LRU
+    - drm/ttm: add ttm_bo_move_to_lru_tail function v2
+    - drm/amdgpu: move VM page tables to the LRU end on CS v2
+    - drm/amdgpu: validate duplicates first
+    - drm/amdgpu: add missing irq.h include
+    - drm/fb_cma_helper: Remove implicit call to disable_unused_functions
+    - drm/amdgpu: Add some tweaks to gfx 8 soft reset
+    - amdkfd: don't open-code memdup_user()
+    - amdkfd: Copy from the proper user command pointer
+    - drm/amdgpu: Use drm_calloc_large for VM page_tables array
+    - amd/powerplay: disable powerplay by default initially
+    - drm/amdgpu: Allow the driver to load if amdgpu.powerplay=1 on asics without powerplay support
+    - drm/atomic-helper: Export framebuffer_changed()
+    - drm/amd/amdgpu: Improve amdgpu_dpm* macros to avoid unexpected result (v2)
+    - drm/amdgpu: add a message to indicate when powerplay is enabled (v2)
+    - drm/amdgpu: fix next_rptr handling for debugfs
+    - drm/radeon: Ensure radeon bo is unreserved in radeon_gem_va_ioctl
+    - drm/radeon: only init fbdev if we have connectors
+    - drm/amdgpu: don't init fbdev if we don't have any connectors
+    - drm/amd/powerplay: Update SMU firmware loading for Stoney
+    - drm/amdgpu: fix non-ANSI declaration of amdgpu_amdkfd_gfx_*_get_functions()
+    - drm/amdkfd: Remove unnecessary cast in kfree
+    - drm/amdgpu: only move pt bos in LRU list on success
+    - drm/amdgpu: mask out WC from BO on unsupported arches
+    - drm/amdgpu/gfx8: enable cp inst/reg error interrupts
+    - drm/amdgpu/gfx7: enable cp inst/reg error interrupts
+    - drm/amdgpu: load MEC ucode manually on iceland
+    - drm/amdgpu: disable uvd and vce clockgating on Fiji
+    - drm/amdgpu: add pcie cap module parameters (v2)
+    - drm/amdgpu/cik: don't mess with aspm if gpu is root bus
+    - drm/amdgpu/dpm/ci: switch over to the common pcie caps interface
+    - drm/amdgpu: handle uvd pg flags properly
+    - drm/amdgpu: handle vce pg flags properly
+    - drm/amdgpu: clean up vce pg flags for cz/st
+    - drm/amdgpu: be consistent with uvd cg flags
+    - drm/amd/powerplay/cz: disable uvd pg
+    - drm/amd/powerplay/cz: disable vce pg
+    - drm/amd/powerplay/tonga: disable uvd pg
+    - drm/amd/powerplay/tonga: disable vce pg
+    - drm/amdgpu: add a cgs interface to fetch cg and pg flags
+    - drm/amdgpu: remove unused cg defines
+    - drma/dmgpu: move cg and pg flags into shared headers
+    - drm/amdgpu/tonga: plumb pg flags through to powerplay
+    - drm/amdgpu/cz: plumb pg flags through to powerplay
+    - SAUCE: drm/amdgpu/cz: enable/disable vce dpm even if vce pg is disabled
+
+  * mlx4_core Set UAR page size to 4KB regardless of system page size (LP:
+    #1552632)
+    - net/mlx4_core: Set UAR page size to 4KB regardless of system page size
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_CAVIUM_ERRATUM_27456=y
+
+  * Miscellaneous upstream changes
+    - net: thunderx: Fix for Qset error due to CQ full
+    - ahci: Workaround for ThunderX Errata#22536
+    - arm64: Add workaround for Cavium erratum 27456
+    - tipc: fix nullptr crash during subscription cancel
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 07 Mar 2016 05:04:22 -0700
+
+linux (4.4.0-11.26) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1553391
+
+  * Xenial update to v4.4.4 stable release (LP: #1553179)
+    - af_iucv: Validate socket address length in iucv_sock_bind()
+    - gro: Make GRO aware of lightweight tunnels.
+    - net: dp83640: Fix tx timestamp overflow handling.
+    - tunnels: Allow IPv6 UDP checksums to be correctly controlled.
+    - lwt: fix rx checksum setting for lwt devices tunneling over ipv6
+    - tcp: fix NULL deref in tcp_v4_send_ack()
+    - af_unix: fix struct pid memory leak
+    - pptp: fix illegal memory access caused by multiple bind()s
+    - sctp: allow setting SCTP_SACK_IMMEDIATELY by the application
+    - net: dsa: fix mv88e6xxx switches
+    - tipc: fix connection abort during subscription cancel
+    - inet: frag: Always orphan skbs inside ip_defrag()
+    - switchdev: Require RTNL mutex to be held when sending FDB notifications
+    - tcp: beware of alignments in tcp_get_info()
+    - ipv6: enforce flowi6_oif usage in ip6_dst_lookup_tail()
+    - ipv6/udp: use sticky pktinfo egress ifindex on connect()
+    - ipv6: addrconf: Fix recursive spin lock call
+    - ipv6: fix a lockdep splat
+    - unix: correctly track in-flight fds in sending process user_struct
+    - tcp: do not drop syn_recv on all icmp reports
+    - net:Add sysctl_max_skb_frags
+    - tg3: Fix for tg3 transmit queue 0 timed out when too many gso_segs
+    - enic: increment devcmd2 result ring in case of timeout
+    - sctp: translate network order to host order when users get a hmacid
+    - net: Copy inner L3 and L4 headers as unaligned on GRE TEB
+    - flow_dissector: Fix unaligned access in __skb_flow_dissector when used by
+      eth_get_headlen
+    - bpf: fix branch offset adjustment on backjumps after patching ctx expansion
+    - bonding: Fix ARP monitor validation
+    - ipv4: fix memory leaks in ip_cmsg_send() callers
+    - af_unix: Don't set err in unix_stream_read_generic unless there was an error
+    - af_unix: Guard against other == sk in unix_dgram_sendmsg
+    - tipc: fix premature addition of node to lookup table
+    - tcp: md5: release request socket instead of listener
+    - qmi_wwan: add "4G LTE usb-modem U901"
+    - net/mlx4_en: Count HW buffer overrun only once
+    - net/mlx4_en: Avoid changing dev->features directly in run-time
+    - l2tp: Fix error creating L2TP tunnels
+    - pppoe: fix reference counting in PPPoE proxy
+    - net_sched fix: reclassification needs to consider ether protocol changes
+    - route: check and remove route cache when we get route
+    - tcp/dccp: fix another race at listener dismantle
+    - IFF_NO_QUEUE: Fix for drivers not calling ether_setup()
+    - rtnl: RTM_GETNETCONF: fix wrong return value
+    - tipc: unlock in error path
+    - unix_diag: fix incorrect sign extension in unix_lookup_by_ino
+    - sctp: Fix port hash table size computation
+    - ext4: fix bh->b_state corruption
+    - ARM: debug-ll: fix BCM63xx entry for multiplatform
+    - arm64: errata: Add -mpc-relative-literal-loads to build flags
+    - KVM: s390: fix guest fprs memory leak
+    - devm_memremap: Fix error value when memremap failed
+    - drm/gma500: Use correct unref in the gem bo create function
+    - ARM: 8457/1: psci-smp is built only for SMP
+    - lib/ucs2_string: Add ucs2 -> utf8 helper functions
+    - efi: Use ucs2_as_utf8 in efivarfs instead of open coding a bad version
+    - efi: Do variable name validation tests in utf8
+    - efi: Make our variable validation list include the guid
+    - efi: Make efivarfs entries immutable by default
+    - efi: Add pstore variables to the deletion whitelist
+    - lib/ucs2_string: Correct ucs2 -> utf8 conversion
+    - bcache: fix a livelock when we cause a huge number of cache misses
+    - bcache: Add a cond_resched() call to gc
+    - bcache: clear BCACHE_DEV_UNLINK_DONE flag when attaching a backing device
+    - bcache: fix a leak in bch_cached_dev_run()
+    - bcache: unregister reboot notifier if bcache fails to unregister device
+    - bcache: allows use of register in udev to avoid "device_busy" error.
+    - bcache: Change refill_dirty() to always scan entire disk if necessary
+    - dm thin: fix race condition when destroying thin pool workqueue
+    - can: ems_usb: Fix possible tx overflow
+    - usb: dwc3: Fix assignment of EP transfer resources
+    - USB: cp210x: add IDs for GE B650V3 and B850V3 boards
+    - USB: option: add support for SIM7100E
+    - USB: option: add "4G LTE usb-modem U901"
+    - drivers: android: correct the size of struct binder_uintptr_t for
+      BC_DEAD_BINDER_DONE
+    - spi: omap2-mcspi: Prevent duplicate gpio_request
+    - iw_cxgb3: Fix incorrectly returning error on success
+    - drm/i915: shut up gen8+ SDE irq dmesg noise
+    - ocfs2: unlock inode if deleting inode from orphan fails
+    - mm: thp: fix SMP race condition between THP page fault and MADV_DONTNEED
+    - mm: numa: quickly fail allocations for NUMA balancing on full nodes
+    - genirq: Validate action before dereferencing it in handle_irq_event_percpu()
+    - clocksource/drivers/vt8500: Increase the minimum delta
+    - s390/kvm: remove dependency on struct save_area definition
+    - KVM: s390: fix memory overwrites when vx is disabled
+    - Btrfs: add missing brelse when superblock checksum fails
+    - Btrfs: igrab inode in writepage
+    - btrfs: statfs: report zero available if metadata are exhausted
+    - Btrfs: send, don't BUG_ON() when an empty symlink is found
+    - Btrfs: fix number of transaction units required to create symlink
+    - Btrfs: fix transaction handle leak on failure to create hard link
+    - Btrfs: Initialize btrfs_root->highest_objectid when loading tree root and
+      subvolume roots
+    - btrfs: initialize the seq counter in struct btrfs_device
+    - s390: fix normalization bug in exception table sorting
+    - s390/dasd: prevent incorrect length error under z/VM after PAV changes
+    - s390/dasd: fix refcount for PAV reassignment
+    - s390/dasd: fix performance drop
+    - uml: flush stdout before forking
+    - uml: fix hostfs mknod()
+    - um: link with -lpthread
+    - locks: fix unlock when fcntl_setlk races with a close
+    - rtlwifi: rtl_pci: Fix kernel panic
+    - rtlwifi: rtl8192cu: Add missing parameter setup
+    - rtlwifi: rtl8192ce: Fix handling of module parameters
+    - rtlwifi: rtl8192de: Fix incorrect module parameter descriptions
+    - rtlwifi: rtl8723ae: Fix initialization of module parameters
+    - rtlwifi: rtl8192se: Fix module parameter initialization
+    - rtlwifi: rtl8188ee: Fix module parameter initialization
+    - rtlwifi: rtl8723be: Fix module parameter initialization
+    - mei: fix fasync return value on error
+    - mei: validate request value in client notify request ioctl
+    - namei: ->d_inode of a pinned dentry is stable only for positives
+    - rc: sunxi-cir: Initialize the spinlock properly
+    - media: dvb-core: Don't force CAN_INVERSION_AUTO in oneshot mode
+    - si2157: return -EINVAL if firmware blob is too big
+    - gspca: ov534/topro: prevent a division by 0
+    - vb2: fix a regression in poll() behavior for output,streams
+    - tda1004x: only update the frontend properties if locked
+    - dm space map metadata: remove unused variable in brb_pop()
+    - dm snapshot: fix hung bios when copy error occurs
+    - dm: fix dm_rq_target_io leak on faults with .request_fn DM w/ blk-mq paths
+    - coresight: checking for NULL string in coresight_name_match()
+    - irqchip/omap-intc: Add support for spurious irq handling
+    - irqchip/mxs: Add missing set_handle_irq()
+    - irqchip/atmel-aic: Fix wrong bit operation for IRQ priority
+    - irqchip/gic-v3-its: Fix double ICC_EOIR write for LPI in EOImode==1
+    - posix-clock: Fix return code on the poll method's error path
+    - clockevents/tcb_clksrc: Prevent disabling an already disabled clock
+    - mmc: usdhi6rol0: handle NULL data in timeout
+    - mmc: sdhci-pci: Do not default to 33 Ohm driver strength for Intel SPT
+    - mmc: sdio: Fix invalid vdd in voltage switch power cycle
+    - mmc: mmc: Fix incorrect use of driver strength switching HS200 and HS400
+    - mmc: sdhci: Fix sdhci_runtime_pm_bus_on/off()
+    - mmc: core: Enable tuning according to the actual timing
+    - mmc: mmci: fix an ages old detection error
+    - mmc: sdhci-acpi: Fix card detect race for Intel BXT/APL
+    - mmc: pxamci: fix again read-only gpio detection polarity
+    - mmc: sdhci-pci: Fix card detect race for Intel BXT/APL
+    - mmc: sdhci: Allow override of mmc host operations
+    - mmc: sdhci: Allow override of get_cd() called from sdhci_request()
+    - Bluetooth: Use continuous scanning when creating LE connections
+    - Bluetooth: Add support of Toshiba Broadcom based devices
+    - Bluetooth: Fix incorrect removing of IRKs
+    - Bluetooth: 6lowpan: Fix kernel NULL pointer dereferences
+    - Bluetooth: 6lowpan: Fix handling of uncompressed IPv6 packets
+    - time: Avoid signed overflow in timekeeping_get_ns()
+    - cputime: Prevent 32bit overflow in time[val|spec]_to_cputime()
+    - Revert "MIPS: Fix PAGE_MASK definition"
+    - MIPS: Loongson-3: Fix SMP_ASK_C0COUNT IPI handler
+    - MIPS: hpet: Choose a safe value for the ETIME check
+    - MIPS: Fix some missing CONFIG_CPU_MIPSR6 #ifdefs
+    - MIPS: Fix buffer overflow in syscall_get_arguments()
+    - EDAC: Robustify workqueues destruction
+    - EDAC, mc_sysfs: Fix freeing bus' name
+    - sparc64: fix incorrect sign extension in sys_sparc64_personality
+    - clk: exynos: use irqsave version of spin_lock to avoid deadlock with irqs
+    - regulator: axp20x: Fix GPIO LDO enable value for AXP22x
+    - regulator: mt6311: MT6311_REGULATOR needs to select REGMAP_I2C
+    - virtio_balloon: fix race by fill and leak
+    - virtio_balloon: fix race between migration and ballooning
+    - virtio_pci: fix use after free on release
+    - drm/vmwgfx: Fix an incorrect lock check
+    - drm/vmwgfx: Fix a width / pitch mismatch on framebuffer updates
+    - drm/vmwgfx: respect 'nomodeset'
+    - drm/amdgpu: Fix off-by-one errors in amdgpu_vm_bo_map
+    - drm/amdgpu: call hpd_irq_event on resume
+    - drm/amdgpu: fix lost sync_to if scheduler is enabled.
+    - drm/amdgpu: fix tonga smu resume
+    - drm/amdgpu: fix amdgpu_bo_pin_restricted VRAM placing v2
+    - drm/amdgpu: no need to load MC firmware on fiji
+    - drm/amdgpu: move gmc7 support out of CIK dependency
+    - drm/amdgpu: iceland use CI based MC IP
+    - drm/amdgpu: The VI specific EXE bit should only apply to GMC v8.0 above
+    - drm/amdgpu: pull topaz gmc bits into gmc_v7
+    - drm/amdgpu: drop topaz support from gmc8 module
+    - drm/amdgpu: don't load MEC2 on topaz
+    - drm/amdgpu: remove exp hardware support from iceland
+    - drm/amdgpu: fix s4 resume
+    - drm/amdgpu: remove unnecessary forward declaration
+    - drm/amdgpu: hold reference to fences in amdgpu_sa_bo_new (v2)
+    - drm/amdgpu: fix issue with overlapping userptrs
+    - drm/amdgpu: use post-decrement in error handling
+    - drm/amdgpu: Don't hang in amdgpu_flip_work_func on disabled crtc.
+    - drm/amdgpu/pm: adjust display configuration after powerstate
+    - drm/nouveau/kms: take mode_config mutex in connector hotplug path
+    - drm/nouveau/display: Enable vblank irqs after display engine is on again.
+    - drm/nouveau/disp/dp: ensure sink is powered up before attempting link
+      training
+    - drm/nouveau: platform: Fix deferred probe
+    - drm/dp/mst: process broadcast messages correctly
+    - drm/dp/mst: always send reply for UP request
+    - drm/dp/mst: fix in MSTB RAD initialization
+    - drm/dp/mst: fix in RAD element access
+    - drm: Add drm_fixp_from_fraction and drm_fixp2int_ceil
+    - drm/dp/mst: Calculate MST PBN with 31.32 fixed point
+    - drm/dp/mst: move GUID storage from mgr, port to only mst branch
+    - drm/dp/mst: Reverse order of MST enable and clearing VC payload table.
+    - drm/dp/mst: deallocate payload on port destruction
+    - drm/radeon: Fix off-by-one errors in radeon_vm_bo_set_addr
+    - drm/radeon: call hpd_irq_event on resume
+    - drm/radeon: Fix "slow" audio over DP on DCE8+
+    - drm/radeon: clean up fujitsu quirks
+    - drm/radeon: properly byte swap vce firmware setup
+    - drm/radeon: cleaned up VCO output settings for DP audio
+    - drm/radeon: Add a common function for DFS handling
+    - drm/radeon: fix DP audio support for APU with DCE4.1 display engine
+    - drm: add helper to check for wc memory support
+    - drm/radeon: mask out WC from BO on unsupported arches
+    - drm/radeon: hold reference to fences in radeon_sa_bo_new
+    - drm: fix missing reference counting decrease
+    - drm/i915: Restore inhibiting the load of the default context
+    - drm/i915: intel_hpd_init(): Fix suspend/resume reprobing
+    - drm/i915: Init power domains early in driver load
+    - drm/i915: Make sure DC writes are coherent on flush.
+    - drm/i915/dp: fall back to 18 bpp when sink capability is unknown
+    - drm/i915: Don't reject primary plane windowing with color keying enabled on
+      SKL+
+    - drm/i915/skl: Don't skip mst encoders in skl_ddi_pll_select()
+    - drm/i915/dsi: defend gpio table against out of bounds access
+    - drm/i915/dsi: don't pass arbitrary data to sideband
+    - drm/i915: fix error path in intel_setup_gmbus()
+    - drm/qxl: use kmalloc_array to alloc reloc_info in qxl_process_single_command
+    - drm/radeon: use post-decrement in error handling
+    - drm: No-Op redundant calls to drm_vblank_off() (v2)
+    - drm: Prevent vblank counter bumps > 1 with active vblank clients. (v2)
+    - drm: Fix drm_vblank_pre/post_modeset regression from Linux 4.4
+    - drm: Fix treatment of drm_vblank_offdelay in drm_vblank_on() (v2)
+    - drm/radeon: Don't hang in radeon_flip_work_func on disabled crtc. (v2)
+    - drm/radeon/pm: adjust display configuration after powerstate
+    - make sure that freeing shmem fast symlinks is RCU-delayed
+    - toshiba_acpi: Fix blank screen at boot if transflective backlight is
+      supported
+    - ideapad-laptop: Add Lenovo ideapad Y700-17ISK to no_hw_rfkill dmi list
+    - ideapad-laptop: Add Lenovo Yoga 700 to no_hw_rfkill dmi list
+    - uapi: update install list after nvme.h rename
+    - lib: sw842: select crc32
+    - ACPI / video: Add disable_backlight_sysfs_if quirk for the Toshiba Portege
+      R700
+    - ACPI / video: Add disable_backlight_sysfs_if quirk for the Toshiba Satellite
+      R830
+    - ACPI: Revert "ACPI / video: Add Dell Inspiron 5737 to the blacklist"
+    - ACPI / PCI / hotplug: unlock in error path in acpiphp_enable_slot()
+    - nfit: fix multi-interface dimm handling, acpi6.1 compatibility
+    - dmaengine: dw: fix cyclic transfer setup
+    - dmaengine: dw: fix cyclic transfer callbacks
+    - dmaengine: at_xdmac: fix resume for cyclic transfers
+    - dmaengine: dw: disable BLOCK IRQs for non-cyclic xfer
+    - IB/cm: Fix a recently introduced deadlock
+    - IB/qib: fix mcast detach when qp not attached
+    - IB/qib: Support creating qps with GFP_NOIO flag
+    - IB/mlx5: Expose correct maximum number of CQE capacity
+    - Thermal: initialize thermal zone device correctly
+    - Thermal: handle thermal zone device properly during system sleep
+    - Thermal: do thermal zone update after a cooling device registered
+    - hwmon: (dell-smm) Blacklist Dell Studio XPS 8000
+    - hwmon: (gpio-fan) Remove un-necessary speed_index lookup for thermal hook
+    - hwmon: (ads1015) Handle negative conversion values correctly
+    - cpufreq: pxa2xx: fix pxa_cpufreq_change_voltage prototype
+    - cpufreq: Fix NULL reference crash while accessing policy->governor_data
+    - seccomp: always propagate NO_NEW_PRIVS on tsync
+    - libceph: fix ceph_msg_revoke()
+    - libceph: don't bail early from try_read() when skipping a message
+    - libceph: use the right footer size when skipping a message
+    - libceph: don't spam dmesg with stray reply warnings
+    - sd: Optimal I/O size is in bytes, not sectors
+    - Staging: speakup: Fix getting port information
+    - Revert "Staging: panel: usleep_range is preferred over udelay"
+    - cdc-acm:exclude Samsung phone 04e8:685d
+    - perf stat: Do not clean event's private stats
+    - tick/nohz: Set the correct expiry when switching to nohz/lowres mode
+    - rfkill: fix rfkill_fop_read wait_event usage
+    - mac80211: Requeue work after scan complete for all VIF types.
+    - workqueue: handle NUMA_NO_NODE for unbound pool_workqueue lookup
+    - Revert "workqueue: make sure delayed work run in local cpu"
+    - ALSA: hda - Apply clock gate workaround to Skylake, too
+    - ALSA: hda - Fixing background noise on Dell Inspiron 3162
+    - target: Fix LUN_RESET active I/O handling for ACK_KREF
+    - target: Fix LUN_RESET active TMR descriptor handling
+    - target: Fix TAS handling for multi-session se_node_acls
+    - target: Fix remote-port TMR ABORT + se_cmd fabric stop
+    - target: Fix race with SCF_SEND_DELAYED_TAS handling
+    - spi: atmel: fix gpio chip-select in case of non-DT platform
+    - libata: fix sff host state machine locking while polling
+    - ARCv2: STAR 9000950267: Handle return from intr to Delay Slot #2
+    - ARCv2: SMP: Emulate IPI to self using software triggered interrupt
+    - PCI/AER: Flush workqueue on device remove to avoid use-after-free
+    - cpuset: make mm migration asynchronous
+    - cgroup: make sure a parent css isn't offlined before its children
+    - writeback: keep superblock pinned during cgroup writeback association
+      switches
+    - phy: core: fix wrong err handle for phy_power_on
+    - i2c: i801: Adding Intel Lewisburg support for iTCO
+    - bio: return EINTR if copying to user space got interrupted
+    - block: fix use-after-free in dio_bio_complete
+    - nfs: fix nfs_size_to_loff_t
+    - NFSv4: Fix a dentry leak on alias use
+    - of/irq: Fix msi-map calculation for nonzero rid-base
+    - KVM: async_pf: do not warn on page allocation failures
+    - KVM: arm/arm64: vgic: Ensure bitmaps are long enough
+    - KVM: x86: fix missed hardware breakpoints
+    - KVM: x86: MMU: fix ubsan index-out-of-range warning
+    - powerpc/eeh: Fix partial hotplug criterion
+    - tracing: Fix showing function event in available_events
+    - sunrpc/cache: fix off-by-one in qword_get()
+    - kernel/resource.c: fix muxed resource handling in __request_region()
+    - do_last(): don't let a bogus return value from ->open() et.al. to confuse us
+    - ARM: OMAP2+: Fix onenand initialization to avoid filesystem corruption
+    - ARM: at91/dt: fix typo in sama5d2 pinmux descriptions
+    - xen/arm: correctly handle DMA mapping of compound pages
+    - xen/scsiback: correct frontend counting
+    - xen/pciback: Check PF instead of VF for PCI_COMMAND_MEMORY
+    - xen/pciback: Save the number of MSI-X entries to be copied later.
+    - xen/pcifront: Fix mysterious crashes when NUMA locality information was
+      extracted.
+    - should_follow_link(): validate ->d_seq after having decided to follow
+    - do_last(): ELOOP failure exit should be done after leaving RCU mode
+    - hpfs: don't truncate the file when delete fails
+    - x86/irq: Call chip->irq_set_affinity in proper context
+    - x86/irq: Fix a race in x86_vector_free_irqs()
+    - x86/irq: Validate that irq descriptor is still active
+    - x86/irq: Do not use apic_chip_data.old_domain as temporary buffer
+    - x86/irq: Reorganize the return path in assign_irq_vector
+    - x86/irq: Reorganize the search in assign_irq_vector
+    - x86/irq: Check vector allocation early
+    - x86/irq: Copy vectormask instead of an AND operation
+    - x86/irq: Get rid of code duplication
+    - x86/irq: Remove offline cpus from vector cleanup
+    - x86/irq: Clear move_in_progress before sending cleanup IPI
+    - x86/irq: Remove the cpumask allocation from send_cleanup_vector()
+    - x86/irq: Remove outgoing CPU from vector cleanup mask
+    - x86/irq: Call irq_force_move_complete with irq descriptor
+    - x86/irq: Plug vector cleanup race
+    - IB/cma: Fix RDMA port validation for iWarp
+    - iwlwifi: dvm: fix WoWLAN
+    - iwlwifi: pcie: properly configure the debug buffer size for 8000
+    - iwlwifi: update and fix 7265 series PCI IDs
+    - iwlwifi: mvm: don't allow sched scans without matches to be started
+    - Revert "UBUNTU: SAUCE: bcache: prevent crash on changing writeback_running"
+    - bcache: prevent crash on changing writeback_running
+    - Linux 4.4.4
+
+  * mlx4_en didn't choose time-stamping shift value according to HW frequency
+    (LP: #1552627)
+    - net/mlx4_en: Choose time-stamping shift value according to HW frequency
+
+  * [Ubuntu 16.04] Help to flush kernel panics to console (LP: #1552332)
+    - target/transport: add flag to indicate CPU Affinity is observed
+    - powerpc/powernv: Add a kmsg_dumper that flushes console output on panic
+    - powerpc/powernv: Fix OPAL_CONSOLE_FLUSH prototype and usages
+
+  * [Ubuntu 16.04] Update qla2xxx driver for POWER (QLogic) (LP: #1541456)
+    - qla2xxx: Fix warning reported by static checker
+    - qla2xxx: Fix TMR ABORT interaction issue between qla2xxx and TCM
+    - qla2xxx: Fix stale pointer access.
+    - qla2xxx: Use ATIO type to send correct tmr response
+    - qla2xxx: use TARGET_SCF_USE_CPUID flag to indiate CPU Affinity
+
+  * [s390x] zfcp.ko missing from scsi-modules udeb (LP: #1552314)
+    - [Config] Add s390x zfcp to scsi-modules udeb
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 02 Mar 2016 08:08:16 -0700
+
+linux (4.4.0-10.25) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1552247
+
+  * linux:  4.4.0-9.X fails yama ptrace restrictions tests (LP: #1551894)
+    - security: let security modules use PTRACE_MODE_* with bitmasks
+
+  * [wily][regression] systemtap script compilation broken by new kernels (LP: #1545330)
+    - SAUCE: (noup) locking/qspinlock: Move __ARCH_SPIN_LOCK_UNLOCKED to qspinlock_types.h
+
+  * [Feature]SD/SDIO/eMMC support for Broxton-P (LP: #1520454)
+    - mmc: sdhci: 64-bit DMA actually has 4-byte alignment
+    - mmc: sdhci: Fix DMA descriptor with zero data length
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) cgroup: fix and restructure error handling in copy_cgroup_ns()
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 29 Feb 2016 13:04:14 -0700
+
+linux (4.4.0-9.24) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1551319
+
+  * AppArmor logs denial for when the device path is ENOENT (LP: #1482943)
+    - SAUCE: apparmor: fix log of apparmor audit message when kern_path() fails
+
+  * BUG: unable to handle kernel NULL pointer dereference (aa_label_merge) (LP:
+    #1448912)
+    - SAUCE: apparmor: Fix: insert race between label_update and label_merge
+    - SAUCE: apparmor: Fix: ensure aa_get_newest will trip debugging if the
+      replacedby is not setup
+    - SAUCE: apparmor: Fix: label merge handling of marking unconfined and stale
+    - SAUCE: apparmor: Fix: refcount race between locating in labelset and get
+    - SAUCE: apparmor: Fix: ensure new labels resulting from merge have a
+      replacedby
+    - SAUCE: apparmor: Fix: label_vec_merge insertion
+    - SAUCE: apparmor: Fix: deadlock in aa_put_label() call chain
+    - SAUCE: apparmor: Fix: add required locking of __aa_update_replacedby on
+      merge path
+    - SAUCE: apparmor: Fix: convert replacedby update to be protected by the
+      labelset lock
+    - SAUCE: apparmor: Fix: update replacedby allocation to take a gfp parameter
+
+  * apparmor kernel BUG kills firefox (LP: #1430546)
+    - SAUCE: apparmor: Disallow update of cred when then subjective != the
+      objective cred
+    - SAUCE: apparmor: rework retrieval of the current label in the profile update
+      case
+
+  * sleep from invalid context in aa_move_mount (LP: #1539349)
+    - SAUCE: apparmor: fix sleep from invalid context
+
+  * s390x: correct restore of high gprs on signal return (LP: #1550468)
+    - s390/compat: correct restore of high gprs on signal return
+
+  * missing SMAP support (LP: #1550517)
+    - x86/entry/compat: Add missing CLAC to entry_INT80_32
+
+  * Floating-point exception handler receives empty Data-Exception Code in
+    Floating Point Control register (LP: #1548414)
+    - s390/fpu: signals vs. floating point control register
+
+  * kvm fails to boot GNU Hurd kernels with 4.4 Xenial kernel (LP: #1550596)
+    - KVM: x86: fix conversion of addresses to linear in 32-bit protected mode
+
+  * Surelock GA2 SP1: capiredp01: cxl_init_adapter fails for CAPI devices
+    0000:01:00.0 and 0005:01:00.0 after upgrading to 840.10 Platform firmware
+    build fips840/b1208b_1604.840 (LP: #1532914)
+    - cxl: Fix PSL timebase synchronization detection
+
+  * [Feature]EDAC support for Knights Landing (LP: #1519631)
+    - EDAC, sb_edac: Set fixed DIMM width on Xeon Knights Landing
+
+  * Various failures of kernel_security suite on Xenial kernel on s390x arch
+    (LP: #1531327)
+    - [config] s390x -- CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+
+  * Unable to install VirtualBox Guest Service in 15.04 (LP: #1434579)
+    - [Config] Provides: virtualbox-guest-modules when appropriate
+
+  * linux is missing provides for virtualbox-guest-modules [i386 amd64 x32] (LP:
+    #1507588)
+    - [Config] Provides: virtualbox-guest-modules when appropriate
+
+  * Backport more recent driver for SKL, KBL and BXT graphics (LP: #1540390)
+    - SAUCE: i915_bpo: Provide a backport driver for SKL, KBL & BXT graphics
+    - SAUCE: i915_bpo: Update intel_ips.h file location
+    - SAUCE: i915_bpo: Rename the backport driver to i915_bpo
+    - SAUCE: i915_bpo: Add i915_bpo_*() calls for ubuntu/i915
+    - drm/i915: remove an extra level of indirection in PCI ID list
+    - drm/i915/kbl: Add Kabylake PCI ID
+    - drm/i915/kbl: Add Kabylake GT4 PCI ID
+    - mm: Export nr_swap_pages
+    - async: export current_is_async()
+    - drm: fix potential dangling else problems in for_each_ macros
+    - dp/mst: add SDP stream support
+    - drm: Implement drm_modeset_lock_all_ctx()
+    - drm: Add "prefix" parameter to drm_rect_debug_print()
+    - drm/i915: Set connector_state->connector using the helper.
+    - drm/atomic: add connector mask to drm_crtc_state.
+    - drm/i915: Report context GTT size
+    - drm/i915: Add get_eld audio component
+    - SAUCE: Backport I915_PARAM_HAS_EXEC_SOFTPIN and EXEC_OBJECT_PINNED
+    - SAUCE: i915_bpo: Revert passing plane/encoder name
+    - SAUCE: sound/hda: Load i915_bpo from the hda driver on SKL/KBL/BXT
+    - SAUCE: i915_bpo: Support only SKL, KBL and BXT with the backport driver
+    - drm/i915/bxt: update list of PCIIDs
+    - drm/i915/skl: Add missing SKL ids
+    - SAUCE: i915_bpo: Revert "drm/i915: Defer probe if gmux is present but its
+      driver isn't"
+    - SAUCE: uapi/drm/i915: Backport I915_EXEC_BSD_MASK
+    - drm/atomic: Do not unset crtc when an encoder is stolen
+    - drm/i915: Update connector_mask during readout, v2.
+    - drm/atomic: Add encoder_mask to crtc_state, v3.
+    - SAUCE: drm/core: Add drm_encoder_index.
+    - SAUCE: i915_bpo: Revert "drm/i915: Switch DDC when reading the EDID"
+    - i915_bpo: [Config] Enable CONFIG_DRM_I915_BPO=m
+
+  * arm64: guest hangs when ntpd is running (LP: #1549494)
+    - hrtimer: Add support for CLOCK_MONOTONIC_RAW
+    - hrtimer: Catch illegal clockids
+    - KVM: arm/arm64: timer: Switch to CLOCK_MONOTONIC_RAW
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] git-ubuntu-log -- wrap long bug and commit titles
+    - [Config] CONFIG_ARM_SMMU=y on arm64
+    - rebase to v4.4.3
+    - [Debian] git-ubuntu-log -- ensure we get the last commit
+    - [Config] fix up spelling of probably again
+    - [Debian] perf -- build in the context of the full generated local headers
+    - SAUCE: tools: lib/bpf -- add generated headers to search path
+    - SAUCE: proc: Always set super block owner to init_user_ns
+    - SAUCE: fix-up: kern_mount fail path should not be doing put_buffers()
+    - SAUCE: apparmor: Fix: oops do to invalid null ptr deref in label print fns
+    - SAUCE: apparmor: debug: POISON label and replaceby pointer on free
+    - SAUCE: apparmor: add underscores to indicate aa_label_next_not_in_set() use
+      needs locking
+    - SAUCE: apparmor: Fix: refcount leak in aa_label_merge
+    - SAUCE: apparmor: ensure that repacedby sharing is done correctly
+    - SAUCE: apparmor Fix: refcount bug in pivotroot mediation
+    - SAUCE: apparmor: Fix: now that insert can force replacement use it instead
+      of remove_and_insert
+    - SAUCE: apparmor: Fix: refcount bug when inserting label update that
+      transitions ns
+    - SAUCE: apparmor: Fix: break circular refcount for label that is directly
+      freed.
+    - SAUCE: apparmor: Don't remove label on rcu callback if the label has already
+      been removed
+    - SAUCE: apparmor: Fix: query label file permission
+    - SAUCE: apparmor: fix: ref count leak when profile sha1 hash is read
+    - SAUCE: fixup: cleanup return handling of labels
+    - SAUCE: fix: replacedby forwarding is not being properly update when ns is
+      destroyed
+    - SAUCE: fixup: make __share_replacedby private to get rid of build warning
+    - SAUCE: fixup: 20/23 locking issue around in __label_update
+    - SAUCE: fixup: get rid of unused var build warning
+    - SAUCE: fixup: cast poison values to remove warnings
+    - SAUCE: apparmor: fix refcount race when finding a child profile
+    - SAUCE: fixup: warning about aa_label_vec_find_or_create not being static
+    - SAUCE: fix: audit "no_new_privs" case for exec failure
+    - SAUCE: Fixup: __label_update() still doesn't handle some cases correctly.
+    - SAUCE: Move replacedby allocation into label_alloc
+    - [Debian] supply zfs dkms Provides: based on do_zfs
+    - [Config] supply zfs dkms Provides: based on do_zfs
+    - [Config] drop linux-image-3.0 provides
+
+  * Miscellaneous upstream changes
+    - x86/mpx: Fix off-by-one comparison with nr_registers
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4.3
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 25 Feb 2016 19:47:55 -0700
+
+linux (4.4.0-8.23) xenial; urgency=low
+
+  * cgroup namespace mounts broken in containers (LP: #1549398)
+    - SAUCE: kernfs: Always set super block owner to init_user_ns
+
+  * 4.4.0-7.22 no longer boots on arm64 (LP: #1547718)
+    - arm64: mm: avoid calling apply_to_page_range on empty range
+    - UBUNTU SAUCE: arm: mm: avoid calling apply_to_page_range on empty range
+
+  * kernel install failed /bin/cp: cannot stat ‘/boot/initrd.img-4.3.0-7-generic’: No such file or directory (LP: #1536810)
+    - [Config] postinst -- handle recreating symlinks when a real file is present
+
+  * insecure overlayfs xattrs handling in copy_up (LP: #1534961)
+    - SAUCE: cred: Add clone_cred() interface
+    - SAUCE: overlayfs: Use mounter's credentials instead of selectively raising caps
+    - SAUCE: overlayfs: Skip permission checking for trusted.overlayfs.* xattrs
+    - SAUCE: overlayfs: Be more careful about copying up sxid files
+    - SAUCE: overlayfs: Propogate nosuid from lower and upper mounts
+
+  * overlayfs over fuse should refuse copy_up of files if uid/gid not mapped (LP: #1535150)
+    - SAUCE: cred: Add clone_cred() interface
+    - SAUCE: overlayfs: Use mounter's credentials instead of selectively raising caps
+    - SAUCE: overlayfs: Skip permission checking for trusted.overlayfs.* xattrs
+    - SAUCE: overlayfs: Be more careful about copying up sxid files
+    - SAUCE: overlayfs: Propogate nosuid from lower and upper mounts
+
+  * overlay: mkdir fails if directory exists in lowerdir in a user namespace (LP: #1531747)
+    - SAUCE: cred: Add clone_cred() interface
+    - SAUCE: overlayfs: Use mounter's credentials instead of selectively raising caps
+    - SAUCE: overlayfs: Skip permission checking for trusted.overlayfs.* xattrs
+
+  * Update Intel ethernet drivers to Fortville SW5 (LP: #1547674)
+    - net: bulk free infrastructure for NAPI context, use napi_consume_skb
+    - net: Add eth_platform_get_mac_address() helper.
+    - i40e: Add mac_filter_element at the end of the list instead of HEAD
+    - i40e/i40evf: Fix RSS rx-flow-hash configuration through ethtool
+    - i40e: Replace X722 mac check in ethtool get_settings
+    - i40evf: allow channel bonding of VFs
+    - i40e: define function capabilities in only one place
+    - i40evf: null out ring pointers on free
+    - i40e: Cleanup the code with respect to restarting autoneg
+    - i40e: update features with right offload
+    - i40e: bump version to 1.4.10
+    - i40e: add new device IDs for X722
+    - i40e: Extend ethtool RSS hooks for X722
+    - i40e/i40evf: Fix for UDP/TCP RSS for X722
+    - i40evf: add new write-back mode
+    - i40e/i40evf: Use private workqueue
+    - i40e: add new proxy-wol bit for X722
+    - i40e: Limit DCB FW version checks to X710/XL710 devices
+    - i40e: AQ Add Run PHY Activity struct
+    - i40e: AQ Geneve cloud tunnel type
+    - i40e: AQ Add external power class to get link status
+    - i40e: add 100Mb ethtool reporting
+    - ixgbe: bulk free SKBs during TX completion cleanup cycle
+    - igb: Remove unnecessary flag setting in igb_set_flag_queue_pairs()
+    - igb: Unpair the queues when changing the number of queues
+    - igb/igbvf: don't give up
+    - igb: clean up code for setting MAC address
+    - igb: Refactor VFTA configuration
+    - igb: Allow asymmetric configuration of MTU versus Rx frame size
+    - igb: Do not factor VLANs into RLPML calculation
+    - igb: Always enable VLAN 0 even if 8021q is not loaded
+    - igb: Merge VLVF configuration into igb_vfta_set
+    - igb: Clean-up configuration of VF port VLANs
+    - igb: Add support for VLAN promiscuous with SR-IOV and NTUPLE
+    - igb: Drop unnecessary checks in transmit path
+    - igb: Enable use of "bridge fdb add" to set unicast table entries
+    - igb: Add workaround for VLAN tag stripping on 82576
+    - i40e: AQ Shared resource flags
+    - i40e: AQ Add set_switch_config
+    - i40e: AQ Add VXLAN-GPE tunnel type
+    - i40e: AQ thermal sensor control struct
+    - i40e: Bump AQ minor version to 1.5 for new FW features
+    - i40e: Store lan_vsi_idx and lan_vsi_id in the right size
+    - i40e: fix write-back-on-itr to work with legacy itr
+    - i40e: add counter for arq overflows
+    - i40e: add 20G speed for Tx bandwidth calculations
+    - i40e: refactor DCB function
+    - i40e: add a little more to an NVM update debug message
+    - i40evf: enable bus master after reset
+    - i40e: add netdev info to VSI dump
+    - i40e: remove VF device IDs from PF
+    - i40e: trivial: remove unnecessary local var
+    - i40e/i40evf: Bump i40e to 1.4.11 and i40evf to 1.4.7
+    - net: ixgbe: add minimal parser details for ixgbe
+    - i40e: trivial: drop duplicate definition
+    - i40e: trivial: fix missing space
+    - i40e: fix bug in dma sync
+    - i40e: do TSO only if CHECKSUM_PARTIAL is set
+    - i40e: allocate memory safer
+    - i40e: fix: do not sleep in netdev_ops
+    - i40e: APIs to Add/remove port mirroring rules
+    - i40e: negate PHY int mask bits
+    - i40e: drop unused function
+    - i40e: count allocation errors
+    - i40e: avoid large memcpy by assigning struct
+    - i40e/i40evf: bump version to 1.4.12/1.4.8
+    - i40e: Enable Geneve offload for FW API ver > 1.4 for XL710/X710 devices
+    - i40e: add priv flag for automatic rule eviction
+    - i40e: use eth_platform_get_mac_address()
+    - i40e: move sync_vsi_filters up in service_task
+    - i40e: Make the DCB firmware checks for X710/XL710 only
+    - i40e: set shared bit for multicast filters
+    - i40e: add VEB stat control and remove L2 cloud filter
+    - i40e: use new add_veb calling with VEB stats control
+    - i40e: Refactor force_wb and WB_ON_ITR functionality code
+    - i40evf: Change vf driver string to reflect all products i40evf supports
+    - i40e/i40evf: don't lose interrupts
+    - i40e/i40evf: try again after failure
+    - i40e: dump descriptor indexes in hex
+    - i40e/i40evf: use __GFP_NOWARN
+    - i40e/i40evf: use pages correctly in Rx
+    - i40e/i40evf: use logical operators, not bitwise
+    - i40e: properly show packet split status in debugfs
+    - i40e/i40evf: Bump version
+    - ixgbe: use u32 instead of __u32 in model header
+    - ixgbe: fix dates on header of ixgbe_model.h
+    - i40e: get rid of magic number
+    - i40e: drop unused debugfs file "dump"
+    - i40evf: support packet split receive
+    - i40e: trivial: cleanup use of pf->hw
+    - i40e: Add a SW workaround for lost interrupts
+    - i40e: Fix PROMISC mode for Multi-function per port (MFP) devices
+    - i40e: Removal of code which relies on BASE VEB SEID
+    - i40e/i40evf: avoid atomics
+    - i40e: Do not disable queues in the Legacy/MSI Interrupt handler
+    - i40e: expand comment
+    - i40e: better error reporting for nvmupdate
+    - i40evf: set adapter state on reset failure
+    - i40e: clean event descriptor before use
+    - i40e: When in promisc mode apply promisc mode to Tx Traffic as well
+    - i40e/i40evf: Bump i40e to 1.4.15 and i40evf to 1.4.11.
+    - i40e/i40evf: Drop outer checksum offload that was not requested
+    - i40e/i40evf: Use u64 values instead of casting them in TSO function
+    - i40e/i40evf: Factor out L4 header and checksum from L3 bits in TSO path
+    - i40e/i40evf: Consolidate all header changes into TSO function
+    - i40e/i40evf: Replace header pointers with unions of pointers in Tx checksum path
+    - i40e/i40evf: Add support for IPv4 encapsulated in IPv6
+    - i40e/i40evf: Handle IPv6 extension headers in checksum offload
+    - i40e/i40evf: Do not write to descriptor unless we complete
+    - i40e/i40evf: Add exception handling for Tx checksum
+    - i40e/i40evf: Clean-up Rx packet checksum handling
+    - i40e/i40evf: Enable support for SKB_GSO_UDP_TUNNEL_CSUM
+    - i40e: Fix ATR in relation to tunnels
+    - i40e: Do not drop support for IPv6 VXLAN or GENEVE tunnels
+    - i40e: Update feature flags to reflect newly enabled features
+    - i40evf: Update feature flags to reflect newly enabled features
+    - i40e: Add support for ATR w/ IPv6 extension headers
+    - i40e/i40evf: Break up xmit_descriptor_count from maybe_stop_tx
+    - i40e/i40evf: Rewrite logic for 8 descriptor per packet check
+    - i40e/i40evf: Move Tx checksum closer to TSO
+    - i40e: Add functions to blink led on 10GBaseT PHY
+    - i40e: Fix led blink capability for 10GBaseT PHY
+    - i40e: Increase timeout when checking GLGEN_RSTAT_DEVSTATE bit
+    - i40e: Do not wait for Rx queue disable in DCB reconfig
+    - i40e: Fix for unexpected messaging
+    - i40e: Expose some registers to program parser, FD and RSS logic
+    - i40e: add check for null VSI
+    - i40e: add adminq commands for Rx CTL registers
+    - i40e: implement and use Rx CTL helper functions
+    - i40e: Use the new rx ctl register helpers. Don't use AQ calls from clear_hw.
+    - i40e: suspend scheduling during driver unload
+    - i40e: let go of the past
+    - i40e/i40evf: Bump i40e to 1.4.25 and i40evf to 1.4.15
+
+  * MPT3SAS Driver update for next kernel release (LP: #1512221)
+    - mpt3sas: A correction in unmap_resources
+    - mpt3sas: Added support for high port count HBA variants.
+    - mpt3sas: Used IEEE SGL instead of MPI SGL while framing a SMP Passthrough request message.
+    - mpt3sas: Fix static analyzer(coverity) tool identified defects
+    - mpt3sas: Never block the Enclosure device
+    - mpt3sas: Make use of additional HighPriority credit message frames for sending SCSI IO's
+    - mpt3sas: Added smp_affinity_enable module parameter.
+    - mpt3sas: Add support for configurable Chain Frame Size
+    - mpt3sas: Updated MPI Header to 2.00.42
+    - mpt3sas: Fix for Asynchronous completion of timedout IO and task abort of timedout IO.
+    - mpt3sas: Updating mpt3sas driver version to 12.100.00.00
+    - mpt3sas: Remove cpumask_clear for zalloc_cpumask_var and don't free free_cpu_mask_var before reply_q
+
+  * /sys/class/scsi_host/hostN/partition_number and .../mad_version showing up BE on LE Ubuntu. (ibmvscsi) (LP: #1547153)
+    - ibmvscsi: Add endian conversions to sysfs attribute show functions
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] git-ubuntu-log -- output should be utf-8
+    - [Packaging] git-ubuntu-log -- handle invalid or private bugs
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 24 Feb 2016 20:34:49 +0000
+
+linux (4.4.0-7.22) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1547205
+
+  * need arm64 acpi parking protocol support in xenial (LP: #1547047)
+    - [Config] Enabled ARM64_ACPI_PARKING_PROTOCOL
+    - arm64: kernel: implement ACPI parking protocol
+
+  * Please pull cgroup namespaces (LP: #1546775)
+    - SAUCE: (noup) kernfs: Add API to generate relative kernfs path
+    - SAUCE: (noup) sched: new clone flag CLONE_NEWCGROUP for cgroup namespace
+    - SAUCE: (noup) cgroup: introduce cgroup namespaces
+    - SAUCE: (noup) cgroup: cgroup namespace setns support
+    - SAUCE: (noup) kernfs: define kernfs_node_dentry
+    - SAUCE: (noup) cgroup: mount cgroupns-root when inside non-init cgroupns
+    - SAUCE: (noup) Add FS_USERNS_FLAG to cgroup fs
+    - SAUCE: (noup) cgroup: Add documentation for cgroup namespaces
+
+  * [Feature]Pulse-Width Modulation enabling on Broxton-P (LP: #1520436)
+    - [Config] CONFIG_PWM_OMAP_DMTIMER=m
+    - pwm: lpss: Remove ->free() callback
+    - pwm: bcm2835: Calculate scaler in ->config()
+    - pwm: bcm2835: Prevent division by zero
+    - pwm: bcm2835: Fix email address specification
+    - pwm: lpss: Update PWM setting for Broxton
+    - pwm: lpss: Select core part automatically
+    - pwm: lpss: Rework the sequence of programming PWM_SW_UPDATE
+    - pwm: fsl-ftm: Fix clock enable/disable when using PM
+    - pwm: lpc32xx: correct number of PWM channels from 2 to 1
+    - pwm: lpc32xx: make device usable with common clock framework
+    - pwm: lpc32xx: fix and simplify duty cycle and period calculations
+    - pwm: lpc32xx: return ERANGE, if requested period is not supported
+    - pwm: rcar: Improve accuracy of frequency division setting
+    - pwm: Add PWM driver for OMAP using dual-mode timers
+    - pwm: add HAS_IOMEM dependency to PWM_FSL_FTM
+    - pwm: omap-dmtimer: Potential NULL dereference on error
+    - pwm: Mark all devices as "might sleep"
+
+  * [Hyper-V] Netmask value is not parsed by hv_set_ifconfig - IP injection (LP: #1540586)
+    - [Debian] hv: hv_set_ifconfig -- switch to approved indentation
+    - [Debian] hv: hv_set_ifconfig -- fix numerous parameter handling issues
+
+  * Update megaraid driver to MR6.10 (LP: #1544679)
+    - megaraid_sas: Do not allow PCI access during OCR
+    - megaraid_sas: MFI IO timeout handling
+    - megaraid_sas: Syncing request flags macro names with firmware
+    - megaraid_sas: Task management support
+    - megaraid_sas: Update device queue depth based on interface type
+    - megaraid_sas: Fastpath region lock bypass
+    - megaraid_sas: Reply Descriptor Post Queue (RDPQ) support
+    - megaraid_sas: Code optimization build_and_issue_cmd return-type
+    - megaraid_sas: Dual queue depth support
+    - megaraid_sas: IO throttling support
+    - megaraid_sas: Make adprecovery variable atomic
+    - megaraid_sas: MFI adapter OCR changes
+    - megaraid_sas: Introduce module parameter for SCSI command timeout
+    - megaraid_sas: SPERC OCR changes
+    - megaraid_sas: driver version upgrade
+    - megaraid: fix null pointer check in megasas_detach_one().
+    - megaraid_sas: Fix for IO failing post OCR in SRIOV environment
+    - megaraid_sas: Fix SMAP issue
+    - megaraid_sas: Add an i/o barrier
+
+  * Surelock-GA2:kernel panic @ cxl_configure_adapter+0x418/0x8b0 (LP: #1546145)
+    - powerpc/powernv: Fix stale PE primary bus
+
+  * In A Single Power VM LPAR : Network Configuration Fails in Ubuntu16.04 while installation (LP: #1544321)
+    - [Config] Update bnx2x d-i firmware to 7.12.30
+
+  * Miscellaneous Ubuntu changes
+    - rebase to v4.4.2
+
+  * Miscellaneous upstream changes
+    - openvswitch: allow management from inside user namespaces
+    - net: thunderx: nicvf_queues: nivc_*_intr: remove duplication
+    - net, thunderx: Remove unnecessary rcv buffer start address management
+    - net: thunderx: HW TSO support for pass-2 hardware
+    - net: thunderx: Enable CQE count threshold interrupt
+    - net: cavium: liquidio: use helpers ns_to_timespec64()
+    - irqchip/gic-v3: Make sure read from ICC_IAR1_EL1 is visible on redestributor
+    - arm64: KVM: Configure TCR_EL2.PS at runtime
+    - arm64: prefetch: don't provide spin_lock_prefetch with LSE
+    - arm64: prefetch: add alternative pattern for CPUs without a prefetcher
+    - arm64: lib: improve copy_page to deal with 128 bytes at a time
+    - arm64: lib: patch in prfm for copy_page if requested
+    - arm64: prefetch: add missing #include for spin_lock_prefetch
+    - net, thunderx: Add TX timeout and RX buffer alloc failure stats.
+    - net: thunderx: Use napi_schedule_irqoff()
+    - net: thunderx: Assign affinity hints to vf's interrupts
+    - net: thunderx: bgx: Use standard firmware node infrastructure.
+    - net: thunderx: bgx: Add log message when setting mac address
+    - net: thunderx: Alloc higher order pages when pagesize is small
+    - net: cavium: liquidio: Return correct error code
+    - net: cavium: liquidio: fix check for in progress flag
+    - livepatch: add old_sympos as disambiguator field to klp_func
+    - livepatch: add sympos as disambiguator field to klp_reloc
+    - livepatch: function,sympos scheme in livepatch sysfs directory
+    - module: Use the same logic for setting and unsetting RO/NX
+    - gcov: use within_module() helper.
+    - module: use a structure to encapsulate layout.
+    - module: clean up RO/NX handling.
+    - module: keep percpu symbols in module's symtab
+    - livepatch: Cleanup module page permission changes
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4.2
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 16 Feb 2016 14:24:45 -0700
+
+linux (4.4.0-6.21) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1546283
+
+  *  Naples/Zen, NTB Driver  (LP: #1542071)
+    - [Config] CONFIG_NTB_AMD=m
+    - NTB: Add support for AMD PCI-Express Non-Transparent Bridge
+
+  * [Hyper-V] kernel panic occurs when installing Ubuntu Server x32 (LP: #1495983)
+    - SAUCE: storvsc: use small sg_tablesize on x86
+
+  * Enable arm64 emulation of removed ARMv7 instructions (LP: #1545542)
+    - [Config] CONFIG_ARMV8_DEPRECATED=y
+
+  * Surelock-GA2:kernel panic/ exception @ pcibios_set_pcie_reset_state+0x118/0x280 + cxl_reset+0x5c/0xc0 (LP: #1545037)
+    - powerpc/eeh: Fix stale cached primary bus
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: fs: Add user namesapace member to struct super_block
+    - SAUCE: fs: Limit file caps to the user namespace of the super block
+    - SAUCE: Smack: Add support for unprivileged mounts from user namespaces
+    - SAUCE: block_dev: Support checking inode permissions in lookup_bdev()
+    - SAUCE: block_dev: Check permissions towards block device inode when mounting
+    - SAUCE: fs: Treat foreign mounts as nosuid
+    - SAUCE: selinux: Add support for unprivileged mounts from user namespaces
+    - SAUCE: userns: Replace in_userns with current_in_userns
+    - SAUCE: Smack: Handle labels consistently in untrusted mounts
+    - SAUCE: fs: Check for invalid i_uid in may_follow_link()
+    - SAUCE: cred: Reject inodes with invalid ids in set_create_file_as()
+    - SAUCE: fs: Refuse uid/gid changes which don't map into s_user_ns
+    - SAUCE: fs: Update posix_acl support to handle user namespace mounts
+    - SAUCE: fs: Ensure the mounter of a filesystem is privileged towards its inodes
+    - SAUCE: fs: Don't remove suid for CAP_FSETID in s_user_ns
+    - SAUCE: fs: Allow superblock owner to access do_remount_sb()
+    - SAUCE: capabilities: Allow privileged user in s_user_ns to set security.* xattrs
+    - SAUCE: fuse: Add support for pid namespaces
+    - SAUCE: fuse: Support fuse filesystems outside of init_user_ns
+    - SAUCE: fuse: Restrict allow_other to the superblock's namespace or a descendant
+    - SAUCE: fuse: Allow user namespace mounts
+    - SAUCE: mtd: Check permissions towards mtd block device inode when mounting
+    - SAUCE: fs: Update i_[ug]id_(read|write) to translate relative to s_user_ns
+    - SAUCE: quota: Convert ids relative to s_user_ns
+    - SAUCE: evm: Translate user/group ids relative to s_user_ns when computing HMAC
+    - SAUCE: fs: Allow CAP_SYS_ADMIN in s_user_ns to freeze and thaw filesystems
+    - SAUCE: quota: Treat superblock owner as privilged
+    - SAUCE: ima/evm: Allow root in s_user_ns to set xattrs
+    - SAUCE: block_dev: Forbid unprivileged mounting when device is opened for writing
+    - SAUCE: ext4: Add support for unprivileged mounts from user namespaces
+    - SAUCE: ext4: Add module parameter to enable user namespace mounts
+    - SAUCE: fuse: Add module parameter to enable user namespace mounts
+
+  * Miscellaneous upstream changes
+    - megaraid: Fix possible NULL pointer deference in mraid_mm_ioctl
+    - libahci: Implement the capability to override the generic ahci interrupt handler.
+    - ata: Remove the AHCI_HFLAG_EDGE_IRQ support from libahci.
+    - ahci_xgene: Implement the workaround to fix the missing of the edge interrupt for the HOST_IRQ_STAT.
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 12 Feb 2016 09:49:05 -0700
+
+linux (4.4.0-5.20) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1544637
+
+  * s390/cio: update measurement characteristics (LP: #1541534)
+    - s390/cio: fix measurement characteristics memleak
+    - s390/cio: ensure consistent measurement state
+    - s390/cio: update measurement characteristics
+
+  * qeth: layer2 reports unknown state to network tools. (LP: #1541907)
+    - qeth: initialize net_device with carrier off
+
+  * Collateral damage due to kernel configuration change enabling CONFIG_ZONE_DEVICE (Kernel 4.4 amd64) (LP: #1534647)
+    - [Config] CONFIG_ZONE_DMA=y
+    - mm: CONFIG_NR_ZONES_EXTENDED
+
+  * perf enahancements for ppc64 (LP: #1521678)
+    - perf kvm/{x86,s390}: Remove dependency on uapi/kvm_perf.h
+    - perf kvm/{x86,s390}: Remove const from kvm_events_tp
+    - perf kvm/powerpc: Port perf kvm stat to powerpc
+    - perf kvm/powerpc: Add support for HCALL reasons
+
+  * Soft lockup with "block nbdX: Attempted send on closed socket" spam (LP: #1505564)
+    - SAUCE: nbd: ratelimit error msgs after socket close
+
+  * sleep from invalid context in aa_move_mount (LP: #1539349)
+    - SAUCE: apparmor: fix sleep from invalid context
+
+  * Introducing ConnectX-4 Ethernet SRIOV (LP: #1540435)
+    - net/mlx5_core: Modify enable/disable hca functions
+    - net/mlx5_core: Add base sriov support
+    - net/mlx5: Add HW capabilities and structs for SR-IOV E-Switch
+    - net/mlx5: Update access functions to Query/Modify vport MAC address
+    - net/mlx5: Introduce access functions to modify/query vport mac lists
+    - net/mlx5: Introduce access functions to modify/query vport state
+    - net/mlx5: Introduce access functions to modify/query vport promisc mode
+    - net/mlx5: Introduce access functions to modify/query vport vlans
+    - net/mlx5e: Write UC/MC list and promisc mode into vport context
+    - net/mlx5e: Write vlan list into vport context
+    - net/mlx5: Introducing E-Switch and l2 table
+    - net/mlx5: E-Switch, Introduce FDB hardware capabilities
+    - net/mlx5: E-Switch, Add SR-IOV (FDB) support
+    - net/mlx5: E-Switch, Introduce Vport administration functions
+    - net/mlx5: E-Switch, Introduce HCA cap and E-Switch vport context
+    - net/mlx5: E-Switch, Introduce set vport vlan (VST mode)
+    - net/mlx5: E-Switch, Introduce get vf statistics
+    - net/mlx5e: Add support for SR-IOV ndos
+    - net/mlx5: Fix query E-Switch capabilities
+    - net/mlx5e: Assign random MAC address if needed
+
+  * make wacom_w8001 work well in xenial (LP: #1542771)
+    - Input: wacom_w8001 - use __set_bit for evbits
+    - Input: wacom_w8001 - set BTN_TOOL_DOUBLETAP if we have 2fg support
+    - Input: wacom_w8001 - handle touch error case correctly
+    - Input: wacom_w8001 - split pen and touch initialization up
+    - Input: wacom_w8001 - split the touch and pen devices into two devices
+    - Input: wacom_w8001 - drop use of ABS_MT_TOOL_TYPE
+
+  * virtualbox: update to 5.0.14-dfsg-2 (LP: #1542728)
+    - ubuntu: vbox -- update to 5.0.14-dfsg-2
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] git-ubuntu-log -- fix empty section formatting
+    - SAUCE: (noup) Update spl to 0.6.5.4-0ubuntu2, zfs to 0.6.5.4-0ubuntu2
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 06 Feb 2016 22:32:10 +0000
+
+linux (4.4.0-4.19) xenial; urgency=low
+
+  * update ZFS and SPL to 0.6.5.4 (LP: #1542296)
+    - [Config] update spl/zfs version
+    - SAUCE: (noup) Update spl to 0.6.5.4-0ubuntu2, zfs to 0.6.5.4-0ubuntu1
+    - [Config] reconstruct -- drop links for zfs userspace components
+    - [Config] reconstruct -- drop links for zfs userspace components -- restore spec links
+
+  * recvmsg() fails SCM_CREDENTIALS request with EOPNOTSUPP. (LP: #1540731)
+    - Revert "af_unix: Revert 'lock_interruptible' in stream receive code"
+
+  * lxc: ADT exercise test failing with linux-4.4.0-3.17  (LP: #1542049)
+    - Revert "UBUNTU: SAUCE: apparmor: fix sleep from invalid context"
+
+  * WARNING: at /build/linux-lts-wily-W0lTWH/linux-lts-wily-4.2.0/net/core/skbuff.c:4174 (Travis IB) (LP: #1541326)
+    - SAUCE: IB/IPoIB: Do not set skb truesize since using one linearskb
+
+  * backport Microsoft Precision Touchpad palm rejection patch (LP: #1541671)
+    - HID: multitouch: enable palm rejection if device implements confidence usage
+
+  * [Ubuntu 16.04] Update qla2xxx driver for POWER (QLogic) (LP: #1541456)
+    - qla2xxx: Remove unavailable firmware files
+    - qla2xxx: Enable Extended Logins support
+    - qla2xxx: Enable Exchange offload support.
+    - qla2xxx: Enable Target counters in DebugFS.
+    - qla2xxx: Add FW resource count in DebugFS.
+    - qla2xxx: Added interface to send explicit LOGO.
+    - qla2xxx: Delete session if initiator is gone from FW
+    - qla2xxx: Wait for all conflicts before ack'ing PLOGI
+    - qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit.
+    - qla2xxx: Remove dependency on hardware_lock to reduce lock contention.
+    - qla2xxx: Add irq affinity notification
+    - qla2xxx: Add selective command queuing
+    - qla2xxx: Move atioq to a different lock to reduce lock contention
+    - qla2xxx: Disable ZIO at start time.
+    - qla2xxx: Set all queues to 4k
+    - qla2xxx: Check for online flag instead of active reset when transmitting responses
+    - scsi: qla2xxxx: avoid type mismatch in comparison
+
+  * [Hyper-V] PCI Passthrough (LP: #1541120)
+    - x86/irq: Export functions to allow MSI domains in modules
+    - genirq/msi: Export functions to allow MSI domains in modules
+
+  * Update lpfc driver to 11.0.0.10 (LP: #1541592)
+    - lpfc: Fix FCF Infinite loop in lpfc_sli4_fcf_rr_next_index_get.
+    - lpfc: Fix the FLOGI discovery logic to comply with T11 standards
+    - lpfc: Fix RegLogin failed error seen on Lancer FC during port bounce
+    - lpfc: Fix driver crash when module parameter lpfc_fcp_io_channel set to 16
+    - lpfc: Fix crash in fcp command completion path.
+    - lpfc: Modularize and cleanup FDMI code in driver
+    - lpfc: Fix RDP Speed reporting.
+    - lpfc: Fix RDP ACC being too long.
+    - lpfc: Make write check error processing more resilient
+    - lpfc: Use new FDMI speed definitions for 10G, 25G and 40G FCoE.
+    - lpfc: Fix mbox reuse in PLOGI completion
+    - lpfc: Fix external loopback failure.
+    - lpfc: Add logging for misconfigured optics.
+    - lpfc: Delete unnecessary checks before the function call "mempool_destroy"
+    - lpfc: Use kzalloc instead of kmalloc
+    - lpfc: Update version to 11.0.0.10 for upstream patch set
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_ARM64_VA_BITS=48
+    - [Config] Fixed Vcs-Git
+
+  * Miscellaneous upstream changes
+    - cxl: Fix possible idr warning when contexts are released
+    - cxl: use correct operator when writing pcie config space values
+    - cxlflash: drop unlikely before IS_ERR_OR_NULL
+    - cxl: Fix DSI misses when the context owning task exits
+    - cxlflash: Removed driver date print
+    - cxlflash: Fix to resolve cmd leak after host reset
+    - cxlflash: Resolve oops in wait_port_offline
+    - cxlflash: Enable device id for future IBM CXL adapter
+    - cxl: fix build for GCC 4.6.x
+    - cxl: use -Werror only with CONFIG_PPC_WERROR
+    - cxl: Enable PCI device ID for future IBM CXL adapter
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Feb 2016 14:58:51 +0000
+
+linux (4.4.0-3.17) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1541058
+  * [Config] CONFIG_BLK_DEV_NVME_SCSI=y
+    - LP: #1531539
+  * SAUCE: nvme merge cleanup
+    - LP: #1531539
+  * rebase to v4.4.1
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: dm: introduce a target_ioctl op to allow target specific
+    ioctls"
+    - LP: #1538618
+  * postinst -- detect symlinks correctly
+    - LP: #1536810
+
+  [ John Johansen ]
+
+  * SAUCE: apparmor: fix sleep from invalid context
+    - LP: #1539349
+
+  [ Upstream Kernel Changes ]
+
+  * powerpc/eeh: Fix PE location code
+    - LP: #1538909
+  * powerpc/pseries: Limit EPOW reset event warnings
+    - LP: #1539102
+  * lightnvm: fix bio submission issue
+    - LP: #1531539
+  * lightnvm: fix incorrect nr_free_blocks stat
+    - LP: #1531539
+  * lightnvm: add check after mempool allocation
+    - LP: #1531539
+  * lightnvm: unlock rq and free ppa_list on submission fail
+    - LP: #1531539
+  * lightnvm: move ppa erase logic to core
+    - LP: #1531539
+  * lightnvm: refactor rqd ppa list into set/free
+    - LP: #1531539
+  * lightnvm: refactor end_io functions for sync
+    - LP: #1531539
+  * lightnvm: return the get_bb_tbl return value
+    - LP: #1531539
+  * lightnvm: check bi_error in gc
+    - LP: #1531539
+  * lightnvm: put block back to gc list on its reclaim fail
+    - LP: #1531539
+  * lightnvm: fix locking and mempool in rrpc_lun_gc
+    - LP: #1531539
+  * lightnvm: sectors first in ppa list
+    - LP: #1531539
+  * lightnvm: move the pages per block check out of the loop
+    - LP: #1531539
+  * lightnvm: support multiple ppas in nvm_erase_ppa
+    - LP: #1531539
+  * lightnvm: move rq->error to nvm_rq->error
+    - LP: #1531539
+  * lightnvm: introduce nvm_submit_ppa
+    - LP: #1531539
+  * lightnvm: reference rrpc lun in rrpc block
+    - LP: #1531539
+  * lightnvm: fix missing grown bad block type
+    - LP: #1531539
+  * lightnvm: manage open and closed blocks separately
+    - LP: #1531539
+  * lightnvm: add mccap support
+    - LP: #1531539
+  * lightnvm: introduce mlc lower page table mappings
+    - LP: #1531539
+  * lightnvm: core on-disk initialization
+    - LP: #1531539
+  * lightnvm: introduce ioctl to initialize device
+    - LP: #1531539
+  * lightnvm: use system block for mm initialization
+    - LP: #1531539
+  * lightnvm: introduce factory reset
+    - LP: #1531539
+  * lightnvm: ensure that nvm_dev_ops can be used without CONFIG_NVM
+    - LP: #1531539
+  * blk-mq: add a flags parameter to blk_mq_alloc_request
+    - LP: #1531539
+  * nvme: move struct nvme_iod to pci.c
+    - LP: #1531539
+  * nvme: split command submission helpers out of pci.c
+    - LP: #1531539
+  * nvme: use offset instead of a struct for registers
+    - LP: #1531539
+  * nvme: split nvme_trans_device_id_page
+    - LP: #1531539
+  * nvme: use vendor it from identify
+    - LP: #1531539
+  * nvme: split a new struct nvme_ctrl out of struct nvme_dev
+    - LP: #1531539
+  * nvme: simplify nvme_setup_prps calling convention
+    - LP: #1531539
+  * nvme: refactor nvme_queue_rq
+    - LP: #1531539
+  * nvme: factor out a nvme_unmap_data helper
+    - LP: #1531539
+  * nvme: move nvme_error_status to common code
+    - LP: #1531539
+  * nvme: move nvme_setup_flush and nvme_setup_rw to common code
+    - LP: #1531539
+  * nvme: split __nvme_submit_sync_cmd
+    - LP: #1531539
+  * nvme: use the block layer for userspace passthrough metadata
+    - LP: #1531539
+  * nvme: move block_device_operations and ns/ctrl freeing to common code
+    - LP: #1531539
+  * nvme: add explicit quirk handling
+    - LP: #1531539
+  * nvme: move remaining CC setup into nvme_enable_ctrl
+    - LP: #1531539
+  * nvme: move nvme_{enable,disable,shutdown}_ctrl to common code
+    - LP: #1531539
+  * nvme: add a common helper to read Identify Controller data
+    - LP: #1531539
+  * nvme: move the call to nvme_init_identify earlier
+    - LP: #1531539
+  * nvme: move namespace scanning to common code
+    - LP: #1531539
+  * nvme: move chardev and sysfs interface to common code
+    - LP: #1531539
+  * nvme: refactor set_queue_count
+    - LP: #1531539
+  * blk-integrity: empty implementation when disabled
+    - LP: #1531539
+  * NVMe: fix build with CONFIG_NVM enabled
+    - LP: #1531539
+  * nvme: fix another 32-bit build warning
+    - LP: #1531539
+  * nvme: precedence bug in nvme_pr_clear()
+    - LP: #1531539
+  * nvme: only ignore hardware errors in nvme_create_io_queues
+    - LP: #1531539
+  * nvme: only add a controller to dev_list after it's been fully
+    initialized
+    - LP: #1531539
+  * nvme: protect against simultaneous shutdown invocations
+    - LP: #1531539
+  * nvme: don't take the I/O queue q_lock in nvme_timeout
+    - LP: #1531539
+  * nvme: merge nvme_abort_req and nvme_timeout
+    - LP: #1531539
+  * nvme: add NVME_SC_CANCELLED
+    - LP: #1531539
+  * nvme: simplify resets
+    - LP: #1531539
+  * nvme: do not restart the request timeout if we're resetting the
+    controller
+    - LP: #1531539
+  * nvme: merge probe_work and reset_work
+    - LP: #1531539
+  * nvme: remove dead controllers from a work item
+    - LP: #1531539
+  * nvme: switch abort_limit to an atomic_t
+    - LP: #1531539
+  * NVMe: Implement namespace list scanning
+    - LP: #1531539
+  * NVMe: Use unbounded work queue for all work
+    - LP: #1531539
+  * NVMe: Remove device management handles on remove
+    - LP: #1531539
+  * NVMe: Simplify metadata setup
+    - LP: #1531539
+  * nvme: fix admin queue depth
+    - LP: #1531539
+  * nvme: factor out a few helpers from req_completion
+    - LP: #1531539
+  * nvme: switch delete SQ/CQ to blk_execute_rq_nowait
+    - LP: #1531539
+  * nvme: switch abort to blk_execute_rq_nowait
+    - LP: #1531539
+  * nvme: special case AEN requests
+    - LP: #1531539
+  * nvme: simplify completion handling
+    - LP: #1531539
+  * nvme: properly free resources for cancelled command
+    - LP: #1531539
+  * nvme: meta_sg doesn't have to be an array
+    - LP: #1531539
+  * nvme: merge iod and cmd_info
+    - LP: #1531539
+  * NVMe: Add pci error handlers
+    - LP: #1531539
+  * NVMe: Export namespace attributes to sysfs
+    - LP: #1531539
+  * nvme: Move nvme_freeze/unfreeze_queues to nvme core
+    - LP: #1531539
+  * nvme: synchronize access to ctrl->namespaces
+    - LP: #1531539
+  * nvme: fixes for NVME_IOCTL_IO_CMD on the char device
+    - LP: #1531539
+  * nvme: make SG_IO support optional
+    - LP: #1531539
+  * NVMe: Fix admin queue ring wrap
+    - LP: #1531539
+  * NVMe: Use a retryable error code on reset
+    - LP: #1531539
+  * NVMe: Remove queue freezing on resets
+    - LP: #1531539
+  * NVMe: IO queue deletion re-write
+    - LP: #1531539
+  * NVMe: Shutdown controller only for power-off
+    - LP: #1531539
+  * NVMe: Export NVMe attributes to sysfs group
+    - LP: #1531539
+  * i40e: fix build warnings
+  * net: i40e: shut up uninitialized variable warnings
+  * Drivers: hv: vmbus: fix build warning
+  * Drivers: hv: util: Increase the timeout for util services
+  * Drivers: hv: utils: run polling callback always in interrupt context
+  * tools: hv: report ENOSPC errors in hv_fcopy_daemon
+  * tools: hv: remove repeated HV_FCOPY string
+  * Drivers: hv: util: catch allocation errors
+  * Drivers: hv: utils: use memdup_user in hvt_op_write
+  * drivers/hv: cleanup synic msrs if vmbus connect failed
+  * drivers:hv: Export a function that maps Linux CPU num onto Hyper-V proc
+    num
+  * drivers:hv: Export the API to invoke a hypercall on Hyper-V
+  * drivers:hv: Define the channel type for Hyper-V PCI Express
+    pass-through
+  * Drivers: hv: vss: run only on supported host versions
+  * Drivers: hv: vmbus: Use uuid_le type consistently
+  * Drivers: hv: vmbus: Use uuid_le_cmp() for comparing GUIDs
+  * Drivers: hv: vmbus: Get rid of the unused macro
+  * Drivers: hv: vmbus: Get rid of the unused irq variable
+  * Drivers: hv: vmbus: serialize process_chn_event() and
+    vmbus_close_internal()
+  * Drivers: hv: vmbus: do sanity check of channel state in
+    vmbus_close_internal()
+  * Drivers: hv: vmbus: fix rescind-offer handling for device without a
+    driver
+  * Drivers: hv: vmbus: release relid on error in vmbus_process_offer()
+  * Drivers: hv: vmbus: channge vmbus_connection.channel_lock to mutex
+  * drivers:hv: Allow for MMIO claims that span ACPI _CRS records
+  * Drivers: hv: vmbus: Fix a Host signaling bug
+  * drivers/hv: correct tsc page sequence invalid value
+  * Drivers: hv: vmbus: Force all channel messages to be delivered on CPU 0
+  * Drivers: hv: utils: Invoke the poll function after handshake
+  * tools: hv: vss: fix the write()'s argument: error -> vss_msg
+  * Drivers: hv: utils: fix memory leak on on_msg() failure
+  * Drivers: hv: utils: rename outmsg_lock
+  * Drivers: hv: utils: introduce HVUTIL_TRANSPORT_DESTROY mode
+  * Drivers: hv: utils: fix crash when device is removed from host side
+  * Drivers: hv: ring_buffer.c: fix comment style
+  * Drivers: hv: ring_buffer: remove stray smp_read_barrier_depends()
+  * Drivers: hv: ring_buffer: remove code duplication from
+    hv_ringbuffer_peek/read()
+  * Drivers: hv: remove code duplication between
+    vmbus_recvpacket()/vmbus_recvpacket_raw()
+  * Drivers: hv: ring_buffer: eliminate hv_ringbuffer_peek()
+  * drivers/hv: replace enum hv_message_type by u32
+  * drivers/hv: Move HV_SYNIC_STIMER_COUNT into Hyper-V UAPI x86 header
+  * drivers/hv: Move struct hv_message into UAPI Hyper-V x86 header
+  * drivers/hv: Move struct hv_timer_message_payload into UAPI Hyper-V x86
+    header
+  * Drivers: hv: vmbus: fix the building warning with hyperv-keyboard
+  * Drivers: hv: utils: fix hvt_op_poll() return value on transport destroy
+  * Drivers: hv: vmbus: Treat Fibre Channel devices as performance critical
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4.1
+    - LP: #1533461
+    - LP: #1529624
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 29 Jan 2016 08:06:37 -0700
+
+linux (4.4.0-2.16) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1539090
+  * SAUCE: hv: hv_set_ifconfig -- convert to python3
+    - LP: #1506521
+  * SAUCE: dm: introduce a target_ioctl op to allow target specific ioctls
+    - LP: #1538618
+
+  [ Colin Ian King ]
+
+  * SAUCE: ACPI / tables: Add acpi_force_32bit_fadt_addr option to force 32
+    bit FADT addresses (LP: #1529381)
+    - LP: #1529381
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up): apparmor: fix for failed mediation of socket that is
+    being shutdown
+    - LP: #1446906
+
+  [ Mahesh Salgaonkar ]
+
+  * SAUCE: Powernv: Remove the usage of PACAR1 from opal wrappers
+    - LP: #1537881
+  * SAUCE: powerpc/book3s: Fix TB corruption in guest exit path on HMI
+    interrupt.
+    - LP: #1537881
+  * SAUCE: KVM: PPC: Book3S HV: Fix soft lockups in KVM on HMI for time
+    base errors
+    - LP: #1537881
+
+  [ Paolo Pisati ]
+
+  * SAUCE: arm64: errata: Add -mpc-relative-literal-loads to erratum
+    #843419 build flags
+    - LP: #1533009
+  * [Config] MFD_TPS65217=y && REGULATOR_TPS65217=y
+  * [Config] disable ARCH_ZX (ZTE ZX Soc)
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: (noup) cxlflash: a couple off by one bugs"
+  * SAUCE: (no-up) Update bnx2x firmware to 7.12.30.0
+    - LP: #1536719
+  * SAUCE: drop obsolete bnx2x firmware
+  * SAUCE: i40e: Silence 'may be used uninitialized' warnings
+    - LP: #1536474
+  * [Config] CONFIG_ZONE_DMA=y for amd64 lowlatency
+    - LP: #1534647
+  * [Config] Add pvpanic to virtual flavour
+    - LP: #1537923
+  * [Config] CONFIG_INTEL_PUNIT_IPC=m, CONFIG_INTEL_TELEMETRY=m
+    - LP: #1520457
+
+  [ Upstream Kernel Changes ]
+
+  * i40evf: fix compiler warning of unused variable
+    - LP: #1536474
+  * intel: i40e: fix confused code
+    - LP: #1536474
+  * i40e/i40evf: remove unused tunnel parameter
+    - LP: #1536474
+  * i40e: Change BUG_ON to WARN_ON in service event complete
+    - LP: #1536474
+  * i40e: remove BUG_ON from feature string building
+    - LP: #1536474
+  * i40e: remove BUG_ON from FCoE setup
+    - LP: #1536474
+  * i40e: Workaround fix for mss < 256 issue
+    - LP: #1536474
+  * i40e/i40evf: Add a stat to track how many times we have to do a force
+    WB
+    - LP: #1536474
+  * i40e: Move the saving of old link info from handle_link_event to
+    link_event
+    - LP: #1536474
+  * i40e/i40evf: Add comment to #endif
+    - LP: #1536474
+  * i40e/i40evf: clean up error messages
+    - LP: #1536474
+  * i40evf: handle many MAC filters correctly
+    - LP: #1536474
+  * i40e: return the number of enabled queues for ETHTOOL_GRXRINGS
+    - LP: #1536474
+  * i40e: rework the functions to configure RSS with similar parameters
+    - LP: #1536474
+  * i40e: create a generic configure rss function
+    - LP: #1536474
+  * i40e: Bump version to 1.4.2
+    - LP: #1536474
+  * i40e: add new fields to store user configuration
+    - LP: #1536474
+  * i40e: rename rss_size to alloc_rss_size in i40e_pf
+    - LP: #1536474
+  * i40e/i40evf: Fix RS bit update in Tx path and disable force WB
+    workaround
+    - LP: #1536474
+  * i40e/i40evf: prefetch skb data on transmit
+    - LP: #1536474
+  * i40evf: rename VF adapter specific RSS function
+    - LP: #1536474
+  * i40evf: create a generic config RSS function
+    - LP: #1536474
+  * i40evf: create a generic get RSS function
+    - LP: #1536474
+  * i40evf: add new fields to store user configuration of RSS
+    - LP: #1536474
+  * i40e: Update error messaging
+    - LP: #1536474
+  * i40e: fix confusing message
+    - LP: #1536474
+  * i40e: make error message more useful
+    - LP: #1536474
+  * i40evf: quoth the VF driver, Nevermore
+    - LP: #1536474
+  * i40evf: allocate queue vectors dynamically
+    - LP: #1536474
+  * i40evf: allocate ring structs dynamically
+    - LP: #1536474
+  * i40e/i40evf: Bump i40e version to 1.4.4 and i40evf to 1.4.1
+    - LP: #1536474
+  * i40e: fix: do not sleep in netdev_ops
+    - LP: #1536474
+  * i40e: remove unused argument
+    - LP: #1536474
+  * i40evf: increase max number of queues
+    - LP: #1536474
+  * i40evf: set real num queues
+    - LP: #1536474
+  * i40evf: remove duplicate string
+    - LP: #1536474
+  * i40e: Detection and recovery of TX queue hung logic moved to
+    service_task from tx_timeout
+    - LP: #1536474
+  * i40e: Fix memory leaks, sideband filter programming
+    - LP: #1536474
+  * i40evf: don't use atomic allocation
+    - LP: #1536474
+  * i40e: propagate properly
+    - LP: #1536474
+  * i40evf: use correct types
+    - LP: #1536474
+  * i40e: use priv flags to control packet split
+    - LP: #1536474
+  * i40e: Remove separate functions gathering XOFF Rx stats
+    - LP: #1536474
+  * i40e: fix whitespace
+    - LP: #1536474
+  * i40e/i40evf: use logical operator
+    - LP: #1536474
+  * i40e/i40evf: Bump version to 1.4.7 for i40e and 1.4.3 for i40evf
+    - LP: #1536474
+  * i40e: trivial fixes
+    - LP: #1536474
+  * i40e: Fix i40e_print_features() VEB mode output
+    - LP: #1536474
+  * i40e: chomp the BIT(_ULL)
+    - LP: #1536474
+  * i40e: properly delete VF MAC filters
+    - LP: #1536474
+  * i40e: don't add zero MAC filter
+    - LP: #1536474
+  * i40evf: check rings before freeing resources
+    - LP: #1536474
+  * i40e: use explicit cast from u16 to u8
+    - LP: #1536474
+  * i40e: Opcode and structures required by OEM Post Update AQ command and
+    add new NVM arq message
+    - LP: #1536474
+  * i40e: hush little warnings
+    - LP: #1536474
+  * i40e/i40evf: Add a new offload for RSS PCTYPE V2 for X722
+    - LP: #1536474
+  * i40e: clean whole mac filter list
+    - LP: #1536474
+  * i40evf: change version string generation
+    - LP: #1536474
+  * i40e/i40evf: Bump i40e to 1.4.8 and i40evf to 1.4.4
+    - LP: #1536474
+  * geneve: UDP checksum configuration via netlink
+    - LP: #1536474
+  * geneve: Add geneve udp port offload for ethernet devices
+    - LP: #1536474
+  * i40e: geneve tunnel offload support
+    - LP: #1536474
+  * geneve: Add geneve_get_rx_port support
+    - LP: #1536474
+  * i40e: Call geneve_get_rx_port to get the existing Geneve ports
+    - LP: #1536474
+  * i40e: change log messages and error returns
+    - LP: #1536474
+  * i40e: allow zero MAC address for VFs
+    - LP: #1536474
+  * i40e: Look up MAC address in Open Firmware or IDPROM
+    - LP: #1536474
+  * i40e: Fix Rx hash reported to the stack by our driver
+    - LP: #1536474
+  * i40e: remove forever unused ID
+    - LP: #1536474
+  * igb: add 88E1543 initialization code
+  * igb: don't unmap NULL hw_addr
+  * igb: use the correct i210 register for EEMNGCTL
+  * igb: fix NULL derefs due to skipped SR-IOV enabling
+  * igb: improve handling of disconnected adapters
+  * igb: Remove GS40G specific defines/functions
+  * igb: Don't add PHY address to PCDL address
+  * igb: Improve cable length function for I210, etc.
+  * igb: Explicitly label self-test result indices
+  * ixgbe: drop null test before destroy functions
+    - LP: #1536473
+  * ixgbe: Delete redundant include file
+    - LP: #1536473
+  * ixgbe: fix multiple kernel-doc errors
+    - LP: #1536473
+  * ixgbe: Fix handling of NAPI budget when multiple queues are enabled per
+    vector
+    - LP: #1536473
+  * ixgbe: Add KR mode support for CS4227 chip
+    - LP: #1536473
+  * ixgbevf: Limit lowest interrupt rate for adaptive interrupt moderation
+    to 12K
+    - LP: #1536473
+  * ixgbe/ixgbevf: use napi_schedule_irqoff()
+    - LP: #1536473
+  * ixgbe: Remove CS4227 diagnostic code
+    - LP: #1536473
+  * ixgbevf: use ether_addr_copy instead of memcpy
+    - LP: #1536473
+  * ixgbevf: fix spoofed packets with random MAC
+    - LP: #1536473
+  * ixgbe: Prevent KR PHY reset in ixgbe_init_phy_ops_x550em
+    - LP: #1536473
+  * ixgbe: Add support for newer thermal alarm
+    - LP: #1536473
+  * ixgbe: Use private workqueue to avoid certain possible hangs
+    - LP: #1536473
+  * ixgbevf: Use a private workqueue to avoid certain possible hangs
+    - LP: #1536473
+  * ixgbevf: Minor cleanups
+    - LP: #1536473
+  * ixgbe: Refactor MAC address configuration code
+    - LP: #1536473
+  * ixgbe: Use __dev_uc_sync and __dev_uc_unsync for unicast addresses
+    - LP: #1536473
+  * ixgbe: Allow FDB entries access to more RAR filters
+    - LP: #1536473
+  * ixgbe: Update PTP to support X550EM_x devices
+    - LP: #1536473
+  * ixgbe: Correct spec violations by waiting after reset
+    - LP: #1536473
+  * ixgbe: Wait for master disable to be set
+    - LP: #1536473
+  * ixgbe: Save VF info and take references
+    - LP: #1536473
+  * ixgbe: Handle extended IPv6 headers in Tx path
+    - LP: #1536473
+  * ixgbe: Always turn PHY power on when requested
+    - LP: #1536473
+  * ixgbevf: Handle extended IPv6 headers in Tx path
+    - LP: #1536473
+  * ixgbe: Return error on failure to allocate mac_table
+    - LP: #1536473
+  * ixgbe: Fix SR-IOV VLAN pool configuration
+    - LP: #1536473
+  * ixgbe: Simplify definitions for regidx and bit in set_vfta
+    - LP: #1536473
+  * ixgbe: Reduce VT code indent in set_vfta by introducing jump label
+    - LP: #1536473
+  * ixgbe: Simplify configuration of setting VLVF and VLVFB
+    - LP: #1536473
+  * ixgbe: Add support for adding/removing VLAN on PF bypassing the VLVF
+    - LP: #1536473
+  * ixgbe: Reorder search to work from the top down instead of bottom up
+    - LP: #1536473
+  * ixgbe: Add support for VLAN promiscuous with SR-IOV
+    - LP: #1536473
+  * ixgbe: Fix VLAN promisc in relation to SR-IOV
+    - LP: #1536473
+  * ixgbe: Clear stale pool mappings
+    - LP: #1536473
+  * ixgbe: Clean stale VLANs when changing port VLAN or resetting
+    - LP: #1536473
+  * ixgbe: do not report 2.5 Gbps as supported
+    - LP: #1536473
+  * ixgbevf: Fix handling of NAPI budget when multiple queues are enabled
+    per vector
+    - LP: #1536473
+  * ixgbevf: minor cleanups for ixgbevf_set_itr()
+    - LP: #1536473
+  * ixgbe: add support for QSFP PHY types in ixgbe_get_settings()
+    - LP: #1536473
+  * ixgbe: report correct media type for KR, KX and KX4 interfaces
+    - LP: #1536473
+  * ixgbe: Clean up redundancy in hw_enc_features
+    - LP: #1536473
+  * ixgbe: fix RSS limit for X550
+    - LP: #1536473
+  * ixgbe: Correct X550EM_x revision check
+    - LP: #1536473
+  * ixgbe: Fix bugs in ixgbe_clear_vf_vlans()
+    - LP: #1536473
+  * ixgbe: Fill at least min credits to a TC credit refills
+    - LP: #1536473
+  * ixgbe: use correct FCoE DDP max check
+    - LP: #1536473
+  * ixgbe: fix broken PFC with X550
+    - LP: #1536473
+  * ixgbe: do not call check_link for ethtool in ixgbe_get_settings()
+    - LP: #1536473
+  * ixgbe: Correct handling of any outer UDP checksum setting
+    - LP: #1536473
+  * ixgbe: Fix to get FDMI HBA attributes information with X550
+    - LP: #1536473
+  * ixgbe: Fix MDD events generated when FCoE+SRIOV are enabled
+    - LP: #1536473
+  * ixgbe: Make ATR recognize IPv6 extended headers
+    - LP: #1536473
+  * e1000: make eeprom read/write scheduler friendly
+  * e1000: fix data race between tx_ring->next_to_clean
+  * e1000: Remove checkpatch coding style errors
+  * e1000: clean up the checking logic
+  * e1000: fix a typo in the comment
+  * e1000e: clean up the local variable
+  * e1000: fix kernel-doc argument being missing
+  * e1000: get rid of duplicate exit path
+  * e1000: Elementary checkpatch warnings and checks removed
+  * e1000e: fix division by zero on jumbo MTUs
+  * e1000e: Increase timeout of polling bit RSPCIPHY
+  * e1000e: initial support for i219-LM (3)
+  * e1000e: Switch e1000e_up to void, drop code checking for error result
+  * e1000e: Remove unreachable code
+  * e1000e: Do not read ICR in Other interrupt
+  * e1000e: Do not write lsc to ics in msi-x mode
+  * e1000e: Fix msi-x interrupt automask
+  * acpi: pci: Setup MSI domain for ACPI based pci devices
+  * irqdomain: Introduce is_fwnode_irqchip helper
+  * irqchip/gic-v2m: Refactor to prepare for ACPI support
+  * irqchip/gic-v2m: acpi: Introducing GICv2m ACPI support
+  * clk: xgene: Fix divider with non-zero shift value
+  * i2c: designware: Do not require clock when SSCN and FFCN are provided
+  * fm10k: do not assume VF always has 1 queue
+    - LP: #1536475
+  * fm10k: Correct MTU for jumbo frames
+    - LP: #1536475
+  * fm10k: Fix handling of NAPI budget when multiple queues are enabled per
+    vector
+    - LP: #1536475
+  * fm10k: use napi_schedule_irqoff()
+    - LP: #1536475
+  * fm10k: set netdev features in one location
+    - LP: #1536475
+  * fm10k: reset max_queues on init_hw_vf failure
+    - LP: #1536475
+  * fm10k: always check init_hw for errors
+    - LP: #1536475
+  * fm10k: reinitialize queuing scheme after calling init_hw
+    - LP: #1536475
+  * fm10k: Correct typecast in fm10k_update_xc_addr_pf
+    - LP: #1536475
+  * fm10k: explicitly typecast vlan values to u16
+    - LP: #1536475
+  * fm10k: add statistics for actual DWORD count of mbmem mailbox
+    - LP: #1536475
+  * fm10k: rename mbx_tx_oversized statistic to mbx_tx_dropped
+    - LP: #1536475
+  * fm10k: Add support for ITR scaling based on PCIe link speed
+    - LP: #1536475
+  * fm10k: introduce ITR_IS_ADAPTIVE macro
+    - LP: #1536475
+  * fm10k: Update adaptive ITR algorithm
+    - LP: #1536475
+  * fm10k: use macro for default Tx and Rx ITR values
+    - LP: #1536475
+  * fm10k: change default Tx ITR to 25usec
+    - LP: #1536475
+  * fm10k: TRIVIAL fix typo of hardware
+    - LP: #1536475
+  * fm10k: TRIVIAL cleanup order at top of fm10k_xmit_frame
+    - LP: #1536475
+  * fm10k: use ether_addr_copy to copy MAC address
+    - LP: #1536475
+  * fm10k: do not use CamelCase
+    - LP: #1536475
+  * fm10k: remove unnecessary else block from if statements with return
+    - LP: #1536475
+  * fm10k: remove namespace pollution of fm10k_iov_msg_data_pf
+    - LP: #1536475
+  * fm10k: consistently refer to VLANs and VLAN IDs
+    - LP: #1536475
+  * fm10k: bump driver version
+    - LP: #1536475
+  * fm10k: conditionally compile DCB and DebugFS support
+    - LP: #1536475
+  * fm10k: Cleanup MSI-X interrupts in case of failure
+    - LP: #1536475
+  * fm10k: Cleanup exception handling for mailbox interrupt
+    - LP: #1536475
+  * fm10k: do not inline fm10k_iov_select_vid()
+    - LP: #1536475
+  * fm10k: whitespace cleanups
+    - LP: #1536475
+  * fm10k: use BIT() macro instead of open-coded bit-shifting
+    - LP: #1536475
+  * fm10k: cleanup namespace pollution
+    - LP: #1536475
+  * fm10k: cleanup overly long lines
+    - LP: #1536475
+  * fm10k: initialize xps at driver load
+    - LP: #1536475
+  * fm10k: don't initialize fm10k_workqueue at global level
+    - LP: #1536475
+  * fm10k: correctly pack TLV structures and explain reasoning
+    - LP: #1536475
+  * fm10k: Cleanup exception handling for changing queues
+    - LP: #1536475
+  * fm10k: use ether_addr_equal instead of memcmp
+    - LP: #1536475
+  * fm10k: address operator not needed when declaring function pointers
+    - LP: #1536475
+  * fm10k: constify fm10k_mac_ops, fm10k_iov_ops and fm10k_info structures
+    - LP: #1536475
+  * fm10k: remove unused struct element
+    - LP: #1536475
+  * fm10k: use true/false for boolean get_host_state
+    - LP: #1536475
+  * fm10k: cleanup mailbox code comments etc
+    - LP: #1536475
+  * fm10k: IS_ENABLED() is not appropriate for boolean kconfig option
+    - LP: #1536475
+  * device property: always check for fwnode type
+    - LP: #1533035
+  * device property: rename helper functions
+    - LP: #1533035
+  * device property: refactor built-in properties support
+    - LP: #1533035
+  * device property: keep single value inplace
+    - LP: #1533035
+  * device property: helper macros for property entry creation
+    - LP: #1533035
+  * device property: improve readability of macros
+    - LP: #1533035
+  * device property: return -EINVAL when property isn't found in ACPI
+    - LP: #1533035
+  * device property: Fallback to secondary fwnode if primary misses the
+    property
+    - LP: #1533035
+  * device property: Take a copy of the property set
+    - LP: #1533035
+  * driver core: platform: Add support for built-in device properties
+    - LP: #1533035
+  * driver core: Do not overwrite secondary fwnode with NULL if it is set
+    - LP: #1533035
+  * mfd: core: propagate device properties to sub devices drivers
+    - LP: #1533035
+  * mfd: intel-lpss: Add support for passing device properties
+    - LP: #1533035
+  * mfd: intel-lpss: Pass SDA hold time to I2C host controller driver
+    - LP: #1533035
+  * mfd: intel-lpss: Pass HSUART configuration via properties
+    - LP: #1533035
+  * i2c: designware: Convert to use unified device property API
+    - LP: #1533035
+  * keys, trusted: fix: *do not* allow duplicate key options
+    - LP: #1398274
+  * keys, trusted: select hash algorithm for TPM2 chips
+    - LP: #1398274
+  * keys, trusted: seal with a TPM2 authorization policy
+    - LP: #1398274
+  * perf/x86/intel: Add perf core PMU support for Intel Knights Landing
+    - LP: #1461360
+  * perf/x86/intel/uncore: Add Knights Landing uncore PMU support
+    - LP: #1461360
+  * perf/x86/intel/uncore: Remove hard coding of PMON box control MSR
+    offset
+    - LP: #1461360
+  * drm/i915: WaRsDisableCoarsePowerGating
+    - LP: #1527462
+  * drm/i915/skl: Add SKL GT4 PCI IDs
+    - LP: #1527462
+  * drm/i915/skl: Disable coarse power gating up until F0
+    - LP: #1527462
+  * platform:x86: add Intel P-Unit mailbox IPC driver
+    - LP: #1520457
+  * intel_punit_ipc: add NULL check for input parameters
+    - LP: #1520457
+  * platform/x86: Add Intel Telemetry Core Driver
+    - LP: #1520457
+  * intel_pmc_ipc: update acpi resource structure for Punit
+    - LP: #1520457
+  * platform:x86: Add Intel telemetry platform device
+    - LP: #1520457
+  * platform:x86: Add Intel telemetry platform driver
+    - LP: #1520457
+  * platform:x86: Add Intel Telemetry Debugfs interfaces
+    - LP: #1520457
+  * cxlflash: a couple off by one bugs
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 28 Jan 2016 13:56:00 +0000
+
+linux (4.4.0-1.15) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1536803
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[SCSI] libiscsi: Reduce locking contention in fast path"
+    - LP: #1517142
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 20 Jan 2016 07:41:40 -0700
+
+linux (4.4.0-0.14) xenial; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "powerpc/pci: Remove unused struct pci_dn.pcidev field"
+    - LP: #1522415
+  * powerpc: Add __raw_rm_writeq() function
+    - LP: #1522415
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 19 Jan 2016 11:24:26 -0700
+
+linux (4.4.0-0.13) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] s390x -- the kernel provides ppp-modules such as there are
+  * SAUCE: (no-up) add compat_uts_machine= kernel command line override
+
+  [ Tim Gardner ]
+
+  * [Config] Update annotations for VIRTIO_{NET,BLK}
+    - LP: #1533382
+
+  [ Upstream Kernel Changes ]
+
+  * powerpc/powernv: Add support for Nvlink NPUs
+    - LP: #1522415
+  * powerpc/powernv: Fix update of NVLink DMA mask
+    - LP: #1522415
+  * powerpc/powernv: Change NPU PE# assignment
+    - LP: #1522415
+  * powerpc/powernv: Reserve PE#0 on NPU
+    - LP: #1522415
+  * KEYS: Fix keyring ref leak in join_session_keyring()
+    - LP: #1534887
+    - CVE-2016-0728
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 19 Jan 2016 05:49:09 -0700
+
+linux (4.4.0-0.12) xenial; urgency=low
+
+  [ Eric Dumazet ]
+
+  * SAUCE: (no-up) udp: properly support MSG_PEEK with truncated buffers
+    - LP: #1527902
+
+  [ Guilherme G. Piccoli ]
+
+  * SAUCE: powerpc/eeh: Validate arch in eeh_add_device_early()
+    - LP: #1486180
+
+  [ Tim Gardner ]
+
+  * SAUCE: AUFS - update to aufs4.x-rcN 20160111
+  * [Config] CONFIG_VIRTIO_BLK=y, CONFIG_VIRTIO_NET=y for s390
+    - LP: #1532886
+  * [Config] nvme.ko moved to drivers/nvme/host
+  * [Config] scsi_dh morphed into 4 modules
+  * [Config] CONFIG_IBMVNIC=m
+  * [Config] Add DRM ast driver to udeb installer image
+    - LP: #1514711
+  * [Config] CONFIG_KVM=y for s390x
+    - LP: #1532886
+  * [Config] Install spl/zfs under the kernel modules directory
+    Fixes some errors in generic.inclusion-list.log
+
+  [ Upstream Kernel Changes ]
+
+  * perf/x86/intel/uncore: Add Broadwell-EP uncore support
+    - LP: #1524574
+  * EDAC: Add DDR4 flag
+    - LP: #1519631
+  * EDAC, sb_edac: Virtualize several hard-coded functions
+    - LP: #1519631
+  * EDAC, sb_edac: Add support for duplicate device IDs
+    - LP: #1519631
+  * EDAC, sb_edac: Add Knights Landing (Xeon Phi gen 2) support
+    - LP: #1519631
+  * Driver for IBM System i/p VNIC protocol
+    - LP: #1532303
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 11 Jan 2016 09:57:16 -0700
+
+linux (4.4.0-0.11) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Fix bogus reconstruct script
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 11 Jan 2016 07:29:17 -0700
+
+linux (4.4.0-0.10) xenial; urgency=low
+
+  [ Haren Myneni ]
+
+  * SAUCE: crypto: nx-842 - Mask XERS0 bit in return value
+    - LP: #1529666
+
+  [ Serge Hallyn ]
+
+  * SAUCE: add a sysctl to disable unprivileged user namespace unsharing
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_ZONE_DEVICE=y for amd64
+  * [Config] CONFIG_BLK_DEV_LOOP=y for s390x
+    - LP: #1526869
+  * SAUCE: (no-up) apparmor: Fix incompatible pointer type warnings
+  * SAUCE: radeon: r100: Silence 'may be used uninitialized' warnings
+  * SAUCE: dmaengine: ioatdma: Squelch framesize warnings
+  * rebase to v4.4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 04 Jan 2016 17:43:51 -0700
+
+linux (4.4.0-0.9) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v4.4-rc8
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc8
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 03 Jan 2016 18:50:33 -0700
+
+linux (4.4.0-0.8) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v4.4-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 28 Dec 2015 16:13:11 -0700
+
+linux (4.4.0-0.7) xenial; urgency=low
+
+  [ Hui Wang ]
+
+  * [Config] CONFIG_I2C_DESIGNWARE_BAYTRAIL=y, CONFIG_IOSF_MBI=y
+    - LP: #1527096
+
+  [ Jann Horn ]
+
+  * SAUCE: (noup) ptrace: being capable wrt a process requires mapped
+    uids/gids
+    - LP: #1527374
+
+  [ Tim Gardner ]
+
+  * rebase to v4.4-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc6
+    - LP: #1526330
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 17 Dec 2015 05:28:27 -0700
+
+linux (4.4.0-0.6) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] disable CONFIG_ARM64_LSE_ATOMICS to avoid issues with ARMv8.1
+    support in latest compilers
+  * [Config] disable CONFIG_CRYPTO_AES_ARM64_CE* to avoid issues with
+    ARMv8.1 support in latest compilers
+
+  [ Tim Gardner ]
+
+  * [Config] s390 -> s390x
+  * SAUCE: include/linux/mmdebug.h: #include <linux/bug.h>
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Dec 2015 06:46:26 -0700
+
+linux (4.4.0-0.5) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] s390x -- enable tools
+    - LP: #1524319
+  * [Config] s390x -- add architecture to getabis
+  * [Config] s390x -- add s390x ABI information
+  * [Config] s390x -- enable ABI checks
+
+  [ Tim Gardner ]
+
+  * [Debian] config-check and prepare using ${DEBIAN}/config/annotations
+  * [Config] Add s390 modules to nic-modules udeb
+    - LP: #1525297
+  * rebase to v4.4-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc5
+    - LP: #1523517
+    - LP: #1523232
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 14 Dec 2015 05:28:05 -0700
+
+linux (4.4.0-0.4) xenial; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * cgroup: make css_set pin its css's to avoid use-afer-free
+  * cgroup_freezer: simplify propagation of CGROUP_FROZEN clearing in
+    freezer_attach()
+  * cgroup: fix handling of multi-destination migration from
+    subtree_control enabling
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Dec 2015 11:20:41 -0700
+
+linux (4.4.0-0.3) xenial; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc4
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 06 Dec 2015 16:50:15 -0700
+
+linux (4.4.0-0.2) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Add spl/zfs provides to generic and powerpc64-smp
+  * [Config] Add zfs to d-i fs-core-modules
+  * [Config] Include all s390 specific drivers in linux-image
+    - LP: #1522210
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 03 Dec 2015 07:05:56 -0700
+
+linux (4.4.0-0.1) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Tests] gcc-multilib does not exist on ppc64el redux
+    - LP: #1515541
+  * [Config] libunwind8-dev is not available on s390x
+  * [Debian] Disable SPL/ZFS for cross compiling -- redux
+  * [Config] s390x -- add dasd udebs
+    - LP: #1519833
+  * [Config] s390x -- include dasd modules in linux-image
+    - LP: #1519833
+  * [Config] s390x -- disable ZFS temporarily
+    - LP: #1519820
+  * [Config] s390s -- disable ABI/module checks
+  * [Config] make IBMVETH consistent on powerpc/ppc64el
+    - LP: #1521712
+  * [Config] follow ibmvscsi name change
+    - LP: #1521712
+  * [Config] move ibm disk and ethernet drivers to linux-image
+    - LP: #1521712
+  * [Config] include ibmveth in nic-modules for ppc64el
+    - LP: #1521712
+  * [Config] s390x -- disable abi/module checks for s390x
+
+  [ Joseph Salisbury ]
+
+  * SAUCE: scsi_sysfs: protect against double execution of
+    __scsi_remove_device()
+    - LP: #1509029
+
+  [ Seth Forshee ]
+
+  * [Config] CONFIG_DRM_AMDGPU_CIK=n
+    - LP: #1510405
+
+  [ Tim Gardner ]
+
+  * [Debian] Disable SPL/ZFS for cross compiling
+  * [Config] CONFIG_SCSI_IBMVSCSI=m
+    - LP: #1515872
+  * rebase to v4.4-rc2
+  * [Config] updateconfigs
+  * [Config] CONFIG_WILC1000_DRIVER=n for FTBS
+  * SAUCE: do_zfs=false temporarily
+  * [Config] CONFIG_LUSTRE_FS=n
+  * [Debian] Disable udebs when cross compiling
+  * rebase to v4.4-rc3
+  * [Config] CONFIG_AUFS_FS=m
+  * SAUCE: AUFS
+
+  [ Upstream Kernel Changes ]
+
+  * ZFS: Update with 4.4 support
+  * SPL: Update with 4.4 support
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.4-rc3
+    - LP: #1519168
+  * rebase to v4.4-rc2
+    - LP: #1506615
+    - LP: #1502781
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 23 Nov 2015 13:22:37 -0700
+
+linux (4.3.0-0.8) xenial; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] re-enable OSS support and blacklist
+    - LP: #1434842
+  * [Config] enable CONFIG_CC_STACKPROTECTOR_STRONG=y
+  * [Packaging] config-check -- improve syntax diagnostics
+  * [Packaging] module-inclusion -- add dependency inclusion for a list
+  * [Packaging] config-check -- accumulate multi-line annotations correctly
+  * [Packaging] config-check -- handle V2 annotations format
+  * [Packaging] s390x -- add architecture to kernelconfig
+    - LP: #1488653
+  * [Config] s390x -- initial configuration
+  * [Config] s390x -- add initial binary image
+  * [Config] s390x -- initial configuration update
+  * [Config] s390x -- produce linux-image
+  * [Config] s390x -- d-i module exclusions
+  * [Config] apply Device Drivers >> LED Support >> LED Class Support
+  * [Config] apply File systems >> Miscellaneous filesystems >> SquashFS 4.0 - Squashed file system support
+  * [Config] apply Device Drivers >> Generic Driver Options >> Userspace firmware loading support
+  * SAUCE: leds: lp55xx -- do not force use of the fallback loader
+  * [Config] -- s390x -- configuration review updates
+  * [Config] annotations -- add review marks
+  * [Config] annotations -- config review 4.3 updates
+  * [Config] annotations -- expose reviews
+  * [Config] updateconfigs following incoporation of s390x configs
+  * [Tests] gcc-multilib does not exist on ppc64el
+    - LP: #1515541
+
+  [ Dan Carpenter ]
+
+  * SAUCE: (noup) cxlflash: a couple off by one bugs
+    - LP: #1499849
+
+  [ Haren Myneni ]
+
+  * Revert "SAUCE: (noup) crypto: 842 - Add CRC and validation support"
+
+  [ Jay Vosburgh ]
+
+  * SAUCE: fan: add VXLAN implementation
+
+  [ Manoj Kumar ]
+
+  * SAUCE: (noup) cxlflash: Fix to escalate LINK_RESET also on port 1
+    - LP: #1513583
+
+  [ Matthew R. Ochs ]
+
+  * SAUCE: (noup) cxlflash: Fix to avoid virtual LUN failover failure
+    - LP: #1513583
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_AUFS_EXPORT=y
+    - LP: #1121699
+
+  [ Upstream Kernel Changes ]
+
+  * misc/genwqe: get rid of atomic allocations
+  * crypto: 842 - Add CRC and validation support
+    - LP: #1497878
+  * cxlflash: Fix to avoid invalid port_sel value
+  * cxlflash: Replace magic numbers with literals
+  * cxlflash: Fix read capacity timeout
+  * cxlflash: Fix potential oops following LUN removal
+  * cxlflash: Fix data corruption when vLUN used over multiple cards
+  * cxlflash: Fix to avoid sizeof(bool)
+  * cxlflash: Fix context encode mask width
+  * cxlflash: Fix to avoid CXL services during EEH
+  * cxlflash: Correct naming of limbo state and waitq
+  * cxlflash: Make functions static
+  * cxlflash: Refine host/device attributes
+  * cxlflash: Fix to avoid spamming the kernel log
+  * cxlflash: Fix to avoid stall while waiting on TMF
+  * cxlflash: Fix location of setting resid
+  * cxlflash: Fix host link up event handling
+  * cxlflash: Fix async interrupt bypass logic
+  * cxlflash: Remove dual port online dependency
+  * cxlflash: Fix AFU version access/storage and add check
+  * cxlflash: Correct usage of scsi_host_put()
+  * cxlflash: Fix to prevent workq from accessing freed memory
+  * cxlflash: Correct behavior in device reset handler following EEH
+  * cxlflash: Remove unnecessary scsi_block_requests
+  * cxlflash: Fix function prolog parameters and return codes
+  * cxlflash: Fix MMIO and endianness errors
+  * cxlflash: Fix to prevent EEH recovery failure
+  * cxlflash: Correct spelling, grammar, and alignment mistakes
+  * cxlflash: Fix to prevent stale AFU RRQ
+  * cxlflash: Fix to double the delay each time
+  * cxlflash: Fix to avoid corrupting adapter fops
+  * cxlflash: Correct trace string
+  * cxlflash: Fix to avoid potential deadlock on EEH
+  * cxlflash: Fix to avoid leaving dangling interrupt resources
+  * cxlflash: Fix to escalate to LINK_RESET on login timeout
+  * cxlflash: Fix to avoid corrupting port selection mask
+  * cxlflash: Fix to avoid lock instrumentation rejection
+  * cxlflash: Fix to avoid bypassing context cleanup
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 06 Nov 2015 10:15:07 -0600
+
+linux (4.3.0-0.7) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Revert "Bypass spl/zfs config"
+    Causes unresolved symbols on load.
+  * [Config] Enable ZFS for powerpc64-smp
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 05 Nov 2015 11:42:37 -0600
+
+linux (4.3.0-0.6) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1512704
+  * UBUNTU: SAUCE: AUFS aufs4.x-rcN 20151102
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] add feature interlock with mainline builds
+  * apparmor -- follow change to this_cpu_ptr
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: add parameter to control whether policy hashing is used
+    - LP: #1383886
+  * SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot
+    - LP: #1362199
+  * SAUCE: Revert: fix: only allow a single threaded process to ...
+    - LP: #1371310
+  * SAUCE: (no-up) fix: bad unix_addr_fs macro
+    - LP: #1390223
+  * SAUCE: (no-up): apparmor: fix mediation of fs unix sockets
+    - LP: #1408833
+  * SAUCE: (no-up) apparmor: fix mount not handling disconnected paths
+    - LP: #1496430
+
+  [ Tim Gardner ]
+
+  * [Config] Add iscsi_ibft and iscsi_boot_sysfs to generic inclusion list
+    - LP: #1511006
+  * rebase to v4.3
+  * Bypass spl/zfs config
+  * SPL/ZFS: Add Makefiles in order to avoid the lengthy config
+  * [Config] Default AppArmor settings
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.3
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 29 Oct 2015 09:16:26 -0600
+
+linux (4.3.0-0.5) xenial; urgency=low
+
+  * Update spl to 0.6.5.3-0ubuntu1, zfs to 0.6.5.3-0ubuntu1
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.3-rc7
+    - LP: #1504778
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 23 Oct 2015 13:59:52 -0600
+
+linux (4.3.0-0.4) xenial; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Debian] Update to new signing key type and location
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 21 Oct 2015 13:07:30 -0600
+
+linux (4.3.0-0.3) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Debian] sign-file is now compiled
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 21 Oct 2015 09:26:34 -0600
+
+linux (4.3.0-0.2) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Added libssl-dev to Build-Depends
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 20 Oct 2015 14:01:55 -0600
+
+linux (4.3.0-0.1) wily; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.3-rc6
+  * rebase to v4.3-rc5
+  * rebase to v4.3-rc4
+  * rebase to v4.3-rc3
+  * rebase to v4.3-rc2
+  * rebase to v4.3-rc1
+    - LP: #1492132
+    - LP: #1481575
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 14 Sep 2015 07:30:36 -0600
+
+linux (4.2.0-10.11) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1495208
+  * No change rebuild to avoid issues with leading zero bytes on
+    internal module signing key.  (see launchpad bug 1494943)
+
+  [ Ming Lei ]
+
+  * [Config] SERIAL_8250_DW=y for arm64
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915: Move WaBarrierPerformanceFixDisable:skl to skl code from chv
+    code
+    - LP: #1484486
+  * drm/i915/gen8: Add infrastructure to initialize WA batch buffers
+    - LP: #1484486
+  * drm/i915/gen8: Re-order init pipe_control in lrc mode
+    - LP: #1484486
+  * drm/i915/gen8: Add WaDisableCtxRestoreArbitration workaround
+    - LP: #1484486
+  * drm/i915/gen8: Add WaFlushCoherentL3CacheLinesAtContextSwitch
+    workaround
+    - LP: #1484486
+  * drm/i915: Bail out early if WA batch is not available for given Gen
+    - LP: #1484486
+  * drm/i915/gen8: Add WaClearSlmSpaceAtContextSwitch workaround
+    - LP: #1484486
+  * drm/i915: Update WaFlushCoherentL3CacheLinesAtContextSwitch
+    - LP: #1484486
+  * drm/i915/gen9: Implement WaDisableKillLogic for gen 9
+    - LP: #1484486
+  * drm/i915: Enable WA batch buffers for Gen9
+    - LP: #1484486
+  * drm/i915/gen9: Add WaDisableCtxRestoreArbitration workaround
+    - LP: #1484486
+  * drm/i915: Update wa_ctx_emit() macro as per kernel coding guidelines
+    - LP: #1484486
+  * drm/i915/gen9: Add WaFlushCoherentL3CacheLinesAtContextSwitch
+    workaround
+    - LP: #1484486
+  * drm/i915/gen9: Add
+    WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken
+    - LP: #1484486
+  * drm/i915:skl: Add WaEnableGapsTsvCreditFix
+    - LP: #1484486
+  * drm/i915/skl: revert duplicated WaBarrierPerformanceFixDisable:skl
+    - LP: #1484486
+  * drm/i915/skl: Don't expose the top most plane on gen9 display
+    - LP: #1484486
+  * drm/i915/skl WaDisableSbeCacheDispatchPortSharing
+    - LP: #1484486
+  * drm/i915/skl: WaIgnoreDDIAStrap is forever, always init DDI A
+    - LP: #1484486
+  * drm/i915: reduce indent in i9xx_hpd_irq_handler
+    - LP: #1484531
+  * drm/i915: reduce duplicate conditions in i9xx_hpd_irq_handler
+    - LP: #1484531
+  * drm/i915: reduce indent in intel_hpd_irq_handler
+    - LP: #1484531
+  * drm/i915: group all hotplug related fields into a new struct in
+    dev_priv
+    - LP: #1484531
+  * drm/i915: add for_each_hpd_pin to iterate over hotplug pins
+    - LP: #1484531
+  * drm/i915: simplify conditions for skipping the 2nd hpd loop iterations
+    - LP: #1484531
+  * drm/i915: put back the indent in intel_hpd_irq_handler
+    - LP: #1484531
+  * drm/i915: merge the two hpd loops in intel_hpd_irq_handler to one
+    - LP: #1484531
+  * drm/i915: simplify condition for digital port
+    - LP: #1484531
+  * drm/i915: abstract away platform specific parts from hpd handling
+    - LP: #1484531
+  * drm/i915: Handle HPD when it has actually occurred
+    - LP: #1484531
+  * drm/i915: Set power domain for DDI-E
+    - LP: #1484531
+  * drm/i915: Set alternate aux for DDI-E
+    - LP: #1484531
+  * drm/i915/skl: enable DDI-E hotplug
+    - LP: #1484531
+  * drm/i915/bxt: fix DDI PHY vswing scale value setting
+    - LP: #1494163
+  * drm/i915/skl: Buffer translation improvements
+    - LP: #1494163
+  * drm/i915: Per-DDI I_boost override
+    - LP: #1494163
+  * drm/i915: fix VBT parsing for SDVO child device mapping
+    - LP: #1494163
+  * drm/i915/bxt: edp1.4 Intermediate Freq support
+    - LP: #1494163
+  * drm/i915: fix link rates reported for SKL
+    - LP: #1494163
+  * drm/i915: Allow parsing of variable size child device entries from VBT
+    - LP: #1494163
+  * drm/i915/skl: Update DDI buffer translation programming.
+    - LP: #1494163
+  * drm/i915: Enable HDMI on DDI-E
+    - LP: #1484531
+  * drm/i915/skl: Enable DDI-E
+    - LP: #1484531
+  * drm/i915: eDP can be present on DDI-E
+    - LP: #1484531
+  * drm/i915/skl: Adding DDI_E power well domain
+    - LP: #1484531
+  * drm/i915: set CDCLK if DPLL0 enabled during resuming from S3
+    - LP: #1490035
+  * drm/i915: Split atomic wm update to pre and post variants
+    - LP: #1493746
+  * drm/i915/skl: Drop the preliminary_hw_support flag
+    - LP: #1486868
+  * drm/i915: set FDI translations to NULL on SKL
+    - LP: #1494163
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 13 Sep 2015 11:32:02 +0100
+
+linux (4.2.0-9.9) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1493970
+  * [Config] CONFIG_MFD_INTEL_LPSS=m
+    - LP: #1397876
+
+  [ dann frazier ]
+
+  * [Config] Disable CONFIG_IPMI_SI_PROBE_DEFAULTS on armhf and arm64
+    - LP: #1388952
+
+  [ Michael Ellerman ]
+
+  * SAUCE: crypto: vmx - VMX crypto should depend on CONFIG_VSX
+    Fixes FTBS on 32 bit powerpc, patch sent upstream.
+
+  [ Upstream Kernel Changes ]
+
+  * thermal/powerclamp: add cpu id for skylake h/s
+    - LP: #1398269
+  * perf/x86/intel/uncore: Add Broadwell-DE uncore support
+    - LP: #1397852
+  * mfd: watchdog: iTCO_wdt: Expose watchdog properties using platform data
+    - LP: #1460905
+  * i2c: i801: Create iTCO device on newer Intel PCHs
+    - LP: #1460905
+  * watchdog: iTCO_wdt: Add support for TCO on Intel Sunrisepoint
+    - LP: #1460905
+  * perf/x86: Add a native_perf_sched_clock_from_tsc()
+    - LP: #1397867
+  * perf/x86/intel: Add support for PEBSv3 profiling
+    - LP: #1397867
+  * perf/x86/intel/lbr: Allow time stamp for free running PEBSv3
+    - LP: #1397867
+  * x86: Add new MSRs and MSR bits used for Intel Skylake PMU support
+    - LP: #1397867
+  * perf: Add cycles to branch_info
+    - LP: #1397867
+  * perf/x86/intel/lbr: Add support for LBRv5
+    - LP: #1397867
+  * perf/x86/intel: Handle new arch perfmon v4 status bits
+    - LP: #1397867
+  * perf/x86/intel: Move PMU ACK to after LBR read
+    - LP: #1397867
+  * perf/x86/intel/lbr: Optimize v4 LBR unfreezing
+    - LP: #1397867
+  * perf/x86/intel: Add Intel Skylake PMU support
+    - LP: #1397867
+  * perf/x86/intel/lbr: Use correct index to save/restore LBR_INFO with
+    call stack
+    - LP: #1397867
+  * perf/x86/intel/lbr: Limit LBR accesses to TOS in callstack mode
+    - LP: #1397867
+  * perf/x86: Make merge_attr() global to use from perf_event_intel
+    - LP: #1397867
+  * perf/x86/intel: Use 0x11 as extra reg test value
+    - LP: #1397867
+  * perf tools: Add support for cycles, weight branch_info field
+    - LP: #1397867
+  * perf report: Add flag for non ANY branch mode
+    - LP: #1397867
+  * perf report: Add infrastructure for a cycles histogram
+    - LP: #1397867
+  * perf report: Add processing for cycle histograms
+    - LP: #1397867
+  * perf annotate: Compute IPC and basic block cycles
+    - LP: #1397867
+  * perf annotate: Finally display IPC and cycle accounting
+    - LP: #1397867
+  * perf top: Add branch annotation code to top
+    - LP: #1397867
+  * perf report: Display cycles in branch sort mode
+    - LP: #1397867
+  * perf annotate: Fix 32-bit compilation error in util/annotate.c
+    - LP: #1397867
+  * PM / QoS: Make it possible to expose device latency tolerance to
+    userspace
+    - LP: #1460908
+  * ACPI / PM: Attach ACPI power domain only once
+    - LP: #1460908
+  * Driver core: wakeup the parent device before trying probe
+    - LP: #1460908
+  * klist: implement klist_prev()
+    - LP: #1460908
+  * driver core: implement device_for_each_child_reverse()
+    - LP: #1460908
+  * mfd: make mfd_remove_devices() iterate in reverse order
+    - LP: #1460908
+  * dmaengine: add a driver for Intel integrated DMA 64-bit
+    - LP: #1460908
+  * mfd: Add support for Intel Sunrisepoint LPSS devices
+    - LP: #1460908
+  * spi: pxa2xx: Add support for Intel Sunrisepoint
+    - LP: #1397876
+  * spi: spi-pxa2xx: Remove unused legacy PXA DMA API channel numbers
+    - LP: #1397876
+  * spi: pxa2xx: Add terminating entry for pxa2xx_spi_pci_compound_match
+    - LP: #1397876
+  * spi: spi-pxa2xx: Remove unused legacy null dma buffer and allocation
+    for it
+    - LP: #1397876
+  * intel_idle: Skylake Client Support
+    - LP: #1397877
+  * powerpc/kernel: Switch to using MAX_ERRNO
+    - LP: #1458876
+  * powerpc/kernel: Change the do_syscall_trace_enter() API
+    - LP: #1458876
+  * powerpc: Drop unused syscall_get_error()
+    - LP: #1458876
+  * powerpc: Don't negate error in syscall_set_return_value()
+    - LP: #1458876
+  * powerpc: Rework syscall_get_arguments() so there is only one loop
+    - LP: #1458876
+  * powerpc: Use orig_gpr3 in syscall_get_arguments()
+    - LP: #1458876
+  * powerpc: Change syscall_get_nr() to return int
+    - LP: #1458876
+  * powerpc/kernel: Add SIG_SYS support for compat tasks
+    - LP: #1458876
+  * powerpc/kernel: Enable seccomp filter
+    - LP: #1458876
+  * selftests/seccomp: Make seccomp tests work on big endian
+    - LP: #1458876
+  * selftests/seccomp: Add powerpc support
+    - LP: #1458876
+  * eCryptfs: Invalidate dcache entries when lower i_nlink is zero
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Sep 2015 19:17:57 -0600
+
+linux (4.2.0-8.8) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1493357
+  * [Config] CONFIG_CRYPTO_DEV_NX_COMPRESS_CRYPTO obsolete
+    - LP: #1488495
+  * [Config] CONFIG_CXLFLASH=m
+  * [Config] CONFIG_CXL_EEH=y for ppc64el, powerpc64-smp
+
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] standardise on stage1 for the bootstrap stage in line with debian
+  * [Packaging] mark up control for stage1
+  * [Config] kernel-versions -- clean up deps field
+  * [Config] s390x -- build linux-libc-dev
+    - LP: #1488653
+  * [Packaging] control -- prepare for new kernel-wedge semantics
+
+  [ Upstream Kernel Changes ]
+
+  * crypto: vmx - Fixing AES-CTR counter bug
+    - LP: #1484519
+  * crypto: vmx - Fixing GHASH Key issue on little endian
+    - LP: #1484519
+  * powerpc: Uncomment and make enable_kernel_vsx() routine available
+    - LP: #1484519
+  * crypto: vmx - Adding enable_kernel_vsx() to access VSX instructions
+    - LP: #1484519
+  * crypto: nx - nx842_OF_upd_status should return ENODEV if device is not
+    'okay'
+    - LP: #1488495
+  * crypto: nx - rename nx842_{init, exit} to nx842_pseries_{init, exit}
+    - LP: #1488495
+  * crypto: nx - do not emit extra output if status is disabled
+    - LP: #1488495
+  * crypto: nx - reduce chattiness of platform drivers
+    - LP: #1488495
+  * crypto: nx/842 - Fix context corruption
+    - LP: #1488495
+  * crypto: nx - remove __init/__exit from VIO functions
+    - LP: #1488495
+  * crypto: nx - remove pSeries NX 'status' field
+    - LP: #1488495
+  * crypto: nx - move kzalloc() out of spinlock
+    - LP: #1488495
+  * crypto: nx - don't register pSeries driver if ENODEV
+    - LP: #1488495
+  * crypto: nx - use common code for both NX decompress success cases
+    - LP: #1488495
+  * crypto: nx - merge nx-compress and nx-compress-crypto
+    - LP: #1488495
+  * crypto: nx - rename nx-842-crypto.c to nx-842.c
+    - LP: #1488495
+  * crypto: nx - make platform drivers directly register with crypto
+    - LP: #1488495
+  * cxlflash: Base support for IBM CXL Flash Adapter
+    - LP: #1449121
+  * cxlflash: Base error recovery support
+    - LP: #1449121
+  * cxlflash: Superpipe support
+    - LP: #1449121
+  * cxlflash: Virtual LUN support
+    - LP: #1449121
+  * cxlflash: off by one bug in cxlflash_show_port_status()
+    - LP: #1449121
+  * cxlflash: shift wrapping bug in afu_link_reset()
+    - LP: #1449121
+  * cxlflash: Remove unused variable from queuecommand
+    - LP: #1449121
+  * powerpc/powernv: move dma_get_required_mask from pnv_phb to
+    pci_controller_ops
+  * powerpc/eeh: Probe after unbalanced kref check
+  * misc: cxl: clean up afu_read_config()
+  * cxl: Add explicit precision specifiers
+  * cxl: use more common format specifier
+  * cxl: Destroy cxl_adapter_idr on module_exit
+  * cxl: Destroy afu->contexts_idr on release of an afu
+  * cxl: Don't ignore add_process_element() result when attaching context
+  * cxl: Compile with -Werror
+  * cxl: sparse: Make declarations static
+  * cxl: sparse: Silence iomem warning in debugfs file creation
+  * cxl: Convert MMIO read/write macros to inline functions
+  * cxl: Drop commands if the PCI channel is not in normal state
+  * cxl: Allocate and release the SPA with the AFU
+  * cxl: Make IRQ release idempotent
+  * cxl: Clean up adapter MMIO unmap path.
+  * cxl: Refactor adaptor init/teardown
+  * cxl: Refactor AFU init/teardown
+  * cxl: Don't remove AFUs/vPHBs in cxl_reset
+  * cxl: Allow the kernel to trust that an image won't change on PERST.
+  * cxl: EEH support
+  * cxl: Add CONFIG_CXL_EEH symbol
+  * cxl: Plug irq_bitmap getting leaked in cxl_context
+  * cxl: Add alternate MMIO error handling
+  * cxl: Allow release of contexts which have been OPENED but not STARTED
+  * cxl: Remove use of macro DEFINE_PCI_DEVICE_TABLE
+  * cxl: Release irqs if memory allocation fails
+  * cxl: Remove racy attempt to force EEH invocation in reset
+  * cxl: Fix + cleanup error paths in cxl_dev_context_init
+  * cxl: Fix force unmapping mmaps of contexts allocated through the kernel api
+  * cxl: Set up and enable PSL Timebase
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 01 Sep 2015 07:38:43 -0600
+
+linux (4.2.0-7.7) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1490564
+  * rebase to v4.2
+
+  [ Wen Xiong ]
+
+  * SAUCE: ipr: Byte swapping for device_id attribute in sysfs
+    - LP: #1453892
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2
+    - LP: #1487345
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 26 Aug 2015 07:06:10 -0600
+
+linux (4.2.0-6.6) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1488138
+
+  [ Andy Whitcroft ]
+
+  * rebase to v4.2-rc8
+
+  [ Shilpasri G Bhat ]
+
+  * SAUCE: cpufreq: powernv: Handle throttling due to Pmax capping at chip
+    level
+    - LP: #1480894
+  * SAUCE: powerpc/powernv: Add definition of OPAL_MSG_OCC message type
+    - LP: #1480894
+  * SAUCE: cpufreq: powernv: Register for OCC related opal_message
+    notification
+    - LP: #1480894
+  * SAUCE: cpufreq: powernv: Call throttle_check() on receiving
+    OCC_THROTTLE
+    - LP: #1480894
+  * SAUCE: cpufreq: powernv: Report Psafe only if PMSR.psafe_mode_active
+    bit is set
+    - LP: #1480894
+  * SAUCE: cpufreq: powernv: Restore cpu frequency to policy->cur on
+    unthrottling
+    - LP: #1480894
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc8
+    - LP: #1483440
+    - LP: #1484334
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 21 Aug 2015 07:12:11 -0600
+
+linux (4.2.0-5.5) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1487173
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] correct spelling of probabaly on the tools packages
+    - LP: #1256822
+  * rebase to v4.2-rc7
+
+  [ dann frazier ]
+
+  * d-i: Add nicpf and nicvf to nic-modules
+  * d-i: Enable usb modules on arm64
+
+  [ Mahesh Salgaonkar ]
+
+  * SAUCE: powerpc/powernv: display reason for Malfunction Alert HMI.
+    - LP: #1482343
+  * SAUCE: powerpc/powernv: Pull all HMI events before panic.
+    - LP: #1482343
+  * SAUCE: powerpc/powernv: Invoke opal_cec_reboot2() on unrecoverable
+    machine check errors.
+    - LP: #1482343
+  * SAUCE: powerpc/powernv: Invoke opal_cec_reboot2() on unrecoverable HMI.
+    - LP: #1482343
+
+  [ Vipin K Parashar ]
+
+  * SAUCE: powerpc/powernv: Add poweroff (EPOW, DPO) events support for
+    PowerNV platform
+    - LP: #1469771
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 11 Aug 2015 09:48:40 -0600
+
+linux (4.2.0-4.4) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1483677
+
+  [ Achiad Shochat ]
+
+  * SAUCE: net/mlx5e: Support TX packet copy into WQE
+  * SAUCE: net/mlx5e: TX latency optimization to save DMA reads
+  * SAUCE: net/mlx5e: Cosmetics: use BIT() instead of "1 <<", and others
+  * SAUCE: net/mlx5e: Input IPSEC.SPI into the RX RSS hash function
+
+  [ Adam Lee ]
+
+  * SAUCE: serial: 8250_pci: Add support for Pericom PI7C9X795[1248]
+    - LP: #1480142
+
+  [ dann frazier ]
+
+  * [Config] CONFIG_NR_CPUS=128 on arm64
+
+  [ Leann Ogasawara ]
+
+  * [Config] d-i -- Add sfc to nic-modules udeb
+    - LP: #1481490
+
+  [ Saeed Mahameed ]
+
+  * SAUCE: net/mlx5e: Support ETH_RSS_HASH_XOR
+  * SAUCE: net/mlx5e: Allocate DMA coherent memory on reader NUMA node
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_X86_INTEL_MPX=y
+    - LP: #1460902
+  * [Debian] change dependency on module-init-tools to kmod
+    - LP: #1481986
+  * rebase to v4.2-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 04 Aug 2015 16:59:45 -0600
+
+linux (4.2.0-3.3) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1481462
+  * SAUCE: workqueue: Make flush_workqueue() available again to non GPL modules
+    Fixes an FTBS for at least one DKMS package.
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 04 Aug 2015 11:26:53 -0600
+
+linux (4.2.0-2.2) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1481067
+  * rebase to v4.2-rc5
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] module-inclusion -- commonise copy code and simplify
+  * [Packaging] module-inclusion -- add manual command entries
+  * [Packaging] module blacklists -- add support for manual blacklists
+  * [Packaging] do_common_tools should always be on
+  * [Packaging] initscripts need installing when making the package
+  * [Packaging] initscripts work around bug in debhelper systemd support
+  * [Config] exclude oss modules from linux-image
+    - LP: #1434842
+  * hyper-v -- add hid and fb drivers to linux-virtual
+    - LP: #1444179
+  * ubuntu: (no-squash) vbox -- infrastructure and updater
+  * ubuntu: vbox -- elide the new symlinks and reconstruct on clean:
+    - LP: #1426113
+  * ubuntu: vbox -- update to 5.0.0-dfsg-1
+    - LP: #1480879
+  * SAUCE: vbox: follow v4.2 updates to follow_link()/put_link() API
+  * [Config] move vbox modules into linux-image
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc5
+    - LP: #1478497
+    - LP: #1477900
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 03 Aug 2015 12:20:10 +0100
+
+linux (4.2.0-1.1~rc1) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1479903
+  * Initial upload of v4.2 based kernel (currently v4.-rc4)
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.2-rc4
+    - LP: #1476987
+    - LP: #1476888
+  * rebase to v4.2-rc3
+  * rebase to v4.2-rc2
+  * rebase to v4.2-rc1
+    - LP: #1394368
+    - LP: #1427680
+    - LP: #1462614
+    - LP: #1397021
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 30 Jul 2015 18:42:46 +0100
+
+linux (4.1.0-3.3) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1478897
+
+  [ Colin Ian King ]
+
+  * SAUCE: KEYS: ensure we free the assoc array edit if edit is valid
+    - CVE-2015-1333
+
+  [ Seth Forshee ]
+
+  * SAUCE: overlayfs: Enable user namespace mounts for the "overlay" fstype
+    - LP: #1478578
+
+  [ Upstream Kernel Changes ]
+
+  * sched/stop_machine: Fix deadlock between multiple stop_two_cpus()
+    - LP: #1461620
+  * x86/nmi: Enable nested do_nmi() handling for 64-bit kernels
+  * x86/nmi/64: Remove asm code that saves cr2
+  * x86/nmi/64: Switch stacks on userspace NMI entry
+  * x86/nmi/64: Reorder nested NMI checks
+  * x86/nmi/64: Use DF to avoid userspace RSP confusing nested NMI
+    detection
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 28 Jul 2015 11:59:03 +0100
+
+linux (4.1.0-2.4) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: overlayfs: when copying up and reading directories ensure
+    mounter had permissions V2
+    - CVE-2015-1328
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1465419
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 15 Jun 2015 14:09:22 -0700
+
+linux (4.1.0-2.2) wily; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v4.1.3
+  * [Config] Add i40e[vf] to d-i
+    - LP: #1476393
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.1.3
+    - LP: #1427680
+    - LP: #1462614
+    - LP: #1394368
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 22 Jul 2015 09:13:02 -0600
+
+linux (4.1.0-1.1) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: overlay: add backwards compatible overlayfs format support V3
+    - LP: #1395877, #1410480
+  * SAUCE: overlayfs: when copying up and reading directories ensure
+    mounter had permissions V2
+    - CVE-2015-1328
+  * [Packaging] fix up Vcs-Git: to point to launchpad
+  * [Config] correct linux-initramfs-tool virtual linkage
+    - LP: #1474810
+
+  [ Chris J Arges ]
+
+  * [Config] Add dm-service-time to multipath-modules
+    - LP: #1469240
+  * [Config] Add MTD_POWERNV_FLASH and OPAL_PRD
+    - LP: #1464560
+
+  [ Jay Vosburgh ]
+
+  * SAUCE: fan: Proof of concept implementation (v2)
+    - LP: #1439706
+  * SAUCE: fan: tunnel multiple mapping mode (v3)
+    - LP: #1470091
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: ext4: disable ext4_punch_hole for indirect filesystems"
+  * Revert "SAUCE: intel_pstate: inform user that thermald is worth
+    considering"
+  * Revert "SAUCE: Work around broken ACPI backlight on Dell Inspiron 5537"
+  * Revert "SAUCE: dm-crypt: never use write same"
+  * Release Tracking Bug
+    - LP: #1476333
+
+  [ Tim Gardner ]
+
+  * Rebase to v4.1
+    - LP: #1443371
+  * [Config] Enable Apparmor
+  * [Config] CONFIG_OVERLAY_FS_V1=y
+  * [Config] DEFAULT_IOSCHED="deadline" for ppc64el
+    - LP: #1469829
+  * [Config] CONFIG_VM86=n
+    - LP: #1473447
+  * [Config] ACORN_PARTITION=n
+    - LP: #1453117
+
+  [ Timo Aaltonen ]
+
+  * [Config] Disable CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT
+    - LP: #1473319
+
+  [ Upstream Kernel Changes ]
+
+  * efi: efivar_create_sysfs_entry() should return negative error codes
+  * efi: Add esrt support
+  * x86, doc: Remove cmdline_size from list of fields to be filled in for
+    EFI handover
+  * efi/esrt: Fix some compiler warnings
+  * efi: dmi: List SMBIOS3 table before SMBIOS table
+  * efi: Add 'systab' information to Documentation/ABI
+  * ALSA: hda - restore the MIC FIXUP for some Dell machines
+    - LP: #1473560
+  * mtd: powernv: Add powernv flash MTD abstraction driver
+    - LP: #1464560
+  * powerpc/powernv: Expose OPAL APIs required by PRD interface
+    - LP: #1464560
+  * powerpc/powernv: Add opal-prd channel
+    - LP: #1464560
+  * powerpc/powernv: fix construction of opal PRD messages
+    - LP: #1464560
+  * powerpc/include: Add opal-prd to installed uapi headers
+    - LP: #1464560
+  * powerpc/powernv: Fix vma page prot flags in opal-prd driver
+    - LP: #1464560
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 20 Jul 2015 10:16:06 -0700
+
+linux (4.0.0-2.4) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: overlayfs: when copying up and reading directories ensure
+    mounter had permissions V2
+    - CVE-2015-1328
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1465419
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 15 Jun 2015 14:09:22 -0700
+
+linux (4.0.0-1.2) wily; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: overlay: add backwards compatible overlayfs format support V3
+    - LP: #1395877, #1410480
+  * [Config] enable CONFIG_OVERLAY_FS_V1
+
+  [ Tai Nguyen ]
+
+  * SAUCE: power: reset: Add syscon reboot device node for APM X-Gene platform
+    - LP: #1463211
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_HIBERNATION=n for ppc64el
+    - LP: #1463836
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 12 Jun 2015 06:11:53 -0600
+
+linux (4.0.0-1.1) wily; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Revert "md/raid0: fix bug with chunksize not a power of 2."
+    - LP: #1457510
+  * powerpc/powernv: Check image loaded or not before calling flash
+    - LP: #1461553
+
+  [ Tim Gardner ]
+
+  * [Config] armhf: CPUFREQ_DT=y
+    - LP: #1457781
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.0.5
+    - LP: #1429756
+    - LP: #1452175
+    - LP: #1454656
+    - LP: #1447909
+    - LP: #1446517
+    - LP: #1428947
+    - LP: #1410704
+    - LP: #1412800
+    - LP: #1400215
+    - LP: #1411193
+    - LP: #1412800
+    - LP: #1408295
+    - LP: #1436745
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 09 Jun 2015 05:58:46 -0700
+
+linux (3.19.0-10.10) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] control -- make element ordering deterministic
+  * [Config] allow dracult to support initramfs as well
+    - LP: #1109029
+  * [Packaging] generate live watchdog blacklists
+    - LP: #1432837
+
+  [ Leann Ogasawara ]
+
+  * [Config] CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
+    - LP: #1397860
+  * rebase to v3.19.2
+
+  [ Upstream Kernel Changes ]
+
+  * thinkpad_acpi: support new BIOS version string pattern
+    - LP: #1417915
+  * arm64: Invalidate the TLB corresponding to intermediate page table
+    levels
+    - LP: #1432546
+  * perf tools: Support parsing parameterized events
+    - LP: #1430341
+  * perf tools: Extend format_alias() to include event parameters
+    - LP: #1430341
+  * perf Documentation: Add event parameters
+    - LP: #1430341
+  * perf tools: Document parameterized and symbolic events
+    - LP: #1430341
+  * perf: provide sysfs_show for struct perf_pmu_events_attr
+    - LP: #1430341
+  * perf: add PMU_EVENT_ATTR_STRING() helper
+    - LP: #1430341
+  * perf: define EVENT_DEFINE_RANGE_FORMAT_LITE helper
+    - LP: #1430341
+  * powerpc/perf/hv-24x7: parse catalog and populate sysfs with events
+    - LP: #1430341
+  * powerpc/perf/{hv-gpci, hv-common}: generate requests with counters
+    annotated
+    - LP: #1430341
+  * powerpc/perf/hv-gpci: add the remaining gpci requests
+    - LP: #1430341
+  * powerpc/perf/hv-24x7: Document sysfs event description entries
+    - LP: #1430341
+  * powerpc/iommu: Remove IOMMU device references via bus notifier
+    - LP: #1425202
+  * powerpc/pseries: Fix endian problems with LE migration
+    - LP: #1428351
+  * intel_idle: support additional Broadwell model
+    - LP: #1400970
+  * tools/power turbostat: support additional Broadwell model
+    - LP: #1400970
+  * KVM: x86: flush TLB when D bit is manually changed.
+    - LP: #1397860
+  * Optimize TLB flush in kvm_mmu_slot_remove_write_access.
+    - LP: #1397860
+  * KVM: Add generic support for dirty page logging
+    - LP: #1397860
+  * KVM: x86: switch to kvm_get_dirty_log_protect
+    - LP: #1397860
+  * KVM: Rename kvm_arch_mmu_write_protect_pt_masked to be more generic for
+    log dirty
+    - LP: #1397860
+  * KVM: MMU: Add mmu help functions to support PML
+    - LP: #1397860
+  * KVM: MMU: Explicitly set D-bit for writable spte.
+    - LP: #1397860
+  * KVM: x86: Change parameter of kvm_mmu_slot_remove_write_access
+    - LP: #1397860
+  * KVM: x86: Add new dirty logging kvm_x86_ops for PML
+    - LP: #1397860
+  * KVM: VMX: Add PML support in VMX
+    - LP: #1397860
+  * HID: multitouch: add support of clickpads
+  * HID: multitouch: Add support for button type usage
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19.2
+    - LP: #1428947
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 23 Mar 2015 15:28:16 +0000
+
+linux (3.19.0-9.9) vivid; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1430930
+
+  [ Shachar Raindel ]
+
+  * SAUCE: IB/core: Prevent integer overflow in ib_umem_get address
+    arithmetic
+    - LP: #1413741
+    - CVE-2014-8159
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 11 Mar 2015 10:29:17 -0700
+
+linux (3.19.0-8.8) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: vbox -- elide the new symlinks and reconstruct on clean:
+    - LP: #1426113
+  * rebase to stable v3.19.1
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up): apparmor: fix mediation of fs unix sockets
+    - LP: #1408833
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1429940
+
+  [ Upstream Kernel Changes ]
+
+  * xen: correct bug in p2m list initialization
+  * net/mlx5_core: Fix configuration of log_uar_page_sz
+    - LP: #1419938
+  * tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send
+    - LP: #1420575
+  * net/mlx4_core: Maintain a persistent memory for mlx4 device
+    - LP: #1422481
+  * net/mlx4_core: Set device configuration data to be persistent across
+    reset
+    - LP: #1422481
+  * net/mlx4_core: Refactor the catas flow to work per device
+    - LP: #1422481
+  * net/mlx4_core: Enhance the catas flow to support device reset
+    - LP: #1422481
+  * net/mlx4_core: Activate reset flow upon fatal command cases
+    - LP: #1422481
+  * net/mlx4_core: Manage interface state for Reset flow cases
+    - LP: #1422481
+  * net/mlx4_core: Handle AER flow properly
+    - LP: #1422481
+  * net/mlx4_core: Enable device recovery flow with SRIOV
+    - LP: #1422481
+  * net/mlx4_core: Reset flow activation upon SRIOV fatal command cases
+    - LP: #1422481
+  * tg3: Hold tp->lock before calling tg3_halt() from tg3_init_one()
+    - LP: #1428111
+  * rebase to v3.19.1
+    - LP: #1410704
+    - LP: #1411193
+    - LP: #1400215
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 09 Mar 2015 10:08:29 -0700
+
+linux (3.19.0-7.7) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1426013
+
+  [ Upstream Kernel Changes ]
+
+  * x86/irq: Fix regression caused by commit b568b8601f05
+  * cxl: Fix leaking interrupts if attach process fails
+    - LP: #1415102
+  * cxl: Early return from cxl_handle_fault for a shut down context
+    - LP: #1415102
+  * cxl: Disable AFU debug flag
+    - LP: #1415102
+  * cxl: Disable SPAP register when freeing SPA
+    - LP: #1415102
+  * cxl: remove redundant increment of hwirq
+    - LP: #1415102
+  * cxl: Add tracepoints
+    - LP: #1415102
+  * cxl: Update CXL ABI documentation
+    - LP: #1415102
+  * cxl: Use image state defaults for reloading FPGA
+    - LP: #1415102
+  * cxl: Add image control to sysfs
+    - LP: #1415102
+  * cxl: Enable CAPP recovery
+    - LP: #1415102
+  * cxl: Add ability to reset the card
+    - LP: #1415102
+  * cxl: Fix device_node reference counting
+    - LP: #1415102
+  * cxl: Export optional AFU configuration record in sysfs
+    - LP: #1415102
+  * cxl: Fail AFU initialisation if an invalid configuration record is
+    found
+    - LP: #1415102
+  * cxl: Add missing return statement after handling AFU errror
+    - LP: #1415102
+  * powerpc/eeh: Introduce flag EEH_PE_REMOVED
+    - LP: #1415102
+  * powerpc/eeh: Allow to set maximal frozen times
+    - LP: #1415102
+  * HID: i2c-hid: Limit reads to wMaxInputLength bytes for input events
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 26 Feb 2015 16:00:18 +0000
+
+linux (3.19.0-6.6) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * systemd -- fix hyper-v units to be non-forking
+    - LP: #1401525
+  * [Config] move vbox modules into linux-image
+  * ubuntu: vbox -- update to 4.3.22-dfsg-1
+
+  [ Brad Figg ]
+
+  * SAUCE: DEP8 test to run our regression tests
+
+  [ Paolo Pisati ]
+
+  * [Config] I2C_CHARDEV=y
+    - LP: #1417032
+
+  [ Upstream Kernel Changes ]
+
+  * PCI: Fix infinite loop with ROM image of size 0
+  * tpm: Fix NULL return in tpm_ibmvtpm_get_desired_dma
+  * Bluetooth: ath3k: workaround the compatibility issue with xHCI
+    controller
+    - LP: #1400215
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 19 Feb 2015 12:44:43 +0000
+
+linux (3.19.0-5.5) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_FA_DUMP=y
+    - LP: #1415562
+  * ubuntu: (no-squash) vbox -- infrastructure and updater
+  * ubuntu: vbox -- update to 4.3.20-dfsg-1ubuntu1
+  * rebase to v3.19 final
+
+  [ Chris J Arges ]
+
+  * [Config] Add ibmvfc to d-i
+    - LP: #1416001
+  * SAUCE: ext4: disable ext4_punch_hole for indirect filesystems
+    - LP: #1292234
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 09 Feb 2015 10:41:11 +0000
+
+linux (3.19.0-4.4) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] apply Kernel hacking >> Tracers config defaults
+  * hyper-v -- fix comment handing in /etc/network/interfaces
+    - LP: #1413020
+  * rebase to v3.19-rc7
+  * updateconfigs following rebase to v3.19-rc7
+
+  [ Ben Hutchings ]
+
+  * SAUCE: rtsx_usb_ms: Use msleep_interruptible() in polling loop
+    - LP: #1413149
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19-rc7
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 02 Feb 2015 17:03:07 +0200
+
+linux (3.19.0-3.3) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Debian] arm64 -- build ubuntu drivers
+    - LP: #1411284
+  * [Packaging] config-check -- add support for enforced annotations
+  * [Config] annotations -- switch to ENFORCED annotations
+  * [Packaging] config-check -- drop support for enforce file
+  * [Packaging] enforce -- drop empty enforce file
+  * rebase to v3.19-rc5
+  * [Config] add modules removed due to tighter dependencies
+  * [Config] updateconfigs following rebase to v3.19-rc5
+  * [Config] enforce CONFIG_FHANDLE=y
+    - LP: #1412543
+  * [Packaging] hyper-v -- daemons now require -n for non-forking startup
+    - LP: #1408355
+  * [Config] CONFIG_DEBUG_INFO_SPLIT=n
+    - LP: #1413646
+  * [Config] apply Device Drivers >> Character devices >> IPMI top-level
+    message handler config defaults
+  * [Config] apply Device Drivers >> Character devices >> Serial drivers
+    config defaults
+  * [Config] apply Device Drivers >> GPIO Support config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Direct Rendering
+    Manager >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI
+    support) config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Frame buffer
+    Devices >> Support for frame buffer devices config defaults
+  * [Config] apply Device Drivers >> HID support >> HID bus support >>
+    Special HID drivers config defaults
+  * [Config] apply Device Drivers >> Hardware Monitoring support config
+    defaults
+  * [Config] apply Device Drivers >> I2C support >> I2C support >> I2C
+    Hardware Bus support config defaults
+  * [Config] apply Device Drivers >> Industrial I/O support >> Analog to
+    digital converters config defaults
+  * [Config] apply Device Drivers >> Industrial I/O support >> Humidity
+    sensors config defaults
+  * [Config] apply Device Drivers >> Industrial I/O support >> Pressure
+    sensors config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Mice config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Touchscreens config defaults
+  * [Config] apply Device Drivers >> LED Support >> LED Class Support
+    config defaults
+  * [Config] apply Device Drivers >> MMC/SD/SDIO card support config
+    defaults
+  * [Config] apply Device Drivers >> Multifunction device drivers config
+    defaults
+  * [Config] apply Device Drivers >> Multimedia support >> Cameras/video
+    grabbers support >> Media test drivers config defaults
+  * [Config] apply Device Drivers >> Multimedia support >> Media PCI
+    Adapters config defaults
+  * [Config] apply Device Drivers >> Multimedia support >> Remote
+    Controller devices config defaults
+  * [Config] apply Device Drivers >> Network device support >> Distributed
+    Switch Architecture drivers config defaults
+  * [Config] apply Device Drivers >> Network device support >> Network core
+    driver support config defaults
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    >> Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) config
+    defaults
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    >> Intel PRO/Wireless 2200BG and 2915ABG Network Connection config
+    defaults
+  * [Config] apply Device Drivers >> PHY Subsystem config defaults
+  * [Config] apply Device Drivers >> Pin controllers config defaults
+  * [Config] apply Device Drivers >> SPI support config defaults
+  * [Config] apply Device Drivers >> Sound card support >> Advanced Linux
+    Sound Architecture >> ALSA for SoC audio support config defaults
+  * [Config] apply Device Drivers >> Sound card support >> Advanced Linux
+    Sound Architecture >> FireWire sound devices config defaults
+  * [Config] apply Device Drivers >> Sound card support >> Advanced Linux
+    Sound Architecture >> HD-Audio config defaults
+  * [Config] apply Device Drivers >> Staging drivers >> Lustre file system
+    client support config defaults
+  * [Config] apply Device Drivers >> Staging drivers >> Media staging
+    drivers config defaults
+  * [Config] apply Device Drivers >> USB support >> USB Gadget Support >>
+    USB Gadget Drivers >> USB functions configurable through configfs
+    config defaults
+  * [Config] apply Device Drivers >> USB support >> USB Gadget Support >>
+    USB Peripheral Controller config defaults
+  * [Config] apply Networking support >> NFC subsystem support >> Near
+    Field Communication (NFC) devices config defaults
+  * [Config] apply Networking support >> Networking options >> Network
+    packet filtering framework (Netfilter) >> Core Netfilter Configuration
+    >> Netfilter nf_tables support config defaults
+  * [Config] apply Networking support >> Networking options >> QoS and/or
+    fair queueing >> Actions config defaults
+  * [Config] apply Networking support >> Networking options >> TCP/IP
+    networking config defaults
+  * [Config] apply Networking support >> Wireless >> Generic IEEE 802.11
+    Networking Stack (mac80211) config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Keyboards config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Mice config defaults
+  * [Config] apply Device Drivers >> Pulse-Width Modulation (PWM) Support
+    config defaults
+  * [Config] apply Networking support >> Networking options >> Network
+    packet filtering framework (Netfilter) >> IP: Netfilter Configuration
+    >> IPv4 NAT config defaults
+  * [Config] apply Networking support >> Networking options >> Network
+    packet filtering framework (Netfilter) >> IPv6: Netfilter Configuration
+    >> IPv6 NAT config defaults
+  * [Config] apply Kernel hacking >> Kernel debugging config defaults
+  * [Config] apply General setup >> Timers subsystem >> Timer tick handling
+    config defaults
+  * SAUCE: arm64 -- psci tell the compiler which registers we are needing
+    values in
+    - LP: #1414002
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    >> Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N
+    (iwlwifi) config defaults
+  * [Config] apply Device Drivers >> Real Time Clock config defaults
+  * [Config] apply Device Drivers >> SCSI device support >> SCSI device
+    support >> SCSI low-level drivers config defaults
+  * [Config] apply General setup >> CPU/Task time and stats accounting >>
+    Cputime accounting config defaults
+  * [Config] apply Device Drivers >> Mailbox Hardware Support config
+    defaults
+  * rebase to v3.19-rc6
+  * [Config] updateconfigs following rebase to v3.19-rc6
+
+  [ Kamal Mostafa ]
+
+  * [Packaging] force "dpkg-source -I -i" behavior
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_USB_OTG
+    - LP: #1411295
+
+  [ Upstream Kernel Changes ]
+
+  * overlay: add backwards compatible overlayfs format support (fixes)
+    - LP: #1410480
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19-rc5
+  * rebase to v3.19-rc6
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 26 Jan 2015 11:37:39 +0000
+
+linux (3.19.0-2.2) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.19-rc4
+  * [Config] updateconfigs following rebase to v3.19-rc4
+  * [Packaging] install all dtb files
+    - LP: #1408002
+  * [Config] switch on "all" dtbs
+    - LP: #1408002
+
+  [ Colin Ian King ]
+
+  * SAUCE: drivers/rtc/interface.c: ignore exprired times when enqueing new
+    timers
+    - LP: #1333569
+
+  [ Joseph Salisbury ]
+
+  * [Config] Enable CONFIG_N_GSM as module.
+    - LP: #1404670
+
+  [ K. Y. Srinivasan ]
+
+  * SAUCE: storvsc: force SPC-3 compliance on win8 and win8 r2 hosts
+    - LP: #1406867
+
+  [ Steve McIntyre ]
+
+  * SAUCE: efi: Expose underlying UEFI firmware platform size to userland
+    - LP: #1409750
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19-rc4
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 13 Jan 2015 12:35:58 +0000
+
+linux (3.19.0-1.1) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: AUFS -- aufs3-standalone.patch"
+  * Revert "SAUCE: AUFS -- aufs3-mmap.patch"
+  * Revert "SAUCE: AUFS -- aufs3-base.patch"
+  * ubuntu: AUFS3 -- follow switch to vfs_fallocate
+  * rebase to v3.19-rc1
+  * rebase to v3.19-rc2
+  * [Config] defaultconfigs following rebase to v3.19-rc2
+  * ubuntu: aufs3 -- follow rename of d_child
+  * ubuntu: aufs3 -- follow switch to d_splice_alias
+  * ubuntu: aufs3 -- follow switch to get_unused_fd_flags()
+  * ubuntu: aufs3 -- follow rename for d_alias
+  * apparmor -- follow change to this_cpu_ptr
+  * disable module checks for rebase
+  * ubuntu: AUFS -- substrate: aufs3-base.patch
+  * ubuntu: AUFS -- substrate: aufs3-mmap.patch
+  * ubuntu: AUFS -- substrate: aufs3-standalone.patch
+  * ubuntu: AUFS -- update to 92ad9cc8bd289bf8e59b6bd8d83137d8e1a58c1c
+  * [Configs] updateconfigs following aufs update
+  * v3.19 series start
+  * rebase to v3.19-rc3
+  * [Configs] updateconfigs following rebase to v3.19-rc3
+  * [Packaging] uploadnum should be the remainder of the version
+    - LP: #1407755
+  * [Packaging] handle dts directories
+    - LP: #1408004
+  * [Config] follow move of arm64 dts' into vendor directories
+
+  [ Upstream Kernel Changes ]
+
+  * arm64: optimized copy_to_user and copy_from_user assembly code
+    - LP: #1400349
+  * iommu/ipmmu-vmsa: follow flag switch to IOMMU_NOEXEC
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.19-rc1
+    - LP: #1173681
+  * rebase to v3.19-rc2
+  * rebase to v3.19-rc3
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 06 Jan 2015 14:30:02 +0000
+
+linux (3.18.0-7.8) vivid; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1401590
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot
+    - LP: #1362199
+  * SAUCE: Revert: fix: only allow a single threaded process to ...
+    - LP: #1371310
+  * SAUCE: (no-up) fix: bad unix_addr_fs macro
+    - LP: #1390223
+  * SAUCE: (no-up) apparmor: add parameter to control whether policy
+    hashing is used
+    - LP: #1383886
+  * [config] set apparmor config options
+
+  [ Seth Forshee ]
+
+  * [Config] CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
+    - LP: #1398458
+
+  [ Upstream Kernel Changes ]
+
+  * mfd: rtsx: Fix PM suspend for 5227 & 5249
+    - LP: #1359052
+  * mmc: sdhci-pci-o2micro: Fix Dell E5440 issue
+    - LP: #1346067
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 11 Dec 2014 08:36:36 -0800
+
+linux (3.18.0-6.7) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) arm64: optimized copy_to_user and copy_from_user
+    assembly code"
+    - LP: #1398596
+  * rebase to v3.18
+
+  [ Chris J Arges ]
+
+  * [Config] CONFIG_PCIEASPM_DEBUG=y
+    - LP: #1398544
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: VIRTIO_[BALLOON|MMIO]=y
+    - LP: #1396470
+
+  [ Upstream Kernel Changes ]
+
+  * drivers:scsi:storvsc: Fix a bug in handling ring buffer failures that
+    may result in I/O freeze
+    - LP: #1400289
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 08 Dec 2014 09:15:17 -0800
+
+linux (3.18.0-5.6) vivid; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1398109
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_SCSI_MQ_DEFAULT=n
+    - LP: #1397061
+  * rebase to v3.18-rc7
+
+  [ Chris J Arges ]
+
+  * [Config] CONFIG_SCOM_DEBUGFS=y for powerpc/powerpc64-smp
+    ppc64el/generic
+    - LP: #1395855
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc7
+    - LP: #1389497
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 01 Dec 2014 10:09:09 -0800
+
+linux (3.18.0-4.5) vivid; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Release Tracking Bug
+    - LP: #1395891
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.18-rc6
+  * [Config] update configs following rebase to v3.18-rc6
+  * [Config] enable overlayfs v1 support
+
+  [ Tim Gardner ]
+
+  * rebase to v3.18-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * overlay: add backwards compatible overlayfs format support
+    - LP: #1395877
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc5
+  * rebase to v3.18-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 24 Nov 2014 13:12:48 -0800
+
+linux (3.18.0-3.4) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] CONFIG_AUFS_FS=n for FTBS"
+  * Revert "SAUCE: AUFS -- update to
+    dcf336a754c86d5ee1c3d50699fd75c586d037cb"
+  * Revert "SAUCE: aufs3 -- (no-up) aufs3-standalone.patch"
+  * Revert "SAUCE: aufs3 -- (no-up) aufs3-base.patch"
+  * [Config] amd64 is now the indep architecture
+  * [Debian] basic hook support
+  * SAUCE: AUFS -- aufs3-base.patch
+  * SAUCE: AUFS -- aufs3-mmap.patch
+  * SAUCE: AUFS -- aufs3-standalone.patch
+  * ubuntu: AUFS -- update to 9d5c349d5c452170b8e813d86956f896a0aef170
+  * [Config] updateconfigs following aufs3 update
+  * SAUCE: AUFS (no-squash): basic framework and update machinary -- part 2
+
+  [ dann frazier ]
+
+  * [Config] Disable CONFIG_IPMI_SI_PROBE_DEFAULTS on armhf and arm64
+    - LP: #1388952
+  * [Config] disable CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET
+  * [Config] Disable CONFIG_RCU_USER_QS on arm64
+
+  [ Tim Gardner ]
+
+  * rebase to v3.18-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc4
+    - LP: #1389497
+    - LP: #1387128
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 11 Nov 2014 17:16:13 +0000
+
+linux (3.18.0-2.2) vivid; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: nft_reject_bridge.c: Include net/ip6_checksum.h
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc3
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 03 Nov 2014 06:09:06 -0700
+
+linux (3.18.0-1.1) vivid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] Switch kernel to vmlinuz (from vmlinux) on ppc64el"
+  * [Config] tools -- only build common tools when enabled
+  * [Config] follow rename of DEB_BUILD_PROFILES
+  * [Config] linux-image-extra is additive to linux-image
+    - LP: #1375310
+  * [Config] linux-image-extra postrm is not needed on purge
+  * [Config] enable cloud tools on i386
+    - LP: #1367399
+
+  [ Marc Dietrich ]
+
+  * [Config] arm/tegra/d-i: framebuffer and usb support for Tegra SoCs
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: REGULATOR_TWL4030=y
+  * [Config] armhf: disable JUMP_LABEL
+    - LP: #1378856
+
+  [ Tim Gardner ]
+
+  * rebase to v3.17-rc2
+  * updateconfigs
+  * [Config] CONFIG_NFC_ST21NFCB=n
+  * [Config] Added net/6lowpan/* to generic inclusion list
+  * [Config] Add arm64 to enforcer CONFIG_CC_STACKPROTECTOR
+  * rebase to v3.17-rc3
+  * rebase to v3.17-rc4
+  * rebase to v3.17-rc5
+  * [Config] armhf: USB_[E|O]HCI_EXYNOS=y
+  * [Config] CONFIG_XMON=y
+    - LP: #1365655
+  * [Config] CONFIG_KVM_BOOK3S_64=m for ppc64el
+    - LP: #1362514
+  * [Config] CONFIG_KVM_BOOK3S_64_HV=m
+    - LP: #1362514
+  * [Config] CONFIG_DMA_CMA=n
+    - LP: #1362261
+  * [Config] Add mpt3sas to d-i
+    - LP: #1368907
+  * [Debian] set do_*_tools after stage1 or bootstrap is determined
+    - LP: #1370211
+  * [Config] CONFIG_USB_OHCI_HCD_PCI=y
+    - LP: #1244176
+  * rebase to v3.17-rc6
+  * SAUCE: usbip: Update include path
+  * [Debian] usbip tools packaging
+    - LP: #898003
+  * [Config] Enable usbip tools
+    - LP: #898003
+  * [Config] CONFIG_CRASH_DUMP=n for powerpc-smp
+    - LP: #1363180
+  * [Config] Correct annotation regarding CONFIG_DMA_CMA
+    - LP: #1362261
+  * [Config] CONFIG_SND_HDA_INTEL=n for ppc64el
+    - LP: #1374438
+  * [Config] CONFIG_HOTPLUG_PCI_SHPC=n for ppc64el
+    - LP: #1374440
+  * [Debian] Don't fail if a symlink already exists
+  * rebase to v3.17-rc7
+  * [Config] CONFIG_HOTPLUG_PCI_PCIE=n for ppc64el
+    - LP: #1374440
+  * rebase to v3.17
+  * rebase to v3.18-rc1
+  * [Config] CONFIG_AUFS_FS=n for FTBS
+  * Enable vivid
+  * [Config] CONFIG_SOUND_OSS_CORE_PRECLAIM=n
+    - LP: #1385510
+  * rebase to v3.18-rc2
+  * [Debian] Fix linux-doc dangling symlinks
+    - LP: #661306
+  * CONFIG_MODULE_COMPRESS=n
+  * [Config] dropped scsi_tgt from generic inclusion list
+  * [Config] Added drivers/uio to generic inclusion list
+  * [Config] CONFIG_PATA_MACIO=y
+    - LP: #1378894
+  * [Config] CONFIG_DRM_BOCHS=n
+  * [Debian] install usbipd
+    - LP: #898003
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc2
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.18-rc1
+    - LP: #1316518
+    - LP: #1371591
+    - LP: #1357928
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc2
+    - LP: #1358116
+    - LP: #1350148
+    - LP: #1334950
+    - LP: #1329580
+    - LP: #1329580
+    - LP: #1329580
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.17-rc2
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 26 Aug 2014 10:36:19 -0600
+
+linux (3.17.0-0.0) utopic; urgency=medium
+
+  * Empty entry
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 26 Aug 2014 10:34:44 -0600
+
+linux (3.16.0-11.16) utopic; urgency=low
+
+  [ Mauricio Faria de Oliveira ]
+
+  * [Config] Switch kernel to vmlinuz (from vmlinux) on ppc64el
+    - LP: #1358920
+
+  [ Peter Zijlstra ]
+
+  * SAUCE: (no-up) mmu_notifier: add call_srcu and sync function for listener to delay call and sync
+    - LP: #1361300
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_ZPOOL=y
+    - LP: #1360428
+  * Release Tracking Bug
+    - LP: #1361308
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "net/mlx4_en: Fix bad use of dev_id"
+    - LP: #1347012
+  * net/mlx4_en: Reduce memory consumption on kdump kernel
+    - LP: #1347012
+  * net/mlx4_en: Fix mac_hash database inconsistency
+    - LP: #1347012
+  * net/mlx4_en: Disable blueflame using ethtool private flags
+    - LP: #1347012
+  * net/mlx4_en: current_mac isn't updated in port up
+    - LP: #1347012
+  * net/mlx4_core: Use low memory profile on kdump kernel
+    - LP: #1347012
+  * Drivers: scsi: storvsc: Change the limits to reflect the values on the host
+    - LP: #1347169
+  * Drivers: scsi: storvsc: Set cmd_per_lun to reflect value supported by the Host
+    - LP: #1347169
+  * Drivers: scsi: storvsc: Filter commands based on the storage protocol version
+    - LP: #1347169
+  * Drivers: scsi: storvsc: Fix a bug in handling VMBUS protocol version
+    - LP: #1347169
+  * Drivers: scsi: storvsc: Implement a eh_timed_out handler
+    - LP: #1347169
+  * drivers: scsi: storvsc: Set srb_flags in all cases
+    - LP: #1347169
+  * drivers: scsi: storvsc: Correctly handle TEST_UNIT_READY failure
+    - LP: #1347169
+  * namespaces: Use task_lock and not rcu to protect nsproxy
+    - LP: #1328088
+  * net: xgene: Check negative return value of xgene_enet_get_ring_size()
+  * mm/zbud: change zbud_alloc size type to size_t
+    - LP: #1360428
+  * mm/zpool: implement common zpool api to zbud/zsmalloc
+    - LP: #1360428
+  * mm/zpool: zbud/zsmalloc implement zpool
+    - LP: #1360428
+  * mm/zpool: update zswap to use zpool
+    - LP: #1360428
+  * ideapad-laptop: Change Lenovo Yoga 2 series rfkill handling
+    - LP: #1341296
+  * iommu/amd: Fix for pasid initialization
+    - LP: #1361300
+  * iommu/amd: Moving PPR fault flags macros definitions
+    - LP: #1361300
+  * iommu/amd: Drop oprofile dependency
+    - LP: #1361300
+  * iommu/amd: Fix typo in amd_iommu_v2 driver
+    - LP: #1361300
+  * iommu/amd: Don't call mmu_notifer_unregister in __unbind_pasid
+    - LP: #1361300
+  * iommu/amd: Don't free pasid_state in mn_release path
+    - LP: #1361300
+  * iommu/amd: Get rid of __unbind_pasid
+    - LP: #1361300
+  * iommu/amd: Drop pasid_state reference in ppr_notifer error path
+    - LP: #1361300
+  * iommu/amd: Add pasid_state->invalid flag
+    - LP: #1361300
+  * iommu/amd: Don't hold a reference to mm_struct
+    - LP: #1361300
+  * iommu/amd: Don't hold a reference to task_struct
+    - LP: #1361300
+  * iommu/amd: Don't call the inv_ctx_cb when pasid is not set up
+    - LP: #1361300
+  * iommu/amd: Don't set pasid_state->mm to NULL in unbind_pasid
+    - LP: #1361300
+  * iommu/amd: Remove change_pte mmu_notifier call-back
+    - LP: #1361300
+  * iommu/amd: Fix device_state reference counting
+    - LP: #1361300
+  * iommu/amd: Fix 2 typos in comments
+    - LP: #1361300
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 22 Aug 2014 08:45:54 -0400
+
+linux (3.16.0-10.15) utopic; urgency=low
+
+  [ dann frazier ]
+
+  * [debian] Fix regression with ABI subversions and backport
+
+  [ Feng Kan ]
+
+  * SAUCE: (no-up) irqchip:gic: change access of gicc_ctrl register to read
+    modify write.
+    - LP: #1357527
+  * SAUCE: (no-up) arm64: optimized copy_to_user and copy_from_user
+    assembly code
+    - LP: #1358949
+
+  [ Stefan Bader ]
+
+  * SAUCE: bcache: prevent crash on changing writeback_running
+    - LP: #1357295
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_XFRM_STATISTICS=y
+  * [Config] CONFIG_SECURITY_NETWORK_XFRM=y
+  * [Config] CONFIG_SENSORS_IBMPOWERNV=m
+    - LP: #1353005
+  * Release Tracking Bug
+    - LP: #1359783
+
+  [ Upstream Kernel Changes ]
+
+  * intel_idle: Broadwell support
+    - LP: #1256170
+  * powerpc/book3s: Add basic infrastructure to handle HMI in Linux.
+    - LP: #1357108
+  * powerpc/powernv: Invoke opal call to handle hmi.
+    - LP: #1357108
+  * powerpc/book3s: handle HMIs for cpus in nap mode.
+    - LP: #1357108
+  * powerpc/book3s: Fix endianess issue for HMI handling on napping cpus.
+    - LP: #1357108
+  * powerpc: Add smp_mb() to arch_spin_is_locked()
+    - LP: #1358569
+  * powerpc: Add smp_mb()s to arch_spin_unlock_wait()
+    - LP: #1358569
+  * hwmon: (powerpc/powernv) hwmon driver for power, fan rpm, voltage and
+    temperature
+    - LP: #1353005
+  * tools/testing/selftests/ptrace/peeksiginfo.c: add PAGE_SIZE definition
+    - LP: #1358855
+  * printk: Add function to return log buffer address and size
+    - LP: #1359423
+  * powerpc/powernv: Interface to register/unregister opal dump region
+    - LP: #1359423
+  * bcache: fix crash on shutdown in passthrough mode
+    - LP: #1357295
+  * bcache: fix uninterruptible sleep in writeback thread
+    - LP: #1357295
+
+  [ Vinayak Kale ]
+
+  * SAUCE: (no-up) dt-bindings: Add Potenza PMU binding
+    - LP: #1357527
+  * SAUCE: (no-up) arm64: dts: Add PMU node for APM X-Gene Storm SOC
+    - LP: #1357527
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 15 Aug 2014 12:34:33 -0600
+
+linux (3.16.0-9.14) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1357370
+
+  [ Serge Hallyn ]
+
+  * SAUCE: Overlayfs: allow unprivileged mounts
+    - LP: #1357025
+
+  [ Upstream Kernel Changes ]
+
+  * MAINTAINERS: Add entry for APM X-Gene SoC ethernet driver
+  * Documentation: dts: Add bindings for APM X-Gene SoC ethernet driver
+  * dts: Add bindings for APM X-Gene SoC ethernet driver
+  * drivers: net: Add APM X-Gene SoC ethernet driver support.
+  * powerpc/thp: Add write barrier after updating the valid bit
+    - LP: #1357014
+  * powerpc/thp: Don't recompute vsid and ssize in loop on invalidate
+    - LP: #1357014
+  * powerpc/thp: Invalidate old 64K based hash page mapping before insert
+    of 4k pte
+    - LP: #1357014
+  * powerpc/thp: Handle combo pages in invalidate
+    - LP: #1357014
+  * powerpc/thp: Invalidate with vpn in loop
+    - LP: #1357014
+  * powerpc/thp: Use ACCESS_ONCE when loading pmdp
+    - LP: #1357014
+  * powerpc/mm: Use read barrier when creating real_pte
+    - LP: #1357014
+  * powerpc/thp: Add tracepoints to track hugepage invalidate
+    - LP: #1357014
+  * rebase to v3.16.1
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 14 Aug 2014 08:18:02 -0400
+
+linux (3.16.0-8.13) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1356403
+
+  [ dann frazier ]
+
+  * [debian] Allow for package revisions condusive for branching
+
+  [ Upstream Kernel Changes ]
+
+  * ahci_xgene: Fix the watermark threshold for the APM X-Gene SATA host controller driver.
+    - LP: #1350087
+  * ahci_xgene: Use correct OOB tunning parameters for APM X-Gene SoC AHCI SATA Host controller driver.
+    - LP: #1350087
+  * powerpc/powernv: Enable M64 aperatus for PHB3
+    - LP: #1355469
+  * powerpc: Fail remap_4k_pfn() if PFN doesn't fit inside PTE
+    - LP: #1352994
+  * powerpc: Add machine_early_initcall()
+    - LP: #1352640
+  * powerpc/powernv: Switch powernv drivers to use machine_xxx_initcall()
+    - LP: #1352640
+  * powerpc/eeh: Avoid event on passed PE
+    - LP: #1352640
+  * powerpc/eeh: EEH support for VFIO PCI device
+    - LP: #1352640
+  * powerpc/eeh: sysfs entries lost
+    - LP: #1352640
+  * powerpc/powernv: Fix IOMMU table for VFIO dev
+    - LP: #1352640
+  * powerpc/eeh: Fetch IOMMU table in reliable way
+    - LP: #1352640
+  * powerpc/eeh: Refactor EEH flag accessors
+    - LP: #1352640
+  * powerpc/eeh: Selectively enable IO for error log
+    - LP: #1352640
+  * powerpc/eeh: Reduce lines of log dump
+    - LP: #1352640
+  * powerpc/eeh: Replace pr_warning() with pr_warn()
+    - LP: #1352640
+  * powerpc/eeh: Make diag-data not endian dependent
+    - LP: #1352640
+  * powerpc/eeh: Aux PE data for error log
+    - LP: #1352640
+  * PCI: Support BAR sizes up to 128GB
+    - LP: #1352640
+  * powerpc/powernv: Allow to freeze PE
+    - LP: #1352640
+  * powerpc/powernv: Split ioda_eeh_get_state()
+    - LP: #1352640
+  * powerpc/powernv: Handle compound PE
+    - LP: #1352640
+  * powerpc/powernv: Handle compound PE for EEH
+    - LP: #1352640
+  * powerpc/powernv: Handle compound PE in config accessors
+    - LP: #1352640
+  * mnt: Only change user settable mount flags in remount
+    - LP: #1356318
+    - CVE-2014-5206
+  * mnt: Move the test for MNT_LOCK_READONLY from change_mount_flags into do_remount
+    - LP: #1356318
+    - CVE-2014-5206
+  * mnt: Correct permission checks in do_remount
+    - LP: #1356323
+    - CVE-2014-5207
+  * mnt: Change the default remount atime from relatime to the existing value
+    - LP: #1356323
+    - CVE-2014-5207
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 10 Aug 2014 09:10:51 -0600
+
+linux (3.16.0-7.12) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.16 final
+  * [Config] d-i -- add virtio_scsi to virtio-modules
+    - LP: #1342000
+
+  [ dann frazier ]
+
+  * [Packaging] Fix 'printchanges' to work with versions containing '+'
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_MICROCODE=y
+    - LP: #1084373
+  * [Config] CONFIG_CONTEXT_TRACKING_FORCE=n
+    - LP: #1349028
+  * [Config] Add hv_balloon to d-i virtio-modules
+    - LP: #1292216
+  * Release Tracking Bug
+    - LP: #1354530
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 29 Jul 2014 09:55:15 -0400
+
+linux (3.16.0-6.11) utopic; urgency=low
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: MXS_DMA=y && MTD_NAND_GPMI_NAND=m
+  * [Config] armhf: KEYBOARD_IMX=m
+  * [Config] armhf: build cubox & imx6 DTBs
+  * [Config] armhf: RTC_DRV_PCF8523=y
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_KEYS_DEBUG_PROC_KEYS=y
+    - LP: #1344405
+  * [Config] CONFIG_SCSI_IPR_TRACE=y, CONFIG_SCSI_IPR_DUMP=y
+    - LP: #1343109
+  * Release Tracking Bug
+    - LP: #1349196
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 24 Jul 2014 09:08:55 -0400
+
+linux (3.16.0-5.10) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1346298
+  * [Config] CONFIG_GPIO_SYSFS=y
+    - LP: #1342153
+  * rebase to v3.16-rc6
+
+  [ Paolo Pisati ]
+
+  * [Config] enable ARCH_MVEBU*
+  * [Config] AHCI_MVEBU=m
+  * [Config] ARMADA_THERMAL=y
+  * [Config] ARM_ARMADA_370_XP_CPUIDLE=y
+  * [Config] CRYPTO_DEV_MV_CESA=m
+  * [Config] I2C_MV64XXX=m
+  * [Config] MMC_MVSDIO=m
+  * [Config] MMC_SDHCI_DOVE=m
+  * [Config] MTD_NAND_ORION=m
+  * [Config] MTD_NAND_PXA3xx=m
+  * [Config] MVNETA=m
+  * [Config] MV_XOR=y
+  * [Config] ORION_WATCHDOG=m
+  * [Config] PCI_MVEBU=y
+  * [Config] RTC_DRV_MV=y
+  * [Config] SND_KIRKWOOD_SOC*=m
+  * [Config] SPI_ORION=m
+  * [Config] USB_XHCI_MVEBU=m
+  * [Config] armhf: build all Armada and Dove DTBs
+  * [Config] armhf: SERIAL_8250_DW=y
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Jul 2014 07:49:42 -0400
+
+linux (3.16.0-4.9) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1341543
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc5
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 13 Jul 2014 21:30:27 -0400
+
+linux (3.16.0-3.8) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1340091
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 10 Jul 2014 10:06:47 +0100
+
+linux (3.16.0-2.7) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: aufs3 -- avoid aufs3-mmap.patch include hell for arm64
+    ubuntu: aufs3 -- (no-up) aufs3-mmap.patch
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 09 Jul 2014 16:16:28 +0100
+
+linux (3.16.0-2.6) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: aufs3 -- (no-up) aufs3-mmap.patch"
+    Fixes FTBS.
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Jul 2014 17:29:26 +0100
+
+linux (3.16.0-2.5) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu -- fix basic format for ubuntu/Makefile
+  * ubuntu: AUFS (no-squash): basic framework and update machinary
+  * ubuntu: aufs3 -- update update scripting
+  * ubuntu: aufs3 -- (no-up) aufs3-base.patch
+  * ubuntu: aufs3 -- (no-up) aufs3-mmap.patch
+  * ubuntu: aufs3 -- (no-up) aufs3-standalone.patch
+  * ubuntu: AUFS -- update to dcf336a754c86d5ee1c3d50699fd75c586d037cb
+  * [Configs] AUFS configs
+  * ubuntu: aufs3 -- reenable
+
+  [ Tim Gardner ]
+
+  * CONFIG_LATENCYTOP=n
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 08 Jul 2014 15:27:35 +0100
+
+linux (3.16.0-2.4) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] flip VIRTIO*=y
+  * [Config] commonise CONFIG_SWIOTLB=y
+  * [Config] apply Bus options (PCI etc.) >> PCI support config defaults
+  * [Config] apply Device Drivers >> ATA/ATAPI/MFM/RLL support (DEPRECATED)
+    config defaults
+  * [Config] apply Device Drivers >> Block devices config defaults
+  * [Config] apply Device Drivers >> Character devices config defaults
+  * [Config] apply Device Drivers >> DMA Engine support config defaults
+  * [Config] apply Device Drivers >> EDAC (Error Detection And Correction)
+    reporting config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Direct Rendering
+    Manager >> Direct Rendering Manager (XFree86 4.1.0 and higher DRI
+    support) config defaults
+  * [Config] apply Device Drivers >> GPIO Support config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Console display
+    driver support config defaults
+  * [Config] apply Device Drivers >> IIO staging drivers >> Accelerometers
+    config defaults
+  * [Config] apply Device Drivers >> IOMMU Hardware Support config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Miscellaneous devices config
+    defaults
+  * [Config] apply Device Drivers >> Input device support >> Hardware I/O
+    ports config defaults
+  * [Config] apply Device Drivers >> LED Support >> LED Class Support
+    config defaults
+  * [Config] apply Device Drivers >> Hardware Spinlock drivers config
+    defaults
+  * [Config] apply Device Drivers >> Multimedia support >> Cameras/video
+    grabbers support config defaults
+  * [Config] apply Security options config defaults
+  * [Config] apply Networking options >> Network packet filtering framework
+    (Netfilter) >> Core Netfilter Configuration config defaults
+  * [Config] apply Device Drivers >> MMC/SD/SDIO card support config
+    defaults
+  * [Config] apply Device Drivers >> Graphics support >> Frame buffer
+    Devices >> Support for frame buffer devices config defaults
+  * [Config] apply Power management and ACPI options >> CPU Frequency
+    scaling config defaults
+  * [Config] apply Processor type and features config defaults
+  * [Config] apply Partition Types config defaults
+  * [Config] apply Power management and ACPI options config defaults
+  * [Config] apply Device Drivers >> InfiniBand support config defaults
+  * [Config] apply Device Drivers >> Misc devices config defaults
+  * [Config] apply Device Drivers >> Multifunction device drivers config
+    defaults
+  * [Config] apply Device Drivers >> SCSI device support >> SCSI device
+    support >> SCSI low-level drivers config defaults
+  * [Config] apply Device Drivers >> Network device support >> Ethernet
+    driver support config defaults
+  * [Config] apply Device Drivers >> Network device support >> Network core
+    driver support config defaults
+  * [Config] apply Device Drivers >> Network device support >> PHY Device
+    support and infrastructure config defaults
+  * [Config] apply File systems >> Network File Systems config defaults
+  * [Config] apply Device Drivers >> Input device support >> Generic input
+    layer (needed for keyboard, mouse, ...) >> Touchscreens config defaults
+  * [Config] apply Device Drivers >> Memory Technology Device (MTD) support
+    >> NAND Device Support config defaults
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    >> Ralink driver support config defaults
+  * [Config] apply Device Drivers >> Staging drivers config defaults
+  * [Config] apply Cryptographic API >> Hardware crypto devices config
+    defaults
+  * [Config] apply Device Drivers >> Macintosh device drivers config
+    defaults
+  * [Config] apply Device Drivers >> Network device support >> Wireless LAN
+    config defaults
+  * [Config] apply Device Drivers >> PPS support config defaults
+  * [Config] apply Device Drivers >> Sound card support config defaults
+  * [Config] apply Networking support >> RF switch subsystem support config
+    defaults
+  * [Config] apply Library routines config defaults
+  * [Config] apply Device Drivers >> CODEC drivers config defaults
+  * [Config] apply Device Drivers >> PHY Subsystem config defaults
+  * [Config] apply Device Drivers >> Pulse-Width Modulation (PWM) Support
+    config defaults
+  * [Config] apply Kernel hacking >> Tracers config defaults
+  * [Config] apply Kernel hacking >> Runtime Testing config defaults
+  * [Config] apply Kernel hacking >> Architecture: powerpc config defaults
+  * [Config] apply Device Drivers >> USB support config defaults
+  * [Config] apply Device Drivers >> Power supply class support config
+    defaults
+  * [Config] apply Device Drivers >> USB Network Adapters config defaults
+  * [Config] apply General setup >> IRQ subsystem config defaults
+  * [Config] apply General setup config defaults
+  * [Config] apply File systems >> Miscellaneous filesystems config
+    defaults
+  * [Config] apply File systems config defaults
+  * [Config] apply Device Drivers >> Userspace I/O drivers config defaults
+  * [Config] apply Device Drivers >> Virtio drivers config defaults
+  * [Config] apply Device Drivers >> USB Peripheral Controller config
+    defaults
+  * [Config] apply Device Drivers >> SCSI device support >> SCSI device
+    support >> SCSI Transports config defaults
+  * [Config] apply Device Drivers >> Real Time Clock config defaults
+  * [Config] apply Device Drivers >> Serial ATA and Parallel ATA drivers
+    (libata) config defaults
+  * [Config] apply Device Drivers >> SoC Audio for Freescale CPUs config
+    defaults
+  * [Config] apply Device Drivers >> Voltage and Current Regulator Support
+    config defaults
+  * [Config] apply Device Drivers >> USB Physical Layer drivers config
+    defaults
+  * [Config] apply Device Drivers >> Watchdog Timer Support config defaults
+  * [Config] powerpc-powerpc-e500mc FTBFS -- CONFIG_CRASH_DUMP=n
+  * [Config] powerpc-powerpc64-emb FTBFS -- CONFIG_IMA=n
+  * [Config] powerpc-powerpc64-emb FTBFS -- CONFIG_HIBERNATION=n
+    CONFIG_HOTPLUG_CPU=n
+  * [Config] ppc64el-generic FTBFS -- CONFIG_LUSTRE_FS=n
+  * [Config] drivers/message/fusion needs scsi_transport_spi in virtual
+  * [Config] drivers/acpi/acpi_ipmi.ko needs
+    drivers/char/ipmi/ipmi_msghandler.ko in virtual
+  * [Config] armhf-* FTBFS -- CONFIG_STACK_TRACER=n
+    CONFIG_FUNCTION_TRACER=n
+  * [Config] ignore modules changing following major config changes
+
+  [ Tim Gardner ]
+
+  * rebase to v3.16-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc4
+    - LP: #1297581
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 03 Jul 2014 11:00:43 +0100
+
+linux (3.16.0-1.3) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "Disable do_tools_perf for FTBS"
+  * SAUCE: fix perf_regs definitions for arm64
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: ARCH_EXYNOS5* support
+  * [Config] armhf: CPU_IDLE=y and ARM_EXYNOS_CPUIDLE=y
+  * [Config] armhf: EXYNOS_THERMAL=y
+  * [Config] armhf: EXYNOS_IOMMU=y
+  * [Config] armhf: EXYNOS_ADC=m
+  * [Config] armhf: EXYNOS_I2C_EXYNOS5=m
+  * [Config] armhf: MMC_SDHCI_S3C=m
+  * [Config] armhf: PCI_EXYNOS=y
+  * [Config] armhf: PHY_EXYNOS5250_SATA=y
+  * [Config] armhf: USB_[E|O]HCI_EXYNOS=y && SAMSUNG_USBPHY=y
+  * [Config] armhf: PWM_SAMSUNG=m
+  * [Config] armhf: RTC_DRV_S3C=y
+  * [Config] armhf: S3C2410_WATCHDOG=m
+  * [Config] armhf: MMC_DW_EXYNOS=m
+  * [Config] armhf: SERIAL_SAMSUNG=y
+  * [Config] armhf: SND_SOC_SAMSUNG=m
+  * [Config] armhf: SPI_S3C64XX=m
+  * [Config] armhf: EXYNOS_VIDEO=y and VIDEO_SAMSUNG*=m
+  * [Config] armhf: FB_S3C=m
+  * [Config] armhf: build all Exynos 5 DTBs
+  * [Config] armhf: disable CPUFREQ_EXYNOS
+
+  [ Tim Gardner ]
+
+  * rebase to v3.16-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc3
+    - LP: #1331915
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 24 Jun 2014 08:58:09 -0600
+
+linux (3.16.0-0.2) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: intel_pstate -- toggle default to disable"
+    - LP: #1333322
+  * CONFIG_BOOKE_WDT=y
+  * Disable do_tools_perf for FTBS (just until I can figure it out)
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 23 Jun 2014 13:37:53 -0600
+
+linux (3.16.0-0.1) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1333265
+
+  [ Andy Whitcroft ]
+
+  * [Config] cloud-tools -- add systemd units
+    - LP: #1329027
+
+  [ dann frazier ]
+
+  * [Config] CONFIG_RTC_DRV_XGENE=y for arm64
+  * [Config] CONFIG_NET_XGENE=m for arm64
+  * [Config] Restrict CONFIG_POWER_RESET_SYSCON to arm64 only
+
+  [ Feng Kan ]
+
+  * SAUCE: (no-up) arm64: dts: Add X-Gene reboot driver dts node
+  * SAUCE: (no-up) Add documentation for generic SYSCON reboot driver.
+  * SAUCE: (no-up) Select reboot driver for X-Gene platform.
+
+  [ Iyappan Subramanian ]
+
+  * SAUCE: (no-up) MAINTAINERS: Add entry for APM X-Gene SoC ethernet driver
+  * SAUCE: (no-up) Documentation: dts: Add bindings for APM X-Gene SoC ethernet driver
+  * SAUCE: (no-up) dts: Add bindings for APM X-Gene SoC ethernet driver
+  * SAUCE: (no-up) drivers: net: Add APM X-Gene SoC ethernet driver support.
+
+  [ Tim Gardner ]
+
+  * updateconfigs
+  * Fix arm64 crypto Makefile
+  * [Config] CONFIG_BOOKE_WDT=n for FTBS
+  * [Debian] Add UTS_UBUNTU_RELEASE_ABI to utsrelease.h
+    - LP: #1327619
+  * Disabled powerpc64-emb for FTBS
+  * [Config] CONFIG_DRM_TEGRA=m
+  * [Config] CONFIG_CMA_SIZE_MBYTES=64
+  * rebase to v3.16-rc2
+  * Clean up generic.inclusion-list warnings
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.16-rc2
+    - LP: #1328587
+    - LP: #1319291
+    - LP: #1310512
+    - LP: #1310512
+    - LP: #1305480
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 12 Jun 2014 12:26:09 +0000
+
+linux (3.15.0-6.11) utopic; urgency=low
+
+  [ Adam Conrad ]
+
+  * Enable building the sata-modules udeb on ppc64el.
+    - LP: #1323980
+  * [Packaging] Set bootloader and loader on ppc64el to grub
+
+  [ Adam Lee ]
+
+  * SAUCE: (no-up) rtlwifi: rtl8723be: disable MSI interrupts mode
+    - LP: #1310512, #1320070
+
+  [ Alex Hung ]
+
+  * SAUCE: (no-up) dell-led: add mic mute led interface
+    - LP: #1308297
+
+  [ Andy Whitcroft ]
+
+  * [Config] d-i -- add hyperv_keyboard to serial-modules udeb
+    - LP: #1285434
+  * [Config] tools -- enable cpupower on ppc64el
+  * [Config] ppc64el -- enable perf tools
+  * [Config] powerpc -- enable perf tools
+  * [Config] ppc64el -- reduce MAX_ORDER with 64k pages
+  * [Config] arm64 -- enable tools
+    - LP: #1326050
+  * [Config] switch hyper-keyboard to virtual
+    - LP: #1325306
+  * [Config] fix up Breaks/Replaces on linux-cloud-tools-common to fix
+    upgrades
+  * SAUCE: kvm: BIOS disabled kvm support should be a warning
+    - LP: #1300247
+  * SAUCE: nouveau: missing outputs should be warnings
+    - LP: #1300244
+  * [Config] d-i -- add nvme devices to block-modules udeb
+    - LP: #1303710
+
+  [ Anton Blanchard ]
+
+  * SAUCE: (no-up) powerpc: 64bit sendfile is capped at 2GB
+    - LP: #1328230
+
+  [ Colin Ian King ]
+
+  * SAUCE: intel_pstate: inform user that thermald is worth considering
+
+  [ Dave Chiluk ]
+
+  * [Config] Enable CONFIG_IP_VS_IPV6=y
+    - LP: #1300739
+
+  [ Paolo Pisati ]
+
+  * [Config] build vexpress a9 dtb
+    - LP: #1303657
+
+  [ Tetsuo Handa ]
+
+  * SAUCE: kthread: Do not leave kthread_create() immediately upon SIGKILL.
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1329045
+  * [Debian] Treat vdso install as an environment variable
+    - LP: #1325713
+  * [Config] Treat vdso install as an environment variable
+    - LP: #1325713
+  * [config] Set IPMI suppoort default to "y"
+  * [Config] powerpc -- CONFIG_SCSI_IBMVSCSI=y
+  * [Config] CONFIG_RT_GROUP_SCHED=n
+    - LP: #1284731
+  * [Config] ppc64el -- switch to 64K system pages
+  * [Config] CONFIG_MICROCODE_EARLY=y
+  * [Config] SND_DAVINCI_SOC && SND_AM33XX_SOC_EVM =m
+  * [Config] armhf: DRM_TILCDC=m
+  * SAUCE: (no-up) mei_me: Add module parameter to disable MSI
+  * [Config] arm64: KVM=y
+  * [Config] armhf: LEDS_TRIGGER_HEARTBEAT=y
+  * [Config] armhf: generic: disable CPU_IDLE
+  * [Config] armhf: CPU_FREQ=y
+  * [Config] Add new mlx modules to d-i
+  * [Config] Added Muti-Arch support for linux-headers-PKGVER-ABINUM, linux-tools-common, and linux-cloud-tools-common
+    - LP: #1295112
+  * [Config] CONFIG_EXYNOS_ADC=n, CONFIG_HW_RANDOM_EXYNOS=n, CONFIG_MMC_DW_EXYNOS=n, CONFIG_USB_DWC3_EXYNOS=n
+    - LP: #1294353
+  * [Config] CONFIG_ABX500_CORE=y for ppc64el
+  * [Config] CONFIG_ALX=m for powerpc
+  * [Config] CONFIG_ACENIC_OMIT_TIGON_I=n for ppc64el
+  * [Config] CONFIG_ACORN_PARTITION_*=n for ppc64el
+  * [Config] CONFIG_ANDROID=n for powerpc
+  * [Config] CONFIG_ASYNC_RAID6_TEST=m for ppc64el
+  * [Config] CONFIG_BIG_KEYS=y for ppc64el
+  * [Config] CONFIG_BSD_PROCESS_ACCT=y for ppc64el
+  * rebase to v3.15
+  * [Config] CONFIG_PHY_XGENE=y
+  * [Config] CONFIG_MLX4_DEBUG=y
+    - LP: #1328256
+  * [Config] CONFIG_POWERNV_CPUFREQ=y for powerpc, ppc64el
+    - LP: #1324571
+  * [Config] CONFIG_BLK_DEV_SR_VENDOR=n for ppc64el
+  * [Config] CONFIG_CFG80211=m for ppc64el
+  * [Config] CONFIG_CHARGER_BQ24190=m for powerpc
+  * [Config] CONFIG_CHARGER_BQ24735=m for powerpc
+  * [Config] CONFIG_EXPERT=y for ppc64el
+  * [Config] CONFIG_ATA_SFF=y on ppc64el
+  * [Config] CONFIG_ATA_GENERIC=y for ppc64el, powerpc
+  * [Config] CONFIG_CHR_DEV_ST=m for ppc64el
+  * [Config] CONFIG_CHECKPOINT_RESTORE=y for ppc64el
+  * [Config] CONFIG_CHELSIO_T1_1G=y for ppc64el
+  * [Config] CONFIG_CHR_DEV_OSST=m for ppc64el
+  * [Config] CONFIG_CHR_DEV_SCH=m for ppc64el
+  * [Config] CONFIG_CPU_FREQ_STAT=y for powerpc
+  * [Config] CONFIG_DDR=y for ppc64el
+  * [Config] CONFIG_DEBUG_BUGVERBOSE=y for powerpc
+  * [Config] CONFIG_E100=m, CONFIG_E1000=m, CONFIG_E1000E=m for ppc64el
+  * [Config] CONFIG_EZX_PCAP=n for all arches
+  * [Config] CONFIG_DYNAMIC_DEBUG=y for powerpc
+  * [Config] CONFIG_ENABLE_MUST_CHECK=n for ppc64el
+  * [Config] CONFIG_ENABLE_WARN_DEPRECATED=n for ppc64el
+  * [Config] CONFIG_FB_3DFX=m for all arches
+  * [Config] CONFIG_FB_MATROX=m for ppc64el
+  * [Config] CONFIG_FB_RADEON=m for ppc64el
+  * [Config] CONFIG_FB_SAVAGE_I2C=y for all arches
+  * [Config] CONFIG_FIREWIRE=m for ppc64el
+  * [Config] CONFIG_FTR_FIXUP_SELFTEST=n for ppc64el
+  * [Config] CONFIG_HAMRADIO=y for ppc64el
+  * [Config] CONFIG_I2C_CHARDEV=m for ppc64el
+  * [Config] CONFIG_I2C_MUX=m for ppc64el
+  * [Config] CONFIG_I2C_STUB=m for ppc64el
+  * [Config] CONFIG_I2O=m for ppc64el
+  * [Config] CONFIG_INET_XFRM_MODE_BEET=m, CONFIG_INET_XFRM_MODE_TRANSPORT=m, CONFIG_INET_XFRM_MODE_TUNNEL=m for ppc64el
+  * [Config] CONFIG_INFINIBAND_IPOIB_DEBUG=n, CONFIG_INFINIBAND_MTHCA_DEBUG=n for ppc64el
+  * [Config] CONFIG_INFINIBAND_NES=m, CONFIG_INFINIBAND_OCRDMA=m, CONFIG_INFINIBAND_QIB=m for ppc64el
+  * [Config] CONFIG_INPUT_FF_MEMLESS=m for ppc64el
+  * [Config] CONFIG_INTERVAL_TREE_TEST=m for ppc64el
+  * [Config] CONFIG_IPACK_BUS=m for ppc64el
+  * [Config] CONFIG_ISDN=y for ppc64el
+  * [Config] CONFIG_ISO9660_FS=m for ppc64el
+  * [Config] CONFIG_KGDB=y for ppc64el
+  * [Config] CONFIG_KVM_GUEST=y for ppc64el
+  * [Config] CONFIG_L2TP_V3=y for powerpc
+  * [Config] CONFIG_MAILBOX=y for ppc64el
+  * [Config] CONFIG_MD_LINEAR=m, CONFIG_MD_RAID0=m, CONFIG_MD_RAID1=m for ppc64el
+  * [Config] CONFIG_MEDIA_SUPPORT=m for ppc64el
+  * [Config] CONFIG_MEMORY=y for ppc64el
+  * [Config] CONFIG_MEMSTICK=m for ppc64el
+  * [Config] CONFIG_MFD_SM501_GPIO=n for ppc64el
+  * [Config] CONFIG_MMC_BLOCK=m for ppc64el
+  * [Config] CONFIG_MOUSE_PS2=m for ppc64el
+  * [Config] CONFIG_NET_9P=m for ppc64el
+  * [Config] CONFIG_MSDOS_FS=m for ppc64el
+  * [Config] CONFIG_MSI_BITMAP_SELFTEST=n for ppc64el
+  * [Config] CONFIG_MTD=m for arm64
+  * [Config] CONFIG_NETCONSOLE=m for ppc64el
+  * [Config] CONFIG_NETFILTER_XT_TARGET_NOTRACK=m for ppc64el
+  * [Config] CONFIG_NET_IPIP=m for ppc64el
+  * [Config] CONFIG_NET_TEAM=m for all arches
+  * [Config] CONFIG_NFC=m for ppc64el
+  * [Config] CONFIG_NL80211_TESTMODE=n for all arches
+  * [Config] CONFIG_NLS_CODEPAGE_437=y for powerpc
+  * [Config] CONFIG_NLS_ASCII=m, CONFIG_NLS_ISO8859_1=m, CONFIG_NLS_UTF8=m for ppc64el
+  * [Config] CONFIG_NOP_USB_XCEIV=m for ppc64el
+  * [Config] CONFIG_NOTIFIER_ERROR_INJECTION=m for ppc64el
+  * [Config] CONFIG_OPROFILE=m for ppc64el
+  * [Config] CONFIG_PARPORT_1284=y for ppc64el
+  * [Config] CONFIG_PARPORT_AX88796=m, CONFIG_PARPORT_PC_FIFO=y, CONFIG_PARPORT_SERIAL=m for ppc64el
+  * [Config] CONFIG_8723AU_P2P=n
+  * [Config] CONFIG_PCI_IOV=y, CONFIG_PCI_PASID=y, CONFIG_PCI_PRI=y, CONFIG_PCI_REALLOC_ENABLE_AUTO=y, CONFIG_PCI_STUB=m for ppc64el
+  * [Config] CONFIG_PCNET32=m for ppc64el
+  * [Config] CONFIG_SCSI_DH_EMC=m for ppc64el
+  * [Config] CONFIG_SCSI_DH_HP_SW=m for ppc64el
+  * [Config] CONFIG_SCSI_FC_ATTRS=m for ppc64el
+  * [Config] CONFIG_SCSI_IPR=m for ppc64el
+  * [Config] CONFIG_SCSI_LOGGING=y for ppc64el
+  * [Config] CONFIG_SCSI_OSD_INITIATOR=m for ppc64el
+  * [Config] CONFIG_SCSI_SCAN_ASYNC=y for ppc64el
+  * [Config] CONFIG_SCSI_SYM53C8XX_2=m for ppc64el
+  * [Config] CONFIG_XILINX_LL_TEMAC=m for powerpc
+  * [Config] CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y for ppc64el
+  * [Config] CONFIG_WLAN=y for arm64
+  * [Config] CONFIG_VORTEX=m for ppc64el
+  * [Config] CONFIG_WIMAX=m for ppc64el
+  * [Config] CONFIG_WATCHDOG=y for ppc64el
+  * [Config] CONFIG_VIRT_DRIVERS=y for ppc64el
+  * [Config] CONFIG_VERSION_SIGNATURE="" for powerpc64-emb
+  * [Config] CONFIG_UWB=m for ppc64el
+  * [Config] CONFIG_USB_STORAGE=y
+  * [Config] CONFIG_SATA_AHCI_PLATFORM=y for armhf
+  * [Config] CONFIG_HID_RMI=m
+  * [Config] CONFIG_HVC_DCC=n
+    - LP: #1303657
+
+  [ Upstream Kernel Changes ]
+
+  * mm/numa: Remove BUG_ON() in __handle_mm_fault()
+    - LP: #1323165
+  * powerpc/powernv: Add calls to support little endian host
+    - LP: #1327400
+  * HID: rmi: introduce RMI driver for Synaptics touchpads
+  * HID: rmi: do not stop the device at the end of probe
+  * HID: rmi: check for the existence of some optional queries before reading query 12
+  * HID: rmi: do not fetch more than 16 bytes in a query
+  * HID: rmi: fix wrong struct field name
+  * HID: rmi: fix masks for x and w_x data
+  * HID: rmi: do not handle touchscreens through hid-rmi
+  * ALSA: pcm: 'BUG:' message unnecessarily triggers kerneloops
+    - LP: #1305480
+  * rebase to v3.15
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 03 Jun 2014 17:02:49 +0000
+
+linux (3.15.0-5.10) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1325596
+  * [Config] CONFIG_POWERNV_CPUFREQ=y for ppc64el
+  * rebase to v3.15-rc8
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc8
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 02 Jun 2014 12:59:34 +0000
+
+linux (3.15.0-4.9) utopic; urgency=low
+
+  * no change rebuild to fix embeded debhelper.
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 29 May 2014 12:41:58 +0100
+
+linux (3.15.0-4.8) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1324107
+  * [Config] enable SECURITY_APPARMOR_UNCONFINED_INIT
+
+  [ Javier Martinez Canillas ]
+
+  * SAUCE: (no-up) apparmor: fix bug that constantly spam the console
+    - LP: #1323526
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor3 - alpha6 snapshot
+    - LP: #1323528
+  * SAUCE: (no-up) apparmor: fix apparmor spams log with warning message
+    - LP: #1308761
+  * SAUCE: (no-up) apparmor: fix refcount bug in apparmor pivotroot
+    - LP: #1308765
+  * SAUCE: (no-up): apparmor: fix apparmor refcount bug in apparmor_kill
+    - LP: #1308764
+  * SAUCE: (no-up): apparmor: use custom write_is_locked macro
+    - LP: #1323530
+
+  [ Kamal Mostafa ]
+
+  * [Config] add debian/gbp.conf
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_SATA_AHCI=m for ppc64el
+    - LP: #1323980
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 28 May 2014 12:47:17 +0100
+
+linux (3.15.0-3.7) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1323189
+
+  [ Andy Whitcroft ]
+
+  * [Config] autopkgtest -- need fakeroot for tests
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 26 May 2014 08:12:50 +0200
+
+linux (3.15.0-2.6) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] remove the kernel-image firmware list on clean
+
+  [ Martin Pitt ]
+
+  * [Config] autopkgtest -- switch to significantly faster rebuild
+
+  [ Stefan Bader ]
+
+  * [Config]: Add missing modules to inclusion list
+
+  [ Tim Gardner ]
+
+  * [debian] Dynamically generate the kernel-image udebs firmware list
+  * [d-i] firmware/kernel-image is generated
+  * rebase to v3.15-rc6
+  * Release Tracking Bug
+    - LP: #1322251
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc6
+    - LP: #1297581
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 21 May 2014 10:51:29 -0700
+
+linux (3.15.0-1.5) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Add apm-mustang.dtb to kernel-image udeb
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 19 May 2014 14:47:42 -0700
+
+linux (3.15.0-1.4) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) hv -- bodge hv_vss_daemon so it can use the
+    local linux/hyperv.h"
+  * Revert "SAUCE: (no-up) hv -- bodge hv_kvp_daemon so it can use the
+    local linux/hyperv.h"
+  * [Packaging] tools -- hv tools build correctly against the built headers
+  * [Packaging] cloud-tools -- add the hv_fcopy_daemon to the package
+  * cloud-tools -- pull in init scripts for Hyper-V daemons
+  * cloud-tools -- detect Hyper-V VM to avoid starting
+  * cloud-tools -- update IF_NAME to DEVICE in hv_* scripts
+    - LP: #1295401
+  * [Config] cloud-tools: reenable cloud-tools
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 18 May 2014 19:21:04 +0100
+
+linux (3.15.0-1.3) utopic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] ppc64el is a powerpc kernel arch and needs its quirks
+    - LP: #1318848
+
+  [ Ben Collins ]
+
+  * [Config] Switch to grub-ieee1275 as recommended on book3e systems
+    - LP: #1318629
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_FSL_PAMU=n
+    - LP: #1311738
+  * Release Tracking Bug
+    - LP: #1320239
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 16 May 2014 07:37:07 -0600
+
+linux (3.15.0-1.2) utopic; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1318171
+  * Add rpcsec_gss_krb5 to generic inclusion list
+    - LP: #769527
+  * rebase to v3.15-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc5
+    - LP: #1297581
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 06 May 2014 15:20:10 -0500
+
+linux (3.15.0-0.1) utopic; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.15-rc4
+    - LP: #1297581
+    - LP: #1297581
+    - LP: #1305133
+    - LP: #1297581
+    - LP: #1297581
+    - LP: #871808
+    - LP: #1260303
+    - LP: #1268468
+    - LP: #1248116
+    - LP: #1211920
+    - LP: #1259790
+    - LP: #1259437
+    - LP: #1259435
+    - LP: #1268468
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 07 Feb 2014 09:35:13 -0700
+
+linux (3.15.0-0.0) utopic; urgency=low
+
+  * Initial version for 3.15.
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 02 May 2014 15:06:39 +0100
+
+linux (3.13.0-8.27) trusty; urgency=low
+
+  [ John Johansen ]
+
+  * SAUCE: Add config option to disable new apparmor 3 semantics
+    -LP: #1270215
+
+  [ Tim Gardner ]
+
+  * [debian] Fix indep_hdrs_pkg_name
+    - LP: #1134441
+  * Update lttng to 00808267d3ba7cdcddfed7bec7e62a40463c1307 Version 2.4.0-rc3
+  * Enabled lttng build
+  * Don't build lttng for armhf
+    lttng hates gcc-4.8 for armhf
+  * Release Tracking Bug
+    - LP: #1277309
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13.2
+    - LP: #1260303
+    - LP: #1260303
+    - LP: #1268468
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 06 Feb 2014 09:25:51 -0700
+
+linux (3.13.0-7.26) trusty; urgency=low
+
+  [ John Johansen ]
+
+  * SAUCE: apparmor: fix uninitialized lsm_audit membe
+    - LP: #1268727
+  * Add config option to optionally enable new apparmor 3 semantics
+
+  [ Tim Gardner ]
+
+  * [Config] Add lowlatency to getabis
+  * [Config] CONFIG_SECURITY_APPARMOR_AA3_SEMANTICS=y
+    - LP: #1270215
+  * Release Tracking Bug
+    - LP: #1276810
+
+  [ Upstream Kernel Changes ]
+
+  * x86, x32: Correct invalid use of user timespec in the kernel
+    - LP: #1274349
+    - CVE-2014-0038
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 05 Feb 2014 15:49:44 -0500
+
+linux (3.13.0-7.25) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: fix fmd headers"
+  * SAUCE: fix fmd headers
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 04 Feb 2014 09:36:09 +0000
+
+linux (3.13.0-7.24) trusty; urgency=low
+
+  [ Stefan Bader ]
+
+  * [Config] Make vmwgfx driver enable the framebuffer device
+
+  [ Tim Gardner ]
+
+  * rebase to v3.13.1
+  * [Config] CONFIG_NFS_FS=m for ppc64el
+  * [Config] CONFIG_X86_SYSFB=n
+    https://lists.ubuntu.com/archives/kernel-team/2014-February/038166.html
+  * Release Tracking Bug
+    - LP: #1275898
+
+  [ Upstream Kernel Changes ]
+
+  * i2c: piix4: Add support for AMD ML and CZ SMBus changes
+    - LP: #1272525
+  * i2c: piix4: Use different message for AMD Auxiliary SMBus Controller
+    - LP: #1272525
+  * mm: ignore VM_SOFTDIRTY on VMA merging
+    - LP: #1274917
+  * drm/radeon: disable dpm on BTC
+    - LP: #1266984
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13.1
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 30 Jan 2014 15:24:48 +0000
+
+linux (3.13.0-6.23) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] fix up architecture for linux-tools
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 30 Jan 2014 09:00:41 +0000
+
+linux (3.13.0-6.22) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] limit linux-udebs-<flavour> to matching arch
+  * [Config] powerpc -- disable perf to fix FTBFS
+  * [Config] ppc64el -- fix up missing udebs
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 29 Jan 2014 16:00:28 +0000
+
+linux (3.13.0-6.21) trusty; urgency=low
+
+  [ Andy Fleming ]
+
+  * SAUCE: net: Add support for handling queueing in hardware
+  * SAUCE: of_mdio: Add of_phy_attach function
+  * SAUCE: phylib: Add generic 10G driver
+  * SAUCE: phylib: Support attaching to gen10g_driver
+  * SAUCE: phylib: Add Clause 45 read/write functions
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: fix fmd headers
+  * [Packaging] lowlatency -- merge out of tree flavours
+  * SAUCE: allow IRQs to be irq-threaded by default via config
+  * [Config]: enable CONFIG_IRQ_FORCED_THREADING_DEFAULT for lowlatency
+  * [Config] powerpc -- fix up Build-depends:
+  * Release Tracking Bug
+    - LP: #1273747
+
+  [ Ben Collins ]
+
+  * SAUCE: PPC: PCI: Fix pcibios_io_space_offset() so it works for 32-bit
+    ptr/64-bit rsrcs
+  * SAUCE: Revert "phy: vitesse make vsc824x_add_skew static"
+  * SAUCE: Fixup freescale usb phy driver to work on ppc64
+  * SAUCE: xgmac_mdio: Silence read errors
+  * SAUCE: Provide booke stub for kvmppc_is_bigendian()
+  * SAUCE: Fix stack overflow on ppc32
+  * SAUCE: Use resource_size_t instead of long for PCI resource address
+  * SAUCE: net/phy: Export function for use by dpaa_eth
+  * [Packaging] powerpc -- merge out of tree powerpc arch
+
+  [ Bjorn Helgaas ]
+
+  * SAUCE: Revert "EISA: Log device resources in dmesg"
+    - LP: #1251816
+  * SAUCE: Revert "EISA: Initialize device before its resources"
+    - LP: #1251816
+
+  [ Emil Medve ]
+
+  * SAUCE: phylib: Minimum hack to get the generic 10G PHY driver to work
+    with 10G "fixed-link"s
+
+  [ Kumar Gala ]
+
+  * SAUCE: fsl_qbman: Add drivers for Freescale DPAA Qman & Bman
+  * SAUCE: fsl_pme2: Add support for DPAA PME
+  * SAUCE: fmd: FMD14 integration
+  * SAUCE: dpaa_eth: Ethernet driver for Freescale QorIQ DPA Architecture
+  * SAUCE: powerpc/85xx: Add DPAA/networking support for CoreNet
+
+  [ Madalin Bucur ]
+
+  * SAUCE: net/flow: remove sleeping and deferral mechanism from
+    flow_cache_flush
+  * SAUCE: net/phy: abort genphy_read_status when link changes during speed
+    and duplex reading
+
+  [ Stefan Bader ]
+
+  * [Config] move some VMWare related modules into main package
+    - LP: #1271669
+
+  [ Tim Gardner ]
+
+  * [Config] Add r815x to nic-modules
+    - LP: #1273735
+  * [Config] CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+    - LP: #239479
+
+  [ Upstream Kernel Changes ]
+
+  * mmc: sdhci-pci: break out definitions to header file
+    - LP: #1239938
+  * mmc: sdhci-pci: add support of O2Micro/BayHubTech SD hosts
+    - LP: #1239938
+  * powerpc/book3e: rename interrupt_end_book3e with __end_interrupts
+  * powerpc/book3e: support CONFIG_RELOCATABLE
+  * book3e/kexec/kdump: enable kexec for kernel
+  * book3e/kexec/kdump: create a 1:1 TLB mapping
+  * book3e/kexec/kdump: introduce a kexec kernel flag
+  * book3e/kexec/kdump: implement ppc64 kexec specfic
+  * book3e/kexec/kdump: redefine VIRT_PHYS_OFFSET
+  * book3e/kexec/kdump: recover "r4 = 0" to create the initial TLB
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 28 Jan 2014 22:59:46 +0000
+
+linux (3.13.0-5.20) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] tools -- do not make symlinks when not making packages
+  * [Packaging] tools -- tidy up control.stub.in ordering
+  * [Packaging] tools -- tools-common is shared and not conditional
+  * rebase to v3.13
+
+  [ Dirk Brandewie ]
+
+  * SAUCE: intel_pstate: Add setting voltage value for baytrail P states.
+
+  [ KY Srinivasan ]
+
+  * SAUCE: Drivers: hv: vmbus: Specify the target CPU that should receive
+    notification
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13
+   - LP: #1270603
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 17 Jan 2014 15:45:31 +0000
+
+linux (3.13.0-4.19) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] libunwind8-dev is now available for ppc64el
+  * [Packaging] tools -- make cpupower optional
+  * [Packaging] tools -- enable correctly for x86
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1269872
+
+  [ Upstream Kernel Changes ]
+
+  * SAUCE: ARM: OMAP: hwmod: Add SYSC offsets for AES IP
+  * SAUCE: ARM: OMAP4: hwmod: Add hwmod data for AES IP
+  * SAUCE: OMAP: AM33xx: hwmod: Correct AES module SYSC type
+  * SAUCE: crypto: omap-aes: add error check for pm_runtime_get_sync
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 85ce70fdf48aa290b4845311c2dd815d7f8d1fa5
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 15 Jan 2014 13:23:05 +0000
+
+linux (3.13.0-3.18) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.13-rc8
+  * [Packaging] efi -- allow EFI signatures on any arch
+
+  [ Tim Gardner ]
+
+  * [Config] Fix vcs-git path
+  * Release Tracking Bug
+    - LP: #1268683
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc8
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 12 Jan 2014 11:58:01 +0000
+
+linux (3.13.0-2.17) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1267809
+  * [Config] apply Platform support>>CPUIdle driver>>CPU Idle config
+    defaults
+  * [Config] apply Platform support>>CPU Frequency scaling config defaults
+  * [Config] CONFIG_PARIDE_EPATC8=y
+  * [Config] apply Device Drivers >> Broadcom specific AMBA config defaults
+  * [Config] apply Bus options >> PCI support >> RapidIO support >> RapidIO
+    Switch drivers config defaults
+  * [Config] apply Cryptographic API config defaults
+  * [Config] apply Device Drivers >> Common Clock Framework config defaults
+  * [Config] apply Device Drivers >> Distributed Switch Architecture
+    drivers config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Backlight & LCD
+    device support config defaults
+  * [Config] apply Device Drivers >> Graphics support >> Support for frame
+    buffer devices >> Bootup logo config defaults
+  * annotations -- update in tree annotations
+  * [Config] apply Bus options >> PCI support >> RapidIO support config
+    defaults
+  * [Config] CONFIG_POWER_AVS=y CONFIG_RESET_CONTROLLER=y
+  * [Config] apply Device Drivers >> 1-wire Bus Masters config defaults
+  * [Config] apply CAN Device Drivers >> Platform CAN drivers with Netlink
+    support config defaults
+  * [Config] apply Device Drivers >> Character devices >> Serial drivers
+    config defaults
+  * [Config] apply Device Drivers >> Generic Thermal sysfs driver config
+    defaults
+  * [Config] apply Device Drivers >> Character devices >> TPM Hardware
+    Support config defaults
+  * [Config] apply Device Drivers >> Character devices config defaults
+  * [Config] apply Device Drivers >> HID support >> USB HID support >> USB
+    HID transport layer config defaults
+  * [Config] apply Device Drivers >> HID support >> HID bus support config
+    defaults
+  * [Config] apply Device Drivers >> HID support >> USB HID support config
+    defaults
+  * annotations -- update in tree annotations
+  * [Config] apply Device Drivers >> GPIO Support config defaults
+  * [Config] update configs for apparmour update
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 - alpha 4 snapshot
+  * SAUCE: apparmor: fix unix domain sockets to be mediated on connection
+    - LP: #1208988
+  * SAUCE: apparmor: allocate path lookup buffers during init
+    - LP: #1208988
+  * SAUCE: (no-up) apparmor: Fix tasks not subject to, reloaded policy
+    - LP: #1236455
+
+  [ Tim Gardner ]
+
+  * Revert "[Debian] getabis: Preface module with package name"
+  * [Config] Added ppc64el to getabis
+  * [packaging] Bump ABI for every new release
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 10 Jan 2014 11:48:39 +0000
+
+linux (3.13.0-1.16) trusty; urgency=low
+
+  * First 3.13 upload.
+  * Release tracker
+    - LP: #1266852
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 07 Jan 2014 09:21:26 -0700
+
+linux (3.13.0-0.15) trusty; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v3.13-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc7
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 05 Jan 2014 06:13:33 -0700
+
+linux (3.13.0-0.14) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to 7a262d2ed9fa42fad8c4f243f8025580b58cf2f6
+
+  [ Tim Gardner ]
+
+  * Remove ubuntu/dm-raid4-5 in favor of CONFIG_MD_RAID456
+  * Update lttng to Version 2.4.0-rc2
+  * lttng: Disabled trace_kvm_async_pf_completed
+  * [Config] CONFIG_IMA=y
+    - LP: #1244627
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 7a262d2ed9fa42fad8c4f243f8025580b58cf2f6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 02 Jan 2014 12:57:13 -0700
+
+linux (3.13.0-0.13) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: aufs3 -- (no-up) aufs3-base.patch
+  * ubuntu: aufs3 -- (no-up) aufs3-mmap.patch
+  * ubuntu: aufs3 -- (no-up) aufs3-standalone.patch
+  * ubuntu: AUFS (no-squash): basic framework and update machinary
+  * ubuntu: AUFS -- update to 7b136a27b021da9010d8b6c101939dd298e46be7
+  * ubuntu: aufs3 -- enable
+  * ubuntu: aufs3 -- update configs
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 02 Jan 2014 09:41:02 +0000
+
+linux (3.13.0-0.12) trusty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 31 Dec 2013 06:16:03 -0700
+
+linux (3.13.0-0.11) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: suspicious unlocked ->status reading and writing in ipc/sem.c
+  * [Config] ppc64el -- initial defconfig based -generic flavour
+  * [Config] initial defconfig for ppc64el
+  * [Config] ubuntuise ppc64el config
+  * [Config] ubuntuise ppc64el config part 2
+  * [Config] d-i -- update empty udebs list
+  * [Config] ppc64el -- split extras package
+
+  [ Anton Blanchard ]
+
+  * SAUCE: KVM: PPC: Book3S HV: Add little-endian guest support
+
+  [ Benjamin Herrenschmidt ]
+
+  * SAUCE: powerpc/powernv: Add calls to support little endian
+
+  [ Cédric Le Goater ]
+
+  * SAUCE: KVM: PPC: Book3S: add helper routine to load guest instructions
+  * SAUCE: KVM: PPC: Book3S: add helper routines to detect endian order
+  * SAUCE: KVM: PPC: Book3S: MMIO emulation support for little endian
+    guests
+
+  [ Paul E. McKenney ]
+
+  * SAUCE: powerpc: Make 64-bit non-VMX copy_tofrom_user() bi-endian
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 27 Dec 2013 16:48:55 +0000
+
+linux (3.13.0-0.10) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.13-rc5
+  * [Config] updateconfigs following rebase to v3.13-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc5
+    - LP: #1260303
+    - LP: #1260303
+    - LP: #1260225
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 23 Dec 2013 12:48:28 +0000
+
+linux (3.13.0-0.9) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] d-i -- allow missing firmware
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 20 Dec 2013 17:57:06 +0000
+
+linux (3.13.0-0.8) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] annotations -- first pass over entire config
+  * [Config] drop libunwind8-dev from Build-Depends for ppc64el
+
+  [ Tim Gardner ]
+
+  * [Config] Add arm64 device tree files
+    - LP: #1262901
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 19 Dec 2013 18:36:43 +0000
+
+linux (3.13.0-0.7) trusty; urgency=low
+
+  [ Rajesh B Prathipati ]
+
+  * SAUCE: powerpc: Make unaligned accesses endian-safe for powerpc
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_REGULATOR_S2MPS11=n for FTBS
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc4
+    - LP: #1259790
+    - LP: #1259437
+    - LP: #1259435
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 13 Dec 2013 07:56:34 -0700
+
+linux (3.13.0-0.6) trusty; urgency=low
+
+  [ Paolo Pisati ]
+
+  * [Config] armhf: arm64: VIRTIO_[BLK|MMIO|NET|CONSOLE|BALLOON]=y
+  * [Config] i386: amd64: VIRTIO_CONSOLE=y
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 08 Dec 2013 09:22:01 -0700
+
+linux (3.13.0-0.5) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * correct bug listing for v3.13-rc2 rebase
+  * [Config] ppc64el -- create linux-libc-dev
+  * [Debian] Improve tools version message
+    - LP: #1257715
+
+  [ Serge Hallyn ]
+
+  * SAUCE: fork: Allow CLONE_PARENT after setns(CLONE_NEWPID)]
+    - LP: #1248590
+  * SAUCE: vfs: Fix a regression in mounting proc
+
+  [ Tim Gardner ]
+
+  * [Config] Build-in ohci-pci
+    - LP: #1244176
+  * Rebase to v3.13-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Revert "fork: unify and tighten up CLONE_NEWUSER/CLONE_NEWPID
+    checks""
+    - LP: #1248590
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc3
+    - LP: #1256840
+    - LP: #1256212
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sat, 07 Dec 2013 07:55:39 -0700
+
+linux (3.13.0-0.4) trusty; urgency=low
+
+  [ Tim Gardner ]
+
+  * Rebase to v3.13-rc2
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.13-rc2
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 29 Nov 2013 23:54:05 -0500
+
+linux (3.13.0-0.3) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: Fix DocBook FTBS"
+
+  [ Tim Gardner ]
+
+  * [Debian] Re-sign modules after debug objcopy
+    - LP: #1253155
+  * [Config] CONFIG_EXT4_USE_FOR_EXT23=y
+
+  [ Upstream Kernel Changes ]
+
+  * doc: fix generation of device-drivers
+  * rebase to b975dc3689fc6a3718ad288ce080924f9cb7e176
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 26 Nov 2013 12:24:42 -0700
+
+linux (3.13.0-0.2) trusty; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: Fix DocBook FTBS
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 25 Nov 2013 13:24:15 -0700
+
+linux (3.13.0-0.1) trusty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 7e3528c3660a2e8602abc7858b0994d611f74bc3
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 12 Nov 2013 07:28:53 -0700
+
+linux (3.13.0-0.0) trusty; urgency=low
+
+  * Major release bump.
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 12 Nov 2013 21:37:52 +0000
+
+linux (3.12.0-2.7) trusty; urgency=low
+
+  * Fixed armhf ABI build failure.
+  * Release tracker
+    - LP: #1249477
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 08 Nov 2013 16:22:45 -0700
+
+linux (3.12.0-2.6) trusty; urgency=low
+
+  [ Joseph Salisbury ]
+
+  * SAUCE: tg3: Add support for new 57786 device id.
+    - LP: #1242610
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_OABI_COMPAT=n
+  * [Config] add the wandboard to shipped dtb
+    - LP: #1249421
+  * Release tracker
+    - LP: #1249477
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 08 Nov 2013 12:23:18 -0700
+
+linux (3.12.0-2.5) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to mainline v3.12
+  * [Config] updateconfigs following rebase to v3.12
+  * postinst -- improve relative symlink detection with missing files
+    - LP: #1248053
+  * postinst -- fix unchanged link detection
+  * [Config] update configs following addition of apparmor fixes
+
+  [ Anthony Wong ]
+
+  * SAUCE: Work around broken ACPI backlight on Dell Inspiron 5537
+    - LP: #1231305
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 - alpha 4 snapshot
+  * SAUCE: apparmor: fix unix domain sockets to be mediated on connection
+    - LP: #1208988
+  * SAUCE: apparmor: allocate path lookup buffers during init
+    - LP: #1208988
+
+  [ Tim Gardner ]
+
+  * [Config] Remove superfluous ubuntu/lttng-modules
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "fork: unify and tighten up CLONE_NEWUSER/CLONE_NEWPID checks"
+    - LP: #1248590
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.12
+    - LP: #1222850
+
+  [ Adam Conrad ]
+  * etc/getabis: Fetch arm64/generic abis as well
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 06 Nov 2013 21:00:21 +0000
+
+linux (3.12.0-1.3) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] arm64 -- add arch to the configuration handlers
+  * [Config] arm64 -- add generic flavour
+  * [Config] arm64 -- default config
+  * [Config] arm64 -- fix up various FTBFS config options
+  * SAUCE: arm64: export __copy_in_user to modules
+  * [Config] arm64 -- disable ABI/module checks
+  * [Config] arm64 -- enforcer -- add arm64 to the enforcer
+  * [Config] arm64 -- enable udebs for arm64
+
+  [ Colin Watson ]
+
+  * [Config] Clean up various udeb Provides
+
+  [ Paolo Pisati ]
+
+  * [Config] AHCI_IMX=y
+  * [Config] build imx*-wandboard dtbs
+
+  [ Serge Hallyn ]
+
+  * SAUCE: device_cgroup: remove can_attach
+
+  [ Tim Gardner ]
+
+  * rebase to v3.12-rc7
+  * SAUCE: KVM: Fix modprobe failure for kvm_intel/kvm_amd
+  * Release tracker
+    - LP: #1245932
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.12-rc7
+    - LP: #1180881
+    - LP: #1180881
+    - LP: #1217957
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 27 Oct 2013 22:08:55 -0600
+
+linux (3.12.0-0.2) trusty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) scsi: hyper-v storage -- mark as preferring READ
+    CAPACITY (16) at SPC-2"
+  * Revert "SAUCE: (no-up) scsi: hyper-v storage -- mark as VPD capable at
+    SPC-2"
+  * Revert "SAUCE: (no-up) scsi: add scsi device flag to request READ
+    CAPACITY (16) be preferred"
+  * Revert "SAUCE: (no-up) scsi: add scsi device flag to request VPD pages
+    be used at SPC-2"
+  * Revert "overlayfs: Update to v19"
+  * Revert "ubuntu: overlayfs v18 -- -- overlayfs: implement show_options"
+  * Revert "ubuntu: overlayfs v18 -- -- overlayfs: add statfs support"
+  * Revert "ubuntu: overlayfs v18 -- -- overlay filesystem"
+  * Revert "ubuntu: overlayfs v18 -- -- vfs: introduce
+    clone_private_mount()"
+  * Revert "ubuntu: overlayfs v18 -- -- vfs: export do_splice_direct() to
+    modules"
+  * Revert "ubuntu: overlayfs v18 -- -- overlay: overlay filesystem
+    documentation"
+  * ubuntu: overlayfs v20 -- overlayfs: add statfs support
+  * [Config] fix linux-libc-dev generation for arm64
+  * [Config] fix linux-libc-dev generation for x32
+  * [Config] add linux-libc-dev generation for ppc64el
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs v20 -- overlayfs: implement show_options
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs v20 -- vfs: add i_op->dentry_open()
+  * ubuntu: overlayfs v20 -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs v20 -- vfs: export __inode_permission() to modules
+  * ubuntu: overlayfs v20 -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs v20 -- overlay filesystem
+  * ubuntu: overlayfs v20 -- fs: limit filesystem stacking depth
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs v20 -- overlay: overlay filesystem documentation
+
+  [ Paolo Pisati ]
+
+  * [Config] arm: VIRTIO_[BLK|NET|MMIO]=y
+
+  [ Seth Forshee ]
+
+  * SAUCE: (no-up) ACPI: Disable Windows 8 compatibility for some Lenovo
+    ThinkPads
+    - LP: #1183856
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_CRYPTO_CRCT10DIF=y, CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m
+  * rebase to v3.12-rc2
+  * updateconfigs
+  * [Config] disable CONFIG_FB_VESA enforcer check
+  * [Config] Disable lttng for FTBS
+  * rebase to v3.12-rc3
+  * rebase to v3.12-rc4
+  * [Config] CONFIG_ANDROID=n
+    - LP: #1235161
+  * [Config] CONFIG_L2TP_V3=y
+    - LP: #1235914
+  * [Config] CONFIG_USB_OTG=n for all arches
+  * Release tracker
+    - LP: #1242811
+
+  [ Upstream Kernel Changes ]
+
+  * scsi: hyper-v storsvc switch up to SPC-3
+
+  * rebase to v3.12-rc6
+    - LP: #1235977
+    - LP: #1235523
+    - LP: #1239392
+    - LP: #1227491
+
+  * rebase to v3.12-rc3
+    - LP: #1231931
+
+  * rebase to v3.12-rc2
+    - LP: #1213820
+    - LP: #1213055
+    - LP: #1198030
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 23 Sep 2013 07:41:07 -0600
+
+linux (3.11.0-8.15) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * Release tracker
+    - LP: #1227969
+
+  * Update lttng
+    Updated to git://git.lttng.org/lttng-modules.git 9998f5216f4641a79e158135
+    Version 2.3.0+
+
+  [ Upstream Kernel Changes ]
+
+  * igb: Add additional get_phy_id call for i354 devices
+    - LP: #1219619
+  * igb: Read flow control for i350 from correct EEPROM section
+    - LP: #1219619
+  * timekeeping: Fix HRTICK related deadlock from ntp lock changes
+    Required for lttng update.
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 19 Sep 2013 07:41:49 -0600
+
+linux (3.11.0-7.14) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] sort out linux-tools naming
+    - LP: #1205284
+  * [Packaging] linux-tools: switch to common generic version helper
+
+  [ Paolo Pisati ]
+
+  * [Config] highbank: ecx1000: CPU_IDLE causes instabilities, disable it
+
+  [ Tim Gardner ]
+
+  * Release tracker
+    - LP: #1226160
+
+  [ Tony Lindgren ]
+
+  * SAUCE: ARM: dts: Fix muxing and regulator for wl12xx on the SDIO bus
+    for pandaboard
+
+  [ Upstream Kernel Changes ]
+
+  * USB: handle LPM errors during device suspend correctly
+    - LP: #1011415
+  * usb: don't check pm qos NO_POWER_OFF flag in usb_port_suspend()
+    - LP: #1011415
+  * usb: Don't fail port power resume on device disconnect.
+    - LP: #1011415
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.11.1
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 11 Sep 2013 07:30:17 -0600
+
+linux (3.11.0-7.13) saucy; urgency=low
+
+  * Release tracker
+    - LP: #1223545
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: (no-up) scsi: add scsi device flag to request VPD pages be used at SPC-2
+    - LP: #1223499
+  * SAUCE: (no-up) scsi: add scsi device flag to request READ CAPACITY (16) be preferred
+    - LP: #1223499
+  * SAUCE: (no-up) scsi: hyper-v storage -- mark as VPD capable at SPC-2
+    - LP: #1223499
+  * SAUCE: (no-up) scsi: hyper-v storage -- mark as preferring READ CAPACITY (16) at SPC-2
+    - LP: #1223499
+
+  [ Maximiliano Curia ]
+
+  * SAUCE: (no-up) Only let characters through when there are active readers.
+    - LP: #1208740
+
+  [ Tim Gardner ]
+
+  * [Debian] getabis: Commit new ABI directory, remove the old
+  * [Config] CONFIG_EFIVAR_FS=y
+    - LP: #1223195
+  * [Config] CONFIG_EFI_VARS_PSTORE=m,
+    CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE=n
+  * SAUCE: (no-up) USB: input: cm109.c: Convert high volume dev_err() to dev_err_ratelimited()
+    - LP: #1222850
+
+  [ Upstream Kernel Changes ]
+
+  * Intel xhci: refactor EHCI/xHCI port switching
+    - LP: #1210858
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 10 Sep 2013 09:00:19 -0600
+
+linux (3.11.0-6.12) saucy; urgency=low
+
+  * Release tracker
+    - LP: #1222893
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: (no-squash) AUFS3 -- aufs3-standalone.patch"
+  * Revert "ubuntu: (no-squash) AUFS3 -- aufs3-base.patch"
+  * ubuntu: (no-squash) AUFS3 -- aufs3-base.patch
+  * ubuntu: (no-squash) AUFS3 -- aufs3-standalone.patch
+    - LP: #1222407
+
+  [ Paolo Pisati ]
+
+  * [Config] restore mmc boot on panda
+
+  [ Tyler Hicks ]
+
+  * SAUCE: apparmor: Use shash crypto API interface for profile hashes
+    - LP: #1216294
+
+  [ Upstream Kernel Changes ]
+
+  * net: calxedaxgmac: remove NETIF_F_FRAGLIST setting
+  * net: calxedaxgmac: read correct field in xgmac_desc_get_buf_len
+  * net: calxedaxgmac: fix race between xgmac_tx_complete and xgmac_tx_err
+  * net: calxedaxgmac: fix possible skb free before tx complete
+  * net: calxedaxgmac: update ring buffer tx_head after barriers
+  * net: calxedaxgmac: fix race with tx queue stop/wake
+  * net: calxedaxgmac: enable interrupts after napi_enable
+  * net: calxedaxgmac: fix various errors in xgmac_set_rx_mode
+  * net: calxedaxgmac: remove some unused statistic counters
+  * net: calxedaxgmac: fix rx DMA mapping API size mismatches
+  * net: calxedaxgmac: fix xgmac_xmit DMA mapping error handling
+  * mfd: rtsx: Read vendor setting from config space
+    - LP: #1201698
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 09 Sep 2013 07:21:06 -0600
+
+linux (3.11.0-5.11) saucy; urgency=low
+
+  * Release tracker
+    - LP: #1221886
+
+  [ Adam Lee ]
+
+  * SAUCE: Bluetooth: Add support for 04ca:2007
+    - LP: #1153448
+  * SAUCE: Bluetooth: Add support for 105b:e065
+    - LP: #1161261
+
+  [ Gavin Guo ]
+
+  * SAUCE: Bluetooth: Add support for Broadcom 413c:8143
+    - LP: #1166113
+
+  [ Upstream Kernel Changes ]
+
+  * igb: Reset the link when EEE setting changed
+    - LP: #1219619
+  * igb: Read register for latch_on without return value
+    - LP: #1219619
+  * igb: Added rcu_lock to avoid race
+    - LP: #1219619
+  * igb: don't allow SR-IOV without MSI-X
+    - LP: #1219619
+  * igb: Update MTU so that it is always at least a standard frame size
+    - LP: #1219619
+  * igb: Refactor of init_nvm_params
+    - LP: #1219619
+  * igb: Refactor NVM read functions to accommodate devices with no flash
+    - LP: #1219619
+  * igb: Add device support for flashless SKU of i210 device
+    - LP: #1219619
+  * igb: Fix get_fw_version function for all parts
+    - LP: #1219619
+  * igb: Add macro for size of RETA indirection table
+    - LP: #1219619
+  * igb: Expose RSS indirection table for ethtool
+    - LP: #1219619
+  * igb: Don't look for a PBA in the iNVM when flashless
+    - LP: #1219619
+  * igb: Implementation of 1-sec delay for i210 devices
+    - LP: #1219619
+  * igb: New PHY_ID for i354 device
+    - LP: #1219619
+  * igb: M88E1543 PHY downshift implementation
+    - LP: #1219619
+  * igb: No PHPM support in i354 devices
+    - LP: #1219619
+  * igb: Support to get 2_5G link status for appropriate media type
+    - LP: #1219619
+  * igb: Get speed and duplex for 1G non_copper devices
+    - LP: #1219619
+  * igb: Implementation to report advertised/supported link on i354 devices
+    - LP: #1219619
+  * igb: Update version number
+    - LP: #1219619
+  * Bluetooth: Take proper tty_struct references
+    - LP: #1189998
+  * Bluetooth: Remove the device from the list in the destructor
+    - LP: #1189998
+  * Bluetooth: Move the tty initialization and cleanup out of open/close
+    - LP: #1189998
+  * Bluetooth: Implement .activate, .shutdown and .carrier_raised methods
+    - LP: #1189998
+  * Bluetooth: Fix the reference counting of tty_port
+    - LP: #1189998
+  * Bluetooth: Purge the dlc->tx_queue to avoid circular dependency
+    - LP: #1189998
+
+  [ Wen-chien Jesse Sung ]
+
+  * SAUCE: Bluetooth: Support for loading broadcom patchram firmware
+    - LP: #1065400
+  * SAUCE: Bluetooth: Add support for 13d3:3388 and 13d3:3389
+    - LP: #1065400
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 05 Sep 2013 08:06:17 -0600
+
+linux (3.11.0-5.10) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release tracker
+    - LP: #1220222
+  * Revert "[Config] Fix ubuntu directoy Kbuilds"
+  * Revert "aufs update dropped some Kbuild files"
+  * Revert "ubuntu: AUFS -- follow rename of loop.h into drivers/block"
+  * Revert "ubuntu: AUFS -- update to
+    8e503d4142c189ed6c47a2177ad2cd058e8d340e"
+  * Revert "ubuntu: (no-squash) AUFS3 -- aufs3-standalone.patch"
+  * Revert "ubuntu: (no-squash) AUFS3 -- aufs3-base.patch"
+  * rebase to v3.11 final
+  * [Config] clean up ubuntu/Kconfig and ubuntu/Makefile
+  * ubuntu: AUFS (no-squash): basic framework and update machinary
+  * ubuntu: (no-squash) AUFS3 -- aufs3-base.patch
+  * ubuntu: (no-squash) AUFS3 -- aufs3-standalone.patch
+  * ubuntu: AUFS -- update to 5ac5fe26a90a818218310e208d17688fddb07622
+  * ubuntu: (no-squash) AUFS -- enable aufs
+  * ubuntu: AUFS -- fix remaining d_count references to use accessor
+  * ubuntu: lttng -- follow rename of pid_ns
+  * SAUCE: disable stack-protector for ARM compressed bootloader
+
+  [ Paolo Pisati ]
+
+  * [Config] ARM_ATAG_DTB_COMPAT=y
+
+  [ Rob Herring ]
+
+  * [Config] Enable KVM and virtio for armhf generic-lpae
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_ARPD=y
+  * [Config] CONFIG_ZSWAP=y
+    - LP: #1215379
+
+  [ Upstream Kernel Changes ]
+
+  * uvcvideo: quirk PROBE_DEF for Dell SP2008WFP monitor.
+    - LP: #1217957
+  * ARM: use phys_addr_t for DMA zone sizes
+  * ARM: highbank: enable DMA zone for LPAE
+  * ARM: highbank: select ARCH_HAS_HOLES_MEMORYMODEL
+  * ARM: highbank: select required errata work-arounds
+  * DMA: fix AMBA PL08x compilation issue with 64bit DMA address type
+  * DMA: fix printk warning in AMBA PL08x DMA driver
+  * ARM: highbank: select ARCH_DMA_ADDR_T_64BIT for LPAE
+  * ARM: move outer_cache declaration out of ifdef
+  * ARM: highbank: avoid L2 cache smc calls when PL310 is not present
+  * ARM: highbank: clean-up some unused includes
+  * ARM: xen: only set pm function ptrs for Xen guests
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.11
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 03 Sep 2013 17:08:06 +0100
+
+linux (3.11.0-4.9) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v3.11-rc7
+  * Release tracker
+    - LP: #1216962
+
+  [ Upstream Kernel Changes ]
+
+  * mwifiex: do not create AP and P2P interfaces upon driver loading
+    - LP: #1212720
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 26 Aug 2013 06:25:35 -0600
+
+linux (3.11.0-3.8) saucy; urgency=low
+
+  [ Johannes Berg ]
+
+  * SAUCE: mac80211: ignore (E)CSA in probe response frames
+    - LP: #1201470
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 23 Aug 2013 09:47:36 -0600
+
+linux (3.11.0-3.7) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: (no-up) hv_vss_daemon -- prevent self-daemonising to allow
+    upstart to track
+  * SAUCE: (no-up) hv -- bodge hv_vss_daemon so it can use the local
+    linux/hyperv.h
+  * SAUCE: hv: Add vss daemon to Makefile
+  * [Debian] Add hv_vss_daemon to tools package
+    - LP: #1213282
+  * [Config] Fix ubuntu directoy Kbuilds
+    - LP: #1181755
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 20 Aug 2013 08:34:05 -0600
+
+linux (3.11.0-3.6) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] tools: conditionalise x86 and hyper-v tools sensibly
+  * [Config] tools: enable x86 and hyper-v
+
+  [ John Johansen ]
+
+  * Revert "SAUCE: (no-up) apparmor: Sync to apparmor 3 dev stable
+    snapshot"
+  * Revert "SAUCE: (no-up) apparmor: fix apparmor module status for none
+    root users"
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 - alpha 4 snapshot
+
+  [ Joseph Salisbury ]
+
+  * SAUCE: (no-up) intel_ips: blacklist ASUSTek G60JX laptops
+    - LP: #1210848
+
+  [ Kamal Mostafa ]
+
+  * [debian] tools: ship 'cpupower' in linux-tools
+    - LP: #1158668
+  * [Config] Build-dep on libpci-dev for cpu tools
+    - LP: #1158668
+
+  [ Tim Gardner ]
+
+  * rebase to v3.11-rc6
+  * Release tracker
+    - LP: #1213941
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 16 Aug 2013 07:02:07 -0600
+
+linux (3.11.0-2.5) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_PM_DEBUG=y
+    - LP: #1210539
+  * rebase to v3.11-rc5
+  * Release tracker
+    - LP: #1211378
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 12 Aug 2013 06:10:39 -0600
+
+linux (3.11.0-1.4) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * Bump ABI when making changes to the inclusion list lest
+    you cause conflicts with existing installed kernel
+    packages.
+    - LP: #1210331
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 09 Aug 2013 03:03:51 +0100
+
+linux (3.11.0-0.3) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Include rbd and kvm in the virtual inclusion list
+    - LP: #1206961
+  * [Config] Removed obsolete inclusion list entries
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 06 Aug 2013 08:52:14 +0100
+
+linux (3.11.0-0.2) saucy; urgency=low
+
+  [ Bruce Allan ]
+
+  * SAUCE: (no-up) e1000e: fix I217/I218 PHY initialization flow
+    - LP: #1206757
+  * SAUCE: (no-up) e1000e: enable support for new device IDs
+    - LP: #1206757
+
+  [ John Johansen ]
+
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 dev stable snapshot
+
+  [ Paolo Pisati ]
+
+  * build vexpress a15 dtb
+  * [Config] disable Broadcom bcm support (ARCH_BCM)
+  * [Config] disable Allwinner a1x support (ARCH_SUNXI)
+  * [Config] disable WonderMedia WM8850 support (ARCH_WM8850)
+  * [Config] disable Rockchip support (ARCH_ROCKCHIP)
+  * [Config] disable STMicroelectronics STiH41x SOCs (ARCH_STI)
+  * [Config] disable TI Keystone, AM43xx and OMAP5 support
+  * [Config] ARM_APPENDED_DTB=y
+
+  [ Tim Gardner ]
+
+  * rebase to v3.11-rc4
+  * overlayfs: Update to v19
+  * [Config] Enable overlayfs
+  * SAUCE: Fix lttng compile errors
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.11-rc4
+    - LP: #1163720
+    - LP: #1162026
+    - LP: #1195636
+    - LP: #1195597
+    - LP: #1180409
+    - LP: #1168430
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Sun, 04 Aug 2013 03:45:31 -0600
+
+linux (3.11.0-0.1) saucy; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 64ccccf8525fee499625b517c0faadf784c79e93
+    - LP: #1163720
+    - LP: #1162026
+    - LP: #1195636
+    - LP: #1195597
+    - LP: #1180409
+    - LP: #1168430
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 08 Jul 2013 08:50:46 -0600
+
+linux (3.10.0-2.10) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_INTEL_MEI*=m
+    - LP: #1196155
+  * [Config] CONFIG_DEBUG_INFO=y
+
+  [ Stephen Warren ]
+
+  * [Config] fix Calxeda xgmac module filename
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "serial: 8250_pci: add support for another kind of NetMos
+    Technology PCI 9835 Multi-I/O Controller"
+    - LP: #1190967
+  * mfd: lpc_ich: Add support for Intel Avoton SoC
+    - LP: #1196658
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Jul 2013 18:08:02 +0100
+
+linux (3.10.0-2.9) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.10
+
+  [ John Johansen ]
+
+  * Revert "SAUCE: (no-up) apparmor: Fix quieting of audit messages for
+    network mediation"
+  * Revert "SAUCE: (no-up) apparmor: Fix compile warnings"
+  * Revert "SAUCE: (no-up) AppArmor: basic networking rules"
+  * Revert "SAUCE: (no-up) apparmor: Add the ability to mediate mount"
+  * Revert "SAUCE: (no-up) AppArmor: Add profile introspection file to
+    interface"
+  * Revert "SAUCE: (no-up) AppArmor: Disable Add PR_{GET,SET}_NO_NEW_PRIVS
+    to prevent execve from granting privs"
+  * SAUCE: (no-up) apparmor: Sync to apparmor 3 dev stable snapshot
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 01 Jul 2013 17:42:29 +0100
+
+linux (3.10.0-1.8) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Release Tracking Bug
+    - LP: #1195717
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: overlayfs -- follow change to do_splice_direct
+    interface"
+  * Revert "ubuntu: overlayfs -- expose do_splice_direct prototype"
+  * Revert "SAUCE: ubuntu: overlayfs -- ovl_path_open should not take path
+    reference"
+  * Revert "ubuntu: overlayfs -- add FS_ALIAS"
+  * Revert "ubuntu: overlayfs --
+    overlayfs-copy-up-i_uid-i_gid-from-the-underlying-inode"
+  * Revert "ubuntu: overlayfs -- ovl-switch-to-inode_permission"
+  * Revert "ubuntu: overlayfs -- vfs-export-inode_permission-to-modules"
+  * Revert "ubuntu: overlayfs -- overlayfs-create-new-inode-in-ovl_link"
+  * Revert "ubuntu: overlayfs --
+    overlayfs-fix-possible-leak-in-ovl_new_inode"
+  * Revert "ubuntu: overlayfs -- fs-limit-filesystem-stacking-depth"
+  * Revert "ubuntu: overlayfs -- overlay-overlay-filesystem-documentation"
+  * Revert "ubuntu: overlayfs -- overlayfs-implement-show_options"
+  * Revert "ubuntu: overlayfs -- overlayfs-add-statfs-support"
+  * Revert "ubuntu: overlayfs -- overlay filesystem"
+  * Revert "ubuntu: overlayfs -- vfs-introduce-clone_private_mount"
+  * Revert "ubuntu: overlayfs -- vfs-export-do_splice_direct-to-modules"
+  * Revert "ubuntu: overlayfs -- vfs-add-i_op-dentry_open"
+  * ubuntu: overlayfs v18 -- -- overlayfs: add statfs support
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs v18 -- -- overlayfs: implement show_options
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs v18 -- -- vfs: add i_op->dentry_open()
+  * ubuntu: overlayfs v18 -- -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs v18 -- -- vfs: export __inode_permission() to modules
+  * ubuntu: overlayfs v18 -- -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs v18 -- -- overlay filesystem
+  * ubuntu: overlayfs v18 -- -- fs: limit filesystem stacking depth
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs v18 -- -- overlay: overlay filesystem documentation
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_SUNRPC_DEBUG=y
+    - LP: #1127319
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 28 Jun 2013 10:26:52 +0100
+
+linux (3.10.0-0.7) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * autopkgtest: switch Depends: to build-essential
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 25 Jun 2013 08:40:55 +0100
+
+linux (3.10.0-0.6) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_ARCH_TEGRA to fix FTBFS on armhf
+  * SAUCE: ubuntu: overlayfs -- ovl_path_open should not take path reference
+    - LP: #1098378
+  * ubuntu: AUFS -- update to 4f14cef47eb7c23eda7198931fbab1040866b6ee
+  * ubuntu: overlayfs -- expose do_splice_direct prototype
+  * ubuntu: overlayfs -- follow change to do_splice_direct interface
+  * [Config] flip CONFIG_NO_HZ_FULL_ALL off as it is overheating machines
+    - LP: #1192691
+
+  [ Stefan Bader ]
+
+  * (d-i) Add dm-snapshot to md-modules
+    - LP: #1191726
+
+  [ Tim Gardner ]
+
+  * Release tracker
+    - LP: #1194149
+  * [Config] CONFIG_WIL6210=n for armhf
+  * [Config] d-i: Add calxedaxgmac to nic-modules
+    - LP: #1192358
+  * [debian] Use dh_strip
+    - LP: #1192759
+  * [Config] Enable perf for armhf
+  * do_tools=false when cross compiling
+  * [Config] CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+    - LP: #1108082
+
+  [ Upstream Kernel Changes ]
+
+  * nsp32: switch reset delay to msleep() as it is tooo long
+  * alx: add a simple AR816x/AR817x device driver
+    Plucked from linux-next. replaces ubuntu/alx in favor of
+    'to be merged' version in 3.11.
+  * rebase to v3.10-rc7
+    - LP: #1189363
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sat, 22 Jun 2013 18:10:31 -0600
+
+linux (3.10.0-0.5) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.10-rc6
+  * [Config] updateconfigs following rebase to v3.10-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc6
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 17 Jun 2013 11:12:39 +0100
+
+linux (3.10.0-0.4) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] updateconfigs following rebase to v3.10-rc4
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 10 Jun 2013 11:42:28 +0100
+
+linux (3.10.0-0.3) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.10-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc5
+    - LP: #1186170
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 10 Jun 2013 09:23:31 +0100
+
+linux (3.10.0-0.2) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.10-rc4
+  * [Config] CONFIG_BINFMT_SCRIPT=y to fix booting initramfs scripts
+  * [Config] enable SND_PCM_DEBUG SND_PCM_XRUN_DEBUG
+    - LP: #1187744
+  * [Config] enforce CONFIG_BINFMT_SCRIPT=y
+
+  [ Dave Chiluk ]
+
+  * SAUCE: ncpfs: fix rmdir returns Device or resource busy
+    - LP: #1035226
+
+  [ Tim Gardner ]
+
+  * rebase to v3.10-rc3
+  * [Config] sparc be gone
+  * [Config] ia64 be gone
+  * d-i: block-modules provides nbd-modules
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc4
+  * rebase to v3.10-rc3
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 28 May 2013 06:16:46 -0600
+
+linux (3.10.0-0.1) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * UBUNTU: Disabled lttng
+  * UBUNTU: Disable aufs for FTBS
+  * UBUNTU: Disabled alx
+  * UBUNTU: alx: rename NETIF_F_HW_VLAN_* feature flags to NETIF_F_HW_VLAN_CTAG_*
+  * UBUNTU: rebase to v3.10-rc2
+  * UBUNTU: SAUCE: uvcvideo: quirk PROBE_DEF for Alienware X51 OmniVision webcam
+
+  [ Andy Whitcroft ]
+
+  * UBUNTU: [Config] update standards version to 3.9.4.0
+  * UBUNTU: [Config] squash duplicate package description (long and short)
+  * UBUNTU: [Config] fix up Vcs-git: to point to saucy
+  * UBUNTU: [Config] drop depenancy on util-linux as is Essential
+  * UBUNTU: [Config] drop redundant Build-Conficts:
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc2
+    - LP: #1180351
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.10-rc1
+    - LP: #1172151
+    - LP: #1089795
+    - LP: #1167270
+    - LP: #1128840
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 14 May 2013 13:41:07 -0600
+
+linux (3.10.0-0.0) saucy; urgency=low
+
+  * Dummy
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 09 May 2013 20:30:40 +0100
+
+linux (3.9.0-2.6) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v3.9.2
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 09 May 2013 20:30:40 +0100
+
+linux (3.9.0-1.5) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * rebase to v3.9.1
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Wed, 08 May 2013 12:49:45 -0400
+
+linux (3.9.0-0.4) saucy; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: overlayfs -- add FS_ALIAS
+
+  [ Tim Gardner ]
+
+  * Added lttng
+    - LP: #1175784
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 02 May 2013 17:17:13 -0400
+
+linux (3.9.0-0.3) saucy; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 29 Apr 2013 18:20:00 -0400
+
+linux (3.9.0-0.2) saucy; urgency=low
+
+  [ Tim Gardner ]
+
+  * Enable extras packaging for amd64/i386.
+    Fixes build depenencies with brittany and linux-meta.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 29 Apr 2013 05:37:01 -0600
+
+linux (3.9.0-0.1) saucy; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc8
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc7
+    - LP: #1128840
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc4
+    - LP: #1095315
+    - LP: #886975
+    - LP: #1086921
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc3
+    - LP: #1155016
+    - LP: #1103594
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc2
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.9-rc1
+    - LP: #901105
+    - LP: #961286
+    - LP: #1011792
+    - LP: #1128934
+    - LP: #886975
+    - LP: #978807
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 20 Feb 2013 09:12:39 -0700
+
+linux (3.8.0-7.14) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_RCU_USER_QS=n
+  * [Config] CONFIG_MTD_ONENAND_SIM=n
+  * annotations: add annotations for CONFIG_CC_STACKPROTECTOR
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1130111
+  * UBUNTU: SAUCE: rt2x00: rt2x00pci_regbusy_read() - only print register access failure once
+    - LP: #1128840
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 18 Feb 2013 09:25:56 -0700
+
+linux (3.8.0-6.13) raring; urgency=low
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1125364
+  * Add ahci modules to d-i
+    - LP: #1124415
+
+
+  [ Chris Wilson ]
+
+  * SAUCE: drm/i915: Wait for pending flips to complete before tearing down
+    the encoders
+    - LP: #1097315
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 13 Feb 2013 12:16:48 -0700
+
+linux (3.8.0-6.12) raring; urgency=low
+
+  [Tim Gardner]
+
+  * perf: NO_LIBPERL=1
+  * Fix linux-headers dependency
+  * Release Tracking Bug
+    - LP: #1124362
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_AUFS_EXPORT to allow nfs exports
+    - LP: #1121699
+
+  [ Daniel Vetter ]
+
+  * SAUCE: drm/i915: write backlight harder
+    - LP: #954661
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 13 Feb 2013 10:25:11 -0700
+
+linux (3.8.0-6.11) raring; urgency=low
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1122071
+  * rebase to v3.8-rc7
+  * Add libaudit-dev as a build dependency
+  * Build perf with NO_LIBPYTHON=1 to avoid a python build dependency.
+
+  [ Leann Ogasawara ]
+
+  * [Config] Remove CONFIG_SATA_AHCI annotation
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Fri, 08 Feb 2013 07:41:13 -0500
+
+linux (3.8.0-5.10) raring; urgency=low
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1118568
+
+  * Bump ABI to fix install issue with 3.8.0-4.8.
+    Moving drivers/ata/*ahci* to linux-image caused an
+    install conflict with linux-image-extras without an
+    ABI bump.
+
+  [ Jan Beulich ]
+
+  * SAUCE: xen-pciback: rate limit error messages from
+    xen_pcibk_enable_msi{, x}()
+    - LP: #1117336
+    - CVE-2013-0231
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 07 Feb 2013 05:38:12 -0700
+
+linux (3.8.0-4.9) raring; urgency=low
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * d-i: Add mellanox ethernet drivers to nic-modules
+    - LP: #1015339
+
+  [ Joseph Salisbury ]
+
+  * SAUCE: ACPI: Add DMI entry for Sony VGN-FW41E_H
+    - LP: #1113547
+
+  [ Kamal Mostafa ]
+
+  * SAUCE: alx driver import script
+
+  [ Qualcomm Atheros, Inc ]
+
+  * SAUCE: alx: Update to heads/master
+
+  [ Tim Gardner ]
+
+  * Release Tracking Bug
+    - LP: #1117673
+
+  * [debian] Remove dangling symlink from headers package
+    - LP: #1112442
+  * [config] CONFIG_ALX=m
+  * [Config] Add alx to d-i nic-modules
+  * [Config] CONFIG_SATA_AHCI=m
+    - LP: #1056563
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 05 Feb 2013 05:54:32 -0800
+
+linux (3.8.0-4.8) raring; urgency=low
+
+  [ Allen Ibara ]
+
+  * SAUCE: imx6: dts: Add IMX6Q AHCI support
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.8-rc6
+  * updateconfigs following rebase to v3.8-rc6
+
+  [Leann Ogasawara]
+
+  * Release Tracking Bug
+    - LP: #1112573
+
+  [ Paolo Pisati ]
+
+  * SAUCE: imx6: enable sata clk if SATA_AHCI_PLATFORM
+  * [Config] SERIAL_AMBA_PL011=y (vexpress serial console)
+  * [Config] MMC_ARMMMCI=y (vexpress mmc)
+  * [Config] FB_ARMCLCD=y (vexpress framebuffer)
+
+  [ Seth Forshee ]
+
+  * [Config] CONFIG_MAC80211_MESSAGE_TRACING=y
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc6
+    - LP: #1107477
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 01 Feb 2013 07:20:59 -0800
+
+linux (3.8.0-3.7) raring; urgency=low
+
+  [ Andy Green ]
+
+  * SAUCE: ARM: OMAP2+: add cpu id register to MAC address helper
+  * SAUCE: ARM: omap2 add mac address allocation register api
+  * SAUCE: ARM: omap2 panda register ethernet and wlan for automatic mac
+    allocation
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.8-rc5
+  * Release Tracking Bug
+    - LP: #1111486
+
+  [ Paolo Pisati ]
+
+  * SAUCE: davinci: vpss: compilation fix
+  * [Config] enable TI OMAP4 support (Pandaboard/ES)
+  * [Config] OMAP_USB2=y (since TWL6030_USB depends on it)
+  * [Config] enable Freescale IMX6 support (SabreLite)
+  * [Config] SERIAL_IMX_CONSOLE=y
+  * [Config] MMC_*_IMX=y
+  * [Config] disable USB_SUSPEND
+  * [Config] USB_MXS_PHY=y
+  * [Config] USB_CHIPIDEA=y
+  * SAUCE: DTB: add support for multiple DTBs
+  * SAUCE: DTB: build imx6q-sabrelite
+  * SAUCE: DTB: build beaglexm
+  * SAUCE: DTB: build panda/panda es
+  * [Config] disable CPU_FREQ
+  * [Config] PANEL_TFP410=y (video DVI output)
+  * [Config] SND_OMAP_SOC*=y
+  * [Config] SND_IMX_SOC*=y
+  * [Config] I2C_IMX=y
+  * [Config] SPI_IMX=m
+
+  [ Stefan Bader ]
+
+  * [Config] Move 9p modules into generic package
+    - LP: #1107658
+
+  [ Tony Lindgren ]
+
+  * SAUCE: ARM: OMAP2+: Limit omap initcalls to omap only on multiplatform
+    kernels
+  * SAUCE: ARM: OMAP2+: Use omap initcalls
+  * SAUCE: ARM: OMAP: Fix i2c cmdline initcall for multiplatform
+  * SAUCE: ARM: OMAP: Fix dmaengine init for multiplatform
+  * SAUCE: ARM: OMAP2+: Add multiplatform debug_ll support
+  * SAUCE: ARM: OMAP2+: Disable code that currently does not work with
+    multiplaform
+  * SAUCE: ARM: OMAP2+: Enable ARCH_MULTIPLATFORM support
+  * SAUCE: ARM: OMAP2+: Add minimal support for booting vexpress
+  * SAUCE: ARM: OMAP2+: Remove now obsolete uncompress.h and debug-macro.S
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc5
+    - LP: #1096789
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 31 Jan 2013 06:44:52 -0800
+
+linux (3.8.0-2.6) raring; urgency=low
+
+  [ Adam Conrad ]
+
+  * Fix up linux-tools -> SRCPKGNAME-tools rename
+
+  [ Andy Whitcroft ]
+
+  * [Config] re-disable CONFIG_SOUND_OSS
+    - LP: #1105230
+
+  [ Arend van Spriel ]
+
+  * SAUCE: brcmsmac: fix tx status processing
+
+  [Leann Ogasawara]
+
+  * Release Tracking Bug
+    - LP: #1105104
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 25 Jan 2013 11:56:30 -0800
+
+linux (3.8.0-1.5) raring; urgency=low
+
+  [Tim Gardner]
+
+  * Release Tracking Bug
+    - LP: #1101235
+
+  [ Dudley Du ]
+
+  * SAUCE: Input: add support for Cypress PS/2 Trackpads
+    - LP: #978807
+
+  [ Kamal Mostafa ]
+
+  * SAUCE: Input: increase struct ps2dev cmdbuf[] to 8 bytes
+  * SAUCE: Input: Cypress PS/2 Trackpad simulated multitouch
+  * [Config] Add CONFIG_PS2_CYPRESS
+
+  [ Tim Gardner ]
+
+  * rebase to v3.8-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc4
+    - LP: #1095315
+    - LP: #886975
+    - LP: #1086921
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 17 Jan 2013 10:50:22 -0800
+
+linux (3.8.0-0.4) raring; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Update CONFIG_TOUCHSCREEN_EGALAX build annotation
+  * [Config] Update CONFIG_IIO build annotation
+  * [Config] Update CONFIG_TOUCHSCREEN_EETI annotation
+  * [Config] Remove CONFIG_SPI_DW_MMIO annotation
+  * [Config] Remove CONFIG_SPI_PL022 annotation
+  * [Config] Update CONFIG_EZX_PCAP annotation
+  * [Config] Update CONFIG_SENSORS_AK8975 annotation
+  * [Config] Disable CONFIG_DRM_MGAG200
+    - LP: #1042903
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 14 Jan 2013 10:01:50 -0800
+
+linux (3.8.0-0.3) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: (no-up) trace: add trace events for open(), exec() and
+    uselib()"
+
+  [ Scott James Remnant ]
+
+  * SAUCE: (no-up) trace: add trace events for open(), exec() and uselib()
+    (for v3.7+)
+    - LP: #1085766, #462111
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 11 Jan 2013 16:57:27 +0000
+
+linux (3.8.0-0.2) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [packaging] Add macro to selectively disable building perf
+  * [packaging] Cannot depend on universe package libaudit-dev
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 10 Jan 2013 12:43:24 -0700
+
+linux (3.8.0-0.1) raring; urgency=low
+
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc3
+    - LP: #1096789
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.8-rc2
+    - LP: #1082357
+    - LP: #1075882
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 17 Dec 2012 10:35:09 +0000
+
+linux (3.7.0-7.15) raring; urgency=low
+
+  [ Chris J Arges ]
+
+  * SAUCE: add eeprom_bad_csum_allow module parameter
+    - LP: #1070182
+
+  [ Leann Ogasawara ]
+
+  * Add ceph to linux-image for virtual instances
+    - LP: #1063784
+
+  [ Serge Hallyn ]
+
+  * SAUCE: net: dev_change_net_namespace: send a KOBJ_REMOVED/KOBJ_ADD
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_SLUB_DEBUG=y
+    - LP: #1090308
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[SCSI] sd: Implement support for WRITE SAME"
+    - LP: #1089818
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 12 Dec 2012 06:50:20 -0800
+
+linux (3.7.0-6.14) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] annotations: all new annotations scheme including defaults
+  * [Configs] apply annotation updates to main configs (top section)
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: include <linux/printk.h> and <stdarg.h> for mmc_core arm
+    build"
+  * Revert "SAUCE: [arm] fixup __aeabi_uldivmod undefined build error"
+  * Temporarily disable module check for build
+
+  [ Stefan Bader ]
+
+  * ubuntu: dm-raid45: Adapt to upstream interface changes
+  * Re-enable build of dm-raid45
+
+  [ Tim Gardner ]
+
+  * SAUCE: Moved scripts/fw-to-ihex.sh to debian/scripts/misc
+  * SAUCE: ACPICA: Fix ACPI mutex object allocation memory leak on error
+  * SAUCE: drm: Fix possible EDID memory allocation oops
+  * SAUCE: ttm: Fix possible _manager memory allocation oops
+  * SAUCE: iwlwifi: iwlagn_request_scan: Fix check for priv->scan_request
+  * SAUCE: i915: intel_set_mode: Reduce stack allocation from 500 bytes to
+    2 pointers
+
+  [ Tomas Hozza ]
+
+  * SAUCE: tools: hv: Netlink source address validation allows DoS
+    - LP: #1084777
+    - CVE-2012-5532
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 05 Dec 2012 14:11:12 -0800
+
+linux (3.7.0-5.13) raring; urgency=low
+
+  [ Lino Sanfilippo ]
+
+  * SAUCE: inotify, fanotify: replace fsnotify_put_group() with
+    fsnotify_destroy_group()
+    - LP: #922906
+  * SAUCE: fsnotify: introduce fsnotify_get_group()
+    - LP: #922906
+  * SAUCE: fsnotify: use reference counting for groups
+    - LP: #922906
+  * SAUCE: fsnotify: take groups mark_lock before mark lock
+    - LP: #922906
+  * SAUCE: fanotify: add an extra flag to mark_remove_from_mask that
+    indicates wheather a mark should be destroyed
+    - LP: #922906
+  * SAUCE: fsnotify: use a mutex instead of a spinlock to protect a groups
+    mark list
+    - LP: #922906
+  * SAUCE: fsnotify: pass group to fsnotify_destroy_mark()
+    - LP: #922906
+  * SAUCE: fsnotify: introduce locked versions of fsnotify_add_mark() and
+    fsnotify_remove_mark()
+    - LP: #922906
+  * SAUCE: fsnotify: dont put marks on temporary list when clearing marks
+    by group
+    - LP: #922906
+  * SAUCE: fsnotify: change locking order
+    - LP: #922906
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NFC_LLCP=y
+  * [Config] get-firmware: Filter new files through fwinfo
+  * [Config] CONFIG_MTD_NAND_DOCG4=m for all arches
+  * [Config] CONFIG_DRM_EXYNOS_HDMI=y
+  * [Config] CONFIG_XEN=y for all arches
+  * [Config] CONFIG_SND_OMAP_SOC_ZOOM2=m
+  * [Config] CONFIG_MMC_DW_EXYNOS=m
+  * [Config] CONFIG_GPIO_ADNP=m
+  * [Config] find-obsolete-firmware: Use correct path
+  * rebase to v3.7-rc8
+    - LP: #1084640
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "VFS: don't do protected {sym,hard}links by default"
+    - LP: #1084192
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 28 Nov 2012 16:07:08 +0000
+
+linux (3.7.0-4.12) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * Revert "[Config] Use -j1 for headers_install"
+  * Revert "[Config] install-arch-headers needs a valid config"
+    Strayed into the weeds in search of the root cause of the periodic
+    build failure.
+    Fixes powerpc FTBS introduced in -4.11.
+  * [Config] hmake -j1
+    The kernel makefile appears to have parallel dependency
+    problems for the install_headers target. This appears to be root
+    cause for a periodic build failure on N-way machines.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 27 Nov 2012 12:33:06 -0800
+
+linux (3.7.0-4.11) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Use -j1 for headers_install
+    Also fixes a powerpc FTBS introduced by
+    "[Config] install-arch-headers needs a valid config".
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 27 Nov 2012 10:19:30 -0700
+
+linux (3.7.0-4.10) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] add rebuild-test support for autopkgtest
+    - LP: #1081500
+  * [tests] move build tests out of the way
+    - LP: #1081500
+  * [tests] add an autopkgtest rebuild test
+    - LP: #1081500
+
+  [ Tim Gardner ]
+
+  * rebase to v3.7-rc7
+  * SAUCE: Remove emi62 files duplicated in linux-firmware
+  * SAUCE: Remove sb16 files duplicated in linux-firmware
+  * SAUCE: Remove whiteheat files duplicated in linux-firmware
+  * SAUCE: Remove yamaha files duplicated in linux-firmware
+  * SAUCE: Remove dsp56k files used only by m68k
+  * SAUCE: firmware: Remove last vestiges of dabusb
+  * SAUCE: Remove vicam files duplicated in linux-firmware
+  * [Config] install-arch-headers needs a valid config
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc7
+    - LP: #1076840
+    - LP: #1081466
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 21 Nov 2012 06:07:23 -0800
+
+linux (3.7.0-3.9) raring; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_X86_CPUFREQ_NFORCE2=y
+    - LP: #1079900
+  * Add nfsv3 to nfs-modules udeb
+
+  [ Paolo Pisati ]
+
+  * [Config] SND_OMAP_SOC*=y
+    - LP: #1019321
+
+  [ Stefan Bader ]
+
+  * SAUCE: (no-up) xen/netfront: handle compound page fragments on transmit
+    - LP: #1078926
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: SECCOMP: audit: always report seccomp violations"
+    - LP: #1079469
+  * Revert "SAUCE: omap3 clocks .dev_id = NULL"
+  * rebase to v3.7-rc6
+  * SAUCE: script to detect obsolete firmware
+  * SAUCE: Remove yam files duplicated in linux-firmware
+  * SAUCE: Remove tehuti files duplicated in linux-firmware
+  * SAUCE: Remove matrox files duplicated in linux-firmware
+  * SAUCE: Remove cxgb3 files duplicated in linux-firmware
+  * SAUCE: Remove r128 files duplicated in linux-firmware
+  * SAUCE: Remove acenic files duplicated in linux-firmware
+  * SAUCE: Remove keyspan files duplicated in linux-firmware
+  * SAUCE: Remove sun files duplicated in linux-firmware
+  * SAUCE: Remove radeon files duplicated in linux-firmware
+  * SAUCE: Update bnx2x firmware to 7.8.2.0
+  * [Config] generic.inclusion-list: econet has disappeared
+
+  [ Upstream Kernel Changes ]
+
+  * seccomp: forcing auditing of kill condition
+    - LP: #1079469
+  * rebase to v3.7-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 20 Nov 2012 12:28:55 -0800
+
+linux (3.7.0-2.8) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "overlayfs: disable until FTBS is fixed"
+  * Revert "ubuntu: overlayfs"
+  * Revert "ubuntu: AUFS"
+  * ubuntu: overlayfs -- overlayfs: add statfs support
+  * ubuntu: overlayfs -- ovl: switch to __inode_permission()
+  * ubuntu: overlayfs -- overlayfs: copy up i_uid/i_gid from the underlying
+    inode
+    - LP: #944386
+  * ubuntu: AUFS (no-squash): basic framework and update machinary
+  * ubuntu: AUFS (no-squash) -- aufs3-base.patch
+  * ubuntu: AUFS (no-squash) -- aufs3-standalone.patch
+  * ubuntu: AUFS: aufs-update -- follow the uapi header changes
+  * ubuntu: AUFS -- update to f2873474324d0a31af4340554b9715f51331bc7f
+  * ubuntu: AUFS (no-squash) -- reenable
+    - LP: #1079193
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs -- overlayfs: implement show_options
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs -- vfs: add i_op->dentry_open()
+  * ubuntu: overlayfs -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs -- overlay filesystem
+  * ubuntu: overlayfs -- fs: limit filesystem stacking depth
+  * ubuntu: overlayfs -- vfs: export __inode_permission() to modules
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs -- overlay: overlay filesystem documentation
+
+  [ Robin Dong ]
+
+  * ubuntu: overlayfs -- overlayfs: fix possible leak in ovl_new_inode
+  * ubuntu: overlayfs -- overlayfs: create new inode in ovl_link
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 15 Nov 2012 13:35:12 +0000
+
+linux (3.7.0-1.7) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Drop dependency on libaudit-dev
+    Its a universe package which causes an FTBS on the builders.
+    libaudit-dev is not strictly required for the perf tools build.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 14 Nov 2012 10:08:13 -0700
+
+linux (3.7.0-1.6) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enforce -- switch CONFIG_NVRAM to more readable form
+  * [Config] better encode the CONFIG_NVRAM constaint
+  * enforcer -- fix debugging output
+
+  [ Ben Collins ]
+
+  * [Config] Add custom_override rule to allow for alternate kernel
+    file/install
+  * [Config] Use SRCPKGNAME as prefix for indep linux headers package
+
+  [ Tim Gardner ]
+
+  * [Config] Dropped armel
+  * Drop highbank from ABI fetch list
+  * [Config] Use dh_prep instead of 'dh_clean -k'
+  * [Config] Build depend on libaudit-dev, libunwind8-dev for tools
+  * [Config] Document binary-indep dependency chain
+  * rebase to v3.7-rc5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc5
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 13 Nov 2012 07:13:37 -0500
+
+linux (3.7.0-0.5) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_AMD_IOMMU_V2=m
+    - LP: #1071520
+  * [Config] CONFIG_MTD_ONENAND_SIM=n for armel
+    Fixes FTBS
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Thu, 08 Nov 2012 15:45:39 -0500
+
+linux (3.7.0-0.4) raring; urgency=low
+
+  [ Ben Collins ]
+
+  * [Config] Update enforce rule for CONFIG_NVRAM to better suit flavours
+
+  [ Tim Gardner ]
+
+  * [Config] do_tools=false for arm
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 08 Nov 2012 05:39:51 -0700
+
+linux (3.7.0-0.3) raring; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_DRM_EXYNOS_HDMI=n for armhf
+  * [Config] CONFIG_MTD_NAND_DOCG4=n for armel/armhf
+  * [Config] Drop highbank harder
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 07 Nov 2012 18:11:45 +0000
+
+linux (3.7.0-0.2) raring; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] add fs/udf to linux-image to support DVD/CD formats in virtual
+    instances
+    - LP: #1066921
+  * [Config] drop highbank builds
+
+  [ Jeremy Kerr ]
+
+  * SAUCE: efivarfs: Implement exclusive access for {get, set}_variable
+    - LP: #1063061
+
+  [ Leann Ogasawara ]
+
+  * Reinstate dropped.txt from Ubuntu-3.7.0-0.1-rc1
+
+  [ Tim Gardner ]
+
+  * [Config] Dropped powerpc/ppc64 in favour of the community kernel
+  * [Config] CONFIG_MODULE_SIG=y for amd64,i386, and highbank
+  * rebase to v3.7-rc4
+  * SAUCE: MODSIGN: Emit error for incorrectly signed module
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc4
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 05 Nov 2012 05:35:41 -0700
+
+linux (3.7.0-0.1) raring; urgency=low
+
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc3
+    - LP: #1056078
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.7-rc2
+    - LP: #1060729
+    - LP: #1059523
+    - LP: #1006690
+    - LP: #1049623
+    - LP: #1046512
+    - LP: #1052499
+    - LP: #1037642
+    - LP: #559939
+    - LP: #1052460
+    - LP: #939161
+    - LP: #1046734
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 02 Oct 2012 08:13:07 -0600
+
+linux (3.6.0-0.1) UNRELEASED; urgency=low
+
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc6
+    - LP: #1000424
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc5
+    - LP: #1040077
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.6-rc3
+    - LP: #1038651
+    - LP: #1034779
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 24 Jul 2012 06:37:09 -0700
+
+linux (3.5.0-6.6) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION enable IPv6
+    experimental features
+  * SAUCE: highbank -- export clock functions for modules
+  * [Config] highbank -- reenable CONFIG_TOUCHSCREEN_W90X900
+  * [Config] highbank -- renenable CONFIG_SERIO_AMBAKMI
+  * [Config] highbank -- reenable CONFIG_RFKILL_GPIO
+  * [Config] highbank -- reenable CONFIG_MMC_SDHCI_PXAV3
+  * [Config] highbank -- reenable CONFIG_MMC_SDHCI_PXAV3
+  * [Config] highbank -- reenable CONFIG_KEYBOARD_SAMSUNG
+  * [Config] highbank -- reenable CONFIG_FB_ARMCLCD
+  * [Config] highbank -- reenable CONFIG_DW_DMAC
+  * [Config] highbank -- reenable CONFIG_USB_R8A66597_HCD
+  * [Config] highbank -- reenable CONFIG_USB_MV_UDC
+  * [Config] highbank -- reenable CONFIG_USB_DWC3
+  * [Config] highbank -- reenable CONFIG_SATA_MV
+  * [Config] highbank -- reenable CONFIG_PATA_ARASAN_CF
+  * [Config] highbank -- CONFIG_CAN_C_CAN_PLATFORM
+  * [Config] highbank -- reenable CONFIG_MMC_ARMMMCI
+  * [Config] highbank -- reenable CONFIG_SERIAL_AMBA_PL010
+  * [Config] highbank -- reenable CONFIG_ATMEL_PWM
+  * [Config] highbank -- enable CONFIG_CHECKPOINT_RESTORE
+  * [Config] highbank -- enable CONFIG_EXPERT
+  * [Config] highbank -- enable CONFIG_CHECKPOINT_RESTORE
+  * [Config] enable CONFIG_USB_DYNAMIC_MINORS
+  * [Config] enable CONFIG_USB_EHCI_TT_NEWSCHED
+  * [Config] enable CONFIG_USB_ETH_EEM
+  * [Config] enable CONFIG_USB_HCD_BCMA/CONFIG_USB_HCD_SSB
+  * [Config] disable CONFIG_USB_M66592
+  * [Config] enable CONFIG_USB_NET2272
+  * [Config] enable CONFIG_USB_R8A66597
+  * [Config] annotate: CONFIG_USB_OMAP not required for our h/w
+  * [Config] set CONFIG_USB_MUSB_HDRC=m for omap
+  * [Config] annotate: CONFIG_USB_G_MULTI fix rule
+  * [Config] CONFIG_USB_GPIO_VBUS=m for OMAP
+  * [Config] Enable CONFIG_DRM_AST/_CIRRUS_QEMU/_MGAG200
+  * [Config] sync configuration armhf omap -> armel omap
+  * [Config] annotate: CONFIG_IIO triggers build failures on OMAP4
+  * [Config] disable CONFIG_OMAP_IOVMM is deprecated
+
+  [ Bryan Wu ]
+
+  * [Config] change default IO scheduler from CFQ to Deadline
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] Temporarily disable CONFIG_MV643XX_ETH on powerpc"
+  * [Config] Disable CONFIG_MOUSE_INPORT
+
+  [ Tim Gardner ]
+
+  * SAUCE: firmware: Update bnx2x to current firmware version 7.2.51
+  * [Config] Add bnx2x firmware to nic-modules udeb
+  * SAUCE: Add script to convert firmware to ihex format
+  * SAUCE: firmware: Upgrade bnx2 to current versions
+  * [Config] Add tigon firmware to nic-modules udeb
+  * [Config] CONFIG_EARLY_PRINTK_DBGP=y
+    - LP: #1026761
+  * SAUCE: Remove redundant cis firmware
+  * SAUCE: Remove redundant emi26 firmware
+  * SAUCE: Remove redundant ttusb-budget firmware
+  * SAUCE: Remove redundant sun/cassini firmware
+  * SAUCE: Remove redundant ositech/Xilinx7OD firmware
+  * SAUCE: Remove redundant 3com/typhoon.bin firmware
+  * SAUCE: Remove redundant yamaha/ds1 firmware
+  * SAUCE: Remove redundant keyspan_pda firmware
+  * rebase to v3.5
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5
+    - LP: #1027828
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 23 Jul 2012 05:57:04 -0700
+
+linux (3.5.0-5.5) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] annotations: initial import of configuration annotations
+
+  [ Bryan Wu ]
+
+  * [Config] enforcer -- add CONFIG_I2C_DESIGNWARE_PLATFORM enforce checker
+
+  [ Leann Ogasawara ]
+
+  * Rebase to v3.5-rc7
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Bluetooth: btusb: Add vendor specific ID (0a5c:21f4) BCM20702A0
+    - LP: #1010281
+
+  [ Tim Gardner ]
+
+  * [Config] enable CONFIG_I2C_HELPER_AUTO for all flavours as policy
+    expects
+  * [Config] CONFIG_I2O_CONFIG_OLD_IOCTL=n
+  * [Config] CONFIG_BRIDGE_EBT_ULOG=n
+  * [Config] CONFIG_IP_NF_QUEUE=n
+  * [Config] CONFIG_MTD_DOC2000=n
+  * [Config] CONFIG_PRINT_QUOTA_WARNING=n
+  * [Config] CONFIG_PRISM54=n
+  * [Config] CONFIG_SCx200_I2C=n
+  * [Config] CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 16 Jul 2012 15:38:41 -0700
+
+linux (3.5.0-4.4) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Packaging] getabis should be extracting all packages
+    - LP: #1021174
+  * [Config] getabis -- series uses linux-image-extra
+    - LP: #1021174
+  * rebase to v3.5-rc6
+
+  [ Bryan Wu ]
+
+  * [Config] built-in CONFIG_MICREL_PHY as other PHY drivers for all
+    flavours
+  * [Config] sync CONFIG_MOUSE_PS2_ config for all flavours
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_RT2800USB_RT35XX and CONFIG_RT2800USB_RT53XX
+    - LP: #1019561
+
+  [ Paolo Pisati ]
+
+  * [Config] SND_OMAP_SOC, SND_OMAP_SOC_MCBSP and SND_OMAP_SOC_OMAP3_BEAGLE =y
+    - LP: #1019321
+
+  [ Stefan Bader ]
+
+  * SAUCE: (pre-up) net: dont use __netdev_alloc_skb for bounce buffer
+    - LP: #1018456
+  * (config) Disable ACPI_PROCFS_POWER
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_ACPI_BGRT=y
+  * Extract firmware module info during getabi
+    - LP: #1021174
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 09 Jul 2012 08:50:20 -0700
+
+linux (3.5.0-3.3) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_MEMTEST=y
+    - LP: #1004535
+  * [Config] config-check: add support for a cut operation
+  * [Config] enforcer -- switch to cut where appropriate
+
+  [ Leann Ogasawara ]
+
+  * Rebase to v3.5-rc5
+  * [Config] Updateconfigs after rebase to v3.5-rc5
+
+  [ Luis Henriques ]
+
+  * SAUCE: ocfs2: Fix NULL pointer dereferrence in
+    __ocfs2_change_file_space
+    - LP: #1006012
+
+  [ Seth Forshee ]
+
+  * SAUCE: (drop after 3.5) drm/i915: ignore pipe select bit when checking
+    for LVDS register initialization
+    - LP: #1012800
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc5
+    - LP: #1013183
+    - LP: #1017017
+    - LP: #884652
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 02 Jul 2012 06:41:58 -0700
+
+linux (3.5.0-2.2) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.5-rc4
+
+  [ Arend van Spriel ]
+
+  * SAUCE: (drop after 3.5) brcmsmac: fix NULL pointer crash in
+    brcms_c_regd_init()
+    - LP: #950320
+
+  [ Bryan Wu ]
+
+  * [Config] Sync CONFIG_CGROUP_MEM_RES_CTLR_SWAP for ARM
+
+  [ Chris J Arges ]
+
+  * PACKAGING: add .gnu_debuglink sections to .ko files
+    - LP: #669641
+
+  [ Leann Ogasawara ]
+
+  * d-i: Add hid-generic to input-modules
+    - LP: #1017879
+
+  [ Ming Lei ]
+
+  * SAUCE: Revert "mmc: omap_hsmmc: Enable Auto CMD12"
+    - LP: #1017717, #225
+
+  [ Paolo Pisati ]
+
+  * SAUCE: Revert "Fix OMAP EHCI suspend/resume failure (i693)"
+    - LP: #1017718
+  * [Config] Disable generic USB_EHCI_HCD_PLATFORM on omap3
+
+  [ Seth Forshee ]
+
+  * SAUCE: (drop after 3.5) brcm80211: smac: don't set up tx power limits
+    during initialization
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: always set channel specified
+    by mac80211
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: remove unused code for 40MHz
+    channels
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: clean up channel.c
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: inform mac80211 of the X2
+    regulatory domain
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: enable/disable radio on
+    regulatory updates
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: use mac80211 channel data for
+    tx power limits
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: don't validate channels
+    against internal regulatory data
+    - LP: #950320
+  * SAUCE: (drop after 3.5) brcm80211: smac: use current regulatory domain
+    when checking whether OFDM is allowed
+    - LP: #950320
+
+  [ Tim Gardner ]
+
+  * [Config] Enable CONFIG_CGROUPS for highbank
+    - LP: #1014692
+  * [Config] FB_OMAP*=y and PANEL_TFP410=y
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 26 Jun 2012 06:21:05 -0700
+
+linux (3.5.0-1.1) quantal-proposed; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] highbank -- enable CONFIG_RFKILL=y and CONFIG_CAN=m
+
+  [ Leann Ogasawara ]
+
+  * Rebase to v3.5-rc1
+  * [Config] Remove USB_DEVICEFS from the config enforcer
+  * [Config] Updateconfigs after rebase to v3.5-rc1
+  * [Config] Temporarily disable CONFIG_MACH_NOKIA_RX51 on arm
+  * [Config] Temporarily disable CONFIG_TOUCHSCREEN_EETI on arm
+  * [Config] Temporarily disable CONFIG_TOUCHSCREEN_EGALAX on arm
+  * [Config] Temporarily disable CONFIG_EZX_PCAP on arm
+  * [Config] Temporarily disable CONFIG_LIS3L02DQ on arm
+  * [Config] Temporarily disable CONFIG_TI_CPSW on arm
+  * [Config] Temporarily disable CONFIG_GPIO_EM on arm
+  * [Config] Temporarily disable CONFIG_SERIAL_8250_EM on armhf
+  * [Config] Temporarily disable CONFIG_STMMAC_ETH on armhf
+  * [Config] Temporarily disable CONFIG_HW_RANDOM_ATMEL on armhf
+  * Rebase to v3.5-rc2
+  * [Config] Updateconfigs after rebase to v3.5-rc2
+  * [Config] Temporarily disable CONFIG_MV643XX_ETH on powerpc
+  * Rebase to v3.5-rc3
+  * [Config] Updateconfigs after rebase to v3.5-rc3
+
+  [ Paul Mundt ]
+
+  * SAUCE: fix bug.h's inclusion of kernel.h
+
+  [ Stefan Bader ]
+
+  * SAUCE: Fix compile failures of dm-raid45
+  * [Config] Enable dm-raid45
+  * Move dependency on crda to extra package
+    - LP: #657901
+  * SAUCE: Mask CR4 writes on older Xen hypervisors
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.5-rc3
+    - LP: #993162
+    - LP: #925577
+  * rebase to v3.5-rc2
+  * rebase to v3.5-rc1
+    - LP: #955892
+    - LP: #978038
+    - LP: #987371
+    - LP: #929545
+    - LP: #942316
+    - LP: #903853
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 08 Jun 2012 14:28:46 -0700
+
+linux (3.4.0-5.11) quantal-proposed; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_ARM_LPAE
+    - LP: #1009061
+
+  [ Oleksij Rempel ]
+
+  * SAUCE: b43: do not call ieee80211_unregister_hw if we are not registred
+    - LP: #1008905
+
+  [ Paolo Pisati ]
+
+  * [Config] omap3: MFD_OMAP_USB_HOST is usb host in omap2+.
+    - LP: #1009061
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 05 Jun 2012 08:06:28 -0700
+
+linux (3.4.0-4.10) quantal; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Temporarily disable ABI and module check
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 04 Jun 2012 20:27:31 -0700
+
+linux (3.4.0-4.9) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] fix config split to avoid the shared config
+  * [Config] updateconfigs following split config fix
+  * [Config] linux-image-extras needs full postinst
+  * [Config] CONFIG_BLK_DEV_NVME commonise across architectures
+  * [Config] CONFIG_HP_WATCHDOG enable as module
+  * [Config] CONFIG_PDC_ADMA is not boot essential
+  * [Config] CONFIG_XEN_ACPI_PROCESSOR should be enabled on x86
+  * [Config] CONFIG_VT6655/CONFIG_VT6656=m
+  * [Config] CONFIG_TRANZPORT=m commonise
+  * [Config] CONFIG_R3964=m commonise
+  * [Config] CONFIG_SCSI_DH=m commonise
+  * [Config] CONFIG_SCSI_IBMVSCSIS=m commonise
+  * [Config] CONFIG_AMD_PHY=y phys are not autoloadable
+  * [Config] CONFIG_SCSI_QLA_ISCSI=m commonise
+  * [Config] CONFIG_SCSI_SPI_ATTR=m commonise
+  * [Config] CONFIG_USB_SN9C102 is deprecated disable
+  * [Config] CONFIG_USB_SI470X=m commonise
+  * [Config] CONFIG_USB_ET61X251=m commonise
+  * [Config] CONFIG_RTS_PSTOR=m commonise
+  * [Config] CONFIG_SCANLOG=m commonise
+  * [Config] CONFIG_SCSI_SYM53C8XX_2=m commonise
+  * [Config] CONFIG_SM_FTL=m commonise
+  * [Config] CONFIG_SOLO6X10=m commonise
+  * [Config] CONFIG_SND_PCM_OSS=n using pulseaudio emulation instead
+  * [Config] CONFIG_SPI_DESIGNWARE=m commonise
+  * [Config] CONFIG_SPI_SPIDEV=m commonise
+  * [Config] CONFIG_TABLET_USB_WACOM=m commonise
+  * [Config] CONFIG_TPS65010=m commonise
+  * [Config] CONFIG_STE10XP=y commonise
+  * [Config] CONFIG_X25_ASY=m commonise
+  * [Config] CONFIG_USB_MON=m commonise
+  * [Config] CONFIG_VME_BUS=m commonise
+  * [Config] CONFIG_W35UND=m commonise
+  * [Config] -CONFIG_TCG_TPM=y commonise
+  * [Config] highbank -- commonise filesystems
+  * [Config] highbank -- commonise subsystems
+  * [Config] highbank -- commonise network protocols
+  * [Config] highbank -- commonise input drivers
+  * [Config] highbank -- commonise CRYPTO options
+  * [Config] highbank -- commonise HID options
+  * [Config] highbank -- commonise sensors options
+  * [Config] highbank -- commonise EXPORTFS/FHANDLE
+  * [Config] highbank -- commonise CONFIG_CRYPTO_LZO
+  * [Config] highbank -- commonise ENCRYPTED_KEYS
+  * [Config] highbank -- commonise CONFIG_ATALK
+  * [Config] highbank -- commonise INET/INET6
+  * [Config] highbank -- commonise NLS
+  * [Config] highbank -- commonise BLK/CHR
+  * [Config] highbank -- CONFIG_EXT2_FS=y boot essential on highbank
+  * [Config] highbank -- commonise INET/INET6 part 2
+  * [Config] highbank -- commonise PHY settings
+  * [Config] highbank -- commonise CRC settings
+  * [Config] highbank -- commonise BINFMT settings
+  * [Config] highbank -- commonise DM settings
+  * [Config] highbank -- commonise RTC_DRV settings
+  * [Config] highbank -- commonise KEYBOARD/MOUSE settings
+  * [Config] highbank -- commonise USB settings
+  * [Config] highbank -- commonise GPIO settings
+  * [Config] highbank -- commonise I2C settings
+  * [Config] highbank -- commonise numerous subsystem selectors
+  * [Config] highbank -- commonise A-C modules missmatches
+  * [Config] highbank -- commonise D-F modules missmatches
+  * [Config] CONFIG_AUDIT_LOGINUID_IMMUTABLE incompatible with upstart
+  * [Config] highbank -- commonise G-I modules missmatches
+  * [Config] highbank -- commonise J-L modules missmatches
+  * [Config] highbank -- commonise M modules missmatches
+  * [Config] highbank -- commonise N-P modules missmatches
+  * [Config] highbank -- commonise Q-R modules missmatches
+  * [Config] highbank -- commonise S modules missmatches -- part 1
+  * [Config] highbank -- commonise S modules missmatches -- part 2
+  * [Config] highbank -- commonise T modules missmatches
+  * [Config] highbank -- commonise U-Z modules missmatches
+
+  [ Ike Panhc ]
+
+  * [Config] add highbank flavour
+    - LP: #1000831
+
+  [ Mark Langsdorf ]
+
+  * SAUCE: arm highbank: add support for pl320-ipc driver
+    - LP: #1000831
+
+  [ Rob Herring ]
+
+  * SAUCE: input: add a key driver for highbank
+    - LP: #1000831
+  * SAUCE: ARM: highbank: Add smc calls to enable/disable the L2
+    - LP: #1000831
+  * SAUCE: force DMA buffers to non-bufferable on highbank
+    - LP: #1000831
+  * SAUCE: net: calxedaxgmac: fix net timeout recovery
+    - LP: #1000831
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_IWLWIFI_EXPERIMENTAL_MFP=n
+  * [Config] CONFIG_PCI_REALLOC_ENABLE_AUTO=y
+  * [Config] CONFIG_CIFS_EXPERIMENTAL has disappeared
+  * [Config] Homogenize CIFS configs across all arches
+  * [Config] armhf should not be skipabi or skipmodules
+    - LP: #1006913
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 04 Jun 2012 05:52:49 -0700
+
+linux (3.4.0-3.8) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] include include/generated/compile.h
+    - LP: #942569
+  * [Config] fix up postinst to ensure we know which error is which
+    - LP: #1002388
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: async_populate_rootfs: fix build warnings
+    - LP: #1003417
+
+  [ John Johansen ]
+
+  * Revert "SAUCE: AppArmor: Add the ability to mediate mount"
+  * SAUCE: apparmor: Add the ability to mediate mount
+  * SAUCE: AppArmor: basic networking rules
+  * SAUCE: apparmor: fix profile lookup for unconfined
+    - LP: #978038, #987371
+  * SAUCE: apparmor: fix long path failure due to disconnected path
+    - LP: #955892
+
+  [ Mario Limonciello ]
+
+  * SAUCE: dell-laptop: rfkill blacklist Dell XPS 13z, 15
+    - LP: #901410
+
+  [ Stefan Bader ]
+
+  * (config) Built-in xen-acpi-processor
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NET_DSA=m
+    - LP: #1004148
+  * [Config] Ensure CONFIG_XEN_ACPI_PROCESSOR=y for amd64
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 25 May 2012 11:38:33 -0700
+
+linux (3.4.0-3.7) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] drop the virtual flavour in favour of a split generic et al
+  * [Config] enforcer -- drop IDLE enforcement
+  * [Config] enable CONFIG_SCSI_VIRTIO=m for amd64
+  * [Config] updateconfigs following removal of -virtual
+
+  [ Leann Ogasawara ]
+
+  * Rebase to v3.4
+
+  [ Seth Forshee ]
+
+  * [Config] disable CONFIG_B43_BCMA_EXTRA
+
+  [ Tim Gardner ]
+
+  * [Config] Check for extras when building udebs
+  * [Config] Collapsed generic-pae into generic [i386]
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 21 May 2012 07:23:47 -0700
+
+linux (3.4.0-2.6) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: overlayfs -- overlayfs: update touch_atime() usage"
+  * Revert "ubuntu: overlayfs -- overlayfs: switch from d_alloc_root() to
+    d_make_root()"
+  * Revert "ubuntu: overlayfs -- overlayfs: follow header cleanup"
+  * Revert "ubuntu: overlayfs -- overlayfs: apply device cgroup and
+    security permissions to overlay files"
+  * Revert "ubuntu: overlayfs -- fs: limit filesystem stacking depth"
+  * Revert "ubuntu: overlayfs -- overlay: overlay filesystem documentation"
+  * Revert "ubuntu: overlayfs -- overlayfs: implement show_options"
+  * Revert "ubuntu: overlayfs -- overlayfs: add statfs support"
+  * Revert "ubuntu: overlayfs -- overlay filesystem"
+  * Revert "ubuntu: overlayfs -- vfs: introduce clone_private_mount()"
+  * Revert "ubuntu: overlayfs -- vfs: export do_splice_direct() to modules"
+  * Revert "ubuntu: overlayfs -- vfs: add i_op->open()"
+  * Revert "ubuntu: overlayfs -- vfs: pass struct path to __dentry_open()"
+  * ubuntu: overlayfs -- overlayfs: add statfs support
+  * ubuntu: overlayfs -- inode_only_permission: export inode level
+    permissions checks
+  * ubuntu: overlayfs -- overlayfs: switch to use inode_only_permissions
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs -- overlayfs: implement show_options
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs -- vfs: pass struct path to __dentry_open()
+  * ubuntu: overlayfs -- vfs: add i_op->open()
+  * ubuntu: overlayfs -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs -- overlay filesystem
+  * ubuntu: overlayfs -- fs: limit filesystem stacking depth
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs -- overlay: overlay filesystem documentation
+
+  [ Robin Dong ]
+
+  * ubuntu: overlayfs -- overlayfs: fix possible leak in ovl_new_inode
+  * ubuntu: overlayfs -- overlayfs: create new inode in ovl_link
+
+  [ Tim Gardner ]
+
+  * [Config] perarch and indep tools builds need separate build directories
+  * Prevent upgrading a non-PAE CPU
+  * perf is not parallel build safe
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 16 May 2012 08:43:18 -0700
+
+linux (3.4.0-2.5) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] perarch and indep tools builds need separate build directories
+
+  [ Tim Gardner ]
+
+  * Prevent upgrading a non-PAE CPU
+  * [Config] build debug
+  * [Config] perf tools are not parallel build safe
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 15 May 2012 11:37:53 -0700
+
+linux (3.4.0-2.4) quantal; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: fsam7400: use UMH_WAIT_PROC consistently"
+  * Revert "ubuntu: fsam7400 select CHECK_SIGNATURE and depend on X86"
+  * Revert "ubuntu: fsam7400: Depend on CHECK_SIGNATURE"
+  * Revert "ubuntu: fsam7400 -- Cleanup Makefile"
+  * Revert "ubuntu: fsam7400 -- kill switch for Fujitsu Siemens Amilo M
+    7400"
+  * Revert "ubuntu: omnibook: fix source file newline"
+  * Revert "ubuntu: omnibook -- update BOM"
+  * Revert "SAUCE: Make CONFIG_{OMNIBOOK, AVERATEC_5100P, PACKARDBELL_E5}
+    depend on X86"
+  * Revert "ubuntu: omnibook -- Added missing BOM file"
+  * Revert "ubuntu: omnibook -- support Toshiba (HP) netbooks"
+  * Revert "ubuntu: nx-emu - i386: mmap randomization for executable
+    mappings"
+  * Revert "SAUCE: disable_nx should not be in __cpuinitdata section for
+    X86_32"
+  * Revert "ubuntu: nx-emu - i386: NX emulation"
+  * Revert "ubuntu: rfkill drivers -- version 1.3"
+  * Temporarily disable module check
+  * [Config] Remove CONFIG_FSAM7400
+  * [Config] Remove CONFIG_OMNIBOOK
+  * [Config] Update configs
+  * Rebase to v3.4-rc7
+  * SAUCE: genirq: export handle_edge_irq() and irq_to_desc()
+
+  [ Tim Gardner ]
+
+  * Updated generic-pae description
+  * Rebase to v3.4-rc6
+  * install-tools depends on build targets
+
+  [ Upstream Kernel Changes ]
+
+  * kconfig: in debug mode some 0 length message prints occur
+  * rebase to v3.4-rc7
+  * rebase to v3.3-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 14 May 2012 08:22:56 -0700
+
+linux (3.4.0-1.3) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] control.stub is an intermediate product not a dependancy
+    - LP: #992414
+
+  [ Leann Ogasawara ]
+
+  * remove i386 generic from getabis
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) b43: only reload config after successful initialization
+    - LP: #950295
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 02 May 2012 09:48:14 -0700
+
+linux (3.4.0-1.2) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] add build depends for flex, bison and pkg-config
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 01 May 2012 13:15:41 +0100
+
+linux (3.4.0-1.1) quantal; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: overlayfs -- overlayfs: apply device cgroup and security
+    permissions to overlay files
+    - LP: #915941, #918212
+    - CVE-2012-0055
+
+  [ Leann Ogasawara ]
+
+  * Open Q
+  * Rebase to v3.4-rc5
+  * [Config] Temporarily disable CONFIG_TOUCHSCREEN_EETI on arm
+  * [Config] Temporarily disable CONFIG_TOUCHSCREEN_EGALAX on arm
+  * [Config] Temporarily disable CONFIG_EZX_PCAP on arm
+  * [Config] Temporarily disable CONFIG_MFD_OMAP_USB_HOST on arm
+  * [Config] Temporarily disable CONFIG_LIS3L02DQ on arm
+  * [Config] Temporarily disable CONFIG_USB_EHCI_HCD_PLATFORM on arm
+  * [Config] Temporarily disable CONFIG_TI_CPSW on arm
+  * [Config] Temporarily disable CONFIG_AX88796 on arm
+
+  [ Upstream Kernel Changes ]
+
+  * vfs: pass struct path to __dentry_open()
+  * vfs: add i_op->open()
+  * vfs: export do_splice_direct() to modules
+  * vfs: introduce clone_private_mount()
+  * overlay filesystem
+  * overlayfs: add statfs support
+  * overlayfs: implement show_options
+  * overlay: overlay filesystem documentation
+  * fs: limit filesystem stacking depth
+  * overlayfs: follow header cleanup
+  * overlayfs: switch from d_alloc_root() to d_make_root()
+  * overlayfs: update touch_atime() usage
+  * rebase to v3.4-rc5
+    - LP: #950490
+  * rebase to v3.4-rc4
+  * rebase to v3.4-rc3
+  * rebase to v3.4-rc2
+  * rebase to v3.4-rc1
+  * rebase to v3.3
+  * rebase to v3.3-rc7
+  * rebase to v3.3-rc6
+  * rebase to v3.3-rc5
+  * rebase to v3.3-rc4
+    - LP: #900802
+    - LP: #930842
+  * rebase to v3.3-rc3
+    - LP: #924320
+    - LP: #923316
+    - LP: #923409
+    - LP: #918254
+  * rebase to v3.3-rc2
+  * rebase to v3.3-rc1
+    - LP: #795823
+    - LP: #909419
+    - LP: #910792
+    - LP: #878701
+    - LP: #724831
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 25 Jan 2012 06:50:04 -0800
+
+linux (3.2.0-10.18) precise; urgency=low
+
+  [ Tim Gardner ]
+
+  * SAUCE: ecryptfs: Print inode on metadata error
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "proc: enable writing to /proc/pid/mem"
+    - LP: #919115
+    - CVE-2012-0056
+  * (pre-stable) ALSA: HDA: Use LPIB position fix for Macbook Pro 7, 1
+    - LP: #909419
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 24 Jan 2012 10:15:12 +0000
+
+linux (3.2.0-10.17) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: overlayfs -- fs: limit filesystem stacking depth"
+  * Revert "SAUCE: overlayfs -- overlay: overlay filesystem documentation"
+  * Revert "SAUCE: overlayfs -- overlayfs: implement show_options"
+  * Revert "SAUCE: overlayfs -- overlayfs: add statfs support"
+  * Revert "SAUCE: overlayfs -- overlay filesystem"
+  * Revert "SAUCE: overlayfs -- vfs: introduce clone_private_mount()"
+  * Revert "SAUCE: overlayfs -- vfs: export do_splice_direct() to modules"
+  * Revert "SAUCE: overlayfs -- vfs: add i_op->open()"
+  * ensure debian/ is not excluded from git by default
+  * add new scripting to handle buglinks in rebases
+  * ubuntu: overlayfs -- overlayfs: add statfs support
+  * ubuntu: overlayfs -- overlayfs: apply device cgroup and security
+    permissions to overlay files
+    - LP: #915941, #918212
+    - CVE-2012-0055
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs -- overlayfs: implement show_options
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: dmar: disable if ricoh multifunction detected"
+  * [Config] Disable CONFIG_INTEL_IOMMU_DEFAULT_ON
+    - LP: #907377, #911236
+  * [Config] Enable CONFIG_IRQ_REMAP
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs -- vfs: pass struct path to __dentry_open()
+  * ubuntu: overlayfs -- vfs: add i_op->open()
+  * ubuntu: overlayfs -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs -- overlay filesystem
+  * ubuntu: overlayfs -- fs: limit filesystem stacking depth
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs -- overlay: overlay filesystem documentation
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) x86/PCI: amd: factor out MMCONFIG discovery
+    - LP: #647043
+  * (pre-stable) PNP: work around Dell 1536/1546 BIOS MMCONFIG bug that
+    breaks USB
+    - LP: #647043
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 16 Jan 2012 07:10:08 -0800
+
+linux (3.2.0-9.16) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] Enable numerous CONFIG_VIDEO_* cards on ARM
+  * [Config] pull ARM sound modules =m
+  * [Config] CONFIG_RTC_DRV_TEST is for testing only
+  * [Config] CONFIG_USB_DUMMY_HCD is testing only
+  * [Config] CONFIG_USB_FILE_STORAGE is deprecated
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] Temporarily disable CONFIG_CAN_TI_HECC on armel"
+  * [Config] Enable CONFIG_HW_RANDOM_PASEMI=m
+  * [Config] Enable CONFIG_MMC_TMIO=m
+  * [Config] Enable CONFIG_MTD_NAND_FSL_ELBC=m
+  * [Config] Enable CONFIG_ISI=m
+  * [Config] Enable CONFIG_MMC=y
+  * [Config] Enable CONFIG_LIRC_PARALLEL=m
+  * [Config] Enable CONFIG_MAC_EMUMOUSEBTN=m
+  * [Config] Enable CONFIG_CHR_DEV_SG=y
+  * [Config] Enable CONFIG_GPIO_PCA953X=m
+  * [Config] Enable CONFIG_GPIO_TWL4030=m
+  * [Config] Enable CONFIG_INET_DIAG=m
+  * [Config] Enable CONFIG_NLS_ISO8859_1=m
+  * [Config] Enable CONFIG_NVRAM=m
+  * [Config] Enable CONFIG_SLIP=m
+  * [Config] Enable CONFIG_PC300TOO=m
+  * [Config] Enable CONFIG_TUN=y
+  * [Config] Enable CONFIG_NET_CLS_CGROUP=m
+  * [Config] Enable CONFIG_THERMAL=y
+  * [Config] Enable CONFIG_PPP=y
+  * [Config] Enable CONFIG_PCI_STUB=m
+  * Rebase to v3.2.1
+  * [Config] Enable CONFIG_RTL8192E=m
+  * [Config] Enable CONFIG_RTS5139=m
+
+  [ Stefan Bader ]
+
+  * [Config] Make CONFIG_VIRTIO_(NET|BLK)=y
+
+  [ Upstream Kernel Changes ]
+
+  * ARM: restart: add restart hook to machine_desc record
+  * ARM: restart: allow platforms more flexibility specifying restart mode
+  * ARM: restart: move reboot failure handing into machine_restart()
+  * ARM: restart: remove argument to setup_mm_for_reboot()
+  * ARM: 7159/1: OMAP: Introduce local common.h files
+  * ARM: restart: only perform setup for restart when soft-restarting
+  * ARM: 7189/1: OMAP3: Fix build break in cpuidle34xx.c because of irq
+    function
+  * ARM: idmap: populate identity map pgd at init time using .init.text
+  * ARM: suspend: use idmap_pgd instead of suspend_pgd
+  * ARM: proc-*.S: place cpu_reset functions into .idmap.text section
+  * ARM: idmap: use idmap_pgd when setting up mm for reboot
+  * ARM: head.S: only include __turn_mmu_on in the initial identity mapping
+  * ARM: SMP: use idmap_pgd for mapping MMU enable during secondary booting
+  * ARM: 7194/1: OMAP: Fix build after a merge between v3.2-rc4 and ARM
+    restart changes
+  * ARM: lib: add call_with_stack function for safely changing stack
+  * ARM: reset: implement soft_restart for jumping to a physical address
+  * ARM: stop: execute platform callback from cpu_stop code
+  * ARM: kexec: use soft_restart for branching to the reboot buffer
+  * ARM: restart: omap: use new restart hook
+  * topdown mmap support
+    - LP: #861296
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v3.2.1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 13 Jan 2012 20:32:08 +0100
+
+linux (3.2.0-8.15) precise; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_ACPI_PROCFS
+  * Remove server from getabis
+  * Temporarily disable module check
+  * [Config] Disable CONFIG_MTD_TESTS
+  * [Config] Disable CONFIG_X86_E_POWERSAVER
+  * [Config] Set CONFIG_ARCNET=m
+  * [Config] Enable CONFIG_ATM_DUMMY=m
+  * [Config] Enable CONFIG_BLK_DEV_MD=y
+  * ubuntu: fsam7400 select CHECK_SIGNATURE and depend on X86
+  * [Config] Enable CONFIG_BLK_DEV_SD=y
+  * [Config] Enable CONFIG_BLK_DEV_SR=y
+  * [Config] Enable CONFIG_BLK_DEV_UB=m
+  * [Config] Enable CONFIG_COPS=m
+  * [Config] Enable CONFIG_DVB_USB_EC168=m
+  * [Config] Enable CONFIG_ENC28J60=m
+  * [Config] Enable CONFIG_FB_UVESA=m
+  * [Config] Enable CONFIG_FB_ATY=m
+  * [Config] Enable CONFIG_BROADCOM_PHY=y
+  * [Config] Enable CONFIG_CICADA_PHY=y
+  * [Config] Enable CONFIG_DAVICOM_PHY=y
+  * [Config] Enable CONFIG_ICPLUS_PHY=y
+  * [Config] Enable CONFIG_LSI_ET1011C_PHY=y
+  * [Config] Enable CONFIG_LXT_PHY=y
+  * [Config] Enable CONFIG_MARVELL_PHY=y
+  * [Config] Enable CONFIG_NATIONAL_PHY=y
+  * [Config] Enable CONFIG_QSEMI_PHY=y
+  * [Config] Enable CONFIG_SMSC_PHY=y
+  * [Config] Enable CONFIG_VITESSE_PHY=y
+  * Add 3w-sas to scsi-modules
+    - LP: #776542
+
+  [ Mathieu Trudel-Lapierre ]
+
+  * SAUCE: ipv6: make the net.ipv6.conf.all.use_tempaddr sysctl propagate
+    to interface settings
+
+  [ Paolo Pisati ]
+
+  * Revert "SAUCE: omap3: beagle: if rev unknown, assume xM revision C"
+    - LP: #912199
+  * Revert "SAUCE: omap3: beagle: detect new xM revision B"
+    - LP: #912199
+  * Revert "SAUCE: omap3: beaglexm: fix DVI initialization"
+    - LP: #912199
+
+  [ Upstream Kernel Changes ]
+
+  * Bluetooth: Add support for BCM20702A0 [0a5c:21e3]
+    - LP: #906832
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 06 Jan 2012 10:02:03 -0800
+
+linux (3.2.0-8.14) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_SND_USB_6FIRE
+    - LP: #912197
+  * rebase to mainline v3.2 final release
+  * updateconfigs following rebase to v3.2 final
+  * ubuntu: AUFS -- add BOM and automated update script
+  * ubuntu: AUFS -- include the aufs_types.h file in linux-libc-headers
+    - LP: #684666
+  * ubuntu: AUFS -- update aufs-update to track new locations of headers
+  * ubuntu: AUFS -- clean up the aufs updater and BOM
+  * ubuntu: AUFS -- documentation on updating aufs2
+  * ubuntu: AUFS -- aufs3-base.patch
+  * ubuntu: AUFS -- aufs3-standalone.patch
+  * ubuntu: AUFS -- fix undefined __devcgroup_inode_permission
+  * ubuntu: AUFS -- fix undefined security_path_link
+  * ubuntu: AUFS -- update to 4cf5db36bcd9748e8e7270022f295f84d1fc2245
+  * ubuntu: AUFS -- updateconfigs following update
+  * ubuntu: AUFS -- suppress benign plink warning messages
+    - LP: #621195
+  * ubuntu: AUFS -- enable in config and makefile
+  * ubuntu: AUFS -- disable in favor of overlayfs
+  * [Config] linux-virtual -- should include the extX modules
+    - LP: #912308
+
+  [ Tyler Hicks ]
+
+  * SAUCE: eCryptfs: Improve statfs reporting
+    - LP: #885744
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to upstream v3.2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 26 Dec 2011 20:24:30 -0800
+
+linux (3.2.0-7.13) precise; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to upstream 3.2-rc7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 19 Dec 2011 09:14:34 -0800
+
+linux (3.2.0-6.12) precise; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to upstream v3.2-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 16 Dec 2011 10:19:02 -0800
+
+linux (3.2.0-5.11) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * enforcer -- allow arch and flavour predicates to take lists
+  * enforcer -- simplify armel/armhf specific options
+  * enforcer -- fix incorrectly specified flavour matches
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable IRQ_REMAP
+  * [Config] Enable CONFIG_SENSORS_LM95245=m
+  * [Config] Enable CONFIG_SENSORS_MAX1668=m
+  * [Config] Enable CONFIG_SENSORS_NTC_THERMISTOR=m
+  * [Config] Enable CONFIG_SENSORS_MAX6639=m
+  * [Config] Enable CONFIG_SENSORS_MAX6642=m
+  * [Config] Enable CONFIG_SENSORS_LINEAGE=m
+  * [Config] Enable CONFIG_CRYPTO_SALSA20=m
+  * [Config] Enable CONFIG_PATA_TOSHIBA=m
+  * [Config] Enable CONFIG_POHMELFS=m
+  * [Config] Enable CONFIG_NET_PACKET_ENGINE=y
+  * [Config] Enable CONFIG_PATA_OPTI=m
+  * add overlayfs to virtual inclusion list
+    - LP: #903897
+  * add veth to virtual inclusion list
+    - LP: #903897
+  * SAUCE: resolve WARNING: at drivers/block/floppy.c:2929 do_fd_request
+
+  [ Paolo Pisati ]
+
+  * [Config] DEFAULT_MMAP_MIN_ADDR=32k on arm
+    - LP: #903346
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_LOCKUP_DETECTOR=y
+    - LP: #903615
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to upstream 55b02d2f
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 12 Dec 2011 07:08:10 -0800
+
+linux (3.2.0-4.10) precise; urgency=low
+
+  [ Kyle McMartin ]
+
+  * SAUCE: dmar: disable if ricoh multifunction detected
+    - LP: #894070
+
+  [ Seth Forshee ]
+
+  * SAUCE: dell-wmi: Demote unknown WMI event message to pr_debug
+    - LP: #581312
+
+  [ Tim Gardner ]
+
+  * Start new release, Bump ABI, rebase to 3.2-rc5
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_SENSORS_AK8975=m
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sat, 10 Dec 2011 08:57:04 -0700
+
+linux (3.2.0-3.9) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: ext4: correct partial write discard size calculation
+    - LP: #894768
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: x86, microcode, AMD: Restrict microcode reporting"
+    - LP: #892615
+
+  [ Matthew Garrett ]
+
+  * SAUCE: pci: Rework ASPM disable code
+
+  [ Upstream Kernel Changes ]
+
+  * x86: Fix boot failures on older AMD CPU's
+    - LP: #892615
+  * EHCI : Fix a regression in the ISO scheduler
+    - LP: #899165
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 05 Dec 2011 10:37:36 -0800
+
+linux (3.2.0-3.8) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * armhf -- add d-i configuration
+  * armhf -- disable ABI checks for armhf
+  * armhf -- add arch to getabis config
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 03 Dec 2011 14:22:52 +0000
+
+linux (3.2.0-3.7) precise; urgency=low
+
+  [ Stefan Bader ]
+
+  * SAUCE: x86/paravirt: PTE updates in k(un)map_atomic need to be
+    synchronous, regardless of lazy_mmu mode
+    - LP: #854050
+
+  [ Tim Gardner ]
+
+  * rebase to v3.2-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 02 Dec 2011 11:53:56 -0800
+
+linux (3.2.0-2.6) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * armhf -- fix omap flavour to build on armhf
+  * [Config] CONFIG_PATA_MACIO=y to fix MAC qemu boot
+
+  [ Borislav Petkov ]
+
+  * SAUCE: x86, microcode, AMD: Restrict microcode reporting
+    - LP: #892615
+
+  [ Colin Watson ]
+
+  * Add pata_macio to pata-modules
+
+  [ Tim Gardner ]
+
+  * [Config] Prefer crda over wireless-crda
+  * [Config] Fix virtual inclusion list.
+    - LP: #897795
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 30 Nov 2011 06:09:35 -0800
+
+linux (3.2.0-2.5) precise; urgency=low
+
+  [ Paolo Pisati ]
+
+  * [Config] PANEL_DVI=y
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 28 Nov 2011 09:13:24 -0800
+
+linux (3.2.0-2.4) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v3.2-rc3
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: xen: Do not use pv spinlocks on HVM"
+  * Revert "fix ERROR: __devcgroup_inode_permission undefined"
+  * Revert "olpc_dcon_xo_1_5 needs delay.h"
+  * Revert "olpc_dcon_xo_1 needs delay.h"
+  * rebase to 6fe4c6d4
+  * [Config] updateconfigs after rebase to 6fe4c6d4
+
+  [ Tim Gardner ]
+
+  * [Config] Replace wireless-crda with crda,wireless-regdb
+    - LP: #856421
+  * [Config] Relax the dependencies on crda
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) HID: bump maximum global item tag report size to 96 bytes
+    - LP: #724831
+  * Ubuntu: remove coreutils|fileutils package dependency
+    - LP: #892814
+  * iio: iio_event_getfd -- fix ev_int build failure
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v3.2-rc3
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 24 Nov 2011 16:20:45 +0000
+
+linux (3.2.0-1.3) precise; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * Ubuntu: Add ext2 to fs-core-modules
+    - LP: #893395
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 21 Nov 2011 20:42:33 -0800
+
+linux (3.2.0-1.2) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_NFC and associated devices
+  * SAUCE: allow brcmsmac and b43 to both build
+
+  [ Soren Hansen ]
+
+  * Add ixgbe driver to d-i
+    - LP: #891969
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 21 Nov 2011 08:33:46 -0800
+
+linux (3.2.0-1.1) precise; urgency=low
+  [ Andy Whitcroft ]
+
+  * armhf -- enable armhf and create the first flavours
+  * SAUCE: ensure root is ready before running usermodehelpers in it
+  * [Config] enforcer -- ensure CONFIG_FAT_FS is built-in on arm
+
+  [ Leann Ogasawara ]
+
+  * Temporarily ignore module check
+  * [Config] Enable PCI_IOV on powerpc
+  * [Config] Temporarily disable CONFIG_PASEMI_MAC on powerpc
+  * rebase to v3.2-rc2
+  * SAUCE: include <linux/export.h> for cpuidle34xx arm build
+  * SAUCE: include <linux/kernel.h> for linux/mtd/map.h arm build
+  * SAUCE: include <linux/printk.h> and <stdarg.h> for mmc_core arm build
+  * SAUCE: select ARM_AMBA if OMAP3_EMU
+  * [Config] updateconfigs after select ARM_AMBA
+  * [Config] Temporarily disable CONFIG_KVM_BOOK3S_32 on powerpc
+  * [Config] Enable CONFIG_EXT2_FS=m
+  * [Config] Build in CONFIG_SATA_AHCI=y
+  * Resolve linux-image-extra's install dependency
+
+  [ Seth Forshee ]
+
+  * [Config] Enable EVENT_POWER_TRACING_DEPRECATED=y for powertop
+  * SAUCE: (drop after 3.2) Input: ALPS - move protocol information to
+    Documentation
+  * SAUCE: (drop after 3.2) Input: ALPS - add protocol version field in
+    alps_model_info
+  * SAUCE: (drop after 3.2) Input: ALPS - remove assumptions about packet
+    size
+  * SAUCE: (drop after 3.2) Input: ALPS - add support for protocol versions
+    3 and 4
+  * SAUCE: (drop after 3.2) Input: ALPS - add semi-MT support for v3
+    protocol
+  * SAUCE: (drop after 3.2) Input: ALPS - add documentation for protocol
+    versions 3 and 4
+
+  [ Stefan Bader ]
+
+  * [Config] Built-in xen-netfront and xen-blkfront
+  * Fix build of dm-raid45 and re-enable it
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_USB_XHCI_HCD=y
+    - LP: #886167
+  * [Config] CONFIG_R6040=m
+    - LP: #650899
+  * SAUCE: Add a new entry (413c:8197) to Bluetooth USB device ID table
+    - LP: #854399
+  * [Config] Consolidated amd64 server flavour into generic
+  * [Config] updateconfigs after rebase to 3.2-rc1
+  * [Config] Disabled dm-raid4-5
+  * [Config] Disabled ndiswrapper
+  * [Config] Disable vt6656
+  * [Config] exclude ppp-modules for virtual flavour
+  * [Config] CONFIG_MEMSTICK_R592=m
+    - LP: #238208
+
+  [ Upstream Kernel Changes ]
+
+  * CHROMIUM: seccomp_filter: new mode with configurable syscall filters
+    - LP: #887780
+  * CHROMIUM: seccomp_filter: add process state reporting
+    - LP: #887780
+  * CHROMIUM: seccomp_filter: Document what seccomp_filter is and how it
+    works.
+    - LP: #887780
+  * CHROMIUM: x86: add HAVE_SECCOMP_FILTER and seccomp_execve
+    - LP: #887780
+  * CHROMIUM: arm: select HAVE_SECCOMP_FILTER
+    - LP: #887780
+  * CHROMIUM: seccomp_filters: move to btrees
+  * CHROMIUM: enable CONFIG_BTREE
+  * CHROMIUM: seccomp_filter: kill NR_syscall references
+  * CHROMIUM: seccomp_filters: guard all ftrace wrapper code
+  * CHROMIUM: seccomp_filters: clean up warnings; kref mistake
+  * CHROMIUM: seccomp_filter: remove "skip" from copy and add drop helper
+  * CHROMIUM: seccomp_filter: allow CAP_SYS_ADMIN management of execve
+  * CHROMIUM: seccomp_filter: inheritance documentation
+  * CHROMIUM: seccomp_filter: make inherited filters composable
+  * CHROMIUM: Fix seccomp_t compile error
+    - LP: #887780
+  * CHROMIUM: Fix kref usage
+    - LP: #887780
+  * CHROMIUM: enable CONFIG_SECCOMP_FILTER and CONFIG_HAVE_SECCOMP_FILTER
+  * rebase to v3.2-rc2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 31 Oct 2011 09:24:39 -0400
+
+linux (3.1.0-2.3) precise; urgency=low
+
+  [ Tim Gardner ]
+
+  * Add postinit and postrm scripts to the extras package
+    - LP: #882120
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 28 Oct 2011 12:48:33 -0700
+
+linux (3.1.0-2.2) precise; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * debian: add locking to protect debian/files from parallel update
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.1
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 19 Oct 2011 07:12:38 -0700
+
+linux (3.1.0-1.1) precise; urgency=low
+
+  [ Andiry Xu ]
+
+  * SAUCE: (drop during 3.2 merge) xHCI: AMD isoc link TRB chain bit quirk
+    - LP: #872811
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: compcache -- follow changes to bd_claim/bd_release"
+    - LP: #832694
+  * Revert "ubuntu: compcache -- version 0.5.3"
+    - LP: #832694
+  * [Config] standardise CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+  * [Config] Enable CONFIG_MACVTAP=m
+    - LP: #822601
+  * record the compiler in the ABI and check for inconsistant builds
+  * [Config] move ECRYPT_FS back to =y for all architectures
+    - LP: #827197
+  * [Config] enable CONFIG_DRM_VMWGFX=m
+    - LP: #698009
+  * [Config] re-fix ECRYPT_FS=y
+    - LP: #827197
+  * enforcer -- ensure we have CONFIG_ECRYPT_FS=y
+    - LP: #827197
+  * [Config] dropping compcache configuration options
+  * [Config] standardise on HZ=250
+  * SAUCE: headers_install: fix #include "..." usage for userspace
+    - LP: #824377
+  * make module-inclusion selection retain the left overs
+  * add a new linux-image-extras package for virtual
+
+  [ Colin Watson ]
+
+  * Deliver more Atheros, Ralink, and iwlagn NIC drivers to d-i
+
+  [ edwin_rong ]
+
+  * SAUCE: Staging: add driver for Realtek RTS5139 cardreader
+    - LP: #824273
+
+  [ Greg Kroah-Hartman ]
+
+  * SAUCE: staging: rts5139: add vmalloc.h to some files to fix the build.
+    - LP: #824273
+
+  [ Jesse Sung ]
+
+  * SAUCE: Unregister input device only if it is registered
+    - LP: #839238
+
+  [ Jiri Kosina ]
+
+  * SAUCE: HID: add MacBookAir4, 2 to hid_have_special_driver[]
+
+  [ Joshua V. Dillon ]
+
+  * SAUCE: HID: add support for MacBookAir4,2 keyboard.
+
+  [ Kees Cook ]
+
+  * [Config] enable and enforce SECCOMP_FILTER on x86
+
+  [ Keng-Yu Lin ]
+
+  * [Config] Enable CONFIG_RTS5139=m on i386/amd64
+    - LP: #824273
+
+  [ Leann Ogasawara ]
+
+  * Revert "ubuntu: overlayfs -- ovl: make lower mount read-only"
+  * Revert "ubuntu: overlayfs -- fs: limit filesystem stacking depth"
+  * Revert "ubuntu: overlayfs -- ovl: improve stack use of lookup and
+    readdir"
+  * Revert "ubuntu: overlayfs -- ovl: fix overlayfs over overlayfs"
+  * Revert "ubuntu: overlayfs -- overlayfs: implement show_options"
+  * Revert "ubuntu: overlayfs -- overlayfs: add statfs support"
+  * Revert "ubuntu: overlayfs -- overlay filesystem"
+  * Revert "ubuntu: overlayfs -- overlay: overlay filesystem documentation"
+  * Revert "SAUCE: ARM: OMAP: Add macros for comparing silicon revision"
+  * Revert "SAUCE: OMAP: DSS2: check for both cpu type and revision, rather
+    than just revision"
+  * Revert "SAUCE: OMAP: DSS2: enable hsclk in dsi_pll_init for OMAP36XX"
+  * Revert "ubuntu: fsam7400 disable driver"
+    - LP: #876030
+  * rebase to v3.1-rc1
+  * [Config] updateconfigs after rebase to v3.1-rc1
+  * rebase to v3.1-rc2
+  * [Config] Updateconfigs after rebase to v3.1-rc2
+  * ubuntu: Yama - update calls to generic_permission() and
+    inode->i_op->permission()
+  * ubuntu: ndiswrapper -- remove netdev_priv macro
+  * ubuntu: aufs -- Temporarily disable due to build failure
+  * [Config] Diable INTEL_MID_PTI on armel
+  * [Config] Temporarily disable CONFIG_FTMAC100 on armel
+  * [Config] Temporarily disable CONFIG_FTGMAC100 on armel
+  * [Config] Temporarily disable CONFIG_CAN_TI_HECC on armel
+  * [Config] Temporarily disable CONFIG_VIDEO_OMAP2_VOUT on armel
+  * [Config] Set CONFIG_DM_MIRROR=m on amd64, i386, and arm
+  * [Config] Set CONFIG_DM_MULTIPATH=m on amd64, i386, and arm
+  * [Config] Set CONFIG_DM_SNAPSHOT=m on amd64, i386, and arm
+  * [Config] Enable CONFIG_EDAC_AMD8111=m on powerpc
+  * [Config] Enable CONFIG_EDAC_AMD8131=m on powerpc
+  * [Config] Enable CONFIG_EDAC_CPC925=m on powerpc
+  * [Config] Enable CONFIG_EDAC_PASEMI=m on powerpc
+  * [Config] Enable CONFIG_ECHO=m on powerpc
+  * [Config] Enable CONFIG_ET131X=m on powerpc
+  * [Config] Set CONFIG_FB_MATROX=m
+  * [Config] Enable CONFIG_FB_UDL=m on powerpc
+  * [Config] Set CONFIG_FB_VIRTUAL=n
+  * [Config] Enable CONFIG_FB_VGA16=m on powerpc
+  * [Config] Enable CONFIG_GPIO_MAX732X=m on arm
+  * [Config] Enable CONFIG_GPIO_PCF857X=m on arm
+  * [Config] Set CONFIG_HOTPLUG_PCI_FAKE=m
+  * [Config] Enable CONFIG_HOTPLUG_PCI=y on powerpc
+  * [Config] Enable CONFIG_HOTPLUG_PCI_CPCI=y on powerpc
+  * [Config] Enable CONFIG_HP_ILO=m on powerpc-smp
+  * [Config] Enable CONFIG_I2C_PASEMI=m on powerpc
+  * [Config] Enable CONFIG_IBM_BSR=m on powerpc
+  * [Config] Enable CONFIG_IBMVETH=m on powerpc
+  * [Config] Enable CONFIG_IDE_PHISON=m on powerpc
+  * [Config] Enable CONFIG_IGB=m on powerpc
+  * [Config] Enable CONFIG_IIO=m on powerpc
+  * [Config] Enable CONFIG_INFINIBAND_NES=m
+  * [Config] Enable CONFIG_IPMI_HANDLER=m on arm
+  * [Config] Enable CONFIG_IWL3945=m on powerpc
+  * [Config] Disable CONFIG_KVM_BOOK3S_64
+  * [Config] Enable CONFIG_LAPBETHER=m on arm
+  * [Config] Enable CONFIG_LEDS_GPIO=m on powerpc
+  * [Config] Enable CONFIG_LEDS_CLEVO_MAIL=m all arch's
+  * [Config] Enable CONFIG_LEDS_PCA9532=m on powerpc
+  * [Config] Enable CONFIG_LEDS_PCA955X=m on powerpc
+  * [Config] Enable CONFIG_LEDS_TRIGGER_DEFAULT_ON=m on powerpc
+  * [Config] Set CONFIG_LEDS_TRIGGER_HEARTBEAT=m on arm and powerpc
+  * [Config] Set CONFIG_LEDS_TRIGGER_TIMER=m on powerpc
+  * [Config] Enable CONFIG_LINE6_USB=m on arm and powerpc
+  * [Config] Enable CONFIG_MEMSTICK=m on arm
+  * [Config] Enable CONFIG_MTD_AFS_PARTS=m on arm
+  * [Config] Enable CONFIG_MTD_ALAUDA=m on arm
+  * [Config] Enable CONFIG_MTD_AR7_PARTS=m on arm
+  * [Config] Enable CONFIG_MTD_ARM_INTEGRATOR=m on arm
+  * [Config] Enable CONFIG_MOXA_SMARTIO=m on powerpc
+  * [Config] Enable CONFIG_MTD_DATAFLASH=m on arm
+  * [Config] Enable CONFIG_MTD_GPIO_ADDR=m on arm
+  * [Config] Enable CONFIG_MTD_IMPA7=m on arm
+  * [Config] Enable CONFIG_MTD_NAND_GPIO=m on arm
+  * [Config] Enable CONFIG_MTD_NAND_NANDSIM=m on arm
+  * [Config] Enable CONFIG_MTD_NAND_PASEMI=m on powerpc
+  * [Config] Enable CONFIG_MTD_NAND_PLATFORM=m on arm
+  * [Config] Enable CONFIG_MTD_NAND_TMIO=m on arm
+  * [Config] Enable CONFIG_MTD_SST25L=m on arm
+  * [Config] Enable CONFIG_NET_CLS_CGROUP=y on arm
+  * [Config] Enable CONFIG_NET_CLS_FLOW=m on arm
+  * [Config] Enable CONFIG_NET_CLS_U32=m on arm
+  * [Config] Enable CONFIG_NET_DCCPPROBE=m on arm
+  * [Config] Enable CONFIG_NET_SCH_INGRESS=m on arm
+  * [Config] Enable CONFIG_NET_TCPPROBE=m on arm
+  * [Config] Enable CONFIG_PASEMI_MAC=m on powerpc
+  * [Config] Enable CONFIG_PATA_NS87410=m on powerpc
+  * [Config] Enable CONFIG_I2C_GPIO=m on powerpc64-smp
+  * [Config] Enable CONFIG_PANEL=m on powerpc
+  * [Config] Enable CONFIG_PATA_CMD640_PCI=m on powerpc
+  * SAUCE: x86: reboot: Make Dell Latitude E6520 use reboot=pci
+    - LP: #833705
+  * [Config] Add CONFIG_EFI_VARS=y to the enforcer
+    - LP: #837332
+  * [Config] Update CONFIG_EFI_VARS enforcer check
+  * [Config] Add aufs to virtual flavor inclusion list
+    - LP: #844159
+  * SAUCE: x86: reboot: Make Dell Optiplex 790 use reboot=pci
+    - LP: #818933
+  * SAUCE: x86: reboot: Make Dell Optiplex 990 use reboot=pci
+    - LP: #768039
+  * SAUCE: x86: reboot: Make Dell Latitude E6220 use reboot=pci
+    - LP: #838402
+  * [Config] Add igbvf to the virtual flavor inclusion list
+    - LP: #794570
+  * [Config] Add ixgbevf to the virtual inclusion list
+    - LP: #872411
+  * [Config] Transition -generic and -server to be identical
+  * rebase to v3.1-rc10
+
+  [ Luke Yelavich ]
+
+  * [Config] Disable legacy IDE drivers on powerpc
+
+  [ Ming Lei ]
+
+  * SAUCE: fireware: add NO_MSI quirks for o2micro controller
+    - LP: #801719
+  * SAUCE: ata_piix: make DVD Drive recognisable on systems with Intel
+    Sandybridge chipsets(v2)
+    - LP: #737388, #782389, #794642
+
+  [ Paolo Pisati ]
+
+  * [Config] Compile-in vfat support for armel
+    - LP: #853783
+
+  [ Randy Dunlap ]
+
+  * SAUCE: staging: fix rts5139 depends & build
+    - LP: #824273
+
+  [ Rene Bolldorf ]
+
+  * SAUCE: (drop after 3.0) ideapad: Check if acpi already handle backlight
+    power in 'ideapad_backlight_notify_power' to avoid a page fault
+
+  [ Seth Forshee ]
+
+  * SAUCE: (no-up) Input: elantech - Add v3 hardware support
+    - LP: #681904
+  * SAUCE: (drop after 3.1) usb_storage: Don't freeze in usb-stor-scan
+    - LP: #810020
+
+  [ Stefan Bader ]
+
+  * (config) Package macvlan and macvtap for virtual
+  * [Config] Force perf to use libiberty for demangling
+    - LP: #783660
+  * SAUCE: xen: Do not use pv spinlocks on HVM
+    - LP: #838026
+
+  [ Tim Gardner ]
+
+  * [Config] Clean up tools rules
+  * [Config] Package x86_energy_perf_policy and turbostat
+    - LP: #797556
+  * rebase to v3.1-rc3
+  * [Config] Simplify binary-udebs dependencies
+  * [Config] kernel preparation cannot be parallelized
+  * [Config] Linearize module/abi checks
+  * [Config] Linearize and simplify tree preparation rules
+  * [Config] Build kernel image in parallel with modules
+  * [Config] Set concurrency for kmake invocations
+  * [Config] Improve install-arch-headers speed
+  * [Config] Fix binary-perarch dependencies
+  * [Config] Removed stamp-flavours target
+  * [Config] Serialize binary indep targets
+  * [Config] Use build stamp directly
+  * [Config] Restore prepare-% target
+  * rebase to v3.1-rc4
+  * rebase to v3.1-rc5
+  * [Config] Disable makedumpfile for i386/amd64
+  * rebase to v3.1-rc6
+  * [Config] Fix binary-% build target
+  * rebase to v3.1-rc7
+  * rebase to v3.1-rc8
+  * SAUCE: Add a new entry (413c:8197) to Bluetooth USB device ID table
+    - LP: #854399
+  * [Config] Enable ftrace support in the mac80211 layer
+    - LP: #865171
+  * rebase to v3.1-rc9
+  * SAUCE: usb/core/devio.c: Check for printer class specific request
+    - LP: #872711
+
+  [ Upstream Kernel Changes ]
+
+  * overlay filesystem
+  * overlayfs: add statfs support
+  * overlayfs: implement show_options
+  * overlay: overlay filesystem documentation
+  * fs: limit filesystem stacking depth
+
+  [ Will Drewry ]
+
+  * SAUCE: seccomp_filter: new mode with configurable syscall filters
+  * SAUCE: seccomp_filter: add process state reporting
+  * SAUCE: seccomp_filter: Document what seccomp_filter is and how it
+    works.
+  * SAUCE: seccomp_filter: add HAVE_SECCOMP_FILTER and seccomp_execve
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.1-rc1
+  * rebase to v3.1-rc2
+  * rebase to v3.1-rc3
+    +CONFIG_BLK_DEV_BSGLIB=y
+    +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+    -CONFIG_VIDEO_OMAP2_VOUT_VRFB=y
+  * rebase to v3.1-rc4
+  * rebase to v3.1-rc5
+  * rebase to v3.1-rc6
+  * rebase to v3.1-rc7
+  * rebase to v3.1-rc8
+  * rebase to v3.1-rc9
+  * rebase to v3.1-rc10
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 10 Aug 2011 15:43:38 -0700
+
+linux (3.1.0-1.0) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Open P-series
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 10 Aug 2011 13:42:40 -0700
+
+linux (3.0.0-8.10) oneiric; urgency=low
+
+  [ Adam Jackson ]
+
+  * SAUCE: drm/i915/pch: Fix integer math bugs in panel fitting
+    - LP: #753994
+
+  [ John Johansen ]
+
+  * [Config] Enable missing IPv6 options
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable config IWLWIFI_DEVICE_SVTOOL
+    - LP: #819925
+  * Rebase to 3.0.1
+
+  [ Upstream Kernel Changes ]
+
+  * x86, intel, power: Correct the MSR_IA32_ENERGY_PERF_BIAS message
+  * ALSA: hda - Turn on extra EAPDs on Conexant codecs
+    - LP: #783582
+  * KVM: Remove SMEP bit from CR4_RESERVED_BITS
+    - LP: #796476
+  * KVM: Add SMEP support when setting CR4
+    - LP: #796476
+  * KVM: Mask function7 ebx against host capability word9
+    - LP: #796476
+  * KVM: Add instruction fetch checking when walking guest page table
+    - LP: #796476
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.0.1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 05 Aug 2011 11:32:25 -0700
+
+linux (3.0.0-7.9) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Upstream] add local prefix to oss local change_bits"
+  * Revert "SAUCE: add tracing for user initiated readahead requests"
+  * Revert "SAUCE: vfs: Add a trace point in the mark_inode_dirty function"
+  * Revert "SAUCE: Input: ALPS - Enable Intellimouse mode for Lenovo
+    Zhaoyang E47"
+  * Revert "SAUCE: fix documentation strings for struct input_keymap_entry"
+  * Revert "SAUCE: vt -- fix handoff numbering to 1..n and add range checks
+    (grub)"
+  * Revert "SAUCE: vt -- fix handoff numbering to 1..n and add range
+    checks"
+  * Revert "SAUCE: vt -- allow grub to request automatic vt_handoff"
+  * Revert "SAUCE: vt -- maintain bootloader screen mode and content until
+    vt switch"
+  * [Config] enable CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
+    - LP: #816035
+  * ubuntu: Yama: if an underlying filesystem provides a permissions op use
+    it
+  * SAUCE: (no-up) add tracing for user initiated readahead requests
+  * SAUCE: vt -- maintain bootloader screen mode and content until vt
+    switch
+  * SAUCE: vt -- allow grub to request automatic vt_handoff
+
+  [ Arjan van de Ven ]
+
+  * SAUCE: (no-up) vfs: Add a trace point in the mark_inode_dirty function
+
+  [ Kees Cook ]
+
+  * Revert "SAUCE: (no-up) Disable building the ACPI debugfs source"
+  * [Config] enforce ACPI_CUSTOM_METHOD disabled
+
+  [ Keng-Yu Lin ]
+
+  * SAUCE: (no-up) Input: ALPS - Enable Intellimouse mode for Lenovo
+    Zhaoyang E47
+    - LP: #632884, #803005
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_BLK_DEV_CMD64X=m on powerpc
+    - LP: #513131
+  * [Config] Enable CONFIG_RT2800PCI_RT53XX=y
+    - LP: #815064
+
+  [ Rezwanul Kabir ]
+
+  * SAUCE: (no-up) Add support for Intellimouse Mode in ALPS touchpad on
+    Dell E2 series Laptops
+    - LP: #632884
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "yama: if an underlying filesystem provides a permissions op use
+    it"
+  * Revert "Add support for Intellimouse Mode in ALPS touchpad on Dell E2
+    series Laptops"
+  * Revert "tty: include linux/slab.h for kfree"
+  * Revert "gpio/ml_ioh_gpio: include linux/slab.h for kfree"
+  * Revert "pch_dma: add include/slab.h for kfree"
+  * mmc: Added quirks for Ricoh 1180:e823 lower base clock frequency
+    - LP: #773524
+  * oss: rename local change_bits to avoid powerpc bitsops.h definition
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 25 Jul 2011 09:08:01 -0700
+
+linux (3.0.0-7.8) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: overlayfs -- overlayfs: add statfs support
+  * [Config] enable CONFIG_OVERLAYFS
+
+  [ Erez Zadok ]
+
+  * ubuntu: overlayfs -- overlayfs: implement show_options
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_ALIM7101_WDT=m on powerpc
+  * [Config] Enable CONFIG_ASUS_OLED=m on powerpc
+  * [Config] Disable CONFIG_ATM_DUMMY on arm
+  * [Config] Enable CONFIG_BLK_DEV_DRBD=m on powerpc
+  * Temporarily disable module check on arm
+  * Rebase to 3.0 final
+  * [Config] Enable CONFIG_CAN_TI_HECC=m on arm
+  * [Config] Set CONFIG_CDROM_PKTCDVD=m on amd64 and i386
+  * [Config] Enable CONFIG_CRYPTO_CCM=m on powerpc
+  * [Config] Enable CONFIG_CRYPTO_DEV_HIFN_795X=m on powerpc
+  * [Config] Enable CONFIG_CRYPTO_GCM=m on powerpc
+  * [Config] Set CRYPTO_LZO=m on powerpc64-smp
+  * [Config] Enable CONFIG_DM9000=m on arm
+  * [Config] Set CONFIG_DISPLAY_SUPPORT=m on arm
+  * [Config] Enable CONFIG_DL2K=m on amd64 and i386
+
+  [ Miklos Szeredi ]
+
+  * ubuntu: overlayfs -- vfs: add i_op->open()
+  * ubuntu: overlayfs -- vfs: export do_splice_direct() to modules
+  * ubuntu: overlayfs -- vfs: introduce clone_private_mount()
+  * ubuntu: overlayfs -- overlay filesystem
+  * ubuntu: overlayfs -- ovl: fix overlayfs over overlayfs
+  * ubuntu: overlayfs -- ovl: improve stack use of lookup and readdir
+  * ubuntu: overlayfs -- fs: limit filesystem stacking depth
+  * ubuntu: overlayfs -- ovl: make lower mount read-only
+
+  [ Neil Brown ]
+
+  * ubuntu: overlayfs -- overlay: overlay filesystem documentation
+
+  [ Tim Gardner ]
+
+  * [Config] Add enic/fnic to udebs
+    - LP: #801610
+
+  [ Upstream Kernel Changes ]
+
+  * yama: if an underlying filesystem provides a permissions op use it
+
+  [ Major Kernel Changes ]
+
+  * Rebase to 3.0 final
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 21 Jul 2011 07:01:32 -0700
+
+linux (3.0.0-6.7) oneiric; urgency=low
+
+  [ Eagon Yager ]
+
+  * [Config] Fix misspelled 'skipmodule' in arm makefile.
+
+  [ Keng-Yu Lin ]
+
+  * SAUCE: Input: ALPS - Enable Intellimouse mode for Lenovo Zhaoyang E47
+    - LP: #632884, #803005
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] Temporarily disable CONFIG_SMC91X on armel-omap"
+  * Revert "[Config] Temporarily Disable CONFIG_BRCMSMAC on arm"
+  * Revert "[Config] Temporarily Disable CONFIG_RTL8192SE on powerpc"
+  * Revert "[Config] Temporarily Disable CONFIG_RTL8192SE on arm"
+  * Revert "[Config] Temporarily disable CONFIG_BRCMSMAC on powerpc"
+  * [Config] Set CONFIG_ACPI_PCI_SLOT=m
+  * [Config] Set CONFIG_ACPI_SBS=m
+  * [Config] Set CONFIG_ACPI_WMI=m
+  * [Config] Set CONFIG_AD7150=m on arm
+  * [Config] Set CONFIG_AD7152=m on arm
+  * [Config] Drop CONFIG_GPIO_S5PV210
+  * [Config] Drop CONFIG_GPIO_S5PC100
+  * [Config] Drop CONFIG_GPIO_PLAT_SAMSUNG
+  * [Config] Drop CONFIG_GPIO_EXYNOS4
+
+  [ Stefan Bader ]
+
+  * SAUCE: Re-enable RODATA for i386 virtual
+    - LP: #809838
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Quirk to fix suspend/resume on Lenovo Edge 11,13,14,15"
+  * (drop after 3.0.0) acer-wmi: Add support for Aspire 1830 wlan hotkey
+    - LP: #771758
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 20 Jul 2011 06:36:02 -0700
+
+linux (3.0.0-5.6) oneiric; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_RTL8192CU=m
+  * Rebase to -rc7
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 11 Jul 2011 22:13:50 +0100
+
+linux (3.0.0-4.5) oneiric; urgency=low
+
+  [ Ming Lei ]
+
+  * SAUCE: fix yama_ptracer_del lockdep warning
+    - LP: #791019
+
+  [ Seth Forshee ]
+
+  * SAUCE: (drop after 3.0) asus-wmi: Add callback for hotkey filtering
+  * SAUCE: (drop after 3.0) eeepc-wmi: Add support for T101MT Home/Express Gate key
+  * SAUCE: (drop after 3.0) asus-wmi: Enable autorepeat for hotkey input device
+  * [Config] CONFIG_{ASUS,ASUS_NB,EEEPC}_WMI=m
+    - LP: #805218
+
+  [ Tim Gardner ]
+
+  * [Config] updateconfigs after rebase to -rc6+
+    Rebased against 4dd1b49c6d215dc41ce50c80b4868388b93f31a3
+  * Adopt a 3 digit verion, e.g., 3.0.0-x.x
+  * Revert "UBUNTU: add dependancies for module-init-tools"
+    This dependency is no longer required for a 3 digit version.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 05 Jul 2011 14:03:04 +0100
+
+linux (3.0-3.4) oneiric; urgency=low
+
+  [ Keng-Yu Lin ]
+
+  * SAUCE: Revert: "dell-laptop: Toggle the unsupported hardware
+    killswitch"
+    - LP: #775281
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc5
+  * [Config] updateconfigs after rebase to 3.0-rc5
+
+  [ Tim Gardner ]
+
+  * [Config] Remove ubuntu/rtl8192se
+  * [Config] Added armel ABI files
+  * [Config] Removed armel versatile flavour
+  * [Config] CONFIG_INTEL_MEI=m
+    - LP: #716867
+
+  [ Upstream Kernel Changes ]
+
+  * ALSA: hda - Enable auto-parser as default for Conexant codecs
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v3.0-rc5
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 30 Jun 2011 14:27:10 +0100
+
+linux (3.0-2.3) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- update to 0e2bafab74f0d1463383faeb93f9fc5eb8c2c54e
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc4
+  * [Config] updateconfigs after rebase to 3.0-rc4
+  * fix ERROR: __devcgroup_inode_permission undefined
+
+  [ Stefan Bader ]
+
+  * SAUCE: iscsitarget: Remove driver from the kernel
+
+  [ Tim Gardner ]
+
+  * SAUCE: rtl8192se: Force a build for a 2.6/3.0 kernel
+  * [Config] Add grub-efi as a recommended bootloader for server and
+    generic
+    - LP: #800910
+
+  [ Upstream Kernel Changes ]
+
+  * Fix node_start/end_pfn() definition for mm/page_cgroup.c
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 24 Jun 2011 11:51:12 -0700
+
+linux (3.0-1.2) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_CAN_CALC_BITTIMING
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc3
+  * [Config] updateconfigs after rebase to 3.0-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * perf: clear out make flags when calling kernel make kernelver
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc3
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 14 Jun 2011 07:25:35 -0700
+
+linux (3.0-0.1) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * use the packaging version in the kernel
+  * use the kernels idea of its version for version_signature
+  * add dependancies for module-init-tools
+  * update control files to version 3
+  * printchanges/insertchanges allow override of prev_release
+  * correct Vcs-Git: to point to oneiric
+
+  [ Leann Ogasawara ]
+
+  * rebase to v3.0-rc1
+  * [Config] updateconfigs after rebase to 3.0-rc1
+  * ubuntu: dm-raid4-5 fix up build failure
+  * [Config] Temporarily Disable CONFIG_GPIO_EXYNOS4 on arm
+  * [Config] Temporarily Disable CONFIG_GPIO_PLAT_SAMSUNG on arm
+  * [Config] Temporarily Disable CONFIG_GPIO_S5PC100 on arm
+  * [Config] Temporarily Disable CONFIG_GPIO_S5PV210 on arm
+  * [Config] Temporarily disable CONFIG_BRCMSMAC on powerpc
+  * [Config] Temporarily Disable CONFIG_BRCMSMAC on arm
+  * [Config] Temporarily Disable CONFIG_RTL8192SE on arm
+  * [Config] Temporarily Disable CONFIG_RTL8192SE on powerpc
+  * [Config] Temporarily disable CONFIG_SMC91X on armel-omap
+  * rebase to v3.0-rc2
+
+  [ Manoj Iyer ]
+
+  * SAUCE: mmc: Enable MMC card reader for RICOH [1180:e823]
+    - LP: #790754
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "x86 idle: EXPORT_SYMBOL(default_idle, pm_idle) only when APM
+    demands it"
+  * drm/i915: fix regression after clock gating init split
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39 to v3.0-rc1
+  * rebase from v3.0-rc1 to v3.0-rc2
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 09 Jun 2011 15:18:33 +0100
+
+linux (2.6.39-3.10) oneiric; urgency=low
+
+  [ Colin Ian King ]
+
+  * SAUCE: S3 early resume debug via keyboard LEDs
+
+  [ Ingo Molnar ]
+
+  * ubuntu: nx-emu - i386: NX emulation
+  * ubuntu: nx-emu - i386: mmap randomization for executable mappings
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] Disable CONFIG_FT1000 on powerpc64-smp"
+  * Revert "[Config] Disable CONFIG_DM_RAID45"
+  * [Config] enable CONFIG_BRCMFMAC=y
+  * [Config] enable CONFIG_MDIO_BITBANG=m across all arch's and flavors
+  * [Config] enable CONFIG_VIDEO_OUTPUT_CONTROL=m on armel-omap
+
+  [ Robert Nelson ]
+
+  * SAUCE: omap3: beagle: detect new xM revision B
+    - LP: #770679
+  * SAUCE: omap3: beagle: detect new xM revision C
+    - LP: #770679
+  * SAUCE: omap3: beagle: if rev unknown, assume xM revision C
+    - LP: #770679
+
+  [ Stefan Bader ]
+
+  * SAUCE: Convert dm-raid45 to new block plugging
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 23 May 2011 11:46:43 -0700
+
+linux (2.6.39-3.9) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_SCSI_LPFC_DEBUG_FS
+  * rebase to v2.6.39
+  * [Config] enable CONFIG_LLC2=m across all arch's and flavours
+  * [Config] enable CONFIG_INPUT_APANEL=m
+
+  [ Thomas Schlichter ]
+
+  * SAUCE: vesafb: mtrr module parameter is uint, not bool
+    - LP: #778043
+  * SAUCE: vesafb: enable mtrr WC by default
+    - LP: #778043
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc7 to v2.6.39
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 20 May 2011 09:52:32 +0100
+
+linux (2.6.39-2.8) oneiric; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-37"
+  * Revert "ubuntu: AUFS -- aufs2-base.patch aufs2.1-37"
+  * Revert "[Config] Disable CONFIG_AUFS_FS"
+  * ubuntu: AUFS -- aufs2-base.patch aufs2.1-39
+  * ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-39
+  * ubuntu: AUFS -- update to c6b76974311efc5bf3eddf921cd015b6aae46935
+  * ubuntu: AUFS -- clean up the aufs updater and BOM
+  * ubuntu: AUFS -- documentation on updating aufs2
+
+  [ Kees Cook ]
+
+  * ubuntu: Yama - LSM hooks
+  * ubuntu: Yama - create task_free security callback
+  * ubuntu: Yama - add ptrace relationship tracking interface
+  * ubuntu: Yama - unconditionally chain to Yama LSM
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: Fix drivers/staging/easycap FTBS"
+  * Revert "[Config] Disable CONFIG_EASYCAP"
+  * ubuntu: fsam7400 disable driver
+  * ubuntu: omnibook disable driver
+  * ubuntu: rfkill disable driver
+
+  [ Tim Gardner ]
+
+  * SAUCE: Fix extra reference in fb_open()
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 16 May 2011 09:23:56 -0700
+
+linux (2.6.39-2.7) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc7
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc6 to v2.6.39-rc7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 10 May 2011 10:18:28 +0200
+
+linux (2.6.39-1.6) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc6
+  * SAUCE: [arm] fixup __aeabi_uldivmod undefined build error
+
+  [ Tim Gardner ]
+
+  * [Config] updateconfigs after rebase to 2.6.39-rc6
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc5 to v2.6.39-rc6
+    - LP: #740126
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 05 May 2011 09:46:12 -0700
+
+linux (2.6.39-0.5) oneiric; urgency=low
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: Revert "x86, hibernate: Initialize mmu_cr4_features during boot"
+    - LP: #764758
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc5
+  * [Config] updateconfigs following rebase to v2.6.39-rc5
+
+  [ Paolo Pisati ]
+
+  * [Config] s/USB_MUSB_TUSB6010/USB_MUSB_OMAP2PLUS/ on omap3 to get musb
+    - LP: #759913
+
+  [ Stefan Bader ]
+
+  * Include nls_iso8859-1 for virtual images
+    - LP: #732046
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc4 to v2.6.39-rc5
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 27 Apr 2011 06:39:42 -0700
+
+linux (2.6.39-0.4) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc4
+  * [Config] updateconfigs following rebase to v2.6.39-rc4
+  * fixup powerpc implicit declaration of function
+    'crash_kexec_wait_realmode'
+  * [Config] Disable CONFIG_FT1000 on powerpc64-smp
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_TRANSPARENT_HUGEPAGE=y
+    - LP: #769503
+  * [Config] Add cachefiles.ko to virtual flavour
+    - LP: #770430
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc3 to v2.6.39-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 19 Apr 2011 06:25:20 -0700
+
+linux (2.6.39-0.3) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc3
+  * crash_kexec_wait_realmode() undefined when !SMP
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_PM_ADVANCED_DEBUG=y for i386/amd64
+    - LP: #632327
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc2 to v2.6.39-rc3
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 12 Apr 2011 06:52:24 -0700
+
+linux (2.6.39-0.2) oneiric; urgency=low
+
+  [ Gustavo F. Padovan ]
+
+  * SAUCE: Revert "Bluetooth: Add new PID for Atheros 3011"
+    - LP: #720949
+
+  [ John Johansen ]
+
+  * AppArmor: Fix masking of capabilities in complain mode
+    - LP: #748656
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc2
+  * [Config] updateconfigs following rebase to v2.6.39-rc2
+  * hv_mouse needs delay.h
+  * olpc_dcon_xo_1 needs delay.h
+  * olpc_dcon_xo_1_5 needs delay.h
+  * Update dropped.txt for Oneiric
+
+  [ Steve Langasek ]
+
+  * [Config] Make linux-libc-dev coinstallable under multiarch
+    - LP: #750585
+
+  [ Upstream Kernel Changes ]
+
+  * x86, hibernate: Initialize mmu_cr4_features during boot
+    - LP: #752870
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.39-rc1 to v2.6.39-rc2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 06 Apr 2011 11:04:15 -0700
+
+linux (2.6.39-0.1) oneiric; urgency=low
+
+  [ Brad Figg ]
+
+  * [Config] Set CONFIG_NR_CPUS=256 for amd64 generic
+    - LP: #737124
+
+  [ Henrik Rydberg ]
+
+  * SAUCE: HID: hid-ntrig: add support for 1b96:0006 model
+  * SAUCE: HID: ntrig: fix suspend/resume on recent models
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: (drop after 2.6.39) v4l: make sure drivers supply a zeroed
+    struct v4l2_subdev
+    - LP: #745213
+
+  [ Kees Cook ]
+
+  * [Config] packaging: adjust perms on vmlinuz as well
+  * SAUCE: nx-emu: further clarify dmesg reporting
+    - LP: #745181
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.39-rc1
+  * [Config] updateconfigs following rebase to v2.6.39-rc1
+  * [Config] Disable CONFIG_DM_RAID45
+  * [Config] Disable CONFIG_SCSI_ISCSITARGET
+  * [Config] Disable CONFIG_EASYCAP
+  * [Config] Disable CONFIG_AUFS_FS
+  * update bnx2 firmware files in d-i/firmware/nic-modules
+  * xhci-pci.c resolve implicit declaration of kzalloc
+  * [Config] Enable CONFIG_DRM_PSB for only x86
+  * [Config] Enable CONFIG_RTS_PSTOR for only x86
+  * mfd/asic3: Fix typo, s/irq_data/data/
+
+  [ Luke Yelavich ]
+
+  * [Config] Disable CONFIG_CRASH_DUMP on 32-bit powerpc kernels
+    - LP: #745358
+  * [Config] Disable CONFIG_DRM_RADEON_KMS on powerpc kernels
+  * [Config] Build some framebuffer drivers as modules for powerpc kernels.
+
+  [ Manoj Iyer ]
+
+  * SAUCE: thinkpad-acpi: module autoloading for newer Lenovo ThinkPads.
+    - LP: #745217
+
+  [ Tim Gardner ]
+
+  * SAUCE: INR_OPEN=4096
+    - LP: #663090
+  * SAUCE: Increase the default hard limit for open FDs to 4096
+    - LP: #663090
+
+  [ Upstream Kernel Changes ]
+
+  * (drop after 2.6.39-rc1) arm: versatile : Fix typo introduced in irq
+    namespace cleanup
+  * (drop after 2.6.39-rc1) [media] staging: altera-jtag needs delay.h
+  * ALSA: pcm: fix infinite loop in snd_pcm_update_hw_ptr0()
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38 to v2.6.39-rc1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 31 Mar 2011 12:50:10 -0700
+
+linux (2.6.39-0.0) oneiric; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Open Oneiric 
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 31 Mar 2011 12:29:23 -0700
+
+linux (2.6.38-7.39) natty; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No change upload.  This is just to rebuild with gcc-4.5.2-7ubuntu1.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 24 Mar 2011 09:27:45 -0700
+
+linux (2.6.38-7.38) natty; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No change upload take 2.  2.6.38-7.37 was accidentally uploaded before
+    gcc-4.5.2-6ubuntu5 finished building on all arches.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 22 Mar 2011 06:12:47 -0700
+
+linux (2.6.38-7.37) natty; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No change upload.  This is just to rebuild with gcc-4.5.2-6ubuntu5.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sun, 20 Mar 2011 16:02:48 -0700
+
+linux (2.6.38-7.36) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: KLUDGE: work around failed 'shrink-wrap' compiler
+    optimisation"
+  * purge last vestiges of maverick
+  * [Config] switch CONFIG_FB_VESA back to module
+
+  [ Chris Wilson ]
+
+  * SAUCE: drm/i915: Fix pipelined fencing
+    - LP: #717114
+
+  [ Loïc Minier ]
+
+  * Include nls_cp437 module in virtual for fat
+    - LP: #732046
+  * Support arch= cross-compilation for any arch
+  * Fix couple of typos in 0-common-vars.mk
+  * Enforce DEFAULT_MMAP_MIN_ADDR on armhf
+  * Add armhf to Debian -> Linux arch map
+  * Add initial armhf.mk
+  * Enable common packages for armhf
+
+  [ Upstream Kernel Changes ]
+
+  * Yama: fix default relationship to check thread group
+    - LP: #737676
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 18 Mar 2011 18:18:02 +0000
+
+linux (2.6.38-7.35) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to 2fbfac4e053861925fa3fffcdc327649b09af54c
+  * rebase fixes bug #715330
+  * [Config] disable CONFIG_SCSI_QLA_ISCSI for powerpc 32bit to fix FTBS
+  * rebase to v2.6.38 final
+
+  [ Herton Ronaldo Krzesinski ]
+
+  * SAUCE: Apply OPTION_BLACKLIST_SENDSETUP also for ZTE MF626
+    - LP: #636091
+
+  [ Tim Gardner ]
+
+  * [Confg] CONFIG_BOOT_PRINTK_DELAY=y
+
+  [ Upstream Kernel Changes ]
+
+  * Yama: use thread group leader when creating match
+    - LP: #729839
+  * (drop after 2.6.38) ahci: AHCI mode SATA patch for Intel Patsburg SATA
+    RAID controller
+    - LP: #735240
+  * (drop after v2.6.38) x86, quirk: Fix SB600 revision check
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc8 to v2.6.38 final
+    - LP: #715330
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 15 Mar 2011 19:04:19 +0000
+
+linux (2.6.38-6.34) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] normalise CONFIG_INTEL_TXT
+  * SAUCE: KLUDGE: work around failed 'shrink-wrap' compiler optimisation
+    - LP: #730860
+  * rebase to mainline v2.6.38-rc8
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc7 + fb62c00a6d8942775abc23d1621db1252e2d93d1
+    to v2.6.38-rc8
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 08 Mar 2011 11:54:48 +0000
+
+linux (2.6.38-6.33) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * d-i -- enable speakup-modules udeb
+    - LP: #672699
+  * rebase to 493f3358cb289ccf716c5a14fa5bb52ab75943e5
+  * [Config] debian PPC64 configuration
+  * [Config] cleanup powerpc config fixing unexpected inconsistancies
+  * [Config] resync ppc64 configuration
+  * SAUCE: match up ENTRY/END naming for 32/64 bit
+  * rebase to fb62c00a6d8942775abc23d1621db1252e2d93d1
+  * [Config] update configs after rebase to
+    fb62c00a6d8942775abc23d1621db1252e2d93d1
+  * [Config] pps_gen_parport no longer built
+
+  [ Corentin Chary ]
+
+  * SAUCE: (drop after 2.6.38) eeepc-wmi: reorder keymap
+    - LP: #689393
+  * SAUCE: (drop after 2.6.38) eeepc-wmi: add wlan key found on 1015P
+    - LP: #689393
+
+  [ John Johansen ]
+
+  * SAUCE: Fix aufs calling of security_path_mknod
+    - LP: #724456
+
+  [ Kees Cook ]
+
+  * SAUCE: proc: hide kernel addresses via %pK in /proc/<pid>/stack
+
+  [ Tim Gardner ]
+
+  * rebase to 2.6.38-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "drm/i915: fix corruptions on i8xx due to relaxed fencing"
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc6 to v2.6.38-rc7 +
+    fb62c00a6d8942775abc23d1621db1252e2d93d1
+    - LP: #721389
+    - LP: #722925
+    - LP: #723672
+    - LP: #723676
+    - LP: #715318
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 07 Mar 2011 15:33:17 +0000
+
+linux (2.6.38-5.32) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to mainline 6f576d57f1fa0d6026b495d8746d56d949989161
+  * [Config] updateconfigs following rebase to v2.6.38-rc6
+  * [Config] enable CONFIG_DMAR
+    - LP: #552311
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915: skip FDI & PCH enabling for DP_A
+    - LP: #561802, #600453, #681877
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc5 to v2.6.38-rc6
+    - LP: #718402
+    - LP: #719524
+    - LP: #721126
+    - LP: #719691
+    - LP: #722689
+    - LP: #722310
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 22 Feb 2011 13:28:39 +0000
+
+linux (2.6.38-4.31) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * add in bugs closed by upstream patches pulled in by rebases
+  * rebase to 795abaf1e4e188c4171e3cd3dbb11a9fcacaf505
+  * [Config] enable CONFIG_VSX to allow use of vector instuctions
+  * resync with maverick 98defa1c5773a3d7e4c524967eb01d5bae035816
+  * rebase to mainline v2.6.38-rc5
+  * SAUCE: ecryptfs: read on a directory should return EISDIR if not
+    supported
+    - LP: #719691
+
+  [ Colin Ian King ]
+
+  * SAUCE: Dell All-In-One: Remove need for Dell module alias
+
+  [ Manoj Iyer ]
+
+  * SAUCE: (drop after 2.6.38) add ricoh 0xe823 pci id.
+    - LP: #717435
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_CRYPTO_CRC32C_INTEL=y
+
+  [ Upstream Kernel Changes ]
+
+  * Quirk to fix suspend/resume on Lenovo Edge 11,13,14,15
+    - LP: #702434
+  * vfs: fix BUG_ON() in fs/namei.c:1461
+
+  [ Vladislav P ]
+
+  * SAUCE: Release BTM while sleeping to avoid deadlock.
+    - LP: #713837
+
+  [ Major Kernel Changes ]
+
+  * rebase from v2.6.38-rc4 to v2.6.38-rc5
+    - LP: #579276
+    - LP: #715877
+    - LP: #713769
+    - LP: #716811
+  * resync with Maverick Ubuntu-2.6.35-27.47
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 11 Feb 2011 17:24:09 +0000
+
+linux (2.6.38-3.30) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.38-rc4
+  * ppc64 -- add basic architecture
+  * ubuntu: AUFS -- update to 65835da20b77c98fb538c9114fc31f5de1328230
+
+  [ Colin Ian King ]
+
+  * SAUCE: Add WMI hotkeys support for Dell All-In-One series
+    - LP: #676997
+  * SAUCE: Add WMI hotkeys support for another Dell All-In-One series
+    - LP: #701530
+  * SAUCE: Dell WMI: Use sparse keymaps and tidy up code.
+    - LP: #701530
+
+  [ Dan Rosenberg ]
+
+  * SAUCE: (drop after 2.6.38) Convert net %p usage %pK
+
+  [ Kees Cook ]
+
+  * Revert "SAUCE: kernel: make /proc/kallsyms mode 400 to reduce ease of
+    attacking"
+  * SAUCE: (drop after 2.6.38) use %pK for /proc/kallsyms and /proc/modules
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_BLK_CGROUP=y
+    - LP: #706394
+  * [Config] CONFIG_DELL_WMI_AIO=m
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915/lvds: Restore dithering on native modes for gen2/3
+    - LP: #711568
+
+  [ Upstream Kernel Changes ]
+
+  * rebase from v2.6.38-rc3 to v2.6.38-rc4.
+    - LP: #701271
+    - LP: #708521
+    - LP: #710371
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 08 Feb 2011 02:07:18 +0000
+
+linux (2.6.38-2.29) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to 1f0324caefd39985e9fe052fac97da31694db31e
+  * [Config] updateconfigs following rebase to
+    1f0324caefd39985e9fe052fac97da31694db31e
+  * rebase to 70d1f365568e0cdbc9f4ab92428e1830fdb09ab0
+  * [Config] reenable HIBERNATE
+    - LP: #710877
+  * rebase to v2.6.38-rc3
+  * [Config] reenable CONFIG_CRASH_DUMP
+
+  [ Kamal Mostafa ]
+
+  * SAUCE: rtl8192se: fix source file perms
+  * SAUCE: rtl8192se: fix source file newline
+  * SAUCE: omnibook: fix source file newline
+
+  [ Kees Cook ]
+
+  * [Config] packaging: really make System.map mode 0600
+
+  [ Ricardo Salveti de Araujo ]
+
+  * SAUCE: OMAP3630: PM: don't warn the user with a trace in case of
+    PM34XX_ERRATUM
+
+  [ Soren Hansen ]
+
+  * SAUCE: nbd: Remove module-level ioctl mutex
+
+  [ Tim Gardner ]
+
+  * SAUCE: Disable building the ACPI debugfs source
+
+  [ Upstream Kernel Changes ]
+
+  * Set physical start and alignment 1M for virtual i386
+    - LP: #710754
+
+  [ Upstream Kernel Changes ]
+
+  * rebase from v2.6.38-rc2 + c723fdab8aa728dc2bf0da6a0de8bb9c3f588d84
+    to v2.6.38-rc3
+    - LP: #707902
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 28 Jan 2011 16:30:32 +0000
+
+linux (2.6.38-1.28) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- update to b1cee06249dfa0ab30951e7f06490a75c155b620
+
+  [ Ricardo Salveti de Araujo ]
+
+  * SAUCE: omap3: beaglexm: fix DVI initialization
+  * [Config] omap: move CONFIG_PANEL_GENERIC_DPI to build in to make
+    display work at Beagle
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 28 Jan 2011 10:51:57 +0000
+
+linux (2.6.38-1.27) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- update aufs-update to track new locations of headers
+  * ubuntu: AUFS -- update to c5021514085a5d96364e096dbd34cadb2251abfd
+  * SAUCE: ensure root is ready before running usermodehelpers in it
+  * correct the Vcs linkage to point to natty
+  * rebase to linux tip e78bf5e6cbe837daa6ab628a5f679548742994d3
+  * [Config] update configs following rebase
+    e78bf5e6cbe837daa6ab628a5f679548742994d3
+  * SAUCE: Yama: follow changes to generic_permission
+  * ubuntu: compcache -- follow changes to bd_claim/bd_release
+  * ubuntu: iscsitarget -- follow changes to open_bdev_exclusive
+  * ubuntu: ndiswrapper -- fix interaction between __packed and packed
+  * ubuntu: AUFS -- update to 806051bcbeec27748aae2b7957726a4e63ff308e
+  * update package version to match payload version
+  * rebase to e6f597a1425b5af64917be3448b29e2d5a585ac8
+  * rebase to v2.6.38-rc1
+  * [Config] updateconfigs following rebase to v2.6.38-rc1
+  * SAUCE: x86 fix up jiffies/jiffies_64 handling
+  * rebase to linus tip 2b1caf6ed7b888c95a1909d343799672731651a5
+  * [Config] updateconfigs following rebase to
+    2b1caf6ed7b888c95a1909d343799672731651a5
+  * [Config] disable CONFIG_TRANSPARENT_HUGEPAGE to fix i386 boot crashes
+  * ubuntu: AUFS -- suppress benign plink warning messages
+    - LP: #621195
+  * [Config] CONFIG_NR_CPUS=256 for amd64 -server flavour
+  * rebase to v2.6.38-rc2
+  * rebase to mainline d315777b32a4696feb86f2a0c9e9f39c94683649
+  * rebase to c723fdab8aa728dc2bf0da6a0de8bb9c3f588d84
+  * [Config] update configs following rebase to
+    c723fdab8aa728dc2bf0da6a0de8bb9c3f588d84
+  * [Config] disable CONFIG_AD7152 to fix FTBS on armel versatile
+  * [Config] disable CONFIG_AD7150 to fix FTBS on armel versatile
+  * [Config] disable CONFIG_RTL8192CE to fix FTBS on armel omap
+  * [Config] disable CONFIG_MANTIS_CORE to fix FTBS on armel versatile
+
+  [ Kees Cook ]
+
+  * SAUCE: kernel: make /proc/kallsyms mode 400 to reduce ease of attacking
+
+  [ Stefan Bader ]
+
+  * Temporarily disable RODATA for virtual i386
+    - LP: #699828
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NLS_DEFAULT=utf8
+    - LP: #683690
+  * [Config] CONFIG_HIBERNATION=n
+  * update bnx2 firmware files in d-i/firmware/nic-modules
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "drm/radeon/bo: add some fallback placements for VRAM only
+    objects."
+  * packaging: make System.map mode 0600
+  * thinkpad_acpi: Always report scancodes for hotkeys
+    - LP: #702407
+  * sched: tg->se->load should be initialised to tg->shares
+  * Input: sysrq -- ensure sysrq_enabled and __sysrq_enabled are consistent
+  * brcm80211: include linux/slab.h for kfree
+  * pch_dma: add include/slab.h for kfree
+  * i2c-eg20t: include linux/slab.h for kfree
+  * gpio/ml_ioh_gpio: include linux/slab.h for kfree
+  * tty: include linux/slab.h for kfree
+  * winbond: include linux/delay.h for mdelay et al
+
+  [ Upstream Kernel Changes ]
+
+  * mark the start of v2.6.38 versioning
+  * rebase v2.6.37 to v2.6.38-rc2 + c723fdab8aa728dc2bf0da6a0de8bb9c3f588d84
+    - LP: #689886
+    - LP: #702125
+    - LP: #608775
+    - LP: #215802
+    - LP: #686333
+    - LP: #677830
+    - LP: #677652
+    - LP: #696493
+    - LP: #697240
+    - LP: #689036
+    - LP: #705323
+    - LP: #686692
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 09 Jan 2011 13:44:52 +0000
+
+linux (2.6.37-12.26) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.37-rc8
+  * [Config] armel -- reenable omap flavour
+  * [Config] disable CONFIG_MACH_OMAP3517EVM to fix FTBS on armel omap
+  * [Config] disable CONFIG_GPIO_VX855 to fix FTBS on omap armel
+  * [Config] disable CONFIG_WESTBRIDGE_ASTORIA to fix FTBS on omap armel
+  * [Config] disable CONFIG_TI_DAVINCI_EMAC to fix FTBS on omap armel
+  * rebase to mainline 989d873fc5b6a96695b97738dea8d9f02a60f8ab
+  * [Config] track missing modules
+  * rebase to v2.6.37 final
+
+  [ Chase Douglas ]
+
+  * SAUCE: (drop after 2.6.37) HID: magicmouse: Don't report REL_{X, Y} for
+    Magic Trackpad
+
+  [ Stefan Bader ]
+
+  * Revert "SAUCE: blkfront: default to sd devices"
+    - LP: #684875
+
+  [ Tim Gardner ]
+
+  * Revert "SAUCE: (no-up) libata: Ignore HPA by default."
+    - LP: #380138
+  * [Config] Added autofs4.ko to -virtual flavour
+    - LP: #692917
+
+  [ Upstream Kernel Changes ]
+
+  * Add support for Intellimouse Mode in ALPS touchpad on Dell E2 series
+    Laptops
+    - LP: #632884
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.37-rc8
+  * rebase to mainline 989d873fc5b6a96695b97738dea8d9f02a60f8ab
+  * rebase to v2.6.37 final
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 23 Dec 2010 18:34:13 +0000
+
+linux (2.6.37-11.25) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] d-i -- add hpsa to the list of block devices
+    - LP: #684304
+  * [Config] add vmw-balloon driver to -virtual flavour
+    - LP: #592039
+  * rebase to v2.6.37-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.37-rc7
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 21 Dec 2010 13:35:28 +0000
+
+linux (2.6.37-10.24) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.37-rc6
+  * updateconfigs following rebase to v2.6.37-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.37-rc6
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 16 Dec 2010 12:34:19 +0000
+
+linux (2.6.37-9.23) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: vt -- fix handoff numbering to 1..n and add range checks
+    - LP: #689606
+  * SAUCE: vt -- fix handoff numbering to 1..n and add range checks (grub)
+    - LP: #689606
+
+  [ Kees Cook ]
+
+  * SAUCE: RO/NX protection for loadable kernel, fix ftrace
+    - LP: #690190
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 15 Dec 2010 19:29:57 +0000
+
+linux (2.6.37-9.22) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.35-rc5
+  * [Config] updateconfigs following rebase to v2.6.37-rc5
+  * (no-up) add support for installed header files to ubuntu directory
+    - LP: #684666
+  * ubuntu: AUFS -- include the aufs_types.h file in linux-libc-headers
+    - LP: #684666
+  * ubuntu: dm-raid4-5 -- follow changes to bio flags
+  * ubuntu: dm-raid4-5 -- re-enable
+  * ubuntu: omnibook -- update BOM
+  * ubuntu: ndiswrapper -- update BOM to match actual version
+  * ubuntu: ndiswrapper -- follow removal of the BKL and locked ioctl
+  * ubuntu: ndiswrapper -- re-enable
+  * ubuntu: iscsitarget -- re-instate copy_io_context
+  * ubuntu: iscsitarget -- follow changes to semaphore initialisation
+  * ubuntu: iscsitarget -- convert NIPQUAD to %pI4
+  * ubuntu: iscsitarget -- re-enable
+
+  [ Kees Cook ]
+
+  * [Config] update config for CONFIG_DEBUG_SET_MODULE_RONX
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Enable jack sense for Thinkpad Edge 13
+    - LP: #685015
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_9P_FSCACHE=y,CONFIG_9P_FS_POSIX_ACL=y
+  * [Config] CONFIG_CRYPTO_CRC32C=y
+    - LP: #681819
+  * [Config] CONFIG_9P_FSCACHE=n
+  * [Config] Add nfsd modules to -virtual flavour
+    - LP: #688070
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Staging: zram: work around oops due to startup ordering snafu"
+  * NFS: Fix panic after nfs_umount()
+    - LP: #683938
+  * x86: Add NX protection for kernel data
+  * x86: Add RO/NX protection for loadable kernel modules
+  * x86: Resume trampoline must be executable
+  * x86: RO/NX protection for loadable kernel, jump_table fix
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.37-rc5
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 09 Dec 2010 18:15:35 +0000
+
+linux (2.6.37-8.21) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- include the aufs_types.h file in
+    linux-libc-headers"
+  * Revert "(no-up) add support for installed header files to ubuntu
+    directory"
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 05 Dec 2010 17:33:28 +0000
+
+linux (2.6.37-8.20) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Upstream] drivers/serial/mfd.c: Fix ARM compile error"
+  * Revert "SAUCE: Nouveau: Disable acceleration on MacBook Pros"
+  * Revert "SAUCE: Nouveau: Add quirk framework to disable acceleration"
+  * Revert "SAUCE: i915 -- disable powersave by default"
+  * SAUCE: enable Marvell 9128 PCIe SATA controller
+    - LP: #658521
+  * [Config] evtchn has been renamed
+  * (no-up) add support for installed header files to ubuntu directory
+    - LP: #684666
+  * ubuntu: AUFS -- include the aufs_types.h file in linux-libc-headers
+    - LP: #684666
+
+  [ Tim Gardner ]
+
+  * [Config] MISS: evtchn, NEW : xen-evtchn
+  * rebase to v2.6.37-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * drm/i915: Clean conflicting modesetting registers upon init
+    - LP: #683775
+  * rebase to v2.6.37-rc4
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 03 Dec 2010 18:42:07 +0000
+
+linux (2.6.37-7.19) natty; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Add bnx2 firmware to nic-modules udeb
+    - LP: #676245
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 26 Nov 2010 17:53:45 +0000
+
+linux (2.6.37-7.18) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Upstream] USB: option: Remove duplicate AMOI_VENDOR_ID"
+  * Revert "SAUCE: Add extra headers to linux-libc-dev"
+  * Revert "SAUCE: Enable speedstep for sonoma processors."
+  * [Config] enable CONFIG_BT_HCIUART_ATH3K
+  * [Config] enable CONFIG_IWLWIFI_DEBUGFS
+  * [Config] standardise CONFIG_MII
+  * [Config] standardise CONFIG_PRISM2_USB
+  * [Config] standardise CONFIG_SCSI_QLA_ISCSI
+  * [Config] build in CONFIG_AGP
+  * [Config] build in CONFIG_AGP_INTEL
+  * [Config] build in CONFIG_AGP_AMD
+  * [Config] build in CONFIG_AGP_AMD64
+  * [Config] build in CONFIG_AGP_NVIDIA
+  * [Config] build in CONFIG_AGP_VIA
+  * [Config] disable CONFIG_SCSI_QLA_ISCSI for FTBS (arm)
+  * (no-up): document the new ## scheme
+  * [Config] harmonise CONFIG_SERIAL_8250_NR_UARTS
+  * [Config] update CONFIG_SERIAL_8250_RUNTIME_UARTS=32
+    - LP: #675453
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: ARM: Adding vdd_sdi regulator supply to OMAP3EVM
+
+  [ Upstream Kernel Changes ]
+
+  * nx-emu: fix inverted report of disable_nx
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 23 Nov 2010 21:00:39 +0000
+
+linux (2.6.37-6.17) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- aufs2-standalone.patch
+    aufs2.1-36-UNRELEASED-20101103"
+  * Revert "ubuntu: AUFS -- aufs2-base.patch
+    aufs2.1-36-UNRELEASED-20101103"
+  * [Config] standardise CONFIG_BT
+  * [Config] standardise CONFIG_IRDA
+  * [Config] standardise CONFIG_LAPB
+  * [Config] standardise CONFIG_RDS
+  * [Config] standardise CONFIG_RFKILL
+  * [Config] standardise CONFIG_TIPC
+  * [Config] standardise CONFIG_X25
+  * [Config] standardise CONFIG_INPUT_EVDEV
+  * [Config] standardise CONFIG_INPUT_JOYDEV
+  * [Config] standardise CONFIG_INPUT_JOYSTICK
+  * [Config] standardise CONFIG_INPUT_TOUCHSCREEN
+  * [Config] CONFIG_INPUT_TOUCHSCREEN=n for FTBS (arm)
+  * [Config] CONFIG_IRDA=n for FTBS (arm)
+  * ubuntu: AUFS -- aufs2-base.patch aufs2.1-37
+  * ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-37
+  * ubuntu: AUFS -- update to 097bf62d6f49619359d34bf17f242df38562489a
+
+  [ Tim Gardner ]
+
+  * SAUCE: Fix drivers/staging/easycap FTBS
+  * [Config] CONFIG_EASYCAP=m after fixing FTBS
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "x86: Add NX protection for kernel data"
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 22 Nov 2010 18:09:10 +0000
+
+linux (2.6.37-6.16) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] update config for CONFIG_DEBUG_SET_MODULE_RONX"
+  * rebase to v2.6.37-rc3
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_SCHED_AUTOGROUP=y
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "x86: Add RO/NX protection for loadable kernel modules"
+  * sched: automated per session task groups
+  * rebase to v2.6.37-rc3
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 22 Nov 2010 10:11:13 +0000
+
+linux (2.6.37-6.15) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] standardise CONFIG_CEPH_FS
+  * [Config] standardise CONFIG_SCSI_LPFC_DEBUG_FS
+  * [Config] standardise CONFIG_SCSI_PROC_FS
+  * [Config] standardise CONFIG_UBIFS_FS
+  * [Config] standardise CONFIG_USB_GADGET_DEBUG_FS
+
+  [ Kees Cook ]
+
+  * [Config] update config for CONFIG_DEBUG_SET_MODULE_RONX
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Enable jack sense for Thinkpad Edge 11
+    - LP: #677210
+  * SAUCE: enable rfkill for rtl8192se driver
+    - LP: #640992
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_EASYCAP=n for FTBS
+  * Rebase to v2.6.32-rc2+git
+
+  [ Upstream Kernel Changes ]
+
+  * x86: Fix improper large page preservation
+  * x86: Add NX protection for kernel data
+  * x86: Add RO/NX protection for loadable kernel modules
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to Linus 2.6.37-rc2+git
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 20 Nov 2010 11:40:00 +0000
+
+linux (2.6.37-5.14) natty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * PCI: fix offset check for sysfs mmapped files
+    - LP: #676963
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 18 Nov 2010 18:12:27 +0000
+
+linux (2.6.37-5.13) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebased to v2.6.37-rc2
+  * updateconfigs following rebase to v2.6.37-rc2
+
+  [ Tim Gardner ]
+
+  * [Config] Added NFS and related modules to virtual flavour
+    - LP: #659084
+
+  [ Upstream Kernel Changes ]
+
+  * x86, cpu: Rename verify_cpu_64.S to verify_cpu.S
+  * x86, cpu: Clear XD_DISABLED flag on Intel to regain NX
+  * x86, cpu: Call verify_cpu during 32bit CPU startup
+  * x86, cpu: Only CPU features determine NX capabilities
+
+  [ Upstream Changes ]
+
+  * rebased to v2.67.37-rc2
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 16 Nov 2010 13:13:29 +0000
+
+linux (2.6.37-4.12) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Upstream] HID: magicmouse: add param for scroll speed"
+  * Revert "[Upstream] HID: magicmouse: properly account for scroll
+    movement in state"
+  * Revert "[Upstream] HID: magicmouse: disable and add module param for
+    scroll acceleration"
+  * Revert "[Upstream] HID: magicmouse: scroll on entire surface, not just
+    middle of mouse"
+
+  [ Henrik Rydberg ]
+
+  * SAUCE: hid: ntrig: remove sysfs nodes
+  * SAUCE: hid: ntrig: Setup input filtering manually
+  * SAUCE: hid: ntrig: New ghost-filtering event logic
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Added quirk to recognize GE0301 3G modem as an interface.
+    - LP: #348861
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "mmc: fix all hangs related to mmc/sd card insert/removal during
+    suspend/resume"
+  * Revert "[ARM] implement arch_randomize_brk()"
+  * Revert "ARM: stack protector: change the canary value per task"
+  * Revert "ARM: initial stack protector (-fstack-protector) support"
+  * Revert "ALSA: hda - Handle pin NID 0x1a on ALC259/269"
+  * Revert "ALSA: hda - Handle missing NID 0x1b on ALC259 codec"
+  * Revert "perf probe: Add kernel source path option"
+  * hid: ntrig: Support single-touch devices
+  * hid: ntrig: Mask pen switch events
+  * net: rtnetlink.h -- only include linux/netdevice.h when used by the
+    kernel
+    - LP: #673073
+  * Fix userspace build of linux/fs.h
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 15 Nov 2010 19:31:44 +0000
+
+linux (2.6.37-3.11) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- update to
+    b37c575759dc4535ccc03241c584ad5fe69e3b25"
+  * Revert "ubuntu: AUFS -- track changes to the arguements to fop fsync()"
+  * Revert "ubuntu: AUFS -- update to standalone 2.6.35-rcN as at 20100601"
+  * Revert "ubuntu: AUFS -- update to standalone 2.6.34 as at 20100601"
+  * Revert "ubuntu: AUFS -- aufs2 base patch for linux-2.6.34"
+  * [Config] Disable intel_idle for -virtual kernels
+    - LP: #651370
+  * [Config] enforcer -- ensure we never enable CONFIG_IMA
+  * debian -- pass the correct flavour name when checking configs
+  * [Config] enforcer -- ensure CONFIG_INTEL_IDLE is off for -virtual
+  * [Config] ensure CONFIG_IPV6=y for powerpc
+  * [Config] enforcer -- ensure CONFIG_IPV6=y
+  * ubuntu: AUFS -- aufs2-base.patch aufs2.1-36-UNRELEASED-20101103
+  * ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-36-UNRELEASED-20101103
+  * ubuntu: AUFS -- update to aufs2.1-36-UNRELEASED-20101103
+  * ubuntu: AUFS -- re-enable
+  * ubuntu: AUFS -- track changes to work queue initialisation
+  * ubuntu: AUFS -- track changes to llseek in v2.6.37-rc1
+  * SAUCE: fbcon -- fix race between open and removal of framebuffers
+  * SAUCE: fbcon -- fix OOPs triggered by race prevention fixes
+    - LP: #614008
+  * SAUCE: drm -- stop early access to drm devices
+
+  [ Jeremy Kerr ]
+
+  * [Config] Build-in powermac ZILOG serial driver
+    - LP: #673346
+
+  [ Kees Cook ]
+
+  * SAUCE: nx-emu: use upstream ASLR when possible
+
+  [ Tim Gardner ]
+
+  * [Config] Use correct be2iscsi module name in d-i/modules/scsi-modules
+    - LP: #628776
+
+  [ Upstream Kernel Changes ]
+
+  * i386: NX emulation
+  * nx-emu: drop exec-shield sysctl, merge with disable_nx
+  * nx-emu: standardize boottime message prefix
+  * mmap randomization for executable mappings on 32-bit
+  * exec-randomization: brk away from exec rand area
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 11 Nov 2010 23:46:37 +0000
+
+linux (2.6.37-2.10) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * reinstate armel config changes:
+   * [Config] CONFIG_GPIO_PCH=n for armel FTBS
+   * [Config] CONFIG_GPIO_VX855=n for armel FTBS
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 03 Nov 2010 22:20:35 +0000
+
+linux (2.6.37-2.9) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * config -- fix genportsconfig
+  * [Config] move powerpc over from ports to distro
+  * bump master version number to match contained kernel
+  * SAUCE: fix documentation strings for struct input_keymap_entry
+  * usb: gadget: goku_udc: add registered flag bit
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 02 Nov 2010 15:14:11 +0000
+
+linux (2.6.36-2.8) natty; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config]: fix changed CONFIG_SYSFS_DEPRECATED_V2 enforcement rules
+  * [Config]: TWL4030_CORE=n for FTBS
+  * [Config]: CONFIG_ATH6K_LEGACY=n for FTBS
+  * [Config]: CONFIG_SOLO6X10=n for FTBS
+  * [Config]: CONFIG_GPIO_PCH=n for armel FTBS
+  * [Config]: CONFIG_GPIO_VX855=n for armel FTBS
+  * [Config]: CONFIG_DRM_NOUVEAU=n for armel FTBS
+  * [Config]: CONFIG_LINE6_USB=n for armel FTBS
+  * [Config]: CONFIG_SENSORS_AK8975=n for armel FTBS
+  * [Config]: CONFIG_I2C_I801=n for armel FTBS
+  * UBUNTU: SAUCE: AppArmor: Fix unpack of network tables.
+  * AppArmor: compatibility patch for v5 interface
+  * AppArmor: compatibility patch for v5 network controll
+  * Dropped (pre-stable): input: Support Clickpad devices in ClickZone mode
+  * Dropped: UBUNTU: SAUCE: libata: Add ALPM power state accounting to the AHCI driver
+  * Dropped: UBUNTU: SAUCE: Added quirk to recognize GE0301 3G modem as an interface.
+  * Dropped: hid: 3m: Convert to MT slots
+  * Dropped: HID: magicmouse: don't allow hidinput to initialize the device
+  * Dropped: HID: magicmouse: simplify touch data bit manipulation
+  * Dropped: HID: magicmouse: simplify touch down logic
+  * Dropped: HID: magicmouse: enable Magic Trackpad support
+  * Dropped: UBUNTU: SAUCE: hid: ntrig: remove sysfs nodes
+  * Dropped: UBUNTU: SAUCE: hid: ntrig: Setup input filtering manually
+  * Dropped: UBUNTU: SAUCE: hid: ntrig: New ghost-filtering event logic
+  * Dropped: UBUNTU: SAUCE: hid: ntrig: identify firmware version (wiggled)
+  * Dropped: UBUNTU: (pre-stable): input: Support Clickpad devices in ClickZone mode
+  * Dropped: UBUNTU: SAUCE: KMS: cache the EDID information of the LVDS
+  * Dropped: UBUNTU: SAUCE: fbcon -- fix race between open and removal of framebuffers
+  * Dropped: UBUNTU: SAUCE: fbcon -- fix OOPs triggered by race prevention fixes
+  * Dropped: UBUNTU: SAUCE: x86: implement cs-limit nx-emulation for ia32
+  * Dropped: UBUNTU: SAUCE: x86: more tightly confine cs-limit nx-emulation to ia32 only
+  * Dropped: UBUNTU: SAUCE: [um] Don't use nx_enabled under UML
+  * Dropped: UBUNTU: SAUCE: x86: brk away from exec rand area
+
+  [ Upstream Kernel Changes ]
+
+  * rebased against 2.6.27-rc1
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 22 Oct 2010 19:35:05 -0600
+
+linux (2.6.36-1.7) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebased to v2.6.36 final
+  * [Config] update configs following rebase to v2.6.36 final
+  * [Config] update ports configs following rebase to v2.6.36 final
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to v2.6.36 final
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 21 Oct 2010 14:28:57 +0100
+
+linux (2.6.36-1.6) natty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * drop broadcom staging driver preview:
+   * Revert "Staging: Add initial release of brcm80211 - Broadcom 802.11n
+     wireless LAN driver."
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 20 Oct 2010 10:41:25 +0100
+
+linux (2.6.36-1.5) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.36-rc8
+  * updateconfigs following rebase to v2.6.36-rc8
+  * updateportsconfigs following rebase to v2.6.36-rc8
+  * config -- simplify the kernelconfig interface
+  * config -- add new config mode 'dumpconfigs'
+
+  [ Tim Gardner ]
+
+  * Simplify the use of CROSS_COMPILER
+
+  [ Upstream Kernel Changes ]
+
+  * drop broadcom staging driver preview:
+   * Revert "staging: brcm80211: Make compiling of brcm80211.ko and
+     brcmfmac.ko mutually exclusive."
+   * Revert "staging: brcm80211: Fix compile issue when BRCM80211_PCI is not
+     set."
+   * Revert "Staging: brcm80211: remove driver specific -W options"
+   * Revert "Staging: brcm80211: clean up makefile cflag lines"
+   * Revert "staging: brcm80211: add fullmac driver"
+   * Revert "staging: brcm80211: use string native library"
+   * Revert "staging: brcm80211: use native ctype library"
+   * Revert "staging: brcm80211: fix remaining checkpatch errors."
+   * Revert "staging: brcm80211: fix "ERROR: trailing whitespace.""
+   * Revert "staging: brcm80211: fix "ERROR: spaces required around that
+     ...""
+   * Revert "staging: brcm80211: fix "ERROR: spaces prohibited around that
+     ':' ...""
+   * Revert "staging: brcm80211: fix "ERROR: space required before that
+     ...""
+   * Revert "staging: brcm80211: fix "ERROR: space required after that ...""
+   * Revert "staging: brcm80211: fix "ERROR: space required after that close
+     brace""
+   * Revert "staging: brcm80211: fix "ERROR: space prohibited before
+     ...close square bracket""
+   * Revert "staging: brcm80211: fix "ERROR: space prohibited after that
+     ...""
+   * Revert "staging: brcm80211: fix "ERROR: need consistent spacing around
+     '*'""
+   * Revert "staging: brcm80211: fix 'ERROR: "(foo*)" should be "(foo *)"'"
+   * Revert "staging: brcm80211: fix "ERROR: Macros w/ mult. statements ...
+     do - while loop""
+   * Revert "staging: brcm80211: fix "ERROR: Macros w/ complex values ...
+     parenthesis""
+   * Revert "staging: brcm80211: fix "ERROR: do not initialise statics to 0
+     or NULL""
+   * Revert "staging: brcm80211: fix "ERROR: do not initialise globals to 0
+    or NULL""
+   * Revert "staging: brcm80211: fix "ERROR: while should follow close brace
+     '}'""
+   * Revert "staging: brcm80211: fix "ERROR: that open brace { ... prev
+     line""
+   * Revert "staging: brcm80211: fix "ERROR: trailing statements should be
+     on next line""
+   * Revert "staging: brcm80211: fix "ERROR: do not use assignment in if
+     condition""
+   * Revert "staging: brcm80211: fix "ERROR: return is not a function,
+     paren...""
+   * Revert "staging: brcm80211: fix "ERROR: open brace '{' following
+     function dec...""
+   * Revert "staging: brcm80211: fix 'ERROR: "foo * bar" should be "foo
+     *bar"'"
+   * Revert "staging: brcm80211: Fix URLs for firmware files."
+   * Revert "staging: brcm80211: use '%pM' format to print MAC address"
+   * Revert "staging: brcm80211: Add contact info to TODO list."
+   * Revert "staging: brcm80211: Fix some initialisation failure paths"
+  * Export dump_{write,seek} to binary loader modules
+  * rebase to v2.6.36-rc8.
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 19 Oct 2010 18:58:11 +0100
+
+linux (2.6.36-0.4) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: perf: increase stack footprint to avoid stack-protector warning
+    (fixes FTBS on powerpc)
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 14 Oct 2010 13:16:16 +0100
+
+linux (2.6.36-0.3) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] disable CONFIG_SCSI_QLA_ISCSI to fix FTBS on powerpc
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 14 Oct 2010 03:01:30 +0100
+
+linux (2.6.36-0.2) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] updateportsconfigs following rebase to 2.6.36-rc7
+    (fix FTBS on powerpc)
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 13 Oct 2010 23:25:12 +0100
+
+linux (2.6.36-0.1) natty; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * reduce disk usage during buildd builds
+    - LP: #645653
+  * [Config] enforcer -- ensure CONFIG_INIT_PASS_ALL_PARAMS is y
+  * [Config] armel -- drop omap flavour
+
+  [ Tim Gardner ]
+
+  * Added dropped patch list
+  * more dropped patches
+  * [Config] Disable aufs, dmraid-4.5, ndis-wrapper
+  * [Config] Add support for cross compiling armel
+  * [Config] CONFIG_SCSI_QLA_ISCSI=n for armel
+  * [Upstream] drivers/serial/mfd.c: Fix ARM compile error
+  * [Config]: updateconfigs after adding brcm80211
+  * staging: brcm80211: Fix Makefile syntax error
+  * rebased to v2.6.36-rc7
+
+  [ Upstream Kernel Changes ]
+
+  * (upstream) IPS driver: don't toggle CPU turbo on unsupported CPUs
+  * (upstream) IPS driver: verify BIOS provided limits
+  * intel_ips: Print MCP limit exceeded values.
+  * Staging: Add initial release of brcm80211 - Broadcom 802.11n wireless
+    LAN driver.
+  * staging: brcm80211: Fix some initialisation failure paths
+  * staging: brcm80211: Add contact info to TODO list.
+  * staging: brcm80211: use '%pM' format to print MAC address
+  * staging: brcm80211: Fix URLs for firmware files.
+  * staging: brcm80211: fix 'ERROR: "foo * bar" should be "foo *bar"'
+  * staging: brcm80211: fix "ERROR: open brace '{' following function
+    dec..."
+  * staging: brcm80211: fix "ERROR: return is not a function, paren..."
+  * staging: brcm80211: fix "ERROR: do not use assignment in if condition"
+  * staging: brcm80211: fix "ERROR: trailing statements should be on next
+    line"
+  * staging: brcm80211: fix "ERROR: that open brace { ... prev line"
+  * staging: brcm80211: fix "ERROR: while should follow close brace '}'"
+  * staging: brcm80211: fix "ERROR: do not initialise globals to 0 or NULL"
+  * staging: brcm80211: fix "ERROR: do not initialise statics to 0 or NULL"
+  * staging: brcm80211: fix "ERROR: Macros w/ complex values ...
+    parenthesis"
+  * staging: brcm80211: fix "ERROR: Macros w/ mult. statements ... do -
+    while loop"
+  * staging: brcm80211: fix 'ERROR: "(foo*)" should be "(foo *)"'
+  * staging: brcm80211: fix "ERROR: need consistent spacing around '*'"
+  * staging: brcm80211: fix "ERROR: space prohibited after that ..."
+  * staging: brcm80211: fix "ERROR: space prohibited before ...close square
+    bracket"
+  * staging: brcm80211: fix "ERROR: space required after that close brace"
+  * staging: brcm80211: fix "ERROR: space required after that ..."
+  * staging: brcm80211: fix "ERROR: space required before that ..."
+  * staging: brcm80211: fix "ERROR: spaces prohibited around that ':' ..."
+  * staging: brcm80211: fix "ERROR: spaces required around that ..."
+  * staging: brcm80211: fix "ERROR: trailing whitespace."
+  * staging: brcm80211: fix remaining checkpatch errors.
+  * staging: brcm80211: use native ctype library
+  * staging: brcm80211: use string native library
+  * staging: brcm80211: add fullmac driver
+  * Staging: brcm80211: clean up makefile cflag lines
+  * Staging: brcm80211: remove driver specific -W options
+  * staging: brcm80211: Fix compile issue when BRCM80211_PCI is not set.
+  * staging: brcm80211: Make compiling of brcm80211.ko and brcmfmac.ko
+    mutually exclusive.
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 12 Oct 2010 16:00:27 +0100
+
+linux (2.6.35-22.33) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: Add support for Intellimouse Mode in ALPS touchpad on
+    Dell E2 series Laptops"
+    - LP: #641320
+
+  [ Brian Rogers ]
+
+  * SAUCE: ir-core: Fix null dereferences in the protocols sysfs interface
+    - LP: #624701
+
+  [ Christopher James Halse Rogers ]
+
+  * SAUCE: Nouveau: Add quirk framework to disable acceleration
+    - LP: #544088, #546393
+  * SAUCE: Nouveau: Disable acceleration on MacBook Pros
+    - LP: #546393
+
+  [ John Johansen ]
+
+  * Revert "SAUCE: AppArmor: allow newer tools to load policy on older
+    kernels"
+  * SAUCE: AppArmor: allow newer tools to load policy on older kernels
+    - LP: #639758
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: Adding vdd_sdi regulator supply to OMAP3EVM
+
+  [ Upstream Kernel Changes ]
+
+  * ALSA: HDA: Enable internal speaker on Dell M101z
+    - LP: #640254
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 17 Sep 2010 13:21:28 -0700
+
+linux (2.6.35-22.32) maverick; urgency=low
+
+  [ Arjan van de Ven ]
+
+  * SAUCE: libata: Add ALPM power state accounting to the AHCI driver
+
+  [ David Henningsson ]
+
+  * SAUCE: ALSA: HDA: Enable internal mic on Dell E6410 and Dell E6510
+    - LP: #605047, #628961
+
+  [ John Johansen ]
+
+  * [Upstream] AppArmor: Fix splitting an fqname into separate namespace
+    and profile names
+    - LP: #615947
+  * [Upstream] AppArmor: Fix locking from removal of profile namespace
+    - LP: #615947
+  * SAUCE: AppArmor: allow newer tools to load policy on older kernels
+    - LP: #639758
+  * SAUCE: Improve Amazon EBS performance for EC2
+    - LP: #634316
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: i915 KMS -- blacklist i855"
+  * Revert "SAUCE: i915 KMS -- blacklist i845g"
+  * Revert "SAUCE: i915 KMS -- blacklist i830"
+  * Revert "SAUCE: i915 KMS -- support disabling KMS for known broken
+    devices"
+  * execute module-inclusion within a subshell
+    - LP: #621175
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) bounce: call flush_dcache_page() after bounce_copy_vec()
+    - LP: #633227
+  * (pre-stable) drm/i915: don't enable self-refresh on Ironlake
+    - LP: #629711
+  * (pre-stable) mm: Move vma_stack_continue into mm.h
+  * x86, hwmon: Fix unsafe smp_processor_id() in thermal_throttle_add_dev
+    - LP: #601073
+  * PM / Runtime: Make runtime_status attribute not debug-only (v. 2)
+  * PM / Runtime: Add runtime PM statistics (v3)
+  * compat: Make compat_alloc_user_space() incorporate the access_ok()
+    - CVE-2010-3081
+  * x86-64, compat: Test %rax for the syscall number, not %eax
+    - CVE-2010-3301
+  * x86-64, compat: Retruncate rax after ia32 syscall entry tracing
+    - CVE-2010-3301
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 14 Sep 2010 08:46:49 -0700
+
+linux (2.6.35-21.31) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * bodge linux-libc-dev package version due to ti-omap4 error
+  * linux-libc-dev -- ensure we can only build this on debian.master
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 13 Sep 2010 09:54:31 -0700
+
+linux (2.6.35-21.30) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: fbcon -- fix OOPs triggered by race prevention fixes
+    - LP: #614008
+
+  [ Daniel Lezcano ]
+
+  * SAUCE: fix compilation warning when CONFIG_SECURITY is not set
+
+  [ Henrik Rydberg ]
+
+  * SAUCE: Input: wacom - add fuzz parameters to features
+  * SAUCE: Input: wacom - collect device quirks into single function
+  * SAUCE: Input: wacom - add support for the Bamboo Touch trackpad
+  * SAUCE: Input: wacom - add a quirk for low resolution Bamboo devices
+  * SAUCE: hid: ntrig: Remove unused device ids
+  * SAUCE: hid: ntrig: remove sysfs nodes
+  * SAUCE: hid: ntrig: Correct logic for quirks
+  * SAUCE: hid: ntrig: zero-initialize ntrig struct
+  * SAUCE: hid: ntrig: Setup input filtering manually
+  * SAUCE: hid: ntrig: New ghost-filtering event logic
+
+  [ Leann Ogasawara ]
+
+  * SAUCE: ndiswrapper: Initialize buffer index and check its value
+    - LP: #613796
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Add support for Intellimouse Mode in ALPS touchpad on Dell E2
+    series Laptops
+    - LP: #632884
+
+  [ Ping Cheng ]
+
+  * SAUCE: Input: wacom - parse the Bamboo device family
+
+  [ Rafi Rubin ]
+
+  * SAUCE: hid: ntrig: identify firmware version (wiggled)
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NL80211_TESTMODE=n
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "input: mt: Add support for the Bamboo Touch trackpad"
+  * e1000e: initial support for 82579 LOMs
+  * e1000e: correct MAC-PHY interconnect register offset for 82579
+  * (pre-stable) ALSA: hda - Add a new hp-laptop model for Conexant 5066,
+    tested on HP G60
+    - LP: #587388
+  * DSS2: Don't power off a panel twice
+    - LP: #588243
+  * mmc: build fix: mmc_pm_notify is only available with CONFIG_PM=y
+  * Input: i8042 - reset keyboard controller wehen resuming from S2R
+    - LP: #86820
+  * ALSA: hda - Fix beep frequency on IDT 92HD73xx and 92HD71Bxx codecs
+    - LP: #414795
+  * agp/intel: Support the extended physical addressing bits on
+    Sandybridge.
+    - LP: #632488
+  * drm/i915,intel_agp: Add support for Sandybridge D0
+    - LP: #632488
+  * (pre-stable) intel_agp,i915: Add more sandybridge graphics device ids
+    - LP: #632488
+  * mmc: omap: fix for bus width which improves SD card's peformance.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 07 Sep 2010 09:58:52 -0700
+
+linux (2.6.35-20.29) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: i915 KMS -- support disabling KMS for known broken devices
+    - LP: #563277
+  * SAUCE: i915 KMS -- blacklist i830
+    - LP: #542208, #563277
+  * SAUCE: i915 KMS -- blacklist i845g
+    - LP: #541492, #563277
+  * SAUCE: i915 KMS -- blacklist i855
+    - LP: #511001, #541511, #563277
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_SENSORS_PKGTEMP=m
+    - LP: #601073
+  * ARM: Temporarily disable module check for armel
+  * rebase to v2.6.35.4
+  * [Config] update configs following rebase to v2.6.35.4
+
+  [ Ricardo Salveti de Araujo ]
+
+  * [Config] Change CONFIG_LEDS_TRIGGER_HEARTBEAT from module to built-in
+    in Omap
+
+  [ Tim Gardner ]
+
+  * [Config] Added be2net, be2scsi to udebs
+    - LP: #628776
+
+  [ Upstream Kernel Changes ]
+
+  * x86, cpu: Package Level Thermal Control, Power Limit Notification
+    definitions
+    - LP: #601073
+  * x86, hwmon: Package Level Thermal/Power: pkgtemp hwmon driver
+    - LP: #601073
+  * x86, hwmon: Package Level Thermal/Power: thermal throttling handler
+    - LP: #601073
+  * x86, hwmon: Package Level Thermal/Power: power limit
+    - LP: #601073
+  * x86, hwmon: Package Level Thermal/Power: pkgtemp documentation
+    - LP: #601073
+  * hid: 3m: Adjust to sequential MT HID protocol
+  * hid: 3m: Convert to MT slots
+  * hid: 3m: Correct touchscreen emulation
+  * hid: 3m: Adjust major / minor axes to scale
+  * input: bcm5974: Adjust major / minor to scale
+  * HID: magicmouse: don't allow hidinput to initialize the device
+  * HID: magicmouse: simplify multitouch feature request
+  * HID: magicmouse: simplify touch data bit manipulation
+  * HID: magicmouse: simplify touch down logic
+  * HID: magicmouse: remove timestamp logic
+  * HID: magicmouse: enable Magic Trackpad support
+  * HID: magicmouse: Adjust major / minor axes to scale
+  * mmc: fix all hangs related to mmc/sd card insert/removal during
+    suspend/resume
+    - LP: #477106
+  * drm/i915: fix VGA plane disable for Ironlake+
+    - LP: #602281
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 30 Aug 2010 08:38:01 -0700
+
+linux (2.6.35-19.28) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No changes from 2.6.35-19.27.  Some armel udebs were accidentally deleted
+    from the archive and a no-change rebuild was attempted.  However, the ABI
+    did not get bumped and resulted in build failures for 2.6.35-19.27.  Fix
+    up the ABI and re-upload.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sat, 28 Aug 2010 16:42:27 -0700
+
+linux (2.6.35-19.27) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * No changes from 2.6.35-19.26.  Some armel udebs were accidentally deleted
+    from the archive.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 27 Aug 2010 08:58:35 -0700
+
+linux (2.6.35-19.26) maverick; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * ARM: OMAP: Beagle: revision detection
+  * ARM: OMAP: Beagle: only Cx boards use pin 23 for write protect
+  * ARM: OMAP: Beagle: no gpio_wp pin connection on xM
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 26 Aug 2010 09:15:09 -0700
+
+linux (2.6.35-19.25) maverick; urgency=low
+
+  [ Jarod Wilson ]
+
+  * SAUCE: Bring in staging/lirc from 2.6.36
+    - LP: #609234
+  * SAUCE: Update ir-core to linuxtv/other which should be merged for
+    2.6.36.
+    - LP: #609234
+  * SAUCE: Fix memleaks in imon and mceusb drivers
+    - LP: #609234
+  * SAUCE: Bring in streamzap support from linuxtv/other
+    - LP: #609234
+
+  [ Mario Limonciello ]
+
+  * Remove ubuntu/lirc in favor of staging/lirc from 2.6.36
+    - LP: #609234
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: ARM: adding i2c eeprom driver to read EDID
+    - LP: #608279
+
+  [ Upstream Kernel Changes ]
+
+  * intel_idle: disable module support
+    - LP: #615265
+  * (pre-stable) ALSA: hda - Ensure codec patch files are checked for the
+    correct codec ID
+  * (pre-stable) ALSA: hda - Rename iMic to Int Mic on Lenovo NB0763
+    - LP: #605101
+  * (pre-stable) ALSA: HDA: Use model=auto for LG R510
+    - LP: #495134
+  * (pre-stable) ALSA: HDA: Add Sony VAIO quirk for ALC269
+    - LP: #519066
+  * (pre-stable) ALSA: HDA: Fix front mic on Dell Precision M6500
+    - LP: #519066
+  * input: mt: Initialize slots to unused (rev2)
+  * input: mt: Add support for the Bamboo Touch trackpad
+  * hid: Add a hid quirk for input sync override
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 23 Aug 2010 12:42:52 -0700
+
+linux (2.6.35-18.24) maverick; urgency=low
+
+  [ Colin Watson ]
+
+  * Pass DEB_MAINT_PARAMS to hook scripts
+
+  [ Leann Ogasawara ]
+
+  * [Config] Add CONFIG_INPUT_UINPUT=y to config enforcer
+    - LP: #584812
+  * rebase to v2.6.35.3
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) dell-wmi: Add support for eject key on Dell Studio 1555
+    - LP: #609234
+  * can: add limit for nframes and clean up signed/unsigned variables
+    - CVE-2010-2959
+  * drm: Initialize ioctl struct when no user data is present
+    - CVE-2010-2803
+  * ARM: initial stack protector (-fstack-protector) support
+  * ARM: stack protector: change the canary value per task
+  * [ARM] implement arch_randomize_brk()
+  * [ARM] add address randomization to mmap()
+  * ARM: fix ASLR of PIE executables
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sun, 22 Aug 2010 19:22:04 -0700
+
+linux (2.6.35-17.23) maverick; urgency=low
+
+  [ Jeremy Kerr ]
+
+  * [Config] build-in uinput module
+    - LP: #584812
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Config] [FTBS] ia64: Temporarily disable CONFIG_CEPH_FS"
+  * Revert "[Config] [FTBS] ia64: Temporarily disable gpiolib"
+  * Revert "[Config] [FTBS] sparc: Temporarily disable
+    CONFIG_MTD_NAND_DENALI"
+  * Revert "[Config] [FTBS] sparc: Temporarily disable
+    CONFIG_MFD_JANZ_CMODIO"
+  * Revert "[Config] [FTBS] sparc: Temporarily disable
+    CONFIG_INFINIBAND_QIB"
+  * [Config] Enable INTEL_IPS
+    - LP: #601057
+  * Remove ia64 support
+  * [Config] Update portsconfigs after removing ia64 support
+  * Remove sparc support
+  * [Config] Update portsconfigs after removing sparc support
+
+  [ Linus Torvalds ]
+
+  * (pre-stable) mm: fix page table unmap for stack guard page properly
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: (no-up) ARM: Resetting power_mode to its original value.
+    - LP: #591941
+
+  [ Upstream Kernel Changes ]
+
+  * timer: add on-stack deferrable timer interfaces
+    - LP: #601057
+  * x86 platform driver: intelligent power sharing driver
+    - LP: #601057
+  * IPS driver: add GPU busy and turbo checking
+    - LP: #601057
+  * X86: intel_ips, check for kzalloc properly
+    - LP: #601057
+  * ips driver: make it less chatty
+    - LP: #601057
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 17 Aug 2010 09:38:08 -0700
+
+linux (2.6.35-16.22) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * debian -- more agressivly clean up after depmod on purge
+    - LP: #618591
+
+  [ Henrik Rydberg ]
+
+  * SAUCE: hid: 3m: Simplify touchsreen emulation logic
+
+  [ Leann Ogasawara ]
+
+  * ubuntu: iscsitarget -- version 1.4.20.2
+  * ubuntu: rtl8192se -- update to version 0017.0507.2010
+  * rebase to v2.6.35.2
+  * [Config] update configs following rebase to v2.6.35.2
+  * [Config] update ports configs following rebase to v2.6.35.2
+
+  [ Luke Yelavich ]
+
+  * [Config] Enable new firewire stack on powerpc
+
+  [ Mathieu J. Poirier ]
+
+  * SAUCE: (drop after 2.6.35) ARM: Using gpmc function to init nand flash.
+    - LP: #608266
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 12 Aug 2010 09:58:01 -0700
+
+linux (2.6.35-15.21) maverick; urgency=low
+
+  [ Luke Yelavich ]
+
+  * [Config] CONFIG_SND_USB_UA101=m for all architectures
+
+  [ Upstream Kernel Changes ]
+
+  * Input: introduce MT event slots
+  * Input: document the MT event slot protocol
+  * (pre-stable) sched: Revert nohz_ratelimit() for now
+  * (pre-stable) drm/radeon/kms: add missing copy from user
+    - LP: #606081
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35.1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 09 Aug 2010 09:24:04 -0700
+
+linux (2.6.35-14.20) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * update Vcs-Git to point to maverick repo
+  * debian -- include the debian packaging in the -source package
+    - LP: #608674
+  * select debian source format 1.0
+  * add support for building selected stages of kernel
+    - LP: #603087
+  * cleanup conditional dependancy handling
+    - LP: #603087
+
+  [ Upstream Kernel Changes ]
+
+  * ALSA: hda - Handle missing NID 0x1b on ALC259 codec
+    - LP: #582199, #586418, #588031
+  * ALSA: hda - Handle pin NID 0x1a on ALC259/269
+    - LP: #582199, #586418, #588031
+  * sched: Revert nohz_ratelimit() for now
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 03 Aug 2010 08:46:47 -0700
+
+linux (2.6.35-14.19) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sun, 01 Aug 2010 10:35:56 -0700
+
+linux (2.6.35-13.18) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: (no-up) Modularize vesafb -- fix initialisation
+  * SAUCE: add tracing for user initiated readahead requests
+  * SAUCE: vt -- maintain bootloader screen mode and content until vt
+    switch
+  * SAUCE: vt -- allow grub to request automatic vt_handoff
+  * SAUCE: fbcon -- fix race between open and removal of framebuffers
+  * SAUCE: drm -- stop early access to drm devices
+
+  [ Bryan Wu ]
+
+  * CONFIG: compile in OTG driver and Transceiver driver
+    - LP: #566645
+  * remove OTG modules from modules list file
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: -- sync to AppArmor mainline 2010-07-27
+    - LP: #581525, #599450
+  * SAUCE: AppArmor: -- sync to AppArmor mainline 2010-07-29
+  * SAUCE: AppArmor 2.4 compatibility patch
+  * SAUCE: AppArmor: Allow dfa backward compatibility with broken userspace
+  * SAUCE: fix pv-ops for legacy Xen
+  * SAUCE: blkfront: default to sd devices
+  * [Config] Build in drivers required for Xen pv-ops
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Upstream] i915: Use the correct mask to detect i830 aperture
+    size."
+
+  [ Lee Jones ]
+
+  * SAUCE: ARM: OMAP: Add macros for comparing silicon revision
+    - LP: #608095
+  * SAUCE: OMAP: DSS2: check for both cpu type and revision, rather than
+    just revision
+    - LP: #608095
+  * SAUCE: OMAP: DSS2: enable hsclk in dsi_pll_init for OMAP36XX
+    - LP: #608095
+  * SAUCE: ARM: OMAP: Beagle: support twl gpio differences on xM
+    - LP: #608095
+
+  [ Upstream Kernel Changes ]
+
+  * agp/intel: Use the correct mask to detect i830 aperture size.
+    - LP: #597075
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 30 Jul 2010 15:46:59 -0700
+
+linux (2.6.35-12.17) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc6
+  * [Config] update configs following rebase to v2.6.35-rc6
+  * [Config] update ports configs following rebase to v2.6.35-rc6
+  * SAUCE: [FTBS] armel: define KEY_F10 and KEYF11
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 23 Jul 2010 16:16:38 +0200
+
+linux (2.6.35-11.16) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Bump ABI for new compiler update 
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 23 Jul 2010 10:24:58 +0200
+
+linux (2.6.35-10.15) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: ensure vga16fb loads if no other driver claims the VGA
+    device"
+  * [Config] Enable CONFIG_M686=y
+    - LP: #592495
+
+  [ Upstream Kernel Changes ]
+
+  * tracing: Add alignment to syscall metadata declarations
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 20 Jul 2010 18:18:49 +0200
+
+linux (2.6.35-9.14) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- add BOM and automated update script
+  * ubuntu: AUFS -- update to b37c575759dc4535ccc03241c584ad5fe69e3b25
+
+  [ John Johansen ]
+
+  * [Config] Enable DRBD as a module
+
+  [ Kees Cook ]
+
+  * SAUCE: Yama: verify inode is symlink to avoid bind mounts
+    - LP: #604407
+
+  [ Leann Ogasawara ]
+
+  * [Config] Disable CONFIG_DRM_VMWGFX (staging driver)
+    - LP: #606139
+  * [Config] ports: Disable CONFIG_DRM_VMWGFX (staging driver)
+    - LP: #606139
+  * [Config] Enable CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
+  * [Config] ports: Enable CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
+
+  [ Lee Jones ]
+
+  * Stop ARM boards crashing when CUPS is loaded
+    - LP: #601226
+
+  [ Upstream Kernel Changes ]
+
+  * perf probe: Support tracing an entry of array
+  * perf probe: Support static and global variables
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 16 Jul 2010 14:38:17 -0700
+
+linux (2.6.35-8.13) maverick; urgency=low
+
+  [ Kees Cook ]
+
+  * SAUCE: Yama: check PTRACE using thread group leader
+  * SAUCE: Yama: search for PTRACE exceptions via thread group leader
+    - LP: #603716
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc5
+  * [Config] update configs following rebase to v2.6.35-rc5
+
+  [ Nicolas Pitre ]
+
+  * SAUCE: make ndiswrapper available on X86 only
+
+  [ Tim Gardner ]
+
+  * [Config] Added ums-cypress to udeb
+    - LP: #576066
+  * SAUCE: fix build error with CONFIG_BLK_DEV_INITRD=n
+  * [Config] CONFIG_NDISWRAPPER=m across all configs
+
+  [ Upstream Kernel Changes ]
+
+  * HID: magicmouse: report last touch up
+  * rebase to 2.6.35-rc5
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 13 Jul 2010 18:57:59 -0700
+
+linux (2.6.35-7.12) maverick; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Upstream] i915: Use the correct mask to detect i830 aperture size.
+    - LP: #597075
+
+  [ Upstream Kernel Changes ]
+
+  * (drop after 2.6.35) drm/radeon/kms: add ioport register access
+    (squashed)
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 08 Jul 2010 09:53:13 -0600
+
+linux (2.6.35-7.11) maverick; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_X86_MRST=n
+
+  [ Upstream Kernel Changes ]
+
+  * (drop after 2.6.35-rc5) writeback: remove writeback_inodes_wbc
+  * (drop after 2.6.35-rc5) writeback: split writeback_inodes_wb
+  * (drop after 2.6.35-rc5) writeback: simplify the write back thread queue
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 06 Jul 2010 18:39:08 -0600
+
+linux (2.6.35-7.10) maverick; urgency=low
+
+  [ Kees Cook ]
+
+  * SAUCE: security: create task_free security callback
+  * SAUCE: Yama: add PTRACE exception tracking and interface
+  * SAUCE: security: unconditionally chain to Yama LSM
+  * Revert "SAUCE: ptrace: restrict ptrace scope to children"
+  * Revert "SAUCE: fs: block hardlinks to non-accessible sources"
+  * Revert "SAUCE: fs: block cross-uid sticky symlinks"
+  * [Upstream] security: Yama LSM
+  * [Config] Enable CONFIG_SECURITY_YAMA=y
+
+  [ Tim Gardner ]
+
+  * [Config] updateconfigs/updateportsconfigs after rebase to 2.6.35-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to 2.6.35-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 01 Jul 2010 08:55:57 -0700
+
+linux (2.6.35-6.9) maverick; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Upstream] direct_splice_actor() should not use pos in sd
+    - LP: #588861
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 28 Jun 2010 12:35:49 -0700
+
+linux (2.6.35-6.8) maverick; urgency=low
+
+  [ Mathieu J. Poirier ]
+
+  * ARM: Adding regulator supply for vdds_sdi.
+    - LP: #597904
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Sun, 27 Jun 2010 16:34:43 -0700
+
+linux (2.6.35-6.7) maverick; urgency=low
+
+  [ Alberto Milone ]
+
+  * [Upstream] Add support for the ATIF ACPI method to the radeon driver
+
+  [ Chase Douglas ]
+
+  * [Upstream] HID: magicmouse: scroll on entire surface, not just middle
+    of mouse
+  * [Upstream] HID: magicmouse: disable and add module param for scroll
+    acceleration
+  * [Upstream] HID: magicmouse: properly account for scroll movement in
+    state
+  * [Upstream] HID: magicmouse: add param for scroll speed
+  * [Upstream] HID: magicmouse: enable horizontal scrolling
+
+  [ Henrik Rydberg ]
+
+  * [Upstream] Input: evdev - convert to dynamic event buffer
+  * [Upstream] Input: evdev - use driver hint to compute size of event
+    buffer
+  * [Upstream] Input: bcm5974 - set the average number of events per MT
+    event packet
+  * [Upstream] Input: hid-input - use a larger event buffer for MT devices
+  * [Upstream] Input: evdev - never leave the client buffer empty after
+    write
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: -- mainline 2010-06-23
+  * SAUCE: AppArmor 2.4 compatibility patch
+  * SAUCE: fs: block hardlinks to non-accessible sources AppArmor portion
+
+  [ Leann Ogasawara ]
+
+  * [Config] Enable CONFIG_INTR_REMAP=y
+    - LP: #597091
+  * [Config] Enable CONFIG_X86_X2APIC
+    - LP: #597091
+
+  [ Mathieu J. Poirier ]
+
+  * [Config] ARM: Turning off CONFIG_CPU_IDLE on omap
+    - LP: #594382
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 24 Jun 2010 12:19:48 -0700
+
+linux (2.6.35-5.6) maverick; urgency=low
+
+  [ Amit Kucheria ]
+
+  * [Config] update omap flavour description
+
+  [ Andy Whitcroft ]
+
+  * update to ubuntu-debian:508b7aa34b578c0d1e51bfb571f2bfb824dc65ac
+    - LP: #570500, #576274
+  * SAUCE: add option to hand off all kernel parameters to init
+    - LP: #586386
+  * [Config] enable passing all kernel command line to init
+    - LP: #586386
+  * [Config] disable CONFIG_VMI
+    - LP: #537601
+  * [Config] enable CONFIG_IPV6_SIT_6RD
+    - LP: #591869
+  * [Config] enable CONFIG_VMWARE_BALOON as module
+    - LP: #592039
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: pm: Config option to disable handling of console during
+    suspend/resume"
+    - LP: #594885
+  * [Config] Remove CONFIG_PM_DISABLE_CONSOLE
+  * [Config] ports: enable passing all kernel command line to init
+    - LP: #586386
+  * [Config] Enable CONFIG_FB_VESA=y for x86
+  * [Config] Add CONFIG_FRAMEBUFFER_CONSOLE=y to config enforcer
+  * [Config] Add CONFIG_FB_VESA=y for x86 to config enforcer
+  * [Config] Enable CONFIG_TASK_DELAY_ACCT=y
+    - LP: #493156
+
+  [ Mathieu Poirier ]
+
+  * ARM: Adding MosChip MCS7830 to nic-usb
+    - LP: #584920
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[Upstream] docbook: need xmldoclinks for all doc types"
+  * docbook: need xmldoclinks for all doc types
+  * perf probe: Add kernel source path option
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 17 Jun 2010 08:05:29 -0700
+
+linux (2.6.35-4.5) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Revert "[Upstream] (evdev) Use driver hint to compute the evdev buffer
+    size (rev2)"
+  * Revert "[Upstream] (evdev) Convert to dynamic event buffer (rev4)"
+  * Revert "[Upstream] (evdev) Use multi-reader buffer to save space
+    (rev4)"
+  * Revert "SAUCE: drivers: Remove some duplicate device entries in various
+    modules"
+  * [Upstream] USB: option: Remove duplicate AMOI_VENDOR_ID
+  * [Upstream] Revert "USB: Adding support for HTC Smartphones to ipaq"
+  * [Upstream] p54usb: Comment out duplicate Medion MD40900 device id
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_NFS_FSCACHE=y
+    - LP: #440522
+  * [Config] CONFIG_FSCACHE_STATS=y, CONFIG_FSCACHE_HISTOGRAM=y
+    - LP: #440522
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 16 Jun 2010 08:43:07 -0700
+
+linux (2.6.35-3.4) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * debian -- ensure the version number is clean
+
+  [ Henrik Rydberg ]
+
+  * [Upstream] Introduce MT event slots (rev 5)
+  * [Upstream] Document the MT event slot protocol (rev5)
+  * [Upstream] (evdev) Use multi-reader buffer to save space (rev4)
+  * [Upstream] (evdev) Convert to dynamic event buffer (rev4)
+  * [Upstream] (evdev) Use driver hint to compute the evdev buffer size
+    (rev2)
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: Add MODULE_ALIAS for Dell WMI module"
+  * Revert "SAUCE: hostap: send events on data interface as well as master
+    interface"
+  * Revert "Fix webcam having USB ID 0ac8:303b"
+  * Revert "SAUCE: toshiba_acpi -- pull in current -dev version of driver"
+  * rebase to v2.6.35-rc3
+
+  [ Maxim Levitsky ]
+
+  * [Config] Enable new Smartmedia/xD translation layer
+    - LP: #202490
+
+  [ Upstream Kernel Changes ]
+
+  * net: fix deliver_no_wcard regression on loopback device
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.35-rc3
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 10 Jun 2010 16:15:22 -0700
+
+linux (2.6.35-2.3) maverick; urgency=low
+
+  [ Bryan Wu ]
+
+  * CONFIG: enforce -- make sure we disable CONFIG_LOCALVERSION_AUTO
+
+  [ Leann Ogasawara ]
+
+  * [Config] armel: Enable CONFIG_BNX2=m
+  * [Config] ports: Enable CONFIG_BNX2X=m
+  * SAUCE: armel: define get_dma_ops to fix FTBS
+
+  [ Tim Gardner ]
+
+  * [Upstream] net: Print num_rx_queues imbalance warning only when there
+    are allocated queues
+    - LP: #591416
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 09 Jun 2010 08:27:41 -0700
+
+linux (2.6.35-2.2) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] d-i: make armel configuration versatile flavour specific
+    - LP: #588805
+  * [Config] d-i: enable .udebs for omap flavour
+    - LP: #588805
+
+  [ Kees Cook ]
+
+  * ptrace: limit scope to attach only (allow read)
+    - LP: #589656
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc2
+  * [Config] update configs following rebase to v2.6.35-rc2
+  * [Config] update port configs following rebase to v2.6.35-rc2
+
+  [ Lee Jones ]
+
+  * Enable perf to be more helpful when perf_<version> does not exist.
+    - LP: #570500
+  * 'fdr editconfig' modification. Easily skip over unwanted menuconfigs.
+
+  [ Tim Gardner ]
+
+  * [Config] Update bnx2 udeb firmware files
+    - LP: #589304
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.35-rc2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Mon, 07 Jun 2010 09:45:04 -0700
+
+linux (2.6.35-1.1) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ubuntu: AUFS -- update to standalone 2.6.35-rcN as at 20100601
+    - LP: #587888
+  * ubuntu: AUFS -- track changes to the arguements to fop fsync()
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.35-rc1
+  * [Config] update configs following rebase to v2.6.35-rc1
+  * [Config] update port configs following rebase to v2.6.35-rc1
+  * SAUCE: lirc: rename usb_buffer_alloc() and usb_buffer_free()
+  * SAUCE: ndiswrapper: rename usb_buffer_alloc() and usb_buffer_free()
+  * SAUCE: ndiswrapper: convert multicast list to list_head
+  * [Config] [FTBS] armel: Temporarily disable CONFIG_GPIO_JANZ_TTL
+  * [Config] [FTBS] ia64: Temporarily disable gpiolib
+  * [Config] [FTBS] ia64: Temporarily disable CONFIG_CEPH_FS
+  * [Config] [FTBS] sparc: Temporarily disable CONFIG_INFINIBAND_QIB
+  * [Config] [FTBS] sparc: Temporarily disable CONFIG_MFD_JANZ_CMODIO
+  * [Config] [FTBS] armel: Temporarily disable CONFIG_MFD_JANZ_CMODIO
+  * [Config] [FTBS] armel: Temporarily disable CONFIG_DT3155
+  * [Config] [FTBS] sparc: Temporarily disable CONFIG_MTD_NAND_DENALI
+  * [Config] [FTBS] armel: Temporarily disable bnx2
+  * [Config] [FTBS] armel: Temporarily disable CONFIG_SERIAL_UARTLITE
+  * SAUCE: [FTBS] armel: Don't include asm/agp.h for ttm
+  * SAUCE: [FTBS] armel: include linux/dma-mapping.h
+  * SAUCE: [FTBS] armel: replace omap_set_gpio_debounce with
+    gpio_set_debounce
+
+  [ Upstream Kernel Changes ]
+
+  * of/usb: fix build error due to of_node pointer move
+  * n2_crypto: Fix build after of_device/of_platform_driver changes.
+  * powerpc/fsl-booke: fix the case where we are not in the first page
+  * powerpc/fsl-booke: Move the entry setup code into a seperate file
+  * powerpc/kexec: Add support for FSL-BookE
+  * greth: Fix build after OF device conversions.
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.35-rc1
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 04 Jun 2010 23:01:52 -0700
+
+linux (2.6.35-1.0) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Null entry.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 02 Jun 2010 15:17:41 -0700
+
+linux (2.6.34-5.14) maverick; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Added module inclusion support
+  * [Config] Added virtual flavour module inclusion list and d-i package
+    definitions
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 02 Jun 2010 12:58:14 -0700
+
+linux (2.6.34-5.13) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "ubuntu: AUFS -- aufs2 20091209"
+  * Revert "ubuntu: AUFS -- export various core functions
+    (aufs2-standalone.patch)"
+  * Revert "ubuntu: AUFS -- export various core functions
+    (aufs2-base.patch)"
+  * ubuntu: AUFS -- aufs2 base patch for linux-2.6.34
+    - LP: #587888
+  * ubuntu: AUFS -- aufs2 standalone patch for linux-2.6.34
+    - LP: #587888
+  * ubuntu: AUFS -- update to standalone 2.6.34 as at 20100601
+    - LP: #587888
+  * [Config] AUFS -- enable aufs options
+    - LP: #587888
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 01 Jun 2010 08:56:43 -0700
+
+linux (2.6.34-5.12) maverick; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * enforce -- ensure SYSFS compatibility is disabled
+
+  [ Chase Douglas ]
+
+  * build with libdw-dev for perf probe symbol support
+  * maverick ftrace configuration changes
+
+  [ Kees Cook ]
+
+  * Revert "SAUCE: x86: brk away from exec rand area"
+  * Revert "SAUCE: [um] Don't use nx_enabled under UML"
+  * Revert "SAUCE: [x86] implement cs-limit nx-emulation for ia32"
+  * SAUCE: x86: implement cs-limit nx-emulation for ia32
+    - LP: #369978
+  * SAUCE: x86: more tightly confine cs-limit nx-emulation to ia32 only
+  * SAUCE: x86: brk away from exec rand area
+    - LP: #452175
+  * SAUCE: ptrace: restrict ptrace scope to children
+
+  [ Leann Ogasawara ]
+
+  * Add new omap flavour to getabis
+  * [Config] Enable CONFIG_FRAMEBUFFER_CONSOLE=y for all archs
+    - LP: #585490
+  * build/modules: Temorarily add ignore.modules
+  * ubuntu: iscsitarget -- version 1.4.20.1
+
+  [ Loïc Minier ]
+
+  * SAUCE: [um] Don't use nx_enabled under UML
+    - LP: #524849
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 28 May 2010 08:27:17 -0700
+
+linux (2.6.34-4.11) maverick; urgency=low
+
+  [ Amit Kucheria ]
+
+  * SAUCE: omap: remove calls to usb_nop_xceiv_register from board files
+  * [Config] Add support for OMAP-mainline flavour
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: powerpc: fix compile error when ptrace.h is included from
+    userspace
+    - LP: #583733
+
+  [ Chase Douglas ]
+
+  * Revert "SAUCE: Don't register vga16fb framebuffer if other framebuffers
+    are present"
+  * Revert "SAUCE: Disable function tracing after hitting __schedule_bug"
+  * Revert "SAUCE: drm/i915: don't change DRM configuration when releasing
+    load detect pipe"
+
+  [ Kees Cook ]
+
+  * SAUCE: fs: block cross-uid sticky symlinks
+  * SAUCE: fs: block hardlinks to non-accessible sources
+
+  [ Koen Kooi ]
+
+  * SAUCE: board-omap3-beagle: add DSS2 support
+
+  [ Leann Ogasawara ]
+
+  * Revert "staging/go7007 -- disable"
+  * Revert "[Config] staging/winbond -- disable"
+  * Revert "Disable 4MB page tables for Atom, work around errata AAE44"
+  * Revert "SAUCE: sync before umount to reduce time taken by ext4 umount"
+  * Revert "SAUCE: Enable an e1000e Intel Corporation 82567 Gigabit
+    controller"
+  * Revert "SAUCE: Fix MODULE_IMPORT/MODULE_EXPORT"
+  * Revert "SAUCE: Created MODULE_EXPORT/MODULE_IMPORT macros"
+  * Revert "SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps"
+  * Revert "SAUCE: r8169: disable TSO by default for RTL8111/8168B
+    chipsets."
+  * Revert "[Upstream] b43: Declare all possible firmware files."
+  * Revert "add Breaks: against hardy lvm2"
+  * Revert "SAUCE: Guest OS does not recognize a lun with non zero target
+    id on Vmware ESX Server"
+  * Revert "SAUCE: Catch nonsense keycodes and silently ignore"
+  * [Config] Enable CONFIG_ECRYPT_FS=y for ports
+  * [Config] Enable CONFIG_USB=y for armel and sparc
+  * [Config] Enable CONFIG_SCSI=y for ia64 and sparc
+  * [Config] Enable CONFIG_RFKILL=y for ports
+  * [Config] Enable CONFIG_ATH9K_DEBUGFS=y
+  * [Config] Enable CONFIG_IWMC3200TOP_DEBUGFS=y
+  * [Config] Enable CONFIG_RCU_FAST_NO_HZ=y
+  * [Config] Enable CONFIG_IWLWIFI_DEVICE_TRACING=y
+  * [Config] Enable CONFIG_LIBERTAS_MESH=y
+  * [Config] Enable CONFIG_MMC_RICOH_MMC=y
+  * [Config] CONFIG_RT2800USB_UNKNOWN=y
+  * [Config] Enable CONFIG_VGA_SWITCHEROO=y
+  * [Config] Enable CONFIG_CEPH_FS=m
+  * [Config] Enable CONFIG_CRYPTO_PCRYPT=m
+  * [Config] Enable CONFIG_EEEPC_WMI=m
+  * [Config] Enable CONFIG_RT2800PCI=m
+  * [Config] Enable CONFIG_SCSI_HPSA=m
+  * [Config] Enable CONFIG_VHOST_NET=m
+  * [Config] Disable CONFIG_SND_HDA_INPUT_BEEP_MODE by default
+    - LP: #582350
+  * [Config] Disable CONFIG_SOUND_OSS* and CONFIG_SND_*OSS
+    - LP: #579300
+  * [Config] Enable CONFIG_PCIEASPM=y
+    - LP: #333990
+  * [Config] updateconfigs for OMAP flavour
+
+  [ Loïc Minier ]
+
+  * Enable perf tools on armel
+
+  [ Tim Gardner ]
+
+  * SAUCE: Updated ndiswrapper to 1.56
+    - LP: #582555
+  * [Config] Added virtual flavour
+  * [Config] Remove support for sub-flavours
+  * [Config] Removed amd64 preempt flavour
+  * [Config] updateconfigs, updateportsconfigs after flavour munging
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 25 May 2010 09:34:55 -0700
+
+linux (2.6.34-3.10) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 18 May 2010 17:35:35 -0700
+
+linux (2.6.34-2.9) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] [FTBS] Disable comedi for armel
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 13 May 2010 23:20:55 +0200
+
+linux (2.6.34-2.8) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Drop lpia
+  * [Config] [FTBS] disable KVM
+  * [Config] [FTBS] disable ipr for armel
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 13 May 2010 16:07:52 +0200
+
+linux (2.6.34-2.7) maverick; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Config] disable CONFIG_SCSI_IPR on powerpc
+  * [Config] Remove 386 flavour per UDS discussion
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 12 May 2010 18:26:43 +0200
+
+linux (2.6.34-1.6) maverick; urgency=low
+
+  [ Chase Douglas ]
+
+  * enforce CONFIG_TMPFS_POSIX_ACL=y
+    - LP: #575940
+  * don't force module dependency checking
+    - LP: #577029
+
+  [ Kees Cook ]
+
+  * SAUCE: mmap_min_addr check CAP_SYS_RAWIO only for write
+    - LP: #568844
+
+  [ Leann Ogasawara ]
+
+  * Revert "SAUCE: ata: blacklist FUJITSU MHW2160BH PL"
+  * rebase to v2.6.34-rc7
+  * [Config] update configs following rebase to v2.6.34-rc7
+  * [Config] update port configs following rebase to v2.6.34-rc7
+  * Add btrfs to the udebs
+
+  [ Tim Gardner ]
+
+  * [Config] Add atl1c to nic-modules udeb
+    - LP: #557130
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc7
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 11 May 2010 11:29:08 +0200
+
+linux (2.6.34-1.5) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34-rc6
+  * [Config] update configs following rebase to v2.6.34-rc6
+  * [Config] update port configs following rebase to v2.6.34-rc6
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc6
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Fri, 30 Apr 2010 15:54:05 +0100
+
+linux (2.6.34-1.4) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34-rc5
+  * [Config] update ports configs following rebase to v2.6.34-rc5
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc5
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Thu, 22 Apr 2010 15:36:12 -0700
+
+linux (2.6.34-1.3) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34-rc4
+  * [Config] update configs following rebase to v2.6.34-rc4
+  * [Config] update port configs following rebase to v2.6.34-rc4
+  * ubuntu: dm-raid4-5 -- update to compile with 2.6.34-rc4
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc4
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 13 Apr 2010 18:33:44 -0700
+
+linux (2.6.34-1.2) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Temorarily disable building linux-doc
+  * rebase to v2.6.34-rc3
+  * [Config] update configs following rebase to v2.6.34-rc3
+  * [Config] update port configs following rebase to v2.6.34-rc3
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc3
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 30 Mar 2010 16:55:44 -0700
+
+linux (2.6.34-1.1) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * rebase to v2.6.34-rc2
+  * ubuntu: dm-raid4-5 -- update to compile with 2.6.34-rc2
+  * [Config] update port configs following rebase to v2.6.34-rc2
+  * [Config] update configs following rebase to v2.6.34-rc2
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.34-rc2
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 24 Mar 2010 23:00:39 -0700
+
+linux (2.6.33-1.1) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * ubuntu: dm-raid4-5 -- update to compile with 2.6.33
+  * ubuntu: lirc -- drop explicit include of linux/autoconf.h
+  * ubuntu: lirc -- pass kfifo to kfifo_alloc and move spinlock
+  * ubuntu: lirc -- rename kfifo_put and kfifo_get
+  * ubuntu: iscsitarget -- rename daddr inet_sock field
+  * rebased to v2.6.33
+  * [Config] update configs following rebase to v2.6.33
+  * [Config] update ports configs following rebase to v2.6.33
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.33
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Tue, 23 Mar 2010 03:55:46 -0700
+
+linux (2.6.33-0.0) UNRELEASED; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * Null entry.
+
+ -- Leann Ogasawara <leann.ogasawara@canonical.com>  Wed, 17 Mar 2010 07:48:56 -0700
+
+linux (2.6.32-16.25) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * linux-tools -- move to Suggests: with explicit seeding
+    - LP: #534635
+
+  [ Tim Gardner ]
+
+  * [Config] CONFIG_HID=m
+
+  [ Upstream Kernel Changes ]
+
+  * (pre-stable) sched: Fix SMT scheduler regression in
+    find_busiest_queue()
+  * KVM: introduce kvm_vcpu_on_spin
+  * KVM: VMX: Add support for Pause-Loop Exiting
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 09 Mar 2010 14:13:51 +0000
+
+linux (2.6.32-16.24) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * armel -- perf userspace does not support arm
+  * ia64 -- libelf-dev/binutils-dev to not provide necessary libraries
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 06 Mar 2010 11:42:12 +0000
+
+linux (2.6.32-16.23) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: PM report driver and device suspend/resume times -- move config
+  * update to standards version 3.8.4.0
+  * printenv -- expose all of the package selectors
+  * source package -- cleanup source content control
+  * doc package -- ensure we do build package content on buildd
+  * lintian -- correct the address in the debian/copyright
+  * lintian -- update debhelper package version dependancy
+  * lintian -- fix ghostscript dependancy
+  * lintian -- add required misc:Depends
+  * lintian -- move our debhelper compat level to debian/compat
+  * perf -- build the kernel carried tools
+  * perf -- add linux-tools carrying the version switches and manuals
+  * SAUCE: fix up Kconfig for staging drivers
+  * [Config] enable NOUVEAU etc following drm backport
+  * update DRM to mainline v2.6.33
+  * [Config] Remove AppArmor config options that no longer exist (ports)
+  * [Config] updateportsconfigs following drm update
+
+  [ John Johansen ]
+
+  * ubuntu: AppArmor -- update to mainline 2010-03-04
+  * SAUCE: AppArmor: Reintroduce AppArmor 2.4 compatibility
+  * SAUCE: AppArmor: replace strim with strstrip for 2.6.32 kernels
+  * [Config] Remove AppArmor config options that no longer exist
+
+  [ Manoj Iyer ]
+
+  * ubuntu: rtl8192se -- version 2010-0115,0014
+    - LP: #530275
+  * [Config] added CONFIG_RTL8192SE module.
+    - LP: #530275
+
+  [ Tim Gardner ]
+
+  * [Config] Added vmw_pvscsi to d-i/scsi-modules
+    - LP: #531017
+  * [Upstream] netfilter: xt_recent: Add an entry reaper
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "KVM: x86 emulator: Check CPL level during privilege instruction
+    emulation"
+  * Revert "KVM: x86 emulator: Fix popf emulation"
+  * Revert "KVM: x86 emulator: Check IOPL level during io instruction
+    emulation"
+  * Revert "KVM: x86 emulator: Add Virtual-8086 mode of emulation"
+  * Revert "KVM: fix memory access during x86 emulation."
+  * Add vlan (8021.Q) module package for d-i.
+  * (pre-stable) drm/i915: blacklist lid status: Sony VGN-BX196VP, Dell
+    Inspiron 700m
+    - LP: #515246
+  * [Upstream] docbook: need xmldoclinks for all doc types
+  * x86: set_personality_ia32() misses force_personality32
+  * lib: Introduce generic list_sort function
+  * drm/nv50: Implement ctxprog/state generation.
+  * drm/nv50: Remove redundant/incorrect ctxvals initialisation.
+  * (pre-stable) drm/i915: blacklist lid status: Sony VGN-BX196VP, Dell
+    Inspiron 700m
+    - LP: #515246
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Mar 2010 15:40:38 +0000
+
+linux (2.6.32-15.22) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] added new config option CONFIG_SR_REPORT_TIME_LIMIT"
+  * Revert "SAUCE: PM report driver and device suspend/resume times."
+  * [Config] set CONFIG_SR_REPORT_TIME_LIMIT
+
+  [ Manoj Iyer ]
+
+  * SAUCE: PM report driver and device suspend/resume times.
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 02 Mar 2010 01:35:37 +0000
+
+linux (2.6.32-15.21) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "(pre-stable) drm/i915: Increase fb alignment to 64k"
+  * Revert "[Config] lenovo-sl-laptop -- enable"
+  * Revert "ubuntu: lenovo-sl-laptop -- git tip (b19a08f81f)"
+  * armel -- cramfs module will no longer be built
+  * d-i -- make all modules optional
+  * rename the debug packages to match archive standard
+    - LP: #527837
+  * lenovo-sl-laptop is no longer built
+
+  [ Colin Ian King ]
+
+  * Disable 4MB page tables for Atom, work around errata AAE44
+    - LP: #523112
+
+  [ Colin Watson ]
+
+  * ubuntu: dm-raid4-5: Depend on XOR_BLOCKS
+  * ubuntu: fsam7400: Depend on CHECK_SIGNATURE
+
+  [ Jesse Barnes ]
+
+  * SAUCE: drm/i915: don't change DRM configuration when releasing load
+    detect pipe
+    - LP: #488328
+
+  [ Loïc Minier ]
+
+  * [Config] armel Update versatile initrd configs
+    - LP: #524893
+  * SAUCE: [um] Don't use nx_enabled under UML
+    - LP: #524849
+
+  [ Manoj Iyer ]
+
+  * [Config] added new config option CONFIG_SR_REPORT_TIME_LIMIT
+
+  [ Mario Limonciello ]
+
+  * SAUCE: v3 - Add Dell Business Class Netbook LED driver
+
+  [ Rafael J. Wysocki ]
+
+  * SAUCE: PM report driver and device suspend/resume times.
+
+  [ Surbhi Palande ]
+
+  * Revert "[Upstream] e1000e: enhance frame fragment detection"
+    - CVE-2009-4538
+  * Revert "[Upstream] e1000: enhance frame fragment detection"
+    - CVE-2009-4536
+
+  [ Tim Gardner ]
+
+  * [Config] Enabled CONFIG_LEDS_DELL_NETBOOKS=m
+  * SAUCE: (pre-stable) netfilter: xt_recent: fix buffer overflow
+  * SAUCE: (pre-stable) netfilter: xt_recent: fix false match
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "(pre-stable) eCryptfs: Add getattr function"
+  * Fix potential crash with sys_move_pages
+  * futex_lock_pi() key refcnt fix
+  * futex: Handle user space corruption gracefully
+  * futex: Handle futex value corruption gracefully
+  * Fix race in tty_fasync() properly
+  * hwmon: (w83781d) Request I/O ports individually for probing
+  * hwmon: (lm78) Request I/O ports individually for probing
+  * hwmon: (adt7462) Wrong ADT7462_VOLT_COUNT
+  * ALSA: ctxfi - fix PTP address initialization
+  * drm/i915: disable hotplug detect before Ironlake CRT detect
+  * drm/i915: enable self-refresh on 965
+  * drm/i915: Disable SR when more than one pipe is enabled
+  * drm/i915: Fix DDC on some systems by clearing BIOS GMBUS setup.
+  * drm/i915: Add HP nx9020/SamsungSX20S to ACPI LID quirk list
+  * drm/i915: Fix the incorrect DMI string for Samsung SX20S laptop
+  * drm/i915: Add MALATA PC-81005 to ACPI LID quirk list
+  * usb: r8a66597-hcd: Flush the D-cache for the pipe-in transfer buffers.
+  * i2c-tiny-usb: Fix on big-endian systems
+  * drm/i915: handle FBC and self-refresh better
+  * drm/i915: Increase fb alignment to 64k
+  * drm/i915: Update write_domains on active list after flush.
+  * regulator: Fix display of null constraints for regulators
+  * ALSA: hda-intel: Avoid divide by zero crash
+  * CPUFREQ: Fix use after free of struct powernow_k8_data
+  * freeze_bdev: don't deactivate successfully frozen MS_RDONLY sb
+  * cciss: Make cciss_seq_show handle holes in the h->drv[] array
+  * ioat: fix infinite timeout checking in ioat2_quiesce
+  * resource: add helpers for fetching rlimits
+  * fs/exec.c: restrict initial stack space expansion to rlimit
+  * cifs: fix length calculation for converted unicode readdir names
+  * NFS: Fix a reference leak in nfs_wb_cancel_page()
+  * NFS: Try to commit unstable writes in nfs_release_page()
+  * NFSv4: Don't allow posix locking against servers that don't support it
+  * NFSv4: Ensure that the NFSv4 locking can recover from stateid errors
+  * NFS: Fix an Oops when truncating a file
+  * NFS: Fix a umount race
+  * NFS: Fix a bug in nfs_fscache_release_page()
+  * NFS: Fix the mapping of the NFSERR_SERVERFAULT error
+  * md: fix 'degraded' calculation when starting a reshape.
+  * V4L/DVB: dvb-core: fix initialization of feeds list in demux filter
+  * Export the symbol of getboottime and mmonotonic_to_bootbased
+  * kvmclock: count total_sleep_time when updating guest clock
+  * KVM: PIT: control word is write-only
+  * tpm_infineon: fix suspend/resume handler for pnp_driver
+  * amd64_edac: Do not falsely trigger kerneloops
+  * netfilter: nf_conntrack: fix memory corruption with multiple namespaces
+  * netfilter: nf_conntrack: per netns nf_conntrack_cachep
+  * netfilter: nf_conntrack: restrict runtime expect hashsize modifications
+  * netfilter: xtables: compat out of scope fix
+  * netfilter: nf_conntrack: fix hash resizing with namespaces
+  * drm/i915: remove full registers dump debug
+  * drm/i915: add i915_lp_ring_sync helper
+  * drm/i915: Don't wait interruptible for possible plane buffer flush
+  * dasd: remove strings from s390dbf
+  * crypto: padlock-sha - Add import/export support
+  * wmi: Free the allocated acpi objects through wmi_get_event_data
+  * dell-wmi, hp-wmi, msi-wmi: check wmi_get_event_data() return value
+  * /dev/mem: introduce size_inside_page()
+  * devmem: check vmalloc address on kmem read/write
+  * devmem: fix kmem write bug on memory holes
+  * SCSI: mptfusion : mptscsih_abort return value should be SUCCESS instead
+    of value 0.
+  * sh: Couple kernel and user write page perm bits for CONFIG_X2TLB
+  * ALSA: hda - use WARN_ON_ONCE() for zero-division detection
+  * dst: call cond_resched() in dst_gc_task()
+  * ALSA: hda - Improved MacBook (Pro) 5,1 / 5,2 support
+  * befs: fix leak
+  * rtc-fm3130: add missing braces
+  * Call flush_dcache_page after PIO data transfers in libata-sff.c
+  * ahci: add Acer G725 to broken suspend list
+  * pktgen: Fix freezing problem
+  * x86/amd-iommu: Fix IOMMU-API initialization for iommu=pt
+  * x86/amd-iommu: Fix deassignment of a device from the pt_domain
+  * x86: Re-get cfg_new in case reuse/move irq_desc
+  * Staging: fix rtl8187se compilation errors with mac80211
+  * ALSA: usb-audio - Avoid Oops after disconnect
+  * serial: 8250: add serial transmitter fully empty test
+  * sysfs: sysfs_sd_setattr set iattrs unconditionally
+  * class: Free the class private data in class_release
+  * USB: usbfs: only copy the actual data received
+  * USB: usbfs: properly clean up the as structure on error paths
+  * rtl8187: Add new device ID
+  * ACPI: Add NULL pointer check in acpi_bus_start
+  * ACPI: fix High cpu temperature with 2.6.32
+  * drm/radeon/kms: use udelay for short delays
+  * NFS: Too many GETATTR and ACCESS calls after direct I/O
+  * eCryptfs: Add getattr function
+  * b43: Fix throughput regression
+  * ath9k: Fix sequence numbers for PAE frames
+  * mac80211: Fix probe request filtering in IBSS mode
+  * iwlwifi: Fix to set correct ht configuration
+  * dm stripe: avoid divide by zero with invalid stripe count
+  * dm log: userspace fix overhead_size calcuations
+  * Linux 2.6.32.9
+  * sfc: Fix SFE4002 initialisation
+  * sfc: Fix sign of efx_mcdi_poll_reboot() error in efx_mcdi_poll()
+  * sfc: SFE4002/SFN4112F: Widen temperature and voltage tolerances
+  * (pre-stable) HID: handle joysticks with large number of buttons
+    - LP: #492056
+  * (pre-stable) HID: extend mask for BUTTON usage page
+    - LP: #492056
+  * PM: Measure device suspend and resume times
+  * e1000: enhance frame fragment detection
+    - CVE-2009-4536
+  * e1000e: enhance frame fragment detection
+    - CVE-2009-4538
+  * KVM: fix memory access during x86 emulation.
+    - CVE-2010-0306
+  * KVM: x86 emulator: Add Virtual-8086 mode of emulation
+    - CVE-2010-0306
+  * KVM: x86 emulator: Check IOPL level during io instruction emulation
+    - CVE-2010-0306
+  * KVM: x86 emulator: Fix popf emulation
+    - CVE-2010-0306
+  * KVM: x86 emulator: Check CPL level during privilege instruction
+    emulation
+    - CVE-2010-0306
+  * Input: wacom - ensure the device is initialized properly upon resume
+  * Input: wacom - add defines for packet lengths of various devices
+  * Input: wacom - add support for new LCD tablets
+    - LP: #516777
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 01 Mar 2010 22:56:28 +0000
+
+linux (2.6.32-14.20) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebuild following the GCC update to match compiler for out of tree modules
+  * Revert "[Config] drbd -- enable"
+  * Revert "ubuntu: drbd -- version 8.3.1"
+  * SAUCE: khubd -- switch USB product/manufacturer/serial handling to RCU
+    - LP: #510937
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 19 Feb 2010 18:47:18 +0000
+
+linux (2.6.32-14.19) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * ensure we build the source package contents when enabled
+    - LP: #522308
+  * [Config] enable CONFIG_X86_MCE_XEON75XX
+  * SAUCE: AppArmor -- add linux/kref.h for struct kref
+  * [Config] enable CONFIG_HID_ORTEK
+  * enable udeb generation for arm versatile flavour
+    - LP: #522515
+
+  [ John Johansen ]
+
+  * ubuntu: AppArmor -- update to mainline 2010-02-18
+    - LP: #439560, #496110, #507069
+
+  [ Johnathon Harris ]
+
+  * SAUCE: HID: add support for Ortek WKB-2000
+    - LP: #405390
+
+  [ Upstream Kernel Changes ]
+
+  * tpm_tis: TPM_STS_DATA_EXPECT workaround
+    - LP: #490487
+  * x86, mce: Xeon75xx specific interface to get corrected memory error
+    information
+  * x86, mce: Rename cpu_specific_poll to mce_cpu_specific_poll
+  * x86, mce: Make xeon75xx memory driver dependent on PCI
+  * drm/edid: Unify detailed block parsing between base and extension
+    blocks
+    - LP: #500999
+  * (pre-stable) eCryptfs: Add getattr function
+    - LP: #390833
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 18 Feb 2010 19:22:02 +0000
+
+linux (2.6.32-13.18) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "enforcer -- make the enforcement configuration common"
+  * Revert "(pre-stable) Input: ALPS - add interleaved protocol support
+    (Dell E6x00 series)"
+  * Revert "(pre-stable) driver-core: fix devtmpfs crash on s390"
+  * Revert "(pre-stable) Driver-Core: devtmpfs - set root directory mode to
+    0755"
+  * Revert "SAUCE: Adds support for COMPAL JHL90 webcam"
+  * Revert "SAUCE: fix kernel oops in VirtualBox during paravirt patching"
+  * Revert "SAUCE: make fc transport removal of target configurable"
+  * enforcer -- make the enforcement configuration common
+  * getabis -- add preempt flavour to the list
+  * [Config] enforce DEVTMPFS options
+  * [Config] armel -- cleanup to-be builtin modules
+  * [Config] cleanup ports configs
+  * [Config] enable CRYPTO_GHASH_CLMUL_NI_INTEL
+    - LP: #485536
+  * add printdebian target to find branch target
+  * distclean -- do not remove debian.env
+  * [Config] generic-pae switch to M586TSC
+    - LP: #519448
+  * git-ubuntu-log -- commonise duplicated log handling
+  * git-ubuntu-log -- tighten up Bug: NNNN matching
+  * git-ubuntu-log -- sort the bug numbers
+
+  [ Chris Wilson ]
+
+  * (pre-stable) drm/i915: Increase fb alignment to 64k
+    - LP: #404064
+
+  [ Eric Miao ]
+
+  * arm -- enable ubuntu/ directory
+
+  [ Huang Ying ]
+
+  * SAUCE: crypto: ghash - Add PCLMULQDQ accelerated implementation
+  * SAUCE: crypto: ghash-intel - Fix building failure on x86_32
+
+  [ Loïc Minier ]
+
+  * [Config] cleanup preempt configuration
+  * [Config] versatile: Fix video output
+    - LP: #517594
+  * [Config] armel DEFAULT_MMAP_MIN_ADDR=32768
+  * [Config] Large update to armel/versatile
+  * [Config] versatile: Add RTC support
+  * [Config] armel: Enable NEON
+  * [Config] versatile: Builtin MMC support
+  * [Config] versatile Builtin SCSI controller
+  * [Config] armel Disable dma_cache_sync callers
+  * [Config] armel Disable asm/time.h users
+  * [Config] armel Disable out of range udelay()
+  * [Config] armel Disable flush_cache_range() users
+  * [Config] armel -- Enable ubuntu/ drivers
+
+  [ Steve Conklin ]
+
+  * SAUCE: drm/i915: Add display hotplug event on Ironlake
+  * SAUCE: drm/i915: Add ACPI OpRegion support for Ironlake
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "[Upstream]: oprofile/x86: add Xeon 7500 series support"
+  * Revert "Revert "[Bluetooth] Eliminate checks for impossible conditions
+    in IRQ handler""
+  * clockevent: Don't remove broadcast device when cpu is dead
+  * clockevents: Add missing include to pacify sparse
+  * ACPI: don't cond_resched if irq is disabled
+  * be2net: Add support for next generation of BladeEngine device.
+  * be2net: Add the new PCI IDs to PCI_DEVICE_TABLE.
+  * mpt2sas: New device SAS2208 support is added
+  * ar9170: Add support for D-Link DWA 160 A2
+  * powerpc/fsl: Add PCI device ids for new QoirQ chips
+  * davinci: dm646x: Add support for 3.x silicon revision
+  * Input: ALPS - add interleaved protocol support (Dell E6x00 series)
+  * Driver-Core: devtmpfs - set root directory mode to 0755
+  * driver-core: fix devtmpfs crash on s390
+  * vfs: get_sb_single() - do not pass options twice
+  * ALSA: hda - Add PCI IDs for Nvidia G2xx-series
+  * V4L/DVB (13569): smsusb: add autodetection support for five additional
+    Hauppauge USB IDs
+  * USB: mos7840: add device IDs for B&B electronics devices
+  * USB: ftdi_sio: add USB device ID's for B&B Electronics line
+  * V4L/DVB (13168): Add support for Asus Europa Hybrid DVB-T card (SAA7134
+    SubVendor ID: 0x1043 Device ID: 0x4847)
+  * iTCO_wdt: Add support for Intel Ibex Peak
+  * atl1c:use common_task instead of reset_task and link_chg_task
+  * atl1e:disable NETIF_F_TSO6 for hardware limit
+  * V4L/DVB (13680a): DocBook/media: copy images after building HTML
+  * V4L/DVB (13680b): DocBook/media: create links for included sources
+  * netfilter: xtables: fix conntrack match v1 ipt-save output
+  * partitions: read whole sector with EFI GPT header
+  * partitions: use sector size for EFI GPT
+  * ALSA: ice1724 - Patch for suspend/resume for ESI Juli@
+  * sched: Fix isolcpus boot option
+  * sched: Fix missing sched tunable recalculation on cpu add/remove
+  * nohz: Prevent clocksource wrapping during idle
+  * nfsd: Fix sort_pacl in fs/nfsd/nf4acl.c to actually sort groups
+  * timers, init: Limit the number of per cpu calibration bootup messages
+  * PCI: Always set prefetchable base/limit upper32 registers
+  * iscsi class: modify handling of replacement timeout
+  * NFS: Revert default r/wsize behavior
+  * HID: fixup quirk for NCR devices
+  * scsi_devinfo: update Hitachi entries (v2)
+  * scsi_dh: create sysfs file, dh_state for all SCSI disk devices
+  * scsi_transport_fc: remove invalid BUG_ON
+  * lpfc: fix hang on SGI ia64 platform
+  * libfc: fix typo in retry check on received PRLI
+  * libfc: fix ddp in fc_fcp for 0 xid
+  * fcoe: remove redundant checking of netdev->netdev_ops
+  * libfc: Fix wrong scsi return status under FC_DATA_UNDRUN
+  * libfc: lport: fix minor documentation errors
+  * libfc: don't WARN_ON in lport_timeout for RESET state
+  * fcoe: initialize return value in fcoe_destroy
+  * libfc: Fix frags in frame exceeding SKB_MAX_FRAGS in fc_fcp_send_data
+  * libfc: fix memory corruption caused by double frees and bad error
+    handling
+  * libfc: fix free of fc_rport_priv with timer pending
+  * libfc: remote port gets stuck in restart state without really
+    restarting
+  * fcoe, libfc: fix an libfc issue with queue ramp down in libfc
+  * fcoe: Fix checking san mac address
+  * fcoe: Fix getting san mac for VLAN interface
+  * qlge: Remove explicit setting of PCI Dev CTL reg.
+  * qlge: Set PCIE max read request size.
+  * qlge: Don't fail open when port is not initialized.
+  * qlge: Add handler for DCBX firmware event.
+  * qlge: Bonding fix for mode 6.
+  * PCI: AER: fix aer inject result in kernel oops
+  * DMI: allow omitting ident strings in DMI tables
+  * Input: i8042 - remove identification strings from DMI tables
+  * Input: i8042 - add Gigabyte M1022M to the noloop list
+  * Input: i8042 - add Dritek quirk for Acer Aspire 5610.
+  * ALSA: hda - select IbexPeak handler for Calpella
+  * ALSA: hda - Fix quirk for Maxdata obook4-1
+  * ALSA: hda - Add missing Line-Out and PCM switches as slave
+  * iTCO_wdt.c - cleanup chipset documentation
+  * iTCO_wdt: add PCI ID for the Intel EP80579 (Tolapai) SoC
+  * iTCO_wdt: Add Intel Cougar Point and PCH DeviceIDs
+  * ahci: disable SNotification capability for ich8
+  * ata_piix: fix MWDMA handling on PIIX3
+  * md: fix small irregularity with start_ro module parameter
+  * V4L/DVB (13826): uvcvideo: Fix controls blacklisting
+  * cio: fix double free in case of probe failure
+  * cio: dont panic in non-fatal conditions
+  * netiucv: displayed TX bytes value much too high
+  * ipc ns: fix memory leak (idr)
+  * ALSA: hda - Fix HP T5735 automute
+  * hwmon: (fschmd) Fix a memleak on multiple opens of /dev/watchdog
+  * UBI: fix memory leak in update path
+  * UBI: initialise update marker
+  * ASoC: fix a memory-leak in wm8903
+  * mac80211: check that ieee80211_set_power_mgmt only handles STA
+    interfaces.
+  * cfg80211: fix channel setting for wext
+  * KVM: S390: fix potential array overrun in intercept handling
+  * KVM: only allow one gsi per fd
+  * KVM: Fix race between APIC TMR and IRR
+  * KVM: MMU: bail out pagewalk on kvm_read_guest error
+  * KVM: x86: Fix host_mapping_level()
+  * KVM: x86: Fix probable memory leak of vcpu->arch.mce_banks
+  * KVM: x86: Fix leak of free lapic date in kvm_arch_vcpu_init()
+  * KVM: fix lock imbalance in kvm_*_irq_source_id()
+  * KVM: only clear irq_source_id if irqchip is present
+  * IPoIB: Clear ipoib_neigh.dgid in ipoib_neigh_alloc()
+  * x86: Reenable TSC sync check at boot, even with NONSTOP_TSC
+  * ACPI: enable C2 and Turbo-mode on Nehalem notebooks on A/C
+    - LP: #516325
+  * iwlwifi: Fix throughput stall issue in HT mode for 5000
+  * fnctl: f_modown should call write_lock_irqsave/restore
+  * x86, msr/cpuid: Pass the number of minors when unregistering MSR and
+    CPUID drivers.
+  * Linux 2.6.32.7
+  * scsi_lib: Fix bug in completion of bidi commands
+  * mptsas: Fix issue with chain pools allocation on katmai
+  * mm: add new 'read_cache_page_gfp()' helper function
+  * drm/i915: Selectively enable self-reclaim
+  * firewire: ohci: fix crashes with TSB43AB23 on 64bit systems
+  * S390: fix single stepped svcs with TRACE_IRQFLAGS=y
+  * x86: Set hotpluggable nodes in nodes_possible_map
+  * x86: Remove "x86 CPU features in debugfs" (CONFIG_X86_CPU_DEBUG)
+  * libata: retry FS IOs even if it has failed with AC_ERR_INVALID
+  * zcrypt: Do not remove coprocessor for error 8/72
+  * dasd: fix possible NULL pointer errors
+  * ACPI: Add a generic API for _OSC -v2
+  * ACPI: Add platform-wide _OSC support.
+  * ACPI: fix OSC regression that caused aer and pciehp not to load
+  * ACPI: Advertise to BIOS in _OSC: _OST on _PPC changes
+  * UBI: fix volume creation input checking
+  * e1000/e1000e: don't use small hardware rx buffers
+  * drm/i915: Reload hangcheck timer too for Ironlake
+  * Fix a leak in affs_fill_super()
+  * Fix failure exits in bfs_fill_super()
+  * fix oops in fs/9p late mount failure
+  * fix leak in romfs_fill_super()
+  * Fix remount races with symlink handling in affs
+  * fix affs parse_options()
+  * Fix failure exit in ipathfs
+  * mm: fix migratetype bug which slowed swapping
+  * FDPIC: Respect PT_GNU_STACK exec protection markings when creating
+    NOMMU stack
+  * Split 'flush_old_exec' into two functions
+  * sparc: TIF_ABI_PENDING bit removal
+  * x86: get rid of the insane TIF_ABI_PENDING bit
+  * Input: winbond-cir - remove dmesg spam
+  * x86: Disable HPET MSI on ATI SB700/SB800
+  * iwlwifi: set default aggregation frame count limit to 31
+  * drm/i915: only enable hotplug for detected outputs
+  * firewire: core: add_descriptor size check
+  * SECURITY: selinux, fix update_rlimit_cpu parameter
+  * regulator: Specify REGULATOR_CHANGE_STATUS for WM835x LED constraints
+  * x86: Add Dell OptiPlex 760 reboot quirk
+    - LP: #488319
+  * x86: Add quirk for Intel DG45FC board to avoid low memory corruption
+  * x86/amd-iommu: Fix possible integer overflow
+  * clocksource: fix compilation if no GENERIC_TIME
+  * tcp: update the netstamp_needed counter when cloning sockets
+  * sky2: Fix oops in sky2_xmit_frame() after TX timeout
+  * net: restore ip source validation
+  * af_packet: Don't use skb after dev_queue_xmit()
+  * ax25: netrom: rose: Fix timer oopses
+  * KVM: allow userspace to adjust kvmclock offset
+  * oprofile/x86: add Xeon 7500 series support
+  * oprofile/x86: fix crash when profiling more than 28 events
+  * libata: retry link resume if necessary
+  * mm: percpu-vmap fix RCU list walking
+  * mm: purge fragmented percpu vmap blocks
+  * block: fix bio_add_page for non trivial merge_bvec_fn case
+  * Fix 'flush_old_exec()/setup_new_exec()' split
+  * random: drop weird m_time/a_time manipulation
+  * random: Remove unused inode variable
+  * block: fix bugs in bio-integrity mempool usage
+  * usb: r8a66597-hdc disable interrupts fix
+  * connector: Delete buggy notification code.
+  * be2net: Bug fix to support newer generation of BE ASIC
+  * be2net: Fix memset() arg ordering.
+  * mm: flush dcache before writing into page to avoid alias
+  * mac80211: fix NULL pointer dereference when ftrace is enabled
+  * imxfb: correct location of callbacks in suspend and resume
+  * mx3fb: some debug and initialisation fixes
+  * starfire: clean up properly if firmware loading fails
+  * kernel/cred.c: use kmem_cache_free
+  * uartlite: fix crash when using as console
+  * pktcdvd: removing device does not remove its sysfs dir
+  * ath9k: fix eeprom INI values override for 2GHz-only cards
+  * ath9k: fix beacon slot/buffer leak
+  * powerpc: TIF_ABI_PENDING bit removal
+  * NET: fix oops at bootime in sysctl code
+  * Linux 2.6.32.8
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 10 Feb 2010 18:56:52 +0000
+
+linux (2.6.32-12.17) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * restore linux-image prefix -- master
+  * enforce -- we require SELINUX enabled -- master
+  * enforce -- ensure APPARMOR is our default LSM -- master
+  * make doc package completely optional -- master
+  * make source package completely optional -- master
+  * make linux-libc-dev completly optional -- master
+  * convert package disable to a deps list -- master
+  * allow common headers to switch from indep to arch -- master
+  * convert binary package disable to a deps list -- master
+  * add configuration option for a full source build tree -- master
+  * add support for uImage kernels in package control scripts
+  * getabis -- cleanup and parameterise repository list -- master
+  * getabis -- move configuration to etc/getabi -- master
+  * kernelconfig -- move configuration to etc -- master
+  * rules -- make debian/debian.env master for branch name
+  * set the current branch name -- master
+  * pull back common debian.master files into debian -- master
+  * enforcer -- make the enforcement configuration common
+  * insert-changes -- correctly link to debian/rules in DROOT
+
+  [ Colin Watson ]
+
+  * future-proof ddeb handling against buildd changes
+
+  [ Eric Miao ]
+
+  * SAUCE: Make CONFIG_{OMNIBOOK, AVERATEC_5100P, PACKARDBELL_E5} depend on
+    X86
+
+  [ Loïc Minier ]
+
+  * Add modules.builtin.bin to prerm rm list
+    - LP: #516584
+
+  [ Tim Gardner ]
+
+  * [Config] Implement the amd64 preempt flavour
+
+  [ Upstream Kernel Changes ]
+
+  * syslog: distinguish between /proc/kmsg and syscalls
+    - LP: #515623
+  * sfc: Fix polling for slow MCDI operations
+  * sfc: Fix conditions for MDIO self-test
+  * sfc: QT202x: Remove unreliable MMD check at initialisation
+  * sfc: Add workspace for GMAC bug workaround to MCDI MAC_STATS buffer
+  * sfc: Use fixed-size buffers for MCDI NVRAM requests
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Feb 2010 07:09:31 +0000
+
+linux (2.6.32-12.16) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: acpi battery -- delay first lookup of the battery until
+    first use"
+  * SAUCE: acpi battery -- move first lookup asynchronous
+    - LP: #507211
+  * [Config] update configs to cleanup generic configs
+  * [Config] disable CONFIG_X86_CPU_DEBUG for amd64
+  * [Config] enable USER_NS
+    - LP: #480739, #509808
+
+  [ Heiko Carstens ]
+
+  * (pre-stable) driver-core: fix devtmpfs crash on s390
+    - LP: #512370
+
+  [ John Johansen ]
+
+  * [Config] for server and virtual flavours make CONFIG_SCSI_SYM53C8XX_2=y
+    - LP: #494565
+  * [Config] VIRTIO=y for server/virtual flavours
+    - LP: #494565
+
+  [ Kay Sievers ]
+
+  * (pre-stable) Driver-Core: devtmpfs - set root directory mode to 0755
+    - LP: #512370
+
+  [ Kees Cook ]
+
+  * SAUCE: x86: brk away from exec rand area
+    - LP: #452175
+
+  [ Leann Ogasawara ]
+
+  * [Upstream] e1000: enhance frame fragment detection
+    - CVE-2009-4536
+  * [Upstream] e1000e: enhance frame fragment detection
+    - CVE-2009-4538
+
+  [ Sebastian Kapfer ]
+
+  * (pre-stable) Input: ALPS - add interleaved protocol support (Dell E6x00
+    series)
+    - LP: #296610
+
+  [ Upstream Kernel Changes ]
+
+  * inotify: do not reuse watch descriptors
+    - LP: #485556
+  * inotify: only warn once for inotify problems
+  * revert "drivers/video/s3c-fb.c: fix clock setting for Samsung SoC
+    Framebuffer"
+  * memcg: ensure list is empty at rmdir
+  * drm/i915: remove loop in Ironlake interrupt handler
+  * block: Fix incorrect reporting of partition alignment
+  * x86, mce: Thermal monitoring depends on APIC being enabled
+  * futexes: Remove rw parameter from get_futex_key()
+  * page allocator: update NR_FREE_PAGES only when necessary
+  * x86, apic: use physical mode for IBM summit platforms
+  * edac: i5000_edac critical fix panic out of bounds
+  * x86: SGI UV: Fix mapping of MMIO registers
+  * mfd: WM835x GPIO direction register is not locked
+  * mfd: Correct WM835x ISINK ramp time defines
+  * ALSA: hda - Fix missing capture mixer for ALC861/660 codecs
+  * V4L/DVB (13868): gspca - sn9c20x: Fix test of unsigned.
+  * reiserfs: truncate blocks not used by a write
+  * HID: add device IDs for new model of Apple Wireless Keyboard
+  * PCI/cardbus: Add a fixup hook and fix powerpc
+  * Input: pmouse - move Sentelic probe down the list
+  * asus-laptop: add Lenovo SL hotkey support
+  * sched: Fix cpu_clock() in NMIs, on !CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
+  * sparc64: Fix NMI programming when perf events are active.
+  * sparc64: Fix Niagara2 perf event handling.
+  * i2c: Do not use device name after device_unregister
+  * i2c/pca: Don't use *_interruptible
+  * serial/8250_pnp: add a new Fujitsu Wacom Tablet PC device
+  * sched: Fix task priority bug
+  * vfs: Fix vmtruncate() regression
+  * Linux 2.6.32.5
+  * x86, msr/cpuid: Register enough minors for the MSR and CPUID drivers
+  * V4L/DVB (13900): gspca - sunplus: Fix bridge exchanges.
+  * Staging: asus_oled: fix oops in 2.6.32.2
+  * Staging: hv: fix smp problems in the hyperv core code
+  * tty: fix race in tty_fasync
+  * ecryptfs: use after free
+  * ecryptfs: initialize private persistent file before dereferencing
+    pointer
+  * nozomi: quick fix for the close/close bug
+  * serial: 8250_pnp: use wildcard for serial Wacom tablets
+  * usb: serial: fix memory leak in generic driver
+  * USB: fix bitmask merge error
+  * USB: Don't use GFP_KERNEL while we cannot reset a storage device
+  * USB: EHCI: fix handling of unusual interrupt intervals
+  * USB: EHCI & UHCI: fix race between root-hub suspend and port resume
+  * USB: add missing delay during remote wakeup
+  * USB: add speed values for USB 3.0 and wireless controllers
+  * ACPI: EC: Accelerate query execution
+  * ACPI: EC: Add wait for irq storm
+  * SCSI: enclosure: fix oops while iterating enclosure_status array
+  * drm/i915: Read the response after issuing DDC bus switch command
+  * drm/i915: try another possible DDC bus for the SDVO device with
+    multiple outputs
+  * block: bdev_stack_limits wrapper
+  * DM: Fix device mapper topology stacking
+  * x86/PCI/PAT: return EINVAL for pci mmap WC request for !pat_enabled
+  * USB: fix usbstorage for 2770:915d delivers no FAT
+  * vmalloc: remove BUG_ON due to racy counting of VM_LAZY_FREE
+  * perf timechart: Use tid not pid for COMM change
+  * perf events: Dont report side-band events on each cpu for
+    per-task-per-cpu events
+  * perf: Honour event state for aux stream data
+  * Linux 2.6.32.6
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 27 Jan 2010 16:40:23 +0000
+
+linux (2.6.32-11.15) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "(pre-stable) drm/radeon/kms: fix crtc vblank update for r600"
+  * Revert "(pre-stable) sched: Fix balance vs hotplug race"
+  * Revert "[Upstream] acerhdf: Limit modalias matching to supported
+    boards"
+  * Revert "[Upstream] mmc: prevent dangling block device from accessing
+    stale queues"
+  * Revert "SAUCE: Fix nx_enable reporting"
+  * Revert "SAUCE: [x86] fix report of cs-limit nx-emulation"
+  * Revert "SAUCE: [x86] implement cs-limit nx-emulation for ia32"
+  * SAUCE: i915 -- disable powersave by default
+    - LP: #492392
+
+  [ Kees Cook ]
+
+  * SAUCE: [x86] implement cs-limit nx-emulation for ia32
+    - LP: #369978
+  * SAUCE: [x86] fix report of cs-limit nx-emulation
+    - LP: #454285
+  * SAUCE: Fix nx_enable reporting
+    - LP: #454285
+
+  [ Tim Gardner ]
+
+  * [Upstream] b43: Declare all possible firmware files.
+    - LP: #488636
+  * [Config] updateconfigs after adding pvscsi
+    - LP: #497156
+  * [Config] CONFIG_BT=m
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "x86: Side-step lguest problem by only building cmpxchg8b_emu
+    for pre-Pentium"
+  * SCSI: ipr: fix EEH recovery
+  * SCSI: qla2xxx: dpc thread can execute before scsi host has been added
+  * SCSI: st: fix mdata->page_order handling
+  * SCSI: fc class: fix fc_transport_init error handling
+  * sched: Fix task_hot() test order
+  * x86, cpuid: Add "volatile" to asm in native_cpuid()
+  * sched: Select_task_rq_fair() must honour SD_LOAD_BALANCE
+  * clockevents: Prevent clockevent_devices list corruption on cpu hotplug
+  * pata_hpt3x2n: fix clock turnaround
+  * pata_cmd64x: fix overclocking of UDMA0-2 modes
+  * ASoC: wm8974: fix a wrong bit definition
+  * sound: sgio2audio/pdaudiocf/usb-audio: initialize PCM buffer
+  * ALSA: hda - Fix missing capsrc_nids for ALC88x
+  * acerhdf: limit modalias matching to supported
+    - LP: #435958
+  * ACPI: EC: Fix MSI DMI detection
+  * ACPI: Use the return result of ACPI lid notifier chain correctly
+  * powerpc: Handle VSX alignment faults correctly in little-endian mode
+  * ASoC: Do not write to invalid registers on the wm9712.
+  * drm/radeon: fix build on 64-bit with some compilers.
+  * USB: emi62: fix crash when trying to load EMI 6|2 firmware
+  * USB: option: support hi speed for modem Haier CE100
+  * USB: Fix a bug on appledisplay.c regarding signedness
+  * USB: musb: gadget_ep0: avoid SetupEnd interrupt
+  * Bluetooth: Prevent ill-timed autosuspend in USB driver
+  * USB: rename usb_configure_device
+  * USB: fix bugs in usb_(de)authorize_device
+  * drivers/net/usb: Correct code taking the size of a pointer
+  * x86: SGI UV: Fix writes to led registers on remote uv hubs
+  * md: Fix unfortunate interaction with evms
+  * dma: at_hdmac: correct incompatible type for argument 1 of
+    'spin_lock_bh'
+  * dma-debug: Do not add notifier when dma debugging is disabled.
+  * dma-debug: Fix bug causing build warning
+  * cifs: NULL out tcon, pSesInfo, and srvTcp pointers when chasing DFS
+    referrals
+  * x86/amd-iommu: Fix initialization failure panic
+  * ioat3: fix p-disabled q-continuation
+  * ioat2,3: put channel hardware in known state at init
+  * KVM: MMU: remove prefault from invlpg handler
+  * KVM: LAPIC: make sure IRR bitmap is scanned after vm load
+  * Libertas: fix buffer overflow in lbs_get_essid()
+  * iwmc3200wifi: fix array out-of-boundary access
+  * mac80211: fix propagation of failed hardware reconfigurations
+  * mac80211: fix WMM AP settings application
+  * mac80211: Fix IBSS merge
+  * cfg80211: fix race between deauth and assoc response
+  * ath5k: fix SWI calibration interrupt storm
+  * ath9k: wake hardware for interface IBSS/AP/Mesh removal
+  * ath9k: Fix TX queue draining
+  * ath9k: fix missed error codes in the tx status check
+  * ath9k: wake hardware during AMPDU TX actions
+  * ath9k: fix suspend by waking device prior to stop
+  * ath9k_hw: Fix possible OOB array indexing in gen_timer_index[] on
+    64-bit
+  * ath9k_hw: Fix AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB and its shift value
+    in 0x4054
+  * iwl3945: disable power save
+  * iwl3945: fix panic in iwl3945 driver
+  * iwlwifi: fix EEPROM/OTP reading endian annotations and a bug
+  * iwlwifi: fix more eeprom endian bugs
+  * iwlwifi: fix 40MHz operation setting on cards that do not allow it
+  * mac80211: fix race with suspend and dynamic_ps_disable_work
+  * NOMMU: Optimise away the {dac_,}mmap_min_addr tests
+  * 'sysctl_max_map_count' should be non-negative
+  * kernel/sysctl.c: fix the incomplete part of
+    sysctl_max_map_count-should-be-non-negative.patch
+  * V4L/DVB (13596): ov511.c typo: lock => unlock
+  * x86/ptrace: make genregs[32]_get/set more robust
+  * memcg: avoid oom-killing innocent task in case of use_hierarchy
+  * e100: Fix broken cbs accounting due to missing memset.
+  * ipv6: reassembly: use seperate reassembly queues for conntrack and
+    local delivery
+  * netfilter: fix crashes in bridge netfilter caused by fragment jumps
+  * hwmon: (sht15) Off-by-one error in array index + incorrect constants
+  * b43: avoid PPC fault during resume
+  * Keys: KEYCTL_SESSION_TO_PARENT needs TIF_NOTIFY_RESUME architecture
+    support
+  * sched: Fix balance vs hotplug race
+  * drm/radeon/kms: fix crtc vblank update for r600
+  * drm: disable all the possible outputs/crtcs before entering KMS mode
+  * S390: dasd: support DIAG access for read-only devices
+  * xen: fix is_disconnected_device/exists_disconnected_device
+  * xen: improvement to wait_for_devices()
+  * xen: wait up to 5 minutes for device connetion
+  * orinoco: fix GFP_KERNEL in orinoco_set_key with interrupts disabled
+  * udf: Try harder when looking for VAT inode
+  * Add unlocked version of inode_add_bytes() function
+  * quota: decouple fs reserved space from quota reservation
+  * ext4: Convert to generic reserved quota's space management.
+  * ext4: fix sleep inside spinlock issue with quota and dealloc (#14739)
+  * x86, msr: Unify rdmsr_on_cpus/wrmsr_on_cpus
+  * cpumask: use modern cpumask style in drivers/edac/amd64_edac.c
+  * amd64_edac: unify MCGCTL ECC switching
+  * x86, msr: Add support for non-contiguous cpumasks
+  * x86, msr: msrs_alloc/free for CONFIG_SMP=n
+  * amd64_edac: fix driver instance freeing
+  * amd64_edac: make driver loading more robust
+  * amd64_edac: fix forcing module load/unload
+  * sched: Sched_rt_periodic_timer vs cpu hotplug
+  * ext4: Update documentation to correct the inode_readahead_blks option
+    name
+  * lguest: fix bug in setting guest GDT entry
+  * vmscan: do not evict inactive pages when skipping an active list scan
+  * ksm: fix mlockfreed to munlocked
+  * rt2x00: Disable powersaving for rt61pci and rt2800pci.
+  * generic_permission: MAY_OPEN is not write access
+  * Linux 2.6.32.3
+  * untangle the do_mremap() mess
+  * fasync: split 'fasync_helper()' into separate add/remove functions
+  * ASoC: fix params_rate() macro use in several codecs
+  * modules: Skip empty sections when exporting section notes
+  * exofs: simple_write_end does not mark_inode_dirty
+  * nfsd: make sure data is on disk before calling ->fsync
+  * sunrpc: fix peername failed on closed listener
+  * SUNRPC: Fix up an error return value in
+    gss_import_sec_context_kerberos()
+  * SUNRPC: Fix the return value in gss_import_sec_context()
+  * sunrpc: on successful gss error pipe write, don't return error
+  * drm/i915: Update LVDS connector status when receiving ACPI LID event
+  * drm/i915: fix order of fence release wrt flushing
+  * drm/i915: Permit pinning whilst the device is 'suspended'
+  * drm: remove address mask param for drm_pci_alloc()
+  * drm/i915: Enable/disable the dithering for LVDS based on VBT setting
+  * drm/i915: Make the BPC in FDI rx/transcoder be consistent with that in
+    pipeconf on Ironlake
+  * drm/i915: Select the correct BPC for LVDS on Ironlake
+  * drm/i915: fix unused var
+  * rtc_cmos: convert shutdown to new pnp_driver->shutdown
+  * drivers/cpuidle/governors/menu.c: fix undefined reference to
+    `__udivdi3'
+  * cgroups: fix 2.6.32 regression causing BUG_ON() in cgroup_diput()
+  * lib/rational.c needs module.h
+  * dma-debug: allow DMA_BIDIRECTIONAL mappings to be synced with
+    DMA_FROM_DEVICE and
+  * kernel/signal.c: fix kernel information leak with print-fatal-signals=1
+  * mmc_block: add dev_t initialization check
+  * mmc_block: fix probe error cleanup bug
+  * mmc_block: fix queue cleanup
+  * ALSA: hda - Fix ALC861-VD capture source mixer
+  * ALSA: ac97: Add Dell Dimension 2400 to Headphone/Line Jack Sense
+    blacklist
+  * ALSA: atiixp: Specify codec for Foxconn RC4107MA-RS2
+    - LP: #498863
+  * ASoC: Fix WM8350 DSP mode B configuration
+  * netfilter: ebtables: enforce CAP_NET_ADMIN
+  * netfilter: nf_ct_ftp: fix out of bounds read in update_nl_seq()
+  * hwmon: (coretemp) Fix TjMax for Atom N450/D410/D510 CPUs
+  * hwmon: (adt7462) Fix pin 28 monitoring
+  * quota: Fix dquot_transfer for filesystems different from ext4
+  * xen: fix hang on suspend.
+  * iwlwifi: fix iwl_queue_used bug when read_ptr == write_ptr
+  * ath5k: Fix eeprom checksum check for custom sized eeproms
+  * cfg80211: fix syntax error on user regulatory hints
+  * iwl: off by one bug
+  * mac80211: add missing sanity checks for action frames
+  * drm/i915: remove render reclock support
+  * libertas: Remove carrier signaling from the scan code
+  * kernel/sysctl.c: fix stable merge error in NOMMU mmap_min_addr
+  * mac80211: fix skb buffering issue (and fixes to that)
+  * fix braindamage in audit_tree.c untag_chunk()
+  * fix more leaks in audit_tree.c tag_chunk()
+  * module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y
+  * ipv6: skb_dst() can be NULL in ipv6_hop_jumbo().
+  * agp/intel-agp: Clear entire GTT on startup
+  * Linux 2.6.32.4
+  * ethtool: Add reset operation
+  * gro: Name the GRO result enumeration type
+  * gro: Change all receive functions to return GRO result codes
+  * sfc: 10Xpress: Initialise pause advertising flags
+  * sfc: 10Xpress: Report support for pause frames
+  * sfc: Remove redundant header gmii.h
+  * sfc: Remove redundant hardware initialisation
+  * sfc: Rename Falcon-specific board code and types
+  * sfc: Remove boards.h, moving last remaining declaration to falcon.h
+  * sfc: Remove versioned bitfield macros
+  * sfc: Move RX data FIFO thresholds out of struct efx_nic_type
+  * sfc: Update hardware definitions for Siena
+  * sfc: Rename register I/O header and functions used by both Falcon and
+    Siena
+  * sfc: Eliminate indirect lookups of queue size constants
+  * sfc: Define DMA address mask explicitly in terms of descriptor field
+    width
+  * sfc: Move all TX DMA length limiting into tx.c
+  * sfc: Change order of device removal to reverse of probe order
+  * sfc: Remove declarations of nonexistent functions
+  * sfc: Move efx_xmit_done() declaration into correct stanza
+  * sfc: Move shared members of struct falcon_nic_data into struct efx_nic
+  * sfc: Maintain interrupt moderation values in ticks, not microseconds
+  * sfc: Removed kernel-doc for nonexistent member of efx_phy_operations
+  * sfc: Remove pointless abstraction of memory BAR number
+  * sfc: Remove incorrect assertion from efx_pci_remove_main()
+  * sfc: Remove unnecessary tests of efx->membase
+  * sfc: Move MTD probe after netdev registration and name allocation
+  * sfc: Remove unused code for non-autoneg speed/duplex switching
+  * sfc: Rename 'xfp' file and functions to reflect reality
+  * sfc: Really allow RX checksum offload to be disabled
+  * sfc: Feed GRO result into RX allocation policy and interrupt moderation
+  * sfc: Enable heuristic selection between page and skb RX buffers
+  * sfc: Remove pointless abstraction of memory BAR number (2)
+  * sfc: Remove redundant gotos from __efx_rx_packet()
+  * sfc: Remove ridiculously paranoid assertions
+  * sfc: Move assertions and buffer cleanup earlier in efx_rx_packet_lro()
+  * sfc: Record RX queue number on GRO path
+  * sfc: SFT9001: Reset LED configuration correctly after blinking
+  * sfc: Use a single blink implementation
+  * sfc: Rename efx_board::init_leds to init_phy and use for SFN4111T
+  * sfc: Make board information explicitly Falcon-specific
+  * sfc: Move definition of struct falcon_nic_data into falcon.h
+  * sfc: Move struct falcon_board into struct falcon_nic_data
+  * sfc: Move all I2C stuff into struct falcon_board
+  * sfc: Gather link state fields in struct efx_nic into new struct
+    efx_link_state
+  * sfc: Remove unnecessary casts to struct sk_buff *
+  * sfc: Remove redundant efx_xmit() function
+  * sfc: Combine high-level header files
+  * sfc: Log interrupt and reset type names, not numbers
+  * sfc: Fix descriptor cache sizes
+  * sfc: Treat all MAC registers as 128-bit
+  * sfc: Strengthen EFX_ASSERT_RESET_SERIALISED
+  * sfc: Comment corrections
+  * sfc: Remove unused constant
+  * sfc: Clean up struct falcon_board and struct falcon_board_data
+  * sfc: Fix bugs in RX queue flushing
+  * sfc: Remove unused function efx_flush_queues()
+  * sfc: Only switch Falcon MAC clocks as necessary
+  * sfc: Hold MAC lock for longer in efx_init_port()
+  * sfc: Split MAC stats DMA initiation and completion
+  * sfc: Move Falcon board/PHY/MAC monitoring code to falcon.c
+  * sfc: Simplify XMAC link polling
+  * sfc: Change MAC promiscuity and multicast hash at the same time
+  * sfc: Move inline comment into kernel-doc
+  * sfc: Do not set net_device::trans_start in self-test
+  * sfc: Simplify PHY polling
+  * sfc: QT202x: Reset before reading PHY id
+  * sfc: Replace MDIO spinlock with mutex
+  * sfc: Always start Falcon using the XMAC
+  * sfc: Limit some hardware workarounds to Falcon
+  * sfc: Remove EFX_WORKAROUND_9141 macro
+  * sfc: Remove another unused workaround macro
+  * sfc: Remove some redundant whitespace
+  * sfc: Decouple NIC revision number from Falcon PCI revision number
+  * sfc: Move descriptor cache base addresses to struct efx_nic_type
+  * sfc: Clean up RX event handling
+  * sfc: Remove redundant writes to INT_ADR_KER
+  * sfc: Remove duplicate hardware structure definitions
+  * sfc: Turn pause frame generation on and off at the MAC, not the RX FIFO
+  * sfc: Move Falcon NIC operations to efx_nic_type
+  * sfc: Refactor link configuration
+  * sfc: Generalise link state monitoring
+  * sfc: Add power-management and wake-on-LAN support
+  * sfc: Implement ethtool reset operation
+  * sfc: Add efx_nic_type operation for register self-test
+  * sfc: Add efx_nic_type operation for NVRAM self-test
+  * sfc: Add efx_nic_type operation for identity LED control
+  * sfc: Separate shared NIC code from Falcon-specific and rename
+    accordingly
+  * sfc: Fold falcon_probe_nic_variant() into falcon_probe_nic()
+  * sfc: Extend loopback mode enumeration
+  * sfc: Remove static PHY data and enumerations
+  * sfc: Extend MTD driver for use with new NICs
+  * sfc: Allow for additional checksum offload features
+  * sfc: Rename falcon.h to nic.h
+  * sfc: Move shared NIC code from falcon.c to new source file nic.c
+  * sfc: Add firmware protocol definitions (MCDI)
+  * sfc: Add support for SFC9000 family (1)
+  * sfc: Add support for SFC9000 family (2)
+  * sfc: Implement TSO for TCP/IPv6
+  * sfc: Update version, copyright dates, authors
+  * drivers/net/sfc: Correct code taking the size of a pointer
+  * sfc: Move PHY software state initialisation from init() into probe()
+  * sfc: Include XGXS in XMAC link status check except in XGMII loopback
+  * sfc: Fix DMA mapping cleanup in case of an error in TSO
+  * sfc: QT2025C: Work around PHY bug
+  * sfc: QT2025C: Switch into self-configure mode when not in loopback
+  * sfc: QT2025C: Work around PHY firmware initialisation bug
+  * sfc: QT2025C: Add error message for suspected bad SFP+ cables
+  * sfc: Disable TX descriptor prefetch watchdog
+  * [SCSI] vmw_pvscsi: SCSI driver for VMware's virtual HBA.
+    - LP: #497156
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 19 Jan 2010 16:12:47 +0000
+
+linux (2.6.32-10.14) lucid; urgency=low
+
+  [ Alex Deucher ]
+
+  * SAUCE: drm/radeon/kms: fix LVDS setup on r4xx
+    - LP: #493795
+
+  [ Andy Whitcroft ]
+
+  * Revert "(pre-stable) acpi: Use the ARB_DISABLE for the CPU which model
+    id is less than 0x0f."
+  * config-check -- ensure the checks get run at build time
+  * config-check -- check the processed config during updateconfigs
+  * config-check -- CONFIG_SECCOMP may not be present
+  * TUN is now built in ignore
+  * SAUCE: acpi battery -- delay first lookup of the battery until first
+    use
+  * SAUCE: async_populate_rootfs: move rootfs init earlier
+  * ubuntu: AppArmor -- update to mainline 2010-01-06
+  * SAUCE: move RLIMIT_CORE pipe dumper marker to 1
+    - LP: #498525
+
+  [ Dave Airlie ]
+
+  * (pre-stable) drm/radeon/kms: fix crtc vblank update for r600
+
+  [ Leann Ogasawara ]
+
+  * Add asix to nic-usb-modules file
+    - LP: #499785
+
+  [ Peter Zijlstra ]
+
+  * (pre-stable) sched: Fix balance vs hotplug race
+
+  [ Tim Gardner ]
+
+  * [Config] Enable CONFIG_FUNCTION_TRACER
+    - LP: #497989
+  * [Config] Drop lpia from getabis
+  * [Config] Build in TUN/TAP driver
+    - LP: #499491
+  * [Config] DH_COMPAT=5
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "(pre-stable) drm/i915: Avoid NULL dereference with
+    component_only tv_modes"
+  * Revert "(pre-stable) drm/i915: Fix sync to vblank when VGA output is
+    turned off"
+  * USB: usb-storage: fix bug in fill_inquiry
+  * USB: option: add pid for ZTE
+  * firewire: ohci: handle receive packets with a data length of zero
+  * rcu: Prepare for synchronization fixes: clean up for non-NO_HZ handling
+    of ->completed counter
+  * rcu: Fix synchronization for rcu_process_gp_end() uses of ->completed
+    counter
+  * rcu: Fix note_new_gpnum() uses of ->gpnum
+  * rcu: Remove inline from forward-referenced functions
+  * perf_event: Fix invalid type in ioctl definition
+  * perf_event: Initialize data.period in perf_swevent_hrtimer()
+  * perf: Don't free perf_mmap_data until work has been done
+  * PM / Runtime: Fix lockdep warning in __pm_runtime_set_status()
+  * sched: Check for an idle shared cache in select_task_rq_fair()
+  * sched: Fix affinity logic in select_task_rq_fair()
+  * sched: Rate-limit newidle
+  * sched: Fix and clean up rate-limit newidle code
+  * x86/amd-iommu: attach devices to pre-allocated domains early
+  * x86/amd-iommu: un__init iommu_setup_msi
+  * x86, Calgary IOMMU quirk: Find nearest matching Calgary while walking
+    up the PCI tree
+  * x86: Fix iommu=nodac parameter handling
+  * x86: GART: pci-gart_64.c: Use correct length in strncmp
+  * x86: ASUS P4S800 reboot=bios quirk
+    - LP: #366682
+  * x86, apic: Enable lapic nmi watchdog on AMD Family 11h
+  * ssb: Fix range check in sprom write
+  * ath5k: allow setting txpower to 0
+  * ath5k: enable EEPROM checksum check
+  * hrtimer: Fix /proc/timer_list regression
+  * ALSA: hrtimer - Fix lock-up
+  * ALSA: hda - Terradici HDA controllers does not support 64-bit mode
+  * KVM: x86 emulator: limit instructions to 15 bytes
+  * KVM: s390: Fix prefix register checking in arch/s390/kvm/sigp.c
+  * KVM: s390: Make psw available on all exits, not just a subset
+  * KVM: fix irq_source_id size verification
+  * KVM: x86: include pvclock MSRs in msrs_to_save
+  * x86: Prevent GCC 4.4.x (pentium-mmx et al) function prologue wreckage
+  * x86: Use -maccumulate-outgoing-args for sane mcount prologues
+  * x86, mce: don't restart timer if disabled
+  * x86/mce: Set up timer unconditionally
+  * x86: SGI UV: Fix BAU initialization
+  * x86: Fix duplicated UV BAU interrupt vector
+  * x86: Add new Intel CPU cache size descriptors
+  * x86: Fix typo in Intel CPU cache size descriptor
+  * pata_hpt{37x|3x2n}: fix timing register masks (take 2)
+  * s390: clear high-order bits of registers after sam64
+  * V4L/DVB: Fix test in copy_reg_bits()
+  * bsdacct: fix uid/gid misreporting
+  * UBI: flush wl before clearing update marker
+  * jbd2: don't wipe the journal on a failed journal checksum
+  * USB: xhci: Add correct email and files to MAINTAINERS entry.
+  * USB: musb_gadget_ep0: fix unhandled endpoint 0 IRQs, again
+  * USB: option.c: add support for D-Link DWM-162-U5
+  * USB: usbtmc: repeat usb_bulk_msg until whole message is transfered
+  * USB: usb-storage: add BAD_SENSE flag
+  * USB: Close usb_find_interface race v3
+  * pxa/em-x270: fix usb hub power up/reset sequence
+  * hfs: fix a potential buffer overflow
+  * SUNRPC: IS_ERR/PTR_ERR confusion
+  * NFS: Fix nfs_migrate_page()
+  * md/bitmap: protect against bitmap removal while being updated.
+  * futex: Take mmap_sem for get_user_pages in fault_in_user_writeable
+  * devpts_get_tty() should validate inode
+  * debugfs: fix create mutex racy fops and private data
+  * Driver core: fix race in dev_driver_string
+  * Serial: Do not read IIR in serial8250_start_tx when UART_BUG_TXEN
+  * mac80211: Fix bug in computing crc over dynamic IEs in beacon
+  * mac80211: Fixed bug in mesh portal paths
+  * mac80211: Revert 'Use correct sign for mesh active path refresh'
+  * mac80211: fix scan abort sanity checks
+  * wireless: correctly report signal value for IEEE80211_HW_SIGNAL_UNSPEC
+  * rtl8187: Fix wrong rfkill switch mask for some models
+  * x86: Fix bogus warning in apic_noop.apic_write()
+  * mm: hugetlb: fix hugepage memory leak in mincore()
+  * mm: hugetlb: fix hugepage memory leak in walk_page_range()
+  * powerpc/windfarm: Add detection for second cpu pump
+  * powerpc/therm_adt746x: Record pwm invert bit at module load time]
+  * powerpc: Fix usage of 64-bit instruction in 32-bit altivec code
+  * drm/radeon/kms: Add quirk for HIS X1300 board
+  * drm/radeon/kms: handle vblanks properly with dpms on
+  * drm/radeon/kms: fix legacy crtc2 dpms
+  * drm/radeon/kms: fix vram setup on rs600
+  * drm/radeon/kms: rs6xx/rs740: clamp vram to aperture size
+  * drm/ttm: Fix build failure due to missing struct page
+  * drm/i915: Set the error code after failing to insert new offset into mm
+    ht.
+  * drm/i915: Add the missing clonemask for display port on Ironlake
+  * xen/xenbus: make DEVICE_ATTR()s static
+  * xen: re-register runstate area earlier on resume.
+  * xen: restore runstate_info even if !have_vcpu_info_placement
+  * xen: correctly restore pfn_to_mfn_list_list after resume
+  * xen: register timer interrupt with IRQF_TIMER
+  * xen: register runstate on secondary CPUs
+  * xen: don't call dpm_resume_noirq() with interrupts disabled.
+  * xen: register runstate info for boot CPU early
+  * xen: call clock resume notifier on all CPUs
+  * xen: improve error handling in do_suspend.
+  * xen: don't leak IRQs over suspend/resume.
+  * xen: use iret for return from 64b kernel to 32b usermode
+  * xen: explicitly create/destroy stop_machine workqueues outside
+    suspend/resume region.
+  * Xen balloon: fix totalram_pages counting.
+  * xen: try harder to balloon up under memory pressure.
+  * dm exception store: free tmp_store on persistent flag error
+  * dm snapshot: only take lock for statustype info not table
+  * dm crypt: move private iv fields to structs
+  * dm crypt: restructure essiv error path
+  * dm: avoid _hash_lock deadlock
+  * dm snapshot: cope with chunk size larger than origin
+  * dm crypt: separate essiv allocation from initialisation
+  * dm crypt: make wipe message also wipe essiv key
+  * slc90e66: fix UDMA handling
+  * tcp: Stalling connections: Fix timeout calculation routine
+  * ip_fragment: also adjust skb->truesize for packets not owned by a
+    socket
+  * b44 WOL setup: one-bit-off stack corruption kernel panic fix
+  * sparc64: Don't specify IRQF_SHARED for LDC interrupts.
+  * sparc64: Fix overly strict range type matching for PCI devices.
+  * sparc64: Fix stack debugging IRQ stack regression.
+  * sparc: Set UTS_MACHINE correctly.
+  * b43legacy: avoid PPC fault during resume
+  * tracing: Fix event format export
+  * ath9k: Fix TX hang poll routine
+  * ath9k: fix processing of TX PS null data frames
+  * ath9k: Fix maximum tx fifo settings for single stream devices
+  * ath9k: fix tx status reporting
+  * mac80211: Fix dynamic power save for scanning.
+  * drm/i915: Fix sync to vblank when VGA output is turned off
+  * memcg: fix memory.memsw.usage_in_bytes for root cgroup
+  * thinkpad-acpi: fix default brightness_mode for R50e/R51
+  * thinkpad-acpi: preserve rfkill state across suspend/resume
+  * ipw2100: fix rebooting hang with driver loaded
+  * matroxfb: fix problems with display stability
+  * acerhdf: add new BIOS versions
+  * asus-laptop: change light sens default values.
+  * vmalloc: conditionalize build of pcpu_get_vm_areas()
+  * ACPI: Use the ARB_DISABLE for the CPU which model id is less than 0x0f.
+  * net: Fix userspace RTM_NEWLINK notifications.
+  * ext3: Fix data / filesystem corruption when write fails to copy data
+  * V4L/DVB (13116): gspca - ov519: Webcam 041e:4067 added.
+  * bcm63xx_enet: fix compilation failure after get_stats_count removal
+  * x86: Under BIOS control, restore AP's APIC_LVTTHMR to the BSP value
+  * drm/i915: Avoid NULL dereference with component_only tv_modes
+  * drm/i915: PineView only has LVDS and CRT ports
+  * drm/i915: Fix LVDS stability issue on Ironlake
+  * mm: sigbus instead of abusing oom
+  * ipvs: zero usvc and udest
+  * jffs2: Fix long-standing bug with symlink garbage collection.
+  * intel-iommu: Detect DMAR in hyperspace at probe time.
+  * intel-iommu: Apply BIOS sanity checks for interrupt remapping too.
+  * intel-iommu: Check for an RMRR which ends before it starts.
+  * intel-iommu: Fix oops with intel_iommu=igfx_off
+  * intel-iommu: ignore page table validation in pass through mode
+  * netfilter: xtables: document minimal required version
+  * perf_event: Fix incorrect range check on cpu number
+  * implement early_io{re,un}map for ia64
+  * Linux 2.6.32.2
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 07 Jan 2010 15:28:43 +0000
+
+linux (2.6.32-9.13) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_B43_PHY_LP
+    - LP: #493059
+  * include modules.builtin in the binary debs
+  * config-check -- add a configuration enforcer
+  * config-check -- add a unit-test suite to the checker
+  * [Config] Enable CONFIG_SYN_COOKIES for versatile
+  * [Config] Enable CONFIG_SECURITY_SMACK for ports
+  * [Config] Enable CONFIG_SECURITY_FILE_CAPABILITIES for ports
+  * [Config] Disable CONFIG_COMPAT_BRK for ports
+  * getabis -- add armel versatile to the list
+
+  [ Brad Figg ]
+
+  * SAUCE: Increase the default prealloc buffer for HDA audio devices
+    (non-modem)
+
+  [ Manoj Iyer ]
+
+  * ubuntu: onmibook -- Added missing BOM file
+
+  [ Tim Gardner ]
+
+  * ubuntu: fsam7400 -- Cleanup Makefile
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "ext4: Fix insufficient checks in EXT4_IOC_MOVE_EXT"
+  * signal: Fix alternate signal stack check
+  * SCSI: scsi_lib_dma: fix bug with dma maps on nested scsi objects
+  * SCSI: osd_protocol.h: Add missing #include
+  * SCSI: megaraid_sas: fix 64 bit sense pointer truncation
+  * ext4: fix potential buffer head leak when add_dirent_to_buf() returns
+    ENOSPC
+  * ext4: avoid divide by zero when trying to mount a corrupted file system
+  * ext4: fix the returned block count if EXT4_IOC_MOVE_EXT fails
+  * ext4: fix lock order problem in ext4_move_extents()
+  * ext4: fix possible recursive locking warning in EXT4_IOC_MOVE_EXT
+  * ext4: plug a buffer_head leak in an error path of ext4_iget()
+  * ext4: make sure directory and symlink blocks are revoked
+  * ext4: fix i_flags access in ext4_da_writepages_trans_blocks()
+  * ext4: journal all modifications in ext4_xattr_set_handle
+  * ext4: don't update the superblock in ext4_statfs()
+  * ext4: fix uninit block bitmap initialization when s_meta_first_bg is
+    non-zero
+  * ext4: fix block validity checks so they work correctly with meta_bg
+  * ext4: avoid issuing unnecessary barriers
+  * ext4: fix error handling in ext4_ind_get_blocks()
+  * ext4: make trim/discard optional (and off by default)
+  * ext4: make "norecovery" an alias for "noload"
+  * ext4: Fix double-free of blocks with EXT4_IOC_MOVE_EXT
+  * ext4: initialize moved_len before calling ext4_move_extents()
+  * ext4: move_extent_per_page() cleanup
+  * jbd2: Add ENOMEM checking in and for
+    jbd2_journal_write_metadata_buffer()
+  * ext4: Return the PTR_ERR of the correct pointer in
+    setup_new_group_blocks()
+  * ext4: Avoid data / filesystem corruption when write fails to copy data
+  * ext4: wait for log to commit when umounting
+  * ext4: remove blocks from inode prealloc list on failure
+  * ext4: ext4_get_reserved_space() must return bytes instead of blocks
+  * ext4: quota macros cleanup
+  * ext4: fix incorrect block reservation on quota transfer.
+  * ext4: Wait for proper transaction commit on fsync
+  * ext4: Fix insufficient checks in EXT4_IOC_MOVE_EXT
+  * ext4: Fix potential fiemap deadlock (mmap_sem vs. i_data_sem)
+  * Linux 2.6.32.1
+  * kbuild: generate modules.builtin
+  * (pre-stable) drm/i915: Fix sync to vblank when VGA output is turned off
+    - LP: #494461
+  * (pre-stable) drm/i915: Avoid NULL dereference with component_only
+    tv_modes
+    - LP: #494045
+
+  [ Zhao Yakui ]
+
+  * (pre-stable) acpi: Use the ARB_DISABLE for the CPU which model id is
+    less than 0x0f.
+    - LP: #481765
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 17 Dec 2009 15:41:21 +0000
+
+linux (2.6.32-8.12) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: AppArmor -- add linux/err.h for ERR_PTR
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 12 Dec 2009 10:56:16 +0000
+
+linux (2.6.32-8.11) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: default ATI Radeon KMS to off until userspace catches
+    up"
+  * Revert "SAUCE: AppArmor: Fix oops there is no tracer and doing unsafe
+    transition."
+  * Revert "SAUCE: AppArmor: Fix refcounting bug causing leak of creds"
+  * Revert "SAUCE: AppArmor: Fix cap audit_caching preemption disabling"
+  * Revert "SAUCE: AppArmor: Fix Oops when in apparmor_bprm_set_creds"
+  * Revert "SAUCE: AppArmor: Fix oops after profile removal"
+  * Revert "SAUCE: AppArmor: AppArmor disallows truncate of deleted files."
+  * Revert "SAUCE: AppArmor: AppArmor fails to audit change_hat correctly"
+  * Revert "SAUCE: AppArmor: Policy load and replacement can fail to alloc
+    mem"
+  * Revert "SAUCE: AppArmor: AppArmor wrongly reports allow perms as
+    denied"
+  * Revert "SAUCE: AppArmor: Fix mediation of "deleted" paths"
+  * Revert "SAUCE: AppArmor: Fix off by 2 error in getprocattr mem
+    allocation"
+  * Revert "SAUCE: AppArmor: Set error code after structure
+    initialization."
+  * Revert "AppArmor -- fix pstrace_may_access rename"
+  * Revert "ubuntu: AppArmor security module"
+  * Revert "SAUCE: Add config option to set a default LSM"
+  * Revert "ubuntu: fsam7400 -- sw kill switch driver"
+  * Revert "[Config] fsam7400 -- enable"
+  * Revert "[Config] AUFS -- enable"
+  * Revert "ubuntu: AUFS -- aufs2-30 20090727"
+  * Revert "ubuntu: AUFS -- export various core functions -- fixes"
+  * Revert "ubuntu: AUFS -- export various core functions"
+  * Revert "[Config] ubuntu/iscsitarget -- disable"
+  * Revert "[Config] iscsitarget -- enable"
+  * Revert "ubuntu: iscsitarget -- SVN revision r214"
+  * update Vcs-Git to point to the correct repository
+    - LP: #493589
+  * update build environment overrides to lucid
+    - LP: #493589
+  * [Config] enable CONFIG_DEVTMPFS
+  * [Config] update all configs following AppArmor 2009-12-08 update
+  * SAUCE: isapnp_init: make isa PNP scans occur async
+  * [Config] fsam7400 -- enable
+  * [Config] omnibook -- enable
+  * [Config] cleanup CONFIG_AUDIT
+  * ubuntu: AUFS -- export various core functions (aufs2-base.patch)
+  * ubuntu: AUFS -- export various core functions (aufs2-standalone.patch)
+  * ubuntu: AUFS -- aufs2 20091209
+  * [Config] AUFS -- enable
+  * [Config] iscsitarget -- enable
+
+  [ Arjan van de Ven ]
+
+  * SAUCE: KMS: cache the EDID information of the LVDS
+
+  [ Colin Watson ]
+
+  * bnx2: update d-i firmware filenames
+    - LP: #494052
+  * add cdc_ether to nic-usb-modules udeb
+    - LP: #495060
+
+  [ John Johansen ]
+
+  * ubuntu: AppArmor -- mainline 2009-10-08
+
+  [ Manoj Iyer ]
+
+  * ubuntu: fsam7400 -- kill switch for Fujitsu Siemens Amilo M 7400
+  * ubuntu: omnibook -- support Toshiba (HP) netbooks
+  * ubuntu: iscsitarget --- version 1.4.19
+    - LP: #494693
+
+  [ Surbhi Palande ]
+
+  * SAUCE: Make populate_rootfs asynchronous
+
+  [ Tim Gardner ]
+
+  * Parallelize flavour builds and packaging
+  * [Config] Enable CONFIG_KSM
+
+  [ Upstream Kernel Changes ]
+
+  * Config option to set a default LSM
+  * LSM: Add security_path_chroot().
+  * LSM: Add security_path_chroot().
+  * LSM: Move security_path_chmod()/security_path_chown() to after
+    mutex_lock().
+  * ext4: Fix insufficient checks in EXT4_IOC_MOVE_EXT
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 11 Dec 2009 17:45:19 +0000
+
+linux (2.6.32-7.10) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] disable CONFIG_THUMB2_KERNEL to fix arm FTBFS
+
+ -- Andy Whitcroft <apw@canonical.com>  Sun, 06 Dec 2009 12:56:48 +0000
+
+linux (2.6.32-7.9) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: set /proc/acpi/video/*/DOS to 4 by default
+    - LP: #458982
+  * SAUCE: ensure vga16fb loads if no other driver claims the VGA device
+  * [Config] update configs following versatile switch to V7
+  * rebased to v2.6.32
+  * [Config] update configs following rebase to v2.6.32
+  * [Config] update ports configs following rebase to v2.6.32
+  * SAUCE: default ATI Radeon KMS to off until userspace catches up
+
+  [ Arjan van de Ven ]
+
+  * SAUCE: vfs: Add a trace point in the mark_inode_dirty function
+
+  [ Leann Ogasawara ]
+
+  * [SCSI] megaraid_sas: remove sysfs poll_mode_io world writeable
+    permissions
+    - CVE-2009-3939
+
+  [ Loic Minier ]
+
+  * SAUCE: select a v7 CPU for versatile
+
+  [ Takashi Iwai ]
+
+  * SAUCE: ALSA: hda - Add power on/off counter
+
+  [ Upstream changes ]
+
+  * rebased to v2.6.32
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 04 Dec 2009 10:44:50 +0000
+
+linux (2.6.32-6.8) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] disable SSB devices for armel
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 28 Nov 2009 12:16:40 +0000
+
+linux (2.6.32-6.7) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: default ATI Radeon KMS to off until userspace catches up"
+  * Revert "SAUCE: Dell XPS710 reboot quirk"
+  * Revert "SAUCE: Link acpi-cpufreq.o first"
+  * Revert "SAUCE: LPIA  Logical reset of USB port on resume"
+  * Revert "SAUCE: LPIA Reboot fix for Intel Crownbeach development boards"
+  * Revert "SAUCE: Enable HDMI audio codec on Studio XPS 1340"
+  * Revert "SAUCE: Dell laptop digital mic does not work, PCI 1028:0271"
+  * Revert "Add Dell Dimension 9200 reboot quirk"
+  * Revert "SAUCE: Correctly blacklist Thinkpad r40e in ACPI"
+  * Revert "SAUCE: tulip: Define ULI PCI ID's"
+  * Revert "SAUCE: Lower warning level of some PCI messages"
+  * Revert "mac80211: fix two issues in debugfs"
+    Drop a number of known redundant commits as identified in the Ubuntu
+    delta review blueprint.
+
+  * reenable armel versatile flavour
+  * [Config] disable CONFIG_USB_DEVICEFS
+
+  [ Tim Gardner ]
+
+  * [Config] udeb: Add squashfs to fs-core-modules
+    - LP: #352615
+  * [Config] Create a real squashfs udeb
+    - LP: #352615
+
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 27 Nov 2009 17:31:16 +0000
+
+linux (2.6.32-5.6) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.32-rc8
+  * update configs following rebase to v2.6.32-rc8
+  * update ports configs since rebase to v2.6.32-rc8
+  * [Config] enable cgroup options
+    - LP: #480739
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.32-rc8
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 23 Nov 2009 11:16:14 +0000
+
+linux (2.6.32-4.5) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] SERIO_LIBPS2 and SERIO_I8042 must match
+  * rebase to v2.6.32-rc7
+  * resync with Karmic proposed
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: Fix oops after profile removal
+    - LP: #475619
+  * SAUCE: AppArmor: Fix Oops when in apparmor_bprm_set_creds
+    - LP: #437258
+  * SAUCE: AppArmor: Fix cap audit_caching preemption disabling
+    - LP: #479102
+  * SAUCE: AppArmor: Fix refcounting bug causing leak of creds
+    - LP: #479115
+  * SAUCE: AppArmor: Fix oops there is no tracer and doing unsafe
+    transition.
+    - LP: #480112
+
+  [ Ubuntu Changes ]
+
+  * resync with Karmic proposed (ddbc670a86a3dee18541a3734149f250ff307adf)
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.32-rc7
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 13 Nov 2009 11:35:13 +0000
+
+linux (2.6.32-3.4) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] SERIO_LIBPS2 and SERIO_I8042 must match
+  * [Upstream] add local prefix to oss local change_bits
+
+  [ Upstream Kernel Changes ]
+
+  * mtd/maps: gpio-addr-flash: pull in linux/ headers rather than asm/
+  * mtd/maps: gpio-addr-flash: depend on GPIO arch support
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 11 Nov 2009 14:47:04 +0000
+
+linux (2.6.32-3.3) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.32-rc6
+  * [Config] update configs following rebase to v2.6.32-rc6
+  * [Config] update ports configs following rebase to v2.6.32-rc6
+  * resync with Karmic Ubuntu-2.6.31-15.49
+  * [Config] add module ignores for broken drivers
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: AppArmor wrongly reports allow perms as denied
+    - LP: #453335
+  * SAUCE: AppArmor: Policy load and replacement can fail to alloc mem
+    - LP: #458299
+  * SAUCE: AppArmor: AppArmor fails to audit change_hat correctly
+    - LP: #462824
+  * SAUCE: AppArmor: AppArmor disallows truncate of deleted files.
+    - LP: #451375
+
+  [ Kees Cook ]
+
+  * SAUCE: Fix nx_enable reporting
+    - LP: #454285
+
+  [ Scott James Remnant ]
+
+  * Revert "SAUCE: trace: add trace_event for the open() syscall"
+  * SAUCE: trace: add trace events for open(), exec() and uselib()
+    - LP: #462111
+
+  [ Stefan Bader ]
+
+  * SAUCE: Fix sub-flavour script to not stop on missing directories
+    - LP: #453073
+
+  [ Ubuntu Changes ]
+
+  * resync with Karmic Ubuntu-2.6.31-15.49
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.32-rc6
+    - LP: #464552
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 10 Nov 2009 15:00:57 +0000
+
+linux (2.6.32-2.2) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * install the full changelog with the binary package
+  * changelog -- explicitly note rebases and clean history
+  * reinstate armel.mk with no flavours
+    - LP: #449637
+  * [Upstream] block: silently error unsupported empty barriers too
+    - LP: #420423
+  * [Config] udate configs following karmic resync
+  * [Config] update ports configs following karmic resync
+  * [Upstream] lirc -- follow removal of .id element
+
+  [ Colin Watson ]
+
+  * Use section 'admin' rather than 'base'
+  * Add more e100 firmware to nic-modules
+    - LP: #451872
+  * Add qla1280 firmware to scsi-modules
+    - LP: #381037
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: Set error code after structure initialization.
+    - LP: #427948
+  * SAUCE: AppArmor: Fix off by 2 error in getprocattr mem allocation
+    - LP: #446595
+  * SAUCE: AppArmor: Fix mediation of "deleted" paths
+
+  [ Kees Cook ]
+
+  * SAUCE: [x86] fix report of cs-limit nx-emulation
+    - LP: #454285
+
+  [ Leann Ogasawara ]
+
+  * SAUCE: (drop after 2.6.31) input: Add support for filtering input
+    events
+    - LP: #430809
+  * SAUCE: (drop after 2.6.31) dell-laptop: Trigger rfkill updates on wifi
+    toggle switch press
+    - LP: #430809
+
+  [ Luke Yelavich ]
+
+  * SAUCE: Add sr_mod to the scsi-modules udeb for powerpc
+  * [Config] Add sd_mod to scsi-modules udeb for powerpc
+
+  [ Mario Limonciello ]
+
+  * SAUCE: Update to LIRC 0.8.6
+    - LP: #432678
+  * SAUCE: dell-laptop: Store the HW switch status internally rather than
+    requerying every time
+    - LP: #430809
+  * SAUCE: dell-laptop: Blacklist machines not supporting dell-laptop
+    - LP: #430809
+
+  [ Stefan Bader ]
+
+  * [Upstream] acerhdf: Limit modalias matching to supported boards
+    - LP: #435958
+
+  [ Tim Gardner ]
+
+  * [Upstream] i915: Fix i2c init message
+    - LP: #409361
+  * [Config] Add sym53c8xx.ko to virtual sub-flavour
+    - LP: #439415
+  * [Config] Add d101m_ucode.bin to d-i/firmware/nic-modules
+    - LP: #439456
+  * [Config] Set default I/O scheduler back to CFQ for desktop flavours
+    - LP: #381300
+  * SAUCE: Created MODULE_EXPORT/MODULE_IMPORT macros
+    - LP: #430694
+  * SAUCE: Use MODULE_IMPORT macro to tie intel_agp to i915
+    - LP: #430694
+  * [Config] CONFIG_GFS2_FS_LOCKING_DLM=y
+    - LP: #416325
+  * SAUCE: Fix MODULE_IMPORT/MODULE_EXPORT
+    - LP: #430694
+  * SAUCE: Raise the default console 'quiet' level to 2
+  * [Config] CONFIG_X86_PAT=y
+  * [Config] Add armel arch to linux-libc-dev arches.
+    - LP: #449637
+  * [Config] CONFIG_X86_MCE
+  * [Upstream] (drop after 2.6.31) Input: synaptics - add another Protege
+    M300 to rate blacklist
+    - LP: #433801
+
+  [ Upstream Kernel Changes ]
+
+  * sgi-gru: Fix kernel stack buffer overrun, CVE-2009-2584
+  * drm/i915: Fix FDI M/N setting according with correct color depth
+    - LP: #416792
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 22 Oct 2009 16:53:33 +0100
+
+linux (2.6.32-1.1) lucid; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.32-rc3
+  * [Config] update configs following rebase to 2.6.32-rc3
+  * [Config] update ports configs following rebase to 2.6.32-rc3
+  * AppArmor -- fix pstrace_may_access rename
+  * staging/android -- disable
+  * ubuntu: dm-raid-45 -- update to compile with 2.6.32
+  * ubuntu: drbd -- disable
+  * staging/comdi -- disable
+  * staging/go7007 -- disable
+  * [Config] staging/winbond -- disable
+  * [Config] ubuntu/iscsitarget -- disable
+  * [d-i] cbc and ecb are builtin make them optional in udebs
+  * rebase to v2.6.32-rc5
+  * [Config] update configs following rebase to v2.6.32-rc5
+  * [Config] update ports configs following rebase to v2.6.31-rc5
+
+  [ Tim Gardner ]
+
+  * [Config] Add cpio as a build dependency.
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v2.6.32-rc3
+  * rebase to v2.6.32-rc5
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 05 Oct 2009 15:48:58 +0100
+
+linux (2.6.31-11.37) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Increase kernel log buffer to 256K for amd64 flavours
+    - LP: #424810
+  * [Config] Set HZ=100 for amd64 flavours
+    - LP: #438234
+  * [Upstream] e1000e: Emit notice instead of an error when
+    pci_enable_pcie_error_reporting() fails
+    - LP: #436370
+
+  [ Upstream Kernel Changes ]
+
+  * n_tty: honor opost flag for echoes
+  * n_tty: move echoctl check and clean up logic
+    - LP: #438310
+
+  * Revert "[Upstream] drm/i915: Check that the relocation points to within
+    the target" - Use upstream cherry-pick.
+  * drm/i915: Check that the relocation points to within the target
+    - LP: #429241
+
+  * drm/i915: fix tiling on IGDNG
+  * drm/i915: add B43 chipset support
+  * agp/intel: Add B43 chipset support
+    Intel request from kernel team mailing list.
+
+  * HID: completely remove apple mightymouse from blacklist
+    - LP: #428111
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 28 Sep 2009 11:47:29 -0600
+
+linux (2.6.31-11.36) karmic; urgency=low
+
+  [ Brian Rogers ]
+
+  * SAUCE: (drop after 2.6.31) em28xx: ir-kbd-i2c init data needs a
+    persistent object
+  * SAUCE: (drop after 2.6.31) saa7134: ir-kbd-i2c init data needs a
+    persistent object
+
+  [ Takashi Iwai ]
+
+  * [Upstream] ALSA: hda - Add another entry for Nvidia HDMI device
+    - LP: #416482
+
+  [ Tyler Hicks ]
+
+  * SAUCE: (drop after 2.6.31) eCryptfs: Prevent lower dentry from going
+    negative during unlink
+
+  [ Upstream Kernel Changes ]
+
+  * sg: fix oops in the error path in sg_build_indirect()
+  * mpt2sas : Rescan topology from Interrupt context instead of work thread
+  * mpt2sas: Prevent sending command to FW while Host Reset
+  * mpt2sas: setting SDEV into RUNNING state from Interrupt context
+  * mpt2sas: Raid 10 Volume is showing as Raid 1E in dmesg
+  * SCSI: fix oops during scsi scanning
+  * SCSI: libsrp: fix memory leak in srp_ring_free()
+  * cfg80211: fix looping soft lockup in find_ie()
+  * ath5k: write PCU registers on initial reset
+  * binfmt_elf: fix PT_INTERP bss handling
+  * TPM: Fixup boot probe timeout for tpm_tis driver
+  * md: Fix "strchr" [drivers/md/dm-log-userspace.ko] undefined!
+  * x86/amd-iommu: fix broken check in amd_iommu_flush_all_devices
+  * fix undefined reference to user_shm_unlock
+  * perf_counter: Fix buffer overflow in perf_copy_attr()
+  * perf_counter: Start counting time enabled when group leader gets
+    enabled
+  * powerpc/perf_counters: Reduce stack usage of power_check_constraints
+  * powerpc: Fix bug where perf_counters breaks oprofile
+  * powerpc/ps3: Workaround for flash memory I/O error
+  * block: don't assume device has a request list backing in nr_requests
+    store
+  * agp/intel: remove restore in resume
+  * ALSA: cs46xx - Fix minimum period size
+  * ASoC: Fix WM835x Out4 capture enumeration
+  * sound: oxygen: work around MCE when changing volume
+  * mlx4_core: Allocate and map sufficient ICM memory for EQ context
+  * perf stat: Change noise calculation to use stddev
+  * x86: Fix x86_model test in es7000_apic_is_cluster()
+  * x86/i386: Make sure stack-protector segment base is cache aligned
+  * PCI: apply nv_msi_ht_cap_quirk on resume too
+  * x86, pat: Fix cacheflush address in change_page_attr_set_clr()
+  * ARM: 5691/1: fix cache aliasing issues between kmap() and kmap_atomic()
+    with highmem
+  * KVM guest: do not batch pte updates from interrupt context
+  * KVM: Fix coalesced interrupt reporting in IOAPIC
+  * KVM: VMX: Check cpl before emulating debug register access
+  * KVM guest: fix bogus wallclock physical address calculation
+  * KVM: x86: Disallow hypercalls for guest callers in rings > 0
+  * KVM: VMX: Fix cr8 exiting control clobbering by EPT
+  * KVM: x86 emulator: Implement zero-extended immediate decoding
+  * KVM: MMU: make __kvm_mmu_free_some_pages handle empty list
+  * KVM: x86 emulator: fix jmp far decoding (opcode 0xea)
+  * KVM: limit lapic periodic timer frequency
+  * libata: fix off-by-one error in ata_tf_read_block()
+  * PCI quirk: update 82576 device ids in SR-IOV quirks list
+  * PCI: Unhide the SMBus on the Compaq Evo D510 USDT
+  * powerpc/pseries: Fix to handle slb resize across migration
+  * Linux 2.6.31.1
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 24 Sep 2009 13:04:28 -0600
+
+linux (2.6.31-10.35) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * Disable CONFIG_UEVENT_HELPER_PATH
+
+  [ Andy Whitcroft ]
+
+  * [Config] Enable CONFIG_USB_GADGET_DUMMY_HCD
+  * remove the tlsup driver
+  * remove lmpcm logitech driver support
+
+  [ Bryan Wu ]
+
+  * Add 3 missing files to prerm remove file list
+    - LP: #345623, #415832
+
+  [ Chris Wilson ]
+
+  * [Upstream] drm/i915: Check that the relocation points to within the
+    target
+    - LP: #429241
+
+  [ Luke Yelavich ]
+
+  * [Config] Set CONFIG_EXT4_FS=y on ports architectures
+
+  [ Manoj Iyer ]
+
+  * SAUCE: Added quirk to recognize GE0301 3G modem as an interface.
+    - LP: #348861
+
+  [ Tim Gardner ]
+
+  * Revert "[Upstream] ACPI: Add Thinkpad W500, W700, & W700ds to OSI(Linux) white-list"
+  * Revert "[Upstream] ACPI: Add Thinkpad R400 & Thinkpad R500 to OSI(Linux) white-list"
+  * Revert "[Upstream] ACPI: Add Thinkpad X300 & Thinkpad X301 to OSI(Linux) white-list"
+  * Revert "[Upstream] ACPI: Add Thinkpad X200, X200s, X200t to OSI(Linux) white-list"
+  * Revert "[Upstream] ACPI: Add Thinkpad T400 & Thinkpad T500 to OSI(Linux) white-list"
+    Upstream suggests that this is not the right approach.
+
+  * [Config] Set default I/O scheduler to DEADLINE
+    CFQ seems to have some load related problems which are often exacerbated by sreadahead.
+    - LP: #381300
+
+  [ ubuntu@tjworld.net ]
+
+  * SAUCE: ipw2200: Enable LED by default
+    - LP: #21367
+
+  [ Upstream Kernel Changes ]
+
+  * ALSA: hda - Add support for new AMD HD audio devices
+    - LP: #430564
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 16 Sep 2009 15:37:49 +0100
+
+linux (2.6.31-10.34) karmic; urgency=low
+
+  [ Ted Tso ]
+
+  * [Upstream] ext3: Don't update superblock write time when filesystem is
+    read-only
+    - LP: #427822
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Sep 2009 16:00:45 -0600
+
+linux (2.6.31-10.33) karmic; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Upstream] dvb-usb: fix tuning with Cinergy T2
+    - LP: #421258
+
+  [ Tim Gardner ]
+
+  * [Config] Unconditionally copy files from sub-flavours lists.
+    (really, really fix it this time)
+    - LP: #423426
+  * [Config] Set CONFIG_CACHEFILES=m for all flavours
+
+  [ Upstream Kernel Changes ]
+
+  * ext4: Don't update superblock write time when filesystem is read-only
+    - LP: #427822
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 15 Sep 2009 07:50:21 -0600
+
+linux (2.6.31-10.32) karmic; urgency=low
+
+  [ Eric Miao ]
+
+  * [Config] enable module support for memory stick
+    - LP: #159951
+
+  [ Tim Gardner ]
+
+  * [Config] Unconditionally copy files from sub-flavours lists.
+    - LP: #423426
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 10 Sep 2009 15:57:55 -0600
+
+linux (2.6.31-10.31) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.31 final
+
+  [ Colin Watson ]
+
+  * [Config] Recommend grub-pc in linux-image
+    - LP: #385741
+
+  [ Ike Panhc ]
+
+  * [Upstream] Pull latest update of lenovo-sl-laptop
+
+  [ Peter Feuerer ]
+
+  * [Upstream] (drop after 2.6.31) acerhdf: fix fan control for AOA150
+    model
+    - LP: #426691
+
+  [ Tim Gardner ]
+
+  * [Config] De-macro some package names.
+
+  [ Upstream Changes ]
+
+  * rebase to 2.6.31 final.
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 10 Sep 2009 09:38:10 +0100
+
+linux (2.6.31-10.30) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * [Config] Enable CONFIG_USB_DEVICEFS
+    - LP: #417748
+  * [Config] Populate the config-update template a bit more
+
+  [ Andy Whitcroft ]
+
+  * rebase to v2.6.31-rc9
+  * [Config] update configs following rebase to v2.6.31-rc9
+  * [Config] update ports configs following rebase to v2.6.31-rc9
+
+  [ Colin Ian King ]
+
+  * SAUCE: wireless: hostap, fix oops due to early probing interrupt
+    - LP: #254837
+
+  [ Jerone Young ]
+
+  * [Upstream] ACPI: Add Thinkpad T400 & Thinkpad T500 to OSI(Linux)
+    white-list
+    - LP: #281732
+  * [Upstream] ACPI: Add Thinkpad X200, X200s, X200t to OSI(Linux)
+    white-list
+    - LP: #281732
+  * [Upstream] ACPI: Add Thinkpad X300 & Thinkpad X301 to OSI(Linux)
+    white-list
+    - LP: #281732
+  * [Upstream] ACPI: Add Thinkpad R400 & Thinkpad R500 to OSI(Linux)
+    white-list
+    - LP: #281732
+  * [Upstream] ACPI: Add Thinkpad W500, W700, & W700ds to OSI(Linux)
+    white-list
+    - LP: #281732
+
+  [ John Johansen ]
+
+  * SAUCE: AppArmor: Fix profile attachment for regexp based profile names
+    - LP: #419308
+  * SAUCE: AppArmor: Return the correct error codes on profile
+    addition/removal
+    - LP: #408473
+  * SAUCE: AppArmor: Fix OOPS in profile listing, and display full list
+    - LP: #408454
+  * SAUCE: AppArmor: Fix mapping of pux to new internal permission format
+    - LP: #419222
+  * SAUCE: AppArmor: Fix change_profile failure
+    - LP: #401931
+  * SAUCE: AppArmor: Tell git to ignore generated include files
+    - LP: #419505
+
+  [ Stefan Bader ]
+
+  * [Upstream] acpi: video: Loosen strictness of video bus detection code
+    - LP: #333386
+  * SAUCE: Remove ov511 driver from ubuntu subdirectory
+
+  [ Tim Gardner ]
+
+  * [Config] Exclude char-modules from non-x86 udeb creation
+  * SAUCE: Notify the ACPI call chain of AC events
+  * [Config] CONFIG_SATA_VIA=m
+    - LP: #403385
+  * [Config] Build in all phylib support modules.
+  * [Config] Don't fail when sub-flavour files are missing
+    - LP: #423426
+  * [Config] Set CONFIG_LSM_MMAP_MIN_ADDR=0
+    - LP: #423513
+
+  [ Upstream ]
+
+  * Rebased against v2.6.31-rc9
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 07 Sep 2009 11:33:45 +0100
+
+linux (2.6.31-9.29) karmic; urgency=low
+
+  [ Leann Ogasawara ]
+
+  * [Upstream] agp/intel: support for new chip variant of IGDNG mobile
+    - LP: #419993
+  * [Config] d-i/modules: Add new char-modules file, initialize with
+    intel-agp
+    - LP: #420605
+
+  [ Upstream ]
+
+  * Rebased against 2.6.31-rc8 plus some inotify regression patches:
+    up through git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+    adda766193ea1cf3137484a9521972d080d0b7af.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 28 Aug 2009 06:31:30 -0600
+
+linux (2.6.31-8.28) karmic; urgency=low
+
+  [ Ike Panhc ]
+
+  * [Config] Let nic-shared-modules depends on crypto-modules
+    - LP: #360966
+
+  [ Leann Ogasawara ]
+
+  * [Upstream] (drop after 2.6.31) drm/i915: increase default latency
+    constant
+    - LP: #412492
+
+  [ Mario Limonciello ]
+
+  * [Upstream]: (drop after 2.6.31) dell-laptop: don't change softblock
+    status if HW switch is disabled
+    - LP: #418721
+  * [Upstream]: (drop after 2.6.31) compal-laptop: Add support for known
+    Compal made Dell laptops
+  * [Upstream]: (drop after 2.6.31) compal-laptop: Replace sysfs support
+    with rfkill support
+
+  [ Tim Gardner ]
+
+  * [Config] Add acpiphp to virtual sub-flavour
+    - LP: #364916
+  * Drop KSM patch set for now because of instabilities with encrypted swap.
+    - LP: #418781
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Wed, 26 Aug 2009 08:14:26 -0600
+
+linux (2.6.31-7.27) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] updateconfigs updateportsconfigs after 2.6.31-rc7 rebase
+  * SAUCE: (drop after 2.6.31) Added KSM from mmotm-2009-08-20-19-18
+    Replaces previous ksm patches from 2.6.31-6.25
+  * [Config] KSM=y
+
+  [ Upstream ]
+
+  * Rebased against v2.6.31-rc7
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sat, 22 Aug 2009 20:32:11 -0600
+
+linux (2.6.31-6.26) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] enable CONFIG_AUFS_BR_RAMFS
+    - LP: #414738
+  * split out debian directory ready for abstraction
+  * add printdebian target to find branch target
+  * abstracted debian -- debian/files is not abstracted
+  * abstracted debian -- packages must be built in debian/<pkg>
+  * abstracted debian -- kernel-wedge needs to work in debian/
+  * abstracted debian -- ensure we install the copyright file
+  * abstracted-debian -- drop the debian directories from headers
+  * abstracted-debian -- drop the debian directories from headers part 2
+  * SAUCE: ubuntu-insert-changes -- follow abstracted debian
+  * [Upstream] aoe: ensure we initialise the request_queue correctly V2
+    - LP: #410198
+
+  [ Luke Yelavich ]
+
+  * [Config] Ports: Disable CONFIG_CPU_FREQ_DEBUG on powerpc-smp
+  * [Config] Ports: Re-enable windfarm modules on powerpc64-smp
+    - LP: #413150
+  * [Config] Ports: Build all cpu frequency scaling governors into ports
+    kernels
+  * [Config] Ports: Build ext2 and ext3 modules into ports kernels
+  * [Config] Ports: CONFIG_PACKET=y for all ports kernels
+  * [Config] Ports: Enable PS3 network driver
+
+  [ Stefan Bader ]
+
+  * abstracted debian -- call $(DEBIAN)/rules using make
+
+  [ Tim Gardner ]
+
+  * [Config] Abstract the debian directory
+  * SAUCE: Improve error reporting in postinst
+    - LP: #358564
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Sun, 16 Aug 2009 20:33:28 -0600
+
+linux (2.6.31-6.25) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * script to generate Ubuntu changes from changelog
+  * [Config] standardise ANDROID options
+  * [Config] standardise CONFIG_ATM as module
+  * [Config] standardise CONFIG_LIB80211 as module
+  * [Config] disable CONFIG_PRINT_QUOTA_WARNING
+  * [Config] set CONFIG_CRAMFS as module
+  * [Config] enable CONFIG_DAB and modules
+  * [Config] set CONFIG_MAC80211_HWSIM as module
+  * [Config] set CONFIG_NET_CLS_FLOW as module
+  * [Config] set CONFIG_NF_CONNTRACK_SANE as module
+  * [Config] set CONFIG_NF_CT_PROTO_DCCP as module
+  * [Config] set CONFIG_RTC_DRV_DS1511 as module
+  * [Config] set CONFIG_RTC_DRV_R9701 as module
+  * [Config] set CONFIG_RTC_DRV_S35390A as module
+  * [Config] set CONFIG_TOIM3232_DONGLE as module
+  * [Config] standardise CONFIG_USB_MIDI_GADGET as module
+  * [Config] standardise CONFIG_USB_G_PRINTER as module
+  * [Config] standardise CONFIG_USB_SERIAL_IR as module
+  * [Config] set CONFIG_USB_SERIAL_IUU as module
+  * [Config] standardise CONFIG_USB_STORAGE_CYPRESS_ATACB as module
+  * [Config] standardise CONFIG_USB_STORAGE_ONETOUCH as module
+  * cleanup remains of dm-loop
+  * drop thinkpad ec and smapi support
+  * drop appleir
+  * [Config] update configs following rebase to v2.6.31-rc6
+  * rebase to v2.6.31-rc6
+
+  [ Hugh Dickins ]
+
+  * SAUCE: ksm patch 1, drop after 2.6.31
+  * SAUCE: ksm patch 2, drop after 2.6.31
+  * SAUCE: ksm patch 3, drop after 2.6.31
+  * SAUCE: ksm patch 4, drop after 2.6.31
+  * SAUCE: ksm patch 5, drop after 2.6.31
+  * SAUCE: ksm patch 7, drop after 2.6.31
+
+  [ Izik Eidus ]
+
+  * SAUCE: ksm patch 0, drop after 2.6.31
+  * SAUCE: ksm patch 6, drop after 2.6.31
+  * SAUCE: ksm patch 8, drop after 2.6.31
+  * SAUCE: ksm patch 9, drop after 2.6.31
+
+  [ Luke Yelavich ]
+
+  * [Config] Ports: Re-add PS3 modules to udebs
+
+  [ Michael Casadevall ]
+
+  * [Config] Update SPARC config and d-i files to reflect what can be built
+
+  [ Tim Gardner ]
+
+  * [Config] Removed armel package support
+  * [Config] Enabled CONFIG_KSM=y
+
+  [ Upstream Kernel Changes ]
+
+  * Rebased against v2.6.31-rc6
+  * ARM: Cleanup: Revert "ARM: Add more cache memory types macros"
+  * ARM: Cleanup: Revert "Do not use OOB with MLC NAND"
+  * ARM: Cleanup: Revert "ARM: Make ARM arch aware of ubuntu/ drivers"
+  * ARM: Cleanup: Revert "ARM: IMX51: Make video capture drivers compile"
+  * ARM: Cleanup: Revert "ARM: IMX51: Fix isl29003 HWMON driver for i2c
+    changes"
+  * ARM: Cleanup: Revert "ARM: IMX51: IPU irq handler deadlock fix"
+  * ARM: Cleanup: Revert "ARM: IMX51: Babbage 2.5 needs a different system
+    revision"
+  * ARM: Cleanup: Revert "ARM: IMX51: Compile-in the IMX51 cpufreq driver
+    by default"
+  * ARM: Cleanup: Revert "ARM: IMX51: Enable ZONE_DMA for ARCH_MXC"
+  * ARM: Cleanup: Revert "ARM: IMX51: Make ARCH_MXC auto-enable
+    ARCH_MXC_CANONICAL"
+  * ARM: Cleanup: Revert "ARM: IMX51: Unconditionally disable
+    CONFIG_GPIOLIB"
+  * ARM: Cleanup: Revert "ARM: IMX51: Minimal changes for USB to work on
+    2.6.31"
+  * ARM: Cleanup: Revert "ARM: IMX51: Fix plat-mxc/timer.c to handle imx51"
+  * ARM: Cleanup: Revert "ARM: IMX51: Make it compile."
+  * ARM: Cleanup: Revert "ARM: IMX51: Clean-up the craziness of including
+    mxc_uart.h _everywhere_"
+  * ARM: Cleanup: Revert "ARM: IMX51: Move board-mx51* header files to the
+    correct location"
+  * ARM: Cleanup: Revert "ARM: IMX51: Changed from snd_card_new to
+    snd_card_create"
+  * ARM: Cleanup: Revert "ARM: IMX51: Fix up merge error in Kconfig"
+  * ARM: Cleanup: Revert "ARM: IMX51: mxc_timer_init prototype"
+  * ARM: Cleanup: Revert "ARM: IMX51: Removed the mxc_gpio_port structure."
+  * ARM: Cleanup: Revert "ARM: IMX51: Added external declaration for
+    mxc_map_io."
+  * ARM: Cleanup: Revert "ARM: IMX51: Get to bus_id by calling dev_name."
+  * ARM: Cleanup: Revert "ARM: IMX51: Get to bus_id by calling dev_name."
+  * ARM: Cleanup: Revert "ARM: IMX51: snd_soc_machine structure replaced
+    with snd_soc_card."
+  * ARM: Cleanup: Revert "ARM: IMX51: codec structure was moved to the card
+    structure"
+  * ARM: Cleanup: Revert "ARM: IMX51: Hack to add defines for
+    DMA_MODE_READ/WRITE/MASK"
+  * ARM: Cleanup: Revert "ARM: IMX51: Add SoC and board support for
+    Freescale mx51 platform"
+  * Driver core: add new device to bus's list before probing
+  * [Upstream] (drop after 2.6.31) ALSA: hda - Reduce click noise at
+    power-saving
+    - LP: #381693, #399750, #380892
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 14 Aug 2009 11:32:23 +0100
+
+linux (2.6.31-5.24) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * ARM: IMX51: Make video capture drivers compile
+  * [Config] IMX51: Config updates
+
+  [ Andy Whitcroft ]
+
+  * remove leftovers of dm-bbr
+
+  [ Leann Ogasawara ]
+
+  * Add pata_cs5535 to pata-modules
+    - LP: #318805
+
+  [ Luke Yelavich ]
+
+  * [Config] CONFIG_PPC64=y for powerpc64-smp
+  * [Config] Set the maximum number of CPUs to 1024 for powerpc64-smp
+  * [Config] CONFIG_PPC_PS3=y for powerpc64-smp
+  * [Config] CONFIG_PPC_MAPLE=y on powerpc64-smp
+  * [Config] CONFIG_PPC_PASEMI=y on powerpc64-smp
+  * [Config] CONFIG_CPU_FREQ_PMAC64=y on powerpc64-smp
+  * [Config] Enable all PS3 drivers in powerpc64-smp
+
+  [ Mario Limonciello ]
+
+  * LIRC -- fix lirc-i2c 2.6.31 compilation
+
+  [ Matthew Garrett ]
+
+  * [Upstream] dell-laptop: Fix rfkill state queries
+
+  [ Tim Gardner ]
+
+  * [Config] Ignore armel ABI and module changes
+  * [Config] Update configs after rebase against 2.6.31-rc5
+
+  [ Upstream ]
+
+  * Rebased to 2.6.31-rc5
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 28 Jul 2009 10:10:09 +0100
+
+linux (2.6.31-4.23) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * AUFS -- update to aufs2-30 20090727
+  * [Config] enable AUFS FUSE support
+
+  [ Luke Yelavich ]
+
+  * [Config] CONFIG_JFS_FS=m on sparc
+
+  [ Tim Gardner ]
+
+  * [Upstream] dell-laptop: Fix rfkill state setting.
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 27 Jul 2009 11:11:47 +0100
+
+linux (2.6.31-4.22) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * ARM: IMX51: Add SoC and board support for Freescale mx51 platform
+  * ARM: IMX51: Move board-mx51* header files to the correct location
+  * ARM: IMX51: Clean-up the craziness of including mxc_uart.h _everywhere_
+  * ARM: IMX51: Make it compile.
+  * ARM: IMX51: Unconditionally disable CONFIG_GPIOLIB
+  * ARM: IMX51: Make ARCH_MXC auto-enable ARCH_MXC_CANONICAL
+  * ARM: IMX51: Enable ZONE_DMA for ARCH_MXC
+  * ARM: IMX51: Compile-in the IMX51 cpufreq driver by default
+  * ARM: IMX51: Fix isl29003 HWMON driver for i2c changes
+  * ARM: USB: musb: Refer to musb_otg_timer_func under correct #ifdef
+  * ARM: staging: udlfb: Add vmalloc.h include
+  * UBUNTU [Config]: Bring imx51 config upto date with other flavours
+
+  [ Brad Figg ]
+
+  * ARM: IMX51: Hack to add defines for DMA_MODE_READ/WRITE/MASK
+  * ARM: IMX51: codec structure was moved to the card structure
+  * ARM: IMX51: snd_soc_machine structure replaced with snd_soc_card.
+  * ARM: IMX51: Get to bus_id by calling dev_name.
+  * ARM: IMX51: Get to bus_id by calling dev_name.
+  * ARM: IMX51: Added external declaration for mxc_map_io.
+  * ARM: IMX51: Removed the mxc_gpio_port structure.
+  * ARM: IMX51: mxc_timer_init prototype
+  * ARM: IMX51: Fix up merge error in Kconfig
+  * ARM: IMX51: Changed from snd_card_new to snd_card_create
+
+  [ Dinh Nguyen ]
+
+  * ARM: IMX51: Fix plat-mxc/timer.c to handle imx51
+  * ARM: IMX51: Minimal changes for USB to work on 2.6.31
+  * ARM: IMX51: Babbage 2.5 needs a different system revision
+  * ARM: IMX51: IPU irq handler deadlock fix
+
+  [ Tim Gardner ]
+
+  * [Config] Enabled CONFIG_CAN=m
+    - LP: #327243
+  * [Config] Enabled CONFIG_SERIAL=m
+    - LP: #397189
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 24 Jul 2009 06:19:10 -0600
+
+linux (2.6.31-4.21) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * dm-raid-4-5: Add missing brackets around test_bit()
+
+  [ John Johansen ]
+
+  * AppArmor: Fix change_profile failing lpn401931
+  * AppArmor: Fix determination of forced AUDIT messages.
+  * AppArmor: Fix oops in auditing of the policy interface offset
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 23 Jul 2009 19:18:30 +0100
+
+linux (2.6.31-4.20) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: iscsitarget -- update to SVN revision r214
+  * SAUCE: iscsitarget -- renable driver
+  * [Config] consolidate lpia/lpia and i386/generic configs
+  * [Config] enable CRYPTO modules for all architectures
+  * [Config] enable cryptoloop
+  * [Config] enable various filesystems for armel
+  * [Config] sync i386 generic and generic-pae
+  * [Config] add the 386 (486 processors and above) flavour
+  * [Config] re-set DEFAULT_MMAP_MIN_ADDR
+    - LP: #399914
+  * add genconfigs/genportsconfigs to extract the built configs
+  * updateconfigs -- alter concatenation order allow easier updates
+  * intelfb -- INTELFB now conflicts with DRM_I915
+  * printchanges -- rebase tree does not have stable tags use changelog
+  * AppArmor: fix argument size missmatch on 64 bit builds
+
+  [ Ike Panhc ]
+
+  * Ship bnx2x firmware in nic-modules udeb
+    - LP: #360966
+
+  [ Jeff Mahoney ]
+
+  * AppArmor: fix build failure on ia64
+
+  [ John Johansen ]
+
+  * AppArmour: ensure apparmor enabled parmater is off if AppArmor fails to
+    initialize.
+  * AppArmour: fix auditing of domain transitions to include target profile
+    information
+  * AppArmor: fix C99 violation
+  * AppArmor: revert reporting of create to write permission.
+  * SAUCE: Add config option to set a default LSM
+  * [Config] enable AppArmor by default
+  * AppArmor: Fix NULL pointer dereference oops in profile attachment.
+
+  [ Keith Packard ]
+
+  * SAUCE: drm/i915: Allow frame buffers up to 4096x4096 on 915/945 class
+    hardware
+    - LP: #351756
+
+  [ Luke Yelavich ]
+
+  * [Config] add .o files found in arch/powerpc/lib to all powerpc kernel
+    header packages
+    - LP: #355344
+
+  [ Michael Casadevall ]
+
+  * [Config] update SPARC config files to allow success build
+
+  [ Scott James Remnant ]
+
+  * SAUCE: trace: add trace_event for the open() syscall
+
+  [ Stefan Bader ]
+
+  * SAUCE: jfs: Fix early release of acl in jfs_get_acl
+    - LP: #396780
+
+  [ Tim Gardner ]
+
+  * [Upstream] Fix Soltech TA12 volume hotkeys not sending key release
+    - LP: #397499
+  * [Upstream] USB Option driver - Add USB ID for Novatel MC727/U727/USB727
+    refresh
+    - LP: #365291
+  * [Config] SSB/B44 are common across all arches/flavours.
+
+  [ Upstream ]
+
+  * Rebased to 2.6.31-rc4
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 23 Jul 2009 08:41:39 +0100
+
+linux (2.6.31-3.19) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "[Config] Disabled NDISWRAPPER"
+  * ndiswrapper -- fix i386 compilation failures on cmpxchg8b
+  * AUFS -- export various core functions
+  * AUFS -- export various core functions -- fixes
+  * AUFS -- core filesystem
+  * AUFS -- track changes in v2.6.31
+  * [Config] Enable AUFS
+  * droppped 'iwl3945: do not send scan command if channel count zero' as it
+    is already upstream but failed to auto-drop on rebase.
+
+  [ Eric Paris ]
+
+  * SAUCE: fsnotify: use def_bool in kconfig instead of letting the user
+    choose
+  * SAUCE: inotify: check filename before dropping repeat events
+  * SAUCE: fsnotify: fix inotify tail drop check with path entries
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 14 Jul 2009 12:52:55 +0100
+
+linux (2.6.31-3.18) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Revert "Add splice-2.6.23.patch from AUFS to export a symbol needed by
+    AUFS"
+  * Revert "Add put_filp.patch from AUFS to export a symbol needed by AUFS"
+  * Revert "Add sec_perm-2.6.24.patch from AUFS - export
+    security_inode_permission"
+  * clear out left over AUFS files and modifications
+
+  [ Luke Yelavich ]
+
+  * [Config] Enable CONFIG_USB_ISP116X_HCD on sparc
+  * SAUCE: Explicitly include header files to allow apparmor to build on
+    powerpc
+  * [Config] Enable CONFIG_BLK_DEV_IDECD on powerpc
+
+  [ Tim Gardner ]
+
+  * [Config] Dropped ubuntu/misc/wireless/acx
+  * [Config] Disabled NDISWRAPPER until the compile issues are fixed.
+
+  [ Upstream ]
+
+  * Rebased to 2.6.31-rc3
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 10 Jul 2009 18:59:33 +0100
+
+linux (2.6.31-2.17) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_BLK_DEV_CRYPTOLOOP=m for sparc
+  * compcache -- remove redundant Kconfig entries part 2
+  * compcache -- clean up CCFLAGS declarations
+  * [Config] enable AppArmor
+  * AppArmor: fix operator precidence issue in as_path_link
+
+  [ John Johansen ]
+
+  * AppArmor security module
+  * AppArmor: Correct mapping of file permissions.
+  * AppArmor: Turn auditing of ptrace on
+
+  [ Luke Yelavich ]
+
+  * [Config] disable CONFIG_DM_RAID45 on powerpc
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 10 Jul 2009 15:02:05 +0100
+
+linux (2.6.31-2.16) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * compcache -- remove redundant Kconfig entries
+    added ignore and ignore.modules for all arches since the compcache update
+    changes the modules names as well as some compcache ABI values.
+
+  [ Manoj Iyer ]
+
+  * SAUCE: updated dm-raid45 module version to 2009.04.24 (2.6.30-rc3)
+  * SAUCE: update compcache version to 0.5.3
+
+  [ Tim Gardner ]
+
+  * [Config]: Fix sparc FTBS by adding ignore.modules
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 06 Jul 2009 13:35:29 -0600
+
+linux (2.6.31-2.15) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * SAUCE: default ATI Radeon KMS to off until userspace catches up
+  * [Config] Update configs following rebase to 2.6.31-rc2
+  * [Config] update ports configs following update to 2.6.31-rc2
+
+  [ Luke Yelavich ]
+
+  * [Config] powerpc - Disable CONFIG_RDS
+
+  [ Matt Zimmerman ]
+
+  * Rename linux-doc-PKGVER to linux-doc and clean up its description
+    - LP: #382115
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to mainline 2.6.31-rc2
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 04 Jul 2009 17:39:13 +0100
+
+linux (2.6.31-1.14) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * update ndiswrapper to 1.55
+  * remove leftovers of gfs
+  * [Config] powerpc: enable CONFIG_PPC_DISABLE_WERROR
+
+  [ Luke Yelavich ]
+
+  * [Config] re-enable and build the ide-pmac driver into powerpc kernels
+  * [Config] Build the ServerWorks Frodo / Apple K2 SATA driver into the
+    kernel
+
+  [ Manoj Iyer ]
+
+  * Remove snd-bt-sco ubuntu driver
+
+  [ Michael Casadevall ]
+
+  * [Config] updates ia64 config and d-i folders to allow succesful build
+  * [Config] Update powerpc and sparc for 2.6.31
+
+  [ Upstream Kernel Changes ]
+
+  * intel-iommu: fix Identity Mapping to be arch independent
+    - LP: #384695
+  * ACPI: video: prevent NULL deref in acpi_get_pci_dev()
+
+ -- Andy Whitcroft <apw@canonical.com>  Tue, 30 Jun 2009 17:47:32 +0100
+
+linux (2.6.31-1.13) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * REBASE: rebased to mainline 2.6.31-rc1
+    - "UBUNTU: SAUCE: UHCI USB quirk for resume"
+      no longer applies, using deprecated interfaces, LPIA only, dropped
+    - "UBUNTU: SAUCE: Mask off garbage in Dell WMI scan code data"
+      changes now upstream, dropped
+  * [Config] Update configs following rebase to 2.6.31-rc1
+  * [Config] update ports configs following update to 2.6.31-rc1
+
+  * [Config] disable broken staging driver CONFIG_STLC45XX
+  * SAUCE: fix compcache to use updates accessors
+  * [Config] disable staging driver CONFIG_VT6655
+  * SAUCE: fix DRDB to use updates accessors
+  * [Disable] ndiswrapper needs update
+  * [Disable] LIRC I2C needs update
+  * [Disable] CONFIG_LENOVO_SL_LAPTOP needs update
+  * [Config] disable I2C_DESIGNWARE does not compile
+  * [Config] disable CONFIG_TLSUP for lpia
+  * [Config] disable CONFIG_FB_UDL for arm
+  * SAUCE: disable adding scsi headers to linux-libc-dev
+
+  [ Mario Limonciello ]
+
+  * SAUCE: Add LIRC drivers
+
+ -- Andy Whitcroft <apw@canonical.com>  Thu, 25 Jun 2009 12:06:22 +0100
+
+linux (2.6.30-10.12) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] split out the ports configs into their own family
+  * [Config] update configs following introduction of ports family
+
+  [ Upstream Kernel Changes ]
+
+  * Revert "Rename linux-doc-PKGVER to linux-doc and clean up its
+    description". Fixes linux-doc package name conflicts for now.
+    - LP: #382115
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 22 Jun 2009 09:17:14 -0600
+
+linux (2.6.30-10.11) karmic; urgency=low
+
+  [ Amit Kucheria ]
+
+  * [Config] Comment splitconfig.pl and misc cleanup
+  * [Config] Rename all configs to the new naming scheme
+  * [Config] Splitconfig rework
+  * [Config] Rename scripts/misc/oldconfig to kernelconfig
+  * [Config] Fix build system for new config split
+  * [Config] Run updateconfigs after the splitconfig rework
+
+  [ Andy Whitcroft ]
+
+  * Revert "SAUCE: Default to i915.modeset=0 if CONFIG_DRM_I915_KMS=y"
+  * [Config] standardise CONFIG_STAGING=y
+  * [Config] standardise CONFIG_RD_LZMA=y
+  * [Config] CONFIG_PCI_IOV=y
+  * [Config] CONFIG_PCI_STUB=m
+  * [Config] merge kernel configs more agressively
+
+  [ Colin Watson ]
+
+  * [Config] Run kernel-wedge in $(builddir) rather than at the top level
+  * [Config] Add support for including firmware in udebs
+  * [Config] Ship bnx2 firmware in nic-modules udeb
+    - LP: #384861
+
+  [ Luke Yelavich ]
+
+  * [Config] ports - Import of ports architectures into kernel packaging
+    infrastructure
+  * [Config] ports - Do not update ports kernel configurations by default
+  * [Config] ports - Disable ABI checking for ports architectures
+  * [Config] ports - Build drivers in ubuntu sub-directory on powerpc
+  * [Config] ports - Add control.d/vars.* files for ports architectures
+  * [Config] ports - Add ports architectures for linux-libc-dev
+  * [Config] ports - Create powerpc specific message-modules and
+    block-modules udebs
+  * [Config] ports - Add configuration files for ports architectures
+
+  [ Manoj Iyer ]
+
+  * [Config] Enable CONFIG_BLK_DEV_AEC62XX=m for amd64 and i386
+    - LP: #329864
+
+  [ Michael Casadevall ]
+
+  * [Config] ports - Fix compression of kernels
+
+  [ Stefan Bader ]
+
+  * [Upstream] mmc: prevent dangling block device from accessing stale
+    queues
+    - LP: #383668
+
+  [ Tim Gardner ]
+
+  * [Config] Recommend grub-pc in linux-image
+    - LP: #385741
+  * [Config] Implement i386 generic and generic-pae flavours
+  * [Config] ports - Add control info after integrating ports arches
+  * [Config] Removed auto-generated files from git
+  * [Config] Added netxen_nic to nic-modules
+    - LP: #389603
+
+  [ Matt Zimmerman ]
+
+  * Rename linux-doc-PKGVER to linux-doc and clean up its description
+    - LP: #382115
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 15 Jun 2009 14:38:26 -0600
+
+linux (2.6.30-9.10) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * [Config] CONFIG_SECURITY_TOMOYO=y (amd64, i386, lpia)
+  * [Config] CONFIG_KEXEC_JUMP=y (amd64, lpia)
+  * [Config] CONFIG_LENOVO_SL_LAPTOP=m (amd64, lpia)
+  * [Config] CONFIG_POHMELFS_CRYPTO=y (i386, amd64)
+  * [Config] CONFIG_SERIAL_MAX3100=m (i386, amd64, lpia)
+  * [Config] CONFIG_VIDEO_GO7007=m (amd64, i386)
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30 final
+
+ -- Andy Whitcroft <apw@canonical.com>  Fri, 05 Jun 2009 11:42:53 +0100
+
+linux (2.6.30-8.9) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Config update removed the following options:
+        CONFIG_EDAC_AMD8111=m
+        CONFIG_EDAC_AMD8131=m
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc8
+
+ -- Andy Whitcroft <apw@canonical.com>  Wed, 03 Jun 2009 09:21:13 +0100
+
+linux (2.6.30-7.8) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Enabled NEW configration options:
+      Paravirtualization layer for spinlocks (PARAVIRT_SPINLOCKS) [N/y/?] Y
+      Cisco FNIC Driver (FCOE_FNIC) [N/m/y/?] M
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc7
+
+ -- Andy Whitcroft <apw@canonical.com>  Sat, 23 May 2009 23:47:24 +0100
+
+linux (2.6.30-6.7) karmic; urgency=low
+
+  [ Andy Whitcroft ]
+
+  * Dropped: UBUNTU: SAUCE: input: Blacklist digitizers from joydev.c (now
+    upstream)
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc6
+
+ -- Andy Whitcroft <apw@canonical.com>  Mon, 18 May 2009 18:05:54 +0100
+
+linux (2.6.30-5.6) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Enable Keyspan USB serial device firmware in kernel module
+    - LP: #334285
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc5
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Mon, 11 May 2009 12:02:16 -0600
+
+linux (2.6.30-4.5) karmic; urgency=low
+
+  [ Colin Watson ]
+
+  * Build-Conflict with findutils (= 4.4.1-1ubuntu1), to avoid
+    /usr/include/asm/* going missing
+    - LP: #373214
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 08 May 2009 11:09:08 +0200
+
+linux (2.6.30-3.4) karmic; urgency=low
+
+  [ Kees Cook ]
+
+  * SAUCE: [x86] implement cs-limit nx-emulation for ia32
+    - LP: #369978
+
+  [ Stefan Bader ]
+
+  * SAUCE: input: Blacklist digitizers from joydev.c
+    - LP: #300143
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Fri, 01 May 2009 14:00:42 -0600
+
+linux (2.6.30-2.3) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] Enabled CC_STACKPROTECTOR=y for all x86en
+    - LP: #369152
+  * SAUCE: Default to i915_modeset=0 if CONFIG_DRM_I915_KMS=y
+  * [Config] CONFIG_DRM_I915_KMS=y
+  * [Config] Set CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR to appropriate ARCH
+    minimums
+
+  [ Upstream Kernel Changes ]
+
+  * rebased to 2.6.30-rc4
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 30 Apr 2009 09:17:05 -0600
+
+linux (2.6.30-1.2) karmic; urgency=low
+
+  [ Tim Gardner ]
+
+  * [Config] armel: disable staging drivers, fixes FTBS
+  * [Config] armel imx51: Disable CONFIG_MTD_NAND_MXC, fixes FTBS
+
+  [ Upstream Kernel Changes ]
+
+  * mpt2sas: Change reset_type enum to avoid namespace collision.
+    Submitted upstream.
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Tue, 28 Apr 2009 16:54:41 -0600
+
+linux (2.6.30-1.1) karmic; urgency=low
+
+  * Initial release after rebasing against v2.6.30-rc3
+
+ --  Tim Gardner <tim.gardner@canonical.com>  Thu, 12 Mar 2009 19:16:07 -0600
+
--- linux-4.4.0.orig/debian/cloud-tools/hv_get_dhcp_info
+++ linux-4.4.0/debian/cloud-tools/hv_get_dhcp_info
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+# This example script retrieves the DHCP state of a given interface.
+# In the interest of keeping the KVP daemon code free of distro specific
+# information; the kvp daemon code invokes this external script to gather
+# DHCP setting for the specific interface.
+#
+# Input: Name of the interface
+#
+# Output: The script prints the string "Enabled" to stdout to indicate
+#	that DHCP is enabled on the interface. If DHCP is not enabled,
+#	the script prints the string "Disabled" to stdout.
+#
+# Each Distro is expected to implement this script in a distro specific
+# fashion. 
+
+#set -x
+
+IF_FILE="/etc/network/interfaces"
+NMCMD="nmcli"
+
+function checknetworkmanager {
+	#Assumes if $NMCMD exists, inteface exists and interface is not
+	#  in $IF_FILE then dhcp is being used by NM
+        if  hash $NMCMD >/dev/null 2>&1  ; then
+                if  $NMCMD  dev status |grep -q $1  ; then
+                        echo "Enabled"
+                else
+                        echo "Disabled"
+                fi
+        else
+                #Give up
+                echo "Disabled"
+        fi
+}
+
+if [ -z $1 ]  ; then echo "Disabled"; exit; fi
+
+if [ -e $IF_FILE ]; then
+	if grep -v -e "^#" $IF_FILE|grep -q $1 ; then
+		#interface exists so
+		if grep -q -e $1\.\*dhcp $IF_FILE; then 
+			echo "Enabled"; exit;
+		else
+			echo "Disabled"; exit;
+		fi
+	else
+		checknetworkmanager $1
+		exit
+	fi
+else
+	checknetworkmanager $1
+	exit
+fi
+
--- linux-4.4.0.orig/debian/cloud-tools/hv_get_dns_info
+++ linux-4.4.0/debian/cloud-tools/hv_get_dns_info
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# This example script parses /etc/resolv.conf to retrive DNS information.
+# In the interest of keeping the KVP daemon code free of distro specific
+# information; the kvp daemon code invokes this external script to gather
+# DNS information.
+# This script is expected to print the nameserver values to stdout.
+# Each Distro is expected to implement this script in a distro specific
+# fashion. For instance on Distros that ship with Network Manager enabled,
+# this script can be based on the Network Manager APIs for retrieving DNS
+# entries.
+
+cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }'
--- linux-4.4.0.orig/debian/cloud-tools/hv_set_ifconfig
+++ linux-4.4.0/debian/cloud-tools/hv_set_ifconfig
@@ -0,0 +1,288 @@
+#!/usr/bin/python3
+#
+# hv_set_ifconfig <config> -- take the hv_kvp_daemon generated configuration
+#                             file and apply it to the Ubuntu configuration.
+#
+
+# CONFIG example:
+# HWADDR=11:22:33:44:55:66
+# DEVICE=foo1
+# DHCP=yes
+
+# CONFIG example:
+# HWADDR=11:22:33:44:55:66
+# DEVICE=foo1
+# IPADDR=192.168.99.10
+# GATEWAY=192.168.99.1
+# DNS1=192.168.88.250
+# IPADDR2=192.168.99.11
+# IPV6ADDR=2001:DB8:99::10
+# IPV6NETMASK=64
+# IPV6_DEFAULTGW=2001:DB8:99::10
+
+# set interfaces in hv_kvp_daemon style
+import fileinput
+import sys
+import errno
+import os
+import shutil
+import tempfile
+import subprocess
+
+if_filename="/etc/network/interfaces"
+
+# Drop our output (XXX?)
+sys.stdout = open(os.devnull, 'w')
+sys.stderr = open(os.devnull, 'w')
+
+# Confirm we can open the network configuration.
+try:
+    if_file=open(if_filename,"r+")
+except IOError as e:
+    exit(e.errno)
+else:
+    if_file.close()
+
+# Usage: hv_set_ifconfig <config>
+if len(sys.argv) != 2 :
+    exit(errno.EINVAL)
+
+#
+# Here is the format of the ip configuration file:
+#
+# HWADDR=macaddr
+# DEVICE=interface name
+# BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
+#                       or "none" if no boot-time protocol should be used)
+#
+# IPADDR0=ipaddr1
+# IPADDR1=ipaddr2
+# IPADDRx=ipaddry (where y = x + 1)
+#
+# NETMASK0=netmask1
+# NETMASKx=netmasky (where y = x + 1)
+#
+# GATEWAY=ipaddr1
+# GATEWAYx=ipaddry (where y = x + 1)
+#
+# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
+#
+# IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
+# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
+# IPV6NETMASK.
+#
+
+kvp=dict(line.strip().split("=") for line in fileinput.input())
+
+# Setting the hwaddress to something azure is not expecting is fatal
+# to networking.
+if not "HWADDR" in kvp :
+    exit(errno.EPROTO)
+
+# Confirm we have a device specified.
+if not "DEVICE" in kvp :
+    exit(1)
+
+autolist = []
+output=[]
+basename=kvp["DEVICE"]
+
+# DNS entries will go with the first interface and there can be a max
+# of three.  These will be emitted with the first interface.
+dns = []
+for count in (1, 2, 3):
+    key = "DNS" + str(count)
+    if key in kvp:
+        dns += [kvp[key]]
+dns_emitted = False
+
+# IPV4 may either be dhcp or static.
+if ("DHCP" in kvp and kvp["DHCP"] == "yes") or \
+   ("BOOTPROTO" in kvp and kvp["BOOTPROTO"] == "dhcp"):
+    autolist.append(basename)
+    output += ["iface " + basename  + " inet dhcp"]
+    output += [""]
+else:
+    # Matchup the interface specific lines
+
+    # No real max for the number of interface + aliases ...
+    # only required is the address (but mate everything up that comes in.
+
+    # IPv4 -- ensure we sort by numeric suffixes.
+    v4names = [ int(name[6:]) for name in kvp.keys() if name.startswith("IPADDR") ]
+    v4names.sort()
+
+    for if_count in v4names:
+        ifname = basename
+        which = str(if_count)
+
+        if if_count:
+            ifname += ":" + str(if_count)
+            which_gw = which
+        else:
+            which_gw = ""
+
+        if not ifname in autolist:
+            autolist += [ifname]
+
+        output += [ "iface " + ifname + " inet static" ]
+        output += [ "\t" + "address " + kvp["IPADDR" + which] ]
+        if "NETMASK" + which in kvp:
+            output += [ "\tnetmask " + kvp["NETMASK" + which] ]
+        if "GATEWAY" + which_gw in kvp:
+            output += ["\tgateway " + kvp["GATEWAY" + which_gw]]
+
+        if not dns_emitted:
+            dns_emitted = True
+            output += ["\tdns-nameservers " + ' '.join(dns)]
+        output += [""]
+
+# IPv6 requires a netmask
+# If an ipv6 exists, you'll want to turn off /proc/sys/net/ipv6/conf/all/autoconf with
+# echo 0 > /proc/sys/net/ipv6/conf/all/autoconf
+v6names = [ int(name[8:]) for name in kvp.keys() if name.startswith("IPV6ADDR") ]
+v6names.sort()
+
+for if6_count in v6names:
+    ifname = basename
+    which = str(if6_count)
+
+    if if6_count:
+        ifname += ":" + str(if6_count)
+        which_gw = which
+    else:
+        which_gw = ""
+
+    if not ifname in autolist:
+        autolist += [ifname]
+
+    if "IPV6NETMASK" + which in kvp:
+        output += [ "iface " + ifname + " inet6 static"]
+        output += [ "\taddress " + kvp["IPV6ADDR" + which]]
+        output += [ "\tnetmask " + kvp["IPV6NETMASK" + which]]
+        if "IPV6_DEFAULTGW" + which_gw in kvp:
+            output += [ "\tgateway " + kvp["IPV6_DEFAULTGW" + which_gw] ]
+        if not dns_emitted:
+            dns_emitted = True
+            output += ["\tdns-nameservers " + ' '.join(dns)]
+        output += [""]
+
+# Mark this new interface for automatic up.
+if len(autolist):
+    output = ["auto "+" ".join(autolist)] + output
+
+print("===================================")
+print(output)
+print("===================================")
+
+
+# Time to clean out the existing interface file
+
+# Markers.
+start_mark = "# The following stanza(s) added by hv_set_ifconfig"
+end_mark = "#End of hv_set_ifconfig stanzas"
+
+f=open(if_filename,"r")
+flines=f.readlines()
+f.close()
+newfile=[]
+pitchstanza=0
+inastanza=0
+stanza=[]
+prev_line=None
+for line in flines:
+    if line.startswith("auto"):
+        if inastanza:
+            if not pitchstanza:
+                newfile.extend(stanza)
+            stanza=[]
+        inastanza=0
+        newline=""
+        autoline=line.strip().split(" ")
+        for word in autoline:
+            if (not word == basename) and (not word.startswith(basename+":")):
+                newline+=word + " "
+        newline = newline.strip()
+        if not newline == "auto":
+            newfile += [newline.strip()]
+    elif line.startswith(("iface","mapping","source")):
+        '''Read a stanza'''
+        '''A Stanza can also start with allow- ie allow-hotplug'''
+        if inastanza:
+            if not pitchstanza:
+                newfile.extend(stanza)
+            stanza=[]
+        inastanza=1
+        pitchstanza=0
+        autoline=line.strip().split(" ")
+        for word in autoline:
+            if (word == basename) or (word.startswith(basename+":")):
+                pitchstanza=1
+        if not pitchstanza:
+            stanza+=[line.strip()]
+    elif line.strip() in (start_mark, end_mark):
+        if inastanza:
+            if not pitchstanza:
+                newfile.extend(stanza)
+            stanza=[]
+        inastanza = 0
+        pitchstanza = 0
+        # Deduplicate markers.
+        if line != prev_line:
+            newfile += [line.strip()]
+    else:
+        if inastanza:
+            if not pitchstanza:
+                stanza+=[line.strip()]
+        else:
+            if not pitchstanza:
+                newfile += [line.strip()]
+    prev_line=line
+
+# Include pending stanza if any.
+if inastanza and not pitchstanza:
+    newfile.extend(stanza)
+
+
+def emit(line):
+    print(line)
+    output = line + "\n"
+    os.write(fd, output.encode('utf-8'))
+
+# Insert the new output at the end and inside the existing markers if found.
+emitted = False
+fd, path = tempfile.mkstemp()
+for line in newfile:
+    if line == end_mark:
+        emit("\n".join(output))
+        emitted = True
+    emit(line)
+if not emitted:
+    emit(start_mark)
+    emit("\n".join(output))
+    emit(end_mark)
+os.close(fd)
+
+shutil.copy(path,if_filename)
+os.chmod(if_filename,0o644)
+
+#print("TMPFILE is at: " + path)
+#print("Copied file is at: " + if_filename)
+
+try:
+    retcode = subprocess.call("ifdown "+basename , shell=True)
+    if retcode < 0:
+        print("Child was terminated by signal", -retcode, file=sys.stderr)
+    else:
+        print("Child returned", retcode, file=sys.stderr)
+except OSError as e:
+    print("Execution failed:", e, file=sys.stderr)
+
+try:
+    retcode = subprocess.call("ifup "+basename , shell=True)
+    if retcode < 0:
+        print("Child was terminated by signal", -retcode, file=sys.stderr)
+    else:
+        print("Child returned", retcode, file=sys.stderr)
+except OSError as e:
+    print("Execution failed:", e, file=sys.stderr)
--- linux-4.4.0.orig/debian/commit-templates/bumpabi
+++ linux-4.4.0/debian/commit-templates/bumpabi
@@ -0,0 +1,3 @@
+UBUNTU: Bump ABI
+
+Ignore: yes
--- linux-4.4.0.orig/debian/commit-templates/config-updates
+++ linux-4.4.0/debian/commit-templates/config-updates
@@ -0,0 +1,15 @@
+#
+# This template is used for commit messages that don't need to
+# show up in debian/changelog. Administrative stuff like config
+# updates, ABI bumps, etc. Setting 'Ignore: yes' prevents
+# 'debian/rules insertchanges' from inserting this commit meesage
+# as a changelog entry.
+#
+# Please give a one-line description of the config change followed
+# by a detailed explanation if necessary
+
+UBUNTU: [Config] XXXX
+
+# BugLink: http://bugs.launchpad.net/bugs/<enter bug# here>
+# Ignore: yes
+# Other text below here.
--- linux-4.4.0.orig/debian/commit-templates/external-driver
+++ linux-4.4.0/debian/commit-templates/external-driver
@@ -0,0 +1,20 @@
+# Ubuntu external driver commit.
+#
+# NOTE: This gets reformatted for README.Ubuntu-External-Drivers and
+# debian/changelog.
+#
+# This is only needed when a driver is added, updated or removed. It is
+# not needed when patches or fixes are applied to the driver. If the
+# driver is being removed, add the line:
+#
+# Removing: yes
+#
+# to the commit, and you can remove all other tags (except UBUNTU:).
+#
+UBUNTU: 
+
+ExternalDriver: 
+Description:
+Url:
+Mask:
+Version:
--- linux-4.4.0.orig/debian/commit-templates/missing-modules
+++ linux-4.4.0/debian/commit-templates/missing-modules
@@ -0,0 +1,3 @@
+UBUNTU: build/modules: Add modules that have intentionally gone missing
+
+Ignore: yes
--- linux-4.4.0.orig/debian/commit-templates/newrelease
+++ linux-4.4.0/debian/commit-templates/newrelease
@@ -0,0 +1,3 @@
+UBUNTU: Start new release
+
+Ignore: yes
--- linux-4.4.0.orig/debian/commit-templates/sauce-patch
+++ linux-4.4.0/debian/commit-templates/sauce-patch
@@ -0,0 +1,40 @@
+# Ubuntu commit template.
+#
+# NOTE: This gets reformatted for debian/changelog
+#
+#
+# SAUCE refers to the fact that this patch might not go upstream, but we need to
+# carry it to successive releases. In most cases you DONOT want to use this
+# template. 
+#
+# An example of a SAUCE patch is the ACPI DSDT-in-initramfs patch which has been
+# refused upstream, but still provides useful functionality to users with broken
+# BIOSes.
+#
+#-------------------------------------------------------------------------
+#
+# The initial UBUNTU is a flag that this is an Ubuntu commit. It will be
+# referenced to the Author in the debian/changelog entry.
+#
+# The text following is the short message that will be placed in the
+# changelog. Extra text on the following lines will be ignored, but left
+# in the git commit. Lines with # will be ignored in the commit.
+#
+# OriginalAuthor allows for alternate attribution.
+#
+# OriginalLocation allows for a URL or description of where the patch came
+# from.
+#
+# BugLink is a URL to a Malone bug.
+#
+# Ignore: yes will keep this commit from showing up in the changelog.
+#
+UBUNTU: SAUCE: 
+
+<Why is this patch not going upstream?>
+
+# OriginalAuthor: 
+# OriginalLocation: 
+# BugLink: http://bugs.launchpad.net/bugs/<enter bug# here>
+# Ignore: yes
+# Other text below here.
--- linux-4.4.0.orig/debian/commit-templates/upstream-patch
+++ linux-4.4.0/debian/commit-templates/upstream-patch
@@ -0,0 +1,27 @@
+# Ubuntu commit template.
+#
+# NOTE: This gets reformatted for debian/changelog
+#
+# The initial UBUNTU is a flag that this is an Ubuntu commit. It will be
+# referenced to the Author in the debian/changelog entry.
+#
+# The text following is the short message that will be placed in the
+# changelog. Extra text on the following lines will be ignored, but left
+# in the git commit. Lines with # will be ignored in the commit.
+#
+# OriginalAuthor allows for alternate attribution.
+#
+# OriginalLocation allows for a URL or description of where the patch came
+# from.
+#
+# BugLink is a URL to a Malone bug.
+#
+# Ignore: yes will keep this commit from showing up in the changelog.
+#
+UBUNTU: [Upstream]
+
+# OriginalAuthor: 
+# OriginalLocation: 
+# BugLink: http://bugs.launchpad.net/bugs/<enter bug# here>
+# Ignore: yes
+# Other text below here.
--- linux-4.4.0.orig/debian/compat
+++ linux-4.4.0/debian/compat
@@ -0,0 +1 @@
+9
--- linux-4.4.0.orig/debian/control
+++ linux-4.4.0/debian/control
@@ -0,0 +1,473 @@
+Source: linux
+Section: devel
+Priority: optional
+Maintainer: Ubuntu Kernel Team <kernel-team@lists.ubuntu.com>
+Standards-Version: 3.9.4.0
+Build-Depends:
+ debhelper (>= 9),
+ dh-systemd,
+ cpio,
+ kernel-wedge,
+ kmod <!stage1>,
+ makedumpfile [amd64 i386] <!stage1>,
+ libelf-dev <!stage1>,
+ libnewt-dev <!stage1>,
+ libiberty-dev <!stage1>,
+ rsync <!stage1>,
+ libdw-dev <!stage1>,
+ libpci-dev <!stage1>,
+ pkg-config <!stage1>,
+ flex <!stage1>,
+ bison <!stage1>,
+ libunwind8-dev [amd64 arm64 armhf i386 powerpc ppc64el] <!stage1>,
+ binutils-dev <!stage1>,
+ liblzma-dev <!stage1>,
+ openssl <!stage1>,
+ libssl-dev <!stage1>,
+ libaudit-dev <!stage1>,
+ bc <!stage1>,
+ python-dev <!stage1>,
+ gawk <!stage1>,
+ device-tree-compiler [powerpc] <!stage1>,
+ u-boot-tools [powerpc] <!stage1>,
+ libc6-dev-ppc64 [powerpc] <!stage1>,
+ libudev-dev <!stage1>,
+ autoconf <!stage1>,
+ automake <!stage1>,
+ libtool <!stage1>,
+ uuid-dev <!stage1>,
+ dkms <!stage1>,
+ curl <!stage1>,
+Build-Depends-Indep:
+ xmlto <!stage1>,
+ docbook-utils <!stage1>,
+ ghostscript <!stage1>,
+ transfig <!stage1>,
+ bzip2 <!stage1>,
+ sharutils <!stage1>,
+ asciidoc <!stage1>,
+Vcs-Git: git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/xenial
+XS-Testsuite: autopkgtest
+#XS-Testsuite-Depends: gcc-4.7 binutils
+
+Package: linux-source-4.4.0
+Build-Profiles: <!stage1>
+Architecture: all
+Section: devel
+Priority: optional
+Provides: linux-source, linux-source-3
+Depends: ${misc:Depends}, binutils, bzip2, coreutils
+Recommends: libc-dev, gcc, make
+Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-dev
+Description: Linux kernel source for version 4.4.0 with Ubuntu patches
+ This package provides the source code for the Linux kernel version
+ 4.4.0.
+ .
+ This package is mainly meant for other packages to use, in order to build
+ custom flavours.
+ .
+ If you wish to use this package to create a custom Linux kernel, then it
+ is suggested that you investigate the package kernel-package, which has
+ been designed to ease the task of creating kernel image packages.
+ .
+ If you are simply trying to build third-party modules for your kernel,
+ you do not want this package. Install the appropriate linux-headers
+ package instead.
+
+Package: linux-doc
+Build-Profiles: <!stage1>
+Architecture: all
+Section: doc
+Priority: optional
+Depends: ${misc:Depends}
+Description: Linux kernel specific documentation for version 4.4.0
+ This package provides the various documents in the 4.4.0 kernel
+ Documentation/ subdirectory.  These document kernel subsystems, APIs, device
+ drivers, and so on.  See
+ /usr/share/doc/linux-doc/00-INDEX for a list of what is
+ contained in each file.
+
+Package: linux-headers-4.4.0-279
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, coreutils
+Breaks: iscsitarget-dkms (<< 1.4.20.3+svn502-2ubuntu4.3)
+Description: Header files related to Linux kernel version 4.4.0
+ This package provides kernel header files for version 4.4.0, for sites
+ that want the latest kernel headers. Please read
+ /usr/share/doc/linux-headers-4.4.0-279/debian.README.gz for details
+
+Package: linux-libc-dev
+Architecture: amd64 arm64 s390x
+Depends: ${misc:Depends}
+Conflicts: linux-kernel-headers
+Replaces: linux-kernel-headers
+Provides: linux-kernel-headers
+Multi-Arch: same
+Description: Linux Kernel Headers for development
+ This package provides headers from the Linux kernel.  These headers
+ are used by the installed headers for GNU glibc and other system
+ libraries. They are NOT meant to be used to build third-party modules for
+ your kernel. Use linux-headers-* packages for that.
+
+Package: linux-tools-common
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: kernel
+Priority: optional
+Provides:
+ linux-aws-tools-common,
+ linux-gke-tools-common,
+Conflicts:
+ linux-aws-tools-common,
+ linux-gke-tools-common,
+Replaces:
+ linux-aws-tools-common,
+ linux-gke-tools-common,
+Depends: ${misc:Depends}, lsb-release
+Description: Linux kernel version specific tools for version 4.4.0
+ This package provides the architecture independent parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version 4.4.0.
+
+Package: linux-tools-4.4.0-279
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-tools-common
+Description: Linux kernel version specific tools for version 4.4.0-279
+ This package provides the architecture dependant parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version 4.4.0-279 on
+ 64 bit x86.
+ You probably want to install linux-tools-4.4.0-279-<flavour>.
+
+Package: linux-cloud-tools-common
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: kernel
+Priority: optional
+Provides:
+ linux-aws-cloud-tools-common,
+ linux-gke-cloud-tools-common,
+Conflicts:
+ linux-aws-cloud-tools-common,
+ linux-gke-cloud-tools-common,
+Replaces:
+ linux-aws-cloud-tools-common,
+ linux-gke-cloud-tools-common,
+Depends: ${misc:Depends}
+Description: Linux kernel version specific cloud tools for version 4.4.0
+ This package provides the architecture independent parts for kernel
+ version locked tools for cloud tools for version 4.4.0.
+
+Package: linux-cloud-tools-4.4.0-279
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-cloud-tools-common
+Description: Linux kernel version specific cloud tools for version 4.4.0-279
+ This package provides the architecture dependant parts for kernel
+ version locked tools for cloud tools for version 4.4.0-279 on
+ 64 bit x86.
+ You probably want to install linux-cloud-tools-4.4.0-279-<flavour>.
+
+Package: linux-tools-host
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, python3
+Description: Linux kernel VM host tools
+ This package provides kernel tools useful for VM hosts.
+
+
+Package: linux-image-unsigned-4.4.0-279-generic
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: kernel
+Priority: optional
+Provides: linux-image, fuse-module, kvm-api-4, redhat-cluster-modules, ivtv-modules, virtualbox-guest-modules [i386 amd64 x32]${linux:rprovides}
+Depends: ${misc:Depends}, ${shlibs:Depends}, kmod, linux-base (>= 4.5ubuntu1~16.04.1), linux-modules-4.4.0-279-generic
+Recommends: grub-pc [i386 amd64 x32] | grub-efi-amd64 [amd64 x32] | grub-efi-ia32 [i386 amd64 x32] | grub [i386 amd64 x32] | lilo [i386 amd64 x32] | flash-kernel [armhf arm64] | grub-ieee1275 [ppc64el], initramfs-tools | linux-initramfs-tool
+Conflicts: linux-image-4.4.0-279-generic
+Suggests: fdutils, linux-doc-4.4.0 | linux-source-4.4.0, linux-tools, linux-headers-4.4.0-279-generic
+Description: Linux kernel image for version 4.4.0 on 64 bit x86 SMP
+ This package contains the unsigned Linux kernel image for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ Supports Generic processors.
+ .
+ Geared toward desktop and server systems.
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-generic meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-modules-4.4.0-279-generic
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Description: Linux kernel extra modules for version 4.4.0 on 64 bit x86 SMP
+ Contains the corresponding System.map file, the modules built by the
+ packager, and scripts that try to ensure that the system is not left in an
+ unbootable state after an update.
+ .
+ Supports Generic processors.
+ .
+ Geared toward desktop and server systems.
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-generic meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-modules-extra-4.4.0-279-generic
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-4.4.0-279-generic | linux-image-unsigned-4.4.0-279-generic, crda | wireless-crda
+Description: Linux kernel extra modules for version 4.4.0 on 64 bit x86 SMP
+ This package contains the Linux kernel extra modules for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ Also includes the corresponding System.map file, the modules built by the
+ packager, and scripts that try to ensure that the system is not left in an
+ unbootable state after an update.
+ .
+ Supports Generic processors.
+ .
+ Geared toward desktop and server systems.
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-generic meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-headers-4.4.0-279-generic
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, linux-headers-4.4.0-279, ${shlibs:Depends}
+Provides: linux-headers, linux-headers-3.0
+Description: Linux kernel headers for version 4.4.0 on 64 bit x86 SMP
+ This package provides kernel header files for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ This is for sites that want the latest kernel headers.  Please read
+ /usr/share/doc/linux-headers-4.4.0-279/debian.README.gz for details.
+
+Package: linux-image-unsigned-4.4.0-279-generic-dbgsym
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}
+Provides: linux-debug
+Description: Linux kernel debug image for version 4.4.0 on 64 bit x86 SMP
+ This package provides the unsigned kernel debug image for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ This is for sites that wish to debug the kernel.
+ .
+ The kernel image contained in this package is NOT meant to boot from. It
+ is uncompressed, and unstripped. This package also includes the
+ unstripped modules.
+
+Package: linux-tools-4.4.0-279-generic
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, linux-tools-4.4.0-279
+Description: Linux kernel version specific tools for version 4.4.0-279
+ This package provides the architecture dependant parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version 4.4.0-279 on
+ 64 bit x86.
+
+Package: linux-cloud-tools-4.4.0-279-generic
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, linux-cloud-tools-4.4.0-279
+Description: Linux kernel version specific cloud tools for version 4.4.0-279
+ This package provides the architecture dependant parts for kernel
+ version locked tools for cloud for version 4.4.0-279 on
+ 64 bit x86.
+
+Package: linux-udebs-generic
+Build-Profiles: <!stage1>
+XC-Package-Type: udeb
+Section: debian-installer
+Architecture: amd64 arm64 s390x
+Depends: ${udeb:Depends}
+Description: Metapackage depending on kernel udebs
+ This package depends on the all udebs that the kernel build generated,
+ for easier version and migration tracking.
+
+
+Package: linux-buildinfo-4.4.0-279-generic
+Build-Profiles: <!stage1>
+Architecture: amd64 arm64 s390x
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Built-Using: ${linux:BuiltUsing}
+Description: Linux kernel buildinfo for version 4.4.0 on 64 bit x86 SMP
+ This package contains the Linux kernel buildinfo for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ You likely do not want to install this package.
+
+Package: linux-image-unsigned-4.4.0-279-lowlatency
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: kernel
+Priority: optional
+Provides: linux-image, fuse-module, kvm-api-4, redhat-cluster-modules, ivtv-modules, virtualbox-guest-modules [i386 amd64 x32]${linux:rprovides}
+Depends: ${misc:Depends}, ${shlibs:Depends}, kmod, linux-base (>= 4.5ubuntu1~16.04.1), linux-modules-4.4.0-279-lowlatency
+Recommends: grub-pc [i386 amd64 x32] | grub-efi-amd64 [amd64 x32] | grub-efi-ia32 [i386 amd64 x32] | grub [i386 amd64 x32] | lilo [i386 amd64 x32] | flash-kernel [armhf arm64], initramfs-tools | linux-initramfs-tool
+Conflicts: linux-image-4.4.0-279-lowlatency
+Suggests: fdutils, linux-doc-4.4.0 | linux-source-4.4.0, linux-tools, linux-headers-4.4.0-279-lowlatency
+Description: Linux kernel image for version 4.4.0 on 64 bit x86 SMP
+ This package contains the unsigned Linux kernel image for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ Supports Lowlatency processors.
+ .
+ Geared toward desktop and server systems.
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-lowlatency meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-modules-4.4.0-279-lowlatency
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Description: Linux kernel extra modules for version 4.4.0 on 64 bit x86 SMP
+ Contains the corresponding System.map file, the modules built by the
+ packager, and scripts that try to ensure that the system is not left in an
+ unbootable state after an update.
+ .
+ Supports Lowlatency processors.
+ .
+ Geared toward desktop and server systems.
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-lowlatency meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-modules-extra-4.4.0-279-lowlatency
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-4.4.0-279-lowlatency | linux-image-unsigned-4.4.0-279-lowlatency, crda | wireless-crda
+Description: Linux kernel extra modules for version 4.4.0 on 64 bit x86 SMP
+ This package contains the Linux kernel extra modules for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ Also includes the corresponding System.map file, the modules built by the
+ packager, and scripts that try to ensure that the system is not left in an
+ unbootable state after an update.
+ .
+ Supports Lowlatency processors.
+ .
+ Geared toward desktop and server systems.
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-lowlatency meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-headers-4.4.0-279-lowlatency
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, linux-headers-4.4.0-279, ${shlibs:Depends}
+Provides: linux-headers, linux-headers-3.0
+Description: Linux kernel headers for version 4.4.0 on 64 bit x86 SMP
+ This package provides kernel header files for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ This is for sites that want the latest kernel headers.  Please read
+ /usr/share/doc/linux-headers-4.4.0-279/debian.README.gz for details.
+
+Package: linux-image-unsigned-4.4.0-279-lowlatency-dbgsym
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}
+Provides: linux-debug
+Description: Linux kernel debug image for version 4.4.0 on 64 bit x86 SMP
+ This package provides the unsigned kernel debug image for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ This is for sites that wish to debug the kernel.
+ .
+ The kernel image contained in this package is NOT meant to boot from. It
+ is uncompressed, and unstripped. This package also includes the
+ unstripped modules.
+
+Package: linux-tools-4.4.0-279-lowlatency
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, linux-tools-4.4.0-279
+Description: Linux kernel version specific tools for version 4.4.0-279
+ This package provides the architecture dependant parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version 4.4.0-279 on
+ 64 bit x86.
+
+Package: linux-cloud-tools-4.4.0-279-lowlatency
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, linux-cloud-tools-4.4.0-279
+Description: Linux kernel version specific cloud tools for version 4.4.0-279
+ This package provides the architecture dependant parts for kernel
+ version locked tools for cloud for version 4.4.0-279 on
+ 64 bit x86.
+
+Package: linux-udebs-lowlatency
+Build-Profiles: <!stage1>
+XC-Package-Type: udeb
+Section: debian-installer
+Architecture: amd64
+Depends: ${udeb:Depends}
+Description: Metapackage depending on kernel udebs
+ This package depends on the all udebs that the kernel build generated,
+ for easier version and migration tracking.
+
+
+Package: linux-buildinfo-4.4.0-279-lowlatency
+Build-Profiles: <!stage1>
+Architecture: amd64
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Built-Using: ${linux:BuiltUsing}
+Description: Linux kernel buildinfo for version 4.4.0 on 64 bit x86 SMP
+ This package contains the Linux kernel buildinfo for version 4.4.0 on
+ 64 bit x86 SMP.
+ .
+ You likely do not want to install this package.
--- linux-4.4.0.orig/debian/control.d/flavour-buildinfo.stub
+++ linux-4.4.0/debian/control.d/flavour-buildinfo.stub
@@ -0,0 +1,13 @@
+
+Package: linux-buildinfo-PKGVER-ABINUM-FLAVOUR
+Build-Profiles: <!stage1>
+Architecture: ARCH
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Built-Using: ${linux:BuiltUsing}
+Description: Linux kernel buildinfo for version PKGVER on DESC
+ This package contains the Linux kernel buildinfo for version PKGVER on
+ DESC.
+ .
+ You likely do not want to install this package.
--- linux-4.4.0.orig/debian/copyright
+++ linux-4.4.0/debian/copyright
@@ -0,0 +1,60 @@
+This is the Ubuntu prepackaged version of the Linux kernel.
+Linux was written by Linus Torvalds <Linus.Torvalds@cs.Helsinki.FI>
+and others.
+
+This package was put together by the Ubuntu Kernel Team, from
+sources retrieved from upstream linux git.
+The sources may be found at most Linux ftp sites, including 
+ftp://ftp.kernel.org/pub/linux/kernel/
+
+This package is currently maintained by the
+Ubuntu Kernel Team <ubuntu-kernel@lists.ubuntu.com>
+
+Linux is copyrighted by Linus Torvalds and others.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 dated June, 1991.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You 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
+
+On Ubuntu Linux systems, the complete text of the GNU General
+Public License v2 can be found in `/usr/share/common-licenses/GPL-2'.
+
+Files: ubuntu/rsi/*
+Copyright (c) 2017 Redpine Signals Inc. All rights reserved.
+License: redpine-signals
+   Copyright (c) 2017 Redpine Signals Inc. All rights reserved.
+   
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+   
+   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.
+   
+   3. Neither the name of the copyright holder 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 HOLDER 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.
--- linux-4.4.0.orig/debian/debian.env
+++ linux-4.4.0/debian/debian.env
@@ -0,0 +1 @@
+DEBIAN=debian.master
--- linux-4.4.0.orig/debian/docs/README.inclusion-list
+++ linux-4.4.0/debian/docs/README.inclusion-list
@@ -0,0 +1,51 @@
+This README describes the reason for, and the use of, module
+inclusion lists.
+
+The original Hardy release had the notion of sub-flavours,
+e.g., a flavour that was constructed as a subset of an existing flavour.
+For example, the virtual flavour was extracted from the server flavour using
+a subset of the server flavour modules. However, there were some difficult
+mainteneance issues with regard to packaging, make rules, and scripts. This
+re-implementation of the sub-flavours philosophy is hopefully simpler,
+and retrofitable to all releases.
+
+A module inclusion list looks at the problem of of constructing a package
+from the perspective of what modules do we _want_ in the package, as opposed
+to what modules we _don't_ want. As the kernel matures, more and more devices are added
+which makes the problem of configuration maintenance a real pain in the ass.
+If we took the approach of disabling all of the config options that we don't want,
+then the differences between flavours will quickly become quite large, making
+it difficult to quickly compare the individual flavour configs.  Each time a
+new config option is added then we also have to make a decision about disabling in
+order to continue to keep the minimal number of modules.
+
+A module inclusion list is applied on a per-flavour basis. For example,
+debian.<BRANCH>/control.d/${flavour}.inclusion-list. For example, the
+config for virtual is very close to server and generic, but the inclusion list
+causes the virtual package to be constructed with _only_ the modules described 
+in the inclusion list.
+
+The inclusion list format is a simple bash regular expression list of files. For example,
+
+arch/*/{crypto,kernel,oprofile}
+drivers/acpi/*
+drivers/ata/ahci.ko
+
+These 3 regular expression forms are suitable for expansion by bash and as inputs to 'find'.
+See debian/scripts/module-inclusion for details.
+
+There are 2 log files created as a side effect of the application of the module
+inclusion list; $(flavour).inclusion-list.log and $(flavour).depmod.log.
+
+$(flavour).inclusion-list.log : This log is created while the inclusion list
+modules are being copied. If any are missing, then those warnings go in this log.
+While its not considered a fatal error, you should endevour to correct your inclusion
+list such that there are no missing modules.
+
+$(flavour).depmod.log : The log is created as a result of running depmod on the
+resulting set of modules. If there are missing symbols then you'll find that information
+here. Again, you should modify your inclusion list such that there are no missing
+symbols.
+
+Tim Gardner <tim.gardner@canonical.com>
+June 2, 2010
--- linux-4.4.0.orig/debian/gbp.conf
+++ linux-4.4.0/debian/gbp.conf
@@ -0,0 +1,2 @@
+[buildpackage]
+debian-tag = Ubuntu-%(version)s
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-fcopy-daemon.service
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-fcopy-daemon.service
@@ -0,0 +1,14 @@
+# On Azure/Hyper-V systems start the hv_fcopy_daemon
+#
+# author "Andy Whitcroft <apw@canonical.com>"
+[Unit]
+Description=Hyper-V File Copy Protocol Daemon
+ConditionVirtualization=microsoft
+ConditionPathExists=/dev/vmbus/hv_fcopy
+BindsTo=sys-devices-virtual-misc-vmbus\x21hv_fcopy.device
+
+[Service]
+ExecStart=/usr/sbin/hv_fcopy_daemon -n
+
+[Install]
+WantedBy=multi-user.target
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-fcopy-daemon.udev
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-fcopy-daemon.udev
@@ -0,0 +1 @@
+SUBSYSTEM=="misc", KERNEL=="vmbus/hv_fcopy", TAG+="systemd", ENV{SYSTEMD_WANTS}+="hv-fcopy-daemon.service"
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-fcopy-daemon.upstart
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-fcopy-daemon.upstart
@@ -0,0 +1,22 @@
+# On Azure/Hyper-V systems start the hv_fcopy_daemon
+#
+description "Hyper-V File Copy Protocol Daemon"
+author "Andy Whitcroft <apw@canonical.com>"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+console log
+
+pre-start script
+        if [ -e "/etc/default/hv-kvp-daemon-init" ]; then
+                . /etc/default/hv-kvp-daemon-init
+        fi
+        [ "$RUN_FCOPY_DAEMON" -eq 0 ] && { stop; exit 0; }
+	if [ -d /sys/class/dmi/id/. ]; then
+		read company </sys/class/dmi/id/sys_vendor
+		read product </sys/class/dmi/id/product_name
+		[ "$company:$product" = 'Microsoft Corporation:Virtual Machine' ] || { stop; exit 0; }
+	fi
+end script
+
+exec /usr/sbin/hv_fcopy_daemon -n
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-kvp-daemon.service
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-kvp-daemon.service
@@ -0,0 +1,18 @@
+# On Azure/Hyper-V systems start the hv_kvp_daemon
+#
+# author "Andy Whitcroft <apw@canonical.com>"
+[Unit]
+Description=Hyper-V KVP Protocol Daemon
+ConditionVirtualization=microsoft
+DefaultDependencies=no
+BindsTo=sys-devices-virtual-misc-vmbus\x21hv_kvp.device
+After=sys-devices-virtual-misc-vmbus\x21hv_kvp.device systemd-remount-fs.service
+Before=shutdown.target cloud-init-local.service walinuxagent.service
+Conflicts=shutdown.target
+RequiresMountsFor=/var/lib/hyperv
+
+[Service]
+ExecStart=/usr/sbin/hv_kvp_daemon -n
+
+[Install]
+WantedBy=multi-user.target
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-kvp-daemon.udev
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-kvp-daemon.udev
@@ -0,0 +1 @@
+SUBSYSTEM=="misc", KERNEL=="vmbus/hv_kvp", TAG+="systemd", ENV{SYSTEMD_WANTS}+="hv-kvp-daemon.service"
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-kvp-daemon.upstart
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-kvp-daemon.upstart
@@ -0,0 +1,22 @@
+# On Azure/Hyper-V systems start the hv_kvp_daemon
+#
+description "Hyper-V KVP Protocol Daemon"
+author "Adam Conrad <adconrad@canonical.com>"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+console log
+
+pre-start script
+        if [ -e "/etc/default/hv-kvp-daemon-init" ]; then
+                . /etc/default/hv-kvp-daemon-init
+        fi
+        [ "$RUN_KVP_DAEMON" = 0 ] && { stop; exit 0; }
+	if [ -d /sys/class/dmi/id/. ]; then
+		read company </sys/class/dmi/id/sys_vendor
+		read product </sys/class/dmi/id/product_name
+		[ "$company:$product" = 'Microsoft Corporation:Virtual Machine' ] || { stop; exit 0; }
+	fi
+end script
+
+exec /usr/sbin/hv_kvp_daemon -n
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-vss-daemon.service
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-vss-daemon.service
@@ -0,0 +1,14 @@
+# On Azure/Hyper-V systems start the hv_vss_daemon
+#
+# author "Andy Whitcroft <apw@canonical.com>"
+[Unit]
+Description=Hyper-V VSS Protocol Daemon
+ConditionVirtualization=microsoft
+ConditionPathExists=/dev/vmbus/hv_vss
+BindsTo=sys-devices-virtual-misc-vmbus\x21hv_vss.device
+
+[Service]
+ExecStart=/usr/sbin/hv_vss_daemon -n
+
+[Install]
+WantedBy=multi-user.target
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-vss-daemon.udev
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-vss-daemon.udev
@@ -0,0 +1 @@
+SUBSYSTEM=="misc", KERNEL=="vmbus/hv_vss", TAG+="systemd", ENV{SYSTEMD_WANTS}+="hv-vss-daemon.service"
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.hv-vss-daemon.upstart
+++ linux-4.4.0/debian/linux-cloud-tools-common.hv-vss-daemon.upstart
@@ -0,0 +1,22 @@
+# On Azure/Hyper-V systems start the hv_vss_daemon
+#
+description "Hyper-V VSS Protocol Daemon"
+author "Ben Howard <ben.howard@canonical.com>"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+console log
+
+pre-start script
+        if [ -e "/etc/default/hv-kvp-daemon-init" ]; then
+                . /etc/default/hv-kvp-daemon-init
+        fi
+        [ "$RUN_VSS_DAEMON" -eq 0 ] && { stop; exit 0; }
+	if [ -d /sys/class/dmi/id/. ]; then
+		read company </sys/class/dmi/id/sys_vendor
+		read product </sys/class/dmi/id/product_name
+		[ "$company:$product" = 'Microsoft Corporation:Virtual Machine' ] || { stop; exit 0; }
+	fi
+end script
+
+exec /usr/sbin/hv_vss_daemon -n
--- linux-4.4.0.orig/debian/linux-cloud-tools-common.intel-sgx-load-module.service
+++ linux-4.4.0/debian/linux-cloud-tools-common.intel-sgx-load-module.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Install SGX kernel module
+DefaultDependencies=false
+ConditionVirtualization=microsoft
+
+[Service]
+Type=oneshot
+RemainAfterExit=true
+ExecStart=/sbin/modprobe intel_sgx
+ExecStop=/sbin/modprobe -r intel_sgx
+
+[Install]
+WantedBy=multi-user.target
--- linux-4.4.0.orig/debian/rules
+++ linux-4.4.0/debian/rules
@@ -0,0 +1,315 @@
+#!/usr/bin/make -f
+#
+# $(DEBIAN)/rules for Ubuntu linux
+#
+# Use this however you want, just give credit where credit is due.
+#
+# Copyright (c) 2007 Ben Collins <bcollins@ubuntu.com>
+#
+
+DEBIAN=$(shell awk -F= '($$1 == "DEBIAN") { print $$2 }' <debian/debian.env)
+
+# dpkg-buildpackage passes options that are incomptatible
+# with the kernel build.
+unexport CFLAGS
+unexport LDFLAGS
+
+export LC_ALL=C
+export SHELL=/bin/bash -e
+
+# Where do we find the common configuration.
+export DROOT=debian
+
+# Common variables for all architectures
+include $(DROOT)/rules.d/0-common-vars.mk
+
+# Pull in some arch specific stuff
+-include $(DEBIAN)/rules.d/$(arch).mk
+
+# Pull in some branch specific stuff. Used by LTS backport
+# branches to override master branch settings such as do_tools_common.
+-include $(DEBIAN)/rules.d/hooks.mk
+
+# Maintainer targets
+include $(DROOT)/rules.d/1-maintainer.mk
+
+do_linux_tools=$(sort $(filter-out false,$(do_tools_usbip) $(do_tools_cpupower) $(do_tools_perf) $(do_tools_x86)))
+do_cloud_tools=$(sort $(filter-out false,$(do_tools_hyperv)))
+do_tools_common?=true
+do_tools_host?=false
+
+# Don't build tools or udebs in a cross compile environment.
+ifneq ($(DEB_HOST_ARCH),$(DEB_BUILD_ARCH))
+	do_tools=false
+	disable_d_i=true
+	do_zfs=false
+	do_dkms_wireguard=false
+endif
+
+# Are any of the kernel signing options enabled.
+any_signed=$(sort $(filter-out false,$(uefi_signed) $(fit_signed) $(opal_signed)))
+ifeq ($(any_signed),true)
+bin_pkg_name=$(bin_pkg_name_unsigned)
+else
+bin_pkg_name=$(bin_pkg_name_signed)
+endif
+
+# Stages -- support both DEB_STAGE=stage1 and DEB_BUILD_PROFILE=bootstrap
+ifeq ($(DEB_STAGE),stage1)
+    DEB_BUILD_PROFILES=stage1
+endif
+ifneq ($(DEB_BUILD_PROFILE),)
+    DEB_BUILD_PROFILES=$(DEB_BUILD_PROFILE)
+endif
+ifneq ($(filter stage1,$(DEB_BUILD_PROFILES)),)
+    do_tools=false
+    do_doc_package=false
+    do_source_package=false
+    do_flavour_image_package=false
+    do_flavour_header_package=false
+endif
+
+# Being used to build a mainline build -- turn off things which do not work.
+ifeq ($(do_mainline_build),true)
+	do_extras_package=false
+	do_tools=false
+	no_dumpfile=1
+	do_zfs=false
+	do_dkms_wireguard=false
+	skipabi=true
+	skipmodule=true
+	skipretpoline=true
+endif
+
+# Disable tools build and packaging if do_tools != true
+ifneq ($(do_tools),true)
+	do_linux_tools=
+	do_cloud_tools=
+	do_tools_common=
+	do_tools_host=
+endif
+
+# Either tools package needs the common source preparation
+do_any_tools=$(sort $(filter-out false,$(do_linux_tools) $(do_cloud_tools)))
+
+# autopkgtest -- rebuild support
+#  only build the first flavour on the assumption it is representative
+ifneq ($(filter autopkgtest,$(DEB_BUILD_PROFILES)),)
+flavours := $(firstword $(flavours))
+disable_d_i=true
+endif
+
+# Versions of dkms packages.
+dkms_wireguard_version=$(shell gawk '/^wireguard-linux-compat / { print $$2; }' $(DEBIAN)/dkms-versions)
+
+# Debian Build System targets
+binary: binary-indep binary-arch
+
+build: build-arch build-indep
+
+clean: debian/control
+	dh_testdir
+	dh_testroot
+	dh_clean
+
+	# d-i stuff
+	rm -rf $(DEBIAN)/d-i-$(arch)
+	# Generated on the fly.
+	rm -f $(DEBIAN)/d-i/firmware/kernel-image
+
+	# normal build junk
+	rm -rf $(DEBIAN)/abi
+	rm -rf $(builddir)
+	rm -f $(stampdir)/stamp-*
+	rm -rf $(DEBIAN)/linux-*
+
+	# This gets rid of the d-i packages in control
+	cp -f $(DEBIAN)/control.stub $(DROOT)/control
+	cp $(DEBIAN)/changelog debian/changelog
+
+	# Install the copyright information.
+	cp $(DEBIAN)/copyright debian/copyright
+
+	# Install the retpoline extractor.
+	cp $(DROOT)/scripts/retpoline-extract-one scripts/ubuntu-retpoline-extract-one
+
+	# If we have a reconstruct script use it.
+	[ -f $(DEBIAN)/reconstruct ] && bash $(DEBIAN)/reconstruct
+
+	# Remove generated intermediate files
+	rm -f $(DROOT)/control.stub $(DEBIAN)/control.stub \
+		$(DEBIAN)/d-i/kernel-versions
+	rm -f $(DROOT)/scripts/fix-filenames
+
+distclean: clean
+	rm -rf $(DROOT)/control debian/changelog \
+		debian/control debian/control.stub debian/copyright \
+		scripts/ubuntu-retpoline-extract-one
+
+# Builds the image, arch headers and debug packages
+include $(DROOT)/rules.d/2-binary-arch.mk
+
+# Rules for building the udebs ($(DEBIAN)-installer)
+include $(DROOT)/rules.d/5-udebs.mk
+
+# Builds the source, doc and linux-headers indep packages
+include $(DROOT)/rules.d/3-binary-indep.mk
+
+# Various checks to be performed on builds
+include $(DROOT)/rules.d/4-checks.mk
+
+# Misc stuff
+.PHONY: $(DEBIAN)/control.stub
+$(DEBIAN)/control.stub: $(DEBIAN)/d-i/kernel-versions.in	\
+		$(DROOT)/scripts/control-create		\
+		$(DEBIAN)/control.stub.in			\
+		$(DEBIAN)/changelog			\
+		$(wildcard $(DEBIAN)/control.d/* $(DEBIAN)/sub-flavours/*.vars)
+	for i in $(DEBIAN)/d-i/kernel-versions.in $(DEBIAN)/control.stub.in; do	\
+	  new=`echo $$i | sed 's/\.in$$//'`;					\
+	  cat $$i | sed -e 's/PKGVER/$(release)/g'                              \
+	        -e 's/ABINUM/$(abinum)/g'                                       \
+		-e 's/SRCPKGNAME/$(src_pkg_name)/g'                             \
+		-e 's/=HUMAN=/$(human_arch)/g'                                    \
+	  > $$new;								\
+	done
+	flavours="$(sort $(wildcard $(DEBIAN)/control.d/vars.* $(DEBIAN)/sub-flavours/*.vars))";\
+	for i in $$flavours; do							\
+	  $(SHELL) $(DROOT)/scripts/control-create $$i "$(any_signed)" |	\
+		sed -e 's/PKGVER/$(release)/g'                                  \
+		-e 's/ABINUM/$(abinum)/g'                                       \
+		-e 's/SRCPKGNAME/$(src_pkg_name)/g'                             \
+		-e 's/=HUMAN=/$(human_arch)/g'                                    \
+		>> $(DEBIAN)/control.stub;						\
+	done
+
+.PHONY: debian/control
+debian/control: $(DEBIAN)/control.stub
+	rm -rf $(builddir)/modules $(builddir)/firmware			\
+		$(builddir)/kernel-versions $(builddir)/package-list	\
+		$(builddir)/$(DEBIAN)
+	mkdir -p $(builddir)/modules/$(arch)/
+	cp $(DEBIAN)/d-i/modules/* $(builddir)/modules/$(arch)/
+	mkdir -p $(builddir)/firmware/$(arch)/
+	cp $(DEBIAN)/d-i/firmware/* $(builddir)/firmware/$(arch)/
+	cp $(DEBIAN)/d-i/package-list $(DEBIAN)/d-i/kernel-versions $(builddir)/
+	touch $(builddir)/modules/$(arch)/kernel-image
+	# kernel-wedge needs to poke around in $(DEBIAN)/
+	ln -nsf $(CURDIR)/debian $(builddir)/debian
+
+	# Some files may need to differ between architectures
+	if [ -d $(DEBIAN)/d-i/modules-$(arch) ]; then			\
+	    cp $(DEBIAN)/d-i/modules-$(arch)/* \
+		$(builddir)/modules/$(arch)/;				\
+	fi
+	if [ -d $(DEBIAN)/d-i/firmware-$(arch) ]; then			\
+	    cp $(DEBIAN)/d-i/firmware-$(arch)/* \
+		$(builddir)/firmware/$(arch)/;				\
+	fi
+
+	# Remove unwanted stuff for this architecture
+	if [ -r "$(DEBIAN)/d-i/exclude-modules.$(arch)" ]; then		\
+	    (cat $(DEBIAN)/d-i/exclude-modules.$(arch);			\
+	     ls $(builddir)/modules/$(arch)/) | sort | uniq -d |	\
+		(cd $(builddir)/modules/$(arch)/; xargs rm -f);		\
+	fi
+	if [ -r "$(DEBIAN)/d-i/exclude-firmware.$(arch)" ]; then		\
+	    (cat $(DEBIAN)/d-i/exclude-firmware.$(arch);			\
+	     ls $(builddir)/firmware/$(arch)/) | sort | uniq -d |	\
+		(cd $(builddir)/firmware/$(arch)/; xargs rm -f);	\
+	fi
+
+	# Per flavour module lists
+	flavour_modules=`ls $(DEBIAN)/d-i/modules.$(arch)-* 2>/dev/null`	\
+		|| true;						\
+	if [ "$$flavour_modules" != "" ]; then				\
+	    for flav in $$flavour_modules; do				\
+		name=`echo $$flav | sed 's/.*\/modules.$(arch)-//'`;	\
+		mkdir $(builddir)/modules/$(arch)-$$name;		\
+		(cd $(builddir)/modules/; tar cf - `cat ../$$flav`) |	\
+		    (cd $(builddir)/modules/$(arch)-$$name/; tar xf -);	\
+		touch $(builddir)/modules/$(arch)-$$name/kernel-image;	\
+	    done;							\
+	fi
+	flavour_firmware=`ls $(DEBIAN)/d-i/firmware.$(arch)-* 2>/dev/null`	\
+		|| true;						\
+	if [ "$$flavour_firmware" != "" ]; then				\
+	    for flav in $$flavour_firmware; do				\
+		name=`echo $$flav | sed 's/.*\/firmware.$(arch)-//'`;	\
+		mkdir $(builddir)/firmware/$(arch)-$$name;		\
+		(cd $(builddir)/firmware/; tar cf - `cat ../$$flav`) |	\
+		    (cd $(builddir)/firmware/$(arch)-$$name/; tar xf -);\
+		touch $(builddir)/firmware/$(arch)-$$name/kernel-image;	\
+	    done;							\
+	fi
+
+	# Some files may need to differ between flavours
+	flavour_module_dirs=`ls -d $(DEBIAN)/d-i/modules-$(arch)-* 2>/dev/null`\
+		|| true;						\
+	if [ "$$flavour_module_dirs" ]; then				\
+	    for flav in $$flavour_module_dirs; do			\
+		name=`echo $$flav | sed 's/.*\/modules-$(arch)-//'`;	\
+		[ -d $(builddir)/modules/$(arch)-$$name ] ||		\
+		    cp -a $(builddir)/modules/$(arch)			\
+			modules/$(arch)-$$name;				\
+		cp $$flav/* $(builddir)/modules/$(arch)-$$name/;	\
+	    done;							\
+	fi
+	flavour_firmware_dirs=`ls -d $(DEBIAN)/d-i/firmware-$(arch)-* 2>/dev/null`\
+		|| true;						\
+	if [ "$$flavour_firmware_dirs" ]; then				\
+	    for flav in $$flavour_firmware_dirs; do			\
+		name=`echo $$flav | sed 's/.*\/firmware-$(arch)-//'`;	\
+		[ -d $(builddir)/firmware/$(arch)-$$name ] ||		\
+		    cp -a $(builddir)/firmware/$(arch)			\
+			firmware/$(arch)-$$name;			\
+		cp $$flav/* $(builddir)/firmware/$(arch)-$$name/;	\
+	    done;							\
+	fi
+
+	# Remove unwanted stuff for each flavour
+	flavour_exclude=`ls $(DEBIAN)/d-i/exclude-modules.$(arch)-* 2>/dev/null`\
+		|| true;						\
+	if [ "$$flavour_exclude" ]; then				\
+	    for flav in $$flavour_exclude; do				\
+		name=`echo $$flav | sed 's/.*\/exclude-modules.$(arch)-//'`;\
+		[ -d $(builddir)/modules/$(arch)-$$name ] ||		\
+		    cp -a $(builddir)/modules/$(arch) 			\
+			$(builddir)/modules/$(arch)-$$name;		\
+		(cat $$flav;						\
+		 ls $(builddir)/modules/$(arch)-$$name) |		\
+		 sort |	uniq -d |					\
+		    (cd $(builddir)/modules/$(arch)-$$name/;		\
+		     xargs rm -f);					\
+	    done;							\
+	fi
+	flavour_exclude=`ls $(DEBIAN)/d-i/exclude-firmware.$(arch)-* 2>/dev/null`\
+		|| true;						\
+	if [ "$$flavour_exclude" ]; then				\
+	    for flav in $$flavour_exclude; do				\
+		name=`echo $$flav | sed 's/.*\/exclude-firmware.$(arch)-//'`;\
+		[ -d $(builddir)/firmware/$(arch)-$$name ] ||		\
+		    cp -a $(builddir)/firmware/$(arch) 			\
+			$(builddir)/firmware/$(arch)-$$name;		\
+		(cat $$flav;						\
+		 ls $(builddir)/firmware/$(arch)-$$name) |		\
+		 sort |	uniq -d |					\
+		    (cd $(builddir)/firmware/$(arch)-$$name/;		\
+		     xargs rm -f);					\
+	    done;							\
+	fi
+
+	if [ ! -d $(builddir)/modules/$(build_arch) ]; then		\
+		mkdir -p $(builddir)/modules/$(build_arch);		\
+		cp $(builddir)/modules/$(arch)/*			\
+			$(builddir)/modules/$(build_arch);		\
+	fi
+	if [ ! -d $(builddir)/firmware/$(build_arch) ]; then		\
+		mkdir -p $(builddir)/firmware/$(build_arch);		\
+		cp $(builddir)/firmware/$(arch)/*			\
+			$(builddir)/firmware/$(build_arch);		\
+	fi
+
+	echo "# placebo control.stub for kernel-wedge flow change" >debian/control.stub
+	cp $(DEBIAN)/control.stub debian/control
+	cd $(builddir) && LANG=C kernel-wedge gen-control >> $(CURDIR)/debian/control
--- linux-4.4.0.orig/debian/rules.d/0-common-vars.mk
+++ linux-4.4.0/debian/rules.d/0-common-vars.mk
@@ -0,0 +1,257 @@
+# Used when you need to 'escape' a comma.
+comma = ,
+
+#
+# The source package name will be the first token from $(DEBIAN)/changelog
+#
+src_pkg_name=$(shell sed -n '1s/^\(.*\) (.*).*$$/\1/p' $(DEBIAN)/changelog)
+
+# Get some version info
+release := $(shell sed -n '1s/^$(src_pkg_name).*(\(.*\)-.*).*$$/\1/p' $(DEBIAN)/changelog)
+revisions := $(shell sed -n 's/^$(src_pkg_name)\ .*($(release)-\(.*\)).*$$/\1/p' $(DEBIAN)/changelog | tac)
+revision ?= $(word $(words $(revisions)),$(revisions))
+prev_revisions := $(filter-out $(revision),0.0 $(revisions))
+prev_revision := $(word $(words $(prev_revisions)),$(prev_revisions))
+
+prev_fullver ?= $(shell dpkg-parsechangelog -l$(DEBIAN)/changelog -o1 -c1 | sed -ne 's/^Version: *//p')
+
+# Get upstream version info
+upstream_version := $(shell sed -n 's/^VERSION = \(.*\)$$/\1/p' Makefile)
+upstream_patchlevel := $(shell sed -n 's/^PATCHLEVEL = \(.*\)$$/\1/p' Makefile)
+upstream_extraversion := $(shell sed -n 's/^EXTRAVERSION = \(.*\)$$/\1/p' Makefile)
+upstream_tag := "v$(upstream_version).$(upstream_patchlevel)$(upstream_extraversion)"
+
+family=ubuntu
+
+# This is an internally used mechanism for the daily kernel builds. It
+# creates packages whose ABI is suffixed with a minimal representation of
+# the current git HEAD sha. If .git/HEAD is not present, then it uses the
+# uuidgen program,
+#
+# AUTOBUILD can also be used by anyone wanting to build a custom kernel
+# image, or rebuild the entire set of Ubuntu packages using custom patches
+# or configs.
+AUTOBUILD=
+
+ifneq ($(AUTOBUILD),)
+skipabi		= true
+skipmodule	= true
+skipretpoline	= true
+skipdbg		= true
+gitver=$(shell if test -f .git/HEAD; then cat .git/HEAD; else uuidgen; fi)
+gitverpre=$(shell echo $(gitver) | cut -b -3)
+gitverpost=$(shell echo $(gitver) | cut -b 38-40)
+abi_suffix = -$(gitverpre)$(gitverpost)
+endif
+
+ifneq ($(NOKERNLOG),)
+ubuntu_log_opts += --no-kern-log
+endif
+ifneq ($(PRINTSHAS),)
+ubuntu_log_opts += --print-shas
+endif
+
+# Get the kernels own extra version to be added to the release signature.
+raw_kernelversion=$(shell make kernelversion)
+
+#
+# full_build -- are we doing a full buildd style build
+#
+ifeq ($(wildcard /CurrentlyBuilding),)
+full_build?=false
+else
+full_build?=true
+endif
+
+#
+# The debug packages are ginormous, so you probably want to skip
+# building them (as a developer).
+#
+ifeq ($(full_build),false)
+skipdbg=true
+endif
+
+abinum		:= $(shell echo $(revision) | sed -r -e 's/([^\+~]*)\.[^\.]+(~.*)?(\+.*)?$$/\1/')$(abi_suffix)
+prev_abinum	:= $(shell echo $(prev_revision) | sed -r -e 's/([^\+~]*)\.[^\.]+(~.*)?(\+.*)?$$/\1/')$(abi_suffix)
+abi_release	:= $(release)-$(abinum)
+
+uploadnum	:= $(shell echo $(revision) | sed -r -e 's/[^\+~]*\.([^\.~]+(~.*)?(\+.*)?$$)/\1/')
+ifneq ($(full_build),false)
+  uploadnum	:= $(uploadnum)-Ubuntu
+endif
+
+# XXX: linux-libc-dev got bumped to -803.N inadvertantly by a ti-omap4 upload
+#      shift our version higher for this package only.  Ensure this only
+#      occurs for the v2.6.35 kernel so that we do not propogate this into
+#      any other series.
+raw_uploadnum	:= $(shell echo $(revision) | sed -e 's/.*\.//')
+libc_dev_version :=
+ifeq ($(DEBIAN),debian.master)
+ifeq ($(release),2.6.35)
+libc_dev_version := -v$(release)-$(shell expr "$(abinum)" + 1000).$(raw_uploadnum)
+endif
+endif
+
+DEB_HOST_MULTIARCH = $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+DEB_HOST_GNU_TYPE  = $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE = $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+DEB_HOST_ARCH = $(shell dpkg-architecture -qDEB_HOST_ARCH)
+DEB_BUILD_ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH)
+
+#
+# Detect invocations of the form 'fakeroot debian/rules binary arch=armhf'
+# within an x86'en schroot. This only gets you part of the way since the
+# packaging phase fails, but you can at least compile the kernel quickly.
+#
+arch := $(DEB_HOST_ARCH)
+ifneq ($(arch),$(DEB_HOST_ARCH))
+	CROSS_COMPILE ?= $(shell dpkg-architecture -a$(arch) -qDEB_HOST_GNU_TYPE -f 2>/dev/null)-
+endif
+
+#
+# Detect invocations of the form 'dpkg-buildpackage -B -aarmhf' within
+# an x86'en schroot. This is the only way to build all of the packages
+# (except for tools).
+#
+ifneq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
+	CROSS_COMPILE ?= $(DEB_HOST_GNU_TYPE)-
+endif
+
+abidir		:= $(CURDIR)/$(DEBIAN)/abi/$(release)-$(revision)/$(arch)
+commonconfdir	:= $(CURDIR)/$(DEBIAN)/config
+archconfdir	:= $(CURDIR)/$(DEBIAN)/config/$(arch)
+sharedconfdir	:= $(CURDIR)/debian.master/config
+builddir	:= $(CURDIR)/debian/build
+stampdir	:= $(CURDIR)/debian/stamps
+
+#
+# The binary package name always starts with linux-image-$KVER-$ABI.$UPLOAD_NUM. There
+# are places that you'll find linux-image hard coded, but I guess thats OK since the
+# assumption that the binary package always starts with linux-image will never change.
+#
+bin_pkg_name_signed=linux-image-$(abi_release)
+bin_pkg_name_unsigned=linux-image-unsigned-$(abi_release)
+mods_pkg_name=linux-modules-$(abi_release)
+mods_extra_pkg_name=linux-modules-extra-$(abi_release)
+bldinfo_pkg_name=linux-buildinfo-$(abi_release)
+hdrs_pkg_name=linux-headers-$(abi_release)
+indep_hdrs_pkg_name=$(src_pkg_name)-headers-$(abi_release)
+
+#
+# The generation of content in the doc package depends on both 'AUTOBUILD=' and
+# 'do_doc_package_content=true'. There are usually build errors during the development
+# cycle, so its OK to leave 'do_doc_package_content=false' until those build
+# failures get sorted out. Finally, the doc package doesn't really need to be built
+# for developer testing (its kind of slow), so only do it if on a buildd.
+do_doc_package=true
+do_doc_package_content=true
+ifeq ($(full_build),false)
+do_doc_package_content=false
+endif
+doc_pkg_name=$(src_pkg_name)-doc
+
+#
+# Similarly with the linux-source package, you need not build it as a developer. Its
+# somewhat I/O intensive and utterly useless.
+#
+do_source_package=true
+do_source_package_content=true
+ifeq ($(full_build),false)
+do_source_package_content=false
+endif
+
+# linux-libc-dev may not be needed, default to building it.
+do_libc_dev_package=true
+
+# common headers normally is built as an indep package, but may be arch
+do_common_headers_indep=true
+
+# add a 'full source' mode
+do_full_source=false
+
+# build tools
+ifneq ($(wildcard $(CURDIR)/tools),)
+	ifeq ($(do_tools),)
+		ifneq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
+			do_tools=false
+		endif
+	endif
+	do_tools?=true
+else
+	do_tools?=false
+endif
+tools_pkg_name=$(src_pkg_name)-tools-$(abi_release)
+tools_common_pkg_name=$(src_pkg_name)-tools-common
+tools_flavour_pkg_name=linux-tools-$(abi_release)
+cloud_pkg_name=$(src_pkg_name)-cloud-tools-$(abi_release)
+cloud_common_pkg_name=$(src_pkg_name)-cloud-tools-common
+cloud_flavour_pkg_name=linux-cloud-tools-$(abi_release)
+hosttools_pkg_name=$(src_pkg_name)-tools-host
+
+# The general flavour specific image package.
+do_flavour_image_package=true
+
+# The general flavour specific header package.
+do_flavour_header_package=true
+
+# DTBs
+do_dtbs=false
+
+# Support parallel=<n> in DEB_BUILD_OPTIONS (see #209008)
+#
+# These 2 environment variables set the -j value of the kernel build. For example,
+# CONCURRENCY_LEVEL=16 fakeroot $(DEBIAN)/rules binary-debs
+# or
+# DEB_BUILD_OPTIONS=parallel=16 fakeroot $(DEBIAN)/rules binary-debs
+#
+# The default is to use the number of CPUs.
+#
+COMMA=,
+DEB_BUILD_OPTIONS_PARA = $(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS))))
+ifneq (,$(DEB_BUILD_OPTIONS_PARA))
+  CONCURRENCY_LEVEL := $(DEB_BUILD_OPTIONS_PARA)
+endif
+
+ifeq ($(CONCURRENCY_LEVEL),)
+  # Check the environment
+  CONCURRENCY_LEVEL := $(shell echo $$CONCURRENCY_LEVEL)
+  # No? Then build with the number of CPUs on the host.
+  ifeq ($(CONCURRENCY_LEVEL),)
+      CONCURRENCY_LEVEL := $(shell expr `getconf _NPROCESSORS_ONLN` \* 1)
+  endif
+  # Oh hell, give 'em one
+  ifeq ($(CONCURRENCY_LEVEL),)
+    CONCURRENCY_LEVEL := 1
+  endif
+endif
+
+conc_level		= -j$(CONCURRENCY_LEVEL)
+
+# target_flavour is filled in for each step
+kmake = make ARCH=$(build_arch) \
+	CROSS_COMPILE=$(CROSS_COMPILE) \
+	KERNELVERSION=$(abi_release)-$(target_flavour) \
+	CONFIG_DEBUG_SECTION_MISMATCH=y \
+	KBUILD_BUILD_VERSION="$(uploadnum)" \
+	LOCALVERSION= localver-extra= \
+	CFLAGS_MODULE="-DPKG_ABI=$(abinum)"
+ifneq ($(LOCAL_ENV_CC),)
+kmake += CC="$(LOCAL_ENV_CC)" DISTCC_HOSTS="$(LOCAL_ENV_DISTCC_HOSTS)"
+endif
+
+# Locking is required in parallel builds to prevent loss of contents
+# of the debian/files.
+lockme_file = $(CURDIR)/debian/.LOCK
+lockme_cmd = flock -w 60
+lockme = $(lockme_cmd) $(lockme_file)
+
+# Don't fail if a link already exists.
+LN = ln -sf
+
+# Checks if a var is overriden by the custom rules. Called with var and
+# flavour as arguments.
+custom_override = \
+ $(shell if [ -n "$($(1)_$(2))" ]; then echo "$($(1)_$(2))"; else echo "$($(1))"; fi)
+
+# selftests that Ubuntu cares about
+ubuntu_selftests = breakpoints cpu-hotplug efivarfs memory-hotplug mount net ptrace powerpc seccomp user
--- linux-4.4.0.orig/debian/rules.d/1-maintainer.mk
+++ linux-4.4.0/debian/rules.d/1-maintainer.mk
@@ -0,0 +1,166 @@
+# The following targets are for the maintainer only! do not run if you don't
+# know what they do.
+
+.PHONY: printenv updateconfigs printchanges insertchanges startnewrelease diffupstream help updateportsconfigs editportsconfigs autoreconstruct finalchecks
+
+help:
+	@echo "These are the targets in addition to the normal $(DEBIAN) ones:"
+	@echo
+	@echo "  printenv        : Print some variables used in the build"
+	@echo
+	@echo "  updateconfigs        : Update core arch configs"
+	@echo
+	@echo "  editconfigs          : Update core arch configs interractively"
+	@echo "  genconfigs           : Generate core arch configs in CONFIGS/*"
+	@echo
+	@echo "  updateportsconfigs   : Update ports arch configs"
+	@echo
+	@echo "  editportsconfigs     : Update ports arch configs interactivly"
+	@echo "  genportconfigs       : Generate ports arch configs in CONFIGS/*"
+	@echo
+	@echo "  printchanges    : Print the current changelog entries (from git)"
+	@echo
+	@echo "  insertchanges   : Insert current changelog entries (from git)"
+	@echo
+	@echo "  startnewrelease : Start a new changelog set"
+	@echo
+	@echo "  diffupstream    : Diff stock kernel code against upstream (git)"
+	@echo
+	@echo "  compileselftests : Only compile the selftests listed on ubuntu_selftests variable"
+	@echo
+	@echo "  runselftests    : Run the selftests listed on ubuntu_selftests variable"
+	@echo
+	@echo "  help            : If you are kernel hacking, you need the professional"
+	@echo "                    version of this"
+	@echo
+	@echo "Environment variables:"
+	@echo
+	@echo "  NOKERNLOG       : Do not add upstream kernel commits to changelog"
+	@echo "  CONCURRENCY_LEVEL=X"
+	@echo "                  : Use -jX for kernel compile"
+	@echo "  PRINTSHAS       : Include SHAs for commits in changelog"
+
+printdebian:
+	@echo "$(DEBIAN)"
+
+updateconfigs defaultconfigs editconfigs genconfigs dumpconfigs:
+	dh_testdir;
+	$(SHELL) $(DROOT)/scripts/misc/kernelconfig $@
+	rm -rf build
+
+updateportsconfigs defaultportsconfigs editportsconfigs genportsconfigs askconfigs:
+	dh_testdir;
+	$(SHELL) $(DROOT)/scripts/misc/kernelconfig $@ ports
+	rm -rf build
+
+printenv:
+	dh_testdir
+	@echo "src package name  = $(src_pkg_name)"
+	@echo "release           = $(release)"
+	@echo "revisions         = $(revisions)"
+	@echo "revision          = $(revision)"
+	@echo "uploadnum         = $(uploadnum)"
+	@echo "prev_revisions    = $(prev_revisions)"
+	@echo "prev_revision     = $(prev_revision)"
+	@echo "abinum            = $(abinum)"
+	@echo "upstream_tag      = $(upstream_tag)"
+	@echo "gitver            = $(gitver)"
+	@echo "flavours          = $(flavours)"
+	@echo "skipabi           = $(skipabi)"
+	@echo "skipmodule        = $(skipmodule)"
+	@echo "skipdbg           = $(skipdbg)"
+	@echo "ubuntu_log_opts   = $(ubuntu_log_opts)"
+	@echo "CONCURRENCY_LEVEL = $(CONCURRENCY_LEVEL)"
+	@echo "ubuntu_selftests  = $(ubuntu_selftests)"
+	@echo "bin package name  = $(bin_pkg_name)"
+	@echo "hdr package name  = $(hdrs_pkg_name)"
+	@echo "doc package name  = $(doc_pkg_name)"
+	@echo "do_doc_package            = $(do_doc_package)"
+	@echo "do_doc_package_content    = $(do_doc_package_content)"
+	@echo "do_source_package         = $(do_source_package)"
+	@echo "do_source_package_content = $(do_source_package_content)"
+	@echo "do_libc_dev_package       = $(do_libc_dev_package)"
+	@echo "do_flavour_image_package  = $(do_flavour_image_package)"
+	@echo "do_flavour_header_package = $(do_flavour_header_package)"
+	@echo "do_common_headers_indep   = $(do_common_headers_indep)"
+	@echo "do_full_source            = $(do_full_source)"
+	@echo "do_tools                  = $(do_tools)"
+	@echo "do_any_tools              = $(do_any_tools)"
+	@echo "do_linux_tools            = $(do_linux_tools)"
+	@echo " do_tools_cpupower         = $(do_tools_cpupower)"
+	@echo " do_tools_perf             = $(do_tools_perf)"
+	@echo " do_tools_x86              = $(do_tools_x86)"
+	@echo " do_tools_host             = $(do_tools_host)"
+	@echo "do_cloud_tools            = $(do_cloud_tools)"
+	@echo " do_tools_hyperv           = $(do_tools_hyperv)"
+	@echo "any_signed                = $(any_signed)"
+	@echo " uefi_signed               = $(uefi_signed)"
+	@echo " opal_signed               = $(opal_signed)"
+	@echo " fit_signed                = $(fit_signed)"
+	@echo "full_build                = $(full_build)"
+	@echo "libc_dev_version          = $(libc_dev_version)"
+	@echo "DEB_HOST_GNU_TYPE         = $(DEB_HOST_GNU_TYPE)"
+	@echo "DEB_BUILD_GNU_TYPE        = $(DEB_BUILD_GNU_TYPE)"
+	@echo "DEB_HOST_ARCH             = $(DEB_HOST_ARCH)"
+	@echo "DEB_BUILD_ARCH            = $(DEB_BUILD_ARCH)"
+	@echo "arch                      = $(arch)"
+	@echo "kmake                     = $(kmake)"
+
+printchanges:
+	@baseCommit=$$(git log --pretty=format:'%H %s' | \
+		gawk '/UBUNTU: '".*Ubuntu-.*`echo $(prev_fullver) | sed 's/+/\\\\+/'`"'(~.*)?$$/ { print $$1; exit }'); \
+	if [ -z "$$baseCommit" ]; then \
+		echo "WARNING: couldn't find a commit for the previous version. Using the lastest one." >&2; \
+		baseCommit=$$(git log --pretty=format:'%H %s' | \
+			gawk '/UBUNTU:\s*Ubuntu-.*$$/ { print $$1; exit }'); \
+	fi; \
+	git log "$$baseCommit"..HEAD | \
+	$(DROOT)/scripts/misc/git-ubuntu-log $(ubuntu_log_opts)
+
+insertchanges: autoreconstruct finalchecks
+	@perl -w -f $(DROOT)/scripts/misc/insert-changes.pl $(DROOT) $(DEBIAN) 
+
+autoreconstruct:
+	$(DROOT)/scripts/misc/gen-auto-reconstruct $(upstream_tag) $(DEBIAN)/reconstruct $(DROOT)/source/options
+
+finalchecks:
+	$(DROOT)/scripts/misc/final-checks "$(DEBIAN)" "$(prev_fullver)"
+
+diffupstream:
+	@git diff-tree -p refs/remotes/linux-2.6/master..HEAD $(shell ls | grep -vE '^(ubuntu|$(DEBIAN)|\.git.*)')
+
+startnewrelease:
+	dh_testdir
+	@[ -f "$(DEBIAN)/etc/update.conf" ] && . "$(DEBIAN)/etc/update.conf"; \
+	if [ -n "$$BACKPORT_SUFFIX" ]; then \
+		ver="$$(dpkg-parsechangelog -l"$$DEBIAN_MASTER/changelog" -SVersion)$${BACKPORT_SUFFIX}.1"; \
+		prev_ver="$$(dpkg-parsechangelog -l"$(DEBIAN)/changelog" -SVersion)"; \
+		if [ "$${ver%.*}" = "$${prev_ver%.*}" ]; then \
+			ver="$${ver%.*}.$$(( $${prev_ver##*.} +1 ))"; \
+		fi; \
+	else \
+		ver="$(release)-$$(echo "$(revision)" | \
+			perl -ne 'if (/^(\d*)\.(\d*)(.*)?$$/) { printf("%d.%d%s\n", $$1 + 1, $$2 +1, $$3) }')"; \
+	fi; \
+	now="$(shell date -R)"; \
+	echo "Creating new changelog set for $$ver..."; \
+	echo -e "$(src_pkg_name) ($$ver) UNRELEASED; urgency=medium\n" > $(DEBIAN)/changelog.new; \
+	echo "  CHANGELOG: Do not edit directly. Autogenerated at release." >> \
+		$(DEBIAN)/changelog.new; \
+	echo "  CHANGELOG: Use the printchanges target to see the curent changes." \
+		>> $(DEBIAN)/changelog.new; \
+	echo "  CHANGELOG: Use the insertchanges target to create the final log." \
+		>> $(DEBIAN)/changelog.new; \
+	echo -e "\n -- $$DEBFULLNAME <$$DEBEMAIL>  $$now\n" >> \
+		$(DEBIAN)/changelog.new ; \
+	cat $(DEBIAN)/changelog >> $(DEBIAN)/changelog.new; \
+	mv $(DEBIAN)/changelog.new $(DEBIAN)/changelog
+
+compileselftests:
+	# a loop is needed here to fail on errors
+	for test in $(ubuntu_selftests); do \
+		$(kmake) -C tools/testing/selftests TARGETS="$$test"; \
+	done;
+
+runselftests:
+	$(kmake) -C tools/testing/selftests TARGETS="$(ubuntu_selftests)" run_tests
--- linux-4.4.0.orig/debian/rules.d/2-binary-arch.mk
+++ linux-4.4.0/debian/rules.d/2-binary-arch.mk
@@ -0,0 +1,797 @@
+# We don't want make removing intermediary stamps
+.SECONDARY :
+
+# Prepare the out-of-tree build directory
+ifeq ($(do_full_source),true)
+build_cd = cd $(builddir)/build-$*; #
+build_O  =
+else
+build_cd =
+build_O  = O=$(builddir)/build-$*
+endif
+
+# Typically supplied from the arch makefile, e.g., debian.master/control.d/armhf.mk
+ifneq ($(gcc),)
+kmake += CC=$(CROSS_COMPILE)$(gcc)
+endif
+
+shlibdeps_opts = $(if $(CROSS_COMPILE),-- -l$(CROSS_COMPILE:%-=/usr/%)/lib)
+
+debian/scripts/fix-filenames: debian/scripts/fix-filenames.c
+	$(CC) -o $@ $^
+
+$(stampdir)/stamp-prepare-%: config-prepare-check-%
+	@echo Debug: $@
+	@touch $@
+$(stampdir)/stamp-prepare-tree-%: target_flavour = $*
+$(stampdir)/stamp-prepare-tree-%: $(commonconfdir)/config.common.$(family) $(archconfdir)/config.common.$(arch) $(archconfdir)/config.flavour.% debian/scripts/fix-filenames
+	@echo Debug: $@
+	install -d $(builddir)/build-$*
+	touch $(builddir)/build-$*/ubuntu-build
+	[ "$(do_full_source)" != 'true' ] && true || \
+		rsync -a --exclude debian --exclude debian.master --exclude $(DEBIAN) * $(builddir)/build-$*
+	cat $(wordlist 1,3,$^) | sed -e 's/.*CONFIG_VERSION_SIGNATURE.*/CONFIG_VERSION_SIGNATURE="Ubuntu $(release)-$(revision)-$* $(raw_kernelversion)"/' > $(builddir)/build-$*/.config
+	find $(builddir)/build-$* -name "*.ko" | xargs rm -f
+	$(build_cd) $(kmake) $(build_O) -j1 silentoldconfig prepare scripts
+	touch $@
+
+# Used by developers as a shortcut to prepare a tree for compilation.
+prepare-%: $(stampdir)/stamp-prepare-%
+	@echo Debug: $@
+# Used by developers to allow efficient pre-building without fakeroot.
+build-%: $(stampdir)/stamp-build-%
+	@echo Debug: $@
+
+define build_zfs =
+	#
+	# SPL/ZFS wants a fully built kernel before you can configure and build.
+	# It seems to be impossible to tease out the application configuration
+	# from the modules, but at least one can build just the modules.
+	#
+	install -d $(builddir)/build-$*/spl
+	rsync -a --exclude=dkms.conf --delete spl/ $(builddir)/build-$*/spl/
+	cd $(builddir)/build-$*/spl; sh autogen.sh; sh configure $(splopts)
+	$(kmake) -C $(builddir)/build-$*/spl/module $(conc_level)
+
+	install -d $(builddir)/build-$*/zfs
+	rsync -a --exclude=dkms.conf --delete zfs/ $(builddir)/build-$*/zfs/
+	cd $(builddir)/build-$*/zfs; sh autogen.sh; sh configure $(zfsopts)
+	$(kmake) -C $(builddir)/build-$*/zfs/module $(conc_level)
+endef
+
+# Do the actual build, including image and modules
+$(stampdir)/stamp-build-%: target_flavour = $*
+$(stampdir)/stamp-build-%: splopts  = --with-linux=$(CURDIR)
+$(stampdir)/stamp-build-%: splopts += --with-linux-obj=$(builddir)/build-$*
+$(stampdir)/stamp-build-%: zfsopts  = $(splopts)
+$(stampdir)/stamp-build-%: zfsopts += --with-spl=$(builddir)/build-$*/spl
+$(stampdir)/stamp-build-%: zfsopts += --with-spl-obj=$(builddir)/build-$*/spl
+$(stampdir)/stamp-build-%: zfsopts += --prefix=/usr --with-config=kernel
+$(stampdir)/stamp-build-%: bldimg = $(call custom_override,build_image,$*)
+$(stampdir)/stamp-build-%: enable_zfs = $(call custom_override,do_zfs,$*)
+$(stampdir)/stamp-build-%: $(stampdir)/stamp-prepare-%
+	@echo Debug: $@ build_image $(build_image) bldimg $(bldimg)
+	$(build_cd) $(kmake) $(build_O) $(conc_level) $(bldimg) modules $(if $(filter true,$(do_dtbs)),dtbs)
+
+	$(if $(filter true,$(enable_zfs)),$(call build_zfs))
+
+	@touch $@
+
+define install_zfs =
+	cd $(builddir)/build-$*/spl/module; \
+		$(kmake) -C $(builddir)/build-$* SUBDIRS=`pwd` modules_install $(splopts)
+	cd $(builddir)/build-$*/zfs/module; \
+		$(kmake) -C $(builddir)/build-$* SUBDIRS=`pwd` modules_install $(zfsopts)
+endef
+
+define build_dkms_sign =
+	$(shell set -x; if grep -q CONFIG_MODULE_SIG=y $(1)/.config; then
+			echo $(1)/scripts/sign-file $(MODHASHALGO) $(MODSECKEY) $(MODPUBKEY);
+		else
+			echo "-";
+		fi
+	)
+endef
+define build_dkms =
+	$(SHELL) $(DROOT)/scripts/dkms-build $(dkms_dir) $(abi_release)-$* '$(call build_dkms_sign,$(builddir)/build-$*)' $(1) $(2) $(3) $(4)
+endef
+
+define install_control =
+	for which in $(3);							\
+	do									\
+		template="$(DROOT)/templates/$(2).$$which.in";			\
+		script="$(DROOT)/$(1).$$which";					\
+		sed -e 's/@abiname@/$(abi_release)/g'				\
+		    -e 's/@localversion@/-$*/g'					\
+		    -e 's/@image-stem@/$(instfile)/g'				\
+			<"$$template" >"$$script";				\
+	done
+endef
+
+# Ensure the directory prefix is exactly 100 characters long so pathnames are the
+# exact same length in any binary files produced by the builds.  These will be
+# commonised later.
+dkms_20d=....................
+dkms_100d=$(dkms_20d)$(dkms_20d)$(dkms_20d)$(dkms_20d)$(dkms_20d)
+dkms_100c=$(shell echo '$(dkms_100d)' | sed -e 's/\./_/g')
+define dkms_dir_prefix =
+$(shell echo $(1)/$(dkms_100c) | \
+	sed -e 's/\($(dkms_100d)\).*/\1/' -e 's/^\(.*\)....$$/\1dkms/')
+endef
+
+# Install the finished build
+install-%: pkgdir_bin = $(CURDIR)/debian/$(bin_pkg_name)-$*
+install-%: pkgdir = $(CURDIR)/debian/$(mods_pkg_name)-$*
+install-%: pkgdir_ex = $(CURDIR)/debian/$(mods_extra_pkg_name)-$*
+install-%: pkgdir_bldinfo = $(CURDIR)/debian/$(bldinfo_pkg_name)-$*
+install-%: bindoc = $(pkgdir)/usr/share/doc/$(bin_pkg_name)-$*
+install-%: dbgpkgdir = $(CURDIR)/debian/$(bin_pkg_name)-$*-dbgsym
+install-%: signingv = $(CURDIR)/debian/$(bin_pkg_name)-signing/$(release)-$(revision)
+install-%: toolspkgdir = $(CURDIR)/debian/$(tools_flavour_pkg_name)-$*
+install-%: cloudpkgdir = $(CURDIR)/debian/$(cloud_flavour_pkg_name)-$*
+install-%: basepkg = $(hdrs_pkg_name)
+install-%: indeppkg = $(indep_hdrs_pkg_name)
+install-%: kernfile = $(call custom_override,kernel_file,$*)
+install-%: instfile = $(call custom_override,install_file,$*)
+install-%: hdrdir = $(CURDIR)/debian/$(basepkg)-$*/usr/src/$(basepkg)-$*
+install-%: target_flavour = $*
+install-%: MODHASHALGO=sha512
+install-%: MODSECKEY=$(builddir)/build-$*/certs/signing_key.pem
+install-%: MODPUBKEY=$(builddir)/build-$*/certs/signing_key.x509
+install-%: build_dir=$(builddir)/build-$*
+install-%: dkms_dir=$(call dkms_dir_prefix,$(builddir)/build-$*)
+install-%: enable_zfs = $(call custom_override,do_zfs,$*)
+install-%: splopts  = INSTALL_MOD_STRIP=1
+install-%: splopts += INSTALL_MOD_PATH=$(pkgdir)/
+install-%: splopts += INSTALL_MOD_DIR=kernel/zfs
+install-%: splopts += $(conc_level)
+install-%: zfsopts  = $(splopts)
+install-%: $(stampdir)/stamp-build-% install-headers
+	@echo Debug: $@ kernel_file $(kernel_file) kernfile $(kernfile) install_file $(install_file) instfile $(instfile)
+	dh_testdir
+	dh_testroot
+	dh_prep -p$(bin_pkg_name)-$*
+	dh_prep -p$(mods_pkg_name)-$*
+	dh_prep -p$(hdrs_pkg_name)-$*
+ifneq ($(skipdbg),true)
+	dh_prep -p$(bin_pkg_name)-$*-dbgsym
+endif
+
+	# The main image
+	# compress_file logic required because not all architectures
+	# generate a zImage automatically out of the box
+ifeq ($(compress_file),)
+	install -m600 -D $(builddir)/build-$*/$(kernfile) \
+		$(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$*
+else
+	install -d $(pkgdir_bin)/boot
+	gzip -c9v $(builddir)/build-$*/$(kernfile) > \
+		$(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$*
+	chmod 600 $(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$*
+endif
+
+ifeq ($(uefi_signed),true)
+	install -d $(signingv)
+	# Check to see if this supports handoff, if not do not sign it.
+	# Check the identification area magic and version >= 0x020b
+	handoff=`dd if="$(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$*" bs=1 skip=514 count=6 2>/dev/null | od -s | gawk '($$1 == 0 && $$2 == 25672 && $$3 == 21362 && $$4 >= 523) { print "GOOD" }'`; \
+	if [ "$$handoff" = "GOOD" ]; then \
+		cp -p $(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$* \
+			$(signingv)/$(instfile)-$(abi_release)-$*.efi; \
+	fi
+endif
+ifeq ($(opal_signed),true)
+	install -d $(signingv)
+	cp -p $(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$* \
+		$(signingv)/$(instfile)-$(abi_release)-$*.opal;
+endif
+
+	install -d $(pkgdir)/boot
+	install -m644 $(builddir)/build-$*/.config \
+		$(pkgdir)/boot/config-$(abi_release)-$*
+	install -m600 $(builddir)/build-$*/System.map \
+		$(pkgdir)/boot/System.map-$(abi_release)-$*
+	if [ "$(filter true,$(do_dtbs))" ]; then \
+		$(build_cd) $(kmake) $(build_O) $(conc_level) dtbs_install \
+			INSTALL_DTBS_PATH=$(pkgdir)/lib/firmware/$(abi_release)-$*/device-tree; \
+		( cd $(pkgdir)/lib/firmware/$(abi_release)-$*/ && find device-tree -print ) | \
+		while read dtb_file; do \
+			echo "$$dtb_file ?" >> $(DEBIAN)/d-i/firmware/kernel-image; \
+		done; \
+	fi
+ifeq ($(no_dumpfile),)
+	makedumpfile -g $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$* \
+		-x $(builddir)/build-$*/vmlinux
+	chmod 0600 $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$*
+endif
+
+	$(build_cd) $(kmake) $(build_O) $(conc_level) modules_install $(vdso) \
+		INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=$(pkgdir)/ \
+		INSTALL_FW_PATH=$(pkgdir)/lib/firmware/$(abi_release)-$*
+
+	$(if $(filter true,$(enable_zfs)),$(call install_zfs))
+
+	#
+	# Build module blacklists:
+	#  - blacklist all watchdog drivers (LP:1432837)
+	#
+	install -d $(pkgdir)/lib/modprobe.d
+	echo "# Kernel supplied blacklist for $(src_pkg_name) $(abi_release)-$* $(arch)" \
+		>$(pkgdir)/lib/modprobe.d/blacklist_$(src_pkg_name)_$(abi_release)-$*.conf
+	for conf in $(arch)-$* $(arch) common.conf; do \
+		if [ -f $(DEBIAN)/modprobe.d/$$conf ]; then \
+			echo "# modprobe.d/$$conf"; \
+			cat $(DEBIAN)/modprobe.d/$$conf; \
+		fi; \
+	done >>$(pkgdir)/lib/modprobe.d/blacklist_$(src_pkg_name)_$(abi_release)-$*.conf
+	echo "# Autogenerated watchdog blacklist" \
+		>>$(pkgdir)/lib/modprobe.d/blacklist_$(src_pkg_name)_$(abi_release)-$*.conf
+	ls -1 $(pkgdir)/lib/modules/$(abi_release)-$*/kernel/drivers/watchdog/ | \
+		sed -e 's/^/blacklist /' -e 's/.ko$$//' | \
+		sort -u \
+		>>$(pkgdir)/lib/modprobe.d/blacklist_$(src_pkg_name)_$(abi_release)-$*.conf
+
+ifeq ($(do_extras_package),true)
+	#
+	# Remove all modules not in the inclusion list.
+	#
+	if [ -f $(DEBIAN)/control.d/$(target_flavour).inclusion-list ] ; then \
+		/sbin/depmod -v -b $(pkgdir) $(abi_release)-$* | \
+			sed -e "s@$(pkgdir)/lib/modules/$(abi_release)-$*/kernel/@@g" | \
+			awk '{ print $$1 " " $$NF}' >$(build_dir)/module-inclusion.depmap; \
+		mkdir -p $(pkgdir_ex)/lib/modules/$(abi_release)-$*; \
+		mv $(pkgdir)/lib/modules/$(abi_release)-$*/kernel \
+			$(pkgdir_ex)/lib/modules/$(abi_release)-$*/kernel; \
+		$(SHELL) $(DROOT)/scripts/module-inclusion --master \
+			$(pkgdir_ex)/lib/modules/$(abi_release)-$*/kernel \
+			$(pkgdir)/lib/modules/$(abi_release)-$*/kernel \
+			$(DEBIAN)/control.d/$(target_flavour).inclusion-list \
+			$(build_dir)/module-inclusion.depmap 2>&1 | \
+				tee $(target_flavour).inclusion-list.log; \
+		/sbin/depmod -b $(pkgdir) -ea -F $(pkgdir)/boot/System.map-$(abi_release)-$* \
+			$(abi_release)-$* 2>&1 |tee $(target_flavour).depmod.log; \
+		if [ `grep -c 'unknown symbol' $(target_flavour).depmod.log` -gt 0 ]; then \
+			echo "EE: Unresolved module dependencies in base package!"; \
+			exit 1; \
+		fi \
+	fi
+endif
+
+ifeq ($(no_dumpfile),)
+	makedumpfile -g $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$* \
+		-x $(builddir)/build-$*/vmlinux
+	chmod 0600 $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$*
+endif
+	rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/build
+	rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/source
+
+	# Some initramfs-tools specific modules
+	install -d $(pkgdir)/lib/modules/$(abi_release)-$*/initrd
+	if [ -f $(pkgdir)/lib/modules/$(abi_release)-$*/kernel/drivers/video/vesafb.ko ]; then\
+	  $(LN) $(pkgdir)/lib/modules/$(abi_release)-$*/kernel/drivers/video/vesafb.ko \
+		$(pkgdir)/lib/modules/$(abi_release)-$*/initrd/; \
+	fi
+
+	echo "interest linux-update-$(abi_release)-$*" >"$(DROOT)/$(bin_pkg_name)-$*.triggers"
+	$(call install_control,$(bin_pkg_name)-$*,image,postinst postrm preinst prerm)
+	$(call install_control,$(mods_pkg_name)-$*,extra,postinst postrm)
+ifeq ($(do_extras_package),true)
+	# Install the postinit/postrm scripts in the extras package.
+	if [ -f $(DEBIAN)/control.d/$(target_flavour).inclusion-list ] ; then	\
+		$(call install_control,$(mods_extra_pkg_name)-$*,extra,postinst postrm); \
+	fi
+endif
+
+	# Install the full changelog.
+ifeq ($(do_doc_package),true)
+	install -d $(bindoc)
+	cat $(DEBIAN)/changelog $(DEBIAN)/changelog.historical | \
+		gzip -9 >$(bindoc)/changelog.Debian.old.gz
+	chmod 644 $(bindoc)/changelog.Debian.old.gz
+endif
+
+ifneq ($(skipsub),true)
+	for sub in $($(*)_sub); do					\
+		if ! (TO=$$sub FROM=$* ABI_RELEASE=$(abi_release) $(SHELL)		\
+			$(DROOT)/scripts/sub-flavour); then exit 1; fi;		\
+		/sbin/depmod -b debian/$(bin_pkg_name)-$$sub		\
+			-ea -F debian/$(bin_pkg_name)-$$sub/boot/System.map-$(abi_release)-$* \
+			$(abi_release)-$*;					\
+		$(call install_control,$(bin_pkg_name)--$$sub,image,postinst postrm preinst prerm); \
+	done
+endif
+
+ifneq ($(skipdbg),true)
+	# Debug image is simple
+	install -m644 -D $(builddir)/build-$*/vmlinux \
+		$(dbgpkgdir)/usr/lib/debug/boot/vmlinux-$(abi_release)-$*
+	$(build_cd) $(kmake) $(build_O) modules_install $(vdso) \
+		INSTALL_MOD_PATH=$(dbgpkgdir)/usr/lib/debug
+	# Add .gnu_debuglink sections to each stripped .ko
+	# pointing to unstripped verson
+	find $(pkgdir) -name '*.ko' | sed 's|$(pkgdir)||'| while read module ; do \
+		if [[ -f "$(dbgpkgdir)/usr/lib/debug/$$module" ]] ; then \
+			$(CROSS_COMPILE)objcopy \
+				--add-gnu-debuglink=$(dbgpkgdir)/usr/lib/debug/$$module \
+				$(pkgdir)/$$module; \
+			if grep -q CONFIG_MODULE_SIG=y $(builddir)/build-$*/.config; then \
+				$(builddir)/build-$*/scripts/sign-file $(MODHASHALGO) \
+					$(MODSECKEY) \
+					$(MODPUBKEY) \
+					$(pkgdir)/$$module; \
+			fi; \
+		fi; \
+	done
+	rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/build
+	rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/source
+	rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/modules.*
+	rm -fr $(dbgpkgdir)/usr/lib/debug/lib/firmware
+endif
+
+	# The flavour specific headers image
+	# TODO: Would be nice if we didn't have to dupe the original builddir
+	install -d -m755 $(hdrdir)
+	cat $(builddir)/build-$*/.config | \
+		sed -e 's/.*CONFIG_DEBUG_INFO=.*/# CONFIG_DEBUG_INFO is not set/g' > \
+		$(hdrdir)/.config
+	chmod 644 $(hdrdir)/.config
+	$(kmake) O=$(hdrdir) -j1 silentoldconfig prepare scripts
+	# We'll symlink this stuff
+	rm -f $(hdrdir)/Makefile
+	rm -rf $(hdrdir)/include2 $(hdrdir)/source
+	# We do not need the retpoline information.
+	find $(hdrdir) -name \*.o.ur-\* | xargs rm -f
+	# Copy over the compilation version.
+	cp "$(builddir)/build-$*/include/generated/compile.h" \
+		"$(hdrdir)/include/generated/compile.h"
+	# Add UTS_UBUNTU_RELEASE_ABI since UTS_RELEASE is difficult to parse.
+	echo "#define UTS_UBUNTU_RELEASE_ABI $(abinum)" >> $(hdrdir)/include/generated/utsrelease.h
+	# powerpc kernel arch seems to need some .o files for external module linking. Add them in.
+ifeq ($(build_arch),powerpc)
+	mkdir -p $(hdrdir)/arch/powerpc/lib
+	cp $(builddir)/build-$*/arch/powerpc/lib/*.o $(hdrdir)/arch/powerpc/lib
+endif
+	# Copy over the new retpoline extractor.
+	cp scripts/ubuntu-retpoline-extract-one $(hdrdir)/scripts
+	# Script to symlink everything up
+	$(SHELL) $(DROOT)/scripts/link-headers "$(hdrdir)" "$(indeppkg)" "$*"
+	# The build symlink
+	install -d debian/$(basepkg)-$*/lib/modules/$(abi_release)-$*
+	$(LN) /usr/src/$(basepkg)-$* \
+		debian/$(basepkg)-$*/lib/modules/$(abi_release)-$*/build
+	# And finally the symvers
+	install -m644 $(builddir)/build-$*/Module.symvers \
+		$(hdrdir)/Module.symvers
+
+	# Now the header scripts
+	$(call install_control,$(hdrs_pkg_name)-$*,headers,postinst)
+
+	# At the end of the package prep, call the tests
+	DPKG_ARCH="$(arch)" KERN_ARCH="$(build_arch)" FLAVOUR="$*"	\
+	 VERSION="$(abi_release)" REVISION="$(revision)"		\
+	 PREV_REVISION="$(prev_revision)" ABI_NUM="$(abinum)"		\
+	 PREV_ABI_NUM="$(prev_abinum)" BUILD_DIR="$(builddir)/build-$*"	\
+	 INSTALL_DIR="$(pkgdir)" SOURCE_DIR="$(CURDIR)"			\
+	 run-parts -v $(DROOT)/tests-build
+
+	#
+	# Remove files which are generated at installation by postinst,
+	# except for modules.order and modules.builtin
+	# 
+	# NOTE: need to keep this list in sync with postrm
+	#
+	mkdir $(pkgdir)/lib/modules/$(abi_release)-$*/_
+	mv $(pkgdir)/lib/modules/$(abi_release)-$*/modules.order \
+		$(pkgdir)/lib/modules/$(abi_release)-$*/_
+	if [ -f $(pkgdir)/lib/modules/$(abi_release)-$*/modules.builtin ] ; then \
+	    mv $(pkgdir)/lib/modules/$(abi_release)-$*/modules.builtin \
+		$(pkgdir)/lib/modules/$(abi_release)-$*/_; \
+	fi
+	rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/modules.*
+	mv $(pkgdir)/lib/modules/$(abi_release)-$*/_/* \
+		$(pkgdir)/lib/modules/$(abi_release)-$*
+	rmdir $(pkgdir)/lib/modules/$(abi_release)-$*/_
+
+ifeq ($(do_linux_tools),true)
+	# Create the linux-tools tool links
+	install -d $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+ifeq ($(do_tools_usbip),true)
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/usbip $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/usbipd $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+endif
+ifeq ($(do_tools_acpidbg),true)
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/acpidbg $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+endif
+ifeq ($(do_tools_cpupower),true)
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/cpupower $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+endif
+ifeq ($(do_tools_perf),true)
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/perf $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+endif
+ifeq ($(do_tools_x86),true)
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/x86_energy_perf_policy $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/turbostat $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+endif
+endif
+ifeq ($(do_cloud_tools),true)
+ifeq ($(do_tools_hyperv),true)
+	# Create the linux-hyperv tool links
+	install -d $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/hv_kvp_daemon $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/hv_vss_daemon $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/hv_fcopy_daemon $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/lsvmbus $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+endif
+endif
+
+	# Build a temporary "installed headers" directory.
+	install -d $(dkms_dir) $(dkms_dir)/headers $(dkms_dir)/build $(dkms_dir)/source
+	cp -rp "$(hdrdir)" "$(indep_hdrdir)" "$(dkms_dir)/headers"
+
+	$(if $(filter true,$(do_dkms_wireguard)),$(call build_dkms, $(mods_pkg_name)-$*, $(pkgdir)/lib/modules/$(abi_release)-$*/kernel, wireguard, pool/universe/w/wireguard-linux-compat/wireguard-dkms_$(dkms_wireguard_version)_all.deb))
+
+	# Build the final ABI information.
+	install -d $(abidir)
+	sed -e 's/^\(.\+\)[[:space:]]\+\(.\+\)[[:space:]]\(.\+\)$$/\3 \2 \1/'	\
+		$(builddir)/build-$*/Module.symvers | sort > $(abidir)/$*
+
+	# Build the final ABI modules information.
+	find $(pkgdir_bin) $(pkgdir) $(pkgdir_ex) -name \*.ko | \
+		sed -e 's/.*\/\([^\/]*\)\.ko/\1/' | sort > $(abidir)/$*.modules
+
+	# Build the final ABI firmware information.
+	find $(pkgdir_bin) $(pkgdir) $(pkgdir_ex) -name \*.ko | \
+	while read ko; do \
+		/sbin/modinfo $$ko | grep ^firmware || true; \
+	done | sort -u >$(abidir)/$*.fwinfo
+
+	# Build the final ABI compiler information.
+	ko=$$(find $(pkgdir_bin) $(pkgdir) $(pkgdir_ex) -name \*.ko | head -1); \
+	readelf -p .comment "$$ko" | gawk ' \
+		($$1 == "[") { \
+			printf("%s", $$3); \
+			for (n=4; n<=NF; n++) { \
+				printf(" %s", $$n); \
+			} \
+			print "" \
+		}' | sort -u >$(abidir)/$*.compiler
+
+	# Build the final ABI retpoline information.
+	if grep -q CONFIG_RETPOLINE=y $(builddir)/build-$*/.config; then \
+		echo "# retpoline v1.0" >$(abidir)/$*.retpoline; \
+		$(SHELL) $(DROOT)/scripts/retpoline-extract $(builddir)/build-$* $(CURDIR) | \
+			sort >>$(abidir)/$*.retpoline; \
+	else \
+		echo "# RETPOLINE NOT ENABLED" >$(abidir)/$*.retpoline; \
+	fi
+
+	# Build the buildinfo package content.
+	install -d $(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*
+	install -m644 $(builddir)/build-$*/.config \
+		$(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/config
+	install -m644 $(abidir)/$* \
+		$(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/abi
+	install -m644 $(abidir)/$*.modules \
+		$(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/modules
+	install -m644 $(abidir)/$*.fwinfo \
+		$(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/fwinfo
+	install -m644 $(abidir)/$*.retpoline \
+		$(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/retpoline
+	install -m644 $(abidir)/$*.compiler \
+		$(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/compiler
+
+ifeq ($(fit_signed),true)
+	install -d $(signingv)
+	cp -p $(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$* \
+		$(signingv)/$(instfile)-$(abi_release)-$*;
+	# Build FIT image now that the modules folder exists
+	$(SHELL) $(DROOT)/scripts/build-fit \
+		$(CURDIR)/$(DEBIAN)/$(fit_its) \
+		"$(foreach f, $(fit_dtb_files), $(builddir)/build-$*/$(f))" \
+		$(abi_release)-$(target_flavour) \
+		$(CURDIR)/$(DROOT)/linux-modules-$(abi_release)-$* \
+		$(signingv)
+	cp -p $(signingv)/fit-$(abi_release)-$*.fit $(pkgdir_bin)/boot/
+endif
+
+headers_tmp := $(CURDIR)/debian/tmp-headers
+headers_dir := $(CURDIR)/debian/linux-libc-dev
+
+hmake := $(MAKE) -C $(CURDIR) O=$(headers_tmp) \
+	KERNELVERSION=$(abi_release) INSTALL_HDR_PATH=$(headers_tmp)/install \
+	SHELL="$(SHELL)" ARCH=$(header_arch)
+
+install-arch-headers:
+	@echo Debug: $@
+	dh_testdir
+	dh_testroot
+ifeq ($(do_libc_dev_package),true)
+	dh_prep -plinux-libc-dev
+endif
+
+	rm -rf $(headers_tmp)
+	install -d $(headers_tmp) $(headers_dir)/usr/include/
+
+	$(hmake) $(defconfig)
+	mv $(headers_tmp)/.config $(headers_tmp)/.config.old
+	sed -e 's/^# \(CONFIG_MODVERSIONS\) is not set$$/\1=y/' \
+	  -e 's/.*CONFIG_LOCALVERSION_AUTO.*/# CONFIG_LOCALVERSION_AUTO is not set/' \
+	  $(headers_tmp)/.config.old > $(headers_tmp)/.config
+	$(hmake) silentoldconfig
+	$(hmake) headers_install
+
+	( cd $(headers_tmp)/install/include/ && \
+		find . -name '.' -o -name '.*' -prune -o -print | \
+                cpio -pvd --preserve-modification-time \
+			$(headers_dir)/usr/include/ )
+	mkdir -p $(headers_dir)/usr/include/$(DEB_HOST_MULTIARCH)
+	rm -rf $(headers_dir)/usr/include/$(DEB_HOST_MULTIARCH)/asm
+	mv $(headers_dir)/usr/include/asm $(headers_dir)/usr/include/$(DEB_HOST_MULTIARCH)/
+
+	rm -rf $(headers_tmp)
+
+define dh_all
+	dh_installchangelogs -p$(1)
+	dh_installdocs -p$(1)
+	dh_compress -p$(1)
+	dh_fixperms -p$(1) -X/boot/
+	dh_shlibdeps -p$(1) $(shlibdeps_opts)
+	dh_installdeb -p$(1)
+	dh_installdebconf -p$(1)
+	$(lockme) dh_gencontrol -p$(1) -- -Vlinux:rprovides='$(rprovides)'
+	dh_md5sums -p$(1)
+	dh_builddeb -p$(1) -- $(2)
+endef
+define newline
+
+
+endef
+define dh_all_inline
+        $(subst ${newline},; \${newline},$(call dh_all,$(1),$(2)))
+endef
+
+binary-arch-headers: install-arch-headers
+	@echo Debug: $@
+	dh_testdir
+	dh_testroot
+ifeq ($(do_libc_dev_package),true)
+ifneq ($(DEBIAN),debian.master)
+	echo "non-master branch building linux-libc-dev, aborting"
+	exit 1
+endif
+	$(call dh_all,linux-libc-dev)
+endif
+
+binary-%: pkgimg = $(bin_pkg_name)-$*
+binary-%: pkgimg_mods = $(mods_pkg_name)-$*
+binary-%: pkgimg_ex = $(mods_extra_pkg_name)-$*
+binary-%: pkgdir_ex = $(CURDIR)/debian/$(mods_extra_pkg_name)-$*
+binary-%: pkgbldinfo = $(bldinfo_pkg_name)-$*
+binary-%: pkghdr = $(hdrs_pkg_name)-$*
+binary-%: dbgpkg = $(bin_pkg_name)-$*-dbgsym
+binary-%: dbgpkgdir = $(CURDIR)/debian/$(bin_pkg_name)-$*-dbgsym
+binary-%: pkgtools = $(tools_flavour_pkg_name)-$*
+binary-%: pkgcloud = $(cloud_flavour_pkg_name)-$*
+binary-%: rprovides = $(if $(filter true,$(call custom_override,do_zfs,$*)),$(comma) spl-modules$(comma) spl-dkms$(comma) zfs-modules$(comma) zfs-dkms)
+binary-%: target_flavour = $*
+binary-%: checks-%
+	@echo Debug: $@
+	dh_testdir
+	dh_testroot
+
+	$(call dh_all,$(pkgimg),-Zbzip2 -z9)
+	$(call dh_all,$(pkgimg_mods))
+
+ifeq ($(do_extras_package),true)
+  ifeq ($(ship_extras_package),false)
+	# If $(ship_extras_package) is explicitly set to false, then do not
+	# construct the linux-image-extra package; instead just log all of the
+	# "extra" modules which were pointlessly built yet won't be shipped.
+	find $(pkgdir_ex) -name '*.ko' | sort \
+		| sed 's|^$(pkgdir_ex)/|NOT-SHIPPED |' \
+		| tee -a $(target_flavour).not-shipped.log;
+  else
+	if [ -f $(DEBIAN)/control.d/$(target_flavour).inclusion-list ] ; then \
+		$(call dh_all_inline,$(pkgimg_ex),-Zbzip2 -z9); \
+	fi
+  endif
+endif
+
+	$(call dh_all,$(pkgbldinfo))
+	$(call dh_all,$(pkghdr))
+
+ifneq ($(skipsub),true)
+	@set -e; for sub in $($(*)_sub); do		\
+		pkg=$(bin_pkg_name)-$$sub;		\
+		$(call dh_all_inline,$$pkg);		\
+	done
+endif
+
+ifneq ($(skipdbg),true)
+	$(call dh_all,$(dbgpkg))
+
+	# Hokay...here's where we do a little twiddling...
+	# Renaming the debug package prevents it from getting into
+	# the primary archive, and therefore prevents this very large
+	# package from being mirrored. It is instead, through some
+	# archive admin hackery, copied to http://ddebs.ubuntu.com.
+	#
+	mv ../$(dbgpkg)_$(release)-$(revision)_$(arch).deb \
+		../$(dbgpkg)_$(release)-$(revision)_$(arch).ddeb
+	set -e; \
+	( \
+		$(lockme_cmd) 9 || exit 1; \
+		if grep -qs '^Build-Debug-Symbols: yes$$' /CurrentlyBuilding; then \
+			sed -i '/^$(dbgpkg)_/s/\.deb /.ddeb /' debian/files; \
+		else \
+			grep -v '^$(dbgpkg)_.*$$' debian/files > debian/files.new; \
+			mv debian/files.new debian/files; \
+		fi; \
+	) 9>$(lockme_file)
+	# Now, the package wont get into the archive, but it will get put
+	# into the debug system.
+endif
+
+ifeq ($(do_linux_tools),true)
+	$(call dh_all,$(pkgtools))
+endif
+ifeq ($(do_cloud_tools),true)
+	$(call dh_all,$(pkgcloud))
+endif
+
+ifneq ($(full_build),false)
+	# Clean out this flavours build directory.
+	rm -rf $(builddir)/build-$*
+	# Clean out the debugging package source directory.
+	rm -rf $(dbgpkgdir)
+endif
+
+#
+# per-architecture packages
+#
+builddirpa = $(builddir)/tools-perarch
+
+$(stampdir)/stamp-prepare-perarch:
+	@echo Debug: $@
+ifeq ($(do_any_tools),true)
+	rm -rf $(builddirpa)
+	install -d $(builddirpa)
+	rsync -a --exclude debian --exclude debian.master --exclude $(DEBIAN) --exclude .git -a ./ $(builddirpa)/
+endif
+	touch $@
+
+$(stampdir)/stamp-build-perarch: $(stampdir)/stamp-prepare-perarch install-arch-headers
+	@echo Debug: $@
+ifeq ($(do_linux_tools),true)
+ifeq ($(do_tools_usbip),true)
+	chmod 755 $(builddirpa)/tools/usb/usbip/autogen.sh
+	cd $(builddirpa)/tools/usb/usbip && ./autogen.sh
+	chmod 755 $(builddirpa)/tools/usb/usbip/configure
+	cd $(builddirpa)/tools/usb/usbip && ./configure --prefix=$(builddirpa)/tools/usb/usbip/bin
+	cd $(builddirpa)/tools/usb/usbip && make install CFLAGS="-g -O2 -static" CROSS_COMPILE=$(CROSS_COMPILE)
+endif
+ifeq ($(do_tools_acpidbg),true)
+	cd $(builddirpa)/tools/power/acpi && make clean && make CFLAGS="-g -O2 -static -I$(builddirpa)/include" CROSS_COMPILE=$(CROSS_COMPILE) acpidbg
+endif
+ifeq ($(do_tools_cpupower),true)
+	# Allow for multiple installed versions of cpupower and libcpupower.so:
+	# Override LIB_MIN in order to to generate a versioned .so named
+	# libcpupower.so.$(abi_release) and link cpupower with that.
+	make -C $(builddirpa)/tools/power/cpupower \
+		CROSS_COMPILE=$(CROSS_COMPILE) \
+		CROSS=$(CROSS_COMPILE) \
+		LIB_MIN=$(abi_release) CPUFREQ_BENCH=false
+endif
+ifeq ($(do_tools_perf),true)
+	cd $(builddirpa) && $(kmake) $(defconfig)
+	mv $(builddirpa)/.config $(builddirpa)/.config.old
+	sed -e 's/^# \(CONFIG_MODVERSIONS\) is not set$$/\1=y/' \
+	  -e 's/.*CONFIG_LOCALVERSION_AUTO.*/# CONFIG_LOCALVERSION_AUTO is not set/' \
+	  $(builddirpa)/.config.old > $(builddirpa)/.config
+	cd $(builddirpa) && $(kmake) silentoldconfig
+	cd $(builddirpa) && $(kmake) prepare
+	cd $(builddirpa)/tools/perf && \
+		$(kmake) prefix=/usr HAVE_NO_LIBBFD=1 HAVE_CPLUS_DEMANGLE_SUPPORT=1 CROSS_COMPILE=$(CROSS_COMPILE) NO_LIBPYTHON=1 NO_LIBPERL=1 PYTHON=python2.7
+endif
+ifeq ($(do_tools_x86),true)
+	cd $(builddirpa)/tools/power/x86/x86_energy_perf_policy && make CROSS_COMPILE=$(CROSS_COMPILE)
+	cd $(builddirpa)/tools/power/x86/turbostat && make CROSS_COMPILE=$(CROSS_COMPILE)
+endif
+endif
+ifeq ($(do_cloud_tools),true)
+ifeq ($(do_tools_hyperv),true)
+	cd $(builddirpa)/tools/hv && make CFLAGS="-I$(headers_dir)/usr/include -I$(headers_dir)/usr/include/$(DEB_HOST_MULTIARCH)" CROSS_COMPILE=$(CROSS_COMPILE) hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon
+endif
+endif
+	@touch $@
+
+install-perarch: toolspkgdir = $(CURDIR)/debian/$(tools_pkg_name)
+install-perarch: cloudpkgdir = $(CURDIR)/debian/$(cloud_pkg_name)
+install-perarch: $(stampdir)/stamp-build-perarch
+	@echo Debug: $@
+	# Add the tools.
+ifeq ($(do_linux_tools),true)
+	install -d $(toolspkgdir)/usr/lib
+	install -d $(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+ifeq ($(do_tools_usbip),true)
+	install -m755 $(builddirpa)/tools/usb/usbip/bin/sbin/usbip \
+		$(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+	install -m755 $(builddirpa)/tools/usb/usbip/bin/sbin/usbipd \
+		$(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+endif
+ifeq ($(do_tools_acpidbg),true)
+	install -m755 $(builddirpa)/tools/power/acpi/acpidbg \
+		$(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+endif
+ifeq ($(do_tools_cpupower),true)
+	install -m755 $(builddirpa)/tools/power/cpupower/cpupower \
+		$(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+	# Install only the full versioned libcpupower.so.$(abi_release), not
+	# the usual symlinks to it.
+	install -m644 $(builddirpa)/tools/power/cpupower/libcpupower.so.$(abi_release) \
+		$(toolspkgdir)/usr/lib/
+endif
+ifeq ($(do_tools_perf),true)
+	install -m755 $(builddirpa)/tools/perf/perf $(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+endif
+ifeq ($(do_tools_x86),true)
+	install -m755 $(builddirpa)/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy \
+		$(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+	install -m755 $(builddirpa)/tools/power/x86/turbostat/turbostat \
+		$(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+endif
+endif
+ifeq ($(do_cloud_tools),true)
+ifeq ($(do_tools_hyperv),true)
+	install -d $(cloudpkgdir)/usr/lib
+	install -d $(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+	install -m755 $(builddirpa)/tools/hv/hv_kvp_daemon \
+		$(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+	install -m755 $(builddirpa)/tools/hv/hv_vss_daemon \
+		$(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+	install -m755 $(builddirpa)/tools/hv/hv_fcopy_daemon \
+		$(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+	install -m755 $(builddirpa)/tools/hv/lsvmbus \
+		$(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+endif
+endif
+
+binary-perarch: toolspkg = $(tools_pkg_name)
+binary-perarch: cloudpkg = $(cloud_pkg_name)
+binary-perarch: install-perarch
+	@echo Debug: $@
+ifeq ($(do_linux_tools),true)
+	$(call dh_all,$(toolspkg))
+endif
+ifeq ($(do_cloud_tools),true)
+	$(call dh_all,$(cloudpkg))
+endif
+
+binary-debs: signing = $(CURDIR)/debian/$(bin_pkg_name)-signing
+binary-debs: signingv = $(CURDIR)/debian/$(bin_pkg_name)-signing/$(release)-$(revision)
+binary-debs: signing_tar = $(src_pkg_name)_$(release)-$(revision)_$(arch).tar.gz
+binary-debs: binary-perarch $(addprefix binary-,$(flavours))
+	@echo Debug: $@
+ifeq ($(any_signed),true)
+	install -d $(signingv)/control
+	{ echo "tarball"; } >$(signingv)/control/options
+	cd $(signing) && tar czvf ../../../$(signing_tar) .
+	dpkg-distaddfile $(signing_tar) raw-signing -
+endif
+
+build-arch-deps-$(do_flavour_image_package) += $(addprefix $(stampdir)/stamp-build-,$(flavours))
+build-arch: $(build-arch-deps-true)
+	@echo Debug: $@
+
+ifeq ($(AUTOBUILD),)
+binary-arch-deps-$(do_flavour_image_package) += binary-udebs
+else
+binary-arch-deps-$(do_flavour_image_package) = binary-debs
+endif
+binary-arch-deps-$(do_libc_dev_package) += binary-arch-headers
+ifneq ($(do_common_headers_indep),true)
+binary-arch-deps-$(do_flavour_header_package) += binary-headers
+endif
+binary-arch: $(binary-arch-deps-true)
+	@echo Debug: $@
+
--- linux-4.4.0.orig/debian/rules.d/3-binary-indep.mk
+++ linux-4.4.0/debian/rules.d/3-binary-indep.mk
@@ -0,0 +1,219 @@
+build-indep:
+	@echo Debug: $@
+
+# The binary-indep dependency chain is:
+#
+# install-headers <- install-doc <- install-source <- install-tools <- install-indep <- binary-indep
+# install-headers <- binary-headers
+#
+indep_hdrpkg = $(indep_hdrs_pkg_name)
+indep_hdrdir = $(CURDIR)/debian/$(indep_hdrpkg)/usr/src/$(indep_hdrpkg)
+install-headers: prepare-indep
+	@echo Debug: $@
+	dh_testdir
+	dh_testroot
+
+ifeq ($(do_flavour_header_package),true)
+	install -d $(indep_hdrdir)
+	find . -path './debian' -prune -o -path './$(DEBIAN)' -prune \
+	  -o -path './include/*' -prune \
+	  -o -path './scripts/*' -prune -o -type f \
+	  \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \
+	     -name '*.sh' -o -name '*.pl' -o -name '*.lds' \) \
+	  -print | cpio -pd --preserve-modification-time $(indep_hdrdir)
+	cp -a scripts include $(indep_hdrdir)
+	(find arch -name include -type d -print | \
+		xargs -n1 -i: find : -type f) | \
+		cpio -pd --preserve-modification-time $(indep_hdrdir)
+endif
+
+docpkg = $(doc_pkg_name)
+docdir = $(CURDIR)/debian/$(docpkg)/usr/share/doc/$(docpkg)
+install-doc: prepare-indep
+	@echo Debug: $@
+ifeq ($(do_doc_package),true)
+	dh_testdir
+	dh_testroot
+
+	install -d $(docdir)
+ifeq ($(do_doc_package_content),true)
+	# First the html docs. We skip these for autobuilds
+	if [ -z "$(AUTOBUILD)" ]; then \
+		install -d $(docdir)/$(doc_pkg_name)-tmp; \
+		$(kmake) O=$(docdir)/$(doc_pkg_name)-tmp htmldocs; \
+		install -d $(docdir)/html; \
+		rsync -aL $(docdir)/$(doc_pkg_name)-tmp/Documentation/DocBook/ \
+			$(docdir)/html/; \
+		rm -rf $(docdir)/$(doc_pkg_name)-tmp; \
+	fi
+endif
+	# Copy the rest
+	cp -a Documentation/* $(docdir)
+	rm -rf $(docdir)/DocBook
+	find $(docdir) -name .gitignore | xargs rm -f
+endif
+
+srcpkg = linux-source-$(release)
+srcdir = $(CURDIR)/debian/$(srcpkg)/usr/src/$(srcpkg)
+balldir = $(CURDIR)/debian/$(srcpkg)/usr/src/$(srcpkg)/$(srcpkg)
+install-source: prepare-indep
+	@echo Debug: $@
+ifeq ($(do_source_package),true)
+
+	install -d $(srcdir)
+ifeq ($(do_source_package_content),true)
+	find . -path './debian' -prune -o -path './$(DEBIAN)' -prune -o \
+		-path './.*' -prune -o -print | \
+		cpio -pd --preserve-modification-time $(balldir)
+	(cd $(srcdir); tar cf - $(srcpkg)) | bzip2 -9c > \
+		$(srcdir)/$(srcpkg).tar.bz2
+	rm -rf $(balldir)
+	find './debian' './$(DEBIAN)' \
+		-path './debian/linux-*' -prune -o \
+		-path './debian/$(src_pkg_name)-*' -prune -o \
+		-path './debian/build' -prune -o \
+		-path './debian/files' -prune -o \
+		-path './debian/stamps' -prune -o \
+		-path './debian/tmp' -prune -o \
+		-print | \
+		cpio -pd --preserve-modification-time $(srcdir)
+	$(LN) $(srcpkg)/$(srcpkg).tar.bz2 $(srcdir)/..
+endif
+endif
+
+install-tools: toolspkg = $(tools_common_pkg_name)
+install-tools: toolsbin = $(CURDIR)/debian/$(toolspkg)/usr/bin
+install-tools: toolssbin = $(CURDIR)/debian/$(toolspkg)/usr/sbin
+install-tools: toolsman = $(CURDIR)/debian/$(toolspkg)/usr/share/man
+install-tools: hosttoolspkg = $(hosttools_pkg_name)
+install-tools: hosttoolsbin = $(CURDIR)/debian/$(hosttoolspkg)/usr/bin
+install-tools: hosttoolsman = $(CURDIR)/debian/$(hosttoolspkg)/usr/share/man
+install-tools: cloudpkg = $(cloud_common_pkg_name)
+install-tools: cloudbin = $(CURDIR)/debian/$(cloudpkg)/usr/bin
+install-tools: cloudsbin = $(CURDIR)/debian/$(cloudpkg)/usr/sbin
+install-tools: cloudman = $(CURDIR)/debian/$(cloudpkg)/usr/share/man
+install-tools: prepare-indep $(stampdir)/stamp-build-perarch
+	@echo Debug: $@
+
+ifeq ($(do_tools_common),true)
+ifneq ($(DEBIAN),debian.master)
+	echo "non-master branch building linux-tools-common, aborting"
+	exit 1
+endif
+	rm -rf $(builddir)/tools
+	install -d $(builddir)/tools
+	for i in *; do $(LN) $(CURDIR)/$$i $(builddir)/tools/; done
+	rm $(builddir)/tools/tools
+	rsync -a tools/ $(builddir)/tools/tools/
+
+	install -d $(toolsbin)
+	install -d $(toolsman)/man1
+
+	install -m755 debian/tools/generic $(toolsbin)/usbip
+	install -m755 debian/tools/generic $(toolsbin)/usbipd
+	install -m644 $(CURDIR)/tools/usb/usbip/doc/*.8 $(toolsman)/man1/
+
+	install -m755 debian/tools/generic $(toolsbin)/cpupower
+	install -m644 $(CURDIR)/tools/power/cpupower/man/*.1 $(toolsman)/man1/
+
+	install -m755 debian/tools/generic $(toolsbin)/perf
+
+	install -m755 debian/tools/generic $(toolsbin)/x86_energy_perf_policy
+	install -m755 debian/tools/generic $(toolsbin)/turbostat
+
+	cd $(builddir)/tools/tools/perf && make man
+	install -m644 $(builddir)/tools/tools/perf/Documentation/*.1 \
+		$(toolsman)/man1
+
+	install -d $(toolsman)/man8
+	install -m644 $(CURDIR)/tools/power/x86/x86_energy_perf_policy/*.8 $(toolsman)/man8
+	install -m644 $(CURDIR)/tools/power/x86/turbostat/*.8 $(toolsman)/man8
+
+ifeq ($(do_cloud_tools),true)
+ifeq ($(do_tools_hyperv),true)
+	install -d $(cloudsbin)
+	install -m755 debian/tools/generic $(cloudsbin)/hv_kvp_daemon
+	install -m755 debian/tools/generic $(cloudsbin)/hv_vss_daemon
+	install -m755 debian/tools/generic $(cloudsbin)/hv_fcopy_daemon
+	install -m755 debian/tools/generic $(cloudsbin)/lsvmbus
+	install -m755 debian/cloud-tools/hv_get_dhcp_info $(cloudsbin)
+	install -m755 debian/cloud-tools/hv_get_dns_info $(cloudsbin)
+	install -m755 debian/cloud-tools/hv_set_ifconfig $(cloudsbin)
+
+	install -d $(cloudman)/man8
+	install -m644 $(CURDIR)/tools/hv/*.8 $(cloudman)/man8
+endif
+endif
+
+ifeq ($(do_tools_acpidbg),true)
+	install -m755 debian/tools/generic $(toolsbin)/acpidbg
+endif
+
+endif
+
+ifeq ($(do_tools_host),true)
+	install -d $(hosttoolsbin)
+	install -d $(hosttoolsman)/man1
+
+	install -m 755 $(CURDIR)/tools/kvm/kvm_stat/kvm_stat $(hosttoolsbin)/
+
+	cd $(builddir)/tools/tools/kvm/kvm_stat && make man
+	install -m644 $(builddir)/tools/tools/kvm/kvm_stat/*.1 \
+		$(hosttoolsman)/man1
+endif
+
+prepare-indep:
+	@echo Debug: $@
+	dh_prep -i
+
+install-indep: install-headers install-doc install-source install-tools
+	@echo Debug: $@
+
+# This is just to make it easy to call manually. Normally done in
+# binary-indep target during builds.
+binary-headers: prepare-indep install-headers
+	@echo Debug: $@
+	dh_installchangelogs -p$(indep_hdrpkg)
+	dh_installdocs -p$(indep_hdrpkg)
+	dh_compress -p$(indep_hdrpkg)
+	dh_fixperms -p$(indep_hdrpkg)
+	dh_installdeb -p$(indep_hdrpkg)
+	$(lockme) dh_gencontrol -p$(indep_hdrpkg)
+	dh_md5sums -p$(indep_hdrpkg)
+	dh_builddeb -p$(indep_hdrpkg)
+
+binary-indep: cloudpkg = $(cloud_common_pkg_name)
+binary-indep: install-indep
+	@echo Debug: $@
+	dh_installchangelogs -i
+	dh_installdocs -i
+	dh_compress -i
+	dh_fixperms -i
+ifeq ($(do_tools_common),true)
+ifneq ($(DEBIAN),debian.master)
+	echo "non-master branch building linux-cloud-tools-common, aborting"
+	exit 1
+endif
+ifeq ($(do_cloud_tools),true)
+ifeq ($(do_tools_hyperv),true)
+	dh_installinit -p$(cloudpkg) -n --name hv-kvp-daemon
+	dh_installinit -p$(cloudpkg) -n --name hv-vss-daemon
+	dh_installinit -p$(cloudpkg) -n --name hv-fcopy-daemon
+	dh_installudev -p$(cloudpkg) -n --name hv-kvp-daemon
+	dh_installudev -p$(cloudpkg) -n --name hv-vss-daemon
+	dh_installudev -p$(cloudpkg) -n --name hv-fcopy-daemon
+	dh_systemd_enable -p$(cloudpkg)
+	dh_installinit -p$(cloudpkg) -o --name hv-kvp-daemon
+	dh_installinit -p$(cloudpkg) -o --name hv-vss-daemon
+	dh_installinit -p$(cloudpkg) -o --name hv-fcopy-daemon
+	dh_systemd_start -p$(cloudpkg)
+endif
+	# Keep intel_sgx service disabled by default, so add it after dh_systemd_enable
+	# and dh_systemd_start are called:
+	dh_installinit -p$(cloudpkg) --no-start --name intel-sgx-load-module
+endif
+endif
+	dh_installdeb -i
+	$(lockme) dh_gencontrol -i
+	dh_md5sums -i
+	dh_builddeb -i
--- linux-4.4.0.orig/debian/rules.d/4-checks.mk
+++ linux-4.4.0/debian/rules.d/4-checks.mk
@@ -0,0 +1,9 @@
+checks-%: install-%
+	@echo Debug: $@
+
+# Check the config against the known options list.
+config-prepare-check-%: $(stampdir)/stamp-prepare-tree-%
+	@echo Debug: $@
+	@perl -f $(DROOT)/scripts/config-check \
+		$(builddir)/build-$*/.config "$(arch)" "$*" "$(commonconfdir)" "$(skipconfig)"
+
--- linux-4.4.0.orig/debian/rules.d/5-udebs.mk
+++ linux-4.4.0/debian/rules.d/5-udebs.mk
@@ -0,0 +1,78 @@
+# Do udebs if not disabled in the arch-specific makefile
+binary-udebs: binary-debs
+	@echo Debug: $@
+ifeq ($(disable_d_i),)
+	@$(MAKE) --no-print-directory -f $(DROOT)/rules DEBIAN=$(DEBIAN) \
+		do-binary-udebs
+endif
+
+do-binary-udebs: linux_udeb_name=$(shell if echo $(src_pkg_name)|egrep -q '(linux-lts|linux-hwe)'; then echo $(src_pkg_name); else echo linux; fi)
+do-binary-udebs: debian/control
+	@echo Debug: $@
+	dh_testdir
+	dh_testroot
+
+	# unpack the kernels into a temporary directory
+	mkdir -p debian/d-i-${arch}
+
+	imagelist=$$(cat $(CURDIR)/$(DEBIAN)/d-i/kernel-versions | grep ^${arch} | gawk '{print $$3}') && \
+	for f in $$imagelist; do \
+	  i=$(release)-$(abinum)-$$f; \
+          for f in \
+		../linux-image-$$i\_$(release)-$(revision)_${arch}.deb \
+		../linux-image-unsigned-$$i\_$(release)-$(revision)_${arch}.deb \
+		../linux-modules-$$i\_$(release)-$(revision)_${arch}.deb \
+		../linux-modules-extra-$$i\_$(release)-$(revision)_${arch}.deb; \
+	  do \
+		  [ -f $$f ] && dpkg -x $$f debian/d-i-${arch}; \
+	  done; \
+	  /sbin/depmod -b debian/d-i-${arch} $$i; \
+	done
+
+	# kernel-wedge will error if no modules unless this is touched
+	touch $(CURDIR)/debian/build/no-modules
+
+	touch ignore-dups
+	export SOURCEDIR=$(CURDIR)/debian/d-i-${arch} && \
+	  cd $(builddir) && \
+	  kernel-wedge install-files && \
+	  kernel-wedge check
+
+        # Build just the udebs
+	dilist=$$(dh_listpackages -s | grep "\-di$$") && \
+	[ -z "$dilist" ] || \
+	for i in $$dilist; do \
+	  dh_fixperms -p$$i; \
+	  $(lockme) dh_gencontrol -p$$i; \
+	  dh_builddeb -p$$i; \
+	done
+	
+	# Generate the meta-udeb dependancy lists.
+	@gawk '										\
+		/^Package:/ {								\
+			package=$$2; flavour=""; parch="" }				\
+		(/Package-Type: udeb/ && package !~ /^$(linux_udeb_name)-udebs-/) {      \
+			match(package, "'$(release)'-'$(abinum)'-(.*)-di", bits);       \
+			flavour = bits[1];						\
+		}									\
+		(/^Architecture:/ && $$0 " " ~ / '$(arch)'/) {				\
+			parch=$$0;							\
+		}									\
+		(flavour != "" && parch != "") {					\
+			udebs[flavour] = udebs[flavour] package ", ";			\
+			flavour=""; parch="";						\
+		}                                                      			\
+		END {                                                  			\
+			for (flavour in udebs) {					\
+				package="$(linux_udeb_name)-udebs-" flavour;		\
+				file="debian/" package ".substvars";			\
+				print("udeb:Depends=" udebs[flavour]) > file;		\
+				metas="'$(builddir)'/udeb-meta-packages";		\
+				print(package) >metas					\
+			}								\
+		}									\
+	' <$(CURDIR)/debian/control
+	@while read i; do \
+		$(lockme) dh_gencontrol -p$$i; \
+		dh_builddeb -p$$i; \
+	done <$(builddir)/udeb-meta-packages
--- linux-4.4.0.orig/debian/scripts/build-fit
+++ linux-4.4.0/debian/scripts/build-fit
@@ -0,0 +1,40 @@
+#!/bin/sh -e
+# Creates a FIT image
+# $1: ITS file (FIT components description)
+# $2: list of space-separated dtb files
+# $3: kernel version
+# $4: kernel modules directory
+# $5: destination directory
+
+. debian/debian.env
+
+echo "Creating FIT image"
+fit_its="$1"
+dtb_files="$2"
+KERNEL_VERSION="$3"
+KERNEL_MODULES_D="$4"
+dest_d="$5"
+
+set -x
+fit_d=$dest_d
+mkdir -p "$fit_d"
+# Export variables to be used by hooks
+export KERNEL_VERSION
+export KERNEL_MODULES_D
+initrd_f=initrd.img
+mkinitramfs -o "$initrd_f"
+mv "$initrd_f" "$fit_d"
+
+mkdir -p "$fit_d"/dtbs/
+for dtb in $dtb_files; do
+    cp -f "$dtb" "$fit_d"/dtbs/
+done
+
+cp -f "$dest_d"/vmlinuz-* "$fit_d"/zImage
+cp -f "$fit_its" "$fit_d"
+
+cd "$fit_d"
+mkimage -D "-I dts -O dtb -p 2000" -f "${fit_its##*/}" fit-"$KERNEL_VERSION".fit
+cd -
+
+rm -rf "$fit_d"/"$initrd_f" "$fit_d"/dtbs/ "$fit_d"/zImage "$fit_d"/"${fit_its##*/}"
--- linux-4.4.0.orig/debian/scripts/config-check
+++ linux-4.4.0/debian/scripts/config-check
@@ -0,0 +1,159 @@
+#!/usr/bin/perl
+#
+# check-config -- check the current config for issues
+#
+use strict;
+use File::Basename;
+use File::Spec;
+
+my $P = 'check-config';
+
+my $test = -1;
+if ($ARGV[0] eq '--test') {
+	$test = $ARGV[1] + 0;
+} elsif ($#ARGV != 4) {
+	die "Usage: $P <config> <arch> <flavour> <commonconfig> <warn-only>\n";
+}
+
+my ($configfile, $arch, $flavour, $commonconfig, $warn_only) = @ARGV;
+
+my %values = ();
+
+# If we are in overridden then still perform the checks and emit the messages
+# but do not return failure.  Those items marked FATAL will alway trigger
+# failure.
+my $fail_exit = 1;
+$fail_exit = 0 if ($warn_only eq 'true' || $warn_only eq '1');
+my $exit_val = 0;
+
+# Load up the current configuration values -- FATAL if this fails
+print "$P: $configfile: loading config\n";
+open(CONFIG, "<$configfile") || die "$P: $configfile: open failed -- $! -- aborting\n";
+while (<CONFIG>) {
+	# Pull out values.
+	/^#*\s*(CONFIG_\w+)[\s=](.*)$/ or next;
+	if ($2 eq 'is not set') {
+		$values{$1} = 'n';
+	} else {
+		$values{$1} = $2;
+	}
+}
+close(CONFIG);
+
+sub read_annotations {
+    my ($filename) = @_;
+    my %annot;
+    my $form = 1;
+    my ($config, $value, $options);
+
+    # Keep track of the configs that shouldn't be appended because
+    # they were include_annot from another annotations file.
+    # That's a hash of undefs, aka a set.
+    my %noappend;
+
+    print "$P: $filename loading annotations\n";
+    open(my $fd, "<$filename") ||
+	die "$P: $filename: open failed -- $! -- aborting\n";
+    while (<$fd>) {
+	if (/^# FORMAT: (\S+)/) {
+	    die "$P: $1: unknown annotations format\n" if ($1 != 2 && $1 != 3);
+	    $form = $1;
+	}
+
+	# Format #3 adds the include directive on top of format #2:
+	if ($form == 3 && /^\s*include(\s|$)/) {
+	    # Include quoted or unquoted files:
+	    if (/^\s*include\s+"(.*)"\s*$/ || /^\s*include\s+(.*)$/) {
+		# The include is relative to the current file
+		my $include_filename = File::Spec->join(dirname($filename), $1);
+		# Append the include files
+		my %include_annot = read_annotations($include_filename);
+		%annot = ( %annot, %include_annot );
+		# And marked them to not be appended:
+		my %included_noappend;
+		# Discard the values and keep only the keys
+		@included_noappend{keys %include_annot} = ();
+		%noappend = ( %noappend, %included_noappend );
+		next;
+	    } else {
+		die "$P: Invalid include: $_";
+	    }
+	}
+
+	/^#/ && next;
+	chomp;
+	/^$/ && next;
+	/^CONFIG_/ || next;
+
+	if ($form == 1) {
+	    ($config, $value, $options) = split(' ', $_, 3);
+	} elsif ($form >= 2) {
+	    ($config, $options) = split(' ', $_, 2);
+	}
+
+	if (exists $noappend{$config}) {
+	    delete $annot{$config};
+	    delete $noappend{$config};
+	}
+	$annot{$config} = $annot{$config} . ' ' . $options;
+    }
+    close($fd);
+    return %annot;
+}
+
+# ANNOTATIONS: check any annotations marked for enforcement
+my $annotations = "$commonconfig/annotations";
+my %annot = read_annotations($annotations);
+
+my $pass = 0;
+my $total = 0;
+my ($config, $value, $options, $option, $check, $policy);
+for $config (keys %annot) {
+	$check = 0;
+	$options = $annot{$config};
+
+	$policy = undef;
+	while ($options =~ /\s*([^\s<]+)<(.*?)?>/g) {
+		($option, $value) = ($1, $2);
+
+		if ($option eq 'mark' && $value eq 'ENFORCED') {
+			$check = 1;
+
+		} elsif ($option eq 'policy') {
+			if ($value =~ /^{/) {
+				$value =~ s/:/=>/g;
+				$policy = eval($value);
+				warn "$@" if ($@);
+			} else {
+				$policy = undef;
+			}
+		}
+	}
+	if ($check == 1 && !defined($policy)) {
+		print "$P: INVALID POLICY (use policy<{...}>) $config$options\n";
+		$total++;
+		$check = 0;
+	}
+	if ($check) {
+		my $is = '-';
+		$is = $values{$config} if (defined $values{$config});
+
+		my $value = '-';
+		for my $which ("$arch-$flavour", "$arch-*", "*-$flavour", "$arch", "*") {
+			if (defined $policy->{$which}) {
+				$value = $policy->{$which};
+				last;
+			}
+		}
+		if ($is eq $value) {
+			$pass++;
+		} else {
+			print "$P: FAIL ($is != $value): $config$options\n";
+			$exit_val = $fail_exit;
+		}
+		$total++;
+	}
+}
+
+print "$P: $pass/$total checks passed -- exit $exit_val\n";
+exit $exit_val;
--- linux-4.4.0.orig/debian/scripts/control-create
+++ linux-4.4.0/debian/scripts/control-create
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+. debian/debian.env
+
+vars=$1
+any_signed=$2
+
+. $vars
+
+if [ "$is_sub" = "" ]; then
+	flavour=$(basename $vars | sed 's/.*\.//')
+	stub="${DEBIAN}/control.d/flavour-control.stub debian/control.d/flavour-buildinfo.stub"
+	if [ "$any_signed" = 'true' ]; then
+		sign_me_pkg="-unsigned"
+		sign_me_txt=" unsigned"
+		sign_peer_pkg=""
+	else
+		sign_me_pkg=""
+		sign_me_txt=""
+		sign_peer_pkg="-unsigned"
+	fi
+else
+	flavour=$(basename $vars .vars)
+	stub=${DEBIAN}/sub-flavours/control.stub
+fi
+
+cat $stub | grep -v '^#' | sed \
+	-e "s#FLAVOUR#$flavour#g"		\
+	-e "s#DESC#$desc#g"			\
+	-e "s#ARCH#$arch#g"			\
+	-e "s#SUPPORTED#$supported#g"		\
+	-e "s#TARGET#$target#g"			\
+	-e "s#BOOTLOADER#$bootloader#g" 	\
+	-e "s#=PROVIDES=#$provides#g"		\
+	-e "s#=CONFLICTS=#$conflicts#g"		\
+	-e "s#=SIGN-ME-PKG=#$sign_me_pkg#g"	\
+	-e "s#=SIGN-ME-TXT=#$sign_me_txt#g"	\
+	-e "s#=SIGN-PEER-PKG=#$sign_peer_pkg#g"
--- linux-4.4.0.orig/debian/scripts/dkms-build
+++ linux-4.4.0/debian/scripts/dkms-build
@@ -0,0 +1,204 @@
+#!/bin/bash
+set -e
+
+dkms_dir="$1"
+abi_flavour="$2"
+sign="$3"
+pkgname="$4"
+pkgdir="$5"
+package="$6"
+shift 6
+
+here=$(dirname "$(readlink -f "${0}")")
+
+srcdir=$(pwd)
+cd "$dkms_dir" || exit 1
+
+built_using_record()
+{
+	local subst="$1"
+	local built_using="$2"
+	if [ ! -f "$subst" ]; then
+		touch "$subst"
+	fi
+	if ! grep -q -s "^linux:BuiltUsing=" "$subst"; then
+		echo "linux:BuiltUsing=" >>"$subst"
+	fi
+	sed -i -e "s/^\(linux:BuiltUsing=.*\)/\1$built_using, /" "$subst"
+}
+
+# ABI: returns present in $? and located path in lpackage_path when found.
+package_present()
+{
+	for lpackage_path in "$1"_*.deb
+	do
+		break
+	done
+	[ -f "$lpackage_path" ]
+}
+
+# Download and extract the DKMS package -- note there may be more
+# than one package to install.
+for package_path in "$@"
+do
+	package_file=$(basename "$package_path")
+	echo "II: dkms-build downloading $package ($package_file)"
+	rpackage=$( echo "$package_path" | sed -e 's@.*/@@' -e 's@_.*@@' )
+	lpackage=$( echo "$rpackage" | sed -e 's@=.*@@' )
+
+	while true
+	do
+		if package_present "$lpackage"; then
+			break
+		fi
+		case "$package_path" in
+		pool/*)
+			# Attempt download from the launchpad librarian first.
+			"$here/file-downloader" "https://launchpad.net/ubuntu/+archive/primary/+files/$package_file" || true
+			if package_present "$lpackage"; then
+				break
+			fi
+
+			# Download from the available pools.
+			for pool in $( grep -h '^deb ' /etc/apt/sources.list /etc/apt/sources.list.d/*.list | awk '{print $2}' | sort -u )
+			do
+				if package_present "$lpackage"; then
+					break
+				fi
+				url="$pool/$package_path"
+				"$here/file-downloader" "$url" && break || true
+				# No components in PPAs.
+				url=$(echo "$url" | sed -e 's@/pool/[^/]*/@/pool/main/@')
+				"$here/file-downloader" "$url" && break || true
+			done
+			;;
+		http*:*)
+			"$here/file-downloader" "$package_path"
+			;;
+		*/*)
+			cp -p "$package_path" .
+			;;
+		*)
+			apt-get download "$rpackage"
+			;;
+		esac
+		break
+	done
+	if ! package_present "$lpackage"; then
+		echo "EE: $lpackage not found"
+		exit 1
+	fi
+
+	dpkg -x "$lpackage"_*.deb "$package"
+
+	lversion=$( echo "$lpackage_path" | sed -e 's@.*/@@' -e 's@_[^_]*$@@' -e 's@.*_@@')
+	#built_using_record "$srcdir/debian/$pkgname.substvars" "$built_using$lpackage (= $lversion)"
+done
+
+# Pick out the package/version from the dkms.conf.
+for dkms_conf in "$package/usr/src"/*/"dkms.conf"
+do
+	break
+done
+# It seems some packages have a # in the name which works fine if the
+# package is installed directly, but not so much if we build it out
+# of the normal location.
+sed -i -e '/^PACKAGE_NAME=/ s/#//g' "$dkms_conf"
+cat - <<'EOF' >>"$dkms_conf"
+POST_BUILD="ubuntu-save-objects ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/objects $POST_BUILD"
+EOF
+ubuntu_script="$(dirname "$dkms_conf")/ubuntu-save-objects"
+cat - <<'EOF' >"$ubuntu_script"
+#!/bin/sh
+from="$1"
+to="$2"
+script="$3"
+shift 2
+
+# Copy the objects.
+echo "II: copying objects to '$to'"
+mkdir -p "$to"
+(cd "$from" && find -name \*.o -o -name \*.o.ur-\* | cpio -Lpd "$to")
+
+# Call the original post_install script if there is one.
+[ "$script" = '' ] && exit 0
+
+shift
+exec "$(dirname "$0")/$script" "$@"
+EOF
+chmod +x "$ubuntu_script"
+dkms_package=$( sed -ne 's/PACKAGE_NAME="\(.*\)"/\1/p' "$dkms_conf" )
+dkms_version=$( sed -ne 's/PACKAGE_VERSION="\(.*\)"/\1/p' "$dkms_conf" )
+
+# Build the DKMS binaries.
+echo "II: dkms-build building $package"
+rc=0
+/usr/sbin/dkms build --no-prepare-kernel --no-clean-kernel \
+	-k "$abi_flavour" \
+	--sourcetree "$dkms_dir/source" \
+	--dkmstree "$dkms_dir/build" \
+	--kernelsourcedir "$dkms_dir/headers/linux-headers-$abi_flavour" \
+	"$dkms_conf" || rc=1
+
+# Find the log and add it to our own.
+for log in "$dkms_dir/build/$dkms_package/$dkms_version/$abi_flavour"/*/"log/make.log" "$dkms_dir/build/$dkms_package/$dkms_version/build/make.log"
+do
+	[ -f "$log" ] && break
+done
+sed -e "s@$dkms_dir@<<DKMSDIR>>@g" <"$log"
+
+# If this build failed then exit here.
+[ "$rc" != 0 ] && exit "$rc"
+
+# Install and optionally sign the modules we have built.
+pkgdir="$pkgdir/$package"
+echo "II: dkms-build installing $package into $pkgdir"
+install -d "$pkgdir"
+find "$dkms_dir/build/$dkms_package/$dkms_version/$abi_version" -name \*.ko |
+while read module; do
+	vmodule=$( basename "$module" )
+	case "$sign" in
+	--*)
+		echo "copying $vmodule"
+		cp "$module" "$pkgdir"
+		;;
+	*)
+		echo "signing $vmodule"
+		$sign "$module" "$pkgdir/$vmodule"
+		;;
+	esac
+done
+
+find "$dkms_dir/build/$dkms_package/$dkms_version/objects" -name \*.o -print | \
+while read object
+do
+	"$srcdir/debian/scripts/fix-filenames" "$object" "$dkms_dir"
+done
+
+# Finally see if there is a dkms-package specific post processor present.  Hand
+# it the original source directory, destination package directory, the objects
+# as squirreled away, and the log in case it is useful.  Finally pass a formed
+# signing command line in case we need to do that.
+dkms_build_specific="$srcdir/$0--$package"
+dkms_build_generic=$(echo "$dkms_build_specific" | sed -e 's/-[0-9][0-9]*$/-N/')
+for dkms_build in "$dkms_build_specific" "$dkms_build_generic"
+do
+	if [ ! -e "$dkms_build" ]; then
+		continue
+	fi
+	echo "II: dkms-build override $(basename "$dkms_build") found, executing"
+	$SHELL "$dkms_build" \
+		"$srcdir" \
+		"$dkms_dir/build/$dkms_package/$dkms_version/objects" \
+		"$log" \
+		"$dkms_dir" \
+		"$abi_flavour" \
+		"$sign" \
+		"$pkgname" \
+		"$pkgdir" \
+		"$package" \
+		"$@" || exit 1
+	break
+done
+
+echo "II: dkms-build build $package complete"
--- linux-4.4.0.orig/debian/scripts/file-downloader
+++ linux-4.4.0/debian/scripts/file-downloader
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+if [ "$#" -ne 1 ]; then
+	echo "Usage: $0 <url>" 1>&2
+	exit 1
+fi
+url="$1"
+
+to=$(basename "$url")
+
+count=0
+what='fetching'
+while :
+do
+	if [ "$count" -eq 20 ]; then
+		echo "EE: excessive redirects" 1>&2
+		exit 1
+	fi
+	count=$(($count+1))
+
+	echo "II: $what $url"
+
+	curl --silent --fail --show-error "$url" -o "$to" -D "$to.hdr" || exit 1
+	redirect=$(awk '/^Location: / {gsub(/^[[:space:]]+|[[:space:]]+$/,"",$2); print $2;}' "$to.hdr")
+	[ -z "$redirect" ] && break
+	what='  following'
+
+	url=$(echo "$redirect" | sed -e 's@https://launchpadlibrarian.net/@http://launchpadlibrarian.net/@')
+	if [ "$redirect" != "$url" ]; then
+		echo "II:   fixing $redirect"
+	fi
+done
+
+exit 0
--- linux-4.4.0.orig/debian/scripts/fix-filenames.c
+++ linux-4.4.0/debian/scripts/fix-filenames.c
@@ -0,0 +1,73 @@
+/*
+ * fix-filenames: find a specified pathname prefix and remove it from
+ *                C strings.
+ *
+ * Copyright (C) 2018 Canonical Ltd.
+ * Author: Andy Whitcroft <apw@canonical.com>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int
+main(int argc, char *argv[])
+{
+	int rc;
+	char *in_name;
+	char *prefix;
+	int prefix_len;
+	int in_fd;
+	struct stat in_info;
+	char *in;
+	off_t size;
+	int length;
+
+	if (argc != 3) {
+		fprintf(stderr, "Usage: %s <file> <prefix>\n", argv[0]);
+		exit(1);
+	}
+	in_name    = argv[1];
+	prefix     = argv[2];
+	prefix_len = strlen(prefix);
+
+	in_fd = open(in_name, O_RDWR);
+	if (in_fd < 0) {
+		perror("open input failed");
+		exit(1);
+	}
+
+	rc = fstat(in_fd, &in_info);
+	if (rc < 0) {
+		perror("fstat input failed");
+		exit(1);
+	}
+	size = in_info.st_size;
+	printf("%s %ld bytes\n", in_name + prefix_len + 1, size);
+
+	in = mmap((void *)0, size, PROT_READ|PROT_WRITE, MAP_SHARED, in_fd, (off_t)0);
+	if (!in) {
+		perror("mmap failed");
+		exit(1);
+	}
+
+	for (; size > 0; size--, in++) {
+		if (*in != *prefix)
+			continue;
+		if (strncmp(in, prefix, prefix_len) != 0)
+			continue;
+		length = strlen(in + prefix_len + 1) + 1;
+
+		/*
+		 * Copy the suffix portion down to the start and clear
+		 * the remainder of the space to 0.
+		 */
+		memmove(in, in + prefix_len + 1, length);
+		memset(in + length, '_', prefix_len);
+	}
+}
--- linux-4.4.0.orig/debian/scripts/link-headers
+++ linux-4.4.0/debian/scripts/link-headers
@@ -0,0 +1,42 @@
+#!/bin/bash -e
+
+. debian/debian.env
+
+hdrdir="$1"
+symdir="$2"
+flavour="$3"
+
+echo "Symlinking and copying headers for $flavour..."
+
+excludes="( -path ./debian -prune -o -path ./${DEBIAN} -prune -o -path ./.git ) -prune -o"
+
+(
+find . $excludes  -type f \
+	\( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \
+	-name '*.sh' -o -name '*.pl' -o -name '*.lds' \) -print
+find ./include ./scripts -name .gitignore -prune -o -type f -print
+find ./include -mindepth 1 -maxdepth 1 $excludes -type d -print
+) | (
+while read file; do
+	dir=$file
+	lastdir=$file
+
+	if [ -e "$hdrdir/$file" -o -L "$hdrdir/$file" ]; then
+		continue
+	fi
+
+	while [ ! -e "$hdrdir/$dir" -a ! -L "$hdrdir/$dir" ]; do
+		lastdir=$dir
+		dir=`dirname $dir`
+	done
+	# If the last item to exist is a symlink we assume all is good
+	if [ ! -L "$hdrdir/$dir" ]; then
+		# Turns things like "./foo" into "../"
+		deref="`echo -n $lastdir | sed -e 's/^\.//' -e's,/[^/]*,../,g'`"
+		item="`echo -n $lastdir | sed -e 's/^\.\///'`"
+		ln -s $deref$symdir/$item $hdrdir/$item
+	fi
+done
+)
+
+exit
--- linux-4.4.0.orig/debian/scripts/misc/final-checks
+++ linux-4.4.0/debian/scripts/misc/final-checks
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+debian="$1"
+abi="$2"
+abi=${abi%~*}
+
+. "$debian/etc/kernelconfig"
+
+fail=0
+
+failure()
+{
+	echo "EE: $@" 1>&2
+	fail=1
+}
+
+for arch in $archs
+do
+	for flavour in $(ls -1 "$debian/config/$arch/config.flavour."*)
+	do
+		flavour=$(echo "$flavour" | sed -e 's@.*/config.flavour.@@')
+	done
+done
+
+exit "$fail"
--- linux-4.4.0.orig/debian/scripts/misc/find-obsolete-firmware
+++ linux-4.4.0/debian/scripts/misc/find-obsolete-firmware
@@ -0,0 +1,91 @@
+#!/bin/bash
+#
+# Find all duplicate or obsolete firmware that is being carried
+# in the kernel firmware directory. Compare these files against
+# the linux-firmware package for the approriate release. For example,
+# assuming this is raring, then compare the kernel firmware files
+# against the raring branch of linux-firmware.
+#
+# Example: $0 ~/ubuntu/linux-firmware-raring
+
+USEAGE="$0 LINUX-FIRMWARE"
+
+. debian/debian.env
+
+NFWINFO="`find $DEBIAN -name fwinfo|wc -l`"
+if [ ! "$NFWINFO" = "1" ]
+then
+	echo Your repo is hosed. There can only be one fwinfo file.
+	find $DEBIAN -name fwinfo
+	exit 1
+fi
+
+FWINFO="`pwd`/`find $DEBIAN -name fwinfo`"
+
+if [ "$1" = "" ]
+then
+	echo $USEAGE
+	exit 1
+fi
+FW="$1"
+
+if [ ! -f $FW/WHENCE ]
+then
+	echo Bogus linux-firmware directory
+	exit 1
+fi
+if ! egrep -q "^firmware:" $FWINFO
+then
+	echo Bogus firmware info file
+	exit 1
+fi
+
+#
+# Prepare the tree and make firmware.
+#
+TEE="tee -a"
+LO=`pwd`/firmware.txt
+LF=`pwd`/lib/firmware
+rm -rf debian/build $LF $LO
+fakeroot debian/rules clean prepare-generic
+cp debian/build/build-generic/.config .
+mkdir -p $LF
+make firmware_install INSTALL_MOD_PATH=`pwd`
+
+(cd $LF
+find . -type f | while read f
+do
+	BN="`basename $f`"
+
+	if ! grep -q $BN $FWINFO
+	then
+		echo "Unused firmware: $f" | $TEE $LO
+	else
+		if [ -f $FW/$f ]
+		then
+			if ! cmp $FW/$f $f
+			then
+				echo "$f differs" | $TEE $LO
+			else
+				echo "$f is duplicated" | $TEE $LO
+			fi
+		else
+			echo "$f does not exist in $FW" | $TEE $LO
+		fi
+	fi
+done)
+
+#
+# Check for firmware files referenced by the kernel
+# that do not exist in either location.
+#
+cat $FWINFO | while read fwi f
+do
+	if [ -s lib/firmware/$f ] || [ -s $FW/$f ]
+	then
+		continue
+	else
+		echo "Missing firmware $f" | $TEE $LO
+	fi
+done
+
--- linux-4.4.0.orig/debian/scripts/misc/fw-to-ihex.sh
+++ linux-4.4.0/debian/scripts/misc/fw-to-ihex.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+F=$1
+if [ "$F" = "" ]
+then
+	echo You must supply a firmware file.
+	exit 1
+fi
+
+echo "unsigned char d[] = {" > $F.c
+hexdump -v -e '"\t" 8/1 "0x%02x, " "\n"' $F >> $F.c
+echo "};" >> $F.c
+sed -i 's/0x .*$//' $F.c
+
+O="`dirname $F`/`basename $F`.o"
+gcc -o $O -c $F.c
+objcopy -Oihex $F.o $F.ihex
+
--- linux-4.4.0.orig/debian/scripts/misc/gen-auto-reconstruct
+++ linux-4.4.0/debian/scripts/misc/gen-auto-reconstruct
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+if [ "$#" -ne 3 ]; then
+	echo "Usage: $0 <orig tag>|<base release> <reconstruct> <options>" 1>&2
+	exit 1
+fi
+tag="$1"
+reconstruct="$2"
+options="$3"
+
+case "$tag" in
+v*)	;;
+*)	tag="v${tag%.*}" ;;
+esac
+
+# Validate the tag.
+count=$( git tag -l "$tag" | wc -l )
+if [ "$count" != 1 ]; then
+	echo "$0: $tag: tag invalid" 1>&2
+	exit 1
+fi
+
+#git ls-tree -r --full-tree HEAD | grep ^120 | \
+#while read mode type blobid name
+
+(
+	# Identify all new symlinks since the proffered tag.
+	echo "# Recreate any symlinks created since the orig."
+	git diff "$tag.." --raw --no-renames | awk '(/^:000000 120000/ && $5 == "A") { print $NF }' | \
+	while read name
+	do
+		link=$( readlink "$name" )
+
+		echo "[ ! -L '$name' ] && ln -sf '$link' '$name'"
+	done
+
+	# Identify all removed files since the proffered tag.
+	echo "# Remove any files deleted from the orig."
+	git diff "$tag.." --raw --no-renames | awk '(/^:/ && $5 == "D") { print $NF }' | \
+	while read name
+	do
+		echo "rm -f '$name'"
+	done
+
+	# Identify files with execute permissions added since the proffered tag.
+	git diff "$tag.." --raw --no-renames | awk -F '[: \t]' '{print $2, $3, $NF }' | \
+	while IFS=" " read old new name
+	do
+		old=$( printf "0%s" $old )
+		new=$( printf "0%s" $new )
+		changed=$(( (old ^ new) & 0111 ))
+		if [ "$changed" -ne 0 ]; then
+			echo "chmod +x '$name'"
+		fi
+	done
+
+	# All done, make sure this does not complete in error.
+	echo "exit 0"
+) >"$reconstruct"
+
+(
+	# Identify all new symlinks since the proffered tag.
+	echo "# Ignore any symlinks created since the orig which are rebuilt by reconstruct."
+	git diff "$tag.." --raw --no-renames | awk '(/^:000000 120000/ && $5 == "A") { print $NF }' | \
+	while read name
+	do
+		echo "extend-diff-ignore=^$name\$"
+	done
+) >"$options.update"
+
+
+head='^## autoreconstruct -- begin$'
+foot='^## autoreconstruct -- end$'
+sed -i -e "
+	/$head/,/$foot/{
+		/$head/{
+			p;
+			r $options.update
+		};
+		/$foot/p;
+		d
+	}
+" "$options"
+rm -f "$options.update"
--- linux-4.4.0.orig/debian/scripts/misc/get-firmware
+++ linux-4.4.0/debian/scripts/misc/get-firmware
@@ -0,0 +1,62 @@
+#!/bin/bash
+#
+# Find all files in linux-firmware that are new or different since the previous release
+# and copy them into the kernel firmware directory. You should only do this on the
+# backport branch since it would be redundant on the released kernel. It assumed you've
+# unpacked linux-firmware from each release into separate directories.
+#
+# Example: $0 ~/ubuntu/linux-firmware-precise ~/ubuntu/linux-firmware-quantal
+
+if [ "$1" = "" ] || [ "$2" = "" ] || [ ! -f $1/WHENCE ] || [ ! -f $2/WHENCE ]
+then
+	echo You must supply 2 firmware directories.
+	exit 1
+fi
+
+if [ ! -f debian/debian.env ]
+then
+	echo You must run this script from the root of the repo
+	exit 1
+fi
+. debian/debian.env
+
+NFWINFO="`find $DEBIAN -name fwinfo|wc -l`"
+if [ ! "$NFWINFO" = "1" ]
+then
+	echo Your repo is hosed. There can only be one fwinfo file.
+	find $DEBIAN -name fwinfo
+	exit 1
+fi
+
+FWINFO="`pwd`/`find $DEBIAN -name fwinfo`"
+
+CDIR=`pwd`
+OFW=$1
+NFW=$2
+
+cd $NFW
+#
+# Find all files in $NFW that are new or different from $1
+#
+(find . -type f | egrep -v "debian|git|LICEN|WHEN|READ|Make|configure" | sed 's;\./;;' | \
+while read f
+do
+	if grep -q $f $FWINFO
+	then
+		if [ ! -f $OFW/$f ]
+		then
+			echo $f
+		elif ! cmp $f $OFW/$f > /dev/null
+		then
+			echo $f
+		fi
+	fi
+done) |\
+while read f
+do
+	mkdir -p $CDIR/firmware/`dirname $f`
+	if [ ! -f $CDIR/firmware/`dirname $f`/`basename $f`.ihex ]
+	then
+		cp -v $f $CDIR/firmware/`dirname $f`
+	fi
+done
--- linux-4.4.0.orig/debian/scripts/misc/git-ubuntu-log
+++ linux-4.4.0/debian/scripts/misc/git-ubuntu-log
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+
+import codecs
+import json
+import sys
+import textwrap
+import urllib.request
+
+sys.stdin = codecs.getreader("utf-8")(sys.stdin.detach())
+sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
+
+entries = []
+
+
+def add_entry(entry):
+    global tracking_bug
+
+    if entry and "ignore" not in entry:
+        combo = []
+        for bug in set(entry.get("bugs", [])):
+            combo.append(bug)
+        for cve in set(entry.get("cves", [])):
+            combo.append(cve)
+        combo = sorted(combo)
+
+        if len(combo) == 0:
+            if entry.get("subject", "").startswith("UBUNTU"):
+                combo = "__packaging__"
+            else:
+                combo = "__mainline__"
+        else:
+            if entry.get("subject", "") == "UBUNTU: link-to-tracker: update tracking bug":
+                tracking_bug = combo
+            if combo not in keys:
+                keys.append(combo)
+
+        entry["key"] = combo
+        entries.append(entry)
+
+
+# Suck up the git log output and extract the information we need.
+keys = []
+tracking_bug = None
+entry = None
+subject_wait = False
+for line in sys.stdin:
+    if line.startswith("commit "):
+        add_entry(entry)
+        entry = {}
+        subject_wait = True
+
+    elif line.startswith("Author: "):
+        bits = line.strip().split(maxsplit=1)
+        entry["author"] = bits[1]
+
+    elif subject_wait and line.startswith("    "):
+        subject_wait = False
+        entry["subject"] = line.strip()
+
+    elif line.startswith("    BugLink: "):
+        bits = line.strip().split(maxsplit=2)
+        if len(bits) > 2:
+            # There is text after the URL, so use that (after stripping the
+            # enclosing characters)
+            entry.setdefault("bugs", []).append(bits[2][1:-1])
+        elif "launchpad.net" in bits[1]:
+            # Extract the bug number from the launchpad URL
+            bits = bits[1].split("/")
+            entry.setdefault("bugs", []).append(bits[-1])
+
+    elif line.startswith("    CVE-"):
+        entry.setdefault("cves", []).append(line.strip())
+
+    elif line.startswith("    Ignore:"):
+        entry["ignore"] = True
+
+    elif line.startswith("    Properties:"):
+        for prop in line.strip().split()[1:]:
+            if prop in ("ignore", "no-changelog"):
+                entry["ignore"] = True
+
+add_entry(entry)
+
+entries.reverse()
+
+# Go through the entries and clear out authors for upstream commits.
+for entry in entries:
+    if entry["subject"].startswith("UBUNTU:"):
+        entry["subject"] = entry["subject"][7:].strip()
+    else:
+        del entry["author"]
+
+# Lump everything without a bug at the bottom.
+keys.append("__packaging__")
+keys.append("__mainline__")
+
+# Ensure we list the tracking bug updates first.
+if tracking_bug is not None:
+    keys.remove(tracking_bug)
+    keys.insert(0, tracking_bug)
+
+emit_nl = False
+for key in keys:
+    if key == "__packaging__":
+        title_set = ["Miscellaneous Ubuntu changes"]
+    elif key == "__mainline__":
+        title_set = ["Miscellaneous upstream changes"]
+    else:
+        title_set = []
+        for bug in key:
+            if bug.startswith("CVE-"):
+                title_set.append(bug)
+            elif bug.isdigit():
+                # Assume that it is an LP bug number if 'bug' contains only digits
+                bug_info = None
+
+                try:
+                    # urllib.request.urlcleanup()
+                    request = urllib.request.Request("https://api.launchpad.net/devel/bugs/" + bug)
+                    request.add_header("Cache-Control", "no-cache")
+                    with urllib.request.urlopen(request) as response:
+                        data = response.read()
+                        bug_info = json.loads(data.decode("utf-8"))
+
+                    title = bug_info["title"]
+                    if "description" in bug_info:
+                        for line in bug_info["description"].split("\n"):
+                            if line.startswith("Kernel-Description:"):
+                                title = line.split(" ", 1)[1]
+
+                except urllib.error.HTTPError:
+                    title = "INVALID or PRIVATE BUG"
+
+                title += " (LP###" + bug + ")"
+                title_set.append(title)
+            else:
+                # Finally treat 'bug' itself as the title
+                title_set.append(bug)
+
+    emit_title = True
+    for entry in entries:
+        if entry["key"] != key:
+            continue
+
+        if emit_title:
+            if emit_nl:
+                print("")
+            emit_nl = True
+
+            title_lines = textwrap.wrap("#// ".join(title_set), 76)
+            print("  * " + title_lines[0].replace("LP###", "LP: #").replace("#//", " //"))
+            for line in title_lines[1:]:
+                line = line.replace("LP###", "LP: #").replace("#//", " //")
+                print("    " + line)
+
+            emit_title = False
+
+        if key != tracking_bug or (key == tracking_bug and entry["subject"] != "link-to-tracker: update tracking bug"):
+            title_lines = textwrap.wrap(entry["subject"], 76)
+            print("    - " + title_lines[0])
+            for line in title_lines[1:]:
+                line = line.replace("LP###", "LP: #")
+                print("      " + line)
--- linux-4.4.0.orig/debian/scripts/misc/insert-changes.pl
+++ linux-4.4.0/debian/scripts/misc/insert-changes.pl
@@ -0,0 +1,43 @@
+#!/usr/bin/perl -w
+
+my $debian;
+$droot = $ARGV[0] if (defined $ARGV[0]);
+$droot = 'debian' if (!defined $droot);
+$debian = $ARGV[1] if (defined $ARGV[1]);
+$debian = 'debian.master' if (!defined $debian);
+
+system("make -s -f $droot/rules printchanges > $debian/changes");
+
+open(CHANGELOG, "< $debian/changelog") or die "Cannot open changelog";
+open(CHANGES, "< $debian/changes") or die "Cannot open new changes";
+open(NEW, "> $debian/changelog.new") or die "Cannot open new changelog";
+
+$printed = 0;
+my $skip_newline = 0;
+
+while (<CHANGELOG>) {
+	if (/^  CHANGELOG: /) {
+		next if $printed;
+
+		$skip_newline = 1;
+		while (<CHANGES>) {
+			$skip_newline = 0;
+			print NEW;
+		}
+
+		$printed = 1;
+	} else {
+		if (/^$/ && $skip_newline == 1) {
+			$skip_newline = 0;
+			next;
+		}
+		print NEW;
+	}
+}
+
+close(NEW);
+close(CHANGES);
+close(CHANGELOG);
+
+rename("$debian/changelog.new", "$debian/changelog");
+unlink("$debian/changes");
--- linux-4.4.0.orig/debian/scripts/misc/insert-mainline-changes
+++ linux-4.4.0/debian/scripts/misc/insert-mainline-changes
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+if ($#ARGV != 2) {
+	warn "Usage: $0 <changelog> <to> <range>\n";
+	die  "       $0 debian.master/changelog v3.2.3 v3.2.2..v3.2.3\n";
+}
+my ($changelog, $to, $range) = @ARGV;
+
+my @changes = ();
+
+push(@changes, "\n");
+push(@changes, "  [ Upstream Kernel Changes ]\n\n");
+push(@changes, "  * rebase to $to\n");
+
+open(LOG, "git log '$range'|") || die "$0: git log failed: - $!\n";
+while (<LOG>) {
+	if (m@BugLink: .*launchpad.net/.*/([0-9]+)\s$@) {
+		push(@changes, "    - LP: #$1\n");
+	}
+}
+close(LOG);
+
+open(CHANGELOG, "< $changelog") or die "Cannot open changelog";
+open(NEW, "> $changelog.new") or die "Cannot open new changelog";
+
+$printed = 3;
+while (<CHANGELOG>) {
+	if (/^  CHANGELOG: /) {
+		$printed--;
+		print NEW;
+		if ($printed == 0) {
+			print NEW @changes;
+		}
+		next;
+	}
+	print NEW;
+}
+
+close(NEW);
+close(CHANGELOG);
+
+rename("$changelog.new", "$changelog");
--- linux-4.4.0.orig/debian/scripts/misc/insert-ubuntu-changes
+++ linux-4.4.0/debian/scripts/misc/insert-ubuntu-changes
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+if ($#ARGV != 2 && $#ARGV != 3) {
+	die "Usage: $0 <changelog> <stop at> <start at> [<source changelog>]\n";
+}
+if ($#ARGV == 2) {
+	push(@ARGV, "debian.master/changelog")
+}
+my ($changelog, $end, $start, $source_changelog) = @ARGV;
+
+$end =~ s/^\D+//;
+$start =~ s/^\D+//;
+
+sub version_cmp($$) {
+	my @a = split(/[\.-]+/, $_[0]);
+	my @b = split(/[\.-]+/, $_[1]);
+	for (my $i = 1;; $i++) {
+		if (!defined $a[$i]) {
+			if (!defined $b[$i]) {
+				return 0;
+			}
+			return -1;
+		}
+		if (!defined $b[$i]) {
+			return 1;
+		}
+		if ($a[$i] < $b[$i]) {
+			return -1;
+		}
+		if ($a[$i] > $b[$i]) {
+			return 1;
+		}
+	}
+}
+
+my @changes = ();
+my $output = 0;
+open(CHG, "<$source_changelog") ||
+	open(CHG, "<debian/changelog") ||
+	die "$0: debian/changelog: open failed - $!\n";
+while (<CHG>) {
+	if (/^\S+\s+\((.*)\)/) {
+		if (version_cmp($1, $end) <= 0) {
+			last;
+		}
+		if ($1 eq $start) {
+			$output = 1;
+		}
+		if ($output) {
+			push(@changes, "\n  [ Ubuntu: $1 ]\n\n");
+			next;
+		}
+	}
+	next if ($output == 0);
+
+	next if (/^\s*$/);
+	next if (/^\s--/);
+	next if (/^\s\s[^\*\s]/);
+
+	push(@changes, $_);
+}
+close(CHG);
+
+open(CHANGELOG, "< $changelog") or die "Cannot open changelog";
+open(NEW, "> $changelog.new") or die "Cannot open new changelog";
+
+$printed = 3;
+while (<CHANGELOG>) {
+	if (/^  CHANGELOG: /) {
+		$printed--;
+		print NEW;
+		if ($printed == 0) {
+			print NEW @changes;
+		}
+		next;
+	}
+	print NEW;
+}
+
+close(NEW);
+close(CHANGELOG);
+
+rename("$changelog.new", "$changelog");
--- linux-4.4.0.orig/debian/scripts/misc/kernelconfig
+++ linux-4.4.0/debian/scripts/misc/kernelconfig
@@ -0,0 +1,172 @@
+#!/bin/bash
+
+. debian/debian.env
+
+# Script to merge all configs and run 'make silentoldconfig' on it to wade out bad juju.
+# Then split the configs into distro-commmon and flavour-specific parts
+
+# We have to be in the top level kernel source directory
+if [ ! -f MAINTAINERS ] || [ ! -f Makefile ]; then
+	echo "This does not appear to be the kernel source directory." 1>&2
+	exit 1
+fi
+
+mode=${1:?"Usage: $0 [oldconfig|editconfig]"}
+yes=0
+case "$mode" in
+    update*configs)  mode='silentoldconfig' ;;
+    default*configs) mode='oldconfig'; yes=1 ;;
+    edit*configs)    ;; # All is good
+    gen*configs)     mode='genconfigs' ;; # All is good
+    dump*configs)    mode='config'; yes=1 ;;
+    *) echo "$0 called with invalid mode" 1>&2
+       exit 1 ;;
+esac
+kerneldir="`pwd`"
+confdir="$kerneldir/${DEBIAN}/config"
+variant="$2"
+
+. $DEBIAN/etc/kernelconfig
+
+bindir="`pwd`/${DROOT}/scripts/misc"
+common_conf="$confdir/config.common.$family"
+tmpdir=`mktemp -d`
+mkdir "$tmpdir/CONFIGS"
+
+if [ "$mode" = "genconfigs" ]; then
+	keep=1
+	mode="oldconfig"
+	test -d CONFIGS || mkdir CONFIGS
+fi
+
+for arch in $archs; do
+	rm -rf build
+	mkdir build
+
+	# Map debian archs to kernel archs
+	case "$arch" in
+		ppc64|ppc64el)	kernarch="powerpc"	;;
+		amd64)		kernarch="x86_64"	;;
+		lpia)		kernarch="x86" 		;;
+		sparc)		kernarch="sparc64"	;;
+		armel|armhf)	kernarch="arm"		;;
+		s390x)		kernarch="s390"		;;
+		*)		kernarch="$arch"	;;
+	esac
+
+	archconfdir=$confdir/$arch
+	flavourconfigs=$(cd $archconfdir && ls config.flavour.*)
+
+	# Merge configs
+	# We merge config.common.ubuntu + config.common.<arch> +
+	# config.flavour.<flavour>
+
+	for config in $flavourconfigs; do
+		fullconf="$tmpdir/$arch-$config-full"
+		case $config in
+		*)
+			: >"$fullconf"
+			if [ -f $common_conf ]; then
+				cat $common_conf >> "$fullconf"
+			fi
+			if [ -f $archconfdir/config.common.$arch ]; then
+				cat $archconfdir/config.common.$arch >> "$fullconf"
+			fi
+			cat "$archconfdir/$config" >>"$fullconf"
+			if [ -f $confdir/OVERRIDES ]; then
+				cat $confdir/OVERRIDES >> "$fullconf"
+			fi
+			;;
+		esac
+	done
+
+	for config in $flavourconfigs; do
+		if [ -f $archconfdir/$config ]; then
+			fullconf="$tmpdir/$arch-$config-full"
+			cat "$fullconf" > build/.config
+			# Call oldconfig or menuconfig
+			case "$mode" in
+			    editconfigs)
+				# Interactively edit config parameters
+				while : ; do
+					echo -n "Do you want to edit config: $arch/$config? [Y/n] "
+					read choice
+					
+					case "$choice" in
+					y* | Y* | "" )
+						make O=`pwd`/build ARCH=$kernarch menuconfig
+						break ;;
+					n* | N* )
+						break ;;
+					*)
+						echo "Entry not valid"
+					esac
+				done
+				;;
+			    *)
+				echo "* Run $mode (yes=$yes) on $arch/$config ..."
+				if [ "$yes" -eq 1 ]; then
+					yes "" | make O=`pwd`/build ARCH=$kernarch "$mode"
+				else
+					make O=`pwd`/build ARCH=$kernarch "$mode"
+				fi ;;
+			esac
+			cat build/.config > $archconfdir/$config
+			cat build/.config > "$tmpdir/CONFIGS/$arch-$config"
+			if [ "$keep" = "1" ]; then
+				cat build/.config > CONFIGS/$arch-$config
+			fi
+		else
+			echo "!! Config not found $archconfdir/$config..."
+		fi
+	done
+
+	echo "Running splitconfig.pl for $arch"
+	echo
+
+	# Can we make this more robust by avoiding $tmpdir completely?
+	# This approach was used for now because I didn't want to change
+	# splitconfig.pl
+	(cd $archconfdir; $bindir/splitconfig.pl config.flavour.*; mv config.common \
+	 config.common.$arch; cp config.common.$arch $tmpdir)
+done
+
+rm -f $common_conf
+
+# Now run splitconfig.pl on all the config.common.<arch> copied to
+# $tmpdir
+(cd $tmpdir; $bindir/splitconfig.pl *)
+(
+	cd $confdir;
+	rm -f *-full
+	grep -v 'is UNMERGABLE' <$tmpdir/config.common >$common_conf
+	for arch in $archs; do
+		grep -v 'is UNMERGABLE' <$tmpdir/config.common.$arch \
+			>$arch/config.common.$arch
+	done
+)
+
+echo ""
+echo "Running config-check for all configurations ..."
+echo ""
+fail=0
+for arch in $archs; do
+	archconfdir=$confdir/$arch
+	flavourconfigs=$(cd $archconfdir && ls config.flavour.*)
+	for config in $flavourconfigs; do
+		flavour="${config##*.}"
+		if [ -f $archconfdir/$config ]; then
+			fullconf="$tmpdir/CONFIGS/$arch-$config"
+			"$bindir/../config-check" "$fullconf" "$arch" "$flavour" "$confdir" "0" || let "fail=$fail+1"
+		fi
+	done
+done
+
+if [ "$fail" != 0 ]; then
+	echo ""
+	echo "*** ERROR: $fail config-check failures detected"
+	echo ""
+fi
+
+rm -rf build
+
--- linux-4.4.0.orig/debian/scripts/misc/retag
+++ linux-4.4.0/debian/scripts/misc/retag
@@ -0,0 +1,34 @@
+#!/usr/bin/perl -w
+
+open(TAGS, "git tag -l |") or die "Could not get list of tags";
+@tags = <TAGS>;
+close(TAGS);
+
+open(LOGS, "git log --pretty=short |") or die "ERROR: Calling git log";
+my $commit = "";
+
+while (<LOGS>) {
+	my $origtag;
+
+	if (m|^commit (.*)$|) {
+		$commit = $1;
+		next;
+	}
+
+	m|\s*UBUNTU: (Ubuntu-2\.6\..*)| or next;
+
+	$tag = $1;
+
+	($origtag) = grep(/^$tag.orig$/, @tags);
+
+	if (!defined($origtag)) {
+		print "I: Adding original tag for $tag\n";
+		system("git tag -m $tag $tag.orig $tag");
+	}
+
+	print "I: Tagging $tag => $commit\n";
+
+	system("git tag -f -m $tag $tag $commit");
+}
+
+close(LOGS);
--- linux-4.4.0.orig/debian/scripts/misc/splitconfig.pl
+++ linux-4.4.0/debian/scripts/misc/splitconfig.pl
@@ -0,0 +1,107 @@
+#!/usr/bin/perl -w
+
+%allconfigs = ();
+%common = ();
+
+print "Reading config's ...\n";
+
+for $config (@ARGV) {
+	# Only config.*
+	next if $config !~ /^config\..*/;
+	# Nothing that is disabled, or remnant
+	next if $config =~ /.*\.(default|disabled|stub)$/;
+
+	%{$allconfigs{$config}} = ();
+
+	print "  processing $config ... ";
+
+	open(CONFIG, "< $config");
+
+	while (<CONFIG>) {
+		# Skip comments
+		/^#*\s*CONFIG_(\w+)[\s=](.*)$/ or next;
+
+		${$allconfigs{$config}}{$1} = $2;
+
+		$common{$1} = $2;
+	}
+
+	close(CONFIG);
+
+	print "done.\n";
+}
+
+print "\n";
+
+print "Merging lists ... \n";
+
+# %options - pointer to flavour config inside the allconfigs array
+for $config (keys(%allconfigs)) {
+	my %options = %{$allconfigs{$config}};
+
+	print "   processing $config ... ";
+
+	for $key (keys(%common)) {
+		next if not defined $common{$key};
+
+		# If we don't have the common option, then it isn't
+		# common. If we do have that option, it must have the same
+		# value.  EXCEPT where this file does not have a value at all
+		# which may safely be merged with any other value; the value
+		# will be elided during recombination of the parts.
+		if (!defined($options{$key})) {
+			# Its ok really ... let it merge
+		} elsif (not defined($options{$key})) {
+			undef $common{$key};
+		} elsif ($common{$key} ne $options{$key}) {
+			undef $common{$key};
+		}
+	}
+
+	print "done.\n";
+}
+
+print "\n";
+
+print "Creating common config ... ";
+
+open(COMMON, "> config.common");
+print COMMON "#\n# Common config options automatically generated by splitconfig.pl\n#\n";
+
+for $key (sort(keys(%common))) {
+	if (not defined $common{$key}) {
+		print COMMON "# CONFIG_$key is UNMERGABLE\n";
+	} elsif ($common{$key} eq "is not set") {
+		print COMMON "# CONFIG_$key is not set\n";
+	} else {
+		print COMMON "CONFIG_$key=$common{$key}\n";
+	}
+}
+close(COMMON);
+
+print "done.\n\n";
+
+print "Creating stub configs ...\n";
+
+for $config (keys(%allconfigs)) {
+	my %options = %{$allconfigs{$config}};
+
+	print "  processing $config ... ";
+
+	open(STUB, "> $config");
+	print STUB "#\n# Config options for $config automatically generated by splitconfig.pl\n#\n";
+
+	for $key (sort(keys(%options))) {
+		next if defined $common{$key};
+
+		if ($options{$key} =~ /^is /) {
+			print STUB "# CONFIG_$key $options{$key}\n";
+		} else {
+			print STUB "CONFIG_$key=$options{$key}\n";
+		}
+	}
+
+	close(STUB);
+
+	print "done.\n";
+}
--- linux-4.4.0.orig/debian/scripts/misc/update-aufs.sh
+++ linux-4.4.0/debian/scripts/misc/update-aufs.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+AUFS=aufs4-standalone
+
+#
+# Before you run this be sure you've removed or reverted the 'UBUNTU: SAUCE: AUFS" patch.
+#
+#
+# Make sure the current working directory is at the top of the
+# linux tree.
+#
+if ! grep PATCHLEVEL Makefile
+then
+	echo "You must run this script from the top of the linux tree"
+	exit 1
+fi
+
+clean=0
+if [ "$#" = 1 ]; then
+	AUFS="$1"
+else
+	clean=1
+	rm -rf ${AUFS}
+	git clone https://github.com/sfjro/aufs4-standalone.git ${AUFS}
+	(cd ${AUFS}; git checkout -b aufs4.x-rcN remotes/origin/aufs4.x-rcN)
+fi
+
+cp ${AUFS}/include/uapi/linux/aufs_type.h include/uapi/linux
+rsync -av ${AUFS}/fs/ fs/
+rsync -av ${AUFS}/Documentation/ Documentation/
+
+PATCHES="${PATCHES} aufs4-kbuild.patch"
+PATCHES="${PATCHES} aufs4-base.patch"
+PATCHES="${PATCHES} aufs4-mmap.patch"
+PATCHES="${PATCHES} aufs4-standalone.patch"
+PATCHES="${PATCHES} aufs4-loopback.patch"
+#PATCHES="${PATCHES} vfs-ino.patch"
+PATCHES="${PATCHES} tmpfs-idr.patch"
+
+for i in ${PATCHES}
+do
+	patch -p1 < ${AUFS}/$i
+done
+
+[ "$clean" = 1 ] && rm -rf ${AUFS}
+git add mm/prfile.c
+git add -u
+find . -name "*.orig" | xargs rm
+find . |grep aufs | xargs git add
+git commit -s -m"UBUNTU: SAUCE: AUFS"
--- linux-4.4.0.orig/debian/scripts/misc/update-zfs.sh
+++ linux-4.4.0/debian/scripts/misc/update-zfs.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Update spl/zfs from the Ubuntu archive. You will have to manually check
+# to see if the version has been updated.
+#
+SPL_MAJOR_VER=${_SPL_MAJOR_VER:-0.6.5.4}
+SPL_MINOR_VER=${_SPL_MINOR_VER:-0ubuntu1}
+SPL_DKMS=${_SPL_DKMS:-http://archive.ubuntu.com/ubuntu/pool/universe/s/spl-linux/spl-dkms_${SPL_MAJOR_VER}-${SPL_MINOR_VER}_amd64.deb}
+
+ZFS_MAJOR_VER=${_ZFS_MAJOR_VER:-0.6.5.4}
+ZFS_MINOR_VER=${_ZFS_MINOR_VER:-0ubuntu1}
+ZFS_DKMS=${_ZFS_DKMS:-http://archive.ubuntu.com/ubuntu/pool/universe/z/zfs-linux/zfs-dkms_${ZFS_MAJOR_VER}-${ZFS_MINOR_VER}_amd64.deb}
+
+function update_from_archive {
+
+	URL=$1
+	DEST_DIR=$2
+	VER=$3
+
+	rm -rf ${DEST_DIR}.tmp
+	wget -O ${DEST_DIR}.deb ${URL}
+	dpkg -x ${DEST_DIR}.deb ${DEST_DIR}.tmp
+	mkdir -p ${DEST_DIR}
+	rsync -a --delete ${DEST_DIR}.tmp/usr/src/${DEST_DIR}-${VER}*/ ${DEST_DIR}/
+	rm -rf ${DEST_DIR}.deb ${DEST_DIR}.tmp
+	find ${DEST_DIR} -type f | while read f;do git add -f $f;done
+}
+
+update_from_archive ${SPL_DKMS} spl ${SPL_MAJOR_VER}
+update_from_archive ${ZFS_DKMS} zfs ${ZFS_MAJOR_VER}
+
+git add -u
+git commit -s -m"UBUNTU: SAUCE: (noup) Update spl to ${SPL_MAJOR_VER}-${SPL_MINOR_VER}, zfs to ${ZFS_MAJOR_VER}-${ZFS_MINOR_VER}"
--- linux-4.4.0.orig/debian/scripts/module-inclusion
+++ linux-4.4.0/debian/scripts/module-inclusion
@@ -0,0 +1,104 @@
+#!/bin/bash
+
+#
+# Build a new directory of modules based on an inclusion list.
+# The includsion list format must be a bash regular expression.
+#
+# usage: $0 ROOT INCLUSION_LIST
+# example: $0 \
+#       debian/build/build-virtual-ALL debian/build/build-virtual \
+#	debian.master/control.d/virtual.inclusion-list \
+#	virtual.depmap
+master=0
+if [ "$1" = "--master" ]; then
+	master=1
+	shift
+fi
+
+ROOT=$1
+NROOT=$2
+ILIST=$3
+DEPMAP=$4
+
+tmp="/tmp/module-inclusion.$$"
+
+#
+# Prep a destination directory.
+#
+mkdir -p ${NROOT}
+
+{
+	# Copy over the framework into the master package.
+	if  [ "$master" -eq 1 ]; then
+		(cd ${ROOT}; find . ! -name "*.ko" -type f)
+	fi
+
+	# Copy over modules by name or pattern.
+	while read -r i
+	do
+		#
+		# 'find' blurts a warning if it cannot find any ko files.
+		#
+		case "$i" in
+		\!*)
+			(cd ${ROOT}; ${i#!} || true)
+			;;
+		*\**)
+			(cd ${ROOT}; eval find "${i}" -name "*.ko" || true)
+			;;
+		*)
+			echo "$i"
+			;;
+		esac
+	done <"${ILIST}"
+} >"$tmp"
+
+# Copy over the listed modules.
+while read i
+do
+	# If this is already moved over, all is good.
+	if [ -f "${NROOT}/$i" ]; then
+		:
+
+	# If present in the source, moved it over.
+	elif [ -f "${ROOT}/$i" ]; then
+		mkdir -p "${NROOT}/`dirname $i`"
+		mv "${ROOT}/$i" "${NROOT}/$i"
+
+	# Otherwise, it is missing.
+	else
+		echo "Warning: Could not find ${ROOT}/$i" 1>&2
+	fi
+done <"$tmp"
+
+# Copy over any dependancies, note if those are missing
+# we know they are in a pre-requisite package as they must
+# have existed at depmap generation time, and can only have
+# moved into a package.
+let n=0 || true
+while [ -s "$tmp" ]
+do
+	let n="$n+1" || true
+	[ "$n" = "20" ] && break || true
+
+	echo "NOTE: pass $n: dependency scan" 1>&2
+
+	while read i
+	do
+		grep "^$i " "$DEPMAP" | \
+		while read m d
+		do
+			if [ -f "${ROOT}/$d" ]; then
+				echo "NOTE: pass $n: ${i} pulls in ${d}" 1>&2
+				echo "$d"
+				mkdir -p "${NROOT}/`dirname $d`"
+				mv "${ROOT}/$d" "${NROOT}/$d"
+			fi
+		done
+	done <"$tmp" >"$tmp.new"
+	mv -f "$tmp.new" "$tmp"
+done
+
+rm -f "$tmp"
+
+exit 0
--- linux-4.4.0.orig/debian/scripts/retpoline-extract
+++ linux-4.4.0/debian/scripts/retpoline-extract
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+cd "$1" || exit 1
+
+# Find all valid retpoline information, collate the detected and
+# safe information together.  Join the result to find the detected
+# but non-safe elements.  These are our concern.
+ur_detected=$(mktemp --tmpdir "retpoline-check-XXXXXX.ur-detected")
+ur_safe=$(mktemp --tmpdir "retpoline-check-XXXXXX.ur-safe")
+
+find "." -path './drivers/firmware/efi/libstub' -prune -o \
+	 -path './arch/x86/boot' -prune -o \
+	 -path './arch/x86/purgatory' -prune -o \
+	 -name \*.ur-detected -print0 | xargs -0 cat | \
+	sed -e "s@^$1@@" -e "s@ $2/@ @" -e "s@^/@@" | \
+	sort -k 1b,1 >"$ur_detected"
+find "." -name \*.ur-safe -print0 | xargs -0 cat | \
+	sed -e "s@^$1@@" -e "s@^/@@" | \
+	sort -k 1b,1 >"$ur_safe"
+
+join -v 1 -j 1 "$ur_detected" "$ur_safe" | sed -s 's/[^ ]*  *//'
+
+rm -f "$ur_detected" "$ur_safe"
--- linux-4.4.0.orig/debian/scripts/retpoline-extract-one
+++ linux-4.4.0/debian/scripts/retpoline-extract-one
@@ -0,0 +1,270 @@
+#!/bin/bash
+
+exec </dev/null
+
+object="$1"
+src="$2"
+bit16="$3"
+
+SECTION=".discard.retpoline_safe"
+
+# Form an associative lookup for the symbol numbers in the ELF symbol table.
+# Uses 8 character 0 expanded hexadecimal key for ease of consumption.
+__symbolmap_init()
+{
+	readelf -W --syms "$1" |
+		awk '($4 == "SECTION" && $1 ~ /^[0-9]*:/) { printf("%08x %08x\n", int($1), int($7)); }' | \
+	while read symbol_num section_num
+	do
+		echo "symbolmap_$symbol_num='$section_num'"
+	done
+}
+symbolmap_init()
+{
+	eval $(__symbolmap_init "$1")
+}
+symbolmap()
+{
+	eval RET="\$symbolmap_$1"
+	if [ "$RET" = '' ]; then
+		echo "symbolmap: $1: invalid section" 1>&2
+		exit 1
+	fi
+}
+
+# Form an associative lookup for the section numbers in the ELF symbol table.
+# Uses 8 character 0 expanded hexadecimal key for ease of consumption.
+__sectionmap_init()
+{
+	readelf -W --headers "$1" | \
+		awk '
+						{ sub("\\[", ""); sub("\\]", ""); }
+                        ($1 ~ /^[0-9][0-9]*/)   { printf("%08x %s %s %s\n", int($1), $2, $3, $4); }
+		' | \
+	{
+		while read section_num section_name section_type section_vma
+		do
+			echo "sectionmap_$section_num='$section_name'"
+			echo "sectionvma_$section_num='$section_vma'"
+			case "$section_type" in
+			REL|RELA) section_relocation="$section_type" ;;
+			esac
+		done
+		echo "section_relocation='$section_relocation'"
+	}
+}
+sectionmap_init()
+{
+	eval $(__sectionmap_init "$1")
+}
+sectionmap()
+{
+	eval RET="\$sectionmap_$1"
+	if [ "$RET" = '' ]; then
+		echo "sectionmap: $1: invalid section" 1>&2
+		exit 1
+	fi
+}
+sectionvma()
+{
+	eval RET="\$sectionvma_$1"
+	if [ "$RET" = '' ]; then
+		echo "sectionvma: $1: invalid section" 1>&2
+		exit 1
+	fi
+}
+
+# Read and parse the hex-dump output.
+hex="[0-9a-f]"
+hex_8="$hex$hex$hex$hex$hex$hex$hex$hex"
+hexspc="[0-9a-f ]"
+hexspc_8="$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc"
+
+raw32()
+{
+	readelf --hex-dump "$2" "$1" 2>/dev/null |
+	sed \
+		-e '/^Hex/d' -e '/^$/d' -e '/^ *NOTE/d' \
+		-e 's/  *[^ ][^ ]*  *\('"$hex_8"'\) \('"$hexspc_8"'\) \('"$hexspc_8"'\) \('"$hexspc_8"'\) .*/\1 \2 \3 \4 /' \
+		-e 's/\('"$hex$hex"'\)\('"$hex$hex"'\)\('"$hex$hex"'\)\('"$hex$hex"'\) /\4\3\2\1 /g' \
+		-e 's/ $//g' -e 's/ /\n/g'
+}
+#-e 's/\([^ ][^ ][^ ][^ ][^ ][^ ][^ ][^ ]\) \([^ ][^ ][^ ][^ ][^ ][^ ][^ ][^ ]\) /\2\1 /g' \
+
+rela()
+{
+	#file="$(basename "$1")"
+	file="$1"
+
+	# Read relocation information for a 64bit binary.  Each relocation entry
+	# is 3 long longs so we collect 6 quads here.  Note that the dump is in
+	# listed in increasing byte order not withstanding the quad split.
+	#
+	# The record says to take the value of <symbol> add <symbol offset> and
+	# shove that into <write offset> in the segment of the <symbol>.
+	#
+	# Format:
+	#  <write offset>	64 bits
+	#  <symbol number>	32 bits
+	#  <relocation type>	32 bits
+	#  <symbol offset>	64 bits
+	raw32 "$1" ".rela$SECTION" | \
+	{
+		a1=''; a2=''; a3=''; a4=''; a5=''
+		while read a6
+		do
+			[ "$a1" = '' ] && { a1="$a6"; continue; }
+			[ "$a2" = '' ] && { a2="$a6"; continue; }
+			[ "$a3" = '' ] && { a3="$a6"; continue; }
+			[ "$a4" = '' ] && { a4="$a6"; continue; }
+			[ "$a5" = '' ] && { a5="$a6"; continue; }
+
+			#echo ">$a1< >$a2< >$a3< >$a4< >$a5< >$a6<" 1>&2
+			#echo "type<$a3> symbol<$a4> offset<$a2$a1> addr<$a6a5>" 1>&2
+
+			symbolmap "$a4"; section_num="$RET"
+			#echo "section_num<$section_num>" 1>&2
+
+			sectionmap "$section_num"; section="$RET"
+			sectionvma "$section_num"; vma="$RET"
+			#echo "section<$section> vma<$vma>" 1>&2
+
+			# Adjust the segment addressing by the segment offset.
+			printf -v addr "%u" "0x$a6$a5"
+			printf -v vma "%u" "0x$vma"
+			let offset="$addr + $vma"
+			printf -v offset "%x" "$offset"
+
+			echo "$file-$section-$offset"
+
+			a1=''; a2=''; a3=''; a4=''; a5=''
+		done
+	} | sed -e 's/-00*\([0-9a-f]\)/-\1/'
+}
+
+# Form an associative lookup for the raw contents for an ELF section.
+# Uses 8 character 0 expanded hexadecimal key for ease of consumption.
+contentmap_init()
+{
+	raw32 "$1" "$2" >"$tmp"
+	let offset=0
+	while read value
+	do
+		printf -v offset_hex "%08x" $offset
+		eval contentmap_$offset_hex=\'$value\'
+
+		let offset="$offset + 4"
+	done <"$tmp"
+	rm -f "$tmp"
+}
+contentmap()
+{
+	eval RET="\$contentmap_$1"
+	if [ "$RET" = '' ]; then
+		echo "contentmap: $1: invalid offset" 1>&2
+		exit 1
+	fi
+}
+
+rel()
+{
+	# Load up the current contents of the $SECTION segment
+	# as the offsets (see below) are recorded there and we will need
+	# those to calculate the actuall address.
+	contentmap_init "$1" "$SECTION"
+
+	#file="$(basename "$1")"
+	file="$1"
+
+	# Read relocation information for a 32bit binary.  Each relocation entry
+	# is 3 longs so we collect 3 quads here.  Note that the dump is in
+	# listed in increasing byte order not withstanding the quad split.
+	#
+	# The record says to take the value of <symbol> and add that to the
+	# existing contents of <write offset> in the segment of the <symbol>.
+	#
+	# Format:
+	#  <write offset>	32 bits
+	#  <symbol number>	24 bits
+	#  <relocation type>	 8 bits
+	raw32 "$1" ".rel$SECTION" | \
+	{
+		a1=''
+		while read a2
+		do
+			[ "$a1" = '' ] && { a1="$a2"; continue; }
+
+			#echo ">$a1< >$a2<"
+			contentmap "$a1"; offset="$RET"
+			symbolmap "00${a2%??}"; section_num="$RET"
+
+			sectionmap "$section_num"; section="$RET"
+			sectionvma "$section_num"; vma="$RET"
+			#echo ">$a1< >$a2< >$offset< >$section<"
+
+			echo "$file-$section-$offset"
+
+			a1=''
+		done
+	} | sed -e 's/-00*\([0-9a-f]\)/-\1/'
+}
+
+tmp=$(mktemp --tmpdir "retpoline-extract-XXXXXX")
+
+disassemble()
+{
+	local object="$1"
+	local src="$2"
+	local options="$3"
+	local selector="$4"
+
+	objdump $options --disassemble --no-show-raw-insn "$object" | \
+	awk -F' ' '
+		BEGIN				{ file="'"$object"'"; src="'"$src"'"; }
+		/Disassembly of section/        { segment=$4; sub(":", "", segment); }
+		/^[0-9a-f][0-9a-f]* <.*>:/      { tag=$0; sub(".*<", "", tag); sub(">.*", "", tag); }
+		$0 ~ /(call|jmp)q?  *\*0x[0-9a-f]*\(%rip\)/ {
+			next
+		}
+		$0 ~ /(call|jmp)q?  *\*.*%/ {
+			sub(":", "", $1);
+			if ('"$selector"') {
+				offset=$1
+				$1=tag
+				print(file "-" segment "-" offset " " src " " segment " " $0);
+			}
+		}
+	'
+}
+
+# Accumulate potentially vunerable indirect call/jmp sequences.  We do this
+# by examining the raw disassembly for affected forms, recording the location
+# of each.
+case "$bit16" in
+'')	disassemble "$object" "$src" '' 'segment != ".init.text"' ;;
+*)	disassemble "$object" "$src" '--disassembler-options=i8086' 'segment != ".init.text" && segment != ".text32" && segment != ".text64"'
+	disassemble "$object" "$src" '--disassembler-options=i386' 'segment == ".text32"'
+	disassemble "$object" "$src" '--disassembler-options=x86-64' 'segment == ".text64"'
+	;;
+esac | sort -k 1b,1 >"$object.ur-detected"
+[ ! -s "$object.ur-detected" ] && rm -f "$object.ur-detected"
+
+# Load up the symbol table and section mappings.
+symbolmap_init "$object"
+sectionmap_init "$object"
+
+# Accumulate annotated safe indirect call/jmp sequences.  We do this by examining
+# the $SECTION sections (and their associated relocation information),
+# each entry represents the address of an instruction which has been marked
+# as ok.
+case "$section_relocation" in
+REL)	rel "$object" ;;
+RELA)	rela "$object" ;;
+esac | sort -k 1b,1 >"$object.ur-safe"
+[ ! -s "$object.ur-safe" ] && rm -f "$object.ur-safe"
+
+# We will perform the below join on the summarised and sorted fragments
+# formed above.  This is performed in retpoline-check.
+#join -v 1 -j 1 "$tmp.extracted" "$tmp.safe" | sed -s 's/[^ ]*  *//'
+
+rm -f "$tmp"
--- linux-4.4.0.orig/debian/scripts/sub-flavour
+++ linux-4.4.0/debian/scripts/sub-flavour
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+. debian/debian.env
+
+echo "SUB_PROCESS $FROM => $TO"
+
+export from_pkg="linux-image-$ABI_RELEASE-$FROM"
+export to_pkg="linux-image-$ABI_RELEASE-$TO"
+
+from_moddir="debian/$from_pkg/lib/modules/$ABI_RELEASE-$FROM"
+to_moddir="debian/$to_pkg/lib/modules/$ABI_RELEASE-$FROM"
+
+install -d "debian/$to_pkg/boot"
+install -m644 debian/$from_pkg/boot/config-$ABI_RELEASE-$FROM \
+	debian/$to_pkg/boot/
+install -m600 debian/$from_pkg/boot/{vmlinuz,System.map}-$ABI_RELEASE-$FROM \
+	debian/$to_pkg/boot/
+
+#
+# Print some warnings if there are files in the sub-flavours list
+# that do not actually exist.
+#
+cat ${DEBIAN}/sub-flavours/$TO.list | while read line
+do
+(
+	cd debian/$from_pkg/lib/modules/$ABI_RELEASE-$FROM/kernel;
+	#
+	# If its a wildcard, then check that there are files that match.
+	#
+	if echo "$line" | grep '\*' > /dev/null
+	then
+		if [ `eval find "$line" -name '*.ko' 2>/dev/null|wc -l` -lt 1 ]
+		then
+			echo SUB_INST Warning - No files in $line
+		fi
+	#
+	# Else it should be a single file reference.
+	#
+	elif [ ! -f "$line" ]
+	then
+		echo SUB_INST Warning - could not find "$line"
+	fi
+)
+done
+
+cat ${DEBIAN}/sub-flavours/$TO.list | while read line; do
+	(
+	cd debian/$from_pkg/lib/modules/$ABI_RELEASE-$FROM/kernel;
+	if echo "$line" | grep '\*' > /dev/null
+	then
+		eval find "$line" -name '*.ko' 2>/dev/null || true
+	elif [ -f "$line" ]
+	then
+		echo "$line"
+	fi
+	);
+done | while read mod; do
+	echo "SUB_INST checking: $mod"
+	fromdir="/lib/modules/$ABI_RELEASE-$FROM/"
+	egrep "^($fromdir)?kernel/$mod:" \
+		$from_moddir/modules.dep | sed -e "s|^$fromdir||" -e 's/://' -e 's/ /\n/g' | \
+	while read m; do
+		m="${fromdir}$m"
+		test -f debian/$to_pkg/$m && continue
+		echo "SUB_INST installing: $m"
+		install -D -m644 debian/$from_pkg/$m \
+			debian/$to_pkg/$m
+	done
+done
--- linux-4.4.0.orig/debian/snapcraft.mk
+++ linux-4.4.0/debian/snapcraft.mk
@@ -0,0 +1,11 @@
+ifeq ($(ARCH),)
+  arch := $(shell uname -m | sed -e s/i.86/i386/ -e s/x86_64/amd64/ \
+            -e s/arm.*/armhf/ -e s/s390/s390x/ -e s/ppc.*/powerpc/ \
+            -e s/aarch64.*/arm64/ )
+else ifeq ($(ARCH),arm)
+  arch := armhf
+else
+  arch := $(ARCH)
+endif
+config:
+	cat debian.$(branch)/config/config.common.ubuntu debian.$(branch)/config/$(arch)/config.common.$(arch) debian.$(branch)/config/$(arch)/config.flavour.$(flavour) >.config
--- linux-4.4.0.orig/debian/source/format
+++ linux-4.4.0/debian/source/format
@@ -0,0 +1 @@
+1.0
--- linux-4.4.0.orig/debian/source/options
+++ linux-4.4.0/debian/source/options
@@ -0,0 +1,14 @@
+# Ignore vbox symlinks, we will regenerate these at clean (LP:1426113)
+## autoreconstruct -- begin
+# Ignore any symlinks created since the orig which are rebuilt by reconstruct.
+extend-diff-ignore=^ubuntu/vbox/vboxguest/include$
+extend-diff-ignore=^ubuntu/vbox/vboxguest/r0drv$
+extend-diff-ignore=^ubuntu/vbox/vboxsf/include$
+extend-diff-ignore=^ubuntu/vbox/vboxsf/r0drv$
+extend-diff-ignore=^ubuntu/vbox/vboxvideo/include$
+extend-diff-ignore=^ubuntu/vbox/vboxvideo/r0drv$
+## autoreconstruct -- end
+
+# force "dpkg-source -I -i" behavior
+diff-ignore
+tar-ignore
--- linux-4.4.0.orig/debian/stamps/keep-dir
+++ linux-4.4.0/debian/stamps/keep-dir
@@ -0,0 +1 @@
+Place holder
--- linux-4.4.0.orig/debian/templates/extra.postinst.in
+++ linux-4.4.0/debian/templates/extra.postinst.in
@@ -0,0 +1,21 @@
+#!/bin/sh
+set -e
+
+version=@abiname@@localversion@
+image_path=/boot/@image-stem@-$version
+
+if [ "$1" != configure ]; then
+    exit 0
+fi
+
+depmod -a -F /boot/System.map-$version $version || true
+if [ -d /etc/kernel/postinst.d ]; then
+    mkdir -p /usr/lib/linux/triggers
+    cat - >/usr/lib/linux/triggers/$version <<EOF
+DEB_MAINT_PARAMS="$*" run-parts --report --exit-on-error --arg=$version \
+	    --arg="$image_path" /etc/kernel/postinst.d
+EOF
+    dpkg-trigger --no-await linux-update-$version
+fi
+
+exit 0
--- linux-4.4.0.orig/debian/templates/extra.postrm.in
+++ linux-4.4.0/debian/templates/extra.postrm.in
@@ -0,0 +1,32 @@
+#!/bin/sh
+set -e
+
+version=@abiname@@localversion@
+image_path=/boot/@image-stem@-$version
+
+if [ "$1" != remove ]; then
+    exit 0
+fi
+
+depmod -a -F /boot/System.map-$version $version 2>/dev/null || true
+#
+# We should be rebuilding the initramfs here on removal to pare down the
+# initramfs if it contains any of the objects we just removed.  But people
+# commonly remove kernels in order to free space in /boot, and rebuilding the
+# initramfs now risks ENOSPC when we are trying to make space.  The files we
+# leave lying about could be confusing, but we trade that against safety on
+# removal.
+#
+#if [ -d /etc/kernel/postinst.d ]; then
+#    # We want to behave as if linux-image (without us) was installed, therefore
+#    # we do not want the postinst support to know we are being removed, claim
+#    # this is an installation event.
+#    mkdir -p /usr/lib/linux/triggers
+#    cat - >/usr/lib/linux/triggers/$version <<EOF
+#DEB_MAINT_PARAMS="configure" run-parts --report --exit-on-error --arg=$version \
+#	--arg="$image_path" /etc/kernel/postinst.d
+#EOF
+#    dpkg-trigger --no-await linux-update-$version
+#fi
+
+exit 0
--- linux-4.4.0.orig/debian/templates/headers.postinst.in
+++ linux-4.4.0/debian/templates/headers.postinst.in
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+
+version=@abiname@@localversion@
+
+if [ "$1" != configure ]; then
+    exit 0
+fi
+
+if [ -d /etc/kernel/header_postinst.d ]; then
+    DEB_MAINT_PARAMS="$*" run-parts --report --exit-on-error --arg=$version \
+		/etc/kernel/header_postinst.d
+fi
+
+exit 0
--- linux-4.4.0.orig/debian/templates/image.postinst.in
+++ linux-4.4.0/debian/templates/image.postinst.in
@@ -0,0 +1,62 @@
+#!/bin/sh
+set -e
+
+version=@abiname@@localversion@
+image_path=/boot/@image-stem@-$version
+
+#
+# When we install linux-image we have to run kernel postinst.d support to
+# generate the initramfs, create links etc.  Should it have an associated
+# linux-image-extra package and we install that we also need to run kernel
+# postinst.d, to regenerate the initramfs.  If we are installing both at the
+# same time, we necessarily trigger kernel postinst.d twice. As this includes
+# rebuilding the initramfs and reconfiguring the boot loader this is very time
+# consuming.
+#
+# Similarly for removal when we remove the linux-image-extra package we need to
+# run kernel postinst.d handling in order to pare down the initramfs to
+# linux-image contents only.  When we remove the linux-image need to remove the
+# now redundant initramfs.  If we are removing both at the same time, then
+# we will rebuilt the initramfs and then immediatly remove it.
+#
+# Switches to using a trigger against the linux-image package for all
+# postinst.d and postrm.d handling.  On installation postinst.d gets triggered
+# twice once by linux-image and once by linux-image-extra.  As triggers are
+# non-cumulative we will only run this processing once.  When removing both
+# packages we will trigger postinst.d from linux-image-extra and then in
+# linux-image postrm.d we effectivly ignore the pending trigger and simply run
+# the postrm.d.  This prevents us from rebuilding the initramfs.
+#
+if [ "$1" = triggered ]; then
+    trigger=/usr/lib/linux/triggers/$version
+    if [ -f "$trigger" ]; then
+	sh "$trigger"
+	rm -f "$trigger"
+    fi
+    exit 0
+fi
+
+if [ "$1" != configure ]; then
+    exit 0
+fi
+
+depmod $version
+
+if [ -f /lib/modules/$version/.fresh-install ]; then
+    change=install
+else
+    change=upgrade
+fi
+linux-update-symlinks $change $version $image_path
+rm -f /lib/modules/$version/.fresh-install
+
+if [ -d /etc/kernel/postinst.d ]; then
+    mkdir -p /usr/lib/linux/triggers
+    cat - >/usr/lib/linux/triggers/$version <<EOF
+DEB_MAINT_PARAMS="$*" run-parts --report --exit-on-error --arg=$version \
+      --arg=$image_path /etc/kernel/postinst.d
+EOF
+    dpkg-trigger --no-await linux-update-$version
+fi
+
+exit 0
--- linux-4.4.0.orig/debian/templates/image.postrm.in
+++ linux-4.4.0/debian/templates/image.postrm.in
@@ -0,0 +1,41 @@
+#!/bin/sh
+set -e
+
+version=@abiname@@localversion@
+image_path=/boot/@image-stem@-$version
+
+rm -f /lib/modules/$version/.fresh-install
+
+if [ "$1" != upgrade ] && command -v linux-update-symlinks >/dev/null; then
+    linux-update-symlinks remove $version $image_path
+fi
+
+if [ -d /etc/kernel/postrm.d ]; then
+    # We cannot trigger ourselves as at the end of this we will no longer
+    # exist and can no longer respond to the trigger.  The trigger would
+    # then become lost.  Therefore we clear any pending trigger and apply
+    # postrm directly.
+    if [ -f /usr/lib/linux/triggers/$version ]; then
+	echo "$0 ... removing pending trigger"
+	rm -f /usr/lib/linux/triggers/$version
+	rmdir --ignore-fail-on-non-empty /usr/lib/linux/triggers
+    fi
+    DEB_MAINT_PARAMS="$*" run-parts --report --exit-on-error --arg=$version \
+	      --arg=$image_path /etc/kernel/postrm.d
+fi
+
+if [ "$1" = purge ]; then
+    for extra_file in modules.dep modules.isapnpmap modules.pcimap \
+                      modules.usbmap modules.parportmap \
+                      modules.generic_string modules.ieee1394map \
+                      modules.ieee1394map modules.pnpbiosmap \
+                      modules.alias modules.ccwmap modules.inputmap \
+                      modules.symbols modules.ofmap \
+                      modules.seriomap modules.\*.bin \
+		      modules.softdep modules.devname; do
+	eval rm -f /lib/modules/$version/$extra_file
+    done
+    rmdir /lib/modules/$version || true
+fi
+
+exit 0
--- linux-4.4.0.orig/debian/templates/image.preinst.in
+++ linux-4.4.0/debian/templates/image.preinst.in
@@ -0,0 +1,22 @@
+#!/bin/sh
+set -e
+
+version=@abiname@@localversion@
+image_path=/boot/@image-stem@-$version
+
+if [ "$1" = abort-upgrade ]; then
+    exit 0
+fi
+
+if [ "$1" = install ]; then
+    # Create a flag file for postinst
+    mkdir -p /lib/modules/$version
+    touch /lib/modules/$version/.fresh-install
+fi
+
+if [ -d /etc/kernel/preinst.d ]; then
+    DEB_MAINT_PARAMS="$*" run-parts --report --exit-on-error --arg=$version \
+	      --arg=$image_path /etc/kernel/preinst.d
+fi
+
+exit 0
--- linux-4.4.0.orig/debian/templates/image.prerm.in
+++ linux-4.4.0/debian/templates/image.prerm.in
@@ -0,0 +1,18 @@
+#!/bin/sh
+set -e
+
+version=@abiname@@localversion@
+image_path=/boot/@image-stem@-$version
+
+if [ "$1" != remove ]; then
+    exit 0
+fi
+
+linux-check-removal $version
+
+if [ -d /etc/kernel/prerm.d ]; then
+    DEB_MAINT_PARAMS="$*" run-parts --report --exit-on-error --arg=$version \
+	      --arg=$image_path /etc/kernel/prerm.d
+fi
+
+exit 0
--- linux-4.4.0.orig/debian/tests-build/README
+++ linux-4.4.0/debian/tests-build/README
@@ -0,0 +1,21 @@
+Scripts placed in this directory get called one at a time by run-parts(8).
+The scripts are expected to perform some sort of sanity checks on the
+finished build. Scripts will be called once for each flavour.
+
+Some environment variables are exported to make life a little easier:
+
+DPKG_ARCH     : The dpkg architecture (e.g. "amd64")
+KERN_ARCH     : The kernel architecture (e.g. "x86_64")
+FLAVOUR       : The specific flavour for this run (e.g. "generic")
+VERSION       : The full version of this build (e.g. 2.6.22-1)
+REVISION      : The exact revision of this build (e.g. 1.3)
+PREV_REVISION : The revision prior to this one
+ABI_NUM       : The specific ABI number for this build (e.g. 2)
+PREV_ABI_NUM  : The previous ABI number. Can be the same as ABI_NUM.
+BUILD_DIR     : The directory where this build took place
+INSTALL_DIR   : The directory where the package is prepared
+SOURCE_DIR    : Where the main kernel source is
+
+Scripts are expected to have a zero exit status when no problems occur,
+and non-zero when an error occurs that should stop the build. Scripts
+should print whatever info they deem needed to deduce the problem.
--- linux-4.4.0.orig/debian/tests-build/check-aliases
+++ linux-4.4.0/debian/tests-build/check-aliases
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+my %map;
+
+print "Checking for dupe aliases in $ENV{'FLAVOUR'}...\n";
+
+$aliases =
+  "$ENV{'INSTALL_DIR'}/lib/modules/$ENV{'VERSION'}-$ENV{'FLAVOUR'}/modules.alias";
+
+open(ALIASES, "< $aliases") or die "Could not open $aliases";
+
+while (<ALIASES>) {
+	chomp;
+	my ($junk, $alias, $module) = split;
+
+	if (defined($map{$alias})) {
+		printf("%s %20s / %-20s : %s \n", ("$map{$alias}" eq "$module")
+			? "INT" : "   ", $map{$alias}, $module, $alias);
+	} else {
+		$map{$alias} = $module;
+	}
+}
+
+exit(0);
--- linux-4.4.0.orig/debian/tests/control
+++ linux-4.4.0/debian/tests/control
@@ -0,0 +1,7 @@
+Tests: rebuild
+Depends: @builddeps@, fakeroot
+Restrictions: allow-stderr, skippable
+
+Tests: ubuntu-regression-suite
+Depends: build-essential, gcc-multilib [amd64 arm64 armhf i386 powerpc], gdb, git, bzr
+Restrictions: allow-stderr, isolation-machine, breaks-testbed, skippable
--- linux-4.4.0.orig/debian/tests/rebuild
+++ linux-4.4.0/debian/tests/rebuild
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# If we are triggering for just linux or linux-meta we know we have
+# just built the kernel and there is no point in repeating that
+# build, it just wastes time.  (LP: #1498862)
+build_needed=0
+for trigger in ${ADT_TEST_TRIGGERS:-force}
+do
+	case "$trigger" in
+	linux/*|linux-lts-*/*|linux-meta*/*|fakeroot/*|gdb/*|git/*|bzr/*|gcc-multilib/*)		;;
+	*)						build_needed=1 ;;
+	esac
+done
+if [ "$build_needed" -eq 0 ]; then
+	echo "rebuild: short circuiting build for '${ADT_TEST_TRIGGERS}'"
+	exit 77
+fi
+
+set -e
+dpkg-buildpackage -rfakeroot -us -uc -b -Pautopkgtest
--- linux-4.4.0.orig/debian/tests/ubuntu-regression-suite
+++ linux-4.4.0/debian/tests/ubuntu-regression-suite
@@ -0,0 +1,45 @@
+#!/bin/sh
+set -e
+
+# Only run regression-suite on kernels we can boot in canonistack
+source=`dpkg-parsechangelog -SSource`
+case $source in
+    linux|linux-hwe|linux-kvm|linux-oem)
+	;;
+    *)
+	echo "ubuntu-regression-suite is pointless, if one cannot boot the kernel"
+	exit 77
+	;;
+esac
+
+# Only run regression-suite if we were requested to
+have_meta=0
+for trigger in ${ADT_TEST_TRIGGERS}
+do
+    case "$trigger" in
+	linux-meta/*|linux-meta-*/*)
+	    have_meta=1
+	    ;;
+    esac
+done
+if [ -n "$ADT_TEST_TRIGGERS" ] && [ "$have_meta" -eq 0 ]; then
+    echo "ubuntu-regression-suite is not requested, as there is no linux-meta trigger"
+    exit 77
+fi
+
+sver=`dpkg-parsechangelog -SVersion`
+read x rver x </proc/version_signature
+
+flavour=${rver#*-*-}
+rver=${rver%-$flavour}
+
+echo "Source Package Version: $sver"
+echo "Running Kernel Version: $rver"
+
+if [ "$sver" != "$rver" ]; then
+    echo "ERROR: running version does not match source package" 1>&2
+    exit 1
+fi
+
+git clone --depth=1 git://git.launchpad.net/~canonical-kernel-team/+git/kernel-testing
+kernel-testing/run-dep8-tests
--- linux-4.4.0.orig/debian/tools/generic
+++ linux-4.4.0/debian/tools/generic
@@ -0,0 +1,60 @@
+#!/bin/bash
+full_version=`uname -r`
+
+# First check for a fully qualified version.
+this="/usr/lib/linux-tools/$full_version/`basename $0`"
+if [ -f "$this" ]; then
+	exec "$this" "$@"
+fi
+
+# Removing flavour from version i.e. generic or server.
+flavour_abi=${full_version#*-}
+flavour=${flavour_abi#*-}
+version=${full_version%-$flavour}
+this="$0_$version"
+if [ -f "$this" ]; then
+	exec "$this" "$@"
+fi
+
+# Before saucy kernels we had no flavour linkage.
+if dpkg --compare-versions "$version" lt "3.11.0"; then
+	flavour=''
+else
+	flavour="-$flavour"
+fi
+# Hint at the cloud tools if they exist (trusty and later)
+if dpkg --compare-versions "$version" ge "3.13.0"; then
+	cld=""
+else
+	cld=":"
+fi
+# Work out if this is an LTS backport or not.
+codename=`lsb_release -cs`
+case "$codename" in
+precise)	base='3.2.0-9999' ;;
+trusty)		base='3.13.0-9999' ;;
+*)		base='' ;;
+esac
+std=""
+lts=":"
+if [ "$base" != "" ]; then
+	if dpkg --compare-versions "$version" gt "$base"; then
+		std=":"
+		lts=""
+	fi
+fi
+
+# Give them a hint as to what to install.
+		echo "WARNING: `basename $0` not found for kernel $version" >&2
+		echo "" >&2
+		echo "  You may need to install the following packages for this specific kernel:" >&2
+		echo "    linux-tools-$version$flavour" >&2
+$cld		echo "    linux-cloud-tools-$version$flavour" >&2
+		echo "" >&2
+		echo "  You may also want to install one of the following packages to keep up to date:" >&2
+$std		echo "    linux-tools$flavour" >&2
+$std $cld	echo "    linux-cloud-tools$flavour" >&2
+$lts		echo "    linux-tools$flavour-lts-<series>" >&2
+$lts $cld	echo "    linux-cloud-tools$flavour-lts-<series>" >&2
+
+exit 2
--- linux-4.4.0.orig/debian/wireguard-modules.ignore
+++ linux-4.4.0/debian/wireguard-modules.ignore
@@ -0,0 +1 @@
+wireguard
--- linux-4.4.0.orig/debian/zfs-modules.ignore
+++ linux-4.4.0/debian/zfs-modules.ignore
@@ -0,0 +1,8 @@
+spl
+splat
+zavl
+zcommon
+zfs
+znvpair
+zpios
+zunicode
--- linux-4.4.0.orig/drivers/Makefile
+++ linux-4.4.0/drivers/Makefile
@@ -96,8 +96,10 @@
 obj-$(CONFIG_UWB)		+= uwb/
 obj-$(CONFIG_USB_PHY)		+= usb/
 obj-$(CONFIG_USB)		+= usb/
+obj-$(CONFIG_USB_SUPPORT)	+= usb/
 obj-$(CONFIG_PCI)		+= usb/
 obj-$(CONFIG_USB_GADGET)	+= usb/
+obj-$(CONFIG_OF)		+= usb/
 obj-$(CONFIG_SERIO)		+= input/serio/
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
 obj-$(CONFIG_INPUT)		+= input/
--- linux-4.4.0.orig/drivers/acpi/Kconfig
+++ linux-4.4.0/drivers/acpi/Kconfig
@@ -66,6 +66,9 @@
 	  This is still under development, currently enabling this only
 	  results in the compilation of the ACPICA debugger files.
 
+config ACPI_SPCR_TABLE
+	bool
+
 config ACPI_SLEEP
 	bool
 	depends on SUSPEND || HIBERNATION
@@ -206,6 +209,9 @@
 	bool
 	select CPU_IDLE
 
+config ACPI_MCFG
+	bool
+
 config ACPI_CPPC_LIB
 	bool
 	depends on ACPI_PROCESSOR
--- linux-4.4.0.orig/drivers/acpi/Makefile
+++ linux-4.4.0/drivers/acpi/Makefile
@@ -2,7 +2,6 @@
 # Makefile for the Linux ACPI interpreter
 #
 
-ccflags-y			:= -Os
 ccflags-$(CONFIG_ACPI_DEBUG)	+= -DACPI_DEBUG_OUTPUT
 
 #
@@ -40,6 +39,7 @@
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
+obj-$(CONFIG_ACPI_MCFG)		+= pci_mcfg.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
@@ -79,6 +79,7 @@
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
 obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
+obj-$(CONFIG_ACPI_SPCR_TABLE)	+= spcr.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o
--- linux-4.4.0.orig/drivers/acpi/acpi_extlog.c
+++ linux-4.4.0/drivers/acpi/acpi_extlog.c
@@ -223,9 +223,9 @@
 	u64 cap;
 	int rc;
 
-	rdmsrl(MSR_IA32_MCG_CAP, cap);
-
-	if (!(cap & MCG_ELOG_P) || !extlog_get_l1addr())
+	if (rdmsrl_safe(MSR_IA32_MCG_CAP, &cap) ||
+	    !(cap & MCG_ELOG_P) ||
+	    !extlog_get_l1addr())
 		return -ENODEV;
 
 	if (get_edac_report_status() == EDAC_REPORTING_FORCE) {
--- linux-4.4.0.orig/drivers/acpi/acpi_lpss.c
+++ linux-4.4.0/drivers/acpi/acpi_lpss.c
@@ -15,6 +15,7 @@
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/clk-lpss.h>
 #include <linux/pm_runtime.h>
@@ -26,6 +27,10 @@
 
 #ifdef CONFIG_X86_INTEL_LPSS
 
+#include <asm/cpu_device_id.h>
+#include <asm/iosf_mbi.h>
+#include <asm/pmc_atom.h>
+
 #define LPSS_ADDR(desc) ((unsigned long)&desc)
 
 #define LPSS_CLK_SIZE	0x04
@@ -71,7 +76,7 @@
 	void (*setup)(struct lpss_private_data *pdata);
 };
 
-static struct lpss_device_desc lpss_dma_desc = {
+static const struct lpss_device_desc lpss_dma_desc = {
 	.flags = LPSS_CLK,
 };
 
@@ -84,6 +89,23 @@
 	u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
 };
 
+/* LPSS run time quirks */
+static unsigned int lpss_quirks;
+
+/*
+ * LPSS_QUIRK_ALWAYS_POWER_ON: override power state for LPSS DMA device.
+ *
+ * The LPSS DMA controller does not have neither _PS0 nor _PS3 method. Moreover
+ * it can be powered off automatically whenever the last LPSS device goes down.
+ * In case of no power any access to the DMA controller will hang the system.
+ * The behaviour is reproduced on some HP laptops based on Intel BayTrail as
+ * well as on ASuS T100TA transformer.
+ *
+ * This quirk overrides power state of entire LPSS island to keep DMA powered
+ * on whenever we have at least one other device in use.
+ */
+#define LPSS_QUIRK_ALWAYS_POWER_ON	BIT(0)
+
 /* UART Component Parameter Register */
 #define LPSS_UART_CPR			0xF4
 #define LPSS_UART_CPR_AFCE		BIT(4)
@@ -154,10 +176,12 @@
 
 static const struct lpss_device_desc byt_pwm_dev_desc = {
 	.flags = LPSS_SAVE_CTX,
+	.prv_offset = 0x800,
 };
 
 static const struct lpss_device_desc bsw_pwm_dev_desc = {
 	.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
+	.prv_offset = 0x800,
 };
 
 static const struct lpss_device_desc byt_uart_dev_desc = {
@@ -196,13 +220,21 @@
 	.setup = byt_i2c_setup,
 };
 
-static struct lpss_device_desc bsw_spi_dev_desc = {
+static const struct lpss_device_desc bsw_spi_dev_desc = {
 	.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX
 			| LPSS_NO_D3_DELAY,
 	.prv_offset = 0x400,
 	.setup = lpss_deassert_reset,
 };
 
+#define ICPU(model)	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
+
+static const struct x86_cpu_id lpss_cpu_ids[] = {
+	ICPU(0x37),	/* Valleyview, Bay Trail */
+	ICPU(0x4c),	/* Braswell, Cherry Trail */
+	{}
+};
+
 #else
 
 #define LPSS_ADDR(desc) (0UL)
@@ -233,9 +265,11 @@
 	{ "INT33FC", },
 
 	/* Braswell LPSS devices */
+	{ "80862286", LPSS_ADDR(lpss_dma_desc) },
 	{ "80862288", LPSS_ADDR(bsw_pwm_dev_desc) },
 	{ "8086228A", LPSS_ADDR(bsw_uart_dev_desc) },
 	{ "8086228E", LPSS_ADDR(bsw_spi_dev_desc) },
+	{ "808622C0", LPSS_ADDR(lpss_dma_desc) },
 	{ "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) },
 
 	/* Broadwell LPSS devices */
@@ -401,12 +435,7 @@
 	 * have _PS0 and _PS3 without _PSC (and no power resources), so
 	 * acpi_bus_init_power() will assume that the BIOS has put them into D0.
 	 */
-	ret = acpi_device_fix_up_power(adev);
-	if (ret) {
-		/* Skip the device, but continue the namespace scan. */
-		ret = 0;
-		goto err_out;
-	}
+	acpi_device_fix_up_power(adev);
 
 	adev->driver_data = pdata;
 	pdev = acpi_create_platform_device(adev);
@@ -628,6 +657,89 @@
 }
 #endif /* CONFIG_PM_SLEEP */
 
+/* IOSF SB for LPSS island */
+#define LPSS_IOSF_UNIT_LPIOEP		0xA0
+#define LPSS_IOSF_UNIT_LPIO1		0xAB
+#define LPSS_IOSF_UNIT_LPIO2		0xAC
+
+#define LPSS_IOSF_PMCSR			0x84
+#define LPSS_PMCSR_D0			0
+#define LPSS_PMCSR_D3hot		3
+#define LPSS_PMCSR_Dx_MASK		GENMASK(1, 0)
+
+#define LPSS_IOSF_GPIODEF0		0x154
+#define LPSS_GPIODEF0_DMA1_D3		BIT(2)
+#define LPSS_GPIODEF0_DMA2_D3		BIT(3)
+#define LPSS_GPIODEF0_DMA_D3_MASK	GENMASK(3, 2)
+
+static DEFINE_MUTEX(lpss_iosf_mutex);
+
+static void lpss_iosf_enter_d3_state(void)
+{
+	u32 value1 = 0;
+	u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK;
+	u32 value2 = LPSS_PMCSR_D3hot;
+	u32 mask2 = LPSS_PMCSR_Dx_MASK;
+	/*
+	 * PMC provides an information about actual status of the LPSS devices.
+	 * Here we read the values related to LPSS power island, i.e. LPSS
+	 * devices, excluding both LPSS DMA controllers, along with SCC domain.
+	 */
+	u32 func_dis, d3_sts_0, pmc_status, pmc_mask = 0xfe000ffe;
+	int ret;
+
+	ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis);
+	if (ret)
+		return;
+
+	mutex_lock(&lpss_iosf_mutex);
+
+	ret = pmc_atom_read(PMC_D3_STS_0, &d3_sts_0);
+	if (ret)
+		goto exit;
+
+	/*
+	 * Get the status of entire LPSS power island per device basis.
+	 * Shutdown both LPSS DMA controllers if and only if all other devices
+	 * are already in D3hot.
+	 */
+	pmc_status = (~(d3_sts_0 | func_dis)) & pmc_mask;
+	if (pmc_status)
+		goto exit;
+
+	iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO1, MBI_CFG_WRITE,
+			LPSS_IOSF_PMCSR, value2, mask2);
+
+	iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO2, MBI_CFG_WRITE,
+			LPSS_IOSF_PMCSR, value2, mask2);
+
+	iosf_mbi_modify(LPSS_IOSF_UNIT_LPIOEP, MBI_CR_WRITE,
+			LPSS_IOSF_GPIODEF0, value1, mask1);
+exit:
+	mutex_unlock(&lpss_iosf_mutex);
+}
+
+static void lpss_iosf_exit_d3_state(void)
+{
+	u32 value1 = LPSS_GPIODEF0_DMA1_D3 | LPSS_GPIODEF0_DMA2_D3;
+	u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK;
+	u32 value2 = LPSS_PMCSR_D0;
+	u32 mask2 = LPSS_PMCSR_Dx_MASK;
+
+	mutex_lock(&lpss_iosf_mutex);
+
+	iosf_mbi_modify(LPSS_IOSF_UNIT_LPIOEP, MBI_CR_WRITE,
+			LPSS_IOSF_GPIODEF0, value1, mask1);
+
+	iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO2, MBI_CFG_WRITE,
+			LPSS_IOSF_PMCSR, value2, mask2);
+
+	iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO1, MBI_CFG_WRITE,
+			LPSS_IOSF_PMCSR, value2, mask2);
+
+	mutex_unlock(&lpss_iosf_mutex);
+}
+
 static int acpi_lpss_runtime_suspend(struct device *dev)
 {
 	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
@@ -640,7 +752,17 @@
 	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
 		acpi_lpss_save_ctx(dev, pdata);
 
-	return acpi_dev_runtime_suspend(dev);
+	ret = acpi_dev_runtime_suspend(dev);
+
+	/*
+	 * This call must be last in the sequence, otherwise PMC will return
+	 * wrong status for devices being about to be powered off. See
+	 * lpss_iosf_enter_d3_state() for further information.
+	 */
+	if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available())
+		lpss_iosf_enter_d3_state();
+
+	return ret;
 }
 
 static int acpi_lpss_runtime_resume(struct device *dev)
@@ -648,6 +770,13 @@
 	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
 	int ret;
 
+	/*
+	 * This call is kept first to be in symmetry with
+	 * acpi_lpss_runtime_suspend() one.
+	 */
+	if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available())
+		lpss_iosf_exit_d3_state();
+
 	ret = acpi_dev_runtime_resume(dev);
 	if (ret)
 		return ret;
@@ -754,10 +883,19 @@
 
 void __init acpi_lpss_init(void)
 {
-	if (!lpt_clk_init()) {
-		bus_register_notifier(&platform_bus_type, &acpi_lpss_nb);
-		acpi_scan_add_handler(&lpss_handler);
-	}
+	const struct x86_cpu_id *id;
+	int ret;
+
+	ret = lpt_clk_init();
+	if (ret)
+		return;
+
+	id = x86_match_cpu(lpss_cpu_ids);
+	if (id)
+		lpss_quirks |= LPSS_QUIRK_ALWAYS_POWER_ON;
+
+	bus_register_notifier(&platform_bus_type, &acpi_lpss_nb);
+	acpi_scan_add_handler(&lpss_handler);
 }
 
 #else
--- linux-4.4.0.orig/drivers/acpi/acpi_pad.c
+++ linux-4.4.0/drivers/acpi/acpi_pad.c
@@ -108,6 +108,7 @@
 		cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus);
 	if (cpumask_empty(tmp)) {
 		mutex_unlock(&round_robin_lock);
+		free_cpumask_var(tmp);
 		return;
 	}
 	for_each_cpu(cpu, tmp) {
@@ -125,13 +126,18 @@
 	mutex_unlock(&round_robin_lock);
 
 	set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu));
+
+	free_cpumask_var(tmp);
 }
 
 static void exit_round_robin(unsigned int tsk_index)
 {
 	struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
-	cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
-	tsk_in_cpu[tsk_index] = -1;
+
+	if (tsk_in_cpu[tsk_index] != -1) {
+		cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+		tsk_in_cpu[tsk_index] = -1;
+	}
 }
 
 static unsigned int idle_pct = 5; /* percentage */
--- linux-4.4.0.orig/drivers/acpi/acpi_platform.c
+++ linux-4.4.0/drivers/acpi/acpi_platform.c
@@ -24,9 +24,12 @@
 ACPI_MODULE_NAME("platform");
 
 static const struct acpi_device_id forbidden_id_list[] = {
-	{"PNP0000", 0},	/* PIC */
-	{"PNP0100", 0},	/* Timer */
-	{"PNP0200", 0},	/* AT DMA Controller */
+	{"PNP0000",  0},	/* PIC */
+	{"PNP0100",  0},	/* Timer */
+	{"PNP0200",  0},	/* AT DMA Controller */
+	{"ACPI0009", 0},	/* IOxAPIC */
+	{"ACPI000A", 0},	/* IOAPIC */
+	{"SMB0001",  0},	/* ACPI SMBUS virtual device */
 	{"", 0},
 };
 
--- linux-4.4.0.orig/drivers/acpi/acpi_pnp.c
+++ linux-4.4.0/drivers/acpi/acpi_pnp.c
@@ -320,6 +320,9 @@
 {
 	int i;
 
+	if (strlen(idstr) != strlen(list_id))
+		return false;
+
 	if (memcmp(idstr, list_id, 3))
 		return false;
 
--- linux-4.4.0.orig/drivers/acpi/acpi_processor.c
+++ linux-4.4.0/drivers/acpi/acpi_processor.c
@@ -331,15 +331,6 @@
 		pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
 
 		pr->pblk = object.processor.pblk_address;
-
-		/*
-		 * We don't care about error returns - we just try to mark
-		 * these reserved so that nobody else is confused into thinking
-		 * that this region might be unused..
-		 *
-		 * (In particular, allocating the IO range for Cardbus)
-		 */
-		request_region(pr->throttling.address, 6, "ACPI CPU throttle");
 	}
 
 	/*
@@ -491,6 +482,58 @@
 }
 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
 
+#ifdef CONFIG_X86
+static bool acpi_hwp_native_thermal_lvt_set;
+static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle,
+							  u32 lvl,
+							  void *context,
+							  void **rv)
+{
+	u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953";
+	u32 capbuf[2];
+	struct acpi_osc_context osc_context = {
+		.uuid_str = sb_uuid_str,
+		.rev = 1,
+		.cap.length = 8,
+		.cap.pointer = capbuf,
+	};
+
+	if (acpi_hwp_native_thermal_lvt_set)
+		return AE_CTRL_TERMINATE;
+
+	capbuf[0] = 0x0000;
+	capbuf[1] = 0x1000; /* set bit 12 */
+
+	if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) {
+		if (osc_context.ret.pointer && osc_context.ret.length > 1) {
+			u32 *capbuf_ret = osc_context.ret.pointer;
+
+			if (capbuf_ret[1] & 0x1000) {
+				acpi_handle_info(handle,
+					"_OSC native thermal LVT Acked\n");
+				acpi_hwp_native_thermal_lvt_set = true;
+			}
+		}
+		kfree(osc_context.ret.pointer);
+	}
+
+	return AE_OK;
+}
+
+void __init acpi_early_processor_osc(void)
+{
+	if (boot_cpu_has(X86_FEATURE_HWP)) {
+		acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
+				    ACPI_UINT32_MAX,
+				    acpi_hwp_native_thermal_lvt_osc,
+				    NULL, NULL, NULL);
+		acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID,
+				 acpi_hwp_native_thermal_lvt_osc,
+				 NULL, NULL);
+	}
+}
+#endif
+
 /*
  * The following ACPI IDs are known to be suitable for representing as
  * processor devices.
--- linux-4.4.0.orig/drivers/acpi/acpi_video.c
+++ linux-4.4.0/drivers/acpi/acpi_video.c
@@ -465,6 +465,15 @@
 	 * as brightness control does not work.
 	 */
 	{
+	 /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
+	 .callback = video_disable_backlight_sysfs_if,
+	 .ident = "Toshiba Portege R700",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"),
+		},
+	},
+	{
 	 /* https://bugs.freedesktop.org/show_bug.cgi?id=82634 */
 	 .callback = video_disable_backlight_sysfs_if,
 	 .ident = "Toshiba Portege R830",
@@ -473,6 +482,15 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"),
 		},
 	},
+	{
+	 /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
+	 .callback = video_disable_backlight_sysfs_if,
+	 .ident = "Toshiba Satellite R830",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE R830"),
+		},
+	},
 	/*
 	 * Some machine's _DOD IDs don't have bit 31(Device ID Scheme) set
 	 * but the IDs actually follow the Device ID Scheme.
@@ -1193,6 +1211,9 @@
 	union acpi_object *dod = NULL;
 	union acpi_object *obj;
 
+	if (!video->cap._DOD)
+		return AE_NOT_EXIST;
+
 	status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
 	if (!ACPI_SUCCESS(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
--- linux-4.4.0.orig/drivers/acpi/acpica/dsfield.c
+++ linux-4.4.0/drivers/acpi/acpica/dsfield.c
@@ -272,7 +272,7 @@
  * FUNCTION:    acpi_ds_get_field_names
  *
  * PARAMETERS:  info            - create_field info structure
- *  `           walk_state      - Current method state
+ *              walk_state      - Current method state
  *              arg             - First parser arg for the field name list
  *
  * RETURN:      Status
--- linux-4.4.0.orig/drivers/acpi/acpica/dsmethod.c
+++ linux-4.4.0/drivers/acpi/acpica/dsmethod.c
@@ -417,6 +417,9 @@
 				obj_desc->method.mutex->mutex.
 				    original_sync_level =
 				    obj_desc->method.mutex->mutex.sync_level;
+
+				obj_desc->method.mutex->mutex.thread_id =
+				    acpi_os_get_thread_id();
 			}
 		}
 
--- linux-4.4.0.orig/drivers/acpi/acpica/dswload.c
+++ linux-4.4.0/drivers/acpi/acpica/dswload.c
@@ -440,6 +440,27 @@
 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
 			  walk_state));
 
+	/*
+	 * Disassembler: handle create field operators here.
+	 *
+	 * create_buffer_field is a deferred op that is typically processed in load
+	 * pass 2. However, disassembly of control method contents walk the parse
+	 * tree with ACPI_PARSE_LOAD_PASS1 and AML_CREATE operators are processed
+	 * in a later walk. This is a problem when there is a control method that
+	 * has the same name as the AML_CREATE object. In this case, any use of the
+	 * name segment will be detected as a method call rather than a reference
+	 * to a buffer field.
+	 *
+	 * This earlier creation during disassembly solves this issue by inserting
+	 * the named object in the ACPI namespace so that references to this name
+	 * would be a name string rather than a method call.
+	 */
+	if ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) &&
+	    (walk_state->op_info->flags & AML_CREATE)) {
+		status = acpi_ds_create_buffer_field(op, walk_state);
+		return_ACPI_STATUS(status);
+	}
+
 	/* We are only interested in opcodes that have an associated name */
 
 	if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) {
--- linux-4.4.0.orig/drivers/acpi/acpica/evevent.c
+++ linux-4.4.0/drivers/acpi/acpica/evevent.c
@@ -204,6 +204,7 @@
 	u32 fixed_status;
 	u32 fixed_enable;
 	u32 i;
+	acpi_status status;
 
 	ACPI_FUNCTION_NAME(ev_fixed_event_detect);
 
@@ -211,8 +212,12 @@
 	 * Read the fixed feature status and enable registers, as all the cases
 	 * depend on their values. Ignore errors here.
 	 */
-	(void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status);
-	(void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
+	status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status);
+	status |=
+	    acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
+	if (ACPI_FAILURE(status)) {
+		return (int_status);
+	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
 			  "Fixed Event Block: Enable %08X Status %08X\n",
--- linux-4.4.0.orig/drivers/acpi/acpica/evxfevnt.c
+++ linux-4.4.0/drivers/acpi/acpica/evxfevnt.c
@@ -180,6 +180,12 @@
 
 	ACPI_FUNCTION_TRACE(acpi_enable_event);
 
+	/* If Hardware Reduced flag is set, there are no fixed events */
+
+	if (acpi_gbl_reduced_hardware) {
+		return_ACPI_STATUS(AE_OK);
+	}
+
 	/* Decode the Fixed Event */
 
 	if (event > ACPI_EVENT_MAX) {
@@ -237,6 +243,12 @@
 
 	ACPI_FUNCTION_TRACE(acpi_disable_event);
 
+	/* If Hardware Reduced flag is set, there are no fixed events */
+
+	if (acpi_gbl_reduced_hardware) {
+		return_ACPI_STATUS(AE_OK);
+	}
+
 	/* Decode the Fixed Event */
 
 	if (event > ACPI_EVENT_MAX) {
@@ -290,6 +302,12 @@
 
 	ACPI_FUNCTION_TRACE(acpi_clear_event);
 
+	/* If Hardware Reduced flag is set, there are no fixed events */
+
+	if (acpi_gbl_reduced_hardware) {
+		return_ACPI_STATUS(AE_OK);
+	}
+
 	/* Decode the Fixed Event */
 
 	if (event > ACPI_EVENT_MAX) {
--- linux-4.4.0.orig/drivers/acpi/acpica/exprep.c
+++ linux-4.4.0/drivers/acpi/acpica/exprep.c
@@ -502,10 +502,6 @@
 				    (u8)access_byte_width;
 			}
 		}
-		/* An additional reference for the container */
-
-		acpi_ut_add_reference(obj_desc->field.region_obj);
-
 		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 				  "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
 				  obj_desc->field.start_field_bit_offset,
--- linux-4.4.0.orig/drivers/acpi/acpica/hwxface.c
+++ linux-4.4.0/drivers/acpi/acpica/hwxface.c
@@ -504,11 +504,20 @@
 	 * Evaluate the \_Sx namespace object containing the register values
 	 * for this state
 	 */
-	info->relative_pathname =
-	    ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
+	info->relative_pathname = ACPI_CAST_PTR(char,
+						acpi_gbl_sleep_state_names
+						[sleep_state]);
+
 	status = acpi_ns_evaluate(info);
 	if (ACPI_FAILURE(status)) {
-		goto cleanup;
+		if (status == AE_NOT_FOUND) {
+
+			/* The _Sx states are optional, ignore NOT_FOUND */
+
+			goto final_cleanup;
+		}
+
+		goto warning_cleanup;
 	}
 
 	/* Must have a return object */
@@ -517,7 +526,7 @@
 		ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
 			    info->relative_pathname));
 		status = AE_AML_NO_RETURN_VALUE;
-		goto cleanup;
+		goto warning_cleanup;
 	}
 
 	/* Return object must be of type Package */
@@ -526,7 +535,7 @@
 		ACPI_ERROR((AE_INFO,
 			    "Sleep State return object is not a Package"));
 		status = AE_AML_OPERAND_TYPE;
-		goto cleanup1;
+		goto return_value_cleanup;
 	}
 
 	/*
@@ -570,16 +579,17 @@
 		break;
 	}
 
-cleanup1:
+return_value_cleanup:
 	acpi_ut_remove_reference(info->return_object);
 
-cleanup:
+warning_cleanup:
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status,
 				"While evaluating Sleep State [%s]",
 				info->relative_pathname));
 	}
 
+final_cleanup:
 	ACPI_FREE(info);
 	return_ACPI_STATUS(status);
 }
--- linux-4.4.0.orig/drivers/acpi/acpica/nseval.c
+++ linux-4.4.0/drivers/acpi/acpica/nseval.c
@@ -308,6 +308,14 @@
 		/* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
 
 		status = AE_OK;
+	} else if (ACPI_FAILURE(status)) {
+
+		/* If return_object exists, delete it */
+
+		if (info->return_object) {
+			acpi_ut_remove_reference(info->return_object);
+			info->return_object = NULL;
+		}
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
--- linux-4.4.0.orig/drivers/acpi/acpica/nsutils.c
+++ linux-4.4.0/drivers/acpi/acpica/nsutils.c
@@ -593,25 +593,20 @@
 void acpi_ns_terminate(void)
 {
 	acpi_status status;
+	union acpi_operand_object *prev;
+	union acpi_operand_object *next;
 
 	ACPI_FUNCTION_TRACE(ns_terminate);
 
-#ifdef ACPI_EXEC_APP
-	{
-		union acpi_operand_object *prev;
-		union acpi_operand_object *next;
+	/* Delete any module-level code blocks */
 
-		/* Delete any module-level code blocks */
-
-		next = acpi_gbl_module_code_list;
-		while (next) {
-			prev = next;
-			next = next->method.mutex;
-			prev->method.mutex = NULL;	/* Clear the Mutex (cheated) field */
-			acpi_ut_remove_reference(prev);
-		}
+	next = acpi_gbl_module_code_list;
+	while (next) {
+		prev = next;
+		next = next->method.mutex;
+		prev->method.mutex = NULL;	/* Clear the Mutex (cheated) field */
+		acpi_ut_remove_reference(prev);
 	}
-#endif
 
 	/*
 	 * Free the entire namespace -- all nodes and all objects
--- linux-4.4.0.orig/drivers/acpi/acpica/psobject.c
+++ linux-4.4.0/drivers/acpi/acpica/psobject.c
@@ -121,6 +121,9 @@
 			     (u32)(aml_offset +
 				   sizeof(struct acpi_table_header)));
 
+			ACPI_ERROR((AE_INFO,
+				    "Aborting disassembly, AML byte code is corrupt"));
+
 			/* Dump the context surrounding the invalid opcode */
 
 			acpi_ut_dump_buffer(((u8 *)walk_state->parser_state.
@@ -129,6 +132,14 @@
 					     sizeof(struct acpi_table_header) -
 					     16));
 			acpi_os_printf(" */\n");
+
+			/*
+			 * Just abort the disassembly, cannot continue because the
+			 * parser is essentially lost. The disassembler can then
+			 * randomly fail because an ill-constructed parse tree
+			 * can result.
+			 */
+			return_ACPI_STATUS(AE_AML_BAD_OPCODE);
 #endif
 		}
 
@@ -293,6 +304,9 @@
 	if (status == AE_CTRL_PARSE_CONTINUE) {
 		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
 	}
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
 
 	/* Create Op structure and append to parent's argument list */
 
--- linux-4.4.0.orig/drivers/acpi/acpica/utdelete.c
+++ linux-4.4.0/drivers/acpi/acpica/utdelete.c
@@ -590,11 +590,6 @@
 			next_object = object->buffer_field.buffer_obj;
 			break;
 
-		case ACPI_TYPE_LOCAL_REGION_FIELD:
-
-			next_object = object->field.region_obj;
-			break;
-
 		case ACPI_TYPE_LOCAL_BANK_FIELD:
 
 			next_object = object->bank_field.bank_obj;
@@ -635,6 +630,7 @@
 			}
 			break;
 
+		case ACPI_TYPE_LOCAL_REGION_FIELD:
 		case ACPI_TYPE_REGION:
 		default:
 
--- linux-4.4.0.orig/drivers/acpi/apei/erst.c
+++ linux-4.4.0/drivers/acpi/apei/erst.c
@@ -1020,7 +1020,7 @@
 	/* The record may be cleared by others, try read next record */
 	if (len == -ENOENT)
 		goto skip;
-	else if (len < sizeof(*rcd)) {
+	else if (len < 0 || len < sizeof(*rcd)) {
 		rc = -EIO;
 		goto out;
 	}
--- linux-4.4.0.orig/drivers/acpi/apei/ghes.c
+++ linux-4.4.0/drivers/acpi/apei/ghes.c
@@ -198,40 +198,40 @@
 	return 0;
 }
 
-static void ghes_estatus_pool_free_chunk_page(struct gen_pool *pool,
+static void ghes_estatus_pool_free_chunk(struct gen_pool *pool,
 					      struct gen_pool_chunk *chunk,
 					      void *data)
 {
-	free_page(chunk->start_addr);
+	vfree((void *)chunk->start_addr);
 }
 
 static void ghes_estatus_pool_exit(void)
 {
 	gen_pool_for_each_chunk(ghes_estatus_pool,
-				ghes_estatus_pool_free_chunk_page, NULL);
+				ghes_estatus_pool_free_chunk, NULL);
 	gen_pool_destroy(ghes_estatus_pool);
 }
 
 static int ghes_estatus_pool_expand(unsigned long len)
 {
-	unsigned long i, pages, size, addr;
-	int ret;
+	unsigned long size, addr;
 
 	ghes_estatus_pool_size_request += PAGE_ALIGN(len);
 	size = gen_pool_size(ghes_estatus_pool);
 	if (size >= ghes_estatus_pool_size_request)
 		return 0;
-	pages = (ghes_estatus_pool_size_request - size) / PAGE_SIZE;
-	for (i = 0; i < pages; i++) {
-		addr = __get_free_page(GFP_KERNEL);
-		if (!addr)
-			return -ENOMEM;
-		ret = gen_pool_add(ghes_estatus_pool, addr, PAGE_SIZE, -1);
-		if (ret)
-			return ret;
-	}
 
-	return 0;
+	addr = (unsigned long)vmalloc(PAGE_ALIGN(len));
+	if (!addr)
+		return -ENOMEM;
+
+	/*
+	 * New allocation must be visible in all pgd before it can be found by
+	 * an NMI allocating from the pool.
+	 */
+	vmalloc_sync_mappings();
+
+	return gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1);
 }
 
 static struct ghes *ghes_new(struct acpi_hest_generic *generic)
@@ -657,7 +657,7 @@
 	ghes_do_proc(ghes, ghes->estatus);
 out:
 	ghes_clear_estatus(ghes);
-	return 0;
+	return rc;
 }
 
 static void ghes_add_timer(struct ghes *ghes)
@@ -847,6 +847,8 @@
 		if (ghes_read_estatus(ghes, 1)) {
 			ghes_clear_estatus(ghes);
 			continue;
+		} else {
+			ret = NMI_HANDLED;
 		}
 
 		sev = ghes_severity(ghes->estatus->error_severity);
@@ -858,12 +860,11 @@
 
 		__process_error(ghes);
 		ghes_clear_estatus(ghes);
-
-		ret = NMI_HANDLED;
 	}
 
 #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
-	irq_work_queue(&ghes_proc_irq_work);
+	if (ret == NMI_HANDLED)
+		irq_work_queue(&ghes_proc_irq_work);
 #endif
 	atomic_dec(&ghes_in_nmi);
 	return ret;
@@ -1066,6 +1067,7 @@
 		if (list_empty(&ghes_sci))
 			unregister_acpi_hed_notifier(&ghes_notifier_sci);
 		mutex_unlock(&ghes_list_mutex);
+		synchronize_rcu();
 		break;
 	case ACPI_HEST_NOTIFY_NMI:
 		ghes_nmi_remove(ghes);
--- linux-4.4.0.orig/drivers/acpi/blacklist.c
+++ linux-4.4.0/drivers/acpi/blacklist.c
@@ -313,6 +313,77 @@
 	},
 
 	/*
+	 * The following Lenovo models have a broken workaround in the
+	 * acpi_video backlight implementation to meet the Windows 8
+	 * requirement of 101 backlight levels. Reverting to pre-Win8
+	 * behavior fixes the problem.
+	 */
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad L430",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L430"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad T430",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad T430s",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad T530",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T530"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad W530",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad X1 Carbon",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad X230",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad Edge E330",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Edge E330"),
+		},
+	},
+
+	/*
 	 * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
 	 * Linux ignores it, except for the machines enumerated below.
 	 */
@@ -346,6 +417,34 @@
 		      DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"),
 		},
 	},
+	/*
+	 * Resolves a quirk with the Dell Latitude 3350 that
+	 * causes the ethernet adapter to not function.
+	 */
+	{
+	 .callback = dmi_enable_rev_override,
+	 .ident = "DELL Latitude 3350",
+	 .matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"),
+		},
+	},
+	{
+	 .callback = dmi_enable_rev_override,
+	 .ident = "DELL Precision 5520",
+	 .matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "Precision 5520"),
+		},
+	},
+	{
+	 .callback = dmi_enable_rev_override,
+	 .ident = "DELL Precision 3520",
+	 .matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3520"),
+		},
+	},
 #endif
 	{}
 };
--- linux-4.4.0.orig/drivers/acpi/bus.c
+++ linux-4.4.0/drivers/acpi/bus.c
@@ -154,7 +154,7 @@
 {
 	acpi_status status;
 
-	if (!*data)
+	if (!data)
 		return -EINVAL;
 
 	status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
@@ -1004,6 +1004,9 @@
 		goto error1;
 	}
 
+	/* Set capability bits for _OSC under processor scope */
+	acpi_early_processor_osc();
+
 	/*
 	 * _OSC method may exist in module level code,
 	 * so it must be run after ACPI_FULL_INITIALIZATION
--- linux-4.4.0.orig/drivers/acpi/cppc_acpi.c
+++ linux-4.4.0/drivers/acpi/cppc_acpi.c
@@ -137,8 +137,10 @@
 	union acpi_object  *psd = NULL;
 	struct acpi_psd_package *pdomain;
 
-	status = acpi_evaluate_object_typed(handle, "_PSD", NULL, &buffer,
-			ACPI_TYPE_PACKAGE);
+	status = acpi_evaluate_object_typed(handle, "_PSD", NULL,
+					    &buffer, ACPI_TYPE_PACKAGE);
+	if (status == AE_NOT_FOUND)	/* _PSD is optional */
+		return 0;
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
@@ -216,8 +218,10 @@
 			continue;
 
 		cpc_ptr = per_cpu(cpc_desc_ptr, i);
-		if (!cpc_ptr)
-			continue;
+		if (!cpc_ptr) {
+			retval = -EFAULT;
+			goto err_ret;
+		}
 
 		pdomain = &(cpc_ptr->domain_info);
 		cpumask_set_cpu(i, pr->shared_cpu_map);
@@ -239,8 +243,10 @@
 				continue;
 
 			match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
-			if (!match_cpc_ptr)
-				continue;
+			if (!match_cpc_ptr) {
+				retval = -EFAULT;
+				goto err_ret;
+			}
 
 			match_pdomain = &(match_cpc_ptr->domain_info);
 			if (match_pdomain->domain != pdomain->domain)
@@ -270,8 +276,10 @@
 				continue;
 
 			match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
-			if (!match_cpc_ptr)
-				continue;
+			if (!match_cpc_ptr) {
+				retval = -EFAULT;
+				goto err_ret;
+			}
 
 			match_pdomain = &(match_cpc_ptr->domain_info);
 			if (match_pdomain->domain != pdomain->domain)
@@ -502,9 +510,6 @@
 	/* Store CPU Logical ID */
 	cpc_ptr->cpu_id = pr->id;
 
-	/* Plug it into this CPUs CPC descriptor. */
-	per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
-
 	/* Parse PSD data for this CPU */
 	ret = acpi_get_psd(cpc_ptr, handle);
 	if (ret)
@@ -517,6 +522,9 @@
 			goto out_free;
 	}
 
+	/* Plug PSD data into this CPUs CPC descriptor. */
+	per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
+
 	/* Everything looks okay */
 	pr_debug("Parsed CPC struct for CPU: %d\n", pr->id);
 
--- linux-4.4.0.orig/drivers/acpi/custom_method.c
+++ linux-4.4.0/drivers/acpi/custom_method.c
@@ -29,6 +29,9 @@
 	struct acpi_table_header table;
 	acpi_status status;
 
+	if (secure_modules())
+		return -EPERM;
+
 	if (!(*ppos)) {
 		/* parse the table header to get the table length */
 		if (count <= sizeof(struct acpi_table_header))
@@ -48,8 +51,11 @@
 	if ((*ppos > max_size) ||
 	    (*ppos + count > max_size) ||
 	    (*ppos + count < count) ||
-	    (count > uncopied_bytes))
+	    (count > uncopied_bytes)) {
+		kfree(buf);
+		buf = NULL;
 		return -EINVAL;
+	}
 
 	if (copy_from_user(buf + (*ppos), user_buf, count)) {
 		kfree(buf);
--- linux-4.4.0.orig/drivers/acpi/device_pm.c
+++ linux-4.4.0/drivers/acpi/device_pm.c
@@ -170,7 +170,7 @@
 		 * possibly drop references to the power resources in use.
 		 */
 		state = ACPI_STATE_D3_HOT;
-		/* If _PR3 is not available, use D3hot as the target state. */
+		/* If D3cold is not supported, use D3hot as the target state. */
 		if (!device->power.states[ACPI_STATE_D3_COLD].flags.valid)
 			target_state = state;
 	} else if (!device->power.states[state].flags.valid) {
@@ -225,13 +225,13 @@
  end:
 	if (result) {
 		dev_warn(&device->dev, "Failed to change power state to %s\n",
-			 acpi_power_state_string(state));
+			 acpi_power_state_string(target_state));
 	} else {
 		device->power.state = target_state;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Device [%s] transitioned to %s\n",
 				  device->pnp.bus_id,
-				  acpi_power_state_string(state)));
+				  acpi_power_state_string(target_state)));
 	}
 
 	return result;
@@ -1094,9 +1094,19 @@
  */
 int acpi_dev_pm_attach(struct device *dev, bool power_on)
 {
+	/*
+	 * Skip devices whose ACPI companions match the device IDs below,
+	 * because they require special power management handling incompatible
+	 * with the generic ACPI PM domain.
+	 */
+	static const struct acpi_device_id special_pm_ids[] = {
+		{"PNP0C0B", }, /* Generic ACPI fan */
+		{"INT3404", }, /* Fan */
+		{}
+	};
 	struct acpi_device *adev = ACPI_COMPANION(dev);
 
-	if (!adev)
+	if (!adev || !acpi_match_device_ids(adev, special_pm_ids))
 		return -ENODEV;
 
 	if (dev->pm_domain)
--- linux-4.4.0.orig/drivers/acpi/device_sysfs.c
+++ linux-4.4.0/drivers/acpi/device_sysfs.c
@@ -146,6 +146,10 @@
 	int count;
 	struct acpi_hardware_id *id;
 
+	/* Avoid unnecessarily loading modules for non present devices. */
+	if (!acpi_device_is_present(acpi_dev))
+		return 0;
+
 	/*
 	 * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
 	 * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
@@ -198,11 +202,15 @@
 {
 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
 	const union acpi_object *of_compatible, *obj;
+	acpi_status status;
 	int len, count;
 	int i, nval;
 	char *c;
 
-	acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+	status = acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
 	/* DT strings are all in lower case */
 	for (c = buf.pointer; *c != '\0'; c++)
 		*c = tolower(*c);
@@ -251,20 +259,12 @@
 	if (add_uevent_var(env, "MODALIAS="))
 		return -ENOMEM;
 
-	len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
-				  sizeof(env->buf) - env->buflen);
-	if (len < 0)
-		return len;
-
-	env->buflen += len;
-	if (!adev->data.of_compatible)
-		return 0;
-
-	if (len > 0 && add_uevent_var(env, "MODALIAS="))
-		return -ENOMEM;
-
-	len = create_of_modalias(adev, &env->buf[env->buflen - 1],
-				 sizeof(env->buf) - env->buflen);
+	if (adev->data.of_compatible)
+		len = create_of_modalias(adev, &env->buf[env->buflen - 1],
+					 sizeof(env->buf) - env->buflen);
+	else
+		len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
+					  sizeof(env->buf) - env->buflen);
 	if (len < 0)
 		return len;
 
--- linux-4.4.0.orig/drivers/acpi/ec.c
+++ linux-4.4.0/drivers/acpi/ec.c
@@ -101,6 +101,7 @@
 #define ACPI_EC_UDELAY_POLL	550	/* Wait 1ms for EC transaction polling */
 #define ACPI_EC_CLEAR_MAX	100	/* Maximum number of events to query
 					 * when trying to clear the EC */
+#define ACPI_EC_MAX_QUERIES	16	/* Maximum number of parallel queries */
 
 enum {
 	EC_FLAGS_QUERY_PENDING,		/* Query is pending */
@@ -121,6 +122,10 @@
 module_param(ec_delay, uint, 0644);
 MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
 
+static unsigned int ec_max_queries __read_mostly = ACPI_EC_MAX_QUERIES;
+module_param(ec_max_queries, uint, 0644);
+MODULE_PARM_DESC(ec_max_queries, "Maximum parallel _Qxx evaluations");
+
 static bool ec_busy_polling __read_mostly;
 module_param(ec_busy_polling, bool, 0644);
 MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction");
@@ -174,6 +179,7 @@
 
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
+static struct workqueue_struct *ec_query_wq;
 
 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
 static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
@@ -938,28 +944,20 @@
                                 Event Management
    -------------------------------------------------------------------------- */
 static struct acpi_ec_query_handler *
-acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
-{
-	if (handler)
-		kref_get(&handler->kref);
-	return handler;
-}
-
-static struct acpi_ec_query_handler *
 acpi_ec_get_query_handler_by_value(struct acpi_ec *ec, u8 value)
 {
 	struct acpi_ec_query_handler *handler;
-	bool found = false;
 
 	mutex_lock(&ec->mutex);
 	list_for_each_entry(handler, &ec->list, node) {
 		if (value == handler->query_bit) {
-			found = true;
-			break;
+			kref_get(&handler->kref);
+			mutex_unlock(&ec->mutex);
+			return handler;
 		}
 	}
 	mutex_unlock(&ec->mutex);
-	return found ? acpi_ec_get_query_handler(handler) : NULL;
+	return NULL;
 }
 
 static void acpi_ec_query_handler_release(struct kref *kref)
@@ -1097,7 +1095,7 @@
 	 * work queue execution.
 	 */
 	ec_dbg_evt("Query(0x%02x) scheduled", value);
-	if (!schedule_work(&q->work)) {
+	if (!queue_work(ec_query_wq, &q->work)) {
 		ec_dbg_evt("Query(0x%02x) overlapped", value);
 		result = -EBUSY;
 	}
@@ -1657,15 +1655,41 @@
 		},
 };
 
+static inline int acpi_ec_query_init(void)
+{
+	if (!ec_query_wq) {
+		ec_query_wq = alloc_workqueue("kec_query", 0,
+					      ec_max_queries);
+		if (!ec_query_wq)
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static inline void acpi_ec_query_exit(void)
+{
+	if (ec_query_wq) {
+		destroy_workqueue(ec_query_wq);
+		ec_query_wq = NULL;
+	}
+}
+
 int __init acpi_ec_init(void)
 {
-	int result = 0;
+	int result;
 
+	/* register workqueue for _Qxx evaluations */
+	result = acpi_ec_query_init();
+	if (result)
+		goto err_exit;
 	/* Now register the driver for the EC */
 	result = acpi_bus_register_driver(&acpi_ec_driver);
-	if (result < 0)
-		return -ENODEV;
+	if (result)
+		goto err_exit;
 
+err_exit:
+	if (result)
+		acpi_ec_query_exit();
 	return result;
 }
 
@@ -1675,5 +1699,6 @@
 {
 
 	acpi_bus_unregister_driver(&acpi_ec_driver);
+	acpi_ec_query_exit();
 }
 #endif	/* 0 */
--- linux-4.4.0.orig/drivers/acpi/glue.c
+++ linux-4.4.0/drivers/acpi/glue.c
@@ -98,7 +98,15 @@
 	if (check_children && list_empty(&adev->children))
 		return -ENODEV;
 
-	return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
+	/*
+	 * If the device has a _HID returning a valid ACPI/PNP device ID, it is
+	 * better to make it look less attractive here, so that the other device
+	 * with the same _ADR value (that may not have a valid device ID) can be
+	 * matched going forward.  [This means a second spec violation in a row,
+	 * so whatever we do here is best effort anyway.]
+	 */
+	return sta_present && !adev->pnp.type.platform_id ?
+			FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
 }
 
 struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
--- linux-4.4.0.orig/drivers/acpi/internal.h
+++ linux-4.4.0/drivers/acpi/internal.h
@@ -130,6 +130,12 @@
 static inline void acpi_early_processor_set_pdc(void) {}
 #endif
 
+#ifdef CONFIG_X86
+void acpi_early_processor_osc(void);
+#else
+static inline void acpi_early_processor_osc(void) {}
+#endif
+
 /* --------------------------------------------------------------------------
                                   Embedded Controller
    -------------------------------------------------------------------------- */
--- linux-4.4.0.orig/drivers/acpi/ioapic.c
+++ linux-4.4.0/drivers/acpi/ioapic.c
@@ -45,6 +45,12 @@
 	struct resource *res = data;
 	struct resource_win win;
 
+	/*
+	 * We might assign this to 'res' later, make sure all pointers are
+	 * cleared before the resource is added to the global list
+	 */
+	memset(&win, 0, sizeof(win));
+
 	res->flags = 0;
 	if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM) == 0)
 		return AE_OK;
--- linux-4.4.0.orig/drivers/acpi/nfit.c
+++ linux-4.4.0/drivers/acpi/nfit.c
@@ -468,37 +468,16 @@
 	nfit_mem->bdw = NULL;
 }
 
-static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
+static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
 		struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
 {
 	u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
 	struct nfit_memdev *nfit_memdev;
 	struct nfit_flush *nfit_flush;
-	struct nfit_dcr *nfit_dcr;
 	struct nfit_bdw *nfit_bdw;
 	struct nfit_idt *nfit_idt;
 	u16 idt_idx, range_index;
 
-	list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
-		if (nfit_dcr->dcr->region_index != dcr)
-			continue;
-		nfit_mem->dcr = nfit_dcr->dcr;
-		break;
-	}
-
-	if (!nfit_mem->dcr) {
-		dev_dbg(acpi_desc->dev, "SPA %d missing:%s%s\n",
-				spa->range_index, __to_nfit_memdev(nfit_mem)
-				? "" : " MEMDEV", nfit_mem->dcr ? "" : " DCR");
-		return -ENODEV;
-	}
-
-	/*
-	 * We've found enough to create an nvdimm, optionally
-	 * find an associated BDW
-	 */
-	list_add(&nfit_mem->list, &acpi_desc->dimms);
-
 	list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
 		if (nfit_bdw->bdw->region_index != dcr)
 			continue;
@@ -507,12 +486,12 @@
 	}
 
 	if (!nfit_mem->bdw)
-		return 0;
+		return;
 
 	nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
 
 	if (!nfit_mem->spa_bdw)
-		return 0;
+		return;
 
 	range_index = nfit_mem->spa_bdw->range_index;
 	list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
@@ -537,8 +516,6 @@
 		}
 		break;
 	}
-
-	return 0;
 }
 
 static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
@@ -547,7 +524,6 @@
 	struct nfit_mem *nfit_mem, *found;
 	struct nfit_memdev *nfit_memdev;
 	int type = nfit_spa_type(spa);
-	u16 dcr;
 
 	switch (type) {
 	case NFIT_SPA_DCR:
@@ -558,14 +534,18 @@
 	}
 
 	list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-		int rc;
+		struct nfit_dcr *nfit_dcr;
+		u32 device_handle;
+		u16 dcr;
 
 		if (nfit_memdev->memdev->range_index != spa->range_index)
 			continue;
 		found = NULL;
 		dcr = nfit_memdev->memdev->region_index;
+		device_handle = nfit_memdev->memdev->device_handle;
 		list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
-			if (__to_nfit_memdev(nfit_mem)->region_index == dcr) {
+			if (__to_nfit_memdev(nfit_mem)->device_handle
+					== device_handle) {
 				found = nfit_mem;
 				break;
 			}
@@ -578,6 +558,31 @@
 			if (!nfit_mem)
 				return -ENOMEM;
 			INIT_LIST_HEAD(&nfit_mem->list);
+			list_add(&nfit_mem->list, &acpi_desc->dimms);
+		}
+
+		list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+			if (nfit_dcr->dcr->region_index != dcr)
+				continue;
+			/*
+			 * Record the control region for the dimm.  For
+			 * the ACPI 6.1 case, where there are separate
+			 * control regions for the pmem vs blk
+			 * interfaces, be sure to record the extended
+			 * blk details.
+			 */
+			if (!nfit_mem->dcr)
+				nfit_mem->dcr = nfit_dcr->dcr;
+			else if (nfit_mem->dcr->windows == 0
+					&& nfit_dcr->dcr->windows)
+				nfit_mem->dcr = nfit_dcr->dcr;
+			break;
+		}
+
+		if (dcr && !nfit_mem->dcr) {
+			dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
+					spa->range_index, dcr);
+			return -ENODEV;
 		}
 
 		if (type == NFIT_SPA_DCR) {
@@ -594,6 +599,7 @@
 				nfit_mem->idt_dcr = nfit_idt->idt;
 				break;
 			}
+			nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
 		} else {
 			/*
 			 * A single dimm may belong to multiple SPA-PM
@@ -602,13 +608,6 @@
 			 */
 			nfit_mem->memdev_pmem = nfit_memdev->memdev;
 		}
-
-		if (found)
-			continue;
-
-		rc = nfit_mem_add(acpi_desc, nfit_mem, spa);
-		if (rc)
-			return rc;
 	}
 
 	return 0;
@@ -966,7 +965,7 @@
 		+ num_mappings * sizeof(struct nfit_set_info_map);
 }
 
-static int cmp_map(const void *m0, const void *m1)
+static int cmp_map_compat(const void *m0, const void *m1)
 {
 	const struct nfit_set_info_map *map0 = m0;
 	const struct nfit_set_info_map *map1 = m1;
@@ -975,6 +974,18 @@
 			sizeof(u64));
 }
 
+static int cmp_map(const void *m0, const void *m1)
+{
+	const struct nfit_set_info_map *map0 = m0;
+	const struct nfit_set_info_map *map1 = m1;
+
+	if (map0->region_offset < map1->region_offset)
+		return -1;
+	else if (map0->region_offset > map1->region_offset)
+		return 1;
+	return 0;
+}
+
 /* Retrieve the nth entry referencing this spa */
 static struct acpi_nfit_memory_map *memdev_from_spa(
 		struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
@@ -1030,6 +1041,12 @@
 	sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
 			cmp_map, NULL);
 	nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+
+	/* support namespaces created with the wrong sort order */
+	sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
+			cmp_map_compat, NULL);
+	nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+
 	ndr_desc->nd_set = nd_set;
 	devm_kfree(dev, info);
 
@@ -1073,11 +1090,12 @@
 {
 	struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
 	u64 offset = nfit_blk->stat_offset + mmio->size * bw;
+	const u32 STATUS_MASK = 0x80000037;
 
 	if (mmio->num_lines)
 		offset = to_interleave_offset(offset, mmio);
 
-	return readl(mmio->addr.base + offset);
+	return readl(mmio->addr.base + offset) & STATUS_MASK;
 }
 
 static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
@@ -1806,6 +1824,9 @@
 
 	dev_dbg(dev, "%s: event: %d\n", __func__, event);
 
+	if (event != NFIT_NOTIFY_UPDATE)
+		return;
+
 	device_lock(dev);
 	if (!dev->driver) {
 		/* dev->driver may be null if we're being removed */
--- linux-4.4.0.orig/drivers/acpi/nfit.h
+++ linux-4.4.0/drivers/acpi/nfit.h
@@ -45,6 +45,10 @@
 	ND_BLK_DCR_LATCH = 2,
 };
 
+enum nfit_root_notifiers {
+	NFIT_NOTIFY_UPDATE = 0x80,
+};
+
 struct nfit_spa {
 	struct acpi_nfit_system_address *spa;
 	struct list_head list;
--- linux-4.4.0.orig/drivers/acpi/numa.c
+++ linux-4.4.0/drivers/acpi/numa.c
@@ -103,25 +103,27 @@
  */
 int acpi_map_pxm_to_online_node(int pxm)
 {
-	int node, n, dist, min_dist;
+	int node, min_node;
 
 	node = acpi_map_pxm_to_node(pxm);
 
 	if (node == NUMA_NO_NODE)
 		node = 0;
 
+	min_node = node;
 	if (!node_online(node)) {
-		min_dist = INT_MAX;
+		int min_dist = INT_MAX, dist, n;
+
 		for_each_online_node(n) {
 			dist = node_distance(node, n);
 			if (dist < min_dist) {
 				min_dist = dist;
-				node = n;
+				min_node = n;
 			}
 		}
 	}
 
-	return node;
+	return min_node;
 }
 EXPORT_SYMBOL(acpi_map_pxm_to_online_node);
 
@@ -327,10 +329,18 @@
 
 	/* SRAT: Static Resource Affinity Table */
 	if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
-		acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
-				     acpi_parse_x2apic_affinity, 0);
-		acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
-				     acpi_parse_processor_affinity, 0);
+		struct acpi_subtable_proc srat_proc[2];
+
+		memset(srat_proc, 0, sizeof(srat_proc));
+		srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY;
+		srat_proc[0].handler = acpi_parse_processor_affinity;
+		srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY;
+		srat_proc[1].handler = acpi_parse_x2apic_affinity;
+
+		acpi_table_parse_entries_array(ACPI_SIG_SRAT,
+					sizeof(struct acpi_table_srat),
+					srat_proc, ARRAY_SIZE(srat_proc), 0);
+
 		cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
 					    acpi_parse_memory_affinity,
 					    NR_NODE_MEMBLKS);
--- linux-4.4.0.orig/drivers/acpi/osl.c
+++ linux-4.4.0/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -135,7 +136,7 @@
 	unsigned int	enable:1;
 	unsigned int	dmi:1;
 	unsigned int	cmdline:1;
-	unsigned int	default_disabling:1;
+	u8		default_disabling;
 } osi_linux = {0, 0, 0, 0};
 
 static u32 acpi_osi_handler(acpi_string interface, u32 supported)
@@ -252,7 +253,7 @@
 acpi_physical_address __init acpi_os_get_root_pointer(void)
 {
 #ifdef CONFIG_KEXEC
-	if (acpi_rsdp)
+	if (acpi_rsdp && !secure_modules())
 		return acpi_rsdp;
 #endif
 
@@ -424,24 +425,27 @@
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
-static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
+/* Must be called with mutex_lock(&acpi_ioremap_lock) */
+static unsigned long acpi_os_drop_map_ref(struct acpi_ioremap *map)
 {
-	if (!--map->refcount)
+	unsigned long refcount = --map->refcount;
+
+	if (!refcount)
 		list_del_rcu(&map->list);
+	return refcount;
 }
 
 static void acpi_os_map_cleanup(struct acpi_ioremap *map)
 {
-	if (!map->refcount) {
-		synchronize_rcu_expedited();
-		acpi_unmap(map->phys, map->virt);
-		kfree(map);
-	}
+	synchronize_rcu_expedited();
+	acpi_unmap(map->phys, map->virt);
+	kfree(map);
 }
 
 void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
 {
 	struct acpi_ioremap *map;
+	unsigned long refcount;
 
 	if (!acpi_gbl_permanent_mmap) {
 		__acpi_unmap_table(virt, size);
@@ -455,10 +459,11 @@
 		WARN(true, PREFIX "%s: bad address %p\n", __func__, virt);
 		return;
 	}
-	acpi_os_drop_map_ref(map);
+	refcount = acpi_os_drop_map_ref(map);
 	mutex_unlock(&acpi_ioremap_lock);
 
-	acpi_os_map_cleanup(map);
+	if (!refcount)
+		acpi_os_map_cleanup(map);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem);
 
@@ -499,6 +504,7 @@
 {
 	u64 addr;
 	struct acpi_ioremap *map;
+	unsigned long refcount;
 
 	if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
 		return;
@@ -514,10 +520,11 @@
 		mutex_unlock(&acpi_ioremap_lock);
 		return;
 	}
-	acpi_os_drop_map_ref(map);
+	refcount = acpi_os_drop_map_ref(map);
 	mutex_unlock(&acpi_ioremap_lock);
 
-	acpi_os_map_cleanup(map);
+	if (!refcount)
+		acpi_os_map_cleanup(map);
 }
 EXPORT_SYMBOL(acpi_os_unmap_generic_address);
 
@@ -668,6 +675,11 @@
 	if (table_nr == 0)
 		return;
 
+	if (secure_modules()) {
+		pr_notice("kernel is locked down, ignoring table override\n");
+		return;
+	}
+
 	acpi_tables_addr =
 		memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
 				       all_tables_size, PAGE_SIZE);
@@ -1186,6 +1198,7 @@
 	flush_workqueue(kacpid_wq);
 	flush_workqueue(kacpi_notify_wq);
 }
+EXPORT_SYMBOL(acpi_os_wait_events_complete);
 
 struct acpi_hp_work {
 	struct work_struct work;
@@ -1444,10 +1457,13 @@
 	if (*str == '!') {
 		str++;
 		if (*str == '\0') {
-			osi_linux.default_disabling = 1;
+			/* Do not override acpi_osi=!* */
+			if (!osi_linux.default_disabling)
+				osi_linux.default_disabling =
+					ACPI_DISABLE_ALL_VENDOR_STRINGS;
 			return;
 		} else if (*str == '*') {
-			acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS);
+			osi_linux.default_disabling = ACPI_DISABLE_ALL_STRINGS;
 			for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
 				osi = &osi_setup_entries[i];
 				osi->enable = false;
@@ -1520,10 +1536,13 @@
 	acpi_status status;
 
 	if (osi_linux.default_disabling) {
-		status = acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
+		status = acpi_update_interfaces(osi_linux.default_disabling);
 
 		if (ACPI_SUCCESS(status))
-			printk(KERN_INFO PREFIX "Disabled all _OSI OS vendors\n");
+			printk(KERN_INFO PREFIX "Disabled all _OSI OS vendors%s\n",
+				osi_linux.default_disabling ==
+				ACPI_DISABLE_ALL_STRINGS ?
+				" and feature groups" : "");
 	}
 
 	for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
--- linux-4.4.0.orig/drivers/acpi/pci_irq.c
+++ linux-4.4.0/drivers/acpi/pci_irq.c
@@ -131,9 +131,6 @@
 		quirk = &prt_quirks[i];
 
 		/* All current quirks involve link devices, not GSIs */
-		if (!prt->source)
-			continue;
-
 		if (dmi_check_system(quirk->system) &&
 		    entry->id.segment == quirk->segment &&
 		    entry->id.bus == quirk->bus &&
@@ -409,7 +406,7 @@
 		return 0;
 	}
 
-	if (pci_has_managed_irq(dev))
+	if (dev->irq_managed && dev->irq > 0)
 		return 0;
 
 	entry = acpi_pci_irq_lookup(dev, pin);
@@ -454,7 +451,8 @@
 		kfree(entry);
 		return rc;
 	}
-	pci_set_managed_irq(dev, rc);
+	dev->irq = rc;
+	dev->irq_managed = 1;
 
 	if (link)
 		snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
@@ -477,8 +475,16 @@
 	u8 pin;
 
 	pin = dev->pin;
-	if (!pin || !pci_has_managed_irq(dev))
+	if (!pin || !dev->irq_managed || dev->irq <= 0)
+		return;
+
+	/* Keep IOAPIC pin configuration when suspending */
+	if (dev->dev.power.is_prepared)
 		return;
+#ifdef	CONFIG_PM
+	if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+		return;
+#endif
 
 	entry = acpi_pci_irq_lookup(dev, pin);
 	if (!entry)
@@ -499,6 +505,6 @@
 	dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
 	if (gsi >= 0) {
 		acpi_unregister_gsi(gsi);
-		pci_reset_managed_irq(dev);
+		dev->irq_managed = 0;
 	}
 }
--- linux-4.4.0.orig/drivers/acpi/pci_mcfg.c
+++ linux-4.4.0/drivers/acpi/pci_mcfg.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *	Author: Jayachandran C <jchandra@broadcom.com>
+ * Copyright (C) 2016 Semihalf
+ * 	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+#define pr_fmt(fmt) "ACPI: " fmt
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci-acpi.h>
+
+/* Structure to hold entries from the MCFG table */
+struct mcfg_entry {
+	struct list_head	list;
+	phys_addr_t		addr;
+	u16			segment;
+	u8			bus_start;
+	u8			bus_end;
+};
+
+/* List to save MCFG entries */
+static LIST_HEAD(pci_mcfg_list);
+
+phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
+{
+	struct mcfg_entry *e;
+
+	/*
+	 * We expect exact match, unless MCFG entry end bus covers more than
+	 * specified by caller.
+	 */
+	list_for_each_entry(e, &pci_mcfg_list, list) {
+		if (e->segment == seg && e->bus_start == bus_res->start &&
+		    e->bus_end >= bus_res->end)
+			return e->addr;
+	}
+
+	return 0;
+}
+
+static __init int pci_mcfg_parse(struct acpi_table_header *header)
+{
+	struct acpi_table_mcfg *mcfg;
+	struct acpi_mcfg_allocation *mptr;
+	struct mcfg_entry *e, *arr;
+	int i, n;
+
+	if (header->length < sizeof(struct acpi_table_mcfg))
+		return -EINVAL;
+
+	n = (header->length - sizeof(struct acpi_table_mcfg)) /
+					sizeof(struct acpi_mcfg_allocation);
+	mcfg = (struct acpi_table_mcfg *)header;
+	mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
+
+	arr = kcalloc(n, sizeof(*arr), GFP_KERNEL);
+	if (!arr)
+		return -ENOMEM;
+
+	for (i = 0, e = arr; i < n; i++, mptr++, e++) {
+		e->segment = mptr->pci_segment;
+		e->addr =  mptr->address;
+		e->bus_start = mptr->start_bus_number;
+		e->bus_end = mptr->end_bus_number;
+		list_add(&e->list, &pci_mcfg_list);
+	}
+
+	pr_info("MCFG table detected, %d entries\n", n);
+	return 0;
+}
+
+/* Interface called by ACPI - parse and save MCFG table */
+void __init pci_mmcfg_late_init(void)
+{
+	int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
+	if (err)
+		pr_err("Failed to parse MCFG (%d)\n", err);
+}
--- linux-4.4.0.orig/drivers/acpi/pci_root.c
+++ linux-4.4.0/drivers/acpi/pci_root.c
@@ -454,8 +454,9 @@
 	decode_osc_support(root, "OS supports", support);
 	status = acpi_pci_osc_support(root, support);
 	if (ACPI_FAILURE(status)) {
-		dev_info(&device->dev, "_OSC failed (%s); disabling ASPM\n",
-			 acpi_format_exception(status));
+		dev_info(&device->dev, "_OSC failed (%s)%s\n",
+			 acpi_format_exception(status),
+			 pcie_aspm_support_enabled() ? "; disabling ASPM" : "");
 		*no_aspm = 1;
 		return;
 	}
@@ -472,9 +473,11 @@
 	}
 
 	control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL
-		| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
 		| OSC_PCI_EXPRESS_PME_CONTROL;
 
+	if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
+		control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL;
+
 	if (pci_aer_available()) {
 		if (aer_acpi_firmware_first())
 			dev_info(&device->dev,
@@ -720,6 +723,36 @@
 	}
 }
 
+static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
+{
+#ifdef PCI_IOBASE
+	struct resource *res = entry->res;
+	resource_size_t cpu_addr = res->start;
+	resource_size_t pci_addr = cpu_addr - entry->offset;
+	resource_size_t length = resource_size(res);
+	unsigned long port;
+
+	if (pci_register_io_range(cpu_addr, length))
+		goto err;
+
+	port = pci_address_to_pio(cpu_addr);
+	if (port == (unsigned long)-1)
+		goto err;
+
+	res->start = port;
+	res->end = port + length - 1;
+	entry->offset = port - pci_addr;
+
+	if (pci_remap_iospace(res, cpu_addr) < 0)
+		goto err;
+
+	pr_info("Remapped I/O %pa to %pR\n", &cpu_addr, res);
+	return;
+err:
+	res->flags |= IORESOURCE_DISABLED;
+#endif
+}
+
 int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 {
 	int ret;
@@ -740,6 +773,9 @@
 			"no IO and memory resources present in _CRS\n");
 	else {
 		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_IO)
+				acpi_pci_root_remap_iospace(entry);
+
 			if (entry->res->flags & IORESOURCE_DISABLED)
 				resource_list_destroy_entry(entry);
 			else
@@ -811,6 +847,8 @@
 
 	resource_list_for_each_entry(entry, &bridge->windows) {
 		res = entry->res;
+		if (res->flags & IORESOURCE_IO)
+			pci_unmap_iospace(res);
 		if (res->parent &&
 		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
 			release_resource(res);
--- linux-4.4.0.orig/drivers/acpi/pmic/intel_pmic_xpower.c
+++ linux-4.4.0/drivers/acpi/pmic/intel_pmic_xpower.c
@@ -28,97 +28,97 @@
 		.address = 0x00,
 		.reg = 0x13,
 		.bit = 0x05,
-	},
+	}, /* ALD1 */
 	{
 		.address = 0x04,
 		.reg = 0x13,
 		.bit = 0x06,
-	},
+	}, /* ALD2 */
 	{
 		.address = 0x08,
 		.reg = 0x13,
 		.bit = 0x07,
-	},
+	}, /* ALD3 */
 	{
 		.address = 0x0c,
 		.reg = 0x12,
 		.bit = 0x03,
-	},
+	}, /* DLD1 */
 	{
 		.address = 0x10,
 		.reg = 0x12,
 		.bit = 0x04,
-	},
+	}, /* DLD2 */
 	{
 		.address = 0x14,
 		.reg = 0x12,
 		.bit = 0x05,
-	},
+	}, /* DLD3 */
 	{
 		.address = 0x18,
 		.reg = 0x12,
 		.bit = 0x06,
-	},
+	}, /* DLD4 */
 	{
 		.address = 0x1c,
 		.reg = 0x12,
 		.bit = 0x00,
-	},
+	}, /* ELD1 */
 	{
 		.address = 0x20,
 		.reg = 0x12,
 		.bit = 0x01,
-	},
+	}, /* ELD2 */
 	{
 		.address = 0x24,
 		.reg = 0x12,
 		.bit = 0x02,
-	},
+	}, /* ELD3 */
 	{
 		.address = 0x28,
 		.reg = 0x13,
 		.bit = 0x02,
-	},
+	}, /* FLD1 */
 	{
 		.address = 0x2c,
 		.reg = 0x13,
 		.bit = 0x03,
-	},
+	}, /* FLD2 */
 	{
 		.address = 0x30,
 		.reg = 0x13,
 		.bit = 0x04,
-	},
+	}, /* FLD3 */
 	{
-		.address = 0x38,
+		.address = 0x34,
 		.reg = 0x10,
 		.bit = 0x03,
-	},
+	}, /* BUC1 */
 	{
-		.address = 0x3c,
+		.address = 0x38,
 		.reg = 0x10,
 		.bit = 0x06,
-	},
+	}, /* BUC2 */
 	{
-		.address = 0x40,
+		.address = 0x3c,
 		.reg = 0x10,
 		.bit = 0x05,
-	},
+	}, /* BUC3 */
 	{
-		.address = 0x44,
+		.address = 0x40,
 		.reg = 0x10,
 		.bit = 0x04,
-	},
+	}, /* BUC4 */
 	{
-		.address = 0x48,
+		.address = 0x44,
 		.reg = 0x10,
 		.bit = 0x01,
-	},
+	}, /* BUC5 */
 	{
-		.address = 0x4c,
+		.address = 0x48,
 		.reg = 0x10,
 		.bit = 0x00
-	},
+	}, /* BUC6 */
 };
 
 /* TMP0 - TMP5 are the same, all from GPADC */
--- linux-4.4.0.orig/drivers/acpi/power.c
+++ linux-4.4.0/drivers/acpi/power.c
@@ -131,6 +131,23 @@
 	}
 }
 
+static bool acpi_power_resource_is_dup(union acpi_object *package,
+				       unsigned int start, unsigned int i)
+{
+	acpi_handle rhandle, dup;
+	unsigned int j;
+
+	/* The caller is expected to check the package element types */
+	rhandle = package->package.elements[i].reference.handle;
+	for (j = start; j < i; j++) {
+		dup = package->package.elements[j].reference.handle;
+		if (dup == rhandle)
+			return true;
+	}
+
+	return false;
+}
+
 int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
 				 struct list_head *list)
 {
@@ -150,6 +167,11 @@
 			err = -ENODEV;
 			break;
 		}
+
+		/* Some ACPI tables contain duplicate power resource references */
+		if (acpi_power_resource_is_dup(package, start, i))
+			continue;
+
 		err = acpi_add_power_resource(rhandle);
 		if (err)
 			break;
@@ -200,6 +222,7 @@
 		return -EINVAL;
 
 	/* The state of the list is 'on' IFF all resources are 'on'. */
+	cur_state = 0;
 	list_for_each_entry(entry, list, node) {
 		struct acpi_power_resource *resource = entry->resource;
 		acpi_handle handle = resource->device.handle;
--- linux-4.4.0.orig/drivers/acpi/processor_driver.c
+++ linux-4.4.0/drivers/acpi/processor_driver.c
@@ -259,6 +259,9 @@
 	if (ACPI_SUCCESS(status))
 		return 0;
 
+	result = -ENODEV;
+	acpi_pss_perf_exit(pr, device);
+
 err_power_exit:
 	acpi_processor_power_exit(pr);
 	return result;
@@ -267,11 +270,16 @@
 static int acpi_processor_start(struct device *dev)
 {
 	struct acpi_device *device = ACPI_COMPANION(dev);
+	int ret;
 
 	if (!device)
 		return -ENODEV;
 
-	return __acpi_processor_start(device);
+	/* Protect against concurrent CPU hotplug operations */
+	get_online_cpus();
+	ret = __acpi_processor_start(device);
+	put_online_cpus();
+	return ret;
 }
 
 static int acpi_processor_stop(struct device *dev)
--- linux-4.4.0.orig/drivers/acpi/processor_perflib.c
+++ linux-4.4.0/drivers/acpi/processor_perflib.c
@@ -161,7 +161,7 @@
 {
 	int ret;
 
-	if (ignore_ppc) {
+	if (ignore_ppc || !pr->performance) {
 		/*
 		 * Only when it is notification event, the _OST object
 		 * will be evaluated. Otherwise it is skipped.
--- linux-4.4.0.orig/drivers/acpi/processor_throttling.c
+++ linux-4.4.0/drivers/acpi/processor_throttling.c
@@ -62,8 +62,8 @@
 #define THROTTLING_POSTCHANGE      (2)
 
 static int acpi_processor_get_throttling(struct acpi_processor *pr);
-int acpi_processor_set_throttling(struct acpi_processor *pr,
-						int state, bool force);
+static int __acpi_processor_set_throttling(struct acpi_processor *pr,
+					   int state, bool force, bool direct);
 
 static int acpi_processor_update_tsd_coord(void)
 {
@@ -676,6 +676,15 @@
 	if (!pr->flags.throttling)
 		return -ENODEV;
 
+	/*
+	 * We don't care about error returns - we just try to mark
+	 * these reserved so that nobody else is confused into thinking
+	 * that this region might be unused..
+	 *
+	 * (In particular, allocating the IO range for Cardbus)
+	 */
+	request_region(pr->throttling.address, 6, "ACPI CPU throttle");
+
 	pr->throttling.state = 0;
 
 	duty_mask = pr->throttling.state_count - 1;
@@ -882,7 +891,8 @@
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				"Invalid throttling state, reset\n"));
 			state = 0;
-			ret = acpi_processor_set_throttling(pr, state, true);
+			ret = __acpi_processor_set_throttling(pr, state, true,
+							      true);
 			if (ret)
 				return ret;
 		}
@@ -892,36 +902,31 @@
 	return 0;
 }
 
-static int acpi_processor_get_throttling(struct acpi_processor *pr)
+static long __acpi_processor_get_throttling(void *data)
 {
-	cpumask_var_t saved_mask;
-	int ret;
+	struct acpi_processor *pr = data;
 
+	return pr->throttling.acpi_processor_get_throttling(pr);
+}
+
+static int acpi_processor_get_throttling(struct acpi_processor *pr)
+{
 	if (!pr)
 		return -EINVAL;
 
 	if (!pr->flags.throttling)
 		return -ENODEV;
 
-	if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
-		return -ENOMEM;
-
 	/*
-	 * Migrate task to the cpu pointed by pr.
+	 * This is either called from the CPU hotplug callback of
+	 * processor_driver or via the ACPI probe function. In the latter
+	 * case the CPU is not guaranteed to be online. Both call sites are
+	 * protected against CPU hotplug.
 	 */
-	cpumask_copy(saved_mask, &current->cpus_allowed);
-	/* FIXME: use work_on_cpu() */
-	if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
-		/* Can't migrate to the target pr->id CPU. Exit */
-		free_cpumask_var(saved_mask);
+	if (!cpu_online(pr->id))
 		return -ENODEV;
-	}
-	ret = pr->throttling.acpi_processor_get_throttling(pr);
-	/* restore the previous state */
-	set_cpus_allowed_ptr(current, saved_mask);
-	free_cpumask_var(saved_mask);
 
-	return ret;
+	return work_on_cpu(pr->id, __acpi_processor_get_throttling, pr);
 }
 
 static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
@@ -1071,8 +1076,15 @@
 			arg->target_state, arg->force);
 }
 
-int acpi_processor_set_throttling(struct acpi_processor *pr,
-						int state, bool force)
+static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct)
+{
+	if (direct)
+		return fn(arg);
+	return work_on_cpu(cpu, fn, arg);
+}
+
+static int __acpi_processor_set_throttling(struct acpi_processor *pr,
+					   int state, bool force, bool direct)
 {
 	int ret = 0;
 	unsigned int i;
@@ -1121,7 +1133,8 @@
 		arg.pr = pr;
 		arg.target_state = state;
 		arg.force = force;
-		ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg);
+		ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg,
+				  direct);
 	} else {
 		/*
 		 * When the T-state coordination is SW_ALL or HW_ALL,
@@ -1154,8 +1167,8 @@
 			arg.pr = match_pr;
 			arg.target_state = state;
 			arg.force = force;
-			ret = work_on_cpu(pr->id, acpi_processor_throttling_fn,
-				&arg);
+			ret = call_on_cpu(pr->id, acpi_processor_throttling_fn,
+					  &arg, direct);
 		}
 	}
 	/*
@@ -1173,6 +1186,12 @@
 	return ret;
 }
 
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state,
+				  bool force)
+{
+	return __acpi_processor_set_throttling(pr, state, force, false);
+}
+
 int acpi_processor_get_throttling_info(struct acpi_processor *pr)
 {
 	int result = 0;
--- linux-4.4.0.orig/drivers/acpi/property.c
+++ linux-4.4.0/drivers/acpi/property.c
@@ -346,7 +346,7 @@
  *
  * Return: %0 if property with @name has been found (success),
  *         %-EINVAL if the arguments are invalid,
- *         %-ENODATA if the property doesn't exist,
+ *         %-EINVAL if the property doesn't exist,
  *         %-EPROTO if the property value type doesn't match @type.
  */
 static int acpi_data_get_property(struct acpi_device_data *data,
@@ -360,7 +360,7 @@
 		return -EINVAL;
 
 	if (!data->pointer || !data->properties)
-		return -ENODATA;
+		return -EINVAL;
 
 	properties = data->properties;
 	for (i = 0; i < properties->package.count; i++) {
@@ -375,13 +375,13 @@
 		if (!strcmp(name, propname->string.pointer)) {
 			if (type != ACPI_TYPE_ANY && propvalue->type != type)
 				return -EPROTO;
-			else if (obj)
+			if (obj)
 				*obj = propvalue;
 
 			return 0;
 		}
 	}
-	return -ENODATA;
+	return -EINVAL;
 }
 
 /**
@@ -439,7 +439,7 @@
  *
  * Return: %0 if array property (package) with @name has been found (success),
  *         %-EINVAL if the arguments are invalid,
- *         %-ENODATA if the property doesn't exist,
+ *         %-EINVAL if the property doesn't exist,
  *         %-EPROTO if the property is not a package or the type of its elements
  *           doesn't match @type.
  */
--- linux-4.4.0.orig/drivers/acpi/resource.c
+++ linux-4.4.0/drivers/acpi/resource.c
@@ -26,8 +26,20 @@
 
 #ifdef CONFIG_X86
 #define valid_IRQ(i) (((i) != 0) && ((i) != 2))
+static inline bool acpi_iospace_resource_valid(struct resource *res)
+{
+	/* On X86 IO space is limited to the [0 - 64K] IO port range */
+	return res->end < 0x10003;
+}
 #else
 #define valid_IRQ(i) (true)
+/*
+ * ACPI IO descriptors on arches other than X86 contain MMIO CPU physical
+ * addresses mapping IO space in CPU physical address space, IO space
+ * resources can be placed anywhere in the 64-bit physical address space.
+ */
+static inline bool
+acpi_iospace_resource_valid(struct resource *res) { return true; }
 #endif
 
 static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
@@ -126,7 +138,7 @@
 	if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
-	if (res->end >= 0x10003)
+	if (!acpi_iospace_resource_valid(res))
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
 	if (io_decode == ACPI_DECODE_16)
@@ -494,7 +506,7 @@
 		ret = c->preproc(ares, c->preproc_data);
 		if (ret < 0) {
 			c->error = ret;
-			return AE_CTRL_TERMINATE;
+			return AE_ABORT_METHOD;
 		} else if (ret > 0) {
 			return AE_OK;
 		}
--- linux-4.4.0.orig/drivers/acpi/sbs.c
+++ linux-4.4.0/drivers/acpi/sbs.c
@@ -443,9 +443,13 @@
 
 	/*
 	 * The spec requires that bit 4 always be 1. If it's not set, assume
-	 * that the implementation doesn't support an SBS charger
+	 * that the implementation doesn't support an SBS charger.
+	 *
+	 * And on some MacBooks a status of 0xffff is always returned, no
+	 * matter whether the charger is plugged in or not, which is also
+	 * wrong, so ignore the SBS charger for those too.
 	 */
-	if (!((status >> 4) & 0x1))
+	if (!((status >> 4) & 0x1) || status == 0xffff)
 		return -ENODEV;
 
 	sbs->charger_present = (status >> 15) & 0x1;
--- linux-4.4.0.orig/drivers/acpi/sbshc.c
+++ linux-4.4.0/drivers/acpi/sbshc.c
@@ -196,6 +196,7 @@
 	hc->callback = NULL;
 	hc->context = NULL;
 	mutex_unlock(&hc->lock);
+	acpi_os_wait_events_complete();
 	return 0;
 }
 
@@ -275,8 +276,8 @@
 	device->driver_data = hc;
 
 	acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
-	printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
-		hc->ec, hc->offset, hc->query_bit);
+	dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
+		 hc->offset, hc->query_bit);
 
 	return 0;
 }
@@ -292,6 +293,7 @@
 
 	hc = acpi_driver_data(device);
 	acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
+	acpi_os_wait_events_complete();
 	kfree(hc);
 	device->driver_data = NULL;
 	return 0;
--- linux-4.4.0.orig/drivers/acpi/scan.c
+++ linux-4.4.0/drivers/acpi/scan.c
@@ -564,6 +564,8 @@
 	if (!device)
 		return -EINVAL;
 
+	*device = NULL;
+
 	status = acpi_get_data_full(handle, acpi_scan_drop_device,
 				    (void **)device, callback);
 	if (ACPI_FAILURE(status) || !*device) {
@@ -907,12 +909,9 @@
 
 		if (buffer.length && package
 		    && package->type == ACPI_TYPE_PACKAGE
-		    && package->package.count) {
-			int err = acpi_extract_power_resources(package, 0,
-							       &ps->resources);
-			if (!err)
-				device->power.flags.power_resources = 1;
-		}
+		    && package->package.count)
+			acpi_extract_power_resources(package, 0, &ps->resources);
+
 		ACPI_FREE(buffer.pointer);
 	}
 
@@ -959,14 +958,27 @@
 		acpi_bus_init_power_state(device, i);
 
 	INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources);
-	if (!list_empty(&device->power.states[ACPI_STATE_D3_HOT].resources))
-		device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
 
-	/* Set defaults for D0 and D3hot states (always valid) */
+	/* Set the defaults for D0 and D3hot (always supported). */
 	device->power.states[ACPI_STATE_D0].flags.valid = 1;
 	device->power.states[ACPI_STATE_D0].power = 100;
 	device->power.states[ACPI_STATE_D3_HOT].flags.valid = 1;
 
+	/*
+	 * Use power resources only if the D0 list of them is populated, because
+	 * some platforms may provide _PR3 only to indicate D3cold support and
+	 * in those cases the power resources list returned by it may be bogus.
+	 */
+	if (!list_empty(&device->power.states[ACPI_STATE_D0].resources)) {
+		device->power.flags.power_resources = 1;
+		/*
+		 * D3cold is supported if the D3hot list of power resources is
+		 * not empty.
+		 */
+		if (!list_empty(&device->power.states[ACPI_STATE_D3_HOT].resources))
+			device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
+	}
+
 	if (acpi_bus_init_power(device))
 		device->flags.power_manageable = 0;
 }
@@ -1958,7 +1970,7 @@
 
 static struct acpi_probe_entry *ape;
 static int acpi_probe_count;
-static DEFINE_SPINLOCK(acpi_probe_lock);
+static DEFINE_MUTEX(acpi_probe_mutex);
 
 static int __init acpi_match_madt(struct acpi_subtable_header *header,
 				  const unsigned long end)
@@ -1977,7 +1989,7 @@
 	if (acpi_disabled)
 		return 0;
 
-	spin_lock(&acpi_probe_lock);
+	mutex_lock(&acpi_probe_mutex);
 	for (ape = ap_head; nr; ape++, nr--) {
 		if (ACPI_COMPARE_NAME(ACPI_SIG_MADT, ape->id)) {
 			acpi_probe_count = 0;
@@ -1990,7 +2002,7 @@
 				count++;
 		}
 	}
-	spin_unlock(&acpi_probe_lock);
+	mutex_unlock(&acpi_probe_mutex);
 
 	return count;
 }
--- linux-4.4.0.orig/drivers/acpi/sleep.c
+++ linux-4.4.0/drivers/acpi/sleep.c
@@ -124,6 +124,12 @@
 	nvs_nosave_s3 = true;
 }
 
+static int __init init_nvs_save_s3(const struct dmi_system_id *d)
+{
+	nvs_nosave_s3 = false;
+	return 0;
+}
+
 /*
  * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
  * user to request that behavior by using the 'acpi_old_suspend_ordering'
@@ -318,6 +324,27 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"),
 		},
 	},
+	{
+	.callback = init_nvs_save_s3,
+	.ident = "Asus 1025C",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "1025C"),
+		},
+	},
+	/*
+	 * https://bugzilla.kernel.org/show_bug.cgi?id=189431
+	 * Lenovo G50-45 is a platform later than 2012, but needs nvs memory
+	 * saving during S3.
+	 */
+	{
+	.callback = init_nvs_save_s3,
+	.ident = "Lenovo G50-45",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "80E3"),
+		},
+	},
 	{},
 };
 
@@ -714,6 +741,7 @@
 
 static void acpi_hibernation_leave(void)
 {
+	pm_set_resume_via_firmware();
 	/*
 	 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 	 * enable it here.
--- linux-4.4.0.orig/drivers/acpi/spcr.c
+++ linux-4.4.0/drivers/acpi/spcr.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2012, Intel Corporation
+ * Copyright (c) 2015, Red Hat, Inc.
+ * Copyright (c) 2015, 2016 Linaro 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.
+ *
+ */
+
+#define pr_fmt(fmt) "ACPI: SPCR: " fmt
+
+#include <linux/acpi.h>
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/serial_core.h>
+
+/**
+ * parse_spcr() - parse ACPI SPCR table and add preferred console
+ *
+ * @earlycon: set up earlycon for the console specified by the table
+ *
+ * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be
+ * defined to parse ACPI SPCR table.  As a result of the parsing preferred
+ * console is registered and if @earlycon is true, earlycon is set up.
+ *
+ * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called
+ * from arch inintialization code as soon as the DT/ACPI decision is made.
+ *
+ */
+int __init parse_spcr(bool earlycon)
+{
+	static char opts[64];
+	struct acpi_table_spcr *table;
+	acpi_size table_size;
+	acpi_status status;
+	char *uart;
+	char *iotype;
+	int baud_rate;
+	int err;
+
+	if (acpi_disabled)
+		return -ENODEV;
+
+	status = acpi_get_table_with_size(ACPI_SIG_SPCR, 0,
+					  (struct acpi_table_header **)&table,
+					  &table_size);
+
+	if (ACPI_FAILURE(status))
+		return -ENOENT;
+
+	if (table->header.revision < 2) {
+		err = -ENOENT;
+		pr_err("wrong table version\n");
+		goto done;
+	}
+
+	iotype = table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY ?
+			"mmio" : "io";
+
+	switch (table->interface_type) {
+	case ACPI_DBG2_ARM_SBSA_32BIT:
+		iotype = "mmio32";
+		/* fall through */
+	case ACPI_DBG2_ARM_PL011:
+	case ACPI_DBG2_ARM_SBSA_GENERIC:
+	case ACPI_DBG2_BCM2835:
+		uart = "pl011";
+		break;
+	case ACPI_DBG2_16550_COMPATIBLE:
+	case ACPI_DBG2_16550_SUBSET:
+		uart = "uart";
+		break;
+	default:
+		err = -ENOENT;
+		goto done;
+	}
+
+	switch (table->baud_rate) {
+	case 3:
+		baud_rate = 9600;
+		break;
+	case 4:
+		baud_rate = 19200;
+		break;
+	case 6:
+		baud_rate = 57600;
+		break;
+	case 7:
+		baud_rate = 115200;
+		break;
+	default:
+		err = -ENOENT;
+		goto done;
+	}
+
+	snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype,
+		 table->serial_port.address, baud_rate);
+
+	pr_info("console: %s\n", opts);
+
+	if (earlycon)
+		setup_earlycon(opts);
+
+	err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
+
+done:
+	early_acpi_os_unmap_memory((void __iomem *)table, table_size);
+	return err;
+}
--- linux-4.4.0.orig/drivers/acpi/sysfs.c
+++ linux-4.4.0/drivers/acpi/sysfs.c
@@ -555,23 +555,22 @@
 static int get_status(u32 index, acpi_event_status *status,
 		      acpi_handle *handle)
 {
-	int result = 0;
+	int result;
 
 	if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
-		goto end;
+		return -EINVAL;
 
 	if (index < num_gpes) {
 		result = acpi_get_gpe_device(index, handle);
 		if (result) {
 			ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND,
 					"Invalid GPE 0x%x", index));
-			goto end;
+			return result;
 		}
 		result = acpi_get_gpe_status(*handle, index, status);
 	} else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS))
 		result = acpi_get_event_status(index - num_gpes, status);
 
-end:
 	return result;
 }
 
@@ -777,13 +776,13 @@
 }
 
 static ssize_t
-acpi_show_profile(struct device *dev, struct device_attribute *attr,
+acpi_show_profile(struct kobject *kobj, struct kobj_attribute *attr,
 		  char *buf)
 {
 	return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile);
 }
 
-static const struct device_attribute pm_profile_attr =
+static const struct kobj_attribute pm_profile_attr =
 	__ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
 
 static ssize_t hotplug_enabled_show(struct kobject *kobj,
@@ -832,8 +831,10 @@
 
 	error = kobject_init_and_add(&hotplug->kobj,
 		&acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name);
-	if (error)
+	if (error) {
+		kobject_put(&hotplug->kobj);
 		goto err_out;
+	}
 
 	kobject_uevent(&hotplug->kobj, KOBJ_ADD);
 	return;
--- linux-4.4.0.orig/drivers/acpi/tables.c
+++ linux-4.4.0/drivers/acpi/tables.c
@@ -484,3 +484,13 @@
 }
 
 early_param("acpi_force_table_verification", acpi_force_table_verification_setup);
+
+static int __init acpi_force_32bit_fadt_addr(char *s)
+{
+	pr_info("Forcing 32 Bit FADT addresses\n");
+	acpi_gbl_use32_bit_fadt_addresses = TRUE;
+
+	return 0;
+}
+
+early_param("acpi_force_32bit_fadt_addr", acpi_force_32bit_fadt_addr);
--- linux-4.4.0.orig/drivers/acpi/thermal.c
+++ linux-4.4.0/drivers/acpi/thermal.c
@@ -188,6 +188,8 @@
 	int tz_enabled;
 	int kelvin_offset;
 	struct work_struct thermal_check_work;
+	struct mutex thermal_check_lock;
+	atomic_t thermal_check_count;
 };
 
 /* --------------------------------------------------------------------------
@@ -513,16 +515,6 @@
 	return 0;
 }
 
-static void acpi_thermal_check(void *data)
-{
-	struct acpi_thermal *tz = data;
-
-	if (!tz->tz_enabled)
-		return;
-
-	thermal_zone_device_update(tz->thermal_zone);
-}
-
 /* sys I/F for generic thermal sysfs support */
 
 static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
@@ -556,6 +548,8 @@
 	return 0;
 }
 
+static void acpi_thermal_check_fn(struct work_struct *work);
+
 static int thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
@@ -581,7 +575,7 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			"%s kernel ACPI thermal control\n",
 			tz->tz_enabled ? "Enable" : "Disable"));
-		acpi_thermal_check(tz);
+		acpi_thermal_check_fn(&tz->thermal_check_work);
 	}
 	return 0;
 }
@@ -950,6 +944,12 @@
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
+static void acpi_queue_thermal_check(struct acpi_thermal *tz)
+{
+	if (!work_pending(&tz->thermal_check_work))
+		queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
+}
+
 static void acpi_thermal_notify(struct acpi_device *device, u32 event)
 {
 	struct acpi_thermal *tz = acpi_driver_data(device);
@@ -960,17 +960,17 @@
 
 	switch (event) {
 	case ACPI_THERMAL_NOTIFY_TEMPERATURE:
-		acpi_thermal_check(tz);
+		acpi_queue_thermal_check(tz);
 		break;
 	case ACPI_THERMAL_NOTIFY_THRESHOLDS:
 		acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
-		acpi_thermal_check(tz);
+		acpi_queue_thermal_check(tz);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event, 0);
 		break;
 	case ACPI_THERMAL_NOTIFY_DEVICES:
 		acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
-		acpi_thermal_check(tz);
+		acpi_queue_thermal_check(tz);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event, 0);
 		break;
@@ -1070,7 +1070,27 @@
 {
 	struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
 					       thermal_check_work);
-	acpi_thermal_check(tz);
+
+	if (!tz->tz_enabled)
+		return;
+	/*
+	 * In general, it is not sufficient to check the pending bit, because
+	 * subsequent instances of this function may be queued after one of them
+	 * has started running (e.g. if _TMP sleeps).  Avoid bailing out if just
+	 * one of them is running, though, because it may have done the actual
+	 * check some time ago, so allow at least one of them to block on the
+	 * mutex while another one is running the update.
+	 */
+	if (!atomic_add_unless(&tz->thermal_check_count, -1, 1))
+		return;
+
+	mutex_lock(&tz->thermal_check_lock);
+
+	thermal_zone_device_update(tz->thermal_zone);
+
+	atomic_inc(&tz->thermal_check_count);
+
+	mutex_unlock(&tz->thermal_check_lock);
 }
 
 static int acpi_thermal_add(struct acpi_device *device)
@@ -1102,6 +1122,8 @@
 	if (result)
 		goto free_memory;
 
+	atomic_set(&tz->thermal_check_count, 3);
+	mutex_init(&tz->thermal_check_lock);
 	INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
 
 	pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
@@ -1167,7 +1189,7 @@
 		tz->state.active |= tz->trips.active[i].flags.enabled;
 	}
 
-	queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
+	acpi_queue_thermal_check(tz);
 
 	return AE_OK;
 }
--- linux-4.4.0.orig/drivers/acpi/video_detect.c
+++ linux-4.4.0/drivers/acpi/video_detect.c
@@ -135,14 +135,6 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
 		},
 	},
-	{
-	.callback = video_detect_force_vendor,
-	.ident = "Dell Inspiron 5737",
-	.matches = {
-		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-		DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5737"),
-		},
-	},
 
 	/*
 	 * These models have a working acpi_video backlight control, and using
@@ -214,6 +206,15 @@
 		},
 	},
 	{
+	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */
+	 .callback = video_detect_force_video,
+	 .ident = "SAMSUNG 670Z5E",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"),
+		},
+	},
+	{
 	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
 	 .callback = video_detect_force_video,
 	 .ident = "SAMSUNG 730U3E/740U3E",
@@ -250,6 +251,15 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
 		},
 	},
+	/* https://bugs.launchpad.net/bugs/1894667 */
+	{
+	 .callback = video_detect_force_video,
+	 .ident = "HP 635 Notebook",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "HP 635 Notebook PC"),
+		},
+	},
 
 	/* Non win8 machines which need native backlight nevertheless */
 	{
@@ -279,6 +289,15 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
 		},
 	},
+	{
+	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1123661 */
+	 .callback = video_detect_force_native,
+	 .ident = "Dell XPS 17 L702X",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"),
+		},
+	},
 	{ },
 };
 
--- linux-4.4.0.orig/drivers/amba/bus.c
+++ linux-4.4.0/drivers/amba/bus.c
@@ -68,11 +68,12 @@
 				    struct device_attribute *attr, char *buf)
 {
 	struct amba_device *dev = to_amba_device(_dev);
+	ssize_t len;
 
-	if (!dev->driver_override)
-		return 0;
-
-	return sprintf(buf, "%s\n", dev->driver_override);
+	device_lock(_dev);
+	len = sprintf(buf, "%s\n", dev->driver_override);
+	device_unlock(_dev);
+	return len;
 }
 
 static ssize_t driver_override_store(struct device *_dev,
@@ -80,9 +81,10 @@
 				     const char *buf, size_t count)
 {
 	struct amba_device *dev = to_amba_device(_dev);
-	char *driver_override, *old = dev->driver_override, *cp;
+	char *driver_override, *old, *cp;
 
-	if (count > PATH_MAX)
+	/* We need to keep extra room for a newline */
+	if (count >= (PAGE_SIZE - 1))
 		return -EINVAL;
 
 	driver_override = kstrndup(buf, count, GFP_KERNEL);
@@ -93,12 +95,15 @@
 	if (cp)
 		*cp = '\0';
 
+	device_lock(_dev);
+	old = dev->driver_override;
 	if (strlen(driver_override)) {
 		dev->driver_override = driver_override;
 	} else {
 	       kfree(driver_override);
 	       dev->driver_override = NULL;
 	}
+	device_unlock(_dev);
 
 	kfree(old);
 
@@ -270,10 +275,11 @@
 {
 	struct amba_device *pcdev = to_amba_device(dev);
 	struct amba_driver *drv = to_amba_driver(dev->driver);
-	int ret;
+	int ret = 0;
 
 	pm_runtime_get_sync(dev);
-	ret = drv->remove(pcdev);
+	if (drv->remove)
+		ret = drv->remove(pcdev);
 	pm_runtime_put_noidle(dev);
 
 	/* Undo the runtime PM settings in amba_probe() */
@@ -290,7 +296,9 @@
 static void amba_shutdown(struct device *dev)
 {
 	struct amba_driver *drv = to_amba_driver(dev->driver);
-	drv->shutdown(to_amba_device(dev));
+
+	if (drv->shutdown)
+		drv->shutdown(to_amba_device(dev));
 }
 
 /**
@@ -303,12 +311,13 @@
  */
 int amba_driver_register(struct amba_driver *drv)
 {
-	drv->drv.bus = &amba_bustype;
+	if (!drv->probe)
+		return -EINVAL;
 
-#define SETFN(fn)	if (drv->fn) drv->drv.fn = amba_##fn
-	SETFN(probe);
-	SETFN(remove);
-	SETFN(shutdown);
+	drv->drv.bus = &amba_bustype;
+	drv->drv.probe = amba_probe;
+	drv->drv.remove = amba_remove;
+	drv->drv.shutdown = amba_shutdown;
 
 	return driver_register(&drv->drv);
 }
--- linux-4.4.0.orig/drivers/android/binder.c
+++ linux-4.4.0/drivers/android/binder.c
@@ -334,7 +334,8 @@
 	BINDER_LOOPER_STATE_EXITED      = 0x04,
 	BINDER_LOOPER_STATE_INVALID     = 0x08,
 	BINDER_LOOPER_STATE_WAITING     = 0x10,
-	BINDER_LOOPER_STATE_NEED_RETURN = 0x20
+	BINDER_LOOPER_STATE_NEED_RETURN = 0x20,
+	BINDER_LOOPER_STATE_POLL	= 0x40,
 };
 
 struct binder_thread {
@@ -477,7 +478,7 @@
 	new_buffer_size = binder_buffer_size(proc, new_buffer);
 
 	binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-		     "%d: add free buffer, size %zd, at %p\n",
+		     "%d: add free buffer, size %zd, at %pK\n",
 		      proc->pid, new_buffer_size, new_buffer);
 
 	while (*p) {
@@ -555,7 +556,7 @@
 	struct mm_struct *mm;
 
 	binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-		     "%d: %s pages %p-%p\n", proc->pid,
+		     "%d: %s pages %pK-%pK\n", proc->pid,
 		     allocate ? "allocate" : "free", start, end);
 
 	if (end <= start)
@@ -570,6 +571,12 @@
 
 	if (mm) {
 		down_write(&mm->mmap_sem);
+		if (!mmget_still_valid(mm)) {
+			if (allocate == 0)
+				goto free_range;
+			goto err_no_vma;
+		}
+
 		vma = proc->vma;
 		if (vma && mm != proc->vma_vm_mm) {
 			pr_err("%d: vma mm and task mm mismatch\n",
@@ -595,7 +602,7 @@
 		BUG_ON(*page);
 		*page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
 		if (*page == NULL) {
-			pr_err("%d: binder_alloc_buf failed for page at %p\n",
+			pr_err("%d: binder_alloc_buf failed for page at %pK\n",
 				proc->pid, page_addr);
 			goto err_alloc_page_failed;
 		}
@@ -604,7 +611,7 @@
 		flush_cache_vmap((unsigned long)page_addr,
 				(unsigned long)page_addr + PAGE_SIZE);
 		if (ret != 1) {
-			pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n",
+			pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n",
 			       proc->pid, page_addr);
 			goto err_map_kernel_failed;
 		}
@@ -708,7 +715,7 @@
 	}
 
 	binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-		     "%d: binder_alloc_buf size %zd got buffer %p size %zd\n",
+		     "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n",
 		      proc->pid, size, buffer, buffer_size);
 
 	has_page_addr =
@@ -738,7 +745,7 @@
 		binder_insert_free_buffer(proc, new_buffer);
 	}
 	binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-		     "%d: binder_alloc_buf size %zd got %p\n",
+		     "%d: binder_alloc_buf size %zd got %pK\n",
 		      proc->pid, size, buffer);
 	buffer->data_size = data_size;
 	buffer->offsets_size = offsets_size;
@@ -778,7 +785,7 @@
 		if (buffer_end_page(prev) == buffer_end_page(buffer))
 			free_page_end = 0;
 		binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-			     "%d: merge free, buffer %p share page with %p\n",
+			     "%d: merge free, buffer %pK share page with %pK\n",
 			      proc->pid, buffer, prev);
 	}
 
@@ -791,14 +798,14 @@
 			    buffer_start_page(buffer))
 				free_page_start = 0;
 			binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-				     "%d: merge free, buffer %p share page with %p\n",
+				     "%d: merge free, buffer %pK share page with %pK\n",
 				      proc->pid, buffer, prev);
 		}
 	}
 	list_del(&buffer->entry);
 	if (free_page_start || free_page_end) {
 		binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-			     "%d: merge free, buffer %p do not share page%s%s with %p or %p\n",
+			     "%d: merge free, buffer %pK do not share page%s%s with %pK or %pK\n",
 			     proc->pid, buffer, free_page_start ? "" : " end",
 			     free_page_end ? "" : " start", prev, next);
 		binder_update_page_range(proc, 0, free_page_start ?
@@ -819,7 +826,7 @@
 		ALIGN(buffer->offsets_size, sizeof(void *));
 
 	binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-		     "%d: binder_free_buf %p size %zd buffer_size %zd\n",
+		     "%d: binder_free_buf %pK size %zd buffer_size %zd\n",
 		      proc->pid, buffer, size, buffer_size);
 
 	BUG_ON(buffer->free);
@@ -1003,7 +1010,7 @@
 
 
 static struct binder_ref *binder_get_ref(struct binder_proc *proc,
-					 uint32_t desc)
+					 u32 desc, bool need_strong_ref)
 {
 	struct rb_node *n = proc->refs_by_desc.rb_node;
 	struct binder_ref *ref;
@@ -1011,12 +1018,16 @@
 	while (n) {
 		ref = rb_entry(n, struct binder_ref, rb_node_desc);
 
-		if (desc < ref->desc)
+		if (desc < ref->desc) {
 			n = n->rb_left;
-		else if (desc > ref->desc)
+		} else if (desc > ref->desc) {
 			n = n->rb_right;
-		else
+		} else if (need_strong_ref && !ref->strong) {
+			binder_user_error("tried to use weak ref as strong ref\n");
+			return NULL;
+		} else {
 			return ref;
+		}
 	}
 	return NULL;
 }
@@ -1245,7 +1256,7 @@
 	int debug_id = buffer->debug_id;
 
 	binder_debug(BINDER_DEBUG_TRANSACTION,
-		     "%d buffer release %d, size %zd-%zd, failed at %p\n",
+		     "%d buffer release %d, size %zd-%zd, failed at %pK\n",
 		     proc->pid, buffer->debug_id,
 		     buffer->data_size, buffer->offsets_size, failed_at);
 
@@ -1286,7 +1297,10 @@
 		} break;
 		case BINDER_TYPE_HANDLE:
 		case BINDER_TYPE_WEAK_HANDLE: {
-			struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+			struct binder_ref *ref;
+
+			ref = binder_get_ref(proc, fp->handle,
+					     fp->type == BINDER_TYPE_HANDLE);
 
 			if (ref == NULL) {
 				pr_err("transaction release %d bad handle %d\n",
@@ -1380,7 +1394,7 @@
 		if (tr->target.handle) {
 			struct binder_ref *ref;
 
-			ref = binder_get_ref(proc, tr->target.handle);
+			ref = binder_get_ref(proc, tr->target.handle, true);
 			if (ref == NULL) {
 				binder_user_error("%d:%d got transaction to invalid handle\n",
 					proc->pid, thread->pid);
@@ -1401,6 +1415,10 @@
 			return_error = BR_DEAD_REPLY;
 			goto err_dead_binder;
 		}
+		if (WARN_ON(proc == target_proc)) {
+			return_error = BR_FAILED_REPLY;
+			goto err_invalid_target_handle;
+		}
 		if (security_binder_transaction(proc->tsk,
 						target_proc->tsk) < 0) {
 			return_error = BR_FAILED_REPLY;
@@ -1571,7 +1589,9 @@
 				fp->type = BINDER_TYPE_HANDLE;
 			else
 				fp->type = BINDER_TYPE_WEAK_HANDLE;
+			fp->binder = 0;
 			fp->handle = ref->desc;
+			fp->cookie = 0;
 			binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
 				       &thread->todo);
 
@@ -1583,7 +1603,10 @@
 		} break;
 		case BINDER_TYPE_HANDLE:
 		case BINDER_TYPE_WEAK_HANDLE: {
-			struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+			struct binder_ref *ref;
+
+			ref = binder_get_ref(proc, fp->handle,
+					     fp->type == BINDER_TYPE_HANDLE);
 
 			if (ref == NULL) {
 				binder_user_error("%d:%d got transaction with invalid handle, %d\n",
@@ -1618,7 +1641,9 @@
 					return_error = BR_FAILED_REPLY;
 					goto err_binder_get_ref_for_node_failed;
 				}
+				fp->binder = 0;
 				fp->handle = new_ref->desc;
+				fp->cookie = 0;
 				binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
 				trace_binder_transaction_ref_to_ref(t, ref,
 								    new_ref);
@@ -1672,6 +1697,7 @@
 			binder_debug(BINDER_DEBUG_TRANSACTION,
 				     "        fd %d -> %d\n", fp->handle, target_fd);
 			/* TODO: fput? */
+			fp->binder = 0;
 			fp->handle = target_fd;
 		} break;
 
@@ -1703,8 +1729,12 @@
 	list_add_tail(&t->work.entry, target_list);
 	tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
 	list_add_tail(&tcomplete->entry, &thread->todo);
-	if (target_wait)
-		wake_up_interruptible(target_wait);
+	if (target_wait) {
+		if (reply || !(t->flags & TF_ONE_WAY))
+			wake_up_interruptible_sync(target_wait);
+		else
+			wake_up_interruptible(target_wait);
+	}
 	return;
 
 err_get_unused_fd_failed:
@@ -1786,6 +1816,11 @@
 			ptr += sizeof(uint32_t);
 			if (target == 0 && binder_context_mgr_node &&
 			    (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
+				if (binder_context_mgr_node->proc == proc) {
+					binder_user_error("%d:%d context manager tried to acquire desc 0\n",
+							  proc->pid, thread->pid);
+					return -EINVAL;
+				}
 				ref = binder_get_ref_for_node(proc,
 					       binder_context_mgr_node);
 				if (ref->desc != target) {
@@ -1794,7 +1829,9 @@
 						ref->desc);
 				}
 			} else
-				ref = binder_get_ref(proc, target);
+				ref = binder_get_ref(proc, target,
+						     cmd == BC_ACQUIRE ||
+						     cmd == BC_RELEASE);
 			if (ref == NULL) {
 				binder_user_error("%d:%d refcount change on invalid ref %d\n",
 					proc->pid, thread->pid, target);
@@ -1990,7 +2027,7 @@
 			if (get_user(cookie, (binder_uintptr_t __user *)ptr))
 				return -EFAULT;
 			ptr += sizeof(binder_uintptr_t);
-			ref = binder_get_ref(proc, target);
+			ref = binder_get_ref(proc, target, false);
 			if (ref == NULL) {
 				binder_user_error("%d:%d %s invalid ref %d\n",
 					proc->pid, thread->pid,
@@ -2074,7 +2111,7 @@
 			if (get_user(cookie, (binder_uintptr_t __user *)ptr))
 				return -EFAULT;
 
-			ptr += sizeof(void *);
+			ptr += sizeof(cookie);
 			list_for_each_entry(w, &proc->delivered_death, entry) {
 				struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
 
@@ -2084,7 +2121,7 @@
 				}
 			}
 			binder_debug(BINDER_DEBUG_DEAD_BINDER,
-				     "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
+				     "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n",
 				     proc->pid, thread->pid, (u64)cookie,
 				     death);
 			if (death == NULL) {
@@ -2583,6 +2620,27 @@
 		} else
 			BUG();
 	}
+
+	/*
+	 * If this thread used poll, make sure we remove the waitqueue
+	 * from any epoll data structures holding it with POLLFREE.
+	 * waitqueue_active() is safe to use here because we're holding
+	 * the global lock.
+	 */
+	if ((thread->looper & BINDER_LOOPER_STATE_POLL) &&
+	    waitqueue_active(&thread->wait)) {
+		wake_up_poll(&thread->wait, POLLHUP | POLLFREE);
+	}
+
+	/*
+	 * This is needed to avoid races between wake_up_poll() above and
+	 * and ep_remove_waitqueue() called for other reasons (eg the epoll file
+	 * descriptor being closed); ep_remove_waitqueue() holds an RCU read
+	 * lock, so we can be sure it's done after calling synchronize_rcu().
+	 */
+	if (thread->looper & BINDER_LOOPER_STATE_POLL)
+		synchronize_rcu();
+
 	if (send_reply)
 		binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
 	binder_release_work(&thread->todo);
@@ -2601,6 +2659,12 @@
 	binder_lock(__func__);
 
 	thread = binder_get_thread(proc);
+	if (!thread) {
+		binder_unlock(__func__);
+		return POLLERR;
+	}
+
+	thread->looper |= BINDER_LOOPER_STATE_POLL;
 
 	wait_for_proc_work = thread->transaction_stack == NULL &&
 		list_empty(&thread->todo) && thread->return_error == BR_OK;
@@ -2848,7 +2912,7 @@
 	const char *failure_string;
 	struct binder_buffer *buffer;
 
-	if (proc->tsk != current)
+	if (proc->tsk != current->group_leader)
 		return -EINVAL;
 
 	if ((vma->vm_end - vma->vm_start) > SZ_4M)
@@ -2887,7 +2951,7 @@
 #ifdef CONFIG_CPU_CACHE_VIPT
 	if (cache_is_vipt_aliasing()) {
 		while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) {
-			pr_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 %pK bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
 			vma->vm_start += PAGE_SIZE;
 		}
 	}
@@ -2949,8 +3013,8 @@
 	proc = kzalloc(sizeof(*proc), GFP_KERNEL);
 	if (proc == NULL)
 		return -ENOMEM;
-	get_task_struct(current);
-	proc->tsk = current;
+	get_task_struct(current->group_leader);
+	proc->tsk = current->group_leader;
 	INIT_LIST_HEAD(&proc->todo);
 	init_waitqueue_head(&proc->wait);
 	proc->default_priority = task_nice(current);
@@ -3145,7 +3209,7 @@
 
 			page_addr = proc->buffer + i * PAGE_SIZE;
 			binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
-				     "%s: %d: page %d at %p not freed\n",
+				     "%s: %d: page %d at %pK not freed\n",
 				     __func__, proc->pid, i, page_addr);
 			unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
 			__free_page(proc->pages[i]);
@@ -3224,7 +3288,7 @@
 				     struct binder_transaction *t)
 {
 	seq_printf(m,
-		   "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
+		   "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d",
 		   prefix, t->debug_id, t,
 		   t->from ? t->from->proc->pid : 0,
 		   t->from ? t->from->pid : 0,
@@ -3238,7 +3302,7 @@
 	if (t->buffer->target_node)
 		seq_printf(m, " node %d",
 			   t->buffer->target_node->debug_id);
-	seq_printf(m, " size %zd:%zd data %p\n",
+	seq_printf(m, " size %zd:%zd data %pK\n",
 		   t->buffer->data_size, t->buffer->offsets_size,
 		   t->buffer->data);
 }
@@ -3246,7 +3310,7 @@
 static void print_binder_buffer(struct seq_file *m, const char *prefix,
 				struct binder_buffer *buffer)
 {
-	seq_printf(m, "%s %d: %p size %zd:%zd %s\n",
+	seq_printf(m, "%s %d: %pK size %zd:%zd %s\n",
 		   prefix, buffer->debug_id, buffer->data,
 		   buffer->data_size, buffer->offsets_size,
 		   buffer->transaction ? "active" : "delivered");
@@ -3349,7 +3413,7 @@
 
 static void print_binder_ref(struct seq_file *m, struct binder_ref *ref)
 {
-	seq_printf(m, "  ref %d: desc %d %snode %d s %d w %d d %p\n",
+	seq_printf(m, "  ref %d: desc %d %snode %d s %d w %d d %pK\n",
 		   ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ",
 		   ref->node->debug_id, ref->strong, ref->weak, ref->death);
 }
--- linux-4.4.0.orig/drivers/ata/Kconfig
+++ linux-4.4.0/drivers/ata/Kconfig
@@ -272,6 +272,7 @@
 
 config ATA_BMDMA
 	bool "ATA BMDMA support"
+	depends on HAS_DMA
 	default y
 	help
 	  This option adds support for SFF ATA controllers with BMDMA
@@ -318,6 +319,7 @@
 
 config SATA_HIGHBANK
 	tristate "Calxeda Highbank SATA support"
+	depends on HAS_DMA
 	depends on ARCH_HIGHBANK || COMPILE_TEST
 	help
 	  This option enables support for the Calxeda Highbank SoC's
@@ -327,6 +329,7 @@
 
 config SATA_MV
 	tristate "Marvell SATA support"
+	depends on HAS_DMA
 	depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \
 		   ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
 	select GENERIC_PHY
--- linux-4.4.0.orig/drivers/ata/acard-ahci.c
+++ linux-4.4.0/drivers/ata/acard-ahci.c
@@ -72,7 +72,7 @@
 	__le32			size;	 /* bit 31 (EOT) max==0x10000 (64k) */
 };
 
-static void acard_ahci_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc);
 static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
 static int acard_ahci_port_start(struct ata_port *ap);
 static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -257,7 +257,7 @@
 	return si;
 }
 
-static void acard_ahci_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct ahci_port_priv *pp = ap->private_data;
@@ -295,6 +295,8 @@
 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
 	ahci_fill_cmd_slot(pp, qc->tag, opts);
+
+	return AC_ERR_OK;
 }
 
 static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
--- linux-4.4.0.orig/drivers/ata/ahci.c
+++ linux-4.4.0/drivers/ata/ahci.c
@@ -260,14 +260,34 @@
 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
-	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
+	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
-	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH M RAID */
 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
+	{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
 	{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
-	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
-	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
+	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT M RAID */
 	{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
 	{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
 	{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
@@ -276,20 +296,20 @@
 	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
 	{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
 	{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
-	{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
+	{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
-	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point M RAID */
 	{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
-	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
+	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point M RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point M RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point M RAID */
 	{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
 	{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
 	{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
@@ -330,32 +350,43 @@
 	{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
 	{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
-	{ PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
+	{ PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series M RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series M RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series M RAID */
 	{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
 	{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
 	{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
 	{ PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
-	{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
+	{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H M AHCI */
 	{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
 	{ PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
-	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
+	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H M RAID */
 	{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
+	{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
 	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
+	{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
 	{ PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
+	{ PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/
+	{ PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
 	{ PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
+	{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
+	{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
+	{ PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
+	{ PCI_VDEVICE(INTEL, 0x0f22), board_ahci }, /* Bay Trail AHCI */
+	{ PCI_VDEVICE(INTEL, 0x0f23), board_ahci }, /* Bay Trail AHCI */
+	{ PCI_VDEVICE(INTEL, 0x22a3), board_ahci }, /* Cherry Trail AHCI */
+	{ PCI_VDEVICE(INTEL, 0x5ae3), board_ahci }, /* Apollo Lake AHCI */
 
 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -507,7 +538,9 @@
 	  .driver_data = board_ahci_yes_fbs },
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
 	  .driver_data = board_ahci_yes_fbs },
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642),
+	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), /* highpoint rocketraid 642L */
+	  .driver_data = board_ahci_yes_fbs },
+	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */
 	  .driver_data = board_ahci_yes_fbs },
 
 	/* Promise */
@@ -586,8 +619,11 @@
 static int ahci_pci_reset_controller(struct ata_host *host)
 {
 	struct pci_dev *pdev = to_pci_dev(host->dev);
+	int rc;
 
-	ahci_reset_controller(host);
+	rc = ahci_reset_controller(host);
+	if (rc)
+		return rc;
 
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
 		struct ahci_host_priv *hpriv = host->private_data;
@@ -1196,6 +1232,59 @@
 	return strcmp(buf, dmi->driver_data) < 0;
 }
 
+static bool ahci_broken_lpm(struct pci_dev *pdev)
+{
+	static const struct dmi_system_id sysids[] = {
+		/* Various Lenovo 50 series have LPM issues with older BIOSen */
+		{
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X250"),
+			},
+			.driver_data = "20180406", /* 1.31 */
+		},
+		{
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L450"),
+			},
+			.driver_data = "20180420", /* 1.28 */
+		},
+		{
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T450s"),
+			},
+			.driver_data = "20180315", /* 1.33 */
+		},
+		{
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+				DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W541"),
+			},
+			/*
+			 * Note date based on release notes, 2.35 has been
+			 * reported to be good, but I've been unable to get
+			 * a hold of the reporter to get the DMI BIOS date.
+			 * TODO: fix this.
+			 */
+			.driver_data = "20180310", /* 2.35 */
+		},
+		{ }	/* terminate list */
+	};
+	const struct dmi_system_id *dmi = dmi_first_match(sysids);
+	int year, month, date;
+	char buf[9];
+
+	if (!dmi)
+		return false;
+
+	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+
+	return strcmp(buf, dmi->driver_data) < 0;
+}
+
 static bool ahci_broken_online(struct pci_dev *pdev)
 {
 #define ENCODE_BUSDEVFN(bus, slot, func)			\
@@ -1305,6 +1394,44 @@
 {}
 #endif
 
+#ifdef CONFIG_ARM64
+/*
+ * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
+ * Workaround is to make sure all pending IRQs are served before leaving
+ * handler.
+ */
+static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
+{
+	struct ata_host *host = dev_instance;
+	struct ahci_host_priv *hpriv;
+	unsigned int rc = 0;
+	void __iomem *mmio;
+	u32 irq_stat, irq_masked;
+	unsigned int handled = 1;
+
+	VPRINTK("ENTER\n");
+	hpriv = host->private_data;
+	mmio = hpriv->mmio;
+	irq_stat = readl(mmio + HOST_IRQ_STAT);
+	if (!irq_stat)
+		return IRQ_NONE;
+
+	do {
+		irq_masked = irq_stat & hpriv->port_map;
+		spin_lock(&host->lock);
+		rc = ahci_handle_port_intr(host, irq_masked);
+		if (!rc)
+			handled = 0;
+		writel(irq_stat, mmio + HOST_IRQ_STAT);
+		irq_stat = readl(mmio + HOST_IRQ_STAT);
+		spin_unlock(&host->lock);
+	} while (irq_stat);
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(handled);
+}
+#endif
+
 /*
  * ahci_init_msix() only implements single MSI-X support, not multiple
  * MSI-X per-port interrupts. This is needed for host controllers that only
@@ -1520,6 +1647,11 @@
 	if (ahci_broken_devslp(pdev))
 		hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
 
+#ifdef CONFIG_ARM64
+	if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
+		hpriv->irq_handler = ahci_thunderx_irq_handler;
+#endif
+
 	/* save initial config */
 	ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1555,6 +1687,12 @@
 			"quirky BIOS, skipping spindown on poweroff\n");
 	}
 
+	if (ahci_broken_lpm(pdev)) {
+		pi.flags |= ATA_FLAG_NO_LPM;
+		dev_warn(&pdev->dev,
+			 "BIOS update required for Link Power Management support\n");
+	}
+
 	if (ahci_broken_suspend(pdev)) {
 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
 		dev_warn(&pdev->dev,
--- linux-4.4.0.orig/drivers/ata/ahci.h
+++ linux-4.4.0/drivers/ata/ahci.h
@@ -240,8 +240,6 @@
 	AHCI_HFLAG_MULTI_MSI		= (1 << 16), /* multiple PCI MSIs */
 	AHCI_HFLAG_NO_DEVSLP		= (1 << 17), /* no device sleep */
 	AHCI_HFLAG_NO_FBS		= (1 << 18), /* no FBS */
-	AHCI_HFLAG_EDGE_IRQ		= (1 << 19), /* HOST_IRQ_STAT behaves as
-							Edge Triggered */
 
 	/* ap->flags bits */
 
@@ -352,6 +350,7 @@
 	 * be overridden anytime before the host is activated.
 	 */
 	void			(*start_engine)(struct ata_port *ap);
+	irqreturn_t 		(*irq_handler)(int irq, void *dev_instance);
 };
 
 extern int ahci_ignore_sss;
@@ -400,6 +399,7 @@
 void ahci_print_info(struct ata_host *host, const char *scc_s);
 int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht);
 void ahci_error_handler(struct ata_port *ap);
+u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked);
 
 static inline void __iomem *__ahci_port_base(struct ata_host *host,
 					     unsigned int port_no)
--- linux-4.4.0.orig/drivers/ata/ahci_platform.c
+++ linux-4.4.0/drivers/ata/ahci_platform.c
@@ -51,6 +51,9 @@
 	if (rc)
 		return rc;
 
+	of_property_read_u32(dev->of_node,
+			     "ports-implemented", &hpriv->force_port_map);
+
 	if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
 		hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
 
--- linux-4.4.0.orig/drivers/ata/ahci_xgene.c
+++ linux-4.4.0/drivers/ata/ahci_xgene.c
@@ -548,6 +548,88 @@
 	return rc;
 }
 
+/**
+ * xgene_ahci_handle_broken_edge_irq - Handle the broken irq.
+ * @ata_host: Host that recieved the irq
+ * @irq_masked: HOST_IRQ_STAT value
+ *
+ * For hardware with broken edge trigger latch
+ * the HOST_IRQ_STAT register misses the edge interrupt
+ * when clearing of HOST_IRQ_STAT register and hardware
+ * reporting the PORT_IRQ_STAT register at the
+ * same clock cycle.
+ * As such, the algorithm below outlines the workaround.
+ *
+ * 1. Read HOST_IRQ_STAT register and save the state.
+ * 2. Clear the HOST_IRQ_STAT register.
+ * 3. Read back the HOST_IRQ_STAT register.
+ * 4. If HOST_IRQ_STAT register equals to zero, then
+ *    traverse the rest of port's PORT_IRQ_STAT register
+ *    to check if an interrupt is triggered at that point else
+ *    go to step 6.
+ * 5. If PORT_IRQ_STAT register of rest ports is not equal to zero
+ *    then update the state of HOST_IRQ_STAT saved in step 1.
+ * 6. Handle port interrupts.
+ * 7. Exit
+ */
+static int xgene_ahci_handle_broken_edge_irq(struct ata_host *host,
+					     u32 irq_masked)
+{
+	struct ahci_host_priv *hpriv = host->private_data;
+	void __iomem *port_mmio;
+	int i;
+
+	if (!readl(hpriv->mmio + HOST_IRQ_STAT)) {
+		for (i = 0; i < host->n_ports; i++) {
+			if (irq_masked & (1 << i))
+				continue;
+
+			port_mmio = ahci_port_base(host->ports[i]);
+			if (readl(port_mmio + PORT_IRQ_STAT))
+				irq_masked |= (1 << i);
+		}
+	}
+
+	return ahci_handle_port_intr(host, irq_masked);
+}
+
+static irqreturn_t xgene_ahci_irq_intr(int irq, void *dev_instance)
+{
+	struct ata_host *host = dev_instance;
+	struct ahci_host_priv *hpriv;
+	unsigned int rc = 0;
+	void __iomem *mmio;
+	u32 irq_stat, irq_masked;
+
+	VPRINTK("ENTER\n");
+
+	hpriv = host->private_data;
+	mmio = hpriv->mmio;
+
+	/* sigh.  0xffffffff is a valid return from h/w */
+	irq_stat = readl(mmio + HOST_IRQ_STAT);
+	if (!irq_stat)
+		return IRQ_NONE;
+
+	irq_masked = irq_stat & hpriv->port_map;
+
+	spin_lock(&host->lock);
+
+	/*
+	 * HOST_IRQ_STAT behaves as edge triggered latch meaning that
+	 * it should be cleared before all the port events are cleared.
+	 */
+	writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+	rc = xgene_ahci_handle_broken_edge_irq(host, irq_masked);
+
+	spin_unlock(&host->lock);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(rc);
+}
+
 static struct ata_port_operations xgene_ahci_v1_ops = {
 	.inherits = &ahci_ops,
 	.host_stop = xgene_ahci_host_stop,
@@ -739,9 +821,9 @@
 				dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n",
 					__func__);
 				version = XGENE_AHCI_V1;
-			}
-			if (info->valid & ACPI_VALID_CID)
+			} else if (info->valid & ACPI_VALID_CID) {
 				version = XGENE_AHCI_V2;
+			}
 		}
 	}
 #endif
@@ -779,7 +861,8 @@
 		hpriv->flags = AHCI_HFLAG_NO_NCQ;
 		break;
 	case XGENE_AHCI_V2:
-		hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ;
+		hpriv->flags |= AHCI_HFLAG_YES_FBS;
+		hpriv->irq_handler = xgene_ahci_irq_intr;
 		break;
 	default:
 		break;
--- linux-4.4.0.orig/drivers/ata/libahci.c
+++ linux-4.4.0/drivers/ata/libahci.c
@@ -35,6 +35,7 @@
 #include <linux/kernel.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
+#include <linux/nospec.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -71,7 +72,7 @@
 static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
-static void ahci_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors ahci_qc_prep(struct ata_queued_cmd *qc);
 static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);
 static void ahci_freeze(struct ata_port *ap);
 static void ahci_thaw(struct ata_port *ap);
@@ -112,6 +113,7 @@
 				    const char *buf, size_t size);
 static ssize_t ahci_show_em_supported(struct device *dev,
 				      struct device_attribute *attr, char *buf);
+static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance);
 
 static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
 static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
@@ -187,7 +189,6 @@
 EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops);
 
 static bool ahci_em_messages __read_mostly = true;
-EXPORT_SYMBOL_GPL(ahci_em_messages);
 module_param(ahci_em_messages, bool, 0444);
 /* add other LED protocol types when they become supported */
 MODULE_PARM_DESC(ahci_em_messages,
@@ -467,6 +468,7 @@
 		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
 			 port_map, hpriv->force_port_map);
 		port_map = hpriv->force_port_map;
+		hpriv->saved_port_map = port_map;
 	}
 
 	if (hpriv->mask_port_map) {
@@ -495,8 +497,8 @@
 		}
 	}
 
-	/* fabricate port_map from cap.nr_ports */
-	if (!port_map) {
+	/* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
+	if (!port_map && vers < 0x10300) {
 		port_map = (1 << ahci_nr_ports(cap)) - 1;
 		dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
 
@@ -511,6 +513,9 @@
 
 	if (!hpriv->start_engine)
 		hpriv->start_engine = ahci_start_engine;
+
+	if (!hpriv->irq_handler)
+		hpriv->irq_handler = ahci_single_level_irq_intr;
 }
 EXPORT_SYMBOL_GPL(ahci_save_initial_config);
 
@@ -1054,10 +1059,12 @@
 
 	/* get the slot number from the message */
 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
-	if (pmp < EM_MAX_SLOTS)
+	if (pmp < EM_MAX_SLOTS) {
+		pmp = array_index_nospec(pmp, EM_MAX_SLOTS);
 		emp = &pp->em_priv[pmp];
-	else
+	} else {
 		return -EINVAL;
+	}
 
 	/* mask off the activity bits if we are in sw_activity
 	 * mode, user should turn off sw_activity before setting
@@ -1142,8 +1149,7 @@
 
 	/* mark esata ports */
 	tmp = readl(port_mmio + PORT_CMD);
-	if ((tmp & PORT_CMD_HPCP) ||
-	    ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)))
+	if ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS))
 		ap->pflags |= ATA_PFLAG_EXTERNAL;
 }
 
@@ -1536,7 +1542,7 @@
 		return sata_pmp_qc_defer_cmd_switch(qc);
 }
 
-static void ahci_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors ahci_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct ahci_port_priv *pp = ap->private_data;
@@ -1572,6 +1578,8 @@
 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
 	ahci_fill_cmd_slot(pp, qc->tag, opts);
+
+	return AC_ERR_OK;
 }
 
 static void ahci_fbs_dec_intr(struct ata_port *ap)
@@ -1841,7 +1849,7 @@
 	return IRQ_WAKE_THREAD;
 }
 
-static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
+u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
 {
 	unsigned int i, handled = 0;
 
@@ -1867,43 +1875,7 @@
 
 	return handled;
 }
-
-static irqreturn_t ahci_single_edge_irq_intr(int irq, void *dev_instance)
-{
-	struct ata_host *host = dev_instance;
-	struct ahci_host_priv *hpriv;
-	unsigned int rc = 0;
-	void __iomem *mmio;
-	u32 irq_stat, irq_masked;
-
-	VPRINTK("ENTER\n");
-
-	hpriv = host->private_data;
-	mmio = hpriv->mmio;
-
-	/* sigh.  0xffffffff is a valid return from h/w */
-	irq_stat = readl(mmio + HOST_IRQ_STAT);
-	if (!irq_stat)
-		return IRQ_NONE;
-
-	irq_masked = irq_stat & hpriv->port_map;
-
-	spin_lock(&host->lock);
-
-	/*
-	 * HOST_IRQ_STAT behaves as edge triggered latch meaning that
-	 * it should be cleared before all the port events are cleared.
-	 */
-	writel(irq_stat, mmio + HOST_IRQ_STAT);
-
-	rc = ahci_handle_port_intr(host, irq_masked);
-
-	spin_unlock(&host->lock);
-
-	VPRINTK("EXIT\n");
-
-	return IRQ_RETVAL(rc);
-}
+EXPORT_SYMBOL_GPL(ahci_handle_port_intr);
 
 static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
 {
@@ -2113,6 +2085,8 @@
 		deto = 20;
 	}
 
+	/* Make dito, mdat, deto bits to 0s */
+	devslp &= ~GENMASK_ULL(24, 2);
 	devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) |
 		   (mdat << PORT_DEVSLP_MDAT_OFFSET) |
 		   (deto << PORT_DEVSLP_DETO_OFFSET) |
@@ -2528,14 +2502,18 @@
 	int irq = hpriv->irq;
 	int rc;
 
-	if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
+	if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
+		if (hpriv->irq_handler)
+			dev_warn(host->dev, "both AHCI_HFLAG_MULTI_MSI flag set \
+				 and custom irq handler implemented\n");
+
 		rc = ahci_host_activate_multi_irqs(host, irq, sht);
-	else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
-		rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
-				       IRQF_SHARED, sht);
-	else
-		rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
+	} else {
+		rc = ata_host_activate(host, irq, hpriv->irq_handler,
 				       IRQF_SHARED, sht);
+	}
+
+
 	return rc;
 }
 EXPORT_SYMBOL_GPL(ahci_host_activate);
--- linux-4.4.0.orig/drivers/ata/libahci_platform.c
+++ linux-4.4.0/drivers/ata/libahci_platform.c
@@ -300,6 +300,9 @@
 		hpriv->phys[port] = NULL;
 		rc = 0;
 		break;
+	case -EPROBE_DEFER:
+		/* Do not complain yet */
+		break;
 
 	default:
 		dev_err(dev,
@@ -514,8 +517,9 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq <= 0) {
-		dev_err(dev, "no irq\n");
-		return -EINVAL;
+		if (irq != -EPROBE_DEFER)
+			dev_err(dev, "no irq\n");
+		return irq;
 	}
 
 	hpriv->irq = irq;
--- linux-4.4.0.orig/drivers/ata/libata-core.c
+++ linux-4.4.0/drivers/ata/libata-core.c
@@ -56,7 +56,6 @@
 #include <linux/workqueue.h>
 #include <linux/scatterlist.h>
 #include <linux/io.h>
-#include <linux/async.h>
 #include <linux/log2.h>
 #include <linux/slab.h>
 #include <linux/glob.h>
@@ -2209,6 +2208,9 @@
 	    (id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2)
 		dev->horkage |= ATA_HORKAGE_NOLPM;
 
+	if (ap->flags & ATA_FLAG_NO_LPM)
+		dev->horkage |= ATA_HORKAGE_NOLPM;
+
 	if (dev->horkage & ATA_HORKAGE_NOLPM) {
 		ata_dev_warn(dev, "LPM support broken, forcing max_power\n");
 		dev->link->ap->target_lpm_policy = ATA_LPM_MAX_POWER;
@@ -4138,6 +4140,13 @@
 	 */
 	{ "ST380013AS",		"3.20",		ATA_HORKAGE_MAX_SEC_1024 },
 
+	/*
+	 * These devices time out with higher max sects.
+	 * https://bugzilla.kernel.org/show_bug.cgi?id=121671
+	 */
+	{ "LITEON CX1-JB*-HP",	NULL,		ATA_HORKAGE_MAX_SEC_1024 },
+	{ "LITEON EP1-*",	NULL,		ATA_HORKAGE_MAX_SEC_1024 },
+
 	/* Devices we expect to fail diagnostics */
 
 	/* Devices where NCQ should be avoided */
@@ -4166,9 +4175,12 @@
 	{ "ST3320[68]13AS",	"SD1[5-9]",	ATA_HORKAGE_NONCQ |
 						ATA_HORKAGE_FIRMWARE_WARN },
 
-	/* drives which fail FPDMA_AA activation (some may freeze afterwards) */
-	{ "ST1000LM024 HN-M101MBB", "2AR10001",	ATA_HORKAGE_BROKEN_FPDMA_AA },
-	{ "ST1000LM024 HN-M101MBB", "2BA30001",	ATA_HORKAGE_BROKEN_FPDMA_AA },
+	/* drives which fail FPDMA_AA activation (some may freeze afterwards)
+	   the ST disks also have LPM issues */
+	{ "ST1000LM024 HN-M101MBB", "2AR10001",	ATA_HORKAGE_BROKEN_FPDMA_AA |
+						ATA_HORKAGE_NOLPM, },
+	{ "ST1000LM024 HN-M101MBB", "2BA30001",	ATA_HORKAGE_BROKEN_FPDMA_AA |
+						ATA_HORKAGE_NOLPM, },
 	{ "VB0250EAVER",	"HPG7",		ATA_HORKAGE_BROKEN_FPDMA_AA },
 
 	/* Blacklist entries taken from Silicon Image 3124/3132
@@ -4180,6 +4192,10 @@
 	/* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */
 	{ "C300-CTFDDAC128MAG",	"0001",		ATA_HORKAGE_NONCQ, },
 
+	/* Some Sandisk SSDs lock up hard with NCQ enabled.  Reported on
+	   SD7SN6S256G and SD8SN8U256G */
+	{ "SanDisk SD[78]SN*G",	NULL,		ATA_HORKAGE_NONCQ, },
+
 	/* devices which puke on READ_NATIVE_MAX */
 	{ "HDS724040KLSA80",	"KFAOA20N",	ATA_HORKAGE_BROKEN_HPA, },
 	{ "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA },
@@ -4217,7 +4233,28 @@
 	{ "PIONEER DVD-RW  DVR-212D",	NULL,	ATA_HORKAGE_NOSETXFER },
 	{ "PIONEER DVD-RW  DVR-216D",	NULL,	ATA_HORKAGE_NOSETXFER },
 
+	/* Crucial BX100 SSD 500GB has broken LPM support */
+	{ "CT500BX100SSD1",		NULL,	ATA_HORKAGE_NOLPM },
+
+	/* 512GB MX100 with MU01 firmware has both queued TRIM and LPM issues */
+	{ "Crucial_CT512MX100*",	"MU01",	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_ZERO_AFTER_TRIM |
+						ATA_HORKAGE_NOLPM, },
+	/* 512GB MX100 with newer firmware has only LPM issues */
+	{ "Crucial_CT512MX100*",	NULL,	ATA_HORKAGE_ZERO_AFTER_TRIM |
+						ATA_HORKAGE_NOLPM, },
+
+	/* 480GB+ M500 SSDs have both queued TRIM and LPM issues */
+	{ "Crucial_CT480M500*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_ZERO_AFTER_TRIM |
+						ATA_HORKAGE_NOLPM, },
+	{ "Crucial_CT960M500*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_ZERO_AFTER_TRIM |
+						ATA_HORKAGE_NOLPM, },
+
 	/* devices that don't properly handle queued TRIM commands */
+	{ "Micron_M500IT_*",		"MU01",	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_ZERO_AFTER_TRIM, },
 	{ "Micron_M500_*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
 	{ "Crucial_CT*M500*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
@@ -4228,7 +4265,9 @@
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
 	{ "Crucial_CT*MX100*",		"MU01",	ATA_HORKAGE_NO_NCQ_TRIM |
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
-	{ "Samsung SSD 8*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
+	{ "Samsung SSD 840*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_ZERO_AFTER_TRIM, },
+	{ "Samsung SSD 850*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
 	{ "FCCT*M500*",			NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
@@ -4260,6 +4299,7 @@
 	{ "SSD*INTEL*",			NULL,	ATA_HORKAGE_ZERO_AFTER_TRIM, },
 	{ "Samsung*SSD*",		NULL,	ATA_HORKAGE_ZERO_AFTER_TRIM, },
 	{ "SAMSUNG*SSD*",		NULL,	ATA_HORKAGE_ZERO_AFTER_TRIM, },
+	{ "SAMSUNG*MZ7KM*",		NULL,	ATA_HORKAGE_ZERO_AFTER_TRIM, },
 	{ "ST[1248][0248]0[FH]*",	NULL,	ATA_HORKAGE_ZERO_AFTER_TRIM, },
 
 	/*
@@ -4673,7 +4713,10 @@
 	return ATA_DEFER_LINK;
 }
 
-void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
+enum ata_completion_errors ata_noop_qc_prep(struct ata_queued_cmd *qc)
+{
+	return AC_ERR_OK;
+}
 
 /**
  *	ata_sg_init - Associate command with scatter-gather table.
@@ -5070,8 +5113,7 @@
 	 * We guarantee to LLDs that they will have at least one
 	 * non-zero sg if the command is a data command.
 	 */
-	if (WARN_ON_ONCE(ata_is_data(prot) &&
-			 (!qc->sg || !qc->n_elem || !qc->nbytes)))
+	if (ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes))
 		goto sys_err;
 
 	if (ata_is_dma(prot) || (ata_is_pio(prot) &&
@@ -5087,7 +5129,9 @@
 		return;
 	}
 
-	ap->ops->qc_prep(qc);
+	qc->err_mask |= ap->ops->qc_prep(qc);
+	if (unlikely(qc->err_mask))
+		goto err;
 	trace_ata_qc_issue(qc);
 	qc->err_mask |= ap->ops->qc_issue(qc);
 	if (unlikely(qc->err_mask))
@@ -6182,7 +6226,7 @@
 	/* perform each probe asynchronously */
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
-		async_schedule(async_port_probe, ap);
+		ap->cookie = async_schedule(async_port_probe, ap);
 	}
 
 	return 0;
@@ -6315,8 +6359,11 @@
 {
 	int i;
 
-	for (i = 0; i < host->n_ports; i++)
+	for (i = 0; i < host->n_ports; i++) {
+		/* Ensure ata_port probe has completed */
+		async_synchronize_cookie(host->ports[i]->cookie + 1);
 		ata_port_detach(host->ports[i]);
+	}
 
 	/* the host is dead now, dissociate ACPI */
 	ata_acpi_dissociate(host);
--- linux-4.4.0.orig/drivers/ata/libata-eh.c
+++ linux-4.4.0/drivers/ata/libata-eh.c
@@ -606,7 +606,7 @@
 	ata_scsi_port_error_handler(host, ap);
 
 	/* finish or retry handled scmd's and clean up */
-	WARN_ON(host->host_failed || !list_empty(&eh_work_q));
+	WARN_ON(!list_empty(&eh_work_q));
 
 	DPRINTK("EXIT\n");
 }
@@ -2198,12 +2198,16 @@
 		if (qc->err_mask & ~AC_ERR_OTHER)
 			qc->err_mask &= ~AC_ERR_OTHER;
 
-		/* SENSE_VALID trumps dev/unknown error and revalidation */
+		/*
+		 * SENSE_VALID trumps dev/unknown error and revalidation. Upper
+		 * layers will determine whether the command is worth retrying
+		 * based on the sense data and device class/type. Otherwise,
+		 * determine directly if the command is worth retrying using its
+		 * error mask and flags.
+		 */
 		if (qc->flags & ATA_QCFLAG_SENSE_VALID)
 			qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
-
-		/* determine whether the command is worth retrying */
-		if (ata_eh_worth_retry(qc))
+		else if (ata_eh_worth_retry(qc))
 			qc->flags |= ATA_QCFLAG_RETRY;
 
 		/* accumulate error info */
@@ -2245,8 +2249,8 @@
 		if (dev->flags & ATA_DFLAG_DUBIOUS_XFER)
 			eflags |= ATA_EFLAG_DUBIOUS_XFER;
 		ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask);
+		trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask);
 	}
-	trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask);
 	DPRINTK("EXIT\n");
 }
 
--- linux-4.4.0.orig/drivers/ata/libata-pmp.c
+++ linux-4.4.0/drivers/ata/libata-pmp.c
@@ -764,6 +764,7 @@
 
 	if (dev->flags & ATA_DFLAG_DETACH) {
 		detach = 1;
+		rc = -ENODEV;
 		goto fail;
 	}
 
--- linux-4.4.0.orig/drivers/ata/libata-scsi.c
+++ linux-4.4.0/drivers/ata/libata-scsi.c
@@ -675,19 +675,18 @@
 int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
 		     int cmd, void __user *arg)
 {
-	int val = -EINVAL, rc = -EINVAL;
+	unsigned long val;
+	int rc = -EINVAL;
 	unsigned long flags;
 
 	switch (cmd) {
-	case ATA_IOC_GET_IO32:
+	case HDIO_GET_32BIT:
 		spin_lock_irqsave(ap->lock, flags);
 		val = ata_ioc32(ap);
 		spin_unlock_irqrestore(ap->lock, flags);
-		if (copy_to_user(arg, &val, 1))
-			return -EFAULT;
-		return 0;
+		return put_user(val, (unsigned long __user *)arg);
 
-	case ATA_IOC_SET_IO32:
+	case HDIO_SET_32BIT:
 		val = (unsigned long) arg;
 		rc = 0;
 		spin_lock_irqsave(ap->lock, flags);
@@ -1655,6 +1654,21 @@
 	return 1;
 }
 
+static bool ata_check_nblocks(struct scsi_cmnd *scmd, u32 n_blocks)
+{
+	struct request *rq = scmd->request;
+	u32 req_blocks;
+
+	if (!blk_rq_is_passthrough(rq))
+		return true;
+
+	req_blocks = blk_rq_bytes(rq) / scmd->device->sector_size;
+	if (n_blocks > req_blocks)
+		return false;
+
+	return true;
+}
+
 /**
  *	ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
  *	@qc: Storage for translated ATA taskfile
@@ -1694,6 +1708,8 @@
 		scsi_10_lba_len(cdb, &block, &n_block);
 		if (cdb[1] & (1 << 3))
 			tf_flags |= ATA_TFLAG_FUA;
+		if (!ata_check_nblocks(scmd, n_block))
+			goto invalid_fld;
 		break;
 	case READ_6:
 	case WRITE_6:
@@ -1706,6 +1722,8 @@
 		 */
 		if (!n_block)
 			n_block = 256;
+		if (!ata_check_nblocks(scmd, n_block))
+			goto invalid_fld;
 		break;
 	case READ_16:
 	case WRITE_16:
@@ -1714,6 +1732,8 @@
 		scsi_16_lba_len(cdb, &block, &n_block);
 		if (cdb[1] & (1 << 3))
 			tf_flags |= ATA_TFLAG_FUA;
+		if (!ata_check_nblocks(scmd, n_block))
+			goto invalid_fld;
 		break;
 	default:
 		DPRINTK("no-byte command\n");
@@ -2833,10 +2853,12 @@
 static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
 {
 	if (!sata_pmp_attached(ap)) {
-		if (likely(devno < ata_link_max_devices(&ap->link)))
+		if (likely(devno >= 0 &&
+			   devno < ata_link_max_devices(&ap->link)))
 			return &ap->link.device[devno];
 	} else {
-		if (likely(devno < ap->nr_pmp_links))
+		if (likely(devno >= 0 &&
+			   devno < ap->nr_pmp_links))
 			return &ap->pmp_link[devno].device[0];
 	}
 
@@ -3471,7 +3493,9 @@
 		if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
 			/* relay SCSI command to ATAPI device */
 			int len = COMMAND_SIZE(scsi_op);
-			if (unlikely(len > scmd->cmd_len || len > dev->cdb_len))
+			if (unlikely(len > scmd->cmd_len ||
+				     len > dev->cdb_len ||
+				     scmd->cmd_len > ATAPI_CDB_LEN))
 				goto bad_cdb_len;
 
 			xlat_func = atapi_xlat;
@@ -3696,22 +3720,19 @@
 		 */
 		shost->max_host_blocked = 1;
 
-		rc = scsi_add_host_with_dma(ap->scsi_host,
-						&ap->tdev, ap->host->dev);
+		rc = scsi_add_host_with_dma(shost, &ap->tdev, ap->host->dev);
 		if (rc)
-			goto err_add;
+			goto err_alloc;
 	}
 
 	return 0;
 
- err_add:
-	scsi_host_put(host->ports[i]->scsi_host);
  err_alloc:
 	while (--i >= 0) {
 		struct Scsi_Host *shost = host->ports[i]->scsi_host;
 
+		/* scsi_host_put() is in ata_devres_release() */
 		scsi_remove_host(shost);
-		scsi_host_put(shost);
 	}
 	return rc;
 }
--- linux-4.4.0.orig/drivers/ata/libata-sff.c
+++ linux-4.4.0/drivers/ata/libata-sff.c
@@ -703,6 +703,10 @@
 	unsigned int offset;
 	unsigned char *buf;
 
+	if (!qc->cursg) {
+		qc->curbytes = qc->nbytes;
+		return;
+	}
 	if (qc->curbytes == qc->nbytes - qc->sect_size)
 		ap->hsm_task_state = HSM_ST_LAST;
 
@@ -742,6 +746,8 @@
 
 	if (qc->cursg_ofs == qc->cursg->length) {
 		qc->cursg = sg_next(qc->cursg);
+		if (!qc->cursg)
+			ap->hsm_task_state = HSM_ST_LAST;
 		qc->cursg_ofs = 0;
 	}
 }
@@ -997,12 +1003,9 @@
 static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
 {
 	struct ata_port *ap = qc->ap;
-	unsigned long flags;
 
 	if (ap->ops->error_handler) {
 		if (in_wq) {
-			spin_lock_irqsave(ap->lock, flags);
-
 			/* EH might have kicked in while host lock is
 			 * released.
 			 */
@@ -1014,8 +1017,6 @@
 				} else
 					ata_port_freeze(ap);
 			}
-
-			spin_unlock_irqrestore(ap->lock, flags);
 		} else {
 			if (likely(!(qc->err_mask & AC_ERR_HSM)))
 				ata_qc_complete(qc);
@@ -1024,10 +1025,8 @@
 		}
 	} else {
 		if (in_wq) {
-			spin_lock_irqsave(ap->lock, flags);
 			ata_sff_irq_on(ap);
 			ata_qc_complete(qc);
-			spin_unlock_irqrestore(ap->lock, flags);
 		} else
 			ata_qc_complete(qc);
 	}
@@ -1048,9 +1047,10 @@
 {
 	struct ata_link *link = qc->dev->link;
 	struct ata_eh_info *ehi = &link->eh_info;
-	unsigned long flags = 0;
 	int poll_next;
 
+	lockdep_assert_held(ap->lock);
+
 	WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
 
 	/* Make sure ata_sff_qc_issue() does not throw things
@@ -1112,14 +1112,6 @@
 			}
 		}
 
-		/* Send the CDB (atapi) or the first data block (ata pio out).
-		 * During the state transition, interrupt handler shouldn't
-		 * be invoked before the data transfer is complete and
-		 * hsm_task_state is changed. Hence, the following locking.
-		 */
-		if (in_wq)
-			spin_lock_irqsave(ap->lock, flags);
-
 		if (qc->tf.protocol == ATA_PROT_PIO) {
 			/* PIO data out protocol.
 			 * send first data block.
@@ -1135,9 +1127,6 @@
 			/* send CDB */
 			atapi_send_cdb(ap, qc);
 
-		if (in_wq)
-			spin_unlock_irqrestore(ap->lock, flags);
-
 		/* if polling, ata_sff_pio_task() handles the rest.
 		 * otherwise, interrupt handler takes over from here.
 		 */
@@ -1361,12 +1350,14 @@
 	u8 status;
 	int poll_next;
 
+	spin_lock_irq(ap->lock);
+
 	BUG_ON(ap->sff_pio_task_link == NULL);
 	/* qc can be NULL if timeout occurred */
 	qc = ata_qc_from_tag(ap, link->active_tag);
 	if (!qc) {
 		ap->sff_pio_task_link = NULL;
-		return;
+		goto out_unlock;
 	}
 
 fsm_start:
@@ -1381,11 +1372,14 @@
 	 */
 	status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
 	if (status & ATA_BUSY) {
+		spin_unlock_irq(ap->lock);
 		ata_msleep(ap, 2);
+		spin_lock_irq(ap->lock);
+
 		status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
 		if (status & ATA_BUSY) {
 			ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
-			return;
+			goto out_unlock;
 		}
 	}
 
@@ -1402,6 +1396,8 @@
 	 */
 	if (poll_next)
 		goto fsm_start;
+out_unlock:
+	spin_unlock_irq(ap->lock);
 }
 
 /**
@@ -1490,7 +1486,6 @@
 		break;
 
 	default:
-		WARN_ON_ONCE(1);
 		return AC_ERR_SYSTEM;
 	}
 
@@ -2746,12 +2741,14 @@
  *	LOCKING:
  *	spin_lock_irqsave(host lock)
  */
-void ata_bmdma_qc_prep(struct ata_queued_cmd *qc)
+enum ata_completion_errors ata_bmdma_qc_prep(struct ata_queued_cmd *qc)
 {
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 
 	ata_bmdma_fill_sg(qc);
+
+	return AC_ERR_OK;
 }
 EXPORT_SYMBOL_GPL(ata_bmdma_qc_prep);
 
@@ -2764,12 +2761,14 @@
  *	LOCKING:
  *	spin_lock_irqsave(host lock)
  */
-void ata_bmdma_dumb_qc_prep(struct ata_queued_cmd *qc)
+enum ata_completion_errors ata_bmdma_dumb_qc_prep(struct ata_queued_cmd *qc)
 {
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 
 	ata_bmdma_fill_sg_dumb(qc);
+
+	return AC_ERR_OK;
 }
 EXPORT_SYMBOL_GPL(ata_bmdma_dumb_qc_prep);
 
--- linux-4.4.0.orig/drivers/ata/libata-transport.c
+++ linux-4.4.0/drivers/ata/libata-transport.c
@@ -224,7 +224,6 @@
 
 static void ata_tport_release(struct device *dev)
 {
-	put_device(dev->parent);
 }
 
 /**
@@ -284,7 +283,7 @@
 	device_initialize(dev);
 	dev->type = &ata_port_type;
 
-	dev->parent = get_device(parent);
+	dev->parent = parent;
 	dev->release = ata_tport_release;
 	dev_set_name(dev, "ata%d", ap->print_id);
 	transport_setup_device(dev);
@@ -348,7 +347,6 @@
 
 static void ata_tlink_release(struct device *dev)
 {
-	put_device(dev->parent);
 }
 
 /**
@@ -410,7 +408,7 @@
 	int error;
 
 	device_initialize(dev);
-	dev->parent = get_device(&ap->tdev);
+	dev->parent = &ap->tdev;
 	dev->release = ata_tlink_release;
 	if (ata_is_host_link(link))
 		dev_set_name(dev, "link%d", ap->print_id);
@@ -588,7 +586,6 @@
 
 static void ata_tdev_release(struct device *dev)
 {
-	put_device(dev->parent);
 }
 
 /**
@@ -661,7 +658,7 @@
 	int error;
 
 	device_initialize(dev);
-	dev->parent = get_device(&link->tdev);
+	dev->parent = &link->tdev;
 	dev->release = ata_tdev_release;
 	if (ata_is_host_link(link))
 		dev_set_name(dev, "dev%d.%d", ap->print_id,ata_dev->devno);
--- linux-4.4.0.orig/drivers/ata/libata-zpodd.c
+++ linux-4.4.0/drivers/ata/libata-zpodd.c
@@ -34,7 +34,7 @@
 static int eject_tray(struct ata_device *dev)
 {
 	struct ata_taskfile tf;
-	const char cdb[] = {  GPCMD_START_STOP_UNIT,
+	static const char cdb[ATAPI_CDB_LEN] = {  GPCMD_START_STOP_UNIT,
 		0, 0, 0,
 		0x02,     /* LoEj */
 		0, 0, 0, 0, 0, 0, 0,
@@ -51,38 +51,52 @@
 /* Per the spec, only slot type and drawer type ODD can be supported */
 static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
 {
-	char buf[16];
+	char *buf;
 	unsigned int ret;
-	struct rm_feature_desc *desc = (void *)(buf + 8);
+	struct rm_feature_desc *desc;
 	struct ata_taskfile tf;
-	char cdb[] = {  GPCMD_GET_CONFIGURATION,
+	static const char cdb[ATAPI_CDB_LEN] = {  GPCMD_GET_CONFIGURATION,
 			2,      /* only 1 feature descriptor requested */
 			0, 3,   /* 3, removable medium feature */
 			0, 0, 0,/* reserved */
-			0, sizeof(buf),
+			0, 16,
 			0, 0, 0,
 	};
 
+	buf = kzalloc(16, GFP_KERNEL);
+	if (!buf)
+		return ODD_MECH_TYPE_UNSUPPORTED;
+	desc = (void *)(buf + 8);
+
 	ata_tf_init(dev, &tf);
 	tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	tf.command = ATA_CMD_PACKET;
 	tf.protocol = ATAPI_PROT_PIO;
-	tf.lbam = sizeof(buf);
+	tf.lbam = 16;
 
 	ret = ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
-				buf, sizeof(buf), 0);
-	if (ret)
+				buf, 16, 0);
+	if (ret) {
+		kfree(buf);
 		return ODD_MECH_TYPE_UNSUPPORTED;
+	}
 
-	if (be16_to_cpu(desc->feature_code) != 3)
+	if (be16_to_cpu(desc->feature_code) != 3) {
+		kfree(buf);
 		return ODD_MECH_TYPE_UNSUPPORTED;
+	}
 
-	if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1)
+	if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1) {
+		kfree(buf);
 		return ODD_MECH_TYPE_SLOT;
-	else if (desc->mech_type == 1 && desc->load == 0 && desc->eject == 1)
+	} else if (desc->mech_type == 1 && desc->load == 0 &&
+		   desc->eject == 1) {
+		kfree(buf);
 		return ODD_MECH_TYPE_DRAWER;
-	else
+	} else {
+		kfree(buf);
 		return ODD_MECH_TYPE_UNSUPPORTED;
+	}
 }
 
 /* Test if ODD is zero power ready by sense code */
--- linux-4.4.0.orig/drivers/ata/pata_amd.c
+++ linux-4.4.0/drivers/ata/pata_amd.c
@@ -616,6 +616,7 @@
 	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE),	8 },
 	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE),	8 },
 	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_CS5536_IDE),		9 },
+	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_CS5536_DEV_IDE),	9 },
 
 	{ },
 };
--- linux-4.4.0.orig/drivers/ata/pata_cs5536.c
+++ linux-4.4.0/drivers/ata/pata_cs5536.c
@@ -289,6 +289,7 @@
 
 static const struct pci_device_id cs5536[] = {
 	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_CS5536_IDE), },
+	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), },
 	{ },
 };
 
--- linux-4.4.0.orig/drivers/ata/pata_ep93xx.c
+++ linux-4.4.0/drivers/ata/pata_ep93xx.c
@@ -659,7 +659,7 @@
 	 * start of new transfer.
 	 */
 	drv_data->dma_rx_data.port = EP93XX_DMA_IDE;
-	drv_data->dma_rx_data.direction = DMA_FROM_DEVICE;
+	drv_data->dma_rx_data.direction = DMA_DEV_TO_MEM;
 	drv_data->dma_rx_data.name = "ep93xx-pata-rx";
 	drv_data->dma_rx_channel = dma_request_channel(mask,
 		ep93xx_pata_dma_filter, &drv_data->dma_rx_data);
@@ -667,7 +667,7 @@
 		return;
 
 	drv_data->dma_tx_data.port = EP93XX_DMA_IDE;
-	drv_data->dma_tx_data.direction = DMA_TO_DEVICE;
+	drv_data->dma_tx_data.direction = DMA_MEM_TO_DEV;
 	drv_data->dma_tx_data.name = "ep93xx-pata-tx";
 	drv_data->dma_tx_channel = dma_request_channel(mask,
 		ep93xx_pata_dma_filter, &drv_data->dma_tx_data);
@@ -678,7 +678,7 @@
 
 	/* Configure receive channel direction and source address */
 	memset(&conf, 0, sizeof(conf));
-	conf.direction = DMA_FROM_DEVICE;
+	conf.direction = DMA_DEV_TO_MEM;
 	conf.src_addr = drv_data->udma_in_phys;
 	conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) {
@@ -689,7 +689,7 @@
 
 	/* Configure transmit channel direction and destination address */
 	memset(&conf, 0, sizeof(conf));
-	conf.direction = DMA_TO_DEVICE;
+	conf.direction = DMA_MEM_TO_DEV;
 	conf.dst_addr = drv_data->udma_out_phys;
 	conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) {
--- linux-4.4.0.orig/drivers/ata/pata_macio.c
+++ linux-4.4.0/drivers/ata/pata_macio.c
@@ -507,7 +507,7 @@
 	return ATA_CBL_PATA40;
 }
 
-static void pata_macio_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors pata_macio_qc_prep(struct ata_queued_cmd *qc)
 {
 	unsigned int write = (qc->tf.flags & ATA_TFLAG_WRITE);
 	struct ata_port *ap = qc->ap;
@@ -520,7 +520,7 @@
 		   __func__, qc, qc->flags, write, qc->dev->devno);
 
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 
 	table = (struct dbdma_cmd *) priv->dma_table_cpu;
 
@@ -565,6 +565,8 @@
 	table->command = cpu_to_le16(DBDMA_STOP);
 
 	dev_dbgdma(priv->dev, "%s: %d DMA list entries\n", __func__, pi);
+
+	return AC_ERR_OK;
 }
 
 
--- linux-4.4.0.orig/drivers/ata/pata_pxa.c
+++ linux-4.4.0/drivers/ata/pata_pxa.c
@@ -59,25 +59,27 @@
 /*
  * Prepare taskfile for submission.
  */
-static void pxa_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors pxa_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct pata_pxa_data *pd = qc->ap->private_data;
 	struct dma_async_tx_descriptor *tx;
 	enum dma_transfer_direction dir;
 
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 
 	dir = (qc->dma_dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
 	tx = dmaengine_prep_slave_sg(pd->dma_chan, qc->sg, qc->n_elem, dir,
 				     DMA_PREP_INTERRUPT);
 	if (!tx) {
 		ata_dev_err(qc->dev, "prep_slave_sg() failed\n");
-		return;
+		return AC_ERR_OK;
 	}
 	tx->callback = pxa_ata_dma_irq;
 	tx->callback_param = pd;
 	pd->dma_cookie = dmaengine_submit(tx);
+
+	return AC_ERR_OK;
 }
 
 /*
--- linux-4.4.0.orig/drivers/ata/pata_rb532_cf.c
+++ linux-4.4.0/drivers/ata/pata_rb532_cf.c
@@ -32,6 +32,8 @@
 #include <linux/libata.h>
 #include <scsi/scsi_host.h>
 
+#include <asm/mach-rc32434/rb.h>
+
 #define DRV_NAME	"pata-rb532-cf"
 #define DRV_VERSION	"0.1.0"
 #define DRV_DESC	"PATA driver for RouterBOARD 532 Compact Flash"
@@ -107,6 +109,7 @@
 	int gpio;
 	struct resource *res;
 	struct ata_host *ah;
+	struct cf_device *pdata;
 	struct rb532_cf_info *info;
 	int ret;
 
@@ -122,7 +125,13 @@
 		return -ENOENT;
 	}
 
-	gpio = irq_to_gpio(irq);
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data specified\n");
+		return -EINVAL;
+	}
+
+	gpio = pdata->gpio_pin;
 	if (gpio < 0) {
 		dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq);
 		return -ENOENT;
--- linux-4.4.0.orig/drivers/ata/pdc_adma.c
+++ linux-4.4.0/drivers/ata/pdc_adma.c
@@ -132,7 +132,7 @@
 				const struct pci_device_id *ent);
 static int adma_port_start(struct ata_port *ap);
 static void adma_port_stop(struct ata_port *ap);
-static void adma_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors adma_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
 static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void adma_freeze(struct ata_port *ap);
@@ -311,7 +311,7 @@
 	return i;
 }
 
-static void adma_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors adma_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct adma_port_priv *pp = qc->ap->private_data;
 	u8  *buf = pp->pkt;
@@ -322,7 +322,7 @@
 
 	adma_enter_reg_mode(qc->ap);
 	if (qc->tf.protocol != ATA_PROT_DMA)
-		return;
+		return AC_ERR_OK;
 
 	buf[i++] = 0;	/* Response flags */
 	buf[i++] = 0;	/* reserved */
@@ -387,6 +387,7 @@
 			printk("%s\n", obuf);
 	}
 #endif
+	return AC_ERR_OK;
 }
 
 static inline void adma_packet_start(struct ata_queued_cmd *qc)
--- linux-4.4.0.orig/drivers/ata/sata_dwc_460ex.c
+++ linux-4.4.0/drivers/ata/sata_dwc_460ex.c
@@ -924,15 +924,13 @@
 					 struct ata_taskfile *tf,
 					 u8 tag, u32 cmd_issued)
 {
-	unsigned long flags;
 	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
 
 	dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d\n", __func__, tf->command,
 		ata_get_cmd_descript(tf->command), tag);
 
-	spin_lock_irqsave(&ap->host->lock, flags);
 	hsdevp->cmd_issued[tag] = cmd_issued;
-	spin_unlock_irqrestore(&ap->host->lock, flags);
+
 	/*
 	 * Clear SError before executing a new command.
 	 * sata_dwc_scr_write and read can not be used here. Clearing the PM
--- linux-4.4.0.orig/drivers/ata/sata_fsl.c
+++ linux-4.4.0/drivers/ata/sata_fsl.c
@@ -513,7 +513,7 @@
 	return num_prde;
 }
 
-static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors sata_fsl_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct sata_fsl_port_priv *pp = ap->private_data;
@@ -559,6 +559,8 @@
 
 	VPRINTK("SATA FSL : xx_qc_prep, di = 0x%x, ttl = %d, num_prde = %d\n",
 		desc_info, ttl_dwords, num_prde);
+
+	return AC_ERR_OK;
 }
 
 static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc)
--- linux-4.4.0.orig/drivers/ata/sata_inic162x.c
+++ linux-4.4.0/drivers/ata/sata_inic162x.c
@@ -472,7 +472,7 @@
 	prd[-1].flags |= PRD_END;
 }
 
-static void inic_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors inic_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct inic_port_priv *pp = qc->ap->private_data;
 	struct inic_pkt *pkt = pp->pkt;
@@ -532,6 +532,8 @@
 		inic_fill_sg(prd, qc);
 
 	pp->cpb_tbl[0] = pp->pkt_dma;
+
+	return AC_ERR_OK;
 }
 
 static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
--- linux-4.4.0.orig/drivers/ata/sata_mv.c
+++ linux-4.4.0/drivers/ata/sata_mv.c
@@ -605,8 +605,8 @@
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static int mv_qc_defer(struct ata_queued_cmd *qc);
-static void mv_qc_prep(struct ata_queued_cmd *qc);
-static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
+static enum ata_completion_errors mv_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors mv_qc_prep_iie(struct ata_queued_cmd *qc);
 static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
 static int mv_hardreset(struct ata_link *link, unsigned int *class,
 			unsigned long deadline);
@@ -2046,7 +2046,7 @@
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors mv_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct mv_port_priv *pp = ap->private_data;
@@ -2058,15 +2058,15 @@
 	switch (tf->protocol) {
 	case ATA_PROT_DMA:
 		if (tf->command == ATA_CMD_DSM)
-			return;
+			return AC_ERR_OK;
 		/* fall-thru */
 	case ATA_PROT_NCQ:
 		break;	/* continue below */
 	case ATA_PROT_PIO:
 		mv_rw_multi_errata_sata24(qc);
-		return;
+		return AC_ERR_OK;
 	default:
-		return;
+		return AC_ERR_OK;
 	}
 
 	/* Fill in command request block
@@ -2113,12 +2113,10 @@
 		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
 		 * of which are defined/used by Linux.  If we get here, this
 		 * driver needs work.
-		 *
-		 * FIXME: modify libata to give qc_prep a return value and
-		 * return error here.
 		 */
-		BUG_ON(tf->command);
-		break;
+		ata_port_err(ap, "%s: unsupported command: %.2x\n", __func__,
+				tf->command);
+		return AC_ERR_INVALID;
 	}
 	mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
 	mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
@@ -2131,8 +2129,10 @@
 	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
 
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 	mv_fill_sg(qc);
+
+	return AC_ERR_OK;
 }
 
 /**
@@ -2147,7 +2147,7 @@
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
+static enum ata_completion_errors mv_qc_prep_iie(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct mv_port_priv *pp = ap->private_data;
@@ -2158,9 +2158,9 @@
 
 	if ((tf->protocol != ATA_PROT_DMA) &&
 	    (tf->protocol != ATA_PROT_NCQ))
-		return;
+		return AC_ERR_OK;
 	if (tf->command == ATA_CMD_DSM)
-		return;  /* use bmdma for this */
+		return AC_ERR_OK;  /* use bmdma for this */
 
 	/* Fill in Gen IIE command request block */
 	if (!(tf->flags & ATA_TFLAG_WRITE))
@@ -2201,8 +2201,10 @@
 		);
 
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 	mv_fill_sg(qc);
+
+	return AC_ERR_OK;
 }
 
 /**
@@ -4121,6 +4123,9 @@
 	host->iomap = NULL;
 	hpriv->base = devm_ioremap(&pdev->dev, res->start,
 				   resource_size(res));
+	if (!hpriv->base)
+		return -ENOMEM;
+
 	hpriv->base -= SATAHC0_REG_BASE;
 
 	hpriv->clk = clk_get(&pdev->dev, NULL);
--- linux-4.4.0.orig/drivers/ata/sata_nv.c
+++ linux-4.4.0/drivers/ata/sata_nv.c
@@ -313,7 +313,7 @@
 static void nv_ck804_thaw(struct ata_port *ap);
 static int nv_adma_slave_config(struct scsi_device *sdev);
 static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc);
-static void nv_adma_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors nv_adma_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance);
 static void nv_adma_irq_clear(struct ata_port *ap);
@@ -335,7 +335,7 @@
 static void nv_swncq_error_handler(struct ata_port *ap);
 static int nv_swncq_slave_config(struct scsi_device *sdev);
 static int nv_swncq_port_start(struct ata_port *ap);
-static void nv_swncq_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors nv_swncq_qc_prep(struct ata_queued_cmd *qc);
 static void nv_swncq_fill_sg(struct ata_queued_cmd *qc);
 static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc);
 static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis);
@@ -1382,7 +1382,7 @@
 	return 1;
 }
 
-static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors nv_adma_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct nv_adma_port_priv *pp = qc->ap->private_data;
 	struct nv_adma_cpb *cpb = &pp->cpb[qc->tag];
@@ -1394,7 +1394,7 @@
 			(qc->flags & ATA_QCFLAG_DMAMAP));
 		nv_adma_register_mode(qc->ap);
 		ata_bmdma_qc_prep(qc);
-		return;
+		return AC_ERR_OK;
 	}
 
 	cpb->resp_flags = NV_CPB_RESP_DONE;
@@ -1426,6 +1426,8 @@
 	cpb->ctl_flags = ctl_flags;
 	wmb();
 	cpb->resp_flags = 0;
+
+	return AC_ERR_OK;
 }
 
 static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
@@ -1989,17 +1991,19 @@
 	return 0;
 }
 
-static void nv_swncq_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors nv_swncq_qc_prep(struct ata_queued_cmd *qc)
 {
 	if (qc->tf.protocol != ATA_PROT_NCQ) {
 		ata_bmdma_qc_prep(qc);
-		return;
+		return AC_ERR_OK;
 	}
 
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 
 	nv_swncq_fill_sg(qc);
+
+	return AC_ERR_OK;
 }
 
 static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
--- linux-4.4.0.orig/drivers/ata/sata_promise.c
+++ linux-4.4.0/drivers/ata/sata_promise.c
@@ -155,7 +155,7 @@
 static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static int pdc_common_port_start(struct ata_port *ap);
 static int pdc_sata_port_start(struct ata_port *ap);
-static void pdc_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors pdc_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
@@ -649,7 +649,7 @@
 	prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
-static void pdc_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors pdc_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct pdc_port_priv *pp = qc->ap->private_data;
 	unsigned int i;
@@ -681,6 +681,8 @@
 	default:
 		break;
 	}
+
+	return AC_ERR_OK;
 }
 
 static int pdc_is_sataii_tx4(unsigned long flags)
--- linux-4.4.0.orig/drivers/ata/sata_qstor.c
+++ linux-4.4.0/drivers/ata/sata_qstor.c
@@ -116,7 +116,7 @@
 static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static int qs_port_start(struct ata_port *ap);
 static void qs_host_stop(struct ata_host *host);
-static void qs_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors qs_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
 static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
 static void qs_freeze(struct ata_port *ap);
@@ -276,7 +276,7 @@
 	return si;
 }
 
-static void qs_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors qs_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct qs_port_priv *pp = qc->ap->private_data;
 	u8 dflags = QS_DF_PORD, *buf = pp->pkt;
@@ -288,7 +288,7 @@
 
 	qs_enter_reg_mode(qc->ap);
 	if (qc->tf.protocol != ATA_PROT_DMA)
-		return;
+		return AC_ERR_OK;
 
 	nelem = qs_fill_sg(qc);
 
@@ -311,6 +311,8 @@
 
 	/* frame information structure (FIS) */
 	ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
+
+	return AC_ERR_OK;
 }
 
 static inline void qs_packet_start(struct ata_queued_cmd *qc)
--- linux-4.4.0.orig/drivers/ata/sata_rcar.c
+++ linux-4.4.0/drivers/ata/sata_rcar.c
@@ -122,7 +122,7 @@
 /* Descriptor table word 0 bit (when DTA32M = 1) */
 #define SATA_RCAR_DTEND			BIT(0)
 
-#define SATA_RCAR_DMA_BOUNDARY		0x1FFFFFFEUL
+#define SATA_RCAR_DMA_BOUNDARY		0x1FFFFFFFUL
 
 /* Gen2 Physical Layer Control Registers */
 #define RCAR_GEN2_PHY_CTL1_REG		0x1704
@@ -551,12 +551,14 @@
 	prd[si - 1].addr |= cpu_to_le32(SATA_RCAR_DTEND);
 }
 
-static void sata_rcar_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors sata_rcar_qc_prep(struct ata_queued_cmd *qc)
 {
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 
 	sata_rcar_bmdma_fill_sg(qc);
+
+	return AC_ERR_OK;
 }
 
 static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
@@ -875,7 +877,9 @@
 	int ret = 0;
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0)
+	if (irq < 0)
+		return irq;
+	if (!irq)
 		return -EINVAL;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(struct sata_rcar_priv),
--- linux-4.4.0.orig/drivers/ata/sata_sil.c
+++ linux-4.4.0/drivers/ata/sata_sil.c
@@ -119,7 +119,7 @@
 static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
 static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
-static void sil_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors sil_qc_prep(struct ata_queued_cmd *qc);
 static void sil_bmdma_setup(struct ata_queued_cmd *qc);
 static void sil_bmdma_start(struct ata_queued_cmd *qc);
 static void sil_bmdma_stop(struct ata_queued_cmd *qc);
@@ -333,12 +333,14 @@
 		last_prd->flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
-static void sil_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors sil_qc_prep(struct ata_queued_cmd *qc)
 {
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 
 	sil_fill_sg(qc);
+
+	return AC_ERR_OK;
 }
 
 static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
--- linux-4.4.0.orig/drivers/ata/sata_sil24.c
+++ linux-4.4.0/drivers/ata/sata_sil24.c
@@ -336,7 +336,7 @@
 static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val);
 static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val);
 static int sil24_qc_defer(struct ata_queued_cmd *qc);
-static void sil24_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
 static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc);
 static void sil24_pmp_attach(struct ata_port *ap);
@@ -840,7 +840,7 @@
 	return ata_std_qc_defer(qc);
 }
 
-static void sil24_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors sil24_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct sil24_port_priv *pp = ap->private_data;
@@ -884,6 +884,8 @@
 
 	if (qc->flags & ATA_QCFLAG_DMAMAP)
 		sil24_fill_sg(qc, sge);
+
+	return AC_ERR_OK;
 }
 
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
--- linux-4.4.0.orig/drivers/ata/sata_sx4.c
+++ linux-4.4.0/drivers/ata/sata_sx4.c
@@ -218,7 +218,7 @@
 static void pdc_freeze(struct ata_port *ap);
 static void pdc_thaw(struct ata_port *ap);
 static int pdc_port_start(struct ata_port *ap);
-static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
+static enum ata_completion_errors pdc20621_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static unsigned int pdc20621_dimm_init(struct ata_host *host);
@@ -546,7 +546,7 @@
 	VPRINTK("ata pkt buf ofs %u, mmio copied\n", i);
 }
 
-static void pdc20621_qc_prep(struct ata_queued_cmd *qc)
+static enum ata_completion_errors pdc20621_qc_prep(struct ata_queued_cmd *qc)
 {
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
@@ -558,6 +558,8 @@
 	default:
 		break;
 	}
+
+	return AC_ERR_OK;
 }
 
 static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
--- linux-4.4.0.orig/drivers/atm/Kconfig
+++ linux-4.4.0/drivers/atm/Kconfig
@@ -199,7 +199,7 @@
 	  make the card work).
 
 config ATM_NICSTAR_USE_IDT77105
-	bool "Use IDT77015 PHY driver (25Mbps)"
+	bool "Use IDT77105 PHY driver (25Mbps)"
 	depends on ATM_NICSTAR
 	help
 	  Support for the PHYsical layer chip in ForeRunner LE25 cards. In
--- linux-4.4.0.orig/drivers/atm/atmtcp.c
+++ linux-4.4.0/drivers/atm/atmtcp.c
@@ -432,9 +432,15 @@
 		return -EMEDIUMTYPE;
 	}
 	dev_data = PRIV(dev);
-	if (!dev_data->persist) return 0;
+	if (!dev_data->persist) {
+		atm_dev_put(dev);
+		return 0;
+	}
 	dev_data->persist = 0;
-	if (PRIV(dev)->vcc) return 0;
+	if (PRIV(dev)->vcc) {
+		atm_dev_put(dev);
+		return 0;
+	}
 	kfree(dev_data);
 	atm_dev_put(dev);
 	atm_dev_deregister(dev);
--- linux-4.4.0.orig/drivers/atm/eni.c
+++ linux-4.4.0/drivers/atm/eni.c
@@ -372,7 +372,7 @@
 		here = (eni_vcc->descr+skip) & (eni_vcc->words-1);
 		dma[j++] = (here << MID_DMA_COUNT_SHIFT) | (vcc->vci
 		    << MID_DMA_VCI_SHIFT) | MID_DT_JK;
-		j++;
+		dma[j++] = 0;
 	}
 	here = (eni_vcc->descr+size+skip) & (eni_vcc->words-1);
 	if (!eff) size += skip;
@@ -445,7 +445,7 @@
 	if (size != eff) {
 		dma[j++] = (here << MID_DMA_COUNT_SHIFT) |
 		    (vcc->vci << MID_DMA_VCI_SHIFT) | MID_DT_JK;
-		j++;
+		dma[j++] = 0;
 	}
 	if (!j || j > 2*RX_DMA_BUF) {
 		printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n");
@@ -2242,7 +2242,7 @@
 
 	rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32));
 	if (rc < 0)
-		goto out;
+		goto err_disable;
 
 	rc = -ENOMEM;
 	eni_dev = kmalloc(sizeof(struct eni_dev), GFP_KERNEL);
--- linux-4.4.0.orig/drivers/atm/firestream.c
+++ linux-4.4.0/drivers/atm/firestream.c
@@ -923,6 +923,7 @@
 			}
 			if (!to) {
 				printk ("No more free channels for FS50..\n");
+				kfree(vcc);
 				return -EBUSY;
 			}
 			vcc->channo = dev->channo;
@@ -933,6 +934,7 @@
 			if (((DO_DIRECTION(rxtp) && dev->atm_vccs[vcc->channo])) ||
 			    ( DO_DIRECTION(txtp) && test_bit (vcc->channo, dev->tx_inuse))) {
 				printk ("Channel is in use for FS155.\n");
+				kfree(vcc);
 				return -EBUSY;
 			}
 		}
@@ -946,6 +948,7 @@
 			    tc, sizeof (struct fs_transmit_config));
 		if (!tc) {
 			fs_dprintk (FS_DEBUG_OPEN, "fs: can't alloc transmit_config.\n");
+			kfree(vcc);
 			return -ENOMEM;
 		}
 
@@ -1006,6 +1009,7 @@
 				error = make_rate (pcr, r, &tmc0, NULL);
 				if (error) {
 					kfree(tc);
+					kfree(vcc);
 					return error;
 				}
 			}
--- linux-4.4.0.orig/drivers/atm/he.c
+++ linux-4.4.0/drivers/atm/he.c
@@ -717,7 +717,7 @@
 			instead of '/ 512', use '>> 9' to prevent a call
 			to divdu3 on x86 platforms
 		*/
-		rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9;
+		rate_cps = (unsigned long long) (1UL << exp) * (man + 512) >> 9;
 
 		if (rate_cps < 10)
 			rate_cps = 10;	/* 2.2.1 minimum payload rate is 10 cps */
--- linux-4.4.0.orig/drivers/atm/horizon.c
+++ linux-4.4.0/drivers/atm/horizon.c
@@ -2804,7 +2804,7 @@
 	return err;
 
 out_free_irq:
-	free_irq(dev->irq, dev);
+	free_irq(irq, dev);
 out_free:
 	kfree(dev);
 out_release:
--- linux-4.4.0.orig/drivers/atm/idt77252.c
+++ linux-4.4.0/drivers/atm/idt77252.c
@@ -1118,8 +1118,8 @@
 	rpp->len += skb->len;
 
 	if (stat & SAR_RSQE_EPDU) {
+		unsigned int len, truesize;
 		unsigned char *l1l2;
-		unsigned int len;
 
 		l1l2 = (unsigned char *) ((unsigned long) skb->data + skb->len - 6);
 
@@ -1190,14 +1190,15 @@
 		ATM_SKB(skb)->vcc = vcc;
 		__net_timestamp(skb);
 
+		truesize = skb->truesize;
 		vcc->push(vcc, skb);
 		atomic_inc(&vcc->stats->rx);
 
-		if (skb->truesize > SAR_FB_SIZE_3)
+		if (truesize > SAR_FB_SIZE_3)
 			add_rx_skb(card, 3, SAR_FB_SIZE_3, 1);
-		else if (skb->truesize > SAR_FB_SIZE_2)
+		else if (truesize > SAR_FB_SIZE_2)
 			add_rx_skb(card, 2, SAR_FB_SIZE_2, 1);
-		else if (skb->truesize > SAR_FB_SIZE_1)
+		else if (truesize > SAR_FB_SIZE_1)
 			add_rx_skb(card, 1, SAR_FB_SIZE_1, 1);
 		else
 			add_rx_skb(card, 0, SAR_FB_SIZE_0, 1);
@@ -3615,7 +3616,7 @@
 
 	if ((err = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)))) {
 		printk("idt77252: can't enable DMA for PCI device at %s\n", pci_name(pcidev));
-		return err;
+		goto err_out_disable_pdev;
 	}
 
 	card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
@@ -3777,6 +3778,7 @@
 		card = idt77252_chain;
 		dev = card->atmdev;
 		idt77252_chain = card->next;
+		del_timer_sync(&card->tst_timer);
 
 		if (dev->phy->stop)
 			dev->phy->stop(dev);
--- linux-4.4.0.orig/drivers/atm/iphase.c
+++ linux-4.4.0/drivers/atm/iphase.c
@@ -63,6 +63,7 @@
 #include <asm/byteorder.h>  
 #include <linux/vmalloc.h>
 #include <linux/jiffies.h>
+#include <linux/nospec.h>
 #include "iphase.h"		  
 #include "suni.h"		  
 #define swap_byte_order(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
@@ -2755,8 +2756,11 @@
    }
    if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT; 
    board = ia_cmds.status;
-   if ((board < 0) || (board > iadev_count))
-         board = 0;    
+
+	if ((board < 0) || (board > iadev_count))
+		board = 0;
+	board = array_index_nospec(board, iadev_count + 1);
+
    iadev = ia_dev[board];
    switch (ia_cmds.cmd) {
    case MEMDUMP:
--- linux-4.4.0.orig/drivers/atm/nicstar.c
+++ linux-4.4.0/drivers/atm/nicstar.c
@@ -1704,6 +1704,8 @@
 
 	if (push_scqe(card, vc, scq, &scqe, skb) != 0) {
 		atomic_inc(&vcc->stats->tx_err);
+		dma_unmap_single(&card->pcidev->dev, NS_PRV_DMA(skb), skb->len,
+				 DMA_TO_DEVICE);
 		dev_kfree_skb_any(skb);
 		return -EIO;
 	}
--- linux-4.4.0.orig/drivers/atm/zatm.c
+++ linux-4.4.0/drivers/atm/zatm.c
@@ -23,6 +23,7 @@
 #include <linux/bitops.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
+#include <linux/nospec.h>
 #include <asm/byteorder.h>
 #include <asm/string.h>
 #include <asm/io.h>
@@ -125,7 +126,7 @@
 #define zin_n(r) inl(zatm_dev->base+r*4)
 #define zin(r) inl(zatm_dev->base+uPD98401_##r*4)
 #define zout(v,r) outl(v,zatm_dev->base+uPD98401_##r*4)
-#define zwait while (zin(CMR) & uPD98401_BUSY)
+#define zwait() do {} while (zin(CMR) & uPD98401_BUSY)
 
 /* RX0, RX1, TX0, TX1 */
 static const int mbx_entries[NR_MBX] = { 1024,1024,1024,1024 };
@@ -139,7 +140,7 @@
 
 static void zpokel(struct zatm_dev *zatm_dev,u32 value,u32 addr)
 {
-	zwait;
+	zwait();
 	zout(value,CER);
 	zout(uPD98401_IND_ACC | uPD98401_IA_BALL |
 	    (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR);
@@ -148,10 +149,10 @@
 
 static u32 zpeekl(struct zatm_dev *zatm_dev,u32 addr)
 {
-	zwait;
+	zwait();
 	zout(uPD98401_IND_ACC | uPD98401_IA_BALL | uPD98401_IA_RW |
 	  (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR);
-	zwait;
+	zwait();
 	return zin(CER);
 }
 
@@ -240,7 +241,7 @@
 	}
 	if (first) {
 		spin_lock_irqsave(&zatm_dev->lock, flags);
-		zwait;
+		zwait();
 		zout(virt_to_bus(first),CER);
 		zout(uPD98401_ADD_BAT | (pool << uPD98401_POOL_SHIFT) | count,
 		    CMR);
@@ -507,9 +508,9 @@
 	}
 	if (zatm_vcc->pool < 0) return -EMSGSIZE;
 	spin_lock_irqsave(&zatm_dev->lock, flags);
-	zwait;
+	zwait();
 	zout(uPD98401_OPEN_CHAN,CMR);
-	zwait;
+	zwait();
 	DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER));
 	chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT;
 	spin_unlock_irqrestore(&zatm_dev->lock, flags);
@@ -570,21 +571,21 @@
 		pos = vcc->vci >> 1;
 		shift = (1-(vcc->vci & 1)) << 4;
 		zpokel(zatm_dev,zpeekl(zatm_dev,pos) & ~(0xffff << shift),pos);
-		zwait;
+		zwait();
 		zout(uPD98401_NOP,CMR);
-		zwait;
+		zwait();
 		zout(uPD98401_NOP,CMR);
 		spin_unlock_irqrestore(&zatm_dev->lock, flags);
 	}
 	spin_lock_irqsave(&zatm_dev->lock, flags);
-	zwait;
+	zwait();
 	zout(uPD98401_DEACT_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan <<
 	    uPD98401_CHAN_ADDR_SHIFT),CMR);
-	zwait;
+	zwait();
 	udelay(10); /* why oh why ... ? */
 	zout(uPD98401_CLOSE_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan <<
 	    uPD98401_CHAN_ADDR_SHIFT),CMR);
-	zwait;
+	zwait();
 	if (!(zin(CMR) & uPD98401_CHAN_ADDR))
 		printk(KERN_CRIT DEV_LABEL "(itf %d): can't close RX channel "
 		    "%d\n",vcc->dev->number,zatm_vcc->rx_chan);
@@ -697,7 +698,7 @@
 	skb_queue_tail(&zatm_vcc->tx_queue,skb);
 	DPRINTK("QRP=0x%08lx\n",zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+
 	  uPD98401_TXVC_QRP));
-	zwait;
+	zwait();
 	zout(uPD98401_TX_READY | (zatm_vcc->tx_chan <<
 	    uPD98401_CHAN_ADDR_SHIFT),CMR);
 	spin_unlock_irqrestore(&zatm_dev->lock, flags);
@@ -889,12 +890,12 @@
 	}
 	spin_lock_irqsave(&zatm_dev->lock, flags);
 #if 0
-	zwait;
+	zwait();
 	zout(uPD98401_DEACT_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR);
 #endif
-	zwait;
+	zwait();
 	zout(uPD98401_CLOSE_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR);
-	zwait;
+	zwait();
 	if (!(zin(CMR) & uPD98401_CHAN_ADDR))
 		printk(KERN_CRIT DEV_LABEL "(itf %d): can't close TX channel "
 		    "%d\n",vcc->dev->number,chan);
@@ -924,9 +925,9 @@
 	zatm_vcc->tx_chan = 0;
 	if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
 	spin_lock_irqsave(&zatm_dev->lock, flags);
-	zwait;
+	zwait();
 	zout(uPD98401_OPEN_CHAN,CMR);
-	zwait;
+	zwait();
 	DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER));
 	chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT;
 	spin_unlock_irqrestore(&zatm_dev->lock, flags);
@@ -1148,8 +1149,8 @@
 }
 
 
-static unsigned char eprom_try_esi(struct atm_dev *dev, unsigned short cmd,
-				   int offset, int swap)
+static int eprom_try_esi(struct atm_dev *dev, unsigned short cmd, int offset,
+			 int swap)
 {
 	unsigned char buf[ZEPROM_SIZE];
 	struct zatm_dev *zatm_dev;
@@ -1456,6 +1457,8 @@
 					return -EFAULT;
 				if (pool < 0 || pool > ZATM_LAST_POOL)
 					return -EINVAL;
+				pool = array_index_nospec(pool,
+							  ZATM_LAST_POOL + 1);
 				spin_lock_irqsave(&zatm_dev->lock, flags);
 				info = zatm_dev->pool_info[pool];
 				if (cmd == ZATM_GETPOOLZ) {
@@ -1478,6 +1481,8 @@
 					return -EFAULT;
 				if (pool < 0 || pool > ZATM_LAST_POOL)
 					return -EINVAL;
+				pool = array_index_nospec(pool,
+							  ZATM_LAST_POOL + 1);
 				if (copy_from_user(&info,
 				    &((struct zatm_pool_req __user *) arg)->info,
 				    sizeof(info))) return -EFAULT;
@@ -1552,7 +1557,7 @@
 	struct zatm_dev *zatm_dev;
 
 	zatm_dev = ZATM_DEV(dev);
-	zwait;
+	zwait();
 	zout(value,CER);
 	zout(uPD98401_IND_ACC | uPD98401_IA_B0 |
 	    (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR);
@@ -1564,10 +1569,10 @@
 	struct zatm_dev *zatm_dev;
 
 	zatm_dev = ZATM_DEV(dev);
-	zwait;
+	zwait();
 	zout(uPD98401_IND_ACC | uPD98401_IA_B0 | uPD98401_IA_RW |
 	  (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR);
-	zwait;
+	zwait();
 	return zin(CER) & 0xff;
 }
 
--- linux-4.4.0.orig/drivers/base/Kconfig
+++ linux-4.4.0/drivers/base/Kconfig
@@ -223,6 +223,9 @@
 config GENERIC_CPU_AUTOPROBE
 	bool
 
+config GENERIC_CPU_VULNERABILITIES
+	bool
+
 config SOC_BUS
 	bool
 
--- linux-4.4.0.orig/drivers/base/bus.c
+++ linux-4.4.0/drivers/base/bus.c
@@ -33,6 +33,9 @@
 
 #define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
 
+#define DRIVER_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \
+	struct driver_attribute driver_attr_##_name =		\
+		__ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store)
 
 static int __must_check bus_rescan_devices_helper(struct device *dev,
 						void *data);
@@ -198,7 +201,7 @@
 	bus_put(bus);
 	return err;
 }
-static DRIVER_ATTR_WO(unbind);
+static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, S_IWUSR, NULL, unbind_store);
 
 /*
  * Manually attach a device to a driver.
@@ -234,7 +237,7 @@
 	bus_put(bus);
 	return err;
 }
-static DRIVER_ATTR_WO(bind);
+static DRIVER_ATTR_IGNORE_LOCKDEP(bind, S_IWUSR, NULL, bind_store);
 
 static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
 {
@@ -737,7 +740,7 @@
 
 out_unregister:
 	kobject_put(&priv->kobj);
-	kfree(drv->p);
+	/* drv->p is freed in driver_release()  */
 	drv->p = NULL;
 out_put_bus:
 	bus_put(bus);
--- linux-4.4.0.orig/drivers/base/cacheinfo.c
+++ linux-4.4.0/drivers/base/cacheinfo.c
@@ -16,6 +16,7 @@
  * 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/acpi.h>
 #include <linux/bitops.h>
 #include <linux/cacheinfo.h>
 #include <linux/compiler.h>
@@ -104,9 +105,16 @@
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 	struct cacheinfo *this_leaf, *sib_leaf;
 	unsigned int index;
-	int ret;
+	int ret = 0;
+
+	if (this_cpu_ci->cpu_map_populated)
+		return 0;
 
-	ret = cache_setup_of_node(cpu);
+	if (of_have_populated_dt())
+		ret = cache_setup_of_node(cpu);
+	else if (!acpi_disabled)
+		/* No cache property/hierarchy support yet in ACPI */
+		ret = -ENOTSUPP;
 	if (ret)
 		return ret;
 
@@ -203,8 +211,7 @@
 	 */
 	ret = cache_shared_cpu_map_setup(cpu);
 	if (ret) {
-		pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n",
-			cpu);
+		pr_warn("Unable to detect cache hierarchy for CPU %d\n", cpu);
 		goto free_ci;
 	}
 	return 0;
--- linux-4.4.0.orig/drivers/base/core.c
+++ linux-4.4.0/drivers/base/core.c
@@ -10,6 +10,7 @@
  *
  */
 
+#include <linux/cpufreq.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/fwnode.h>
@@ -759,7 +760,7 @@
 
 	dir = kzalloc(sizeof(*dir), GFP_KERNEL);
 	if (!dir)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	dir->class = class;
 	kobject_init(&dir->kobj, &class_dir_ktype);
@@ -769,7 +770,7 @@
 	retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
 	if (retval < 0) {
 		kobject_put(&dir->kobj);
-		return NULL;
+		return ERR_PTR(retval);
 	}
 	return &dir->kobj;
 }
@@ -836,23 +837,89 @@
 	return NULL;
 }
 
+static inline bool live_in_glue_dir(struct kobject *kobj,
+				    struct device *dev)
+{
+	if (!kobj || !dev->class ||
+	    kobj->kset != &dev->class->p->glue_dirs)
+		return false;
+	return true;
+}
+
+static inline struct kobject *get_glue_dir(struct device *dev)
+{
+	return dev->kobj.parent;
+}
+
+/*
+ * make sure cleaning up dir as the last step, we need to make
+ * sure .release handler of kobject is run with holding the
+ * global lock
+ */
 static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
 {
+	unsigned int ref;
+
 	/* see if we live in a "glue" directory */
-	if (!glue_dir || !dev->class ||
-	    glue_dir->kset != &dev->class->p->glue_dirs)
+	if (!live_in_glue_dir(glue_dir, dev))
 		return;
 
 	mutex_lock(&gdp_mutex);
+	/**
+	 * There is a race condition between removing glue directory
+	 * and adding a new device under the glue directory.
+	 *
+	 * CPU1:                                         CPU2:
+	 *
+	 * device_add()
+	 *   get_device_parent()
+	 *     class_dir_create_and_add()
+	 *       kobject_add_internal()
+	 *         create_dir()    // create glue_dir
+	 *
+	 *                                               device_add()
+	 *                                                 get_device_parent()
+	 *                                                   kobject_get() // get glue_dir
+	 *
+	 * device_del()
+	 *   cleanup_glue_dir()
+	 *     kobject_del(glue_dir)
+	 *
+	 *                                               kobject_add()
+	 *                                                 kobject_add_internal()
+	 *                                                   create_dir() // in glue_dir
+	 *                                                     sysfs_create_dir_ns()
+	 *                                                       kernfs_create_dir_ns(sd)
+	 *
+	 *       sysfs_remove_dir() // glue_dir->sd=NULL
+	 *       sysfs_put()        // free glue_dir->sd
+	 *
+	 *                                                         // sd is freed
+	 *                                                         kernfs_new_node(sd)
+	 *                                                           kernfs_get(glue_dir)
+	 *                                                           kernfs_add_one()
+	 *                                                           kernfs_put()
+	 *
+	 * Before CPU1 remove last child device under glue dir, if CPU2 add
+	 * a new device under glue dir, the glue_dir kobject reference count
+	 * will be increase to 2 in kobject_get(k). And CPU2 has been called
+	 * kernfs_create_dir_ns(). Meanwhile, CPU1 call sysfs_remove_dir()
+	 * and sysfs_put(). This result in glue_dir->sd is freed.
+	 *
+	 * Then the CPU2 will see a stale "empty" but still potentially used
+	 * glue dir around in kernfs_new_node().
+	 *
+	 * In order to avoid this happening, we also should make sure that
+	 * kernfs_node for glue_dir is released in CPU1 only when refcount
+	 * for glue_dir kobj is 1.
+	 */
+	ref = atomic_read(&glue_dir->kref.refcount);
+	if (!kobject_has_children(glue_dir) && !--ref)
+		kobject_del(glue_dir);
 	kobject_put(glue_dir);
 	mutex_unlock(&gdp_mutex);
 }
 
-static void cleanup_device_parent(struct device *dev)
-{
-	cleanup_glue_dir(dev, dev->kobj.parent);
-}
-
 static int device_add_class_symlinks(struct device *dev)
 {
 	struct device_node *of_node = dev_of_node(dev);
@@ -1028,6 +1095,7 @@
 	struct kobject *kobj;
 	struct class_interface *class_intf;
 	int error = -EINVAL;
+	struct kobject *glue_dir = NULL;
 
 	dev = get_device(dev);
 	if (!dev)
@@ -1062,6 +1130,10 @@
 
 	parent = get_device(dev->parent);
 	kobj = get_device_parent(dev, parent);
+	if (IS_ERR(kobj)) {
+		error = PTR_ERR(kobj);
+		goto parent_error;
+	}
 	if (kobj)
 		dev->kobj.parent = kobj;
 
@@ -1072,8 +1144,10 @@
 	/* first, register with generic layer. */
 	/* we require the name to be set before, and pass NULL */
 	error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
-	if (error)
+	if (error) {
+		glue_dir = get_glue_dir(dev);
 		goto Error;
+	}
 
 	/* notify platform of device entry */
 	if (platform_notify)
@@ -1154,9 +1228,11 @@
 	device_remove_file(dev, &dev_attr_uevent);
  attrError:
 	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
+	glue_dir = get_glue_dir(dev);
 	kobject_del(&dev->kobj);
  Error:
-	cleanup_device_parent(dev);
+	cleanup_glue_dir(dev, glue_dir);
+parent_error:
 	put_device(parent);
 name_error:
 	kfree(dev->p);
@@ -1232,6 +1308,7 @@
 void device_del(struct device *dev)
 {
 	struct device *parent = dev->parent;
+	struct kobject *glue_dir = NULL;
 	struct class_interface *class_intf;
 
 	/* Notify clients of device removal.  This call must come
@@ -1276,8 +1353,9 @@
 		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 					     BUS_NOTIFY_REMOVED_DEVICE, dev);
 	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
-	cleanup_device_parent(dev);
+	glue_dir = get_glue_dir(dev);
 	kobject_del(&dev->kobj);
+	cleanup_glue_dir(dev, glue_dir);
 	put_device(parent);
 }
 EXPORT_SYMBOL_GPL(device_del);
@@ -1971,6 +2049,11 @@
 	device_pm_lock();
 	new_parent = get_device(new_parent);
 	new_parent_kobj = get_device_parent(dev, new_parent);
+	if (IS_ERR(new_parent_kobj)) {
+		error = PTR_ERR(new_parent_kobj);
+		put_device(new_parent);
+		goto out;
+	}
 
 	pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev),
 		 __func__, new_parent ? dev_name(new_parent) : "<NULL>");
@@ -2042,6 +2125,8 @@
 {
 	struct device *dev, *parent;
 
+	cpufreq_suspend();
+
 	spin_lock(&devices_kset->list_lock);
 	/*
 	 * Walk the devices list backward, shutting down each in turn.
@@ -2075,7 +2160,11 @@
 		pm_runtime_get_noresume(dev);
 		pm_runtime_barrier(dev);
 
-		if (dev->bus && dev->bus->shutdown) {
+		if (dev->class && dev->class->shutdown) {
+			if (initcall_debug)
+				dev_info(dev, "shutdown\n");
+			dev->class->shutdown(dev);
+		} else if (dev->bus && dev->bus->shutdown) {
 			if (initcall_debug)
 				dev_info(dev, "shutdown\n");
 			dev->bus->shutdown(dev);
@@ -2255,17 +2344,26 @@
  */
 void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
 {
-	if (fwnode) {
-		struct fwnode_handle *fn = dev->fwnode;
+	struct device *parent = dev->parent;
+	struct fwnode_handle *fn = dev->fwnode;
 
+	if (fwnode) {
 		if (fwnode_is_primary(fn))
 			fn = fn->secondary;
 
-		fwnode->secondary = fn;
+		if (fn) {
+			WARN_ON(fwnode->secondary);
+			fwnode->secondary = fn;
+		}
 		dev->fwnode = fwnode;
 	} else {
-		dev->fwnode = fwnode_is_primary(dev->fwnode) ?
-			dev->fwnode->secondary : NULL;
+		if (fwnode_is_primary(fn)) {
+			dev->fwnode = fn->secondary;
+			if (!(parent && fn == parent->fwnode))
+				fn->secondary = NULL;
+		} else {
+			dev->fwnode = NULL;
+		}
 	}
 }
 EXPORT_SYMBOL_GPL(set_primary_fwnode);
--- linux-4.4.0.orig/drivers/base/cpu.c
+++ linux-4.4.0/drivers/base/cpu.c
@@ -498,10 +498,139 @@
 #endif
 }
 
+#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES
+
+ssize_t __weak cpu_show_meltdown(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_spectre_v1(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_spectre_v2(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_spec_store_bypass(struct device *dev,
+					  struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_l1tf(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_mds(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_tsx_async_abort(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_itlb_multihit(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_srbds(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_mmio_stale_data(struct device *dev,
+					struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_retbleed(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_gds(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_vmscape(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "Not affected\n");
+}
+
+static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
+static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
+static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
+static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL);
+static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL);
+static DEVICE_ATTR(mds, 0444, cpu_show_mds, NULL);
+static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL);
+static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL);
+static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL);
+static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
+static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
+static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL);
+static DEVICE_ATTR(vmscape, 0444, cpu_show_vmscape, NULL);
+
+static struct attribute *cpu_root_vulnerabilities_attrs[] = {
+	&dev_attr_meltdown.attr,
+	&dev_attr_spectre_v1.attr,
+	&dev_attr_spectre_v2.attr,
+	&dev_attr_spec_store_bypass.attr,
+	&dev_attr_l1tf.attr,
+	&dev_attr_mds.attr,
+	&dev_attr_tsx_async_abort.attr,
+	&dev_attr_itlb_multihit.attr,
+	&dev_attr_srbds.attr,
+	&dev_attr_mmio_stale_data.attr,
+	&dev_attr_retbleed.attr,
+	&dev_attr_gather_data_sampling.attr,
+	&dev_attr_vmscape.attr,
+	NULL
+};
+
+static const struct attribute_group cpu_root_vulnerabilities_group = {
+	.name  = "vulnerabilities",
+	.attrs = cpu_root_vulnerabilities_attrs,
+};
+
+static void __init cpu_register_vulnerabilities(void)
+{
+	if (sysfs_create_group(&cpu_subsys.dev_root->kobj,
+			       &cpu_root_vulnerabilities_group))
+		pr_err("Unable to register CPU vulnerabilities\n");
+}
+
+#else
+static inline void cpu_register_vulnerabilities(void) { }
+#endif
+
 void __init cpu_dev_init(void)
 {
 	if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))
 		panic("Failed to register CPU subsystem");
 
 	cpu_dev_register_generic();
+	cpu_register_vulnerabilities();
 }
--- linux-4.4.0.orig/drivers/base/dd.c
+++ linux-4.4.0/drivers/base/dd.c
@@ -283,7 +283,11 @@
 	atomic_inc(&probe_count);
 	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
 		 drv->bus->name, __func__, drv->name, dev_name(dev));
-	WARN_ON(!list_empty(&dev->devres_head));
+	if (!list_empty(&dev->devres_head)) {
+		dev_crit(dev, "Resources present before probing\n");
+		ret = -EBUSY;
+		goto done;
+	}
 
 	dev->driver = drv;
 
@@ -304,14 +308,6 @@
 			goto probe_failed;
 	}
 
-	/*
-	 * Ensure devices are listed in devices_kset in correct order
-	 * It's important to move Dev to the end of devices_kset before
-	 * calling .probe, because it could be recursive and parent Dev
-	 * should always go first
-	 */
-	devices_kset_move_last(dev);
-
 	if (dev->bus->probe) {
 		ret = dev->bus->probe(dev);
 		if (ret)
@@ -368,7 +364,7 @@
 	ret = 0;
 done:
 	atomic_dec(&probe_count);
-	wake_up(&probe_waitqueue);
+	wake_up_all(&probe_waitqueue);
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/base/dma-mapping.c
+++ linux-4.4.0/drivers/base/dma-mapping.c
@@ -102,9 +102,9 @@
 {
 	struct dma_devres match_data = { size, vaddr, dma_handle };
 
-	dma_free_coherent(dev, size, vaddr, dma_handle);
 	WARN_ON(devres_destroy(dev, dmam_coherent_release, dmam_match,
 			       &match_data));
+	dma_free_coherent(dev, size, vaddr, dma_handle);
 }
 EXPORT_SYMBOL(dmam_free_coherent);
 
@@ -335,7 +335,7 @@
 		return;
 	}
 
-	unmap_kernel_range((unsigned long)cpu_addr, size);
+	unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
 	vunmap(cpu_addr);
 }
 #endif
--- linux-4.4.0.orig/drivers/base/firmware_class.c
+++ linux-4.4.0/drivers/base/firmware_class.c
@@ -942,13 +942,14 @@
 		timeout = MAX_JIFFY_OFFSET;
 	}
 
-	retval = wait_for_completion_interruptible_timeout(&buf->completion,
+	timeout = wait_for_completion_interruptible_timeout(&buf->completion,
 			timeout);
-	if (retval == -ERESTARTSYS || !retval) {
+	if (timeout == -ERESTARTSYS || !timeout) {
+		retval = timeout;
 		mutex_lock(&fw_lock);
 		fw_load_abort(fw_priv);
 		mutex_unlock(&fw_lock);
-	} else if (retval > 0) {
+	} else if (timeout > 0) {
 		retval = 0;
 	}
 
@@ -1118,15 +1119,17 @@
 _request_firmware(const struct firmware **firmware_p, const char *name,
 		  struct device *device, unsigned int opt_flags)
 {
-	struct firmware *fw;
+	struct firmware *fw = NULL;
 	long timeout;
 	int ret;
 
 	if (!firmware_p)
 		return -EINVAL;
 
-	if (!name || name[0] == '\0')
-		return -EINVAL;
+	if (!name || name[0] == '\0') {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	ret = _request_firmware_prepare(&fw, name, device);
 	if (ret <= 0) /* error or already assigned */
--- linux-4.4.0.orig/drivers/base/isa.c
+++ linux-4.4.0/drivers/base/isa.c
@@ -39,7 +39,7 @@
 {
 	struct isa_driver *isa_driver = dev->platform_data;
 
-	if (isa_driver->probe)
+	if (isa_driver && isa_driver->probe)
 		return isa_driver->probe(dev, to_isa_dev(dev)->id);
 
 	return 0;
@@ -49,7 +49,7 @@
 {
 	struct isa_driver *isa_driver = dev->platform_data;
 
-	if (isa_driver->remove)
+	if (isa_driver && isa_driver->remove)
 		return isa_driver->remove(dev, to_isa_dev(dev)->id);
 
 	return 0;
@@ -59,7 +59,7 @@
 {
 	struct isa_driver *isa_driver = dev->platform_data;
 
-	if (isa_driver->shutdown)
+	if (isa_driver && isa_driver->shutdown)
 		isa_driver->shutdown(dev, to_isa_dev(dev)->id);
 }
 
@@ -67,7 +67,7 @@
 {
 	struct isa_driver *isa_driver = dev->platform_data;
 
-	if (isa_driver->suspend)
+	if (isa_driver && isa_driver->suspend)
 		return isa_driver->suspend(dev, to_isa_dev(dev)->id, state);
 
 	return 0;
@@ -77,7 +77,7 @@
 {
 	struct isa_driver *isa_driver = dev->platform_data;
 
-	if (isa_driver->resume)
+	if (isa_driver && isa_driver->resume)
 		return isa_driver->resume(dev, to_isa_dev(dev)->id);
 
 	return 0;
@@ -180,4 +180,4 @@
 	return error;
 }
 
-device_initcall(isa_bus_init);
+postcore_initcall(isa_bus_init);
--- linux-4.4.0.orig/drivers/base/memory.c
+++ linux-4.4.0/drivers/base/memory.c
@@ -251,7 +251,7 @@
 	return ret;
 }
 
-static int memory_block_change_state(struct memory_block *mem,
+int memory_block_change_state(struct memory_block *mem,
 		unsigned long to_state, unsigned long from_state_req)
 {
 	int ret = 0;
@@ -388,30 +388,29 @@
 {
 	struct memory_block *mem = to_memory_block(dev);
 	unsigned long start_pfn, end_pfn;
+	unsigned long valid_start, valid_end;
 	unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
-	struct page *first_page;
 	struct zone *zone;
 
 	start_pfn = section_nr_to_pfn(mem->start_section_nr);
 	end_pfn = start_pfn + nr_pages;
-	first_page = pfn_to_page(start_pfn);
 
 	/* The block contains more than one zone can not be offlined. */
-	if (!test_pages_in_a_zone(start_pfn, end_pfn))
+	if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end))
 		return sprintf(buf, "none\n");
 
-	zone = page_zone(first_page);
+	zone = page_zone(pfn_to_page(valid_start));
 
 	if (zone_idx(zone) == ZONE_MOVABLE - 1) {
 		/*The mem block is the last memoryblock of this zone.*/
-		if (end_pfn == zone_end_pfn(zone))
+		if (valid_end == zone_end_pfn(zone))
 			return sprintf(buf, "%s %s\n",
 					zone->name, (zone + 1)->name);
 	}
 
 	if (zone_idx(zone) == ZONE_MOVABLE) {
 		/*The mem block is the first memoryblock of ZONE_MOVABLE.*/
-		if (start_pfn == zone->zone_start_pfn)
+		if (valid_start == zone->zone_start_pfn)
 			return sprintf(buf, "%s %s\n",
 					zone->name, (zone - 1)->name);
 	}
@@ -439,6 +438,37 @@
 static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL);
 
 /*
+ * Memory auto online policy.
+ */
+
+static ssize_t
+show_auto_online_blocks(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	if (memhp_auto_online)
+		return sprintf(buf, "online\n");
+	else
+		return sprintf(buf, "offline\n");
+}
+
+static ssize_t
+store_auto_online_blocks(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	if (sysfs_streq(buf, "online"))
+		memhp_auto_online = true;
+	else if (sysfs_streq(buf, "offline"))
+		memhp_auto_online = false;
+	else
+		return -EINVAL;
+
+	return count;
+}
+
+static DEVICE_ATTR(auto_online_blocks, 0644, show_auto_online_blocks,
+		   store_auto_online_blocks);
+
+/*
  * Some architectures will have custom drivers to do this, and
  * will not need to do it from userspace.  The fake hot-add code
  * as well as ppc64 will do all of their discovery in userspace
@@ -737,6 +767,7 @@
 #endif
 
 	&dev_attr_block_size_bytes.attr,
+	&dev_attr_auto_online_blocks.attr,
 	NULL
 };
 
--- linux-4.4.0.orig/drivers/base/module.c
+++ linux-4.4.0/drivers/base/module.c
@@ -24,10 +24,12 @@
 
 static void module_create_drivers_dir(struct module_kobject *mk)
 {
-	if (!mk || mk->drivers_dir)
-		return;
+	static DEFINE_MUTEX(drivers_dir_mutex);
 
-	mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj);
+	mutex_lock(&drivers_dir_mutex);
+	if (mk && !mk->drivers_dir)
+		mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj);
+	mutex_unlock(&drivers_dir_mutex);
 }
 
 void module_add_driver(struct module *mod, struct device_driver *drv)
--- linux-4.4.0.orig/drivers/base/platform.c
+++ linux-4.4.0/drivers/base/platform.c
@@ -26,6 +26,7 @@
 #include <linux/acpi.h>
 #include <linux/clk/clk-conf.h>
 #include <linux/limits.h>
+#include <linux/property.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -96,7 +97,7 @@
 		int ret;
 
 		ret = of_irq_get(dev->dev.of_node, num);
-		if (ret >= 0 || ret == -EPROBE_DEFER)
+		if (ret > 0 || ret == -EPROBE_DEFER)
 			return ret;
 	}
 
@@ -154,7 +155,7 @@
 		int ret;
 
 		ret = of_irq_get_byname(dev->dev.of_node, name);
-		if (ret >= 0 || ret == -EPROBE_DEFER)
+		if (ret > 0 || ret == -EPROBE_DEFER)
 			return ret;
 	}
 
@@ -299,6 +300,22 @@
 EXPORT_SYMBOL_GPL(platform_device_add_data);
 
 /**
+ * platform_device_add_properties - add built-in properties to a platform device
+ * @pdev: platform device to add properties to
+ * @pset: properties to add
+ *
+ * The function will take deep copy of the properties in @pset and attach
+ * the copy to the platform device. The memory associated with properties
+ * will be freed when the platform device is released.
+ */
+int platform_device_add_properties(struct platform_device *pdev,
+				   const struct property_set *pset)
+{
+	return device_add_property_set(&pdev->dev, pset);
+}
+EXPORT_SYMBOL_GPL(platform_device_add_properties);
+
+/**
  * platform_device_add - add a platform device to device hierarchy
  * @pdev: platform device we're adding
  *
@@ -409,6 +426,8 @@
 			if (r->parent)
 				release_resource(r);
 		}
+
+		device_remove_property_set(&pdev->dev);
 	}
 }
 EXPORT_SYMBOL_GPL(platform_device_del);
@@ -487,6 +506,12 @@
 	if (ret)
 		goto err;
 
+	if (pdevinfo->pset) {
+		ret = platform_device_add_properties(pdev, pdevinfo->pset);
+		if (ret)
+			goto err;
+	}
+
 	ret = platform_device_add(pdev);
 	if (ret) {
 err:
@@ -513,10 +538,15 @@
 		return ret;
 
 	ret = dev_pm_domain_attach(_dev, true);
-	if (ret != -EPROBE_DEFER && drv->probe) {
-		ret = drv->probe(dev);
-		if (ret)
-			dev_pm_domain_detach(_dev, true);
+	if (ret != -EPROBE_DEFER) {
+		if (drv->probe) {
+			ret = drv->probe(dev);
+			if (ret)
+				dev_pm_domain_detach(_dev, true);
+		} else {
+			/* don't fail if just dev_pm_domain_attach failed */
+			ret = 0;
+		}
 	}
 
 	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
@@ -633,6 +663,8 @@
 	/* temporary section violation during probe() */
 	drv->probe = probe;
 	retval = code = __platform_driver_register(drv, module);
+	if (retval)
+		return retval;
 
 	/*
 	 * Fixup that section violation, being paranoid about code scanning
@@ -802,9 +834,10 @@
 				     const char *buf, size_t count)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	char *driver_override, *old = pdev->driver_override, *cp;
+	char *driver_override, *old, *cp;
 
-	if (count > PATH_MAX)
+	/* We need to keep extra room for a newline */
+	if (count >= (PAGE_SIZE - 1))
 		return -EINVAL;
 
 	driver_override = kstrndup(buf, count, GFP_KERNEL);
@@ -815,12 +848,15 @@
 	if (cp)
 		*cp = '\0';
 
+	device_lock(dev);
+	old = pdev->driver_override;
 	if (strlen(driver_override)) {
 		pdev->driver_override = driver_override;
 	} else {
 		kfree(driver_override);
 		pdev->driver_override = NULL;
 	}
+	device_unlock(dev);
 
 	kfree(old);
 
@@ -831,8 +867,12 @@
 				    struct device_attribute *attr, char *buf)
 {
 	struct platform_device *pdev = to_platform_device(dev);
+	ssize_t len;
 
-	return sprintf(buf, "%s\n", pdev->driver_override);
+	device_lock(dev);
+	len = sprintf(buf, "%s\n", pdev->driver_override);
+	device_unlock(dev);
+	return len;
 }
 static DEVICE_ATTR_RW(driver_override);
 
--- linux-4.4.0.orig/drivers/base/power/domain.c
+++ linux-4.4.0/drivers/base/power/domain.c
@@ -1188,7 +1188,6 @@
 	}
 
 	dev->power.subsys_data->domain_data = &gpd_data->base;
-	dev->pm_domain = &genpd->domain;
 
 	spin_unlock_irq(&dev->power.lock);
 
@@ -1207,7 +1206,6 @@
 {
 	spin_lock_irq(&dev->power.lock);
 
-	dev->pm_domain = NULL;
 	dev->power.subsys_data->domain_data = NULL;
 
 	spin_unlock_irq(&dev->power.lock);
@@ -1248,6 +1246,8 @@
 	if (ret)
 		goto out;
 
+	dev->pm_domain = &genpd->domain;
+
 	genpd->device_count++;
 	genpd->max_off_time_changed = true;
 
@@ -1299,6 +1299,8 @@
 	if (genpd->detach_dev)
 		genpd->detach_dev(genpd, dev);
 
+	dev->pm_domain = NULL;
+
 	list_del_init(&pdd->list_node);
 
 	mutex_unlock(&genpd->lock);
@@ -1373,7 +1375,7 @@
 int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 			      struct generic_pm_domain *subdomain)
 {
-	struct gpd_link *link;
+	struct gpd_link *l, *link;
 	int ret = -EINVAL;
 
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
@@ -1381,14 +1383,14 @@
 
 	mutex_lock(&genpd->lock);
 
-	if (!list_empty(&subdomain->slave_links) || subdomain->device_count) {
+	if (!list_empty(&subdomain->master_links) || subdomain->device_count) {
 		pr_warn("%s: unable to remove subdomain %s\n", genpd->name,
 			subdomain->name);
 		ret = -EBUSY;
 		goto out;
 	}
 
-	list_for_each_entry(link, &genpd->master_links, master_node) {
+	list_for_each_entry_safe(link, l, &genpd->master_links, master_node) {
 		if (link->slave != subdomain)
 			continue;
 
@@ -1642,10 +1644,10 @@
  */
 void of_genpd_del_provider(struct device_node *np)
 {
-	struct of_genpd_provider *cp;
+	struct of_genpd_provider *cp, *tmp;
 
 	mutex_lock(&of_genpd_mutex);
-	list_for_each_entry(cp, &of_genpd_providers, link) {
+	list_for_each_entry_safe(cp, tmp, &of_genpd_providers, link) {
 		if (cp->node == np) {
 			list_del(&cp->link);
 			of_node_put(cp->node);
--- linux-4.4.0.orig/drivers/base/power/main.c
+++ linux-4.4.0/drivers/base/power/main.c
@@ -1022,6 +1022,8 @@
 	TRACE_DEVICE(dev);
 	TRACE_SUSPEND(0);
 
+	dpm_wait_for_children(dev, async);
+
 	if (async_error)
 		goto Complete;
 
@@ -1033,8 +1035,6 @@
 	if (dev->power.syscore || dev->power.direct_complete)
 		goto Complete;
 
-	dpm_wait_for_children(dev, async);
-
 	if (dev->pm_domain) {
 		info = "noirq power domain ";
 		callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -1169,6 +1169,8 @@
 
 	__pm_runtime_disable(dev, false);
 
+	dpm_wait_for_children(dev, async);
+
 	if (async_error)
 		goto Complete;
 
@@ -1180,8 +1182,6 @@
 	if (dev->power.syscore || dev->power.direct_complete)
 		goto Complete;
 
-	dpm_wait_for_children(dev, async);
-
 	if (dev->pm_domain) {
 		info = "late power domain ";
 		callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -1262,14 +1262,15 @@
 		error = device_suspend_late(dev);
 
 		mutex_lock(&dpm_list_mtx);
+		if (!list_empty(&dev->power.entry))
+			list_move(&dev->power.entry, &dpm_late_early_list);
+
 		if (error) {
 			pm_dev_err(dev, state, " late", error);
 			dpm_save_failed_dev(dev_name(dev));
 			put_device(dev);
 			break;
 		}
-		if (!list_empty(&dev->power.entry))
-			list_move(&dev->power.entry, &dpm_late_early_list);
 		put_device(dev);
 
 		if (async_error)
@@ -1354,19 +1355,26 @@
 
 	dpm_wait_for_children(dev, async);
 
-	if (async_error)
+	if (async_error) {
+		dev->power.direct_complete = false;
 		goto Complete;
+	}
 
 	/*
-	 * If a device configured to wake up the system from sleep states
-	 * has been suspended at run time and there's a resume request pending
-	 * for it, this is equivalent to the device signaling wakeup, so the
-	 * system suspend operation should be aborted.
+	 * Wait for possible runtime PM transitions of the device in progress
+	 * to complete and if there's a runtime resume request pending for it,
+	 * resume it before proceeding with invoking the system-wide suspend
+	 * callbacks for it.
+	 *
+	 * If the system-wide suspend callbacks below change the configuration
+	 * of the device, they must disable runtime PM for it or otherwise
+	 * ensure that its runtime-resume callbacks will not be confused by that
+	 * change in case they are invoked going forward.
 	 */
-	if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
-		pm_wakeup_event(dev, 0);
+	pm_runtime_barrier(dev);
 
 	if (pm_wakeup_pending()) {
+		dev->power.direct_complete = false;
 		async_error = -EBUSY;
 		goto Complete;
 	}
@@ -1374,6 +1382,10 @@
 	if (dev->power.syscore)
 		goto Complete;
 
+	/* Avoid direct_complete to let wakeup_path propagate. */
+	if (device_may_wakeup(dev) || dev->power.wakeup_path)
+		dev->power.direct_complete = false;
+
 	if (dev->power.direct_complete) {
 		if (pm_runtime_status_suspended(dev)) {
 			pm_runtime_disable(dev);
--- linux-4.4.0.orig/drivers/base/power/opp/core.c
+++ linux-4.4.0/drivers/base/power/opp/core.c
@@ -809,8 +809,14 @@
 	}
 
 	opp->u_volt = microvolt[0];
-	opp->u_volt_min = microvolt[1];
-	opp->u_volt_max = microvolt[2];
+
+	if (count == 1) {
+		opp->u_volt_min = opp->u_volt;
+		opp->u_volt_max = opp->u_volt;
+	} else {
+		opp->u_volt_min = microvolt[1];
+		opp->u_volt_max = microvolt[2];
+	}
 
 	if (!of_property_read_u32(opp->np, "opp-microamp", &val))
 		opp->u_amp = val;
@@ -1199,6 +1205,7 @@
 		if (ret) {
 			dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
 				ret);
+			of_node_put(np);
 			goto free_table;
 		}
 	}
--- linux-4.4.0.orig/drivers/base/power/power.h
+++ linux-4.4.0/drivers/base/power/power.h
@@ -20,14 +20,22 @@
 extern void pm_runtime_init(struct device *dev);
 extern void pm_runtime_remove(struct device *dev);
 
+#define WAKE_IRQ_DEDICATED_ALLOCATED	BIT(0)
+#define WAKE_IRQ_DEDICATED_MANAGED	BIT(1)
+#define WAKE_IRQ_DEDICATED_MASK		(WAKE_IRQ_DEDICATED_ALLOCATED | \
+					 WAKE_IRQ_DEDICATED_MANAGED)
+
 struct wake_irq {
 	struct device *dev;
+	unsigned int status;
 	int irq;
-	bool dedicated_irq:1;
 };
 
 extern void dev_pm_arm_wake_irq(struct wake_irq *wirq);
 extern void dev_pm_disarm_wake_irq(struct wake_irq *wirq);
+extern void dev_pm_enable_wake_irq_check(struct device *dev,
+					 bool can_change_status);
+extern void dev_pm_disable_wake_irq_check(struct device *dev);
 
 #ifdef CONFIG_PM_SLEEP
 
@@ -102,6 +110,15 @@
 {
 }
 
+static inline void dev_pm_enable_wake_irq_check(struct device *dev,
+						bool can_change_status)
+{
+}
+
+static inline void dev_pm_disable_wake_irq_check(struct device *dev)
+{
+}
+
 #endif
 
 #ifdef CONFIG_PM_SLEEP
--- linux-4.4.0.orig/drivers/base/power/qos.c
+++ linux-4.4.0/drivers/base/power/qos.c
@@ -883,6 +883,7 @@
 	mutex_unlock(&dev_pm_qos_mtx);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(dev_pm_qos_update_user_latency_tolerance);
 
 /**
  * dev_pm_qos_expose_latency_tolerance - Expose latency tolerance to userspace
--- linux-4.4.0.orig/drivers/base/power/runtime.c
+++ linux-4.4.0/drivers/base/power/runtime.c
@@ -515,7 +515,7 @@
 
 	callback = RPM_GET_CALLBACK(dev, runtime_suspend);
 
-	dev_pm_enable_wake_irq(dev);
+	dev_pm_enable_wake_irq_check(dev, true);
 	retval = rpm_callback(callback, dev);
 	if (retval)
 		goto fail;
@@ -554,7 +554,7 @@
 	return retval;
 
  fail:
-	dev_pm_disable_wake_irq(dev);
+	dev_pm_disable_wake_irq_check(dev);
 	__update_runtime_status(dev, RPM_ACTIVE);
 	dev->power.deferred_resume = false;
 	wake_up_all(&dev->power.wait_queue);
@@ -737,12 +737,12 @@
 
 	callback = RPM_GET_CALLBACK(dev, runtime_resume);
 
-	dev_pm_disable_wake_irq(dev);
+	dev_pm_disable_wake_irq_check(dev);
 	retval = rpm_callback(callback, dev);
 	if (retval) {
 		__update_runtime_status(dev, RPM_SUSPENDED);
 		pm_runtime_cancel_pending(dev);
-		dev_pm_enable_wake_irq(dev);
+		dev_pm_enable_wake_irq_check(dev, false);
 	} else {
  no_callback:
 		__update_runtime_status(dev, RPM_ACTIVE);
@@ -889,13 +889,13 @@
 	unsigned long flags;
 	int retval;
 
-	might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
-
 	if (rpmflags & RPM_GET_PUT) {
 		if (!atomic_dec_and_test(&dev->power.usage_count))
 			return 0;
 	}
 
+	might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
 	spin_lock_irqsave(&dev->power.lock, flags);
 	retval = rpm_idle(dev, rpmflags);
 	spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -921,13 +921,13 @@
 	unsigned long flags;
 	int retval;
 
-	might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
-
 	if (rpmflags & RPM_GET_PUT) {
 		if (!atomic_dec_and_test(&dev->power.usage_count))
 			return 0;
 	}
 
+	might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
 	spin_lock_irqsave(&dev->power.lock, flags);
 	retval = rpm_suspend(dev, rpmflags);
 	spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -952,7 +952,8 @@
 	unsigned long flags;
 	int retval;
 
-	might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+	might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe &&
+			dev->power.runtime_status != RPM_ACTIVE);
 
 	if (rpmflags & RPM_GET_PUT)
 		atomic_inc(&dev->power.usage_count);
@@ -966,6 +967,30 @@
 EXPORT_SYMBOL_GPL(__pm_runtime_resume);
 
 /**
+ * pm_runtime_get_if_in_use - Conditionally bump up the device's usage counter.
+ * @dev: Device to handle.
+ *
+ * Return -EINVAL if runtime PM is disabled for the device.
+ *
+ * If that's not the case and if the device's runtime PM status is RPM_ACTIVE
+ * and the runtime PM usage counter is nonzero, increment the counter and
+ * return 1.  Otherwise return 0 without changing the counter.
+ */
+int pm_runtime_get_if_in_use(struct device *dev)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&dev->power.lock, flags);
+	retval = dev->power.disable_depth > 0 ? -EINVAL :
+		dev->power.runtime_status == RPM_ACTIVE
+			&& atomic_inc_not_zero(&dev->power.usage_count);
+	spin_unlock_irqrestore(&dev->power.lock, flags);
+	return retval;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
+
+/**
  * __pm_runtime_set_status - Set runtime PM status of a device.
  * @dev: Device to handle.
  * @status: New runtime PM status of the device.
@@ -1468,11 +1493,16 @@
 		goto out;
 	}
 
-	ret = callback(dev);
+	ret = pm_runtime_set_active(dev);
 	if (ret)
 		goto out;
 
-	pm_runtime_set_active(dev);
+	ret = callback(dev);
+	if (ret) {
+		pm_runtime_set_suspended(dev);
+		goto out;
+	}
+
 	pm_runtime_mark_last_busy(dev);
 out:
 	pm_runtime_enable(dev);
--- linux-4.4.0.orig/drivers/base/power/sysfs.c
+++ linux-4.4.0/drivers/base/power/sysfs.c
@@ -268,6 +268,8 @@
 			value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
 		else if (!strcmp(buf, "any") || !strcmp(buf, "any\n"))
 			value = PM_QOS_LATENCY_ANY;
+		else
+			return -EINVAL;
 	}
 	ret = dev_pm_qos_update_user_latency_tolerance(dev, value);
 	return ret < 0 ? ret : n;
--- linux-4.4.0.orig/drivers/base/power/trace.c
+++ linux-4.4.0/drivers/base/power/trace.c
@@ -166,14 +166,14 @@
 }
 EXPORT_SYMBOL(generate_pm_trace);
 
-extern char __tracedata_start, __tracedata_end;
+extern char __tracedata_start[], __tracedata_end[];
 static int show_file_hash(unsigned int value)
 {
 	int match;
 	char *tracedata;
 
 	match = 0;
-	for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ;
+	for (tracedata = __tracedata_start ; tracedata < __tracedata_end ;
 			tracedata += 2 + sizeof(unsigned long)) {
 		unsigned short lineno = *(unsigned short *)tracedata;
 		const char *file = *(const char **)(tracedata + 2);
--- linux-4.4.0.orig/drivers/base/power/wakeirq.c
+++ linux-4.4.0/drivers/base/power/wakeirq.c
@@ -110,8 +110,10 @@
 	dev->power.wakeirq = NULL;
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
-	if (wirq->dedicated_irq)
+	if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) {
 		free_irq(wirq->irq, wirq);
+		wirq->status &= ~WAKE_IRQ_DEDICATED_MASK;
+	}
 	kfree(wirq);
 }
 EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
@@ -139,6 +141,13 @@
 	struct wake_irq *wirq = _wirq;
 	int res;
 
+	/* Maybe abort suspend? */
+	if (irqd_is_wakeup_set(irq_get_irq_data(irq))) {
+		pm_wakeup_event(wirq->dev, 0);
+
+		return IRQ_HANDLED;
+	}
+
 	/* We don't want RPM_ASYNC or RPM_NOWAIT here */
 	res = pm_runtime_resume(wirq->dev);
 	if (res < 0)
@@ -179,7 +188,6 @@
 
 	wirq->dev = dev;
 	wirq->irq = irq;
-	wirq->dedicated_irq = true;
 	irq_set_status_flags(irq, IRQ_NOAUTOEN);
 
 	/*
@@ -195,6 +203,8 @@
 	if (err)
 		goto err_free_irq;
 
+	wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED;
+
 	return err;
 
 err_free_irq:
@@ -210,9 +220,9 @@
  * dev_pm_enable_wake_irq - Enable device wake-up interrupt
  * @dev: Device
  *
- * Called from the bus code or the device driver for
- * runtime_suspend() to enable the wake-up interrupt while
- * the device is running.
+ * Optionally called from the bus code or the device driver for
+ * runtime_resume() to override the PM runtime core managed wake-up
+ * interrupt handling to enable the wake-up interrupt.
  *
  * Note that for runtime_suspend()) the wake-up interrupts
  * should be unconditionally enabled unlike for suspend()
@@ -222,7 +232,7 @@
 {
 	struct wake_irq *wirq = dev->power.wakeirq;
 
-	if (wirq && wirq->dedicated_irq)
+	if (wirq && (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED))
 		enable_irq(wirq->irq);
 }
 EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
@@ -231,20 +241,73 @@
  * dev_pm_disable_wake_irq - Disable device wake-up interrupt
  * @dev: Device
  *
- * Called from the bus code or the device driver for
- * runtime_resume() to disable the wake-up interrupt while
- * the device is running.
+ * Optionally called from the bus code or the device driver for
+ * runtime_suspend() to override the PM runtime core managed wake-up
+ * interrupt handling to disable the wake-up interrupt.
  */
 void dev_pm_disable_wake_irq(struct device *dev)
 {
 	struct wake_irq *wirq = dev->power.wakeirq;
 
-	if (wirq && wirq->dedicated_irq)
+	if (wirq && (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED))
 		disable_irq_nosync(wirq->irq);
 }
 EXPORT_SYMBOL_GPL(dev_pm_disable_wake_irq);
 
 /**
+ * dev_pm_enable_wake_irq_check - Checks and enables wake-up interrupt
+ * @dev: Device
+ * @can_change_status: Can change wake-up interrupt status
+ *
+ * Enables wakeirq conditionally. We need to enable wake-up interrupt
+ * lazily on the first rpm_suspend(). This is needed as the consumer device
+ * starts in RPM_SUSPENDED state, and the the first pm_runtime_get() would
+ * otherwise try to disable already disabled wakeirq. The wake-up interrupt
+ * starts disabled with IRQ_NOAUTOEN set.
+ *
+ * Should be only called from rpm_suspend() and rpm_resume() path.
+ * Caller must hold &dev->power.lock to change wirq->status
+ */
+void dev_pm_enable_wake_irq_check(struct device *dev,
+				  bool can_change_status)
+{
+	struct wake_irq *wirq = dev->power.wakeirq;
+
+	if (!wirq || !((wirq->status & WAKE_IRQ_DEDICATED_MASK)))
+		return;
+
+	if (likely(wirq->status & WAKE_IRQ_DEDICATED_MANAGED)) {
+		goto enable;
+	} else if (can_change_status) {
+		wirq->status |= WAKE_IRQ_DEDICATED_MANAGED;
+		goto enable;
+	}
+
+	return;
+
+enable:
+	enable_irq(wirq->irq);
+}
+
+/**
+ * dev_pm_disable_wake_irq_check - Checks and disables wake-up interrupt
+ * @dev: Device
+ *
+ * Disables wake-up interrupt conditionally based on status.
+ * Should be only called from rpm_suspend() and rpm_resume() path.
+ */
+void dev_pm_disable_wake_irq_check(struct device *dev)
+{
+	struct wake_irq *wirq = dev->power.wakeirq;
+
+	if (!wirq || !((wirq->status & WAKE_IRQ_DEDICATED_MASK)))
+		return;
+
+	if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED)
+		disable_irq_nosync(wirq->irq);
+}
+
+/**
  * dev_pm_arm_wake_irq - Arm device wake-up
  * @wirq: Device wake-up interrupt
  *
--- linux-4.4.0.orig/drivers/base/power/wakeup.c
+++ linux-4.4.0/drivers/base/power/wakeup.c
@@ -60,6 +60,8 @@
 
 static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
 
+DEFINE_STATIC_SRCU(wakeup_srcu);
+
 static struct wakeup_source deleted_ws = {
 	.name = "deleted",
 	.lock =  __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
@@ -111,7 +113,6 @@
 	if (!ws)
 		return;
 
-	del_timer_sync(&ws->timer);
 	__pm_relax(ws);
 }
 EXPORT_SYMBOL_GPL(wakeup_source_drop);
@@ -198,7 +199,14 @@
 	spin_lock_irqsave(&events_lock, flags);
 	list_del_rcu(&ws->entry);
 	spin_unlock_irqrestore(&events_lock, flags);
-	synchronize_rcu();
+	synchronize_srcu(&wakeup_srcu);
+
+	del_timer_sync(&ws->timer);
+	/*
+	 * Clear timer.function to make wakeup_source_not_registered() treat
+	 * this wakeup source as not registered.
+	 */
+	ws->timer.function = NULL;
 }
 EXPORT_SYMBOL_GPL(wakeup_source_remove);
 
@@ -330,13 +338,14 @@
 void device_wakeup_arm_wake_irqs(void)
 {
 	struct wakeup_source *ws;
+	int srcuidx;
 
-	rcu_read_lock();
+	srcuidx = srcu_read_lock(&wakeup_srcu);
 	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
 		if (ws->wakeirq)
 			dev_pm_arm_wake_irq(ws->wakeirq);
 	}
-	rcu_read_unlock();
+	srcu_read_unlock(&wakeup_srcu, srcuidx);
 }
 
 /**
@@ -347,13 +356,14 @@
 void device_wakeup_disarm_wake_irqs(void)
 {
 	struct wakeup_source *ws;
+	int srcuidx;
 
-	rcu_read_lock();
+	srcuidx = srcu_read_lock(&wakeup_srcu);
 	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
 		if (ws->wakeirq)
 			dev_pm_disarm_wake_irq(ws->wakeirq);
 	}
-	rcu_read_unlock();
+	srcu_read_unlock(&wakeup_srcu, srcuidx);
 }
 
 /**
@@ -807,10 +817,10 @@
 void pm_print_active_wakeup_sources(void)
 {
 	struct wakeup_source *ws;
-	int active = 0;
+	int srcuidx, active = 0;
 	struct wakeup_source *last_activity_ws = NULL;
 
-	rcu_read_lock();
+	srcuidx = srcu_read_lock(&wakeup_srcu);
 	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
 		if (ws->active) {
 			pr_info("active wakeup source: %s\n", ws->name);
@@ -826,7 +836,7 @@
 	if (!active && last_activity_ws)
 		pr_info("last active wakeup source: %s\n",
 			last_activity_ws->name);
-	rcu_read_unlock();
+	srcu_read_unlock(&wakeup_srcu, srcuidx);
 }
 EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
 
@@ -953,8 +963,9 @@
 {
 	struct wakeup_source *ws;
 	ktime_t now = ktime_get();
+	int srcuidx;
 
-	rcu_read_lock();
+	srcuidx = srcu_read_lock(&wakeup_srcu);
 	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
 		spin_lock_irq(&ws->lock);
 		if (ws->autosleep_enabled != set) {
@@ -968,7 +979,7 @@
 		}
 		spin_unlock_irq(&ws->lock);
 	}
-	rcu_read_unlock();
+	srcu_read_unlock(&wakeup_srcu, srcuidx);
 }
 #endif /* CONFIG_PM_AUTOSLEEP */
 
@@ -1029,15 +1040,16 @@
 static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
 {
 	struct wakeup_source *ws;
+	int srcuidx;
 
 	seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
 		"expire_count\tactive_since\ttotal_time\tmax_time\t"
 		"last_change\tprevent_suspend_time\n");
 
-	rcu_read_lock();
+	srcuidx = srcu_read_lock(&wakeup_srcu);
 	list_for_each_entry_rcu(ws, &wakeup_sources, entry)
 		print_wakeup_source_stats(m, ws);
-	rcu_read_unlock();
+	srcu_read_unlock(&wakeup_srcu, srcuidx);
 
 	print_wakeup_source_stats(m, &deleted_ws);
 
--- linux-4.4.0.orig/drivers/base/property.c
+++ linux-4.4.0/drivers/base/property.c
@@ -19,32 +19,14 @@
 #include <linux/etherdevice.h>
 #include <linux/phy.h>
 
-/**
- * device_add_property_set - Add a collection of properties to a device object.
- * @dev: Device to add properties to.
- * @pset: Collection of properties to add.
- *
- * Associate a collection of device properties represented by @pset with @dev
- * as its secondary firmware node.
- */
-void device_add_property_set(struct device *dev, struct property_set *pset)
-{
-	if (!pset)
-		return;
-
-	pset->fwnode.type = FWNODE_PDATA;
-	set_secondary_fwnode(dev, &pset->fwnode);
-}
-EXPORT_SYMBOL_GPL(device_add_property_set);
-
-static inline bool is_pset(struct fwnode_handle *fwnode)
+static inline bool is_pset_node(struct fwnode_handle *fwnode)
 {
 	return fwnode && fwnode->type == FWNODE_PDATA;
 }
 
-static inline struct property_set *to_pset(struct fwnode_handle *fwnode)
+static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode)
 {
-	return is_pset(fwnode) ?
+	return is_pset_node(fwnode) ?
 		container_of(fwnode, struct property_set, fwnode) : NULL;
 }
 
@@ -63,45 +45,135 @@
 	return NULL;
 }
 
-static int pset_prop_read_array(struct property_set *pset, const char *name,
-				enum dev_prop_type type, void *val, size_t nval)
+static void *pset_prop_find(struct property_set *pset, const char *propname,
+			    size_t length)
 {
 	struct property_entry *prop;
-	unsigned int item_size;
+	void *pointer;
 
-	prop = pset_prop_get(pset, name);
+	prop = pset_prop_get(pset, propname);
 	if (!prop)
-		return -ENODATA;
+		return ERR_PTR(-EINVAL);
+	if (prop->is_array)
+		pointer = prop->pointer.raw_data;
+	else
+		pointer = &prop->value.raw_data;
+	if (!pointer)
+		return ERR_PTR(-ENODATA);
+	if (length > prop->length)
+		return ERR_PTR(-EOVERFLOW);
+	return pointer;
+}
+
+static int pset_prop_read_u8_array(struct property_set *pset,
+				   const char *propname,
+				   u8 *values, size_t nval)
+{
+	void *pointer;
+	size_t length = nval * sizeof(*values);
+
+	pointer = pset_prop_find(pset, propname, length);
+	if (IS_ERR(pointer))
+		return PTR_ERR(pointer);
+
+	memcpy(values, pointer, length);
+	return 0;
+}
+
+static int pset_prop_read_u16_array(struct property_set *pset,
+				    const char *propname,
+				    u16 *values, size_t nval)
+{
+	void *pointer;
+	size_t length = nval * sizeof(*values);
+
+	pointer = pset_prop_find(pset, propname, length);
+	if (IS_ERR(pointer))
+		return PTR_ERR(pointer);
+
+	memcpy(values, pointer, length);
+	return 0;
+}
 
-	if (prop->type != type)
-		return -EPROTO;
+static int pset_prop_read_u32_array(struct property_set *pset,
+				    const char *propname,
+				    u32 *values, size_t nval)
+{
+	void *pointer;
+	size_t length = nval * sizeof(*values);
+
+	pointer = pset_prop_find(pset, propname, length);
+	if (IS_ERR(pointer))
+		return PTR_ERR(pointer);
+
+	memcpy(values, pointer, length);
+	return 0;
+}
+
+static int pset_prop_read_u64_array(struct property_set *pset,
+				    const char *propname,
+				    u64 *values, size_t nval)
+{
+	void *pointer;
+	size_t length = nval * sizeof(*values);
+
+	pointer = pset_prop_find(pset, propname, length);
+	if (IS_ERR(pointer))
+		return PTR_ERR(pointer);
+
+	memcpy(values, pointer, length);
+	return 0;
+}
+
+static int pset_prop_count_elems_of_size(struct property_set *pset,
+					 const char *propname, size_t length)
+{
+	struct property_entry *prop;
+
+	prop = pset_prop_get(pset, propname);
+	if (!prop)
+		return -EINVAL;
+
+	return prop->length / length;
+}
+
+static int pset_prop_read_string_array(struct property_set *pset,
+				       const char *propname,
+				       const char **strings, size_t nval)
+{
+	void *pointer;
+	size_t length = nval * sizeof(*strings);
+
+	pointer = pset_prop_find(pset, propname, length);
+	if (IS_ERR(pointer))
+		return PTR_ERR(pointer);
+
+	memcpy(strings, pointer, length);
+	return 0;
+}
 
-	if (!val)
-		return prop->nval;
+static int pset_prop_read_string(struct property_set *pset,
+				 const char *propname, const char **strings)
+{
+	struct property_entry *prop;
+	const char **pointer;
 
-	if (prop->nval < nval)
-		return -EOVERFLOW;
-
-	switch (type) {
-	case DEV_PROP_U8:
-		item_size = sizeof(u8);
-		break;
-	case DEV_PROP_U16:
-		item_size = sizeof(u16);
-		break;
-	case DEV_PROP_U32:
-		item_size = sizeof(u32);
-		break;
-	case DEV_PROP_U64:
-		item_size = sizeof(u64);
-		break;
-	case DEV_PROP_STRING:
-		item_size = sizeof(const char *);
-		break;
-	default:
+	prop = pset_prop_get(pset, propname);
+	if (!prop)
 		return -EINVAL;
+	if (!prop->is_string)
+		return -EILSEQ;
+	if (prop->is_array) {
+		pointer = prop->pointer.str;
+		if (!pointer)
+			return -ENODATA;
+	} else {
+		pointer = &prop->value.str;
+		if (*pointer && strnlen(*pointer, prop->length) >= prop->length)
+			return -EILSEQ;
 	}
-	memcpy(val, prop->value.raw_data, nval * item_size);
+
+	*strings = *pointer;
 	return 0;
 }
 
@@ -124,6 +196,18 @@
 }
 EXPORT_SYMBOL_GPL(device_property_present);
 
+static bool __fwnode_property_present(struct fwnode_handle *fwnode,
+				      const char *propname)
+{
+	if (is_of_node(fwnode))
+		return of_property_read_bool(to_of_node(fwnode), propname);
+	else if (is_acpi_node(fwnode))
+		return !acpi_node_prop_get(fwnode, propname, NULL);
+	else if (is_pset_node(fwnode))
+		return !!pset_prop_get(to_pset_node(fwnode), propname);
+	return false;
+}
+
 /**
  * fwnode_property_present - check if a property of a firmware node is present
  * @fwnode: Firmware node whose property to check
@@ -131,12 +215,12 @@
  */
 bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
 {
-	if (is_of_node(fwnode))
-		return of_property_read_bool(to_of_node(fwnode), propname);
-	else if (is_acpi_node(fwnode))
-		return !acpi_node_prop_get(fwnode, propname, NULL);
+	bool ret;
 
-	return !!pset_prop_get(to_pset(fwnode), propname);
+	ret = __fwnode_property_present(fwnode, propname);
+	if (ret == false && fwnode->secondary)
+		ret = __fwnode_property_present(fwnode->secondary, propname);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(fwnode_property_present);
 
@@ -309,25 +393,40 @@
 }
 EXPORT_SYMBOL_GPL(device_property_match_string);
 
-#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
-	(val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval)				\
+	(val) ? of_property_read_##type##_array((node), (propname), (val), (nval))	\
 	      : of_property_count_elems_of_size((node), (propname), sizeof(type))
 
-#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
-({ \
-	int _ret_; \
-	if (is_of_node(_fwnode_)) \
-		_ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \
-					       _type_, _val_, _nval_); \
-	else if (is_acpi_node(_fwnode_)) \
-		_ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \
-					    _val_, _nval_); \
-	else if (is_pset(_fwnode_)) \
-		_ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \
-					     _proptype_, _val_, _nval_); \
-	else \
-		_ret_ = -ENXIO; \
-	_ret_; \
+#define PSET_PROP_READ_ARRAY(node, propname, type, val, nval)				\
+	(val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval))	\
+	      : pset_prop_count_elems_of_size((node), (propname), sizeof(type))
+
+#define FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_)	\
+({											\
+	int _ret_;									\
+	if (is_of_node(_fwnode_))							\
+		_ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_,	\
+					       _type_, _val_, _nval_);			\
+	else if (is_acpi_node(_fwnode_))						\
+		_ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_,		\
+					    _val_, _nval_);				\
+	else if (is_pset_node(_fwnode_)) 						\
+		_ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_,	\
+					     _type_, _val_, _nval_);			\
+	else										\
+		_ret_ = -ENXIO;								\
+	_ret_;										\
+})
+
+#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_)	\
+({											\
+	int _ret_;									\
+	_ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_,		\
+				 _val_, _nval_);					\
+	if (_ret_ == -EINVAL && _fwnode_->secondary)					\
+		_ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_,	\
+				_proptype_, _val_, _nval_);				\
+	_ret_;										\
 })
 
 /**
@@ -434,6 +533,41 @@
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
 
+static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+					       const char *propname,
+					       const char **val, size_t nval)
+{
+	if (is_of_node(fwnode))
+		return val ?
+			of_property_read_string_array(to_of_node(fwnode),
+						      propname, val, nval) :
+			of_property_count_strings(to_of_node(fwnode), propname);
+	else if (is_acpi_node(fwnode))
+		return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
+					   val, nval);
+	else if (is_pset_node(fwnode))
+		return val ?
+			pset_prop_read_string_array(to_pset_node(fwnode),
+						    propname, val, nval) :
+			pset_prop_count_elems_of_size(to_pset_node(fwnode),
+						      propname,
+						      sizeof(const char *));
+	return -ENXIO;
+}
+
+static int __fwnode_property_read_string(struct fwnode_handle *fwnode,
+					 const char *propname, const char **val)
+{
+	if (is_of_node(fwnode))
+		return of_property_read_string(to_of_node(fwnode), propname, val);
+	else if (is_acpi_node(fwnode))
+		return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
+					   val, 1);
+	else if (is_pset_node(fwnode))
+		return pset_prop_read_string(to_pset_node(fwnode), propname, val);
+	return -ENXIO;
+}
+
 /**
  * fwnode_property_read_string_array - return string array property of a node
  * @fwnode: Firmware node to get the property of
@@ -456,18 +590,13 @@
 				      const char *propname, const char **val,
 				      size_t nval)
 {
-	if (is_of_node(fwnode))
-		return val ?
-			of_property_read_string_array(to_of_node(fwnode),
-						      propname, val, nval) :
-			of_property_count_strings(to_of_node(fwnode), propname);
-	else if (is_acpi_node(fwnode))
-		return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
-					   val, nval);
-	else if (is_pset(fwnode))
-		return pset_prop_read_array(to_pset(fwnode), propname,
-					    DEV_PROP_STRING, val, nval);
-	return -ENXIO;
+	int ret;
+
+	ret = __fwnode_property_read_string_array(fwnode, propname, val, nval);
+	if (ret == -EINVAL && fwnode->secondary)
+		ret = __fwnode_property_read_string_array(fwnode->secondary,
+							  propname, val, nval);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
 
@@ -489,14 +618,13 @@
 int fwnode_property_read_string(struct fwnode_handle *fwnode,
 				const char *propname, const char **val)
 {
-	if (is_of_node(fwnode))
-		return of_property_read_string(to_of_node(fwnode), propname, val);
-	else if (is_acpi_node(fwnode))
-		return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
-					   val, 1);
+	int ret;
 
-	return pset_prop_read_array(to_pset(fwnode), propname,
-				    DEV_PROP_STRING, val, 1);
+	ret = __fwnode_property_read_string(fwnode, propname, val);
+	if (ret == -EINVAL && fwnode->secondary)
+		ret = __fwnode_property_read_string(fwnode->secondary,
+						    propname, val);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_string);
 
@@ -547,6 +675,179 @@
 EXPORT_SYMBOL_GPL(fwnode_property_match_string);
 
 /**
+ * pset_free_set - releases memory allocated for copied property set
+ * @pset: Property set to release
+ *
+ * Function takes previously copied property set and releases all the
+ * memory allocated to it.
+ */
+static void pset_free_set(struct property_set *pset)
+{
+	const struct property_entry *prop;
+	size_t i, nval;
+
+	if (!pset)
+		return;
+
+	for (prop = pset->properties; prop->name; prop++) {
+		if (prop->is_array) {
+			if (prop->is_string && prop->pointer.str) {
+				nval = prop->length / sizeof(const char *);
+				for (i = 0; i < nval; i++)
+					kfree(prop->pointer.str[i]);
+			}
+			kfree(prop->pointer.raw_data);
+		} else if (prop->is_string) {
+			kfree(prop->value.str);
+		}
+		kfree(prop->name);
+	}
+
+	kfree(pset->properties);
+	kfree(pset);
+}
+
+static int pset_copy_entry(struct property_entry *dst,
+			   const struct property_entry *src)
+{
+	const char **d, **s;
+	size_t i, nval;
+
+	dst->name = kstrdup(src->name, GFP_KERNEL);
+	if (!dst->name)
+		return -ENOMEM;
+
+	if (src->is_array) {
+		if (src->is_string) {
+			nval = src->length / sizeof(const char *);
+			dst->pointer.str = kcalloc(nval, sizeof(const char *),
+						   GFP_KERNEL);
+			if (!dst->pointer.str)
+				return -ENOMEM;
+
+			d = dst->pointer.str;
+			s = src->pointer.str;
+			for (i = 0; i < nval; i++) {
+				d[i] = kstrdup(s[i], GFP_KERNEL);
+				if (!d[i] && s[i])
+					return -ENOMEM;
+			}
+		} else {
+			dst->pointer.raw_data = kmemdup(src->pointer.raw_data,
+							src->length, GFP_KERNEL);
+			if (!dst->pointer.raw_data)
+				return -ENOMEM;
+		}
+	} else if (src->is_string) {
+		dst->value.str = kstrdup(src->value.str, GFP_KERNEL);
+		if (!dst->value.str && src->value.str)
+			return -ENOMEM;
+	} else {
+		dst->value.raw_data = src->value.raw_data;
+	}
+
+	dst->length = src->length;
+	dst->is_array = src->is_array;
+	dst->is_string = src->is_string;
+
+	return 0;
+}
+
+/**
+ * pset_copy_set - copies property set
+ * @pset: Property set to copy
+ *
+ * This function takes a deep copy of the given property set and returns
+ * pointer to the copy. Call device_free_property_set() to free resources
+ * allocated in this function.
+ *
+ * Return: Pointer to the new property set or error pointer.
+ */
+static struct property_set *pset_copy_set(const struct property_set *pset)
+{
+	const struct property_entry *entry;
+	struct property_set *p;
+	size_t i, n = 0;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return ERR_PTR(-ENOMEM);
+
+	while (pset->properties[n].name)
+		n++;
+
+	p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL);
+	if (!p->properties) {
+		kfree(p);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	for (i = 0; i < n; i++) {
+		int ret = pset_copy_entry(&p->properties[i],
+					  &pset->properties[i]);
+		if (ret) {
+			pset_free_set(p);
+			return ERR_PTR(ret);
+		}
+	}
+
+	return p;
+}
+
+/**
+ * device_remove_property_set - Remove properties from a device object.
+ * @dev: Device whose properties to remove.
+ *
+ * The function removes properties previously associated to the device
+ * secondary firmware node with device_add_property_set(). Memory allocated
+ * to the properties will also be released.
+ */
+void device_remove_property_set(struct device *dev)
+{
+	struct fwnode_handle *fwnode;
+
+	fwnode = dev_fwnode(dev);
+	if (!fwnode)
+		return;
+	/*
+	 * Pick either primary or secondary node depending which one holds
+	 * the pset. If there is no real firmware node (ACPI/DT) primary
+	 * will hold the pset.
+	 */
+	if (!is_pset_node(fwnode))
+		fwnode = fwnode->secondary;
+	if (!IS_ERR(fwnode) && is_pset_node(fwnode))
+		pset_free_set(to_pset_node(fwnode));
+	set_secondary_fwnode(dev, NULL);
+}
+EXPORT_SYMBOL_GPL(device_remove_property_set);
+
+/**
+ * device_add_property_set - Add a collection of properties to a device object.
+ * @dev: Device to add properties to.
+ * @pset: Collection of properties to add.
+ *
+ * Associate a collection of device properties represented by @pset with @dev
+ * as its secondary firmware node. The function takes a copy of @pset.
+ */
+int device_add_property_set(struct device *dev, const struct property_set *pset)
+{
+	struct property_set *p;
+
+	if (!pset)
+		return -EINVAL;
+
+	p = pset_copy_set(pset);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+
+	p->fwnode.type = FWNODE_PDATA;
+	set_secondary_fwnode(dev, &p->fwnode);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(device_add_property_set);
+
+/**
  * device_get_next_child_node - Return the next child node handle for a device
  * @dev: Device to find the next child node for.
  * @child: Handle to one of the device's child nodes or a null handle.
--- linux-4.4.0.orig/drivers/base/regmap/internal.h
+++ linux-4.4.0/drivers/base/regmap/internal.h
@@ -92,10 +92,14 @@
 	bool (*readable_reg)(struct device *dev, unsigned int reg);
 	bool (*volatile_reg)(struct device *dev, unsigned int reg);
 	bool (*precious_reg)(struct device *dev, unsigned int reg);
+	bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
+	bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
 	const struct regmap_access_table *wr_table;
 	const struct regmap_access_table *rd_table;
 	const struct regmap_access_table *volatile_table;
 	const struct regmap_access_table *precious_table;
+	const struct regmap_access_table *wr_noinc_table;
+	const struct regmap_access_table *rd_noinc_table;
 
 	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
 	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
@@ -175,6 +179,8 @@
 bool regmap_readable(struct regmap *map, unsigned int reg);
 bool regmap_volatile(struct regmap *map, unsigned int reg);
 bool regmap_precious(struct regmap *map, unsigned int reg);
+bool regmap_writeable_noinc(struct regmap *map, unsigned int reg);
+bool regmap_readable_noinc(struct regmap *map, unsigned int reg);
 
 int _regmap_write(struct regmap *map, unsigned int reg,
 		  unsigned int val);
@@ -243,7 +249,7 @@
 int regcache_lookup_reg(struct regmap *map, unsigned int reg);
 
 int _regmap_raw_write(struct regmap *map, unsigned int reg,
-		      const void *val, size_t val_len);
+		      const void *val, size_t val_len, bool noinc);
 
 void regmap_async_complete_cb(struct regmap_async *async, int ret);
 
--- linux-4.4.0.orig/drivers/base/regmap/regcache-rbtree.c
+++ linux-4.4.0/drivers/base/regmap/regcache-rbtree.c
@@ -296,14 +296,14 @@
 	if (!blk)
 		return -ENOMEM;
 
+	rbnode->block = blk;
+
 	if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) {
 		present = krealloc(rbnode->cache_present,
 				   BITS_TO_LONGS(blklen) * sizeof(*present),
 				   GFP_KERNEL);
-		if (!present) {
-			kfree(blk);
+		if (!present)
 			return -ENOMEM;
-		}
 
 		memset(present + BITS_TO_LONGS(rbnode->blklen), 0,
 		       (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen))
@@ -320,7 +320,6 @@
 	}
 
 	/* update the rbnode block, its size and the base register */
-	rbnode->block = blk;
 	rbnode->blklen = blklen;
 	rbnode->base_reg = base_reg;
 	rbnode->cache_present = present;
--- linux-4.4.0.orig/drivers/base/regmap/regcache.c
+++ linux-4.4.0/drivers/base/regmap/regcache.c
@@ -670,7 +670,7 @@
 
 	map->cache_bypass = true;
 
-	ret = _regmap_raw_write(map, base, *data, count * val_bytes);
+	ret = _regmap_raw_write(map, base, *data, count * val_bytes, false);
 	if (ret)
 		dev_err(map->dev, "Unable to sync registers %#x-%#x. %d\n",
 			base, cur - map->reg_stride, ret);
--- linux-4.4.0.orig/drivers/base/regmap/regmap-debugfs.c
+++ linux-4.4.0/drivers/base/regmap/regmap-debugfs.c
@@ -194,6 +194,9 @@
 	if (*ppos < 0 || !count)
 		return -EINVAL;
 
+	if (count > (PAGE_SIZE << (MAX_ORDER - 1)))
+		count = PAGE_SIZE << (MAX_ORDER - 1);
+
 	buf = kmalloc(count, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
@@ -342,6 +345,9 @@
 	if (*ppos < 0 || !count)
 		return -EINVAL;
 
+	if (count > (PAGE_SIZE << (MAX_ORDER - 1)))
+		count = PAGE_SIZE << (MAX_ORDER - 1);
+
 	buf = kmalloc(count, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/base/regmap/regmap-spmi.c
+++ linux-4.4.0/drivers/base/regmap/regmap-spmi.c
@@ -142,7 +142,7 @@
 	while (val_size) {
 		len = min_t(size_t, val_size, 8);
 
-		err = spmi_ext_register_readl(context, addr, val, val_size);
+		err = spmi_ext_register_readl(context, addr, val, len);
 		if (err)
 			goto err_out;
 
--- linux-4.4.0.orig/drivers/base/regmap/regmap.c
+++ linux-4.4.0/drivers/base/regmap/regmap.c
@@ -143,6 +143,28 @@
 	return false;
 }
 
+bool regmap_writeable_noinc(struct regmap *map, unsigned int reg)
+{
+	if (map->writeable_noinc_reg)
+		return map->writeable_noinc_reg(map->dev, reg);
+
+	if (map->wr_noinc_table)
+		return regmap_check_range_table(map, reg, map->wr_noinc_table);
+
+	return true;
+}
+
+bool regmap_readable_noinc(struct regmap *map, unsigned int reg)
+{
+	if (map->readable_noinc_reg)
+		return map->readable_noinc_reg(map->dev, reg);
+
+	if (map->rd_noinc_table)
+		return regmap_check_range_table(map, reg, map->rd_noinc_table);
+
+	return true;
+}
+
 static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
 	size_t num)
 {
@@ -596,10 +618,14 @@
 	map->rd_table = config->rd_table;
 	map->volatile_table = config->volatile_table;
 	map->precious_table = config->precious_table;
+	map->wr_noinc_table = config->wr_noinc_table;
+	map->rd_noinc_table = config->rd_noinc_table;
 	map->writeable_reg = config->writeable_reg;
 	map->readable_reg = config->readable_reg;
 	map->volatile_reg = config->volatile_reg;
 	map->precious_reg = config->precious_reg;
+	map->writeable_noinc_reg = config->writeable_noinc_reg;
+	map->readable_noinc_reg = config->readable_noinc_reg;
 	map->cache_type = config->cache_type;
 	map->name = config->name;
 
@@ -1060,6 +1086,8 @@
 	map->readable_reg = config->readable_reg;
 	map->volatile_reg = config->volatile_reg;
 	map->precious_reg = config->precious_reg;
+	map->writeable_noinc_reg = config->writeable_noinc_reg;
+	map->readable_noinc_reg = config->readable_noinc_reg;
 	map->cache_type = config->cache_type;
 
 	regmap_debugfs_init(map, config->name);
@@ -1106,7 +1134,7 @@
 
 	/* If the user didn't specify a name match any */
 	if (data)
-		return (*r)->name == data;
+		return !strcmp((*r)->name, data);
 	else
 		return 1;
 }
@@ -1196,7 +1224,7 @@
 }
 
 int _regmap_raw_write(struct regmap *map, unsigned int reg,
-		      const void *val, size_t val_len)
+		      const void *val, size_t val_len, bool noinc)
 {
 	struct regmap_range_node *range;
 	unsigned long flags;
@@ -1218,16 +1246,19 @@
 				return -EINVAL;
 
 	if (!map->cache_bypass && map->format.parse_val) {
-		unsigned int ival;
+		unsigned int ival, offset;
 		int val_bytes = map->format.val_bytes;
-		for (i = 0; i < val_len / val_bytes; i++) {
-			ival = map->format.parse_val(val + (i * val_bytes));
-			ret = regcache_write(map, reg + (i * map->reg_stride),
-					     ival);
+
+		/* Cache the last written value for noinc writes */
+		i = noinc ? val_len - val_bytes : 0;
+		for (; i < val_len; i += val_bytes) {
+			ival = map->format.parse_val(val + i);
+			offset = noinc ? 0 : (i / val_bytes) * map->reg_stride;
+			ret = regcache_write(map, reg + offset, ival);
 			if (ret) {
 				dev_err(map->dev,
 					"Error in caching of register: %x ret: %d\n",
-					reg + i, ret);
+					reg + offset, ret);
 				return ret;
 			}
 		}
@@ -1248,7 +1279,7 @@
 			dev_dbg(map->dev, "Writing window %d/%zu\n",
 				win_residue, val_len / map->format.val_bytes);
 			ret = _regmap_raw_write(map, reg, val, win_residue *
-						map->format.val_bytes);
+						map->format.val_bytes, noinc);
 			if (ret != 0)
 				return ret;
 
@@ -1262,7 +1293,7 @@
 			win_residue = range->window_len - win_offset;
 		}
 
-		ret = _regmap_select_page(map, &reg, range, val_num);
+		ret = _regmap_select_page(map, &reg, range, noinc ? 1 : val_num);
 		if (ret != 0)
 			return ret;
 	}
@@ -1358,6 +1389,8 @@
 					     map->format.reg_bytes +
 					     map->format.pad_bytes,
 					     val, val_len);
+	else
+		ret = -ENOTSUPP;
 
 	/* If that didn't work fall back on linearising by hand. */
 	if (ret == -ENOTSUPP) {
@@ -1462,7 +1495,8 @@
 				 map->work_buf +
 				 map->format.reg_bytes +
 				 map->format.pad_bytes,
-				 map->format.val_bytes);
+				 map->format.val_bytes,
+				 false);
 }
 
 static inline void *_regmap_map_get_context(struct regmap *map)
@@ -1582,12 +1616,12 @@
 		return -EINVAL;
 	if (val_len % map->format.val_bytes)
 		return -EINVAL;
-	if (map->max_raw_write && map->max_raw_write > val_len)
+	if (map->max_raw_write && map->max_raw_write < val_len)
 		return -E2BIG;
 
 	map->lock(map->lock_arg);
 
-	ret = _regmap_raw_write(map, reg, val, val_len);
+	ret = _regmap_raw_write(map, reg, val, val_len, false);
 
 	map->unlock(map->lock_arg);
 
@@ -1596,6 +1630,69 @@
 EXPORT_SYMBOL_GPL(regmap_raw_write);
 
 /**
+ * regmap_noinc_write(): Write data from a register without incrementing the
+ *			register number
+ *
+ * @map: Register map to write to
+ * @reg: Register to write to
+ * @val: Pointer to data buffer
+ * @val_len: Length of output buffer in bytes.
+ *
+ * The regmap API usually assumes that bulk bus write operations will write a
+ * range of registers. Some devices have certain registers for which a write
+ * operation can write to an internal FIFO.
+ *
+ * The target register must be volatile but registers after it can be
+ * completely unrelated cacheable registers.
+ *
+ * This will attempt multiple writes as required to write val_len bytes.
+ *
+ * A value of zero will be returned on success, a negative errno will be
+ * returned in error cases.
+ */
+int regmap_noinc_write(struct regmap *map, unsigned int reg,
+		      const void *val, size_t val_len)
+{
+	size_t write_len;
+	int ret;
+
+	if (!map->bus)
+		return -EINVAL;
+	if (!map->bus->write)
+		return -ENOTSUPP;
+	if (val_len % map->format.val_bytes)
+		return -EINVAL;
+	if (!IS_ALIGNED(reg, map->reg_stride))
+		return -EINVAL;
+	if (val_len == 0)
+		return -EINVAL;
+
+	map->lock(map->lock_arg);
+
+	if (!regmap_volatile(map, reg) || !regmap_writeable_noinc(map, reg)) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	while (val_len) {
+		if (map->max_raw_write && map->max_raw_write < val_len)
+			write_len = map->max_raw_write;
+		else
+			write_len = val_len;
+		ret = _regmap_raw_write(map, reg, val, write_len, true);
+		if (ret)
+			goto out_unlock;
+		val = ((u8 *)val) + write_len;
+		val_len -= write_len;
+	}
+
+out_unlock:
+	map->unlock(map->lock_arg);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_noinc_write);
+
+/**
  * regmap_field_write(): Write a value to a single register field
  *
  * @field: Register field to write to
@@ -1779,7 +1876,7 @@
 			ret = _regmap_raw_write(map,
 						reg + (i * chunk_stride),
 						val + (i * chunk_size),
-						chunk_size);
+						chunk_size, false);
 			if (ret)
 				break;
 		}
@@ -1788,7 +1885,7 @@
 		if (!ret && chunk_size * i < total_size) {
 			ret = _regmap_raw_write(map, reg + (i * chunk_stride),
 						val + (i * chunk_size),
-						total_size - i * chunk_size);
+						total_size - i * chunk_size, false);
 		}
 		map->unlock(map->lock_arg);
 	} else {
@@ -1806,7 +1903,7 @@
 			map->format.parse_inplace(wval + i);
 
 		map->lock(map->lock_arg);
-		ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+		ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count, false);
 		map->unlock(map->lock_arg);
 
 		kfree(wval);
@@ -2140,7 +2237,7 @@
 
 	map->async = true;
 
-	ret = _regmap_raw_write(map, reg, val, val_len);
+	ret = _regmap_raw_write(map, reg, val, val_len, false);
 
 	map->async = false;
 
@@ -2151,7 +2248,7 @@
 EXPORT_SYMBOL_GPL(regmap_raw_write_async);
 
 static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
-			    unsigned int val_len)
+			    unsigned int val_len, bool noinc)
 {
 	struct regmap_range_node *range;
 	u8 *u8 = map->work_buf;
@@ -2162,7 +2259,7 @@
 	range = _regmap_range_lookup(map, reg);
 	if (range) {
 		ret = _regmap_select_page(map, &reg, range,
-					  val_len / map->format.val_bytes);
+					  noinc ? 1 : val_len / map->format.val_bytes);
 		if (ret != 0)
 			return ret;
 	}
@@ -2205,7 +2302,7 @@
 	if (!map->format.parse_val)
 		return -EINVAL;
 
-	ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
+	ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes, false);
 	if (ret == 0)
 		*val = map->format.parse_val(map->work_buf);
 
@@ -2315,7 +2412,7 @@
 		}
 
 		/* Physical block read if there's no cache involved */
-		ret = _regmap_raw_read(map, reg, val, val_len);
+		ret = _regmap_raw_read(map, reg, val, val_len, false);
 
 	} else {
 		/* Otherwise go word by word for the cache; should be low
@@ -2339,6 +2436,69 @@
 EXPORT_SYMBOL_GPL(regmap_raw_read);
 
 /**
+ * regmap_noinc_read(): Read data from a register without incrementing the
+ *			register number
+ *
+ * @map: Register map to read from
+ * @reg: Register to read from
+ * @val: Pointer to data buffer
+ * @val_len: Length of output buffer in bytes.
+ *
+ * The regmap API usually assumes that bulk bus read operations will read a
+ * range of registers. Some devices have certain registers for which a read
+ * operation read will read from an internal FIFO.
+ *
+ * The target register must be volatile but registers after it can be
+ * completely unrelated cacheable registers.
+ *
+ * This will attempt multiple reads as required to read val_len bytes.
+ *
+ * A value of zero will be returned on success, a negative errno will be
+ * returned in error cases.
+ */
+int regmap_noinc_read(struct regmap *map, unsigned int reg,
+		      void *val, size_t val_len)
+{
+	size_t read_len;
+	int ret;
+
+	if (!map->bus)
+		return -EINVAL;
+	if (!map->bus->read)
+		return -ENOTSUPP;
+	if (val_len % map->format.val_bytes)
+		return -EINVAL;
+	if (!IS_ALIGNED(reg, map->reg_stride))
+		return -EINVAL;
+	if (val_len == 0)
+		return -EINVAL;
+
+	map->lock(map->lock_arg);
+
+	if (!regmap_volatile(map, reg) || !regmap_readable_noinc(map, reg)) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	while (val_len) {
+		if (map->max_raw_read && map->max_raw_read < val_len)
+			read_len = map->max_raw_read;
+		else
+			read_len = val_len;
+		ret = _regmap_raw_read(map, reg, val, read_len, true);
+		if (ret)
+			goto out_unlock;
+		val = ((u8 *)val) + read_len;
+		val_len -= read_len;
+	}
+
+out_unlock:
+	map->unlock(map->lock_arg);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_noinc_read);
+
+/**
  * regmap_field_read(): Read a value to a single register field
  *
  * @field: Register field to read from
--- linux-4.4.0.orig/drivers/base/soc.c
+++ linux-4.4.0/drivers/base/soc.c
@@ -146,6 +146,7 @@
 out1:
 	return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(soc_device_register);
 
 /* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
 void soc_device_unregister(struct soc_device *soc_dev)
@@ -154,6 +155,7 @@
 
 	device_unregister(&soc_dev->dev);
 }
+EXPORT_SYMBOL_GPL(soc_device_unregister);
 
 static int __init soc_bus_register(void)
 {
--- linux-4.4.0.orig/drivers/bcma/bcma_private.h
+++ linux-4.4.0/drivers/bcma/bcma_private.h
@@ -8,8 +8,6 @@
 #include <linux/bcma/bcma.h>
 #include <linux/delay.h>
 
-#define BCMA_CORE_SIZE		0x1000
-
 #define bcma_err(bus, fmt, ...) \
 	pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
 #define bcma_warn(bus, fmt, ...) \
--- linux-4.4.0.orig/drivers/bcma/driver_pci.c
+++ linux-4.4.0/drivers/bcma/driver_pci.c
@@ -78,7 +78,7 @@
 		v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
 	}
 
-	v = BCMA_CORE_PCI_MDIODATA_START;
+	v |= BCMA_CORE_PCI_MDIODATA_START;
 	v |= BCMA_CORE_PCI_MDIODATA_READ;
 	v |= BCMA_CORE_PCI_MDIODATA_TA;
 
@@ -121,7 +121,7 @@
 		v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
 	}
 
-	v = BCMA_CORE_PCI_MDIODATA_START;
+	v |= BCMA_CORE_PCI_MDIODATA_START;
 	v |= BCMA_CORE_PCI_MDIODATA_WRITE;
 	v |= BCMA_CORE_PCI_MDIODATA_TA;
 	v |= data;
--- linux-4.4.0.orig/drivers/bcma/main.c
+++ linux-4.4.0/drivers/bcma/main.c
@@ -640,8 +640,11 @@
 					       drv);
 	int err = 0;
 
+	get_device(dev);
 	if (adrv->probe)
 		err = adrv->probe(core);
+	if (err)
+		put_device(dev);
 
 	return err;
 }
@@ -654,6 +657,7 @@
 
 	if (adrv->remove)
 		adrv->remove(core);
+	put_device(dev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/block/Kconfig
+++ linux-4.4.0/drivers/block/Kconfig
@@ -540,6 +540,7 @@
 config BLK_DEV_RSXX
 	tristate "IBM Flash Adapter 900GB Full Height PCIe Device Driver"
 	depends on PCI
+	select CRC32
 	help
 	  Device driver for IBM's high speed PCIe SSD
 	  storage device: Flash Adapter 900GB Full Height.
--- linux-4.4.0.orig/drivers/block/amiflop.c
+++ linux-4.4.0/drivers/block/amiflop.c
@@ -1699,11 +1699,41 @@
 	.check_events	= amiga_check_events,
 };
 
+static struct gendisk *fd_alloc_disk(int drive)
+{
+	struct gendisk *disk;
+
+	disk = alloc_disk(1);
+	if (!disk)
+		goto out;
+
+	disk->queue = blk_init_queue(do_fd_request, &amiflop_lock);
+	if (IS_ERR(disk->queue)) {
+		disk->queue = NULL;
+		goto out_put_disk;
+	}
+
+	unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL);
+	if (!unit[drive].trackbuf)
+		goto out_cleanup_queue;
+
+	return disk;
+
+out_cleanup_queue:
+	blk_cleanup_queue(disk->queue);
+	disk->queue = NULL;
+out_put_disk:
+	put_disk(disk);
+out:
+	unit[drive].type->code = FD_NODRIVE;
+	return NULL;
+}
+
 static int __init fd_probe_drives(void)
 {
 	int drive,drives,nomem;
 
-	printk(KERN_INFO "FD: probing units\nfound ");
+	pr_info("FD: probing units\nfound");
 	drives=0;
 	nomem=0;
 	for(drive=0;drive<FD_MAX_UNITS;drive++) {
@@ -1711,27 +1741,17 @@
 		fd_probe(drive);
 		if (unit[drive].type->code == FD_NODRIVE)
 			continue;
-		disk = alloc_disk(1);
+
+		disk = fd_alloc_disk(drive);
 		if (!disk) {
-			unit[drive].type->code = FD_NODRIVE;
+			pr_cont(" no mem for fd%d", drive);
+			nomem = 1;
 			continue;
 		}
 		unit[drive].gendisk = disk;
-
-		disk->queue = blk_init_queue(do_fd_request, &amiflop_lock);
-		if (!disk->queue) {
-			unit[drive].type->code = FD_NODRIVE;
-			continue;
-		}
-
 		drives++;
-		if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) {
-			printk("no mem for ");
-			unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */
-			drives--;
-			nomem = 1;
-		}
-		printk("fd%d ",drive);
+
+		pr_cont(" fd%d",drive);
 		disk->major = FLOPPY_MAJOR;
 		disk->first_minor = drive;
 		disk->fops = &floppy_fops;
@@ -1742,11 +1762,11 @@
 	}
 	if ((drives > 0) || (nomem == 0)) {
 		if (drives == 0)
-			printk("no drives");
-		printk("\n");
+			pr_cont(" no drives");
+		pr_cont("\n");
 		return drives;
 	}
-	printk("\n");
+	pr_cont("\n");
 	return -ENOMEM;
 }
  
@@ -1837,30 +1857,6 @@
 	return ret;
 }
 
-#if 0 /* not safe to unload */
-static int __exit amiga_floppy_remove(struct platform_device *pdev)
-{
-	int i;
-
-	for( i = 0; i < FD_MAX_UNITS; i++) {
-		if (unit[i].type->code != FD_NODRIVE) {
-			struct request_queue *q = unit[i].gendisk->queue;
-			del_gendisk(unit[i].gendisk);
-			put_disk(unit[i].gendisk);
-			kfree(unit[i].trackbuf);
-			if (q)
-				blk_cleanup_queue(q);
-		}
-	}
-	blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
-	free_irq(IRQ_AMIGA_CIAA_TB, NULL);
-	free_irq(IRQ_AMIGA_DSKBLK, NULL);
-	custom.dmacon = DMAF_DISK; /* disable DMA */
-	amiga_chip_free(raw_buf);
-	unregister_blkdev(FLOPPY_MAJOR, "fd");
-}
-#endif
-
 static struct platform_driver amiga_floppy_driver = {
 	.driver   = {
 		.name	= "amiga-floppy",
--- linux-4.4.0.orig/drivers/block/aoe/aoeblk.c
+++ linux-4.4.0/drivers/block/aoe/aoeblk.c
@@ -396,8 +396,8 @@
 	WARN_ON(d->gd);
 	WARN_ON(d->flags & DEVFL_UP);
 	blk_queue_max_hw_sectors(q, BLK_DEF_MAX_SECTORS);
-	q->backing_dev_info.name = "aoe";
-	q->backing_dev_info.ra_pages = READ_AHEAD / PAGE_CACHE_SIZE;
+	q->backing_dev_info->name = "aoe";
+	q->backing_dev_info->ra_pages = READ_AHEAD / PAGE_CACHE_SIZE;
 	d->bufpool = mp;
 	d->blkq = gd->queue = q;
 	q->queuedata = d;
--- linux-4.4.0.orig/drivers/block/aoe/aoecmd.c
+++ linux-4.4.0/drivers/block/aoe/aoecmd.c
@@ -421,13 +421,16 @@
 	rcu_read_lock();
 	for_each_netdev_rcu(&init_net, ifp) {
 		dev_hold(ifp);
-		if (!is_aoe_netif(ifp))
-			goto cont;
+		if (!is_aoe_netif(ifp)) {
+			dev_put(ifp);
+			continue;
+		}
 
 		skb = new_skb(sizeof *h + sizeof *ch);
 		if (skb == NULL) {
 			printk(KERN_INFO "aoe: skb alloc failure\n");
-			goto cont;
+			dev_put(ifp);
+			continue;
 		}
 		skb_put(skb, sizeof *h + sizeof *ch);
 		skb->dev = ifp;
@@ -442,9 +445,6 @@
 		h->major = cpu_to_be16(aoemajor);
 		h->minor = aoeminor;
 		h->cmd = AOECMD_CFG;
-
-cont:
-		dev_put(ifp);
 	}
 	rcu_read_unlock();
 }
--- linux-4.4.0.orig/drivers/block/aoe/aoenet.c
+++ linux-4.4.0/drivers/block/aoe/aoenet.c
@@ -64,6 +64,7 @@
 			pr_warn("aoe: packet could not be sent on %s.  %s\n",
 				ifp ? ifp->name : "netif",
 				"consider increasing tx_queue_len");
+		dev_put(ifp);
 		spin_lock_irq(&txlock);
 	}
 	return 0;
--- linux-4.4.0.orig/drivers/block/ataflop.c
+++ linux-4.4.0/drivers/block/ataflop.c
@@ -1933,6 +1933,11 @@
 		unit[i].disk = alloc_disk(1);
 		if (!unit[i].disk)
 			goto Enomem;
+
+		unit[i].disk->queue = blk_init_queue(do_fd_request,
+						     &ataflop_lock);
+		if (!unit[i].disk->queue)
+			goto Enomem;
 	}
 
 	if (UseTrackbuffer < 0)
@@ -1964,10 +1969,6 @@
 		sprintf(unit[i].disk->disk_name, "fd%d", i);
 		unit[i].disk->fops = &floppy_fops;
 		unit[i].disk->private_data = &unit[i];
-		unit[i].disk->queue = blk_init_queue(do_fd_request,
-					&ataflop_lock);
-		if (!unit[i].disk->queue)
-			goto Enomem;
 		set_capacity(unit[i].disk, MAX_DISK_SIZE * 2);
 		add_disk(unit[i].disk);
 	}
@@ -1982,13 +1983,17 @@
 
 	return 0;
 Enomem:
-	while (i--) {
-		struct request_queue *q = unit[i].disk->queue;
+	do {
+		struct gendisk *disk = unit[i].disk;
 
-		put_disk(unit[i].disk);
-		if (q)
-			blk_cleanup_queue(q);
-	}
+		if (disk) {
+			if (disk->queue) {
+				blk_cleanup_queue(disk->queue);
+				disk->queue = NULL;
+			}
+			put_disk(unit[i].disk);
+		}
+	} while (i--);
 
 	unregister_blkdev(FLOPPY_MAJOR, "fd");
 	return -ENOMEM;
--- linux-4.4.0.orig/drivers/block/brd.c
+++ linux-4.4.0/drivers/block/brd.c
@@ -22,7 +22,6 @@
 
 #include <asm/uaccess.h>
 
-#define SECTOR_SHIFT		9
 #define PAGE_SECTORS_SHIFT	(PAGE_SHIFT - SECTOR_SHIFT)
 #define PAGE_SECTORS		(1 << PAGE_SECTORS_SHIFT)
 
@@ -338,7 +337,7 @@
 
 	if (unlikely(bio->bi_rw & REQ_DISCARD)) {
 		if (sector & ((PAGE_SIZE >> SECTOR_SHIFT) - 1) ||
-		    bio->bi_iter.bi_size & PAGE_MASK)
+		    bio->bi_iter.bi_size & ~PAGE_MASK)
 			goto io_error;
 		discard_from_brd(brd, sector, bio->bi_iter.bi_size);
 		goto out;
@@ -581,6 +580,25 @@
 	return kobj;
 }
 
+static inline void brd_check_and_reset_par(void)
+{
+	if (unlikely(!max_part))
+		max_part = 1;
+
+	/*
+	 * make sure 'max_part' can be divided exactly by (1U << MINORBITS),
+	 * otherwise, it is possiable to get same dev_t when adding partitions.
+	 */
+	if ((1U << MINORBITS) % max_part != 0)
+		max_part = 1UL << fls(max_part);
+
+	if (max_part > DISK_MAX_PARTS) {
+		pr_info("brd: max_part can't be larger than %d, reset max_part = %d.\n",
+			DISK_MAX_PARTS, DISK_MAX_PARTS);
+		max_part = DISK_MAX_PARTS;
+	}
+}
+
 static int __init brd_init(void)
 {
 	struct brd_device *brd, *next;
@@ -604,8 +622,7 @@
 	if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
 		return -EIO;
 
-	if (unlikely(!max_part))
-		max_part = 1;
+	brd_check_and_reset_par();
 
 	for (i = 0; i < rd_nr; i++) {
 		brd = brd_alloc(i);
--- linux-4.4.0.orig/drivers/block/drbd/drbd_bitmap.c
+++ linux-4.4.0/drivers/block/drbd/drbd_bitmap.c
@@ -479,8 +479,14 @@
  * this masks out the remaining bits.
  * Returns the number of bits cleared.
  */
+#ifndef BITS_PER_PAGE
 #define BITS_PER_PAGE		(1UL << (PAGE_SHIFT + 3))
 #define BITS_PER_PAGE_MASK	(BITS_PER_PAGE - 1)
+#else
+# if BITS_PER_PAGE != (1UL << (PAGE_SHIFT + 3))
+#  error "ambiguous BITS_PER_PAGE"
+# endif
+#endif
 #define BITS_PER_LONG_MASK	(BITS_PER_LONG - 1)
 static int bm_clear_surplus(struct drbd_bitmap *b)
 {
--- linux-4.4.0.orig/drivers/block/drbd/drbd_main.c
+++ linux-4.4.0/drivers/block/drbd/drbd_main.c
@@ -331,6 +331,8 @@
 		 thi->name[0],
 		 resource->name);
 
+	allow_kernel_signal(DRBD_SIGKILL);
+	allow_kernel_signal(SIGXCPU);
 restart:
 	retval = thi->function(thi);
 
@@ -792,7 +794,6 @@
 
 	if (nc->tentative && connection->agreed_pro_version < 92) {
 		rcu_read_unlock();
-		mutex_unlock(&sock->mutex);
 		drbd_err(connection, "--dry-run is not supported by peer");
 		return -EOPNOTSUPP;
 	}
@@ -1802,7 +1803,7 @@
  * do we need to block DRBD_SIG if sock == &meta.socket ??
  * otherwise wake_asender() might interrupt some send_*Ack !
  */
-		rv = kernel_sendmsg(sock, &msg, &iov, 1, size);
+		rv = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len);
 		if (rv == -EAGAIN) {
 			if (we_should_drop_the_connection(connection, sock))
 				break;
@@ -2393,7 +2394,7 @@
 
 	if (get_ldev(device)) {
 		q = bdev_get_queue(device->ldev->backing_bdev);
-		r = bdi_congested(&q->backing_dev_info, bdi_bits);
+		r = bdi_congested(q->backing_dev_info, bdi_bits);
 		put_ldev(device);
 		if (r)
 			reason = 'b';
@@ -2765,8 +2766,8 @@
 	/* we have no partitions. we contain only ourselves. */
 	device->this_bdev->bd_contains = device->this_bdev;
 
-	q->backing_dev_info.congested_fn = drbd_congested;
-	q->backing_dev_info.congested_data = device;
+	q->backing_dev_info->congested_fn = drbd_congested;
+	q->backing_dev_info->congested_data = device;
 
 	blk_queue_make_request(q, drbd_make_request);
 	blk_queue_flush(q, REQ_FLUSH | REQ_FUA);
--- linux-4.4.0.orig/drivers/block/drbd/drbd_nl.c
+++ linux-4.4.0/drivers/block/drbd/drbd_nl.c
@@ -632,14 +632,15 @@
 		if (rv == SS_TWO_PRIMARIES) {
 			/* Maybe the peer is detected as dead very soon...
 			   retry at most once more in this case. */
-			int timeo;
-			rcu_read_lock();
-			nc = rcu_dereference(connection->net_conf);
-			timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
-			rcu_read_unlock();
-			schedule_timeout_interruptible(timeo);
-			if (try < max_tries)
+			if (try < max_tries) {
+				int timeo;
 				try = max_tries - 1;
+				rcu_read_lock();
+				nc = rcu_dereference(connection->net_conf);
+				timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
+				rcu_read_unlock();
+				schedule_timeout_interruptible(timeo);
+			}
 			continue;
 		}
 		if (rv < SS_SUCCESS) {
@@ -1170,11 +1171,13 @@
 
 		blk_queue_stack_limits(q, b);
 
-		if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+		if (q->backing_dev_info->ra_pages !=
+		    b->backing_dev_info->ra_pages) {
 			drbd_info(device, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
-				 q->backing_dev_info.ra_pages,
-				 b->backing_dev_info.ra_pages);
-			q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+				 q->backing_dev_info->ra_pages,
+				 b->backing_dev_info->ra_pages);
+			q->backing_dev_info->ra_pages =
+						b->backing_dev_info->ra_pages;
 		}
 	}
 }
@@ -1684,9 +1687,9 @@
 		}
 	}
 
-	if (device->state.conn < C_CONNECTED &&
-	    device->state.role == R_PRIMARY && device->ed_uuid &&
-	    (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
+	if (device->state.pdsk != D_UP_TO_DATE && device->ed_uuid &&
+	    (device->state.role == R_PRIMARY || device->state.peer == R_PRIMARY) &&
+            (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
 		drbd_err(device, "Can only attach to data with current UUID=%016llX\n",
 		    (unsigned long long)device->ed_uuid);
 		retcode = ERR_DATA_NOT_CURRENT;
--- linux-4.4.0.orig/drivers/block/drbd/drbd_proc.c
+++ linux-4.4.0/drivers/block/drbd/drbd_proc.c
@@ -288,7 +288,7 @@
 			seq_printf(seq, "%2d: cs:Unconfigured\n", i);
 		} else {
 			/* reset device->congestion_reason */
-			bdi_rw_congested(&device->rq_queue->backing_dev_info);
+			bdi_rw_congested(device->rq_queue->backing_dev_info);
 
 			nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
 			wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
--- linux-4.4.0.orig/drivers/block/drbd/drbd_receiver.c
+++ linux-4.4.0/drivers/block/drbd/drbd_receiver.c
@@ -3126,7 +3126,7 @@
 	enum drbd_conns rv = C_MASK;
 	enum drbd_disk_state mydisk;
 	struct net_conf *nc;
-	int hg, rule_nr, rr_conflict, tentative;
+	int hg, rule_nr, rr_conflict, tentative, always_asbp;
 
 	mydisk = device->state.disk;
 	if (mydisk == D_NEGOTIATING)
@@ -3168,8 +3168,12 @@
 
 	rcu_read_lock();
 	nc = rcu_dereference(peer_device->connection->net_conf);
+	always_asbp = nc->always_asbp;
+	rr_conflict = nc->rr_conflict;
+	tentative = nc->tentative;
+	rcu_read_unlock();
 
-	if (hg == 100 || (hg == -100 && nc->always_asbp)) {
+	if (hg == 100 || (hg == -100 && always_asbp)) {
 		int pcount = (device->state.role == R_PRIMARY)
 			   + (peer_role == R_PRIMARY);
 		int forced = (hg == -100);
@@ -3208,9 +3212,6 @@
 			     "Sync from %s node\n",
 			     (hg < 0) ? "peer" : "this");
 	}
-	rr_conflict = nc->rr_conflict;
-	tentative = nc->tentative;
-	rcu_read_unlock();
 
 	if (hg == -100) {
 		/* FIXME this log message is not correct if we end up here
@@ -3889,7 +3890,7 @@
 	kfree(device->p_uuid);
 	device->p_uuid = p_uuid;
 
-	if (device->state.conn < C_CONNECTED &&
+	if ((device->state.conn < C_CONNECTED || device->state.pdsk == D_DISKLESS) &&
 	    device->state.disk < D_INCONSISTENT &&
 	    device->state.role == R_PRIMARY &&
 	    (device->ed_uuid & ~((u64)1)) != (p_uuid[UI_CURRENT] & ~((u64)1))) {
@@ -4115,6 +4116,25 @@
 	if (peer_state.conn == C_AHEAD)
 		ns.conn = C_BEHIND;
 
+	/* TODO:
+	 * if (primary and diskless and peer uuid != effective uuid)
+	 *     abort attach on peer;
+	 *
+	 * If this node does not have good data, was already connected, but
+	 * the peer did a late attach only now, trying to "negotiate" with me,
+	 * AND I am currently Primary, possibly frozen, with some specific
+	 * "effective" uuid, this should never be reached, really, because
+	 * we first send the uuids, then the current state.
+	 *
+	 * In this scenario, we already dropped the connection hard
+	 * when we received the unsuitable uuids (receive_uuids().
+	 *
+	 * Should we want to change this, that is: not drop the connection in
+	 * receive_uuids() already, then we would need to add a branch here
+	 * that aborts the attach of "unsuitable uuids" on the peer in case
+	 * this node is currently Diskless Primary.
+	 */
+
 	if (device->p_uuid && peer_state.disk >= D_NEGOTIATING &&
 	    get_ldev_if_state(device, D_NEGOTIATING)) {
 		int cr; /* consider resync */
--- linux-4.4.0.orig/drivers/block/drbd/drbd_req.c
+++ linux-4.4.0/drivers/block/drbd/drbd_req.c
@@ -937,7 +937,7 @@
 
 	switch (rbm) {
 	case RB_CONGESTED_REMOTE:
-		bdi = &device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
+		bdi = device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
 		return bdi_read_congested(bdi);
 	case RB_LEAST_PENDING:
 		return atomic_read(&device->local_cnt) >
--- linux-4.4.0.orig/drivers/block/drbd/drbd_state.h
+++ linux-4.4.0/drivers/block/drbd/drbd_state.h
@@ -126,7 +126,7 @@
 					   enum chg_state_flags,
 					   struct completion *done);
 extern void print_st_err(struct drbd_device *, union drbd_state,
-			union drbd_state, int);
+			union drbd_state, enum drbd_state_rv);
 
 enum drbd_state_rv
 _conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
--- linux-4.4.0.orig/drivers/block/drbd/drbd_worker.c
+++ linux-4.4.0/drivers/block/drbd/drbd_worker.c
@@ -256,8 +256,8 @@
 	} else
 		what = COMPLETED_OK;
 
-	bio_put(req->private_bio);
 	req->private_bio = ERR_PTR(bio->bi_error);
+	bio_put(bio);
 
 	/* not req_mod(), we need irqsave here! */
 	spin_lock_irqsave(&device->resource->req_lock, flags);
--- linux-4.4.0.orig/drivers/block/floppy.c
+++ linux-4.4.0/drivers/block/floppy.c
@@ -192,6 +192,7 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/async.h>
+#include <linux/compat.h>
 
 /*
  * PS/2 floppies have much slower step rates than regular floppies.
@@ -515,8 +516,8 @@
 static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
 static DECLARE_WAIT_QUEUE_HEAD(command_done);
 
-/* Errors during formatting are counted here. */
-static int format_errors;
+/* errors encountered on the current (or last) request */
+static int floppy_errors;
 
 /* Format request descriptor. */
 static struct format_descr format_req;
@@ -536,7 +537,6 @@
 static char *floppy_track_buffer;
 static int max_buffer_sectors;
 
-static int *errors;
 typedef void (*done_f)(int);
 static const struct cont_t {
 	void (*interrupt)(void);
@@ -847,14 +847,17 @@
 /* selects the fdc and drive, and enables the fdc's input/dma. */
 static void set_fdc(int drive)
 {
+	unsigned int new_fdc = fdc;
+
 	if (drive >= 0 && drive < N_DRIVE) {
-		fdc = FDC(drive);
+		new_fdc = FDC(drive);
 		current_drive = drive;
 	}
-	if (fdc != 1 && fdc != 0) {
+	if (new_fdc >= N_FDC) {
 		pr_info("bad fdc value\n");
 		return;
 	}
+	fdc = new_fdc;
 	set_dor(fdc, ~0, 8);
 #if N_FDC > 1
 	set_dor(1 - fdc, ~8, 0);
@@ -866,7 +869,7 @@
 }
 
 /* locks the driver */
-static int lock_fdc(int drive, bool interruptible)
+static int lock_fdc(int drive)
 {
 	if (WARN(atomic_read(&usage_count) == 0,
 		 "Trying to lock fdc while usage count=0\n"))
@@ -1422,7 +1425,7 @@
 			if (DP->flags & FTD_MSG)
 				DPRINT("Over/Underrun - retrying\n");
 			bad = 0;
-		} else if (*errors >= DP->max_errors.reporting) {
+		} else if (floppy_errors >= DP->max_errors.reporting) {
 			print_errors();
 		}
 		if (ST2 & ST2_WC || ST2 & ST2_BC)
@@ -2045,7 +2048,7 @@
 		if (!next_valid_format())
 			return;
 	}
-	err_count = ++(*errors);
+	err_count = ++floppy_errors;
 	INFBOUND(DRWE->badness, err_count);
 	if (err_count > DP->max_errors.abort)
 		cont->done(0);
@@ -2113,6 +2116,9 @@
 	raw_cmd->kernel_data = floppy_track_buffer;
 	raw_cmd->length = 4 * F_SECT_PER_TRACK;
 
+	if (!F_SECT_PER_TRACK)
+		return;
+
 	/* allow for about 30ms for data transport per track */
 	head_shift = (F_SECT_PER_TRACK + 5) / 6;
 
@@ -2173,7 +2179,7 @@
 {
 	int ret;
 
-	if (lock_fdc(drive, true))
+	if (lock_fdc(drive))
 		return -EINTR;
 
 	set_floppy(drive);
@@ -2187,9 +2193,8 @@
 		return -EINVAL;
 	}
 	format_req = *tmp_format_req;
-	format_errors = 0;
 	cont = &format_cont;
-	errors = &format_errors;
+	floppy_errors = 0;
 	ret = wait_til_done(redo_format, true);
 	if (ret == -EINTR)
 		return -EINTR;
@@ -2672,7 +2677,7 @@
 		 */
 		if (!direct ||
 		    (indirect * 2 > direct * 3 &&
-		     *errors < DP->max_errors.read_track &&
+		     floppy_errors < DP->max_errors.read_track &&
 		     ((!probing ||
 		       (DP->read_track & (1 << DRS->probed_format)))))) {
 			max_size = blk_rq_sectors(current_req);
@@ -2805,8 +2810,10 @@
 			fdc_queue = 0;
 		if (q) {
 			current_req = blk_fetch_request(q);
-			if (current_req)
+			if (current_req) {
+				floppy_errors = 0;
 				break;
+			}
 		}
 	} while (fdc_queue != old_pos);
 
@@ -2866,7 +2873,6 @@
 		_floppy = floppy_type + DP->autodetect[DRS->probed_format];
 	} else
 		probing = 0;
-	errors = &(current_req->errors);
 	tmp = make_raw_rw_request();
 	if (tmp < 2) {
 		request_done(tmp);
@@ -2960,7 +2966,7 @@
 {
 	int ret;
 
-	if (lock_fdc(drive, interruptible))
+	if (lock_fdc(drive))
 		return -EINTR;
 
 	if (arg == FD_RESET_ALWAYS)
@@ -3233,8 +3239,12 @@
 	int cnt;
 
 	/* sanity checking for parameters. */
-	if (g->sect <= 0 ||
-	    g->head <= 0 ||
+	if ((int)g->sect <= 0 ||
+	    (int)g->head <= 0 ||
+	    /* check for overflow in max_sector */
+	    (int)(g->sect * g->head) <= 0 ||
+	    /* check for zero in F_SECT_PER_TRACK */
+	    (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
 	    g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
 	    /* check if reserved bits are set */
 	    (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
@@ -3243,7 +3253,7 @@
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		mutex_lock(&open_lock);
-		if (lock_fdc(drive, true)) {
+		if (lock_fdc(drive)) {
 			mutex_unlock(&open_lock);
 			return -EINTR;
 		}
@@ -3263,7 +3273,7 @@
 	} else {
 		int oldStretch;
 
-		if (lock_fdc(drive, true))
+		if (lock_fdc(drive))
 			return -EINTR;
 		if (cmd != FDDEFPRM) {
 			/* notice a disk change immediately, else
@@ -3349,7 +3359,7 @@
 	if (type)
 		*g = &floppy_type[type];
 	else {
-		if (lock_fdc(drive, false))
+		if (lock_fdc(drive))
 			return -EINTR;
 		if (poll_drive(false, 0) == -EINTR)
 			return -EINTR;
@@ -3378,6 +3388,24 @@
 	return 0;
 }
 
+static bool valid_floppy_drive_params(const short autodetect[8],
+		int native_format)
+{
+	size_t floppy_type_size = ARRAY_SIZE(floppy_type);
+	size_t i = 0;
+
+	for (i = 0; i < 8; ++i) {
+		if (autodetect[i] < 0 ||
+		    autodetect[i] >= floppy_type_size)
+			return false;
+	}
+
+	if (native_format < 0 || native_format >= floppy_type_size)
+		return false;
+
+	return true;
+}
+
 static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
 		    unsigned long param)
 {
@@ -3433,7 +3461,7 @@
 		if (UDRS->fd_ref != 1)
 			/* somebody else has this drive open */
 			return -EBUSY;
-		if (lock_fdc(drive, true))
+		if (lock_fdc(drive))
 			return -EINTR;
 
 		/* do the actual eject. Fails on
@@ -3445,7 +3473,7 @@
 		process_fd_request();
 		return ret;
 	case FDCLRPRM:
-		if (lock_fdc(drive, true))
+		if (lock_fdc(drive))
 			return -EINTR;
 		current_type[drive] = NULL;
 		floppy_sizes[drive] = MAX_DISK_SIZE << 1;
@@ -3459,6 +3487,9 @@
 					  (struct floppy_struct **)&outparam);
 		if (ret)
 			return ret;
+		memcpy(&inparam.g, outparam,
+				offsetof(struct floppy_struct, name));
+		outparam = &inparam.g;
 		break;
 	case FDMSGON:
 		UDP->flags |= FTD_MSG;
@@ -3467,7 +3498,7 @@
 		UDP->flags &= ~FTD_MSG;
 		return 0;
 	case FDFMTBEG:
-		if (lock_fdc(drive, true))
+		if (lock_fdc(drive))
 			return -EINTR;
 		if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
 			return -EINTR;
@@ -3484,7 +3515,7 @@
 		return do_format(drive, &inparam.f);
 	case FDFMTEND:
 	case FDFLUSH:
-		if (lock_fdc(drive, true))
+		if (lock_fdc(drive))
 			return -EINTR;
 		return invalidate_drive(bdev);
 	case FDSETEMSGTRESH:
@@ -3501,13 +3532,16 @@
 		SUPBOUND(size, strlen((const char *)outparam) + 1);
 		break;
 	case FDSETDRVPRM:
+		if (!valid_floppy_drive_params(inparam.dp.autodetect,
+				inparam.dp.native_format))
+			return -EINVAL;
 		*UDP = inparam.dp;
 		break;
 	case FDGETDRVPRM:
 		outparam = UDP;
 		break;
 	case FDPOLLDRVSTAT:
-		if (lock_fdc(drive, true))
+		if (lock_fdc(drive))
 			return -EINTR;
 		if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
 			return -EINTR;
@@ -3530,7 +3564,7 @@
 	case FDRAWCMD:
 		if (type)
 			return -EINVAL;
-		if (lock_fdc(drive, true))
+		if (lock_fdc(drive))
 			return -EINTR;
 		set_floppy(drive);
 		i = raw_cmd_ioctl(cmd, (void __user *)param);
@@ -3539,7 +3573,7 @@
 		process_fd_request();
 		return i;
 	case FDTWADDLE:
-		if (lock_fdc(drive, true))
+		if (lock_fdc(drive))
 			return -EINTR;
 		twaddle();
 		process_fd_request();
@@ -3566,6 +3600,332 @@
 	return ret;
 }
 
+#ifdef CONFIG_COMPAT
+
+struct compat_floppy_drive_params {
+	char		cmos;
+	compat_ulong_t	max_dtr;
+	compat_ulong_t	hlt;
+	compat_ulong_t	hut;
+	compat_ulong_t	srt;
+	compat_ulong_t	spinup;
+	compat_ulong_t	spindown;
+	unsigned char	spindown_offset;
+	unsigned char	select_delay;
+	unsigned char	rps;
+	unsigned char	tracks;
+	compat_ulong_t	timeout;
+	unsigned char	interleave_sect;
+	struct floppy_max_errors max_errors;
+	char		flags;
+	char		read_track;
+	short		autodetect[8];
+	compat_int_t	checkfreq;
+	compat_int_t	native_format;
+};
+
+struct compat_floppy_drive_struct {
+	signed char	flags;
+	compat_ulong_t	spinup_date;
+	compat_ulong_t	select_date;
+	compat_ulong_t	first_read_date;
+	short		probed_format;
+	short		track;
+	short		maxblock;
+	short		maxtrack;
+	compat_int_t	generation;
+	compat_int_t	keep_data;
+	compat_int_t	fd_ref;
+	compat_int_t	fd_device;
+	compat_int_t	last_checked;
+	compat_caddr_t dmabuf;
+	compat_int_t	bufblocks;
+};
+
+struct compat_floppy_fdc_state {
+	compat_int_t	spec1;
+	compat_int_t	spec2;
+	compat_int_t	dtr;
+	unsigned char	version;
+	unsigned char	dor;
+	compat_ulong_t	address;
+	unsigned int	rawcmd:2;
+	unsigned int	reset:1;
+	unsigned int	need_configure:1;
+	unsigned int	perp_mode:2;
+	unsigned int	has_fifo:1;
+	unsigned int	driver_version;
+	unsigned char	track[4];
+};
+
+struct compat_floppy_write_errors {
+	unsigned int	write_errors;
+	compat_ulong_t	first_error_sector;
+	compat_int_t	first_error_generation;
+	compat_ulong_t	last_error_sector;
+	compat_int_t	last_error_generation;
+	compat_uint_t	badness;
+};
+
+#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
+#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
+#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
+#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
+#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
+#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
+#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
+#define FDWERRORGET32  _IOR(2, 0x17, struct compat_floppy_write_errors)
+
+static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
+		    struct compat_floppy_struct __user *arg)
+{
+	struct floppy_struct v;
+	int drive, type;
+	int err;
+
+	BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
+		     offsetof(struct compat_floppy_struct, name));
+
+	if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
+		return -EPERM;
+
+	memset(&v, 0, sizeof(struct floppy_struct));
+	if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
+		return -EFAULT;
+
+	mutex_lock(&floppy_mutex);
+	drive = (long)bdev->bd_disk->private_data;
+	type = ITYPE(UDRS->fd_device);
+	err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
+			&v, drive, type, bdev);
+	mutex_unlock(&floppy_mutex);
+	return err;
+}
+
+static int compat_get_prm(int drive,
+			  struct compat_floppy_struct __user *arg)
+{
+	struct compat_floppy_struct v;
+	struct floppy_struct *p;
+	int err;
+
+	memset(&v, 0, sizeof(v));
+	mutex_lock(&floppy_mutex);
+	err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
+	if (err) {
+		mutex_unlock(&floppy_mutex);
+		return err;
+	}
+	memcpy(&v, p, offsetof(struct floppy_struct, name));
+	mutex_unlock(&floppy_mutex);
+	if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
+		return -EFAULT;
+	return 0;
+}
+
+static int compat_setdrvprm(int drive,
+			    struct compat_floppy_drive_params __user *arg)
+{
+	struct compat_floppy_drive_params v;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
+		return -EFAULT;
+	if (!valid_floppy_drive_params(v.autodetect, v.native_format))
+		return -EINVAL;
+	mutex_lock(&floppy_mutex);
+	UDP->cmos = v.cmos;
+	UDP->max_dtr = v.max_dtr;
+	UDP->hlt = v.hlt;
+	UDP->hut = v.hut;
+	UDP->srt = v.srt;
+	UDP->spinup = v.spinup;
+	UDP->spindown = v.spindown;
+	UDP->spindown_offset = v.spindown_offset;
+	UDP->select_delay = v.select_delay;
+	UDP->rps = v.rps;
+	UDP->tracks = v.tracks;
+	UDP->timeout = v.timeout;
+	UDP->interleave_sect = v.interleave_sect;
+	UDP->max_errors = v.max_errors;
+	UDP->flags = v.flags;
+	UDP->read_track = v.read_track;
+	memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
+	UDP->checkfreq = v.checkfreq;
+	UDP->native_format = v.native_format;
+	mutex_unlock(&floppy_mutex);
+	return 0;
+}
+
+static int compat_getdrvprm(int drive,
+			    struct compat_floppy_drive_params __user *arg)
+{
+	struct compat_floppy_drive_params v;
+
+	memset(&v, 0, sizeof(struct compat_floppy_drive_params));
+	mutex_lock(&floppy_mutex);
+	v.cmos = UDP->cmos;
+	v.max_dtr = UDP->max_dtr;
+	v.hlt = UDP->hlt;
+	v.hut = UDP->hut;
+	v.srt = UDP->srt;
+	v.spinup = UDP->spinup;
+	v.spindown = UDP->spindown;
+	v.spindown_offset = UDP->spindown_offset;
+	v.select_delay = UDP->select_delay;
+	v.rps = UDP->rps;
+	v.tracks = UDP->tracks;
+	v.timeout = UDP->timeout;
+	v.interleave_sect = UDP->interleave_sect;
+	v.max_errors = UDP->max_errors;
+	v.flags = UDP->flags;
+	v.read_track = UDP->read_track;
+	memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
+	v.checkfreq = UDP->checkfreq;
+	v.native_format = UDP->native_format;
+	mutex_unlock(&floppy_mutex);
+
+	if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
+		return -EFAULT;
+	return 0;
+}
+
+static int compat_getdrvstat(int drive, bool poll,
+			    struct compat_floppy_drive_struct __user *arg)
+{
+	struct compat_floppy_drive_struct v;
+
+	memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
+	mutex_lock(&floppy_mutex);
+
+	if (poll) {
+		if (lock_fdc(drive))
+			goto Eintr;
+		if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
+			goto Eintr;
+		process_fd_request();
+	}
+	v.spinup_date = UDRS->spinup_date;
+	v.select_date = UDRS->select_date;
+	v.first_read_date = UDRS->first_read_date;
+	v.probed_format = UDRS->probed_format;
+	v.track = UDRS->track;
+	v.maxblock = UDRS->maxblock;
+	v.maxtrack = UDRS->maxtrack;
+	v.generation = UDRS->generation;
+	v.keep_data = UDRS->keep_data;
+	v.fd_ref = UDRS->fd_ref;
+	v.fd_device = UDRS->fd_device;
+	v.last_checked = UDRS->last_checked;
+	v.dmabuf = (uintptr_t)UDRS->dmabuf;
+	v.bufblocks = UDRS->bufblocks;
+	mutex_unlock(&floppy_mutex);
+
+	if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
+		return -EFAULT;
+	return 0;
+Eintr:
+	mutex_unlock(&floppy_mutex);
+	return -EINTR;
+}
+
+static int compat_getfdcstat(int drive,
+			    struct compat_floppy_fdc_state __user *arg)
+{
+	struct compat_floppy_fdc_state v32;
+	struct floppy_fdc_state v;
+
+	mutex_lock(&floppy_mutex);
+	v = *UFDCS;
+	mutex_unlock(&floppy_mutex);
+
+	memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
+	v32.spec1 = v.spec1;
+	v32.spec2 = v.spec2;
+	v32.dtr = v.dtr;
+	v32.version = v.version;
+	v32.dor = v.dor;
+	v32.address = v.address;
+	v32.rawcmd = v.rawcmd;
+	v32.reset = v.reset;
+	v32.need_configure = v.need_configure;
+	v32.perp_mode = v.perp_mode;
+	v32.has_fifo = v.has_fifo;
+	v32.driver_version = v.driver_version;
+	memcpy(v32.track, v.track, 4);
+	if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
+		return -EFAULT;
+	return 0;
+}
+
+static int compat_werrorget(int drive,
+			    struct compat_floppy_write_errors __user *arg)
+{
+	struct compat_floppy_write_errors v32;
+	struct floppy_write_errors v;
+
+	memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
+	mutex_lock(&floppy_mutex);
+	v = *UDRWE;
+	mutex_unlock(&floppy_mutex);
+	v32.write_errors = v.write_errors;
+	v32.first_error_sector = v.first_error_sector;
+	v32.first_error_generation = v.first_error_generation;
+	v32.last_error_sector = v.last_error_sector;
+	v32.last_error_generation = v.last_error_generation;
+	v32.badness = v.badness;
+	if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
+		return -EFAULT;
+	return 0;
+}
+
+static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
+		    unsigned long param)
+{
+	int drive = (long)bdev->bd_disk->private_data;
+	switch (cmd) {
+	case FDMSGON:
+	case FDMSGOFF:
+	case FDSETEMSGTRESH:
+	case FDFLUSH:
+	case FDWERRORCLR:
+	case FDEJECT:
+	case FDCLRPRM:
+	case FDFMTBEG:
+	case FDRESET:
+	case FDTWADDLE:
+		return fd_ioctl(bdev, mode, cmd, param);
+	case FDSETMAXERRS:
+	case FDGETMAXERRS:
+	case FDGETDRVTYP:
+	case FDFMTEND:
+	case FDFMTTRK:
+	case FDRAWCMD:
+		return fd_ioctl(bdev, mode, cmd,
+				(unsigned long)compat_ptr(param));
+	case FDSETPRM32:
+	case FDDEFPRM32:
+		return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
+	case FDGETPRM32:
+		return compat_get_prm(drive, compat_ptr(param));
+	case FDSETDRVPRM32:
+		return compat_setdrvprm(drive, compat_ptr(param));
+	case FDGETDRVPRM32:
+		return compat_getdrvprm(drive, compat_ptr(param));
+	case FDPOLLDRVSTAT32:
+		return compat_getdrvstat(drive, true, compat_ptr(param));
+	case FDGETDRVSTAT32:
+		return compat_getdrvstat(drive, false, compat_ptr(param));
+	case FDGETFDCSTAT32:
+		return compat_getfdcstat(drive, compat_ptr(param));
+	case FDWERRORGET32:
+		return compat_werrorget(drive, compat_ptr(param));
+	}
+	return -EINVAL;
+}
+#endif
+
 static void __init config_types(void)
 {
 	bool has_drive = false;
@@ -3705,21 +4065,22 @@
 	if (UFDCS->rawcmd == 1)
 		UFDCS->rawcmd = 2;
 
-	if (!(mode & FMODE_NDELAY)) {
-		if (mode & (FMODE_READ|FMODE_WRITE)) {
-			UDRS->last_checked = 0;
-			clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
-			check_disk_change(bdev);
-			if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
-				goto out;
-			if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
-				goto out;
-		}
-		res = -EROFS;
-		if ((mode & FMODE_WRITE) &&
-		    !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
+	if (mode & (FMODE_READ|FMODE_WRITE)) {
+		UDRS->last_checked = 0;
+		clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
+		check_disk_change(bdev);
+		if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
+			goto out;
+		if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
 			goto out;
 	}
+
+	res = -EROFS;
+
+	if ((mode & FMODE_WRITE) &&
+			!test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
+		goto out;
+
 	mutex_unlock(&open_lock);
 	mutex_unlock(&floppy_mutex);
 	return 0;
@@ -3747,7 +4108,8 @@
 		return DISK_EVENT_MEDIA_CHANGE;
 
 	if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
-		lock_fdc(drive, false);
+		if (lock_fdc(drive))
+			return -EINTR;
 		poll_drive(false, 0);
 		process_fd_request();
 	}
@@ -3846,7 +4208,9 @@
 			 "VFS: revalidate called on non-open device.\n"))
 			return -EFAULT;
 
-		lock_fdc(drive, false);
+		res = lock_fdc(drive);
+		if (res)
+			return res;
 		cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
 		      test_bit(FD_VERIFY_BIT, &UDRS->flags));
 		if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
@@ -3882,6 +4246,9 @@
 	.getgeo			= fd_getgeo,
 	.check_events		= floppy_check_events,
 	.revalidate_disk	= floppy_revalidate,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= fd_compat_ioctl,
+#endif
 };
 
 /*
--- linux-4.4.0.orig/drivers/block/loop.c
+++ linux-4.4.0/drivers/block/loop.c
@@ -263,7 +263,7 @@
 	struct iov_iter i;
 	ssize_t bw;
 
-	iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len);
+	iov_iter_bvec(&i, ITER_BVEC | WRITE, bvec, 1, bvec->bv_len);
 
 	file_start_write(file);
 	bw = vfs_iter_write(file, &i, ppos);
@@ -488,6 +488,12 @@
 	bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
 	iov_iter_bvec(&iter, ITER_BVEC | rw, bvec,
 		      bio_segments(bio), blk_rq_bytes(cmd->rq));
+	/*
+	 * This bio may be started from the middle of the 'bvec'
+	 * because of bio splitting, so offset from the bvec must
+	 * be passed to iov iterator
+	 */
+	iter.iov_offset = bio->bi_iter.bi_bvec_done;
 
 	cmd->iocb.ki_pos = pos;
 	cmd->iocb.ki_filp = file;
@@ -556,7 +562,7 @@
 }
 
 struct switch_request {
-	struct file *file;
+	struct file *file, *virt_file;
 	struct completion wait;
 };
 
@@ -582,6 +588,7 @@
 	mapping = file->f_mapping;
 	mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
 	lo->lo_backing_file = file;
+	lo->lo_backing_virt_file = p->virt_file;
 	lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ?
 		mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
 	lo->old_gfp_mask = mapping_gfp_mask(mapping);
@@ -594,11 +601,13 @@
  * First it needs to flush existing IO, it does this by sending a magic
  * BIO down the pipe. The completion of this BIO does the actual switch.
  */
-static int loop_switch(struct loop_device *lo, struct file *file)
+static int loop_switch(struct loop_device *lo, struct file *file,
+		       struct file *virt_file)
 {
 	struct switch_request w;
 
 	w.file = file;
+	w.virt_file = virt_file;
 
 	/* freeze queue and wait for completion of scheduled requests */
 	blk_mq_freeze_queue(lo->lo_queue);
@@ -617,7 +626,19 @@
  */
 static int loop_flush(struct loop_device *lo)
 {
-	return loop_switch(lo, NULL);
+	/* loop not yet configured, no running thread, nothing to flush */
+	if (lo->lo_state != Lo_bound)
+		return 0;
+	return loop_switch(lo, NULL, NULL);
+}
+
+static struct file *loop_real_file(struct file *file)
+{
+	struct file *f = NULL;
+
+	if (file->f_path.dentry->d_sb->s_op->real_loop)
+		f = file->f_path.dentry->d_sb->s_op->real_loop(file);
+	return f;
 }
 
 static void loop_reread_partitions(struct loop_device *lo,
@@ -642,6 +663,36 @@
 			__func__, lo->lo_number, lo->lo_file_name, rc);
 }
 
+static inline int is_loop_device(struct file *file)
+{
+	struct inode *i = file->f_mapping->host;
+
+	return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR;
+}
+
+static int loop_validate_file(struct file *file, struct block_device *bdev)
+{
+	struct inode    *inode = file->f_mapping->host;
+	struct file     *f = file;
+
+	/* Avoid recursion */
+	while (is_loop_device(f)) {
+		struct loop_device *l;
+
+		if (f->f_mapping->host->i_bdev == bdev)
+			return -EBADF;
+
+		l = f->f_mapping->host->i_bdev->bd_disk->private_data;
+		if (l->lo_state == Lo_unbound) {
+			return -EINVAL;
+		}
+		f = l->lo_backing_file;
+	}
+	if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
+		return -EINVAL;
+	return 0;
+}
+
 /*
  * loop_change_fd switched the backing store of a loopback device to
  * a new file. This is useful for operating system installers to free up
@@ -654,6 +705,7 @@
 			  unsigned int arg)
 {
 	struct file	*file, *old_file;
+	struct file	*f, *virt_file = NULL, *old_virt_file;
 	struct inode	*inode;
 	int		error;
 
@@ -671,40 +723,64 @@
 	if (!file)
 		goto out;
 
+	error = loop_validate_file(file, bdev);
+	if (error)
+		goto out_putf;
+
+	f = loop_real_file(file);
+	if (f) {
+		virt_file = file;
+		file = f;
+		get_file(file);
+	}
+
 	inode = file->f_mapping->host;
 	old_file = lo->lo_backing_file;
+	old_virt_file = lo->lo_backing_virt_file;
 
 	error = -EINVAL;
 
-	if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
-		goto out_putf;
-
 	/* size of the new backing store needs to be the same */
 	if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
 		goto out_putf;
 
 	/* and ... switch */
-	error = loop_switch(lo, file);
+	error = loop_switch(lo, file, virt_file);
 	if (error)
 		goto out_putf;
 
 	fput(old_file);
+	if (old_virt_file)
+		fput(old_virt_file);
 	if (lo->lo_flags & LO_FLAGS_PARTSCAN)
 		loop_reread_partitions(lo, bdev);
 	return 0;
 
  out_putf:
 	fput(file);
+	if (virt_file)
+		fput(virt_file);
  out:
 	return error;
 }
 
-static inline int is_loop_device(struct file *file)
+/*
+ * for AUFS
+ * no get/put for file.
+ */
+struct file *loop_backing_file(struct super_block *sb)
 {
-	struct inode *i = file->f_mapping->host;
+	struct file *ret;
+	struct loop_device *l;
 
-	return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR;
+	ret = NULL;
+	if (MAJOR(sb->s_dev) == LOOP_MAJOR) {
+		l = sb->s_bdev->bd_disk->private_data;
+		ret = l->lo_backing_file;
+	}
+	return ret;
 }
+EXPORT_SYMBOL(loop_backing_file);
 
 /* loop sysfs attributes */
 
@@ -802,16 +878,17 @@
 	.attrs= loop_attrs,
 };
 
-static int loop_sysfs_init(struct loop_device *lo)
+static void loop_sysfs_init(struct loop_device *lo)
 {
-	return sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj,
-				  &loop_attribute_group);
+	lo->sysfs_inited = !sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj,
+						&loop_attribute_group);
 }
 
 static void loop_sysfs_exit(struct loop_device *lo)
 {
-	sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj,
-			   &loop_attribute_group);
+	if (lo->sysfs_inited)
+		sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj,
+				   &loop_attribute_group);
 }
 
 static void loop_config_discard(struct loop_device *lo)
@@ -863,7 +940,7 @@
 static int loop_set_fd(struct loop_device *lo, fmode_t mode,
 		       struct block_device *bdev, unsigned int arg)
 {
-	struct file	*file, *f;
+	struct file	*file, *f, *virt_file = NULL;
 	struct inode	*inode;
 	struct address_space *mapping;
 	unsigned lo_blocksize;
@@ -878,34 +955,24 @@
 	file = fget(arg);
 	if (!file)
 		goto out;
+	f = loop_real_file(file);
+	if (f) {
+		virt_file = file;
+		file = f;
+		get_file(file);
+	}
 
 	error = -EBUSY;
 	if (lo->lo_state != Lo_unbound)
 		goto out_putf;
 
-	/* Avoid recursion */
-	f = file;
-	while (is_loop_device(f)) {
-		struct loop_device *l;
-
-		if (f->f_mapping->host->i_bdev == bdev)
-			goto out_putf;
-
-		l = f->f_mapping->host->i_bdev->bd_disk->private_data;
-		if (l->lo_state == Lo_unbound) {
-			error = -EINVAL;
-			goto out_putf;
-		}
-		f = l->lo_backing_file;
-	}
+	error = loop_validate_file(file, bdev);
+	if (error)
+		goto out_putf;
 
 	mapping = file->f_mapping;
 	inode = mapping->host;
 
-	error = -EINVAL;
-	if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
-		goto out_putf;
-
 	if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) ||
 	    !file->f_op->write_iter)
 		lo_flags |= LO_FLAGS_READ_ONLY;
@@ -930,6 +997,7 @@
 	lo->lo_device = bdev;
 	lo->lo_flags = lo_flags;
 	lo->lo_backing_file = file;
+	lo->lo_backing_virt_file = virt_file;
 	lo->transfer = NULL;
 	lo->ioctl = NULL;
 	lo->lo_sizelimit = 0;
@@ -962,6 +1030,8 @@
 
  out_putf:
 	fput(file);
+	if (virt_file)
+		fput(virt_file);
  out:
 	/* This is safe: open() is still holding a reference. */
 	module_put(THIS_MODULE);
@@ -1008,6 +1078,7 @@
 static int loop_clr_fd(struct loop_device *lo)
 {
 	struct file *filp = lo->lo_backing_file;
+	struct file *virt_filp = lo->lo_backing_virt_file;
 	gfp_t gfp = lo->old_gfp_mask;
 	struct block_device *bdev = lo->lo_device;
 
@@ -1039,6 +1110,7 @@
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_rundown;
 	lo->lo_backing_file = NULL;
+	lo->lo_backing_virt_file = NULL;
 	spin_unlock_irq(&lo->lo_lock);
 
 	loop_release_xfer(lo);
@@ -1083,6 +1155,8 @@
 	 * bd_mutex which is usually taken before lo_ctl_mutex.
 	 */
 	fput(filp);
+	if (virt_filp)
+		fput(virt_filp);
 	return 0;
 }
 
@@ -1102,29 +1176,38 @@
 	if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
 		return -EINVAL;
 
+	/* I/O need to be drained during transfer transition */
+	blk_mq_freeze_queue(lo->lo_queue);
+
 	err = loop_release_xfer(lo);
 	if (err)
-		return err;
+		goto exit;
 
 	if (info->lo_encrypt_type) {
 		unsigned int type = info->lo_encrypt_type;
 
-		if (type >= MAX_LO_CRYPT)
-			return -EINVAL;
+		if (type >= MAX_LO_CRYPT) {
+			err = -EINVAL;
+			goto exit;
+		}
 		xfer = xfer_funcs[type];
-		if (xfer == NULL)
-			return -EINVAL;
+		if (xfer == NULL) {
+			err = -EINVAL;
+			goto exit;
+		}
 	} else
 		xfer = NULL;
 
 	err = loop_init_xfer(lo, xfer, info);
 	if (err)
-		return err;
+		goto exit;
 
 	if (lo->lo_offset != info->lo_offset ||
 	    lo->lo_sizelimit != info->lo_sizelimit)
-		if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
-			return -EFBIG;
+		if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) {
+			err = -EFBIG;
+			goto exit;
+		}
 
 	loop_config_discard(lo);
 
@@ -1142,13 +1225,6 @@
 	     (info->lo_flags & LO_FLAGS_AUTOCLEAR))
 		lo->lo_flags ^= LO_FLAGS_AUTOCLEAR;
 
-	if ((info->lo_flags & LO_FLAGS_PARTSCAN) &&
-	     !(lo->lo_flags & LO_FLAGS_PARTSCAN)) {
-		lo->lo_flags |= LO_FLAGS_PARTSCAN;
-		lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
-		loop_reread_partitions(lo, lo->lo_device);
-	}
-
 	lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
 	lo->lo_init[0] = info->lo_init[0];
 	lo->lo_init[1] = info->lo_init[1];
@@ -1161,7 +1237,17 @@
 	/* update dio if lo_offset or transfer is changed */
 	__loop_update_dio(lo, lo->use_dio);
 
-	return 0;
+ exit:
+	blk_mq_unfreeze_queue(lo->lo_queue);
+
+	if (!err && (info->lo_flags & LO_FLAGS_PARTSCAN) &&
+	     !(lo->lo_flags & LO_FLAGS_PARTSCAN)) {
+		lo->lo_flags |= LO_FLAGS_PARTSCAN;
+		lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
+		loop_reread_partitions(lo, lo->lo_device);
+	}
+
+	return err;
 }
 
 static int
@@ -1527,6 +1613,7 @@
 		arg = (unsigned long) compat_ptr(arg);
 	case LOOP_SET_FD:
 	case LOOP_CHANGE_FD:
+	case LOOP_SET_DIRECT_IO:
 		err = lo_ioctl(bdev, mode, cmd, arg);
 		break;
 	default:
@@ -1555,9 +1642,8 @@
 	return err;
 }
 
-static void lo_release(struct gendisk *disk, fmode_t mode)
+static void __lo_release(struct loop_device *lo)
 {
-	struct loop_device *lo = disk->private_data;
 	int err;
 
 	if (atomic_dec_return(&lo->lo_refcnt))
@@ -1583,6 +1669,13 @@
 	mutex_unlock(&lo->lo_ctl_mutex);
 }
 
+static void lo_release(struct gendisk *disk, fmode_t mode)
+{
+	mutex_lock(&loop_index_mutex);
+	__lo_release(disk->private_data);
+	mutex_unlock(&loop_index_mutex);
+}
+
 static const struct block_device_operations lo_fops = {
 	.owner =	THIS_MODULE,
 	.open =		lo_open,
@@ -1651,7 +1744,7 @@
 	blk_mq_start_request(bd->rq);
 
 	if (lo->lo_state != Lo_bound)
-		return -EIO;
+		return BLK_MQ_RQ_QUEUE_ERROR;
 
 	if (lo->use_dio && !(cmd->rq->cmd_flags & (REQ_FLUSH |
 					REQ_DISCARD)))
--- linux-4.4.0.orig/drivers/block/loop.h
+++ linux-4.4.0/drivers/block/loop.h
@@ -46,7 +46,7 @@
 	int		(*ioctl)(struct loop_device *, int cmd, 
 				 unsigned long arg); 
 
-	struct file *	lo_backing_file;
+	struct file *	lo_backing_file, *lo_backing_virt_file;
 	struct block_device *lo_device;
 	unsigned	lo_blocksize;
 	void		*key_data; 
@@ -59,6 +59,7 @@
 	struct kthread_worker	worker;
 	struct task_struct	*worker_task;
 	bool			use_dio;
+	bool			sysfs_inited;
 
 	struct request_queue	*lo_queue;
 	struct blk_mq_tag_set	tag_set;
--- linux-4.4.0.orig/drivers/block/mtip32xx/mtip32xx.c
+++ linux-4.4.0/drivers/block/mtip32xx/mtip32xx.c
@@ -173,7 +173,13 @@
 {
 	struct request *rq;
 
-	rq = blk_mq_alloc_request(dd->queue, 0, __GFP_RECLAIM, true);
+	if (mtip_check_surprise_removal(dd->pdev))
+		return NULL;
+
+	rq = blk_mq_alloc_request(dd->queue, 0, BLK_MQ_REQ_RESERVED);
+	if (IS_ERR(rq))
+		return NULL;
+
 	return blk_mq_rq_to_pdu(rq);
 }
 
@@ -233,15 +239,9 @@
 			"Command tag %d failed due to TFE\n", tag);
 	}
 
-	/* Unmap the DMA scatter list entries */
-	dma_unmap_sg(&dd->pdev->dev, cmd->sg, cmd->scatter_ents, cmd->direction);
-
 	rq = mtip_rq_from_tag(dd, tag);
 
-	if (unlikely(cmd->unaligned))
-		up(&port->cmd_slot_unal);
-
-	blk_mq_end_request(rq, status ? -EIO : 0);
+	blk_mq_complete_request(rq, status);
 }
 
 /*
@@ -581,6 +581,8 @@
 		dev_warn(&port->dd->pdev->dev,
 			"Internal command %d completed with TFE\n", tag);
 
+	command->comp_func = NULL;
+	command->comp_data = NULL;
 	complete(waiting);
 }
 
@@ -618,8 +620,6 @@
 
 	port = dd->port;
 
-	set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
-
 	if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
 		cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL);
 		dbg_printk(MTIP_DRV_NAME " TFE for the internal command\n");
@@ -628,7 +628,7 @@
 			cmd->comp_func(port, MTIP_TAG_INTERNAL,
 					cmd, PORT_IRQ_TF_ERR);
 		}
-		goto handle_tfe_exit;
+		return;
 	}
 
 	/* clear the tag accumulator */
@@ -701,7 +701,7 @@
 			fail_reason = "thermal shutdown";
 		}
 		if (buf[288] == 0xBF) {
-			set_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag);
+			set_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag);
 			dev_info(&dd->pdev->dev,
 				"Drive indicates rebuild has failed. Secure erase required.\n");
 			fail_all_ncq_cmds = 1;
@@ -771,11 +771,6 @@
 		}
 	}
 	print_tags(dd, "reissued (TFE)", tagaccum, cmd_cnt);
-
-handle_tfe_exit:
-	/* clear eh_active */
-	clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
-	wake_up_interruptible(&port->svc_wait);
 }
 
 /*
@@ -1007,6 +1002,7 @@
 			(fis->features == 0x27 || fis->features == 0x72 ||
 			 fis->features == 0x62 || fis->features == 0x26))) {
 		clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
+		clear_bit(MTIP_DDF_REBUILD_FAILED_BIT, &port->dd->dd_flag);
 		/* Com reset after secure erase or lowlevel format */
 		mtip_restart_port(port);
 		clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
@@ -1021,12 +1017,14 @@
  *
  * @port    Pointer to port data structure
  * @timeout Max duration to wait (ms)
+ * @atomic  gfp_t flag to indicate blockable context or not
  *
  * return value
  *	0	Success
  *	-EBUSY  Commands still active
  */
-static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout)
+static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout,
+								gfp_t atomic)
 {
 	unsigned long to;
 	unsigned int n;
@@ -1037,16 +1035,21 @@
 	to = jiffies + msecs_to_jiffies(timeout);
 	do {
 		if (test_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags) &&
-			test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) {
+			test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags) &&
+			atomic == GFP_KERNEL) {
 			msleep(20);
 			continue; /* svc thd is actively issuing commands */
 		}
 
-		msleep(100);
+		if (atomic == GFP_KERNEL)
+			msleep(100);
+		else {
+			cpu_relax();
+			udelay(100);
+		}
+
 		if (mtip_check_surprise_removal(port->dd->pdev))
 			goto err_fault;
-		if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag))
-			goto err_fault;
 
 		/*
 		 * Ignore s_active bit 0 of array element 0.
@@ -1099,6 +1102,7 @@
 	struct mtip_cmd *int_cmd;
 	struct driver_data *dd = port->dd;
 	int rv = 0;
+	unsigned long start;
 
 	/* Make sure the buffer is 8 byte aligned. This is asic specific. */
 	if (buffer & 0x00000007) {
@@ -1107,6 +1111,10 @@
 	}
 
 	int_cmd = mtip_get_int_command(dd);
+	if (!int_cmd) {
+		dbg_printk(MTIP_DRV_NAME "Unable to allocate tag for PIO cmd\n");
+		return -EFAULT;
+	}
 
 	set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
 
@@ -1119,7 +1127,7 @@
 		if (fis->command != ATA_CMD_STANDBYNOW1) {
 			/* wait for io to complete if non atomic */
 			if (mtip_quiesce_io(port,
-					MTIP_QUIESCE_IO_TIMEOUT_MS) < 0) {
+				MTIP_QUIESCE_IO_TIMEOUT_MS, atomic) < 0) {
 				dev_warn(&dd->pdev->dev,
 					"Failed to quiesce IO\n");
 				mtip_put_int_command(dd, int_cmd);
@@ -1162,6 +1170,8 @@
 	/* Populate the command header */
 	int_cmd->command_header->byte_count = 0;
 
+	start = jiffies;
+
 	/* Issue the command to the hardware */
 	mtip_issue_non_ncq_command(port, MTIP_TAG_INTERNAL);
 
@@ -1170,10 +1180,12 @@
 		if ((rv = wait_for_completion_interruptible_timeout(
 				&wait,
 				msecs_to_jiffies(timeout))) <= 0) {
+
 			if (rv == -ERESTARTSYS) { /* interrupted */
 				dev_err(&dd->pdev->dev,
-					"Internal command [%02X] was interrupted after %lu ms\n",
-					fis->command, timeout);
+					"Internal command [%02X] was interrupted after %u ms\n",
+					fis->command,
+					jiffies_to_msecs(jiffies - start));
 				rv = -EINTR;
 				goto exec_ic_exit;
 			} else if (rv == 0) /* timeout */
@@ -2897,6 +2909,42 @@
 	return -EFAULT;
 }
 
+static void mtip_softirq_done_fn(struct request *rq)
+{
+	struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
+	struct driver_data *dd = rq->q->queuedata;
+
+	/* Unmap the DMA scatter list entries */
+	dma_unmap_sg(&dd->pdev->dev, cmd->sg, cmd->scatter_ents,
+							cmd->direction);
+
+	if (unlikely(cmd->unaligned))
+		up(&dd->port->cmd_slot_unal);
+
+	blk_mq_end_request(rq, rq->errors);
+}
+
+static void mtip_abort_cmd(struct request *req, void *data,
+							bool reserved)
+{
+	struct driver_data *dd = data;
+
+	dbg_printk(MTIP_DRV_NAME " Aborting request, tag = %d\n", req->tag);
+
+	clear_bit(req->tag, dd->port->cmds_to_issue);
+	req->errors = -EIO;
+	mtip_softirq_done_fn(req);
+}
+
+static void mtip_queue_cmd(struct request *req, void *data,
+							bool reserved)
+{
+	struct driver_data *dd = data;
+
+	set_bit(req->tag, dd->port->cmds_to_issue);
+	blk_abort_request(req);
+}
+
 /*
  * service thread to issue queued commands
  *
@@ -2909,7 +2957,7 @@
 static int mtip_service_thread(void *data)
 {
 	struct driver_data *dd = (struct driver_data *)data;
-	unsigned long slot, slot_start, slot_wrap;
+	unsigned long slot, slot_start, slot_wrap, to;
 	unsigned int num_cmd_slots = dd->slot_groups * 32;
 	struct mtip_port *port = dd->port;
 
@@ -2924,9 +2972,7 @@
 		 * is in progress nor error handling is active
 		 */
 		wait_event_interruptible(port->svc_wait, (port->flags) &&
-			!(port->flags & MTIP_PF_PAUSE_IO));
-
-		set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags);
+			(port->flags & MTIP_PF_SVC_THD_WORK));
 
 		if (kthread_should_stop() ||
 			test_bit(MTIP_PF_SVC_THD_STOP_BIT, &port->flags))
@@ -2936,6 +2982,8 @@
 				&dd->dd_flag)))
 			goto st_out;
 
+		set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags);
+
 restart_eh:
 		/* Demux bits: start with error handling */
 		if (test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags)) {
@@ -2946,6 +2994,32 @@
 		if (test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags))
 			goto restart_eh;
 
+		if (test_bit(MTIP_PF_TO_ACTIVE_BIT, &port->flags)) {
+			to = jiffies + msecs_to_jiffies(5000);
+
+			do {
+				mdelay(100);
+			} while (atomic_read(&dd->irq_workers_active) != 0 &&
+				time_before(jiffies, to));
+
+			if (atomic_read(&dd->irq_workers_active) != 0)
+				dev_warn(&dd->pdev->dev,
+					"Completion workers still active!");
+
+			spin_lock(dd->queue->queue_lock);
+			blk_mq_all_tag_busy_iter(*dd->tags.tags,
+							mtip_queue_cmd, dd);
+			spin_unlock(dd->queue->queue_lock);
+
+			set_bit(MTIP_PF_ISSUE_CMDS_BIT, &dd->port->flags);
+
+			if (mtip_device_reset(dd))
+				blk_mq_all_tag_busy_iter(*dd->tags.tags,
+							mtip_abort_cmd, dd);
+
+			clear_bit(MTIP_PF_TO_ACTIVE_BIT, &dd->port->flags);
+		}
+
 		if (test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) {
 			slot = 1;
 			/* used to restrict the loop to one iteration */
@@ -2978,10 +3052,8 @@
 		}
 
 		if (test_bit(MTIP_PF_REBUILD_BIT, &port->flags)) {
-			if (mtip_ftl_rebuild_poll(dd) < 0)
-				set_bit(MTIP_DDF_REBUILD_FAILED_BIT,
-							&dd->dd_flag);
-			clear_bit(MTIP_PF_REBUILD_BIT, &port->flags);
+			if (mtip_ftl_rebuild_poll(dd) == 0)
+				clear_bit(MTIP_PF_REBUILD_BIT, &port->flags);
 		}
 	}
 
@@ -3096,7 +3168,7 @@
 		if (buf[288] == 0xBF) {
 			dev_info(&dd->pdev->dev,
 				"Drive indicates rebuild has failed.\n");
-			/* TODO */
+			set_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag);
 		}
 	}
 
@@ -3270,20 +3342,25 @@
 	return rv;
 }
 
-static void mtip_standby_drive(struct driver_data *dd)
+static int mtip_standby_drive(struct driver_data *dd)
 {
-	if (dd->sr)
-		return;
+	int rv = 0;
 
+	if (dd->sr || !dd->port)
+		return -ENODEV;
 	/*
 	 * Send standby immediate (E0h) to the drive so that it
 	 * saves its state.
 	 */
 	if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags) &&
-	    !test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))
-		if (mtip_standby_immediate(dd->port))
+	    !test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag) &&
+	    !test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag)) {
+		rv = mtip_standby_immediate(dd->port);
+		if (rv)
 			dev_warn(&dd->pdev->dev,
 				"STANDBY IMMEDIATE failed\n");
+	}
+	return rv;
 }
 
 /*
@@ -3296,10 +3373,6 @@
  */
 static int mtip_hw_exit(struct driver_data *dd)
 {
-	/*
-	 * Send standby immediate (E0h) to the drive so that it
-	 * saves its state.
-	 */
 	if (!dd->sr) {
 		/* de-initialize the port. */
 		mtip_deinit_port(dd->port);
@@ -3341,8 +3414,7 @@
 	 * Send standby immediate (E0h) to the drive so that it
 	 * saves its state.
 	 */
-	if (!dd->sr && dd->port)
-		mtip_standby_immediate(dd->port);
+	mtip_standby_drive(dd);
 
 	return 0;
 }
@@ -3365,7 +3437,7 @@
 	 * Send standby immediate (E0h) to the drive
 	 * so that it saves its state.
 	 */
-	if (mtip_standby_immediate(dd->port) != 0) {
+	if (mtip_standby_drive(dd) != 0) {
 		dev_err(&dd->pdev->dev,
 			"Failed standby-immediate command\n");
 		return -EFAULT;
@@ -3603,6 +3675,28 @@
 	return 0;
 }
 
+static int mtip_block_open(struct block_device *dev, fmode_t mode)
+{
+	struct driver_data *dd;
+
+	if (dev && dev->bd_disk) {
+		dd = (struct driver_data *) dev->bd_disk->private_data;
+
+		if (dd) {
+			if (test_bit(MTIP_DDF_REMOVAL_BIT,
+							&dd->dd_flag)) {
+				return -ENODEV;
+			}
+			return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+void mtip_block_release(struct gendisk *disk, fmode_t mode)
+{
+}
+
 /*
  * Block device operation function.
  *
@@ -3610,6 +3704,8 @@
  * layer.
  */
 static const struct block_device_operations mtip_block_ops = {
+	.open		= mtip_block_open,
+	.release	= mtip_block_release,
 	.ioctl		= mtip_block_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= mtip_block_compat_ioctl,
@@ -3671,10 +3767,9 @@
 				rq_data_dir(rq))) {
 			return -ENODATA;
 		}
-		if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag)))
+		if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag) ||
+			test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)))
 			return -ENODATA;
-		if (test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag))
-			return -ENXIO;
 	}
 
 	if (rq->cmd_flags & REQ_DISCARD) {
@@ -3786,11 +3881,33 @@
 	return 0;
 }
 
+static enum blk_eh_timer_return mtip_cmd_timeout(struct request *req,
+								bool reserved)
+{
+	struct driver_data *dd = req->q->queuedata;
+	int ret = BLK_EH_RESET_TIMER;
+
+	if (reserved)
+		goto exit_handler;
+
+	if (test_bit(req->tag, dd->port->cmds_to_issue))
+		goto exit_handler;
+
+	if (test_and_set_bit(MTIP_PF_TO_ACTIVE_BIT, &dd->port->flags))
+		goto exit_handler;
+
+	wake_up_interruptible(&dd->port->svc_wait);
+exit_handler:
+	return ret;
+}
+
 static struct blk_mq_ops mtip_mq_ops = {
 	.queue_rq	= mtip_queue_rq,
 	.map_queue	= blk_mq_map_queue,
 	.init_request	= mtip_init_cmd,
 	.exit_request	= mtip_free_cmd,
+	.complete	= mtip_softirq_done_fn,
+	.timeout        = mtip_cmd_timeout,
 };
 
 /*
@@ -3857,7 +3974,6 @@
 
 	mtip_hw_debugfs_init(dd);
 
-skip_create_disk:
 	memset(&dd->tags, 0, sizeof(dd->tags));
 	dd->tags.ops = &mtip_mq_ops;
 	dd->tags.nr_hw_queues = 1;
@@ -3867,12 +3983,13 @@
 	dd->tags.numa_node = dd->numa_node;
 	dd->tags.flags = BLK_MQ_F_SHOULD_MERGE;
 	dd->tags.driver_data = dd;
+	dd->tags.timeout = MTIP_NCQ_CMD_TIMEOUT_MS;
 
 	rv = blk_mq_alloc_tag_set(&dd->tags);
 	if (rv) {
 		dev_err(&dd->pdev->dev,
 			"Unable to allocate request queue\n");
-		goto block_queue_alloc_init_error;
+		goto block_queue_alloc_tag_error;
 	}
 
 	/* Allocate the request queue. */
@@ -3887,6 +4004,7 @@
 	dd->disk->queue		= dd->queue;
 	dd->queue->queuedata	= dd;
 
+skip_create_disk:
 	/* Initialize the protocol layer. */
 	wait_for_rebuild = mtip_hw_get_identify(dd);
 	if (wait_for_rebuild < 0) {
@@ -3983,8 +4101,9 @@
 read_capacity_error:
 init_hw_cmds_error:
 	blk_cleanup_queue(dd->queue);
-	blk_mq_free_tag_set(&dd->tags);
 block_queue_alloc_init_error:
+	blk_mq_free_tag_set(&dd->tags);
+block_queue_alloc_tag_error:
 	mtip_hw_debugfs_exit(dd);
 disk_index_error:
 	spin_lock(&rssd_index_lock);
@@ -4001,6 +4120,22 @@
 	return rv;
 }
 
+static void mtip_no_dev_cleanup(struct request *rq, void *data, bool reserv)
+{
+	struct driver_data *dd = (struct driver_data *)data;
+	struct mtip_cmd *cmd;
+
+	if (likely(!reserv))
+		blk_mq_complete_request(rq, -ENODEV);
+	else if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &dd->port->flags)) {
+
+		cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL);
+		if (cmd->comp_func)
+			cmd->comp_func(dd->port, MTIP_TAG_INTERNAL,
+					cmd, -ENODEV);
+	}
+}
+
 /*
  * Block layer deinitialization function.
  *
@@ -4032,12 +4167,23 @@
 		}
 	}
 
-	if (!dd->sr)
-		mtip_standby_drive(dd);
+	if (!dd->sr) {
+		/*
+		 * Explicitly wait here for IOs to quiesce,
+		 * as mtip_standby_drive usually won't wait for IOs.
+		 */
+		if (!mtip_quiesce_io(dd->port, MTIP_QUIESCE_IO_TIMEOUT_MS,
+								GFP_KERNEL))
+			mtip_standby_drive(dd);
+	}
 	else
 		dev_info(&dd->pdev->dev, "device %s surprise removal\n",
 						dd->disk->disk_name);
 
+	blk_mq_freeze_queue_start(dd->queue);
+	blk_mq_stop_hw_queues(dd->queue);
+	blk_mq_all_tag_busy_iter(dd->tags.tags[0], mtip_no_dev_cleanup, dd);
+
 	/*
 	 * Delete our gendisk structure. This also removes the device
 	 * from /dev
@@ -4047,7 +4193,8 @@
 		dd->bdev = NULL;
 	}
 	if (dd->disk) {
-		del_gendisk(dd->disk);
+		if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag))
+			del_gendisk(dd->disk);
 		if (dd->disk->queue) {
 			blk_cleanup_queue(dd->queue);
 			blk_mq_free_tag_set(&dd->tags);
@@ -4088,7 +4235,8 @@
 		dev_info(&dd->pdev->dev,
 			"Shutting down %s ...\n", dd->disk->disk_name);
 
-		del_gendisk(dd->disk);
+		if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag))
+			del_gendisk(dd->disk);
 		if (dd->disk->queue) {
 			blk_cleanup_queue(dd->queue);
 			blk_mq_free_tag_set(&dd->tags);
@@ -4433,7 +4581,7 @@
 	struct driver_data *dd = pci_get_drvdata(pdev);
 	unsigned long flags, to;
 
-	set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
+	set_bit(MTIP_DDF_REMOVAL_BIT, &dd->dd_flag);
 
 	spin_lock_irqsave(&dev_lock, flags);
 	list_del_init(&dd->online_list);
@@ -4450,12 +4598,17 @@
 	} while (atomic_read(&dd->irq_workers_active) != 0 &&
 		time_before(jiffies, to));
 
+	if (!dd->sr)
+		fsync_bdev(dd->bdev);
+
 	if (atomic_read(&dd->irq_workers_active) != 0) {
 		dev_warn(&dd->pdev->dev,
 			"Completion workers still active!\n");
 	}
 
-	blk_mq_stop_hw_queues(dd->queue);
+	blk_set_queue_dying(dd->queue);
+	set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
+
 	/* Clean up the block layer. */
 	mtip_block_remove(dd);
 
--- linux-4.4.0.orig/drivers/block/mtip32xx/mtip32xx.h
+++ linux-4.4.0/drivers/block/mtip32xx/mtip32xx.h
@@ -134,16 +134,24 @@
 	MTIP_PF_EH_ACTIVE_BIT       = 1, /* error handling */
 	MTIP_PF_SE_ACTIVE_BIT       = 2, /* secure erase */
 	MTIP_PF_DM_ACTIVE_BIT       = 3, /* download microcde */
+	MTIP_PF_TO_ACTIVE_BIT       = 9, /* timeout handling */
 	MTIP_PF_PAUSE_IO      =	((1 << MTIP_PF_IC_ACTIVE_BIT) |
 				(1 << MTIP_PF_EH_ACTIVE_BIT) |
 				(1 << MTIP_PF_SE_ACTIVE_BIT) |
-				(1 << MTIP_PF_DM_ACTIVE_BIT)),
+				(1 << MTIP_PF_DM_ACTIVE_BIT) |
+				(1 << MTIP_PF_TO_ACTIVE_BIT)),
 
 	MTIP_PF_SVC_THD_ACTIVE_BIT  = 4,
 	MTIP_PF_ISSUE_CMDS_BIT      = 5,
 	MTIP_PF_REBUILD_BIT         = 6,
 	MTIP_PF_SVC_THD_STOP_BIT    = 8,
 
+	MTIP_PF_SVC_THD_WORK	= ((1 << MTIP_PF_EH_ACTIVE_BIT) |
+				  (1 << MTIP_PF_ISSUE_CMDS_BIT) |
+				  (1 << MTIP_PF_REBUILD_BIT) |
+				  (1 << MTIP_PF_SVC_THD_STOP_BIT) |
+				  (1 << MTIP_PF_TO_ACTIVE_BIT)),
+
 	/* below are bit numbers in 'dd_flag' defined in driver_data */
 	MTIP_DDF_SEC_LOCK_BIT	    = 0,
 	MTIP_DDF_REMOVE_PENDING_BIT = 1,
@@ -153,6 +161,7 @@
 	MTIP_DDF_RESUME_BIT         = 6,
 	MTIP_DDF_INIT_DONE_BIT      = 7,
 	MTIP_DDF_REBUILD_FAILED_BIT = 8,
+	MTIP_DDF_REMOVAL_BIT	    = 9,
 
 	MTIP_DDF_STOP_IO      = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) |
 				(1 << MTIP_DDF_SEC_LOCK_BIT) |
--- linux-4.4.0.orig/drivers/block/nbd.c
+++ linux-4.4.0/drivers/block/nbd.c
@@ -54,13 +54,15 @@
 
 	struct mutex tx_lock;
 	struct gendisk *disk;
-	int blksize;
+	loff_t blksize;
 	loff_t bytesize;
 	int xmit_timeout;
+	bool timedout;
 	bool disconnect; /* a disconnect has been requested by user */
 
 	struct timer_list timeout_timer;
-	spinlock_t tasks_lock;
+	/* protects initialization and shutdown of the socket */
+	spinlock_t sock_lock;
 	struct task_struct *task_recv;
 	struct task_struct *task_send;
 
@@ -79,7 +81,7 @@
 
 static unsigned int nbds_max = 16;
 static struct nbd_device *nbd_dev;
-static int max_part;
+static int max_part = 15;
 
 /*
  * Use just one lock (or at most 1 per NIC). Two arguments for this:
@@ -98,6 +100,11 @@
 	return disk_to_dev(nbd->disk);
 }
 
+static bool nbd_is_connected(struct nbd_device *nbd)
+{
+	return !!nbd->task_recv;
+}
+
 static const char *nbdcmd_to_ascii(int cmd)
 {
 	switch (cmd) {
@@ -110,6 +117,42 @@
 	return "invalid";
 }
 
+static int nbd_size_clear(struct nbd_device *nbd, struct block_device *bdev)
+{
+	bdev->bd_inode->i_size = 0;
+	set_capacity(nbd->disk, 0);
+	kobject_uevent(&nbd_to_dev(nbd)->kobj, KOBJ_CHANGE);
+
+	return 0;
+}
+
+static void nbd_size_update(struct nbd_device *nbd, struct block_device *bdev)
+{
+	if (!nbd_is_connected(nbd))
+		return;
+
+	bdev->bd_inode->i_size = nbd->bytesize;
+	set_capacity(nbd->disk, nbd->bytesize >> 9);
+	kobject_uevent(&nbd_to_dev(nbd)->kobj, KOBJ_CHANGE);
+}
+
+static int nbd_size_set(struct nbd_device *nbd, struct block_device *bdev,
+			loff_t blocksize, loff_t nr_blocks)
+{
+	int ret;
+
+	ret = set_blocksize(bdev, blocksize);
+	if (ret)
+		return ret;
+
+	nbd->blksize = blocksize;
+	nbd->bytesize = blocksize * nr_blocks;
+
+	nbd_size_update(nbd, bdev);
+
+	return 0;
+}
+
 static void nbd_end_request(struct nbd_device *nbd, struct request *req)
 {
 	int error = req->errors ? -EIO : 0;
@@ -129,36 +172,51 @@
  */
 static void sock_shutdown(struct nbd_device *nbd)
 {
-	if (!nbd->sock)
+	struct socket *sock;
+
+	spin_lock_irq(&nbd->sock_lock);
+
+	if (!nbd->sock) {
+		spin_unlock_irq(&nbd->sock_lock);
 		return;
+	}
 
+	sock = nbd->sock;
 	dev_warn(disk_to_dev(nbd->disk), "shutting down socket\n");
-	kernel_sock_shutdown(nbd->sock, SHUT_RDWR);
 	nbd->sock = NULL;
-	del_timer_sync(&nbd->timeout_timer);
+	spin_unlock_irq(&nbd->sock_lock);
+
+	kernel_sock_shutdown(sock, SHUT_RDWR);
+	sockfd_put(sock);
+
+	del_timer(&nbd->timeout_timer);
 }
 
 static void nbd_xmit_timeout(unsigned long arg)
 {
 	struct nbd_device *nbd = (struct nbd_device *)arg;
+	struct socket *sock = NULL;
 	unsigned long flags;
 
 	if (list_empty(&nbd->queue_head))
 		return;
 
-	nbd->disconnect = true;
-
-	spin_lock_irqsave(&nbd->tasks_lock, flags);
+	spin_lock_irqsave(&nbd->sock_lock, flags);
 
-	if (nbd->task_recv)
-		force_sig(SIGKILL, nbd->task_recv);
+	nbd->timedout = true;
 
-	if (nbd->task_send)
-		force_sig(SIGKILL, nbd->task_send);
+	if (nbd->sock) {
+		sock = nbd->sock;
+		get_file(sock->file);
+	}
 
-	spin_unlock_irqrestore(&nbd->tasks_lock, flags);
+	spin_unlock_irqrestore(&nbd->sock_lock, flags);
+	if (sock) {
+		kernel_sock_shutdown(sock, SHUT_RDWR);
+		sockfd_put(sock);
+	}
 
-	dev_err(nbd_to_dev(nbd), "Connection timed out, killed receiver and sender, shutting down connection\n");
+	dev_err(nbd_to_dev(nbd), "Connection timed out, shutting down connection\n");
 }
 
 /*
@@ -171,7 +229,6 @@
 	int result;
 	struct msghdr msg;
 	struct kvec iov;
-	sigset_t blocked, oldset;
 	unsigned long pflags = current->flags;
 
 	if (unlikely(!sock)) {
@@ -181,11 +238,6 @@
 		return -EINVAL;
 	}
 
-	/* Allow interception of SIGKILL only
-	 * Don't allow other signals to interrupt the transmission */
-	siginitsetinv(&blocked, sigmask(SIGKILL));
-	sigprocmask(SIG_SETMASK, &blocked, &oldset);
-
 	current->flags |= PF_MEMALLOC;
 	do {
 		sock->sk->sk_allocation = GFP_NOIO | __GFP_MEMALLOC;
@@ -212,7 +264,6 @@
 		buf += result;
 	} while (size > 0);
 
-	sigprocmask(SIG_SETMASK, &oldset, NULL);
 	tsk_restore_flags(current, pflags, PF_MEMALLOC);
 
 	if (!send && nbd->xmit_timeout)
@@ -402,31 +453,23 @@
 	.show = pid_show,
 };
 
-static int nbd_thread_recv(struct nbd_device *nbd)
+static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
 {
 	struct request *req;
 	int ret;
-	unsigned long flags;
 
 	BUG_ON(nbd->magic != NBD_MAGIC);
 
 	sk_set_memalloc(nbd->sock->sk);
 
-	spin_lock_irqsave(&nbd->tasks_lock, flags);
-	nbd->task_recv = current;
-	spin_unlock_irqrestore(&nbd->tasks_lock, flags);
-
 	ret = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
 	if (ret) {
 		dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
-
-		spin_lock_irqsave(&nbd->tasks_lock, flags);
-		nbd->task_recv = NULL;
-		spin_unlock_irqrestore(&nbd->tasks_lock, flags);
-
 		return ret;
 	}
 
+	nbd_size_update(nbd, bdev);
+
 	while (1) {
 		req = nbd_read_stat(nbd);
 		if (IS_ERR(req)) {
@@ -437,22 +480,9 @@
 		nbd_end_request(nbd, req);
 	}
 
-	device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
-
-	spin_lock_irqsave(&nbd->tasks_lock, flags);
-	nbd->task_recv = NULL;
-	spin_unlock_irqrestore(&nbd->tasks_lock, flags);
-
-	if (signal_pending(current)) {
-		ret = kernel_dequeue_signal(NULL);
-		dev_warn(nbd_to_dev(nbd), "pid %d, %s, got signal %d\n",
-			 task_pid_nr(current), current->comm, ret);
-		mutex_lock(&nbd->tx_lock);
-		sock_shutdown(nbd);
-		mutex_unlock(&nbd->tx_lock);
-		ret = -ETIMEDOUT;
-	}
+	nbd_size_clear(nbd, bdev);
 
+	device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
 	return ret;
 }
 
@@ -544,11 +574,8 @@
 {
 	struct nbd_device *nbd = data;
 	struct request *req;
-	unsigned long flags;
 
-	spin_lock_irqsave(&nbd->tasks_lock, flags);
 	nbd->task_send = current;
-	spin_unlock_irqrestore(&nbd->tasks_lock, flags);
 
 	set_user_nice(current, MIN_NICE);
 	while (!kthread_should_stop() || !list_empty(&nbd->waiting_queue)) {
@@ -557,17 +584,6 @@
 					 kthread_should_stop() ||
 					 !list_empty(&nbd->waiting_queue));
 
-		if (signal_pending(current)) {
-			int ret = kernel_dequeue_signal(NULL);
-
-			dev_warn(nbd_to_dev(nbd), "pid %d, %s, got signal %d\n",
-				 task_pid_nr(current), current->comm, ret);
-			mutex_lock(&nbd->tx_lock);
-			sock_shutdown(nbd);
-			mutex_unlock(&nbd->tx_lock);
-			break;
-		}
-
 		/* extract request */
 		if (list_empty(&nbd->waiting_queue))
 			continue;
@@ -582,13 +598,7 @@
 		nbd_handle_req(nbd, req);
 	}
 
-	spin_lock_irqsave(&nbd->tasks_lock, flags);
 	nbd->task_send = NULL;
-	spin_unlock_irqrestore(&nbd->tasks_lock, flags);
-
-	/* Clear maybe pending signals */
-	if (signal_pending(current))
-		kernel_dequeue_signal(NULL);
 
 	return 0;
 }
@@ -618,8 +628,8 @@
 			req, req->cmd_type);
 
 		if (unlikely(!nbd->sock)) {
-			dev_err(disk_to_dev(nbd->disk),
-				"Attempted send on closed socket\n");
+			dev_err_ratelimited(disk_to_dev(nbd->disk),
+					    "Attempted send on closed socket\n");
 			req->errors++;
 			nbd_end_request(nbd, req);
 			spin_lock_irq(q->queue_lock);
@@ -636,6 +646,49 @@
 	}
 }
 
+static int nbd_set_socket(struct nbd_device *nbd, struct socket *sock)
+{
+	int ret = 0;
+
+	spin_lock_irq(&nbd->sock_lock);
+
+	if (nbd->sock) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	nbd->sock = sock;
+
+out:
+	spin_unlock_irq(&nbd->sock_lock);
+
+	return ret;
+}
+
+/* Reset all properties of an NBD device */
+static void nbd_reset(struct nbd_device *nbd)
+{
+	nbd->disconnect = false;
+	nbd->timedout = false;
+	nbd->blksize = 1024;
+	nbd->bytesize = 0;
+	set_capacity(nbd->disk, 0);
+	nbd->flags = 0;
+	nbd->xmit_timeout = 0;
+	queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, nbd->disk->queue);
+	del_timer_sync(&nbd->timeout_timer);
+}
+
+static void nbd_bdev_reset(struct block_device *bdev)
+{
+	set_device_ro(bdev, false);
+	bdev->bd_inode->i_size = 0;
+	if (max_part > 0) {
+		blkdev_reread_part(bdev);
+		bdev->bd_invalidated = 1;
+	}
+}
+
 static int nbd_dev_dbg_init(struct nbd_device *nbd);
 static void nbd_dev_dbg_close(struct nbd_device *nbd);
 
@@ -668,48 +721,41 @@
 		return 0;
 	}
  
-	case NBD_CLEAR_SOCK: {
-		struct socket *sock = nbd->sock;
-		nbd->sock = NULL;
+	case NBD_CLEAR_SOCK:
+		sock_shutdown(nbd);
 		nbd_clear_que(nbd);
 		BUG_ON(!list_empty(&nbd->queue_head));
 		BUG_ON(!list_empty(&nbd->waiting_queue));
 		kill_bdev(bdev);
-		if (sock)
-			sockfd_put(sock);
 		return 0;
-	}
 
 	case NBD_SET_SOCK: {
-		struct socket *sock;
 		int err;
-		if (nbd->sock)
-			return -EBUSY;
-		sock = sockfd_lookup(arg, &err);
-		if (sock) {
-			nbd->sock = sock;
-			if (max_part > 0)
-				bdev->bd_invalidated = 1;
-			nbd->disconnect = false; /* we're connected now */
-			return 0;
-		}
-		return -EINVAL;
+		struct socket *sock = sockfd_lookup(arg, &err);
+
+		if (!sock)
+			return err;
+
+		err = nbd_set_socket(nbd, sock);
+		if (!err && max_part)
+			bdev->bd_invalidated = 1;
+
+		return err;
 	}
 
-	case NBD_SET_BLKSIZE:
-		nbd->blksize = arg;
-		nbd->bytesize &= ~(nbd->blksize-1);
-		bdev->bd_inode->i_size = nbd->bytesize;
-		set_blocksize(bdev, nbd->blksize);
-		set_capacity(nbd->disk, nbd->bytesize >> 9);
-		return 0;
+	case NBD_SET_BLKSIZE: {
+		loff_t bsize = nbd->bytesize;
+		do_div(bsize, arg);
+
+		return nbd_size_set(nbd, bdev, arg, bsize);
+	}
 
 	case NBD_SET_SIZE:
-		nbd->bytesize = arg & ~(nbd->blksize-1);
-		bdev->bd_inode->i_size = nbd->bytesize;
-		set_blocksize(bdev, nbd->blksize);
-		set_capacity(nbd->disk, nbd->bytesize >> 9);
-		return 0;
+		return nbd_size_set(nbd, bdev, nbd->blksize,
+					div_s64(arg, nbd->blksize));
+
+	case NBD_SET_SIZE_BLOCKS:
+		return nbd_size_set(nbd, bdev, nbd->blksize, arg);
 
 	case NBD_SET_TIMEOUT:
 		nbd->xmit_timeout = arg * HZ;
@@ -725,16 +771,8 @@
 		nbd->flags = arg;
 		return 0;
 
-	case NBD_SET_SIZE_BLOCKS:
-		nbd->bytesize = ((u64) arg) * nbd->blksize;
-		bdev->bd_inode->i_size = nbd->bytesize;
-		set_blocksize(bdev, nbd->blksize);
-		set_capacity(nbd->disk, nbd->bytesize >> 9);
-		return 0;
-
 	case NBD_DO_IT: {
 		struct task_struct *thread;
-		struct socket *sock;
 		int error;
 
 		if (nbd->task_recv)
@@ -742,6 +780,8 @@
 		if (!nbd->sock)
 			return -EINVAL;
 
+		/* We have to claim the device under the lock */
+		nbd->task_recv = current;
 		mutex_unlock(&nbd->tx_lock);
 
 		if (nbd->flags & NBD_FLAG_READ_ONLY)
@@ -758,33 +798,30 @@
 				     nbd_name(nbd));
 		if (IS_ERR(thread)) {
 			mutex_lock(&nbd->tx_lock);
+			nbd->task_recv = NULL;
 			return PTR_ERR(thread);
 		}
 
 		nbd_dev_dbg_init(nbd);
-		error = nbd_thread_recv(nbd);
+		error = nbd_thread_recv(nbd, bdev);
 		nbd_dev_dbg_close(nbd);
 		kthread_stop(thread);
 
 		mutex_lock(&nbd->tx_lock);
+		nbd->task_recv = NULL;
 
 		sock_shutdown(nbd);
-		sock = nbd->sock;
-		nbd->sock = NULL;
 		nbd_clear_que(nbd);
 		kill_bdev(bdev);
-		queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, nbd->disk->queue);
-		set_device_ro(bdev, false);
-		if (sock)
-			sockfd_put(sock);
-		nbd->flags = 0;
-		nbd->bytesize = 0;
-		bdev->bd_inode->i_size = 0;
-		set_capacity(nbd->disk, 0);
-		if (max_part > 0)
-			blkdev_reread_part(bdev);
+		nbd_bdev_reset(bdev);
+
 		if (nbd->disconnect) /* user requested, ignore socket errors */
-			return 0;
+			error = 0;
+		if (nbd->timedout)
+			error = -ETIMEDOUT;
+
+		nbd_reset(nbd);
+
 		return error;
 	}
 
@@ -922,7 +959,7 @@
 		return PTR_ERR(f);
 	}
 
-	f = debugfs_create_u32("blocksize", 0444, dir, &nbd->blksize);
+	f = debugfs_create_u64("blocksize", 0444, dir, &nbd->blksize);
 	if (IS_ERR_OR_NULL(f)) {
 		dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'blocksize', %ld\n",
 			PTR_ERR(f));
@@ -1068,7 +1105,7 @@
 		nbd_dev[i].magic = NBD_MAGIC;
 		INIT_LIST_HEAD(&nbd_dev[i].waiting_queue);
 		spin_lock_init(&nbd_dev[i].queue_lock);
-		spin_lock_init(&nbd_dev[i].tasks_lock);
+		spin_lock_init(&nbd_dev[i].sock_lock);
 		INIT_LIST_HEAD(&nbd_dev[i].queue_head);
 		mutex_init(&nbd_dev[i].tx_lock);
 		init_timer(&nbd_dev[i].timeout_timer);
@@ -1076,14 +1113,12 @@
 		nbd_dev[i].timeout_timer.data = (unsigned long)&nbd_dev[i];
 		init_waitqueue_head(&nbd_dev[i].active_wq);
 		init_waitqueue_head(&nbd_dev[i].waiting_wq);
-		nbd_dev[i].blksize = 1024;
-		nbd_dev[i].bytesize = 0;
 		disk->major = NBD_MAJOR;
 		disk->first_minor = i << part_shift;
 		disk->fops = &nbd_fops;
 		disk->private_data = &nbd_dev[i];
 		sprintf(disk->disk_name, "nbd%d", i);
-		set_capacity(disk, 0);
+		nbd_reset(&nbd_dev[i]);
 		add_disk(disk);
 	}
 
--- linux-4.4.0.orig/drivers/block/null_blk.c
+++ linux-4.4.0/drivers/block/null_blk.c
@@ -436,9 +436,8 @@
 static void null_lnvm_end_io(struct request *rq, int error)
 {
 	struct nvm_rq *rqd = rq->end_io_data;
-	struct nvm_dev *dev = rqd->dev;
 
-	dev->mt->end_io(rqd, error);
+	nvm_end_io(rqd, error);
 
 	blk_put_request(rq);
 }
@@ -449,7 +448,7 @@
 	struct request *rq;
 	struct bio *bio = rqd->bio;
 
-	rq = blk_mq_alloc_request(q, bio_rw(bio), GFP_KERNEL, 0);
+	rq = blk_mq_alloc_request(q, bio_rw(bio), 0);
 	if (IS_ERR(rq))
 		return -ENOMEM;
 
--- linux-4.4.0.orig/drivers/block/paride/pcd.c
+++ linux-4.4.0/drivers/block/paride/pcd.c
@@ -230,6 +230,8 @@
 	struct pcd_unit *cd = bdev->bd_disk->private_data;
 	int ret;
 
+	check_disk_change(bdev);
+
 	mutex_lock(&pcd_mutex);
 	ret = cdrom_open(&cd->info, bdev, mode);
 	mutex_unlock(&pcd_mutex);
--- linux-4.4.0.orig/drivers/block/paride/pd.c
+++ linux-4.4.0/drivers/block/paride/pd.c
@@ -126,7 +126,7 @@
 */
 #include <linux/types.h>
 
-static bool verbose = 0;
+static int verbose = 0;
 static int major = PD_MAJOR;
 static char *name = PD_NAME;
 static int cluster = 64;
@@ -161,7 +161,7 @@
 static DEFINE_MUTEX(pd_mutex);
 static DEFINE_SPINLOCK(pd_lock);
 
-module_param(verbose, bool, 0);
+module_param(verbose, int, 0);
 module_param(major, int, 0);
 module_param(name, charp, 0);
 module_param(cluster, int, 0);
--- linux-4.4.0.orig/drivers/block/paride/pt.c
+++ linux-4.4.0/drivers/block/paride/pt.c
@@ -117,7 +117,7 @@
 
 */
 
-static bool verbose = 0;
+static int verbose = 0;
 static int major = PT_MAJOR;
 static char *name = PT_NAME;
 static int disable = 0;
@@ -152,7 +152,7 @@
 
 #include <asm/uaccess.h>
 
-module_param(verbose, bool, 0);
+module_param(verbose, int, 0);
 module_param(major, int, 0);
 module_param(name, charp, 0);
 module_param_array(drive0, int, NULL, 0);
--- linux-4.4.0.orig/drivers/block/pktcdvd.c
+++ linux-4.4.0/drivers/block/pktcdvd.c
@@ -67,6 +67,7 @@
 #include <scsi/scsi.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
+#include <linux/nospec.h>
 
 #include <asm/uaccess.h>
 
@@ -1276,7 +1277,7 @@
 	 		&& pd->bio_queue_size <= pd->write_congestion_off);
 	spin_unlock(&pd->lock);
 	if (wakeup) {
-		clear_bdi_congested(&pd->disk->queue->backing_dev_info,
+		clear_bdi_congested(pd->disk->queue->backing_dev_info,
 					BLK_RW_ASYNC);
 	}
 
@@ -2267,6 +2268,8 @@
 {
 	if (dev_minor >= MAX_WRITERS)
 		return NULL;
+
+	dev_minor = array_index_nospec(dev_minor, MAX_WRITERS);
 	return pkt_devs[dev_minor];
 }
 
@@ -2405,7 +2408,7 @@
 	spin_lock(&pd->lock);
 	if (pd->write_congestion_on > 0
 	    && pd->bio_queue_size >= pd->write_congestion_on) {
-		set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC);
+		set_bdi_congested(q->backing_dev_info, BLK_RW_ASYNC);
 		do {
 			spin_unlock(&pd->lock);
 			congestion_wait(BLK_RW_ASYNC, HZ);
@@ -2779,7 +2782,7 @@
 	pd->pkt_dev = MKDEV(pktdev_major, idx);
 	ret = pkt_new_dev(pd, dev);
 	if (ret)
-		goto out_new_dev;
+		goto out_mem2;
 
 	/* inherit events of the host device */
 	disk->events = pd->bdev->bd_disk->events;
@@ -2797,8 +2800,6 @@
 	mutex_unlock(&ctl_mutex);
 	return 0;
 
-out_new_dev:
-	blk_cleanup_queue(disk->queue);
 out_mem2:
 	put_disk(disk);
 out_mem:
--- linux-4.4.0.orig/drivers/block/ps3disk.c
+++ linux-4.4.0/drivers/block/ps3disk.c
@@ -464,7 +464,6 @@
 	blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
 
 	blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
-	blk_queue_segment_boundary(queue, -1UL);
 	blk_queue_dma_alignment(queue, dev->blk_size-1);
 	blk_queue_logical_block_size(queue, dev->blk_size);
 
--- linux-4.4.0.orig/drivers/block/rbd.c
+++ linux-4.4.0/drivers/block/rbd.c
@@ -50,15 +50,6 @@
 #define RBD_DEBUG	/* Activate rbd_assert() calls */
 
 /*
- * The basic unit of block I/O is a sector.  It is interpreted in a
- * number of contexts in Linux (blk, bio, genhd), but the default is
- * universally 512 bytes.  These symbols are just slightly more
- * meaningful than the bare numbers they represent.
- */
-#define	SECTOR_SHIFT	9
-#define	SECTOR_SIZE	(1ULL << SECTOR_SHIFT)
-
-/*
  * Increment the given counter and return its updated value.
  * If the counter is already 0 it will not be incremented.
  * If the counter is already at its maximum value returns
@@ -1955,7 +1946,7 @@
 
 	osdc = &rbd_dev->rbd_client->client->osdc;
 	osd_req = ceph_osdc_alloc_request(osdc, snapc, num_ops, false,
-					  GFP_ATOMIC);
+					  GFP_NOIO);
 	if (!osd_req)
 		return NULL;	/* ENOMEM */
 
@@ -2004,7 +1995,7 @@
 	rbd_dev = img_request->rbd_dev;
 	osdc = &rbd_dev->rbd_client->client->osdc;
 	osd_req = ceph_osdc_alloc_request(osdc, snapc, num_osd_ops,
-						false, GFP_ATOMIC);
+						false, GFP_NOIO);
 	if (!osd_req)
 		return NULL;	/* ENOMEM */
 
@@ -2506,7 +2497,7 @@
 					bio_chain_clone_range(&bio_list,
 								&bio_offset,
 								clone_size,
-								GFP_ATOMIC);
+								GFP_NOIO);
 			if (!obj_request->bio_list)
 				goto out_unwind;
 		} else if (type == OBJ_REQUEST_PAGES) {
@@ -2736,7 +2727,7 @@
 	 * from the parent.
 	 */
 	page_count = (u32)calc_pages_for(0, length);
-	pages = ceph_alloc_page_vector(page_count, GFP_KERNEL);
+	pages = ceph_alloc_page_vector(page_count, GFP_NOIO);
 	if (IS_ERR(pages)) {
 		result = PTR_ERR(pages);
 		pages = NULL;
@@ -2863,7 +2854,7 @@
 	 */
 	size = sizeof (__le64) + sizeof (__le32) + sizeof (__le32);
 	page_count = (u32)calc_pages_for(0, size);
-	pages = ceph_alloc_page_vector(page_count, GFP_KERNEL);
+	pages = ceph_alloc_page_vector(page_count, GFP_NOIO);
 	if (IS_ERR(pages))
 		return PTR_ERR(pages);
 
@@ -3767,7 +3758,7 @@
 	segment_size = rbd_obj_bytes(&rbd_dev->header);
 	blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE);
 	q->limits.max_sectors = queue_max_hw_sectors(q);
-	blk_queue_max_segments(q, segment_size / SECTOR_SIZE);
+	blk_queue_max_segments(q, USHRT_MAX);
 	blk_queue_max_segment_size(q, segment_size);
 	blk_queue_io_min(q, segment_size);
 	blk_queue_io_opt(q, segment_size);
@@ -3780,7 +3771,7 @@
 	q->limits.discard_zeroes_data = 1;
 
 	if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
-		q->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+		q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
 
 	disk->queue = q;
 
@@ -3945,6 +3936,9 @@
 	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 	int ret;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	ret = rbd_dev_refresh(rbd_dev);
 	if (ret)
 		return ret;
@@ -5404,6 +5398,9 @@
 	bool read_only;
 	int rc;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	if (!try_module_get(THIS_MODULE))
 		return -ENODEV;
 
@@ -5548,6 +5545,9 @@
 	bool already = false;
 	int ret;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	ret = kstrtoul(buf, 10, &ul);
 	if (ret)
 		return ret;
--- linux-4.4.0.orig/drivers/block/rsxx/core.c
+++ linux-4.4.0/drivers/block/rsxx/core.c
@@ -180,15 +180,17 @@
 {
 	struct rsxx_cardinfo *card = file_inode(fp)->i_private;
 	char *buf;
-	ssize_t st;
+	int st;
 
 	buf = kzalloc(cnt, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
 	st = rsxx_creg_read(card, CREG_ADD_CRAM + (u32)*ppos, cnt, buf, 1);
-	if (!st)
-		st = copy_to_user(ubuf, buf, cnt);
+	if (!st) {
+		if (copy_to_user(ubuf, buf, cnt))
+			st = -EFAULT;
+	}
 	kfree(buf);
 	if (st)
 		return st;
@@ -893,6 +895,7 @@
 	card->event_wq = create_singlethread_workqueue(DRIVER_NAME"_event");
 	if (!card->event_wq) {
 		dev_err(CARD_TO_DEV(card), "Failed card event setup.\n");
+		st = -ENOMEM;
 		goto failed_event_handler;
 	}
 
@@ -1028,8 +1031,10 @@
 
 	cancel_work_sync(&card->event_work);
 
+	destroy_workqueue(card->event_wq);
 	rsxx_destroy_dev(card);
 	rsxx_dma_destroy(card);
+	destroy_workqueue(card->creg_ctrl.creg_wq);
 
 	spin_lock_irqsave(&card->irq_lock, flags);
 	rsxx_disable_ier_and_isr(card, CR_INTR_ALL);
--- linux-4.4.0.orig/drivers/block/skd_main.c
+++ linux-4.4.0/drivers/block/skd_main.c
@@ -2214,6 +2214,9 @@
 		 */
 		qcmd |= FIT_QCMD_MSGSIZE_64;
 
+	/* Make sure skd_msg_buf is written before the doorbell is triggered. */
+	smp_wmb();
+
 	SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND);
 
 }
@@ -2260,6 +2263,9 @@
 	qcmd = skspcl->mb_dma_address;
 	qcmd |= FIT_QCMD_QID_NORMAL + FIT_QCMD_MSGSIZE_128;
 
+	/* Make sure skd_msg_buf is written before the doorbell is triggered. */
+	smp_wmb();
+
 	SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND);
 }
 
@@ -4679,15 +4685,16 @@
 {
 	struct gendisk *disk = skdev->disk;
 
-	if (disk != NULL) {
-		struct request_queue *q = disk->queue;
+	if (disk && (disk->flags & GENHD_FL_UP))
+		del_gendisk(disk);
 
-		if (disk->flags & GENHD_FL_UP)
-			del_gendisk(disk);
-		if (q)
-			blk_cleanup_queue(q);
-		put_disk(disk);
+	if (skdev->queue) {
+		blk_cleanup_queue(skdev->queue);
+		skdev->queue = NULL;
+		disk->queue = NULL;
 	}
+
+	put_disk(disk);
 	skdev->disk = NULL;
 }
 
--- linux-4.4.0.orig/drivers/block/sunvdc.c
+++ linux-4.4.0/drivers/block/sunvdc.c
@@ -40,6 +40,8 @@
 #define WAITING_FOR_GEN_CMD	0x04
 #define WAITING_FOR_ANY		-1
 
+#define	VDC_MAX_RETRIES	10
+
 static struct workqueue_struct *sunvdc_wq;
 
 struct vdc_req_entry {
@@ -419,6 +421,7 @@
 		.end_idx		= dr->prod,
 	};
 	int err, delay;
+	int retries = 0;
 
 	hdr.seq = dr->snd_nxt;
 	delay = 1;
@@ -431,6 +434,8 @@
 		udelay(delay);
 		if ((delay <<= 1) > 128)
 			delay = 128;
+		if (retries++ > VDC_MAX_RETRIES)
+			break;
 	} while (err == -EAGAIN);
 
 	if (err == -ENOTCONN)
--- linux-4.4.0.orig/drivers/block/swim.c
+++ linux-4.4.0/drivers/block/swim.c
@@ -868,8 +868,17 @@
 
 exit_put_disks:
 	unregister_blkdev(FLOPPY_MAJOR, "fd");
-	while (drive--)
-		put_disk(swd->unit[drive].disk);
+	do {
+		struct gendisk *disk = swd->unit[drive].disk;
+
+		if (disk) {
+			if (disk->queue) {
+				blk_cleanup_queue(disk->queue);
+				disk->queue = NULL;
+			}
+			put_disk(disk);
+		}
+	} while (drive--);
 	return err;
 }
 
--- linux-4.4.0.orig/drivers/block/swim3.c
+++ linux-4.4.0/drivers/block/swim3.c
@@ -1027,7 +1027,11 @@
 	struct swim3 __iomem *sw = fs->swim3;
 
 	mutex_lock(&swim3_mutex);
-	if (fs->ref_count > 0 && --fs->ref_count == 0) {
+	if (fs->ref_count > 0)
+		--fs->ref_count;
+	else if (fs->ref_count == -1)
+		fs->ref_count = 0;
+	if (fs->ref_count == 0) {
 		swim3_action(fs, MOTOR_OFF);
 		out_8(&sw->control_bic, 0xff);
 		swim3_select(fs, RELAX);
--- linux-4.4.0.orig/drivers/block/virtio_blk.c
+++ linux-4.4.0/drivers/block/virtio_blk.c
@@ -641,11 +641,12 @@
 	if (err)
 		goto out_put_disk;
 
-	q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set);
+	q = blk_mq_init_queue(&vblk->tag_set);
 	if (IS_ERR(q)) {
 		err = -ENOMEM;
 		goto out_free_tags;
 	}
+	vblk->disk->queue = q;
 
 	q->queuedata = vblk;
 
@@ -756,6 +757,7 @@
 	put_disk(vblk->disk);
 out_free_vq:
 	vdev->config->del_vqs(vdev);
+	kfree(vblk->vqs);
 out_free_vblk:
 	kfree(vblk);
 out_free_index:
@@ -806,6 +808,8 @@
 	blk_mq_stop_hw_queues(vblk->disk->queue);
 
 	vdev->config->del_vqs(vdev);
+	kfree(vblk->vqs);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/block/xen-blkback/blkback.c
+++ linux-4.4.0/drivers/block/xen-blkback/blkback.c
@@ -173,7 +173,7 @@
 
 #define vaddr(page) ((unsigned long)pfn_to_kaddr(page_to_pfn(page)))
 
-static int do_block_io_op(struct xen_blkif *blkif);
+static int do_block_io_op(struct xen_blkif *blkif, unsigned int *eoi_flags);
 static int dispatch_rw_block_io(struct xen_blkif *blkif,
 				struct blkif_request *req,
 				struct pending_req *pending_req);
@@ -594,8 +594,8 @@
 	struct xen_vbd *vbd = &blkif->vbd;
 	unsigned long timeout;
 	int ret;
-
-	xen_blkif_get(blkif);
+	bool do_eoi;
+	unsigned int eoi_flags = XEN_EOI_FLAG_SPURIOUS;
 
 	while (!kthread_should_stop()) {
 		if (try_to_freeze())
@@ -619,16 +619,23 @@
 		if (timeout == 0)
 			goto purge_gnt_list;
 
+		do_eoi = blkif->waiting_reqs;
+
 		blkif->waiting_reqs = 0;
 		smp_mb(); /* clear flag *before* checking for work */
 
-		ret = do_block_io_op(blkif);
+		ret = do_block_io_op(blkif, &eoi_flags);
 		if (ret > 0)
 			blkif->waiting_reqs = 1;
 		if (ret == -EACCES)
 			wait_event_interruptible(blkif->shutdown_wq,
 						 kthread_should_stop());
 
+		if (do_eoi && !blkif->waiting_reqs) {
+			xen_irq_lateeoi(blkif->irq, eoi_flags);
+			eoi_flags |= XEN_EOI_FLAG_SPURIOUS;
+		}
+
 purge_gnt_list:
 		if (blkif->vbd.feature_gnt_persistent &&
 		    time_after(jiffies, blkif->next_lru)) {
@@ -650,7 +657,6 @@
 		print_stats(blkif);
 
 	blkif->xenblkd = NULL;
-	xen_blkif_put(blkif);
 
 	return 0;
 }
@@ -819,8 +825,11 @@
 			pages[i]->page = persistent_gnt->page;
 			pages[i]->persistent_gnt = persistent_gnt;
 		} else {
-			if (get_free_page(blkif, &pages[i]->page))
-				goto out_of_memory;
+			if (get_free_page(blkif, &pages[i]->page)) {
+				put_free_pages(blkif, pages_to_gnt, segs_to_map);
+				ret = -ENOMEM;
+				goto out;
+			}
 			addr = vaddr(pages[i]->page);
 			pages_to_gnt[segs_to_map] = pages[i]->page;
 			pages[i]->persistent_gnt = NULL;
@@ -836,10 +845,8 @@
 			break;
 	}
 
-	if (segs_to_map) {
+	if (segs_to_map)
 		ret = gnttab_map_refs(map, NULL, pages_to_gnt, segs_to_map);
-		BUG_ON(ret);
-	}
 
 	/*
 	 * Now swizzle the MFN in our domain with the MFN from the other domain
@@ -854,7 +861,7 @@
 				pr_debug("invalid buffer -- could not remap it\n");
 				put_free_pages(blkif, &pages[seg_idx]->page, 1);
 				pages[seg_idx]->handle = BLKBACK_INVALID_HANDLE;
-				ret |= 1;
+				ret |= !ret;
 				goto next;
 			}
 			pages[seg_idx]->handle = map[new_map_idx].handle;
@@ -906,15 +913,18 @@
 	}
 	segs_to_map = 0;
 	last_map = map_until;
-	if (map_until != num)
+	if (!ret && map_until != num)
 		goto again;
 
-	return ret;
+out:
+	for (i = last_map; i < num; i++) {
+		/* Don't zap current batch's valid persistent grants. */
+		if(i >= map_until)
+			pages[i]->persistent_gnt = NULL;
+		pages[i]->handle = BLKBACK_INVALID_HANDLE;
+	}
 
-out_of_memory:
-	pr_alert("%s: out of memory\n", __func__);
-	put_free_pages(blkif, pages_to_gnt, segs_to_map);
-	return -ENOMEM;
+	return ret;
 }
 
 static int xen_blkbk_map_seg(struct pending_req *pending_req)
@@ -1097,7 +1107,7 @@
  * and transmute  it to the block API to hand it over to the proper block disk.
  */
 static int
-__do_block_io_op(struct xen_blkif *blkif)
+__do_block_io_op(struct xen_blkif *blkif, unsigned int *eoi_flags)
 {
 	union blkif_back_rings *blk_rings = &blkif->blk_rings;
 	struct blkif_request req;
@@ -1120,6 +1130,9 @@
 		if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
 			break;
 
+		/* We've seen a request, so clear spurious eoi flag. */
+		*eoi_flags &= ~XEN_EOI_FLAG_SPURIOUS;
+
 		if (kthread_should_stop()) {
 			more_to_do = 1;
 			break;
@@ -1178,13 +1191,13 @@
 }
 
 static int
-do_block_io_op(struct xen_blkif *blkif)
+do_block_io_op(struct xen_blkif *blkif, unsigned int *eoi_flags)
 {
 	union blkif_back_rings *blk_rings = &blkif->blk_rings;
 	int more_to_do;
 
 	do {
-		more_to_do = __do_block_io_op(blkif);
+		more_to_do = __do_block_io_op(blkif, eoi_flags);
 		if (more_to_do)
 			break;
 
@@ -1410,33 +1423,35 @@
 static void make_response(struct xen_blkif *blkif, u64 id,
 			  unsigned short op, int st)
 {
-	struct blkif_response  resp;
+	struct blkif_response *resp;
 	unsigned long     flags;
-	union blkif_back_rings *blk_rings = &blkif->blk_rings;
+	union blkif_back_rings *blk_rings;
 	int notify;
 
-	resp.id        = id;
-	resp.operation = op;
-	resp.status    = st;
-
 	spin_lock_irqsave(&blkif->blk_ring_lock, flags);
+	blk_rings = &blkif->blk_rings;
 	/* Place on the response ring for the relevant domain. */
 	switch (blkif->blk_protocol) {
 	case BLKIF_PROTOCOL_NATIVE:
-		memcpy(RING_GET_RESPONSE(&blk_rings->native, blk_rings->native.rsp_prod_pvt),
-		       &resp, sizeof(resp));
+		resp = RING_GET_RESPONSE(&blk_rings->native,
+					 blk_rings->native.rsp_prod_pvt);
 		break;
 	case BLKIF_PROTOCOL_X86_32:
-		memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, blk_rings->x86_32.rsp_prod_pvt),
-		       &resp, sizeof(resp));
+		resp = RING_GET_RESPONSE(&blk_rings->x86_32,
+					 blk_rings->x86_32.rsp_prod_pvt);
 		break;
 	case BLKIF_PROTOCOL_X86_64:
-		memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, blk_rings->x86_64.rsp_prod_pvt),
-		       &resp, sizeof(resp));
+		resp = RING_GET_RESPONSE(&blk_rings->x86_64,
+					 blk_rings->x86_64.rsp_prod_pvt);
 		break;
 	default:
 		BUG();
 	}
+
+	resp->id        = id;
+	resp->operation = op;
+	resp->status    = st;
+
 	blk_rings->common.rsp_prod_pvt++;
 	RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify);
 	spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
--- linux-4.4.0.orig/drivers/block/xen-blkback/common.h
+++ linux-4.4.0/drivers/block/xen-blkback/common.h
@@ -74,9 +74,8 @@
 struct blkif_common_request {
 	char dummy;
 };
-struct blkif_common_response {
-	char dummy;
-};
+
+/* i386 protocol version */
 
 struct blkif_x86_32_request_rw {
 	uint8_t        nr_segments;  /* number of segments                   */
@@ -128,14 +127,6 @@
 	} u;
 } __attribute__((__packed__));
 
-/* i386 protocol version */
-#pragma pack(push, 4)
-struct blkif_x86_32_response {
-	uint64_t        id;              /* copied from request */
-	uint8_t         operation;       /* copied from request */
-	int16_t         status;          /* BLKIF_RSP_???       */
-};
-#pragma pack(pop)
 /* x86_64 protocol version */
 
 struct blkif_x86_64_request_rw {
@@ -192,18 +183,12 @@
 	} u;
 } __attribute__((__packed__));
 
-struct blkif_x86_64_response {
-	uint64_t       __attribute__((__aligned__(8))) id;
-	uint8_t         operation;       /* copied from request */
-	int16_t         status;          /* BLKIF_RSP_???       */
-};
-
 DEFINE_RING_TYPES(blkif_common, struct blkif_common_request,
-		  struct blkif_common_response);
+		  struct blkif_response);
 DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request,
-		  struct blkif_x86_32_response);
+		  struct blkif_response __packed);
 DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request,
-		  struct blkif_x86_64_response);
+		  struct blkif_response);
 
 union blkif_back_rings {
 	struct blkif_back_ring        native;
--- linux-4.4.0.orig/drivers/block/xen-blkback/xenbus.c
+++ linux-4.4.0/drivers/block/xen-blkback/xenbus.c
@@ -200,9 +200,8 @@
 		BUG();
 	}
 
-	err = bind_interdomain_evtchn_to_irqhandler(blkif->domid, evtchn,
-						    xen_blkif_be_int, 0,
-						    "blkif-backend", blkif);
+	err = bind_interdomain_evtchn_to_irqhandler_lateeoi(blkif->domid,
+			evtchn, xen_blkif_be_int, 0, "blkif-backend", blkif);
 	if (err < 0) {
 		xenbus_unmap_ring_vfree(blkif->be->dev, blkif->blk_ring);
 		blkif->blk_rings.common.sring = NULL;
@@ -220,8 +219,8 @@
 
 	if (blkif->xenblkd) {
 		kthread_stop(blkif->xenblkd);
-		wake_up(&blkif->shutdown_wq);
 		blkif->xenblkd = NULL;
+		wake_up(&blkif->shutdown_wq);
 	}
 
 	/* The above kthread_stop() guarantees that at this point we
@@ -266,9 +265,10 @@
 
 static void xen_blkif_free(struct xen_blkif *blkif)
 {
-
-	xen_blkif_disconnect(blkif);
+	WARN_ON(xen_blkif_disconnect(blkif));
 	xen_vbd_free(&blkif->vbd);
+	kfree(blkif->be->mode);
+	kfree(blkif->be);
 
 	/* Make sure everything is drained before shutting down */
 	BUG_ON(blkif->persistent_gnt_c != 0);
@@ -445,8 +445,6 @@
 		xen_blkif_put(be->blkif);
 	}
 
-	kfree(be->mode);
-	kfree(be);
 	return 0;
 }
 
@@ -556,7 +554,8 @@
 	/* setup back pointer */
 	be->blkif->be = be;
 
-	err = xenbus_watch_pathfmt(dev, &be->backend_watch, backend_changed,
+	err = xenbus_watch_pathfmt(dev, &be->backend_watch, NULL,
+				   backend_changed,
 				   "%s/%s", dev->nodename, "physical-device");
 	if (err)
 		goto fail;
--- linux-4.4.0.orig/drivers/block/xen-blkfront.c
+++ linux-4.4.0/drivers/block/xen-blkfront.c
@@ -64,6 +64,7 @@
 	BLKIF_STATE_DISCONNECTED,
 	BLKIF_STATE_CONNECTED,
 	BLKIF_STATE_SUSPENDED,
+	BLKIF_STATE_ERROR,
 };
 
 struct grant {
@@ -79,6 +80,7 @@
 	struct grant **indirect_grants;
 	struct scatterlist *sg;
 	unsigned int num_sg;
+	bool inflight;
 };
 
 struct split_bio {
@@ -235,7 +237,7 @@
 			goto out_of_memory;
 
 		if (info->feature_persistent) {
-			granted_page = alloc_page(GFP_NOIO);
+			granted_page = alloc_page(GFP_NOIO | __GFP_ZERO);
 			if (!granted_page) {
 				kfree(gnt_list_entry);
 				goto out_of_memory;
@@ -456,16 +458,31 @@
 	return 0;
 }
 
+static unsigned long blkif_ring_get_request(struct blkfront_info *info,
+					    struct request *req,
+					    struct blkif_request **ring_req)
+{
+	unsigned long id;
+
+	*ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+	info->ring.req_prod_pvt++;
+
+	id = get_id_from_freelist(info);
+	info->shadow[id].request = req;
+	info->shadow[id].req.u.rw.id = id;
+
+	return id;
+}
+
 static int blkif_queue_discard_req(struct request *req)
 {
 	struct blkfront_info *info = req->rq_disk->private_data;
-	struct blkif_request *ring_req;
+	struct blkif_request *ring_req, *final_ring_req;
 	unsigned long id;
 
 	/* Fill out a communications ring structure. */
-	ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
-	id = get_id_from_freelist(info);
-	info->shadow[id].request = req;
+	id = blkif_ring_get_request(info, req, &final_ring_req);
+	ring_req = &info->shadow[id].req;
 
 	ring_req->operation = BLKIF_OP_DISCARD;
 	ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
@@ -476,10 +493,9 @@
 	else
 		ring_req->u.discard.flag = 0;
 
-	info->ring.req_prod_pvt++;
-
-	/* Keep a private copy so we can reissue requests when recovering. */
-	info->shadow[id].req = *ring_req;
+	/* Copy the request to the ring page. */
+	*final_ring_req = *ring_req;
+	info->shadow[id].inflight = true;
 
 	return 0;
 }
@@ -569,7 +585,7 @@
 static int blkif_queue_rw_req(struct request *req)
 {
 	struct blkfront_info *info = req->rq_disk->private_data;
-	struct blkif_request *ring_req;
+	struct blkif_request *ring_req, *final_ring_req;
 	unsigned long id;
 	int i;
 	struct setup_rw_req setup = {
@@ -613,9 +629,8 @@
 		new_persistent_gnts = 0;
 
 	/* Fill out a communications ring structure. */
-	ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
-	id = get_id_from_freelist(info);
-	info->shadow[id].request = req;
+	id = blkif_ring_get_request(info, req, &final_ring_req);
+	ring_req = &info->shadow[id].req;
 
 	BUG_ON(info->max_indirect_segments == 0 &&
 	       GREFS(req->nr_phys_segments) > BLKIF_MAX_SEGMENTS_PER_REQUEST);
@@ -694,10 +709,9 @@
 	if (setup.segments)
 		kunmap_atomic(setup.segments);
 
-	info->ring.req_prod_pvt++;
-
-	/* Keep a private copy so we can reissue requests when recovering. */
-	info->shadow[id].req = *ring_req;
+	/* Copy request(s) to the ring page. */
+	*final_ring_req = *ring_req;
+	info->shadow[id].inflight = true;
 
 	if (new_persistent_gnts)
 		gnttab_free_grant_references(setup.gref_head);
@@ -952,8 +966,8 @@
 	if (!VDEV_IS_EXTENDED(info->vdevice)) {
 		err = xen_translate_vdev(info->vdevice, &minor, &offset);
 		if (err)
-			return err;		
- 		nr_parts = PARTS_PER_DISK;
+			return err;
+		nr_parts = PARTS_PER_DISK;
 	} else {
 		minor = BLKIF_MINOR_EXT(info->vdevice);
 		nr_parts = PARTS_PER_EXT_DISK;
@@ -1296,58 +1310,84 @@
 static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 {
 	struct request *req;
-	struct blkif_response *bret;
+	struct blkif_response bret;
 	RING_IDX i, rp;
 	unsigned long flags;
 	struct blkfront_info *info = (struct blkfront_info *)dev_id;
 	int error;
+	unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
 
 	spin_lock_irqsave(&info->io_lock, flags);
 
 	if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
 		spin_unlock_irqrestore(&info->io_lock, flags);
+		xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
 		return IRQ_HANDLED;
 	}
 
  again:
-	rp = info->ring.sring->rsp_prod;
+	rp = READ_ONCE(info->ring.sring->rsp_prod);
 	rmb(); /* Ensure we see queued responses up to 'rp'. */
+	if (RING_RESPONSE_PROD_OVERFLOW(&info->ring, rp)) {
+		pr_alert("%s: illegal number of responses %u\n",
+			 info->gd->disk_name, rp - info->ring.rsp_cons);
+		goto err;
+	}
 
 	for (i = info->ring.rsp_cons; i != rp; i++) {
 		unsigned long id;
+		unsigned int op;
+
+		eoiflag = 0;
+
+		RING_COPY_RESPONSE(&info->ring, i, &bret);
+		id   = bret.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(info)) {
-			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;
+			pr_alert("%s: response has incorrect id (%ld)\n",
+				 info->gd->disk_name, id);
+			goto err;
+		}
+		if (!info->shadow[id].inflight) {
+			pr_alert("%s: response references no pending request\n",
+				 info->gd->disk_name);
+			goto err;
 		}
+
+		info->shadow[id].inflight = false;
 		req  = info->shadow[id].request;
 
-		if (bret->operation != BLKIF_OP_DISCARD)
-			blkif_completion(&info->shadow[id], info, bret);
+		op = info->shadow[id].req.operation;
+		if (op == BLKIF_OP_INDIRECT)
+			op = info->shadow[id].req.u.indirect.indirect_op;
+		if (bret.operation != op) {
+			pr_alert("%s: response has wrong operation (%u instead of %u)\n",
+				 info->gd->disk_name, bret.operation, op);
+			goto err;
+		}
+
+		if (bret.operation != BLKIF_OP_DISCARD)
+			blkif_completion(&info->shadow[id], info, &bret);
 
 		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);
+			     info->gd->disk_name, op_name(bret.operation), id);
 			continue;
 		}
 
-		error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
-		switch (bret->operation) {
+		error = (bret.status == BLKIF_RSP_OKAY) ? 0 : -EIO;
+		switch (bret.operation) {
 		case BLKIF_OP_DISCARD:
-			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+			if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) {
 				struct request_queue *rq = info->rq;
-				printk(KERN_WARNING "blkfront: %s: %s op failed\n",
-					   info->gd->disk_name, op_name(bret->operation));
+
+				pr_warn_ratelimited("blkfront: %s: %s op failed\n",
+					   info->gd->disk_name, op_name(bret.operation));
 				error = -EOPNOTSUPP;
 				info->feature_discard = 0;
 				info->feature_secdiscard = 0;
@@ -1358,15 +1398,15 @@
 			break;
 		case BLKIF_OP_FLUSH_DISKCACHE:
 		case BLKIF_OP_WRITE_BARRIER:
-			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
-				printk(KERN_WARNING "blkfront: %s: %s op failed\n",
-				       info->gd->disk_name, op_name(bret->operation));
+			if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) {
+				pr_warn_ratelimited("blkfront: %s: %s op failed\n",
+				       info->gd->disk_name, op_name(bret.operation));
 				error = -EOPNOTSUPP;
 			}
-			if (unlikely(bret->status == BLKIF_RSP_ERROR &&
+			if (unlikely(bret.status == BLKIF_RSP_ERROR &&
 				     info->shadow[id].req.u.rw.nr_segments == 0)) {
-				printk(KERN_WARNING "blkfront: %s: empty %s op failed\n",
-				       info->gd->disk_name, op_name(bret->operation));
+				pr_warn_ratelimited("blkfront: %s: empty %s op failed\n",
+				       info->gd->disk_name, op_name(bret.operation));
 				error = -EOPNOTSUPP;
 			}
 			if (unlikely(error)) {
@@ -1378,9 +1418,10 @@
 			/* fall through */
 		case BLKIF_OP_READ:
 		case BLKIF_OP_WRITE:
-			if (unlikely(bret->status != BLKIF_RSP_OKAY))
-				dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
-					"request: %x\n", bret->status);
+			if (unlikely(bret.status != BLKIF_RSP_OKAY))
+				dev_dbg_ratelimited(&info->xbdev->dev,
+					"Bad return from blkdev data request: %x\n",
+					bret.status);
 
 			blk_mq_complete_request(req, error);
 			break;
@@ -1403,6 +1444,18 @@
 
 	spin_unlock_irqrestore(&info->io_lock, flags);
 
+	xen_irq_lateeoi(irq, eoiflag);
+
+	return IRQ_HANDLED;
+
+ err:
+	info->connected = BLKIF_STATE_ERROR;
+
+	spin_unlock_irqrestore(&info->io_lock, flags);
+
+	/* No EOI in order to avoid further interrupts. */
+
+	pr_alert("%s disabled for further use\n", info->gd->disk_name);
 	return IRQ_HANDLED;
 }
 
@@ -1418,7 +1471,7 @@
 	for (i = 0; i < info->nr_ring_pages; i++)
 		info->ring_ref[i] = GRANT_INVALID_REF;
 
-	sring = (struct blkif_sring *)__get_free_pages(GFP_NOIO | __GFP_HIGH,
+	sring = (struct blkif_sring *)__get_free_pages(GFP_NOIO | __GFP_HIGH | __GFP_ZERO,
 						       get_order(ring_size));
 	if (!sring) {
 		xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
@@ -1440,8 +1493,8 @@
 	if (err)
 		goto fail;
 
-	err = bind_evtchn_to_irqhandler(info->evtchn, blkif_interrupt, 0,
-					"blkif", info);
+	err = bind_evtchn_to_irqhandler_lateeoi(info->evtchn, blkif_interrupt,
+						0, "blkif", info);
 	if (err <= 0) {
 		xenbus_dev_fatal(dev, err,
 				 "bind_evtchn_to_irqhandler failed");
@@ -1877,7 +1930,8 @@
 
 		BUG_ON(!list_empty(&info->indirect_pages));
 		for (i = 0; i < num; i++) {
-			struct page *indirect_page = alloc_page(GFP_NOIO);
+			struct page *indirect_page = alloc_page(GFP_NOIO |
+			                                        __GFP_ZERO);
 			if (!indirect_page)
 				goto out_of_memory;
 			list_add(&indirect_page->lru, &info->indirect_pages);
@@ -1913,6 +1967,7 @@
 		info->shadow[i].sg = NULL;
 		kfree(info->shadow[i].indirect_grants);
 		info->shadow[i].indirect_grants = NULL;
+		info->shadow[i].inflight = false;
 	}
 	if (!list_empty(&info->indirect_pages)) {
 		struct page *indirect_page, *n;
--- linux-4.4.0.orig/drivers/block/xsysace.c
+++ linux-4.4.0/drivers/block/xsysace.c
@@ -1062,6 +1062,8 @@
 	return 0;
 
 err_read:
+	/* prevent double queue cleanup */
+	ace->gd->queue = NULL;
 	put_disk(ace->gd);
 err_alloc_disk:
 	blk_cleanup_queue(ace->queue);
--- linux-4.4.0.orig/drivers/block/zram/zcomp.c
+++ linux-4.4.0/drivers/block/zram/zcomp.c
@@ -76,7 +76,7 @@
  */
 static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
 {
-	struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL);
+	struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_NOIO);
 	if (!zstrm)
 		return NULL;
 
@@ -85,7 +85,7 @@
 	 * allocate 2 pages. 1 for compressed data, plus 1 extra for the
 	 * case when compressed size is larger than the original one
 	 */
-	zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
+	zstrm->buffer = (void *)__get_free_pages(GFP_NOIO | __GFP_ZERO, 1);
 	if (!zstrm->private || !zstrm->buffer) {
 		zcomp_strm_free(comp, zstrm);
 		zstrm = NULL;
--- linux-4.4.0.orig/drivers/block/zram/zcomp_lz4.c
+++ linux-4.4.0/drivers/block/zram/zcomp_lz4.c
@@ -10,17 +10,36 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/lz4.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
 
 #include "zcomp_lz4.h"
 
 static void *zcomp_lz4_create(void)
 {
-	return kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
+	void *ret;
+
+	/*
+	 * This function can be called in swapout/fs write path
+	 * so we can't use GFP_FS|IO. And it assumes we already
+	 * have at least one stream in zram initialization so we
+	 * don't do best effort to allocate more stream in here.
+	 * A default stream will work well without further multiple
+	 * streams. That's why we use NORETRY | NOWARN.
+	 */
+	ret = kzalloc(LZ4_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY |
+					__GFP_NOWARN);
+	if (!ret)
+		ret = __vmalloc(LZ4_MEM_COMPRESS,
+				GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN |
+				__GFP_ZERO | __GFP_HIGHMEM,
+				PAGE_KERNEL);
+	return ret;
 }
 
 static void zcomp_lz4_destroy(void *private)
 {
-	kfree(private);
+	kvfree(private);
 }
 
 static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst,
--- linux-4.4.0.orig/drivers/block/zram/zcomp_lzo.c
+++ linux-4.4.0/drivers/block/zram/zcomp_lzo.c
@@ -10,17 +10,36 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/lzo.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
 
 #include "zcomp_lzo.h"
 
 static void *lzo_create(void)
 {
-	return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+	void *ret;
+
+	/*
+	 * This function can be called in swapout/fs write path
+	 * so we can't use GFP_FS|IO. And it assumes we already
+	 * have at least one stream in zram initialization so we
+	 * don't do best effort to allocate more stream in here.
+	 * A default stream will work well without further multiple
+	 * streams. That's why we use NORETRY | NOWARN.
+	 */
+	ret = kzalloc(LZO1X_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY |
+					__GFP_NOWARN);
+	if (!ret)
+		ret = __vmalloc(LZO1X_MEM_COMPRESS,
+				GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN |
+				__GFP_ZERO | __GFP_HIGHMEM,
+				PAGE_KERNEL);
+	return ret;
 }
 
 static void lzo_destroy(void *private)
 {
-	kfree(private);
+	kvfree(private);
 }
 
 static int lzo_compress(const unsigned char *src, unsigned char *dst,
--- linux-4.4.0.orig/drivers/block/zram/zram_drv.c
+++ linux-4.4.0/drivers/block/zram/zram_drv.c
@@ -450,7 +450,7 @@
 			zram->limit_pages << PAGE_SHIFT,
 			max_used << PAGE_SHIFT,
 			(u64)atomic64_read(&zram->stats.zero_pages),
-			pool_stats.pages_compacted);
+			atomic_long_read(&pool_stats.pages_compacted));
 	up_read(&zram->init_lock);
 
 	return ret;
@@ -574,13 +574,13 @@
 
 	if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
 		bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
-		clear_page(mem);
+		memset(mem, 0, PAGE_SIZE);
 		return 0;
 	}
 
 	cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
 	if (size == PAGE_SIZE)
-		copy_page(mem, cmem);
+		memcpy(mem, cmem, PAGE_SIZE);
 	else
 		ret = zcomp_decompress(zram->comp, cmem, size, mem);
 	zs_unmap_object(meta->mem_pool, handle);
@@ -738,7 +738,7 @@
 
 	if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
 		src = kmap_atomic(page);
-		copy_page(cmem, src);
+		memcpy(cmem, src, PAGE_SIZE);
 		kunmap_atomic(src);
 	} else {
 		memcpy(cmem, src, clen);
@@ -1184,6 +1184,11 @@
 	.attrs = zram_disk_attrs,
 };
 
+static const struct attribute_group *zram_disk_attr_groups[] = {
+	&zram_disk_attr_group,
+	NULL,
+};
+
 /*
  * Allocate and initialize new zram device. the function returns
  * '>= 0' device_id upon success, and negative value otherwise.
@@ -1247,6 +1252,8 @@
 	blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
 	blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
 	zram->disk->queue->limits.discard_granularity = PAGE_SIZE;
+	zram->disk->queue->limits.max_sectors = SECTORS_PER_PAGE;
+	zram->disk->queue->limits.chunk_sectors = 0;
 	blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX);
 	/*
 	 * zram_bio_discard() will clear all logical blocks if logical block
@@ -1262,15 +1269,9 @@
 		zram->disk->queue->limits.discard_zeroes_data = 0;
 	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue);
 
+	disk_to_dev(zram->disk)->groups = zram_disk_attr_groups;
 	add_disk(zram->disk);
 
-	ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj,
-				&zram_disk_attr_group);
-	if (ret < 0) {
-		pr_err("Error creating sysfs group for device %d\n",
-				device_id);
-		goto out_free_disk;
-	}
 	strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor));
 	zram->meta = NULL;
 	zram->max_comp_streams = 1;
@@ -1278,9 +1279,6 @@
 	pr_info("Added device: %s\n", zram->disk->disk_name);
 	return device_id;
 
-out_free_disk:
-	del_gendisk(zram->disk);
-	put_disk(zram->disk);
 out_free_queue:
 	blk_cleanup_queue(queue);
 out_free_idr:
@@ -1308,16 +1306,6 @@
 	zram->claim = true;
 	mutex_unlock(&bdev->bd_mutex);
 
-	/*
-	 * Remove sysfs first, so no one will perform a disksize
-	 * store while we destroy the devices. This also helps during
-	 * hot_remove -- zram_reset_device() is the last holder of
-	 * ->init_lock, no later/concurrent disksize_store() or any
-	 * other sysfs handlers are possible.
-	 */
-	sysfs_remove_group(&disk_to_dev(zram->disk)->kobj,
-			&zram_disk_attr_group);
-
 	/* Make sure all the pending I/O are finished */
 	fsync_bdev(bdev);
 	zram_reset_device(zram);
@@ -1325,7 +1313,6 @@
 
 	pr_info("Removed device: %s\n", zram->disk->disk_name);
 
-	idr_remove(&zram_index_idr, zram->disk->first_minor);
 	blk_cleanup_queue(zram->disk->queue);
 	del_gendisk(zram->disk);
 	put_disk(zram->disk);
@@ -1367,17 +1354,26 @@
 	mutex_lock(&zram_index_mutex);
 
 	zram = idr_find(&zram_index_idr, dev_id);
-	if (zram)
+	if (zram) {
 		ret = zram_remove(zram);
-	else
+		if (!ret)
+			idr_remove(&zram_index_idr, dev_id);
+	} else {
 		ret = -ENODEV;
+	}
 
 	mutex_unlock(&zram_index_mutex);
 	return ret ? ret : count;
 }
 
+/*
+ * NOTE: hot_add attribute is not the usual read-only sysfs attribute. In a
+ * sense that reading from this file does alter the state of your system -- it
+ * creates a new un-initialized zram device and returns back this device's
+ * device_id (or an error code if it fails to create a new device).
+ */
 static struct class_attribute zram_control_class_attrs[] = {
-	__ATTR_RO(hot_add),
+	__ATTR(hot_add, 0400, hot_add_show, NULL),
 	__ATTR_WO(hot_remove),
 	__ATTR_NULL,
 };
--- linux-4.4.0.orig/drivers/block/zram/zram_drv.h
+++ linux-4.4.0/drivers/block/zram/zram_drv.h
@@ -36,7 +36,6 @@
 
 /*-- End of configurable params */
 
-#define SECTOR_SHIFT		9
 #define SECTORS_PER_PAGE_SHIFT	(PAGE_SHIFT - SECTOR_SHIFT)
 #define SECTORS_PER_PAGE	(1 << SECTORS_PER_PAGE_SHIFT)
 #define ZRAM_LOGICAL_BLOCK_SHIFT 12
--- linux-4.4.0.orig/drivers/bluetooth/ath3k.c
+++ linux-4.4.0/drivers/bluetooth/ath3k.c
@@ -82,6 +82,7 @@
 	{ USB_DEVICE(0x0489, 0xe05f) },
 	{ USB_DEVICE(0x0489, 0xe076) },
 	{ USB_DEVICE(0x0489, 0xe078) },
+	{ USB_DEVICE(0x0489, 0xe095) },
 	{ USB_DEVICE(0x04c5, 0x1330) },
 	{ USB_DEVICE(0x04CA, 0x3004) },
 	{ USB_DEVICE(0x04CA, 0x3005) },
@@ -92,6 +93,8 @@
 	{ USB_DEVICE(0x04CA, 0x300d) },
 	{ USB_DEVICE(0x04CA, 0x300f) },
 	{ USB_DEVICE(0x04CA, 0x3010) },
+	{ USB_DEVICE(0x04CA, 0x3014) },
+	{ USB_DEVICE(0x04CA, 0x3018) },
 	{ USB_DEVICE(0x0930, 0x0219) },
 	{ USB_DEVICE(0x0930, 0x021c) },
 	{ USB_DEVICE(0x0930, 0x0220) },
@@ -113,10 +116,12 @@
 	{ USB_DEVICE(0x13d3, 0x3362) },
 	{ USB_DEVICE(0x13d3, 0x3375) },
 	{ USB_DEVICE(0x13d3, 0x3393) },
+	{ USB_DEVICE(0x13d3, 0x3395) },
 	{ USB_DEVICE(0x13d3, 0x3402) },
 	{ USB_DEVICE(0x13d3, 0x3408) },
 	{ USB_DEVICE(0x13d3, 0x3423) },
 	{ USB_DEVICE(0x13d3, 0x3432) },
+	{ USB_DEVICE(0x13d3, 0x3472) },
 	{ USB_DEVICE(0x13d3, 0x3474) },
 
 	/* Atheros AR5BBU12 with sflash firmware */
@@ -144,6 +149,7 @@
 	{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0489, 0xe095), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
@@ -154,6 +160,8 @@
 	{ USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
@@ -175,10 +183,12 @@
 	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x13d3, 0x3395), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU22 with sflash firmware */
--- linux-4.4.0.orig/drivers/bluetooth/btbcm.c
+++ linux-4.4.0/drivers/bluetooth/btbcm.c
@@ -178,6 +178,9 @@
 	}
 	kfree_skb(skb);
 
+	/* 100 msec delay for module to complete reset process */
+	msleep(100);
+
 	return 0;
 }
 
@@ -270,6 +273,7 @@
 	{ 0x4103, "BCM4330B1"	},	/* 002.001.003 */
 	{ 0x410e, "BCM43341B0"	},	/* 002.001.014 */
 	{ 0x4406, "BCM4324B3"	},	/* 002.004.006 */
+	{ 0x6109, "BCM4335C0"	},	/* 003.001.009 */
 	{ 0x610c, "BCM4354"	},	/* 003.001.012 */
 	{ }
 };
--- linux-4.4.0.orig/drivers/bluetooth/btintel.c
+++ linux-4.4.0/drivers/bluetooth/btintel.c
@@ -343,6 +343,31 @@
 }
 EXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg);
 
+int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
+{
+	struct sk_buff *skb;
+
+	skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT);
+	if (IS_ERR(skb)) {
+		bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
+			   PTR_ERR(skb));
+		return PTR_ERR(skb);
+	}
+
+	if (skb->len != sizeof(*ver)) {
+		bt_dev_err(hdev, "Intel version event size mismatch");
+		kfree_skb(skb);
+		return -EILSEQ;
+	}
+
+	memcpy(ver, skb->data, sizeof(*ver));
+
+	kfree_skb(skb);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(btintel_read_version);
+
 /* ------- REGMAP IBT SUPPORT ------- */
 
 #define IBT_REG_MODE_8BIT  0x00
@@ -544,3 +569,5 @@
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE("intel/ibt-11-5.sfi");
 MODULE_FIRMWARE("intel/ibt-11-5.ddc");
+MODULE_FIRMWARE("intel/ibt-12-16.sfi");
+MODULE_FIRMWARE("intel/ibt-12-16.ddc");
--- linux-4.4.0.orig/drivers/bluetooth/btintel.h
+++ linux-4.4.0/drivers/bluetooth/btintel.h
@@ -83,6 +83,7 @@
 int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
 int btintel_set_event_mask(struct hci_dev *hdev, bool debug);
 int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug);
+int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver);
 
 struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
 				   u16 opcode_write);
@@ -139,6 +140,12 @@
 {
 	return -EOPNOTSUPP;
 }
+
+static inline int btintel_read_version(struct hci_dev *hdev,
+				       struct intel_version *ver)
+{
+	return -EOPNOTSUPP;
+}
 
 static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,
 						 u16 opcode_read,
--- linux-4.4.0.orig/drivers/bluetooth/btmrvl_sdio.c
+++ linux-4.4.0/drivers/bluetooth/btmrvl_sdio.c
@@ -1112,7 +1112,8 @@
 	 */
 	if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
 		BT_ERR("FW failed to be active in time!");
-		return -ETIMEDOUT;
+		ret = -ETIMEDOUT;
+		goto done;
 	}
 
 	sdio_release_host(card->func);
--- linux-4.4.0.orig/drivers/bluetooth/btqca.c
+++ linux-4.4.0/drivers/bluetooth/btqca.c
@@ -363,6 +363,9 @@
 		return err;
 	}
 
+	/* Give the controller some time to get ready to receive the NVM */
+	msleep(10);
+
 	/* Download NVM configuration */
 	config.type = TLV_TYPE_NVM;
 	snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin",
--- linux-4.4.0.orig/drivers/bluetooth/btsdio.c
+++ linux-4.4.0/drivers/bluetooth/btsdio.c
@@ -31,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/skbuff.h>
 
+#include <linux/mmc/host.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio_func.h>
 
@@ -291,6 +292,14 @@
 		tuple = tuple->next;
 	}
 
+	/* BCM43341 devices soldered onto the PCB (non-removable) use an
+	 * uart connection for bluetooth, ignore the BT SDIO interface.
+	 */
+	if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
+	    func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
+	    !mmc_card_is_removable(func->card->host))
+		return -ENODEV;
+
 	data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/bluetooth/btusb.c
+++ linux-4.4.0/drivers/bluetooth/btusb.c
@@ -23,7 +23,9 @@
 
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/usb/quirks.h>
 #include <linux/firmware.h>
+#include <linux/pci.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -153,6 +155,14 @@
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01),
 	  .driver_info = BTUSB_BCM_PATCHRAM },
 
+	/* Dell Computer - Broadcom based  */
+	{ USB_VENDOR_AND_INTERFACE_INFO(0x413c, 0xff, 0x01, 0x01),
+	  .driver_info = BTUSB_BCM_PATCHRAM },
+
+	/* Toshiba Corp - Broadcom based */
+	{ USB_VENDOR_AND_INTERFACE_INFO(0x0930, 0xff, 0x01, 0x01),
+	  .driver_info = BTUSB_BCM_PATCHRAM },
+
 	/* Intel Bluetooth USB Bootloader (RAM module) */
 	{ USB_DEVICE(0x8087, 0x0a5a),
 	  .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC },
@@ -192,6 +202,7 @@
 	{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0489, 0xe095), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
@@ -202,6 +213,8 @@
 	{ USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
@@ -223,10 +236,12 @@
 	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x13d3, 0x3395), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU12 with sflash firmware */
@@ -238,8 +253,10 @@
 
 	/* QCA ROME chipset */
 	{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
+	{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
 	{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
 	{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },
+	{ USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME },
 
 	/* Broadcom BCM2035 */
 	{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
@@ -305,6 +322,7 @@
 	{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
 	{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
 	{ USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW },
+	{ USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL },
 
 	/* Other Intel Bluetooth devices */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01),
@@ -324,6 +342,14 @@
 	{ USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK },
 	{ USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK },
 	{ USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK },
+	{ USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK },
+
+	/* Additional Realtek 8723BU Bluetooth devices */
+	{ USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK },
+
+	/* Additional Realtek 8723DE Bluetooth devices */
+	{ USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },
+	{ USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK },
 
 	/* Additional Realtek 8821AE Bluetooth devices */
 	{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
@@ -332,6 +358,12 @@
 	{ USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK },
 	{ USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK },
 
+	/* Additional Realtek 8822BE Bluetooth devices */
+	{ USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK },
+
+	/* Additional Realtek 8822CE Bluetooth devices */
+	{ USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK },
+
 	/* Silicon Wave based devices */
 	{ USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
 
@@ -350,8 +382,8 @@
 #define BTUSB_FIRMWARE_LOADED	7
 #define BTUSB_FIRMWARE_FAILED	8
 #define BTUSB_BOOTING		9
-#define BTUSB_RESET_RESUME	10
-#define BTUSB_DIAG_RUNNING	11
+#define BTUSB_DIAG_RUNNING	10
+#define BTUSB_OOB_WAKE_ENABLED	11
 
 struct btusb_data {
 	struct hci_dev       *hdev;
@@ -1026,19 +1058,19 @@
 
 	BT_DBG("%s", hdev->name);
 
+	err = usb_autopm_get_interface(data->intf);
+	if (err < 0)
+		return err;
+
 	/* Patching USB firmware files prior to starting any URBs of HCI path
 	 * It is more safe to use USB bulk channel for downloading USB patch
 	 */
 	if (data->setup_on_usb) {
 		err = data->setup_on_usb(hdev);
 		if (err < 0)
-			return err;
+			goto setup_fail;
 	}
 
-	err = usb_autopm_get_interface(data->intf);
-	if (err < 0)
-		return err;
-
 	data->intf->needs_remote_wakeup = 1;
 
 	if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
@@ -1068,6 +1100,7 @@
 
 failed:
 	clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+setup_fail:
 	usb_autopm_put_interface(data->intf);
 	return err;
 }
@@ -1642,8 +1675,8 @@
 	struct sk_buff *skb;
 	const struct firmware *fw;
 	const u8 *fw_ptr;
-	int disable_patch;
-	struct intel_version *ver;
+	int disable_patch, err;
+	struct intel_version ver;
 
 	const u8 mfg_enable[] = { 0x01, 0x00 };
 	const u8 mfg_disable[] = { 0x00, 0x00 };
@@ -1674,35 +1707,22 @@
 	 * The returned information are hardware variant and revision plus
 	 * firmware variant, revision and build number.
 	 */
-	skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
-	if (IS_ERR(skb)) {
-		BT_ERR("%s reading Intel fw version command failed (%ld)",
-		       hdev->name, PTR_ERR(skb));
-		return PTR_ERR(skb);
-	}
-
-	if (skb->len != sizeof(*ver)) {
-		BT_ERR("%s Intel version event length mismatch", hdev->name);
-		kfree_skb(skb);
-		return -EIO;
-	}
-
-	ver = (struct intel_version *)skb->data;
+	err = btintel_read_version(hdev, &ver);
+	if (err)
+		return err;
 
 	BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x",
-		hdev->name, ver->hw_platform, ver->hw_variant,
-		ver->hw_revision, ver->fw_variant,  ver->fw_revision,
-		ver->fw_build_num, ver->fw_build_ww, ver->fw_build_yy,
-		ver->fw_patch_num);
+		hdev->name, ver.hw_platform, ver.hw_variant, ver.hw_revision,
+		ver.fw_variant,  ver.fw_revision, ver.fw_build_num,
+		ver.fw_build_ww, ver.fw_build_yy, ver.fw_patch_num);
 
 	/* fw_patch_num indicates the version of patch the device currently
 	 * have. If there is no patch data in the device, it is always 0x00.
 	 * So, if it is other than 0x00, no need to patch the device again.
 	 */
-	if (ver->fw_patch_num) {
+	if (ver.fw_patch_num) {
 		BT_INFO("%s: Intel device is already patched. patch num: %02x",
-			hdev->name, ver->fw_patch_num);
-		kfree_skb(skb);
+			hdev->name, ver.fw_patch_num);
 		goto complete;
 	}
 
@@ -1712,15 +1732,11 @@
 	 * If no patch file is found, allow the device to operate without
 	 * a patch.
 	 */
-	fw = btusb_setup_intel_get_fw(hdev, ver);
-	if (!fw) {
-		kfree_skb(skb);
+	fw = btusb_setup_intel_get_fw(hdev, &ver);
+	if (!fw)
 		goto complete;
-	}
 	fw_ptr = fw->data;
 
-	kfree_skb(skb);
-
 	/* This Intel specific command enables the manufacturer mode of the
 	 * controller.
 	 *
@@ -2005,7 +2021,7 @@
 					  0x00, 0x08, 0x04, 0x00 };
 	struct btusb_data *data = hci_get_drvdata(hdev);
 	struct sk_buff *skb;
-	struct intel_version *ver;
+	struct intel_version ver;
 	struct intel_boot_params *params;
 	const struct firmware *fw;
 	const u8 *fw_ptr;
@@ -2023,44 +2039,36 @@
 	 * is in bootloader mode or if it already has operational firmware
 	 * loaded.
 	 */
-	skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
-	if (IS_ERR(skb)) {
-		BT_ERR("%s: Reading Intel version information failed (%ld)",
-		       hdev->name, PTR_ERR(skb));
-		return PTR_ERR(skb);
-	}
-
-	if (skb->len != sizeof(*ver)) {
-		BT_ERR("%s: Intel version event size mismatch", hdev->name);
-		kfree_skb(skb);
-		return -EILSEQ;
-	}
-
-	ver = (struct intel_version *)skb->data;
+	err = btintel_read_version(hdev, &ver);
+	if (err)
+		return err;
 
 	/* The hardware platform number has a fixed value of 0x37 and
 	 * for now only accept this single value.
 	 */
-	if (ver->hw_platform != 0x37) {
+	if (ver.hw_platform != 0x37) {
 		BT_ERR("%s: Unsupported Intel hardware platform (%u)",
-		       hdev->name, ver->hw_platform);
-		kfree_skb(skb);
+		       hdev->name, ver.hw_platform);
 		return -EINVAL;
 	}
 
-	/* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is
-	 * supported by this firmware loading method. This check has been
-	 * put in place to ensure correct forward compatibility options
-	 * when newer hardware variants come along.
+	/* Check for supported iBT hardware variants of this firmware
+	 * loading method.
+	 *
+	 * This check has been put in place to ensure correct forward
+	 * compatibility options when newer hardware variants come along.
 	 */
-	if (ver->hw_variant != 0x0b) {
+	switch (ver.hw_variant) {
+	case 0x0b:	/* SfP */
+	case 0x0c:	/* WsP */
+		break;
+	default:
 		BT_ERR("%s: Unsupported Intel hardware variant (%u)",
-		       hdev->name, ver->hw_variant);
-		kfree_skb(skb);
+		       hdev->name, ver.hw_variant);
 		return -EINVAL;
 	}
 
-	btintel_version_info(hdev, ver);
+	btintel_version_info(hdev, &ver);
 
 	/* The firmware variant determines if the device is in bootloader
 	 * mode or is running operational firmware. The value 0x06 identifies
@@ -2075,8 +2083,7 @@
 	 * It is not possible to use the Secure Boot Parameters in this
 	 * case since that command is only available in bootloader mode.
 	 */
-	if (ver->fw_variant == 0x23) {
-		kfree_skb(skb);
+	if (ver.fw_variant == 0x23) {
 		clear_bit(BTUSB_BOOTLOADER, &data->flags);
 		btintel_check_bdaddr(hdev);
 		return 0;
@@ -2085,15 +2092,12 @@
 	/* If the device is not in bootloader mode, then the only possible
 	 * choice is to return an error and abort the device initialization.
 	 */
-	if (ver->fw_variant != 0x06) {
+	if (ver.fw_variant != 0x06) {
 		BT_ERR("%s: Unsupported Intel firmware variant (%u)",
-		       hdev->name, ver->fw_variant);
-		kfree_skb(skb);
+		       hdev->name, ver.fw_variant);
 		return -ENODEV;
 	}
 
-	kfree_skb(skb);
-
 	/* Read the secure boot parameters to identify the operating
 	 * details of the bootloader.
 	 */
@@ -2153,10 +2157,14 @@
 	/* With this Intel bootloader only the hardware variant and device
 	 * revision information are used to select the right firmware.
 	 *
-	 * Currently this bootloader support is limited to hardware variant
-	 * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b).
+	 * The firmware filename is ibt-<hw_variant>-<dev_revid>.sfi.
+	 *
+	 * Currently the supported hardware variants are:
+	 *   11 (0x0b) for iBT3.0 (LnP/SfP)
+	 *   12 (0x0c) for iBT3.5 (WsP)
 	 */
-	snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi",
+	snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi",
+		 le16_to_cpu(ver.hw_variant),
 		 le16_to_cpu(params->dev_revid));
 
 	err = request_firmware(&fw, fwname, &hdev->dev);
@@ -2172,7 +2180,8 @@
 	/* Save the DDC file name for later use to apply once the firmware
 	 * downloading is done.
 	 */
-	snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
+	snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc",
+		 le16_to_cpu(ver.hw_variant),
 		 le16_to_cpu(params->dev_revid));
 
 	kfree_skb(skb);
@@ -2766,6 +2775,33 @@
 }
 #endif
 
+#define BTUSB_EDGE_LED_COMMAND		0xfc77
+static void btusb_edge_set_led(struct hci_dev *hdev, bool state)
+{
+	struct sk_buff *skb;
+	u8 config_led[] = { 0x09, 0x00, 0x01, 0x01 };
+
+	if (state)
+		config_led[1] = 0x01;
+
+	skb = __hci_cmd_sync(hdev, BTUSB_EDGE_LED_COMMAND, sizeof(config_led), config_led, HCI_INIT_TIMEOUT);
+	if (IS_ERR(skb))
+		BT_ERR("%s fail to set LED (%ld)", hdev->name, PTR_ERR(skb));
+	else
+		kfree_skb(skb);
+}
+
+static void btusb_edge_post_open(struct hci_dev *hdev)
+{
+	btusb_edge_set_led(hdev, true);
+}
+
+static int btusb_edge_shutdown(struct hci_dev *hdev)
+{
+	btusb_edge_set_led(hdev, false);
+	return 0;
+}
+
 static int btusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 {
@@ -2936,8 +2972,18 @@
 		set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
 	}
 
-	if (id->driver_info & BTUSB_MARVELL)
+	if (id->driver_info & BTUSB_MARVELL) {
+		struct pci_dev *pdev;
 		hdev->set_bdaddr = btusb_set_bdaddr_marvell;
+		pdev = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, 0x1028, 0x0720, NULL);
+		if (!pdev)
+			pdev = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, 0x1028, 0x0733, NULL);
+		if (pdev) {
+			pci_dev_put(pdev);
+			hdev->post_open = btusb_edge_post_open;
+			hdev->shutdown = btusb_edge_shutdown;
+		}
+	}
 
 	if (id->driver_info & BTUSB_SWAVE) {
 		set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
@@ -2958,6 +3004,12 @@
 	if (id->driver_info & BTUSB_QCA_ROME) {
 		data->setup_on_usb = btusb_setup_qca;
 		hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
+
+		/* QCA Rome devices lose their updated firmware over suspend,
+		 * but the USB hub doesn't notice any status change.
+		 * explicitly request a device reset on resume.
+		 */
+		interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
 	}
 
 #ifdef CONFIG_BT_HCIBTUSB_RTL
@@ -2968,7 +3020,7 @@
 		 * but the USB hub doesn't notice any status change.
 		 * Explicitly request a device reset on resume.
 		 */
-		set_bit(BTUSB_RESET_RESUME, &data->flags);
+		interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
 	}
 #endif
 
@@ -3125,14 +3177,6 @@
 	btusb_stop_traffic(data);
 	usb_kill_anchored_urbs(&data->tx_anchor);
 
-	/* Optionally request a device reset on resume, but only when
-	 * wakeups are disabled. If wakeups are enabled we assume the
-	 * device will stay powered up throughout suspend.
-	 */
-	if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
-	    !device_may_wakeup(&data->udev->dev))
-		data->udev->reset_resume = 1;
-
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/bluetooth/hci_ath.c
+++ linux-4.4.0/drivers/bluetooth/hci_ath.c
@@ -101,6 +101,9 @@
 
 	BT_DBG("hu %p", hu);
 
+	if (!hci_uart_has_flow_control(hu))
+		return -EOPNOTSUPP;
+
 	ath = kzalloc(sizeof(*ath), GFP_KERNEL);
 	if (!ath)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/bluetooth/hci_bcm.c
+++ linux-4.4.0/drivers/bluetooth/hci_bcm.c
@@ -279,6 +279,9 @@
 
 	bt_dev_dbg(hu->hdev, "hu %p", hu);
 
+	if (!hci_uart_has_flow_control(hu))
+		return -EOPNOTSUPP;
+
 	bcm = kzalloc(sizeof(*bcm), GFP_KERNEL);
 	if (!bcm)
 		return -ENOMEM;
@@ -287,6 +290,9 @@
 
 	hu->priv = bcm;
 
+	if (!hu->tty->dev)
+		goto out;
+
 	mutex_lock(&bcm_device_lock);
 	list_for_each(p, &bcm_device_list) {
 		struct bcm_device *dev = list_entry(p, struct bcm_device, list);
@@ -307,7 +313,7 @@
 	}
 
 	mutex_unlock(&bcm_device_lock);
-
+out:
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/bluetooth/hci_bcsp.c
+++ linux-4.4.0/drivers/bluetooth/hci_bcsp.c
@@ -566,6 +566,7 @@
 			if (*ptr == 0xc0) {
 				BT_ERR("Short BCSP packet");
 				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_skb = NULL;
 				bcsp->rx_state = BCSP_W4_PKT_START;
 				bcsp->rx_count = 0;
 			} else
@@ -581,6 +582,7 @@
 					bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
 				BT_ERR("Error in BCSP hdr checksum");
 				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_skb = NULL;
 				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
 				bcsp->rx_count = 0;
 				continue;
@@ -615,6 +617,7 @@
 					bscp_get_crc(bcsp));
 
 				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_skb = NULL;
 				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
 				bcsp->rx_count = 0;
 				continue;
@@ -729,6 +732,11 @@
 	skb_queue_purge(&bcsp->rel);
 	skb_queue_purge(&bcsp->unrel);
 
+	if (bcsp->rx_skb) {
+		kfree_skb(bcsp->rx_skb);
+		bcsp->rx_skb = NULL;
+	}
+
 	kfree(bcsp);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/bluetooth/hci_intel.c
+++ linux-4.4.0/drivers/bluetooth/hci_intel.c
@@ -307,6 +307,9 @@
 	struct list_head *p;
 	int err = -ENODEV;
 
+	if (!hu->tty->dev)
+		return err;
+
 	mutex_lock(&intel_device_list_lock);
 
 	list_for_each(p, &intel_device_list) {
@@ -379,6 +382,9 @@
 	struct intel_data *intel = container_of(work, struct intel_data,
 						busy_work);
 
+	if (!intel->hu->tty->dev)
+		return;
+
 	/* Link is busy, delay the suspend */
 	mutex_lock(&intel_device_list_lock);
 	list_for_each(p, &intel_device_list) {
@@ -401,6 +407,9 @@
 
 	BT_DBG("hu %p", hu);
 
+	if (!hci_uart_has_flow_control(hu))
+		return -EOPNOTSUPP;
+
 	intel = kzalloc(sizeof(*intel), GFP_KERNEL);
 	if (!intel)
 		return -ENOMEM;
@@ -542,7 +551,7 @@
 	struct intel_device *idev = NULL;
 	struct hci_dev *hdev = hu->hdev;
 	struct sk_buff *skb;
-	struct intel_version *ver;
+	struct intel_version ver;
 	struct intel_boot_params *params;
 	struct list_head *p;
 	const struct firmware *fw;
@@ -590,51 +599,36 @@
 	 * is in bootloader mode or if it already has operational firmware
 	 * loaded.
 	 */
-	skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
-	if (IS_ERR(skb)) {
-		bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
-			   PTR_ERR(skb));
-		return PTR_ERR(skb);
-	}
-
-	if (skb->len != sizeof(*ver)) {
-		bt_dev_err(hdev, "Intel version event size mismatch");
-		kfree_skb(skb);
-		return -EILSEQ;
-	}
-
-	ver = (struct intel_version *)skb->data;
-	if (ver->status) {
-		bt_dev_err(hdev, "Intel version command failure (%02x)",
-			   ver->status);
-		err = -bt_to_errno(ver->status);
-		kfree_skb(skb);
+	 err = btintel_read_version(hdev, &ver);
+	 if (err)
 		return err;
-	}
 
 	/* The hardware platform number has a fixed value of 0x37 and
 	 * for now only accept this single value.
 	 */
-	if (ver->hw_platform != 0x37) {
+	if (ver.hw_platform != 0x37) {
 		bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
-			   ver->hw_platform);
-		kfree_skb(skb);
+			   ver.hw_platform);
 		return -EINVAL;
 	}
 
-	/* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is
-	 * supported by this firmware loading method. This check has been
-	 * put in place to ensure correct forward compatibility options
-	 * when newer hardware variants come along.
-	 */
-	if (ver->hw_variant != 0x0b) {
+        /* Check for supported iBT hardware variants of this firmware
+         * loading method.
+         *
+         * This check has been put in place to ensure correct forward
+         * compatibility options when newer hardware variants come along.
+         */
+	switch (ver.hw_variant) {
+	case 0x0b:	/* LnP */
+	case 0x0c:	/* WsP */
+		break;
+	default:
 		bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
-			   ver->hw_variant);
-		kfree_skb(skb);
+			   ver.hw_variant);
 		return -EINVAL;
 	}
 
-	btintel_version_info(hdev, ver);
+	btintel_version_info(hdev, &ver);
 
 	/* The firmware variant determines if the device is in bootloader
 	 * mode or is running operational firmware. The value 0x06 identifies
@@ -649,8 +643,7 @@
 	 * It is not possible to use the Secure Boot Parameters in this
 	 * case since that command is only available in bootloader mode.
 	 */
-	if (ver->fw_variant == 0x23) {
-		kfree_skb(skb);
+	if (ver.fw_variant == 0x23) {
 		clear_bit(STATE_BOOTLOADER, &intel->flags);
 		btintel_check_bdaddr(hdev);
 		return 0;
@@ -659,15 +652,12 @@
 	/* If the device is not in bootloader mode, then the only possible
 	 * choice is to return an error and abort the device initialization.
 	 */
-	if (ver->fw_variant != 0x06) {
+	if (ver.fw_variant != 0x06) {
 		bt_dev_err(hdev, "Unsupported Intel firmware variant (%u)",
-			   ver->fw_variant);
-		kfree_skb(skb);
+			   ver.fw_variant);
 		return -ENODEV;
 	}
 
-	kfree_skb(skb);
-
 	/* Read the secure boot parameters to identify the operating
 	 * details of the bootloader.
 	 */
@@ -725,11 +715,14 @@
 	/* With this Intel bootloader only the hardware variant and device
 	 * revision information are used to select the right firmware.
 	 *
-	 * Currently this bootloader support is limited to hardware variant
-	 * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b).
+	 * The firmware filename is ibt-<hw_variant>-<dev_revid>.sfi.
+	 *
+	 * Currently the supported hardware variants are:
+	 *   11 (0x0b) for iBT 3.0 (LnP/SfP)
 	 */
-	snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi",
-		 le16_to_cpu(params->dev_revid));
+	snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi",
+		le16_to_cpu(ver.hw_variant),
+		le16_to_cpu(params->dev_revid));
 
 	err = request_firmware(&fw, fwname, &hdev->dev);
 	if (err < 0) {
@@ -742,8 +735,9 @@
 	bt_dev_info(hdev, "Found device firmware: %s", fwname);
 
 	/* Save the DDC file name for later */
-	snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
-		 le16_to_cpu(params->dev_revid));
+	snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc",
+		le16_to_cpu(ver.hw_variant),
+		le16_to_cpu(params->dev_revid));
 
 	kfree_skb(skb);
 
@@ -913,6 +907,8 @@
 	list_for_each(p, &intel_device_list) {
 		struct intel_device *dev = list_entry(p, struct intel_device,
 						      list);
+		if (!hu->tty->dev)
+			break;
 		if (hu->tty->dev->parent == dev->pdev->dev.parent) {
 			if (device_may_wakeup(&dev->pdev->dev))
 				idev = dev;
@@ -1094,6 +1090,9 @@
 
 	BT_DBG("hu %p skb %p", hu, skb);
 
+	if (!hu->tty->dev)
+		goto out_enqueue;
+
 	/* Be sure our controller is resumed and potential LPM transaction
 	 * completed before enqueuing any packet.
 	 */
@@ -1110,7 +1109,7 @@
 		}
 	}
 	mutex_unlock(&intel_device_list_lock);
-
+out_enqueue:
 	skb_queue_tail(&intel->txq, skb);
 
 	return 0;
@@ -1234,8 +1233,7 @@
 
 	idev->pdev = pdev;
 
-	idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset",
-					      GPIOD_OUT_LOW);
+	idev->reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(idev->reset)) {
 		dev_err(&pdev->dev, "Unable to retrieve gpio\n");
 		return PTR_ERR(idev->reset);
@@ -1247,8 +1245,7 @@
 
 		dev_err(&pdev->dev, "No IRQ, falling back to gpio-irq\n");
 
-		host_wake = devm_gpiod_get_optional(&pdev->dev, "host-wake",
-						    GPIOD_IN);
+		host_wake = devm_gpiod_get(&pdev->dev, "host-wake", GPIOD_IN);
 		if (IS_ERR(host_wake)) {
 			dev_err(&pdev->dev, "Unable to retrieve IRQ\n");
 			goto no_irq;
--- linux-4.4.0.orig/drivers/bluetooth/hci_ldisc.c
+++ linux-4.4.0/drivers/bluetooth/hci_ldisc.c
@@ -227,7 +227,7 @@
 	tty_ldisc_flush(tty);
 	tty_driver_flush_buffer(tty);
 
-	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+	if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
 		hu->proto->flush(hu);
 
 	return 0;
@@ -257,6 +257,15 @@
 	return 0;
 }
 
+/* Check the underlying device or tty has flow control support */
+bool hci_uart_has_flow_control(struct hci_uart *hu)
+{
+	if (hu->tty->driver->ops->tiocmget && hu->tty->driver->ops->tiocmset)
+		return true;
+
+	return false;
+}
+
 /* Flow control or un-flow control the device */
 void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
 {
@@ -497,7 +506,7 @@
 
 	cancel_work_sync(&hu->write_work);
 
-	if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+	if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) {
 		if (hdev) {
 			if (test_bit(HCI_UART_REGISTERED, &hu->flags))
 				hci_unregister_dev(hdev);
@@ -505,6 +514,7 @@
 		}
 		hu->proto->close(hu);
 	}
+	clear_bit(HCI_UART_PROTO_SET, &hu->flags);
 
 	kfree(hu);
 }
@@ -531,7 +541,7 @@
 	if (tty != hu->tty)
 		return;
 
-	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+	if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
 		hci_uart_tx_wakeup(hu);
 }
 
@@ -555,7 +565,7 @@
 	if (!hu || tty != hu->tty)
 		return;
 
-	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
+	if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
 		return;
 
 	/* It does not need a lock here as it is already protected by a mutex in
@@ -650,6 +660,7 @@
 		return err;
 	}
 
+	set_bit(HCI_UART_PROTO_READY, &hu->flags);
 	return 0;
 }
 
@@ -708,7 +719,8 @@
 		break;
 
 	case HCIUARTGETPROTO:
-		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+		if (test_bit(HCI_UART_PROTO_SET, &hu->flags) &&
+		    test_bit(HCI_UART_PROTO_READY, &hu->flags))
 			return hu->proto->id;
 		return -EUNATCH;
 
--- linux-4.4.0.orig/drivers/bluetooth/hci_qca.c
+++ linux-4.4.0/drivers/bluetooth/hci_qca.c
@@ -884,7 +884,7 @@
 	 */
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
-	set_current_state(TASK_INTERRUPTIBLE);
+	set_current_state(TASK_RUNNING);
 
 	return 0;
 }
@@ -936,6 +936,15 @@
 	if (!ret) {
 		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
 		qca_debugfs_init(hdev);
+	} else if (ret == -ENOENT) {
+		/* No patch/nvm-config found, run with original fw/config */
+		ret = 0;
+	} else if (ret == -EAGAIN) {
+		/*
+		 * Userspace firmware loader will return -EAGAIN in case no
+		 * patch/nvm-config is found, so run with original fw/config.
+		 */
+		ret = 0;
 	}
 
 	/* Setup bdaddr */
--- linux-4.4.0.orig/drivers/bluetooth/hci_uart.h
+++ linux-4.4.0/drivers/bluetooth/hci_uart.h
@@ -94,6 +94,7 @@
 /* HCI_UART proto flag bits */
 #define HCI_UART_PROTO_SET	0
 #define HCI_UART_REGISTERED	1
+#define HCI_UART_PROTO_READY	2
 
 /* TX states  */
 #define HCI_UART_SENDING	1
@@ -105,6 +106,7 @@
 int hci_uart_init_ready(struct hci_uart *hu);
 void hci_uart_init_tty(struct hci_uart *hu);
 void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
+bool hci_uart_has_flow_control(struct hci_uart *hu);
 void hci_uart_set_flow_control(struct hci_uart *hu, bool enable);
 void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
 			 unsigned int oper_speed);
--- linux-4.4.0.orig/drivers/bluetooth/hci_vhci.c
+++ linux-4.4.0/drivers/bluetooth/hci_vhci.c
@@ -50,6 +50,7 @@
 	wait_queue_head_t read_wait;
 	struct sk_buff_head readq;
 
+	struct mutex open_mutex;
 	struct delayed_work open_timeout;
 };
 
@@ -87,12 +88,15 @@
 	return 0;
 }
 
-static int vhci_create_device(struct vhci_data *data, __u8 opcode)
+static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
 {
 	struct hci_dev *hdev;
 	struct sk_buff *skb;
 	__u8 dev_type;
 
+	if (data->hdev)
+		return -EBADFD;
+
 	/* bits 0-1 are dev_type (BR/EDR or AMP) */
 	dev_type = opcode & 0x03;
 
@@ -151,6 +155,17 @@
 	return 0;
 }
 
+static int vhci_create_device(struct vhci_data *data, __u8 opcode)
+{
+	int err;
+
+	mutex_lock(&data->open_mutex);
+	err = __vhci_create_device(data, opcode);
+	mutex_unlock(&data->open_mutex);
+
+	return err;
+}
+
 static inline ssize_t vhci_get_user(struct vhci_data *data,
 				    struct iov_iter *from)
 {
@@ -189,11 +204,6 @@
 		break;
 
 	case HCI_VENDOR_PKT:
-		if (data->hdev) {
-			kfree_skb(skb);
-			return -EBADFD;
-		}
-
 		cancel_delayed_work_sync(&data->open_timeout);
 
 		opcode = *((__u8 *) skb->data);
@@ -320,6 +330,7 @@
 	skb_queue_head_init(&data->readq);
 	init_waitqueue_head(&data->read_wait);
 
+	mutex_init(&data->open_mutex);
 	INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout);
 
 	file->private_data = data;
@@ -333,15 +344,18 @@
 static int vhci_release(struct inode *inode, struct file *file)
 {
 	struct vhci_data *data = file->private_data;
-	struct hci_dev *hdev = data->hdev;
+	struct hci_dev *hdev;
 
 	cancel_delayed_work_sync(&data->open_timeout);
 
+	hdev = data->hdev;
+
 	if (hdev) {
 		hci_unregister_dev(hdev);
 		hci_free_dev(hdev);
 	}
 
+	skb_queue_purge(&data->readq);
 	file->private_data = NULL;
 	kfree(data);
 
--- linux-4.4.0.orig/drivers/bus/arm-ccn.c
+++ linux-4.4.0/drivers/bus/arm-ccn.c
@@ -187,6 +187,7 @@
 	struct arm_ccn_component *xp;
 
 	struct arm_ccn_dt dt;
+	int mn_id;
 };
 
 
@@ -326,6 +327,7 @@
 static ssize_t arm_ccn_pmu_event_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
+	struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev));
 	struct arm_ccn_pmu_event *event = container_of(attr,
 			struct arm_ccn_pmu_event, attr);
 	ssize_t res;
@@ -352,6 +354,9 @@
 			res += snprintf(buf + res, PAGE_SIZE - res,
 					",cmp_l=?,cmp_h=?,mask=?");
 		break;
+	case CCN_TYPE_MN:
+		res += snprintf(buf + res, PAGE_SIZE - res, ",node=%d", ccn->mn_id);
+		break;
 	default:
 		res += snprintf(buf + res, PAGE_SIZE - res, ",node=?");
 		break;
@@ -381,9 +386,9 @@
 }
 
 static struct arm_ccn_pmu_event arm_ccn_pmu_events[] = {
-	CCN_EVENT_MN(eobarrier, "dir=0,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE),
-	CCN_EVENT_MN(ecbarrier, "dir=0,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE),
-	CCN_EVENT_MN(dvmop, "dir=0,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE),
+	CCN_EVENT_MN(eobarrier, "dir=1,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE),
+	CCN_EVENT_MN(ecbarrier, "dir=1,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE),
+	CCN_EVENT_MN(dvmop, "dir=1,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE),
 	CCN_EVENT_HNI(txdatflits, "dir=1,vc=3", CCN_IDX_MASK_ANY),
 	CCN_EVENT_HNI(rxdatflits, "dir=0,vc=3", CCN_IDX_MASK_ANY),
 	CCN_EVENT_HNI(txreqflits, "dir=1,vc=0", CCN_IDX_MASK_ANY),
@@ -757,6 +762,12 @@
 
 	/* Validate node/xp vs topology */
 	switch (type) {
+	case CCN_TYPE_MN:
+		if (node_xp != ccn->mn_id) {
+			dev_warn(ccn->dev, "Invalid MN ID %d!\n", node_xp);
+			return -EINVAL;
+		}
+		break;
 	case CCN_TYPE_XP:
 		if (node_xp >= ccn->num_xps) {
 			dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp);
@@ -884,6 +895,10 @@
 	struct arm_ccn_component *xp;
 	u32 val, dt_cfg;
 
+	/* Nothing to do for cycle counter */
+	if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER)
+		return;
+
 	if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP)
 		xp = &ccn->xp[CCN_CONFIG_XP(event->attr.config)];
 	else
@@ -986,7 +1001,7 @@
 
 	/* Comparison values */
 	writel(cmp_l & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_L(wp));
-	writel((cmp_l >> 32) & 0xefffffff,
+	writel((cmp_l >> 32) & 0x7fffffff,
 			source->base + CCN_XP_DT_CMP_VAL_L(wp) + 4);
 	writel(cmp_h & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_H(wp));
 	writel((cmp_h >> 32) & 0x0fffffff,
@@ -994,7 +1009,7 @@
 
 	/* Mask */
 	writel(mask_l & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_L(wp));
-	writel((mask_l >> 32) & 0xefffffff,
+	writel((mask_l >> 32) & 0x7fffffff,
 			source->base + CCN_XP_DT_CMP_MASK_L(wp) + 4);
 	writel(mask_h & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_H(wp));
 	writel((mask_h >> 32) & 0x0fffffff,
@@ -1245,6 +1260,7 @@
 
 	/* Perf driver registration */
 	ccn->dt.pmu = (struct pmu) {
+		.module = THIS_MODULE,
 		.attr_groups = arm_ccn_pmu_attr_groups,
 		.task_ctx_nr = perf_invalid_context,
 		.event_init = arm_ccn_pmu_event_init,
@@ -1368,6 +1384,8 @@
 
 	switch (type) {
 	case CCN_TYPE_MN:
+		ccn->mn_id = id;
+		return 0;
 	case CCN_TYPE_DT:
 		return 0;
 	case CCN_TYPE_XP:
--- linux-4.4.0.orig/drivers/bus/brcmstb_gisb.c
+++ linux-4.4.0/drivers/bus/brcmstb_gisb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Broadcom Corporation
+ * Copyright (C) 2014-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -33,8 +33,6 @@
 #define  ARB_ERR_CAP_CLEAR		(1 << 0)
 #define  ARB_ERR_CAP_STATUS_TIMEOUT	(1 << 12)
 #define  ARB_ERR_CAP_STATUS_TEA		(1 << 11)
-#define  ARB_ERR_CAP_STATUS_BS_SHIFT	(1 << 2)
-#define  ARB_ERR_CAP_STATUS_BS_MASK	0x3c
 #define  ARB_ERR_CAP_STATUS_WRITE	(1 << 1)
 #define  ARB_ERR_CAP_STATUS_VALID	(1 << 0)
 
@@ -43,7 +41,6 @@
 	ARB_ERR_CAP_CLR,
 	ARB_ERR_CAP_HI_ADDR,
 	ARB_ERR_CAP_ADDR,
-	ARB_ERR_CAP_DATA,
 	ARB_ERR_CAP_STATUS,
 	ARB_ERR_CAP_MASTER,
 };
@@ -53,7 +50,6 @@
 	[ARB_ERR_CAP_CLR]	= 0x0c4,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x0c8,
-	[ARB_ERR_CAP_DATA]	= 0x0cc,
 	[ARB_ERR_CAP_STATUS]	= 0x0d0,
 	[ARB_ERR_CAP_MASTER]	= -1,
 };
@@ -63,7 +59,6 @@
 	[ARB_ERR_CAP_CLR]	= 0x0c8,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x0cc,
-	[ARB_ERR_CAP_DATA]	= 0x0d0,
 	[ARB_ERR_CAP_STATUS]	= 0x0d4,
 	[ARB_ERR_CAP_MASTER]	= 0x0d8,
 };
@@ -73,7 +68,6 @@
 	[ARB_ERR_CAP_CLR]	= 0x168,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x16c,
-	[ARB_ERR_CAP_DATA]	= 0x170,
 	[ARB_ERR_CAP_STATUS]	= 0x174,
 	[ARB_ERR_CAP_MASTER]	= 0x178,
 };
@@ -83,7 +77,6 @@
 	[ARB_ERR_CAP_CLR]	= 0x7e4,
 	[ARB_ERR_CAP_HI_ADDR]	= 0x7e8,
 	[ARB_ERR_CAP_ADDR]	= 0x7ec,
-	[ARB_ERR_CAP_DATA]	= 0x7f0,
 	[ARB_ERR_CAP_STATUS]	= 0x7f4,
 	[ARB_ERR_CAP_MASTER]	= 0x7f8,
 };
@@ -105,9 +98,13 @@
 {
 	int offset = gdev->gisb_offsets[reg];
 
-	/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
-	if (offset == -1)
-		return 1;
+	if (offset < 0) {
+		/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
+		if (reg == ARB_ERR_CAP_MASTER)
+			return 1;
+		else
+			return 0;
+	}
 
 	if (gdev->big_endian)
 		return ioread32be(gdev->base + offset);
@@ -115,6 +112,16 @@
 		return ioread32(gdev->base + offset);
 }
 
+static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
+{
+	u64 value;
+
+	value = gisb_read(gdev, ARB_ERR_CAP_ADDR);
+	value |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
+
+	return value;
+}
+
 static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
 {
 	int offset = gdev->gisb_offsets[reg];
@@ -123,9 +130,9 @@
 		return;
 
 	if (gdev->big_endian)
-		iowrite32be(val, gdev->base + reg);
+		iowrite32be(val, gdev->base + offset);
 	else
-		iowrite32(val, gdev->base + reg);
+		iowrite32(val, gdev->base + offset);
 }
 
 static ssize_t gisb_arb_get_timeout(struct device *dev,
@@ -181,7 +188,7 @@
 					const char *reason)
 {
 	u32 cap_status;
-	unsigned long arb_addr;
+	u64 arb_addr;
 	u32 master;
 	const char *m_name;
 	char m_fmt[11];
@@ -193,10 +200,7 @@
 		return 1;
 
 	/* Read the address and master */
-	arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff;
-#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
-	arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
-#endif
+	arb_addr = gisb_read_address(gdev);
 	master = gisb_read(gdev, ARB_ERR_CAP_MASTER);
 
 	m_name = brcmstb_gisb_master_to_str(gdev, master);
@@ -205,7 +209,7 @@
 		m_name = m_fmt;
 	}
 
-	pr_crit("%s: %s at 0x%lx [%c %s], core: %s\n",
+	pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
 		__func__, reason, arb_addr,
 		cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
 		cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
--- linux-4.4.0.orig/drivers/bus/imx-weim.c
+++ linux-4.4.0/drivers/bus/imx-weim.c
@@ -150,7 +150,7 @@
 			return ret;
 	}
 
-	for_each_child_of_node(pdev->dev.of_node, child) {
+	for_each_available_child_of_node(pdev->dev.of_node, child) {
 		if (!child->name)
 			continue;
 
--- linux-4.4.0.orig/drivers/bus/mips_cdmm.c
+++ linux-4.4.0/drivers/bus/mips_cdmm.c
@@ -544,10 +544,8 @@
 		dev_set_name(&dev->dev, "cdmm%u-%u", cpu, id);
 		++id;
 		ret = device_register(&dev->dev);
-		if (ret) {
+		if (ret)
 			put_device(&dev->dev);
-			kfree(dev);
-		}
 	}
 }
 
--- linux-4.4.0.orig/drivers/bus/mvebu-mbus.c
+++ linux-4.4.0/drivers/bus/mvebu-mbus.c
@@ -720,7 +720,7 @@
 			if (mbus->hw_io_coherency)
 				w->mbus_attr |= ATTR_HW_COHERENCY;
 			w->base = base & DDR_BASE_CS_LOW_MASK;
-			w->size = (size | ~DDR_SIZE_MASK) + 1;
+			w->size = (u64)(size | ~DDR_SIZE_MASK) + 1;
 		}
 	}
 	mvebu_mbus_dram_info.num_cs = cs;
--- linux-4.4.0.orig/drivers/bus/sunxi-rsb.c
+++ linux-4.4.0/drivers/bus/sunxi-rsb.c
@@ -178,6 +178,7 @@
 	.match		= sunxi_rsb_device_match,
 	.probe		= sunxi_rsb_device_probe,
 	.remove		= sunxi_rsb_device_remove,
+	.uevent		= of_device_uevent_modalias,
 };
 
 static void sunxi_rsb_dev_release(struct device *dev)
@@ -344,7 +345,7 @@
 	if (ret)
 		goto unlock;
 
-	*buf = readl(rsb->regs + RSB_DATA);
+	*buf = readl(rsb->regs + RSB_DATA) & GENMASK(len * 8 - 1, 0);
 
 unlock:
 	mutex_unlock(&rsb->lock);
--- linux-4.4.0.orig/drivers/bus/vexpress-config.c
+++ linux-4.4.0/drivers/bus/vexpress-config.c
@@ -171,6 +171,7 @@
 {
 	struct device_node *bridge;
 	struct device *parent;
+	int ret;
 
 	bridge = of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
 	if (!bridge)
@@ -181,7 +182,11 @@
 	if (WARN_ON(!parent))
 		return -ENODEV;
 
-	return of_platform_populate(node, NULL, NULL, parent);
+	ret = of_platform_populate(node, NULL, NULL, parent);
+
+	put_device(parent);
+
+	return ret;
 }
 
 static int __init vexpress_config_init(void)
--- linux-4.4.0.orig/drivers/cdrom/cdrom.c
+++ linux-4.4.0/drivers/cdrom/cdrom.c
@@ -265,6 +265,7 @@
 /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */
 /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */
 
+#include <linux/atomic.h>
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/major.h>
@@ -289,7 +290,7 @@
 /* default compatibility mode */
 static bool autoclose=1;
 static bool autoeject;
-static bool lockdoor = 1;
+static bool lockdoor = 0;
 /* will we ever get to use this... sigh. */
 static bool check_media_type;
 /* automatically restart mrw format */
@@ -997,6 +998,12 @@
 	tracks->xa = 0;
 	tracks->error = 0;
 	cd_dbg(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n");
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO)) {
+		tracks->error = CDS_NO_INFO;
+		return;
+	}
+
 	/* Grab the TOC header so we can see how many tracks there are */
 	ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header);
 	if (ret) {
@@ -1154,9 +1161,6 @@
 
 	cd_dbg(CD_OPEN, "entering cdrom_open\n");
 
-	/* open is event synchronization point, check events first */
-	check_disk_change(bdev);
-
 	/* if this was a O_NONBLOCK open and we should honor the flags,
 	 * do a quick open without drive/disc integrity checks. */
 	cdi->use_count++;
@@ -1166,7 +1170,8 @@
 		ret = open_for_data(cdi);
 		if (ret)
 			goto err;
-		cdrom_mmc3_profile(cdi);
+		if (CDROM_CAN(CDC_GENERIC_PACKET))
+			cdrom_mmc3_profile(cdi);
 		if (mode & FMODE_WRITE) {
 			ret = -EROFS;
 			if (cdrom_open_write(cdi))
@@ -2358,7 +2363,7 @@
 	if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
 		return media_changed(cdi, 1);
 
-	if ((unsigned int)arg >= cdi->capacity)
+	if (arg >= cdi->capacity)
 		return -EINVAL;
 
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -2428,7 +2433,7 @@
 		return -ENOSYS;
 
 	if (arg != CDSL_CURRENT && arg != CDSL_NONE) {
-		if ((int)arg >= cdi->capacity)
+		if (arg >= cdi->capacity)
 			return -EINVAL;
 	}
 
@@ -2529,7 +2534,7 @@
 	if (!CDROM_CAN(CDC_SELECT_DISC) ||
 	    (arg == CDSL_CURRENT || arg == CDSL_NONE))
 		return cdi->ops->drive_status(cdi, CDSL_CURRENT);
-	if (((int)arg >= cdi->capacity))
+	if (arg >= cdi->capacity)
 		return -EINVAL;
 	return cdrom_slot_status(cdi, arg);
 }
@@ -2865,6 +2870,9 @@
 	   it doesn't give enough information or fails. then we return
 	   the toc contents. */
 use_toc:
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+
 	toc.cdte_format = CDROM_MSF;
 	toc.cdte_track = CDROM_LEADOUT;
 	if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)))
@@ -3680,9 +3688,9 @@
 
 static void cdrom_sysctl_register(void)
 {
-	static int initialized;
+	static atomic_t initialized = ATOMIC_INIT(0);
 
-	if (initialized == 1)
+	if (!atomic_add_unless(&initialized, 1, 1))
 		return;
 
 	cdrom_sysctl_header = register_sysctl_table(cdrom_root_table);
@@ -3693,8 +3701,6 @@
 	cdrom_sysctl_settings.debug = debug;
 	cdrom_sysctl_settings.lock = lockdoor;
 	cdrom_sysctl_settings.check = check_media_type;
-
-	initialized = 1;
 }
 
 static void cdrom_sysctl_unregister(void)
--- linux-4.4.0.orig/drivers/cdrom/gdrom.c
+++ linux-4.4.0/drivers/cdrom/gdrom.c
@@ -497,6 +497,9 @@
 static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode)
 {
 	int ret;
+
+	check_disk_change(bdev);
+
 	mutex_lock(&gdrom_mutex);
 	ret = cdrom_open(gd.cd_info, bdev, mode);
 	mutex_unlock(&gdrom_mutex);
@@ -879,6 +882,7 @@
 	platform_device_unregister(pd);
 	platform_driver_unregister(&gdrom_driver);
 	kfree(gd.toc);
+	kfree(gd.cd_info);
 }
 
 module_init(init_gdrom);
--- linux-4.4.0.orig/drivers/char/Kconfig
+++ linux-4.4.0/drivers/char/Kconfig
@@ -389,7 +389,7 @@
 
 config R3964
 	tristate "Siemens R3964 line discipline"
-	depends on TTY
+	depends on TTY && BROKEN
 	---help---
 	  This driver allows synchronous communication with devices using the
 	  Siemens R3964 packet protocol. Unless you are dealing with special
@@ -583,10 +583,12 @@
 	  controlling the behavior of this hardware.
 
 config DEVPORT
-	bool
-	depends on !M68K
+	bool "/dev/port character device"
 	depends on ISA || PCI
 	default y
+	help
+	  Say Y here if you want to support the /dev/port device. The /dev/port
+	  device is similar to /dev/mem, but for I/O ports.
 
 source "drivers/s390/char/Kconfig"
 
--- linux-4.4.0.orig/drivers/char/agp/intel-gtt.c
+++ linux-4.4.0/drivers/char/agp/intel-gtt.c
@@ -303,8 +303,10 @@
 	if (intel_private.needs_dmar) {
 		dma_addr = pci_map_page(intel_private.pcidev, page, 0,
 				    PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-		if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
+		if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) {
+			__free_page(page);
 			return -EINVAL;
+		}
 
 		intel_private.scratch_page_dma = dma_addr;
 	} else
@@ -859,6 +861,8 @@
 		}
 	}
 	wmb();
+	if (intel_private.driver->chipset_flush)
+		intel_private.driver->chipset_flush();
 }
 EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
 
--- linux-4.4.0.orig/drivers/char/applicom.c
+++ linux-4.4.0/drivers/char/applicom.c
@@ -32,6 +32,7 @@
 #include <linux/wait.h>
 #include <linux/init.h>
 #include <linux/fs.h>
+#include <linux/nospec.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -94,9 +95,9 @@
 static unsigned int irq = 0;	/* interrupt number IRQ       */
 static unsigned long mem = 0;	/* physical segment of board  */
 
-module_param(irq, uint, 0);
+module_param_hw(irq, uint, irq, 0);
 MODULE_PARM_DESC(irq, "IRQ of the Applicom board");
-module_param(mem, ulong, 0);
+module_param_hw(mem, ulong, iomem, 0);
 MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board");
 
 static unsigned int numboards;	/* number of installed boards */
@@ -386,7 +387,11 @@
 	TicCard = st_loc.tic_des_from_pc;	/* tic number to send            */
 	IndexCard = NumCard - 1;
 
-	if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO)
+	if (IndexCard >= MAX_BOARD)
+		return -EINVAL;
+	IndexCard = array_index_nospec(IndexCard, MAX_BOARD);
+
+	if (!apbs[IndexCard].RamIO)
 		return -EINVAL;
 
 #ifdef DEBUG
@@ -697,6 +702,7 @@
 	unsigned char IndexCard;
 	void __iomem *pmem;
 	int ret = 0;
+	static int warncount = 10;
 	volatile unsigned char byte_reset_it;
 	struct st_ram_io *adgl;
 	void __user *argp = (void __user *)arg;
@@ -711,16 +717,12 @@
 	mutex_lock(&ac_mutex);	
 	IndexCard = adgl->num_card-1;
 	 
-	if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
-		static int warncount = 10;
-		if (warncount) {
-			printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
-			warncount--;
-		}
-		kfree(adgl);
-		mutex_unlock(&ac_mutex);
-		return -EINVAL;
-	}
+	if (cmd != 6 && IndexCard >= MAX_BOARD)
+		goto err;
+	IndexCard = array_index_nospec(IndexCard, MAX_BOARD);
+
+	if (cmd != 6 && !apbs[IndexCard].RamIO)
+		goto err;
 
 	switch (cmd) {
 		
@@ -838,5 +840,16 @@
 	kfree(adgl);
 	mutex_unlock(&ac_mutex);
 	return 0;
+
+err:
+	if (warncount) {
+		pr_warn("APPLICOM driver IOCTL, bad board number %d\n",
+			(int)IndexCard + 1);
+		warncount--;
+	}
+	kfree(adgl);
+	mutex_unlock(&ac_mutex);
+	return -EINVAL;
+
 }
 
--- linux-4.4.0.orig/drivers/char/hpet.c
+++ linux-4.4.0/drivers/char/hpet.c
@@ -376,7 +376,7 @@
 	pr_info("HPET mmap %s\n", hpet_mmap_enabled ? "enabled" : "disabled");
 	return 1;
 }
-__setup("hpet_mmap", hpet_mmap_enable);
+__setup("hpet_mmap=", hpet_mmap_enable);
 
 static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
 {
@@ -569,8 +569,7 @@
 	unsigned long long m;
 
 	m = hpets->hp_tick_freq + (dis >> 1);
-	do_div(m, dis);
-	return (unsigned long)m;
+	return div64_ul(m, dis);
 }
 
 static int
--- linux-4.4.0.orig/drivers/char/hw_random/core.c
+++ linux-4.4.0/drivers/char/hw_random/core.c
@@ -41,6 +41,7 @@
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/random.h>
 #include <linux/err.h>
 #include <asm/uaccess.h>
@@ -51,6 +52,8 @@
 #define RNG_MISCDEV_MINOR	183 /* official */
 
 
+#define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES)
+
 static struct hwrng *current_rng;
 static struct task_struct *hwrng_fill;
 static LIST_HEAD(rng_list);
@@ -79,19 +82,19 @@
 
 static size_t rng_buffer_size(void)
 {
-	return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES;
+	return RNG_BUFFER_SIZE;
 }
 
 static void add_early_randomness(struct hwrng *rng)
 {
-	unsigned char bytes[16];
 	int bytes_read;
+	size_t size = min_t(size_t, 16, rng_buffer_size());
 
 	mutex_lock(&reading_mutex);
-	bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1);
+	bytes_read = rng_get_data(rng, rng_buffer, size, 0);
 	mutex_unlock(&reading_mutex);
 	if (bytes_read > 0)
-		add_device_randomness(bytes, bytes_read);
+		add_device_randomness(rng_buffer, bytes_read);
 }
 
 static inline void cleanup_rng(struct kref *kref)
@@ -222,6 +225,7 @@
 static ssize_t rng_dev_read(struct file *filp, char __user *buf,
 			    size_t size, loff_t *offp)
 {
+	u8 buffer[RNG_BUFFER_SIZE];
 	ssize_t ret = 0;
 	int err = 0;
 	int bytes_read, len;
@@ -238,7 +242,10 @@
 			goto out;
 		}
 
-		mutex_lock(&reading_mutex);
+		if (mutex_lock_interruptible(&reading_mutex)) {
+			err = -ERESTARTSYS;
+			goto out_put;
+		}
 		if (!data_avail) {
 			bytes_read = rng_get_data(rng, rng_buffer,
 				rng_buffer_size(),
@@ -246,34 +253,37 @@
 			if (bytes_read < 0) {
 				err = bytes_read;
 				goto out_unlock_reading;
+			} else if (bytes_read == 0 &&
+				   (filp->f_flags & O_NONBLOCK)) {
+				err = -EAGAIN;
+				goto out_unlock_reading;
 			}
+
 			data_avail = bytes_read;
 		}
 
-		if (!data_avail) {
-			if (filp->f_flags & O_NONBLOCK) {
-				err = -EAGAIN;
-				goto out_unlock_reading;
-			}
-		} else {
-			len = data_avail;
+		len = data_avail;
+		if (len) {
 			if (len > size)
 				len = size;
 
 			data_avail -= len;
 
-			if (copy_to_user(buf + ret, rng_buffer + data_avail,
-								len)) {
+			memcpy(buffer, rng_buffer + data_avail, len);
+		}
+		mutex_unlock(&reading_mutex);
+		put_rng(rng);
+
+		if (len) {
+			if (copy_to_user(buf + ret, buffer, len)) {
 				err = -EFAULT;
-				goto out_unlock_reading;
+				goto out;
 			}
 
 			size -= len;
 			ret += len;
 		}
 
-		mutex_unlock(&reading_mutex);
-		put_rng(rng);
 
 		if (need_resched())
 			schedule_timeout_interruptible(1);
@@ -284,10 +294,12 @@
 		}
 	}
 out:
+	memzero_explicit(buffer, sizeof(buffer));
 	return ret ? : err;
 
 out_unlock_reading:
 	mutex_unlock(&reading_mutex);
+out_put:
 	put_rng(rng);
 	goto out;
 }
--- linux-4.4.0.orig/drivers/char/hw_random/exynos-rng.c
+++ linux-4.4.0/drivers/char/hw_random/exynos-rng.c
@@ -89,6 +89,7 @@
 						struct exynos_rng, rng);
 	u32 *data = buf;
 	int retry = 100;
+	int ret = 4;
 
 	pm_runtime_get_sync(exynos_rng->dev);
 
@@ -97,23 +98,27 @@
 	while (!(exynos_rng_readl(exynos_rng,
 			EXYNOS_PRNG_STATUS_OFFSET) & PRNG_DONE) && --retry)
 		cpu_relax();
-	if (!retry)
-		return -ETIMEDOUT;
+	if (!retry) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
 
 	exynos_rng_writel(exynos_rng, PRNG_DONE, EXYNOS_PRNG_STATUS_OFFSET);
 
 	*data = exynos_rng_readl(exynos_rng, EXYNOS_PRNG_OUT1_OFFSET);
 
+out:
 	pm_runtime_mark_last_busy(exynos_rng->dev);
 	pm_runtime_put_sync_autosuspend(exynos_rng->dev);
 
-	return 4;
+	return ret;
 }
 
 static int exynos_rng_probe(struct platform_device *pdev)
 {
 	struct exynos_rng *exynos_rng;
 	struct resource *res;
+	int ret;
 
 	exynos_rng = devm_kzalloc(&pdev->dev, sizeof(struct exynos_rng),
 					GFP_KERNEL);
@@ -141,11 +146,24 @@
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
-	return devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
+	ret = devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
+	if (ret) {
+		pm_runtime_dont_use_autosuspend(&pdev->dev);
+		pm_runtime_disable(&pdev->dev);
+	}
+
+	return ret;
+}
+
+static int exynos_rng_remove(struct platform_device *pdev)
+{
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
 }
 
-#ifdef CONFIG_PM
-static int exynos_rng_runtime_suspend(struct device *dev)
+static int __maybe_unused exynos_rng_runtime_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -155,7 +173,7 @@
 	return 0;
 }
 
-static int exynos_rng_runtime_resume(struct device *dev)
+static int __maybe_unused exynos_rng_runtime_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -163,12 +181,12 @@
 	return clk_prepare_enable(exynos_rng->clk);
 }
 
-static int exynos_rng_suspend(struct device *dev)
+static int __maybe_unused exynos_rng_suspend(struct device *dev)
 {
 	return pm_runtime_force_suspend(dev);
 }
 
-static int exynos_rng_resume(struct device *dev)
+static int __maybe_unused exynos_rng_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -180,7 +198,6 @@
 
 	return exynos_rng_configure(exynos_rng);
 }
-#endif
 
 static const struct dev_pm_ops exynos_rng_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(exynos_rng_suspend, exynos_rng_resume)
@@ -203,6 +220,7 @@
 		.of_match_table = exynos_rng_dt_match,
 	},
 	.probe		= exynos_rng_probe,
+	.remove		= exynos_rng_remove,
 };
 
 module_platform_driver(exynos_rng_driver);
--- linux-4.4.0.orig/drivers/char/hw_random/omap-rng.c
+++ linux-4.4.0/drivers/char/hw_random/omap-rng.c
@@ -384,7 +384,12 @@
 	}
 
 	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to runtime_get device: %d\n", ret);
+		pm_runtime_put_noidle(&pdev->dev);
+		goto err_ioremap;
+	}
 
 	ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) :
 				get_omap_rng_device_details(priv);
@@ -435,8 +440,15 @@
 static int __maybe_unused omap_rng_resume(struct device *dev)
 {
 	struct omap_rng_dev *priv = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "Failed to runtime_get device: %d\n", ret);
+		pm_runtime_put_noidle(dev);
+		return ret;
+	}
 
-	pm_runtime_get_sync(dev);
 	priv->pdata->init(priv);
 
 	return 0;
--- linux-4.4.0.orig/drivers/char/hw_random/omap3-rom-rng.c
+++ linux-4.4.0/drivers/char/hw_random/omap3-rom-rng.c
@@ -119,7 +119,8 @@
 static int omap3_rom_rng_remove(struct platform_device *pdev)
 {
 	hwrng_unregister(&omap3_rom_rng_ops);
-	clk_disable_unprepare(rng_clk);
+	if (!rng_idle)
+		clk_disable_unprepare(rng_clk);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/char/hw_random/stm32-rng.c
+++ linux-4.4.0/drivers/char/hw_random/stm32-rng.c
@@ -21,6 +21,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 
 #define RNG_CR 0x00
@@ -46,6 +47,7 @@
 	struct hwrng rng;
 	void __iomem *base;
 	struct clk *clk;
+	struct reset_control *rst;
 };
 
 static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
@@ -140,6 +142,13 @@
 	if (IS_ERR(priv->clk))
 		return PTR_ERR(priv->clk);
 
+	priv->rst = devm_reset_control_get(&ofdev->dev, NULL);
+	if (!IS_ERR(priv->rst)) {
+		reset_control_assert(priv->rst);
+		udelay(2);
+		reset_control_deassert(priv->rst);
+	}
+
 	dev_set_drvdata(dev, priv);
 
 	priv->rng.name = dev_driver_string(dev),
@@ -157,6 +166,13 @@
 	return devm_hwrng_register(dev, &priv->rng);
 }
 
+static int stm32_rng_remove(struct platform_device *ofdev)
+{
+	pm_runtime_disable(&ofdev->dev);
+
+	return 0;
+}
+
 #ifdef CONFIG_PM
 static int stm32_rng_runtime_suspend(struct device *dev)
 {
@@ -193,6 +209,7 @@
 		.of_match_table = stm32_rng_match,
 	},
 	.probe = stm32_rng_probe,
+	.remove = stm32_rng_remove,
 };
 
 module_platform_driver(stm32_rng_driver);
--- linux-4.4.0.orig/drivers/char/hw_random/via-rng.c
+++ linux-4.4.0/drivers/char/hw_random/via-rng.c
@@ -140,7 +140,7 @@
 	 * RNG configuration like it used to be the case in this
 	 * register */
 	if ((c->x86 == 6) && (c->x86_model >= 0x0f)) {
-		if (!cpu_has_xstore_enabled) {
+		if (!boot_cpu_has(X86_FEATURE_XSTORE_EN)) {
 			pr_err(PFX "can't enable hardware RNG "
 				"if XSTORE is not enabled\n");
 			return -ENODEV;
@@ -166,7 +166,7 @@
 	/* Enable secondary noise source on CPUs where it is present. */
 
 	/* Nehemiah stepping 8 and higher */
-	if ((c->x86_model == 9) && (c->x86_mask > 7))
+	if ((c->x86_model == 9) && (c->x86_stepping > 7))
 		lo |= VIA_NOISESRC2;
 
 	/* Esther */
@@ -200,8 +200,9 @@
 {
 	int err;
 
-	if (!cpu_has_xstore)
+	if (!boot_cpu_has(X86_FEATURE_XSTORE))
 		return -ENODEV;
+
 	pr_info("VIA RNG detected\n");
 	err = hwrng_register(&via_rng);
 	if (err) {
--- linux-4.4.0.orig/drivers/char/hw_random/virtio-rng.c
+++ linux-4.4.0/drivers/char/hw_random/virtio-rng.c
@@ -73,7 +73,7 @@
 
 	if (!vi->busy) {
 		vi->busy = true;
-		init_completion(&vi->have_data);
+		reinit_completion(&vi->have_data);
 		register_buffer(vi, buf, size);
 	}
 
--- linux-4.4.0.orig/drivers/char/ipmi/ipmi_bt_sm.c
+++ linux-4.4.0/drivers/char/ipmi/ipmi_bt_sm.c
@@ -522,11 +522,12 @@
 		if (status & BT_H_BUSY)		/* clear a leftover H_BUSY */
 			BT_CONTROL(BT_H_BUSY);
 
+		bt->timeout = bt->BT_CAP_req2rsp;
+
 		/* Read BT capabilities if it hasn't been done yet */
 		if (!bt->BT_CAP_outreqs)
 			BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN,
 					SI_SM_CALL_WITHOUT_DELAY);
-		bt->timeout = bt->BT_CAP_req2rsp;
 		BT_SI_SM_RETURN(SI_SM_IDLE);
 
 	case BT_STATE_XACTION_START:
--- linux-4.4.0.orig/drivers/char/ipmi/ipmi_msghandler.c
+++ linux-4.4.0/drivers/char/ipmi/ipmi_msghandler.c
@@ -46,6 +46,7 @@
 #include <linux/proc_fs.h>
 #include <linux/rcupdate.h>
 #include <linux/interrupt.h>
+#include <linux/nospec.h>
 
 #define PFX "IPMI message handler: "
 
@@ -1132,6 +1133,7 @@
 {
 	if (channel >= IPMI_MAX_CHANNELS)
 		return -EINVAL;
+	channel = array_index_nospec(channel, IPMI_MAX_CHANNELS);
 	user->intf->channels[channel].address = address;
 	return 0;
 }
@@ -1143,6 +1145,7 @@
 {
 	if (channel >= IPMI_MAX_CHANNELS)
 		return -EINVAL;
+	channel = array_index_nospec(channel, IPMI_MAX_CHANNELS);
 	*address = user->intf->channels[channel].address;
 	return 0;
 }
@@ -1154,6 +1157,7 @@
 {
 	if (channel >= IPMI_MAX_CHANNELS)
 		return -EINVAL;
+	channel = array_index_nospec(channel, IPMI_MAX_CHANNELS);
 	user->intf->channels[channel].lun = LUN & 0x3;
 	return 0;
 }
@@ -1165,6 +1169,7 @@
 {
 	if (channel >= IPMI_MAX_CHANNELS)
 		return -EINVAL;
+	channel = array_index_nospec(channel, IPMI_MAX_CHANNELS);
 	*address = user->intf->channels[channel].lun;
 	return 0;
 }
@@ -1926,6 +1931,7 @@
 {
 	if (addr->channel >= IPMI_MAX_CHANNELS)
 		return -EINVAL;
+	addr->channel = array_index_nospec(addr->channel, IPMI_MAX_CHANNELS);
 	*lun = intf->channels[addr->channel].lun;
 	*saddr = intf->channels[addr->channel].address;
 	return 0;
@@ -2645,7 +2651,9 @@
 	if (rv)
 		/* Send failed, no GUID available. */
 		intf->bmc->guid_set = 0;
-	wait_event(intf->waitq, intf->bmc->guid_set != 2);
+	else
+		wait_event(intf->waitq, intf->bmc->guid_set != 2);
+
 	intf->null_user_handler = NULL;
 }
 
@@ -3819,6 +3827,7 @@
 	while (!list_empty(&intf->waiting_rcv_msgs)) {
 		smi_msg = list_entry(intf->waiting_rcv_msgs.next,
 				     struct ipmi_smi_msg, link);
+		list_del(&smi_msg->link);
 		if (!run_to_completion)
 			spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock,
 					       flags);
@@ -3828,11 +3837,14 @@
 		if (rv > 0) {
 			/*
 			 * To preserve message order, quit if we
-			 * can't handle a message.
+			 * can't handle a message.  Add the message
+			 * back at the head, this is safe because this
+			 * tasklet is the only thing that pulls the
+			 * messages.
 			 */
+			list_add(&smi_msg->link, &intf->waiting_rcv_msgs);
 			break;
 		} else {
-			list_del(&smi_msg->link);
 			if (rv == 0)
 				/* Message handled */
 				ipmi_free_smi_msg(smi_msg);
@@ -3873,6 +3885,9 @@
 	 * because the lower layer is allowed to hold locks while calling
 	 * message delivery.
 	 */
+
+	rcu_read_lock();
+
 	if (!run_to_completion)
 		spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
 	if (intf->curr_msg == NULL && !intf->in_shutdown) {
@@ -3895,6 +3910,8 @@
 	if (newmsg)
 		intf->handlers->sender(intf->send_info, newmsg);
 
+	rcu_read_unlock();
+
 	handle_new_recv_msgs(intf);
 }
 
@@ -4020,7 +4037,8 @@
 }
 
 static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
-			      struct list_head *timeouts, long timeout_period,
+			      struct list_head *timeouts,
+			      unsigned long timeout_period,
 			      int slot, unsigned long *flags,
 			      unsigned int *waiting_msgs)
 {
@@ -4033,8 +4051,8 @@
 	if (!ent->inuse)
 		return;
 
-	ent->timeout -= timeout_period;
-	if (ent->timeout > 0) {
+	if (timeout_period < ent->timeout) {
+		ent->timeout -= timeout_period;
 		(*waiting_msgs)++;
 		return;
 	}
@@ -4100,7 +4118,8 @@
 	}
 }
 
-static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, long timeout_period)
+static unsigned int ipmi_timeout_handler(ipmi_smi_t intf,
+					 unsigned long timeout_period)
 {
 	struct list_head     timeouts;
 	struct ipmi_recv_msg *msg, *msg2;
--- linux-4.4.0.orig/drivers/char/ipmi/ipmi_powernv.c
+++ linux-4.4.0/drivers/char/ipmi/ipmi_powernv.c
@@ -251,8 +251,9 @@
 		ipmi->irq = opal_event_request(prop);
 	}
 
-	if (request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH,
-				"opal-ipmi", ipmi)) {
+	rc = request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH,
+			 "opal-ipmi", ipmi);
+	if (rc) {
 		dev_warn(dev, "Unable to request irq\n");
 		goto err_dispose;
 	}
--- linux-4.4.0.orig/drivers/char/ipmi/ipmi_si_intf.c
+++ linux-4.4.0/drivers/char/ipmi/ipmi_si_intf.c
@@ -239,6 +239,9 @@
 	/* The timer for this si. */
 	struct timer_list   si_timer;
 
+	/* This flag is set, if the timer can be set */
+	bool		    timer_can_start;
+
 	/* This flag is set, if the timer is running (timer_pending() isn't enough) */
 	bool		    timer_running;
 
@@ -278,6 +281,9 @@
 	 */
 	bool irq_enable_broken;
 
+	/* Is the driver in maintenance mode? */
+	bool in_maintenance_mode;
+
 	/*
 	 * Did we get an attention that we did not handle?
 	 */
@@ -414,6 +420,8 @@
 
 static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
 {
+	if (!smi_info->timer_can_start)
+		return;
 	smi_info->last_timeout_jiffies = jiffies;
 	mod_timer(&smi_info->si_timer, new_val);
 	smi_info->timer_running = true;
@@ -433,21 +441,18 @@
 	smi_info->handlers->start_transaction(smi_info->si_sm, msg, size);
 }
 
-static void start_check_enables(struct smi_info *smi_info, bool start_timer)
+static void start_check_enables(struct smi_info *smi_info)
 {
 	unsigned char msg[2];
 
 	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
 	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
 
-	if (start_timer)
-		start_new_msg(smi_info, msg, 2);
-	else
-		smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+	start_new_msg(smi_info, msg, 2);
 	smi_info->si_state = SI_CHECKING_ENABLES;
 }
 
-static void start_clear_flags(struct smi_info *smi_info, bool start_timer)
+static void start_clear_flags(struct smi_info *smi_info)
 {
 	unsigned char msg[3];
 
@@ -456,10 +461,7 @@
 	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
 	msg[2] = WDT_PRE_TIMEOUT_INT;
 
-	if (start_timer)
-		start_new_msg(smi_info, msg, 3);
-	else
-		smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
+	start_new_msg(smi_info, msg, 3);
 	smi_info->si_state = SI_CLEARING_FLAGS;
 }
 
@@ -494,11 +496,11 @@
  * Note that we cannot just use disable_irq(), since the interrupt may
  * be shared.
  */
-static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer)
+static inline bool disable_si_irq(struct smi_info *smi_info)
 {
 	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
 		smi_info->interrupt_disabled = true;
-		start_check_enables(smi_info, start_timer);
+		start_check_enables(smi_info);
 		return true;
 	}
 	return false;
@@ -508,7 +510,7 @@
 {
 	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
 		smi_info->interrupt_disabled = false;
-		start_check_enables(smi_info, true);
+		start_check_enables(smi_info);
 		return true;
 	}
 	return false;
@@ -526,7 +528,7 @@
 
 	msg = ipmi_alloc_smi_msg();
 	if (!msg) {
-		if (!disable_si_irq(smi_info, true))
+		if (!disable_si_irq(smi_info))
 			smi_info->si_state = SI_NORMAL;
 	} else if (enable_si_irq(smi_info)) {
 		ipmi_free_smi_msg(msg);
@@ -542,7 +544,7 @@
 		/* Watchdog pre-timeout */
 		smi_inc_stat(smi_info, watchdog_pretimeouts);
 
-		start_clear_flags(smi_info, true);
+		start_clear_flags(smi_info);
 		smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
 		if (smi_info->intf)
 			ipmi_smi_watchdog_pretimeout(smi_info->intf);
@@ -925,7 +927,7 @@
 		 * disable and messages disabled.
 		 */
 		if (smi_info->supports_event_msg_buff || smi_info->irq) {
-			start_check_enables(smi_info, true);
+			start_check_enables(smi_info);
 		} else {
 			smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
 			if (!smi_info->curr_msg)
@@ -1092,11 +1094,20 @@
 		spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 		busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
 						  &busy_until);
-		if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
+		if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
 			; /* do nothing */
-		else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
-			schedule();
-		else if (smi_result == SI_SM_IDLE) {
+		} else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait) {
+			/*
+			 * In maintenance mode we run as fast as
+			 * possible to allow firmware updates to
+			 * complete as fast as possible, but normally
+			 * don't bang on the scheduler.
+			 */
+			if (smi_info->in_maintenance_mode)
+				schedule();
+			else
+				usleep_range(100, 200);
+		} else if (smi_result == SI_SM_IDLE) {
 			if (atomic_read(&smi_info->need_watch)) {
 				schedule_timeout_interruptible(100);
 			} else {
@@ -1104,8 +1115,9 @@
 				__set_current_state(TASK_INTERRUPTIBLE);
 				schedule();
 			}
-		} else
+		} else {
 			schedule_timeout_interruptible(1);
+		}
 	}
 	return 0;
 }
@@ -1232,6 +1244,7 @@
 
 	/* Set up the timer that drives the interface. */
 	setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
+	new_smi->timer_can_start = true;
 	smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
 
 	/* Try to claim any interrupts. */
@@ -1283,6 +1296,7 @@
 
 	if (!enable)
 		atomic_set(&smi_info->req_events, 0);
+	smi_info->in_maintenance_mode = enable;
 }
 
 static const struct ipmi_smi_handlers handlers = {
@@ -1378,39 +1392,39 @@
 		 " interface separated by commas.  The types are 'kcs',"
 		 " 'smic', and 'bt'.  For example si_type=kcs,bt will set"
 		 " the first interface to kcs and the second to bt");
-module_param_array(addrs, ulong, &num_addrs, 0);
+module_param_hw_array(addrs, ulong, iomem, &num_addrs, 0);
 MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the"
 		 " addresses separated by commas.  Only use if an interface"
 		 " is in memory.  Otherwise, set it to zero or leave"
 		 " it blank.");
-module_param_array(ports, uint, &num_ports, 0);
+module_param_hw_array(ports, uint, ioport, &num_ports, 0);
 MODULE_PARM_DESC(ports, "Sets the port address of each interface, the"
 		 " addresses separated by commas.  Only use if an interface"
 		 " is a port.  Otherwise, set it to zero or leave"
 		 " it blank.");
-module_param_array(irqs, int, &num_irqs, 0);
+module_param_hw_array(irqs, int, irq, &num_irqs, 0);
 MODULE_PARM_DESC(irqs, "Sets the interrupt of each interface, the"
 		 " addresses separated by commas.  Only use if an interface"
 		 " has an interrupt.  Otherwise, set it to zero or leave"
 		 " it blank.");
-module_param_array(regspacings, int, &num_regspacings, 0);
+module_param_hw_array(regspacings, int, other, &num_regspacings, 0);
 MODULE_PARM_DESC(regspacings, "The number of bytes between the start address"
 		 " and each successive register used by the interface.  For"
 		 " instance, if the start address is 0xca2 and the spacing"
 		 " is 2, then the second address is at 0xca4.  Defaults"
 		 " to 1.");
-module_param_array(regsizes, int, &num_regsizes, 0);
+module_param_hw_array(regsizes, int, other, &num_regsizes, 0);
 MODULE_PARM_DESC(regsizes, "The size of the specific IPMI register in bytes."
 		 " This should generally be 1, 2, 4, or 8 for an 8-bit,"
 		 " 16-bit, 32-bit, or 64-bit register.  Use this if you"
 		 " the 8-bit IPMI register has to be read from a larger"
 		 " register.");
-module_param_array(regshifts, int, &num_regshifts, 0);
+module_param_hw_array(regshifts, int, other, &num_regshifts, 0);
 MODULE_PARM_DESC(regshifts, "The amount to shift the data read from the."
 		 " IPMI register, in bits.  For instance, if the data"
 		 " is read from a 32-bit word and the IPMI data is in"
 		 " bit 8-15, then the shift would be 8");
-module_param_array(slave_addrs, int, &num_slave_addrs, 0);
+module_param_hw_array(slave_addrs, int, other, &num_slave_addrs, 0);
 MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for"
 		 " the controller.  Normally this is 0x20, but can be"
 		 " overridden by this parm.  This is an array indexed"
@@ -3434,10 +3448,12 @@
 	check_set_rcv_irq(smi_info);
 }
 
-static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
+static inline void stop_timer_and_thread(struct smi_info *smi_info)
 {
 	if (smi_info->thread != NULL)
 		kthread_stop(smi_info->thread);
+
+	smi_info->timer_can_start = false;
 	if (smi_info->timer_running)
 		del_timer_sync(&smi_info->si_timer);
 }
@@ -3635,7 +3651,7 @@
 	 * Start clearing the flags before we enable interrupts or the
 	 * timer to avoid racing with the timer.
 	 */
-	start_clear_flags(new_smi, false);
+	start_clear_flags(new_smi);
 
 	/*
 	 * IRQ is defined to be set when non-zero.  req_events will
@@ -3713,7 +3729,7 @@
 	return 0;
 
  out_err_stop_timer:
-	wait_for_timer_and_thread(new_smi);
+	stop_timer_and_thread(new_smi);
 
  out_err:
 	new_smi->interrupt_disabled = true;
@@ -3919,7 +3935,7 @@
 	 */
 	if (to_clean->irq_cleanup)
 		to_clean->irq_cleanup(to_clean);
-	wait_for_timer_and_thread(to_clean);
+	stop_timer_and_thread(to_clean);
 
 	/*
 	 * Timeouts are stopped, now make sure the interrupts are off
@@ -3930,7 +3946,7 @@
 		poll(to_clean);
 		schedule_timeout_uninterruptible(1);
 	}
-	disable_si_irq(to_clean, false);
+	disable_si_irq(to_clean);
 	while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
 		poll(to_clean);
 		schedule_timeout_uninterruptible(1);
--- linux-4.4.0.orig/drivers/char/ipmi/ipmi_ssif.c
+++ linux-4.4.0/drivers/char/ipmi/ipmi_ssif.c
@@ -409,6 +409,7 @@
 	msg = ipmi_alloc_smi_msg();
 	if (!msg) {
 		ssif_info->ssif_state = SSIF_NORMAL;
+		ipmi_ssif_unlock_cond(ssif_info, flags);
 		return;
 	}
 
@@ -431,6 +432,7 @@
 	msg = ipmi_alloc_smi_msg();
 	if (!msg) {
 		ssif_info->ssif_state = SSIF_NORMAL;
+		ipmi_ssif_unlock_cond(ssif_info, flags);
 		return;
 	}
 
@@ -611,8 +613,9 @@
 			flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
 			ssif_info->waiting_alert = true;
 			ssif_info->rtc_us_timer = SSIF_MSG_USEC;
-			mod_timer(&ssif_info->retry_timer,
-				  jiffies + SSIF_MSG_JIFFIES);
+			if (!ssif_info->stopping)
+				mod_timer(&ssif_info->retry_timer,
+					  jiffies + SSIF_MSG_JIFFIES);
 			ipmi_ssif_unlock_cond(ssif_info, flags);
 			return;
 		}
@@ -634,8 +637,9 @@
 
 		/* Remove the multi-part read marker. */
 		len -= 2;
+		data += 2;
 		for (i = 0; i < len; i++)
-			ssif_info->data[i] = data[i+2];
+			ssif_info->data[i] = data[i];
 		ssif_info->multi_len = len;
 		ssif_info->multi_pos = 1;
 
@@ -663,8 +667,19 @@
 		}
 
 		blocknum = data[0];
+		len--;
+		data++;
+
+		if (blocknum != 0xff && len != 31) {
+		    /* All blocks but the last must have 31 data bytes. */
+			result = -EIO;
+			if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
+				pr_info("Received middle message <31\n");
 
-		if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) {
+			goto continue_op;
+		}
+
+		if (ssif_info->multi_len + len > IPMI_MAX_MSG_LENGTH) {
 			/* Received message too big, abort the operation. */
 			result = -E2BIG;
 			if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
@@ -673,10 +688,8 @@
 			goto continue_op;
 		}
 
-		/* Remove the blocknum from the data. */
-		len--;
 		for (i = 0; i < len; i++)
-			ssif_info->data[i + ssif_info->multi_len] = data[i + 1];
+			ssif_info->data[i + ssif_info->multi_len] = data[i];
 		ssif_info->multi_len += len;
 		if (blocknum == 0xff) {
 			/* End of read */
@@ -688,6 +701,10 @@
 			 * numbers start at zero for the second block,
 			 * but multi_pos starts at one, so the +1.
 			 */
+			if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
+				dev_dbg(&ssif_info->client->dev,
+					"Received message out of sequence, expected %u, got %u\n",
+					ssif_info->multi_pos - 1, blocknum);
 			result = -EIO;
 		} else {
 			ssif_inc_stat(ssif_info, received_message_parts);
@@ -710,6 +727,7 @@
 		}
 	}
 
+ continue_op:
 	if (result < 0) {
 		ssif_inc_stat(ssif_info, receive_errors);
 	} else {
@@ -717,8 +735,6 @@
 		ssif_inc_stat(ssif_info, received_message_parts);
 	}
 
-
- continue_op:
 	if (ssif_info->ssif_debug & SSIF_DEBUG_STATE)
 		pr_info(PFX "DONE 1: state = %d, result=%d.\n",
 			ssif_info->ssif_state, result);
@@ -726,10 +742,14 @@
 	flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
 	msg = ssif_info->curr_msg;
 	if (msg) {
+		if (data) {
+			if (len > IPMI_MAX_MSG_LENGTH)
+				len = IPMI_MAX_MSG_LENGTH;
+			memcpy(msg->rsp, data, len);
+		} else {
+			len = 0;
+		}
 		msg->rsp_size = len;
-		if (msg->rsp_size > IPMI_MAX_MSG_LENGTH)
-			msg->rsp_size = IPMI_MAX_MSG_LENGTH;
-		memcpy(msg->rsp, data, msg->rsp_size);
 		ssif_info->curr_msg = NULL;
 	}
 
@@ -755,9 +775,14 @@
 			ssif_info->ssif_state = SSIF_NORMAL;
 			ipmi_ssif_unlock_cond(ssif_info, flags);
 			pr_warn(PFX "Error getting flags: %d %d, %x\n",
-			       result, len, data[2]);
+			       result, len, (len >= 3) ? data[2] : 0);
 		} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
 			   || data[1] != IPMI_GET_MSG_FLAGS_CMD) {
+			/*
+			 * Don't abort here, maybe it was a queued
+			 * response to a previous command.
+			 */
+			ipmi_ssif_unlock_cond(ssif_info, flags);
 			pr_warn(PFX "Invalid response getting flags: %x %x\n",
 				data[0], data[1]);
 		} else {
@@ -772,7 +797,7 @@
 		if ((result < 0) || (len < 3) || (data[2] != 0)) {
 			/* Error clearing flags */
 			pr_warn(PFX "Error clearing flags: %d %d, %x\n",
-			       result, len, data[2]);
+			       result, len, (len >= 3) ? data[2] : 0);
 		} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
 			   || data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) {
 			pr_warn(PFX "Invalid response clearing flags: %x %x\n",
@@ -888,6 +913,7 @@
 		 * for details on the intricacies of this.
 		 */
 		int left;
+		unsigned char *data_to_send;
 
 		ssif_inc_stat(ssif_info, sent_messages_parts);
 
@@ -896,6 +922,7 @@
 			left = 32;
 		/* Length byte. */
 		ssif_info->multi_data[ssif_info->multi_pos] = left;
+		data_to_send = ssif_info->multi_data + ssif_info->multi_pos;
 		ssif_info->multi_pos += left;
 		if (left < 32)
 			/*
@@ -909,7 +936,7 @@
 		rv = ssif_i2c_send(ssif_info, msg_written_handler,
 				  I2C_SMBUS_WRITE,
 				  SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE,
-				  ssif_info->multi_data + ssif_info->multi_pos,
+				  data_to_send,
 				  I2C_SMBUS_BLOCK_DATA);
 		if (rv < 0) {
 			/* request failed, just return the error. */
@@ -942,8 +969,9 @@
 			ssif_info->waiting_alert = true;
 			ssif_info->retries_left = SSIF_RECV_RETRIES;
 			ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
-			mod_timer(&ssif_info->retry_timer,
-				  jiffies + SSIF_MSG_PART_JIFFIES);
+			if (!ssif_info->stopping)
+				mod_timer(&ssif_info->retry_timer,
+					  jiffies + SSIF_MSG_PART_JIFFIES);
 			ipmi_ssif_unlock_cond(ssif_info, flags);
 		}
 	}
--- linux-4.4.0.orig/drivers/char/ipmi/ipmi_watchdog.c
+++ linux-4.4.0/drivers/char/ipmi/ipmi_watchdog.c
@@ -515,7 +515,7 @@
 	msg.cmd = IPMI_WDOG_RESET_TIMER;
 	msg.data = NULL;
 	msg.data_len = 0;
-	atomic_add(2, &panic_done_count);
+	atomic_add(1, &panic_done_count);
 	rv = ipmi_request_supply_msgs(watchdog_user,
 				      (struct ipmi_addr *) &addr,
 				      0,
@@ -525,7 +525,7 @@
 				      &panic_halt_heartbeat_recv_msg,
 				      1);
 	if (rv)
-		atomic_sub(2, &panic_done_count);
+		atomic_sub(1, &panic_done_count);
 }
 
 static struct ipmi_smi_msg panic_halt_smi_msg = {
@@ -549,12 +549,12 @@
 	/* Wait for the messages to be free. */
 	while (atomic_read(&panic_done_count) != 0)
 		ipmi_poll_interface(watchdog_user);
-	atomic_add(2, &panic_done_count);
+	atomic_add(1, &panic_done_count);
 	rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
 				&panic_halt_recv_msg,
 				&send_heartbeat_now);
 	if (rv) {
-		atomic_sub(2, &panic_done_count);
+		atomic_sub(1, &panic_done_count);
 		printk(KERN_WARNING PFX
 		       "Unable to extend the watchdog timeout.");
 	} else {
@@ -1162,10 +1162,11 @@
 			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
 			ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
 		} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
-			/* Set a long timer to let the reboot happens, but
-			   reboot if it hangs, but only if the watchdog
+			/* Set a long timer to let the reboot happen or
+			   reset if it hangs, but only if the watchdog
 			   timer was already running. */
-			timeout = 120;
+			if (timeout < 120)
+				timeout = 120;
 			pretimeout = 0;
 			ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
 			ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
--- linux-4.4.0.orig/drivers/char/lp.c
+++ linux-4.4.0/drivers/char/lp.c
@@ -859,7 +859,11 @@
 	} else if (!strcmp(str, "auto")) {
 		parport_nr[0] = LP_PARPORT_AUTO;
 	} else if (!strcmp(str, "none")) {
-		parport_nr[parport_ptr++] = LP_PARPORT_NONE;
+		if (parport_ptr < LP_NO)
+			parport_nr[parport_ptr++] = LP_PARPORT_NONE;
+		else
+			printk(KERN_INFO "lp: too many ports, %s ignored.\n",
+			       str);
 	} else if (!strcmp(str, "reset")) {
 		reset = 1;
 	}
--- linux-4.4.0.orig/drivers/char/mem.c
+++ linux-4.4.0/drivers/char/mem.c
@@ -8,6 +8,7 @@
  *  Shared /dev/zero mmapping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
  */
 
+#include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
@@ -59,6 +60,10 @@
 #endif
 
 #ifdef CONFIG_STRICT_DEVMEM
+static inline int page_is_allowed(unsigned long pfn)
+{
+	return devmem_is_allowed(pfn);
+}
 static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 {
 	u64 from = ((u64)pfn) << PAGE_SHIFT;
@@ -66,18 +71,18 @@
 	u64 cursor = from;
 
 	while (cursor < to) {
-		if (!devmem_is_allowed(pfn)) {
-			printk(KERN_INFO
-		"Program %s tried to access /dev/mem between %Lx->%Lx.\n",
-				current->comm, from, to);
+		if (!devmem_is_allowed(pfn))
 			return 0;
-		}
 		cursor += PAGE_SIZE;
 		pfn++;
 	}
 	return 1;
 }
 #else
+static inline int page_is_allowed(unsigned long pfn)
+{
+	return 1;
+}
 static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 {
 	return 1;
@@ -91,6 +96,13 @@
 }
 #endif
 
+static inline bool should_stop_iteration(void)
+{
+	if (need_resched())
+		cond_resched();
+	return fatal_signal_pending(current);
+}
+
 /*
  * This funcion reads the *physical* memory. The f_pos points directly to the
  * memory location.
@@ -125,23 +137,31 @@
 
 	while (count > 0) {
 		unsigned long remaining;
+		int allowed;
 
 		sz = size_inside_page(p, count);
 
-		if (!range_is_allowed(p >> PAGE_SHIFT, count))
+		allowed = page_is_allowed(p >> PAGE_SHIFT);
+		if (!allowed)
 			return -EPERM;
+		if (allowed == 2) {
+			/* Show zeros for restricted memory. */
+			remaining = clear_user(buf, sz);
+		} else {
+			/*
+			 * On ia64 if a page has been mapped somewhere as
+			 * uncached, then it must also be accessed uncached
+			 * by the kernel or data corruption may occur.
+			 */
+			ptr = xlate_dev_mem_ptr(p);
+			if (!ptr)
+				return -EFAULT;
 
-		/*
-		 * On ia64 if a page has been mapped somewhere as uncached, then
-		 * it must also be accessed uncached by the kernel or data
-		 * corruption may occur.
-		 */
-		ptr = xlate_dev_mem_ptr(p);
-		if (!ptr)
-			return -EFAULT;
+			remaining = copy_to_user(buf, ptr, sz);
+
+			unxlate_dev_mem_ptr(p, ptr);
+		}
 
-		remaining = copy_to_user(buf, ptr, sz);
-		unxlate_dev_mem_ptr(p, ptr);
 		if (remaining)
 			return -EFAULT;
 
@@ -149,6 +169,8 @@
 		p += sz;
 		count -= sz;
 		read += sz;
+		if (should_stop_iteration())
+			break;
 	}
 
 	*ppos += read;
@@ -184,36 +206,44 @@
 #endif
 
 	while (count > 0) {
+		int allowed;
+
 		sz = size_inside_page(p, count);
 
-		if (!range_is_allowed(p >> PAGE_SHIFT, sz))
+		allowed = page_is_allowed(p >> PAGE_SHIFT);
+		if (!allowed)
 			return -EPERM;
 
-		/*
-		 * On ia64 if a page has been mapped somewhere as uncached, then
-		 * it must also be accessed uncached by the kernel or data
-		 * corruption may occur.
-		 */
-		ptr = xlate_dev_mem_ptr(p);
-		if (!ptr) {
-			if (written)
-				break;
-			return -EFAULT;
-		}
+		/* Skip actual writing when a page is marked as restricted. */
+		if (allowed == 1) {
+			/*
+			 * On ia64 if a page has been mapped somewhere as
+			 * uncached, then it must also be accessed uncached
+			 * by the kernel or data corruption may occur.
+			 */
+			ptr = xlate_dev_mem_ptr(p);
+			if (!ptr) {
+				if (written)
+					break;
+				return -EFAULT;
+			}
 
-		copied = copy_from_user(ptr, buf, sz);
-		unxlate_dev_mem_ptr(p, ptr);
-		if (copied) {
-			written += sz - copied;
-			if (written)
-				break;
-			return -EFAULT;
+			copied = copy_from_user(ptr, buf, sz);
+			unxlate_dev_mem_ptr(p, ptr);
+			if (copied) {
+				written += sz - copied;
+				if (written)
+					break;
+				return -EFAULT;
+			}
 		}
 
 		buf += sz;
 		p += sz;
 		count -= sz;
 		written += sz;
+		if (should_stop_iteration())
+			break;
 	}
 
 	*ppos += written;
@@ -321,6 +351,11 @@
 static int mmap_mem(struct file *file, struct vm_area_struct *vma)
 {
 	size_t size = vma->vm_end - vma->vm_start;
+	phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;
+
+	/* It's illegal to wrap around the end of the physical address space. */
+	if (offset + (phys_addr_t)size - 1 < offset)
+		return -EINVAL;
 
 	if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
 		return -EINVAL;
@@ -420,6 +455,10 @@
 			read += sz;
 			low_count -= sz;
 			count -= sz;
+			if (should_stop_iteration()) {
+				count = 0;
+				break;
+			}
 		}
 	}
 
@@ -444,6 +483,8 @@
 			buf += sz;
 			read += sz;
 			p += sz;
+			if (should_stop_iteration())
+				break;
 		}
 		free_page((unsigned long)kbuf);
 	}
@@ -494,6 +535,8 @@
 		p += sz;
 		count -= sz;
 		written += sz;
+		if (should_stop_iteration())
+			break;
 	}
 
 	*ppos += written;
@@ -545,6 +588,8 @@
 			buf += sz;
 			virtr += sz;
 			p += sz;
+			if (should_stop_iteration())
+				break;
 		}
 		free_page((unsigned long)kbuf);
 	}
@@ -712,6 +757,8 @@
 
 static int open_port(struct inode *inode, struct file *filp)
 {
+	if (secure_modules())
+		return -EPERM;
 	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 }
 
--- linux-4.4.0.orig/drivers/char/mwave/mwavedd.c
+++ linux-4.4.0/drivers/char/mwave/mwavedd.c
@@ -59,6 +59,7 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/serial_8250.h>
+#include <linux/nospec.h>
 #include "smapi.h"
 #include "mwavedd.h"
 #include "3780i.h"
@@ -80,10 +81,10 @@
 int mwave_uart_irq = 0;
 int mwave_uart_io = 0;
 module_param(mwave_debug, int, 0);
-module_param(mwave_3780i_irq, int, 0);
-module_param(mwave_3780i_io, int, 0);
-module_param(mwave_uart_irq, int, 0);
-module_param(mwave_uart_io, int, 0);
+module_param_hw(mwave_3780i_irq, int, irq, 0);
+module_param_hw(mwave_3780i_io, int, ioport, 0);
+module_param_hw(mwave_uart_irq, int, irq, 0);
+module_param_hw(mwave_uart_io, int, ioport, 0);
 
 static int mwave_open(struct inode *inode, struct file *file);
 static int mwave_close(struct inode *inode, struct file *file);
@@ -289,6 +290,8 @@
 						ipcnum);
 				return -EINVAL;
 			}
+			ipcnum = array_index_nospec(ipcnum,
+						    ARRAY_SIZE(pDrvData->IPCs));
 			PRINTK_3(TRACE_MWAVE,
 				"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
 				" ipcnum %x entry usIntCount %x\n",
@@ -317,6 +320,8 @@
 						" Invalid ipcnum %x\n", ipcnum);
 				return -EINVAL;
 			}
+			ipcnum = array_index_nospec(ipcnum,
+						    ARRAY_SIZE(pDrvData->IPCs));
 			PRINTK_3(TRACE_MWAVE,
 				"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"
 				" ipcnum %x, usIntCount %x\n",
@@ -383,6 +388,8 @@
 						ipcnum);
 				return -EINVAL;
 			}
+			ipcnum = array_index_nospec(ipcnum,
+						    ARRAY_SIZE(pDrvData->IPCs));
 			mutex_lock(&mwave_mutex);
 			if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
 				pDrvData->IPCs[ipcnum].bIsEnabled = FALSE;
--- linux-4.4.0.orig/drivers/char/pcmcia/cm4040_cs.c
+++ linux-4.4.0/drivers/char/pcmcia/cm4040_cs.c
@@ -374,7 +374,7 @@
 
 	rc = write_sync_reg(SCR_HOST_TO_READER_START, dev);
 	if (rc <= 0) {
-		DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
+		DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc);
 		DEBUGP(2, dev, "<- cm4040_write (failed)\n");
 		if (rc == -ERESTARTSYS)
 			return rc;
@@ -387,7 +387,7 @@
 	for (i = 0; i < bytes_to_write; i++) {
 		rc = wait_for_bulk_out_ready(dev);
 		if (rc <= 0) {
-			DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2Zx\n",
+			DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2zx\n",
 			       rc);
 			DEBUGP(2, dev, "<- cm4040_write (failed)\n");
 			if (rc == -ERESTARTSYS)
@@ -403,7 +403,7 @@
 	rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev);
 
 	if (rc <= 0) {
-		DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
+		DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc);
 		DEBUGP(2, dev, "<- cm4040_write (failed)\n");
 		if (rc == -ERESTARTSYS)
 			return rc;
--- linux-4.4.0.orig/drivers/char/random.c
+++ linux-4.4.0/drivers/char/random.c
@@ -678,7 +678,6 @@
 		r->initialized = 1;
 		r->entropy_total = 0;
 		if (r == &nonblocking_pool) {
-			prandom_reseed_late();
 			process_random_ready_list();
 			wake_up_all(&urandom_init_wait);
 			pr_notice("random: %s pool is initialized\n", r->name);
@@ -722,15 +721,18 @@
 	}
 }
 
-static void credit_entropy_bits_safe(struct entropy_store *r, int nbits)
+static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
 {
-	const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1));
+	const int nbits_max = r->poolinfo->poolwords * 32;
+
+	if (nbits < 0)
+		return -EINVAL;
 
 	/* Cap the value to avoid overflows */
 	nbits = min(nbits,  nbits_max);
-	nbits = max(nbits, -nbits_max);
 
 	credit_entropy_bits(r, nbits);
+	return 0;
 }
 
 /*********************************************************************
@@ -883,12 +885,16 @@
 static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
 {
 	__u32 *ptr = (__u32 *) regs;
+	unsigned int idx;
 
 	if (regs == NULL)
 		return 0;
-	if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32))
-		f->reg_idx = 0;
-	return *(ptr + f->reg_idx++);
+	idx = READ_ONCE(f->reg_idx);
+	if (idx >= sizeof(struct pt_regs) / sizeof(__u32))
+		idx = 0;
+	ptr += idx++;
+	WRITE_ONCE(f->reg_idx, idx);
+	return *ptr;
 }
 
 void add_interrupt_randomness(int irq, int irq_flags)
@@ -945,6 +951,7 @@
 	/* award one bit for the contents of the fast pool */
 	credit_entropy_bits(r, credit + 1);
 }
+EXPORT_SYMBOL_GPL(add_interrupt_randomness);
 
 #ifdef CONFIG_BLOCK
 void add_disk_randomness(struct gendisk *disk)
@@ -1457,12 +1464,16 @@
 static ssize_t
 urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
 {
+	static int maxwarn = 10;
 	int ret;
 
-	if (unlikely(nonblocking_pool.initialized == 0))
-		printk_once(KERN_NOTICE "random: %s urandom read "
-			    "with %d bits of entropy available\n",
-			    current->comm, nonblocking_pool.entropy_total);
+	if (unlikely(nonblocking_pool.initialized == 0) &&
+	    maxwarn > 0) {
+		maxwarn--;
+		printk(KERN_NOTICE "random: %s: uninitialized urandom read "
+		       "(%zd bytes read, %d bits of entropy available)\n",
+		       current->comm, nbytes, nonblocking_pool.entropy_total);
+	}
 
 	nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
 	ret = extract_entropy_user(&nonblocking_pool, buf, nbytes);
@@ -1491,14 +1502,22 @@
 write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
 {
 	size_t bytes;
-	__u32 buf[16];
+	__u32 t, buf[16];
 	const char __user *p = buffer;
 
 	while (count > 0) {
+		int b, i = 0;
+
 		bytes = min(count, sizeof(buf));
 		if (copy_from_user(&buf, p, bytes))
 			return -EFAULT;
 
+		for (b = bytes ; b > 0 ; b -= sizeof(__u32), i++) {
+			if (!arch_get_random_int(&t))
+				break;
+			buf[i] ^= t;
+		}
+
 		count -= bytes;
 		p += bytes;
 
@@ -1542,8 +1561,7 @@
 			return -EPERM;
 		if (get_user(ent_count, p))
 			return -EFAULT;
-		credit_entropy_bits_safe(&input_pool, ent_count);
-		return 0;
+		return credit_entropy_bits_safe(&input_pool, ent_count);
 	case RNDADDENTROPY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
@@ -1557,8 +1575,7 @@
 				    size);
 		if (retval < 0)
 			return retval;
-		credit_entropy_bits_safe(&input_pool, ent_count);
-		return 0;
+		return credit_entropy_bits_safe(&input_pool, ent_count);
 	case RNDZAPENTCNT:
 	case RNDCLEARPOOL:
 		/*
@@ -1792,21 +1809,20 @@
 	return 0;
 }
 
+static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash)
+		__aligned(sizeof(unsigned long));
+
 /*
  * Get a random word for internal kernel use only. Similar to urandom but
  * with the goal of minimal entropy pool depletion. As a result, the random
  * value is not cryptographically secure but for several uses the cost of
  * depleting entropy is too high
  */
-static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash);
 unsigned int get_random_int(void)
 {
 	__u32 *hash;
 	unsigned int ret;
 
-	if (arch_get_random_int(&ret))
-		return ret;
-
 	hash = get_cpu_var(get_random_int_hash);
 
 	hash[0] += current->pid + jiffies + random_get_entropy();
@@ -1819,6 +1835,25 @@
 EXPORT_SYMBOL(get_random_int);
 
 /*
+ * Same as get_random_int(), but returns unsigned long.
+ */
+unsigned long get_random_long(void)
+{
+	__u32 *hash;
+	unsigned long ret;
+
+	hash = get_cpu_var(get_random_int_hash);
+
+	hash[0] += current->pid + jiffies + random_get_entropy();
+	md5_transform(hash, random_int_secret);
+	ret = *(unsigned long *)hash;
+	put_cpu_var(get_random_int_hash);
+
+	return ret;
+}
+EXPORT_SYMBOL(get_random_long);
+
+/*
  * randomize_range() returns a start address such that
  *
  *    [...... <range> .....]
@@ -1846,12 +1881,18 @@
 {
 	struct entropy_store *poolp = &input_pool;
 
-	/* Suspend writing if we're above the trickle threshold.
-	 * We'll be woken up again once below random_write_wakeup_thresh,
-	 * or when the calling thread is about to terminate.
-	 */
-	wait_event_interruptible(random_write_wait, kthread_should_stop() ||
+	if (unlikely(nonblocking_pool.initialized == 0))
+		poolp = &nonblocking_pool;
+	else {
+		/* Suspend writing if we're above the trickle
+		 * threshold.  We'll be woken up again once below
+		 * random_write_wakeup_thresh, or when the calling
+		 * thread is about to terminate.
+		 */
+		wait_event_interruptible(random_write_wait,
+					 kthread_should_stop() ||
 			ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits);
+	}
 	mix_pool_bytes(poolp, buffer, count);
 	credit_entropy_bits(poolp, entropy);
 }
--- linux-4.4.0.orig/drivers/char/tlclk.c
+++ linux-4.4.0/drivers/char/tlclk.c
@@ -777,17 +777,21 @@
 {
 	int ret;
 
+	telclk_interrupt = (inb(TLCLK_REG7) & 0x0f);
+
+	alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
+	if (!alarm_events) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+
 	ret = register_chrdev(tlclk_major, "telco_clock", &tlclk_fops);
 	if (ret < 0) {
 		printk(KERN_ERR "tlclk: can't get major %d.\n", tlclk_major);
+		kfree(alarm_events);
 		return ret;
 	}
 	tlclk_major = ret;
-	alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
-	if (!alarm_events) {
-		ret = -ENOMEM;
-		goto out1;
-	}
 
 	/* Read telecom clock IRQ number (Set by BIOS) */
 	if (!request_region(TLCLK_BASE, 8, "telco_clock")) {
@@ -796,7 +800,6 @@
 		ret = -EBUSY;
 		goto out2;
 	}
-	telclk_interrupt = (inb(TLCLK_REG7) & 0x0f);
 
 	if (0x0F == telclk_interrupt ) { /* not MCPBL0010 ? */
 		printk(KERN_ERR "telclk_interrupt = 0x%x non-mcpbl0010 hw.\n",
@@ -837,8 +840,8 @@
 	release_region(TLCLK_BASE, 8);
 out2:
 	kfree(alarm_events);
-out1:
 	unregister_chrdev(tlclk_major, "telco_clock");
+out1:
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/char/tpm/st33zp24/st33zp24.c
+++ linux-4.4.0/drivers/char/tpm/st33zp24/st33zp24.c
@@ -485,7 +485,7 @@
 			    size_t count)
 {
 	int size = 0;
-	int expected;
+	u32 expected;
 
 	if (!chip)
 		return -EBUSY;
@@ -502,7 +502,7 @@
 	}
 
 	expected = be32_to_cpu(*(__be32 *)(buf + 2));
-	if (expected > count) {
+	if (expected > count || expected < TPM_HEADER_SIZE) {
 		size = -EIO;
 		goto out;
 	}
--- linux-4.4.0.orig/drivers/char/tpm/tpm-chip.c
+++ linux-4.4.0/drivers/char/tpm/tpm-chip.c
@@ -26,36 +26,96 @@
 #include <linux/spinlock.h>
 #include <linux/freezer.h>
 #include <linux/major.h>
+#include <linux/of.h>
 #include "tpm.h"
 #include "tpm_eventlog.h"
 
-static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
-static LIST_HEAD(tpm_chip_list);
-static DEFINE_SPINLOCK(driver_lock);
+DEFINE_IDR(dev_nums_idr);
+static DEFINE_MUTEX(idr_lock);
 
 struct class *tpm_class;
 dev_t tpm_devt;
 
-/*
- * tpm_chip_find_get - return tpm_chip for a given chip number
- * @chip_num the device number for the chip
+/**
+ * tpm_try_get_ops() - Get a ref to the tpm_chip
+ * @chip: Chip to ref
+ *
+ * The caller must already have some kind of locking to ensure that chip is
+ * valid. This function will lock the chip so that the ops member can be
+ * accessed safely. The locking prevents tpm_chip_unregister from
+ * completing, so it should not be held for long periods.
+ *
+ * Returns -ERRNO if the chip could not be got.
+ */
+int tpm_try_get_ops(struct tpm_chip *chip)
+{
+	int rc = -EIO;
+
+	get_device(&chip->dev);
+
+	down_read(&chip->ops_sem);
+	if (!chip->ops)
+		goto out_lock;
+
+	if (!try_module_get(chip->dev.parent->driver->owner))
+		goto out_lock;
+
+	return 0;
+out_lock:
+	up_read(&chip->ops_sem);
+	put_device(&chip->dev);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_try_get_ops);
+
+/**
+ * tpm_put_ops() - Release a ref to the tpm_chip
+ * @chip: Chip to put
+ *
+ * This is the opposite pair to tpm_try_get_ops(). After this returns chip may
+ * be kfree'd.
  */
+void tpm_put_ops(struct tpm_chip *chip)
+{
+	module_put(chip->dev.parent->driver->owner);
+	up_read(&chip->ops_sem);
+	put_device(&chip->dev);
+}
+EXPORT_SYMBOL_GPL(tpm_put_ops);
+
+/**
+ * tpm_chip_find_get() - return tpm_chip for a given chip number
+ * @chip_num: id to find
+ *
+ * The return'd chip has been tpm_try_get_ops'd and must be released via
+ * tpm_put_ops
+  */
 struct tpm_chip *tpm_chip_find_get(int chip_num)
 {
-	struct tpm_chip *pos, *chip = NULL;
+	struct tpm_chip *chip, *res = NULL;
+	int chip_prev;
 
-	rcu_read_lock();
-	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
-		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
-			continue;
-
-		if (try_module_get(pos->pdev->driver->owner)) {
-			chip = pos;
-			break;
-		}
+	mutex_lock(&idr_lock);
+
+	if (chip_num == TPM_ANY_NUM) {
+		chip_num = 0;
+		do {
+			chip_prev = chip_num;
+			chip = idr_get_next(&dev_nums_idr, &chip_num);
+			if (chip && !tpm_try_get_ops(chip)) {
+				res = chip;
+				break;
+			}
+		} while (chip_prev != chip_num);
+	} else {
+		chip = idr_find_slowpath(&dev_nums_idr, chip_num);
+		if (chip && !tpm_try_get_ops(chip))
+			res = chip;
 	}
-	rcu_read_unlock();
-	return chip;
+
+	mutex_unlock(&idr_lock);
+
+	return res;
 }
 
 /**
@@ -68,12 +128,48 @@
 {
 	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
 
-	spin_lock(&driver_lock);
-	clear_bit(chip->dev_num, dev_mask);
-	spin_unlock(&driver_lock);
+	mutex_lock(&idr_lock);
+	idr_remove(&dev_nums_idr, chip->dev_num);
+	mutex_unlock(&idr_lock);
+
 	kfree(chip);
 }
 
+
+/**
+ * tpm_class_shutdown() - prepare the TPM device for loss of power.
+ * @dev: device to which the chip is associated.
+ *
+ * Issues a TPM2_Shutdown command prior to loss of power, as required by the
+ * TPM 2.0 spec.
+ * Then, calls bus- and device- specific shutdown code.
+ *
+ * XXX: This codepath relies on the fact that sysfs is not enabled for
+ * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2
+ * has sysfs support enabled before TPM sysfs's implicit locking is fixed.
+ */
+static int tpm_class_shutdown(struct device *dev)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		down_write(&chip->ops_sem);
+		tpm2_shutdown(chip, TPM2_SU_CLEAR);
+		chip->ops = NULL;
+		up_write(&chip->ops_sem);
+	}
+	/* Allow bus- and device-specific code to run. Note: since chip->ops
+	 * is NULL, more-specific shutdown code will not be able to issue TPM
+	 * commands.
+	 */
+	if (dev->bus && dev->bus->shutdown)
+		dev->bus->shutdown(dev);
+	else if (dev->driver && dev->driver->shutdown)
+		dev->driver->shutdown(dev);
+	return 0;
+}
+
+
 /**
  * tpmm_chip_alloc() - allocate a new struct tpm_chip instance
  * @dev: device to which the chip is associated
@@ -88,37 +184,35 @@
 				 const struct tpm_class_ops *ops)
 {
 	struct tpm_chip *chip;
+	int rc;
 
 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 	if (chip == NULL)
 		return ERR_PTR(-ENOMEM);
 
 	mutex_init(&chip->tpm_mutex);
-	INIT_LIST_HEAD(&chip->list);
+	init_rwsem(&chip->ops_sem);
 
 	chip->ops = ops;
 
-	spin_lock(&driver_lock);
-	chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
-	spin_unlock(&driver_lock);
-
-	if (chip->dev_num >= TPM_NUM_DEVICES) {
+	mutex_lock(&idr_lock);
+	rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL);
+	mutex_unlock(&idr_lock);
+	if (rc < 0) {
 		dev_err(dev, "No available tpm device numbers\n");
 		kfree(chip);
-		return ERR_PTR(-ENOMEM);
+		return ERR_PTR(rc);
 	}
-
-	set_bit(chip->dev_num, dev_mask);
+	chip->dev_num = rc;
 
 	scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num);
 
-	chip->pdev = dev;
-
 	dev_set_drvdata(dev, chip);
 
 	chip->dev.class = tpm_class;
+	chip->dev.class->shutdown = tpm_class_shutdown;
 	chip->dev.release = tpm_dev_release;
-	chip->dev.parent = chip->pdev;
+	chip->dev.parent = dev;
 #ifdef CONFIG_ACPI
 	chip->dev.groups = chip->groups;
 #endif
@@ -133,14 +227,20 @@
 	device_initialize(&chip->dev);
 
 	cdev_init(&chip->cdev, &tpm_fops);
-	chip->cdev.owner = chip->pdev->driver->owner;
+	chip->cdev.owner = dev->driver->owner;
 	chip->cdev.kobj.parent = &chip->dev.kobj;
 
+	rc = devm_add_action(dev, (void (*)(void *)) put_device, &chip->dev);
+	if (rc) {
+		put_device(&chip->dev);
+		return ERR_PTR(rc);
+	}
+
 	return chip;
 }
 EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
 
-static int tpm_dev_add_device(struct tpm_chip *chip)
+static int tpm_add_char_device(struct tpm_chip *chip)
 {
 	int rc;
 
@@ -151,7 +251,6 @@
 			chip->devname, MAJOR(chip->dev.devt),
 			MINOR(chip->dev.devt), rc);
 
-		device_unregister(&chip->dev);
 		return rc;
 	}
 
@@ -162,16 +261,32 @@
 			chip->devname, MAJOR(chip->dev.devt),
 			MINOR(chip->dev.devt), rc);
 
+		cdev_del(&chip->cdev);
 		return rc;
 	}
 
+	/* Make the chip available. */
+	mutex_lock(&idr_lock);
+	idr_replace(&dev_nums_idr, chip, chip->dev_num);
+	mutex_unlock(&idr_lock);
+
 	return rc;
 }
 
-static void tpm_dev_del_device(struct tpm_chip *chip)
+static void tpm_del_char_device(struct tpm_chip *chip)
 {
 	cdev_del(&chip->cdev);
-	device_unregister(&chip->dev);
+	device_del(&chip->dev);
+
+	/* Make the chip unavailable. */
+	mutex_lock(&idr_lock);
+	idr_replace(&dev_nums_idr, NULL, chip->dev_num);
+	mutex_unlock(&idr_lock);
+
+	/* Make the driver uncallable. */
+	down_write(&chip->ops_sem);
+	chip->ops = NULL;
+	up_write(&chip->ops_sem);
 }
 
 static int tpm1_chip_register(struct tpm_chip *chip)
@@ -214,29 +329,35 @@
  */
 int tpm_chip_register(struct tpm_chip *chip)
 {
+#ifdef CONFIG_OF
+	struct device_node *np;
+#endif
 	int rc;
 
+#ifdef CONFIG_OF
+	np = of_find_node_by_name(NULL, "vtpm");
+	if (np) {
+		if (of_property_read_bool(np, "powered-while-suspended"))
+			chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
+	}
+	of_node_put(np);
+#endif
+
 	rc = tpm1_chip_register(chip);
 	if (rc)
 		return rc;
 
 	tpm_add_ppi(chip);
 
-	rc = tpm_dev_add_device(chip);
+	rc = tpm_add_char_device(chip);
 	if (rc)
 		goto out_err;
 
-	/* Make the chip available. */
-	spin_lock(&driver_lock);
-	list_add_tail_rcu(&chip->list, &tpm_chip_list);
-	spin_unlock(&driver_lock);
-
 	chip->flags |= TPM_CHIP_FLAG_REGISTERED;
 
 	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
-		rc = __compat_only_sysfs_link_entry_to_kobj(&chip->pdev->kobj,
-							    &chip->dev.kobj,
-							    "ppi");
+		rc = __compat_only_sysfs_link_entry_to_kobj(
+		    &chip->dev.parent->kobj, &chip->dev.kobj, "ppi");
 		if (rc && rc != -ENOENT) {
 			tpm_chip_unregister(chip);
 			return rc;
@@ -257,6 +378,9 @@
  * Takes the chip first away from the list of available TPM chips and then
  * cleans up all the resources reserved by tpm_chip_register().
  *
+ * Once this function returns the driver call backs in 'op's will not be
+ * running and will no longer start.
+ *
  * NOTE: This function should be only called before deinitializing chip
  * resources.
  */
@@ -265,15 +389,10 @@
 	if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED))
 		return;
 
-	spin_lock(&driver_lock);
-	list_del_rcu(&chip->list);
-	spin_unlock(&driver_lock);
-	synchronize_rcu();
-
 	if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
-		sysfs_remove_link(&chip->pdev->kobj, "ppi");
+		sysfs_remove_link(&chip->dev.parent->kobj, "ppi");
 
 	tpm1_chip_unregister(chip);
-	tpm_dev_del_device(chip);
+	tpm_del_char_device(chip);
 }
 EXPORT_SYMBOL_GPL(tpm_chip_unregister);
--- linux-4.4.0.orig/drivers/char/tpm/tpm-dev.c
+++ linux-4.4.0/drivers/char/tpm/tpm-dev.c
@@ -25,7 +25,7 @@
 	struct tpm_chip *chip;
 
 	/* Data passed to and from the tpm via the read/write calls */
-	atomic_t data_pending;
+	size_t data_pending;
 	struct mutex buffer_mutex;
 
 	struct timer_list user_read_timer;      /* user needs to claim result */
@@ -46,7 +46,7 @@
 	struct file_priv *priv = container_of(work, struct file_priv, work);
 
 	mutex_lock(&priv->buffer_mutex);
-	atomic_set(&priv->data_pending, 0);
+	priv->data_pending = 0;
 	memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
 	mutex_unlock(&priv->buffer_mutex);
 }
@@ -61,7 +61,7 @@
 	 * by the check of is_open variable, which is protected
 	 * by driver_lock. */
 	if (test_and_set_bit(0, &chip->is_open)) {
-		dev_dbg(chip->pdev, "Another process owns this TPM\n");
+		dev_dbg(&chip->dev, "Another process owns this TPM\n");
 		return -EBUSY;
 	}
 
@@ -72,14 +72,12 @@
 	}
 
 	priv->chip = chip;
-	atomic_set(&priv->data_pending, 0);
 	mutex_init(&priv->buffer_mutex);
 	setup_timer(&priv->user_read_timer, user_reader_timeout,
 			(unsigned long)priv);
 	INIT_WORK(&priv->work, timeout_work);
 
 	file->private_data = priv;
-	get_device(chip->pdev);
 	return 0;
 }
 
@@ -87,28 +85,24 @@
 			size_t size, loff_t *off)
 {
 	struct file_priv *priv = file->private_data;
-	ssize_t ret_size;
+	ssize_t ret_size = 0;
 	int rc;
 
 	del_singleshot_timer_sync(&priv->user_read_timer);
 	flush_work(&priv->work);
-	ret_size = atomic_read(&priv->data_pending);
-	if (ret_size > 0) {	/* relay data */
-		ssize_t orig_ret_size = ret_size;
-		if (size < ret_size)
-			ret_size = size;
+	mutex_lock(&priv->buffer_mutex);
 
-		mutex_lock(&priv->buffer_mutex);
+	if (priv->data_pending) {
+		ret_size = min_t(ssize_t, size, priv->data_pending);
 		rc = copy_to_user(buf, priv->data_buffer, ret_size);
-		memset(priv->data_buffer, 0, orig_ret_size);
+		memset(priv->data_buffer, 0, priv->data_pending);
 		if (rc)
 			ret_size = -EFAULT;
 
-		mutex_unlock(&priv->buffer_mutex);
+		priv->data_pending = 0;
 	}
 
-	atomic_set(&priv->data_pending, 0);
-
+	mutex_unlock(&priv->buffer_mutex);
 	return ret_size;
 }
 
@@ -119,33 +113,44 @@
 	size_t in_size = size;
 	ssize_t out_size;
 
-	/* cannot perform a write until the read has cleared
-	   either via tpm_read or a user_read_timer timeout.
-	   This also prevents splitted buffered writes from blocking here.
-	*/
-	if (atomic_read(&priv->data_pending) != 0)
-		return -EBUSY;
-
 	if (in_size > TPM_BUFSIZE)
 		return -E2BIG;
 
 	mutex_lock(&priv->buffer_mutex);
 
+	/* Cannot perform a write until the read has cleared either via
+	 * tpm_read or a user_read_timer timeout. This also prevents split
+	 * buffered writes from blocking here.
+	 */
+	if (priv->data_pending != 0) {
+		mutex_unlock(&priv->buffer_mutex);
+		return -EBUSY;
+	}
+
 	if (copy_from_user
 	    (priv->data_buffer, (void __user *) buf, in_size)) {
 		mutex_unlock(&priv->buffer_mutex);
 		return -EFAULT;
 	}
 
-	/* atomic tpm command send and result receive */
+	/* atomic tpm command send and result receive. We only hold the ops
+	 * lock during this period so that the tpm can be unregistered even if
+	 * the char dev is held open.
+	 */
+	if (tpm_try_get_ops(priv->chip)) {
+		mutex_unlock(&priv->buffer_mutex);
+		return -EPIPE;
+	}
 	out_size = tpm_transmit(priv->chip, priv->data_buffer,
-				sizeof(priv->data_buffer));
+				sizeof(priv->data_buffer), 0);
+
+	tpm_put_ops(priv->chip);
 	if (out_size < 0) {
 		mutex_unlock(&priv->buffer_mutex);
 		return out_size;
 	}
 
-	atomic_set(&priv->data_pending, out_size);
+	priv->data_pending = out_size;
 	mutex_unlock(&priv->buffer_mutex);
 
 	/* Set a timeout by which the reader must come claim the result */
@@ -164,9 +169,8 @@
 	del_singleshot_timer_sync(&priv->user_read_timer);
 	flush_work(&priv->work);
 	file->private_data = NULL;
-	atomic_set(&priv->data_pending, 0);
+	priv->data_pending = 0;
 	clear_bit(0, &priv->chip->is_open);
-	put_device(priv->chip->pdev);
 	kfree(priv);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/char/tpm/tpm-interface.c
+++ linux-4.4.0/drivers/char/tpm/tpm-interface.c
@@ -310,10 +310,12 @@
 {
 	int duration_idx = TPM_UNDEFINED;
 	int duration = 0;
-	u8 category = (ordinal >> 24) & 0xFF;
 
-	if ((category == TPM_PROTECTED_COMMAND && ordinal < TPM_MAX_ORDINAL) ||
-	    (category == TPM_CONNECTION_COMMAND && ordinal < TSC_MAX_ORDINAL))
+	/*
+	 * We only have a duration table for protected commands, where the upper
+	 * 16 bits are 0. For the few other ordinals the fallback will be used.
+	 */
+	if (ordinal < TPM_MAX_ORDINAL)
 		duration_idx = tpm_ordinal_duration[ordinal];
 
 	if (duration_idx != TPM_UNDEFINED)
@@ -328,8 +330,8 @@
 /*
  * Internal kernel interface to transmit TPM commands
  */
-ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
-		     size_t bufsiz)
+ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
+		     unsigned int flags)
 {
 	ssize_t rc;
 	u32 count, ordinal;
@@ -343,16 +345,17 @@
 	if (count == 0)
 		return -ENODATA;
 	if (count > bufsiz) {
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"invalid count value %x %zx\n", count, bufsiz);
 		return -E2BIG;
 	}
 
-	mutex_lock(&chip->tpm_mutex);
+	if (!(flags & TPM_TRANSMIT_UNLOCKED))
+		mutex_lock(&chip->tpm_mutex);
 
 	rc = chip->ops->send(chip, (u8 *) buf, count);
 	if (rc < 0) {
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"tpm_transmit: tpm_send: error %zd\n", rc);
 		goto out;
 	}
@@ -371,7 +374,7 @@
 			goto out_recv;
 
 		if (chip->ops->req_canceled(chip, status)) {
-			dev_err(chip->pdev, "Operation Canceled\n");
+			dev_err(&chip->dev, "Operation Canceled\n");
 			rc = -ECANCELED;
 			goto out;
 		}
@@ -381,30 +384,31 @@
 	} while (time_before(jiffies, stop));
 
 	chip->ops->cancel(chip);
-	dev_err(chip->pdev, "Operation Timed out\n");
+	dev_err(&chip->dev, "Operation Timed out\n");
 	rc = -ETIME;
 	goto out;
 
 out_recv:
 	rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
 	if (rc < 0)
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"tpm_transmit: tpm_recv: error %zd\n", rc);
 out:
-	mutex_unlock(&chip->tpm_mutex);
+	if (!(flags & TPM_TRANSMIT_UNLOCKED))
+		mutex_unlock(&chip->tpm_mutex);
 	return rc;
 }
 
 #define TPM_DIGEST_SIZE 20
 #define TPM_RET_CODE_IDX 6
 
-ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
-			 int len, const char *desc)
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd,
+			 int len, unsigned int flags, const char *desc)
 {
-	struct tpm_output_header *header;
+	const struct tpm_output_header *header;
 	int err;
 
-	len = tpm_transmit(chip, (u8 *) cmd, len);
+	len = tpm_transmit(chip, (const u8 *)cmd, len, flags);
 	if (len <  0)
 		return len;
 	else if (len < TPM_HEADER_SIZE)
@@ -413,8 +417,9 @@
 	header = cmd;
 
 	err = be32_to_cpu(header->return_code);
-	if (err != 0 && desc)
-		dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err,
+	if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED
+	    && desc)
+		dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
 			desc);
 
 	return err;
@@ -452,7 +457,8 @@
 		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 		tpm_cmd.params.getcap_in.subcap = subcap_id;
 	}
-	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
+			      desc);
 	if (!rc)
 		*cap = tpm_cmd.params.getcap_out.cap;
 	return rc;
@@ -468,7 +474,7 @@
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 
-	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
 			      "attempting to determine the timeouts");
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
@@ -489,7 +495,7 @@
 	start_cmd.header.in = tpm_startup_header;
 
 	start_cmd.params.startup_in.startup_type = startup_type;
-	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
 				"attempting to start the TPM");
 }
 
@@ -501,16 +507,32 @@
 	struct duration_t *duration_cap;
 	ssize_t rc;
 
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		/* Fixed timeouts for TPM2 */
+		chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
+		chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
+		chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
+		chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
+		chip->vendor.duration[TPM_SHORT] =
+		    msecs_to_jiffies(TPM2_DURATION_SHORT);
+		chip->vendor.duration[TPM_MEDIUM] =
+		    msecs_to_jiffies(TPM2_DURATION_MEDIUM);
+		chip->vendor.duration[TPM_LONG] =
+		    msecs_to_jiffies(TPM2_DURATION_LONG);
+		return 0;
+	}
+
 	tpm_cmd.header.in = tpm_getcap_header;
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
-	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
+			      NULL);
 
 	if (rc == TPM_ERR_INVALID_POSTINIT) {
 		/* The TPM is not started, we are the first to talk to it.
 		   Execute a startup command. */
-		dev_info(chip->pdev, "Issuing TPM_STARTUP");
+		dev_info(&chip->dev, "Issuing TPM_STARTUP");
 		if (tpm_startup(chip, TPM_ST_CLEAR))
 			return rc;
 
@@ -519,10 +541,10 @@
 		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 		rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-				  NULL);
+				      0, NULL);
 	}
 	if (rc) {
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"A TPM error (%zd) occurred attempting to determine the timeouts\n",
 			rc);
 		goto duration;
@@ -561,7 +583,7 @@
 
 	/* Report adjusted timeouts */
 	if (chip->vendor.timeout_adjusted) {
-		dev_info(chip->pdev,
+		dev_info(&chip->dev,
 			 HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
 			 old_timeout[0], new_timeout[0],
 			 old_timeout[1], new_timeout[1],
@@ -580,7 +602,7 @@
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
 
-	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
 			      "attempting to determine the durations");
 	if (rc)
 		return rc;
@@ -608,7 +630,7 @@
 		chip->vendor.duration[TPM_MEDIUM] *= 1000;
 		chip->vendor.duration[TPM_LONG] *= 1000;
 		chip->vendor.duration_adjusted = true;
-		dev_info(chip->pdev, "Adjusting TPM timeout parameters.");
+		dev_info(&chip->dev, "Adjusting TPM timeout parameters.");
 	}
 	return 0;
 }
@@ -636,7 +658,7 @@
 	struct tpm_cmd_t cmd;
 
 	cmd.header.in = continue_selftest_header;
-	rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
+	rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0,
 			      "continue selftest");
 	return rc;
 }
@@ -656,7 +678,7 @@
 
 	cmd.header.in = pcrread_header;
 	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
-	rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
+	rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, 0,
 			      "attempting to read a pcr value");
 
 	if (rc == 0)
@@ -683,7 +705,7 @@
 
 	rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0;
 
-	tpm_chip_put(chip);
+	tpm_put_ops(chip);
 
 	return rc;
 }
@@ -712,7 +734,7 @@
 		rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
 	else
 		rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
-	tpm_chip_put(chip);
+	tpm_put_ops(chip);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_pcr_read);
@@ -747,17 +769,17 @@
 
 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
 		rc = tpm2_pcr_extend(chip, pcr_idx, hash);
-		tpm_chip_put(chip);
+		tpm_put_ops(chip);
 		return rc;
 	}
 
 	cmd.header.in = pcrextend_header;
 	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
 	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
-	rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+	rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0,
 			      "attempting extend a PCR value");
 
-	tpm_chip_put(chip);
+	tpm_put_ops(chip);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_pcr_extend);
@@ -783,6 +805,10 @@
 	loops = jiffies_to_msecs(duration) / delay_msec;
 
 	rc = tpm_continue_selftest(chip);
+	if (rc == TPM_ERR_INVALID_POSTINIT) {
+		chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
+		dev_info(&chip->dev, "TPM not ready (%d)\n", rc);
+	}
 	/* This may fail if there was no TPM driver during a suspend/resume
 	 * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
 	 */
@@ -793,12 +819,14 @@
 		/* 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);
+		rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE, 0);
 		/* Some buggy TPMs will not respond to tpm_tis_ready() for
 		 * around 300ms while the self test is ongoing, keep trying
 		 * until the self test duration expires. */
 		if (rc == -ETIME) {
-			dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test");
+			dev_info(
+			    &chip->dev, HW_ERR
+			    "TPM command timed out during continue self test");
 			msleep(delay_msec);
 			continue;
 		}
@@ -808,7 +836,7 @@
 
 		rc = be32_to_cpu(cmd.header.out.return_code);
 		if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
-			dev_info(chip->pdev,
+			dev_info(&chip->dev,
 				 "TPM is disabled/deactivated (0x%X)\n", rc);
 			/* TPM is disabled and/or deactivated; driver can
 			 * proceed and TPM does handle commands for
@@ -834,9 +862,9 @@
 	if (chip == NULL)
 		return -ENODEV;
 
-	rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
+	rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd");
 
-	tpm_chip_put(chip);
+	tpm_put_ops(chip);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_send);
@@ -925,6 +953,9 @@
 	if (chip == NULL)
 		return -ENODEV;
 
+	if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
+		return 0;
+
 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
 		tpm2_shutdown(chip, TPM2_SU_STATE);
 		return 0;
@@ -936,14 +967,15 @@
 		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
 		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
 		       TPM_DIGEST_SIZE);
-		rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+		rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0,
 				      "extending dummy pcr before suspend");
 	}
 
 	/* now do the actual savestate */
 	for (try = 0; try < TPM_RETRY; try++) {
 		cmd.header.in = savestate_header;
-		rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
+		rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0,
+				      NULL);
 
 		/*
 		 * If the TPM indicates that it is too busy to respond to
@@ -961,10 +993,10 @@
 	}
 
 	if (rc)
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"Error (%d) sending savestate before suspend\n", rc);
 	else if (try > 0)
-		dev_warn(chip->pdev, "TPM savestate took %dms\n",
+		dev_warn(&chip->dev, "TPM savestate took %dms\n",
 			 try * TPM_TIMEOUT_RETRY);
 
 	return rc;
@@ -1018,7 +1050,7 @@
 
 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
 		err = tpm2_get_random(chip, out, max);
-		tpm_chip_put(chip);
+		tpm_put_ops(chip);
 		return err;
 	}
 
@@ -1027,12 +1059,17 @@
 		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
 
 		err = tpm_transmit_cmd(chip, &tpm_cmd,
-				   TPM_GETRANDOM_RESULT_SIZE + num_bytes,
-				   "attempting get random");
+				       TPM_GETRANDOM_RESULT_SIZE + num_bytes,
+				       0, "attempting get random");
 		if (err)
 			break;
 
 		recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len);
+		if (recd > num_bytes) {
+			total = -EFAULT;
+			break;
+		}
+
 		memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd);
 
 		dest += recd;
@@ -1040,7 +1077,7 @@
 		num_bytes -= recd;
 	} while (retries-- && total < max);
 
-	tpm_chip_put(chip);
+	tpm_put_ops(chip);
 	return total ? total : -EIO;
 }
 EXPORT_SYMBOL_GPL(tpm_get_random);
@@ -1066,7 +1103,7 @@
 
 	rc = tpm2_seal_trusted(chip, payload, options);
 
-	tpm_chip_put(chip);
+	tpm_put_ops(chip);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_seal_trusted);
@@ -1092,7 +1129,8 @@
 
 	rc = tpm2_unseal_trusted(chip, payload, options);
 
-	tpm_chip_put(chip);
+	tpm_put_ops(chip);
+
 	return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_unseal_trusted);
@@ -1119,6 +1157,7 @@
 
 static void __exit tpm_exit(void)
 {
+	idr_destroy(&dev_nums_idr);
 	class_destroy(tpm_class);
 	unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
 }
--- linux-4.4.0.orig/drivers/char/tpm/tpm-sysfs.c
+++ linux-4.4.0/drivers/char/tpm/tpm-sysfs.c
@@ -38,8 +38,10 @@
 
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 
+	memset(&tpm_cmd, 0, sizeof(tpm_cmd));
+
 	tpm_cmd.header.in = tpm_readpubek_header;
-	err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
+	err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0,
 			       "attempting to read the PUBEK");
 	if (err)
 		goto out;
@@ -284,16 +286,28 @@
 int tpm_sysfs_add_device(struct tpm_chip *chip)
 {
 	int err;
-	err = sysfs_create_group(&chip->pdev->kobj,
+
+	/* XXX: If you wish to remove this restriction, you must first update
+	 * tpm_sysfs to explicitly lock chip->ops.
+	 */
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		return 0;
+
+	err = sysfs_create_group(&chip->dev.parent->kobj,
 				 &tpm_dev_group);
 
 	if (err)
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"failed to create sysfs attributes, %d\n", err);
 	return err;
 }
 
 void tpm_sysfs_del_device(struct tpm_chip *chip)
 {
-	sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group);
+	/* The sysfs routines rely on an implicit tpm_try_get_ops, this
+	 * function is called before ops is null'd and the sysfs core
+	 * synchronizes this removal so that no callbacks are running or can
+	 * run again
+	 */
+	sysfs_remove_group(&chip->dev.parent->kobj, &tpm_dev_group);
 }
--- linux-4.4.0.orig/drivers/char/tpm/tpm.h
+++ linux-4.4.0/drivers/char/tpm/tpm.h
@@ -34,7 +34,7 @@
 enum tpm_const {
 	TPM_MINOR = 224,	/* officially assigned */
 	TPM_BUFSIZE = 4096,
-	TPM_NUM_DEVICES = 256,
+	TPM_NUM_DEVICES = 65536,
 	TPM_RETRY = 50,		/* 5 seconds */
 };
 
@@ -83,16 +83,20 @@
 };
 
 enum tpm2_return_codes {
-	TPM2_RC_INITIALIZE	= 0x0100,
-	TPM2_RC_TESTING		= 0x090A,
+	TPM2_RC_HASH		= 0x0083, /* RC_FMT1 */
+	TPM2_RC_INITIALIZE	= 0x0100, /* RC_VER1 */
 	TPM2_RC_DISABLED	= 0x0120,
+	TPM2_RC_TESTING		= 0x090A, /* RC_WARN */
 };
 
 enum tpm2_algorithms {
 	TPM2_ALG_SHA1		= 0x0004,
 	TPM2_ALG_KEYEDHASH	= 0x0008,
 	TPM2_ALG_SHA256		= 0x000B,
-	TPM2_ALG_NULL		= 0x0010
+	TPM2_ALG_SHA384		= 0x000C,
+	TPM2_ALG_SHA512		= 0x000D,
+	TPM2_ALG_NULL		= 0x0010,
+	TPM2_ALG_SM3_256	= 0x0012,
 };
 
 enum tpm2_command_codes {
@@ -124,13 +128,6 @@
 	TPM2_SU_STATE	= 0x0001,
 };
 
-enum tpm2_start_method {
-	TPM2_START_ACPI = 2,
-	TPM2_START_FIFO = 6,
-	TPM2_START_CRB = 7,
-	TPM2_START_CRB_WITH_ACPI = 8,
-};
-
 struct tpm_chip;
 
 struct tpm_vendor_specific {
@@ -138,7 +135,6 @@
 	unsigned long base;		/* TPM base address */
 
 	int irq;
-	int probed_irq;
 
 	int region_size;
 	int have_region;
@@ -168,14 +164,20 @@
 enum tpm_chip_flags {
 	TPM_CHIP_FLAG_REGISTERED	= BIT(0),
 	TPM_CHIP_FLAG_TPM2		= BIT(1),
+	TPM_CHIP_FLAG_ALWAYS_POWERED	= BIT(5),
 };
 
 struct tpm_chip {
-	struct device *pdev;	/* Device stuff */
 	struct device dev;
 	struct cdev cdev;
 
+	/* A driver callback under ops cannot be run unless ops_sem is held
+	 * (sometimes implicitly, eg for the sysfs code). ops becomes null
+	 * when the driver is unregistered, see tpm_try_get_ops.
+	 */
+	struct rw_semaphore ops_sem;
 	const struct tpm_class_ops *ops;
+
 	unsigned int flags;
 
 	int dev_num;		/* /dev/tpm# */
@@ -195,17 +197,10 @@
 	acpi_handle acpi_dev_handle;
 	char ppi_version[TPM_PPI_VERSION_LEN + 1];
 #endif /* CONFIG_ACPI */
-
-	struct list_head list;
 };
 
 #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
 
-static inline void tpm_chip_put(struct tpm_chip *chip)
-{
-	module_put(chip->pdev->driver->owner);
-}
-
 static inline int tpm_read_index(int base, int index)
 {
 	outb(index, base);
@@ -497,12 +492,17 @@
 extern struct class *tpm_class;
 extern dev_t tpm_devt;
 extern const struct file_operations tpm_fops;
+extern struct idr dev_nums_idr;
 
+enum tpm_transmit_flags {
+	TPM_TRANSMIT_UNLOCKED	= BIT(0),
+};
+
+ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
+		     unsigned int flags);
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len,
+			 unsigned int flags, const char *desc);
 ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
-ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
-		     size_t bufsiz);
-ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
-			 const char *desc);
 extern int tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern int tpm_do_selftest(struct tpm_chip *);
@@ -513,6 +513,9 @@
 			     wait_queue_head_t *, bool);
 
 struct tpm_chip *tpm_chip_find_get(int chip_num);
+__must_check int tpm_try_get_ops(struct tpm_chip *chip);
+void tpm_put_ops(struct tpm_chip *chip);
+
 extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
 				       const struct tpm_class_ops *ops);
 extern int tpm_chip_register(struct tpm_chip *chip);
--- linux-4.4.0.orig/drivers/char/tpm/tpm2-cmd.c
+++ linux-4.4.0/drivers/char/tpm/tpm2-cmd.c
@@ -16,10 +16,15 @@
  */
 
 #include "tpm.h"
+#include <crypto/hash_info.h>
 #include <keys/trusted-type.h>
 
 enum tpm2_object_attributes {
-	TPM2_ATTR_USER_WITH_AUTH	= BIT(6),
+	TPM2_OA_USER_WITH_AUTH		= BIT(6),
+};
+
+enum tpm2_session_attributes {
+	TPM2_SA_CONTINUE_SESSION	= BIT(0),
 };
 
 struct tpm2_startup_in {
@@ -104,6 +109,19 @@
 	union tpm2_cmd_params	params;
 } __packed;
 
+struct tpm2_hash {
+	unsigned int crypto_id;
+	unsigned int tpm_id;
+};
+
+static struct tpm2_hash tpm2_hash_map[] = {
+	{HASH_ALGO_SHA1, TPM2_ALG_SHA1},
+	{HASH_ALGO_SHA256, TPM2_ALG_SHA256},
+	{HASH_ALGO_SHA384, TPM2_ALG_SHA384},
+	{HASH_ALGO_SHA512, TPM2_ALG_SHA512},
+	{HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
+};
+
 /*
  * Array with one entry per ordinal defining the maximum amount
  * of time the chip could take to return the result. The values
@@ -264,7 +282,7 @@
 	       sizeof(cmd.params.pcrread_in.pcr_select));
 	cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
 
-	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
 			      "attempting to read a pcr value");
 	if (rc == 0) {
 		buf = cmd.params.pcrread_out.digest;
@@ -312,7 +330,7 @@
 	cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
 	memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
 
-	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
 			      "attempting extend a PCR value");
 
 	return rc;
@@ -358,7 +376,7 @@
 		cmd.header.in = tpm2_getrandom_header;
 		cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
 
-		err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+		err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
 				       "attempting get random");
 		if (err)
 			break;
@@ -416,12 +434,12 @@
 }
 
 /**
- * tpm2_seal_trusted() - seal a trusted key
- * @chip_num: A specific chip number for the request or TPM_ANY_NUM
- * @options: authentication values and other options
+ * tpm2_seal_trusted() - seal the payload of a trusted key
+ * @chip_num: TPM chip to use
  * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
  *
- * Returns < 0 on error and 0 on success.
+ * Return: < 0 on error and 0 on success.
  */
 int tpm2_seal_trusted(struct tpm_chip *chip,
 		      struct trusted_key_payload *payload,
@@ -429,8 +447,20 @@
 {
 	unsigned int blob_len;
 	struct tpm_buf buf;
+	u32 hash;
+	int i;
 	int rc;
 
+	for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
+		if (options->hash == tpm2_hash_map[i].crypto_id) {
+			hash = tpm2_hash_map[i].tpm_id;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(tpm2_hash_map))
+		return -EINVAL;
+
 	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
 	if (rc)
 		return rc;
@@ -452,12 +482,22 @@
 	tpm_buf_append_u8(&buf, payload->migratable);
 
 	/* public */
-	tpm_buf_append_u16(&buf, 14);
-
+	tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
 	tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
-	tpm_buf_append_u16(&buf, TPM2_ALG_SHA256);
-	tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
-	tpm_buf_append_u16(&buf, 0); /* policy digest size */
+	tpm_buf_append_u16(&buf, hash);
+
+	/* policy */
+	if (options->policydigest_len) {
+		tpm_buf_append_u32(&buf, 0);
+		tpm_buf_append_u16(&buf, options->policydigest_len);
+		tpm_buf_append(&buf, options->policydigest,
+			       options->policydigest_len);
+	} else {
+		tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH);
+		tpm_buf_append_u16(&buf, 0);
+	}
+
+	/* public parameters */
 	tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
 	tpm_buf_append_u16(&buf, 0);
 
@@ -472,7 +512,7 @@
 		goto out;
 	}
 
-	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "sealing data");
+	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, "sealing data");
 	if (rc)
 		goto out;
 
@@ -488,16 +528,28 @@
 out:
 	tpm_buf_destroy(&buf);
 
-	if (rc > 0)
-		rc = -EPERM;
+	if (rc > 0) {
+		if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH)
+			rc = -EINVAL;
+		else
+			rc = -EPERM;
+	}
 
 	return rc;
 }
 
-static int tpm2_load(struct tpm_chip *chip,
-		     struct trusted_key_payload *payload,
-		     struct trusted_key_options *options,
-		     u32 *blob_handle)
+/**
+ * tpm2_load_cmd() - execute a TPM2_Load command
+ * @chip_num: TPM chip to use
+ * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
+ *
+ * Return: same as with tpm_transmit_cmd
+ */
+static int tpm2_load_cmd(struct tpm_chip *chip,
+			 struct trusted_key_payload *payload,
+			 struct trusted_key_options *options,
+			 u32 *blob_handle, unsigned int flags)
 {
 	struct tpm_buf buf;
 	unsigned int private_len;
@@ -532,7 +584,7 @@
 		goto out;
 	}
 
-	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "loading blob");
+	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "loading blob");
 	if (!rc)
 		*blob_handle = be32_to_cpup(
 			(__be32 *) &buf.data[TPM_HEADER_SIZE]);
@@ -546,32 +598,50 @@
 	return rc;
 }
 
-static void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
+/**
+ * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
+ * @chip_num: TPM chip to use
+ * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
+ *
+ * Return: same as with tpm_transmit_cmd
+ */
+static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
+				   unsigned int flags)
 {
 	struct tpm_buf buf;
 	int rc;
 
 	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
 	if (rc) {
-		dev_warn(chip->pdev, "0x%08x was not flushed, out of memory\n",
+		dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
 			 handle);
 		return;
 	}
 
 	tpm_buf_append_u32(&buf, handle);
 
-	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "flushing context");
+	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags,
+			      "flushing context");
 	if (rc)
-		dev_warn(chip->pdev, "0x%08x was not flushed, rc=%d\n", handle,
+		dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle,
 			 rc);
 
 	tpm_buf_destroy(&buf);
 }
 
-static int tpm2_unseal(struct tpm_chip *chip,
-		       struct trusted_key_payload *payload,
-		       struct trusted_key_options *options,
-		       u32 blob_handle)
+/**
+ * tpm2_unseal_cmd() - execute a TPM2_Unload command
+ * @chip_num: TPM chip to use
+ * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
+ *
+ * Return: same as with tpm_transmit_cmd
+ */
+static int tpm2_unseal_cmd(struct tpm_chip *chip,
+			   struct trusted_key_payload *payload,
+			   struct trusted_key_options *options,
+			   u32 blob_handle, unsigned int flags)
 {
 	struct tpm_buf buf;
 	u16 data_len;
@@ -583,19 +653,26 @@
 		return rc;
 
 	tpm_buf_append_u32(&buf, blob_handle);
-	tpm2_buf_append_auth(&buf, TPM2_RS_PW,
+	tpm2_buf_append_auth(&buf,
+			     options->policyhandle ?
+			     options->policyhandle : TPM2_RS_PW,
 			     NULL /* nonce */, 0,
-			     0 /* session_attributes */,
+			     TPM2_SA_CONTINUE_SESSION,
 			     options->blobauth /* hmac */,
 			     TPM_DIGEST_SIZE);
 
-	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "unsealing");
+	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "unsealing");
 	if (rc > 0)
 		rc = -EPERM;
 
 	if (!rc) {
 		data_len = be16_to_cpup(
 			(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
+		if (data_len < MIN_KEY_SIZE ||  data_len > MAX_KEY_SIZE + 1) {
+			rc = -EFAULT;
+			goto out;
+		}
+
 		data = &buf.data[TPM_HEADER_SIZE + 6];
 
 		memcpy(payload->key, data, data_len - 1);
@@ -603,17 +680,18 @@
 		payload->migratable = data[data_len - 1];
 	}
 
+out:
 	tpm_buf_destroy(&buf);
 	return rc;
 }
 
 /**
- * tpm_unseal_trusted() - unseal a trusted key
- * @chip_num: A specific chip number for the request or TPM_ANY_NUM
- * @options: authentication values and other options
+ * tpm_unseal_trusted() - unseal the payload of a trusted key
+ * @chip_num: TPM chip to use
  * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
  *
- * Returns < 0 on error and 0 on success.
+ * Return: < 0 on error and 0 on success.
  */
 int tpm2_unseal_trusted(struct tpm_chip *chip,
 			struct trusted_key_payload *payload,
@@ -622,14 +700,17 @@
 	u32 blob_handle;
 	int rc;
 
-	rc = tpm2_load(chip, payload, options, &blob_handle);
+	mutex_lock(&chip->tpm_mutex);
+	rc = tpm2_load_cmd(chip, payload, options, &blob_handle,
+			   TPM_TRANSMIT_UNLOCKED);
 	if (rc)
-		return rc;
-
-	rc = tpm2_unseal(chip, payload, options, blob_handle);
-
-	tpm2_flush_context(chip, blob_handle);
+		goto out;
 
+	rc = tpm2_unseal_cmd(chip, payload, options, blob_handle,
+			     TPM_TRANSMIT_UNLOCKED);
+	tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED);
+out:
+	mutex_unlock(&chip->tpm_mutex);
 	return rc;
 }
 
@@ -655,9 +736,9 @@
 	cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
 	cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
 
-	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc);
+	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, desc);
 	if (!rc)
-		*value = cmd.params.get_tpm_pt_out.value;
+		*value = be32_to_cpu(cmd.params.get_tpm_pt_out.value);
 
 	return rc;
 }
@@ -689,7 +770,7 @@
 	cmd.header.in = tpm2_startup_header;
 
 	cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
-	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
 				"attempting to start the TPM");
 }
 EXPORT_SYMBOL_GPL(tpm2_startup);
@@ -718,13 +799,13 @@
 	cmd.header.in = tpm2_shutdown_header;
 	cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
 
-	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "stopping the TPM");
+	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "stopping the TPM");
 
 	/* In places where shutdown command is sent there's no much we can do
 	 * except print the error code on a system failure.
 	 */
 	if (rc < 0)
-		dev_warn(chip->pdev, "transmit returned %d while stopping the TPM",
+		dev_warn(&chip->dev, "transmit returned %d while stopping the TPM",
 			 rc);
 }
 EXPORT_SYMBOL_GPL(tpm2_shutdown);
@@ -784,14 +865,14 @@
 	cmd.header.in = tpm2_selftest_header;
 	cmd.params.selftest_in.full_test = full;
 
-	rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE,
+	rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0,
 			      "continue selftest");
 
 	/* At least some prototype chips seem to give RC_TESTING error
 	 * immediately. This is a workaround for that.
 	 */
 	if (rc == TPM2_RC_TESTING) {
-		dev_warn(chip->pdev, "Got RC_TESTING, ignoring\n");
+		dev_warn(&chip->dev, "Got RC_TESTING, ignoring\n");
 		rc = 0;
 	}
 
@@ -836,7 +917,7 @@
 		cmd.params.pcrread_in.pcr_select[1] = 0x00;
 		cmd.params.pcrread_in.pcr_select[2] = 0x00;
 
-		rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL);
+		rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL);
 		if (rc < 0)
 			break;
 
@@ -885,7 +966,7 @@
 	cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
 	cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
 
-	rc = tpm_transmit(chip, (const char *) &cmd, sizeof(cmd));
+	rc = tpm_transmit(chip, (const u8 *)&cmd, sizeof(cmd), 0);
 	if (rc <  0)
 		return rc;
 	else if (rc < TPM_HEADER_SIZE)
--- linux-4.4.0.orig/drivers/char/tpm/tpm_atmel.c
+++ linux-4.4.0/drivers/char/tpm/tpm_atmel.c
@@ -49,7 +49,7 @@
 	for (i = 0; i < 6; i++) {
 		status = ioread8(chip->vendor.iobase + 1);
 		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
-			dev_err(chip->pdev, "error reading header\n");
+			dev_err(&chip->dev, "error reading header\n");
 			return -EIO;
 		}
 		*buf++ = ioread8(chip->vendor.iobase);
@@ -60,12 +60,12 @@
 	size = be32_to_cpu(*native_size);
 
 	if (count < size) {
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"Recv size(%d) less than available space\n", size);
 		for (; i < size; i++) {	/* clear the waiting data anyway */
 			status = ioread8(chip->vendor.iobase + 1);
 			if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
-				dev_err(chip->pdev, "error reading data\n");
+				dev_err(&chip->dev, "error reading data\n");
 				return -EIO;
 			}
 		}
@@ -76,7 +76,7 @@
 	for (; i < size; i++) {
 		status = ioread8(chip->vendor.iobase + 1);
 		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
-			dev_err(chip->pdev, "error reading data\n");
+			dev_err(&chip->dev, "error reading data\n");
 			return -EIO;
 		}
 		*buf++ = ioread8(chip->vendor.iobase);
@@ -86,7 +86,7 @@
 	status = ioread8(chip->vendor.iobase + 1);
 
 	if (status & ATML_STATUS_DATA_AVAIL) {
-		dev_err(chip->pdev, "data available is stuck\n");
+		dev_err(&chip->dev, "data available is stuck\n");
 		return -EIO;
 	}
 
@@ -97,9 +97,9 @@
 {
 	int i;
 
-	dev_dbg(chip->pdev, "tpm_atml_send:\n");
+	dev_dbg(&chip->dev, "tpm_atml_send:\n");
 	for (i = 0; i < count; i++) {
-		dev_dbg(chip->pdev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
+		dev_dbg(&chip->dev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
  		iowrite8(buf[i], chip->vendor.iobase);
 	}
 
--- linux-4.4.0.orig/drivers/char/tpm/tpm_crb.c
+++ linux-4.4.0/drivers/char/tpm/tpm_crb.c
@@ -34,14 +34,6 @@
 	CRB_ACPI_START_INDEX = 1,
 };
 
-struct acpi_tpm2 {
-	struct acpi_table_header hdr;
-	u16 platform_class;
-	u16 reserved;
-	u64 control_area_pa;
-	u32 start_method;
-} __packed;
-
 enum crb_ca_request {
 	CRB_CA_REQ_GO_IDLE	= BIT(0),
 	CRB_CA_REQ_CMD_READY	= BIT(1),
@@ -85,6 +77,7 @@
 
 struct crb_priv {
 	unsigned int flags;
+	void __iomem *iobase;
 	struct crb_control_area __iomem *cca;
 	u8 __iomem *cmd;
 	u8 __iomem *rsp;
@@ -97,7 +90,7 @@
 	struct crb_priv *priv = chip->vendor.priv;
 	u8 sts = 0;
 
-	if ((le32_to_cpu(ioread32(&priv->cca->start)) & CRB_START_INVOKE) !=
+	if ((ioread32(&priv->cca->start) & CRB_START_INVOKE) !=
 	    CRB_START_INVOKE)
 		sts |= CRB_STS_COMPLETE;
 
@@ -109,20 +102,29 @@
 	struct crb_priv *priv = chip->vendor.priv;
 	unsigned int expected;
 
-	/* sanity check */
-	if (count < 6)
+	/* A sanity check that the upper layer wants to get at least the header
+	 * as that is the minimum size for any TPM response.
+	 */
+	if (count < TPM_HEADER_SIZE)
 		return -EIO;
 
-	if (le32_to_cpu(ioread32(&priv->cca->sts)) & CRB_CA_STS_ERROR)
+	/* If this bit is set, according to the spec, the TPM is in
+	 * unrecoverable condition.
+	 */
+	if (ioread32(&priv->cca->sts) & CRB_CA_STS_ERROR)
 		return -EIO;
 
-	memcpy_fromio(buf, priv->rsp, 6);
-	expected = be32_to_cpup((__be32 *) &buf[2]);
+	/* Read the first 8 bytes in order to get the length of the response.
+	 * We read exactly a quad word in order to make sure that the remaining
+	 * reads will be aligned.
+	 */
+	memcpy_fromio(buf, priv->rsp, 8);
 
-	if (expected > count)
+	expected = be32_to_cpup((__be32 *)&buf[2]);
+	if (expected > count || expected < TPM_HEADER_SIZE)
 		return -EIO;
 
-	memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
+	memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8);
 
 	return expected;
 }
@@ -149,11 +151,16 @@
 	struct crb_priv *priv = chip->vendor.priv;
 	int rc = 0;
 
-	if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) {
+	/* Zero the cancel register so that the next command will not get
+	 * canceled.
+	 */
+	iowrite32(0, &priv->cca->cancel);
+
+	if (len > ioread32(&priv->cca->cmd_size)) {
 		dev_err(&chip->dev,
 			"invalid command count value %x %zx\n",
 			(unsigned int) len,
-			(size_t) le32_to_cpu(ioread32(&priv->cca->cmd_size)));
+			(size_t) ioread32(&priv->cca->cmd_size));
 		return -E2BIG;
 	}
 
@@ -182,14 +189,12 @@
 
 	if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip))
 		dev_err(&chip->dev, "ACPI Start failed\n");
-
-	iowrite32(0, &priv->cca->cancel);
 }
 
 static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
 {
 	struct crb_priv *priv = chip->vendor.priv;
-	u32 cancel = le32_to_cpu(ioread32(&priv->cca->cancel));
+	u32 cancel = ioread32(&priv->cca->cancel);
 
 	return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE;
 }
@@ -204,105 +209,166 @@
 	.req_complete_val = CRB_STS_COMPLETE,
 };
 
-static int crb_acpi_add(struct acpi_device *device)
+static int crb_init(struct acpi_device *device, struct crb_priv *priv)
 {
 	struct tpm_chip *chip;
-	struct acpi_tpm2 *buf;
+	int rc;
+
+	chip = tpmm_chip_alloc(&device->dev, &tpm_crb);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+
+	chip->vendor.priv = priv;
+	chip->acpi_dev_handle = device->handle;
+	chip->flags = TPM_CHIP_FLAG_TPM2;
+
+	rc = tpm_get_timeouts(chip);
+	if (rc)
+		return rc;
+
+	rc = tpm2_do_selftest(chip);
+	if (rc)
+		return rc;
+
+	return tpm_chip_register(chip);
+}
+
+static int crb_check_resource(struct acpi_resource *ares, void *data)
+{
+	struct resource *io_res = data;
+	struct resource res;
+
+	if (acpi_dev_resource_memory(ares, &res)) {
+		*io_res = res;
+		io_res->name = NULL;
+	}
+
+	return 1;
+}
+
+static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv,
+				 struct resource *io_res, u64 start, u32 size)
+{
+	struct resource new_res = {
+		.start	= start,
+		.end	= start + size - 1,
+		.flags	= IORESOURCE_MEM,
+	};
+
+	/* Detect a 64 bit address on a 32 bit system */
+	if (start != new_res.start)
+		return ERR_PTR(-EINVAL);
+
+	if (!resource_contains(io_res, &new_res))
+		return devm_ioremap_resource(dev, &new_res);
+
+	return priv->iobase + (new_res.start - io_res->start);
+}
+
+static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
+		      struct acpi_table_tpm2 *buf)
+{
+	struct list_head resources;
+	struct resource io_res;
+	struct device *dev = &device->dev;
+	u64 cmd_pa;
+	u32 cmd_size;
+	u64 rsp_pa;
+	u32 rsp_size;
+	int ret;
+
+	INIT_LIST_HEAD(&resources);
+	ret = acpi_dev_get_resources(device, &resources, crb_check_resource,
+				     &io_res);
+	if (ret < 0)
+		return ret;
+	acpi_dev_free_resource_list(&resources);
+
+	if (resource_type(&io_res) != IORESOURCE_MEM) {
+		dev_err(dev,
+			FW_BUG "TPM2 ACPI table does not define a memory resource\n");
+		return -EINVAL;
+	}
+
+	priv->iobase = devm_ioremap_resource(dev, &io_res);
+	if (IS_ERR(priv->iobase))
+		return PTR_ERR(priv->iobase);
+
+	priv->cca = crb_map_res(dev, priv, &io_res, buf->control_address,
+				sizeof(struct crb_control_area));
+	if (IS_ERR(priv->cca))
+		return PTR_ERR(priv->cca);
+
+	cmd_pa = ((u64) ioread32(&priv->cca->cmd_pa_high) << 32) |
+		  (u64) ioread32(&priv->cca->cmd_pa_low);
+	cmd_size = ioread32(&priv->cca->cmd_size);
+	priv->cmd = crb_map_res(dev, priv, &io_res, cmd_pa, cmd_size);
+	if (IS_ERR(priv->cmd))
+		return PTR_ERR(priv->cmd);
+
+	memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8);
+	rsp_pa = le64_to_cpu(rsp_pa);
+	rsp_size = ioread32(&priv->cca->rsp_size);
+
+	if (cmd_pa != rsp_pa) {
+		priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size);
+		return PTR_ERR_OR_ZERO(priv->rsp);
+	}
+
+	/* According to the PTP specification, overlapping command and response
+	 * buffer sizes must be identical.
+	 */
+	if (cmd_size != rsp_size) {
+		dev_err(dev, FW_BUG "overlapping command and response buffer sizes are not identical");
+		return -EINVAL;
+	}
+
+	priv->rsp = priv->cmd;
+	return 0;
+}
+
+static int crb_acpi_add(struct acpi_device *device)
+{
+	struct acpi_table_tpm2 *buf;
 	struct crb_priv *priv;
 	struct device *dev = &device->dev;
 	acpi_status status;
 	u32 sm;
-	u64 pa;
 	int rc;
 
 	status = acpi_get_table(ACPI_SIG_TPM2, 1,
 				(struct acpi_table_header **) &buf);
-	if (ACPI_FAILURE(status)) {
-		dev_err(dev, "failed to get TPM2 ACPI table\n");
-		return -ENODEV;
+	if (ACPI_FAILURE(status) || buf->header.length < sizeof(*buf)) {
+		dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n");
+		return -EINVAL;
 	}
 
 	/* Should the FIFO driver handle this? */
-	if (buf->start_method == TPM2_START_FIFO)
+	sm = buf->start_method;
+	if (sm == ACPI_TPM2_MEMORY_MAPPED)
 		return -ENODEV;
 
-	chip = tpmm_chip_alloc(dev, &tpm_crb);
-	if (IS_ERR(chip))
-		return PTR_ERR(chip);
-
-	chip->flags = TPM_CHIP_FLAG_TPM2;
-
-	if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
-		dev_err(dev, "TPM2 ACPI table has wrong size");
-		return -EINVAL;
-	}
-
-	priv = (struct crb_priv *) devm_kzalloc(dev, sizeof(struct crb_priv),
-						GFP_KERNEL);
-	if (!priv) {
-		dev_err(dev, "failed to devm_kzalloc for private data\n");
+	priv = devm_kzalloc(dev, sizeof(struct crb_priv), GFP_KERNEL);
+	if (!priv)
 		return -ENOMEM;
-	}
-
-	sm = le32_to_cpu(buf->start_method);
 
 	/* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
 	 * report only ACPI start but in practice seems to require both
 	 * ACPI start and CRB start.
 	 */
-	if (sm == TPM2_START_CRB || sm == TPM2_START_FIFO ||
+	if (sm == ACPI_TPM2_COMMAND_BUFFER || sm == ACPI_TPM2_MEMORY_MAPPED ||
 	    !strcmp(acpi_device_hid(device), "MSFT0101"))
 		priv->flags |= CRB_FL_CRB_START;
 
-	if (sm == TPM2_START_ACPI || sm == TPM2_START_CRB_WITH_ACPI)
+	if (sm == ACPI_TPM2_START_METHOD ||
+	    sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
 		priv->flags |= CRB_FL_ACPI_START;
 
-	priv->cca = (struct crb_control_area __iomem *)
-		devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
-	if (!priv->cca) {
-		dev_err(dev, "ioremap of the control area failed\n");
-		return -ENOMEM;
-	}
-
-	pa = ((u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_high)) << 32) |
-		(u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_low));
-	priv->cmd = devm_ioremap_nocache(dev, pa,
-					 ioread32(&priv->cca->cmd_size));
-	if (!priv->cmd) {
-		dev_err(dev, "ioremap of the command buffer failed\n");
-		return -ENOMEM;
-	}
-
-	memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
-	pa = le64_to_cpu(pa);
-	priv->rsp = devm_ioremap_nocache(dev, pa,
-					 ioread32(&priv->cca->rsp_size));
-	if (!priv->rsp) {
-		dev_err(dev, "ioremap of the response buffer failed\n");
-		return -ENOMEM;
-	}
-
-	chip->vendor.priv = priv;
-
-	/* Default timeouts and durations */
-	chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
-	chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
-	chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
-	chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
-	chip->vendor.duration[TPM_SHORT] =
-		msecs_to_jiffies(TPM2_DURATION_SHORT);
-	chip->vendor.duration[TPM_MEDIUM] =
-		msecs_to_jiffies(TPM2_DURATION_MEDIUM);
-	chip->vendor.duration[TPM_LONG] =
-		msecs_to_jiffies(TPM2_DURATION_LONG);
-
-	chip->acpi_dev_handle = device->handle;
-
-	rc = tpm2_do_selftest(chip);
+	rc = crb_map_io(device, priv, buf);
 	if (rc)
 		return rc;
 
-	return tpm_chip_register(chip);
+	return crb_init(device, priv);
 }
 
 static int crb_acpi_remove(struct acpi_device *device)
@@ -310,11 +376,11 @@
 	struct device *dev = &device->dev;
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 
-	tpm_chip_unregister(chip);
-
 	if (chip->flags & TPM_CHIP_FLAG_TPM2)
 		tpm2_shutdown(chip, TPM2_SU_CLEAR);
 
+	tpm_chip_unregister(chip);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/char/tpm/tpm_eventlog.c
+++ linux-4.4.0/drivers/char/tpm/tpm_eventlog.c
@@ -232,7 +232,7 @@
 {
 	struct tcpa_event *event = v;
 	struct tcpa_event temp_event;
-	char *tempPtr;
+	char *temp_ptr;
 	int i;
 
 	memcpy(&temp_event, event, sizeof(struct tcpa_event));
@@ -242,10 +242,16 @@
 	temp_event.event_type = do_endian_conversion(event->event_type);
 	temp_event.event_size = do_endian_conversion(event->event_size);
 
-	tempPtr = (char *)&temp_event;
+	temp_ptr = (char *) &temp_event;
 
-	for (i = 0; i < sizeof(struct tcpa_event) + temp_event.event_size; i++)
-		seq_putc(m, tempPtr[i]);
+	for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
+		seq_putc(m, temp_ptr[i]);
+
+	temp_ptr = (char *) v;
+
+	for (i = (sizeof(struct tcpa_event) - 1);
+	     i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
+		seq_putc(m, temp_ptr[i]);
 
 	return 0;
 
--- linux-4.4.0.orig/drivers/char/tpm/tpm_i2c_atmel.c
+++ linux-4.4.0/drivers/char/tpm/tpm_i2c_atmel.c
@@ -52,7 +52,7 @@
 static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
 {
 	struct priv_data *priv = chip->vendor.priv;
-	struct i2c_client *client = to_i2c_client(chip->pdev);
+	struct i2c_client *client = to_i2c_client(chip->dev.parent);
 	s32 status;
 
 	priv->len = 0;
@@ -62,16 +62,24 @@
 
 	status = i2c_master_send(client, buf, len);
 
-	dev_dbg(chip->pdev,
+	dev_dbg(&chip->dev,
 		"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
 		(int)min_t(size_t, 64, len), buf, len, status);
-	return status;
+
+	if (status < 0)
+		return status;
+
+	/* The upper layer does not support incomplete sends. */
+	if (status != len)
+		return -E2BIG;
+
+	return 0;
 }
 
 static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 	struct priv_data *priv = chip->vendor.priv;
-	struct i2c_client *client = to_i2c_client(chip->pdev);
+	struct i2c_client *client = to_i2c_client(chip->dev.parent);
 	struct tpm_output_header *hdr =
 		(struct tpm_output_header *)priv->buffer;
 	u32 expected_len;
@@ -88,7 +96,7 @@
 		return -ENOMEM;
 
 	if (priv->len >= expected_len) {
-		dev_dbg(chip->pdev,
+		dev_dbg(&chip->dev,
 			"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
 			(int)min_t(size_t, 64, expected_len), buf, count,
 			expected_len);
@@ -97,7 +105,7 @@
 	}
 
 	rc = i2c_master_recv(client, buf, expected_len);
-	dev_dbg(chip->pdev,
+	dev_dbg(&chip->dev,
 		"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
 		(int)min_t(size_t, 64, expected_len), buf, count,
 		expected_len);
@@ -106,13 +114,13 @@
 
 static void i2c_atmel_cancel(struct tpm_chip *chip)
 {
-	dev_err(chip->pdev, "TPM operation cancellation was requested, but is not supported");
+	dev_err(&chip->dev, "TPM operation cancellation was requested, but is not supported");
 }
 
 static u8 i2c_atmel_read_status(struct tpm_chip *chip)
 {
 	struct priv_data *priv = chip->vendor.priv;
-	struct i2c_client *client = to_i2c_client(chip->pdev);
+	struct i2c_client *client = to_i2c_client(chip->dev.parent);
 	int rc;
 
 	/* The TPM fails the I2C read until it is ready, so we do the entire
@@ -125,7 +133,7 @@
 	/* Once the TPM has completed the command the command remains readable
 	 * until another command is issued. */
 	rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
-	dev_dbg(chip->pdev,
+	dev_dbg(&chip->dev,
 		"%s: sts=%d", __func__, rc);
 	if (rc <= 0)
 		return 0;
--- linux-4.4.0.orig/drivers/char/tpm/tpm_i2c_infineon.c
+++ linux-4.4.0/drivers/char/tpm/tpm_i2c_infineon.c
@@ -436,7 +436,8 @@
 static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 	int size = 0;
-	int expected, status;
+	int status;
+	u32 expected;
 
 	if (count < TPM_HEADER_SIZE) {
 		size = -EIO;
@@ -446,12 +447,12 @@
 	/* read first 10 bytes, including tag, paramsize, and result */
 	size = recv_data(chip, buf, TPM_HEADER_SIZE);
 	if (size < TPM_HEADER_SIZE) {
-		dev_err(chip->pdev, "Unable to read header\n");
+		dev_err(&chip->dev, "Unable to read header\n");
 		goto out;
 	}
 
 	expected = be32_to_cpu(*(__be32 *)(buf + 2));
-	if ((size_t) expected > count) {
+	if (((size_t) expected > count) || (expected < TPM_HEADER_SIZE)) {
 		size = -EIO;
 		goto out;
 	}
@@ -459,14 +460,14 @@
 	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
 			  expected - TPM_HEADER_SIZE);
 	if (size < expected) {
-		dev_err(chip->pdev, "Unable to read remainder of result\n");
+		dev_err(&chip->dev, "Unable to read remainder of result\n");
 		size = -ETIME;
 		goto out;
 	}
 
 	wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
 	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
-		dev_err(chip->pdev, "Error left over data\n");
+		dev_err(&chip->dev, "Error left over data\n");
 		size = -EIO;
 		goto out;
 	}
--- linux-4.4.0.orig/drivers/char/tpm/tpm_i2c_nuvoton.c
+++ linux-4.4.0/drivers/char/tpm/tpm_i2c_nuvoton.c
@@ -96,13 +96,13 @@
 /* read TPM_STS register */
 static u8 i2c_nuvoton_read_status(struct tpm_chip *chip)
 {
-	struct i2c_client *client = to_i2c_client(chip->pdev);
+	struct i2c_client *client = to_i2c_client(chip->dev.parent);
 	s32 status;
 	u8 data;
 
 	status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data);
 	if (status <= 0) {
-		dev_err(chip->pdev, "%s() error return %d\n", __func__,
+		dev_err(&chip->dev, "%s() error return %d\n", __func__,
 			status);
 		data = TPM_STS_ERR_VAL;
 	}
@@ -127,13 +127,13 @@
 /* write commandReady to TPM_STS register */
 static void i2c_nuvoton_ready(struct tpm_chip *chip)
 {
-	struct i2c_client *client = to_i2c_client(chip->pdev);
+	struct i2c_client *client = to_i2c_client(chip->dev.parent);
 	s32 status;
 
 	/* this causes the current command to be aborted */
 	status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY);
 	if (status < 0)
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"%s() fail to write TPM_STS.commandReady\n", __func__);
 }
 
@@ -212,7 +212,7 @@
 				return 0;
 		} while (time_before(jiffies, stop));
 	}
-	dev_err(chip->pdev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
+	dev_err(&chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
 		value);
 	return -ETIMEDOUT;
 }
@@ -240,7 +240,7 @@
 					       &chip->vendor.read_queue) == 0) {
 		burst_count = i2c_nuvoton_get_burstcount(client, chip);
 		if (burst_count < 0) {
-			dev_err(chip->pdev,
+			dev_err(&chip->dev,
 				"%s() fail to read burstCount=%d\n", __func__,
 				burst_count);
 			return -EIO;
@@ -249,12 +249,12 @@
 		rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R,
 					  bytes2read, &buf[size]);
 		if (rc < 0) {
-			dev_err(chip->pdev,
+			dev_err(&chip->dev,
 				"%s() fail on i2c_nuvoton_read_buf()=%d\n",
 				__func__, rc);
 			return -EIO;
 		}
-		dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read);
+		dev_dbg(&chip->dev, "%s(%d):", __func__, bytes2read);
 		size += bytes2read;
 	}
 
@@ -264,10 +264,14 @@
 /* Read TPM command results */
 static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
-	struct device *dev = chip->pdev;
+	struct device *dev = chip->dev.parent;
 	struct i2c_client *client = to_i2c_client(dev);
 	s32 rc;
-	int expected, status, burst_count, retries, size = 0;
+	int status;
+	int burst_count;
+	int retries;
+	int size = 0;
+	u32 expected;
 
 	if (count < TPM_HEADER_SIZE) {
 		i2c_nuvoton_ready(chip);    /* return to idle */
@@ -309,7 +313,7 @@
 		 * to machine native
 		 */
 		expected = be32_to_cpu(*(__be32 *) (buf + 2));
-		if (expected > count) {
+		if (expected > count || expected < size) {
 			dev_err(dev, "%s() expected > count\n", __func__);
 			size = -EIO;
 			continue;
@@ -334,7 +338,7 @@
 		break;
 	}
 	i2c_nuvoton_ready(chip);
-	dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size);
+	dev_dbg(&chip->dev, "%s() -> %d\n", __func__, size);
 	return size;
 }
 
@@ -347,7 +351,7 @@
  */
 static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
 {
-	struct device *dev = chip->pdev;
+	struct device *dev = chip->dev.parent;
 	struct i2c_client *client = to_i2c_client(dev);
 	u32 ordinal;
 	size_t count = 0;
--- linux-4.4.0.orig/drivers/char/tpm/tpm_ibmvtpm.c
+++ linux-4.4.0/drivers/char/tpm/tpm_ibmvtpm.c
@@ -90,7 +90,7 @@
 		return 0;
 	}
 
-	sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0);
+	sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
 	if (sig)
 		return -EINTR;
 
@@ -125,7 +125,7 @@
 	struct ibmvtpm_dev *ibmvtpm;
 	struct ibmvtpm_crq crq;
 	__be64 *word = (__be64 *)&crq;
-	int rc;
+	int rc, sig;
 
 	ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
 
@@ -141,18 +141,35 @@
 		return -EIO;
 	}
 
+	if (ibmvtpm->tpm_processing_cmd) {
+		dev_info(ibmvtpm->dev,
+		         "Need to wait for TPM to finish\n");
+		/* wait for previous command to finish */
+		sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
+		if (sig)
+			return -EINTR;
+	}
+
 	spin_lock(&ibmvtpm->rtce_lock);
+	ibmvtpm->res_len = 0;
 	memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
 	crq.valid = (u8)IBMVTPM_VALID_CMD;
 	crq.msg = (u8)VTPM_TPM_COMMAND;
 	crq.len = cpu_to_be16(count);
 	crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
 
+	/*
+	 * set the processing flag before the Hcall, since we may get the
+	 * result (interrupt) before even being able to check rc.
+	 */
+	ibmvtpm->tpm_processing_cmd = true;
+
 	rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]),
 			      be64_to_cpu(word[1]));
 	if (rc != H_SUCCESS) {
 		dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
 		rc = 0;
+		ibmvtpm->tpm_processing_cmd = false;
 	} else
 		rc = count;
 
@@ -515,6 +532,7 @@
 		case VTPM_TPM_COMMAND_RES:
 			/* len of the data in rtce buffer */
 			ibmvtpm->res_len = be16_to_cpu(crq->len);
+			ibmvtpm->tpm_processing_cmd = false;
 			wake_up_interruptible(&ibmvtpm->wq);
 			return;
 		default:
@@ -543,6 +561,7 @@
 	 */
 	while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
 		ibmvtpm_crq_process(crq, ibmvtpm);
+		wake_up_interruptible(&ibmvtpm->crq_queue.wq);
 		crq->valid = 0;
 		smp_wmb();
 	}
@@ -589,6 +608,7 @@
 	}
 
 	crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr);
+	init_waitqueue_head(&crq_q->wq);
 	ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr,
 						 CRQ_RES_BUF_SIZE,
 						 DMA_BIDIRECTIONAL);
@@ -641,6 +661,13 @@
 	if (rc)
 		goto init_irq_cleanup;
 
+	if (!wait_event_timeout(ibmvtpm->crq_queue.wq,
+				ibmvtpm->rtce_buf != NULL,
+				HZ)) {
+		dev_err(dev, "CRQ response timed out\n");
+		goto init_irq_cleanup;
+	}
+
 	return tpm_chip_register(chip);
 init_irq_cleanup:
 	do {
--- linux-4.4.0.orig/drivers/char/tpm/tpm_ibmvtpm.h
+++ linux-4.4.0/drivers/char/tpm/tpm_ibmvtpm.h
@@ -31,6 +31,7 @@
 	struct ibmvtpm_crq *crq_addr;
 	u32 index;
 	u32 num_entry;
+	wait_queue_head_t wq;
 };
 
 struct ibmvtpm_dev {
@@ -45,6 +46,7 @@
 	wait_queue_head_t wq;
 	u16 res_len;
 	u32 vtpm_version;
+	bool tpm_processing_cmd;
 };
 
 #define CRQ_RES_BUF_SIZE	PAGE_SIZE
--- linux-4.4.0.orig/drivers/char/tpm/tpm_infineon.c
+++ linux-4.4.0/drivers/char/tpm/tpm_infineon.c
@@ -195,9 +195,9 @@
 	}
 	if (i == TPM_MAX_TRIES) {	/* timeout occurs */
 		if (wait_for_bit == STAT_XFE)
-			dev_err(chip->pdev, "Timeout in wait(STAT_XFE)\n");
+			dev_err(&chip->dev, "Timeout in wait(STAT_XFE)\n");
 		if (wait_for_bit == STAT_RDA)
-			dev_err(chip->pdev, "Timeout in wait(STAT_RDA)\n");
+			dev_err(&chip->dev, "Timeout in wait(STAT_RDA)\n");
 		return -EIO;
 	}
 	return 0;
@@ -220,7 +220,7 @@
 static void tpm_wtx(struct tpm_chip *chip)
 {
 	number_of_wtx++;
-	dev_info(chip->pdev, "Granting WTX (%02d / %02d)\n",
+	dev_info(&chip->dev, "Granting WTX (%02d / %02d)\n",
 		 number_of_wtx, TPM_MAX_WTX_PACKAGES);
 	wait_and_send(chip, TPM_VL_VER);
 	wait_and_send(chip, TPM_CTRL_WTX);
@@ -231,7 +231,7 @@
 
 static void tpm_wtx_abort(struct tpm_chip *chip)
 {
-	dev_info(chip->pdev, "Aborting WTX\n");
+	dev_info(&chip->dev, "Aborting WTX\n");
 	wait_and_send(chip, TPM_VL_VER);
 	wait_and_send(chip, TPM_CTRL_WTX_ABORT);
 	wait_and_send(chip, 0x00);
@@ -257,7 +257,7 @@
 	}
 
 	if (buf[0] != TPM_VL_VER) {
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"Wrong transport protocol implementation!\n");
 		return -EIO;
 	}
@@ -272,7 +272,7 @@
 		}
 
 		if ((size == 0x6D00) && (buf[1] == 0x80)) {
-			dev_err(chip->pdev, "Error handling on vendor layer!\n");
+			dev_err(&chip->dev, "Error handling on vendor layer!\n");
 			return -EIO;
 		}
 
@@ -284,7 +284,7 @@
 	}
 
 	if (buf[1] == TPM_CTRL_WTX) {
-		dev_info(chip->pdev, "WTX-package received\n");
+		dev_info(&chip->dev, "WTX-package received\n");
 		if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
 			tpm_wtx(chip);
 			goto recv_begin;
@@ -295,14 +295,14 @@
 	}
 
 	if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
-		dev_info(chip->pdev, "WTX-abort acknowledged\n");
+		dev_info(&chip->dev, "WTX-abort acknowledged\n");
 		return size;
 	}
 
 	if (buf[1] == TPM_CTRL_ERROR) {
-		dev_err(chip->pdev, "ERROR-package received:\n");
+		dev_err(&chip->dev, "ERROR-package received:\n");
 		if (buf[4] == TPM_INF_NAK)
-			dev_err(chip->pdev,
+			dev_err(&chip->dev,
 				"-> Negative acknowledgement"
 				" - retransmit command!\n");
 		return -EIO;
@@ -321,7 +321,7 @@
 
 	ret = empty_fifo(chip, 1);
 	if (ret) {
-		dev_err(chip->pdev, "Timeout while clearing FIFO\n");
+		dev_err(&chip->dev, "Timeout while clearing FIFO\n");
 		return -EIO;
 	}
 
--- linux-4.4.0.orig/drivers/char/tpm/tpm_nsc.c
+++ linux-4.4.0/drivers/char/tpm/tpm_nsc.c
@@ -113,7 +113,7 @@
 	}
 	while (time_before(jiffies, stop));
 
-	dev_info(chip->pdev, "wait for ready failed\n");
+	dev_info(&chip->dev, "wait for ready failed\n");
 	return -EBUSY;
 }
 
@@ -129,12 +129,12 @@
 		return -EIO;
 
 	if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
-		dev_err(chip->pdev, "F0 timeout\n");
+		dev_err(&chip->dev, "F0 timeout\n");
 		return -EIO;
 	}
 	if ((data =
 	     inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
-		dev_err(chip->pdev, "not in normal mode (0x%x)\n",
+		dev_err(&chip->dev, "not in normal mode (0x%x)\n",
 			data);
 		return -EIO;
 	}
@@ -143,7 +143,7 @@
 	for (p = buffer; p < &buffer[count]; p++) {
 		if (wait_for_stat
 		    (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
-			dev_err(chip->pdev,
+			dev_err(&chip->dev,
 				"OBF timeout (while reading data)\n");
 			return -EIO;
 		}
@@ -154,11 +154,11 @@
 
 	if ((data & NSC_STATUS_F0) == 0 &&
 	(wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
-		dev_err(chip->pdev, "F0 not set\n");
+		dev_err(&chip->dev, "F0 not set\n");
 		return -EIO;
 	}
 	if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
-		dev_err(chip->pdev,
+		dev_err(&chip->dev,
 			"expected end of command(0x%x)\n", data);
 		return -EIO;
 	}
@@ -189,19 +189,19 @@
 		return -EIO;
 
 	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
-		dev_err(chip->pdev, "IBF timeout\n");
+		dev_err(&chip->dev, "IBF timeout\n");
 		return -EIO;
 	}
 
 	outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
 	if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
-		dev_err(chip->pdev, "IBR timeout\n");
+		dev_err(&chip->dev, "IBR timeout\n");
 		return -EIO;
 	}
 
 	for (i = 0; i < count; i++) {
 		if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
-			dev_err(chip->pdev,
+			dev_err(&chip->dev,
 				"IBF timeout (while writing data)\n");
 			return -EIO;
 		}
@@ -209,7 +209,7 @@
 	}
 
 	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
-		dev_err(chip->pdev, "IBF timeout\n");
+		dev_err(&chip->dev, "IBF timeout\n");
 		return -EIO;
 	}
 	outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
--- linux-4.4.0.orig/drivers/char/tpm/tpm_tis.c
+++ linux-4.4.0/drivers/char/tpm/tpm_tis.c
@@ -28,7 +28,6 @@
 #include <linux/wait.h>
 #include <linux/acpi.h>
 #include <linux/freezer.h>
-#include <acpi/actbl2.h>
 #include "tpm.h"
 
 enum tis_access {
@@ -60,22 +59,18 @@
 };
 
 enum tis_defaults {
-	TIS_MEM_BASE = 0xFED40000,
 	TIS_MEM_LEN = 0x5000,
 	TIS_SHORT_TIMEOUT = 750,	/* ms */
 	TIS_LONG_TIMEOUT = 2000,	/* 2 sec */
 };
 
 struct tpm_info {
-	unsigned long start;
-	unsigned long len;
-	unsigned int irq;
-};
-
-static struct tpm_info tis_default_info = {
-	.start = TIS_MEM_BASE,
-	.len = TIS_MEM_LEN,
-	.irq = 0,
+	struct resource res;
+	/* irq > 0 means: use irq $irq;
+	 * irq = 0 means: autoprobe for an irq;
+	 * irq = -1 means: no irq support
+	 */
+	int irq;
 };
 
 /* Some timeout values are needed before it is known whether the chip is
@@ -118,39 +113,11 @@
 {
 	return has_hid(dev, "INTC0102");
 }
-
-static inline int is_fifo(struct acpi_device *dev)
-{
-	struct acpi_table_tpm2 *tbl;
-	acpi_status st;
-
-	/* TPM 1.2 FIFO */
-	if (!has_hid(dev, "MSFT0101"))
-		return 1;
-
-	st = acpi_get_table(ACPI_SIG_TPM2, 1,
-			    (struct acpi_table_header **) &tbl);
-	if (ACPI_FAILURE(st)) {
-		dev_err(&dev->dev, "failed to get TPM2 ACPI table\n");
-		return 0;
-	}
-
-	if (le32_to_cpu(tbl->start_method) != TPM2_START_FIFO)
-		return 0;
-
-	/* TPM 2.0 FIFO */
-	return 1;
-}
 #else
 static inline int is_itpm(struct acpi_device *dev)
 {
 	return 0;
 }
-
-static inline int is_fifo(struct acpi_device *dev)
-{
-	return 1;
-}
 #endif
 
 /* Before we attempt to access the TPM we must see that the valid bit is set.
@@ -283,7 +250,8 @@
 static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 	int size = 0;
-	int expected, status;
+	int status;
+	u32 expected;
 
 	if (count < TPM_HEADER_SIZE) {
 		size = -EIO;
@@ -293,12 +261,12 @@
 	/* read first 10 bytes, including tag, paramsize, and result */
 	if ((size =
 	     recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
-		dev_err(chip->pdev, "Unable to read header\n");
+		dev_err(&chip->dev, "Unable to read header\n");
 		goto out;
 	}
 
 	expected = be32_to_cpu(*(__be32 *) (buf + 2));
-	if (expected > count) {
+	if (expected > count || expected < TPM_HEADER_SIZE) {
 		size = -EIO;
 		goto out;
 	}
@@ -306,7 +274,7 @@
 	if ((size +=
 	     recv_data(chip, &buf[TPM_HEADER_SIZE],
 		       expected - TPM_HEADER_SIZE)) < expected) {
-		dev_err(chip->pdev, "Unable to read remainder of result\n");
+		dev_err(&chip->dev, "Unable to read remainder of result\n");
 		size = -ETIME;
 		goto out;
 	}
@@ -315,7 +283,7 @@
 			  &chip->vendor.int_queue, false);
 	status = tpm_tis_status(chip);
 	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
-		dev_err(chip->pdev, "Error left over data\n");
+		dev_err(&chip->dev, "Error left over data\n");
 		size = -EIO;
 		goto out;
 	}
@@ -401,7 +369,7 @@
 	iowrite32(intmask,
 		  chip->vendor.iobase +
 		  TPM_INT_ENABLE(chip->vendor.locality));
-	free_irq(chip->vendor.irq, chip);
+	devm_free_irq(&chip->dev, chip->vendor.irq, chip);
 	chip->vendor.irq = 0;
 }
 
@@ -461,11 +429,8 @@
 	chip->vendor.irq = irq;
 	if (!priv->irq_tested)
 		msleep(1);
-	if (!priv->irq_tested) {
+	if (!priv->irq_tested)
 		disable_interrupts(chip);
-		dev_err(chip->pdev,
-			FW_BUG "TPM interrupt not working, polling instead\n");
-	}
 	priv->irq_tested = true;
 	return rc;
 }
@@ -533,7 +498,7 @@
 
 	rc = tpm_tis_send_data(chip, cmd_getticks, len);
 	if (rc == 0) {
-		dev_info(chip->pdev, "Detected an iTPM.\n");
+		dev_info(&chip->dev, "Detected an iTPM.\n");
 		rc = 1;
 	} else
 		rc = -EFAULT;
@@ -570,26 +535,6 @@
 	.req_canceled = tpm_tis_req_canceled,
 };
 
-static irqreturn_t tis_int_probe(int irq, void *dev_id)
-{
-	struct tpm_chip *chip = dev_id;
-	u32 interrupt;
-
-	interrupt = ioread32(chip->vendor.iobase +
-			     TPM_INT_STATUS(chip->vendor.locality));
-
-	if (interrupt == 0)
-		return IRQ_NONE;
-
-	chip->vendor.probed_irq = irq;
-
-	/* Clear interrupts handled with TPM_EOI */
-	iowrite32(interrupt,
-		  chip->vendor.iobase +
-		  TPM_INT_STATUS(chip->vendor.locality));
-	return IRQ_HANDLED;
-}
-
 static irqreturn_t tis_int_handler(int dummy, void *dev_id)
 {
 	struct tpm_chip *chip = dev_id;
@@ -622,6 +567,84 @@
 	return IRQ_HANDLED;
 }
 
+/* Register the IRQ and issue a command that will cause an interrupt. If an
+ * irq is seen then leave the chip setup for IRQ operation, otherwise reverse
+ * everything and leave in polling mode. Returns 0 on success.
+ */
+static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
+				    int flags, int irq)
+{
+	struct priv_data *priv = chip->vendor.priv;
+	u8 original_int_vec;
+
+	if (devm_request_irq(&chip->dev, irq, tis_int_handler, flags,
+			     chip->devname, chip) != 0) {
+		dev_info(&chip->dev, "Unable to request irq: %d for probe\n",
+			 irq);
+		return -1;
+	}
+	chip->vendor.irq = irq;
+
+	original_int_vec = ioread8(chip->vendor.iobase +
+				   TPM_INT_VECTOR(chip->vendor.locality));
+	iowrite8(irq,
+		 chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality));
+
+	/* Clear all existing */
+	iowrite32(ioread32(chip->vendor.iobase +
+			   TPM_INT_STATUS(chip->vendor.locality)),
+		  chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
+
+	/* Turn on */
+	iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
+		  chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
+
+	priv->irq_tested = false;
+
+	/* Generate an interrupt by having the core call through to
+	 * tpm_tis_send
+	 */
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		tpm2_gen_interrupt(chip);
+	else
+		tpm_gen_interrupt(chip);
+
+	/* tpm_tis_send will either confirm the interrupt is working or it
+	 * will call disable_irq which undoes all of the above.
+	 */
+	if (!chip->vendor.irq) {
+		iowrite8(original_int_vec,
+			 chip->vendor.iobase +
+			     TPM_INT_VECTOR(chip->vendor.locality));
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Try to find the IRQ the TPM is using. This is for legacy x86 systems that
+ * do not have ACPI/etc. We typically expect the interrupt to be declared if
+ * present.
+ */
+static void tpm_tis_probe_irq(struct tpm_chip *chip, u32 intmask)
+{
+	u8 original_int_vec;
+	int i;
+
+	original_int_vec = ioread8(chip->vendor.iobase +
+				   TPM_INT_VECTOR(chip->vendor.locality));
+
+	if (!original_int_vec) {
+		if (IS_ENABLED(CONFIG_X86))
+			for (i = 3; i <= 15; i++)
+				if (!tpm_tis_probe_irq_single(chip, intmask, 0,
+							      i))
+					return;
+	} else if (!tpm_tis_probe_irq_single(chip, intmask, 0,
+					     original_int_vec))
+		return;
+}
+
 static bool interrupts = true;
 module_param(interrupts, bool, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
@@ -644,8 +667,7 @@
 			acpi_handle acpi_dev_handle)
 {
 	u32 vendor, intfcaps, intmask;
-	int rc, i, irq_s, irq_e, probe;
-	int irq_r = -1;
+	int rc, probe;
 	struct tpm_chip *chip;
 	struct priv_data *priv;
 
@@ -662,9 +684,9 @@
 	chip->acpi_dev_handle = acpi_dev_handle;
 #endif
 
-	chip->vendor.iobase = devm_ioremap(dev, tpm_info->start, tpm_info->len);
-	if (!chip->vendor.iobase)
-		return -EIO;
+	chip->vendor.iobase = devm_ioremap_resource(dev, &tpm_info->res);
+	if (IS_ERR(chip->vendor.iobase))
+		return PTR_ERR(chip->vendor.iobase);
 
 	/* Maximum timeouts */
 	chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX;
@@ -677,6 +699,15 @@
 		goto out_err;
 	}
 
+	/* Take control of the TPM's interrupt hardware and shut it off */
+	intmask = ioread32(chip->vendor.iobase +
+			   TPM_INT_ENABLE(chip->vendor.locality));
+	intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
+		   TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
+	intmask &= ~TPM_GLOBAL_INT_ENABLE;
+	iowrite32(intmask,
+		  chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
+
 	if (request_locality(chip, 0) != 0) {
 		rc = -ENODEV;
 		goto out_err;
@@ -731,126 +762,31 @@
 	if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
 		dev_dbg(dev, "\tData Avail Int Support\n");
 
+	/* Very early on issue a command to the TPM in polling mode to make
+	 * sure it works. May as well use that command to set the proper
+	 *  timeouts for the driver.
+	 */
+	if (tpm_get_timeouts(chip)) {
+		dev_err(dev, "Could not get TPM timeouts and durations\n");
+		rc = -ENODEV;
+		goto out_err;
+	}
+
 	/* INTERRUPT Setup */
 	init_waitqueue_head(&chip->vendor.read_queue);
 	init_waitqueue_head(&chip->vendor.int_queue);
-
-	intmask =
-	    ioread32(chip->vendor.iobase +
-		     TPM_INT_ENABLE(chip->vendor.locality));
-
-	intmask |= TPM_INTF_CMD_READY_INT
-	    | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
-	    | TPM_INTF_STS_VALID_INT;
-
-	iowrite32(intmask,
-		  chip->vendor.iobase +
-		  TPM_INT_ENABLE(chip->vendor.locality));
-	if (interrupts)
-		chip->vendor.irq = tpm_info->irq;
-	if (interrupts && !chip->vendor.irq) {
-		irq_s =
-		    ioread8(chip->vendor.iobase +
-			    TPM_INT_VECTOR(chip->vendor.locality));
-		irq_r = irq_s;
-		if (irq_s) {
-			irq_e = irq_s;
-		} else {
-			irq_s = 3;
-			irq_e = 15;
-		}
-
-		for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
-			iowrite8(i, chip->vendor.iobase +
-				 TPM_INT_VECTOR(chip->vendor.locality));
-			if (devm_request_irq
-			    (dev, i, tis_int_probe, IRQF_SHARED,
-			     chip->devname, chip) != 0) {
-				dev_info(chip->pdev,
-					 "Unable to request irq: %d for probe\n",
-					 i);
-				continue;
-			}
-
-			/* Clear all existing */
-			iowrite32(ioread32
-				  (chip->vendor.iobase +
-				   TPM_INT_STATUS(chip->vendor.locality)),
-				  chip->vendor.iobase +
-				  TPM_INT_STATUS(chip->vendor.locality));
-
-			/* Turn on */
-			iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
-				  chip->vendor.iobase +
-				  TPM_INT_ENABLE(chip->vendor.locality));
-
-			chip->vendor.probed_irq = 0;
-
-			/* Generate Interrupts */
-			if (chip->flags & TPM_CHIP_FLAG_TPM2)
-				tpm2_gen_interrupt(chip);
-			else
-				tpm_gen_interrupt(chip);
-
-			chip->vendor.irq = chip->vendor.probed_irq;
-
-			/* free_irq will call into tis_int_probe;
-			   clear all irqs we haven't seen while doing
-			   tpm_gen_interrupt */
-			iowrite32(ioread32
-				  (chip->vendor.iobase +
-				   TPM_INT_STATUS(chip->vendor.locality)),
-				  chip->vendor.iobase +
-				  TPM_INT_STATUS(chip->vendor.locality));
-
-			/* Turn off */
-			iowrite32(intmask,
-				  chip->vendor.iobase +
-				  TPM_INT_ENABLE(chip->vendor.locality));
-
-			devm_free_irq(dev, i, chip);
-		}
+	if (interrupts && tpm_info->irq != -1) {
+		if (tpm_info->irq) {
+			tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
+						 tpm_info->irq);
+			if (!chip->vendor.irq)
+				dev_err(&chip->dev, FW_BUG
+					"TPM interrupt not working, polling instead\n");
+		} else
+			tpm_tis_probe_irq(chip, intmask);
 	}
-	if (chip->vendor.irq) {
-		iowrite8(chip->vendor.irq,
-			 chip->vendor.iobase +
-			 TPM_INT_VECTOR(chip->vendor.locality));
-		if (devm_request_irq
-		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
-		     chip->devname, chip) != 0) {
-			dev_info(chip->pdev,
-				 "Unable to request irq: %d for use\n",
-				 chip->vendor.irq);
-			chip->vendor.irq = 0;
-		} else {
-			/* Clear all existing */
-			iowrite32(ioread32
-				  (chip->vendor.iobase +
-				   TPM_INT_STATUS(chip->vendor.locality)),
-				  chip->vendor.iobase +
-				  TPM_INT_STATUS(chip->vendor.locality));
-
-			/* Turn on */
-			iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
-				  chip->vendor.iobase +
-				  TPM_INT_ENABLE(chip->vendor.locality));
-		}
-	} else if (irq_r != -1)
-		iowrite8(irq_r, chip->vendor.iobase +
-			 TPM_INT_VECTOR(chip->vendor.locality));
 
 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
-		chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
-		chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
-		chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
-		chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
-		chip->vendor.duration[TPM_SHORT] =
-			msecs_to_jiffies(TPM2_DURATION_SHORT);
-		chip->vendor.duration[TPM_MEDIUM] =
-			msecs_to_jiffies(TPM2_DURATION_MEDIUM);
-		chip->vendor.duration[TPM_LONG] =
-			msecs_to_jiffies(TPM2_DURATION_LONG);
-
 		rc = tpm2_do_selftest(chip);
 		if (rc == TPM2_RC_INITIALIZE) {
 			dev_warn(dev, "Firmware has not started TPM\n");
@@ -866,12 +802,6 @@
 			goto out_err;
 		}
 	} else {
-		if (tpm_get_timeouts(chip)) {
-			dev_err(dev, "Could not get TPM timeouts and durations\n");
-			rc = -ENODEV;
-			goto out_err;
-		}
-
 		if (tpm_do_selftest(chip)) {
 			dev_err(dev, "TPM self test failed\n");
 			rc = -ENODEV;
@@ -931,29 +861,29 @@
 
 static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
 
-#ifdef CONFIG_PNP
 static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
-				      const struct pnp_device_id *pnp_id)
+			    const struct pnp_device_id *pnp_id)
 {
-	struct tpm_info tpm_info = tis_default_info;
+	struct tpm_info tpm_info = {};
 	acpi_handle acpi_dev_handle = NULL;
+	struct resource *res;
 
-	tpm_info.start = pnp_mem_start(pnp_dev, 0);
-	tpm_info.len = pnp_mem_len(pnp_dev, 0);
+	res = pnp_get_resource(pnp_dev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+	tpm_info.res = *res;
 
 	if (pnp_irq_valid(pnp_dev, 0))
 		tpm_info.irq = pnp_irq(pnp_dev, 0);
 	else
-		interrupts = false;
+		tpm_info.irq = -1;
 
-#ifdef CONFIG_ACPI
 	if (pnp_acpi_device(pnp_dev)) {
 		if (is_itpm(pnp_acpi_device(pnp_dev)))
 			itpm = true;
 
-		acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
+		acpi_dev_handle = ACPI_HANDLE(&pnp_dev->dev);
 	}
-#endif
 
 	return tpm_tis_init(&pnp_dev->dev, &tpm_info, acpi_dev_handle);
 }
@@ -994,7 +924,6 @@
 module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
 		    sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
-#endif
 
 #ifdef CONFIG_ACPI
 static int tpm_check_resource(struct acpi_resource *ares, void *data)
@@ -1002,11 +931,11 @@
 	struct tpm_info *tpm_info = (struct tpm_info *) data;
 	struct resource res;
 
-	if (acpi_dev_resource_interrupt(ares, 0, &res)) {
+	if (acpi_dev_resource_interrupt(ares, 0, &res))
 		tpm_info->irq = res.start;
-	} else if (acpi_dev_resource_memory(ares, &res)) {
-		tpm_info->start = res.start;
-		tpm_info->len = resource_size(&res);
+	else if (acpi_dev_resource_memory(ares, &res)) {
+		tpm_info->res = res;
+		tpm_info->res.name = NULL;
 	}
 
 	return 1;
@@ -1014,14 +943,25 @@
 
 static int tpm_tis_acpi_init(struct acpi_device *acpi_dev)
 {
+	struct acpi_table_tpm2 *tbl;
+	acpi_status st;
 	struct list_head resources;
-	struct tpm_info tpm_info = tis_default_info;
+	struct tpm_info tpm_info = {};
 	int ret;
 
-	if (!is_fifo(acpi_dev))
+	st = acpi_get_table(ACPI_SIG_TPM2, 1,
+			    (struct acpi_table_header **) &tbl);
+	if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) {
+		dev_err(&acpi_dev->dev,
+			FW_BUG "failed to get TPM2 ACPI table\n");
+		return -EINVAL;
+	}
+
+	if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED)
 		return -ENODEV;
 
 	INIT_LIST_HEAD(&resources);
+	tpm_info.irq = -1;
 	ret = acpi_dev_get_resources(acpi_dev, &resources, tpm_check_resource,
 				     &tpm_info);
 	if (ret < 0)
@@ -1029,8 +969,11 @@
 
 	acpi_dev_free_resource_list(&resources);
 
-	if (!tpm_info.irq)
-		interrupts = false;
+	if (resource_type(&tpm_info.res) != IORESOURCE_MEM) {
+		dev_err(&acpi_dev->dev,
+			FW_BUG "TPM2 ACPI table does not define a memory resource\n");
+		return -EINVAL;
+	}
 
 	if (is_itpm(acpi_dev))
 		itpm = true;
@@ -1069,80 +1012,135 @@
 };
 #endif
 
+static struct platform_device *force_pdev;
+
+static int tpm_tis_plat_probe(struct platform_device *pdev)
+{
+	struct tpm_info tpm_info = {};
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "no memory resource defined\n");
+		return -ENODEV;
+	}
+	tpm_info.res = *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res) {
+		tpm_info.irq = res->start;
+	} else {
+		if (pdev == force_pdev)
+			tpm_info.irq = -1;
+		else
+			/* When forcing auto probe the IRQ */
+			tpm_info.irq = 0;
+	}
+
+	return tpm_tis_init(&pdev->dev, &tpm_info, NULL);
+}
+
+static int tpm_tis_plat_remove(struct platform_device *pdev)
+{
+	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
+
+	tpm_chip_unregister(chip);
+	tpm_tis_remove(chip);
+
+	return 0;
+}
+
 static struct platform_driver tis_drv = {
+	.probe = tpm_tis_plat_probe,
+	.remove = tpm_tis_plat_remove,
 	.driver = {
 		.name		= "tpm_tis",
 		.pm		= &tpm_tis_pm,
 	},
 };
 
-static struct platform_device *pdev;
-
 static bool force;
+#ifdef CONFIG_X86
 module_param(force, bool, 0444);
 MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
+#endif
+
+static int tpm_tis_force_device(void)
+{
+	struct platform_device *pdev;
+	static const struct resource x86_resources[] = {
+		{
+			.start = 0xFED40000,
+			.end = 0xFED40000 + TIS_MEM_LEN - 1,
+			.flags = IORESOURCE_MEM,
+		},
+	};
+
+	if (!force)
+		return 0;
+
+	/* The driver core will match the name tpm_tis of the device to
+	 * the tpm_tis platform driver and complete the setup via
+	 * tpm_tis_plat_probe
+	 */
+	pdev = platform_device_register_simple("tpm_tis", -1, x86_resources,
+					       ARRAY_SIZE(x86_resources));
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+	force_pdev = pdev;
+
+	return 0;
+}
+
 static int __init init_tis(void)
 {
 	int rc;
-#ifdef CONFIG_PNP
-	if (!force) {
-		rc = pnp_register_driver(&tis_pnp_driver);
-		if (rc)
-			return rc;
-	}
-#endif
+
+	rc = tpm_tis_force_device();
+	if (rc)
+		goto err_force;
+
+	rc = platform_driver_register(&tis_drv);
+	if (rc)
+		goto err_platform;
+
 #ifdef CONFIG_ACPI
-	if (!force) {
-		rc = acpi_bus_register_driver(&tis_acpi_driver);
-		if (rc) {
-#ifdef CONFIG_PNP
-			pnp_unregister_driver(&tis_pnp_driver);
-#endif
-			return rc;
-		}
-	}
+	rc = acpi_bus_register_driver(&tis_acpi_driver);
+	if (rc)
+		goto err_acpi;
 #endif
-	if (!force)
-		return 0;
 
-	rc = platform_driver_register(&tis_drv);
-	if (rc < 0)
-		return rc;
-	pdev = platform_device_register_simple("tpm_tis", -1, NULL, 0);
-	if (IS_ERR(pdev)) {
-		rc = PTR_ERR(pdev);
-		goto err_dev;
+	if (IS_ENABLED(CONFIG_PNP)) {
+		rc = pnp_register_driver(&tis_pnp_driver);
+		if (rc)
+			goto err_pnp;
 	}
-	rc = tpm_tis_init(&pdev->dev, &tis_default_info, NULL);
-	if (rc)
-		goto err_init;
+
 	return 0;
-err_init:
-	platform_device_unregister(pdev);
-err_dev:
-	platform_driver_unregister(&tis_drv);
+
+err_pnp:
+#ifdef CONFIG_ACPI
+	acpi_bus_unregister_driver(&tis_acpi_driver);
+err_acpi:
+#endif
+	platform_device_unregister(force_pdev);
+err_platform:
+	if (force_pdev)
+		platform_device_unregister(force_pdev);
+err_force:
 	return rc;
 }
 
 static void __exit cleanup_tis(void)
 {
-	struct tpm_chip *chip;
-#if defined(CONFIG_PNP) || defined(CONFIG_ACPI)
-	if (!force) {
+	pnp_unregister_driver(&tis_pnp_driver);
 #ifdef CONFIG_ACPI
-		acpi_bus_unregister_driver(&tis_acpi_driver);
-#endif
-#ifdef CONFIG_PNP
-		pnp_unregister_driver(&tis_pnp_driver);
+	acpi_bus_unregister_driver(&tis_acpi_driver);
 #endif
-		return;
-	}
-#endif
-	chip = dev_get_drvdata(&pdev->dev);
-	tpm_chip_unregister(chip);
-	tpm_tis_remove(chip);
-	platform_device_unregister(pdev);
 	platform_driver_unregister(&tis_drv);
+
+	if (force_pdev)
+		platform_device_unregister(force_pdev);
 }
 
 module_init(init_tis);
--- linux-4.4.0.orig/drivers/char/tpm/xen-tpmfront.c
+++ linux-4.4.0/drivers/char/tpm/xen-tpmfront.c
@@ -201,7 +201,7 @@
 		return -ENOMEM;
 	}
 
-	rv = xenbus_grant_ring(dev, &priv->shr, 1, &gref);
+	rv = xenbus_grant_ring(dev, priv->shr, 1, &gref);
 	if (rv < 0)
 		return rv;
 
@@ -305,7 +305,6 @@
 	rv = setup_ring(dev, priv);
 	if (rv) {
 		chip = dev_get_drvdata(&dev->dev);
-		tpm_chip_unregister(chip);
 		ring_free(priv);
 		return rv;
 	}
--- linux-4.4.0.orig/drivers/char/ttyprintk.c
+++ linux-4.4.0/drivers/char/ttyprintk.c
@@ -18,10 +18,11 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 
 struct ttyprintk_port {
 	struct tty_port port;
-	struct mutex port_write_mutex;
+	spinlock_t spinlock;
 };
 
 static struct ttyprintk_port tpk_port;
@@ -107,11 +108,12 @@
 static void tpk_close(struct tty_struct *tty, struct file *filp)
 {
 	struct ttyprintk_port *tpkp = tty->driver_data;
+	unsigned long flags;
 
-	mutex_lock(&tpkp->port_write_mutex);
+	spin_lock_irqsave(&tpkp->spinlock, flags);
 	/* flush tpk_printk buffer */
 	tpk_printk(NULL, 0);
-	mutex_unlock(&tpkp->port_write_mutex);
+	spin_unlock_irqrestore(&tpkp->spinlock, flags);
 
 	tty_port_close(&tpkp->port, tty, filp);
 }
@@ -123,13 +125,14 @@
 		const unsigned char *buf, int count)
 {
 	struct ttyprintk_port *tpkp = tty->driver_data;
+	unsigned long flags;
 	int ret;
 
 
 	/* exclusive use of tpk_printk within this tty */
-	mutex_lock(&tpkp->port_write_mutex);
+	spin_lock_irqsave(&tpkp->spinlock, flags);
 	ret = tpk_printk(buf, count);
-	mutex_unlock(&tpkp->port_write_mutex);
+	spin_unlock_irqrestore(&tpkp->spinlock, flags);
 
 	return ret;
 }
@@ -179,7 +182,7 @@
 {
 	int ret = -ENOMEM;
 
-	mutex_init(&tpk_port.port_write_mutex);
+	spin_lock_init(&tpk_port.spinlock);
 
 	ttyprintk_driver = tty_alloc_driver(1,
 			TTY_DRIVER_RESET_TERMIOS |
--- linux-4.4.0.orig/drivers/char/virtio_console.c
+++ linux-4.4.0/drivers/char/virtio_console.c
@@ -76,7 +76,7 @@
 	/* All the console devices handled by this driver */
 	struct list_head consoles;
 };
-static struct ports_driver_data pdrvdata;
+static struct ports_driver_data pdrvdata = { .next_vtermno = 1};
 
 static DEFINE_SPINLOCK(pdrvdata_lock);
 static DECLARE_COMPLETION(early_console_added);
@@ -417,7 +417,7 @@
 	}
 }
 
-static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
+static struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size,
 				     int pages)
 {
 	struct port_buffer *buf;
@@ -440,7 +440,7 @@
 		return buf;
 	}
 
-	if (is_rproc_serial(vq->vdev)) {
+	if (is_rproc_serial(vdev)) {
 		/*
 		 * Allocate DMA memory from ancestor. When a virtio
 		 * device is created by remoteproc, the DMA memory is
@@ -450,9 +450,9 @@
 		 * DMA_MEMORY_INCLUDES_CHILDREN had been supported
 		 * in dma-coherent.c
 		 */
-		if (!vq->vdev->dev.parent || !vq->vdev->dev.parent->parent)
+		if (!vdev->dev.parent || !vdev->dev.parent->parent)
 			goto free_buf;
-		buf->dev = vq->vdev->dev.parent->parent;
+		buf->dev = vdev->dev.parent->parent;
 
 		/* Increase device refcnt to avoid freeing it */
 		get_device(buf->dev);
@@ -487,7 +487,7 @@
 
 	buf = virtqueue_get_buf(port->in_vq, &len);
 	if (buf) {
-		buf->len = len;
+		buf->len = min_t(size_t, len, buf->size);
 		buf->offset = 0;
 		port->stats.bytes_received += len;
 	}
@@ -835,7 +835,7 @@
 
 	count = min((size_t)(32 * 1024), count);
 
-	buf = alloc_buf(port->out_vq, count, 0);
+	buf = alloc_buf(port->portdev->vdev, count, 0);
 	if (!buf)
 		return -ENOMEM;
 
@@ -954,7 +954,7 @@
 	if (ret < 0)
 		goto error_out;
 
-	buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
+	buf = alloc_buf(port->portdev->vdev, 0, pipe->nrbufs);
 	if (!buf) {
 		ret = -ENOMEM;
 		goto error_out;
@@ -1130,6 +1130,8 @@
 {
 	struct port *port;
 	struct scatterlist sg[1];
+	void *data;
+	int ret;
 
 	if (unlikely(early_put_chars))
 		return early_put_chars(vtermno, buf, count);
@@ -1138,8 +1140,14 @@
 	if (!port)
 		return -EPIPE;
 
-	sg_init_one(sg, buf, count);
-	return __send_to_port(port, sg, 1, count, (void *)buf, false);
+	data = kmemdup(buf, count, GFP_ATOMIC);
+	if (!data)
+		return -ENOMEM;
+
+	sg_init_one(sg, data, count);
+	ret = __send_to_port(port, sg, 1, count, data, false);
+	kfree(data);
+	return ret;
 }
 
 /*
@@ -1355,24 +1363,24 @@
 	port->cons.ws.ws_col = cols;
 }
 
-static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
+static int fill_queue(struct virtqueue *vq, spinlock_t *lock)
 {
 	struct port_buffer *buf;
-	unsigned int nr_added_bufs;
+	int nr_added_bufs;
 	int ret;
 
 	nr_added_bufs = 0;
 	do {
-		buf = alloc_buf(vq, PAGE_SIZE, 0);
+		buf = alloc_buf(vq->vdev, PAGE_SIZE, 0);
 		if (!buf)
-			break;
+			return -ENOMEM;
 
 		spin_lock_irq(lock);
 		ret = add_inbuf(vq, buf);
 		if (ret < 0) {
 			spin_unlock_irq(lock);
 			free_buf(buf, true);
-			break;
+			return ret;
 		}
 		nr_added_bufs++;
 		spin_unlock_irq(lock);
@@ -1391,9 +1399,7 @@
 {
 	char debugfs_name[16];
 	struct port *port;
-	struct port_buffer *buf;
 	dev_t devt;
-	unsigned int nr_added_bufs;
 	int err;
 
 	port = kmalloc(sizeof(*port), GFP_KERNEL);
@@ -1412,6 +1418,7 @@
 	port->async_queue = NULL;
 
 	port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
+	port->cons.vtermno = 0;
 
 	port->host_connected = port->guest_connected = false;
 	port->stats = (struct port_stats) { 0 };
@@ -1451,11 +1458,13 @@
 	spin_lock_init(&port->outvq_lock);
 	init_waitqueue_head(&port->waitqueue);
 
-	/* Fill the in_vq with buffers so the host can send us data. */
-	nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
-	if (!nr_added_bufs) {
+	/* We can safely ignore ENOSPC because it means
+	 * the queue already has buffers. Buffers are removed
+	 * only by virtcons_remove(), not by unplug_port()
+	 */
+	err = fill_queue(port->in_vq, &port->inbuf_lock);
+	if (err < 0 && err != -ENOSPC) {
 		dev_err(port->dev, "Error allocating inbufs\n");
-		err = -ENOMEM;
 		goto free_device;
 	}
 
@@ -1502,8 +1511,6 @@
 	return 0;
 
 free_inbufs:
-	while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-		free_buf(buf, true);
 free_device:
 	device_destroy(pdrvdata.class, port->dev->devt);
 free_cdev:
@@ -1528,23 +1535,13 @@
 
 static void remove_port_data(struct port *port)
 {
-	struct port_buffer *buf;
-
 	spin_lock_irq(&port->inbuf_lock);
 	/* Remove unused data this port might have received. */
 	discard_port_data(port);
-
-	/* Remove buffers we queued up for the Host to send us data in. */
-	while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-		free_buf(buf, true);
 	spin_unlock_irq(&port->inbuf_lock);
 
 	spin_lock_irq(&port->outvq_lock);
 	reclaim_consumed_buffers(port);
-
-	/* Free pending buffers from the out-queue. */
-	while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
-		free_buf(buf, true);
 	spin_unlock_irq(&port->outvq_lock);
 }
 
@@ -1755,7 +1752,7 @@
 	while ((buf = virtqueue_get_buf(vq, &len))) {
 		spin_unlock(&portdev->c_ivq_lock);
 
-		buf->len = len;
+		buf->len = min_t(size_t, len, buf->size);
 		buf->offset = 0;
 
 		handle_control_message(vq->vdev, portdev, buf);
@@ -1770,13 +1767,24 @@
 	spin_unlock(&portdev->c_ivq_lock);
 }
 
+static void flush_bufs(struct virtqueue *vq, bool can_sleep)
+{
+	struct port_buffer *buf;
+	unsigned int len;
+
+	while ((buf = virtqueue_get_buf(vq, &len)))
+		free_buf(buf, can_sleep);
+}
+
 static void out_intr(struct virtqueue *vq)
 {
 	struct port *port;
 
 	port = find_port_by_vq(vq->vdev->priv, vq);
-	if (!port)
+	if (!port) {
+		flush_bufs(vq, false);
 		return;
+	}
 
 	wake_up_interruptible(&port->waitqueue);
 }
@@ -1787,8 +1795,10 @@
 	unsigned long flags;
 
 	port = find_port_by_vq(vq->vdev->priv, vq);
-	if (!port)
+	if (!port) {
+		flush_bufs(vq, false);
 		return;
+	}
 
 	spin_lock_irqsave(&port->inbuf_lock, flags);
 	port->inbuf = get_inbuf(port);
@@ -1846,7 +1856,7 @@
 {
 	struct ports_device *portdev;
 
-	portdev = container_of(work, struct ports_device, control_work);
+	portdev = container_of(work, struct ports_device, config_work);
 	if (!use_multiport(portdev)) {
 		struct virtio_device *vdev;
 		struct port *port;
@@ -1963,24 +1973,54 @@
 
 static void remove_vqs(struct ports_device *portdev)
 {
+	struct virtqueue *vq;
+
+	virtio_device_for_each_vq(portdev->vdev, vq) {
+		struct port_buffer *buf;
+
+		flush_bufs(vq, true);
+		while ((buf = virtqueue_detach_unused_buf(vq)))
+			free_buf(buf, true);
+	}
 	portdev->vdev->config->del_vqs(portdev->vdev);
 	kfree(portdev->in_vqs);
 	kfree(portdev->out_vqs);
 }
 
-static void remove_controlq_data(struct ports_device *portdev)
+static void virtcons_remove(struct virtio_device *vdev)
 {
-	struct port_buffer *buf;
-	unsigned int len;
+	struct ports_device *portdev;
+	struct port *port, *port2;
 
-	if (!use_multiport(portdev))
-		return;
+	portdev = vdev->priv;
 
-	while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
-		free_buf(buf, true);
+	spin_lock_irq(&pdrvdata_lock);
+	list_del(&portdev->list);
+	spin_unlock_irq(&pdrvdata_lock);
 
-	while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
-		free_buf(buf, true);
+	/* Disable interrupts for vqs */
+	vdev->config->reset(vdev);
+	/* Finish up work that's lined up */
+	if (use_multiport(portdev))
+		cancel_work_sync(&portdev->control_work);
+	else
+		cancel_work_sync(&portdev->config_work);
+
+	list_for_each_entry_safe(port, port2, &portdev->ports, list)
+		unplug_port(port);
+
+	unregister_chrdev(portdev->chr_major, "virtio-portsdev");
+
+	/*
+	 * When yanking out a device, we immediately lose the
+	 * (device-side) queues.  So there's no point in keeping the
+	 * guest side around till we drop our final reference.  This
+	 * also means that any ports which are in an open state will
+	 * have to just stop using the port, as the vqs are going
+	 * away.
+	 */
+	remove_vqs(portdev);
+	kfree(portdev);
 }
 
 /*
@@ -2049,6 +2089,7 @@
 
 	spin_lock_init(&portdev->ports_lock);
 	INIT_LIST_HEAD(&portdev->ports);
+	INIT_LIST_HEAD(&portdev->list);
 
 	virtio_device_ready(portdev->vdev);
 
@@ -2056,18 +2097,22 @@
 	INIT_WORK(&portdev->control_work, &control_work_handler);
 
 	if (multiport) {
-		unsigned int nr_added_bufs;
-
 		spin_lock_init(&portdev->c_ivq_lock);
 		spin_lock_init(&portdev->c_ovq_lock);
 
-		nr_added_bufs = fill_queue(portdev->c_ivq,
-					   &portdev->c_ivq_lock);
-		if (!nr_added_bufs) {
+		err = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
+		if (err < 0) {
 			dev_err(&vdev->dev,
 				"Error allocating buffers for control queue\n");
-			err = -ENOMEM;
-			goto free_vqs;
+			/*
+			 * The host might want to notify mgmt sw about device
+			 * add failure.
+			 */
+			__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+					   VIRTIO_CONSOLE_DEVICE_READY, 0);
+			/* Device was functional: we need full cleanup. */
+			virtcons_remove(vdev);
+			return err;
 		}
 	} else {
 		/*
@@ -2098,11 +2143,6 @@
 
 	return 0;
 
-free_vqs:
-	/* The host might want to notify mgmt sw about device add failure */
-	__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
-			   VIRTIO_CONSOLE_DEVICE_READY, 0);
-	remove_vqs(portdev);
 free_chrdev:
 	unregister_chrdev(portdev->chr_major, "virtio-portsdev");
 free:
@@ -2111,47 +2151,11 @@
 	return err;
 }
 
-static void virtcons_remove(struct virtio_device *vdev)
-{
-	struct ports_device *portdev;
-	struct port *port, *port2;
-
-	portdev = vdev->priv;
-
-	spin_lock_irq(&pdrvdata_lock);
-	list_del(&portdev->list);
-	spin_unlock_irq(&pdrvdata_lock);
-
-	/* Disable interrupts for vqs */
-	vdev->config->reset(vdev);
-	/* Finish up work that's lined up */
-	if (use_multiport(portdev))
-		cancel_work_sync(&portdev->control_work);
-	else
-		cancel_work_sync(&portdev->config_work);
-
-	list_for_each_entry_safe(port, port2, &portdev->ports, list)
-		unplug_port(port);
-
-	unregister_chrdev(portdev->chr_major, "virtio-portsdev");
-
-	/*
-	 * When yanking out a device, we immediately lose the
-	 * (device-side) queues.  So there's no point in keeping the
-	 * guest side around till we drop our final reference.  This
-	 * also means that any ports which are in an open state will
-	 * have to just stop using the port, as the vqs are going
-	 * away.
-	 */
-	remove_controlq_data(portdev);
-	remove_vqs(portdev);
-	kfree(portdev);
-}
-
 static struct virtio_device_id id_table[] = {
 	{ VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
 	{ 0 },
 };
+MODULE_DEVICE_TABLE(virtio, id_table);
 
 static unsigned int features[] = {
 	VIRTIO_CONSOLE_F_SIZE,
@@ -2164,6 +2168,7 @@
 #endif
 	{ 0 },
 };
+MODULE_DEVICE_TABLE(virtio, rproc_serial_id_table);
 
 static unsigned int rproc_serial_features[] = {
 };
@@ -2178,15 +2183,16 @@
 
 	vdev->config->reset(vdev);
 
-	virtqueue_disable_cb(portdev->c_ivq);
+	if (use_multiport(portdev))
+		virtqueue_disable_cb(portdev->c_ivq);
 	cancel_work_sync(&portdev->control_work);
 	cancel_work_sync(&portdev->config_work);
 	/*
 	 * Once more: if control_work_handler() was running, it would
 	 * enable the cb as the last step.
 	 */
-	virtqueue_disable_cb(portdev->c_ivq);
-	remove_controlq_data(portdev);
+	if (use_multiport(portdev))
+		virtqueue_disable_cb(portdev->c_ivq);
 
 	list_for_each_entry(port, &portdev->ports, list) {
 		virtqueue_disable_cb(port->in_vq);
@@ -2315,6 +2321,5 @@
 module_init(init);
 module_exit(fini);
 
-MODULE_DEVICE_TABLE(virtio, id_table);
 MODULE_DESCRIPTION("Virtio console driver");
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/clk/Makefile
+++ linux-4.4.0/drivers/clk/Makefile
@@ -78,7 +78,9 @@
 obj-$(CONFIG_ARCH_OMAP2PLUS)		+= ti/
 obj-$(CONFIG_ARCH_U8500)		+= ux500/
 obj-$(CONFIG_COMMON_CLK_VERSATILE)	+= versatile/
+ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_X86)			+= x86/
+endif
 obj-$(CONFIG_ARCH_ZX)			+= zte/
 obj-$(CONFIG_ARCH_ZYNQ)			+= zynq/
 obj-$(CONFIG_H8300)		+= h8300/
--- linux-4.4.0.orig/drivers/clk/at91/clk-h32mx.c
+++ linux-4.4.0/drivers/clk/at91/clk-h32mx.c
@@ -116,7 +116,7 @@
 	h32mxclk->pmc = pmc;
 
 	clk = clk_register(NULL, &h32mxclk->hw);
-	if (!clk) {
+	if (IS_ERR(clk)) {
 		kfree(h32mxclk);
 		return;
 	}
--- linux-4.4.0.orig/drivers/clk/at91/clk-usb.c
+++ linux-4.4.0/drivers/clk/at91/clk-usb.c
@@ -79,6 +79,9 @@
 			tmp_parent_rate = req->rate * div;
 			tmp_parent_rate = clk_hw_round_rate(parent,
 							   tmp_parent_rate);
+			if (!tmp_parent_rate)
+				continue;
+
 			tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div);
 			if (tmp_rate < req->rate)
 				tmp_diff = req->rate - tmp_rate;
--- linux-4.4.0.orig/drivers/clk/bcm/clk-bcm2835.c
+++ linux-4.4.0/drivers/clk/bcm/clk-bcm2835.c
@@ -890,8 +890,12 @@
 	struct bcm2835_cprman *cprman = pll->cprman;
 	const struct bcm2835_pll_data *data = pll->data;
 
+	spin_lock(&cprman->regs_lock);
 	cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST);
-	cprman_write(cprman, data->a2w_ctrl_reg, A2W_PLL_CTRL_PWRDN);
+	cprman_write(cprman, data->a2w_ctrl_reg,
+		     cprman_read(cprman, data->a2w_ctrl_reg) |
+		     A2W_PLL_CTRL_PWRDN);
+	spin_unlock(&cprman->regs_lock);
 }
 
 static int bcm2835_pll_on(struct clk_hw *hw)
@@ -901,9 +905,15 @@
 	const struct bcm2835_pll_data *data = pll->data;
 	ktime_t timeout;
 
+	cprman_write(cprman, data->a2w_ctrl_reg,
+		     cprman_read(cprman, data->a2w_ctrl_reg) &
+		     ~A2W_PLL_CTRL_PWRDN);
+
 	/* Take the PLL out of reset. */
+	spin_lock(&cprman->regs_lock);
 	cprman_write(cprman, data->cm_ctrl_reg,
 		     cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST);
+	spin_unlock(&cprman->regs_lock);
 
 	/* Wait for the PLL to lock. */
 	timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
@@ -917,6 +927,10 @@
 		cpu_relax();
 	}
 
+	cprman_write(cprman, data->a2w_ctrl_reg,
+		     cprman_read(cprman, data->a2w_ctrl_reg) |
+		     A2W_PLL_CTRL_PRST_DISABLE);
+
 	return 0;
 }
 
@@ -987,9 +1001,11 @@
 	}
 
 	/* Unmask the reference clock from the oscillator. */
+	spin_lock(&cprman->regs_lock);
 	cprman_write(cprman, A2W_XOSC_CTRL,
 		     cprman_read(cprman, A2W_XOSC_CTRL) |
 		     data->reference_enable_mask);
+	spin_unlock(&cprman->regs_lock);
 
 	if (do_ana_setup_first)
 		bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana);
@@ -1068,10 +1084,14 @@
 	struct bcm2835_cprman *cprman = divider->cprman;
 	const struct bcm2835_pll_divider_data *data = divider->data;
 
+	spin_lock(&cprman->regs_lock);
 	cprman_write(cprman, data->cm_reg,
 		     (cprman_read(cprman, data->cm_reg) &
 		      ~data->load_mask) | data->hold_mask);
-	cprman_write(cprman, data->a2w_reg, A2W_PLL_CHANNEL_DISABLE);
+	cprman_write(cprman, data->a2w_reg,
+		     cprman_read(cprman, data->a2w_reg) |
+		     A2W_PLL_CHANNEL_DISABLE);
+	spin_unlock(&cprman->regs_lock);
 }
 
 static int bcm2835_pll_divider_on(struct clk_hw *hw)
@@ -1080,12 +1100,14 @@
 	struct bcm2835_cprman *cprman = divider->cprman;
 	const struct bcm2835_pll_divider_data *data = divider->data;
 
+	spin_lock(&cprman->regs_lock);
 	cprman_write(cprman, data->a2w_reg,
 		     cprman_read(cprman, data->a2w_reg) &
 		     ~A2W_PLL_CHANNEL_DISABLE);
 
 	cprman_write(cprman, data->cm_reg,
 		     cprman_read(cprman, data->cm_reg) & ~data->hold_mask);
+	spin_unlock(&cprman->regs_lock);
 
 	return 0;
 }
@@ -1097,13 +1119,15 @@
 	struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw);
 	struct bcm2835_cprman *cprman = divider->cprman;
 	const struct bcm2835_pll_divider_data *data = divider->data;
-	u32 cm;
-	int ret;
+	u32 cm, div, max_div = 1 << A2W_PLL_DIV_BITS;
+
+	div = DIV_ROUND_UP_ULL(parent_rate, rate);
 
-	ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
-	if (ret)
-		return ret;
+	div = min(div, max_div);
+	if (div == max_div)
+		div = 0;
 
+	cprman_write(cprman, data->a2w_reg, div);
 	cm = cprman_read(cprman, data->cm_reg);
 	cprman_write(cprman, data->cm_reg, cm | data->load_mask);
 	cprman_write(cprman, data->cm_reg, cm & ~data->load_mask);
@@ -1165,8 +1189,9 @@
 		div &= ~unused_frac_mask;
 	}
 
-	/* Clamp to the limits. */
-	div = max(div, unused_frac_mask + 1);
+	/* clamp to min divider of 1 */
+	div = max_t(u32, div, 1 << CM_DIV_FRAC_BITS);
+	/* clamp to the highest possible fractional divider */
 	div = min_t(u32, div, GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1,
 				      CM_DIV_FRAC_BITS - data->frac_bits));
 
--- linux-4.4.0.orig/drivers/clk/bcm/clk-ns2.c
+++ linux-4.4.0/drivers/clk/bcm/clk-ns2.c
@@ -103,7 +103,7 @@
 
 static const struct iproc_pll_ctrl genpll_sw = {
 	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_SPLIT_STAT_CTRL,
-	.aon = AON_VAL(0x0, 2, 9, 8),
+	.aon = AON_VAL(0x0, 1, 11, 10),
 	.reset = RESET_VAL(0x4, 2, 1),
 	.dig_filter = DF_VAL(0x0, 9, 3, 5, 4, 2, 3),
 	.ndiv_int = REG_VAL(0x8, 4, 10),
--- linux-4.4.0.orig/drivers/clk/clk-conf.c
+++ linux-4.4.0/drivers/clk/clk-conf.c
@@ -106,7 +106,7 @@
 
 			rc = clk_set_rate(clk, rate);
 			if (rc < 0)
-				pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
+				pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n",
 				       __clk_get_name(clk), rate, rc,
 				       clk_get_rate(clk));
 			clk_put(clk);
--- linux-4.4.0.orig/drivers/clk/clk-divider.c
+++ linux-4.4.0/drivers/clk/clk-divider.c
@@ -354,7 +354,7 @@
 
 	/* if read only, just return current value */
 	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
-		bestdiv = readl(divider->reg) >> divider->shift;
+		bestdiv = clk_readl(divider->reg) >> divider->shift;
 		bestdiv &= div_mask(divider->width);
 		bestdiv = _get_div(divider->table, bestdiv, divider->flags,
 			divider->width);
@@ -422,6 +422,12 @@
 };
 EXPORT_SYMBOL_GPL(clk_divider_ops);
 
+const struct clk_ops clk_divider_ro_ops = {
+	.recalc_rate = clk_divider_recalc_rate,
+	.round_rate = clk_divider_round_rate,
+};
+EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
+
 static struct clk *_register_divider(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
@@ -445,7 +451,10 @@
 		return ERR_PTR(-ENOMEM);
 
 	init.name = name;
-	init.ops = &clk_divider_ops;
+	if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
+		init.ops = &clk_divider_ro_ops;
+	else
+		init.ops = &clk_divider_ops;
 	init.flags = flags | CLK_IS_BASIC;
 	init.parent_names = (parent_name ? &parent_name: NULL);
 	init.num_parents = (parent_name ? 1 : 0);
--- linux-4.4.0.orig/drivers/clk/clk-gpio.c
+++ linux-4.4.0/drivers/clk/clk-gpio.c
@@ -287,12 +287,14 @@
 	const char **parent_names;
 	int i, num_parents;
 
+	num_parents = of_clk_get_parent_count(node);
+	if (num_parents < 0)
+		return;
+
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return;
 
-	num_parents = of_clk_get_parent_count(node);
-
 	parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
 	if (!parent_names)
 		return;
--- linux-4.4.0.orig/drivers/clk/clk-highbank.c
+++ linux-4.4.0/drivers/clk/clk-highbank.c
@@ -294,6 +294,7 @@
 	/* Map system registers */
 	srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
 	hb_clk->reg = of_iomap(srnp, 0);
+	of_node_put(srnp);
 	BUG_ON(!hb_clk->reg);
 	hb_clk->reg += reg;
 
--- linux-4.4.0.orig/drivers/clk/clk-multiplier.c
+++ linux-4.4.0/drivers/clk/clk-multiplier.c
@@ -54,14 +54,28 @@
 				unsigned long *best_parent_rate,
 				u8 width, unsigned long flags)
 {
+	struct clk_multiplier *mult = to_clk_multiplier(hw);
 	unsigned long orig_parent_rate = *best_parent_rate;
 	unsigned long parent_rate, current_rate, best_rate = ~0;
 	unsigned int i, bestmult = 0;
+	unsigned int maxmult = (1 << width) - 1;
 
-	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
-		return rate / *best_parent_rate;
+	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
+		bestmult = rate / orig_parent_rate;
 
-	for (i = 1; i < ((1 << width) - 1); i++) {
+		/* Make sure we don't end up with a 0 multiplier */
+		if ((bestmult == 0) &&
+		    !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
+			bestmult = 1;
+
+		/* Make sure we don't overflow the multiplier */
+		if (bestmult > maxmult)
+			bestmult = maxmult;
+
+		return bestmult;
+	}
+
+	for (i = 1; i < maxmult; i++) {
 		if (rate == orig_parent_rate * i) {
 			/*
 			 * This is the best case for us if we have a
--- linux-4.4.0.orig/drivers/clk/clk-qoriq.c
+++ linux-4.4.0/drivers/clk/clk-qoriq.c
@@ -540,7 +540,7 @@
 		.guts_compat = "fsl,qoriq-device-config-1.0",
 		.init_periph = p5020_init_periph,
 		.cmux_groups = {
-			&p2041_cmux_grp1, &p2041_cmux_grp2
+			&p5020_cmux_grp1, &p5020_cmux_grp2
 		},
 		.cmux_to_group = {
 			0, 1, -1
@@ -700,6 +700,7 @@
 					     struct mux_hwclock *hwc,
 					     const struct clk_ops *ops,
 					     unsigned long min_rate,
+					     unsigned long max_rate,
 					     unsigned long pct80_rate,
 					     const char *fmt, int idx)
 {
@@ -728,6 +729,8 @@
 			continue;
 		if (rate < min_rate)
 			continue;
+		if (rate > max_rate)
+			continue;
 
 		parent_names[j] = div->name;
 		hwc->parent_to_clksel[j] = i;
@@ -759,14 +762,18 @@
 	struct mux_hwclock *hwc;
 	const struct clockgen_pll_div *div;
 	unsigned long plat_rate, min_rate;
-	u64 pct80_rate;
+	u64 max_rate, pct80_rate;
 	u32 clksel;
 
 	hwc = kzalloc(sizeof(*hwc), GFP_KERNEL);
 	if (!hwc)
 		return NULL;
 
-	hwc->reg = cg->regs + 0x20 * idx;
+	if (cg->info.flags & CG_VER3)
+		hwc->reg = cg->regs + 0x70000 + 0x20 * idx;
+	else
+		hwc->reg = cg->regs + 0x20 * idx;
+
 	hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]];
 
 	/*
@@ -783,8 +790,8 @@
 		return NULL;
 	}
 
-	pct80_rate = clk_get_rate(div->clk);
-	pct80_rate *= 8;
+	max_rate = clk_get_rate(div->clk);
+	pct80_rate = max_rate * 8;
 	do_div(pct80_rate, 10);
 
 	plat_rate = clk_get_rate(cg->pll[PLATFORM_PLL].div[PLL_DIV1].clk);
@@ -794,7 +801,7 @@
 	else
 		min_rate = plat_rate / 2;
 
-	return create_mux_common(cg, hwc, &cmux_ops, min_rate,
+	return create_mux_common(cg, hwc, &cmux_ops, min_rate, max_rate,
 				 pct80_rate, "cg-cmux%d", idx);
 }
 
@@ -809,7 +816,7 @@
 	hwc->reg = cg->regs + 0x20 * idx + 0x10;
 	hwc->info = cg->info.hwaccel[idx];
 
-	return create_mux_common(cg, hwc, &hwaccel_ops, 0, 0,
+	return create_mux_common(cg, hwc, &hwaccel_ops, 0, ULONG_MAX, 0,
 				 "cg-hwaccel%d", idx);
 }
 
@@ -1237,6 +1244,7 @@
 				pr_err("%s: Couldn't map %s regs\n", __func__,
 				       guts->full_name);
 			}
+			of_node_put(guts);
 		}
 
 	}
--- linux-4.4.0.orig/drivers/clk/clk-s2mps11.c
+++ linux-4.4.0/drivers/clk/clk-s2mps11.c
@@ -263,6 +263,7 @@
 	return ret;
 
 err_reg:
+	of_node_put(s2mps11_clks[0].clk_np);
 	while (--i >= 0)
 		clkdev_drop(s2mps11_clks[i].lookup);
 
@@ -297,6 +298,36 @@
 };
 MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
 
+#ifdef CONFIG_OF
+/*
+ * Device is instantiated through parent MFD device and device matching is done
+ * through platform_device_id.
+ *
+ * However if device's DT node contains proper clock compatible and driver is
+ * built as a module, then the *module* matching will be done trough DT aliases.
+ * This requires of_device_id table.  In the same time this will not change the
+ * actual *device* matching so do not add .of_match_table.
+ */
+static const struct of_device_id s2mps11_dt_match[] __used = {
+	{
+		.compatible = "samsung,s2mps11-clk",
+		.data = (void *)S2MPS11X,
+	}, {
+		.compatible = "samsung,s2mps13-clk",
+		.data = (void *)S2MPS13X,
+	}, {
+		.compatible = "samsung,s2mps14-clk",
+		.data = (void *)S2MPS14X,
+	}, {
+		.compatible = "samsung,s5m8767-clk",
+		.data = (void *)S5M8767X,
+	}, {
+		/* Sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(of, s2mps11_dt_match);
+#endif
+
 static struct platform_driver s2mps11_clk_driver = {
 	.driver = {
 		.name  = "s2mps11-clk",
--- linux-4.4.0.orig/drivers/clk/clk-scpi.c
+++ linux-4.4.0/drivers/clk/clk-scpi.c
@@ -71,15 +71,15 @@
 };
 
 /* find closest match to given frequency in OPP table */
-static int __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
+static long __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
 {
 	int idx;
-	u32 fmin = 0, fmax = ~0, ftmp;
+	unsigned long fmin = 0, fmax = ~0, ftmp;
 	const struct scpi_opp *opp = clk->info->opps;
 
 	for (idx = 0; idx < clk->info->count; idx++, opp++) {
 		ftmp = opp->freq;
-		if (ftmp >= (u32)rate) {
+		if (ftmp >= rate) {
 			if (ftmp <= fmax)
 				fmax = ftmp;
 			break;
--- linux-4.4.0.orig/drivers/clk/clk-si5351.c
+++ linux-4.4.0/drivers/clk/clk-si5351.c
@@ -72,7 +72,7 @@
 	"xtal", "clkin"
 };
 static const char * const si5351_pll_names[] = {
-	"plla", "pllb", "vxco"
+	"si5351_plla", "si5351_pllb", "si5351_vxco"
 };
 static const char * const si5351_msynth_names[] = {
 	"ms0", "ms1", "ms2", "ms3", "ms4", "ms5", "ms6", "ms7"
--- linux-4.4.0.orig/drivers/clk/clk-wm831x.c
+++ linux-4.4.0/drivers/clk/clk-wm831x.c
@@ -247,7 +247,7 @@
 	if (ret < 0) {
 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
 			ret);
-		return true;
+		return false;
 	}
 
 	return (ret & WM831X_CLKOUT_ENA) != 0;
--- linux-4.4.0.orig/drivers/clk/clk-xgene.c
+++ linux-4.4.0/drivers/clk/clk-xgene.c
@@ -29,7 +29,9 @@
 #include <linux/of_address.h>
 
 /* Register SCU_PCPPLL bit fields */
-#define N_DIV_RD(src)			(((src) & 0x000001ff))
+#define N_DIV_RD(src)			((src) & 0x000001ff)
+#define SC_N_DIV_RD(src)		((src) & 0x0000007f)
+#define SC_OUTDIV2(src)			(((src) & 0x00000100) >> 8)
 
 /* Register SCU_SOCPLL bit fields */
 #define CLKR_RD(src)			(((src) & 0x07000000)>>24)
@@ -63,6 +65,7 @@
 	spinlock_t	*lock;
 	u32		pll_offset;
 	enum xgene_pll_type	type;
+	int		version;
 };
 
 #define to_xgene_clk_pll(_hw) container_of(_hw, struct xgene_clk_pll, hw)
@@ -92,27 +95,37 @@
 
 	pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
 
-	if (pllclk->type == PLL_TYPE_PCP) {
-		/*
-		 * PLL VCO = Reference clock * NF
-		 * PCP PLL = PLL_VCO / 2
-		 */
-		nout = 2;
-		fvco = parent_rate * (N_DIV_RD(pll) + 4);
+	if (pllclk->version <= 1) {
+		if (pllclk->type == PLL_TYPE_PCP) {
+			/*
+			* PLL VCO = Reference clock * NF
+			* PCP PLL = PLL_VCO / 2
+			*/
+			nout = 2;
+			fvco = parent_rate * (N_DIV_RD(pll) + 4);
+		} else {
+			/*
+			* Fref = Reference Clock / NREF;
+			* Fvco = Fref * NFB;
+			* Fout = Fvco / NOUT;
+			*/
+			nref = CLKR_RD(pll) + 1;
+			nout = CLKOD_RD(pll) + 1;
+			nfb = CLKF_RD(pll);
+			fref = parent_rate / nref;
+			fvco = fref * nfb;
+		}
 	} else {
 		/*
-		 * Fref = Reference Clock / NREF;
-		 * Fvco = Fref * NFB;
-		 * Fout = Fvco / NOUT;
+		 * fvco = Reference clock * FBDIVC
+		 * PLL freq = fvco / NOUT
 		 */
-		nref = CLKR_RD(pll) + 1;
-		nout = CLKOD_RD(pll) + 1;
-		nfb = CLKF_RD(pll);
-		fref = parent_rate / nref;
-		fvco = fref * nfb;
+		nout = SC_OUTDIV2(pll) ? 2 : 3;
+		fvco = parent_rate * SC_N_DIV_RD(pll);
 	}
-	pr_debug("%s pll recalc rate %ld parent %ld\n", clk_hw_get_name(hw),
-		fvco / nout, parent_rate);
+	pr_debug("%s pll recalc rate %ld parent %ld version %d\n",
+		 clk_hw_get_name(hw), fvco / nout, parent_rate,
+		 pllclk->version);
 
 	return fvco / nout;
 }
@@ -125,7 +138,7 @@
 static struct clk *xgene_register_clk_pll(struct device *dev,
 	const char *name, const char *parent_name,
 	unsigned long flags, void __iomem *reg, u32 pll_offset,
-	u32 type, spinlock_t *lock)
+	u32 type, spinlock_t *lock, int version)
 {
 	struct xgene_clk_pll *apmclk;
 	struct clk *clk;
@@ -144,6 +157,7 @@
 	init.parent_names = parent_name ? &parent_name : NULL;
 	init.num_parents = parent_name ? 1 : 0;
 
+	apmclk->version = version;
 	apmclk->reg = reg;
 	apmclk->lock = lock;
 	apmclk->pll_offset = pll_offset;
@@ -160,26 +174,37 @@
 	return clk;
 }
 
+static int xgene_pllclk_version(struct device_node *np)
+{
+	if (of_device_is_compatible(np, "apm,xgene-socpll-clock"))
+		return 1;
+	if (of_device_is_compatible(np, "apm,xgene-pcppll-clock"))
+		return 1;
+	return 2;
+}
+
 static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type)
 {
-        const char *clk_name = np->full_name;
-        struct clk *clk;
-        void __iomem *reg;
-
-        reg = of_iomap(np, 0);
-        if (reg == NULL) {
-                pr_err("Unable to map CSR register for %s\n", np->full_name);
-                return;
-        }
-        of_property_read_string(np, "clock-output-names", &clk_name);
-        clk = xgene_register_clk_pll(NULL,
-                        clk_name, of_clk_get_parent_name(np, 0),
-                        CLK_IS_ROOT, reg, 0, pll_type, &clk_lock);
-        if (!IS_ERR(clk)) {
-                of_clk_add_provider(np, of_clk_src_simple_get, clk);
-                clk_register_clkdev(clk, clk_name, NULL);
-                pr_debug("Add %s clock PLL\n", clk_name);
-        }
+	const char *clk_name = np->full_name;
+	struct clk *clk;
+	void __iomem *reg;
+	int version = xgene_pllclk_version(np);
+
+	reg = of_iomap(np, 0);
+	if (reg == NULL) {
+		pr_err("Unable to map CSR register for %s\n", np->full_name);
+		return;
+	}
+	of_property_read_string(np, "clock-output-names", &clk_name);
+	clk = xgene_register_clk_pll(NULL,
+			clk_name, of_clk_get_parent_name(np, 0),
+			CLK_IS_ROOT, reg, 0, pll_type, &clk_lock,
+			version);
+	if (!IS_ERR(clk)) {
+		of_clk_add_provider(np, of_clk_src_simple_get, clk);
+		clk_register_clkdev(clk, clk_name, NULL);
+		pr_debug("Add %s clock PLL\n", clk_name);
+	}
 }
 
 static void xgene_socpllclk_init(struct device_node *np)
@@ -218,22 +243,20 @@
 	struct xgene_clk *pclk = to_xgene_clk(hw);
 	unsigned long flags = 0;
 	u32 data;
-	phys_addr_t reg;
 
 	if (pclk->lock)
 		spin_lock_irqsave(pclk->lock, flags);
 
 	if (pclk->param.csr_reg != NULL) {
 		pr_debug("%s clock enabled\n", clk_hw_get_name(hw));
-		reg = __pa(pclk->param.csr_reg);
 		/* First enable the clock */
 		data = xgene_clk_read(pclk->param.csr_reg +
 					pclk->param.reg_clk_offset);
 		data |= pclk->param.reg_clk_mask;
 		xgene_clk_write(data, pclk->param.csr_reg +
 					pclk->param.reg_clk_offset);
-		pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n",
-			clk_hw_get_name(hw), &reg,
+		pr_debug("%s clk offset 0x%08X mask 0x%08X value 0x%08X\n",
+			clk_hw_get_name(hw),
 			pclk->param.reg_clk_offset, pclk->param.reg_clk_mask,
 			data);
 
@@ -243,8 +266,8 @@
 		data &= ~pclk->param.reg_csr_mask;
 		xgene_clk_write(data, pclk->param.csr_reg +
 					pclk->param.reg_csr_offset);
-		pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n",
-			clk_hw_get_name(hw), &reg,
+		pr_debug("%s csr offset 0x%08X mask 0x%08X value 0x%08X\n",
+			clk_hw_get_name(hw),
 			pclk->param.reg_csr_offset, pclk->param.reg_csr_mask,
 			data);
 	}
@@ -351,7 +374,8 @@
 		/* Set new divider */
 		data = xgene_clk_read(pclk->param.divider_reg +
 				pclk->param.reg_divider_offset);
-		data &= ~((1 << pclk->param.reg_divider_width) - 1);
+		data &= ~(((1 << pclk->param.reg_divider_width) - 1)
+				<< pclk->param.reg_divider_shift);
 		data |= divider;
 		xgene_clk_write(data, pclk->param.divider_reg +
 					pclk->param.reg_divider_offset);
@@ -459,7 +483,7 @@
 		rc = of_address_to_resource(np, i, &res);
 		if (rc != 0) {
 			if (i == 0) {
-				pr_err("no DTS register for %s\n", 
+				pr_err("no DTS register for %s\n",
 					np->full_name);
 				return;
 			}
@@ -517,4 +541,8 @@
 
 CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init);
 CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init);
+CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock",
+	       xgene_socpllclk_init);
+CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock",
+	       xgene_pcppllclk_init);
 CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init);
--- linux-4.4.0.orig/drivers/clk/clk.c
+++ linux-4.4.0/drivers/clk/clk.c
@@ -1905,6 +1905,9 @@
 	int ret;
 
 	clk_prepare_lock();
+	/* Always try to update cached phase if possible */
+	if (core->ops->get_phase)
+		core->phase = core->ops->get_phase(core->hw);
 	ret = core->phase;
 	clk_prepare_unlock();
 
--- linux-4.4.0.orig/drivers/clk/imx/clk-imx31.c
+++ linux-4.4.0/drivers/clk/imx/clk-imx31.c
@@ -157,10 +157,8 @@
 	}
 }
 
-int __init mx31_clocks_init(void)
+int __init mx31_clocks_init(unsigned long fref)
 {
-	u32 fref = 26000000; /* default */
-
 	_mx31_clocks_init(fref);
 
 	clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0");
--- linux-4.4.0.orig/drivers/clk/imx/clk-imx35.c
+++ linux-4.4.0/drivers/clk/imx/clk-imx35.c
@@ -66,7 +66,7 @@
 static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"};
 
 enum mx35_clks {
-	ckih, ckil, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg,
+	ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg,
 	arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel,
 	esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre,
 	spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre,
@@ -79,7 +79,7 @@
 	rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate,
 	ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate,
 	wdog_gate, max_gate, admux_gate, csi_gate, csi_div, csi_sel, iim_gate,
-	gpu2d_gate, clk_max
+	gpu2d_gate, ckil, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -115,7 +115,7 @@
 	}
 
 	clk[ckih] = imx_clk_fixed("ckih", 24000000);
-	clk[ckil] = imx_clk_fixed("ckih", 32768);
+	clk[ckil] = imx_clk_fixed("ckil", 32768);
 	clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL);
 	clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL);
 
--- linux-4.4.0.orig/drivers/clk/imx/clk-imx6q.c
+++ linux-4.4.0/drivers/clk/imx/clk-imx6q.c
@@ -155,6 +155,7 @@
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
+	of_node_put(np);
 
 	/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
 	if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
@@ -239,8 +240,12 @@
 	 * lvds1_gate and lvds2_gate are pseudo-gates.  Both can be
 	 * independently configured as clock inputs or outputs.  We treat
 	 * the "output_enable" bit as a gate, even though it's really just
-	 * enabling clock output.
+	 * enabling clock output. Initially the gate bits are cleared, as
+	 * otherwise the exclusive configuration gets locked in the setup done
+	 * by software running before the clock driver, with no way to change
+	 * it.
 	 */
+	writel(readl(base + 0x160) & ~0x3c00, base + 0x160);
 	clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
 	clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
 
@@ -419,7 +424,7 @@
 		clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
 	clk[IMX6QDL_CLK_GPU3D_CORE]   = imx_clk_gate2("gpu3d_core",    "gpu3d_core_podf",   base + 0x6c, 26);
 	clk[IMX6QDL_CLK_HDMI_IAHB]    = imx_clk_gate2("hdmi_iahb",     "ahb",               base + 0x70, 0);
-	clk[IMX6QDL_CLK_HDMI_ISFR]    = imx_clk_gate2("hdmi_isfr",     "video_27m",         base + 0x70, 4);
+	clk[IMX6QDL_CLK_HDMI_ISFR]    = imx_clk_gate2("hdmi_isfr",     "mipi_core_cfg",     base + 0x70, 4);
 	clk[IMX6QDL_CLK_I2C1]         = imx_clk_gate2("i2c1",          "ipg_per",           base + 0x70, 6);
 	clk[IMX6QDL_CLK_I2C2]         = imx_clk_gate2("i2c2",          "ipg_per",           base + 0x70, 8);
 	clk[IMX6QDL_CLK_I2C3]         = imx_clk_gate2("i2c3",          "ipg_per",           base + 0x70, 10);
@@ -550,6 +555,24 @@
 	if (IS_ENABLED(CONFIG_PCI_IMX6))
 		clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
 
+	/*
+	 * Initialize the GPU clock muxes, so that the maximum specified clock
+	 * rates for the respective SoC are not exceeded.
+	 */
+	if (clk_on_imx6dl()) {
+		clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
+			       clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+		clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
+			       clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+	} else if (clk_on_imx6q()) {
+		clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
+			       clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
+		clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL],
+			       clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+		clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
+			       clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+	}
+
 	imx_register_uart_clocks(uart_clks);
 }
 CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
--- linux-4.4.0.orig/drivers/clk/imx/clk-imx6sl.c
+++ linux-4.4.0/drivers/clk/imx/clk-imx6sl.c
@@ -17,6 +17,8 @@
 
 #include "clk.h"
 
+#define CCDR				0x4
+#define BM_CCM_CCDR_MMDC_CH0_MASK	(1 << 17)
 #define CCSR			0xc
 #define BM_CCSR_PLL1_SW_CLK_SEL	(1 << 2)
 #define CACRR			0x10
@@ -414,6 +416,10 @@
 	clks[IMX6SL_CLK_USDHC3]       = imx_clk_gate2("usdhc3",       "usdhc3_podf",       base + 0x80, 6);
 	clks[IMX6SL_CLK_USDHC4]       = imx_clk_gate2("usdhc4",       "usdhc4_podf",       base + 0x80, 8);
 
+	/* Ensure the MMDC CH0 handshake is bypassed */
+	writel_relaxed(readl_relaxed(base + CCDR) |
+		BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+
 	imx_check_clocks(clks, ARRAY_SIZE(clks));
 
 	clk_data.clks = clks;
--- linux-4.4.0.orig/drivers/clk/imx/clk-imx6sx.c
+++ linux-4.4.0/drivers/clk/imx/clk-imx6sx.c
@@ -162,6 +162,7 @@
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
+	of_node_put(np);
 
 	clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
 	clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
--- linux-4.4.0.orig/drivers/clk/imx/clk-imx6ul.c
+++ linux-4.4.0/drivers/clk/imx/clk-imx6ul.c
@@ -120,6 +120,7 @@
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop");
 	base = of_iomap(np, 0);
+	of_node_put(np);
 	WARN_ON(!base);
 
 	clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
--- linux-4.4.0.orig/drivers/clk/imx/clk-imx7d.c
+++ linux-4.4.0/drivers/clk/imx/clk-imx7d.c
@@ -386,6 +386,7 @@
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
+	of_node_put(np);
 
 	clks[IMX7D_PLL_ARM_MAIN_SRC]  = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
 	clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
--- linux-4.4.0.orig/drivers/clk/imx/clk-pllv3.c
+++ linux-4.4.0/drivers/clk/imx/clk-pllv3.c
@@ -76,9 +76,9 @@
 
 	val = readl_relaxed(pll->base);
 	if (pll->powerup_set)
-		val |= BM_PLL_POWER;
+		val |= pll->powerdown;
 	else
-		val &= ~BM_PLL_POWER;
+		val &= ~pll->powerdown;
 	writel_relaxed(val, pll->base);
 
 	return clk_pllv3_wait_lock(pll);
@@ -91,9 +91,9 @@
 
 	val = readl_relaxed(pll->base);
 	if (pll->powerup_set)
-		val &= ~BM_PLL_POWER;
+		val &= ~pll->powerdown;
 	else
-		val |= BM_PLL_POWER;
+		val |= pll->powerdown;
 	writel_relaxed(val, pll->base);
 }
 
--- linux-4.4.0.orig/drivers/clk/imx/clk-vf610.c
+++ linux-4.4.0/drivers/clk/imx/clk-vf610.c
@@ -155,6 +155,7 @@
 	np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop");
 	anatop_base = of_iomap(np, 0);
 	BUG_ON(!anatop_base);
+	of_node_put(np);
 
 	np = ccm_node;
 	ccm_base = of_iomap(np, 0);
--- linux-4.4.0.orig/drivers/clk/ingenic/cgu.c
+++ linux-4.4.0/drivers/clk/ingenic/cgu.c
@@ -355,16 +355,16 @@
 	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
 	struct ingenic_cgu *cgu = ingenic_clk->cgu;
 	const struct ingenic_cgu_clk_info *clk_info;
-	long rate = *parent_rate;
+	unsigned int div = 1;
 
 	clk_info = &cgu->clock_info[ingenic_clk->idx];
 
 	if (clk_info->type & CGU_CLK_DIV)
-		rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
+		div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
 	else if (clk_info->type & CGU_CLK_FIXDIV)
-		rate /= clk_info->fixdiv.div;
+		div = clk_info->fixdiv.div;
 
-	return rate;
+	return DIV_ROUND_UP(*parent_rate, div);
 }
 
 static int
@@ -384,7 +384,7 @@
 
 	if (clk_info->type & CGU_CLK_DIV) {
 		div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
-		rate = parent_rate / div;
+		rate = DIV_ROUND_UP(parent_rate, div);
 
 		if (rate != req_rate)
 			return -EINVAL;
--- linux-4.4.0.orig/drivers/clk/mediatek/clk-mtk.h
+++ linux-4.4.0/drivers/clk/mediatek/clk-mtk.h
@@ -174,6 +174,7 @@
 	uint32_t pcw_reg;
 	int pcw_shift;
 	const struct mtk_pll_div_table *div_table;
+	const char *parent_name;
 };
 
 void mtk_clk_register_plls(struct device_node *node,
--- linux-4.4.0.orig/drivers/clk/mediatek/clk-pll.c
+++ linux-4.4.0/drivers/clk/mediatek/clk-pll.c
@@ -302,7 +302,10 @@
 
 	init.name = data->name;
 	init.ops = &mtk_pll_ops;
-	init.parent_names = &parent_name;
+	if (data->parent_name)
+		init.parent_names = &data->parent_name;
+	else
+		init.parent_names = &parent_name;
 	init.num_parents = 1;
 
 	clk = clk_register(NULL, &pll->hw);
--- linux-4.4.0.orig/drivers/clk/meson/clk-pll.c
+++ linux-4.4.0/drivers/clk/meson/clk-pll.c
@@ -138,7 +138,7 @@
 	if (parent_rate == 0 || rate == 0)
 		return -EINVAL;
 
-	old_rate = rate;
+	old_rate = clk_hw_get_rate(hw);
 
 	rate_set = meson_clk_get_pll_settings(pll, rate);
 	if (!rate_set)
--- linux-4.4.0.orig/drivers/clk/meson/clkc.c
+++ linux-4.4.0/drivers/clk/meson/clkc.c
@@ -198,7 +198,7 @@
 }
 
 void __init meson_clk_register_clks(const struct clk_conf *clk_confs,
-				    size_t nr_confs,
+				    unsigned int nr_confs,
 				    void __iomem *clk_base)
 {
 	unsigned int i;
--- linux-4.4.0.orig/drivers/clk/mmp/clk-of-mmp2.c
+++ linux-4.4.0/drivers/clk/mmp/clk-of-mmp2.c
@@ -134,7 +134,7 @@
 static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
 
 static DEFINE_SPINLOCK(timer_lock);
-static const char *timer_parent_names[] = {"clk32", "vctcxo_2", "vctcxo_4", "vctcxo"};
+static const char *timer_parent_names[] = {"clk32", "vctcxo_4", "vctcxo_2", "vctcxo"};
 
 static DEFINE_SPINLOCK(reset_lock);
 
@@ -227,8 +227,8 @@
 	/* The gate clocks has mux parent. */
 	{MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
 	{MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
-	{MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
-	{MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
+	{MMP2_CLK_SDH2, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
+	{MMP2_CLK_SDH3, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
 	{MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
 	{MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock},
 	{MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock},
@@ -313,7 +313,7 @@
 	}
 
 	pxa_unit->apmu_base = of_iomap(np, 1);
-	if (!pxa_unit->mpmu_base) {
+	if (!pxa_unit->apmu_base) {
 		pr_err("failed to map apmu registers\n");
 		return;
 	}
--- linux-4.4.0.orig/drivers/clk/mmp/clk-of-pxa168.c
+++ linux-4.4.0/drivers/clk/mmp/clk-of-pxa168.c
@@ -262,7 +262,7 @@
 	}
 
 	pxa_unit->apmu_base = of_iomap(np, 1);
-	if (!pxa_unit->mpmu_base) {
+	if (!pxa_unit->apmu_base) {
 		pr_err("failed to map apmu registers\n");
 		return;
 	}
--- linux-4.4.0.orig/drivers/clk/mmp/clk-of-pxa910.c
+++ linux-4.4.0/drivers/clk/mmp/clk-of-pxa910.c
@@ -282,7 +282,7 @@
 	}
 
 	pxa_unit->apmu_base = of_iomap(np, 1);
-	if (!pxa_unit->mpmu_base) {
+	if (!pxa_unit->apmu_base) {
 		pr_err("failed to map apmu registers\n");
 		return;
 	}
@@ -294,7 +294,7 @@
 	}
 
 	pxa_unit->apbcp_base = of_iomap(np, 3);
-	if (!pxa_unit->mpmu_base) {
+	if (!pxa_unit->apbcp_base) {
 		pr_err("failed to map apbcp registers\n");
 		return;
 	}
--- linux-4.4.0.orig/drivers/clk/mmp/clk.c
+++ linux-4.4.0/drivers/clk/mmp/clk.c
@@ -182,7 +182,7 @@
 		pr_err("CLK %d has invalid pointer %p\n", id, clk);
 		return;
 	}
-	if (id > unit->nr_clks) {
+	if (id >= unit->nr_clks) {
 		pr_err("CLK %d is invalid\n", id);
 		return;
 	}
--- linux-4.4.0.orig/drivers/clk/mvebu/armada-370.c
+++ linux-4.4.0/drivers/clk/mvebu/armada-370.c
@@ -177,8 +177,10 @@
 
 	mvebu_coreclk_setup(np, &a370_coreclks);
 
-	if (cgnp)
+	if (cgnp) {
 		mvebu_clk_gating_setup(cgnp, a370_gating_desc);
+		of_node_put(cgnp);
+	}
 }
 CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init);
 
--- linux-4.4.0.orig/drivers/clk/mvebu/armada-38x.c
+++ linux-4.4.0/drivers/clk/mvebu/armada-38x.c
@@ -46,10 +46,11 @@
 }
 
 static const u32 armada_38x_cpu_frequencies[] __initconst = {
-	0, 0, 0, 0,
-	1066 * 1000 * 1000, 0, 0, 0,
+	666 * 1000 * 1000,  0, 800 * 1000 * 1000, 0,
+	1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0,
 	1332 * 1000 * 1000, 0, 0, 0,
-	1600 * 1000 * 1000,
+	1600 * 1000 * 1000, 0, 0, 0,
+	1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000,
 };
 
 static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
@@ -75,11 +76,11 @@
 };
 
 static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
-	{0, 1}, {0, 1}, {0, 1}, {0, 1},
-	{1, 2}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {1, 2}, {0, 1},
+	{1, 2}, {0, 1}, {1, 2}, {0, 1},
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
-	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {1, 2},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
@@ -90,7 +91,7 @@
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
-	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {7, 15},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
--- linux-4.4.0.orig/drivers/clk/mvebu/armada-xp.c
+++ linux-4.4.0/drivers/clk/mvebu/armada-xp.c
@@ -202,7 +202,9 @@
 
 	mvebu_coreclk_setup(np, &axp_coreclks);
 
-	if (cgnp)
+	if (cgnp) {
 		mvebu_clk_gating_setup(cgnp, axp_gating_desc);
+		of_node_put(cgnp);
+	}
 }
 CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init);
--- linux-4.4.0.orig/drivers/clk/mvebu/kirkwood.c
+++ linux-4.4.0/drivers/clk/mvebu/kirkwood.c
@@ -335,6 +335,8 @@
 	if (cgnp) {
 		mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
 		kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc);
+
+		of_node_put(cgnp);
 	}
 }
 CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
--- linux-4.4.0.orig/drivers/clk/nxp/clk-lpc18xx-ccu.c
+++ linux-4.4.0/drivers/clk/nxp/clk-lpc18xx-ccu.c
@@ -222,7 +222,7 @@
 		div->width = 1;
 
 		div_hw = &div->hw;
-		div_ops = &clk_divider_ops;
+		div_ops = &clk_divider_ro_ops;
 	}
 
 	branch->gate.reg = branch->offset + reg_base;
--- linux-4.4.0.orig/drivers/clk/pxa/clk-pxa27x.c
+++ linux-4.4.0/drivers/clk/pxa/clk-pxa27x.c
@@ -362,6 +362,7 @@
 };
 static struct dummy_clk dummy_clks[] __initdata = {
 	DUMMY_CLK(NULL, "pxa27x-gpio", "osc_32_768khz"),
+	DUMMY_CLK(NULL, "pxa-rtc", "osc_32_768khz"),
 	DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"),
 	DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"),
 };
--- linux-4.4.0.orig/drivers/clk/qcom/clk-rcg2.c
+++ linux-4.4.0/drivers/clk/qcom/clk-rcg2.c
@@ -107,7 +107,7 @@
 	}
 
 	WARN(1, "%s: rcg didn't update its configuration.", name);
-	return 0;
+	return -EBUSY;
 }
 
 static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
@@ -194,8 +194,13 @@
 
 	clk_flags = clk_hw_get_flags(hw);
 	p = clk_hw_get_parent_by_index(hw, index);
+	if (!p)
+		return -EINVAL;
+
 	if (clk_flags & CLK_SET_RATE_PARENT) {
 		if (f->pre_div) {
+			if (!rate)
+				rate = req->rate;
 			rate /= 2;
 			rate *= f->pre_div + 1;
 		}
--- linux-4.4.0.orig/drivers/clk/qcom/common.c
+++ linux-4.4.0/drivers/clk/qcom/common.c
@@ -36,6 +36,9 @@
 	if (!f)
 		return NULL;
 
+	if (!f->freq)
+		return f;
+
 	for (; f->freq; f++)
 		if (rate <= f->freq)
 			return f;
--- linux-4.4.0.orig/drivers/clk/qcom/gcc-msm8916.c
+++ linux-4.4.0/drivers/clk/qcom/gcc-msm8916.c
@@ -270,7 +270,7 @@
 	.l_reg = 0x21004,
 	.m_reg = 0x21008,
 	.n_reg = 0x2100c,
-	.config_reg = 0x21014,
+	.config_reg = 0x21010,
 	.mode_reg = 0x21000,
 	.status_reg = 0x2101c,
 	.status_bit = 17,
@@ -297,7 +297,7 @@
 	.l_reg = 0x20004,
 	.m_reg = 0x20008,
 	.n_reg = 0x2000c,
-	.config_reg = 0x20014,
+	.config_reg = 0x20010,
 	.mode_reg = 0x20000,
 	.status_reg = 0x2001c,
 	.status_bit = 17,
@@ -324,7 +324,7 @@
 	.l_reg = 0x4a004,
 	.m_reg = 0x4a008,
 	.n_reg = 0x4a00c,
-	.config_reg = 0x4a014,
+	.config_reg = 0x4a010,
 	.mode_reg = 0x4a000,
 	.status_reg = 0x4a01c,
 	.status_bit = 17,
@@ -351,7 +351,7 @@
 	.l_reg = 0x23004,
 	.m_reg = 0x23008,
 	.n_reg = 0x2300c,
-	.config_reg = 0x23014,
+	.config_reg = 0x23010,
 	.mode_reg = 0x23000,
 	.status_reg = 0x2301c,
 	.status_bit = 17,
@@ -1437,6 +1437,7 @@
 
 static struct clk_rcg2 codec_digcodec_clk_src = {
 	.cmd_rcgr = 0x1c09c,
+	.mnd_width = 8,
 	.hid_width = 5,
 	.parent_map = gcc_xo_gpll1_emclk_sleep_map,
 	.freq_tbl = ftbl_codec_clk,
@@ -2346,6 +2347,7 @@
 				"pcnoc_bfdcd_clk_src",
 			},
 			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -2381,6 +2383,7 @@
 				"crypto_clk_src",
 			},
 			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
--- linux-4.4.0.orig/drivers/clk/qcom/gcc-msm8960.c
+++ linux-4.4.0/drivers/clk/qcom/gcc-msm8960.c
@@ -2753,7 +2753,7 @@
 	},
 	.freq_tbl = clk_tbl_ce3,
 	.clkr = {
-		.enable_reg = 0x2c08,
+		.enable_reg = 0x36c0,
 		.enable_mask = BIT(7),
 		.hw.init = &(struct clk_init_data){
 			.name = "ce3_src",
@@ -2769,7 +2769,7 @@
 	.halt_reg = 0x2fdc,
 	.halt_bit = 5,
 	.clkr = {
-		.enable_reg = 0x36c4,
+		.enable_reg = 0x36cc,
 		.enable_mask = BIT(4),
 		.hw.init = &(struct clk_init_data){
 			.name = "ce3_core_clk",
--- linux-4.4.0.orig/drivers/clk/qcom/mmcc-apq8084.c
+++ linux-4.4.0/drivers/clk/qcom/mmcc-apq8084.c
@@ -343,6 +343,7 @@
 	F(333430000, P_MMPLL1, 3.5, 0, 0),
 	F(400000000, P_MMPLL0, 2, 0, 0),
 	F(466800000, P_MMPLL1, 2.5, 0, 0),
+	{ }
 };
 
 static struct clk_rcg2 mmss_axi_clk_src = {
@@ -367,6 +368,7 @@
 	F(150000000, P_GPLL0, 4, 0, 0),
 	F(228570000, P_MMPLL0, 3.5, 0, 0),
 	F(320000000, P_MMPLL0, 2.5, 0, 0),
+	{ }
 };
 
 static struct clk_rcg2 ocmemnoc_clk_src = {
--- linux-4.4.0.orig/drivers/clk/rockchip/clk-mmc-phase.c
+++ linux-4.4.0/drivers/clk/rockchip/clk-mmc-phase.c
@@ -41,8 +41,6 @@
 #define ROCKCHIP_MMC_DEGREE_MASK 0x3
 #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
 #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
-#define ROCKCHIP_MMC_INIT_STATE_RESET 0x1
-#define ROCKCHIP_MMC_INIT_STATE_SHIFT 1
 
 #define PSECS_PER_SEC 1000000000000LL
 
@@ -60,6 +58,10 @@
 	u16 degrees;
 	u32 delay_num = 0;
 
+	/* See the comment for rockchip_mmc_set_phase below */
+	if (!rate)
+		return -EINVAL;
+
 	raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);
 
 	degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
@@ -86,6 +88,23 @@
 	u32 raw_value;
 	u32 delay;
 
+	/*
+	 * The below calculation is based on the output clock from
+	 * MMC host to the card, which expects the phase clock inherits
+	 * the clock rate from its parent, namely the output clock
+	 * provider of MMC host. However, things may go wrong if
+	 * (1) It is orphan.
+	 * (2) It is assigned to the wrong parent.
+	 *
+	 * This check help debug the case (1), which seems to be the
+	 * most likely problem we often face and which makes it difficult
+	 * for people to debug unstable mmc tuning results.
+	 */
+	if (!rate) {
+		pr_err("%s: invalid clk rate\n", __func__);
+		return -EINVAL;
+	}
+
 	nineties = degrees / 90;
 	remainder = (degrees % 90);
 
@@ -153,6 +172,7 @@
 		return NULL;
 
 	init.name = name;
+	init.flags = 0;
 	init.num_parents = num_parents;
 	init.parent_names = parent_names;
 	init.ops = &rockchip_mmc_clk_ops;
@@ -161,15 +181,6 @@
 	mmc_clock->reg = reg;
 	mmc_clock->shift = shift;
 
-	/*
-	 * Assert init_state to soft reset the CLKGEN
-	 * for mmc tuning phase and degree
-	 */
-	if (mmc_clock->shift == ROCKCHIP_MMC_INIT_STATE_SHIFT)
-		writel(HIWORD_UPDATE(ROCKCHIP_MMC_INIT_STATE_RESET,
-				     ROCKCHIP_MMC_INIT_STATE_RESET,
-				     mmc_clock->shift), mmc_clock->reg);
-
 	clk = clk_register(NULL, &mmc_clock->hw);
 	if (IS_ERR(clk))
 		goto err_free;
--- linux-4.4.0.orig/drivers/clk/rockchip/clk-rk3188.c
+++ linux-4.4.0/drivers/clk/rockchip/clk-rk3188.c
@@ -329,8 +329,8 @@
 			RK2928_CLKGATE_CON(2), 5, GFLAGS),
 	MUX(SCLK_MAC, "sclk_macref", mux_sclk_macref_p, CLK_SET_RATE_PARENT,
 			RK2928_CLKSEL_CON(21), 4, 1, MFLAGS),
-	GATE(0, "sclk_mac_lbtest", "sclk_macref",
-			RK2928_CLKGATE_CON(2), 12, 0, GFLAGS),
+	GATE(0, "sclk_mac_lbtest", "sclk_macref", 0,
+			RK2928_CLKGATE_CON(2), 12, GFLAGS),
 
 	COMPOSITE(0, "hsadc_src", mux_pll_src_gpll_cpll_p, 0,
 			RK2928_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS,
@@ -360,8 +360,8 @@
 	 * Clock-Architecture Diagram 4
 	 */
 
-	GATE(SCLK_SMC, "sclk_smc", "hclk_peri",
-			RK2928_CLKGATE_CON(2), 4, 0, GFLAGS),
+	GATE(SCLK_SMC, "sclk_smc", "hclk_peri", 0,
+			RK2928_CLKGATE_CON(2), 4, GFLAGS),
 
 	COMPOSITE_NOMUX(SCLK_SPI0, "sclk_spi0", "pclk_peri", 0,
 			RK2928_CLKSEL_CON(25), 0, 7, DFLAGS,
@@ -718,6 +718,7 @@
 	"hclk_peri",
 	"pclk_cpu",
 	"pclk_peri",
+	"hclk_cpubus"
 };
 
 static void __init rk3188_common_clk_init(struct device_node *np)
--- linux-4.4.0.orig/drivers/clk/rockchip/clk-rk3288.c
+++ linux-4.4.0/drivers/clk/rockchip/clk-rk3288.c
@@ -797,6 +797,9 @@
 	RK3288_CLKSEL_CON(10),
 	RK3288_CLKSEL_CON(33),
 	RK3288_CLKSEL_CON(37),
+
+	/* We turn aclk_dmac1 on for suspend; this will restore it */
+	RK3288_CLKGATE_CON(10),
 };
 
 static u32 rk3288_saved_cru_regs[ARRAY_SIZE(rk3288_saved_cru_reg_ids)];
@@ -813,6 +816,14 @@
 	}
 
 	/*
+	 * Going into deep sleep (specifically setting PMU_CLR_DMA in
+	 * RK3288_PMU_PWRMODE_CON1) appears to fail unless
+	 * "aclk_dmac1" is on.
+	 */
+	writel_relaxed(1 << (12 + 16),
+		       rk3288_cru_base + RK3288_CLKGATE_CON(10));
+
+	/*
 	 * Switch PLLs other than DPLL (for SDRAM) to slow mode to
 	 * avoid crashes on resume. The Mask ROM on the system will
 	 * put APLL, CPLL, and GPLL into slow mode at resume time
--- linux-4.4.0.orig/drivers/clk/rockchip/clk-rk3368.c
+++ linux-4.4.0/drivers/clk/rockchip/clk-rk3368.c
@@ -165,7 +165,7 @@
 	.core_reg = RK3368_CLKSEL_CON(0),
 	.div_core_shift = 0,
 	.div_core_mask = 0x1f,
-	.mux_core_shift = 15,
+	.mux_core_shift = 7,
 };
 
 static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = {
@@ -218,29 +218,29 @@
 	}
 
 static struct rockchip_cpuclk_rate_table rk3368_cpuclkb_rates[] __initdata = {
-	RK3368_CPUCLKB_RATE(1512000000, 2, 6, 6),
-	RK3368_CPUCLKB_RATE(1488000000, 2, 5, 5),
-	RK3368_CPUCLKB_RATE(1416000000, 2, 5, 5),
-	RK3368_CPUCLKB_RATE(1200000000, 2, 4, 4),
-	RK3368_CPUCLKB_RATE(1008000000, 2, 4, 4),
-	RK3368_CPUCLKB_RATE( 816000000, 2, 3, 3),
-	RK3368_CPUCLKB_RATE( 696000000, 2, 3, 3),
-	RK3368_CPUCLKB_RATE( 600000000, 2, 2, 2),
-	RK3368_CPUCLKB_RATE( 408000000, 2, 2, 2),
-	RK3368_CPUCLKB_RATE( 312000000, 2, 2, 2),
+	RK3368_CPUCLKB_RATE(1512000000, 1, 5, 5),
+	RK3368_CPUCLKB_RATE(1488000000, 1, 4, 4),
+	RK3368_CPUCLKB_RATE(1416000000, 1, 4, 4),
+	RK3368_CPUCLKB_RATE(1200000000, 1, 3, 3),
+	RK3368_CPUCLKB_RATE(1008000000, 1, 3, 3),
+	RK3368_CPUCLKB_RATE( 816000000, 1, 2, 2),
+	RK3368_CPUCLKB_RATE( 696000000, 1, 2, 2),
+	RK3368_CPUCLKB_RATE( 600000000, 1, 1, 1),
+	RK3368_CPUCLKB_RATE( 408000000, 1, 1, 1),
+	RK3368_CPUCLKB_RATE( 312000000, 1, 1, 1),
 };
 
 static struct rockchip_cpuclk_rate_table rk3368_cpuclkl_rates[] __initdata = {
-	RK3368_CPUCLKL_RATE(1512000000, 2, 7, 7),
-	RK3368_CPUCLKL_RATE(1488000000, 2, 6, 6),
-	RK3368_CPUCLKL_RATE(1416000000, 2, 6, 6),
-	RK3368_CPUCLKL_RATE(1200000000, 2, 5, 5),
-	RK3368_CPUCLKL_RATE(1008000000, 2, 5, 5),
-	RK3368_CPUCLKL_RATE( 816000000, 2, 4, 4),
-	RK3368_CPUCLKL_RATE( 696000000, 2, 3, 3),
-	RK3368_CPUCLKL_RATE( 600000000, 2, 3, 3),
-	RK3368_CPUCLKL_RATE( 408000000, 2, 2, 2),
-	RK3368_CPUCLKL_RATE( 312000000, 2, 2, 2),
+	RK3368_CPUCLKL_RATE(1512000000, 1, 6, 6),
+	RK3368_CPUCLKL_RATE(1488000000, 1, 5, 5),
+	RK3368_CPUCLKL_RATE(1416000000, 1, 5, 5),
+	RK3368_CPUCLKL_RATE(1200000000, 1, 4, 4),
+	RK3368_CPUCLKL_RATE(1008000000, 1, 4, 4),
+	RK3368_CPUCLKL_RATE( 816000000, 1, 3, 3),
+	RK3368_CPUCLKL_RATE( 696000000, 1, 2, 2),
+	RK3368_CPUCLKL_RATE( 600000000, 1, 2, 2),
+	RK3368_CPUCLKL_RATE( 408000000, 1, 1, 1),
+	RK3368_CPUCLKL_RATE( 312000000, 1, 1, 1),
 };
 
 static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
@@ -384,10 +384,10 @@
 	 * Clock-Architecture Diagram 3
 	 */
 
-	COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_usb_p, 0,
+	COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_npll_usb_p, 0,
 			RK3368_CLKSEL_CON(15), 6, 2, MFLAGS, 0, 5, DFLAGS,
 			RK3368_CLKGATE_CON(4), 6, GFLAGS),
-	COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb_p, 0,
+	COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_npll_usb_p, 0,
 			RK3368_CLKSEL_CON(15), 14, 2, MFLAGS, 8, 5, DFLAGS,
 			RK3368_CLKGATE_CON(4), 7, GFLAGS),
 
@@ -442,7 +442,7 @@
 	GATE(SCLK_HDMI_HDCP, "sclk_hdmi_hdcp", "xin24m", 0,
 			RK3368_CLKGATE_CON(4), 13, GFLAGS),
 	GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0,
-			RK3368_CLKGATE_CON(5), 12, GFLAGS),
+			RK3368_CLKGATE_CON(4), 12, GFLAGS),
 
 	COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0,
 			RK3368_CLKSEL_CON(21), 15, 1, MFLAGS,
--- linux-4.4.0.orig/drivers/clk/rockchip/clk.c
+++ linux-4.4.0/drivers/clk/rockchip/clk.c
@@ -70,7 +70,7 @@
 	if (gate_offset >= 0) {
 		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
 		if (!gate)
-			return ERR_PTR(-ENOMEM);
+			goto err_gate;
 
 		gate->flags = gate_flags;
 		gate->reg = base + gate_offset;
@@ -82,7 +82,7 @@
 	if (div_width > 0) {
 		div = kzalloc(sizeof(*div), GFP_KERNEL);
 		if (!div)
-			return ERR_PTR(-ENOMEM);
+			goto err_div;
 
 		div->flags = div_flags;
 		div->reg = base + muxdiv_offset;
@@ -90,7 +90,9 @@
 		div->width = div_width;
 		div->lock = lock;
 		div->table = div_table;
-		div_ops = &clk_divider_ops;
+		div_ops = (div_flags & CLK_DIVIDER_READ_ONLY)
+						? &clk_divider_ro_ops
+						: &clk_divider_ops;
 	}
 
 	clk = clk_register_composite(NULL, name, parent_names, num_parents,
@@ -100,6 +102,11 @@
 				     flags);
 
 	return clk;
+err_div:
+	kfree(gate);
+err_gate:
+	kfree(mux);
+	return ERR_PTR(-ENOMEM);
 }
 
 static struct clk *rockchip_clk_register_frac_branch(const char *name,
--- linux-4.4.0.orig/drivers/clk/samsung/clk-cpu.c
+++ linux-4.4.0/drivers/clk/samsung/clk-cpu.c
@@ -148,6 +148,7 @@
 	unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent);
 	unsigned long alt_div = 0, alt_div_mask = DIV_MASK;
 	unsigned long div0, div1 = 0, mux_reg;
+	unsigned long flags;
 
 	/* find out the divider values to use for clock data */
 	while ((cfg_data->prate * 1000) != ndata->new_rate) {
@@ -156,7 +157,7 @@
 		cfg_data++;
 	}
 
-	spin_lock(cpuclk->lock);
+	spin_lock_irqsave(cpuclk->lock, flags);
 
 	/*
 	 * For the selected PLL clock frequency, get the pre-defined divider
@@ -212,7 +213,7 @@
 				DIV_MASK_ALL);
 	}
 
-	spin_unlock(cpuclk->lock);
+	spin_unlock_irqrestore(cpuclk->lock, flags);
 	return 0;
 }
 
@@ -223,6 +224,7 @@
 	const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
 	unsigned long div = 0, div_mask = DIV_MASK;
 	unsigned long mux_reg;
+	unsigned long flags;
 
 	/* find out the divider values to use for clock data */
 	if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) {
@@ -233,7 +235,7 @@
 		}
 	}
 
-	spin_lock(cpuclk->lock);
+	spin_lock_irqsave(cpuclk->lock, flags);
 
 	/* select mout_apll as the alternate parent */
 	mux_reg = readl(base + E4210_SRC_CPU);
@@ -246,7 +248,7 @@
 	}
 
 	exynos_set_safe_div(base, div, div_mask);
-	spin_unlock(cpuclk->lock);
+	spin_unlock_irqrestore(cpuclk->lock, flags);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/clk/samsung/clk-exynos3250.c
+++ linux-4.4.0/drivers/clk/samsung/clk-exynos3250.c
@@ -683,7 +683,7 @@
 	PLL_36XX_RATE(144000000,  96, 2, 3,     0),
 	PLL_36XX_RATE( 96000000, 128, 2, 4,     0),
 	PLL_36XX_RATE( 84000000, 112, 2, 4,     0),
-	PLL_36XX_RATE( 80000004, 106, 2, 4, 43691),
+	PLL_36XX_RATE( 80000003, 106, 2, 4, 43691),
 	PLL_36XX_RATE( 73728000,  98, 2, 4, 19923),
 	PLL_36XX_RATE( 67737598, 270, 3, 5, 62285),
 	PLL_36XX_RATE( 65535999, 174, 2, 5, 49982),
@@ -719,7 +719,7 @@
 	PLL_36XX_RATE(148352005,  98, 2, 3, 59070),
 	PLL_36XX_RATE(108000000, 144, 2, 4,     0),
 	PLL_36XX_RATE( 74250000,  99, 2, 4,     0),
-	PLL_36XX_RATE( 74176002,  98, 3, 4, 59070),
+	PLL_36XX_RATE( 74176002,  98, 2, 4, 59070),
 	PLL_36XX_RATE( 54054000, 216, 3, 5, 14156),
 	PLL_36XX_RATE( 54000000, 144, 2, 5,     0),
 	{ /* sentinel */ }
--- linux-4.4.0.orig/drivers/clk/samsung/clk-exynos4.c
+++ linux-4.4.0/drivers/clk/samsung/clk-exynos4.c
@@ -1059,7 +1059,7 @@
 	GATE(CLK_PCIE, "pcie", "aclk133", GATE_IP_FSYS, 14, 0, 0),
 	GATE(CLK_SMMU_PCIE, "smmu_pcie", "aclk133", GATE_IP_FSYS, 18, 0, 0),
 	GATE(CLK_MODEMIF, "modemif", "aclk100", GATE_IP_PERIL, 28, 0, 0),
-	GATE(CLK_CHIPID, "chipid", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0),
+	GATE(CLK_CHIPID, "chipid", "aclk100", E4210_GATE_IP_PERIR, 0, CLK_IGNORE_UNUSED, 0),
 	GATE(CLK_SYSREG, "sysreg", "aclk100", E4210_GATE_IP_PERIR, 0,
 			CLK_IGNORE_UNUSED, 0),
 	GATE(CLK_HDMI_CEC, "hdmi_cec", "aclk100", E4210_GATE_IP_PERIR, 11, 0,
@@ -1100,7 +1100,7 @@
 		0),
 	GATE(CLK_TSADC, "tsadc", "aclk133", E4X12_GATE_BUS_FSYS1, 16, 0, 0),
 	GATE(CLK_MIPI_HSI, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0),
-	GATE(CLK_CHIPID, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0),
+	GATE(CLK_CHIPID, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, CLK_IGNORE_UNUSED, 0),
 	GATE(CLK_SYSREG, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1,
 			CLK_IGNORE_UNUSED, 0),
 	GATE(CLK_HDMI_CEC, "hdmi_cec", "aclk100", E4X12_GATE_IP_PERIR, 11, 0,
@@ -1224,6 +1224,7 @@
 			xom = readl(chipid_base + 8);
 
 		iounmap(chipid_base);
+		of_node_put(np);
 	}
 
 	return xom;
--- linux-4.4.0.orig/drivers/clk/samsung/clk-exynos5250.c
+++ linux-4.4.0/drivers/clk/samsung/clk-exynos5250.c
@@ -711,13 +711,13 @@
 	/* sorted in descending order */
 	/* PLL_36XX_RATE(rate, m, p, s, k) */
 	PLL_36XX_RATE(192000000, 64, 2, 2, 0),
-	PLL_36XX_RATE(180633600, 90, 3, 2, 20762),
+	PLL_36XX_RATE(180633605, 90, 3, 2, 20762),
 	PLL_36XX_RATE(180000000, 90, 3, 2, 0),
 	PLL_36XX_RATE(73728000, 98, 2, 4, 19923),
-	PLL_36XX_RATE(67737600, 90, 2, 4, 20762),
+	PLL_36XX_RATE(67737602, 90, 2, 4, 20762),
 	PLL_36XX_RATE(49152000, 98, 3, 4, 19923),
-	PLL_36XX_RATE(45158400, 90, 3, 4, 20762),
-	PLL_36XX_RATE(32768000, 131, 3, 5, 4719),
+	PLL_36XX_RATE(45158401, 90, 3, 4, 20762),
+	PLL_36XX_RATE(32768001, 131, 3, 5, 4719),
 	{ },
 };
 
--- linux-4.4.0.orig/drivers/clk/samsung/clk-exynos5260.c
+++ linux-4.4.0/drivers/clk/samsung/clk-exynos5260.c
@@ -65,7 +65,7 @@
 	PLL_36XX_RATE(480000000, 160, 2, 2, 0),
 	PLL_36XX_RATE(432000000, 144, 2, 2, 0),
 	PLL_36XX_RATE(400000000, 200, 3, 2, 0),
-	PLL_36XX_RATE(394073130, 459, 7, 2, 49282),
+	PLL_36XX_RATE(394073128, 459, 7, 2, 49282),
 	PLL_36XX_RATE(333000000, 111, 2, 2, 0),
 	PLL_36XX_RATE(300000000, 100, 2, 2, 0),
 	PLL_36XX_RATE(266000000, 266, 3, 3, 0),
--- linux-4.4.0.orig/drivers/clk/samsung/clk-exynos5420.c
+++ linux-4.4.0/drivers/clk/samsung/clk-exynos5420.c
@@ -166,12 +166,20 @@
 	GATE_BUS_CPU,
 	GATE_SCLK_CPU,
 	CLKOUT_CMU_CPU,
+	APLL_CON0,
+	KPLL_CON0,
+	CPLL_CON0,
+	DPLL_CON0,
 	EPLL_CON0,
 	EPLL_CON1,
 	EPLL_CON2,
 	RPLL_CON0,
 	RPLL_CON1,
 	RPLL_CON2,
+	IPLL_CON0,
+	SPLL_CON0,
+	VPLL_CON0,
+	MPLL_CON0,
 	SRC_TOP0,
 	SRC_TOP1,
 	SRC_TOP2,
@@ -273,6 +281,7 @@
 	{ .offset = GATE_BUS_TOP,		.value = 0xffffffff, },
 	{ .offset = GATE_BUS_DISP1,		.value = 0xffffffff, },
 	{ .offset = GATE_IP_PERIC,		.value = 0xffffffff, },
+	{ .offset = GATE_IP_PERIS,		.value = 0xffffffff, },
 };
 
 static int exynos5420_clk_suspend(void)
--- linux-4.4.0.orig/drivers/clk/samsung/clk-exynos5433.c
+++ linux-4.4.0/drivers/clk/samsung/clk-exynos5433.c
@@ -747,7 +747,7 @@
 	PLL_35XX_RATE(800000000U,  400, 6,  1),
 	PLL_35XX_RATE(733000000U,  733, 12, 1),
 	PLL_35XX_RATE(700000000U,  175, 3,  1),
-	PLL_35XX_RATE(667000000U,  222, 4,  1),
+	PLL_35XX_RATE(666000000U,  222, 4,  1),
 	PLL_35XX_RATE(633000000U,  211, 4,  1),
 	PLL_35XX_RATE(600000000U,  500, 5,  2),
 	PLL_35XX_RATE(552000000U,  460, 5,  2),
@@ -773,12 +773,12 @@
 /* AUD_PLL */
 static struct samsung_pll_rate_table exynos5443_aud_pll_rates[] = {
 	PLL_36XX_RATE(400000000U, 200, 3, 2,      0),
-	PLL_36XX_RATE(393216000U, 197, 3, 2, -25690),
+	PLL_36XX_RATE(393216003U, 197, 3, 2, -25690),
 	PLL_36XX_RATE(384000000U, 128, 2, 2,      0),
-	PLL_36XX_RATE(368640000U, 246, 4, 2, -15729),
-	PLL_36XX_RATE(361507200U, 181, 3, 2, -16148),
-	PLL_36XX_RATE(338688000U, 113, 2, 2,  -6816),
-	PLL_36XX_RATE(294912000U,  98, 1, 3,  19923),
+	PLL_36XX_RATE(368639991U, 246, 4, 2, -15729),
+	PLL_36XX_RATE(361507202U, 181, 3, 2, -16148),
+	PLL_36XX_RATE(338687988U, 113, 2, 2,  -6816),
+	PLL_36XX_RATE(294912002U,  98, 1, 3,  19923),
 	PLL_36XX_RATE(288000000U,  96, 1, 3,      0),
 	PLL_36XX_RATE(252000000U,  84, 1, 3,      0),
 	{ /* sentinel */ }
@@ -1708,7 +1708,8 @@
 	GATE(CLK_SCLK_PCM1, "sclk_pcm1", "sclk_pcm1_peric",
 			ENABLE_SCLK_PERIC, 7, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_I2S1, "sclk_i2s1", "sclk_i2s1_peric",
-			ENABLE_SCLK_PERIC, 6, CLK_SET_RATE_PARENT, 0),
+			ENABLE_SCLK_PERIC, 6,
+			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
 	GATE(CLK_SCLK_SPI2, "sclk_spi2", "sclk_spi2_peric", ENABLE_SCLK_PERIC,
 			5, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_SPI1, "sclk_spi1", "sclk_spi1_peric", ENABLE_SCLK_PERIC,
--- linux-4.4.0.orig/drivers/clk/samsung/clk-s3c2410.c
+++ linux-4.4.0/drivers/clk/samsung/clk-s3c2410.c
@@ -168,7 +168,7 @@
 	PLL_35XX_RATE(226000000, 105, 1, 1),
 	PLL_35XX_RATE(210000000, 132, 2, 1),
 	/* 2410 common */
-	PLL_35XX_RATE(203000000, 161, 3, 1),
+	PLL_35XX_RATE(202800000, 161, 3, 1),
 	PLL_35XX_RATE(192000000, 88, 1, 1),
 	PLL_35XX_RATE(186000000, 85, 1, 1),
 	PLL_35XX_RATE(180000000, 82, 1, 1),
@@ -178,18 +178,18 @@
 	PLL_35XX_RATE(147000000, 90, 2, 1),
 	PLL_35XX_RATE(135000000, 82, 2, 1),
 	PLL_35XX_RATE(124000000, 116, 1, 2),
-	PLL_35XX_RATE(118000000, 150, 2, 2),
+	PLL_35XX_RATE(118500000, 150, 2, 2),
 	PLL_35XX_RATE(113000000, 105, 1, 2),
-	PLL_35XX_RATE(101000000, 127, 2, 2),
+	PLL_35XX_RATE(101250000, 127, 2, 2),
 	PLL_35XX_RATE(90000000, 112, 2, 2),
-	PLL_35XX_RATE(85000000, 105, 2, 2),
+	PLL_35XX_RATE(84750000, 105, 2, 2),
 	PLL_35XX_RATE(79000000, 71, 1, 2),
-	PLL_35XX_RATE(68000000, 82, 2, 2),
-	PLL_35XX_RATE(56000000, 142, 2, 3),
+	PLL_35XX_RATE(67500000, 82, 2, 2),
+	PLL_35XX_RATE(56250000, 142, 2, 3),
 	PLL_35XX_RATE(48000000, 120, 2, 3),
-	PLL_35XX_RATE(51000000, 161, 3, 3),
+	PLL_35XX_RATE(50700000, 161, 3, 3),
 	PLL_35XX_RATE(45000000, 82, 1, 3),
-	PLL_35XX_RATE(34000000, 82, 2, 3),
+	PLL_35XX_RATE(33750000, 82, 2, 3),
 	{ /* sentinel */ },
 };
 
--- linux-4.4.0.orig/drivers/clk/sirf/clk-atlas6.c
+++ linux-4.4.0/drivers/clk/sirf/clk-atlas6.c
@@ -137,7 +137,7 @@
 
 	for (i = pll1; i < maxclk; i++) {
 		atlas6_clks[i] = clk_register(NULL, atlas6_clk_hw_array[i]);
-		BUG_ON(!atlas6_clks[i]);
+		BUG_ON(IS_ERR(atlas6_clks[i]));
 	}
 	clk_register_clkdev(atlas6_clks[cpu], NULL, "cpu");
 	clk_register_clkdev(atlas6_clks[io],  NULL, "io");
--- linux-4.4.0.orig/drivers/clk/sirf/clk-common.c
+++ linux-4.4.0/drivers/clk/sirf/clk-common.c
@@ -298,9 +298,10 @@
 {
 	struct clk_dmn *clk = to_dmnclk(hw);
 	u32 cfg = clkc_readl(clk->regofs);
+	const char *name = clk_hw_get_name(hw);
 
 	/* parent of io domain can only be pll3 */
-	if (strcmp(hw->init->name, "io") == 0)
+	if (strcmp(name, "io") == 0)
 		return 4;
 
 	WARN_ON((cfg & (BIT(3) - 1)) > 4);
@@ -312,9 +313,10 @@
 {
 	struct clk_dmn *clk = to_dmnclk(hw);
 	u32 cfg = clkc_readl(clk->regofs);
+	const char *name = clk_hw_get_name(hw);
 
 	/* parent of io domain can only be pll3 */
-	if (strcmp(hw->init->name, "io") == 0)
+	if (strcmp(name, "io") == 0)
 		return -EINVAL;
 
 	cfg &= ~(BIT(3) - 1);
@@ -354,7 +356,8 @@
 {
 	unsigned long fin;
 	unsigned ratio, wait, hold;
-	unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
+	const char *name = clk_hw_get_name(hw);
+	unsigned bits = (strcmp(name, "mem") == 0) ? 3 : 4;
 
 	fin = *parent_rate;
 	ratio = fin / rate;
@@ -376,7 +379,8 @@
 	struct clk_dmn *clk = to_dmnclk(hw);
 	unsigned long fin;
 	unsigned ratio, wait, hold, reg;
-	unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
+	const char *name = clk_hw_get_name(hw);
+	unsigned bits = (strcmp(name, "mem") == 0) ? 3 : 4;
 
 	fin = parent_rate;
 	ratio = fin / rate;
--- linux-4.4.0.orig/drivers/clk/socfpga/clk-pll-a10.c
+++ linux-4.4.0/drivers/clk/socfpga/clk-pll-a10.c
@@ -95,6 +95,7 @@
 
 	clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr");
 	clk_mgr_a10_base_addr = of_iomap(clkmgr_np, 0);
+	of_node_put(clkmgr_np);
 	BUG_ON(!clk_mgr_a10_base_addr);
 	pll_clk->hw.reg = clk_mgr_a10_base_addr + reg;
 
--- linux-4.4.0.orig/drivers/clk/socfpga/clk-pll.c
+++ linux-4.4.0/drivers/clk/socfpga/clk-pll.c
@@ -100,6 +100,7 @@
 
 	clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr");
 	clk_mgr_base_addr = of_iomap(clkmgr_np, 0);
+	of_node_put(clkmgr_np);
 	BUG_ON(!clk_mgr_base_addr);
 	pll_clk->hw.reg = clk_mgr_base_addr + reg;
 
--- linux-4.4.0.orig/drivers/clk/st/clkgen-fsyn.c
+++ linux-4.4.0/drivers/clk/st/clkgen-fsyn.c
@@ -549,19 +549,20 @@
 	return 0;
 }
 
-static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, unsigned long rate
-		, unsigned long *prate)
+static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw,
+					   unsigned long rate,
+					   unsigned long *prate)
 {
 	struct stm_fs params;
 
-	if (!clk_fs660c32_vco_get_params(*prate, rate, &params))
-		clk_fs660c32_vco_get_rate(*prate, &params, &rate);
+	if (clk_fs660c32_vco_get_params(*prate, rate, &params))
+		return rate;
 
-	pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
+	clk_fs660c32_vco_get_rate(*prate, &params, &rate);
+
+	pr_debug("%s: %s new rate %ld [ndiv=%u]\n",
 		 __func__, clk_hw_get_name(hw),
-		 rate, (unsigned int)params.sdiv,
-		 (unsigned int)params.mdiv,
-		 (unsigned int)params.pe, (unsigned int)params.nsdiv);
+		 rate, (unsigned int)params.ndiv);
 
 	return rate;
 }
--- linux-4.4.0.orig/drivers/clk/sunxi/clk-simple-gates.c
+++ linux-4.4.0/drivers/clk/sunxi/clk-simple-gates.c
@@ -98,6 +98,8 @@
 	sunxi_simple_gates_setup(node, NULL, 0);
 }
 
+CLK_OF_DECLARE(sun4i_a10_gates, "allwinner,sun4i-a10-gates-clk",
+	       sunxi_simple_gates_init);
 CLK_OF_DECLARE(sun4i_a10_apb0, "allwinner,sun4i-a10-apb0-gates-clk",
 	       sunxi_simple_gates_init);
 CLK_OF_DECLARE(sun4i_a10_apb1, "allwinner,sun4i-a10-apb1-gates-clk",
--- linux-4.4.0.orig/drivers/clk/sunxi/clk-sunxi.c
+++ linux-4.4.0/drivers/clk/sunxi/clk-sunxi.c
@@ -311,7 +311,7 @@
 	 * Round down the frequency to the closest multiple of either
 	 * 6 or 16
 	 */
-	u32 round_freq_6 = round_down(freq_mhz, 6);
+	u32 round_freq_6 = rounddown(freq_mhz, 6);
 	u32 round_freq_16 = round_down(freq_mhz, 16);
 
 	if (round_freq_6 > round_freq_16)
--- linux-4.4.0.orig/drivers/clk/tegra/clk-pll.c
+++ linux-4.4.0/drivers/clk/tegra/clk-pll.c
@@ -492,8 +492,8 @@
 		pll_override_writel(val, params->pmc_divp_reg, pll);
 
 		val = pll_override_readl(params->pmc_divnm_reg, pll);
-		val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) |
-			~(divn_mask(pll) << div_nmp->override_divn_shift);
+		val &= ~((divm_mask(pll) << div_nmp->override_divm_shift) |
+			(divn_mask(pll) << div_nmp->override_divn_shift));
 		val |= (cfg->m << div_nmp->override_divm_shift) |
 			(cfg->n << div_nmp->override_divn_shift);
 		pll_override_writel(val, params->pmc_divnm_reg, pll);
--- linux-4.4.0.orig/drivers/clk/tegra/clk-tegra-pmc.c
+++ linux-4.4.0/drivers/clk/tegra/clk-tegra-pmc.c
@@ -60,16 +60,16 @@
 
 static DEFINE_SPINLOCK(clk_out_lock);
 
-static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
-	"clk_m_div4", "extern1",
+static const char *clk_out1_parents[] = { "osc", "osc_div2",
+	"osc_div4", "extern1",
 };
 
-static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
-	"clk_m_div4", "extern2",
+static const char *clk_out2_parents[] = { "osc", "osc_div2",
+	"osc_div4", "extern2",
 };
 
-static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
-	"clk_m_div4", "extern3",
+static const char *clk_out3_parents[] = { "osc", "osc_div2",
+	"osc_div4", "extern3",
 };
 
 static struct pmc_clk_init_data pmc_clks[] = {
--- linux-4.4.0.orig/drivers/clk/tegra/clk-tegra30.c
+++ linux-4.4.0/drivers/clk/tegra/clk-tegra30.c
@@ -333,11 +333,11 @@
 };
 
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
-	{ 12000000, 480000000, 960, 12, 0, 12},
-	{ 13000000, 480000000, 960, 13, 0, 12},
-	{ 16800000, 480000000, 400, 7,  0, 5},
-	{ 19200000, 480000000, 200, 4,  0, 3},
-	{ 26000000, 480000000, 960, 26, 0, 12},
+	{ 12000000, 480000000, 960, 12, 2, 12 },
+	{ 13000000, 480000000, 960, 13, 2, 12 },
+	{ 16800000, 480000000, 400,  7, 2,  5 },
+	{ 19200000, 480000000, 200,  4, 2,  3 },
+	{ 26000000, 480000000, 960, 26, 2, 12 },
 	{ 0, 0, 0, 0, 0, 0 },
 };
 
@@ -1063,7 +1063,7 @@
 	 * U71 divider of cclk_lp.
 	 */
 	clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3",
-				clk_base + SUPER_CCLKG_DIVIDER, 0,
+				clk_base + SUPER_CCLKLP_DIVIDER, 0,
 				TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
 	clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL);
 
@@ -1372,6 +1372,7 @@
 	{TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0},
 	{TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0},
 	{TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0},
+	{ TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 },
 	{TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0}, /* This MUST be the last entry. */
 };
 
--- linux-4.4.0.orig/drivers/clk/ti/clk-3xxx.c
+++ linux-4.4.0/drivers/clk/ti/clk-3xxx.c
@@ -22,13 +22,6 @@
 
 #include "clock.h"
 
-/*
- * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
- * that are sourced by DPLL5, and both of these require this clock
- * to be at 120 MHz for proper operation.
- */
-#define DPLL5_FREQ_FOR_USBHOST		120000000
-
 #define OMAP3430ES2_ST_DSS_IDLE_SHIFT			1
 #define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT		5
 #define OMAP3430ES2_ST_SSI_IDLE_SHIFT			8
@@ -546,14 +539,21 @@
 	struct clk *dpll5_clk;
 	struct clk *dpll5_m2_clk;
 
+	/*
+	 * Errata sprz319f advisory 2.1 documents a USB host clock drift issue
+	 * that can be worked around using specially crafted dpll5 settings
+	 * with a dpll5_m2 divider set to 8. Set the dpll5 rate to 8x the USB
+	 * host clock rate, its .set_rate handler() will detect that frequency
+	 * and use the errata settings.
+	 */
 	dpll5_clk = clk_get(NULL, "dpll5_ck");
-	clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
+	clk_set_rate(dpll5_clk, OMAP3_DPLL5_FREQ_FOR_USBHOST * 8);
 	clk_prepare_enable(dpll5_clk);
 
-	/* Program dpll5_m2_clk divider for no division */
+	/* Program dpll5_m2_clk divider */
 	dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
 	clk_prepare_enable(dpll5_m2_clk);
-	clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
+	clk_set_rate(dpll5_m2_clk, OMAP3_DPLL5_FREQ_FOR_USBHOST);
 
 	clk_disable_unprepare(dpll5_m2_clk);
 	clk_disable_unprepare(dpll5_clk);
--- linux-4.4.0.orig/drivers/clk/ti/clk-dra7-atl.c
+++ linux-4.4.0/drivers/clk/ti/clk-dra7-atl.c
@@ -265,7 +265,7 @@
 
 		/* Get configuration for the ATL instances */
 		snprintf(prop, sizeof(prop), "atl%u", i);
-		cfg_node = of_find_node_by_name(node, prop);
+		cfg_node = of_get_child_by_name(node, prop);
 		if (cfg_node) {
 			ret = of_property_read_u32(cfg_node, "bws",
 						   &cdesc->bws);
@@ -278,6 +278,7 @@
 				atl_write(cinfo, DRA7_ATL_AWSMUX_REG(i),
 					  cdesc->aws);
 			}
+			of_node_put(cfg_node);
 		}
 
 		cdesc->probed = true;
--- linux-4.4.0.orig/drivers/clk/ti/clock.h
+++ linux-4.4.0/drivers/clk/ti/clock.h
@@ -257,11 +257,20 @@
 unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
 				    unsigned long parent_rate);
 
+/*
+ * OMAP3_DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
+ * that are sourced by DPLL5, and both of these require this clock
+ * to be at 120 MHz for proper operation.
+ */
+#define OMAP3_DPLL5_FREQ_FOR_USBHOST	120000000
+
 unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
 int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
 			 unsigned long parent_rate);
 int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
 				    unsigned long parent_rate, u8 index);
+int omap3_dpll5_set_rate(struct clk_hw *hw, unsigned long rate,
+			 unsigned long parent_rate);
 void omap3_clk_lock_dpll5(void);
 
 unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
--- linux-4.4.0.orig/drivers/clk/ti/clockdomain.c
+++ linux-4.4.0/drivers/clk/ti/clockdomain.c
@@ -124,10 +124,12 @@
 		if (clk_hw_get_flags(clk_hw) & CLK_IS_BASIC) {
 			pr_warn("can't setup clkdm for basic clk %s\n",
 				__clk_get_name(clk));
+			clk_put(clk);
 			continue;
 		}
 		to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name;
 		omap2_init_clk_clkdm(clk_hw);
+		clk_put(clk);
 	}
 }
 
--- linux-4.4.0.orig/drivers/clk/ti/composite.c
+++ linux-4.4.0/drivers/clk/ti/composite.c
@@ -228,6 +228,7 @@
 		if (!cclk->comp_clks[i])
 			continue;
 		list_del(&cclk->comp_clks[i]->link);
+		kfree(cclk->comp_clks[i]->parent_names);
 		kfree(cclk->comp_clks[i]);
 	}
 
--- linux-4.4.0.orig/drivers/clk/ti/dpll.c
+++ linux-4.4.0/drivers/clk/ti/dpll.c
@@ -114,6 +114,18 @@
 	.round_rate	= &omap2_dpll_round_rate,
 };
 
+static const struct clk_ops omap3_dpll5_ck_ops = {
+	.enable		= &omap3_noncore_dpll_enable,
+	.disable	= &omap3_noncore_dpll_disable,
+	.get_parent	= &omap2_init_dpll_parent,
+	.recalc_rate	= &omap3_dpll_recalc,
+	.set_rate	= &omap3_dpll5_set_rate,
+	.set_parent	= &omap3_noncore_dpll_set_parent,
+	.set_rate_and_parent	= &omap3_noncore_dpll_set_rate_and_parent,
+	.determine_rate	= &omap3_noncore_dpll_determine_rate,
+	.round_rate	= &omap2_dpll_round_rate,
+};
+
 static const struct clk_ops omap3_dpll_per_ck_ops = {
 	.enable		= &omap3_noncore_dpll_enable,
 	.disable	= &omap3_noncore_dpll_disable,
@@ -461,7 +473,12 @@
 		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	};
 
-	of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd);
+	if ((of_machine_is_compatible("ti,omap3630") ||
+	     of_machine_is_compatible("ti,omap36xx")) &&
+	    !strcmp(node->name, "dpll5_ck"))
+		of_ti_dpll_setup(node, &omap3_dpll5_ck_ops, &dd);
+	else
+		of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd);
 }
 CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock",
 	       of_ti_omap3_dpll_setup);
--- linux-4.4.0.orig/drivers/clk/ti/dpll3xxx.c
+++ linux-4.4.0/drivers/clk/ti/dpll3xxx.c
@@ -437,7 +437,8 @@
 
 	parent = clk_hw_get_parent(hw);
 
-	if (clk_hw_get_rate(hw) == clk_get_rate(dd->clk_bypass)) {
+	if (clk_hw_get_rate(hw) ==
+	    clk_hw_get_rate(__clk_get_hw(dd->clk_bypass))) {
 		WARN_ON(parent != __clk_get_hw(dd->clk_bypass));
 		r = _omap3_noncore_dpll_bypass(clk);
 	} else {
@@ -815,3 +816,70 @@
 	return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
 						      index);
 }
+
+/* Apply DM3730 errata sprz319 advisory 2.1. */
+static bool omap3_dpll5_apply_errata(struct clk_hw *hw,
+				     unsigned long parent_rate)
+{
+	struct omap3_dpll5_settings {
+		unsigned int rate, m, n;
+	};
+
+	static const struct omap3_dpll5_settings precomputed[] = {
+		/*
+		 * From DM3730 errata advisory 2.1, table 35 and 36.
+		 * The N value is increased by 1 compared to the tables as the
+		 * errata lists register values while last_rounded_field is the
+		 * real divider value.
+		 */
+		{ 12000000,  80,  0 + 1 },
+		{ 13000000, 443,  5 + 1 },
+		{ 19200000,  50,  0 + 1 },
+		{ 26000000, 443, 11 + 1 },
+		{ 38400000,  25,  0 + 1 }
+	};
+
+	const struct omap3_dpll5_settings *d;
+	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+	struct dpll_data *dd;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(precomputed); ++i) {
+		if (parent_rate == precomputed[i].rate)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(precomputed))
+		return false;
+
+	d = &precomputed[i];
+
+	/* Update the M, N and rounded rate values and program the DPLL. */
+	dd = clk->dpll_data;
+	dd->last_rounded_m = d->m;
+	dd->last_rounded_n = d->n;
+	dd->last_rounded_rate = div_u64((u64)parent_rate * d->m, d->n);
+	omap3_noncore_dpll_program(clk, 0);
+
+	return true;
+}
+
+/**
+ * omap3_dpll5_set_rate - set rate for omap3 dpll5
+ * @hw: clock to change
+ * @rate: target rate for clock
+ * @parent_rate: rate of the parent clock
+ *
+ * Set rate for the DPLL5 clock. Apply the sprz319 advisory 2.1 on OMAP36xx if
+ * the DPLL is used for USB host (detected through the requested rate).
+ */
+int omap3_dpll5_set_rate(struct clk_hw *hw, unsigned long rate,
+			 unsigned long parent_rate)
+{
+	if (rate == OMAP3_DPLL5_FREQ_FOR_USBHOST * 8) {
+		if (omap3_dpll5_apply_errata(hw, parent_rate))
+			return 0;
+	}
+
+	return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
+}
--- linux-4.4.0.orig/drivers/clk/ti/fapll.c
+++ linux-4.4.0/drivers/clk/ti/fapll.c
@@ -497,6 +497,7 @@
 {
 	struct clk_init_data *init;
 	struct fapll_synth *synth;
+	struct clk *clk = ERR_PTR(-ENOMEM);
 
 	init = kzalloc(sizeof(*init), GFP_KERNEL);
 	if (!init)
@@ -519,13 +520,19 @@
 	synth->hw.init = init;
 	synth->clk_pll = pll_clk;
 
-	return clk_register(NULL, &synth->hw);
+	clk = clk_register(NULL, &synth->hw);
+	if (IS_ERR(clk)) {
+		pr_err("failed to register clock\n");
+		goto free;
+	}
+
+	return clk;
 
 free:
 	kfree(synth);
 	kfree(init);
 
-	return ERR_PTR(-ENOMEM);
+	return clk;
 }
 
 static void __init ti_fapll_setup(struct device_node *node)
--- linux-4.4.0.orig/drivers/clk/versatile/clk-sp810.c
+++ linux-4.4.0/drivers/clk/versatile/clk-sp810.c
@@ -92,6 +92,7 @@
 	int num = ARRAY_SIZE(parent_names);
 	char name[12];
 	struct clk_init_data init;
+	static int instance;
 	int i;
 	bool deprecated;
 
@@ -118,7 +119,7 @@
 	deprecated = !of_find_property(node, "assigned-clock-parents", NULL);
 
 	for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) {
-		snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
+		snprintf(name, sizeof(name), "sp810_%d_%d", instance, i);
 
 		sp810->timerclken[i].sp810 = sp810;
 		sp810->timerclken[i].channel = i;
@@ -139,5 +140,6 @@
 	}
 
 	of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810);
+	instance++;
 }
 CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup);
--- linux-4.4.0.orig/drivers/clocksource/arm_arch_timer.c
+++ linux-4.4.0/drivers/clocksource/arm_arch_timer.c
@@ -310,15 +310,24 @@
 
 static void arch_timer_configure_evtstream(void)
 {
-	int evt_stream_div, pos;
+	int evt_stream_div, lsb;
+
+	/*
+	 * As the event stream can at most be generated at half the frequency
+	 * of the counter, use half the frequency when computing the divider.
+	 */
+	evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ / 2;
+
+	/*
+	 * Find the closest power of two to the divisor. If the adjacent bit
+	 * of lsb (last set bit, starts from 0) is set, then we use (lsb + 1).
+	 */
+	lsb = fls(evt_stream_div) - 1;
+	if (lsb > 0 && (evt_stream_div & BIT(lsb - 1)))
+		lsb++;
 
-	/* Find the closest power of two to the divisor */
-	evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ;
-	pos = fls(evt_stream_div);
-	if (pos > 1 && !(evt_stream_div & (1 << (pos - 2))))
-		pos--;
 	/* enable event stream */
-	arch_timer_evtstrm_enable(min(pos, 15));
+	arch_timer_evtstrm_enable(max(0, min(lsb, 15)));
 }
 
 static void arch_counter_set_user_access(void)
--- linux-4.4.0.orig/drivers/clocksource/asm9260_timer.c
+++ linux-4.4.0/drivers/clocksource/asm9260_timer.c
@@ -196,6 +196,10 @@
 		panic("%s: unable to map resource", np->name);
 
 	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		pr_err("Failed to get clk!\n");
+		return PTR_ERR(clk);
+	}
 
 	ret = clk_prepare_enable(clk);
 	if (ret)
--- linux-4.4.0.orig/drivers/clocksource/cs5535-clockevt.c
+++ linux-4.4.0/drivers/clocksource/cs5535-clockevt.c
@@ -22,7 +22,7 @@
 #define DRV_NAME "cs5535-clockevt"
 
 static int timer_irq;
-module_param_named(irq, timer_irq, int, 0644);
+module_param_hw_named(irq, timer_irq, int, irq, 0644);
 MODULE_PARM_DESC(irq, "Which IRQ to use for the clock source MFGPT ticks.");
 
 /*
@@ -117,7 +117,8 @@
 	/* Turn off the clock (and clear the event) */
 	disable_timer(cs5535_event_clock);
 
-	if (clockevent_state_shutdown(&cs5535_clockevent))
+	if (clockevent_state_detached(&cs5535_clockevent) ||
+	    clockevent_state_shutdown(&cs5535_clockevent))
 		return IRQ_HANDLED;
 
 	/* Clear the counter */
--- linux-4.4.0.orig/drivers/clocksource/dw_apb_timer_of.c
+++ linux-4.4.0/drivers/clocksource/dw_apb_timer_of.c
@@ -134,16 +134,14 @@
 static void __init dw_apb_timer_init(struct device_node *timer)
 {
 	switch (num_called) {
-	case 0:
-		pr_debug("%s: found clockevent timer\n", __func__);
-		add_clockevent(timer);
-		break;
 	case 1:
 		pr_debug("%s: found clocksource timer\n", __func__);
 		add_clocksource(timer);
 		init_sched_clock();
 		break;
 	default:
+		pr_debug("%s: found clockevent timer\n", __func__);
+		add_clockevent(timer);
 		break;
 	}
 
--- linux-4.4.0.orig/drivers/clocksource/exynos_mct.c
+++ linux-4.4.0/drivers/clocksource/exynos_mct.c
@@ -379,6 +379,13 @@
 	exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
 }
 
+static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
+{
+	/* Clear the MCT tick interrupt */
+	if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1)
+		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
+}
+
 static int exynos4_tick_set_next_event(unsigned long cycles,
 				       struct clock_event_device *evt)
 {
@@ -395,6 +402,7 @@
 
 	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	exynos4_mct_tick_stop(mevt);
+	exynos4_mct_tick_clear(mevt);
 	return 0;
 }
 
@@ -411,8 +419,11 @@
 	return 0;
 }
 
-static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
+static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
 {
+	struct mct_clock_event_device *mevt = dev_id;
+	struct clock_event_device *evt = &mevt->evt;
+
 	/*
 	 * This is for supporting oneshot mode.
 	 * Mct would generate interrupt periodically
@@ -421,16 +432,6 @@
 	if (!clockevent_state_periodic(&mevt->evt))
 		exynos4_mct_tick_stop(mevt);
 
-	/* Clear the MCT tick interrupt */
-	if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1)
-		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
-}
-
-static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
-{
-	struct mct_clock_event_device *mevt = dev_id;
-	struct clock_event_device *evt = &mevt->evt;
-
 	exynos4_mct_tick_clear(mevt);
 
 	evt->event_handler(evt);
@@ -482,6 +483,7 @@
 	if (mct_int_type == MCT_INT_SPI) {
 		if (evt->irq != -1)
 			disable_irq_nosync(evt->irq);
+		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
 	} else {
 		disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
 	}
--- linux-4.4.0.orig/drivers/clocksource/fsl_ftm_timer.c
+++ linux-4.4.0/drivers/clocksource/fsl_ftm_timer.c
@@ -281,7 +281,7 @@
 
 static unsigned long __init ftm_clk_init(struct device_node *np)
 {
-	unsigned long freq;
+	long freq;
 
 	freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt");
 	if (freq <= 0)
--- linux-4.4.0.orig/drivers/clocksource/i8253.c
+++ linux-4.4.0/drivers/clocksource/i8253.c
@@ -19,6 +19,13 @@
 DEFINE_RAW_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
 
+/*
+ * Handle PIT quirk in pit_shutdown() where zeroing the counter register
+ * restarts the PIT, negating the shutdown. On platforms with the quirk,
+ * platform specific code can set this to false.
+ */
+bool i8253_clear_counter_on_shutdown = true;
+
 #ifdef CONFIG_CLKSRC_I8253
 /*
  * Since the PIT overflows every tick, its not very useful
@@ -108,8 +115,11 @@
 	raw_spin_lock(&i8253_lock);
 
 	outb_p(0x30, PIT_MODE);
-	outb_p(0, PIT_CH0);
-	outb_p(0, PIT_CH0);
+
+	if (i8253_clear_counter_on_shutdown) {
+		outb_p(0, PIT_CH0);
+		outb_p(0, PIT_CH0);
+	}
 
 	raw_spin_unlock(&i8253_lock);
 	return 0;
--- linux-4.4.0.orig/drivers/clocksource/mxs_timer.c
+++ linux-4.4.0/drivers/clocksource/mxs_timer.c
@@ -154,10 +154,7 @@
 
 	/* Clear pending interrupt */
 	timrot_irq_acknowledge();
-
-#ifdef DEBUG
-	pr_info("%s: changing mode to %s\n", __func__, state)
-#endif /* DEBUG */
+	pr_debug("%s: changing mode to %s\n", __func__, state);
 }
 
 static int mxs_shutdown(struct clock_event_device *evt)
--- linux-4.4.0.orig/drivers/clocksource/sun4i_timer.c
+++ linux-4.4.0/drivers/clocksource/sun4i_timer.c
@@ -123,12 +123,16 @@
 	.set_next_event = sun4i_clkevt_next_event,
 };
 
+static void sun4i_timer_clear_interrupt(void)
+{
+	writel(TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_ST_REG);
+}
 
 static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
 
-	writel(0x1, timer_base + TIMER_IRQ_ST_REG);
+	sun4i_timer_clear_interrupt();
 	evt->event_handler(evt);
 
 	return IRQ_HANDLED;
@@ -193,6 +197,9 @@
 	/* Make sure timer is stopped before playing with interrupts */
 	sun4i_clkevt_time_stop(0);
 
+	/* clear timer0 interrupt */
+	sun4i_timer_clear_interrupt();
+
 	sun4i_clockevent.cpumask = cpu_possible_mask;
 	sun4i_clockevent.irq = irq;
 
--- linux-4.4.0.orig/drivers/clocksource/tcb_clksrc.c
+++ linux-4.4.0/drivers/clocksource/tcb_clksrc.c
@@ -98,7 +98,8 @@
 
 	__raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR));
 	__raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
-	clk_disable(tcd->clk);
+	if (!clockevent_state_detached(d))
+		clk_disable(tcd->clk);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/clocksource/timer-sun5i.c
+++ linux-4.4.0/drivers/clocksource/timer-sun5i.c
@@ -201,6 +201,11 @@
 	}
 
 	rate = clk_get_rate(clk);
+	if (!rate) {
+		pr_err("Couldn't get parent clock rate\n");
+		ret = -EINVAL;
+		goto err_disable_clk;
+	}
 
 	cs->timer.base = base;
 	cs->timer.clk = clk;
@@ -274,6 +279,11 @@
 	}
 
 	rate = clk_get_rate(clk);
+	if (!rate) {
+		pr_err("Couldn't get parent clock rate\n");
+		ret = -EINVAL;
+		goto err_disable_clk;
+	}
 
 	ce->timer.base = base;
 	ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
--- linux-4.4.0.orig/drivers/clocksource/timer-ti-32k.c
+++ linux-4.4.0/drivers/clocksource/timer-ti-32k.c
@@ -98,6 +98,9 @@
 		return;
 	}
 
+	if (!of_machine_is_compatible("ti,am43"))
+		ti_32k_timer.cs.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
+
 	ti_32k_timer.counter = ti_32k_timer.base;
 
 	/*
--- linux-4.4.0.orig/drivers/clocksource/vt8500_timer.c
+++ linux-4.4.0/drivers/clocksource/vt8500_timer.c
@@ -50,6 +50,8 @@
 
 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
 
+#define MIN_OSCR_DELTA		16
+
 static void __iomem *regbase;
 
 static cycle_t vt8500_timer_read(struct clocksource *cs)
@@ -80,7 +82,7 @@
 		cpu_relax();
 	writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL);
 
-	if ((signed)(alarm - clocksource.read(&clocksource)) <= 16)
+	if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA)
 		return -ETIME;
 
 	writel(1, regbase + TIMER_IER_VAL);
@@ -151,7 +153,7 @@
 		pr_err("%s: setup_irq failed for %s\n", __func__,
 							clockevent.name);
 	clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ,
-					4, 0xf0000000);
+					MIN_OSCR_DELTA * 2, 0xf0000000);
 }
 
 CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);
--- linux-4.4.0.orig/drivers/cpufreq/Kconfig
+++ linux-4.4.0/drivers/cpufreq/Kconfig
@@ -236,6 +236,7 @@
 if MIPS
 config LOONGSON2_CPUFREQ
 	tristate "Loongson2 CPUFreq Driver"
+	depends on LEMOTE_MACH2F
 	help
 	  This option adds a CPUFreq driver for loongson processors which
 	  support software configurable cpu frequency.
@@ -248,6 +249,7 @@
 
 config LOONGSON1_CPUFREQ
 	tristate "Loongson1 CPUFreq Driver"
+	depends on LOONGSON1_LS1B
 	help
 	  This option adds a CPUFreq driver for loongson1 processors which
 	  support software configurable cpu frequency.
--- linux-4.4.0.orig/drivers/cpufreq/Kconfig.arm
+++ linux-4.4.0/drivers/cpufreq/Kconfig.arm
@@ -241,7 +241,7 @@
 
 config ACPI_CPPC_CPUFREQ
 	tristate "CPUFreq driver based on the ACPI CPPC spec"
-	depends on ACPI
+	depends on ACPI_PROCESSOR
 	select ACPI_CPPC_LIB
 	default n
 	help
--- linux-4.4.0.orig/drivers/cpufreq/acpi-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/acpi-cpufreq.c
@@ -45,6 +45,7 @@
 #include <asm/msr.h>
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
@@ -639,7 +640,7 @@
 	if (c->x86_vendor == X86_VENDOR_INTEL) {
 		if ((c->x86 == 15) &&
 		    (c->x86_model == 6) &&
-		    (c->x86_mask == 8)) {
+		    (c->x86_stepping == 8)) {
 			printk(KERN_INFO "acpi-cpufreq: Intel(R) "
 			    "Xeon(R) 7100 Errata AL30, processors may "
 			    "lock up on frequency changes: disabling "
@@ -713,7 +714,8 @@
 		cpumask_copy(policy->cpus, topology_core_cpumask(cpu));
 	}
 
-	if (check_amd_hwpstate_cpu(cpu) && !acpi_pstate_strict) {
+	if (check_amd_hwpstate_cpu(cpu) && boot_cpu_data.x86 < 0x19 &&
+	    !acpi_pstate_strict) {
 		cpumask_clear(policy->cpus);
 		cpumask_set_cpu(cpu, policy->cpus);
 		cpumask_copy(data->freqdomain_cpus,
--- linux-4.4.0.orig/drivers/cpufreq/amd_freq_sensitivity.c
+++ linux-4.4.0/drivers/cpufreq/amd_freq_sensitivity.c
@@ -20,6 +20,7 @@
 
 #include <asm/msr.h>
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 #include "cpufreq_governor.h"
 
--- linux-4.4.0.orig/drivers/cpufreq/cppc_cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/cppc_cpufreq.c
@@ -100,9 +100,19 @@
 	policy->cpuinfo.max_freq = policy->max;
 	policy->shared_type = cpu->shared_type;
 
-	if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+	if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
+		int i;
+
 		cpumask_copy(policy->cpus, cpu->shared_cpu_map);
-	else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) {
+
+		for_each_cpu(i, policy->cpus) {
+			if (unlikely(i == policy->cpu))
+				continue;
+
+			memcpy(&all_cpu_data[i]->perf_caps, &cpu->perf_caps,
+			       sizeof(cpu->perf_caps));
+		}
+	} else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) {
 		/* Support only SW_ANY for now. */
 		pr_debug("Unsupported CPU co-ord type\n");
 		return -EFAULT;
@@ -166,8 +176,13 @@
 	return ret;
 
 out:
-	for_each_possible_cpu(i)
-		kfree(all_cpu_data[i]);
+	for_each_possible_cpu(i) {
+		cpu = all_cpu_data[i];
+		if (!cpu)
+			break;
+		free_cpumask_var(cpu->shared_cpu_map);
+		kfree(cpu);
+	}
 
 	kfree(all_cpu_data);
 	return -ENODEV;
--- linux-4.4.0.orig/drivers/cpufreq/cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/cpufreq.c
@@ -474,13 +474,13 @@
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
 static ssize_t show_boost(struct kobject *kobj,
-				 struct attribute *attr, char *buf)
+			  struct kobj_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
 }
 
-static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
-				  const char *buf, size_t count)
+static ssize_t store_boost(struct kobject *kobj, struct kobj_attribute *attr,
+			   const char *buf, size_t count)
 {
 	int ret, enable;
 
@@ -603,6 +603,8 @@
 	struct cpufreq_policy new_policy;				\
 									\
 	memcpy(&new_policy, policy, sizeof(*policy));			\
+	new_policy.min = policy->user_policy.min;			\
+	new_policy.max = policy->user_policy.max;			\
 									\
 	ret = sscanf(buf, "%u", &new_policy.object);			\
 	if (ret != 1)							\
@@ -626,9 +628,11 @@
 					char *buf)
 {
 	unsigned int cur_freq = __cpufreq_get(policy);
-	if (!cur_freq)
-		return sprintf(buf, "<unknown>");
-	return sprintf(buf, "%u\n", cur_freq);
+
+	if (cur_freq)
+		return sprintf(buf, "%u\n", cur_freq);
+
+	return sprintf(buf, "<unknown>\n");
 }
 
 /**
@@ -817,6 +821,9 @@
 	struct freq_attr *fattr = to_attr(attr);
 	ssize_t ret;
 
+	if (!fattr->show)
+		return -EIO;
+
 	down_read(&policy->rwsem);
 
 	if (fattr->show)
@@ -836,6 +843,9 @@
 	struct freq_attr *fattr = to_attr(attr);
 	ssize_t ret = -EINVAL;
 
+	if (!fattr->store)
+		return -EIO;
+
 	get_online_cpus();
 
 	if (!cpu_online(policy->cpu))
@@ -1026,6 +1036,7 @@
 {
 	struct device *dev = get_cpu_device(cpu);
 	struct cpufreq_policy *policy;
+	int ret;
 
 	if (WARN_ON(!dev))
 		return NULL;
@@ -1043,7 +1054,13 @@
 	if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
 		goto err_free_rcpumask;
 
-	kobject_init(&policy->kobj, &ktype_cpufreq);
+	ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
+				   cpufreq_global_kobject, "policy%u", cpu);
+	if (ret) {
+		pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
+		goto err_free_real_cpus;
+	}
+
 	INIT_LIST_HEAD(&policy->policy_list);
 	init_rwsem(&policy->rwsem);
 	spin_lock_init(&policy->transition_lock);
@@ -1054,6 +1071,8 @@
 	policy->cpu = cpu;
 	return policy;
 
+err_free_real_cpus:
+	free_cpumask_var(policy->real_cpus);
 err_free_rcpumask:
 	free_cpumask_var(policy->related_cpus);
 err_free_cpumask:
@@ -1158,16 +1177,6 @@
 		cpumask_copy(policy->related_cpus, policy->cpus);
 		/* Remember CPUs present at the policy creation time. */
 		cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask);
-
-		/* Name and add the kobject */
-		ret = kobject_add(&policy->kobj, cpufreq_global_kobject,
-				  "policy%u",
-				  cpumask_first(policy->related_cpus));
-		if (ret) {
-			pr_err("%s: failed to add policy->kobj: %d\n", __func__,
-			       ret);
-			goto out_exit_policy;
-		}
 	}
 
 	/*
@@ -1184,6 +1193,9 @@
 		for_each_cpu(j, policy->related_cpus)
 			per_cpu(cpufreq_cpu_data, j) = policy;
 		write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+	} else {
+		policy->min = policy->user_policy.min;
+		policy->max = policy->user_policy.max;
 	}
 
 	if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
@@ -1620,6 +1632,9 @@
 	if (!cpufreq_driver)
 		return;
 
+	if (unlikely(!cpufreq_suspended))
+		return;
+
 	cpufreq_suspended = false;
 
 	if (!has_target())
@@ -2155,10 +2170,7 @@
 			return ret;
 		}
 
-		up_write(&policy->rwsem);
 		ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
-		down_write(&policy->rwsem);
-
 		if (ret) {
 			pr_err("%s: Failed to Exit Governor: %s (%d)\n",
 			       __func__, old_gov->name, ret);
@@ -2174,9 +2186,7 @@
 		if (!ret)
 			goto out;
 
-		up_write(&policy->rwsem);
 		__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
-		down_write(&policy->rwsem);
 	}
 
 	/* new governor failed, so re-start old one */
@@ -2392,6 +2402,20 @@
  *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
  *********************************************************************/
 
+static char cpufreq_driver_name[CPUFREQ_NAME_LEN];
+
+static int __init cpufreq_driver_setup(char *str)
+{
+	strlcpy(cpufreq_driver_name, str, CPUFREQ_NAME_LEN);
+	return 1;
+}
+
+/*
+ * Set this name to only allow one specific cpu freq driver, e.g.,
+ * cpufreq_driver=powernow-k8
+ */
+__setup("cpufreq_driver=", cpufreq_driver_setup);
+
 /**
  * cpufreq_register_driver - register a CPU Frequency driver
  * @driver_data: A struct cpufreq_driver containing the values#
@@ -2410,6 +2434,13 @@
 	if (cpufreq_disabled())
 		return -ENODEV;
 
+	/*
+	 * The cpufreq core depends heavily on the availability of device
+	 * structure, make sure they are available before proceeding further.
+	 */
+	if (!get_cpu_device(0))
+		return -EPROBE_DEFER;
+
 	if (!driver_data || !driver_data->verify || !driver_data->init ||
 	    !(driver_data->setpolicy || driver_data->target_index ||
 		    driver_data->target) ||
@@ -2418,7 +2449,13 @@
 	     (!!driver_data->get_intermediate != !!driver_data->target_intermediate))
 		return -EINVAL;
 
-	pr_debug("trying to register driver %s\n", driver_data->name);
+	pr_debug("trying to register driver %s, cpufreq_driver=%s\n",
+		driver_data->name, cpufreq_driver_name);
+
+	if (cpufreq_driver_name[0])
+		if (!driver_data->name ||
+			strcmp(cpufreq_driver_name, driver_data->name))
+				return -EINVAL;
 
 	/* Protect against concurrent CPU online/offline. */
 	get_online_cpus();
@@ -2446,6 +2483,7 @@
 	if (!(cpufreq_driver->flags & CPUFREQ_STICKY) &&
 	    list_empty(&cpufreq_policy_list)) {
 		/* if all ->init() calls failed, unregister */
+		ret = -ENODEV;
 		pr_debug("%s: No CPU initialized for driver %s\n", __func__,
 			 driver_data->name);
 		goto err_if_unreg;
@@ -2504,14 +2542,6 @@
 }
 EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
 
-/*
- * Stop cpufreq at shutdown to make sure it isn't holding any locks
- * or mutexes when secondary CPUs are halted.
- */
-static struct syscore_ops cpufreq_syscore_ops = {
-	.shutdown = cpufreq_suspend,
-};
-
 struct kobject *cpufreq_global_kobject;
 EXPORT_SYMBOL(cpufreq_global_kobject);
 
@@ -2523,8 +2553,6 @@
 	cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
 	BUG_ON(!cpufreq_global_kobject);
 
-	register_syscore_ops(&cpufreq_syscore_ops);
-
 	return 0;
 }
 core_initcall(cpufreq_core_init);
--- linux-4.4.0.orig/drivers/cpufreq/cpufreq_conservative.c
+++ linux-4.4.0/drivers/cpufreq/cpufreq_conservative.c
@@ -212,8 +212,8 @@
 	int ret;
 	ret = sscanf(buf, "%u", &input);
 
-	/* cannot be lower than 11 otherwise freq will not fall */
-	if (ret != 1 || input < 11 || input > 100 ||
+	/* cannot be lower than 1 otherwise freq will not fall */
+	if (ret != 1 || input < 1 || input > 100 ||
 			input >= cs_tuners->up_threshold)
 		return -EINVAL;
 
--- linux-4.4.0.orig/drivers/cpufreq/cpufreq_governor.c
+++ linux-4.4.0/drivers/cpufreq/cpufreq_governor.c
@@ -356,16 +356,18 @@
 	if (!have_governor_per_policy())
 		cdata->gdbs_data = dbs_data;
 
+	policy->governor_data = dbs_data;
+
 	ret = sysfs_create_group(get_governor_parent_kobj(policy),
 				 get_sysfs_attr(dbs_data));
 	if (ret)
 		goto reset_gdbs_data;
 
-	policy->governor_data = dbs_data;
-
 	return 0;
 
 reset_gdbs_data:
+	policy->governor_data = NULL;
+
 	if (!have_governor_per_policy())
 		cdata->gdbs_data = NULL;
 	cdata->exit(dbs_data, !policy->governor->initialized);
@@ -386,16 +388,19 @@
 	if (!cdbs->shared || cdbs->shared->policy)
 		return -EBUSY;
 
-	policy->governor_data = NULL;
 	if (!--dbs_data->usage_count) {
 		sysfs_remove_group(get_governor_parent_kobj(policy),
 				   get_sysfs_attr(dbs_data));
 
+		policy->governor_data = NULL;
+
 		if (!have_governor_per_policy())
 			cdata->gdbs_data = NULL;
 
 		cdata->exit(dbs_data, policy->governor->initialized == 1);
 		kfree(dbs_data);
+	} else {
+		policy->governor_data = NULL;
 	}
 
 	free_common_dbs_info(policy, cdata);
--- linux-4.4.0.orig/drivers/cpufreq/cpufreq_governor.h
+++ linux-4.4.0/drivers/cpufreq/cpufreq_governor.h
@@ -48,11 +48,11 @@
 
 /* Create attributes */
 #define gov_sys_attr_ro(_name)						\
-static struct global_attr _name##_gov_sys =				\
+static struct kobj_attribute _name##_gov_sys =				\
 __ATTR(_name, 0444, show_##_name##_gov_sys, NULL)
 
 #define gov_sys_attr_rw(_name)						\
-static struct global_attr _name##_gov_sys =				\
+static struct kobj_attribute _name##_gov_sys =				\
 __ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
 
 #define gov_pol_attr_ro(_name)						\
@@ -74,7 +74,7 @@
 /* Create show/store routines */
 #define show_one(_gov, file_name)					\
 static ssize_t show_##file_name##_gov_sys				\
-(struct kobject *kobj, struct attribute *attr, char *buf)		\
+(struct kobject *kobj, struct kobj_attribute *attr, char *buf)		\
 {									\
 	struct _gov##_dbs_tuners *tuners = _gov##_dbs_cdata.gdbs_data->tuners; \
 	return sprintf(buf, "%u\n", tuners->file_name);			\
@@ -90,7 +90,7 @@
 
 #define store_one(_gov, file_name)					\
 static ssize_t store_##file_name##_gov_sys				\
-(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
+(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) \
 {									\
 	struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data;		\
 	return store_##file_name(dbs_data, buf, count);			\
@@ -254,7 +254,7 @@
 
 #define declare_show_sampling_rate_min(_gov)				\
 static ssize_t show_sampling_rate_min_gov_sys				\
-(struct kobject *kobj, struct attribute *attr, char *buf)		\
+(struct kobject *kobj, struct kobj_attribute *attr, char *buf)		\
 {									\
 	struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data;		\
 	return sprintf(buf, "%u\n", dbs_data->min_sampling_rate);	\
--- linux-4.4.0.orig/drivers/cpufreq/cpufreq_userspace.c
+++ linux-4.4.0/drivers/cpufreq/cpufreq_userspace.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
 
 static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
 static DEFINE_MUTEX(userspace_mutex);
@@ -31,6 +32,7 @@
 static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
 {
 	int ret = -EINVAL;
+	unsigned int *setspeed = policy->governor_data;
 
 	pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
 
@@ -38,6 +40,8 @@
 	if (!per_cpu(cpu_is_managed, policy->cpu))
 		goto err;
 
+	*setspeed = freq;
+
 	ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
  err:
 	mutex_unlock(&userspace_mutex);
@@ -49,19 +53,45 @@
 	return sprintf(buf, "%u\n", policy->cur);
 }
 
+static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy)
+{
+	unsigned int *setspeed;
+
+	setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL);
+	if (!setspeed)
+		return -ENOMEM;
+
+	policy->governor_data = setspeed;
+	return 0;
+}
+
 static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
 				   unsigned int event)
 {
+	unsigned int *setspeed = policy->governor_data;
 	unsigned int cpu = policy->cpu;
 	int rc = 0;
 
+	if (event == CPUFREQ_GOV_POLICY_INIT)
+		return cpufreq_userspace_policy_init(policy);
+
+	if (!setspeed)
+		return -EINVAL;
+
 	switch (event) {
+	case CPUFREQ_GOV_POLICY_EXIT:
+		mutex_lock(&userspace_mutex);
+		policy->governor_data = NULL;
+		kfree(setspeed);
+		mutex_unlock(&userspace_mutex);
+		break;
 	case CPUFREQ_GOV_START:
 		BUG_ON(!policy->cur);
 		pr_debug("started managing cpu %u\n", cpu);
 
 		mutex_lock(&userspace_mutex);
 		per_cpu(cpu_is_managed, cpu) = 1;
+		*setspeed = policy->cur;
 		mutex_unlock(&userspace_mutex);
 		break;
 	case CPUFREQ_GOV_STOP:
@@ -69,20 +99,23 @@
 
 		mutex_lock(&userspace_mutex);
 		per_cpu(cpu_is_managed, cpu) = 0;
+		*setspeed = 0;
 		mutex_unlock(&userspace_mutex);
 		break;
 	case CPUFREQ_GOV_LIMITS:
 		mutex_lock(&userspace_mutex);
-		pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n",
-			cpu, policy->min, policy->max,
-			policy->cur);
+		pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n",
+			cpu, policy->min, policy->max, policy->cur, *setspeed);
 
-		if (policy->max < policy->cur)
+		if (policy->max < *setspeed)
 			__cpufreq_driver_target(policy, policy->max,
 						CPUFREQ_RELATION_H);
-		else if (policy->min > policy->cur)
+		else if (policy->min > *setspeed)
 			__cpufreq_driver_target(policy, policy->min,
 						CPUFREQ_RELATION_L);
+		else
+			__cpufreq_driver_target(policy, *setspeed,
+						CPUFREQ_RELATION_L);
 		mutex_unlock(&userspace_mutex);
 		break;
 	}
--- linux-4.4.0.orig/drivers/cpufreq/highbank-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/highbank-cpufreq.c
@@ -104,6 +104,13 @@
 }
 module_init(hb_cpufreq_driver_init);
 
+static const struct of_device_id __maybe_unused hb_cpufreq_of_match[] = {
+	{ .compatible = "calxeda,highbank" },
+	{ .compatible = "calxeda,ecx-2000" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, hb_cpufreq_of_match);
+
 MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
 MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/cpufreq/imx6q-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/imx6q-cpufreq.c
@@ -130,8 +130,13 @@
 	/* Ensure the arm clock divider is what we expect */
 	ret = clk_set_rate(arm_clk, new_freq * 1000);
 	if (ret) {
+		int ret1;
+
 		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
-		regulator_set_voltage_tol(arm_reg, volt_old, 0);
+		ret1 = regulator_set_voltage_tol(arm_reg, volt_old, 0);
+		if (ret1)
+			dev_warn(cpu_dev,
+				 "failed to restore vddarm voltage: %d\n", ret1);
 		return ret;
 	}
 
--- linux-4.4.0.orig/drivers/cpufreq/intel_pstate.c
+++ linux-4.4.0/drivers/cpufreq/intel_pstate.c
@@ -285,14 +285,14 @@
 	int min, hw_min, max, hw_max, cpu, range, adj_range;
 	u64 value, cap;
 
-	rdmsrl(MSR_HWP_CAPABILITIES, cap);
-	hw_min = HWP_LOWEST_PERF(cap);
-	hw_max = HWP_HIGHEST_PERF(cap);
-	range = hw_max - hw_min;
-
 	get_online_cpus();
 
 	for_each_online_cpu(cpu) {
+		rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap);
+		hw_min = HWP_LOWEST_PERF(cap);
+		hw_max = HWP_HIGHEST_PERF(cap);
+		range = hw_max - hw_min;
+
 		rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value);
 		adj_range = limits->min_perf_pct * range / 100;
 		min = hw_min + adj_range;
@@ -368,13 +368,13 @@
 /************************** sysfs begin ************************/
 #define show_one(file_name, object)					\
 	static ssize_t show_##file_name					\
-	(struct kobject *kobj, struct attribute *attr, char *buf)	\
+	(struct kobject *kobj, struct kobj_attribute *attr, char *buf)	\
 	{								\
 		return sprintf(buf, "%u\n", limits->object);		\
 	}
 
 static ssize_t show_turbo_pct(struct kobject *kobj,
-				struct attribute *attr, char *buf)
+				struct kobj_attribute *attr, char *buf)
 {
 	struct cpudata *cpu;
 	int total, no_turbo, turbo_pct;
@@ -390,7 +390,7 @@
 }
 
 static ssize_t show_num_pstates(struct kobject *kobj,
-				struct attribute *attr, char *buf)
+				struct kobj_attribute *attr, char *buf)
 {
 	struct cpudata *cpu;
 	int total;
@@ -401,7 +401,7 @@
 }
 
 static ssize_t show_no_turbo(struct kobject *kobj,
-			     struct attribute *attr, char *buf)
+			     struct kobj_attribute *attr, char *buf)
 {
 	ssize_t ret;
 
@@ -414,7 +414,7 @@
 	return ret;
 }
 
-static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
+static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b,
 			      const char *buf, size_t count)
 {
 	unsigned int input;
@@ -438,7 +438,7 @@
 	return count;
 }
 
-static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
+static ssize_t store_max_perf_pct(struct kobject *a, struct kobj_attribute *b,
 				  const char *buf, size_t count)
 {
 	unsigned int input;
@@ -463,7 +463,7 @@
 	return count;
 }
 
-static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
+static ssize_t store_min_perf_pct(struct kobject *a, struct kobj_attribute *b,
 				  const char *buf, size_t count)
 {
 	unsigned int input;
@@ -662,11 +662,16 @@
 			if (err)
 				goto skip_tar;
 
-			tdp_msr = MSR_CONFIG_TDP_NOMINAL + tdp_ctrl;
+			tdp_msr = MSR_CONFIG_TDP_NOMINAL + (tdp_ctrl & 0x3);
 			err = rdmsrl_safe(tdp_msr, &tdp_ratio);
 			if (err)
 				goto skip_tar;
 
+			/* For level 1 and 2, bits[23:16] contain the ratio */
+			if (tdp_ctrl)
+				tdp_ratio >>= 16;
+
+			tdp_ratio &= 0xff; /* ratios are only 8 bits long */
 			if (tdp_ratio - 1 == tar) {
 				max_pstate = tar;
 				pr_debug("max_pstate=TAC %x\n", max_pstate);
@@ -1356,6 +1361,11 @@
 static inline bool intel_pstate_has_acpi_ppc(void) { return false; }
 #endif /* CONFIG_ACPI */
 
+static const struct x86_cpu_id hwp_support_ids[] __initconst = {
+	{ X86_VENDOR_INTEL, 6, X86_MODEL_ANY, X86_FEATURE_HWP },
+	{}
+};
+
 static int __init intel_pstate_init(void)
 {
 	int cpu, rc = 0;
@@ -1365,17 +1375,16 @@
 	if (no_load)
 		return -ENODEV;
 
+	if (x86_match_cpu(hwp_support_ids) && !no_hwp) {
+		copy_cpu_funcs(&core_params.funcs);
+		hwp_active++;
+		goto hwp_cpu_matched;
+	}
+
 	id = x86_match_cpu(intel_pstate_cpu_ids);
 	if (!id)
 		return -ENODEV;
 
-	/*
-	 * The Intel pstate driver will be ignored if the platform
-	 * firmware has its own power management modes.
-	 */
-	if (intel_pstate_platform_pwr_mgmt_exists())
-		return -ENODEV;
-
 	cpu_def = (struct cpu_defaults *)id->driver_data;
 
 	copy_pid_params(&cpu_def->pid_policy);
@@ -1384,17 +1393,20 @@
 	if (intel_pstate_msrs_not_valid())
 		return -ENODEV;
 
+hwp_cpu_matched:
+	/*
+	 * The Intel pstate driver will be ignored if the platform
+	 * firmware has its own power management modes.
+	 */
+	if (intel_pstate_platform_pwr_mgmt_exists())
+		return -ENODEV;
+
 	pr_info("Intel P-state driver initializing.\n");
 
 	all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus());
 	if (!all_cpu_data)
 		return -ENOMEM;
 
-	if (static_cpu_has_safe(X86_FEATURE_HWP) && !no_hwp) {
-		pr_info("intel_pstate: HWP enabled\n");
-		hwp_active++;
-	}
-
 	if (!hwp_active && hwp_only)
 		goto out;
 
@@ -1405,6 +1417,9 @@
 	intel_pstate_debug_expose_params();
 	intel_pstate_sysfs_expose_params();
 
+	if (hwp_active)
+		pr_info("intel_pstate: HWP enabled\n");
+
 	return rc;
 out:
 	get_online_cpus();
--- linux-4.4.0.orig/drivers/cpufreq/longhaul.c
+++ linux-4.4.0/drivers/cpufreq/longhaul.c
@@ -786,7 +786,7 @@
 		break;
 
 	case 7:
-		switch (c->x86_mask) {
+		switch (c->x86_stepping) {
 		case 0:
 			longhaul_version = TYPE_LONGHAUL_V1;
 			cpu_model = CPU_SAMUEL2;
@@ -798,7 +798,7 @@
 			break;
 		case 1 ... 15:
 			longhaul_version = TYPE_LONGHAUL_V2;
-			if (c->x86_mask < 8) {
+			if (c->x86_stepping < 8) {
 				cpu_model = CPU_SAMUEL2;
 				cpuname = "C3 'Samuel 2' [C5B]";
 			} else {
@@ -825,7 +825,7 @@
 		numscales = 32;
 		memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));
 		memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));
-		switch (c->x86_mask) {
+		switch (c->x86_stepping) {
 		case 0 ... 1:
 			cpu_model = CPU_NEHEMIAH;
 			cpuname = "C3 'Nehemiah A' [C5XLOE]";
--- linux-4.4.0.orig/drivers/cpufreq/ls1x-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/ls1x-cpufreq.c
@@ -217,6 +217,7 @@
 
 module_platform_driver(ls1x_cpufreq_platdrv);
 
+MODULE_ALIAS("platform:ls1x-cpufreq");
 MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>");
 MODULE_DESCRIPTION("Loongson 1 CPUFreq driver");
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/cpufreq/p4-clockmod.c
+++ linux-4.4.0/drivers/cpufreq/p4-clockmod.c
@@ -176,7 +176,7 @@
 #endif
 
 	/* Errata workaround */
-	cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask;
+	cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_stepping;
 	switch (cpuid) {
 	case 0x0f07:
 	case 0x0f0a:
--- linux-4.4.0.orig/drivers/cpufreq/pasemi-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/pasemi-cpufreq.c
@@ -145,10 +145,19 @@
 	int err = -ENODEV;
 
 	cpu = of_get_cpu_node(policy->cpu, NULL);
-
 	if (!cpu)
 		goto out;
 
+	max_freqp = of_get_property(cpu, "clock-frequency", NULL);
+	of_node_put(cpu);
+	if (!max_freqp) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	/* we need the freq in kHz */
+	max_freq = *max_freqp / 1000;
+
 	dn = of_find_compatible_node(NULL, NULL, "1682m-sdc");
 	if (!dn)
 		dn = of_find_compatible_node(NULL, NULL,
@@ -184,16 +193,6 @@
 	}
 
 	pr_debug("init cpufreq on CPU %d\n", policy->cpu);
-
-	max_freqp = of_get_property(cpu, "clock-frequency", NULL);
-	if (!max_freqp) {
-		err = -EINVAL;
-		goto out_unmap_sdcpwr;
-	}
-
-	/* we need the freq in kHz */
-	max_freq = *max_freqp / 1000;
-
 	pr_debug("max clock-frequency is at %u kHz\n", max_freq);
 	pr_debug("initializing frequency table\n");
 
@@ -211,9 +210,6 @@
 
 	return cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
 
-out_unmap_sdcpwr:
-	iounmap(sdcpwr_mapbase);
-
 out_unmap_sdcasr:
 	iounmap(sdcasr_mapbase);
 out:
--- linux-4.4.0.orig/drivers/cpufreq/pmac32-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/pmac32-cpufreq.c
@@ -549,6 +549,7 @@
 	volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
 	if (volt_gpio_np)
 		voltage_gpio = read_gpio(volt_gpio_np);
+	of_node_put(volt_gpio_np);
 	if (!voltage_gpio){
 		printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n");
 		return 1;
@@ -585,6 +586,7 @@
 	if (volt_gpio_np)
 		voltage_gpio = read_gpio(volt_gpio_np);
 
+	of_node_put(volt_gpio_np);
 	pvr = mfspr(SPRN_PVR);
 	has_cpu_l2lve = !((pvr & 0xf00) == 0x100);
 
--- linux-4.4.0.orig/drivers/cpufreq/powernow-k7.c
+++ linux-4.4.0/drivers/cpufreq/powernow-k7.c
@@ -132,7 +132,7 @@
 		return 0;
 	}
 
-	if ((c->x86_model == 6) && (c->x86_mask == 0)) {
+	if ((c->x86_model == 6) && (c->x86_stepping == 0)) {
 		printk(KERN_INFO PFX "K7 660[A0] core detected, "
 				"enabling errata workarounds\n");
 		have_a0 = 1;
--- linux-4.4.0.orig/drivers/cpufreq/powernow-k8.c
+++ linux-4.4.0/drivers/cpufreq/powernow-k8.c
@@ -887,9 +887,9 @@
 
 /* Take a frequency, and issue the fid/vid transition command */
 static int transition_frequency_fidvid(struct powernow_k8_data *data,
-		unsigned int index)
+		unsigned int index,
+		struct cpufreq_policy *policy)
 {
-	struct cpufreq_policy *policy;
 	u32 fid = 0;
 	u32 vid = 0;
 	int res;
@@ -921,9 +921,6 @@
 	freqs.old = find_khz_freq_from_fid(data->currfid);
 	freqs.new = find_khz_freq_from_fid(fid);
 
-	policy = cpufreq_cpu_get(smp_processor_id());
-	cpufreq_cpu_put(policy);
-
 	cpufreq_freq_transition_begin(policy, &freqs);
 	res = transition_fid_vid(data, fid, vid);
 	cpufreq_freq_transition_end(policy, &freqs, res);
@@ -978,7 +975,7 @@
 
 	powernow_k8_acpi_pst_values(data, newstate);
 
-	ret = transition_frequency_fidvid(data, newstate);
+	ret = transition_frequency_fidvid(data, newstate, pol);
 
 	if (ret) {
 		pr_err("transition frequency failed\n");
--- linux-4.4.0.orig/drivers/cpufreq/powernv-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/powernv-cpufreq.c
@@ -28,6 +28,8 @@
 #include <linux/of.h>
 #include <linux/reboot.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
+#include <trace/events/power.h>
 
 #include <asm/cputhreads.h>
 #include <asm/firmware.h>
@@ -43,15 +45,39 @@
 static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
 static bool rebooting, throttled, occ_reset;
 
+static const char * const throttle_reason[] = {
+	"No throttling",
+	"Power Cap",
+	"Processor Over Temperature",
+	"Power Supply Failure",
+	"Over Current",
+	"OCC Reset"
+};
+
+enum throttle_reason_type {
+	NO_THROTTLE = 0,
+	POWERCAP,
+	CPU_OVERTEMP,
+	POWER_SUPPLY_FAILURE,
+	OVERCURRENT,
+	OCC_RESET_THROTTLE,
+	OCC_MAX_REASON
+};
+
 static struct chip {
 	unsigned int id;
 	bool throttled;
+	bool restore;
+	u8 throttle_reason;
 	cpumask_t mask;
 	struct work_struct throttle;
-	bool restore;
+	int throttle_turbo;
+	int throttle_sub_turbo;
+	int reason[OCC_MAX_REASON];
 } *chips;
 
 static int nr_chips;
+static DEFINE_PER_CPU(struct chip *, chip_info);
 
 /*
  * Note: The set of pstates consists of contiguous integers, the
@@ -183,6 +209,42 @@
 	NULL,
 };
 
+#define throttle_attr(name, member)					\
+static ssize_t name##_show(struct cpufreq_policy *policy, char *buf)	\
+{									\
+	struct chip *chip = per_cpu(chip_info, policy->cpu);		\
+									\
+	return sprintf(buf, "%u\n", chip->member);			\
+}									\
+									\
+static struct freq_attr throttle_attr_##name = __ATTR_RO(name)		\
+
+throttle_attr(unthrottle, reason[NO_THROTTLE]);
+throttle_attr(powercap, reason[POWERCAP]);
+throttle_attr(overtemp, reason[CPU_OVERTEMP]);
+throttle_attr(supply_fault, reason[POWER_SUPPLY_FAILURE]);
+throttle_attr(overcurrent, reason[OVERCURRENT]);
+throttle_attr(occ_reset, reason[OCC_RESET_THROTTLE]);
+throttle_attr(turbo_stat, throttle_turbo);
+throttle_attr(sub_turbo_stat, throttle_sub_turbo);
+
+static struct attribute *throttle_attrs[] = {
+	&throttle_attr_unthrottle.attr,
+	&throttle_attr_powercap.attr,
+	&throttle_attr_overtemp.attr,
+	&throttle_attr_supply_fault.attr,
+	&throttle_attr_overcurrent.attr,
+	&throttle_attr_occ_reset.attr,
+	&throttle_attr_turbo_stat.attr,
+	&throttle_attr_sub_turbo_stat.attr,
+	NULL,
+};
+
+static const struct attribute_group throttle_attr_grp = {
+	.name	= "throttle_stats",
+	.attrs	= throttle_attrs,
+};
+
 /* Helper routines */
 
 /* Access helpers to power mgt SPR */
@@ -311,34 +373,36 @@
 
 static void powernv_cpufreq_throttle_check(void *data)
 {
+	struct chip *chip;
 	unsigned int cpu = smp_processor_id();
 	unsigned long pmsr;
-	int pmsr_pmax, i;
+	int pmsr_pmax;
 
 	pmsr = get_pmspr(SPRN_PMSR);
-
-	for (i = 0; i < nr_chips; i++)
-		if (chips[i].id == cpu_to_chip_id(cpu))
-			break;
+	chip = this_cpu_read(chip_info);
 
 	/* Check for Pmax Capping */
 	pmsr_pmax = (s8)PMSR_MAX(pmsr);
 	if (pmsr_pmax != powernv_pstate_info.max) {
-		if (chips[i].throttled)
+		if (chip->throttled)
 			goto next;
-		chips[i].throttled = true;
-		if (pmsr_pmax < powernv_pstate_info.nominal)
-			pr_crit("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
-				cpu, chips[i].id, pmsr_pmax,
-				powernv_pstate_info.nominal);
-		else
-			pr_info("CPU %d on Chip %u has Pmax reduced below turbo frequency (%d < %d)\n",
-				cpu, chips[i].id, pmsr_pmax,
-				powernv_pstate_info.max);
-	} else if (chips[i].throttled) {
-		chips[i].throttled = false;
-		pr_info("CPU %d on Chip %u has Pmax restored to %d\n", cpu,
-			chips[i].id, pmsr_pmax);
+		chip->throttled = true;
+		if (pmsr_pmax < powernv_pstate_info.nominal) {
+			pr_warn_once("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
+				     cpu, chip->id, pmsr_pmax,
+				     powernv_pstate_info.nominal);
+			chip->throttle_sub_turbo++;
+		} else {
+			chip->throttle_turbo++;
+		}
+		trace_powernv_throttle(chip->id,
+				      throttle_reason[chip->throttle_reason],
+				      pmsr_pmax);
+	} else if (chip->throttled) {
+		chip->throttled = false;
+		trace_powernv_throttle(chip->id,
+				      throttle_reason[chip->throttle_reason],
+				      pmsr_pmax);
 	}
 
 	/* Check if Psafe_mode_active is set in PMSR. */
@@ -356,7 +420,7 @@
 
 	if (throttled) {
 		pr_info("PMSR = %16lx\n", pmsr);
-		pr_crit("CPU Frequency could be throttled\n");
+		pr_warn("CPU Frequency could be throttled\n");
 	}
 }
 
@@ -373,8 +437,14 @@
 	if (unlikely(rebooting) && new_index != get_nominal_index())
 		return 0;
 
-	if (!throttled)
+	if (!throttled) {
+		/* we don't want to be preempted while
+		 * checking if the CPU frequency has been throttled
+		 */
+		preempt_disable();
 		powernv_cpufreq_throttle_check(NULL);
+		preempt_enable();
+	}
 
 	freq_data.pstate_id = powernv_freqs[new_index].driver_data;
 
@@ -397,6 +467,21 @@
 	for (i = 0; i < threads_per_core; i++)
 		cpumask_set_cpu(base + i, policy->cpus);
 
+	if (!policy->driver_data) {
+		int ret;
+
+		ret = sysfs_create_group(&policy->kobj, &throttle_attr_grp);
+		if (ret) {
+			pr_info("Failed to create throttle stats directory for cpu %d\n",
+				policy->cpu);
+			return ret;
+		}
+		/*
+		 * policy->driver_data is used as a flag for one-time
+		 * creation of throttle sysfs files.
+		 */
+		policy->driver_data = policy;
+	}
 	return cpufreq_table_validate_and_show(policy, powernv_freqs);
 }
 
@@ -404,12 +489,15 @@
 				unsigned long action, void *unused)
 {
 	int cpu;
-	struct cpufreq_policy cpu_policy;
+	struct cpufreq_policy *cpu_policy;
 
 	rebooting = true;
 	for_each_online_cpu(cpu) {
-		cpufreq_get_policy(&cpu_policy, cpu);
-		powernv_cpufreq_target_index(&cpu_policy, get_nominal_index());
+		cpu_policy = cpufreq_cpu_get(cpu);
+		if (!cpu_policy)
+			continue;
+		powernv_cpufreq_target_index(cpu_policy, get_nominal_index());
+		cpufreq_cpu_put(cpu_policy);
 	}
 
 	return NOTIFY_DONE;
@@ -423,18 +511,19 @@
 {
 	struct chip *chip = container_of(work, struct chip, throttle);
 	unsigned int cpu;
-	cpumask_var_t mask;
+	cpumask_t mask;
 
-	smp_call_function_any(&chip->mask,
+	get_online_cpus();
+	cpumask_and(&mask, &chip->mask, cpu_online_mask);
+	smp_call_function_any(&mask,
 			      powernv_cpufreq_throttle_check, NULL, 0);
 
 	if (!chip->restore)
-		return;
+		goto out;
 
 	chip->restore = false;
-	cpumask_copy(mask, &chip->mask);
-	for_each_cpu_and(cpu, mask, cpu_online_mask) {
-		int index, tcpu;
+	for_each_cpu(cpu, &mask) {
+		int index;
 		struct cpufreq_policy policy;
 
 		cpufreq_get_policy(&policy, cpu);
@@ -442,20 +531,12 @@
 					       policy.cur,
 					       CPUFREQ_RELATION_C, &index);
 		powernv_cpufreq_target_index(&policy, index);
-		for_each_cpu(tcpu, policy.cpus)
-			cpumask_clear_cpu(tcpu, mask);
+		cpumask_andnot(&mask, &mask, policy.cpus);
 	}
+out:
+	put_online_cpus();
 }
 
-static char throttle_reason[][30] = {
-					"No throttling",
-					"Power Cap",
-					"Processor Over Temperature",
-					"Power Supply Failure",
-					"Over Current",
-					"OCC Reset"
-				     };
-
 static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
 				   unsigned long msg_type, void *_msg)
 {
@@ -481,7 +562,7 @@
 		 */
 		if (!throttled) {
 			throttled = true;
-			pr_crit("CPU frequency is throttled for duration\n");
+			pr_warn("CPU frequency is throttled for duration\n");
 		}
 
 		break;
@@ -505,23 +586,20 @@
 			return 0;
 		}
 
-		if (omsg.throttle_status &&
-		    omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS)
-			pr_info("OCC: Chip %u Pmax reduced due to %s\n",
-				(unsigned int)omsg.chip,
-				throttle_reason[omsg.throttle_status]);
-		else if (!omsg.throttle_status)
-			pr_info("OCC: Chip %u %s\n", (unsigned int)omsg.chip,
-				throttle_reason[omsg.throttle_status]);
-		else
-			return 0;
-
 		for (i = 0; i < nr_chips; i++)
-			if (chips[i].id == omsg.chip) {
-				if (!omsg.throttle_status)
-					chips[i].restore = true;
-				schedule_work(&chips[i].throttle);
-			}
+			if (chips[i].id == omsg.chip)
+				break;
+
+		if (omsg.throttle_status >= 0 &&
+		    omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS) {
+			chips[i].throttle_reason = omsg.throttle_status;
+			chips[i].reason[omsg.throttle_status]++;
+		}
+
+		if (!omsg.throttle_status)
+			chips[i].restore = true;
+
+		schedule_work(&chips[i].throttle);
 	}
 	return 0;
 }
@@ -566,53 +644,72 @@
 		}
 	}
 
-	chips = kmalloc_array(nr_chips, sizeof(struct chip), GFP_KERNEL);
+	chips = kcalloc(nr_chips, sizeof(struct chip), GFP_KERNEL);
 	if (!chips)
 		return -ENOMEM;
 
 	for (i = 0; i < nr_chips; i++) {
 		chips[i].id = chip[i];
-		chips[i].throttled = false;
 		cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i]));
 		INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn);
-		chips[i].restore = false;
+		for_each_cpu(cpu, &chips[i].mask)
+			per_cpu(chip_info, cpu) =  &chips[i];
 	}
 
 	return 0;
 }
 
+static inline void clean_chip_info(void)
+{
+	kfree(chips);
+}
+
+static inline void unregister_all_notifiers(void)
+{
+	opal_message_notifier_unregister(OPAL_MSG_OCC,
+					 &powernv_cpufreq_opal_nb);
+	unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
+}
+
 static int __init powernv_cpufreq_init(void)
 {
 	int rc = 0;
 
 	/* Don't probe on pseries (guest) platforms */
-	if (!firmware_has_feature(FW_FEATURE_OPALv3))
+	if (!firmware_has_feature(FW_FEATURE_OPAL))
 		return -ENODEV;
 
 	/* Discover pstates from device tree and init */
 	rc = init_powernv_pstates();
-	if (rc) {
-		pr_info("powernv-cpufreq disabled. System does not support PState control\n");
-		return rc;
-	}
+	if (rc)
+		goto out;
 
 	/* Populate chip info */
 	rc = init_chip_info();
 	if (rc)
-		return rc;
+		goto out;
 
 	register_reboot_notifier(&powernv_cpufreq_reboot_nb);
 	opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb);
-	return cpufreq_register_driver(&powernv_cpufreq_driver);
+
+	rc = cpufreq_register_driver(&powernv_cpufreq_driver);
+	if (!rc)
+		return 0;
+
+	pr_info("Failed to register the cpufreq driver (%d)\n", rc);
+	unregister_all_notifiers();
+	clean_chip_info();
+out:
+	pr_info("Platform driver disabled. System does not support PState control\n");
+	return rc;
 }
 module_init(powernv_cpufreq_init);
 
 static void __exit powernv_cpufreq_exit(void)
 {
-	unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
-	opal_message_notifier_unregister(OPAL_MSG_OCC,
-					 &powernv_cpufreq_opal_nb);
 	cpufreq_unregister_driver(&powernv_cpufreq_driver);
+	unregister_all_notifiers();
+	clean_chip_info();
 }
 module_exit(powernv_cpufreq_exit);
 
--- linux-4.4.0.orig/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -86,6 +86,7 @@
 	if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
 	    !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
 		pr_info("invalid CBE regs pointers for cpufreq\n");
+		of_node_put(cpu);
 		return -EINVAL;
 	}
 
--- linux-4.4.0.orig/drivers/cpufreq/pxa2xx-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -191,7 +191,7 @@
 	return ret;
 }
 
-static void __init pxa_cpufreq_init_voltages(void)
+static void pxa_cpufreq_init_voltages(void)
 {
 	vcc_core = regulator_get(NULL, "vcc_core");
 	if (IS_ERR(vcc_core)) {
@@ -202,12 +202,12 @@
 	}
 }
 #else
-static int pxa_cpufreq_change_voltage(struct pxa_freqs *pxa_freq)
+static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq)
 {
 	return 0;
 }
 
-static void __init pxa_cpufreq_init_voltages(void) { }
+static void pxa_cpufreq_init_voltages(void) { }
 #endif
 
 static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
--- linux-4.4.0.orig/drivers/cpufreq/s3c2416-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/s3c2416-cpufreq.c
@@ -400,7 +400,6 @@
 	rate = clk_get_rate(s3c_freq->hclk);
 	if (rate < 133 * 1000 * 1000) {
 		pr_err("cpufreq: HCLK not at 133MHz\n");
-		clk_put(s3c_freq->hclk);
 		ret = -EINVAL;
 		goto err_armclk;
 	}
--- linux-4.4.0.orig/drivers/cpufreq/s3c24xx-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -364,7 +364,13 @@
 static int s3c_cpufreq_init(struct cpufreq_policy *policy)
 {
 	policy->clk = clk_arm;
-	return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency);
+
+	policy->cpuinfo.transition_latency = cpu_cur.info->latency;
+
+	if (ftab)
+		return cpufreq_table_validate_and_show(policy, ftab);
+
+	return 0;
 }
 
 static int __init s3c_cpufreq_initclks(void)
--- linux-4.4.0.orig/drivers/cpufreq/scpi-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/scpi-cpufreq.c
@@ -119,6 +119,7 @@
 };
 module_platform_driver(scpi_cpufreq_platdrv);
 
+MODULE_ALIAS("platform:scpi-cpufreq");
 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
 MODULE_DESCRIPTION("ARM SCPI CPUFreq interface driver");
 MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/cpufreq/sh-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/sh-cpufreq.c
@@ -30,54 +30,63 @@
 
 static DEFINE_PER_CPU(struct clk, sh_cpuclk);
 
+struct cpufreq_target {
+	struct cpufreq_policy	*policy;
+	unsigned int		freq;
+};
+
 static unsigned int sh_cpufreq_get(unsigned int cpu)
 {
 	return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000;
 }
 
-/*
- * Here we notify other drivers of the proposed change and the final change.
- */
-static int sh_cpufreq_target(struct cpufreq_policy *policy,
-			     unsigned int target_freq,
-			     unsigned int relation)
+static long __sh_cpufreq_target(void *arg)
 {
-	unsigned int cpu = policy->cpu;
+	struct cpufreq_target *target = arg;
+	struct cpufreq_policy *policy = target->policy;
+	int cpu = policy->cpu;
 	struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
-	cpumask_t cpus_allowed;
 	struct cpufreq_freqs freqs;
 	struct device *dev;
 	long freq;
 
-	cpus_allowed = current->cpus_allowed;
-	set_cpus_allowed_ptr(current, cpumask_of(cpu));
-
-	BUG_ON(smp_processor_id() != cpu);
+	if (smp_processor_id() != cpu)
+		return -ENODEV;
 
 	dev = get_cpu_device(cpu);
 
 	/* Convert target_freq from kHz to Hz */
-	freq = clk_round_rate(cpuclk, target_freq * 1000);
+	freq = clk_round_rate(cpuclk, target->freq * 1000);
 
 	if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
 		return -EINVAL;
 
-	dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000);
+	dev_dbg(dev, "requested frequency %u Hz\n", target->freq * 1000);
 
 	freqs.old	= sh_cpufreq_get(cpu);
 	freqs.new	= (freq + 500) / 1000;
 	freqs.flags	= 0;
 
-	cpufreq_freq_transition_begin(policy, &freqs);
-	set_cpus_allowed_ptr(current, &cpus_allowed);
+	cpufreq_freq_transition_begin(target->policy, &freqs);
 	clk_set_rate(cpuclk, freq);
-	cpufreq_freq_transition_end(policy, &freqs, 0);
+	cpufreq_freq_transition_end(target->policy, &freqs, 0);
 
 	dev_dbg(dev, "set frequency %lu Hz\n", freq);
-
 	return 0;
 }
 
+/*
+ * Here we notify other drivers of the proposed change and the final change.
+ */
+static int sh_cpufreq_target(struct cpufreq_policy *policy,
+			     unsigned int target_freq,
+			     unsigned int relation)
+{
+	struct cpufreq_target data = { .policy = policy, .freq = target_freq };
+
+	return work_on_cpu(policy->cpu, __sh_cpufreq_target, &data);
+}
+
 static int sh_cpufreq_verify(struct cpufreq_policy *policy)
 {
 	struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu);
--- linux-4.4.0.orig/drivers/cpufreq/speedstep-centrino.c
+++ linux-4.4.0/drivers/cpufreq/speedstep-centrino.c
@@ -36,7 +36,7 @@
 {
 	__u8	x86;            /* CPU family */
 	__u8	x86_model;	/* model */
-	__u8	x86_mask;	/* stepping */
+	__u8	x86_stepping;	/* stepping */
 };
 
 enum {
@@ -276,7 +276,7 @@
 {
 	if ((c->x86 == x->x86) &&
 	    (c->x86_model == x->x86_model) &&
-	    (c->x86_mask == x->x86_mask))
+	    (c->x86_stepping == x->x86_stepping))
 		return 1;
 	return 0;
 }
--- linux-4.4.0.orig/drivers/cpufreq/speedstep-lib.c
+++ linux-4.4.0/drivers/cpufreq/speedstep-lib.c
@@ -270,9 +270,9 @@
 		ebx = cpuid_ebx(0x00000001);
 		ebx &= 0x000000FF;
 
-		pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
+		pr_debug("ebx value is %x, x86_stepping is %x\n", ebx, c->x86_stepping);
 
-		switch (c->x86_mask) {
+		switch (c->x86_stepping) {
 		case 4:
 			/*
 			 * B-stepping [M-P4-M]
@@ -359,7 +359,7 @@
 				msr_lo, msr_hi);
 		if ((msr_hi & (1<<18)) &&
 		    (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
-			if (c->x86_mask == 0x01) {
+			if (c->x86_stepping == 0x01) {
 				pr_debug("early PIII version\n");
 				return SPEEDSTEP_CPU_PIII_C_EARLY;
 			} else
--- linux-4.4.0.orig/drivers/cpufreq/speedstep-smi.c
+++ linux-4.4.0/drivers/cpufreq/speedstep-smi.c
@@ -377,7 +377,7 @@
 	cpufreq_unregister_driver(&speedstep_driver);
 }
 
-module_param(smi_port, int, 0444);
+module_param_hw(smi_port, int, ioport, 0444);
 module_param(smi_cmd,  int, 0444);
 module_param(smi_sig, uint, 0444);
 
--- linux-4.4.0.orig/drivers/cpufreq/tegra124-cpufreq.c
+++ linux-4.4.0/drivers/cpufreq/tegra124-cpufreq.c
@@ -141,6 +141,8 @@
 
 	platform_set_drvdata(pdev, priv);
 
+	of_node_put(np);
+
 	return 0;
 
 out_switch_to_pllx:
--- linux-4.4.0.orig/drivers/cpuidle/coupled.c
+++ linux-4.4.0/drivers/cpuidle/coupled.c
@@ -119,7 +119,6 @@
 
 #define CPUIDLE_COUPLED_NOT_IDLE	(-1)
 
-static DEFINE_MUTEX(cpuidle_coupled_lock);
 static DEFINE_PER_CPU(struct call_single_data, cpuidle_coupled_poke_cb);
 
 /*
--- linux-4.4.0.orig/drivers/cpuidle/cpuidle-arm.c
+++ linux-4.4.0/drivers/cpuidle/cpuidle-arm.c
@@ -50,7 +50,7 @@
 		 * call the CPU ops suspend protocol with idle index as a
 		 * parameter.
 		 */
-		arm_cpuidle_suspend(idx);
+		ret = arm_cpuidle_suspend(idx);
 
 		cpu_pm_exit();
 	}
@@ -135,6 +135,7 @@
 		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 		if (!dev) {
 			pr_err("Failed to allocate cpuidle device\n");
+			ret = -ENOMEM;
 			goto out_fail;
 		}
 		dev->cpu = cpu;
--- linux-4.4.0.orig/drivers/cpuidle/cpuidle-big_little.c
+++ linux-4.4.0/drivers/cpuidle/cpuidle-big_little.c
@@ -167,6 +167,7 @@
 {
 	int ret;
 	struct device_node *root = of_find_node_by_path("/");
+	const struct of_device_id *match_id;
 
 	if (!root)
 		return -ENODEV;
@@ -174,7 +175,11 @@
 	/*
 	 * Initialize the driver just for a compliant set of machines
 	 */
-	if (!of_match_node(compatible_machine_match, root))
+	match_id = of_match_node(compatible_machine_match, root);
+
+	of_node_put(root);
+
+	if (!match_id)
 		return -ENODEV;
 
 	if (!mcpm_is_available())
--- linux-4.4.0.orig/drivers/cpuidle/cpuidle-powernv.c
+++ linux-4.4.0/drivers/cpuidle/cpuidle-powernv.c
@@ -29,9 +29,31 @@
 
 static int max_idle_state;
 static struct cpuidle_state *cpuidle_state_table;
-static u64 snooze_timeout;
+static u64 default_snooze_timeout;
 static bool snooze_timeout_en;
 
+static u64 get_snooze_timeout(struct cpuidle_device *dev,
+			      struct cpuidle_driver *drv,
+			      int index)
+{
+	int i;
+
+	if (unlikely(!snooze_timeout_en))
+		return default_snooze_timeout;
+
+	for (i = index + 1; i < drv->state_count; i++) {
+		struct cpuidle_state *s = &drv->states[i];
+		struct cpuidle_state_usage *su = &dev->states_usage[i];
+
+		if (s->disabled || su->disable)
+			continue;
+
+		return s->target_residency * tb_ticks_per_usec;
+	}
+
+	return default_snooze_timeout;
+}
+
 static int snooze_loop(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv,
 			int index)
@@ -41,7 +63,7 @@
 	local_irq_enable();
 	set_thread_flag(TIF_POLLING_NRFLAG);
 
-	snooze_exit_time = get_tb() + snooze_timeout;
+	snooze_exit_time = get_tb() + get_snooze_timeout(dev, drv, index);
 	ppc64_runlatch_off();
 	while (!need_resched()) {
 		HMT_low();
@@ -160,6 +182,24 @@
 		drv->state_count += 1;
 	}
 
+	/*
+	 * On the PowerNV platform cpu_present may be less than cpu_possible in
+	 * cases when firmware detects the CPU, but it is not available to the
+	 * OS.  If CONFIG_HOTPLUG_CPU=n, then such CPUs are not hotplugable at
+	 * run time and hence cpu_devices are not created for those CPUs by the
+	 * generic topology_init().
+	 *
+	 * drv->cpumask defaults to cpu_possible_mask in
+	 * __cpuidle_driver_init().  This breaks cpuidle on PowerNV where
+	 * cpu_devices are not created for CPUs in cpu_possible_mask that
+	 * cannot be hot-added later at run time.
+	 *
+	 * Trying cpuidle_register_device() on a CPU without a cpu_device is
+	 * incorrect, so pass a correct CPU mask to the generic cpuidle driver.
+	 */
+
+	drv->cpumask = (struct cpumask *)cpu_present_mask;
+
 	return 0;
 }
 
@@ -264,15 +304,13 @@
 	if (cpuidle_disable != IDLE_NO_OVERRIDE)
 		return -ENODEV;
 
-	if (firmware_has_feature(FW_FEATURE_OPALv3)) {
+	if (firmware_has_feature(FW_FEATURE_OPAL)) {
 		cpuidle_state_table = powernv_states;
 		/* Device tree can indicate more idle states */
 		max_idle_state = powernv_add_idle_states();
-		if (max_idle_state > 1) {
+		default_snooze_timeout = TICK_USEC * tb_ticks_per_usec;
+		if (max_idle_state > 1)
 			snooze_timeout_en = true;
-			snooze_timeout = powernv_states[1].target_residency *
-					 tb_ticks_per_usec;
-		}
  	} else
  		return -ENODEV;
 
--- linux-4.4.0.orig/drivers/cpuidle/cpuidle-pseries.c
+++ linux-4.4.0/drivers/cpuidle/cpuidle-pseries.c
@@ -240,7 +240,13 @@
 		return -ENODEV;
 
 	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
-		if (lppaca_shared_proc(get_lppaca())) {
+		/*
+		 * Use local_paca instead of get_lppaca() since
+		 * preemption is not disabled, and it is not required in
+		 * fact, since lppaca_ptr does not need to be the value
+		 * associated to the current CPU, it can be from any CPU.
+		 */
+		if (lppaca_shared_proc(local_paca->lppaca_ptr)) {
 			cpuidle_state_table = shared_states;
 			max_idle_state = ARRAY_SIZE(shared_states);
 		} else {
--- linux-4.4.0.orig/drivers/cpuidle/cpuidle.c
+++ linux-4.4.0/drivers/cpuidle/cpuidle.c
@@ -189,6 +189,7 @@
 			return -EBUSY;
 		}
 		target_state = &drv->states[index];
+		broadcast = false;
 	}
 
 	/* Take note of the planned idle state. */
@@ -214,7 +215,7 @@
 		tick_broadcast_exit();
 	}
 
-	if (!cpuidle_state_is_coupled(drv, entered_state))
+	if (!cpuidle_state_is_coupled(drv, index))
 		local_irq_enable();
 
 	diff = ktime_to_us(ktime_sub(time_end, time_start));
@@ -433,6 +434,8 @@
 	list_del(&dev->device_list);
 	per_cpu(cpuidle_devices, dev->cpu) = NULL;
 	module_put(drv->owner);
+
+	dev->registered = 0;
 }
 
 static void __cpuidle_device_init(struct cpuidle_device *dev)
--- linux-4.4.0.orig/drivers/cpuidle/driver.c
+++ linux-4.4.0/drivers/cpuidle/driver.c
@@ -60,24 +60,23 @@
  * __cpuidle_set_driver - set per CPU driver variables for the given driver.
  * @drv: a valid pointer to a struct cpuidle_driver
  *
- * For each CPU in the driver's cpumask, unset the registered driver per CPU
- * to @drv.
- *
- * Returns 0 on success, -EBUSY if the CPUs have driver(s) already.
+ * Returns 0 on success, -EBUSY if any CPU in the cpumask have a driver
+ * different from drv already.
  */
 static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
 {
 	int cpu;
 
 	for_each_cpu(cpu, drv->cpumask) {
+		struct cpuidle_driver *old_drv;
 
-		if (__cpuidle_get_cpu_driver(cpu)) {
-			__cpuidle_unset_driver(drv);
+		old_drv = __cpuidle_get_cpu_driver(cpu);
+		if (old_drv && old_drv != drv)
 			return -EBUSY;
-		}
+	}
 
+	for_each_cpu(cpu, drv->cpumask)
 		per_cpu(cpuidle_drivers, cpu) = drv;
-	}
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/cpuidle/dt_idle_states.c
+++ linux-4.4.0/drivers/cpuidle/dt_idle_states.c
@@ -174,8 +174,10 @@
 		if (!state_node)
 			break;
 
-		if (!of_device_is_available(state_node))
+		if (!of_device_is_available(state_node)) {
+			of_node_put(state_node);
 			continue;
+		}
 
 		if (!idle_state_valid(state_node, i, cpumask)) {
 			pr_warn("%s idle state not valid, bailing out\n",
--- linux-4.4.0.orig/drivers/cpuidle/sysfs.c
+++ linux-4.4.0/drivers/cpuidle/sysfs.c
@@ -412,7 +412,7 @@
 		ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
 					   &kdev->kobj, "state%d", i);
 		if (ret) {
-			kfree(kobj);
+			kobject_put(&kobj->kobj);
 			goto error_state;
 		}
 		kobject_uevent(&kobj->kobj, KOBJ_ADD);
@@ -542,7 +542,7 @@
 	ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
 				   &kdev->kobj, "driver");
 	if (ret) {
-		kfree(kdrv);
+		kobject_put(&kdrv->kobj);
 		return ret;
 	}
 
@@ -613,6 +613,18 @@
 	struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
 	int error;
 
+	/*
+	 * Return if cpu_device is not setup for this CPU.
+	 *
+	 * This could happen if the arch did not set up cpu_device
+	 * since this CPU is not in cpu_present mask and the
+	 * driver did not send a correct CPU mask during registration.
+	 * Without this check we would end up passing bogus
+	 * value for &cpu_dev->kobj in kobject_init_and_add()
+	 */
+	if (!cpu_dev)
+		return -ENODEV;
+
 	kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
 	if (!kdev)
 		return -ENOMEM;
@@ -624,7 +636,7 @@
 	error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
 				   "cpuidle");
 	if (error) {
-		kfree(kdev);
+		kobject_put(&kdev->kobj);
 		return error;
 	}
 
--- linux-4.4.0.orig/drivers/crypto/amcc/crypto4xx_core.c
+++ linux-4.4.0/drivers/crypto/amcc/crypto4xx_core.c
@@ -207,7 +207,7 @@
 				  dev->pdr_pa);
 		return -ENOMEM;
 	}
-	memset(dev->pdr, 0,  sizeof(struct ce_pd) * PPC4XX_NUM_PD);
+	memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD);
 	dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device,
 				   256 * PPC4XX_NUM_PD,
 				   &dev->shadow_sa_pool_pa,
@@ -240,13 +240,15 @@
 
 static void crypto4xx_destroy_pdr(struct crypto4xx_device *dev)
 {
-	if (dev->pdr != NULL)
+	if (dev->pdr)
 		dma_free_coherent(dev->core_dev->device,
 				  sizeof(struct ce_pd) * PPC4XX_NUM_PD,
 				  dev->pdr, dev->pdr_pa);
+
 	if (dev->shadow_sa_pool)
 		dma_free_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD,
 				  dev->shadow_sa_pool, dev->shadow_sa_pool_pa);
+
 	if (dev->shadow_sr_pool)
 		dma_free_coherent(dev->core_dev->device,
 			sizeof(struct sa_state_record) * PPC4XX_NUM_PD,
@@ -397,12 +399,8 @@
 		dma_alloc_coherent(dev->core_dev->device,
 			dev->scatter_buffer_size * PPC4XX_NUM_SD,
 			&dev->scatter_buffer_pa, GFP_ATOMIC);
-	if (!dev->scatter_buffer_va) {
-		dma_free_coherent(dev->core_dev->device,
-				  sizeof(struct ce_sd) * PPC4XX_NUM_SD,
-				  dev->sdr, dev->sdr_pa);
+	if (!dev->scatter_buffer_va)
 		return -ENOMEM;
-	}
 
 	sd_array = dev->sdr;
 
@@ -416,12 +414,12 @@
 
 static void crypto4xx_destroy_sdr(struct crypto4xx_device *dev)
 {
-	if (dev->sdr != NULL)
+	if (dev->sdr)
 		dma_free_coherent(dev->core_dev->device,
 				  sizeof(struct ce_sd) * PPC4XX_NUM_SD,
 				  dev->sdr, dev->sdr_pa);
 
-	if (dev->scatter_buffer_va != NULL)
+	if (dev->scatter_buffer_va)
 		dma_free_coherent(dev->core_dev->device,
 				  dev->scatter_buffer_size * PPC4XX_NUM_SD,
 				  dev->scatter_buffer_va,
@@ -1029,12 +1027,10 @@
 			break;
 		}
 
-		if (rc) {
-			list_del(&alg->entry);
+		if (rc)
 			kfree(alg);
-		} else {
+		else
 			list_add_tail(&alg->entry, &sec_dev->alg_list);
-		}
 	}
 
 	return 0;
@@ -1188,7 +1184,7 @@
 
 	rc = crypto4xx_build_gdr(core_dev->dev);
 	if (rc)
-		goto err_build_gdr;
+		goto err_build_pdr;
 
 	rc = crypto4xx_build_sdr(core_dev->dev);
 	if (rc)
@@ -1230,12 +1226,11 @@
 err_request_irq:
 	irq_dispose_mapping(core_dev->irq);
 	tasklet_kill(&core_dev->tasklet);
-	crypto4xx_destroy_sdr(core_dev->dev);
 err_build_sdr:
+	crypto4xx_destroy_sdr(core_dev->dev);
 	crypto4xx_destroy_gdr(core_dev->dev);
-err_build_gdr:
-	crypto4xx_destroy_pdr(core_dev->dev);
 err_build_pdr:
+	crypto4xx_destroy_pdr(core_dev->dev);
 	kfree(core_dev->dev);
 err_alloc_dev:
 	kfree(core_dev);
--- linux-4.4.0.orig/drivers/crypto/amcc/crypto4xx_core.h
+++ linux-4.4.0/drivers/crypto/amcc/crypto4xx_core.h
@@ -32,12 +32,12 @@
 #define PPC405EX_CE_RESET                       0x00000008
 
 #define CRYPTO4XX_CRYPTO_PRIORITY		300
-#define PPC4XX_LAST_PD				63
-#define PPC4XX_NUM_PD				64
-#define PPC4XX_LAST_GD				1023
+#define PPC4XX_NUM_PD				256
+#define PPC4XX_LAST_PD				(PPC4XX_NUM_PD - 1)
 #define PPC4XX_NUM_GD				1024
-#define PPC4XX_LAST_SD				63
-#define PPC4XX_NUM_SD				64
+#define PPC4XX_LAST_GD				(PPC4XX_NUM_GD - 1)
+#define PPC4XX_NUM_SD				256
+#define PPC4XX_LAST_SD				(PPC4XX_NUM_SD - 1)
 #define PPC4XX_SD_BUFFER_SIZE			2048
 
 #define PD_ENTRY_INUSE				1
--- linux-4.4.0.orig/drivers/crypto/atmel-aes.c
+++ linux-4.4.0/drivers/crypto/atmel-aes.c
@@ -1396,9 +1396,9 @@
 	}
 
 	aes_dd->io_base = devm_ioremap_resource(&pdev->dev, aes_res);
-	if (!aes_dd->io_base) {
+	if (IS_ERR(aes_dd->io_base)) {
 		dev_err(dev, "can't ioremap\n");
-		err = -ENOMEM;
+		err = PTR_ERR(aes_dd->io_base);
 		goto res_err;
 	}
 
--- linux-4.4.0.orig/drivers/crypto/atmel-sha.c
+++ linux-4.4.0/drivers/crypto/atmel-sha.c
@@ -783,7 +783,7 @@
 	dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU |
 			SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY);
 
-	clk_disable_unprepare(dd->iclk);
+	clk_disable(dd->iclk);
 
 	if (req->base.complete)
 		req->base.complete(&req->base, err);
@@ -796,7 +796,7 @@
 {
 	int err;
 
-	err = clk_prepare_enable(dd->iclk);
+	err = clk_enable(dd->iclk);
 	if (err)
 		return err;
 
@@ -823,7 +823,7 @@
 	dev_info(dd->dev,
 			"version: 0x%x\n", dd->hw_version);
 
-	clk_disable_unprepare(dd->iclk);
+	clk_disable(dd->iclk);
 }
 
 static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
@@ -963,7 +963,9 @@
 	ctx->flags |= SHA_FLAGS_FINUP;
 
 	err1 = atmel_sha_update(req);
-	if (err1 == -EINPROGRESS || err1 == -EBUSY)
+	if (err1 == -EINPROGRESS ||
+	    (err1 == -EBUSY && (ahash_request_flags(req) &
+				CRYPTO_TFM_REQ_MAY_BACKLOG)))
 		return err1;
 
 	/*
@@ -1405,12 +1407,16 @@
 	}
 
 	sha_dd->io_base = devm_ioremap_resource(&pdev->dev, sha_res);
-	if (!sha_dd->io_base) {
+	if (IS_ERR(sha_dd->io_base)) {
 		dev_err(dev, "can't ioremap\n");
-		err = -ENOMEM;
+		err = PTR_ERR(sha_dd->io_base);
 		goto res_err;
 	}
 
+	err = clk_prepare(sha_dd->iclk);
+	if (err)
+		goto res_err;
+
 	atmel_sha_hw_version_init(sha_dd);
 
 	atmel_sha_get_cap(sha_dd);
@@ -1422,12 +1428,12 @@
 			if (IS_ERR(pdata)) {
 				dev_err(&pdev->dev, "platform data not available\n");
 				err = PTR_ERR(pdata);
-				goto res_err;
+				goto iclk_unprepare;
 			}
 		}
 		if (!pdata->dma_slave) {
 			err = -ENXIO;
-			goto res_err;
+			goto iclk_unprepare;
 		}
 		err = atmel_sha_dma_init(sha_dd, pdata);
 		if (err)
@@ -1458,6 +1464,8 @@
 	if (sha_dd->caps.has_dma)
 		atmel_sha_dma_cleanup(sha_dd);
 err_sha_dma:
+iclk_unprepare:
+	clk_unprepare(sha_dd->iclk);
 res_err:
 	tasklet_kill(&sha_dd->done_task);
 sha_dd_err:
@@ -1484,12 +1492,7 @@
 	if (sha_dd->caps.has_dma)
 		atmel_sha_dma_cleanup(sha_dd);
 
-	iounmap(sha_dd->io_base);
-
-	clk_put(sha_dd->iclk);
-
-	if (sha_dd->irq >= 0)
-		free_irq(sha_dd->irq, sha_dd);
+	clk_unprepare(sha_dd->iclk);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/crypto/atmel-tdes.c
+++ linux-4.4.0/drivers/crypto/atmel-tdes.c
@@ -1417,9 +1417,9 @@
 	}
 
 	tdes_dd->io_base = devm_ioremap_resource(&pdev->dev, tdes_res);
-	if (!tdes_dd->io_base) {
+	if (IS_ERR(tdes_dd->io_base)) {
 		dev_err(dev, "can't ioremap\n");
-		err = -ENOMEM;
+		err = PTR_ERR(tdes_dd->io_base);
 		goto res_err;
 	}
 
--- linux-4.4.0.orig/drivers/crypto/caam/caamalg.c
+++ linux-4.4.0/drivers/crypto/caam/caamalg.c
@@ -75,7 +75,7 @@
 #define DESC_AEAD_BASE			(4 * CAAM_CMD_SZ)
 #define DESC_AEAD_ENC_LEN		(DESC_AEAD_BASE + 11 * CAAM_CMD_SZ)
 #define DESC_AEAD_DEC_LEN		(DESC_AEAD_BASE + 15 * CAAM_CMD_SZ)
-#define DESC_AEAD_GIVENC_LEN		(DESC_AEAD_ENC_LEN + 9 * CAAM_CMD_SZ)
+#define DESC_AEAD_GIVENC_LEN		(DESC_AEAD_ENC_LEN + 10 * CAAM_CMD_SZ)
 
 /* Note: Nonce is counted in enckeylen */
 #define DESC_AEAD_CTR_RFC3686_LEN	(4 * CAAM_CMD_SZ)
@@ -437,10 +437,14 @@
 	u32 geniv, moveiv;
 	u32 ctx1_iv_off = 0;
 	u32 *desc;
+	u32 *wait_cmd;
 	const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) ==
 			       OP_ALG_AAI_CTR_MOD128);
 	const bool is_rfc3686 = alg->caam.rfc3686;
 
+	if (!ctx->authsize)
+		return 0;
+
 	/* NULL encryption / decryption */
 	if (!ctx->enckeylen)
 		return aead_null_set_sh_desc(aead);
@@ -553,7 +557,10 @@
 
 	/* Read and write assoclen bytes */
 	append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
-	append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
+	if (alg->caam.geniv)
+		append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, ivsize);
+	else
+		append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
 
 	/* Skip assoc data */
 	append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
@@ -562,6 +569,14 @@
 	append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG |
 			     KEY_VLF);
 
+	if (alg->caam.geniv) {
+		append_seq_load(desc, ivsize, LDST_CLASS_1_CCB |
+				LDST_SRCDST_BYTE_CONTEXT |
+				(ctx1_iv_off << LDST_OFFSET_SHIFT));
+		append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO |
+			    (ctx1_iv_off << MOVE_OFFSET_SHIFT) | ivsize);
+	}
+
 	/* Load Counter into CONTEXT1 reg */
 	if (is_rfc3686)
 		append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM |
@@ -614,7 +629,7 @@
 		keys_fit_inline = true;
 
 	/* aead_givencrypt shared descriptor */
-	desc = ctx->sh_desc_givenc;
+	desc = ctx->sh_desc_enc;
 
 	/* Note: Context registers are saved. */
 	init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686);
@@ -645,13 +660,13 @@
 	append_operation(desc, ctx->class2_alg_type |
 			 OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT);
 
-	/* ivsize + cryptlen = seqoutlen - authsize */
-	append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
-
 	/* Read and write assoclen bytes */
 	append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
 	append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
 
+	/* ivsize + cryptlen = seqoutlen - authsize */
+	append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
+
 	/* Skip assoc data */
 	append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
 
@@ -688,7 +703,17 @@
 
 	/* Will read cryptlen */
 	append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
-	aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2);
+
+	/*
+	 * Wait for IV transfer (ofifo -> class2) to finish before starting
+	 * ciphertext transfer (ofifo -> external memory).
+	 */
+	wait_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NIFP);
+	set_jump_tgt_here(desc, wait_cmd);
+
+	append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF |
+			     FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH);
+	append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF);
 
 	/* Write ICV */
 	append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB |
@@ -697,7 +722,7 @@
 	ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc,
 					      desc_bytes(desc),
 					      DMA_TO_DEVICE);
-	if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) {
+	if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) {
 		dev_err(jrdev, "unable to map shared descriptor\n");
 		return -ENOMEM;
 	}
@@ -2065,6 +2090,7 @@
 	if (unlikely(req->src != req->dst)) {
 		if (!edesc->dst_nents) {
 			dst_dma = sg_dma_address(req->dst);
+			out_options = 0;
 		} else {
 			dst_dma = edesc->sec4_sg_dma +
 				  sec4_sg_index *
@@ -2147,7 +2173,7 @@
 
 	init_aead_job(req, edesc, all_contig, encrypt);
 
-	if (ivsize && (is_rfc3686 || !(alg->caam.geniv && encrypt)))
+	if (ivsize && ((is_rfc3686 && encrypt) || !alg->caam.geniv))
 		append_load_as_imm(desc, req->iv, ivsize,
 				   LDST_CLASS_1_CCB |
 				   LDST_SRCDST_BYTE_CONTEXT |
@@ -2534,20 +2560,6 @@
 	return ret;
 }
 
-static int aead_givdecrypt(struct aead_request *req)
-{
-	struct crypto_aead *aead = crypto_aead_reqtfm(req);
-	unsigned int ivsize = crypto_aead_ivsize(aead);
-
-	if (req->cryptlen < ivsize)
-		return -EINVAL;
-
-	req->cryptlen -= ivsize;
-	req->assoclen += ivsize;
-
-	return aead_decrypt(req);
-}
-
 /*
  * allocate and map the ablkcipher extended descriptor for ablkcipher
  */
@@ -3207,7 +3219,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = MD5_DIGEST_SIZE,
 		},
@@ -3253,7 +3265,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = SHA1_DIGEST_SIZE,
 		},
@@ -3299,7 +3311,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = SHA224_DIGEST_SIZE,
 		},
@@ -3345,7 +3357,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = SHA256_DIGEST_SIZE,
 		},
@@ -3391,7 +3403,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = SHA384_DIGEST_SIZE,
 		},
@@ -3437,7 +3449,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = SHA512_DIGEST_SIZE,
 		},
@@ -3483,7 +3495,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES3_EDE_BLOCK_SIZE,
 			.maxauthsize = MD5_DIGEST_SIZE,
 		},
@@ -3531,7 +3543,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES3_EDE_BLOCK_SIZE,
 			.maxauthsize = SHA1_DIGEST_SIZE,
 		},
@@ -3579,7 +3591,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES3_EDE_BLOCK_SIZE,
 			.maxauthsize = SHA224_DIGEST_SIZE,
 		},
@@ -3627,7 +3639,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES3_EDE_BLOCK_SIZE,
 			.maxauthsize = SHA256_DIGEST_SIZE,
 		},
@@ -3675,7 +3687,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES3_EDE_BLOCK_SIZE,
 			.maxauthsize = SHA384_DIGEST_SIZE,
 		},
@@ -3723,7 +3735,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES3_EDE_BLOCK_SIZE,
 			.maxauthsize = SHA512_DIGEST_SIZE,
 		},
@@ -3769,7 +3781,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES_BLOCK_SIZE,
 			.maxauthsize = MD5_DIGEST_SIZE,
 		},
@@ -3815,7 +3827,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES_BLOCK_SIZE,
 			.maxauthsize = SHA1_DIGEST_SIZE,
 		},
@@ -3861,7 +3873,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES_BLOCK_SIZE,
 			.maxauthsize = SHA224_DIGEST_SIZE,
 		},
@@ -3907,7 +3919,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES_BLOCK_SIZE,
 			.maxauthsize = SHA256_DIGEST_SIZE,
 		},
@@ -3953,7 +3965,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES_BLOCK_SIZE,
 			.maxauthsize = SHA384_DIGEST_SIZE,
 		},
@@ -3999,7 +4011,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = DES_BLOCK_SIZE,
 			.maxauthsize = SHA512_DIGEST_SIZE,
 		},
@@ -4048,7 +4060,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = CTR_RFC3686_IV_SIZE,
 			.maxauthsize = MD5_DIGEST_SIZE,
 		},
@@ -4099,7 +4111,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = CTR_RFC3686_IV_SIZE,
 			.maxauthsize = SHA1_DIGEST_SIZE,
 		},
@@ -4150,7 +4162,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = CTR_RFC3686_IV_SIZE,
 			.maxauthsize = SHA224_DIGEST_SIZE,
 		},
@@ -4201,7 +4213,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = CTR_RFC3686_IV_SIZE,
 			.maxauthsize = SHA256_DIGEST_SIZE,
 		},
@@ -4252,7 +4264,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = CTR_RFC3686_IV_SIZE,
 			.maxauthsize = SHA384_DIGEST_SIZE,
 		},
@@ -4303,7 +4315,7 @@
 			.setkey = aead_setkey,
 			.setauthsize = aead_setauthsize,
 			.encrypt = aead_encrypt,
-			.decrypt = aead_givdecrypt,
+			.decrypt = aead_decrypt,
 			.ivsize = CTR_RFC3686_IV_SIZE,
 			.maxauthsize = SHA512_DIGEST_SIZE,
 		},
@@ -4542,6 +4554,15 @@
 		if (!aes_inst && (alg_sel == OP_ALG_ALGSEL_AES))
 				continue;
 
+		/*
+		 * Check support for AES modes not available
+		 * on LP devices.
+		 */
+		if ((cha_vid & CHA_ID_LS_AES_MASK) == CHA_ID_LS_AES_LP)
+			if ((alg->class1_alg_type & OP_ALG_AAI_MASK) ==
+			     OP_ALG_AAI_XTS)
+				continue;
+
 		t_alg = caam_alg_alloc(alg);
 		if (IS_ERR(t_alg)) {
 			err = PTR_ERR(t_alg);
--- linux-4.4.0.orig/drivers/crypto/caam/caamhash.c
+++ linux-4.4.0/drivers/crypto/caam/caamhash.c
@@ -498,7 +498,7 @@
 	ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result);
 	if (!ret) {
 		/* in progress */
-		wait_for_completion_interruptible(&result.completion);
+		wait_for_completion(&result.completion);
 		ret = result.err;
 #ifdef DEBUG
 		print_hex_dump(KERN_ERR,
@@ -1873,6 +1873,7 @@
 			 template->name);
 		snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
 			 template->driver_name);
+		t_alg->ahash_alg.setkey = NULL;
 	}
 	alg->cra_module = THIS_MODULE;
 	alg->cra_init = caam_hash_cra_init;
--- linux-4.4.0.orig/drivers/crypto/caam/caamrng.c
+++ linux-4.4.0/drivers/crypto/caam/caamrng.c
@@ -361,7 +361,10 @@
 		goto free_rng_ctx;
 
 	dev_info(dev, "registering rng-caam\n");
-	return hwrng_register(&caam_rng);
+
+	err = hwrng_register(&caam_rng);
+	if (!err)
+		return err;
 
 free_rng_ctx:
 	kfree(rng_ctx);
--- linux-4.4.0.orig/drivers/crypto/caam/ctrl.c
+++ linux-4.4.0/drivers/crypto/caam/ctrl.c
@@ -224,12 +224,16 @@
 		 * without any error (HW optimizations for later
 		 * CAAM eras), then try again.
 		 */
+		if (ret)
+			break;
+
 		rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
 		if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
-		    !(rdsta_val & (1 << sh_idx)))
+		    !(rdsta_val & (1 << sh_idx))) {
 			ret = -EAGAIN;
-		if (ret)
 			break;
+		}
+
 		dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
 		/* Clear the contents before recreating the descriptor */
 		memset(desc, 0x00, CAAM_CMD_SZ * 7);
@@ -278,7 +282,8 @@
 			/* Try to run it through DECO0 */
 			ret = run_descriptor_deco0(ctrldev, desc, &status);
 
-			if (ret || status) {
+			if (ret ||
+			    (status && status != JRSTA_SSRC_JUMP_HALT_CC)) {
 				dev_err(ctrldev,
 					"Failed to deinstantiate RNG4 SH%d\n",
 					sh_idx);
@@ -534,8 +539,8 @@
 	 * long pointers in master configuration register
 	 */
 	clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK, MCFGR_AWCACHE_CACH |
-		      MCFGR_WDENABLE | (sizeof(dma_addr_t) == sizeof(u64) ?
-					MCFGR_LONG_PTR : 0));
+		      MCFGR_AWCACHE_BUFF | MCFGR_WDENABLE |
+		      (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0));
 
 	/*
 	 *  Read the Compile Time paramters and SCFGR to determine
--- linux-4.4.0.orig/drivers/crypto/caam/jr.c
+++ linux-4.4.0/drivers/crypto/caam/jr.c
@@ -248,7 +248,7 @@
 struct device *caam_jr_alloc(void)
 {
 	struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL;
-	struct device *dev = NULL;
+	struct device *dev = ERR_PTR(-ENODEV);
 	int min_tfm_cnt	= INT_MAX;
 	int tfm_cnt;
 
--- linux-4.4.0.orig/drivers/crypto/caam/key_gen.c
+++ linux-4.4.0/drivers/crypto/caam/key_gen.c
@@ -103,7 +103,7 @@
 	ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result);
 	if (!ret) {
 		/* in progress */
-		wait_for_completion_interruptible(&result.completion);
+		wait_for_completion(&result.completion);
 		ret = result.err;
 #ifdef DEBUG
 		print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
--- linux-4.4.0.orig/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
+++ linux-4.4.0/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
@@ -220,6 +220,42 @@
 	return ccp_aes_cmac_finup(req);
 }
 
+static int ccp_aes_cmac_export(struct ahash_request *req, void *out)
+{
+	struct ccp_aes_cmac_req_ctx *rctx = ahash_request_ctx(req);
+	struct ccp_aes_cmac_exp_ctx state;
+
+	/* Don't let anything leak to 'out' */
+	memset(&state, 0, sizeof(state));
+
+	state.null_msg = rctx->null_msg;
+	memcpy(state.iv, rctx->iv, sizeof(state.iv));
+	state.buf_count = rctx->buf_count;
+	memcpy(state.buf, rctx->buf, sizeof(state.buf));
+
+	/* 'out' may not be aligned so memcpy from local variable */
+	memcpy(out, &state, sizeof(state));
+
+	return 0;
+}
+
+static int ccp_aes_cmac_import(struct ahash_request *req, const void *in)
+{
+	struct ccp_aes_cmac_req_ctx *rctx = ahash_request_ctx(req);
+	struct ccp_aes_cmac_exp_ctx state;
+
+	/* 'in' may not be aligned so memcpy to local variable */
+	memcpy(&state, in, sizeof(state));
+
+	memset(rctx, 0, sizeof(*rctx));
+	rctx->null_msg = state.null_msg;
+	memcpy(rctx->iv, state.iv, sizeof(rctx->iv));
+	rctx->buf_count = state.buf_count;
+	memcpy(rctx->buf, state.buf, sizeof(rctx->buf));
+
+	return 0;
+}
+
 static int ccp_aes_cmac_setkey(struct crypto_ahash *tfm, const u8 *key,
 			       unsigned int key_len)
 {
@@ -352,10 +388,13 @@
 	alg->final = ccp_aes_cmac_final;
 	alg->finup = ccp_aes_cmac_finup;
 	alg->digest = ccp_aes_cmac_digest;
+	alg->export = ccp_aes_cmac_export;
+	alg->import = ccp_aes_cmac_import;
 	alg->setkey = ccp_aes_cmac_setkey;
 
 	halg = &alg->halg;
 	halg->digestsize = AES_BLOCK_SIZE;
+	halg->statesize = sizeof(struct ccp_aes_cmac_exp_ctx);
 
 	base = &halg->base;
 	snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "cmac(aes)");
--- linux-4.4.0.orig/drivers/crypto/ccp/ccp-crypto-aes-xts.c
+++ linux-4.4.0/drivers/crypto/ccp/ccp-crypto-aes-xts.c
@@ -122,6 +122,7 @@
 	struct ccp_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
 	struct ccp_aes_req_ctx *rctx = ablkcipher_request_ctx(req);
 	unsigned int unit;
+	u32 unit_size;
 	int ret;
 
 	if (!ctx->u.aes.key_len)
@@ -133,11 +134,17 @@
 	if (!req->info)
 		return -EINVAL;
 
-	for (unit = 0; unit < ARRAY_SIZE(unit_size_map); unit++)
-		if (!(req->nbytes & (unit_size_map[unit].size - 1)))
-			break;
+	unit_size = CCP_XTS_AES_UNIT_SIZE__LAST;
+	if (req->nbytes <= unit_size_map[0].size) {
+		for (unit = 0; unit < ARRAY_SIZE(unit_size_map); unit++) {
+			if (!(req->nbytes & (unit_size_map[unit].size - 1))) {
+				unit_size = unit_size_map[unit].value;
+				break;
+			}
+		}
+	}
 
-	if ((unit_size_map[unit].value == CCP_XTS_AES_UNIT_SIZE__LAST) ||
+	if ((unit_size == CCP_XTS_AES_UNIT_SIZE__LAST) ||
 	    (ctx->u.aes.key_len != AES_KEYSIZE_128)) {
 		/* Use the fallback to process the request for any
 		 * unsupported unit sizes or key sizes
@@ -158,7 +165,7 @@
 	rctx->cmd.engine = CCP_ENGINE_XTS_AES_128;
 	rctx->cmd.u.xts.action = (encrypt) ? CCP_AES_ACTION_ENCRYPT
 					   : CCP_AES_ACTION_DECRYPT;
-	rctx->cmd.u.xts.unit_size = unit_size_map[unit].value;
+	rctx->cmd.u.xts.unit_size = unit_size;
 	rctx->cmd.u.xts.key = &ctx->u.aes.key_sg;
 	rctx->cmd.u.xts.key_len = ctx->u.aes.key_len;
 	rctx->cmd.u.xts.iv = &rctx->iv_sg;
--- linux-4.4.0.orig/drivers/crypto/ccp/ccp-crypto-sha.c
+++ linux-4.4.0/drivers/crypto/ccp/ccp-crypto-sha.c
@@ -207,6 +207,46 @@
 	return ccp_sha_finup(req);
 }
 
+static int ccp_sha_export(struct ahash_request *req, void *out)
+{
+	struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
+	struct ccp_sha_exp_ctx state;
+
+	/* Don't let anything leak to 'out' */
+	memset(&state, 0, sizeof(state));
+
+	state.type = rctx->type;
+	state.msg_bits = rctx->msg_bits;
+	state.first = rctx->first;
+	memcpy(state.ctx, rctx->ctx, sizeof(state.ctx));
+	state.buf_count = rctx->buf_count;
+	memcpy(state.buf, rctx->buf, sizeof(state.buf));
+
+	/* 'out' may not be aligned so memcpy from local variable */
+	memcpy(out, &state, sizeof(state));
+
+	return 0;
+}
+
+static int ccp_sha_import(struct ahash_request *req, const void *in)
+{
+	struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
+	struct ccp_sha_exp_ctx state;
+
+	/* 'in' may not be aligned so memcpy to local variable */
+	memcpy(&state, in, sizeof(state));
+
+	memset(rctx, 0, sizeof(*rctx));
+	rctx->type = state.type;
+	rctx->msg_bits = state.msg_bits;
+	rctx->first = state.first;
+	memcpy(rctx->ctx, state.ctx, sizeof(rctx->ctx));
+	rctx->buf_count = state.buf_count;
+	memcpy(rctx->buf, state.buf, sizeof(rctx->buf));
+
+	return 0;
+}
+
 static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key,
 			  unsigned int key_len)
 {
@@ -403,9 +443,12 @@
 	alg->final = ccp_sha_final;
 	alg->finup = ccp_sha_finup;
 	alg->digest = ccp_sha_digest;
+	alg->export = ccp_sha_export;
+	alg->import = ccp_sha_import;
 
 	halg = &alg->halg;
 	halg->digestsize = def->digest_size;
+	halg->statesize = sizeof(struct ccp_sha_exp_ctx);
 
 	base = &halg->base;
 	snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
--- linux-4.4.0.orig/drivers/crypto/ccp/ccp-crypto.h
+++ linux-4.4.0/drivers/crypto/ccp/ccp-crypto.h
@@ -129,6 +129,15 @@
 	struct ccp_cmd cmd;
 };
 
+struct ccp_aes_cmac_exp_ctx {
+	unsigned int null_msg;
+
+	u8 iv[AES_BLOCK_SIZE];
+
+	unsigned int buf_count;
+	u8 buf[AES_BLOCK_SIZE];
+};
+
 /***** SHA related defines *****/
 #define MAX_SHA_CONTEXT_SIZE	SHA256_DIGEST_SIZE
 #define MAX_SHA_BLOCK_SIZE	SHA256_BLOCK_SIZE
@@ -171,6 +180,19 @@
 	struct ccp_cmd cmd;
 };
 
+struct ccp_sha_exp_ctx {
+	enum ccp_sha_type type;
+
+	u64 msg_bits;
+
+	unsigned int first;
+
+	u8 ctx[MAX_SHA_CONTEXT_SIZE];
+
+	unsigned int buf_count;
+	u8 buf[MAX_SHA_BLOCK_SIZE];
+};
+
 /***** Common Context Structure *****/
 struct ccp_ctx {
 	int (*complete)(struct crypto_async_request *req, int ret);
--- linux-4.4.0.orig/drivers/crypto/ixp4xx_crypto.c
+++ linux-4.4.0/drivers/crypto/ixp4xx_crypto.c
@@ -533,7 +533,7 @@
 
 	if (crypt_virt) {
 		dma_free_coherent(dev,
-			NPE_QLEN_TOTAL * sizeof( struct crypt_ctl),
+			NPE_QLEN * sizeof(struct crypt_ctl),
 			crypt_virt, crypt_phys);
 	}
 	return;
--- linux-4.4.0.orig/drivers/crypto/marvell/cesa.c
+++ linux-4.4.0/drivers/crypto/marvell/cesa.c
@@ -306,7 +306,7 @@
 		return -ENOMEM;
 
 	dma->padding_pool = dmam_pool_create("cesa_padding", dev, 72, 1, 0);
-	if (!dma->cache_pool)
+	if (!dma->padding_pool)
 		return -ENOMEM;
 
 	cesa->dma = dma;
@@ -420,7 +420,7 @@
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
 	cesa->regs = devm_ioremap_resource(dev, res);
 	if (IS_ERR(cesa->regs))
-		return -ENOMEM;
+		return PTR_ERR(cesa->regs);
 
 	ret = mv_cesa_dev_dma_init(cesa);
 	if (ret)
--- linux-4.4.0.orig/drivers/crypto/mxs-dcp.c
+++ linux-4.4.0/drivers/crypto/mxs-dcp.c
@@ -25,12 +25,28 @@
 #include <crypto/aes.h>
 #include <crypto/sha.h>
 #include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
 
 #define DCP_MAX_CHANS	4
 #define DCP_BUF_SZ	PAGE_SIZE
+#define DCP_SHA_PAY_SZ  64
 
 #define DCP_ALIGNMENT	64
 
+/*
+ * Null hashes to align with hw behavior on imx6sl and ull
+ * these are flipped for consistency with hw output
+ */
+static const uint8_t sha1_null_hash[] =
+	"\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf"
+	"\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda";
+
+static const uint8_t sha256_null_hash[] =
+	"\x55\xb8\x52\x78\x1b\x99\x95\xa4"
+	"\x4c\x93\x9b\x64\xe4\x41\xae\x27"
+	"\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a"
+	"\x14\x1c\xfc\x98\x42\xc4\xb0\xe3";
+
 /* DCP DMA descriptor. */
 struct dcp_dma_desc {
 	uint32_t	next_cmd_addr;
@@ -48,6 +64,7 @@
 	uint8_t			aes_in_buf[DCP_BUF_SZ];
 	uint8_t			aes_out_buf[DCP_BUF_SZ];
 	uint8_t			sha_in_buf[DCP_BUF_SZ];
+	uint8_t			sha_out_buf[DCP_SHA_PAY_SZ];
 
 	uint8_t			aes_key[2 * AES_KEYSIZE_128];
 
@@ -63,7 +80,7 @@
 	struct dcp_coherent_block	*coh;
 
 	struct completion		completion[DCP_MAX_CHANS];
-	struct mutex			mutex[DCP_MAX_CHANS];
+	spinlock_t			lock[DCP_MAX_CHANS];
 	struct task_struct		*thread[DCP_MAX_CHANS];
 	struct crypto_queue		queue[DCP_MAX_CHANS];
 };
@@ -209,6 +226,12 @@
 	dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf,
 					     DCP_BUF_SZ, DMA_FROM_DEVICE);
 
+	if (actx->fill % AES_BLOCK_SIZE) {
+		dev_err(sdcp->dev, "Invalid block size!\n");
+		ret = -EINVAL;
+		goto aes_done_run;
+	}
+
 	/* Fill in the DMA descriptor. */
 	desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE |
 		    MXS_DCP_CONTROL0_INTERRUPT |
@@ -238,6 +261,7 @@
 
 	ret = mxs_dcp_start_dma(actx);
 
+aes_done_run:
 	dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
 			 DMA_TO_DEVICE);
 	dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
@@ -264,13 +288,15 @@
 
 	uint8_t *out_tmp, *src_buf, *dst_buf = NULL;
 	uint32_t dst_off = 0;
+	uint32_t last_out_len = 0;
 
 	uint8_t *key = sdcp->coh->aes_key;
 
 	int ret = 0;
 	int split = 0;
-	unsigned int i, len, clen, rem = 0;
+	unsigned int i, len, clen, rem = 0, tlen = 0;
 	int init = 0;
+	bool limit_hit = false;
 
 	actx->fill = 0;
 
@@ -289,6 +315,11 @@
 	for_each_sg(req->src, src, nents, i) {
 		src_buf = sg_virt(src);
 		len = sg_dma_len(src);
+		tlen += len;
+		limit_hit = tlen > req->nbytes;
+
+		if (limit_hit)
+			len = req->nbytes - (tlen - len);
 
 		do {
 			if (actx->fill + len > out_off)
@@ -305,13 +336,15 @@
 			 * If we filled the buffer or this is the last SG,
 			 * submit the buffer.
 			 */
-			if (actx->fill == out_off || sg_is_last(src)) {
+			if (actx->fill == out_off || sg_is_last(src) ||
+				limit_hit) {
 				ret = mxs_dcp_run_aes(actx, req, init);
 				if (ret)
 					return ret;
 				init = 0;
 
 				out_tmp = out_buf;
+				last_out_len = actx->fill;
 				while (dst && actx->fill) {
 					if (!split) {
 						dst_buf = sg_virt(dst);
@@ -334,6 +367,19 @@
 				}
 			}
 		} while (len);
+
+		if (limit_hit)
+			break;
+	}
+
+	/* Copy the IV for CBC for chaining */
+	if (!rctx->ecb) {
+		if (rctx->enc)
+			memcpy(req->info, out_buf+(last_out_len-AES_BLOCK_SIZE),
+				AES_BLOCK_SIZE);
+		else
+			memcpy(req->info, in_buf+(last_out_len-AES_BLOCK_SIZE),
+				AES_BLOCK_SIZE);
 	}
 
 	return ret;
@@ -349,13 +395,20 @@
 
 	int ret;
 
-	do {
-		__set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
 
-		mutex_lock(&sdcp->mutex[chan]);
+		spin_lock(&sdcp->lock[chan]);
 		backlog = crypto_get_backlog(&sdcp->queue[chan]);
 		arq = crypto_dequeue_request(&sdcp->queue[chan]);
-		mutex_unlock(&sdcp->mutex[chan]);
+		spin_unlock(&sdcp->lock[chan]);
+
+		if (!backlog && !arq) {
+			schedule();
+			continue;
+		}
+
+		set_current_state(TASK_RUNNING);
 
 		if (backlog)
 			backlog->complete(backlog, -EINPROGRESS);
@@ -363,11 +416,8 @@
 		if (arq) {
 			ret = mxs_dcp_aes_block_crypt(arq);
 			arq->complete(arq, ret);
-			continue;
 		}
-
-		schedule();
-	} while (!kthread_should_stop());
+	}
 
 	return 0;
 }
@@ -407,9 +457,9 @@
 	rctx->ecb = ecb;
 	actx->chan = DCP_CHAN_CRYPTO;
 
-	mutex_lock(&sdcp->mutex[actx->chan]);
+	spin_lock(&sdcp->lock[actx->chan]);
 	ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base);
-	mutex_unlock(&sdcp->mutex[actx->chan]);
+	spin_unlock(&sdcp->lock[actx->chan]);
 
 	wake_up_process(sdcp->thread[actx->chan]);
 
@@ -514,8 +564,6 @@
 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
 	struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm);
 	struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
-
 	struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
 
 	dma_addr_t digest_phys = 0;
@@ -537,10 +585,23 @@
 	desc->payload = 0;
 	desc->status = 0;
 
+	/*
+	 * Align driver with hw behavior when generating null hashes
+	 */
+	if (rctx->init && rctx->fini && desc->size == 0) {
+		struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
+		const uint8_t *sha_buf =
+			(actx->alg == MXS_DCP_CONTROL1_HASH_SELECT_SHA1) ?
+			sha1_null_hash : sha256_null_hash;
+		memcpy(sdcp->coh->sha_out_buf, sha_buf, halg->digestsize);
+		ret = 0;
+		goto done_run;
+	}
+
 	/* Set HASH_TERM bit for last transfer block. */
 	if (rctx->fini) {
-		digest_phys = dma_map_single(sdcp->dev, req->result,
-					     halg->digestsize, DMA_FROM_DEVICE);
+		digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf,
+					     DCP_SHA_PAY_SZ, DMA_FROM_DEVICE);
 		desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM;
 		desc->payload = digest_phys;
 	}
@@ -548,9 +609,10 @@
 	ret = mxs_dcp_start_dma(actx);
 
 	if (rctx->fini)
-		dma_unmap_single(sdcp->dev, digest_phys, halg->digestsize,
+		dma_unmap_single(sdcp->dev, digest_phys, DCP_SHA_PAY_SZ,
 				 DMA_FROM_DEVICE);
 
+done_run:
 	dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
 
 	return ret;
@@ -565,48 +627,46 @@
 	struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm);
 	struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req);
 	struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
-	const int nents = sg_nents(req->src);
 
 	uint8_t *in_buf = sdcp->coh->sha_in_buf;
-
-	uint8_t *src_buf;
+	uint8_t *out_buf = sdcp->coh->sha_out_buf;
 
 	struct scatterlist *src;
 
-	unsigned int i, len, clen;
+	unsigned int i, len, clen, oft = 0;
 	int ret;
 
 	int fin = rctx->fini;
 	if (fin)
 		rctx->fini = 0;
 
-	for_each_sg(req->src, src, nents, i) {
-		src_buf = sg_virt(src);
-		len = sg_dma_len(src);
+	src = req->src;
+	len = req->nbytes;
 
-		do {
-			if (actx->fill + len > DCP_BUF_SZ)
-				clen = DCP_BUF_SZ - actx->fill;
-			else
-				clen = len;
-
-			memcpy(in_buf + actx->fill, src_buf, clen);
-			len -= clen;
-			src_buf += clen;
-			actx->fill += clen;
-
-			/*
-			 * If we filled the buffer and still have some
-			 * more data, submit the buffer.
-			 */
-			if (len && actx->fill == DCP_BUF_SZ) {
-				ret = mxs_dcp_run_sha(req);
-				if (ret)
-					return ret;
-				actx->fill = 0;
-				rctx->init = 0;
-			}
-		} while (len);
+	while (len) {
+		if (actx->fill + len > DCP_BUF_SZ)
+			clen = DCP_BUF_SZ - actx->fill;
+		else
+			clen = len;
+
+		scatterwalk_map_and_copy(in_buf + actx->fill, src, oft, clen,
+					 0);
+
+		len -= clen;
+		oft += clen;
+		actx->fill += clen;
+
+		/*
+		 * If we filled the buffer and still have some
+		 * more data, submit the buffer.
+		 */
+		if (len && actx->fill == DCP_BUF_SZ) {
+			ret = mxs_dcp_run_sha(req);
+			if (ret)
+				return ret;
+			actx->fill = 0;
+			rctx->init = 0;
+		}
 	}
 
 	if (fin) {
@@ -622,11 +682,9 @@
 
 		actx->fill = 0;
 
-		/* For some reason, the result is flipped. */
-		for (i = 0; i < halg->digestsize / 2; i++) {
-			swap(req->result[i],
-			     req->result[halg->digestsize - i - 1]);
-		}
+		/* For some reason the result is flipped */
+		for (i = 0; i < halg->digestsize; i++)
+			req->result[i] = out_buf[halg->digestsize - i - 1];
 	}
 
 	return 0;
@@ -645,13 +703,20 @@
 	struct ahash_request *req;
 	int ret, fini;
 
-	do {
-		__set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
 
-		mutex_lock(&sdcp->mutex[chan]);
+		spin_lock(&sdcp->lock[chan]);
 		backlog = crypto_get_backlog(&sdcp->queue[chan]);
 		arq = crypto_dequeue_request(&sdcp->queue[chan]);
-		mutex_unlock(&sdcp->mutex[chan]);
+		spin_unlock(&sdcp->lock[chan]);
+
+		if (!backlog && !arq) {
+			schedule();
+			continue;
+		}
+
+		set_current_state(TASK_RUNNING);
 
 		if (backlog)
 			backlog->complete(backlog, -EINPROGRESS);
@@ -663,12 +728,8 @@
 			ret = dcp_sha_req_to_buf(arq);
 			fini = rctx->fini;
 			arq->complete(arq, ret);
-			if (!fini)
-				continue;
 		}
-
-		schedule();
-	} while (!kthread_should_stop());
+	}
 
 	return 0;
 }
@@ -726,9 +787,9 @@
 		rctx->init = 1;
 	}
 
-	mutex_lock(&sdcp->mutex[actx->chan]);
+	spin_lock(&sdcp->lock[actx->chan]);
 	ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base);
-	mutex_unlock(&sdcp->mutex[actx->chan]);
+	spin_unlock(&sdcp->lock[actx->chan]);
 
 	wake_up_process(sdcp->thread[actx->chan]);
 	mutex_unlock(&actx->mutex);
@@ -984,7 +1045,7 @@
 	platform_set_drvdata(pdev, sdcp);
 
 	for (i = 0; i < DCP_MAX_CHANS; i++) {
-		mutex_init(&sdcp->mutex[i]);
+		spin_lock_init(&sdcp->lock[i]);
 		init_completion(&sdcp->completion[i]);
 		crypto_init_queue(&sdcp->queue[i], 50);
 	}
--- linux-4.4.0.orig/drivers/crypto/n2_core.c
+++ linux-4.4.0/drivers/crypto/n2_core.c
@@ -1641,6 +1641,7 @@
 					  CWQ_ENTRY_SIZE, 0, NULL);
 	if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) {
 		kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]);
+		queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL;
 		return -ENOMEM;
 	}
 	return 0;
@@ -1650,6 +1651,8 @@
 {
 	kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]);
 	kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_CWQ - 1]);
+	queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL;
+	queue_cache[HV_NCS_QTYPE_CWQ - 1] = NULL;
 }
 
 static int spu_queue_register(struct spu_queue *p, unsigned long q_type)
--- linux-4.4.0.orig/drivers/crypto/nx/nx-842-powernv.c
+++ linux-4.4.0/drivers/crypto/nx/nx-842-powernv.c
@@ -442,6 +442,14 @@
 			     (unsigned int)ccw,
 			     (unsigned int)be32_to_cpu(crb->ccw));
 
+	/*
+	 * NX842 coprocessor sets 3rd bit in CR register with XER[S0].
+	 * XER[S0] is the integer summary overflow bit which is nothing
+	 * to do NX. Since this bit can be set with other return values,
+	 * mask this bit.
+	 */
+	ret &= ~ICSWX_XERS0;
+
 	switch (ret) {
 	case ICSWX_INITIATED:
 		ret = wait_for_csb(wmem, csb);
@@ -454,10 +462,6 @@
 		pr_err_ratelimited("ICSWX rejected\n");
 		ret = -EPROTO;
 		break;
-	default:
-		pr_err_ratelimited("Invalid ICSWX return code %x\n", ret);
-		ret = -EPROTO;
-		break;
 	}
 
 	if (!ret)
@@ -491,7 +495,7 @@
 				  void *wmem)
 {
 	return nx842_powernv_function(in, inlen, out, outlenp,
-				      wmem, CCW_FC_842_COMP_CRC);
+				      wmem, CCW_FC_842_COMP_NOCRC);
 }
 
 /**
@@ -519,7 +523,7 @@
 				    void *wmem)
 {
 	return nx842_powernv_function(in, inlen, out, outlenp,
-				      wmem, CCW_FC_842_DECOMP_CRC);
+				      wmem, CCW_FC_842_DECOMP_NOCRC);
 }
 
 static int __init nx842_powernv_probe(struct device_node *dn)
--- linux-4.4.0.orig/drivers/crypto/nx/nx-842-pseries.c
+++ linux-4.4.0/drivers/crypto/nx/nx-842-pseries.c
@@ -234,10 +234,6 @@
 		dev_dbg(dev, "%s: Out of space in output buffer\n",
 					__func__);
 		return -ENOSPC;
-	case 65: /* Calculated CRC doesn't match the passed value */
-		dev_dbg(dev, "%s: CRC mismatch for decompression\n",
-					__func__);
-		return -EINVAL;
 	case 66: /* Input data contains an illegal template field */
 	case 67: /* Template indicates data past the end of the input stream */
 		dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n",
@@ -328,7 +324,7 @@
 	slout.entries = (struct nx842_slentry *)workmem->slout;
 
 	/* Init operation */
-	op.flags = NX842_OP_COMPRESS_CRC;
+	op.flags = NX842_OP_COMPRESS;
 	csbcpb = &workmem->csbcpb;
 	memset(csbcpb, 0, sizeof(*csbcpb));
 	op.csbcpb = nx842_get_pa(csbcpb);
@@ -461,7 +457,7 @@
 	slout.entries = (struct nx842_slentry *)workmem->slout;
 
 	/* Init operation */
-	op.flags = NX842_OP_DECOMPRESS_CRC;
+	op.flags = NX842_OP_DECOMPRESS;
 	csbcpb = &workmem->csbcpb;
 	memset(csbcpb, 0, sizeof(*csbcpb));
 	op.csbcpb = nx842_get_pa(csbcpb);
--- linux-4.4.0.orig/drivers/crypto/nx/nx.c
+++ linux-4.4.0/drivers/crypto/nx/nx.c
@@ -392,7 +392,7 @@
 		     ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) &&
 		     i < msc->triplets;
 		     i++) {
-			if (msc->fc > NX_MAX_FC || msc->mode > NX_MAX_MODE) {
+			if (msc->fc >= NX_MAX_FC || msc->mode >= NX_MAX_MODE) {
 				dev_err(dev, "unknown function code/mode "
 					"combo: %d/%d (ignored)\n", msc->fc,
 					msc->mode);
--- linux-4.4.0.orig/drivers/crypto/omap-sham.c
+++ linux-4.4.0/drivers/crypto/omap-sham.c
@@ -453,6 +453,9 @@
 	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
 	u32 val, mask;
 
+	if (likely(ctx->digcnt))
+		omap_sham_write(dd, SHA_REG_DIGCNT(dd), ctx->digcnt);
+
 	/*
 	 * Setting ALGO_CONST only for the first iteration and
 	 * CLOSE_HASH only for the last one. Note that flags mode bits
--- linux-4.4.0.orig/drivers/crypto/padlock-aes.c
+++ linux-4.4.0/drivers/crypto/padlock-aes.c
@@ -266,6 +266,8 @@
 		return;
 	}
 
+	count -= initial;
+
 	if (initial)
 		asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"	/* rep xcryptecb */
 			      : "+S"(input), "+D"(output)
@@ -273,7 +275,7 @@
 
 	asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"	/* rep xcryptecb */
 		      : "+S"(input), "+D"(output)
-		      : "d"(control_word), "b"(key), "c"(count - initial));
+		      : "d"(control_word), "b"(key), "c"(count));
 }
 
 static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
@@ -284,6 +286,8 @@
 	if (count < cbc_fetch_blocks)
 		return cbc_crypt(input, output, key, iv, control_word, count);
 
+	count -= initial;
+
 	if (initial)
 		asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"	/* rep xcryptcbc */
 			      : "+S" (input), "+D" (output), "+a" (iv)
@@ -291,7 +295,7 @@
 
 	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"	/* rep xcryptcbc */
 		      : "+S" (input), "+D" (output), "+a" (iv)
-		      : "d" (control_word), "b" (key), "c" (count-initial));
+		      : "d" (control_word), "b" (key), "c" (count));
 	return iv;
 }
 
@@ -515,7 +519,7 @@
 	if (!x86_match_cpu(padlock_cpu_id))
 		return -ENODEV;
 
-	if (!cpu_has_xcrypt_enabled) {
+	if (!boot_cpu_has(X86_FEATURE_XCRYPT_EN)) {
 		printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
 		return -ENODEV;
 	}
@@ -531,7 +535,7 @@
 
 	printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
 
-	if (c->x86 == 6 && c->x86_model == 15 && c->x86_mask == 2) {
+	if (c->x86 == 6 && c->x86_model == 15 && c->x86_stepping == 2) {
 		ecb_fetch_blocks = MAX_ECB_FETCH_BLOCKS;
 		cbc_fetch_blocks = MAX_CBC_FETCH_BLOCKS;
 		printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n");
--- linux-4.4.0.orig/drivers/crypto/padlock-sha.c
+++ linux-4.4.0/drivers/crypto/padlock-sha.c
@@ -540,7 +540,7 @@
 	struct shash_alg *sha1;
 	struct shash_alg *sha256;
 
-	if (!x86_match_cpu(padlock_sha_ids) || !cpu_has_phe_enabled)
+	if (!x86_match_cpu(padlock_sha_ids) || !boot_cpu_has(X86_FEATURE_PHE_EN))
 		return -ENODEV;
 
 	/* Register the newly added algorithm module if on *
--- linux-4.4.0.orig/drivers/crypto/picoxcell_crypto.c
+++ linux-4.4.0/drivers/crypto/picoxcell_crypto.c
@@ -1610,6 +1610,11 @@
 	return false;
 }
 
+static void spacc_tasklet_kill(void *data)
+{
+	tasklet_kill(data);
+}
+
 static int spacc_probe(struct platform_device *pdev)
 {
 	int i, err, ret = -EINVAL;
@@ -1652,6 +1657,14 @@
 		return -ENXIO;
 	}
 
+	tasklet_init(&engine->complete, spacc_spacc_complete,
+		     (unsigned long)engine);
+
+	ret = devm_add_action(&pdev->dev, spacc_tasklet_kill,
+			      &engine->complete);
+	if (ret)
+		return ret;
+
 	if (devm_request_irq(&pdev->dev, irq->start, spacc_spacc_irq, 0,
 			     engine->name, engine)) {
 		dev_err(engine->dev, "failed to request IRQ\n");
@@ -1714,8 +1727,6 @@
 	INIT_LIST_HEAD(&engine->completed);
 	INIT_LIST_HEAD(&engine->in_progress);
 	engine->in_flight = 0;
-	tasklet_init(&engine->complete, spacc_spacc_complete,
-		     (unsigned long)engine);
 
 	platform_set_drvdata(pdev, engine);
 
--- linux-4.4.0.orig/drivers/crypto/qat/qat_common/Makefile
+++ linux-4.4.0/drivers/crypto/qat/qat_common/Makefile
@@ -2,6 +2,7 @@
 			     $(obj)/qat_rsapubkey-asn1.h
 $(obj)/qat_rsaprivkey-asn1.o: $(obj)/qat_rsaprivkey-asn1.c \
 			      $(obj)/qat_rsaprivkey-asn1.h
+$(obj)/qat_asym_algs.o: $(obj)/qat_rsapubkey-asn1.h $(obj)/qat_rsaprivkey-asn1.h
 
 clean-files += qat_rsapubkey-asn1.c qat_rsapubkey-asn1.h
 clean-files += qat_rsaprivkey-asn1.c qat_rsapvivkey-asn1.h
--- linux-4.4.0.orig/drivers/crypto/qat/qat_common/adf_aer.c
+++ linux-4.4.0/drivers/crypto/qat/qat_common/adf_aer.c
@@ -125,7 +125,8 @@
 	if (adf_dev_init(accel_dev) || adf_dev_start(accel_dev)) {
 		/* The device hanged and we can't restart it so stop here */
 		dev_err(&GET_DEV(accel_dev), "Restart device failed\n");
-		kfree(reset_data);
+		if (reset_data->mode == ADF_DEV_RESET_ASYNC)
+			kfree(reset_data);
 		WARN(1, "QAT: device restart failed. Device is unusable\n");
 		return;
 	}
@@ -133,10 +134,10 @@
 	clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
 
 	/* The dev is back alive. Notify the caller if in sync mode */
-	if (reset_data->mode == ADF_DEV_RESET_SYNC)
-		complete(&reset_data->compl);
-	else
+	if (reset_data->mode == ADF_DEV_RESET_ASYNC)
 		kfree(reset_data);
+	else
+		complete(&reset_data->compl);
 }
 
 static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev,
@@ -168,6 +169,7 @@
 		if (!timeout) {
 			dev_err(&GET_DEV(accel_dev),
 				"Reset device timeout expired\n");
+			cancel_work_sync(&reset_data->reset_work);
 			ret = -EFAULT;
 		}
 		kfree(reset_data);
--- linux-4.4.0.orig/drivers/crypto/qat/qat_common/adf_common_drv.h
+++ linux-4.4.0/drivers/crypto/qat/qat_common/adf_common_drv.h
@@ -95,7 +95,7 @@
 
 static inline int get_current_node(void)
 {
-	return topology_physical_package_id(smp_processor_id());
+	return topology_physical_package_id(raw_smp_processor_id());
 }
 
 int adf_service_register(struct service_hndl *service);
@@ -227,6 +227,8 @@
 				  uint32_t vf_mask);
 void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev,
 				 uint32_t vf_mask);
+int adf_init_pf_wq(void);
+void adf_exit_pf_wq(void);
 #else
 static inline int adf_sriov_configure(struct pci_dev *pdev, int numvfs)
 {
@@ -236,5 +238,14 @@
 static inline void adf_disable_sriov(struct adf_accel_dev *accel_dev)
 {
 }
+
+static inline int adf_init_pf_wq(void)
+{
+	return 0;
+}
+
+static inline void adf_exit_pf_wq(void)
+{
+}
 #endif
 #endif
--- linux-4.4.0.orig/drivers/crypto/qat/qat_common/adf_ctl_drv.c
+++ linux-4.4.0/drivers/crypto/qat/qat_common/adf_ctl_drv.c
@@ -469,12 +469,17 @@
 	if (adf_init_aer())
 		goto err_aer;
 
+	if (adf_init_pf_wq())
+		goto err_pf_wq;
+
 	if (qat_crypto_register())
 		goto err_crypto_register;
 
 	return 0;
 
 err_crypto_register:
+	adf_exit_pf_wq();
+err_pf_wq:
 	adf_exit_aer();
 err_aer:
 	adf_chr_drv_destroy();
@@ -487,6 +492,7 @@
 {
 	adf_chr_drv_destroy();
 	adf_exit_aer();
+	adf_exit_pf_wq();
 	qat_crypto_unregister();
 	adf_clean_vf_map(false);
 	mutex_destroy(&adf_ctl_lock);
--- linux-4.4.0.orig/drivers/crypto/qat/qat_common/adf_sriov.c
+++ linux-4.4.0/drivers/crypto/qat/qat_common/adf_sriov.c
@@ -119,11 +119,6 @@
 	int i;
 	u32 reg;
 
-	/* Workqueue for PF2VF responses */
-	pf2vf_resp_wq = create_workqueue("qat_pf2vf_resp_wq");
-	if (!pf2vf_resp_wq)
-		return -ENOMEM;
-
 	for (i = 0, vf_info = accel_dev->pf.vf_info; i < totalvfs;
 	     i++, vf_info++) {
 		/* This ptr will be populated when VFs will be created */
@@ -216,11 +211,6 @@
 
 	kfree(accel_dev->pf.vf_info);
 	accel_dev->pf.vf_info = NULL;
-
-	if (pf2vf_resp_wq) {
-		destroy_workqueue(pf2vf_resp_wq);
-		pf2vf_resp_wq = NULL;
-	}
 }
 EXPORT_SYMBOL_GPL(adf_disable_sriov);
 
@@ -304,3 +294,19 @@
 	return numvfs;
 }
 EXPORT_SYMBOL_GPL(adf_sriov_configure);
+
+int __init adf_init_pf_wq(void)
+{
+	/* Workqueue for PF2VF responses */
+	pf2vf_resp_wq = create_workqueue("qat_pf2vf_resp_wq");
+
+	return !pf2vf_resp_wq ? -ENOMEM : 0;
+}
+
+void adf_exit_pf_wq(void)
+{
+	if (pf2vf_resp_wq) {
+		destroy_workqueue(pf2vf_resp_wq);
+		pf2vf_resp_wq = NULL;
+	}
+}
--- linux-4.4.0.orig/drivers/crypto/qat/qat_common/qat_algs.c
+++ linux-4.4.0/drivers/crypto/qat/qat_common/qat_algs.c
@@ -822,6 +822,11 @@
 	struct icp_qat_fw_la_bulk_req *msg;
 	int digst_size = crypto_aead_authsize(aead_tfm);
 	int ret, ctr = 0;
+	u32 cipher_len;
+
+	cipher_len = areq->cryptlen - digst_size;
+	if (cipher_len % AES_BLOCK_SIZE != 0)
+		return -EINVAL;
 
 	ret = qat_alg_sgl_to_bufl(ctx->inst, areq->src, areq->dst, qat_req);
 	if (unlikely(ret))
@@ -836,7 +841,7 @@
 	qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
 	qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
 	cipher_param = (void *)&qat_req->req.serv_specif_rqpars;
-	cipher_param->cipher_length = areq->cryptlen - digst_size;
+	cipher_param->cipher_length = cipher_len;
 	cipher_param->cipher_offset = areq->assoclen;
 	memcpy(cipher_param->u.cipher_IV_array, areq->iv, AES_BLOCK_SIZE);
 	auth_param = (void *)((uint8_t *)cipher_param + sizeof(*cipher_param));
@@ -865,6 +870,9 @@
 	uint8_t *iv = areq->iv;
 	int ret, ctr = 0;
 
+	if (areq->cryptlen % AES_BLOCK_SIZE != 0)
+		return -EINVAL;
+
 	ret = qat_alg_sgl_to_bufl(ctx->inst, areq->src, areq->dst, qat_req);
 	if (unlikely(ret))
 		return ret;
@@ -1262,8 +1270,8 @@
 			.setkey = qat_alg_ablkcipher_xts_setkey,
 			.decrypt = qat_alg_ablkcipher_decrypt,
 			.encrypt = qat_alg_ablkcipher_encrypt,
-			.min_keysize = AES_MIN_KEY_SIZE,
-			.max_keysize = AES_MAX_KEY_SIZE,
+			.min_keysize = 2 * AES_MIN_KEY_SIZE,
+			.max_keysize = 2 * AES_MAX_KEY_SIZE,
 			.ivsize = AES_BLOCK_SIZE,
 		},
 	},
--- linux-4.4.0.orig/drivers/crypto/qat/qat_common/qat_uclo.c
+++ linux-4.4.0/drivers/crypto/qat/qat_common/qat_uclo.c
@@ -307,13 +307,18 @@
 	}
 	return 0;
 out_err:
+	/* Do not free the list head unless we allocated it. */
+	tail_old = tail_old->next;
+	if (flag) {
+		kfree(*init_tab_base);
+		*init_tab_base = NULL;
+	}
+
 	while (tail_old) {
 		mem_init = tail_old->next;
 		kfree(tail_old);
 		tail_old = mem_init;
 	}
-	if (flag)
-		kfree(*init_tab_base);
 	return -ENOMEM;
 }
 
--- linux-4.4.0.orig/drivers/crypto/s5p-sss.c
+++ linux-4.4.0/drivers/crypto/s5p-sss.c
@@ -401,16 +401,21 @@
 	uint32_t                    aes_control;
 	int                         err;
 	unsigned long               flags;
+	u8 *iv;
 
 	aes_control = SSS_AES_KEY_CHANGE_MODE;
 	if (mode & FLAGS_AES_DECRYPT)
 		aes_control |= SSS_AES_MODE_DECRYPT;
 
-	if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC)
+	if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) {
 		aes_control |= SSS_AES_CHAIN_MODE_CBC;
-	else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR)
+		iv = req->info;
+	} else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) {
 		aes_control |= SSS_AES_CHAIN_MODE_CTR;
-
+		iv = req->info;
+	} else {
+		iv = NULL; /* AES_ECB */
+	}
 	if (dev->ctx->keylen == AES_KEYSIZE_192)
 		aes_control |= SSS_AES_KEY_SIZE_192;
 	else if (dev->ctx->keylen == AES_KEYSIZE_256)
@@ -440,7 +445,7 @@
 		goto outdata_error;
 
 	SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
-	s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
+	s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen);
 
 	s5p_set_dma_indata(dev,  req->src);
 	s5p_set_dma_outdata(dev, req->dst);
@@ -664,8 +669,9 @@
 		dev_warn(dev, "feed control interrupt is not available.\n");
 		goto err_irq;
 	}
-	err = devm_request_irq(dev, pdata->irq_fc, s5p_aes_interrupt,
-			       IRQF_SHARED, pdev->name, pdev);
+	err = devm_request_threaded_irq(dev, pdata->irq_fc, NULL,
+					s5p_aes_interrupt, IRQF_ONESHOT,
+					pdev->name, pdev);
 	if (err < 0) {
 		dev_warn(dev, "feed control interrupt is not available.\n");
 		goto err_irq;
--- linux-4.4.0.orig/drivers/crypto/sahara.c
+++ linux-4.4.0/drivers/crypto/sahara.c
@@ -1363,7 +1363,7 @@
 
 err_sha_v3_algs:
 	for (j = 0; j < k; j++)
-		crypto_unregister_ahash(&sha_v4_algs[j]);
+		crypto_unregister_ahash(&sha_v3_algs[j]);
 
 err_aes_algs:
 	for (j = 0; j < i; j++)
@@ -1379,7 +1379,7 @@
 	for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
 		crypto_unregister_alg(&aes_algs[i]);
 
-	for (i = 0; i < ARRAY_SIZE(sha_v4_algs); i++)
+	for (i = 0; i < ARRAY_SIZE(sha_v3_algs); i++)
 		crypto_unregister_ahash(&sha_v3_algs[i]);
 
 	if (dev->version > SAHARA_VERSION_3)
--- linux-4.4.0.orig/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
+++ linux-4.4.0/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
@@ -35,6 +35,7 @@
 	unsigned int todo;
 	struct sg_mapping_iter mi, mo;
 	unsigned int oi, oo; /* offset for in and out */
+	unsigned long flags;
 
 	if (areq->nbytes == 0)
 		return 0;
@@ -49,7 +50,7 @@
 		return -EINVAL;
 	}
 
-	spin_lock_bh(&ss->slock);
+	spin_lock_irqsave(&ss->slock, flags);
 
 	for (i = 0; i < op->keylen; i += 4)
 		writel(*(op->key + i / 4), ss->base + SS_KEY0 + i);
@@ -117,7 +118,7 @@
 	sg_miter_stop(&mi);
 	sg_miter_stop(&mo);
 	writel(0, ss->base + SS_CTL);
-	spin_unlock_bh(&ss->slock);
+	spin_unlock_irqrestore(&ss->slock, flags);
 	return err;
 }
 
@@ -149,6 +150,7 @@
 	unsigned int ob = 0;	/* offset in buf */
 	unsigned int obo = 0;	/* offset in bufo*/
 	unsigned int obl = 0;	/* length of data in bufo */
+	unsigned long flags;
 
 	if (areq->nbytes == 0)
 		return 0;
@@ -181,7 +183,7 @@
 	if (no_chunk == 1)
 		return sun4i_ss_opti_poll(areq);
 
-	spin_lock_bh(&ss->slock);
+	spin_lock_irqsave(&ss->slock, flags);
 
 	for (i = 0; i < op->keylen; i += 4)
 		writel(*(op->key + i / 4), ss->base + SS_KEY0 + i);
@@ -308,7 +310,7 @@
 	sg_miter_stop(&mi);
 	sg_miter_stop(&mo);
 	writel(0, ss->base + SS_CTL);
-	spin_unlock_bh(&ss->slock);
+	spin_unlock_irqrestore(&ss->slock, flags);
 
 	return err;
 }
--- linux-4.4.0.orig/drivers/crypto/sunxi-ss/sun4i-ss-core.c
+++ linux-4.4.0/drivers/crypto/sunxi-ss/sun4i-ss-core.c
@@ -39,6 +39,7 @@
 		.import = sun4i_hash_import_md5,
 		.halg = {
 			.digestsize = MD5_DIGEST_SIZE,
+			.statesize = sizeof(struct md5_state),
 			.base = {
 				.cra_name = "md5",
 				.cra_driver_name = "md5-sun4i-ss",
@@ -66,6 +67,7 @@
 		.import = sun4i_hash_import_sha1,
 		.halg = {
 			.digestsize = SHA1_DIGEST_SIZE,
+			.statesize = sizeof(struct sha1_state),
 			.base = {
 				.cra_name = "sha1",
 				.cra_driver_name = "sha1-sun4i-ss",
@@ -420,6 +422,7 @@
 
 module_platform_driver(sun4i_ss_driver);
 
+MODULE_ALIAS("platform:sun4i-ss");
 MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");
--- linux-4.4.0.orig/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ linux-4.4.0/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -245,8 +245,8 @@
 			 */
 			while (op->len < 64 && i < end) {
 				/* how many bytes we can read from current SG */
-				in_r = min3(mi.length - in_i, end - i,
-					    64 - op->len);
+				in_r = min(end - i, 64 - op->len);
+				in_r = min_t(size_t, mi.length - in_i, in_r);
 				memcpy(op->buf + op->len, mi.addr + in_i, in_r);
 				op->len += in_r;
 				i += in_r;
@@ -266,8 +266,8 @@
 		}
 		if (mi.length - in_i > 3 && i < end) {
 			/* how many bytes we can read from current SG */
-			in_r = min3(mi.length - in_i, areq->nbytes - i,
-				    ((mi.length - in_i) / 4) * 4);
+			in_r = min_t(size_t, mi.length - in_i, areq->nbytes - i);
+			in_r = min_t(size_t, ((mi.length - in_i) / 4) * 4, in_r);
 			/* how many bytes we can write in the device*/
 			todo = min3((u32)(end - i) / 4, rx_cnt, (u32)in_r / 4);
 			writesl(ss->base + SS_RXFIFO, mi.addr + in_i, todo);
@@ -289,8 +289,8 @@
 	if ((areq->nbytes - i) < 64) {
 		while (i < areq->nbytes && in_i < mi.length && op->len < 64) {
 			/* how many bytes we can read from current SG */
-			in_r = min3(mi.length - in_i, areq->nbytes - i,
-				    64 - op->len);
+			in_r = min(areq->nbytes - i, 64 - op->len);
+			in_r = min_t(size_t, mi.length - in_i, in_r);
 			memcpy(op->buf + op->len, mi.addr + in_i, in_r);
 			op->len += in_r;
 			i += in_r;
--- linux-4.4.0.orig/drivers/crypto/talitos.c
+++ linux-4.4.0/drivers/crypto/talitos.c
@@ -63,6 +63,14 @@
 		ptr->eptr = upper_32_bits(dma_addr);
 }
 
+static void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
+			     struct talitos_ptr *src_ptr, bool is_sec1)
+{
+	dst_ptr->ptr = src_ptr->ptr;
+	if (!is_sec1)
+		dst_ptr->eptr = src_ptr->eptr;
+}
+
 static void to_talitos_ptr_len(struct talitos_ptr *ptr, unsigned int len,
 			       bool is_sec1)
 {
@@ -432,7 +440,7 @@
 /*
  * locate current (offending) descriptor
  */
-static u32 current_desc_hdr(struct device *dev, int ch)
+static __be32 current_desc_hdr(struct device *dev, int ch)
 {
 	struct talitos_private *priv = dev_get_drvdata(dev);
 	int tail, iter;
@@ -463,13 +471,13 @@
 /*
  * user diagnostics; report root cause of error based on execution unit status
  */
-static void report_eu_error(struct device *dev, int ch, u32 desc_hdr)
+static void report_eu_error(struct device *dev, int ch, __be32 desc_hdr)
 {
 	struct talitos_private *priv = dev_get_drvdata(dev);
 	int i;
 
 	if (!desc_hdr)
-		desc_hdr = in_be32(priv->chan[ch].reg + TALITOS_DESCBUF);
+		desc_hdr = cpu_to_be32(in_be32(priv->chan[ch].reg + TALITOS_DESCBUF));
 
 	switch (desc_hdr & DESC_HDR_SEL0_MASK) {
 	case DESC_HDR_SEL0_AFEU:
@@ -796,7 +804,7 @@
  * crypto alg
  */
 #define TALITOS_CRA_PRIORITY		3000
-#define TALITOS_MAX_KEY_SIZE		96
+#define TALITOS_MAX_KEY_SIZE		(AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE)
 #define TALITOS_MAX_IV_LENGTH		16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
 
 struct talitos_ctx {
@@ -827,6 +835,16 @@
 	struct scatterlist *psrc;
 };
 
+struct talitos_export_state {
+	u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
+	u8 buf[HASH_MAX_BLOCK_SIZE];
+	unsigned int swinit;
+	unsigned int first;
+	unsigned int last;
+	unsigned int to_hash_later;
+	unsigned int nbuf;
+};
+
 static int aead_setkey(struct crypto_aead *authenc,
 		       const u8 *key, unsigned int keylen)
 {
@@ -1083,21 +1101,20 @@
 	sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ?: 1,
 			      (areq->src == areq->dst) ? DMA_BIDIRECTIONAL
 							   : DMA_TO_DEVICE);
-
 	/* hmac data */
 	desc->ptr[1].len = cpu_to_be16(areq->assoclen);
 	if (sg_count > 1 &&
 	    (ret = sg_to_link_tbl_offset(areq->src, sg_count, 0,
 					 areq->assoclen,
 					 &edesc->link_tbl[tbl_off])) > 1) {
-		tbl_off += ret;
-
 		to_talitos_ptr(&desc->ptr[1], edesc->dma_link_tbl + tbl_off *
 			       sizeof(struct talitos_ptr), 0);
 		desc->ptr[1].j_extent = DESC_PTR_LNKTBL_JUMP;
 
 		dma_sync_single_for_device(dev, edesc->dma_link_tbl,
 					   edesc->dma_len, DMA_BIDIRECTIONAL);
+
+		tbl_off += ret;
 	} else {
 		to_talitos_ptr(&desc->ptr[1], sg_dma_address(areq->src), 0);
 		desc->ptr[1].j_extent = 0;
@@ -1126,11 +1143,13 @@
 	if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV)
 		sg_link_tbl_len += authsize;
 
-	if (sg_count > 1 &&
-	    (ret = sg_to_link_tbl_offset(areq->src, sg_count, areq->assoclen,
-					 sg_link_tbl_len,
-					 &edesc->link_tbl[tbl_off])) > 1) {
-		tbl_off += ret;
+	if (sg_count == 1) {
+		to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src) +
+			       areq->assoclen, 0);
+	} else if ((ret = sg_to_link_tbl_offset(areq->src, sg_count,
+						areq->assoclen, sg_link_tbl_len,
+						&edesc->link_tbl[tbl_off])) >
+		   1) {
 		desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
 		to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl +
 					      tbl_off *
@@ -1138,8 +1157,10 @@
 		dma_sync_single_for_device(dev, edesc->dma_link_tbl,
 					   edesc->dma_len,
 					   DMA_BIDIRECTIONAL);
-	} else
-		to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src), 0);
+		tbl_off += ret;
+	} else {
+		copy_talitos_ptr(&desc->ptr[4], &edesc->link_tbl[tbl_off], 0);
+	}
 
 	/* cipher out */
 	desc->ptr[5].len = cpu_to_be16(cryptlen);
@@ -1151,11 +1172,13 @@
 
 	edesc->icv_ool = false;
 
-	if (sg_count > 1 &&
-	    (sg_count = sg_to_link_tbl_offset(areq->dst, sg_count,
+	if (sg_count == 1) {
+		to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst) +
+			       areq->assoclen, 0);
+	} else if ((sg_count =
+			sg_to_link_tbl_offset(areq->dst, sg_count,
 					      areq->assoclen, cryptlen,
-					      &edesc->link_tbl[tbl_off])) >
-	    1) {
+					      &edesc->link_tbl[tbl_off])) > 1) {
 		struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off];
 
 		to_talitos_ptr(&desc->ptr[5], edesc->dma_link_tbl +
@@ -1178,8 +1201,9 @@
 					   edesc->dma_len, DMA_BIDIRECTIONAL);
 
 		edesc->icv_ool = true;
-	} else
-		to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst), 0);
+	} else {
+		copy_talitos_ptr(&desc->ptr[5], &edesc->link_tbl[tbl_off], 0);
+	}
 
 	/* iv out */
 	map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv,
@@ -1364,6 +1388,11 @@
 {
 	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
 
+	if (keylen > TALITOS_MAX_KEY_SIZE) {
+		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
 	memcpy(&ctx->key, key, keylen);
 	ctx->keylen = keylen;
 
@@ -1397,6 +1426,18 @@
 	}
 }
 
+static int ablkcipher_aes_setkey(struct crypto_ablkcipher *cipher,
+				  const u8 *key, unsigned int keylen)
+{
+	if (keylen == AES_KEYSIZE_128 || keylen == AES_KEYSIZE_192 ||
+	    keylen == AES_KEYSIZE_256)
+		return ablkcipher_setkey(cipher, key, keylen);
+
+	crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+	return -EINVAL;
+}
+
 static void common_nonsnoop_unmap(struct device *dev,
 				  struct talitos_edesc *edesc,
 				  struct ablkcipher_request *areq)
@@ -1417,11 +1458,15 @@
 			    int err)
 {
 	struct ablkcipher_request *areq = context;
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	unsigned int ivsize = crypto_ablkcipher_ivsize(cipher);
 	struct talitos_edesc *edesc;
 
 	edesc = container_of(desc, struct talitos_edesc, desc);
 
 	common_nonsnoop_unmap(dev, edesc, areq);
+	memcpy(areq->info, ctx->iv, ivsize);
 
 	kfree(edesc);
 
@@ -1596,6 +1641,14 @@
 	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
 	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
 	struct talitos_edesc *edesc;
+	unsigned int blocksize =
+			crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(cipher));
+
+	if (!areq->nbytes)
+		return 0;
+
+	if (areq->nbytes % blocksize)
+		return -EINVAL;
 
 	/* allocate extended descriptor */
 	edesc = ablkcipher_edesc_alloc(areq, true);
@@ -1613,6 +1666,14 @@
 	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
 	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
 	struct talitos_edesc *edesc;
+	unsigned int blocksize =
+			crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(cipher));
+
+	if (!areq->nbytes)
+		return 0;
+
+	if (areq->nbytes % blocksize)
+		return -EINVAL;
 
 	/* allocate extended descriptor */
 	edesc = ablkcipher_edesc_alloc(areq, false);
@@ -1720,9 +1781,9 @@
 		req_ctx->swinit = 0;
 	} else {
 		desc->ptr[1] = zero_entry;
-		/* Indicate next op is not the first. */
-		req_ctx->first = 0;
 	}
+	/* Indicate next op is not the first. */
+	req_ctx->first = 0;
 
 	/* HMAC key */
 	if (ctx->keylen)
@@ -1940,6 +2001,46 @@
 	return ahash_process_req(areq, areq->nbytes);
 }
 
+static int ahash_export(struct ahash_request *areq, void *out)
+{
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+	struct talitos_export_state *export = out;
+
+	memcpy(export->hw_context, req_ctx->hw_context,
+	       req_ctx->hw_context_size);
+	memcpy(export->buf, req_ctx->buf, req_ctx->nbuf);
+	export->swinit = req_ctx->swinit;
+	export->first = req_ctx->first;
+	export->last = req_ctx->last;
+	export->to_hash_later = req_ctx->to_hash_later;
+	export->nbuf = req_ctx->nbuf;
+
+	return 0;
+}
+
+static int ahash_import(struct ahash_request *areq, const void *in)
+{
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	const struct talitos_export_state *export = in;
+
+	memset(req_ctx, 0, sizeof(*req_ctx));
+	req_ctx->hw_context_size =
+		(crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+			? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+			: TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+	memcpy(req_ctx->hw_context, export->hw_context,
+	       req_ctx->hw_context_size);
+	memcpy(req_ctx->buf, export->buf, export->nbuf);
+	req_ctx->swinit = export->swinit;
+	req_ctx->first = export->first;
+	req_ctx->last = export->last;
+	req_ctx->to_hash_later = export->to_hash_later;
+	req_ctx->nbuf = export->nbuf;
+
+	return 0;
+}
+
 struct keyhash_result {
 	struct completion completion;
 	int err;
@@ -2306,6 +2407,7 @@
 				.min_keysize = AES_MIN_KEY_SIZE,
 				.max_keysize = AES_MAX_KEY_SIZE,
 				.ivsize = AES_BLOCK_SIZE,
+				.setkey = ablkcipher_aes_setkey,
 			}
 		},
 		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
@@ -2334,6 +2436,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = MD5_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "md5",
 				.cra_driver_name = "md5-talitos",
@@ -2349,6 +2452,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA1_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "sha1",
 				.cra_driver_name = "sha1-talitos",
@@ -2364,6 +2468,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA224_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "sha224",
 				.cra_driver_name = "sha224-talitos",
@@ -2379,6 +2484,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA256_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "sha256",
 				.cra_driver_name = "sha256-talitos",
@@ -2394,6 +2500,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA384_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "sha384",
 				.cra_driver_name = "sha384-talitos",
@@ -2409,6 +2516,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA512_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "sha512",
 				.cra_driver_name = "sha512-talitos",
@@ -2424,6 +2532,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = MD5_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "hmac(md5)",
 				.cra_driver_name = "hmac-md5-talitos",
@@ -2439,6 +2548,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA1_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "hmac(sha1)",
 				.cra_driver_name = "hmac-sha1-talitos",
@@ -2454,6 +2564,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA224_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "hmac(sha224)",
 				.cra_driver_name = "hmac-sha224-talitos",
@@ -2469,6 +2580,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA256_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "hmac(sha256)",
 				.cra_driver_name = "hmac-sha256-talitos",
@@ -2484,6 +2596,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA384_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "hmac(sha384)",
 				.cra_driver_name = "hmac-sha384-talitos",
@@ -2499,6 +2612,7 @@
 	{	.type = CRYPTO_ALG_TYPE_AHASH,
 		.alg.hash = {
 			.halg.digestsize = SHA512_DIGEST_SIZE,
+			.halg.statesize = sizeof(struct talitos_export_state),
 			.halg.base = {
 				.cra_name = "hmac(sha512)",
 				.cra_driver_name = "hmac-sha512-talitos",
@@ -2519,21 +2633,11 @@
 	struct talitos_alg_template algt;
 };
 
-static int talitos_cra_init(struct crypto_tfm *tfm)
+static int talitos_init_common(struct talitos_ctx *ctx,
+			       struct talitos_crypto_alg *talitos_alg)
 {
-	struct crypto_alg *alg = tfm->__crt_alg;
-	struct talitos_crypto_alg *talitos_alg;
-	struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct talitos_private *priv;
 
-	if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH)
-		talitos_alg = container_of(__crypto_ahash_alg(alg),
-					   struct talitos_crypto_alg,
-					   algt.alg.hash);
-	else
-		talitos_alg = container_of(alg, struct talitos_crypto_alg,
-					   algt.alg.crypto);
-
 	/* update context with ptr to dev */
 	ctx->dev = talitos_alg->dev;
 
@@ -2551,10 +2655,33 @@
 	return 0;
 }
 
+static int talitos_cra_init(struct crypto_tfm *tfm)
+{
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct talitos_crypto_alg *talitos_alg;
+	struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH)
+		talitos_alg = container_of(__crypto_ahash_alg(alg),
+					   struct talitos_crypto_alg,
+					   algt.alg.hash);
+	else
+		talitos_alg = container_of(alg, struct talitos_crypto_alg,
+					   algt.alg.crypto);
+
+	return talitos_init_common(ctx, talitos_alg);
+}
+
 static int talitos_cra_init_aead(struct crypto_aead *tfm)
 {
-	talitos_cra_init(crypto_aead_tfm(tfm));
-	return 0;
+	struct aead_alg *alg = crypto_aead_alg(tfm);
+	struct talitos_crypto_alg *talitos_alg;
+	struct talitos_ctx *ctx = crypto_aead_ctx(tfm);
+
+	talitos_alg = container_of(alg, struct talitos_crypto_alg,
+				   algt.alg.aead);
+
+	return talitos_init_common(ctx, talitos_alg);
 }
 
 static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
@@ -2603,6 +2730,7 @@
 			break;
 		case CRYPTO_ALG_TYPE_AEAD:
 			crypto_unregister_aead(&t_alg->algt.alg.aead);
+			break;
 		case CRYPTO_ALG_TYPE_AHASH:
 			crypto_unregister_ahash(&t_alg->algt.alg.hash);
 			break;
@@ -2676,7 +2804,10 @@
 		t_alg->algt.alg.hash.final = ahash_final;
 		t_alg->algt.alg.hash.finup = ahash_finup;
 		t_alg->algt.alg.hash.digest = ahash_digest;
-		t_alg->algt.alg.hash.setkey = ahash_setkey;
+		if (!strncmp(alg->cra_name, "hmac", 4))
+			t_alg->algt.alg.hash.setkey = ahash_setkey;
+		t_alg->algt.alg.hash.import = ahash_import;
+		t_alg->algt.alg.hash.export = ahash_export;
 
 		if (!(priv->features & TALITOS_FTR_HMAC_OK) &&
 		    !strncmp(alg->cra_name, "hmac", 4)) {
--- linux-4.4.0.orig/drivers/crypto/ux500/cryp/cryp_core.c
+++ linux-4.4.0/drivers/crypto/ux500/cryp/cryp_core.c
@@ -555,7 +555,7 @@
 		desc = dmaengine_prep_slave_sg(channel,
 				ctx->device->dma.sg_src,
 				ctx->device->dma.sg_src_len,
-				direction, DMA_CTRL_ACK);
+				DMA_MEM_TO_DEV, DMA_CTRL_ACK);
 		break;
 
 	case DMA_FROM_DEVICE:
@@ -579,7 +579,7 @@
 		desc = dmaengine_prep_slave_sg(channel,
 				ctx->device->dma.sg_dst,
 				ctx->device->dma.sg_dst_len,
-				direction,
+				DMA_DEV_TO_MEM,
 				DMA_CTRL_ACK |
 				DMA_PREP_INTERRUPT);
 
@@ -1440,9 +1440,9 @@
 
 	device_data->phybase = res->start;
 	device_data->base = devm_ioremap_resource(dev, res);
-	if (!device_data->base) {
+	if (IS_ERR(device_data->base)) {
 		dev_err(dev, "[%s]: ioremap failed!", __func__);
-		ret = -ENOMEM;
+		ret = PTR_ERR(device_data->base);
 		goto out;
 	}
 
--- linux-4.4.0.orig/drivers/crypto/ux500/hash/hash_core.c
+++ linux-4.4.0/drivers/crypto/ux500/hash/hash_core.c
@@ -181,7 +181,7 @@
 		__func__);
 	desc = dmaengine_prep_slave_sg(channel,
 			ctx->device->dma.sg, ctx->device->dma.sg_len,
-			direction, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+			DMA_MEM_TO_DEV, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
 	if (!desc) {
 		dev_err(ctx->device->dev,
 			"%s: dmaengine_prep_slave_sg() failed!\n", __func__);
@@ -797,7 +797,7 @@
 						&device_data->state);
 				memmove(req_ctx->state.buffer,
 					device_data->state.buffer,
-					HASH_BLOCK_SIZE / sizeof(u32));
+					HASH_BLOCK_SIZE);
 				if (ret) {
 					dev_err(device_data->dev,
 						"%s: hash_resume_state() failed!\n",
@@ -848,7 +848,7 @@
 
 			memmove(device_data->state.buffer,
 				req_ctx->state.buffer,
-				HASH_BLOCK_SIZE / sizeof(u32));
+				HASH_BLOCK_SIZE);
 			if (ret) {
 				dev_err(device_data->dev, "%s: hash_save_state() failed!\n",
 					__func__);
@@ -1675,9 +1675,9 @@
 
 	device_data->phybase = res->start;
 	device_data->base = devm_ioremap_resource(dev, res);
-	if (!device_data->base) {
+	if (IS_ERR(device_data->base)) {
 		dev_err(dev, "%s: ioremap() failed!\n", __func__);
-		ret = -ENOMEM;
+		ret = PTR_ERR(device_data->base);
 		goto out;
 	}
 	spin_lock_init(&device_data->ctx_lock);
--- linux-4.4.0.orig/drivers/crypto/vmx/Kconfig
+++ linux-4.4.0/drivers/crypto/vmx/Kconfig
@@ -1,7 +1,8 @@
 config CRYPTO_DEV_VMX_ENCRYPT
 	tristate "Encryption acceleration support on P8 CPU"
 	depends on CRYPTO_DEV_VMX
-	default y
+	select CRYPTO_GHASH
+	default m
 	help
 	  Support for VMX cryptographic acceleration instructions on Power8 CPU.
 	  This module supports acceleration for AES and GHASH in hardware. If you
--- linux-4.4.0.orig/drivers/crypto/vmx/Makefile
+++ linux-4.4.0/drivers/crypto/vmx/Makefile
@@ -1,14 +1,14 @@
 obj-$(CONFIG_CRYPTO_DEV_VMX_ENCRYPT) += vmx-crypto.o
-vmx-crypto-objs := vmx.o aesp8-ppc.o ghashp8-ppc.o aes.o aes_cbc.o aes_ctr.o ghash.o
+vmx-crypto-objs := vmx.o aesp8-ppc.o ghashp8-ppc.o aes.o aes_cbc.o aes_ctr.o aes_xts.o ghash.o
 
 ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
-TARGET := linux-ppc64le
+override flavour := linux-ppc64le
 else
-TARGET := linux-ppc64
+override flavour := linux-ppc64
 endif
 
 quiet_cmd_perl = PERL $@
-      cmd_perl = $(PERL) $(<) $(TARGET) > $(@)
+      cmd_perl = $(PERL) $(<) $(flavour) > $(@)
 
 $(src)/aesp8-ppc.S: $(src)/aesp8-ppc.pl
 	$(call cmd,perl)
--- linux-4.4.0.orig/drivers/crypto/vmx/aes.c
+++ linux-4.4.0/drivers/crypto/vmx/aes.c
@@ -53,8 +53,6 @@
 		       alg, PTR_ERR(fallback));
 		return PTR_ERR(fallback);
 	}
-	printk(KERN_INFO "Using '%s' as fallback implementation.\n",
-	       crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
 
 	crypto_cipher_set_flags(fallback,
 				crypto_cipher_get_flags((struct
@@ -83,10 +81,10 @@
 
 	preempt_disable();
 	pagefault_disable();
-	enable_kernel_altivec();
 	enable_kernel_vsx();
 	ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
 	ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
+	disable_kernel_vsx();
 	pagefault_enable();
 	preempt_enable();
 
@@ -103,9 +101,9 @@
 	} else {
 		preempt_disable();
 		pagefault_disable();
-		enable_kernel_altivec();
 		enable_kernel_vsx();
 		aes_p8_encrypt(src, dst, &ctx->enc_key);
+		disable_kernel_vsx();
 		pagefault_enable();
 		preempt_enable();
 	}
@@ -120,9 +118,9 @@
 	} else {
 		preempt_disable();
 		pagefault_disable();
-		enable_kernel_altivec();
 		enable_kernel_vsx();
 		aes_p8_decrypt(src, dst, &ctx->dec_key);
+		disable_kernel_vsx();
 		pagefault_enable();
 		preempt_enable();
 	}
--- linux-4.4.0.orig/drivers/crypto/vmx/aes_cbc.c
+++ linux-4.4.0/drivers/crypto/vmx/aes_cbc.c
@@ -55,8 +55,6 @@
 		       alg, PTR_ERR(fallback));
 		return PTR_ERR(fallback);
 	}
-	printk(KERN_INFO "Using '%s' as fallback implementation.\n",
-	       crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
 
 	crypto_blkcipher_set_flags(
 		fallback,
@@ -84,10 +82,10 @@
 
 	preempt_disable();
 	pagefault_disable();
-	enable_kernel_altivec();
 	enable_kernel_vsx();
 	ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
 	ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
+	disable_kernel_vsx();
 	pagefault_enable();
 	preempt_enable();
 
@@ -113,24 +111,23 @@
 		ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src,
 					       nbytes);
 	} else {
-		preempt_disable();
-		pagefault_disable();
-		enable_kernel_altivec();
-		enable_kernel_vsx();
-
 		blkcipher_walk_init(&walk, dst, src, nbytes);
 		ret = blkcipher_walk_virt(desc, &walk);
 		while ((nbytes = walk.nbytes)) {
+			preempt_disable();
+			pagefault_disable();
+			enable_kernel_vsx();
 			aes_p8_cbc_encrypt(walk.src.virt.addr,
 					   walk.dst.virt.addr,
 					   nbytes & AES_BLOCK_MASK,
 					   &ctx->enc_key, walk.iv, 1);
+			disable_kernel_vsx();
+			pagefault_enable();
+			preempt_enable();
+
 			nbytes &= AES_BLOCK_SIZE - 1;
 			ret = blkcipher_walk_done(desc, &walk, nbytes);
 		}
-
-		pagefault_enable();
-		preempt_enable();
 	}
 
 	return ret;
@@ -154,24 +151,23 @@
 		ret = crypto_blkcipher_decrypt(&fallback_desc, dst, src,
 					       nbytes);
 	} else {
-		preempt_disable();
-		pagefault_disable();
-		enable_kernel_altivec();
-		enable_kernel_vsx();
-
 		blkcipher_walk_init(&walk, dst, src, nbytes);
 		ret = blkcipher_walk_virt(desc, &walk);
 		while ((nbytes = walk.nbytes)) {
+			preempt_disable();
+			pagefault_disable();
+			enable_kernel_vsx();
 			aes_p8_cbc_encrypt(walk.src.virt.addr,
 					   walk.dst.virt.addr,
 					   nbytes & AES_BLOCK_MASK,
 					   &ctx->dec_key, walk.iv, 0);
+			disable_kernel_vsx();
+			pagefault_enable();
+			preempt_enable();
+
 			nbytes &= AES_BLOCK_SIZE - 1;
 			ret = blkcipher_walk_done(desc, &walk, nbytes);
 		}
-
-		pagefault_enable();
-		preempt_enable();
 	}
 
 	return ret;
@@ -182,7 +178,7 @@
 	.cra_name = "cbc(aes)",
 	.cra_driver_name = "p8_aes_cbc",
 	.cra_module = THIS_MODULE,
-	.cra_priority = 1000,
+	.cra_priority = 2000,
 	.cra_type = &crypto_blkcipher_type,
 	.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
 	.cra_alignmask = 0,
@@ -191,7 +187,7 @@
 	.cra_init = p8_aes_cbc_init,
 	.cra_exit = p8_aes_cbc_exit,
 	.cra_blkcipher = {
-			  .ivsize = 0,
+			  .ivsize = AES_BLOCK_SIZE,
 			  .min_keysize = AES_MIN_KEY_SIZE,
 			  .max_keysize = AES_MAX_KEY_SIZE,
 			  .setkey = p8_aes_cbc_setkey,
--- linux-4.4.0.orig/drivers/crypto/vmx/aes_ctr.c
+++ linux-4.4.0/drivers/crypto/vmx/aes_ctr.c
@@ -53,8 +53,6 @@
 		       alg, PTR_ERR(fallback));
 		return PTR_ERR(fallback);
 	}
-	printk(KERN_INFO "Using '%s' as fallback implementation.\n",
-	       crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
 
 	crypto_blkcipher_set_flags(
 		fallback,
@@ -80,11 +78,13 @@
 	int ret;
 	struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
 
+	preempt_disable();
 	pagefault_disable();
-	enable_kernel_altivec();
 	enable_kernel_vsx();
 	ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
+	disable_kernel_vsx();
 	pagefault_enable();
+	preempt_enable();
 
 	ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen);
 	return ret;
@@ -99,11 +99,13 @@
 	u8 *dst = walk->dst.virt.addr;
 	unsigned int nbytes = walk->nbytes;
 
+	preempt_disable();
 	pagefault_disable();
-	enable_kernel_altivec();
 	enable_kernel_vsx();
 	aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key);
+	disable_kernel_vsx();
 	pagefault_enable();
+	preempt_enable();
 
 	crypto_xor(keystream, src, nbytes);
 	memcpy(dst, keystream, nbytes);
@@ -132,8 +134,8 @@
 		blkcipher_walk_init(&walk, dst, src, nbytes);
 		ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
 		while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
+			preempt_disable();
 			pagefault_disable();
-			enable_kernel_altivec();
 			enable_kernel_vsx();
 			aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr,
 						    walk.dst.virt.addr,
@@ -142,7 +144,9 @@
 						    AES_BLOCK_SIZE,
 						    &ctx->enc_key,
 						    walk.iv);
+			disable_kernel_vsx();
 			pagefault_enable();
+			preempt_enable();
 
 			/* We need to update IV mostly for last bytes/round */
 			inc = (nbytes & AES_BLOCK_MASK) / AES_BLOCK_SIZE;
@@ -166,7 +170,7 @@
 	.cra_name = "ctr(aes)",
 	.cra_driver_name = "p8_aes_ctr",
 	.cra_module = THIS_MODULE,
-	.cra_priority = 1000,
+	.cra_priority = 2000,
 	.cra_type = &crypto_blkcipher_type,
 	.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
 	.cra_alignmask = 0,
@@ -175,7 +179,7 @@
 	.cra_init = p8_aes_ctr_init,
 	.cra_exit = p8_aes_ctr_exit,
 	.cra_blkcipher = {
-			  .ivsize = 0,
+			  .ivsize = AES_BLOCK_SIZE,
 			  .min_keysize = AES_MIN_KEY_SIZE,
 			  .max_keysize = AES_MAX_KEY_SIZE,
 			  .setkey = p8_aes_ctr_setkey,
--- linux-4.4.0.orig/drivers/crypto/vmx/aes_xts.c
+++ linux-4.4.0/drivers/crypto/vmx/aes_xts.c
@@ -0,0 +1,197 @@
+/**
+ * AES XTS routines supporting VMX In-core instructions on Power 8
+ *
+ * Copyright (C) 2015 International Business Machines 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 Foundations; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY of FITNESS FOR A PARTICUPAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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.
+ *
+ * Author: Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/crypto.h>
+#include <linux/delay.h>
+#include <linux/hardirq.h>
+#include <asm/switch_to.h>
+#include <crypto/aes.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/xts.h>
+
+#include "aesp8-ppc.h"
+
+struct p8_aes_xts_ctx {
+	struct crypto_blkcipher *fallback;
+	struct aes_key enc_key;
+	struct aes_key dec_key;
+	struct aes_key tweak_key;
+};
+
+static int p8_aes_xts_init(struct crypto_tfm *tfm)
+{
+	const char *alg;
+	struct crypto_blkcipher *fallback;
+	struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	if (!(alg = crypto_tfm_alg_name(tfm))) {
+		printk(KERN_ERR "Failed to get algorithm name.\n");
+		return -ENOENT;
+	}
+
+	fallback =
+		crypto_alloc_blkcipher(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
+	if (IS_ERR(fallback)) {
+		printk(KERN_ERR
+			"Failed to allocate transformation for '%s': %ld\n",
+			alg, PTR_ERR(fallback));
+		return PTR_ERR(fallback);
+	}
+	printk(KERN_INFO "Using '%s' as fallback implementation.\n",
+		crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
+
+	crypto_blkcipher_set_flags(
+		fallback,
+		crypto_blkcipher_get_flags((struct crypto_blkcipher *)tfm));
+	ctx->fallback = fallback;
+
+	return 0;
+}
+
+static void p8_aes_xts_exit(struct crypto_tfm *tfm)
+{
+	struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	if (ctx->fallback) {
+		crypto_free_blkcipher(ctx->fallback);
+		ctx->fallback = NULL;
+	}
+}
+
+static int p8_aes_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
+			     unsigned int keylen)
+{
+	int ret;
+	struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	ret = xts_check_key(tfm, key, keylen);
+	if (ret)
+		return ret;
+
+	preempt_disable();
+	pagefault_disable();
+	enable_kernel_vsx();
+	ret = aes_p8_set_encrypt_key(key + keylen/2, (keylen/2) * 8, &ctx->tweak_key);
+	ret += aes_p8_set_encrypt_key(key, (keylen/2) * 8, &ctx->enc_key);
+	ret += aes_p8_set_decrypt_key(key, (keylen/2) * 8, &ctx->dec_key);
+	disable_kernel_vsx();
+	pagefault_enable();
+	preempt_enable();
+
+	ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen);
+	return ret;
+}
+
+static int p8_aes_xts_crypt(struct blkcipher_desc *desc,
+			    struct scatterlist *dst,
+			    struct scatterlist *src,
+			    unsigned int nbytes, int enc)
+{
+	int ret;
+	u8 tweak[AES_BLOCK_SIZE];
+	u8 *iv;
+	struct blkcipher_walk walk;
+	struct p8_aes_xts_ctx *ctx =
+		crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
+	struct blkcipher_desc fallback_desc = {
+		.tfm = ctx->fallback,
+		.info = desc->info,
+		.flags = desc->flags
+	};
+
+	if (in_interrupt()) {
+		ret = enc ? crypto_blkcipher_encrypt(&fallback_desc, dst, src, nbytes) :
+                            crypto_blkcipher_decrypt(&fallback_desc, dst, src, nbytes);
+	} else {
+		blkcipher_walk_init(&walk, dst, src, nbytes);
+
+		ret = blkcipher_walk_virt(desc, &walk);
+
+		preempt_disable();
+		pagefault_disable();
+		enable_kernel_vsx();
+
+		iv = walk.iv;
+		memset(tweak, 0, AES_BLOCK_SIZE);
+		aes_p8_encrypt(iv, tweak, &ctx->tweak_key);
+
+		disable_kernel_vsx();
+		pagefault_enable();
+		preempt_enable();
+
+		while ((nbytes = walk.nbytes)) {
+			preempt_disable();
+			pagefault_disable();
+			enable_kernel_vsx();
+			if (enc)
+				aes_p8_xts_encrypt(walk.src.virt.addr, walk.dst.virt.addr,
+						nbytes & AES_BLOCK_MASK, &ctx->enc_key, NULL, tweak);
+			else
+				aes_p8_xts_decrypt(walk.src.virt.addr, walk.dst.virt.addr,
+						nbytes & AES_BLOCK_MASK, &ctx->dec_key, NULL, tweak);
+			disable_kernel_vsx();
+			pagefault_enable();
+			preempt_enable();
+
+			nbytes &= AES_BLOCK_SIZE - 1;
+			ret = blkcipher_walk_done(desc, &walk, nbytes);
+		}
+	}
+	return ret;
+}
+
+static int p8_aes_xts_encrypt(struct blkcipher_desc *desc,
+			      struct scatterlist *dst,
+			      struct scatterlist *src, unsigned int nbytes)
+{
+	return p8_aes_xts_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int p8_aes_xts_decrypt(struct blkcipher_desc *desc,
+			      struct scatterlist *dst,
+			      struct scatterlist *src, unsigned int nbytes)
+{
+	return p8_aes_xts_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg p8_aes_xts_alg = {
+	.cra_name = "xts(aes)",
+	.cra_driver_name = "p8_aes_xts",
+	.cra_module = THIS_MODULE,
+	.cra_priority = 2000,
+	.cra_type = &crypto_blkcipher_type,
+	.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
+	.cra_alignmask = 0,
+	.cra_blocksize = AES_BLOCK_SIZE,
+	.cra_ctxsize = sizeof(struct p8_aes_xts_ctx),
+	.cra_init = p8_aes_xts_init,
+	.cra_exit = p8_aes_xts_exit,
+	.cra_blkcipher = {
+			.ivsize = AES_BLOCK_SIZE,
+			.min_keysize = 2 * AES_MIN_KEY_SIZE,
+			.max_keysize = 2 * AES_MAX_KEY_SIZE,
+			.setkey	 = p8_aes_xts_setkey,
+			.encrypt = p8_aes_xts_encrypt,
+			.decrypt = p8_aes_xts_decrypt,
+	}
+};
--- linux-4.4.0.orig/drivers/crypto/vmx/aesp8-ppc.h
+++ linux-4.4.0/drivers/crypto/vmx/aesp8-ppc.h
@@ -19,3 +19,7 @@
 void aes_p8_ctr32_encrypt_blocks(const u8 *in, u8 *out,
 				 size_t len, const struct aes_key *key,
 				 const u8 *iv);
+void aes_p8_xts_encrypt(const u8 *in, u8 *out, size_t len,
+			const struct aes_key *key1, const struct aes_key *key2, u8 *iv);
+void aes_p8_xts_decrypt(const u8 *in, u8 *out, size_t len,
+			const struct aes_key *key1, const struct aes_key *key2, u8 *iv);
--- linux-4.4.0.orig/drivers/crypto/vmx/aesp8-ppc.pl
+++ linux-4.4.0/drivers/crypto/vmx/aesp8-ppc.pl
@@ -1,4 +1,11 @@
-#!/usr/bin/env perl
+#! /usr/bin/env perl
+# Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
 #
 # ====================================================================
 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -20,6 +27,19 @@
 # instructions are interleaved. It's reckoned that eventual
 # misalignment penalties at page boundaries are in average lower
 # than additional overhead in pure AltiVec approach.
+#
+# May 2016
+#
+# Add XTS subroutine, 9x on little- and 12x improvement on big-endian
+# systems were measured.
+#
+######################################################################
+# Current large-block performance in cycles per byte processed with
+# 128-bit key (less is better).
+#
+#		CBC en-/decrypt	CTR	XTS
+# POWER8[le]	3.96/0.72	0.74	1.1
+# POWER8[be]	3.75/0.65	0.66	1.0
 
 $flavour = shift;
 
@@ -1298,7 +1318,7 @@
 	addi		$idx,$idx,16
 	bdnz		Loop_ctr32_enc
 
-	vadduwm		$ivec,$ivec,$one
+	vadduqm		$ivec,$ivec,$one
 	 vmr		$dat,$inptail
 	 lvx		$inptail,0,$inp
 	 addi		$inp,$inp,16
@@ -1795,7 +1815,7 @@
 	stvx_u		$out1,$x10,$out
 	stvx_u		$out2,$x20,$out
 	addi		$out,$out,0x30
-	b		Lcbc_dec8x_done
+	b		Lctr32_enc8x_done
 
 .align	5
 Lctr32_enc8x_two:
@@ -1807,7 +1827,7 @@
 	stvx_u		$out0,$x00,$out
 	stvx_u		$out1,$x10,$out
 	addi		$out,$out,0x20
-	b		Lcbc_dec8x_done
+	b		Lctr32_enc8x_done
 
 .align	5
 Lctr32_enc8x_one:
@@ -1875,6 +1895,1845 @@
 ___
 }}	}}}
 
+#########################################################################
+{{{	# XTS procedures						#
+# int aes_p8_xts_[en|de]crypt(const char *inp, char *out, size_t len,	#
+#                             const AES_KEY *key1, const AES_KEY *key2,	#
+#                             [const] unsigned char iv[16]);		#
+# If $key2 is NULL, then a "tweak chaining" mode is engaged, in which	#
+# input tweak value is assumed to be encrypted already, and last tweak	#
+# value, one suitable for consecutive call on same chunk of data, is	#
+# written back to original buffer. In addition, in "tweak chaining"	#
+# mode only complete input blocks are processed.			#
+
+my ($inp,$out,$len,$key1,$key2,$ivp,$rounds,$idx) =	map("r$_",(3..10));
+my ($rndkey0,$rndkey1,$inout) =				map("v$_",(0..2));
+my ($output,$inptail,$inpperm,$leperm,$keyperm) =	map("v$_",(3..7));
+my ($tweak,$seven,$eighty7,$tmp,$tweak1) =		map("v$_",(8..12));
+my $taillen = $key2;
+
+   ($inp,$idx) = ($idx,$inp);				# reassign
+
+$code.=<<___;
+.globl	.${prefix}_xts_encrypt
+	mr		$inp,r3				# reassign
+	li		r3,-1
+	${UCMP}i	$len,16
+	bltlr-
+
+	lis		r0,0xfff0
+	mfspr		r12,256				# save vrsave
+	li		r11,0
+	mtspr		256,r0
+
+	vspltisb	$seven,0x07			# 0x070707..07
+	le?lvsl		$leperm,r11,r11
+	le?vspltisb	$tmp,0x0f
+	le?vxor		$leperm,$leperm,$seven
+
+	li		$idx,15
+	lvx		$tweak,0,$ivp			# load [unaligned] iv
+	lvsl		$inpperm,0,$ivp
+	lvx		$inptail,$idx,$ivp
+	le?vxor		$inpperm,$inpperm,$tmp
+	vperm		$tweak,$tweak,$inptail,$inpperm
+
+	neg		r11,$inp
+	lvsr		$inpperm,0,r11			# prepare for unaligned load
+	lvx		$inout,0,$inp
+	addi		$inp,$inp,15			# 15 is not typo
+	le?vxor		$inpperm,$inpperm,$tmp
+
+	${UCMP}i	$key2,0				# key2==NULL?
+	beq		Lxts_enc_no_key2
+
+	?lvsl		$keyperm,0,$key2		# prepare for unaligned key
+	lwz		$rounds,240($key2)
+	srwi		$rounds,$rounds,1
+	subi		$rounds,$rounds,1
+	li		$idx,16
+
+	lvx		$rndkey0,0,$key2
+	lvx		$rndkey1,$idx,$key2
+	addi		$idx,$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$tweak,$tweak,$rndkey0
+	lvx		$rndkey0,$idx,$key2
+	addi		$idx,$idx,16
+	mtctr		$rounds
+
+Ltweak_xts_enc:
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vcipher		$tweak,$tweak,$rndkey1
+	lvx		$rndkey1,$idx,$key2
+	addi		$idx,$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vcipher		$tweak,$tweak,$rndkey0
+	lvx		$rndkey0,$idx,$key2
+	addi		$idx,$idx,16
+	bdnz		Ltweak_xts_enc
+
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vcipher		$tweak,$tweak,$rndkey1
+	lvx		$rndkey1,$idx,$key2
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vcipherlast	$tweak,$tweak,$rndkey0
+
+	li		$ivp,0				# don't chain the tweak
+	b		Lxts_enc
+
+Lxts_enc_no_key2:
+	li		$idx,-16
+	and		$len,$len,$idx			# in "tweak chaining"
+							# mode only complete
+							# blocks are processed
+Lxts_enc:
+	lvx		$inptail,0,$inp
+	addi		$inp,$inp,16
+
+	?lvsl		$keyperm,0,$key1		# prepare for unaligned key
+	lwz		$rounds,240($key1)
+	srwi		$rounds,$rounds,1
+	subi		$rounds,$rounds,1
+	li		$idx,16
+
+	vslb		$eighty7,$seven,$seven		# 0x808080..80
+	vor		$eighty7,$eighty7,$seven	# 0x878787..87
+	vspltisb	$tmp,1				# 0x010101..01
+	vsldoi		$eighty7,$eighty7,$tmp,15	# 0x870101..01
+
+	${UCMP}i	$len,96
+	bge		_aesp8_xts_encrypt6x
+
+	andi.		$taillen,$len,15
+	subic		r0,$len,32
+	subi		$taillen,$taillen,16
+	subfe		r0,r0,r0
+	and		r0,r0,$taillen
+	add		$inp,$inp,r0
+
+	lvx		$rndkey0,0,$key1
+	lvx		$rndkey1,$idx,$key1
+	addi		$idx,$idx,16
+	vperm		$inout,$inout,$inptail,$inpperm
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$inout,$inout,$tweak
+	vxor		$inout,$inout,$rndkey0
+	lvx		$rndkey0,$idx,$key1
+	addi		$idx,$idx,16
+	mtctr		$rounds
+	b		Loop_xts_enc
+
+.align	5
+Loop_xts_enc:
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vcipher		$inout,$inout,$rndkey1
+	lvx		$rndkey1,$idx,$key1
+	addi		$idx,$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vcipher		$inout,$inout,$rndkey0
+	lvx		$rndkey0,$idx,$key1
+	addi		$idx,$idx,16
+	bdnz		Loop_xts_enc
+
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vcipher		$inout,$inout,$rndkey1
+	lvx		$rndkey1,$idx,$key1
+	li		$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$rndkey0,$rndkey0,$tweak
+	vcipherlast	$output,$inout,$rndkey0
+
+	le?vperm	$tmp,$output,$output,$leperm
+	be?nop
+	le?stvx_u	$tmp,0,$out
+	be?stvx_u	$output,0,$out
+	addi		$out,$out,16
+
+	subic.		$len,$len,16
+	beq		Lxts_enc_done
+
+	vmr		$inout,$inptail
+	lvx		$inptail,0,$inp
+	addi		$inp,$inp,16
+	lvx		$rndkey0,0,$key1
+	lvx		$rndkey1,$idx,$key1
+	addi		$idx,$idx,16
+
+	subic		r0,$len,32
+	subfe		r0,r0,r0
+	and		r0,r0,$taillen
+	add		$inp,$inp,r0
+
+	vsrab		$tmp,$tweak,$seven		# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	vand		$tmp,$tmp,$eighty7
+	vxor		$tweak,$tweak,$tmp
+
+	vperm		$inout,$inout,$inptail,$inpperm
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$inout,$inout,$tweak
+	vxor		$output,$output,$rndkey0	# just in case $len<16
+	vxor		$inout,$inout,$rndkey0
+	lvx		$rndkey0,$idx,$key1
+	addi		$idx,$idx,16
+
+	mtctr		$rounds
+	${UCMP}i	$len,16
+	bge		Loop_xts_enc
+
+	vxor		$output,$output,$tweak
+	lvsr		$inpperm,0,$len			# $inpperm is no longer needed
+	vxor		$inptail,$inptail,$inptail	# $inptail is no longer needed
+	vspltisb	$tmp,-1
+	vperm		$inptail,$inptail,$tmp,$inpperm
+	vsel		$inout,$inout,$output,$inptail
+
+	subi		r11,$out,17
+	subi		$out,$out,16
+	mtctr		$len
+	li		$len,16
+Loop_xts_enc_steal:
+	lbzu		r0,1(r11)
+	stb		r0,16(r11)
+	bdnz		Loop_xts_enc_steal
+
+	mtctr		$rounds
+	b		Loop_xts_enc			# one more time...
+
+Lxts_enc_done:
+	${UCMP}i	$ivp,0
+	beq		Lxts_enc_ret
+
+	vsrab		$tmp,$tweak,$seven		# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	vand		$tmp,$tmp,$eighty7
+	vxor		$tweak,$tweak,$tmp
+
+	le?vperm	$tweak,$tweak,$tweak,$leperm
+	stvx_u		$tweak,0,$ivp
+
+Lxts_enc_ret:
+	mtspr		256,r12				# restore vrsave
+	li		r3,0
+	blr
+	.long		0
+	.byte		0,12,0x04,0,0x80,6,6,0
+	.long		0
+.size	.${prefix}_xts_encrypt,.-.${prefix}_xts_encrypt
+
+.globl	.${prefix}_xts_decrypt
+	mr		$inp,r3				# reassign
+	li		r3,-1
+	${UCMP}i	$len,16
+	bltlr-
+
+	lis		r0,0xfff8
+	mfspr		r12,256				# save vrsave
+	li		r11,0
+	mtspr		256,r0
+
+	andi.		r0,$len,15
+	neg		r0,r0
+	andi.		r0,r0,16
+	sub		$len,$len,r0
+
+	vspltisb	$seven,0x07			# 0x070707..07
+	le?lvsl		$leperm,r11,r11
+	le?vspltisb	$tmp,0x0f
+	le?vxor		$leperm,$leperm,$seven
+
+	li		$idx,15
+	lvx		$tweak,0,$ivp			# load [unaligned] iv
+	lvsl		$inpperm,0,$ivp
+	lvx		$inptail,$idx,$ivp
+	le?vxor		$inpperm,$inpperm,$tmp
+	vperm		$tweak,$tweak,$inptail,$inpperm
+
+	neg		r11,$inp
+	lvsr		$inpperm,0,r11			# prepare for unaligned load
+	lvx		$inout,0,$inp
+	addi		$inp,$inp,15			# 15 is not typo
+	le?vxor		$inpperm,$inpperm,$tmp
+
+	${UCMP}i	$key2,0				# key2==NULL?
+	beq		Lxts_dec_no_key2
+
+	?lvsl		$keyperm,0,$key2		# prepare for unaligned key
+	lwz		$rounds,240($key2)
+	srwi		$rounds,$rounds,1
+	subi		$rounds,$rounds,1
+	li		$idx,16
+
+	lvx		$rndkey0,0,$key2
+	lvx		$rndkey1,$idx,$key2
+	addi		$idx,$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$tweak,$tweak,$rndkey0
+	lvx		$rndkey0,$idx,$key2
+	addi		$idx,$idx,16
+	mtctr		$rounds
+
+Ltweak_xts_dec:
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vcipher		$tweak,$tweak,$rndkey1
+	lvx		$rndkey1,$idx,$key2
+	addi		$idx,$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vcipher		$tweak,$tweak,$rndkey0
+	lvx		$rndkey0,$idx,$key2
+	addi		$idx,$idx,16
+	bdnz		Ltweak_xts_dec
+
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vcipher		$tweak,$tweak,$rndkey1
+	lvx		$rndkey1,$idx,$key2
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vcipherlast	$tweak,$tweak,$rndkey0
+
+	li		$ivp,0				# don't chain the tweak
+	b		Lxts_dec
+
+Lxts_dec_no_key2:
+	neg		$idx,$len
+	andi.		$idx,$idx,15
+	add		$len,$len,$idx			# in "tweak chaining"
+							# mode only complete
+							# blocks are processed
+Lxts_dec:
+	lvx		$inptail,0,$inp
+	addi		$inp,$inp,16
+
+	?lvsl		$keyperm,0,$key1		# prepare for unaligned key
+	lwz		$rounds,240($key1)
+	srwi		$rounds,$rounds,1
+	subi		$rounds,$rounds,1
+	li		$idx,16
+
+	vslb		$eighty7,$seven,$seven		# 0x808080..80
+	vor		$eighty7,$eighty7,$seven	# 0x878787..87
+	vspltisb	$tmp,1				# 0x010101..01
+	vsldoi		$eighty7,$eighty7,$tmp,15	# 0x870101..01
+
+	${UCMP}i	$len,96
+	bge		_aesp8_xts_decrypt6x
+
+	lvx		$rndkey0,0,$key1
+	lvx		$rndkey1,$idx,$key1
+	addi		$idx,$idx,16
+	vperm		$inout,$inout,$inptail,$inpperm
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$inout,$inout,$tweak
+	vxor		$inout,$inout,$rndkey0
+	lvx		$rndkey0,$idx,$key1
+	addi		$idx,$idx,16
+	mtctr		$rounds
+
+	${UCMP}i	$len,16
+	blt		Ltail_xts_dec
+	be?b		Loop_xts_dec
+
+.align	5
+Loop_xts_dec:
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vncipher	$inout,$inout,$rndkey1
+	lvx		$rndkey1,$idx,$key1
+	addi		$idx,$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vncipher	$inout,$inout,$rndkey0
+	lvx		$rndkey0,$idx,$key1
+	addi		$idx,$idx,16
+	bdnz		Loop_xts_dec
+
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vncipher	$inout,$inout,$rndkey1
+	lvx		$rndkey1,$idx,$key1
+	li		$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$rndkey0,$rndkey0,$tweak
+	vncipherlast	$output,$inout,$rndkey0
+
+	le?vperm	$tmp,$output,$output,$leperm
+	be?nop
+	le?stvx_u	$tmp,0,$out
+	be?stvx_u	$output,0,$out
+	addi		$out,$out,16
+
+	subic.		$len,$len,16
+	beq		Lxts_dec_done
+
+	vmr		$inout,$inptail
+	lvx		$inptail,0,$inp
+	addi		$inp,$inp,16
+	lvx		$rndkey0,0,$key1
+	lvx		$rndkey1,$idx,$key1
+	addi		$idx,$idx,16
+
+	vsrab		$tmp,$tweak,$seven		# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	vand		$tmp,$tmp,$eighty7
+	vxor		$tweak,$tweak,$tmp
+
+	vperm		$inout,$inout,$inptail,$inpperm
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$inout,$inout,$tweak
+	vxor		$inout,$inout,$rndkey0
+	lvx		$rndkey0,$idx,$key1
+	addi		$idx,$idx,16
+
+	mtctr		$rounds
+	${UCMP}i	$len,16
+	bge		Loop_xts_dec
+
+Ltail_xts_dec:
+	vsrab		$tmp,$tweak,$seven		# next tweak value
+	vaddubm		$tweak1,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	vand		$tmp,$tmp,$eighty7
+	vxor		$tweak1,$tweak1,$tmp
+
+	subi		$inp,$inp,16
+	add		$inp,$inp,$len
+
+	vxor		$inout,$inout,$tweak		# :-(
+	vxor		$inout,$inout,$tweak1		# :-)
+
+Loop_xts_dec_short:
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vncipher	$inout,$inout,$rndkey1
+	lvx		$rndkey1,$idx,$key1
+	addi		$idx,$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vncipher	$inout,$inout,$rndkey0
+	lvx		$rndkey0,$idx,$key1
+	addi		$idx,$idx,16
+	bdnz		Loop_xts_dec_short
+
+	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
+	vncipher	$inout,$inout,$rndkey1
+	lvx		$rndkey1,$idx,$key1
+	li		$idx,16
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+	vxor		$rndkey0,$rndkey0,$tweak1
+	vncipherlast	$output,$inout,$rndkey0
+
+	le?vperm	$tmp,$output,$output,$leperm
+	be?nop
+	le?stvx_u	$tmp,0,$out
+	be?stvx_u	$output,0,$out
+
+	vmr		$inout,$inptail
+	lvx		$inptail,0,$inp
+	#addi		$inp,$inp,16
+	lvx		$rndkey0,0,$key1
+	lvx		$rndkey1,$idx,$key1
+	addi		$idx,$idx,16
+	vperm		$inout,$inout,$inptail,$inpperm
+	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
+
+	lvsr		$inpperm,0,$len			# $inpperm is no longer needed
+	vxor		$inptail,$inptail,$inptail	# $inptail is no longer needed
+	vspltisb	$tmp,-1
+	vperm		$inptail,$inptail,$tmp,$inpperm
+	vsel		$inout,$inout,$output,$inptail
+
+	vxor		$rndkey0,$rndkey0,$tweak
+	vxor		$inout,$inout,$rndkey0
+	lvx		$rndkey0,$idx,$key1
+	addi		$idx,$idx,16
+
+	subi		r11,$out,1
+	mtctr		$len
+	li		$len,16
+Loop_xts_dec_steal:
+	lbzu		r0,1(r11)
+	stb		r0,16(r11)
+	bdnz		Loop_xts_dec_steal
+
+	mtctr		$rounds
+	b		Loop_xts_dec			# one more time...
+
+Lxts_dec_done:
+	${UCMP}i	$ivp,0
+	beq		Lxts_dec_ret
+
+	vsrab		$tmp,$tweak,$seven		# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	vand		$tmp,$tmp,$eighty7
+	vxor		$tweak,$tweak,$tmp
+
+	le?vperm	$tweak,$tweak,$tweak,$leperm
+	stvx_u		$tweak,0,$ivp
+
+Lxts_dec_ret:
+	mtspr		256,r12				# restore vrsave
+	li		r3,0
+	blr
+	.long		0
+	.byte		0,12,0x04,0,0x80,6,6,0
+	.long		0
+.size	.${prefix}_xts_decrypt,.-.${prefix}_xts_decrypt
+___
+#########################################################################
+{{	# Optimized XTS procedures					#
+my $key_=$key2;
+my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,3,26..31));
+    $x00=0 if ($flavour =~ /osx/);
+my ($in0,  $in1,  $in2,  $in3,  $in4,  $in5 )=map("v$_",(0..5));
+my ($out0, $out1, $out2, $out3, $out4, $out5)=map("v$_",(7,12..16));
+my ($twk0, $twk1, $twk2, $twk3, $twk4, $twk5)=map("v$_",(17..22));
+my $rndkey0="v23";	# v24-v25 rotating buffer for first found keys
+			# v26-v31 last 6 round keys
+my ($keyperm)=($out0);	# aliases with "caller", redundant assignment
+my $taillen=$x70;
+
+$code.=<<___;
+.align	5
+_aesp8_xts_encrypt6x:
+	$STU		$sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
+	mflr		r11
+	li		r7,`$FRAME+8*16+15`
+	li		r3,`$FRAME+8*16+31`
+	$PUSH		r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)
+	stvx		v20,r7,$sp		# ABI says so
+	addi		r7,r7,32
+	stvx		v21,r3,$sp
+	addi		r3,r3,32
+	stvx		v22,r7,$sp
+	addi		r7,r7,32
+	stvx		v23,r3,$sp
+	addi		r3,r3,32
+	stvx		v24,r7,$sp
+	addi		r7,r7,32
+	stvx		v25,r3,$sp
+	addi		r3,r3,32
+	stvx		v26,r7,$sp
+	addi		r7,r7,32
+	stvx		v27,r3,$sp
+	addi		r3,r3,32
+	stvx		v28,r7,$sp
+	addi		r7,r7,32
+	stvx		v29,r3,$sp
+	addi		r3,r3,32
+	stvx		v30,r7,$sp
+	stvx		v31,r3,$sp
+	li		r0,-1
+	stw		$vrsave,`$FRAME+21*16-4`($sp)	# save vrsave
+	li		$x10,0x10
+	$PUSH		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+	li		$x20,0x20
+	$PUSH		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+	li		$x30,0x30
+	$PUSH		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+	li		$x40,0x40
+	$PUSH		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+	li		$x50,0x50
+	$PUSH		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+	li		$x60,0x60
+	$PUSH		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+	li		$x70,0x70
+	mtspr		256,r0
+
+	subi		$rounds,$rounds,3	# -4 in total
+
+	lvx		$rndkey0,$x00,$key1	# load key schedule
+	lvx		v30,$x10,$key1
+	addi		$key1,$key1,0x20
+	lvx		v31,$x00,$key1
+	?vperm		$rndkey0,$rndkey0,v30,$keyperm
+	addi		$key_,$sp,$FRAME+15
+	mtctr		$rounds
+
+Load_xts_enc_key:
+	?vperm		v24,v30,v31,$keyperm
+	lvx		v30,$x10,$key1
+	addi		$key1,$key1,0x20
+	stvx		v24,$x00,$key_		# off-load round[1]
+	?vperm		v25,v31,v30,$keyperm
+	lvx		v31,$x00,$key1
+	stvx		v25,$x10,$key_		# off-load round[2]
+	addi		$key_,$key_,0x20
+	bdnz		Load_xts_enc_key
+
+	lvx		v26,$x10,$key1
+	?vperm		v24,v30,v31,$keyperm
+	lvx		v27,$x20,$key1
+	stvx		v24,$x00,$key_		# off-load round[3]
+	?vperm		v25,v31,v26,$keyperm
+	lvx		v28,$x30,$key1
+	stvx		v25,$x10,$key_		# off-load round[4]
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	?vperm		v26,v26,v27,$keyperm
+	lvx		v29,$x40,$key1
+	?vperm		v27,v27,v28,$keyperm
+	lvx		v30,$x50,$key1
+	?vperm		v28,v28,v29,$keyperm
+	lvx		v31,$x60,$key1
+	?vperm		v29,v29,v30,$keyperm
+	lvx		$twk5,$x70,$key1	# borrow $twk5
+	?vperm		v30,v30,v31,$keyperm
+	lvx		v24,$x00,$key_		# pre-load round[1]
+	?vperm		v31,v31,$twk5,$keyperm
+	lvx		v25,$x10,$key_		# pre-load round[2]
+
+	 vperm		$in0,$inout,$inptail,$inpperm
+	 subi		$inp,$inp,31		# undo "caller"
+	vxor		$twk0,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out0,$in0,$twk0
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in1,$x10,$inp
+	vxor		$twk1,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in1,$in1,$in1,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out1,$in1,$twk1
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in2,$x20,$inp
+	 andi.		$taillen,$len,15
+	vxor		$twk2,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in2,$in2,$in2,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out2,$in2,$twk2
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in3,$x30,$inp
+	 sub		$len,$len,$taillen
+	vxor		$twk3,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in3,$in3,$in3,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out3,$in3,$twk3
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in4,$x40,$inp
+	 subi		$len,$len,0x60
+	vxor		$twk4,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in4,$in4,$in4,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out4,$in4,$twk4
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in5,$x50,$inp
+	 addi		$inp,$inp,0x60
+	vxor		$twk5,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in5,$in5,$in5,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out5,$in5,$twk5
+	vxor		$tweak,$tweak,$tmp
+
+	vxor		v31,v31,$rndkey0
+	mtctr		$rounds
+	b		Loop_xts_enc6x
+
+.align	5
+Loop_xts_enc6x:
+	vcipher		$out0,$out0,v24
+	vcipher		$out1,$out1,v24
+	vcipher		$out2,$out2,v24
+	vcipher		$out3,$out3,v24
+	vcipher		$out4,$out4,v24
+	vcipher		$out5,$out5,v24
+	lvx		v24,$x20,$key_		# round[3]
+	addi		$key_,$key_,0x20
+
+	vcipher		$out0,$out0,v25
+	vcipher		$out1,$out1,v25
+	vcipher		$out2,$out2,v25
+	vcipher		$out3,$out3,v25
+	vcipher		$out4,$out4,v25
+	vcipher		$out5,$out5,v25
+	lvx		v25,$x10,$key_		# round[4]
+	bdnz		Loop_xts_enc6x
+
+	subic		$len,$len,96		# $len-=96
+	 vxor		$in0,$twk0,v31		# xor with last round key
+	vcipher		$out0,$out0,v24
+	vcipher		$out1,$out1,v24
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk0,$tweak,$rndkey0
+	 vaddubm	$tweak,$tweak,$tweak
+	vcipher		$out2,$out2,v24
+	vcipher		$out3,$out3,v24
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vcipher		$out4,$out4,v24
+	vcipher		$out5,$out5,v24
+
+	subfe.		r0,r0,r0		# borrow?-1:0
+	 vand		$tmp,$tmp,$eighty7
+	vcipher		$out0,$out0,v25
+	vcipher		$out1,$out1,v25
+	 vxor		$tweak,$tweak,$tmp
+	vcipher		$out2,$out2,v25
+	vcipher		$out3,$out3,v25
+	 vxor		$in1,$twk1,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk1,$tweak,$rndkey0
+	vcipher		$out4,$out4,v25
+	vcipher		$out5,$out5,v25
+
+	and		r0,r0,$len
+	 vaddubm	$tweak,$tweak,$tweak
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vcipher		$out0,$out0,v26
+	vcipher		$out1,$out1,v26
+	 vand		$tmp,$tmp,$eighty7
+	vcipher		$out2,$out2,v26
+	vcipher		$out3,$out3,v26
+	 vxor		$tweak,$tweak,$tmp
+	vcipher		$out4,$out4,v26
+	vcipher		$out5,$out5,v26
+
+	add		$inp,$inp,r0		# $inp is adjusted in such
+						# way that at exit from the
+						# loop inX-in5 are loaded
+						# with last "words"
+	 vxor		$in2,$twk2,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk2,$tweak,$rndkey0
+	 vaddubm	$tweak,$tweak,$tweak
+	vcipher		$out0,$out0,v27
+	vcipher		$out1,$out1,v27
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vcipher		$out2,$out2,v27
+	vcipher		$out3,$out3,v27
+	 vand		$tmp,$tmp,$eighty7
+	vcipher		$out4,$out4,v27
+	vcipher		$out5,$out5,v27
+
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	 vxor		$tweak,$tweak,$tmp
+	vcipher		$out0,$out0,v28
+	vcipher		$out1,$out1,v28
+	 vxor		$in3,$twk3,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk3,$tweak,$rndkey0
+	vcipher		$out2,$out2,v28
+	vcipher		$out3,$out3,v28
+	 vaddubm	$tweak,$tweak,$tweak
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vcipher		$out4,$out4,v28
+	vcipher		$out5,$out5,v28
+	lvx		v24,$x00,$key_		# re-pre-load round[1]
+	 vand		$tmp,$tmp,$eighty7
+
+	vcipher		$out0,$out0,v29
+	vcipher		$out1,$out1,v29
+	 vxor		$tweak,$tweak,$tmp
+	vcipher		$out2,$out2,v29
+	vcipher		$out3,$out3,v29
+	 vxor		$in4,$twk4,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk4,$tweak,$rndkey0
+	vcipher		$out4,$out4,v29
+	vcipher		$out5,$out5,v29
+	lvx		v25,$x10,$key_		# re-pre-load round[2]
+	 vaddubm	$tweak,$tweak,$tweak
+	 vsldoi		$tmp,$tmp,$tmp,15
+
+	vcipher		$out0,$out0,v30
+	vcipher		$out1,$out1,v30
+	 vand		$tmp,$tmp,$eighty7
+	vcipher		$out2,$out2,v30
+	vcipher		$out3,$out3,v30
+	 vxor		$tweak,$tweak,$tmp
+	vcipher		$out4,$out4,v30
+	vcipher		$out5,$out5,v30
+	 vxor		$in5,$twk5,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk5,$tweak,$rndkey0
+
+	vcipherlast	$out0,$out0,$in0
+	 lvx_u		$in0,$x00,$inp		# load next input block
+	 vaddubm	$tweak,$tweak,$tweak
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vcipherlast	$out1,$out1,$in1
+	 lvx_u		$in1,$x10,$inp
+	vcipherlast	$out2,$out2,$in2
+	 le?vperm	$in0,$in0,$in0,$leperm
+	 lvx_u		$in2,$x20,$inp
+	 vand		$tmp,$tmp,$eighty7
+	vcipherlast	$out3,$out3,$in3
+	 le?vperm	$in1,$in1,$in1,$leperm
+	 lvx_u		$in3,$x30,$inp
+	vcipherlast	$out4,$out4,$in4
+	 le?vperm	$in2,$in2,$in2,$leperm
+	 lvx_u		$in4,$x40,$inp
+	 vxor		$tweak,$tweak,$tmp
+	vcipherlast	$tmp,$out5,$in5		# last block might be needed
+						# in stealing mode
+	 le?vperm	$in3,$in3,$in3,$leperm
+	 lvx_u		$in5,$x50,$inp
+	 addi		$inp,$inp,0x60
+	 le?vperm	$in4,$in4,$in4,$leperm
+	 le?vperm	$in5,$in5,$in5,$leperm
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	 vxor		$out0,$in0,$twk0
+	le?vperm	$out2,$out2,$out2,$leperm
+	stvx_u		$out1,$x10,$out
+	 vxor		$out1,$in1,$twk1
+	le?vperm	$out3,$out3,$out3,$leperm
+	stvx_u		$out2,$x20,$out
+	 vxor		$out2,$in2,$twk2
+	le?vperm	$out4,$out4,$out4,$leperm
+	stvx_u		$out3,$x30,$out
+	 vxor		$out3,$in3,$twk3
+	le?vperm	$out5,$tmp,$tmp,$leperm
+	stvx_u		$out4,$x40,$out
+	 vxor		$out4,$in4,$twk4
+	le?stvx_u	$out5,$x50,$out
+	be?stvx_u	$tmp, $x50,$out
+	 vxor		$out5,$in5,$twk5
+	addi		$out,$out,0x60
+
+	mtctr		$rounds
+	beq		Loop_xts_enc6x		# did $len-=96 borrow?
+
+	addic.		$len,$len,0x60
+	beq		Lxts_enc6x_zero
+	cmpwi		$len,0x20
+	blt		Lxts_enc6x_one
+	nop
+	beq		Lxts_enc6x_two
+	cmpwi		$len,0x40
+	blt		Lxts_enc6x_three
+	nop
+	beq		Lxts_enc6x_four
+
+Lxts_enc6x_five:
+	vxor		$out0,$in1,$twk0
+	vxor		$out1,$in2,$twk1
+	vxor		$out2,$in3,$twk2
+	vxor		$out3,$in4,$twk3
+	vxor		$out4,$in5,$twk4
+
+	bl		_aesp8_xts_enc5x
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	vmr		$twk0,$twk5		# unused tweak
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	le?vperm	$out2,$out2,$out2,$leperm
+	stvx_u		$out1,$x10,$out
+	le?vperm	$out3,$out3,$out3,$leperm
+	stvx_u		$out2,$x20,$out
+	vxor		$tmp,$out4,$twk5	# last block prep for stealing
+	le?vperm	$out4,$out4,$out4,$leperm
+	stvx_u		$out3,$x30,$out
+	stvx_u		$out4,$x40,$out
+	addi		$out,$out,0x50
+	bne		Lxts_enc6x_steal
+	b		Lxts_enc6x_done
+
+.align	4
+Lxts_enc6x_four:
+	vxor		$out0,$in2,$twk0
+	vxor		$out1,$in3,$twk1
+	vxor		$out2,$in4,$twk2
+	vxor		$out3,$in5,$twk3
+	vxor		$out4,$out4,$out4
+
+	bl		_aesp8_xts_enc5x
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	vmr		$twk0,$twk4		# unused tweak
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	le?vperm	$out2,$out2,$out2,$leperm
+	stvx_u		$out1,$x10,$out
+	vxor		$tmp,$out3,$twk4	# last block prep for stealing
+	le?vperm	$out3,$out3,$out3,$leperm
+	stvx_u		$out2,$x20,$out
+	stvx_u		$out3,$x30,$out
+	addi		$out,$out,0x40
+	bne		Lxts_enc6x_steal
+	b		Lxts_enc6x_done
+
+.align	4
+Lxts_enc6x_three:
+	vxor		$out0,$in3,$twk0
+	vxor		$out1,$in4,$twk1
+	vxor		$out2,$in5,$twk2
+	vxor		$out3,$out3,$out3
+	vxor		$out4,$out4,$out4
+
+	bl		_aesp8_xts_enc5x
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	vmr		$twk0,$twk3		# unused tweak
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	vxor		$tmp,$out2,$twk3	# last block prep for stealing
+	le?vperm	$out2,$out2,$out2,$leperm
+	stvx_u		$out1,$x10,$out
+	stvx_u		$out2,$x20,$out
+	addi		$out,$out,0x30
+	bne		Lxts_enc6x_steal
+	b		Lxts_enc6x_done
+
+.align	4
+Lxts_enc6x_two:
+	vxor		$out0,$in4,$twk0
+	vxor		$out1,$in5,$twk1
+	vxor		$out2,$out2,$out2
+	vxor		$out3,$out3,$out3
+	vxor		$out4,$out4,$out4
+
+	bl		_aesp8_xts_enc5x
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	vmr		$twk0,$twk2		# unused tweak
+	vxor		$tmp,$out1,$twk2	# last block prep for stealing
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	stvx_u		$out1,$x10,$out
+	addi		$out,$out,0x20
+	bne		Lxts_enc6x_steal
+	b		Lxts_enc6x_done
+
+.align	4
+Lxts_enc6x_one:
+	vxor		$out0,$in5,$twk0
+	nop
+Loop_xts_enc1x:
+	vcipher		$out0,$out0,v24
+	lvx		v24,$x20,$key_		# round[3]
+	addi		$key_,$key_,0x20
+
+	vcipher		$out0,$out0,v25
+	lvx		v25,$x10,$key_		# round[4]
+	bdnz		Loop_xts_enc1x
+
+	add		$inp,$inp,$taillen
+	cmpwi		$taillen,0
+	vcipher		$out0,$out0,v24
+
+	subi		$inp,$inp,16
+	vcipher		$out0,$out0,v25
+
+	lvsr		$inpperm,0,$taillen
+	vcipher		$out0,$out0,v26
+
+	lvx_u		$in0,0,$inp
+	vcipher		$out0,$out0,v27
+
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	vcipher		$out0,$out0,v28
+	lvx		v24,$x00,$key_		# re-pre-load round[1]
+
+	vcipher		$out0,$out0,v29
+	lvx		v25,$x10,$key_		# re-pre-load round[2]
+	 vxor		$twk0,$twk0,v31
+
+	le?vperm	$in0,$in0,$in0,$leperm
+	vcipher		$out0,$out0,v30
+
+	vperm		$in0,$in0,$in0,$inpperm
+	vcipherlast	$out0,$out0,$twk0
+
+	vmr		$twk0,$twk1		# unused tweak
+	vxor		$tmp,$out0,$twk1	# last block prep for stealing
+	le?vperm	$out0,$out0,$out0,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	addi		$out,$out,0x10
+	bne		Lxts_enc6x_steal
+	b		Lxts_enc6x_done
+
+.align	4
+Lxts_enc6x_zero:
+	cmpwi		$taillen,0
+	beq		Lxts_enc6x_done
+
+	add		$inp,$inp,$taillen
+	subi		$inp,$inp,16
+	lvx_u		$in0,0,$inp
+	lvsr		$inpperm,0,$taillen	# $in5 is no more
+	le?vperm	$in0,$in0,$in0,$leperm
+	vperm		$in0,$in0,$in0,$inpperm
+	vxor		$tmp,$tmp,$twk0
+Lxts_enc6x_steal:
+	vxor		$in0,$in0,$twk0
+	vxor		$out0,$out0,$out0
+	vspltisb	$out1,-1
+	vperm		$out0,$out0,$out1,$inpperm
+	vsel		$out0,$in0,$tmp,$out0	# $tmp is last block, remember?
+
+	subi		r30,$out,17
+	subi		$out,$out,16
+	mtctr		$taillen
+Loop_xts_enc6x_steal:
+	lbzu		r0,1(r30)
+	stb		r0,16(r30)
+	bdnz		Loop_xts_enc6x_steal
+
+	li		$taillen,0
+	mtctr		$rounds
+	b		Loop_xts_enc1x		# one more time...
+
+.align	4
+Lxts_enc6x_done:
+	${UCMP}i	$ivp,0
+	beq		Lxts_enc6x_ret
+
+	vxor		$tweak,$twk0,$rndkey0
+	le?vperm	$tweak,$tweak,$tweak,$leperm
+	stvx_u		$tweak,0,$ivp
+
+Lxts_enc6x_ret:
+	mtlr		r11
+	li		r10,`$FRAME+15`
+	li		r11,`$FRAME+31`
+	stvx		$seven,r10,$sp		# wipe copies of round keys
+	addi		r10,r10,32
+	stvx		$seven,r11,$sp
+	addi		r11,r11,32
+	stvx		$seven,r10,$sp
+	addi		r10,r10,32
+	stvx		$seven,r11,$sp
+	addi		r11,r11,32
+	stvx		$seven,r10,$sp
+	addi		r10,r10,32
+	stvx		$seven,r11,$sp
+	addi		r11,r11,32
+	stvx		$seven,r10,$sp
+	addi		r10,r10,32
+	stvx		$seven,r11,$sp
+	addi		r11,r11,32
+
+	mtspr		256,$vrsave
+	lvx		v20,r10,$sp		# ABI says so
+	addi		r10,r10,32
+	lvx		v21,r11,$sp
+	addi		r11,r11,32
+	lvx		v22,r10,$sp
+	addi		r10,r10,32
+	lvx		v23,r11,$sp
+	addi		r11,r11,32
+	lvx		v24,r10,$sp
+	addi		r10,r10,32
+	lvx		v25,r11,$sp
+	addi		r11,r11,32
+	lvx		v26,r10,$sp
+	addi		r10,r10,32
+	lvx		v27,r11,$sp
+	addi		r11,r11,32
+	lvx		v28,r10,$sp
+	addi		r10,r10,32
+	lvx		v29,r11,$sp
+	addi		r11,r11,32
+	lvx		v30,r10,$sp
+	lvx		v31,r11,$sp
+	$POP		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+	$POP		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+	$POP		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+	$POP		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+	$POP		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+	$POP		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+	addi		$sp,$sp,`$FRAME+21*16+6*$SIZE_T`
+	blr
+	.long		0
+	.byte		0,12,0x04,1,0x80,6,6,0
+	.long		0
+
+.align	5
+_aesp8_xts_enc5x:
+	vcipher		$out0,$out0,v24
+	vcipher		$out1,$out1,v24
+	vcipher		$out2,$out2,v24
+	vcipher		$out3,$out3,v24
+	vcipher		$out4,$out4,v24
+	lvx		v24,$x20,$key_		# round[3]
+	addi		$key_,$key_,0x20
+
+	vcipher		$out0,$out0,v25
+	vcipher		$out1,$out1,v25
+	vcipher		$out2,$out2,v25
+	vcipher		$out3,$out3,v25
+	vcipher		$out4,$out4,v25
+	lvx		v25,$x10,$key_		# round[4]
+	bdnz		_aesp8_xts_enc5x
+
+	add		$inp,$inp,$taillen
+	cmpwi		$taillen,0
+	vcipher		$out0,$out0,v24
+	vcipher		$out1,$out1,v24
+	vcipher		$out2,$out2,v24
+	vcipher		$out3,$out3,v24
+	vcipher		$out4,$out4,v24
+
+	subi		$inp,$inp,16
+	vcipher		$out0,$out0,v25
+	vcipher		$out1,$out1,v25
+	vcipher		$out2,$out2,v25
+	vcipher		$out3,$out3,v25
+	vcipher		$out4,$out4,v25
+	 vxor		$twk0,$twk0,v31
+
+	vcipher		$out0,$out0,v26
+	lvsr		$inpperm,r0,$taillen	# $in5 is no more
+	vcipher		$out1,$out1,v26
+	vcipher		$out2,$out2,v26
+	vcipher		$out3,$out3,v26
+	vcipher		$out4,$out4,v26
+	 vxor		$in1,$twk1,v31
+
+	vcipher		$out0,$out0,v27
+	lvx_u		$in0,0,$inp
+	vcipher		$out1,$out1,v27
+	vcipher		$out2,$out2,v27
+	vcipher		$out3,$out3,v27
+	vcipher		$out4,$out4,v27
+	 vxor		$in2,$twk2,v31
+
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	vcipher		$out0,$out0,v28
+	vcipher		$out1,$out1,v28
+	vcipher		$out2,$out2,v28
+	vcipher		$out3,$out3,v28
+	vcipher		$out4,$out4,v28
+	lvx		v24,$x00,$key_		# re-pre-load round[1]
+	 vxor		$in3,$twk3,v31
+
+	vcipher		$out0,$out0,v29
+	le?vperm	$in0,$in0,$in0,$leperm
+	vcipher		$out1,$out1,v29
+	vcipher		$out2,$out2,v29
+	vcipher		$out3,$out3,v29
+	vcipher		$out4,$out4,v29
+	lvx		v25,$x10,$key_		# re-pre-load round[2]
+	 vxor		$in4,$twk4,v31
+
+	vcipher		$out0,$out0,v30
+	vperm		$in0,$in0,$in0,$inpperm
+	vcipher		$out1,$out1,v30
+	vcipher		$out2,$out2,v30
+	vcipher		$out3,$out3,v30
+	vcipher		$out4,$out4,v30
+
+	vcipherlast	$out0,$out0,$twk0
+	vcipherlast	$out1,$out1,$in1
+	vcipherlast	$out2,$out2,$in2
+	vcipherlast	$out3,$out3,$in3
+	vcipherlast	$out4,$out4,$in4
+	blr
+        .long   	0
+        .byte   	0,12,0x14,0,0,0,0,0
+
+.align	5
+_aesp8_xts_decrypt6x:
+	$STU		$sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
+	mflr		r11
+	li		r7,`$FRAME+8*16+15`
+	li		r3,`$FRAME+8*16+31`
+	$PUSH		r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)
+	stvx		v20,r7,$sp		# ABI says so
+	addi		r7,r7,32
+	stvx		v21,r3,$sp
+	addi		r3,r3,32
+	stvx		v22,r7,$sp
+	addi		r7,r7,32
+	stvx		v23,r3,$sp
+	addi		r3,r3,32
+	stvx		v24,r7,$sp
+	addi		r7,r7,32
+	stvx		v25,r3,$sp
+	addi		r3,r3,32
+	stvx		v26,r7,$sp
+	addi		r7,r7,32
+	stvx		v27,r3,$sp
+	addi		r3,r3,32
+	stvx		v28,r7,$sp
+	addi		r7,r7,32
+	stvx		v29,r3,$sp
+	addi		r3,r3,32
+	stvx		v30,r7,$sp
+	stvx		v31,r3,$sp
+	li		r0,-1
+	stw		$vrsave,`$FRAME+21*16-4`($sp)	# save vrsave
+	li		$x10,0x10
+	$PUSH		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+	li		$x20,0x20
+	$PUSH		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+	li		$x30,0x30
+	$PUSH		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+	li		$x40,0x40
+	$PUSH		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+	li		$x50,0x50
+	$PUSH		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+	li		$x60,0x60
+	$PUSH		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+	li		$x70,0x70
+	mtspr		256,r0
+
+	subi		$rounds,$rounds,3	# -4 in total
+
+	lvx		$rndkey0,$x00,$key1	# load key schedule
+	lvx		v30,$x10,$key1
+	addi		$key1,$key1,0x20
+	lvx		v31,$x00,$key1
+	?vperm		$rndkey0,$rndkey0,v30,$keyperm
+	addi		$key_,$sp,$FRAME+15
+	mtctr		$rounds
+
+Load_xts_dec_key:
+	?vperm		v24,v30,v31,$keyperm
+	lvx		v30,$x10,$key1
+	addi		$key1,$key1,0x20
+	stvx		v24,$x00,$key_		# off-load round[1]
+	?vperm		v25,v31,v30,$keyperm
+	lvx		v31,$x00,$key1
+	stvx		v25,$x10,$key_		# off-load round[2]
+	addi		$key_,$key_,0x20
+	bdnz		Load_xts_dec_key
+
+	lvx		v26,$x10,$key1
+	?vperm		v24,v30,v31,$keyperm
+	lvx		v27,$x20,$key1
+	stvx		v24,$x00,$key_		# off-load round[3]
+	?vperm		v25,v31,v26,$keyperm
+	lvx		v28,$x30,$key1
+	stvx		v25,$x10,$key_		# off-load round[4]
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	?vperm		v26,v26,v27,$keyperm
+	lvx		v29,$x40,$key1
+	?vperm		v27,v27,v28,$keyperm
+	lvx		v30,$x50,$key1
+	?vperm		v28,v28,v29,$keyperm
+	lvx		v31,$x60,$key1
+	?vperm		v29,v29,v30,$keyperm
+	lvx		$twk5,$x70,$key1	# borrow $twk5
+	?vperm		v30,v30,v31,$keyperm
+	lvx		v24,$x00,$key_		# pre-load round[1]
+	?vperm		v31,v31,$twk5,$keyperm
+	lvx		v25,$x10,$key_		# pre-load round[2]
+
+	 vperm		$in0,$inout,$inptail,$inpperm
+	 subi		$inp,$inp,31		# undo "caller"
+	vxor		$twk0,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out0,$in0,$twk0
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in1,$x10,$inp
+	vxor		$twk1,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in1,$in1,$in1,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out1,$in1,$twk1
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in2,$x20,$inp
+	 andi.		$taillen,$len,15
+	vxor		$twk2,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in2,$in2,$in2,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out2,$in2,$twk2
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in3,$x30,$inp
+	 sub		$len,$len,$taillen
+	vxor		$twk3,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in3,$in3,$in3,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out3,$in3,$twk3
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in4,$x40,$inp
+	 subi		$len,$len,0x60
+	vxor		$twk4,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in4,$in4,$in4,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out4,$in4,$twk4
+	vxor		$tweak,$tweak,$tmp
+
+	 lvx_u		$in5,$x50,$inp
+	 addi		$inp,$inp,0x60
+	vxor		$twk5,$tweak,$rndkey0
+	vsrab		$tmp,$tweak,$seven	# next tweak value
+	vaddubm		$tweak,$tweak,$tweak
+	vsldoi		$tmp,$tmp,$tmp,15
+	 le?vperm	$in5,$in5,$in5,$leperm
+	vand		$tmp,$tmp,$eighty7
+	 vxor		$out5,$in5,$twk5
+	vxor		$tweak,$tweak,$tmp
+
+	vxor		v31,v31,$rndkey0
+	mtctr		$rounds
+	b		Loop_xts_dec6x
+
+.align	5
+Loop_xts_dec6x:
+	vncipher	$out0,$out0,v24
+	vncipher	$out1,$out1,v24
+	vncipher	$out2,$out2,v24
+	vncipher	$out3,$out3,v24
+	vncipher	$out4,$out4,v24
+	vncipher	$out5,$out5,v24
+	lvx		v24,$x20,$key_		# round[3]
+	addi		$key_,$key_,0x20
+
+	vncipher	$out0,$out0,v25
+	vncipher	$out1,$out1,v25
+	vncipher	$out2,$out2,v25
+	vncipher	$out3,$out3,v25
+	vncipher	$out4,$out4,v25
+	vncipher	$out5,$out5,v25
+	lvx		v25,$x10,$key_		# round[4]
+	bdnz		Loop_xts_dec6x
+
+	subic		$len,$len,96		# $len-=96
+	 vxor		$in0,$twk0,v31		# xor with last round key
+	vncipher	$out0,$out0,v24
+	vncipher	$out1,$out1,v24
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk0,$tweak,$rndkey0
+	 vaddubm	$tweak,$tweak,$tweak
+	vncipher	$out2,$out2,v24
+	vncipher	$out3,$out3,v24
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vncipher	$out4,$out4,v24
+	vncipher	$out5,$out5,v24
+
+	subfe.		r0,r0,r0		# borrow?-1:0
+	 vand		$tmp,$tmp,$eighty7
+	vncipher	$out0,$out0,v25
+	vncipher	$out1,$out1,v25
+	 vxor		$tweak,$tweak,$tmp
+	vncipher	$out2,$out2,v25
+	vncipher	$out3,$out3,v25
+	 vxor		$in1,$twk1,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk1,$tweak,$rndkey0
+	vncipher	$out4,$out4,v25
+	vncipher	$out5,$out5,v25
+
+	and		r0,r0,$len
+	 vaddubm	$tweak,$tweak,$tweak
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vncipher	$out0,$out0,v26
+	vncipher	$out1,$out1,v26
+	 vand		$tmp,$tmp,$eighty7
+	vncipher	$out2,$out2,v26
+	vncipher	$out3,$out3,v26
+	 vxor		$tweak,$tweak,$tmp
+	vncipher	$out4,$out4,v26
+	vncipher	$out5,$out5,v26
+
+	add		$inp,$inp,r0		# $inp is adjusted in such
+						# way that at exit from the
+						# loop inX-in5 are loaded
+						# with last "words"
+	 vxor		$in2,$twk2,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk2,$tweak,$rndkey0
+	 vaddubm	$tweak,$tweak,$tweak
+	vncipher	$out0,$out0,v27
+	vncipher	$out1,$out1,v27
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vncipher	$out2,$out2,v27
+	vncipher	$out3,$out3,v27
+	 vand		$tmp,$tmp,$eighty7
+	vncipher	$out4,$out4,v27
+	vncipher	$out5,$out5,v27
+
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	 vxor		$tweak,$tweak,$tmp
+	vncipher	$out0,$out0,v28
+	vncipher	$out1,$out1,v28
+	 vxor		$in3,$twk3,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk3,$tweak,$rndkey0
+	vncipher	$out2,$out2,v28
+	vncipher	$out3,$out3,v28
+	 vaddubm	$tweak,$tweak,$tweak
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vncipher	$out4,$out4,v28
+	vncipher	$out5,$out5,v28
+	lvx		v24,$x00,$key_		# re-pre-load round[1]
+	 vand		$tmp,$tmp,$eighty7
+
+	vncipher	$out0,$out0,v29
+	vncipher	$out1,$out1,v29
+	 vxor		$tweak,$tweak,$tmp
+	vncipher	$out2,$out2,v29
+	vncipher	$out3,$out3,v29
+	 vxor		$in4,$twk4,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk4,$tweak,$rndkey0
+	vncipher	$out4,$out4,v29
+	vncipher	$out5,$out5,v29
+	lvx		v25,$x10,$key_		# re-pre-load round[2]
+	 vaddubm	$tweak,$tweak,$tweak
+	 vsldoi		$tmp,$tmp,$tmp,15
+
+	vncipher	$out0,$out0,v30
+	vncipher	$out1,$out1,v30
+	 vand		$tmp,$tmp,$eighty7
+	vncipher	$out2,$out2,v30
+	vncipher	$out3,$out3,v30
+	 vxor		$tweak,$tweak,$tmp
+	vncipher	$out4,$out4,v30
+	vncipher	$out5,$out5,v30
+	 vxor		$in5,$twk5,v31
+	 vsrab		$tmp,$tweak,$seven	# next tweak value
+	 vxor		$twk5,$tweak,$rndkey0
+
+	vncipherlast	$out0,$out0,$in0
+	 lvx_u		$in0,$x00,$inp		# load next input block
+	 vaddubm	$tweak,$tweak,$tweak
+	 vsldoi		$tmp,$tmp,$tmp,15
+	vncipherlast	$out1,$out1,$in1
+	 lvx_u		$in1,$x10,$inp
+	vncipherlast	$out2,$out2,$in2
+	 le?vperm	$in0,$in0,$in0,$leperm
+	 lvx_u		$in2,$x20,$inp
+	 vand		$tmp,$tmp,$eighty7
+	vncipherlast	$out3,$out3,$in3
+	 le?vperm	$in1,$in1,$in1,$leperm
+	 lvx_u		$in3,$x30,$inp
+	vncipherlast	$out4,$out4,$in4
+	 le?vperm	$in2,$in2,$in2,$leperm
+	 lvx_u		$in4,$x40,$inp
+	 vxor		$tweak,$tweak,$tmp
+	vncipherlast	$out5,$out5,$in5
+	 le?vperm	$in3,$in3,$in3,$leperm
+	 lvx_u		$in5,$x50,$inp
+	 addi		$inp,$inp,0x60
+	 le?vperm	$in4,$in4,$in4,$leperm
+	 le?vperm	$in5,$in5,$in5,$leperm
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	 vxor		$out0,$in0,$twk0
+	le?vperm	$out2,$out2,$out2,$leperm
+	stvx_u		$out1,$x10,$out
+	 vxor		$out1,$in1,$twk1
+	le?vperm	$out3,$out3,$out3,$leperm
+	stvx_u		$out2,$x20,$out
+	 vxor		$out2,$in2,$twk2
+	le?vperm	$out4,$out4,$out4,$leperm
+	stvx_u		$out3,$x30,$out
+	 vxor		$out3,$in3,$twk3
+	le?vperm	$out5,$out5,$out5,$leperm
+	stvx_u		$out4,$x40,$out
+	 vxor		$out4,$in4,$twk4
+	stvx_u		$out5,$x50,$out
+	 vxor		$out5,$in5,$twk5
+	addi		$out,$out,0x60
+
+	mtctr		$rounds
+	beq		Loop_xts_dec6x		# did $len-=96 borrow?
+
+	addic.		$len,$len,0x60
+	beq		Lxts_dec6x_zero
+	cmpwi		$len,0x20
+	blt		Lxts_dec6x_one
+	nop
+	beq		Lxts_dec6x_two
+	cmpwi		$len,0x40
+	blt		Lxts_dec6x_three
+	nop
+	beq		Lxts_dec6x_four
+
+Lxts_dec6x_five:
+	vxor		$out0,$in1,$twk0
+	vxor		$out1,$in2,$twk1
+	vxor		$out2,$in3,$twk2
+	vxor		$out3,$in4,$twk3
+	vxor		$out4,$in5,$twk4
+
+	bl		_aesp8_xts_dec5x
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	vmr		$twk0,$twk5		# unused tweak
+	vxor		$twk1,$tweak,$rndkey0
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	vxor		$out0,$in0,$twk1
+	le?vperm	$out2,$out2,$out2,$leperm
+	stvx_u		$out1,$x10,$out
+	le?vperm	$out3,$out3,$out3,$leperm
+	stvx_u		$out2,$x20,$out
+	le?vperm	$out4,$out4,$out4,$leperm
+	stvx_u		$out3,$x30,$out
+	stvx_u		$out4,$x40,$out
+	addi		$out,$out,0x50
+	bne		Lxts_dec6x_steal
+	b		Lxts_dec6x_done
+
+.align	4
+Lxts_dec6x_four:
+	vxor		$out0,$in2,$twk0
+	vxor		$out1,$in3,$twk1
+	vxor		$out2,$in4,$twk2
+	vxor		$out3,$in5,$twk3
+	vxor		$out4,$out4,$out4
+
+	bl		_aesp8_xts_dec5x
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	vmr		$twk0,$twk4		# unused tweak
+	vmr		$twk1,$twk5
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	vxor		$out0,$in0,$twk5
+	le?vperm	$out2,$out2,$out2,$leperm
+	stvx_u		$out1,$x10,$out
+	le?vperm	$out3,$out3,$out3,$leperm
+	stvx_u		$out2,$x20,$out
+	stvx_u		$out3,$x30,$out
+	addi		$out,$out,0x40
+	bne		Lxts_dec6x_steal
+	b		Lxts_dec6x_done
+
+.align	4
+Lxts_dec6x_three:
+	vxor		$out0,$in3,$twk0
+	vxor		$out1,$in4,$twk1
+	vxor		$out2,$in5,$twk2
+	vxor		$out3,$out3,$out3
+	vxor		$out4,$out4,$out4
+
+	bl		_aesp8_xts_dec5x
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	vmr		$twk0,$twk3		# unused tweak
+	vmr		$twk1,$twk4
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	vxor		$out0,$in0,$twk4
+	le?vperm	$out2,$out2,$out2,$leperm
+	stvx_u		$out1,$x10,$out
+	stvx_u		$out2,$x20,$out
+	addi		$out,$out,0x30
+	bne		Lxts_dec6x_steal
+	b		Lxts_dec6x_done
+
+.align	4
+Lxts_dec6x_two:
+	vxor		$out0,$in4,$twk0
+	vxor		$out1,$in5,$twk1
+	vxor		$out2,$out2,$out2
+	vxor		$out3,$out3,$out3
+	vxor		$out4,$out4,$out4
+
+	bl		_aesp8_xts_dec5x
+
+	le?vperm	$out0,$out0,$out0,$leperm
+	vmr		$twk0,$twk2		# unused tweak
+	vmr		$twk1,$twk3
+	le?vperm	$out1,$out1,$out1,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	vxor		$out0,$in0,$twk3
+	stvx_u		$out1,$x10,$out
+	addi		$out,$out,0x20
+	bne		Lxts_dec6x_steal
+	b		Lxts_dec6x_done
+
+.align	4
+Lxts_dec6x_one:
+	vxor		$out0,$in5,$twk0
+	nop
+Loop_xts_dec1x:
+	vncipher	$out0,$out0,v24
+	lvx		v24,$x20,$key_		# round[3]
+	addi		$key_,$key_,0x20
+
+	vncipher	$out0,$out0,v25
+	lvx		v25,$x10,$key_		# round[4]
+	bdnz		Loop_xts_dec1x
+
+	subi		r0,$taillen,1
+	vncipher	$out0,$out0,v24
+
+	andi.		r0,r0,16
+	cmpwi		$taillen,0
+	vncipher	$out0,$out0,v25
+
+	sub		$inp,$inp,r0
+	vncipher	$out0,$out0,v26
+
+	lvx_u		$in0,0,$inp
+	vncipher	$out0,$out0,v27
+
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	vncipher	$out0,$out0,v28
+	lvx		v24,$x00,$key_		# re-pre-load round[1]
+
+	vncipher	$out0,$out0,v29
+	lvx		v25,$x10,$key_		# re-pre-load round[2]
+	 vxor		$twk0,$twk0,v31
+
+	le?vperm	$in0,$in0,$in0,$leperm
+	vncipher	$out0,$out0,v30
+
+	mtctr		$rounds
+	vncipherlast	$out0,$out0,$twk0
+
+	vmr		$twk0,$twk1		# unused tweak
+	vmr		$twk1,$twk2
+	le?vperm	$out0,$out0,$out0,$leperm
+	stvx_u		$out0,$x00,$out		# store output
+	addi		$out,$out,0x10
+	vxor		$out0,$in0,$twk2
+	bne		Lxts_dec6x_steal
+	b		Lxts_dec6x_done
+
+.align	4
+Lxts_dec6x_zero:
+	cmpwi		$taillen,0
+	beq		Lxts_dec6x_done
+
+	lvx_u		$in0,0,$inp
+	le?vperm	$in0,$in0,$in0,$leperm
+	vxor		$out0,$in0,$twk1
+Lxts_dec6x_steal:
+	vncipher	$out0,$out0,v24
+	lvx		v24,$x20,$key_		# round[3]
+	addi		$key_,$key_,0x20
+
+	vncipher	$out0,$out0,v25
+	lvx		v25,$x10,$key_		# round[4]
+	bdnz		Lxts_dec6x_steal
+
+	add		$inp,$inp,$taillen
+	vncipher	$out0,$out0,v24
+
+	cmpwi		$taillen,0
+	vncipher	$out0,$out0,v25
+
+	lvx_u		$in0,0,$inp
+	vncipher	$out0,$out0,v26
+
+	lvsr		$inpperm,0,$taillen	# $in5 is no more
+	vncipher	$out0,$out0,v27
+
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	vncipher	$out0,$out0,v28
+	lvx		v24,$x00,$key_		# re-pre-load round[1]
+
+	vncipher	$out0,$out0,v29
+	lvx		v25,$x10,$key_		# re-pre-load round[2]
+	 vxor		$twk1,$twk1,v31
+
+	le?vperm	$in0,$in0,$in0,$leperm
+	vncipher	$out0,$out0,v30
+
+	vperm		$in0,$in0,$in0,$inpperm
+	vncipherlast	$tmp,$out0,$twk1
+
+	le?vperm	$out0,$tmp,$tmp,$leperm
+	le?stvx_u	$out0,0,$out
+	be?stvx_u	$tmp,0,$out
+
+	vxor		$out0,$out0,$out0
+	vspltisb	$out1,-1
+	vperm		$out0,$out0,$out1,$inpperm
+	vsel		$out0,$in0,$tmp,$out0
+	vxor		$out0,$out0,$twk0
+
+	subi		r30,$out,1
+	mtctr		$taillen
+Loop_xts_dec6x_steal:
+	lbzu		r0,1(r30)
+	stb		r0,16(r30)
+	bdnz		Loop_xts_dec6x_steal
+
+	li		$taillen,0
+	mtctr		$rounds
+	b		Loop_xts_dec1x		# one more time...
+
+.align	4
+Lxts_dec6x_done:
+	${UCMP}i	$ivp,0
+	beq		Lxts_dec6x_ret
+
+	vxor		$tweak,$twk0,$rndkey0
+	le?vperm	$tweak,$tweak,$tweak,$leperm
+	stvx_u		$tweak,0,$ivp
+
+Lxts_dec6x_ret:
+	mtlr		r11
+	li		r10,`$FRAME+15`
+	li		r11,`$FRAME+31`
+	stvx		$seven,r10,$sp		# wipe copies of round keys
+	addi		r10,r10,32
+	stvx		$seven,r11,$sp
+	addi		r11,r11,32
+	stvx		$seven,r10,$sp
+	addi		r10,r10,32
+	stvx		$seven,r11,$sp
+	addi		r11,r11,32
+	stvx		$seven,r10,$sp
+	addi		r10,r10,32
+	stvx		$seven,r11,$sp
+	addi		r11,r11,32
+	stvx		$seven,r10,$sp
+	addi		r10,r10,32
+	stvx		$seven,r11,$sp
+	addi		r11,r11,32
+
+	mtspr		256,$vrsave
+	lvx		v20,r10,$sp		# ABI says so
+	addi		r10,r10,32
+	lvx		v21,r11,$sp
+	addi		r11,r11,32
+	lvx		v22,r10,$sp
+	addi		r10,r10,32
+	lvx		v23,r11,$sp
+	addi		r11,r11,32
+	lvx		v24,r10,$sp
+	addi		r10,r10,32
+	lvx		v25,r11,$sp
+	addi		r11,r11,32
+	lvx		v26,r10,$sp
+	addi		r10,r10,32
+	lvx		v27,r11,$sp
+	addi		r11,r11,32
+	lvx		v28,r10,$sp
+	addi		r10,r10,32
+	lvx		v29,r11,$sp
+	addi		r11,r11,32
+	lvx		v30,r10,$sp
+	lvx		v31,r11,$sp
+	$POP		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+	$POP		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+	$POP		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+	$POP		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+	$POP		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+	$POP		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+	addi		$sp,$sp,`$FRAME+21*16+6*$SIZE_T`
+	blr
+	.long		0
+	.byte		0,12,0x04,1,0x80,6,6,0
+	.long		0
+
+.align	5
+_aesp8_xts_dec5x:
+	vncipher	$out0,$out0,v24
+	vncipher	$out1,$out1,v24
+	vncipher	$out2,$out2,v24
+	vncipher	$out3,$out3,v24
+	vncipher	$out4,$out4,v24
+	lvx		v24,$x20,$key_		# round[3]
+	addi		$key_,$key_,0x20
+
+	vncipher	$out0,$out0,v25
+	vncipher	$out1,$out1,v25
+	vncipher	$out2,$out2,v25
+	vncipher	$out3,$out3,v25
+	vncipher	$out4,$out4,v25
+	lvx		v25,$x10,$key_		# round[4]
+	bdnz		_aesp8_xts_dec5x
+
+	subi		r0,$taillen,1
+	vncipher	$out0,$out0,v24
+	vncipher	$out1,$out1,v24
+	vncipher	$out2,$out2,v24
+	vncipher	$out3,$out3,v24
+	vncipher	$out4,$out4,v24
+
+	andi.		r0,r0,16
+	cmpwi		$taillen,0
+	vncipher	$out0,$out0,v25
+	vncipher	$out1,$out1,v25
+	vncipher	$out2,$out2,v25
+	vncipher	$out3,$out3,v25
+	vncipher	$out4,$out4,v25
+	 vxor		$twk0,$twk0,v31
+
+	sub		$inp,$inp,r0
+	vncipher	$out0,$out0,v26
+	vncipher	$out1,$out1,v26
+	vncipher	$out2,$out2,v26
+	vncipher	$out3,$out3,v26
+	vncipher	$out4,$out4,v26
+	 vxor		$in1,$twk1,v31
+
+	vncipher	$out0,$out0,v27
+	lvx_u		$in0,0,$inp
+	vncipher	$out1,$out1,v27
+	vncipher	$out2,$out2,v27
+	vncipher	$out3,$out3,v27
+	vncipher	$out4,$out4,v27
+	 vxor		$in2,$twk2,v31
+
+	addi		$key_,$sp,$FRAME+15	# rewind $key_
+	vncipher	$out0,$out0,v28
+	vncipher	$out1,$out1,v28
+	vncipher	$out2,$out2,v28
+	vncipher	$out3,$out3,v28
+	vncipher	$out4,$out4,v28
+	lvx		v24,$x00,$key_		# re-pre-load round[1]
+	 vxor		$in3,$twk3,v31
+
+	vncipher	$out0,$out0,v29
+	le?vperm	$in0,$in0,$in0,$leperm
+	vncipher	$out1,$out1,v29
+	vncipher	$out2,$out2,v29
+	vncipher	$out3,$out3,v29
+	vncipher	$out4,$out4,v29
+	lvx		v25,$x10,$key_		# re-pre-load round[2]
+	 vxor		$in4,$twk4,v31
+
+	vncipher	$out0,$out0,v30
+	vncipher	$out1,$out1,v30
+	vncipher	$out2,$out2,v30
+	vncipher	$out3,$out3,v30
+	vncipher	$out4,$out4,v30
+
+	vncipherlast	$out0,$out0,$twk0
+	vncipherlast	$out1,$out1,$in1
+	vncipherlast	$out2,$out2,$in2
+	vncipherlast	$out3,$out3,$in3
+	vncipherlast	$out4,$out4,$in4
+	mtctr		$rounds
+	blr
+        .long   	0
+        .byte   	0,12,0x14,0,0,0,0,0
+___
+}}	}}}
+
 my $consts=1;
 foreach(split("\n",$code)) {
         s/\`([^\`]*)\`/eval($1)/geo;
@@ -1898,7 +3757,7 @@
 	    if ($flavour =~ /le$/o) {
 		SWITCH: for($conv)  {
 		    /\?inv/ && do   { @bytes=map($_^0xf,@bytes); last; };
-		    /\?rev/ && do   { @bytes=reverse(@bytes);    last; }; 
+		    /\?rev/ && do   { @bytes=reverse(@bytes);    last; };
 		}
 	    }
 
--- linux-4.4.0.orig/drivers/crypto/vmx/ghash.c
+++ linux-4.4.0/drivers/crypto/vmx/ghash.c
@@ -1,22 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
 /**
  * GHASH routines supporting VMX instructions on the Power 8
  *
- * Copyright (C) 2015 International Business Machines 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 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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.
+ * Copyright (C) 2015, 2019 International Business Machines Inc.
  *
  * Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com>
+ *
+ * Extended by Daniel Axtens <dja@axtens.net> to replace the fallback
+ * mechanism. The new approach is based on arm64 code, which is:
+ *   Copyright (C) 2014 - 2018 Linaro Ltd. <ard.biesheuvel@linaro.org>
  */
 
 #include <linux/types.h>
@@ -26,86 +18,38 @@
 #include <linux/hardirq.h>
 #include <asm/switch_to.h>
 #include <crypto/aes.h>
+#include <crypto/ghash.h>
 #include <crypto/scatterwalk.h>
 #include <crypto/internal/hash.h>
 #include <crypto/b128ops.h>
 
 #define IN_INTERRUPT in_interrupt()
 
-#define GHASH_BLOCK_SIZE (16)
-#define GHASH_DIGEST_SIZE (16)
-#define GHASH_KEY_LEN (16)
-
 void gcm_init_p8(u128 htable[16], const u64 Xi[2]);
 void gcm_gmult_p8(u64 Xi[2], const u128 htable[16]);
 void gcm_ghash_p8(u64 Xi[2], const u128 htable[16],
 		  const u8 *in, size_t len);
 
 struct p8_ghash_ctx {
+	/* key used by vector asm */
 	u128 htable[16];
-	struct crypto_shash *fallback;
+	/* key used by software fallback */
+	be128 key;
 };
 
 struct p8_ghash_desc_ctx {
 	u64 shash[2];
 	u8 buffer[GHASH_DIGEST_SIZE];
 	int bytes;
-	struct shash_desc fallback_desc;
 };
 
-static int p8_ghash_init_tfm(struct crypto_tfm *tfm)
-{
-	const char *alg;
-	struct crypto_shash *fallback;
-	struct crypto_shash *shash_tfm = __crypto_shash_cast(tfm);
-	struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
-
-	if (!(alg = crypto_tfm_alg_name(tfm))) {
-		printk(KERN_ERR "Failed to get algorithm name.\n");
-		return -ENOENT;
-	}
-
-	fallback = crypto_alloc_shash(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
-	if (IS_ERR(fallback)) {
-		printk(KERN_ERR
-		       "Failed to allocate transformation for '%s': %ld\n",
-		       alg, PTR_ERR(fallback));
-		return PTR_ERR(fallback);
-	}
-	printk(KERN_INFO "Using '%s' as fallback implementation.\n",
-	       crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback)));
-
-	crypto_shash_set_flags(fallback,
-			       crypto_shash_get_flags((struct crypto_shash
-						       *) tfm));
-	ctx->fallback = fallback;
-
-	shash_tfm->descsize = sizeof(struct p8_ghash_desc_ctx)
-	    + crypto_shash_descsize(fallback);
-
-	return 0;
-}
-
-static void p8_ghash_exit_tfm(struct crypto_tfm *tfm)
-{
-	struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
-
-	if (ctx->fallback) {
-		crypto_free_shash(ctx->fallback);
-		ctx->fallback = NULL;
-	}
-}
-
 static int p8_ghash_init(struct shash_desc *desc)
 {
-	struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
 	struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 
 	dctx->bytes = 0;
 	memset(dctx->shash, 0, GHASH_DIGEST_SIZE);
-	dctx->fallback_desc.tfm = ctx->fallback;
-	dctx->fallback_desc.flags = desc->flags;
-	return crypto_shash_init(&dctx->fallback_desc);
+	return 0;
 }
 
 static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
@@ -113,18 +57,63 @@
 {
 	struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(tfm));
 
-	if (keylen != GHASH_KEY_LEN)
+	if (keylen != GHASH_BLOCK_SIZE)
 		return -EINVAL;
 
 	preempt_disable();
 	pagefault_disable();
-	enable_kernel_altivec();
 	enable_kernel_vsx();
-	enable_kernel_fp();
 	gcm_init_p8(ctx->htable, (const u64 *) key);
+	disable_kernel_vsx();
 	pagefault_enable();
 	preempt_enable();
-	return crypto_shash_setkey(ctx->fallback, key, keylen);
+
+	memcpy(&ctx->key, key, GHASH_BLOCK_SIZE);
+
+	return 0;
+}
+
+static inline void __ghash_block(struct p8_ghash_ctx *ctx,
+				 struct p8_ghash_desc_ctx *dctx)
+{
+	if (!IN_INTERRUPT) {
+		preempt_disable();
+		pagefault_disable();
+		enable_kernel_altivec();
+		enable_kernel_vsx();
+		enable_kernel_fp();
+		gcm_ghash_p8(dctx->shash, ctx->htable,
+				dctx->buffer, GHASH_DIGEST_SIZE);
+		pagefault_enable();
+		preempt_enable();
+	} else {
+		crypto_xor((u8 *)dctx->shash, dctx->buffer, GHASH_BLOCK_SIZE);
+		gf128mul_lle((be128 *)dctx->shash, &ctx->key);
+	}
+}
+
+static inline void __ghash_blocks(struct p8_ghash_ctx *ctx,
+				  struct p8_ghash_desc_ctx *dctx,
+				  const u8 *src, unsigned int srclen)
+{
+	if (!IN_INTERRUPT) {
+		preempt_disable();
+		pagefault_disable();
+		enable_kernel_altivec();
+		enable_kernel_vsx();
+		enable_kernel_fp();
+		gcm_ghash_p8(dctx->shash, ctx->htable,
+				src, srclen);
+		pagefault_enable();
+		preempt_enable();
+	} else {
+		while (srclen >= GHASH_BLOCK_SIZE) {
+			crypto_xor((u8 *)dctx->shash, src, GHASH_BLOCK_SIZE);
+			gf128mul_lle((be128 *)dctx->shash, &ctx->key);
+			srclen -= GHASH_BLOCK_SIZE;
+			src += GHASH_BLOCK_SIZE;
+		}
+	}
 }
 
 static int p8_ghash_update(struct shash_desc *desc,
@@ -134,51 +123,33 @@
 	struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
 	struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 
-	if (IN_INTERRUPT) {
-		return crypto_shash_update(&dctx->fallback_desc, src,
-					   srclen);
-	} else {
-		if (dctx->bytes) {
-			if (dctx->bytes + srclen < GHASH_DIGEST_SIZE) {
-				memcpy(dctx->buffer + dctx->bytes, src,
-				       srclen);
-				dctx->bytes += srclen;
-				return 0;
-			}
+	if (dctx->bytes) {
+		if (dctx->bytes + srclen < GHASH_DIGEST_SIZE) {
 			memcpy(dctx->buffer + dctx->bytes, src,
-			       GHASH_DIGEST_SIZE - dctx->bytes);
-			preempt_disable();
-			pagefault_disable();
-			enable_kernel_altivec();
-			enable_kernel_vsx();
-			enable_kernel_fp();
-			gcm_ghash_p8(dctx->shash, ctx->htable,
-				     dctx->buffer, GHASH_DIGEST_SIZE);
-			pagefault_enable();
-			preempt_enable();
-			src += GHASH_DIGEST_SIZE - dctx->bytes;
-			srclen -= GHASH_DIGEST_SIZE - dctx->bytes;
-			dctx->bytes = 0;
+				srclen);
+			dctx->bytes += srclen;
+			return 0;
 		}
-		len = srclen & ~(GHASH_DIGEST_SIZE - 1);
-		if (len) {
-			preempt_disable();
-			pagefault_disable();
-			enable_kernel_altivec();
-			enable_kernel_vsx();
-			enable_kernel_fp();
-			gcm_ghash_p8(dctx->shash, ctx->htable, src, len);
-			pagefault_enable();
-			preempt_enable();
-			src += len;
-			srclen -= len;
-		}
-		if (srclen) {
-			memcpy(dctx->buffer, src, srclen);
-			dctx->bytes = srclen;
-		}
-		return 0;
+		memcpy(dctx->buffer + dctx->bytes, src,
+			GHASH_DIGEST_SIZE - dctx->bytes);
+
+		__ghash_block(ctx, dctx);
+
+		src += GHASH_DIGEST_SIZE - dctx->bytes;
+		srclen -= GHASH_DIGEST_SIZE - dctx->bytes;
+		dctx->bytes = 0;
+	}
+	len = srclen & ~(GHASH_DIGEST_SIZE - 1);
+	if (len) {
+		__ghash_blocks(ctx, dctx, src, len);
+		src += len;
+		srclen -= len;
 	}
+	if (srclen) {
+		memcpy(dctx->buffer, src, srclen);
+		dctx->bytes = srclen;
+	}
+	return 0;
 }
 
 static int p8_ghash_final(struct shash_desc *desc, u8 *out)
@@ -187,26 +158,14 @@
 	struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
 	struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 
-	if (IN_INTERRUPT) {
-		return crypto_shash_final(&dctx->fallback_desc, out);
-	} else {
-		if (dctx->bytes) {
-			for (i = dctx->bytes; i < GHASH_DIGEST_SIZE; i++)
-				dctx->buffer[i] = 0;
-			preempt_disable();
-			pagefault_disable();
-			enable_kernel_altivec();
-			enable_kernel_vsx();
-			enable_kernel_fp();
-			gcm_ghash_p8(dctx->shash, ctx->htable,
-				     dctx->buffer, GHASH_DIGEST_SIZE);
-			pagefault_enable();
-			preempt_enable();
-			dctx->bytes = 0;
-		}
-		memcpy(out, dctx->shash, GHASH_DIGEST_SIZE);
-		return 0;
+	if (dctx->bytes) {
+		for (i = dctx->bytes; i < GHASH_DIGEST_SIZE; i++)
+			dctx->buffer[i] = 0;
+		__ghash_block(ctx, dctx);
+		dctx->bytes = 0;
 	}
+	memcpy(out, dctx->shash, GHASH_DIGEST_SIZE);
+	return 0;
 }
 
 struct shash_alg p8_ghash_alg = {
@@ -215,16 +174,15 @@
 	.update = p8_ghash_update,
 	.final = p8_ghash_final,
 	.setkey = p8_ghash_setkey,
-	.descsize = sizeof(struct p8_ghash_desc_ctx),
+	.descsize = sizeof(struct p8_ghash_desc_ctx)
+		+ sizeof(struct ghash_desc_ctx),
 	.base = {
 		 .cra_name = "ghash",
 		 .cra_driver_name = "p8_ghash",
 		 .cra_priority = 1000,
-		 .cra_flags = CRYPTO_ALG_TYPE_SHASH | CRYPTO_ALG_NEED_FALLBACK,
+		 .cra_flags = CRYPTO_ALG_TYPE_SHASH,
 		 .cra_blocksize = GHASH_BLOCK_SIZE,
 		 .cra_ctxsize = sizeof(struct p8_ghash_ctx),
 		 .cra_module = THIS_MODULE,
-		 .cra_init = p8_ghash_init_tfm,
-		 .cra_exit = p8_ghash_exit_tfm,
 	},
 };
--- linux-4.4.0.orig/drivers/crypto/vmx/ppc-xlate.pl
+++ linux-4.4.0/drivers/crypto/vmx/ppc-xlate.pl
@@ -139,6 +139,26 @@
     "	vor	$vx,$vy,$vy";
 };
 
+# Some ABIs specify vrsave, special-purpose register #256, as reserved
+# for system use.
+my $no_vrsave = ($flavour =~ /linux-ppc64le/);
+my $mtspr = sub {
+    my ($f,$idx,$ra) = @_;
+    if ($idx == 256 && $no_vrsave) {
+	"	or	$ra,$ra,$ra";
+    } else {
+	"	mtspr	$idx,$ra";
+    }
+};
+my $mfspr = sub {
+    my ($f,$rd,$idx) = @_;
+    if ($idx == 256 && $no_vrsave) {
+	"	li	$rd,-1";
+    } else {
+	"	mfspr	$rd,$idx";
+    }
+};
+
 # PowerISA 2.06 stuff
 sub vsxmem_op {
     my ($f, $vrt, $ra, $rb, $op) = @_;
--- linux-4.4.0.orig/drivers/crypto/vmx/vmx.c
+++ linux-4.4.0/drivers/crypto/vmx/vmx.c
@@ -23,6 +23,7 @@
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/err.h>
+#include <linux/cpufeature.h>
 #include <linux/crypto.h>
 #include <asm/cputable.h>
 #include <crypto/internal/hash.h>
@@ -31,10 +32,12 @@
 extern struct crypto_alg p8_aes_alg;
 extern struct crypto_alg p8_aes_cbc_alg;
 extern struct crypto_alg p8_aes_ctr_alg;
+extern struct crypto_alg p8_aes_xts_alg;
 static struct crypto_alg *algs[] = {
 	&p8_aes_alg,
 	&p8_aes_cbc_alg,
 	&p8_aes_ctr_alg,
+	&p8_aes_xts_alg,
 	NULL,
 };
 
@@ -43,9 +46,6 @@
 	int ret = 0;
 	struct crypto_alg **alg_it;
 
-	if (!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_VEC_CRYPTO))
-		return -ENODEV;
-
 	for (alg_it = algs; *alg_it; alg_it++) {
 		ret = crypto_register_alg(*alg_it);
 		printk(KERN_INFO "crypto_register_alg '%s' = %d\n",
@@ -78,7 +78,7 @@
 	crypto_unregister_shash(&p8_ghash_alg);
 }
 
-module_init(p8_init);
+module_cpu_feature_match(PPC_MODULE_FEATURE_VEC_CRYPTO, p8_init);
 module_exit(p8_exit);
 
 MODULE_AUTHOR("Marcelo Cerri<mhcerri@br.ibm.com>");
--- linux-4.4.0.orig/drivers/devfreq/devfreq.c
+++ linux-4.4.0/drivers/devfreq/devfreq.c
@@ -396,11 +396,6 @@
 static void _remove_devfreq(struct devfreq *devfreq)
 {
 	mutex_lock(&devfreq_list_lock);
-	if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
-		mutex_unlock(&devfreq_list_lock);
-		dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n");
-		return;
-	}
 	list_del(&devfreq->node);
 	mutex_unlock(&devfreq_list_lock);
 
@@ -472,6 +467,7 @@
 	devfreq->dev.parent = dev;
 	devfreq->dev.class = devfreq_class;
 	devfreq->dev.release = devfreq_dev_release;
+	INIT_LIST_HEAD(&devfreq->node);
 	devfreq->profile = profile;
 	strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
 	devfreq->previous_freq = profile->initial_freq;
@@ -583,7 +579,7 @@
 	devfreq = devfreq_add_device(dev, profile, governor_name, data);
 	if (IS_ERR(devfreq)) {
 		devres_free(ptr);
-		return ERR_PTR(-ENOMEM);
+		return devfreq;
 	}
 
 	*ptr = devfreq;
@@ -998,7 +994,7 @@
 			       struct device_attribute *attr, char *buf)
 {
 	struct devfreq *devfreq = to_devfreq(dev);
-	ssize_t len;
+	ssize_t len = 0;
 	int i, j;
 	unsigned int max_state = devfreq->profile->max_state;
 
@@ -1006,32 +1002,53 @@
 			devfreq_update_status(devfreq, devfreq->previous_freq))
 		return 0;
 
-	len = sprintf(buf, "   From  :   To\n");
-	len += sprintf(buf + len, "         :");
-	for (i = 0; i < max_state; i++)
-		len += sprintf(buf + len, "%8u",
+	len += scnprintf(buf + len, PAGE_SIZE - len, "     From  :   To\n");
+	len += scnprintf(buf + len, PAGE_SIZE - len, "           :");
+	for (i = 0; i < max_state; i++) {
+		if (len >= PAGE_SIZE - 1)
+			break;
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%8u",
 				devfreq->profile->freq_table[i]);
+	}
+	if (len >= PAGE_SIZE - 1)
+		return PAGE_SIZE - 1;
 
-	len += sprintf(buf + len, "   time(ms)\n");
+	len += scnprintf(buf + len, PAGE_SIZE - len, "   time(ms)\n");
 
 	for (i = 0; i < max_state; i++) {
+		if (len >= PAGE_SIZE - 1)
+			break;
 		if (devfreq->profile->freq_table[i]
 					== devfreq->previous_freq) {
-			len += sprintf(buf + len, "*");
+			len += scnprintf(buf + len, PAGE_SIZE - len, "*");
 		} else {
-			len += sprintf(buf + len, " ");
+			len += scnprintf(buf + len, PAGE_SIZE - len, " ");
 		}
-		len += sprintf(buf + len, "%8u:",
+		if (len >= PAGE_SIZE - 1)
+			break;
+
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%8u:",
 				devfreq->profile->freq_table[i]);
-		for (j = 0; j < max_state; j++)
-			len += sprintf(buf + len, "%8u",
+		for (j = 0; j < max_state; j++) {
+			if (len >= PAGE_SIZE - 1)
+				break;
+			len += scnprintf(buf + len, PAGE_SIZE - len, "%8u",
 				devfreq->trans_table[(i * max_state) + j]);
-		len += sprintf(buf + len, "%10u\n",
+		}
+		if (len >= PAGE_SIZE - 1)
+			break;
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%10u\n",
 			jiffies_to_msecs(devfreq->time_in_state[i]));
 	}
+	if (len < PAGE_SIZE - 1)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "Total transition : %u\n",
+				 devfreq->total_trans);
+
+	if (len >= PAGE_SIZE - 1) {
+		pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n");
+		return -EFBIG;
+	}
 
-	len += sprintf(buf + len, "Total transition : %u\n",
-					devfreq->total_trans);
 	return len;
 }
 static DEVICE_ATTR_RO(trans_stat);
--- linux-4.4.0.orig/drivers/devfreq/tegra-devfreq.c
+++ linux-4.4.0/drivers/devfreq/tegra-devfreq.c
@@ -79,6 +79,8 @@
 
 #define KHZ							1000
 
+#define KHZ_MAX						(ULONG_MAX / KHZ)
+
 /* Assume that the bus is saturated if the utilization is 25% */
 #define BUS_SATURATION_RATIO					25
 
@@ -179,7 +181,7 @@
 };
 
 static struct tegra_actmon_emc_ratio actmon_emc_ratios[] = {
-	{ 1400000, ULONG_MAX },
+	{ 1400000,    KHZ_MAX },
 	{ 1200000,    750000 },
 	{ 1100000,    600000 },
 	{ 1000000,    500000 },
@@ -688,9 +690,9 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
-		dev_err(&pdev->dev, "Failed to get IRQ\n");
-		return -ENODEV;
+	if (irq < 0) {
+		dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
+		return irq;
 	}
 
 	platform_set_drvdata(pdev, tegra);
--- linux-4.4.0.orig/drivers/dma/at_hdmac.c
+++ linux-4.4.0/drivers/dma/at_hdmac.c
@@ -716,7 +716,7 @@
 			 unsigned long flags)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
-	struct data_chunk	*first = xt->sgl;
+	struct data_chunk	*first;
 	struct at_desc		*desc = NULL;
 	size_t			xfer_count;
 	unsigned int		dwidth;
@@ -728,6 +728,8 @@
 	if (unlikely(!xt || xt->numf != 1 || !xt->frame_size))
 		return NULL;
 
+	first = xt->sgl;
+
 	dev_info(chan2dev(chan),
 		 "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
 		__func__, &xt->src_start, &xt->dst_start, xt->numf,
@@ -1779,6 +1781,12 @@
 	atchan->descs_allocated = 0;
 	atchan->status = 0;
 
+	/*
+	 * Free atslave allocated in at_dma_xlate()
+	 */
+	kfree(chan->private);
+	chan->private = NULL;
+
 	dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
 }
 
@@ -1809,11 +1817,13 @@
 		return NULL;
 
 	dmac_pdev = of_find_device_by_node(dma_spec->np);
+	if (!dmac_pdev)
+		return NULL;
 
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
 
-	atslave = devm_kzalloc(&dmac_pdev->dev, sizeof(*atslave), GFP_KERNEL);
+	atslave = kzalloc(sizeof(*atslave), GFP_KERNEL);
 	if (!atslave)
 		return NULL;
 
@@ -2144,6 +2154,8 @@
 	struct resource		*io;
 
 	at_dma_off(atdma);
+	if (pdev->dev.of_node)
+		of_dma_controller_free(pdev->dev.of_node);
 	dma_async_device_unregister(&atdma->dma_common);
 
 	dma_pool_destroy(atdma->memset_pool);
--- linux-4.4.0.orig/drivers/dma/at_xdmac.c
+++ linux-4.4.0/drivers/dma/at_xdmac.c
@@ -176,6 +176,7 @@
 #define AT_XDMAC_MAX_CHAN	0x20
 #define AT_XDMAC_MAX_CSIZE	16	/* 16 data */
 #define AT_XDMAC_MAX_DWIDTH	8	/* 64 bits */
+#define AT_XDMAC_RESIDUE_MAX_RETRIES	5
 
 #define AT_XDMAC_DMA_BUSWIDTHS\
 	(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
@@ -202,6 +203,7 @@
 	u32				save_cim;
 	u32				save_cnda;
 	u32				save_cndc;
+	u32				irq_status;
 	unsigned long			status;
 	struct tasklet_struct		tasklet;
 	struct dma_slave_config		sconfig;
@@ -241,7 +243,7 @@
 	u32		mbr_dus;	/* Destination Microblock Stride Register */
 };
 
-
+/* 64-bit alignment needed to update CNDA and CUBC registers in an atomic way. */
 struct at_xdmac_desc {
 	struct at_xdmac_lld		lld;
 	enum dma_transfer_direction	direction;
@@ -252,7 +254,7 @@
 	unsigned int			xfer_size;
 	struct list_head		descs_list;
 	struct list_head		xfer_node;
-};
+} __aligned(sizeof(u64));
 
 static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, unsigned int chan_nb)
 {
@@ -863,8 +865,12 @@
 	 * access. Hopefully we can access DDR through both ports (at least on
 	 * SAMA5D4x), so we can use the same interface for source and dest,
 	 * that solves the fact we don't know the direction.
+	 * ERRATA: Even if useless for memory transfers, the PERID has to not
+	 * match the one of another channel. If not, it could lead to spurious
+	 * flag status.
 	 */
-	u32			chan_cc = AT_XDMAC_CC_DIF(0)
+	u32			chan_cc = AT_XDMAC_CC_PERID(0x3f)
+					| AT_XDMAC_CC_DIF(0)
 					| AT_XDMAC_CC_SIF(0)
 					| AT_XDMAC_CC_MBSIZE_SIXTEEN
 					| AT_XDMAC_CC_TYPE_MEM_TRAN;
@@ -1041,8 +1047,12 @@
 	 * access DDR through both ports (at least on SAMA5D4x), so we can use
 	 * the same interface for source and dest, that solves the fact we
 	 * don't know the direction.
+	 * ERRATA: Even if useless for memory transfers, the PERID has to not
+	 * match the one of another channel. If not, it could lead to spurious
+	 * flag status.
 	 */
-	u32			chan_cc = AT_XDMAC_CC_DAM_INCREMENTED_AM
+	u32			chan_cc = AT_XDMAC_CC_PERID(0x3f)
+					| AT_XDMAC_CC_DAM_INCREMENTED_AM
 					| AT_XDMAC_CC_SAM_INCREMENTED_AM
 					| AT_XDMAC_CC_DIF(0)
 					| AT_XDMAC_CC_SIF(0)
@@ -1143,8 +1153,12 @@
 	 * access. Hopefully we can access DDR through both ports (at least on
 	 * SAMA5D4x), so we can use the same interface for source and dest,
 	 * that solves the fact we don't know the direction.
+	 * ERRATA: Even if useless for memory transfers, the PERID has to not
+	 * match the one of another channel. If not, it could lead to spurious
+	 * flag status.
 	 */
-	u32			chan_cc = AT_XDMAC_CC_DAM_UBS_AM
+	u32			chan_cc = AT_XDMAC_CC_PERID(0x3f)
+					| AT_XDMAC_CC_DAM_UBS_AM
 					| AT_XDMAC_CC_SAM_INCREMENTED_AM
 					| AT_XDMAC_CC_DIF(0)
 					| AT_XDMAC_CC_SIF(0)
@@ -1182,8 +1196,8 @@
 	desc->lld.mbr_cfg = chan_cc;
 
 	dev_dbg(chan2dev(chan),
-		"%s: lld: mbr_da=%pad, mbr_ds=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
-		__func__, &desc->lld.mbr_da, &desc->lld.mbr_ds, desc->lld.mbr_ubc,
+		"%s: lld: mbr_da=%pad, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
+		__func__, &desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc,
 		desc->lld.mbr_cfg);
 
 	return desc;
@@ -1203,6 +1217,8 @@
 		return NULL;
 
 	desc = at_xdmac_memset_create_desc(chan, atchan, dest, len, value);
+	if (!desc)
+		return NULL;
 	list_add_tail(&desc->desc_node, &desc->descs_list);
 
 	desc->tx_dma_desc.cookie = -EBUSY;
@@ -1383,10 +1399,11 @@
 	struct at_xdmac_desc	*desc, *_desc;
 	struct list_head	*descs_list;
 	enum dma_status		ret;
-	int			residue;
-	u32			cur_nda, mask, value;
+	int			residue, retry;
+	u32			cur_nda, check_nda, cur_ubc, mask, value;
 	u8			dwidth = 0;
 	unsigned long		flags;
+	bool			initd;
 
 	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret == DMA_COMPLETE)
@@ -1411,7 +1428,16 @@
 	residue = desc->xfer_size;
 	/*
 	 * Flush FIFO: only relevant when the transfer is source peripheral
-	 * synchronized.
+	 * synchronized. Flush is needed before reading CUBC because data in
+	 * the FIFO are not reported by CUBC. Reporting a residue of the
+	 * transfer length while we have data in FIFO can cause issue.
+	 * Usecase: atmel USART has a timeout which means I have received
+	 * characters but there is no more character received for a while. On
+	 * timeout, it requests the residue. If the data are in the DMA FIFO,
+	 * we will return a residue of the transfer length. It means no data
+	 * received. If an application is waiting for these data, it will hang
+	 * since we won't have another USART timeout without receiving new
+	 * data.
 	 */
 	mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
 	value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
@@ -1421,7 +1447,64 @@
 			cpu_relax();
 	}
 
-	cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
+	/*
+	 * The easiest way to compute the residue should be to pause the DMA
+	 * but doing this can lead to miss some data as some devices don't
+	 * have FIFO.
+	 * We need to read several registers because:
+	 * - DMA is running therefore a descriptor change is possible while
+	 * reading these registers
+	 * - When the block transfer is done, the value of the CUBC register
+	 * is set to its initial value until the fetch of the next descriptor.
+	 * This value will corrupt the residue calculation so we have to skip
+	 * it.
+	 *
+	 * INITD --------                    ------------
+	 *              |____________________|
+	 *       _______________________  _______________
+	 * NDA       @desc2             \/   @desc3
+	 *       _______________________/\_______________
+	 *       __________  ___________  _______________
+	 * CUBC       0    \/ MAX desc1 \/  MAX desc2
+	 *       __________/\___________/\_______________
+	 *
+	 * Since descriptors are aligned on 64 bits, we can assume that
+	 * the update of NDA and CUBC is atomic.
+	 * Memory barriers are used to ensure the read order of the registers.
+	 * A max number of retries is set because unlikely it could never ends.
+	 */
+	for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
+		check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
+		rmb();
+		cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
+		rmb();
+		initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD);
+		rmb();
+		cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
+		rmb();
+
+		if ((check_nda == cur_nda) && initd)
+			break;
+	}
+
+	if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) {
+		ret = DMA_ERROR;
+		goto spin_unlock;
+	}
+
+	/*
+	 * Flush FIFO: only relevant when the transfer is source peripheral
+	 * synchronized. Another flush is needed here because CUBC is updated
+	 * when the controller sends the data write command. It can lead to
+	 * report data that are not written in the memory or the device. The
+	 * FIFO flush ensures that data are really written.
+	 */
+	if ((desc->lld.mbr_cfg & mask) == value) {
+		at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
+		while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
+			cpu_relax();
+	}
+
 	/*
 	 * Remove size of all microblocks already transferred and the current
 	 * one. Then add the remaining size to transfer of the current
@@ -1434,7 +1517,7 @@
 		if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda)
 			break;
 	}
-	residue += at_xdmac_chan_read(atchan, AT_XDMAC_CUBC) << dwidth;
+	residue += cur_ubc << dwidth;
 
 	dma_set_residue(txstate, residue);
 
@@ -1502,8 +1585,8 @@
 	struct at_xdmac_desc	*desc;
 	u32			error_mask;
 
-	dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08lx\n",
-		 __func__, atchan->status);
+	dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08x\n",
+		__func__, atchan->irq_status);
 
 	error_mask = AT_XDMAC_CIS_RBEIS
 		     | AT_XDMAC_CIS_WBEIS
@@ -1511,15 +1594,15 @@
 
 	if (at_xdmac_chan_is_cyclic(atchan)) {
 		at_xdmac_handle_cyclic(atchan);
-	} else if ((atchan->status & AT_XDMAC_CIS_LIS)
-		   || (atchan->status & error_mask)) {
+	} else if ((atchan->irq_status & AT_XDMAC_CIS_LIS)
+		   || (atchan->irq_status & error_mask)) {
 		struct dma_async_tx_descriptor  *txd;
 
-		if (atchan->status & AT_XDMAC_CIS_RBEIS)
+		if (atchan->irq_status & AT_XDMAC_CIS_RBEIS)
 			dev_err(chan2dev(&atchan->chan), "read bus error!!!");
-		if (atchan->status & AT_XDMAC_CIS_WBEIS)
+		if (atchan->irq_status & AT_XDMAC_CIS_WBEIS)
 			dev_err(chan2dev(&atchan->chan), "write bus error!!!");
-		if (atchan->status & AT_XDMAC_CIS_ROIS)
+		if (atchan->irq_status & AT_XDMAC_CIS_ROIS)
 			dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
 
 		spin_lock_bh(&atchan->lock);
@@ -1527,7 +1610,11 @@
 					struct at_xdmac_desc,
 					xfer_node);
 		dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
-		BUG_ON(!desc->active_xfer);
+		if (!desc->active_xfer) {
+			dev_err(chan2dev(&atchan->chan), "Xfer not active: exiting");
+			spin_unlock_bh(&atchan->lock);
+			return;
+		}
 
 		txd = &desc->tx_dma_desc;
 
@@ -1574,7 +1661,7 @@
 			atchan = &atxdmac->chan[i];
 			chan_imr = at_xdmac_chan_read(atchan, AT_XDMAC_CIM);
 			chan_status = at_xdmac_chan_read(atchan, AT_XDMAC_CIS);
-			atchan->status = chan_status & chan_imr;
+			atchan->irq_status = chan_status & chan_imr;
 			dev_vdbg(atxdmac->dma.dev,
 				 "%s: chan%d: imr=0x%x, status=0x%x\n",
 				 __func__, i, chan_imr, chan_status);
@@ -1588,7 +1675,7 @@
 				 at_xdmac_chan_read(atchan, AT_XDMAC_CDA),
 				 at_xdmac_chan_read(atchan, AT_XDMAC_CUBC));
 
-			if (atchan->status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
+			if (atchan->irq_status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
 				at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
 
 			tasklet_schedule(&atchan->tasklet);
@@ -1688,6 +1775,7 @@
 	list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node)
 		at_xdmac_remove_xfer(atchan, desc);
 
+	clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
 	clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
@@ -1820,6 +1908,8 @@
 		atchan = to_at_xdmac_chan(chan);
 		at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc);
 		if (at_xdmac_chan_is_cyclic(atchan)) {
+			if (at_xdmac_chan_is_paused(atchan))
+				at_xdmac_device_resume(chan);
 			at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, atchan->save_cnda);
 			at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc);
 			at_xdmac_chan_write(atchan, AT_XDMAC_CIE, atchan->save_cim);
@@ -1984,7 +2074,7 @@
 err_clk_disable:
 	clk_disable_unprepare(atxdmac->clk);
 err_free_irq:
-	free_irq(atxdmac->irq, atxdmac->dma.dev);
+	free_irq(atxdmac->irq, atxdmac);
 	return ret;
 }
 
@@ -2000,7 +2090,7 @@
 
 	synchronize_irq(atxdmac->irq);
 
-	free_irq(atxdmac->irq, atxdmac->dma.dev);
+	free_irq(atxdmac->irq, atxdmac);
 
 	for (i = 0; i < atxdmac->dma.chancnt; i++) {
 		struct at_xdmac_chan *atchan = &atxdmac->chan[i];
--- linux-4.4.0.orig/drivers/dma/bcm2835-dma.c
+++ linux-4.4.0/drivers/dma/bcm2835-dma.c
@@ -595,8 +595,10 @@
 		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
 
 	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-	if (rc)
+	if (rc) {
+		dev_err(&pdev->dev, "Unable to set DMA mask\n");
 		return rc;
+	}
 
 	od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
 	if (!od)
--- linux-4.4.0.orig/drivers/dma/coh901318.c
+++ linux-4.4.0/drivers/dma/coh901318.c
@@ -1810,13 +1810,10 @@
 static int coh901318_config(struct coh901318_chan *cohc,
 			    struct coh901318_params *param)
 {
-	unsigned long flags;
 	const struct coh901318_params *p;
 	int channel = cohc->id;
 	void __iomem *virtbase = cohc->base->virtbase;
 
-	spin_lock_irqsave(&cohc->lock, flags);
-
 	if (param)
 		p = param;
 	else
@@ -1836,8 +1833,6 @@
 	coh901318_set_conf(cohc, p->config);
 	coh901318_set_ctrl(cohc, p->ctrl_lli_last);
 
-	spin_unlock_irqrestore(&cohc->lock, flags);
-
 	return 0;
 }
 
@@ -1965,8 +1960,6 @@
 		return;
 	}
 
-	spin_lock(&cohc->lock);
-
 	/*
 	 * When we reach this point, at least one queue item
 	 * should have been moved over from cohc->queue to
@@ -1987,8 +1980,6 @@
 	if (coh901318_queue_start(cohc) == NULL)
 		cohc->busy = 0;
 
-	spin_unlock(&cohc->lock);
-
 	/*
 	 * This tasklet will remove items from cohc->active
 	 * and thus terminates them.
--- linux-4.4.0.orig/drivers/dma/dma-axi-dmac.c
+++ linux-4.4.0/drivers/dma/dma-axi-dmac.c
@@ -441,7 +441,7 @@
 
 	if (chan->hw_2d) {
 		if (!axi_dmac_check_len(chan, xt->sgl[0].size) ||
-		    !axi_dmac_check_len(chan, xt->numf))
+		    xt->numf == 0)
 			return NULL;
 		if (xt->sgl[0].size + dst_icg > chan->max_length ||
 		    xt->sgl[0].size + src_icg > chan->max_length)
--- linux-4.4.0.orig/drivers/dma/dma-jz4740.c
+++ linux-4.4.0/drivers/dma/dma-jz4740.c
@@ -557,7 +557,7 @@
 
 	ret = dma_async_device_register(dd);
 	if (ret)
-		return ret;
+		goto err_clk;
 
 	irq = platform_get_irq(pdev, 0);
 	ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev);
@@ -570,6 +570,8 @@
 
 err_unregister:
 	dma_async_device_unregister(dd);
+err_clk:
+	clk_disable_unprepare(dmadev->clk);
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/dma/dma-jz4780.c
+++ linux-4.4.0/drivers/dma/dma-jz4780.c
@@ -563,11 +563,11 @@
 	enum dma_status status;
 	unsigned long flags;
 
+	spin_lock_irqsave(&jzchan->vchan.lock, flags);
+
 	status = dma_cookie_status(chan, cookie, txstate);
 	if ((status == DMA_COMPLETE) || (txstate == NULL))
-		return status;
-
-	spin_lock_irqsave(&jzchan->vchan.lock, flags);
+		goto out_unlock_irqrestore;
 
 	vdesc = vchan_find_desc(&jzchan->vchan, cookie);
 	if (vdesc) {
@@ -576,7 +576,7 @@
 					to_jz4780_dma_desc(vdesc), 0);
 	} else if (cookie == jzchan->desc->vdesc.tx.cookie) {
 		txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc,
-			  (jzchan->curr_hwdesc + 1) % jzchan->desc->count);
+					jzchan->curr_hwdesc + 1);
 	} else
 		txstate->residue = 0;
 
@@ -584,6 +584,7 @@
 	    && jzchan->desc->status & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT))
 		status = DMA_ERROR;
 
+out_unlock_irqrestore:
 	spin_unlock_irqrestore(&jzchan->vchan.lock, flags);
 	return status;
 }
@@ -750,6 +751,11 @@
 	struct resource *res;
 	int i, ret;
 
+	if (!dev->of_node) {
+		dev_err(dev, "This driver must be probed from devicetree\n");
+		return -EINVAL;
+	}
+
 	jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL);
 	if (!jzdma)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/dma/dmaengine.c
+++ linux-4.4.0/drivers/dma/dmaengine.c
@@ -1023,12 +1023,14 @@
 	switch (order) {
 	case 0 ... 1:
 		return &unmap_pool[0];
+#if IS_ENABLED(CONFIG_DMA_ENGINE_RAID)
 	case 2 ... 4:
 		return &unmap_pool[1];
 	case 5 ... 7:
 		return &unmap_pool[2];
 	case 8:
 		return &unmap_pool[3];
+#endif
 	default:
 		BUG();
 		return NULL;
--- linux-4.4.0.orig/drivers/dma/dmatest.c
+++ linux-4.4.0/drivers/dma/dmatest.c
@@ -148,6 +148,12 @@
 #define PATTERN_OVERWRITE	0x20
 #define PATTERN_COUNT_MASK	0x1f
 
+/* poor man's completion - we want to use wait_event_freezable() on it */
+struct dmatest_done {
+	bool			done;
+	wait_queue_head_t	*wait;
+};
+
 struct dmatest_thread {
 	struct list_head	node;
 	struct dmatest_info	*info;
@@ -156,6 +162,8 @@
 	u8			**srcs;
 	u8			**dsts;
 	enum dma_transaction_type type;
+	wait_queue_head_t done_wait;
+	struct dmatest_done test_done;
 	bool			done;
 };
 
@@ -316,18 +324,25 @@
 	return error_count;
 }
 
-/* poor man's completion - we want to use wait_event_freezable() on it */
-struct dmatest_done {
-	bool			done;
-	wait_queue_head_t	*wait;
-};
 
 static void dmatest_callback(void *arg)
 {
 	struct dmatest_done *done = arg;
-
-	done->done = true;
-	wake_up_all(done->wait);
+	struct dmatest_thread *thread =
+		container_of(done, struct dmatest_thread, test_done);
+	if (!thread->done) {
+		done->done = true;
+		wake_up_all(done->wait);
+	} else {
+		/*
+		 * If thread->done, it means that this callback occurred
+		 * after the parent thread has cleaned up. This can
+		 * happen in the case that driver doesn't implement
+		 * the terminate_all() functionality and a dma operation
+		 * did not occur within the timeout period
+		 */
+		WARN(1, "dmatest: Kernel memory may be corrupted!!\n");
+	}
 }
 
 static unsigned int min_odd(unsigned int x, unsigned int y)
@@ -398,9 +413,8 @@
  */
 static int dmatest_func(void *data)
 {
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait);
 	struct dmatest_thread	*thread = data;
-	struct dmatest_done	done = { .wait = &done_wait };
+	struct dmatest_done	*done = &thread->test_done;
 	struct dmatest_info	*info;
 	struct dmatest_params	*params;
 	struct dma_chan		*chan;
@@ -477,8 +491,8 @@
 	flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
 
 	ktime = ktime_get();
-	while (!kthread_should_stop()
-	       && !(params->iterations && total_tests >= params->iterations)) {
+	while (!(kthread_should_stop() ||
+	       (params->iterations && total_tests >= params->iterations))) {
 		struct dma_async_tx_descriptor *tx = NULL;
 		struct dmaengine_unmap_data *um;
 		dma_addr_t srcs[src_cnt];
@@ -549,11 +563,9 @@
 			srcs[i] = um->addr[i] + src_off;
 			ret = dma_mapping_error(dev->dev, um->addr[i]);
 			if (ret) {
-				dmaengine_unmap_put(um);
 				result("src mapping error", total_tests,
 				       src_off, dst_off, len, ret);
-				failed_tests++;
-				continue;
+				goto error_unmap_continue;
 			}
 			um->to_cnt++;
 		}
@@ -568,11 +580,9 @@
 					       DMA_BIDIRECTIONAL);
 			ret = dma_mapping_error(dev->dev, dsts[i]);
 			if (ret) {
-				dmaengine_unmap_put(um);
 				result("dst mapping error", total_tests,
 				       src_off, dst_off, len, ret);
-				failed_tests++;
-				continue;
+				goto error_unmap_continue;
 			}
 			um->bidi_cnt++;
 		}
@@ -597,56 +607,42 @@
 		}
 
 		if (!tx) {
-			dmaengine_unmap_put(um);
 			result("prep error", total_tests, src_off,
 			       dst_off, len, ret);
 			msleep(100);
-			failed_tests++;
-			continue;
+			goto error_unmap_continue;
 		}
 
-		done.done = false;
+		done->done = false;
 		tx->callback = dmatest_callback;
-		tx->callback_param = &done;
+		tx->callback_param = done;
 		cookie = tx->tx_submit(tx);
 
 		if (dma_submit_error(cookie)) {
-			dmaengine_unmap_put(um);
 			result("submit error", total_tests, src_off,
 			       dst_off, len, ret);
 			msleep(100);
-			failed_tests++;
-			continue;
+			goto error_unmap_continue;
 		}
 		dma_async_issue_pending(chan);
 
-		wait_event_freezable_timeout(done_wait, done.done,
+		wait_event_freezable_timeout(thread->done_wait, done->done,
 					     msecs_to_jiffies(params->timeout));
 
 		status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
 
-		if (!done.done) {
-			/*
-			 * We're leaving the timed out dma operation with
-			 * dangling pointer to done_wait.  To make this
-			 * correct, we'll need to allocate wait_done for
-			 * each test iteration and perform "who's gonna
-			 * free it this time?" dancing.  For now, just
-			 * leave it dangling.
-			 */
+		if (!done->done) {
 			dmaengine_unmap_put(um);
 			result("test timed out", total_tests, src_off, dst_off,
 			       len, 0);
-			failed_tests++;
-			continue;
+			goto error_unmap_continue;
 		} else if (status != DMA_COMPLETE) {
 			dmaengine_unmap_put(um);
 			result(status == DMA_ERROR ?
 			       "completion error status" :
 			       "completion busy status", total_tests, src_off,
 			       dst_off, len, ret);
-			failed_tests++;
-			continue;
+			goto error_unmap_continue;
 		}
 
 		dmaengine_unmap_put(um);
@@ -685,6 +681,12 @@
 			verbose_result("test passed", total_tests, src_off,
 				       dst_off, len, 0);
 		}
+
+		continue;
+
+error_unmap_continue:
+		dmaengine_unmap_put(um);
+		failed_tests++;
 	}
 	runtime = ktime_us_delta(ktime_get(), ktime);
 
@@ -707,7 +709,7 @@
 		dmatest_KBs(runtime, total_len), ret);
 
 	/* terminate all transfers on specified channels */
-	if (ret)
+	if (ret || failed_tests)
 		dmaengine_terminate_all(chan);
 
 	thread->done = true;
@@ -765,6 +767,8 @@
 		thread->info = info;
 		thread->chan = dtc->chan;
 		thread->type = type;
+		thread->test_done.wait = &thread->done_wait;
+		init_waitqueue_head(&thread->done_wait);
 		smp_wmb();
 		thread->task = kthread_create(dmatest_func, thread, "%s-%s%u",
 				dma_chan_name(chan), op, i);
--- linux-4.4.0.orig/drivers/dma/dw/core.c
+++ linux-4.4.0/drivers/dma/dw/core.c
@@ -130,26 +130,14 @@
 static void dwc_initialize(struct dw_dma_chan *dwc)
 {
 	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
-	struct dw_dma_slave *dws = dwc->chan.private;
 	u32 cfghi = DWC_CFGH_FIFO_MODE;
 	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
 
 	if (dwc->initialized == true)
 		return;
 
-	if (dws) {
-		/*
-		 * We need controller-specific data to set up slave
-		 * transfers.
-		 */
-		BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
-
-		cfghi |= DWC_CFGH_DST_PER(dws->dst_id);
-		cfghi |= DWC_CFGH_SRC_PER(dws->src_id);
-	} else {
-		cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
-		cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
-	}
+	cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
+	cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
 
 	channel_writel(dwc, CFG_LO, cfglo);
 	channel_writel(dwc, CFG_HI, cfghi);
@@ -536,16 +524,17 @@
 
 /* Called with dwc->lock held and all DMAC interrupts disabled */
 static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
-		u32 status_err, u32 status_xfer)
+		u32 status_block, u32 status_err, u32 status_xfer)
 {
 	unsigned long flags;
 
-	if (dwc->mask) {
+	if (status_block & dwc->mask) {
 		void (*callback)(void *param);
 		void *callback_param;
 
 		dev_vdbg(chan2dev(&dwc->chan), "new cyclic period llp 0x%08x\n",
 				channel_readl(dwc, LLP));
+		dma_writel(dw, CLEAR.BLOCK, dwc->mask);
 
 		callback = dwc->cdesc->period_callback;
 		callback_param = dwc->cdesc->period_callback_param;
@@ -577,6 +566,7 @@
 		channel_writel(dwc, CTL_LO, 0);
 		channel_writel(dwc, CTL_HI, 0);
 
+		dma_writel(dw, CLEAR.BLOCK, dwc->mask);
 		dma_writel(dw, CLEAR.ERROR, dwc->mask);
 		dma_writel(dw, CLEAR.XFER, dwc->mask);
 
@@ -585,6 +575,9 @@
 
 		spin_unlock_irqrestore(&dwc->lock, flags);
 	}
+
+	/* Re-enable interrupts */
+	channel_set_bit(dw, MASK.BLOCK, dwc->mask);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -593,10 +586,12 @@
 {
 	struct dw_dma *dw = (struct dw_dma *)data;
 	struct dw_dma_chan *dwc;
+	u32 status_block;
 	u32 status_xfer;
 	u32 status_err;
 	int i;
 
+	status_block = dma_readl(dw, RAW.BLOCK);
 	status_xfer = dma_readl(dw, RAW.XFER);
 	status_err = dma_readl(dw, RAW.ERROR);
 
@@ -605,16 +600,15 @@
 	for (i = 0; i < dw->dma.chancnt; i++) {
 		dwc = &dw->chan[i];
 		if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags))
-			dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
+			dwc_handle_cyclic(dw, dwc, status_block, status_err,
+					status_xfer);
 		else if (status_err & (1 << i))
 			dwc_handle_error(dw, dwc);
 		else if (status_xfer & (1 << i))
 			dwc_scan_descriptors(dw, dwc);
 	}
 
-	/*
-	 * Re-enable interrupts.
-	 */
+	/* Re-enable interrupts */
 	channel_set_bit(dw, MASK.XFER, dw->all_chan_mask);
 	channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask);
 }
@@ -635,6 +629,7 @@
 	 * softirq handler.
 	 */
 	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
+	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
 
 	status = dma_readl(dw, STATUS_INT);
@@ -645,6 +640,7 @@
 
 		/* Try to recover */
 		channel_clear_bit(dw, MASK.XFER, (1 << 8) - 1);
+		channel_clear_bit(dw, MASK.BLOCK, (1 << 8) - 1);
 		channel_clear_bit(dw, MASK.SRC_TRAN, (1 << 8) - 1);
 		channel_clear_bit(dw, MASK.DST_TRAN, (1 << 8) - 1);
 		channel_clear_bit(dw, MASK.ERROR, (1 << 8) - 1);
@@ -928,7 +924,7 @@
 	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
 	struct dw_dma_slave *dws = param;
 
-	if (!dws || dws->dma_dev != chan->device->dev)
+	if (dws->dma_dev != chan->device->dev)
 		return false;
 
 	/* We have to copy data since dws can be temporary storage */
@@ -1111,6 +1107,7 @@
 	dma_writel(dw, CFG, 0);
 
 	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
+	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
@@ -1151,6 +1148,14 @@
 	 * doesn't mean what you think it means), and status writeback.
 	 */
 
+	/*
+	 * We need controller-specific data to set up slave transfers.
+	 */
+	if (chan->private && !dw_dma_filter(chan, chan->private)) {
+		dev_warn(chan2dev(chan), "Wrong controller-specific data\n");
+		return -EINVAL;
+	}
+
 	/* Enable controller here if needed */
 	if (!dw->in_use)
 		dw_dma_on(dw);
@@ -1212,10 +1217,19 @@
 	spin_lock_irqsave(&dwc->lock, flags);
 	list_splice_init(&dwc->free_list, &list);
 	dwc->descs_allocated = 0;
+
+	/* Clear custom channel configuration */
+	dwc->src_id = 0;
+	dwc->dst_id = 0;
+
+	dwc->src_master = 0;
+	dwc->dst_master = 0;
+
 	dwc->initialized = false;
 
 	/* Disable interrupts */
 	channel_clear_bit(dw, MASK.XFER, dwc->mask);
+	channel_clear_bit(dw, MASK.BLOCK, dwc->mask);
 	channel_clear_bit(dw, MASK.ERROR, dwc->mask);
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1245,7 +1259,7 @@
 int dw_dma_cyclic_start(struct dma_chan *chan)
 {
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
-	struct dw_dma		*dw = to_dw_dma(dwc->chan.device);
+	struct dw_dma		*dw = to_dw_dma(chan->device);
 	unsigned long		flags;
 
 	if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) {
@@ -1255,25 +1269,10 @@
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
-	/* Assert channel is idle */
-	if (dma_readl(dw, CH_EN) & dwc->mask) {
-		dev_err(chan2dev(&dwc->chan),
-			"%s: BUG: Attempted to start non-idle channel\n",
-			__func__);
-		dwc_dump_chan_regs(dwc);
-		spin_unlock_irqrestore(&dwc->lock, flags);
-		return -EBUSY;
-	}
+	/* Enable interrupts to perform cyclic transfer */
+	channel_set_bit(dw, MASK.BLOCK, dwc->mask);
 
-	dma_writel(dw, CLEAR.ERROR, dwc->mask);
-	dma_writel(dw, CLEAR.XFER, dwc->mask);
-
-	/* Setup DMAC channel registers */
-	channel_writel(dwc, LLP, dwc->cdesc->desc[0]->txd.phys);
-	channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
-	channel_writel(dwc, CTL_HI, 0);
-
-	channel_set_bit(dw, CH_EN, dwc->mask);
+	dwc_dostart(dwc, dwc->cdesc->desc[0]);
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -1479,6 +1478,7 @@
 
 	dwc_chan_disable(dw, dwc);
 
+	dma_writel(dw, CLEAR.BLOCK, dwc->mask);
 	dma_writel(dw, CLEAR.ERROR, dwc->mask);
 	dma_writel(dw, CLEAR.XFER, dwc->mask);
 
@@ -1567,9 +1567,6 @@
 	/* 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);
-
 	/* Create a pool of consistent memory blocks for hardware descriptors */
 	dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", chip->dev,
 					 sizeof(struct dw_desc), 4, 0);
--- linux-4.4.0.orig/drivers/dma/dw/platform.c
+++ linux-4.4.0/drivers/dma/dw/platform.c
@@ -87,13 +87,20 @@
 	dma_cap_set(DMA_SLAVE, info->dma_cap);
 	info->filter_fn = dw_dma_acpi_filter;
 
-	ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate,
-						info);
+	ret = acpi_dma_controller_register(dev, acpi_dma_simple_xlate, info);
 	if (ret)
 		dev_err(dev, "could not register acpi_dma_controller\n");
 }
+
+static void dw_dma_acpi_controller_free(struct dw_dma *dw)
+{
+	struct device *dev = dw->dma.dev;
+
+	acpi_dma_controller_free(dev);
+}
 #else /* !CONFIG_ACPI */
 static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {}
+static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {}
 #endif /* !CONFIG_ACPI */
 
 #ifdef CONFIG_OF
@@ -225,6 +232,9 @@
 {
 	struct dw_dma_chip *chip = platform_get_drvdata(pdev);
 
+	if (ACPI_HANDLE(&pdev->dev))
+		dw_dma_acpi_controller_free(chip->dw);
+
 	if (pdev->dev.of_node)
 		of_dma_controller_free(pdev->dev.of_node);
 
@@ -239,7 +249,19 @@
 {
 	struct dw_dma_chip *chip = platform_get_drvdata(pdev);
 
+	/*
+	 * We have to call dw_dma_disable() to stop any ongoing transfer. On
+	 * some platforms we can't do that since DMA device is powered off.
+	 * Moreover we have no possibility to check if the platform is affected
+	 * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put()
+	 * unconditionally. On the other hand we can't use
+	 * pm_runtime_suspended() because runtime PM framework is not fully
+	 * used by the driver.
+	 */
+	pm_runtime_get_sync(chip->dev);
 	dw_dma_disable(chip);
+	pm_runtime_put_sync_suspend(chip->dev);
+
 	clk_disable_unprepare(chip->clk);
 }
 
--- linux-4.4.0.orig/drivers/dma/edma.c
+++ linux-4.4.0/drivers/dma/edma.c
@@ -1126,11 +1126,24 @@
 	struct edma_desc *edesc;
 	struct device *dev = chan->device->dev;
 	struct edma_chan *echan = to_edma_chan(chan);
-	unsigned int width, pset_len;
+	unsigned int width, pset_len, array_size;
 
 	if (unlikely(!echan || !len))
 		return NULL;
 
+	/* Align the array size (acnt block) with the transfer properties */
+	switch (__ffs((src | dest | len))) {
+	case 0:
+		array_size = SZ_32K - 1;
+		break;
+	case 1:
+		array_size = SZ_32K - 2;
+		break;
+	default:
+		array_size = SZ_32K - 4;
+		break;
+	}
+
 	if (len < SZ_64K) {
 		/*
 		 * Transfer size less than 64K can be handled with one paRAM
@@ -1152,7 +1165,7 @@
 		 * When the full_length is multibple of 32767 one slot can be
 		 * used to complete the transfer.
 		 */
-		width = SZ_32K - 1;
+		width = array_size;
 		pset_len = rounddown(len, width);
 		/* One slot is enough for lengths multiple of (SZ_32K -1) */
 		if (unlikely(pset_len == len))
@@ -1202,7 +1215,7 @@
 		}
 		dest += pset_len;
 		src += pset_len;
-		pset_len = width = len % (SZ_32K - 1);
+		pset_len = width = len % array_size;
 
 		ret = edma_config_pset(chan, &edesc->pset[1], src, dest, 1,
 				       width, pset_len, DMA_MEM_TO_MEM);
@@ -2205,9 +2218,6 @@
 
 	ecc->default_queue = info->default_queue;
 
-	for (i = 0; i < ecc->num_slots; i++)
-		edma_write_slot(ecc, i, &dummy_paramset);
-
 	if (info->rsv) {
 		/* Set the reserved slots in inuse list */
 		rsv_slots = info->rsv->rsv_slots;
@@ -2220,6 +2230,12 @@
 		}
 	}
 
+	for (i = 0; i < ecc->num_slots; i++) {
+		/* Reset only unused - not reserved - paRAM slots */
+		if (!test_bit(i, ecc->slot_inuse))
+			edma_write_slot(ecc, i, &dummy_paramset);
+	}
+
 	/* Clear the xbar mapped channels in unused list */
 	xbar_chans = info->xbar_chans;
 	if (xbar_chans) {
@@ -2272,8 +2288,10 @@
 
 		ecc->tc_list = devm_kcalloc(dev, ecc->num_tc,
 					    sizeof(*ecc->tc_list), GFP_KERNEL);
-		if (!ecc->tc_list)
-			return -ENOMEM;
+		if (!ecc->tc_list) {
+			ret = -ENOMEM;
+			goto err_reg1;
+		}
 
 		for (i = 0;; i++) {
 			ret = of_parse_phandle_with_fixed_args(node, "ti,tptcs",
@@ -2421,7 +2439,13 @@
 	},
 };
 
+static int edma_tptc_probe(struct platform_device *pdev)
+{
+	return 0;
+}
+
 static struct platform_driver edma_tptc_driver = {
+	.probe		= edma_tptc_probe,
 	.driver = {
 		.name	= "edma3-tptc",
 		.of_match_table = edma_tptc_of_ids,
--- linux-4.4.0.orig/drivers/dma/ep93xx_dma.c
+++ linux-4.4.0/drivers/dma/ep93xx_dma.c
@@ -325,6 +325,8 @@
 		| M2P_CONTROL_ENABLE;
 	m2p_set_control(edmac, control);
 
+	edmac->buffer = 0;
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/dma/fsl-edma.c
+++ linux-4.4.0/drivers/dma/fsl-edma.c
@@ -671,6 +671,13 @@
 			fsl_chan = &fsl_edma->chans[ch];
 
 			spin_lock(&fsl_chan->vchan.lock);
+
+			if (!fsl_chan->edesc) {
+				/* terminate_all called before */
+				spin_unlock(&fsl_chan->vchan.lock);
+				continue;
+			}
+
 			if (!fsl_chan->edesc->iscyclic) {
 				list_del(&fsl_chan->edesc->vdesc.node);
 				vchan_cookie_complete(&fsl_chan->edesc->vdesc);
--- linux-4.4.0.orig/drivers/dma/fsldma.c
+++ linux-4.4.0/drivers/dma/fsldma.c
@@ -1335,6 +1335,7 @@
 {
 	struct fsldma_device *fdev;
 	struct device_node *child;
+	unsigned int i;
 	int err;
 
 	fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
@@ -1416,6 +1417,10 @@
 	return 0;
 
 out_free_fdev:
+	for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
+		if (fdev->chan[i])
+			fsl_dma_chan_remove(fdev->chan[i]);
+	}
 	irq_dispose_mapping(fdev->irq);
 	kfree(fdev);
 out_return:
@@ -1436,6 +1441,7 @@
 		if (fdev->chan[i])
 			fsl_dma_chan_remove(fdev->chan[i]);
 	}
+	irq_dispose_mapping(fdev->irq);
 
 	iounmap(fdev->regs);
 	kfree(fdev);
--- linux-4.4.0.orig/drivers/dma/hsu/hsu.c
+++ linux-4.4.0/drivers/dma/hsu/hsu.c
@@ -135,7 +135,7 @@
 	sr = hsu_chan_readl(hsuc, HSU_CH_SR);
 	spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
 
-	return sr;
+	return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY);
 }
 
 irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
--- linux-4.4.0.orig/drivers/dma/hsu/hsu.h
+++ linux-4.4.0/drivers/dma/hsu/hsu.h
@@ -41,6 +41,9 @@
 #define HSU_CH_SR_DESCTO(x)	BIT(8 + (x))
 #define HSU_CH_SR_DESCTO_ANY	(BIT(11) | BIT(10) | BIT(9) | BIT(8))
 #define HSU_CH_SR_CHE		BIT(15)
+#define HSU_CH_SR_DESCE(x)	BIT(16 + (x))
+#define HSU_CH_SR_DESCE_ANY	(BIT(19) | BIT(18) | BIT(17) | BIT(16))
+#define HSU_CH_SR_CDESC_ANY	(BIT(31) | BIT(30))
 
 /* Bits in HSU_CH_CR */
 #define HSU_CH_CR_CHA		BIT(0)
--- linux-4.4.0.orig/drivers/dma/idma64.c
+++ linux-4.4.0/drivers/dma/idma64.c
@@ -594,7 +594,7 @@
 	idma64->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
 	idma64->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
 
-	idma64->dma.dev = chip->dev;
+	idma64->dma.dev = chip->sysdev;
 
 	ret = dma_async_device_register(&idma64->dma);
 	if (ret)
@@ -632,6 +632,7 @@
 {
 	struct idma64_chip *chip;
 	struct device *dev = &pdev->dev;
+	struct device *sysdev = dev->parent;
 	struct resource *mem;
 	int ret;
 
@@ -648,11 +649,12 @@
 	if (IS_ERR(chip->regs))
 		return PTR_ERR(chip->regs);
 
-	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+	ret = dma_coerce_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
 	if (ret)
 		return ret;
 
 	chip->dev = dev;
+	chip->sysdev = sysdev;
 
 	ret = idma64_probe(chip);
 	if (ret)
--- linux-4.4.0.orig/drivers/dma/idma64.h
+++ linux-4.4.0/drivers/dma/idma64.h
@@ -215,12 +215,14 @@
 /**
  * struct idma64_chip - representation of iDMA 64-bit controller hardware
  * @dev:		struct device of the DMA controller
+ * @sysdev:		struct device of the physical device that does DMA
  * @irq:		irq line
  * @regs:		memory mapped I/O space
  * @idma64:		struct idma64 that is filed by idma64_probe()
  */
 struct idma64_chip {
 	struct device	*dev;
+	struct device	*sysdev;
 	int		irq;
 	void __iomem	*regs;
 	struct idma64	*idma64;
--- linux-4.4.0.orig/drivers/dma/imx-dma.c
+++ linux-4.4.0/drivers/dma/imx-dma.c
@@ -286,7 +286,7 @@
 	struct scatterlist *sg = d->sg;
 	unsigned long now;
 
-	now = min(d->len, sg_dma_len(sg));
+	now = min_t(size_t, d->len, sg_dma_len(sg));
 	if (d->len != IMX_DMA_LENGTH_LOOP)
 		d->len -= now;
 
@@ -619,7 +619,7 @@
 {
 	struct imxdma_channel *imxdmac = (void *)data;
 	struct imxdma_engine *imxdma = imxdmac->imxdma;
-	struct imxdma_desc *desc;
+	struct imxdma_desc *desc, *next_desc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&imxdma->lock, flags);
@@ -649,10 +649,10 @@
 	list_move_tail(imxdmac->ld_active.next, &imxdmac->ld_free);
 
 	if (!list_empty(&imxdmac->ld_queue)) {
-		desc = list_first_entry(&imxdmac->ld_queue, struct imxdma_desc,
-					node);
+		next_desc = list_first_entry(&imxdmac->ld_queue,
+					     struct imxdma_desc, node);
 		list_move_tail(imxdmac->ld_queue.next, &imxdmac->ld_active);
-		if (imxdma_xfer_desc(desc) < 0)
+		if (imxdma_xfer_desc(next_desc) < 0)
 			dev_warn(imxdma->dev, "%s: channel: %d couldn't xfer desc\n",
 				 __func__, imxdmac->channel);
 	}
--- linux-4.4.0.orig/drivers/dma/imx-sdma.c
+++ linux-4.4.0/drivers/dma/imx-sdma.c
@@ -614,7 +614,7 @@
 	spin_lock_irqsave(&sdma->channel_0_lock, flags);
 
 	bd0->mode.command = C0_SETPM;
-	bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+	bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
 	bd0->mode.count = size / 2;
 	bd0->buffer_addr = buf_phys;
 	bd0->ext_buffer_addr = address;
@@ -883,7 +883,7 @@
 	context->gReg[7] = sdmac->watermark_level;
 
 	bd0->mode.command = C0_SETDM;
-	bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+	bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
 	bd0->mode.count = sizeof(*context) / 4;
 	bd0->buffer_addr = sdma->context_phys;
 	bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
@@ -911,6 +911,21 @@
 	return 0;
 }
 
+static int sdma_disable_channel_with_delay(struct dma_chan *chan)
+{
+	sdma_disable_channel(chan);
+
+	/*
+	 * According to NXP R&D team a delay of one BD SDMA cost time
+	 * (maximum is 1ms) should be added after disable of the channel
+	 * bit, to ensure SDMA core has really been stopped after SDMA
+	 * clients call .device_terminate_all.
+	 */
+	mdelay(1);
+
+	return 0;
+}
+
 static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
 {
 	struct sdma_engine *sdma = sdmac->sdma;
@@ -1396,6 +1411,14 @@
 	if (!sdma->script_number)
 		sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
 
+	if (sdma->script_number > sizeof(struct sdma_script_start_addrs)
+				  / sizeof(s32)) {
+		dev_err(sdma->dev,
+			"SDMA script number %d not match with firmware.\n",
+			sdma->script_number);
+		return;
+	}
+
 	for (i = 0; i < sdma->script_number; i++)
 		if (addr_arr[i] > 0)
 			saddr_arr[i] = addr_arr[i];
@@ -1707,17 +1730,24 @@
 	if (IS_ERR(sdma->clk_ahb))
 		return PTR_ERR(sdma->clk_ahb);
 
-	clk_prepare(sdma->clk_ipg);
-	clk_prepare(sdma->clk_ahb);
+	ret = clk_prepare(sdma->clk_ipg);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare(sdma->clk_ahb);
+	if (ret)
+		goto err_clk;
 
 	ret = devm_request_irq(&pdev->dev, irq, sdma_int_handler, 0, "sdma",
 			       sdma);
 	if (ret)
-		return ret;
+		goto err_irq;
 
 	sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
-	if (!sdma->script_addrs)
-		return -ENOMEM;
+	if (!sdma->script_addrs) {
+		ret = -ENOMEM;
+		goto err_irq;
+	}
 
 	/* initially no scripts available */
 	saddr_arr = (s32 *)sdma->script_addrs;
@@ -1764,27 +1794,6 @@
 	if (pdata && pdata->script_addrs)
 		sdma_add_scripts(sdma, pdata->script_addrs);
 
-	if (pdata) {
-		ret = sdma_get_firmware(sdma, pdata->fw_name);
-		if (ret)
-			dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
-	} else {
-		/*
-		 * Because that device tree does not encode ROM script address,
-		 * the RAM script in firmware is mandatory for device tree
-		 * probe, otherwise it fails.
-		 */
-		ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
-					      &fw_name);
-		if (ret)
-			dev_warn(&pdev->dev, "failed to get firmware name\n");
-		else {
-			ret = sdma_get_firmware(sdma, fw_name);
-			if (ret)
-				dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
-		}
-	}
-
 	sdma->dma_device.dev = &pdev->dev;
 
 	sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
@@ -1793,7 +1802,7 @@
 	sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
 	sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
 	sdma->dma_device.device_config = sdma_config;
-	sdma->dma_device.device_terminate_all = sdma_disable_channel;
+	sdma->dma_device.device_terminate_all = sdma_disable_channel_with_delay;
 	sdma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
 	sdma->dma_device.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
 	sdma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
@@ -1826,12 +1835,43 @@
 		of_node_put(spba_bus);
 	}
 
+	/*
+	 * Kick off firmware loading as the very last step:
+	 * attempt to load firmware only if we're not on the error path, because
+	 * the firmware callback requires a fully functional and allocated sdma
+	 * instance.
+	 */
+	if (pdata) {
+		ret = sdma_get_firmware(sdma, pdata->fw_name);
+		if (ret)
+			dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
+	} else {
+		/*
+		 * Because that device tree does not encode ROM script address,
+		 * the RAM script in firmware is mandatory for device tree
+		 * probe, otherwise it fails.
+		 */
+		ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
+					      &fw_name);
+		if (ret) {
+			dev_warn(&pdev->dev, "failed to get firmware name\n");
+		} else {
+			ret = sdma_get_firmware(sdma, fw_name);
+			if (ret)
+				dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
+		}
+	}
+
 	return 0;
 
 err_register:
 	dma_async_device_unregister(&sdma->dma_device);
 err_init:
 	kfree(sdma->script_addrs);
+err_irq:
+	clk_unprepare(sdma->clk_ahb);
+err_clk:
+	clk_unprepare(sdma->clk_ipg);
 	return ret;
 }
 
@@ -1842,6 +1882,8 @@
 
 	dma_async_device_unregister(&sdma->dma_device);
 	kfree(sdma->script_addrs);
+	clk_unprepare(sdma->clk_ahb);
+	clk_unprepare(sdma->clk_ipg);
 	/* Kill the tasklet */
 	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
 		struct sdma_channel *sdmac = &sdma->channel[i];
--- linux-4.4.0.orig/drivers/dma/ioat/dca.c
+++ linux-4.4.0/drivers/dma/ioat/dca.c
@@ -336,10 +336,10 @@
 	}
 
 	if (dca3_tag_map_invalid(ioatdca->tag_map)) {
-		WARN_TAINT_ONCE(1, TAINT_FIRMWARE_WORKAROUND,
-				"%s %s: APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n",
-				dev_driver_string(&pdev->dev),
-				dev_name(&pdev->dev));
+		add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
+		pr_warn_once("%s %s: APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n",
+			     dev_driver_string(&pdev->dev),
+			     dev_name(&pdev->dev));
 		free_dca_provider(dca);
 		return NULL;
 	}
--- linux-4.4.0.orig/drivers/dma/ioat/hw.h
+++ linux-4.4.0/drivers/dma/ioat/hw.h
@@ -64,6 +64,8 @@
 #define PCI_DEVICE_ID_INTEL_IOAT_BDX8	0x6f2e
 #define PCI_DEVICE_ID_INTEL_IOAT_BDX9	0x6f2f
 
+#define PCI_DEVICE_ID_INTEL_IOAT_SKX	0x2021
+
 #define IOAT_VER_1_2            0x12    /* Version 1.2 */
 #define IOAT_VER_2_0            0x20    /* Version 2.0 */
 #define IOAT_VER_3_0            0x30    /* Version 3.0 */
--- linux-4.4.0.orig/drivers/dma/ioat/init.c
+++ linux-4.4.0/drivers/dma/ioat/init.c
@@ -105,6 +105,8 @@
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX8) },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX9) },
 
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SKX) },
+
 	/* I/OAT v3.3 platforms */
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD0) },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD1) },
@@ -126,7 +128,7 @@
 ioat_init_channel(struct ioatdma_device *ioat_dma,
 		  struct ioatdma_chan *ioat_chan, int idx);
 static void ioat_intr_quirk(struct ioatdma_device *ioat_dma);
-static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma);
+static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma);
 static int ioat3_dma_self_test(struct ioatdma_device *ioat_dma);
 
 static int ioat_dca_enabled = 1;
@@ -250,10 +252,15 @@
 	}
 }
 
+static inline bool is_skx_ioat(struct pci_dev *pdev)
+{
+	return (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SKX) ? true : false;
+}
+
 static bool is_xeon_cb32(struct pci_dev *pdev)
 {
 	return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) ||
-		is_hsw_ioat(pdev) || is_bdx_ioat(pdev);
+		is_hsw_ioat(pdev) || is_bdx_ioat(pdev) || is_skx_ioat(pdev);
 }
 
 bool is_bwd_ioat(struct pci_dev *pdev)
@@ -388,7 +395,7 @@
 	if (memcmp(src, dest, IOAT_TEST_SIZE)) {
 		dev_err(dev, "Self-test copy failed compare, disabling\n");
 		err = -ENODEV;
-		goto free_resources;
+		goto unmap_dma;
 	}
 
 unmap_dma:
@@ -586,7 +593,7 @@
  * ioat_enumerate_channels - find and initialize the device's channels
  * @ioat_dma: the ioat dma device to be enumerated
  */
-static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
+static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
 {
 	struct ioatdma_chan *ioat_chan;
 	struct device *dev = &ioat_dma->pdev->dev;
@@ -605,7 +612,7 @@
 	xfercap_log = readb(ioat_dma->reg_base + IOAT_XFERCAP_OFFSET);
 	xfercap_log &= 0x1f; /* bits [4:0] valid */
 	if (xfercap_log == 0)
-		return 0;
+		return;
 	dev_dbg(dev, "%s: xfercap = %d\n", __func__, 1 << xfercap_log);
 
 	for (i = 0; i < dma->chancnt; i++) {
@@ -622,7 +629,6 @@
 		}
 	}
 	dma->chancnt = i;
-	return i;
 }
 
 /**
@@ -1203,8 +1209,15 @@
 
 		spin_lock_bh(&ioat_chan->prep_lock);
 		set_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
-		del_timer_sync(&ioat_chan->timer);
 		spin_unlock_bh(&ioat_chan->prep_lock);
+		/*
+		 * Synchronization rule for del_timer_sync():
+		 *  - The caller must not hold locks which would prevent
+		 *    completion of the timer's handler.
+		 * So prep_lock cannot be held before calling it.
+		 */
+		del_timer_sync(&ioat_chan->timer);
+
 		/* this should quiesce then reset */
 		ioat_reset_hw(ioat_chan);
 	}
@@ -1350,6 +1363,8 @@
 
 	device->version = readb(device->reg_base + IOAT_VER_OFFSET);
 	if (device->version >= IOAT_VER_3_0) {
+		if (is_skx_ioat(pdev))
+			device->version = IOAT_VER_3_2;
 		err = ioat3_dma_probe(device, ioat_dca_enabled);
 
 		if (device->version >= IOAT_VER_3_3)
--- linux-4.4.0.orig/drivers/dma/ioat/prep.c
+++ linux-4.4.0/drivers/dma/ioat/prep.c
@@ -26,7 +26,7 @@
 #include "hw.h"
 #include "dma.h"
 
-#define MAX_SCF	1024
+#define MAX_SCF	256
 
 /* provide a lookup table for setting the source address in the base or
  * extended descriptor of an xor or pq descriptor
--- linux-4.4.0.orig/drivers/dma/iop-adma.c
+++ linux-4.4.0/drivers/dma/iop-adma.c
@@ -126,9 +126,9 @@
 	list_for_each_entry_safe(iter, _iter, &iop_chan->chain,
 					chain_node) {
 		pr_debug("\tcookie: %d slot: %d busy: %d "
-			"this_desc: %#x next_desc: %#x ack: %d\n",
+			"this_desc: %#x next_desc: %#llx ack: %d\n",
 			iter->async_tx.cookie, iter->idx, busy,
-			iter->async_tx.phys, iop_desc_get_next_desc(iter),
+			iter->async_tx.phys, (u64)iop_desc_get_next_desc(iter),
 			async_tx_test_ack(&iter->async_tx));
 		prefetch(_iter);
 		prefetch(&_iter->async_tx);
@@ -316,9 +316,9 @@
 				int i;
 				dev_dbg(iop_chan->device->common.dev,
 					"allocated slot: %d "
-					"(desc %p phys: %#x) slots_per_op %d\n",
+					"(desc %p phys: %#llx) slots_per_op %d\n",
 					iter->idx, iter->hw_desc,
-					iter->async_tx.phys, slots_per_op);
+					(u64)iter->async_tx.phys, slots_per_op);
 
 				/* pre-ack all but the last descriptor */
 				if (num_slots != slots_per_op)
@@ -526,7 +526,7 @@
 		return NULL;
 	BUG_ON(len > IOP_ADMA_MAX_BYTE_COUNT);
 
-	dev_dbg(iop_chan->device->common.dev, "%s len: %u\n",
+	dev_dbg(iop_chan->device->common.dev, "%s len: %zu\n",
 		__func__, len);
 
 	spin_lock_bh(&iop_chan->lock);
@@ -559,7 +559,7 @@
 	BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT);
 
 	dev_dbg(iop_chan->device->common.dev,
-		"%s src_cnt: %d len: %u flags: %lx\n",
+		"%s src_cnt: %d len: %zu flags: %lx\n",
 		__func__, src_cnt, len, flags);
 
 	spin_lock_bh(&iop_chan->lock);
@@ -592,7 +592,7 @@
 	if (unlikely(!len))
 		return NULL;
 
-	dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n",
+	dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %zu\n",
 		__func__, src_cnt, len);
 
 	spin_lock_bh(&iop_chan->lock);
@@ -630,7 +630,7 @@
 	BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT);
 
 	dev_dbg(iop_chan->device->common.dev,
-		"%s src_cnt: %d len: %u flags: %lx\n",
+		"%s src_cnt: %d len: %zu flags: %lx\n",
 		__func__, src_cnt, len, flags);
 
 	if (dmaf_p_disabled_continue(flags))
@@ -693,7 +693,7 @@
 		return NULL;
 	BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT);
 
-	dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n",
+	dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %zu\n",
 		__func__, src_cnt, len);
 
 	spin_lock_bh(&iop_chan->lock);
--- linux-4.4.0.orig/drivers/dma/ipu/ipu_irq.c
+++ linux-4.4.0/drivers/dma/ipu/ipu_irq.c
@@ -272,7 +272,7 @@
 	u32 status;
 	int i, line;
 
-	for (i = IPU_IRQ_NR_FN_BANKS; i < IPU_IRQ_NR_BANKS; i++) {
+	for (i = 0; i < IPU_IRQ_NR_BANKS; i++) {
 		struct ipu_irq_bank *bank = irq_bank + i;
 
 		raw_spin_lock(&bank_lock);
@@ -286,22 +286,21 @@
 		raw_spin_unlock(&bank_lock);
 		while ((line = ffs(status))) {
 			struct ipu_irq_map *map;
-			unsigned int irq = NO_IRQ;
+			unsigned int irq;
 
 			line--;
 			status &= ~(1UL << line);
 
 			raw_spin_lock(&bank_lock);
 			map = src2map(32 * i + line);
-			if (map)
-				irq = map->irq;
-			raw_spin_unlock(&bank_lock);
-
 			if (!map) {
+				raw_spin_unlock(&bank_lock);
 				pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
 				       line, i);
 				continue;
 			}
+			irq = map->irq;
+			raw_spin_unlock(&bank_lock);
 			generic_handle_irq(irq);
 		}
 	}
--- linux-4.4.0.orig/drivers/dma/k3dma.c
+++ linux-4.4.0/drivers/dma/k3dma.c
@@ -660,7 +660,7 @@
 	struct k3_dma_dev *d = ofdma->of_dma_data;
 	unsigned int request = dma_spec->args[0];
 
-	if (request > d->dma_requests)
+	if (request >= d->dma_requests)
 		return NULL;
 
 	return dma_get_slave_channel(&(d->chans[request].vc.chan));
--- linux-4.4.0.orig/drivers/dma/mmp_tdma.c
+++ linux-4.4.0/drivers/dma/mmp_tdma.c
@@ -364,6 +364,8 @@
 		gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
 				size);
 	tdmac->desc_arr = NULL;
+	if (tdmac->status == DMA_ERROR)
+		tdmac->status = DMA_COMPLETE;
 
 	return;
 }
--- linux-4.4.0.orig/drivers/dma/of-dma.c
+++ linux-4.4.0/drivers/dma/of-dma.c
@@ -72,12 +72,12 @@
 		return NULL;
 
 	chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target);
-	if (chan) {
-		chan->router = ofdma->dma_router;
-		chan->route_data = route_data;
-	} else {
+	if (IS_ERR_OR_NULL(chan)) {
 		ofdma->dma_router->route_free(ofdma->dma_router->dev,
 					      route_data);
+	} else {
+		chan->router = ofdma->dma_router;
+		chan->route_data = route_data;
 	}
 
 	/*
--- linux-4.4.0.orig/drivers/dma/omap-dma.c
+++ linux-4.4.0/drivers/dma/omap-dma.c
@@ -1199,8 +1199,10 @@
 
 		rc = devm_request_irq(&pdev->dev, irq, omap_dma_irq,
 				      IRQF_SHARED, "omap-dma-engine", od);
-		if (rc)
+		if (rc) {
+			omap_dma_free(od);
 			return rc;
+		}
 	}
 
 	rc = dma_async_device_register(&od->ddev);
--- linux-4.4.0.orig/drivers/dma/pch_dma.c
+++ linux-4.4.0/drivers/dma/pch_dma.c
@@ -877,6 +877,7 @@
 	}
 
 	pci_set_master(pdev);
+	pd->dma.dev = &pdev->dev;
 
 	err = request_irq(pdev->irq, pd_irq, IRQF_SHARED, DRV_NAME, pd);
 	if (err) {
@@ -892,7 +893,6 @@
 		goto err_free_irq;
 	}
 
-	pd->dma.dev = &pdev->dev;
 
 	INIT_LIST_HEAD(&pd->dma.channels);
 
--- linux-4.4.0.orig/drivers/dma/pl330.c
+++ linux-4.4.0/drivers/dma/pl330.c
@@ -445,6 +445,9 @@
 
 	/* for cyclic capability */
 	bool cyclic;
+
+	/* for runtime pm tracking */
+	bool active;
 };
 
 struct pl330_dmac {
@@ -1003,6 +1006,7 @@
 {
 	void __iomem *regs = thrd->dmac->base;
 	u8 insn[6] = {0, 0, 0, 0, 0, 0};
+	u32 inten = readl(regs + INTEN);
 
 	if (_state(thrd) == PL330_STATE_FAULT_COMPLETING)
 		UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
@@ -1015,10 +1019,13 @@
 
 	_emit_KILL(0, insn);
 
-	/* Stop generating interrupts for SEV */
-	writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN);
-
 	_execute_DBGINSN(thrd, insn, is_manager(thrd));
+
+	/* clear the event */
+	if (inten & (1 << thrd->ev))
+		writel(1 << thrd->ev, regs + INTCLR);
+	/* Stop generating interrupts for SEV */
+	writel(inten & ~(1 << thrd->ev), regs + INTEN);
 }
 
 /* Start doing req 'idx' of thread 'thrd' */
@@ -1530,7 +1537,7 @@
 /* Returns 1 if state was updated, 0 otherwise */
 static int pl330_update(struct pl330_dmac *pl330)
 {
-	struct dma_pl330_desc *descdone, *tmp;
+	struct dma_pl330_desc *descdone;
 	unsigned long flags;
 	void __iomem *regs;
 	u32 val;
@@ -1608,7 +1615,9 @@
 	}
 
 	/* Now that we are in no hurry, do the callbacks */
-	list_for_each_entry_safe(descdone, tmp, &pl330->req_done, rqd) {
+	while (!list_empty(&pl330->req_done)) {
+		descdone = list_first_entry(&pl330->req_done,
+					    struct dma_pl330_desc, rqd);
 		list_del(&descdone->rqd);
 		spin_unlock_irqrestore(&pl330->lock, flags);
 		dma_pl330_rqcb(descdone, PL330_ERR_NONE);
@@ -1654,7 +1663,6 @@
 static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
 {
 	struct pl330_thread *thrd = NULL;
-	unsigned long flags;
 	int chans, i;
 
 	if (pl330->state == DYING)
@@ -1662,8 +1670,6 @@
 
 	chans = pl330->pcfg.num_chan;
 
-	spin_lock_irqsave(&pl330->lock, flags);
-
 	for (i = 0; i < chans; i++) {
 		thrd = &pl330->channels[i];
 		if ((thrd->free) && (!_manager_ns(thrd) ||
@@ -1681,8 +1687,6 @@
 		thrd = NULL;
 	}
 
-	spin_unlock_irqrestore(&pl330->lock, flags);
-
 	return thrd;
 }
 
@@ -1700,7 +1704,6 @@
 static void pl330_release_channel(struct pl330_thread *thrd)
 {
 	struct pl330_dmac *pl330;
-	unsigned long flags;
 
 	if (!thrd || thrd->free)
 		return;
@@ -1712,10 +1715,8 @@
 
 	pl330 = thrd->dmac;
 
-	spin_lock_irqsave(&pl330->lock, flags);
 	_free_event(thrd, thrd->ev);
 	thrd->free = true;
-	spin_unlock_irqrestore(&pl330->lock, flags);
 }
 
 /* Initialize the structure for PL330 configuration, that can be used
@@ -1994,6 +1995,7 @@
 		_stop(pch->thread);
 		spin_unlock(&pch->thread->dmac->lock);
 		power_down = true;
+		pch->active = false;
 	} else {
 		/* Make sure the PL330 Channel thread is active */
 		spin_lock(&pch->thread->dmac->lock);
@@ -2015,6 +2017,7 @@
 			desc->status = PREP;
 			list_move_tail(&desc->node, &pch->work_list);
 			if (power_down) {
+				pch->active = true;
 				spin_lock(&pch->thread->dmac->lock);
 				_start(pch->thread);
 				spin_unlock(&pch->thread->dmac->lock);
@@ -2080,20 +2083,20 @@
 	struct pl330_dmac *pl330 = pch->dmac;
 	unsigned long flags;
 
-	spin_lock_irqsave(&pch->lock, flags);
+	spin_lock_irqsave(&pl330->lock, flags);
 
 	dma_cookie_init(chan);
 	pch->cyclic = false;
 
 	pch->thread = pl330_request_channel(pl330);
 	if (!pch->thread) {
-		spin_unlock_irqrestore(&pch->lock, flags);
+		spin_unlock_irqrestore(&pl330->lock, flags);
 		return -ENOMEM;
 	}
 
 	tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
 
-	spin_unlock_irqrestore(&pch->lock, flags);
+	spin_unlock_irqrestore(&pl330->lock, flags);
 
 	return 1;
 }
@@ -2129,16 +2132,20 @@
 	unsigned long flags;
 	struct pl330_dmac *pl330 = pch->dmac;
 	LIST_HEAD(list);
+	bool power_down = false;
 
 	pm_runtime_get_sync(pl330->ddma.dev);
 	spin_lock_irqsave(&pch->lock, flags);
+
 	spin_lock(&pl330->lock);
 	_stop(pch->thread);
-	spin_unlock(&pl330->lock);
-
 	pch->thread->req[0].desc = NULL;
 	pch->thread->req[1].desc = NULL;
 	pch->thread->req_running = -1;
+	spin_unlock(&pl330->lock);
+
+	power_down = pch->active;
+	pch->active = false;
 
 	/* Mark all desc done */
 	list_for_each_entry(desc, &pch->submitted_list, node) {
@@ -2156,6 +2163,8 @@
 	list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
 	spin_unlock_irqrestore(&pch->lock, flags);
 	pm_runtime_mark_last_busy(pl330->ddma.dev);
+	if (power_down)
+		pm_runtime_put_autosuspend(pl330->ddma.dev);
 	pm_runtime_put_autosuspend(pl330->ddma.dev);
 
 	return 0;
@@ -2191,12 +2200,13 @@
 static void pl330_free_chan_resources(struct dma_chan *chan)
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
+	struct pl330_dmac *pl330 = pch->dmac;
 	unsigned long flags;
 
 	tasklet_kill(&pch->task);
 
 	pm_runtime_get_sync(pch->dmac->ddma.dev);
-	spin_lock_irqsave(&pch->lock, flags);
+	spin_lock_irqsave(&pl330->lock, flags);
 
 	pl330_release_channel(pch->thread);
 	pch->thread = NULL;
@@ -2204,7 +2214,7 @@
 	if (pch->cyclic)
 		list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
 
-	spin_unlock_irqrestore(&pch->lock, flags);
+	spin_unlock_irqrestore(&pl330->lock, flags);
 	pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
 	pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
 }
@@ -2302,6 +2312,7 @@
 		 * updated on work_list emptiness status.
 		 */
 		WARN_ON(list_empty(&pch->submitted_list));
+		pch->active = true;
 		pm_runtime_get_sync(pch->dmac->ddma.dev);
 	}
 	list_splice_tail_init(&pch->submitted_list, &pch->work_list);
@@ -2618,14 +2629,14 @@
 	while (burst != (1 << desc->rqcfg.brst_size))
 		desc->rqcfg.brst_size++;
 
+	desc->rqcfg.brst_len = get_burst_len(desc, len);
 	/*
 	 * If burst size is smaller than bus width then make sure we only
 	 * transfer one at a time to avoid a burst stradling an MFIFO entry.
 	 */
-	if (desc->rqcfg.brst_size * 8 < pl330->pcfg.data_bus_width)
+	if (burst * 8 < pl330->pcfg.data_bus_width)
 		desc->rqcfg.brst_len = 1;
 
-	desc->rqcfg.brst_len = get_burst_len(desc, len);
 	desc->bytes_requested = len;
 
 	desc->txd.flags = flags;
--- linux-4.4.0.orig/drivers/dma/pxa_dma.c
+++ linux-4.4.0/drivers/dma/pxa_dma.c
@@ -122,6 +122,7 @@
 struct pxad_device {
 	struct dma_device		slave;
 	int				nr_chans;
+	int				nr_requestors;
 	void __iomem			*base;
 	struct pxad_phy			*phys;
 	spinlock_t			phy_lock;	/* Phy association */
@@ -473,7 +474,7 @@
 		return;
 
 	/* clear the channel mapping in DRCMR */
-	if (chan->drcmr <= DRCMR_CHLNUM) {
+	if (chan->drcmr <= pdev->nr_requestors) {
 		reg = pxad_drcmr(chan->drcmr);
 		writel_relaxed(0, chan->phy->base + reg);
 	}
@@ -509,6 +510,7 @@
 
 static void phy_enable(struct pxad_phy *phy, bool misaligned)
 {
+	struct pxad_device *pdev;
 	u32 reg, dalgn;
 
 	if (!phy->vchan)
@@ -518,7 +520,8 @@
 		"%s(); phy=%p(%d) misaligned=%d\n", __func__,
 		phy, phy->idx, misaligned);
 
-	if (phy->vchan->drcmr <= DRCMR_CHLNUM) {
+	pdev = to_pxad_dev(phy->vchan->vc.chan.device);
+	if (phy->vchan->drcmr <= pdev->nr_requestors) {
 		reg = pxad_drcmr(phy->vchan->drcmr);
 		writel_relaxed(DRCMR_MAPVLD | phy->idx, phy->base + reg);
 	}
@@ -583,6 +586,8 @@
 		(PXA_DCMD_LENGTH & sizeof(u32));
 	if (flags & DMA_PREP_INTERRUPT)
 		updater->dcmd |= PXA_DCMD_ENDIRQEN;
+	if (sw_desc->cyclic)
+		sw_desc->hw_desc[sw_desc->nb_desc - 2]->ddadr = sw_desc->first;
 }
 
 static bool is_desc_completed(struct virt_dma_desc *vd)
@@ -673,6 +678,10 @@
 		dev_dbg(&chan->vc.chan.dev->device,
 			"%s(): checking txd %p[%x]: completed=%d\n",
 			__func__, vd, vd->tx.cookie, is_desc_completed(vd));
+		if (to_pxad_sw_desc(vd)->cyclic) {
+			vchan_cyclic_callback(vd);
+			break;
+		}
 		if (is_desc_completed(vd)) {
 			list_del(&vd->node);
 			vchan_cookie_complete(vd);
@@ -908,6 +917,7 @@
 {
 	u32 maxburst = 0, dev_addr = 0;
 	enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+	struct pxad_device *pdev = to_pxad_dev(chan->vc.chan.device);
 
 	*dcmd = 0;
 	if (dir == DMA_DEV_TO_MEM) {
@@ -916,7 +926,7 @@
 		dev_addr = chan->cfg.src_addr;
 		*dev_src = dev_addr;
 		*dcmd |= PXA_DCMD_INCTRGADDR;
-		if (chan->drcmr <= DRCMR_CHLNUM)
+		if (chan->drcmr <= pdev->nr_requestors)
 			*dcmd |= PXA_DCMD_FLOWSRC;
 	}
 	if (dir == DMA_MEM_TO_DEV) {
@@ -925,7 +935,7 @@
 		dev_addr = chan->cfg.dst_addr;
 		*dev_dst = dev_addr;
 		*dcmd |= PXA_DCMD_INCSRCADDR;
-		if (chan->drcmr <= DRCMR_CHLNUM)
+		if (chan->drcmr <= pdev->nr_requestors)
 			*dcmd |= PXA_DCMD_FLOWTRG;
 	}
 	if (dir == DMA_MEM_TO_MEM)
@@ -1080,7 +1090,7 @@
 		return NULL;
 
 	pxad_get_config(chan, dir, &dcmd, &dsadr, &dtadr);
-	dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH | period_len);
+	dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH & period_len);
 	dev_dbg(&chan->vc.chan.dev->device,
 		"%s(): buf_addr=0x%lx len=%zu period=%zu dir=%d flags=%lx\n",
 		__func__, (unsigned long)buf_addr, len, period_len, dir, flags);
@@ -1311,7 +1321,7 @@
 	return 0;
 }
 
-static const struct of_device_id const pxad_dt_ids[] = {
+static const struct of_device_id pxad_dt_ids[] = {
 	{ .compatible = "marvell,pdma-1.0", },
 	{}
 };
@@ -1335,13 +1345,15 @@
 
 static int pxad_init_dmadev(struct platform_device *op,
 			    struct pxad_device *pdev,
-			    unsigned int nr_phy_chans)
+			    unsigned int nr_phy_chans,
+			    unsigned int nr_requestors)
 {
 	int ret;
 	unsigned int i;
 	struct pxad_chan *c;
 
 	pdev->nr_chans = nr_phy_chans;
+	pdev->nr_requestors = nr_requestors;
 	INIT_LIST_HEAD(&pdev->slave.channels);
 	pdev->slave.device_alloc_chan_resources = pxad_alloc_chan_resources;
 	pdev->slave.device_free_chan_resources = pxad_free_chan_resources;
@@ -1376,7 +1388,7 @@
 	const struct of_device_id *of_id;
 	struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev);
 	struct resource *iores;
-	int ret, dma_channels = 0;
+	int ret, dma_channels = 0, nb_requestors = 0;
 	const enum dma_slave_buswidth widths =
 		DMA_SLAVE_BUSWIDTH_1_BYTE   | DMA_SLAVE_BUSWIDTH_2_BYTES |
 		DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1393,13 +1405,23 @@
 		return PTR_ERR(pdev->base);
 
 	of_id = of_match_device(pxad_dt_ids, &op->dev);
-	if (of_id)
+	if (of_id) {
 		of_property_read_u32(op->dev.of_node, "#dma-channels",
 				     &dma_channels);
-	else if (pdata && pdata->dma_channels)
+		ret = of_property_read_u32(op->dev.of_node, "#dma-requests",
+					   &nb_requestors);
+		if (ret) {
+			dev_warn(pdev->slave.dev,
+				 "#dma-requests set to default 32 as missing in OF: %d",
+				 ret);
+			nb_requestors = 32;
+		};
+	} else if (pdata && pdata->dma_channels) {
 		dma_channels = pdata->dma_channels;
-	else
+		nb_requestors = pdata->nb_requestors;
+	} else {
 		dma_channels = 32;	/* default 32 channel */
+	}
 
 	dma_cap_set(DMA_SLAVE, pdev->slave.cap_mask);
 	dma_cap_set(DMA_MEMCPY, pdev->slave.cap_mask);
@@ -1416,7 +1438,7 @@
 	pdev->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
 
 	pdev->slave.dev = &op->dev;
-	ret = pxad_init_dmadev(op, pdev, dma_channels);
+	ret = pxad_init_dmadev(op, pdev, dma_channels, nb_requestors);
 	if (ret) {
 		dev_err(pdev->slave.dev, "unable to register\n");
 		return ret;
@@ -1435,7 +1457,8 @@
 
 	platform_set_drvdata(op, pdev);
 	pxad_init_debugfs(pdev);
-	dev_info(pdev->slave.dev, "initialized %d channels\n", dma_channels);
+	dev_info(pdev->slave.dev, "initialized %d channels on %d requestors\n",
+		 dma_channels, nb_requestors);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/dma/qcom_bam_dma.c
+++ linux-4.4.0/drivers/dma/qcom_bam_dma.c
@@ -671,7 +671,21 @@
 
 	/* remove all transactions, including active transaction */
 	spin_lock_irqsave(&bchan->vc.lock, flag);
+	/*
+	 * If we have transactions queued, then some might be committed to the
+	 * hardware in the desc fifo.  The only way to reset the desc fifo is
+	 * to do a hardware reset (either by pipe or the entire block).
+	 * bam_chan_init_hw() will trigger a pipe reset, and also reinit the
+	 * pipe.  If the pipe is left disabled (default state after pipe reset)
+	 * and is accessed by a connected hardware engine, a fatal error in
+	 * the BAM will occur.  There is a small window where this could happen
+	 * with bam_chan_init_hw(), but it is assumed that the caller has
+	 * stopped activity on any attached hardware engine.  Make sure to do
+	 * this first so that the BAM hardware doesn't cause memory corruption
+	 * by accessing freed resources.
+	 */
 	if (bchan->curr_txd) {
+		bam_chan_init_hw(bchan, bchan->curr_txd->dir);
 		list_add(&bchan->curr_txd->vd.node, &bchan->vc.desc_issued);
 		bchan->curr_txd = NULL;
 	}
--- linux-4.4.0.orig/drivers/dma/sh/rcar-dmac.c
+++ linux-4.4.0/drivers/dma/sh/rcar-dmac.c
@@ -851,7 +851,7 @@
 
 	rcar_dmac_chan_configure_desc(chan, desc);
 
-	max_chunk_size = (RCAR_DMATCR_MASK + 1) << desc->xfer_shift;
+	max_chunk_size = RCAR_DMATCR_MASK << desc->xfer_shift;
 
 	/*
 	 * Allocate and fill the transfer chunk descriptors. We own the only
@@ -1030,7 +1030,7 @@
 	dma_addr_t dev_addr;
 
 	/* Someone calling slave DMA on a generic channel? */
-	if (rchan->mid_rid < 0 || !sg_len) {
+	if (rchan->mid_rid < 0 || !sg_len || !sg_dma_len(sgl)) {
 		dev_warn(chan->device->dev,
 			 "%s: bad parameter: len=%d, id=%d\n",
 			 __func__, sg_len, rchan->mid_rid);
--- linux-4.4.0.orig/drivers/dma/sh/usb-dmac.c
+++ linux-4.4.0/drivers/dma/sh/usb-dmac.c
@@ -117,7 +117,7 @@
 #define USB_DMASWR			0x0008
 #define USB_DMASWR_SWR			(1 << 0)
 #define USB_DMAOR			0x0060
-#define USB_DMAOR_AE			(1 << 2)
+#define USB_DMAOR_AE			(1 << 1)
 #define USB_DMAOR_DME			(1 << 0)
 
 #define USB_DMASAR			0x0000
@@ -448,7 +448,7 @@
 static int usb_dmac_chan_terminate_all(struct dma_chan *chan)
 {
 	struct usb_dmac_chan *uchan = to_usb_dmac_chan(chan);
-	struct usb_dmac_desc *desc;
+	struct usb_dmac_desc *desc, *_desc;
 	unsigned long flags;
 	LIST_HEAD(head);
 	LIST_HEAD(list);
@@ -459,7 +459,7 @@
 	if (uchan->desc)
 		uchan->desc = NULL;
 	list_splice_init(&uchan->desc_got, &list);
-	list_for_each_entry(desc, &list, node)
+	list_for_each_entry_safe(desc, _desc, &list, node)
 		list_move_tail(&desc->node, &uchan->desc_freed);
 	spin_unlock_irqrestore(&uchan->vc.lock, flags);
 	vchan_dma_desc_free_list(&uchan->vc, &head);
@@ -600,27 +600,30 @@
 {
 	struct usb_dmac_chan *chan = dev;
 	irqreturn_t ret = IRQ_NONE;
-	u32 mask = USB_DMACHCR_TE;
-	u32 check_bits = USB_DMACHCR_TE | USB_DMACHCR_SP;
+	u32 mask = 0;
 	u32 chcr;
+	bool xfer_end = false;
 
 	spin_lock(&chan->vc.lock);
 
 	chcr = usb_dmac_chan_read(chan, USB_DMACHCR);
-	if (chcr & check_bits)
-		mask |= USB_DMACHCR_DE | check_bits;
+	if (chcr & (USB_DMACHCR_TE | USB_DMACHCR_SP)) {
+		mask |= USB_DMACHCR_DE | USB_DMACHCR_TE | USB_DMACHCR_SP;
+		if (chcr & USB_DMACHCR_DE)
+			xfer_end = true;
+		ret |= IRQ_HANDLED;
+	}
 	if (chcr & USB_DMACHCR_NULL) {
 		/* An interruption of TE will happen after we set FTE */
 		mask |= USB_DMACHCR_NULL;
 		chcr |= USB_DMACHCR_FTE;
 		ret |= IRQ_HANDLED;
 	}
-	usb_dmac_chan_write(chan, USB_DMACHCR, chcr & ~mask);
+	if (mask)
+		usb_dmac_chan_write(chan, USB_DMACHCR, chcr & ~mask);
 
-	if (chcr & check_bits) {
+	if (xfer_end)
 		usb_dmac_isr_transfer_end(chan);
-		ret |= IRQ_HANDLED;
-	}
 
 	spin_unlock(&chan->vc.lock);
 
@@ -697,6 +700,8 @@
 #endif /* CONFIG_PM */
 
 static const struct dev_pm_ops usb_dmac_pm = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				      pm_runtime_force_resume)
 	SET_RUNTIME_PM_OPS(usb_dmac_runtime_suspend, usb_dmac_runtime_resume,
 			   NULL)
 };
--- linux-4.4.0.orig/drivers/dma/ste_dma40.c
+++ linux-4.4.0/drivers/dma/ste_dma40.c
@@ -142,7 +142,7 @@
  * when the DMA hw is powered off.
  * TODO: Add save/restore of D40_DREG_GCC on dma40 v3 or later, if that works.
  */
-static u32 d40_backup_regs[] = {
+static __maybe_unused u32 d40_backup_regs[] = {
 	D40_DREG_LCPA,
 	D40_DREG_LCLA,
 	D40_DREG_PRMSE,
@@ -211,7 +211,7 @@
 
 #define BACKUP_REGS_SZ_V4B ARRAY_SIZE(d40_backup_regs_v4b)
 
-static u32 d40_backup_regs_chan[] = {
+static __maybe_unused u32 d40_backup_regs_chan[] = {
 	D40_CHAN_REG_SSCFG,
 	D40_CHAN_REG_SSELT,
 	D40_CHAN_REG_SSPTR,
--- linux-4.4.0.orig/drivers/dma/tegra20-apb-dma.c
+++ linux-4.4.0/drivers/dma/tegra20-apb-dma.c
@@ -285,7 +285,7 @@
 
 	/* 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)) {
+		if (async_tx_test_ack(&dma_desc->txd) && !dma_desc->cb_count) {
 			list_del(&dma_desc->node);
 			spin_unlock_irqrestore(&tdc->lock, flags);
 			dma_desc->txd.flags = 0;
@@ -632,7 +632,10 @@
 
 	sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node);
 	dma_desc = sgreq->dma_desc;
-	dma_desc->bytes_transferred += sgreq->req_len;
+	/* if we dma for long enough the transfer count will wrap */
+	dma_desc->bytes_transferred =
+		(dma_desc->bytes_transferred + sgreq->req_len) %
+		dma_desc->bytes_requested;
 
 	/* Callback need to be call */
 	if (!dma_desc->cb_count)
@@ -751,10 +754,6 @@
 	bool was_busy;
 
 	spin_lock_irqsave(&tdc->lock, flags);
-	if (list_empty(&tdc->pending_sg_req)) {
-		spin_unlock_irqrestore(&tdc->lock, flags);
-		return 0;
-	}
 
 	if (!tdc->busy)
 		goto skip_dma_stop;
@@ -1208,8 +1207,7 @@
 
 	dev_dbg(tdc2dev(tdc), "Freeing channel %d\n", tdc->id);
 
-	if (tdc->busy)
-		tegra_dma_terminate_all(dc);
+	tegra_dma_terminate_all(dc);
 
 	spin_lock_irqsave(&tdc->lock, flags);
 	list_splice_init(&tdc->pending_sg_req, &sg_req_list);
--- linux-4.4.0.orig/drivers/dma/ti-dma-crossbar.c
+++ linux-4.4.0/drivers/dma/ti-dma-crossbar.c
@@ -46,12 +46,20 @@
 
 struct ti_am335x_xbar_map {
 	u16 dma_line;
-	u16 mux_val;
+	u8 mux_val;
 };
 
-static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u16 val)
+static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u8 val)
 {
-	writeb_relaxed(val & 0x1f, iomem + event);
+	/*
+	 * TPCC_EVT_MUX_60_63 register layout is different than the
+	 * rest, in the sense, that event 63 is mapped to lowest byte
+	 * and event 60 is mapped to highest, handle it separately.
+	 */
+	if (event >= 60 && event <= 63)
+		writeb_relaxed(val, iomem + (63 - event % 4));
+	else
+		writeb_relaxed(val, iomem + event);
 }
 
 static void ti_am335x_xbar_free(struct device *dev, void *route_data)
@@ -102,7 +110,7 @@
 	}
 
 	map->dma_line = (u16)dma_spec->args[0];
-	map->mux_val = (u16)dma_spec->args[2];
+	map->mux_val = (u8)dma_spec->args[2];
 
 	dma_spec->args[2] = 0;
 	dma_spec->args_count = 2;
@@ -146,6 +154,7 @@
 	match = of_match_node(ti_am335x_master_match, dma_node);
 	if (!match) {
 		dev_err(&pdev->dev, "DMA master is not supported\n");
+		of_node_put(dma_node);
 		return -EINVAL;
 	}
 
@@ -310,6 +319,7 @@
 	match = of_match_node(ti_dra7_master_match, dma_node);
 	if (!match) {
 		dev_err(&pdev->dev, "DMA master is not supported\n");
+		of_node_put(dma_node);
 		return -EINVAL;
 	}
 
--- linux-4.4.0.orig/drivers/dma/timb_dma.c
+++ linux-4.4.0/drivers/dma/timb_dma.c
@@ -552,7 +552,7 @@
 	}
 
 	dma_sync_single_for_device(chan2dmadev(chan), td_desc->txd.phys,
-		td_desc->desc_list_len, DMA_MEM_TO_DEV);
+		td_desc->desc_list_len, DMA_TO_DEVICE);
 
 	return &td_desc->txd;
 }
--- linux-4.4.0.orig/drivers/dma/zx296702_dma.c
+++ linux-4.4.0/drivers/dma/zx296702_dma.c
@@ -26,7 +26,7 @@
 
 #define DRIVER_NAME		"zx-dma"
 #define DMA_ALIGN		4
-#define DMA_MAX_SIZE		(0x10000 - PAGE_SIZE)
+#define DMA_MAX_SIZE		(0x10000 - 512)
 #define LLI_BLOCK_SIZE		(4 * PAGE_SIZE)
 
 #define REG_ZX_SRC_ADDR			0x00
@@ -813,6 +813,7 @@
 	INIT_LIST_HEAD(&d->slave.channels);
 	dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
 	dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
+	dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
 	dma_cap_set(DMA_PRIVATE, d->slave.cap_mask);
 	d->slave.dev = &op->dev;
 	d->slave.device_free_chan_resources = zx_dma_free_chan_resources;
--- linux-4.4.0.orig/drivers/edac/Kconfig
+++ linux-4.4.0/drivers/edac/Kconfig
@@ -251,6 +251,14 @@
 	  Support for error detection and correction the Intel
 	  Sandy Bridge, Ivy Bridge and Haswell Integrated Memory Controllers.
 
+config EDAC_SKX
+	tristate "Intel Skylake server Integrated MC"
+	depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
+	depends on PCI_MMCONFIG
+	help
+	  Support for error detection and correction the Intel
+	  Skylake server Integrated Memory Controllers.
+
 config EDAC_MPC85XX
 	tristate "Freescale MPC83xx / MPC85xx"
 	depends on EDAC_MM_EDAC && FSL_SOC
--- linux-4.4.0.orig/drivers/edac/Makefile
+++ linux-4.4.0/drivers/edac/Makefile
@@ -31,6 +31,7 @@
 obj-$(CONFIG_EDAC_I7300)		+= i7300_edac.o
 obj-$(CONFIG_EDAC_I7CORE)		+= i7core_edac.o
 obj-$(CONFIG_EDAC_SBRIDGE)		+= sb_edac.o
+obj-$(CONFIG_EDAC_SKX)			+= skx_edac.o
 obj-$(CONFIG_EDAC_E7XXX)		+= e7xxx_edac.o
 obj-$(CONFIG_EDAC_E752X)		+= e752x_edac.o
 obj-$(CONFIG_EDAC_I82443BXGX)		+= i82443bxgx_edac.o
--- linux-4.4.0.orig/drivers/edac/amd64_edac.c
+++ linux-4.4.0/drivers/edac/amd64_edac.c
@@ -248,6 +248,8 @@
 
 		if (pvt->model == 0x60)
 			amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval);
+		else
+			amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
 	} else
 		amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
 
@@ -1452,7 +1454,7 @@
 	u64 chan_off;
 	u64 dram_base		= get_dram_base(pvt, range);
 	u64 hole_off		= f10_dhar_offset(pvt);
-	u64 dct_sel_base_off	= (pvt->dct_sel_hi & 0xFFFFFC00) << 16;
+	u64 dct_sel_base_off	= (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16;
 
 	if (hi_rng) {
 		/*
@@ -2715,7 +2717,7 @@
 	struct amd64_family_type *fam_type = NULL;
 
 	pvt->ext_model  = boot_cpu_data.x86_model >> 4;
-	pvt->stepping	= boot_cpu_data.x86_mask;
+	pvt->stepping	= boot_cpu_data.x86_stepping;
 	pvt->model	= boot_cpu_data.x86_model;
 	pvt->fam	= boot_cpu_data.x86;
 
--- linux-4.4.0.orig/drivers/edac/edac_device.c
+++ linux-4.4.0/drivers/edac/edac_device.c
@@ -435,16 +435,13 @@
  */
 void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
 {
-	int status;
-
 	if (!edac_dev->edac_check)
 		return;
 
-	status = cancel_delayed_work(&edac_dev->work);
-	if (status == 0) {
-		/* workq instance might be running, wait for it */
-		flush_workqueue(edac_workqueue);
-	}
+	edac_dev->op_state = OP_OFFLINE;
+
+	cancel_delayed_work_sync(&edac_dev->work);
+	flush_workqueue(edac_workqueue);
 }
 
 /*
--- linux-4.4.0.orig/drivers/edac/edac_device_sysfs.c
+++ linux-4.4.0/drivers/edac/edac_device_sysfs.c
@@ -280,6 +280,7 @@
 
 	/* Error exit stack */
 err_kobj_reg:
+	kobject_put(&edac_dev->kobj);
 	module_put(edac_dev->owner);
 
 err_mod_get:
--- linux-4.4.0.orig/drivers/edac/edac_mc.c
+++ linux-4.4.0/drivers/edac/edac_mc.c
@@ -586,18 +586,10 @@
  */
 static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
 {
-	int status;
-
-	if (mci->op_state != OP_RUNNING_POLL)
-		return;
-
-	status = cancel_delayed_work(&mci->work);
-	if (status == 0) {
-		edac_dbg(0, "not canceled, flush the queue\n");
+	mci->op_state = OP_OFFLINE;
 
-		/* workq instance might be running, wait for it */
-		flush_workqueue(edac_workqueue);
-	}
+	cancel_delayed_work_sync(&mci->work);
+	flush_workqueue(edac_workqueue);
 }
 
 /*
@@ -974,7 +966,7 @@
 	mci->ue_mc += count;
 
 	if (!enable_per_layer_report) {
-		mci->ce_noinfo_count += count;
+		mci->ue_noinfo_count += count;
 		return;
 	}
 
--- linux-4.4.0.orig/drivers/edac/edac_mc_sysfs.c
+++ linux-4.4.0/drivers/edac/edac_mc_sysfs.c
@@ -26,7 +26,7 @@
 static int edac_mc_log_ue = 1;
 static int edac_mc_log_ce = 1;
 static int edac_mc_panic_on_ue;
-static int edac_mc_poll_msec = 1000;
+static unsigned int edac_mc_poll_msec = 1000;
 
 /* Getter functions for above */
 int edac_mc_get_log_ue(void)
@@ -45,30 +45,30 @@
 }
 
 /* this is temporary */
-int edac_mc_get_poll_msec(void)
+unsigned int edac_mc_get_poll_msec(void)
 {
 	return edac_mc_poll_msec;
 }
 
 static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
 {
-	unsigned long l;
+	unsigned int i;
 	int ret;
 
 	if (!val)
 		return -EINVAL;
 
-	ret = kstrtoul(val, 0, &l);
+	ret = kstrtouint(val, 0, &i);
 	if (ret)
 		return ret;
 
-	if (l < 1000)
+	if (i < 1000)
 		return -EINVAL;
 
-	*((unsigned long *)kp->arg) = l;
+	*((unsigned int *)kp->arg) = i;
 
 	/* notify edac_mc engine to reset the poll period */
-	edac_mc_reset_delay_period(l);
+	edac_mc_reset_delay_period(i);
 
 	return 0;
 }
@@ -82,7 +82,7 @@
 module_param(edac_mc_log_ce, int, 0644);
 MODULE_PARM_DESC(edac_mc_log_ce,
 		 "Log correctable error to console: 0=off 1=on");
-module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int,
+module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_uint,
 		  &edac_mc_poll_msec, 0644);
 MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
 
@@ -313,7 +313,6 @@
  * possible dynamic channel DIMM Label attribute files
  *
  */
-
 DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
 	channel_dimm_label_show, channel_dimm_label_store, 0);
 DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
@@ -326,6 +325,10 @@
 	channel_dimm_label_show, channel_dimm_label_store, 4);
 DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
 	channel_dimm_label_show, channel_dimm_label_store, 5);
+DEVICE_CHANNEL(ch6_dimm_label, S_IRUGO | S_IWUSR,
+	channel_dimm_label_show, channel_dimm_label_store, 6);
+DEVICE_CHANNEL(ch7_dimm_label, S_IRUGO | S_IWUSR,
+	channel_dimm_label_show, channel_dimm_label_store, 7);
 
 /* Total possible dynamic DIMM Label attribute file table */
 static struct attribute *dynamic_csrow_dimm_attr[] = {
@@ -335,6 +338,8 @@
 	&dev_attr_legacy_ch3_dimm_label.attr.attr,
 	&dev_attr_legacy_ch4_dimm_label.attr.attr,
 	&dev_attr_legacy_ch5_dimm_label.attr.attr,
+	&dev_attr_legacy_ch6_dimm_label.attr.attr,
+	&dev_attr_legacy_ch7_dimm_label.attr.attr,
 	NULL
 };
 
@@ -351,6 +356,10 @@
 		   channel_ce_count_show, NULL, 4);
 DEVICE_CHANNEL(ch5_ce_count, S_IRUGO,
 		   channel_ce_count_show, NULL, 5);
+DEVICE_CHANNEL(ch6_ce_count, S_IRUGO,
+		   channel_ce_count_show, NULL, 6);
+DEVICE_CHANNEL(ch7_ce_count, S_IRUGO,
+		   channel_ce_count_show, NULL, 7);
 
 /* Total possible dynamic ce_count attribute file table */
 static struct attribute *dynamic_csrow_ce_count_attr[] = {
@@ -360,6 +369,8 @@
 	&dev_attr_legacy_ch3_ce_count.attr.attr,
 	&dev_attr_legacy_ch4_ce_count.attr.attr,
 	&dev_attr_legacy_ch5_ce_count.attr.attr,
+	&dev_attr_legacy_ch6_ce_count.attr.attr,
+	&dev_attr_legacy_ch7_ce_count.attr.attr,
 	NULL
 };
 
@@ -371,9 +382,16 @@
 
 	if (idx >= csrow->nr_channels)
 		return 0;
+
+	if (idx >= ARRAY_SIZE(dynamic_csrow_ce_count_attr) - 1) {
+		WARN_ONCE(1, "idx: %d\n", idx);
+		return 0;
+	}
+
 	/* Only expose populated DIMMs */
 	if (!csrow->channels[idx]->dimm->nr_pages)
 		return 0;
+
 	return attr->mode;
 }
 
@@ -408,6 +426,8 @@
 static int edac_create_csrow_object(struct mem_ctl_info *mci,
 				    struct csrow_info *csrow, int index)
 {
+	int err;
+
 	csrow->dev.type = &csrow_attr_type;
 	csrow->dev.bus = mci->bus;
 	csrow->dev.groups = csrow_dev_groups;
@@ -420,7 +440,11 @@
 	edac_dbg(0, "creating (virtual) csrow node %s\n",
 		 dev_name(&csrow->dev));
 
-	return device_add(&csrow->dev);
+	err = device_add(&csrow->dev);
+	if (err)
+		put_device(&csrow->dev);
+
+	return err;
 }
 
 /* Create a CSROW object under specifed edac_mc_device */
@@ -880,21 +904,26 @@
 int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
 				 const struct attribute_group **groups)
 {
+	char *name;
 	int i, err;
 
 	/*
 	 * 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)
+	name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+	if (!name)
 		return -ENOMEM;
 
+	mci->bus->name = name;
+
 	edac_dbg(0, "creating bus %s\n", mci->bus->name);
 
 	err = bus_register(mci->bus);
-	if (err < 0)
-		goto fail_free_name;
+	if (err < 0) {
+		kfree(name);
+		return err;
+	}
 
 	/* get the /sys/devices/system/edac subsys reference */
 	mci->dev.type = &mci_attr_type;
@@ -961,8 +990,8 @@
 	device_unregister(&mci->dev);
 fail_unregister_bus:
 	bus_unregister(mci->bus);
-fail_free_name:
-	kfree(mci->bus->name);
+	kfree(name);
+
 	return err;
 }
 
@@ -993,10 +1022,12 @@
 
 void edac_unregister_sysfs(struct mem_ctl_info *mci)
 {
+	const char *name = mci->bus->name;
+
 	edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
 	device_unregister(&mci->dev);
 	bus_unregister(mci->bus);
-	kfree(mci->bus->name);
+	kfree(name);
 }
 
 static void mc_attr_release(struct device *dev)
--- linux-4.4.0.orig/drivers/edac/edac_module.h
+++ linux-4.4.0/drivers/edac/edac_module.h
@@ -33,7 +33,7 @@
 extern int edac_mc_get_log_ce(void);
 extern int edac_mc_get_panic_on_ue(void);
 extern int edac_get_poll_msec(void);
-extern int edac_mc_get_poll_msec(void);
+extern unsigned int edac_mc_get_poll_msec(void);
 
 unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
 				 unsigned len);
--- linux-4.4.0.orig/drivers/edac/edac_pci.c
+++ linux-4.4.0/drivers/edac/edac_pci.c
@@ -274,13 +274,12 @@
  */
 static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 {
-	int status;
-
 	edac_dbg(0, "\n");
 
-	status = cancel_delayed_work(&pci->work);
-	if (status == 0)
-		flush_workqueue(edac_workqueue);
+	pci->op_state = OP_OFFLINE;
+
+	cancel_delayed_work_sync(&pci->work);
+	flush_workqueue(edac_workqueue);
 }
 
 /*
--- linux-4.4.0.orig/drivers/edac/edac_pci_sysfs.c
+++ linux-4.4.0/drivers/edac/edac_pci_sysfs.c
@@ -394,7 +394,7 @@
 
 	/* Error unwind statck */
 kobject_init_and_add_fail:
-	kfree(edac_pci_top_main_kobj);
+	kobject_put(edac_pci_top_main_kobj);
 
 kzalloc_fail:
 	module_put(THIS_MODULE);
--- linux-4.4.0.orig/drivers/edac/ghes_edac.c
+++ linux-4.4.0/drivers/edac/ghes_edac.c
@@ -189,6 +189,7 @@
 	/* Cleans the error report buffer */
 	memset(e, 0, sizeof (*e));
 	e->error_count = 1;
+	e->grain = 1;
 	strcpy(e->label, "unknown label");
 	e->msg = pvt->msg;
 	e->other_detail = pvt->other_detail;
@@ -284,7 +285,7 @@
 
 	/* Error grain */
 	if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK)
-		e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK);
+		e->grain = ~mem_err->physical_addr_mask + 1;
 
 	/* Memory error location, mapped on e->location */
 	p = e->location;
@@ -391,8 +392,13 @@
 	if (p > pvt->other_detail)
 		*(p - 1) = '\0';
 
+	/* Sanity-check driver-supplied grain value. */
+	if (WARN_ON_ONCE(!e->grain))
+		e->grain = 1;
+
+	grain_bits = fls_long(e->grain - 1);
+
 	/* Generate the trace event */
-	grain_bits = fls_long(e->grain);
 	snprintf(pvt->detail_location, sizeof(pvt->detail_location),
 		 "APEI location: %s %s", e->location, e->other_detail);
 	trace_mc_event(type, e->msg, e->label, e->error_count,
--- linux-4.4.0.orig/drivers/edac/i5000_edac.c
+++ linux-4.4.0/drivers/edac/i5000_edac.c
@@ -227,7 +227,7 @@
 #define			NREC_RDWR(x)		(((x)>>11) & 1)
 #define			NREC_RANK(x)		(((x)>>8) & 0x7)
 #define		NRECMEMB		0xC0
-#define			NREC_CAS(x)		(((x)>>16) & 0xFFFFFF)
+#define			NREC_CAS(x)		(((x)>>16) & 0xFFF)
 #define			NREC_RAS(x)		((x) & 0x7FFF)
 #define		NRECFGLOG		0xC4
 #define		NREEECFBDA		0xC8
@@ -371,7 +371,7 @@
 	/* These registers are input ONLY if there was a
 	 * Non-Recoverable Error */
 	u16 nrecmema;		/* Non-Recoverable Mem log A */
-	u16 nrecmemb;		/* Non-Recoverable Mem log B */
+	u32 nrecmemb;		/* Non-Recoverable Mem log B */
 
 };
 
@@ -407,7 +407,7 @@
 				NERR_FAT_FBD, &info->nerr_fat_fbd);
 		pci_read_config_word(pvt->branchmap_werrors,
 				NRECMEMA, &info->nrecmema);
-		pci_read_config_word(pvt->branchmap_werrors,
+		pci_read_config_dword(pvt->branchmap_werrors,
 				NRECMEMB, &info->nrecmemb);
 
 		/* Clear the error bits, by writing them back */
@@ -1293,7 +1293,7 @@
 			dimm->mtype = MEM_FB_DDR2;
 
 			/* ask what device type on this row */
-			if (MTR_DRAM_WIDTH(mtr))
+			if (MTR_DRAM_WIDTH(mtr) == 8)
 				dimm->dtype = DEV_X8;
 			else
 				dimm->dtype = DEV_X4;
--- linux-4.4.0.orig/drivers/edac/i5100_edac.c
+++ linux-4.4.0/drivers/edac/i5100_edac.c
@@ -1075,16 +1075,15 @@
 				    PCI_DEVICE_ID_INTEL_5100_19, 0);
 	if (!einj) {
 		ret = -ENODEV;
-		goto bail_einj;
+		goto bail_mc_free;
 	}
 
 	rc = pci_enable_device(einj);
 	if (rc < 0) {
 		ret = rc;
-		goto bail_disable_einj;
+		goto bail_einj;
 	}
 
-
 	mci->pdev = &pdev->dev;
 
 	priv = mci->pvt_info;
@@ -1151,14 +1150,14 @@
 bail_scrub:
 	priv->scrub_enable = 0;
 	cancel_delayed_work_sync(&(priv->i5100_scrubbing));
-	edac_mc_free(mci);
-
-bail_disable_einj:
 	pci_disable_device(einj);
 
 bail_einj:
 	pci_dev_put(einj);
 
+bail_mc_free:
+	edac_mc_free(mci);
+
 bail_disable_ch1:
 	pci_disable_device(ch1mm);
 
--- linux-4.4.0.orig/drivers/edac/i5400_edac.c
+++ linux-4.4.0/drivers/edac/i5400_edac.c
@@ -368,7 +368,7 @@
 
 	/* These registers are input ONLY if there was a Non-Rec Error */
 	u16 nrecmema;		/* Non-Recoverable Mem log A */
-	u16 nrecmemb;		/* Non-Recoverable Mem log B */
+	u32 nrecmemb;		/* Non-Recoverable Mem log B */
 
 };
 
@@ -458,7 +458,7 @@
 				NERR_FAT_FBD, &info->nerr_fat_fbd);
 		pci_read_config_word(pvt->branchmap_werrors,
 				NRECMEMA, &info->nrecmema);
-		pci_read_config_word(pvt->branchmap_werrors,
+		pci_read_config_dword(pvt->branchmap_werrors,
 				NRECMEMB, &info->nrecmemb);
 
 		/* Clear the error bits, by writing them back */
@@ -1207,13 +1207,14 @@
 
 			dimm->nr_pages = size_mb << 8;
 			dimm->grain = 8;
-			dimm->dtype = MTR_DRAM_WIDTH(mtr) ? DEV_X8 : DEV_X4;
+			dimm->dtype = MTR_DRAM_WIDTH(mtr) == 8 ?
+				      DEV_X8 : DEV_X4;
 			dimm->mtype = MEM_FB_DDR2;
 			/*
 			 * The eccc mechanism is SDDC (aka SECC), with
 			 * is similar to Chipkill.
 			 */
-			dimm->edac_mode = MTR_DRAM_WIDTH(mtr) ?
+			dimm->edac_mode = MTR_DRAM_WIDTH(mtr) == 8 ?
 					  EDAC_S8ECD8ED : EDAC_S4ECD4ED;
 			ndimms++;
 		}
--- linux-4.4.0.orig/drivers/edac/i7core_edac.c
+++ linux-4.4.0/drivers/edac/i7core_edac.c
@@ -1187,15 +1187,14 @@
 
 	rc = device_add(pvt->addrmatch_dev);
 	if (rc < 0)
-		return rc;
+		goto err_put_addrmatch;
 
 	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 -ENOMEM;
+			rc = -ENOMEM;
+			goto err_del_addrmatch;
 		}
 
 		pvt->chancounts_dev->type = &all_channel_counts_type;
@@ -1209,9 +1208,18 @@
 
 		rc = device_add(pvt->chancounts_dev);
 		if (rc < 0)
-			return rc;
+			goto err_put_chancounts;
 	}
 	return 0;
+
+err_put_chancounts:
+	put_device(pvt->chancounts_dev);
+err_del_addrmatch:
+	device_del(pvt->addrmatch_dev);
+err_put_addrmatch:
+	put_device(pvt->addrmatch_dev);
+
+	return rc;
 }
 
 static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci)
@@ -1221,11 +1229,11 @@
 	edac_dbg(1, "\n");
 
 	if (!pvt->is_registered) {
-		put_device(pvt->chancounts_dev);
 		device_del(pvt->chancounts_dev);
+		put_device(pvt->chancounts_dev);
 	}
-	put_device(pvt->addrmatch_dev);
 	device_del(pvt->addrmatch_dev);
+	put_device(pvt->addrmatch_dev);
 }
 
 /****************************************************************************
@@ -1866,7 +1874,7 @@
 
 	i7_dev = get_i7core_dev(mce->socketid);
 	if (!i7_dev)
-		return NOTIFY_BAD;
+		return NOTIFY_DONE;
 
 	mci = i7_dev->mci;
 	pvt = mci->pvt_info;
--- linux-4.4.0.orig/drivers/edac/ie31200_edac.c
+++ linux-4.4.0/drivers/edac/ie31200_edac.c
@@ -17,6 +17,7 @@
  * 015c: Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller
  * 0c04: Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller
  * 0c08: Xeon E3-1200 v3 Processor DRAM Controller
+ * 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers
  *
  * Based on Intel specification:
  * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf
@@ -55,6 +56,7 @@
 #define PCI_DEVICE_ID_INTEL_IE31200_HB_5 0x015c
 #define PCI_DEVICE_ID_INTEL_IE31200_HB_6 0x0c04
 #define PCI_DEVICE_ID_INTEL_IE31200_HB_7 0x0c08
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918
 
 #define IE31200_DIMMS			4
 #define IE31200_RANKS			8
@@ -105,8 +107,11 @@
  *    1  Multiple Bit Error Status (MERRSTS)
  *    0  Correctable Error Status (CERRSTS)
  */
+
 #define IE31200_C0ECCERRLOG			0x40c8
 #define IE31200_C1ECCERRLOG			0x44c8
+#define IE31200_C0ECCERRLOG_SKL			0x4048
+#define IE31200_C1ECCERRLOG_SKL			0x4448
 #define IE31200_ECCERRLOG_CE			BIT(0)
 #define IE31200_ECCERRLOG_UE			BIT(1)
 #define IE31200_ECCERRLOG_RANK_BITS		GENMASK_ULL(28, 27)
@@ -123,17 +128,30 @@
 #define IE31200_CAPID0_DDPCD		BIT(6)
 #define IE31200_CAPID0_ECC		BIT(1)
 
-#define IE31200_MAD_DIMM_0_OFFSET	0x5004
-#define IE31200_MAD_DIMM_SIZE		GENMASK_ULL(7, 0)
-#define IE31200_MAD_DIMM_A_RANK		BIT(17)
-#define IE31200_MAD_DIMM_A_WIDTH	BIT(19)
-
-#define IE31200_PAGES(n)		(n << (28 - PAGE_SHIFT))
+#define IE31200_MAD_DIMM_0_OFFSET		0x5004
+#define IE31200_MAD_DIMM_0_OFFSET_SKL		0x500C
+#define IE31200_MAD_DIMM_SIZE			GENMASK_ULL(7, 0)
+#define IE31200_MAD_DIMM_A_RANK			BIT(17)
+#define IE31200_MAD_DIMM_A_RANK_SHIFT		17
+#define IE31200_MAD_DIMM_A_RANK_SKL		BIT(10)
+#define IE31200_MAD_DIMM_A_RANK_SKL_SHIFT	10
+#define IE31200_MAD_DIMM_A_WIDTH		BIT(19)
+#define IE31200_MAD_DIMM_A_WIDTH_SHIFT		19
+#define IE31200_MAD_DIMM_A_WIDTH_SKL		GENMASK_ULL(9, 8)
+#define IE31200_MAD_DIMM_A_WIDTH_SKL_SHIFT	8
+
+/* Skylake reports 1GB increments, everything else is 256MB */
+#define IE31200_PAGES(n, skl)	\
+	(n << (28 + (2 * skl) - PAGE_SHIFT))
 
 static int nr_channels;
+static struct pci_dev *mci_pdev;
+static int ie31200_registered = 1;
 
 struct ie31200_priv {
 	void __iomem *window;
+	void __iomem *c0errlog;
+	void __iomem *c1errlog;
 };
 
 enum ie31200_chips {
@@ -157,9 +175,9 @@
 };
 
 struct dimm_data {
-	u8 size; /* in 256MB multiples */
+	u8 size; /* in multiples of 256MB, except Skylake is 1GB */
 	u8 dual_rank : 1,
-	   x16_width : 1; /* 0 means x8 width */
+	   x16_width : 2; /* 0 means x8 width */
 };
 
 static int how_many_channels(struct pci_dev *pdev)
@@ -197,11 +215,10 @@
 	return true;
 }
 
-static int eccerrlog_row(int channel, u64 log)
+static int eccerrlog_row(u64 log)
 {
-	int rank = ((log & IE31200_ECCERRLOG_RANK_BITS) >>
-		IE31200_ECCERRLOG_RANK_SHIFT);
-	return rank | (channel * IE31200_RANKS_PER_CHANNEL);
+	return ((log & IE31200_ECCERRLOG_RANK_BITS) >>
+				IE31200_ECCERRLOG_RANK_SHIFT);
 }
 
 static void ie31200_clear_error_info(struct mem_ctl_info *mci)
@@ -219,7 +236,6 @@
 {
 	struct pci_dev *pdev;
 	struct ie31200_priv *priv = mci->pvt_info;
-	void __iomem *window = priv->window;
 
 	pdev = to_pci_dev(mci->pdev);
 
@@ -232,9 +248,9 @@
 	if (!(info->errsts & IE31200_ERRSTS_BITS))
 		return;
 
-	info->eccerrlog[0] = lo_hi_readq(window + IE31200_C0ECCERRLOG);
+	info->eccerrlog[0] = lo_hi_readq(priv->c0errlog);
 	if (nr_channels == 2)
-		info->eccerrlog[1] = lo_hi_readq(window + IE31200_C1ECCERRLOG);
+		info->eccerrlog[1] = lo_hi_readq(priv->c1errlog);
 
 	pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts2);
 
@@ -245,10 +261,10 @@
 	 * should be UE info.
 	 */
 	if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) {
-		info->eccerrlog[0] = lo_hi_readq(window + IE31200_C0ECCERRLOG);
+		info->eccerrlog[0] = lo_hi_readq(priv->c0errlog);
 		if (nr_channels == 2)
 			info->eccerrlog[1] =
-				lo_hi_readq(window + IE31200_C1ECCERRLOG);
+				lo_hi_readq(priv->c1errlog);
 	}
 
 	ie31200_clear_error_info(mci);
@@ -274,14 +290,14 @@
 		if (log & IE31200_ECCERRLOG_UE) {
 			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					     0, 0, 0,
-					     eccerrlog_row(channel, log),
+					     eccerrlog_row(log),
 					     channel, -1,
 					     "ie31200 UE", "");
 		} else if (log & IE31200_ECCERRLOG_CE) {
 			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 					     0, 0,
 					     IE31200_ECCERRLOG_SYNDROME(log),
-					     eccerrlog_row(channel, log),
+					     eccerrlog_row(log),
 					     channel, -1,
 					     "ie31200 CE", "");
 		}
@@ -326,6 +342,33 @@
 	return window;
 }
 
+static void __skl_populate_dimm_info(struct dimm_data *dd, u32 addr_decode,
+				     int chan)
+{
+	dd->size = (addr_decode >> (chan << 4)) & IE31200_MAD_DIMM_SIZE;
+	dd->dual_rank = (addr_decode & (IE31200_MAD_DIMM_A_RANK_SKL << (chan << 4))) ? 1 : 0;
+	dd->x16_width = ((addr_decode & (IE31200_MAD_DIMM_A_WIDTH_SKL << (chan << 4))) >>
+				(IE31200_MAD_DIMM_A_WIDTH_SKL_SHIFT + (chan << 4)));
+}
+
+static void __populate_dimm_info(struct dimm_data *dd, u32 addr_decode,
+				 int chan)
+{
+	dd->size = (addr_decode >> (chan << 3)) & IE31200_MAD_DIMM_SIZE;
+	dd->dual_rank = (addr_decode & (IE31200_MAD_DIMM_A_RANK << chan)) ? 1 : 0;
+	dd->x16_width = (addr_decode & (IE31200_MAD_DIMM_A_WIDTH << chan)) ? 1 : 0;
+}
+
+static void populate_dimm_info(struct dimm_data *dd, u32 addr_decode, int chan,
+			       bool skl)
+{
+	if (skl)
+		__skl_populate_dimm_info(dd, addr_decode, chan);
+	else
+		__populate_dimm_info(dd, addr_decode, chan);
+}
+
+
 static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
 {
 	int i, j, ret;
@@ -334,7 +377,8 @@
 	struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL];
 	void __iomem *window;
 	struct ie31200_priv *priv;
-	u32 addr_decode;
+	u32 addr_decode, mad_offset;
+	bool skl = (pdev->device == PCI_DEVICE_ID_INTEL_IE31200_HB_8);
 
 	edac_dbg(0, "MC:\n");
 
@@ -363,7 +407,10 @@
 
 	edac_dbg(3, "MC: init mci\n");
 	mci->pdev = &pdev->dev;
-	mci->mtype_cap = MEM_FLAG_DDR3;
+	if (skl)
+		mci->mtype_cap = MEM_FLAG_DDR4;
+	else
+		mci->mtype_cap = MEM_FLAG_DDR3;
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_SECDED;
 	mci->mod_name = EDAC_MOD_STR;
@@ -374,19 +421,24 @@
 	mci->ctl_page_to_phys = NULL;
 	priv = mci->pvt_info;
 	priv->window = window;
+	if (skl) {
+		priv->c0errlog = window + IE31200_C0ECCERRLOG_SKL;
+		priv->c1errlog = window + IE31200_C1ECCERRLOG_SKL;
+		mad_offset = IE31200_MAD_DIMM_0_OFFSET_SKL;
+	} else {
+		priv->c0errlog = window + IE31200_C0ECCERRLOG;
+		priv->c1errlog = window + IE31200_C1ECCERRLOG;
+		mad_offset = IE31200_MAD_DIMM_0_OFFSET;
+	}
 
 	/* populate DIMM info */
 	for (i = 0; i < IE31200_CHANNELS; i++) {
-		addr_decode = readl(window + IE31200_MAD_DIMM_0_OFFSET +
+		addr_decode = readl(window + mad_offset +
 					(i * 4));
 		edac_dbg(0, "addr_decode: 0x%x\n", addr_decode);
 		for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) {
-			dimm_info[i][j].size = (addr_decode >> (j * 8)) &
-						IE31200_MAD_DIMM_SIZE;
-			dimm_info[i][j].dual_rank = (addr_decode &
-				(IE31200_MAD_DIMM_A_RANK << j)) ? 1 : 0;
-			dimm_info[i][j].x16_width = (addr_decode &
-				(IE31200_MAD_DIMM_A_WIDTH << j)) ? 1 : 0;
+			populate_dimm_info(&dimm_info[i][j], addr_decode, j,
+					   skl);
 			edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n",
 				 dimm_info[i][j].size,
 				 dimm_info[i][j].dual_rank,
@@ -405,7 +457,7 @@
 			struct dimm_info *dimm;
 			unsigned long nr_pages;
 
-			nr_pages = IE31200_PAGES(dimm_info[j][i].size);
+			nr_pages = IE31200_PAGES(dimm_info[j][i].size, skl);
 			if (nr_pages == 0)
 				continue;
 
@@ -417,7 +469,10 @@
 				dimm->nr_pages = nr_pages;
 				edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
 				dimm->grain = 8; /* just a guess */
-				dimm->mtype = MEM_DDR3;
+				if (skl)
+					dimm->mtype = MEM_DDR4;
+				else
+					dimm->mtype = MEM_DDR3;
 				dimm->dtype = DEV_UNKNOWN;
 				dimm->edac_mode = EDAC_UNKNOWN;
 			}
@@ -426,7 +481,10 @@
 			dimm->nr_pages = nr_pages;
 			edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
 			dimm->grain = 8; /* same guess */
-			dimm->mtype = MEM_DDR3;
+			if (skl)
+				dimm->mtype = MEM_DDR4;
+			else
+				dimm->mtype = MEM_DDR3;
 			dimm->dtype = DEV_UNKNOWN;
 			dimm->edac_mode = EDAC_UNKNOWN;
 		}
@@ -456,12 +514,16 @@
 static int ie31200_init_one(struct pci_dev *pdev,
 			    const struct pci_device_id *ent)
 {
-	edac_dbg(0, "MC:\n");
+	int rc;
 
+	edac_dbg(0, "MC:\n");
 	if (pci_enable_device(pdev) < 0)
 		return -EIO;
+	rc = ie31200_probe1(pdev, ent->driver_data);
+	if (rc == 0 && !mci_pdev)
+		mci_pdev = pci_dev_get(pdev);
 
-	return ie31200_probe1(pdev, ent->driver_data);
+	return rc;
 }
 
 static void ie31200_remove_one(struct pci_dev *pdev)
@@ -470,6 +532,8 @@
 	struct ie31200_priv *priv;
 
 	edac_dbg(0, "\n");
+	pci_dev_put(mci_pdev);
+	mci_pdev = NULL;
 	mci = edac_mc_del_mc(&pdev->dev);
 	if (!mci)
 		return;
@@ -501,6 +565,9 @@
 		PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		IE31200},
 	{
+		PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		IE31200},
+	{
 		0,
 	}            /* 0 terminated list. */
 };
@@ -515,17 +582,53 @@
 
 static int __init ie31200_init(void)
 {
+	int pci_rc, i;
+
 	edac_dbg(3, "MC:\n");
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
 
-	return pci_register_driver(&ie31200_driver);
+	pci_rc = pci_register_driver(&ie31200_driver);
+	if (pci_rc < 0)
+		goto fail0;
+
+	if (!mci_pdev) {
+		ie31200_registered = 0;
+		for (i = 0; ie31200_pci_tbl[i].vendor != 0; i++) {
+			mci_pdev = pci_get_device(ie31200_pci_tbl[i].vendor,
+						  ie31200_pci_tbl[i].device,
+						  NULL);
+			if (mci_pdev)
+				break;
+		}
+		if (!mci_pdev) {
+			edac_dbg(0, "ie31200 pci_get_device fail\n");
+			pci_rc = -ENODEV;
+			goto fail1;
+		}
+		pci_rc = ie31200_init_one(mci_pdev, &ie31200_pci_tbl[i]);
+		if (pci_rc < 0) {
+			edac_dbg(0, "ie31200 init fail\n");
+			pci_rc = -ENODEV;
+			goto fail1;
+		}
+	}
+	return 0;
+
+fail1:
+	pci_unregister_driver(&ie31200_driver);
+fail0:
+	pci_dev_put(mci_pdev);
+
+	return pci_rc;
 }
 
 static void __exit ie31200_exit(void)
 {
 	edac_dbg(3, "MC:\n");
 	pci_unregister_driver(&ie31200_driver);
+	if (!ie31200_registered)
+		ie31200_remove_one(mci_pdev);
 }
 
 module_init(ie31200_init);
--- linux-4.4.0.orig/drivers/edac/mce_amd.c
+++ linux-4.4.0/drivers/edac/mce_amd.c
@@ -760,7 +760,7 @@
 
 	pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
 		m->extcpu,
-		c->x86, c->x86_model, c->x86_mask,
+		c->x86, c->x86_model, c->x86_stepping,
 		m->bank,
 		((m->status & MCI_STATUS_OVER)	? "Over"  : "-"),
 		((m->status & MCI_STATUS_UC)	? "UE"	  :
--- linux-4.4.0.orig/drivers/edac/mv64x60_edac.c
+++ linux-4.4.0/drivers/edac/mv64x60_edac.c
@@ -763,7 +763,7 @@
 		/* Non-ECC RAM? */
 		printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__);
 		res = -ENODEV;
-		goto err2;
+		goto err;
 	}
 
 	edac_dbg(3, "init mci\n");
--- linux-4.4.0.orig/drivers/edac/octeon_edac-lmc.c
+++ linux-4.4.0/drivers/edac/octeon_edac-lmc.c
@@ -79,6 +79,7 @@
 	if (!pvt->inject)
 		int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
 	else {
+		int_reg.u64 = 0;
 		if (pvt->error_type == 1)
 			int_reg.s.sec_err = 1;
 		if (pvt->error_type == 2)
--- linux-4.4.0.orig/drivers/edac/sb_edac.c
+++ linux-4.4.0/drivers/edac/sb_edac.c
@@ -65,15 +65,20 @@
 	0xd8, 0xe0, 0xe8, 0xf0, 0xf8,
 };
 
-#define SAD_LIMIT(reg)		((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff)
-#define DRAM_ATTR(reg)		GET_BITFIELD(reg, 2,  3)
-#define INTERLEAVE_MODE(reg)	GET_BITFIELD(reg, 1,  1)
+static const u32 knl_dram_rule[] = {
+	0x60, 0x68, 0x70, 0x78, 0x80, /* 0-4 */
+	0x88, 0x90, 0x98, 0xa0, 0xa8, /* 5-9 */
+	0xb0, 0xb8, 0xc0, 0xc8, 0xd0, /* 10-14 */
+	0xd8, 0xe0, 0xe8, 0xf0, 0xf8, /* 15-19 */
+	0x100, 0x108, 0x110, 0x118,   /* 20-23 */
+};
+
 #define DRAM_RULE_ENABLE(reg)	GET_BITFIELD(reg, 0,  0)
 #define A7MODE(reg)		GET_BITFIELD(reg, 26, 26)
 
-static char *get_dram_attr(u32 reg)
+static char *show_dram_attr(u32 attr)
 {
-	switch(DRAM_ATTR(reg)) {
+	switch (attr) {
 		case 0:
 			return "DRAM";
 		case 1:
@@ -97,6 +102,14 @@
 	0xdc, 0xe4, 0xec, 0xf4, 0xfc,
 };
 
+static const u32 knl_interleave_list[] = {
+	0x64, 0x6c, 0x74, 0x7c, 0x84, /* 0-4 */
+	0x8c, 0x94, 0x9c, 0xa4, 0xac, /* 5-9 */
+	0xb4, 0xbc, 0xc4, 0xcc, 0xd4, /* 10-14 */
+	0xdc, 0xe4, 0xec, 0xf4, 0xfc, /* 15-19 */
+	0x104, 0x10c, 0x114, 0x11c,   /* 20-23 */
+};
+
 struct interleave_pkg {
 	unsigned char start;
 	unsigned char end;
@@ -134,10 +147,13 @@
 /* Devices 12 Function 7 */
 
 #define TOLM		0x80
-#define	TOHM		0x84
+#define TOHM		0x84
 #define HASWELL_TOLM	0xd0
 #define HASWELL_TOHM_0	0xd4
 #define HASWELL_TOHM_1	0xd8
+#define KNL_TOLM	0xd0
+#define KNL_TOHM_0	0xd4
+#define KNL_TOHM_1	0xd8
 
 #define GET_TOLM(reg)		((GET_BITFIELD(reg, 0,  3) << 28) | 0x3ffffff)
 #define GET_TOHM(reg)		((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff)
@@ -148,6 +164,8 @@
 
 #define SOURCE_ID(reg)		GET_BITFIELD(reg, 9, 11)
 
+#define SOURCE_ID_KNL(reg)	GET_BITFIELD(reg, 12, 14)
+
 #define SAD_CONTROL	0xf4
 
 /* Device 14 function 0 */
@@ -170,6 +188,7 @@
 /* Device 15, function 0 */
 
 #define MCMTR			0x7c
+#define KNL_MCMTR		0x624
 
 #define IS_ECC_ENABLED(mcmtr)		GET_BITFIELD(mcmtr, 2, 2)
 #define IS_LOCKSTEP_ENABLED(mcmtr)	GET_BITFIELD(mcmtr, 1, 1)
@@ -186,6 +205,8 @@
 	0x80, 0x84, 0x88,
 };
 
+static const int knl_mtr_reg = 0xb60;
+
 #define RANK_DISABLE(mtr)		GET_BITFIELD(mtr, 16, 19)
 #define IS_DIMM_PRESENT(mtr)		GET_BITFIELD(mtr, 14, 14)
 #define RANK_CNT_BITS(mtr)		GET_BITFIELD(mtr, 12, 13)
@@ -218,8 +239,11 @@
 	{ 0x1a0, 0x1a4, 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc },
 };
 
-#define RIR_RNK_TGT(reg)		GET_BITFIELD(reg, 16, 19)
-#define RIR_OFFSET(reg)		GET_BITFIELD(reg,  2, 14)
+#define RIR_RNK_TGT(type, reg) (((type) == BROADWELL) ? \
+	GET_BITFIELD(reg, 20, 23) : GET_BITFIELD(reg, 16, 19))
+
+#define RIR_OFFSET(type, reg) (((type) == HASWELL || (type) == BROADWELL) ? \
+	GET_BITFIELD(reg,  2, 15) : GET_BITFIELD(reg,  2, 14))
 
 /* Device 16, functions 2-7 */
 
@@ -256,6 +280,9 @@
 
 #define NUM_CHANNELS		8	/* 2MC per socket, four chan per MC */
 #define MAX_DIMMS		3	/* Max DIMMS per channel */
+#define KNL_MAX_CHAS		38	/* KNL max num. of Cache Home Agents */
+#define KNL_MAX_CHANNELS	6	/* KNL max num. of PCI channels */
+#define KNL_MAX_EDCS		8	/* Embedded DRAM controllers */
 #define CHANNEL_UNSPECIFIED	0xf	/* Intel IA32 SDM 15-14 */
 
 enum type {
@@ -263,6 +290,7 @@
 	IVY_BRIDGE,
 	HASWELL,
 	BROADWELL,
+	KNIGHTS_LANDING,
 };
 
 struct sbridge_pvt;
@@ -273,6 +301,10 @@
 	u64		(*get_tolm)(struct sbridge_pvt *pvt);
 	u64		(*get_tohm)(struct sbridge_pvt *pvt);
 	u64		(*rir_limit)(u32 reg);
+	u64		(*sad_limit)(u32 reg);
+	u32		(*interleave_mode)(u32 reg);
+	char*		(*show_interleave_mode)(u32 reg);
+	u32		(*dram_attr)(u32 reg);
 	const u32	*dram_rule;
 	const u32	*interleave_list;
 	const struct interleave_pkg *interleave_pkg;
@@ -308,6 +340,16 @@
 	struct mem_ctl_info	*mci;
 };
 
+struct knl_pvt {
+	struct pci_dev          *pci_cha[KNL_MAX_CHAS];
+	struct pci_dev          *pci_channel[KNL_MAX_CHANNELS];
+	struct pci_dev          *pci_mc0;
+	struct pci_dev          *pci_mc1;
+	struct pci_dev          *pci_mc0_misc;
+	struct pci_dev          *pci_mc1_misc;
+	struct pci_dev          *pci_mc_info; /* tolm, tohm */
+};
+
 struct sbridge_pvt {
 	struct pci_dev		*pci_ta, *pci_ddrio, *pci_ras;
 	struct pci_dev		*pci_sad0, *pci_sad1;
@@ -336,6 +378,7 @@
 
 	/* Memory description */
 	u64			tolm, tohm;
+	struct knl_pvt knl;
 };
 
 #define PCI_DESCR(device_id, opt)	\
@@ -509,6 +552,50 @@
 	{0,}			/* 0 terminated list. */
 };
 
+/* Knight's Landing Support */
+/*
+ * KNL's memory channels are swizzled between memory controllers.
+ * MC0 is mapped to CH3,5,6 and MC1 is mapped to CH0,1,2
+ */
+#define knl_channel_remap(channel) ((channel + 3) % 6)
+
+/* Memory controller, TAD tables, error injection - 2-8-0, 2-9-0 (2 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_MC       0x7840
+/* DRAM channel stuff; bank addrs, dimmmtr, etc.. 2-8-2 - 2-9-4 (6 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL  0x7843
+/* kdrwdbu TAD limits/offsets, MCMTR - 2-10-1, 2-11-1 (2 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_TA       0x7844
+/* CHA broadcast registers, dram rules - 1-29-0 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0     0x782a
+/* SAD target - 1-29-1 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1     0x782b
+/* Caching / Home Agent */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_CHA      0x782c
+/* Device with TOLM and TOHM, 0-5-0 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM    0x7810
+
+/*
+ * KNL differs from SB, IB, and Haswell in that it has multiple
+ * instances of the same device with the same device ID, so we handle that
+ * by creating as many copies in the table as we expect to find.
+ * (Like device ID must be grouped together.)
+ */
+
+static const struct pci_id_descr pci_dev_descr_knl[] = {
+	[0]         = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0, 0) },
+	[1]         = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1, 0) },
+	[2 ... 3]   = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_MC, 0)},
+	[4 ... 41]  = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHA, 0) },
+	[42 ... 47] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL, 0) },
+	[48]        = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TA, 0) },
+	[49]        = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM, 0) },
+};
+
+static const struct pci_id_table pci_dev_descr_knl_table[] = {
+	PCI_ID_TABLE_ENTRY(pci_dev_descr_knl),
+	{0,}
+};
+
 /*
  * Broadwell support
  *
@@ -585,6 +672,7 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0)},
 	{0,}			/* 0 terminated list. */
 };
 
@@ -598,7 +686,7 @@
 	int ranks = (1 << RANK_CNT_BITS(mtr));
 	int max = 4;
 
-	if (type == HASWELL || type == BROADWELL)
+	if (type == HASWELL || type == BROADWELL || type == KNIGHTS_LANDING)
 		max = 8;
 
 	if (ranks > max) {
@@ -636,10 +724,19 @@
 	return 1 << cols;
 }
 
-static struct sbridge_dev *get_sbridge_dev(u8 bus)
+static struct sbridge_dev *get_sbridge_dev(u8 bus, int multi_bus)
 {
 	struct sbridge_dev *sbridge_dev;
 
+	/*
+	 * If we have devices scattered across several busses that pertain
+	 * to the same memory controller, we'll lump them all together.
+	 */
+	if (multi_bus) {
+		return list_first_entry_or_null(&sbridge_edac_list,
+				struct sbridge_dev, list);
+	}
+
 	list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
 		if (sbridge_dev->bus == bus)
 			return sbridge_dev;
@@ -718,6 +815,67 @@
 	return ((u64)GET_BITFIELD(reg,  1, 10) << 29) | 0x1fffffff;
 }
 
+static u64 sad_limit(u32 reg)
+{
+	return (GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff;
+}
+
+static u32 interleave_mode(u32 reg)
+{
+	return GET_BITFIELD(reg, 1, 1);
+}
+
+char *show_interleave_mode(u32 reg)
+{
+	return interleave_mode(reg) ? "8:6" : "[8:6]XOR[18:16]";
+}
+
+static u32 dram_attr(u32 reg)
+{
+	return GET_BITFIELD(reg, 2, 3);
+}
+
+static u64 knl_sad_limit(u32 reg)
+{
+	return (GET_BITFIELD(reg, 7, 26) << 26) | 0x3ffffff;
+}
+
+static u32 knl_interleave_mode(u32 reg)
+{
+	return GET_BITFIELD(reg, 1, 2);
+}
+
+static char *knl_show_interleave_mode(u32 reg)
+{
+	char *s;
+
+	switch (knl_interleave_mode(reg)) {
+	case 0:
+		s = "use address bits [8:6]";
+		break;
+	case 1:
+		s = "use address bits [10:8]";
+		break;
+	case 2:
+		s = "use address bits [14:12]";
+		break;
+	case 3:
+		s = "use address bits [32:30]";
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+
+	return s;
+}
+
+static u32 dram_attr_knl(u32 reg)
+{
+	return GET_BITFIELD(reg, 3, 4);
+}
+
+
 static enum mem_type get_memory_type(struct sbridge_pvt *pvt)
 {
 	u32 reg;
@@ -769,6 +927,12 @@
 	return mtype;
 }
 
+static enum dev_type knl_get_width(struct sbridge_pvt *pvt, u32 mtr)
+{
+	/* for KNL value is fixed */
+	return DEV_X16;
+}
+
 static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr)
 {
 	/* there's no way to figure out */
@@ -812,6 +976,12 @@
 	return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9));
 }
 
+static enum mem_type knl_get_memory_type(struct sbridge_pvt *pvt)
+{
+	/* DDR4 RDIMMS and LRDIMMS are supported */
+	return MEM_RDDR4;
+}
+
 static u8 get_node_id(struct sbridge_pvt *pvt)
 {
 	u32 reg;
@@ -827,6 +997,15 @@
 	return GET_BITFIELD(reg, 0, 3);
 }
 
+static u8 knl_get_node_id(struct sbridge_pvt *pvt)
+{
+	u32 reg;
+
+	pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, &reg);
+	return GET_BITFIELD(reg, 0, 2);
+}
+
+
 static u64 haswell_get_tolm(struct sbridge_pvt *pvt)
 {
 	u32 reg;
@@ -848,6 +1027,26 @@
 	return rc | 0x1ffffff;
 }
 
+static u64 knl_get_tolm(struct sbridge_pvt *pvt)
+{
+	u32 reg;
+
+	pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOLM, &reg);
+	return (GET_BITFIELD(reg, 26, 31) << 26) | 0x3ffffff;
+}
+
+static u64 knl_get_tohm(struct sbridge_pvt *pvt)
+{
+	u64 rc;
+	u32 reg_lo, reg_hi;
+
+	pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_0, &reg_lo);
+	pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_1, &reg_hi);
+	rc = ((u64)reg_hi << 32) | reg_lo;
+	return rc | 0x3ffffff;
+}
+
+
 static u64 haswell_rir_limit(u32 reg)
 {
 	return (((u64)GET_BITFIELD(reg,  1, 11) + 1) << 29) - 1;
@@ -905,11 +1104,22 @@
 	case BROADWELL:
 		id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA;
 		break;
+	case KNIGHTS_LANDING:
+		/*
+		 * KNL doesn't group things by bus the same way
+		 * SB/IB/Haswell does.
+		 */
+		id = PCI_DEVICE_ID_INTEL_KNL_IMC_TA;
+		break;
 	default:
 		return -ENODEV;
 	}
 
-	pdev = get_pdev_same_bus(bus, id);
+	if (type != KNIGHTS_LANDING)
+		pdev = get_pdev_same_bus(bus, id);
+	else
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, 0);
+
 	if (!pdev) {
 		sbridge_printk(KERN_ERR, "Couldn't find PCI device "
 					"%04x:%04x! on bus %02d\n",
@@ -917,7 +1127,8 @@
 		return -ENODEV;
 	}
 
-	pci_read_config_dword(pdev, MCMTR, &mcmtr);
+	pci_read_config_dword(pdev,
+			type == KNIGHTS_LANDING ? KNL_MCMTR : MCMTR, &mcmtr);
 	if (!IS_ECC_ENABLED(mcmtr)) {
 		sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n");
 		return -ENODEV;
@@ -925,6 +1136,476 @@
 	return 0;
 }
 
+/* Low bits of TAD limit, and some metadata. */
+static const u32 knl_tad_dram_limit_lo[] = {
+	0x400, 0x500, 0x600, 0x700,
+	0x800, 0x900, 0xa00, 0xb00,
+};
+
+/* Low bits of TAD offset. */
+static const u32 knl_tad_dram_offset_lo[] = {
+	0x404, 0x504, 0x604, 0x704,
+	0x804, 0x904, 0xa04, 0xb04,
+};
+
+/* High 16 bits of TAD limit and offset. */
+static const u32 knl_tad_dram_hi[] = {
+	0x408, 0x508, 0x608, 0x708,
+	0x808, 0x908, 0xa08, 0xb08,
+};
+
+/* Number of ways a tad entry is interleaved. */
+static const u32 knl_tad_ways[] = {
+	8, 6, 4, 3, 2, 1,
+};
+
+/*
+ * Retrieve the n'th Target Address Decode table entry
+ * from the memory controller's TAD table.
+ *
+ * @pvt:	driver private data
+ * @entry:	which entry you want to retrieve
+ * @mc:		which memory controller (0 or 1)
+ * @offset:	output tad range offset
+ * @limit:	output address of first byte above tad range
+ * @ways:	output number of interleave ways
+ *
+ * The offset value has curious semantics.  It's a sort of running total
+ * of the sizes of all the memory regions that aren't mapped in this
+ * tad table.
+ */
+static int knl_get_tad(const struct sbridge_pvt *pvt,
+		const int entry,
+		const int mc,
+		u64 *offset,
+		u64 *limit,
+		int *ways)
+{
+	u32 reg_limit_lo, reg_offset_lo, reg_hi;
+	struct pci_dev *pci_mc;
+	int way_id;
+
+	switch (mc) {
+	case 0:
+		pci_mc = pvt->knl.pci_mc0;
+		break;
+	case 1:
+		pci_mc = pvt->knl.pci_mc1;
+		break;
+	default:
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	pci_read_config_dword(pci_mc,
+			knl_tad_dram_limit_lo[entry], &reg_limit_lo);
+	pci_read_config_dword(pci_mc,
+			knl_tad_dram_offset_lo[entry], &reg_offset_lo);
+	pci_read_config_dword(pci_mc,
+			knl_tad_dram_hi[entry], &reg_hi);
+
+	/* Is this TAD entry enabled? */
+	if (!GET_BITFIELD(reg_limit_lo, 0, 0))
+		return -ENODEV;
+
+	way_id = GET_BITFIELD(reg_limit_lo, 3, 5);
+
+	if (way_id < ARRAY_SIZE(knl_tad_ways)) {
+		*ways = knl_tad_ways[way_id];
+	} else {
+		*ways = 0;
+		sbridge_printk(KERN_ERR,
+				"Unexpected value %d in mc_tad_limit_lo wayness field\n",
+				way_id);
+		return -ENODEV;
+	}
+
+	/*
+	 * The least significant 6 bits of base and limit are truncated.
+	 * For limit, we fill the missing bits with 1s.
+	 */
+	*offset = ((u64) GET_BITFIELD(reg_offset_lo, 6, 31) << 6) |
+				((u64) GET_BITFIELD(reg_hi, 0,  15) << 32);
+	*limit = ((u64) GET_BITFIELD(reg_limit_lo,  6, 31) << 6) | 63 |
+				((u64) GET_BITFIELD(reg_hi, 16, 31) << 32);
+
+	return 0;
+}
+
+/* Determine which memory controller is responsible for a given channel. */
+static int knl_channel_mc(int channel)
+{
+	WARN_ON(channel < 0 || channel >= 6);
+
+	return channel < 3 ? 1 : 0;
+}
+
+/*
+ * Get the Nth entry from EDC_ROUTE_TABLE register.
+ * (This is the per-tile mapping of logical interleave targets to
+ *  physical EDC modules.)
+ *
+ * entry 0: 0:2
+ *       1: 3:5
+ *       2: 6:8
+ *       3: 9:11
+ *       4: 12:14
+ *       5: 15:17
+ *       6: 18:20
+ *       7: 21:23
+ * reserved: 24:31
+ */
+static u32 knl_get_edc_route(int entry, u32 reg)
+{
+	WARN_ON(entry >= KNL_MAX_EDCS);
+	return GET_BITFIELD(reg, entry*3, (entry*3)+2);
+}
+
+/*
+ * Get the Nth entry from MC_ROUTE_TABLE register.
+ * (This is the per-tile mapping of logical interleave targets to
+ *  physical DRAM channels modules.)
+ *
+ * entry 0: mc 0:2   channel 18:19
+ *       1: mc 3:5   channel 20:21
+ *       2: mc 6:8   channel 22:23
+ *       3: mc 9:11  channel 24:25
+ *       4: mc 12:14 channel 26:27
+ *       5: mc 15:17 channel 28:29
+ * reserved: 30:31
+ *
+ * Though we have 3 bits to identify the MC, we should only see
+ * the values 0 or 1.
+ */
+
+static u32 knl_get_mc_route(int entry, u32 reg)
+{
+	int mc, chan;
+
+	WARN_ON(entry >= KNL_MAX_CHANNELS);
+
+	mc = GET_BITFIELD(reg, entry*3, (entry*3)+2);
+	chan = GET_BITFIELD(reg, (entry*2) + 18, (entry*2) + 18 + 1);
+
+	return knl_channel_remap(mc*3 + chan);
+}
+
+/*
+ * Render the EDC_ROUTE register in human-readable form.
+ * Output string s should be at least KNL_MAX_EDCS*2 bytes.
+ */
+static void knl_show_edc_route(u32 reg, char *s)
+{
+	int i;
+
+	for (i = 0; i < KNL_MAX_EDCS; i++) {
+		s[i*2] = knl_get_edc_route(i, reg) + '0';
+		s[i*2+1] = '-';
+	}
+
+	s[KNL_MAX_EDCS*2 - 1] = '\0';
+}
+
+/*
+ * Render the MC_ROUTE register in human-readable form.
+ * Output string s should be at least KNL_MAX_CHANNELS*2 bytes.
+ */
+static void knl_show_mc_route(u32 reg, char *s)
+{
+	int i;
+
+	for (i = 0; i < KNL_MAX_CHANNELS; i++) {
+		s[i*2] = knl_get_mc_route(i, reg) + '0';
+		s[i*2+1] = '-';
+	}
+
+	s[KNL_MAX_CHANNELS*2 - 1] = '\0';
+}
+
+#define KNL_EDC_ROUTE 0xb8
+#define KNL_MC_ROUTE 0xb4
+
+/* Is this dram rule backed by regular DRAM in flat mode? */
+#define KNL_EDRAM(reg) GET_BITFIELD(reg, 29, 29)
+
+/* Is this dram rule cached? */
+#define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28)
+
+/* Is this rule backed by edc ? */
+#define KNL_EDRAM_ONLY(reg) GET_BITFIELD(reg, 29, 29)
+
+/* Is this rule backed by DRAM, cacheable in EDRAM? */
+#define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28)
+
+/* Is this rule mod3? */
+#define KNL_MOD3(reg) GET_BITFIELD(reg, 27, 27)
+
+/*
+ * Figure out how big our RAM modules are.
+ *
+ * The DIMMMTR register in KNL doesn't tell us the size of the DIMMs, so we
+ * have to figure this out from the SAD rules, interleave lists, route tables,
+ * and TAD rules.
+ *
+ * SAD rules can have holes in them (e.g. the 3G-4G hole), so we have to
+ * inspect the TAD rules to figure out how large the SAD regions really are.
+ *
+ * When we know the real size of a SAD region and how many ways it's
+ * interleaved, we know the individual contribution of each channel to
+ * TAD is size/ways.
+ *
+ * Finally, we have to check whether each channel participates in each SAD
+ * region.
+ *
+ * Fortunately, KNL only supports one DIMM per channel, so once we know how
+ * much memory the channel uses, we know the DIMM is at least that large.
+ * (The BIOS might possibly choose not to map all available memory, in which
+ * case we will underreport the size of the DIMM.)
+ *
+ * In theory, we could try to determine the EDC sizes as well, but that would
+ * only work in flat mode, not in cache mode.
+ *
+ * @mc_sizes: Output sizes of channels (must have space for KNL_MAX_CHANNELS
+ *            elements)
+ */
+static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
+{
+	u64 sad_base, sad_size, sad_limit = 0;
+	u64 tad_base, tad_size, tad_limit, tad_deadspace, tad_livespace;
+	int sad_rule = 0;
+	int tad_rule = 0;
+	int intrlv_ways, tad_ways;
+	u32 first_pkg, pkg;
+	int i;
+	u64 sad_actual_size[2]; /* sad size accounting for holes, per mc */
+	u32 dram_rule, interleave_reg;
+	u32 mc_route_reg[KNL_MAX_CHAS];
+	u32 edc_route_reg[KNL_MAX_CHAS];
+	int edram_only;
+	char edc_route_string[KNL_MAX_EDCS*2];
+	char mc_route_string[KNL_MAX_CHANNELS*2];
+	int cur_reg_start;
+	int mc;
+	int channel;
+	int way;
+	int participants[KNL_MAX_CHANNELS];
+	int participant_count = 0;
+
+	for (i = 0; i < KNL_MAX_CHANNELS; i++)
+		mc_sizes[i] = 0;
+
+	/* Read the EDC route table in each CHA. */
+	cur_reg_start = 0;
+	for (i = 0; i < KNL_MAX_CHAS; i++) {
+		pci_read_config_dword(pvt->knl.pci_cha[i],
+				KNL_EDC_ROUTE, &edc_route_reg[i]);
+
+		if (i > 0 && edc_route_reg[i] != edc_route_reg[i-1]) {
+			knl_show_edc_route(edc_route_reg[i-1],
+					edc_route_string);
+			if (cur_reg_start == i-1)
+				edac_dbg(0, "edc route table for CHA %d: %s\n",
+					cur_reg_start, edc_route_string);
+			else
+				edac_dbg(0, "edc route table for CHA %d-%d: %s\n",
+					cur_reg_start, i-1, edc_route_string);
+			cur_reg_start = i;
+		}
+	}
+	knl_show_edc_route(edc_route_reg[i-1], edc_route_string);
+	if (cur_reg_start == i-1)
+		edac_dbg(0, "edc route table for CHA %d: %s\n",
+			cur_reg_start, edc_route_string);
+	else
+		edac_dbg(0, "edc route table for CHA %d-%d: %s\n",
+			cur_reg_start, i-1, edc_route_string);
+
+	/* Read the MC route table in each CHA. */
+	cur_reg_start = 0;
+	for (i = 0; i < KNL_MAX_CHAS; i++) {
+		pci_read_config_dword(pvt->knl.pci_cha[i],
+			KNL_MC_ROUTE, &mc_route_reg[i]);
+
+		if (i > 0 && mc_route_reg[i] != mc_route_reg[i-1]) {
+			knl_show_mc_route(mc_route_reg[i-1], mc_route_string);
+			if (cur_reg_start == i-1)
+				edac_dbg(0, "mc route table for CHA %d: %s\n",
+					cur_reg_start, mc_route_string);
+			else
+				edac_dbg(0, "mc route table for CHA %d-%d: %s\n",
+					cur_reg_start, i-1, mc_route_string);
+			cur_reg_start = i;
+		}
+	}
+	knl_show_mc_route(mc_route_reg[i-1], mc_route_string);
+	if (cur_reg_start == i-1)
+		edac_dbg(0, "mc route table for CHA %d: %s\n",
+			cur_reg_start, mc_route_string);
+	else
+		edac_dbg(0, "mc route table for CHA %d-%d: %s\n",
+			cur_reg_start, i-1, mc_route_string);
+
+	/* Process DRAM rules */
+	for (sad_rule = 0; sad_rule < pvt->info.max_sad; sad_rule++) {
+		/* previous limit becomes the new base */
+		sad_base = sad_limit;
+
+		pci_read_config_dword(pvt->pci_sad0,
+			pvt->info.dram_rule[sad_rule], &dram_rule);
+
+		if (!DRAM_RULE_ENABLE(dram_rule))
+			break;
+
+		edram_only = KNL_EDRAM_ONLY(dram_rule);
+
+		sad_limit = pvt->info.sad_limit(dram_rule)+1;
+		sad_size = sad_limit - sad_base;
+
+		pci_read_config_dword(pvt->pci_sad0,
+			pvt->info.interleave_list[sad_rule], &interleave_reg);
+
+		/*
+		 * Find out how many ways this dram rule is interleaved.
+		 * We stop when we see the first channel again.
+		 */
+		first_pkg = sad_pkg(pvt->info.interleave_pkg,
+						interleave_reg, 0);
+		for (intrlv_ways = 1; intrlv_ways < 8; intrlv_ways++) {
+			pkg = sad_pkg(pvt->info.interleave_pkg,
+						interleave_reg, intrlv_ways);
+
+			if ((pkg & 0x8) == 0) {
+				/*
+				 * 0 bit means memory is non-local,
+				 * which KNL doesn't support
+				 */
+				edac_dbg(0, "Unexpected interleave target %d\n",
+					pkg);
+				return -1;
+			}
+
+			if (pkg == first_pkg)
+				break;
+		}
+		if (KNL_MOD3(dram_rule))
+			intrlv_ways *= 3;
+
+		edac_dbg(3, "dram rule %d (base 0x%llx, limit 0x%llx), %d way interleave%s\n",
+			sad_rule,
+			sad_base,
+			sad_limit,
+			intrlv_ways,
+			edram_only ? ", EDRAM" : "");
+
+		/*
+		 * Find out how big the SAD region really is by iterating
+		 * over TAD tables (SAD regions may contain holes).
+		 * Each memory controller might have a different TAD table, so
+		 * we have to look at both.
+		 *
+		 * Livespace is the memory that's mapped in this TAD table,
+		 * deadspace is the holes (this could be the MMIO hole, or it
+		 * could be memory that's mapped by the other TAD table but
+		 * not this one).
+		 */
+		for (mc = 0; mc < 2; mc++) {
+			sad_actual_size[mc] = 0;
+			tad_livespace = 0;
+			for (tad_rule = 0;
+					tad_rule < ARRAY_SIZE(
+						knl_tad_dram_limit_lo);
+					tad_rule++) {
+				if (knl_get_tad(pvt,
+						tad_rule,
+						mc,
+						&tad_deadspace,
+						&tad_limit,
+						&tad_ways))
+					break;
+
+				tad_size = (tad_limit+1) -
+					(tad_livespace + tad_deadspace);
+				tad_livespace += tad_size;
+				tad_base = (tad_limit+1) - tad_size;
+
+				if (tad_base < sad_base) {
+					if (tad_limit > sad_base)
+						edac_dbg(0, "TAD region overlaps lower SAD boundary -- TAD tables may be configured incorrectly.\n");
+				} else if (tad_base < sad_limit) {
+					if (tad_limit+1 > sad_limit) {
+						edac_dbg(0, "TAD region overlaps upper SAD boundary -- TAD tables may be configured incorrectly.\n");
+					} else {
+						/* TAD region is completely inside SAD region */
+						edac_dbg(3, "TAD region %d 0x%llx - 0x%llx (%lld bytes) table%d\n",
+							tad_rule, tad_base,
+							tad_limit, tad_size,
+							mc);
+						sad_actual_size[mc] += tad_size;
+					}
+				}
+				tad_base = tad_limit+1;
+			}
+		}
+
+		for (mc = 0; mc < 2; mc++) {
+			edac_dbg(3, " total TAD DRAM footprint in table%d : 0x%llx (%lld bytes)\n",
+				mc, sad_actual_size[mc], sad_actual_size[mc]);
+		}
+
+		/* Ignore EDRAM rule */
+		if (edram_only)
+			continue;
+
+		/* Figure out which channels participate in interleave. */
+		for (channel = 0; channel < KNL_MAX_CHANNELS; channel++)
+			participants[channel] = 0;
+
+		/* For each channel, does at least one CHA have
+		 * this channel mapped to the given target?
+		 */
+		for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
+			for (way = 0; way < intrlv_ways; way++) {
+				int target;
+				int cha;
+
+				if (KNL_MOD3(dram_rule))
+					target = way;
+				else
+					target = 0x7 & sad_pkg(
+				pvt->info.interleave_pkg, interleave_reg, way);
+
+				for (cha = 0; cha < KNL_MAX_CHAS; cha++) {
+					if (knl_get_mc_route(target,
+						mc_route_reg[cha]) == channel
+						&& participants[channel]) {
+						participant_count++;
+						participants[channel] = 1;
+						break;
+					}
+				}
+			}
+		}
+
+		if (participant_count != intrlv_ways)
+			edac_dbg(0, "participant_count (%d) != interleave_ways (%d): DIMM size may be incorrect\n",
+				participant_count, intrlv_ways);
+
+		for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
+			mc = knl_channel_mc(channel);
+			if (participants[channel]) {
+				edac_dbg(4, "mc channel %d contributes %lld bytes via sad entry %d\n",
+					channel,
+					sad_actual_size[mc]/intrlv_ways,
+					sad_rule);
+				mc_sizes[channel] +=
+					sad_actual_size[mc]/intrlv_ways;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static int get_dimm_config(struct mem_ctl_info *mci)
 {
 	struct sbridge_pvt *pvt = mci->pvt_info;
@@ -934,13 +1615,20 @@
 	u32 reg;
 	enum edac_type mode;
 	enum mem_type mtype;
+	int channels = pvt->info.type == KNIGHTS_LANDING ?
+		KNL_MAX_CHANNELS : NUM_CHANNELS;
+	u64 knl_mc_sizes[KNL_MAX_CHANNELS];
 
-	if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL)
+	if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL ||
+			pvt->info.type == KNIGHTS_LANDING)
 		pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, &reg);
 	else
 		pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
 
-	pvt->sbridge_dev->source_id = SOURCE_ID(reg);
+	if (pvt->info.type == KNIGHTS_LANDING)
+		pvt->sbridge_dev->source_id = SOURCE_ID_KNL(reg);
+	else
+		pvt->sbridge_dev->source_id = SOURCE_ID(reg);
 
 	pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt);
 	edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
@@ -948,31 +1636,42 @@
 		 pvt->sbridge_dev->node_id,
 		 pvt->sbridge_dev->source_id);
 
-	pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg);
-	if (IS_MIRROR_ENABLED(reg)) {
-		edac_dbg(0, "Memory mirror is enabled\n");
-		pvt->is_mirrored = true;
-	} else {
-		edac_dbg(0, "Memory mirror is disabled\n");
+	/* KNL doesn't support mirroring or lockstep,
+	 * and is always closed page
+	 */
+	if (pvt->info.type == KNIGHTS_LANDING) {
+		mode = EDAC_S4ECD4ED;
 		pvt->is_mirrored = false;
-	}
 
-	pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr);
-	if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) {
-		edac_dbg(0, "Lockstep is enabled\n");
-		mode = EDAC_S8ECD8ED;
-		pvt->is_lockstep = true;
+		if (knl_get_dimm_capacity(pvt, knl_mc_sizes) != 0)
+			return -1;
 	} else {
-		edac_dbg(0, "Lockstep is disabled\n");
-		mode = EDAC_S4ECD4ED;
-		pvt->is_lockstep = false;
-	}
-	if (IS_CLOSE_PG(pvt->info.mcmtr)) {
-		edac_dbg(0, "address map is on closed page mode\n");
-		pvt->is_close_pg = true;
-	} else {
-		edac_dbg(0, "address map is on open page mode\n");
-		pvt->is_close_pg = false;
+		pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg);
+		if (IS_MIRROR_ENABLED(reg)) {
+			edac_dbg(0, "Memory mirror is enabled\n");
+			pvt->is_mirrored = true;
+		} else {
+			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)) {
+			edac_dbg(0, "Lockstep is enabled\n");
+			mode = EDAC_S8ECD8ED;
+			pvt->is_lockstep = true;
+		} else {
+			edac_dbg(0, "Lockstep is disabled\n");
+			mode = EDAC_S4ECD4ED;
+			pvt->is_lockstep = false;
+		}
+		if (IS_CLOSE_PG(pvt->info.mcmtr)) {
+			edac_dbg(0, "address map is on closed page mode\n");
+			pvt->is_close_pg = true;
+		} else {
+			edac_dbg(0, "address map is on open page mode\n");
+			pvt->is_close_pg = false;
+		}
 	}
 
 	mtype = pvt->info.get_memory_type(pvt);
@@ -988,23 +1687,46 @@
 	else
 		banks = 8;
 
-	for (i = 0; i < NUM_CHANNELS; i++) {
+	for (i = 0; i < channels; i++) {
 		u32 mtr;
 
-		if (!pvt->pci_tad[i])
-			continue;
-		for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) {
+		int max_dimms_per_channel;
+
+		if (pvt->info.type == KNIGHTS_LANDING) {
+			max_dimms_per_channel = 1;
+			if (!pvt->knl.pci_channel[i])
+				continue;
+		} else {
+			max_dimms_per_channel = ARRAY_SIZE(mtr_regs);
+			if (!pvt->pci_tad[i])
+				continue;
+		}
+
+		for (j = 0; j < max_dimms_per_channel; j++) {
 			dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
 				       i, j, 0);
-			pci_read_config_dword(pvt->pci_tad[i],
-					      mtr_regs[j], &mtr);
+			if (pvt->info.type == KNIGHTS_LANDING) {
+				pci_read_config_dword(pvt->knl.pci_channel[i],
+					knl_mtr_reg, &mtr);
+			} else {
+				pci_read_config_dword(pvt->pci_tad[i],
+					mtr_regs[j], &mtr);
+			}
 			edac_dbg(4, "Channel #%d  MTR%d = %x\n", i, j, mtr);
 			if (IS_DIMM_PRESENT(mtr)) {
 				pvt->channel[i].dimms++;
 
 				ranks = numrank(pvt->info.type, mtr);
-				rows = numrow(mtr);
-				cols = numcol(mtr);
+
+				if (pvt->info.type == KNIGHTS_LANDING) {
+					/* For DDR4, this is fixed. */
+					cols = 1 << 10;
+					rows = knl_mc_sizes[i] /
+						((u64) cols * ranks * banks * 8);
+				} else {
+					rows = numrow(mtr);
+					cols = numcol(mtr);
+				}
 
 				size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
 				npages = MiB_TO_PAGES(size);
@@ -1069,7 +1791,7 @@
 		/* SAD_LIMIT Address range is 45:26 */
 		pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],
 				      &reg);
-		limit = SAD_LIMIT(reg);
+		limit = pvt->info.sad_limit(reg);
 
 		if (!DRAM_RULE_ENABLE(reg))
 			continue;
@@ -1081,10 +1803,10 @@
 		gb = div_u64_rem(tmp_mb, 1024, &mb);
 		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),
+			 show_dram_attr(pvt->info.dram_attr(reg)),
 			 gb, (mb*1000)/1024,
 			 ((u64)tmp_mb) << 20L,
-			 INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]",
+			 pvt->info.show_interleave_mode(reg),
 			 reg);
 		prv = limit;
 
@@ -1101,6 +1823,9 @@
 		}
 	}
 
+	if (pvt->info.type == KNIGHTS_LANDING)
+		return;
+
 	/*
 	 * Step 3) Get TAD range
 	 */
@@ -1117,8 +1842,8 @@
 		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, gb, (mb*1000)/1024,
 			 ((u64)tmp_mb) << 20L,
-			 (u32)TAD_SOCK(reg),
-			 (u32)TAD_CH(reg),
+			 (u32)(1 << TAD_SOCK(reg)),
+			 (u32)TAD_CH(reg) + 1,
 			 (u32)TAD_TGT0(reg),
 			 (u32)TAD_TGT1(reg),
 			 (u32)TAD_TGT2(reg),
@@ -1175,14 +1900,14 @@
 				pci_read_config_dword(pvt->pci_tad[i],
 						      rir_offset[j][k],
 						      &reg);
-				tmp_mb = RIR_OFFSET(reg) << 6;
+				tmp_mb = RIR_OFFSET(pvt->info.type, reg) << 6;
 
 				gb = div_u64_rem(tmp_mb, 1024, &mb);
 				edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
 					 i, j, k,
 					 gb, (mb*1000)/1024,
 					 ((u64)tmp_mb) << 20L,
-					 (u32)RIR_RNK_TGT(reg),
+					 (u32)RIR_RNK_TGT(pvt->info.type, reg),
 					 reg);
 			}
 		}
@@ -1248,7 +1973,7 @@
 		if (!DRAM_RULE_ENABLE(reg))
 			continue;
 
-		limit = SAD_LIMIT(reg);
+		limit = pvt->info.sad_limit(reg);
 		if (limit <= prv) {
 			sprintf(msg, "Can't discover the memory socket");
 			return -EINVAL;
@@ -1262,8 +1987,8 @@
 		return -EINVAL;
 	}
 	dram_rule = reg;
-	*area_type = get_dram_attr(dram_rule);
-	interleave_mode = INTERLEAVE_MODE(dram_rule);
+	*area_type = show_dram_attr(pvt->info.dram_attr(dram_rule));
+	interleave_mode = pvt->info.interleave_mode(dram_rule);
 
 	pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
 			      &reg);
@@ -1396,7 +2121,7 @@
 	}
 
 	ch_way = TAD_CH(reg) + 1;
-	sck_way = TAD_SOCK(reg) + 1;
+	sck_way = TAD_SOCK(reg);
 
 	if (ch_way == 3)
 		idx = addr >> 6;
@@ -1435,7 +2160,7 @@
 		switch(ch_way) {
 		case 2:
 		case 4:
-			sck_xch = 1 << sck_way * (ch_way >> 1);
+			sck_xch = (1 << sck_way) * (ch_way >> 1);
 			break;
 		default:
 			sprintf(msg, "Invalid mirror set. Can't decode addr");
@@ -1453,7 +2178,7 @@
 		 n_tads,
 		 addr,
 		 limit,
-		 (u32)TAD_SOCK(reg),
+		 sck_way,
 		 ch_way,
 		 offset,
 		 idx,
@@ -1468,18 +2193,12 @@
 			offset, addr);
 		return -EINVAL;
 	}
-	addr -= offset;
-	/* Store the low bits [0:6] of the addr */
-	ch_addr = addr & 0x7f;
-	/* Remove socket wayness and remove 6 bits */
-	addr >>= 6;
-	addr = div_u64(addr, sck_xch);
-#if 0
-	/* Divide by channel way */
-	addr = addr / ch_way;
-#endif
-	/* Recover the last 6 bits */
-	ch_addr |= addr << 6;
+
+	ch_addr = addr - offset;
+	ch_addr >>= (6 + shiftup);
+	ch_addr /= sck_xch;
+	ch_addr <<= (6 + shiftup);
+	ch_addr |= addr & ((1 << (6 + shiftup)) - 1);
 
 	/*
 	 * Step 3) Decode rank
@@ -1518,7 +2237,7 @@
 	pci_read_config_dword(pvt->pci_tad[ch_add + base_ch],
 			      rir_offset[n_rir][idx],
 			      &reg);
-	*rank = RIR_RNK_TGT(reg);
+	*rank = RIR_RNK_TGT(pvt->info.type, reg);
 
 	edac_dbg(0, "RIR#%d: channel address 0x%08Lx < 0x%08Lx, RIR interleave %d, index %d\n",
 		 n_rir,
@@ -1567,7 +2286,8 @@
 static int sbridge_get_onedevice(struct pci_dev **prev,
 				 u8 *num_mc,
 				 const struct pci_id_table *table,
-				 const unsigned devno)
+				 const unsigned devno,
+				 const int multi_bus)
 {
 	struct sbridge_dev *sbridge_dev;
 	const struct pci_id_descr *dev_descr = &table->descr[devno];
@@ -1603,7 +2323,7 @@
 	}
 	bus = pdev->bus->number;
 
-	sbridge_dev = get_sbridge_dev(bus);
+	sbridge_dev = get_sbridge_dev(bus, multi_bus);
 	if (!sbridge_dev) {
 		sbridge_dev = alloc_sbridge_dev(bus, table);
 		if (!sbridge_dev) {
@@ -1652,21 +2372,32 @@
  * @num_mc: pointer to the memory controllers count, to be incremented in case
  *	    of success.
  * @table: model specific table
+ * @allow_dups: allow for multiple devices to exist with the same device id
+ *              (as implemented, this isn't expected to work correctly in the
+ *              multi-socket case).
+ * @multi_bus: don't assume devices on different buses belong to different
+ *             memory controllers.
  *
  * returns 0 in case of success or error code
  */
-static int sbridge_get_all_devices(u8 *num_mc,
-				   const struct pci_id_table *table)
+static int sbridge_get_all_devices_full(u8 *num_mc,
+					const struct pci_id_table *table,
+					int allow_dups,
+					int multi_bus)
 {
 	int i, rc;
 	struct pci_dev *pdev = NULL;
 
 	while (table && table->descr) {
 		for (i = 0; i < table->n_devs; i++) {
-			pdev = NULL;
+			if (!allow_dups || i == 0 ||
+					table->descr[i].dev_id !=
+						table->descr[i-1].dev_id) {
+				pdev = NULL;
+			}
 			do {
 				rc = sbridge_get_onedevice(&pdev, num_mc,
-							   table, i);
+							   table, i, multi_bus);
 				if (rc < 0) {
 					if (i == 0) {
 						i = table->n_devs;
@@ -1675,7 +2406,7 @@
 					sbridge_put_all_devices();
 					return -ENODEV;
 				}
-			} while (pdev);
+			} while (pdev && !allow_dups);
 		}
 		table++;
 	}
@@ -1683,6 +2414,11 @@
 	return 0;
 }
 
+#define sbridge_get_all_devices(num_mc, table) \
+		sbridge_get_all_devices_full(num_mc, table, 0, 0)
+#define sbridge_get_all_devices_knl(num_mc, table) \
+		sbridge_get_all_devices_full(num_mc, table, 1, 1)
+
 static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
 				 struct sbridge_dev *sbridge_dev)
 {
@@ -1776,6 +2512,7 @@
 			break;
 		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
 			pvt->pci_ta = pdev;
+			break;
 		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS:
 			pvt->pci_ras = pdev;
 			break;
@@ -2038,6 +2775,131 @@
 	return -ENODEV;
 }
 
+static int knl_mci_bind_devs(struct mem_ctl_info *mci,
+			struct sbridge_dev *sbridge_dev)
+{
+	struct sbridge_pvt *pvt = mci->pvt_info;
+	struct pci_dev *pdev;
+	int dev, func;
+
+	int i;
+	int devidx;
+
+	for (i = 0; i < sbridge_dev->n_devs; i++) {
+		pdev = sbridge_dev->pdev[i];
+		if (!pdev)
+			continue;
+
+		/* Extract PCI device and function. */
+		dev = (pdev->devfn >> 3) & 0x1f;
+		func = pdev->devfn & 0x7;
+
+		switch (pdev->device) {
+		case PCI_DEVICE_ID_INTEL_KNL_IMC_MC:
+			if (dev == 8)
+				pvt->knl.pci_mc0 = pdev;
+			else if (dev == 9)
+				pvt->knl.pci_mc1 = pdev;
+			else {
+				sbridge_printk(KERN_ERR,
+					"Memory controller in unexpected place! (dev %d, fn %d)\n",
+					dev, func);
+				continue;
+			}
+			break;
+
+		case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0:
+			pvt->pci_sad0 = pdev;
+			break;
+
+		case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1:
+			pvt->pci_sad1 = pdev;
+			break;
+
+		case PCI_DEVICE_ID_INTEL_KNL_IMC_CHA:
+			/* There are one of these per tile, and range from
+			 * 1.14.0 to 1.18.5.
+			 */
+			devidx = ((dev-14)*8)+func;
+
+			if (devidx < 0 || devidx >= KNL_MAX_CHAS) {
+				sbridge_printk(KERN_ERR,
+					"Caching and Home Agent in unexpected place! (dev %d, fn %d)\n",
+					dev, func);
+				continue;
+			}
+
+			WARN_ON(pvt->knl.pci_cha[devidx] != NULL);
+
+			pvt->knl.pci_cha[devidx] = pdev;
+			break;
+
+		case PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL:
+			devidx = -1;
+
+			/*
+			 *  MC0 channels 0-2 are device 9 function 2-4,
+			 *  MC1 channels 3-5 are device 8 function 2-4.
+			 */
+
+			if (dev == 9)
+				devidx = func-2;
+			else if (dev == 8)
+				devidx = 3 + (func-2);
+
+			if (devidx < 0 || devidx >= KNL_MAX_CHANNELS) {
+				sbridge_printk(KERN_ERR,
+					"DRAM Channel Registers in unexpected place! (dev %d, fn %d)\n",
+					dev, func);
+				continue;
+			}
+
+			WARN_ON(pvt->knl.pci_channel[devidx] != NULL);
+			pvt->knl.pci_channel[devidx] = pdev;
+			break;
+
+		case PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM:
+			pvt->knl.pci_mc_info = pdev;
+			break;
+
+		case PCI_DEVICE_ID_INTEL_KNL_IMC_TA:
+			pvt->pci_ta = pdev;
+			break;
+
+		default:
+			sbridge_printk(KERN_ERR, "Unexpected device %d\n",
+				pdev->device);
+			break;
+		}
+	}
+
+	if (!pvt->knl.pci_mc0  || !pvt->knl.pci_mc1 ||
+	    !pvt->pci_sad0     || !pvt->pci_sad1    ||
+	    !pvt->pci_ta) {
+		goto enodev;
+	}
+
+	for (i = 0; i < KNL_MAX_CHANNELS; i++) {
+		if (!pvt->knl.pci_channel[i]) {
+			sbridge_printk(KERN_ERR, "Missing channel %d\n", i);
+			goto enodev;
+		}
+	}
+
+	for (i = 0; i < KNL_MAX_CHAS; i++) {
+		if (!pvt->knl.pci_cha[i]) {
+			sbridge_printk(KERN_ERR, "Missing CHA %d\n", i);
+			goto enodev;
+		}
+	}
+
+	return 0;
+
+enodev:
+	sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
+	return -ENODEV;
+}
+
 /****************************************************************************
 			Error check routines
  ****************************************************************************/
@@ -2127,8 +2989,36 @@
 	if (!GET_BITFIELD(m->status, 58, 58))
 		return;
 
-	rc = get_memory_error_data(mci, m->addr, &socket, &ha,
-				   &channel_mask, &rank, &area_type, msg);
+	if (pvt->info.type == KNIGHTS_LANDING) {
+		if (channel == 14) {
+			edac_dbg(0, "%s%s err_code:%04x:%04x EDRAM bank %d\n",
+				overflow ? " OVERFLOW" : "",
+				(uncorrected_error && recoverable)
+				? " recoverable" : "",
+				mscod, errcode,
+				m->bank);
+		} else {
+			char A = *("A");
+
+			channel = knl_channel_remap(channel);
+			channel_mask = 1 << channel;
+			snprintf(msg, sizeof(msg),
+				"%s%s err_code:%04x:%04x channel:%d (DIMM_%c)",
+				overflow ? " OVERFLOW" : "",
+				(uncorrected_error && recoverable)
+				? " recoverable" : " ",
+				mscod, errcode, channel, A + channel);
+			edac_mc_handle_error(tp_event, mci, core_err_cnt,
+				m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
+				channel, 0, -1,
+				optype, msg);
+		}
+		return;
+	} else {
+		rc = get_memory_error_data(mci, m->addr, &socket, &ha,
+				&channel_mask, &rank, &area_type, msg);
+	}
+
 	if (rc < 0)
 		goto err_parsing;
 	new_mci = get_mci_for_node_id(socket);
@@ -2260,7 +3150,7 @@
 
 	mci = get_mci_for_node_id(mce->socketid);
 	if (!mci)
-		return NOTIFY_BAD;
+		return NOTIFY_DONE;
 	pvt = mci->pvt_info;
 
 	/*
@@ -2359,10 +3249,11 @@
 
 	/* allocate a new MC control structure */
 	layers[0].type = EDAC_MC_LAYER_CHANNEL;
-	layers[0].size = NUM_CHANNELS;
+	layers[0].size = type == KNIGHTS_LANDING ?
+		KNL_MAX_CHANNELS : NUM_CHANNELS;
 	layers[0].is_virt_csrow = false;
 	layers[1].type = EDAC_MC_LAYER_SLOT;
-	layers[1].size = MAX_DIMMS;
+	layers[1].size = type == KNIGHTS_LANDING ? 1 : MAX_DIMMS;
 	layers[1].is_virt_csrow = true;
 	mci = edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers,
 			    sizeof(*pvt));
@@ -2380,7 +3271,8 @@
 	pvt->sbridge_dev = sbridge_dev;
 	sbridge_dev->mci = mci;
 
-	mci->mtype_cap = MEM_FLAG_DDR3;
+	mci->mtype_cap = type == KNIGHTS_LANDING ?
+		MEM_FLAG_DDR4 : MEM_FLAG_DDR3;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE;
 	mci->edac_cap = EDAC_FLAG_NONE;
 	mci->mod_name = "sbridge_edac.c";
@@ -2401,6 +3293,10 @@
 		pvt->info.get_memory_type = get_memory_type;
 		pvt->info.get_node_id = get_node_id;
 		pvt->info.rir_limit = rir_limit;
+		pvt->info.sad_limit = sad_limit;
+		pvt->info.interleave_mode = interleave_mode;
+		pvt->info.show_interleave_mode = show_interleave_mode;
+		pvt->info.dram_attr = dram_attr;
 		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
 		pvt->info.interleave_list = ibridge_interleave_list;
 		pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2421,6 +3317,10 @@
 		pvt->info.get_memory_type = get_memory_type;
 		pvt->info.get_node_id = get_node_id;
 		pvt->info.rir_limit = rir_limit;
+		pvt->info.sad_limit = sad_limit;
+		pvt->info.interleave_mode = interleave_mode;
+		pvt->info.show_interleave_mode = show_interleave_mode;
+		pvt->info.dram_attr = dram_attr;
 		pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
 		pvt->info.interleave_list = sbridge_interleave_list;
 		pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
@@ -2441,6 +3341,10 @@
 		pvt->info.get_memory_type = haswell_get_memory_type;
 		pvt->info.get_node_id = haswell_get_node_id;
 		pvt->info.rir_limit = haswell_rir_limit;
+		pvt->info.sad_limit = sad_limit;
+		pvt->info.interleave_mode = interleave_mode;
+		pvt->info.show_interleave_mode = show_interleave_mode;
+		pvt->info.dram_attr = dram_attr;
 		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
 		pvt->info.interleave_list = ibridge_interleave_list;
 		pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2461,6 +3365,10 @@
 		pvt->info.get_memory_type = haswell_get_memory_type;
 		pvt->info.get_node_id = haswell_get_node_id;
 		pvt->info.rir_limit = haswell_rir_limit;
+		pvt->info.sad_limit = sad_limit;
+		pvt->info.interleave_mode = interleave_mode;
+		pvt->info.show_interleave_mode = show_interleave_mode;
+		pvt->info.dram_attr = dram_attr;
 		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
 		pvt->info.interleave_list = ibridge_interleave_list;
 		pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2473,6 +3381,30 @@
 		if (unlikely(rc < 0))
 			goto fail0;
 		break;
+	case KNIGHTS_LANDING:
+		/* pvt->info.rankcfgr == ??? */
+		pvt->info.get_tolm = knl_get_tolm;
+		pvt->info.get_tohm = knl_get_tohm;
+		pvt->info.dram_rule = knl_dram_rule;
+		pvt->info.get_memory_type = knl_get_memory_type;
+		pvt->info.get_node_id = knl_get_node_id;
+		pvt->info.rir_limit = NULL;
+		pvt->info.sad_limit = knl_sad_limit;
+		pvt->info.interleave_mode = knl_interleave_mode;
+		pvt->info.show_interleave_mode = knl_show_interleave_mode;
+		pvt->info.dram_attr = dram_attr_knl;
+		pvt->info.max_sad = ARRAY_SIZE(knl_dram_rule);
+		pvt->info.interleave_list = knl_interleave_list;
+		pvt->info.max_interleave = ARRAY_SIZE(knl_interleave_list);
+		pvt->info.interleave_pkg = ibridge_interleave_pkg;
+		pvt->info.get_width = knl_get_width;
+		mci->ctl_name = kasprintf(GFP_KERNEL,
+			"Knights Landing Socket#%d", mci->mc_idx);
+
+		rc = knl_mci_bind_devs(mci, sbridge_dev);
+		if (unlikely(rc < 0))
+			goto fail0;
+		break;
 	}
 
 	/* Get dimm basic config and the memory layout */
@@ -2527,20 +3459,29 @@
 
 	switch (pdev->device) {
 	case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
-		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
+		rc = sbridge_get_all_devices(&num_mc,
+					pci_dev_descr_ibridge_table);
 		type = IVY_BRIDGE;
 		break;
 	case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
-		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
+		rc = sbridge_get_all_devices(&num_mc,
+					pci_dev_descr_sbridge_table);
 		type = SANDY_BRIDGE;
 		break;
 	case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
-		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table);
+		rc = sbridge_get_all_devices(&num_mc,
+					pci_dev_descr_haswell_table);
 		type = HASWELL;
 		break;
 	case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
-		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_broadwell_table);
+		rc = sbridge_get_all_devices(&num_mc,
+					pci_dev_descr_broadwell_table);
 		type = BROADWELL;
+	    break;
+	case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0:
+		rc = sbridge_get_all_devices_knl(&num_mc,
+					pci_dev_descr_knl_table);
+		type = KNIGHTS_LANDING;
 		break;
 	}
 	if (unlikely(rc < 0)) {
--- linux-4.4.0.orig/drivers/edac/skx_edac.c
+++ linux-4.4.0/drivers/edac/skx_edac.c
@@ -0,0 +1,1121 @@
+/*
+ * EDAC driver for Intel(R) Xeon(R) Skylake processors
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/edac.h>
+#include <linux/mmzone.h>
+#include <linux/smp.h>
+#include <linux/bitmap.h>
+#include <linux/math64.h>
+#include <linux/mod_devicetable.h>
+#include <asm/cpu_device_id.h>
+#include <asm/processor.h>
+#include <asm/mce.h>
+
+#include "edac_core.h"
+
+#define SKX_REVISION    " Ver: 1.0 "
+
+/*
+ * Debug macros
+ */
+#define skx_printk(level, fmt, arg...)			\
+	edac_printk(level, "skx", fmt, ##arg)
+
+#define skx_mc_printk(mci, level, fmt, arg...)		\
+	edac_mc_chipset_printk(mci, level, "skx", fmt, ##arg)
+
+/*
+ * Get a bit field at register value <v>, from bit <lo> to bit <hi>
+ */
+#define GET_BITFIELD(v, lo, hi) \
+	(((v) & GENMASK_ULL((hi), (lo))) >> (lo))
+
+static LIST_HEAD(skx_edac_list);
+
+static u64 skx_tolm, skx_tohm;
+
+#define NUM_IMC			2	/* memory controllers per socket */
+#define NUM_CHANNELS		3	/* channels per memory controller */
+#define NUM_DIMMS		2	/* Max DIMMS per channel */
+
+#define	MASK26	0x3FFFFFF		/* Mask for 2^26 */
+#define MASK29	0x1FFFFFFF		/* Mask for 2^29 */
+
+/*
+ * Each cpu socket contains some pci devices that provide global
+ * information, and also some that are local to each of the two
+ * memory controllers on the die.
+ */
+struct skx_dev {
+	struct list_head	list;
+	u8			bus[4];
+	struct pci_dev	*sad_all;
+	struct pci_dev	*util_all;
+	u32	mcroute;
+	struct skx_imc {
+		struct mem_ctl_info *mci;
+		u8	mc;	/* system wide mc# */
+		u8	lmc;	/* socket relative mc# */
+		u8	src_id, node_id;
+		struct skx_channel {
+			struct pci_dev *cdev;
+			struct skx_dimm {
+				u8	close_pg;
+				u8	bank_xor_enable;
+				u8	fine_grain_bank;
+				u8	rowbits;
+				u8	colbits;
+			} dimms[NUM_DIMMS];
+		} chan[NUM_CHANNELS];
+	} imc[NUM_IMC];
+};
+static int skx_num_sockets;
+
+struct skx_pvt {
+	struct skx_imc	*imc;
+};
+
+struct decoded_addr {
+	struct skx_dev *dev;
+	u64	addr;
+	int	socket;
+	int	imc;
+	int	channel;
+	u64	chan_addr;
+	int	sktways;
+	int	chanways;
+	int	dimm;
+	int	rank;
+	int	channel_rank;
+	u64	rank_address;
+	int	row;
+	int	column;
+	int	bank_address;
+	int	bank_group;
+};
+
+static struct skx_dev *get_skx_dev(u8 bus, u8 idx)
+{
+	struct skx_dev *d;
+
+	list_for_each_entry(d, &skx_edac_list, list) {
+		if (d->bus[idx] == bus)
+			return d;
+	}
+
+	return NULL;
+}
+
+enum munittype {
+	CHAN0, CHAN1, CHAN2, SAD_ALL, UTIL_ALL, SAD
+};
+
+struct munit {
+	u16	did;
+	u16	devfn[NUM_IMC];
+	u8	busidx;
+	u8	per_socket;
+	enum munittype mtype;
+};
+
+/*
+ * List of PCI device ids that we need together with some device
+ * number and function numbers to tell which memory controller the
+ * device belongs to.
+ */
+static const struct munit skx_all_munits[] = {
+	{ 0x2054, { }, 1, 1, SAD_ALL },
+	{ 0x2055, { }, 1, 1, UTIL_ALL },
+	{ 0x2040, { PCI_DEVFN(10, 0), PCI_DEVFN(12, 0) }, 2, 2, CHAN0 },
+	{ 0x2044, { PCI_DEVFN(10, 4), PCI_DEVFN(12, 4) }, 2, 2, CHAN1 },
+	{ 0x2048, { PCI_DEVFN(11, 0), PCI_DEVFN(13, 0) }, 2, 2, CHAN2 },
+	{ 0x208e, { }, 1, 0, SAD },
+	{ }
+};
+
+/*
+ * We use the per-socket device 0x2016 to count how many sockets are present,
+ * and to detemine which PCI buses are associated with each socket. Allocate
+ * and build the full list of all the skx_dev structures that we need here.
+ */
+static int get_all_bus_mappings(void)
+{
+	struct pci_dev *pdev, *prev;
+	struct skx_dev *d;
+	u32 reg;
+	int ndev = 0;
+
+	prev = NULL;
+	for (;;) {
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x2016, prev);
+		if (!pdev)
+			break;
+		ndev++;
+		d = kzalloc(sizeof(*d), GFP_KERNEL);
+		if (!d) {
+			pci_dev_put(pdev);
+			return -ENOMEM;
+		}
+		pci_read_config_dword(pdev, 0xCC, &reg);
+		d->bus[0] =  GET_BITFIELD(reg, 0, 7);
+		d->bus[1] =  GET_BITFIELD(reg, 8, 15);
+		d->bus[2] =  GET_BITFIELD(reg, 16, 23);
+		d->bus[3] =  GET_BITFIELD(reg, 24, 31);
+		edac_dbg(2, "busses: %x, %x, %x, %x\n",
+			 d->bus[0], d->bus[1], d->bus[2], d->bus[3]);
+		list_add_tail(&d->list, &skx_edac_list);
+		skx_num_sockets++;
+		prev = pdev;
+	}
+
+	return ndev;
+}
+
+static int get_all_munits(const struct munit *m)
+{
+	struct pci_dev *pdev, *prev;
+	struct skx_dev *d;
+	u32 reg;
+	int i = 0, ndev = 0;
+
+	prev = NULL;
+	for (;;) {
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL, m->did, prev);
+		if (!pdev)
+			break;
+		ndev++;
+		if (m->per_socket == NUM_IMC) {
+			for (i = 0; i < NUM_IMC; i++)
+				if (m->devfn[i] == pdev->devfn)
+					break;
+			if (i == NUM_IMC)
+				goto fail;
+		}
+		d = get_skx_dev(pdev->bus->number, m->busidx);
+		if (!d)
+			goto fail;
+
+		/* Be sure that the device is enabled */
+		if (unlikely(pci_enable_device(pdev) < 0)) {
+			skx_printk(KERN_ERR,
+				"Couldn't enable %04x:%04x\n", PCI_VENDOR_ID_INTEL, m->did);
+			goto fail;
+		}
+
+		switch (m->mtype) {
+		case CHAN0: case CHAN1: case CHAN2:
+			pci_dev_get(pdev);
+			d->imc[i].chan[m->mtype].cdev = pdev;
+			break;
+		case SAD_ALL:
+			pci_dev_get(pdev);
+			d->sad_all = pdev;
+			break;
+		case UTIL_ALL:
+			pci_dev_get(pdev);
+			d->util_all = pdev;
+			break;
+		case SAD:
+			/*
+			 * one of these devices per core, including cores
+			 * that don't exist on this SKU. Ignore any that
+			 * read a route table of zero, make sure all the
+			 * non-zero values match.
+			 */
+			pci_read_config_dword(pdev, 0xB4, &reg);
+			if (reg != 0) {
+				if (d->mcroute == 0)
+					d->mcroute = reg;
+				else if (d->mcroute != reg) {
+					skx_printk(KERN_ERR,
+						"mcroute mismatch\n");
+					goto fail;
+				}
+			}
+			ndev--;
+			break;
+		}
+
+		prev = pdev;
+	}
+
+	return ndev;
+fail:
+	pci_dev_put(pdev);
+	return -ENODEV;
+}
+
+const struct x86_cpu_id skx_cpuids[] = {
+	{ X86_VENDOR_INTEL, 6, 0x55, 0, 0 },	/* Skylake */
+	{ }
+};
+MODULE_DEVICE_TABLE(x86cpu, skx_cpuids);
+
+static u8 get_src_id(struct skx_dev *d)
+{
+	u32 reg;
+
+	pci_read_config_dword(d->util_all, 0xF0, &reg);
+
+	return GET_BITFIELD(reg, 12, 14);
+}
+
+static u8 skx_get_node_id(struct skx_dev *d)
+{
+	u32 reg;
+
+	pci_read_config_dword(d->util_all, 0xF4, &reg);
+
+	return GET_BITFIELD(reg, 0, 2);
+}
+
+static int get_dimm_attr(u32 reg, int lobit, int hibit, int add, int minval,
+			 int maxval, char *name)
+{
+	u32 val = GET_BITFIELD(reg, lobit, hibit);
+
+	if (val < minval || val > maxval) {
+		edac_dbg(2, "bad %s = %d (raw=%x)\n", name, val, reg);
+		return -EINVAL;
+	}
+	return val + add;
+}
+
+#define IS_DIMM_PRESENT(mtr)		GET_BITFIELD((mtr), 15, 15)
+
+#define numrank(reg) get_dimm_attr((reg), 12, 13, 0, 1, 2, "ranks")
+#define numrow(reg) get_dimm_attr((reg), 2, 4, 12, 1, 6, "rows")
+#define numcol(reg) get_dimm_attr((reg), 0, 1, 10, 0, 2, "cols")
+
+static int get_width(u32 mtr)
+{
+	switch (GET_BITFIELD(mtr, 8, 9)) {
+	case 0:
+		return DEV_X4;
+	case 1:
+		return DEV_X8;
+	case 2:
+		return DEV_X16;
+	}
+	return DEV_UNKNOWN;
+}
+
+static int skx_get_hi_lo(void)
+{
+	struct pci_dev *pdev;
+	u32 reg;
+
+	pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x2034, NULL);
+	if (!pdev) {
+		edac_dbg(0, "Can't get tolm/tohm\n");
+		return -ENODEV;
+	}
+
+	pci_read_config_dword(pdev, 0xD0, &reg);
+	skx_tolm = reg;
+	pci_read_config_dword(pdev, 0xD4, &reg);
+	skx_tohm = reg;
+	pci_read_config_dword(pdev, 0xD8, &reg);
+	skx_tohm |= (u64)reg << 32;
+
+	pci_dev_put(pdev);
+	edac_dbg(2, "tolm=%llx tohm=%llx\n", skx_tolm, skx_tohm);
+
+	return 0;
+}
+
+static int get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
+			 struct skx_imc *imc, int chan, int dimmno)
+{
+	int  banks = 16, ranks, rows, cols, npages;
+	u64 size;
+
+	if (!IS_DIMM_PRESENT(mtr))
+		return 0;
+	ranks = numrank(mtr);
+	rows = numrow(mtr);
+	cols = numcol(mtr);
+
+	/*
+	 * Compute size in 8-byte (2^3) words, then shift to MiB (2^20)
+	 */
+	size = ((1ull << (rows + cols + ranks)) * banks) >> (20 - 3);
+	npages = MiB_TO_PAGES(size);
+
+	edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+		 imc->mc, chan, dimmno, size, npages,
+		 banks, ranks, rows, cols);
+
+	imc->chan[chan].dimms[dimmno].close_pg = GET_BITFIELD(mtr, 0, 0);
+	imc->chan[chan].dimms[dimmno].bank_xor_enable = GET_BITFIELD(mtr, 9, 9);
+	imc->chan[chan].dimms[dimmno].fine_grain_bank = GET_BITFIELD(amap, 0, 0);
+	imc->chan[chan].dimms[dimmno].rowbits = rows;
+	imc->chan[chan].dimms[dimmno].colbits = cols;
+
+	dimm->nr_pages = npages;
+	dimm->grain = 32;
+	dimm->dtype = get_width(mtr);
+	dimm->mtype = MEM_DDR4;
+	dimm->edac_mode = EDAC_SECDED; /* likely better than this */
+	snprintf(dimm->label, sizeof(dimm->label), "CPU_SrcID#%u_MC#%u_Chan#%u_DIMM#%u",
+		 imc->src_id, imc->lmc, chan, dimmno);
+
+	return 1;
+}
+
+#define SKX_GET_MTMTR(dev, reg) \
+	pci_read_config_dword((dev), 0x87c, &reg)
+
+static bool skx_check_ecc(struct pci_dev *pdev)
+{
+	u32 mtmtr;
+
+	SKX_GET_MTMTR(pdev, mtmtr);
+
+	return !!GET_BITFIELD(mtmtr, 2, 2);
+}
+
+static int skx_get_dimm_config(struct mem_ctl_info *mci)
+{
+	struct skx_pvt *pvt = mci->pvt_info;
+	struct skx_imc *imc = pvt->imc;
+	struct dimm_info *dimm;
+	int i, j;
+	u32 mtr, amap;
+	int ndimms;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		ndimms = 0;
+		pci_read_config_dword(imc->chan[i].cdev, 0x8C, &amap);
+		for (j = 0; j < NUM_DIMMS; j++) {
+			dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
+					     mci->n_layers, i, j, 0);
+			pci_read_config_dword(imc->chan[i].cdev,
+					0x80 + 4*j, &mtr);
+			ndimms += get_dimm_info(mtr, amap, dimm, imc, i, j);
+		}
+		if (ndimms && !skx_check_ecc(imc->chan[0].cdev)) {
+			skx_printk(KERN_ERR, "ECC is disabled on imc %d\n", imc->mc);
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static void skx_unregister_mci(struct skx_imc *imc)
+{
+	struct mem_ctl_info *mci = imc->mci;
+
+	if (!mci)
+		return;
+
+	edac_dbg(0, "MC%d: mci = %p\n", imc->mc, mci);
+
+	/* Remove MC sysfs nodes */
+	edac_mc_del_mc(mci->pdev);
+
+	edac_dbg(1, "%s: free mci struct\n", mci->ctl_name);
+	kfree(mci->ctl_name);
+	edac_mc_free(mci);
+}
+
+static int skx_register_mci(struct skx_imc *imc)
+{
+	struct mem_ctl_info *mci;
+	struct edac_mc_layer layers[2];
+	struct pci_dev *pdev = imc->chan[0].cdev;
+	struct skx_pvt *pvt;
+	int rc;
+
+	/* allocate a new MC control structure */
+	layers[0].type = EDAC_MC_LAYER_CHANNEL;
+	layers[0].size = NUM_CHANNELS;
+	layers[0].is_virt_csrow = false;
+	layers[1].type = EDAC_MC_LAYER_SLOT;
+	layers[1].size = NUM_DIMMS;
+	layers[1].is_virt_csrow = true;
+	mci = edac_mc_alloc(imc->mc, ARRAY_SIZE(layers), layers,
+			    sizeof(struct skx_pvt));
+
+	if (unlikely(!mci))
+		return -ENOMEM;
+
+	edac_dbg(0, "MC#%d: mci = %p\n", imc->mc, mci);
+
+	/* Associate skx_dev and mci for future usage */
+	imc->mci = mci;
+	pvt = mci->pvt_info;
+	pvt->imc = imc;
+
+	mci->ctl_name = kasprintf(GFP_KERNEL, "Skylake Socket#%d IMC#%d",
+				  imc->node_id, imc->lmc);
+	mci->mtype_cap = MEM_FLAG_DDR4;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE;
+	mci->edac_cap = EDAC_FLAG_NONE;
+	mci->mod_name = "skx_edac.c";
+	mci->dev_name = pci_name(imc->chan[0].cdev);
+	mci->mod_ver = SKX_REVISION;
+	mci->ctl_page_to_phys = NULL;
+
+	rc = skx_get_dimm_config(mci);
+	if (rc < 0)
+		goto fail;
+
+	/* record ptr to the generic device */
+	mci->pdev = &pdev->dev;
+
+	/* add this new MC control structure to EDAC's list of MCs */
+	if (unlikely(edac_mc_add_mc(mci))) {
+		edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	kfree(mci->ctl_name);
+	edac_mc_free(mci);
+	imc->mci = NULL;
+	return rc;
+}
+
+#define	SKX_MAX_SAD 24
+
+#define SKX_GET_SAD(d, i, reg)	\
+	pci_read_config_dword((d)->sad_all, 0x60 + 8 * (i), &reg)
+#define SKX_GET_ILV(d, i, reg)	\
+	pci_read_config_dword((d)->sad_all, 0x64 + 8 * (i), &reg)
+
+#define	SKX_SAD_MOD3MODE(sad)	GET_BITFIELD((sad), 30, 31)
+#define	SKX_SAD_MOD3(sad)	GET_BITFIELD((sad), 27, 27)
+#define SKX_SAD_LIMIT(sad)	(((u64)GET_BITFIELD((sad), 7, 26) << 26) | MASK26)
+#define	SKX_SAD_MOD3ASMOD2(sad)	GET_BITFIELD((sad), 5, 6)
+#define	SKX_SAD_ATTR(sad)	GET_BITFIELD((sad), 3, 4)
+#define	SKX_SAD_INTERLEAVE(sad)	GET_BITFIELD((sad), 1, 2)
+#define SKX_SAD_ENABLE(sad)	GET_BITFIELD((sad), 0, 0)
+
+#define SKX_ILV_REMOTE(tgt)	(((tgt) & 8) == 0)
+#define SKX_ILV_TARGET(tgt)	((tgt) & 7)
+
+static bool skx_sad_decode(struct decoded_addr *res)
+{
+	struct skx_dev *d = list_first_entry(&skx_edac_list, typeof(*d), list);
+	u64 addr = res->addr;
+	int i, idx, tgt, lchan, shift;
+	u32 sad, ilv;
+	u64 limit, prev_limit;
+	int remote = 0;
+
+	/* Simple sanity check for I/O space or out of range */
+	if (addr >= skx_tohm || (addr >= skx_tolm && addr < BIT_ULL(32))) {
+		edac_dbg(0, "Address %llx out of range\n", addr);
+		return false;
+	}
+
+restart:
+	prev_limit = 0;
+	for (i = 0; i < SKX_MAX_SAD; i++) {
+		SKX_GET_SAD(d, i, sad);
+		limit = SKX_SAD_LIMIT(sad);
+		if (SKX_SAD_ENABLE(sad)) {
+			if (addr >= prev_limit && addr <= limit)
+				goto sad_found;
+		}
+		prev_limit = limit + 1;
+	}
+	edac_dbg(0, "No SAD entry for %llx\n", addr);
+	return false;
+
+sad_found:
+	SKX_GET_ILV(d, i, ilv);
+
+	switch (SKX_SAD_INTERLEAVE(sad)) {
+	case 0:
+		idx = GET_BITFIELD(addr, 6, 8);
+		break;
+	case 1:
+		idx = GET_BITFIELD(addr, 8, 10);
+		break;
+	case 2:
+		idx = GET_BITFIELD(addr, 12, 14);
+		break;
+	case 3:
+		idx = GET_BITFIELD(addr, 30, 32);
+		break;
+	}
+
+	tgt = GET_BITFIELD(ilv, 4 * idx, 4 * idx + 3);
+
+	/* If point to another node, find it and start over */
+	if (SKX_ILV_REMOTE(tgt)) {
+		if (remote) {
+			edac_dbg(0, "Double remote!\n");
+			return false;
+		}
+		remote = 1;
+		list_for_each_entry(d, &skx_edac_list, list) {
+			if (d->imc[0].src_id == SKX_ILV_TARGET(tgt))
+				goto restart;
+		}
+		edac_dbg(0, "Can't find node %d\n", SKX_ILV_TARGET(tgt));
+		return false;
+	}
+
+	if (SKX_SAD_MOD3(sad) == 0)
+		lchan = SKX_ILV_TARGET(tgt);
+	else {
+		switch (SKX_SAD_MOD3MODE(sad)) {
+		case 0:
+			shift = 6;
+			break;
+		case 1:
+			shift = 8;
+			break;
+		case 2:
+			shift = 12;
+			break;
+		default:
+			edac_dbg(0, "illegal mod3mode\n");
+			return false;
+		}
+		switch (SKX_SAD_MOD3ASMOD2(sad)) {
+		case 0:
+			lchan = (addr >> shift) % 3;
+			break;
+		case 1:
+			lchan = (addr >> shift) % 2;
+			break;
+		case 2:
+			lchan = (addr >> shift) % 2;
+			lchan = (lchan << 1) | ~lchan;
+			break;
+		case 3:
+			lchan = ((addr >> shift) % 2) << 1;
+			break;
+		}
+		lchan = (lchan << 1) | (SKX_ILV_TARGET(tgt) & 1);
+	}
+
+	res->dev = d;
+	res->socket = d->imc[0].src_id;
+	res->imc = GET_BITFIELD(d->mcroute, lchan * 3, lchan * 3 + 2);
+	res->channel = GET_BITFIELD(d->mcroute, lchan * 2 + 18, lchan * 2 + 19);
+
+	edac_dbg(2, "%llx: socket=%d imc=%d channel=%d\n",
+		 res->addr, res->socket, res->imc, res->channel);
+	return true;
+}
+
+#define	SKX_MAX_TAD 8
+
+#define SKX_GET_TADBASE(d, mc, i, reg)			\
+	pci_read_config_dword((d)->imc[mc].chan[0].cdev, 0x850 + 4 * (i), &reg)
+#define SKX_GET_TADWAYNESS(d, mc, i, reg)		\
+	pci_read_config_dword((d)->imc[mc].chan[0].cdev, 0x880 + 4 * (i), &reg)
+#define SKX_GET_TADCHNILVOFFSET(d, mc, ch, i, reg)	\
+	pci_read_config_dword((d)->imc[mc].chan[ch].cdev, 0x90 + 4 * (i), &reg)
+
+#define	SKX_TAD_BASE(b)		((u64)GET_BITFIELD((b), 12, 31) << 26)
+#define SKX_TAD_SKT_GRAN(b)	GET_BITFIELD((b), 4, 5)
+#define SKX_TAD_CHN_GRAN(b)	GET_BITFIELD((b), 6, 7)
+#define	SKX_TAD_LIMIT(b)	(((u64)GET_BITFIELD((b), 12, 31) << 26) | MASK26)
+#define	SKX_TAD_OFFSET(b)	((u64)GET_BITFIELD((b), 4, 23) << 26)
+#define	SKX_TAD_SKTWAYS(b)	(1 << GET_BITFIELD((b), 10, 11))
+#define	SKX_TAD_CHNWAYS(b)	(GET_BITFIELD((b), 8, 9) + 1)
+
+/* which bit used for both socket and channel interleave */
+static int skx_granularity[] = { 6, 8, 12, 30 };
+
+static u64 skx_do_interleave(u64 addr, int shift, int ways, u64 lowbits)
+{
+	addr >>= shift;
+	addr /= ways;
+	addr <<= shift;
+
+	return addr | (lowbits & ((1ull << shift) - 1));
+}
+
+static bool skx_tad_decode(struct decoded_addr *res)
+{
+	int i;
+	u32 base, wayness, chnilvoffset;
+	int skt_interleave_bit, chn_interleave_bit;
+	u64 channel_addr;
+
+	for (i = 0; i < SKX_MAX_TAD; i++) {
+		SKX_GET_TADBASE(res->dev, res->imc, i, base);
+		SKX_GET_TADWAYNESS(res->dev, res->imc, i, wayness);
+		if (SKX_TAD_BASE(base) <= res->addr && res->addr <= SKX_TAD_LIMIT(wayness))
+			goto tad_found;
+	}
+	edac_dbg(0, "No TAD entry for %llx\n", res->addr);
+	return false;
+
+tad_found:
+	res->sktways = SKX_TAD_SKTWAYS(wayness);
+	res->chanways = SKX_TAD_CHNWAYS(wayness);
+	skt_interleave_bit = skx_granularity[SKX_TAD_SKT_GRAN(base)];
+	chn_interleave_bit = skx_granularity[SKX_TAD_CHN_GRAN(base)];
+
+	SKX_GET_TADCHNILVOFFSET(res->dev, res->imc, res->channel, i, chnilvoffset);
+	channel_addr = res->addr - SKX_TAD_OFFSET(chnilvoffset);
+
+	if (res->chanways == 3 && skt_interleave_bit > chn_interleave_bit) {
+		/* Must handle channel first, then socket */
+		channel_addr = skx_do_interleave(channel_addr, chn_interleave_bit,
+						 res->chanways, channel_addr);
+		channel_addr = skx_do_interleave(channel_addr, skt_interleave_bit,
+						 res->sktways, channel_addr);
+	} else {
+		/* Handle socket then channel. Preserve low bits from original address */
+		channel_addr = skx_do_interleave(channel_addr, skt_interleave_bit,
+						 res->sktways, res->addr);
+		channel_addr = skx_do_interleave(channel_addr, chn_interleave_bit,
+						 res->chanways, res->addr);
+	}
+
+	res->chan_addr = channel_addr;
+
+	edac_dbg(2, "%llx: chan_addr=%llx sktways=%d chanways=%d\n",
+		 res->addr, res->chan_addr, res->sktways, res->chanways);
+	return true;
+}
+
+#define SKX_MAX_RIR 4
+
+#define SKX_GET_RIRWAYNESS(d, mc, ch, i, reg)		\
+	pci_read_config_dword((d)->imc[mc].chan[ch].cdev,	\
+			      0x108 + 4 * (i), &reg)
+#define SKX_GET_RIRILV(d, mc, ch, idx, i, reg)		\
+	pci_read_config_dword((d)->imc[mc].chan[ch].cdev,	\
+			      0x120 + 16 * idx + 4 * (i), &reg)
+
+#define	SKX_RIR_VALID(b) GET_BITFIELD((b), 31, 31)
+#define	SKX_RIR_LIMIT(b) (((u64)GET_BITFIELD((b), 1, 11) << 29) | MASK29)
+#define	SKX_RIR_WAYS(b) (1 << GET_BITFIELD((b), 28, 29))
+#define	SKX_RIR_CHAN_RANK(b) GET_BITFIELD((b), 16, 19)
+#define	SKX_RIR_OFFSET(b) ((u64)(GET_BITFIELD((b), 2, 15) << 26))
+
+static bool skx_rir_decode(struct decoded_addr *res)
+{
+	int i, idx, chan_rank;
+	int shift;
+	u32 rirway, rirlv;
+	u64 rank_addr, prev_limit = 0, limit;
+
+	if (res->dev->imc[res->imc].chan[res->channel].dimms[0].close_pg)
+		shift = 6;
+	else
+		shift = 13;
+
+	for (i = 0; i < SKX_MAX_RIR; i++) {
+		SKX_GET_RIRWAYNESS(res->dev, res->imc, res->channel, i, rirway);
+		limit = SKX_RIR_LIMIT(rirway);
+		if (SKX_RIR_VALID(rirway)) {
+			if (prev_limit <= res->chan_addr &&
+			    res->chan_addr <= limit)
+				goto rir_found;
+		}
+		prev_limit = limit;
+	}
+	edac_dbg(0, "No RIR entry for %llx\n", res->addr);
+	return false;
+
+rir_found:
+	rank_addr = res->chan_addr >> shift;
+	rank_addr /= SKX_RIR_WAYS(rirway);
+	rank_addr <<= shift;
+	rank_addr |= res->chan_addr & GENMASK_ULL(shift - 1, 0);
+
+	res->rank_address = rank_addr;
+	idx = (res->chan_addr >> shift) % SKX_RIR_WAYS(rirway);
+
+	SKX_GET_RIRILV(res->dev, res->imc, res->channel, idx, i, rirlv);
+	res->rank_address = rank_addr - SKX_RIR_OFFSET(rirlv);
+	chan_rank = SKX_RIR_CHAN_RANK(rirlv);
+	res->channel_rank = chan_rank;
+	res->dimm = chan_rank / 4;
+	res->rank = chan_rank % 4;
+
+	edac_dbg(2, "%llx: dimm=%d rank=%d chan_rank=%d rank_addr=%llx\n",
+		 res->addr, res->dimm, res->rank,
+		 res->channel_rank, res->rank_address);
+	return true;
+}
+
+static u8 skx_close_row[] = {
+	15, 16, 17, 18, 20, 21, 22, 28, 10, 11, 12, 13, 29, 30, 31, 32, 33
+};
+static u8 skx_close_column[] = {
+	3, 4, 5, 14, 19, 23, 24, 25, 26, 27
+};
+static u8 skx_open_row[] = {
+	14, 15, 16, 20, 28, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33
+};
+static u8 skx_open_column[] = {
+	3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+};
+static u8 skx_open_fine_column[] = {
+	3, 4, 5, 7, 8, 9, 10, 11, 12, 13
+};
+
+static int skx_bits(u64 addr, int nbits, u8 *bits)
+{
+	int i, res = 0;
+
+	for (i = 0; i < nbits; i++)
+		res |= ((addr >> bits[i]) & 1) << i;
+	return res;
+}
+
+static int skx_bank_bits(u64 addr, int b0, int b1, int do_xor, int x0, int x1)
+{
+	int ret = GET_BITFIELD(addr, b0, b0) | (GET_BITFIELD(addr, b1, b1) << 1);
+
+	if (do_xor)
+		ret ^= GET_BITFIELD(addr, x0, x0) | (GET_BITFIELD(addr, x1, x1) << 1);
+
+	return ret;
+}
+
+static bool skx_mad_decode(struct decoded_addr *r)
+{
+	struct skx_dimm *dimm = &r->dev->imc[r->imc].chan[r->channel].dimms[r->dimm];
+	int bg0 = dimm->fine_grain_bank ? 6 : 13;
+
+	if (dimm->close_pg) {
+		r->row = skx_bits(r->rank_address, dimm->rowbits, skx_close_row);
+		r->column = skx_bits(r->rank_address, dimm->colbits, skx_close_column);
+		r->column |= 0x400; /* C10 is autoprecharge, always set */
+		r->bank_address = skx_bank_bits(r->rank_address, 8, 9, dimm->bank_xor_enable, 22, 28);
+		r->bank_group = skx_bank_bits(r->rank_address, 6, 7, dimm->bank_xor_enable, 20, 21);
+	} else {
+		r->row = skx_bits(r->rank_address, dimm->rowbits, skx_open_row);
+		if (dimm->fine_grain_bank)
+			r->column = skx_bits(r->rank_address, dimm->colbits, skx_open_fine_column);
+		else
+			r->column = skx_bits(r->rank_address, dimm->colbits, skx_open_column);
+		r->bank_address = skx_bank_bits(r->rank_address, 18, 19, dimm->bank_xor_enable, 22, 23);
+		r->bank_group = skx_bank_bits(r->rank_address, bg0, 17, dimm->bank_xor_enable, 20, 21);
+	}
+	r->row &= (1u << dimm->rowbits) - 1;
+
+	edac_dbg(2, "%llx: row=%x col=%x bank_addr=%d bank_group=%d\n",
+		 r->addr, r->row, r->column, r->bank_address,
+		 r->bank_group);
+	return true;
+}
+
+static bool skx_decode(struct decoded_addr *res)
+{
+
+	return skx_sad_decode(res) && skx_tad_decode(res) &&
+		skx_rir_decode(res) && skx_mad_decode(res);
+}
+
+#ifdef CONFIG_EDAC_DEBUG
+/*
+ * Debug feature. Make /sys/kernel/debug/skx_edac_test/addr.
+ * Write an address to this file to exercise the address decode
+ * logic in this driver.
+ */
+static struct dentry *skx_test;
+static u64 skx_fake_addr;
+
+static int debugfs_u64_set(void *data, u64 val)
+{
+	struct decoded_addr res;
+
+	res.addr = val;
+	skx_decode(&res);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
+
+static struct dentry *mydebugfs_create(const char *name, umode_t mode,
+				       struct dentry *parent, u64 *value)
+{
+	return debugfs_create_file(name, mode, parent, value, &fops_u64_wo);
+}
+
+static void setup_skx_debug(void)
+{
+	skx_test = debugfs_create_dir("skx_edac_test", NULL);
+	mydebugfs_create("addr", S_IWUSR, skx_test, &skx_fake_addr);
+}
+
+static void teardown_skx_debug(void)
+{
+	debugfs_remove_recursive(skx_test);
+}
+#else
+static void setup_skx_debug(void)
+{
+}
+
+static void teardown_skx_debug(void)
+{
+}
+#endif /*CONFIG_EDAC_DEBUG*/
+
+static void skx_mce_output_error(struct mem_ctl_info *mci,
+				 const struct mce *m,
+				 struct decoded_addr *res)
+{
+	enum hw_event_mc_err_type tp_event;
+	char *type, *optype, msg[256];
+	bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);
+	bool overflow = GET_BITFIELD(m->status, 62, 62);
+	bool uncorrected_error = GET_BITFIELD(m->status, 61, 61);
+	bool recoverable;
+	u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52);
+	u32 mscod = GET_BITFIELD(m->status, 16, 31);
+	u32 errcode = GET_BITFIELD(m->status, 0, 15);
+	u32 optypenum = GET_BITFIELD(m->status, 4, 6);
+
+	recoverable = GET_BITFIELD(m->status, 56, 56);
+
+	if (uncorrected_error) {
+		if (ripv) {
+			type = "FATAL";
+			tp_event = HW_EVENT_ERR_FATAL;
+		} else {
+			type = "NON_FATAL";
+			tp_event = HW_EVENT_ERR_UNCORRECTED;
+		}
+	} else {
+		type = "CORRECTED";
+		tp_event = HW_EVENT_ERR_CORRECTED;
+	}
+
+	/*
+	 * According with Table 15-9 of the Intel Architecture spec vol 3A,
+	 * memory errors should fit in this mask:
+	 *	000f 0000 1mmm cccc (binary)
+	 * where:
+	 *	f = Correction Report Filtering Bit. If 1, subsequent errors
+	 *	    won't be shown
+	 *	mmm = error type
+	 *	cccc = channel
+	 * If the mask doesn't match, report an error to the parsing logic
+	 */
+	if (!((errcode & 0xef80) == 0x80)) {
+		optype = "Can't parse: it is not a mem";
+	} else {
+		switch (optypenum) {
+		case 0:
+			optype = "generic undef request error";
+			break;
+		case 1:
+			optype = "memory read error";
+			break;
+		case 2:
+			optype = "memory write error";
+			break;
+		case 3:
+			optype = "addr/cmd error";
+			break;
+		case 4:
+			optype = "memory scrubbing error";
+			break;
+		default:
+			optype = "reserved";
+			break;
+		}
+	}
+
+	snprintf(msg, sizeof(msg),
+		 "%s%s err_code:%04x:%04x socket:%d imc:%d rank:%d bg:%d ba:%d row:%x col:%x",
+		 overflow ? " OVERFLOW" : "",
+		 (uncorrected_error && recoverable) ? " recoverable" : "",
+		 mscod, errcode,
+		 res->socket, res->imc, res->rank,
+		 res->bank_group, res->bank_address, res->row, res->column);
+
+	edac_dbg(0, "%s\n", msg);
+
+	/* Call the helper to output message */
+	edac_mc_handle_error(tp_event, mci, core_err_cnt,
+			     m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
+			     res->channel, res->dimm, -1,
+			     optype, msg);
+}
+
+static int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
+			       void *data)
+{
+	struct mce *mce = (struct mce *)data;
+	struct decoded_addr res;
+	struct mem_ctl_info *mci;
+	char *type;
+
+	if (get_edac_report_status() == EDAC_REPORTING_DISABLED)
+		return NOTIFY_DONE;
+
+	/* ignore unless this is memory related with an address */
+	if ((mce->status & 0xefff) >> 7 != 1 || !(mce->status & MCI_STATUS_ADDRV))
+		return NOTIFY_DONE;
+
+	res.addr = mce->addr;
+	if (!skx_decode(&res))
+		return NOTIFY_DONE;
+	mci = res.dev->imc[res.imc].mci;
+
+	if (mce->mcgstatus & MCG_STATUS_MCIP)
+		type = "Exception";
+	else
+		type = "Event";
+
+	skx_mc_printk(mci, KERN_DEBUG, "HANDLING MCE MEMORY ERROR\n");
+
+	skx_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: %Lx "
+			  "Bank %d: %016Lx\n", mce->extcpu, type,
+			  mce->mcgstatus, mce->bank, mce->status);
+	skx_mc_printk(mci, KERN_DEBUG, "TSC %llx ", mce->tsc);
+	skx_mc_printk(mci, KERN_DEBUG, "ADDR %llx ", mce->addr);
+	skx_mc_printk(mci, KERN_DEBUG, "MISC %llx ", mce->misc);
+
+	skx_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:%x TIME %llu SOCKET "
+			  "%u APIC %x\n", mce->cpuvendor, mce->cpuid,
+			  mce->time, mce->socketid, mce->apicid);
+
+	skx_mce_output_error(mci, mce, &res);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block skx_mce_dec = {
+	.notifier_call = skx_mce_check_error,
+};
+
+static void skx_remove(void)
+{
+	int i, j;
+	struct skx_dev *d, *tmp;
+
+	edac_dbg(0, "\n");
+
+	list_for_each_entry_safe(d, tmp, &skx_edac_list, list) {
+		list_del(&d->list);
+		for (i = 0; i < NUM_IMC; i++) {
+			skx_unregister_mci(&d->imc[i]);
+			for (j = 0; j < NUM_CHANNELS; j++)
+				pci_dev_put(d->imc[i].chan[j].cdev);
+		}
+		pci_dev_put(d->util_all);
+		pci_dev_put(d->sad_all);
+
+		kfree(d);
+	}
+}
+
+/*
+ * skx_init:
+ *	make sure we are running on the correct cpu model
+ *	search for all the devices we need
+ *	check which DIMMs are present.
+ */
+int __init skx_init(void)
+{
+	const struct x86_cpu_id *id;
+	const struct munit *m;
+	int rc = 0, i;
+	u8 mc = 0, src_id, node_id;
+	struct skx_dev *d;
+
+	edac_dbg(2, "\n");
+
+	id = x86_match_cpu(skx_cpuids);
+	if (!id)
+		return -ENODEV;
+
+	rc = skx_get_hi_lo();
+	if (rc)
+		return rc;
+
+	rc = get_all_bus_mappings();
+	if (rc < 0)
+		goto fail;
+	if (rc == 0) {
+		edac_dbg(2, "No memory controllers found\n");
+		return -ENODEV;
+	}
+
+	for (m = skx_all_munits; m->did; m++) {
+		rc = get_all_munits(m);
+		if (rc < 0)
+			goto fail;
+		if (rc != m->per_socket * skx_num_sockets) {
+			edac_dbg(2, "Expected %d, got %d of %x\n",
+				 m->per_socket * skx_num_sockets, rc, m->did);
+			rc = -ENODEV;
+			goto fail;
+		}
+	}
+
+	list_for_each_entry(d, &skx_edac_list, list) {
+		src_id = get_src_id(d);
+		node_id = skx_get_node_id(d);
+		edac_dbg(2, "src_id=%d node_id=%d\n", src_id, node_id);
+		for (i = 0; i < NUM_IMC; i++) {
+			d->imc[i].mc = mc++;
+			d->imc[i].lmc = i;
+			d->imc[i].src_id = src_id;
+			d->imc[i].node_id = node_id;
+			rc = skx_register_mci(&d->imc[i]);
+			if (rc < 0)
+				goto fail;
+		}
+	}
+
+	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
+	opstate_init();
+
+	setup_skx_debug();
+
+	mce_register_decode_chain(&skx_mce_dec);
+
+	return 0;
+fail:
+	skx_remove();
+	return rc;
+}
+
+static void __exit skx_exit(void)
+{
+	edac_dbg(2, "\n");
+	mce_unregister_decode_chain(&skx_mce_dec);
+	skx_remove();
+	teardown_skx_debug();
+}
+
+module_init(skx_init);
+module_exit(skx_exit);
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Tony Luck");
+MODULE_DESCRIPTION("MC Driver for Intel Skylake server processors");
--- linux-4.4.0.orig/drivers/extcon/extcon-arizona.c
+++ linux-4.4.0/drivers/extcon/extcon-arizona.c
@@ -1616,6 +1616,16 @@
 	struct arizona_extcon_info *info = platform_get_drvdata(pdev);
 	struct arizona *arizona = info->arizona;
 	int jack_irq_rise, jack_irq_fall;
+	bool change;
+
+	regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+				 ARIZONA_MICD_ENA, 0,
+				 &change);
+
+	if (change) {
+		regulator_disable(info->micvdd);
+		pm_runtime_put(info->dev);
+	}
 
 	gpiod_put(info->micd_pol_gpio);
 
--- linux-4.4.0.orig/drivers/extcon/extcon-axp288.c
+++ linux-4.4.0/drivers/extcon/extcon-axp288.c
@@ -168,7 +168,7 @@
 		return ret;
 	}
 
-	vbus_attach = (pwr_stat & PS_STAT_VBUS_PRESENT);
+	vbus_attach = (pwr_stat & PS_STAT_VBUS_VALID);
 	if (!vbus_attach)
 		goto notify_otg;
 
--- linux-4.4.0.orig/drivers/extcon/extcon-max77693.c
+++ linux-4.4.0/drivers/extcon/extcon-max77693.c
@@ -1262,4 +1262,4 @@
 MODULE_DESCRIPTION("Maxim MAX77693 Extcon driver");
 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:extcon-max77693");
+MODULE_ALIAS("platform:max77693-muic");
--- linux-4.4.0.orig/drivers/extcon/extcon-max77843.c
+++ linux-4.4.0/drivers/extcon/extcon-max77843.c
@@ -803,7 +803,7 @@
 	/* Clear IRQ bits before request IRQs */
 	ret = regmap_bulk_read(max77843->regmap_muic,
 			MAX77843_MUIC_REG_INT1, info->status,
-			MAX77843_MUIC_IRQ_NUM);
+			MAX77843_MUIC_STATUS_NUM);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to Clear IRQ bits\n");
 		goto err_muic_irq;
--- linux-4.4.0.orig/drivers/extcon/extcon-max8997.c
+++ linux-4.4.0/drivers/extcon/extcon-max8997.c
@@ -320,12 +320,10 @@
 {
 	int ret = 0;
 
-	if (usb_type == MAX8997_USB_HOST) {
-		ret = max8997_muic_set_path(info, info->path_usb, attached);
-		if (ret < 0) {
-			dev_err(info->dev, "failed to update muic register\n");
-			return ret;
-		}
+	ret = max8997_muic_set_path(info, info->path_usb, attached);
+	if (ret < 0) {
+		dev_err(info->dev, "failed to update muic register\n");
+		return ret;
 	}
 
 	switch (usb_type) {
--- linux-4.4.0.orig/drivers/extcon/extcon-palmas.c
+++ linux-4.4.0/drivers/extcon/extcon-palmas.c
@@ -190,6 +190,11 @@
 	struct palmas_usb *palmas_usb;
 	int status;
 
+	if (!palmas) {
+		dev_err(&pdev->dev, "failed to get valid parent\n");
+		return -EINVAL;
+	}
+
 	palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
 	if (!palmas_usb)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/extcon/extcon-sm5502.c
+++ linux-4.4.0/drivers/extcon/extcon-sm5502.c
@@ -69,6 +69,10 @@
 /* Default value of SM5502 register to bring up MUIC device. */
 static struct reg_data sm5502_reg_data[] = {
 	{
+		.reg = SM5502_REG_RESET,
+		.val = SM5502_REG_RESET_MASK,
+		.invert = true,
+	}, {
 		.reg = SM5502_REG_CONTROL,
 		.val = SM5502_REG_CONTROL_MASK_INT_MASK,
 		.invert = false,
--- linux-4.4.0.orig/drivers/extcon/extcon-sm5502.h
+++ linux-4.4.0/drivers/extcon/extcon-sm5502.h
@@ -241,6 +241,8 @@
 #define DM_DP_SWITCH_UART			((DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
 						| (DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
 
+#define SM5502_REG_RESET_MASK			(0x1)
+
 /* SM5502 Interrupts */
 enum sm5502_irq {
 	/* INT1 */
--- linux-4.4.0.orig/drivers/extcon/extcon-usb-gpio.c
+++ linux-4.4.0/drivers/extcon/extcon-usb-gpio.c
@@ -192,6 +192,9 @@
 	}
 
 	enable_irq(info->id_irq);
+	if (!device_may_wakeup(dev))
+		queue_delayed_work(system_power_efficient_wq,
+				   &info->wq_detcable, 0);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/firewire/core-cdev.c
+++ linux-4.4.0/drivers/firewire/core-cdev.c
@@ -1496,6 +1496,7 @@
 {
 	struct outbound_phy_packet_event *e =
 		container_of(packet, struct outbound_phy_packet_event, p);
+	struct client *e_client;
 
 	switch (status) {
 	/* expected: */
@@ -1512,9 +1513,10 @@
 	}
 	e->phy_packet.data[0] = packet->timestamp;
 
+	e_client = e->client;
 	queue_event(e->client, &e->event, &e->phy_packet,
 		    sizeof(e->phy_packet) + e->phy_packet.length, NULL, 0);
-	client_put(e->client);
+	client_put(e_client);
 }
 
 static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
--- linux-4.4.0.orig/drivers/firewire/net.c
+++ linux-4.4.0/drivers/firewire/net.c
@@ -73,13 +73,13 @@
 
 #define fwnet_get_hdr_lf(h)		(((h)->w0 & 0xc0000000) >> 30)
 #define fwnet_get_hdr_ether_type(h)	(((h)->w0 & 0x0000ffff))
-#define fwnet_get_hdr_dg_size(h)	(((h)->w0 & 0x0fff0000) >> 16)
+#define fwnet_get_hdr_dg_size(h)	((((h)->w0 & 0x0fff0000) >> 16) + 1)
 #define fwnet_get_hdr_fg_off(h)		(((h)->w0 & 0x00000fff))
 #define fwnet_get_hdr_dgl(h)		(((h)->w1 & 0xffff0000) >> 16)
 
-#define fwnet_set_hdr_lf(lf)		((lf)  << 30)
+#define fwnet_set_hdr_lf(lf)		((lf) << 30)
 #define fwnet_set_hdr_ether_type(et)	(et)
-#define fwnet_set_hdr_dg_size(dgs)	((dgs) << 16)
+#define fwnet_set_hdr_dg_size(dgs)	(((dgs) - 1) << 16)
 #define fwnet_set_hdr_fg_off(fgo)	(fgo)
 
 #define fwnet_set_hdr_dgl(dgl)		((dgl) << 16)
@@ -249,7 +249,11 @@
 	h = (struct fwnet_header *)((u8 *)hh->hh_data + HH_DATA_OFF(sizeof(*h)));
 	h->h_proto = type;
 	memcpy(h->h_dest, neigh->ha, net->addr_len);
-	hh->hh_len = FWNET_HLEN;
+
+	/* Pairs with the READ_ONCE() in neigh_resolve_output(),
+	 * neigh_hh_output() and neigh_update_hhs().
+	 */
+	smp_store_release(&hh->hh_len, FWNET_HLEN);
 
 	return 0;
 }
@@ -578,6 +582,9 @@
 	int retval;
 	u16 ether_type;
 
+	if (len <= RFC2374_UNFRAG_HDR_SIZE)
+		return 0;
+
 	hdr.w0 = be32_to_cpu(buf[0]);
 	lf = fwnet_get_hdr_lf(&hdr);
 	if (lf == RFC2374_HDR_UNFRAG) {
@@ -602,7 +609,12 @@
 		return fwnet_finish_incoming_packet(net, skb, source_node_id,
 						    is_broadcast, ether_type);
 	}
+
 	/* A datagram fragment has been received, now the fun begins. */
+
+	if (len <= RFC2374_FRAG_HDR_SIZE)
+		return 0;
+
 	hdr.w1 = ntohl(buf[1]);
 	buf += 2;
 	len -= RFC2374_FRAG_HDR_SIZE;
@@ -614,7 +626,10 @@
 		fg_off = fwnet_get_hdr_fg_off(&hdr);
 	}
 	datagram_label = fwnet_get_hdr_dgl(&hdr);
-	dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */
+	dg_size = fwnet_get_hdr_dg_size(&hdr);
+
+	if (fg_off + len > dg_size)
+		return 0;
 
 	spin_lock_irqsave(&dev->lock, flags);
 
@@ -722,6 +737,22 @@
 	fw_send_response(card, r, rcode);
 }
 
+static int gasp_source_id(__be32 *p)
+{
+	return be32_to_cpu(p[0]) >> 16;
+}
+
+static u32 gasp_specifier_id(__be32 *p)
+{
+	return (be32_to_cpu(p[0]) & 0xffff) << 8 |
+	       (be32_to_cpu(p[1]) & 0xff000000) >> 24;
+}
+
+static u32 gasp_version(__be32 *p)
+{
+	return be32_to_cpu(p[1]) & 0xffffff;
+}
+
 static void fwnet_receive_broadcast(struct fw_iso_context *context,
 		u32 cycle, size_t header_length, void *header, void *data)
 {
@@ -731,9 +762,6 @@
 	__be32 *buf_ptr;
 	int retval;
 	u32 length;
-	u16 source_node_id;
-	u32 specifier_id;
-	u32 ver;
 	unsigned long offset;
 	unsigned long flags;
 
@@ -750,22 +778,17 @@
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	specifier_id =    (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8
-			| (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24;
-	ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;
-	source_node_id = be32_to_cpu(buf_ptr[0]) >> 16;
-
-	if (specifier_id == IANA_SPECIFIER_ID &&
-	    (ver == RFC2734_SW_VERSION
+	if (length > IEEE1394_GASP_HDR_SIZE &&
+	    gasp_specifier_id(buf_ptr) == IANA_SPECIFIER_ID &&
+	    (gasp_version(buf_ptr) == RFC2734_SW_VERSION
 #if IS_ENABLED(CONFIG_IPV6)
-	     || ver == RFC3146_SW_VERSION
+	     || gasp_version(buf_ptr) == RFC3146_SW_VERSION
 #endif
-	    )) {
-		buf_ptr += 2;
-		length -= IEEE1394_GASP_HDR_SIZE;
-		fwnet_incoming_packet(dev, buf_ptr, length, source_node_id,
+	    ))
+		fwnet_incoming_packet(dev, buf_ptr + 2,
+				      length - IEEE1394_GASP_HDR_SIZE,
+				      gasp_source_id(buf_ptr),
 				      context->card->generation, true);
-	}
 
 	packet.payload_length = dev->rcv_buffer_size;
 	packet.interrupt = 1;
--- linux-4.4.0.orig/drivers/firewire/nosy.c
+++ linux-4.4.0/drivers/firewire/nosy.c
@@ -358,6 +358,7 @@
 	struct client *client = file->private_data;
 	spinlock_t *client_list_lock = &client->lynx->client_list_lock;
 	struct nosy_stats stats;
+	int ret;
 
 	switch (cmd) {
 	case NOSY_IOC_GET_STATS:
@@ -372,11 +373,15 @@
 			return 0;
 
 	case NOSY_IOC_START:
+		ret = -EBUSY;
 		spin_lock_irq(client_list_lock);
-		list_add_tail(&client->link, &client->lynx->client_list);
+		if (list_empty(&client->link)) {
+			list_add_tail(&client->link, &client->lynx->client_list);
+			ret = 0;
+		}
 		spin_unlock_irq(client_list_lock);
 
-		return 0;
+		return ret;
 
 	case NOSY_IOC_STOP:
 		spin_lock_irq(client_list_lock);
--- linux-4.4.0.orig/drivers/firewire/ohci.c
+++ linux-4.4.0/drivers/firewire/ohci.c
@@ -1130,7 +1130,13 @@
 		return -ENOMEM;
 
 	offset = (void *)&desc->buffer - (void *)desc;
-	desc->buffer_size = PAGE_SIZE - offset;
+	/*
+	 * Some controllers, like JMicron ones, always issue 0x20-byte DMA reads
+	 * for descriptors, even 0x10-byte ones. This can cause page faults when
+	 * an IOMMU is in use and the oversized read crosses a page boundary.
+	 * Work around this by always leaving at least 0x10 bytes of padding.
+	 */
+	desc->buffer_size = PAGE_SIZE - offset - 0x10;
 	desc->buffer_bus = bus_addr + offset;
 	desc->used = 0;
 
--- linux-4.4.0.orig/drivers/firmware/Kconfig
+++ linux-4.4.0/drivers/firmware/Kconfig
@@ -135,7 +135,7 @@
 
 config ISCSI_IBFT_FIND
 	bool "iSCSI Boot Firmware Table Attributes"
-	depends on X86 && ACPI
+	depends on X86 && ISCSI_IBFT
 	default n
 	help
 	  This option enables the kernel to find the region of memory
@@ -146,7 +146,8 @@
 config ISCSI_IBFT
 	tristate "iSCSI Boot Firmware Table Attributes module"
 	select ISCSI_BOOT_SYSFS
-	depends on ISCSI_IBFT_FIND && SCSI && SCSI_LOWLEVEL
+	select ISCSI_IBFT_FIND if X86
+	depends on ACPI && SCSI && SCSI_LOWLEVEL
 	default	n
 	help
 	  This option enables support for detection and exposing of iSCSI
@@ -173,6 +174,9 @@
 	def_bool y
 	depends on QCOM_SCM && ARM64
 
+config HAVE_ARM_SMCCC
+	bool
+
 source "drivers/firmware/broadcom/Kconfig"
 source "drivers/firmware/google/Kconfig"
 source "drivers/firmware/efi/Kconfig"
--- linux-4.4.0.orig/drivers/firmware/dmi_scan.c
+++ linux-4.4.0/drivers/firmware/dmi_scan.c
@@ -18,7 +18,7 @@
  * of and an antecedent to, SMBIOS, which stands for System
  * Management BIOS.  See further: http://www.dmtf.org/standards
  */
-static const char dmi_empty_string[] = "        ";
+static const char dmi_empty_string[] = "";
 
 static u32 dmi_ver __initdata;
 static u32 dmi_len;
@@ -44,25 +44,21 @@
 static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
 {
 	const u8 *bp = ((u8 *) dm) + dm->length;
+	const u8 *nsp;
 
 	if (s) {
-		s--;
-		while (s > 0 && *bp) {
+		while (--s > 0 && *bp)
 			bp += strlen(bp) + 1;
-			s--;
-		}
 
-		if (*bp != 0) {
-			size_t len = strlen(bp)+1;
-			size_t cmp_len = len > 8 ? 8 : len;
-
-			if (!memcmp(bp, dmi_empty_string, cmp_len))
-				return dmi_empty_string;
+		/* Strings containing only spaces are considered empty */
+		nsp = bp;
+		while (*nsp == ' ')
+			nsp++;
+		if (*nsp != '\0')
 			return bp;
-		}
 	}
 
-	return "";
+	return dmi_empty_string;
 }
 
 static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
--- linux-4.4.0.orig/drivers/firmware/efi/Kconfig
+++ linux-4.4.0/drivers/firmware/efi/Kconfig
@@ -87,6 +87,23 @@
 config EFI_ARMSTUB
 	bool
 
+config EFI_TEST
+	tristate "EFI Runtime Service Tests Support"
+	depends on EFI
+	default n
+	help
+	  This driver uses the efi.<service> function pointers directly instead
+	  of going through the efivar API, because it is not trying to test the
+	  kernel subsystem, just for testing the UEFI runtime service
+	  interfaces which are provided by the firmware. This driver is used
+	  by the Firmware Test Suite (FWTS) for testing the UEFI runtime
+	  interfaces readiness of the firmware.
+	  Details for FWTS are available from:
+	  <https://wiki.ubuntu.com/FirmwareTestSuite>
+
+	  Say Y here to enable the runtime services support via /dev/efi_test.
+	  If unsure, say N.
+
 endmenu
 
 config UEFI_CPER
--- linux-4.4.0.orig/drivers/firmware/efi/Makefile
+++ linux-4.4.0/drivers/firmware/efi/Makefile
@@ -18,3 +18,5 @@
 obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)	+= runtime-wrappers.o
 obj-$(CONFIG_EFI_STUB)			+= libstub/
 obj-$(CONFIG_EFI_FAKE_MEMMAP)		+= fake_mem.o
+obj-$(CONFIG_EFI_TEST)                  += test/
+
--- linux-4.4.0.orig/drivers/firmware/efi/cper.c
+++ linux-4.4.0/drivers/firmware/efi/cper.c
@@ -375,7 +375,7 @@
 		printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
 		       pcie->device_id.vendor_id, pcie->device_id.device_id);
 		p = pcie->device_id.class_code;
-		printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
+		printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
 	}
 	if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
 		printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
@@ -384,6 +384,21 @@
 		printk(
 	"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
 	pfx, pcie->bridge.secondary_status, pcie->bridge.control);
+
+	/* Fatal errors call __ghes_panic() before AER handler prints this */
+	if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
+	    (gdata->error_severity & CPER_SEV_FATAL)) {
+		struct aer_capability_regs *aer;
+
+		aer = (struct aer_capability_regs *)pcie->aer_info;
+		printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
+		       pfx, aer->uncor_status, aer->uncor_mask);
+		printk("%saer_uncor_severity: 0x%08x\n",
+		       pfx, aer->uncor_severity);
+		printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
+		       aer->header_log.dw0, aer->header_log.dw1,
+		       aer->header_log.dw2, aer->header_log.dw3);
+	}
 }
 
 static void cper_estatus_print_section(
--- linux-4.4.0.orig/drivers/firmware/efi/efi.c
+++ linux-4.4.0/drivers/firmware/efi/efi.c
@@ -113,8 +113,7 @@
 	return str - buf;
 }
 
-static struct kobj_attribute efi_attr_systab =
-			__ATTR(systab, 0400, systab_show, NULL);
+static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
 
 #define EFI_FIELD(var) efi.var
 
@@ -180,6 +179,7 @@
 {
 	generic_ops.get_variable = efi.get_variable;
 	generic_ops.set_variable = efi.set_variable;
+	generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
 	generic_ops.get_next_variable = efi.get_next_variable;
 	generic_ops.query_variable_store = efi_query_variable_store;
 
@@ -310,7 +310,6 @@
 
 		early_memunmap(md, sizeof (*md));
 	}
-	pr_err_once("requested map not found.\n");
 	return -ENOENT;
 }
 
@@ -324,38 +323,6 @@
 	return end;
 }
 
-/*
- * We can't ioremap data in EFI boot services RAM, because we've already mapped
- * it as RAM.  So, look it up in the existing EFI memory map instead.  Only
- * callable after efi_enter_virtual_mode and before efi_free_boot_services.
- */
-void __iomem *efi_lookup_mapped_addr(u64 phys_addr)
-{
-	struct efi_memory_map *map;
-	void *p;
-	map = efi.memmap;
-	if (!map)
-		return NULL;
-	if (WARN_ON(!map->map))
-		return NULL;
-	for (p = map->map; p < map->map_end; p += map->desc_size) {
-		efi_memory_desc_t *md = p;
-		u64 size = md->num_pages << EFI_PAGE_SHIFT;
-		u64 end = md->phys_addr + size;
-		if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
-		    md->type != EFI_BOOT_SERVICES_CODE &&
-		    md->type != EFI_BOOT_SERVICES_DATA)
-			continue;
-		if (!md->virt_addr)
-			continue;
-		if (phys_addr >= md->phys_addr && phys_addr < end) {
-			phys_addr += md->virt_addr - md->phys_addr;
-			return (__force void __iomem *)(unsigned long)phys_addr;
-		}
-	}
-	return NULL;
-}
-
 static __initdata efi_config_table_type_t common_tables[] = {
 	{ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
 	{ACPI_TABLE_GUID, "ACPI", &efi.acpi},
@@ -611,13 +578,16 @@
 	if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
 		     EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
 		     EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
+		     EFI_MEMORY_NV |
 		     EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
 		snprintf(pos, size, "|attr=0x%016llx]",
 			 (unsigned long long)attr);
 	else
-		snprintf(pos, size, "|%3s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
+		snprintf(pos, size,
+			 "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
 			 attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
 			 attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
+			 attr & EFI_MEMORY_NV      ? "NV"  : "",
 			 attr & EFI_MEMORY_XP      ? "XP"  : "",
 			 attr & EFI_MEMORY_RP      ? "RP"  : "",
 			 attr & EFI_MEMORY_WP      ? "WP"  : "",
--- linux-4.4.0.orig/drivers/firmware/efi/efivars.c
+++ linux-4.4.0/drivers/firmware/efi/efivars.c
@@ -139,13 +139,16 @@
 efivar_attr_read(struct efivar_entry *entry, char *buf)
 {
 	struct efi_variable *var = &entry->var;
+	unsigned long size = sizeof(var->Data);
 	char *str = buf;
+	int ret;
 
 	if (!entry || !buf)
 		return -EINVAL;
 
-	var->DataSize = 1024;
-	if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+	ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+	var->DataSize = size;
+	if (ret)
 		return -EIO;
 
 	if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
@@ -172,13 +175,16 @@
 efivar_size_read(struct efivar_entry *entry, char *buf)
 {
 	struct efi_variable *var = &entry->var;
+	unsigned long size = sizeof(var->Data);
 	char *str = buf;
+	int ret;
 
 	if (!entry || !buf)
 		return -EINVAL;
 
-	var->DataSize = 1024;
-	if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+	ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+	var->DataSize = size;
+	if (ret)
 		return -EIO;
 
 	str += sprintf(str, "0x%lx\n", var->DataSize);
@@ -189,12 +195,15 @@
 efivar_data_read(struct efivar_entry *entry, char *buf)
 {
 	struct efi_variable *var = &entry->var;
+	unsigned long size = sizeof(var->Data);
+	int ret;
 
 	if (!entry || !buf)
 		return -EINVAL;
 
-	var->DataSize = 1024;
-	if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+	ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+	var->DataSize = size;
+	if (ret)
 		return -EIO;
 
 	memcpy(buf, var->Data, var->DataSize);
@@ -221,7 +230,7 @@
 	}
 
 	if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
-	    efivar_validate(name, data, size) == false) {
+	    efivar_validate(vendor, name, data, size) == false) {
 		printk(KERN_ERR "efivars: Malformed variable content\n");
 		return -EINVAL;
 	}
@@ -263,6 +272,9 @@
 	u8 *data;
 	int err;
 
+	if (!entry || !buf)
+		return -EINVAL;
+
 	if (is_compat()) {
 		struct compat_efi_variable *compat;
 
@@ -314,14 +326,16 @@
 {
 	struct efi_variable *var = &entry->var;
 	struct compat_efi_variable *compat;
+	unsigned long datasize = sizeof(var->Data);
 	size_t size;
+	int ret;
 
 	if (!entry || !buf)
 		return 0;
 
-	var->DataSize = 1024;
-	if (efivar_entry_get(entry, &entry->var.Attributes,
-			     &entry->var.DataSize, entry->var.Data))
+	ret = efivar_entry_get(entry, &var->Attributes, &datasize, var->Data);
+	var->DataSize = datasize;
+	if (ret)
 		return -EIO;
 
 	if (is_compat()) {
@@ -447,7 +461,8 @@
 	}
 
 	if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
-	    efivar_validate(name, data, size) == false) {
+	    efivar_validate(new_var->VendorGuid, name, data,
+			    size) == false) {
 		printk(KERN_ERR "efivars: Malformed variable content\n");
 		return -EINVAL;
 	}
@@ -540,46 +555,40 @@
 static int
 efivar_create_sysfs_entry(struct efivar_entry *new_var)
 {
-	int i, short_name_size;
+	int short_name_size;
 	char *short_name;
-	unsigned long variable_name_size;
-	efi_char16_t *variable_name;
+	unsigned long utf8_name_size;
+	efi_char16_t *variable_name = new_var->var.VariableName;
 	int ret;
 
-	variable_name = new_var->var.VariableName;
-	variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
-
 	/*
-	 * Length of the variable bytes in ASCII, plus the '-' separator,
+	 * Length of the variable bytes in UTF8, plus the '-' separator,
 	 * plus the GUID, plus trailing NUL
 	 */
-	short_name_size = variable_name_size / sizeof(efi_char16_t)
-				+ 1 + EFI_VARIABLE_GUID_LEN + 1;
-
-	short_name = kzalloc(short_name_size, GFP_KERNEL);
+	utf8_name_size = ucs2_utf8size(variable_name);
+	short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
 
+	short_name = kmalloc(short_name_size, GFP_KERNEL);
 	if (!short_name)
 		return -ENOMEM;
 
-	/* Convert Unicode to normal chars (assume top bits are 0),
-	   ala UTF-8 */
-	for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
-		short_name[i] = variable_name[i] & 0xFF;
-	}
+	ucs2_as_utf8(short_name, variable_name, short_name_size);
+
 	/* This is ugly, but necessary to separate one vendor's
 	   private variables from another's.         */
-
-	*(short_name + strlen(short_name)) = '-';
+	short_name[utf8_name_size] = '-';
 	efi_guid_to_str(&new_var->var.VendorGuid,
-			 short_name + strlen(short_name));
+			 short_name + utf8_name_size + 1);
 
 	new_var->kobj.kset = efivars_kset;
 
 	ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
 				   NULL, "%s", short_name);
 	kfree(short_name);
-	if (ret)
+	if (ret) {
+		kobject_put(&new_var->kobj);
 		return ret;
+	}
 
 	kobject_uevent(&new_var->kobj, KOBJ_ADD);
 	efivar_entry_add(new_var, &efivar_sysfs_list);
--- linux-4.4.0.orig/drivers/firmware/efi/esrt.c
+++ linux-4.4.0/drivers/firmware/efi/esrt.c
@@ -105,7 +105,7 @@
 };
 
 /* Generic ESRT Entry ("ESRE") support. */
-static ssize_t esre_fw_class_show(struct esre_entry *entry, char *buf)
+static ssize_t fw_class_show(struct esre_entry *entry, char *buf)
 {
 	char *str = buf;
 
@@ -116,18 +116,16 @@
 	return str - buf;
 }
 
-static struct esre_attribute esre_fw_class = __ATTR(fw_class, 0400,
-	esre_fw_class_show, NULL);
+static struct esre_attribute esre_fw_class = __ATTR_RO_MODE(fw_class, 0400);
 
 #define esre_attr_decl(name, size, fmt) \
-static ssize_t esre_##name##_show(struct esre_entry *entry, char *buf) \
+static ssize_t name##_show(struct esre_entry *entry, char *buf) \
 { \
 	return sprintf(buf, fmt "\n", \
 		       le##size##_to_cpu(entry->esre.esre1->name)); \
 } \
 \
-static struct esre_attribute esre_##name = __ATTR(name, 0400, \
-	esre_##name##_show, NULL)
+static struct esre_attribute esre_##name = __ATTR_RO_MODE(name, 0400)
 
 esre_attr_decl(fw_type, 32, "%u");
 esre_attr_decl(fw_version, 32, "%u");
@@ -184,7 +182,7 @@
 		rc = kobject_init_and_add(&entry->kobj, &esre1_ktype, NULL,
 					  "%s", name);
 		if (rc) {
-			kfree(entry);
+			kobject_put(&entry->kobj);
 			return rc;
 		}
 	}
@@ -195,14 +193,13 @@
 
 /* support for displaying ESRT fields at the top level */
 #define esrt_attr_decl(name, size, fmt) \
-static ssize_t esrt_##name##_show(struct kobject *kobj, \
+static ssize_t name##_show(struct kobject *kobj, \
 				  struct kobj_attribute *attr, char *buf)\
 { \
 	return sprintf(buf, fmt "\n", le##size##_to_cpu(esrt->name)); \
 } \
 \
-static struct kobj_attribute esrt_##name = __ATTR(name, 0400, \
-	esrt_##name##_show, NULL)
+static struct kobj_attribute esrt_##name = __ATTR_RO_MODE(name, 0400)
 
 esrt_attr_decl(fw_resource_count, 32, "%u");
 esrt_attr_decl(fw_resource_count_max, 32, "%u");
@@ -256,7 +253,7 @@
 
 	rc = efi_mem_desc_lookup(efi.esrt, &md);
 	if (rc < 0) {
-		pr_err("ESRT header is not in the memory map.\n");
+		pr_warn("ESRT header is not in the memory map.\n");
 		return;
 	}
 
--- linux-4.4.0.orig/drivers/firmware/efi/libstub/Makefile
+++ linux-4.4.0/drivers/firmware/efi/libstub/Makefile
@@ -8,15 +8,15 @@
 cflags-$(CONFIG_X86_64)		:= -mcmodel=small
 cflags-$(CONFIG_X86)		+= -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
 				   -fPIC -fno-strict-aliasing -mno-red-zone \
-				   -mno-mmx -mno-sse -DDISABLE_BRANCH_PROFILING
+				   -mno-mmx -mno-sse
 
-cflags-$(CONFIG_ARM64)		:= $(subst -pg,,$(KBUILD_CFLAGS))
+cflags-$(CONFIG_ARM64)		:= $(subst -pg,,$(KBUILD_CFLAGS)) -fpie
 cflags-$(CONFIG_ARM)		:= $(subst -pg,,$(KBUILD_CFLAGS)) \
 				   -fno-builtin -fpic -mno-single-pic-base
 
 cflags-$(CONFIG_EFI_ARMSTUB)	+= -I$(srctree)/scripts/dtc/libfdt
 
-KBUILD_CFLAGS			:= $(cflags-y) \
+KBUILD_CFLAGS			:= $(cflags-y) -DDISABLE_BRANCH_PROFILING \
 				   $(call cc-option,-ffreestanding) \
 				   $(call cc-option,-fno-stack-protector)
 
@@ -34,7 +34,7 @@
 lib-$(CONFIG_EFI_ARMSTUB)	+= arm-stub.o fdt.o string.o \
 				   $(patsubst %.c,lib-%.o,$(arm-deps))
 
-lib-$(CONFIG_ARM64)		+= arm64-stub.o
+lib-$(CONFIG_ARM64)		+= arm64-stub.o random.o
 CFLAGS_arm64-stub.o 		:= -DTEXT_OFFSET=$(TEXT_OFFSET)
 
 #
--- linux-4.4.0.orig/drivers/firmware/efi/libstub/arm64-stub.c
+++ linux-4.4.0/drivers/firmware/efi/libstub/arm64-stub.c
@@ -9,9 +9,17 @@
  * published by the Free Software Foundation.
  *
  */
+
+/*
+ * To prevent the compiler from emitting GOT-indirected (and thus absolute)
+ * references to the section markers, override their visibility as 'hidden'
+ */
+#pragma GCC visibility push(hidden)
+#include <asm/sections.h>
+#pragma GCC visibility pop
+
 #include <linux/efi.h>
 #include <asm/efi.h>
-#include <asm/sections.h>
 
 efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
 					unsigned long *image_addr,
--- linux-4.4.0.orig/drivers/firmware/efi/libstub/efistub.h
+++ linux-4.4.0/drivers/firmware/efi/libstub/efistub.h
@@ -43,4 +43,7 @@
 		     unsigned long desc_size, efi_memory_desc_t *runtime_map,
 		     int *count);
 
+efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table,
+				  unsigned long size, u8 *out);
+
 #endif
--- linux-4.4.0.orig/drivers/firmware/efi/libstub/fdt.c
+++ linux-4.4.0/drivers/firmware/efi/libstub/fdt.c
@@ -24,7 +24,7 @@
 			unsigned long map_size, unsigned long desc_size,
 			u32 desc_ver)
 {
-	int node, prev, num_rsv;
+	int node, num_rsv;
 	int status;
 	u32 fdt_val32;
 	u64 fdt_val64;
@@ -54,28 +54,6 @@
 		goto fdt_set_fail;
 
 	/*
-	 * Delete any memory nodes present. We must delete nodes which
-	 * early_init_dt_scan_memory may try to use.
-	 */
-	prev = 0;
-	for (;;) {
-		const char *type;
-		int len;
-
-		node = fdt_next_node(fdt, prev, NULL);
-		if (node < 0)
-			break;
-
-		type = fdt_getprop(fdt, node, "device_type", &len);
-		if (type && strncmp(type, "memory", len) == 0) {
-			fdt_del_node(fdt, node);
-			continue;
-		}
-
-		prev = node;
-	}
-
-	/*
 	 * Delete all memory reserve map entries. When booting via UEFI,
 	 * kernel will use the UEFI memory map to find reserved regions.
 	 */
--- linux-4.4.0.orig/drivers/firmware/efi/libstub/random.c
+++ linux-4.4.0/drivers/firmware/efi/libstub/random.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 Linaro Ltd;  <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+struct efi_rng_protocol {
+	efi_status_t (*get_info)(struct efi_rng_protocol *,
+				 unsigned long *, efi_guid_t *);
+	efi_status_t (*get_rng)(struct efi_rng_protocol *,
+				efi_guid_t *, unsigned long, u8 *out);
+};
+
+efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg,
+				  unsigned long size, u8 *out)
+{
+	efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
+	efi_status_t status;
+	struct efi_rng_protocol *rng;
+
+	status = efi_call_early(locate_protocol, &rng_proto, NULL,
+				(void **)&rng);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	return rng->get_rng(rng, NULL, size, out);
+}
--- linux-4.4.0.orig/drivers/firmware/efi/runtime-map.c
+++ linux-4.4.0/drivers/firmware/efi/runtime-map.c
@@ -67,11 +67,11 @@
 	return map_attr->show(entry, buf);
 }
 
-static struct map_attribute map_type_attr = __ATTR_RO(type);
-static struct map_attribute map_phys_addr_attr   = __ATTR_RO(phys_addr);
-static struct map_attribute map_virt_addr_attr  = __ATTR_RO(virt_addr);
-static struct map_attribute map_num_pages_attr  = __ATTR_RO(num_pages);
-static struct map_attribute map_attribute_attr  = __ATTR_RO(attribute);
+static struct map_attribute map_type_attr = __ATTR_RO_MODE(type, 0400);
+static struct map_attribute map_phys_addr_attr = __ATTR_RO_MODE(phys_addr, 0400);
+static struct map_attribute map_virt_addr_attr = __ATTR_RO_MODE(virt_addr, 0400);
+static struct map_attribute map_num_pages_attr = __ATTR_RO_MODE(num_pages, 0400);
+static struct map_attribute map_attribute_attr = __ATTR_RO_MODE(attribute, 0400);
 
 /*
  * These are default attributes that are added for every memmap entry.
--- linux-4.4.0.orig/drivers/firmware/efi/runtime-wrappers.c
+++ linux-4.4.0/drivers/firmware/efi/runtime-wrappers.c
@@ -230,6 +230,27 @@
 	return status;
 }
 
+static efi_status_t
+virt_efi_query_variable_info_nonblocking(u32 attr,
+					 u64 *storage_space,
+					 u64 *remaining_space,
+					 u64 *max_variable_size)
+{
+	unsigned long flags;
+	efi_status_t status;
+
+	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+		return EFI_UNSUPPORTED;
+
+	if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
+		return EFI_NOT_READY;
+
+	status = efi_call_virt(query_variable_info, attr, storage_space,
+			       remaining_space, max_variable_size);
+	spin_unlock_irqrestore(&efi_runtime_lock, flags);
+	return status;
+}
+
 static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
 {
 	unsigned long flags;
@@ -300,6 +321,7 @@
 	efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
 	efi.reset_system = virt_efi_reset_system;
 	efi.query_variable_info = virt_efi_query_variable_info;
+	efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking;
 	efi.update_capsule = virt_efi_update_capsule;
 	efi.query_capsule_caps = virt_efi_query_capsule_caps;
 }
--- linux-4.4.0.orig/drivers/firmware/efi/test/Makefile
+++ linux-4.4.0/drivers/firmware/efi/test/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_EFI_TEST)			+= efi_test.o
--- linux-4.4.0.orig/drivers/firmware/efi/test/efi_test.c
+++ linux-4.4.0/drivers/firmware/efi/test/efi_test.c
@@ -0,0 +1,756 @@
+/*
+ * EFI Test Driver for Runtime Services
+ *
+ * Copyright(C) 2012-2016 Canonical Ltd.
+ *
+ * This driver exports EFI runtime services interfaces into userspace, which
+ * allow to use and test UEFI runtime services provided by firmware.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/efi.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "efi_test.h"
+
+MODULE_AUTHOR("Ivan Hu <ivan.hu@canonical.com>");
+MODULE_DESCRIPTION("EFI Test Driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Count the bytes in 'str', including the terminating NULL.
+ *
+ * Note this function returns the number of *bytes*, not the number of
+ * ucs2 characters.
+ */
+static inline size_t user_ucs2_strsize(efi_char16_t  __user *str)
+{
+	efi_char16_t *s = str, c;
+	size_t len;
+
+	if (!str)
+		return 0;
+
+	/* Include terminating NULL */
+	len = sizeof(efi_char16_t);
+
+	if (get_user(c, s++)) {
+		/* Can't read userspace memory for size */
+		return 0;
+	}
+
+	while (c != 0) {
+		if (get_user(c, s++)) {
+			/* Can't read userspace memory for size */
+			return 0;
+		}
+		len += sizeof(efi_char16_t);
+	}
+	return len;
+}
+
+/*
+ * Allocate a buffer and copy a ucs2 string from user space into it.
+ */
+static inline int
+copy_ucs2_from_user_len(efi_char16_t **dst, efi_char16_t __user *src,
+			size_t len)
+{
+	efi_char16_t *buf;
+
+	if (!src) {
+		*dst = NULL;
+		return 0;
+	}
+
+	if (!access_ok(VERIFY_READ, src, 1))
+		return -EFAULT;
+
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf) {
+		*dst = NULL;
+		return -ENOMEM;
+	}
+	*dst = buf;
+
+	if (copy_from_user(*dst, src, len)) {
+		kfree(buf);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*
+ * Count the bytes in 'str', including the terminating NULL.
+ *
+ * Just a wrap for user_ucs2_strsize
+ */
+static inline int
+get_ucs2_strsize_from_user(efi_char16_t __user *src, size_t *len)
+{
+	if (!access_ok(VERIFY_READ, src, 1))
+		return -EFAULT;
+
+	*len = user_ucs2_strsize(src);
+	if (*len == 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * Calculate the required buffer allocation size and copy a ucs2 string
+ * from user space into it.
+ *
+ * This function differs from copy_ucs2_from_user_len() because it
+ * calculates the size of the buffer to allocate by taking the length of
+ * the string 'src'.
+ *
+ * If a non-zero value is returned, the caller MUST NOT access 'dst'.
+ *
+ * It is the caller's responsibility to free 'dst'.
+ */
+static inline int
+copy_ucs2_from_user(efi_char16_t **dst, efi_char16_t __user *src)
+{
+	size_t len;
+
+	if (!access_ok(VERIFY_READ, src, 1))
+		return -EFAULT;
+
+	len = user_ucs2_strsize(src);
+	if (len == 0)
+		return -EFAULT;
+	return copy_ucs2_from_user_len(dst, src, len);
+}
+
+/*
+ * Copy a ucs2 string to a user buffer.
+ *
+ * This function is a simple wrapper around copy_to_user() that does
+ * nothing if 'src' is NULL, which is useful for reducing the amount of
+ * NULL checking the caller has to do.
+ *
+ * 'len' specifies the number of bytes to copy.
+ */
+static inline int
+copy_ucs2_to_user_len(efi_char16_t __user *dst, efi_char16_t *src, size_t len)
+{
+	if (!src)
+		return 0;
+
+	if (!access_ok(VERIFY_WRITE, dst, 1))
+		return -EFAULT;
+
+	return copy_to_user(dst, src, len);
+}
+
+static long efi_runtime_get_variable(unsigned long arg)
+{
+	struct efi_getvariable __user *getvariable_user;
+	struct efi_getvariable getvariable;
+	unsigned long datasize, prev_datasize, *dz;
+	efi_guid_t vendor_guid, *vd = NULL;
+	efi_status_t status;
+	efi_char16_t *name = NULL;
+	u32 attr, *at;
+	void *data = NULL;
+	int rv = 0;
+
+	getvariable_user = (struct efi_getvariable __user *)arg;
+
+	if (copy_from_user(&getvariable, getvariable_user,
+			   sizeof(getvariable)))
+		return -EFAULT;
+	if (getvariable.data_size &&
+	    get_user(datasize, getvariable.data_size))
+		return -EFAULT;
+	if (getvariable.vendor_guid) {
+		if (copy_from_user(&vendor_guid, getvariable.vendor_guid,
+					sizeof(vendor_guid)))
+			return -EFAULT;
+		vd = &vendor_guid;
+	}
+
+	if (getvariable.variable_name) {
+		rv = copy_ucs2_from_user(&name, getvariable.variable_name);
+		if (rv)
+			return rv;
+	}
+
+	at = getvariable.attributes ? &attr : NULL;
+	dz = getvariable.data_size ? &datasize : NULL;
+
+	if (getvariable.data_size && getvariable.data) {
+		data = kmalloc(datasize, GFP_KERNEL);
+		if (!data) {
+			kfree(name);
+			return -ENOMEM;
+		}
+	}
+
+	prev_datasize = datasize;
+	status = efi.get_variable(name, vd, at, dz, data);
+	kfree(name);
+
+	if (put_user(status, getvariable.status)) {
+		rv = -EFAULT;
+		goto out;
+	}
+
+	if (status != EFI_SUCCESS) {
+		if (status == EFI_BUFFER_TOO_SMALL) {
+			if (dz && put_user(datasize, getvariable.data_size)) {
+				rv = -EFAULT;
+				goto out;
+			}
+		}
+		rv = -EINVAL;
+		goto out;
+	}
+
+	if (prev_datasize < datasize) {
+		rv = -EINVAL;
+		goto out;
+	}
+
+	if (data) {
+		if (copy_to_user(getvariable.data, data, datasize)) {
+			rv = -EFAULT;
+			goto out;
+		}
+	}
+
+	if (at && put_user(attr, getvariable.attributes)) {
+		rv = -EFAULT;
+		goto out;
+	}
+
+	if (dz && put_user(datasize, getvariable.data_size))
+		rv = -EFAULT;
+
+out:
+	kfree(data);
+	return rv;
+
+}
+
+static long efi_runtime_set_variable(unsigned long arg)
+{
+	struct efi_setvariable __user *setvariable_user;
+	struct efi_setvariable setvariable;
+	efi_guid_t vendor_guid;
+	efi_status_t status;
+	efi_char16_t *name = NULL;
+	void *data;
+	int rv = 0;
+
+	setvariable_user = (struct efi_setvariable __user *)arg;
+
+	if (copy_from_user(&setvariable, setvariable_user, sizeof(setvariable)))
+		return -EFAULT;
+	if (copy_from_user(&vendor_guid, setvariable.vendor_guid,
+				sizeof(vendor_guid)))
+		return -EFAULT;
+
+	if (setvariable.variable_name) {
+		rv = copy_ucs2_from_user(&name, setvariable.variable_name);
+		if (rv)
+			return rv;
+	}
+
+	data = kmalloc(setvariable.data_size, GFP_KERNEL);
+	if (!data) {
+		kfree(name);
+		return -ENOMEM;
+	}
+	if (copy_from_user(data, setvariable.data, setvariable.data_size)) {
+		rv = -EFAULT;
+		goto out;
+	}
+
+	status = efi.set_variable(name, &vendor_guid,
+				setvariable.attributes,
+				setvariable.data_size, data);
+
+	if (put_user(status, setvariable.status)) {
+		rv = -EFAULT;
+		goto out;
+	}
+
+	rv = status == EFI_SUCCESS ? 0 : -EINVAL;
+
+out:
+	kfree(data);
+	kfree(name);
+
+	return rv;
+}
+
+static long efi_runtime_get_time(unsigned long arg)
+{
+	struct efi_gettime __user *gettime_user;
+	struct efi_gettime  gettime;
+	efi_status_t status;
+	efi_time_cap_t cap;
+	efi_time_t efi_time;
+
+	gettime_user = (struct efi_gettime __user *)arg;
+	if (copy_from_user(&gettime, gettime_user, sizeof(gettime)))
+		return -EFAULT;
+
+	status = efi.get_time(gettime.time ? &efi_time : NULL,
+			      gettime.capabilities ? &cap : NULL);
+
+	if (put_user(status, gettime.status))
+		return -EFAULT;
+
+	if (status != EFI_SUCCESS)
+		return -EINVAL;
+
+	if (gettime.capabilities) {
+		efi_time_cap_t __user *cap_local;
+
+		cap_local = (efi_time_cap_t *)gettime.capabilities;
+		if (put_user(cap.resolution, &(cap_local->resolution)) ||
+			put_user(cap.accuracy, &(cap_local->accuracy)) ||
+			put_user(cap.sets_to_zero, &(cap_local->sets_to_zero)))
+			return -EFAULT;
+	}
+	if (gettime.time) {
+		if (copy_to_user(gettime.time, &efi_time, sizeof(efi_time_t)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static long efi_runtime_set_time(unsigned long arg)
+{
+	struct efi_settime __user *settime_user;
+	struct efi_settime settime;
+	efi_status_t status;
+	efi_time_t efi_time;
+
+	settime_user = (struct efi_settime __user *)arg;
+	if (copy_from_user(&settime, settime_user, sizeof(settime)))
+		return -EFAULT;
+	if (copy_from_user(&efi_time, settime.time,
+					sizeof(efi_time_t)))
+		return -EFAULT;
+	status = efi.set_time(&efi_time);
+
+	if (put_user(status, settime.status))
+		return -EFAULT;
+
+	return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static long efi_runtime_get_waketime(unsigned long arg)
+{
+	struct efi_getwakeuptime __user *getwakeuptime_user;
+	struct efi_getwakeuptime getwakeuptime;
+	efi_bool_t enabled, pending;
+	efi_status_t status;
+	efi_time_t efi_time;
+
+	getwakeuptime_user = (struct efi_getwakeuptime __user *)arg;
+	if (copy_from_user(&getwakeuptime, getwakeuptime_user,
+				sizeof(getwakeuptime)))
+		return -EFAULT;
+
+	status = efi.get_wakeup_time(
+		getwakeuptime.enabled ? (efi_bool_t *)&enabled : NULL,
+		getwakeuptime.pending ? (efi_bool_t *)&pending : NULL,
+		getwakeuptime.time ? &efi_time : NULL);
+
+	if (put_user(status, getwakeuptime.status))
+		return -EFAULT;
+
+	if (status != EFI_SUCCESS)
+		return -EINVAL;
+
+	if (getwakeuptime.enabled && put_user(enabled,
+						getwakeuptime.enabled))
+		return -EFAULT;
+
+	if (getwakeuptime.time) {
+		if (copy_to_user(getwakeuptime.time, &efi_time,
+				sizeof(efi_time_t)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static long efi_runtime_set_waketime(unsigned long arg)
+{
+	struct efi_setwakeuptime __user *setwakeuptime_user;
+	struct efi_setwakeuptime setwakeuptime;
+	efi_bool_t enabled;
+	efi_status_t status;
+	efi_time_t efi_time;
+
+	setwakeuptime_user = (struct efi_setwakeuptime __user *)arg;
+
+	if (copy_from_user(&setwakeuptime, setwakeuptime_user,
+				sizeof(setwakeuptime)))
+		return -EFAULT;
+
+	enabled = setwakeuptime.enabled;
+	if (setwakeuptime.time) {
+		if (copy_from_user(&efi_time, setwakeuptime.time,
+					sizeof(efi_time_t)))
+			return -EFAULT;
+
+		status = efi.set_wakeup_time(enabled, &efi_time);
+	} else
+		status = efi.set_wakeup_time(enabled, NULL);
+
+	if (put_user(status, setwakeuptime.status))
+		return -EFAULT;
+
+	return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static long efi_runtime_get_nextvariablename(unsigned long arg)
+{
+	struct efi_getnextvariablename __user *getnextvariablename_user;
+	struct efi_getnextvariablename getnextvariablename;
+	unsigned long name_size, prev_name_size = 0, *ns = NULL;
+	efi_status_t status;
+	efi_guid_t *vd = NULL;
+	efi_guid_t vendor_guid;
+	efi_char16_t *name = NULL;
+	int rv;
+
+	getnextvariablename_user = (struct efi_getnextvariablename __user *)arg;
+
+	if (copy_from_user(&getnextvariablename, getnextvariablename_user,
+			   sizeof(getnextvariablename)))
+		return -EFAULT;
+
+	if (getnextvariablename.variable_name_size) {
+		if (get_user(name_size, getnextvariablename.variable_name_size))
+			return -EFAULT;
+		ns = &name_size;
+		prev_name_size = name_size;
+	}
+
+	if (getnextvariablename.vendor_guid) {
+		if (copy_from_user(&vendor_guid,
+				getnextvariablename.vendor_guid,
+				sizeof(vendor_guid)))
+			return -EFAULT;
+		vd = &vendor_guid;
+	}
+
+	if (getnextvariablename.variable_name) {
+		size_t name_string_size = 0;
+
+		rv = get_ucs2_strsize_from_user(
+				getnextvariablename.variable_name,
+				&name_string_size);
+		if (rv)
+			return rv;
+		/*
+		 * The name_size may be smaller than the real buffer size where
+		 * variable name located in some use cases. The most typical
+		 * case is passing a 0 to get the required buffer size for the
+		 * 1st time call. So we need to copy the content from user
+		 * space for at least the string size of variable name, or else
+		 * the name passed to UEFI may not be terminated as we expected.
+		 */
+		rv = copy_ucs2_from_user_len(&name,
+				getnextvariablename.variable_name,
+				prev_name_size > name_string_size ?
+				prev_name_size : name_string_size);
+		if (rv)
+			return rv;
+	}
+
+	status = efi.get_next_variable(ns, name, vd);
+
+	if (put_user(status, getnextvariablename.status)) {
+		rv = -EFAULT;
+		goto out;
+	}
+
+	if (status != EFI_SUCCESS) {
+		if (status == EFI_BUFFER_TOO_SMALL) {
+			if (ns && put_user(*ns,
+				getnextvariablename.variable_name_size)) {
+				rv = -EFAULT;
+				goto out;
+			}
+		}
+		rv = -EINVAL;
+		goto out;
+	}
+
+	if (name) {
+		if (copy_ucs2_to_user_len(getnextvariablename.variable_name,
+						name, prev_name_size)) {
+			rv = -EFAULT;
+			goto out;
+		}
+	}
+
+	if (ns) {
+		if (put_user(*ns, getnextvariablename.variable_name_size)) {
+			rv = -EFAULT;
+			goto out;
+		}
+	}
+
+	if (vd) {
+		if (copy_to_user(getnextvariablename.vendor_guid, vd,
+							sizeof(efi_guid_t)))
+			rv = -EFAULT;
+	}
+
+out:
+	kfree(name);
+	return rv;
+}
+
+static long efi_runtime_get_nexthighmonocount(unsigned long arg)
+{
+	struct efi_getnexthighmonotoniccount __user *getnexthighmonocount_user;
+	struct efi_getnexthighmonotoniccount getnexthighmonocount;
+	efi_status_t status;
+	u32 count;
+
+	getnexthighmonocount_user = (struct
+			efi_getnexthighmonotoniccount __user *)arg;
+
+	if (copy_from_user(&getnexthighmonocount,
+			   getnexthighmonocount_user,
+			   sizeof(getnexthighmonocount)))
+		return -EFAULT;
+
+	status = efi.get_next_high_mono_count(
+		getnexthighmonocount.high_count ? &count : NULL);
+
+	if (put_user(status, getnexthighmonocount.status))
+		return -EFAULT;
+
+	if (status != EFI_SUCCESS)
+		return -EINVAL;
+
+	if (getnexthighmonocount.high_count &&
+	    put_user(count, getnexthighmonocount.high_count))
+		return -EFAULT;
+
+	return 0;
+}
+
+static long efi_runtime_query_variableinfo(unsigned long arg)
+{
+	struct efi_queryvariableinfo __user *queryvariableinfo_user;
+	struct efi_queryvariableinfo queryvariableinfo;
+	efi_status_t status;
+	u64 max_storage, remaining, max_size;
+
+	queryvariableinfo_user = (struct efi_queryvariableinfo __user *)arg;
+
+	if (copy_from_user(&queryvariableinfo, queryvariableinfo_user,
+			   sizeof(queryvariableinfo)))
+		return -EFAULT;
+
+	status = efi.query_variable_info(queryvariableinfo.attributes,
+					 &max_storage, &remaining, &max_size);
+
+	if (put_user(status, queryvariableinfo.status))
+		return -EFAULT;
+
+	if (status != EFI_SUCCESS)
+		return -EINVAL;
+
+	if (put_user(max_storage,
+		     queryvariableinfo.maximum_variable_storage_size))
+		return -EFAULT;
+
+	if (put_user(remaining,
+		     queryvariableinfo.remaining_variable_storage_size))
+		return -EFAULT;
+
+	if (put_user(max_size, queryvariableinfo.maximum_variable_size))
+		return -EFAULT;
+
+	return 0;
+}
+
+static long efi_runtime_query_capsulecaps(unsigned long arg)
+{
+	struct efi_querycapsulecapabilities __user *qcaps_user;
+	struct efi_querycapsulecapabilities qcaps;
+	efi_capsule_header_t *capsules;
+	efi_status_t status;
+	u64 max_size;
+	int i, reset_type;
+	int rv = 0;
+
+	qcaps_user = (struct efi_querycapsulecapabilities __user *)arg;
+
+	if (copy_from_user(&qcaps, qcaps_user, sizeof(qcaps)))
+		return -EFAULT;
+
+	capsules = kcalloc(qcaps.capsule_count + 1,
+			   sizeof(efi_capsule_header_t), GFP_KERNEL);
+	if (!capsules)
+		return -ENOMEM;
+
+	for (i = 0; i < qcaps.capsule_count; i++) {
+		efi_capsule_header_t *c;
+		/*
+		 * We cannot dereference qcaps.capsule_header_array directly to
+		 * obtain the address of the capsule as it resides in the
+		 * user space
+		 */
+		if (get_user(c, qcaps.capsule_header_array + i)) {
+			rv = -EFAULT;
+			goto out;
+		}
+		if (copy_from_user(&capsules[i], c,
+				sizeof(efi_capsule_header_t))) {
+			rv = -EFAULT;
+			goto out;
+		}
+	}
+
+	qcaps.capsule_header_array = &capsules;
+
+	status = efi.query_capsule_caps((efi_capsule_header_t **)
+					qcaps.capsule_header_array,
+					qcaps.capsule_count,
+					&max_size, &reset_type);
+
+	if (put_user(status, qcaps.status)) {
+		rv = -EFAULT;
+		goto out;
+	}
+
+	if (status != EFI_SUCCESS) {
+		rv = -EINVAL;
+		goto out;
+	}
+
+	if (put_user(max_size, qcaps.maximum_capsule_size)) {
+		rv = -EFAULT;
+		goto out;
+	}
+
+	if (put_user(reset_type, qcaps.reset_type))
+		rv = -EFAULT;
+
+out:
+	kfree(capsules);
+	return rv;
+}
+
+static long efi_test_ioctl(struct file *file, unsigned int cmd,
+							unsigned long arg)
+{
+	switch (cmd) {
+	case EFI_RUNTIME_GET_VARIABLE:
+		return efi_runtime_get_variable(arg);
+
+	case EFI_RUNTIME_SET_VARIABLE:
+		return efi_runtime_set_variable(arg);
+
+	case EFI_RUNTIME_GET_TIME:
+		return efi_runtime_get_time(arg);
+
+	case EFI_RUNTIME_SET_TIME:
+		return efi_runtime_set_time(arg);
+
+	case EFI_RUNTIME_GET_WAKETIME:
+		return efi_runtime_get_waketime(arg);
+
+	case EFI_RUNTIME_SET_WAKETIME:
+		return efi_runtime_set_waketime(arg);
+
+	case EFI_RUNTIME_GET_NEXTVARIABLENAME:
+		return efi_runtime_get_nextvariablename(arg);
+
+	case EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT:
+		return efi_runtime_get_nexthighmonocount(arg);
+
+	case EFI_RUNTIME_QUERY_VARIABLEINFO:
+		return efi_runtime_query_variableinfo(arg);
+
+	case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES:
+		return efi_runtime_query_capsulecaps(arg);
+	}
+
+	return -ENOTTY;
+}
+
+static int efi_test_open(struct inode *inode, struct file *file)
+{
+	bool locked_down = secure_modules();
+
+	if (locked_down)
+		return -EPERM;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	/*
+	 * nothing special to do here
+	 * We do accept multiple open files at the same time as we
+	 * synchronize on the per call operation.
+	 */
+	return 0;
+}
+
+static int efi_test_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+static const struct file_operations efi_test_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= efi_test_ioctl,
+	.open		= efi_test_open,
+	.release	= efi_test_close,
+	.llseek		= no_llseek,
+};
+
+static struct miscdevice efi_test_dev = {
+	MISC_DYNAMIC_MINOR,
+	"efi_test",
+	&efi_test_fops
+};
+
+static int __init efi_test_init(void)
+{
+	int ret;
+
+	ret = misc_register(&efi_test_dev);
+	if (ret) {
+		pr_err("efi_test: can't misc_register on minor=%d\n",
+			MISC_DYNAMIC_MINOR);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit efi_test_exit(void)
+{
+	misc_deregister(&efi_test_dev);
+}
+
+module_init(efi_test_init);
+module_exit(efi_test_exit);
--- linux-4.4.0.orig/drivers/firmware/efi/test/efi_test.h
+++ linux-4.4.0/drivers/firmware/efi/test/efi_test.h
@@ -0,0 +1,110 @@
+/*
+ * EFI Test driver Header
+ *
+ * Copyright(C) 2012-2016 Canonical Ltd.
+ *
+ */
+
+#ifndef _DRIVERS_FIRMWARE_EFI_TEST_H_
+#define _DRIVERS_FIRMWARE_EFI_TEST_H_
+
+#include <linux/efi.h>
+
+struct efi_getvariable {
+	efi_char16_t	*variable_name;
+	efi_guid_t	*vendor_guid;
+	u32		*attributes;
+	unsigned long	*data_size;
+	void		*data;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_setvariable {
+	efi_char16_t	*variable_name;
+	efi_guid_t	*vendor_guid;
+	u32		attributes;
+	unsigned long	data_size;
+	void		*data;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_getnextvariablename {
+	unsigned long	*variable_name_size;
+	efi_char16_t	*variable_name;
+	efi_guid_t	*vendor_guid;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_queryvariableinfo {
+	u32		attributes;
+	u64		*maximum_variable_storage_size;
+	u64		*remaining_variable_storage_size;
+	u64		*maximum_variable_size;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_gettime {
+	efi_time_t	*time;
+	efi_time_cap_t	*capabilities;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_settime {
+	efi_time_t	*time;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_getwakeuptime {
+	efi_bool_t	*enabled;
+	efi_bool_t	*pending;
+	efi_time_t	*time;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_setwakeuptime {
+	efi_bool_t	enabled;
+	efi_time_t	*time;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_getnexthighmonotoniccount {
+	u32		*high_count;
+	efi_status_t	*status;
+} __packed;
+
+struct efi_querycapsulecapabilities {
+	efi_capsule_header_t	**capsule_header_array;
+	unsigned long		capsule_count;
+	u64			*maximum_capsule_size;
+	int			*reset_type;
+	efi_status_t		*status;
+} __packed;
+
+#define EFI_RUNTIME_GET_VARIABLE \
+	_IOWR('p', 0x01, struct efi_getvariable)
+#define EFI_RUNTIME_SET_VARIABLE \
+	_IOW('p', 0x02, struct efi_setvariable)
+
+#define EFI_RUNTIME_GET_TIME \
+	_IOR('p', 0x03, struct efi_gettime)
+#define EFI_RUNTIME_SET_TIME \
+	_IOW('p', 0x04, struct efi_settime)
+
+#define EFI_RUNTIME_GET_WAKETIME \
+	_IOR('p', 0x05, struct efi_getwakeuptime)
+#define EFI_RUNTIME_SET_WAKETIME \
+	_IOW('p', 0x06, struct efi_setwakeuptime)
+
+#define EFI_RUNTIME_GET_NEXTVARIABLENAME \
+	_IOWR('p', 0x07, struct efi_getnextvariablename)
+
+#define EFI_RUNTIME_QUERY_VARIABLEINFO \
+	_IOR('p', 0x08, struct efi_queryvariableinfo)
+
+#define EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT \
+	_IOR('p', 0x09, struct efi_getnexthighmonotoniccount)
+
+#define EFI_RUNTIME_QUERY_CAPSULECAPABILITIES \
+	_IOR('p', 0x0A, struct efi_querycapsulecapabilities)
+
+#endif /* _DRIVERS_FIRMWARE_EFI_TEST_H_ */
--- linux-4.4.0.orig/drivers/firmware/efi/vars.c
+++ linux-4.4.0/drivers/firmware/efi/vars.c
@@ -165,67 +165,148 @@
 }
 
 struct variable_validate {
+	efi_guid_t vendor;
 	char *name;
 	bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
 			 unsigned long len);
 };
 
+/*
+ * This is the list of variables we need to validate, as well as the
+ * whitelist for what we think is safe not to default to immutable.
+ *
+ * If it has a validate() method that's not NULL, it'll go into the
+ * validation routine.  If not, it is assumed valid, but still used for
+ * whitelisting.
+ *
+ * Note that it's sorted by {vendor,name}, but globbed names must come after
+ * any other name with the same prefix.
+ */
 static const struct variable_validate variable_validate[] = {
-	{ "BootNext", validate_uint16 },
-	{ "BootOrder", validate_boot_order },
-	{ "DriverOrder", validate_boot_order },
-	{ "Boot*", validate_load_option },
-	{ "Driver*", validate_load_option },
-	{ "ConIn", validate_device_path },
-	{ "ConInDev", validate_device_path },
-	{ "ConOut", validate_device_path },
-	{ "ConOutDev", validate_device_path },
-	{ "ErrOut", validate_device_path },
-	{ "ErrOutDev", validate_device_path },
-	{ "Timeout", validate_uint16 },
-	{ "Lang", validate_ascii_string },
-	{ "PlatformLang", validate_ascii_string },
-	{ "", NULL },
+	{ EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 },
+	{ EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order },
+	{ EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option },
+	{ EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order },
+	{ EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option },
+	{ EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path },
+	{ EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path },
+	{ EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path },
+	{ EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path },
+	{ EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path },
+	{ EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path },
+	{ EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string },
+	{ EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL },
+	{ EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string },
+	{ EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 },
+	{ LINUX_EFI_CRASH_GUID, "*", NULL },
+	{ NULL_GUID, "", NULL },
 };
 
+/*
+ * Check if @var_name matches the pattern given in @match_name.
+ *
+ * @var_name: an array of @len non-NUL characters.
+ * @match_name: a NUL-terminated pattern string, optionally ending in "*". A
+ *              final "*" character matches any trailing characters @var_name,
+ *              including the case when there are none left in @var_name.
+ * @match: on output, the number of non-wildcard characters in @match_name
+ *         that @var_name matches, regardless of the return value.
+ * @return: whether @var_name fully matches @match_name.
+ */
+static bool
+variable_matches(const char *var_name, size_t len, const char *match_name,
+		 int *match)
+{
+	for (*match = 0; ; (*match)++) {
+		char c = match_name[*match];
+
+		switch (c) {
+		case '*':
+			/* Wildcard in @match_name means we've matched. */
+			return true;
+
+		case '\0':
+			/* @match_name has ended. Has @var_name too? */
+			return (*match == len);
+
+		default:
+			/*
+			 * We've reached a non-wildcard char in @match_name.
+			 * Continue only if there's an identical character in
+			 * @var_name.
+			 */
+			if (*match < len && c == var_name[*match])
+				continue;
+			return false;
+		}
+	}
+}
+
 bool
-efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len)
+efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
+		unsigned long data_size)
 {
 	int i;
-	u16 *unicode_name = var_name;
+	unsigned long utf8_size;
+	u8 *utf8_name;
+
+	utf8_size = ucs2_utf8size(var_name);
+	utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL);
+	if (!utf8_name)
+		return false;
 
-	for (i = 0; variable_validate[i].validate != NULL; i++) {
+	ucs2_as_utf8(utf8_name, var_name, utf8_size);
+	utf8_name[utf8_size] = '\0';
+
+	for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
 		const char *name = variable_validate[i].name;
-		int match;
+		int match = 0;
 
-		for (match = 0; ; match++) {
-			char c = name[match];
-			u16 u = unicode_name[match];
-
-			/* All special variables are plain ascii */
-			if (u > 127)
-				return true;
-
-			/* Wildcard in the matching name means we've matched */
-			if (c == '*')
-				return variable_validate[i].validate(var_name,
-							     match, data, len);
+		if (efi_guidcmp(vendor, variable_validate[i].vendor))
+			continue;
 
-			/* Case sensitive match */
-			if (c != u)
+		if (variable_matches(utf8_name, utf8_size+1, name, &match)) {
+			if (variable_validate[i].validate == NULL)
 				break;
-
-			/* Reached the end of the string while matching */
-			if (!c)
-				return variable_validate[i].validate(var_name,
-							     match, data, len);
+			kfree(utf8_name);
+			return variable_validate[i].validate(var_name, match,
+							     data, data_size);
 		}
 	}
-
+	kfree(utf8_name);
 	return true;
 }
 EXPORT_SYMBOL_GPL(efivar_validate);
 
+bool
+efivar_variable_is_removable(efi_guid_t vendor, const char *var_name,
+			     size_t len)
+{
+	int i;
+	bool found = false;
+	int match = 0;
+
+	/*
+	 * Check if our variable is in the validated variables list
+	 */
+	for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
+		if (efi_guidcmp(variable_validate[i].vendor, vendor))
+			continue;
+
+		if (variable_matches(var_name, len,
+				     variable_validate[i].name, &match)) {
+			found = true;
+			break;
+		}
+	}
+
+	/*
+	 * If it's in our list, it is removable.
+	 */
+	return found;
+}
+EXPORT_SYMBOL_GPL(efivar_variable_is_removable);
+
 static efi_status_t
 check_var_size(u32 attributes, unsigned long size)
 {
@@ -234,7 +315,18 @@
 	if (!fops->query_variable_store)
 		return EFI_UNSUPPORTED;
 
-	return fops->query_variable_store(attributes, size);
+	return fops->query_variable_store(attributes, size, false);
+}
+
+static efi_status_t
+check_var_size_nonblocking(u32 attributes, unsigned long size)
+{
+	const struct efivar_operations *fops = __efivars->ops;
+
+	if (!fops->query_variable_store)
+		return EFI_UNSUPPORTED;
+
+	return fops->query_variable_store(attributes, size, true);
 }
 
 static int efi_status_to_err(efi_status_t status)
@@ -615,7 +707,8 @@
 	if (!spin_trylock_irqsave(&__efivars->lock, flags))
 		return -EBUSY;
 
-	status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
+	status = check_var_size_nonblocking(attributes,
+					    size + ucs2_strsize(name, 1024));
 	if (status != EFI_SUCCESS) {
 		spin_unlock_irqrestore(&__efivars->lock, flags);
 		return -ENOSPC;
@@ -852,7 +945,7 @@
 
 	*set = false;
 
-	if (efivar_validate(name, data, *size) == false)
+	if (efivar_validate(*vendor, name, data, *size) == false)
 		return -EINVAL;
 
 	/*
--- linux-4.4.0.orig/drivers/firmware/google/gsmi.c
+++ linux-4.4.0/drivers/firmware/google/gsmi.c
@@ -480,11 +480,10 @@
 	if (count < sizeof(u32))
 		return -EINVAL;
 	param.type = *(u32 *)buf;
-	count -= sizeof(u32);
 	buf += sizeof(u32);
 
 	/* The remaining buffer is the data payload */
-	if (count > gsmi_dev.data_buf->length)
+	if ((count - sizeof(u32)) > gsmi_dev.data_buf->length)
 		return -EINVAL;
 	param.data_len = count - sizeof(u32);
 
@@ -504,7 +503,7 @@
 
 	spin_unlock_irqrestore(&gsmi_dev.lock, flags);
 
-	return rc;
+	return (rc == 0) ? count : rc;
 
 }
 
--- linux-4.4.0.orig/drivers/firmware/iscsi_ibft.c
+++ linux-4.4.0/drivers/firmware/iscsi_ibft.c
@@ -93,6 +93,10 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IBFT_ISCSI_VERSION);
 
+#ifndef CONFIG_ISCSI_IBFT_FIND
+struct acpi_table_ibft *ibft_addr;
+#endif
+
 struct ibft_hdr {
 	u8 id;
 	u8 version;
@@ -513,6 +517,7 @@
 	case ISCSI_BOOT_TGT_NIC_ASSOC:
 	case ISCSI_BOOT_TGT_CHAP_TYPE:
 		rc = S_IRUGO;
+		break;
 	case ISCSI_BOOT_TGT_NAME:
 		if (tgt->tgt_name_len)
 			rc = S_IRUGO;
--- linux-4.4.0.orig/drivers/firmware/psci.c
+++ linux-4.4.0/drivers/firmware/psci.c
@@ -13,6 +13,7 @@
 
 #define pr_fmt(fmt) "psci: " fmt
 
+#include <linux/arm-smccc.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/of.h>
@@ -54,12 +55,13 @@
 	return cpu == resident_cpu;
 }
 
-struct psci_operations psci_ops;
+struct psci_operations psci_ops = {
+	.conduit = PSCI_CONDUIT_NONE,
+	.smccc_version = SMCCC_VERSION_1_0,
+};
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
 				unsigned long, unsigned long);
-asmlinkage psci_fn __invoke_psci_fn_hvc;
-asmlinkage psci_fn __invoke_psci_fn_smc;
 static psci_fn *invoke_psci_fn;
 
 enum psci_function {
@@ -107,6 +109,26 @@
 	return !(state & ~valid_mask);
 }
 
+static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
+			unsigned long arg0, unsigned long arg1,
+			unsigned long arg2)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
+static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
+			unsigned long arg0, unsigned long arg1,
+			unsigned long arg2)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
 static int psci_to_linux_errno(int errno)
 {
 	switch (errno) {
@@ -187,6 +209,22 @@
 			      0, 0, 0);
 }
 
+static void set_conduit(enum psci_conduit conduit)
+{
+	switch (conduit) {
+	case PSCI_CONDUIT_HVC:
+		invoke_psci_fn = __invoke_psci_fn_hvc;
+		break;
+	case PSCI_CONDUIT_SMC:
+		invoke_psci_fn = __invoke_psci_fn_smc;
+		break;
+	default:
+		WARN(1, "Unexpected PSCI conduit %d\n", conduit);
+	}
+
+	psci_ops.conduit = conduit;
+}
+
 static int get_set_conduit_method(struct device_node *np)
 {
 	const char *method;
@@ -199,9 +237,9 @@
 	}
 
 	if (!strcmp("hvc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	} else if (!strcmp("smc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 	} else {
 		pr_warn("invalid \"method\" property: %s\n", method);
 		return -EINVAL;
@@ -302,6 +340,31 @@
 	pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
 }
 
+static void __init psci_init_smccc(void)
+{
+	u32 ver = ARM_SMCCC_VERSION_1_0;
+	int feature;
+
+	feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
+
+	if (feature != PSCI_RET_NOT_SUPPORTED) {
+		u32 ret;
+		ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
+		if (ret == ARM_SMCCC_VERSION_1_1) {
+			psci_ops.smccc_version = SMCCC_VERSION_1_1;
+			ver = ret;
+		}
+	}
+
+	/*
+	 * Conveniently, the SMCCC and PSCI versions are encoded the
+	 * same way. No, this isn't accidental.
+	 */
+	pr_info("SMC Calling Convention v%d.%d\n",
+		PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver));
+
+}
+
 static void __init psci_0_2_set_functions(void)
 {
 	pr_info("Using standard PSCI v0.2 function IDs\n");
@@ -348,6 +411,7 @@
 	psci_init_migrate();
 
 	if (PSCI_VERSION_MAJOR(ver) >= 1) {
+		psci_init_smccc();
 		psci_init_cpu_suspend();
 		psci_init_system_suspend();
 	}
@@ -424,7 +488,7 @@
 	return err;
 }
 
-static const struct of_device_id const psci_of_match[] __initconst = {
+static const struct of_device_id psci_of_match[] __initconst = {
 	{ .compatible = "arm,psci",	.data = psci_0_1_init},
 	{ .compatible = "arm,psci-0.2",	.data = psci_0_2_init},
 	{ .compatible = "arm,psci-1.0",	.data = psci_0_2_init},
@@ -461,9 +525,9 @@
 	pr_info("probing for conduit method from ACPI.\n");
 
 	if (acpi_psci_use_hvc())
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	else
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 
 	return psci_probe();
 }
--- linux-4.4.0.orig/drivers/gpio/Kconfig
+++ linux-4.4.0/drivers/gpio/Kconfig
@@ -50,6 +50,7 @@
 config OF_GPIO
 	def_bool y
 	depends on OF
+	depends on HAS_IOMEM
 
 config GPIO_ACPI
 	def_bool y
@@ -578,6 +579,7 @@
 config GPIO_ADP5588_IRQ
 	bool "Interrupt controller support for ADP5588"
 	depends on GPIO_ADP5588=y
+	select GPIOLIB_IRQCHIP
 	help
 	  Say yes here to enable the adp5588 to be used as an interrupt
 	  controller. It requires the driver to be built in the kernel.
--- linux-4.4.0.orig/drivers/gpio/gpio-104-idio-16.c
+++ linux-4.4.0/drivers/gpio/gpio-104-idio-16.c
@@ -23,7 +23,7 @@
 #include <linux/spinlock.h>
 
 static unsigned idio_16_base;
-module_param(idio_16_base, uint, 0);
+module_param_hw(idio_16_base, uint, ioport, 0);
 MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address");
 
 /**
--- linux-4.4.0.orig/drivers/gpio/gpio-adnp.c
+++ linux-4.4.0/drivers/gpio/gpio-adnp.c
@@ -137,8 +137,10 @@
 	if (err < 0)
 		goto out;
 
-	if (err & BIT(pos))
-		err = -EACCES;
+	if (value & BIT(pos)) {
+		err = -EPERM;
+		goto out;
+	}
 
 	err = 0;
 
--- linux-4.4.0.orig/drivers/gpio/gpio-adp5588.c
+++ linux-4.4.0/drivers/gpio/gpio-adp5588.c
@@ -41,6 +41,8 @@
 	uint8_t int_en[3];
 	uint8_t irq_mask[3];
 	uint8_t irq_stat[3];
+	uint8_t int_input_en[3];
+	uint8_t int_lvl_cached[3];
 };
 
 static int adp5588_gpio_read(struct i2c_client *client, u8 reg)
@@ -177,12 +179,28 @@
 	struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d);
 	int i;
 
-	for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++)
+	for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
+		if (dev->int_input_en[i]) {
+			mutex_lock(&dev->lock);
+			dev->dir[i] &= ~dev->int_input_en[i];
+			dev->int_input_en[i] = 0;
+			adp5588_gpio_write(dev->client, GPIO_DIR1 + i,
+					   dev->dir[i]);
+			mutex_unlock(&dev->lock);
+		}
+
+		if (dev->int_lvl_cached[i] != dev->int_lvl[i]) {
+			dev->int_lvl_cached[i] = dev->int_lvl[i];
+			adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + i,
+					   dev->int_lvl[i]);
+		}
+
 		if (dev->int_en[i] ^ dev->irq_mask[i]) {
 			dev->int_en[i] = dev->irq_mask[i];
 			adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i,
 					   dev->int_en[i]);
 		}
+	}
 
 	mutex_unlock(&dev->irq_lock);
 }
@@ -225,9 +243,7 @@
 	else
 		return -EINVAL;
 
-	adp5588_gpio_direction_input(&dev->gpio_chip, gpio);
-	adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank,
-			   dev->int_lvl[bank]);
+	dev->int_input_en[bank] |= bit;
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpio/gpio-altera.c
+++ linux-4.4.0/drivers/gpio/gpio-altera.c
@@ -94,21 +94,18 @@
 
 	altera_gc = to_altera(irq_data_get_irq_chip_data(d));
 
-	if (type == IRQ_TYPE_NONE)
+	if (type == IRQ_TYPE_NONE) {
+		irq_set_handler_locked(d, handle_bad_irq);
 		return 0;
-	if (type == IRQ_TYPE_LEVEL_HIGH &&
-		altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
-		return 0;
-	if (type == IRQ_TYPE_EDGE_RISING &&
-		altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_RISING)
-		return 0;
-	if (type == IRQ_TYPE_EDGE_FALLING &&
-		altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_FALLING)
-		return 0;
-	if (type == IRQ_TYPE_EDGE_BOTH &&
-		altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_BOTH)
+	}
+	if (type == altera_gc->interrupt_trigger) {
+		if (type == IRQ_TYPE_LEVEL_HIGH)
+			irq_set_handler_locked(d, handle_level_irq);
+		else
+			irq_set_handler_locked(d, handle_simple_irq);
 		return 0;
-
+	}
+	irq_set_handler_locked(d, handle_bad_irq);
 	return -EINVAL;
 }
 
@@ -234,7 +231,6 @@
 	chained_irq_exit(chip, desc);
 }
 
-
 static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
 {
 	struct altera_gpio_chip *altera_gc;
@@ -314,7 +310,7 @@
 	altera_gc->interrupt_trigger = reg;
 
 	ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0,
-		handle_simple_irq, IRQ_TYPE_NONE);
+		handle_bad_irq, IRQ_TYPE_NONE);
 
 	if (ret) {
 		dev_info(&pdev->dev, "could not add irqchip\n");
--- linux-4.4.0.orig/drivers/gpio/gpio-ath79.c
+++ linux-4.4.0/drivers/gpio/gpio-ath79.c
@@ -203,3 +203,6 @@
 };
 
 module_platform_driver(ath79_gpio_driver);
+
+MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X GPIO API support");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/gpio/gpio-bcm-kona.c
+++ linux-4.4.0/drivers/gpio/gpio-bcm-kona.c
@@ -551,11 +551,11 @@
 	/* disable interrupts and clear status */
 	for (i = 0; i < kona_gpio->num_bank; i++) {
 		/* Unlock the entire bank first */
-		bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE);
+		bcm_kona_gpio_write_lock_regs(reg_base, i, UNLOCK_CODE);
 		writel(0xffffffff, reg_base + GPIO_INT_MASK(i));
 		writel(0xffffffff, reg_base + GPIO_INT_STATUS(i));
 		/* Now re-lock the bank */
-		bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE);
+		bcm_kona_gpio_write_lock_regs(reg_base, i, LOCK_CODE);
 	}
 }
 
--- linux-4.4.0.orig/drivers/gpio/gpio-intel-mid.c
+++ linux-4.4.0/drivers/gpio/gpio-intel-mid.c
@@ -17,7 +17,6 @@
  * Moorestown platform Langwell chip.
  * Medfield platform Penwell chip.
  * Clovertrail platform Cloverview chip.
- * Merrifield platform Tangier chip.
  */
 
 #include <linux/module.h>
@@ -64,10 +63,6 @@
 /* intel_mid gpio driver data */
 struct intel_mid_gpio_ddata {
 	u16 ngpio;		/* number of gpio pins */
-	u32 gplr_offset;	/* offset of first GPLR register from base */
-	u32 flis_base;		/* base address of FLIS registers */
-	u32 flis_len;		/* length of FLIS registers */
-	u32 (*get_flis_offset)(int gpio);
 	u32 chip_irq_type;	/* chip interrupt type */
 };
 
@@ -257,15 +252,6 @@
 	.chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
 };
 
-static const struct intel_mid_gpio_ddata gpio_tangier = {
-	.ngpio = 192,
-	.gplr_offset = 4,
-	.flis_base = 0xff0c0000,
-	.flis_len = 0x8000,
-	.get_flis_offset = NULL,
-	.chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
-};
-
 static const struct pci_device_id intel_gpio_ids[] = {
 	{
 		/* Lincroft */
@@ -292,11 +278,6 @@
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7),
 		.driver_data = (kernel_ulong_t)&gpio_cloverview_core,
 	},
-	{
-		/* Tangier */
-		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199),
-		.driver_data = (kernel_ulong_t)&gpio_tangier,
-	},
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
@@ -345,7 +326,7 @@
 	}
 }
 
-static int intel_gpio_runtime_idle(struct device *dev)
+static int __maybe_unused intel_gpio_runtime_idle(struct device *dev)
 {
 	int err = pm_schedule_suspend(dev, 500);
 	return err ?: -EBUSY;
--- linux-4.4.0.orig/drivers/gpio/gpio-iop.c
+++ linux-4.4.0/drivers/gpio/gpio-iop.c
@@ -129,3 +129,7 @@
 	return platform_driver_register(&iop3xx_gpio_driver);
 }
 arch_initcall(iop3xx_gpio_init);
+
+MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors");
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/gpio/gpio-max7301.c
+++ linux-4.4.0/drivers/gpio/gpio-max7301.c
@@ -25,7 +25,7 @@
 	struct spi_device *spi = to_spi_device(dev);
 	u16 word = ((reg & 0x7F) << 8) | (val & 0xFF);
 
-	return spi_write(spi, (const u8 *)&word, sizeof(word));
+	return spi_write_then_read(spi, &word, sizeof(word), NULL, 0);
 }
 
 /* A read from the MAX7301 means two transfers; here, one message each */
@@ -37,14 +37,8 @@
 	struct spi_device *spi = to_spi_device(dev);
 
 	word = 0x8000 | (reg << 8);
-	ret = spi_write(spi, (const u8 *)&word, sizeof(word));
-	if (ret)
-		return ret;
-	/*
-	 * This relies on the fact, that a transfer with NULL tx_buf shifts out
-	 * zero bytes (=NOOP for MAX7301)
-	 */
-	ret = spi_read(spi, (u8 *)&word, sizeof(word));
+	ret = spi_write_then_read(spi, &word, sizeof(word), &word,
+				  sizeof(word));
 	if (ret)
 		return ret;
 	return word & 0xff;
--- linux-4.4.0.orig/drivers/gpio/gpio-ml-ioh.c
+++ linux-4.4.0/drivers/gpio/gpio-ml-ioh.c
@@ -495,9 +495,10 @@
 
 	chip = chip_save;
 err_gpiochip_add:
+	chip = chip_save;
 	while (--i >= 0) {
-		chip--;
 		gpiochip_remove(&chip->gpio);
+		chip++;
 	}
 	kfree(chip_save);
 
--- linux-4.4.0.orig/drivers/gpio/gpio-mpc8xxx.c
+++ linux-4.4.0/drivers/gpio/gpio-mpc8xxx.c
@@ -329,7 +329,7 @@
 				irq_hw_number_t hwirq)
 {
 	irq_set_chip_data(irq, h->host_data);
-	irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq);
+	irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_edge_irq);
 
 	return 0;
 }
@@ -409,7 +409,8 @@
 	 * It's assumed that only a single type of gpio controller is available
 	 * on the current machine, so overwriting global data is fine.
 	 */
-	mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
+	if (devtype->irq_set_type)
+		mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
 
 	gc->direction_output = devtype->gpio_dir_out ?: mpc8xxx_gpio_dir_out;
 	gc->get = devtype->gpio_get ?: mpc8xxx_gpio_get;
--- linux-4.4.0.orig/drivers/gpio/gpio-msic.c
+++ linux-4.4.0/drivers/gpio/gpio-msic.c
@@ -266,8 +266,8 @@
 	int i;
 
 	if (irq < 0) {
-		dev_err(dev, "no IRQ line\n");
-		return -EINVAL;
+		dev_err(dev, "no IRQ line: %d\n", irq);
+		return irq;
 	}
 
 	if (!pdata || !pdata->gpio_base) {
--- linux-4.4.0.orig/drivers/gpio/gpio-omap.c
+++ linux-4.4.0/drivers/gpio/gpio-omap.c
@@ -292,6 +292,22 @@
 	}
 }
 
+/*
+ * Off mode wake-up capable GPIOs in bank(s) that are in the wakeup domain.
+ * See TRM section for GPIO for "Wake-Up Generation" for the list of GPIOs
+ * in wakeup domain. If bank->non_wakeup_gpios is not configured, assume none
+ * are capable waking up the system from off mode.
+ */
+static bool omap_gpio_is_off_wakeup_capable(struct gpio_bank *bank, u32 gpio_mask)
+{
+	u32 no_wake = bank->non_wakeup_gpios;
+
+	if (no_wake)
+		return !!(~no_wake & gpio_mask);
+
+	return false;
+}
+
 static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
 						unsigned trigger)
 {
@@ -323,13 +339,7 @@
 	}
 
 	/* This part needs to be executed always for OMAP{34xx, 44xx} */
-	if (!bank->regs->irqctrl) {
-		/* On omap24xx proceed only when valid GPIO bit is set */
-		if (bank->non_wakeup_gpios) {
-			if (!(bank->non_wakeup_gpios & gpio_bit))
-				goto exit;
-		}
-
+	if (!bank->regs->irqctrl && !omap_gpio_is_off_wakeup_capable(bank, gpio)) {
 		/*
 		 * Log the edge gpio and manually trigger the IRQ
 		 * after resume if the input level changes
@@ -342,7 +352,6 @@
 			bank->enabled_non_wakeup_gpios &= ~gpio_bit;
 	}
 
-exit:
 	bank->level_mask =
 		readl_relaxed(bank->base + bank->regs->leveldetect0) |
 		readl_relaxed(bank->base + bank->regs->leveldetect1);
@@ -812,9 +821,9 @@
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
 	bank->irq_usage &= ~(BIT(offset));
-	omap_set_gpio_irqenable(bank, offset, 0);
-	omap_clear_gpio_irqstatus(bank, offset);
 	omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+	omap_clear_gpio_irqstatus(bank, offset);
+	omap_set_gpio_irqenable(bank, offset, 0);
 	if (!LINE_USED(bank->mod_usage, offset))
 		omap_clear_gpio_debounce(bank, offset);
 	omap_disable_gpio_module(bank, offset);
@@ -856,8 +865,8 @@
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
-	omap_set_gpio_irqenable(bank, offset, 0);
 	omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+	omap_set_gpio_irqenable(bank, offset, 0);
 	raw_spin_unlock_irqrestore(&bank->lock, flags);
 }
 
@@ -869,17 +878,20 @@
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
-	if (trigger)
-		omap_set_gpio_triggering(bank, offset, trigger);
+	omap_set_gpio_irqenable(bank, offset, 1);
 
-	/* For level-triggered GPIOs, the clearing must be done after
-	 * the HW source is cleared, thus after the handler has run */
-	if (bank->level_mask & BIT(offset)) {
-		omap_set_gpio_irqenable(bank, offset, 0);
+	/*
+	 * For level-triggered GPIOs, clearing must be done after the source
+	 * is cleared, thus after the handler has run. OMAP4 needs this done
+	 * after enabing the interrupt to clear the wakeup status.
+	 */
+	if (bank->regs->leveldetect0 && bank->regs->wkup_en &&
+	    trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
 		omap_clear_gpio_irqstatus(bank, offset);
-	}
 
-	omap_set_gpio_irqenable(bank, offset, 1);
+	if (trigger)
+		omap_set_gpio_triggering(bank, offset, trigger);
+
 	raw_spin_unlock_irqrestore(&bank->lock, flags);
 }
 
@@ -1600,6 +1612,8 @@
 	.clr_dataout =		OMAP4_GPIO_CLEARDATAOUT,
 	.irqstatus =		OMAP4_GPIO_IRQSTATUS0,
 	.irqstatus2 =		OMAP4_GPIO_IRQSTATUS1,
+	.irqstatus_raw0 =	OMAP4_GPIO_IRQSTATUSRAW0,
+	.irqstatus_raw1 =	OMAP4_GPIO_IRQSTATUSRAW1,
 	.irqenable =		OMAP4_GPIO_IRQSTATUSSET0,
 	.irqenable2 =		OMAP4_GPIO_IRQSTATUSSET1,
 	.set_irqenable =	OMAP4_GPIO_IRQSTATUSSET0,
--- linux-4.4.0.orig/drivers/gpio/gpio-pca953x.c
+++ linux-4.4.0/drivers/gpio/gpio-pca953x.c
@@ -86,7 +86,7 @@
 #define MAX_BANK 5
 #define BANK_SZ 8
 
-#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
+#define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
 
 struct pca953x_chip {
 	unsigned gpio_start;
--- linux-4.4.0.orig/drivers/gpio/gpio-pcf857x.c
+++ linux-4.4.0/drivers/gpio/gpio-pcf857x.c
@@ -370,7 +370,7 @@
 	 * reset state.  Otherwise it flags pins to be driven low.
 	 */
 	gpio->out = ~n_latch;
-	gpio->status = gpio->out;
+	gpio->status = gpio->read(gpio->client);
 
 	status = gpiochip_add(&gpio->chip);
 	if (status < 0)
--- linux-4.4.0.orig/drivers/gpio/gpio-rcar.c
+++ linux-4.4.0/drivers/gpio/gpio-rcar.c
@@ -200,6 +200,48 @@
 	return 0;
 }
 
+static void gpio_rcar_irq_bus_lock(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
+						gpio_chip);
+
+	pm_runtime_get_sync(&p->pdev->dev);
+}
+
+static void gpio_rcar_irq_bus_sync_unlock(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
+						gpio_chip);
+
+	pm_runtime_put(&p->pdev->dev);
+}
+
+
+static int gpio_rcar_irq_request_resources(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
+						gpio_chip);
+	int error;
+
+	error = pm_runtime_get_sync(&p->pdev->dev);
+	if (error < 0)
+		return error;
+
+	return 0;
+}
+
+static void gpio_rcar_irq_release_resources(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
+						gpio_chip);
+
+	pm_runtime_put(&p->pdev->dev);
+}
+
 static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
 {
 	struct gpio_rcar_priv *p = dev_id;
@@ -460,6 +502,10 @@
 	irq_chip->irq_unmask = gpio_rcar_irq_enable;
 	irq_chip->irq_set_type = gpio_rcar_irq_set_type;
 	irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
+	irq_chip->irq_bus_lock = gpio_rcar_irq_bus_lock;
+	irq_chip->irq_bus_sync_unlock = gpio_rcar_irq_bus_sync_unlock;
+	irq_chip->irq_request_resources = gpio_rcar_irq_request_resources;
+	irq_chip->irq_release_resources = gpio_rcar_irq_release_resources;
 	irq_chip->flags	= IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
 
 	ret = gpiochip_add(gpio_chip);
--- linux-4.4.0.orig/drivers/gpio/gpio-sa1100.c
+++ linux-4.4.0/drivers/gpio/gpio-sa1100.c
@@ -155,7 +155,7 @@
 {
 	irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip,
 				 handle_edge_irq);
-	irq_set_noprobe(irq);
+	irq_set_probe(irq);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpio/gpio-syscon.c
+++ linux-4.4.0/drivers/gpio/gpio-syscon.c
@@ -127,7 +127,7 @@
 				   BIT(offs % SYSCON_REG_BITS));
 	}
 
-	priv->data->set(chip, offset, val);
+	chip->set(chip, offset, val);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpio/gpio-tc3589x.c
+++ linux-4.4.0/drivers/gpio/gpio-tc3589x.c
@@ -157,7 +157,7 @@
 				continue;
 
 			tc3589x_gpio->oldregs[i][j] = new;
-			tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new);
+			tc3589x_reg_write(tc3589x, regmap[i] + j, new);
 		}
 	}
 
--- linux-4.4.0.orig/drivers/gpio/gpio-tegra.c
+++ linux-4.4.0/drivers/gpio/gpio-tegra.c
@@ -591,4 +591,4 @@
 {
 	return platform_driver_register(&tegra_gpio_driver);
 }
-postcore_initcall(tegra_gpio_init);
+subsys_initcall(tegra_gpio_init);
--- linux-4.4.0.orig/drivers/gpio/gpio-vf610.c
+++ linux-4.4.0/drivers/gpio/gpio-vf610.c
@@ -227,6 +227,7 @@
 	struct vf610_gpio_port *port;
 	struct resource *iores;
 	struct gpio_chip *gc;
+	int i;
 	int ret;
 
 	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
@@ -265,6 +266,10 @@
 	if (ret < 0)
 		return ret;
 
+	/* Mask all GPIO interrupts */
+	for (i = 0; i < gc->ngpio; i++)
+		vf610_gpio_writel(0, port->base + PORT_PCR(i));
+
 	/* Clear the interrupt status register for all GPIO's */
 	vf610_gpio_writel(~0, port->base + PORT_ISFR);
 
--- linux-4.4.0.orig/drivers/gpio/gpio-xgene.c
+++ linux-4.4.0/drivers/gpio/gpio-xgene.c
@@ -42,9 +42,7 @@
 	struct gpio_chip	chip;
 	void __iomem		*base;
 	spinlock_t		lock;
-#ifdef CONFIG_PM
 	u32			set_dr_val[XGENE_MAX_GPIO_BANKS];
-#endif
 };
 
 static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip)
@@ -132,8 +130,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int xgene_gpio_suspend(struct device *dev)
+static __maybe_unused int xgene_gpio_suspend(struct device *dev)
 {
 	struct xgene_gpio *gpio = dev_get_drvdata(dev);
 	unsigned long bank_offset;
@@ -146,7 +143,7 @@
 	return 0;
 }
 
-static int xgene_gpio_resume(struct device *dev)
+static __maybe_unused int xgene_gpio_resume(struct device *dev)
 {
 	struct xgene_gpio *gpio = dev_get_drvdata(dev);
 	unsigned long bank_offset;
@@ -160,10 +157,6 @@
 }
 
 static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
-#define XGENE_GPIO_PM_OPS	(&xgene_gpio_pm)
-#else
-#define XGENE_GPIO_PM_OPS	NULL
-#endif
 
 static int xgene_gpio_probe(struct platform_device *pdev)
 {
@@ -230,7 +223,7 @@
 	.driver = {
 		.name = "xgene-gpio",
 		.of_match_table = xgene_gpio_of_match,
-		.pm     = XGENE_GPIO_PM_OPS,
+		.pm     = &xgene_gpio_pm,
 	},
 	.probe = xgene_gpio_probe,
 	.remove = xgene_gpio_remove,
--- linux-4.4.0.orig/drivers/gpio/gpiolib-legacy.c
+++ linux-4.4.0/drivers/gpio/gpiolib-legacy.c
@@ -28,6 +28,10 @@
 	if (!desc && gpio_is_valid(gpio))
 		return -EPROBE_DEFER;
 
+	err = gpiod_request(desc, label);
+	if (err)
+		return err;
+
 	if (flags & GPIOF_OPEN_DRAIN)
 		set_bit(FLAG_OPEN_DRAIN, &desc->flags);
 
@@ -37,10 +41,6 @@
 	if (flags & GPIOF_ACTIVE_LOW)
 		set_bit(FLAG_ACTIVE_LOW, &desc->flags);
 
-	err = gpiod_request(desc, label);
-	if (err)
-		return err;
-
 	if (flags & GPIOF_DIR_IN)
 		err = gpiod_direction_input(desc);
 	else
--- linux-4.4.0.orig/drivers/gpio/gpiolib-of.c
+++ linux-4.4.0/drivers/gpio/gpiolib-of.c
@@ -91,7 +91,7 @@
 					 &gg_data.gpiospec);
 	if (ret) {
 		pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n",
-			__func__, propname, np->full_name, index);
+			__func__, propname, np ? np->full_name : NULL, index);
 		return ERR_PTR(ret);
 	}
 
--- linux-4.4.0.orig/drivers/gpio/gpiolib.c
+++ linux-4.4.0/drivers/gpio/gpiolib.c
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/nospec.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/device.h>
@@ -55,6 +56,8 @@
 
 static void gpiochip_free_hogs(struct gpio_chip *chip);
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
+static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
+static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);
 
 
 static inline void desc_set_label(struct gpio_desc *d, const char *label)
@@ -97,7 +100,7 @@
 	if (hwnum >= chip->ngpio)
 		return ERR_PTR(-EINVAL);
 
-	return &chip->desc[hwnum];
+	return &chip->desc[array_index_nospec(hwnum, chip->ngpio)];
 }
 
 /**
@@ -163,6 +166,14 @@
 	chip = gpiod_to_chip(desc);
 	offset = gpio_chip_hwgpio(desc);
 
+	/*
+	 * Open drain emulation using input mode may incorrectly report
+	 * input here, fix that up.
+	 */
+	if (test_bit(FLAG_OPEN_DRAIN, &desc->flags) &&
+	    test_bit(FLAG_IS_OUT, &desc->flags))
+		return 0;
+
 	if (!chip->get_direction)
 		return status;
 
@@ -355,6 +366,10 @@
 	if (status)
 		goto err_remove_from_list;
 
+	status = gpiochip_irqchip_init_valid_mask(chip);
+	if (status)
+		goto err_remove_from_list;
+
 	status = of_gpiochip_add(chip);
 	if (status)
 		goto err_remove_chip;
@@ -375,6 +390,7 @@
 	acpi_gpiochip_remove(chip);
 	gpiochip_free_hogs(chip);
 	of_gpiochip_remove(chip);
+	gpiochip_irqchip_free_valid_mask(chip);
 err_remove_from_list:
 	spin_lock_irqsave(&gpio_lock, flags);
 	list_del(&chip->list);
@@ -481,6 +497,40 @@
  * The following is irqchip helper code for gpiochips.
  */
 
+static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
+{
+	int i;
+
+	if (!gpiochip->irq_need_valid_mask)
+		return 0;
+
+	gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
+					   sizeof(long), GFP_KERNEL);
+	if (!gpiochip->irq_valid_mask)
+		return -ENOMEM;
+
+	/* Assume by default all GPIOs are valid */
+	for (i = 0; i < gpiochip->ngpio; i++)
+		set_bit(i, gpiochip->irq_valid_mask);
+
+	return 0;
+}
+
+static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
+{
+	kfree(gpiochip->irq_valid_mask);
+	gpiochip->irq_valid_mask = NULL;
+}
+
+static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
+				       unsigned int offset)
+{
+	/* No mask means all valid */
+	if (likely(!gpiochip->irq_valid_mask))
+		return true;
+	return test_bit(offset, gpiochip->irq_valid_mask);
+}
+
 /**
  * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip
  * @gpiochip: the gpiochip to set the irqchip chain to
@@ -522,9 +572,12 @@
 	}
 
 	/* Set the parent IRQ for all affected IRQs */
-	for (offset = 0; offset < gpiochip->ngpio; offset++)
+	for (offset = 0; offset < gpiochip->ngpio; offset++) {
+		if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
+			continue;
 		irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
 			       parent_irq);
+	}
 }
 EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
 
@@ -631,9 +684,12 @@
 
 	/* Remove all IRQ mappings and delete the domain */
 	if (gpiochip->irqdomain) {
-		for (offset = 0; offset < gpiochip->ngpio; offset++)
+		for (offset = 0; offset < gpiochip->ngpio; offset++) {
+			if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
+				continue;
 			irq_dispose_mapping(
 				irq_find_mapping(gpiochip->irqdomain, offset));
+		}
 		irq_domain_remove(gpiochip->irqdomain);
 	}
 
@@ -642,6 +698,8 @@
 		gpiochip->irqchip->irq_release_resources = NULL;
 		gpiochip->irqchip = NULL;
 	}
+
+	gpiochip_irqchip_free_valid_mask(gpiochip);
 }
 
 /**
@@ -677,6 +735,7 @@
 			  struct lock_class_key *lock_key)
 {
 	struct device_node *of_node;
+	bool irq_base_set = false;
 	unsigned int offset;
 	unsigned irq_base = 0;
 
@@ -725,13 +784,17 @@
 	 * necessary to allocate descriptors for all IRQs.
 	 */
 	for (offset = 0; offset < gpiochip->ngpio; offset++) {
+		if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
+			continue;
 		irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
-		if (offset == 0)
+		if (!irq_base_set) {
 			/*
 			 * Store the base into the gpiochip to be used when
 			 * unmapping the irqs.
 			 */
 			gpiochip->irq_base = irq_base;
+			irq_base_set = true;
+		}
 	}
 
 	acpi_gpiochip_request_interrupts(gpiochip);
@@ -743,6 +806,12 @@
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
+static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
+{
+	return 0;
+}
+static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
+{ }
 
 #endif /* CONFIG_GPIOLIB_IRQCHIP */
 
@@ -927,14 +996,6 @@
 		spin_lock_irqsave(&gpio_lock, flags);
 	}
 done:
-	if (status < 0) {
-		/* Clear flags that might have been set by the caller before
-		 * requesting the GPIO.
-		 */
-		clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
-		clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
-		clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
-	}
 	spin_unlock_irqrestore(&gpio_lock, flags);
 	return status;
 }
@@ -1649,6 +1710,15 @@
 }
 EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
 
+bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset)
+{
+	if (offset >= chip->ngpio)
+		return false;
+
+	return test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
+}
+EXPORT_SYMBOL_GPL(gpiochip_line_is_irq);
+
 /**
  * gpiod_get_raw_value_cansleep() - return a gpio's raw value
  * @desc: gpio whose value will be returned
@@ -1949,8 +2019,9 @@
 
 		if (chip->ngpio <= p->chip_hwnum) {
 			dev_err(dev,
-				"requested GPIO %d is out of range [0..%d] for chip %s\n",
-				idx, chip->ngpio, chip->label);
+				"requested GPIO %u (%u) is out of range [0..%u] for chip %s\n",
+				idx, p->chip_hwnum, chip->ngpio - 1,
+				chip->label);
 			return ERR_PTR(-EINVAL);
 		}
 
@@ -2062,28 +2133,13 @@
 }
 EXPORT_SYMBOL_GPL(gpiod_get_optional);
 
-/**
- * gpiod_parse_flags - helper function to parse GPIO lookup flags
- * @desc:	gpio to be setup
- * @lflags:	gpio_lookup_flags - returned from of_find_gpio() or
- *		of_get_gpio_hog()
- *
- * Set the GPIO descriptor flags based on the given GPIO lookup flags.
- */
-static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags)
-{
-	if (lflags & GPIO_ACTIVE_LOW)
-		set_bit(FLAG_ACTIVE_LOW, &desc->flags);
-	if (lflags & GPIO_OPEN_DRAIN)
-		set_bit(FLAG_OPEN_DRAIN, &desc->flags);
-	if (lflags & GPIO_OPEN_SOURCE)
-		set_bit(FLAG_OPEN_SOURCE, &desc->flags);
-}
 
 /**
  * gpiod_configure_flags - helper function to configure a given GPIO
  * @desc:	gpio whose value will be assigned
  * @con_id:	function within the GPIO consumer
+ * @lflags:	gpio_lookup_flags - returned from of_find_gpio() or
+ *		of_get_gpio_hog()
  * @dflags:	gpiod_flags - optional GPIO initialization flags
  *
  * Return 0 on success, -ENOENT if no GPIO has been assigned to the
@@ -2091,10 +2147,17 @@
  * occurred while trying to acquire the GPIO.
  */
 static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
-				 enum gpiod_flags dflags)
+		unsigned long lflags, enum gpiod_flags dflags)
 {
 	int status;
 
+	if (lflags & GPIO_ACTIVE_LOW)
+		set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+	if (lflags & GPIO_OPEN_DRAIN)
+		set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+	if (lflags & GPIO_OPEN_SOURCE)
+		set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
 	/* No particular flag request, return here... */
 	if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
 		pr_debug("no flags found for %s\n", con_id);
@@ -2133,6 +2196,8 @@
 	struct gpio_desc *desc = NULL;
 	int status;
 	enum gpio_lookup_flags lookupflags = 0;
+	/* Maybe we have a device name, maybe not */
+	const char *devname = dev ? dev_name(dev) : "?";
 
 	dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
 
@@ -2161,13 +2226,15 @@
 		return desc;
 	}
 
-	gpiod_parse_flags(desc, lookupflags);
-
-	status = gpiod_request(desc, con_id);
+	/*
+	 * If a connection label was passed use that, else attempt to use
+	 * the device name as label
+	 */
+	status = gpiod_request(desc, con_id ? con_id : devname);
 	if (status < 0)
 		return ERR_PTR(status);
 
-	status = gpiod_configure_flags(desc, con_id, flags);
+	status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
 	if (status < 0) {
 		dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
 		gpiod_put(desc);
@@ -2223,6 +2290,10 @@
 	if (IS_ERR(desc))
 		return desc;
 
+	ret = gpiod_request(desc, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
 	if (active_low)
 		set_bit(FLAG_ACTIVE_LOW, &desc->flags);
 
@@ -2233,10 +2304,6 @@
 			set_bit(FLAG_OPEN_SOURCE, &desc->flags);
 	}
 
-	ret = gpiod_request(desc, NULL);
-	if (ret)
-		return ERR_PTR(ret);
-
 	return desc;
 }
 EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
@@ -2289,8 +2356,6 @@
 	chip = gpiod_to_chip(desc);
 	hwnum = gpio_chip_hwgpio(desc);
 
-	gpiod_parse_flags(desc, lflags);
-
 	local_desc = gpiochip_request_own_desc(chip, hwnum, name);
 	if (IS_ERR(local_desc)) {
 		pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
@@ -2298,7 +2363,7 @@
 		return PTR_ERR(local_desc);
 	}
 
-	status = gpiod_configure_flags(desc, name, dflags);
+	status = gpiod_configure_flags(desc, name, lflags, dflags);
 	if (status < 0) {
 		pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
 		       name, chip->label, hwnum);
--- linux-4.4.0.orig/drivers/gpio/gpiolib.h
+++ linux-4.4.0/drivers/gpio/gpiolib.h
@@ -30,7 +30,7 @@
 };
 
 /* gpio suffixes used for ACPI and device tree lookup */
-static const char * const gpio_suffixes[] = { "gpios", "gpio" };
+static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
 
 #ifdef CONFIG_ACPI
 void acpi_gpiochip_add(struct gpio_chip *chip);
--- linux-4.4.0.orig/drivers/gpu/drm/Kconfig
+++ linux-4.4.0/drivers/gpu/drm/Kconfig
@@ -25,6 +25,14 @@
 	bool
 	depends on DRM
 
+config DRM_DP_AUX_CHARDEV
+	bool "DRM DP AUX Interface"
+	depends on DRM
+	help
+	  Choose this option to enable a /dev/drm_dp_auxN node that allows to
+	  read and write values to arbitrary DPCD registers on the DP aux
+	  channel.
+
 config DRM_KMS_HELPER
 	tristate
 	depends on DRM
@@ -160,6 +168,7 @@
 	  If M is selected, the module will be called amdgpu.
 
 source "drivers/gpu/drm/amd/amdgpu/Kconfig"
+source "drivers/gpu/drm/amd/powerplay/Kconfig"
 
 source "drivers/gpu/drm/nouveau/Kconfig"
 
--- linux-4.4.0.orig/drivers/gpu/drm/Makefile
+++ linux-4.4.0/drivers/gpu/drm/Makefile
@@ -24,10 +24,13 @@
 drm-y += $(drm-m)
 
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
-		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o
+		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
+		drm_kms_helper_common.o drm_dp_dual_mode_helper.o
+
 drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
 drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
+drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/Makefile
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -2,10 +2,13 @@
 # Makefile for the drm device driver.  This driver provides support for the
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
-ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/asic_reg \
-	-Idrivers/gpu/drm/amd/include \
-	-Idrivers/gpu/drm/amd/amdgpu \
-	-Idrivers/gpu/drm/amd/scheduler
+FULL_AMD_PATH=$(src)/..
+
+ccflags-y := -Iinclude/drm -I$(FULL_AMD_PATH)/include/asic_reg \
+	-I$(FULL_AMD_PATH)/include \
+	-I$(FULL_AMD_PATH)/amdgpu \
+	-I$(FULL_AMD_PATH)/scheduler \
+	-I$(FULL_AMD_PATH)/powerplay/inc
 
 amdgpu-y := amdgpu_drv.o
 
@@ -22,7 +25,7 @@
 	amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o
 
 # add asic specific block
-amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o gmc_v7_0.o cik_ih.o kv_smc.o kv_dpm.o \
+amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
 	ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o \
 	amdgpu_amdkfd_gfx_v7.o
 
@@ -31,6 +34,7 @@
 
 # add GMC block
 amdgpu-y += \
+	gmc_v7_0.o \
 	gmc_v8_0.o
 
 # add IH block
@@ -44,6 +48,7 @@
 # add SMC block
 amdgpu-y += \
 	amdgpu_dpm.o \
+	amdgpu_powerplay.o \
 	cz_smc.o cz_dpm.o \
 	tonga_smc.o tonga_dpm.o \
 	fiji_smc.o fiji_dpm.o \
@@ -94,6 +99,14 @@
 amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o
 amdgpu-$(CONFIG_MMU_NOTIFIER) += amdgpu_mn.o
 
+ifneq ($(CONFIG_DRM_AMD_POWERPLAY),)
+
+include $(FULL_AMD_PATH)/powerplay/Makefile
+
+amdgpu-y += $(AMD_POWERPLAY_FILES)
+
+endif
+
 obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
 
 CFLAGS_amdgpu_trace_points.o := -I$(src)
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -52,6 +52,7 @@
 #include "amdgpu_irq.h"
 #include "amdgpu_ucode.h"
 #include "amdgpu_gds.h"
+#include "amd_powerplay.h"
 
 #include "gpu_scheduler.h"
 
@@ -85,6 +86,9 @@
 extern int amdgpu_sched_jobs;
 extern int amdgpu_sched_hw_submission;
 extern int amdgpu_enable_semaphores;
+extern int amdgpu_powerplay;
+extern unsigned amdgpu_pcie_gen_cap;
+extern unsigned amdgpu_pcie_lane_cap;
 
 #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS	        3000
 #define AMDGPU_MAX_USEC_TIMEOUT			100000	/* 100 ms */
@@ -130,47 +134,6 @@
 #define AMDGPU_RESET_VCE			(1 << 13)
 #define AMDGPU_RESET_VCE1			(1 << 14)
 
-/* CG block flags */
-#define AMDGPU_CG_BLOCK_GFX			(1 << 0)
-#define AMDGPU_CG_BLOCK_MC			(1 << 1)
-#define AMDGPU_CG_BLOCK_SDMA			(1 << 2)
-#define AMDGPU_CG_BLOCK_UVD			(1 << 3)
-#define AMDGPU_CG_BLOCK_VCE			(1 << 4)
-#define AMDGPU_CG_BLOCK_HDP			(1 << 5)
-#define AMDGPU_CG_BLOCK_BIF			(1 << 6)
-
-/* CG flags */
-#define AMDGPU_CG_SUPPORT_GFX_MGCG		(1 << 0)
-#define AMDGPU_CG_SUPPORT_GFX_MGLS		(1 << 1)
-#define AMDGPU_CG_SUPPORT_GFX_CGCG		(1 << 2)
-#define AMDGPU_CG_SUPPORT_GFX_CGLS		(1 << 3)
-#define AMDGPU_CG_SUPPORT_GFX_CGTS		(1 << 4)
-#define AMDGPU_CG_SUPPORT_GFX_CGTS_LS		(1 << 5)
-#define AMDGPU_CG_SUPPORT_GFX_CP_LS		(1 << 6)
-#define AMDGPU_CG_SUPPORT_GFX_RLC_LS		(1 << 7)
-#define AMDGPU_CG_SUPPORT_MC_LS			(1 << 8)
-#define AMDGPU_CG_SUPPORT_MC_MGCG		(1 << 9)
-#define AMDGPU_CG_SUPPORT_SDMA_LS		(1 << 10)
-#define AMDGPU_CG_SUPPORT_SDMA_MGCG		(1 << 11)
-#define AMDGPU_CG_SUPPORT_BIF_LS		(1 << 12)
-#define AMDGPU_CG_SUPPORT_UVD_MGCG		(1 << 13)
-#define AMDGPU_CG_SUPPORT_VCE_MGCG		(1 << 14)
-#define AMDGPU_CG_SUPPORT_HDP_LS		(1 << 15)
-#define AMDGPU_CG_SUPPORT_HDP_MGCG		(1 << 16)
-
-/* PG flags */
-#define AMDGPU_PG_SUPPORT_GFX_PG		(1 << 0)
-#define AMDGPU_PG_SUPPORT_GFX_SMG		(1 << 1)
-#define AMDGPU_PG_SUPPORT_GFX_DMG		(1 << 2)
-#define AMDGPU_PG_SUPPORT_UVD			(1 << 3)
-#define AMDGPU_PG_SUPPORT_VCE			(1 << 4)
-#define AMDGPU_PG_SUPPORT_CP			(1 << 5)
-#define AMDGPU_PG_SUPPORT_GDS			(1 << 6)
-#define AMDGPU_PG_SUPPORT_RLC_SMU_HS		(1 << 7)
-#define AMDGPU_PG_SUPPORT_SDMA			(1 << 8)
-#define AMDGPU_PG_SUPPORT_ACP			(1 << 9)
-#define AMDGPU_PG_SUPPORT_SAMU			(1 << 10)
-
 /* GFX current status */
 #define AMDGPU_GFX_NORMAL_MODE			0x00000000L
 #define AMDGPU_GFX_SAFE_MODE			0x00000001L
@@ -532,6 +495,7 @@
 	u64				metadata_flags;
 	void				*metadata;
 	u32				metadata_size;
+	unsigned			prime_shared_count;
 	/* list of all virtual address to which this bo
 	 * is associated to
 	 */
@@ -604,8 +568,6 @@
 	uint32_t		align;
 };
 
-struct amdgpu_sa_bo;
-
 /* sub-allocation buffer */
 struct amdgpu_sa_bo {
 	struct list_head		olist;
@@ -712,9 +674,9 @@
 void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev);
 int amdgpu_gart_init(struct amdgpu_device *adev);
 void amdgpu_gart_fini(struct amdgpu_device *adev);
-void amdgpu_gart_unbind(struct amdgpu_device *adev, unsigned offset,
+void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
 			int pages);
-int amdgpu_gart_bind(struct amdgpu_device *adev, unsigned offset,
+int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
 		     int pages, struct page **pagelist,
 		     dma_addr_t *dma_addr, uint32_t flags);
 
@@ -918,8 +880,8 @@
 #define AMDGPU_VM_FAULT_STOP_ALWAYS	2
 
 struct amdgpu_vm_pt {
-	struct amdgpu_bo	*bo;
-	uint64_t		addr;
+	struct amdgpu_bo_list_entry	entry;
+	uint64_t			addr;
 };
 
 struct amdgpu_vm_id {
@@ -981,9 +943,12 @@
 void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
 int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm);
 void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
-struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
-					       struct amdgpu_vm *vm,
-					       struct list_head *head);
+void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
+			 struct list_head *validated,
+			 struct amdgpu_bo_list_entry *entry);
+void amdgpu_vm_get_pt_bos(struct amdgpu_vm *vm, struct list_head *duplicates);
+void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev,
+				  struct amdgpu_vm *vm);
 int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
 		      struct amdgpu_sync *sync);
 void amdgpu_vm_flush(struct amdgpu_ring *ring,
@@ -1024,11 +989,9 @@
  * context related structures
  */
 
-#define AMDGPU_CTX_MAX_CS_PENDING	16
-
 struct amdgpu_ctx_ring {
 	uint64_t		sequence;
-	struct fence		*fences[AMDGPU_CTX_MAX_CS_PENDING];
+	struct fence		**fences;
 	struct amd_sched_entity	entity;
 };
 
@@ -1037,6 +1000,7 @@
 	struct amdgpu_device    *adev;
 	unsigned		reset_counter;
 	spinlock_t		ring_lock;
+	struct fence            **fences;
 	struct amdgpu_ctx_ring	rings[AMDGPU_MAX_RINGS];
 };
 
@@ -1047,7 +1011,7 @@
 	struct idr		ctx_handles;
 };
 
-int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
+int amdgpu_ctx_init(struct amdgpu_device *adev, enum amd_sched_priority pri,
 		    struct amdgpu_ctx *ctx);
 void amdgpu_ctx_fini(struct amdgpu_ctx *ctx);
 
@@ -1254,7 +1218,7 @@
 	unsigned		nchunks;
 	struct amdgpu_cs_chunk	*chunks;
 	/* relocations */
-	struct amdgpu_bo_list_entry	*vm_bos;
+	struct amdgpu_bo_list_entry	vm_pd;
 	struct list_head	validated;
 	struct fence		*fence;
 
@@ -1301,31 +1265,7 @@
 int amdgpu_wb_get(struct amdgpu_device *adev, u32 *wb);
 void amdgpu_wb_free(struct amdgpu_device *adev, u32 wb);
 
-/**
- * struct amdgpu_pm - power management datas
- * It keeps track of various data needed to take powermanagement decision.
- */
-
-enum amdgpu_pm_state_type {
-	/* not used for dpm */
-	POWER_STATE_TYPE_DEFAULT,
-	POWER_STATE_TYPE_POWERSAVE,
-	/* user selectable states */
-	POWER_STATE_TYPE_BATTERY,
-	POWER_STATE_TYPE_BALANCED,
-	POWER_STATE_TYPE_PERFORMANCE,
-	/* internal states */
-	POWER_STATE_TYPE_INTERNAL_UVD,
-	POWER_STATE_TYPE_INTERNAL_UVD_SD,
-	POWER_STATE_TYPE_INTERNAL_UVD_HD,
-	POWER_STATE_TYPE_INTERNAL_UVD_HD2,
-	POWER_STATE_TYPE_INTERNAL_UVD_MVC,
-	POWER_STATE_TYPE_INTERNAL_BOOT,
-	POWER_STATE_TYPE_INTERNAL_THERMAL,
-	POWER_STATE_TYPE_INTERNAL_ACPI,
-	POWER_STATE_TYPE_INTERNAL_ULV,
-	POWER_STATE_TYPE_INTERNAL_3DPERF,
-};
+
 
 enum amdgpu_int_thermal_type {
 	THERMAL_TYPE_NONE,
@@ -1607,8 +1547,8 @@
 	/* vce requirements */
 	struct amdgpu_vce_state vce_states[AMDGPU_MAX_VCE_LEVELS];
 	enum amdgpu_vce_level vce_level;
-	enum amdgpu_pm_state_type state;
-	enum amdgpu_pm_state_type user_state;
+	enum amd_pm_state_type state;
+	enum amd_pm_state_type user_state;
 	u32                     platform_caps;
 	u32                     voltage_response_time;
 	u32                     backbias_response_time;
@@ -1661,8 +1601,13 @@
 	const struct firmware	*fw;	/* SMC firmware */
 	uint32_t                fw_version;
 	const struct amdgpu_dpm_funcs *funcs;
+	uint32_t                pcie_gen_mask;
+	uint32_t                pcie_mlw_mask;
+	struct amd_pp_display_configuration pm_display_cfg;/* set by DAL */
 };
 
+void amdgpu_get_pcie_info(struct amdgpu_device *adev);
+
 /*
  * UVD
  */
@@ -1675,6 +1620,7 @@
 	struct amdgpu_bo	*vcpu_bo;
 	void			*cpu_addr;
 	uint64_t		gpu_addr;
+	unsigned		fw_version;
 	atomic_t		handles[AMDGPU_MAX_UVD_HANDLES];
 	struct drm_file		*filp[AMDGPU_MAX_UVD_HANDLES];
 	struct delayed_work	idle_work;
@@ -1830,6 +1776,8 @@
  */
 struct amdgpu_asic_funcs {
 	bool (*read_disabled_bios)(struct amdgpu_device *adev);
+	bool (*read_bios_from_rom)(struct amdgpu_device *adev,
+				   u8 *bios, u32 length_bytes);
 	int (*read_register)(struct amdgpu_device *adev, u32 se_num,
 			     u32 sh_num, u32 reg_offset, u32 *value);
 	void (*set_vga_state)(struct amdgpu_device *adev, bool state);
@@ -2060,6 +2008,10 @@
 	/* interrupts */
 	struct amdgpu_irq		irq;
 
+	/* powerplay */
+	struct amd_powerplay		powerplay;
+	bool				pp_enabled;
+
 	/* dpm */
 	struct amdgpu_pm		pm;
 	u32				cg_flags;
@@ -2236,6 +2188,7 @@
 #define amdgpu_asic_set_vce_clocks(adev, ev, ec) (adev)->asic_funcs->set_vce_clocks((adev), (ev), (ec))
 #define amdgpu_asic_get_gpu_clock_counter(adev) (adev)->asic_funcs->get_gpu_clock_counter((adev))
 #define amdgpu_asic_read_disabled_bios(adev) (adev)->asic_funcs->read_disabled_bios((adev))
+#define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l))
 #define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v)))
 #define amdgpu_asic_get_cu_info(adev, info) (adev)->asic_funcs->get_cu_info((adev), (info))
 #define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid))
@@ -2277,24 +2230,78 @@
 #define amdgpu_display_resume_mc_access(adev, s) (adev)->mode_info.funcs->resume_mc_access((adev), (s))
 #define amdgpu_emit_copy_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_copy_buffer((ib),  (s), (d), (b))
 #define amdgpu_emit_fill_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((ib), (s), (d), (b))
-#define amdgpu_dpm_get_temperature(adev) (adev)->pm.funcs->get_temperature((adev))
 #define amdgpu_dpm_pre_set_power_state(adev) (adev)->pm.funcs->pre_set_power_state((adev))
 #define amdgpu_dpm_set_power_state(adev) (adev)->pm.funcs->set_power_state((adev))
 #define amdgpu_dpm_post_set_power_state(adev) (adev)->pm.funcs->post_set_power_state((adev))
 #define amdgpu_dpm_display_configuration_changed(adev) (adev)->pm.funcs->display_configuration_changed((adev))
-#define amdgpu_dpm_get_sclk(adev, l) (adev)->pm.funcs->get_sclk((adev), (l))
-#define amdgpu_dpm_get_mclk(adev, l) (adev)->pm.funcs->get_mclk((adev), (l))
 #define amdgpu_dpm_print_power_state(adev, ps) (adev)->pm.funcs->print_power_state((adev), (ps))
-#define amdgpu_dpm_debugfs_print_current_performance_level(adev, m) (adev)->pm.funcs->debugfs_print_current_performance_level((adev), (m))
-#define amdgpu_dpm_force_performance_level(adev, l) (adev)->pm.funcs->force_performance_level((adev), (l))
 #define amdgpu_dpm_vblank_too_short(adev) (adev)->pm.funcs->vblank_too_short((adev))
-#define amdgpu_dpm_powergate_uvd(adev, g) (adev)->pm.funcs->powergate_uvd((adev), (g))
-#define amdgpu_dpm_powergate_vce(adev, g) (adev)->pm.funcs->powergate_vce((adev), (g))
 #define amdgpu_dpm_enable_bapm(adev, e) (adev)->pm.funcs->enable_bapm((adev), (e))
-#define amdgpu_dpm_set_fan_control_mode(adev, m) (adev)->pm.funcs->set_fan_control_mode((adev), (m))
-#define amdgpu_dpm_get_fan_control_mode(adev) (adev)->pm.funcs->get_fan_control_mode((adev))
-#define amdgpu_dpm_set_fan_speed_percent(adev, s) (adev)->pm.funcs->set_fan_speed_percent((adev), (s))
-#define amdgpu_dpm_get_fan_speed_percent(adev, s) (adev)->pm.funcs->get_fan_speed_percent((adev), (s))
+
+#define amdgpu_dpm_get_temperature(adev) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->get_temperature((adev)->powerplay.pp_handle) : \
+	      (adev)->pm.funcs->get_temperature((adev)))
+
+#define amdgpu_dpm_set_fan_control_mode(adev, m) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->set_fan_control_mode((adev)->powerplay.pp_handle, (m)) : \
+	      (adev)->pm.funcs->set_fan_control_mode((adev), (m)))
+
+#define amdgpu_dpm_get_fan_control_mode(adev) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->get_fan_control_mode((adev)->powerplay.pp_handle) : \
+	      (adev)->pm.funcs->get_fan_control_mode((adev)))
+
+#define amdgpu_dpm_set_fan_speed_percent(adev, s) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->set_fan_speed_percent((adev)->powerplay.pp_handle, (s)) : \
+	      (adev)->pm.funcs->set_fan_speed_percent((adev), (s)))
+
+#define amdgpu_dpm_get_fan_speed_percent(adev, s) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->get_fan_speed_percent((adev)->powerplay.pp_handle, (s)) : \
+	      (adev)->pm.funcs->get_fan_speed_percent((adev), (s)))
+
+#define amdgpu_dpm_get_sclk(adev, l) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->get_sclk((adev)->powerplay.pp_handle, (l)) : \
+		(adev)->pm.funcs->get_sclk((adev), (l)))
+
+#define amdgpu_dpm_get_mclk(adev, l)  \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->get_mclk((adev)->powerplay.pp_handle, (l)) : \
+	      (adev)->pm.funcs->get_mclk((adev), (l)))
+
+
+#define amdgpu_dpm_force_performance_level(adev, l) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->force_performance_level((adev)->powerplay.pp_handle, (l)) : \
+	      (adev)->pm.funcs->force_performance_level((adev), (l)))
+
+#define amdgpu_dpm_powergate_uvd(adev, g) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->powergate_uvd((adev)->powerplay.pp_handle, (g)) : \
+	      (adev)->pm.funcs->powergate_uvd((adev), (g)))
+
+#define amdgpu_dpm_powergate_vce(adev, g) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->powergate_vce((adev)->powerplay.pp_handle, (g)) : \
+	      (adev)->pm.funcs->powergate_vce((adev), (g)))
+
+#define amdgpu_dpm_debugfs_print_current_performance_level(adev, m) \
+	((adev)->pp_enabled ?						\
+	      (adev)->powerplay.pp_funcs->print_current_performance_level((adev)->powerplay.pp_handle, (m)) : \
+	      (adev)->pm.funcs->debugfs_print_current_performance_level((adev), (m)))
+
+#define amdgpu_dpm_get_current_power_state(adev) \
+	(adev)->powerplay.pp_funcs->get_current_power_state((adev)->powerplay.pp_handle)
+
+#define amdgpu_dpm_get_performance_level(adev) \
+	(adev)->powerplay.pp_funcs->get_performance_level((adev)->powerplay.pp_handle)
+
+#define amdgpu_dpm_dispatch_task(adev, event_id, input, output)		\
+	(adev)->powerplay.pp_funcs->dispatch_tasks((adev)->powerplay.pp_handle, (event_id), (input), (output))
 
 #define amdgpu_gds_switch(adev, r, v, d, w, a) (adev)->gds.funcs->patch_gds_switch((r), (v), (d), (w), (a))
 
@@ -2314,6 +2321,8 @@
 int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
 				     uint32_t flags);
 bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm);
+bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
+				  unsigned long end);
 bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm);
 uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
 				 struct ttm_mem_reg *mem);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -29,66 +29,10 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include "amdgpu.h"
-#include "amdgpu_acpi.h"
+#include "amd_acpi.h"
 #include "atom.h"
 
-#define ACPI_AC_CLASS           "ac_adapter"
-
 extern void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev);
-
-struct atif_verify_interface {
-	u16 size;		/* structure size in bytes (includes size field) */
-	u16 version;		/* version */
-	u32 notification_mask;	/* supported notifications mask */
-	u32 function_bits;	/* supported functions bit vector */
-} __packed;
-
-struct atif_system_params {
-	u16 size;		/* structure size in bytes (includes size field) */
-	u32 valid_mask;		/* valid flags mask */
-	u32 flags;		/* flags */
-	u8 command_code;	/* notify command code */
-} __packed;
-
-struct atif_sbios_requests {
-	u16 size;		/* structure size in bytes (includes size field) */
-	u32 pending;		/* pending sbios requests */
-	u8 panel_exp_mode;	/* panel expansion mode */
-	u8 thermal_gfx;		/* thermal state: target gfx controller */
-	u8 thermal_state;	/* thermal state: state id (0: exit state, non-0: state) */
-	u8 forced_power_gfx;	/* forced power state: target gfx controller */
-	u8 forced_power_state;	/* forced power state: state id */
-	u8 system_power_src;	/* system power source */
-	u8 backlight_level;	/* panel backlight level (0-255) */
-} __packed;
-
-#define ATIF_NOTIFY_MASK	0x3
-#define ATIF_NOTIFY_NONE	0
-#define ATIF_NOTIFY_81		1
-#define ATIF_NOTIFY_N		2
-
-struct atcs_verify_interface {
-	u16 size;		/* structure size in bytes (includes size field) */
-	u16 version;		/* version */
-	u32 function_bits;	/* supported functions bit vector */
-} __packed;
-
-#define ATCS_VALID_FLAGS_MASK	0x3
-
-struct atcs_pref_req_input {
-	u16 size;		/* structure size in bytes (includes size field) */
-	u16 client_id;		/* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
-	u16 valid_flags_mask;	/* valid flags mask */
-	u16 flags;		/* flags */
-	u8 req_type;		/* request type */
-	u8 perf_req;		/* performance request */
-} __packed;
-
-struct atcs_pref_req_output {
-	u16 size;		/* structure size in bytes (includes size field) */
-	u8 ret_val;		/* return value */
-} __packed;
-
 /* Call the ATIF method
  */
 /**
@@ -105,6 +49,7 @@
 		struct acpi_buffer *params)
 {
 	acpi_status status;
+	union acpi_object *obj;
 	union acpi_object atif_arg_elements[2];
 	struct acpi_object_list atif_arg;
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -126,16 +71,24 @@
 	}
 
 	status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer);
+	obj = (union acpi_object *)buffer.pointer;
 
-	/* Fail only if calling the method fails and ATIF is supported */
+	/* Fail if calling the method fails and ATIF is supported */
 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 		DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
 				 acpi_format_exception(status));
-		kfree(buffer.pointer);
+		kfree(obj);
 		return NULL;
 	}
 
-	return buffer.pointer;
+	if (obj->type != ACPI_TYPE_BUFFER) {
+		DRM_DEBUG_DRIVER("bad object returned from ATIF: %d\n",
+				 obj->type);
+		kfree(obj);
+		return NULL;
+	}
+
+	return obj;
 }
 
 /**
@@ -585,6 +538,9 @@
 	size_t size;
 	u32 retry = 3;
 
+	if (amdgpu_acpi_pcie_notify_device_ready(adev))
+		return -EINVAL;
+
 	/* Get the device handle */
 	handle = ACPI_HANDLE(&adev->pdev->dev);
 	if (!handle)
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
@@ -154,7 +154,7 @@
 	.get_fw_version = get_fw_version
 };
 
-struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions()
+struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void)
 {
 	return (struct kfd2kgd_calls *)&kfd2kgd;
 }
@@ -367,29 +367,50 @@
 {
 	struct amdgpu_device *adev = get_amdgpu_device(kgd);
 	struct cik_sdma_rlc_registers *m;
+	unsigned long end_jiffies;
 	uint32_t sdma_base_addr;
+	uint32_t data;
 
 	m = get_sdma_mqd(mqd);
 	sdma_base_addr = get_sdma_base_addr(m);
 
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR,
-			m->sdma_rlc_virtual_addr);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
+		m->sdma_rlc_rb_cntl & (~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK));
 
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE,
-			m->sdma_rlc_rb_base);
+	end_jiffies = msecs_to_jiffies(2000) + jiffies;
+	while (true) {
+		data = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS);
+		if (data & SDMA0_RLC0_CONTEXT_STATUS__IDLE_MASK)
+			break;
+		if (time_after(jiffies, end_jiffies))
+			return -ETIME;
+		usleep_range(500, 1000);
+	}
+	if (m->sdma_engine_id) {
+		data = RREG32(mmSDMA1_GFX_CONTEXT_CNTL);
+		data = REG_SET_FIELD(data, SDMA1_GFX_CONTEXT_CNTL,
+				RESUME_CTX, 0);
+		WREG32(mmSDMA1_GFX_CONTEXT_CNTL, data);
+	} else {
+		data = RREG32(mmSDMA0_GFX_CONTEXT_CNTL);
+		data = REG_SET_FIELD(data, SDMA0_GFX_CONTEXT_CNTL,
+				RESUME_CTX, 0);
+		WREG32(mmSDMA0_GFX_CONTEXT_CNTL, data);
+	}
 
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL,
+				m->sdma_rlc_doorbell);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR,
+				m->sdma_rlc_virtual_addr);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, m->sdma_rlc_rb_base);
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI,
 			m->sdma_rlc_rb_base_hi);
-
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO,
 			m->sdma_rlc_rb_rptr_addr_lo);
-
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI,
 			m->sdma_rlc_rb_rptr_addr_hi);
-
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL,
-			m->sdma_rlc_doorbell);
-
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
 			m->sdma_rlc_rb_cntl);
 
@@ -483,7 +504,7 @@
 
 	while (true) {
 		temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS);
-		if (temp & SDMA0_STATUS_REG__RB_CMD_IDLE__SHIFT)
+		if (temp & SDMA0_RLC0_CONTEXT_STATUS__IDLE_MASK)
 			break;
 		if (timeout == 0)
 			return -ETIME;
@@ -492,9 +513,9 @@
 	}
 
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
+		RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL) |
+		SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
@@ -115,7 +115,7 @@
 	.get_fw_version = get_fw_version
 };
 
-struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions()
+struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void)
 {
 	return (struct kfd2kgd_calls *)&kfd2kgd;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
@@ -319,17 +319,22 @@
 		path_size += le16_to_cpu(path->usSize);
 
 		if (device_support & le16_to_cpu(path->usDeviceTag)) {
-			uint8_t con_obj_id, con_obj_num, con_obj_type;
-
-			con_obj_id =
+			uint8_t con_obj_id =
 			    (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK)
 			    >> OBJECT_ID_SHIFT;
-			con_obj_num =
-			    (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK)
-			    >> ENUM_ID_SHIFT;
-			con_obj_type =
-			    (le16_to_cpu(path->usConnObjectId) &
-			     OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
+
+			/* Skip TV/CV support */
+			if ((le16_to_cpu(path->usDeviceTag) ==
+			     ATOM_DEVICE_TV1_SUPPORT) ||
+			    (le16_to_cpu(path->usDeviceTag) ==
+			     ATOM_DEVICE_CV_SUPPORT))
+				continue;
+
+			if (con_obj_id >= ARRAY_SIZE(object_connector_convert)) {
+				DRM_ERROR("invalid con_obj_id %d for device tag 0x%04x\n",
+					  con_obj_id, le16_to_cpu(path->usDeviceTag));
+				continue;
+			}
 
 			connector_type =
 				object_connector_convert[con_obj_id];
@@ -341,15 +346,7 @@
 			router.ddc_valid = false;
 			router.cd_valid = false;
 			for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
-				uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
-
-				grph_obj_id =
-				    (le16_to_cpu(path->usGraphicObjIds[j]) &
-				     OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
-				grph_obj_num =
-				    (le16_to_cpu(path->usGraphicObjIds[j]) &
-				     ENUM_ID_MASK) >> ENUM_ID_SHIFT;
-				grph_obj_type =
+				uint8_t grph_obj_type =
 				    (le16_to_cpu(path->usGraphicObjIds[j]) &
 				     OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
 
@@ -566,28 +563,19 @@
 		    le16_to_cpu(firmware_info->info.usReferenceClock);
 		ppll->reference_div = 0;
 
-		if (crev < 2)
-			ppll->pll_out_min =
-				le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
-		else
-			ppll->pll_out_min =
-				le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
+		ppll->pll_out_min =
+			le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
 		ppll->pll_out_max =
 		    le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
 
-		if (crev >= 4) {
-			ppll->lcd_pll_out_min =
-				le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
-			if (ppll->lcd_pll_out_min == 0)
-				ppll->lcd_pll_out_min = ppll->pll_out_min;
-			ppll->lcd_pll_out_max =
-				le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
-			if (ppll->lcd_pll_out_max == 0)
-				ppll->lcd_pll_out_max = ppll->pll_out_max;
-		} else {
+		ppll->lcd_pll_out_min =
+			le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
+		if (ppll->lcd_pll_out_min == 0)
 			ppll->lcd_pll_out_min = ppll->pll_out_min;
+		ppll->lcd_pll_out_max =
+			le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
+		if (ppll->lcd_pll_out_max == 0)
 			ppll->lcd_pll_out_max = ppll->pll_out_max;
-		}
 
 		if (ppll->pll_out_min == 0)
 			ppll->pll_out_min = 64800;
@@ -677,6 +665,10 @@
 			DRM_INFO("Changing default dispclk from %dMhz to 600Mhz\n",
 				 adev->clock.default_dispclk / 100);
 			adev->clock.default_dispclk = 60000;
+		} else if (adev->clock.default_dispclk <= 60000) {
+			DRM_INFO("Changing default dispclk from %dMhz to 625Mhz\n",
+				 adev->clock.default_dispclk / 100);
+			adev->clock.default_dispclk = 62500;
 		}
 		adev->clock.dp_extclk =
 			le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
@@ -1485,6 +1477,8 @@
 										(u32)le32_to_cpu(*((u32 *)reg_data + j));
 									j++;
 								} else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
+									if (i == 0)
+										continue;
 									reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
 										reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1];
 								}
@@ -1567,34 +1561,32 @@
 		WREG32(mmBIOS_SCRATCH_0 + i, adev->bios_scratch[i]);
 }
 
-/* Atom needs data in little endian format
- * so swap as appropriate when copying data to
- * or from atom. Note that atom operates on
- * dw units.
+/* Atom needs data in little endian format so swap as appropriate when copying
+ * data to or from atom. Note that atom operates on dw units.
+ *
+ * Use to_le=true when sending data to atom and provide at least
+ * ALIGN(num_bytes,4) bytes in the dst buffer.
+ *
+ * Use to_le=false when receiving data from atom and provide ALIGN(num_bytes,4)
+ * byes in the src buffer.
  */
 void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
 {
 #ifdef __BIG_ENDIAN
-	u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
-	u32 *dst32, *src32;
+	u32 src_tmp[5], dst_tmp[5];
 	int i;
+	u8 align_num_bytes = ALIGN(num_bytes, 4);
 
-	memcpy(src_tmp, src, num_bytes);
-	src32 = (u32 *)src_tmp;
-	dst32 = (u32 *)dst_tmp;
 	if (to_le) {
-		for (i = 0; i < ((num_bytes + 3) / 4); i++)
-			dst32[i] = cpu_to_le32(src32[i]);
-		memcpy(dst, dst_tmp, num_bytes);
+		memcpy(src_tmp, src, num_bytes);
+		for (i = 0; i < align_num_bytes / 4; i++)
+			dst_tmp[i] = cpu_to_le32(src_tmp[i]);
+		memcpy(dst, dst_tmp, align_num_bytes);
 	} else {
-		u8 dws = num_bytes & ~3;
-		for (i = 0; i < ((num_bytes + 3) / 4); i++)
-			dst32[i] = le32_to_cpu(src32[i]);
-		memcpy(dst, dst_tmp, dws);
-		if (num_bytes % 4) {
-			for (i = 0; i < (num_bytes % 4); i++)
-				dst[dws+i] = dst_tmp[dws+i];
-		}
+		memcpy(src_tmp, src, align_num_bytes);
+		for (i = 0; i < align_num_bytes / 4; i++)
+			dst_tmp[i] = le32_to_cpu(src_tmp[i]);
+		memcpy(dst, dst_tmp, num_bytes);
 	}
 #else
 	memcpy(dst, src, num_bytes);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
@@ -10,8 +10,9 @@
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 
-#include "amdgpu_acpi.h"
+#include "amd_acpi.h"
 
 struct amdgpu_atpx_functions {
 	bool px_params;
@@ -256,6 +257,10 @@
 		if (!info)
 			return -EIO;
 		kfree(info);
+
+		/* 200ms delay is required after off */
+		if (state == 0)
+			msleep(200);
 	}
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -35,6 +35,13 @@
  * BIOS.
  */
 
+#define AMD_VBIOS_SIGNATURE " 761295520"
+#define AMD_VBIOS_SIGNATURE_OFFSET 0x30
+#define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE)
+#define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE)
+#define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)
+#define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)
+
 /* If you boot an IGP board with a discrete card as the primary,
  * the IGP rom is not accessible via the rom bar as the IGP rom is
  * part of the system bios.  On boot, the system bios puts a
@@ -58,7 +65,7 @@
 		return false;
 	}
 
-	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+	if (size == 0 || !AMD_IS_VALID_VBIOS(bios)) {
 		iounmap(bios);
 		return false;
 	}
@@ -74,7 +81,7 @@
 
 bool amdgpu_read_bios(struct amdgpu_device *adev)
 {
-	uint8_t __iomem *bios, val1, val2;
+	uint8_t __iomem *bios, val[2];
 	size_t size;
 
 	adev->bios = NULL;
@@ -84,10 +91,10 @@
 		return false;
 	}
 
-	val1 = readb(&bios[0]);
-	val2 = readb(&bios[1]);
+	val[0] = readb(&bios[0]);
+	val[1] = readb(&bios[1]);
 
-	if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
+	if (size == 0 || !AMD_IS_VALID_VBIOS(val)) {
 		pci_unmap_rom(adev->pdev, bios);
 		return false;
 	}
@@ -101,6 +108,38 @@
 	return true;
 }
 
+static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
+{
+	u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};
+	int len;
+
+	if (!adev->asic_funcs->read_bios_from_rom)
+		return false;
+
+	/* validate VBIOS signature */
+	if (amdgpu_asic_read_bios_from_rom(adev, &header[0], sizeof(header)) == false)
+		return false;
+	header[AMD_VBIOS_SIGNATURE_END] = 0;
+
+	if ((!AMD_IS_VALID_VBIOS(header)) ||
+	    0 != memcmp((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET],
+			AMD_VBIOS_SIGNATURE,
+			strlen(AMD_VBIOS_SIGNATURE)))
+		return false;
+
+	/* valid vbios, go on */
+	len = AMD_VBIOS_LENGTH(header);
+	len = ALIGN(len, 4);
+	adev->bios = kmalloc(len, GFP_KERNEL);
+	if (!adev->bios) {
+		DRM_ERROR("no memory to allocate for BIOS\n");
+		return false;
+	}
+
+	/* read complete BIOS */
+	return amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
+}
+
 static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
 {
 	uint8_t __iomem *bios;
@@ -113,7 +152,7 @@
 		return false;
 	}
 
-	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+	if (size == 0 || !AMD_IS_VALID_VBIOS(bios)) {
 		return false;
 	}
 	adev->bios = kmemdup(bios, size, GFP_KERNEL);
@@ -230,7 +269,7 @@
 			break;
 	}
 
-	if (i == 0 || adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
+	if (i == 0 || !AMD_IS_VALID_VBIOS(adev->bios)) {
 		kfree(adev->bios);
 		return false;
 	}
@@ -320,6 +359,9 @@
 	if (r == false)
 		r = amdgpu_read_bios(adev);
 	if (r == false) {
+		r = amdgpu_read_bios_from_rom(adev);
+	}
+	if (r == false) {
 		r = amdgpu_read_disabled_bios(adev);
 	}
 	if (r == false) {
@@ -330,7 +372,7 @@
 		adev->bios = NULL;
 		return false;
 	}
-	if (adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
+	if (!AMD_IS_VALID_VBIOS(adev->bios)) {
 		printk("BIOS signature incorrect %x %x\n", adev->bios[0], adev->bios[1]);
 		goto free_bios;
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -117,7 +117,7 @@
 			entry->allowed_domains = AMDGPU_GEM_DOMAIN_GTT;
 		}
 		entry->tv.bo = &entry->robj->tbo;
-		entry->tv.shared = true;
+		entry->tv.shared = !entry->robj->prime_shared_count;
 
 		if (entry->prefered_domains == AMDGPU_GEM_DOMAIN_GDS)
 			gds_obj = entry->robj;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/acpi.h>
 #include <drm/drmP.h>
 #include <linux/firmware.h>
 #include <drm/amdgpu_drm.h>
@@ -32,7 +33,6 @@
 #include "atom.h"
 #include "amdgpu_ucode.h"
 
-
 struct amdgpu_cgs_device {
 	struct cgs_device base;
 	struct amdgpu_device *adev;
@@ -398,6 +398,41 @@
 	WARN(ret, "pci_write_config_dword error");
 }
 
+
+static int amdgpu_cgs_get_pci_resource(void *cgs_device,
+				       enum cgs_resource_type resource_type,
+				       uint64_t size,
+				       uint64_t offset,
+				       uint64_t *resource_base)
+{
+	CGS_FUNC_ADEV;
+
+	if (resource_base == NULL)
+		return -EINVAL;
+
+	switch (resource_type) {
+	case CGS_RESOURCE_TYPE_MMIO:
+		if (adev->rmmio_size == 0)
+			return -ENOENT;
+		if ((offset + size) > adev->rmmio_size)
+			return -EINVAL;
+		*resource_base = adev->rmmio_base;
+		return 0;
+	case CGS_RESOURCE_TYPE_DOORBELL:
+		if (adev->doorbell.size == 0)
+			return -ENOENT;
+		if ((offset + size) > adev->doorbell.size)
+			return -EINVAL;
+		*resource_base = adev->doorbell.base;
+		return 0;
+	case CGS_RESOURCE_TYPE_FB:
+	case CGS_RESOURCE_TYPE_IO:
+	case CGS_RESOURCE_TYPE_ROM:
+	default:
+		return -EINVAL;
+	}
+}
+
 static const void *amdgpu_cgs_atom_get_data_table(void *cgs_device,
 						  unsigned table, uint16_t *size,
 						  uint8_t *frev, uint8_t *crev)
@@ -674,6 +709,9 @@
 		struct amdgpu_firmware_info *ucode;
 
 		id = fw_type_convert(cgs_device, type);
+		if (id >= AMDGPU_UCODE_ID_MAXIMUM)
+			return -EINVAL;
+
 		ucode = &adev->firmware.ucode[id];
 		if (ucode->fw == NULL)
 			return -EINVAL;
@@ -703,6 +741,9 @@
 		case CHIP_TONGA:
 			strcpy(fw_name, "amdgpu/tonga_smc.bin");
 			break;
+		case CHIP_FIJI:
+			strcpy(fw_name, "amdgpu/fiji_smc.bin");
+			break;
 		default:
 			DRM_ERROR("SMC firmware not supported\n");
 			return -EINVAL;
@@ -736,6 +777,297 @@
 	return 0;
 }
 
+static int amdgpu_cgs_query_system_info(void *cgs_device,
+				struct cgs_system_info *sys_info)
+{
+	CGS_FUNC_ADEV;
+
+	if (NULL == sys_info)
+		return -ENODEV;
+
+	if (sizeof(struct cgs_system_info) != sys_info->size)
+		return -ENODEV;
+
+	switch (sys_info->info_id) {
+	case CGS_SYSTEM_INFO_ADAPTER_BDF_ID:
+		sys_info->value = adev->pdev->devfn | (adev->pdev->bus->number << 8);
+		break;
+	case CGS_SYSTEM_INFO_PCIE_GEN_INFO:
+		sys_info->value = adev->pm.pcie_gen_mask;
+		break;
+	case CGS_SYSTEM_INFO_PCIE_MLW:
+		sys_info->value = adev->pm.pcie_mlw_mask;
+		break;
+	case CGS_SYSTEM_INFO_CG_FLAGS:
+		sys_info->value = adev->cg_flags;
+		break;
+	case CGS_SYSTEM_INFO_PG_FLAGS:
+		sys_info->value = adev->pg_flags;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int amdgpu_cgs_get_active_displays_info(void *cgs_device,
+					  struct cgs_display_info *info)
+{
+	CGS_FUNC_ADEV;
+	struct amdgpu_crtc *amdgpu_crtc;
+	struct drm_device *ddev = adev->ddev;
+	struct drm_crtc *crtc;
+	uint32_t line_time_us, vblank_lines;
+	struct cgs_mode_info *mode_info;
+
+	if (info == NULL)
+		return -EINVAL;
+
+	mode_info = info->mode_info;
+
+	if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
+		list_for_each_entry(crtc,
+				&ddev->mode_config.crtc_list, head) {
+			amdgpu_crtc = to_amdgpu_crtc(crtc);
+			if (crtc->enabled) {
+				info->active_display_mask |= (1 << amdgpu_crtc->crtc_id);
+				info->display_count++;
+			}
+			if (mode_info != NULL &&
+				crtc->enabled && amdgpu_crtc->enabled &&
+				amdgpu_crtc->hw_mode.clock) {
+				line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
+							amdgpu_crtc->hw_mode.clock;
+				vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
+							amdgpu_crtc->hw_mode.crtc_vdisplay +
+							(amdgpu_crtc->v_border * 2);
+				mode_info->vblank_time_us = vblank_lines * line_time_us;
+				mode_info->refresh_rate = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
+				mode_info->ref_clock = adev->clock.spll.reference_freq;
+				mode_info = NULL;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/** \brief evaluate acpi namespace object, handle or pathname must be valid
+ *  \param cgs_device
+ *  \param info input/output arguments for the control method
+ *  \return status
+ */
+
+#if defined(CONFIG_ACPI)
+static int amdgpu_cgs_acpi_eval_object(void *cgs_device,
+				    struct cgs_acpi_method_info *info)
+{
+	CGS_FUNC_ADEV;
+	acpi_handle handle;
+	struct acpi_object_list input;
+	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *params = NULL;
+	union acpi_object *obj = NULL;
+	uint8_t name[5] = {'\0'};
+	struct cgs_acpi_method_argument *argument = NULL;
+	uint32_t i, count;
+	acpi_status status;
+	int result;
+	uint32_t func_no = 0xFFFFFFFF;
+
+	handle = ACPI_HANDLE(&adev->pdev->dev);
+	if (!handle)
+		return -ENODEV;
+
+	memset(&input, 0, sizeof(struct acpi_object_list));
+
+	/* validate input info */
+	if (info->size != sizeof(struct cgs_acpi_method_info))
+		return -EINVAL;
+
+	input.count = info->input_count;
+	if (info->input_count > 0) {
+		if (info->pinput_argument == NULL)
+			return -EINVAL;
+		argument = info->pinput_argument;
+		func_no = argument->value;
+		for (i = 0; i < info->input_count; i++) {
+			if (((argument->type == ACPI_TYPE_STRING) ||
+			     (argument->type == ACPI_TYPE_BUFFER)) &&
+			    (argument->pointer == NULL))
+				return -EINVAL;
+			argument++;
+		}
+	}
+
+	if (info->output_count > 0) {
+		if (info->poutput_argument == NULL)
+			return -EINVAL;
+		argument = info->poutput_argument;
+		for (i = 0; i < info->output_count; i++) {
+			if (((argument->type == ACPI_TYPE_STRING) ||
+				(argument->type == ACPI_TYPE_BUFFER))
+				&& (argument->pointer == NULL))
+				return -EINVAL;
+			argument++;
+		}
+	}
+
+	/* The path name passed to acpi_evaluate_object should be null terminated */
+	if ((info->field & CGS_ACPI_FIELD_METHOD_NAME) != 0) {
+		strncpy(name, (char *)&(info->name), sizeof(uint32_t));
+		name[4] = '\0';
+	}
+
+	/* parse input parameters */
+	if (input.count > 0) {
+		input.pointer = params =
+				kzalloc(sizeof(union acpi_object) * input.count, GFP_KERNEL);
+		if (params == NULL)
+			return -EINVAL;
+
+		argument = info->pinput_argument;
+
+		for (i = 0; i < input.count; i++) {
+			params->type = argument->type;
+			switch (params->type) {
+			case ACPI_TYPE_INTEGER:
+				params->integer.value = argument->value;
+				break;
+			case ACPI_TYPE_STRING:
+				params->string.length = argument->method_length;
+				params->string.pointer = argument->pointer;
+				break;
+			case ACPI_TYPE_BUFFER:
+				params->buffer.length = argument->method_length;
+				params->buffer.pointer = argument->pointer;
+				break;
+			default:
+				break;
+			}
+			params++;
+			argument++;
+		}
+	}
+
+	/* parse output info */
+	count = info->output_count;
+	argument = info->poutput_argument;
+
+	/* evaluate the acpi method */
+	status = acpi_evaluate_object(handle, name, &input, &output);
+
+	if (ACPI_FAILURE(status)) {
+		result = -EIO;
+		goto error;
+	}
+
+	/* return the output info */
+	obj = output.pointer;
+
+	if (count > 1) {
+		if ((obj->type != ACPI_TYPE_PACKAGE) ||
+			(obj->package.count != count)) {
+			result = -EIO;
+			goto error;
+		}
+		params = obj->package.elements;
+	} else
+		params = obj;
+
+	if (params == NULL) {
+		result = -EIO;
+		goto error;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (argument->type != params->type) {
+			result = -EIO;
+			goto error;
+		}
+		switch (params->type) {
+		case ACPI_TYPE_INTEGER:
+			argument->value = params->integer.value;
+			break;
+		case ACPI_TYPE_STRING:
+			if ((params->string.length != argument->data_length) ||
+				(params->string.pointer == NULL)) {
+				result = -EIO;
+				goto error;
+			}
+			strncpy(argument->pointer,
+				params->string.pointer,
+				params->string.length);
+			break;
+		case ACPI_TYPE_BUFFER:
+			if (params->buffer.pointer == NULL) {
+				result = -EIO;
+				goto error;
+			}
+			memcpy(argument->pointer,
+				params->buffer.pointer,
+				argument->data_length);
+			break;
+		default:
+			break;
+		}
+		argument++;
+		params++;
+	}
+
+error:
+	if (obj != NULL)
+		kfree(obj);
+	kfree((void *)input.pointer);
+	return result;
+}
+#else
+static int amdgpu_cgs_acpi_eval_object(void *cgs_device,
+				struct cgs_acpi_method_info *info)
+{
+	return -EIO;
+}
+#endif
+
+int amdgpu_cgs_call_acpi_method(void *cgs_device,
+					uint32_t acpi_method,
+					uint32_t acpi_function,
+					void *pinput, void *poutput,
+					uint32_t output_count,
+					uint32_t input_size,
+					uint32_t output_size)
+{
+	struct cgs_acpi_method_argument acpi_input[2] = { {0}, {0} };
+	struct cgs_acpi_method_argument acpi_output = {0};
+	struct cgs_acpi_method_info info = {0};
+
+	acpi_input[0].type = CGS_ACPI_TYPE_INTEGER;
+	acpi_input[0].method_length = sizeof(uint32_t);
+	acpi_input[0].data_length = sizeof(uint32_t);
+	acpi_input[0].value = acpi_function;
+
+	acpi_input[1].type = CGS_ACPI_TYPE_BUFFER;
+	acpi_input[1].method_length = CGS_ACPI_MAX_BUFFER_SIZE;
+	acpi_input[1].data_length = input_size;
+	acpi_input[1].pointer = pinput;
+
+	acpi_output.type = CGS_ACPI_TYPE_BUFFER;
+	acpi_output.method_length = CGS_ACPI_MAX_BUFFER_SIZE;
+	acpi_output.data_length = output_size;
+	acpi_output.pointer = poutput;
+
+	info.size = sizeof(struct cgs_acpi_method_info);
+	info.field = CGS_ACPI_FIELD_METHOD_NAME | CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT;
+	info.input_count = 2;
+	info.name = acpi_method;
+	info.pinput_argument = acpi_input;
+	info.output_count = output_count;
+	info.poutput_argument = &acpi_output;
+
+	return amdgpu_cgs_acpi_eval_object(cgs_device, &info);
+}
+
 static const struct cgs_ops amdgpu_cgs_ops = {
 	amdgpu_cgs_gpu_mem_info,
 	amdgpu_cgs_gmap_kmem,
@@ -756,6 +1088,7 @@
 	amdgpu_cgs_write_pci_config_byte,
 	amdgpu_cgs_write_pci_config_word,
 	amdgpu_cgs_write_pci_config_dword,
+	amdgpu_cgs_get_pci_resource,
 	amdgpu_cgs_atom_get_data_table,
 	amdgpu_cgs_atom_get_cmd_table_revs,
 	amdgpu_cgs_atom_exec_cmd_table,
@@ -768,7 +1101,10 @@
 	amdgpu_cgs_set_camera_voltages,
 	amdgpu_cgs_get_firmware_info,
 	amdgpu_cgs_set_powergating_state,
-	amdgpu_cgs_set_clockgating_state
+	amdgpu_cgs_set_clockgating_state,
+	amdgpu_cgs_get_active_displays_info,
+	amdgpu_cgs_call_acpi_method,
+	amdgpu_cgs_query_system_info,
 };
 
 static const struct cgs_os_ops amdgpu_cgs_os_ops = {
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -69,25 +69,18 @@
 		/* don't do anything if sink is not display port, i.e.,
 		 * passive dp->(dvi|hdmi) adaptor
 		 */
-		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-			int saved_dpms = connector->dpms;
-			/* Only turn off the display if it's physically disconnected */
-			if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
-				drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
-			} else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
-				/* Don't try to start link training before we
-				 * have the dpcd */
-				if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
-					return;
+		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
+		    amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd) &&
+		    amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
+			/* Don't start link training before we have the DPCD */
+			if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
+				return;
 
-				/* set it to OFF so that drm_helper_connector_dpms()
-				 * won't return immediately since the current state
-				 * is ON at this point.
-				 */
-				connector->dpms = DRM_MODE_DPMS_OFF;
-				drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-			}
-			connector->dpms = saved_dpms;
+			/* Turn the connector off and back on immediately, which
+			 * will trigger link training
+			 */
+			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
 		}
 	}
 }
@@ -194,12 +187,12 @@
 				bpc = 8;
 				DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n",
 					  connector->name, bpc);
-			} else if (bpc > 8) {
-				/* max_tmds_clock missing, but hdmi spec mandates it for deep color. */
-				DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n",
-					  connector->name);
-				bpc = 8;
 			}
+		} else if (bpc > 8) {
+			/* max_tmds_clock missing, but hdmi spec mandates it for deep color. */
+			DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n",
+				  connector->name);
+			bpc = 8;
 		}
 	}
 
@@ -739,9 +732,13 @@
 	enum drm_connector_status ret = connector_status_disconnected;
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	if (encoder) {
 		struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
@@ -760,8 +757,12 @@
 	/* check acpi lid status ??? */
 
 	amdgpu_connector_update_scratch_regs(connector, ret);
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
+
 	return ret;
 }
 
@@ -862,9 +863,13 @@
 	enum drm_connector_status ret = connector_status_disconnected;
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	encoder = amdgpu_connector_best_single_encoder(connector);
 	if (!encoder)
@@ -918,8 +923,10 @@
 	amdgpu_connector_update_scratch_regs(connector, ret);
 
 out:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -981,9 +988,13 @@
 	enum drm_connector_status ret = connector_status_disconnected;
 	bool dret = false, broken_edid = false;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
 		ret = connector->status;
@@ -1108,8 +1119,10 @@
 	amdgpu_connector_update_scratch_regs(connector, ret);
 
 exit:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -1351,9 +1364,13 @@
 	struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
 		ret = connector->status;
@@ -1421,8 +1438,10 @@
 
 	amdgpu_connector_update_scratch_regs(connector, ret);
 out:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -1690,7 +1709,6 @@
 						   DRM_MODE_SCALE_NONE);
 			/* no HPD on analog connectors */
 			amdgpu_connector->hpd.hpd = AMDGPU_HPD_NONE;
-			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 			connector->interlace_allowed = true;
 			connector->doublescan_allowed = true;
 			break;
@@ -1893,8 +1911,10 @@
 	}
 
 	if (amdgpu_connector->hpd.hpd == AMDGPU_HPD_NONE) {
-		if (i2c_bus->valid)
-			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+		if (i2c_bus->valid) {
+			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+			                    DRM_CONNECTOR_POLL_DISCONNECT;
+		}
 	} else
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -124,6 +124,13 @@
 		}
 		break;
 	}
+
+	if (!(*out_ring && (*out_ring)->adev)) {
+		DRM_ERROR("Ring %d is not initialized on IP %d\n",
+			  ring, ip_type);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -406,8 +413,8 @@
 		amdgpu_cs_buckets_get_list(&buckets, &p->validated);
 	}
 
-	p->vm_bos = amdgpu_vm_get_bos(p->adev, &fpriv->vm,
-				      &p->validated);
+	INIT_LIST_HEAD(&duplicates);
+	amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd);
 
 	if (p->uf.bo)
 		list_add(&p->uf_entry.tv.head, &p->validated);
@@ -415,20 +422,23 @@
 	if (need_mmap_lock)
 		down_read(&current->mm->mmap_sem);
 
-	INIT_LIST_HEAD(&duplicates);
 	r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, &duplicates);
 	if (unlikely(r != 0))
 		goto error_reserve;
 
-	r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &p->validated);
+	amdgpu_vm_get_pt_bos(&fpriv->vm, &duplicates);
+
+	r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &duplicates);
 	if (r)
 		goto error_validate;
 
-	r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &duplicates);
+	r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &p->validated);
 
 error_validate:
-	if (r)
+	if (r) {
+		amdgpu_vm_move_pt_bos_in_lru(p->adev, &fpriv->vm);
 		ttm_eu_backoff_reservation(&p->ticket, &p->validated);
+	}
 
 error_reserve:
 	if (need_mmap_lock)
@@ -472,9 +482,12 @@
  **/
 static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
 {
+	struct amdgpu_fpriv *fpriv = parser->filp->driver_priv;
 	unsigned i;
 
 	if (!error) {
+		amdgpu_vm_move_pt_bos_in_lru(parser->adev, &fpriv->vm);
+
 		/* Sort the buffer list from the smallest to largest buffer,
 		 * which affects the order of buffers in the LRU list.
 		 * This assures that the smallest buffers are added first
@@ -501,7 +514,6 @@
 	if (parser->bo_list)
 		amdgpu_bo_list_put(parser->bo_list);
 
-	drm_free_large(parser->vm_bos);
 	for (i = 0; i < parser->nchunks; i++)
 		drm_free_large(parser->chunks[i].kdata);
 	kfree(parser->chunks);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -25,7 +25,7 @@
 #include <drm/drmP.h>
 #include "amdgpu.h"
 
-int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
+int amdgpu_ctx_init(struct amdgpu_device *adev, enum amd_sched_priority pri,
 		    struct amdgpu_ctx *ctx)
 {
 	unsigned i, j;
@@ -35,17 +35,25 @@
 	ctx->adev = adev;
 	kref_init(&ctx->refcount);
 	spin_lock_init(&ctx->ring_lock);
-	for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
-		ctx->rings[i].sequence = 1;
+	ctx->fences = kzalloc(sizeof(struct fence *) * amdgpu_sched_jobs *
+			 AMDGPU_MAX_RINGS, GFP_KERNEL);
+	if (!ctx->fences)
+		return -ENOMEM;
 
+	for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+		ctx->rings[i].sequence = 1;
+		ctx->rings[i].fences = (void *)ctx->fences + sizeof(struct fence *) *
+			amdgpu_sched_jobs * i;
+	}
 	if (amdgpu_enable_scheduler) {
 		/* create context entity for each ring */
 		for (i = 0; i < adev->num_rings; i++) {
 			struct amd_sched_rq *rq;
-			if (kernel)
-				rq = &adev->rings[i]->sched.kernel_rq;
-			else
-				rq = &adev->rings[i]->sched.sched_rq;
+			if (pri >= AMD_SCHED_MAX_PRIORITY) {
+				kfree(ctx->fences);
+				return -EINVAL;
+			}
+			rq = &adev->rings[i]->sched.sched_rq[pri];
 			r = amd_sched_entity_init(&adev->rings[i]->sched,
 						  &ctx->rings[i].entity,
 						  rq, amdgpu_sched_jobs);
@@ -57,7 +65,7 @@
 			for (j = 0; j < i; j++)
 				amd_sched_entity_fini(&adev->rings[j]->sched,
 						      &ctx->rings[j].entity);
-			kfree(ctx);
+			kfree(ctx->fences);
 			return r;
 		}
 	}
@@ -73,8 +81,9 @@
 		return;
 
 	for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
-		for (j = 0; j < AMDGPU_CTX_MAX_CS_PENDING; ++j)
+		for (j = 0; j < amdgpu_sched_jobs; ++j)
 			fence_put(ctx->rings[i].fences[j]);
+	kfree(ctx->fences);
 
 	if (amdgpu_enable_scheduler) {
 		for (i = 0; i < adev->num_rings; i++)
@@ -103,9 +112,13 @@
 		return r;
 	}
 	*id = (uint32_t)r;
-	r = amdgpu_ctx_init(adev, false, ctx);
+	r = amdgpu_ctx_init(adev, AMD_SCHED_PRIORITY_NORMAL, ctx);
+	if (r) {
+		idr_remove(&mgr->ctx_handles, *id);
+		*id = 0;
+		kfree(ctx);
+	}
 	mutex_unlock(&mgr->lock);
-
 	return r;
 }
 
@@ -239,7 +252,7 @@
 	unsigned idx = 0;
 	struct fence *other = NULL;
 
-	idx = seq % AMDGPU_CTX_MAX_CS_PENDING;
+	idx = seq & (amdgpu_sched_jobs - 1);
 	other = cring->fences[idx];
 	if (other) {
 		signed long r;
@@ -274,12 +287,12 @@
 	}
 
 
-	if (seq + AMDGPU_CTX_MAX_CS_PENDING < cring->sequence) {
+	if (seq + amdgpu_sched_jobs < cring->sequence) {
 		spin_unlock(&ctx->ring_lock);
 		return NULL;
 	}
 
-	fence = fence_get(cring->fences[seq % AMDGPU_CTX_MAX_CS_PENDING]);
+	fence = fence_get(cring->fences[seq & (amdgpu_sched_jobs - 1)]);
 	spin_unlock(&ctx->ring_lock);
 
 	return fence;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -38,6 +38,7 @@
 #include "amdgpu_i2c.h"
 #include "atom.h"
 #include "amdgpu_atombios.h"
+#include "amd_pcie.h"
 #ifdef CONFIG_DRM_AMDGPU_CIK
 #include "cik.h"
 #endif
@@ -949,6 +950,15 @@
  */
 static void amdgpu_check_arguments(struct amdgpu_device *adev)
 {
+	if (amdgpu_sched_jobs < 4) {
+		dev_warn(adev->dev, "sched jobs (%d) must be at least 4\n",
+			 amdgpu_sched_jobs);
+		amdgpu_sched_jobs = 4;
+	} else if (!amdgpu_check_pot_argument(amdgpu_sched_jobs)){
+		dev_warn(adev->dev, "sched jobs (%d) must be a power of 2\n",
+			 amdgpu_sched_jobs);
+		amdgpu_sched_jobs = roundup_pow_of_two(amdgpu_sched_jobs);
+	}
 	/* vramlimit must be a power of two */
 	if (!amdgpu_check_pot_argument(amdgpu_vram_limit)) {
 		dev_warn(adev->dev, "vram limit (%d) must be a power of 2\n",
@@ -1214,12 +1224,14 @@
 		} else {
 			if (adev->ip_blocks[i].funcs->early_init) {
 				r = adev->ip_blocks[i].funcs->early_init((void *)adev);
-				if (r == -ENOENT)
+				if (r == -ENOENT) {
 					adev->ip_block_status[i].valid = false;
-				else if (r)
+				} else if (r) {
+					DRM_ERROR("early_init %d failed %d\n", i, r);
 					return r;
-				else
+				} else {
 					adev->ip_block_status[i].valid = true;
+				}
 			} else {
 				adev->ip_block_status[i].valid = true;
 			}
@@ -1237,20 +1249,28 @@
 		if (!adev->ip_block_status[i].valid)
 			continue;
 		r = adev->ip_blocks[i].funcs->sw_init((void *)adev);
-		if (r)
+		if (r) {
+			DRM_ERROR("sw_init %d failed %d\n", i, r);
 			return r;
+		}
 		adev->ip_block_status[i].sw = true;
 		/* need to do gmc hw init early so we can allocate gpu mem */
 		if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
 			r = amdgpu_vram_scratch_init(adev);
-			if (r)
+			if (r) {
+				DRM_ERROR("amdgpu_vram_scratch_init failed %d\n", r);
 				return r;
+			}
 			r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
-			if (r)
+			if (r) {
+				DRM_ERROR("hw_init %d failed %d\n", i, r);
 				return r;
+			}
 			r = amdgpu_wb_init(adev);
-			if (r)
+			if (r) {
+				DRM_ERROR("amdgpu_wb_init failed %d\n", r);
 				return r;
+			}
 			adev->ip_block_status[i].hw = true;
 		}
 	}
@@ -1262,8 +1282,10 @@
 		if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC)
 			continue;
 		r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
-		if (r)
+		if (r) {
+			DRM_ERROR("hw_init %d failed %d\n", i, r);
 			return r;
+		}
 		adev->ip_block_status[i].hw = true;
 	}
 
@@ -1280,12 +1302,16 @@
 		/* enable clockgating to save power */
 		r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
 								    AMD_CG_STATE_GATE);
-		if (r)
+		if (r) {
+			DRM_ERROR("set_clockgating_state(gate) %d failed %d\n", i, r);
 			return r;
+		}
 		if (adev->ip_blocks[i].funcs->late_init) {
 			r = adev->ip_blocks[i].funcs->late_init((void *)adev);
-			if (r)
+			if (r) {
+				DRM_ERROR("late_init %d failed %d\n", i, r);
 				return r;
+			}
 		}
 	}
 
@@ -1306,10 +1332,15 @@
 		/* ungate blocks before hw fini so that we can shutdown the blocks safely */
 		r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
 								    AMD_CG_STATE_UNGATE);
-		if (r)
+		if (r) {
+			DRM_ERROR("set_clockgating_state(ungate) %d failed %d\n", i, r);
 			return r;
+		}
 		r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
 		/* XXX handle errors */
+		if (r) {
+			DRM_DEBUG("hw_fini %d failed %d\n", i, r);
+		}
 		adev->ip_block_status[i].hw = false;
 	}
 
@@ -1318,6 +1349,9 @@
 			continue;
 		r = adev->ip_blocks[i].funcs->sw_fini((void *)adev);
 		/* XXX handle errors */
+		if (r) {
+			DRM_DEBUG("sw_fini %d failed %d\n", i, r);
+		}
 		adev->ip_block_status[i].sw = false;
 		adev->ip_block_status[i].valid = false;
 	}
@@ -1335,9 +1369,15 @@
 		/* ungate blocks so that suspend can properly shut them down */
 		r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
 								    AMD_CG_STATE_UNGATE);
+		if (r) {
+			DRM_ERROR("set_clockgating_state(ungate) %d failed %d\n", i, r);
+		}
 		/* XXX handle errors */
 		r = adev->ip_blocks[i].funcs->suspend(adev);
 		/* XXX handle errors */
+		if (r) {
+			DRM_ERROR("suspend %d failed %d\n", i, r);
+		}
 	}
 
 	return 0;
@@ -1351,8 +1391,10 @@
 		if (!adev->ip_block_status[i].valid)
 			continue;
 		r = adev->ip_blocks[i].funcs->resume(adev);
-		if (r)
+		if (r) {
+			DRM_ERROR("resume %d failed %d\n", i, r);
 			return r;
+		}
 	}
 
 	return 0;
@@ -1467,8 +1509,6 @@
 	 * ignore it */
 	vga_client_register(adev->pdev, adev, NULL, amdgpu_vga_set_decode);
 
-	if (amdgpu_runtime_pm == 1)
-		runtime = true;
 	if (amdgpu_device_is_px(ddev))
 		runtime = true;
 	vga_switcheroo_register_client(adev->pdev, &amdgpu_switcheroo_ops, runtime);
@@ -1484,8 +1524,10 @@
 		return -EINVAL;
 	}
 	r = amdgpu_atombios_init(adev);
-	if (r)
+	if (r) {
+		dev_err(adev->dev, "amdgpu_atombios_init failed\n");
 		return r;
+	}
 
 	/* Post card if necessary */
 	if (!amdgpu_card_posted(adev)) {
@@ -1499,21 +1541,26 @@
 
 	/* Initialize clocks */
 	r = amdgpu_atombios_get_clock_info(adev);
-	if (r)
+	if (r) {
+		dev_err(adev->dev, "amdgpu_atombios_get_clock_info failed\n");
 		return r;
+	}
 	/* init i2c buses */
 	amdgpu_atombios_i2c_init(adev);
 
 	/* Fence driver */
 	r = amdgpu_fence_driver_init(adev);
-	if (r)
+	if (r) {
+		dev_err(adev->dev, "amdgpu_fence_driver_init failed\n");
 		return r;
+	}
 
 	/* init the mode config */
 	drm_mode_config_init(adev->ddev);
 
 	r = amdgpu_init(adev);
 	if (r) {
+		dev_err(adev->dev, "amdgpu_init failed\n");
 		amdgpu_fini(adev);
 		return r;
 	}
@@ -1528,7 +1575,7 @@
 		return r;
 	}
 
-	r = amdgpu_ctx_init(adev, true, &adev->kernel_ctx);
+	r = amdgpu_ctx_init(adev, AMD_SCHED_PRIORITY_KERNEL, &adev->kernel_ctx);
 	if (r) {
 		dev_err(adev->dev, "failed to create kernel context (%d).\n", r);
 		return r;
@@ -1570,8 +1617,10 @@
 	 * explicit gating rather than handling it automatically.
 	 */
 	r = amdgpu_late_init(adev);
-	if (r)
+	if (r) {
+		dev_err(adev->dev, "amdgpu_late_init failed\n");
 		return r;
+	}
 
 	return 0;
 }
@@ -1744,19 +1793,27 @@
 	}
 
 	/* post card */
-	amdgpu_atom_asic_init(adev->mode_info.atom_context);
+	if (!amdgpu_card_posted(adev))
+		amdgpu_atom_asic_init(adev->mode_info.atom_context);
 
 	r = amdgpu_resume(adev);
+	if (r)
+		DRM_ERROR("amdgpu_resume failed (%d).\n", r);
 
 	amdgpu_fence_driver_resume(adev);
 
-	r = amdgpu_ib_ring_tests(adev);
-	if (r)
-		DRM_ERROR("ib ring test failed (%d).\n", r);
+	if (resume) {
+		r = amdgpu_ib_ring_tests(adev);
+		if (r)
+			DRM_ERROR("ib ring test failed (%d).\n", r);
+	}
 
 	r = amdgpu_late_init(adev);
-	if (r)
+	if (r) {
+		if (fbcon)
+			console_unlock();
 		return r;
+	}
 
 	/* pin cursors */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -1789,6 +1846,23 @@
 
 	drm_kms_helper_poll_enable(dev);
 
+	/*
+	 * Most of the connector probing functions try to acquire runtime pm
+	 * refs to ensure that the GPU is powered on when connector polling is
+	 * performed. Since we're calling this from a runtime PM callback,
+	 * trying to acquire rpm refs will cause us to deadlock.
+	 *
+	 * Since we're guaranteed to be holding the rpm lock, it's safe to
+	 * temporarily disable the rpm helpers so this doesn't deadlock us.
+	 */
+#ifdef CONFIG_PM
+	dev->dev->power.disable_depth++;
+#endif
+	drm_helper_hpd_irq_event(dev);
+#ifdef CONFIG_PM
+	dev->dev->power.disable_depth--;
+#endif
+
 	if (fbcon) {
 		amdgpu_fbdev_set_suspend(adev, 0);
 		console_unlock();
@@ -1881,6 +1955,100 @@
 	return r;
 }
 
+#define AMDGPU_DEFAULT_PCIE_GEN_MASK 0x30007  /* gen: chipset 1/2, asic 1/2/3 */
+#define AMDGPU_DEFAULT_PCIE_MLW_MASK 0x2f0000 /* 1/2/4/8/16 lanes */
+
+void amdgpu_get_pcie_info(struct amdgpu_device *adev)
+{
+	u32 mask;
+	int ret;
+
+	if (amdgpu_pcie_gen_cap)
+		adev->pm.pcie_gen_mask = amdgpu_pcie_gen_cap;
+
+	if (amdgpu_pcie_lane_cap)
+		adev->pm.pcie_mlw_mask = amdgpu_pcie_lane_cap;
+
+	/* covers APUs as well */
+	if (pci_is_root_bus(adev->pdev->bus)) {
+		if (adev->pm.pcie_gen_mask == 0)
+			adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK;
+		if (adev->pm.pcie_mlw_mask == 0)
+			adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK;
+		return;
+	}
+
+	if (adev->pm.pcie_gen_mask == 0) {
+		ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
+		if (!ret) {
+			adev->pm.pcie_gen_mask = (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
+						  CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
+						  CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3);
+
+			if (mask & DRM_PCIE_SPEED_25)
+				adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1;
+			if (mask & DRM_PCIE_SPEED_50)
+				adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2;
+			if (mask & DRM_PCIE_SPEED_80)
+				adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3;
+		} else {
+			adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK;
+		}
+	}
+	if (adev->pm.pcie_mlw_mask == 0) {
+		ret = drm_pcie_get_max_link_width(adev->ddev, &mask);
+		if (!ret) {
+			switch (mask) {
+			case 32:
+				adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+				break;
+			case 16:
+				adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+				break;
+			case 12:
+				adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+				break;
+			case 8:
+				adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+				break;
+			case 4:
+				adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+				break;
+			case 2:
+				adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+							  CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+				break;
+			case 1:
+				adev->pm.pcie_mlw_mask = CAIL_PCIE_LINK_WIDTH_SUPPORT_X1;
+				break;
+			default:
+				break;
+			}
+		} else {
+			adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK;
+		}
+	}
+}
 
 /*
  * Debugfs
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -72,8 +72,8 @@
 
 	struct drm_crtc *crtc = &amdgpuCrtc->base;
 	unsigned long flags;
-	unsigned i;
-	int vpos, hpos, stat, min_udelay;
+	unsigned i, repcnt = 4;
+	int vpos, hpos, stat, min_udelay = 0;
 	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
 
 	amdgpu_flip_wait_fence(adev, &work->excl);
@@ -96,7 +96,7 @@
 	 * In practice this won't execute very often unless on very fast
 	 * machines because the time window for this to happen is very small.
 	 */
-	for (;;) {
+	while (amdgpuCrtc->enabled && --repcnt) {
 		/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
 		 * start in hpos, and to the "fudged earlier" vblank start in
 		 * vpos.
@@ -112,12 +112,24 @@
 			break;
 
 		/* Sleep at least until estimated real start of hw vblank */
-		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 		min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+		if (min_udelay > vblank->framedur_ns / 2000) {
+			/* Don't wait ridiculously long - something is wrong */
+			repcnt = 0;
+			break;
+		}
+		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 		usleep_range(min_udelay, 2 * min_udelay);
 		spin_lock_irqsave(&crtc->dev->event_lock, flags);
 	};
 
+	if (!repcnt)
+		DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
+				 "framedur %d, linedur %d, stat %d, vpos %d, "
+				 "hpos %d\n", work->crtc_id, min_udelay,
+				 vblank->framedur_ns / 1000,
+				 vblank->linedur_ns / 1000, stat, vpos, hpos);
+
 	/* do the flip (mmio) */
 	adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
 	/* set the flip status */
@@ -284,7 +296,7 @@
 
 	ret = pm_runtime_get_sync(dev->dev);
 	if (ret < 0)
-		return ret;
+		goto out;
 
 	ret = drm_crtc_helper_set_config(set);
 
@@ -308,6 +320,7 @@
 		adev->have_disp_power_ref = false;
 	}
 
+out:
 	/* drop the power reference we got coming in here */
 	pm_runtime_put_autosuspend(dev->dev);
 	return ret;
@@ -548,6 +561,12 @@
 		return ERR_PTR(-ENOENT);
 	}
 
+	/* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */
+	if (obj->import_attach) {
+		DRM_DEBUG_KMS("Cannot create framebuffer from imported dma_buf\n");
+		return ERR_PTR(-EINVAL);
+	}
+
 	amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL);
 	if (amdgpu_fb == NULL) {
 		drm_gem_object_unreference_unlocked(obj);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c
@@ -113,24 +113,26 @@
 	printk("\n");
 }
 
+
 u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev)
 {
 	struct drm_device *dev = adev->ddev;
 	struct drm_crtc *crtc;
 	struct amdgpu_crtc *amdgpu_crtc;
-	u32 line_time_us, vblank_lines;
+	u32 vblank_in_pixels;
 	u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
 
 	if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 			amdgpu_crtc = to_amdgpu_crtc(crtc);
 			if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) {
-				line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
-					amdgpu_crtc->hw_mode.clock;
-				vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
+				vblank_in_pixels =
+					amdgpu_crtc->hw_mode.crtc_htotal *
+					(amdgpu_crtc->hw_mode.crtc_vblank_end -
 					amdgpu_crtc->hw_mode.crtc_vdisplay +
-					(amdgpu_crtc->v_border * 2);
-				vblank_time_us = vblank_lines * line_time_us;
+					(amdgpu_crtc->v_border * 2));
+
+				vblank_time_us = vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock;
 				break;
 			}
 		}
@@ -150,7 +152,7 @@
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 			amdgpu_crtc = to_amdgpu_crtc(crtc);
 			if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) {
-				vrefresh = amdgpu_crtc->hw_mode.vrefresh;
+				vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
 				break;
 			}
 		}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -79,9 +79,12 @@
 int amdgpu_vm_debug = 0;
 int amdgpu_exp_hw_support = 0;
 int amdgpu_enable_scheduler = 1;
-int amdgpu_sched_jobs = 16;
+int amdgpu_sched_jobs = 32;
 int amdgpu_sched_hw_submission = 2;
 int amdgpu_enable_semaphores = 0;
+int amdgpu_powerplay = -1;
+unsigned amdgpu_pcie_gen_cap = 0;
+unsigned amdgpu_pcie_lane_cap = 0;
 
 MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");
 module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
@@ -155,7 +158,7 @@
 MODULE_PARM_DESC(enable_scheduler, "enable SW GPU scheduler (1 = enable (default), 0 = disable)");
 module_param_named(enable_scheduler, amdgpu_enable_scheduler, int, 0444);
 
-MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 16)");
+MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 32)");
 module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444);
 
 MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default 2)");
@@ -164,6 +167,17 @@
 MODULE_PARM_DESC(enable_semaphores, "Enable semaphores (1 = enable, 0 = disable (default))");
 module_param_named(enable_semaphores, amdgpu_enable_semaphores, int, 0644);
 
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+MODULE_PARM_DESC(powerplay, "Powerplay component (1 = enable, 0 = disable, -1 = auto (default))");
+module_param_named(powerplay, amdgpu_powerplay, int, 0444);
+#endif
+
+MODULE_PARM_DESC(pcie_gen_cap, "PCIE Gen Caps (0: autodetect (default))");
+module_param_named(pcie_gen_cap, amdgpu_pcie_gen_cap, uint, 0444);
+
+MODULE_PARM_DESC(pcie_lane_cap, "PCIE Lane Caps (0: autodetect (default))");
+module_param_named(pcie_lane_cap, amdgpu_pcie_lane_cap, uint, 0444);
+
 static struct pci_device_id pciidlist[] = {
 #ifdef CONFIG_DRM_AMDGPU_CIK
 	/* Kaveri */
@@ -250,11 +264,11 @@
 	{0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
 #endif
 	/* topaz */
-	{0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
-	{0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
-	{0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
-	{0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
-	{0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
+	{0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+	{0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+	{0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+	{0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+	{0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
 	/* tonga */
 	{0x1002, 0x6920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
 	{0x1002, 0x6921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
@@ -443,11 +457,12 @@
 	dev = file_priv->minor->dev;
 	ret = pm_runtime_get_sync(dev->dev);
 	if (ret < 0)
-		return ret;
+		goto out;
 
 	ret = drm_ioctl(filp, cmd, arg);
 
 	pm_runtime_mark_last_busy(dev->dev);
+out:
 	pm_runtime_put_autosuspend(dev->dev);
 	return ret;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
@@ -264,7 +264,7 @@
 
 	}
 	if (fb && ret) {
-		drm_gem_object_unreference(gobj);
+		drm_gem_object_unreference_unlocked(gobj);
 		drm_framebuffer_unregister_private(fb);
 		drm_framebuffer_cleanup(fb);
 		kfree(fb);
@@ -334,6 +334,10 @@
 	if (!adev->mode_info.mode_config_initialized)
 		return 0;
 
+	/* don't init fbdev if there are no connectors */
+	if (list_empty(&adev->ddev->mode_config.connector_list))
+		return 0;
+
 	/* select 8 bpp console on low vram cards */
 	if (adev->mc.real_vram_size <= (32*1024*1024))
 		bpp_sel = 8;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
@@ -221,7 +221,7 @@
  * Unbinds the requested pages from the gart page table and
  * replaces them with the dummy page (all asics).
  */
-void amdgpu_gart_unbind(struct amdgpu_device *adev, unsigned offset,
+void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
 			int pages)
 {
 	unsigned t;
@@ -269,7 +269,7 @@
  * (all asics).
  * Returns 0 for success, -EINVAL for failure.
  */
-int amdgpu_gart_bind(struct amdgpu_device *adev, unsigned offset,
+int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
 		     int pages, struct page **pagelist, dma_addr_t *dma_addr,
 		     uint32_t flags)
 {
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -448,7 +448,7 @@
 				    struct amdgpu_bo_va *bo_va, uint32_t operation)
 {
 	struct ttm_validate_buffer tv, *entry;
-	struct amdgpu_bo_list_entry *vm_bos;
+	struct amdgpu_bo_list_entry vm_pd;
 	struct ww_acquire_ctx ticket;
 	struct list_head list, duplicates;
 	unsigned domain;
@@ -461,15 +461,14 @@
 	tv.shared = true;
 	list_add(&tv.head, &list);
 
-	vm_bos = amdgpu_vm_get_bos(adev, bo_va->vm, &list);
-	if (!vm_bos)
-		return;
+	amdgpu_vm_get_pd_bo(bo_va->vm, &list, &vm_pd);
 
 	/* Provide duplicates to avoid -EALREADY */
 	r = ttm_eu_reserve_buffers(&ticket, &list, true, &duplicates);
 	if (r)
-		goto error_free;
+		goto error_print;
 
+	amdgpu_vm_get_pt_bos(bo_va->vm, &duplicates);
 	list_for_each_entry(entry, &list, head) {
 		domain = amdgpu_mem_type_to_domain(entry->bo->mem.mem_type);
 		/* if anything is swapped out don't swap it in here,
@@ -499,9 +498,7 @@
 error_unreserve:
 	ttm_eu_backoff_reservation(&ticket, &list);
 
-error_free:
-	drm_free_large(vm_bos);
-
+error_print:
 	if (r && r != -ERESTARTSYS)
 		DRM_ERROR("Couldn't update BO_VA (%d)\n", r);
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -288,7 +288,7 @@
 int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
 {
 	unsigned i;
-	int r;
+	int r, ret = 0;
 
 	for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
 		struct amdgpu_ring *ring = adev->rings[i];
@@ -309,10 +309,11 @@
 			} else {
 				/* still not good, but we can live with it */
 				DRM_ERROR("amdgpu: failed testing IB on ring %d (%d).\n", i, r);
+				ret = r;
 			}
 		}
 	}
-	return 0;
+	return ret;
 }
 
 /*
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -25,6 +25,7 @@
  *          Alex Deucher
  *          Jerome Glisse
  */
+#include <linux/irq.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/amdgpu_drm.h>
@@ -312,6 +313,7 @@
 	}
 
 	adev->irq.sources[src_id] = source;
+
 	return 0;
 }
 
@@ -335,15 +337,19 @@
 		return;
 	}
 
-	src = adev->irq.sources[src_id];
-	if (!src) {
-		DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
-		return;
-	}
+	if (adev->irq.virq[src_id]) {
+		generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
+	} else {
+		src = adev->irq.sources[src_id];
+		if (!src) {
+			DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
+			return;
+		}
 
-	r = src->funcs->process(adev, src, entry);
-	if (r)
-		DRM_ERROR("error processing interrupt (%d)\n", r);
+		r = src->funcs->process(adev, src, entry);
+		if (r)
+			DRM_ERROR("error processing interrupt (%d)\n", r);
+	}
 }
 
 /**
@@ -461,3 +467,90 @@
 
 	return !!atomic_read(&src->enabled_types[type]);
 }
+
+/* gen irq */
+static void amdgpu_irq_mask(struct irq_data *irqd)
+{
+	/* XXX */
+}
+
+static void amdgpu_irq_unmask(struct irq_data *irqd)
+{
+	/* XXX */
+}
+
+static struct irq_chip amdgpu_irq_chip = {
+	.name = "amdgpu-ih",
+	.irq_mask = amdgpu_irq_mask,
+	.irq_unmask = amdgpu_irq_unmask,
+};
+
+static int amdgpu_irqdomain_map(struct irq_domain *d,
+				unsigned int irq, irq_hw_number_t hwirq)
+{
+	if (hwirq >= AMDGPU_MAX_IRQ_SRC_ID)
+		return -EPERM;
+
+	irq_set_chip_and_handler(irq,
+				 &amdgpu_irq_chip, handle_simple_irq);
+	return 0;
+}
+
+static struct irq_domain_ops amdgpu_hw_irqdomain_ops = {
+	.map = amdgpu_irqdomain_map,
+};
+
+/**
+ * amdgpu_irq_add_domain - create a linear irq domain
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Create an irq domain for GPU interrupt sources
+ * that may be driven by another driver (e.g., ACP).
+ */
+int amdgpu_irq_add_domain(struct amdgpu_device *adev)
+{
+	adev->irq.domain = irq_domain_add_linear(NULL, AMDGPU_MAX_IRQ_SRC_ID,
+						 &amdgpu_hw_irqdomain_ops, adev);
+	if (!adev->irq.domain) {
+		DRM_ERROR("GPU irq add domain failed\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * amdgpu_irq_remove_domain - remove the irq domain
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Remove the irq domain for GPU interrupt sources
+ * that may be driven by another driver (e.g., ACP).
+ */
+void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
+{
+	if (adev->irq.domain) {
+		irq_domain_remove(adev->irq.domain);
+		adev->irq.domain = NULL;
+	}
+}
+
+/**
+ * amdgpu_irq_create_mapping - create a mapping between a domain irq and a
+ *                             Linux irq
+ *
+ * @adev: amdgpu device pointer
+ * @src_id: IH source id
+ *
+ * Create a mapping between a domain irq (GPU IH src id) and a Linux irq
+ * Use this for components that generate a GPU interrupt, but are driven
+ * by a different driver (e.g., ACP).
+ * Returns the Linux irq.
+ */
+unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id)
+{
+	adev->irq.virq[src_id] = irq_create_mapping(adev->irq.domain, src_id);
+
+	return adev->irq.virq[src_id];
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
@@ -24,6 +24,7 @@
 #ifndef __AMDGPU_IRQ_H__
 #define __AMDGPU_IRQ_H__
 
+#include <linux/irqdomain.h>
 #include "amdgpu_ih.h"
 
 #define AMDGPU_MAX_IRQ_SRC_ID	0x100
@@ -65,6 +66,10 @@
 	/* interrupt ring */
 	struct amdgpu_ih_ring		ih;
 	const struct amdgpu_ih_funcs	*ih_funcs;
+
+	/* gen irq stuff */
+	struct irq_domain		*domain; /* GPU irq controller domain */
+	unsigned			virq[AMDGPU_MAX_IRQ_SRC_ID];
 };
 
 void amdgpu_irq_preinstall(struct drm_device *dev);
@@ -90,4 +95,8 @@
 bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
 			unsigned type);
 
+int amdgpu_irq_add_domain(struct amdgpu_device *adev);
+void amdgpu_irq_remove_domain(struct amdgpu_device *adev);
+unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id);
+
 #endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -227,7 +227,7 @@
 			type = AMD_IP_BLOCK_TYPE_UVD;
 			ring_mask = adev->uvd.ring.ready ? 1 : 0;
 			ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
-			ib_size_alignment = 8;
+			ib_size_alignment = 16;
 			break;
 		case AMDGPU_HW_IP_VCE:
 			type = AMD_IP_BLOCK_TYPE_VCE;
@@ -303,7 +303,7 @@
 			fw_info.feature = adev->vce.fb_version;
 			break;
 		case AMDGPU_INFO_FW_UVD:
-			fw_info.ver = 0;
+			fw_info.ver = adev->uvd.fw_version;
 			fw_info.feature = 0;
 			break;
 		case AMDGPU_INFO_FW_GMC:
@@ -406,6 +406,9 @@
 		if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
 			sh_num = 0xffffffff;
 
+		if (info->read_mmr_reg.count > 128)
+			return -EINVAL;
+
 		regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL);
 		if (!regs)
 			return -ENOMEM;
@@ -425,9 +428,10 @@
 		return n ? -EFAULT : 0;
 	}
 	case AMDGPU_INFO_DEV_INFO: {
-		struct drm_amdgpu_info_device dev_info = {};
+		struct drm_amdgpu_info_device dev_info;
 		struct amdgpu_cu_info cu_info;
 
+		memset(&dev_info, 0, sizeof(dev_info));
 		dev_info.device_id = dev->pdev->device;
 		dev_info.chip_rev = adev->rev_id;
 		dev_info.external_rev = adev->external_rev_id;
@@ -518,7 +522,7 @@
 
 	r = pm_runtime_get_sync(dev->dev);
 	if (r < 0)
-		return r;
+		goto pm_put;
 
 	fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
 	if (unlikely(!fpriv))
@@ -536,6 +540,7 @@
 	file_priv->driver_priv = fpriv;
 
 	pm_runtime_mark_last_busy(dev->dev);
+pm_put:
 	pm_runtime_put_autosuspend(dev->dev);
 	return 0;
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
@@ -142,7 +142,8 @@
 
 		list_for_each_entry(bo, &node->bos, mn_list) {
 
-			if (!bo->tbo.ttm || bo->tbo.ttm->state != tt_bound)
+			if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, start,
+							  end))
 				continue;
 
 			r = amdgpu_bo_reserve(bo, true);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -52,7 +52,7 @@
 
 #define AMDGPU_MAX_HPD_PINS 6
 #define AMDGPU_MAX_CRTCS 6
-#define AMDGPU_MAX_AFMT_BLOCKS 7
+#define AMDGPU_MAX_AFMT_BLOCKS 9
 
 enum amdgpu_rmx_type {
 	RMX_OFF,
@@ -308,8 +308,8 @@
 	struct atom_context *atom_context;
 	struct card_info *atom_card_info;
 	bool mode_config_initialized;
-	struct amdgpu_crtc *crtcs[6];
-	struct amdgpu_afmt *afmt[7];
+	struct amdgpu_crtc *crtcs[AMDGPU_MAX_CRTCS];
+	struct amdgpu_afmt *afmt[AMDGPU_MAX_AFMT_BLOCKS];
 	/* DVI-I properties */
 	struct drm_property *coherent_mode_property;
 	/* DAC enable load detect */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <drm/drmP.h>
 #include <drm/amdgpu_drm.h>
+#include <drm/drm_cache.h>
 #include "amdgpu.h"
 #include "amdgpu_trace.h"
 
@@ -261,6 +262,13 @@
 				       AMDGPU_GEM_DOMAIN_OA);
 
 	bo->flags = flags;
+
+	/* For architectures that don't support WC memory,
+	 * mask out the WC flag from the BO
+	 */
+	if (!drm_arch_can_wc_memory())
+		bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC;
+
 	amdgpu_fill_placement_to_bo(bo, placement);
 	/* Kernel allocation are uninterruptible */
 	r = ttm_bo_init(&adev->mman.bdev, &bo->tbo, size, type,
@@ -399,7 +407,8 @@
 		}
 		if (fpfn > bo->placements[i].fpfn)
 			bo->placements[i].fpfn = fpfn;
-		if (lpfn && lpfn < bo->placements[i].lpfn)
+		if (!bo->placements[i].lpfn ||
+		    (lpfn && lpfn < bo->placements[i].lpfn))
 			bo->placements[i].lpfn = lpfn;
 		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
 	}
@@ -483,6 +492,10 @@
 
 int amdgpu_bo_init(struct amdgpu_device *adev)
 {
+	/* reserve PAT memory space to WC for VRAM */
+	arch_io_reserve_memtype_wc(adev->mc.aper_base,
+				   adev->mc.aper_size);
+
 	/* Add an MTRR for the VRAM */
 	adev->mc.vram_mtrr = arch_phys_wc_add(adev->mc.aper_base,
 					      adev->mc.aper_size);
@@ -498,6 +511,7 @@
 {
 	amdgpu_ttm_fini(adev);
 	arch_phys_wc_del(adev->mc.vram_mtrr);
+	arch_io_free_memtype_wc(adev->mc.aper_base, adev->mc.aper_size);
 }
 
 int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
@@ -531,6 +545,7 @@
 	if (!metadata_size) {
 		if (bo->metadata_size) {
 			kfree(bo->metadata);
+			bo->metadata = NULL;
 			bo->metadata_size = 0;
 		}
 		return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -96,6 +96,7 @@
  */
 static inline u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
 {
+	WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM);
 	return bo->tbo.offset;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -30,10 +30,16 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 
+#include "amd_powerplay.h"
+
 static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev);
 
 void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
 {
+	if (adev->pp_enabled)
+		/* TODO */
+		return;
+
 	if (adev->pm.dpm_enabled) {
 		mutex_lock(&adev->pm.mutex);
 		if (power_supply_is_system_supplied() > 0)
@@ -52,7 +58,12 @@
 {
 	struct drm_device *ddev = dev_get_drvdata(dev);
 	struct amdgpu_device *adev = ddev->dev_private;
-	enum amdgpu_pm_state_type pm = adev->pm.dpm.user_state;
+	enum amd_pm_state_type pm;
+
+	if (adev->pp_enabled) {
+		pm = amdgpu_dpm_get_current_power_state(adev);
+	} else
+		pm = adev->pm.dpm.user_state;
 
 	return snprintf(buf, PAGE_SIZE, "%s\n",
 			(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
@@ -66,40 +77,57 @@
 {
 	struct drm_device *ddev = dev_get_drvdata(dev);
 	struct amdgpu_device *adev = ddev->dev_private;
+	enum amd_pm_state_type  state;
 
-	mutex_lock(&adev->pm.mutex);
 	if (strncmp("battery", buf, strlen("battery")) == 0)
-		adev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
+		state = POWER_STATE_TYPE_BATTERY;
 	else if (strncmp("balanced", buf, strlen("balanced")) == 0)
-		adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+		state = POWER_STATE_TYPE_BALANCED;
 	else if (strncmp("performance", buf, strlen("performance")) == 0)
-		adev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
+		state = POWER_STATE_TYPE_PERFORMANCE;
 	else {
-		mutex_unlock(&adev->pm.mutex);
 		count = -EINVAL;
 		goto fail;
 	}
-	mutex_unlock(&adev->pm.mutex);
 
-	/* Can't set dpm state when the card is off */
-	if (!(adev->flags & AMD_IS_PX) ||
-	    (ddev->switch_power_state == DRM_SWITCH_POWER_ON))
-		amdgpu_pm_compute_clocks(adev);
+	if (adev->pp_enabled) {
+		amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_ENABLE_USER_STATE, &state, NULL);
+	} else {
+		mutex_lock(&adev->pm.mutex);
+		adev->pm.dpm.user_state = state;
+		mutex_unlock(&adev->pm.mutex);
+
+		/* Can't set dpm state when the card is off */
+		if (!(adev->flags & AMD_IS_PX) ||
+		    (ddev->switch_power_state == DRM_SWITCH_POWER_ON))
+			amdgpu_pm_compute_clocks(adev);
+	}
 fail:
 	return count;
 }
 
 static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
-						       struct device_attribute *attr,
-						       char *buf)
+						struct device_attribute *attr,
+								char *buf)
 {
 	struct drm_device *ddev = dev_get_drvdata(dev);
 	struct amdgpu_device *adev = ddev->dev_private;
-	enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
 
-	return snprintf(buf, PAGE_SIZE, "%s\n",
-			(level == AMDGPU_DPM_FORCED_LEVEL_AUTO) ? "auto" :
-			(level == AMDGPU_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+	if (adev->pp_enabled) {
+		enum amd_dpm_forced_level level;
+
+		level = amdgpu_dpm_get_performance_level(adev);
+		return snprintf(buf, PAGE_SIZE, "%s\n",
+				(level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+				(level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+	} else {
+		enum amdgpu_dpm_forced_level level;
+
+		level = adev->pm.dpm.forced_level;
+		return snprintf(buf, PAGE_SIZE, "%s\n",
+				(level == AMDGPU_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+				(level == AMDGPU_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+	}
 }
 
 static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
@@ -112,7 +140,6 @@
 	enum amdgpu_dpm_forced_level level;
 	int ret = 0;
 
-	mutex_lock(&adev->pm.mutex);
 	if (strncmp("low", buf, strlen("low")) == 0) {
 		level = AMDGPU_DPM_FORCED_LEVEL_LOW;
 	} else if (strncmp("high", buf, strlen("high")) == 0) {
@@ -123,7 +150,11 @@
 		count = -EINVAL;
 		goto fail;
 	}
-	if (adev->pm.funcs->force_performance_level) {
+
+	if (adev->pp_enabled)
+		amdgpu_dpm_force_performance_level(adev, level);
+	else {
+		mutex_lock(&adev->pm.mutex);
 		if (adev->pm.dpm.thermal_active) {
 			count = -EINVAL;
 			goto fail;
@@ -131,6 +162,9 @@
 		ret = amdgpu_dpm_force_performance_level(adev, level);
 		if (ret)
 			count = -EINVAL;
+		else
+			adev->pm.dpm.forced_level = level;
+		mutex_unlock(&adev->pm.mutex);
 	}
 fail:
 	mutex_unlock(&adev->pm.mutex);
@@ -150,10 +184,10 @@
 	struct amdgpu_device *adev = dev_get_drvdata(dev);
 	int temp;
 
-	if (adev->pm.funcs->get_temperature)
-		temp = amdgpu_dpm_get_temperature(adev);
-	else
+	if (!adev->pp_enabled && !adev->pm.funcs->get_temperature)
 		temp = 0;
+	else
+		temp = amdgpu_dpm_get_temperature(adev);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", temp);
 }
@@ -181,8 +215,10 @@
 	struct amdgpu_device *adev = dev_get_drvdata(dev);
 	u32 pwm_mode = 0;
 
-	if (adev->pm.funcs->get_fan_control_mode)
-		pwm_mode = amdgpu_dpm_get_fan_control_mode(adev);
+	if (!adev->pp_enabled && !adev->pm.funcs->get_fan_control_mode)
+		return -EINVAL;
+
+	pwm_mode = amdgpu_dpm_get_fan_control_mode(adev);
 
 	/* never 0 (full-speed), fuse or smc-controlled always */
 	return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
@@ -197,7 +233,7 @@
 	int err;
 	int value;
 
-	if(!adev->pm.funcs->set_fan_control_mode)
+	if (!adev->pp_enabled && !adev->pm.funcs->set_fan_control_mode)
 		return -EINVAL;
 
 	err = kstrtoint(buf, 10, &value);
@@ -290,11 +326,11 @@
 static umode_t hwmon_attributes_visible(struct kobject *kobj,
 					struct attribute *attr, int index)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
+	struct device *dev = kobj_to_dev(kobj);
 	struct amdgpu_device *adev = dev_get_drvdata(dev);
 	umode_t effective_mode = attr->mode;
 
-	/* Skip attributes if DPM is not enabled */
+	/* Skip limit attributes if DPM is not enabled */
 	if (!adev->pm.dpm_enabled &&
 	    (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
 	     attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr ||
@@ -304,6 +340,9 @@
 	     attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
 		return 0;
 
+	if (adev->pp_enabled)
+		return effective_mode;
+
 	/* Skip fan attributes if fan is not present */
 	if (adev->pm.no_fan &&
 	    (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
@@ -351,7 +390,7 @@
 		container_of(work, struct amdgpu_device,
 			     pm.dpm.thermal.work);
 	/* switch to the thermal state */
-	enum amdgpu_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
+	enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
 
 	if (!adev->pm.dpm_enabled)
 		return;
@@ -379,7 +418,7 @@
 }
 
 static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
-						     enum amdgpu_pm_state_type dpm_state)
+						     enum amd_pm_state_type dpm_state)
 {
 	int i;
 	struct amdgpu_ps *ps;
@@ -516,7 +555,7 @@
 {
 	int i;
 	struct amdgpu_ps *ps;
-	enum amdgpu_pm_state_type dpm_state;
+	enum amd_pm_state_type dpm_state;
 	int ret;
 
 	/* if dpm init failed */
@@ -595,11 +634,6 @@
 
 	/* update display watermarks based on new power state */
 	amdgpu_display_bandwidth_update(adev);
-	/* update displays */
-	amdgpu_dpm_display_configuration_changed(adev);
-
-	adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
-	adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
 
 	/* wait for the rings to drain */
 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
@@ -616,6 +650,12 @@
 
 	amdgpu_dpm_post_set_power_state(adev);
 
+	/* update displays */
+	amdgpu_dpm_display_configuration_changed(adev);
+
+	adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
+	adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
+
 	if (adev->pm.funcs->force_performance_level) {
 		if (adev->pm.dpm.thermal_active) {
 			enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
@@ -635,49 +675,54 @@
 
 void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
 {
-	if (adev->pm.funcs->powergate_uvd) {
-		mutex_lock(&adev->pm.mutex);
-		/* enable/disable UVD */
+	if (adev->pp_enabled)
 		amdgpu_dpm_powergate_uvd(adev, !enable);
-		mutex_unlock(&adev->pm.mutex);
-	} else {
-		if (enable) {
+	else {
+		if (adev->pm.funcs->powergate_uvd) {
 			mutex_lock(&adev->pm.mutex);
-			adev->pm.dpm.uvd_active = true;
-			adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
+			/* enable/disable UVD */
+			amdgpu_dpm_powergate_uvd(adev, !enable);
 			mutex_unlock(&adev->pm.mutex);
 		} else {
-			mutex_lock(&adev->pm.mutex);
-			adev->pm.dpm.uvd_active = false;
-			mutex_unlock(&adev->pm.mutex);
+			if (enable) {
+				mutex_lock(&adev->pm.mutex);
+				adev->pm.dpm.uvd_active = true;
+				adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
+				mutex_unlock(&adev->pm.mutex);
+			} else {
+				mutex_lock(&adev->pm.mutex);
+				adev->pm.dpm.uvd_active = false;
+				mutex_unlock(&adev->pm.mutex);
+			}
+			amdgpu_pm_compute_clocks(adev);
 		}
 
-		amdgpu_pm_compute_clocks(adev);
 	}
 }
 
 void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
 {
-	if (adev->pm.funcs->powergate_vce) {
-		mutex_lock(&adev->pm.mutex);
-		/* enable/disable VCE */
+	if (adev->pp_enabled)
 		amdgpu_dpm_powergate_vce(adev, !enable);
-
-		mutex_unlock(&adev->pm.mutex);
-	} else {
-		if (enable) {
+	else {
+		if (adev->pm.funcs->powergate_vce) {
 			mutex_lock(&adev->pm.mutex);
-			adev->pm.dpm.vce_active = true;
-			/* XXX select vce level based on ring/task */
-			adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL;
+			amdgpu_dpm_powergate_vce(adev, !enable);
 			mutex_unlock(&adev->pm.mutex);
 		} else {
-			mutex_lock(&adev->pm.mutex);
-			adev->pm.dpm.vce_active = false;
-			mutex_unlock(&adev->pm.mutex);
+			if (enable) {
+				mutex_lock(&adev->pm.mutex);
+				adev->pm.dpm.vce_active = true;
+				/* XXX select vce level based on ring/task */
+				adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL;
+				mutex_unlock(&adev->pm.mutex);
+			} else {
+				mutex_lock(&adev->pm.mutex);
+				adev->pm.dpm.vce_active = false;
+				mutex_unlock(&adev->pm.mutex);
+			}
+			amdgpu_pm_compute_clocks(adev);
 		}
-
-		amdgpu_pm_compute_clocks(adev);
 	}
 }
 
@@ -685,10 +730,13 @@
 {
 	int i;
 
-	for (i = 0; i < adev->pm.dpm.num_ps; i++) {
-		printk("== power state %d ==\n", i);
+	if (adev->pp_enabled)
+		/* TO DO */
+		return;
+
+	for (i = 0; i < adev->pm.dpm.num_ps; i++)
 		amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]);
-	}
+
 }
 
 int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
@@ -698,8 +746,11 @@
 	if (adev->pm.sysfs_initialized)
 		return 0;
 
-	if (adev->pm.funcs->get_temperature == NULL)
-		return 0;
+	if (!adev->pp_enabled) {
+		if (adev->pm.funcs->get_temperature == NULL)
+			return 0;
+	}
+
 	adev->pm.int_hwmon_dev = hwmon_device_register_with_groups(adev->dev,
 								   DRIVER_NAME, adev,
 								   hwmon_groups);
@@ -748,32 +799,43 @@
 	if (!adev->pm.dpm_enabled)
 		return;
 
-	mutex_lock(&adev->pm.mutex);
+	if (adev->pp_enabled) {
+		int i = 0;
 
-	/* update active crtc counts */
-	adev->pm.dpm.new_active_crtcs = 0;
-	adev->pm.dpm.new_active_crtc_count = 0;
-	if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
-		list_for_each_entry(crtc,
-				    &ddev->mode_config.crtc_list, head) {
-			amdgpu_crtc = to_amdgpu_crtc(crtc);
-			if (crtc->enabled) {
-				adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id);
-				adev->pm.dpm.new_active_crtc_count++;
+		amdgpu_display_bandwidth_update(adev);
+		mutex_lock(&adev->ring_lock);
+			for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
+				struct amdgpu_ring *ring = adev->rings[i];
+				if (ring && ring->ready)
+					amdgpu_fence_wait_empty(ring);
 			}
-		}
-	}
+		mutex_unlock(&adev->ring_lock);
 
-	/* update battery/ac status */
-	if (power_supply_is_system_supplied() > 0)
-		adev->pm.dpm.ac_power = true;
-	else
-		adev->pm.dpm.ac_power = false;
-
-	amdgpu_dpm_change_power_state_locked(adev);
+		amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE, NULL, NULL);
+	} else {
+		mutex_lock(&adev->pm.mutex);
+		adev->pm.dpm.new_active_crtcs = 0;
+		adev->pm.dpm.new_active_crtc_count = 0;
+		if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
+			list_for_each_entry(crtc,
+					    &ddev->mode_config.crtc_list, head) {
+				amdgpu_crtc = to_amdgpu_crtc(crtc);
+				if (crtc->enabled) {
+					adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id);
+					adev->pm.dpm.new_active_crtc_count++;
+				}
+			}
+		}
+		/* update battery/ac status */
+		if (power_supply_is_system_supplied() > 0)
+			adev->pm.dpm.ac_power = true;
+		else
+			adev->pm.dpm.ac_power = false;
 
-	mutex_unlock(&adev->pm.mutex);
+		amdgpu_dpm_change_power_state_locked(adev);
 
+		mutex_unlock(&adev->pm.mutex);
+	}
 }
 
 /*
@@ -787,7 +849,13 @@
 	struct drm_device *dev = node->minor->dev;
 	struct amdgpu_device *adev = dev->dev_private;
 
-	if (adev->pm.dpm_enabled) {
+	if (!adev->pm.dpm_enabled) {
+		seq_printf(m, "dpm not enabled\n");
+		return 0;
+	}
+	if (adev->pp_enabled) {
+		amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
+	} else {
 		mutex_lock(&adev->pm.mutex);
 		if (adev->pm.funcs->debugfs_print_current_performance_level)
 			amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "atom.h"
+#include "amdgpu.h"
+#include "amd_shared.h"
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include "amdgpu_pm.h"
+#include <drm/amdgpu_drm.h>
+#include "amdgpu_powerplay.h"
+#include "cik_dpm.h"
+#include "vi_dpm.h"
+
+static int amdgpu_powerplay_init(struct amdgpu_device *adev)
+{
+	int ret = 0;
+	struct amd_powerplay *amd_pp;
+
+	amd_pp = &(adev->powerplay);
+
+	if (adev->pp_enabled) {
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+		struct amd_pp_init *pp_init;
+
+		pp_init = kzalloc(sizeof(struct amd_pp_init), GFP_KERNEL);
+
+		if (pp_init == NULL)
+			return -ENOMEM;
+
+		pp_init->chip_family = adev->family;
+		pp_init->chip_id = adev->asic_type;
+		pp_init->device = amdgpu_cgs_create_device(adev);
+
+		ret = amd_powerplay_init(pp_init, amd_pp);
+		kfree(pp_init);
+#endif
+	} else {
+		amd_pp->pp_handle = (void *)adev;
+
+		switch (adev->asic_type) {
+#ifdef CONFIG_DRM_AMDGPU_CIK
+		case CHIP_BONAIRE:
+		case CHIP_HAWAII:
+			amd_pp->ip_funcs = &ci_dpm_ip_funcs;
+			break;
+		case CHIP_KABINI:
+		case CHIP_MULLINS:
+		case CHIP_KAVERI:
+			amd_pp->ip_funcs = &kv_dpm_ip_funcs;
+			break;
+#endif
+		case CHIP_TOPAZ:
+			amd_pp->ip_funcs = &iceland_dpm_ip_funcs;
+			break;
+		case CHIP_TONGA:
+			amd_pp->ip_funcs = &tonga_dpm_ip_funcs;
+			break;
+		case CHIP_FIJI:
+			amd_pp->ip_funcs = &fiji_dpm_ip_funcs;
+			break;
+		case CHIP_CARRIZO:
+		case CHIP_STONEY:
+			amd_pp->ip_funcs = &cz_dpm_ip_funcs;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int amdgpu_pp_early_init(void *handle)
+{
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	int ret = 0;
+
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+	switch (adev->asic_type) {
+	case CHIP_TONGA:
+	case CHIP_FIJI:
+		adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true;
+		break;
+	case CHIP_CARRIZO:
+	case CHIP_STONEY:
+		adev->pp_enabled = (amdgpu_powerplay > 0) ? true : false;
+		break;
+	/* These chips don't have powerplay implemenations */
+	case CHIP_BONAIRE:
+	case CHIP_HAWAII:
+	case CHIP_KABINI:
+	case CHIP_MULLINS:
+	case CHIP_KAVERI:
+	case CHIP_TOPAZ:
+	default:
+		adev->pp_enabled = false;
+		break;
+	}
+#else
+	adev->pp_enabled = false;
+#endif
+
+	ret = amdgpu_powerplay_init(adev);
+	if (ret)
+		return ret;
+
+	if (adev->powerplay.ip_funcs->early_init)
+		ret = adev->powerplay.ip_funcs->early_init(
+					adev->powerplay.pp_handle);
+	return ret;
+}
+
+
+static int amdgpu_pp_late_init(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->late_init)
+		ret = adev->powerplay.ip_funcs->late_init(
+					adev->powerplay.pp_handle);
+
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+	if (adev->pp_enabled)
+		amdgpu_pm_sysfs_init(adev);
+#endif
+	return ret;
+}
+
+static int amdgpu_pp_sw_init(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->sw_init)
+		ret = adev->powerplay.ip_funcs->sw_init(
+					adev->powerplay.pp_handle);
+
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+	if (adev->pp_enabled) {
+		if (amdgpu_dpm == 0)
+			adev->pm.dpm_enabled = false;
+		else
+			adev->pm.dpm_enabled = true;
+	}
+#endif
+
+	return ret;
+}
+
+static int amdgpu_pp_sw_fini(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->sw_fini)
+		ret = adev->powerplay.ip_funcs->sw_fini(
+					adev->powerplay.pp_handle);
+	if (ret)
+		return ret;
+
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+	if (adev->pp_enabled) {
+		amdgpu_pm_sysfs_fini(adev);
+		amd_powerplay_fini(adev->powerplay.pp_handle);
+	}
+#endif
+
+	return ret;
+}
+
+static int amdgpu_pp_hw_init(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->pp_enabled && adev->firmware.smu_load)
+		amdgpu_ucode_init_bo(adev);
+
+	if (adev->powerplay.ip_funcs->hw_init)
+		ret = adev->powerplay.ip_funcs->hw_init(
+					adev->powerplay.pp_handle);
+
+	return ret;
+}
+
+static int amdgpu_pp_hw_fini(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->hw_fini)
+		ret = adev->powerplay.ip_funcs->hw_fini(
+					adev->powerplay.pp_handle);
+
+	if (adev->pp_enabled && adev->firmware.smu_load)
+		amdgpu_ucode_fini_bo(adev);
+
+	return ret;
+}
+
+static int amdgpu_pp_suspend(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->suspend)
+		ret = adev->powerplay.ip_funcs->suspend(
+					 adev->powerplay.pp_handle);
+	return ret;
+}
+
+static int amdgpu_pp_resume(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->resume)
+		ret = adev->powerplay.ip_funcs->resume(
+					adev->powerplay.pp_handle);
+	return ret;
+}
+
+static int amdgpu_pp_set_clockgating_state(void *handle,
+					enum amd_clockgating_state state)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->set_clockgating_state)
+		ret = adev->powerplay.ip_funcs->set_clockgating_state(
+				adev->powerplay.pp_handle, state);
+	return ret;
+}
+
+static int amdgpu_pp_set_powergating_state(void *handle,
+					enum amd_powergating_state state)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->set_powergating_state)
+		ret = adev->powerplay.ip_funcs->set_powergating_state(
+				 adev->powerplay.pp_handle, state);
+	return ret;
+}
+
+
+static bool amdgpu_pp_is_idle(void *handle)
+{
+	bool ret = true;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->is_idle)
+		ret = adev->powerplay.ip_funcs->is_idle(
+					adev->powerplay.pp_handle);
+	return ret;
+}
+
+static int amdgpu_pp_wait_for_idle(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->wait_for_idle)
+		ret = adev->powerplay.ip_funcs->wait_for_idle(
+					adev->powerplay.pp_handle);
+	return ret;
+}
+
+static int amdgpu_pp_soft_reset(void *handle)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->soft_reset)
+		ret = adev->powerplay.ip_funcs->soft_reset(
+					adev->powerplay.pp_handle);
+	return ret;
+}
+
+static void amdgpu_pp_print_status(void *handle)
+{
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (adev->powerplay.ip_funcs->print_status)
+		adev->powerplay.ip_funcs->print_status(
+					adev->powerplay.pp_handle);
+}
+
+const struct amd_ip_funcs amdgpu_pp_ip_funcs = {
+	.early_init = amdgpu_pp_early_init,
+	.late_init = amdgpu_pp_late_init,
+	.sw_init = amdgpu_pp_sw_init,
+	.sw_fini = amdgpu_pp_sw_fini,
+	.hw_init = amdgpu_pp_hw_init,
+	.hw_fini = amdgpu_pp_hw_fini,
+	.suspend = amdgpu_pp_suspend,
+	.resume = amdgpu_pp_resume,
+	.is_idle = amdgpu_pp_is_idle,
+	.wait_for_idle = amdgpu_pp_wait_for_idle,
+	.soft_reset = amdgpu_pp_soft_reset,
+	.print_status = amdgpu_pp_print_status,
+	.set_clockgating_state = amdgpu_pp_set_clockgating_state,
+	.set_powergating_state = amdgpu_pp_set_powergating_state,
+};
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __AMDGPU_POPWERPLAY_H__
+#define __AMDGPU_POPWERPLAY_H__
+
+#include "amd_shared.h"
+
+extern const struct amd_ip_funcs amdgpu_pp_ip_funcs;
+
+#endif /* __AMDSOC_DM_H__ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
@@ -77,20 +77,36 @@
 	list_add_tail(&bo->list, &adev->gem.objects);
 	mutex_unlock(&adev->gem.mutex);
 
+	bo->prime_shared_count = 1;
 	return &bo->gem_base;
 }
 
 int amdgpu_gem_prime_pin(struct drm_gem_object *obj)
 {
 	struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
-	int ret = 0;
+	long ret = 0;
 
 	ret = amdgpu_bo_reserve(bo, false);
 	if (unlikely(ret != 0))
 		return ret;
 
+	/*
+	 * Wait for all shared fences to complete before we switch to future
+	 * use of exclusive fence on this prime shared bo.
+	 */
+	ret = reservation_object_wait_timeout_rcu(bo->tbo.resv, true, false,
+						  MAX_SCHEDULE_TIMEOUT);
+	if (unlikely(ret < 0)) {
+		DRM_DEBUG_PRIME("Fence wait failed: %li\n", ret);
+		amdgpu_bo_unreserve(bo);
+		return ret;
+	}
+
 	/* pin buffer into GTT */
 	ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL);
+	if (likely(ret == 0))
+		bo->prime_shared_count++;
+
 	amdgpu_bo_unreserve(bo);
 	return ret;
 }
@@ -105,6 +121,8 @@
 		return;
 
 	amdgpu_bo_unpin(bo);
+	if (bo->prime_shared_count)
+		bo->prime_shared_count--;
 	amdgpu_bo_unreserve(bo);
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -487,7 +487,7 @@
 	seq_printf(m, "rptr: 0x%08x [%5d]\n",
 		   rptr, rptr);
 
-	rptr_next = ~0;
+	rptr_next = le32_to_cpu(*ring->next_rptr_cpu_addr);
 
 	seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n",
 		   ring->wptr, ring->wptr);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
@@ -354,12 +354,15 @@
 
 		for (i = 0, count = 0; i < AMDGPU_MAX_RINGS; ++i)
 			if (fences[i])
-				fences[count++] = fences[i];
+				fences[count++] = fence_get(fences[i]);
 
 		if (count) {
 			spin_unlock(&sa_manager->wq.lock);
 			t = fence_wait_any_timeout(fences, count, false,
 						   MAX_SCHEDULE_TIMEOUT);
+			for (i = 0; i < count; ++i)
+				fence_put(fences[i]);
+
 			r = (t > 0) ? 0 : t;
 			spin_lock(&sa_manager->wq.lock);
 		} else {
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
@@ -293,7 +293,8 @@
 		fence = to_amdgpu_fence(sync->sync_to[i]);
 
 		/* check if we really need to sync */
-		if (!amdgpu_fence_need_sync(fence, ring))
+		if (!amdgpu_enable_scheduler &&
+		    !amdgpu_fence_need_sync(fence, ring))
 			continue;
 
 		/* prevent GPU deadlocks */
@@ -303,7 +304,7 @@
 		}
 
 		if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores) {
-			r = fence_wait(&fence->base, true);
+			r = fence_wait(sync->sync_to[i], true);
 			if (r)
 				return r;
 			continue;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -233,8 +233,8 @@
 
 	adev = amdgpu_get_adev(bo->bdev);
 	ring = adev->mman.buffer_funcs_ring;
-	old_start = old_mem->start << PAGE_SHIFT;
-	new_start = new_mem->start << PAGE_SHIFT;
+	old_start = (u64)old_mem->start << PAGE_SHIFT;
+	new_start = (u64)new_mem->start << PAGE_SHIFT;
 
 	switch (old_mem->mem_type) {
 	case TTM_PL_VRAM:
@@ -496,9 +496,13 @@
 	int r;
 
 	int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
+	unsigned int flags = 0;
 	enum dma_data_direction direction = write ?
 		DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
 
+	if (write)
+		flags |= FOLL_WRITE;
+
 	if (current->mm != gtt->usermm)
 		return -EPERM;
 
@@ -519,7 +523,7 @@
 		struct page **pages = ttm->pages + pinned;
 
 		r = get_user_pages(current, current->mm, userptr, num_pages,
-				   write, 0, pages, NULL);
+				   flags, pages, NULL);
 		if (r < 0)
 			goto release_pages;
 
@@ -712,7 +716,7 @@
 						       0, PAGE_SIZE,
 						       PCI_DMA_BIDIRECTIONAL);
 		if (pci_dma_mapping_error(adev->pdev, gtt->ttm.dma_address[i])) {
-			while (--i) {
+			while (i--) {
 				pci_unmap_page(adev->pdev, gtt->ttm.dma_address[i],
 					       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
 				gtt->ttm.dma_address[i] = 0;
@@ -733,6 +737,7 @@
 
 	if (gtt && gtt->userptr) {
 		kfree(ttm->sg);
+		ttm->sg = NULL;
 		ttm->page_flags &= ~TTM_PAGE_FLAG_SG;
 		return;
 	}
@@ -783,6 +788,25 @@
 	return !!gtt->userptr;
 }
 
+bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
+				  unsigned long end)
+{
+	struct amdgpu_ttm_tt *gtt = (void *)ttm;
+	unsigned long size;
+
+	if (gtt == NULL)
+		return false;
+
+	if (gtt->ttm.ttm.state != tt_bound || !gtt->userptr)
+		return false;
+
+	size = (unsigned long)gtt->ttm.ttm.num_pages * PAGE_SIZE;
+	if (gtt->userptr > end || gtt->userptr + size <= start)
+		return false;
+
+	return true;
+}
+
 bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
 {
 	struct amdgpu_ttm_tt *gtt = (void *)ttm;
@@ -808,7 +832,7 @@
 			flags |= AMDGPU_PTE_SNOOPED;
 	}
 
-	if (adev->asic_type >= CHIP_TOPAZ)
+	if (adev->asic_type >= CHIP_TONGA)
 		flags |= AMDGPU_PTE_EXECUTABLE;
 
 	flags |= AMDGPU_PTE_READABLE;
@@ -1107,6 +1131,9 @@
 	if (size & 0x3 || *pos & 0x3)
 		return -EINVAL;
 
+	if (*pos >= adev->mc.mc_vram_size)
+		return -ENXIO;
+
 	while (size) {
 		unsigned long flags;
 		uint32_t value;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -156,6 +156,9 @@
 	DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n",
 		version_major, version_minor, family_id);
 
+	adev->uvd.fw_version = ((version_major << 24) | (version_minor << 16) |
+				(family_id << 8));
+
 	bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8)
 		 +  AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE;
 	r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true,
@@ -273,6 +276,8 @@
 	memcpy(adev->uvd.cpu_addr, (adev->uvd.fw->data) + offset,
 		(adev->uvd.fw->size) - offset);
 
+	cancel_delayed_work_sync(&adev->uvd.idle_work);
+
 	size = amdgpu_bo_size(adev->uvd.vcpu_bo);
 	size -= le32_to_cpu(hdr->ucode_size_bytes);
 	ptr = adev->uvd.cpu_addr;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -190,13 +190,13 @@
 	if (adev->vce.vcpu_bo == NULL)
 		return 0;
 
-	amdgpu_bo_unref(&adev->vce.vcpu_bo);
-
 	amdgpu_ring_fini(&adev->vce.ring[0]);
 	amdgpu_ring_fini(&adev->vce.ring[1]);
 
 	release_firmware(adev->vce.fw);
 
+	amdgpu_bo_unref(&adev->vce.vcpu_bo);
+
 	return 0;
 }
 
@@ -220,6 +220,7 @@
 	if (i == AMDGPU_MAX_VCE_HANDLES)
 		return 0;
 
+	cancel_delayed_work_sync(&adev->vce.idle_work);
 	/* TODO: suspending running encoding sessions isn't supported */
 	return -EINVAL;
 }
@@ -283,6 +284,10 @@
 			amdgpu_dpm_enable_vce(adev, false);
 		} else {
 			amdgpu_asic_set_vce_clocks(adev, 0, 0);
+			amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+							    AMD_PG_STATE_GATE);
+			amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+							    AMD_CG_STATE_GATE);
 		}
 	} else {
 		schedule_delayed_work(&adev->vce.idle_work,
@@ -314,6 +319,11 @@
 			amdgpu_dpm_enable_vce(adev, true);
 		} else {
 			amdgpu_asic_set_vce_clocks(adev, 53300, 40000);
+			amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+							    AMD_CG_STATE_UNGATE);
+			amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+							    AMD_PG_STATE_UNGATE);
+
 		}
 	}
 }
@@ -613,7 +623,8 @@
 	bool created = false;
 	bool allocated = false;
 	uint32_t tmp, handle = 0;
-	uint32_t *size = &tmp;
+	uint32_t dummy = 0xffffffff;
+	uint32_t *size = &dummy;
 	int i, r = 0, idx = 0;
 
 	amdgpu_vce_note_usage(p->adev);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -75,50 +75,77 @@
 }
 
 /**
- * amdgpu_vm_get_bos - add the vm BOs to a validation list
+ * amdgpu_vm_get_pd_bo - add the VM PD to a validation list
  *
  * @vm: vm providing the BOs
- * @head: head of validation list
+ * @validated: head of validation list
+ * @entry: entry to add
  *
  * Add the page directory to the list of BOs to
- * validate for command submission (cayman+).
+ * validate for command submission.
  */
-struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
-					  struct amdgpu_vm *vm,
-					  struct list_head *head)
-{
-	struct amdgpu_bo_list_entry *list;
-	unsigned i, idx;
-
-	list = drm_malloc_ab(vm->max_pde_used + 2,
-			     sizeof(struct amdgpu_bo_list_entry));
-	if (!list) {
-		return NULL;
-	}
+void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
+			 struct list_head *validated,
+			 struct amdgpu_bo_list_entry *entry)
+{
+	entry->robj = vm->page_directory;
+	entry->prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
+	entry->allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
+	entry->priority = 0;
+	entry->tv.bo = &vm->page_directory->tbo;
+	entry->tv.shared = true;
+	list_add(&entry->tv.head, validated);
+}
+
+/**
+ * amdgpu_vm_get_bos - add the vm BOs to a duplicates list
+ *
+ * @vm: vm providing the BOs
+ * @duplicates: head of duplicates list
+ *
+ * Add the page directory to the BO duplicates list
+ * for command submission.
+ */
+void amdgpu_vm_get_pt_bos(struct amdgpu_vm *vm, struct list_head *duplicates)
+{
+	unsigned i;
 
 	/* add the vm page table to the list */
-	list[0].robj = vm->page_directory;
-	list[0].prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
-	list[0].allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
-	list[0].priority = 0;
-	list[0].tv.bo = &vm->page_directory->tbo;
-	list[0].tv.shared = true;
-	list_add(&list[0].tv.head, head);
+	for (i = 0; i <= vm->max_pde_used; ++i) {
+		struct amdgpu_bo_list_entry *entry = &vm->page_tables[i].entry;
 
-	for (i = 0, idx = 1; i <= vm->max_pde_used; i++) {
-		if (!vm->page_tables[i].bo)
+		if (!entry->robj)
 			continue;
 
-		list[idx].robj = vm->page_tables[i].bo;
-		list[idx].prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
-		list[idx].allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
-		list[idx].priority = 0;
-		list[idx].tv.bo = &list[idx].robj->tbo;
-		list[idx].tv.shared = true;
-		list_add(&list[idx++].tv.head, head);
+		list_add(&entry->tv.head, duplicates);
 	}
 
-	return list;
+}
+
+/**
+ * amdgpu_vm_move_pt_bos_in_lru - move the PT BOs to the LRU tail
+ *
+ * @adev: amdgpu device instance
+ * @vm: vm providing the BOs
+ *
+ * Move the PT BOs to the tail of the LRU.
+ */
+void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev,
+				  struct amdgpu_vm *vm)
+{
+	struct ttm_bo_global *glob = adev->mman.bdev.glob;
+	unsigned i;
+
+	spin_lock(&glob->lru_lock);
+	for (i = 0; i <= vm->max_pde_used; ++i) {
+		struct amdgpu_bo_list_entry *entry = &vm->page_tables[i].entry;
+
+		if (!entry->robj)
+			continue;
+
+		ttm_bo_move_to_lru_tail(&entry->robj->tbo);
+	}
+	spin_unlock(&glob->lru_lock);
 }
 
 /**
@@ -461,7 +488,7 @@
 
 	/* walk over the address space and update the page directory */
 	for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) {
-		struct amdgpu_bo *bo = vm->page_tables[pt_idx].bo;
+		struct amdgpu_bo *bo = vm->page_tables[pt_idx].entry.robj;
 		uint64_t pde, pt;
 
 		if (bo == NULL)
@@ -638,7 +665,7 @@
 	/* walk over the address space and update the page tables */
 	for (addr = start; addr < end; ) {
 		uint64_t pt_idx = addr >> amdgpu_vm_block_size;
-		struct amdgpu_bo *pt = vm->page_tables[pt_idx].bo;
+		struct amdgpu_bo *pt = vm->page_tables[pt_idx].entry.robj;
 		unsigned nptes;
 		uint64_t pte;
 		int r;
@@ -1010,13 +1037,13 @@
 		return -EINVAL;
 
 	/* make sure object fit at this offset */
-	eaddr = saddr + size;
+	eaddr = saddr + size - 1;
 	if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo)))
 		return -EINVAL;
 
 	last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE;
-	if (last_pfn > adev->vm_manager.max_pfn) {
-		dev_err(adev->dev, "va above limit (0x%08X > 0x%08X)\n",
+	if (last_pfn >= adev->vm_manager.max_pfn) {
+		dev_err(adev->dev, "va above limit (0x%08X >= 0x%08X)\n",
 			last_pfn, adev->vm_manager.max_pfn);
 		return -EINVAL;
 	}
@@ -1025,7 +1052,7 @@
 	eaddr /= AMDGPU_GPU_PAGE_SIZE;
 
 	spin_lock(&vm->it_lock);
-	it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1);
+	it = interval_tree_iter_first(&vm->va, saddr, eaddr);
 	spin_unlock(&vm->it_lock);
 	if (it) {
 		struct amdgpu_bo_va_mapping *tmp;
@@ -1046,7 +1073,7 @@
 
 	INIT_LIST_HEAD(&mapping->list);
 	mapping->it.start = saddr;
-	mapping->it.last = eaddr - 1;
+	mapping->it.last = eaddr;
 	mapping->offset = offset;
 	mapping->flags = flags;
 
@@ -1070,9 +1097,11 @@
 	/* walk over the address space and allocate the page tables */
 	for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) {
 		struct reservation_object *resv = vm->page_directory->tbo.resv;
+		struct amdgpu_bo_list_entry *entry;
 		struct amdgpu_bo *pt;
 
-		if (vm->page_tables[pt_idx].bo)
+		entry = &vm->page_tables[pt_idx].entry;
+		if (entry->robj)
 			continue;
 
 		r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,
@@ -1094,8 +1123,13 @@
 			goto error_free;
 		}
 
+		entry->robj = pt;
+		entry->prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
+		entry->allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
+		entry->priority = 0;
+		entry->tv.bo = &entry->robj->tbo;
+		entry->tv.shared = true;
 		vm->page_tables[pt_idx].addr = 0;
-		vm->page_tables[pt_idx].bo = pt;
 	}
 
 	return 0;
@@ -1248,7 +1282,7 @@
 {
 	const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE,
 		AMDGPU_VM_PTE_COUNT * 8);
-	unsigned pd_size, pd_entries, pts_size;
+	unsigned pd_size, pd_entries;
 	int i, r;
 
 	for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
@@ -1266,8 +1300,7 @@
 	pd_entries = amdgpu_vm_num_pdes(adev);
 
 	/* allocate page table array */
-	pts_size = pd_entries * sizeof(struct amdgpu_vm_pt);
-	vm->page_tables = kzalloc(pts_size, GFP_KERNEL);
+	vm->page_tables = drm_calloc_large(pd_entries, sizeof(struct amdgpu_vm_pt));
 	if (vm->page_tables == NULL) {
 		DRM_ERROR("Cannot allocate memory for page table array\n");
 		return -ENOMEM;
@@ -1326,8 +1359,8 @@
 	}
 
 	for (i = 0; i < amdgpu_vm_num_pdes(adev); i++)
-		amdgpu_bo_unref(&vm->page_tables[i].bo);
-	kfree(vm->page_tables);
+		amdgpu_bo_unref(&vm->page_tables[i].entry.robj);
+	drm_free_large(vm->page_tables);
 
 	amdgpu_bo_unref(&vm->page_directory);
 	fence_put(vm->page_directory_fence);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/atom.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/atom.c
@@ -748,8 +748,8 @@
 			cjiffies = jiffies;
 			if (time_after(cjiffies, ctx->last_jump_jiffies)) {
 				cjiffies -= ctx->last_jump_jiffies;
-				if ((jiffies_to_msecs(cjiffies) > 5000)) {
-					DRM_ERROR("atombios stuck in loop for more than 5secs aborting\n");
+				if ((jiffies_to_msecs(cjiffies) > 10000)) {
+					DRM_ERROR("atombios stuck in loop for more than 10secs aborting\n");
 					ctx->abort = true;
 				}
 			} else {
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
@@ -164,7 +164,7 @@
 	struct drm_device *dev = crtc->dev;
 	struct amdgpu_device *adev = dev->dev_private;
 	int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
-	ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args;
+	ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
 
 	memset(&args, 0, sizeof(args));
 
@@ -177,7 +177,7 @@
 void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev)
 {
 	int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
-	ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args;
+	ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
 
 	memset(&args, 0, sizeof(args));
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
@@ -243,7 +243,7 @@
 
 /* convert bits per color to bits per pixel */
 /* get bpc from the EDID */
-static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
+static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
 {
 	if (bpc == 0)
 		return 24;
@@ -251,64 +251,44 @@
 		return bpc * 3;
 }
 
-/* get the max pix clock supported by the link rate and lane num */
-static int amdgpu_atombios_dp_get_max_dp_pix_clock(int link_rate,
-					    int lane_num,
-					    int bpp)
-{
-	return (link_rate * lane_num * 8) / bpp;
-}
-
 /***** amdgpu specific DP functions *****/
 
-/* First get the min lane# when low rate is used according to pixel clock
- * (prefer low rate), second check max lane# supported by DP panel,
- * if the max lane# < low rate lane# then use max lane# instead.
- */
-static int amdgpu_atombios_dp_get_dp_lane_number(struct drm_connector *connector,
+static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector,
 						 const u8 dpcd[DP_DPCD_SIZE],
-						 int pix_clock)
-{
-	int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
-	int max_link_rate = drm_dp_max_link_rate(dpcd);
-	int max_lane_num = drm_dp_max_lane_count(dpcd);
-	int lane_num;
-	int max_dp_pix_clock;
-
-	for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
-		max_dp_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
-		if (pix_clock <= max_dp_pix_clock)
-			break;
-	}
-
-	return lane_num;
-}
-
-static int amdgpu_atombios_dp_get_dp_link_clock(struct drm_connector *connector,
-						const u8 dpcd[DP_DPCD_SIZE],
-						int pix_clock)
+						 unsigned pix_clock,
+						 unsigned *dp_lanes, unsigned *dp_rate)
 {
-	int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
-	int lane_num, max_pix_clock;
+	unsigned bpp =
+		amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
+	static const unsigned link_rates[3] = { 162000, 270000, 540000 };
+	unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
+	unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+	unsigned lane_num, i, max_pix_clock;
 
 	if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
-	    ENCODER_OBJECT_ID_NUTMEG)
-		return 270000;
-
-	lane_num = amdgpu_atombios_dp_get_dp_lane_number(connector, dpcd, pix_clock);
-	max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(162000, lane_num, bpp);
-	if (pix_clock <= max_pix_clock)
-		return 162000;
-	max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(270000, lane_num, bpp);
-	if (pix_clock <= max_pix_clock)
-		return 270000;
-	if (amdgpu_connector_is_dp12_capable(connector)) {
-		max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(540000, lane_num, bpp);
-		if (pix_clock <= max_pix_clock)
-			return 540000;
+	    ENCODER_OBJECT_ID_NUTMEG) {
+		for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+			max_pix_clock = (lane_num * 270000 * 8) / bpp;
+			if (max_pix_clock >= pix_clock) {
+				*dp_lanes = lane_num;
+				*dp_rate = 270000;
+				return 0;
+			}
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
+			for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+				max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+				if (max_pix_clock >= pix_clock) {
+					*dp_lanes = lane_num;
+					*dp_rate = link_rates[i];
+					return 0;
+				}
+			}
+		}
 	}
 
-	return drm_dp_max_link_rate(dpcd);
+	return -EINVAL;
 }
 
 static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev,
@@ -422,6 +402,7 @@
 {
 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 	struct amdgpu_connector_atom_dig *dig_connector;
+	int ret;
 
 	if (!amdgpu_connector->con_priv)
 		return;
@@ -429,10 +410,14 @@
 
 	if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
 	    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
-		dig_connector->dp_clock =
-			amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
-		dig_connector->dp_lane_count =
-			amdgpu_atombios_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+		ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
+							    mode->clock,
+							    &dig_connector->dp_lane_count,
+							    &dig_connector->dp_clock);
+		if (ret) {
+			dig_connector->dp_clock = 0;
+			dig_connector->dp_lane_count = 0;
+		}
 	}
 }
 
@@ -441,14 +426,17 @@
 {
 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 	struct amdgpu_connector_atom_dig *dig_connector;
-	int dp_clock;
+	unsigned dp_lanes, dp_clock;
+	int ret;
 
 	if (!amdgpu_connector->con_priv)
 		return MODE_CLOCK_HIGH;
 	dig_connector = amdgpu_connector->con_priv;
 
-	dp_clock =
-		amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+	ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
+						    mode->clock, &dp_lanes, &dp_clock);
+	if (ret)
+		return MODE_CLOCK_HIGH;
 
 	if ((dp_clock == 540000) &&
 	    (!amdgpu_connector_is_dp12_capable(connector)))
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
@@ -98,6 +98,7 @@
 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 			if (dig->backlight_level == 0)
 				amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
 								       ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
@@ -298,6 +299,10 @@
 	    && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
 		adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
 
+	/* vertical FP must be at least 1 */
+	if (mode->crtc_vsync_start == mode->crtc_vdisplay)
+		adjusted_mode->crtc_vsync_start++;
+
 	/* get the native mode for scaling */
 	if (amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT))
 		amdgpu_panel_mode_fixup(encoder, adjusted_mode);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
@@ -31,6 +31,7 @@
 #include "ci_dpm.h"
 #include "gfx_v7_0.h"
 #include "atom.h"
+#include "amd_pcie.h"
 #include <linux/seq_file.h>
 
 #include "smu/smu_7_0_1_d.h"
@@ -893,6 +894,12 @@
 	u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
 	u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300;
 
+	/* disable mclk switching if the refresh is >120Hz, even if the
+	 * blanking period would allow it
+	 */
+	if (amdgpu_dpm_get_vrefresh(adev) > 120)
+		return true;
+
 	if (vblank_time < switch_limit)
 		return true;
 	else
@@ -1395,7 +1402,6 @@
 		ci_fan_ctrl_set_default_mode(adev);
 }
 
-#if 0
 static int ci_read_smc_soft_register(struct amdgpu_device *adev,
 				     u16 reg_offset, u32 *value)
 {
@@ -1405,7 +1411,6 @@
 				      pi->soft_regs_start + reg_offset,
 				      value, pi->sram_end);
 }
-#endif
 
 static int ci_write_smc_soft_register(struct amdgpu_device *adev,
 				      u16 reg_offset, u32 value)
@@ -5837,18 +5842,16 @@
 	u8 frev, crev;
 	struct ci_power_info *pi;
 	int ret;
-	u32 mask;
 
 	pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL);
 	if (pi == NULL)
 		return -ENOMEM;
 	adev->pm.dpm.priv = pi;
 
-	ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
-	if (ret)
-		pi->sys_pcie_mask = 0;
-	else
-		pi->sys_pcie_mask = mask;
+	pi->sys_pcie_mask =
+		(adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >>
+		CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT;
+
 	pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
 
 	pi->pcie_gen_performance.max = AMDGPU_PCIE_GEN1;
@@ -6084,11 +6087,23 @@
 	struct amdgpu_ps *rps = &pi->current_rps;
 	u32 sclk = ci_get_average_sclk_freq(adev);
 	u32 mclk = ci_get_average_mclk_freq(adev);
+	u32 activity_percent = 50;
+	int ret;
+
+	ret = ci_read_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, AverageGraphicsA),
+					&activity_percent);
+
+	if (ret == 0) {
+		activity_percent += 0x80;
+		activity_percent >>= 8;
+		activity_percent = activity_percent > 100 ? 100 : activity_percent;
+	}
 
 	seq_printf(m, "uvd %sabled\n", pi->uvd_enabled ? "en" : "dis");
 	seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis");
 	seq_printf(m, "power level avg    sclk: %u mclk: %u\n",
 		   sclk, mclk);
+	seq_printf(m, "GPU load: %u %%\n", activity_percent);
 }
 
 static void ci_dpm_print_power_state(struct amdgpu_device *adev,
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/cik.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/cik.c
@@ -32,6 +32,7 @@
 #include "amdgpu_vce.h"
 #include "cikd.h"
 #include "atom.h"
+#include "amd_pcie.h"
 
 #include "cik.h"
 #include "gmc_v7_0.h"
@@ -65,6 +66,7 @@
 #include "oss/oss_2_0_sh_mask.h"
 
 #include "amdgpu_amdkfd.h"
+#include "amdgpu_powerplay.h"
 
 /*
  * Indirect registers accessor
@@ -929,6 +931,37 @@
 	return r;
 }
 
+static bool cik_read_bios_from_rom(struct amdgpu_device *adev,
+				   u8 *bios, u32 length_bytes)
+{
+	u32 *dw_ptr;
+	unsigned long flags;
+	u32 i, length_dw;
+
+	if (bios == NULL)
+		return false;
+	if (length_bytes == 0)
+		return false;
+	/* APU vbios image is part of sbios image */
+	if (adev->flags & AMD_IS_APU)
+		return false;
+
+	dw_ptr = (u32 *)bios;
+	length_dw = ALIGN(length_bytes, 4) / 4;
+	/* take the smc lock since we are using the smc index */
+	spin_lock_irqsave(&adev->smc_idx_lock, flags);
+	/* set rom index to 0 */
+	WREG32(mmSMC_IND_INDEX_0, ixROM_INDEX);
+	WREG32(mmSMC_IND_DATA_0, 0);
+	/* set index to data for continous read */
+	WREG32(mmSMC_IND_INDEX_0, ixROM_DATA);
+	for (i = 0; i < length_dw; i++)
+		dw_ptr[i] = RREG32(mmSMC_IND_DATA_0);
+	spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+	return true;
+}
+
 static struct amdgpu_allowed_register_entry cik_allowed_read_registers[] = {
 	{mmGRBM_STATUS, false},
 	{mmGB_ADDR_CONFIG, false},
@@ -1563,8 +1596,8 @@
 {
 	struct pci_dev *root = adev->pdev->bus->self;
 	int bridge_pos, gpu_pos;
-	u32 speed_cntl, mask, current_data_rate;
-	int ret, i;
+	u32 speed_cntl, current_data_rate;
+	int i;
 	u16 tmp16;
 
 	if (pci_is_root_bus(adev->pdev->bus))
@@ -1576,23 +1609,20 @@
 	if (adev->flags & AMD_IS_APU)
 		return;
 
-	ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
-	if (ret != 0)
-		return;
-
-	if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
+	if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
+					CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)))
 		return;
 
 	speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL);
 	current_data_rate = (speed_cntl & PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) >>
 		PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
-	if (mask & DRM_PCIE_SPEED_80) {
+	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
 		if (current_data_rate == 2) {
 			DRM_INFO("PCIE gen 3 link speeds already enabled\n");
 			return;
 		}
 		DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n");
-	} else if (mask & DRM_PCIE_SPEED_50) {
+	} else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) {
 		if (current_data_rate == 1) {
 			DRM_INFO("PCIE gen 2 link speeds already enabled\n");
 			return;
@@ -1608,7 +1638,7 @@
 	if (!gpu_pos)
 		return;
 
-	if (mask & DRM_PCIE_SPEED_80) {
+	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
 		/* re-try equalization if gen3 is not already enabled */
 		if (current_data_rate != 2) {
 			u16 bridge_cfg, gpu_cfg;
@@ -1703,9 +1733,9 @@
 
 	pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
 	tmp16 &= ~0xf;
-	if (mask & DRM_PCIE_SPEED_80)
+	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
 		tmp16 |= 3; /* gen3 */
-	else if (mask & DRM_PCIE_SPEED_50)
+	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
 		tmp16 |= 2; /* gen2 */
 	else
 		tmp16 |= 1; /* gen1 */
@@ -1732,6 +1762,9 @@
 	if (amdgpu_aspm == 0)
 		return;
 
+	if (pci_is_root_bus(adev->pdev->bus))
+		return;
+
 	/* XXX double check APUs */
 	if (adev->flags & AMD_IS_APU)
 		return;
@@ -1922,7 +1955,7 @@
 		.major = 7,
 		.minor = 0,
 		.rev = 0,
-		.funcs = &ci_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -1990,7 +2023,7 @@
 		.major = 7,
 		.minor = 0,
 		.rev = 0,
-		.funcs = &ci_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -2058,7 +2091,7 @@
 		.major = 7,
 		.minor = 0,
 		.rev = 0,
-		.funcs = &kv_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -2126,7 +2159,7 @@
 		.major = 7,
 		.minor = 0,
 		.rev = 0,
-		.funcs = &kv_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -2194,7 +2227,7 @@
 		.major = 7,
 		.minor = 0,
 		.rev = 0,
-		.funcs = &kv_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -2267,6 +2300,7 @@
 static const struct amdgpu_asic_funcs cik_asic_funcs =
 {
 	.read_disabled_bios = &cik_read_disabled_bios,
+	.read_bios_from_rom = &cik_read_bios_from_rom,
 	.read_register = &cik_read_register,
 	.reset = &cik_asic_reset,
 	.set_vga_state = &cik_vga_set_state,
@@ -2301,72 +2335,72 @@
 	switch (adev->asic_type) {
 	case CHIP_BONAIRE:
 		adev->cg_flags =
-			AMDGPU_CG_SUPPORT_GFX_MGCG |
-			AMDGPU_CG_SUPPORT_GFX_MGLS |
-			/*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
-			AMDGPU_CG_SUPPORT_GFX_CGLS |
-			AMDGPU_CG_SUPPORT_GFX_CGTS |
-			AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
-			AMDGPU_CG_SUPPORT_GFX_CP_LS |
-			AMDGPU_CG_SUPPORT_MC_LS |
-			AMDGPU_CG_SUPPORT_MC_MGCG |
-			AMDGPU_CG_SUPPORT_SDMA_MGCG |
-			AMDGPU_CG_SUPPORT_SDMA_LS |
-			AMDGPU_CG_SUPPORT_BIF_LS |
-			AMDGPU_CG_SUPPORT_VCE_MGCG |
-			AMDGPU_CG_SUPPORT_UVD_MGCG |
-			AMDGPU_CG_SUPPORT_HDP_LS |
-			AMDGPU_CG_SUPPORT_HDP_MGCG;
+			AMD_CG_SUPPORT_GFX_MGCG |
+			AMD_CG_SUPPORT_GFX_MGLS |
+			/*AMD_CG_SUPPORT_GFX_CGCG |*/
+			AMD_CG_SUPPORT_GFX_CGLS |
+			AMD_CG_SUPPORT_GFX_CGTS |
+			AMD_CG_SUPPORT_GFX_CGTS_LS |
+			AMD_CG_SUPPORT_GFX_CP_LS |
+			AMD_CG_SUPPORT_MC_LS |
+			AMD_CG_SUPPORT_MC_MGCG |
+			AMD_CG_SUPPORT_SDMA_MGCG |
+			AMD_CG_SUPPORT_SDMA_LS |
+			AMD_CG_SUPPORT_BIF_LS |
+			AMD_CG_SUPPORT_VCE_MGCG |
+			AMD_CG_SUPPORT_UVD_MGCG |
+			AMD_CG_SUPPORT_HDP_LS |
+			AMD_CG_SUPPORT_HDP_MGCG;
 		adev->pg_flags = 0;
 		adev->external_rev_id = adev->rev_id + 0x14;
 		break;
 	case CHIP_HAWAII:
 		adev->cg_flags =
-			AMDGPU_CG_SUPPORT_GFX_MGCG |
-			AMDGPU_CG_SUPPORT_GFX_MGLS |
-			/*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
-			AMDGPU_CG_SUPPORT_GFX_CGLS |
-			AMDGPU_CG_SUPPORT_GFX_CGTS |
-			AMDGPU_CG_SUPPORT_GFX_CP_LS |
-			AMDGPU_CG_SUPPORT_MC_LS |
-			AMDGPU_CG_SUPPORT_MC_MGCG |
-			AMDGPU_CG_SUPPORT_SDMA_MGCG |
-			AMDGPU_CG_SUPPORT_SDMA_LS |
-			AMDGPU_CG_SUPPORT_BIF_LS |
-			AMDGPU_CG_SUPPORT_VCE_MGCG |
-			AMDGPU_CG_SUPPORT_UVD_MGCG |
-			AMDGPU_CG_SUPPORT_HDP_LS |
-			AMDGPU_CG_SUPPORT_HDP_MGCG;
+			AMD_CG_SUPPORT_GFX_MGCG |
+			AMD_CG_SUPPORT_GFX_MGLS |
+			/*AMD_CG_SUPPORT_GFX_CGCG |*/
+			AMD_CG_SUPPORT_GFX_CGLS |
+			AMD_CG_SUPPORT_GFX_CGTS |
+			AMD_CG_SUPPORT_GFX_CP_LS |
+			AMD_CG_SUPPORT_MC_LS |
+			AMD_CG_SUPPORT_MC_MGCG |
+			AMD_CG_SUPPORT_SDMA_MGCG |
+			AMD_CG_SUPPORT_SDMA_LS |
+			AMD_CG_SUPPORT_BIF_LS |
+			AMD_CG_SUPPORT_VCE_MGCG |
+			AMD_CG_SUPPORT_UVD_MGCG |
+			AMD_CG_SUPPORT_HDP_LS |
+			AMD_CG_SUPPORT_HDP_MGCG;
 		adev->pg_flags = 0;
 		adev->external_rev_id = 0x28;
 		break;
 	case CHIP_KAVERI:
 		adev->cg_flags =
-			AMDGPU_CG_SUPPORT_GFX_MGCG |
-			AMDGPU_CG_SUPPORT_GFX_MGLS |
-			/*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
-			AMDGPU_CG_SUPPORT_GFX_CGLS |
-			AMDGPU_CG_SUPPORT_GFX_CGTS |
-			AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
-			AMDGPU_CG_SUPPORT_GFX_CP_LS |
-			AMDGPU_CG_SUPPORT_SDMA_MGCG |
-			AMDGPU_CG_SUPPORT_SDMA_LS |
-			AMDGPU_CG_SUPPORT_BIF_LS |
-			AMDGPU_CG_SUPPORT_VCE_MGCG |
-			AMDGPU_CG_SUPPORT_UVD_MGCG |
-			AMDGPU_CG_SUPPORT_HDP_LS |
-			AMDGPU_CG_SUPPORT_HDP_MGCG;
+			AMD_CG_SUPPORT_GFX_MGCG |
+			AMD_CG_SUPPORT_GFX_MGLS |
+			/*AMD_CG_SUPPORT_GFX_CGCG |*/
+			AMD_CG_SUPPORT_GFX_CGLS |
+			AMD_CG_SUPPORT_GFX_CGTS |
+			AMD_CG_SUPPORT_GFX_CGTS_LS |
+			AMD_CG_SUPPORT_GFX_CP_LS |
+			AMD_CG_SUPPORT_SDMA_MGCG |
+			AMD_CG_SUPPORT_SDMA_LS |
+			AMD_CG_SUPPORT_BIF_LS |
+			AMD_CG_SUPPORT_VCE_MGCG |
+			AMD_CG_SUPPORT_UVD_MGCG |
+			AMD_CG_SUPPORT_HDP_LS |
+			AMD_CG_SUPPORT_HDP_MGCG;
 		adev->pg_flags =
-			/*AMDGPU_PG_SUPPORT_GFX_PG |
-			  AMDGPU_PG_SUPPORT_GFX_SMG |
-			  AMDGPU_PG_SUPPORT_GFX_DMG |*/
-			AMDGPU_PG_SUPPORT_UVD |
-			/*AMDGPU_PG_SUPPORT_VCE |
-			  AMDGPU_PG_SUPPORT_CP |
-			  AMDGPU_PG_SUPPORT_GDS |
-			  AMDGPU_PG_SUPPORT_RLC_SMU_HS |
-			  AMDGPU_PG_SUPPORT_ACP |
-			  AMDGPU_PG_SUPPORT_SAMU |*/
+			/*AMD_PG_SUPPORT_GFX_PG |
+			  AMD_PG_SUPPORT_GFX_SMG |
+			  AMD_PG_SUPPORT_GFX_DMG |*/
+			AMD_PG_SUPPORT_UVD |
+			/*AMD_PG_SUPPORT_VCE |
+			  AMD_PG_SUPPORT_CP |
+			  AMD_PG_SUPPORT_GDS |
+			  AMD_PG_SUPPORT_RLC_SMU_HS |
+			  AMD_PG_SUPPORT_ACP |
+			  AMD_PG_SUPPORT_SAMU |*/
 			0;
 		if (adev->pdev->device == 0x1312 ||
 			adev->pdev->device == 0x1316 ||
@@ -2378,29 +2412,29 @@
 	case CHIP_KABINI:
 	case CHIP_MULLINS:
 		adev->cg_flags =
-			AMDGPU_CG_SUPPORT_GFX_MGCG |
-			AMDGPU_CG_SUPPORT_GFX_MGLS |
-			/*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
-			AMDGPU_CG_SUPPORT_GFX_CGLS |
-			AMDGPU_CG_SUPPORT_GFX_CGTS |
-			AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
-			AMDGPU_CG_SUPPORT_GFX_CP_LS |
-			AMDGPU_CG_SUPPORT_SDMA_MGCG |
-			AMDGPU_CG_SUPPORT_SDMA_LS |
-			AMDGPU_CG_SUPPORT_BIF_LS |
-			AMDGPU_CG_SUPPORT_VCE_MGCG |
-			AMDGPU_CG_SUPPORT_UVD_MGCG |
-			AMDGPU_CG_SUPPORT_HDP_LS |
-			AMDGPU_CG_SUPPORT_HDP_MGCG;
+			AMD_CG_SUPPORT_GFX_MGCG |
+			AMD_CG_SUPPORT_GFX_MGLS |
+			/*AMD_CG_SUPPORT_GFX_CGCG |*/
+			AMD_CG_SUPPORT_GFX_CGLS |
+			AMD_CG_SUPPORT_GFX_CGTS |
+			AMD_CG_SUPPORT_GFX_CGTS_LS |
+			AMD_CG_SUPPORT_GFX_CP_LS |
+			AMD_CG_SUPPORT_SDMA_MGCG |
+			AMD_CG_SUPPORT_SDMA_LS |
+			AMD_CG_SUPPORT_BIF_LS |
+			AMD_CG_SUPPORT_VCE_MGCG |
+			AMD_CG_SUPPORT_UVD_MGCG |
+			AMD_CG_SUPPORT_HDP_LS |
+			AMD_CG_SUPPORT_HDP_MGCG;
 		adev->pg_flags =
-			/*AMDGPU_PG_SUPPORT_GFX_PG |
-			  AMDGPU_PG_SUPPORT_GFX_SMG | */
-			AMDGPU_PG_SUPPORT_UVD |
-			/*AMDGPU_PG_SUPPORT_VCE |
-			  AMDGPU_PG_SUPPORT_CP |
-			  AMDGPU_PG_SUPPORT_GDS |
-			  AMDGPU_PG_SUPPORT_RLC_SMU_HS |
-			  AMDGPU_PG_SUPPORT_SAMU |*/
+			/*AMD_PG_SUPPORT_GFX_PG |
+			  AMD_PG_SUPPORT_GFX_SMG | */
+			AMD_PG_SUPPORT_UVD |
+			/*AMD_PG_SUPPORT_VCE |
+			  AMD_PG_SUPPORT_CP |
+			  AMD_PG_SUPPORT_GDS |
+			  AMD_PG_SUPPORT_RLC_SMU_HS |
+			  AMD_PG_SUPPORT_SAMU |*/
 			0;
 		if (adev->asic_type == CHIP_KABINI) {
 			if (adev->rev_id == 0)
@@ -2417,6 +2451,8 @@
 		return -EINVAL;
 	}
 
+	amdgpu_get_pcie_info(adev);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/cik_ih.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/cik_ih.c
@@ -202,6 +202,12 @@
 		tmp = RREG32(mmIH_RB_CNTL);
 		tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
 		WREG32(mmIH_RB_CNTL, tmp);
+
+		/* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+		 * can be detected.
+		 */
+		tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
+		WREG32(mmIH_RB_CNTL, tmp);
 	}
 	return (wptr & adev->irq.ih.ptr_mask);
 }
@@ -274,6 +280,11 @@
 static int cik_ih_early_init(void *handle)
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	int ret;
+
+	ret = amdgpu_irq_add_domain(adev);
+	if (ret)
+		return ret;
 
 	cik_ih_set_interrupt_funcs(adev);
 
@@ -300,6 +311,7 @@
 
 	amdgpu_irq_fini(adev);
 	amdgpu_ih_ring_fini(adev);
+	amdgpu_irq_remove_domain(adev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -52,6 +52,7 @@
 static void cik_sdma_set_irq_funcs(struct amdgpu_device *adev);
 static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev);
 static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev);
+static int cik_sdma_soft_reset(void *handle);
 
 MODULE_FIRMWARE("radeon/bonaire_sdma.bin");
 MODULE_FIRMWARE("radeon/bonaire_sdma1.bin");
@@ -885,7 +886,7 @@
 {
 	u32 orig, data;
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_SDMA_MGCG)) {
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_SDMA_MGCG)) {
 		WREG32(mmSDMA0_CLK_CTRL + SDMA0_REGISTER_OFFSET, 0x00000100);
 		WREG32(mmSDMA0_CLK_CTRL + SDMA1_REGISTER_OFFSET, 0x00000100);
 	} else {
@@ -906,7 +907,7 @@
 {
 	u32 orig, data;
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_SDMA_LS)) {
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_SDMA_LS)) {
 		orig = data = RREG32(mmSDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET);
 		data |= 0x100;
 		if (orig != data)
@@ -1030,6 +1031,8 @@
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	cik_sdma_soft_reset(handle);
+
 	return cik_sdma_hw_init(adev);
 }
 
@@ -1115,22 +1118,19 @@
 {
 	u32 srbm_soft_reset = 0;
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-	u32 tmp = RREG32(mmSRBM_STATUS2);
+	u32 tmp;
 
-	if (tmp & SRBM_STATUS2__SDMA_BUSY_MASK) {
-		/* sdma0 */
-		tmp = RREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET);
-		tmp |= SDMA0_F32_CNTL__HALT_MASK;
-		WREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET, tmp);
-		srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK;
-	}
-	if (tmp & SRBM_STATUS2__SDMA1_BUSY_MASK) {
-		/* sdma1 */
-		tmp = RREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET);
-		tmp |= SDMA0_F32_CNTL__HALT_MASK;
-		WREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET, tmp);
-		srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK;
-	}
+	/* sdma0 */
+	tmp = RREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET);
+	tmp |= SDMA0_F32_CNTL__HALT_MASK;
+	WREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+	srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK;
+
+	/* sdma1 */
+	tmp = RREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET);
+	tmp |= SDMA0_F32_CNTL__HALT_MASK;
+	WREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+	srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK;
 
 	if (srbm_soft_reset) {
 		cik_sdma_print_status((void *)adev);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
@@ -445,13 +445,13 @@
 	pi->gfx_pg_threshold = 500;
 	pi->caps_fps = true;
 	/* uvd */
-	pi->caps_uvd_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_UVD) ? true : false;
+	pi->caps_uvd_pg = (adev->pg_flags & AMD_PG_SUPPORT_UVD) ? true : false;
 	pi->caps_uvd_dpm = true;
 	/* vce */
-	pi->caps_vce_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_VCE) ? true : false;
+	pi->caps_vce_pg = (adev->pg_flags & AMD_PG_SUPPORT_VCE) ? true : false;
 	pi->caps_vce_dpm = true;
 	/* acp */
-	pi->caps_acp_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_ACP) ? true : false;
+	pi->caps_acp_pg = (adev->pg_flags & AMD_PG_SUPPORT_ACP) ? true : false;
 	pi->caps_acp_dpm = true;
 
 	pi->caps_stable_power_state = false;
@@ -1078,6 +1078,37 @@
 	return i;
 }
 
+static uint32_t cz_get_uvd_level(struct amdgpu_device *adev,
+				 uint32_t clock, uint16_t msg)
+{
+	int i = 0;
+	struct amdgpu_uvd_clock_voltage_dependency_table *table =
+		&adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+
+	switch (msg) {
+	case PPSMC_MSG_SetUvdSoftMin:
+	case PPSMC_MSG_SetUvdHardMin:
+		for (i = 0; i < table->count; i++)
+			if (clock <= table->entries[i].vclk)
+				break;
+		if (i == table->count)
+			i = table->count - 1;
+		break;
+	case PPSMC_MSG_SetUvdSoftMax:
+	case PPSMC_MSG_SetUvdHardMax:
+		for (i = table->count - 1; i >= 0; i--)
+			if (clock >= table->entries[i].vclk)
+				break;
+		if (i < 0)
+			i = 0;
+		break;
+	default:
+		break;
+	}
+
+	return i;
+}
+
 static int cz_program_bootup_state(struct amdgpu_device *adev)
 {
 	struct cz_power_info *pi = cz_get_pi(adev);
@@ -1739,6 +1770,200 @@
 	return 0;
 }
 
+static int cz_dpm_uvd_force_highest(struct amdgpu_device *adev)
+{
+	struct cz_power_info *pi = cz_get_pi(adev);
+	int ret = 0;
+
+	if (pi->uvd_dpm.soft_min_clk != pi->uvd_dpm.soft_max_clk) {
+		pi->uvd_dpm.soft_min_clk =
+			pi->uvd_dpm.soft_max_clk;
+		ret = cz_send_msg_to_smc_with_parameter(adev,
+				PPSMC_MSG_SetUvdSoftMin,
+				cz_get_uvd_level(adev,
+					pi->uvd_dpm.soft_min_clk,
+					PPSMC_MSG_SetUvdSoftMin));
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int cz_dpm_uvd_force_lowest(struct amdgpu_device *adev)
+{
+	struct cz_power_info *pi = cz_get_pi(adev);
+	int ret = 0;
+
+	if (pi->uvd_dpm.soft_max_clk != pi->uvd_dpm.soft_min_clk) {
+		pi->uvd_dpm.soft_max_clk = pi->uvd_dpm.soft_min_clk;
+		ret = cz_send_msg_to_smc_with_parameter(adev,
+				PPSMC_MSG_SetUvdSoftMax,
+				cz_get_uvd_level(adev,
+					pi->uvd_dpm.soft_max_clk,
+					PPSMC_MSG_SetUvdSoftMax));
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static uint32_t cz_dpm_get_max_uvd_level(struct amdgpu_device *adev)
+{
+	struct cz_power_info *pi = cz_get_pi(adev);
+
+	if (!pi->max_uvd_level) {
+		cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxUvdLevel);
+		pi->max_uvd_level = cz_get_argument(adev) + 1;
+	}
+
+	if (pi->max_uvd_level > CZ_MAX_HARDWARE_POWERLEVELS) {
+		DRM_ERROR("Invalid max uvd level!\n");
+		return -EINVAL;
+	}
+
+	return pi->max_uvd_level;
+}
+
+static int cz_dpm_unforce_uvd_dpm_levels(struct amdgpu_device *adev)
+{
+	struct cz_power_info *pi = cz_get_pi(adev);
+	struct amdgpu_uvd_clock_voltage_dependency_table *dep_table =
+		&adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+	uint32_t level = 0;
+	int ret = 0;
+
+	pi->uvd_dpm.soft_min_clk = dep_table->entries[0].vclk;
+	level = cz_dpm_get_max_uvd_level(adev) - 1;
+	if (level < dep_table->count)
+		pi->uvd_dpm.soft_max_clk = dep_table->entries[level].vclk;
+	else
+		pi->uvd_dpm.soft_max_clk =
+			dep_table->entries[dep_table->count - 1].vclk;
+
+	/* get min/max sclk soft value
+	 * notify SMU to execute */
+	ret = cz_send_msg_to_smc_with_parameter(adev,
+				PPSMC_MSG_SetUvdSoftMin,
+				cz_get_uvd_level(adev,
+					pi->uvd_dpm.soft_min_clk,
+					PPSMC_MSG_SetUvdSoftMin));
+	if (ret)
+		return ret;
+
+	ret = cz_send_msg_to_smc_with_parameter(adev,
+				PPSMC_MSG_SetUvdSoftMax,
+				cz_get_uvd_level(adev,
+					pi->uvd_dpm.soft_max_clk,
+					PPSMC_MSG_SetUvdSoftMax));
+	if (ret)
+		return ret;
+
+	DRM_DEBUG("DPM uvd unforce state min=%d, max=%d.\n",
+		  pi->uvd_dpm.soft_min_clk,
+		  pi->uvd_dpm.soft_max_clk);
+
+	return 0;
+}
+
+static int cz_dpm_vce_force_highest(struct amdgpu_device *adev)
+{
+	struct cz_power_info *pi = cz_get_pi(adev);
+	int ret = 0;
+
+	if (pi->vce_dpm.soft_min_clk != pi->vce_dpm.soft_max_clk) {
+		pi->vce_dpm.soft_min_clk =
+			pi->vce_dpm.soft_max_clk;
+		ret = cz_send_msg_to_smc_with_parameter(adev,
+				PPSMC_MSG_SetEclkSoftMin,
+				cz_get_eclk_level(adev,
+					pi->vce_dpm.soft_min_clk,
+					PPSMC_MSG_SetEclkSoftMin));
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int cz_dpm_vce_force_lowest(struct amdgpu_device *adev)
+{
+	struct cz_power_info *pi = cz_get_pi(adev);
+	int ret = 0;
+
+	if (pi->vce_dpm.soft_max_clk != pi->vce_dpm.soft_min_clk) {
+		pi->vce_dpm.soft_max_clk = pi->vce_dpm.soft_min_clk;
+		ret = cz_send_msg_to_smc_with_parameter(adev,
+				PPSMC_MSG_SetEclkSoftMax,
+				cz_get_uvd_level(adev,
+					pi->vce_dpm.soft_max_clk,
+					PPSMC_MSG_SetEclkSoftMax));
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static uint32_t cz_dpm_get_max_vce_level(struct amdgpu_device *adev)
+{
+	struct cz_power_info *pi = cz_get_pi(adev);
+
+	if (!pi->max_vce_level) {
+		cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxEclkLevel);
+		pi->max_vce_level = cz_get_argument(adev) + 1;
+	}
+
+	if (pi->max_vce_level > CZ_MAX_HARDWARE_POWERLEVELS) {
+		DRM_ERROR("Invalid max vce level!\n");
+		return -EINVAL;
+	}
+
+	return pi->max_vce_level;
+}
+
+static int cz_dpm_unforce_vce_dpm_levels(struct amdgpu_device *adev)
+{
+	struct cz_power_info *pi = cz_get_pi(adev);
+	struct amdgpu_vce_clock_voltage_dependency_table *dep_table =
+		&adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+	uint32_t level = 0;
+	int ret = 0;
+
+	pi->vce_dpm.soft_min_clk = dep_table->entries[0].ecclk;
+	level = cz_dpm_get_max_vce_level(adev) - 1;
+	if (level < dep_table->count)
+		pi->vce_dpm.soft_max_clk = dep_table->entries[level].ecclk;
+	else
+		pi->vce_dpm.soft_max_clk =
+			dep_table->entries[dep_table->count - 1].ecclk;
+
+	/* get min/max sclk soft value
+	 * notify SMU to execute */
+	ret = cz_send_msg_to_smc_with_parameter(adev,
+				PPSMC_MSG_SetEclkSoftMin,
+				cz_get_eclk_level(adev,
+					pi->vce_dpm.soft_min_clk,
+					PPSMC_MSG_SetEclkSoftMin));
+	if (ret)
+		return ret;
+
+	ret = cz_send_msg_to_smc_with_parameter(adev,
+				PPSMC_MSG_SetEclkSoftMax,
+				cz_get_eclk_level(adev,
+					pi->vce_dpm.soft_max_clk,
+					PPSMC_MSG_SetEclkSoftMax));
+	if (ret)
+		return ret;
+
+	DRM_DEBUG("DPM vce unforce state min=%d, max=%d.\n",
+		  pi->vce_dpm.soft_min_clk,
+		  pi->vce_dpm.soft_max_clk);
+
+	return 0;
+}
+
 static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
 				  enum amdgpu_dpm_forced_level level)
 {
@@ -1746,25 +1971,70 @@
 
 	switch (level) {
 	case AMDGPU_DPM_FORCED_LEVEL_HIGH:
+		/* sclk */
 		ret = cz_dpm_unforce_dpm_levels(adev);
 		if (ret)
 			return ret;
 		ret = cz_dpm_force_highest(adev);
 		if (ret)
 			return ret;
+
+		/* uvd */
+		ret = cz_dpm_unforce_uvd_dpm_levels(adev);
+		if (ret)
+			return ret;
+		ret = cz_dpm_uvd_force_highest(adev);
+		if (ret)
+			return ret;
+
+		/* vce */
+		ret = cz_dpm_unforce_vce_dpm_levels(adev);
+		if (ret)
+			return ret;
+		ret = cz_dpm_vce_force_highest(adev);
+		if (ret)
+			return ret;
 		break;
 	case AMDGPU_DPM_FORCED_LEVEL_LOW:
+		/* sclk */
 		ret = cz_dpm_unforce_dpm_levels(adev);
 		if (ret)
 			return ret;
 		ret = cz_dpm_force_lowest(adev);
 		if (ret)
 			return ret;
+
+		/* uvd */
+		ret = cz_dpm_unforce_uvd_dpm_levels(adev);
+		if (ret)
+			return ret;
+		ret = cz_dpm_uvd_force_lowest(adev);
+		if (ret)
+			return ret;
+
+		/* vce */
+		ret = cz_dpm_unforce_vce_dpm_levels(adev);
+		if (ret)
+			return ret;
+		ret = cz_dpm_vce_force_lowest(adev);
+		if (ret)
+			return ret;
 		break;
 	case AMDGPU_DPM_FORCED_LEVEL_AUTO:
+		/* sclk */
 		ret = cz_dpm_unforce_dpm_levels(adev);
 		if (ret)
 			return ret;
+
+		/* uvd */
+		ret = cz_dpm_unforce_uvd_dpm_levels(adev);
+		if (ret)
+			return ret;
+
+		/* vce */
+		ret = cz_dpm_unforce_vce_dpm_levels(adev);
+		if (ret)
+			return ret;
 		break;
 	default:
 		break;
@@ -1905,7 +2175,8 @@
 		pi->vce_dpm.hard_min_clk = table->entries[table->count-1].ecclk;
 
 	} else { /* non-stable p-state cases. without vce.Arbiter.EcclkHardMin */
-		pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;
+		/* leave it as set by user */
+		/*pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;*/
 	}
 
 	cz_send_msg_to_smc_with_parameter(adev,
@@ -1955,10 +2226,8 @@
 		}
 	} else { /*pi->caps_vce_pg*/
 		cz_update_vce_dpm(adev);
-		cz_enable_vce_dpm(adev, true);
+		cz_enable_vce_dpm(adev, !gate);
 	}
-
-	return;
 }
 
 const struct amd_ip_funcs cz_dpm_ip_funcs = {
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
@@ -183,6 +183,8 @@
 	uint32_t voltage_drop_threshold;
 	uint32_t gfx_pg_threshold;
 	uint32_t max_sclk_level;
+	uint32_t max_uvd_level;
+	uint32_t max_vce_level;
 	/* flags */
 	bool didt_enabled;
 	bool video_start;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/cz_ih.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/cz_ih.c
@@ -192,19 +192,35 @@
 
 	wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
 
-	if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
-		wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
-		/* When a ring buffer overflow happen start parsing interrupt
-		 * from the last not overwritten vector (wptr + 16). Hopefully
-		 * this should allow us to catchup.
-		 */
-		dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
-			wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
-		adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
-		tmp = RREG32(mmIH_RB_CNTL);
-		tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
-		WREG32(mmIH_RB_CNTL, tmp);
-	}
+	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
+		goto out;
+
+	/* Double check that the overflow wasn't already cleared. */
+	wptr = RREG32(mmIH_RB_WPTR);
+
+	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
+		goto out;
+
+	wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
+
+	/* When a ring buffer overflow happen start parsing interrupt
+	 * from the last not overwritten vector (wptr + 16). Hopefully
+	 * this should allow us to catchup.
+	 */
+	dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
+		wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
+	adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+	tmp = RREG32(mmIH_RB_CNTL);
+	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
+	WREG32(mmIH_RB_CNTL, tmp);
+
+	/* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+	 * can be detected.
+	 */
+	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+	WREG32(mmIH_RB_CNTL, tmp);
+
+out:
 	return (wptr & adev->irq.ih.ptr_mask);
 }
 
@@ -253,8 +269,14 @@
 static int cz_ih_early_init(void *handle)
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	int ret;
+
+	ret = amdgpu_irq_add_domain(adev);
+	if (ret)
+		return ret;
 
 	cz_ih_set_interrupt_funcs(adev);
+
 	return 0;
 }
 
@@ -278,6 +300,7 @@
 
 	amdgpu_irq_fini(adev);
 	amdgpu_ih_ring_fini(adev);
+	amdgpu_irq_remove_domain(adev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -419,16 +419,6 @@
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-		    connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-			/* don't try to enable hpd on eDP or LVDS avoid breaking the
-			 * aux dp channel on imac and help (but not completely fix)
-			 * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-			 * also avoid interrupt storms during dpms.
-			 */
-			continue;
-		}
-
 		switch (amdgpu_connector->hpd.hpd) {
 		case AMDGPU_HPD_1:
 			idx = 0;
@@ -452,6 +442,19 @@
 			continue;
 		}
 
+		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+		    connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+			/* don't try to enable hpd on eDP or LVDS avoid breaking the
+			 * aux dp channel on imac and help (but not completely fix)
+			 * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+			 * also avoid interrupt storms during dpms.
+			 */
+			tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx]);
+			tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_EN, 0);
+			WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx], tmp);
+			continue;
+		}
+
 		tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
 		tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 1);
 		WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
@@ -1123,23 +1126,10 @@
 	a.full = dfixed_const(available_bandwidth);
 	b.full = dfixed_const(wm->num_heads);
 	a.full = dfixed_div(a, b);
+	tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
+	tmp = min(dfixed_trunc(a), tmp);
 
-	b.full = dfixed_const(mc_latency + 512);
-	c.full = dfixed_const(wm->disp_clk);
-	b.full = dfixed_div(b, c);
-
-	c.full = dfixed_const(dmif_size);
-	b.full = dfixed_div(c, b);
-
-	tmp = min(dfixed_trunc(a), dfixed_trunc(b));
-
-	b.full = dfixed_const(1000);
-	c.full = dfixed_const(wm->disp_clk);
-	b.full = dfixed_div(c, b);
-	c.full = dfixed_const(wm->bytes_per_pixel);
-	b.full = dfixed_mul(b, c);
-
-	lb_fill_bw = min(tmp, dfixed_trunc(b));
+	lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
 
 	a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
 	b.full = dfixed_const(1000);
@@ -1247,14 +1237,14 @@
 {
 	struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
 	struct dce10_wm_params wm_low, wm_high;
-	u32 pixel_period;
+	u32 active_time;
 	u32 line_time = 0;
 	u32 latency_watermark_a = 0, latency_watermark_b = 0;
 	u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
 
 	if (amdgpu_crtc->base.enabled && num_heads && mode) {
-		pixel_period = 1000000 / (u32)mode->clock;
-		line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+		active_time = 1000000UL * (u32)mode->crtc_hdisplay / (u32)mode->clock;
+		line_time = min((u32) (1000000UL * (u32)mode->crtc_htotal / (u32)mode->clock), (u32)65535);
 
 		/* watermark for high clocks */
 		if (adev->pm.dpm_enabled) {
@@ -1269,7 +1259,7 @@
 
 		wm_high.disp_clk = mode->clock;
 		wm_high.src_width = mode->crtc_hdisplay;
-		wm_high.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_high.active_time = active_time;
 		wm_high.blank_time = line_time - wm_high.active_time;
 		wm_high.interlaced = false;
 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
@@ -1308,7 +1298,7 @@
 
 		wm_low.disp_clk = mode->clock;
 		wm_low.src_width = mode->crtc_hdisplay;
-		wm_low.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_low.active_time = active_time;
 		wm_low.blank_time = line_time - wm_low.active_time;
 		wm_low.interlaced = false;
 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -409,16 +409,6 @@
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-		    connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-			/* don't try to enable hpd on eDP or LVDS avoid breaking the
-			 * aux dp channel on imac and help (but not completely fix)
-			 * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-			 * also avoid interrupt storms during dpms.
-			 */
-			continue;
-		}
-
 		switch (amdgpu_connector->hpd.hpd) {
 		case AMDGPU_HPD_1:
 			idx = 0;
@@ -442,6 +432,19 @@
 			continue;
 		}
 
+		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+		    connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+			/* don't try to enable hpd on eDP or LVDS avoid breaking the
+			 * aux dp channel on imac and help (but not completely fix)
+			 * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+			 * also avoid interrupt storms during dpms.
+			 */
+			tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx]);
+			tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_EN, 0);
+			WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx], tmp);
+			continue;
+		}
+
 		tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
 		tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 1);
 		WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
@@ -1111,23 +1114,10 @@
 	a.full = dfixed_const(available_bandwidth);
 	b.full = dfixed_const(wm->num_heads);
 	a.full = dfixed_div(a, b);
+	tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
+	tmp = min(dfixed_trunc(a), tmp);
 
-	b.full = dfixed_const(mc_latency + 512);
-	c.full = dfixed_const(wm->disp_clk);
-	b.full = dfixed_div(b, c);
-
-	c.full = dfixed_const(dmif_size);
-	b.full = dfixed_div(c, b);
-
-	tmp = min(dfixed_trunc(a), dfixed_trunc(b));
-
-	b.full = dfixed_const(1000);
-	c.full = dfixed_const(wm->disp_clk);
-	b.full = dfixed_div(c, b);
-	c.full = dfixed_const(wm->bytes_per_pixel);
-	b.full = dfixed_mul(b, c);
-
-	lb_fill_bw = min(tmp, dfixed_trunc(b));
+	lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
 
 	a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
 	b.full = dfixed_const(1000);
@@ -1235,14 +1225,14 @@
 {
 	struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
 	struct dce10_wm_params wm_low, wm_high;
-	u32 pixel_period;
+	u32 active_time;
 	u32 line_time = 0;
 	u32 latency_watermark_a = 0, latency_watermark_b = 0;
 	u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
 
 	if (amdgpu_crtc->base.enabled && num_heads && mode) {
-		pixel_period = 1000000 / (u32)mode->clock;
-		line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+		active_time = 1000000UL * (u32)mode->crtc_hdisplay / (u32)mode->clock;
+		line_time = min((u32) (1000000UL * (u32)mode->crtc_htotal / (u32)mode->clock), (u32)65535);
 
 		/* watermark for high clocks */
 		if (adev->pm.dpm_enabled) {
@@ -1257,7 +1247,7 @@
 
 		wm_high.disp_clk = mode->clock;
 		wm_high.src_width = mode->crtc_hdisplay;
-		wm_high.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_high.active_time = active_time;
 		wm_high.blank_time = line_time - wm_high.active_time;
 		wm_high.interlaced = false;
 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
@@ -1296,7 +1286,7 @@
 
 		wm_low.disp_clk = mode->clock;
 		wm_low.src_width = mode->crtc_hdisplay;
-		wm_low.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_low.active_time = active_time;
 		wm_low.blank_time = line_time - wm_low.active_time;
 		wm_low.interlaced = false;
 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
@@ -3030,6 +3020,7 @@
 
 	dce_v11_0_afmt_fini(adev);
 
+	drm_mode_config_cleanup(adev->ddev);
 	adev->mode_info.mode_config_initialized = false;
 
 	return 0;
@@ -3700,9 +3691,15 @@
 	default:
 		encoder->possible_crtcs = 0x3;
 		break;
+	case 3:
+		encoder->possible_crtcs = 0x7;
+		break;
 	case 4:
 		encoder->possible_crtcs = 0xf;
 		break;
+	case 5:
+		encoder->possible_crtcs = 0x1f;
+		break;
 	case 6:
 		encoder->possible_crtcs = 0x3f;
 		break;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -392,15 +392,6 @@
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-		    connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-			/* don't try to enable hpd on eDP or LVDS avoid breaking the
-			 * aux dp channel on imac and help (but not completely fix)
-			 * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-			 * also avoid interrupt storms during dpms.
-			 */
-			continue;
-		}
 		switch (amdgpu_connector->hpd.hpd) {
 		case AMDGPU_HPD_1:
 			WREG32(mmDC_HPD1_CONTROL, tmp);
@@ -423,6 +414,45 @@
 		default:
 			break;
 		}
+
+		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+		    connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+			/* don't try to enable hpd on eDP or LVDS avoid breaking the
+			 * aux dp channel on imac and help (but not completely fix)
+			 * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+			 * also avoid interrupt storms during dpms.
+			 */
+			u32 dc_hpd_int_cntl_reg, dc_hpd_int_cntl;
+
+			switch (amdgpu_connector->hpd.hpd) {
+			case AMDGPU_HPD_1:
+				dc_hpd_int_cntl_reg = mmDC_HPD1_INT_CONTROL;
+				break;
+			case AMDGPU_HPD_2:
+				dc_hpd_int_cntl_reg = mmDC_HPD2_INT_CONTROL;
+				break;
+			case AMDGPU_HPD_3:
+				dc_hpd_int_cntl_reg = mmDC_HPD3_INT_CONTROL;
+				break;
+			case AMDGPU_HPD_4:
+				dc_hpd_int_cntl_reg = mmDC_HPD4_INT_CONTROL;
+				break;
+			case AMDGPU_HPD_5:
+				dc_hpd_int_cntl_reg = mmDC_HPD5_INT_CONTROL;
+				break;
+			case AMDGPU_HPD_6:
+				dc_hpd_int_cntl_reg = mmDC_HPD6_INT_CONTROL;
+				break;
+			default:
+				continue;
+			}
+
+			dc_hpd_int_cntl = RREG32(dc_hpd_int_cntl_reg);
+			dc_hpd_int_cntl &= ~DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK;
+			WREG32(dc_hpd_int_cntl_reg, dc_hpd_int_cntl);
+			continue;
+		}
+
 		dce_v8_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd);
 		amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd);
 	}
@@ -1066,23 +1096,10 @@
 	a.full = dfixed_const(available_bandwidth);
 	b.full = dfixed_const(wm->num_heads);
 	a.full = dfixed_div(a, b);
+	tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
+	tmp = min(dfixed_trunc(a), tmp);
 
-	b.full = dfixed_const(mc_latency + 512);
-	c.full = dfixed_const(wm->disp_clk);
-	b.full = dfixed_div(b, c);
-
-	c.full = dfixed_const(dmif_size);
-	b.full = dfixed_div(c, b);
-
-	tmp = min(dfixed_trunc(a), dfixed_trunc(b));
-
-	b.full = dfixed_const(1000);
-	c.full = dfixed_const(wm->disp_clk);
-	b.full = dfixed_div(c, b);
-	c.full = dfixed_const(wm->bytes_per_pixel);
-	b.full = dfixed_mul(b, c);
-
-	lb_fill_bw = min(tmp, dfixed_trunc(b));
+	lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
 
 	a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
 	b.full = dfixed_const(1000);
@@ -1190,14 +1207,14 @@
 {
 	struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
 	struct dce8_wm_params wm_low, wm_high;
-	u32 pixel_period;
+	u32 active_time;
 	u32 line_time = 0;
 	u32 latency_watermark_a = 0, latency_watermark_b = 0;
 	u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
 
 	if (amdgpu_crtc->base.enabled && num_heads && mode) {
-		pixel_period = 1000000 / (u32)mode->clock;
-		line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+		active_time = 1000000UL * (u32)mode->crtc_hdisplay / (u32)mode->clock;
+		line_time = min((u32) (1000000UL * (u32)mode->crtc_htotal / (u32)mode->clock), (u32)65535);
 
 		/* watermark for high clocks */
 		if (adev->pm.dpm_enabled) {
@@ -1212,7 +1229,7 @@
 
 		wm_high.disp_clk = mode->clock;
 		wm_high.src_width = mode->crtc_hdisplay;
-		wm_high.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_high.active_time = active_time;
 		wm_high.blank_time = line_time - wm_high.active_time;
 		wm_high.interlaced = false;
 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
@@ -1251,7 +1268,7 @@
 
 		wm_low.disp_clk = mode->clock;
 		wm_low.src_width = mode->crtc_hdisplay;
-		wm_low.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_low.active_time = active_time;
 		wm_low.blank_time = line_time - wm_low.active_time;
 		wm_low.interlaced = false;
 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c
@@ -24,7 +24,7 @@
 #include <linux/firmware.h>
 #include "drmP.h"
 #include "amdgpu.h"
-#include "fiji_smumgr.h"
+#include "fiji_smum.h"
 
 MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/fiji_smc.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/fiji_smc.c
@@ -25,7 +25,7 @@
 #include "drmP.h"
 #include "amdgpu.h"
 #include "fiji_ppsmc.h"
-#include "fiji_smumgr.h"
+#include "fiji_smum.h"
 #include "smu_ucode_xfer_vi.h"
 #include "amdgpu_ucode.h"
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/fiji_smum.h
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/fiji_smum.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef FIJI_SMUMGR_H
+#define FIJI_SMUMGR_H
+
+#include "fiji_ppsmc.h"
+
+int fiji_smu_init(struct amdgpu_device *adev);
+int fiji_smu_fini(struct amdgpu_device *adev);
+int fiji_smu_start(struct amdgpu_device *adev);
+
+struct fiji_smu_private_data
+{
+	uint8_t *header;
+	uint32_t smu_buffer_addr_high;
+	uint32_t smu_buffer_addr_low;
+	uint32_t header_addr_high;
+	uint32_t header_addr_low;
+};
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -2104,34 +2104,8 @@
 	case CHIP_KAVERI:
 		adev->gfx.config.max_shader_engines = 1;
 		adev->gfx.config.max_tile_pipes = 4;
-		if ((adev->pdev->device == 0x1304) ||
-		    (adev->pdev->device == 0x1305) ||
-		    (adev->pdev->device == 0x130C) ||
-		    (adev->pdev->device == 0x130F) ||
-		    (adev->pdev->device == 0x1310) ||
-		    (adev->pdev->device == 0x1311) ||
-		    (adev->pdev->device == 0x131C)) {
-			adev->gfx.config.max_cu_per_sh = 8;
-			adev->gfx.config.max_backends_per_se = 2;
-		} else if ((adev->pdev->device == 0x1309) ||
-			   (adev->pdev->device == 0x130A) ||
-			   (adev->pdev->device == 0x130D) ||
-			   (adev->pdev->device == 0x1313) ||
-			   (adev->pdev->device == 0x131D)) {
-			adev->gfx.config.max_cu_per_sh = 6;
-			adev->gfx.config.max_backends_per_se = 2;
-		} else if ((adev->pdev->device == 0x1306) ||
-			   (adev->pdev->device == 0x1307) ||
-			   (adev->pdev->device == 0x130B) ||
-			   (adev->pdev->device == 0x130E) ||
-			   (adev->pdev->device == 0x1315) ||
-			   (adev->pdev->device == 0x131B)) {
-			adev->gfx.config.max_cu_per_sh = 4;
-			adev->gfx.config.max_backends_per_se = 1;
-		} else {
-			adev->gfx.config.max_cu_per_sh = 3;
-			adev->gfx.config.max_backends_per_se = 1;
-		}
+		adev->gfx.config.max_cu_per_sh = 8;
+		adev->gfx.config.max_backends_per_se = 2;
 		adev->gfx.config.max_sh_per_se = 1;
 		adev->gfx.config.max_texture_channel_caches = 4;
 		adev->gfx.config.max_gprs = 256;
@@ -3628,6 +3602,19 @@
 					unsigned vm_id, uint64_t pd_addr)
 {
 	int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX);
+	uint32_t seq = ring->fence_drv.sync_seq[ring->idx];
+	uint64_t addr = ring->fence_drv.gpu_addr;
+
+	amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+	amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
+				 WAIT_REG_MEM_FUNCTION(3) | /* equal */
+				 WAIT_REG_MEM_ENGINE(usepfp)));   /* pfp or me */
+	amdgpu_ring_write(ring, addr & 0xfffffffc);
+	amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+	amdgpu_ring_write(ring, seq);
+	amdgpu_ring_write(ring, 0xffffffff);
+	amdgpu_ring_write(ring, 4); /* poll interval */
+
 	if (usepfp) {
 		/* synce CE with ME to prevent CE fetch CEIB before context switch done */
 		amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
@@ -4109,7 +4096,7 @@
 
 	orig = data = RREG32(mmRLC_CGCG_CGLS_CTRL);
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_CGCG)) {
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
 		gfx_v7_0_enable_gui_idle_interrupt(adev, true);
 
 		tmp = gfx_v7_0_halt_rlc(adev);
@@ -4147,9 +4134,9 @@
 {
 	u32 data, orig, tmp = 0;
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_MGCG)) {
-		if (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_MGLS) {
-			if (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_CP_LS) {
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
+		if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) {
+			if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS) {
 				orig = data = RREG32(mmCP_MEM_SLP_CNTL);
 				data |= CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
 				if (orig != data)
@@ -4176,14 +4163,14 @@
 
 		gfx_v7_0_update_rlc(adev, tmp);
 
-		if (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_CGTS) {
+		if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGTS) {
 			orig = data = RREG32(mmCGTS_SM_CTRL_REG);
 			data &= ~CGTS_SM_CTRL_REG__SM_MODE_MASK;
 			data |= (0x2 << CGTS_SM_CTRL_REG__SM_MODE__SHIFT);
 			data |= CGTS_SM_CTRL_REG__SM_MODE_ENABLE_MASK;
 			data &= ~CGTS_SM_CTRL_REG__OVERRIDE_MASK;
-			if ((adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_MGLS) &&
-			    (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_CGTS_LS))
+			if ((adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) &&
+			    (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGTS_LS))
 				data &= ~CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK;
 			data &= ~CGTS_SM_CTRL_REG__ON_MONITOR_ADD_MASK;
 			data |= CGTS_SM_CTRL_REG__ON_MONITOR_ADD_EN_MASK;
@@ -4249,7 +4236,7 @@
 	u32 data, orig;
 
 	orig = data = RREG32(mmRLC_PG_CNTL);
-	if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_RLC_SMU_HS))
+	if (enable && (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS))
 		data |= RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PU_ENABLE_MASK;
 	else
 		data &= ~RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PU_ENABLE_MASK;
@@ -4263,7 +4250,7 @@
 	u32 data, orig;
 
 	orig = data = RREG32(mmRLC_PG_CNTL);
-	if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_RLC_SMU_HS))
+	if (enable && (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS))
 		data |= RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PD_ENABLE_MASK;
 	else
 		data &= ~RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PD_ENABLE_MASK;
@@ -4276,7 +4263,7 @@
 	u32 data, orig;
 
 	orig = data = RREG32(mmRLC_PG_CNTL);
-	if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_CP))
+	if (enable && (adev->pg_flags & AMD_PG_SUPPORT_CP))
 		data &= ~0x8000;
 	else
 		data |= 0x8000;
@@ -4289,7 +4276,7 @@
 	u32 data, orig;
 
 	orig = data = RREG32(mmRLC_PG_CNTL);
-	if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_GDS))
+	if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GDS))
 		data &= ~0x2000;
 	else
 		data |= 0x2000;
@@ -4370,7 +4357,7 @@
 {
 	u32 data, orig;
 
-	if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_PG)) {
+	if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) {
 		orig = data = RREG32(mmRLC_PG_CNTL);
 		data |= RLC_PG_CNTL__GFX_POWER_GATING_ENABLE_MASK;
 		if (orig != data)
@@ -4442,7 +4429,7 @@
 	u32 data, orig;
 
 	orig = data = RREG32(mmRLC_PG_CNTL);
-	if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_SMG))
+	if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG))
 		data |= RLC_PG_CNTL__STATIC_PER_CU_PG_ENABLE_MASK;
 	else
 		data &= ~RLC_PG_CNTL__STATIC_PER_CU_PG_ENABLE_MASK;
@@ -4456,7 +4443,7 @@
 	u32 data, orig;
 
 	orig = data = RREG32(mmRLC_PG_CNTL);
-	if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_DMG))
+	if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_DMG))
 		data |= RLC_PG_CNTL__DYN_PER_CU_PG_ENABLE_MASK;
 	else
 		data &= ~RLC_PG_CNTL__DYN_PER_CU_PG_ENABLE_MASK;
@@ -4623,15 +4610,15 @@
 
 static void gfx_v7_0_init_pg(struct amdgpu_device *adev)
 {
-	if (adev->pg_flags & (AMDGPU_PG_SUPPORT_GFX_PG |
-			      AMDGPU_PG_SUPPORT_GFX_SMG |
-			      AMDGPU_PG_SUPPORT_GFX_DMG |
-			      AMDGPU_PG_SUPPORT_CP |
-			      AMDGPU_PG_SUPPORT_GDS |
-			      AMDGPU_PG_SUPPORT_RLC_SMU_HS)) {
+	if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+			      AMD_PG_SUPPORT_GFX_SMG |
+			      AMD_PG_SUPPORT_GFX_DMG |
+			      AMD_PG_SUPPORT_CP |
+			      AMD_PG_SUPPORT_GDS |
+			      AMD_PG_SUPPORT_RLC_SMU_HS)) {
 		gfx_v7_0_enable_sclk_slowdown_on_pu(adev, true);
 		gfx_v7_0_enable_sclk_slowdown_on_pd(adev, true);
-		if (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_PG) {
+		if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
 			gfx_v7_0_init_gfx_cgpg(adev);
 			gfx_v7_0_enable_cp_pg(adev, true);
 			gfx_v7_0_enable_gds_pg(adev, true);
@@ -4643,14 +4630,14 @@
 
 static void gfx_v7_0_fini_pg(struct amdgpu_device *adev)
 {
-	if (adev->pg_flags & (AMDGPU_PG_SUPPORT_GFX_PG |
-			      AMDGPU_PG_SUPPORT_GFX_SMG |
-			      AMDGPU_PG_SUPPORT_GFX_DMG |
-			      AMDGPU_PG_SUPPORT_CP |
-			      AMDGPU_PG_SUPPORT_GDS |
-			      AMDGPU_PG_SUPPORT_RLC_SMU_HS)) {
+	if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+			      AMD_PG_SUPPORT_GFX_SMG |
+			      AMD_PG_SUPPORT_GFX_DMG |
+			      AMD_PG_SUPPORT_CP |
+			      AMD_PG_SUPPORT_GDS |
+			      AMD_PG_SUPPORT_RLC_SMU_HS)) {
 		gfx_v7_0_update_gfx_pg(adev, false);
-		if (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_PG) {
+		if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
 			gfx_v7_0_enable_cp_pg(adev, false);
 			gfx_v7_0_enable_gds_pg(adev, false);
 		}
@@ -4738,6 +4725,22 @@
 	return 0;
 }
 
+static int gfx_v7_0_late_init(void *handle)
+{
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	int r;
+
+	r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0);
+	if (r)
+		return r;
+
+	r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0);
+	if (r)
+		return r;
+
+	return 0;
+}
+
 static int gfx_v7_0_sw_init(void *handle)
 {
 	struct amdgpu_ring *ring;
@@ -4890,6 +4893,8 @@
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
+	amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
 	gfx_v7_0_cp_enable(adev, false);
 	gfx_v7_0_rlc_stop(adev);
 	gfx_v7_0_fini_pg(adev);
@@ -5450,7 +5455,7 @@
 	case 2:
 		for (i = 0; i < adev->gfx.num_compute_rings; i++) {
 			ring = &adev->gfx.compute_ring[i];
-			if ((ring->me == me_id) & (ring->pipe == pipe_id))
+			if ((ring->me == me_id) && (ring->pipe == pipe_id))
 				amdgpu_fence_process(ring);
 		}
 		break;
@@ -5509,14 +5514,14 @@
 	if (state == AMD_PG_STATE_GATE)
 		gate = true;
 
-	if (adev->pg_flags & (AMDGPU_PG_SUPPORT_GFX_PG |
-			      AMDGPU_PG_SUPPORT_GFX_SMG |
-			      AMDGPU_PG_SUPPORT_GFX_DMG |
-			      AMDGPU_PG_SUPPORT_CP |
-			      AMDGPU_PG_SUPPORT_GDS |
-			      AMDGPU_PG_SUPPORT_RLC_SMU_HS)) {
+	if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+			      AMD_PG_SUPPORT_GFX_SMG |
+			      AMD_PG_SUPPORT_GFX_DMG |
+			      AMD_PG_SUPPORT_CP |
+			      AMD_PG_SUPPORT_GDS |
+			      AMD_PG_SUPPORT_RLC_SMU_HS)) {
 		gfx_v7_0_update_gfx_pg(adev, gate);
-		if (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_PG) {
+		if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
 			gfx_v7_0_enable_cp_pg(adev, gate);
 			gfx_v7_0_enable_gds_pg(adev, gate);
 		}
@@ -5527,7 +5532,7 @@
 
 const struct amd_ip_funcs gfx_v7_0_ip_funcs = {
 	.early_init = gfx_v7_0_early_init,
-	.late_init = NULL,
+	.late_init = gfx_v7_0_late_init,
 	.sw_init = gfx_v7_0_sw_init,
 	.sw_fini = gfx_v7_0_sw_fini,
 	.hw_init = gfx_v7_0_hw_init,
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -66,6 +66,27 @@
 #define MACRO_TILE_ASPECT(x)				((x) << GB_MACROTILE_MODE0__MACRO_TILE_ASPECT__SHIFT)
 #define NUM_BANKS(x)					((x) << GB_MACROTILE_MODE0__NUM_BANKS__SHIFT)
 
+#define RLC_CGTT_MGCG_OVERRIDE__CPF_MASK            0x00000001L
+#define RLC_CGTT_MGCG_OVERRIDE__RLC_MASK            0x00000002L
+#define RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK           0x00000004L
+#define RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK           0x00000008L
+#define RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK           0x00000010L
+#define RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK           0x00000020L
+
+/* BPM SERDES CMD */
+#define SET_BPM_SERDES_CMD    1
+#define CLE_BPM_SERDES_CMD    0
+
+/* BPM Register Address*/
+enum {
+	BPM_REG_CGLS_EN = 0,        /* Enable/Disable CGLS */
+	BPM_REG_CGLS_ON,            /* ON/OFF CGLS: shall be controlled by RLC FW */
+	BPM_REG_CGCG_OVERRIDE,      /* Set/Clear CGCG Override */
+	BPM_REG_MGCG_OVERRIDE,      /* Set/Clear MGCG Override */
+	BPM_REG_FGCG_OVERRIDE,      /* Set/Clear FGCG Override */
+	BPM_REG_FGCG_MAX
+};
+
 MODULE_FIRMWARE("amdgpu/carrizo_ce.bin");
 MODULE_FIRMWARE("amdgpu/carrizo_pfp.bin");
 MODULE_FIRMWARE("amdgpu/carrizo_me.bin");
@@ -90,7 +111,6 @@
 MODULE_FIRMWARE("amdgpu/topaz_pfp.bin");
 MODULE_FIRMWARE("amdgpu/topaz_me.bin");
 MODULE_FIRMWARE("amdgpu/topaz_mec.bin");
-MODULE_FIRMWARE("amdgpu/topaz_mec2.bin");
 MODULE_FIRMWARE("amdgpu/topaz_rlc.bin");
 
 MODULE_FIRMWARE("amdgpu/fiji_ce.bin");
@@ -807,7 +827,8 @@
 	adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
 	adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
-	if (adev->asic_type != CHIP_STONEY) {
+	if ((adev->asic_type != CHIP_STONEY) &&
+	    (adev->asic_type != CHIP_TOPAZ)) {
 		snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
 		err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
 		if (!err) {
@@ -964,6 +985,322 @@
 	return 0;
 }
 
+static const u32 vgpr_init_compute_shader[] =
+{
+	0x7e000209, 0x7e020208,
+	0x7e040207, 0x7e060206,
+	0x7e080205, 0x7e0a0204,
+	0x7e0c0203, 0x7e0e0202,
+	0x7e100201, 0x7e120200,
+	0x7e140209, 0x7e160208,
+	0x7e180207, 0x7e1a0206,
+	0x7e1c0205, 0x7e1e0204,
+	0x7e200203, 0x7e220202,
+	0x7e240201, 0x7e260200,
+	0x7e280209, 0x7e2a0208,
+	0x7e2c0207, 0x7e2e0206,
+	0x7e300205, 0x7e320204,
+	0x7e340203, 0x7e360202,
+	0x7e380201, 0x7e3a0200,
+	0x7e3c0209, 0x7e3e0208,
+	0x7e400207, 0x7e420206,
+	0x7e440205, 0x7e460204,
+	0x7e480203, 0x7e4a0202,
+	0x7e4c0201, 0x7e4e0200,
+	0x7e500209, 0x7e520208,
+	0x7e540207, 0x7e560206,
+	0x7e580205, 0x7e5a0204,
+	0x7e5c0203, 0x7e5e0202,
+	0x7e600201, 0x7e620200,
+	0x7e640209, 0x7e660208,
+	0x7e680207, 0x7e6a0206,
+	0x7e6c0205, 0x7e6e0204,
+	0x7e700203, 0x7e720202,
+	0x7e740201, 0x7e760200,
+	0x7e780209, 0x7e7a0208,
+	0x7e7c0207, 0x7e7e0206,
+	0xbf8a0000, 0xbf810000,
+};
+
+static const u32 sgpr_init_compute_shader[] =
+{
+	0xbe8a0100, 0xbe8c0102,
+	0xbe8e0104, 0xbe900106,
+	0xbe920108, 0xbe940100,
+	0xbe960102, 0xbe980104,
+	0xbe9a0106, 0xbe9c0108,
+	0xbe9e0100, 0xbea00102,
+	0xbea20104, 0xbea40106,
+	0xbea60108, 0xbea80100,
+	0xbeaa0102, 0xbeac0104,
+	0xbeae0106, 0xbeb00108,
+	0xbeb20100, 0xbeb40102,
+	0xbeb60104, 0xbeb80106,
+	0xbeba0108, 0xbebc0100,
+	0xbebe0102, 0xbec00104,
+	0xbec20106, 0xbec40108,
+	0xbec60100, 0xbec80102,
+	0xbee60004, 0xbee70005,
+	0xbeea0006, 0xbeeb0007,
+	0xbee80008, 0xbee90009,
+	0xbefc0000, 0xbf8a0000,
+	0xbf810000, 0x00000000,
+};
+
+static const u32 vgpr_init_regs[] =
+{
+	mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0xffffffff,
+	mmCOMPUTE_RESOURCE_LIMITS, 0,
+	mmCOMPUTE_NUM_THREAD_X, 256*4,
+	mmCOMPUTE_NUM_THREAD_Y, 1,
+	mmCOMPUTE_NUM_THREAD_Z, 1,
+	mmCOMPUTE_PGM_RSRC2, 20,
+	mmCOMPUTE_USER_DATA_0, 0xedcedc00,
+	mmCOMPUTE_USER_DATA_1, 0xedcedc01,
+	mmCOMPUTE_USER_DATA_2, 0xedcedc02,
+	mmCOMPUTE_USER_DATA_3, 0xedcedc03,
+	mmCOMPUTE_USER_DATA_4, 0xedcedc04,
+	mmCOMPUTE_USER_DATA_5, 0xedcedc05,
+	mmCOMPUTE_USER_DATA_6, 0xedcedc06,
+	mmCOMPUTE_USER_DATA_7, 0xedcedc07,
+	mmCOMPUTE_USER_DATA_8, 0xedcedc08,
+	mmCOMPUTE_USER_DATA_9, 0xedcedc09,
+};
+
+static const u32 sgpr1_init_regs[] =
+{
+	mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0x0f,
+	mmCOMPUTE_RESOURCE_LIMITS, 0x1000000,
+	mmCOMPUTE_NUM_THREAD_X, 256*5,
+	mmCOMPUTE_NUM_THREAD_Y, 1,
+	mmCOMPUTE_NUM_THREAD_Z, 1,
+	mmCOMPUTE_PGM_RSRC2, 20,
+	mmCOMPUTE_USER_DATA_0, 0xedcedc00,
+	mmCOMPUTE_USER_DATA_1, 0xedcedc01,
+	mmCOMPUTE_USER_DATA_2, 0xedcedc02,
+	mmCOMPUTE_USER_DATA_3, 0xedcedc03,
+	mmCOMPUTE_USER_DATA_4, 0xedcedc04,
+	mmCOMPUTE_USER_DATA_5, 0xedcedc05,
+	mmCOMPUTE_USER_DATA_6, 0xedcedc06,
+	mmCOMPUTE_USER_DATA_7, 0xedcedc07,
+	mmCOMPUTE_USER_DATA_8, 0xedcedc08,
+	mmCOMPUTE_USER_DATA_9, 0xedcedc09,
+};
+
+static const u32 sgpr2_init_regs[] =
+{
+	mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0xf0,
+	mmCOMPUTE_RESOURCE_LIMITS, 0x1000000,
+	mmCOMPUTE_NUM_THREAD_X, 256*5,
+	mmCOMPUTE_NUM_THREAD_Y, 1,
+	mmCOMPUTE_NUM_THREAD_Z, 1,
+	mmCOMPUTE_PGM_RSRC2, 20,
+	mmCOMPUTE_USER_DATA_0, 0xedcedc00,
+	mmCOMPUTE_USER_DATA_1, 0xedcedc01,
+	mmCOMPUTE_USER_DATA_2, 0xedcedc02,
+	mmCOMPUTE_USER_DATA_3, 0xedcedc03,
+	mmCOMPUTE_USER_DATA_4, 0xedcedc04,
+	mmCOMPUTE_USER_DATA_5, 0xedcedc05,
+	mmCOMPUTE_USER_DATA_6, 0xedcedc06,
+	mmCOMPUTE_USER_DATA_7, 0xedcedc07,
+	mmCOMPUTE_USER_DATA_8, 0xedcedc08,
+	mmCOMPUTE_USER_DATA_9, 0xedcedc09,
+};
+
+static const u32 sec_ded_counter_registers[] =
+{
+	mmCPC_EDC_ATC_CNT,
+	mmCPC_EDC_SCRATCH_CNT,
+	mmCPC_EDC_UCODE_CNT,
+	mmCPF_EDC_ATC_CNT,
+	mmCPF_EDC_ROQ_CNT,
+	mmCPF_EDC_TAG_CNT,
+	mmCPG_EDC_ATC_CNT,
+	mmCPG_EDC_DMA_CNT,
+	mmCPG_EDC_TAG_CNT,
+	mmDC_EDC_CSINVOC_CNT,
+	mmDC_EDC_RESTORE_CNT,
+	mmDC_EDC_STATE_CNT,
+	mmGDS_EDC_CNT,
+	mmGDS_EDC_GRBM_CNT,
+	mmGDS_EDC_OA_DED,
+	mmSPI_EDC_CNT,
+	mmSQC_ATC_EDC_GATCL1_CNT,
+	mmSQC_EDC_CNT,
+	mmSQ_EDC_DED_CNT,
+	mmSQ_EDC_INFO,
+	mmSQ_EDC_SEC_CNT,
+	mmTCC_EDC_CNT,
+	mmTCP_ATC_EDC_GATCL1_CNT,
+	mmTCP_EDC_CNT,
+	mmTD_EDC_CNT
+};
+
+static int gfx_v8_0_do_edc_gpr_workarounds(struct amdgpu_device *adev)
+{
+	struct amdgpu_ring *ring = &adev->gfx.compute_ring[0];
+	struct amdgpu_ib ib;
+	struct fence *f = NULL;
+	int r, i;
+	u32 tmp;
+	unsigned total_size, vgpr_offset, sgpr_offset;
+	u64 gpu_addr;
+
+	/* only supported on CZ */
+	if (adev->asic_type != CHIP_CARRIZO)
+		return 0;
+
+	/* bail if the compute ring is not ready */
+	if (!ring->ready)
+		return 0;
+
+	tmp = RREG32(mmGB_EDC_MODE);
+	WREG32(mmGB_EDC_MODE, 0);
+
+	total_size =
+		(((ARRAY_SIZE(vgpr_init_regs) / 2) * 3) + 4 + 5 + 2) * 4;
+	total_size +=
+		(((ARRAY_SIZE(sgpr1_init_regs) / 2) * 3) + 4 + 5 + 2) * 4;
+	total_size +=
+		(((ARRAY_SIZE(sgpr2_init_regs) / 2) * 3) + 4 + 5 + 2) * 4;
+	total_size = ALIGN(total_size, 256);
+	vgpr_offset = total_size;
+	total_size += ALIGN(sizeof(vgpr_init_compute_shader), 256);
+	sgpr_offset = total_size;
+	total_size += sizeof(sgpr_init_compute_shader);
+
+	/* allocate an indirect buffer to put the commands in */
+	memset(&ib, 0, sizeof(ib));
+	r = amdgpu_ib_get(ring, NULL, total_size, &ib);
+	if (r) {
+		DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
+		return r;
+	}
+
+	/* load the compute shaders */
+	for (i = 0; i < ARRAY_SIZE(vgpr_init_compute_shader); i++)
+		ib.ptr[i + (vgpr_offset / 4)] = vgpr_init_compute_shader[i];
+
+	for (i = 0; i < ARRAY_SIZE(sgpr_init_compute_shader); i++)
+		ib.ptr[i + (sgpr_offset / 4)] = sgpr_init_compute_shader[i];
+
+	/* init the ib length to 0 */
+	ib.length_dw = 0;
+
+	/* VGPR */
+	/* write the register state for the compute dispatch */
+	for (i = 0; i < ARRAY_SIZE(vgpr_init_regs); i += 2) {
+		ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 1);
+		ib.ptr[ib.length_dw++] = vgpr_init_regs[i] - PACKET3_SET_SH_REG_START;
+		ib.ptr[ib.length_dw++] = vgpr_init_regs[i + 1];
+	}
+	/* write the shader start address: mmCOMPUTE_PGM_LO, mmCOMPUTE_PGM_HI */
+	gpu_addr = (ib.gpu_addr + (u64)vgpr_offset) >> 8;
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 2);
+	ib.ptr[ib.length_dw++] = mmCOMPUTE_PGM_LO - PACKET3_SET_SH_REG_START;
+	ib.ptr[ib.length_dw++] = lower_32_bits(gpu_addr);
+	ib.ptr[ib.length_dw++] = upper_32_bits(gpu_addr);
+
+	/* write dispatch packet */
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3);
+	ib.ptr[ib.length_dw++] = 8; /* x */
+	ib.ptr[ib.length_dw++] = 1; /* y */
+	ib.ptr[ib.length_dw++] = 1; /* z */
+	ib.ptr[ib.length_dw++] =
+		REG_SET_FIELD(0, COMPUTE_DISPATCH_INITIATOR, COMPUTE_SHADER_EN, 1);
+
+	/* write CS partial flush packet */
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_EVENT_WRITE, 0);
+	ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4);
+
+	/* SGPR1 */
+	/* write the register state for the compute dispatch */
+	for (i = 0; i < ARRAY_SIZE(sgpr1_init_regs); i += 2) {
+		ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 1);
+		ib.ptr[ib.length_dw++] = sgpr1_init_regs[i] - PACKET3_SET_SH_REG_START;
+		ib.ptr[ib.length_dw++] = sgpr1_init_regs[i + 1];
+	}
+	/* write the shader start address: mmCOMPUTE_PGM_LO, mmCOMPUTE_PGM_HI */
+	gpu_addr = (ib.gpu_addr + (u64)sgpr_offset) >> 8;
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 2);
+	ib.ptr[ib.length_dw++] = mmCOMPUTE_PGM_LO - PACKET3_SET_SH_REG_START;
+	ib.ptr[ib.length_dw++] = lower_32_bits(gpu_addr);
+	ib.ptr[ib.length_dw++] = upper_32_bits(gpu_addr);
+
+	/* write dispatch packet */
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3);
+	ib.ptr[ib.length_dw++] = 8; /* x */
+	ib.ptr[ib.length_dw++] = 1; /* y */
+	ib.ptr[ib.length_dw++] = 1; /* z */
+	ib.ptr[ib.length_dw++] =
+		REG_SET_FIELD(0, COMPUTE_DISPATCH_INITIATOR, COMPUTE_SHADER_EN, 1);
+
+	/* write CS partial flush packet */
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_EVENT_WRITE, 0);
+	ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4);
+
+	/* SGPR2 */
+	/* write the register state for the compute dispatch */
+	for (i = 0; i < ARRAY_SIZE(sgpr2_init_regs); i += 2) {
+		ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 1);
+		ib.ptr[ib.length_dw++] = sgpr2_init_regs[i] - PACKET3_SET_SH_REG_START;
+		ib.ptr[ib.length_dw++] = sgpr2_init_regs[i + 1];
+	}
+	/* write the shader start address: mmCOMPUTE_PGM_LO, mmCOMPUTE_PGM_HI */
+	gpu_addr = (ib.gpu_addr + (u64)sgpr_offset) >> 8;
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 2);
+	ib.ptr[ib.length_dw++] = mmCOMPUTE_PGM_LO - PACKET3_SET_SH_REG_START;
+	ib.ptr[ib.length_dw++] = lower_32_bits(gpu_addr);
+	ib.ptr[ib.length_dw++] = upper_32_bits(gpu_addr);
+
+	/* write dispatch packet */
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3);
+	ib.ptr[ib.length_dw++] = 8; /* x */
+	ib.ptr[ib.length_dw++] = 1; /* y */
+	ib.ptr[ib.length_dw++] = 1; /* z */
+	ib.ptr[ib.length_dw++] =
+		REG_SET_FIELD(0, COMPUTE_DISPATCH_INITIATOR, COMPUTE_SHADER_EN, 1);
+
+	/* write CS partial flush packet */
+	ib.ptr[ib.length_dw++] = PACKET3(PACKET3_EVENT_WRITE, 0);
+	ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4);
+
+	/* shedule the ib on the ring */
+	r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, &ib, 1, NULL,
+						 AMDGPU_FENCE_OWNER_UNDEFINED,
+						 &f);
+	if (r) {
+		DRM_ERROR("amdgpu: ib submit failed (%d).\n", r);
+		goto fail;
+	}
+
+	/* wait for the GPU to finish processing the IB */
+	r = fence_wait(f, false);
+	if (r) {
+		DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
+		goto fail;
+	}
+
+	tmp = REG_SET_FIELD(tmp, GB_EDC_MODE, DED_MODE, 2);
+	tmp = REG_SET_FIELD(tmp, GB_EDC_MODE, PROP_FED, 1);
+	WREG32(mmGB_EDC_MODE, tmp);
+
+	tmp = RREG32(mmCC_GC_EDC_CONFIG);
+	tmp = REG_SET_FIELD(tmp, CC_GC_EDC_CONFIG, DIS_EDC, 0) | 1;
+	WREG32(mmCC_GC_EDC_CONFIG, tmp);
+
+
+	/* read back registers to clear the counters */
+	for (i = 0; i < ARRAY_SIZE(sec_ded_counter_registers); i++)
+		RREG32(sec_ded_counter_registers[i]);
+
+fail:
+	fence_put(f);
+	amdgpu_ib_free(adev, &ib);
+
+	return r;
+}
+
 static void gfx_v8_0_gpu_early_init(struct amdgpu_device *adev)
 {
 	u32 gb_addr_config;
@@ -2809,7 +3146,7 @@
 	mutex_lock(&adev->grbm_idx_mutex);
 	for (i = 0; i < se_num; i++) {
 		gfx_v8_0_select_se_sh(adev, i, 0xffffffff);
-		data = 0;
+		data = RREG32(mmPA_SC_RASTER_CONFIG);
 		for (j = 0; j < sh_per_se; j++) {
 			switch (enabled_rbs & 3) {
 			case 0:
@@ -3087,16 +3424,18 @@
 
 	gfx_v8_0_rlc_reset(adev);
 
-	if (!adev->firmware.smu_load) {
-		/* legacy rlc firmware loading */
-		r = gfx_v8_0_rlc_load_microcode(adev);
-		if (r)
-			return r;
-	} else {
-		r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
-						AMDGPU_UCODE_ID_RLC_G);
-		if (r)
-			return -EINVAL;
+	if (!adev->pp_enabled) {
+		if (!adev->firmware.smu_load) {
+			/* legacy rlc firmware loading */
+			r = gfx_v8_0_rlc_load_microcode(adev);
+			if (r)
+				return r;
+		} else {
+			r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+							AMDGPU_UCODE_ID_RLC_G);
+			if (r)
+				return -EINVAL;
+		}
 	}
 
 	gfx_v8_0_rlc_start(adev);
@@ -3941,6 +4280,11 @@
 		tmp = REG_SET_FIELD(tmp, CP_HQD_PERSISTENT_STATE, PRELOAD_SIZE, 0x53);
 		WREG32(mmCP_HQD_PERSISTENT_STATE, tmp);
 		mqd->cp_hqd_persistent_state = tmp;
+		if (adev->asic_type == CHIP_STONEY) {
+			tmp = RREG32(mmCP_ME1_PIPE3_INT_CNTL);
+			tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE3_INT_CNTL, GENERIC2_INT_ENABLE, 1);
+			WREG32(mmCP_ME1_PIPE3_INT_CNTL, tmp);
+		}
 
 		/* activate the queue */
 		mqd->cp_hqd_active = 1;
@@ -3982,35 +4326,43 @@
 	if (!(adev->flags & AMD_IS_APU))
 		gfx_v8_0_enable_gui_idle_interrupt(adev, false);
 
-	if (!adev->firmware.smu_load) {
-		/* legacy firmware loading */
-		r = gfx_v8_0_cp_gfx_load_microcode(adev);
-		if (r)
-			return r;
-
-		r = gfx_v8_0_cp_compute_load_microcode(adev);
-		if (r)
-			return r;
-	} else {
-		r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
-						AMDGPU_UCODE_ID_CP_CE);
-		if (r)
-			return -EINVAL;
-
-		r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
-						AMDGPU_UCODE_ID_CP_PFP);
-		if (r)
-			return -EINVAL;
-
-		r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
-						AMDGPU_UCODE_ID_CP_ME);
-		if (r)
-			return -EINVAL;
+	if (!adev->pp_enabled) {
+		if (!adev->firmware.smu_load) {
+			/* legacy firmware loading */
+			r = gfx_v8_0_cp_gfx_load_microcode(adev);
+			if (r)
+				return r;
 
-		r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
-						AMDGPU_UCODE_ID_CP_MEC1);
-		if (r)
-			return -EINVAL;
+			r = gfx_v8_0_cp_compute_load_microcode(adev);
+			if (r)
+				return r;
+		} else {
+			r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+							AMDGPU_UCODE_ID_CP_CE);
+			if (r)
+				return -EINVAL;
+
+			r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+							AMDGPU_UCODE_ID_CP_PFP);
+			if (r)
+				return -EINVAL;
+
+			r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+							AMDGPU_UCODE_ID_CP_ME);
+			if (r)
+				return -EINVAL;
+
+			if (adev->asic_type == CHIP_TOPAZ) {
+				r = gfx_v8_0_cp_compute_load_microcode(adev);
+				if (r)
+					return r;
+			} else {
+				r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+										 AMDGPU_UCODE_ID_CP_MEC1);
+				if (r)
+					return -EINVAL;
+			}
+		}
 	}
 
 	r = gfx_v8_0_cp_gfx_resume(adev);
@@ -4056,6 +4408,8 @@
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
+	amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
 	gfx_v8_0_cp_enable(adev, false);
 	gfx_v8_0_rlc_stop(adev);
 	gfx_v8_0_cp_compute_fini(adev);
@@ -4341,7 +4695,18 @@
 		gfx_v8_0_cp_gfx_enable(adev, false);
 
 		/* Disable MEC parsing/prefetching */
-		/* XXX todo */
+		gfx_v8_0_cp_compute_enable(adev, false);
+
+		if (grbm_soft_reset || srbm_soft_reset) {
+			tmp = RREG32(mmGMCON_DEBUG);
+			tmp = REG_SET_FIELD(tmp,
+					    GMCON_DEBUG, GFX_STALL, 1);
+			tmp = REG_SET_FIELD(tmp,
+					    GMCON_DEBUG, GFX_CLEAR, 1);
+			WREG32(mmGMCON_DEBUG, tmp);
+
+			udelay(50);
+		}
 
 		if (grbm_soft_reset) {
 			tmp = RREG32(mmGRBM_SOFT_RESET);
@@ -4370,6 +4735,16 @@
 			WREG32(mmSRBM_SOFT_RESET, tmp);
 			tmp = RREG32(mmSRBM_SOFT_RESET);
 		}
+
+		if (grbm_soft_reset || srbm_soft_reset) {
+			tmp = RREG32(mmGMCON_DEBUG);
+			tmp = REG_SET_FIELD(tmp,
+					    GMCON_DEBUG, GFX_STALL, 0);
+			tmp = REG_SET_FIELD(tmp,
+					    GMCON_DEBUG, GFX_CLEAR, 0);
+			WREG32(mmGMCON_DEBUG, tmp);
+		}
+
 		/* Wait a little for things to settle down */
 		udelay(50);
 		gfx_v8_0_print_status((void *)adev);
@@ -4458,15 +4833,269 @@
 	return 0;
 }
 
+static int gfx_v8_0_late_init(void *handle)
+{
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	int r;
+
+	r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0);
+	if (r)
+		return r;
+
+	r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0);
+	if (r)
+		return r;
+
+	/* requires IBs so do in late init after IB pool is initialized */
+	r = gfx_v8_0_do_edc_gpr_workarounds(adev);
+	if (r)
+		return r;
+
+	return 0;
+}
+
 static int gfx_v8_0_set_powergating_state(void *handle,
 					  enum amd_powergating_state state)
 {
 	return 0;
 }
 
+static void fiji_send_serdes_cmd(struct amdgpu_device *adev,
+		uint32_t reg_addr, uint32_t cmd)
+{
+	uint32_t data;
+
+	gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff);
+
+	WREG32(mmRLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
+	WREG32(mmRLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
+
+	data = RREG32(mmRLC_SERDES_WR_CTRL);
+	data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK |
+			RLC_SERDES_WR_CTRL__READ_COMMAND_MASK |
+			RLC_SERDES_WR_CTRL__P1_SELECT_MASK |
+			RLC_SERDES_WR_CTRL__P2_SELECT_MASK |
+			RLC_SERDES_WR_CTRL__RDDATA_RESET_MASK |
+			RLC_SERDES_WR_CTRL__POWER_DOWN_MASK |
+			RLC_SERDES_WR_CTRL__POWER_UP_MASK |
+			RLC_SERDES_WR_CTRL__SHORT_FORMAT_MASK |
+			RLC_SERDES_WR_CTRL__BPM_DATA_MASK |
+			RLC_SERDES_WR_CTRL__REG_ADDR_MASK |
+			RLC_SERDES_WR_CTRL__SRBM_OVERRIDE_MASK);
+	data |= (RLC_SERDES_WR_CTRL__RSVD_BPM_ADDR_MASK |
+			(cmd << RLC_SERDES_WR_CTRL__BPM_DATA__SHIFT) |
+			(reg_addr << RLC_SERDES_WR_CTRL__REG_ADDR__SHIFT) |
+			(0xff << RLC_SERDES_WR_CTRL__BPM_ADDR__SHIFT));
+
+	WREG32(mmRLC_SERDES_WR_CTRL, data);
+}
+
+static void fiji_update_medium_grain_clock_gating(struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t temp, data;
+
+	/* It is disabled by HW by default */
+	if (enable) {
+		/* 1 - RLC memory Light sleep */
+		temp = data = RREG32(mmRLC_MEM_SLP_CNTL);
+		data |= RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
+		if (temp != data)
+			WREG32(mmRLC_MEM_SLP_CNTL, data);
+
+		/* 2 - CP memory Light sleep */
+		temp = data = RREG32(mmCP_MEM_SLP_CNTL);
+		data |= CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
+		if (temp != data)
+			WREG32(mmCP_MEM_SLP_CNTL, data);
+
+		/* 3 - RLC_CGTT_MGCG_OVERRIDE */
+		temp = data = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+		data &= ~(RLC_CGTT_MGCG_OVERRIDE__CPF_MASK |
+				RLC_CGTT_MGCG_OVERRIDE__RLC_MASK |
+				RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK |
+				RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK);
+
+		if (temp != data)
+			WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data);
+
+		/* 4 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		gfx_v8_0_wait_for_rlc_serdes(adev);
+
+		/* 5 - clear mgcg override */
+		fiji_send_serdes_cmd(adev, BPM_REG_MGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
+
+		/* 6 - Enable CGTS(Tree Shade) MGCG /MGLS */
+		temp = data = RREG32(mmCGTS_SM_CTRL_REG);
+		data &= ~(CGTS_SM_CTRL_REG__SM_MODE_MASK);
+		data |= (0x2 << CGTS_SM_CTRL_REG__SM_MODE__SHIFT);
+		data |= CGTS_SM_CTRL_REG__SM_MODE_ENABLE_MASK;
+		data &= ~CGTS_SM_CTRL_REG__OVERRIDE_MASK;
+		data &= ~CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK;
+		data |= CGTS_SM_CTRL_REG__ON_MONITOR_ADD_EN_MASK;
+		data |= (0x96 << CGTS_SM_CTRL_REG__ON_MONITOR_ADD__SHIFT);
+		if (temp != data)
+			WREG32(mmCGTS_SM_CTRL_REG, data);
+		udelay(50);
+
+		/* 7 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		gfx_v8_0_wait_for_rlc_serdes(adev);
+	} else {
+		/* 1 - MGCG_OVERRIDE[0] for CP and MGCG_OVERRIDE[1] for RLC */
+		temp = data = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+		data |= (RLC_CGTT_MGCG_OVERRIDE__CPF_MASK |
+				RLC_CGTT_MGCG_OVERRIDE__RLC_MASK |
+				RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK |
+				RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK);
+		if (temp != data)
+			WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data);
+
+		/* 2 - disable MGLS in RLC */
+		data = RREG32(mmRLC_MEM_SLP_CNTL);
+		if (data & RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK) {
+			data &= ~RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
+			WREG32(mmRLC_MEM_SLP_CNTL, data);
+		}
+
+		/* 3 - disable MGLS in CP */
+		data = RREG32(mmCP_MEM_SLP_CNTL);
+		if (data & CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK) {
+			data &= ~CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
+			WREG32(mmCP_MEM_SLP_CNTL, data);
+		}
+
+		/* 4 - Disable CGTS(Tree Shade) MGCG and MGLS */
+		temp = data = RREG32(mmCGTS_SM_CTRL_REG);
+		data |= (CGTS_SM_CTRL_REG__OVERRIDE_MASK |
+				CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK);
+		if (temp != data)
+			WREG32(mmCGTS_SM_CTRL_REG, data);
+
+		/* 5 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		gfx_v8_0_wait_for_rlc_serdes(adev);
+
+		/* 6 - set mgcg override */
+		fiji_send_serdes_cmd(adev, BPM_REG_MGCG_OVERRIDE, SET_BPM_SERDES_CMD);
+
+		udelay(50);
+
+		/* 7- wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		gfx_v8_0_wait_for_rlc_serdes(adev);
+	}
+}
+
+static void fiji_update_coarse_grain_clock_gating(struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t temp, temp1, data, data1;
+
+	temp = data = RREG32(mmRLC_CGCG_CGLS_CTRL);
+
+	if (enable) {
+		/* 1 enable cntx_empty_int_enable/cntx_busy_int_enable/
+		 * Cmp_busy/GFX_Idle interrupts
+		 */
+		gfx_v8_0_enable_gui_idle_interrupt(adev, true);
+
+		temp1 = data1 =	RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+		data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK;
+		if (temp1 != data1)
+			WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
+
+		/* 2 wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		gfx_v8_0_wait_for_rlc_serdes(adev);
+
+		/* 3 - clear cgcg override */
+		fiji_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
+
+		/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		gfx_v8_0_wait_for_rlc_serdes(adev);
+
+		/* 4 - write cmd to set CGLS */
+		fiji_send_serdes_cmd(adev, BPM_REG_CGLS_EN, SET_BPM_SERDES_CMD);
+
+		/* 5 - enable cgcg */
+		data |= RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
+
+		/* enable cgls*/
+		data |= RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK;
+
+		temp1 = data1 =	RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+		data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK;
+
+		if (temp1 != data1)
+			WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
+
+		if (temp != data)
+			WREG32(mmRLC_CGCG_CGLS_CTRL, data);
+	} else {
+		/* disable cntx_empty_int_enable & GFX Idle interrupt */
+		gfx_v8_0_enable_gui_idle_interrupt(adev, false);
+
+		/* TEST CGCG */
+		temp1 = data1 =	RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+		data1 |= (RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK |
+				RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK);
+		if (temp1 != data1)
+			WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
+
+		/* read gfx register to wake up cgcg */
+		RREG32(mmCB_CGTT_SCLK_CTRL);
+		RREG32(mmCB_CGTT_SCLK_CTRL);
+		RREG32(mmCB_CGTT_SCLK_CTRL);
+		RREG32(mmCB_CGTT_SCLK_CTRL);
+
+		/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		gfx_v8_0_wait_for_rlc_serdes(adev);
+
+		/* write cmd to Set CGCG Overrride */
+		fiji_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, SET_BPM_SERDES_CMD);
+
+		/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		gfx_v8_0_wait_for_rlc_serdes(adev);
+
+		/* write cmd to Clear CGLS */
+		fiji_send_serdes_cmd(adev, BPM_REG_CGLS_EN, CLE_BPM_SERDES_CMD);
+
+		/* disable cgcg, cgls should be disabled too. */
+		data &= ~(RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK |
+				RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK);
+		if (temp != data)
+			WREG32(mmRLC_CGCG_CGLS_CTRL, data);
+	}
+}
+static int fiji_update_gfx_clock_gating(struct amdgpu_device *adev,
+		bool enable)
+{
+	if (enable) {
+		/* CGCG/CGLS should be enabled after MGCG/MGLS/TS(CG/LS)
+		 * ===  MGCG + MGLS + TS(CG/LS) ===
+		 */
+		fiji_update_medium_grain_clock_gating(adev, enable);
+		fiji_update_coarse_grain_clock_gating(adev, enable);
+	} else {
+		/* CGCG/CGLS should be disabled before MGCG/MGLS/TS(CG/LS)
+		 * ===  CGCG + CGLS ===
+		 */
+		fiji_update_coarse_grain_clock_gating(adev, enable);
+		fiji_update_medium_grain_clock_gating(adev, enable);
+	}
+	return 0;
+}
+
 static int gfx_v8_0_set_clockgating_state(void *handle,
 					  enum amd_clockgating_state state)
 {
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	switch (adev->asic_type) {
+	case CHIP_FIJI:
+		fiji_update_gfx_clock_gating(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		break;
+	default:
+		break;
+	}
 	return 0;
 }
 
@@ -4681,7 +5310,8 @@
 
 	amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
 	amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
-		 WAIT_REG_MEM_FUNCTION(3))); /* equal */
+				 WAIT_REG_MEM_FUNCTION(3) | /* equal */
+				 WAIT_REG_MEM_ENGINE(usepfp))); /* pfp or me */
 	amdgpu_ring_write(ring, addr & 0xfffffffc);
 	amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
 	amdgpu_ring_write(ring, seq);
@@ -4995,7 +5625,7 @@
 
 const struct amd_ip_funcs gfx_v8_0_ip_funcs = {
 	.early_init = gfx_v8_0_early_init,
-	.late_init = NULL,
+	.late_init = gfx_v8_0_late_init,
 	.sw_init = gfx_v8_0_sw_init,
 	.sw_fini = gfx_v8_0_sw_fini,
 	.hw_init = gfx_v8_0_hw_init,
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -42,9 +42,39 @@
 
 MODULE_FIRMWARE("radeon/bonaire_mc.bin");
 MODULE_FIRMWARE("radeon/hawaii_mc.bin");
+MODULE_FIRMWARE("amdgpu/topaz_mc.bin");
+
+static const u32 golden_settings_iceland_a11[] =
+{
+	mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+	mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+	mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+	mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff
+};
+
+static const u32 iceland_mgcg_cgcg_init[] =
+{
+	mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
+};
+
+static void gmc_v7_0_init_golden_registers(struct amdgpu_device *adev)
+{
+	switch (adev->asic_type) {
+	case CHIP_TOPAZ:
+		amdgpu_program_register_sequence(adev,
+						 iceland_mgcg_cgcg_init,
+						 (const u32)ARRAY_SIZE(iceland_mgcg_cgcg_init));
+		amdgpu_program_register_sequence(adev,
+						 golden_settings_iceland_a11,
+						 (const u32)ARRAY_SIZE(golden_settings_iceland_a11));
+		break;
+	default:
+		break;
+	}
+}
 
 /**
- * gmc8_mc_wait_for_idle - wait for MC idle callback.
+ * gmc7_mc_wait_for_idle - wait for MC idle callback.
  *
  * @adev: amdgpu_device pointer
  *
@@ -132,13 +162,21 @@
 	case CHIP_HAWAII:
 		chip_name = "hawaii";
 		break;
+	case CHIP_TOPAZ:
+		chip_name = "topaz";
+		break;
 	case CHIP_KAVERI:
 	case CHIP_KABINI:
+	case CHIP_MULLINS:
 		return 0;
 	default: BUG();
 	}
 
-	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+	if (adev->asic_type == CHIP_TOPAZ)
+		snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name);
+	else
+		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+
 	err = request_firmware(&adev->mc.fw, fw_name, adev->dev);
 	if (err)
 		goto out;
@@ -370,6 +408,10 @@
 	adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
 	adev->mc.visible_vram_size = adev->mc.aper_size;
 
+	/* In case the PCI BAR is larger than the actual amount of vram */
+	if (adev->mc.visible_vram_size > adev->mc.real_vram_size)
+		adev->mc.visible_vram_size = adev->mc.real_vram_size;
+
 	/* unless the user had overridden it, set the gart
 	 * size equal to the 1024 or vram, whichever is larger.
 	 */
@@ -751,7 +793,7 @@
 
 	for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) {
 		orig = data = RREG32(mc_cg_registers[i]);
-		if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_MC_LS))
+		if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS))
 			data |= mc_cg_ls_en[i];
 		else
 			data &= ~mc_cg_ls_en[i];
@@ -768,7 +810,7 @@
 
 	for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) {
 		orig = data = RREG32(mc_cg_registers[i]);
-		if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_MC_MGCG))
+		if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG))
 			data |= mc_cg_en[i];
 		else
 			data &= ~mc_cg_en[i];
@@ -784,7 +826,7 @@
 
 	orig = data = RREG32_PCIE(ixPCIE_CNTL2);
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_BIF_LS)) {
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_BIF_LS)) {
 		data = REG_SET_FIELD(data, PCIE_CNTL2, SLV_MEM_LS_EN, 1);
 		data = REG_SET_FIELD(data, PCIE_CNTL2, MST_MEM_LS_EN, 1);
 		data = REG_SET_FIELD(data, PCIE_CNTL2, REPLAY_MEM_LS_EN, 1);
@@ -807,7 +849,7 @@
 
 	orig = data = RREG32(mmHDP_HOST_PATH_CNTL);
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_HDP_MGCG))
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_MGCG))
 		data = REG_SET_FIELD(data, HDP_HOST_PATH_CNTL, CLOCK_GATING_DIS, 0);
 	else
 		data = REG_SET_FIELD(data, HDP_HOST_PATH_CNTL, CLOCK_GATING_DIS, 1);
@@ -823,7 +865,7 @@
 
 	orig = data = RREG32(mmHDP_MEM_POWER_LS);
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_HDP_LS))
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
 		data = REG_SET_FIELD(data, HDP_MEM_POWER_LS, LS_ENABLE, 1);
 	else
 		data = REG_SET_FIELD(data, HDP_MEM_POWER_LS, LS_ENABLE, 0);
@@ -861,14 +903,6 @@
 	gmc_v7_0_set_gart_funcs(adev);
 	gmc_v7_0_set_irq_funcs(adev);
 
-	if (adev->flags & AMD_IS_APU) {
-		adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
-	} else {
-		u32 tmp = RREG32(mmMC_SEQ_MISC0);
-		tmp &= MC_SEQ_MISC0__MT__MASK;
-		adev->mc.vram_type = gmc_v7_0_convert_vram_type(tmp);
-	}
-
 	return 0;
 }
 
@@ -889,6 +923,14 @@
 	if (r)
 		return r;
 
+	if (adev->flags & AMD_IS_APU) {
+		adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
+	} else {
+		u32 tmp = RREG32(mmMC_SEQ_MISC0);
+		tmp &= MC_SEQ_MISC0__MT__MASK;
+		adev->mc.vram_type = gmc_v7_0_convert_vram_type(tmp);
+	}
+
 	r = amdgpu_irq_add_id(adev, 146, &adev->mc.vm_fault);
 	if (r)
 		return r;
@@ -964,7 +1006,6 @@
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
 	if (adev->vm_manager.enabled) {
-		amdgpu_vm_manager_fini(adev);
 		gmc_v7_0_vm_fini(adev);
 		adev->vm_manager.enabled = false;
 	}
@@ -980,6 +1021,8 @@
 	int r;
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	gmc_v7_0_init_golden_registers(adev);
+
 	gmc_v7_0_mc_program(adev);
 
 	if (!(adev->flags & AMD_IS_APU)) {
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -42,9 +42,7 @@
 static void gmc_v8_0_set_gart_funcs(struct amdgpu_device *adev);
 static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev);
 
-MODULE_FIRMWARE("amdgpu/topaz_mc.bin");
 MODULE_FIRMWARE("amdgpu/tonga_mc.bin");
-MODULE_FIRMWARE("amdgpu/fiji_mc.bin");
 
 static const u32 golden_settings_tonga_a11[] =
 {
@@ -75,19 +73,6 @@
 	mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
 };
 
-static const u32 golden_settings_iceland_a11[] =
-{
-	mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff,
-	mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
-	mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
-	mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff
-};
-
-static const u32 iceland_mgcg_cgcg_init[] =
-{
-	mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
-};
-
 static const u32 cz_mgcg_cgcg_init[] =
 {
 	mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
@@ -102,14 +87,6 @@
 static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev)
 {
 	switch (adev->asic_type) {
-	case CHIP_TOPAZ:
-		amdgpu_program_register_sequence(adev,
-						 iceland_mgcg_cgcg_init,
-						 (const u32)ARRAY_SIZE(iceland_mgcg_cgcg_init));
-		amdgpu_program_register_sequence(adev,
-						 golden_settings_iceland_a11,
-						 (const u32)ARRAY_SIZE(golden_settings_iceland_a11));
-		break;
 	case CHIP_FIJI:
 		amdgpu_program_register_sequence(adev,
 						 fiji_mgcg_cgcg_init,
@@ -229,15 +206,10 @@
 	DRM_DEBUG("\n");
 
 	switch (adev->asic_type) {
-	case CHIP_TOPAZ:
-		chip_name = "topaz";
-		break;
 	case CHIP_TONGA:
 		chip_name = "tonga";
 		break;
 	case CHIP_FIJI:
-		chip_name = "fiji";
-		break;
 	case CHIP_CARRIZO:
 	case CHIP_STONEY:
 		return 0;
@@ -476,6 +448,10 @@
 	adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
 	adev->mc.visible_vram_size = adev->mc.aper_size;
 
+	/* In case the PCI BAR is larger than the actual amount of vram */
+	if (adev->mc.visible_vram_size > adev->mc.real_vram_size)
+		adev->mc.visible_vram_size = adev->mc.real_vram_size;
+
 	/* unless the user had overridden it, set the gart
 	 * size equal to the 1024 or vram, whichever is larger.
 	 */
@@ -880,14 +856,6 @@
 	gmc_v8_0_set_gart_funcs(adev);
 	gmc_v8_0_set_irq_funcs(adev);
 
-	if (adev->flags & AMD_IS_APU) {
-		adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
-	} else {
-		u32 tmp = RREG32(mmMC_SEQ_MISC0);
-		tmp &= MC_SEQ_MISC0__MT__MASK;
-		adev->mc.vram_type = gmc_v8_0_convert_vram_type(tmp);
-	}
-
 	return 0;
 }
 
@@ -898,6 +866,8 @@
 	return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0);
 }
 
+#define mmMC_SEQ_MISC0_FIJI 0xA71
+
 static int gmc_v8_0_sw_init(void *handle)
 {
 	int r;
@@ -908,6 +878,19 @@
 	if (r)
 		return r;
 
+	if (adev->flags & AMD_IS_APU) {
+		adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
+	} else {
+		u32 tmp;
+
+		if (adev->asic_type == CHIP_FIJI)
+			tmp = RREG32(mmMC_SEQ_MISC0_FIJI);
+		else
+			tmp = RREG32(mmMC_SEQ_MISC0);
+		tmp &= MC_SEQ_MISC0__MT__MASK;
+		adev->mc.vram_type = gmc_v8_0_convert_vram_type(tmp);
+	}
+
 	r = amdgpu_irq_add_id(adev, 146, &adev->mc.vm_fault);
 	if (r)
 		return r;
@@ -1003,7 +986,7 @@
 
 	gmc_v8_0_mc_program(adev);
 
-	if (!(adev->flags & AMD_IS_APU)) {
+	if (adev->asic_type == CHIP_TONGA) {
 		r = gmc_v8_0_mc_load_microcode(adev);
 		if (r) {
 			DRM_ERROR("Failed to load MC firmware!\n");
@@ -1033,7 +1016,6 @@
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
 	if (adev->vm_manager.enabled) {
-		amdgpu_vm_manager_fini(adev);
 		gmc_v8_0_vm_fini(adev);
 		adev->vm_manager.enabled = false;
 	}
@@ -1324,9 +1306,181 @@
 	return 0;
 }
 
+static void fiji_update_mc_medium_grain_clock_gating(struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t data;
+
+	if (enable) {
+		data = RREG32(mmMC_HUB_MISC_HUB_CG);
+		data |= MC_HUB_MISC_HUB_CG__ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_HUB_CG, data);
+
+		data = RREG32(mmMC_HUB_MISC_SIP_CG);
+		data |= MC_HUB_MISC_SIP_CG__ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_SIP_CG, data);
+
+		data = RREG32(mmMC_HUB_MISC_VM_CG);
+		data |= MC_HUB_MISC_VM_CG__ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_VM_CG, data);
+
+		data = RREG32(mmMC_XPB_CLK_GAT);
+		data |= MC_XPB_CLK_GAT__ENABLE_MASK;
+		WREG32(mmMC_XPB_CLK_GAT, data);
+
+		data = RREG32(mmATC_MISC_CG);
+		data |= ATC_MISC_CG__ENABLE_MASK;
+		WREG32(mmATC_MISC_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_WR_CG);
+		data |= MC_CITF_MISC_WR_CG__ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_WR_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_RD_CG);
+		data |= MC_CITF_MISC_RD_CG__ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_RD_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_VM_CG);
+		data |= MC_CITF_MISC_VM_CG__ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_VM_CG, data);
+
+		data = RREG32(mmVM_L2_CG);
+		data |= VM_L2_CG__ENABLE_MASK;
+		WREG32(mmVM_L2_CG, data);
+	} else {
+		data = RREG32(mmMC_HUB_MISC_HUB_CG);
+		data &= ~MC_HUB_MISC_HUB_CG__ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_HUB_CG, data);
+
+		data = RREG32(mmMC_HUB_MISC_SIP_CG);
+		data &= ~MC_HUB_MISC_SIP_CG__ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_SIP_CG, data);
+
+		data = RREG32(mmMC_HUB_MISC_VM_CG);
+		data &= ~MC_HUB_MISC_VM_CG__ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_VM_CG, data);
+
+		data = RREG32(mmMC_XPB_CLK_GAT);
+		data &= ~MC_XPB_CLK_GAT__ENABLE_MASK;
+		WREG32(mmMC_XPB_CLK_GAT, data);
+
+		data = RREG32(mmATC_MISC_CG);
+		data &= ~ATC_MISC_CG__ENABLE_MASK;
+		WREG32(mmATC_MISC_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_WR_CG);
+		data &= ~MC_CITF_MISC_WR_CG__ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_WR_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_RD_CG);
+		data &= ~MC_CITF_MISC_RD_CG__ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_RD_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_VM_CG);
+		data &= ~MC_CITF_MISC_VM_CG__ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_VM_CG, data);
+
+		data = RREG32(mmVM_L2_CG);
+		data &= ~VM_L2_CG__ENABLE_MASK;
+		WREG32(mmVM_L2_CG, data);
+	}
+}
+
+static void fiji_update_mc_light_sleep(struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t data;
+
+	if (enable) {
+		data = RREG32(mmMC_HUB_MISC_HUB_CG);
+		data |= MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_HUB_CG, data);
+
+		data = RREG32(mmMC_HUB_MISC_SIP_CG);
+		data |= MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_SIP_CG, data);
+
+		data = RREG32(mmMC_HUB_MISC_VM_CG);
+		data |= MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_VM_CG, data);
+
+		data = RREG32(mmMC_XPB_CLK_GAT);
+		data |= MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_XPB_CLK_GAT, data);
+
+		data = RREG32(mmATC_MISC_CG);
+		data |= ATC_MISC_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmATC_MISC_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_WR_CG);
+		data |= MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_WR_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_RD_CG);
+		data |= MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_RD_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_VM_CG);
+		data |= MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_VM_CG, data);
+
+		data = RREG32(mmVM_L2_CG);
+		data |= VM_L2_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmVM_L2_CG, data);
+	} else {
+		data = RREG32(mmMC_HUB_MISC_HUB_CG);
+		data &= ~MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_HUB_CG, data);
+
+		data = RREG32(mmMC_HUB_MISC_SIP_CG);
+		data &= ~MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_SIP_CG, data);
+
+		data = RREG32(mmMC_HUB_MISC_VM_CG);
+		data &= ~MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_HUB_MISC_VM_CG, data);
+
+		data = RREG32(mmMC_XPB_CLK_GAT);
+		data &= ~MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_XPB_CLK_GAT, data);
+
+		data = RREG32(mmATC_MISC_CG);
+		data &= ~ATC_MISC_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmATC_MISC_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_WR_CG);
+		data &= ~MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_WR_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_RD_CG);
+		data &= ~MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_RD_CG, data);
+
+		data = RREG32(mmMC_CITF_MISC_VM_CG);
+		data &= ~MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmMC_CITF_MISC_VM_CG, data);
+
+		data = RREG32(mmVM_L2_CG);
+		data &= ~VM_L2_CG__MEM_LS_ENABLE_MASK;
+		WREG32(mmVM_L2_CG, data);
+	}
+}
+
 static int gmc_v8_0_set_clockgating_state(void *handle,
 					  enum amd_clockgating_state state)
 {
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	switch (adev->asic_type) {
+	case CHIP_FIJI:
+		fiji_update_mc_medium_grain_clock_gating(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		fiji_update_mc_light_sleep(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		break;
+	default:
+		break;
+	}
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
@@ -192,19 +192,34 @@
 
 	wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
 
-	if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
-		wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
-		/* When a ring buffer overflow happen start parsing interrupt
-		 * from the last not overwritten vector (wptr + 16). Hopefully
-		 * this should allow us to catchup.
-		 */
-		dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
-			wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
-		adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
-		tmp = RREG32(mmIH_RB_CNTL);
-		tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
-		WREG32(mmIH_RB_CNTL, tmp);
-	}
+	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
+		goto out;
+
+	/* Double check that the overflow wasn't already cleared. */
+	wptr = RREG32(mmIH_RB_WPTR);
+
+	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
+		goto out;
+
+	wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
+	/* When a ring buffer overflow happen start parsing interrupt
+	 * from the last not overwritten vector (wptr + 16). Hopefully
+	 * this should allow us to catchup.
+	 */
+	dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
+		wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
+	adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+	tmp = RREG32(mmIH_RB_CNTL);
+	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
+	WREG32(mmIH_RB_CNTL, tmp);
+
+	/* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+	 * can be detected.
+	 */
+	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+	WREG32(mmIH_RB_CNTL, tmp);
+
+out:
 	return (wptr & adev->irq.ih.ptr_mask);
 }
 
@@ -253,8 +268,14 @@
 static int iceland_ih_early_init(void *handle)
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	int ret;
+
+	ret = amdgpu_irq_add_domain(adev);
+	if (ret)
+		return ret;
 
 	iceland_ih_set_interrupt_funcs(adev);
+
 	return 0;
 }
 
@@ -278,6 +299,7 @@
 
 	amdgpu_irq_fini(adev);
 	amdgpu_ih_ring_fini(adev);
+	amdgpu_irq_remove_domain(adev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/iceland_smc.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/iceland_smc.c
@@ -432,7 +432,7 @@
 		case AMDGPU_UCODE_ID_CP_ME:
 			return UCODE_ID_CP_ME_MASK;
 		case AMDGPU_UCODE_ID_CP_MEC1:
-			return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK | UCODE_ID_CP_MEC_JT2_MASK;
+			return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK;
 		case AMDGPU_UCODE_ID_CP_MEC2:
 			return UCODE_ID_CP_MEC_MASK;
 		case AMDGPU_UCODE_ID_RLC_G:
@@ -522,12 +522,6 @@
 		return -EINVAL;
 	}
 
-	if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2,
-			&toc->entry[toc->num_entries++])) {
-		DRM_ERROR("Failed to get firmware entry for MEC_JT2\n");
-		return -EINVAL;
-	}
-
 	if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
 			&toc->entry[toc->num_entries++])) {
 		DRM_ERROR("Failed to get firmware entry for SDMA0\n");
@@ -550,8 +544,8 @@
 			UCODE_ID_CP_ME_MASK |
 			UCODE_ID_CP_PFP_MASK |
 			UCODE_ID_CP_MEC_MASK |
-			UCODE_ID_CP_MEC_JT1_MASK |
-			UCODE_ID_CP_MEC_JT2_MASK;
+			UCODE_ID_CP_MEC_JT1_MASK;
+
 
 	if (iceland_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
 		DRM_ERROR("Fail to request SMU load ucode\n");
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
@@ -2258,7 +2258,7 @@
 	if (pi->caps_stable_p_state) {
 		stable_p_state_sclk = (max_limits->sclk * 75) / 100;
 
-		for (i = table->count - 1; i >= 0; i++) {
+		for (i = table->count - 1; i >= 0; i--) {
 			if (stable_p_state_sclk >= table->entries[i].clk) {
 				stable_p_state_sclk = table->entries[i].clk;
 				break;
@@ -2771,10 +2771,8 @@
 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
 		ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL);
-		if (ps == NULL) {
-			kfree(adev->pm.dpm.ps);
+		if (ps == NULL)
 			return -ENOMEM;
-		}
 		adev->pm.dpm.ps[i].ps_priv = ps;
 		k = 0;
 		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
@@ -2859,11 +2857,11 @@
 	pi->voltage_drop_t = 0;
 	pi->caps_sclk_throttle_low_notification = false;
 	pi->caps_fps = false; /* true? */
-	pi->caps_uvd_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_UVD) ? true : false;
+	pi->caps_uvd_pg = (adev->pg_flags & AMD_PG_SUPPORT_UVD) ? true : false;
 	pi->caps_uvd_dpm = true;
-	pi->caps_vce_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_VCE) ? true : false;
-	pi->caps_samu_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_SAMU) ? true : false;
-	pi->caps_acp_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_ACP) ? true : false;
+	pi->caps_vce_pg = (adev->pg_flags & AMD_PG_SUPPORT_VCE) ? true : false;
+	pi->caps_samu_pg = (adev->pg_flags & AMD_PG_SUPPORT_SAMU) ? true : false;
+	pi->caps_acp_pg = (adev->pg_flags & AMD_PG_SUPPORT_ACP) ? true : false;
 	pi->caps_stable_p_state = false;
 
 	ret = kv_parse_sys_info_table(adev);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -32,8 +32,8 @@
 #include "oss/oss_2_4_d.h"
 #include "oss/oss_2_4_sh_mask.h"
 
-#include "gmc/gmc_8_1_d.h"
-#include "gmc/gmc_8_1_sh_mask.h"
+#include "gmc/gmc_7_1_d.h"
+#include "gmc/gmc_7_1_sh_mask.h"
 
 #include "gca/gfx_8_0_d.h"
 #include "gca/gfx_8_0_enum.h"
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -727,18 +727,20 @@
 {
 	int r, i;
 
-	if (!adev->firmware.smu_load) {
-		r = sdma_v3_0_load_microcode(adev);
-		if (r)
-			return r;
-	} else {
-		for (i = 0; i < adev->sdma.num_instances; i++) {
-			r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
-									 (i == 0) ?
-									 AMDGPU_UCODE_ID_SDMA0 :
-									 AMDGPU_UCODE_ID_SDMA1);
+	if (!adev->pp_enabled) {
+		if (!adev->firmware.smu_load) {
+			r = sdma_v3_0_load_microcode(adev);
 			if (r)
-				return -EINVAL;
+				return r;
+		} else {
+			for (i = 0; i < adev->sdma.num_instances; i++) {
+				r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+										 (i == 0) ?
+										 AMDGPU_UCODE_ID_SDMA0 :
+										 AMDGPU_UCODE_ID_SDMA1);
+				if (r)
+					return -EINVAL;
+			}
 		}
 	}
 
@@ -1427,9 +1429,114 @@
 	return 0;
 }
 
+static void fiji_update_sdma_medium_grain_clock_gating(
+		struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t temp, data;
+
+	if (enable) {
+		temp = data = RREG32(mmSDMA0_CLK_CTRL);
+		data &= ~(SDMA0_CLK_CTRL__SOFT_OVERRIDE7_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE6_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE5_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE4_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE3_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE2_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE1_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE0_MASK);
+		if (data != temp)
+			WREG32(mmSDMA0_CLK_CTRL, data);
+
+		temp = data = RREG32(mmSDMA1_CLK_CTRL);
+		data &= ~(SDMA1_CLK_CTRL__SOFT_OVERRIDE7_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE6_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE5_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE4_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE3_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE2_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE1_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE0_MASK);
+
+		if (data != temp)
+			WREG32(mmSDMA1_CLK_CTRL, data);
+	} else {
+		temp = data = RREG32(mmSDMA0_CLK_CTRL);
+		data |= SDMA0_CLK_CTRL__SOFT_OVERRIDE7_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE6_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE5_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE4_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE3_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE2_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE1_MASK |
+				SDMA0_CLK_CTRL__SOFT_OVERRIDE0_MASK;
+
+		if (data != temp)
+			WREG32(mmSDMA0_CLK_CTRL, data);
+
+		temp = data = RREG32(mmSDMA1_CLK_CTRL);
+		data |= SDMA1_CLK_CTRL__SOFT_OVERRIDE7_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE6_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE5_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE4_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE3_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE2_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE1_MASK |
+				SDMA1_CLK_CTRL__SOFT_OVERRIDE0_MASK;
+
+		if (data != temp)
+			WREG32(mmSDMA1_CLK_CTRL, data);
+	}
+}
+
+static void fiji_update_sdma_medium_grain_light_sleep(
+		struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t temp, data;
+
+	if (enable) {
+		temp = data = RREG32(mmSDMA0_POWER_CNTL);
+		data |= SDMA0_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
+
+		if (temp != data)
+			WREG32(mmSDMA0_POWER_CNTL, data);
+
+		temp = data = RREG32(mmSDMA1_POWER_CNTL);
+		data |= SDMA1_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
+
+		if (temp != data)
+			WREG32(mmSDMA1_POWER_CNTL, data);
+	} else {
+		temp = data = RREG32(mmSDMA0_POWER_CNTL);
+		data &= ~SDMA0_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
+
+		if (temp != data)
+			WREG32(mmSDMA0_POWER_CNTL, data);
+
+		temp = data = RREG32(mmSDMA1_POWER_CNTL);
+		data &= ~SDMA1_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
+
+		if (temp != data)
+			WREG32(mmSDMA1_POWER_CNTL, data);
+	}
+}
+
 static int sdma_v3_0_set_clockgating_state(void *handle,
 					  enum amd_clockgating_state state)
 {
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	switch (adev->asic_type) {
+	case CHIP_FIJI:
+		fiji_update_sdma_medium_grain_clock_gating(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		fiji_update_sdma_medium_grain_light_sleep(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		break;
+	default:
+		break;
+	}
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c
@@ -24,7 +24,7 @@
 #include <linux/firmware.h>
 #include "drmP.h"
 #include "amdgpu.h"
-#include "tonga_smumgr.h"
+#include "tonga_smum.h"
 
 MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
 
@@ -122,25 +122,12 @@
 
 static int tonga_dpm_suspend(void *handle)
 {
-	return 0;
+	return tonga_dpm_hw_fini(handle);
 }
 
 static int tonga_dpm_resume(void *handle)
 {
-	int ret;
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-	mutex_lock(&adev->pm.mutex);
-
-	ret = tonga_smu_start(adev);
-	if (ret) {
-		DRM_ERROR("SMU start failed\n");
-		goto fail;
-	}
-
-fail:
-	mutex_unlock(&adev->pm.mutex);
-	return ret;
+	return tonga_dpm_hw_init(handle);
 }
 
 static int tonga_dpm_set_clockgating_state(void *handle,
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
@@ -203,19 +203,36 @@
 	else
 		wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
 
-	if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
-		wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
-		/* When a ring buffer overflow happen start parsing interrupt
-		 * from the last not overwritten vector (wptr + 16). Hopefully
-		 * this should allow us to catchup.
-		 */
-		dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
-			wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
-		adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
-		tmp = RREG32(mmIH_RB_CNTL);
-		tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
-		WREG32(mmIH_RB_CNTL, tmp);
-	}
+	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
+		goto out;
+
+	/* Double check that the overflow wasn't already cleared. */
+	wptr = RREG32(mmIH_RB_WPTR);
+
+	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
+		goto out;
+
+	wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
+
+	/* When a ring buffer overflow happen start parsing interrupt
+	 * from the last not overwritten vector (wptr + 16). Hopefully
+	 * this should allow us to catchup.
+	 */
+
+	dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
+		wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
+	adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+	tmp = RREG32(mmIH_RB_CNTL);
+	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
+	WREG32(mmIH_RB_CNTL, tmp);
+
+	/* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+	 * can be detected.
+	 */
+	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+	WREG32(mmIH_RB_CNTL, tmp);
+
+out:
 	return (wptr & adev->irq.ih.ptr_mask);
 }
 
@@ -273,8 +290,14 @@
 static int tonga_ih_early_init(void *handle)
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	int ret;
+
+	ret = amdgpu_irq_add_domain(adev);
+	if (ret)
+		return ret;
 
 	tonga_ih_set_interrupt_funcs(adev);
+
 	return 0;
 }
 
@@ -301,6 +324,7 @@
 
 	amdgpu_irq_fini(adev);
 	amdgpu_ih_ring_fini(adev);
+	amdgpu_irq_add_domain(adev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/tonga_smc.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/tonga_smc.c
@@ -25,7 +25,7 @@
 #include "drmP.h"
 #include "amdgpu.h"
 #include "tonga_ppsmc.h"
-#include "tonga_smumgr.h"
+#include "tonga_smum.h"
 #include "smu_ucode_xfer_vi.h"
 #include "amdgpu_ucode.h"
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/tonga_smum.h
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/tonga_smum.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef TONGA_SMUMGR_H
+#define TONGA_SMUMGR_H
+
+#include "tonga_ppsmc.h"
+
+int tonga_smu_init(struct amdgpu_device *adev);
+int tonga_smu_fini(struct amdgpu_device *adev);
+int tonga_smu_start(struct amdgpu_device *adev);
+
+struct tonga_smu_private_data
+{
+	uint8_t *header;
+	uint32_t smu_buffer_addr_high;
+	uint32_t smu_buffer_addr_low;
+	uint32_t header_addr_high;
+	uint32_t header_addr_low;
+};
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
@@ -611,7 +611,7 @@
 {
 	u32 orig, data;
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_UVD_MGCG)) {
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) {
 		data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
 		data = 0xfff;
 		WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
@@ -830,6 +830,9 @@
 	bool gate = false;
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
+		return 0;
+
 	if (state == AMD_CG_STATE_GATE)
 		gate = true;
 
@@ -848,7 +851,10 @@
 	 * revisit this when there is a cleaner line between
 	 * the smc and the hw blocks
 	 */
-	 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
+		return 0;
 
 	if (state == AMD_PG_STATE_GATE) {
 		uvd_v4_2_stop(adev);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
@@ -774,6 +774,11 @@
 static int uvd_v5_0_set_clockgating_state(void *handle,
 					  enum amd_clockgating_state state)
 {
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
+		return 0;
+
 	return 0;
 }
 
@@ -789,6 +794,9 @@
 	 */
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
+		return 0;
+
 	if (state == AMD_PG_STATE_GATE) {
 		uvd_v5_0_stop(adev);
 		return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -279,6 +279,234 @@
 	WREG32(mmUVD_VCPU_CACHE_SIZE2, size);
 }
 
+static void cz_set_uvd_clock_gating_branches(struct amdgpu_device *adev,
+		bool enable)
+{
+	u32 data, data1;
+
+	data = RREG32(mmUVD_CGC_GATE);
+	data1 = RREG32(mmUVD_SUVD_CGC_GATE);
+	if (enable) {
+		data |= UVD_CGC_GATE__SYS_MASK |
+				UVD_CGC_GATE__UDEC_MASK |
+				UVD_CGC_GATE__MPEG2_MASK |
+				UVD_CGC_GATE__RBC_MASK |
+				UVD_CGC_GATE__LMI_MC_MASK |
+				UVD_CGC_GATE__IDCT_MASK |
+				UVD_CGC_GATE__MPRD_MASK |
+				UVD_CGC_GATE__MPC_MASK |
+				UVD_CGC_GATE__LBSI_MASK |
+				UVD_CGC_GATE__LRBBM_MASK |
+				UVD_CGC_GATE__UDEC_RE_MASK |
+				UVD_CGC_GATE__UDEC_CM_MASK |
+				UVD_CGC_GATE__UDEC_IT_MASK |
+				UVD_CGC_GATE__UDEC_DB_MASK |
+				UVD_CGC_GATE__UDEC_MP_MASK |
+				UVD_CGC_GATE__WCB_MASK |
+				UVD_CGC_GATE__VCPU_MASK |
+				UVD_CGC_GATE__SCPU_MASK;
+		data1 |= UVD_SUVD_CGC_GATE__SRE_MASK |
+				UVD_SUVD_CGC_GATE__SIT_MASK |
+				UVD_SUVD_CGC_GATE__SMP_MASK |
+				UVD_SUVD_CGC_GATE__SCM_MASK |
+				UVD_SUVD_CGC_GATE__SDB_MASK |
+				UVD_SUVD_CGC_GATE__SRE_H264_MASK |
+				UVD_SUVD_CGC_GATE__SRE_HEVC_MASK |
+				UVD_SUVD_CGC_GATE__SIT_H264_MASK |
+				UVD_SUVD_CGC_GATE__SIT_HEVC_MASK |
+				UVD_SUVD_CGC_GATE__SCM_H264_MASK |
+				UVD_SUVD_CGC_GATE__SCM_HEVC_MASK |
+				UVD_SUVD_CGC_GATE__SDB_H264_MASK |
+				UVD_SUVD_CGC_GATE__SDB_HEVC_MASK;
+	} else {
+		data &= ~(UVD_CGC_GATE__SYS_MASK |
+				UVD_CGC_GATE__UDEC_MASK |
+				UVD_CGC_GATE__MPEG2_MASK |
+				UVD_CGC_GATE__RBC_MASK |
+				UVD_CGC_GATE__LMI_MC_MASK |
+				UVD_CGC_GATE__LMI_UMC_MASK |
+				UVD_CGC_GATE__IDCT_MASK |
+				UVD_CGC_GATE__MPRD_MASK |
+				UVD_CGC_GATE__MPC_MASK |
+				UVD_CGC_GATE__LBSI_MASK |
+				UVD_CGC_GATE__LRBBM_MASK |
+				UVD_CGC_GATE__UDEC_RE_MASK |
+				UVD_CGC_GATE__UDEC_CM_MASK |
+				UVD_CGC_GATE__UDEC_IT_MASK |
+				UVD_CGC_GATE__UDEC_DB_MASK |
+				UVD_CGC_GATE__UDEC_MP_MASK |
+				UVD_CGC_GATE__WCB_MASK |
+				UVD_CGC_GATE__VCPU_MASK |
+				UVD_CGC_GATE__SCPU_MASK);
+		data1 &= ~(UVD_SUVD_CGC_GATE__SRE_MASK |
+				UVD_SUVD_CGC_GATE__SIT_MASK |
+				UVD_SUVD_CGC_GATE__SMP_MASK |
+				UVD_SUVD_CGC_GATE__SCM_MASK |
+				UVD_SUVD_CGC_GATE__SDB_MASK |
+				UVD_SUVD_CGC_GATE__SRE_H264_MASK |
+				UVD_SUVD_CGC_GATE__SRE_HEVC_MASK |
+				UVD_SUVD_CGC_GATE__SIT_H264_MASK |
+				UVD_SUVD_CGC_GATE__SIT_HEVC_MASK |
+				UVD_SUVD_CGC_GATE__SCM_H264_MASK |
+				UVD_SUVD_CGC_GATE__SCM_HEVC_MASK |
+				UVD_SUVD_CGC_GATE__SDB_H264_MASK |
+				UVD_SUVD_CGC_GATE__SDB_HEVC_MASK);
+	}
+	WREG32(mmUVD_CGC_GATE, data);
+	WREG32(mmUVD_SUVD_CGC_GATE, data1);
+}
+
+static void tonga_set_uvd_clock_gating_branches(struct amdgpu_device *adev,
+		bool enable)
+{
+	u32 data, data1;
+
+	data = RREG32(mmUVD_CGC_GATE);
+	data1 = RREG32(mmUVD_SUVD_CGC_GATE);
+	if (enable) {
+		data |= UVD_CGC_GATE__SYS_MASK |
+				UVD_CGC_GATE__UDEC_MASK |
+				UVD_CGC_GATE__MPEG2_MASK |
+				UVD_CGC_GATE__RBC_MASK |
+				UVD_CGC_GATE__LMI_MC_MASK |
+				UVD_CGC_GATE__IDCT_MASK |
+				UVD_CGC_GATE__MPRD_MASK |
+				UVD_CGC_GATE__MPC_MASK |
+				UVD_CGC_GATE__LBSI_MASK |
+				UVD_CGC_GATE__LRBBM_MASK |
+				UVD_CGC_GATE__UDEC_RE_MASK |
+				UVD_CGC_GATE__UDEC_CM_MASK |
+				UVD_CGC_GATE__UDEC_IT_MASK |
+				UVD_CGC_GATE__UDEC_DB_MASK |
+				UVD_CGC_GATE__UDEC_MP_MASK |
+				UVD_CGC_GATE__WCB_MASK |
+				UVD_CGC_GATE__VCPU_MASK |
+				UVD_CGC_GATE__SCPU_MASK;
+		data1 |= UVD_SUVD_CGC_GATE__SRE_MASK |
+				UVD_SUVD_CGC_GATE__SIT_MASK |
+				UVD_SUVD_CGC_GATE__SMP_MASK |
+				UVD_SUVD_CGC_GATE__SCM_MASK |
+				UVD_SUVD_CGC_GATE__SDB_MASK;
+	} else {
+		data &= ~(UVD_CGC_GATE__SYS_MASK |
+				UVD_CGC_GATE__UDEC_MASK |
+				UVD_CGC_GATE__MPEG2_MASK |
+				UVD_CGC_GATE__RBC_MASK |
+				UVD_CGC_GATE__LMI_MC_MASK |
+				UVD_CGC_GATE__LMI_UMC_MASK |
+				UVD_CGC_GATE__IDCT_MASK |
+				UVD_CGC_GATE__MPRD_MASK |
+				UVD_CGC_GATE__MPC_MASK |
+				UVD_CGC_GATE__LBSI_MASK |
+				UVD_CGC_GATE__LRBBM_MASK |
+				UVD_CGC_GATE__UDEC_RE_MASK |
+				UVD_CGC_GATE__UDEC_CM_MASK |
+				UVD_CGC_GATE__UDEC_IT_MASK |
+				UVD_CGC_GATE__UDEC_DB_MASK |
+				UVD_CGC_GATE__UDEC_MP_MASK |
+				UVD_CGC_GATE__WCB_MASK |
+				UVD_CGC_GATE__VCPU_MASK |
+				UVD_CGC_GATE__SCPU_MASK);
+		data1 &= ~(UVD_SUVD_CGC_GATE__SRE_MASK |
+				UVD_SUVD_CGC_GATE__SIT_MASK |
+				UVD_SUVD_CGC_GATE__SMP_MASK |
+				UVD_SUVD_CGC_GATE__SCM_MASK |
+				UVD_SUVD_CGC_GATE__SDB_MASK);
+	}
+	WREG32(mmUVD_CGC_GATE, data);
+	WREG32(mmUVD_SUVD_CGC_GATE, data1);
+}
+
+static void uvd_v6_0_set_uvd_dynamic_clock_mode(struct amdgpu_device *adev,
+		bool swmode)
+{
+	u32 data, data1 = 0, data2;
+
+	/* Always un-gate UVD REGS bit */
+	data = RREG32(mmUVD_CGC_GATE);
+	data &= ~(UVD_CGC_GATE__REGS_MASK);
+	WREG32(mmUVD_CGC_GATE, data);
+
+	data = RREG32(mmUVD_CGC_CTRL);
+	data &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK |
+			UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK);
+	data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK |
+			1 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_GATE_DLY_TIMER) |
+			4 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_OFF_DELAY);
+
+	data2 = RREG32(mmUVD_SUVD_CGC_CTRL);
+	if (swmode) {
+		data &= ~(UVD_CGC_CTRL__UDEC_RE_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_CM_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_IT_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_DB_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_MP_MODE_MASK |
+				UVD_CGC_CTRL__SYS_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_MODE_MASK |
+				UVD_CGC_CTRL__MPEG2_MODE_MASK |
+				UVD_CGC_CTRL__REGS_MODE_MASK |
+				UVD_CGC_CTRL__RBC_MODE_MASK |
+				UVD_CGC_CTRL__LMI_MC_MODE_MASK |
+				UVD_CGC_CTRL__LMI_UMC_MODE_MASK |
+				UVD_CGC_CTRL__IDCT_MODE_MASK |
+				UVD_CGC_CTRL__MPRD_MODE_MASK |
+				UVD_CGC_CTRL__MPC_MODE_MASK |
+				UVD_CGC_CTRL__LBSI_MODE_MASK |
+				UVD_CGC_CTRL__LRBBM_MODE_MASK |
+				UVD_CGC_CTRL__WCB_MODE_MASK |
+				UVD_CGC_CTRL__VCPU_MODE_MASK |
+				UVD_CGC_CTRL__JPEG_MODE_MASK |
+				UVD_CGC_CTRL__SCPU_MODE_MASK);
+		data1 |= UVD_CGC_CTRL2__DYN_OCLK_RAMP_EN_MASK |
+				UVD_CGC_CTRL2__DYN_RCLK_RAMP_EN_MASK;
+		data1 &= ~UVD_CGC_CTRL2__GATER_DIV_ID_MASK;
+		data1 |= 7 << REG_FIELD_SHIFT(UVD_CGC_CTRL2, GATER_DIV_ID);
+		data2 &= ~(UVD_SUVD_CGC_CTRL__SRE_MODE_MASK |
+				UVD_SUVD_CGC_CTRL__SIT_MODE_MASK |
+				UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
+				UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
+				UVD_SUVD_CGC_CTRL__SDB_MODE_MASK);
+	} else {
+		data |= UVD_CGC_CTRL__UDEC_RE_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_CM_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_IT_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_DB_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_MP_MODE_MASK |
+				UVD_CGC_CTRL__SYS_MODE_MASK |
+				UVD_CGC_CTRL__UDEC_MODE_MASK |
+				UVD_CGC_CTRL__MPEG2_MODE_MASK |
+				UVD_CGC_CTRL__REGS_MODE_MASK |
+				UVD_CGC_CTRL__RBC_MODE_MASK |
+				UVD_CGC_CTRL__LMI_MC_MODE_MASK |
+				UVD_CGC_CTRL__LMI_UMC_MODE_MASK |
+				UVD_CGC_CTRL__IDCT_MODE_MASK |
+				UVD_CGC_CTRL__MPRD_MODE_MASK |
+				UVD_CGC_CTRL__MPC_MODE_MASK |
+				UVD_CGC_CTRL__LBSI_MODE_MASK |
+				UVD_CGC_CTRL__LRBBM_MODE_MASK |
+				UVD_CGC_CTRL__WCB_MODE_MASK |
+				UVD_CGC_CTRL__VCPU_MODE_MASK |
+				UVD_CGC_CTRL__SCPU_MODE_MASK;
+		data2 |= UVD_SUVD_CGC_CTRL__SRE_MODE_MASK |
+				UVD_SUVD_CGC_CTRL__SIT_MODE_MASK |
+				UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
+				UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
+				UVD_SUVD_CGC_CTRL__SDB_MODE_MASK;
+	}
+	WREG32(mmUVD_CGC_CTRL, data);
+	WREG32(mmUVD_SUVD_CGC_CTRL, data2);
+
+	data = RREG32_UVD_CTX(ixUVD_CGC_CTRL2);
+	data &= ~(REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_OCLK_RAMP_EN) |
+			REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_RCLK_RAMP_EN) |
+			REG_FIELD_MASK(UVD_CGC_CTRL2, GATER_DIV_ID));
+	data1 &= (REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_OCLK_RAMP_EN) |
+			REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_RCLK_RAMP_EN) |
+			REG_FIELD_MASK(UVD_CGC_CTRL2, GATER_DIV_ID));
+	data |= data1;
+	WREG32_UVD_CTX(ixUVD_CGC_CTRL2, data);
+}
+
 /**
  * uvd_v6_0_start - start UVD block
  *
@@ -303,8 +531,19 @@
 
 	uvd_v6_0_mc_resume(adev);
 
-	/* disable clock gating */
-	WREG32(mmUVD_CGC_GATE, 0);
+	/* Set dynamic clock gating in S/W control mode */
+	if (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG) {
+		if (adev->flags & AMD_IS_APU)
+			cz_set_uvd_clock_gating_branches(adev, false);
+		else
+			tonga_set_uvd_clock_gating_branches(adev, false);
+		uvd_v6_0_set_uvd_dynamic_clock_mode(adev, true);
+	} else {
+		/* disable clock gating */
+		uint32_t data = RREG32(mmUVD_CGC_CTRL);
+		data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
+		WREG32(mmUVD_CGC_CTRL, data);
+	}
 
 	/* disable interupt */
 	WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1));
@@ -758,6 +997,24 @@
 static int uvd_v6_0_set_clockgating_state(void *handle,
 					  enum amd_clockgating_state state)
 {
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
+
+	if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
+		return 0;
+
+	if (enable) {
+		if (adev->flags & AMD_IS_APU)
+			cz_set_uvd_clock_gating_branches(adev, enable);
+		else
+			tonga_set_uvd_clock_gating_branches(adev, enable);
+		uvd_v6_0_set_uvd_dynamic_clock_mode(adev, true);
+	} else {
+		uint32_t data = RREG32(mmUVD_CGC_CTRL);
+		data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
+		WREG32(mmUVD_CGC_CTRL, data);
+	}
+
 	return 0;
 }
 
@@ -773,6 +1030,9 @@
 	 */
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
+		return 0;
+
 	if (state == AMD_PG_STATE_GATE) {
 		uvd_v6_0_stop(adev);
 		return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
@@ -373,7 +373,7 @@
 {
 	bool sw_cg = false;
 
-	if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG)) {
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) {
 		if (sw_cg)
 			vce_v2_0_set_sw_cg(adev, true);
 		else
@@ -608,6 +608,9 @@
 	 */
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
+		return 0;
+
 	if (state == AMD_PG_STATE_GATE)
 		/* XXX do we need a vce_v2_0_stop()? */
 		return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -103,6 +103,108 @@
 		WREG32(mmVCE_RB_WPTR2, ring->wptr);
 }
 
+static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override)
+{
+	u32 tmp, data;
+
+	tmp = data = RREG32(mmVCE_RB_ARB_CTRL);
+	if (override)
+		data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
+	else
+		data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
+
+	if (tmp != data)
+		WREG32(mmVCE_RB_ARB_CTRL, data);
+}
+
+static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
+					     bool gated)
+{
+	u32 tmp, data;
+	/* Set Override to disable Clock Gating */
+	vce_v3_0_override_vce_clock_gating(adev, true);
+
+	if (!gated) {
+		/* Force CLOCK ON for VCE_CLOCK_GATING_B,
+		 * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
+		 * VREG can be FORCE ON or set to Dynamic, but can't be OFF
+		 */
+		tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
+		data |= 0x1ff;
+		data &= ~0xef0000;
+		if (tmp != data)
+			WREG32(mmVCE_CLOCK_GATING_B, data);
+
+		/* Force CLOCK ON for VCE_UENC_CLOCK_GATING,
+		 * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
+		 */
+		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
+		data |= 0x3ff000;
+		data &= ~0xffc00000;
+		if (tmp != data)
+			WREG32(mmVCE_UENC_CLOCK_GATING, data);
+
+		/* set VCE_UENC_CLOCK_GATING_2 */
+		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
+		data |= 0x2;
+		data &= ~0x2;
+		if (tmp != data)
+			WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
+
+		/* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */
+		tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
+		data |= 0x37f;
+		if (tmp != data)
+			WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
+
+		/* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */
+		tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
+		data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
+				VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
+				VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
+				0x8;
+		if (tmp != data)
+			WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
+	} else {
+		/* Force CLOCK OFF for VCE_CLOCK_GATING_B,
+		 * {*, *_FORCE_OFF} = {*, 1}
+		 * set VREG to Dynamic, as it can't be OFF
+		 */
+		tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
+		data &= ~0x80010;
+		data |= 0xe70008;
+		if (tmp != data)
+			WREG32(mmVCE_CLOCK_GATING_B, data);
+		/* Force CLOCK OFF for VCE_UENC_CLOCK_GATING,
+		 * Force ClOCK OFF takes precedent over Force CLOCK ON setting.
+		 * {*_FORCE_ON, *_FORCE_OFF} = {*, 1}
+		 */
+		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
+		data |= 0xffc00000;
+		if (tmp != data)
+			WREG32(mmVCE_UENC_CLOCK_GATING, data);
+		/* Set VCE_UENC_CLOCK_GATING_2 */
+		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
+		data |= 0x10000;
+		if (tmp != data)
+			WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
+		/* Set VCE_UENC_REG_CLOCK_GATING to dynamic */
+		tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
+		data &= ~0xffc00000;
+		if (tmp != data)
+			WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
+		/* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */
+		tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
+		data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
+				VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
+				VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
+				0x8);
+		if (tmp != data)
+			WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
+	}
+	vce_v3_0_override_vce_clock_gating(adev, false);
+}
+
 /**
  * vce_v3_0_start - start VCE block
  *
@@ -121,7 +223,7 @@
 		if (adev->vce.harvest_config & (1 << idx))
 			continue;
 
-		if(idx == 0)
+		if (idx == 0)
 			WREG32_P(mmGRBM_GFX_INDEX, 0,
 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
 		else
@@ -174,6 +276,10 @@
 		/* clear BUSY flag */
 		WREG32_P(mmVCE_STATUS, 0, ~1);
 
+		/* Set Clock-Gating off */
+		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
+			vce_v3_0_set_vce_sw_clock_gating(adev, false);
+
 		if (r) {
 			DRM_ERROR("VCE not responding, giving up!!!\n");
 			mutex_unlock(&adev->grbm_idx_mutex);
@@ -609,6 +715,47 @@
 static int vce_v3_0_set_clockgating_state(void *handle,
 					  enum amd_clockgating_state state)
 {
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
+	int i;
+
+	if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
+		return 0;
+
+	mutex_lock(&adev->grbm_idx_mutex);
+	for (i = 0; i < 2; i++) {
+		/* Program VCE Instance 0 or 1 if not harvested */
+		if (adev->vce.harvest_config & (1 << i))
+			continue;
+
+		if (i == 0)
+			WREG32_P(mmGRBM_GFX_INDEX, 0,
+					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+		else
+			WREG32_P(mmGRBM_GFX_INDEX,
+					GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
+					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+
+		if (enable) {
+			/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
+			uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
+			data &= ~(0xf | 0xff0);
+			data |= ((0x0 << 0) | (0x04 << 4));
+			WREG32(mmVCE_CLOCK_GATING_A, data);
+
+			/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
+			data = RREG32(mmVCE_UENC_CLOCK_GATING);
+			data &= ~(0xf | 0xff0);
+			data |= ((0x0 << 0) | (0x04 << 4));
+			WREG32(mmVCE_UENC_CLOCK_GATING, data);
+		}
+
+		vce_v3_0_set_vce_sw_clock_gating(adev, enable);
+	}
+
+	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+	mutex_unlock(&adev->grbm_idx_mutex);
+
 	return 0;
 }
 
@@ -624,6 +771,9 @@
 	 */
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
+		return 0;
+
 	if (state == AMD_PG_STATE_GATE)
 		/* XXX do we need a vce_v3_0_stop()? */
 		return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdgpu/vi.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdgpu/vi.c
@@ -31,6 +31,7 @@
 #include "amdgpu_vce.h"
 #include "amdgpu_ucode.h"
 #include "atom.h"
+#include "amd_pcie.h"
 
 #include "gmc/gmc_8_1_d.h"
 #include "gmc/gmc_8_1_sh_mask.h"
@@ -60,6 +61,7 @@
 #include "vi.h"
 #include "vi_dpm.h"
 #include "gmc_v8_0.h"
+#include "gmc_v7_0.h"
 #include "gfx_v8_0.h"
 #include "sdma_v2_4.h"
 #include "sdma_v3_0.h"
@@ -71,6 +73,7 @@
 #include "uvd_v5_0.h"
 #include "uvd_v6_0.h"
 #include "vce_v3_0.h"
+#include "amdgpu_powerplay.h"
 
 /*
  * Indirect registers accessor
@@ -376,6 +379,38 @@
 	WREG32_SMC(ixROM_CNTL, rom_cntl);
 	return r;
 }
+
+static bool vi_read_bios_from_rom(struct amdgpu_device *adev,
+				  u8 *bios, u32 length_bytes)
+{
+	u32 *dw_ptr;
+	unsigned long flags;
+	u32 i, length_dw;
+
+	if (bios == NULL)
+		return false;
+	if (length_bytes == 0)
+		return false;
+	/* APU vbios image is part of sbios image */
+	if (adev->flags & AMD_IS_APU)
+		return false;
+
+	dw_ptr = (u32 *)bios;
+	length_dw = ALIGN(length_bytes, 4) / 4;
+	/* take the smc lock since we are using the smc index */
+	spin_lock_irqsave(&adev->smc_idx_lock, flags);
+	/* set rom index to 0 */
+	WREG32(mmSMC_IND_INDEX_0, ixROM_INDEX);
+	WREG32(mmSMC_IND_DATA_0, 0);
+	/* set index to data for continous read */
+	WREG32(mmSMC_IND_INDEX_0, ixROM_DATA);
+	for (i = 0; i < length_dw; i++)
+		dw_ptr[i] = RREG32(mmSMC_IND_DATA_0);
+	spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+	return true;
+}
+
 static struct amdgpu_allowed_register_entry tonga_allowed_read_registers[] = {
 	{mmGB_MACROTILE_MODE7, true},
 };
@@ -1019,9 +1054,6 @@
 
 static void vi_pcie_gen3_enable(struct amdgpu_device *adev)
 {
-	u32 mask;
-	int ret;
-
 	if (pci_is_root_bus(adev->pdev->bus))
 		return;
 
@@ -1031,11 +1063,8 @@
 	if (adev->flags & AMD_IS_APU)
 		return;
 
-	ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
-	if (ret != 0)
-		return;
-
-	if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
+	if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
+					CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)))
 		return;
 
 	/* todo */
@@ -1081,10 +1110,10 @@
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_GMC,
-		.major = 8,
-		.minor = 0,
+		.major = 7,
+		.minor = 4,
 		.rev = 0,
-		.funcs = &gmc_v8_0_ip_funcs,
+		.funcs = &gmc_v7_0_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_IH,
@@ -1098,7 +1127,7 @@
 		.major = 7,
 		.minor = 1,
 		.rev = 0,
-		.funcs = &iceland_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_GFX,
@@ -1145,7 +1174,7 @@
 		.major = 7,
 		.minor = 1,
 		.rev = 0,
-		.funcs = &tonga_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -1213,7 +1242,7 @@
 		.major = 7,
 		.minor = 1,
 		.rev = 0,
-		.funcs = &fiji_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs,
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -1281,7 +1310,7 @@
 		.major = 8,
 		.minor = 0,
 		.rev = 0,
-		.funcs = &cz_dpm_ip_funcs,
+		.funcs = &amdgpu_pp_ip_funcs
 	},
 	{
 		.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -1354,20 +1383,18 @@
 
 static uint32_t vi_get_rev_id(struct amdgpu_device *adev)
 {
-	if (adev->asic_type == CHIP_TOPAZ)
-		return (RREG32(mmPCIE_EFUSE4) & PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID_MASK)
-			>> PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID__SHIFT;
-	else if (adev->flags & AMD_IS_APU)
+	if (adev->flags & AMD_IS_APU)
 		return (RREG32_SMC(ATI_REV_ID_FUSE_MACRO__ADDRESS) & ATI_REV_ID_FUSE_MACRO__MASK)
 			>> ATI_REV_ID_FUSE_MACRO__SHIFT;
 	else
-		return (RREG32(mmCC_DRM_ID_STRAPS) & CC_DRM_ID_STRAPS__ATI_REV_ID_MASK)
-			>> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT;
+		return (RREG32(mmPCIE_EFUSE4) & PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID_MASK)
+			>> PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID__SHIFT;
 }
 
 static const struct amdgpu_asic_funcs vi_asic_funcs =
 {
 	.read_disabled_bios = &vi_read_disabled_bios,
+	.read_bios_from_rom = &vi_read_bios_from_rom,
 	.read_register = &vi_read_register,
 	.reset = &vi_asic_reset,
 	.set_vga_state = &vi_vga_set_state,
@@ -1430,8 +1457,7 @@
 	case CHIP_STONEY:
 		adev->has_uvd = true;
 		adev->cg_flags = 0;
-		/* Disable UVD pg */
-		adev->pg_flags = /* AMDGPU_PG_SUPPORT_UVD | */AMDGPU_PG_SUPPORT_VCE;
+		adev->pg_flags = 0;
 		adev->external_rev_id = adev->rev_id + 0x1;
 		break;
 	default:
@@ -1442,6 +1468,8 @@
 	if (amdgpu_smc_load_fw && smc_enabled)
 		adev->firmware.smu_load = true;
 
+	amdgpu_get_pcie_info(adev);
+
 	return 0;
 }
 
@@ -1515,9 +1543,95 @@
 	return 0;
 }
 
+static void fiji_update_bif_medium_grain_light_sleep(struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t temp, data;
+
+	temp = data = RREG32_PCIE(ixPCIE_CNTL2);
+
+	if (enable)
+		data |= PCIE_CNTL2__SLV_MEM_LS_EN_MASK |
+				PCIE_CNTL2__MST_MEM_LS_EN_MASK |
+				PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK;
+	else
+		data &= ~(PCIE_CNTL2__SLV_MEM_LS_EN_MASK |
+				PCIE_CNTL2__MST_MEM_LS_EN_MASK |
+				PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK);
+
+	if (temp != data)
+		WREG32_PCIE(ixPCIE_CNTL2, data);
+}
+
+static void fiji_update_hdp_medium_grain_clock_gating(struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t temp, data;
+
+	temp = data = RREG32(mmHDP_HOST_PATH_CNTL);
+
+	if (enable)
+		data &= ~HDP_HOST_PATH_CNTL__CLOCK_GATING_DIS_MASK;
+	else
+		data |= HDP_HOST_PATH_CNTL__CLOCK_GATING_DIS_MASK;
+
+	if (temp != data)
+		WREG32(mmHDP_HOST_PATH_CNTL, data);
+}
+
+static void fiji_update_hdp_light_sleep(struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t temp, data;
+
+	temp = data = RREG32(mmHDP_MEM_POWER_LS);
+
+	if (enable)
+		data |= HDP_MEM_POWER_LS__LS_ENABLE_MASK;
+	else
+		data &= ~HDP_MEM_POWER_LS__LS_ENABLE_MASK;
+
+	if (temp != data)
+		WREG32(mmHDP_MEM_POWER_LS, data);
+}
+
+static void fiji_update_rom_medium_grain_clock_gating(struct amdgpu_device *adev,
+		bool enable)
+{
+	uint32_t temp, data;
+
+	temp = data = RREG32_SMC(ixCGTT_ROM_CLK_CTRL0);
+
+	if (enable)
+		data &= ~(CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK |
+				CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE1_MASK);
+	else
+		data |= CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK |
+				CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE1_MASK;
+
+	if (temp != data)
+		WREG32_SMC(ixCGTT_ROM_CLK_CTRL0, data);
+}
+
 static int vi_common_set_clockgating_state(void *handle,
 					    enum amd_clockgating_state state)
 {
+	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+	switch (adev->asic_type) {
+	case CHIP_FIJI:
+		fiji_update_bif_medium_grain_light_sleep(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		fiji_update_hdp_medium_grain_clock_gating(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		fiji_update_hdp_light_sleep(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		fiji_update_rom_medium_grain_clock_gating(adev,
+				state == AMD_CG_STATE_GATE ? true : false);
+		break;
+	default:
+		break;
+	}
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -558,20 +558,10 @@
 		return -EINVAL;
 
 	/* this is the actual buffer to work with */
-
-	args_buff = kmalloc(args->buf_size_in_bytes -
-					sizeof(*args), GFP_KERNEL);
-	if (args_buff == NULL)
-		return -ENOMEM;
-
-	status = copy_from_user(args_buff, cmd_from_user,
+	args_buff = memdup_user(cmd_from_user,
 				args->buf_size_in_bytes - sizeof(*args));
-
-	if (status != 0) {
-		pr_debug("Failed to copy address watch user data\n");
-		kfree(args_buff);
-		return -EINVAL;
-	}
+	if (IS_ERR(args_buff))
+		return PTR_ERR(args_buff);
 
 	aw_info.process = p;
 
@@ -677,22 +667,12 @@
 	if (cmd_from_user == NULL)
 		return -EINVAL;
 
-	/* this is the actual buffer to work with */
-
-	args_buff = kmalloc(args->buf_size_in_bytes - sizeof(*args),
-			GFP_KERNEL);
-
-	if (args_buff == NULL)
-		return -ENOMEM;
+	/* copy the entire buffer from user */
 
-	/* Now copy the entire buffer from user */
-	status = copy_from_user(args_buff, cmd_from_user,
+	args_buff = memdup_user(cmd_from_user,
 				args->buf_size_in_bytes - sizeof(*args));
-	if (status != 0) {
-		pr_debug("Failed to copy wave control user data\n");
-		kfree(args_buff);
-		return -EINVAL;
-	}
+	if (IS_ERR(args_buff))
+		return PTR_ERR(args_buff);
 
 	/* move ptr to the start of the "pay-load" area */
 	wac_info.process = p;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c
@@ -513,7 +513,7 @@
 				union SQ_CMD_BITS *in_reg_sq_cmd,
 				union GRBM_GFX_INDEX_BITS *in_reg_gfx_index)
 {
-	int status;
+	int status = 0;
 	union SQ_CMD_BITS reg_sq_cmd;
 	union GRBM_GFX_INDEX_BITS reg_gfx_index;
 	struct HsaDbgWaveMsgAMDGen2 *pMsg;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -739,8 +739,10 @@
 		struct kfd_event_data event_data;
 
 		if (copy_from_user(&event_data, &events[i],
-				sizeof(struct kfd_event_data)))
+				sizeof(struct kfd_event_data))) {
+			ret = -EFAULT;
 			goto fail;
+		}
 
 		ret = init_event_waiter(p, &event_waiters[i],
 				event_data.event_id, i);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
@@ -215,8 +215,8 @@
 	BUG_ON(!mm || !mqd || !q);
 
 	m = get_sdma_mqd(mqd);
-	m->sdma_rlc_rb_cntl = ffs(q->queue_size / sizeof(unsigned int)) <<
-			SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT |
+	m->sdma_rlc_rb_cntl = (ffs(q->queue_size / sizeof(unsigned int)) - 1)
+			<< SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT |
 			q->vmid << SDMA0_RLC0_RB_CNTL__RB_VMID__SHIFT |
 			1 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_ENABLE__SHIFT |
 			6 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT;
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -125,6 +125,8 @@
 		return ERR_PTR(-EINVAL);
 
 	process = find_process(thread);
+	if (!process)
+		return ERR_PTR(-EINVAL);
 
 	return process;
 }
@@ -194,7 +196,7 @@
 
 	kfree(p);
 
-	kfree((void *)work);
+	kfree(work);
 }
 
 static void kfd_process_destroy_delayed(struct rcu_head *rcu)
@@ -242,13 +244,19 @@
 	pqm_uninit(&p->pqm);
 
 	/* Iterate over all process device data structure and check
-	 * if we should reset all wavefronts */
-	list_for_each_entry(pdd, &p->per_device_data, per_device_list)
+	 * if we should delete debug managers and reset all wavefronts
+	 */
+	list_for_each_entry(pdd, &p->per_device_data, per_device_list) {
+		if ((pdd->dev->dbgmgr) &&
+				(pdd->dev->dbgmgr->pasid == p->pasid))
+			kfd_dbgmgr_destroy(pdd->dev->dbgmgr);
+
 		if (pdd->reset_wavefronts) {
 			pr_warn("amdkfd: Resetting all wave fronts\n");
 			dbgdev_wave_reset_wavefronts(pdd->dev, p);
 			pdd->reset_wavefronts = false;
 		}
+	}
 
 	mutex_unlock(&p->mutex);
 
@@ -404,42 +412,52 @@
 
 	idx = srcu_read_lock(&kfd_processes_srcu);
 
+	/*
+	 * Look for the process that matches the pasid. If there is no such
+	 * process, we either released it in amdkfd's own notifier, or there
+	 * is a bug. Unfortunately, there is no way to tell...
+	 */
 	hash_for_each_rcu(kfd_processes_table, i, p, kfd_processes)
-		if (p->pasid == pasid)
-			break;
+		if (p->pasid == pasid) {
 
-	srcu_read_unlock(&kfd_processes_srcu, idx);
+			srcu_read_unlock(&kfd_processes_srcu, idx);
 
-	BUG_ON(p->pasid != pasid);
+			pr_debug("Unbinding process %d from IOMMU\n", pasid);
 
-	mutex_lock(&p->mutex);
+			mutex_lock(&p->mutex);
 
-	if ((dev->dbgmgr) && (dev->dbgmgr->pasid == p->pasid))
-		kfd_dbgmgr_destroy(dev->dbgmgr);
+			if ((dev->dbgmgr) && (dev->dbgmgr->pasid == p->pasid))
+				kfd_dbgmgr_destroy(dev->dbgmgr);
 
-	pqm_uninit(&p->pqm);
+			pqm_uninit(&p->pqm);
 
-	pdd = kfd_get_process_device_data(dev, p);
+			pdd = kfd_get_process_device_data(dev, p);
 
-	if (!pdd) {
-		mutex_unlock(&p->mutex);
-		return;
-	}
+			if (!pdd) {
+				mutex_unlock(&p->mutex);
+				return;
+			}
 
-	if (pdd->reset_wavefronts) {
-		dbgdev_wave_reset_wavefronts(pdd->dev, p);
-		pdd->reset_wavefronts = false;
-	}
+			if (pdd->reset_wavefronts) {
+				dbgdev_wave_reset_wavefronts(pdd->dev, p);
+				pdd->reset_wavefronts = false;
+			}
 
-	/*
-	 * Just mark pdd as unbound, because we still need it to call
-	 * amd_iommu_unbind_pasid() in when the process exits.
-	 * We don't call amd_iommu_unbind_pasid() here
-	 * because the IOMMU called us.
-	 */
-	pdd->bound = false;
+			/*
+			 * Just mark pdd as unbound, because we still need it
+			 * to call amd_iommu_unbind_pasid() in when the
+			 * process exits.
+			 * We don't call amd_iommu_unbind_pasid() here
+			 * because the IOMMU called us.
+			 */
+			pdd->bound = false;
 
-	mutex_unlock(&p->mutex);
+			mutex_unlock(&p->mutex);
+
+			return;
+		}
+
+	srcu_read_unlock(&kfd_processes_srcu, idx);
 }
 
 struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p)
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -205,6 +205,24 @@
 
 	switch (type) {
 	case KFD_QUEUE_TYPE_SDMA:
+		if (dev->dqm->queue_count >=
+			CIK_SDMA_QUEUES_PER_ENGINE * CIK_SDMA_ENGINE_NUM) {
+			pr_err("Over-subscription is not allowed for SDMA.\n");
+			retval = -EPERM;
+			goto err_create_queue;
+		}
+
+		retval = create_cp_queue(pqm, dev, &q, properties, f, *qid);
+		if (retval != 0)
+			goto err_create_queue;
+		pqn->q = q;
+		pqn->kq = NULL;
+		retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd,
+						&q->properties.vmid);
+		pr_debug("DQM returned %d for create_queue\n", retval);
+		print_queue(q);
+		break;
+
 	case KFD_QUEUE_TYPE_COMPUTE:
 		/* check if there is over subscription */
 		if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
--- linux-4.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ linux-4.4.0/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -519,11 +519,17 @@
 	return ret;
 }
 
+static void kfd_topology_kobj_release(struct kobject *kobj)
+{
+	kfree(kobj);
+}
+
 static const struct sysfs_ops sysprops_ops = {
 	.show = sysprops_show,
 };
 
 static struct kobj_type sysprops_type = {
+	.release = kfd_topology_kobj_release,
 	.sysfs_ops = &sysprops_ops,
 };
 
@@ -559,6 +565,7 @@
 };
 
 static struct kobj_type iolink_type = {
+	.release = kfd_topology_kobj_release,
 	.sysfs_ops = &iolink_ops,
 };
 
@@ -586,6 +593,7 @@
 };
 
 static struct kobj_type mem_type = {
+	.release = kfd_topology_kobj_release,
 	.sysfs_ops = &mem_ops,
 };
 
@@ -625,6 +633,7 @@
 };
 
 static struct kobj_type cache_type = {
+	.release = kfd_topology_kobj_release,
 	.sysfs_ops = &cache_ops,
 };
 
@@ -747,6 +756,7 @@
 };
 
 static struct kobj_type node_type = {
+	.release = kfd_topology_kobj_release,
 	.sysfs_ops = &node_ops,
 };
 
@@ -831,8 +841,10 @@
 
 	ret = kobject_init_and_add(dev->kobj_node, &node_type,
 			sys_props.kobj_nodes, "%d", id);
-	if (ret < 0)
+	if (ret < 0) {
+		kobject_put(dev->kobj_node);
 		return ret;
+	}
 
 	dev->kobj_mem = kobject_create_and_add("mem_banks", dev->kobj_node);
 	if (!dev->kobj_mem)
@@ -875,8 +887,10 @@
 			return -ENOMEM;
 		ret = kobject_init_and_add(mem->kobj, &mem_type,
 				dev->kobj_mem, "%d", i);
-		if (ret < 0)
+		if (ret < 0) {
+			kobject_put(mem->kobj);
 			return ret;
+		}
 
 		mem->attr.name = "properties";
 		mem->attr.mode = KFD_SYSFS_FILE_MODE;
@@ -894,8 +908,10 @@
 			return -ENOMEM;
 		ret = kobject_init_and_add(cache->kobj, &cache_type,
 				dev->kobj_cache, "%d", i);
-		if (ret < 0)
+		if (ret < 0) {
+			kobject_put(cache->kobj);
 			return ret;
+		}
 
 		cache->attr.name = "properties";
 		cache->attr.mode = KFD_SYSFS_FILE_MODE;
@@ -913,8 +929,10 @@
 			return -ENOMEM;
 		ret = kobject_init_and_add(iolink->kobj, &iolink_type,
 				dev->kobj_iolink, "%d", i);
-		if (ret < 0)
+		if (ret < 0) {
+			kobject_put(iolink->kobj);
 			return ret;
+		}
 
 		iolink->attr.name = "properties";
 		iolink->attr.mode = KFD_SYSFS_FILE_MODE;
@@ -966,8 +984,10 @@
 		ret = kobject_init_and_add(sys_props.kobj_topology,
 				&sysprops_type,  &kfd_device->kobj,
 				"topology");
-		if (ret < 0)
+		if (ret < 0) {
+			kobject_put(sys_props.kobj_topology);
 			return ret;
+		}
 
 		sys_props.kobj_nodes = kobject_create_and_add("nodes",
 				sys_props.kobj_topology);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/amd_acpi.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/amd_acpi.h
@@ -0,0 +1,494 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef AMD_ACPI_H
+#define AMD_ACPI_H
+
+#define ACPI_AC_CLASS           "ac_adapter"
+
+struct atif_verify_interface {
+	u16 size;		/* structure size in bytes (includes size field) */
+	u16 version;		/* version */
+	u32 notification_mask;	/* supported notifications mask */
+	u32 function_bits;	/* supported functions bit vector */
+} __packed;
+
+struct atif_system_params {
+	u16 size;		/* structure size in bytes (includes size field) */
+	u32 valid_mask;		/* valid flags mask */
+	u32 flags;		/* flags */
+	u8 command_code;	/* notify command code */
+} __packed;
+
+struct atif_sbios_requests {
+	u16 size;		/* structure size in bytes (includes size field) */
+	u32 pending;		/* pending sbios requests */
+	u8 panel_exp_mode;	/* panel expansion mode */
+	u8 thermal_gfx;		/* thermal state: target gfx controller */
+	u8 thermal_state;	/* thermal state: state id (0: exit state, non-0: state) */
+	u8 forced_power_gfx;	/* forced power state: target gfx controller */
+	u8 forced_power_state;	/* forced power state: state id */
+	u8 system_power_src;	/* system power source */
+	u8 backlight_level;	/* panel backlight level (0-255) */
+} __packed;
+
+#define ATIF_NOTIFY_MASK	0x3
+#define ATIF_NOTIFY_NONE	0
+#define ATIF_NOTIFY_81		1
+#define ATIF_NOTIFY_N		2
+
+struct atcs_verify_interface {
+	u16 size;		/* structure size in bytes (includes size field) */
+	u16 version;		/* version */
+	u32 function_bits;	/* supported functions bit vector */
+} __packed;
+
+#define ATCS_VALID_FLAGS_MASK	0x3
+
+struct atcs_pref_req_input {
+	u16 size;		/* structure size in bytes (includes size field) */
+	u16 client_id;		/* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
+	u16 valid_flags_mask;	/* valid flags mask */
+	u16 flags;		/* flags */
+	u8 req_type;		/* request type */
+	u8 perf_req;		/* performance request */
+} __packed;
+
+struct atcs_pref_req_output {
+	u16 size;		/* structure size in bytes (includes size field) */
+	u8 ret_val;		/* return value */
+} __packed;
+
+/* AMD hw uses four ACPI control methods:
+ * 1. ATIF
+ * ARG0: (ACPI_INTEGER) function code
+ * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes
+ * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes
+ * ATIF provides an entry point for the gfx driver to interact with the sbios.
+ * The AMD ACPI notification mechanism uses Notify (VGA, 0x81) or a custom
+ * notification. Which notification is used as indicated by the ATIF Control
+ * Method GET_SYSTEM_PARAMETERS. When the driver receives Notify (VGA, 0x81) or
+ * a custom notification it invokes ATIF Control Method GET_SYSTEM_BIOS_REQUESTS
+ * to identify pending System BIOS requests and associated parameters. For
+ * example, if one of the pending requests is DISPLAY_SWITCH_REQUEST, the driver
+ * will perform display device detection and invoke ATIF Control Method
+ * SELECT_ACTIVE_DISPLAYS.
+ *
+ * 2. ATPX
+ * ARG0: (ACPI_INTEGER) function code
+ * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes
+ * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes
+ * ATPX methods are used on PowerXpress systems to handle mux switching and
+ * discrete GPU power control.
+ *
+ * 3. ATRM
+ * ARG0: (ACPI_INTEGER) offset of vbios rom data
+ * ARG1: (ACPI_BUFFER) size of the buffer to fill (up to 4K).
+ * OUTPUT: (ACPI_BUFFER) output buffer
+ * ATRM provides an interfacess to access the discrete GPU vbios image on
+ * PowerXpress systems with multiple GPUs.
+ *
+ * 4. ATCS
+ * ARG0: (ACPI_INTEGER) function code
+ * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes
+ * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes
+ * ATCS provides an interface to AMD chipset specific functionality.
+ *
+ */
+/* ATIF */
+#define ATIF_FUNCTION_VERIFY_INTERFACE                             0x0
+/* ARG0: ATIF_FUNCTION_VERIFY_INTERFACE
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - version
+ * DWORD - supported notifications mask
+ * DWORD - supported functions bit vector
+ */
+/* Notifications mask */
+#       define ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED               (1 << 0)
+#       define ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED        (1 << 1)
+#       define ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED         (1 << 2)
+#       define ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED    (1 << 3)
+#       define ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED   (1 << 4)
+#       define ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED          (1 << 5)
+#       define ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED                (1 << 6)
+#       define ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED      (1 << 7)
+#       define ATIF_DGPU_DISPLAY_EVENT_SUPPORTED                   (1 << 8)
+/* supported functions vector */
+#       define ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED               (1 << 0)
+#       define ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED            (1 << 1)
+#       define ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED              (1 << 2)
+#       define ATIF_GET_LID_STATE_SUPPORTED                       (1 << 3)
+#       define ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED           (1 << 4)
+#       define ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED             (1 << 5)
+#       define ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED  (1 << 6)
+#       define ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED    (1 << 7)
+#       define ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED     (1 << 12)
+#       define ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED           (1 << 14)
+#define ATIF_FUNCTION_GET_SYSTEM_PARAMETERS                        0x1
+/* ARG0: ATIF_FUNCTION_GET_SYSTEM_PARAMETERS
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * DWORD - valid flags mask
+ * DWORD - flags
+ *
+ * OR
+ *
+ * WORD  - structure size in bytes (includes size field)
+ * DWORD - valid flags mask
+ * DWORD - flags
+ * BYTE  - notify command code
+ *
+ * flags
+ * bits 1:0:
+ * 0 - Notify(VGA, 0x81) is not used for notification
+ * 1 - Notify(VGA, 0x81) is used for notification
+ * 2 - Notify(VGA, n) is used for notification where
+ * n (0xd0-0xd9) is specified in notify command code.
+ * bit 2:
+ * 1 - lid changes not reported though int10
+ */
+#define ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS                     0x2
+/* ARG0: ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * DWORD - pending sbios requests
+ * BYTE  - panel expansion mode
+ * BYTE  - thermal state: target gfx controller
+ * BYTE  - thermal state: state id (0: exit state, non-0: state)
+ * BYTE  - forced power state: target gfx controller
+ * BYTE  - forced power state: state id
+ * BYTE  - system power source
+ * BYTE  - panel backlight level (0-255)
+ */
+/* pending sbios requests */
+#       define ATIF_DISPLAY_SWITCH_REQUEST                         (1 << 0)
+#       define ATIF_EXPANSION_MODE_CHANGE_REQUEST                  (1 << 1)
+#       define ATIF_THERMAL_STATE_CHANGE_REQUEST                   (1 << 2)
+#       define ATIF_FORCED_POWER_STATE_CHANGE_REQUEST              (1 << 3)
+#       define ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST             (1 << 4)
+#       define ATIF_DISPLAY_CONF_CHANGE_REQUEST                    (1 << 5)
+#       define ATIF_PX_GFX_SWITCH_REQUEST                          (1 << 6)
+#       define ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST                (1 << 7)
+#       define ATIF_DGPU_DISPLAY_EVENT                             (1 << 8)
+/* panel expansion mode */
+#       define ATIF_PANEL_EXPANSION_DISABLE                        0
+#       define ATIF_PANEL_EXPANSION_FULL                           1
+#       define ATIF_PANEL_EXPANSION_ASPECT                         2
+/* target gfx controller */
+#       define ATIF_TARGET_GFX_SINGLE                              0
+#       define ATIF_TARGET_GFX_PX_IGPU                             1
+#       define ATIF_TARGET_GFX_PX_DGPU                             2
+/* system power source */
+#       define ATIF_POWER_SOURCE_AC                                1
+#       define ATIF_POWER_SOURCE_DC                                2
+#       define ATIF_POWER_SOURCE_RESTRICTED_AC_1                   3
+#       define ATIF_POWER_SOURCE_RESTRICTED_AC_2                   4
+#define ATIF_FUNCTION_SELECT_ACTIVE_DISPLAYS                       0x3
+/* ARG0: ATIF_FUNCTION_SELECT_ACTIVE_DISPLAYS
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - selected displays
+ * WORD  - connected displays
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - selected displays
+ */
+#       define ATIF_LCD1                                           (1 << 0)
+#       define ATIF_CRT1                                           (1 << 1)
+#       define ATIF_TV                                             (1 << 2)
+#       define ATIF_DFP1                                           (1 << 3)
+#       define ATIF_CRT2                                           (1 << 4)
+#       define ATIF_LCD2                                           (1 << 5)
+#       define ATIF_DFP2                                           (1 << 7)
+#       define ATIF_CV                                             (1 << 8)
+#       define ATIF_DFP3                                           (1 << 9)
+#       define ATIF_DFP4                                           (1 << 10)
+#       define ATIF_DFP5                                           (1 << 11)
+#       define ATIF_DFP6                                           (1 << 12)
+#define ATIF_FUNCTION_GET_LID_STATE                                0x4
+/* ARG0: ATIF_FUNCTION_GET_LID_STATE
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - lid state (0: open, 1: closed)
+ *
+ * GET_LID_STATE only works at boot and resume, for general lid
+ * status, use the kernel provided status
+ */
+#define ATIF_FUNCTION_GET_TV_STANDARD_FROM_CMOS                    0x5
+/* ARG0: ATIF_FUNCTION_GET_TV_STANDARD_FROM_CMOS
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - 0
+ * BYTE  - TV standard
+ */
+#       define ATIF_TV_STD_NTSC                                    0
+#       define ATIF_TV_STD_PAL                                     1
+#       define ATIF_TV_STD_PALM                                    2
+#       define ATIF_TV_STD_PAL60                                   3
+#       define ATIF_TV_STD_NTSCJ                                   4
+#       define ATIF_TV_STD_PALCN                                   5
+#       define ATIF_TV_STD_PALN                                    6
+#       define ATIF_TV_STD_SCART_RGB                               9
+#define ATIF_FUNCTION_SET_TV_STANDARD_IN_CMOS                      0x6
+/* ARG0: ATIF_FUNCTION_SET_TV_STANDARD_IN_CMOS
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - 0
+ * BYTE  - TV standard
+ * OUTPUT: none
+ */
+#define ATIF_FUNCTION_GET_PANEL_EXPANSION_MODE_FROM_CMOS           0x7
+/* ARG0: ATIF_FUNCTION_GET_PANEL_EXPANSION_MODE_FROM_CMOS
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - panel expansion mode
+ */
+#define ATIF_FUNCTION_SET_PANEL_EXPANSION_MODE_IN_CMOS             0x8
+/* ARG0: ATIF_FUNCTION_SET_PANEL_EXPANSION_MODE_IN_CMOS
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - panel expansion mode
+ * OUTPUT: none
+ */
+#define ATIF_FUNCTION_TEMPERATURE_CHANGE_NOTIFICATION              0xD
+/* ARG0: ATIF_FUNCTION_TEMPERATURE_CHANGE_NOTIFICATION
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - gfx controller id
+ * BYTE  - current temperature (degress Celsius)
+ * OUTPUT: none
+ */
+#define ATIF_FUNCTION_GET_GRAPHICS_DEVICE_TYPES                    0xF
+/* ARG0: ATIF_FUNCTION_GET_GRAPHICS_DEVICE_TYPES
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - number of gfx devices
+ * WORD  - device structure size in bytes (excludes device size field)
+ * DWORD - flags         \
+ * WORD  - bus number     } repeated structure
+ * WORD  - device number /
+ */
+/* flags */
+#       define ATIF_PX_REMOVABLE_GRAPHICS_DEVICE                   (1 << 0)
+#       define ATIF_XGP_PORT                                       (1 << 1)
+#       define ATIF_VGA_ENABLED_GRAPHICS_DEVICE                    (1 << 2)
+#       define ATIF_XGP_PORT_IN_DOCK                               (1 << 3)
+
+/* ATPX */
+#define ATPX_FUNCTION_VERIFY_INTERFACE                             0x0
+/* ARG0: ATPX_FUNCTION_VERIFY_INTERFACE
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - version
+ * DWORD - supported functions bit vector
+ */
+/* supported functions vector */
+#       define ATPX_GET_PX_PARAMETERS_SUPPORTED                    (1 << 0)
+#       define ATPX_POWER_CONTROL_SUPPORTED                        (1 << 1)
+#       define ATPX_DISPLAY_MUX_CONTROL_SUPPORTED                  (1 << 2)
+#       define ATPX_I2C_MUX_CONTROL_SUPPORTED                      (1 << 3)
+#       define ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED (1 << 4)
+#       define ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED   (1 << 5)
+#       define ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED       (1 << 7)
+#       define ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED          (1 << 8)
+#define ATPX_FUNCTION_GET_PX_PARAMETERS                            0x1
+/* ARG0: ATPX_FUNCTION_GET_PX_PARAMETERS
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * DWORD - valid flags mask
+ * DWORD - flags
+ */
+/* flags */
+#       define ATPX_LVDS_I2C_AVAILABLE_TO_BOTH_GPUS                (1 << 0)
+#       define ATPX_CRT1_I2C_AVAILABLE_TO_BOTH_GPUS                (1 << 1)
+#       define ATPX_DVI1_I2C_AVAILABLE_TO_BOTH_GPUS                (1 << 2)
+#       define ATPX_CRT1_RGB_SIGNAL_MUXED                          (1 << 3)
+#       define ATPX_TV_SIGNAL_MUXED                                (1 << 4)
+#       define ATPX_DFP_SIGNAL_MUXED                               (1 << 5)
+#       define ATPX_SEPARATE_MUX_FOR_I2C                           (1 << 6)
+#       define ATPX_DYNAMIC_PX_SUPPORTED                           (1 << 7)
+#       define ATPX_ACF_NOT_SUPPORTED                              (1 << 8)
+#       define ATPX_FIXED_NOT_SUPPORTED                            (1 << 9)
+#       define ATPX_DYNAMIC_DGPU_POWER_OFF_SUPPORTED               (1 << 10)
+#       define ATPX_DGPU_REQ_POWER_FOR_DISPLAYS                    (1 << 11)
+#define ATPX_FUNCTION_POWER_CONTROL                                0x2
+/* ARG0: ATPX_FUNCTION_POWER_CONTROL
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - dGPU power state (0: power off, 1: power on)
+ * OUTPUT: none
+ */
+#define ATPX_FUNCTION_DISPLAY_MUX_CONTROL                          0x3
+/* ARG0: ATPX_FUNCTION_DISPLAY_MUX_CONTROL
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - display mux control (0: iGPU, 1: dGPU)
+ * OUTPUT: none
+ */
+#       define ATPX_INTEGRATED_GPU                                 0
+#       define ATPX_DISCRETE_GPU                                   1
+#define ATPX_FUNCTION_I2C_MUX_CONTROL                              0x4
+/* ARG0: ATPX_FUNCTION_I2C_MUX_CONTROL
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - i2c/aux/hpd mux control (0: iGPU, 1: dGPU)
+ * OUTPUT: none
+ */
+#define ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION    0x5
+/* ARG0: ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - target gpu (0: iGPU, 1: dGPU)
+ * OUTPUT: none
+ */
+#define ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION      0x6
+/* ARG0: ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - target gpu (0: iGPU, 1: dGPU)
+ * OUTPUT: none
+ */
+#define ATPX_FUNCTION_GET_DISPLAY_CONNECTORS_MAPPING               0x8
+/* ARG0: ATPX_FUNCTION_GET_DISPLAY_CONNECTORS_MAPPING
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - number of display connectors
+ * WORD  - connector structure size in bytes (excludes connector size field)
+ * BYTE  - flags                                                     \
+ * BYTE  - ATIF display vector bit position                           } repeated
+ * BYTE  - adapter id (0: iGPU, 1-n: dGPU ordered by pcie bus number) } structure
+ * WORD  - connector ACPI id                                         /
+ */
+/* flags */
+#       define ATPX_DISPLAY_OUTPUT_SUPPORTED_BY_ADAPTER_ID_DEVICE  (1 << 0)
+#       define ATPX_DISPLAY_HPD_SUPPORTED_BY_ADAPTER_ID_DEVICE     (1 << 1)
+#       define ATPX_DISPLAY_I2C_SUPPORTED_BY_ADAPTER_ID_DEVICE     (1 << 2)
+#define ATPX_FUNCTION_GET_DISPLAY_DETECTION_PORTS                  0x9
+/* ARG0: ATPX_FUNCTION_GET_DISPLAY_DETECTION_PORTS
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - number of HPD/DDC ports
+ * WORD  - port structure size in bytes (excludes port size field)
+ * BYTE  - ATIF display vector bit position \
+ * BYTE  - hpd id                            } reapeated structure
+ * BYTE  - ddc id                           /
+ *
+ * available on A+A systems only
+ */
+/* hpd id */
+#       define ATPX_HPD_NONE                                       0
+#       define ATPX_HPD1                                           1
+#       define ATPX_HPD2                                           2
+#       define ATPX_HPD3                                           3
+#       define ATPX_HPD4                                           4
+#       define ATPX_HPD5                                           5
+#       define ATPX_HPD6                                           6
+/* ddc id */
+#       define ATPX_DDC_NONE                                       0
+#       define ATPX_DDC1                                           1
+#       define ATPX_DDC2                                           2
+#       define ATPX_DDC3                                           3
+#       define ATPX_DDC4                                           4
+#       define ATPX_DDC5                                           5
+#       define ATPX_DDC6                                           6
+#       define ATPX_DDC7                                           7
+#       define ATPX_DDC8                                           8
+
+/* ATCS */
+#define ATCS_FUNCTION_VERIFY_INTERFACE                             0x0
+/* ARG0: ATCS_FUNCTION_VERIFY_INTERFACE
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - version
+ * DWORD - supported functions bit vector
+ */
+/* supported functions vector */
+#       define ATCS_GET_EXTERNAL_STATE_SUPPORTED                   (1 << 0)
+#       define ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED             (1 << 1)
+#       define ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED       (1 << 2)
+#       define ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED                   (1 << 3)
+#define ATCS_FUNCTION_GET_EXTERNAL_STATE                           0x1
+/* ARG0: ATCS_FUNCTION_GET_EXTERNAL_STATE
+ * ARG1: none
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * DWORD - valid flags mask
+ * DWORD - flags (0: undocked, 1: docked)
+ */
+/* flags */
+#       define ATCS_DOCKED                                         (1 << 0)
+#define ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST                     0x2
+/* ARG0: ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num)
+ * WORD  - valid flags mask
+ * WORD  - flags
+ * BYTE  - request type
+ * BYTE  - performance request
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - return value
+ */
+/* flags */
+#       define ATCS_ADVERTISE_CAPS                                 (1 << 0)
+#       define ATCS_WAIT_FOR_COMPLETION                            (1 << 1)
+/* request type */
+#       define ATCS_PCIE_LINK_SPEED                                1
+/* performance request */
+#       define ATCS_REMOVE                                         0
+#       define ATCS_FORCE_LOW_POWER                                1
+#       define ATCS_PERF_LEVEL_1                                   2 /* PCIE Gen 1 */
+#       define ATCS_PERF_LEVEL_2                                   3 /* PCIE Gen 2 */
+#       define ATCS_PERF_LEVEL_3                                   4 /* PCIE Gen 3 */
+/* return value */
+#       define ATCS_REQUEST_REFUSED                                1
+#       define ATCS_REQUEST_COMPLETE                               2
+#       define ATCS_REQUEST_IN_PROGRESS                            3
+#define ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION               0x3
+/* ARG0: ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION
+ * ARG1: none
+ * OUTPUT: none
+ */
+#define ATCS_FUNCTION_SET_PCIE_BUS_WIDTH                           0x4
+/* ARG0: ATCS_FUNCTION_SET_PCIE_BUS_WIDTH
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num)
+ * BYTE  - number of active lanes
+ * OUTPUT:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - number of active lanes
+ */
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/amd_pcie.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/amd_pcie.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __AMD_PCIE_H__
+#define __AMD_PCIE_H__
+
+/* Following flags shows PCIe link speed supported in driver which are decided by chipset and ASIC */
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1        0x00010000
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2        0x00020000
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3        0x00040000
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_MASK        0xFFFF0000
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT       16
+
+/* Following flags shows PCIe link speed supported by ASIC H/W.*/
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1   0x00000001
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2   0x00000002
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3   0x00000004
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK   0x0000FFFF
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_SHIFT  0
+
+/* Following flags shows PCIe lane width switch supported in driver which are decided by chipset and ASIC */
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X1          0x00010000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X2          0x00020000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X4          0x00040000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X8          0x00080000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X12         0x00100000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X16         0x00200000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X32         0x00400000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_SHIFT       16
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/amd_pcie_helpers.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/amd_pcie_helpers.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __AMD_PCIE_HELPERS_H__
+#define __AMD_PCIE_HELPERS_H__
+
+#include "amd_pcie.h"
+
+static inline bool is_pcie_gen3_supported(uint32_t pcie_link_speed_cap)
+{
+	if (pcie_link_speed_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+		return true;
+
+	return false;
+}
+
+static inline bool is_pcie_gen2_supported(uint32_t pcie_link_speed_cap)
+{
+	if (pcie_link_speed_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
+		return true;
+
+	return false;
+}
+
+/* Get the new PCIE speed given the ASIC PCIE Cap and the NewState's requested PCIE speed*/
+static inline uint16_t get_pcie_gen_support(uint32_t pcie_link_speed_cap,
+					    uint16_t ns_pcie_gen)
+{
+	uint32_t asic_pcie_link_speed_cap = (pcie_link_speed_cap &
+		CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK);
+	uint32_t sys_pcie_link_speed_cap  = (pcie_link_speed_cap &
+		CAIL_PCIE_LINK_SPEED_SUPPORT_MASK);
+
+	switch (asic_pcie_link_speed_cap) {
+	case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1:
+		return PP_PCIEGen1;
+
+	case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2:
+		return PP_PCIEGen2;
+
+	case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3:
+		return PP_PCIEGen3;
+
+	default:
+		if (is_pcie_gen3_supported(sys_pcie_link_speed_cap) &&
+			(ns_pcie_gen == PP_PCIEGen3)) {
+			return PP_PCIEGen3;
+		} else if (is_pcie_gen2_supported(sys_pcie_link_speed_cap) &&
+			((ns_pcie_gen == PP_PCIEGen3) || (ns_pcie_gen == PP_PCIEGen2))) {
+			return PP_PCIEGen2;
+		}
+	}
+
+	return PP_PCIEGen1;
+}
+
+static inline uint16_t get_pcie_lane_support(uint32_t pcie_lane_width_cap,
+					     uint16_t ns_pcie_lanes)
+{
+	int i, j;
+	uint16_t new_pcie_lanes = ns_pcie_lanes;
+	uint16_t pcie_lanes[7] = {1, 2, 4, 8, 12, 16, 32};
+
+	switch (pcie_lane_width_cap) {
+	case 0:
+		printk(KERN_ERR "No valid PCIE lane width reported");
+		break;
+	case CAIL_PCIE_LINK_WIDTH_SUPPORT_X1:
+		new_pcie_lanes = 1;
+		break;
+	case CAIL_PCIE_LINK_WIDTH_SUPPORT_X2:
+		new_pcie_lanes = 2;
+		break;
+	case CAIL_PCIE_LINK_WIDTH_SUPPORT_X4:
+		new_pcie_lanes = 4;
+		break;
+	case CAIL_PCIE_LINK_WIDTH_SUPPORT_X8:
+		new_pcie_lanes = 8;
+		break;
+	case CAIL_PCIE_LINK_WIDTH_SUPPORT_X12:
+		new_pcie_lanes = 12;
+		break;
+	case CAIL_PCIE_LINK_WIDTH_SUPPORT_X16:
+		new_pcie_lanes = 16;
+		break;
+	case CAIL_PCIE_LINK_WIDTH_SUPPORT_X32:
+		new_pcie_lanes = 32;
+		break;
+	default:
+		for (i = 0; i < 7; i++) {
+			if (ns_pcie_lanes == pcie_lanes[i]) {
+				if (pcie_lane_width_cap & (0x10000 << i)) {
+					break;
+				} else {
+					for (j = i - 1; j >= 0; j--) {
+						if (pcie_lane_width_cap & (0x10000 << j)) {
+							new_pcie_lanes = pcie_lanes[j];
+							break;
+						}
+					}
+
+					if (j < 0) {
+						for (j = i + 1; j < 7; j++) {
+							if (pcie_lane_width_cap & (0x10000 << j)) {
+								new_pcie_lanes = pcie_lanes[j];
+								break;
+							}
+						}
+						if (j > 7)
+							printk(KERN_ERR "Cannot find a valid PCIE lane width!");
+					}
+				}
+				break;
+			}
+		}
+		break;
+	}
+
+	return new_pcie_lanes;
+}
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/amd_shared.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/amd_shared.h
@@ -85,6 +85,59 @@
 	AMD_PG_STATE_UNGATE,
 };
 
+/* CG flags */
+#define AMD_CG_SUPPORT_GFX_MGCG			(1 << 0)
+#define AMD_CG_SUPPORT_GFX_MGLS			(1 << 1)
+#define AMD_CG_SUPPORT_GFX_CGCG			(1 << 2)
+#define AMD_CG_SUPPORT_GFX_CGLS			(1 << 3)
+#define AMD_CG_SUPPORT_GFX_CGTS			(1 << 4)
+#define AMD_CG_SUPPORT_GFX_CGTS_LS		(1 << 5)
+#define AMD_CG_SUPPORT_GFX_CP_LS		(1 << 6)
+#define AMD_CG_SUPPORT_GFX_RLC_LS		(1 << 7)
+#define AMD_CG_SUPPORT_MC_LS			(1 << 8)
+#define AMD_CG_SUPPORT_MC_MGCG			(1 << 9)
+#define AMD_CG_SUPPORT_SDMA_LS			(1 << 10)
+#define AMD_CG_SUPPORT_SDMA_MGCG		(1 << 11)
+#define AMD_CG_SUPPORT_BIF_LS			(1 << 12)
+#define AMD_CG_SUPPORT_UVD_MGCG			(1 << 13)
+#define AMD_CG_SUPPORT_VCE_MGCG			(1 << 14)
+#define AMD_CG_SUPPORT_HDP_LS			(1 << 15)
+#define AMD_CG_SUPPORT_HDP_MGCG			(1 << 16)
+
+/* PG flags */
+#define AMD_PG_SUPPORT_GFX_PG			(1 << 0)
+#define AMD_PG_SUPPORT_GFX_SMG			(1 << 1)
+#define AMD_PG_SUPPORT_GFX_DMG			(1 << 2)
+#define AMD_PG_SUPPORT_UVD			(1 << 3)
+#define AMD_PG_SUPPORT_VCE			(1 << 4)
+#define AMD_PG_SUPPORT_CP			(1 << 5)
+#define AMD_PG_SUPPORT_GDS			(1 << 6)
+#define AMD_PG_SUPPORT_RLC_SMU_HS		(1 << 7)
+#define AMD_PG_SUPPORT_SDMA			(1 << 8)
+#define AMD_PG_SUPPORT_ACP			(1 << 9)
+#define AMD_PG_SUPPORT_SAMU			(1 << 10)
+
+enum amd_pm_state_type {
+	/* not used for dpm */
+	POWER_STATE_TYPE_DEFAULT,
+	POWER_STATE_TYPE_POWERSAVE,
+	/* user selectable states */
+	POWER_STATE_TYPE_BATTERY,
+	POWER_STATE_TYPE_BALANCED,
+	POWER_STATE_TYPE_PERFORMANCE,
+	/* internal states */
+	POWER_STATE_TYPE_INTERNAL_UVD,
+	POWER_STATE_TYPE_INTERNAL_UVD_SD,
+	POWER_STATE_TYPE_INTERNAL_UVD_HD,
+	POWER_STATE_TYPE_INTERNAL_UVD_HD2,
+	POWER_STATE_TYPE_INTERNAL_UVD_MVC,
+	POWER_STATE_TYPE_INTERNAL_BOOT,
+	POWER_STATE_TYPE_INTERNAL_THERMAL,
+	POWER_STATE_TYPE_INTERNAL_ACPI,
+	POWER_STATE_TYPE_INTERNAL_ULV,
+	POWER_STATE_TYPE_INTERNAL_3DPERF,
+};
+
 struct amd_ip_funcs {
 	/* sets up early driver state (pre sw_init), does not configure hw - Optional */
 	int (*early_init)(void *handle);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_d.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_d.h
@@ -596,6 +596,7 @@
 #define mmSWRST_EP_CONTROL_0                                                    0x14ac
 #define mmCPM_CONTROL                                                           0x14b8
 #define mmGSKT_CONTROL                                                          0x14bf
+#define ixSWRST_COMMAND_1                                                       0x1400103
 #define ixLM_CONTROL                                                            0x1400120
 #define ixLM_PCIETXMUX0                                                         0x1400121
 #define ixLM_PCIETXMUX1                                                         0x1400122
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_d.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_d.h
@@ -2807,5 +2807,18 @@
 #define ixDIDT_DBR_WEIGHT0_3                                                    0x90
 #define ixDIDT_DBR_WEIGHT4_7                                                    0x91
 #define ixDIDT_DBR_WEIGHT8_11                                                   0x92
+#define mmTD_EDC_CNT                                                            0x252e
+#define mmCPF_EDC_TAG_CNT                                                       0x3188
+#define mmCPF_EDC_ROQ_CNT                                                       0x3189
+#define mmCPF_EDC_ATC_CNT                                                       0x318a
+#define mmCPG_EDC_TAG_CNT                                                       0x318b
+#define mmCPG_EDC_ATC_CNT                                                       0x318c
+#define mmCPG_EDC_DMA_CNT                                                       0x318d
+#define mmCPC_EDC_SCRATCH_CNT                                                   0x318e
+#define mmCPC_EDC_UCODE_CNT                                                     0x318f
+#define mmCPC_EDC_ATC_CNT                                                       0x3190
+#define mmDC_EDC_STATE_CNT                                                      0x3191
+#define mmDC_EDC_CSINVOC_CNT                                                    0x3192
+#define mmDC_EDC_RESTORE_CNT                                                    0x3193
 
 #endif /* GFX_8_0_D_H */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/atombios.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/atombios.h
@@ -550,6 +550,13 @@
 //MPLL_CNTL_FLAG_BYPASS_AD_PLL has a wrong name, should be BYPASS_DQ_PLL
 #define MPLL_CNTL_FLAG_BYPASS_AD_PLL            0x04
 
+// use for ComputeMemoryClockParamTable
+typedef struct _COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2
+{
+  COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 ulClock;
+  ULONG ulReserved;
+}COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2;
+
 typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER
 {
   ATOM_COMPUTE_CLOCK_FREQ ulClock;
@@ -4988,6 +4995,78 @@
   ULONG  ulSDCMargine;
 }ATOM_ASIC_PROFILING_INFO_V3_3;
 
+// for Fiji speed EVV algorithm
+typedef struct  _ATOM_ASIC_PROFILING_INFO_V3_4
+{
+  ATOM_COMMON_TABLE_HEADER         asHeader;
+  ULONG  ulEvvLkgFactor;
+  ULONG  ulBoardCoreTemp;
+  ULONG  ulMaxVddc;
+  ULONG  ulMinVddc;
+  ULONG  ulLoadLineSlop;
+  ULONG  ulLeakageTemp;
+  ULONG  ulLeakageVoltage;
+  EFUSE_LINEAR_FUNC_PARAM sCACm;
+  EFUSE_LINEAR_FUNC_PARAM sCACb;
+  EFUSE_LOGISTIC_FUNC_PARAM sKt_b;
+  EFUSE_LOGISTIC_FUNC_PARAM sKv_m;
+  EFUSE_LOGISTIC_FUNC_PARAM sKv_b;
+  USHORT usLkgEuseIndex;
+  UCHAR  ucLkgEfuseBitLSB;
+  UCHAR  ucLkgEfuseLength;
+  ULONG  ulLkgEncodeLn_MaxDivMin;
+  ULONG  ulLkgEncodeMax;
+  ULONG  ulLkgEncodeMin;
+  ULONG  ulEfuseLogisticAlpha;
+  USHORT usPowerDpm0;
+  USHORT usPowerDpm1;
+  USHORT usPowerDpm2;
+  USHORT usPowerDpm3;
+  USHORT usPowerDpm4;
+  USHORT usPowerDpm5;
+  USHORT usPowerDpm6;
+  USHORT usPowerDpm7;
+  ULONG  ulTdpDerateDPM0;
+  ULONG  ulTdpDerateDPM1;
+  ULONG  ulTdpDerateDPM2;
+  ULONG  ulTdpDerateDPM3;
+  ULONG  ulTdpDerateDPM4;
+  ULONG  ulTdpDerateDPM5;
+  ULONG  ulTdpDerateDPM6;
+  ULONG  ulTdpDerateDPM7;
+  EFUSE_LINEAR_FUNC_PARAM sRoFuse;
+  ULONG  ulEvvDefaultVddc;
+  ULONG  ulEvvNoCalcVddc;
+  USHORT usParamNegFlag;
+  USHORT usSpeed_Model;
+  ULONG  ulSM_A0;
+  ULONG  ulSM_A1;
+  ULONG  ulSM_A2;
+  ULONG  ulSM_A3;
+  ULONG  ulSM_A4;
+  ULONG  ulSM_A5;
+  ULONG  ulSM_A6;
+  ULONG  ulSM_A7;
+  UCHAR  ucSM_A0_sign;
+  UCHAR  ucSM_A1_sign;
+  UCHAR  ucSM_A2_sign;
+  UCHAR  ucSM_A3_sign;
+  UCHAR  ucSM_A4_sign;
+  UCHAR  ucSM_A5_sign;
+  UCHAR  ucSM_A6_sign;
+  UCHAR  ucSM_A7_sign;
+  ULONG ulMargin_RO_a;
+  ULONG ulMargin_RO_b;
+  ULONG ulMargin_RO_c;
+  ULONG ulMargin_fixed;
+  ULONG ulMargin_Fmax_mean;
+  ULONG ulMargin_plat_mean;
+  ULONG ulMargin_Fmax_sigma;
+  ULONG ulMargin_plat_sigma;
+  ULONG ulMargin_DC_sigma;
+  ULONG ulReserved[8];            // Reserved for future ASIC
+}ATOM_ASIC_PROFILING_INFO_V3_4;
+
 typedef struct _ATOM_POWER_SOURCE_OBJECT
 {
    UCHAR  ucPwrSrcId;                                   // Power source
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/cgs_common.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/cgs_common.h
@@ -105,6 +105,36 @@
 	CGS_UCODE_ID_MAXIMUM,
 };
 
+enum cgs_system_info_id {
+	CGS_SYSTEM_INFO_ADAPTER_BDF_ID = 1,
+	CGS_SYSTEM_INFO_PCIE_GEN_INFO,
+	CGS_SYSTEM_INFO_PCIE_MLW,
+	CGS_SYSTEM_INFO_CG_FLAGS,
+	CGS_SYSTEM_INFO_PG_FLAGS,
+	CGS_SYSTEM_INFO_ID_MAXIMUM,
+};
+
+struct cgs_system_info {
+	uint64_t       size;
+	uint64_t       info_id;
+	union {
+		void           *ptr;
+		uint64_t        value;
+	};
+	uint64_t               padding[13];
+};
+
+/*
+ * enum cgs_resource_type - GPU resource type
+ */
+enum cgs_resource_type {
+	CGS_RESOURCE_TYPE_MMIO = 0,
+	CGS_RESOURCE_TYPE_FB,
+	CGS_RESOURCE_TYPE_IO,
+	CGS_RESOURCE_TYPE_DOORBELL,
+	CGS_RESOURCE_TYPE_ROM,
+};
+
 /**
  * struct cgs_clock_limits - Clock limits
  *
@@ -127,8 +157,53 @@
 	void			*kptr;
 };
 
+struct cgs_mode_info {
+	uint32_t		refresh_rate;
+	uint32_t		ref_clock;
+	uint32_t		vblank_time_us;
+};
+
+struct cgs_display_info {
+	uint32_t		display_count;
+	uint32_t		active_display_mask;
+	struct cgs_mode_info *mode_info;
+};
+
 typedef unsigned long cgs_handle_t;
 
+#define CGS_ACPI_METHOD_ATCS          0x53435441
+#define CGS_ACPI_METHOD_ATIF          0x46495441
+#define CGS_ACPI_METHOD_ATPX          0x58505441
+#define CGS_ACPI_FIELD_METHOD_NAME                      0x00000001
+#define CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT             0x00000002
+#define CGS_ACPI_MAX_BUFFER_SIZE     256
+#define CGS_ACPI_TYPE_ANY                      0x00
+#define CGS_ACPI_TYPE_INTEGER               0x01
+#define CGS_ACPI_TYPE_STRING                0x02
+#define CGS_ACPI_TYPE_BUFFER                0x03
+#define CGS_ACPI_TYPE_PACKAGE               0x04
+
+struct cgs_acpi_method_argument {
+	uint32_t type;
+	uint32_t method_length;
+	uint32_t data_length;
+	union{
+		uint32_t value;
+		void *pointer;
+	};
+};
+
+struct cgs_acpi_method_info {
+	uint32_t size;
+	uint32_t field;
+	uint32_t input_count;
+	uint32_t name;
+	struct cgs_acpi_method_argument *pinput_argument;
+	uint32_t output_count;
+	struct cgs_acpi_method_argument *poutput_argument;
+	uint32_t padding[9];
+};
+
 /**
  * cgs_gpu_mem_info() - Return information about memory heaps
  * @cgs_device: opaque device handle
@@ -355,6 +430,23 @@
 typedef void (*cgs_write_pci_config_dword_t)(void *cgs_device, unsigned addr,
 					     uint32_t value);
 
+
+/**
+ * cgs_get_pci_resource() - provide access to a device resource (PCI BAR)
+ * @cgs_device:	opaque device handle
+ * @resource_type:	Type of Resource (MMIO, IO, ROM, FB, DOORBELL)
+ * @size:	size of the region
+ * @offset:	offset from the start of the region
+ * @resource_base:	base address (not including offset) returned
+ *
+ * Return: 0 on success, -errno otherwise
+ */
+typedef int (*cgs_get_pci_resource_t)(void *cgs_device,
+				      enum cgs_resource_type resource_type,
+				      uint64_t size,
+				      uint64_t offset,
+				      uint64_t *resource_base);
+
 /**
  * cgs_atom_get_data_table() - Get a pointer to an ATOM BIOS data table
  * @cgs_device:	opaque device handle
@@ -493,6 +585,21 @@
 				  enum amd_ip_block_type block_type,
 				  enum amd_clockgating_state state);
 
+typedef int(*cgs_get_active_displays_info)(
+					void *cgs_device,
+					struct cgs_display_info *info);
+
+typedef int (*cgs_call_acpi_method)(void *cgs_device,
+					uint32_t acpi_method,
+					uint32_t acpi_function,
+					void *pinput, void *poutput,
+					uint32_t output_count,
+					uint32_t input_size,
+					uint32_t output_size);
+
+typedef int (*cgs_query_system_info)(void *cgs_device,
+				struct cgs_system_info *sys_info);
+
 struct cgs_ops {
 	/* memory management calls (similar to KFD interface) */
 	cgs_gpu_mem_info_t gpu_mem_info;
@@ -516,6 +623,8 @@
 	cgs_write_pci_config_byte_t write_pci_config_byte;
 	cgs_write_pci_config_word_t write_pci_config_word;
 	cgs_write_pci_config_dword_t write_pci_config_dword;
+	/* PCI resources */
+	cgs_get_pci_resource_t get_pci_resource;
 	/* ATOM BIOS */
 	cgs_atom_get_data_table_t atom_get_data_table;
 	cgs_atom_get_cmd_table_revs_t atom_get_cmd_table_revs;
@@ -533,7 +642,12 @@
 	/* cg pg interface*/
 	cgs_set_powergating_state set_powergating_state;
 	cgs_set_clockgating_state set_clockgating_state;
-	/* ACPI (TODO) */
+	/* display manager */
+	cgs_get_active_displays_info get_active_displays_info;
+	/* ACPI */
+	cgs_call_acpi_method call_acpi_method;
+	/* get system info */
+	cgs_query_system_info query_system_info;
 };
 
 struct cgs_os_ops; /* To be define in OS-specific CGS header */
@@ -620,5 +734,15 @@
 	CGS_CALL(set_powergating_state, dev, block_type, state)
 #define cgs_set_clockgating_state(dev, block_type, state)	\
 	CGS_CALL(set_clockgating_state, dev, block_type, state)
+#define cgs_get_active_displays_info(dev, info)	\
+	CGS_CALL(get_active_displays_info, dev, info)
+#define cgs_call_acpi_method(dev, acpi_method, acpi_function, pintput, poutput, output_count, input_size, output_size)	\
+	CGS_CALL(call_acpi_method, dev, acpi_method, acpi_function, pintput, poutput, output_count, input_size, output_size)
+#define cgs_query_system_info(dev, sys_info)	\
+	CGS_CALL(query_system_info, dev, sys_info)
+#define cgs_get_pci_resource(cgs_device, resource_type, size, offset, \
+	resource_base) \
+	CGS_CALL(get_pci_resource, cgs_device, resource_type, size, offset, \
+	resource_base)
 
 #endif /* _CGS_COMMON_H */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/include/pptable.h
+++ linux-4.4.0/drivers/gpu/drm/amd/include/pptable.h
@@ -74,7 +74,7 @@
 typedef struct _ATOM_PPLIB_STATE
 {
     UCHAR ucNonClockStateIndex;
-    UCHAR ucClockStateIndices[1]; // variable-sized
+    UCHAR ucClockStateIndices[]; // variable-sized
 } ATOM_PPLIB_STATE;
 
 
@@ -443,7 +443,7 @@
       /**
       * Driver will read the first ucNumDPMLevels in this array
       */
-      UCHAR clockInfoIndex[1];
+      UCHAR clockInfoIndex[];
 } ATOM_PPLIB_STATE_V2;
 
 typedef struct _StateArray{
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/Kconfig
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/Kconfig
@@ -0,0 +1,6 @@
+config DRM_AMD_POWERPLAY
+	bool  "Enable AMD powerplay component"
+	depends on DRM_AMDGPU
+	default n
+	help
+	  select this option will enable AMD powerplay component.
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/Makefile
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/Makefile
@@ -0,0 +1,22 @@
+
+subdir-ccflags-y += -Iinclude/drm  \
+		-Idrivers/gpu/drm/amd/powerplay/inc/  \
+		-Idrivers/gpu/drm/amd/include/asic_reg  \
+		-Idrivers/gpu/drm/amd/include  \
+		-Idrivers/gpu/drm/amd/powerplay/smumgr\
+		-Idrivers/gpu/drm/amd/powerplay/hwmgr \
+		-Idrivers/gpu/drm/amd/powerplay/eventmgr
+
+AMD_PP_PATH = ../powerplay
+
+PP_LIBS = smumgr hwmgr eventmgr
+
+AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix drivers/gpu/drm/amd/powerplay/,$(PP_LIBS)))
+
+include $(AMD_POWERPLAY)
+
+POWER_MGR = amd_powerplay.o
+
+AMD_PP_POWER = $(addprefix $(AMD_PP_PATH)/,$(POWER_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_PP_POWER)
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
@@ -0,0 +1,665 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include "amd_shared.h"
+#include "amd_powerplay.h"
+#include "pp_instance.h"
+#include "power_state.h"
+#include "eventmanager.h"
+
+#define PP_CHECK(handle)						\
+	do {								\
+		if ((handle) == NULL || (handle)->pp_valid != PP_VALID)	\
+			return -EINVAL;					\
+	} while (0)
+
+static int pp_early_init(void *handle)
+{
+	return 0;
+}
+
+static int pp_sw_init(void *handle)
+{
+	struct pp_instance *pp_handle;
+	struct pp_hwmgr  *hwmgr;
+	int ret = 0;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	pp_handle = (struct pp_instance *)handle;
+	hwmgr = pp_handle->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->pptable_func == NULL ||
+	    hwmgr->hwmgr_func == NULL ||
+	    hwmgr->pptable_func->pptable_init == NULL ||
+	    hwmgr->hwmgr_func->backend_init == NULL)
+		return -EINVAL;
+
+	ret = hwmgr->pptable_func->pptable_init(hwmgr);
+
+	if (ret == 0)
+		ret = hwmgr->hwmgr_func->backend_init(hwmgr);
+
+	if (ret)
+		printk("amdgpu: powerplay initialization failed\n");
+	else
+		printk("amdgpu: powerplay initialized\n");
+
+	return ret;
+}
+
+static int pp_sw_fini(void *handle)
+{
+	struct pp_instance *pp_handle;
+	struct pp_hwmgr  *hwmgr;
+	int ret = 0;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	pp_handle = (struct pp_instance *)handle;
+	hwmgr = pp_handle->hwmgr;
+
+	if (hwmgr != NULL || hwmgr->hwmgr_func != NULL ||
+	    hwmgr->hwmgr_func->backend_fini != NULL)
+		ret = hwmgr->hwmgr_func->backend_fini(hwmgr);
+
+	return ret;
+}
+
+static int pp_hw_init(void *handle)
+{
+	struct pp_instance *pp_handle;
+	struct pp_smumgr *smumgr;
+	struct pp_eventmgr *eventmgr;
+	int ret = 0;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	pp_handle = (struct pp_instance *)handle;
+	smumgr = pp_handle->smu_mgr;
+
+	if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
+		smumgr->smumgr_funcs->smu_init == NULL ||
+		smumgr->smumgr_funcs->start_smu == NULL)
+		return -EINVAL;
+
+	ret = smumgr->smumgr_funcs->smu_init(smumgr);
+	if (ret) {
+		printk(KERN_ERR "[ powerplay ] smc initialization failed\n");
+		return ret;
+	}
+
+	ret = smumgr->smumgr_funcs->start_smu(smumgr);
+	if (ret) {
+		printk(KERN_ERR "[ powerplay ] smc start failed\n");
+		smumgr->smumgr_funcs->smu_fini(smumgr);
+		return ret;
+	}
+
+	hw_init_power_state_table(pp_handle->hwmgr);
+	eventmgr = pp_handle->eventmgr;
+
+	if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
+		return -EINVAL;
+
+	ret = eventmgr->pp_eventmgr_init(eventmgr);
+	return 0;
+}
+
+static int pp_hw_fini(void *handle)
+{
+	struct pp_instance *pp_handle;
+	struct pp_smumgr *smumgr;
+	struct pp_eventmgr *eventmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	pp_handle = (struct pp_instance *)handle;
+	eventmgr = pp_handle->eventmgr;
+
+	if (eventmgr != NULL || eventmgr->pp_eventmgr_fini != NULL)
+		eventmgr->pp_eventmgr_fini(eventmgr);
+
+	smumgr = pp_handle->smu_mgr;
+
+	if (smumgr != NULL || smumgr->smumgr_funcs != NULL ||
+		smumgr->smumgr_funcs->smu_fini != NULL)
+		smumgr->smumgr_funcs->smu_fini(smumgr);
+
+	return 0;
+}
+
+static bool pp_is_idle(void *handle)
+{
+	return 0;
+}
+
+static int pp_wait_for_idle(void *handle)
+{
+	return 0;
+}
+
+static int pp_sw_reset(void *handle)
+{
+	return 0;
+}
+
+static void pp_print_status(void *handle)
+{
+
+}
+
+static int pp_set_clockgating_state(void *handle,
+				    enum amd_clockgating_state state)
+{
+	return 0;
+}
+
+static int pp_set_powergating_state(void *handle,
+				    enum amd_powergating_state state)
+{
+	return 0;
+}
+
+static int pp_suspend(void *handle)
+{
+	struct pp_instance *pp_handle;
+	struct pp_eventmgr *eventmgr;
+	struct pem_event_data event_data = { {0} };
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	pp_handle = (struct pp_instance *)handle;
+	eventmgr = pp_handle->eventmgr;
+	pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
+	return 0;
+}
+
+static int pp_resume(void *handle)
+{
+	struct pp_instance *pp_handle;
+	struct pp_eventmgr *eventmgr;
+	struct pem_event_data event_data = { {0} };
+	struct pp_smumgr *smumgr;
+	int ret;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	pp_handle = (struct pp_instance *)handle;
+	smumgr = pp_handle->smu_mgr;
+
+	if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
+		smumgr->smumgr_funcs->start_smu == NULL)
+		return -EINVAL;
+
+	ret = smumgr->smumgr_funcs->start_smu(smumgr);
+	if (ret) {
+		printk(KERN_ERR "[ powerplay ] smc start failed\n");
+		smumgr->smumgr_funcs->smu_fini(smumgr);
+		return ret;
+	}
+
+	eventmgr = pp_handle->eventmgr;
+	pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
+
+	return 0;
+}
+
+const struct amd_ip_funcs pp_ip_funcs = {
+	.early_init = pp_early_init,
+	.late_init = NULL,
+	.sw_init = pp_sw_init,
+	.sw_fini = pp_sw_fini,
+	.hw_init = pp_hw_init,
+	.hw_fini = pp_hw_fini,
+	.suspend = pp_suspend,
+	.resume = pp_resume,
+	.is_idle = pp_is_idle,
+	.wait_for_idle = pp_wait_for_idle,
+	.soft_reset = pp_sw_reset,
+	.print_status = pp_print_status,
+	.set_clockgating_state = pp_set_clockgating_state,
+	.set_powergating_state = pp_set_powergating_state,
+};
+
+static int pp_dpm_load_fw(void *handle)
+{
+	return 0;
+}
+
+static int pp_dpm_fw_loading_complete(void *handle)
+{
+	return 0;
+}
+
+static int pp_dpm_force_performance_level(void *handle,
+					enum amd_dpm_forced_level level)
+{
+	struct pp_instance *pp_handle;
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	pp_handle = (struct pp_instance *)handle;
+
+	hwmgr = pp_handle->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	    hwmgr->hwmgr_func->force_dpm_level == NULL)
+		return -EINVAL;
+
+	hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
+
+	return 0;
+}
+
+static enum amd_dpm_forced_level pp_dpm_get_performance_level(
+								void *handle)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL)
+		return -EINVAL;
+
+	return (((struct pp_instance *)handle)->hwmgr->dpm_level);
+}
+
+static int pp_dpm_get_sclk(void *handle, bool low)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	    hwmgr->hwmgr_func->get_sclk == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->get_sclk(hwmgr, low);
+}
+
+static int pp_dpm_get_mclk(void *handle, bool low)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	    hwmgr->hwmgr_func->get_mclk == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->get_mclk(hwmgr, low);
+}
+
+static int pp_dpm_powergate_vce(void *handle, bool gate)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	    hwmgr->hwmgr_func->powergate_vce == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
+}
+
+static int pp_dpm_powergate_uvd(void *handle, bool gate)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	    hwmgr->hwmgr_func->powergate_uvd == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
+}
+
+static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type  state)
+{
+	switch (state) {
+	case POWER_STATE_TYPE_BATTERY:
+		return PP_StateUILabel_Battery;
+	case POWER_STATE_TYPE_BALANCED:
+		return PP_StateUILabel_Balanced;
+	case POWER_STATE_TYPE_PERFORMANCE:
+		return PP_StateUILabel_Performance;
+	default:
+		return PP_StateUILabel_None;
+	}
+}
+
+int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input, void *output)
+{
+	int ret = 0;
+	struct pp_instance *pp_handle;
+	struct pem_event_data data = { {0} };
+
+	pp_handle = (struct pp_instance *)handle;
+
+	if (pp_handle == NULL)
+		return -EINVAL;
+
+	switch (event_id) {
+	case AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE:
+		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
+		break;
+	case AMD_PP_EVENT_ENABLE_USER_STATE:
+	{
+		enum amd_pm_state_type  ps;
+
+		if (input == NULL)
+			return -EINVAL;
+		ps = *(unsigned long *)input;
+
+		data.requested_ui_label = power_state_convert(ps);
+		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
+	}
+	break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
+{
+	struct pp_hwmgr *hwmgr;
+	struct pp_power_state *state;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->current_ps == NULL)
+		return -EINVAL;
+
+	state = hwmgr->current_ps;
+
+	switch (state->classification.ui_label) {
+	case PP_StateUILabel_Battery:
+		return POWER_STATE_TYPE_BATTERY;
+	case PP_StateUILabel_Balanced:
+		return POWER_STATE_TYPE_BALANCED;
+	case PP_StateUILabel_Performance:
+		return POWER_STATE_TYPE_PERFORMANCE;
+	default:
+		return POWER_STATE_TYPE_DEFAULT;
+	}
+}
+
+static void
+pp_debugfs_print_current_performance_level(void *handle,
+					       struct seq_file *m)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	  hwmgr->hwmgr_func->print_current_perforce_level == NULL)
+		return;
+
+	hwmgr->hwmgr_func->print_current_perforce_level(hwmgr, m);
+}
+
+static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	  hwmgr->hwmgr_func->set_fan_control_mode == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
+}
+
+static int pp_dpm_get_fan_control_mode(void *handle)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	  hwmgr->hwmgr_func->get_fan_control_mode == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
+}
+
+static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	  hwmgr->hwmgr_func->set_fan_speed_percent == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
+}
+
+static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	  hwmgr->hwmgr_func->get_fan_speed_percent == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
+}
+
+static int pp_dpm_get_temperature(void *handle)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+	  hwmgr->hwmgr_func->get_temperature == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->get_temperature(hwmgr);
+}
+
+const struct amd_powerplay_funcs pp_dpm_funcs = {
+	.get_temperature = pp_dpm_get_temperature,
+	.load_firmware = pp_dpm_load_fw,
+	.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
+	.force_performance_level = pp_dpm_force_performance_level,
+	.get_performance_level = pp_dpm_get_performance_level,
+	.get_current_power_state = pp_dpm_get_current_power_state,
+	.get_sclk = pp_dpm_get_sclk,
+	.get_mclk = pp_dpm_get_mclk,
+	.powergate_vce = pp_dpm_powergate_vce,
+	.powergate_uvd = pp_dpm_powergate_uvd,
+	.dispatch_tasks = pp_dpm_dispatch_tasks,
+	.print_current_performance_level = pp_debugfs_print_current_performance_level,
+	.set_fan_control_mode = pp_dpm_set_fan_control_mode,
+	.get_fan_control_mode = pp_dpm_get_fan_control_mode,
+	.set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
+	.get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
+};
+
+static int amd_pp_instance_init(struct amd_pp_init *pp_init,
+				struct amd_powerplay *amd_pp)
+{
+	int ret;
+	struct pp_instance *handle;
+
+	handle = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
+	if (handle == NULL)
+		return -ENOMEM;
+
+	handle->pp_valid = PP_VALID;
+
+	ret = smum_init(pp_init, handle);
+	if (ret)
+		goto fail_smum;
+
+	ret = hwmgr_init(pp_init, handle);
+	if (ret)
+		goto fail_hwmgr;
+
+	ret = eventmgr_init(handle);
+	if (ret)
+		goto fail_eventmgr;
+
+	amd_pp->pp_handle = handle;
+	return 0;
+
+fail_eventmgr:
+	hwmgr_fini(handle->hwmgr);
+fail_hwmgr:
+	smum_fini(handle->smu_mgr);
+fail_smum:
+	kfree(handle);
+	return ret;
+}
+
+static int amd_pp_instance_fini(void *handle)
+{
+	struct pp_instance *instance = (struct pp_instance *)handle;
+
+	if (instance == NULL)
+		return -EINVAL;
+
+	eventmgr_fini(instance->eventmgr);
+
+	hwmgr_fini(instance->hwmgr);
+
+	smum_fini(instance->smu_mgr);
+
+	kfree(handle);
+	return 0;
+}
+
+int amd_powerplay_init(struct amd_pp_init *pp_init,
+		       struct amd_powerplay *amd_pp)
+{
+	int ret;
+
+	if (pp_init == NULL || amd_pp == NULL)
+		return -EINVAL;
+
+	ret = amd_pp_instance_init(pp_init, amd_pp);
+
+	if (ret)
+		return ret;
+
+	amd_pp->ip_funcs = &pp_ip_funcs;
+	amd_pp->pp_funcs = &pp_dpm_funcs;
+
+	return 0;
+}
+
+int amd_powerplay_fini(void *handle)
+{
+	amd_pp_instance_fini(handle);
+
+	return 0;
+}
+
+/* export this function to DAL */
+
+int amd_powerplay_display_configuration_change(void *handle, const void *input)
+{
+	struct pp_hwmgr  *hwmgr;
+	const struct amd_pp_display_configuration *display_config = input;
+
+	PP_CHECK((struct pp_instance *)handle);
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	phm_store_dal_configuration_data(hwmgr, display_config);
+
+	return 0;
+}
+
+int amd_powerplay_get_display_power_level(void *handle,
+		struct amd_pp_dal_clock_info *output)
+{
+	struct pp_hwmgr  *hwmgr;
+
+	PP_CHECK((struct pp_instance *)handle);
+
+	if (output == NULL)
+		return -EINVAL;
+
+	hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+	return phm_get_dal_power_level(hwmgr, output);
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/Makefile
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the 'event manager' sub-component of powerplay.
+# It provides the event management services for the driver.
+
+EVENT_MGR = eventmgr.o eventinit.o eventmanagement.o  \
+		eventactionchains.o eventsubchains.o eventtasks.o psm.o
+
+AMD_PP_EVENT = $(addprefix $(AMD_PP_PATH)/eventmgr/,$(EVENT_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_PP_EVENT)
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "eventmgr.h"
+#include "eventactionchains.h"
+#include "eventsubchains.h"
+
+static const pem_event_action *initialize_event[] = {
+	block_adjust_power_state_tasks,
+	power_budget_tasks,
+	system_config_tasks,
+	setup_asic_tasks,
+	enable_dynamic_state_management_tasks,
+	enable_clock_power_gatings_tasks,
+	get_2d_performance_state_tasks,
+	set_performance_state_tasks,
+	initialize_thermal_controller_tasks,
+	conditionally_force_3d_performance_state_tasks,
+	process_vbios_eventinfo_tasks,
+	broadcast_power_policy_tasks,
+	NULL
+};
+
+const struct action_chain initialize_action_chain = {
+	"Initialize",
+	initialize_event
+};
+
+static const pem_event_action *uninitialize_event[] = {
+	ungate_all_display_phys_tasks,
+	uninitialize_display_phy_access_tasks,
+	disable_gfx_voltage_island_power_gating_tasks,
+	disable_gfx_clock_gating_tasks,
+	set_boot_state_tasks,
+	adjust_power_state_tasks,
+	disable_dynamic_state_management_tasks,
+	disable_clock_power_gatings_tasks,
+	cleanup_asic_tasks,
+	prepare_for_pnp_stop_tasks,
+	NULL
+};
+
+const struct action_chain uninitialize_action_chain = {
+	"Uninitialize",
+	uninitialize_event
+};
+
+static const pem_event_action *power_source_change_event_pp_enabled[] = {
+	set_power_source_tasks,
+	set_power_saving_state_tasks,
+	adjust_power_state_tasks,
+	enable_disable_fps_tasks,
+	set_nbmcu_state_tasks,
+	broadcast_power_policy_tasks,
+	NULL
+};
+
+const struct action_chain power_source_change_action_chain_pp_enabled = {
+	"Power source change - PowerPlay enabled",
+	power_source_change_event_pp_enabled
+};
+
+static const pem_event_action *power_source_change_event_pp_disabled[] = {
+	set_power_source_tasks,
+	set_nbmcu_state_tasks,
+	NULL
+};
+
+const struct action_chain power_source_changes_action_chain_pp_disabled = {
+	"Power source change - PowerPlay disabled",
+	power_source_change_event_pp_disabled
+};
+
+static const pem_event_action *power_source_change_event_hardware_dc[] = {
+	set_power_source_tasks,
+	set_power_saving_state_tasks,
+	adjust_power_state_tasks,
+	enable_disable_fps_tasks,
+	reset_hardware_dc_notification_tasks,
+	set_nbmcu_state_tasks,
+	broadcast_power_policy_tasks,
+	NULL
+};
+
+const struct action_chain power_source_change_action_chain_hardware_dc = {
+	"Power source change - with Hardware DC switching",
+	power_source_change_event_hardware_dc
+};
+
+static const pem_event_action *suspend_event[] = {
+	reset_display_phy_access_tasks,
+	unregister_interrupt_tasks,
+	disable_gfx_voltage_island_power_gating_tasks,
+	disable_gfx_clock_gating_tasks,
+	notify_smu_suspend_tasks,
+	disable_smc_firmware_ctf_tasks,
+	set_boot_state_tasks,
+	adjust_power_state_tasks,
+	disable_fps_tasks,
+	vari_bright_suspend_tasks,
+	reset_fan_speed_to_default_tasks,
+	power_down_asic_tasks,
+	disable_stutter_mode_tasks,
+	set_connected_standby_tasks,
+	block_hw_access_tasks,
+	NULL
+};
+
+const struct action_chain suspend_action_chain = {
+	"Suspend",
+	suspend_event
+};
+
+static const pem_event_action *resume_event[] = {
+	unblock_hw_access_tasks,
+	resume_connected_standby_tasks,
+	notify_smu_resume_tasks,
+	reset_display_configCounter_tasks,
+	update_dal_configuration_tasks,
+	vari_bright_resume_tasks,
+	block_adjust_power_state_tasks,
+	setup_asic_tasks,
+	enable_stutter_mode_tasks, /*must do this in boot state and before SMC is started */
+	enable_dynamic_state_management_tasks,
+	enable_clock_power_gatings_tasks,
+	enable_disable_bapm_tasks,
+	initialize_thermal_controller_tasks,
+	reset_boot_state_tasks,
+	adjust_power_state_tasks,
+	enable_disable_fps_tasks,
+	notify_hw_power_source_tasks,
+	process_vbios_event_info_tasks,
+	enable_gfx_clock_gating_tasks,
+	enable_gfx_voltage_island_power_gating_tasks,
+	reset_clock_gating_tasks,
+	notify_smu_vpu_recovery_end_tasks,
+	disable_vpu_cap_tasks,
+	execute_escape_sequence_tasks,
+	NULL
+};
+
+
+const struct action_chain resume_action_chain = {
+	"resume",
+	resume_event
+};
+
+static const pem_event_action *complete_init_event[] = {
+	adjust_power_state_tasks,
+	enable_gfx_clock_gating_tasks,
+	enable_gfx_voltage_island_power_gating_tasks,
+	notify_power_state_change_tasks,
+	NULL
+};
+
+const struct action_chain complete_init_action_chain = {
+	"complete init",
+	complete_init_event
+};
+
+static const pem_event_action *enable_gfx_clock_gating_event[] = {
+	enable_gfx_clock_gating_tasks,
+	NULL
+};
+
+const struct action_chain enable_gfx_clock_gating_action_chain = {
+	"enable gfx clock gate",
+	enable_gfx_clock_gating_event
+};
+
+static const pem_event_action *disable_gfx_clock_gating_event[] = {
+	disable_gfx_clock_gating_tasks,
+	NULL
+};
+
+const struct action_chain disable_gfx_clock_gating_action_chain = {
+	"disable gfx clock gate",
+	disable_gfx_clock_gating_event
+};
+
+static const pem_event_action *enable_cgpg_event[] = {
+	enable_cgpg_tasks,
+	NULL
+};
+
+const struct action_chain enable_cgpg_action_chain = {
+	"eable cg pg",
+	enable_cgpg_event
+};
+
+static const pem_event_action *disable_cgpg_event[] = {
+	disable_cgpg_tasks,
+	NULL
+};
+
+const struct action_chain disable_cgpg_action_chain = {
+	"disable cg pg",
+	disable_cgpg_event
+};
+
+
+/* Enable user _2d performance and activate */
+
+static const pem_event_action *enable_user_state_event[] = {
+	create_new_user_performance_state_tasks,
+	adjust_power_state_tasks,
+	NULL
+};
+
+const struct action_chain enable_user_state_action_chain = {
+	"Enable user state",
+	enable_user_state_event
+};
+
+static const pem_event_action *enable_user_2d_performance_event[] = {
+	enable_user_2d_performance_tasks,
+	add_user_2d_performance_state_tasks,
+	set_performance_state_tasks,
+	adjust_power_state_tasks,
+	delete_user_2d_performance_state_tasks,
+	NULL
+};
+
+const struct action_chain enable_user_2d_performance_action_chain = {
+	"enable_user_2d_performance_event_activate",
+	enable_user_2d_performance_event
+};
+
+
+static const pem_event_action *disable_user_2d_performance_event[] = {
+	disable_user_2d_performance_tasks,
+	delete_user_2d_performance_state_tasks,
+	NULL
+};
+
+const struct action_chain disable_user_2d_performance_action_chain = {
+	"disable_user_2d_performance_event",
+	disable_user_2d_performance_event
+};
+
+
+static const pem_event_action *display_config_change_event[] = {
+	/* countDisplayConfigurationChangeEventTasks, */
+	unblock_adjust_power_state_tasks,
+	set_cpu_power_state,
+	notify_hw_power_source_tasks,
+	/* updateDALConfigurationTasks,
+	variBrightDisplayConfigurationChangeTasks, */
+	adjust_power_state_tasks,
+	/*enableDisableFPSTasks,
+	setNBMCUStateTasks,
+	notifyPCIEDeviceReadyTasks,*/
+	NULL
+};
+
+const struct action_chain display_config_change_action_chain = {
+	"Display configuration change",
+	display_config_change_event
+};
+
+static const pem_event_action *readjust_power_state_event[] = {
+	adjust_power_state_tasks,
+	NULL
+};
+
+const struct action_chain readjust_power_state_action_chain = {
+	"re-adjust power state",
+	readjust_power_state_event
+};
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _EVENT_ACTION_CHAINS_H_
+#define _EVENT_ACTION_CHAINS_H_
+#include "eventmgr.h"
+
+extern const struct action_chain initialize_action_chain;
+
+extern const struct action_chain uninitialize_action_chain;
+
+extern const struct action_chain power_source_change_action_chain_pp_enabled;
+
+extern const struct action_chain power_source_changes_action_chain_pp_disabled;
+
+extern const struct action_chain power_source_change_action_chain_hardware_dc;
+
+extern const struct action_chain suspend_action_chain;
+
+extern const struct action_chain resume_action_chain;
+
+extern const struct action_chain complete_init_action_chain;
+
+extern const struct action_chain enable_gfx_clock_gating_action_chain;
+
+extern const struct action_chain disable_gfx_clock_gating_action_chain;
+
+extern const struct action_chain enable_cgpg_action_chain;
+
+extern const struct action_chain disable_cgpg_action_chain;
+
+extern const struct action_chain enable_user_2d_performance_action_chain;
+
+extern const struct action_chain disable_user_2d_performance_action_chain;
+
+extern const struct action_chain enable_user_state_action_chain;
+
+extern const struct action_chain readjust_power_state_action_chain;
+
+extern const struct action_chain display_config_change_action_chain;
+
+#endif /*_EVENT_ACTION_CHAINS_H_*/
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "eventmgr.h"
+#include "eventinit.h"
+#include "ppinterrupt.h"
+#include "hardwaremanager.h"
+
+void pem_init_feature_info(struct pp_eventmgr *eventmgr)
+{
+
+	/* PowerPlay info */
+	eventmgr->ui_state_info[PP_PowerSource_AC].default_ui_lable =
+					    PP_StateUILabel_Performance;
+
+	eventmgr->ui_state_info[PP_PowerSource_AC].current_ui_label =
+					    PP_StateUILabel_Performance;
+
+	eventmgr->ui_state_info[PP_PowerSource_DC].default_ui_lable =
+						  PP_StateUILabel_Battery;
+
+	eventmgr->ui_state_info[PP_PowerSource_DC].current_ui_label =
+						  PP_StateUILabel_Battery;
+
+	if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_PowerPlaySupport)) {
+		eventmgr->features[PP_Feature_PowerPlay].supported = true;
+		eventmgr->features[PP_Feature_PowerPlay].version = PEM_CURRENT_POWERPLAY_FEATURE_VERSION;
+		eventmgr->features[PP_Feature_PowerPlay].enabled_default = true;
+		eventmgr->features[PP_Feature_PowerPlay].enabled = true;
+	} else {
+		eventmgr->features[PP_Feature_PowerPlay].supported = false;
+		eventmgr->features[PP_Feature_PowerPlay].enabled = false;
+		eventmgr->features[PP_Feature_PowerPlay].enabled_default = false;
+	}
+
+	eventmgr->features[PP_Feature_Force3DClock].supported = true;
+	eventmgr->features[PP_Feature_Force3DClock].enabled = false;
+	eventmgr->features[PP_Feature_Force3DClock].enabled_default = false;
+	eventmgr->features[PP_Feature_Force3DClock].version = 1;
+
+	/* over drive*/
+	eventmgr->features[PP_Feature_User2DPerformance].version = 4;
+	eventmgr->features[PP_Feature_User3DPerformance].version = 4;
+	eventmgr->features[PP_Feature_OverdriveTest].version = 4;
+
+	eventmgr->features[PP_Feature_OverDrive].version = 4;
+	eventmgr->features[PP_Feature_OverDrive].enabled = false;
+	eventmgr->features[PP_Feature_OverDrive].enabled_default = false;
+
+	eventmgr->features[PP_Feature_User2DPerformance].supported = false;
+	eventmgr->features[PP_Feature_User2DPerformance].enabled = false;
+	eventmgr->features[PP_Feature_User2DPerformance].enabled_default = false;
+
+	eventmgr->features[PP_Feature_User3DPerformance].supported = false;
+	eventmgr->features[PP_Feature_User3DPerformance].enabled = false;
+	eventmgr->features[PP_Feature_User3DPerformance].enabled_default = false;
+
+	eventmgr->features[PP_Feature_OverdriveTest].supported = false;
+	eventmgr->features[PP_Feature_OverdriveTest].enabled = false;
+	eventmgr->features[PP_Feature_OverdriveTest].enabled_default = false;
+
+	eventmgr->features[PP_Feature_OverDrive].supported = false;
+
+	eventmgr->features[PP_Feature_PowerBudgetWaiver].enabled_default = false;
+	eventmgr->features[PP_Feature_PowerBudgetWaiver].version = 1;
+	eventmgr->features[PP_Feature_PowerBudgetWaiver].supported = false;
+	eventmgr->features[PP_Feature_PowerBudgetWaiver].enabled = false;
+
+	/* Multi UVD States support */
+	eventmgr->features[PP_Feature_MultiUVDState].supported = false;
+	eventmgr->features[PP_Feature_MultiUVDState].enabled = false;
+	eventmgr->features[PP_Feature_MultiUVDState].enabled_default = false;
+
+	/* Dynamic UVD States support */
+	eventmgr->features[PP_Feature_DynamicUVDState].supported = false;
+	eventmgr->features[PP_Feature_DynamicUVDState].enabled = false;
+	eventmgr->features[PP_Feature_DynamicUVDState].enabled_default = false;
+
+	/* VCE DPM support */
+	eventmgr->features[PP_Feature_VCEDPM].supported = false;
+	eventmgr->features[PP_Feature_VCEDPM].enabled = false;
+	eventmgr->features[PP_Feature_VCEDPM].enabled_default = false;
+
+	/* ACP PowerGating support */
+	eventmgr->features[PP_Feature_ACP_POWERGATING].supported = false;
+	eventmgr->features[PP_Feature_ACP_POWERGATING].enabled = false;
+	eventmgr->features[PP_Feature_ACP_POWERGATING].enabled_default = false;
+
+	/* PPM support */
+	eventmgr->features[PP_Feature_PPM].version = 1;
+	eventmgr->features[PP_Feature_PPM].supported = false;
+	eventmgr->features[PP_Feature_PPM].enabled = false;
+
+	/* FFC support (enables fan and temp settings, Gemini needs temp settings) */
+	if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport) ||
+	    phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_GeminiRegulatorFanControlSupport)) {
+		eventmgr->features[PP_Feature_FFC].version = 1;
+		eventmgr->features[PP_Feature_FFC].supported = true;
+		eventmgr->features[PP_Feature_FFC].enabled = true;
+		eventmgr->features[PP_Feature_FFC].enabled_default = true;
+	} else {
+		eventmgr->features[PP_Feature_FFC].supported = false;
+		eventmgr->features[PP_Feature_FFC].enabled = false;
+		eventmgr->features[PP_Feature_FFC].enabled_default = false;
+	}
+
+	eventmgr->features[PP_Feature_VariBright].supported = false;
+	eventmgr->features[PP_Feature_VariBright].enabled = false;
+	eventmgr->features[PP_Feature_VariBright].enabled_default = false;
+
+	eventmgr->features[PP_Feature_BACO].supported = false;
+	eventmgr->features[PP_Feature_BACO].supported = false;
+	eventmgr->features[PP_Feature_BACO].enabled_default = false;
+
+	/* PowerDown feature support */
+	eventmgr->features[PP_Feature_PowerDown].supported = false;
+	eventmgr->features[PP_Feature_PowerDown].enabled = false;
+	eventmgr->features[PP_Feature_PowerDown].enabled_default = false;
+
+	eventmgr->features[PP_Feature_FPS].version = 1;
+	eventmgr->features[PP_Feature_FPS].supported = false;
+	eventmgr->features[PP_Feature_FPS].enabled_default = false;
+	eventmgr->features[PP_Feature_FPS].enabled = false;
+
+	eventmgr->features[PP_Feature_ViPG].version = 1;
+	eventmgr->features[PP_Feature_ViPG].supported = false;
+	eventmgr->features[PP_Feature_ViPG].enabled_default = false;
+	eventmgr->features[PP_Feature_ViPG].enabled = false;
+}
+
+static int thermal_interrupt_callback(void *private_data,
+				      unsigned src_id, const uint32_t *iv_entry)
+{
+	/* TO DO hanle PEM_Event_ThermalNotification (struct pp_eventmgr *)private_data*/
+	printk("current thermal is out of range \n");
+	return 0;
+}
+
+int pem_register_interrupts(struct pp_eventmgr *eventmgr)
+{
+	int result = 0;
+	struct pp_interrupt_registration_info info;
+
+	info.call_back = thermal_interrupt_callback;
+	info.context = eventmgr;
+
+	result = phm_register_thermal_interrupt(eventmgr->hwmgr, &info);
+
+	/* TODO:
+	 * 2. Register CTF event interrupt
+	 * 3. Register for vbios events interrupt
+	 * 4. Register External Throttle Interrupt
+	 * 5. Register Smc To Host Interrupt
+	 * */
+	return result;
+}
+
+
+int pem_unregister_interrupts(struct pp_eventmgr *eventmgr)
+{
+	return 0;
+}
+
+
+void pem_uninit_featureInfo(struct pp_eventmgr *eventmgr)
+{
+	eventmgr->features[PP_Feature_MultiUVDState].supported = false;
+	eventmgr->features[PP_Feature_VariBright].supported = false;
+	eventmgr->features[PP_Feature_PowerBudgetWaiver].supported = false;
+	eventmgr->features[PP_Feature_OverDrive].supported = false;
+	eventmgr->features[PP_Feature_OverdriveTest].supported = false;
+	eventmgr->features[PP_Feature_User3DPerformance].supported = false;
+	eventmgr->features[PP_Feature_User2DPerformance].supported = false;
+	eventmgr->features[PP_Feature_PowerPlay].supported = false;
+	eventmgr->features[PP_Feature_Force3DClock].supported = false;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _EVENTINIT_H_
+#define _EVENTINIT_H_
+
+#define PEM_CURRENT_POWERPLAY_FEATURE_VERSION 4
+
+void pem_init_feature_info(struct pp_eventmgr *eventmgr);
+void pem_uninit_featureInfo(struct pp_eventmgr *eventmgr);
+int pem_register_interrupts(struct pp_eventmgr *eventmgr);
+int pem_unregister_interrupts(struct pp_eventmgr *eventmgr);
+
+#endif /* _EVENTINIT_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "eventmanagement.h"
+#include "eventmgr.h"
+#include "eventactionchains.h"
+
+int pem_init_event_action_chains(struct pp_eventmgr *eventmgr)
+{
+	int i;
+
+	for (i = 0; i < AMD_PP_EVENT_MAX; i++)
+		eventmgr->event_chain[i] = NULL;
+
+	eventmgr->event_chain[AMD_PP_EVENT_SUSPEND] = pem_get_suspend_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_INITIALIZE] = pem_get_initialize_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_UNINITIALIZE] = pem_get_uninitialize_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_POWER_SOURCE_CHANGE] = pem_get_power_source_change_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_HIBERNATE] = pem_get_hibernate_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_RESUME] = pem_get_resume_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_THERMAL_NOTIFICATION] = pem_get_thermal_notification_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_VBIOS_NOTIFICATION] = pem_get_vbios_notification_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_ENTER_THERMAL_STATE] = pem_get_enter_thermal_state_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_EXIT_THERMAL_STATE] = pem_get_exit_thermal_state_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_ENABLE_POWER_PLAY] = pem_get_enable_powerplay_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_DISABLE_POWER_PLAY] = pem_get_disable_powerplay_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_ENABLE_OVER_DRIVE_TEST] = pem_get_enable_overdrive_test_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_DISABLE_OVER_DRIVE_TEST] = pem_get_disable_overdrive_test_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_ENABLE_GFX_CLOCK_GATING] = pem_get_enable_gfx_clock_gating_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_DISABLE_GFX_CLOCK_GATING] = pem_get_disable_gfx_clock_gating_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_ENABLE_CGPG] = pem_get_enable_cgpg_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_DISABLE_CGPG] = pem_get_disable_cgpg_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_COMPLETE_INIT] = pem_get_complete_init_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_SCREEN_ON] = pem_get_screen_on_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_SCREEN_OFF] = pem_get_screen_off_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_PRE_SUSPEND] = pem_get_pre_suspend_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_PRE_RESUME] = pem_get_pre_resume_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_ENABLE_USER_STATE] = pem_enable_user_state_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_READJUST_POWER_STATE] = pem_readjust_power_state_action_chain(eventmgr);
+	eventmgr->event_chain[AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE] = pem_display_config_change_action_chain(eventmgr);
+	return 0;
+}
+
+int pem_excute_event_chain(struct pp_eventmgr *eventmgr, const struct action_chain *event_chain, struct pem_event_data *event_data)
+{
+	const pem_event_action **paction_chain;
+	const pem_event_action *psub_chain;
+	int tmp_result = 0;
+	int result = 0;
+
+	if (eventmgr == NULL || event_chain == NULL || event_data == NULL)
+		return -EINVAL;
+
+	for (paction_chain = event_chain->action_chain; NULL != *paction_chain; paction_chain++) {
+		if (0 != result)
+			return result;
+
+		for (psub_chain = *paction_chain; NULL != *psub_chain; psub_chain++) {
+			tmp_result = (*psub_chain)(eventmgr, event_data);
+			if (0 == result)
+				result = tmp_result;
+		}
+	}
+
+	return result;
+}
+
+const struct action_chain *pem_get_suspend_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &suspend_action_chain;
+}
+
+const struct action_chain *pem_get_initialize_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &initialize_action_chain;
+}
+
+const struct action_chain *pem_get_uninitialize_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &uninitialize_action_chain;
+}
+
+const struct action_chain *pem_get_power_source_change_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &power_source_change_action_chain_pp_enabled;  /* other case base on feature info*/
+}
+
+const struct action_chain *pem_get_resume_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &resume_action_chain;
+}
+
+const struct action_chain *pem_get_hibernate_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_thermal_notification_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_vbios_notification_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_enter_thermal_state_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_exit_thermal_state_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_enable_powerplay_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_disable_powerplay_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_enable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_disable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_enable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &enable_gfx_clock_gating_action_chain;
+}
+
+const struct action_chain *pem_get_disable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &disable_gfx_clock_gating_action_chain;
+}
+
+const struct action_chain *pem_get_enable_cgpg_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &enable_cgpg_action_chain;
+}
+
+const struct action_chain *pem_get_disable_cgpg_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &disable_cgpg_action_chain;
+}
+
+const struct action_chain *pem_get_complete_init_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &complete_init_action_chain;
+}
+
+const struct action_chain *pem_get_screen_on_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_screen_off_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_pre_suspend_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_get_pre_resume_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return NULL;
+}
+
+const struct action_chain *pem_enable_user_state_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &enable_user_state_action_chain;
+}
+
+const struct action_chain *pem_readjust_power_state_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &readjust_power_state_action_chain;
+}
+
+const struct action_chain *pem_display_config_change_action_chain(struct pp_eventmgr *eventmgr)
+{
+	return &display_config_change_action_chain;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _EVENT_MANAGEMENT_H_
+#define _EVENT_MANAGEMENT_H_
+
+#include "eventmgr.h"
+
+int pem_init_event_action_chains(struct pp_eventmgr *eventmgr);
+int pem_excute_event_chain(struct pp_eventmgr *eventmgr, const struct action_chain *event_chain, struct pem_event_data *event_data);
+const struct action_chain *pem_get_suspend_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_initialize_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_uninitialize_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_power_source_change_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_resume_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_hibernate_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_thermal_notification_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_vbios_notification_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enter_thermal_state_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_exit_thermal_state_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enable_powerplay_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_disable_powerplay_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_disable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_disable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enable_cgpg_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_disable_cgpg_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_complete_init_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_screen_on_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_screen_off_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_pre_suspend_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_pre_resume_action_chain(struct pp_eventmgr *eventmgr);
+
+extern const struct action_chain *pem_enable_user_state_action_chain(struct pp_eventmgr *eventmgr);
+extern const struct action_chain *pem_readjust_power_state_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_display_config_change_action_chain(struct pp_eventmgr *eventmgr);
+
+
+#endif /* _EVENT_MANAGEMENT_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "eventmgr.h"
+#include "hwmgr.h"
+#include "eventinit.h"
+#include "eventmanagement.h"
+
+static int pem_init(struct pp_eventmgr *eventmgr)
+{
+	int result = 0;
+	struct pem_event_data event_data;
+
+	/* Initialize PowerPlay feature info */
+	pem_init_feature_info(eventmgr);
+
+	/* Initialize event action chains */
+	pem_init_event_action_chains(eventmgr);
+
+	/* Call initialization event */
+	result = pem_handle_event(eventmgr, AMD_PP_EVENT_INITIALIZE, &event_data);
+
+	if (0 != result)
+		return result;
+
+	/* Register interrupt callback functions */
+	result = pem_register_interrupts(eventmgr);
+	return 0;
+}
+
+static void pem_fini(struct pp_eventmgr *eventmgr)
+{
+	struct pem_event_data event_data;
+
+	pem_uninit_featureInfo(eventmgr);
+	pem_unregister_interrupts(eventmgr);
+
+	pem_handle_event(eventmgr, AMD_PP_EVENT_UNINITIALIZE, &event_data);
+
+	if (eventmgr != NULL)
+		kfree(eventmgr);
+}
+
+int eventmgr_init(struct pp_instance *handle)
+{
+	int result = 0;
+	struct pp_eventmgr *eventmgr;
+
+	if (handle == NULL)
+		return -EINVAL;
+
+	eventmgr = kzalloc(sizeof(struct pp_eventmgr), GFP_KERNEL);
+	if (eventmgr == NULL)
+		return -ENOMEM;
+
+	eventmgr->hwmgr = handle->hwmgr;
+	handle->eventmgr = eventmgr;
+
+	eventmgr->platform_descriptor = &(eventmgr->hwmgr->platform_descriptor);
+	eventmgr->pp_eventmgr_init = pem_init;
+	eventmgr->pp_eventmgr_fini = pem_fini;
+
+	return result;
+}
+
+int eventmgr_fini(struct pp_eventmgr *eventmgr)
+{
+	kfree(eventmgr);
+	return 0;
+}
+
+static int pem_handle_event_unlocked(struct pp_eventmgr *eventmgr, enum amd_pp_event event, struct pem_event_data *data)
+{
+	if (eventmgr == NULL || event >= AMD_PP_EVENT_MAX || data == NULL)
+		return -EINVAL;
+
+	return pem_excute_event_chain(eventmgr, eventmgr->event_chain[event], data);
+}
+
+int pem_handle_event(struct pp_eventmgr *eventmgr, enum amd_pp_event event, struct pem_event_data *event_data)
+{
+	int r = 0;
+
+	r = pem_handle_event_unlocked(eventmgr, event, event_data);
+
+	return r;
+}
+
+bool pem_is_hw_access_blocked(struct pp_eventmgr *eventmgr)
+{
+	return (eventmgr->block_adjust_power_state || phm_is_hw_access_blocked(eventmgr->hwmgr));
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "eventmgr.h"
+#include "eventsubchains.h"
+#include "eventtasks.h"
+#include "hardwaremanager.h"
+
+const pem_event_action reset_display_phy_access_tasks[] = {
+	pem_task_reset_display_phys_access,
+	NULL
+};
+
+const pem_event_action broadcast_power_policy_tasks[] = {
+	/* PEM_Task_BroadcastPowerPolicyChange, */
+	NULL
+};
+
+const pem_event_action unregister_interrupt_tasks[] = {
+	pem_task_unregister_interrupts,
+	NULL
+};
+
+/* Disable GFX Voltage Islands Power Gating */
+const pem_event_action disable_gfx_voltage_island_powergating_tasks[] = {
+	pem_task_disable_voltage_island_power_gating,
+	NULL
+};
+
+const pem_event_action disable_gfx_clockgating_tasks[] = {
+	pem_task_disable_gfx_clock_gating,
+	NULL
+};
+
+const pem_event_action block_adjust_power_state_tasks[] = {
+	pem_task_block_adjust_power_state,
+	NULL
+};
+
+
+const pem_event_action unblock_adjust_power_state_tasks[] = {
+	pem_task_unblock_adjust_power_state,
+	NULL
+};
+
+const pem_event_action set_performance_state_tasks[] = {
+	pem_task_set_performance_state,
+	NULL
+};
+
+const pem_event_action get_2d_performance_state_tasks[] = {
+	pem_task_get_2D_performance_state_id,
+	NULL
+};
+
+const pem_event_action conditionally_force3D_performance_state_tasks[] = {
+	pem_task_conditionally_force_3d_performance_state,
+	NULL
+};
+
+const pem_event_action process_vbios_eventinfo_tasks[] = {
+	/* PEM_Task_ProcessVbiosEventInfo,*/
+	NULL
+};
+
+const pem_event_action enable_dynamic_state_management_tasks[] = {
+	/* PEM_Task_ResetBAPMPolicyChangedFlag,*/
+	pem_task_get_boot_state_id,
+	pem_task_enable_dynamic_state_management,
+	pem_task_register_interrupts,
+	NULL
+};
+
+const pem_event_action enable_clock_power_gatings_tasks[] = {
+	pem_task_enable_clock_power_gatings_tasks,
+	pem_task_powerdown_uvd_tasks,
+	pem_task_powerdown_vce_tasks,
+	NULL
+};
+
+const pem_event_action setup_asic_tasks[] = {
+	pem_task_setup_asic,
+	NULL
+};
+
+const pem_event_action power_budget_tasks[] = {
+	/* TODO
+	 * PEM_Task_PowerBudgetWaiverAvailable,
+	 * PEM_Task_PowerBudgetWarningMessage,
+	 * PEM_Task_PruneStatesBasedOnPowerBudget,
+	*/
+	NULL
+};
+
+const pem_event_action system_config_tasks[] = {
+	/* PEM_Task_PruneStatesBasedOnSystemConfig,*/
+	NULL
+};
+
+
+const pem_event_action conditionally_force_3d_performance_state_tasks[] = {
+	pem_task_conditionally_force_3d_performance_state,
+	NULL
+};
+
+const pem_event_action ungate_all_display_phys_tasks[] = {
+	/* PEM_Task_GetDisplayPhyAccessInfo */
+	NULL
+};
+
+const pem_event_action uninitialize_display_phy_access_tasks[] = {
+	/* PEM_Task_UninitializeDisplayPhysAccess, */
+	NULL
+};
+
+const pem_event_action disable_gfx_voltage_island_power_gating_tasks[] = {
+	/* PEM_Task_DisableVoltageIslandPowerGating, */
+	NULL
+};
+
+const pem_event_action disable_gfx_clock_gating_tasks[] = {
+	pem_task_disable_gfx_clock_gating,
+	NULL
+};
+
+const pem_event_action set_boot_state_tasks[] = {
+	pem_task_get_boot_state_id,
+	pem_task_set_boot_state,
+	NULL
+};
+
+const pem_event_action adjust_power_state_tasks[] = {
+	pem_task_notify_hw_mgr_display_configuration_change,
+	pem_task_adjust_power_state,
+	pem_task_notify_smc_display_config_after_power_state_adjustment,
+	pem_task_update_allowed_performance_levels,
+	/* to do pem_task_Enable_disable_bapm, */
+	NULL
+};
+
+const pem_event_action disable_dynamic_state_management_tasks[] = {
+	pem_task_unregister_interrupts,
+	pem_task_get_boot_state_id,
+	pem_task_disable_dynamic_state_management,
+	NULL
+};
+
+const pem_event_action disable_clock_power_gatings_tasks[] = {
+	pem_task_disable_clock_power_gatings_tasks,
+	NULL
+};
+
+const pem_event_action cleanup_asic_tasks[] = {
+	/* PEM_Task_DisableFPS,*/
+	pem_task_cleanup_asic,
+	NULL
+};
+
+const pem_event_action prepare_for_pnp_stop_tasks[] = {
+	/* PEM_Task_PrepareForPnpStop,*/
+	NULL
+};
+
+const pem_event_action set_power_source_tasks[] = {
+	pem_task_set_power_source,
+	pem_task_notify_hw_of_power_source,
+	NULL
+};
+
+const pem_event_action set_power_saving_state_tasks[] = {
+	pem_task_reset_power_saving_state,
+	pem_task_get_power_saving_state,
+	pem_task_set_power_saving_state,
+	/* PEM_Task_ResetODDCState,
+	 * PEM_Task_GetODDCState,
+	 * PEM_Task_SetODDCState,*/
+	NULL
+};
+
+const pem_event_action enable_disable_fps_tasks[] = {
+	/* PEM_Task_EnableDisableFPS,*/
+	NULL
+};
+
+const pem_event_action set_nbmcu_state_tasks[] = {
+	/* PEM_Task_NBMCUStateChange,*/
+	NULL
+};
+
+const pem_event_action reset_hardware_dc_notification_tasks[] = {
+	/* PEM_Task_ResetHardwareDCNotification,*/
+	NULL
+};
+
+
+const pem_event_action notify_smu_suspend_tasks[] = {
+	/* PEM_Task_NotifySMUSuspend,*/
+	NULL
+};
+
+const pem_event_action disable_smc_firmware_ctf_tasks[] = {
+	/* PEM_Task_DisableSMCFirmwareCTF,*/
+	NULL
+};
+
+const pem_event_action disable_fps_tasks[] = {
+	/* PEM_Task_DisableFPS,*/
+	NULL
+};
+
+const pem_event_action vari_bright_suspend_tasks[] = {
+	/* PEM_Task_VariBright_Suspend,*/
+	NULL
+};
+
+const pem_event_action reset_fan_speed_to_default_tasks[] = {
+	/* PEM_Task_ResetFanSpeedToDefault,*/
+	NULL
+};
+
+const pem_event_action power_down_asic_tasks[] = {
+	/* PEM_Task_DisableFPS,*/
+	pem_task_power_down_asic,
+	NULL
+};
+
+const pem_event_action disable_stutter_mode_tasks[] = {
+	/* PEM_Task_DisableStutterMode,*/
+	NULL
+};
+
+const pem_event_action set_connected_standby_tasks[] = {
+	/* PEM_Task_SetConnectedStandby,*/
+	NULL
+};
+
+const pem_event_action block_hw_access_tasks[] = {
+	pem_task_block_hw_access,
+	NULL
+};
+
+const pem_event_action unblock_hw_access_tasks[] = {
+	pem_task_un_block_hw_access,
+	NULL
+};
+
+const pem_event_action resume_connected_standby_tasks[] = {
+	/* PEM_Task_ResumeConnectedStandby,*/
+	NULL
+};
+
+const pem_event_action notify_smu_resume_tasks[] = {
+	/* PEM_Task_NotifySMUResume,*/
+	NULL
+};
+
+const pem_event_action reset_display_configCounter_tasks[] = {
+	pem_task_reset_display_phys_access,
+	NULL
+};
+
+const pem_event_action update_dal_configuration_tasks[] = {
+	/* PEM_Task_CheckVBlankTime,*/
+	NULL
+};
+
+const pem_event_action vari_bright_resume_tasks[] = {
+	/* PEM_Task_VariBright_Resume,*/
+	NULL
+};
+
+const pem_event_action notify_hw_power_source_tasks[] = {
+	pem_task_notify_hw_of_power_source,
+	NULL
+};
+
+const pem_event_action process_vbios_event_info_tasks[] = {
+	/* PEM_Task_ProcessVbiosEventInfo,*/
+	NULL
+};
+
+const pem_event_action enable_gfx_clock_gating_tasks[] = {
+	pem_task_enable_gfx_clock_gating,
+	NULL
+};
+
+const pem_event_action enable_gfx_voltage_island_power_gating_tasks[] = {
+	pem_task_enable_voltage_island_power_gating,
+	NULL
+};
+
+const pem_event_action reset_clock_gating_tasks[] = {
+	/* PEM_Task_ResetClockGating*/
+	NULL
+};
+
+const pem_event_action notify_smu_vpu_recovery_end_tasks[] = {
+	/* PEM_Task_NotifySmuVPURecoveryEnd,*/
+	NULL
+};
+
+const pem_event_action disable_vpu_cap_tasks[] = {
+	/* PEM_Task_DisableVPUCap,*/
+	NULL
+};
+
+const pem_event_action execute_escape_sequence_tasks[] = {
+	/* PEM_Task_ExecuteEscapesequence,*/
+	NULL
+};
+
+const pem_event_action notify_power_state_change_tasks[] = {
+	pem_task_notify_power_state_change,
+	NULL
+};
+
+const pem_event_action enable_cgpg_tasks[] = {
+	pem_task_enable_cgpg,
+	NULL
+};
+
+const pem_event_action disable_cgpg_tasks[] = {
+	pem_task_disable_cgpg,
+	NULL
+};
+
+const pem_event_action enable_user_2d_performance_tasks[] = {
+	/* PEM_Task_SetUser2DPerformanceFlag,*/
+	/* PEM_Task_UpdateUser2DPerformanceEnableEvents,*/
+	NULL
+};
+
+const pem_event_action add_user_2d_performance_state_tasks[] = {
+	/* PEM_Task_Get2DPerformanceTemplate,*/
+	/* PEM_Task_AllocateNewPowerStateMemory,*/
+	/* PEM_Task_CopyNewPowerStateInfo,*/
+	/* PEM_Task_UpdateNewPowerStateClocks,*/
+	/* PEM_Task_UpdateNewPowerStateUser2DPerformanceFlag,*/
+	/* PEM_Task_AddPowerState,*/
+	/* PEM_Task_ReleaseNewPowerStateMemory,*/
+	NULL
+};
+
+const pem_event_action delete_user_2d_performance_state_tasks[] = {
+	/* PEM_Task_GetCurrentUser2DPerformanceStateID,*/
+	/* PEM_Task_DeletePowerState,*/
+	/* PEM_Task_SetCurrentUser2DPerformanceStateID,*/
+	NULL
+};
+
+const pem_event_action disable_user_2d_performance_tasks[] = {
+	/* PEM_Task_ResetUser2DPerformanceFlag,*/
+	/* PEM_Task_UpdateUser2DPerformanceDisableEvents,*/
+	NULL
+};
+
+const pem_event_action enable_stutter_mode_tasks[] = {
+	pem_task_enable_stutter_mode,
+	NULL
+};
+
+const pem_event_action enable_disable_bapm_tasks[] = {
+	/*PEM_Task_EnableDisableBAPM,*/
+	NULL
+};
+
+const pem_event_action reset_boot_state_tasks[] = {
+	pem_task_reset_boot_state,
+	NULL
+};
+
+const pem_event_action create_new_user_performance_state_tasks[] = {
+	pem_task_create_user_performance_state,
+	NULL
+};
+
+const pem_event_action initialize_thermal_controller_tasks[] = {
+	pem_task_initialize_thermal_controller,
+	NULL
+};
+
+const pem_event_action uninitialize_thermal_controller_tasks[] = {
+	pem_task_uninitialize_thermal_controller,
+	NULL
+};
+
+const pem_event_action set_cpu_power_state[] = {
+	pem_task_set_cpu_power_state,
+	NULL
+};
\ No newline at end of file
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _EVENT_SUB_CHAINS_H_
+#define _EVENT_SUB_CHAINS_H_
+
+#include "eventmgr.h"
+
+extern const pem_event_action reset_display_phy_access_tasks[];
+extern const pem_event_action broadcast_power_policy_tasks[];
+extern const pem_event_action unregister_interrupt_tasks[];
+extern const pem_event_action disable_GFX_voltage_island_powergating_tasks[];
+extern const pem_event_action disable_GFX_clockgating_tasks[];
+extern const pem_event_action block_adjust_power_state_tasks[];
+extern const pem_event_action unblock_adjust_power_state_tasks[];
+extern const pem_event_action set_performance_state_tasks[];
+extern const pem_event_action get_2D_performance_state_tasks[];
+extern const pem_event_action conditionally_force3D_performance_state_tasks[];
+extern const pem_event_action process_vbios_eventinfo_tasks[];
+extern const pem_event_action enable_dynamic_state_management_tasks[];
+extern const pem_event_action enable_clock_power_gatings_tasks[];
+extern const pem_event_action conditionally_force3D_performance_state_tasks[];
+extern const pem_event_action setup_asic_tasks[];
+extern const pem_event_action power_budget_tasks[];
+extern const pem_event_action system_config_tasks[];
+extern const pem_event_action get_2d_performance_state_tasks[];
+extern const pem_event_action conditionally_force_3d_performance_state_tasks[];
+extern const pem_event_action ungate_all_display_phys_tasks[];
+extern const pem_event_action uninitialize_display_phy_access_tasks[];
+extern const pem_event_action disable_gfx_voltage_island_power_gating_tasks[];
+extern const pem_event_action disable_gfx_clock_gating_tasks[];
+extern const pem_event_action set_boot_state_tasks[];
+extern const pem_event_action adjust_power_state_tasks[];
+extern const pem_event_action disable_dynamic_state_management_tasks[];
+extern const pem_event_action disable_clock_power_gatings_tasks[];
+extern const pem_event_action cleanup_asic_tasks[];
+extern const pem_event_action prepare_for_pnp_stop_tasks[];
+extern const pem_event_action set_power_source_tasks[];
+extern const pem_event_action set_power_saving_state_tasks[];
+extern const pem_event_action enable_disable_fps_tasks[];
+extern const pem_event_action set_nbmcu_state_tasks[];
+extern const pem_event_action reset_hardware_dc_notification_tasks[];
+extern const pem_event_action notify_smu_suspend_tasks[];
+extern const pem_event_action disable_smc_firmware_ctf_tasks[];
+extern const pem_event_action disable_fps_tasks[];
+extern const pem_event_action vari_bright_suspend_tasks[];
+extern const pem_event_action reset_fan_speed_to_default_tasks[];
+extern const pem_event_action power_down_asic_tasks[];
+extern const pem_event_action disable_stutter_mode_tasks[];
+extern const pem_event_action set_connected_standby_tasks[];
+extern const pem_event_action block_hw_access_tasks[];
+extern const pem_event_action unblock_hw_access_tasks[];
+extern const pem_event_action resume_connected_standby_tasks[];
+extern const pem_event_action notify_smu_resume_tasks[];
+extern const pem_event_action reset_display_configCounter_tasks[];
+extern const pem_event_action update_dal_configuration_tasks[];
+extern const pem_event_action vari_bright_resume_tasks[];
+extern const pem_event_action notify_hw_power_source_tasks[];
+extern const pem_event_action process_vbios_event_info_tasks[];
+extern const pem_event_action enable_gfx_clock_gating_tasks[];
+extern const pem_event_action enable_gfx_voltage_island_power_gating_tasks[];
+extern const pem_event_action reset_clock_gating_tasks[];
+extern const pem_event_action notify_smu_vpu_recovery_end_tasks[];
+extern const pem_event_action disable_vpu_cap_tasks[];
+extern const pem_event_action execute_escape_sequence_tasks[];
+extern const pem_event_action notify_power_state_change_tasks[];
+extern const pem_event_action enable_cgpg_tasks[];
+extern const pem_event_action disable_cgpg_tasks[];
+extern const pem_event_action enable_user_2d_performance_tasks[];
+extern const pem_event_action add_user_2d_performance_state_tasks[];
+extern const pem_event_action delete_user_2d_performance_state_tasks[];
+extern const pem_event_action disable_user_2d_performance_tasks[];
+extern const pem_event_action enable_stutter_mode_tasks[];
+extern const pem_event_action enable_disable_bapm_tasks[];
+extern const pem_event_action reset_boot_state_tasks[];
+extern const pem_event_action create_new_user_performance_state_tasks[];
+extern const pem_event_action initialize_thermal_controller_tasks[];
+extern const pem_event_action uninitialize_thermal_controller_tasks[];
+extern const pem_event_action set_cpu_power_state[];
+#endif /* _EVENT_SUB_CHAINS_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "eventmgr.h"
+#include "eventinit.h"
+#include "eventmanagement.h"
+#include "eventmanager.h"
+#include "hardwaremanager.h"
+#include "eventtasks.h"
+#include "power_state.h"
+#include "hwmgr.h"
+#include "amd_powerplay.h"
+#include "psm.h"
+
+#define TEMP_RANGE_MIN (90 * 1000)
+#define TEMP_RANGE_MAX (120 * 1000)
+
+int pem_task_update_allowed_performance_levels(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+
+	if (pem_is_hw_access_blocked(eventmgr))
+		return 0;
+
+	phm_force_dpm_levels(eventmgr->hwmgr, AMD_DPM_FORCED_LEVEL_AUTO);
+
+	return 0;
+}
+
+/* eventtasks_generic.c */
+int pem_task_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	struct pp_hwmgr *hwmgr;
+
+	if (pem_is_hw_access_blocked(eventmgr))
+		return 0;
+
+	hwmgr = eventmgr->hwmgr;
+	if (event_data->pnew_power_state != NULL)
+		hwmgr->request_ps = event_data->pnew_power_state;
+
+	if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
+		psm_adjust_power_state_dynamic(eventmgr, event_data->skip_state_adjust_rules);
+	else
+		psm_adjust_power_state_static(eventmgr, event_data->skip_state_adjust_rules);
+
+	return 0;
+}
+
+int pem_task_power_down_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return phm_power_down_asic(eventmgr->hwmgr);
+}
+
+int pem_task_set_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	if (pem_is_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID))
+		return psm_set_states(eventmgr, &(event_data->requested_state_id));
+
+	return 0;
+}
+
+int pem_task_reset_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_update_new_power_state_clocks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_system_shutdown(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_register_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_unregister_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return pem_unregister_interrupts(eventmgr);
+}
+
+int pem_task_get_boot_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	int result;
+
+	result = psm_get_state_by_classification(eventmgr,
+		PP_StateClassificationFlag_Boot,
+		&(event_data->requested_state_id)
+	);
+
+	if (0 == result)
+		pem_set_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
+	else
+		pem_unset_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
+
+	return result;
+}
+
+int pem_task_enable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return phm_enable_dynamic_state_management(eventmgr->hwmgr);
+}
+
+int pem_task_disable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_enable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return phm_enable_clock_power_gatings(eventmgr->hwmgr);
+}
+
+int pem_task_powerdown_uvd_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return phm_powerdown_uvd(eventmgr->hwmgr);
+}
+
+int pem_task_powerdown_vce_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	phm_powergate_uvd(eventmgr->hwmgr, true);
+	phm_powergate_vce(eventmgr->hwmgr, true);
+	return 0;
+}
+
+int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_start_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_stop_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_setup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return phm_setup_asic(eventmgr->hwmgr);
+}
+
+int pem_task_cleanup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_store_dal_configuration(struct pp_eventmgr *eventmgr, const struct amd_display_configuration *display_config)
+{
+	/* TODO */
+	return 0;
+	/*phm_store_dal_configuration_data(eventmgr->hwmgr, display_config) */
+}
+
+int pem_task_notify_hw_mgr_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	if (pem_is_hw_access_blocked(eventmgr))
+		return 0;
+
+	return phm_display_configuration_changed(eventmgr->hwmgr);
+}
+
+int pem_task_notify_hw_mgr_pre_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return 0;
+}
+
+int pem_task_notify_smc_display_config_after_power_state_adjustment(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	if (pem_is_hw_access_blocked(eventmgr))
+		return 0;
+
+	return phm_notify_smc_display_config_after_ps_adjustment(eventmgr->hwmgr);
+}
+
+int pem_task_block_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	eventmgr->block_adjust_power_state = true;
+	/* to do PHM_ResetIPSCounter(pEventMgr->pHwMgr);*/
+	return 0;
+}
+
+int pem_task_unblock_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	eventmgr->block_adjust_power_state = false;
+	return 0;
+}
+
+int pem_task_notify_power_state_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_un_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_reset_display_phys_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_set_cpu_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return phm_set_cpu_power_state(eventmgr->hwmgr);
+}
+
+/*powersaving*/
+
+int pem_task_set_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_notify_hw_of_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_get_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_reset_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_set_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_set_screen_state_on(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_set_screen_state_off(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_enable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_disable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_enable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_disable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_enable_clock_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+
+int pem_task_enable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_disable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+
+/* performance */
+int pem_task_set_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	if (pem_is_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID))
+		return psm_set_states(eventmgr, &(event_data->requested_state_id));
+
+	return 0;
+}
+
+int pem_task_conditionally_force_3d_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_enable_stutter_mode(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	/* TODO */
+	return 0;
+}
+
+int pem_task_get_2D_performance_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	int result;
+
+	if (eventmgr->features[PP_Feature_PowerPlay].supported &&
+		!(eventmgr->features[PP_Feature_PowerPlay].enabled))
+			result = psm_get_state_by_classification(eventmgr,
+					PP_StateClassificationFlag_Boot,
+					&(event_data->requested_state_id));
+	else if (eventmgr->features[PP_Feature_User2DPerformance].enabled)
+			result = psm_get_state_by_classification(eventmgr,
+				   PP_StateClassificationFlag_User2DPerformance,
+					&(event_data->requested_state_id));
+	else
+		result = psm_get_ui_state(eventmgr, PP_StateUILabel_Performance,
+					&(event_data->requested_state_id));
+
+	if (0 == result)
+		pem_set_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
+	else
+		pem_unset_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
+
+	return result;
+}
+
+int pem_task_create_user_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	struct pp_power_state *state;
+	int table_entries;
+	struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
+	int i;
+
+	table_entries = hwmgr->num_ps;
+	state = hwmgr->ps;
+
+restart_search:
+	for (i = 0; i < table_entries; i++) {
+		if (state->classification.ui_label & event_data->requested_ui_label) {
+			event_data->pnew_power_state = state;
+			return 0;
+		}
+		state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
+	}
+
+	switch (event_data->requested_ui_label) {
+	case PP_StateUILabel_Battery:
+	case PP_StateUILabel_Balanced:
+		event_data->requested_ui_label = PP_StateUILabel_Performance;
+		goto restart_search;
+	default:
+		break;
+	}
+	return -1;
+}
+
+int pem_task_initialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	struct PP_TemperatureRange range;
+
+	range.max = TEMP_RANGE_MAX;
+	range.min = TEMP_RANGE_MIN;
+
+	if (eventmgr == NULL || eventmgr->platform_descriptor == NULL)
+		return -EINVAL;
+
+	if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_ThermalController))
+		return phm_start_thermal_controller(eventmgr->hwmgr, &range);
+
+	return 0;
+}
+
+int pem_task_uninitialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+	return phm_stop_thermal_controller(eventmgr->hwmgr);
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _EVENT_TASKS_H_
+#define _EVENT_TASKS_H_
+#include "eventmgr.h"
+
+struct amd_display_configuration;
+
+/* eventtasks_generic.c */
+int pem_task_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_power_down_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_get_boot_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_reset_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_update_new_power_state_clocks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_system_shutdown(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_register_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_unregister_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_powerdown_uvd_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_powerdown_vce_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_start_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_stop_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_setup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_cleanup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_store_dal_configuration (struct pp_eventmgr *eventmgr, const struct amd_display_configuration *display_config);
+int pem_task_notify_hw_mgr_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_notify_hw_mgr_pre_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_block_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_unblock_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_notify_power_state_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_un_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_reset_display_phys_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_cpu_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_notify_smc_display_config_after_power_state_adjustment(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+/*powersaving*/
+
+int pem_task_set_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_notify_hw_of_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_get_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_reset_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_screen_state_on(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_screen_state_off(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_stutter_mode(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+
+/* performance */
+int pem_task_set_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_conditionally_force_3d_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_get_2D_performance_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_create_user_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_update_allowed_performance_levels(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+/*thermal */
+int pem_task_initialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_uninitialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+
+#endif /* _EVENT_TASKS_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/psm.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/psm.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "psm.h"
+
+int psm_get_ui_state(struct pp_eventmgr *eventmgr, enum PP_StateUILabel ui_label, unsigned long *state_id)
+{
+	struct pp_power_state *state;
+	int table_entries;
+	struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
+	int i;
+
+	table_entries = hwmgr->num_ps;
+	state = hwmgr->ps;
+
+	for (i = 0; i < table_entries; i++) {
+		if (state->classification.ui_label & ui_label) {
+			*state_id = state->id;
+			return 0;
+		}
+		state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
+	}
+	return -1;
+}
+
+int psm_get_state_by_classification(struct pp_eventmgr *eventmgr, enum PP_StateClassificationFlag flag, unsigned long *state_id)
+{
+	struct pp_power_state *state;
+	int table_entries;
+	struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
+	int i;
+
+	table_entries = hwmgr->num_ps;
+	state = hwmgr->ps;
+
+	for (i = 0; i < table_entries; i++) {
+		if (state->classification.flags & flag) {
+			*state_id = state->id;
+			return 0;
+		}
+		state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
+	}
+	return -1;
+}
+
+int psm_set_states(struct pp_eventmgr *eventmgr, unsigned long *state_id)
+{
+	struct pp_power_state *state;
+	int table_entries;
+	struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
+	int i;
+
+	table_entries = hwmgr->num_ps;
+	state = hwmgr->ps;
+
+	for (i = 0; i < table_entries; i++) {
+		if (state->id == *state_id) {
+			hwmgr->request_ps = state;
+			return 0;
+		}
+		state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
+	}
+	return -1;
+}
+
+int psm_adjust_power_state_dynamic(struct pp_eventmgr *eventmgr, bool skip)
+{
+
+	struct pp_power_state *pcurrent;
+	struct pp_power_state *requested;
+	struct pp_hwmgr *hwmgr;
+	bool equal;
+
+	if (skip)
+		return 0;
+
+	hwmgr = eventmgr->hwmgr;
+	pcurrent = hwmgr->current_ps;
+	requested = hwmgr->request_ps;
+
+	if (requested == NULL)
+		return 0;
+
+	if (pcurrent == NULL || (0 != phm_check_states_equal(hwmgr, &pcurrent->hardware, &requested->hardware, &equal)))
+		equal = false;
+
+	if (!equal || phm_check_smc_update_required_for_display_configuration(hwmgr)) {
+		phm_apply_state_adjust_rules(hwmgr, requested, pcurrent);
+		phm_set_power_state(hwmgr, &pcurrent->hardware, &requested->hardware);
+		hwmgr->current_ps = requested;
+	}
+	return 0;
+}
+
+int psm_adjust_power_state_static(struct pp_eventmgr *eventmgr, bool skip)
+{
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/eventmgr/psm.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/eventmgr/psm.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "eventmgr.h"
+#include "eventinit.h"
+#include "eventmanagement.h"
+#include "eventmanager.h"
+#include "power_state.h"
+#include "hardwaremanager.h"
+
+int psm_get_ui_state(struct pp_eventmgr *eventmgr, enum PP_StateUILabel ui_label, unsigned long *state_id);
+
+int psm_get_state_by_classification(struct pp_eventmgr *eventmgr, enum PP_StateClassificationFlag flag, unsigned long *state_id);
+
+int psm_set_states(struct pp_eventmgr *eventmgr, unsigned long *state_id);
+
+int psm_adjust_power_state_dynamic(struct pp_eventmgr *eventmgr, bool skip);
+
+int psm_adjust_power_state_static(struct pp_eventmgr *eventmgr, bool skip);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the 'hw manager' sub-component of powerplay.
+# It provides the hardware management services for the driver.
+
+HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \
+	       hardwaremanager.o pp_acpi.o cz_hwmgr.o \
+               cz_clockpowergating.o \
+	       tonga_processpptables.o ppatomctrl.o \
+               tonga_hwmgr.o pppcielanes.o  tonga_thermal.o\
+               fiji_powertune.o fiji_hwmgr.o tonga_clockpowergating.o \
+               fiji_clockpowergating.o fiji_thermal.o
+
+AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_PP_HWMGR)
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "hwmgr.h"
+#include "cz_clockpowergating.h"
+#include "cz_ppsmc.h"
+
+/* PhyID -> Status Mapping in DDI_PHY_GEN_STATUS
+    0    GFX0L (3:0),                  (27:24),
+    1    GFX0H (7:4),                  (31:28),
+    2    GFX1L (3:0),                  (19:16),
+    3    GFX1H (7:4),                  (23:20),
+    4    DDIL   (3:0),                   (11: 8),
+    5    DDIH  (7:4),                   (15:12),
+    6    DDI2L (3:0),                   ( 3: 0),
+    7    DDI2H (7:4),                   ( 7: 4),
+*/
+#define DDI_PHY_GEN_STATUS_VAL(phyID)   (1 << ((3 - ((phyID & 0x07)/2))*8 + (phyID & 0x01)*4))
+#define IS_PHY_ID_USED_BY_PLL(PhyID)    (((0xF3 & (1 << PhyID)) & 0xFF) ? true : false)
+
+
+int cz_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
+{
+	int ret = 0;
+
+	switch (block) {
+	case PHM_AsicBlock_UVD_MVC:
+	case PHM_AsicBlock_UVD:
+	case PHM_AsicBlock_UVD_HD:
+	case PHM_AsicBlock_UVD_SD:
+		if (gating == PHM_ClockGateSetting_StaticOff)
+			ret = cz_dpm_powerdown_uvd(hwmgr);
+		else
+			ret = cz_dpm_powerup_uvd(hwmgr);
+		break;
+	case PHM_AsicBlock_GFX:
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+
+bool cz_phm_is_safe_for_asic_block(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, enum PHM_AsicBlock block)
+{
+	return true;
+}
+
+
+int cz_phm_enable_disable_gfx_power_gating(struct pp_hwmgr *hwmgr, bool enable)
+{
+	return 0;
+}
+
+int cz_phm_smu_power_up_down_pcie(struct pp_hwmgr *hwmgr, uint32_t target, bool up, uint32_t args)
+{
+	/* TODO */
+	return 0;
+}
+
+int cz_phm_initialize_display_phy_access(struct pp_hwmgr *hwmgr, bool initialize, bool accesshw)
+{
+	/* TODO */
+	return 0;
+}
+
+int cz_phm_get_display_phy_access_info(struct pp_hwmgr *hwmgr)
+{
+	/* TODO */
+	return 0;
+}
+
+int cz_phm_gate_unused_display_phys(struct pp_hwmgr *hwmgr)
+{
+	/* TODO */
+	return 0;
+}
+
+int cz_phm_ungate_all_display_phys(struct pp_hwmgr *hwmgr)
+{
+	/* TODO */
+	return 0;
+}
+
+static int cz_tf_uvd_power_gating_initialize(struct pp_hwmgr *hwmgr, void *pInput, void *pOutput, void *pStorage, int Result)
+{
+	return 0;
+}
+
+static int cz_tf_vce_power_gating_initialize(struct pp_hwmgr *hwmgr, void *pInput, void *pOutput, void *pStorage, int Result)
+{
+	return 0;
+}
+
+int cz_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	uint32_t dpm_features = 0;
+
+	if (enable &&
+		phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				  PHM_PlatformCaps_UVDDPM)) {
+		cz_hwmgr->dpm_flags |= DPMFlags_UVD_Enabled;
+		dpm_features |= UVD_DPM_MASK;
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+			    PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
+	} else {
+		dpm_features |= UVD_DPM_MASK;
+		cz_hwmgr->dpm_flags &= ~DPMFlags_UVD_Enabled;
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+			   PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
+	}
+	return 0;
+}
+
+int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	uint32_t dpm_features = 0;
+
+	if (enable && phm_cap_enabled(
+				hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_VCEDPM)) {
+		cz_hwmgr->dpm_flags |= DPMFlags_VCE_Enabled;
+		dpm_features |= VCE_DPM_MASK;
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+			    PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
+	} else {
+		dpm_features |= VCE_DPM_MASK;
+		cz_hwmgr->dpm_flags &= ~DPMFlags_VCE_Enabled;
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+			   PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
+	}
+
+	return 0;
+}
+
+
+int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	if (cz_hwmgr->uvd_power_gated == bgate)
+		return 0;
+
+	cz_hwmgr->uvd_power_gated = bgate;
+
+	if (bgate) {
+		cgs_set_clockgating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_CG_STATE_UNGATE);
+		cgs_set_powergating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_PG_STATE_GATE);
+		cz_dpm_update_uvd_dpm(hwmgr, true);
+		cz_dpm_powerdown_uvd(hwmgr);
+	} else {
+		cz_dpm_powerup_uvd(hwmgr);
+		cgs_set_clockgating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_PG_STATE_GATE);
+		cgs_set_powergating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_CG_STATE_UNGATE);
+		cz_dpm_update_uvd_dpm(hwmgr, false);
+	}
+
+	return 0;
+}
+
+int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_VCEPowerGating)) {
+		if (cz_hwmgr->vce_power_gated != bgate) {
+			if (bgate) {
+				cgs_set_clockgating_state(
+							hwmgr->device,
+							AMD_IP_BLOCK_TYPE_VCE,
+							AMD_CG_STATE_UNGATE);
+				cgs_set_powergating_state(
+							hwmgr->device,
+							AMD_IP_BLOCK_TYPE_VCE,
+							AMD_PG_STATE_GATE);
+				cz_enable_disable_vce_dpm(hwmgr, false);
+			/* TODO: to figure out why vce can't be poweroff*/
+				cz_hwmgr->vce_power_gated = true;
+			} else {
+				cz_dpm_powerup_vce(hwmgr);
+				cz_hwmgr->vce_power_gated = false;
+				cgs_set_clockgating_state(
+							hwmgr->device,
+							AMD_IP_BLOCK_TYPE_VCE,
+							AMD_PG_STATE_GATE);
+				cgs_set_powergating_state(
+							hwmgr->device,
+							AMD_IP_BLOCK_TYPE_VCE,
+							AMD_CG_STATE_UNGATE);
+				cz_dpm_update_vce_dpm(hwmgr);
+				cz_enable_disable_vce_dpm(hwmgr, true);
+				return 0;
+			}
+		}
+	} else {
+		cz_dpm_update_vce_dpm(hwmgr);
+		cz_enable_disable_vce_dpm(hwmgr, true);
+		return 0;
+	}
+
+	if (!cz_hwmgr->vce_power_gated)
+		cz_dpm_update_vce_dpm(hwmgr);
+
+	return 0;
+}
+
+
+static struct phm_master_table_item cz_enable_clock_power_gatings_list[] = {
+	/*we don't need an exit table here, because there is only D3 cold on Kv*/
+	{ phm_cf_want_uvd_power_gating, cz_tf_uvd_power_gating_initialize },
+	{ phm_cf_want_vce_power_gating, cz_tf_vce_power_gating_initialize },
+	/* to do { NULL, cz_tf_xdma_power_gating_enable }, */
+	{ NULL, NULL }
+};
+
+struct phm_master_table_header cz_phm_enable_clock_power_gatings_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	cz_enable_clock_power_gatings_list
+};
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _CZ_CLOCK_POWER_GATING_H_
+#define _CZ_CLOCK_POWER_GATING_H_
+
+#include "cz_hwmgr.h"
+#include "pp_asicblocks.h"
+
+extern int cz_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
+extern struct phm_master_table_header cz_phm_enable_clock_power_gatings_master;
+extern struct phm_master_table_header cz_phm_disable_clock_power_gatings_master;
+extern int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
+extern int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
+extern int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
+extern int cz_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable);
+#endif /* _CZ_CLOCK_POWER_GATING_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
@@ -0,0 +1,1760 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "atom-types.h"
+#include "atombios.h"
+#include "processpptables.h"
+#include "pp_debug.h"
+#include "cgs_common.h"
+#include "smu/smu_8_0_d.h"
+#include "smu8_fusion.h"
+#include "smu/smu_8_0_sh_mask.h"
+#include "smumgr.h"
+#include "hwmgr.h"
+#include "hardwaremanager.h"
+#include "cz_ppsmc.h"
+#include "cz_hwmgr.h"
+#include "power_state.h"
+#include "cz_clockpowergating.h"
+#include "pp_debug.h"
+
+#define ixSMUSVI_NB_CURRENTVID 0xD8230044
+#define CURRENT_NB_VID_MASK 0xff000000
+#define CURRENT_NB_VID__SHIFT 24
+#define ixSMUSVI_GFX_CURRENTVID  0xD8230048
+#define CURRENT_GFX_VID_MASK 0xff000000
+#define CURRENT_GFX_VID__SHIFT 24
+
+static const unsigned long PhwCz_Magic = (unsigned long) PHM_Cz_Magic;
+
+static struct cz_power_state *cast_PhwCzPowerState(struct pp_hw_power_state *hw_ps)
+{
+	if (PhwCz_Magic != hw_ps->magic)
+		return NULL;
+
+	return (struct cz_power_state *)hw_ps;
+}
+
+static const struct cz_power_state *cast_const_PhwCzPowerState(
+				const struct pp_hw_power_state *hw_ps)
+{
+	if (PhwCz_Magic != hw_ps->magic)
+		return NULL;
+
+	return (struct cz_power_state *)hw_ps;
+}
+
+uint32_t cz_get_eclk_level(struct pp_hwmgr *hwmgr,
+					uint32_t clock, uint32_t msg)
+{
+	int i = 0;
+	struct phm_vce_clock_voltage_dependency_table *ptable =
+		hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+	switch (msg) {
+	case PPSMC_MSG_SetEclkSoftMin:
+	case PPSMC_MSG_SetEclkHardMin:
+		for (i = 0; i < (int)ptable->count; i++) {
+			if (clock <= ptable->entries[i].ecclk)
+				break;
+		}
+		break;
+
+	case PPSMC_MSG_SetEclkSoftMax:
+	case PPSMC_MSG_SetEclkHardMax:
+		for (i = ptable->count - 1; i >= 0; i--) {
+			if (clock >= ptable->entries[i].ecclk)
+				break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return i;
+}
+
+static uint32_t cz_get_sclk_level(struct pp_hwmgr *hwmgr,
+				uint32_t clock, uint32_t msg)
+{
+	int i = 0;
+	struct phm_clock_voltage_dependency_table *table =
+				hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+	switch (msg) {
+	case PPSMC_MSG_SetSclkSoftMin:
+	case PPSMC_MSG_SetSclkHardMin:
+		for (i = 0; i < (int)table->count; i++) {
+			if (clock <= table->entries[i].clk)
+				break;
+		}
+		break;
+
+	case PPSMC_MSG_SetSclkSoftMax:
+	case PPSMC_MSG_SetSclkHardMax:
+		for (i = table->count - 1; i >= 0; i--) {
+			if (clock >= table->entries[i].clk)
+				break;
+		}
+		break;
+
+	default:
+		break;
+	}
+	return i;
+}
+
+static uint32_t cz_get_uvd_level(struct pp_hwmgr *hwmgr,
+					uint32_t clock, uint32_t msg)
+{
+	int i = 0;
+	struct phm_uvd_clock_voltage_dependency_table *ptable =
+		hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+
+	switch (msg) {
+	case PPSMC_MSG_SetUvdSoftMin:
+	case PPSMC_MSG_SetUvdHardMin:
+		for (i = 0; i < (int)ptable->count; i++) {
+			if (clock <= ptable->entries[i].vclk)
+				break;
+		}
+		break;
+
+	case PPSMC_MSG_SetUvdSoftMax:
+	case PPSMC_MSG_SetUvdHardMax:
+		for (i = ptable->count - 1; i >= 0; i--) {
+			if (clock >= ptable->entries[i].vclk)
+				break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return i;
+}
+
+static uint32_t cz_get_max_sclk_level(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	if (cz_hwmgr->max_sclk_level == 0) {
+		smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxSclkLevel);
+		cz_hwmgr->max_sclk_level = smum_get_argument(hwmgr->smumgr) + 1;
+	}
+
+	return cz_hwmgr->max_sclk_level;
+}
+
+static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	uint32_t i;
+	struct cgs_system_info sys_info = {0};
+	int result;
+
+	cz_hwmgr->gfx_ramp_step = 256*25/100;
+
+	cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */
+
+	for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++)
+		cz_hwmgr->activity_target[i] = CZ_AT_DFLT;
+
+	cz_hwmgr->mgcg_cgtt_local0 = 0x00000000;
+	cz_hwmgr->mgcg_cgtt_local1 = 0x00000000;
+
+	cz_hwmgr->clock_slow_down_freq = 25000;
+
+	cz_hwmgr->skip_clock_slow_down = 1;
+
+	cz_hwmgr->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */
+
+	cz_hwmgr->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */
+
+	cz_hwmgr->voting_rights_clients = 0x00C00033;
+
+	cz_hwmgr->static_screen_threshold = 8;
+
+	cz_hwmgr->ddi_power_gating_disabled = 0;
+
+	cz_hwmgr->bapm_enabled = 1;
+
+	cz_hwmgr->voltage_drop_threshold = 0;
+
+	cz_hwmgr->gfx_power_gating_threshold = 500;
+
+	cz_hwmgr->vce_slow_sclk_threshold = 20000;
+
+	cz_hwmgr->dce_slow_sclk_threshold = 30000;
+
+	cz_hwmgr->disable_driver_thermal_policy = 1;
+
+	cz_hwmgr->disable_nb_ps3_in_battery = 0;
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+							PHM_PlatformCaps_ABM);
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				    PHM_PlatformCaps_NonABMSupportInPPLib);
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+					   PHM_PlatformCaps_SclkDeepSleep);
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_DynamicM3Arbiter);
+
+	cz_hwmgr->override_dynamic_mgpg = 1;
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				  PHM_PlatformCaps_DynamicPatchPowerState);
+
+	cz_hwmgr->thermal_auto_throttling_treshold = 0;
+
+	cz_hwmgr->tdr_clock = 0;
+
+	cz_hwmgr->disable_gfx_power_gating_in_uvd = 0;
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_DynamicUVDState);
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_UVDDPM);
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_VCEDPM);
+
+	cz_hwmgr->cc6_settings.cpu_cc6_disable = false;
+	cz_hwmgr->cc6_settings.cpu_pstate_disable = false;
+	cz_hwmgr->cc6_settings.nb_pstate_switch_disable = false;
+	cz_hwmgr->cc6_settings.cpu_pstate_separation_time = 0;
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				   PHM_PlatformCaps_DisableVoltageIsland);
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+		      PHM_PlatformCaps_UVDPowerGating);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+		      PHM_PlatformCaps_VCEPowerGating);
+	sys_info.size = sizeof(struct cgs_system_info);
+	sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS;
+	result = cgs_query_system_info(hwmgr->device, &sys_info);
+	if (!result) {
+		if (sys_info.value & AMD_PG_SUPPORT_UVD)
+			phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				      PHM_PlatformCaps_UVDPowerGating);
+		if (sys_info.value & AMD_PG_SUPPORT_VCE)
+			phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				      PHM_PlatformCaps_VCEPowerGating);
+	}
+
+	return 0;
+}
+
+static uint32_t cz_convert_8Bit_index_to_voltage(
+			struct pp_hwmgr *hwmgr, uint16_t voltage)
+{
+	return 6200 - (voltage * 25);
+}
+
+static int cz_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
+			struct phm_clock_and_voltage_limits *table)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)hwmgr->backend;
+	struct cz_sys_info *sys_info = &cz_hwmgr->sys_info;
+	struct phm_clock_voltage_dependency_table *dep_table =
+				hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+	if (dep_table->count > 0) {
+		table->sclk = dep_table->entries[dep_table->count-1].clk;
+		table->vddc = cz_convert_8Bit_index_to_voltage(hwmgr,
+		   (uint16_t)dep_table->entries[dep_table->count-1].v);
+	}
+	table->mclk = sys_info->nbp_memory_clock[0];
+	return 0;
+}
+
+static int cz_init_dynamic_state_adjustment_rule_settings(
+			struct pp_hwmgr *hwmgr,
+			ATOM_CLK_VOLT_CAPABILITY *disp_voltage_table)
+{
+	uint32_t table_size =
+		sizeof(struct phm_clock_voltage_dependency_table) +
+		(7 * sizeof(struct phm_clock_voltage_dependency_record));
+
+	struct phm_clock_voltage_dependency_table *table_clk_vlt =
+					kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == table_clk_vlt) {
+		printk(KERN_ERR "[ powerplay ] Can not allocate memory!\n");
+		return -ENOMEM;
+	}
+
+	table_clk_vlt->count = 8;
+	table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
+	table_clk_vlt->entries[0].v = 0;
+	table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
+	table_clk_vlt->entries[1].v = 1;
+	table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
+	table_clk_vlt->entries[2].v = 2;
+	table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
+	table_clk_vlt->entries[3].v = 3;
+	table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
+	table_clk_vlt->entries[4].v = 4;
+	table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
+	table_clk_vlt->entries[5].v = 5;
+	table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
+	table_clk_vlt->entries[6].v = 6;
+	table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
+	table_clk_vlt->entries[7].v = 7;
+	hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
+
+	return 0;
+}
+
+static int cz_get_system_info_data(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)hwmgr->backend;
+	ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info = NULL;
+	uint32_t i;
+	int result = 0;
+	uint8_t frev, crev;
+	uint16_t size;
+
+	info = (ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *) cgs_atom_get_data_table(
+			hwmgr->device,
+			GetIndexIntoMasterTable(DATA, IntegratedSystemInfo),
+			&size, &frev, &crev);
+
+	if (crev != 9) {
+		printk(KERN_ERR "[ powerplay ] Unsupported IGP table: %d %d\n", frev, crev);
+		return -EINVAL;
+	}
+
+	if (info == NULL) {
+		printk(KERN_ERR "[ powerplay ] Could not retrieve the Integrated System Info Table!\n");
+		return -EINVAL;
+	}
+
+	cz_hwmgr->sys_info.bootup_uma_clock =
+				   le32_to_cpu(info->ulBootUpUMAClock);
+
+	cz_hwmgr->sys_info.bootup_engine_clock =
+				le32_to_cpu(info->ulBootUpEngineClock);
+
+	cz_hwmgr->sys_info.dentist_vco_freq =
+				   le32_to_cpu(info->ulDentistVCOFreq);
+
+	cz_hwmgr->sys_info.system_config =
+				     le32_to_cpu(info->ulSystemConfig);
+
+	cz_hwmgr->sys_info.bootup_nb_voltage_index =
+				  le16_to_cpu(info->usBootUpNBVoltage);
+
+	cz_hwmgr->sys_info.htc_hyst_lmt =
+			(info->ucHtcHystLmt == 0) ? 5 : info->ucHtcHystLmt;
+
+	cz_hwmgr->sys_info.htc_tmp_lmt =
+			(info->ucHtcTmpLmt == 0) ? 203 : info->ucHtcTmpLmt;
+
+	if (cz_hwmgr->sys_info.htc_tmp_lmt <=
+			cz_hwmgr->sys_info.htc_hyst_lmt) {
+		printk(KERN_ERR "[ powerplay ] The htcTmpLmt should be larger than htcHystLmt.\n");
+		return -EINVAL;
+	}
+
+	cz_hwmgr->sys_info.nb_dpm_enable =
+				cz_hwmgr->enable_nb_ps_policy &&
+				(le32_to_cpu(info->ulSystemConfig) >> 3 & 0x1);
+
+	for (i = 0; i < CZ_NUM_NBPSTATES; i++) {
+		if (i < CZ_NUM_NBPMEMORYCLOCK) {
+			cz_hwmgr->sys_info.nbp_memory_clock[i] =
+			  le32_to_cpu(info->ulNbpStateMemclkFreq[i]);
+		}
+		cz_hwmgr->sys_info.nbp_n_clock[i] =
+			    le32_to_cpu(info->ulNbpStateNClkFreq[i]);
+	}
+
+	for (i = 0; i < MAX_DISPLAY_CLOCK_LEVEL; i++) {
+		cz_hwmgr->sys_info.display_clock[i] =
+					le32_to_cpu(info->sDispClkVoltageMapping[i].ulMaximumSupportedCLK);
+	}
+
+	/* Here use 4 levels, make sure not exceed */
+	for (i = 0; i < CZ_NUM_NBPSTATES; i++) {
+		cz_hwmgr->sys_info.nbp_voltage_index[i] =
+			     le16_to_cpu(info->usNBPStateVoltage[i]);
+	}
+
+	if (!cz_hwmgr->sys_info.nb_dpm_enable) {
+		for (i = 1; i < CZ_NUM_NBPSTATES; i++) {
+			if (i < CZ_NUM_NBPMEMORYCLOCK) {
+				cz_hwmgr->sys_info.nbp_memory_clock[i] =
+				    cz_hwmgr->sys_info.nbp_memory_clock[0];
+			}
+			cz_hwmgr->sys_info.nbp_n_clock[i] =
+				    cz_hwmgr->sys_info.nbp_n_clock[0];
+			cz_hwmgr->sys_info.nbp_voltage_index[i] =
+				    cz_hwmgr->sys_info.nbp_voltage_index[0];
+		}
+	}
+
+	if (le32_to_cpu(info->ulGPUCapInfo) &
+		SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) {
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				    PHM_PlatformCaps_EnableDFSBypass);
+	}
+
+	cz_hwmgr->sys_info.uma_channel_number = info->ucUMAChannelNumber;
+
+	cz_construct_max_power_limits_table (hwmgr,
+				    &hwmgr->dyn_state.max_clock_voltage_on_ac);
+
+	cz_init_dynamic_state_adjustment_rule_settings(hwmgr,
+				    &info->sDISPCLK_Voltage[0]);
+
+	return result;
+}
+
+static int cz_construct_boot_state(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	cz_hwmgr->boot_power_level.engineClock =
+				cz_hwmgr->sys_info.bootup_engine_clock;
+
+	cz_hwmgr->boot_power_level.vddcIndex =
+			(uint8_t)cz_hwmgr->sys_info.bootup_nb_voltage_index;
+
+	cz_hwmgr->boot_power_level.dsDividerIndex = 0;
+
+	cz_hwmgr->boot_power_level.ssDividerIndex = 0;
+
+	cz_hwmgr->boot_power_level.allowGnbSlow = 1;
+
+	cz_hwmgr->boot_power_level.forceNBPstate = 0;
+
+	cz_hwmgr->boot_power_level.hysteresis_up = 0;
+
+	cz_hwmgr->boot_power_level.numSIMDToPowerDown = 0;
+
+	cz_hwmgr->boot_power_level.display_wm = 0;
+
+	cz_hwmgr->boot_power_level.vce_wm = 0;
+
+	return 0;
+}
+
+static int cz_tf_reset_active_process_mask(struct pp_hwmgr *hwmgr, void *input,
+					void *output, void *storage, int result)
+{
+	return 0;
+}
+
+static int cz_tf_upload_pptable_to_smu(struct pp_hwmgr *hwmgr, void *input,
+				       void *output, void *storage, int result)
+{
+	struct SMU8_Fusion_ClkTable *clock_table;
+	int ret;
+	uint32_t i;
+	void *table = NULL;
+	pp_atomctrl_clock_dividers_kong dividers;
+
+	struct phm_clock_voltage_dependency_table *vddc_table =
+		hwmgr->dyn_state.vddc_dependency_on_sclk;
+	struct phm_clock_voltage_dependency_table *vdd_gfx_table =
+		hwmgr->dyn_state.vdd_gfx_dependency_on_sclk;
+	struct phm_acp_clock_voltage_dependency_table *acp_table =
+		hwmgr->dyn_state.acp_clock_voltage_dependency_table;
+	struct phm_uvd_clock_voltage_dependency_table *uvd_table =
+		hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+	struct phm_vce_clock_voltage_dependency_table *vce_table =
+		hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+	if (!hwmgr->need_pp_table_upload)
+		return 0;
+
+	ret = smum_download_powerplay_table(hwmgr->smumgr, &table);
+
+	PP_ASSERT_WITH_CODE((0 == ret && NULL != table),
+			    "Fail to get clock table from SMU!", return -EINVAL;);
+
+	clock_table = (struct SMU8_Fusion_ClkTable *)table;
+
+	/* patch clock table */
+	PP_ASSERT_WITH_CODE((vddc_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+			    "Dependency table entry exceeds max limit!", return -EINVAL;);
+	PP_ASSERT_WITH_CODE((vdd_gfx_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+			    "Dependency table entry exceeds max limit!", return -EINVAL;);
+	PP_ASSERT_WITH_CODE((acp_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+			    "Dependency table entry exceeds max limit!", return -EINVAL;);
+	PP_ASSERT_WITH_CODE((uvd_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+			    "Dependency table entry exceeds max limit!", return -EINVAL;);
+	PP_ASSERT_WITH_CODE((vce_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+			    "Dependency table entry exceeds max limit!", return -EINVAL;);
+
+	for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++) {
+
+		/* vddc_sclk */
+		clock_table->SclkBreakdownTable.ClkLevel[i].GnbVid =
+			(i < vddc_table->count) ? (uint8_t)vddc_table->entries[i].v : 0;
+		clock_table->SclkBreakdownTable.ClkLevel[i].Frequency =
+			(i < vddc_table->count) ? vddc_table->entries[i].clk : 0;
+
+		atomctrl_get_engine_pll_dividers_kong(hwmgr,
+						      clock_table->SclkBreakdownTable.ClkLevel[i].Frequency,
+						      &dividers);
+
+		clock_table->SclkBreakdownTable.ClkLevel[i].DfsDid =
+			(uint8_t)dividers.pll_post_divider;
+
+		/* vddgfx_sclk */
+		clock_table->SclkBreakdownTable.ClkLevel[i].GfxVid =
+			(i < vdd_gfx_table->count) ? (uint8_t)vdd_gfx_table->entries[i].v : 0;
+
+		/* acp breakdown */
+		clock_table->AclkBreakdownTable.ClkLevel[i].GfxVid =
+			(i < acp_table->count) ? (uint8_t)acp_table->entries[i].v : 0;
+		clock_table->AclkBreakdownTable.ClkLevel[i].Frequency =
+			(i < acp_table->count) ? acp_table->entries[i].acpclk : 0;
+
+		atomctrl_get_engine_pll_dividers_kong(hwmgr,
+						      clock_table->AclkBreakdownTable.ClkLevel[i].Frequency,
+						      &dividers);
+
+		clock_table->AclkBreakdownTable.ClkLevel[i].DfsDid =
+			(uint8_t)dividers.pll_post_divider;
+
+
+		/* uvd breakdown */
+		clock_table->VclkBreakdownTable.ClkLevel[i].GfxVid =
+			(i < uvd_table->count) ? (uint8_t)uvd_table->entries[i].v : 0;
+		clock_table->VclkBreakdownTable.ClkLevel[i].Frequency =
+			(i < uvd_table->count) ? uvd_table->entries[i].vclk : 0;
+
+		atomctrl_get_engine_pll_dividers_kong(hwmgr,
+						      clock_table->VclkBreakdownTable.ClkLevel[i].Frequency,
+						      &dividers);
+
+		clock_table->VclkBreakdownTable.ClkLevel[i].DfsDid =
+			(uint8_t)dividers.pll_post_divider;
+
+		clock_table->DclkBreakdownTable.ClkLevel[i].GfxVid =
+			(i < uvd_table->count) ? (uint8_t)uvd_table->entries[i].v : 0;
+		clock_table->DclkBreakdownTable.ClkLevel[i].Frequency =
+			(i < uvd_table->count) ? uvd_table->entries[i].dclk : 0;
+
+		atomctrl_get_engine_pll_dividers_kong(hwmgr,
+						      clock_table->DclkBreakdownTable.ClkLevel[i].Frequency,
+						      &dividers);
+
+		clock_table->DclkBreakdownTable.ClkLevel[i].DfsDid =
+			(uint8_t)dividers.pll_post_divider;
+
+		/* vce breakdown */
+		clock_table->EclkBreakdownTable.ClkLevel[i].GfxVid =
+			(i < vce_table->count) ? (uint8_t)vce_table->entries[i].v : 0;
+		clock_table->EclkBreakdownTable.ClkLevel[i].Frequency =
+			(i < vce_table->count) ? vce_table->entries[i].ecclk : 0;
+
+
+		atomctrl_get_engine_pll_dividers_kong(hwmgr,
+						      clock_table->EclkBreakdownTable.ClkLevel[i].Frequency,
+						      &dividers);
+
+		clock_table->EclkBreakdownTable.ClkLevel[i].DfsDid =
+			(uint8_t)dividers.pll_post_divider;
+
+	}
+	ret = smum_upload_powerplay_table(hwmgr->smumgr);
+
+	return ret;
+}
+
+static int cz_tf_init_sclk_limit(struct pp_hwmgr *hwmgr, void *input,
+				 void *output, void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct phm_clock_voltage_dependency_table *table =
+					hwmgr->dyn_state.vddc_dependency_on_sclk;
+	unsigned long clock = 0, level;
+
+	if (NULL == table || table->count <= 0)
+		return -EINVAL;
+
+	cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
+	cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk;
+
+	level = cz_get_max_sclk_level(hwmgr) - 1;
+
+	if (level < table->count)
+		clock = table->entries[level].clk;
+	else
+		clock = table->entries[table->count - 1].clk;
+
+	cz_hwmgr->sclk_dpm.soft_max_clk = clock;
+	cz_hwmgr->sclk_dpm.hard_max_clk = clock;
+
+	return 0;
+}
+
+static int cz_tf_init_uvd_limit(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct phm_uvd_clock_voltage_dependency_table *table =
+				hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+	unsigned long clock = 0, level;
+
+	if (NULL == table || table->count <= 0)
+		return -EINVAL;
+
+	cz_hwmgr->uvd_dpm.soft_min_clk = 0;
+	cz_hwmgr->uvd_dpm.hard_min_clk = 0;
+
+	smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxUvdLevel);
+	level = smum_get_argument(hwmgr->smumgr);
+
+	if (level < table->count)
+		clock = table->entries[level].vclk;
+	else
+		clock = table->entries[table->count - 1].vclk;
+
+	cz_hwmgr->uvd_dpm.soft_max_clk = clock;
+	cz_hwmgr->uvd_dpm.hard_max_clk = clock;
+
+	return 0;
+}
+
+static int cz_tf_init_vce_limit(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct phm_vce_clock_voltage_dependency_table *table =
+				hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+	unsigned long clock = 0, level;
+
+	if (NULL == table || table->count <= 0)
+		return -EINVAL;
+
+	cz_hwmgr->vce_dpm.soft_min_clk = 0;
+	cz_hwmgr->vce_dpm.hard_min_clk = 0;
+
+	smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxEclkLevel);
+	level = smum_get_argument(hwmgr->smumgr);
+
+	if (level < table->count)
+		clock = table->entries[level].ecclk;
+	else
+		clock = table->entries[table->count - 1].ecclk;
+
+	cz_hwmgr->vce_dpm.soft_max_clk = clock;
+	cz_hwmgr->vce_dpm.hard_max_clk = clock;
+
+	return 0;
+}
+
+static int cz_tf_init_acp_limit(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct phm_acp_clock_voltage_dependency_table *table =
+				hwmgr->dyn_state.acp_clock_voltage_dependency_table;
+	unsigned long clock = 0, level;
+
+	if (NULL == table || table->count <= 0)
+		return -EINVAL;
+
+	cz_hwmgr->acp_dpm.soft_min_clk = 0;
+	cz_hwmgr->acp_dpm.hard_min_clk = 0;
+
+	smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxAclkLevel);
+	level = smum_get_argument(hwmgr->smumgr);
+
+	if (level < table->count)
+		clock = table->entries[level].acpclk;
+	else
+		clock = table->entries[table->count - 1].acpclk;
+
+	cz_hwmgr->acp_dpm.soft_max_clk = clock;
+	cz_hwmgr->acp_dpm.hard_max_clk = clock;
+	return 0;
+}
+
+static int cz_tf_init_power_gate_state(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	cz_hwmgr->uvd_power_gated = false;
+	cz_hwmgr->vce_power_gated = false;
+	cz_hwmgr->samu_power_gated = false;
+	cz_hwmgr->acp_power_gated = false;
+	cz_hwmgr->pgacpinit = true;
+
+	return 0;
+}
+
+static int cz_tf_init_sclk_threshold(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	cz_hwmgr->low_sclk_interrupt_threshold = 0;
+
+	return 0;
+}
+static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct phm_clock_voltage_dependency_table *table =
+					hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+	unsigned long clock = 0;
+	unsigned long level;
+	unsigned long stable_pstate_sclk;
+	struct PP_Clocks clocks;
+	unsigned long percentage;
+
+	cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
+	level = cz_get_max_sclk_level(hwmgr) - 1;
+
+	if (level < table->count)
+		cz_hwmgr->sclk_dpm.soft_max_clk  = table->entries[level].clk;
+	else
+		cz_hwmgr->sclk_dpm.soft_max_clk  = table->entries[table->count - 1].clk;
+
+	/*PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks);*/
+	clock = clocks.engineClock;
+
+	if (cz_hwmgr->sclk_dpm.hard_min_clk != clock) {
+		cz_hwmgr->sclk_dpm.hard_min_clk = clock;
+
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_SetSclkHardMin,
+						 cz_get_sclk_level(hwmgr,
+					cz_hwmgr->sclk_dpm.hard_min_clk,
+					     PPSMC_MSG_SetSclkHardMin));
+	}
+
+	clock = cz_hwmgr->sclk_dpm.soft_min_clk;
+
+	/* update minimum clocks for Stable P-State feature */
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				     PHM_PlatformCaps_StablePState)) {
+		percentage = 75;
+		/*Sclk - calculate sclk value based on percentage and find FLOOR sclk from VddcDependencyOnSCLK table  */
+		stable_pstate_sclk = (hwmgr->dyn_state.max_clock_voltage_on_ac.mclk *
+					percentage) / 100;
+
+		if (clock < stable_pstate_sclk)
+			clock = stable_pstate_sclk;
+	} else {
+		if (clock < hwmgr->gfx_arbiter.sclk)
+			clock = hwmgr->gfx_arbiter.sclk;
+	}
+
+	if (cz_hwmgr->sclk_dpm.soft_min_clk != clock) {
+		cz_hwmgr->sclk_dpm.soft_min_clk = clock;
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_SetSclkSoftMin,
+						cz_get_sclk_level(hwmgr,
+					cz_hwmgr->sclk_dpm.soft_min_clk,
+					     PPSMC_MSG_SetSclkSoftMin));
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				    PHM_PlatformCaps_StablePState) &&
+			 cz_hwmgr->sclk_dpm.soft_max_clk != clock) {
+		cz_hwmgr->sclk_dpm.soft_max_clk = clock;
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_SetSclkSoftMax,
+						cz_get_sclk_level(hwmgr,
+					cz_hwmgr->sclk_dpm.soft_max_clk,
+					PPSMC_MSG_SetSclkSoftMax));
+	}
+
+	return 0;
+}
+
+static int cz_tf_set_deep_sleep_sclk_threshold(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_SclkDeepSleep)) {
+		uint32_t clks = hwmgr->display_config.min_core_set_clock_in_sr;
+		if (clks == 0)
+			clks = CZ_MIN_DEEP_SLEEP_SCLK;
+
+		PP_DBG_LOG("Setting Deep Sleep Clock: %d\n", clks);
+
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetMinDeepSleepSclk,
+				clks);
+	}
+
+	return 0;
+}
+
+static int cz_tf_set_watermark_threshold(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr =
+				  (struct cz_hwmgr *)(hwmgr->backend);
+
+	smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_SetWatermarkFrequency,
+				      cz_hwmgr->sclk_dpm.soft_max_clk);
+
+	return 0;
+}
+
+static int cz_tf_set_enabled_levels(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	return 0;
+}
+
+
+static int cz_tf_enable_nb_dpm(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	int ret = 0;
+
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	unsigned long dpm_features = 0;
+
+	if (!cz_hwmgr->is_nb_dpm_enabled) {
+		PP_DBG_LOG("enabling ALL SMU features.\n");
+		dpm_features |= NB_DPM_MASK;
+		ret = smum_send_msg_to_smc_with_parameter(
+							     hwmgr->smumgr,
+					 PPSMC_MSG_EnableAllSmuFeatures,
+							     dpm_features);
+		if (ret == 0)
+			cz_hwmgr->is_nb_dpm_enabled = true;
+	}
+
+	return ret;
+}
+
+static int cz_nbdpm_pstate_enable_disable(struct pp_hwmgr *hwmgr, bool enable, bool lock)
+{
+	struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+
+	if (hw_data->is_nb_dpm_enabled) {
+		if (enable) {
+			PP_DBG_LOG("enable Low Memory PState.\n");
+
+			return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_EnableLowMemoryPstate,
+						(lock ? 1 : 0));
+		} else {
+			PP_DBG_LOG("disable Low Memory PState.\n");
+
+			return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_DisableLowMemoryPstate,
+						(lock ? 1 : 0));
+		}
+	}
+
+	return 0;
+}
+
+static int cz_tf_update_low_mem_pstate(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	bool disable_switch;
+	bool enable_low_mem_state;
+	struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+	const struct phm_set_power_state_input *states = (struct phm_set_power_state_input *)input;
+	const struct cz_power_state *pnew_state = cast_const_PhwCzPowerState(states->pnew_state);
+
+	if (hw_data->sys_info.nb_dpm_enable) {
+		disable_switch = hw_data->cc6_settings.nb_pstate_switch_disable ? true : false;
+		enable_low_mem_state = hw_data->cc6_settings.nb_pstate_switch_disable ? false : true;
+
+		if (pnew_state->action == FORCE_HIGH)
+			cz_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch);
+		else if(pnew_state->action == CANCEL_FORCE_HIGH)
+			cz_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch);
+		else 
+			cz_nbdpm_pstate_enable_disable(hwmgr, enable_low_mem_state, disable_switch);
+	}
+	return 0;
+}
+
+static struct phm_master_table_item cz_set_power_state_list[] = {
+	{NULL, cz_tf_update_sclk_limit},
+	{NULL, cz_tf_set_deep_sleep_sclk_threshold},
+	{NULL, cz_tf_set_watermark_threshold},
+	{NULL, cz_tf_set_enabled_levels},
+	{NULL, cz_tf_enable_nb_dpm},
+	{NULL, cz_tf_update_low_mem_pstate},
+	{NULL, NULL}
+};
+
+static struct phm_master_table_header cz_set_power_state_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	cz_set_power_state_list
+};
+
+static struct phm_master_table_item cz_setup_asic_list[] = {
+	{NULL, cz_tf_reset_active_process_mask},
+	{NULL, cz_tf_upload_pptable_to_smu},
+	{NULL, cz_tf_init_sclk_limit},
+	{NULL, cz_tf_init_uvd_limit},
+	{NULL, cz_tf_init_vce_limit},
+	{NULL, cz_tf_init_acp_limit},
+	{NULL, cz_tf_init_power_gate_state},
+	{NULL, cz_tf_init_sclk_threshold},
+	{NULL, NULL}
+};
+
+static struct phm_master_table_header cz_setup_asic_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	cz_setup_asic_list
+};
+
+static int cz_tf_power_up_display_clock_sys_pll(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+	hw_data->disp_clk_bypass_pending = false;
+	hw_data->disp_clk_bypass = false;
+
+	return 0;
+}
+
+static int cz_tf_clear_nb_dpm_flag(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+	hw_data->is_nb_dpm_enabled = false;
+
+	return 0;
+}
+
+static int cz_tf_reset_cc6_data(struct pp_hwmgr *hwmgr,
+					void *input, void *output,
+					void *storage, int result)
+{
+	struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+
+	hw_data->cc6_settings.cc6_setting_changed = false;
+	hw_data->cc6_settings.cpu_pstate_separation_time = 0;
+	hw_data->cc6_settings.cpu_cc6_disable = false;
+	hw_data->cc6_settings.cpu_pstate_disable = false;
+
+	return 0;
+}
+
+static struct phm_master_table_item cz_power_down_asic_list[] = {
+	{NULL, cz_tf_power_up_display_clock_sys_pll},
+	{NULL, cz_tf_clear_nb_dpm_flag},
+	{NULL, cz_tf_reset_cc6_data},
+	{NULL, NULL}
+};
+
+static struct phm_master_table_header cz_power_down_asic_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	cz_power_down_asic_list
+};
+
+static int cz_tf_program_voting_clients(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	PHMCZ_WRITE_SMC_REGISTER(hwmgr->device, CG_FREQ_TRAN_VOTING_0,
+				PPCZ_VOTINGRIGHTSCLIENTS_DFLT0);
+	return 0;
+}
+
+static int cz_tf_start_dpm(struct pp_hwmgr *hwmgr, void *input, void *output,
+			   void *storage, int result)
+{
+	int res = 0xff;
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	unsigned long dpm_features = 0;
+
+	cz_hwmgr->dpm_flags |= DPMFlags_SCLK_Enabled;
+	dpm_features |= SCLK_DPM_MASK;
+
+	res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_EnableAllSmuFeatures,
+				dpm_features);
+
+	return res;
+}
+
+static int cz_tf_program_bootup_state(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	cz_hwmgr->sclk_dpm.soft_min_clk = cz_hwmgr->sys_info.bootup_engine_clock;
+	cz_hwmgr->sclk_dpm.soft_max_clk = cz_hwmgr->sys_info.bootup_engine_clock;
+
+	smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetSclkSoftMin,
+				cz_get_sclk_level(hwmgr,
+				cz_hwmgr->sclk_dpm.soft_min_clk,
+				PPSMC_MSG_SetSclkSoftMin));
+
+	smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetSclkSoftMax,
+				cz_get_sclk_level(hwmgr,
+				cz_hwmgr->sclk_dpm.soft_max_clk,
+				PPSMC_MSG_SetSclkSoftMax));
+
+	return 0;
+}
+
+int cz_tf_reset_acp_boot_level(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	cz_hwmgr->acp_boot_level = 0xff;
+	return 0;
+}
+
+static bool cz_dpm_check_smu_features(struct pp_hwmgr *hwmgr,
+				unsigned long check_feature)
+{
+	int result;
+	unsigned long features;
+
+	result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_GetFeatureStatus, 0);
+	if (result == 0) {
+		features = smum_get_argument(hwmgr->smumgr);
+		if (features & check_feature)
+			return true;
+	}
+
+	return result;
+}
+
+static int cz_tf_check_for_dpm_disabled(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	if (cz_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn))
+		return PP_Result_TableImmediateExit;
+	return 0;
+}
+
+static int cz_tf_enable_didt(struct pp_hwmgr *hwmgr, void *input,
+				void *output, void *storage, int result)
+{
+	/* TO DO */
+	return 0;
+}
+
+static int cz_tf_check_for_dpm_enabled(struct pp_hwmgr *hwmgr,
+						void *input, void *output,
+						void *storage, int result)
+{
+	if (!cz_dpm_check_smu_features(hwmgr,
+			     SMU_EnabledFeatureScoreboard_SclkDpmOn))
+		return PP_Result_TableImmediateExit;
+	return 0;
+}
+
+static struct phm_master_table_item cz_disable_dpm_list[] = {
+	{ NULL, cz_tf_check_for_dpm_enabled},
+	{NULL, NULL},
+};
+
+
+static struct phm_master_table_header cz_disable_dpm_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	cz_disable_dpm_list
+};
+
+static struct phm_master_table_item cz_enable_dpm_list[] = {
+	{ NULL, cz_tf_check_for_dpm_disabled },
+	{ NULL, cz_tf_program_voting_clients },
+	{ NULL, cz_tf_start_dpm},
+	{ NULL, cz_tf_program_bootup_state},
+	{ NULL, cz_tf_enable_didt },
+	{ NULL, cz_tf_reset_acp_boot_level },
+	{NULL, NULL},
+};
+
+static struct phm_master_table_header cz_enable_dpm_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	cz_enable_dpm_list
+};
+
+static int cz_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+				struct pp_power_state  *prequest_ps,
+			const struct pp_power_state *pcurrent_ps)
+{
+	struct cz_power_state *cz_ps =
+				cast_PhwCzPowerState(&prequest_ps->hardware);
+
+	const struct cz_power_state *cz_current_ps =
+				cast_const_PhwCzPowerState(&pcurrent_ps->hardware);
+
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct PP_Clocks clocks;
+	bool force_high;
+	unsigned long  num_of_active_displays = 4;
+
+	cz_ps->evclk = hwmgr->vce_arbiter.evclk;
+	cz_ps->ecclk = hwmgr->vce_arbiter.ecclk;
+
+	cz_ps->need_dfs_bypass = true;
+
+	cz_hwmgr->video_start = (hwmgr->uvd_arbiter.vclk != 0 || hwmgr->uvd_arbiter.dclk != 0 ||
+				hwmgr->vce_arbiter.evclk != 0 || hwmgr->vce_arbiter.ecclk != 0);
+
+	cz_hwmgr->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
+
+	/* to do PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks); */
+	/* PECI_GetNumberOfActiveDisplays(pHwMgr->pPECI, &numOfActiveDisplays); */
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
+		clocks.memoryClock = hwmgr->dyn_state.max_clock_voltage_on_ac.mclk;
+	else
+		clocks.memoryClock = 0;
+
+	if (clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
+		clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
+
+	force_high = (clocks.memoryClock > cz_hwmgr->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK - 1])
+			|| (num_of_active_displays >= 3);
+
+	cz_ps->action = cz_current_ps->action;
+
+	if ((force_high == false) && (cz_ps->action == FORCE_HIGH))
+		cz_ps->action = CANCEL_FORCE_HIGH;
+	else if ((force_high == true) && (cz_ps->action != FORCE_HIGH))
+		cz_ps->action = FORCE_HIGH;
+	else
+		cz_ps->action = DO_NOTHING;
+
+	return 0;
+}
+
+static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
+{
+	int result = 0;
+
+	result = cz_initialize_dpm_defaults(hwmgr);
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] cz_initialize_dpm_defaults failed\n");
+		return result;
+	}
+
+	result = cz_get_system_info_data(hwmgr);
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] cz_get_system_info_data failed\n");
+		return result;
+	}
+
+	cz_construct_boot_state(hwmgr);
+
+	result = phm_construct_table(hwmgr, &cz_setup_asic_master,
+				&(hwmgr->setup_asic));
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] Fail to construct setup ASIC\n");
+		return result;
+	}
+
+	result = phm_construct_table(hwmgr, &cz_power_down_asic_master,
+				&(hwmgr->power_down_asic));
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] Fail to construct power down ASIC\n");
+		return result;
+	}
+
+	result = phm_construct_table(hwmgr, &cz_disable_dpm_master,
+				&(hwmgr->disable_dynamic_state_management));
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] Fail to disable_dynamic_state\n");
+		return result;
+	}
+	result = phm_construct_table(hwmgr, &cz_enable_dpm_master,
+				&(hwmgr->enable_dynamic_state_management));
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] Fail to enable_dynamic_state\n");
+		return result;
+	}
+	result = phm_construct_table(hwmgr, &cz_set_power_state_master,
+				&(hwmgr->set_power_state));
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] Fail to construct set_power_state\n");
+		return result;
+	}
+
+	result = phm_construct_table(hwmgr, &cz_phm_enable_clock_power_gatings_master, &(hwmgr->enable_clock_power_gatings));
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] Fail to construct enable_clock_power_gatings\n");
+		return result;
+	}
+	return result;
+}
+
+static int cz_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
+{
+	if (hwmgr != NULL || hwmgr->backend != NULL) {
+		kfree(hwmgr->backend);
+		kfree(hwmgr);
+	}
+	return 0;
+}
+
+int cz_phm_force_dpm_highest(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	if (cz_hwmgr->sclk_dpm.soft_min_clk !=
+				cz_hwmgr->sclk_dpm.soft_max_clk)
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_SetSclkSoftMin,
+						cz_get_sclk_level(hwmgr,
+						cz_hwmgr->sclk_dpm.soft_max_clk,
+						PPSMC_MSG_SetSclkSoftMin));
+	return 0;
+}
+
+int cz_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct phm_clock_voltage_dependency_table *table =
+				hwmgr->dyn_state.vddc_dependency_on_sclk;
+	unsigned long clock = 0, level;
+
+	if (NULL == table || table->count <= 0)
+		return -EINVAL;
+
+	cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
+	cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk;
+
+	level = cz_get_max_sclk_level(hwmgr) - 1;
+
+	if (level < table->count)
+		clock = table->entries[level].clk;
+	else
+		clock = table->entries[table->count - 1].clk;
+
+	cz_hwmgr->sclk_dpm.soft_max_clk = clock;
+	cz_hwmgr->sclk_dpm.hard_max_clk = clock;
+
+	smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetSclkSoftMin,
+				cz_get_sclk_level(hwmgr,
+				cz_hwmgr->sclk_dpm.soft_min_clk,
+				PPSMC_MSG_SetSclkSoftMin));
+
+	smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetSclkSoftMax,
+				cz_get_sclk_level(hwmgr,
+				cz_hwmgr->sclk_dpm.soft_max_clk,
+				PPSMC_MSG_SetSclkSoftMax));
+
+	return 0;
+}
+
+int cz_phm_force_dpm_lowest(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	if (cz_hwmgr->sclk_dpm.soft_min_clk !=
+				cz_hwmgr->sclk_dpm.soft_max_clk) {
+		cz_hwmgr->sclk_dpm.soft_max_clk =
+			cz_hwmgr->sclk_dpm.soft_min_clk;
+
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetSclkSoftMax,
+				cz_get_sclk_level(hwmgr,
+				cz_hwmgr->sclk_dpm.soft_max_clk,
+				PPSMC_MSG_SetSclkSoftMax));
+	}
+
+	return 0;
+}
+
+static int cz_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
+				enum amd_dpm_forced_level level)
+{
+	int ret = 0;
+
+	switch (level) {
+	case AMD_DPM_FORCED_LEVEL_HIGH:
+		ret = cz_phm_force_dpm_highest(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	case AMD_DPM_FORCED_LEVEL_LOW:
+		ret = cz_phm_force_dpm_lowest(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	case AMD_DPM_FORCED_LEVEL_AUTO:
+		ret = cz_phm_unforce_dpm_levels(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	default:
+		break;
+	}
+
+	hwmgr->dpm_level = level;
+
+	return ret;
+}
+
+int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					 PHM_PlatformCaps_UVDPowerGating))
+		return smum_send_msg_to_smc(hwmgr->smumgr,
+						     PPSMC_MSG_UVDPowerOFF);
+	return 0;
+}
+
+int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					 PHM_PlatformCaps_UVDPowerGating)) {
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				  PHM_PlatformCaps_UVDDynamicPowerGating)) {
+			return smum_send_msg_to_smc_with_parameter(
+								hwmgr->smumgr,
+						   PPSMC_MSG_UVDPowerON, 1);
+		} else {
+			return smum_send_msg_to_smc_with_parameter(
+								hwmgr->smumgr,
+						   PPSMC_MSG_UVDPowerON, 0);
+		}
+	}
+
+	return 0;
+}
+
+int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct phm_uvd_clock_voltage_dependency_table *ptable =
+		hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+
+	if (!bgate) {
+		/* Stable Pstate is enabled and we need to set the UVD DPM to highest level */
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					 PHM_PlatformCaps_StablePState)) {
+			cz_hwmgr->uvd_dpm.hard_min_clk =
+				   ptable->entries[ptable->count - 1].vclk;
+
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						     PPSMC_MSG_SetUvdHardMin,
+						      cz_get_uvd_level(hwmgr,
+					     cz_hwmgr->uvd_dpm.hard_min_clk,
+						   PPSMC_MSG_SetUvdHardMin));
+
+			cz_enable_disable_uvd_dpm(hwmgr, true);
+		} else
+			cz_enable_disable_uvd_dpm(hwmgr, true);
+	} else
+		cz_enable_disable_uvd_dpm(hwmgr, false);
+
+	return 0;
+}
+
+int  cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct phm_vce_clock_voltage_dependency_table *ptable =
+		hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+	/* Stable Pstate is enabled and we need to set the VCE DPM to highest level */
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					 PHM_PlatformCaps_StablePState)) {
+		cz_hwmgr->vce_dpm.hard_min_clk =
+				  ptable->entries[ptable->count - 1].ecclk;
+
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_SetEclkHardMin,
+					cz_get_eclk_level(hwmgr,
+					     cz_hwmgr->vce_dpm.hard_min_clk,
+						PPSMC_MSG_SetEclkHardMin));
+	} else {
+		/*EPR# 419220 -HW limitation to to */
+		cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk;
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					    PPSMC_MSG_SetEclkHardMin,
+					    cz_get_eclk_level(hwmgr,
+				     cz_hwmgr->vce_dpm.hard_min_clk,
+					  PPSMC_MSG_SetEclkHardMin));
+
+	}
+	return 0;
+}
+
+int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					 PHM_PlatformCaps_VCEPowerGating))
+		return smum_send_msg_to_smc(hwmgr->smumgr,
+						     PPSMC_MSG_VCEPowerOFF);
+	return 0;
+}
+
+int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					 PHM_PlatformCaps_VCEPowerGating))
+		return smum_send_msg_to_smc(hwmgr->smumgr,
+						     PPSMC_MSG_VCEPowerON);
+	return 0;
+}
+
+static int cz_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	return cz_hwmgr->sys_info.bootup_uma_clock;
+}
+
+static int cz_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
+{
+	struct pp_power_state  *ps;
+	struct cz_power_state  *cz_ps;
+
+	if (hwmgr == NULL)
+		return -EINVAL;
+
+	ps = hwmgr->request_ps;
+
+	if (ps == NULL)
+		return -EINVAL;
+
+	cz_ps = cast_PhwCzPowerState(&ps->hardware);
+
+	if (low)
+		return cz_ps->levels[0].engineClock;
+	else
+		return cz_ps->levels[cz_ps->level-1].engineClock;
+}
+
+static int cz_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
+					struct pp_hw_power_state *hw_ps)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct cz_power_state *cz_ps = cast_PhwCzPowerState(hw_ps);
+
+	cz_ps->level = 1;
+	cz_ps->nbps_flags = 0;
+	cz_ps->bapm_flags = 0;
+	cz_ps->levels[0] = cz_hwmgr->boot_power_level;
+
+	return 0;
+}
+
+static int cz_dpm_get_pp_table_entry_callback(
+						     struct pp_hwmgr *hwmgr,
+					   struct pp_hw_power_state *hw_ps,
+							  unsigned int index,
+						     const void *clock_info)
+{
+	struct cz_power_state *cz_ps = cast_PhwCzPowerState(hw_ps);
+
+	const ATOM_PPLIB_CZ_CLOCK_INFO *cz_clock_info = clock_info;
+
+	struct phm_clock_voltage_dependency_table *table =
+				    hwmgr->dyn_state.vddc_dependency_on_sclk;
+	uint8_t clock_info_index = cz_clock_info->index;
+
+	if (clock_info_index > (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1))
+		clock_info_index = (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1);
+
+	cz_ps->levels[index].engineClock = table->entries[clock_info_index].clk;
+	cz_ps->levels[index].vddcIndex = (uint8_t)table->entries[clock_info_index].v;
+
+	cz_ps->level = index + 1;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
+		cz_ps->levels[index].dsDividerIndex = 5;
+		cz_ps->levels[index].ssDividerIndex = 5;
+	}
+
+	return 0;
+}
+
+static int cz_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr)
+{
+	int result;
+	unsigned long ret = 0;
+
+	result = pp_tables_get_num_of_entries(hwmgr, &ret);
+
+	return result ? 0 : ret;
+}
+
+static int cz_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr,
+		    unsigned long entry, struct pp_power_state *ps)
+{
+	int result;
+	struct cz_power_state *cz_ps;
+
+	ps->hardware.magic = PhwCz_Magic;
+
+	cz_ps = cast_PhwCzPowerState(&(ps->hardware));
+
+	result = pp_tables_get_entry(hwmgr, entry, ps,
+			cz_dpm_get_pp_table_entry_callback);
+
+	cz_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK;
+	cz_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK;
+
+	return result;
+}
+
+int cz_get_power_state_size(struct pp_hwmgr *hwmgr)
+{
+	return sizeof(struct cz_power_state);
+}
+
+static void
+cz_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
+{
+	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+	struct phm_clock_voltage_dependency_table *table =
+				hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+	struct phm_vce_clock_voltage_dependency_table *vce_table =
+		hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+	struct phm_uvd_clock_voltage_dependency_table *uvd_table =
+		hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+
+	uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
+					TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
+	uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+					TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
+	uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+					TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
+
+	uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;
+	uint16_t vddnb, vddgfx;
+	int result;
+
+	if (sclk_index >= NUM_SCLK_LEVELS) {
+		seq_printf(m, "\n invalid sclk dpm profile %d\n", sclk_index);
+	} else {
+		sclk = table->entries[sclk_index].clk;
+		seq_printf(m, "\n index: %u sclk: %u MHz\n", sclk_index, sclk/100);
+	}
+
+	tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
+		CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
+	vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);
+	tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
+		CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
+	vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);
+	seq_printf(m, "\n vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
+
+	seq_printf(m, "\n uvd    %sabled\n", cz_hwmgr->uvd_power_gated ? "dis" : "en");
+	if (!cz_hwmgr->uvd_power_gated) {
+		if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+			seq_printf(m, "\n invalid uvd dpm level %d\n", uvd_index);
+		} else {
+			vclk = uvd_table->entries[uvd_index].vclk;
+			dclk = uvd_table->entries[uvd_index].dclk;
+			seq_printf(m, "\n index: %u uvd vclk: %u MHz dclk: %u MHz\n", uvd_index, vclk/100, dclk/100);
+		}
+	}
+
+	seq_printf(m, "\n vce    %sabled\n", cz_hwmgr->vce_power_gated ? "dis" : "en");
+	if (!cz_hwmgr->vce_power_gated) {
+		if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+			seq_printf(m, "\n invalid vce dpm level %d\n", vce_index);
+		} else {
+			ecclk = vce_table->entries[vce_index].ecclk;
+			seq_printf(m, "\n index: %u vce ecclk: %u MHz\n", vce_index, ecclk/100);
+		}
+	}
+
+	result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetAverageGraphicsActivity);
+	if (0 == result) {
+		activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);
+		activity_percent = activity_percent > 100 ? 100 : activity_percent;
+	} else {
+		activity_percent = 50;
+	}
+
+	seq_printf(m, "\n [GPU load]: %u %%\n\n", activity_percent);
+}
+
+static void cz_hw_print_display_cfg(
+	const struct cc6_settings *cc6_settings)
+{
+	PP_DBG_LOG("New Display Configuration:\n");
+
+	PP_DBG_LOG("   cpu_cc6_disable: %d\n",
+			cc6_settings->cpu_cc6_disable);
+	PP_DBG_LOG("   cpu_pstate_disable: %d\n",
+			cc6_settings->cpu_pstate_disable);
+	PP_DBG_LOG("   nb_pstate_switch_disable: %d\n",
+			cc6_settings->nb_pstate_switch_disable);
+	PP_DBG_LOG("   cpu_pstate_separation_time: %d\n\n",
+			cc6_settings->cpu_pstate_separation_time);
+}
+
+ static int cz_set_cpu_power_state(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+	uint32_t data = 0;
+
+	if (hw_data->cc6_settings.cc6_setting_changed == true) {
+
+		hw_data->cc6_settings.cc6_setting_changed = false;
+
+		cz_hw_print_display_cfg(&hw_data->cc6_settings);
+
+		data |= (hw_data->cc6_settings.cpu_pstate_separation_time
+			& PWRMGT_SEPARATION_TIME_MASK)
+			<< PWRMGT_SEPARATION_TIME_SHIFT;
+
+		data|= (hw_data->cc6_settings.cpu_cc6_disable ? 0x1 : 0x0)
+			<< PWRMGT_DISABLE_CPU_CSTATES_SHIFT;
+
+		data|= (hw_data->cc6_settings.cpu_pstate_disable ? 0x1 : 0x0)
+			<< PWRMGT_DISABLE_CPU_PSTATES_SHIFT;
+
+		PP_DBG_LOG("SetDisplaySizePowerParams data: 0x%X\n",
+			data);
+
+		smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_SetDisplaySizePowerParams,
+						data);
+	}
+
+	return 0;
+}
+
+
+ static int cz_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time,
+			bool cc6_disable, bool pstate_disable, bool pstate_switch_disable)
+ {
+	struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+
+	if (separation_time !=
+		hw_data->cc6_settings.cpu_pstate_separation_time
+		|| cc6_disable !=
+		hw_data->cc6_settings.cpu_cc6_disable
+		|| pstate_disable !=
+		hw_data->cc6_settings.cpu_pstate_disable
+		|| pstate_switch_disable !=
+		hw_data->cc6_settings.nb_pstate_switch_disable) {
+
+		hw_data->cc6_settings.cc6_setting_changed = true;
+
+		hw_data->cc6_settings.cpu_pstate_separation_time =
+			separation_time;
+		hw_data->cc6_settings.cpu_cc6_disable =
+			cc6_disable;
+		hw_data->cc6_settings.cpu_pstate_disable =
+			pstate_disable;
+		hw_data->cc6_settings.nb_pstate_switch_disable =
+			pstate_switch_disable;
+
+	}
+
+	return 0;
+}
+
+ static int cz_get_dal_power_level(struct pp_hwmgr *hwmgr,
+		struct amd_pp_dal_clock_info*info)
+{
+	uint32_t i;
+	const struct phm_clock_voltage_dependency_table * table =
+			hwmgr->dyn_state.vddc_dep_on_dal_pwrl;
+	const struct phm_clock_and_voltage_limits* limits =
+			&hwmgr->dyn_state.max_clock_voltage_on_ac;
+
+	info->engine_max_clock = limits->sclk;
+	info->memory_max_clock = limits->mclk;
+
+	for (i = table->count - 1; i > 0; i--) {
+
+		if (limits->vddc >= table->entries[i].v) {
+			info->level = table->entries[i].clk;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static const struct pp_hwmgr_func cz_hwmgr_funcs = {
+	.backend_init = cz_hwmgr_backend_init,
+	.backend_fini = cz_hwmgr_backend_fini,
+	.asic_setup = NULL,
+	.apply_state_adjust_rules = cz_apply_state_adjust_rules,
+	.force_dpm_level = cz_dpm_force_dpm_level,
+	.get_power_state_size = cz_get_power_state_size,
+	.powerdown_uvd = cz_dpm_powerdown_uvd,
+	.powergate_uvd = cz_dpm_powergate_uvd,
+	.powergate_vce = cz_dpm_powergate_vce,
+	.get_mclk = cz_dpm_get_mclk,
+	.get_sclk = cz_dpm_get_sclk,
+	.patch_boot_state = cz_dpm_patch_boot_state,
+	.get_pp_table_entry = cz_dpm_get_pp_table_entry,
+	.get_num_of_pp_table_entries = cz_dpm_get_num_of_pp_table_entries,
+	.print_current_perforce_level = cz_print_current_perforce_level,
+	.set_cpu_power_state = cz_set_cpu_power_state,
+	.store_cc6_data = cz_store_cc6_data,
+	.get_dal_power_level= cz_get_dal_power_level,
+};
+
+int cz_hwmgr_init(struct pp_hwmgr *hwmgr)
+{
+	struct cz_hwmgr *cz_hwmgr;
+	int ret = 0;
+
+	cz_hwmgr = kzalloc(sizeof(struct cz_hwmgr), GFP_KERNEL);
+	if (cz_hwmgr == NULL)
+		return -ENOMEM;
+
+	hwmgr->backend = cz_hwmgr;
+	hwmgr->hwmgr_func = &cz_hwmgr_funcs;
+	hwmgr->pptable_func = &pptable_funcs;
+	return ret;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _CZ_HWMGR_H_
+#define _CZ_HWMGR_H_
+
+#include "cgs_common.h"
+#include "ppatomctrl.h"
+
+#define CZ_NUM_NBPSTATES               4
+#define CZ_NUM_NBPMEMORYCLOCK          2
+#define MAX_DISPLAY_CLOCK_LEVEL        8
+#define CZ_AT_DFLT                     30
+#define CZ_MAX_HARDWARE_POWERLEVELS    8
+#define PPCZ_VOTINGRIGHTSCLIENTS_DFLT0   0x3FFFC102
+#define CZ_MIN_DEEP_SLEEP_SCLK         800
+
+/* Carrizo device IDs */
+#define DEVICE_ID_CZ_9870             0x9870
+#define DEVICE_ID_CZ_9874             0x9874
+#define DEVICE_ID_CZ_9875             0x9875
+#define DEVICE_ID_CZ_9876             0x9876
+#define DEVICE_ID_CZ_9877             0x9877
+
+#define PHMCZ_WRITE_SMC_REGISTER(device, reg, value)                            \
+		cgs_write_ind_register(device, CGS_IND_REG__SMC, ix##reg, value)
+
+struct cz_dpm_entry {
+	uint32_t soft_min_clk;
+	uint32_t hard_min_clk;
+	uint32_t soft_max_clk;
+	uint32_t hard_max_clk;
+};
+
+struct cz_sys_info {
+	uint32_t bootup_uma_clock;
+	uint32_t bootup_engine_clock;
+	uint32_t dentist_vco_freq;
+	uint32_t nb_dpm_enable;
+	uint32_t nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK];
+	uint32_t nbp_n_clock[CZ_NUM_NBPSTATES];
+	uint16_t nbp_voltage_index[CZ_NUM_NBPSTATES];
+	uint32_t display_clock[MAX_DISPLAY_CLOCK_LEVEL];
+	uint16_t bootup_nb_voltage_index;
+	uint8_t htc_tmp_lmt;
+	uint8_t htc_hyst_lmt;
+	uint32_t system_config;
+	uint32_t uma_channel_number;
+};
+
+#define MAX_DISPLAYPHY_IDS			0x8
+#define DISPLAYPHY_LANEMASK			0xF
+#define UNKNOWN_TRANSMITTER_PHY_ID		(-1)
+
+#define DISPLAYPHY_PHYID_SHIFT			24
+#define DISPLAYPHY_LANESELECT_SHIFT		16
+
+#define DISPLAYPHY_RX_SELECT			0x1
+#define DISPLAYPHY_TX_SELECT			0x2
+#define DISPLAYPHY_CORE_SELECT			0x4
+
+#define DDI_POWERGATING_ARG(phyID, lanemask, rx, tx, core) \
+		(((uint32_t)(phyID))<<DISPLAYPHY_PHYID_SHIFT | \
+		((uint32_t)(lanemask))<<DISPLAYPHY_LANESELECT_SHIFT | \
+		((rx) ? DISPLAYPHY_RX_SELECT : 0) | \
+		((tx) ? DISPLAYPHY_TX_SELECT : 0) | \
+		((core) ? DISPLAYPHY_CORE_SELECT : 0))
+
+struct cz_display_phy_info_entry {
+	uint8_t phy_present;
+	uint8_t active_lane_mapping;
+	uint8_t display_config_type;
+	uint8_t active_number_of_lanes;
+};
+
+#define CZ_MAX_DISPLAYPHY_IDS			10
+
+struct cz_display_phy_info {
+	bool display_phy_access_initialized;
+	struct cz_display_phy_info_entry entries[CZ_MAX_DISPLAYPHY_IDS];
+};
+
+struct cz_power_level {
+	uint32_t engineClock;
+	uint8_t vddcIndex;
+	uint8_t dsDividerIndex;
+	uint8_t ssDividerIndex;
+	uint8_t allowGnbSlow;
+	uint8_t forceNBPstate;
+	uint8_t display_wm;
+	uint8_t vce_wm;
+	uint8_t numSIMDToPowerDown;
+	uint8_t hysteresis_up;
+	uint8_t rsv[3];
+};
+
+struct cz_uvd_clocks {
+	uint32_t vclk;
+	uint32_t dclk;
+	uint32_t vclk_low_divider;
+	uint32_t vclk_high_divider;
+	uint32_t dclk_low_divider;
+	uint32_t dclk_high_divider;
+};
+
+enum cz_pstate_previous_action {
+	DO_NOTHING = 1,
+	FORCE_HIGH,
+	CANCEL_FORCE_HIGH
+};
+
+struct pp_disable_nb_ps_flags {
+	union {
+		struct {
+			uint32_t entry : 1;
+			uint32_t display : 1;
+			uint32_t driver: 1;
+			uint32_t vce : 1;
+			uint32_t uvd : 1;
+			uint32_t acp : 1;
+			uint32_t reserved: 26;
+		} bits;
+		uint32_t u32All;
+	};
+};
+
+struct cz_power_state {
+	unsigned int magic;
+	uint32_t level;
+	struct cz_uvd_clocks uvd_clocks;
+	uint32_t evclk;
+	uint32_t ecclk;
+	uint32_t samclk;
+	uint32_t acpclk;
+	bool need_dfs_bypass;
+	uint32_t nbps_flags;
+	uint32_t bapm_flags;
+	uint8_t dpm_0_pg_nb_ps_low;
+	uint8_t dpm_0_pg_nb_ps_high;
+	uint8_t dpm_x_nb_ps_low;
+	uint8_t dpm_x_nb_ps_high;
+	enum cz_pstate_previous_action action;
+	struct cz_power_level levels[CZ_MAX_HARDWARE_POWERLEVELS];
+	struct pp_disable_nb_ps_flags disable_nb_ps_flag;
+};
+
+#define DPMFlags_SCLK_Enabled			0x00000001
+#define DPMFlags_UVD_Enabled			0x00000002
+#define DPMFlags_VCE_Enabled			0x00000004
+#define DPMFlags_ACP_Enabled			0x00000008
+#define DPMFlags_ForceHighestValid		0x40000000
+#define DPMFlags_Debug				0x80000000
+
+#define SMU_EnabledFeatureScoreboard_AcpDpmOn   0x00000001 /* bit 0 */
+#define SMU_EnabledFeatureScoreboard_SclkDpmOn    0x00200000
+#define SMU_EnabledFeatureScoreboard_UvdDpmOn   0x00800000 /* bit 23 */
+#define SMU_EnabledFeatureScoreboard_VceDpmOn   0x01000000 /* bit 24 */
+
+struct cc6_settings {
+	bool cc6_setting_changed;
+	bool nb_pstate_switch_disable;/* controls NB PState switch */
+	bool cpu_cc6_disable; /* controls CPU CState switch ( on or off) */
+	bool cpu_pstate_disable;
+	uint32_t cpu_pstate_separation_time;
+};
+
+struct cz_hwmgr {
+	uint32_t activity_target[CZ_MAX_HARDWARE_POWERLEVELS];
+	uint32_t dpm_interval;
+
+	uint32_t voltage_drop_threshold;
+
+	uint32_t voting_rights_clients;
+
+	uint32_t disable_driver_thermal_policy;
+
+	uint32_t static_screen_threshold;
+
+	uint32_t gfx_power_gating_threshold;
+
+	uint32_t activity_hysteresis;
+	uint32_t bootup_sclk_divider;
+	uint32_t gfx_ramp_step;
+	uint32_t gfx_ramp_delay; /* in micro-seconds */
+
+	uint32_t thermal_auto_throttling_treshold;
+
+	struct cz_sys_info sys_info;
+
+	struct cz_power_level boot_power_level;
+	struct cz_power_state *cz_current_ps;
+	struct cz_power_state *cz_requested_ps;
+
+	uint32_t mgcg_cgtt_local0;
+	uint32_t mgcg_cgtt_local1;
+
+	uint32_t tdr_clock; /* in 10khz unit */
+
+	uint32_t ddi_power_gating_disabled;
+	uint32_t disable_gfx_power_gating_in_uvd;
+	uint32_t disable_nb_ps3_in_battery;
+
+	uint32_t lock_nb_ps_in_uvd_play_back;
+
+	struct cz_display_phy_info display_phy_info;
+	uint32_t vce_slow_sclk_threshold; /* default 200mhz */
+	uint32_t dce_slow_sclk_threshold; /* default 300mhz */
+	uint32_t min_sclk_did;  /* minimum sclk divider */
+
+	bool disp_clk_bypass;
+	bool disp_clk_bypass_pending;
+	uint32_t bapm_enabled;
+	uint32_t clock_slow_down_freq;
+	uint32_t skip_clock_slow_down;
+	uint32_t enable_nb_ps_policy;
+	uint32_t voltage_drop_in_dce_power_gating;
+	uint32_t uvd_dpm_interval;
+	uint32_t override_dynamic_mgpg;
+	uint32_t lclk_deep_enabled;
+
+	uint32_t uvd_performance;
+
+	bool video_start;
+	bool battery_state;
+	uint32_t lowest_valid;
+	uint32_t highest_valid;
+	uint32_t high_voltage_threshold;
+	uint32_t is_nb_dpm_enabled;
+	struct cc6_settings cc6_settings;
+	uint32_t is_voltage_island_enabled;
+
+	bool pgacpinit;
+
+	uint8_t disp_config;
+
+	/* PowerTune */
+	uint32_t power_containment_features;
+	bool cac_enabled;
+	bool disable_uvd_power_tune_feature;
+	bool enable_ba_pm_feature;
+	bool enable_tdc_limit_feature;
+
+	uint32_t sram_end;
+	uint32_t dpm_table_start;
+	uint32_t soft_regs_start;
+
+	uint8_t uvd_level_count;
+	uint8_t vce_level_count;
+
+	uint8_t acp_level_count;
+	uint8_t samu_level_count;
+	uint32_t fps_high_threshold;
+	uint32_t fps_low_threshold;
+
+	uint32_t dpm_flags;
+	struct cz_dpm_entry sclk_dpm;
+	struct cz_dpm_entry uvd_dpm;
+	struct cz_dpm_entry vce_dpm;
+	struct cz_dpm_entry acp_dpm;
+
+	uint8_t uvd_boot_level;
+	uint8_t vce_boot_level;
+	uint8_t acp_boot_level;
+	uint8_t samu_boot_level;
+	uint8_t uvd_interval;
+	uint8_t vce_interval;
+	uint8_t acp_interval;
+	uint8_t samu_interval;
+
+	uint8_t graphics_interval;
+	uint8_t graphics_therm_throttle_enable;
+	uint8_t graphics_voltage_change_enable;
+
+	uint8_t graphics_clk_slow_enable;
+	uint8_t graphics_clk_slow_divider;
+
+	uint32_t display_cac;
+	uint32_t low_sclk_interrupt_threshold;
+
+	uint32_t dram_log_addr_h;
+	uint32_t dram_log_addr_l;
+	uint32_t dram_log_phy_addr_h;
+	uint32_t dram_log_phy_addr_l;
+	uint32_t dram_log_buff_size;
+
+	bool uvd_power_gated;
+	bool vce_power_gated;
+	bool samu_power_gated;
+	bool acp_power_gated;
+	bool acp_power_up_no_dsp;
+	uint32_t active_process_mask;
+
+	uint32_t max_sclk_level;
+	uint32_t num_of_clk_entries;
+};
+
+struct pp_hwmgr;
+
+int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
+int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr);
+int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr);
+int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr);
+int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr);
+int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int  cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr);
+#endif /* _CZ_HWMGR_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "hwmgr.h"
+#include "fiji_clockpowergating.h"
+#include "fiji_ppsmc.h"
+#include "fiji_hwmgr.h"
+
+int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	data->uvd_power_gated = false;
+	data->vce_power_gated = false;
+	data->samu_power_gated = false;
+	data->acp_power_gated = false;
+
+	return 0;
+}
+
+int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if (data->uvd_power_gated == bgate)
+		return 0;
+
+	data->uvd_power_gated = bgate;
+
+	if (bgate)
+		fiji_update_uvd_dpm(hwmgr, true);
+	else
+		fiji_update_uvd_dpm(hwmgr, false);
+
+	return 0;
+}
+
+int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_set_power_state_input states;
+	const struct pp_power_state  *pcurrent;
+	struct pp_power_state  *requested;
+
+	if (data->vce_power_gated == bgate)
+		return 0;
+
+	data->vce_power_gated = bgate;
+
+	pcurrent = hwmgr->current_ps;
+	requested = hwmgr->request_ps;
+
+	states.pcurrent_state = &(pcurrent->hardware);
+	states.pnew_state = &(requested->hardware);
+
+	fiji_update_vce_dpm(hwmgr, &states);
+	fiji_enable_disable_vce_dpm(hwmgr, !bgate);
+
+	return 0;
+}
+
+int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if (data->samu_power_gated == bgate)
+		return 0;
+
+	data->samu_power_gated = bgate;
+
+	if (bgate)
+		fiji_update_samu_dpm(hwmgr, true);
+	else
+		fiji_update_samu_dpm(hwmgr, false);
+
+	return 0;
+}
+
+int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if (data->acp_power_gated == bgate)
+		return 0;
+
+	data->acp_power_gated = bgate;
+
+	if (bgate)
+		fiji_update_acp_dpm(hwmgr, true);
+	else
+		fiji_update_acp_dpm(hwmgr, false);
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _FIJI_CLOCK_POWER_GATING_H_
+#define _FIJI_CLOCK_POWER_GATING_H_
+
+#include "fiji_hwmgr.h"
+#include "pp_asicblocks.h"
+
+extern int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
+extern int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
+extern int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
+extern int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
+extern int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
+#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef FIJI_DYN_DEFAULTS_H
+#define FIJI_DYN_DEFAULTS_H
+
+/** \file
+* Volcanic Islands Dynamic default parameters.
+*/
+
+enum FIJIdpm_TrendDetection
+{
+    FIJIAdpm_TrendDetection_AUTO,
+    FIJIAdpm_TrendDetection_UP,
+    FIJIAdpm_TrendDetection_DOWN
+};
+typedef enum FIJIdpm_TrendDetection FIJIdpm_TrendDetection;
+
+/* We need to fill in the default values!!!!!!!!!!!!!!!!!!!!!!! */
+
+/* Bit vector representing same fields as hardware register. */
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0    0x3FFFC102  /* CP_Gfx_busy ????
+                                                         * HDP_busy
+                                                         * IH_busy
+                                                         * UVD_busy
+                                                         * VCE_busy
+                                                         * ACP_busy
+                                                         * SAMU_busy
+                                                         * SDMA enabled */
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1    0x000400  /* FE_Gfx_busy  - Intended for primary usage.   Rest are for flexibility. ????
+                                                       * SH_Gfx_busy
+                                                       * RB_Gfx_busy
+                                                       * VCE_busy */
+
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2    0xC00080  /* SH_Gfx_busy - Intended for primary usage.   Rest are for flexibility.
+                                                       * FE_Gfx_busy
+                                                       * RB_Gfx_busy
+                                                       * ACP_busy */
+
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3    0xC00200  /* RB_Gfx_busy - Intended for primary usage.   Rest are for flexibility.
+                                                       * FE_Gfx_busy
+                                                       * SH_Gfx_busy
+                                                       * UVD_busy */
+
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4    0xC01680  /* UVD_busy
+                                                       * VCE_busy
+                                                       * ACP_busy
+                                                       * SAMU_busy */
+
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5    0xC00033  /* GFX, HDP */
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6    0xC00033  /* GFX, HDP */
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7    0x3FFFC000  /* GFX, HDP */
+
+
+/* thermal protection counter (units). */
+#define PPFIJI_THERMALPROTECTCOUNTER_DFLT            0x200 /* ~19us */
+
+/* static screen threshold unit */
+#define PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT    0
+
+/* static screen threshold */
+#define PPFIJI_STATICSCREENTHRESHOLD_DFLT        0x00C8
+
+/* gfx idle clock stop threshold */
+#define PPFIJI_GFXIDLECLOCKSTOPTHRESHOLD_DFLT        0x200 /* ~19us with static screen threshold unit of 0 */
+
+/* Fixed reference divider to use when building baby stepping tables. */
+#define PPFIJI_REFERENCEDIVIDER_DFLT                  4
+
+/* ULV voltage change delay time
+ * Used to be delay_vreg in N.I. split for S.I.
+ * Using N.I. delay_vreg value as default
+ * ReferenceClock = 2700
+ * VoltageResponseTime = 1000
+ * VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
+ */
+#define PPFIJI_ULVVOLTAGECHANGEDELAY_DFLT             1687
+
+#define PPFIJI_CGULVPARAMETER_DFLT			0x00040035
+#define PPFIJI_CGULVCONTROL_DFLT			0x00007450
+#define PPFIJI_TARGETACTIVITY_DFLT			30 /* 30%*/
+#define PPFIJI_MCLK_TARGETACTIVITY_DFLT		10 /* 10% */
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c
@@ -0,0 +1,5127 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include "linux/delay.h"
+
+#include "hwmgr.h"
+#include "fiji_smumgr.h"
+#include "atombios.h"
+#include "hardwaremanager.h"
+#include "ppatomctrl.h"
+#include "atombios.h"
+#include "cgs_common.h"
+#include "fiji_dyn_defaults.h"
+#include "fiji_powertune.h"
+#include "smu73.h"
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+#include "pppcielanes.h"
+#include "fiji_hwmgr.h"
+#include "tonga_processpptables.h"
+#include "tonga_pptable.h"
+#include "pp_debug.h"
+#include "pp_acpi.h"
+#include "amd_pcie_helpers.h"
+#include "cgs_linux.h"
+#include "ppinterrupt.h"
+
+#include "fiji_clockpowergating.h"
+#include "fiji_thermal.h"
+
+#define VOLTAGE_SCALE	4
+#define SMC_RAM_END		0x40000
+#define VDDC_VDDCI_DELTA	300
+
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+
+#define MC_CG_ARB_FREQ_F0           0x0a /* boot-up default */
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+/* From smc_reg.h */
+#define SMC_CG_IND_START            0xc0030000
+#define SMC_CG_IND_END              0xc0040000  /* First byte after SMC_CG_IND */
+
+#define VOLTAGE_SCALE               4
+#define VOLTAGE_VID_OFFSET_SCALE1   625
+#define VOLTAGE_VID_OFFSET_SCALE2   100
+
+#define VDDC_VDDCI_DELTA            300
+
+#define ixSWRST_COMMAND_1           0x1400103
+#define MC_SEQ_CNTL__CAC_EN_MASK    0x40000000
+
+/** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
+enum DPM_EVENT_SRC {
+    DPM_EVENT_SRC_ANALOG = 0,               /* Internal analog trip point */
+    DPM_EVENT_SRC_EXTERNAL = 1,             /* External (GPIO 17) signal */
+    DPM_EVENT_SRC_DIGITAL = 2,              /* Internal digital trip point (DIG_THERM_DPM) */
+    DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,   /* Internal analog or external */
+    DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4   /* Internal digital or external */
+};
+
+
+/* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
+ * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
+ */
+uint16_t fiji_clock_stretcher_lookup_table[2][4] = { {600, 1050, 3, 0},
+                                                {600, 1050, 6, 1} };
+
+/* [FF, SS] type, [] 4 voltage ranges, and
+ * [Floor Freq, Boundary Freq, VID min , VID max]
+ */
+uint32_t fiji_clock_stretcher_ddt_table[2][4][4] =
+{ { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
+  { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
+
+/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
+ * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
+ */
+uint8_t fiji_clock_stretch_amount_conversion[2][6] = { {0, 1, 3, 2, 4, 5},
+                                                  {0, 2, 4, 5, 6, 5} };
+
+const unsigned long PhwFiji_Magic = (unsigned long)(PHM_VIslands_Magic);
+
+struct fiji_power_state *cast_phw_fiji_power_state(
+				  struct pp_hw_power_state *hw_ps)
+{
+	PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
+				"Invalid Powerstate Type!",
+				 return NULL;);
+
+	return (struct fiji_power_state *)hw_ps;
+}
+
+const struct fiji_power_state *cast_const_phw_fiji_power_state(
+				 const struct pp_hw_power_state *hw_ps)
+{
+	PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
+				"Invalid Powerstate Type!",
+				 return NULL;);
+
+	return (const struct fiji_power_state *)hw_ps;
+}
+
+static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+	return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
+			CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
+			? true : false;
+}
+
+static void fiji_init_dpm_defaults(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_ulv_parm *ulv = &data->ulv;
+
+	ulv->cg_ulv_parameter = PPFIJI_CGULVPARAMETER_DFLT;
+	data->voting_rights_clients0 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0;
+	data->voting_rights_clients1 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1;
+	data->voting_rights_clients2 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2;
+	data->voting_rights_clients3 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3;
+	data->voting_rights_clients4 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4;
+	data->voting_rights_clients5 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5;
+	data->voting_rights_clients6 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6;
+	data->voting_rights_clients7 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7;
+
+	data->static_screen_threshold_unit =
+			PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT;
+	data->static_screen_threshold =
+			PPFIJI_STATICSCREENTHRESHOLD_DFLT;
+
+	/* Unset ABM cap as it moved to DAL.
+	 * Add PHM_PlatformCaps_NonABMSupportInPPLib
+	 * for re-direct ABM related request to DAL
+	 */
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ABM);
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_NonABMSupportInPPLib);
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_DynamicACTiming);
+
+	fiji_initialize_power_tune_defaults(hwmgr);
+
+	data->mclk_stutter_mode_threshold = 60000;
+	data->pcie_gen_performance.max = PP_PCIEGen1;
+	data->pcie_gen_performance.min = PP_PCIEGen3;
+	data->pcie_gen_power_saving.max = PP_PCIEGen1;
+	data->pcie_gen_power_saving.min = PP_PCIEGen3;
+	data->pcie_lane_performance.max = 0;
+	data->pcie_lane_performance.min = 16;
+	data->pcie_lane_power_saving.max = 0;
+	data->pcie_lane_power_saving.min = 16;
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_DynamicUVDState);
+}
+
+static int fiji_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
+	phm_ppt_v1_voltage_lookup_table *lookup_table,
+	uint16_t virtual_voltage_id, int32_t *sclk)
+{
+	uint8_t entryId;
+	uint8_t voltageId;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
+
+	/* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
+	for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
+		voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
+		if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
+			break;
+	}
+
+	PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
+			"Can't find requested voltage id in vdd_dep_on_sclk table!",
+			return -EINVAL;
+			);
+
+	*sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
+
+	return 0;
+}
+
+/**
+* Get Leakage VDDC based on leakage ID.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int fiji_get_evv_voltages(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint16_t    vv_id;
+	uint16_t    vddc = 0;
+	uint16_t    evv_default = 1150;
+	uint16_t    i, j;
+	uint32_t  sclk = 0;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)hwmgr->pptable;
+	struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+			table_info->vdd_dep_on_sclk;
+	int result;
+
+	for (i = 0; i < FIJI_MAX_LEAKAGE_COUNT; i++) {
+		vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
+		if (!fiji_get_sclk_for_voltage_evv(hwmgr,
+				table_info->vddc_lookup_table, vv_id, &sclk)) {
+			if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_ClockStretcher)) {
+				for (j = 1; j < sclk_table->count; j++) {
+					if (sclk_table->entries[j].clk == sclk &&
+							sclk_table->entries[j].cks_enable == 0) {
+						sclk += 5000;
+						break;
+					}
+				}
+			}
+
+			if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_EnableDriverEVV))
+				result = atomctrl_calculate_voltage_evv_on_sclk(hwmgr,
+						VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc, i, true);
+			else
+				result = -EINVAL;
+
+			if (result)
+				result = atomctrl_get_voltage_evv_on_sclk(hwmgr,
+						VOLTAGE_TYPE_VDDC, sclk,vv_id, &vddc);
+
+			/* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
+			PP_ASSERT_WITH_CODE((vddc < 2000),
+					"Invalid VDDC value, greater than 2v!", result = -EINVAL;);
+
+			if (result)
+				/* 1.15V is the default safe value for Fiji */
+				vddc = evv_default;
+
+			/* the voltage should not be zero nor equal to leakage ID */
+			if (vddc != 0 && vddc != vv_id) {
+				data->vddc_leakage.actual_voltage
+				[data->vddc_leakage.count] = vddc;
+				data->vddc_leakage.leakage_id
+				[data->vddc_leakage.count] = vv_id;
+				data->vddc_leakage.count++;
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ * Change virtual leakage voltage to actual value.
+ *
+ * @param     hwmgr  the address of the powerplay hardware manager.
+ * @param     pointer to changing voltage
+ * @param     pointer to leakage table
+ */
+static void fiji_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
+		uint16_t *voltage, struct fiji_leakage_voltage *leakage_table)
+{
+	uint32_t index;
+
+	/* search for leakage voltage ID 0xff01 ~ 0xff08 */
+	for (index = 0; index < leakage_table->count; index++) {
+		/* if this voltage matches a leakage voltage ID */
+		/* patch with actual leakage voltage */
+		if (leakage_table->leakage_id[index] == *voltage) {
+			*voltage = leakage_table->actual_voltage[index];
+			break;
+		}
+	}
+
+	if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
+		printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
+}
+
+/**
+* Patch voltage lookup table by EVV leakages.
+*
+* @param     hwmgr  the address of the powerplay hardware manager.
+* @param     pointer to voltage lookup table
+* @param     pointer to leakage table
+* @return     always 0
+*/
+static int fiji_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_voltage_lookup_table *lookup_table,
+		struct fiji_leakage_voltage *leakage_table)
+{
+	uint32_t i;
+
+	for (i = 0; i < lookup_table->count; i++)
+		fiji_patch_with_vdd_leakage(hwmgr,
+				&lookup_table->entries[i].us_vdd, leakage_table);
+
+	return 0;
+}
+
+static int fiji_patch_clock_voltage_limits_with_vddc_leakage(
+		struct pp_hwmgr *hwmgr, struct fiji_leakage_voltage *leakage_table,
+		uint16_t *vddc)
+{
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	fiji_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
+	hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
+			table_info->max_clock_voltage_on_dc.vddc;
+	return 0;
+}
+
+static int fiji_patch_voltage_dependency_tables_with_lookup_table(
+		struct pp_hwmgr *hwmgr)
+{
+	uint8_t entryId;
+	uint8_t voltageId;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+			table_info->vdd_dep_on_sclk;
+	struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
+			table_info->vdd_dep_on_mclk;
+	struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+			table_info->mm_dep_table;
+
+	for (entryId = 0; entryId < sclk_table->count; ++entryId) {
+		voltageId = sclk_table->entries[entryId].vddInd;
+		sclk_table->entries[entryId].vddc =
+				table_info->vddc_lookup_table->entries[voltageId].us_vdd;
+	}
+
+	for (entryId = 0; entryId < mclk_table->count; ++entryId) {
+		voltageId = mclk_table->entries[entryId].vddInd;
+		mclk_table->entries[entryId].vddc =
+			table_info->vddc_lookup_table->entries[voltageId].us_vdd;
+	}
+
+	for (entryId = 0; entryId < mm_table->count; ++entryId) {
+		voltageId = mm_table->entries[entryId].vddcInd;
+		mm_table->entries[entryId].vddc =
+			table_info->vddc_lookup_table->entries[voltageId].us_vdd;
+	}
+
+	return 0;
+
+}
+
+static int fiji_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+	/* Need to determine if we need calculated voltage. */
+	return 0;
+}
+
+static int fiji_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
+{
+	/* Need to determine if we need calculated voltage from mm table. */
+	return 0;
+}
+
+static int fiji_sort_lookup_table(struct pp_hwmgr *hwmgr,
+		struct phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+	uint32_t table_size, i, j;
+	struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
+	table_size = lookup_table->count;
+
+	PP_ASSERT_WITH_CODE(0 != lookup_table->count,
+		"Lookup table is empty", return -EINVAL);
+
+	/* Sorting voltages */
+	for (i = 0; i < table_size - 1; i++) {
+		for (j = i + 1; j > 0; j--) {
+			if (lookup_table->entries[j].us_vdd <
+					lookup_table->entries[j - 1].us_vdd) {
+				tmp_voltage_lookup_record = lookup_table->entries[j - 1];
+				lookup_table->entries[j - 1] = lookup_table->entries[j];
+				lookup_table->entries[j] = tmp_voltage_lookup_record;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int fiji_complete_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+	int result = 0;
+	int tmp_result;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	tmp_result = fiji_patch_lookup_table_with_leakage(hwmgr,
+			table_info->vddc_lookup_table, &(data->vddc_leakage));
+	if (tmp_result)
+		result = tmp_result;
+
+	tmp_result = fiji_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
+			&(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
+	if (tmp_result)
+		result = tmp_result;
+
+	tmp_result = fiji_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
+	if (tmp_result)
+		result = tmp_result;
+
+	tmp_result = fiji_calc_voltage_dependency_tables(hwmgr);
+	if (tmp_result)
+		result = tmp_result;
+
+	tmp_result = fiji_calc_mm_voltage_dependency_table(hwmgr);
+	if (tmp_result)
+		result = tmp_result;
+
+	tmp_result = fiji_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
+	if(tmp_result)
+		result = tmp_result;
+
+	return result;
+}
+
+static int fiji_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
+			table_info->vdd_dep_on_sclk;
+	struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
+			table_info->vdd_dep_on_mclk;
+
+	PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
+		"VDD dependency on SCLK table is missing. 	\
+		This table is mandatory", return -EINVAL);
+	PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
+		"VDD dependency on SCLK table has to have is missing. 	\
+		This table is mandatory", return -EINVAL);
+
+	PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
+		"VDD dependency on MCLK table is missing. 	\
+		This table is mandatory", return -EINVAL);
+	PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
+		"VDD dependency on MCLK table has to have is missing.	 \
+		This table is mandatory", return -EINVAL);
+
+	data->min_vddc_in_pptable = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
+	data->max_vddc_in_pptable =	(uint16_t)allowed_sclk_vdd_table->
+			entries[allowed_sclk_vdd_table->count - 1].vddc;
+
+	table_info->max_clock_voltage_on_ac.sclk =
+		allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
+	table_info->max_clock_voltage_on_ac.mclk =
+		allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
+	table_info->max_clock_voltage_on_ac.vddc =
+		allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
+	table_info->max_clock_voltage_on_ac.vddci =
+		allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
+
+	hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
+		table_info->max_clock_voltage_on_ac.sclk;
+	hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
+		table_info->max_clock_voltage_on_ac.mclk;
+	hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
+		table_info->max_clock_voltage_on_ac.vddc;
+	hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
+		table_info->max_clock_voltage_on_ac.vddci;
+
+	return 0;
+}
+
+static uint16_t fiji_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
+{
+	uint32_t speedCntl = 0;
+
+	/* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
+	speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
+			ixPCIE_LC_SPEED_CNTL);
+	return((uint16_t)PHM_GET_FIELD(speedCntl,
+			PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
+}
+
+static int fiji_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr)
+{
+	uint32_t link_width;
+
+	/* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
+	link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
+			PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD);
+
+	PP_ASSERT_WITH_CODE((7 >= link_width),
+			"Invalid PCIe lane width!", return 0);
+
+	return decode_pcie_lane_width(link_width);
+}
+
+/** Patch the Boot State to match VBIOS boot clocks and voltage.
+*
+* @param hwmgr Pointer to the hardware manager.
+* @param pPowerState The address of the PowerState instance being created.
+*
+*/
+static int fiji_patch_boot_state(struct pp_hwmgr *hwmgr,
+		struct pp_hw_power_state *hw_ps)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_power_state *ps = (struct fiji_power_state *)hw_ps;
+	ATOM_FIRMWARE_INFO_V2_2 *fw_info;
+	uint16_t size;
+	uint8_t frev, crev;
+	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+
+	/* First retrieve the Boot clocks and VDDC from the firmware info table.
+	 * We assume here that fw_info is unchanged if this call fails.
+	 */
+	fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
+			hwmgr->device, index,
+			&size, &frev, &crev);
+	if (!fw_info)
+		/* During a test, there is no firmware info table. */
+		return 0;
+
+	/* Patch the state. */
+	data->vbios_boot_state.sclk_bootup_value =
+			le32_to_cpu(fw_info->ulDefaultEngineClock);
+	data->vbios_boot_state.mclk_bootup_value =
+			le32_to_cpu(fw_info->ulDefaultMemoryClock);
+	data->vbios_boot_state.mvdd_bootup_value =
+			le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
+	data->vbios_boot_state.vddc_bootup_value =
+			le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+	data->vbios_boot_state.vddci_bootup_value =
+			le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
+	data->vbios_boot_state.pcie_gen_bootup_value =
+			fiji_get_current_pcie_speed(hwmgr);
+	data->vbios_boot_state.pcie_lane_bootup_value =
+			(uint16_t)fiji_get_current_pcie_lane_number(hwmgr);
+
+	/* set boot power state */
+	ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
+	ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
+	ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
+	ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
+
+	return 0;
+}
+
+static int fiji_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t i;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	bool stay_in_boot;
+	int result;
+
+	data->dll_default_on = false;
+	data->sram_end = SMC_RAM_END;
+
+	for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
+		data->activity_target[i] = FIJI_AT_DFLT;
+
+	data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
+
+	data->mclk_activity_target = PPFIJI_MCLK_TARGETACTIVITY_DFLT;
+	data->mclk_dpm0_activity_target = 0xa;
+
+	data->sclk_dpm_key_disabled = 0;
+	data->mclk_dpm_key_disabled = 0;
+	data->pcie_dpm_key_disabled = 0;
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_UnTabledHardwareInterface);
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_TablelessHardwareInterface);
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_SclkDeepSleep);
+
+	data->gpio_debug = 0;
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_DynamicPatchPowerState);
+
+	/* need to set voltage control types before EVV patching */
+	data->voltage_control = FIJI_VOLTAGE_CONTROL_NONE;
+	data->vddci_control = FIJI_VOLTAGE_CONTROL_NONE;
+	data->mvdd_control = FIJI_VOLTAGE_CONTROL_NONE;
+
+	if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+			VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
+		data->voltage_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_EnableMVDDControl))
+		if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+				VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
+			data->mvdd_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
+
+	if (data->mvdd_control == FIJI_VOLTAGE_CONTROL_NONE)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_EnableMVDDControl);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ControlVDDCI)) {
+		if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+				VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
+			data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
+		else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+				VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
+			data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
+	}
+
+	if (data->vddci_control == FIJI_VOLTAGE_CONTROL_NONE)
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_ControlVDDCI);
+
+	if (table_info && table_info->cac_dtp_table->usClockStretchAmount)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_ClockStretcher);
+
+	fiji_init_dpm_defaults(hwmgr);
+
+	/* Get leakage voltage based on leakage ID. */
+	fiji_get_evv_voltages(hwmgr);
+
+	/* Patch our voltage dependency table with actual leakage voltage
+	 * We need to perform leakage translation before it's used by other functions
+	 */
+	fiji_complete_dependency_tables(hwmgr);
+
+	/* Parse pptable data read from VBIOS */
+	fiji_set_private_data_based_on_pptable(hwmgr);
+
+	/* ULV Support */
+	data->ulv.ulv_supported = true; /* ULV feature is enabled by default */
+
+	/* Initalize Dynamic State Adjustment Rule Settings */
+	result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
+
+	if (!result) {
+		data->uvd_enabled = false;
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_EnableSMU7ThermalManagement);
+		data->vddc_phase_shed_control = false;
+	}
+
+	stay_in_boot = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_StayInBootState);
+
+	if (0 == result) {
+		struct cgs_system_info sys_info = {0};
+
+		data->is_tlu_enabled = 0;
+		hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
+				FIJI_MAX_HARDWARE_POWERLEVELS;
+		hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
+		hwmgr->platform_descriptor.minimumClocksReductionPercentage  = 50;
+
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_FanSpeedInTableIsRPM);
+
+		if (table_info->cac_dtp_table->usDefaultTargetOperatingTemp &&
+				hwmgr->thermal_controller.
+				advanceFanControlParameters.ucFanControlMode) {
+			hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM =
+					hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
+			hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
+					hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM;
+			hwmgr->dyn_state.cac_dtp_table->usOperatingTempMinLimit =
+					table_info->cac_dtp_table->usOperatingTempMinLimit;
+			hwmgr->dyn_state.cac_dtp_table->usOperatingTempMaxLimit =
+					table_info->cac_dtp_table->usOperatingTempMaxLimit;
+			hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
+					table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
+			hwmgr->dyn_state.cac_dtp_table->usOperatingTempStep =
+					table_info->cac_dtp_table->usOperatingTempStep;
+			hwmgr->dyn_state.cac_dtp_table->usTargetOperatingTemp =
+					table_info->cac_dtp_table->usTargetOperatingTemp;
+
+			phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_ODFuzzyFanControlSupport);
+		}
+
+		sys_info.size = sizeof(struct cgs_system_info);
+		sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
+		result = cgs_query_system_info(hwmgr->device, &sys_info);
+		if (result)
+			data->pcie_gen_cap = 0x30007;
+		else
+			data->pcie_gen_cap = (uint32_t)sys_info.value;
+		if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+			data->pcie_spc_cap = 20;
+		sys_info.size = sizeof(struct cgs_system_info);
+		sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
+		result = cgs_query_system_info(hwmgr->device, &sys_info);
+		if (result)
+			data->pcie_lane_cap = 0x2f0000;
+		else
+			data->pcie_lane_cap = (uint32_t)sys_info.value;
+	} else {
+		/* Ignore return value in here, we are cleaning up a mess. */
+		tonga_hwmgr_backend_fini(hwmgr);
+	}
+
+	return 0;
+}
+
+/**
+ * Read clock related registers.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+static int fiji_read_clock_registers(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	data->clock_registers.vCG_SPLL_FUNC_CNTL =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixCG_SPLL_FUNC_CNTL);
+	data->clock_registers.vCG_SPLL_FUNC_CNTL_2 =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixCG_SPLL_FUNC_CNTL_2);
+	data->clock_registers.vCG_SPLL_FUNC_CNTL_3 =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixCG_SPLL_FUNC_CNTL_3);
+	data->clock_registers.vCG_SPLL_FUNC_CNTL_4 =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixCG_SPLL_FUNC_CNTL_4);
+	data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixCG_SPLL_SPREAD_SPECTRUM);
+	data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixCG_SPLL_SPREAD_SPECTRUM_2);
+
+	return 0;
+}
+
+/**
+ * Find out if memory is GDDR5.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+static int fiji_get_memory_type(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t temp;
+
+	temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
+
+	data->is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
+			((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
+			 MC_SEQ_MISC0_GDDR5_SHIFT));
+
+	return 0;
+}
+
+/**
+ * Enables Dynamic Power Management by SMC
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+static int fiji_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
+{
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			GENERAL_PWRMGT, STATIC_PM_EN, 1);
+
+	return 0;
+}
+
+/**
+ * Initialize PowerGating States for different engines
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+static int fiji_init_power_gate_state(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	data->uvd_power_gated = false;
+	data->vce_power_gated = false;
+	data->samu_power_gated = false;
+	data->acp_power_gated = false;
+	data->pg_acp_init = true;
+
+	return 0;
+}
+
+static int fiji_init_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	data->low_sclk_interrupt_threshold = 0;
+
+	return 0;
+}
+
+static int fiji_setup_asic_task(struct pp_hwmgr *hwmgr)
+{
+	int tmp_result, result = 0;
+
+	tmp_result = fiji_read_clock_registers(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to read clock registers!", result = tmp_result);
+
+	tmp_result = fiji_get_memory_type(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to get memory type!", result = tmp_result);
+
+	tmp_result = fiji_enable_acpi_power_management(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable ACPI power management!", result = tmp_result);
+
+	tmp_result = fiji_init_power_gate_state(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to init power gate state!", result = tmp_result);
+
+	tmp_result = tonga_get_mc_microcode_version(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to get MC microcode version!", result = tmp_result);
+
+	tmp_result = fiji_init_sclk_threshold(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to init sclk threshold!", result = tmp_result);
+
+	return result;
+}
+
+/**
+* Checks if we want to support voltage control
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+*/
+static bool fiji_voltage_control(const struct pp_hwmgr *hwmgr)
+{
+	const struct fiji_hwmgr *data =
+			(const struct fiji_hwmgr *)(hwmgr->backend);
+
+	return (FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control);
+}
+
+/**
+* Enable voltage control
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int fiji_enable_voltage_control(struct pp_hwmgr *hwmgr)
+{
+	/* enable voltage control */
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
+
+	return 0;
+}
+
+/**
+* Remove repeated voltage values and create table with unique values.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    vol_table  the pointer to changing voltage table
+* @return    0 in success
+*/
+
+static int fiji_trim_voltage_table(struct pp_hwmgr *hwmgr,
+		struct pp_atomctrl_voltage_table *vol_table)
+{
+	uint32_t i, j;
+	uint16_t vvalue;
+	bool found = false;
+	struct pp_atomctrl_voltage_table *table;
+
+	PP_ASSERT_WITH_CODE((NULL != vol_table),
+			"Voltage Table empty.", return -EINVAL);
+	table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
+			GFP_KERNEL);
+
+	if (NULL == table)
+		return -ENOMEM;
+
+	table->mask_low = vol_table->mask_low;
+	table->phase_delay = vol_table->phase_delay;
+
+	for (i = 0; i < vol_table->count; i++) {
+		vvalue = vol_table->entries[i].value;
+		found = false;
+
+		for (j = 0; j < table->count; j++) {
+			if (vvalue == table->entries[j].value) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			table->entries[table->count].value = vvalue;
+			table->entries[table->count].smio_low =
+					vol_table->entries[i].smio_low;
+			table->count++;
+		}
+	}
+
+	memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
+	kfree(table);
+
+	return 0;
+}
+
+static int fiji_get_svi2_mvdd_voltage_table(struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_clock_voltage_dependency_table *dep_table)
+{
+	uint32_t i;
+	int result;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct pp_atomctrl_voltage_table *vol_table = &(data->mvdd_voltage_table);
+
+	PP_ASSERT_WITH_CODE((0 != dep_table->count),
+			"Voltage Dependency Table empty.", return -EINVAL);
+
+	vol_table->mask_low = 0;
+	vol_table->phase_delay = 0;
+	vol_table->count = dep_table->count;
+
+	for (i = 0; i < dep_table->count; i++) {
+		vol_table->entries[i].value = dep_table->entries[i].mvdd;
+		vol_table->entries[i].smio_low = 0;
+	}
+
+	result = fiji_trim_voltage_table(hwmgr, vol_table);
+	PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to trim MVDD table.", return result);
+
+	return 0;
+}
+
+static int fiji_get_svi2_vddci_voltage_table(struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_clock_voltage_dependency_table *dep_table)
+{
+	uint32_t i;
+	int result;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct pp_atomctrl_voltage_table *vol_table = &(data->vddci_voltage_table);
+
+	PP_ASSERT_WITH_CODE((0 != dep_table->count),
+			"Voltage Dependency Table empty.", return -EINVAL);
+
+	vol_table->mask_low = 0;
+	vol_table->phase_delay = 0;
+	vol_table->count = dep_table->count;
+
+	for (i = 0; i < dep_table->count; i++) {
+		vol_table->entries[i].value = dep_table->entries[i].vddci;
+		vol_table->entries[i].smio_low = 0;
+	}
+
+	result = fiji_trim_voltage_table(hwmgr, vol_table);
+	PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to trim VDDCI table.", return result);
+
+	return 0;
+}
+
+static int fiji_get_svi2_vdd_voltage_table(struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+	int i = 0;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct pp_atomctrl_voltage_table *vol_table = &(data->vddc_voltage_table);
+
+	PP_ASSERT_WITH_CODE((0 != lookup_table->count),
+			"Voltage Lookup Table empty.", return -EINVAL);
+
+	vol_table->mask_low = 0;
+	vol_table->phase_delay = 0;
+
+	vol_table->count = lookup_table->count;
+
+	for (i = 0; i < vol_table->count; i++) {
+		vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
+		vol_table->entries[i].smio_low = 0;
+	}
+
+	return 0;
+}
+
+/* ---- Voltage Tables ----
+ * If the voltage table would be bigger than
+ * what will fit into the state table on
+ * the SMC keep only the higher entries.
+ */
+static void fiji_trim_voltage_table_to_fit_state_table(struct pp_hwmgr *hwmgr,
+		uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table)
+{
+	unsigned int i, diff;
+
+	if (vol_table->count <= max_vol_steps)
+		return;
+
+	diff = vol_table->count - max_vol_steps;
+
+	for (i = 0; i < max_vol_steps; i++)
+		vol_table->entries[i] = vol_table->entries[i + diff];
+
+	vol_table->count = max_vol_steps;
+
+	return;
+}
+
+/**
+* Create Voltage Tables.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int fiji_construct_voltage_tables(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)hwmgr->pptable;
+	int result;
+
+	if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+		result = atomctrl_get_voltage_table_v3(hwmgr,
+				VOLTAGE_TYPE_MVDDC,	VOLTAGE_OBJ_GPIO_LUT,
+				&(data->mvdd_voltage_table));
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Failed to retrieve MVDD table.",
+				return result);
+	} else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
+		result = fiji_get_svi2_mvdd_voltage_table(hwmgr,
+				table_info->vdd_dep_on_mclk);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Failed to retrieve SVI2 MVDD table from dependancy table.",
+				return result;);
+	}
+
+	if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+		result = atomctrl_get_voltage_table_v3(hwmgr,
+				VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT,
+				&(data->vddci_voltage_table));
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Failed to retrieve VDDCI table.",
+				return result);
+	} else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+		result = fiji_get_svi2_vddci_voltage_table(hwmgr,
+				table_info->vdd_dep_on_mclk);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Failed to retrieve SVI2 VDDCI table from dependancy table.",
+				return result);
+	}
+
+	if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+		result = fiji_get_svi2_vdd_voltage_table(hwmgr,
+				table_info->vddc_lookup_table);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Failed to retrieve SVI2 VDDC table from lookup table.",
+				return result);
+	}
+
+	PP_ASSERT_WITH_CODE(
+			(data->vddc_voltage_table.count <= (SMU73_MAX_LEVELS_VDDC)),
+			"Too many voltage values for VDDC. Trimming to fit state table.",
+			fiji_trim_voltage_table_to_fit_state_table(hwmgr,
+					SMU73_MAX_LEVELS_VDDC, &(data->vddc_voltage_table)));
+
+	PP_ASSERT_WITH_CODE(
+			(data->vddci_voltage_table.count <= (SMU73_MAX_LEVELS_VDDCI)),
+			"Too many voltage values for VDDCI. Trimming to fit state table.",
+			fiji_trim_voltage_table_to_fit_state_table(hwmgr,
+					SMU73_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table)));
+
+	PP_ASSERT_WITH_CODE(
+			(data->mvdd_voltage_table.count <= (SMU73_MAX_LEVELS_MVDD)),
+			"Too many voltage values for MVDD. Trimming to fit state table.",
+			fiji_trim_voltage_table_to_fit_state_table(hwmgr,
+					SMU73_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table)));
+
+	return 0;
+}
+
+static int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+	/* Program additional LP registers
+	 * that are no longer programmed by VBIOS
+	 */
+	cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
+			cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
+			cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
+			cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
+			cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
+			cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
+			cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
+			cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
+
+	return 0;
+}
+
+/**
+* Programs static screed detection parameters
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int fiji_program_static_screen_threshold_parameters(
+		struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	/* Set static screen threshold unit */
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
+			data->static_screen_threshold_unit);
+	/* Set static screen threshold */
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
+			data->static_screen_threshold);
+
+	return 0;
+}
+
+/**
+* Setup display gap for glitch free memory clock switching.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always  0
+*/
+static int fiji_enable_display_gap(struct pp_hwmgr *hwmgr)
+{
+	uint32_t displayGap =
+			cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixCG_DISPLAY_GAP_CNTL);
+
+	displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
+			DISP_GAP, DISPLAY_GAP_IGNORE);
+
+	displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
+			DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_DISPLAY_GAP_CNTL, displayGap);
+
+	return 0;
+}
+
+/**
+* Programs activity state transition voting clients
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always  0
+*/
+static int fiji_program_voting_clients(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	/* Clear reset for voting clients before enabling DPM */
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
+
+	return 0;
+}
+
+/**
+* Get the location of various tables inside the FW image.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always  0
+*/
+static int fiji_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+	uint32_t tmp;
+	int result;
+	bool error = false;
+
+	result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION +
+			offsetof(SMU73_Firmware_Header, DpmTable),
+			&tmp, data->sram_end);
+
+	if (0 == result)
+		data->dpm_table_start = tmp;
+
+	error |= (0 != result);
+
+	result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION +
+			offsetof(SMU73_Firmware_Header, SoftRegisters),
+			&tmp, data->sram_end);
+
+	if (!result) {
+		data->soft_regs_start = tmp;
+		smu_data->soft_regs_start = tmp;
+	}
+
+	error |= (0 != result);
+
+	result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION +
+			offsetof(SMU73_Firmware_Header, mcRegisterTable),
+			&tmp, data->sram_end);
+
+	if (!result)
+		data->mc_reg_table_start = tmp;
+
+	result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION +
+			offsetof(SMU73_Firmware_Header, FanTable),
+			&tmp, data->sram_end);
+
+	if (!result)
+		data->fan_table_start = tmp;
+
+	error |= (0 != result);
+
+	result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION +
+			offsetof(SMU73_Firmware_Header, mcArbDramTimingTable),
+			&tmp, data->sram_end);
+
+	if (!result)
+		data->arb_table_start = tmp;
+
+	error |= (0 != result);
+
+	result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION +
+			offsetof(SMU73_Firmware_Header, Version),
+			&tmp, data->sram_end);
+
+	if (!result)
+		hwmgr->microcode_version_info.SMC = tmp;
+
+	error |= (0 != result);
+
+	return error ? -1 : 0;
+}
+
+/* Copy one arb setting to another and then switch the active set.
+ * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
+ */
+static int fiji_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
+		uint32_t arb_src, uint32_t arb_dest)
+{
+	uint32_t mc_arb_dram_timing;
+	uint32_t mc_arb_dram_timing2;
+	uint32_t burst_time;
+	uint32_t mc_cg_config;
+
+	switch (arb_src) {
+	case MC_CG_ARB_FREQ_F0:
+		mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+		mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+		burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+		break;
+	case MC_CG_ARB_FREQ_F1:
+		mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
+		mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
+		burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (arb_dest) {
+	case MC_CG_ARB_FREQ_F0:
+		cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+		cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+		PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
+		break;
+	case MC_CG_ARB_FREQ_F1:
+		cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+		cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+		PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
+	mc_cg_config |= 0x0000000F;
+	cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
+	PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest);
+
+	return 0;
+}
+
+/**
+* Initial switch from ARB F0->F1
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+* This function is to be called from the SetPowerState table.
+*/
+static int fiji_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
+{
+	return fiji_copy_and_switch_arb_sets(hwmgr,
+			MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+static int fiji_reset_single_dpm_table(struct pp_hwmgr *hwmgr,
+		struct fiji_single_dpm_table *dpm_table, uint32_t count)
+{
+	int i;
+	PP_ASSERT_WITH_CODE(count <= MAX_REGULAR_DPM_NUMBER,
+			"Fatal error, can not set up single DPM table entries "
+			"to exceed max number!",);
+
+	dpm_table->count = count;
+	for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
+		dpm_table->dpm_levels[i].enabled = false;
+
+	return 0;
+}
+
+static void fiji_setup_pcie_table_entry(
+	struct fiji_single_dpm_table *dpm_table,
+	uint32_t index, uint32_t pcie_gen,
+	uint32_t pcie_lanes)
+{
+	dpm_table->dpm_levels[index].value = pcie_gen;
+	dpm_table->dpm_levels[index].param1 = pcie_lanes;
+	dpm_table->dpm_levels[index].enabled = 1;
+}
+
+static int fiji_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
+	uint32_t i, max_entry;
+
+	PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels ||
+			data->use_pcie_power_saving_levels), "No pcie performance levels!",
+			return -EINVAL);
+
+	if (data->use_pcie_performance_levels &&
+			!data->use_pcie_power_saving_levels) {
+		data->pcie_gen_power_saving = data->pcie_gen_performance;
+		data->pcie_lane_power_saving = data->pcie_lane_performance;
+	} else if (!data->use_pcie_performance_levels &&
+			data->use_pcie_power_saving_levels) {
+		data->pcie_gen_performance = data->pcie_gen_power_saving;
+		data->pcie_lane_performance = data->pcie_lane_power_saving;
+	}
+
+	fiji_reset_single_dpm_table(hwmgr,
+			&data->dpm_table.pcie_speed_table, SMU73_MAX_LEVELS_LINK);
+
+	if (pcie_table != NULL) {
+		/* max_entry is used to make sure we reserve one PCIE level
+		 * for boot level (fix for A+A PSPP issue).
+		 * If PCIE table from PPTable have ULV entry + 8 entries,
+		 * then ignore the last entry.*/
+		max_entry = (SMU73_MAX_LEVELS_LINK < pcie_table->count) ?
+				SMU73_MAX_LEVELS_LINK : pcie_table->count;
+		for (i = 1; i < max_entry; i++) {
+			fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1,
+					get_pcie_gen_support(data->pcie_gen_cap,
+							pcie_table->entries[i].gen_speed),
+					get_pcie_lane_support(data->pcie_lane_cap,
+							pcie_table->entries[i].lane_width));
+		}
+		data->dpm_table.pcie_speed_table.count = max_entry - 1;
+	} else {
+		/* Hardcode Pcie Table */
+		fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
+				get_pcie_gen_support(data->pcie_gen_cap,
+						PP_Min_PCIEGen),
+				get_pcie_lane_support(data->pcie_lane_cap,
+						PP_Max_PCIELane));
+		fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
+				get_pcie_gen_support(data->pcie_gen_cap,
+						PP_Min_PCIEGen),
+				get_pcie_lane_support(data->pcie_lane_cap,
+						PP_Max_PCIELane));
+		fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
+				get_pcie_gen_support(data->pcie_gen_cap,
+						PP_Max_PCIEGen),
+				get_pcie_lane_support(data->pcie_lane_cap,
+						PP_Max_PCIELane));
+		fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
+				get_pcie_gen_support(data->pcie_gen_cap,
+						PP_Max_PCIEGen),
+				get_pcie_lane_support(data->pcie_lane_cap,
+						PP_Max_PCIELane));
+		fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
+				get_pcie_gen_support(data->pcie_gen_cap,
+						PP_Max_PCIEGen),
+				get_pcie_lane_support(data->pcie_lane_cap,
+						PP_Max_PCIELane));
+		fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
+				get_pcie_gen_support(data->pcie_gen_cap,
+						PP_Max_PCIEGen),
+				get_pcie_lane_support(data->pcie_lane_cap,
+						PP_Max_PCIELane));
+
+		data->dpm_table.pcie_speed_table.count = 6;
+	}
+	/* Populate last level for boot PCIE level, but do not increment count. */
+	fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
+			data->dpm_table.pcie_speed_table.count,
+			get_pcie_gen_support(data->pcie_gen_cap,
+					PP_Min_PCIEGen),
+			get_pcie_lane_support(data->pcie_lane_cap,
+					PP_Max_PCIELane));
+
+	return 0;
+}
+
+/*
+ * This function is to initalize all DPM state tables
+ * for SMU7 based on the dependency table.
+ * Dynamic state patching function will then trim these
+ * state tables to the allowed range based
+ * on the power policy or external client requests,
+ * such as UVD request, etc.
+ */
+static int fiji_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	uint32_t i;
+
+	struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table =
+			table_info->vdd_dep_on_sclk;
+	struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
+			table_info->vdd_dep_on_mclk;
+
+	PP_ASSERT_WITH_CODE(dep_sclk_table != NULL,
+			"SCLK dependency table is missing. This table is mandatory",
+			return -EINVAL);
+	PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1,
+			"SCLK dependency table has to have is missing. "
+			"This table is mandatory",
+			return -EINVAL);
+
+	PP_ASSERT_WITH_CODE(dep_mclk_table != NULL,
+			"MCLK dependency table is missing. This table is mandatory",
+			return -EINVAL);
+	PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
+			"MCLK dependency table has to have is missing. "
+			"This table is mandatory",
+			return -EINVAL);
+
+	/* clear the state table to reset everything to default */
+	fiji_reset_single_dpm_table(hwmgr,
+			&data->dpm_table.sclk_table, SMU73_MAX_LEVELS_GRAPHICS);
+	fiji_reset_single_dpm_table(hwmgr,
+			&data->dpm_table.mclk_table, SMU73_MAX_LEVELS_MEMORY);
+
+	/* Initialize Sclk DPM table based on allow Sclk values */
+	data->dpm_table.sclk_table.count = 0;
+	for (i = 0; i < dep_sclk_table->count; i++) {
+		if (i == 0 || data->dpm_table.sclk_table.dpm_levels
+				[data->dpm_table.sclk_table.count - 1].value !=
+						dep_sclk_table->entries[i].clk) {
+			data->dpm_table.sclk_table.dpm_levels
+			[data->dpm_table.sclk_table.count].value =
+					dep_sclk_table->entries[i].clk;
+			data->dpm_table.sclk_table.dpm_levels
+			[data->dpm_table.sclk_table.count].enabled =
+					(i == 0) ? true : false;
+			data->dpm_table.sclk_table.count++;
+		}
+	}
+
+	/* Initialize Mclk DPM table based on allow Mclk values */
+	data->dpm_table.mclk_table.count = 0;
+	for (i=0; i<dep_mclk_table->count; i++) {
+		if ( i==0 || data->dpm_table.mclk_table.dpm_levels
+				[data->dpm_table.mclk_table.count - 1].value !=
+						dep_mclk_table->entries[i].clk) {
+			data->dpm_table.mclk_table.dpm_levels
+			[data->dpm_table.mclk_table.count].value =
+					dep_mclk_table->entries[i].clk;
+			data->dpm_table.mclk_table.dpm_levels
+			[data->dpm_table.mclk_table.count].enabled =
+					(i == 0) ? true : false;
+			data->dpm_table.mclk_table.count++;
+		}
+	}
+
+	/* setup PCIE gen speed levels */
+	fiji_setup_default_pcie_table(hwmgr);
+
+	/* save a copy of the default DPM table */
+	memcpy(&(data->golden_dpm_table), &(data->dpm_table),
+			sizeof(struct fiji_dpm_table));
+
+	return 0;
+}
+
+/**
+ * @brief PhwFiji_GetVoltageOrder
+ *  Returns index of requested voltage record in lookup(table)
+ * @param lookup_table - lookup list to search in
+ * @param voltage - voltage to look for
+ * @return 0 on success
+ */
+uint8_t fiji_get_voltage_index(
+		struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
+{
+	uint8_t count = (uint8_t) (lookup_table->count);
+	uint8_t i;
+
+	PP_ASSERT_WITH_CODE((NULL != lookup_table),
+			"Lookup Table empty.", return 0);
+	PP_ASSERT_WITH_CODE((0 != count),
+			"Lookup Table empty.", return 0);
+
+	for (i = 0; i < lookup_table->count; i++) {
+		/* find first voltage equal or bigger than requested */
+		if (lookup_table->entries[i].us_vdd >= voltage)
+			return i;
+	}
+	/* voltage is bigger than max voltage in the table */
+	return i - 1;
+}
+
+/**
+* Preparation of vddc and vddgfx CAC tables for SMC.
+*
+* @param    hwmgr  the address of the hardware manager
+* @param    table  the SMC DPM table structure to be populated
+* @return   always 0
+*/
+static int fiji_populate_cac_table(struct pp_hwmgr *hwmgr,
+		struct SMU73_Discrete_DpmTable *table)
+{
+	uint32_t count;
+	uint8_t index;
+	int result = 0;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_voltage_lookup_table *lookup_table =
+			table_info->vddc_lookup_table;
+	/* tables is already swapped, so in order to use the value from it,
+	 * we need to swap it back.
+	 * We are populating vddc CAC data to BapmVddc table
+	 * in split and merged mode
+	 */
+	for( count = 0; count<lookup_table->count; count++) {
+		index = fiji_get_voltage_index(lookup_table,
+				data->vddc_voltage_table.entries[count].value);
+		table->BapmVddcVidLoSidd[count] = (uint8_t) ((6200 -
+				(lookup_table->entries[index].us_cac_low *
+						VOLTAGE_SCALE)) / 25);
+		table->BapmVddcVidHiSidd[count] = (uint8_t) ((6200 -
+				(lookup_table->entries[index].us_cac_high *
+						VOLTAGE_SCALE)) / 25);
+	}
+
+	return result;
+}
+
+/**
+* Preparation of voltage tables for SMC.
+*
+* @param    hwmgr   the address of the hardware manager
+* @param    table   the SMC DPM table structure to be populated
+* @return   always  0
+*/
+
+int fiji_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
+		struct SMU73_Discrete_DpmTable *table)
+{
+	int result;
+
+	result = fiji_populate_cac_table(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"can not populate CAC voltage tables to SMC",
+			return -EINVAL);
+
+	return 0;
+}
+
+static int fiji_populate_ulv_level(struct pp_hwmgr *hwmgr,
+		struct SMU73_Discrete_Ulv *state)
+{
+	int result = 0;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	state->CcPwrDynRm = 0;
+	state->CcPwrDynRm1 = 0;
+
+	state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
+	state->VddcOffsetVid = (uint8_t)( table_info->us_ulv_voltage_offset *
+			VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1 );
+
+	state->VddcPhase = (data->vddc_phase_shed_control) ? 0 : 1;
+
+	if (!result) {
+		CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
+		CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
+		CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
+	}
+	return result;
+}
+
+static int fiji_populate_ulv_state(struct pp_hwmgr *hwmgr,
+		struct SMU73_Discrete_DpmTable *table)
+{
+	return fiji_populate_ulv_level(hwmgr, &table->Ulv);
+}
+
+static int32_t fiji_get_dpm_level_enable_mask_value(
+		struct fiji_single_dpm_table* dpm_table)
+{
+	int32_t i;
+	int32_t mask = 0;
+
+	for (i = dpm_table->count; i > 0; i--) {
+		mask = mask << 1;
+		if (dpm_table->dpm_levels[i - 1].enabled)
+			mask |= 0x1;
+		else
+			mask &= 0xFFFFFFFE;
+	}
+	return mask;
+}
+
+static int fiji_populate_smc_link_level(struct pp_hwmgr *hwmgr,
+		struct SMU73_Discrete_DpmTable *table)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_dpm_table *dpm_table = &data->dpm_table;
+	int i;
+
+	/* Index (dpm_table->pcie_speed_table.count)
+	 * is reserved for PCIE boot level. */
+	for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
+		table->LinkLevel[i].PcieGenSpeed  =
+				(uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
+		table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
+				dpm_table->pcie_speed_table.dpm_levels[i].param1);
+		table->LinkLevel[i].EnabledForActivity = 1;
+		table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
+		table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
+		table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
+	}
+
+	data->smc_state_table.LinkLevelCount =
+			(uint8_t)dpm_table->pcie_speed_table.count;
+	data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+			fiji_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+
+	return 0;
+}
+
+/**
+* Calculates the SCLK dividers using the provided engine clock
+*
+* @param    hwmgr  the address of the hardware manager
+* @param    clock  the engine clock to use to populate the structure
+* @param    sclk   the SMC SCLK structure to be populated
+*/
+static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr,
+		uint32_t clock, struct SMU73_Discrete_GraphicsLevel *sclk)
+{
+	const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct pp_atomctrl_clock_dividers_vi dividers;
+	uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+	uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+	uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+	uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+	uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+	uint32_t ref_clock;
+	uint32_t ref_divider;
+	uint32_t fbdiv;
+	int result;
+
+	/* get the engine clock dividers for this clock value */
+	result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock,  &dividers);
+
+	PP_ASSERT_WITH_CODE(result == 0,
+			"Error retrieving Engine Clock dividers from VBIOS.",
+			return result);
+
+	/* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
+	ref_clock = atomctrl_get_reference_clock(hwmgr);
+	ref_divider = 1 + dividers.uc_pll_ref_div;
+
+	/* low 14 bits is fraction and high 12 bits is divider */
+	fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
+
+	/* SPLL_FUNC_CNTL setup */
+	spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+			SPLL_REF_DIV, dividers.uc_pll_ref_div);
+	spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+			SPLL_PDIV_A,  dividers.uc_pll_post_div);
+
+	/* SPLL_FUNC_CNTL_3 setup*/
+	spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
+			SPLL_FB_DIV, fbdiv);
+
+	/* set to use fractional accumulation*/
+	spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
+			SPLL_DITHEN, 1);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
+		struct pp_atomctrl_internal_ss_info ssInfo;
+
+		uint32_t vco_freq = clock * dividers.uc_pll_post_div;
+		if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
+				vco_freq, &ssInfo)) {
+			/*
+			 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
+			 * ss_info.speed_spectrum_rate -- in unit of khz
+			 *
+			 * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
+			 */
+			uint32_t clk_s = ref_clock * 5 /
+					(ref_divider * ssInfo.speed_spectrum_rate);
+			/* clkv = 2 * D * fbdiv / NS */
+			uint32_t clk_v = 4 * ssInfo.speed_spectrum_percentage *
+					fbdiv / (clk_s * 10000);
+
+			cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
+					CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
+			cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
+					CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
+			cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
+					CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
+		}
+	}
+
+	sclk->SclkFrequency        = clock;
+	sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
+	sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
+	sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
+	sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
+	sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
+
+	return 0;
+}
+
+static uint16_t fiji_find_closest_vddci(struct pp_hwmgr *hwmgr, uint16_t vddci)
+{
+	uint32_t  i;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct pp_atomctrl_voltage_table *vddci_table =
+			&(data->vddci_voltage_table);
+
+	for (i = 0; i < vddci_table->count; i++) {
+		if (vddci_table->entries[i].value >= vddci)
+			return vddci_table->entries[i].value;
+	}
+
+	PP_ASSERT_WITH_CODE(false,
+			"VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
+			return vddci_table->entries[i].value);
+}
+
+static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
+		struct phm_ppt_v1_clock_voltage_dependency_table* dep_table,
+		uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
+{
+	uint32_t i;
+	uint16_t vddci;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	*voltage = *mvdd = 0;
+
+	/* clock - voltage dependency table is empty table */
+	if (dep_table->count == 0)
+		return -EINVAL;
+
+	for (i = 0; i < dep_table->count; i++) {
+		/* find first sclk bigger than request */
+		if (dep_table->entries[i].clk >= clock) {
+			*voltage |= (dep_table->entries[i].vddc *
+					VOLTAGE_SCALE) << VDDC_SHIFT;
+			if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
+				*voltage |= (data->vbios_boot_state.vddci_bootup_value *
+						VOLTAGE_SCALE) << VDDCI_SHIFT;
+			else if (dep_table->entries[i].vddci)
+				*voltage |= (dep_table->entries[i].vddci *
+						VOLTAGE_SCALE) << VDDCI_SHIFT;
+			else {
+				vddci = fiji_find_closest_vddci(hwmgr,
+						(dep_table->entries[i].vddc -
+								(uint16_t)data->vddc_vddci_delta));
+				*voltage |= (vddci * VOLTAGE_SCALE) <<	VDDCI_SHIFT;
+			}
+
+			if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
+				*mvdd = data->vbios_boot_state.mvdd_bootup_value *
+					VOLTAGE_SCALE;
+			else if (dep_table->entries[i].mvdd)
+				*mvdd = (uint32_t) dep_table->entries[i].mvdd *
+					VOLTAGE_SCALE;
+
+			*voltage |= 1 << PHASES_SHIFT;
+			return 0;
+		}
+	}
+
+	/* sclk is bigger than max sclk in the dependence table */
+	*voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
+
+	if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
+		*voltage |= (data->vbios_boot_state.vddci_bootup_value *
+				VOLTAGE_SCALE) << VDDCI_SHIFT;
+	else if (dep_table->entries[i-1].vddci) {
+		vddci = fiji_find_closest_vddci(hwmgr,
+				(dep_table->entries[i].vddc -
+						(uint16_t)data->vddc_vddci_delta));
+		*voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+	}
+
+	if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
+		*mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
+	else if (dep_table->entries[i].mvdd)
+		*mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
+
+	return 0;
+}
+/**
+* Populates single SMC SCLK structure using the provided engine clock
+*
+* @param    hwmgr      the address of the hardware manager
+* @param    clock the engine clock to use to populate the structure
+* @param    sclk        the SMC SCLK structure to be populated
+*/
+
+static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
+		uint32_t clock, uint16_t sclk_al_threshold,
+		struct SMU73_Discrete_GraphicsLevel *level)
+{
+	int result;
+	/* PP_Clocks minClocks; */
+	uint32_t threshold, mvdd;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	result = fiji_calculate_sclk_params(hwmgr, clock, level);
+
+	/* populate graphics levels */
+	result = fiji_get_dependency_volt_by_clk(hwmgr,
+			table_info->vdd_dep_on_sclk, clock,
+			&level->MinVoltage, &mvdd);
+	PP_ASSERT_WITH_CODE((0 == result),
+			"can not find VDDC voltage value for "
+			"VDDC engine clock dependency table",
+			return result);
+
+	level->SclkFrequency = clock;
+	level->ActivityLevel = sclk_al_threshold;
+	level->CcPwrDynRm = 0;
+	level->CcPwrDynRm1 = 0;
+	level->EnabledForActivity = 0;
+	level->EnabledForThrottle = 1;
+	level->UpHyst = 10;
+	level->DownHyst = 0;
+	level->VoltageDownHyst = 0;
+	level->PowerThrottle = 0;
+
+	threshold = clock * data->fast_watermark_threshold / 100;
+
+	/*
+	* TODO: get minimum clocks from dal configaration
+	* PECI_GetMinClockSettings(hwmgr->pPECI, &minClocks);
+	*/
+	/* data->DisplayTiming.minClockInSR = minClocks.engineClockInSR; */
+
+	/* get level->DeepSleepDivId
+	if (phm_cap_enabled(hwmgr->platformDescriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
+	{
+	level->DeepSleepDivId = PhwFiji_GetSleepDividerIdFromClock(hwmgr, clock, minClocks.engineClockInSR);
+	} */
+
+	/* Default to slow, highest DPM level will be
+	 * set to PPSMC_DISPLAY_WATERMARK_LOW later.
+	 */
+	level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+	CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
+	CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
+	CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
+	CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
+	CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
+	CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
+	CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
+	CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
+	CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
+
+	return 0;
+}
+/**
+* Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
+*
+* @param    hwmgr      the address of the hardware manager
+*/
+static int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_dpm_table *dpm_table = &data->dpm_table;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
+	uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count;
+	int result = 0;
+	uint32_t array = data->dpm_table_start +
+			offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
+	uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) *
+			SMU73_MAX_LEVELS_GRAPHICS;
+	struct SMU73_Discrete_GraphicsLevel *levels =
+			data->smc_state_table.GraphicsLevel;
+	uint32_t i, max_entry;
+	uint8_t hightest_pcie_level_enabled = 0,
+			lowest_pcie_level_enabled = 0,
+			mid_pcie_level_enabled = 0,
+			count = 0;
+
+	for (i = 0; i < dpm_table->sclk_table.count; i++) {
+		result = fiji_populate_single_graphic_level(hwmgr,
+				dpm_table->sclk_table.dpm_levels[i].value,
+				(uint16_t)data->activity_target[i],
+				&levels[i]);
+		if (result)
+			return result;
+
+		/* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
+		if (i > 1)
+			levels[i].DeepSleepDivId = 0;
+	}
+
+	/* Only enable level 0 for now.*/
+	levels[0].EnabledForActivity = 1;
+
+	/* set highest level watermark to high */
+	levels[dpm_table->sclk_table.count - 1].DisplayWatermark =
+			PPSMC_DISPLAY_WATERMARK_HIGH;
+
+	data->smc_state_table.GraphicsDpmLevelCount =
+			(uint8_t)dpm_table->sclk_table.count;
+	data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+			fiji_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+	if (pcie_table != NULL) {
+		PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
+				"There must be 1 or more PCIE levels defined in PPTable.",
+				return -EINVAL);
+		max_entry = pcie_entry_cnt - 1;
+		for (i = 0; i < dpm_table->sclk_table.count; i++)
+			levels[i].pcieDpmLevel =
+					(uint8_t) ((i < max_entry)? i : max_entry);
+	} else {
+		while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+				((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+						(1 << (hightest_pcie_level_enabled + 1))) != 0 ))
+			hightest_pcie_level_enabled++;
+
+		while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+				((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+						(1 << lowest_pcie_level_enabled)) == 0 ))
+			lowest_pcie_level_enabled++;
+
+		while ((count < hightest_pcie_level_enabled) &&
+				((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+						(1 << (lowest_pcie_level_enabled + 1 + count))) == 0 ))
+			count++;
+
+		mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1+ count) <
+				hightest_pcie_level_enabled?
+						(lowest_pcie_level_enabled + 1 + count) :
+						hightest_pcie_level_enabled;
+
+		/* set pcieDpmLevel to hightest_pcie_level_enabled */
+		for(i = 2; i < dpm_table->sclk_table.count; i++)
+			levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
+
+		/* set pcieDpmLevel to lowest_pcie_level_enabled */
+		levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
+
+		/* set pcieDpmLevel to mid_pcie_level_enabled */
+		levels[1].pcieDpmLevel = mid_pcie_level_enabled;
+	}
+	/* level count will send to smc once at init smc table and never change */
+	result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
+			(uint32_t)array_size, data->sram_end);
+
+	return result;
+}
+
+/**
+ * MCLK Frequency Ratio
+ * SEQ_CG_RESP  Bit[31:24] - 0x0
+ * Bit[27:24] \96 DDR3 Frequency ratio
+ * 0x0 <= 100MHz,       450 < 0x8 <= 500MHz
+ * 100 < 0x1 <= 150MHz,       500 < 0x9 <= 550MHz
+ * 150 < 0x2 <= 200MHz,       550 < 0xA <= 600MHz
+ * 200 < 0x3 <= 250MHz,       600 < 0xB <= 650MHz
+ * 250 < 0x4 <= 300MHz,       650 < 0xC <= 700MHz
+ * 300 < 0x5 <= 350MHz,       700 < 0xD <= 750MHz
+ * 350 < 0x6 <= 400MHz,       750 < 0xE <= 800MHz
+ * 400 < 0x7 <= 450MHz,       800 < 0xF
+ */
+static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock)
+{
+	if (mem_clock <= 10000) return 0x0;
+	if (mem_clock <= 15000) return 0x1;
+	if (mem_clock <= 20000) return 0x2;
+	if (mem_clock <= 25000) return 0x3;
+	if (mem_clock <= 30000) return 0x4;
+	if (mem_clock <= 35000) return 0x5;
+	if (mem_clock <= 40000) return 0x6;
+	if (mem_clock <= 45000) return 0x7;
+	if (mem_clock <= 50000) return 0x8;
+	if (mem_clock <= 55000) return 0x9;
+	if (mem_clock <= 60000) return 0xa;
+	if (mem_clock <= 65000) return 0xb;
+	if (mem_clock <= 70000) return 0xc;
+	if (mem_clock <= 75000) return 0xd;
+	if (mem_clock <= 80000) return 0xe;
+	/* mem_clock > 800MHz */
+	return 0xf;
+}
+
+/**
+* Populates the SMC MCLK structure using the provided memory clock
+*
+* @param    hwmgr   the address of the hardware manager
+* @param    clock   the memory clock to use to populate the structure
+* @param    sclk    the SMC SCLK structure to be populated
+*/
+static int fiji_calculate_mclk_params(struct pp_hwmgr *hwmgr,
+    uint32_t clock, struct SMU73_Discrete_MemoryLevel *mclk)
+{
+	struct pp_atomctrl_memory_clock_param mem_param;
+	int result;
+
+	result = atomctrl_get_memory_pll_dividers_vi(hwmgr, clock, &mem_param);
+	PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to get Memory PLL Dividers.",);
+
+	/* Save the result data to outpupt memory level structure */
+	mclk->MclkFrequency   = clock;
+	mclk->MclkDivider     = (uint8_t)mem_param.mpll_post_divider;
+	mclk->FreqRange       = fiji_get_mclk_frequency_ratio(clock);
+
+	return result;
+}
+
+static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr,
+		uint32_t clock, struct SMU73_Discrete_MemoryLevel *mem_level)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	int result = 0;
+
+	if (table_info->vdd_dep_on_mclk) {
+		result = fiji_get_dependency_volt_by_clk(hwmgr,
+				table_info->vdd_dep_on_mclk, clock,
+				&mem_level->MinVoltage, &mem_level->MinMvdd);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"can not find MinVddc voltage value from memory "
+				"VDDC voltage dependency table", return result);
+	}
+
+	mem_level->EnabledForThrottle = 1;
+	mem_level->EnabledForActivity = 0;
+	mem_level->UpHyst = 0;
+	mem_level->DownHyst = 100;
+	mem_level->VoltageDownHyst = 0;
+	mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
+	mem_level->StutterEnable = false;
+
+	mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+	/* enable stutter mode if all the follow condition applied
+	 * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
+	 * &(data->DisplayTiming.numExistingDisplays));
+	 */
+	data->display_timing.num_existing_displays = 1;
+
+	if ((data->mclk_stutter_mode_threshold) &&
+		(clock <= data->mclk_stutter_mode_threshold) &&
+		(!data->is_uvd_enabled) &&
+		(PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
+				STUTTER_ENABLE) & 0x1))
+		mem_level->StutterEnable = true;
+
+	result = fiji_calculate_mclk_params(hwmgr, clock, mem_level);
+	if (!result) {
+		CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
+		CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
+		CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
+		CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
+	}
+	return result;
+}
+
+/**
+* Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
+*
+* @param    hwmgr      the address of the hardware manager
+*/
+static int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_dpm_table *dpm_table = &data->dpm_table;
+	int result;
+	/* populate MCLK dpm table to SMU7 */
+	uint32_t array = data->dpm_table_start +
+			offsetof(SMU73_Discrete_DpmTable, MemoryLevel);
+	uint32_t array_size = sizeof(SMU73_Discrete_MemoryLevel) *
+			SMU73_MAX_LEVELS_MEMORY;
+	struct SMU73_Discrete_MemoryLevel *levels =
+			data->smc_state_table.MemoryLevel;
+	uint32_t i;
+
+	for (i = 0; i < dpm_table->mclk_table.count; i++) {
+		PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
+				"can not populate memory level as memory clock is zero",
+				return -EINVAL);
+		result = fiji_populate_single_memory_level(hwmgr,
+				dpm_table->mclk_table.dpm_levels[i].value,
+				&levels[i]);
+		if (result)
+			return result;
+	}
+
+	/* Only enable level 0 for now. */
+	levels[0].EnabledForActivity = 1;
+
+	/* in order to prevent MC activity from stutter mode to push DPM up.
+	 * the UVD change complements this by putting the MCLK in
+	 * a higher state by default such that we are not effected by
+	 * up threshold or and MCLK DPM latency.
+	 */
+	levels[0].ActivityLevel = (uint16_t)data->mclk_dpm0_activity_target;
+	CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
+
+	data->smc_state_table.MemoryDpmLevelCount =
+			(uint8_t)dpm_table->mclk_table.count;
+	data->dpm_level_enable_mask.mclk_dpm_enable_mask =
+			fiji_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+	/* set highest level watermark to high */
+	levels[dpm_table->mclk_table.count - 1].DisplayWatermark =
+			PPSMC_DISPLAY_WATERMARK_HIGH;
+
+	/* level count will send to smc once at init smc table and never change */
+	result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
+			(uint32_t)array_size, data->sram_end);
+
+	return result;
+}
+
+/**
+* Populates the SMC MVDD structure using the provided memory clock.
+*
+* @param    hwmgr      the address of the hardware manager
+* @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
+* @param    voltage     the SMC VOLTAGE structure to be populated
+*/
+int fiji_populate_mvdd_value(struct pp_hwmgr *hwmgr,
+		uint32_t mclk, SMIO_Pattern *smio_pat)
+{
+	const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	uint32_t i = 0;
+
+	if (FIJI_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
+		/* find mvdd value which clock is more than request */
+		for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
+			if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
+				smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
+				break;
+			}
+		}
+		PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
+				"MVDD Voltage is outside the supported range.",
+				return -EINVAL);
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
+		SMU73_Discrete_DpmTable *table)
+{
+	int result = 0;
+	const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct pp_atomctrl_clock_dividers_vi dividers;
+	SMIO_Pattern vol_level;
+	uint32_t mvdd;
+	uint16_t us_mvdd;
+	uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+	uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
+
+	table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+	if (!data->sclk_dpm_key_disabled) {
+		/* Get MinVoltage and Frequency from DPM0,
+		 * already converted to SMC_UL */
+		table->ACPILevel.SclkFrequency =
+				data->dpm_table.sclk_table.dpm_levels[0].value;
+		result = fiji_get_dependency_volt_by_clk(hwmgr,
+				table_info->vdd_dep_on_sclk,
+				table->ACPILevel.SclkFrequency,
+				&table->ACPILevel.MinVoltage, &mvdd);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Cannot find ACPI VDDC voltage value "
+				"in Clock Dependency Table",);
+	} else {
+		table->ACPILevel.SclkFrequency =
+				data->vbios_boot_state.sclk_bootup_value;
+		table->ACPILevel.MinVoltage =
+				data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE;
+	}
+
+	/* get the engine clock dividers for this clock value */
+	result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
+			table->ACPILevel.SclkFrequency,  &dividers);
+	PP_ASSERT_WITH_CODE(result == 0,
+			"Error retrieving Engine Clock dividers from VBIOS.",
+			return result);
+
+	table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
+	table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+	table->ACPILevel.DeepSleepDivId = 0;
+
+	spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+			SPLL_PWRON, 0);
+	spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+			SPLL_RESET, 1);
+	spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
+			SCLK_MUX_SEL, 4);
+
+	table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
+	table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
+	table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+	table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+	table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+	table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+	table->ACPILevel.CcPwrDynRm = 0;
+	table->ACPILevel.CcPwrDynRm1 = 0;
+
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
+
+	if (!data->mclk_dpm_key_disabled) {
+		/* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
+		table->MemoryACPILevel.MclkFrequency =
+				data->dpm_table.mclk_table.dpm_levels[0].value;
+		result = fiji_get_dependency_volt_by_clk(hwmgr,
+				table_info->vdd_dep_on_mclk,
+				table->MemoryACPILevel.MclkFrequency,
+				&table->MemoryACPILevel.MinVoltage, &mvdd);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Cannot find ACPI VDDCI voltage value "
+				"in Clock Dependency Table",);
+	} else {
+		table->MemoryACPILevel.MclkFrequency =
+				data->vbios_boot_state.mclk_bootup_value;
+		table->MemoryACPILevel.MinVoltage =
+				data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE;
+	}
+
+	us_mvdd = 0;
+	if ((FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
+			(data->mclk_dpm_key_disabled))
+		us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
+	else {
+		if (!fiji_populate_mvdd_value(hwmgr,
+				data->dpm_table.mclk_table.dpm_levels[0].value,
+				&vol_level))
+			us_mvdd = vol_level.Voltage;
+	}
+
+	table->MemoryACPILevel.MinMvdd =
+			PP_HOST_TO_SMC_UL(us_mvdd * VOLTAGE_SCALE);
+
+	table->MemoryACPILevel.EnabledForThrottle = 0;
+	table->MemoryACPILevel.EnabledForActivity = 0;
+	table->MemoryACPILevel.UpHyst = 0;
+	table->MemoryACPILevel.DownHyst = 100;
+	table->MemoryACPILevel.VoltageDownHyst = 0;
+	table->MemoryACPILevel.ActivityLevel =
+			PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
+
+	table->MemoryACPILevel.StutterEnable = false;
+	CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
+
+	return result;
+}
+
+static int fiji_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
+		SMU73_Discrete_DpmTable *table)
+{
+	int result = -EINVAL;
+	uint8_t count;
+	struct pp_atomctrl_clock_dividers_vi dividers;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+			table_info->mm_dep_table;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	table->VceLevelCount = (uint8_t)(mm_table->count);
+	table->VceBootLevel = 0;
+
+	for(count = 0; count < table->VceLevelCount; count++) {
+		table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
+		table->VceLevel[count].MinVoltage |=
+				(mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
+		table->VceLevel[count].MinVoltage |=
+				((mm_table->entries[count].vddc - data->vddc_vddci_delta) *
+						VOLTAGE_SCALE) << VDDCI_SHIFT;
+		table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+		/*retrieve divider value for VBIOS */
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+				table->VceLevel[count].Frequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"can not find divide id for VCE engine clock",
+				return result);
+
+		table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
+		CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
+	}
+	return result;
+}
+
+static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
+		SMU73_Discrete_DpmTable *table)
+{
+	int result = -EINVAL;
+	uint8_t count;
+	struct pp_atomctrl_clock_dividers_vi dividers;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+			table_info->mm_dep_table;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	table->AcpLevelCount = (uint8_t)(mm_table->count);
+	table->AcpBootLevel = 0;
+
+	for (count = 0; count < table->AcpLevelCount; count++) {
+		table->AcpLevel[count].Frequency = mm_table->entries[count].aclk;
+		table->AcpLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+				VOLTAGE_SCALE) << VDDC_SHIFT;
+		table->AcpLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+				data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+		table->AcpLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+		/* retrieve divider value for VBIOS */
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+				table->AcpLevel[count].Frequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"can not find divide id for engine clock", return result);
+
+		table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
+		CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].MinVoltage);
+	}
+	return result;
+}
+
+static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
+		SMU73_Discrete_DpmTable *table)
+{
+	int result = -EINVAL;
+	uint8_t count;
+	struct pp_atomctrl_clock_dividers_vi dividers;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+			table_info->mm_dep_table;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	table->SamuBootLevel = 0;
+	table->SamuLevelCount = (uint8_t)(mm_table->count);
+
+	for (count = 0; count < table->SamuLevelCount; count++) {
+		/* not sure whether we need evclk or not */
+		table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
+		table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+				VOLTAGE_SCALE) << VDDC_SHIFT;
+		table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+				data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+		table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+		/* retrieve divider value for VBIOS */
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+				table->SamuLevel[count].Frequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"can not find divide id for samu clock", return result);
+
+		table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
+		CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
+	}
+	return result;
+}
+
+static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
+		int32_t eng_clock, int32_t mem_clock,
+		struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs)
+{
+	uint32_t dram_timing;
+	uint32_t dram_timing2;
+	uint32_t burstTime;
+	ULONG state, trrds, trrdl;
+	int result;
+
+	result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
+			eng_clock, mem_clock);
+	PP_ASSERT_WITH_CODE(result == 0,
+			"Error calling VBIOS to set DRAM_TIMING.", return result);
+
+	dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+	dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+	burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME);
+
+	state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0);
+	trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0);
+	trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0);
+
+	arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dram_timing);
+	arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
+	arb_regs->McArbBurstTime   = (uint8_t)burstTime;
+	arb_regs->TRRDS            = (uint8_t)trrds;
+	arb_regs->TRRDL            = (uint8_t)trrdl;
+
+	return 0;
+}
+
+static int fiji_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct SMU73_Discrete_MCArbDramTimingTable arb_regs;
+	uint32_t i, j;
+	int result = 0;
+
+	for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
+		for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
+			result = fiji_populate_memory_timing_parameters(hwmgr,
+					data->dpm_table.sclk_table.dpm_levels[i].value,
+					data->dpm_table.mclk_table.dpm_levels[j].value,
+					&arb_regs.entries[i][j]);
+			if (result)
+				break;
+		}
+	}
+
+	if (!result)
+		result = fiji_copy_bytes_to_smc(
+				hwmgr->smumgr,
+				data->arb_table_start,
+				(uint8_t *)&arb_regs,
+				sizeof(SMU73_Discrete_MCArbDramTimingTable),
+				data->sram_end);
+	return result;
+}
+
+static int fiji_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
+		struct SMU73_Discrete_DpmTable *table)
+{
+	int result = -EINVAL;
+	uint8_t count;
+	struct pp_atomctrl_clock_dividers_vi dividers;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+			table_info->mm_dep_table;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	table->UvdLevelCount = (uint8_t)(mm_table->count);
+	table->UvdBootLevel = 0;
+
+	for (count = 0; count < table->UvdLevelCount; count++) {
+		table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
+		table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
+		table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+				VOLTAGE_SCALE) << VDDC_SHIFT;
+		table->UvdLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+				data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+		table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+		/* retrieve divider value for VBIOS */
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+				table->UvdLevel[count].VclkFrequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"can not find divide id for Vclk clock", return result);
+
+		table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
+
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+				table->UvdLevel[count].DclkFrequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"can not find divide id for Dclk clock", return result);
+
+		table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
+		CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
+		CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
+
+	}
+	return result;
+}
+
+static int fiji_find_boot_level(struct fiji_single_dpm_table *table,
+		uint32_t value, uint32_t *boot_level)
+{
+	int result = -EINVAL;
+	uint32_t i;
+
+	for (i = 0; i < table->count; i++) {
+		if (value == table->dpm_levels[i].value) {
+			*boot_level = i;
+			result = 0;
+		}
+	}
+	return result;
+}
+
+static int fiji_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
+		struct SMU73_Discrete_DpmTable *table)
+{
+	int result = 0;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	table->GraphicsBootLevel = 0;
+	table->MemoryBootLevel = 0;
+
+	/* find boot level from dpm table */
+	result = fiji_find_boot_level(&(data->dpm_table.sclk_table),
+			data->vbios_boot_state.sclk_bootup_value,
+			(uint32_t *)&(table->GraphicsBootLevel));
+
+	result = fiji_find_boot_level(&(data->dpm_table.mclk_table),
+			data->vbios_boot_state.mclk_bootup_value,
+			(uint32_t *)&(table->MemoryBootLevel));
+
+	table->BootVddc  = data->vbios_boot_state.vddc_bootup_value *
+			VOLTAGE_SCALE;
+	table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
+			VOLTAGE_SCALE;
+	table->BootMVdd  = data->vbios_boot_state.mvdd_bootup_value *
+			VOLTAGE_SCALE;
+
+	CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
+	CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
+	CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
+
+	return 0;
+}
+
+static int fiji_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	uint8_t count, level;
+
+	count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
+	for (level = 0; level < count; level++) {
+		if(table_info->vdd_dep_on_sclk->entries[level].clk >=
+				data->vbios_boot_state.sclk_bootup_value) {
+			data->smc_state_table.GraphicsBootLevel = level;
+			break;
+		}
+	}
+
+	count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
+	for (level = 0; level < count; level++) {
+		if(table_info->vdd_dep_on_mclk->entries[level].clk >=
+				data->vbios_boot_state.mclk_bootup_value) {
+			data->smc_state_table.MemoryBootLevel = level;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
+{
+	uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
+			volt_with_cks, value;
+	uint16_t clock_freq_u16;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
+			volt_offset = 0;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+			table_info->vdd_dep_on_sclk;
+
+	stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
+
+	/* Read SMU_Eefuse to read and calculate RO and determine
+	 * if the part is SS or FF. if RO >= 1660MHz, part is FF.
+	 */
+	efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixSMU_EFUSE_0 + (146 * 4));
+	efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixSMU_EFUSE_0 + (148 * 4));
+	efuse &= 0xFF000000;
+	efuse = efuse >> 24;
+	efuse2 &= 0xF;
+
+	if (efuse2 == 1)
+		ro = (2300 - 1350) * efuse / 255 + 1350;
+	else
+		ro = (2500 - 1000) * efuse / 255 + 1000;
+
+	if (ro >= 1660)
+		type = 0;
+	else
+		type = 1;
+
+	/* Populate Stretch amount */
+	data->smc_state_table.ClockStretcherAmount = stretch_amount;
+
+	/* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
+	for (i = 0; i < sclk_table->count; i++) {
+		data->smc_state_table.Sclk_CKS_masterEn0_7 |=
+				sclk_table->entries[i].cks_enable << i;
+		volt_without_cks = (uint32_t)((14041 *
+			(sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
+			(4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
+		volt_with_cks = (uint32_t)((13946 *
+			(sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
+			(3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
+		if (volt_without_cks >= volt_with_cks)
+			volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
+					sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
+		data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
+	}
+
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+			STRETCH_ENABLE, 0x0);
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+			masterReset, 0x1);
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+			staticEnable, 0x1);
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+			masterReset, 0x0);
+
+	/* Populate CKS Lookup Table */
+	if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
+		stretch_amount2 = 0;
+	else if (stretch_amount == 3 || stretch_amount == 4)
+		stretch_amount2 = 1;
+	else {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_ClockStretcher);
+		PP_ASSERT_WITH_CODE(false,
+				"Stretch Amount in PPTable not supported\n",
+				return -EINVAL);
+	}
+
+	value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixPWR_CKS_CNTL);
+	value &= 0xFFC2FF87;
+	data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
+			fiji_clock_stretcher_lookup_table[stretch_amount2][0];
+	data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
+			fiji_clock_stretcher_lookup_table[stretch_amount2][1];
+	clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(data->smc_state_table.
+			GraphicsLevel[data->smc_state_table.GraphicsDpmLevelCount - 1].
+			SclkFrequency) / 100);
+	if (fiji_clock_stretcher_lookup_table[stretch_amount2][0] <
+			clock_freq_u16 &&
+	    fiji_clock_stretcher_lookup_table[stretch_amount2][1] >
+			clock_freq_u16) {
+		/* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
+		value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
+		/* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
+		value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
+		/* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
+		value |= (fiji_clock_stretch_amount_conversion
+				[fiji_clock_stretcher_lookup_table[stretch_amount2][3]]
+				 [stretch_amount]) << 3;
+	}
+	CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
+			CKS_LOOKUPTableEntry[0].minFreq);
+	CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
+			CKS_LOOKUPTableEntry[0].maxFreq);
+	data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
+			fiji_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
+	data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
+			(fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixPWR_CKS_CNTL, value);
+
+	/* Populate DDT Lookup Table */
+	for (i = 0; i < 4; i++) {
+		/* Assign the minimum and maximum VID stored
+		 * in the last row of Clock Stretcher Voltage Table.
+		 */
+		data->smc_state_table.ClockStretcherDataTable.
+		ClockStretcherDataTableEntry[i].minVID =
+				(uint8_t) fiji_clock_stretcher_ddt_table[type][i][2];
+		data->smc_state_table.ClockStretcherDataTable.
+		ClockStretcherDataTableEntry[i].maxVID =
+				(uint8_t) fiji_clock_stretcher_ddt_table[type][i][3];
+		/* Loop through each SCLK and check the frequency
+		 * to see if it lies within the frequency for clock stretcher.
+		 */
+		for (j = 0; j < data->smc_state_table.GraphicsDpmLevelCount; j++) {
+			cks_setting = 0;
+			clock_freq = PP_SMC_TO_HOST_UL(
+					data->smc_state_table.GraphicsLevel[j].SclkFrequency);
+			/* Check the allowed frequency against the sclk level[j].
+			 *  Sclk's endianness has already been converted,
+			 *  and it's in 10Khz unit,
+			 *  as opposed to Data table, which is in Mhz unit.
+			 */
+			if (clock_freq >=
+					(fiji_clock_stretcher_ddt_table[type][i][0]) * 100) {
+				cks_setting |= 0x2;
+				if (clock_freq <
+						(fiji_clock_stretcher_ddt_table[type][i][1]) * 100)
+					cks_setting |= 0x1;
+			}
+			data->smc_state_table.ClockStretcherDataTable.
+			ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
+		}
+		CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.
+				ClockStretcherDataTable.
+				ClockStretcherDataTableEntry[i].setting);
+	}
+
+	value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
+	value &= 0xFFFFFFFE;
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
+
+	return 0;
+}
+
+/**
+* Populates the SMC VRConfig field in DPM table.
+*
+* @param    hwmgr   the address of the hardware manager
+* @param    table   the SMC DPM table structure to be populated
+* @return   always 0
+*/
+static int fiji_populate_vr_config(struct pp_hwmgr *hwmgr,
+		struct SMU73_Discrete_DpmTable *table)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint16_t config;
+
+	config = VR_MERGED_WITH_VDDC;
+	table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
+
+	/* Set Vddc Voltage Controller */
+	if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+		config = VR_SVI2_PLANE_1;
+		table->VRConfig |= config;
+	} else {
+		PP_ASSERT_WITH_CODE(false,
+				"VDDC should be on SVI2 control in merged mode!",);
+	}
+	/* Set Vddci Voltage Controller */
+	if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+		config = VR_SVI2_PLANE_2;  /* only in merged mode */
+		table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+	} else if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+		config = VR_SMIO_PATTERN_1;
+		table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+	} else {
+		config = VR_STATIC_VOLTAGE;
+		table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+	}
+	/* Set Mvdd Voltage Controller */
+	if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
+		config = VR_SVI2_PLANE_2;
+		table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+	} else if(FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+		config = VR_SMIO_PATTERN_2;
+		table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+	} else {
+		config = VR_STATIC_VOLTAGE;
+		table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+	}
+
+	return 0;
+}
+
+/**
+* Initializes the SMC table and uploads it
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput  the pointer to input data (PowerState)
+* @return   always 0
+*/
+static int fiji_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+	int result;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct SMU73_Discrete_DpmTable *table = &(data->smc_state_table);
+	const struct fiji_ulv_parm *ulv = &(data->ulv);
+	uint8_t i;
+	struct pp_atomctrl_gpio_pin_assignment gpio_pin;
+
+	result = fiji_setup_default_dpm_tables(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to setup default DPM tables!", return result);
+
+	if(FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control)
+		fiji_populate_smc_voltage_tables(hwmgr, table);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_AutomaticDCTransition))
+		table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_StepVddc))
+		table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+	if (data->is_memory_gddr5)
+		table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+	if (ulv->ulv_supported && table_info->us_ulv_voltage_offset) {
+		result = fiji_populate_ulv_state(hwmgr, table);
+		PP_ASSERT_WITH_CODE(0 == result,
+				"Failed to initialize ULV state!", return result);
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixCG_ULV_PARAMETER, ulv->cg_ulv_parameter);
+	}
+
+	result = fiji_populate_smc_link_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize Link Level!", return result);
+
+	result = fiji_populate_all_graphic_levels(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize Graphics Level!", return result);
+
+	result = fiji_populate_all_memory_levels(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize Memory Level!", return result);
+
+	result = fiji_populate_smc_acpi_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize ACPI Level!", return result);
+
+	result = fiji_populate_smc_vce_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize VCE Level!", return result);
+
+	result = fiji_populate_smc_acp_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize ACP Level!", return result);
+
+	result = fiji_populate_smc_samu_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize SAMU Level!", return result);
+
+	/* Since only the initial state is completely set up at this point
+	 * (the other states are just copies of the boot state) we only
+	 * need to populate the  ARB settings for the initial state.
+	 */
+	result = fiji_program_memory_timing_parameters(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to Write ARB settings for the initial state.", return result);
+
+	result = fiji_populate_smc_uvd_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize UVD Level!", return result);
+
+	result = fiji_populate_smc_boot_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize Boot Level!", return result);
+
+	result = fiji_populate_smc_initailial_state(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize Boot State!", return result);
+
+	result = fiji_populate_bapm_parameters_in_dpm_table(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to populate BAPM Parameters!", return result);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ClockStretcher)) {
+		result = fiji_populate_clock_stretcher_data_table(hwmgr);
+		PP_ASSERT_WITH_CODE(0 == result,
+				"Failed to populate Clock Stretcher Data Table!",
+				return result);
+	}
+
+	table->GraphicsVoltageChangeEnable  = 1;
+	table->GraphicsThermThrottleEnable  = 1;
+	table->GraphicsInterval = 1;
+	table->VoltageInterval  = 1;
+	table->ThermalInterval  = 1;
+	table->TemperatureLimitHigh =
+			table_info->cac_dtp_table->usTargetOperatingTemp *
+			FIJI_Q88_FORMAT_CONVERSION_UNIT;
+	table->TemperatureLimitLow  =
+			(table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
+			FIJI_Q88_FORMAT_CONVERSION_UNIT;
+	table->MemoryVoltageChangeEnable = 1;
+	table->MemoryInterval = 1;
+	table->VoltageResponseTime = 0;
+	table->PhaseResponseTime = 0;
+	table->MemoryThermThrottleEnable = 1;
+	table->PCIeBootLinkLevel = 0;      /* 0:Gen1 1:Gen2 2:Gen3*/
+	table->PCIeGenInterval = 1;
+
+	result = fiji_populate_vr_config(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to populate VRConfig setting!", return result);
+
+	table->ThermGpio = 17;
+	table->SclkStepSize = 0x4000;
+
+	if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
+		table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_RegulatorHot);
+	} else {
+		table->VRHotGpio = FIJI_UNUSED_GPIO_PIN;
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_RegulatorHot);
+	}
+
+	if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
+			&gpio_pin)) {
+		table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_AutomaticDCTransition);
+	} else {
+		table->AcDcGpio = FIJI_UNUSED_GPIO_PIN;
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_AutomaticDCTransition);
+	}
+
+	/* Thermal Output GPIO */
+	if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
+			&gpio_pin)) {
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_ThermalOutGPIO);
+
+		table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
+
+		/* For porlarity read GPIOPAD_A with assigned Gpio pin
+		 * since VBIOS will program this register to set 'inactive state',
+		 * driver can then determine 'active state' from this and
+		 * program SMU with correct polarity
+		 */
+		table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
+				(1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
+		table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
+
+		/* if required, combine VRHot/PCC with thermal out GPIO */
+		if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_RegulatorHot) &&
+			phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_CombinePCCWithThermalSignal))
+			table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
+	} else {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_ThermalOutGPIO);
+		table->ThermOutGpio = 17;
+		table->ThermOutPolarity = 1;
+		table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
+	}
+
+	for (i = 0; i < SMU73_MAX_ENTRIES_SMIO; i++)
+		table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
+
+	CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
+	CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
+	CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
+	CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
+	CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
+
+	/* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
+	result = fiji_copy_bytes_to_smc(hwmgr->smumgr,
+			data->dpm_table_start +
+			offsetof(SMU73_Discrete_DpmTable, SystemFlags),
+			(uint8_t *)&(table->SystemFlags),
+			sizeof(SMU73_Discrete_DpmTable) - 3 * sizeof(SMU73_PIDController),
+			data->sram_end);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to upload dpm data to SMC memory!", return result);
+
+	return 0;
+}
+
+/**
+* Initialize the ARB DRAM timing table's index field.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int fiji_init_arb_table_index(struct pp_hwmgr *hwmgr)
+{
+	const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t tmp;
+	int result;
+
+	/* This is a read-modify-write on the first byte of the ARB table.
+	 * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
+	 * is the field 'current'.
+	 * This solution is ugly, but we never write the whole table only
+	 * individual fields in it.
+	 * In reality this field should not be in that structure
+	 * but in a soft register.
+	 */
+	result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+			data->arb_table_start, &tmp, data->sram_end);
+
+	if (result)
+		return result;
+
+	tmp &= 0x00FFFFFF;
+	tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
+
+	return fiji_write_smc_sram_dword(hwmgr->smumgr,
+			data->arb_table_start,  tmp, data->sram_end);
+}
+
+static int fiji_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr)
+{
+	if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_RegulatorHot))
+		return smum_send_msg_to_smc(hwmgr->smumgr,
+				PPSMC_MSG_EnableVRHotGPIOInterrupt);
+
+	return 0;
+}
+
+static int fiji_enable_sclk_control(struct pp_hwmgr *hwmgr)
+{
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
+			SCLK_PWRMGT_OFF, 0);
+	return 0;
+}
+
+static int fiji_enable_ulv(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_ulv_parm *ulv = &(data->ulv);
+
+	if (ulv->ulv_supported)
+		return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_EnableULV);
+
+	return 0;
+}
+
+static int fiji_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_SclkDeepSleep)) {
+		if (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MASTER_DeepSleep_ON))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to enable Master Deep Sleep switch failed!",
+					return -1);
+	} else {
+		if (smum_send_msg_to_smc(hwmgr->smumgr,
+				PPSMC_MSG_MASTER_DeepSleep_OFF)) {
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to disable Master Deep Sleep switch failed!",
+					return -1);
+		}
+	}
+
+	return 0;
+}
+
+static int fiji_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t   val, val0, val2;
+	uint32_t   i, cpl_cntl, cpl_threshold, mc_threshold;
+
+	/* enable SCLK dpm */
+	if(!data->sclk_dpm_key_disabled)
+		PP_ASSERT_WITH_CODE(
+		(0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Enable)),
+		"Failed to enable SCLK DPM during DPM Start Function!",
+		return -1);
+
+	/* enable MCLK dpm */
+	if(0 == data->mclk_dpm_key_disabled) {
+		cpl_threshold = 0;
+		mc_threshold = 0;
+
+		/* Read per MCD tile (0 - 7) */
+		for (i = 0; i < 8; i++) {
+			PHM_WRITE_FIELD(hwmgr->device, MC_CONFIG_MCD, MC_RD_ENABLE, i);
+			val = cgs_read_register(hwmgr->device, mmMC_SEQ_RESERVE_0_S) & 0xf0000000;
+			if (0xf0000000 != val) {
+				/* count number of MCQ that has channel(s) enabled */
+				cpl_threshold++;
+				/* only harvest 3 or full 4 supported */
+				mc_threshold = val ? 3 : 4;
+			}
+		}
+		PP_ASSERT_WITH_CODE(0 != cpl_threshold,
+				"Number of MCQ is zero!", return -EINVAL;);
+
+		mc_threshold = ((mc_threshold & LCAC_MC0_CNTL__MC0_THRESHOLD_MASK) <<
+				LCAC_MC0_CNTL__MC0_THRESHOLD__SHIFT) |
+						LCAC_MC0_CNTL__MC0_ENABLE_MASK;
+		cpl_cntl = ((cpl_threshold & LCAC_CPL_CNTL__CPL_THRESHOLD_MASK) <<
+				LCAC_CPL_CNTL__CPL_THRESHOLD__SHIFT) |
+						LCAC_CPL_CNTL__CPL_ENABLE_MASK;
+		cpl_cntl = (cpl_cntl | (8 << LCAC_CPL_CNTL__CPL_BLOCK_ID__SHIFT));
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixLCAC_MC0_CNTL, mc_threshold);
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixLCAC_MC1_CNTL, mc_threshold);
+		if (8 == cpl_threshold) {
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC2_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC3_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC4_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC5_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC6_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC7_CNTL, mc_threshold);
+		}
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixLCAC_CPL_CNTL, cpl_cntl);
+
+		udelay(5);
+
+		mc_threshold = mc_threshold |
+				(1 << LCAC_MC0_CNTL__MC0_SIGNAL_ID__SHIFT);
+		cpl_cntl = cpl_cntl | (1 << LCAC_CPL_CNTL__CPL_SIGNAL_ID__SHIFT);
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixLCAC_MC0_CNTL, mc_threshold);
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixLCAC_MC1_CNTL, mc_threshold);
+		if (8 == cpl_threshold) {
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC2_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC3_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC4_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC5_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC6_CNTL, mc_threshold);
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+					ixLCAC_MC7_CNTL, mc_threshold);
+		}
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+				ixLCAC_CPL_CNTL, cpl_cntl);
+
+		/* Program CAC_EN per MCD (0-7) Tile */
+		val0 = val = cgs_read_register(hwmgr->device, mmMC_CONFIG_MCD);
+		val &= ~(MC_CONFIG_MCD__MCD0_WR_ENABLE_MASK |
+				MC_CONFIG_MCD__MCD1_WR_ENABLE_MASK |
+				MC_CONFIG_MCD__MCD2_WR_ENABLE_MASK |
+				MC_CONFIG_MCD__MCD3_WR_ENABLE_MASK |
+				MC_CONFIG_MCD__MCD4_WR_ENABLE_MASK |
+				MC_CONFIG_MCD__MCD5_WR_ENABLE_MASK |
+				MC_CONFIG_MCD__MCD6_WR_ENABLE_MASK |
+				MC_CONFIG_MCD__MCD7_WR_ENABLE_MASK |
+				MC_CONFIG_MCD__MC_RD_ENABLE_MASK);
+
+		for (i = 0; i < 8; i++) {
+			/* Enable MCD i Tile read & write */
+			val2  = (val | (i << MC_CONFIG_MCD__MC_RD_ENABLE__SHIFT) |
+					(1 << i));
+			cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val2);
+			/* Enbale CAC_ON MCD i Tile */
+			val2 = cgs_read_register(hwmgr->device, mmMC_SEQ_CNTL);
+			val2 |= MC_SEQ_CNTL__CAC_EN_MASK;
+			cgs_write_register(hwmgr->device, mmMC_SEQ_CNTL, val2);
+		}
+		/* Set MC_CONFIG_MCD back to its default setting val0 */
+		cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val0);
+
+		PP_ASSERT_WITH_CODE(
+				(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+						PPSMC_MSG_MCLKDPM_Enable)),
+				"Failed to enable MCLK DPM during DPM Start Function!",
+				return -1);
+	}
+	return 0;
+}
+
+static int fiji_start_dpm(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	/*enable general power management */
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+			GLOBAL_PWRMGT_EN, 1);
+	/* enable sclk deep sleep */
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
+			DYNAMIC_PM_EN, 1);
+	/* prepare for PCIE DPM */
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			data->soft_regs_start + offsetof(SMU73_SoftRegisters,
+					VoltageChangeTimeout), 0x1000);
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
+			SWRST_COMMAND_1, RESETLC, 0x0);
+
+	PP_ASSERT_WITH_CODE(
+			(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+					PPSMC_MSG_Voltage_Cntl_Enable)),
+			"Failed to enable voltage DPM during DPM Start Function!",
+			return -1);
+
+	if (fiji_enable_sclk_mclk_dpm(hwmgr)) {
+		printk(KERN_ERR "Failed to enable Sclk DPM and Mclk DPM!");
+		return -1;
+	}
+
+	/* enable PCIE dpm */
+	if(!data->pcie_dpm_key_disabled) {
+		PP_ASSERT_WITH_CODE(
+				(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+						PPSMC_MSG_PCIeDPM_Enable)),
+				"Failed to enable pcie DPM during DPM Start Function!",
+				return -1);
+	}
+
+	return 0;
+}
+
+static void fiji_set_dpm_event_sources(struct pp_hwmgr *hwmgr,
+		uint32_t sources)
+{
+	bool protection;
+	enum DPM_EVENT_SRC src;
+
+	switch (sources) {
+	default:
+		printk(KERN_ERR "Unknown throttling event sources.");
+		/* fall through */
+	case 0:
+		protection = false;
+		/* src is unused */
+		break;
+	case (1 << PHM_AutoThrottleSource_Thermal):
+		protection = true;
+		src = DPM_EVENT_SRC_DIGITAL;
+		break;
+	case (1 << PHM_AutoThrottleSource_External):
+		protection = true;
+		src = DPM_EVENT_SRC_EXTERNAL;
+		break;
+	case (1 << PHM_AutoThrottleSource_External) |
+			(1 << PHM_AutoThrottleSource_Thermal):
+		protection = true;
+		src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL;
+		break;
+	}
+	/* Order matters - don't enable thermal protection for the wrong source. */
+	if (protection) {
+		PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL,
+				DPM_EVENT_SRC, src);
+		PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+				THERMAL_PROTECTION_DIS,
+				phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+						PHM_PlatformCaps_ThermalController));
+	} else
+		PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+				THERMAL_PROTECTION_DIS, 1);
+}
+
+static int fiji_enable_auto_throttle_source(struct pp_hwmgr *hwmgr,
+		PHM_AutoThrottleSource source)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if (!(data->active_auto_throttle_sources & (1 << source))) {
+		data->active_auto_throttle_sources |= 1 << source;
+		fiji_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
+	}
+	return 0;
+}
+
+static int fiji_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
+{
+	return fiji_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
+}
+
+static int fiji_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
+{
+	int tmp_result, result = 0;
+
+	tmp_result = (!fiji_is_dpm_running(hwmgr))? 0 : -1;
+	PP_ASSERT_WITH_CODE(result == 0,
+			"DPM is already running right now, no need to enable DPM!",
+			return 0);
+
+	if (fiji_voltage_control(hwmgr)) {
+		tmp_result = fiji_enable_voltage_control(hwmgr);
+		PP_ASSERT_WITH_CODE(tmp_result == 0,
+				"Failed to enable voltage control!",
+				result = tmp_result);
+	}
+
+	if (fiji_voltage_control(hwmgr)) {
+		tmp_result = fiji_construct_voltage_tables(hwmgr);
+		PP_ASSERT_WITH_CODE((0 == tmp_result),
+				"Failed to contruct voltage tables!",
+				result = tmp_result);
+	}
+
+	tmp_result = fiji_initialize_mc_reg_table(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to initialize MC reg table!", result = tmp_result);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_EngineSpreadSpectrumSupport))
+		PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 1);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ThermalController))
+		PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 0);
+
+	tmp_result = fiji_program_static_screen_threshold_parameters(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to program static screen threshold parameters!",
+			result = tmp_result);
+
+	tmp_result = fiji_enable_display_gap(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable display gap!", result = tmp_result);
+
+	tmp_result = fiji_program_voting_clients(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to program voting clients!", result = tmp_result);
+
+	tmp_result = fiji_process_firmware_header(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to process firmware header!", result = tmp_result);
+
+	tmp_result = fiji_initial_switch_from_arbf0_to_f1(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to initialize switch from ArbF0 to F1!",
+			result = tmp_result);
+
+	tmp_result = fiji_init_smc_table(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to initialize SMC table!", result = tmp_result);
+
+	tmp_result = fiji_init_arb_table_index(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to initialize ARB table index!", result = tmp_result);
+
+	tmp_result = fiji_populate_pm_fuses(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to populate PM fuses!", result = tmp_result);
+
+	tmp_result = fiji_enable_vrhot_gpio_interrupt(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable VR hot GPIO interrupt!", result = tmp_result);
+
+	tmp_result = tonga_notify_smc_display_change(hwmgr, false);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to notify no display!", result = tmp_result);
+
+	tmp_result = fiji_enable_sclk_control(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable SCLK control!", result = tmp_result);
+
+	tmp_result = fiji_enable_ulv(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable ULV!", result = tmp_result);
+
+	tmp_result = fiji_enable_deep_sleep_master_switch(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable deep sleep master switch!", result = tmp_result);
+
+	tmp_result = fiji_start_dpm(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to start DPM!", result = tmp_result);
+
+	tmp_result = fiji_enable_smc_cac(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable SMC CAC!", result = tmp_result);
+
+	tmp_result = fiji_enable_power_containment(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable power containment!", result = tmp_result);
+
+	tmp_result = fiji_power_control_set_level(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to power control set level!", result = tmp_result);
+
+	tmp_result = fiji_enable_thermal_auto_throttle(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable thermal auto throttle!", result = tmp_result);
+
+	return result;
+}
+
+static int fiji_force_dpm_highest(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t level, tmp;
+
+	if (!data->sclk_dpm_key_disabled) {
+		if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+			level = 0;
+			tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
+			while (tmp >>= 1)
+				level++;
+			if (level)
+				smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_SCLKDPM_SetEnabledMask,
+						(1 << level));
+		}
+	}
+
+	if (!data->mclk_dpm_key_disabled) {
+		if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+			level = 0;
+			tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+			while (tmp >>= 1)
+				level++;
+			if (level)
+				smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_MCLKDPM_SetEnabledMask,
+						(1 << level));
+		}
+	}
+
+	if (!data->pcie_dpm_key_disabled) {
+		if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+			level = 0;
+			tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
+			while (tmp >>= 1)
+				level++;
+			if (level)
+				smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_PCIeDPM_ForceLevel,
+						(1 << level));
+		}
+	}
+	return 0;
+}
+
+static void fiji_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr)
+{
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)hwmgr->pptable;
+	struct phm_clock_voltage_dependency_table *table =
+				table_info->vddc_dep_on_dal_pwrl;
+	struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table;
+	enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level;
+	uint32_t req_vddc = 0, req_volt, i;
+
+	if (!table && !(dal_power_level >= PP_DAL_POWERLEVEL_ULTRALOW &&
+			dal_power_level <= PP_DAL_POWERLEVEL_PERFORMANCE))
+		return;
+
+	for (i= 0; i < table->count; i++) {
+		if (dal_power_level == table->entries[i].clk) {
+			req_vddc = table->entries[i].v;
+			break;
+		}
+	}
+
+	vddc_table = table_info->vdd_dep_on_sclk;
+	for (i= 0; i < vddc_table->count; i++) {
+		if (req_vddc <= vddc_table->entries[i].vddc) {
+			req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE)
+					<< VDDC_SHIFT;
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_VddC_Request, req_volt);
+			return;
+		}
+	}
+	printk(KERN_ERR "DAL requested level can not"
+			" found a available voltage in VDDC DPM Table \n");
+}
+
+static int fiji_upload_dpmlevel_enable_mask(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	fiji_apply_dal_min_voltage_request(hwmgr);
+
+	if (!data->sclk_dpm_key_disabled) {
+		if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_SCLKDPM_SetEnabledMask,
+					data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+	}
+	return 0;
+}
+
+static int fiji_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if (!fiji_is_dpm_running(hwmgr))
+		return -EINVAL;
+
+	if (!data->pcie_dpm_key_disabled) {
+		smum_send_msg_to_smc(hwmgr->smumgr,
+				PPSMC_MSG_PCIeDPM_UnForceLevel);
+	}
+
+	return fiji_upload_dpmlevel_enable_mask(hwmgr);
+}
+
+static uint32_t fiji_get_lowest_enabled_level(
+		struct pp_hwmgr *hwmgr, uint32_t mask)
+{
+	uint32_t level = 0;
+
+	while(0 == (mask & (1 << level)))
+		level++;
+
+	return level;
+}
+
+static int fiji_force_dpm_lowest(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data =
+			(struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t level;
+
+	if (!data->sclk_dpm_key_disabled)
+		if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+			level = fiji_get_lowest_enabled_level(hwmgr,
+							      data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+							    PPSMC_MSG_SCLKDPM_SetEnabledMask,
+							    (1 << level));
+
+	}
+
+	if (!data->mclk_dpm_key_disabled) {
+		if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+			level = fiji_get_lowest_enabled_level(hwmgr,
+							      data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+							    PPSMC_MSG_MCLKDPM_SetEnabledMask,
+							    (1 << level));
+		}
+	}
+
+	if (!data->pcie_dpm_key_disabled) {
+		if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+			level = fiji_get_lowest_enabled_level(hwmgr,
+							      data->dpm_level_enable_mask.pcie_dpm_enable_mask);
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+							    PPSMC_MSG_PCIeDPM_ForceLevel,
+							    (1 << level));
+		}
+	}
+
+	return 0;
+
+}
+static int fiji_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
+				enum amd_dpm_forced_level level)
+{
+	int ret = 0;
+
+	switch (level) {
+	case AMD_DPM_FORCED_LEVEL_HIGH:
+		ret = fiji_force_dpm_highest(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	case AMD_DPM_FORCED_LEVEL_LOW:
+		ret = fiji_force_dpm_lowest(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	case AMD_DPM_FORCED_LEVEL_AUTO:
+		ret = fiji_unforce_dpm_levels(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	default:
+		break;
+	}
+
+	hwmgr->dpm_level = level;
+
+	return ret;
+}
+
+static int fiji_get_power_state_size(struct pp_hwmgr *hwmgr)
+{
+	return sizeof(struct fiji_power_state);
+}
+
+static int fiji_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
+		void *state, struct pp_power_state *power_state,
+		void *pp_table, uint32_t classification_flag)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_power_state  *fiji_power_state =
+			(struct fiji_power_state *)(&(power_state->hardware));
+	struct fiji_performance_level *performance_level;
+	ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
+	ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
+			(ATOM_Tonga_POWERPLAYTABLE *)pp_table;
+	ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
+			(ATOM_Tonga_SCLK_Dependency_Table *)
+			(((unsigned long)powerplay_table) +
+				le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
+	ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
+			(ATOM_Tonga_MCLK_Dependency_Table *)
+			(((unsigned long)powerplay_table) +
+				le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
+
+	/* The following fields are not initialized here: id orderedList allStatesList */
+	power_state->classification.ui_label =
+			(le16_to_cpu(state_entry->usClassification) &
+			ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
+			ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
+	power_state->classification.flags = classification_flag;
+	/* NOTE: There is a classification2 flag in BIOS that is not being used right now */
+
+	power_state->classification.temporary_state = false;
+	power_state->classification.to_be_deleted = false;
+
+	power_state->validation.disallowOnDC =
+			(0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
+					ATOM_Tonga_DISALLOW_ON_DC));
+
+	power_state->pcie.lanes = 0;
+
+	power_state->display.disableFrameModulation = false;
+	power_state->display.limitRefreshrate = false;
+	power_state->display.enableVariBright =
+			(0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
+					ATOM_Tonga_ENABLE_VARIBRIGHT));
+
+	power_state->validation.supportedPowerLevels = 0;
+	power_state->uvd_clocks.VCLK = 0;
+	power_state->uvd_clocks.DCLK = 0;
+	power_state->temperatures.min = 0;
+	power_state->temperatures.max = 0;
+
+	performance_level = &(fiji_power_state->performance_levels
+			[fiji_power_state->performance_level_count++]);
+
+	PP_ASSERT_WITH_CODE(
+			(fiji_power_state->performance_level_count < SMU73_MAX_LEVELS_GRAPHICS),
+			"Performance levels exceeds SMC limit!",
+			return -1);
+
+	PP_ASSERT_WITH_CODE(
+			(fiji_power_state->performance_level_count <=
+					hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
+			"Performance levels exceeds Driver limit!",
+			return -1);
+
+	/* Performance levels are arranged from low to high. */
+	performance_level->memory_clock = mclk_dep_table->entries
+			[state_entry->ucMemoryClockIndexLow].ulMclk;
+	performance_level->engine_clock = sclk_dep_table->entries
+			[state_entry->ucEngineClockIndexLow].ulSclk;
+	performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
+			state_entry->ucPCIEGenLow);
+	performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
+			state_entry->ucPCIELaneHigh);
+
+	performance_level = &(fiji_power_state->performance_levels
+			[fiji_power_state->performance_level_count++]);
+	performance_level->memory_clock = mclk_dep_table->entries
+			[state_entry->ucMemoryClockIndexHigh].ulMclk;
+	performance_level->engine_clock = sclk_dep_table->entries
+			[state_entry->ucEngineClockIndexHigh].ulSclk;
+	performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
+			state_entry->ucPCIEGenHigh);
+	performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
+			state_entry->ucPCIELaneHigh);
+
+	return 0;
+}
+
+static int fiji_get_pp_table_entry(struct pp_hwmgr *hwmgr,
+		unsigned long entry_index, struct pp_power_state *state)
+{
+	int result;
+	struct fiji_power_state *ps;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
+			table_info->vdd_dep_on_mclk;
+
+	state->hardware.magic = PHM_VIslands_Magic;
+
+	ps = (struct fiji_power_state *)(&state->hardware);
+
+	result = tonga_get_powerplay_table_entry(hwmgr, entry_index, state,
+			fiji_get_pp_table_entry_callback_func);
+
+	/* This is the earliest time we have all the dependency table and the VBIOS boot state
+	 * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
+	 * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
+	 */
+	if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
+		if (dep_mclk_table->entries[0].clk !=
+				data->vbios_boot_state.mclk_bootup_value)
+			printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
+					"does not match VBIOS boot MCLK level");
+		if (dep_mclk_table->entries[0].vddci !=
+				data->vbios_boot_state.vddci_bootup_value)
+			printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
+					"does not match VBIOS boot VDDCI level");
+	}
+
+	/* set DC compatible flag if this state supports DC */
+	if (!state->validation.disallowOnDC)
+		ps->dc_compatible = true;
+
+	if (state->classification.flags & PP_StateClassificationFlag_ACPI)
+		data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
+
+	ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
+	ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
+
+	if (!result) {
+		uint32_t i;
+
+		switch (state->classification.ui_label) {
+		case PP_StateUILabel_Performance:
+			data->use_pcie_performance_levels = true;
+
+			for (i = 0; i < ps->performance_level_count; i++) {
+				if (data->pcie_gen_performance.max <
+						ps->performance_levels[i].pcie_gen)
+					data->pcie_gen_performance.max =
+							ps->performance_levels[i].pcie_gen;
+
+				if (data->pcie_gen_performance.min >
+						ps->performance_levels[i].pcie_gen)
+					data->pcie_gen_performance.min =
+							ps->performance_levels[i].pcie_gen;
+
+				if (data->pcie_lane_performance.max <
+						ps->performance_levels[i].pcie_lane)
+					data->pcie_lane_performance.max =
+							ps->performance_levels[i].pcie_lane;
+
+				if (data->pcie_lane_performance.min >
+						ps->performance_levels[i].pcie_lane)
+					data->pcie_lane_performance.min =
+							ps->performance_levels[i].pcie_lane;
+			}
+			break;
+		case PP_StateUILabel_Battery:
+			data->use_pcie_power_saving_levels = true;
+
+			for (i = 0; i < ps->performance_level_count; i++) {
+				if (data->pcie_gen_power_saving.max <
+						ps->performance_levels[i].pcie_gen)
+					data->pcie_gen_power_saving.max =
+							ps->performance_levels[i].pcie_gen;
+
+				if (data->pcie_gen_power_saving.min >
+						ps->performance_levels[i].pcie_gen)
+					data->pcie_gen_power_saving.min =
+							ps->performance_levels[i].pcie_gen;
+
+				if (data->pcie_lane_power_saving.max <
+						ps->performance_levels[i].pcie_lane)
+					data->pcie_lane_power_saving.max =
+							ps->performance_levels[i].pcie_lane;
+
+				if (data->pcie_lane_power_saving.min >
+						ps->performance_levels[i].pcie_lane)
+					data->pcie_lane_power_saving.min =
+							ps->performance_levels[i].pcie_lane;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+static int fiji_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+				struct pp_power_state  *request_ps,
+			const struct pp_power_state *current_ps)
+{
+	struct fiji_power_state *fiji_ps =
+				cast_phw_fiji_power_state(&request_ps->hardware);
+	uint32_t sclk;
+	uint32_t mclk;
+	struct PP_Clocks minimum_clocks = {0};
+	bool disable_mclk_switching;
+	bool disable_mclk_switching_for_frame_lock;
+	struct cgs_display_info info = {0};
+	const struct phm_clock_and_voltage_limits *max_limits;
+	uint32_t i;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	int32_t count;
+	int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
+
+	data->battery_state = (PP_StateUILabel_Battery ==
+			request_ps->classification.ui_label);
+
+	PP_ASSERT_WITH_CODE(fiji_ps->performance_level_count == 2,
+				 "VI should always have 2 performance levels",);
+
+	max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
+			&(hwmgr->dyn_state.max_clock_voltage_on_ac) :
+			&(hwmgr->dyn_state.max_clock_voltage_on_dc);
+
+	/* Cap clock DPM tables at DC MAX if it is in DC. */
+	if (PP_PowerSource_DC == hwmgr->power_source) {
+		for (i = 0; i < fiji_ps->performance_level_count; i++) {
+			if (fiji_ps->performance_levels[i].memory_clock > max_limits->mclk)
+				fiji_ps->performance_levels[i].memory_clock = max_limits->mclk;
+			if (fiji_ps->performance_levels[i].engine_clock > max_limits->sclk)
+				fiji_ps->performance_levels[i].engine_clock = max_limits->sclk;
+		}
+	}
+
+	fiji_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk;
+	fiji_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk;
+
+	fiji_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+
+	/*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
+
+	/* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_StablePState)) {
+		max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
+		stable_pstate_sclk = (max_limits->sclk * 75) / 100;
+
+		for (count = table_info->vdd_dep_on_sclk->count - 1;
+				count >= 0; count--) {
+			if (stable_pstate_sclk >=
+					table_info->vdd_dep_on_sclk->entries[count].clk) {
+				stable_pstate_sclk =
+						table_info->vdd_dep_on_sclk->entries[count].clk;
+				break;
+			}
+		}
+
+		if (count < 0)
+			stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
+
+		stable_pstate_mclk = max_limits->mclk;
+
+		minimum_clocks.engineClock = stable_pstate_sclk;
+		minimum_clocks.memoryClock = stable_pstate_mclk;
+	}
+
+	if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
+		minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
+
+	if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
+		minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
+
+	fiji_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
+
+	if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
+		PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <=
+				hwmgr->platform_descriptor.overdriveLimit.engineClock),
+				"Overdrive sclk exceeds limit",
+				hwmgr->gfx_arbiter.sclk_over_drive =
+						hwmgr->platform_descriptor.overdriveLimit.engineClock);
+
+		if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
+			fiji_ps->performance_levels[1].engine_clock =
+					hwmgr->gfx_arbiter.sclk_over_drive;
+	}
+
+	if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
+		PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <=
+				hwmgr->platform_descriptor.overdriveLimit.memoryClock),
+				"Overdrive mclk exceeds limit",
+				hwmgr->gfx_arbiter.mclk_over_drive =
+						hwmgr->platform_descriptor.overdriveLimit.memoryClock);
+
+		if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
+			fiji_ps->performance_levels[1].memory_clock =
+					hwmgr->gfx_arbiter.mclk_over_drive;
+	}
+
+	disable_mclk_switching_for_frame_lock = phm_cap_enabled(
+				    hwmgr->platform_descriptor.platformCaps,
+				    PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
+
+	disable_mclk_switching = (1 < info.display_count) ||
+				    disable_mclk_switching_for_frame_lock;
+
+	sclk = fiji_ps->performance_levels[0].engine_clock;
+	mclk = fiji_ps->performance_levels[0].memory_clock;
+
+	if (disable_mclk_switching)
+		mclk = fiji_ps->performance_levels
+		[fiji_ps->performance_level_count - 1].memory_clock;
+
+	if (sclk < minimum_clocks.engineClock)
+		sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
+				max_limits->sclk : minimum_clocks.engineClock;
+
+	if (mclk < minimum_clocks.memoryClock)
+		mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
+				max_limits->mclk : minimum_clocks.memoryClock;
+
+	fiji_ps->performance_levels[0].engine_clock = sclk;
+	fiji_ps->performance_levels[0].memory_clock = mclk;
+
+	fiji_ps->performance_levels[1].engine_clock =
+		(fiji_ps->performance_levels[1].engine_clock >=
+				fiji_ps->performance_levels[0].engine_clock) ?
+						fiji_ps->performance_levels[1].engine_clock :
+						fiji_ps->performance_levels[0].engine_clock;
+
+	if (disable_mclk_switching) {
+		if (mclk < fiji_ps->performance_levels[1].memory_clock)
+			mclk = fiji_ps->performance_levels[1].memory_clock;
+
+		fiji_ps->performance_levels[0].memory_clock = mclk;
+		fiji_ps->performance_levels[1].memory_clock = mclk;
+	} else {
+		if (fiji_ps->performance_levels[1].memory_clock <
+				fiji_ps->performance_levels[0].memory_clock)
+			fiji_ps->performance_levels[1].memory_clock =
+					fiji_ps->performance_levels[0].memory_clock;
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_StablePState)) {
+		for (i = 0; i < fiji_ps->performance_level_count; i++) {
+			fiji_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
+			fiji_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
+			fiji_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
+			fiji_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
+		}
+	}
+
+	return 0;
+}
+
+static int fiji_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
+{
+	const struct phm_set_power_state_input *states =
+			(const struct phm_set_power_state_input *)input;
+	const struct fiji_power_state *fiji_ps =
+			cast_const_phw_fiji_power_state(states->pnew_state);
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
+	uint32_t sclk = fiji_ps->performance_levels
+			[fiji_ps->performance_level_count - 1].engine_clock;
+	struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
+	uint32_t mclk = fiji_ps->performance_levels
+			[fiji_ps->performance_level_count - 1].memory_clock;
+	struct PP_Clocks min_clocks = {0};
+	uint32_t i;
+	struct cgs_display_info info = {0};
+
+	data->need_update_smu7_dpm_table = 0;
+
+	for (i = 0; i < sclk_table->count; i++) {
+		if (sclk == sclk_table->dpm_levels[i].value)
+			break;
+	}
+
+	if (i >= sclk_table->count)
+		data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
+	else {
+	/* TODO: Check SCLK in DAL's minimum clocks
+	 * in case DeepSleep divider update is required.
+	 */
+		if(data->display_timing.min_clock_in_sr != min_clocks.engineClockInSR)
+			data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
+	}
+
+	for (i = 0; i < mclk_table->count; i++) {
+		if (mclk == mclk_table->dpm_levels[i].value)
+			break;
+	}
+
+	if (i >= mclk_table->count)
+		data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+
+	if (data->display_timing.num_existing_displays != info.display_count)
+		data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
+
+	return 0;
+}
+
+static uint16_t fiji_get_maximum_link_speed(struct pp_hwmgr *hwmgr,
+		const struct fiji_power_state *fiji_ps)
+{
+	uint32_t i;
+	uint32_t sclk, max_sclk = 0;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_dpm_table *dpm_table = &data->dpm_table;
+
+	for (i = 0; i < fiji_ps->performance_level_count; i++) {
+		sclk = fiji_ps->performance_levels[i].engine_clock;
+		if (max_sclk < sclk)
+			max_sclk = sclk;
+	}
+
+	for (i = 0; i < dpm_table->sclk_table.count; i++) {
+		if (dpm_table->sclk_table.dpm_levels[i].value == max_sclk)
+			return (uint16_t) ((i >= dpm_table->pcie_speed_table.count) ?
+					dpm_table->pcie_speed_table.dpm_levels
+					[dpm_table->pcie_speed_table.count - 1].value :
+					dpm_table->pcie_speed_table.dpm_levels[i].value);
+	}
+
+	return 0;
+}
+
+static int fiji_request_link_speed_change_before_state_change(
+		struct pp_hwmgr *hwmgr, const void *input)
+{
+	const struct phm_set_power_state_input *states =
+			(const struct phm_set_power_state_input *)input;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	const struct fiji_power_state *fiji_nps =
+			cast_const_phw_fiji_power_state(states->pnew_state);
+	const struct fiji_power_state *fiji_cps =
+			cast_const_phw_fiji_power_state(states->pcurrent_state);
+
+	uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_nps);
+	uint16_t current_link_speed;
+
+	if (data->force_pcie_gen == PP_PCIEGenInvalid)
+		current_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_cps);
+	else
+		current_link_speed = data->force_pcie_gen;
+
+	data->force_pcie_gen = PP_PCIEGenInvalid;
+	data->pspp_notify_required = false;
+	if (target_link_speed > current_link_speed) {
+		switch(target_link_speed) {
+		case PP_PCIEGen3:
+			if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
+				break;
+			data->force_pcie_gen = PP_PCIEGen2;
+			if (current_link_speed == PP_PCIEGen2)
+				break;
+		case PP_PCIEGen2:
+			if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
+				break;
+		default:
+			data->force_pcie_gen = fiji_get_current_pcie_speed(hwmgr);
+			break;
+		}
+	} else {
+		if (target_link_speed < current_link_speed)
+			data->pspp_notify_required = true;
+	}
+
+	return 0;
+}
+
+static int fiji_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if (0 == data->need_update_smu7_dpm_table)
+		return 0;
+
+	if ((0 == data->sclk_dpm_key_disabled) &&
+		(data->need_update_smu7_dpm_table &
+			(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+		PP_ASSERT_WITH_CODE(true == fiji_is_dpm_running(hwmgr),
+				"Trying to freeze SCLK DPM when DPM is disabled",);
+		PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+				PPSMC_MSG_SCLKDPM_FreezeLevel),
+				"Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
+				return -1);
+	}
+
+	if ((0 == data->mclk_dpm_key_disabled) &&
+		(data->need_update_smu7_dpm_table &
+		 DPMTABLE_OD_UPDATE_MCLK)) {
+		PP_ASSERT_WITH_CODE(true == fiji_is_dpm_running(hwmgr),
+				"Trying to freeze MCLK DPM when DPM is disabled",);
+		PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+				PPSMC_MSG_MCLKDPM_FreezeLevel),
+				"Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
+				return -1);
+	}
+
+	return 0;
+}
+
+static int fiji_populate_and_upload_sclk_mclk_dpm_levels(
+		struct pp_hwmgr *hwmgr, const void *input)
+{
+	int result = 0;
+	const struct phm_set_power_state_input *states =
+			(const struct phm_set_power_state_input *)input;
+	const struct fiji_power_state *fiji_ps =
+			cast_const_phw_fiji_power_state(states->pnew_state);
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t sclk = fiji_ps->performance_levels
+			[fiji_ps->performance_level_count - 1].engine_clock;
+	uint32_t mclk = fiji_ps->performance_levels
+			[fiji_ps->performance_level_count - 1].memory_clock;
+	struct fiji_dpm_table *dpm_table = &data->dpm_table;
+
+	struct fiji_dpm_table *golden_dpm_table = &data->golden_dpm_table;
+	uint32_t dpm_count, clock_percent;
+	uint32_t i;
+
+	if (0 == data->need_update_smu7_dpm_table)
+		return 0;
+
+	if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
+		dpm_table->sclk_table.dpm_levels
+		[dpm_table->sclk_table.count - 1].value = sclk;
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_OD6PlusinACSupport) ||
+			phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_OD6PlusinDCSupport)) {
+		/* Need to do calculation based on the golden DPM table
+		 * as the Heatmap GPU Clock axis is also based on the default values
+		 */
+			PP_ASSERT_WITH_CODE(
+				(golden_dpm_table->sclk_table.dpm_levels
+						[golden_dpm_table->sclk_table.count - 1].value != 0),
+				"Divide by 0!",
+				return -1);
+			dpm_count = dpm_table->sclk_table.count < 2 ?
+					0 : dpm_table->sclk_table.count - 2;
+			for (i = dpm_count; i > 1; i--) {
+				if (sclk > golden_dpm_table->sclk_table.dpm_levels
+						[golden_dpm_table->sclk_table.count-1].value) {
+					clock_percent =
+						((sclk - golden_dpm_table->sclk_table.dpm_levels
+							[golden_dpm_table->sclk_table.count-1].value) * 100) /
+						golden_dpm_table->sclk_table.dpm_levels
+							[golden_dpm_table->sclk_table.count-1].value;
+
+					dpm_table->sclk_table.dpm_levels[i].value =
+							golden_dpm_table->sclk_table.dpm_levels[i].value +
+							(golden_dpm_table->sclk_table.dpm_levels[i].value *
+								clock_percent)/100;
+
+				} else if (golden_dpm_table->sclk_table.dpm_levels
+						[dpm_table->sclk_table.count-1].value > sclk) {
+					clock_percent =
+						((golden_dpm_table->sclk_table.dpm_levels
+						[golden_dpm_table->sclk_table.count - 1].value - sclk) *
+								100) /
+						golden_dpm_table->sclk_table.dpm_levels
+							[golden_dpm_table->sclk_table.count-1].value;
+
+					dpm_table->sclk_table.dpm_levels[i].value =
+							golden_dpm_table->sclk_table.dpm_levels[i].value -
+							(golden_dpm_table->sclk_table.dpm_levels[i].value *
+									clock_percent) / 100;
+				} else
+					dpm_table->sclk_table.dpm_levels[i].value =
+							golden_dpm_table->sclk_table.dpm_levels[i].value;
+			}
+		}
+	}
+
+	if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
+		dpm_table->mclk_table.dpm_levels
+			[dpm_table->mclk_table.count - 1].value = mclk;
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_OD6PlusinACSupport) ||
+			phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_OD6PlusinDCSupport)) {
+
+			PP_ASSERT_WITH_CODE(
+					(golden_dpm_table->mclk_table.dpm_levels
+						[golden_dpm_table->mclk_table.count-1].value != 0),
+					"Divide by 0!",
+					return -1);
+			dpm_count = dpm_table->mclk_table.count < 2 ?
+					0 : dpm_table->mclk_table.count - 2;
+			for (i = dpm_count; i > 1; i--) {
+				if (mclk > golden_dpm_table->mclk_table.dpm_levels
+						[golden_dpm_table->mclk_table.count-1].value) {
+					clock_percent = ((mclk -
+							golden_dpm_table->mclk_table.dpm_levels
+							[golden_dpm_table->mclk_table.count-1].value) * 100) /
+							golden_dpm_table->mclk_table.dpm_levels
+							[golden_dpm_table->mclk_table.count-1].value;
+
+					dpm_table->mclk_table.dpm_levels[i].value =
+							golden_dpm_table->mclk_table.dpm_levels[i].value +
+							(golden_dpm_table->mclk_table.dpm_levels[i].value *
+									clock_percent) / 100;
+
+				} else if (golden_dpm_table->mclk_table.dpm_levels
+						[dpm_table->mclk_table.count-1].value > mclk) {
+					clock_percent = ((golden_dpm_table->mclk_table.dpm_levels
+							[golden_dpm_table->mclk_table.count-1].value - mclk) * 100) /
+									golden_dpm_table->mclk_table.dpm_levels
+									[golden_dpm_table->mclk_table.count-1].value;
+
+					dpm_table->mclk_table.dpm_levels[i].value =
+							golden_dpm_table->mclk_table.dpm_levels[i].value -
+							(golden_dpm_table->mclk_table.dpm_levels[i].value *
+									clock_percent) / 100;
+				} else
+					dpm_table->mclk_table.dpm_levels[i].value =
+							golden_dpm_table->mclk_table.dpm_levels[i].value;
+			}
+		}
+	}
+
+	if (data->need_update_smu7_dpm_table &
+			(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
+		result = fiji_populate_all_memory_levels(hwmgr);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
+				return result);
+	}
+
+	if (data->need_update_smu7_dpm_table &
+			(DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
+		/*populate MCLK dpm table to SMU7 */
+		result = fiji_populate_all_memory_levels(hwmgr);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
+				return result);
+	}
+
+	return result;
+}
+
+static int fiji_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
+			  struct fiji_single_dpm_table * dpm_table,
+			     uint32_t low_limit, uint32_t high_limit)
+{
+	uint32_t i;
+
+	for (i = 0; i < dpm_table->count; i++) {
+		if ((dpm_table->dpm_levels[i].value < low_limit) ||
+		    (dpm_table->dpm_levels[i].value > high_limit))
+			dpm_table->dpm_levels[i].enabled = false;
+		else
+			dpm_table->dpm_levels[i].enabled = true;
+	}
+	return 0;
+}
+
+static int fiji_trim_dpm_states(struct pp_hwmgr *hwmgr,
+		const struct fiji_power_state *fiji_ps)
+{
+	int result = 0;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t high_limit_count;
+
+	PP_ASSERT_WITH_CODE((fiji_ps->performance_level_count >= 1),
+			"power state did not have any performance level",
+			return -1);
+
+	high_limit_count = (1 == fiji_ps->performance_level_count) ? 0 : 1;
+
+	fiji_trim_single_dpm_states(hwmgr,
+			&(data->dpm_table.sclk_table),
+			fiji_ps->performance_levels[0].engine_clock,
+			fiji_ps->performance_levels[high_limit_count].engine_clock);
+
+	fiji_trim_single_dpm_states(hwmgr,
+			&(data->dpm_table.mclk_table),
+			fiji_ps->performance_levels[0].memory_clock,
+			fiji_ps->performance_levels[high_limit_count].memory_clock);
+
+	return result;
+}
+
+static int fiji_generate_dpm_level_enable_mask(
+		struct pp_hwmgr *hwmgr, const void *input)
+{
+	int result;
+	const struct phm_set_power_state_input *states =
+			(const struct phm_set_power_state_input *)input;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	const struct fiji_power_state *fiji_ps =
+			cast_const_phw_fiji_power_state(states->pnew_state);
+
+	result = fiji_trim_dpm_states(hwmgr, fiji_ps);
+	if (result)
+		return result;
+
+	data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+			fiji_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
+	data->dpm_level_enable_mask.mclk_dpm_enable_mask =
+			fiji_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
+	data->last_mclk_dpm_enable_mask =
+			data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+
+	if (data->uvd_enabled) {
+		if (data->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
+			data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
+	}
+
+	data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+			fiji_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
+
+	return 0;
+}
+
+int fiji_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+	return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+				  (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
+				  (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
+}
+
+int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+	return smum_send_msg_to_smc(hwmgr->smumgr, enable?
+			PPSMC_MSG_VCEDPM_Enable :
+			PPSMC_MSG_VCEDPM_Disable);
+}
+
+int fiji_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+	return smum_send_msg_to_smc(hwmgr->smumgr, enable?
+			PPSMC_MSG_SAMUDPM_Enable :
+			PPSMC_MSG_SAMUDPM_Disable);
+}
+
+int fiji_enable_disable_acp_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+	return smum_send_msg_to_smc(hwmgr->smumgr, enable?
+			PPSMC_MSG_ACPDPM_Enable :
+			PPSMC_MSG_ACPDPM_Disable);
+}
+
+int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t mm_boot_level_offset, mm_boot_level_value;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (!bgate) {
+		data->smc_state_table.UvdBootLevel = 0;
+		if (table_info->mm_dep_table->count > 0)
+			data->smc_state_table.UvdBootLevel =
+					(uint8_t) (table_info->mm_dep_table->count - 1);
+		mm_boot_level_offset = data->dpm_table_start +
+				offsetof(SMU73_Discrete_DpmTable, UvdBootLevel);
+		mm_boot_level_offset /= 4;
+		mm_boot_level_offset *= 4;
+		mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+				CGS_IND_REG__SMC, mm_boot_level_offset);
+		mm_boot_level_value &= 0x00FFFFFF;
+		mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
+		cgs_write_ind_register(hwmgr->device,
+				CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+		if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_UVDDPM) ||
+			phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_StablePState))
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_UVDDPM_SetEnabledMask,
+					(uint32_t)(1 << data->smc_state_table.UvdBootLevel));
+	}
+
+	return fiji_enable_disable_uvd_dpm(hwmgr, !bgate);
+}
+
+int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
+{
+	const struct phm_set_power_state_input *states =
+			(const struct phm_set_power_state_input *)input;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	const struct fiji_power_state *fiji_nps =
+			cast_const_phw_fiji_power_state(states->pnew_state);
+	const struct fiji_power_state *fiji_cps =
+			cast_const_phw_fiji_power_state(states->pcurrent_state);
+
+	uint32_t mm_boot_level_offset, mm_boot_level_value;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (fiji_nps->vce_clks.evclk >0 &&
+	(fiji_cps == NULL || fiji_cps->vce_clks.evclk == 0)) {
+		data->smc_state_table.VceBootLevel =
+				(uint8_t) (table_info->mm_dep_table->count - 1);
+
+		mm_boot_level_offset = data->dpm_table_start +
+				offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
+		mm_boot_level_offset /= 4;
+		mm_boot_level_offset *= 4;
+		mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+				CGS_IND_REG__SMC, mm_boot_level_offset);
+		mm_boot_level_value &= 0xFF00FFFF;
+		mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
+		cgs_write_ind_register(hwmgr->device,
+				CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_StablePState)) {
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_VCEDPM_SetEnabledMask,
+					(uint32_t)1 << data->smc_state_table.VceBootLevel);
+
+			fiji_enable_disable_vce_dpm(hwmgr, true);
+		} else if (fiji_nps->vce_clks.evclk == 0 &&
+				fiji_cps != NULL &&
+				fiji_cps->vce_clks.evclk > 0)
+			fiji_enable_disable_vce_dpm(hwmgr, false);
+	}
+
+	return 0;
+}
+
+int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t mm_boot_level_offset, mm_boot_level_value;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (!bgate) {
+		data->smc_state_table.SamuBootLevel =
+				(uint8_t) (table_info->mm_dep_table->count - 1);
+		mm_boot_level_offset = data->dpm_table_start +
+				offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
+		mm_boot_level_offset /= 4;
+		mm_boot_level_offset *= 4;
+		mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+				CGS_IND_REG__SMC, mm_boot_level_offset);
+		mm_boot_level_value &= 0xFFFFFF00;
+		mm_boot_level_value |= data->smc_state_table.SamuBootLevel << 0;
+		cgs_write_ind_register(hwmgr->device,
+				CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_StablePState))
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_SAMUDPM_SetEnabledMask,
+					(uint32_t)(1 << data->smc_state_table.SamuBootLevel));
+	}
+
+	return fiji_enable_disable_samu_dpm(hwmgr, !bgate);
+}
+
+int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t mm_boot_level_offset, mm_boot_level_value;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (!bgate) {
+		data->smc_state_table.AcpBootLevel =
+				(uint8_t) (table_info->mm_dep_table->count - 1);
+		mm_boot_level_offset = data->dpm_table_start +
+				offsetof(SMU73_Discrete_DpmTable, AcpBootLevel);
+		mm_boot_level_offset /= 4;
+		mm_boot_level_offset *= 4;
+		mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+				CGS_IND_REG__SMC, mm_boot_level_offset);
+		mm_boot_level_value &= 0xFFFF00FF;
+		mm_boot_level_value |= data->smc_state_table.AcpBootLevel << 8;
+		cgs_write_ind_register(hwmgr->device,
+				CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_StablePState))
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_ACPDPM_SetEnabledMask,
+						(uint32_t)(1 << data->smc_state_table.AcpBootLevel));
+	}
+
+	return fiji_enable_disable_acp_dpm(hwmgr, !bgate);
+}
+
+static int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	int result = 0;
+	uint32_t low_sclk_interrupt_threshold = 0;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_SclkThrottleLowNotification)
+		&& (hwmgr->gfx_arbiter.sclk_threshold !=
+				data->low_sclk_interrupt_threshold)) {
+		data->low_sclk_interrupt_threshold =
+				hwmgr->gfx_arbiter.sclk_threshold;
+		low_sclk_interrupt_threshold =
+				data->low_sclk_interrupt_threshold;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
+
+		result = fiji_copy_bytes_to_smc(
+				hwmgr->smumgr,
+				data->dpm_table_start +
+				offsetof(SMU73_Discrete_DpmTable,
+					LowSclkInterruptThreshold),
+				(uint8_t *)&low_sclk_interrupt_threshold,
+				sizeof(uint32_t),
+				data->sram_end);
+	}
+
+	return result;
+}
+
+static int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if (data->need_update_smu7_dpm_table &
+		(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+		return fiji_program_memory_timing_parameters(hwmgr);
+
+	return 0;
+}
+
+static int fiji_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if (0 == data->need_update_smu7_dpm_table)
+		return 0;
+
+	if ((0 == data->sclk_dpm_key_disabled) &&
+		(data->need_update_smu7_dpm_table &
+		(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+
+		PP_ASSERT_WITH_CODE(true == fiji_is_dpm_running(hwmgr),
+				"Trying to Unfreeze SCLK DPM when DPM is disabled",);
+		PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+				PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+			"Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
+			return -1);
+	}
+
+	if ((0 == data->mclk_dpm_key_disabled) &&
+		(data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
+
+		PP_ASSERT_WITH_CODE(true == fiji_is_dpm_running(hwmgr),
+				"Trying to Unfreeze MCLK DPM when DPM is disabled",);
+		PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+				PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+		    "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
+		    return -1);
+	}
+
+	data->need_update_smu7_dpm_table = 0;
+
+	return 0;
+}
+
+/* Look up the voltaged based on DAL's requested level.
+ * and then send the requested VDDC voltage to SMC
+ */
+static void fiji_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
+{
+	return;
+}
+
+int fiji_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
+{
+	int result;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	/* Apply minimum voltage based on DAL's request level */
+	fiji_apply_dal_minimum_voltage_request(hwmgr);
+
+	if (0 == data->sclk_dpm_key_disabled) {
+		/* Checking if DPM is running.  If we discover hang because of this,
+		 *  we should skip this message.
+		 */
+		if (!fiji_is_dpm_running(hwmgr))
+			printk(KERN_ERR "[ powerplay ] "
+					"Trying to set Enable Mask when DPM is disabled \n");
+
+		if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+			result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_SCLKDPM_SetEnabledMask,
+					data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+			PP_ASSERT_WITH_CODE((0 == result),
+				"Set Sclk Dpm enable Mask failed", return -1);
+		}
+	}
+
+	if (0 == data->mclk_dpm_key_disabled) {
+		/* Checking if DPM is running.  If we discover hang because of this,
+		 *  we should skip this message.
+		 */
+		if (!fiji_is_dpm_running(hwmgr))
+			printk(KERN_ERR "[ powerplay ]"
+					" Trying to set Enable Mask when DPM is disabled \n");
+
+		if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+			result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_MCLKDPM_SetEnabledMask,
+					data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+			PP_ASSERT_WITH_CODE((0 == result),
+				"Set Mclk Dpm enable Mask failed", return -1);
+		}
+	}
+
+	return 0;
+}
+
+static int fiji_notify_link_speed_change_after_state_change(
+		struct pp_hwmgr *hwmgr, const void *input)
+{
+	const struct phm_set_power_state_input *states =
+			(const struct phm_set_power_state_input *)input;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	const struct fiji_power_state *fiji_ps =
+			cast_const_phw_fiji_power_state(states->pnew_state);
+	uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_ps);
+	uint8_t  request;
+
+	if (data->pspp_notify_required) {
+		if (target_link_speed == PP_PCIEGen3)
+			request = PCIE_PERF_REQ_GEN3;
+		else if (target_link_speed == PP_PCIEGen2)
+			request = PCIE_PERF_REQ_GEN2;
+		else
+			request = PCIE_PERF_REQ_GEN1;
+
+		if(request == PCIE_PERF_REQ_GEN1 &&
+				fiji_get_current_pcie_speed(hwmgr) > 0)
+			return 0;
+
+		if (acpi_pcie_perf_request(hwmgr->device, request, false)) {
+			if (PP_PCIEGen2 == target_link_speed)
+				printk("PSPP request to switch to Gen2 from Gen3 Failed!");
+			else
+				printk("PSPP request to switch to Gen1 from Gen2 Failed!");
+		}
+	}
+
+	return 0;
+}
+
+static int fiji_set_power_state_tasks(struct pp_hwmgr *hwmgr,
+		const void *input)
+{
+	int tmp_result, result = 0;
+
+	tmp_result = fiji_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to find DPM states clocks in DPM table!",
+			result = tmp_result);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_PCIEPerformanceRequest)) {
+		tmp_result =
+			fiji_request_link_speed_change_before_state_change(hwmgr, input);
+		PP_ASSERT_WITH_CODE((0 == tmp_result),
+				"Failed to request link speed change before state change!",
+				result = tmp_result);
+	}
+
+	tmp_result = fiji_freeze_sclk_mclk_dpm(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to freeze SCLK MCLK DPM!", result = tmp_result);
+
+	tmp_result = fiji_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to populate and upload SCLK MCLK DPM levels!",
+			result = tmp_result);
+
+	tmp_result = fiji_generate_dpm_level_enable_mask(hwmgr, input);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to generate DPM level enabled mask!",
+			result = tmp_result);
+
+	tmp_result = fiji_update_vce_dpm(hwmgr, input);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to update VCE DPM!",
+			result = tmp_result);
+
+	tmp_result = fiji_update_sclk_threshold(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to update SCLK threshold!",
+			result = tmp_result);
+
+	tmp_result = fiji_program_mem_timing_parameters(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to program memory timing parameters!",
+			result = tmp_result);
+
+	tmp_result = fiji_unfreeze_sclk_mclk_dpm(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to unfreeze SCLK MCLK DPM!",
+			result = tmp_result);
+
+	tmp_result = fiji_upload_dpm_level_enable_mask(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to upload DPM level enabled mask!",
+			result = tmp_result);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_PCIEPerformanceRequest)) {
+		tmp_result =
+			fiji_notify_link_speed_change_after_state_change(hwmgr, input);
+		PP_ASSERT_WITH_CODE((0 == tmp_result),
+				"Failed to notify link speed change after state change!",
+				result = tmp_result);
+	}
+
+	return result;
+}
+
+static int fiji_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
+{
+	struct pp_power_state  *ps;
+	struct fiji_power_state  *fiji_ps;
+
+	if (hwmgr == NULL)
+		return -EINVAL;
+
+	ps = hwmgr->request_ps;
+
+	if (ps == NULL)
+		return -EINVAL;
+
+	fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
+
+	if (low)
+		return fiji_ps->performance_levels[0].engine_clock;
+	else
+		return fiji_ps->performance_levels
+				[fiji_ps->performance_level_count-1].engine_clock;
+}
+
+static int fiji_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
+{
+	struct pp_power_state  *ps;
+	struct fiji_power_state  *fiji_ps;
+
+	if (hwmgr == NULL)
+		return -EINVAL;
+
+	ps = hwmgr->request_ps;
+
+	if (ps == NULL)
+		return -EINVAL;
+
+	fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
+
+	if (low)
+		return fiji_ps->performance_levels[0].memory_clock;
+	else
+		return fiji_ps->performance_levels
+				[fiji_ps->performance_level_count-1].memory_clock;
+}
+
+static void fiji_print_current_perforce_level(
+		struct pp_hwmgr *hwmgr, struct seq_file *m)
+{
+	uint32_t sclk, mclk, activity_percent = 0;
+	uint32_t offset;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
+
+	sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+
+	smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
+
+	mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+	seq_printf(m, "\n [  mclk  ]: %u MHz\n\n [  sclk  ]: %u MHz\n",
+			mclk / 100, sclk / 100);
+
+	offset = data->soft_regs_start + offsetof(SMU73_SoftRegisters, AverageGraphicsActivity);
+	activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
+	activity_percent += 0x80;
+	activity_percent >>= 8;
+
+	seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
+}
+
+static int fiji_program_display_gap(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t num_active_displays = 0;
+	uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
+			CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
+	uint32_t display_gap2;
+	uint32_t pre_vbi_time_in_us;
+	uint32_t frame_time_in_us;
+	uint32_t ref_clock;
+	uint32_t refresh_rate = 0;
+	struct cgs_display_info info = {0};
+	struct cgs_mode_info mode_info;
+
+	info.mode_info = &mode_info;
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+	num_active_displays = info.display_count;
+
+	display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
+			DISP_GAP, (num_active_displays > 0)?
+			DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_DISPLAY_GAP_CNTL, display_gap);
+
+	ref_clock = mode_info.ref_clock;
+	refresh_rate = mode_info.refresh_rate;
+
+	if (refresh_rate == 0)
+		refresh_rate = 60;
+
+	frame_time_in_us = 1000000 / refresh_rate;
+
+	pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
+	display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_DISPLAY_GAP_CNTL2, display_gap2);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			data->soft_regs_start +
+			offsetof(SMU73_SoftRegisters, PreVBlankGap), 0x64);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			data->soft_regs_start +
+			offsetof(SMU73_SoftRegisters, VBlankTimeout),
+			(frame_time_in_us - pre_vbi_time_in_us));
+
+	if (num_active_displays == 1)
+		tonga_notify_smc_display_change(hwmgr, true);
+
+	return 0;
+}
+
+int fiji_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
+{
+	return fiji_program_display_gap(hwmgr);
+}
+
+static int fiji_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr,
+		uint16_t us_max_fan_pwm)
+{
+	hwmgr->thermal_controller.
+	advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
+
+	if (phm_is_hw_access_blocked(hwmgr))
+		return 0;
+
+	return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+			PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
+}
+
+static int fiji_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr,
+		uint16_t us_max_fan_rpm)
+{
+	hwmgr->thermal_controller.
+	advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
+
+	if (phm_is_hw_access_blocked(hwmgr))
+		return 0;
+
+	return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+			PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
+}
+
+int fiji_dpm_set_interrupt_state(void *private_data,
+					 unsigned src_id, unsigned type,
+					 int enabled)
+{
+	uint32_t cg_thermal_int;
+	struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
+
+	if (hwmgr == NULL)
+		return -EINVAL;
+
+	switch (type) {
+	case AMD_THERMAL_IRQ_LOW_TO_HIGH:
+		if (enabled) {
+			cg_thermal_int = cgs_read_ind_register(hwmgr->device,
+					CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+			cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+			cgs_write_ind_register(hwmgr->device,
+					CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+		} else {
+			cg_thermal_int = cgs_read_ind_register(hwmgr->device,
+					CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+			cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+			cgs_write_ind_register(hwmgr->device,
+					CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+		}
+		break;
+
+	case AMD_THERMAL_IRQ_HIGH_TO_LOW:
+		if (enabled) {
+			cg_thermal_int = cgs_read_ind_register(hwmgr->device,
+					CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+			cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+			cgs_write_ind_register(hwmgr->device,
+					CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+		} else {
+			cg_thermal_int = cgs_read_ind_register(hwmgr->device,
+					CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+			cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+			cgs_write_ind_register(hwmgr->device,
+					CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+int fiji_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
+					const void *thermal_interrupt_info)
+{
+	int result;
+	const struct pp_interrupt_registration_info *info =
+			(const struct pp_interrupt_registration_info *)
+			thermal_interrupt_info;
+
+	if (info == NULL)
+		return -EINVAL;
+
+	result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
+				fiji_dpm_set_interrupt_state,
+				info->call_back, info->context);
+
+	if (result)
+		return -EINVAL;
+
+	result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
+				fiji_dpm_set_interrupt_state,
+				info->call_back, info->context);
+
+	if (result)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int fiji_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+	if (mode) {
+		/* stop auto-manage */
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_MicrocodeFanControl))
+			fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
+		fiji_fan_ctrl_set_static_mode(hwmgr, mode);
+	} else
+		/* restart auto-manage */
+		fiji_fan_ctrl_reset_fan_speed_to_default(hwmgr);
+
+	return 0;
+}
+
+static int fiji_get_fan_control_mode(struct pp_hwmgr *hwmgr)
+{
+	if (hwmgr->fan_ctrl_is_in_default_mode)
+		return hwmgr->fan_ctrl_default_mode;
+	else
+		return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				CG_FDO_CTRL2, FDO_PWM_MODE);
+}
+
+static const struct pp_hwmgr_func fiji_hwmgr_funcs = {
+	.backend_init = &fiji_hwmgr_backend_init,
+	.backend_fini = &tonga_hwmgr_backend_fini,
+	.asic_setup = &fiji_setup_asic_task,
+	.dynamic_state_management_enable = &fiji_enable_dpm_tasks,
+	.force_dpm_level = &fiji_dpm_force_dpm_level,
+	.get_num_of_pp_table_entries = &tonga_get_number_of_powerplay_table_entries,
+	.get_power_state_size = &fiji_get_power_state_size,
+	.get_pp_table_entry = &fiji_get_pp_table_entry,
+	.patch_boot_state = &fiji_patch_boot_state,
+	.apply_state_adjust_rules = &fiji_apply_state_adjust_rules,
+	.power_state_set = &fiji_set_power_state_tasks,
+	.get_sclk = &fiji_dpm_get_sclk,
+	.get_mclk = &fiji_dpm_get_mclk,
+	.print_current_perforce_level = &fiji_print_current_perforce_level,
+	.powergate_uvd = &fiji_phm_powergate_uvd,
+	.powergate_vce = &fiji_phm_powergate_vce,
+	.disable_clock_power_gating = &fiji_phm_disable_clock_power_gating,
+	.notify_smc_display_config_after_ps_adjustment =
+			&tonga_notify_smc_display_config_after_ps_adjustment,
+	.display_config_changed = &fiji_display_configuration_changed_task,
+	.set_max_fan_pwm_output = fiji_set_max_fan_pwm_output,
+	.set_max_fan_rpm_output = fiji_set_max_fan_rpm_output,
+	.get_temperature = fiji_thermal_get_temperature,
+	.stop_thermal_controller = fiji_thermal_stop_thermal_controller,
+	.get_fan_speed_info = fiji_fan_ctrl_get_fan_speed_info,
+	.get_fan_speed_percent = fiji_fan_ctrl_get_fan_speed_percent,
+	.set_fan_speed_percent = fiji_fan_ctrl_set_fan_speed_percent,
+	.reset_fan_speed_to_default = fiji_fan_ctrl_reset_fan_speed_to_default,
+	.get_fan_speed_rpm = fiji_fan_ctrl_get_fan_speed_rpm,
+	.set_fan_speed_rpm = fiji_fan_ctrl_set_fan_speed_rpm,
+	.uninitialize_thermal_controller = fiji_thermal_ctrl_uninitialize_thermal_controller,
+	.register_internal_thermal_interrupt = fiji_register_internal_thermal_interrupt,
+	.set_fan_control_mode = fiji_set_fan_control_mode,
+	.get_fan_control_mode = fiji_get_fan_control_mode,
+};
+
+int fiji_hwmgr_init(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr  *data;
+	int ret = 0;
+
+	data = kzalloc(sizeof(struct fiji_hwmgr), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	hwmgr->backend = data;
+	hwmgr->hwmgr_func = &fiji_hwmgr_funcs;
+	hwmgr->pptable_func = &tonga_pptable_funcs;
+	pp_fiji_thermal_initialize(hwmgr);
+	return ret;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _FIJI_HWMGR_H_
+#define _FIJI_HWMGR_H_
+
+#include "hwmgr.h"
+#include "smu73.h"
+#include "smu73_discrete.h"
+#include "ppatomctrl.h"
+#include "fiji_ppsmc.h"
+
+#define FIJI_MAX_HARDWARE_POWERLEVELS	2
+#define FIJI_AT_DFLT	30
+
+#define FIJI_VOLTAGE_CONTROL_NONE                   0x0
+#define FIJI_VOLTAGE_CONTROL_BY_GPIO                0x1
+#define FIJI_VOLTAGE_CONTROL_BY_SVID2               0x2
+#define FIJI_VOLTAGE_CONTROL_MERGED                 0x3
+
+#define DPMTABLE_OD_UPDATE_SCLK     0x00000001
+#define DPMTABLE_OD_UPDATE_MCLK     0x00000002
+#define DPMTABLE_UPDATE_SCLK        0x00000004
+#define DPMTABLE_UPDATE_MCLK        0x00000008
+
+struct fiji_performance_level {
+	uint32_t  memory_clock;
+	uint32_t  engine_clock;
+	uint16_t  pcie_gen;
+	uint16_t  pcie_lane;
+};
+
+struct fiji_uvd_clocks {
+	uint32_t  vclk;
+	uint32_t  dclk;
+};
+
+struct fiji_vce_clocks {
+	uint32_t  evclk;
+	uint32_t  ecclk;
+};
+
+struct fiji_power_state {
+    uint32_t                  magic;
+    struct fiji_uvd_clocks    uvd_clks;
+    struct fiji_vce_clocks    vce_clks;
+    uint32_t                  sam_clk;
+    uint32_t                  acp_clk;
+    uint16_t                  performance_level_count;
+    bool                      dc_compatible;
+    uint32_t                  sclk_threshold;
+    struct fiji_performance_level  performance_levels[FIJI_MAX_HARDWARE_POWERLEVELS];
+};
+
+struct fiji_dpm_level {
+	bool	enabled;
+    uint32_t	value;
+    uint32_t	param1;
+};
+
+#define FIJI_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define MAX_REGULAR_DPM_NUMBER 8
+#define FIJI_MINIMUM_ENGINE_CLOCK 2500
+
+struct fiji_single_dpm_table {
+	uint32_t		count;
+	struct fiji_dpm_level	dpm_levels[MAX_REGULAR_DPM_NUMBER];
+};
+
+struct fiji_dpm_table {
+	struct fiji_single_dpm_table  sclk_table;
+	struct fiji_single_dpm_table  mclk_table;
+	struct fiji_single_dpm_table  pcie_speed_table;
+	struct fiji_single_dpm_table  vddc_table;
+	struct fiji_single_dpm_table  vddci_table;
+	struct fiji_single_dpm_table  mvdd_table;
+};
+
+struct fiji_clock_registers {
+	uint32_t  vCG_SPLL_FUNC_CNTL;
+	uint32_t  vCG_SPLL_FUNC_CNTL_2;
+	uint32_t  vCG_SPLL_FUNC_CNTL_3;
+	uint32_t  vCG_SPLL_FUNC_CNTL_4;
+	uint32_t  vCG_SPLL_SPREAD_SPECTRUM;
+	uint32_t  vCG_SPLL_SPREAD_SPECTRUM_2;
+	uint32_t  vDLL_CNTL;
+	uint32_t  vMCLK_PWRMGT_CNTL;
+	uint32_t  vMPLL_AD_FUNC_CNTL;
+	uint32_t  vMPLL_DQ_FUNC_CNTL;
+	uint32_t  vMPLL_FUNC_CNTL;
+	uint32_t  vMPLL_FUNC_CNTL_1;
+	uint32_t  vMPLL_FUNC_CNTL_2;
+	uint32_t  vMPLL_SS1;
+	uint32_t  vMPLL_SS2;
+};
+
+struct fiji_voltage_smio_registers {
+	uint32_t vS0_VID_LOWER_SMIO_CNTL;
+};
+
+#define FIJI_MAX_LEAKAGE_COUNT  8
+struct fiji_leakage_voltage {
+	uint16_t  count;
+	uint16_t  leakage_id[FIJI_MAX_LEAKAGE_COUNT];
+	uint16_t  actual_voltage[FIJI_MAX_LEAKAGE_COUNT];
+};
+
+struct fiji_vbios_boot_state {
+	uint16_t    mvdd_bootup_value;
+	uint16_t    vddc_bootup_value;
+	uint16_t    vddci_bootup_value;
+	uint32_t    sclk_bootup_value;
+	uint32_t    mclk_bootup_value;
+	uint16_t    pcie_gen_bootup_value;
+	uint16_t    pcie_lane_bootup_value;
+};
+
+struct fiji_bacos {
+	uint32_t                       best_match;
+	uint32_t                       baco_flags;
+	struct fiji_performance_level  performance_level;
+};
+
+/* Ultra Low Voltage parameter structure */
+struct fiji_ulv_parm {
+	bool                           ulv_supported;
+	uint32_t                       cg_ulv_parameter;
+	uint32_t                       ulv_volt_change_delay;
+	struct fiji_performance_level  ulv_power_level;
+};
+
+struct fiji_display_timing {
+	uint32_t  min_clock_in_sr;
+	uint32_t  num_existing_displays;
+};
+
+struct fiji_dpmlevel_enable_mask {
+	uint32_t  uvd_dpm_enable_mask;
+	uint32_t  vce_dpm_enable_mask;
+	uint32_t  acp_dpm_enable_mask;
+	uint32_t  samu_dpm_enable_mask;
+	uint32_t  sclk_dpm_enable_mask;
+	uint32_t  mclk_dpm_enable_mask;
+	uint32_t  pcie_dpm_enable_mask;
+};
+
+struct fiji_pcie_perf_range {
+	uint16_t  max;
+	uint16_t  min;
+};
+
+struct fiji_hwmgr {
+	struct fiji_dpm_table			dpm_table;
+	struct fiji_dpm_table			golden_dpm_table;
+
+	uint32_t						voting_rights_clients0;
+	uint32_t						voting_rights_clients1;
+	uint32_t						voting_rights_clients2;
+	uint32_t						voting_rights_clients3;
+	uint32_t						voting_rights_clients4;
+	uint32_t						voting_rights_clients5;
+	uint32_t						voting_rights_clients6;
+	uint32_t						voting_rights_clients7;
+	uint32_t						static_screen_threshold_unit;
+	uint32_t						static_screen_threshold;
+	uint32_t						voltage_control;
+	uint32_t						vddc_vddci_delta;
+
+	uint32_t						active_auto_throttle_sources;
+
+	struct fiji_clock_registers            clock_registers;
+	struct fiji_voltage_smio_registers      voltage_smio_registers;
+
+	bool                           is_memory_gddr5;
+	uint16_t                       acpi_vddc;
+	bool                           pspp_notify_required;
+	uint16_t                       force_pcie_gen;
+	uint16_t                       acpi_pcie_gen;
+	uint32_t                       pcie_gen_cap;
+	uint32_t                       pcie_lane_cap;
+	uint32_t                       pcie_spc_cap;
+	struct fiji_leakage_voltage          vddc_leakage;
+	struct fiji_leakage_voltage          Vddci_leakage;
+
+	uint32_t                             mvdd_control;
+	uint32_t                             vddc_mask_low;
+	uint32_t                             mvdd_mask_low;
+	uint16_t                            max_vddc_in_pptable;
+	uint16_t                            min_vddc_in_pptable;
+	uint16_t                            max_vddci_in_pptable;
+	uint16_t                            min_vddci_in_pptable;
+	uint32_t                             mclk_strobe_mode_threshold;
+	uint32_t                             mclk_stutter_mode_threshold;
+	uint32_t                             mclk_edc_enable_threshold;
+	uint32_t                             mclk_edcwr_enable_threshold;
+	bool                                is_uvd_enabled;
+	struct fiji_vbios_boot_state        vbios_boot_state;
+
+	bool                           battery_state;
+	bool                           is_tlu_enabled;
+
+	/* ---- SMC SRAM Address of firmware header tables ---- */
+	uint32_t                             sram_end;
+	uint32_t                             dpm_table_start;
+	uint32_t                             soft_regs_start;
+	uint32_t                             mc_reg_table_start;
+	uint32_t                             fan_table_start;
+	uint32_t                             arb_table_start;
+	struct SMU73_Discrete_DpmTable       smc_state_table;
+	struct SMU73_Discrete_Ulv            ulv_setting;
+
+	/* ---- Stuff originally coming from Evergreen ---- */
+	uint32_t                             vddci_control;
+	struct pp_atomctrl_voltage_table     vddc_voltage_table;
+	struct pp_atomctrl_voltage_table     vddci_voltage_table;
+	struct pp_atomctrl_voltage_table     mvdd_voltage_table;
+
+	uint32_t                             mgcg_cgtt_local2;
+	uint32_t                             mgcg_cgtt_local3;
+	uint32_t                             gpio_debug;
+	uint32_t                             mc_micro_code_feature;
+	uint32_t                             highest_mclk;
+	uint16_t                             acpi_vddci;
+	uint8_t                              mvdd_high_index;
+	uint8_t                              mvdd_low_index;
+	bool                                 dll_default_on;
+	bool                                 performance_request_registered;
+
+	/* ---- Low Power Features ---- */
+	struct fiji_bacos                    bacos;
+	struct fiji_ulv_parm                 ulv;
+
+	/* ---- CAC Stuff ---- */
+	uint32_t                       cac_table_start;
+	bool                           cac_configuration_required;
+	bool                           driver_calculate_cac_leakage;
+	bool                           cac_enabled;
+
+	/* ---- DPM2 Parameters ---- */
+	uint32_t                       power_containment_features;
+	bool                           enable_dte_feature;
+	bool                           enable_tdc_limit_feature;
+	bool                           enable_pkg_pwr_tracking_feature;
+	bool                           disable_uvd_power_tune_feature;
+	struct fiji_pt_defaults       *power_tune_defaults;
+	struct SMU73_Discrete_PmFuses  power_tune_table;
+	uint32_t                       dte_tj_offset;
+	uint32_t                       fast_watermark_threshold;
+
+	/* ---- Phase Shedding ---- */
+	bool                           vddc_phase_shed_control;
+
+	/* ---- DI/DT ---- */
+	struct fiji_display_timing        display_timing;
+
+	/* ---- Thermal Temperature Setting ---- */
+	struct fiji_dpmlevel_enable_mask     dpm_level_enable_mask;
+	uint32_t                             need_update_smu7_dpm_table;
+	uint32_t                             sclk_dpm_key_disabled;
+	uint32_t                             mclk_dpm_key_disabled;
+	uint32_t                             pcie_dpm_key_disabled;
+	uint32_t                             min_engine_clocks;
+	struct fiji_pcie_perf_range          pcie_gen_performance;
+	struct fiji_pcie_perf_range          pcie_lane_performance;
+	struct fiji_pcie_perf_range          pcie_gen_power_saving;
+	struct fiji_pcie_perf_range          pcie_lane_power_saving;
+	bool                                 use_pcie_performance_levels;
+	bool                                 use_pcie_power_saving_levels;
+	uint32_t                             activity_target[SMU73_MAX_LEVELS_GRAPHICS];
+	uint32_t                             mclk_activity_target;
+	uint32_t                             mclk_dpm0_activity_target;
+	uint32_t                             low_sclk_interrupt_threshold;
+	uint32_t                             last_mclk_dpm_enable_mask;
+	bool                                 uvd_enabled;
+
+	/* ---- Power Gating States ---- */
+	bool                           uvd_power_gated;
+	bool                           vce_power_gated;
+	bool                           samu_power_gated;
+	bool                           acp_power_gated;
+	bool                           pg_acp_init;
+	bool                           frtc_enabled;
+	bool                           frtc_status_changed;
+};
+
+/* To convert to Q8.8 format for firmware */
+#define FIJI_Q88_FORMAT_CONVERSION_UNIT             256
+
+enum Fiji_I2CLineID {
+    Fiji_I2CLineID_DDC1 = 0x90,
+    Fiji_I2CLineID_DDC2 = 0x91,
+    Fiji_I2CLineID_DDC3 = 0x92,
+    Fiji_I2CLineID_DDC4 = 0x93,
+    Fiji_I2CLineID_DDC5 = 0x94,
+    Fiji_I2CLineID_DDC6 = 0x95,
+    Fiji_I2CLineID_SCLSDA = 0x96,
+    Fiji_I2CLineID_DDCVGA = 0x97
+};
+
+#define Fiji_I2C_DDC1DATA          0
+#define Fiji_I2C_DDC1CLK           1
+#define Fiji_I2C_DDC2DATA          2
+#define Fiji_I2C_DDC2CLK           3
+#define Fiji_I2C_DDC3DATA          4
+#define Fiji_I2C_DDC3CLK           5
+#define Fiji_I2C_SDA               40
+#define Fiji_I2C_SCL               41
+#define Fiji_I2C_DDC4DATA          65
+#define Fiji_I2C_DDC4CLK           66
+#define Fiji_I2C_DDC5DATA          0x48
+#define Fiji_I2C_DDC5CLK           0x49
+#define Fiji_I2C_DDC6DATA          0x4a
+#define Fiji_I2C_DDC6CLK           0x4b
+#define Fiji_I2C_DDCVGADATA        0x4c
+#define Fiji_I2C_DDCVGACLK         0x4d
+
+#define FIJI_UNUSED_GPIO_PIN       0x7F
+
+extern int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
+extern int tonga_hwmgr_backend_fini(struct pp_hwmgr *hwmgr);
+extern int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr);
+extern int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr);
+extern int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display);
+int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
+int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
+
+#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X)
+#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X)
+
+#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X)
+#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X)
+
+#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X))
+#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X))
+
+#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X))
+
+#endif /* _FIJI_HWMGR_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "hwmgr.h"
+#include "smumgr.h"
+#include "fiji_hwmgr.h"
+#include "fiji_powertune.h"
+#include "fiji_smumgr.h"
+#include "smu73_discrete.h"
+#include "pp_debug.h"
+
+#define VOLTAGE_SCALE  4
+#define POWERTUNE_DEFAULT_SET_MAX    1
+
+struct fiji_pt_defaults fiji_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
+		/*sviLoadLIneEn,  SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
+		{1,               0xF,             0xFD,
+		/* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
+		0x19,        5,               45}
+};
+
+void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *fiji_hwmgr = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct  phm_ppt_v1_information *table_info =
+			(struct  phm_ppt_v1_information *)(hwmgr->pptable);
+	uint32_t tmp = 0;
+
+	if(table_info &&
+			table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
+			table_info->cac_dtp_table->usPowerTuneDataSetID)
+		fiji_hwmgr->power_tune_defaults =
+				&fiji_power_tune_data_set_array
+				[table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
+	else
+		fiji_hwmgr->power_tune_defaults = &fiji_power_tune_data_set_array[0];
+
+	/* Assume disabled */
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_PowerContainment);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_CAC);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_SQRamping);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_DBRamping);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_TDRamping);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_TCPRamping);
+
+	fiji_hwmgr->dte_tj_offset = tmp;
+
+	if (!tmp) {
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_PowerContainment);
+
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_CAC);
+
+		fiji_hwmgr->fast_watermark_threshold = 100;
+
+		tmp = 1;
+		fiji_hwmgr->enable_dte_feature = tmp ? false : true;
+		fiji_hwmgr->enable_tdc_limit_feature = tmp ? true : false;
+		fiji_hwmgr->enable_pkg_pwr_tracking_feature = tmp ? true : false;
+	}
+}
+
+/* PPGen has the gain setting generated in x * 100 unit
+ * This function is to convert the unit to x * 4096(0x1000) unit.
+ *  This is the unit expected by SMC firmware
+ */
+static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
+{
+	uint32_t tmp;
+	tmp = raw_setting * 4096 / 100;
+	return (uint16_t)tmp;
+}
+
+static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t* sda)
+{
+	switch (line) {
+	case Fiji_I2CLineID_DDC1 :
+		*scl = Fiji_I2C_DDC1CLK;
+		*sda = Fiji_I2C_DDC1DATA;
+		break;
+	case Fiji_I2CLineID_DDC2 :
+		*scl = Fiji_I2C_DDC2CLK;
+		*sda = Fiji_I2C_DDC2DATA;
+		break;
+	case Fiji_I2CLineID_DDC3 :
+		*scl = Fiji_I2C_DDC3CLK;
+		*sda = Fiji_I2C_DDC3DATA;
+		break;
+	case Fiji_I2CLineID_DDC4 :
+		*scl = Fiji_I2C_DDC4CLK;
+		*sda = Fiji_I2C_DDC4DATA;
+		break;
+	case Fiji_I2CLineID_DDC5 :
+		*scl = Fiji_I2C_DDC5CLK;
+		*sda = Fiji_I2C_DDC5DATA;
+		break;
+	case Fiji_I2CLineID_DDC6 :
+		*scl = Fiji_I2C_DDC6CLK;
+		*sda = Fiji_I2C_DDC6DATA;
+		break;
+	case Fiji_I2CLineID_SCLSDA :
+		*scl = Fiji_I2C_SCL;
+		*sda = Fiji_I2C_SDA;
+		break;
+	case Fiji_I2CLineID_DDCVGA :
+		*scl = Fiji_I2C_DDCVGACLK;
+		*sda = Fiji_I2C_DDCVGADATA;
+		break;
+	default:
+		*scl = 0;
+		*sda = 0;
+		break;
+	}
+}
+
+int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct fiji_pt_defaults *defaults = data->power_tune_defaults;
+	SMU73_Discrete_DpmTable  *dpm_table = &(data->smc_state_table);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
+	struct pp_advance_fan_control_parameters *fan_table=
+			&hwmgr->thermal_controller.advanceFanControlParameters;
+	uint8_t uc_scl, uc_sda;
+
+	/* TDP number of fraction bits are changed from 8 to 7 for Fiji
+	 * as requested by SMC team
+	 */
+	dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
+			(uint16_t)(cac_dtp_table->usTDP * 128));
+	dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
+			(uint16_t)(cac_dtp_table->usTDP * 128));
+
+	PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
+			"Target Operating Temp is out of Range!",);
+
+	dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
+	dpm_table->GpuTjHyst = 8;
+
+	dpm_table->DTEAmbientTempBase = defaults->DTEAmbientTempBase;
+
+	/* The following are for new Fiji Multi-input fan/thermal control */
+	dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
+			cac_dtp_table->usTargetOperatingTemp * 256);
+	dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
+			cac_dtp_table->usTemperatureLimitHotspot * 256);
+	dpm_table->TemperatureLimitLiquid1 = PP_HOST_TO_SMC_US(
+			cac_dtp_table->usTemperatureLimitLiquid1 * 256);
+	dpm_table->TemperatureLimitLiquid2 = PP_HOST_TO_SMC_US(
+			cac_dtp_table->usTemperatureLimitLiquid2 * 256);
+	dpm_table->TemperatureLimitVrVddc = PP_HOST_TO_SMC_US(
+			cac_dtp_table->usTemperatureLimitVrVddc * 256);
+	dpm_table->TemperatureLimitVrMvdd = PP_HOST_TO_SMC_US(
+			cac_dtp_table->usTemperatureLimitVrMvdd * 256);
+	dpm_table->TemperatureLimitPlx = PP_HOST_TO_SMC_US(
+			cac_dtp_table->usTemperatureLimitPlx * 256);
+
+	dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
+			scale_fan_gain_settings(fan_table->usFanGainEdge));
+	dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
+			scale_fan_gain_settings(fan_table->usFanGainHotspot));
+	dpm_table->FanGainLiquid = PP_HOST_TO_SMC_US(
+			scale_fan_gain_settings(fan_table->usFanGainLiquid));
+	dpm_table->FanGainVrVddc = PP_HOST_TO_SMC_US(
+			scale_fan_gain_settings(fan_table->usFanGainVrVddc));
+	dpm_table->FanGainVrMvdd = PP_HOST_TO_SMC_US(
+			scale_fan_gain_settings(fan_table->usFanGainVrMvdd));
+	dpm_table->FanGainPlx = PP_HOST_TO_SMC_US(
+			scale_fan_gain_settings(fan_table->usFanGainPlx));
+	dpm_table->FanGainHbm = PP_HOST_TO_SMC_US(
+			scale_fan_gain_settings(fan_table->usFanGainHbm));
+
+	dpm_table->Liquid1_I2C_address = cac_dtp_table->ucLiquid1_I2C_address;
+	dpm_table->Liquid2_I2C_address = cac_dtp_table->ucLiquid2_I2C_address;
+	dpm_table->Vr_I2C_address = cac_dtp_table->ucVr_I2C_address;
+	dpm_table->Plx_I2C_address = cac_dtp_table->ucPlx_I2C_address;
+
+	get_scl_sda_value(cac_dtp_table->ucLiquid_I2C_Line, &uc_scl, &uc_sda);
+	dpm_table->Liquid_I2C_LineSCL = uc_scl;
+	dpm_table->Liquid_I2C_LineSDA = uc_sda;
+
+	get_scl_sda_value(cac_dtp_table->ucVr_I2C_Line, &uc_scl, &uc_sda);
+	dpm_table->Vr_I2C_LineSCL = uc_scl;
+	dpm_table->Vr_I2C_LineSDA = uc_sda;
+
+	get_scl_sda_value(cac_dtp_table->ucPlx_I2C_Line, &uc_scl, &uc_sda);
+	dpm_table->Plx_I2C_LineSCL = uc_scl;
+	dpm_table->Plx_I2C_LineSDA = uc_sda;
+
+	return 0;
+}
+
+static int fiji_populate_svi_load_line(struct pp_hwmgr *hwmgr)
+{
+    struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+    struct fiji_pt_defaults *defaults = data->power_tune_defaults;
+
+    data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
+    data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
+    data->power_tune_table.SviLoadLineTrimVddC = 3;
+    data->power_tune_table.SviLoadLineOffsetVddC = 0;
+
+    return 0;
+}
+
+static int fiji_populate_tdc_limit(struct pp_hwmgr *hwmgr)
+{
+	uint16_t tdc_limit;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct  fiji_pt_defaults *defaults = data->power_tune_defaults;
+
+	/* TDC number of fraction bits are changed from 8 to 7
+	 * for Fiji as requested by SMC team
+	 */
+	tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
+	data->power_tune_table.TDC_VDDC_PkgLimit =
+			CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
+	data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
+			defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
+	data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
+
+	return 0;
+}
+
+static int fiji_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct  fiji_pt_defaults *defaults = data->power_tune_defaults;
+	uint32_t temp;
+
+	if (fiji_read_smc_sram_dword(hwmgr->smumgr,
+			fuse_table_offset +
+			offsetof(SMU73_Discrete_PmFuses, TdcWaterfallCtl),
+			(uint32_t *)&temp, data->sram_end))
+		PP_ASSERT_WITH_CODE(false,
+				"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
+				return -EINVAL);
+	else {
+		data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
+		data->power_tune_table.LPMLTemperatureMin =
+				(uint8_t)((temp >> 16) & 0xff);
+		data->power_tune_table.LPMLTemperatureMax =
+				(uint8_t)((temp >> 8) & 0xff);
+		data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
+	}
+	return 0;
+}
+
+static int fiji_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
+{
+	int i;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	/* Currently not used. Set all to zero. */
+	for (i = 0; i < 16; i++)
+		data->power_tune_table.LPMLTemperatureScaler[i] = 0;
+
+	return 0;
+}
+
+static int fiji_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if( (hwmgr->thermal_controller.advanceFanControlParameters.
+			usFanOutputSensitivity & (1 << 15)) ||
+			0 == hwmgr->thermal_controller.advanceFanControlParameters.
+			usFanOutputSensitivity )
+		hwmgr->thermal_controller.advanceFanControlParameters.
+		usFanOutputSensitivity = hwmgr->thermal_controller.
+			advanceFanControlParameters.usDefaultFanOutputSensitivity;
+
+	data->power_tune_table.FuzzyFan_PwmSetDelta =
+			PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
+					advanceFanControlParameters.usFanOutputSensitivity);
+	return 0;
+}
+
+static int fiji_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
+{
+	int i;
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	/* Currently not used. Set all to zero. */
+	for (i = 0; i < 16; i++)
+		data->power_tune_table.GnbLPML[i] = 0;
+
+	return 0;
+}
+
+static int fiji_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
+{
+ /*   int  i, min, max;
+    struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+    uint8_t * pHiVID = data->power_tune_table.BapmVddCVidHiSidd;
+    uint8_t * pLoVID = data->power_tune_table.BapmVddCVidLoSidd;
+
+    min = max = pHiVID[0];
+    for (i = 0; i < 8; i++) {
+        if (0 != pHiVID[i]) {
+            if (min > pHiVID[i])
+                min = pHiVID[i];
+            if (max < pHiVID[i])
+                max = pHiVID[i];
+        }
+
+        if (0 != pLoVID[i]) {
+            if (min > pLoVID[i])
+                min = pLoVID[i];
+            if (max < pLoVID[i])
+                max = pLoVID[i];
+        }
+    }
+
+    PP_ASSERT_WITH_CODE((0 != min) && (0 != max), "BapmVddcVidSidd table does not exist!", return int_Failed);
+    data->power_tune_table.GnbLPMLMaxVid = (uint8_t)max;
+    data->power_tune_table.GnbLPMLMinVid = (uint8_t)min;
+*/
+    return 0;
+}
+
+static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	uint16_t HiSidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
+	uint16_t LoSidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
+	struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
+
+	HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
+	LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
+
+	data->power_tune_table.BapmVddCBaseLeakageHiSidd =
+			CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
+	data->power_tune_table.BapmVddCBaseLeakageLoSidd =
+			CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
+
+	return 0;
+}
+
+int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	uint32_t pm_fuse_table_offset;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_PowerContainment)) {
+		if (fiji_read_smc_sram_dword(hwmgr->smumgr,
+				SMU7_FIRMWARE_HEADER_LOCATION +
+				offsetof(SMU73_Firmware_Header, PmFuseTable),
+				&pm_fuse_table_offset, data->sram_end))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to get pm_fuse_table_offset Failed!",
+					return -EINVAL);
+
+		/* DW6 */
+		if (fiji_populate_svi_load_line(hwmgr))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to populate SviLoadLine Failed!",
+					return -EINVAL);
+		/* DW7 */
+		if (fiji_populate_tdc_limit(hwmgr))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to populate TDCLimit Failed!", return -EINVAL);
+		/* DW8 */
+		if (fiji_populate_dw8(hwmgr, pm_fuse_table_offset))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to populate TdcWaterfallCtl, "
+					"LPMLTemperature Min and Max Failed!",
+					return -EINVAL);
+
+		/* DW9-DW12 */
+		if (0 != fiji_populate_temperature_scaler(hwmgr))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to populate LPMLTemperatureScaler Failed!",
+					return -EINVAL);
+
+		/* DW13-DW14 */
+		if(fiji_populate_fuzzy_fan(hwmgr))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to populate Fuzzy Fan Control parameters Failed!",
+					return -EINVAL);
+
+		/* DW15-DW18 */
+		if (fiji_populate_gnb_lpml(hwmgr))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to populate GnbLPML Failed!",
+					return -EINVAL);
+
+		/* DW19 */
+		if (fiji_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to populate GnbLPML Min and Max Vid Failed!",
+					return -EINVAL);
+
+		/* DW20 */
+		if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to populate BapmVddCBaseLeakage Hi and Lo "
+					"Sidd Failed!", return -EINVAL);
+
+		if (fiji_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
+				(uint8_t *)&data->power_tune_table,
+				sizeof(struct SMU73_Discrete_PmFuses), data->sram_end))
+			PP_ASSERT_WITH_CODE(false,
+					"Attempt to download PmFuseTable Failed!",
+					return -EINVAL);
+	}
+	return 0;
+}
+
+int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	int result = 0;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_CAC)) {
+		int smc_result;
+		smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+				(uint16_t)(PPSMC_MSG_EnableCac));
+		PP_ASSERT_WITH_CODE((0 == smc_result),
+				"Failed to enable CAC in SMC.", result = -1);
+
+        data->cac_enabled = (0 == smc_result) ? true : false;
+	}
+	return result;
+}
+
+int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+	if(data->power_containment_features &
+			POWERCONTAINMENT_FEATURE_PkgPwrLimit)
+		return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_PkgPwrSetLimit, n);
+	return 0;
+}
+
+static int fiji_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
+{
+	return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
+			PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
+}
+
+int fiji_enable_power_containment(struct pp_hwmgr *hwmgr)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	int smc_result;
+	int result = 0;
+
+	data->power_containment_features = 0;
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_PowerContainment)) {
+		if (data->enable_dte_feature) {
+			smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+					(uint16_t)(PPSMC_MSG_EnableDTE));
+			PP_ASSERT_WITH_CODE((0 == smc_result),
+					"Failed to enable DTE in SMC.", result = -1;);
+			if (0 == smc_result)
+				data->power_containment_features |= POWERCONTAINMENT_FEATURE_DTE;
+		}
+
+		if (data->enable_tdc_limit_feature) {
+			smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+					(uint16_t)(PPSMC_MSG_TDCLimitEnable));
+			PP_ASSERT_WITH_CODE((0 == smc_result),
+					"Failed to enable TDCLimit in SMC.", result = -1;);
+			if (0 == smc_result)
+				data->power_containment_features |=
+						POWERCONTAINMENT_FEATURE_TDCLimit;
+		}
+
+		if (data->enable_pkg_pwr_tracking_feature) {
+			smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+					(uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
+			PP_ASSERT_WITH_CODE((0 == smc_result),
+					"Failed to enable PkgPwrTracking in SMC.", result = -1;);
+			if (0 == smc_result) {
+				struct phm_cac_tdp_table *cac_table =
+						table_info->cac_dtp_table;
+				uint32_t default_limit =
+					(uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
+
+				data->power_containment_features |=
+						POWERCONTAINMENT_FEATURE_PkgPwrLimit;
+
+				if (fiji_set_power_limit(hwmgr, default_limit))
+					printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
+			}
+		}
+	}
+	return result;
+}
+
+int fiji_power_control_set_level(struct pp_hwmgr *hwmgr)
+{
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
+	int adjust_percent, target_tdp;
+	int result = 0;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_PowerContainment)) {
+		/* adjustment percentage has already been validated */
+		adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
+				hwmgr->platform_descriptor.TDPAdjustment :
+				(-1 * hwmgr->platform_descriptor.TDPAdjustment);
+		/* SMC requested that target_tdp to be 7 bit fraction in DPM table
+		 * but message to be 8 bit fraction for messages
+		 */
+		target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
+		result = fiji_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
+	}
+
+	return result;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef FIJI_POWERTUNE_H
+#define FIJI_POWERTUNE_H
+
+enum fiji_pt_config_reg_type {
+	FIJI_CONFIGREG_MMR = 0,
+	FIJI_CONFIGREG_SMC_IND,
+	FIJI_CONFIGREG_DIDT_IND,
+	FIJI_CONFIGREG_CACHE,
+	FIJI_CONFIGREG_MAX
+};
+
+/* PowerContainment Features */
+#define POWERCONTAINMENT_FEATURE_DTE             0x00000001
+#define POWERCONTAINMENT_FEATURE_TDCLimit        0x00000002
+#define POWERCONTAINMENT_FEATURE_PkgPwrLimit     0x00000004
+
+struct fiji_pt_config_reg {
+	uint32_t                           offset;
+	uint32_t                           mask;
+	uint32_t                           shift;
+	uint32_t                           value;
+	enum fiji_pt_config_reg_type       type;
+};
+
+struct fiji_pt_defaults
+{
+    uint8_t   SviLoadLineEn;
+    uint8_t   SviLoadLineVddC;
+    uint8_t   TDC_VDDC_ThrottleReleaseLimitPerc;
+    uint8_t   TDC_MAWt;
+    uint8_t   TdcWaterfallCtl;
+    uint8_t   DTEAmbientTempBase;
+};
+
+void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
+int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
+int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr);
+int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr);
+int fiji_enable_power_containment(struct pp_hwmgr *hwmgr);
+int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
+int fiji_power_control_set_level(struct pp_hwmgr *hwmgr);
+
+#endif  /* FIJI_POWERTUNE_H */
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c
@@ -0,0 +1,687 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <asm/div64.h>
+#include "fiji_thermal.h"
+#include "fiji_hwmgr.h"
+#include "fiji_smumgr.h"
+#include "fiji_ppsmc.h"
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+
+int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
+		struct phm_fan_speed_info *fan_speed_info)
+{
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		return 0;
+
+	fan_speed_info->supports_percent_read = true;
+	fan_speed_info->supports_percent_write = true;
+	fan_speed_info->min_percent = 0;
+	fan_speed_info->max_percent = 100;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
+		hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
+		fan_speed_info->supports_rpm_read = true;
+		fan_speed_info->supports_rpm_write = true;
+		fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
+		fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
+	} else {
+		fan_speed_info->min_rpm = 0;
+		fan_speed_info->max_rpm = 0;
+	}
+
+	return 0;
+}
+
+int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
+		uint32_t *speed)
+{
+	uint32_t duty100;
+	uint32_t duty;
+	uint64_t tmp64;
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		return 0;
+
+	duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_FDO_CTRL1, FMAX_DUTY100);
+	duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_THERMAL_STATUS, FDO_PWM_DUTY);
+
+	if (duty100 == 0)
+		return -EINVAL;
+
+
+	tmp64 = (uint64_t)duty * 100;
+	do_div(tmp64, duty100);
+	*speed = (uint32_t)tmp64;
+
+	if (*speed > 100)
+		*speed = 100;
+
+	return 0;
+}
+
+int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
+{
+	uint32_t tach_period;
+	uint32_t crystal_clock_freq;
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan ||
+			(hwmgr->thermal_controller.fanInfo.
+				ucTachometerPulsesPerRevolution == 0))
+		return 0;
+
+	tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_TACH_STATUS, TACH_PERIOD);
+
+	if (tach_period == 0)
+		return -EINVAL;
+
+	crystal_clock_freq = tonga_get_xclk(hwmgr);
+
+	*speed = 60 * crystal_clock_freq * 10000/ tach_period;
+
+	return 0;
+}
+
+/**
+* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
+* @param    hwmgr  the address of the powerplay hardware manager.
+*           mode    the fan control mode, 0 default, 1 by percent, 5, by RPM
+* @exception Should always succeed.
+*/
+int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+
+	if (hwmgr->fan_ctrl_is_in_default_mode) {
+		hwmgr->fan_ctrl_default_mode =
+				PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,	CGS_IND_REG__SMC,
+						CG_FDO_CTRL2, FDO_PWM_MODE);
+		hwmgr->tmin =
+				PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+						CG_FDO_CTRL2, TMIN);
+		hwmgr->fan_ctrl_is_in_default_mode = false;
+	}
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_FDO_CTRL2, TMIN, 0);
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_FDO_CTRL2, FDO_PWM_MODE, mode);
+
+	return 0;
+}
+
+/**
+* Reset Fan Speed Control to default mode.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @exception Should always succeed.
+*/
+int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
+{
+	if (!hwmgr->fan_ctrl_is_in_default_mode) {
+		PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
+		PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				CG_FDO_CTRL2, TMIN, hwmgr->tmin);
+		hwmgr->fan_ctrl_is_in_default_mode = true;
+	}
+
+	return 0;
+}
+
+int fiji_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+	int result;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
+		cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
+		result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_FanSpeedInTableIsRPM))
+			hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
+					hwmgr->thermal_controller.
+					advanceFanControlParameters.usMaxFanRPM);
+		else
+			hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
+					hwmgr->thermal_controller.
+					advanceFanControlParameters.usMaxFanPWM);
+
+	} else {
+		cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
+		result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
+	}
+
+	if (!result && hwmgr->thermal_controller.
+			advanceFanControlParameters.ucTargetTemperature)
+		result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetFanTemperatureTarget,
+				hwmgr->thermal_controller.
+				advanceFanControlParameters.ucTargetTemperature);
+
+	return result;
+}
+
+
+int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+	return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
+}
+
+/**
+* Set Fan Speed in percent.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    speed is the percentage value (0% - 100%) to be set.
+* @exception Fails is the 100% setting appears to be 0.
+*/
+int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
+		uint32_t speed)
+{
+	uint32_t duty100;
+	uint32_t duty;
+	uint64_t tmp64;
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		return 0;
+
+	if (speed > 100)
+		speed = 100;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_MicrocodeFanControl))
+		fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
+
+	duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_FDO_CTRL1, FMAX_DUTY100);
+
+	if (duty100 == 0)
+		return -EINVAL;
+
+	tmp64 = (uint64_t)speed * 100;
+	do_div(tmp64, duty100);
+	duty = (uint32_t)tmp64;
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
+
+	return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+}
+
+/**
+* Reset Fan Speed to default.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @exception Always succeeds.
+*/
+int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
+{
+	int result;
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		return 0;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_MicrocodeFanControl)) {
+		result = fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+		if (!result)
+			result = fiji_fan_ctrl_start_smc_fan_control(hwmgr);
+	} else
+		result = fiji_fan_ctrl_set_default_mode(hwmgr);
+
+	return result;
+}
+
+/**
+* Set Fan Speed in RPM.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    speed is the percentage value (min - max) to be set.
+* @exception Fails is the speed not lie between min and max.
+*/
+int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
+{
+	uint32_t tach_period;
+	uint32_t crystal_clock_freq;
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan ||
+			(hwmgr->thermal_controller.fanInfo.
+			ucTachometerPulsesPerRevolution == 0) ||
+			(speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
+			(speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
+		return 0;
+
+	crystal_clock_freq = tonga_get_xclk(hwmgr);
+
+	tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				CG_TACH_STATUS, TACH_PERIOD, tach_period);
+
+	return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+}
+
+/**
+* Reads the remote temperature from the SIslands thermal controller.
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr)
+{
+	int temp;
+
+	temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_MULT_THERMAL_STATUS, CTF_TEMP);
+
+	/* Bit 9 means the reading is lower than the lowest usable value. */
+	if (temp & 0x200)
+		temp = FIJI_THERMAL_MAXIMUM_TEMP_READING;
+	else
+		temp = temp & 0x1ff;
+
+	temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+	return temp;
+}
+
+/**
+* Set the requested temperature range for high and low alert signals
+*
+* @param    hwmgr The address of the hardware manager.
+* @param    range Temperature range to be programmed for high and low alert signals
+* @exception PP_Result_BadInput if the input data is not valid.
+*/
+static int fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
+		uint32_t low_temp, uint32_t high_temp)
+{
+	uint32_t low = FIJI_THERMAL_MINIMUM_ALERT_TEMP *
+			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+	uint32_t high = FIJI_THERMAL_MAXIMUM_ALERT_TEMP *
+			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+	if (low < low_temp)
+		low = low_temp;
+	if (high > high_temp)
+		high = high_temp;
+
+	if (low > high)
+		return -EINVAL;
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_THERMAL_INT, DIG_THERM_INTH,
+			(high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_THERMAL_INT, DIG_THERM_INTL,
+			(low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_THERMAL_CTRL, DIG_THERM_DPM,
+			(high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+
+	return 0;
+}
+
+/**
+* Programs thermal controller one-time setting registers
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+static int fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+	if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
+		PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				CG_TACH_CTRL, EDGE_PER_REV,
+				hwmgr->thermal_controller.fanInfo.
+				ucTachometerPulsesPerRevolution - 1);
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
+
+	return 0;
+}
+
+/**
+* Enable thermal alerts on the RV770 thermal controller.
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+static int fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr)
+{
+	uint32_t alert;
+
+	alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_THERMAL_INT, THERM_INT_MASK);
+	alert &= ~(FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+	/* send message to SMU to enable internal thermal interrupts */
+	return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
+}
+
+/**
+* Disable thermal alerts on the RV770 thermal controller.
+* @param    hwmgr The address of the hardware manager.
+*/
+static int fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr)
+{
+	uint32_t alert;
+
+	alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_THERMAL_INT, THERM_INT_MASK);
+	alert |= (FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+	/* send message to SMU to disable internal thermal interrupts */
+	return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
+}
+
+/**
+* Uninitialize the thermal controller.
+* Currently just disables alerts.
+* @param    hwmgr The address of the hardware manager.
+*/
+int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+	int result = fiji_thermal_disable_alert(hwmgr);
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		fiji_fan_ctrl_set_default_mode(hwmgr);
+
+	return result;
+}
+
+/**
+* Set up the fan table to control the fan using the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int tf_fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
+		void *input, void *output, void *storage, int result)
+{
+	struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+	SMU73_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+	uint32_t duty100;
+	uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+	uint16_t fdo_min, slope1, slope2;
+	uint32_t reference_clock;
+	int res;
+	uint64_t tmp64;
+
+	if (data->fan_table_start == 0) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_MicrocodeFanControl);
+		return 0;
+	}
+
+	duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+			CG_FDO_CTRL1, FMAX_DUTY100);
+
+	if (duty100 == 0) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_MicrocodeFanControl);
+		return 0;
+	}
+
+	tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
+			usPWMMin * duty100;
+	do_div(tmp64, 10000);
+	fdo_min = (uint16_t)tmp64;
+
+	t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
+			hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
+	t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
+			hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
+
+	pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
+			hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
+	pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
+			hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
+
+	slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+	slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+	fan_table.TempMin = cpu_to_be16((50 + hwmgr->
+			thermal_controller.advanceFanControlParameters.usTMin) / 100);
+	fan_table.TempMed = cpu_to_be16((50 + hwmgr->
+			thermal_controller.advanceFanControlParameters.usTMed) / 100);
+	fan_table.TempMax = cpu_to_be16((50 + hwmgr->
+			thermal_controller.advanceFanControlParameters.usTMax) / 100);
+
+	fan_table.Slope1 = cpu_to_be16(slope1);
+	fan_table.Slope2 = cpu_to_be16(slope2);
+
+	fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+	fan_table.HystDown = cpu_to_be16(hwmgr->
+			thermal_controller.advanceFanControlParameters.ucTHyst);
+
+	fan_table.HystUp = cpu_to_be16(1);
+
+	fan_table.HystSlope = cpu_to_be16(1);
+
+	fan_table.TempRespLim = cpu_to_be16(5);
+
+	reference_clock = tonga_get_xclk(hwmgr);
+
+	fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
+			thermal_controller.advanceFanControlParameters.ulCycleDelay *
+			reference_clock) / 1600);
+
+	fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
+
+	fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
+			hwmgr->device, CGS_IND_REG__SMC,
+			CG_MULT_THERMAL_CTRL, TEMP_SEL);
+
+	res = fiji_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start,
+			(uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
+			data->sram_end);
+
+	if (!res && hwmgr->thermal_controller.
+			advanceFanControlParameters.ucMinimumPWMLimit)
+		res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetFanMinPwm,
+				hwmgr->thermal_controller.
+				advanceFanControlParameters.ucMinimumPWMLimit);
+
+	if (!res && hwmgr->thermal_controller.
+			advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
+		res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+				PPSMC_MSG_SetFanSclkTarget,
+				hwmgr->thermal_controller.
+				advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
+
+	if (res)
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_MicrocodeFanControl);
+
+	return 0;
+}
+
+/**
+* Start the fan control on the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int tf_fiji_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
+		void *input, void *output, void *storage, int result)
+{
+/* If the fantable setup has failed we could have disabled
+ * PHM_PlatformCaps_MicrocodeFanControl even after
+ * this function was included in the table.
+ * Make sure that we still think controlling the fan is OK.
+*/
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_MicrocodeFanControl)) {
+		fiji_fan_ctrl_start_smc_fan_control(hwmgr);
+		fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+	}
+
+	return 0;
+}
+
+/**
+* Set temperature range for high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
+		void *input, void *output, void *storage, int result)
+{
+	struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
+
+	if (range == NULL)
+		return -EINVAL;
+
+	return fiji_thermal_set_temperature_range(hwmgr, range->min, range->max);
+}
+
+/**
+* Programs one-time setting registers
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from initialize thermal controller routine
+*/
+int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr,
+		void *input, void *output, void *storage, int result)
+{
+    return fiji_thermal_initialize(hwmgr);
+}
+
+/**
+* Enable high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from enable alert routine
+*/
+int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr,
+		void *input, void *output, void *storage, int result)
+{
+	return fiji_thermal_enable_alert(hwmgr);
+}
+
+/**
+* Disable high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from disable alert routine
+*/
+static int tf_fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr,
+		void *input, void *output, void *storage, int result)
+{
+	return fiji_thermal_disable_alert(hwmgr);
+}
+
+static struct phm_master_table_item
+fiji_thermal_start_thermal_controller_master_list[] = {
+	{NULL, tf_fiji_thermal_initialize},
+	{NULL, tf_fiji_thermal_set_temperature_range},
+	{NULL, tf_fiji_thermal_enable_alert},
+/* We should restrict performance levels to low before we halt the SMC.
+ * On the other hand we are still in boot state when we do this
+ * so it would be pointless.
+ * If this assumption changes we have to revisit this table.
+ */
+	{NULL, tf_fiji_thermal_setup_fan_table},
+	{NULL, tf_fiji_thermal_start_smc_fan_control},
+	{NULL, NULL}
+};
+
+static struct phm_master_table_header
+fiji_thermal_start_thermal_controller_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	fiji_thermal_start_thermal_controller_master_list
+};
+
+static struct phm_master_table_item
+fiji_thermal_set_temperature_range_master_list[] = {
+	{NULL, tf_fiji_thermal_disable_alert},
+	{NULL, tf_fiji_thermal_set_temperature_range},
+	{NULL, tf_fiji_thermal_enable_alert},
+	{NULL, NULL}
+};
+
+struct phm_master_table_header
+fiji_thermal_set_temperature_range_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	fiji_thermal_set_temperature_range_master_list
+};
+
+int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+	if (!hwmgr->thermal_controller.fanInfo.bNoFan)
+		fiji_fan_ctrl_set_default_mode(hwmgr);
+	return 0;
+}
+
+/**
+* Initializes the thermal controller related functions in the Hardware Manager structure.
+* @param    hwmgr The address of the hardware manager.
+* @exception Any error code from the low-level communication.
+*/
+int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+	int result;
+
+	result = phm_construct_table(hwmgr,
+			&fiji_thermal_set_temperature_range_master,
+			&(hwmgr->set_temperature_range));
+
+	if (!result) {
+		result = phm_construct_table(hwmgr,
+				&fiji_thermal_start_thermal_controller_master,
+				&(hwmgr->start_thermal_controller));
+		if (result)
+			phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
+	}
+
+	if (!result)
+		hwmgr->fan_ctrl_is_in_default_mode = true;
+	return result;
+}
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef FIJI_THERMAL_H
+#define FIJI_THERMAL_H
+
+#include "hwmgr.h"
+
+#define FIJI_THERMAL_HIGH_ALERT_MASK         0x1
+#define FIJI_THERMAL_LOW_ALERT_MASK          0x2
+
+#define FIJI_THERMAL_MINIMUM_TEMP_READING    -256
+#define FIJI_THERMAL_MAXIMUM_TEMP_READING    255
+
+#define FIJI_THERMAL_MINIMUM_ALERT_TEMP      0
+#define FIJI_THERMAL_MAXIMUM_ALERT_TEMP      255
+
+#define FDO_PWM_MODE_STATIC  1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
+
+extern int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+extern int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+extern int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+
+extern int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr);
+extern int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
+extern int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
+extern int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
+extern int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
+extern int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
+extern int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr);
+extern int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
+extern int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
+extern uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "hwmgr.h"
+
+static int phm_run_table(struct pp_hwmgr *hwmgr,
+			 struct phm_runtime_table_header *rt_table,
+			 void *input,
+			 void *output,
+			 void *temp_storage)
+{
+	int result = 0;
+	phm_table_function *function;
+
+	for (function = rt_table->function_list; NULL != *function; function++) {
+		int tmp = (*function)(hwmgr, input, output, temp_storage, result);
+
+		if (tmp == PP_Result_TableImmediateExit)
+			break;
+		if (tmp) {
+			if (0 == result)
+				result = tmp;
+			if (rt_table->exit_error)
+				break;
+		}
+	}
+
+	return result;
+}
+
+int phm_dispatch_table(struct pp_hwmgr *hwmgr,
+		       struct phm_runtime_table_header *rt_table,
+		       void *input, void *output)
+{
+	int result = 0;
+	void *temp_storage = NULL;
+
+	if (hwmgr == NULL || rt_table == NULL || rt_table->function_list == NULL) {
+		printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
+		return 0; /*temp return ture because some function not implement on some asic */
+	}
+
+	if (0 != rt_table->storage_size) {
+		temp_storage = kzalloc(rt_table->storage_size, GFP_KERNEL);
+		if (temp_storage == NULL) {
+			printk(KERN_ERR "[ powerplay ] Could not allocate table temporary storage\n");
+			return -ENOMEM;
+		}
+	}
+
+	result = phm_run_table(hwmgr, rt_table, input, output, temp_storage);
+
+	if (NULL != temp_storage)
+		kfree(temp_storage);
+
+	return result;
+}
+
+int phm_construct_table(struct pp_hwmgr *hwmgr,
+			struct phm_master_table_header *master_table,
+			struct phm_runtime_table_header *rt_table)
+{
+	uint32_t function_count = 0;
+	const struct phm_master_table_item *table_item;
+	uint32_t size;
+	phm_table_function *run_time_list;
+	phm_table_function *rtf;
+
+	if (hwmgr == NULL || master_table == NULL || rt_table == NULL) {
+		printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
+		return -EINVAL;
+	}
+
+	for (table_item = master_table->master_list;
+		NULL != table_item->tableFunction; table_item++) {
+		if ((NULL == table_item->isFunctionNeededInRuntimeTable) ||
+		    (table_item->isFunctionNeededInRuntimeTable(hwmgr)))
+			function_count++;
+	}
+
+	size = (function_count + 1) * sizeof(phm_table_function);
+	run_time_list = kzalloc(size, GFP_KERNEL);
+
+	if (NULL == run_time_list)
+		return -ENOMEM;
+
+	rtf = run_time_list;
+	for (table_item = master_table->master_list;
+		NULL != table_item->tableFunction; table_item++) {
+		if ((rtf - run_time_list) > function_count) {
+			printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
+			kfree(run_time_list);
+			return -EINVAL;
+		}
+
+		if ((NULL == table_item->isFunctionNeededInRuntimeTable) ||
+		     (table_item->isFunctionNeededInRuntimeTable(hwmgr))) {
+			*(rtf++) = table_item->tableFunction;
+		}
+	}
+
+	if ((rtf - run_time_list) > function_count) {
+		printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
+		kfree(run_time_list);
+		return -EINVAL;
+	}
+
+	*rtf = NULL;
+	rt_table->function_list = run_time_list;
+	rt_table->exit_error = (0 != (master_table->flags & PHM_MasterTableFlag_ExitOnError));
+	rt_table->storage_size = master_table->storage_size;
+	return 0;
+}
+
+int phm_destroy_table(struct pp_hwmgr *hwmgr,
+		      struct phm_runtime_table_header *rt_table)
+{
+	if (hwmgr == NULL || rt_table == NULL) {
+		printk(KERN_ERR "[ powerplay ] Invalid Parameter\n");
+		return -EINVAL;
+	}
+
+	if (NULL == rt_table->function_list)
+		return 0;
+
+	kfree(rt_table->function_list);
+
+	rt_table->function_list = NULL;
+	rt_table->storage_size = 0;
+	rt_table->exit_error = false;
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/errno.h>
+#include "hwmgr.h"
+#include "hardwaremanager.h"
+#include "power_state.h"
+#include "pp_acpi.h"
+#include "amd_acpi.h"
+#include "amd_powerplay.h"
+
+#define PHM_FUNC_CHECK(hw) \
+	do {							\
+		if ((hw) == NULL || (hw)->hwmgr_func == NULL)	\
+			return -EINVAL;				\
+	} while (0)
+
+void phm_init_dynamic_caps(struct pp_hwmgr *hwmgr)
+{
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableVoltageTransition);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableEngineTransition);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMemoryTransition);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGClockGating);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGCGTSSM);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLSClockGating);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_Force3DClockSupport);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLightSleep);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMCLS);
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisablePowerGating);
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableDPM);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableSMUUVDHandshake);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ThermalAutoThrottling);
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_NoOD5Support);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UserMaxClockForMultiDisplays);
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VpuRecoveryInProgress);
+
+	if (acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST) &&
+		acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION))
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
+}
+
+bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr)
+{
+	return hwmgr->block_hw_access;
+}
+
+int phm_block_hw_access(struct pp_hwmgr *hwmgr, bool block)
+{
+	hwmgr->block_hw_access = block;
+	return 0;
+}
+
+int phm_setup_asic(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_TablelessHardwareInterface)) {
+		if (NULL != hwmgr->hwmgr_func->asic_setup)
+			return hwmgr->hwmgr_func->asic_setup(hwmgr);
+	} else {
+		return phm_dispatch_table(hwmgr, &(hwmgr->setup_asic),
+					  NULL, NULL);
+	}
+
+	return 0;
+}
+
+int phm_power_down_asic(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_TablelessHardwareInterface)) {
+		if (NULL != hwmgr->hwmgr_func->power_off_asic)
+			return hwmgr->hwmgr_func->power_off_asic(hwmgr);
+	} else {
+		return phm_dispatch_table(hwmgr, &(hwmgr->power_down_asic),
+					  NULL, NULL);
+	}
+
+	return 0;
+}
+
+int phm_set_power_state(struct pp_hwmgr *hwmgr,
+		    const struct pp_hw_power_state *pcurrent_state,
+		    const struct pp_hw_power_state *pnew_power_state)
+{
+	struct phm_set_power_state_input states;
+
+	PHM_FUNC_CHECK(hwmgr);
+
+	states.pcurrent_state = pcurrent_state;
+	states.pnew_state = pnew_power_state;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_TablelessHardwareInterface)) {
+		if (NULL != hwmgr->hwmgr_func->power_state_set)
+			return hwmgr->hwmgr_func->power_state_set(hwmgr, &states);
+	} else {
+		return phm_dispatch_table(hwmgr, &(hwmgr->set_power_state), &states, NULL);
+	}
+
+	return 0;
+}
+
+int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_TablelessHardwareInterface)) {
+		if (NULL != hwmgr->hwmgr_func->dynamic_state_management_enable)
+			return hwmgr->hwmgr_func->dynamic_state_management_enable(hwmgr);
+	} else {
+		return phm_dispatch_table(hwmgr,
+				&(hwmgr->enable_dynamic_state_management),
+				NULL, NULL);
+	}
+	return 0;
+}
+
+int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->force_dpm_level != NULL)
+		return hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
+
+	return 0;
+}
+
+int phm_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+				   struct pp_power_state *adjusted_ps,
+			     const struct pp_power_state *current_ps)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->apply_state_adjust_rules != NULL)
+		return hwmgr->hwmgr_func->apply_state_adjust_rules(
+									hwmgr,
+								 adjusted_ps,
+								 current_ps);
+	return 0;
+}
+
+int phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->powerdown_uvd != NULL)
+		return hwmgr->hwmgr_func->powerdown_uvd(hwmgr);
+	return 0;
+}
+
+int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->powergate_uvd != NULL)
+		return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
+	return 0;
+}
+
+int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->powergate_vce != NULL)
+		return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
+	return 0;
+}
+
+int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_TablelessHardwareInterface)) {
+		if (NULL != hwmgr->hwmgr_func->enable_clock_power_gating)
+			return hwmgr->hwmgr_func->enable_clock_power_gating(hwmgr);
+	} else {
+		return phm_dispatch_table(hwmgr, &(hwmgr->enable_clock_power_gatings), NULL, NULL);
+	}
+	return 0;
+}
+
+int phm_display_configuration_changed(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				 PHM_PlatformCaps_TablelessHardwareInterface)) {
+		if (NULL != hwmgr->hwmgr_func->display_config_changed)
+			hwmgr->hwmgr_func->display_config_changed(hwmgr);
+	} else
+		return phm_dispatch_table(hwmgr, &hwmgr->display_configuration_changed, NULL, NULL);
+	return 0;
+}
+
+int phm_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				 PHM_PlatformCaps_TablelessHardwareInterface))
+		if (NULL != hwmgr->hwmgr_func->display_config_changed)
+			hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment(hwmgr);
+
+	return 0;
+}
+
+int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->stop_thermal_controller == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->stop_thermal_controller(hwmgr);
+}
+
+int phm_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->register_internal_thermal_interrupt == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->register_internal_thermal_interrupt(hwmgr, info);
+}
+
+/**
+* Initializes the thermal controller subsystem.
+*
+* @param    pHwMgr  the address of the powerplay hardware manager.
+* @param    pTemperatureRange the address of the structure holding the temperature range.
+* @exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the dispatcher.
+*/
+int phm_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *temperature_range)
+{
+	return phm_dispatch_table(hwmgr, &(hwmgr->start_thermal_controller), temperature_range, NULL);
+}
+
+
+bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration(hwmgr);
+}
+
+
+int phm_check_states_equal(struct pp_hwmgr *hwmgr,
+				 const struct pp_hw_power_state *pstate1,
+				 const struct pp_hw_power_state *pstate2,
+				 bool *equal)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->check_states_equal == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->check_states_equal(hwmgr, pstate1, pstate2, equal);
+}
+
+int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
+		    const struct amd_pp_display_configuration *display_config)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->store_cc6_data == NULL)
+		return -EINVAL;
+
+	hwmgr->display_config = *display_config;
+	/* to do pass other display configuration in furture */
+
+	if (hwmgr->hwmgr_func->store_cc6_data)
+		hwmgr->hwmgr_func->store_cc6_data(hwmgr,
+				display_config->cpu_pstate_separation_time,
+				display_config->cpu_cc6_disable,
+				display_config->cpu_pstate_disable,
+				display_config->nb_pstate_switch_disable);
+
+	return 0;
+}
+
+int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
+		struct amd_pp_dal_clock_info *info)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL)
+		return -EINVAL;
+
+	return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info);
+}
+
+int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (hwmgr->hwmgr_func->set_cpu_power_state != NULL)
+		return hwmgr->hwmgr_func->set_cpu_power_state(hwmgr);
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
@@ -0,0 +1,563 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "linux/delay.h"
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "cgs_common.h"
+#include "power_state.h"
+#include "hwmgr.h"
+#include "pppcielanes.h"
+#include "pp_debug.h"
+#include "ppatomctrl.h"
+
+extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
+extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
+extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr);
+
+int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
+{
+	struct pp_hwmgr *hwmgr;
+
+	if ((handle == NULL) || (pp_init == NULL))
+		return -EINVAL;
+
+	hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
+	if (hwmgr == NULL)
+		return -ENOMEM;
+
+	handle->hwmgr = hwmgr;
+	hwmgr->smumgr = handle->smu_mgr;
+	hwmgr->device = pp_init->device;
+	hwmgr->chip_family = pp_init->chip_family;
+	hwmgr->chip_id = pp_init->chip_id;
+	hwmgr->hw_revision = pp_init->rev_id;
+	hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
+	hwmgr->power_source = PP_PowerSource_AC;
+
+	switch (hwmgr->chip_family) {
+	case AMD_FAMILY_CZ:
+		cz_hwmgr_init(hwmgr);
+		break;
+	case AMD_FAMILY_VI:
+		switch (hwmgr->chip_id) {
+		case CHIP_TONGA:
+			tonga_hwmgr_init(hwmgr);
+			break;
+		case CHIP_FIJI:
+			fiji_hwmgr_init(hwmgr);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	phm_init_dynamic_caps(hwmgr);
+
+	return 0;
+}
+
+int hwmgr_fini(struct pp_hwmgr *hwmgr)
+{
+	if (hwmgr == NULL || hwmgr->ps == NULL)
+		return -EINVAL;
+
+	kfree(hwmgr->ps);
+	kfree(hwmgr);
+	return 0;
+}
+
+int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
+{
+	int result;
+	unsigned int i;
+	unsigned int table_entries;
+	struct pp_power_state *state;
+	int size;
+
+	if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL)
+		return -EINVAL;
+
+	if (hwmgr->hwmgr_func->get_power_state_size == NULL)
+		return -EINVAL;
+
+	hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr);
+
+	hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) +
+					  sizeof(struct pp_power_state);
+
+	hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL);
+
+	if (hwmgr->ps == NULL)
+		return -ENOMEM;
+
+	state = hwmgr->ps;
+
+	for (i = 0; i < table_entries; i++) {
+		result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state);
+
+		if (state->classification.flags & PP_StateClassificationFlag_Boot) {
+			hwmgr->boot_ps = state;
+			hwmgr->current_ps = hwmgr->request_ps = state;
+		}
+
+		state->id = i + 1; /* assigned unique num for every power state id */
+
+		if (state->classification.flags & PP_StateClassificationFlag_Uvd)
+			hwmgr->uvd_ps = state;
+		state = (struct pp_power_state *)((unsigned long)state + size);
+	}
+
+	return 0;
+}
+
+
+/**
+ * Returns once the part of the register indicated by the mask has
+ * reached the given value.
+ */
+int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
+			 uint32_t value, uint32_t mask)
+{
+	uint32_t i;
+	uint32_t cur_value;
+
+	if (hwmgr == NULL || hwmgr->device == NULL) {
+		printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < hwmgr->usec_timeout; i++) {
+		cur_value = cgs_read_register(hwmgr->device, index);
+		if ((cur_value & mask) == (value & mask))
+			break;
+		udelay(1);
+	}
+
+	/* timeout means wrong logic*/
+	if (i == hwmgr->usec_timeout)
+		return -1;
+	return 0;
+}
+
+int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
+				uint32_t index, uint32_t value, uint32_t mask)
+{
+	uint32_t i;
+	uint32_t cur_value;
+
+	if (hwmgr == NULL || hwmgr->device == NULL) {
+		printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < hwmgr->usec_timeout; i++) {
+		cur_value = cgs_read_register(hwmgr->device, index);
+		if ((cur_value & mask) != (value & mask))
+			break;
+		udelay(1);
+	}
+
+	/* timeout means wrong logic*/
+	if (i == hwmgr->usec_timeout)
+		return -1;
+	return 0;
+}
+
+
+/**
+ * Returns once the part of the register indicated by the mask has
+ * reached the given value.The indirect space is described by giving
+ * the memory-mapped index of the indirect index register.
+ */
+void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
+				uint32_t indirect_port,
+				uint32_t index,
+				uint32_t value,
+				uint32_t mask)
+{
+	if (hwmgr == NULL || hwmgr->device == NULL) {
+		printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+		return;
+	}
+
+	cgs_write_register(hwmgr->device, indirect_port, index);
+	phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
+}
+
+void phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr,
+					uint32_t indirect_port,
+					uint32_t index,
+					uint32_t value,
+					uint32_t mask)
+{
+	if (hwmgr == NULL || hwmgr->device == NULL) {
+		printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+		return;
+	}
+
+	cgs_write_register(hwmgr->device, indirect_port, index);
+	phm_wait_for_register_unequal(hwmgr, indirect_port + 1,
+				      value, mask);
+}
+
+bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr)
+{
+	return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating);
+}
+
+bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr)
+{
+	return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating);
+}
+
+
+int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table)
+{
+	uint32_t i, j;
+	uint16_t vvalue;
+	bool found = false;
+	struct pp_atomctrl_voltage_table *table;
+
+	PP_ASSERT_WITH_CODE((NULL != vol_table),
+			"Voltage Table empty.", return -EINVAL);
+
+	table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
+			GFP_KERNEL);
+
+	if (NULL == table)
+		return -EINVAL;
+
+	table->mask_low = vol_table->mask_low;
+	table->phase_delay = vol_table->phase_delay;
+
+	for (i = 0; i < vol_table->count; i++) {
+		vvalue = vol_table->entries[i].value;
+		found = false;
+
+		for (j = 0; j < table->count; j++) {
+			if (vvalue == table->entries[j].value) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			table->entries[table->count].value = vvalue;
+			table->entries[table->count].smio_low =
+					vol_table->entries[i].smio_low;
+			table->count++;
+		}
+	}
+
+	memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
+	kfree(table);
+
+	return 0;
+}
+
+int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
+		phm_ppt_v1_clock_voltage_dependency_table *dep_table)
+{
+	uint32_t i;
+	int result;
+
+	PP_ASSERT_WITH_CODE((0 != dep_table->count),
+			"Voltage Dependency Table empty.", return -EINVAL);
+
+	PP_ASSERT_WITH_CODE((NULL != vol_table),
+			"vol_table empty.", return -EINVAL);
+
+	vol_table->mask_low = 0;
+	vol_table->phase_delay = 0;
+	vol_table->count = dep_table->count;
+
+	for (i = 0; i < dep_table->count; i++) {
+		vol_table->entries[i].value = dep_table->entries[i].mvdd;
+		vol_table->entries[i].smio_low = 0;
+	}
+
+	result = phm_trim_voltage_table(vol_table);
+	PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to trim MVDD table.", return result);
+
+	return 0;
+}
+
+int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
+		phm_ppt_v1_clock_voltage_dependency_table *dep_table)
+{
+	uint32_t i;
+	int result;
+
+	PP_ASSERT_WITH_CODE((0 != dep_table->count),
+			"Voltage Dependency Table empty.", return -EINVAL);
+
+	PP_ASSERT_WITH_CODE((NULL != vol_table),
+			"vol_table empty.", return -EINVAL);
+
+	vol_table->mask_low = 0;
+	vol_table->phase_delay = 0;
+	vol_table->count = dep_table->count;
+
+	for (i = 0; i < dep_table->count; i++) {
+		vol_table->entries[i].value = dep_table->entries[i].vddci;
+		vol_table->entries[i].smio_low = 0;
+	}
+
+	result = phm_trim_voltage_table(vol_table);
+	PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to trim VDDCI table.", return result);
+
+	return 0;
+}
+
+int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
+		phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+	int i = 0;
+
+	PP_ASSERT_WITH_CODE((0 != lookup_table->count),
+			"Voltage Lookup Table empty.", return -EINVAL);
+
+	PP_ASSERT_WITH_CODE((NULL != vol_table),
+			"vol_table empty.", return -EINVAL);
+
+	vol_table->mask_low = 0;
+	vol_table->phase_delay = 0;
+
+	vol_table->count = lookup_table->count;
+
+	for (i = 0; i < vol_table->count; i++) {
+		vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
+		vol_table->entries[i].smio_low = 0;
+	}
+
+	return 0;
+}
+
+void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps,
+				struct pp_atomctrl_voltage_table *vol_table)
+{
+	unsigned int i, diff;
+
+	if (vol_table->count <= max_vol_steps)
+		return;
+
+	diff = vol_table->count - max_vol_steps;
+
+	for (i = 0; i < max_vol_steps; i++)
+		vol_table->entries[i] = vol_table->entries[i + diff];
+
+	vol_table->count = max_vol_steps;
+
+	return;
+}
+
+int phm_reset_single_dpm_table(void *table,
+				uint32_t count, int max)
+{
+	int i;
+
+	struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
+
+	PP_ASSERT_WITH_CODE(count <= max,
+			"Fatal error, can not set up single DPM table entries to exceed max number!",
+			   );
+
+	dpm_table->count = count;
+	for (i = 0; i < max; i++)
+		dpm_table->dpm_level[i].enabled = false;
+
+	return 0;
+}
+
+void phm_setup_pcie_table_entry(
+	void *table,
+	uint32_t index, uint32_t pcie_gen,
+	uint32_t pcie_lanes)
+{
+	struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
+	dpm_table->dpm_level[index].value = pcie_gen;
+	dpm_table->dpm_level[index].param1 = pcie_lanes;
+	dpm_table->dpm_level[index].enabled = 1;
+}
+
+int32_t phm_get_dpm_level_enable_mask_value(void *table)
+{
+	int32_t i;
+	int32_t mask = 0;
+	struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
+
+	for (i = dpm_table->count; i > 0; i--) {
+		mask = mask << 1;
+		if (dpm_table->dpm_level[i - 1].enabled)
+			mask |= 0x1;
+		else
+			mask &= 0xFFFFFFFE;
+	}
+
+	return mask;
+}
+
+uint8_t phm_get_voltage_index(
+		struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
+{
+	uint8_t count = (uint8_t) (lookup_table->count);
+	uint8_t i;
+
+	PP_ASSERT_WITH_CODE((NULL != lookup_table),
+			"Lookup Table empty.", return 0);
+	PP_ASSERT_WITH_CODE((0 != count),
+			"Lookup Table empty.", return 0);
+
+	for (i = 0; i < lookup_table->count; i++) {
+		/* find first voltage equal or bigger than requested */
+		if (lookup_table->entries[i].us_vdd >= voltage)
+			return i;
+	}
+	/* voltage is bigger than max voltage in the table */
+	return i - 1;
+}
+
+uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci)
+{
+	uint32_t  i;
+
+	for (i = 0; i < vddci_table->count; i++) {
+		if (vddci_table->entries[i].value >= vddci)
+			return vddci_table->entries[i].value;
+	}
+
+	PP_ASSERT_WITH_CODE(false,
+			"VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
+			return vddci_table->entries[i].value);
+}
+
+int phm_find_boot_level(void *table,
+		uint32_t value, uint32_t *boot_level)
+{
+	int result = -EINVAL;
+	uint32_t i;
+	struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
+
+	for (i = 0; i < dpm_table->count; i++) {
+		if (value == dpm_table->dpm_level[i].value) {
+			*boot_level = i;
+			result = 0;
+		}
+	}
+
+	return result;
+}
+
+int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
+	phm_ppt_v1_voltage_lookup_table *lookup_table,
+	uint16_t virtual_voltage_id, int32_t *sclk)
+{
+	uint8_t entryId;
+	uint8_t voltageId;
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
+
+	/* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
+	for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
+		voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
+		if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
+			break;
+	}
+
+	PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
+			"Can't find requested voltage id in vdd_dep_on_sclk table!",
+			return -EINVAL;
+			);
+
+	*sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
+
+	return 0;
+}
+
+/**
+ * Initialize Dynamic State Adjustment Rule Settings
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ */
+int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
+{
+	uint32_t table_size;
+	struct phm_clock_voltage_dependency_table *table_clk_vlt;
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	/* initialize vddc_dep_on_dal_pwrl table */
+	table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
+	table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == table_clk_vlt) {
+		printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
+		return -ENOMEM;
+	} else {
+		table_clk_vlt->count = 4;
+		table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
+		table_clk_vlt->entries[0].v = 0;
+		table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
+		table_clk_vlt->entries[1].v = 720;
+		table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
+		table_clk_vlt->entries[2].v = 810;
+		table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
+		table_clk_vlt->entries[3].v = 900;
+		pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
+		hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
+	}
+
+	return 0;
+}
+
+int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
+{
+	if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
+		kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
+		hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+	}
+
+	if (NULL != hwmgr->backend) {
+		kfree(hwmgr->backend);
+		hwmgr->backend = NULL;
+	}
+
+	return 0;
+}
+
+uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
+{
+	uint32_t level = 0;
+
+	while (0 == (mask & (1 << level)))
+		level++;
+
+	return level;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef PP_HWMGR_PPT_H
+#define PP_HWMGR_PPT_H
+
+#include "hardwaremanager.h"
+#include "smumgr.h"
+#include "atom-types.h"
+
+struct phm_ppt_v1_clock_voltage_dependency_record {
+	uint32_t clk;
+	uint8_t vddInd;
+	uint16_t vdd_offset;
+	uint16_t vddc;
+	uint16_t vddgfx;
+	uint16_t vddci;
+	uint16_t mvdd;
+	uint8_t phases;
+	uint8_t cks_enable;
+	uint8_t cks_voffset;
+};
+
+typedef struct phm_ppt_v1_clock_voltage_dependency_record phm_ppt_v1_clock_voltage_dependency_record;
+
+struct phm_ppt_v1_clock_voltage_dependency_table {
+	uint32_t count;                                            /* Number of entries. */
+	phm_ppt_v1_clock_voltage_dependency_record entries[1];     /* Dynamically allocate count entries. */
+};
+
+typedef struct phm_ppt_v1_clock_voltage_dependency_table phm_ppt_v1_clock_voltage_dependency_table;
+
+
+/* Multimedia Clock Voltage Dependency records and table */
+struct phm_ppt_v1_mm_clock_voltage_dependency_record {
+	uint32_t  dclk;                                              /* UVD D-clock */
+	uint32_t  vclk;                                              /* UVD V-clock */
+	uint32_t  eclk;                                              /* VCE clock */
+	uint32_t  aclk;                                              /* ACP clock */
+	uint32_t  samclock;                                          /* SAMU clock */
+	uint8_t	vddcInd;
+	uint16_t vddgfx_offset;
+	uint16_t vddc;
+	uint16_t vddgfx;
+	uint8_t phases;
+};
+typedef struct phm_ppt_v1_mm_clock_voltage_dependency_record phm_ppt_v1_mm_clock_voltage_dependency_record;
+
+struct phm_ppt_v1_mm_clock_voltage_dependency_table {
+	uint32_t count;													/* Number of entries. */
+	phm_ppt_v1_mm_clock_voltage_dependency_record entries[1];		/* Dynamically allocate count entries. */
+};
+typedef struct phm_ppt_v1_mm_clock_voltage_dependency_table phm_ppt_v1_mm_clock_voltage_dependency_table;
+
+struct phm_ppt_v1_voltage_lookup_record {
+	uint16_t us_calculated;
+	uint16_t us_vdd;												/* Base voltage */
+	uint16_t us_cac_low;
+	uint16_t us_cac_mid;
+	uint16_t us_cac_high;
+};
+typedef struct phm_ppt_v1_voltage_lookup_record phm_ppt_v1_voltage_lookup_record;
+
+struct phm_ppt_v1_voltage_lookup_table {
+	uint32_t count;
+	phm_ppt_v1_voltage_lookup_record entries[1];    /* Dynamically allocate count entries. */
+};
+typedef struct phm_ppt_v1_voltage_lookup_table phm_ppt_v1_voltage_lookup_table;
+
+/* PCIE records and Table */
+
+struct phm_ppt_v1_pcie_record {
+	uint8_t gen_speed;
+	uint8_t lane_width;
+};
+typedef struct phm_ppt_v1_pcie_record phm_ppt_v1_pcie_record;
+
+struct phm_ppt_v1_pcie_table {
+	uint32_t count;                                            /* Number of entries. */
+	phm_ppt_v1_pcie_record entries[1];                         /* Dynamically allocate count entries. */
+};
+typedef struct phm_ppt_v1_pcie_table phm_ppt_v1_pcie_table;
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c
@@ -0,0 +1,76 @@
+#include <linux/errno.h>
+#include "linux/delay.h"
+#include "hwmgr.h"
+#include "amd_acpi.h"
+
+bool acpi_atcs_functions_supported(void *device, uint32_t index)
+{
+	int32_t result;
+	struct atcs_verify_interface output_buf = {0};
+
+	int32_t temp_buffer = 1;
+
+	result = cgs_call_acpi_method(device, CGS_ACPI_METHOD_ATCS,
+						ATCS_FUNCTION_VERIFY_INTERFACE,
+						&temp_buffer,
+						&output_buf,
+						1,
+						sizeof(temp_buffer),
+						sizeof(output_buf));
+
+	return result == 0 ? (output_buf.function_bits & (1 << (index - 1))) != 0 : false;
+}
+
+int acpi_pcie_perf_request(void *device, uint8_t perf_req, bool advertise)
+{
+	struct atcs_pref_req_input atcs_input;
+	struct atcs_pref_req_output atcs_output;
+	u32 retry = 3;
+	int result;
+	struct cgs_system_info info = {0};
+
+	if (!acpi_atcs_functions_supported(device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST))
+		return -EINVAL;
+
+	info.size = sizeof(struct cgs_system_info);
+	info.info_id = CGS_SYSTEM_INFO_ADAPTER_BDF_ID;
+	result = cgs_query_system_info(device, &info);
+	if (result != 0)
+		return -EINVAL;
+	atcs_input.client_id = (uint16_t)info.value;
+	atcs_input.size = sizeof(struct atcs_pref_req_input);
+	atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK;
+	atcs_input.flags = ATCS_WAIT_FOR_COMPLETION;
+	if (advertise)
+		atcs_input.flags |= ATCS_ADVERTISE_CAPS;
+	atcs_input.req_type = ATCS_PCIE_LINK_SPEED;
+	atcs_input.perf_req = perf_req;
+
+	atcs_output.size = sizeof(struct atcs_pref_req_input);
+
+	while (retry--) {
+		result = cgs_call_acpi_method(device,
+						CGS_ACPI_METHOD_ATCS,
+						ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST,
+						&atcs_input,
+						&atcs_output,
+						0,
+						sizeof(atcs_input),
+						sizeof(atcs_output));
+		if (result != 0)
+			return -EIO;
+
+		switch (atcs_output.ret_val) {
+		case ATCS_REQUEST_REFUSED:
+		default:
+			return -EINVAL;
+		case ATCS_REQUEST_COMPLETE:
+			return 0;
+		case ATCS_REQUEST_IN_PROGRESS:
+			udelay(10);
+			break;
+		}
+	}
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
@@ -0,0 +1,1207 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+
+#include "ppatomctrl.h"
+#include "atombios.h"
+#include "cgs_common.h"
+#include "pp_debug.h"
+#include "ppevvmath.h"
+
+#define MEM_ID_MASK           0xff000000
+#define MEM_ID_SHIFT          24
+#define CLOCK_RANGE_MASK      0x00ffffff
+#define CLOCK_RANGE_SHIFT     0
+#define LOW_NIBBLE_MASK       0xf
+#define DATA_EQU_PREV         0
+#define DATA_FROM_TABLE       4
+
+union voltage_object_info {
+	struct _ATOM_VOLTAGE_OBJECT_INFO v1;
+	struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
+	struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
+};
+
+static int atomctrl_retrieve_ac_timing(
+		uint8_t index,
+		ATOM_INIT_REG_BLOCK *reg_block,
+		pp_atomctrl_mc_reg_table *table)
+{
+	uint32_t i, j;
+	uint8_t tmem_id;
+	ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
+		((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize));
+
+	uint8_t num_ranges = 0;
+
+	while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
+			num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) {
+		tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
+
+		if (index == tmem_id) {
+			table->mc_reg_table_entry[num_ranges].mclk_max =
+				(uint32_t)((*(uint32_t *)reg_data & CLOCK_RANGE_MASK) >>
+						CLOCK_RANGE_SHIFT);
+
+			for (i = 0, j = 1; i < table->last; i++) {
+				if ((table->mc_reg_address[i].uc_pre_reg_data &
+							LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
+					table->mc_reg_table_entry[num_ranges].mc_data[i] =
+						(uint32_t)*((uint32_t *)reg_data + j);
+					j++;
+				} else if ((table->mc_reg_address[i].uc_pre_reg_data &
+							LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
+					table->mc_reg_table_entry[num_ranges].mc_data[i] =
+						table->mc_reg_table_entry[num_ranges].mc_data[i-1];
+				}
+			}
+			num_ranges++;
+		}
+
+		reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
+			((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ;
+	}
+
+	PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK),
+			"Invalid VramInfo table.", return -1);
+	table->num_entries = num_ranges;
+
+	return 0;
+}
+
+/**
+ * Get memory clock AC timing registers index from VBIOS table
+ * VBIOS set end of memory clock AC timing registers by ucPreRegDataLength bit6 = 1
+ * @param    reg_block the address ATOM_INIT_REG_BLOCK
+ * @param    table the address of MCRegTable
+ * @return   0
+ */
+static int atomctrl_set_mc_reg_address_table(
+		ATOM_INIT_REG_BLOCK *reg_block,
+		pp_atomctrl_mc_reg_table *table)
+{
+	uint8_t i = 0;
+	uint8_t num_entries = (uint8_t)((le16_to_cpu(reg_block->usRegIndexTblSize))
+			/ sizeof(ATOM_INIT_REG_INDEX_FORMAT));
+	ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
+
+	num_entries--;        /* subtract 1 data end mark entry */
+
+	PP_ASSERT_WITH_CODE((num_entries <= VBIOS_MC_REGISTER_ARRAY_SIZE),
+			"Invalid VramInfo table.", return -1);
+
+	/* ucPreRegDataLength bit6 = 1 is the end of memory clock AC timing registers */
+	while ((!(format->ucPreRegDataLength & ACCESS_PLACEHOLDER)) &&
+			(i < num_entries)) {
+		table->mc_reg_address[i].s1 =
+			(uint16_t)(le16_to_cpu(format->usRegIndex));
+		table->mc_reg_address[i].uc_pre_reg_data =
+			format->ucPreRegDataLength;
+
+		i++;
+		format = (ATOM_INIT_REG_INDEX_FORMAT *)
+			((uint8_t *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
+	}
+
+	table->last = i;
+	return 0;
+}
+
+
+int atomctrl_initialize_mc_reg_table(
+		struct pp_hwmgr *hwmgr,
+		uint8_t module_index,
+		pp_atomctrl_mc_reg_table *table)
+{
+	ATOM_VRAM_INFO_HEADER_V2_1 *vram_info;
+	ATOM_INIT_REG_BLOCK *reg_block;
+	int result = 0;
+	u8 frev, crev;
+	u16 size;
+
+	vram_info = (ATOM_VRAM_INFO_HEADER_V2_1 *)
+		cgs_atom_get_data_table(hwmgr->device,
+				GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
+
+	if (module_index >= vram_info->ucNumOfVRAMModule) {
+		printk(KERN_ERR "[ powerplay ] Invalid VramInfo table.");
+		result = -1;
+	} else if (vram_info->sHeader.ucTableFormatRevision < 2) {
+		printk(KERN_ERR "[ powerplay ] Invalid VramInfo table.");
+		result = -1;
+	}
+
+	if (0 == result) {
+		reg_block = (ATOM_INIT_REG_BLOCK *)
+			((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
+		result = atomctrl_set_mc_reg_address_table(reg_block, table);
+	}
+
+	if (0 == result) {
+		result = atomctrl_retrieve_ac_timing(module_index,
+					reg_block, table);
+	}
+
+	return result;
+}
+
+/**
+ * Set DRAM timings based on engine clock and memory clock.
+ */
+int atomctrl_set_engine_dram_timings_rv770(
+		struct pp_hwmgr *hwmgr,
+		uint32_t engine_clock,
+		uint32_t memory_clock)
+{
+	SET_ENGINE_CLOCK_PS_ALLOCATION engine_clock_parameters;
+
+	/* They are both in 10KHz Units. */
+	engine_clock_parameters.ulTargetEngineClock =
+		(uint32_t) engine_clock & SET_CLOCK_FREQ_MASK;
+	engine_clock_parameters.ulTargetEngineClock |=
+		(COMPUTE_ENGINE_PLL_PARAM << 24);
+
+	/* in 10 khz units.*/
+	engine_clock_parameters.sReserved.ulClock =
+		(uint32_t) memory_clock & SET_CLOCK_FREQ_MASK;
+	return cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings),
+			&engine_clock_parameters);
+}
+
+/**
+ * Private Function to get the PowerPlay Table Address.
+ * WARNING: The tabled returned by this function is in
+ * dynamically allocated memory.
+ * The caller has to release if by calling kfree.
+ */
+static ATOM_VOLTAGE_OBJECT_INFO *get_voltage_info_table(void *device)
+{
+	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+	u8 frev, crev;
+	u16 size;
+	union voltage_object_info *voltage_info;
+
+	voltage_info = (union voltage_object_info *)
+		cgs_atom_get_data_table(device, index,
+			&size, &frev, &crev);
+
+	if (voltage_info != NULL)
+		return (ATOM_VOLTAGE_OBJECT_INFO *) &(voltage_info->v3);
+	else
+		return NULL;
+}
+
+static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3(
+		const ATOM_VOLTAGE_OBJECT_INFO_V3_1 * voltage_object_info_table,
+		uint8_t voltage_type, uint8_t voltage_mode)
+{
+	unsigned int size = le16_to_cpu(voltage_object_info_table->sHeader.usStructureSize);
+	unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
+	uint8_t *start = (uint8_t *)voltage_object_info_table;
+
+	while (offset < size) {
+		const ATOM_VOLTAGE_OBJECT_V3 *voltage_object =
+			(const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
+
+		if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType &&
+			voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode)
+			return voltage_object;
+
+		offset += le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
+	}
+
+	return NULL;
+}
+
+/** atomctrl_get_memory_pll_dividers_si().
+ *
+ * @param hwmgr                 input parameter: pointer to HwMgr
+ * @param clock_value             input parameter: memory clock
+ * @param dividers                 output parameter: memory PLL dividers
+ * @param strobe_mode            input parameter: 1 for strobe mode,  0 for performance mode
+ */
+int atomctrl_get_memory_pll_dividers_si(
+		struct pp_hwmgr *hwmgr,
+		uint32_t clock_value,
+		pp_atomctrl_memory_clock_param *mpll_param,
+		bool strobe_mode)
+{
+	COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters;
+	int result;
+
+	mpll_parameters.ulClock = (uint32_t) clock_value;
+	mpll_parameters.ucInputFlag = (uint8_t)((strobe_mode) ? 1 : 0);
+
+	result = cgs_atom_exec_cmd_table
+		(hwmgr->device,
+		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
+		 &mpll_parameters);
+
+	if (0 == result) {
+		mpll_param->mpll_fb_divider.clk_frac =
+			mpll_parameters.ulFbDiv.usFbDivFrac;
+		mpll_param->mpll_fb_divider.cl_kf =
+			mpll_parameters.ulFbDiv.usFbDiv;
+		mpll_param->mpll_post_divider =
+			(uint32_t)mpll_parameters.ucPostDiv;
+		mpll_param->vco_mode =
+			(uint32_t)(mpll_parameters.ucPllCntlFlag &
+					MPLL_CNTL_FLAG_VCO_MODE_MASK);
+		mpll_param->yclk_sel =
+			(uint32_t)((mpll_parameters.ucPllCntlFlag &
+						MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0);
+		mpll_param->qdr =
+			(uint32_t)((mpll_parameters.ucPllCntlFlag &
+						MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0);
+		mpll_param->half_rate =
+			(uint32_t)((mpll_parameters.ucPllCntlFlag &
+						MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0);
+		mpll_param->dll_speed =
+			(uint32_t)(mpll_parameters.ucDllSpeed);
+		mpll_param->bw_ctrl =
+			(uint32_t)(mpll_parameters.ucBWCntl);
+	}
+
+	return result;
+}
+
+/** atomctrl_get_memory_pll_dividers_vi().
+ *
+ * @param hwmgr                 input parameter: pointer to HwMgr
+ * @param clock_value             input parameter: memory clock
+ * @param dividers               output parameter: memory PLL dividers
+ */
+int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr,
+		uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param)
+{
+	COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2 mpll_parameters;
+	int result;
+
+	mpll_parameters.ulClock.ulClock = (uint32_t)clock_value;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
+			&mpll_parameters);
+
+	if (!result)
+		mpll_param->mpll_post_divider =
+				(uint32_t)mpll_parameters.ulClock.ucPostDiv;
+
+	return result;
+}
+
+int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr,
+					  uint32_t clock_value,
+					  pp_atomctrl_clock_dividers_kong *dividers)
+{
+	COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 pll_parameters;
+	int result;
+
+	pll_parameters.ulClock = clock_value;
+
+	result = cgs_atom_exec_cmd_table
+		(hwmgr->device,
+		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
+		 &pll_parameters);
+
+	if (0 == result) {
+		dividers->pll_post_divider = pll_parameters.ucPostDiv;
+		dividers->real_clock = pll_parameters.ulClock;
+	}
+
+	return result;
+}
+
+int atomctrl_get_engine_pll_dividers_vi(
+		struct pp_hwmgr *hwmgr,
+		uint32_t clock_value,
+		pp_atomctrl_clock_dividers_vi *dividers)
+{
+	COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
+	int result;
+
+	pll_patameters.ulClock.ulClock = clock_value;
+	pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK;
+
+	result = cgs_atom_exec_cmd_table
+		(hwmgr->device,
+		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
+		 &pll_patameters);
+
+	if (0 == result) {
+		dividers->pll_post_divider =
+			pll_patameters.ulClock.ucPostDiv;
+		dividers->real_clock =
+			pll_patameters.ulClock.ulClock;
+
+		dividers->ul_fb_div.ul_fb_div_frac =
+			pll_patameters.ulFbDiv.usFbDivFrac;
+		dividers->ul_fb_div.ul_fb_div =
+			pll_patameters.ulFbDiv.usFbDiv;
+
+		dividers->uc_pll_ref_div =
+			pll_patameters.ucPllRefDiv;
+		dividers->uc_pll_post_div =
+			pll_patameters.ucPllPostDiv;
+		dividers->uc_pll_cntl_flag =
+			pll_patameters.ucPllCntlFlag;
+	}
+
+	return result;
+}
+
+int atomctrl_get_dfs_pll_dividers_vi(
+		struct pp_hwmgr *hwmgr,
+		uint32_t clock_value,
+		pp_atomctrl_clock_dividers_vi *dividers)
+{
+	COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
+	int result;
+
+	pll_patameters.ulClock.ulClock = clock_value;
+	pll_patameters.ulClock.ucPostDiv =
+		COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK;
+
+	result = cgs_atom_exec_cmd_table
+		(hwmgr->device,
+		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
+		 &pll_patameters);
+
+	if (0 == result) {
+		dividers->pll_post_divider =
+			pll_patameters.ulClock.ucPostDiv;
+		dividers->real_clock =
+			pll_patameters.ulClock.ulClock;
+
+		dividers->ul_fb_div.ul_fb_div_frac =
+			pll_patameters.ulFbDiv.usFbDivFrac;
+		dividers->ul_fb_div.ul_fb_div =
+			pll_patameters.ulFbDiv.usFbDiv;
+
+		dividers->uc_pll_ref_div =
+			pll_patameters.ucPllRefDiv;
+		dividers->uc_pll_post_div =
+			pll_patameters.ucPllPostDiv;
+		dividers->uc_pll_cntl_flag =
+			pll_patameters.ucPllCntlFlag;
+	}
+
+	return result;
+}
+
+/**
+ * Get the reference clock in 10KHz
+ */
+uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr)
+{
+	ATOM_FIRMWARE_INFO *fw_info;
+	u8 frev, crev;
+	u16 size;
+	uint32_t clock;
+
+	fw_info = (ATOM_FIRMWARE_INFO *)
+		cgs_atom_get_data_table(hwmgr->device,
+			GetIndexIntoMasterTable(DATA, FirmwareInfo),
+			&size, &frev, &crev);
+
+	if (fw_info == NULL)
+		clock = 2700;
+	else
+		clock = (uint32_t)(le16_to_cpu(fw_info->usReferenceClock));
+
+	return clock;
+}
+
+/**
+ * Returns true if the given voltage type is controlled by GPIO pins.
+ * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
+ * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
+ * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
+ */
+bool atomctrl_is_voltage_controled_by_gpio_v3(
+		struct pp_hwmgr *hwmgr,
+		uint8_t voltage_type,
+		uint8_t voltage_mode)
+{
+	ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
+		(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->device);
+	bool ret;
+
+	PP_ASSERT_WITH_CODE((NULL != voltage_info),
+			"Could not find Voltage Table in BIOS.", return false;);
+
+	ret = (NULL != atomctrl_lookup_voltage_type_v3
+			(voltage_info, voltage_type, voltage_mode)) ? true : false;
+
+	return ret;
+}
+
+int atomctrl_get_voltage_table_v3(
+		struct pp_hwmgr *hwmgr,
+		uint8_t voltage_type,
+		uint8_t voltage_mode,
+		pp_atomctrl_voltage_table *voltage_table)
+{
+	ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
+		(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->device);
+	const ATOM_VOLTAGE_OBJECT_V3 *voltage_object;
+	unsigned int i;
+
+	PP_ASSERT_WITH_CODE((NULL != voltage_info),
+			"Could not find Voltage Table in BIOS.", return -1;);
+
+	voltage_object = atomctrl_lookup_voltage_type_v3
+		(voltage_info, voltage_type, voltage_mode);
+
+	if (voltage_object == NULL)
+		return -1;
+
+	PP_ASSERT_WITH_CODE(
+			(voltage_object->asGpioVoltageObj.ucGpioEntryNum <=
+			PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES),
+			"Too many voltage entries!",
+			return -1;
+			);
+
+	for (i = 0; i < voltage_object->asGpioVoltageObj.ucGpioEntryNum; i++) {
+		voltage_table->entries[i].value =
+			voltage_object->asGpioVoltageObj.asVolGpioLut[i].usVoltageValue;
+		voltage_table->entries[i].smio_low =
+			voltage_object->asGpioVoltageObj.asVolGpioLut[i].ulVoltageId;
+	}
+
+	voltage_table->mask_low    =
+		voltage_object->asGpioVoltageObj.ulGpioMaskVal;
+	voltage_table->count      =
+		voltage_object->asGpioVoltageObj.ucGpioEntryNum;
+	voltage_table->phase_delay =
+		voltage_object->asGpioVoltageObj.ucPhaseDelay;
+
+	return 0;
+}
+
+static bool atomctrl_lookup_gpio_pin(
+		ATOM_GPIO_PIN_LUT * gpio_lookup_table,
+		const uint32_t pinId,
+		pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
+{
+	unsigned int size = le16_to_cpu(gpio_lookup_table->sHeader.usStructureSize);
+	unsigned int offset = offsetof(ATOM_GPIO_PIN_LUT, asGPIO_Pin[0]);
+	uint8_t *start = (uint8_t *)gpio_lookup_table;
+
+	while (offset < size) {
+		const ATOM_GPIO_PIN_ASSIGNMENT *pin_assignment =
+			(const ATOM_GPIO_PIN_ASSIGNMENT *)(start + offset);
+
+		if (pinId == pin_assignment->ucGPIO_ID) {
+			gpio_pin_assignment->uc_gpio_pin_bit_shift =
+				pin_assignment->ucGpioPinBitShift;
+			gpio_pin_assignment->us_gpio_pin_aindex =
+				le16_to_cpu(pin_assignment->usGpioPin_AIndex);
+			return false;
+		}
+
+		offset += offsetof(ATOM_GPIO_PIN_ASSIGNMENT, ucGPIO_ID) + 1;
+	}
+
+	return true;
+}
+
+/**
+ * Private Function to get the PowerPlay Table Address.
+ * WARNING: The tabled returned by this function is in
+ * dynamically allocated memory.
+ * The caller has to release if by calling kfree.
+ */
+static ATOM_GPIO_PIN_LUT *get_gpio_lookup_table(void *device)
+{
+	u8 frev, crev;
+	u16 size;
+	void *table_address;
+
+	table_address = (ATOM_GPIO_PIN_LUT *)
+		cgs_atom_get_data_table(device,
+				GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT),
+				&size, &frev, &crev);
+
+	PP_ASSERT_WITH_CODE((NULL != table_address),
+			"Error retrieving BIOS Table Address!", return NULL;);
+
+	return (ATOM_GPIO_PIN_LUT *)table_address;
+}
+
+/**
+ * Returns 1 if the given pin id find in lookup table.
+ */
+bool atomctrl_get_pp_assign_pin(
+		struct pp_hwmgr *hwmgr,
+		const uint32_t pinId,
+		pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
+{
+	bool bRet = 0;
+	ATOM_GPIO_PIN_LUT *gpio_lookup_table =
+		get_gpio_lookup_table(hwmgr->device);
+
+	PP_ASSERT_WITH_CODE((NULL != gpio_lookup_table),
+			"Could not find GPIO lookup Table in BIOS.", return -1);
+
+	bRet = atomctrl_lookup_gpio_pin(gpio_lookup_table, pinId,
+		gpio_pin_assignment);
+
+	return bRet;
+}
+
+int atomctrl_calculate_voltage_evv_on_sclk(
+		struct pp_hwmgr *hwmgr,
+		uint8_t voltage_type,
+		uint32_t sclk,
+		uint16_t virtual_voltage_Id,
+		uint16_t *voltage,
+		uint16_t dpm_level,
+		bool debug)
+{
+	ATOM_ASIC_PROFILING_INFO_V3_4 *getASICProfilingInfo;
+
+	EFUSE_LINEAR_FUNC_PARAM sRO_fuse;
+	EFUSE_LINEAR_FUNC_PARAM sCACm_fuse;
+	EFUSE_LINEAR_FUNC_PARAM sCACb_fuse;
+	EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse;
+	EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse;
+	EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse;
+	EFUSE_INPUT_PARAMETER sInput_FuseValues;
+	READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues;
+
+	uint32_t ul_RO_fused, ul_CACb_fused, ul_CACm_fused, ul_Kt_Beta_fused, ul_Kv_m_fused, ul_Kv_b_fused;
+	fInt fSM_A0, fSM_A1, fSM_A2, fSM_A3, fSM_A4, fSM_A5, fSM_A6, fSM_A7;
+	fInt fMargin_RO_a, fMargin_RO_b, fMargin_RO_c, fMargin_fixed, fMargin_FMAX_mean, fMargin_Plat_mean, fMargin_FMAX_sigma, fMargin_Plat_sigma, fMargin_DC_sigma;
+	fInt fLkg_FT, repeat;
+	fInt fMicro_FMAX, fMicro_CR, fSigma_FMAX, fSigma_CR, fSigma_DC, fDC_SCLK, fSquared_Sigma_DC, fSquared_Sigma_CR, fSquared_Sigma_FMAX;
+	fInt fRLL_LoadLine, fPowerDPMx, fDerateTDP, fVDDC_base, fA_Term, fC_Term, fB_Term, fRO_DC_margin;
+	fInt fRO_fused, fCACm_fused, fCACb_fused, fKv_m_fused, fKv_b_fused, fKt_Beta_fused, fFT_Lkg_V0NORM;
+	fInt fSclk_margin, fSclk, fEVV_V;
+	fInt fV_min, fV_max, fT_prod, fLKG_Factor, fT_FT, fV_FT, fV_x, fTDP_Power, fTDP_Power_right, fTDP_Power_left, fTDP_Current, fV_NL;
+	uint32_t ul_FT_Lkg_V0NORM;
+	fInt fLn_MaxDivMin, fMin, fAverage, fRange;
+	fInt fRoots[2];
+	fInt fStepSize = GetScaledFraction(625, 100000);
+
+	int result;
+
+	getASICProfilingInfo = (ATOM_ASIC_PROFILING_INFO_V3_4 *)
+			cgs_atom_get_data_table(hwmgr->device,
+					GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
+					NULL, NULL, NULL);
+
+	if (!getASICProfilingInfo)
+		return -1;
+
+	if(getASICProfilingInfo->asHeader.ucTableFormatRevision < 3 ||
+			(getASICProfilingInfo->asHeader.ucTableFormatRevision == 3 &&
+			getASICProfilingInfo->asHeader.ucTableContentRevision < 4))
+		return -1;
+
+	/*-----------------------------------------------------------
+	 *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL
+	 *-----------------------------------------------------------
+	 */
+	fRLL_LoadLine = Divide(getASICProfilingInfo->ulLoadLineSlop, 1000);
+
+	switch (dpm_level) {
+	case 1:
+		fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm1);
+		fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM1, 1000);
+		break;
+	case 2:
+		fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm2);
+		fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM2, 1000);
+		break;
+	case 3:
+		fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm3);
+		fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM3, 1000);
+		break;
+	case 4:
+		fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm4);
+		fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM4, 1000);
+		break;
+	case 5:
+		fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm5);
+		fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM5, 1000);
+		break;
+	case 6:
+		fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm6);
+		fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM6, 1000);
+		break;
+	case 7:
+		fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm7);
+		fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM7, 1000);
+		break;
+	default:
+		printk(KERN_ERR "DPM Level not supported\n");
+		fPowerDPMx = Convert_ULONG_ToFraction(1);
+		fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM0, 1000);
+	}
+
+	/*-------------------------
+	 * DECODING FUSE VALUES
+	 * ------------------------
+	 */
+	/*Decode RO_Fused*/
+	sRO_fuse = getASICProfilingInfo->sRoFuse;
+
+	sInput_FuseValues.usEfuseIndex = sRO_fuse.usEfuseIndex;
+	sInput_FuseValues.ucBitShift = sRO_fuse.ucEfuseBitLSB;
+	sInput_FuseValues.ucBitLength = sRO_fuse.ucEfuseLength;
+
+	sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+			&sOutput_FuseValues);
+
+	if (result)
+		return result;
+
+	/* Finally, the actual fuse value */
+	ul_RO_fused = sOutput_FuseValues.ulEfuseValue;
+	fMin = GetScaledFraction(sRO_fuse.ulEfuseMin, 1);
+	fRange = GetScaledFraction(sRO_fuse.ulEfuseEncodeRange, 1);
+	fRO_fused = fDecodeLinearFuse(ul_RO_fused, fMin, fRange, sRO_fuse.ucEfuseLength);
+
+	sCACm_fuse = getASICProfilingInfo->sCACm;
+
+	sInput_FuseValues.usEfuseIndex = sCACm_fuse.usEfuseIndex;
+	sInput_FuseValues.ucBitShift = sCACm_fuse.ucEfuseBitLSB;
+	sInput_FuseValues.ucBitLength = sCACm_fuse.ucEfuseLength;
+
+	sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+			&sOutput_FuseValues);
+
+	if (result)
+		return result;
+
+	ul_CACm_fused = sOutput_FuseValues.ulEfuseValue;
+	fMin = GetScaledFraction(sCACm_fuse.ulEfuseMin, 1000);
+	fRange = GetScaledFraction(sCACm_fuse.ulEfuseEncodeRange, 1000);
+
+	fCACm_fused = fDecodeLinearFuse(ul_CACm_fused, fMin, fRange, sCACm_fuse.ucEfuseLength);
+
+	sCACb_fuse = getASICProfilingInfo->sCACb;
+
+	sInput_FuseValues.usEfuseIndex = sCACb_fuse.usEfuseIndex;
+	sInput_FuseValues.ucBitShift = sCACb_fuse.ucEfuseBitLSB;
+	sInput_FuseValues.ucBitLength = sCACb_fuse.ucEfuseLength;
+	sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+			&sOutput_FuseValues);
+
+	if (result)
+		return result;
+
+	ul_CACb_fused = sOutput_FuseValues.ulEfuseValue;
+	fMin = GetScaledFraction(sCACb_fuse.ulEfuseMin, 1000);
+	fRange = GetScaledFraction(sCACb_fuse.ulEfuseEncodeRange, 1000);
+
+	fCACb_fused = fDecodeLinearFuse(ul_CACb_fused, fMin, fRange, sCACb_fuse.ucEfuseLength);
+
+	sKt_Beta_fuse = getASICProfilingInfo->sKt_b;
+
+	sInput_FuseValues.usEfuseIndex = sKt_Beta_fuse.usEfuseIndex;
+	sInput_FuseValues.ucBitShift = sKt_Beta_fuse.ucEfuseBitLSB;
+	sInput_FuseValues.ucBitLength = sKt_Beta_fuse.ucEfuseLength;
+
+	sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+			&sOutput_FuseValues);
+
+	if (result)
+		return result;
+
+	ul_Kt_Beta_fused = sOutput_FuseValues.ulEfuseValue;
+	fAverage = GetScaledFraction(sKt_Beta_fuse.ulEfuseEncodeAverage, 1000);
+	fRange = GetScaledFraction(sKt_Beta_fuse.ulEfuseEncodeRange, 1000);
+
+	fKt_Beta_fused = fDecodeLogisticFuse(ul_Kt_Beta_fused,
+			fAverage, fRange, sKt_Beta_fuse.ucEfuseLength);
+
+	sKv_m_fuse = getASICProfilingInfo->sKv_m;
+
+	sInput_FuseValues.usEfuseIndex = sKv_m_fuse.usEfuseIndex;
+	sInput_FuseValues.ucBitShift = sKv_m_fuse.ucEfuseBitLSB;
+	sInput_FuseValues.ucBitLength = sKv_m_fuse.ucEfuseLength;
+
+	sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+			&sOutput_FuseValues);
+	if (result)
+		return result;
+
+	ul_Kv_m_fused = sOutput_FuseValues.ulEfuseValue;
+	fAverage = GetScaledFraction(sKv_m_fuse.ulEfuseEncodeAverage, 1000);
+	fRange = GetScaledFraction((sKv_m_fuse.ulEfuseEncodeRange & 0x7fffffff), 1000);
+	fRange = fMultiply(fRange, ConvertToFraction(-1));
+
+	fKv_m_fused = fDecodeLogisticFuse(ul_Kv_m_fused,
+			fAverage, fRange, sKv_m_fuse.ucEfuseLength);
+
+	sKv_b_fuse = getASICProfilingInfo->sKv_b;
+
+	sInput_FuseValues.usEfuseIndex = sKv_b_fuse.usEfuseIndex;
+	sInput_FuseValues.ucBitShift = sKv_b_fuse.ucEfuseBitLSB;
+	sInput_FuseValues.ucBitLength = sKv_b_fuse.ucEfuseLength;
+	sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+			&sOutput_FuseValues);
+
+	if (result)
+		return result;
+
+	ul_Kv_b_fused = sOutput_FuseValues.ulEfuseValue;
+	fAverage = GetScaledFraction(sKv_b_fuse.ulEfuseEncodeAverage, 1000);
+	fRange = GetScaledFraction(sKv_b_fuse.ulEfuseEncodeRange, 1000);
+
+	fKv_b_fused = fDecodeLogisticFuse(ul_Kv_b_fused,
+			fAverage, fRange, sKv_b_fuse.ucEfuseLength);
+
+	/* Decoding the Leakage - No special struct container */
+	/*
+	 * usLkgEuseIndex=56
+	 * ucLkgEfuseBitLSB=6
+	 * ucLkgEfuseLength=10
+	 * ulLkgEncodeLn_MaxDivMin=69077
+	 * ulLkgEncodeMax=1000000
+	 * ulLkgEncodeMin=1000
+	 * ulEfuseLogisticAlpha=13
+	 */
+
+	sInput_FuseValues.usEfuseIndex = getASICProfilingInfo->usLkgEuseIndex;
+	sInput_FuseValues.ucBitShift = getASICProfilingInfo->ucLkgEfuseBitLSB;
+	sInput_FuseValues.ucBitLength = getASICProfilingInfo->ucLkgEfuseLength;
+
+	sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+			&sOutput_FuseValues);
+
+	if (result)
+		return result;
+
+	ul_FT_Lkg_V0NORM = sOutput_FuseValues.ulEfuseValue;
+	fLn_MaxDivMin = GetScaledFraction(getASICProfilingInfo->ulLkgEncodeLn_MaxDivMin, 10000);
+	fMin = GetScaledFraction(getASICProfilingInfo->ulLkgEncodeMin, 10000);
+
+	fFT_Lkg_V0NORM = fDecodeLeakageID(ul_FT_Lkg_V0NORM,
+			fLn_MaxDivMin, fMin, getASICProfilingInfo->ucLkgEfuseLength);
+	fLkg_FT = fFT_Lkg_V0NORM;
+
+	/*-------------------------------------------
+	 * PART 2 - Grabbing all required values
+	 *-------------------------------------------
+	 */
+	fSM_A0 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A0, 1000000),
+			ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A0_sign)));
+	fSM_A1 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A1, 1000000),
+			ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A1_sign)));
+	fSM_A2 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A2, 100000),
+			ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A2_sign)));
+	fSM_A3 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A3, 1000000),
+			ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A3_sign)));
+	fSM_A4 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A4, 1000000),
+			ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A4_sign)));
+	fSM_A5 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A5, 1000),
+			ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A5_sign)));
+	fSM_A6 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A6, 1000),
+			ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A6_sign)));
+	fSM_A7 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A7, 1000),
+			ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A7_sign)));
+
+	fMargin_RO_a = ConvertToFraction(getASICProfilingInfo->ulMargin_RO_a);
+	fMargin_RO_b = ConvertToFraction(getASICProfilingInfo->ulMargin_RO_b);
+	fMargin_RO_c = ConvertToFraction(getASICProfilingInfo->ulMargin_RO_c);
+
+	fMargin_fixed = ConvertToFraction(getASICProfilingInfo->ulMargin_fixed);
+
+	fMargin_FMAX_mean = GetScaledFraction(
+			getASICProfilingInfo->ulMargin_Fmax_mean, 10000);
+	fMargin_Plat_mean = GetScaledFraction(
+			getASICProfilingInfo->ulMargin_plat_mean, 10000);
+	fMargin_FMAX_sigma = GetScaledFraction(
+			getASICProfilingInfo->ulMargin_Fmax_sigma, 10000);
+	fMargin_Plat_sigma = GetScaledFraction(
+			getASICProfilingInfo->ulMargin_plat_sigma, 10000);
+
+	fMargin_DC_sigma = GetScaledFraction(
+			getASICProfilingInfo->ulMargin_DC_sigma, 100);
+	fMargin_DC_sigma = fDivide(fMargin_DC_sigma, ConvertToFraction(1000));
+
+	fCACm_fused = fDivide(fCACm_fused, ConvertToFraction(100));
+	fCACb_fused = fDivide(fCACb_fused, ConvertToFraction(100));
+	fKt_Beta_fused = fDivide(fKt_Beta_fused, ConvertToFraction(100));
+	fKv_m_fused =  fNegate(fDivide(fKv_m_fused, ConvertToFraction(100)));
+	fKv_b_fused = fDivide(fKv_b_fused, ConvertToFraction(10));
+
+	fSclk = GetScaledFraction(sclk, 100);
+
+	fV_max = fDivide(GetScaledFraction(
+			getASICProfilingInfo->ulMaxVddc, 1000), ConvertToFraction(4));
+	fT_prod = GetScaledFraction(getASICProfilingInfo->ulBoardCoreTemp, 10);
+	fLKG_Factor = GetScaledFraction(getASICProfilingInfo->ulEvvLkgFactor, 100);
+	fT_FT = GetScaledFraction(getASICProfilingInfo->ulLeakageTemp, 10);
+	fV_FT = fDivide(GetScaledFraction(
+			getASICProfilingInfo->ulLeakageVoltage, 1000), ConvertToFraction(4));
+	fV_min = fDivide(GetScaledFraction(
+			getASICProfilingInfo->ulMinVddc, 1000), ConvertToFraction(4));
+
+	/*-----------------------
+	 * PART 3
+	 *-----------------------
+	 */
+
+	fA_Term = fAdd(fMargin_RO_a, fAdd(fMultiply(fSM_A4,fSclk), fSM_A5));
+	fB_Term = fAdd(fAdd(fMultiply(fSM_A2, fSclk), fSM_A6), fMargin_RO_b);
+	fC_Term = fAdd(fMargin_RO_c,
+			fAdd(fMultiply(fSM_A0,fLkg_FT),
+			fAdd(fMultiply(fSM_A1, fMultiply(fLkg_FT,fSclk)),
+			fAdd(fMultiply(fSM_A3, fSclk),
+			fSubtract(fSM_A7,fRO_fused)))));
+
+	fVDDC_base = fSubtract(fRO_fused,
+			fSubtract(fMargin_RO_c,
+					fSubtract(fSM_A3, fMultiply(fSM_A1, fSclk))));
+	fVDDC_base = fDivide(fVDDC_base, fAdd(fMultiply(fSM_A0,fSclk), fSM_A2));
+
+	repeat = fSubtract(fVDDC_base,
+			fDivide(fMargin_DC_sigma, ConvertToFraction(1000)));
+
+	fRO_DC_margin = fAdd(fMultiply(fMargin_RO_a,
+			fGetSquare(repeat)),
+			fAdd(fMultiply(fMargin_RO_b, repeat),
+			fMargin_RO_c));
+
+	fDC_SCLK = fSubtract(fRO_fused,
+			fSubtract(fRO_DC_margin,
+			fSubtract(fSM_A3,
+			fMultiply(fSM_A2, repeat))));
+	fDC_SCLK = fDivide(fDC_SCLK, fAdd(fMultiply(fSM_A0,repeat), fSM_A1));
+
+	fSigma_DC = fSubtract(fSclk, fDC_SCLK);
+
+	fMicro_FMAX = fMultiply(fSclk, fMargin_FMAX_mean);
+	fMicro_CR = fMultiply(fSclk, fMargin_Plat_mean);
+	fSigma_FMAX = fMultiply(fSclk, fMargin_FMAX_sigma);
+	fSigma_CR = fMultiply(fSclk, fMargin_Plat_sigma);
+
+	fSquared_Sigma_DC = fGetSquare(fSigma_DC);
+	fSquared_Sigma_CR = fGetSquare(fSigma_CR);
+	fSquared_Sigma_FMAX = fGetSquare(fSigma_FMAX);
+
+	fSclk_margin = fAdd(fMicro_FMAX,
+			fAdd(fMicro_CR,
+			fAdd(fMargin_fixed,
+			fSqrt(fAdd(fSquared_Sigma_FMAX,
+			fAdd(fSquared_Sigma_DC, fSquared_Sigma_CR))))));
+	/*
+	 fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5;
+	 fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6;
+	 fC_Term = fRO_DC_margin + fSM_A0 * fLkg_FT + fSM_A1 * fLkg_FT * (fSclk + fSclk_margin) + fSM_A3 * (fSclk + fSclk_margin) + fSM_A7 - fRO_fused;
+	 */
+
+	fA_Term = fAdd(fMultiply(fSM_A4, fAdd(fSclk, fSclk_margin)), fSM_A5);
+	fB_Term = fAdd(fMultiply(fSM_A2, fAdd(fSclk, fSclk_margin)), fSM_A6);
+	fC_Term = fAdd(fRO_DC_margin,
+			fAdd(fMultiply(fSM_A0, fLkg_FT),
+			fAdd(fMultiply(fMultiply(fSM_A1, fLkg_FT),
+			fAdd(fSclk, fSclk_margin)),
+			fAdd(fMultiply(fSM_A3,
+			fAdd(fSclk, fSclk_margin)),
+			fSubtract(fSM_A7, fRO_fused)))));
+
+	SolveQuadracticEqn(fA_Term, fB_Term, fC_Term, fRoots);
+
+	if (GreaterThan(fRoots[0], fRoots[1]))
+		fEVV_V = fRoots[1];
+	else
+		fEVV_V = fRoots[0];
+
+	if (GreaterThan(fV_min, fEVV_V))
+		fEVV_V = fV_min;
+	else if (GreaterThan(fEVV_V, fV_max))
+		fEVV_V = fSubtract(fV_max, fStepSize);
+
+	fEVV_V = fRoundUpByStepSize(fEVV_V, fStepSize, 0);
+
+	/*-----------------
+	 * PART 4
+	 *-----------------
+	 */
+
+	fV_x = fV_min;
+
+	while (GreaterThan(fAdd(fV_max, fStepSize), fV_x)) {
+		fTDP_Power_left = fMultiply(fMultiply(fMultiply(fAdd(
+				fMultiply(fCACm_fused, fV_x), fCACb_fused), fSclk),
+				fGetSquare(fV_x)), fDerateTDP);
+
+		fTDP_Power_right = fMultiply(fFT_Lkg_V0NORM, fMultiply(fLKG_Factor,
+				fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused,
+				fT_prod), fKv_b_fused), fV_x)), fV_x)));
+		fTDP_Power_right = fMultiply(fTDP_Power_right, fExponential(fMultiply(
+				fKt_Beta_fused, fT_prod)));
+		fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply(
+				fAdd(fMultiply(fKv_m_fused, fT_prod), fKv_b_fused), fV_FT)));
+		fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply(
+				fKt_Beta_fused, fT_FT)));
+
+		fTDP_Power = fAdd(fTDP_Power_left, fTDP_Power_right);
+
+		fTDP_Current = fDivide(fTDP_Power, fV_x);
+
+		fV_NL = fAdd(fV_x, fDivide(fMultiply(fTDP_Current, fRLL_LoadLine),
+				ConvertToFraction(10)));
+
+		fV_NL = fRoundUpByStepSize(fV_NL, fStepSize, 0);
+
+		if (GreaterThan(fV_max, fV_NL) &&
+			(GreaterThan(fV_NL,fEVV_V) ||
+			Equal(fV_NL, fEVV_V))) {
+			fV_NL = fMultiply(fV_NL, ConvertToFraction(1000));
+
+			*voltage = (uint16_t)fV_NL.partial.real;
+			break;
+		} else
+			fV_x = fAdd(fV_x, fStepSize);
+	}
+
+	return result;
+}
+
+/** atomctrl_get_voltage_evv_on_sclk gets voltage via call to ATOM COMMAND table.
+ * @param hwmgr               	input: pointer to hwManager
+ * @param voltage_type            input: type of EVV voltage VDDC or VDDGFX
+ * @param sclk                        input: in 10Khz unit. DPM state SCLK frequency
+ *                                   		which is define in PPTable SCLK/VDDC dependence
+ *				table associated with this virtual_voltage_Id
+ * @param virtual_voltage_Id      input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
+ * @param voltage		       output: real voltage level in unit of mv
+ */
+int atomctrl_get_voltage_evv_on_sclk(
+		struct pp_hwmgr *hwmgr,
+		uint8_t voltage_type,
+		uint32_t sclk, uint16_t virtual_voltage_Id,
+		uint16_t *voltage)
+{
+	int result;
+	GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space;
+
+	get_voltage_info_param_space.ucVoltageType   =
+		voltage_type;
+	get_voltage_info_param_space.ucVoltageMode   =
+		ATOM_GET_VOLTAGE_EVV_VOLTAGE;
+	get_voltage_info_param_space.usVoltageLevel  =
+		virtual_voltage_Id;
+	get_voltage_info_param_space.ulSCLKFreq      =
+		sclk;
+
+	result = cgs_atom_exec_cmd_table(hwmgr->device,
+			GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
+			&get_voltage_info_param_space);
+
+	if (0 != result)
+		return result;
+
+	*voltage = ((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *)
+			(&get_voltage_info_param_space))->usVoltageLevel;
+
+	return result;
+}
+
+/**
+ * Get the mpll reference clock in 10KHz
+ */
+uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr)
+{
+	ATOM_COMMON_TABLE_HEADER *fw_info;
+	uint32_t clock;
+	u8 frev, crev;
+	u16 size;
+
+	fw_info = (ATOM_COMMON_TABLE_HEADER *)
+		cgs_atom_get_data_table(hwmgr->device,
+				GetIndexIntoMasterTable(DATA, FirmwareInfo),
+				&size, &frev, &crev);
+
+	if (fw_info == NULL)
+		clock = 2700;
+	else {
+		if ((fw_info->ucTableFormatRevision == 2) &&
+			(le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1))) {
+			ATOM_FIRMWARE_INFO_V2_1 *fwInfo_2_1 =
+				(ATOM_FIRMWARE_INFO_V2_1 *)fw_info;
+			clock = (uint32_t)(le16_to_cpu(fwInfo_2_1->usMemoryReferenceClock));
+		} else {
+			ATOM_FIRMWARE_INFO *fwInfo_0_0 =
+				(ATOM_FIRMWARE_INFO *)fw_info;
+			clock = (uint32_t)(le16_to_cpu(fwInfo_0_0->usReferenceClock));
+		}
+	}
+
+	return clock;
+}
+
+/**
+ * Get the asic internal spread spectrum table
+ */
+static ATOM_ASIC_INTERNAL_SS_INFO *asic_internal_ss_get_ss_table(void *device)
+{
+	ATOM_ASIC_INTERNAL_SS_INFO *table = NULL;
+	u8 frev, crev;
+	u16 size;
+
+	table = (ATOM_ASIC_INTERNAL_SS_INFO *)
+		cgs_atom_get_data_table(device,
+			GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info),
+			&size, &frev, &crev);
+
+	return table;
+}
+
+/**
+ * Get the asic internal spread spectrum assignment
+ */
+static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr *hwmgr,
+		const uint8_t clockSource,
+		const uint32_t clockSpeed,
+		pp_atomctrl_internal_ss_info *ssEntry)
+{
+	ATOM_ASIC_INTERNAL_SS_INFO *table;
+	ATOM_ASIC_SS_ASSIGNMENT *ssInfo;
+	int entry_found = 0;
+
+	memset(ssEntry, 0x00, sizeof(pp_atomctrl_internal_ss_info));
+
+	table = asic_internal_ss_get_ss_table(hwmgr->device);
+
+	if (NULL == table)
+		return -1;
+
+	ssInfo = &table->asSpreadSpectrum[0];
+
+	while (((uint8_t *)ssInfo - (uint8_t *)table) <
+		le16_to_cpu(table->sHeader.usStructureSize)) {
+		if ((clockSource == ssInfo->ucClockIndication) &&
+			((uint32_t)clockSpeed <= le32_to_cpu(ssInfo->ulTargetClockRange))) {
+			entry_found = 1;
+			break;
+		}
+
+		ssInfo = (ATOM_ASIC_SS_ASSIGNMENT *)((uint8_t *)ssInfo +
+				sizeof(ATOM_ASIC_SS_ASSIGNMENT));
+	}
+
+	if (entry_found) {
+		ssEntry->speed_spectrum_percentage =
+			ssInfo->usSpreadSpectrumPercentage;
+		ssEntry->speed_spectrum_rate = ssInfo->usSpreadRateInKhz;
+
+		if (((GET_DATA_TABLE_MAJOR_REVISION(table) == 2) &&
+			(GET_DATA_TABLE_MINOR_REVISION(table) >= 2)) ||
+			(GET_DATA_TABLE_MAJOR_REVISION(table) == 3)) {
+			ssEntry->speed_spectrum_rate /= 100;
+		}
+
+		switch (ssInfo->ucSpreadSpectrumMode) {
+		case 0:
+			ssEntry->speed_spectrum_mode =
+				pp_atomctrl_spread_spectrum_mode_down;
+			break;
+		case 1:
+			ssEntry->speed_spectrum_mode =
+				pp_atomctrl_spread_spectrum_mode_center;
+			break;
+		default:
+			ssEntry->speed_spectrum_mode =
+				pp_atomctrl_spread_spectrum_mode_down;
+			break;
+		}
+	}
+
+	return entry_found ? 0 : 1;
+}
+
+/**
+ * Get the memory clock spread spectrum info
+ */
+int atomctrl_get_memory_clock_spread_spectrum(
+		struct pp_hwmgr *hwmgr,
+		const uint32_t memory_clock,
+		pp_atomctrl_internal_ss_info *ssInfo)
+{
+	return asic_internal_ss_get_ss_asignment(hwmgr,
+			ASIC_INTERNAL_MEMORY_SS, memory_clock, ssInfo);
+}
+/**
+ * Get the engine clock spread spectrum info
+ */
+int atomctrl_get_engine_clock_spread_spectrum(
+		struct pp_hwmgr *hwmgr,
+		const uint32_t engine_clock,
+		pp_atomctrl_internal_ss_info *ssInfo)
+{
+	return asic_internal_ss_get_ss_asignment(hwmgr,
+			ASIC_INTERNAL_ENGINE_SS, engine_clock, ssInfo);
+}
+
+int atomctrl_read_efuse(void *device, uint16_t start_index,
+		uint16_t end_index, uint32_t mask, uint32_t *efuse)
+{
+	int result;
+	READ_EFUSE_VALUE_PARAMETER efuse_param;
+
+	efuse_param.sEfuse.usEfuseIndex = (start_index / 32) * 4;
+	efuse_param.sEfuse.ucBitShift = (uint8_t)
+			(start_index - ((start_index / 32) * 32));
+	efuse_param.sEfuse.ucBitLength  = (uint8_t)
+			((end_index - start_index) + 1);
+
+	result = cgs_atom_exec_cmd_table(device,
+			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+			&efuse_param);
+	if (!result)
+		*efuse = efuse_param.ulEfuseValue & mask;
+
+	return result;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef PP_ATOMVOLTAGECTRL_H
+#define PP_ATOMVOLTAGECTRL_H
+
+#include "hwmgr.h"
+
+#define MEM_TYPE_GDDR5  0x50
+#define MEM_TYPE_GDDR4  0x40
+#define MEM_TYPE_GDDR3  0x30
+#define MEM_TYPE_DDR2   0x20
+#define MEM_TYPE_GDDR1  0x10
+#define MEM_TYPE_DDR3   0xb0
+#define MEM_TYPE_MASK   0xF0
+
+
+/* As returned from PowerConnectorDetectionTable. */
+#define PP_ATOM_POWER_BUDGET_DISABLE_OVERDRIVE  0x80
+#define PP_ATOM_POWER_BUDGET_SHOW_WARNING       0x40
+#define PP_ATOM_POWER_BUDGET_SHOW_WAIVER        0x20
+#define PP_ATOM_POWER_POWER_BUDGET_BEHAVIOUR    0x0F
+
+/* New functions for Evergreen and beyond. */
+#define PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES 32
+
+struct pp_atomctrl_clock_dividers {
+	uint32_t pll_post_divider;
+	uint32_t pll_feedback_divider;
+	uint32_t pll_ref_divider;
+	bool  enable_post_divider;
+};
+
+typedef struct pp_atomctrl_clock_dividers pp_atomctrl_clock_dividers;
+
+union pp_atomctrl_tcipll_fb_divider {
+	struct {
+		uint32_t ul_fb_div_frac : 14;
+		uint32_t ul_fb_div : 12;
+		uint32_t un_used : 6;
+	};
+	uint32_t ul_fb_divider;
+};
+
+typedef union pp_atomctrl_tcipll_fb_divider pp_atomctrl_tcipll_fb_divider;
+
+struct pp_atomctrl_clock_dividers_rv730 {
+	uint32_t pll_post_divider;
+	pp_atomctrl_tcipll_fb_divider mpll_feedback_divider;
+	uint32_t pll_ref_divider;
+	bool  enable_post_divider;
+	bool  enable_dithen;
+	uint32_t vco_mode;
+};
+typedef struct pp_atomctrl_clock_dividers_rv730 pp_atomctrl_clock_dividers_rv730;
+
+
+struct pp_atomctrl_clock_dividers_kong {
+	uint32_t    pll_post_divider;
+	uint32_t    real_clock;
+};
+typedef struct pp_atomctrl_clock_dividers_kong pp_atomctrl_clock_dividers_kong;
+
+struct pp_atomctrl_clock_dividers_ci {
+	uint32_t    pll_post_divider;               /* post divider value */
+	uint32_t    real_clock;
+	pp_atomctrl_tcipll_fb_divider   ul_fb_div;         /* Output Parameter: PLL FB divider */
+	uint8_t   uc_pll_ref_div;                      /* Output Parameter: PLL ref divider */
+	uint8_t   uc_pll_post_div;                      /* Output Parameter: PLL post divider */
+	uint8_t   uc_pll_cntl_flag;                    /*Output Flags: control flag */
+};
+typedef struct pp_atomctrl_clock_dividers_ci pp_atomctrl_clock_dividers_ci;
+
+struct pp_atomctrl_clock_dividers_vi {
+	uint32_t    pll_post_divider;               /* post divider value */
+	uint32_t    real_clock;
+	pp_atomctrl_tcipll_fb_divider   ul_fb_div;         /*Output Parameter: PLL FB divider */
+	uint8_t   uc_pll_ref_div;                      /*Output Parameter: PLL ref divider */
+	uint8_t   uc_pll_post_div;                     /*Output Parameter: PLL post divider */
+	uint8_t   uc_pll_cntl_flag;                    /*Output Flags: control flag */
+};
+typedef struct pp_atomctrl_clock_dividers_vi pp_atomctrl_clock_dividers_vi;
+
+union pp_atomctrl_s_mpll_fb_divider {
+	struct {
+		uint32_t cl_kf : 12;
+		uint32_t clk_frac : 12;
+		uint32_t un_used : 8;
+	};
+	uint32_t ul_fb_divider;
+};
+typedef union pp_atomctrl_s_mpll_fb_divider pp_atomctrl_s_mpll_fb_divider;
+
+enum pp_atomctrl_spread_spectrum_mode {
+	pp_atomctrl_spread_spectrum_mode_down = 0,
+	pp_atomctrl_spread_spectrum_mode_center
+};
+typedef enum pp_atomctrl_spread_spectrum_mode pp_atomctrl_spread_spectrum_mode;
+
+struct pp_atomctrl_memory_clock_param {
+	pp_atomctrl_s_mpll_fb_divider mpll_fb_divider;
+	uint32_t mpll_post_divider;
+	uint32_t bw_ctrl;
+	uint32_t dll_speed;
+	uint32_t vco_mode;
+	uint32_t yclk_sel;
+	uint32_t qdr;
+	uint32_t half_rate;
+};
+typedef struct pp_atomctrl_memory_clock_param pp_atomctrl_memory_clock_param;
+
+struct pp_atomctrl_internal_ss_info {
+	uint32_t speed_spectrum_percentage;                      /* in 1/100 percentage */
+	uint32_t speed_spectrum_rate;                            /* in KHz */
+	pp_atomctrl_spread_spectrum_mode speed_spectrum_mode;
+};
+typedef struct pp_atomctrl_internal_ss_info pp_atomctrl_internal_ss_info;
+
+#ifndef NUMBER_OF_M3ARB_PARAMS
+#define NUMBER_OF_M3ARB_PARAMS 3
+#endif
+
+#ifndef NUMBER_OF_M3ARB_PARAM_SETS
+#define NUMBER_OF_M3ARB_PARAM_SETS 10
+#endif
+
+struct pp_atomctrl_kong_system_info {
+	uint32_t			ul_bootup_uma_clock;          /* in 10kHz unit */
+	uint16_t			us_max_nb_voltage;            /* high NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; */
+	uint16_t			us_min_nb_voltage;            /* low NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; */
+	uint16_t			us_bootup_nb_voltage;         /* boot up NB voltage */
+	uint8_t			uc_htc_tmp_lmt;               /* bit [22:16] of D24F3x64 Hardware Thermal Control (HTC) Register, may not be needed, TBD */
+	uint8_t			uc_tj_offset;                /* bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed, TBD */
+	/* 0: default 1: uvd 2: fs-3d */
+	uint32_t          ul_csr_m3_srb_cntl[NUMBER_OF_M3ARB_PARAM_SETS][NUMBER_OF_M3ARB_PARAMS];/* arrays with values for CSR M3 arbiter for default */
+};
+typedef struct pp_atomctrl_kong_system_info pp_atomctrl_kong_system_info;
+
+struct pp_atomctrl_memory_info {
+	uint8_t memory_vendor;
+	uint8_t memory_type;
+};
+typedef struct pp_atomctrl_memory_info pp_atomctrl_memory_info;
+
+#define MAX_AC_TIMING_ENTRIES 16
+
+struct pp_atomctrl_memory_clock_range_table {
+	uint8_t   num_entries;
+	uint8_t   rsv[3];
+
+	uint32_t mclk[MAX_AC_TIMING_ENTRIES];
+};
+typedef struct pp_atomctrl_memory_clock_range_table pp_atomctrl_memory_clock_range_table;
+
+struct pp_atomctrl_voltage_table_entry {
+	uint16_t value;
+	uint32_t smio_low;
+};
+
+typedef struct pp_atomctrl_voltage_table_entry pp_atomctrl_voltage_table_entry;
+
+struct pp_atomctrl_voltage_table {
+	uint32_t count;
+	uint32_t mask_low;
+	uint32_t phase_delay;   /* Used for ATOM_GPIO_VOLTAGE_OBJECT_V3 and later */
+	pp_atomctrl_voltage_table_entry entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES];
+};
+
+typedef struct pp_atomctrl_voltage_table pp_atomctrl_voltage_table;
+
+#define VBIOS_MC_REGISTER_ARRAY_SIZE           32
+#define VBIOS_MAX_AC_TIMING_ENTRIES            20
+
+struct pp_atomctrl_mc_reg_entry {
+	uint32_t           mclk_max;
+	uint32_t mc_data[VBIOS_MC_REGISTER_ARRAY_SIZE];
+};
+typedef struct pp_atomctrl_mc_reg_entry pp_atomctrl_mc_reg_entry;
+
+struct pp_atomctrl_mc_register_address {
+	uint16_t s1;
+	uint8_t  uc_pre_reg_data;
+};
+
+typedef struct pp_atomctrl_mc_register_address pp_atomctrl_mc_register_address;
+
+struct pp_atomctrl_mc_reg_table {
+	uint8_t                         last;                    /* number of registers */
+	uint8_t                         num_entries;             /* number of AC timing entries */
+	pp_atomctrl_mc_reg_entry        mc_reg_table_entry[VBIOS_MAX_AC_TIMING_ENTRIES];
+	pp_atomctrl_mc_register_address mc_reg_address[VBIOS_MC_REGISTER_ARRAY_SIZE];
+};
+typedef struct pp_atomctrl_mc_reg_table pp_atomctrl_mc_reg_table;
+
+struct pp_atomctrl_gpio_pin_assignment {
+	uint16_t                   us_gpio_pin_aindex;
+	uint8_t                    uc_gpio_pin_bit_shift;
+};
+typedef struct pp_atomctrl_gpio_pin_assignment pp_atomctrl_gpio_pin_assignment;
+
+extern bool atomctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr, const uint32_t pinId, pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment);
+extern int atomctrl_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage);
+extern uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr);
+extern int atomctrl_get_memory_clock_spread_spectrum(struct pp_hwmgr *hwmgr, const uint32_t memory_clock, pp_atomctrl_internal_ss_info *ssInfo);
+extern int atomctrl_get_engine_clock_spread_spectrum(struct pp_hwmgr *hwmgr, const uint32_t engine_clock, pp_atomctrl_internal_ss_info *ssInfo);
+extern int atomctrl_initialize_mc_reg_table(struct pp_hwmgr *hwmgr, uint8_t module_index, pp_atomctrl_mc_reg_table *table);
+extern int atomctrl_set_engine_dram_timings_rv770(struct pp_hwmgr *hwmgr, uint32_t engine_clock, uint32_t memory_clock);
+extern uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr);
+extern int atomctrl_get_memory_pll_dividers_si(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param, bool strobe_mode);
+extern int atomctrl_get_engine_pll_dividers_vi(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_vi *dividers);
+extern int atomctrl_get_dfs_pll_dividers_vi(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_vi *dividers);
+extern bool atomctrl_is_voltage_controled_by_gpio_v3(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode);
+extern int atomctrl_get_voltage_table_v3(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode, pp_atomctrl_voltage_table *voltage_table);
+extern int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr,
+		uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param);
+extern int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr,
+						 uint32_t clock_value,
+						 pp_atomctrl_clock_dividers_kong *dividers);
+extern int atomctrl_read_efuse(void *device, uint16_t start_index,
+		uint16_t end_index, uint32_t mask, uint32_t *efuse);
+extern int atomctrl_calculate_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
+		uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage, uint16_t dpm_level, bool debug);
+
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <asm/div64.h>
+
+#define SHIFT_AMOUNT 16 /* We multiply all original integers with 2^SHIFT_AMOUNT to get the fInt representation */
+
+#define PRECISION 5 /* Change this value to change the number of decimal places in the final output - 5 is a good default */
+
+#define SHIFTED_2 (2 << SHIFT_AMOUNT)
+#define MAX (1 << (SHIFT_AMOUNT - 1)) - 1 /* 32767 - Might change in the future */
+
+/* -------------------------------------------------------------------------------
+ * NEW TYPE - fINT
+ * -------------------------------------------------------------------------------
+ * A variable of type fInt can be accessed in 3 ways using the dot (.) operator
+ * fInt A;
+ * A.full => The full number as it is. Generally not easy to read
+ * A.partial.real => Only the integer portion
+ * A.partial.decimal => Only the fractional portion
+ */
+typedef union _fInt {
+    int full;
+    struct _partial {
+        unsigned int decimal: SHIFT_AMOUNT; /*Needs to always be unsigned*/
+        int real: 32 - SHIFT_AMOUNT;
+    } partial;
+} fInt;
+
+/* -------------------------------------------------------------------------------
+ * Function Declarations
+ *  -------------------------------------------------------------------------------
+ */
+fInt ConvertToFraction(int);                       /* Use this to convert an INT to a FINT */
+fInt Convert_ULONG_ToFraction(uint32_t);              /* Use this to convert an uint32_t to a FINT */
+fInt GetScaledFraction(int, int);                  /* Use this to convert an INT to a FINT after scaling it by a factor */
+int ConvertBackToInteger(fInt);                    /* Convert a FINT back to an INT that is scaled by 1000 (i.e. last 3 digits are the decimal digits) */
+
+fInt fNegate(fInt);                                /* Returns -1 * input fInt value */
+fInt fAdd (fInt, fInt);                            /* Returns the sum of two fInt numbers */
+fInt fSubtract (fInt A, fInt B);                   /* Returns A-B - Sometimes easier than Adding negative numbers */
+fInt fMultiply (fInt, fInt);                       /* Returns the product of two fInt numbers */
+fInt fDivide (fInt A, fInt B);                     /* Returns A/B */
+fInt fGetSquare(fInt);                             /* Returns the square of a fInt number */
+fInt fSqrt(fInt);                                  /* Returns the Square Root of a fInt number */
+
+int uAbs(int);                                     /* Returns the Absolute value of the Int */
+fInt fAbs(fInt);                                   /* Returns the Absolute value of the fInt */
+int uPow(int base, int exponent);                  /* Returns base^exponent an INT */
+
+void SolveQuadracticEqn(fInt, fInt, fInt, fInt[]); /* Returns the 2 roots via the array */
+bool Equal(fInt, fInt);                         /* Returns true if two fInts are equal to each other */
+bool GreaterThan(fInt A, fInt B);               /* Returns true if A > B */
+
+fInt fExponential(fInt exponent);                  /* Can be used to calculate e^exponent */
+fInt fNaturalLog(fInt value);                      /* Can be used to calculate ln(value) */
+
+/* Fuse decoding functions
+ * -------------------------------------------------------------------------------------
+ */
+fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength);
+fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength);
+fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength);
+
+/* Internal Support Functions - Use these ONLY for testing or adding to internal functions
+ * -------------------------------------------------------------------------------------
+ * Some of the following functions take two INTs as their input - This is unsafe for a variety of reasons.
+ */
+fInt Add (int, int);                               /* Add two INTs and return Sum as FINT */
+fInt Multiply (int, int);                          /* Multiply two INTs and return Product as FINT */
+fInt Divide (int, int);                            /* You get the idea... */
+fInt fNegate(fInt);
+
+int uGetScaledDecimal (fInt);                      /* Internal function */
+int GetReal (fInt A);                              /* Internal function */
+
+/* Future Additions and Incomplete Functions
+ * -------------------------------------------------------------------------------------
+ */
+int GetRoundedValue(fInt);                         /* Incomplete function - Useful only when Precision is lacking */
+                                                   /* Let us say we have 2.126 but can only handle 2 decimal points. We could */
+                                                   /* either chop of 6 and keep 2.12 or use this function to get 2.13, which is more accurate */
+
+/* -------------------------------------------------------------------------------------
+ * TROUBLESHOOTING INFORMATION
+ * -------------------------------------------------------------------------------------
+ * 1) ConvertToFraction - InputOutOfRangeException: Only accepts numbers smaller than MAX (default: 32767)
+ * 2) fAdd - OutputOutOfRangeException: Output bigger than MAX (default: 32767)
+ * 3) fMultiply - OutputOutOfRangeException:
+ * 4) fGetSquare - OutputOutOfRangeException:
+ * 5) fDivide - DivideByZeroException
+ * 6) fSqrt - NegativeSquareRootException: Input cannot be a negative number
+ */
+
+/* -------------------------------------------------------------------------------------
+ * START OF CODE
+ * -------------------------------------------------------------------------------------
+ */
+fInt fExponential(fInt exponent)        /*Can be used to calculate e^exponent*/
+{
+	uint32_t i;
+	bool bNegated = false;
+
+	fInt fPositiveOne = ConvertToFraction(1);
+	fInt fZERO = ConvertToFraction(0);
+
+	fInt lower_bound = Divide(78, 10000);
+	fInt solution = fPositiveOne; /*Starting off with baseline of 1 */
+	fInt error_term;
+
+	uint32_t k_array[11] = {55452, 27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78};
+	uint32_t expk_array[11] = {2560000, 160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078};
+
+	if (GreaterThan(fZERO, exponent)) {
+		exponent = fNegate(exponent);
+		bNegated = true;
+	}
+
+	while (GreaterThan(exponent, lower_bound)) {
+		for (i = 0; i < 11; i++) {
+			if (GreaterThan(exponent, GetScaledFraction(k_array[i], 10000))) {
+				exponent = fSubtract(exponent, GetScaledFraction(k_array[i], 10000));
+				solution = fMultiply(solution, GetScaledFraction(expk_array[i], 10000));
+			}
+		}
+	}
+
+	error_term = fAdd(fPositiveOne, exponent);
+
+	solution = fMultiply(solution, error_term);
+
+	if (bNegated)
+		solution = fDivide(fPositiveOne, solution);
+
+	return solution;
+}
+
+fInt fNaturalLog(fInt value)
+{
+	uint32_t i;
+	fInt upper_bound = Divide(8, 1000);
+	fInt fNegativeOne = ConvertToFraction(-1);
+	fInt solution = ConvertToFraction(0); /*Starting off with baseline of 0 */
+	fInt error_term;
+
+	uint32_t k_array[10] = {160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078};
+	uint32_t logk_array[10] = {27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78};
+
+	while (GreaterThan(fAdd(value, fNegativeOne), upper_bound)) {
+		for (i = 0; i < 10; i++) {
+			if (GreaterThan(value, GetScaledFraction(k_array[i], 10000))) {
+				value = fDivide(value, GetScaledFraction(k_array[i], 10000));
+				solution = fAdd(solution, GetScaledFraction(logk_array[i], 10000));
+			}
+		}
+	}
+
+	error_term = fAdd(fNegativeOne, value);
+
+	return (fAdd(solution, error_term));
+}
+
+fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength)
+{
+	fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value);
+	fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
+
+	fInt f_decoded_value;
+
+	f_decoded_value = fDivide(f_fuse_value, f_bit_max_value);
+	f_decoded_value = fMultiply(f_decoded_value, f_range);
+	f_decoded_value = fAdd(f_decoded_value, f_min);
+
+	return f_decoded_value;
+}
+
+
+fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength)
+{
+	fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value);
+	fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
+
+	fInt f_CONSTANT_NEG13 = ConvertToFraction(-13);
+	fInt f_CONSTANT1 = ConvertToFraction(1);
+
+	fInt f_decoded_value;
+
+	f_decoded_value = fSubtract(fDivide(f_bit_max_value, f_fuse_value), f_CONSTANT1);
+	f_decoded_value = fNaturalLog(f_decoded_value);
+	f_decoded_value = fMultiply(f_decoded_value, fDivide(f_range, f_CONSTANT_NEG13));
+	f_decoded_value = fAdd(f_decoded_value, f_average);
+
+	return f_decoded_value;
+}
+
+fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength)
+{
+	fInt fLeakage;
+	fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
+
+	fLeakage = fMultiply(ln_max_div_min, Convert_ULONG_ToFraction(leakageID_fuse));
+	fLeakage = fDivide(fLeakage, f_bit_max_value);
+	fLeakage = fExponential(fLeakage);
+	fLeakage = fMultiply(fLeakage, f_min);
+
+	return fLeakage;
+}
+
+fInt ConvertToFraction(int X) /*Add all range checking here. Is it possible to make fInt a private declaration? */
+{
+	fInt temp;
+
+	if (X <= MAX)
+		temp.full = (X << SHIFT_AMOUNT);
+	else
+		temp.full = 0;
+
+	return temp;
+}
+
+fInt fNegate(fInt X)
+{
+	fInt CONSTANT_NEGONE = ConvertToFraction(-1);
+	return (fMultiply(X, CONSTANT_NEGONE));
+}
+
+fInt Convert_ULONG_ToFraction(uint32_t X)
+{
+	fInt temp;
+
+	if (X <= MAX)
+		temp.full = (X << SHIFT_AMOUNT);
+	else
+		temp.full = 0;
+
+	return temp;
+}
+
+fInt GetScaledFraction(int X, int factor)
+{
+	int times_shifted, factor_shifted;
+	bool bNEGATED;
+	fInt fValue;
+
+	times_shifted = 0;
+	factor_shifted = 0;
+	bNEGATED = false;
+
+	if (X < 0) {
+		X = -1*X;
+		bNEGATED = true;
+	}
+
+	if (factor < 0) {
+		factor = -1*factor;
+		bNEGATED = !bNEGATED; /*If bNEGATED = true due to X < 0, this will cover the case of negative cancelling negative */
+	}
+
+	if ((X > MAX) || factor > MAX) {
+		if ((X/factor) <= MAX) {
+			while (X > MAX) {
+				X = X >> 1;
+				times_shifted++;
+			}
+
+			while (factor > MAX) {
+				factor = factor >> 1;
+				factor_shifted++;
+			}
+		} else {
+			fValue.full = 0;
+			return fValue;
+		}
+	}
+
+	if (factor == 1)
+	return (ConvertToFraction(X));
+
+	fValue = fDivide(ConvertToFraction(X * uPow(-1, bNEGATED)), ConvertToFraction(factor));
+
+	fValue.full = fValue.full << times_shifted;
+	fValue.full = fValue.full >> factor_shifted;
+
+	return fValue;
+}
+
+/* Addition using two fInts */
+fInt fAdd (fInt X, fInt Y)
+{
+	fInt Sum;
+
+	Sum.full = X.full + Y.full;
+
+	return Sum;
+}
+
+/* Addition using two fInts */
+fInt fSubtract (fInt X, fInt Y)
+{
+	fInt Difference;
+
+	Difference.full = X.full - Y.full;
+
+	return Difference;
+}
+
+bool Equal(fInt A, fInt B)
+{
+	if (A.full == B.full)
+		return true;
+	else
+		return false;
+}
+
+bool GreaterThan(fInt A, fInt B)
+{
+	if (A.full > B.full)
+		return true;
+	else
+		return false;
+}
+
+fInt fMultiply (fInt X, fInt Y) /* Uses 64-bit integers (int64_t) */
+{
+	fInt Product;
+	int64_t tempProduct;
+	bool X_LessThanOne, Y_LessThanOne;
+
+	X_LessThanOne = (X.partial.real == 0 && X.partial.decimal != 0 && X.full >= 0);
+	Y_LessThanOne = (Y.partial.real == 0 && Y.partial.decimal != 0 && Y.full >= 0);
+
+	/*The following is for a very specific common case: Non-zero number with ONLY fractional portion*/
+	/* TEMPORARILY DISABLED - CAN BE USED TO IMPROVE PRECISION
+
+	if (X_LessThanOne && Y_LessThanOne) {
+		Product.full = X.full * Y.full;
+		return Product
+	}*/
+
+	tempProduct = ((int64_t)X.full) * ((int64_t)Y.full); /*Q(16,16)*Q(16,16) = Q(32, 32) - Might become a negative number! */
+	tempProduct = tempProduct >> 16; /*Remove lagging 16 bits - Will lose some precision from decimal; */
+	Product.full = (int)tempProduct; /*The int64_t will lose the leading 16 bits that were part of the integer portion */
+
+	return Product;
+}
+
+fInt fDivide (fInt X, fInt Y)
+{
+	fInt fZERO, fQuotient;
+	int64_t longlongX, longlongY;
+
+	fZERO = ConvertToFraction(0);
+
+	if (Equal(Y, fZERO))
+	return fZERO;
+
+	longlongX = (int64_t)X.full;
+	longlongY = (int64_t)Y.full;
+
+	longlongX = longlongX << 16; /*Q(16,16) -> Q(32,32) */
+
+	div64_s64(longlongX, longlongY); /*Q(32,32) divided by Q(16,16) = Q(16,16) Back to original format */
+
+	fQuotient.full = (int)longlongX;
+	return fQuotient;
+}
+
+int ConvertBackToInteger (fInt A) /*THIS is the function that will be used to check with the Golden settings table*/
+{
+	fInt fullNumber, scaledDecimal, scaledReal;
+
+	scaledReal.full = GetReal(A) * uPow(10, PRECISION-1); /* DOUBLE CHECK THISSSS!!! */
+
+	scaledDecimal.full = uGetScaledDecimal(A);
+
+	fullNumber = fAdd(scaledDecimal,scaledReal);
+
+	return fullNumber.full;
+}
+
+fInt fGetSquare(fInt A)
+{
+	return fMultiply(A,A);
+}
+
+/* x_new = x_old - (x_old^2 - C) / (2 * x_old) */
+fInt fSqrt(fInt num)
+{
+	fInt F_divide_Fprime, Fprime;
+	fInt test;
+	fInt twoShifted;
+	int seed, counter, error;
+	fInt x_new, x_old, C, y;
+
+	fInt fZERO = ConvertToFraction(0);
+
+	/* (0 > num) is the same as (num < 0), i.e., num is negative */
+
+	if (GreaterThan(fZERO, num) || Equal(fZERO, num))
+		return fZERO;
+
+	C = num;
+
+	if (num.partial.real > 3000)
+		seed = 60;
+	else if (num.partial.real > 1000)
+		seed = 30;
+	else if (num.partial.real > 100)
+		seed = 10;
+	else
+		seed = 2;
+
+	counter = 0;
+
+	if (Equal(num, fZERO)) /*Square Root of Zero is zero */
+		return fZERO;
+
+	twoShifted = ConvertToFraction(2);
+	x_new = ConvertToFraction(seed);
+
+	do {
+		counter++;
+
+		x_old.full = x_new.full;
+
+		test = fGetSquare(x_old); /*1.75*1.75 is reverting back to 1 when shifted down */
+		y = fSubtract(test, C); /*y = f(x) = x^2 - C; */
+
+		Fprime = fMultiply(twoShifted, x_old);
+		F_divide_Fprime = fDivide(y, Fprime);
+
+		x_new = fSubtract(x_old, F_divide_Fprime);
+
+		error = ConvertBackToInteger(x_new) - ConvertBackToInteger(x_old);
+
+		if (counter > 20) /*20 is already way too many iterations. If we dont have an answer by then, we never will*/
+			return x_new;
+
+	} while (uAbs(error) > 0);
+
+	return (x_new);
+}
+
+void SolveQuadracticEqn(fInt A, fInt B, fInt C, fInt Roots[])
+{
+	fInt *pRoots = &Roots[0];
+	fInt temp, root_first, root_second;
+	fInt f_CONSTANT10, f_CONSTANT100;
+
+	f_CONSTANT100 = ConvertToFraction(100);
+	f_CONSTANT10 = ConvertToFraction(10);
+
+	while(GreaterThan(A, f_CONSTANT100) || GreaterThan(B, f_CONSTANT100) || GreaterThan(C, f_CONSTANT100)) {
+		A = fDivide(A, f_CONSTANT10);
+		B = fDivide(B, f_CONSTANT10);
+		C = fDivide(C, f_CONSTANT10);
+	}
+
+	temp = fMultiply(ConvertToFraction(4), A); /* root = 4*A */
+	temp = fMultiply(temp, C); /* root = 4*A*C */
+	temp = fSubtract(fGetSquare(B), temp); /* root = b^2 - 4AC */
+	temp = fSqrt(temp); /*root = Sqrt (b^2 - 4AC); */
+
+	root_first = fSubtract(fNegate(B), temp); /* b - Sqrt(b^2 - 4AC) */
+	root_second = fAdd(fNegate(B), temp); /* b + Sqrt(b^2 - 4AC) */
+
+	root_first = fDivide(root_first, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */
+	root_first = fDivide(root_first, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */
+
+	root_second = fDivide(root_second, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */
+	root_second = fDivide(root_second, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */
+
+	*(pRoots + 0) = root_first;
+	*(pRoots + 1) = root_second;
+}
+
+/* -----------------------------------------------------------------------------
+ * SUPPORT FUNCTIONS
+ * -----------------------------------------------------------------------------
+ */
+
+/* Addition using two normal ints - Temporary - Use only for testing purposes?. */
+fInt Add (int X, int Y)
+{
+	fInt A, B, Sum;
+
+	A.full = (X << SHIFT_AMOUNT);
+	B.full = (Y << SHIFT_AMOUNT);
+
+	Sum.full = A.full + B.full;
+
+	return Sum;
+}
+
+/* Conversion Functions */
+int GetReal (fInt A)
+{
+	return (A.full >> SHIFT_AMOUNT);
+}
+
+/* Temporarily Disabled */
+int GetRoundedValue(fInt A) /*For now, round the 3rd decimal place */
+{
+	/* ROUNDING TEMPORARLY DISABLED
+	int temp = A.full;
+	int decimal_cutoff, decimal_mask = 0x000001FF;
+	decimal_cutoff = temp & decimal_mask;
+	if (decimal_cutoff > 0x147) {
+		temp += 673;
+	}*/
+
+	return ConvertBackToInteger(A)/10000; /*Temporary - in case this was used somewhere else */
+}
+
+fInt Multiply (int X, int Y)
+{
+	fInt A, B, Product;
+
+	A.full = X << SHIFT_AMOUNT;
+	B.full = Y << SHIFT_AMOUNT;
+
+	Product = fMultiply(A, B);
+
+	return Product;
+}
+
+fInt Divide (int X, int Y)
+{
+	fInt A, B, Quotient;
+
+	A.full = X << SHIFT_AMOUNT;
+	B.full = Y << SHIFT_AMOUNT;
+
+	Quotient = fDivide(A, B);
+
+	return Quotient;
+}
+
+int uGetScaledDecimal (fInt A) /*Converts the fractional portion to whole integers - Costly function */
+{
+	int dec[PRECISION];
+	int i, scaledDecimal = 0, tmp = A.partial.decimal;
+
+	for (i = 0; i < PRECISION; i++) {
+		dec[i] = tmp / (1 << SHIFT_AMOUNT);
+		tmp = tmp - ((1 << SHIFT_AMOUNT)*dec[i]);
+		tmp *= 10;
+		scaledDecimal = scaledDecimal + dec[i]*uPow(10, PRECISION - 1 -i);
+	}
+
+	return scaledDecimal;
+}
+
+int uPow(int base, int power)
+{
+	if (power == 0)
+		return 1;
+	else
+		return (base)*uPow(base, power - 1);
+}
+
+fInt fAbs(fInt A)
+{
+	if (A.partial.real < 0)
+		return (fMultiply(A, ConvertToFraction(-1)));
+	else
+		return A;
+}
+
+int uAbs(int X)
+{
+	if (X < 0)
+		return (X * -1);
+	else
+		return X;
+}
+
+fInt fRoundUpByStepSize(fInt A, fInt fStepSize, bool error_term)
+{
+	fInt solution;
+
+	solution = fDivide(A, fStepSize);
+	solution.partial.decimal = 0; /*All fractional digits changes to 0 */
+
+	if (error_term)
+		solution.partial.real += 1; /*Error term of 1 added */
+
+	solution = fMultiply(solution, fStepSize);
+	solution = fAdd(solution, fStepSize);
+
+	return solution;
+}
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+#include "atom-types.h"
+#include "atombios.h"
+#include "pppcielanes.h"
+
+/** \file
+ * Functions related to PCIe lane changes.
+ */
+
+/* For converting from number of lanes to lane bits.  */
+static const unsigned char pp_r600_encode_lanes[] = {
+	0,          /*  0 Not Supported  */
+	1,          /*  1 Lane  */
+	2,          /*  2 Lanes  */
+	0,          /*  3 Not Supported  */
+	3,          /*  4 Lanes  */
+	0,          /*  5 Not Supported  */
+	0,          /*  6 Not Supported  */
+	0,          /*  7 Not Supported  */
+	4,          /*  8 Lanes  */
+	0,          /*  9 Not Supported  */
+	0,          /* 10 Not Supported  */
+	0,          /* 11 Not Supported  */
+	5,          /* 12 Lanes (Not actually supported)  */
+	0,          /* 13 Not Supported  */
+	0,          /* 14 Not Supported  */
+	0,          /* 15 Not Supported  */
+	6           /* 16 Lanes  */
+};
+
+static const unsigned char pp_r600_decoded_lanes[8] = { 16, 1, 2, 4, 8, 12, 16, };
+
+uint8_t encode_pcie_lane_width(uint32_t num_lanes)
+{
+	return pp_r600_encode_lanes[num_lanes];
+}
+
+uint8_t decode_pcie_lane_width(uint32_t num_lanes)
+{
+	return pp_r600_decoded_lanes[num_lanes];
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef PP_PCIELANES_H
+#define PP_PCIELANES_H
+
+extern uint8_t encode_pcie_lane_width(uint32_t num_lanes);
+extern uint8_t decode_pcie_lane_width(uint32_t num_lanes);
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
@@ -0,0 +1,1688 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "processpptables.h"
+#include <atom-types.h>
+#include <atombios.h>
+#include "pp_debug.h"
+#include "pptable.h"
+#include "power_state.h"
+#include "hwmgr.h"
+#include "hardwaremanager.h"
+
+
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
+
+#define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6
+
+static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t vce_table_offset = 0;
+
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+	   sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+
+		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+			const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
+						(const ATOM_PPLIB_EXTENDEDHEADER *)
+						(((unsigned long)powerplay_table3) +
+						le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+			if (le16_to_cpu(extended_header->usSize) >=
+			   SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2)
+				vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset);
+		}
+	}
+
+	return vce_table_offset;
+}
+
+static uint16_t get_vce_clock_info_array_offset(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_vce_table_offset(hwmgr,
+						powerplay_table);
+
+	if (table_offset > 0)
+		return table_offset + 1;
+
+	return 0;
+}
+
+static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
+							powerplay_table);
+	uint16_t table_size = 0;
+
+	if (table_offset > 0) {
+		const VCEClockInfoArray *p = (const VCEClockInfoArray *)
+			(((unsigned long) powerplay_table) + table_offset);
+		table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo);
+	}
+
+	return table_size;
+}
+
+static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr,
+				const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
+							powerplay_table);
+
+	if (table_offset > 0)
+		return table_offset + get_vce_clock_info_array_size(hwmgr,
+							powerplay_table);
+
+	return 0;
+}
+
+static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr,
+							const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
+	uint16_t table_size = 0;
+
+	if (table_offset > 0) {
+		const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable =
+			(const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset);
+
+		table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record);
+	}
+	return table_size;
+}
+
+static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
+
+	if (table_offset > 0)
+		return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table);
+
+	return 0;
+}
+
+static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table(
+						struct pp_hwmgr *hwmgr,
+						const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table);
+
+	if (table_offset > 0)
+		return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset);
+
+	return NULL;
+}
+
+static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t uvd_table_offset = 0;
+
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+			const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
+					(const ATOM_PPLIB_EXTENDEDHEADER *)
+					(((unsigned long)powerplay_table3) +
+				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+			if (le16_to_cpu(extended_header->usSize) >=
+			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3)
+				uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset);
+		}
+	}
+	return uvd_table_offset;
+}
+
+static uint16_t get_uvd_clock_info_array_offset(struct pp_hwmgr *hwmgr,
+			 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_uvd_table_offset(hwmgr,
+						    powerplay_table);
+
+	if (table_offset > 0)
+		return table_offset + 1;
+	return 0;
+}
+
+static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
+						    powerplay_table);
+	uint16_t table_size = 0;
+
+	if (table_offset > 0) {
+		const UVDClockInfoArray *p = (const UVDClockInfoArray *)
+					(((unsigned long) powerplay_table)
+					+ table_offset);
+		table_size = sizeof(UCHAR) +
+			     p->ucNumEntries * sizeof(UVDClockInfo);
+	}
+
+	return table_size;
+}
+
+static uint16_t get_uvd_clock_voltage_limit_table_offset(
+			struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
+						     powerplay_table);
+
+	if (table_offset > 0)
+		return table_offset +
+			get_uvd_clock_info_array_size(hwmgr, powerplay_table);
+
+	return 0;
+}
+
+static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t samu_table_offset = 0;
+
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+			const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
+				(const ATOM_PPLIB_EXTENDEDHEADER *)
+				(((unsigned long)powerplay_table3) +
+				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+			if (le16_to_cpu(extended_header->usSize) >=
+			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4)
+				samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset);
+		}
+	}
+
+	return samu_table_offset;
+}
+
+static uint16_t get_samu_clock_voltage_limit_table_offset(
+			struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t table_offset = get_samu_table_offset(hwmgr,
+					    powerplay_table);
+
+	if (table_offset > 0)
+		return table_offset + 1;
+
+	return 0;
+}
+
+static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr,
+				const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t acp_table_offset = 0;
+
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+			const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
+				(const ATOM_PPLIB_EXTENDEDHEADER *)
+				(((unsigned long)powerplay_table3) +
+				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+			if (le16_to_cpu(pExtendedHeader->usSize) >=
+			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6)
+				acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset);
+		}
+	}
+
+	return acp_table_offset;
+}
+
+static uint16_t get_acp_clock_voltage_limit_table_offset(
+				struct pp_hwmgr *hwmgr,
+				const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t tableOffset = get_acp_table_offset(hwmgr, powerplay_table);
+
+	if (tableOffset > 0)
+		return tableOffset + 1;
+
+	return 0;
+}
+
+static uint16_t get_cacp_tdp_table_offset(
+				struct pp_hwmgr *hwmgr,
+				const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t cacTdpTableOffset = 0;
+
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+				(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+			const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
+					(const ATOM_PPLIB_EXTENDEDHEADER *)
+					(((unsigned long)powerplay_table3) +
+				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+			if (le16_to_cpu(pExtendedHeader->usSize) >=
+			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7)
+				cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset);
+		}
+	}
+
+	return cacTdpTableOffset;
+}
+
+static int get_cac_tdp_table(struct pp_hwmgr *hwmgr,
+				struct phm_cac_tdp_table **ptable,
+				const ATOM_PowerTune_Table *table,
+				uint16_t us_maximum_power_delivery_limit)
+{
+	unsigned long table_size;
+	struct phm_cac_tdp_table *tdp_table;
+
+	table_size = sizeof(unsigned long) + sizeof(struct phm_cac_tdp_table);
+
+	tdp_table = kzalloc(table_size, GFP_KERNEL);
+	if (NULL == tdp_table)
+		return -ENOMEM;
+
+	tdp_table->usTDP = le16_to_cpu(table->usTDP);
+	tdp_table->usConfigurableTDP = le16_to_cpu(table->usConfigurableTDP);
+	tdp_table->usTDC = le16_to_cpu(table->usTDC);
+	tdp_table->usBatteryPowerLimit = le16_to_cpu(table->usBatteryPowerLimit);
+	tdp_table->usSmallPowerLimit = le16_to_cpu(table->usSmallPowerLimit);
+	tdp_table->usLowCACLeakage = le16_to_cpu(table->usLowCACLeakage);
+	tdp_table->usHighCACLeakage = le16_to_cpu(table->usHighCACLeakage);
+	tdp_table->usMaximumPowerDeliveryLimit = us_maximum_power_delivery_limit;
+
+	*ptable = tdp_table;
+
+	return 0;
+}
+
+static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t sclk_vdd_gfx_table_offset = 0;
+
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+				(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+			const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
+				(const ATOM_PPLIB_EXTENDEDHEADER *)
+				(((unsigned long)powerplay_table3) +
+				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+			if (le16_to_cpu(pExtendedHeader->usSize) >=
+			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8)
+				sclk_vdd_gfx_table_offset =
+					le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset);
+		}
+	}
+
+	return sclk_vdd_gfx_table_offset;
+}
+
+static uint16_t get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(
+			struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	uint16_t tableOffset = get_sclk_vdd_gfx_table_offset(hwmgr, powerplay_table);
+
+	if (tableOffset > 0)
+		return tableOffset;
+
+	return 0;
+}
+
+
+static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
+		struct phm_clock_voltage_dependency_table **ptable,
+		const ATOM_PPLIB_Clock_Voltage_Dependency_Table *table)
+{
+
+	unsigned long table_size, i;
+	struct phm_clock_voltage_dependency_table *dep_table;
+
+	table_size = sizeof(unsigned long) +
+		sizeof(struct phm_clock_voltage_dependency_table)
+		* table->ucNumEntries;
+
+	dep_table = kzalloc(table_size, GFP_KERNEL);
+	if (NULL == dep_table)
+		return -ENOMEM;
+
+	dep_table->count = (unsigned long)table->ucNumEntries;
+
+	for (i = 0; i < dep_table->count; i++) {
+		dep_table->entries[i].clk =
+			((unsigned long)table->entries[i].ucClockHigh << 16) |
+			le16_to_cpu(table->entries[i].usClockLow);
+			dep_table->entries[i].v =
+				(unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+	}
+
+	*ptable = dep_table;
+
+	return 0;
+}
+
+static int get_valid_clk(struct pp_hwmgr *hwmgr,
+			struct phm_clock_array **ptable,
+			const struct phm_clock_voltage_dependency_table *table)
+{
+	unsigned long table_size, i;
+	struct phm_clock_array *clock_table;
+
+	table_size = sizeof(unsigned long) + sizeof(unsigned long) * table->count;
+	clock_table = kzalloc(table_size, GFP_KERNEL);
+	if (NULL == clock_table)
+		return -ENOMEM;
+
+	clock_table->count = (unsigned long)table->count;
+
+	for (i = 0; i < clock_table->count; i++)
+		clock_table->values[i] = (unsigned long)table->entries[i].clk;
+
+	*ptable = clock_table;
+
+	return 0;
+}
+
+static int get_clock_voltage_limit(struct pp_hwmgr *hwmgr,
+			struct phm_clock_and_voltage_limits *limits,
+			const ATOM_PPLIB_Clock_Voltage_Limit_Table *table)
+{
+	limits->sclk = ((unsigned long)table->entries[0].ucSclkHigh << 16) |
+			le16_to_cpu(table->entries[0].usSclkLow);
+	limits->mclk = ((unsigned long)table->entries[0].ucMclkHigh << 16) |
+			le16_to_cpu(table->entries[0].usMclkLow);
+	limits->vddc = (unsigned long)le16_to_cpu(table->entries[0].usVddc);
+	limits->vddci = (unsigned long)le16_to_cpu(table->entries[0].usVddci);
+
+	return 0;
+}
+
+
+static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable,
+		       enum phm_platform_caps cap)
+{
+	if (enable)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
+	else
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
+}
+
+static int set_platform_caps(struct pp_hwmgr *hwmgr,
+			unsigned long powerplay_caps)
+{
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_POWERPLAY),
+		PHM_PlatformCaps_PowerPlaySupport
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
+		PHM_PlatformCaps_BiosPowerSourceControl
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s),
+		PHM_PlatformCaps_EnableASPML0s
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1),
+		PHM_PlatformCaps_EnableASPML1
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS),
+		PHM_PlatformCaps_EnableBackbias
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC),
+		PHM_PlatformCaps_AutomaticDCTransition
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY),
+		PHM_PlatformCaps_GeminiPrimary
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC),
+		PHM_PlatformCaps_StepVddc
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL),
+		PHM_PlatformCaps_EnableVoltageControl
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL),
+		PHM_PlatformCaps_EnableSideportControl
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1),
+		PHM_PlatformCaps_TurnOffPll_ASPML1
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HTLINKCONTROL),
+		PHM_PlatformCaps_EnableHTLinkControl
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL),
+		PHM_PlatformCaps_EnableMVDDControl
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL),
+		PHM_PlatformCaps_ControlVDDCI
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT),
+		PHM_PlatformCaps_RegulatorHot
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT),
+		PHM_PlatformCaps_BootStateOnAlert
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT),
+		PHM_PlatformCaps_DontWaitForVBlankOnAlert
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACO),
+		PHM_PlatformCaps_BACO
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE),
+		PHM_PlatformCaps_NewCACVoltage
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY),
+		PHM_PlatformCaps_RevertGPIO5Polarity
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17),
+		PHM_PlatformCaps_Thermal2GPIO17
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE),
+		PHM_PlatformCaps_VRHotGPIOConfigurable
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TEMP_INVERSION),
+		PHM_PlatformCaps_TempInversion
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_EVV),
+		PHM_PlatformCaps_EVV
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
+		PHM_PlatformCaps_CombinePCCWithThermalSignal
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
+		PHM_PlatformCaps_LoadPostProductionFirmware
+	);
+
+	set_hw_cap(
+		hwmgr,
+		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DISABLE_USING_ACTUAL_TEMPERATURE_FOR_POWER_CALC),
+		PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc
+	);
+
+	return 0;
+}
+
+static PP_StateClassificationFlags make_classification_flags(
+						   struct pp_hwmgr *hwmgr,
+						    USHORT classification,
+						   USHORT classification2)
+{
+	PP_StateClassificationFlags result = 0;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
+		result |= PP_StateClassificationFlag_Boot;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+		result |= PP_StateClassificationFlag_Thermal;
+
+	if (classification &
+			ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
+		result |= PP_StateClassificationFlag_LimitedPowerSource;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
+		result |= PP_StateClassificationFlag_Rest;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
+		result |= PP_StateClassificationFlag_Forced;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+		result |= PP_StateClassificationFlag_3DPerformance;
+
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
+		result |= PP_StateClassificationFlag_ACOverdriveTemplate;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		result |= PP_StateClassificationFlag_Uvd;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+		result |= PP_StateClassificationFlag_UvdHD;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+		result |= PP_StateClassificationFlag_UvdSD;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+		result |= PP_StateClassificationFlag_HD2;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
+		result |= PP_StateClassificationFlag_ACPI;
+
+	if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
+		result |= PP_StateClassificationFlag_LimitedPowerSource_2;
+
+
+	if (classification2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
+		result |= PP_StateClassificationFlag_ULV;
+
+	if (classification2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+		result |= PP_StateClassificationFlag_UvdMVC;
+
+	return result;
+}
+
+static int init_non_clock_fields(struct pp_hwmgr *hwmgr,
+						struct pp_power_state *ps,
+							    uint8_t version,
+			 const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info) {
+	unsigned long rrr_index;
+	unsigned long tmp;
+
+	ps->classification.ui_label = (le16_to_cpu(pnon_clock_info->usClassification) &
+					ATOM_PPLIB_CLASSIFICATION_UI_MASK) >> ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
+	ps->classification.flags = make_classification_flags(hwmgr,
+				le16_to_cpu(pnon_clock_info->usClassification),
+				le16_to_cpu(pnon_clock_info->usClassification2));
+
+	ps->classification.temporary_state = false;
+	ps->classification.to_be_deleted = false;
+	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+		ATOM_PPLIB_SINGLE_DISPLAY_ONLY;
+
+	ps->validation.singleDisplayOnly = (0 != tmp);
+
+	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+		ATOM_PPLIB_DISALLOW_ON_DC;
+
+	ps->validation.disallowOnDC = (0 != tmp);
+
+	ps->pcie.lanes = ((le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+				ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
+				ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
+
+	ps->pcie.lanes = 0;
+
+	ps->display.disableFrameModulation = false;
+
+	rrr_index = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+			ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK) >>
+			ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT;
+
+	if (rrr_index != ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED) {
+		static const uint8_t look_up[(ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK >> ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT) + 1] = \
+								{ 0, 50, 0 };
+
+		ps->display.refreshrateSource = PP_RefreshrateSource_Explicit;
+		ps->display.explicitRefreshrate = look_up[rrr_index];
+		ps->display.limitRefreshrate = true;
+
+		if (ps->display.explicitRefreshrate == 0)
+			ps->display.limitRefreshrate = false;
+	} else
+		ps->display.limitRefreshrate = false;
+
+	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+		ATOM_PPLIB_ENABLE_VARIBRIGHT;
+
+	ps->display.enableVariBright = (0 != tmp);
+
+	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+		ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF;
+
+	ps->memory.dllOff = (0 != tmp);
+
+	ps->memory.m3arb = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+			    ATOM_PPLIB_M3ARB_MASK) >> ATOM_PPLIB_M3ARB_SHIFT;
+
+	ps->temperatures.min = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
+				     pnon_clock_info->ucMinTemperature;
+
+	ps->temperatures.max = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
+				     pnon_clock_info->ucMaxTemperature;
+
+	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+		ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING;
+
+	ps->software.disableLoadBalancing = tmp;
+
+	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+		ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS;
+
+	ps->software.enableSleepForTimestamps = (0 != tmp);
+
+	ps->validation.supportedPowerLevels = pnon_clock_info->ucRequiredPower;
+
+	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < version) {
+		ps->uvd_clocks.VCLK = pnon_clock_info->ulVCLK;
+		ps->uvd_clocks.DCLK = pnon_clock_info->ulDCLK;
+	} else {
+		ps->uvd_clocks.VCLK = 0;
+		ps->uvd_clocks.DCLK = 0;
+	}
+
+	return 0;
+}
+
+static ULONG size_of_entry_v2(ULONG num_dpm_levels)
+{
+	return (sizeof(UCHAR) + sizeof(UCHAR) +
+			(num_dpm_levels * sizeof(UCHAR)));
+}
+
+static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
+					const StateArray * pstate_arrays,
+							 ULONG entry_index)
+{
+	ULONG i;
+	const ATOM_PPLIB_STATE_V2 *pstate;
+
+	pstate = pstate_arrays->states;
+	if (entry_index <= pstate_arrays->ucNumEntries) {
+		for (i = 0; i < entry_index; i++)
+			pstate = (ATOM_PPLIB_STATE_V2 *)(
+						  (unsigned long)pstate +
+			     size_of_entry_v2(pstate->ucNumDPMLevels));
+	}
+	return pstate;
+}
+
+
+static const ATOM_PPLIB_POWERPLAYTABLE *get_powerplay_table(
+				     struct pp_hwmgr *hwmgr)
+{
+	const void *table_addr = NULL;
+	uint8_t frev, crev;
+	uint16_t size;
+
+	table_addr = cgs_atom_get_data_table(hwmgr->device,
+			GetIndexIntoMasterTable(DATA, PowerPlayInfo),
+			&size, &frev, &crev);
+
+	hwmgr->soft_pp_table = table_addr;
+
+	return (const ATOM_PPLIB_POWERPLAYTABLE *)table_addr;
+}
+
+
+int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
+				     unsigned long *num_of_entries)
+{
+	const StateArray *pstate_arrays;
+	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
+
+	if (powerplay_table == NULL)
+		return -1;
+
+	if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
+		pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
+					le16_to_cpu(powerplay_table->usStateArrayOffset));
+
+		*num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries);
+	} else
+		*num_of_entries = (unsigned long)(powerplay_table->ucNumStates);
+
+	return 0;
+}
+
+int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
+				unsigned long entry_index,
+				struct pp_power_state *ps,
+			 pp_tables_hw_clock_info_callback func)
+{
+	int i;
+	const StateArray *pstate_arrays;
+	const ATOM_PPLIB_STATE_V2 *pstate_entry_v2;
+	const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info;
+	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
+	int result = 0;
+	int res = 0;
+
+	const ClockInfoArray *pclock_arrays;
+
+	const NonClockInfoArray *pnon_clock_arrays;
+
+	const ATOM_PPLIB_STATE *pstate_entry;
+
+	if (powerplay_table == NULL)
+		return -1;
+
+	ps->classification.bios_index = entry_index;
+
+	if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
+		pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
+					le16_to_cpu(powerplay_table->usStateArrayOffset));
+
+		if (entry_index > pstate_arrays->ucNumEntries)
+			return -1;
+
+		pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index);
+		pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
+					le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
+
+		pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) +
+						le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset));
+
+		pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) +
+					(pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize));
+
+		result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info);
+
+		for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) {
+			const void *pclock_info = (const void *)(
+							(unsigned long)(pclock_arrays->clockInfo) +
+							(pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize));
+			res = func(hwmgr, &ps->hardware, i, pclock_info);
+			if ((0 == result) && (0 != res))
+				result = res;
+		}
+	} else {
+		if (entry_index > powerplay_table->ucNumStates)
+			return -1;
+
+		pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table + powerplay_table->usStateArrayOffset +
+				entry_index * powerplay_table->ucStateEntrySize);
+
+		pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
+						le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
+						pstate_entry->ucNonClockStateIndex *
+						powerplay_table->ucNonClockSize);
+
+		result = init_non_clock_fields(hwmgr, ps,
+							powerplay_table->ucNonClockSize,
+							pnon_clock_info);
+
+		for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
+			const void *pclock_info = (const void *)((unsigned long)powerplay_table +
+						le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
+						pstate_entry->ucClockStateIndices[i] *
+						powerplay_table->ucClockInfoSize);
+
+			int res = func(hwmgr, &ps->hardware, i, pclock_info);
+
+			if ((0 == result) && (0 != res))
+					result = res;
+		}
+	}
+
+	if ((0 == result) &&
+		(0 != (ps->classification.flags & PP_StateClassificationFlag_Boot)))
+		result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware));
+
+	return result;
+}
+
+
+
+static int init_powerplay_tables(
+			struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table
+)
+{
+	return 0;
+}
+
+
+static int init_thermal_controller(
+			struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	return 0;
+}
+
+static int init_overdrive_limits_V1_4(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
+			const ATOM_FIRMWARE_INFO_V1_4 *fw_info)
+{
+	hwmgr->platform_descriptor.overdriveLimit.engineClock =
+				le32_to_cpu(fw_info->ulASICMaxEngineClock);
+
+	hwmgr->platform_descriptor.overdriveLimit.memoryClock =
+				le32_to_cpu(fw_info->ulASICMaxMemoryClock);
+
+	hwmgr->platform_descriptor.maxOverdriveVDDC =
+		le32_to_cpu(fw_info->ul3DAccelerationEngineClock) & 0x7FF;
+
+	hwmgr->platform_descriptor.minOverdriveVDDC =
+			   le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+
+	hwmgr->platform_descriptor.maxOverdriveVDDC =
+			   le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+
+	hwmgr->platform_descriptor.overdriveVDDCStep = 0;
+	return 0;
+}
+
+static int init_overdrive_limits_V2_1(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
+			const ATOM_FIRMWARE_INFO_V2_1 *fw_info)
+{
+	const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3;
+	const ATOM_PPLIB_EXTENDEDHEADER *header;
+
+	if (le16_to_cpu(powerplay_table->usTableSize) <
+	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3))
+		return 0;
+
+	powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+
+	if (0 == powerplay_table3->usExtendendedHeaderOffset)
+		return 0;
+
+	header = (ATOM_PPLIB_EXTENDEDHEADER *)(((unsigned long) powerplay_table) +
+			le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+
+	hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(header->ulMaxEngineClock);
+	hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(header->ulMaxMemoryClock);
+
+
+	hwmgr->platform_descriptor.minOverdriveVDDC = 0;
+	hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
+	hwmgr->platform_descriptor.overdriveVDDCStep = 0;
+
+	return 0;
+}
+
+static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	int result;
+	uint8_t frev, crev;
+	uint16_t size;
+
+	const ATOM_COMMON_TABLE_HEADER *fw_info = NULL;
+
+	hwmgr->platform_descriptor.overdriveLimit.engineClock = 0;
+	hwmgr->platform_descriptor.overdriveLimit.memoryClock = 0;
+	hwmgr->platform_descriptor.minOverdriveVDDC = 0;
+	hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
+
+	/* We assume here that fw_info is unchanged if this call fails.*/
+	fw_info = cgs_atom_get_data_table(hwmgr->device,
+			 GetIndexIntoMasterTable(DATA, FirmwareInfo),
+			 &size, &frev, &crev);
+
+	if ((fw_info->ucTableFormatRevision == 1)
+		&& (fw_info->usStructureSize >= sizeof(ATOM_FIRMWARE_INFO_V1_4)))
+		result = init_overdrive_limits_V1_4(hwmgr,
+				powerplay_table,
+				(const ATOM_FIRMWARE_INFO_V1_4 *)fw_info);
+
+	else if ((fw_info->ucTableFormatRevision == 2)
+		&& (fw_info->usStructureSize >= sizeof(ATOM_FIRMWARE_INFO_V2_1)))
+		result = init_overdrive_limits_V2_1(hwmgr,
+				powerplay_table,
+				(const ATOM_FIRMWARE_INFO_V2_1 *)fw_info);
+
+	if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0
+		&& hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0
+		&& !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_OverdriveDisabledByPowerBudget))
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_ACOverdriveSupport);
+
+	return result;
+}
+
+static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
+		struct phm_uvd_clock_voltage_dependency_table **ptable,
+		const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *table,
+		const UVDClockInfoArray *array)
+{
+	unsigned long table_size, i;
+	struct phm_uvd_clock_voltage_dependency_table *uvd_table;
+
+	table_size = sizeof(unsigned long) +
+		 sizeof(struct phm_uvd_clock_voltage_dependency_table) *
+		 table->numEntries;
+
+	uvd_table = kzalloc(table_size, GFP_KERNEL);
+	if (NULL == uvd_table)
+		return -ENOMEM;
+
+	uvd_table->count = table->numEntries;
+
+	for (i = 0; i < table->numEntries; i++) {
+		const UVDClockInfo *entry =
+			&array->entries[table->entries[i].ucUVDClockInfoIndex];
+		uvd_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+		uvd_table->entries[i].vclk = ((unsigned long)entry->ucVClkHigh << 16)
+					 | le16_to_cpu(entry->usVClkLow);
+		uvd_table->entries[i].dclk = ((unsigned long)entry->ucDClkHigh << 16)
+					 | le16_to_cpu(entry->usDClkLow);
+	}
+
+	*ptable = uvd_table;
+
+	return 0;
+}
+
+static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
+		struct phm_vce_clock_voltage_dependency_table **ptable,
+		const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table,
+		const VCEClockInfoArray    *array)
+{
+	unsigned long table_size, i;
+	struct phm_vce_clock_voltage_dependency_table *vce_table = NULL;
+
+	table_size = sizeof(unsigned long) +
+			sizeof(struct phm_vce_clock_voltage_dependency_table)
+			* table->numEntries;
+
+	vce_table = kzalloc(table_size, GFP_KERNEL);
+	if (NULL == vce_table)
+		return -ENOMEM;
+
+	vce_table->count = table->numEntries;
+	for (i = 0; i < table->numEntries; i++) {
+		const VCEClockInfo *entry = &array->entries[table->entries[i].ucVCEClockInfoIndex];
+
+		vce_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+		vce_table->entries[i].evclk = ((unsigned long)entry->ucEVClkHigh << 16)
+					| le16_to_cpu(entry->usEVClkLow);
+		vce_table->entries[i].ecclk = ((unsigned long)entry->ucECClkHigh << 16)
+					| le16_to_cpu(entry->usECClkLow);
+	}
+
+	*ptable = vce_table;
+
+	return 0;
+}
+
+static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
+		 struct phm_samu_clock_voltage_dependency_table **ptable,
+		 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *table)
+{
+	unsigned long table_size, i;
+	struct phm_samu_clock_voltage_dependency_table *samu_table;
+
+	table_size = sizeof(unsigned long) +
+		sizeof(struct phm_samu_clock_voltage_dependency_table) *
+		table->numEntries;
+
+	samu_table = kzalloc(table_size, GFP_KERNEL);
+	if (NULL == samu_table)
+		return -ENOMEM;
+
+	samu_table->count = table->numEntries;
+
+	for (i = 0; i < table->numEntries; i++) {
+		samu_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+		samu_table->entries[i].samclk = ((unsigned long)table->entries[i].ucSAMClockHigh << 16)
+					 | le16_to_cpu(table->entries[i].usSAMClockLow);
+	}
+
+	*ptable = samu_table;
+
+	return 0;
+}
+
+static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
+		struct phm_acp_clock_voltage_dependency_table **ptable,
+		const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *table)
+{
+	unsigned table_size, i;
+	struct phm_acp_clock_voltage_dependency_table *acp_table;
+
+	table_size = sizeof(unsigned long) +
+		sizeof(struct phm_acp_clock_voltage_dependency_table) *
+		table->numEntries;
+
+	acp_table = kzalloc(table_size, GFP_KERNEL);
+	if (NULL == acp_table)
+		return -ENOMEM;
+
+	acp_table->count = (unsigned long)table->numEntries;
+
+	for (i = 0; i < table->numEntries; i++) {
+		acp_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+		acp_table->entries[i].acpclk = ((unsigned long)table->entries[i].ucACPClockHigh << 16)
+					 | le16_to_cpu(table->entries[i].usACPClockLow);
+	}
+
+	*ptable = acp_table;
+
+	return 0;
+}
+
+static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	ATOM_PPLIB_Clock_Voltage_Dependency_Table *table;
+	ATOM_PPLIB_Clock_Voltage_Limit_Table *limit_table;
+	int result = 0;
+
+	uint16_t vce_clock_info_array_offset;
+	uint16_t uvd_clock_info_array_offset;
+	uint16_t table_offset;
+
+	hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
+	hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
+	hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
+	hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+	hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
+	hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
+	hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
+	hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
+	hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
+	hwmgr->dyn_state.ppm_parameter_table = NULL;
+	hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
+
+	vce_clock_info_array_offset = get_vce_clock_info_array_offset(
+						hwmgr, powerplay_table);
+	table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr,
+						powerplay_table);
+	if (vce_clock_info_array_offset > 0 && table_offset > 0) {
+		const VCEClockInfoArray *array = (const VCEClockInfoArray *)
+				(((unsigned long) powerplay_table) +
+				vce_clock_info_array_offset);
+		const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table =
+				(const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
+				(((unsigned long) powerplay_table) + table_offset);
+		result = get_vce_clock_voltage_limit_table(hwmgr,
+				&hwmgr->dyn_state.vce_clock_voltage_dependency_table,
+				table, array);
+	}
+
+	uvd_clock_info_array_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table);
+	table_offset = get_uvd_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
+
+	if (uvd_clock_info_array_offset > 0 && table_offset > 0) {
+		const UVDClockInfoArray *array = (const UVDClockInfoArray *)
+				(((unsigned long) powerplay_table) +
+				uvd_clock_info_array_offset);
+		const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable =
+				(const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
+				(((unsigned long) powerplay_table) + table_offset);
+		result = get_uvd_clock_voltage_limit_table(hwmgr,
+				&hwmgr->dyn_state.uvd_clock_voltage_dependency_table, ptable, array);
+	}
+
+	table_offset = get_samu_clock_voltage_limit_table_offset(hwmgr,
+							    powerplay_table);
+
+	if (table_offset > 0) {
+		const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable =
+				(const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
+				(((unsigned long) powerplay_table) + table_offset);
+		result = get_samu_clock_voltage_limit_table(hwmgr,
+				&hwmgr->dyn_state.samu_clock_voltage_dependency_table, ptable);
+	}
+
+	table_offset = get_acp_clock_voltage_limit_table_offset(hwmgr,
+							     powerplay_table);
+
+	if (table_offset > 0) {
+		const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable =
+				(const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
+				(((unsigned long) powerplay_table) + table_offset);
+		result = get_acp_clock_voltage_limit_table(hwmgr,
+				&hwmgr->dyn_state.acp_clock_voltage_dependency_table, ptable);
+	}
+
+	table_offset = get_cacp_tdp_table_offset(hwmgr, powerplay_table);
+	if (table_offset > 0) {
+		UCHAR rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset);
+
+		if (rev_id > 0) {
+			const ATOM_PPLIB_POWERTUNE_Table_V1 *tune_table =
+				(const ATOM_PPLIB_POWERTUNE_Table_V1 *)
+				(((unsigned long) powerplay_table) + table_offset);
+			result = get_cac_tdp_table(hwmgr, &hwmgr->dyn_state.cac_dtp_table,
+				&tune_table->power_tune_table,
+				le16_to_cpu(tune_table->usMaximumPowerDeliveryLimit));
+			hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
+				le16_to_cpu(tune_table->usTjMax);
+		} else {
+			const ATOM_PPLIB_POWERTUNE_Table *tune_table =
+				(const ATOM_PPLIB_POWERTUNE_Table *)
+				(((unsigned long) powerplay_table) + table_offset);
+			result = get_cac_tdp_table(hwmgr,
+				&hwmgr->dyn_state.cac_dtp_table,
+				&tune_table->power_tune_table, 255);
+		}
+	}
+
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+		sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
+		const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
+				(const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
+		if (0 != powerplay_table4->usVddcDependencyOnSCLKOffset) {
+			table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+				(((unsigned long) powerplay_table4) +
+				powerplay_table4->usVddcDependencyOnSCLKOffset);
+			result = get_clock_voltage_dependency_table(hwmgr,
+				&hwmgr->dyn_state.vddc_dependency_on_sclk, table);
+		}
+
+		if (result == 0 && (0 != powerplay_table4->usVddciDependencyOnMCLKOffset)) {
+			table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+				(((unsigned long) powerplay_table4) +
+				powerplay_table4->usVddciDependencyOnMCLKOffset);
+			result = get_clock_voltage_dependency_table(hwmgr,
+				&hwmgr->dyn_state.vddci_dependency_on_mclk, table);
+		}
+
+		if (result == 0 && (0 != powerplay_table4->usVddcDependencyOnMCLKOffset)) {
+			table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+				(((unsigned long) powerplay_table4) +
+				powerplay_table4->usVddcDependencyOnMCLKOffset);
+			result = get_clock_voltage_dependency_table(hwmgr,
+				&hwmgr->dyn_state.vddc_dependency_on_mclk, table);
+		}
+
+		if (result == 0 && (0 != powerplay_table4->usMaxClockVoltageOnDCOffset)) {
+			limit_table = (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
+				(((unsigned long) powerplay_table4) +
+				powerplay_table4->usMaxClockVoltageOnDCOffset);
+			result = get_clock_voltage_limit(hwmgr,
+				&hwmgr->dyn_state.max_clock_voltage_on_dc, limit_table);
+		}
+
+		if (result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) &&
+			(0 != hwmgr->dyn_state.vddc_dependency_on_mclk->count))
+			result = get_valid_clk(hwmgr, &hwmgr->dyn_state.valid_mclk_values,
+					hwmgr->dyn_state.vddc_dependency_on_mclk);
+
+		if(result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) &&
+			(0 != hwmgr->dyn_state.vddc_dependency_on_sclk->count))
+			result = get_valid_clk(hwmgr,
+				&hwmgr->dyn_state.valid_sclk_values,
+				hwmgr->dyn_state.vddc_dependency_on_sclk);
+
+		if (result == 0 && (0 != powerplay_table4->usMvddDependencyOnMCLKOffset)) {
+			table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+				(((unsigned long) powerplay_table4) +
+				powerplay_table4->usMvddDependencyOnMCLKOffset);
+			result = get_clock_voltage_dependency_table(hwmgr,
+				&hwmgr->dyn_state.mvdd_dependency_on_mclk, table);
+		}
+	}
+
+	table_offset = get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(hwmgr,
+								powerplay_table);
+
+	if (table_offset > 0) {
+		table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+			(((unsigned long) powerplay_table) + table_offset);
+		result = get_clock_voltage_dependency_table(hwmgr,
+			&hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, table);
+	}
+
+	return result;
+}
+
+static int get_cac_leakage_table(struct pp_hwmgr *hwmgr,
+				 struct phm_cac_leakage_table **ptable,
+				const ATOM_PPLIB_CAC_Leakage_Table *table)
+{
+	struct phm_cac_leakage_table  *cac_leakage_table;
+	unsigned long            table_size, i;
+
+	if (hwmgr == NULL || table == NULL || ptable == NULL)
+		return -EINVAL;
+
+	table_size = sizeof(ULONG) +
+		(sizeof(struct phm_cac_leakage_table) * table->ucNumEntries);
+
+	cac_leakage_table = kzalloc(table_size, GFP_KERNEL);
+
+	if (cac_leakage_table == NULL)
+		return -ENOMEM;
+
+	cac_leakage_table->count = (ULONG)table->ucNumEntries;
+
+	for (i = 0; i < cac_leakage_table->count; i++) {
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_EVV)) {
+			cac_leakage_table->entries[i].Vddc1 = le16_to_cpu(table->entries[i].usVddc1);
+			cac_leakage_table->entries[i].Vddc2 = le16_to_cpu(table->entries[i].usVddc2);
+			cac_leakage_table->entries[i].Vddc3 = le16_to_cpu(table->entries[i].usVddc3);
+		} else {
+			cac_leakage_table->entries[i].Vddc    = le16_to_cpu(table->entries[i].usVddc);
+			cac_leakage_table->entries[i].Leakage = le32_to_cpu(table->entries[i].ulLeakageValue);
+		}
+	}
+
+	*ptable = cac_leakage_table;
+
+	return 0;
+}
+
+static int get_platform_power_management_table(struct pp_hwmgr *hwmgr,
+			ATOM_PPLIB_PPM_Table *atom_ppm_table)
+{
+	struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL);
+
+	if (NULL == ptr)
+		return -ENOMEM;
+
+	ptr->ppm_design            = atom_ppm_table->ucPpmDesign;
+	ptr->cpu_core_number        = le16_to_cpu(atom_ppm_table->usCpuCoreNumber);
+	ptr->platform_tdp          = le32_to_cpu(atom_ppm_table->ulPlatformTDP);
+	ptr->small_ac_platform_tdp   = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDP);
+	ptr->platform_tdc          = le32_to_cpu(atom_ppm_table->ulPlatformTDC);
+	ptr->small_ac_platform_tdc   = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDC);
+	ptr->apu_tdp               = le32_to_cpu(atom_ppm_table->ulApuTDP);
+	ptr->dgpu_tdp              = le32_to_cpu(atom_ppm_table->ulDGpuTDP);
+	ptr->dgpu_ulv_power         = le32_to_cpu(atom_ppm_table->ulDGpuUlvPower);
+	ptr->tj_max                = le32_to_cpu(atom_ppm_table->ulTjmax);
+	hwmgr->dyn_state.ppm_parameter_table = ptr;
+
+	return 0;
+}
+
+static int init_dpm2_parameters(struct pp_hwmgr *hwmgr,
+			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	int result = 0;
+
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+	    sizeof(ATOM_PPLIB_POWERPLAYTABLE5)) {
+		const  ATOM_PPLIB_POWERPLAYTABLE5 *ptable5 =
+				(const ATOM_PPLIB_POWERPLAYTABLE5 *)powerplay_table;
+		const  ATOM_PPLIB_POWERPLAYTABLE4 *ptable4 =
+				(const ATOM_PPLIB_POWERPLAYTABLE4 *)
+				(&ptable5->basicTable4);
+		const  ATOM_PPLIB_POWERPLAYTABLE3 *ptable3 =
+				(const ATOM_PPLIB_POWERPLAYTABLE3 *)
+				(&ptable4->basicTable3);
+		const  ATOM_PPLIB_EXTENDEDHEADER  *extended_header;
+		uint16_t table_offset;
+		ATOM_PPLIB_PPM_Table *atom_ppm_table;
+
+		hwmgr->platform_descriptor.TDPLimit     = le32_to_cpu(ptable5->ulTDPLimit);
+		hwmgr->platform_descriptor.nearTDPLimit = le32_to_cpu(ptable5->ulNearTDPLimit);
+
+		hwmgr->platform_descriptor.TDPODLimit   = le16_to_cpu(ptable5->usTDPODLimit);
+		hwmgr->platform_descriptor.TDPAdjustment = 0;
+
+		hwmgr->platform_descriptor.VidAdjustment = 0;
+		hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
+		hwmgr->platform_descriptor.VidMinLimit     = 0;
+		hwmgr->platform_descriptor.VidMaxLimit     = 1500000;
+		hwmgr->platform_descriptor.VidStep         = 6250;
+
+		hwmgr->platform_descriptor.nearTDPLimitAdjusted = le32_to_cpu(ptable5->ulNearTDPLimit);
+
+		if (hwmgr->platform_descriptor.TDPODLimit != 0)
+			phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_PowerControl);
+
+		hwmgr->platform_descriptor.SQRampingThreshold = le32_to_cpu(ptable5->ulSQRampingThreshold);
+
+		hwmgr->platform_descriptor.CACLeakage = le32_to_cpu(ptable5->ulCACLeakage);
+
+		hwmgr->dyn_state.cac_leakage_table = NULL;
+
+		if (0 != ptable5->usCACLeakageTableOffset) {
+			const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table =
+				(ATOM_PPLIB_CAC_Leakage_Table *)(((unsigned long)ptable5) +
+				le16_to_cpu(ptable5->usCACLeakageTableOffset));
+			result = get_cac_leakage_table(hwmgr,
+				&hwmgr->dyn_state.cac_leakage_table, pCAC_leakage_table);
+		}
+
+		hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(ptable5->usLoadLineSlope);
+
+		hwmgr->dyn_state.ppm_parameter_table = NULL;
+
+		if (0 != ptable3->usExtendendedHeaderOffset) {
+			extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *)
+					(((unsigned long)powerplay_table) +
+					le16_to_cpu(ptable3->usExtendendedHeaderOffset));
+			if ((extended_header->usPPMTableOffset > 0) &&
+				le16_to_cpu(extended_header->usSize) >=
+				    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) {
+				table_offset = le16_to_cpu(extended_header->usPPMTableOffset);
+				atom_ppm_table = (ATOM_PPLIB_PPM_Table *)
+					(((unsigned long)powerplay_table) + table_offset);
+				if (0 == get_platform_power_management_table(hwmgr, atom_ppm_table))
+					phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+						PHM_PlatformCaps_EnablePlatformPowerManagement);
+			}
+		}
+	}
+	return result;
+}
+
+static int init_phase_shedding_table(struct pp_hwmgr *hwmgr,
+		const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+	if (le16_to_cpu(powerplay_table->usTableSize) >=
+	    sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
+		const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
+				(const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
+
+		if (0 != powerplay_table4->usVddcPhaseShedLimitsTableOffset) {
+			const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable =
+				(ATOM_PPLIB_PhaseSheddingLimits_Table *)
+				(((unsigned long)powerplay_table4) +
+				le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset));
+			struct phm_phase_shedding_limits_table *table;
+			unsigned long size, i;
+
+
+			size = sizeof(unsigned long) +
+				(sizeof(struct phm_phase_shedding_limits_table) *
+				ptable->ucNumEntries);
+
+			table = kzalloc(size, GFP_KERNEL);
+
+			if (table == NULL)
+				return -ENOMEM;
+
+			table->count = (unsigned long)ptable->ucNumEntries;
+
+			for (i = 0; i < table->count; i++) {
+				table->entries[i].Voltage = (unsigned long)le16_to_cpu(ptable->entries[i].usVoltage);
+				table->entries[i].Sclk    = ((unsigned long)ptable->entries[i].ucSclkHigh << 16)
+							| le16_to_cpu(ptable->entries[i].usSclkLow);
+				table->entries[i].Mclk    = ((unsigned long)ptable->entries[i].ucMclkHigh << 16)
+							| le16_to_cpu(ptable->entries[i].usMclkLow);
+			}
+			hwmgr->dyn_state.vddc_phase_shed_limits_table = table;
+		}
+	}
+
+	return 0;
+}
+
+int get_number_of_vce_state_table_entries(
+						  struct pp_hwmgr *hwmgr)
+{
+	const ATOM_PPLIB_POWERPLAYTABLE *table =
+					     get_powerplay_table(hwmgr);
+	const ATOM_PPLIB_VCE_State_Table *vce_table =
+				    get_vce_state_table(hwmgr, table);
+
+	if (vce_table > 0)
+		return vce_table->numEntries;
+
+	return 0;
+}
+
+int get_vce_state_table_entry(struct pp_hwmgr *hwmgr,
+							unsigned long i,
+							struct PP_VCEState *vce_state,
+							void **clock_info,
+							unsigned long *flag)
+{
+	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
+
+	const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table);
+
+	unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table);
+
+	const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset);
+
+	const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + powerplay_table->usClockInfoArrayOffset);
+
+	const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i];
+
+	const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex];
+
+	unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F;
+
+	*flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX);
+
+	vce_state->evclk = ((uint32_t)vce_clock_info->ucEVClkHigh << 16) | vce_clock_info->usEVClkLow;
+	vce_state->ecclk = ((uint32_t)vce_clock_info->ucECClkHigh << 16) | vce_clock_info->usECClkLow;
+
+	*clock_info = (void *)((unsigned long)(clock_arrays->clockInfo) + (clockInfoIndex * clock_arrays->ucEntrySize));
+
+	return 0;
+}
+
+
+static int pp_tables_initialize(struct pp_hwmgr *hwmgr)
+{
+	int result;
+	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table;
+
+	hwmgr->need_pp_table_upload = true;
+
+	powerplay_table = get_powerplay_table(hwmgr);
+
+	result = init_powerplay_tables(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_powerplay_tables failed", return result);
+
+	result = set_platform_caps(hwmgr,
+				le32_to_cpu(powerplay_table->ulPlatformCaps));
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "set_platform_caps failed", return result);
+
+	result = init_thermal_controller(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_thermal_controller failed", return result);
+
+	result = init_overdrive_limits(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_overdrive_limits failed", return result);
+
+	result = init_clock_voltage_dependency(hwmgr,
+					       powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_clock_voltage_dependency failed", return result);
+
+	result = init_dpm2_parameters(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_dpm2_parameters failed", return result);
+
+	result = init_phase_shedding_table(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_phase_shedding_table failed", return result);
+
+	return result;
+}
+
+static int pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
+{
+	if (NULL != hwmgr->soft_pp_table) {
+		kfree(hwmgr->soft_pp_table);
+		hwmgr->soft_pp_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) {
+		kfree(hwmgr->dyn_state.vddc_dependency_on_sclk);
+		hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.vddci_dependency_on_mclk) {
+		kfree(hwmgr->dyn_state.vddci_dependency_on_mclk);
+		hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) {
+		kfree(hwmgr->dyn_state.vddc_dependency_on_mclk);
+		hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.mvdd_dependency_on_mclk) {
+		kfree(hwmgr->dyn_state.mvdd_dependency_on_mclk);
+		hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.valid_mclk_values) {
+		kfree(hwmgr->dyn_state.valid_mclk_values);
+		hwmgr->dyn_state.valid_mclk_values = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.valid_sclk_values) {
+		kfree(hwmgr->dyn_state.valid_sclk_values);
+		hwmgr->dyn_state.valid_sclk_values = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.cac_leakage_table) {
+		kfree(hwmgr->dyn_state.cac_leakage_table);
+		hwmgr->dyn_state.cac_leakage_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.vddc_phase_shed_limits_table) {
+		kfree(hwmgr->dyn_state.vddc_phase_shed_limits_table);
+		hwmgr->dyn_state.vddc_phase_shed_limits_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.vce_clock_voltage_dependency_table) {
+		kfree(hwmgr->dyn_state.vce_clock_voltage_dependency_table);
+		hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.uvd_clock_voltage_dependency_table) {
+		kfree(hwmgr->dyn_state.uvd_clock_voltage_dependency_table);
+		hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.samu_clock_voltage_dependency_table) {
+		kfree(hwmgr->dyn_state.samu_clock_voltage_dependency_table);
+		hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.acp_clock_voltage_dependency_table) {
+		kfree(hwmgr->dyn_state.acp_clock_voltage_dependency_table);
+		hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.cac_dtp_table) {
+		kfree(hwmgr->dyn_state.cac_dtp_table);
+		hwmgr->dyn_state.cac_dtp_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.ppm_parameter_table) {
+		kfree(hwmgr->dyn_state.ppm_parameter_table);
+		hwmgr->dyn_state.ppm_parameter_table = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.vdd_gfx_dependency_on_sclk) {
+		kfree(hwmgr->dyn_state.vdd_gfx_dependency_on_sclk);
+		hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
+	}
+
+	if (NULL != hwmgr->dyn_state.vq_budgeting_table) {
+		kfree(hwmgr->dyn_state.vq_budgeting_table);
+		hwmgr->dyn_state.vq_budgeting_table = NULL;
+	}
+
+	return 0;
+}
+
+const struct pp_table_func pptable_funcs = {
+	.pptable_init = pp_tables_initialize,
+	.pptable_fini = pp_tables_uninitialize,
+	.pptable_get_number_of_vce_state_table_entries =
+				get_number_of_vce_state_table_entries,
+	.pptable_get_vce_state_table_entry =
+						get_vce_state_table_entry,
+};
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * Interface Functions related to the BIOS PowerPlay Tables.
+ *
+ */
+
+#ifndef PROCESSPPTABLES_H
+#define PROCESSPPTABLES_H
+
+struct pp_hwmgr;
+struct pp_power_state;
+struct pp_hw_power_state;
+
+extern const struct pp_table_func pptable_funcs;
+
+typedef int (*pp_tables_hw_clock_info_callback)(struct pp_hwmgr *hwmgr,
+					struct pp_hw_power_state *hw_ps,
+							unsigned int index,
+						 const void *clock_info);
+
+int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
+				     unsigned long *num_of_entries);
+
+int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
+						unsigned long entry_index,
+						struct pp_power_state *ps,
+				pp_tables_hw_clock_info_callback func);
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "hwmgr.h"
+#include "tonga_clockpowergating.h"
+#include "tonga_ppsmc.h"
+#include "tonga_hwmgr.h"
+
+int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cf_want_uvd_power_gating(hwmgr))
+		return smum_send_msg_to_smc(hwmgr->smumgr,
+						     PPSMC_MSG_UVDPowerOFF);
+	return 0;
+}
+
+int tonga_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cf_want_uvd_power_gating(hwmgr)) {
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				  PHM_PlatformCaps_UVDDynamicPowerGating)) {
+			return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+								PPSMC_MSG_UVDPowerON, 1);
+		} else {
+			return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+								PPSMC_MSG_UVDPowerON, 0);
+		}
+	}
+
+	return 0;
+}
+
+int tonga_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cf_want_vce_power_gating(hwmgr))
+		return smum_send_msg_to_smc(hwmgr->smumgr,
+						  PPSMC_MSG_VCEPowerOFF);
+	return 0;
+}
+
+int tonga_phm_powerup_vce(struct pp_hwmgr *hwmgr)
+{
+	if (phm_cf_want_vce_power_gating(hwmgr))
+		return smum_send_msg_to_smc(hwmgr->smumgr,
+						  PPSMC_MSG_VCEPowerON);
+	return 0;
+}
+
+int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
+{
+	int ret = 0;
+
+	switch (block) {
+	case PHM_AsicBlock_UVD_MVC:
+	case PHM_AsicBlock_UVD:
+	case PHM_AsicBlock_UVD_HD:
+	case PHM_AsicBlock_UVD_SD:
+		if (gating == PHM_ClockGateSetting_StaticOff)
+			ret = tonga_phm_powerdown_uvd(hwmgr);
+		else
+			ret = tonga_phm_powerup_uvd(hwmgr);
+		break;
+	case PHM_AsicBlock_GFX:
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	data->uvd_power_gated = false;
+	data->vce_power_gated = false;
+
+	tonga_phm_powerup_uvd(hwmgr);
+	tonga_phm_powerup_vce(hwmgr);
+
+	return 0;
+}
+
+int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	if (data->uvd_power_gated == bgate)
+		return 0;
+
+	data->uvd_power_gated = bgate;
+
+	if (bgate) {
+		cgs_set_clockgating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_CG_STATE_UNGATE);
+		cgs_set_powergating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_PG_STATE_GATE);
+		tonga_update_uvd_dpm(hwmgr, true);
+		tonga_phm_powerdown_uvd(hwmgr);
+	} else {
+		tonga_phm_powerup_uvd(hwmgr);
+		cgs_set_powergating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_PG_STATE_UNGATE);
+		cgs_set_clockgating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_PG_STATE_GATE);
+
+		tonga_update_uvd_dpm(hwmgr, false);
+	}
+
+	return 0;
+}
+
+int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	struct phm_set_power_state_input states;
+	const struct pp_power_state  *pcurrent;
+	struct pp_power_state  *requested;
+
+	pcurrent = hwmgr->current_ps;
+	requested = hwmgr->request_ps;
+
+	states.pcurrent_state = &(pcurrent->hardware);
+	states.pnew_state = &(requested->hardware);
+
+	if (phm_cf_want_vce_power_gating(hwmgr)) {
+		if (data->vce_power_gated != bgate) {
+			if (bgate) {
+				cgs_set_clockgating_state(
+							hwmgr->device,
+							AMD_IP_BLOCK_TYPE_VCE,
+							AMD_CG_STATE_UNGATE);
+				cgs_set_powergating_state(
+							hwmgr->device,
+							AMD_IP_BLOCK_TYPE_VCE,
+							AMD_PG_STATE_GATE);
+				tonga_enable_disable_vce_dpm(hwmgr, false);
+				data->vce_power_gated = true;
+			} else {
+				tonga_phm_powerup_vce(hwmgr);
+				data->vce_power_gated = false;
+				cgs_set_powergating_state(
+							hwmgr->device,
+							AMD_IP_BLOCK_TYPE_VCE,
+							AMD_PG_STATE_UNGATE);
+				cgs_set_clockgating_state(
+							hwmgr->device,
+							AMD_IP_BLOCK_TYPE_VCE,
+							AMD_PG_STATE_GATE);
+
+				tonga_update_vce_dpm(hwmgr, &states);
+				tonga_enable_disable_vce_dpm(hwmgr, true);
+				return 0;
+			}
+		}
+	} else {
+		tonga_update_vce_dpm(hwmgr, &states);
+		tonga_enable_disable_vce_dpm(hwmgr, true);
+		return 0;
+	}
+
+	if (!data->vce_power_gated)
+		tonga_update_vce_dpm(hwmgr, &states);
+
+	return 0;
+}
+
+int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
+					const uint32_t *msg_id)
+{
+	PPSMC_Msg msg;
+	uint32_t value;
+
+	switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
+	case PP_GROUP_GFX:
+		switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
+		case PP_BLOCK_GFX_CG:
+			if (PP_STATE_SUPPORT_CG & *msg_id) {
+				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+				  ? PPSMC_MSG_EnableClockGatingFeature
+				  : PPSMC_MSG_DisableClockGatingFeature;
+				value = CG_GFX_CGCG_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+			if (PP_STATE_SUPPORT_LS & *msg_id) {
+				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+					? PPSMC_MSG_EnableClockGatingFeature
+					: PPSMC_MSG_DisableClockGatingFeature;
+				value = CG_GFX_CGLS_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+			break;
+
+		case PP_BLOCK_GFX_MG:
+			/* For GFX MGCG, there are three different ones;
+			 * CPF, RLC, and all others.  CPF MGCG will not be used for Tonga.
+			 * For GFX MGLS, Tonga will not support it.
+			 * */
+			if (PP_STATE_SUPPORT_CG & *msg_id) {
+				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+				? PPSMC_MSG_EnableClockGatingFeature
+				: PPSMC_MSG_DisableClockGatingFeature;
+				value = (CG_RLC_MGCG_MASK | CG_GFX_OTHERS_MGCG_MASK);
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+			break;
+
+		default:
+			return -1;
+		}
+		break;
+
+	case PP_GROUP_SYS:
+		switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
+		case PP_BLOCK_SYS_BIF:
+			if (PP_STATE_SUPPORT_LS & *msg_id) {
+				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+				? PPSMC_MSG_EnableClockGatingFeature
+				: PPSMC_MSG_DisableClockGatingFeature;
+				value = CG_SYS_BIF_MGLS_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+			break;
+
+		case PP_BLOCK_SYS_MC:
+			if (PP_STATE_SUPPORT_CG & *msg_id) {
+				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+				? PPSMC_MSG_EnableClockGatingFeature
+				: PPSMC_MSG_DisableClockGatingFeature;
+				value = CG_SYS_MC_MGCG_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+
+			if (PP_STATE_SUPPORT_LS & *msg_id) {
+				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+				? PPSMC_MSG_EnableClockGatingFeature
+				: PPSMC_MSG_DisableClockGatingFeature;
+				value = CG_SYS_MC_MGLS_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+
+			}
+			break;
+
+		case PP_BLOCK_SYS_HDP:
+			if (PP_STATE_SUPPORT_CG & *msg_id) {
+				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+					? PPSMC_MSG_EnableClockGatingFeature
+					: PPSMC_MSG_DisableClockGatingFeature;
+				value = CG_SYS_HDP_MGCG_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+
+			if (PP_STATE_SUPPORT_LS & *msg_id) {
+				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+					? PPSMC_MSG_EnableClockGatingFeature
+					: PPSMC_MSG_DisableClockGatingFeature;
+
+				value = CG_SYS_HDP_MGLS_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+			break;
+
+		case PP_BLOCK_SYS_SDMA:
+			if (PP_STATE_SUPPORT_CG & *msg_id) {
+				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+				? PPSMC_MSG_EnableClockGatingFeature
+				: PPSMC_MSG_DisableClockGatingFeature;
+				value = CG_SYS_SDMA_MGCG_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+
+			if (PP_STATE_SUPPORT_LS & *msg_id) {
+				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+				? PPSMC_MSG_EnableClockGatingFeature
+				: PPSMC_MSG_DisableClockGatingFeature;
+
+				value = CG_SYS_SDMA_MGLS_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+			break;
+
+		case PP_BLOCK_SYS_ROM:
+			if (PP_STATE_SUPPORT_CG & *msg_id) {
+				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+				? PPSMC_MSG_EnableClockGatingFeature
+				: PPSMC_MSG_DisableClockGatingFeature;
+				value = CG_SYS_ROM_MASK;
+
+				if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+					return -1;
+			}
+			break;
+
+		default:
+			return -1;
+
+		}
+		break;
+
+	default:
+		return -1;
+
+	}
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _TONGA_CLOCK_POWER_GATING_H_
+#define _TONGA_CLOCK_POWER_GATING_H_
+
+#include "tonga_hwmgr.h"
+#include "pp_asicblocks.h"
+
+extern int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
+extern int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
+extern int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
+extern int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
+extern int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
+extern int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id);
+#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef TONGA_DYN_DEFAULTS_H
+#define TONGA_DYN_DEFAULTS_H
+
+
+/** \file
+ * Volcanic Islands Dynamic default parameters.
+ */
+
+enum TONGAdpm_TrendDetection {
+	TONGAdpm_TrendDetection_AUTO,
+	TONGAdpm_TrendDetection_UP,
+	TONGAdpm_TrendDetection_DOWN
+};
+typedef enum TONGAdpm_TrendDetection TONGAdpm_TrendDetection;
+
+/* Bit vector representing same fields as hardware register. */
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0              0x3FFFC102  /* CP_Gfx_busy */
+/* HDP_busy */
+/* IH_busy */
+/* DRM_busy */
+/* DRMDMA_busy */
+/* UVD_busy */
+/* VCE_busy */
+/* ACP_busy */
+/* SAMU_busy */
+/* AVP_busy  */
+/* SDMA enabled */
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1              0x000400  /* FE_Gfx_busy  - Intended for primary usage.   Rest are for flexibility. */
+/* SH_Gfx_busy */
+/* RB_Gfx_busy */
+/* VCE_busy */
+
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2              0xC00080  /* SH_Gfx_busy - Intended for primary usage.   Rest are for flexibility. */
+/* FE_Gfx_busy */
+/* RB_Gfx_busy */
+/* ACP_busy */
+
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3              0xC00200  /* RB_Gfx_busy - Intended for primary usage.   Rest are for flexibility. */
+/* FE_Gfx_busy */
+/* SH_Gfx_busy */
+/* UVD_busy */
+
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4              0xC01680  /* UVD_busy */
+/* VCE_busy */
+/* ACP_busy */
+/* SAMU_busy */
+
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5              0xC00033  /* GFX, HDP, DRMDMA */
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6              0xC00033  /* GFX, HDP, DRMDMA */
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7              0x3FFFC000  /* GFX, HDP, DRMDMA */
+
+
+/* thermal protection counter (units).*/
+#define PPTONGA_THERMALPROTECTCOUNTER_DFLT            0x200 /* ~19us */
+
+/* static screen threshold unit */
+#define PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT        0
+
+/* static screen threshold */
+#define PPTONGA_STATICSCREENTHRESHOLD_DFLT            0x00C8
+
+/* gfx idle clock stop threshold */
+#define PPTONGA_GFXIDLECLOCKSTOPTHRESHOLD_DFLT        0x200 /* ~19us with static screen threshold unit of 0 */
+
+/* Fixed reference divider to use when building baby stepping tables. */
+#define PPTONGA_REFERENCEDIVIDER_DFLT                  4
+
+/*
+ * ULV voltage change delay time
+ * Used to be delay_vreg in N.I. split for S.I.
+ * Using N.I. delay_vreg value as default
+ * ReferenceClock = 2700
+ * VoltageResponseTime = 1000
+ * VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
+ */
+
+#define PPTONGA_ULVVOLTAGECHANGEDELAY_DFLT             1687
+
+#define PPTONGA_CGULVPARAMETER_DFLT                    0x00040035
+#define PPTONGA_CGULVCONTROL_DFLT                      0x00007450
+#define PPTONGA_TARGETACTIVITY_DFLT                     30  /*30%  */
+#define PPTONGA_MCLK_TARGETACTIVITY_DFLT                10  /*10%  */
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c
@@ -0,0 +1,6090 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include "linux/delay.h"
+#include "pp_acpi.h"
+#include "hwmgr.h"
+#include <atombios.h>
+#include "tonga_hwmgr.h"
+#include "pptable.h"
+#include "processpptables.h"
+#include "tonga_processpptables.h"
+#include "tonga_pptable.h"
+#include "pp_debug.h"
+#include "tonga_ppsmc.h"
+#include "cgs_common.h"
+#include "pppcielanes.h"
+#include "tonga_dyn_defaults.h"
+#include "smumgr.h"
+#include "tonga_smumgr.h"
+#include "tonga_clockpowergating.h"
+#include "tonga_thermal.h"
+
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
+
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+
+#include "cgs_linux.h"
+#include "eventmgr.h"
+#include "amd_pcie_helpers.h"
+
+#define MC_CG_ARB_FREQ_F0           0x0a
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0       0x05
+#define MC_CG_SEQ_DRAMCONF_S1       0x06
+#define MC_CG_SEQ_YCLK_SUSPEND      0x04
+#define MC_CG_SEQ_YCLK_RESUME       0x0a
+
+#define PCIE_BUS_CLK                10000
+#define TCLK                        (PCIE_BUS_CLK / 10)
+
+#define SMC_RAM_END 0x40000
+#define SMC_CG_IND_START            0xc0030000
+#define SMC_CG_IND_END              0xc0040000  /* First byte after SMC_CG_IND*/
+
+#define VOLTAGE_SCALE               4
+#define VOLTAGE_VID_OFFSET_SCALE1   625
+#define VOLTAGE_VID_OFFSET_SCALE2   100
+
+#define VDDC_VDDCI_DELTA            200
+#define VDDC_VDDGFX_DELTA           300
+
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+
+typedef uint32_t PECI_RegistryValue;
+
+/* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
+uint16_t PP_ClockStretcherLookupTable[2][4] = {
+	{600, 1050, 3, 0},
+	{600, 1050, 6, 1} };
+
+/* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
+uint32_t PP_ClockStretcherDDTTable[2][4][4] = {
+	{ {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
+	{ {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
+
+/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
+uint8_t PP_ClockStretchAmountConversion[2][6] = {
+	{0, 1, 3, 2, 4, 5},
+	{0, 2, 4, 5, 6, 5} };
+
+/* Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
+enum DPM_EVENT_SRC {
+	DPM_EVENT_SRC_ANALOG = 0,               /* Internal analog trip point */
+	DPM_EVENT_SRC_EXTERNAL = 1,             /* External (GPIO 17) signal */
+	DPM_EVENT_SRC_DIGITAL = 2,              /* Internal digital trip point (DIG_THERM_DPM) */
+	DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,   /* Internal analog or external */
+	DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4   /* Internal digital or external */
+};
+typedef enum DPM_EVENT_SRC DPM_EVENT_SRC;
+
+const unsigned long PhwTonga_Magic = (unsigned long)(PHM_VIslands_Magic);
+
+struct tonga_power_state *cast_phw_tonga_power_state(
+				  struct pp_hw_power_state *hw_ps)
+{
+	if (hw_ps == NULL)
+		return NULL;
+
+	PP_ASSERT_WITH_CODE((PhwTonga_Magic == hw_ps->magic),
+				"Invalid Powerstate Type!",
+				 return NULL);
+
+	return (struct tonga_power_state *)hw_ps;
+}
+
+const struct tonga_power_state *cast_const_phw_tonga_power_state(
+				 const struct pp_hw_power_state *hw_ps)
+{
+	if (hw_ps == NULL)
+		return NULL;
+
+	PP_ASSERT_WITH_CODE((PhwTonga_Magic == hw_ps->magic),
+				"Invalid Powerstate Type!",
+				 return NULL);
+
+	return (const struct tonga_power_state *)hw_ps;
+}
+
+int tonga_add_voltage(struct pp_hwmgr *hwmgr,
+	phm_ppt_v1_voltage_lookup_table *look_up_table,
+	phm_ppt_v1_voltage_lookup_record *record)
+{
+	uint32_t i;
+	PP_ASSERT_WITH_CODE((NULL != look_up_table),
+		"Lookup Table empty.", return -1;);
+	PP_ASSERT_WITH_CODE((0 != look_up_table->count),
+		"Lookup Table empty.", return -1;);
+	PP_ASSERT_WITH_CODE((SMU72_MAX_LEVELS_VDDGFX >= look_up_table->count),
+		"Lookup Table is full.", return -1;);
+
+	/* This is to avoid entering duplicate calculated records. */
+	for (i = 0; i < look_up_table->count; i++) {
+		if (look_up_table->entries[i].us_vdd == record->us_vdd) {
+			if (look_up_table->entries[i].us_calculated == 1)
+				return 0;
+			else
+				break;
+		}
+	}
+
+	look_up_table->entries[i].us_calculated = 1;
+	look_up_table->entries[i].us_vdd = record->us_vdd;
+	look_up_table->entries[i].us_cac_low = record->us_cac_low;
+	look_up_table->entries[i].us_cac_mid = record->us_cac_mid;
+	look_up_table->entries[i].us_cac_high = record->us_cac_high;
+	/* Only increment the count when we're appending, not replacing duplicate entry. */
+	if (i == look_up_table->count)
+		look_up_table->count++;
+
+	return 0;
+}
+
+int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
+{
+	PPSMC_Msg msg = has_display? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
+
+	return (smum_send_msg_to_smc(hwmgr->smumgr, msg) == 0) ?  0 : -1;
+}
+
+uint8_t tonga_get_voltage_id(pp_atomctrl_voltage_table *voltage_table,
+		uint32_t voltage)
+{
+	uint8_t count = (uint8_t) (voltage_table->count);
+	uint8_t i = 0;
+
+	PP_ASSERT_WITH_CODE((NULL != voltage_table),
+		"Voltage Table empty.", return 0;);
+	PP_ASSERT_WITH_CODE((0 != count),
+		"Voltage Table empty.", return 0;);
+
+	for (i = 0; i < count; i++) {
+		/* find first voltage bigger than requested */
+		if (voltage_table->entries[i].value >= voltage)
+			return i;
+	}
+
+	/* voltage is bigger than max voltage in the table */
+	return i - 1;
+}
+
+/**
+ * @brief PhwTonga_GetVoltageOrder
+ *  Returns index of requested voltage record in lookup(table)
+ * @param hwmgr - pointer to hardware manager
+ * @param lookupTable - lookup list to search in
+ * @param voltage - voltage to look for
+ * @return 0 on success
+ */
+uint8_t tonga_get_voltage_index(phm_ppt_v1_voltage_lookup_table *look_up_table,
+		uint16_t voltage)
+{
+	uint8_t count = (uint8_t) (look_up_table->count);
+	uint8_t i;
+
+	PP_ASSERT_WITH_CODE((NULL != look_up_table), "Lookup Table empty.", return 0;);
+	PP_ASSERT_WITH_CODE((0 != count), "Lookup Table empty.", return 0;);
+
+	for (i = 0; i < count; i++) {
+		/* find first voltage equal or bigger than requested */
+		if (look_up_table->entries[i].us_vdd >= voltage)
+			return i;
+	}
+
+	/* voltage is bigger than max voltage in the table */
+	return i-1;
+}
+
+bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+	/*
+	 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
+	 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
+	 * whereas voltage control is a fundemental change that will not be disabled
+	 */
+
+	return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+					FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) ? 1 : 0);
+}
+
+/**
+ * Re-generate the DPM level mask value
+ * @param    hwmgr      the address of the hardware manager
+ */
+static uint32_t tonga_get_dpm_level_enable_mask_value(
+			struct tonga_single_dpm_table * dpm_table)
+{
+	uint32_t i;
+	uint32_t mask_value = 0;
+
+	for (i = dpm_table->count; i > 0; i--) {
+		mask_value = mask_value << 1;
+
+		if (dpm_table->dpm_levels[i-1].enabled)
+			mask_value |= 0x1;
+		else
+			mask_value &= 0xFFFFFFFE;
+	}
+	return mask_value;
+}
+
+/**
+ * Retrieve DPM default values from registry (if available)
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ */
+void tonga_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	phw_tonga_ulv_parm *ulv = &(data->ulv);
+	uint32_t tmp;
+
+	ulv->ch_ulv_parameter = PPTONGA_CGULVPARAMETER_DFLT;
+	data->voting_rights_clients0 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0;
+	data->voting_rights_clients1 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1;
+	data->voting_rights_clients2 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2;
+	data->voting_rights_clients3 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3;
+	data->voting_rights_clients4 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4;
+	data->voting_rights_clients5 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5;
+	data->voting_rights_clients6 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6;
+	data->voting_rights_clients7 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7;
+
+	data->static_screen_threshold_unit = PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT;
+	data->static_screen_threshold = PPTONGA_STATICSCREENTHRESHOLD_DFLT;
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_ABM);
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_NonABMSupportInPPLib);
+
+	tmp = 0;
+	if (tmp == 0)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_DynamicACTiming);
+
+	tmp = 0;
+	if (0 != tmp)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_DisableMemoryTransition);
+
+	data->mclk_strobe_mode_threshold = 40000;
+	data->mclk_stutter_mode_threshold = 30000;
+	data->mclk_edc_enable_threshold = 40000;
+	data->mclk_edc_wr_enable_threshold = 40000;
+
+	tmp = 0;
+	if (tmp != 0)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_DisableMCLS);
+
+	data->pcie_gen_performance.max = PP_PCIEGen1;
+	data->pcie_gen_performance.min = PP_PCIEGen3;
+	data->pcie_gen_power_saving.max = PP_PCIEGen1;
+	data->pcie_gen_power_saving.min = PP_PCIEGen3;
+
+	data->pcie_lane_performance.max = 0;
+	data->pcie_lane_performance.min = 16;
+	data->pcie_lane_power_saving.max = 0;
+	data->pcie_lane_power_saving.min = 16;
+
+	tmp = 0;
+
+	if (tmp)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_SclkThrottleLowNotification);
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_DynamicUVDState);
+
+}
+
+int tonga_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	int result = 0;
+	uint32_t low_sclk_interrupt_threshold = 0;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_SclkThrottleLowNotification)
+		&& (hwmgr->gfx_arbiter.sclk_threshold != data->low_sclk_interrupt_threshold)) {
+		data->low_sclk_interrupt_threshold = hwmgr->gfx_arbiter.sclk_threshold;
+		low_sclk_interrupt_threshold = data->low_sclk_interrupt_threshold;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
+
+		result = tonga_copy_bytes_to_smc(
+				hwmgr->smumgr,
+				data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable,
+				LowSclkInterruptThreshold),
+				(uint8_t *)&low_sclk_interrupt_threshold,
+				sizeof(uint32_t),
+				data->sram_end
+				);
+	}
+
+	return result;
+}
+
+/**
+ * Find SCLK value that is associated with specified virtual_voltage_Id.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @param    virtual_voltage_Id  voltageId to look for.
+ * @param    sclk output value .
+ * @return   always 0 if success and 2 if association not found
+ */
+static int tonga_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
+	phm_ppt_v1_voltage_lookup_table *lookup_table,
+	uint16_t virtual_voltage_id, uint32_t *sclk)
+{
+	uint8_t entryId;
+	uint8_t voltageId;
+	struct phm_ppt_v1_information *pptable_info =
+					(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -1);
+
+	/* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
+	for (entryId = 0; entryId < pptable_info->vdd_dep_on_sclk->count; entryId++) {
+		voltageId = pptable_info->vdd_dep_on_sclk->entries[entryId].vddInd;
+		if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
+			break;
+	}
+
+	PP_ASSERT_WITH_CODE(entryId < pptable_info->vdd_dep_on_sclk->count,
+			"Can't find requested voltage id in vdd_dep_on_sclk table!",
+			return -1;
+			);
+
+	*sclk = pptable_info->vdd_dep_on_sclk->entries[entryId].clk;
+
+	return 0;
+}
+
+/**
+ * Get Leakage VDDC based on leakage ID.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   2 if vddgfx returned is greater than 2V or if BIOS
+ */
+int tonga_get_evv_voltage(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
+	uint16_t    virtual_voltage_id;
+	uint16_t    vddc = 0;
+	uint16_t    vddgfx = 0;
+	uint16_t    i, j;
+	uint32_t  sclk = 0;
+
+	/* retrieve voltage for leakage ID (0xff01 + i) */
+	for (i = 0; i < TONGA_MAX_LEAKAGE_COUNT; i++) {
+		virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
+
+		/* in split mode we should have only vddgfx EVV leakages */
+		if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+			if (0 == tonga_get_sclk_for_voltage_evv(hwmgr,
+						pptable_info->vddgfx_lookup_table, virtual_voltage_id, &sclk)) {
+				if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+							PHM_PlatformCaps_ClockStretcher)) {
+					for (j = 1; j < sclk_table->count; j++) {
+						if (sclk_table->entries[j].clk == sclk &&
+								sclk_table->entries[j].cks_enable == 0) {
+							sclk += 5000;
+							break;
+						}
+					}
+				}
+				PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
+						(hwmgr, VOLTAGE_TYPE_VDDGFX, sclk,
+						 virtual_voltage_id, &vddgfx),
+						"Error retrieving EVV voltage value!", continue);
+
+				/* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
+				PP_ASSERT_WITH_CODE((vddgfx < 2000 && vddgfx != 0), "Invalid VDDGFX value!", return -1);
+
+				/* the voltage should not be zero nor equal to leakage ID */
+				if (vddgfx != 0 && vddgfx != virtual_voltage_id) {
+					data->vddcgfx_leakage.actual_voltage[data->vddcgfx_leakage.count] = vddgfx;
+					data->vddcgfx_leakage.leakage_id[data->vddcgfx_leakage.count] = virtual_voltage_id;
+					data->vddcgfx_leakage.count++;
+				}
+			}
+		} else {
+			/*  in merged mode we have only vddc EVV leakages */
+			if (0 == tonga_get_sclk_for_voltage_evv(hwmgr,
+						pptable_info->vddc_lookup_table,
+						virtual_voltage_id, &sclk)) {
+				PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
+						(hwmgr, VOLTAGE_TYPE_VDDC, sclk,
+						 virtual_voltage_id, &vddc),
+						"Error retrieving EVV voltage value!", continue);
+
+				/* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
+				if (vddc > 2000)
+					printk(KERN_ERR "[ powerplay ] Invalid VDDC value! \n");
+
+				/* the voltage should not be zero nor equal to leakage ID */
+				if (vddc != 0 && vddc != virtual_voltage_id) {
+					data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = vddc;
+					data->vddc_leakage.leakage_id[data->vddc_leakage.count] = virtual_voltage_id;
+					data->vddc_leakage.count++;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+int tonga_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	/* enable SCLK dpm */
+	if (0 == data->sclk_dpm_key_disabled) {
+		PP_ASSERT_WITH_CODE(
+				(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+						   PPSMC_MSG_DPM_Enable)),
+				"Failed to enable SCLK DPM during DPM Start Function!",
+				return -1);
+	}
+
+	/* enable MCLK dpm */
+	if (0 == data->mclk_dpm_key_disabled) {
+		PP_ASSERT_WITH_CODE(
+				(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+					     PPSMC_MSG_MCLKDPM_Enable)),
+				"Failed to enable MCLK DPM during DPM Start Function!",
+				return -1);
+
+		PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1);
+
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixLCAC_MC0_CNTL, 0x05);/* CH0,1 read */
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixLCAC_MC1_CNTL, 0x05);/* CH2,3 read */
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixLCAC_CPL_CNTL, 0x100005);/*Read */
+
+		udelay(10);
+
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixLCAC_MC0_CNTL, 0x400005);/* CH0,1 write */
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixLCAC_MC1_CNTL, 0x400005);/* CH2,3 write */
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixLCAC_CPL_CNTL, 0x500005);/* write */
+
+	}
+
+	return 0;
+}
+
+int tonga_start_dpm(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	/* enable general power management */
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 1);
+	/* enable sclk deep sleep */
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 1);
+
+	/* prepare for PCIE DPM */
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start +
+			offsetof(SMU72_SoftRegisters, VoltageChangeTimeout), 0x1000);
+
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE, SWRST_COMMAND_1, RESETLC, 0x0);
+
+	PP_ASSERT_WITH_CODE(
+			(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+					PPSMC_MSG_Voltage_Cntl_Enable)),
+			"Failed to enable voltage DPM during DPM Start Function!",
+			return -1);
+
+	if (0 != tonga_enable_sclk_mclk_dpm(hwmgr)) {
+		PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1);
+	}
+
+	/* enable PCIE dpm */
+	if (0 == data->pcie_dpm_key_disabled) {
+		PP_ASSERT_WITH_CODE(
+				(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+						PPSMC_MSG_PCIeDPM_Enable)),
+				"Failed to enable pcie DPM during DPM Start Function!",
+				return -1
+				);
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_Falcon_QuickTransition)) {
+				   smum_send_msg_to_smc(hwmgr->smumgr,
+				    PPSMC_MSG_EnableACDCGPIOInterrupt);
+	}
+
+	return 0;
+}
+
+int tonga_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	/* disable SCLK dpm */
+	if (0 == data->sclk_dpm_key_disabled) {
+		/* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
+		PP_ASSERT_WITH_CODE(
+				(0 == tonga_is_dpm_running(hwmgr)),
+				"Trying to Disable SCLK DPM when DPM is disabled",
+				return -1
+				);
+
+		PP_ASSERT_WITH_CODE(
+				(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+						  PPSMC_MSG_DPM_Disable)),
+				"Failed to disable SCLK DPM during DPM stop Function!",
+				return -1);
+	}
+
+	/* disable MCLK dpm */
+	if (0 == data->mclk_dpm_key_disabled) {
+		/* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
+		PP_ASSERT_WITH_CODE(
+				(0 == tonga_is_dpm_running(hwmgr)),
+				"Trying to Disable MCLK DPM when DPM is disabled",
+				return -1
+				);
+
+		PP_ASSERT_WITH_CODE(
+				(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+					    PPSMC_MSG_MCLKDPM_Disable)),
+				"Failed to Disable MCLK DPM during DPM stop Function!",
+				return -1);
+	}
+
+	return 0;
+}
+
+int tonga_stop_dpm(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 0);
+	/* disable sclk deep sleep*/
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 0);
+
+	/* disable PCIE dpm */
+	if (0 == data->pcie_dpm_key_disabled) {
+		/* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
+		PP_ASSERT_WITH_CODE(
+				(0 == tonga_is_dpm_running(hwmgr)),
+				"Trying to Disable PCIE DPM when DPM is disabled",
+				return -1
+				);
+		PP_ASSERT_WITH_CODE(
+				(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+						PPSMC_MSG_PCIeDPM_Disable)),
+				"Failed to disable pcie DPM during DPM stop Function!",
+				return -1);
+	}
+
+	if (0 != tonga_disable_sclk_mclk_dpm(hwmgr))
+		PP_ASSERT_WITH_CODE(0, "Failed to disable Sclk DPM and Mclk DPM!", return -1);
+
+	/* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
+	PP_ASSERT_WITH_CODE(
+			(0 == tonga_is_dpm_running(hwmgr)),
+			"Trying to Disable Voltage CNTL when DPM is disabled",
+			return -1
+			);
+
+	PP_ASSERT_WITH_CODE(
+			(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+					PPSMC_MSG_Voltage_Cntl_Disable)),
+			"Failed to disable voltage DPM during DPM stop Function!",
+			return -1);
+
+	return 0;
+}
+
+int tonga_enable_sclk_control(struct pp_hwmgr *hwmgr)
+{
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, 0);
+
+	return 0;
+}
+
+/**
+ * Send a message to the SMC and return a parameter
+ *
+ * @param    hwmgr:  the address of the powerplay hardware manager.
+ * @param    msg: the message to send.
+ * @param    parameter: pointer to the received parameter
+ * @return   The response that came from the SMC.
+ */
+PPSMC_Result tonga_send_msg_to_smc_return_parameter(
+		struct pp_hwmgr *hwmgr,
+		PPSMC_Msg msg,
+		uint32_t *parameter)
+{
+	int result;
+
+	result = smum_send_msg_to_smc(hwmgr->smumgr, msg);
+
+	if ((0 == result) && parameter) {
+		*parameter = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+	}
+
+	return result;
+}
+
+/**
+ * force DPM power State
+ *
+ * @param    hwmgr:  the address of the powerplay hardware manager.
+ * @param    n     :  DPM level
+ * @return   The response that came from the SMC.
+ */
+int tonga_dpm_force_state(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	uint32_t level_mask = 1 << n;
+
+	/* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
+	PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
+			"Trying to force SCLK when DPM is disabled", return -1;);
+	if (0 == data->sclk_dpm_key_disabled)
+		return (0 == smum_send_msg_to_smc_with_parameter(
+							     hwmgr->smumgr,
+		     (PPSMC_Msg)(PPSMC_MSG_SCLKDPM_SetEnabledMask),
+						    level_mask) ? 0 : 1);
+
+	return 0;
+}
+
+/**
+ * force DPM power State
+ *
+ * @param    hwmgr:  the address of the powerplay hardware manager.
+ * @param    n     :  DPM level
+ * @return   The response that came from the SMC.
+ */
+int tonga_dpm_force_state_mclk(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	uint32_t level_mask = 1 << n;
+
+	/* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
+	PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
+			"Trying to Force MCLK when DPM is disabled", return -1;);
+	if (0 == data->mclk_dpm_key_disabled)
+		return (0 == smum_send_msg_to_smc_with_parameter(
+								hwmgr->smumgr,
+								(PPSMC_Msg)(PPSMC_MSG_MCLKDPM_SetEnabledMask),
+								level_mask) ? 0 : 1);
+
+	return 0;
+}
+
+/**
+ * force DPM power State
+ *
+ * @param    hwmgr:  the address of the powerplay hardware manager.
+ * @param    n     :  DPM level
+ * @return   The response that came from the SMC.
+ */
+int tonga_dpm_force_state_pcie(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	/* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
+	PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
+			"Trying to Force PCIE level when DPM is disabled", return -1;);
+	if (0 == data->pcie_dpm_key_disabled)
+		return (0 == smum_send_msg_to_smc_with_parameter(
+							     hwmgr->smumgr,
+			   (PPSMC_Msg)(PPSMC_MSG_PCIeDPM_ForceLevel),
+								n) ? 0 : 1);
+
+	return 0;
+}
+
+/**
+ * Set the initial state by calling SMC to switch to this state directly
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_set_boot_state(struct pp_hwmgr *hwmgr)
+{
+	/*
+	* SMC only stores one state that SW will ask to switch too,
+	* so we switch the the just uploaded one
+	*/
+	return (0 == tonga_disable_sclk_mclk_dpm(hwmgr)) ? 0 : 1;
+}
+
+/**
+ * Get the location of various tables inside the FW image.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct tonga_smumgr *tonga_smu = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+
+	uint32_t tmp;
+	int result;
+	bool error = 0;
+
+	result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+				SMU72_FIRMWARE_HEADER_LOCATION +
+				offsetof(SMU72_Firmware_Header, DpmTable),
+				&tmp, data->sram_end);
+
+	if (0 == result) {
+		data->dpm_table_start = tmp;
+	}
+
+	error |= (0 != result);
+
+	result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+				SMU72_FIRMWARE_HEADER_LOCATION +
+				offsetof(SMU72_Firmware_Header, SoftRegisters),
+				&tmp, data->sram_end);
+
+	if (0 == result) {
+		data->soft_regs_start = tmp;
+		tonga_smu->ulSoftRegsStart = tmp;
+	}
+
+	error |= (0 != result);
+
+
+	result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+				SMU72_FIRMWARE_HEADER_LOCATION +
+				offsetof(SMU72_Firmware_Header, mcRegisterTable),
+				&tmp, data->sram_end);
+
+	if (0 == result) {
+		data->mc_reg_table_start = tmp;
+	}
+
+	result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+				SMU72_FIRMWARE_HEADER_LOCATION +
+				offsetof(SMU72_Firmware_Header, FanTable),
+				&tmp, data->sram_end);
+
+	if (0 == result) {
+		data->fan_table_start = tmp;
+	}
+
+	error |= (0 != result);
+
+	result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+				SMU72_FIRMWARE_HEADER_LOCATION +
+				offsetof(SMU72_Firmware_Header, mcArbDramTimingTable),
+				&tmp, data->sram_end);
+
+	if (0 == result) {
+		data->arb_table_start = tmp;
+	}
+
+	error |= (0 != result);
+
+
+	result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+				SMU72_FIRMWARE_HEADER_LOCATION +
+				offsetof(SMU72_Firmware_Header, Version),
+				&tmp, data->sram_end);
+
+	if (0 == result) {
+		hwmgr->microcode_version_info.SMC = tmp;
+	}
+
+	error |= (0 != result);
+
+	return error ? 1 : 0;
+}
+
+/**
+ * Read clock related registers.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_read_clock_registers(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	data->clock_registers.vCG_SPLL_FUNC_CNTL         =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL);
+	data->clock_registers.vCG_SPLL_FUNC_CNTL_2       =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_2);
+	data->clock_registers.vCG_SPLL_FUNC_CNTL_3       =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_3);
+	data->clock_registers.vCG_SPLL_FUNC_CNTL_4       =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_4);
+	data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM   =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM);
+	data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
+		cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM_2);
+	data->clock_registers.vDLL_CNTL                  =
+		cgs_read_register(hwmgr->device, mmDLL_CNTL);
+	data->clock_registers.vMCLK_PWRMGT_CNTL          =
+		cgs_read_register(hwmgr->device, mmMCLK_PWRMGT_CNTL);
+	data->clock_registers.vMPLL_AD_FUNC_CNTL         =
+		cgs_read_register(hwmgr->device, mmMPLL_AD_FUNC_CNTL);
+	data->clock_registers.vMPLL_DQ_FUNC_CNTL         =
+		cgs_read_register(hwmgr->device, mmMPLL_DQ_FUNC_CNTL);
+	data->clock_registers.vMPLL_FUNC_CNTL            =
+		cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL);
+	data->clock_registers.vMPLL_FUNC_CNTL_1          =
+		cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_1);
+	data->clock_registers.vMPLL_FUNC_CNTL_2          =
+		cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_2);
+	data->clock_registers.vMPLL_SS1                  =
+		cgs_read_register(hwmgr->device, mmMPLL_SS1);
+	data->clock_registers.vMPLL_SS2                  =
+		cgs_read_register(hwmgr->device, mmMPLL_SS2);
+
+	return 0;
+}
+
+/**
+ * Find out if memory is GDDR5.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_get_memory_type(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	uint32_t temp;
+
+	temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
+
+	data->is_memory_GDDR5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
+			((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
+			 MC_SEQ_MISC0_GDDR5_SHIFT));
+
+	return 0;
+}
+
+/**
+ * Enables Dynamic Power Management by SMC
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
+{
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, STATIC_PM_EN, 1);
+
+	return 0;
+}
+
+/**
+ * Initialize PowerGating States for different engines
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_init_power_gate_state(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	data->uvd_power_gated = 0;
+	data->vce_power_gated = 0;
+	data->samu_power_gated = 0;
+	data->acp_power_gated = 0;
+	data->pg_acp_init = 1;
+
+	return 0;
+}
+
+/**
+ * Checks if DPM is enabled
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_check_for_dpm_running(struct pp_hwmgr *hwmgr)
+{
+	/*
+	 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
+	 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
+	 * whereas voltage control is a fundemental change that will not be disabled
+	 */
+	return (0 == tonga_is_dpm_running(hwmgr) ? 0 : 1);
+}
+
+/**
+ * Checks if DPM is stopped
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_check_for_dpm_stopped(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	if (0 != tonga_is_dpm_running(hwmgr)) {
+		/* If HW Virtualization is enabled, dpm_table_start will not have a valid value */
+		if (!data->dpm_table_start) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Remove repeated voltage values and create table with unique values.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @param    voltage_table  the pointer to changing voltage table
+ * @return    1 in success
+ */
+
+static int tonga_trim_voltage_table(struct pp_hwmgr *hwmgr,
+			pp_atomctrl_voltage_table *voltage_table)
+{
+	uint32_t table_size, i, j;
+	uint16_t vvalue;
+	bool bVoltageFound = 0;
+	pp_atomctrl_voltage_table *table;
+
+	PP_ASSERT_WITH_CODE((NULL != voltage_table), "Voltage Table empty.", return -1;);
+	table_size = sizeof(pp_atomctrl_voltage_table);
+	table = kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == table)
+		return -ENOMEM;
+
+	memset(table, 0x00, table_size);
+	table->mask_low = voltage_table->mask_low;
+	table->phase_delay = voltage_table->phase_delay;
+
+	for (i = 0; i < voltage_table->count; i++) {
+		vvalue = voltage_table->entries[i].value;
+		bVoltageFound = 0;
+
+		for (j = 0; j < table->count; j++) {
+			if (vvalue == table->entries[j].value) {
+				bVoltageFound = 1;
+				break;
+			}
+		}
+
+		if (!bVoltageFound) {
+			table->entries[table->count].value = vvalue;
+			table->entries[table->count].smio_low =
+				voltage_table->entries[i].smio_low;
+			table->count++;
+		}
+	}
+
+	memcpy(table, voltage_table, sizeof(pp_atomctrl_voltage_table));
+
+	kfree(table);
+
+	return 0;
+}
+
+static int tonga_get_svi2_vdd_ci_voltage_table(
+		struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_clock_voltage_dependency_table *voltage_dependency_table)
+{
+	uint32_t i;
+	int result;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	pp_atomctrl_voltage_table *vddci_voltage_table = &(data->vddci_voltage_table);
+
+	PP_ASSERT_WITH_CODE((0 != voltage_dependency_table->count),
+			"Voltage Dependency Table empty.", return -1;);
+
+	vddci_voltage_table->mask_low = 0;
+	vddci_voltage_table->phase_delay = 0;
+	vddci_voltage_table->count = voltage_dependency_table->count;
+
+	for (i = 0; i < voltage_dependency_table->count; i++) {
+		vddci_voltage_table->entries[i].value =
+			voltage_dependency_table->entries[i].vddci;
+		vddci_voltage_table->entries[i].smio_low = 0;
+	}
+
+	result = tonga_trim_voltage_table(hwmgr, vddci_voltage_table);
+	PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to trim VDDCI table.", return result;);
+
+	return 0;
+}
+
+
+
+static int tonga_get_svi2_vdd_voltage_table(
+		struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_voltage_lookup_table *look_up_table,
+		pp_atomctrl_voltage_table *voltage_table)
+{
+	uint8_t i = 0;
+
+	PP_ASSERT_WITH_CODE((0 != look_up_table->count),
+			"Voltage Lookup Table empty.", return -1;);
+
+	voltage_table->mask_low = 0;
+	voltage_table->phase_delay = 0;
+
+	voltage_table->count = look_up_table->count;
+
+	for (i = 0; i < voltage_table->count; i++) {
+		voltage_table->entries[i].value = look_up_table->entries[i].us_vdd;
+		voltage_table->entries[i].smio_low = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * -------------------------------------------------------- Voltage Tables --------------------------------------------------------------------------
+ * If the voltage table would be bigger than what will fit into the state table on the SMC keep only the higher entries.
+ */
+
+static void tonga_trim_voltage_table_to_fit_state_table(
+		struct pp_hwmgr *hwmgr,
+		uint32_t max_voltage_steps,
+		pp_atomctrl_voltage_table *voltage_table)
+{
+	unsigned int i, diff;
+
+	if (voltage_table->count <= max_voltage_steps) {
+		return;
+	}
+
+	diff = voltage_table->count - max_voltage_steps;
+
+	for (i = 0; i < max_voltage_steps; i++) {
+		voltage_table->entries[i] = voltage_table->entries[i + diff];
+	}
+
+	voltage_table->count = max_voltage_steps;
+
+	return;
+}
+
+/**
+ * Create Voltage Tables.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_construct_voltage_tables(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	int result;
+
+	/* MVDD has only GPIO voltage control */
+	if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+		result = atomctrl_get_voltage_table_v3(hwmgr,
+					VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT, &(data->mvdd_voltage_table));
+		PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to retrieve MVDD table.", return result;);
+	}
+
+	if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
+		/* GPIO voltage */
+		result = atomctrl_get_voltage_table_v3(hwmgr,
+					VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT, &(data->vddci_voltage_table));
+		PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to retrieve VDDCI table.", return result;);
+	} else if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
+		/* SVI2 voltage */
+		result = tonga_get_svi2_vdd_ci_voltage_table(hwmgr,
+					pptable_info->vdd_dep_on_mclk);
+		PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to retrieve SVI2 VDDCI table from dependancy table.", return result;);
+	}
+
+	if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+		/* VDDGFX has only SVI2 voltage control */
+		result = tonga_get_svi2_vdd_voltage_table(hwmgr,
+					pptable_info->vddgfx_lookup_table, &(data->vddgfx_voltage_table));
+		PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to retrieve SVI2 VDDGFX table from lookup table.", return result;);
+	}
+
+	if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+		/* VDDC has only SVI2 voltage control */
+		result = tonga_get_svi2_vdd_voltage_table(hwmgr,
+					pptable_info->vddc_lookup_table, &(data->vddc_voltage_table));
+		PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to retrieve SVI2 VDDC table from lookup table.", return result;);
+	}
+
+	PP_ASSERT_WITH_CODE(
+			(data->vddc_voltage_table.count <= (SMU72_MAX_LEVELS_VDDC)),
+			"Too many voltage values for VDDC. Trimming to fit state table.",
+			tonga_trim_voltage_table_to_fit_state_table(hwmgr,
+			SMU72_MAX_LEVELS_VDDC, &(data->vddc_voltage_table));
+			);
+
+	PP_ASSERT_WITH_CODE(
+			(data->vddgfx_voltage_table.count <= (SMU72_MAX_LEVELS_VDDGFX)),
+			"Too many voltage values for VDDGFX. Trimming to fit state table.",
+			tonga_trim_voltage_table_to_fit_state_table(hwmgr,
+			SMU72_MAX_LEVELS_VDDGFX, &(data->vddgfx_voltage_table));
+			);
+
+	PP_ASSERT_WITH_CODE(
+			(data->vddci_voltage_table.count <= (SMU72_MAX_LEVELS_VDDCI)),
+			"Too many voltage values for VDDCI. Trimming to fit state table.",
+			tonga_trim_voltage_table_to_fit_state_table(hwmgr,
+			SMU72_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table));
+			);
+
+	PP_ASSERT_WITH_CODE(
+			(data->mvdd_voltage_table.count <= (SMU72_MAX_LEVELS_MVDD)),
+			"Too many voltage values for MVDD. Trimming to fit state table.",
+			tonga_trim_voltage_table_to_fit_state_table(hwmgr,
+			SMU72_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table));
+			);
+
+	return 0;
+}
+
+/**
+ * Vddc table preparation for SMC.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+static int tonga_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
+			SMU72_Discrete_DpmTable *table)
+{
+	unsigned int count;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+		table->VddcLevelCount = data->vddc_voltage_table.count;
+		for (count = 0; count < table->VddcLevelCount; count++) {
+			table->VddcTable[count] =
+				PP_HOST_TO_SMC_US(data->vddc_voltage_table.entries[count].value * VOLTAGE_SCALE);
+		}
+		CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
+	}
+	return 0;
+}
+
+/**
+ * VddGfx table preparation for SMC.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr *hwmgr,
+			SMU72_Discrete_DpmTable *table)
+{
+	unsigned int count;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+		table->VddGfxLevelCount = data->vddgfx_voltage_table.count;
+		for (count = 0; count < data->vddgfx_voltage_table.count; count++) {
+			table->VddGfxTable[count] =
+				PP_HOST_TO_SMC_US(data->vddgfx_voltage_table.entries[count].value * VOLTAGE_SCALE);
+		}
+		CONVERT_FROM_HOST_TO_SMC_UL(table->VddGfxLevelCount);
+	}
+	return 0;
+}
+
+/**
+ * Vddci table preparation for SMC.
+ *
+ * @param    *hwmgr The address of the hardware manager.
+ * @param    *table The SMC DPM table structure to be populated.
+ * @return   0
+ */
+static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
+			SMU72_Discrete_DpmTable *table)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	uint32_t count;
+
+	table->VddciLevelCount = data->vddci_voltage_table.count;
+	for (count = 0; count < table->VddciLevelCount; count++) {
+		if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
+			table->VddciTable[count] =
+				PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+		} else if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
+			table->SmioTable1.Pattern[count].Voltage =
+				PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+			/* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
+			table->SmioTable1.Pattern[count].Smio =
+				(uint8_t) count;
+			table->Smio[count] |=
+				data->vddci_voltage_table.entries[count].smio_low;
+			table->VddciTable[count] =
+				PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+		}
+	}
+
+	table->SmioMask1 = data->vddci_voltage_table.mask_low;
+	CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
+
+	return 0;
+}
+
+/**
+ * Mvdd table preparation for SMC.
+ *
+ * @param    *hwmgr The address of the hardware manager.
+ * @param    *table The SMC DPM table structure to be populated.
+ * @return   0
+ */
+static int tonga_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
+			SMU72_Discrete_DpmTable *table)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	uint32_t count;
+
+	if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+		table->MvddLevelCount = data->mvdd_voltage_table.count;
+		for (count = 0; count < table->MvddLevelCount; count++) {
+			table->SmioTable2.Pattern[count].Voltage =
+				PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
+			/* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
+			table->SmioTable2.Pattern[count].Smio =
+				(uint8_t) count;
+			table->Smio[count] |=
+				data->mvdd_voltage_table.entries[count].smio_low;
+		}
+		table->SmioMask2 = data->vddci_voltage_table.mask_low;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
+	}
+
+	return 0;
+}
+
+/**
+ * Convert a voltage value in mv unit to VID number required by SMU firmware
+ */
+static uint8_t convert_to_vid(uint16_t vddc)
+{
+	return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
+}
+
+
+/**
+ * Preparation of vddc and vddgfx CAC tables for SMC.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr,
+			SMU72_Discrete_DpmTable *table)
+{
+	uint32_t count;
+	uint8_t index;
+	int result = 0;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table = pptable_info->vddgfx_lookup_table;
+	struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table = pptable_info->vddc_lookup_table;
+
+	/* pTables is already swapped, so in order to use the value from it, we need to swap it back. */
+	uint32_t vddcLevelCount = PP_SMC_TO_HOST_UL(table->VddcLevelCount);
+	uint32_t vddgfxLevelCount = PP_SMC_TO_HOST_UL(table->VddGfxLevelCount);
+
+	for (count = 0; count < vddcLevelCount; count++) {
+		/* We are populating vddc CAC data to BapmVddc table in split and merged mode */
+		index = tonga_get_voltage_index(vddc_lookup_table,
+			data->vddc_voltage_table.entries[count].value);
+		table->BapmVddcVidLoSidd[count] =
+			convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
+		table->BapmVddcVidHiSidd[count] =
+			convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
+		table->BapmVddcVidHiSidd2[count] =
+			convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
+	}
+
+	if ((data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2)) {
+		/* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
+		for (count = 0; count < vddgfxLevelCount; count++) {
+			index = tonga_get_voltage_index(vddgfx_lookup_table,
+				data->vddgfx_voltage_table.entries[count].value);
+			table->BapmVddGfxVidLoSidd[count] =
+				convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_low);
+			table->BapmVddGfxVidHiSidd[count] =
+				convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_mid);
+			table->BapmVddGfxVidHiSidd2[count] =
+				convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_high);
+		}
+	} else {
+		for (count = 0; count < vddcLevelCount; count++) {
+			index = tonga_get_voltage_index(vddc_lookup_table,
+				data->vddc_voltage_table.entries[count].value);
+			table->BapmVddGfxVidLoSidd[count] =
+				convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
+			table->BapmVddGfxVidHiSidd[count] =
+				convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
+			table->BapmVddGfxVidHiSidd2[count] =
+				convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
+		}
+	}
+
+	return result;
+}
+
+
+/**
+ * Preparation of voltage tables for SMC.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+
+int tonga_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
+	SMU72_Discrete_DpmTable *table)
+{
+	int result;
+
+	result = tonga_populate_smc_vddc_table(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"can not populate VDDC voltage table to SMC", return -1);
+
+	result = tonga_populate_smc_vdd_ci_table(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"can not populate VDDCI voltage table to SMC", return -1);
+
+	result = tonga_populate_smc_vdd_gfx_table(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"can not populate VDDGFX voltage table to SMC", return -1);
+
+	result = tonga_populate_smc_mvdd_table(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"can not populate MVDD voltage table to SMC", return -1);
+
+	result = tonga_populate_cac_tables(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"can not populate CAC voltage tables to SMC", return -1);
+
+	return 0;
+}
+
+/**
+ * Populates the SMC VRConfig field in DPM table.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
+			SMU72_Discrete_DpmTable *table)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	uint16_t config;
+
+	if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+		/*  Splitted mode */
+		config = VR_SVI2_PLANE_1;
+		table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
+
+		if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+			config = VR_SVI2_PLANE_2;
+			table->VRConfig |= config;
+		} else {
+			printk(KERN_ERR "[ powerplay ] VDDC and VDDGFX should be both on SVI2 control in splitted mode! \n");
+		}
+	} else {
+		/* Merged mode  */
+		config = VR_MERGED_WITH_VDDC;
+		table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
+
+		/* Set Vddc Voltage Controller  */
+		if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+			config = VR_SVI2_PLANE_1;
+			table->VRConfig |= config;
+		} else {
+			printk(KERN_ERR "[ powerplay ] VDDC should be on SVI2 control in merged mode! \n");
+		}
+	}
+
+	/* Set Vddci Voltage Controller  */
+	if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
+		config = VR_SVI2_PLANE_2;  /* only in merged mode */
+		table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
+	} else if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
+		config = VR_SMIO_PATTERN_1;
+		table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
+	}
+
+	/* Set Mvdd Voltage Controller */
+	if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+		config = VR_SMIO_PATTERN_2;
+		table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
+	}
+
+	return 0;
+}
+
+static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr *hwmgr,
+	phm_ppt_v1_clock_voltage_dependency_table *allowed_clock_voltage_table,
+	uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
+{
+	uint32_t i = 0;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	/* clock - voltage dependency table is empty table */
+	if (allowed_clock_voltage_table->count == 0)
+		return -1;
+
+	for (i = 0; i < allowed_clock_voltage_table->count; i++) {
+		/* find first sclk bigger than request */
+		if (allowed_clock_voltage_table->entries[i].clk >= clock) {
+			voltage->VddGfx = tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+								allowed_clock_voltage_table->entries[i].vddgfx);
+
+			voltage->Vddc = tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+								allowed_clock_voltage_table->entries[i].vddc);
+
+			if (allowed_clock_voltage_table->entries[i].vddci) {
+				voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
+									allowed_clock_voltage_table->entries[i].vddci);
+			} else {
+				voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
+									allowed_clock_voltage_table->entries[i].vddc - data->vddc_vddci_delta);
+			}
+
+			if (allowed_clock_voltage_table->entries[i].mvdd) {
+				*mvdd = (uint32_t) allowed_clock_voltage_table->entries[i].mvdd;
+			}
+
+			voltage->Phases = 1;
+			return 0;
+		}
+	}
+
+	/* sclk is bigger than max sclk in the dependence table */
+	voltage->VddGfx = tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+		allowed_clock_voltage_table->entries[i-1].vddgfx);
+	voltage->Vddc = tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+		allowed_clock_voltage_table->entries[i-1].vddc);
+
+	if (allowed_clock_voltage_table->entries[i-1].vddci) {
+		voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
+			allowed_clock_voltage_table->entries[i-1].vddci);
+	}
+	if (allowed_clock_voltage_table->entries[i-1].mvdd) {
+		*mvdd = (uint32_t) allowed_clock_voltage_table->entries[i-1].mvdd;
+	}
+
+	return 0;
+}
+
+/**
+ * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_reset_to_default(struct pp_hwmgr *hwmgr)
+{
+	return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults) == 0) ? 0 : 1;
+}
+
+int tonga_populate_memory_timing_parameters(
+		struct pp_hwmgr *hwmgr,
+		uint32_t engine_clock,
+		uint32_t memory_clock,
+		struct SMU72_Discrete_MCArbDramTimingTableEntry *arb_regs
+		)
+{
+	uint32_t dramTiming;
+	uint32_t dramTiming2;
+	uint32_t burstTime;
+	int result;
+
+	result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
+				engine_clock, memory_clock);
+
+	PP_ASSERT_WITH_CODE(result == 0,
+		"Error calling VBIOS to set DRAM_TIMING.", return result);
+
+	dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+	dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+	burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+
+	arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
+	arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
+	arb_regs->McArbBurstTime = (uint8_t)burstTime;
+
+	return 0;
+}
+
+/**
+ * Setup parameters for the MC ARB.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ * This function is to be called from the SetPowerState table.
+ */
+int tonga_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	int result = 0;
+	SMU72_Discrete_MCArbDramTimingTable  arb_regs;
+	uint32_t i, j;
+
+	memset(&arb_regs, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable));
+
+	for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
+		for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
+			result = tonga_populate_memory_timing_parameters
+				(hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
+				 data->dpm_table.mclk_table.dpm_levels[j].value,
+				 &arb_regs.entries[i][j]);
+
+			if (0 != result) {
+				break;
+			}
+		}
+	}
+
+	if (0 == result) {
+		result = tonga_copy_bytes_to_smc(
+				hwmgr->smumgr,
+				data->arb_table_start,
+				(uint8_t *)&arb_regs,
+				sizeof(SMU72_Discrete_MCArbDramTimingTable),
+				data->sram_end
+				);
+	}
+
+	return result;
+}
+
+static int tonga_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU72_Discrete_DpmTable *table)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct tonga_dpm_table *dpm_table = &data->dpm_table;
+	uint32_t i;
+
+	/* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
+	for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
+		table->LinkLevel[i].PcieGenSpeed  =
+			(uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
+		table->LinkLevel[i].PcieLaneCount =
+			(uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
+		table->LinkLevel[i].EnabledForActivity =
+			1;
+		table->LinkLevel[i].SPC =
+			(uint8_t)(data->pcie_spc_cap & 0xff);
+		table->LinkLevel[i].DownThreshold =
+			PP_HOST_TO_SMC_UL(5);
+		table->LinkLevel[i].UpThreshold =
+			PP_HOST_TO_SMC_UL(30);
+	}
+
+	data->smc_state_table.LinkLevelCount =
+		(uint8_t)dpm_table->pcie_speed_table.count;
+	data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+		tonga_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+
+	return 0;
+}
+
+static int tonga_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
+					SMU72_Discrete_DpmTable *table)
+{
+	int result = 0;
+
+	uint8_t count;
+	pp_atomctrl_clock_dividers_vi dividers;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+	table->UvdLevelCount = (uint8_t) (mm_table->count);
+	table->UvdBootLevel = 0;
+
+	for (count = 0; count < table->UvdLevelCount; count++) {
+		table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
+		table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
+		table->UvdLevel[count].MinVoltage.Vddc =
+			tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+						mm_table->entries[count].vddc);
+		table->UvdLevel[count].MinVoltage.VddGfx =
+			(data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
+			tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+						mm_table->entries[count].vddgfx) : 0;
+		table->UvdLevel[count].MinVoltage.Vddci =
+			tonga_get_voltage_id(&data->vddci_voltage_table,
+					     mm_table->entries[count].vddc - data->vddc_vddci_delta);
+		table->UvdLevel[count].MinVoltage.Phases = 1;
+
+		/* retrieve divider value for VBIOS */
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+							  table->UvdLevel[count].VclkFrequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+				    "can not find divide id for Vclk clock", return result);
+
+		table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
+
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+							  table->UvdLevel[count].DclkFrequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+				    "can not find divide id for Dclk clock", return result);
+
+		table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
+		CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
+		//CONVERT_FROM_HOST_TO_SMC_UL((uint32_t)table->UvdLevel[count].MinVoltage);
+	}
+
+	return result;
+
+}
+
+static int tonga_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
+		SMU72_Discrete_DpmTable *table)
+{
+	int result = 0;
+
+	uint8_t count;
+	pp_atomctrl_clock_dividers_vi dividers;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+	table->VceLevelCount = (uint8_t) (mm_table->count);
+	table->VceBootLevel = 0;
+
+	for (count = 0; count < table->VceLevelCount; count++) {
+		table->VceLevel[count].Frequency =
+			mm_table->entries[count].eclk;
+		table->VceLevel[count].MinVoltage.Vddc =
+			tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+				mm_table->entries[count].vddc);
+		table->VceLevel[count].MinVoltage.VddGfx =
+			(data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
+			tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+				mm_table->entries[count].vddgfx) : 0;
+		table->VceLevel[count].MinVoltage.Vddci =
+			tonga_get_voltage_id(&data->vddci_voltage_table,
+				mm_table->entries[count].vddc - data->vddc_vddci_delta);
+		table->VceLevel[count].MinVoltage.Phases = 1;
+
+		/* retrieve divider value for VBIOS */
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+					table->VceLevel[count].Frequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"can not find divide id for VCE engine clock", return result);
+
+		table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
+	}
+
+	return result;
+}
+
+static int tonga_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
+		SMU72_Discrete_DpmTable *table)
+{
+	int result = 0;
+	uint8_t count;
+	pp_atomctrl_clock_dividers_vi dividers;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+	table->AcpLevelCount = (uint8_t) (mm_table->count);
+	table->AcpBootLevel = 0;
+
+	for (count = 0; count < table->AcpLevelCount; count++) {
+		table->AcpLevel[count].Frequency =
+			pptable_info->mm_dep_table->entries[count].aclk;
+		table->AcpLevel[count].MinVoltage.Vddc =
+			tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+			mm_table->entries[count].vddc);
+		table->AcpLevel[count].MinVoltage.VddGfx =
+			(data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
+			tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+				mm_table->entries[count].vddgfx) : 0;
+		table->AcpLevel[count].MinVoltage.Vddci =
+			tonga_get_voltage_id(&data->vddci_voltage_table,
+				mm_table->entries[count].vddc - data->vddc_vddci_delta);
+		table->AcpLevel[count].MinVoltage.Phases = 1;
+
+		/* retrieve divider value for VBIOS */
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+			table->AcpLevel[count].Frequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+			"can not find divide id for engine clock", return result);
+
+		table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
+	}
+
+	return result;
+}
+
+static int tonga_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
+	SMU72_Discrete_DpmTable *table)
+{
+	int result = 0;
+	uint8_t count;
+	pp_atomctrl_clock_dividers_vi dividers;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+	table->SamuBootLevel = 0;
+	table->SamuLevelCount = (uint8_t) (mm_table->count);
+
+	for (count = 0; count < table->SamuLevelCount; count++) {
+		/* not sure whether we need evclk or not */
+		table->SamuLevel[count].Frequency =
+			pptable_info->mm_dep_table->entries[count].samclock;
+		table->SamuLevel[count].MinVoltage.Vddc =
+			tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+				mm_table->entries[count].vddc);
+		table->SamuLevel[count].MinVoltage.VddGfx =
+			(data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
+			tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+				mm_table->entries[count].vddgfx) : 0;
+		table->SamuLevel[count].MinVoltage.Vddci =
+			tonga_get_voltage_id(&data->vddci_voltage_table,
+				mm_table->entries[count].vddc - data->vddc_vddci_delta);
+		table->SamuLevel[count].MinVoltage.Phases = 1;
+
+		/* retrieve divider value for VBIOS */
+		result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+					table->SamuLevel[count].Frequency, &dividers);
+		PP_ASSERT_WITH_CODE((0 == result),
+			"can not find divide id for samu clock", return result);
+
+		table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+		CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
+	}
+
+	return result;
+}
+
+/**
+ * Populates the SMC MCLK structure using the provided memory clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    memory_clock the memory clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+static int tonga_calculate_mclk_params(
+		struct pp_hwmgr *hwmgr,
+		uint32_t memory_clock,
+		SMU72_Discrete_MemoryLevel *mclk,
+		bool strobe_mode,
+		bool dllStateOn
+		)
+{
+	const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	uint32_t  dll_cntl = data->clock_registers.vDLL_CNTL;
+	uint32_t  mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
+	uint32_t  mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
+	uint32_t  mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
+	uint32_t  mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
+	uint32_t  mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
+	uint32_t  mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
+	uint32_t  mpll_ss1 = data->clock_registers.vMPLL_SS1;
+	uint32_t  mpll_ss2 = data->clock_registers.vMPLL_SS2;
+
+	pp_atomctrl_memory_clock_param mpll_param;
+	int result;
+
+	result = atomctrl_get_memory_pll_dividers_si(hwmgr,
+				memory_clock, &mpll_param, strobe_mode);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Error retrieving Memory Clock Parameters from VBIOS.", return result);
+
+	/* MPLL_FUNC_CNTL setup*/
+	mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl);
+
+	/* MPLL_FUNC_CNTL_1 setup*/
+	mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+							MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf);
+	mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+							MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac);
+	mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+							MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode);
+
+	/* MPLL_AD_FUNC_CNTL setup*/
+	mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
+							MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
+
+	if (data->is_memory_GDDR5) {
+		/* MPLL_DQ_FUNC_CNTL setup*/
+		mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
+								MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel);
+		mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
+								MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
+		/*
+		 ************************************
+		 Fref = Reference Frequency
+		 NF = Feedback divider ratio
+		 NR = Reference divider ratio
+		 Fnom = Nominal VCO output frequency = Fref * NF / NR
+		 Fs = Spreading Rate
+		 D = Percentage down-spread / 2
+		 Fint = Reference input frequency to PFD = Fref / NR
+		 NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
+		 CLKS = NS - 1 = ISS_STEP_NUM[11:0]
+		 NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
+		 CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
+		 *************************************
+		 */
+		pp_atomctrl_internal_ss_info ss_info;
+		uint32_t freq_nom;
+		uint32_t tmp;
+		uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
+
+		/* for GDDR5 for all modes and DDR3 */
+		if (1 == mpll_param.qdr)
+			freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
+		else
+			freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
+
+		/* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
+		tmp = (freq_nom / reference_clock);
+		tmp = tmp * tmp;
+
+		if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
+			/* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
+			/* ss.Info.speed_spectrum_rate -- in unit of khz */
+			/* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
+			/*     = reference_clock * 5 / speed_spectrum_rate */
+			uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
+
+			/* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
+			/*     = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
+			uint32_t clkv =
+				(uint32_t)((((131 * ss_info.speed_spectrum_percentage *
+							ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
+
+			mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
+			mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
+		}
+	}
+
+	/* MCLK_PWRMGT_CNTL setup */
+	mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+		MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
+	mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+		MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
+	mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+		MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
+
+
+	/* Save the result data to outpupt memory level structure */
+	mclk->MclkFrequency   = memory_clock;
+	mclk->MpllFuncCntl    = mpll_func_cntl;
+	mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
+	mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
+	mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
+	mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
+	mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
+	mclk->DllCntl         = dll_cntl;
+	mclk->MpllSs1         = mpll_ss1;
+	mclk->MpllSs2         = mpll_ss2;
+
+	return 0;
+}
+
+static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock,
+		bool strobe_mode)
+{
+	uint8_t mc_para_index;
+
+	if (strobe_mode) {
+		if (memory_clock < 12500) {
+			mc_para_index = 0x00;
+		} else if (memory_clock > 47500) {
+			mc_para_index = 0x0f;
+		} else {
+			mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
+		}
+	} else {
+		if (memory_clock < 65000) {
+			mc_para_index = 0x00;
+		} else if (memory_clock > 135000) {
+			mc_para_index = 0x0f;
+		} else {
+			mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
+		}
+	}
+
+	return mc_para_index;
+}
+
+static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
+{
+	uint8_t mc_para_index;
+
+	if (memory_clock < 10000) {
+		mc_para_index = 0;
+	} else if (memory_clock >= 80000) {
+		mc_para_index = 0x0f;
+	} else {
+		mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
+	}
+
+	return mc_para_index;
+}
+
+static int tonga_populate_single_memory_level(
+		struct pp_hwmgr *hwmgr,
+		uint32_t memory_clock,
+		SMU72_Discrete_MemoryLevel *memory_level
+		)
+{
+	uint32_t minMvdd = 0;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	int result = 0;
+	bool dllStateOn;
+	struct cgs_display_info info = {0};
+
+
+	if (NULL != pptable_info->vdd_dep_on_mclk) {
+		result = tonga_get_dependecy_volt_by_clk(hwmgr,
+			pptable_info->vdd_dep_on_mclk, memory_clock, &memory_level->MinVoltage, &minMvdd);
+		PP_ASSERT_WITH_CODE((0 == result),
+			"can not find MinVddc voltage value from memory VDDC voltage dependency table", return result);
+	}
+
+	if (data->mvdd_control == TONGA_VOLTAGE_CONTROL_NONE) {
+		memory_level->MinMvdd = data->vbios_boot_state.mvdd_bootup_value;
+	} else {
+		memory_level->MinMvdd = minMvdd;
+	}
+	memory_level->EnabledForThrottle = 1;
+	memory_level->EnabledForActivity = 0;
+	memory_level->UpHyst = 0;
+	memory_level->DownHyst = 100;
+	memory_level->VoltageDownHyst = 0;
+
+	/* Indicates maximum activity level for this performance level.*/
+	memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
+	memory_level->StutterEnable = 0;
+	memory_level->StrobeEnable = 0;
+	memory_level->EdcReadEnable = 0;
+	memory_level->EdcWriteEnable = 0;
+	memory_level->RttEnable = 0;
+
+	/* default set to low watermark. Highest level will be set to high later.*/
+	memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+	data->display_timing.num_existing_displays = info.display_count;
+
+	if ((data->mclk_stutter_mode_threshold != 0) &&
+			(memory_clock <= data->mclk_stutter_mode_threshold) &&
+			(data->is_uvd_enabled == 0)
+#if defined(LINUX)
+			&& (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE) & 0x1)
+			&& (data->display_timing.num_existing_displays <= 2)
+			&& (data->display_timing.num_existing_displays != 0)
+#endif
+	)
+		memory_level->StutterEnable = 1;
+
+	/* decide strobe mode*/
+	memory_level->StrobeEnable = (data->mclk_strobe_mode_threshold != 0) &&
+		(memory_clock <= data->mclk_strobe_mode_threshold);
+
+	/* decide EDC mode and memory clock ratio*/
+	if (data->is_memory_GDDR5) {
+		memory_level->StrobeRatio = tonga_get_mclk_frequency_ratio(memory_clock,
+					memory_level->StrobeEnable);
+
+		if ((data->mclk_edc_enable_threshold != 0) &&
+				(memory_clock > data->mclk_edc_enable_threshold)) {
+			memory_level->EdcReadEnable = 1;
+		}
+
+		if ((data->mclk_edc_wr_enable_threshold != 0) &&
+				(memory_clock > data->mclk_edc_wr_enable_threshold)) {
+			memory_level->EdcWriteEnable = 1;
+		}
+
+		if (memory_level->StrobeEnable) {
+			if (tonga_get_mclk_frequency_ratio(memory_clock, 1) >=
+					((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf)) {
+				dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
+			} else {
+				dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
+			}
+
+		} else {
+			dllStateOn = data->dll_defaule_on;
+		}
+	} else {
+		memory_level->StrobeRatio =
+			tonga_get_ddr3_mclk_frequency_ratio(memory_clock);
+		dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
+	}
+
+	result = tonga_calculate_mclk_params(hwmgr,
+		memory_clock, memory_level, memory_level->StrobeEnable, dllStateOn);
+
+	if (0 == result) {
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinMvdd);
+		/* MCLK frequency in units of 10KHz*/
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
+		/* Indicates maximum activity level for this performance level.*/
+		CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
+		CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
+	}
+
+	return result;
+}
+
+/**
+ * Populates the SMC MVDD structure using the provided memory clock.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
+ * @param    voltage     the SMC VOLTAGE structure to be populated
+ */
+int tonga_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk, SMIO_Pattern *smio_pattern)
+{
+	const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	uint32_t i = 0;
+
+	if (TONGA_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
+		/* find mvdd value which clock is more than request */
+		for (i = 0; i < pptable_info->vdd_dep_on_mclk->count; i++) {
+			if (mclk <= pptable_info->vdd_dep_on_mclk->entries[i].clk) {
+				/* Always round to higher voltage. */
+				smio_pattern->Voltage = data->mvdd_voltage_table.entries[i].value;
+				break;
+			}
+		}
+
+		PP_ASSERT_WITH_CODE(i < pptable_info->vdd_dep_on_mclk->count,
+			"MVDD Voltage is outside the supported range.", return -1);
+
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int tonga_populate_smv_acpi_level(struct pp_hwmgr *hwmgr,
+	SMU72_Discrete_DpmTable *table)
+{
+	int result = 0;
+	const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	pp_atomctrl_clock_dividers_vi dividers;
+	SMIO_Pattern voltage_level;
+	uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+	uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
+	uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
+	uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
+
+	/* The ACPI state should not do DPM on DC (or ever).*/
+	table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+	table->ACPILevel.MinVoltage = data->smc_state_table.GraphicsLevel[0].MinVoltage;
+
+	/* assign zero for now*/
+	table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
+
+	/* get the engine clock dividers for this clock value*/
+	result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
+		table->ACPILevel.SclkFrequency,  &dividers);
+
+	PP_ASSERT_WITH_CODE(result == 0,
+		"Error retrieving Engine Clock dividers from VBIOS.", return result);
+
+	/* divider ID for required SCLK*/
+	table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
+	table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+	table->ACPILevel.DeepSleepDivId = 0;
+
+	spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
+							CG_SPLL_FUNC_CNTL,   SPLL_PWRON,     0);
+	spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
+							CG_SPLL_FUNC_CNTL,   SPLL_RESET,     1);
+	spll_func_cntl_2    = PHM_SET_FIELD(spll_func_cntl_2,
+							CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL,   4);
+
+	table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
+	table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
+	table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+	table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+	table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+	table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+	table->ACPILevel.CcPwrDynRm = 0;
+	table->ACPILevel.CcPwrDynRm1 = 0;
+
+
+	/* For various features to be enabled/disabled while this level is active.*/
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
+	/* SCLK frequency in units of 10KHz*/
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
+
+	/* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
+	table->MemoryACPILevel.MinVoltage = data->smc_state_table.MemoryLevel[0].MinVoltage;
+
+	/*  CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
+
+	if (0 == tonga_populate_mvdd_value(hwmgr, 0, &voltage_level))
+		table->MemoryACPILevel.MinMvdd =
+			PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
+	else
+		table->MemoryACPILevel.MinMvdd = 0;
+
+	/* Force reset on DLL*/
+	mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+		MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
+	mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+		MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
+
+	/* Disable DLL in ACPIState*/
+	mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+		MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
+	mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+		MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
+
+	/* Enable DLL bypass signal*/
+	dll_cntl            = PHM_SET_FIELD(dll_cntl,
+		DLL_CNTL, MRDCK0_BYPASS, 0);
+	dll_cntl            = PHM_SET_FIELD(dll_cntl,
+		DLL_CNTL, MRDCK1_BYPASS, 0);
+
+	table->MemoryACPILevel.DllCntl            =
+		PP_HOST_TO_SMC_UL(dll_cntl);
+	table->MemoryACPILevel.MclkPwrmgtCntl     =
+		PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
+	table->MemoryACPILevel.MpllAdFuncCntl     =
+		PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
+	table->MemoryACPILevel.MpllDqFuncCntl     =
+		PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
+	table->MemoryACPILevel.MpllFuncCntl       =
+		PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
+	table->MemoryACPILevel.MpllFuncCntl_1     =
+		PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
+	table->MemoryACPILevel.MpllFuncCntl_2     =
+		PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
+	table->MemoryACPILevel.MpllSs1            =
+		PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
+	table->MemoryACPILevel.MpllSs2            =
+		PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
+
+	table->MemoryACPILevel.EnabledForThrottle = 0;
+	table->MemoryACPILevel.EnabledForActivity = 0;
+	table->MemoryACPILevel.UpHyst = 0;
+	table->MemoryACPILevel.DownHyst = 100;
+	table->MemoryACPILevel.VoltageDownHyst = 0;
+	/* Indicates maximum activity level for this performance level.*/
+	table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
+
+	table->MemoryACPILevel.StutterEnable = 0;
+	table->MemoryACPILevel.StrobeEnable = 0;
+	table->MemoryACPILevel.EdcReadEnable = 0;
+	table->MemoryACPILevel.EdcWriteEnable = 0;
+	table->MemoryACPILevel.RttEnable = 0;
+
+	return result;
+}
+
+static int tonga_find_boot_level(struct tonga_single_dpm_table *table, uint32_t value, uint32_t *boot_level)
+{
+	int result = 0;
+	uint32_t i;
+
+	for (i = 0; i < table->count; i++) {
+		if (value == table->dpm_levels[i].value) {
+			*boot_level = i;
+			result = 0;
+		}
+	}
+	return result;
+}
+
+static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
+			SMU72_Discrete_DpmTable *table)
+{
+	int result = 0;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	table->GraphicsBootLevel  = 0;        /* 0 == DPM[0] (low), etc. */
+	table->MemoryBootLevel    = 0;        /* 0 == DPM[0] (low), etc. */
+
+	/* find boot level from dpm table*/
+	result = tonga_find_boot_level(&(data->dpm_table.sclk_table),
+	data->vbios_boot_state.sclk_bootup_value,
+	(uint32_t *)&(data->smc_state_table.GraphicsBootLevel));
+
+	if (0 != result) {
+		data->smc_state_table.GraphicsBootLevel = 0;
+		printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
+			in dependency table. Using Graphics DPM level 0!");
+		result = 0;
+	}
+
+	result = tonga_find_boot_level(&(data->dpm_table.mclk_table),
+		data->vbios_boot_state.mclk_bootup_value,
+		(uint32_t *)&(data->smc_state_table.MemoryBootLevel));
+
+	if (0 != result) {
+		data->smc_state_table.MemoryBootLevel = 0;
+		printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
+			in dependency table. Using Memory DPM level 0!");
+		result = 0;
+	}
+
+	table->BootVoltage.Vddc =
+		tonga_get_voltage_id(&(data->vddc_voltage_table),
+			data->vbios_boot_state.vddc_bootup_value);
+	table->BootVoltage.VddGfx =
+		tonga_get_voltage_id(&(data->vddgfx_voltage_table),
+			data->vbios_boot_state.vddgfx_bootup_value);
+	table->BootVoltage.Vddci =
+		tonga_get_voltage_id(&(data->vddci_voltage_table),
+			data->vbios_boot_state.vddci_bootup_value);
+	table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
+
+	CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
+
+	return result;
+}
+
+
+/**
+ * Calculates the SCLK dividers using the provided engine clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    engine_clock the engine clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr,
+		uint32_t engine_clock, SMU72_Discrete_GraphicsLevel *sclk)
+{
+	const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	pp_atomctrl_clock_dividers_vi dividers;
+	uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+	uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+	uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+	uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+	uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+	uint32_t    reference_clock;
+	uint32_t reference_divider;
+	uint32_t fbdiv;
+	int result;
+
+	/* get the engine clock dividers for this clock value*/
+	result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock,  &dividers);
+
+	PP_ASSERT_WITH_CODE(result == 0,
+		"Error retrieving Engine Clock dividers from VBIOS.", return result);
+
+	/* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
+	reference_clock = atomctrl_get_reference_clock(hwmgr);
+
+	reference_divider = 1 + dividers.uc_pll_ref_div;
+
+	/* low 14 bits is fraction and high 12 bits is divider*/
+	fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
+
+	/* SPLL_FUNC_CNTL setup*/
+	spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+		CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
+	spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+		CG_SPLL_FUNC_CNTL, SPLL_PDIV_A,  dividers.uc_pll_post_div);
+
+	/* SPLL_FUNC_CNTL_3 setup*/
+	spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
+		CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
+
+	/* set to use fractional accumulation*/
+	spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
+		CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
+		pp_atomctrl_internal_ss_info ss_info;
+
+		uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
+		if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
+			/*
+			* ss_info.speed_spectrum_percentage -- in unit of 0.01%
+			* ss_info.speed_spectrum_rate -- in unit of khz
+			*/
+			/* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
+			uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
+
+			/* clkv = 2 * D * fbdiv / NS */
+			uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
+
+			cg_spll_spread_spectrum =
+				PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
+			cg_spll_spread_spectrum =
+				PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
+			cg_spll_spread_spectrum_2 =
+				PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
+		}
+	}
+
+	sclk->SclkFrequency        = engine_clock;
+	sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
+	sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
+	sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
+	sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
+	sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
+
+	return 0;
+}
+
+/**
+ * Populates single SMC SCLK structure using the provided engine clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    engine_clock the engine clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t engine_clock, uint16_t sclk_activity_level_threshold, SMU72_Discrete_GraphicsLevel *graphic_level)
+{
+	int result;
+	uint32_t threshold;
+	uint32_t mvdd;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
+
+
+	/* populate graphics levels*/
+	result = tonga_get_dependecy_volt_by_clk(hwmgr,
+		pptable_info->vdd_dep_on_sclk, engine_clock,
+		&graphic_level->MinVoltage, &mvdd);
+	PP_ASSERT_WITH_CODE((0 == result),
+		"can not find VDDC voltage value for VDDC	\
+		engine clock dependency table", return result);
+
+	/* SCLK frequency in units of 10KHz*/
+	graphic_level->SclkFrequency = engine_clock;
+
+	/* Indicates maximum activity level for this performance level. 50% for now*/
+	graphic_level->ActivityLevel = sclk_activity_level_threshold;
+
+	graphic_level->CcPwrDynRm = 0;
+	graphic_level->CcPwrDynRm1 = 0;
+	/* this level can be used if activity is high enough.*/
+	graphic_level->EnabledForActivity = 0;
+	/* this level can be used for throttling.*/
+	graphic_level->EnabledForThrottle = 1;
+	graphic_level->UpHyst = 0;
+	graphic_level->DownHyst = 0;
+	graphic_level->VoltageDownHyst = 0;
+	graphic_level->PowerThrottle = 0;
+
+	threshold = engine_clock * data->fast_watemark_threshold / 100;
+/*
+	*get the DAL clock. do it in funture.
+	PECI_GetMinClockSettings(hwmgr->peci, &minClocks);
+	data->display_timing.min_clock_insr = minClocks.engineClockInSR;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
+	{
+		graphic_level->DeepSleepDivId = PhwTonga_GetSleepDividerIdFromClock(hwmgr, engine_clock, minClocks.engineClockInSR);
+	}
+*/
+
+	/* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
+	graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+	if (0 == result) {
+		/* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
+		/* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
+		CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
+		CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
+		CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
+		CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
+		CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
+		CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
+		CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
+		CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
+	}
+
+	return result;
+}
+
+/**
+ * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
+ *
+ * @param    hwmgr      the address of the hardware manager
+ */
+static int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	struct tonga_dpm_table *dpm_table = &data->dpm_table;
+	phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
+	uint8_t pcie_entry_count = (uint8_t) data->dpm_table.pcie_speed_table.count;
+	int result = 0;
+	uint32_t level_array_adress = data->dpm_table_start +
+		offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
+	uint32_t level_array_size = sizeof(SMU72_Discrete_GraphicsLevel) *
+		SMU72_MAX_LEVELS_GRAPHICS;   /* 64 -> long; 32 -> int*/
+	SMU72_Discrete_GraphicsLevel *levels = data->smc_state_table.GraphicsLevel;
+	uint32_t i, maxEntry;
+	uint8_t highest_pcie_level_enabled = 0, lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0, count = 0;
+	PECI_RegistryValue reg_value;
+	memset(levels, 0x00, level_array_size);
+
+	for (i = 0; i < dpm_table->sclk_table.count; i++) {
+		result = tonga_populate_single_graphic_level(hwmgr,
+					dpm_table->sclk_table.dpm_levels[i].value,
+					(uint16_t)data->activity_target[i],
+					&(data->smc_state_table.GraphicsLevel[i]));
+
+		if (0 != result)
+			return result;
+
+		/* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
+		if (i > 1)
+			data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
+
+		if (0 == i) {
+			reg_value = 0;
+			if (reg_value != 0)
+				data->smc_state_table.GraphicsLevel[0].UpHyst = (uint8_t)reg_value;
+		}
+
+		if (1 == i) {
+			reg_value = 0;
+			if (reg_value != 0)
+				data->smc_state_table.GraphicsLevel[1].UpHyst = (uint8_t)reg_value;
+		}
+	}
+
+	/* Only enable level 0 for now. */
+	data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
+
+	/* set highest level watermark to high */
+	if (dpm_table->sclk_table.count > 1)
+		data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
+			PPSMC_DISPLAY_WATERMARK_HIGH;
+
+	data->smc_state_table.GraphicsDpmLevelCount =
+		(uint8_t)dpm_table->sclk_table.count;
+	data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+		tonga_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+	if (pcie_table != NULL) {
+		PP_ASSERT_WITH_CODE((pcie_entry_count >= 1),
+			"There must be 1 or more PCIE levels defined in PPTable.", return -1);
+		maxEntry = pcie_entry_count - 1; /* for indexing, we need to decrement by 1.*/
+		for (i = 0; i < dpm_table->sclk_table.count; i++) {
+			data->smc_state_table.GraphicsLevel[i].pcieDpmLevel =
+				(uint8_t) ((i < maxEntry) ? i : maxEntry);
+		}
+	} else {
+		if (0 == data->dpm_level_enable_mask.pcie_dpm_enable_mask)
+			printk(KERN_ERR "[ powerplay ] Pcie Dpm Enablemask is 0!");
+
+		while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+				((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+					(1<<(highest_pcie_level_enabled+1))) != 0)) {
+			highest_pcie_level_enabled++;
+		}
+
+		while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+				((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+					(1<<lowest_pcie_level_enabled)) == 0)) {
+			lowest_pcie_level_enabled++;
+		}
+
+		while ((count < highest_pcie_level_enabled) &&
+				((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+					(1<<(lowest_pcie_level_enabled+1+count))) == 0)) {
+			count++;
+		}
+		mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
+			(lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
+
+
+		/* set pcieDpmLevel to highest_pcie_level_enabled*/
+		for (i = 2; i < dpm_table->sclk_table.count; i++) {
+			data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
+		}
+
+		/* set pcieDpmLevel to lowest_pcie_level_enabled*/
+		data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
+
+		/* set pcieDpmLevel to mid_pcie_level_enabled*/
+		data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
+	}
+	/* level count will send to smc once at init smc table and never change*/
+	result = tonga_copy_bytes_to_smc(hwmgr->smumgr, level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end);
+
+	if (0 != result)
+		return result;
+
+	return 0;
+}
+
+/**
+ * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
+ *
+ * @param    hwmgr      the address of the hardware manager
+ */
+
+static int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct tonga_dpm_table *dpm_table = &data->dpm_table;
+	int result;
+	/* populate MCLK dpm table to SMU7 */
+	uint32_t level_array_adress = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
+	uint32_t level_array_size = sizeof(SMU72_Discrete_MemoryLevel) * SMU72_MAX_LEVELS_MEMORY;
+	SMU72_Discrete_MemoryLevel *levels = data->smc_state_table.MemoryLevel;
+	uint32_t i;
+
+	memset(levels, 0x00, level_array_size);
+
+	for (i = 0; i < dpm_table->mclk_table.count; i++) {
+		PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
+			"can not populate memory level as memory clock is zero", return -1);
+		result = tonga_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
+			&(data->smc_state_table.MemoryLevel[i]));
+		if (0 != result) {
+			return result;
+		}
+	}
+
+	/* Only enable level 0 for now.*/
+	data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
+
+	/*
+	* in order to prevent MC activity from stutter mode to push DPM up.
+	* the UVD change complements this by putting the MCLK in a higher state
+	* by default such that we are not effected by up threshold or and MCLK DPM latency.
+	*/
+	data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
+	CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.MemoryLevel[0].ActivityLevel);
+
+	data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
+	data->dpm_level_enable_mask.mclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+	/* set highest level watermark to high*/
+	data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
+
+	/* level count will send to smc once at init smc table and never change*/
+	result = tonga_copy_bytes_to_smc(hwmgr->smumgr,
+		level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end);
+
+	if (0 != result) {
+		return result;
+	}
+
+	return 0;
+}
+
+struct TONGA_DLL_SPEED_SETTING {
+	uint16_t            Min;                          /* Minimum Data Rate*/
+	uint16_t            Max;                          /* Maximum Data Rate*/
+	uint32_t 			dll_speed;                     /* The desired DLL_SPEED setting*/
+};
+
+static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
+{
+	return 0;
+}
+
+/* ---------------------------------------- ULV related functions ----------------------------------------------------*/
+
+
+static int tonga_reset_single_dpm_table(
+	struct pp_hwmgr *hwmgr,
+	struct tonga_single_dpm_table *dpm_table,
+	uint32_t count)
+{
+	uint32_t i;
+	if (!(count <= MAX_REGULAR_DPM_NUMBER))
+		printk(KERN_ERR "[ powerplay ] Fatal error, can not set up single DPM \
+			table entries to exceed max number! \n");
+
+	dpm_table->count = count;
+	for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++) {
+		dpm_table->dpm_levels[i].enabled = 0;
+	}
+
+	return 0;
+}
+
+static void tonga_setup_pcie_table_entry(
+	struct tonga_single_dpm_table *dpm_table,
+	uint32_t index, uint32_t pcie_gen,
+	uint32_t pcie_lanes)
+{
+	dpm_table->dpm_levels[index].value = pcie_gen;
+	dpm_table->dpm_levels[index].param1 = pcie_lanes;
+	dpm_table->dpm_levels[index].enabled = 1;
+}
+
+static int tonga_setup_default_pcie_tables(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
+	uint32_t i, maxEntry;
+
+	if (data->use_pcie_performance_levels && !data->use_pcie_power_saving_levels) {
+		data->pcie_gen_power_saving = data->pcie_gen_performance;
+		data->pcie_lane_power_saving = data->pcie_lane_performance;
+	} else if (!data->use_pcie_performance_levels && data->use_pcie_power_saving_levels) {
+		data->pcie_gen_performance = data->pcie_gen_power_saving;
+		data->pcie_lane_performance = data->pcie_lane_power_saving;
+	}
+
+	tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.pcie_speed_table, SMU72_MAX_LEVELS_LINK);
+
+	if (pcie_table != NULL) {
+		/*
+		* maxEntry is used to make sure we reserve one PCIE level for boot level (fix for A+A PSPP issue).
+		* If PCIE table from PPTable have ULV entry + 8 entries, then ignore the last entry.
+		*/
+		maxEntry = (SMU72_MAX_LEVELS_LINK < pcie_table->count) ?
+						SMU72_MAX_LEVELS_LINK : pcie_table->count;
+		for (i = 1; i < maxEntry; i++) {
+			tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i-1,
+				get_pcie_gen_support(data->pcie_gen_cap, pcie_table->entries[i].gen_speed),
+				get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+		}
+		data->dpm_table.pcie_speed_table.count = maxEntry - 1;
+	} else {
+		/* Hardcode Pcie Table */
+		tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
+			get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
+			get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+		tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
+			get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
+			get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+		tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
+			get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
+			get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+		tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
+			get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
+			get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+		tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
+			get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
+			get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+		tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
+			get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
+			get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+		data->dpm_table.pcie_speed_table.count = 6;
+	}
+	/* Populate last level for boot PCIE level, but do not increment count. */
+	tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
+		data->dpm_table.pcie_speed_table.count,
+		get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
+		get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+
+	return 0;
+
+}
+
+/*
+ * This function is to initalize all DPM state tables for SMU7 based on the dependency table.
+ * Dynamic state patching function will then trim these state tables to the allowed range based
+ * on the power policy or external client requests, such as UVD request, etc.
+ */
+static int tonga_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	uint32_t i;
+
+	phm_ppt_v1_clock_voltage_dependency_table *allowed_vdd_sclk_table =
+		pptable_info->vdd_dep_on_sclk;
+	phm_ppt_v1_clock_voltage_dependency_table *allowed_vdd_mclk_table =
+		pptable_info->vdd_dep_on_mclk;
+
+	PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
+		"SCLK dependency table is missing. This table is mandatory", return -1);
+	PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table->count >= 1,
+		"SCLK dependency table has to have is missing. This table is mandatory", return -1);
+
+	PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
+		"MCLK dependency table is missing. This table is mandatory", return -1);
+	PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table->count >= 1,
+		"VMCLK dependency table has to have is missing. This table is mandatory", return -1);
+
+	/* clear the state table to reset everything to default */
+	memset(&(data->dpm_table), 0x00, sizeof(data->dpm_table));
+	tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.sclk_table, SMU72_MAX_LEVELS_GRAPHICS);
+	tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.mclk_table, SMU72_MAX_LEVELS_MEMORY);
+	/* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.VddcTable, SMU72_MAX_LEVELS_VDDC); */
+	/* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_gfx_table, SMU72_MAX_LEVELS_VDDGFX);*/
+	/* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_ci_table, SMU72_MAX_LEVELS_VDDCI);*/
+	/* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.mvdd_table, SMU72_MAX_LEVELS_MVDD);*/
+
+	PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
+		"SCLK dependency table is missing. This table is mandatory", return -1);
+	/* Initialize Sclk DPM table based on allow Sclk values*/
+	data->dpm_table.sclk_table.count = 0;
+
+	for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+		if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
+				allowed_vdd_sclk_table->entries[i].clk) {
+			data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
+				allowed_vdd_sclk_table->entries[i].clk;
+			data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; to do */
+			data->dpm_table.sclk_table.count++;
+		}
+	}
+
+	PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
+		"MCLK dependency table is missing. This table is mandatory", return -1);
+	/* Initialize Mclk DPM table based on allow Mclk values */
+	data->dpm_table.mclk_table.count = 0;
+	for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
+		if (i == 0 || data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count-1].value !=
+			allowed_vdd_mclk_table->entries[i].clk) {
+			data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
+				allowed_vdd_mclk_table->entries[i].clk;
+			data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; */
+			data->dpm_table.mclk_table.count++;
+		}
+	}
+
+	/* Initialize Vddc DPM table based on allow Vddc values.  And populate corresponding std values. */
+	for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+		data->dpm_table.vddc_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].vddc;
+		/* tonga_hwmgr->dpm_table.VddcTable.dpm_levels[i].param1 = stdVoltageTable->entries[i].Leakage; */
+		/* param1 is for corresponding std voltage */
+		data->dpm_table.vddc_table.dpm_levels[i].enabled = 1;
+	}
+	data->dpm_table.vddc_table.count = allowed_vdd_sclk_table->count;
+
+	if (NULL != allowed_vdd_mclk_table) {
+		/* Initialize Vddci DPM table based on allow Mclk values */
+		for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
+			data->dpm_table.vdd_ci_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].vddci;
+			data->dpm_table.vdd_ci_table.dpm_levels[i].enabled = 1;
+			data->dpm_table.mvdd_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].mvdd;
+			data->dpm_table.mvdd_table.dpm_levels[i].enabled = 1;
+		}
+		data->dpm_table.vdd_ci_table.count = allowed_vdd_mclk_table->count;
+		data->dpm_table.mvdd_table.count = allowed_vdd_mclk_table->count;
+	}
+
+	/* setup PCIE gen speed levels*/
+	tonga_setup_default_pcie_tables(hwmgr);
+
+	/* save a copy of the default DPM table*/
+	memcpy(&(data->golden_dpm_table), &(data->dpm_table), sizeof(struct tonga_dpm_table));
+
+	return 0;
+}
+
+int tonga_populate_smc_initial_state(struct pp_hwmgr *hwmgr,
+		const struct tonga_power_state *bootState)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	uint8_t count, level;
+
+	count = (uint8_t) (pptable_info->vdd_dep_on_sclk->count);
+	for (level = 0; level < count; level++) {
+		if (pptable_info->vdd_dep_on_sclk->entries[level].clk >=
+			bootState->performance_levels[0].engine_clock) {
+			data->smc_state_table.GraphicsBootLevel = level;
+			break;
+		}
+	}
+
+	count = (uint8_t) (pptable_info->vdd_dep_on_mclk->count);
+	for (level = 0; level < count; level++) {
+		if (pptable_info->vdd_dep_on_mclk->entries[level].clk >=
+			bootState->performance_levels[0].memory_clock) {
+			data->smc_state_table.MemoryBootLevel = level;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Initializes the SMC table and uploads it
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @param    pInput  the pointer to input data (PowerState)
+ * @return   always 0
+ */
+int tonga_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+	int result;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	SMU72_Discrete_DpmTable  *table = &(data->smc_state_table);
+	const phw_tonga_ulv_parm *ulv = &(data->ulv);
+	uint8_t i;
+	PECI_RegistryValue reg_value;
+	pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
+
+	result = tonga_setup_default_dpm_tables(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to setup default DPM tables!", return result;);
+	memset(&(data->smc_state_table), 0x00, sizeof(data->smc_state_table));
+	if (TONGA_VOLTAGE_CONTROL_NONE != data->voltage_control) {
+		tonga_populate_smc_voltage_tables(hwmgr, table);
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_AutomaticDCTransition)) {
+		table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_StepVddc)) {
+		table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+	}
+
+	if (data->is_memory_GDDR5) {
+		table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+	}
+
+	i = PHM_READ_FIELD(hwmgr->device, CC_MC_MAX_CHANNEL, NOOFCHAN);
+
+	if (i == 1 || i == 0) {
+		table->SystemFlags |= PPSMC_SYSTEMFLAG_12CHANNEL;
+	}
+
+	if (ulv->ulv_supported && pptable_info->us_ulv_voltage_offset) {
+		PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to initialize ULV state!", return result;);
+
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCG_ULV_PARAMETER, ulv->ch_ulv_parameter);
+	}
+
+	result = tonga_populate_smc_link_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize Link Level!", return result;);
+
+	result = tonga_populate_all_graphic_levels(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize Graphics Level!", return result;);
+
+	result = tonga_populate_all_memory_levels(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize Memory Level!", return result;);
+
+	result = tonga_populate_smv_acpi_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize ACPI Level!", return result;);
+
+	result = tonga_populate_smc_vce_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize VCE Level!", return result;);
+
+	result = tonga_populate_smc_acp_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize ACP Level!", return result;);
+
+	result = tonga_populate_smc_samu_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize SAMU Level!", return result;);
+
+	/* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
+	/* need to populate the  ARB settings for the initial state. */
+	result = tonga_program_memory_timing_parameters(hwmgr);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to Write ARB settings for the initial state.", return result;);
+
+	result = tonga_populate_smc_uvd_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize UVD Level!", return result;);
+
+	result = tonga_populate_smc_boot_level(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize Boot Level!", return result;);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ClockStretcher)) {
+		result = tonga_populate_clock_stretcher_data_table(hwmgr);
+		PP_ASSERT_WITH_CODE(0 == result,
+			"Failed to populate Clock Stretcher Data Table!", return result;);
+	}
+	table->GraphicsVoltageChangeEnable  = 1;
+	table->GraphicsThermThrottleEnable  = 1;
+	table->GraphicsInterval = 1;
+	table->VoltageInterval  = 1;
+	table->ThermalInterval  = 1;
+	table->TemperatureLimitHigh =
+		pptable_info->cac_dtp_table->usTargetOperatingTemp *
+		TONGA_Q88_FORMAT_CONVERSION_UNIT;
+	table->TemperatureLimitLow =
+		(pptable_info->cac_dtp_table->usTargetOperatingTemp - 1) *
+		TONGA_Q88_FORMAT_CONVERSION_UNIT;
+	table->MemoryVoltageChangeEnable  = 1;
+	table->MemoryInterval  = 1;
+	table->VoltageResponseTime  = 0;
+	table->PhaseResponseTime  = 0;
+	table->MemoryThermThrottleEnable  = 1;
+
+	/*
+	* Cail reads current link status and reports it as cap (we cannot change this due to some previous issues we had)
+	* SMC drops the link status to lowest level after enabling DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
+	* but this time Cail reads current link status which was set to low by SMC and reports it as cap to powerplay
+	* To avoid it, we set PCIeBootLinkLevel to highest dpm level
+	*/
+	PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
+			"There must be 1 or more PCIE levels defined in PPTable.",
+			return -1);
+
+	table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
+
+	table->PCIeGenInterval  = 1;
+
+	result = tonga_populate_vr_config(hwmgr, table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to populate VRConfig setting!", return result);
+
+	table->ThermGpio  = 17;
+	table->SclkStepSize = 0x4000;
+
+	reg_value = 0;
+	if ((0 == reg_value) &&
+		(0 == atomctrl_get_pp_assign_pin(hwmgr,
+			VDDC_VRHOT_GPIO_PINID, &gpio_pin_assignment))) {
+		table->VRHotGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_RegulatorHot);
+	} else {
+		table->VRHotGpio = TONGA_UNUSED_GPIO_PIN;
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_RegulatorHot);
+	}
+
+	/* ACDC Switch GPIO */
+	reg_value = 0;
+	if ((0 == reg_value) &&
+		(0 == atomctrl_get_pp_assign_pin(hwmgr,
+			PP_AC_DC_SWITCH_GPIO_PINID, &gpio_pin_assignment))) {
+		table->AcDcGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_AutomaticDCTransition);
+	} else {
+		table->AcDcGpio = TONGA_UNUSED_GPIO_PIN;
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_AutomaticDCTransition);
+	}
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_Falcon_QuickTransition);
+
+	reg_value = 0;
+	if (1 == reg_value) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_AutomaticDCTransition);
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_Falcon_QuickTransition);
+	}
+
+	reg_value = 0;
+	if ((0 == reg_value) &&
+		(0 == atomctrl_get_pp_assign_pin(hwmgr,
+			THERMAL_INT_OUTPUT_GPIO_PINID, &gpio_pin_assignment))) {
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ThermalOutGPIO);
+
+		table->ThermOutGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+
+		table->ThermOutPolarity =
+			(0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
+			(1 << gpio_pin_assignment.uc_gpio_pin_bit_shift))) ? 1:0;
+
+		table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
+
+		/* if required, combine VRHot/PCC with thermal out GPIO*/
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_RegulatorHot) &&
+			phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_CombinePCCWithThermalSignal)){
+			table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
+		}
+	} else {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ThermalOutGPIO);
+
+		table->ThermOutGpio = 17;
+		table->ThermOutPolarity = 1;
+		table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
+	}
+
+	for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++) {
+		table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
+	}
+	CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
+	CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
+	CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
+	CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
+	CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
+	CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
+
+	/* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
+	result = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->dpm_table_start +
+										offsetof(SMU72_Discrete_DpmTable, SystemFlags),
+										(uint8_t *)&(table->SystemFlags),
+										sizeof(SMU72_Discrete_DpmTable)-3 * sizeof(SMU72_PIDController),
+										data->sram_end);
+
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to upload dpm data to SMC memory!", return result;);
+
+	return result;
+}
+
+/* Look up the voltaged based on DAL's requested level. and then send the requested VDDC voltage to SMC*/
+static void tonga_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
+{
+	return;
+}
+
+int tonga_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
+{
+	PPSMC_Result result;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	/* Apply minimum voltage based on DAL's request level */
+	tonga_apply_dal_minimum_voltage_request(hwmgr);
+
+	if (0 == data->sclk_dpm_key_disabled) {
+		/* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
+		if (0 != tonga_is_dpm_running(hwmgr))
+			printk(KERN_ERR "[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
+
+		if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+			result = smum_send_msg_to_smc_with_parameter(
+								hwmgr->smumgr,
+				(PPSMC_Msg)PPSMC_MSG_SCLKDPM_SetEnabledMask,
+				data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+			PP_ASSERT_WITH_CODE((0 == result),
+				"Set Sclk Dpm enable Mask failed", return -1);
+		}
+	}
+
+	if (0 == data->mclk_dpm_key_disabled) {
+		/* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
+		if (0 != tonga_is_dpm_running(hwmgr))
+			printk(KERN_ERR "[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
+
+		if (0 != data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+			result = smum_send_msg_to_smc_with_parameter(
+								hwmgr->smumgr,
+				(PPSMC_Msg)PPSMC_MSG_MCLKDPM_SetEnabledMask,
+				data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+			PP_ASSERT_WITH_CODE((0 == result),
+				"Set Mclk Dpm enable Mask failed", return -1);
+		}
+	}
+
+	return 0;
+}
+
+
+int tonga_force_dpm_highest(struct pp_hwmgr *hwmgr)
+{
+	uint32_t level, tmp;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	if (0 == data->pcie_dpm_key_disabled) {
+		/* PCIE */
+		if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) {
+			level = 0;
+			tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
+			while (tmp >>= 1)
+				level++ ;
+
+			if (0 != level) {
+				PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr, level)),
+					"force highest pcie dpm state failed!", return -1);
+			}
+		}
+	}
+
+	if (0 == data->sclk_dpm_key_disabled) {
+		/* SCLK */
+		if (data->dpm_level_enable_mask.sclk_dpm_enable_mask != 0) {
+			level = 0;
+			tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
+			while (tmp >>= 1)
+				level++ ;
+
+			if (0 != level) {
+				PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr, level)),
+					"force highest sclk dpm state failed!", return -1);
+				if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
+					CGS_IND_REG__SMC, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX) != level)
+					printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
+						Curr_Sclk_Index does not match the level \n");
+
+			}
+		}
+	}
+
+	if (0 == data->mclk_dpm_key_disabled) {
+		/* MCLK */
+		if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) {
+			level = 0;
+			tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+			while (tmp >>= 1)
+				level++ ;
+
+			if (0 != level) {
+				PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr, level)),
+					"force highest mclk dpm state failed!", return -1);
+				if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+					TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX) != level)
+					printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
+						Curr_Mclk_Index does not match the level \n");
+			}
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Find the MC microcode version and store it in the HwMgr struct
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr)
+{
+	cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F);
+
+	hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
+
+	return 0;
+}
+
+/**
+ * Initialize Dynamic State Adjustment Rule Settings
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ */
+int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
+{
+	uint32_t table_size;
+	struct phm_clock_voltage_dependency_table *table_clk_vlt;
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	hwmgr->dyn_state.mclk_sclk_ratio = 4;
+	hwmgr->dyn_state.sclk_mclk_delta = 15000;      /* 150 MHz */
+	hwmgr->dyn_state.vddc_vddci_delta = 200;       /* 200mV */
+
+	/* initialize vddc_dep_on_dal_pwrl table */
+	table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
+	table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == table_clk_vlt) {
+		printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
+		return -ENOMEM;
+	} else {
+		table_clk_vlt->count = 4;
+		table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
+		table_clk_vlt->entries[0].v = 0;
+		table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
+		table_clk_vlt->entries[1].v = 720;
+		table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
+		table_clk_vlt->entries[2].v = 810;
+		table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
+		table_clk_vlt->entries[3].v = 900;
+		pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
+		hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
+	}
+
+	return 0;
+}
+
+static int tonga_set_private_var_based_on_pptale(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
+		pptable_info->vdd_dep_on_sclk;
+	phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
+		pptable_info->vdd_dep_on_mclk;
+
+	PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
+		"VDD dependency on SCLK table is missing. 	\
+		This table is mandatory", return -1);
+	PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
+		"VDD dependency on SCLK table has to have is missing. 	\
+		This table is mandatory", return -1);
+
+	PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
+		"VDD dependency on MCLK table is missing. 	\
+		This table is mandatory", return -1);
+	PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
+		"VDD dependency on MCLK table has to have is missing.	 \
+		This table is mandatory", return -1);
+
+	data->min_vddc_in_pp_table = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
+	data->max_vddc_in_pp_table = (uint16_t)allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
+
+	pptable_info->max_clock_voltage_on_ac.sclk =
+		allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
+	pptable_info->max_clock_voltage_on_ac.mclk =
+		allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
+	pptable_info->max_clock_voltage_on_ac.vddc =
+		allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
+	pptable_info->max_clock_voltage_on_ac.vddci =
+		allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
+
+	hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
+		pptable_info->max_clock_voltage_on_ac.sclk;
+	hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
+		pptable_info->max_clock_voltage_on_ac.mclk;
+	hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
+		pptable_info->max_clock_voltage_on_ac.vddc;
+	hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
+		pptable_info->max_clock_voltage_on_ac.vddci;
+
+	return 0;
+}
+
+int tonga_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	int result = 1;
+
+	PP_ASSERT_WITH_CODE (0 == tonga_is_dpm_running(hwmgr),
+		"Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.",
+							return result);
+
+	if (0 == data->pcie_dpm_key_disabled) {
+		PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(
+							     hwmgr->smumgr,
+					PPSMC_MSG_PCIeDPM_UnForceLevel)),
+					   "unforce pcie level failed!",
+								return -1);
+	}
+
+	result = tonga_upload_dpm_level_enable_mask(hwmgr);
+
+	return result;
+}
+
+static uint32_t tonga_get_lowest_enable_level(
+				struct pp_hwmgr *hwmgr, uint32_t level_mask)
+{
+	uint32_t level = 0;
+
+	while (0 == (level_mask & (1 << level)))
+		level++;
+
+	return level;
+}
+
+static int tonga_force_dpm_lowest(struct pp_hwmgr *hwmgr)
+{
+	uint32_t level;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	if (0 == data->pcie_dpm_key_disabled) {
+		/* PCIE */
+		if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) {
+			level = tonga_get_lowest_enable_level(hwmgr,
+							      data->dpm_level_enable_mask.pcie_dpm_enable_mask);
+			PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr, level)),
+					    "force lowest pcie dpm state failed!", return -1);
+		}
+	}
+
+	if (0 == data->sclk_dpm_key_disabled) {
+		/* SCLK */
+		if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+			level = tonga_get_lowest_enable_level(hwmgr,
+							      data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+
+			PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr, level)),
+					    "force sclk dpm state failed!", return -1);
+
+			if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
+							 CGS_IND_REG__SMC, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX) != level)
+				printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index.	\
+				Curr_Sclk_Index does not match the level \n");
+		}
+	}
+
+	if (0 == data->mclk_dpm_key_disabled) {
+		/* MCLK */
+		if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) {
+			level = tonga_get_lowest_enable_level(hwmgr,
+							      data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+			PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr, level)),
+					    "force lowest mclk dpm state failed!", return -1);
+			if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+							 TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX) != level)
+				printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
+						Curr_Mclk_Index does not match the level \n");
+		}
+	}
+
+	return 0;
+}
+
+static int tonga_patch_voltage_dependency_tables_with_lookup_table(struct pp_hwmgr *hwmgr)
+{
+	uint8_t entryId;
+	uint8_t voltageId;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
+	phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
+	phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+	if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+		for (entryId = 0; entryId < sclk_table->count; ++entryId) {
+			voltageId = sclk_table->entries[entryId].vddInd;
+			sclk_table->entries[entryId].vddgfx =
+				pptable_info->vddgfx_lookup_table->entries[voltageId].us_vdd;
+		}
+	} else {
+		for (entryId = 0; entryId < sclk_table->count; ++entryId) {
+			voltageId = sclk_table->entries[entryId].vddInd;
+			sclk_table->entries[entryId].vddc =
+				pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
+		}
+	}
+
+	for (entryId = 0; entryId < mclk_table->count; ++entryId) {
+		voltageId = mclk_table->entries[entryId].vddInd;
+		mclk_table->entries[entryId].vddc =
+			pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
+	}
+
+	for (entryId = 0; entryId < mm_table->count; ++entryId) {
+		voltageId = mm_table->entries[entryId].vddcInd;
+		mm_table->entries[entryId].vddc =
+			pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
+	}
+
+	return 0;
+
+}
+
+static int tonga_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+	uint8_t entryId;
+	phm_ppt_v1_voltage_lookup_record v_record;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
+	phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
+
+	if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+		for (entryId = 0; entryId < sclk_table->count; ++entryId) {
+			if (sclk_table->entries[entryId].vdd_offset & (1 << 15))
+				v_record.us_vdd = sclk_table->entries[entryId].vddgfx +
+					sclk_table->entries[entryId].vdd_offset - 0xFFFF;
+			else
+				v_record.us_vdd = sclk_table->entries[entryId].vddgfx +
+					sclk_table->entries[entryId].vdd_offset;
+
+			sclk_table->entries[entryId].vddc =
+				v_record.us_cac_low = v_record.us_cac_mid =
+				v_record.us_cac_high = v_record.us_vdd;
+
+			tonga_add_voltage(hwmgr, pptable_info->vddc_lookup_table, &v_record);
+		}
+
+		for (entryId = 0; entryId < mclk_table->count; ++entryId) {
+			if (mclk_table->entries[entryId].vdd_offset & (1 << 15))
+				v_record.us_vdd = mclk_table->entries[entryId].vddc +
+					mclk_table->entries[entryId].vdd_offset - 0xFFFF;
+			else
+				v_record.us_vdd = mclk_table->entries[entryId].vddc +
+					mclk_table->entries[entryId].vdd_offset;
+
+			mclk_table->entries[entryId].vddgfx = v_record.us_cac_low =
+				v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
+			tonga_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
+		}
+	}
+
+	return 0;
+
+}
+
+static int tonga_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
+{
+	uint32_t entryId;
+	phm_ppt_v1_voltage_lookup_record v_record;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+	if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+		for (entryId = 0; entryId < mm_table->count; entryId++) {
+			if (mm_table->entries[entryId].vddgfx_offset & (1 << 15))
+				v_record.us_vdd = mm_table->entries[entryId].vddc +
+					mm_table->entries[entryId].vddgfx_offset - 0xFFFF;
+			else
+				v_record.us_vdd = mm_table->entries[entryId].vddc +
+					mm_table->entries[entryId].vddgfx_offset;
+
+			/* Add the calculated VDDGFX to the VDDGFX lookup table */
+			mm_table->entries[entryId].vddgfx = v_record.us_cac_low =
+				v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
+			tonga_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * Change virtual leakage voltage to actual value.
+ *
+ * @param     hwmgr  the address of the powerplay hardware manager.
+ * @param     pointer to changing voltage
+ * @param     pointer to leakage table
+ */
+static void tonga_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
+		uint16_t *voltage, phw_tonga_leakage_voltage *pLeakageTable)
+{
+	uint32_t leakage_index;
+
+	/* search for leakage voltage ID 0xff01 ~ 0xff08 */
+	for (leakage_index = 0; leakage_index < pLeakageTable->count; leakage_index++) {
+		/* if this voltage matches a leakage voltage ID */
+		/* patch with actual leakage voltage */
+		if (pLeakageTable->leakage_id[leakage_index] == *voltage) {
+			*voltage = pLeakageTable->actual_voltage[leakage_index];
+			break;
+		}
+	}
+
+	if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
+		printk(KERN_ERR "[ powerplay ] Voltage value looks like a Leakage ID but it's not patched \n");
+}
+
+/**
+ * Patch voltage lookup table by EVV leakages.
+ *
+ * @param     hwmgr  the address of the powerplay hardware manager.
+ * @param     pointer to voltage lookup table
+ * @param     pointer to leakage table
+ * @return     always 0
+ */
+static int tonga_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_voltage_lookup_table *lookup_table,
+		phw_tonga_leakage_voltage *pLeakageTable)
+{
+	uint32_t i;
+
+	for (i = 0; i < lookup_table->count; i++) {
+		tonga_patch_with_vdd_leakage(hwmgr,
+			&lookup_table->entries[i].us_vdd, pLeakageTable);
+	}
+
+	return 0;
+}
+
+static int tonga_patch_clock_voltage_lomits_with_vddc_leakage(struct pp_hwmgr *hwmgr,
+		phw_tonga_leakage_voltage *pLeakageTable, uint16_t *Vddc)
+{
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	tonga_patch_with_vdd_leakage(hwmgr, (uint16_t *)Vddc, pLeakageTable);
+	hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
+		pptable_info->max_clock_voltage_on_dc.vddc;
+
+	return 0;
+}
+
+static int tonga_patch_clock_voltage_limits_with_vddgfx_leakage(
+		struct pp_hwmgr *hwmgr, phw_tonga_leakage_voltage *pLeakageTable,
+		uint16_t *Vddgfx)
+{
+	tonga_patch_with_vdd_leakage(hwmgr, (uint16_t *)Vddgfx, pLeakageTable);
+	return 0;
+}
+
+int tonga_sort_lookup_table(struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+	uint32_t table_size, i, j;
+	phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
+	table_size = lookup_table->count;
+
+	PP_ASSERT_WITH_CODE(0 != lookup_table->count,
+		"Lookup table is empty", return -1);
+
+	/* Sorting voltages */
+	for (i = 0; i < table_size - 1; i++) {
+		for (j = i + 1; j > 0; j--) {
+			if (lookup_table->entries[j].us_vdd < lookup_table->entries[j-1].us_vdd) {
+				tmp_voltage_lookup_record = lookup_table->entries[j-1];
+				lookup_table->entries[j-1] = lookup_table->entries[j];
+				lookup_table->entries[j] = tmp_voltage_lookup_record;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int tonga_complete_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+	int result = 0;
+	int tmp_result;
+	tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+		tmp_result = tonga_patch_lookup_table_with_leakage(hwmgr,
+			pptable_info->vddgfx_lookup_table, &(data->vddcgfx_leakage));
+		if (tmp_result != 0)
+			result = tmp_result;
+
+		tmp_result = tonga_patch_clock_voltage_limits_with_vddgfx_leakage(hwmgr,
+			&(data->vddcgfx_leakage), &pptable_info->max_clock_voltage_on_dc.vddgfx);
+		if (tmp_result != 0)
+			result = tmp_result;
+	} else {
+		tmp_result = tonga_patch_lookup_table_with_leakage(hwmgr,
+			pptable_info->vddc_lookup_table, &(data->vddc_leakage));
+		if (tmp_result != 0)
+			result = tmp_result;
+
+		tmp_result = tonga_patch_clock_voltage_lomits_with_vddc_leakage(hwmgr,
+			&(data->vddc_leakage), &pptable_info->max_clock_voltage_on_dc.vddc);
+		if (tmp_result != 0)
+			result = tmp_result;
+	}
+
+	tmp_result = tonga_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
+	if (tmp_result != 0)
+		result = tmp_result;
+
+	tmp_result = tonga_calc_voltage_dependency_tables(hwmgr);
+	if (tmp_result != 0)
+		result = tmp_result;
+
+	tmp_result = tonga_calc_mm_voltage_dependency_table(hwmgr);
+	if (tmp_result != 0)
+		result = tmp_result;
+
+	tmp_result = tonga_sort_lookup_table(hwmgr, pptable_info->vddgfx_lookup_table);
+	if (tmp_result != 0)
+		result = tmp_result;
+
+	tmp_result = tonga_sort_lookup_table(hwmgr, pptable_info->vddc_lookup_table);
+	if (tmp_result != 0)
+		result = tmp_result;
+
+	return result;
+}
+
+int tonga_init_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	data->low_sclk_interrupt_threshold = 0;
+
+	return 0;
+}
+
+int tonga_setup_asic_task(struct pp_hwmgr *hwmgr)
+{
+	int tmp_result, result = 0;
+
+	tmp_result = tonga_read_clock_registers(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to read clock registers!", result = tmp_result);
+
+	tmp_result = tonga_get_memory_type(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to get memory type!", result = tmp_result);
+
+	tmp_result = tonga_enable_acpi_power_management(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to enable ACPI power management!", result = tmp_result);
+
+	tmp_result = tonga_init_power_gate_state(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to init power gate state!", result = tmp_result);
+
+	tmp_result = tonga_get_mc_microcode_version(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to get MC microcode version!", result = tmp_result);
+
+	tmp_result = tonga_init_sclk_threshold(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to init sclk threshold!", result = tmp_result);
+
+	return result;
+}
+
+/**
+ * Enable voltage control
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_enable_voltage_control(struct pp_hwmgr *hwmgr)
+{
+	/* enable voltage control */
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
+
+	return 0;
+}
+
+/**
+ * Checks if we want to support voltage control
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ */
+bool cf_tonga_voltage_control(const struct pp_hwmgr *hwmgr)
+{
+	const struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	return(TONGA_VOLTAGE_CONTROL_NONE != data->voltage_control);
+}
+
+/*---------------------------MC----------------------------*/
+
+uint8_t tonga_get_memory_modile_index(struct pp_hwmgr *hwmgr)
+{
+	return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
+}
+
+bool tonga_check_s0_mc_reg_index(uint16_t inReg, uint16_t *outReg)
+{
+	bool result = 1;
+
+	switch (inReg) {
+	case  mmMC_SEQ_RAS_TIMING:
+		*outReg = mmMC_SEQ_RAS_TIMING_LP;
+		break;
+
+	case  mmMC_SEQ_DLL_STBY:
+		*outReg = mmMC_SEQ_DLL_STBY_LP;
+		break;
+
+	case  mmMC_SEQ_G5PDX_CMD0:
+		*outReg = mmMC_SEQ_G5PDX_CMD0_LP;
+		break;
+
+	case  mmMC_SEQ_G5PDX_CMD1:
+		*outReg = mmMC_SEQ_G5PDX_CMD1_LP;
+		break;
+
+	case  mmMC_SEQ_G5PDX_CTRL:
+		*outReg = mmMC_SEQ_G5PDX_CTRL_LP;
+		break;
+
+	case mmMC_SEQ_CAS_TIMING:
+		*outReg = mmMC_SEQ_CAS_TIMING_LP;
+		break;
+
+	case mmMC_SEQ_MISC_TIMING:
+		*outReg = mmMC_SEQ_MISC_TIMING_LP;
+		break;
+
+	case mmMC_SEQ_MISC_TIMING2:
+		*outReg = mmMC_SEQ_MISC_TIMING2_LP;
+		break;
+
+	case mmMC_SEQ_PMG_DVS_CMD:
+		*outReg = mmMC_SEQ_PMG_DVS_CMD_LP;
+		break;
+
+	case mmMC_SEQ_PMG_DVS_CTL:
+		*outReg = mmMC_SEQ_PMG_DVS_CTL_LP;
+		break;
+
+	case mmMC_SEQ_RD_CTL_D0:
+		*outReg = mmMC_SEQ_RD_CTL_D0_LP;
+		break;
+
+	case mmMC_SEQ_RD_CTL_D1:
+		*outReg = mmMC_SEQ_RD_CTL_D1_LP;
+		break;
+
+	case mmMC_SEQ_WR_CTL_D0:
+		*outReg = mmMC_SEQ_WR_CTL_D0_LP;
+		break;
+
+	case mmMC_SEQ_WR_CTL_D1:
+		*outReg = mmMC_SEQ_WR_CTL_D1_LP;
+		break;
+
+	case mmMC_PMG_CMD_EMRS:
+		*outReg = mmMC_SEQ_PMG_CMD_EMRS_LP;
+		break;
+
+	case mmMC_PMG_CMD_MRS:
+		*outReg = mmMC_SEQ_PMG_CMD_MRS_LP;
+		break;
+
+	case mmMC_PMG_CMD_MRS1:
+		*outReg = mmMC_SEQ_PMG_CMD_MRS1_LP;
+		break;
+
+	case mmMC_SEQ_PMG_TIMING:
+		*outReg = mmMC_SEQ_PMG_TIMING_LP;
+		break;
+
+	case mmMC_PMG_CMD_MRS2:
+		*outReg = mmMC_SEQ_PMG_CMD_MRS2_LP;
+		break;
+
+	case mmMC_SEQ_WR_CTL_2:
+		*outReg = mmMC_SEQ_WR_CTL_2_LP;
+		break;
+
+	default:
+		result = 0;
+		break;
+	}
+
+	return result;
+}
+
+int tonga_set_s0_mc_reg_index(phw_tonga_mc_reg_table *table)
+{
+	uint32_t i;
+	uint16_t address;
+
+	for (i = 0; i < table->last; i++) {
+		table->mc_reg_address[i].s0 =
+			tonga_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address)
+			? address : table->mc_reg_address[i].s1;
+	}
+	return 0;
+}
+
+int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table, phw_tonga_mc_reg_table *ni_table)
+{
+	uint8_t i, j;
+
+	PP_ASSERT_WITH_CODE((table->last <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+		"Invalid VramInfo table.", return -1);
+	PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
+		"Invalid VramInfo table.", return -1);
+
+	for (i = 0; i < table->last; i++) {
+		ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+	}
+	ni_table->last = table->last;
+
+	for (i = 0; i < table->num_entries; i++) {
+		ni_table->mc_reg_table_entry[i].mclk_max =
+			table->mc_reg_table_entry[i].mclk_max;
+		for (j = 0; j < table->last; j++) {
+			ni_table->mc_reg_table_entry[i].mc_data[j] =
+				table->mc_reg_table_entry[i].mc_data[j];
+		}
+	}
+
+	ni_table->num_entries = table->num_entries;
+
+	return 0;
+}
+
+/**
+ * VBIOS omits some information to reduce size, we need to recover them here.
+ * 1.   when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to  mmMC_PMG_CMD_EMRS /_LP[15:0].
+ *      Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
+ * 2.   when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
+ * 3.   need to set these data for each clock range
+ *
+ * @param    hwmgr the address of the powerplay hardware manager.
+ * @param    table the address of MCRegTable
+ * @return   always 0
+ */
+int tonga_set_mc_special_registers(struct pp_hwmgr *hwmgr, phw_tonga_mc_reg_table *table)
+{
+	uint8_t i, j, k;
+	uint32_t temp_reg;
+	const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	for (i = 0, j = table->last; i < table->last; i++) {
+		PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+			"Invalid VramInfo table.", return -1);
+		switch (table->mc_reg_address[i].s1) {
+		/*
+		* mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to  mmMC_PMG_CMD_EMRS /_LP[15:0].
+		* Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
+		*/
+		case mmMC_SEQ_MISC1:
+			temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS);
+			table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
+			table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
+			for (k = 0; k < table->num_entries; k++) {
+				table->mc_reg_table_entry[k].mc_data[j] =
+					((temp_reg & 0xffff0000)) |
+					((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
+			}
+			j++;
+			PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+				"Invalid VramInfo table.", return -1);
+
+			temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
+			table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
+			table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
+			for (k = 0; k < table->num_entries; k++) {
+				table->mc_reg_table_entry[k].mc_data[j] =
+					(temp_reg & 0xffff0000) |
+					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+
+				if (!data->is_memory_GDDR5) {
+					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+				}
+			}
+			j++;
+			PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+				"Invalid VramInfo table.", return -1);
+
+			if (!data->is_memory_GDDR5) {
+				table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
+				table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
+				for (k = 0; k < table->num_entries; k++) {
+					table->mc_reg_table_entry[k].mc_data[j] =
+						(table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
+				}
+				j++;
+				PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+					"Invalid VramInfo table.", return -1);
+			}
+
+			break;
+
+		case mmMC_SEQ_RESERVE_M:
+			temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
+			table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
+			table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
+			for (k = 0; k < table->num_entries; k++) {
+				table->mc_reg_table_entry[k].mc_data[j] =
+					(temp_reg & 0xffff0000) |
+					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+			}
+			j++;
+			PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+				"Invalid VramInfo table.", return -1);
+			break;
+
+		default:
+			break;
+		}
+
+	}
+
+	table->last = j;
+
+	return 0;
+}
+
+int tonga_set_valid_flag(phw_tonga_mc_reg_table *table)
+{
+	uint8_t i, j;
+	for (i = 0; i < table->last; i++) {
+		for (j = 1; j < table->num_entries; j++) {
+			if (table->mc_reg_table_entry[j-1].mc_data[i] !=
+				table->mc_reg_table_entry[j].mc_data[i]) {
+				table->validflag |= (1<<i);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+	int result;
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+	pp_atomctrl_mc_reg_table *table;
+	phw_tonga_mc_reg_table *ni_table = &data->tonga_mc_reg_table;
+	uint8_t module_index = tonga_get_memory_modile_index(hwmgr);
+
+	table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
+
+	if (NULL == table)
+		return -ENOMEM;
+
+	/* Program additional LP registers that are no longer programmed by VBIOS */
+	cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
+	cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
+
+	memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
+
+	result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
+
+	if (0 == result)
+		result = tonga_copy_vbios_smc_reg_table(table, ni_table);
+
+	if (0 == result) {
+		tonga_set_s0_mc_reg_index(ni_table);
+		result = tonga_set_mc_special_registers(hwmgr, ni_table);
+	}
+
+	if (0 == result)
+		tonga_set_valid_flag(ni_table);
+
+	kfree(table);
+	return result;
+}
+
+/*
+* Copy one arb setting to another and then switch the active set.
+* arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants.
+*/
+int tonga_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
+		uint32_t arbFreqSrc, uint32_t arbFreqDest)
+{
+	uint32_t mc_arb_dram_timing;
+	uint32_t mc_arb_dram_timing2;
+	uint32_t burst_time;
+	uint32_t mc_cg_config;
+
+	switch (arbFreqSrc) {
+	case MC_CG_ARB_FREQ_F0:
+		mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+		mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+		burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+		break;
+
+	case MC_CG_ARB_FREQ_F1:
+		mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
+		mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
+		burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
+		break;
+
+	default:
+		return -1;
+	}
+
+	switch (arbFreqDest) {
+	case MC_CG_ARB_FREQ_F0:
+		cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+		cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+		PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
+		break;
+
+	case MC_CG_ARB_FREQ_F1:
+		cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+		cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+		PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
+		break;
+
+	default:
+		return -1;
+	}
+
+	mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
+	mc_cg_config |= 0x0000000F;
+	cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
+	PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arbFreqDest);
+
+	return 0;
+}
+
+/**
+ * Initial switch from ARB F0->F1
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ * This function is to be called from the SetPowerState table.
+ */
+int tonga_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr *hwmgr)
+{
+	return tonga_copy_and_switch_arb_sets(hwmgr, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+/**
+ * Initialize the ARB DRAM timing table's index field.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_init_arb_table_index(struct pp_hwmgr *hwmgr)
+{
+	const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	uint32_t tmp;
+	int result;
+
+	/*
+	* This is a read-modify-write on the first byte of the ARB table.
+	* The first byte in the SMU72_Discrete_MCArbDramTimingTable structure is the field 'current'.
+	* This solution is ugly, but we never write the whole table only individual fields in it.
+	* In reality this field should not be in that structure but in a soft register.
+	*/
+	result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+				data->arb_table_start, &tmp, data->sram_end);
+
+	if (0 != result)
+		return result;
+
+	tmp &= 0x00FFFFFF;
+	tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
+
+	return tonga_write_smc_sram_dword(hwmgr->smumgr,
+			data->arb_table_start,  tmp, data->sram_end);
+}
+
+int tonga_populate_mc_reg_address(struct pp_hwmgr *hwmgr, SMU72_Discrete_MCRegisters *mc_reg_table)
+{
+	const struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	uint32_t i, j;
+
+	for (i = 0, j = 0; j < data->tonga_mc_reg_table.last; j++) {
+		if (data->tonga_mc_reg_table.validflag & 1<<j) {
+			PP_ASSERT_WITH_CODE(i < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE,
+				"Index of mc_reg_table->address[] array out of boundary", return -1);
+			mc_reg_table->address[i].s0 =
+				PP_HOST_TO_SMC_US(data->tonga_mc_reg_table.mc_reg_address[j].s0);
+			mc_reg_table->address[i].s1 =
+				PP_HOST_TO_SMC_US(data->tonga_mc_reg_table.mc_reg_address[j].s1);
+			i++;
+		}
+	}
+
+	mc_reg_table->last = (uint8_t)i;
+
+	return 0;
+}
+
+/*convert register values from driver to SMC format */
+void tonga_convert_mc_registers(
+	const phw_tonga_mc_reg_entry * pEntry,
+	SMU72_Discrete_MCRegisterSet *pData,
+	uint32_t numEntries, uint32_t validflag)
+{
+	uint32_t i, j;
+
+	for (i = 0, j = 0; j < numEntries; j++) {
+		if (validflag & 1<<j) {
+			pData->value[i] = PP_HOST_TO_SMC_UL(pEntry->mc_data[j]);
+			i++;
+		}
+	}
+}
+
+/* find the entry in the memory range table, then populate the value to SMC's tonga_mc_reg_table */
+int tonga_convert_mc_reg_table_entry_to_smc(
+		struct pp_hwmgr *hwmgr,
+		const uint32_t memory_clock,
+		SMU72_Discrete_MCRegisterSet *mc_reg_table_data
+		)
+{
+	const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	uint32_t i = 0;
+
+	for (i = 0; i < data->tonga_mc_reg_table.num_entries; i++) {
+		if (memory_clock <=
+			data->tonga_mc_reg_table.mc_reg_table_entry[i].mclk_max) {
+			break;
+		}
+	}
+
+	if ((i == data->tonga_mc_reg_table.num_entries) && (i > 0))
+		--i;
+
+	tonga_convert_mc_registers(&data->tonga_mc_reg_table.mc_reg_table_entry[i],
+		mc_reg_table_data, data->tonga_mc_reg_table.last, data->tonga_mc_reg_table.validflag);
+
+	return 0;
+}
+
+int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
+		SMU72_Discrete_MCRegisters *mc_reg_table)
+{
+	int result = 0;
+	tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	int res;
+	uint32_t i;
+
+	for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
+		res = tonga_convert_mc_reg_table_entry_to_smc(
+				hwmgr,
+				data->dpm_table.mclk_table.dpm_levels[i].value,
+				&mc_reg_table->data[i]
+				);
+
+		if (0 != res)
+			result = res;
+	}
+
+	return result;
+}
+
+int tonga_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+	int result;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	memset(&data->mc_reg_table, 0x00, sizeof(SMU72_Discrete_MCRegisters));
+	result = tonga_populate_mc_reg_address(hwmgr, &(data->mc_reg_table));
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize MCRegTable for the MC register addresses!", return result;);
+
+	result = tonga_convert_mc_reg_table_to_smc(hwmgr, &data->mc_reg_table);
+	PP_ASSERT_WITH_CODE(0 == result,
+		"Failed to initialize MCRegTable for driver state!", return result;);
+
+	return tonga_copy_bytes_to_smc(hwmgr->smumgr, data->mc_reg_table_start,
+			(uint8_t *)&data->mc_reg_table, sizeof(SMU72_Discrete_MCRegisters), data->sram_end);
+}
+
+/**
+ * Programs static screed detection parameters
+ *
+ * @param   hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_program_static_screen_threshold_parameters(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	/* Set static screen threshold unit*/
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
+		CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
+		data->static_screen_threshold_unit);
+	/* Set static screen threshold*/
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
+		CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
+		data->static_screen_threshold);
+
+	return 0;
+}
+
+/**
+ * Setup display gap for glitch free memory clock switching.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_enable_display_gap(struct pp_hwmgr *hwmgr)
+{
+	uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
+							CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
+
+	display_gap = PHM_SET_FIELD(display_gap,
+					CG_DISPLAY_GAP_CNTL, DISP_GAP, DISPLAY_GAP_IGNORE);
+
+	display_gap = PHM_SET_FIELD(display_gap,
+					CG_DISPLAY_GAP_CNTL, DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_DISPLAY_GAP_CNTL, display_gap);
+
+	return 0;
+}
+
+/**
+ * Programs activity state transition voting clients
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_program_voting_clients(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+	/* Clear reset for voting clients before enabling DPM */
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+		SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+		SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+		ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
+
+	return 0;
+}
+
+
+int tonga_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
+{
+	int tmp_result, result = 0;
+
+	tmp_result = tonga_check_for_dpm_stopped(hwmgr);
+
+	if (cf_tonga_voltage_control(hwmgr)) {
+		tmp_result = tonga_enable_voltage_control(hwmgr);
+		PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to enable voltage control!", result = tmp_result);
+
+		tmp_result = tonga_construct_voltage_tables(hwmgr);
+		PP_ASSERT_WITH_CODE((0 == tmp_result),
+			"Failed to contruct voltage tables!", result = tmp_result);
+	}
+
+	tmp_result = tonga_initialize_mc_reg_table(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to initialize MC reg table!", result = tmp_result);
+
+	tmp_result = tonga_program_static_screen_threshold_parameters(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to program static screen threshold parameters!", result = tmp_result);
+
+	tmp_result = tonga_enable_display_gap(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to enable display gap!", result = tmp_result);
+
+	tmp_result = tonga_program_voting_clients(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to program voting clients!", result = tmp_result);
+
+	tmp_result = tonga_process_firmware_header(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to process firmware header!", result = tmp_result);
+
+	tmp_result = tonga_initial_switch_from_arb_f0_to_f1(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to initialize switch from ArbF0 to F1!", result = tmp_result);
+
+	tmp_result = tonga_init_smc_table(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to initialize SMC table!", result = tmp_result);
+
+	tmp_result = tonga_init_arb_table_index(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to initialize ARB table index!", result = tmp_result);
+
+	tmp_result = tonga_populate_initial_mc_reg_table(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to populate initialize MC Reg table!", result = tmp_result);
+
+	tmp_result = tonga_notify_smc_display_change(hwmgr, false);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to notify no display!", result = tmp_result);
+
+	/* enable SCLK control */
+	tmp_result = tonga_enable_sclk_control(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to enable SCLK control!", result = tmp_result);
+
+	/* enable DPM */
+	tmp_result = tonga_start_dpm(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to start DPM!", result = tmp_result);
+
+	return result;
+}
+
+int tonga_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
+{
+	int tmp_result, result = 0;
+
+	tmp_result = tonga_check_for_dpm_running(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"SMC is still running!", return 0);
+
+	tmp_result = tonga_stop_dpm(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to stop DPM!", result = tmp_result);
+
+	tmp_result = tonga_reset_to_default(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result),
+		"Failed to reset to default!", result = tmp_result);
+
+	return result;
+}
+
+int tonga_reset_asic_tasks(struct pp_hwmgr *hwmgr)
+{
+	int result;
+
+	result = tonga_set_boot_state(hwmgr);
+	if (0 != result)
+		printk(KERN_ERR "[ powerplay ] Failed to reset asic via set boot state! \n");
+
+	return result;
+}
+
+int tonga_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
+{
+	if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
+		kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
+		hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+	}
+
+	if (NULL != hwmgr->backend) {
+		kfree(hwmgr->backend);
+		hwmgr->backend = NULL;
+	}
+
+	return 0;
+}
+
+/**
+ * Initializes the Volcanic Islands Hardware Manager
+ *
+ * @param   hwmgr the address of the powerplay hardware manager.
+ * @return   1 if success; otherwise appropriate error code.
+ */
+int tonga_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
+{
+	int result = 0;
+	SMU72_Discrete_DpmTable  *table = NULL;
+	tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	phw_tonga_ulv_parm *ulv;
+	struct cgs_system_info sys_info = {0};
+
+	PP_ASSERT_WITH_CODE((NULL != hwmgr),
+		"Invalid Parameter!", return -1;);
+
+	data->dll_defaule_on = 0;
+	data->sram_end = SMC_RAM_END;
+
+	data->activity_target[0] = PPTONGA_TARGETACTIVITY_DFLT;
+	data->activity_target[1] = PPTONGA_TARGETACTIVITY_DFLT;
+	data->activity_target[2] = PPTONGA_TARGETACTIVITY_DFLT;
+	data->activity_target[3] = PPTONGA_TARGETACTIVITY_DFLT;
+	data->activity_target[4] = PPTONGA_TARGETACTIVITY_DFLT;
+	data->activity_target[5] = PPTONGA_TARGETACTIVITY_DFLT;
+	data->activity_target[6] = PPTONGA_TARGETACTIVITY_DFLT;
+	data->activity_target[7] = PPTONGA_TARGETACTIVITY_DFLT;
+
+	data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
+	data->vddc_vddgfx_delta = VDDC_VDDGFX_DELTA;
+	data->mclk_activity_target = PPTONGA_MCLK_TARGETACTIVITY_DFLT;
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_DisableVoltageIsland);
+
+	data->sclk_dpm_key_disabled = 0;
+	data->mclk_dpm_key_disabled = 0;
+	data->pcie_dpm_key_disabled = 0;
+	data->pcc_monitor_enabled = 0;
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_UnTabledHardwareInterface);
+
+	data->gpio_debug = 0;
+	data->engine_clock_data = 0;
+	data->memory_clock_data = 0;
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_DynamicPatchPowerState);
+
+	/* need to set voltage control types before EVV patching*/
+	data->voltage_control = TONGA_VOLTAGE_CONTROL_NONE;
+	data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_NONE;
+	data->vdd_gfx_control = TONGA_VOLTAGE_CONTROL_NONE;
+	data->mvdd_control = TONGA_VOLTAGE_CONTROL_NONE;
+
+	if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+				VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2)) {
+		data->voltage_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ControlVDDGFX)) {
+		if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+			VOLTAGE_TYPE_VDDGFX, VOLTAGE_OBJ_SVID2)) {
+			data->vdd_gfx_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
+		}
+	}
+
+	if (TONGA_VOLTAGE_CONTROL_NONE == data->vdd_gfx_control) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ControlVDDGFX);
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_EnableMVDDControl)) {
+		if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+					VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT)) {
+			data->mvdd_control = TONGA_VOLTAGE_CONTROL_BY_GPIO;
+		}
+	}
+
+	if (TONGA_VOLTAGE_CONTROL_NONE == data->mvdd_control) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_EnableMVDDControl);
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ControlVDDCI)) {
+		if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+					VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
+			data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_BY_GPIO;
+		else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+						VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
+			data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
+	}
+
+	if (TONGA_VOLTAGE_CONTROL_NONE == data->vdd_ci_control)
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_ControlVDDCI);
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_TablelessHardwareInterface);
+
+	if (pptable_info->cac_dtp_table->usClockStretchAmount != 0)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ClockStretcher);
+
+	/* Initializes DPM default values*/
+	tonga_initialize_dpm_defaults(hwmgr);
+
+	/* Get leakage voltage based on leakage ID.*/
+	PP_ASSERT_WITH_CODE((0 == tonga_get_evv_voltage(hwmgr)),
+		"Get EVV Voltage Failed.  Abort Driver loading!", return -1);
+
+	tonga_complete_dependency_tables(hwmgr);
+
+	/* Parse pptable data read from VBIOS*/
+	tonga_set_private_var_based_on_pptale(hwmgr);
+
+	/* ULV Support*/
+	ulv = &(data->ulv);
+	ulv->ulv_supported = 0;
+
+	/* Initalize Dynamic State Adjustment Rule Settings*/
+	result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
+	if (result)
+		printk(KERN_ERR "[ powerplay ] tonga_initializa_dynamic_state_adjustment_rule_settings failed!\n");
+	data->uvd_enabled = 0;
+
+	table = &(data->smc_state_table);
+
+	/*
+	* if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable,
+	* Peak Current Control feature is enabled and we should program PCC HW register
+	*/
+	if (0 == atomctrl_get_pp_assign_pin(hwmgr, VDDC_PCC_GPIO_PINID, &gpio_pin_assignment)) {
+		uint32_t temp_reg = cgs_read_ind_register(hwmgr->device,
+										CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL);
+
+		switch (gpio_pin_assignment.uc_gpio_pin_bit_shift) {
+		case 0:
+			temp_reg = PHM_SET_FIELD(temp_reg,
+				CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x1);
+			break;
+		case 1:
+			temp_reg = PHM_SET_FIELD(temp_reg,
+				CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x2);
+			break;
+		case 2:
+			temp_reg = PHM_SET_FIELD(temp_reg,
+				CNB_PWRMGT_CNTL, GNB_SLOW, 0x1);
+			break;
+		case 3:
+			temp_reg = PHM_SET_FIELD(temp_reg,
+				CNB_PWRMGT_CNTL, FORCE_NB_PS1, 0x1);
+			break;
+		case 4:
+			temp_reg = PHM_SET_FIELD(temp_reg,
+				CNB_PWRMGT_CNTL, DPM_ENABLED, 0x1);
+			break;
+		default:
+			printk(KERN_ERR "[ powerplay ] Failed to setup PCC HW register!	\
+				Wrong GPIO assigned for VDDC_PCC_GPIO_PINID! \n");
+			break;
+		}
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+			ixCNB_PWRMGT_CNTL, temp_reg);
+	}
+
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_EnableSMU7ThermalManagement);
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_SMU7);
+
+	data->vddc_phase_shed_control = 0;
+
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+		      PHM_PlatformCaps_UVDPowerGating);
+	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+		      PHM_PlatformCaps_VCEPowerGating);
+	sys_info.size = sizeof(struct cgs_system_info);
+	sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS;
+	result = cgs_query_system_info(hwmgr->device, &sys_info);
+	if (!result) {
+		if (sys_info.value & AMD_PG_SUPPORT_UVD)
+			phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				      PHM_PlatformCaps_UVDPowerGating);
+		if (sys_info.value & AMD_PG_SUPPORT_VCE)
+			phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+				      PHM_PlatformCaps_VCEPowerGating);
+	}
+
+	if (0 == result) {
+		data->is_tlu_enabled = 0;
+		hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
+			TONGA_MAX_HARDWARE_POWERLEVELS;
+		hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
+		hwmgr->platform_descriptor.minimumClocksReductionPercentage  = 50;
+
+		sys_info.size = sizeof(struct cgs_system_info);
+		sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
+		result = cgs_query_system_info(hwmgr->device, &sys_info);
+		if (result)
+			data->pcie_gen_cap = 0x30007;
+		else
+			data->pcie_gen_cap = (uint32_t)sys_info.value;
+		if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+			data->pcie_spc_cap = 20;
+		sys_info.size = sizeof(struct cgs_system_info);
+		sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
+		result = cgs_query_system_info(hwmgr->device, &sys_info);
+		if (result)
+			data->pcie_lane_cap = 0x2f0000;
+		else
+			data->pcie_lane_cap = (uint32_t)sys_info.value;
+	} else {
+		/* Ignore return value in here, we are cleaning up a mess. */
+		tonga_hwmgr_backend_fini(hwmgr);
+	}
+
+	return result;
+}
+
+static int tonga_force_dpm_level(struct pp_hwmgr *hwmgr,
+		enum amd_dpm_forced_level level)
+{
+	int ret = 0;
+
+	switch (level) {
+	case AMD_DPM_FORCED_LEVEL_HIGH:
+		ret = tonga_force_dpm_highest(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	case AMD_DPM_FORCED_LEVEL_LOW:
+		ret = tonga_force_dpm_lowest(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	case AMD_DPM_FORCED_LEVEL_AUTO:
+		ret = tonga_unforce_dpm_levels(hwmgr);
+		if (ret)
+			return ret;
+		break;
+	default:
+		break;
+	}
+
+	hwmgr->dpm_level = level;
+	return ret;
+}
+
+static int tonga_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+				struct pp_power_state  *prequest_ps,
+			const struct pp_power_state *pcurrent_ps)
+{
+	struct tonga_power_state *tonga_ps =
+				cast_phw_tonga_power_state(&prequest_ps->hardware);
+
+	uint32_t sclk;
+	uint32_t mclk;
+	struct PP_Clocks minimum_clocks = {0};
+	bool disable_mclk_switching;
+	bool disable_mclk_switching_for_frame_lock;
+	struct cgs_display_info info = {0};
+	const struct phm_clock_and_voltage_limits *max_limits;
+	uint32_t i;
+	tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	int32_t count;
+	int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
+
+	data->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
+
+	PP_ASSERT_WITH_CODE(tonga_ps->performance_level_count == 2,
+				 "VI should always have 2 performance levels",
+				 );
+
+	max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
+			&(hwmgr->dyn_state.max_clock_voltage_on_ac) :
+			&(hwmgr->dyn_state.max_clock_voltage_on_dc);
+
+	if (PP_PowerSource_DC == hwmgr->power_source) {
+		for (i = 0; i < tonga_ps->performance_level_count; i++) {
+			if (tonga_ps->performance_levels[i].memory_clock > max_limits->mclk)
+				tonga_ps->performance_levels[i].memory_clock = max_limits->mclk;
+			if (tonga_ps->performance_levels[i].engine_clock > max_limits->sclk)
+				tonga_ps->performance_levels[i].engine_clock = max_limits->sclk;
+		}
+	}
+
+	tonga_ps->vce_clocks.EVCLK = hwmgr->vce_arbiter.evclk;
+	tonga_ps->vce_clocks.ECCLK = hwmgr->vce_arbiter.ecclk;
+
+	tonga_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+
+	/*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
+
+	/* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) {
+
+		max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
+		stable_pstate_sclk = (max_limits->sclk * 75) / 100;
+
+		for (count = pptable_info->vdd_dep_on_sclk->count-1; count >= 0; count--) {
+			if (stable_pstate_sclk >= pptable_info->vdd_dep_on_sclk->entries[count].clk) {
+				stable_pstate_sclk = pptable_info->vdd_dep_on_sclk->entries[count].clk;
+				break;
+			}
+		}
+
+		if (count < 0)
+			stable_pstate_sclk = pptable_info->vdd_dep_on_sclk->entries[0].clk;
+
+		stable_pstate_mclk = max_limits->mclk;
+
+		minimum_clocks.engineClock = stable_pstate_sclk;
+		minimum_clocks.memoryClock = stable_pstate_mclk;
+	}
+
+	if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
+		minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
+
+	if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
+		minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
+
+	tonga_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
+
+	if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
+		PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.engineClock),
+					"Overdrive sclk exceeds limit",
+					hwmgr->gfx_arbiter.sclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.engineClock);
+
+		if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
+			tonga_ps->performance_levels[1].engine_clock = hwmgr->gfx_arbiter.sclk_over_drive;
+	}
+
+	if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
+		PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.memoryClock),
+			"Overdrive mclk exceeds limit",
+			hwmgr->gfx_arbiter.mclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.memoryClock);
+
+		if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
+			tonga_ps->performance_levels[1].memory_clock = hwmgr->gfx_arbiter.mclk_over_drive;
+	}
+
+	disable_mclk_switching_for_frame_lock = phm_cap_enabled(
+				    hwmgr->platform_descriptor.platformCaps,
+				    PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
+
+	disable_mclk_switching = (1 < info.display_count) ||
+				    disable_mclk_switching_for_frame_lock;
+
+	sclk  = tonga_ps->performance_levels[0].engine_clock;
+	mclk  = tonga_ps->performance_levels[0].memory_clock;
+
+	if (disable_mclk_switching)
+		mclk  = tonga_ps->performance_levels[tonga_ps->performance_level_count - 1].memory_clock;
+
+	if (sclk < minimum_clocks.engineClock)
+		sclk = (minimum_clocks.engineClock > max_limits->sclk) ? max_limits->sclk : minimum_clocks.engineClock;
+
+	if (mclk < minimum_clocks.memoryClock)
+		mclk = (minimum_clocks.memoryClock > max_limits->mclk) ? max_limits->mclk : minimum_clocks.memoryClock;
+
+	tonga_ps->performance_levels[0].engine_clock = sclk;
+	tonga_ps->performance_levels[0].memory_clock = mclk;
+
+	tonga_ps->performance_levels[1].engine_clock =
+		(tonga_ps->performance_levels[1].engine_clock >= tonga_ps->performance_levels[0].engine_clock) ?
+			      tonga_ps->performance_levels[1].engine_clock :
+			      tonga_ps->performance_levels[0].engine_clock;
+
+	if (disable_mclk_switching) {
+		if (mclk < tonga_ps->performance_levels[1].memory_clock)
+			mclk = tonga_ps->performance_levels[1].memory_clock;
+
+		tonga_ps->performance_levels[0].memory_clock = mclk;
+		tonga_ps->performance_levels[1].memory_clock = mclk;
+	} else {
+		if (tonga_ps->performance_levels[1].memory_clock < tonga_ps->performance_levels[0].memory_clock)
+			tonga_ps->performance_levels[1].memory_clock = tonga_ps->performance_levels[0].memory_clock;
+	}
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) {
+		for (i=0; i < tonga_ps->performance_level_count; i++) {
+			tonga_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
+			tonga_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
+			tonga_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
+			tonga_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
+		}
+	}
+
+	return 0;
+}
+
+int tonga_get_power_state_size(struct pp_hwmgr *hwmgr)
+{
+	return sizeof(struct tonga_power_state);
+}
+
+static int tonga_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
+{
+	struct pp_power_state  *ps;
+	struct tonga_power_state  *tonga_ps;
+
+	if (hwmgr == NULL)
+		return -EINVAL;
+
+	ps = hwmgr->request_ps;
+
+	if (ps == NULL)
+		return -EINVAL;
+
+	tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
+
+	if (low)
+		return tonga_ps->performance_levels[0].memory_clock;
+	else
+		return tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
+}
+
+static int tonga_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
+{
+	struct pp_power_state  *ps;
+	struct tonga_power_state  *tonga_ps;
+
+	if (hwmgr == NULL)
+		return -EINVAL;
+
+	ps = hwmgr->request_ps;
+
+	if (ps == NULL)
+		return -EINVAL;
+
+	tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
+
+	if (low)
+		return tonga_ps->performance_levels[0].engine_clock;
+	else
+		return tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
+}
+
+static uint16_t tonga_get_current_pcie_speed(
+						   struct pp_hwmgr *hwmgr)
+{
+	uint32_t speed_cntl = 0;
+
+	speed_cntl = cgs_read_ind_register(hwmgr->device,
+						   CGS_IND_REG__PCIE,
+						   ixPCIE_LC_SPEED_CNTL);
+	return((uint16_t)PHM_GET_FIELD(speed_cntl,
+			PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
+}
+
+static int tonga_get_current_pcie_lane_number(
+						   struct pp_hwmgr *hwmgr)
+{
+	uint32_t link_width;
+
+	link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device,
+							CGS_IND_REG__PCIE,
+						  PCIE_LC_LINK_WIDTH_CNTL,
+							LC_LINK_WIDTH_RD);
+
+	PP_ASSERT_WITH_CODE((7 >= link_width),
+			"Invalid PCIe lane width!", return 0);
+
+	return decode_pcie_lane_width(link_width);
+}
+
+static int tonga_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
+					struct pp_hw_power_state *hw_ps)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	struct tonga_power_state *ps = (struct tonga_power_state *)hw_ps;
+	ATOM_FIRMWARE_INFO_V2_2 *fw_info;
+	uint16_t size;
+	uint8_t frev, crev;
+	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+
+	/* First retrieve the Boot clocks and VDDC from the firmware info table.
+	 * We assume here that fw_info is unchanged if this call fails.
+	 */
+	fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
+			hwmgr->device, index,
+			&size, &frev, &crev);
+	if (!fw_info)
+		/* During a test, there is no firmware info table. */
+		return 0;
+
+	/* Patch the state. */
+	data->vbios_boot_state.sclk_bootup_value  = le32_to_cpu(fw_info->ulDefaultEngineClock);
+	data->vbios_boot_state.mclk_bootup_value  = le32_to_cpu(fw_info->ulDefaultMemoryClock);
+	data->vbios_boot_state.mvdd_bootup_value  = le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
+	data->vbios_boot_state.vddc_bootup_value  = le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+	data->vbios_boot_state.vddci_bootup_value = le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
+	data->vbios_boot_state.pcie_gen_bootup_value = tonga_get_current_pcie_speed(hwmgr);
+	data->vbios_boot_state.pcie_lane_bootup_value =
+			(uint16_t)tonga_get_current_pcie_lane_number(hwmgr);
+
+	/* set boot power state */
+	ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
+	ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
+	ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
+	ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
+
+	return 0;
+}
+
+static int tonga_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
+		void *state, struct pp_power_state *power_state,
+		void *pp_table, uint32_t classification_flag)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	struct tonga_power_state  *tonga_ps =
+			(struct tonga_power_state *)(&(power_state->hardware));
+
+	struct tonga_performance_level *performance_level;
+
+	ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
+
+	ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
+			(ATOM_Tonga_POWERPLAYTABLE *)pp_table;
+
+	ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
+			(ATOM_Tonga_SCLK_Dependency_Table *)
+			(((unsigned long)powerplay_table) +
+			le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
+
+	ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
+			(ATOM_Tonga_MCLK_Dependency_Table *)
+			(((unsigned long)powerplay_table) +
+			le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
+
+	/* The following fields are not initialized here: id orderedList allStatesList */
+	power_state->classification.ui_label =
+			(le16_to_cpu(state_entry->usClassification) &
+			ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
+			ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
+	power_state->classification.flags = classification_flag;
+	/* NOTE: There is a classification2 flag in BIOS that is not being used right now */
+
+	power_state->classification.temporary_state = false;
+	power_state->classification.to_be_deleted = false;
+
+	power_state->validation.disallowOnDC =
+			(0 != (le32_to_cpu(state_entry->ulCapsAndSettings) & ATOM_Tonga_DISALLOW_ON_DC));
+
+	power_state->pcie.lanes = 0;
+
+	power_state->display.disableFrameModulation = false;
+	power_state->display.limitRefreshrate = false;
+	power_state->display.enableVariBright =
+			(0 != (le32_to_cpu(state_entry->ulCapsAndSettings) & ATOM_Tonga_ENABLE_VARIBRIGHT));
+
+	power_state->validation.supportedPowerLevels = 0;
+	power_state->uvd_clocks.VCLK = 0;
+	power_state->uvd_clocks.DCLK = 0;
+	power_state->temperatures.min = 0;
+	power_state->temperatures.max = 0;
+
+	performance_level = &(tonga_ps->performance_levels
+			[tonga_ps->performance_level_count++]);
+
+	PP_ASSERT_WITH_CODE(
+			(tonga_ps->performance_level_count < SMU72_MAX_LEVELS_GRAPHICS),
+			"Performance levels exceeds SMC limit!",
+			return -1);
+
+	PP_ASSERT_WITH_CODE(
+			(tonga_ps->performance_level_count <=
+					hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
+			"Performance levels exceeds Driver limit!",
+			return -1);
+
+	/* Performance levels are arranged from low to high. */
+	performance_level->memory_clock =
+				le32_to_cpu(mclk_dep_table->entries[state_entry->ucMemoryClockIndexLow].ulMclk);
+
+	performance_level->engine_clock =
+				le32_to_cpu(sclk_dep_table->entries[state_entry->ucEngineClockIndexLow].ulSclk);
+
+	performance_level->pcie_gen = get_pcie_gen_support(
+							data->pcie_gen_cap,
+					     state_entry->ucPCIEGenLow);
+
+	performance_level->pcie_lane = get_pcie_lane_support(
+						    data->pcie_lane_cap,
+					   state_entry->ucPCIELaneHigh);
+
+	performance_level =
+			&(tonga_ps->performance_levels[tonga_ps->performance_level_count++]);
+
+	performance_level->memory_clock =
+				le32_to_cpu(mclk_dep_table->entries[state_entry->ucMemoryClockIndexHigh].ulMclk);
+
+	performance_level->engine_clock =
+				le32_to_cpu(sclk_dep_table->entries[state_entry->ucEngineClockIndexHigh].ulSclk);
+
+	performance_level->pcie_gen = get_pcie_gen_support(
+							data->pcie_gen_cap,
+					    state_entry->ucPCIEGenHigh);
+
+	performance_level->pcie_lane = get_pcie_lane_support(
+						    data->pcie_lane_cap,
+					   state_entry->ucPCIELaneHigh);
+
+	return 0;
+}
+
+static int tonga_get_pp_table_entry(struct pp_hwmgr *hwmgr,
+		    unsigned long entry_index, struct pp_power_state *ps)
+{
+	int result;
+	struct tonga_power_state *tonga_ps;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	struct phm_ppt_v1_information *table_info =
+			(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
+					   table_info->vdd_dep_on_mclk;
+
+	ps->hardware.magic = PhwTonga_Magic;
+
+	tonga_ps = cast_phw_tonga_power_state(&(ps->hardware));
+
+	result = tonga_get_powerplay_table_entry(hwmgr, entry_index, ps,
+			tonga_get_pp_table_entry_callback_func);
+
+	/* This is the earliest time we have all the dependency table and the VBIOS boot state
+	 * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
+	 * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
+	 */
+	if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
+		if (dep_mclk_table->entries[0].clk !=
+				data->vbios_boot_state.mclk_bootup_value)
+			printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
+					"does not match VBIOS boot MCLK level");
+		if (dep_mclk_table->entries[0].vddci !=
+				data->vbios_boot_state.vddci_bootup_value)
+			printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
+					"does not match VBIOS boot VDDCI level");
+	}
+
+	/* set DC compatible flag if this state supports DC */
+	if (!ps->validation.disallowOnDC)
+		tonga_ps->dc_compatible = true;
+
+	if (ps->classification.flags & PP_StateClassificationFlag_ACPI)
+		data->acpi_pcie_gen = tonga_ps->performance_levels[0].pcie_gen;
+	else if (ps->classification.flags & PP_StateClassificationFlag_Boot) {
+		if (data->bacos.best_match == 0xffff) {
+			/* For V.I. use boot state as base BACO state */
+			data->bacos.best_match = PP_StateClassificationFlag_Boot;
+			data->bacos.performance_level = tonga_ps->performance_levels[0];
+		}
+	}
+
+	tonga_ps->uvd_clocks.VCLK = ps->uvd_clocks.VCLK;
+	tonga_ps->uvd_clocks.DCLK = ps->uvd_clocks.DCLK;
+
+	if (!result) {
+		uint32_t i;
+
+		switch (ps->classification.ui_label) {
+		case PP_StateUILabel_Performance:
+			data->use_pcie_performance_levels = true;
+
+			for (i = 0; i < tonga_ps->performance_level_count; i++) {
+				if (data->pcie_gen_performance.max <
+						tonga_ps->performance_levels[i].pcie_gen)
+					data->pcie_gen_performance.max =
+							tonga_ps->performance_levels[i].pcie_gen;
+
+				if (data->pcie_gen_performance.min >
+						tonga_ps->performance_levels[i].pcie_gen)
+					data->pcie_gen_performance.min =
+							tonga_ps->performance_levels[i].pcie_gen;
+
+				if (data->pcie_lane_performance.max <
+						tonga_ps->performance_levels[i].pcie_lane)
+					data->pcie_lane_performance.max =
+							tonga_ps->performance_levels[i].pcie_lane;
+
+				if (data->pcie_lane_performance.min >
+						tonga_ps->performance_levels[i].pcie_lane)
+					data->pcie_lane_performance.min =
+							tonga_ps->performance_levels[i].pcie_lane;
+			}
+			break;
+		case PP_StateUILabel_Battery:
+			data->use_pcie_power_saving_levels = true;
+
+			for (i = 0; i < tonga_ps->performance_level_count; i++) {
+				if (data->pcie_gen_power_saving.max <
+						tonga_ps->performance_levels[i].pcie_gen)
+					data->pcie_gen_power_saving.max =
+							tonga_ps->performance_levels[i].pcie_gen;
+
+				if (data->pcie_gen_power_saving.min >
+						tonga_ps->performance_levels[i].pcie_gen)
+					data->pcie_gen_power_saving.min =
+							tonga_ps->performance_levels[i].pcie_gen;
+
+				if (data->pcie_lane_power_saving.max <
+						tonga_ps->performance_levels[i].pcie_lane)
+					data->pcie_lane_power_saving.max =
+							tonga_ps->performance_levels[i].pcie_lane;
+
+				if (data->pcie_lane_power_saving.min >
+						tonga_ps->performance_levels[i].pcie_lane)
+					data->pcie_lane_power_saving.min =
+							tonga_ps->performance_levels[i].pcie_lane;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+static void
+tonga_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
+{
+	uint32_t sclk, mclk, activity_percent;
+	uint32_t offset;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetSclkFrequency));
+
+	sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+
+	smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetMclkFrequency));
+
+	mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+	seq_printf(m, "\n [  mclk  ]: %u MHz\n\n [  sclk  ]: %u MHz\n", mclk/100, sclk/100);
+
+
+	offset = data->soft_regs_start + offsetof(SMU72_SoftRegisters, AverageGraphicsActivity);
+	activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
+	activity_percent += 0x80;
+	activity_percent >>= 8;
+
+	seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
+
+}
+
+static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
+{
+	const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+	const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	struct tonga_single_dpm_table *psclk_table = &(data->dpm_table.sclk_table);
+	uint32_t sclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
+	struct tonga_single_dpm_table *pmclk_table = &(data->dpm_table.mclk_table);
+	uint32_t mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
+	struct PP_Clocks min_clocks = {0};
+	uint32_t i;
+	struct cgs_display_info info = {0};
+
+	data->need_update_smu7_dpm_table = 0;
+
+	for (i = 0; i < psclk_table->count; i++) {
+		if (sclk == psclk_table->dpm_levels[i].value)
+			break;
+	}
+
+	if (i >= psclk_table->count)
+		data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
+	else {
+	/* TODO: Check SCLK in DAL's minimum clocks in case DeepSleep divider update is required.*/
+		if(data->display_timing.min_clock_insr != min_clocks.engineClockInSR)
+			data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
+	}
+
+	for (i=0; i < pmclk_table->count; i++) {
+		if (mclk == pmclk_table->dpm_levels[i].value)
+			break;
+	}
+
+	if (i >= pmclk_table->count)
+		data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+
+	if (data->display_timing.num_existing_displays != info.display_count)
+		data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
+
+	return 0;
+}
+
+static uint16_t tonga_get_maximum_link_speed(struct pp_hwmgr *hwmgr, const struct tonga_power_state *hw_ps)
+{
+	uint32_t i;
+	uint32_t sclk, max_sclk = 0;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	struct tonga_dpm_table *pdpm_table = &data->dpm_table;
+
+	for (i = 0; i < hw_ps->performance_level_count; i++) {
+		sclk = hw_ps->performance_levels[i].engine_clock;
+		if (max_sclk < sclk)
+			max_sclk = sclk;
+	}
+
+	for (i = 0; i < pdpm_table->sclk_table.count; i++) {
+		if (pdpm_table->sclk_table.dpm_levels[i].value == max_sclk)
+			return (uint16_t) ((i >= pdpm_table->pcie_speed_table.count) ?
+					pdpm_table->pcie_speed_table.dpm_levels[pdpm_table->pcie_speed_table.count-1].value :
+					pdpm_table->pcie_speed_table.dpm_levels[i].value);
+	}
+
+	return 0;
+}
+
+static int tonga_request_link_speed_change_before_state_change(struct pp_hwmgr *hwmgr, const void *input)
+{
+	const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	const struct tonga_power_state *tonga_nps = cast_const_phw_tonga_power_state(states->pnew_state);
+	const struct tonga_power_state *tonga_cps = cast_const_phw_tonga_power_state(states->pcurrent_state);
+
+	uint16_t target_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_nps);
+	uint16_t current_link_speed;
+
+	if (data->force_pcie_gen == PP_PCIEGenInvalid)
+		current_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_cps);
+	else
+		current_link_speed = data->force_pcie_gen;
+
+	data->force_pcie_gen = PP_PCIEGenInvalid;
+	data->pspp_notify_required = false;
+	if (target_link_speed > current_link_speed) {
+		switch(target_link_speed) {
+		case PP_PCIEGen3:
+			if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
+				break;
+			data->force_pcie_gen = PP_PCIEGen2;
+			if (current_link_speed == PP_PCIEGen2)
+				break;
+		case PP_PCIEGen2:
+			if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
+				break;
+		default:
+			data->force_pcie_gen = tonga_get_current_pcie_speed(hwmgr);
+			break;
+		}
+	} else {
+		if (target_link_speed < current_link_speed)
+			data->pspp_notify_required = true;
+	}
+
+	return 0;
+}
+
+static int tonga_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	if (0 == data->need_update_smu7_dpm_table)
+		return 0;
+
+	if ((0 == data->sclk_dpm_key_disabled) &&
+		(data->need_update_smu7_dpm_table &
+		(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+		PP_ASSERT_WITH_CODE(
+			true == tonga_is_dpm_running(hwmgr),
+			"Trying to freeze SCLK DPM when DPM is disabled",
+			);
+		PP_ASSERT_WITH_CODE(
+			0 == smum_send_msg_to_smc(hwmgr->smumgr,
+					  PPSMC_MSG_SCLKDPM_FreezeLevel),
+			"Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
+			return -1);
+	}
+
+	if ((0 == data->mclk_dpm_key_disabled) &&
+		(data->need_update_smu7_dpm_table &
+		 DPMTABLE_OD_UPDATE_MCLK)) {
+		PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr),
+			"Trying to freeze MCLK DPM when DPM is disabled",
+			);
+		PP_ASSERT_WITH_CODE(
+			0 == smum_send_msg_to_smc(hwmgr->smumgr,
+							PPSMC_MSG_MCLKDPM_FreezeLevel),
+			"Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
+			return -1);
+	}
+
+	return 0;
+}
+
+static int tonga_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr *hwmgr, const void *input)
+{
+	int result = 0;
+
+	const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+	const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	uint32_t sclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
+	uint32_t mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
+	struct tonga_dpm_table *pdpm_table = &data->dpm_table;
+
+	struct tonga_dpm_table *pgolden_dpm_table = &data->golden_dpm_table;
+	uint32_t dpm_count, clock_percent;
+	uint32_t i;
+
+	if (0 == data->need_update_smu7_dpm_table)
+		return 0;
+
+	if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
+		pdpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value = sclk;
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
+		    phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
+		/* Need to do calculation based on the golden DPM table
+		 * as the Heatmap GPU Clock axis is also based on the default values
+		 */
+			PP_ASSERT_WITH_CODE(
+				(pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value != 0),
+				"Divide by 0!",
+				return -1);
+			dpm_count = pdpm_table->sclk_table.count < 2 ? 0 : pdpm_table->sclk_table.count-2;
+			for (i = dpm_count; i > 1; i--) {
+				if (sclk > pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value) {
+					clock_percent = ((sclk - pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value)*100) /
+							pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value;
+
+					pdpm_table->sclk_table.dpm_levels[i].value =
+							pgolden_dpm_table->sclk_table.dpm_levels[i].value +
+							(pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100;
+
+				} else if (pgolden_dpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value > sclk) {
+					clock_percent = ((pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value - sclk)*100) /
+								pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value;
+
+					pdpm_table->sclk_table.dpm_levels[i].value =
+							pgolden_dpm_table->sclk_table.dpm_levels[i].value -
+							(pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100;
+				} else
+					pdpm_table->sclk_table.dpm_levels[i].value =
+							pgolden_dpm_table->sclk_table.dpm_levels[i].value;
+			}
+		}
+	}
+
+	if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
+		pdpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value = mclk;
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
+			phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
+
+			PP_ASSERT_WITH_CODE(
+					(pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value != 0),
+					"Divide by 0!",
+					return -1);
+			dpm_count = pdpm_table->mclk_table.count < 2? 0 : pdpm_table->mclk_table.count-2;
+			for (i = dpm_count; i > 1; i--) {
+				if (mclk > pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value) {
+						clock_percent = ((mclk - pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value)*100) /
+								    pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value;
+
+						pdpm_table->mclk_table.dpm_levels[i].value =
+										pgolden_dpm_table->mclk_table.dpm_levels[i].value +
+										(pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100;
+
+				} else if (pgolden_dpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value > mclk) {
+						clock_percent = ((pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value - mclk)*100) /
+								    pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value;
+
+						pdpm_table->mclk_table.dpm_levels[i].value =
+									pgolden_dpm_table->mclk_table.dpm_levels[i].value -
+									(pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100;
+				} else
+					pdpm_table->mclk_table.dpm_levels[i].value = pgolden_dpm_table->mclk_table.dpm_levels[i].value;
+			}
+		}
+	}
+
+	if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
+		result = tonga_populate_all_memory_levels(hwmgr);
+		PP_ASSERT_WITH_CODE((0 == result),
+			"Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
+			return result);
+	}
+
+	if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
+		/*populate MCLK dpm table to SMU7 */
+		result = tonga_populate_all_memory_levels(hwmgr);
+		PP_ASSERT_WITH_CODE((0 == result),
+				"Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
+				return result);
+	}
+
+	return result;
+}
+
+static	int tonga_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
+			  struct tonga_single_dpm_table * pdpm_table,
+			     uint32_t low_limit, uint32_t high_limit)
+{
+	uint32_t i;
+
+	for (i = 0; i < pdpm_table->count; i++) {
+		if ((pdpm_table->dpm_levels[i].value < low_limit) ||
+		    (pdpm_table->dpm_levels[i].value > high_limit))
+			pdpm_table->dpm_levels[i].enabled = false;
+		else
+			pdpm_table->dpm_levels[i].enabled = true;
+	}
+	return 0;
+}
+
+static int tonga_trim_dpm_states(struct pp_hwmgr *hwmgr, const struct tonga_power_state *hw_state)
+{
+	int result = 0;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	uint32_t high_limit_count;
+
+	PP_ASSERT_WITH_CODE((hw_state->performance_level_count >= 1),
+				"power state did not have any performance level",
+				 return -1);
+
+	high_limit_count = (1 == hw_state->performance_level_count) ? 0: 1;
+
+	tonga_trim_single_dpm_states(hwmgr,
+					&(data->dpm_table.sclk_table),
+					hw_state->performance_levels[0].engine_clock,
+					hw_state->performance_levels[high_limit_count].engine_clock);
+
+	tonga_trim_single_dpm_states(hwmgr,
+						&(data->dpm_table.mclk_table),
+						hw_state->performance_levels[0].memory_clock,
+						hw_state->performance_levels[high_limit_count].memory_clock);
+
+	return result;
+}
+
+static int tonga_generate_dpm_level_enable_mask(struct pp_hwmgr *hwmgr, const void *input)
+{
+	int result;
+	const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
+
+	result = tonga_trim_dpm_states(hwmgr, tonga_ps);
+	if (0 != result)
+		return result;
+
+	data->dpm_level_enable_mask.sclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
+	data->dpm_level_enable_mask.mclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
+	data->last_mclk_dpm_enable_mask = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+	if (data->uvd_enabled)
+		data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
+
+	data->dpm_level_enable_mask.pcie_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
+
+	return 0;
+}
+
+int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+	return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+				  (PPSMC_Msg)PPSMC_MSG_VCEDPM_Enable :
+				  (PPSMC_Msg)PPSMC_MSG_VCEDPM_Disable);
+}
+
+int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+	return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+				  (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
+				  (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
+}
+
+int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	uint32_t mm_boot_level_offset, mm_boot_level_value;
+	struct phm_ppt_v1_information *ptable_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (!bgate) {
+		data->smc_state_table.UvdBootLevel = (uint8_t) (ptable_information->mm_dep_table->count - 1);
+		mm_boot_level_offset = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
+		mm_boot_level_offset /= 4;
+		mm_boot_level_offset *= 4;
+		mm_boot_level_value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset);
+		mm_boot_level_value &= 0x00FFFFFF;
+		mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+		if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDDPM) ||
+		    phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+						PPSMC_MSG_UVDDPM_SetEnabledMask,
+						(uint32_t)(1 << data->smc_state_table.UvdBootLevel));
+	}
+
+	return tonga_enable_disable_uvd_dpm(hwmgr, !bgate);
+}
+
+int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
+{
+	const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	const struct tonga_power_state *tonga_nps = cast_const_phw_tonga_power_state(states->pnew_state);
+	const struct tonga_power_state *tonga_cps = cast_const_phw_tonga_power_state(states->pcurrent_state);
+
+	uint32_t mm_boot_level_offset, mm_boot_level_value;
+	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (tonga_nps->vce_clocks.EVCLK > 0 && (tonga_cps == NULL || tonga_cps->vce_clocks.EVCLK == 0)) {
+		data->smc_state_table.VceBootLevel = (uint8_t) (pptable_info->mm_dep_table->count - 1);
+
+		mm_boot_level_offset = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
+		mm_boot_level_offset /= 4;
+		mm_boot_level_offset *= 4;
+		mm_boot_level_value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset);
+		mm_boot_level_value &= 0xFF00FFFF;
+		mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
+		cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
+			smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+					PPSMC_MSG_VCEDPM_SetEnabledMask,
+				(uint32_t)(1 << data->smc_state_table.VceBootLevel));
+
+		tonga_enable_disable_vce_dpm(hwmgr, true);
+	} else if (tonga_nps->vce_clocks.EVCLK == 0 && tonga_cps != NULL && tonga_cps->vce_clocks.EVCLK > 0)
+		tonga_enable_disable_vce_dpm(hwmgr, false);
+
+	return 0;
+}
+
+static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	uint32_t address;
+	int32_t result;
+
+	if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
+		return 0;
+
+
+	memset(&data->mc_reg_table, 0, sizeof(SMU72_Discrete_MCRegisters));
+
+	result = tonga_convert_mc_reg_table_to_smc(hwmgr, &(data->mc_reg_table));
+
+	if(result != 0)
+		return result;
+
+
+	address = data->mc_reg_table_start + (uint32_t)offsetof(SMU72_Discrete_MCRegisters, data[0]);
+
+	return  tonga_copy_bytes_to_smc(hwmgr->smumgr, address,
+				 (uint8_t *)&data->mc_reg_table.data[0],
+				sizeof(SMU72_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
+				data->sram_end);
+}
+
+static int tonga_program_memory_timing_parameters_conditionally(struct pp_hwmgr *hwmgr)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	if (data->need_update_smu7_dpm_table &
+		(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+		return tonga_program_memory_timing_parameters(hwmgr);
+
+	return 0;
+}
+
+static int tonga_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+	if (0 == data->need_update_smu7_dpm_table)
+		return 0;
+
+	if ((0 == data->sclk_dpm_key_disabled) &&
+		(data->need_update_smu7_dpm_table &
+		(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+
+		PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr),
+			"Trying to Unfreeze SCLK DPM when DPM is disabled",
+			);
+		PP_ASSERT_WITH_CODE(
+			 0 == smum_send_msg_to_smc(hwmgr->smumgr,
+					 PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+			"Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
+			return -1);
+	}
+
+	if ((0 == data->mclk_dpm_key_disabled) &&
+		(data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
+
+		PP_ASSERT_WITH_CODE(
+				true == tonga_is_dpm_running(hwmgr),
+				"Trying to Unfreeze MCLK DPM when DPM is disabled",
+				);
+		PP_ASSERT_WITH_CODE(
+			 0 == smum_send_msg_to_smc(hwmgr->smumgr,
+					 PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+		    "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
+		    return -1);
+	}
+
+	data->need_update_smu7_dpm_table = 0;
+
+	return 0;
+}
+
+static int tonga_notify_link_speed_change_after_state_change(struct pp_hwmgr *hwmgr, const void *input)
+{
+	const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
+	uint16_t target_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_ps);
+	uint8_t  request;
+
+	if (data->pspp_notify_required  ||
+	    data->pcie_performance_request) {
+		if (target_link_speed == PP_PCIEGen3)
+			request = PCIE_PERF_REQ_GEN3;
+		else if (target_link_speed == PP_PCIEGen2)
+			request = PCIE_PERF_REQ_GEN2;
+		else
+			request = PCIE_PERF_REQ_GEN1;
+
+		if(request == PCIE_PERF_REQ_GEN1 && tonga_get_current_pcie_speed(hwmgr) > 0) {
+			data->pcie_performance_request = false;
+			return 0;
+		}
+
+		if (0 != acpi_pcie_perf_request(hwmgr->device, request, false)) {
+			if (PP_PCIEGen2 == target_link_speed)
+				printk("PSPP request to switch to Gen2 from Gen3 Failed!");
+			else
+				printk("PSPP request to switch to Gen1 from Gen2 Failed!");
+		}
+	}
+
+	data->pcie_performance_request = false;
+	return 0;
+}
+
+static int tonga_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
+{
+	int tmp_result, result = 0;
+
+	tmp_result = tonga_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to find DPM states clocks in DPM table!", result = tmp_result);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) {
+		tmp_result = tonga_request_link_speed_change_before_state_change(hwmgr, input);
+		PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to request link speed change before state change!", result = tmp_result);
+	}
+
+	tmp_result = tonga_freeze_sclk_mclk_dpm(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
+
+	tmp_result = tonga_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to populate and upload SCLK MCLK DPM levels!", result = tmp_result);
+
+	tmp_result = tonga_generate_dpm_level_enable_mask(hwmgr, input);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to generate DPM level enabled mask!", result = tmp_result);
+
+	tmp_result = tonga_update_vce_dpm(hwmgr, input);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update VCE DPM!", result = tmp_result);
+
+	tmp_result = tonga_update_sclk_threshold(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update SCLK threshold!", result = tmp_result);
+
+	tmp_result = tonga_update_and_upload_mc_reg_table(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload MC reg table!", result = tmp_result);
+
+	tmp_result = tonga_program_memory_timing_parameters_conditionally(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to program memory timing parameters!", result = tmp_result);
+
+	tmp_result = tonga_unfreeze_sclk_mclk_dpm(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to unfreeze SCLK MCLK DPM!", result = tmp_result);
+
+	tmp_result = tonga_upload_dpm_level_enable_mask(hwmgr);
+	PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload DPM level enabled mask!", result = tmp_result);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) {
+		tmp_result = tonga_notify_link_speed_change_after_state_change(hwmgr, input);
+		PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to notify link speed change after state change!", result = tmp_result);
+	}
+
+	return result;
+}
+
+/**
+*  Set maximum target operating fan output PWM
+*
+* @param    pHwMgr:  the address of the powerplay hardware manager.
+* @param    usMaxFanPwm:  max operating fan PWM in percents
+* @return   The response that came from the SMC.
+*/
+static int tonga_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
+{
+	hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
+
+	if (phm_is_hw_access_blocked(hwmgr))
+		return 0;
+
+	return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm) ? 0 : -1);
+}
+
+int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
+{
+	uint32_t num_active_displays = 0;
+	struct cgs_display_info info = {0};
+	info.mode_info = NULL;
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+
+	num_active_displays = info.display_count;
+
+	if (num_active_displays > 1)  /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
+		tonga_notify_smc_display_change(hwmgr, false);
+	else
+		tonga_notify_smc_display_change(hwmgr, true);
+
+	return 0;
+}
+
+/**
+* Programs the display gap
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always OK
+*/
+int tonga_program_display_gap(struct pp_hwmgr *hwmgr)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	uint32_t num_active_displays = 0;
+	uint32_t display_gap = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
+	uint32_t display_gap2;
+	uint32_t pre_vbi_time_in_us;
+	uint32_t frame_time_in_us;
+	uint32_t ref_clock;
+	uint32_t refresh_rate = 0;
+	struct cgs_display_info info = {0};
+	struct cgs_mode_info mode_info;
+
+	info.mode_info = &mode_info;
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+	num_active_displays = info.display_count;
+
+	display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, DISP_GAP, (num_active_displays > 0)? DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL, display_gap);
+
+	ref_clock = mode_info.ref_clock;
+	refresh_rate = mode_info.refresh_rate;
+
+	if(0 == refresh_rate)
+		refresh_rate = 60;
+
+	frame_time_in_us = 1000000 / refresh_rate;
+
+	pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
+	display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU72_SoftRegisters, PreVBlankGap), 0x64);
+
+	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU72_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
+
+	if (num_active_displays == 1)
+		tonga_notify_smc_display_change(hwmgr, true);
+
+	return 0;
+}
+
+int tonga_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
+{
+
+	tonga_program_display_gap(hwmgr);
+
+	/* to do PhwTonga_CacUpdateDisplayConfiguration(pHwMgr); */
+	return 0;
+}
+
+/**
+*  Set maximum target operating fan output RPM
+*
+* @param    pHwMgr:  the address of the powerplay hardware manager.
+* @param    usMaxFanRpm:  max operating fan RPM value.
+* @return   The response that came from the SMC.
+*/
+static int tonga_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
+{
+	hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM = us_max_fan_pwm;
+
+	if (phm_is_hw_access_blocked(hwmgr))
+		return 0;
+
+	return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanRpmMax, us_max_fan_pwm) ? 0 : -1);
+}
+
+uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr)
+{
+	uint32_t reference_clock;
+	uint32_t tc;
+	uint32_t divide;
+
+	ATOM_FIRMWARE_INFO *fw_info;
+	uint16_t size;
+	uint8_t frev, crev;
+	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+
+	tc = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK);
+
+	if (tc)
+		return TCLK;
+
+	fw_info = (ATOM_FIRMWARE_INFO *)cgs_atom_get_data_table(hwmgr->device, index,
+						  &size, &frev, &crev);
+
+	if (!fw_info)
+		return 0;
+
+	reference_clock = le16_to_cpu(fw_info->usMinPixelClockPLL_Output);
+
+	divide = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL, XTALIN_DIVIDE);
+
+	if (0 != divide)
+		return reference_clock / 4;
+
+	return reference_clock;
+}
+
+int tonga_dpm_set_interrupt_state(void *private_data,
+					 unsigned src_id, unsigned type,
+					 int enabled)
+{
+	uint32_t cg_thermal_int;
+	struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
+
+	if (hwmgr == NULL)
+		return -EINVAL;
+
+	switch (type) {
+	case AMD_THERMAL_IRQ_LOW_TO_HIGH:
+		if (enabled) {
+			cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+			cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+		} else {
+			cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+			cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+		}
+		break;
+
+	case AMD_THERMAL_IRQ_HIGH_TO_LOW:
+		if (enabled) {
+			cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+			cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+		} else {
+			cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+			cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+			cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+int tonga_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
+					const void *thermal_interrupt_info)
+{
+	int result;
+	const struct pp_interrupt_registration_info *info =
+			(const struct pp_interrupt_registration_info *)thermal_interrupt_info;
+
+	if (info == NULL)
+		return -EINVAL;
+
+	result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
+				tonga_dpm_set_interrupt_state,
+				info->call_back, info->context);
+
+	if (result)
+		return -EINVAL;
+
+	result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
+				tonga_dpm_set_interrupt_state,
+				info->call_back, info->context);
+
+	if (result)
+		return -EINVAL;
+
+	return 0;
+}
+
+bool tonga_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	bool is_update_required = false;
+	struct cgs_display_info info = {0,0,NULL};
+
+	cgs_get_active_displays_info(hwmgr->device, &info);
+
+	if (data->display_timing.num_existing_displays != info.display_count)
+		is_update_required = true;
+/* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL
+	if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
+		cgs_get_min_clock_settings(hwmgr->device, &min_clocks);
+		if(min_clocks.engineClockInSR != data->display_timing.minClockInSR)
+			is_update_required = true;
+*/
+	return is_update_required;
+}
+
+static inline bool tonga_are_power_levels_equal(const struct tonga_performance_level *pl1,
+							   const struct tonga_performance_level *pl2)
+{
+	return ((pl1->memory_clock == pl2->memory_clock) &&
+		  (pl1->engine_clock == pl2->engine_clock) &&
+		  (pl1->pcie_gen == pl2->pcie_gen) &&
+		  (pl1->pcie_lane == pl2->pcie_lane));
+}
+
+int tonga_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
+{
+	const struct tonga_power_state *psa = cast_const_phw_tonga_power_state(pstate1);
+	const struct tonga_power_state *psb = cast_const_phw_tonga_power_state(pstate2);
+	int i;
+
+	if (equal == NULL || psa == NULL || psb == NULL)
+		return -EINVAL;
+
+	/* If the two states don't even have the same number of performance levels they cannot be the same state. */
+	if (psa->performance_level_count != psb->performance_level_count) {
+		*equal = false;
+		return 0;
+	}
+
+	for (i = 0; i < psa->performance_level_count; i++) {
+		if (!tonga_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
+			/* If we have found even one performance level pair that is different the states are different. */
+			*equal = false;
+			return 0;
+		}
+	}
+
+	/* If all performance levels are the same try to use the UVD clocks to break the tie.*/
+	*equal = ((psa->uvd_clocks.VCLK == psb->uvd_clocks.VCLK) && (psa->uvd_clocks.DCLK == psb->uvd_clocks.DCLK));
+	*equal &= ((psa->vce_clocks.EVCLK == psb->vce_clocks.EVCLK) && (psa->vce_clocks.ECCLK == psb->vce_clocks.ECCLK));
+	*equal &= (psa->sclk_threshold == psb->sclk_threshold);
+	*equal &= (psa->acp_clk == psb->acp_clk);
+
+	return 0;
+}
+
+static int tonga_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+	if (mode) {
+		/* stop auto-manage */
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+				PHM_PlatformCaps_MicrocodeFanControl))
+			tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
+		tonga_fan_ctrl_set_static_mode(hwmgr, mode);
+	} else
+		/* restart auto-manage */
+		tonga_fan_ctrl_reset_fan_speed_to_default(hwmgr);
+
+	return 0;
+}
+
+static int tonga_get_fan_control_mode(struct pp_hwmgr *hwmgr)
+{
+	if (hwmgr->fan_ctrl_is_in_default_mode)
+		return hwmgr->fan_ctrl_default_mode;
+	else
+		return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				CG_FDO_CTRL2, FDO_PWM_MODE);
+}
+
+static const struct pp_hwmgr_func tonga_hwmgr_funcs = {
+	.backend_init = &tonga_hwmgr_backend_init,
+	.backend_fini = &tonga_hwmgr_backend_fini,
+	.asic_setup = &tonga_setup_asic_task,
+	.dynamic_state_management_enable = &tonga_enable_dpm_tasks,
+	.apply_state_adjust_rules = tonga_apply_state_adjust_rules,
+	.force_dpm_level = &tonga_force_dpm_level,
+	.power_state_set = tonga_set_power_state_tasks,
+	.get_power_state_size = tonga_get_power_state_size,
+	.get_mclk = tonga_dpm_get_mclk,
+	.get_sclk = tonga_dpm_get_sclk,
+	.patch_boot_state = tonga_dpm_patch_boot_state,
+	.get_pp_table_entry = tonga_get_pp_table_entry,
+	.get_num_of_pp_table_entries = tonga_get_number_of_powerplay_table_entries,
+	.print_current_perforce_level = tonga_print_current_perforce_level,
+	.powerdown_uvd = tonga_phm_powerdown_uvd,
+	.powergate_uvd = tonga_phm_powergate_uvd,
+	.powergate_vce = tonga_phm_powergate_vce,
+	.disable_clock_power_gating = tonga_phm_disable_clock_power_gating,
+	.notify_smc_display_config_after_ps_adjustment = tonga_notify_smc_display_config_after_ps_adjustment,
+	.display_config_changed = tonga_display_configuration_changed_task,
+	.set_max_fan_pwm_output = tonga_set_max_fan_pwm_output,
+	.set_max_fan_rpm_output = tonga_set_max_fan_rpm_output,
+	.get_temperature = tonga_thermal_get_temperature,
+	.stop_thermal_controller = tonga_thermal_stop_thermal_controller,
+	.get_fan_speed_info = tonga_fan_ctrl_get_fan_speed_info,
+	.get_fan_speed_percent = tonga_fan_ctrl_get_fan_speed_percent,
+	.set_fan_speed_percent = tonga_fan_ctrl_set_fan_speed_percent,
+	.reset_fan_speed_to_default = tonga_fan_ctrl_reset_fan_speed_to_default,
+	.get_fan_speed_rpm = tonga_fan_ctrl_get_fan_speed_rpm,
+	.set_fan_speed_rpm = tonga_fan_ctrl_set_fan_speed_rpm,
+	.uninitialize_thermal_controller = tonga_thermal_ctrl_uninitialize_thermal_controller,
+	.register_internal_thermal_interrupt = tonga_register_internal_thermal_interrupt,
+	.check_smc_update_required_for_display_configuration = tonga_check_smc_update_required_for_display_configuration,
+	.check_states_equal = tonga_check_states_equal,
+	.set_fan_control_mode = tonga_set_fan_control_mode,
+	.get_fan_control_mode = tonga_get_fan_control_mode,
+};
+
+int tonga_hwmgr_init(struct pp_hwmgr *hwmgr)
+{
+	tonga_hwmgr  *data;
+
+	data = kzalloc (sizeof(tonga_hwmgr), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+	memset(data, 0x00, sizeof(tonga_hwmgr));
+
+	hwmgr->backend = data;
+	hwmgr->hwmgr_func = &tonga_hwmgr_funcs;
+	hwmgr->pptable_func = &tonga_pptable_funcs;
+	pp_tonga_thermal_initialize(hwmgr);
+	return 0;
+}
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef TONGA_HWMGR_H
+#define TONGA_HWMGR_H
+
+#include "hwmgr.h"
+#include "smu72_discrete.h"
+#include "ppatomctrl.h"
+#include "ppinterrupt.h"
+#include "tonga_powertune.h"
+
+#define TONGA_MAX_HARDWARE_POWERLEVELS 2
+#define TONGA_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15
+
+struct tonga_performance_level {
+	uint32_t	memory_clock;
+	uint32_t	engine_clock;
+	uint16_t    pcie_gen;
+	uint16_t    pcie_lane;
+};
+
+struct _phw_tonga_bacos {
+	uint32_t                          best_match;
+	uint32_t                          baco_flags;
+	struct tonga_performance_level		  performance_level;
+};
+typedef struct _phw_tonga_bacos phw_tonga_bacos;
+
+struct _phw_tonga_uvd_clocks {
+	uint32_t   VCLK;
+	uint32_t   DCLK;
+};
+
+typedef struct _phw_tonga_uvd_clocks phw_tonga_uvd_clocks;
+
+struct _phw_tonga_vce_clocks {
+	uint32_t   EVCLK;
+	uint32_t   ECCLK;
+};
+
+typedef struct _phw_tonga_vce_clocks phw_tonga_vce_clocks;
+
+struct tonga_power_state {
+	uint32_t                    magic;
+	phw_tonga_uvd_clocks        uvd_clocks;
+	phw_tonga_vce_clocks        vce_clocks;
+	uint32_t                    sam_clk;
+	uint32_t                    acp_clk;
+	uint16_t                    performance_level_count;
+	bool                        dc_compatible;
+	uint32_t                    sclk_threshold;
+	struct tonga_performance_level performance_levels[TONGA_MAX_HARDWARE_POWERLEVELS];
+};
+
+struct _phw_tonga_dpm_level {
+	bool  		enabled;
+	uint32_t    value;
+	uint32_t    param1;
+};
+typedef struct _phw_tonga_dpm_level phw_tonga_dpm_level;
+
+#define TONGA_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define MAX_REGULAR_DPM_NUMBER 8
+#define TONGA_MINIMUM_ENGINE_CLOCK 2500
+
+struct tonga_single_dpm_table {
+	uint32_t count;
+	phw_tonga_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
+};
+
+struct tonga_dpm_table {
+	struct tonga_single_dpm_table  sclk_table;
+	struct tonga_single_dpm_table  mclk_table;
+	struct tonga_single_dpm_table  pcie_speed_table;
+	struct tonga_single_dpm_table  vddc_table;
+	struct tonga_single_dpm_table  vdd_gfx_table;
+	struct tonga_single_dpm_table  vdd_ci_table;
+	struct tonga_single_dpm_table  mvdd_table;
+};
+typedef struct _phw_tonga_dpm_table phw_tonga_dpm_table;
+
+
+struct _phw_tonga_clock_regisiters {
+	uint32_t  vCG_SPLL_FUNC_CNTL;
+	uint32_t  vCG_SPLL_FUNC_CNTL_2;
+	uint32_t  vCG_SPLL_FUNC_CNTL_3;
+	uint32_t  vCG_SPLL_FUNC_CNTL_4;
+	uint32_t  vCG_SPLL_SPREAD_SPECTRUM;
+	uint32_t  vCG_SPLL_SPREAD_SPECTRUM_2;
+	uint32_t  vDLL_CNTL;
+	uint32_t  vMCLK_PWRMGT_CNTL;
+	uint32_t  vMPLL_AD_FUNC_CNTL;
+	uint32_t  vMPLL_DQ_FUNC_CNTL;
+	uint32_t  vMPLL_FUNC_CNTL;
+	uint32_t  vMPLL_FUNC_CNTL_1;
+	uint32_t  vMPLL_FUNC_CNTL_2;
+	uint32_t  vMPLL_SS1;
+	uint32_t  vMPLL_SS2;
+};
+typedef struct _phw_tonga_clock_regisiters phw_tonga_clock_registers;
+
+struct _phw_tonga_voltage_smio_registers {
+	uint32_t vs0_vid_lower_smio_cntl;
+};
+typedef struct _phw_tonga_voltage_smio_registers phw_tonga_voltage_smio_registers;
+
+
+struct _phw_tonga_mc_reg_entry {
+	uint32_t mclk_max;
+	uint32_t mc_data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+typedef struct _phw_tonga_mc_reg_entry phw_tonga_mc_reg_entry;
+
+struct _phw_tonga_mc_reg_table {
+	uint8_t   last;               /* number of registers*/
+	uint8_t   num_entries;        /* number of entries in mc_reg_table_entry used*/
+	uint16_t  validflag;          /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
+	phw_tonga_mc_reg_entry    mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+	SMU72_Discrete_MCRegisterAddress mc_reg_address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+typedef struct _phw_tonga_mc_reg_table phw_tonga_mc_reg_table;
+
+#define DISABLE_MC_LOADMICROCODE   1
+#define DISABLE_MC_CFGPROGRAMMING  2
+
+/*Ultra Low Voltage parameter structure */
+struct _phw_tonga_ulv_parm{
+	bool	ulv_supported;
+	uint32_t   ch_ulv_parameter;
+	uint32_t   ulv_volt_change_delay;
+	struct tonga_performance_level   ulv_power_level;
+};
+typedef struct _phw_tonga_ulv_parm phw_tonga_ulv_parm;
+
+#define TONGA_MAX_LEAKAGE_COUNT  8
+
+struct _phw_tonga_leakage_voltage {
+	uint16_t  count;
+	uint16_t  leakage_id[TONGA_MAX_LEAKAGE_COUNT];
+	uint16_t  actual_voltage[TONGA_MAX_LEAKAGE_COUNT];
+};
+typedef struct _phw_tonga_leakage_voltage phw_tonga_leakage_voltage;
+
+struct _phw_tonga_display_timing {
+	uint32_t min_clock_insr;
+	uint32_t num_existing_displays;
+};
+typedef struct _phw_tonga_display_timing phw_tonga_display_timing;
+
+struct _phw_tonga_dpmlevel_enable_mask {
+	uint32_t uvd_dpm_enable_mask;
+	uint32_t vce_dpm_enable_mask;
+	uint32_t acp_dpm_enable_mask;
+	uint32_t samu_dpm_enable_mask;
+	uint32_t sclk_dpm_enable_mask;
+	uint32_t mclk_dpm_enable_mask;
+	uint32_t pcie_dpm_enable_mask;
+};
+typedef struct _phw_tonga_dpmlevel_enable_mask phw_tonga_dpmlevel_enable_mask;
+
+struct _phw_tonga_pcie_perf_range {
+	uint16_t max;
+	uint16_t min;
+};
+typedef struct _phw_tonga_pcie_perf_range phw_tonga_pcie_perf_range;
+
+struct _phw_tonga_vbios_boot_state {
+	uint16_t					mvdd_bootup_value;
+	uint16_t					vddc_bootup_value;
+	uint16_t					vddci_bootup_value;
+	uint16_t					vddgfx_bootup_value;
+	uint32_t					sclk_bootup_value;
+	uint32_t					mclk_bootup_value;
+	uint16_t					pcie_gen_bootup_value;
+	uint16_t					pcie_lane_bootup_value;
+};
+typedef struct _phw_tonga_vbios_boot_state phw_tonga_vbios_boot_state;
+
+#define DPMTABLE_OD_UPDATE_SCLK     0x00000001
+#define DPMTABLE_OD_UPDATE_MCLK     0x00000002
+#define DPMTABLE_UPDATE_SCLK        0x00000004
+#define DPMTABLE_UPDATE_MCLK        0x00000008
+
+/* We need to review which fields are needed. */
+/* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */
+struct tonga_hwmgr {
+	struct tonga_dpm_table               dpm_table;
+	struct tonga_dpm_table               golden_dpm_table;
+
+	uint32_t                           voting_rights_clients0;
+	uint32_t                           voting_rights_clients1;
+	uint32_t                           voting_rights_clients2;
+	uint32_t                           voting_rights_clients3;
+	uint32_t                           voting_rights_clients4;
+	uint32_t                           voting_rights_clients5;
+	uint32_t                           voting_rights_clients6;
+	uint32_t                           voting_rights_clients7;
+	uint32_t                           static_screen_threshold_unit;
+	uint32_t                           static_screen_threshold;
+	uint32_t                           voltage_control;
+	uint32_t                           vdd_gfx_control;
+
+	uint32_t                           vddc_vddci_delta;
+	uint32_t                           vddc_vddgfx_delta;
+
+	struct pp_interrupt_registration_info    internal_high_thermal_interrupt_info;
+	struct pp_interrupt_registration_info    internal_low_thermal_interrupt_info;
+	struct pp_interrupt_registration_info    smc_to_host_interrupt_info;
+	uint32_t                          active_auto_throttle_sources;
+
+	struct pp_interrupt_registration_info    external_throttle_interrupt;
+	irq_handler_func_t             external_throttle_callback;
+	void                             *external_throttle_context;
+
+	struct pp_interrupt_registration_info    ctf_interrupt_info;
+	irq_handler_func_t             ctf_callback;
+	void                             *ctf_context;
+
+	phw_tonga_clock_registers      	  clock_registers;
+	phw_tonga_voltage_smio_registers  voltage_smio_registers;
+
+	bool                         	is_memory_GDDR5;
+	uint16_t                          acpi_vddc;
+	bool                         	pspp_notify_required;        /* Flag to indicate if PSPP notification to SBIOS is required */
+	uint16_t                          force_pcie_gen;            /* The forced PCI-E speed if not 0xffff */
+	uint16_t                          acpi_pcie_gen;             /* The PCI-E speed at ACPI time */
+	uint32_t                           pcie_gen_cap;             /* The PCI-E speed capabilities bitmap from CAIL */
+	uint32_t                           pcie_lane_cap;            /* The PCI-E lane capabilities bitmap from CAIL */
+	uint32_t                           pcie_spc_cap;             /* Symbol Per Clock Capabilities from registry */
+	phw_tonga_leakage_voltage       	vddc_leakage;            /* The Leakage VDDC supported (based on leakage ID).*/
+	phw_tonga_leakage_voltage       	vddcgfx_leakage;         /* The Leakage VDDC supported (based on leakage ID). */
+	phw_tonga_leakage_voltage       	vddci_leakage;           /* The Leakage VDDCI supported (based on leakage ID). */
+
+	uint32_t                           mvdd_control;
+	uint32_t                           vddc_mask_low;
+	uint32_t                           mvdd_mask_low;
+	uint16_t                          max_vddc_in_pp_table;        /* the maximum VDDC value in the powerplay table*/
+	uint16_t                          min_vddc_in_pp_table;
+	uint16_t                          max_vddci_in_pp_table;       /* the maximum VDDCI value in the powerplay table */
+	uint16_t                          min_vddci_in_pp_table;
+	uint32_t                           mclk_strobe_mode_threshold;
+	uint32_t                           mclk_stutter_mode_threshold;
+	uint32_t                           mclk_edc_enable_threshold;
+	uint32_t                           mclk_edc_wr_enable_threshold;
+	bool                         	is_uvd_enabled;
+	bool                         	is_xdma_enabled;
+	phw_tonga_vbios_boot_state      vbios_boot_state;
+
+	bool                         battery_state;
+	bool                         is_tlu_enabled;
+	bool                         pcie_performance_request;
+
+	/* -------------- SMC SRAM Address of firmware header tables ----------------*/
+	uint32_t                           sram_end;                 /* The first address after the SMC SRAM. */
+	uint32_t                           dpm_table_start;          /* The start of the dpm table in the SMC SRAM. */
+	uint32_t                           soft_regs_start;          /* The start of the soft registers in the SMC SRAM. */
+	uint32_t                           mc_reg_table_start;       /* The start of the mc register table in the SMC SRAM. */
+	uint32_t                           fan_table_start;          /* The start of the fan table in the SMC SRAM. */
+	uint32_t                           arb_table_start;          /* The start of the ARB setting table in the SMC SRAM. */
+	SMU72_Discrete_DpmTable         smc_state_table;             /* The carbon copy of the SMC state table. */
+	SMU72_Discrete_MCRegisters      mc_reg_table;
+	SMU72_Discrete_Ulv              ulv_setting;                 /* The carbon copy of ULV setting. */
+	/* -------------- Stuff originally coming from Evergreen --------------------*/
+	phw_tonga_mc_reg_table			tonga_mc_reg_table;
+	uint32_t                         vdd_ci_control;
+	pp_atomctrl_voltage_table        vddc_voltage_table;
+	pp_atomctrl_voltage_table        vddci_voltage_table;
+	pp_atomctrl_voltage_table        vddgfx_voltage_table;
+	pp_atomctrl_voltage_table        mvdd_voltage_table;
+
+	uint32_t                           mgcg_cgtt_local2;
+	uint32_t                           mgcg_cgtt_local3;
+	uint32_t                           gpio_debug;
+	uint32_t							mc_micro_code_feature;
+	uint32_t							highest_mclk;
+	uint16_t                          acpi_vdd_ci;
+	uint8_t                           mvdd_high_index;
+	uint8_t                           mvdd_low_index;
+	bool                         dll_defaule_on;
+	bool                         performance_request_registered;
+
+	/* ----------------- Low Power Features ---------------------*/
+	phw_tonga_bacos					bacos;
+	phw_tonga_ulv_parm              ulv;
+	/* ----------------- CAC Stuff ---------------------*/
+	uint32_t					cac_table_start;
+	bool                         cac_configuration_required;    /* TRUE if PP_CACConfigurationRequired == 1 */
+	bool                         driver_calculate_cac_leakage;  /* TRUE if PP_DriverCalculateCACLeakage == 1 */
+	bool                         cac_enabled;
+	/* ----------------- DPM2 Parameters ---------------------*/
+	uint32_t					power_containment_features;
+	bool                         enable_bapm_feature;
+	bool                         enable_tdc_limit_feature;
+	bool                         enable_pkg_pwr_tracking_feature;
+	bool                         disable_uvd_power_tune_feature;
+	phw_tonga_pt_defaults           *power_tune_defaults;
+	SMU72_Discrete_PmFuses           power_tune_table;
+	uint32_t                           ul_dte_tj_offset;             /* Fudge factor in DPM table to correct HW DTE errors */
+	uint32_t                           fast_watemark_threshold;      /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */
+
+	/* ----------------- Phase Shedding ---------------------*/
+	bool                         vddc_phase_shed_control;
+	/* --------------------- DI/DT --------------------------*/
+	phw_tonga_display_timing       display_timing;
+	/* --------- ReadRegistry data for memory and engine clock margins ---- */
+	uint32_t                           engine_clock_data;
+	uint32_t                           memory_clock_data;
+	/* -------- Thermal Temperature Setting --------------*/
+	phw_tonga_dpmlevel_enable_mask     dpm_level_enable_mask;
+	uint32_t                           need_update_smu7_dpm_table;
+	uint32_t                           sclk_dpm_key_disabled;
+	uint32_t                           mclk_dpm_key_disabled;
+	uint32_t                           pcie_dpm_key_disabled;
+	uint32_t                           min_engine_clocks; /* used to store the previous dal min sclock */
+	phw_tonga_pcie_perf_range       pcie_gen_performance;
+	phw_tonga_pcie_perf_range       pcie_lane_performance;
+	phw_tonga_pcie_perf_range       pcie_gen_power_saving;
+	phw_tonga_pcie_perf_range       pcie_lane_power_saving;
+	bool                            use_pcie_performance_levels;
+	bool                            use_pcie_power_saving_levels;
+	uint32_t                           activity_target[SMU72_MAX_LEVELS_GRAPHICS]; /* percentage value from 0-100, default 50 */
+	uint32_t                           mclk_activity_target;
+	uint32_t                           low_sclk_interrupt_threshold;
+	uint32_t                           last_mclk_dpm_enable_mask;
+	bool								uvd_enabled;
+	uint32_t                           pcc_monitor_enabled;
+
+	/* --------- Power Gating States ------------*/
+	bool                           uvd_power_gated;  /* 1: gated, 0:not gated */
+	bool                           vce_power_gated;  /* 1: gated, 0:not gated */
+	bool                           samu_power_gated; /* 1: gated, 0:not gated */
+	bool                           acp_power_gated;  /* 1: gated, 0:not gated */
+	bool                           pg_acp_init;
+
+};
+
+typedef struct tonga_hwmgr tonga_hwmgr;
+
+#define TONGA_DPM2_NEAR_TDP_DEC          10
+#define TONGA_DPM2_ABOVE_SAFE_INC        5
+#define TONGA_DPM2_BELOW_SAFE_INC        20
+
+#define TONGA_DPM2_LTA_WINDOW_SIZE       7  /* Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size is 128, then this value should be Log2(128) = 7. */
+
+#define TONGA_DPM2_LTS_TRUNCATE          0
+
+#define TONGA_DPM2_TDP_SAFE_LIMIT_PERCENT            80  /* Maximum 100 */
+
+#define TONGA_DPM2_MAXPS_PERCENT_H                   90  /* Maximum 0xFF */
+#define TONGA_DPM2_MAXPS_PERCENT_M                   90  /* Maximum 0xFF */
+
+#define TONGA_DPM2_PWREFFICIENCYRATIO_MARGIN         50
+
+#define TONGA_DPM2_SQ_RAMP_MAX_POWER                 0x3FFF
+#define TONGA_DPM2_SQ_RAMP_MIN_POWER                 0x12
+#define TONGA_DPM2_SQ_RAMP_MAX_POWER_DELTA           0x15
+#define TONGA_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE  0x1E
+#define TONGA_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO  0xF
+
+#define TONGA_VOLTAGE_CONTROL_NONE                   0x0
+#define TONGA_VOLTAGE_CONTROL_BY_GPIO                0x1
+#define TONGA_VOLTAGE_CONTROL_BY_SVID2               0x2
+#define TONGA_VOLTAGE_CONTROL_MERGED                 0x3
+
+#define TONGA_Q88_FORMAT_CONVERSION_UNIT             256 /*To convert to Q8.8 format for firmware */
+
+#define TONGA_UNUSED_GPIO_PIN                        0x7F
+
+#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X)
+#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X)
+
+#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X)
+#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X)
+
+#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X))
+#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X))
+
+#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X))
+
+int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
+int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
+int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable);
+int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
+uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef TONGA_POWERTUNE_H
+#define TONGA_POWERTUNE_H
+
+enum _phw_tonga_ptc_config_reg_type {
+	TONGA_CONFIGREG_MMR = 0,
+	TONGA_CONFIGREG_SMC_IND,
+	TONGA_CONFIGREG_DIDT_IND,
+	TONGA_CONFIGREG_CACHE,
+
+	TONGA_CONFIGREG_MAX
+};
+typedef enum _phw_tonga_ptc_config_reg_type phw_tonga_ptc_config_reg_type;
+
+/* PowerContainment Features */
+#define POWERCONTAINMENT_FEATURE_BAPM            0x00000001
+#define POWERCONTAINMENT_FEATURE_TDCLimit        0x00000002
+#define POWERCONTAINMENT_FEATURE_PkgPwrLimit     0x00000004
+
+struct _phw_tonga_pt_config_reg {
+	uint32_t                           Offset;
+	uint32_t                           Mask;
+	uint32_t                           Shift;
+	uint32_t                           Value;
+	phw_tonga_ptc_config_reg_type     Type;
+};
+typedef struct _phw_tonga_pt_config_reg phw_tonga_pt_config_reg;
+
+struct _phw_tonga_pt_defaults {
+	uint8_t   svi_load_line_en;
+	uint8_t   svi_load_line_vddC;
+	uint8_t   tdc_vddc_throttle_release_limit_perc;
+	uint8_t   tdc_mawt;
+	uint8_t   tdc_waterfall_ctl;
+	uint8_t   dte_ambient_temp_base;
+	uint32_t  display_cac;
+	uint32_t  bamp_temp_gradient;
+	uint16_t  bapmti_r[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
+	uint16_t  bapmti_rc[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
+};
+typedef struct _phw_tonga_pt_defaults phw_tonga_pt_defaults;
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef TONGA_PPTABLE_H
+#define TONGA_PPTABLE_H
+
+/** \file
+ * This is a PowerPlay table header file
+ */
+#pragma pack(push, 1)
+
+#include "hwmgr.h"
+
+#define ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f
+#define ATOM_TONGA_PP_FANPARAMETERS_NOFAN                                 0x80    /* No fan is connected to this controller. */
+
+#define ATOM_TONGA_PP_THERMALCONTROLLER_NONE      0
+#define ATOM_TONGA_PP_THERMALCONTROLLER_LM96163   17
+#define ATOM_TONGA_PP_THERMALCONTROLLER_TONGA     21
+#define ATOM_TONGA_PP_THERMALCONTROLLER_FIJI      22
+
+/*
+ * Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
+ * We probably should reserve the bit 0x80 for this use.
+ * To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here).
+ * The driver can pick the correct internal controller based on the ASIC.
+ */
+
+#define ATOM_TONGA_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL   0x89    /* ADT7473 Fan Control + Internal Thermal Controller */
+#define ATOM_TONGA_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL   0x8D    /* EMC2103 Fan Control + Internal Thermal Controller */
+
+/*/* ATOM_TONGA_POWERPLAYTABLE::ulPlatformCaps */
+#define ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL              0x1            /* This cap indicates whether vddgfx will be a separated power rail. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY                   0x2            /* This cap indicates whether this is a mobile part and CCC need to show Powerplay page. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE            0x4            /* This cap indicates whether power source notificaiton is done by SBIOS directly. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND      0x8            /* Enable the option to overwrite voltage island feature to be disabled, regardless of VddGfx power rail support. */
+#define ____RETIRE16____                                0x10
+#define ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC                 0x20            /* This cap indicates whether power source notificaiton is done by GPIO directly. */
+#define ____RETIRE64____                                0x40
+#define ____RETIRE128____                               0x80
+#define ____RETIRE256____                              0x100
+#define ____RETIRE512____                              0x200
+#define ____RETIRE1024____                             0x400
+#define ____RETIRE2048____                             0x800
+#define ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL             0x1000            /* This cap indicates dynamic MVDD is required. Uncheck to disable it. */
+#define ____RETIRE2000____                            0x2000
+#define ____RETIRE4000____                            0x4000
+#define ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL            0x8000            /* This cap indicates dynamic VDDCI is required. Uncheck to disable it. */
+#define ____RETIRE10000____                          0x10000
+#define ATOM_TONGA_PP_PLATFORM_CAP_BACO                    0x20000            /* Enable to indicate the driver supports BACO state. */
+
+#define ATOM_TONGA_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17         0x100000     /* Enable to indicate the driver supports thermal2GPIO17. */
+#define ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL  0x1000000     /* Enable to indicate if thermal and PCC are sharing the same GPIO */
+#define ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE       0x2000000
+
+/* ATOM_PPLIB_NONCLOCK_INFO::usClassification */
+#define ATOM_PPLIB_CLASSIFICATION_UI_MASK               0x0007
+#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT              0
+#define ATOM_PPLIB_CLASSIFICATION_UI_NONE               0
+#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY            1
+#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED           3
+#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE        5
+/* 2, 4, 6, 7 are reserved */
+
+#define ATOM_PPLIB_CLASSIFICATION_BOOT                  0x0008
+#define ATOM_PPLIB_CLASSIFICATION_THERMAL               0x0010
+#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE    0x0020
+#define ATOM_PPLIB_CLASSIFICATION_REST                  0x0040
+#define ATOM_PPLIB_CLASSIFICATION_FORCED                0x0080
+#define ATOM_PPLIB_CLASSIFICATION_ACPI                  0x1000
+
+/* ATOM_PPLIB_NONCLOCK_INFO::usClassification2 */
+#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001
+
+#define ATOM_Tonga_DISALLOW_ON_DC                       0x00004000
+#define ATOM_Tonga_ENABLE_VARIBRIGHT                    0x00008000
+
+#define ATOM_Tonga_TABLE_REVISION_TONGA                 7
+
+typedef struct _ATOM_Tonga_POWERPLAYTABLE {
+	ATOM_COMMON_TABLE_HEADER sHeader;
+
+	UCHAR  ucTableRevision;
+	USHORT usTableSize;						/*the size of header structure */
+
+	ULONG	ulGoldenPPID;
+	ULONG	ulGoldenRevision;
+	USHORT	usFormatID;
+
+	USHORT	usVoltageTime;					 /*in microseconds */
+	ULONG	ulPlatformCaps;					  /*See ATOM_Tonga_CAPS_* */
+
+	ULONG	ulMaxODEngineClock; 			   /*For Overdrive.  */
+	ULONG	ulMaxODMemoryClock; 			   /*For Overdrive. */
+
+	USHORT	usPowerControlLimit;
+	USHORT	usUlvVoltageOffset;				  /*in mv units */
+
+	USHORT	usStateArrayOffset;				  /*points to ATOM_Tonga_State_Array */
+	USHORT	usFanTableOffset;				  /*points to ATOM_Tonga_Fan_Table */
+	USHORT	usThermalControllerOffset;		   /*points to ATOM_Tonga_Thermal_Controller */
+	USHORT	usReserv;						   /*CustomThermalPolicy removed for Tonga. Keep this filed as reserved. */
+
+	USHORT	usMclkDependencyTableOffset;	   /*points to ATOM_Tonga_MCLK_Dependency_Table */
+	USHORT	usSclkDependencyTableOffset;	   /*points to ATOM_Tonga_SCLK_Dependency_Table */
+	USHORT	usVddcLookupTableOffset;		   /*points to ATOM_Tonga_Voltage_Lookup_Table */
+	USHORT	usVddgfxLookupTableOffset; 		/*points to ATOM_Tonga_Voltage_Lookup_Table */
+
+	USHORT	usMMDependencyTableOffset;		  /*points to ATOM_Tonga_MM_Dependency_Table */
+
+	USHORT	usVCEStateTableOffset;			   /*points to ATOM_Tonga_VCE_State_Table; */
+
+	USHORT	usPPMTableOffset;				  /*points to ATOM_Tonga_PPM_Table */
+	USHORT	usPowerTuneTableOffset;			  /*points to ATOM_PowerTune_Table */
+
+	USHORT	usHardLimitTableOffset; 		   /*points to ATOM_Tonga_Hard_Limit_Table */
+
+	USHORT	usPCIETableOffset;				  /*points to ATOM_Tonga_PCIE_Table */
+
+	USHORT	usGPIOTableOffset;				  /*points to ATOM_Tonga_GPIO_Table */
+
+	USHORT	usReserved[6];					   /*TODO: modify reserved size to fit structure aligning */
+} ATOM_Tonga_POWERPLAYTABLE;
+
+typedef struct _ATOM_Tonga_State {
+	UCHAR  ucEngineClockIndexHigh;
+	UCHAR  ucEngineClockIndexLow;
+
+	UCHAR  ucMemoryClockIndexHigh;
+	UCHAR  ucMemoryClockIndexLow;
+
+	UCHAR  ucPCIEGenLow;
+	UCHAR  ucPCIEGenHigh;
+
+	UCHAR  ucPCIELaneLow;
+	UCHAR  ucPCIELaneHigh;
+
+	USHORT usClassification;
+	ULONG ulCapsAndSettings;
+	USHORT usClassification2;
+	UCHAR  ucUnused[4];
+} ATOM_Tonga_State;
+
+typedef struct _ATOM_Tonga_State_Array {
+	UCHAR ucRevId;
+	UCHAR ucNumEntries;		/* Number of entries. */
+	ATOM_Tonga_State states[1];	/* Dynamically allocate entries. */
+} ATOM_Tonga_State_Array;
+
+typedef struct _ATOM_Tonga_MCLK_Dependency_Record {
+	UCHAR  ucVddcInd;	/* Vddc voltage */
+	USHORT usVddci;
+	USHORT usVddgfxOffset;	/* Offset relative to Vddc voltage */
+	USHORT usMvdd;
+	ULONG ulMclk;
+	USHORT usReserved;
+} ATOM_Tonga_MCLK_Dependency_Record;
+
+typedef struct _ATOM_Tonga_MCLK_Dependency_Table {
+	UCHAR ucRevId;
+	UCHAR ucNumEntries; 										/* Number of entries. */
+	ATOM_Tonga_MCLK_Dependency_Record entries[];				/* Dynamically allocate entries. */
+} ATOM_Tonga_MCLK_Dependency_Table;
+
+typedef struct _ATOM_Tonga_SCLK_Dependency_Record {
+	UCHAR  ucVddInd;											/* Base voltage */
+	USHORT usVddcOffset;										/* Offset relative to base voltage */
+	ULONG ulSclk;
+	USHORT usEdcCurrent;
+	UCHAR  ucReliabilityTemperature;
+	UCHAR  ucCKSVOffsetandDisable;							  /* Bits 0~6: Voltage offset for CKS, Bit 7: Disable/enable for the SCLK level. */
+} ATOM_Tonga_SCLK_Dependency_Record;
+
+typedef struct _ATOM_Tonga_SCLK_Dependency_Table {
+	UCHAR ucRevId;
+	UCHAR ucNumEntries; 										/* Number of entries. */
+	ATOM_Tonga_SCLK_Dependency_Record entries[];				 /* Dynamically allocate entries. */
+} ATOM_Tonga_SCLK_Dependency_Table;
+
+typedef struct _ATOM_Tonga_PCIE_Record {
+	UCHAR ucPCIEGenSpeed;
+	UCHAR usPCIELaneWidth;
+	UCHAR ucReserved[2];
+} ATOM_Tonga_PCIE_Record;
+
+typedef struct _ATOM_Tonga_PCIE_Table {
+	UCHAR ucRevId;
+	UCHAR ucNumEntries; 										/* Number of entries. */
+	ATOM_Tonga_PCIE_Record entries[1];							/* Dynamically allocate entries. */
+} ATOM_Tonga_PCIE_Table;
+
+typedef struct _ATOM_Tonga_MM_Dependency_Record {
+	UCHAR   ucVddcInd;											 /* VDDC voltage */
+	USHORT  usVddgfxOffset;									  /* Offset relative to VDDC voltage */
+	ULONG  ulDClk;												/* UVD D-clock */
+	ULONG  ulVClk;												/* UVD V-clock */
+	ULONG  ulEClk;												/* VCE clock */
+	ULONG  ulAClk;												/* ACP clock */
+	ULONG  ulSAMUClk;											/* SAMU clock */
+} ATOM_Tonga_MM_Dependency_Record;
+
+typedef struct _ATOM_Tonga_MM_Dependency_Table {
+	UCHAR ucRevId;
+	UCHAR ucNumEntries; 										/* Number of entries. */
+	ATOM_Tonga_MM_Dependency_Record entries[1]; 			   /* Dynamically allocate entries. */
+} ATOM_Tonga_MM_Dependency_Table;
+
+typedef struct _ATOM_Tonga_Voltage_Lookup_Record {
+	USHORT usVdd;											   /* Base voltage */
+	USHORT usCACLow;
+	USHORT usCACMid;
+	USHORT usCACHigh;
+} ATOM_Tonga_Voltage_Lookup_Record;
+
+typedef struct _ATOM_Tonga_Voltage_Lookup_Table {
+	UCHAR ucRevId;
+	UCHAR ucNumEntries; 										/* Number of entries. */
+	ATOM_Tonga_Voltage_Lookup_Record entries[1];				/* Dynamically allocate entries. */
+} ATOM_Tonga_Voltage_Lookup_Table;
+
+typedef struct _ATOM_Tonga_Fan_Table {
+	UCHAR   ucRevId;						 /* Change this if the table format changes or version changes so that the other fields are not the same. */
+	UCHAR   ucTHyst;						 /* Temperature hysteresis. Integer. */
+	USHORT  usTMin; 						 /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
+	USHORT  usTMed; 						 /* The middle temperature where we change slopes. */
+	USHORT  usTHigh;						 /* The high point above TMed for adjusting the second slope. */
+	USHORT  usPWMMin;						 /* The minimum PWM value in percent (0.01% increments). */
+	USHORT  usPWMMed;						 /* The PWM value (in percent) at TMed. */
+	USHORT  usPWMHigh;						 /* The PWM value at THigh. */
+	USHORT  usTMax; 						 /* The max temperature */
+	UCHAR   ucFanControlMode;				  /* Legacy or Fuzzy Fan mode */
+	USHORT  usFanPWMMax;					  /* Maximum allowed fan power in percent */
+	USHORT  usFanOutputSensitivity;		  /* Sensitivity of fan reaction to temepature changes */
+	USHORT  usFanRPMMax;					  /* The default value in RPM */
+	ULONG  ulMinFanSCLKAcousticLimit;	   /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
+	UCHAR   ucTargetTemperature;			 /* Advanced fan controller target temperature. */
+	UCHAR   ucMinimumPWMLimit; 			  /* The minimum PWM that the advanced fan controller can set.	This should be set to the highest PWM that will run the fan at its lowest RPM. */
+	USHORT  usReserved;
+} ATOM_Tonga_Fan_Table;
+
+typedef struct _ATOM_Fiji_Fan_Table {
+	UCHAR   ucRevId;						 /* Change this if the table format changes or version changes so that the other fields are not the same. */
+	UCHAR   ucTHyst;						 /* Temperature hysteresis. Integer. */
+	USHORT  usTMin; 						 /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
+	USHORT  usTMed; 						 /* The middle temperature where we change slopes. */
+	USHORT  usTHigh;						 /* The high point above TMed for adjusting the second slope. */
+	USHORT  usPWMMin;						 /* The minimum PWM value in percent (0.01% increments). */
+	USHORT  usPWMMed;						 /* The PWM value (in percent) at TMed. */
+	USHORT  usPWMHigh;						 /* The PWM value at THigh. */
+	USHORT  usTMax; 						 /* The max temperature */
+	UCHAR   ucFanControlMode;				  /* Legacy or Fuzzy Fan mode */
+	USHORT  usFanPWMMax;					  /* Maximum allowed fan power in percent */
+	USHORT  usFanOutputSensitivity;		  /* Sensitivity of fan reaction to temepature changes */
+	USHORT  usFanRPMMax;					  /* The default value in RPM */
+	ULONG  ulMinFanSCLKAcousticLimit;		/* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
+	UCHAR   ucTargetTemperature;			 /* Advanced fan controller target temperature. */
+	UCHAR   ucMinimumPWMLimit; 			  /* The minimum PWM that the advanced fan controller can set.	This should be set to the highest PWM that will run the fan at its lowest RPM. */
+	USHORT  usFanGainEdge;
+	USHORT  usFanGainHotspot;
+	USHORT  usFanGainLiquid;
+	USHORT  usFanGainVrVddc;
+	USHORT  usFanGainVrMvdd;
+	USHORT  usFanGainPlx;
+	USHORT  usFanGainHbm;
+	USHORT  usReserved;
+} ATOM_Fiji_Fan_Table;
+
+typedef struct _ATOM_Tonga_Thermal_Controller {
+	UCHAR ucRevId;
+	UCHAR ucType;		   /* one of ATOM_TONGA_PP_THERMALCONTROLLER_* */
+	UCHAR ucI2cLine;		/* as interpreted by DAL I2C */
+	UCHAR ucI2cAddress;
+	UCHAR ucFanParameters;	/* Fan Control Parameters. */
+	UCHAR ucFanMinRPM; 	 /* Fan Minimum RPM (hundreds) -- for display purposes only. */
+	UCHAR ucFanMaxRPM; 	 /* Fan Maximum RPM (hundreds) -- for display purposes only. */
+	UCHAR ucReserved;
+	UCHAR ucFlags;		   /* to be defined */
+} ATOM_Tonga_Thermal_Controller;
+
+typedef struct _ATOM_Tonga_VCE_State_Record {
+	UCHAR  ucVCEClockIndex;	/*index into usVCEDependencyTableOffset of 'ATOM_Tonga_MM_Dependency_Table' type */
+	UCHAR  ucFlag;		/* 2 bits indicates memory p-states */
+	UCHAR  ucSCLKIndex;		/*index into ATOM_Tonga_SCLK_Dependency_Table */
+	UCHAR  ucMCLKIndex;		/*index into ATOM_Tonga_MCLK_Dependency_Table */
+} ATOM_Tonga_VCE_State_Record;
+
+typedef struct _ATOM_Tonga_VCE_State_Table {
+	UCHAR ucRevId;
+	UCHAR ucNumEntries;
+	ATOM_Tonga_VCE_State_Record entries[1];
+} ATOM_Tonga_VCE_State_Table;
+
+typedef struct _ATOM_Tonga_PowerTune_Table {
+	UCHAR  ucRevId;
+	USHORT usTDP;
+	USHORT usConfigurableTDP;
+	USHORT usTDC;
+	USHORT usBatteryPowerLimit;
+	USHORT usSmallPowerLimit;
+	USHORT usLowCACLeakage;
+	USHORT usHighCACLeakage;
+	USHORT usMaximumPowerDeliveryLimit;
+	USHORT usTjMax;
+	USHORT usPowerTuneDataSetID;
+	USHORT usEDCLimit;
+	USHORT usSoftwareShutdownTemp;
+	USHORT usClockStretchAmount;
+	USHORT usReserve[2];
+} ATOM_Tonga_PowerTune_Table;
+
+typedef struct _ATOM_Fiji_PowerTune_Table {
+	UCHAR  ucRevId;
+	USHORT usTDP;
+	USHORT usConfigurableTDP;
+	USHORT usTDC;
+	USHORT usBatteryPowerLimit;
+	USHORT usSmallPowerLimit;
+	USHORT usLowCACLeakage;
+	USHORT usHighCACLeakage;
+	USHORT usMaximumPowerDeliveryLimit;
+	USHORT usTjMax;  /* For Fiji, this is also usTemperatureLimitEdge; */
+	USHORT usPowerTuneDataSetID;
+	USHORT usEDCLimit;
+	USHORT usSoftwareShutdownTemp;
+	USHORT usClockStretchAmount;
+	USHORT usTemperatureLimitHotspot;  /*The following are added for Fiji */
+	USHORT usTemperatureLimitLiquid1;
+	USHORT usTemperatureLimitLiquid2;
+	USHORT usTemperatureLimitVrVddc;
+	USHORT usTemperatureLimitVrMvdd;
+	USHORT usTemperatureLimitPlx;
+	UCHAR  ucLiquid1_I2C_address;  /*Liquid */
+	UCHAR  ucLiquid2_I2C_address;
+	UCHAR  ucLiquid_I2C_Line;
+	UCHAR  ucVr_I2C_address;	/*VR */
+	UCHAR  ucVr_I2C_Line;
+	UCHAR  ucPlx_I2C_address;  /*PLX */
+	UCHAR  ucPlx_I2C_Line;
+	USHORT usReserved;
+} ATOM_Fiji_PowerTune_Table;
+
+#define ATOM_PPM_A_A    1
+#define ATOM_PPM_A_I    2
+typedef struct _ATOM_Tonga_PPM_Table {
+	UCHAR   ucRevId;
+	UCHAR   ucPpmDesign;		  /*A+I or A+A */
+	USHORT  usCpuCoreNumber;
+	ULONG  ulPlatformTDP;
+	ULONG  ulSmallACPlatformTDP;
+	ULONG  ulPlatformTDC;
+	ULONG  ulSmallACPlatformTDC;
+	ULONG  ulApuTDP;
+	ULONG  ulDGpuTDP;
+	ULONG  ulDGpuUlvPower;
+	ULONG  ulTjmax;
+} ATOM_Tonga_PPM_Table;
+
+typedef struct _ATOM_Tonga_Hard_Limit_Record {
+	ULONG  ulSCLKLimit;
+	ULONG  ulMCLKLimit;
+	USHORT  usVddcLimit;
+	USHORT  usVddciLimit;
+	USHORT  usVddgfxLimit;
+} ATOM_Tonga_Hard_Limit_Record;
+
+typedef struct _ATOM_Tonga_Hard_Limit_Table {
+	UCHAR ucRevId;
+	UCHAR ucNumEntries;
+	ATOM_Tonga_Hard_Limit_Record entries[1];
+} ATOM_Tonga_Hard_Limit_Table;
+
+typedef struct _ATOM_Tonga_GPIO_Table {
+	UCHAR  ucRevId;
+	UCHAR  ucVRHotTriggeredSclkDpmIndex;		/* If VRHot signal is triggered SCLK will be limited to this DPM level */
+	UCHAR  ucReserve[5];
+} ATOM_Tonga_GPIO_Table;
+
+typedef struct _PPTable_Generic_SubTable_Header {
+	UCHAR  ucRevId;
+} PPTable_Generic_SubTable_Header;
+
+
+#pragma pack(pop)
+
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c
@@ -0,0 +1,1142 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+
+#include "tonga_processpptables.h"
+#include "ppatomctrl.h"
+#include "atombios.h"
+#include "pp_debug.h"
+#include "hwmgr.h"
+#include "cgs_common.h"
+#include "tonga_pptable.h"
+
+/**
+ * Private Function used during initialization.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param setIt A flag indication if the capability should be set (TRUE) or reset (FALSE).
+ * @param cap Which capability to set/reset.
+ */
+static void set_hw_cap(struct pp_hwmgr *hwmgr, bool setIt, enum phm_platform_caps cap)
+{
+	if (setIt)
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
+	else
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
+}
+
+
+/**
+ * Private Function used during initialization.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_caps the bit array (from BIOS) of capability bits.
+ * @exception the current implementation always returns 1.
+ */
+static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
+{
+	PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE16____),
+		"ATOM_PP_PLATFORM_CAP_ASPM_L1 is not supported!", continue);
+	PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE64____),
+		"ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY is not supported!", continue);
+	PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE512____),
+		"ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL is not supported!", continue);
+	PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE1024____),
+		"ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 is not supported!", continue);
+	PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE2048____),
+		"ATOM_PP_PLATFORM_CAP_HTLINKCONTROL is not supported!", continue);
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY),
+			PHM_PlatformCaps_PowerPlaySupport
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
+			PHM_PlatformCaps_BiosPowerSourceControl
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC),
+			PHM_PlatformCaps_AutomaticDCTransition
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL),
+			PHM_PlatformCaps_EnableMVDDControl
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL),
+			PHM_PlatformCaps_ControlVDDCI
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL),
+			PHM_PlatformCaps_ControlVDDGFX
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_BACO),
+			PHM_PlatformCaps_BACO
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND),
+			PHM_PlatformCaps_DisableVoltageIsland
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
+			PHM_PlatformCaps_CombinePCCWithThermalSignal
+		  );
+
+	set_hw_cap(
+			hwmgr,
+			0 != (powerplay_caps & ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
+			PHM_PlatformCaps_LoadPostProductionFirmware
+		  );
+
+	return 0;
+}
+
+/**
+ * Private Function to get the PowerPlay Table Address.
+ */
+const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
+{
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+
+	u16 size;
+	u8 frev, crev;
+	void *table_address;
+
+	table_address = (ATOM_Tonga_POWERPLAYTABLE *)
+		cgs_atom_get_data_table(hwmgr->device, index, &size, &frev, &crev);
+
+	hwmgr->soft_pp_table = table_address;	/*Cache the result in RAM.*/
+
+	return table_address;
+}
+
+static int get_vddc_lookup_table(
+		struct pp_hwmgr	*hwmgr,
+		phm_ppt_v1_voltage_lookup_table	**lookup_table,
+		const ATOM_Tonga_Voltage_Lookup_Table	*vddc_lookup_pp_tables,
+		uint32_t	max_levels
+		)
+{
+	uint32_t table_size, i;
+	phm_ppt_v1_voltage_lookup_table *table;
+
+	PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
+		"Invalid CAC Leakage PowerPlay Table!", return 1);
+
+	table_size = sizeof(uint32_t) +
+		sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels;
+
+	table = (phm_ppt_v1_voltage_lookup_table *)
+		kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == table)
+		return -ENOMEM;
+
+	memset(table, 0x00, table_size);
+
+	table->count = vddc_lookup_pp_tables->ucNumEntries;
+
+	for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) {
+		table->entries[i].us_calculated = 0;
+		table->entries[i].us_vdd =
+			vddc_lookup_pp_tables->entries[i].usVdd;
+		table->entries[i].us_cac_low =
+			vddc_lookup_pp_tables->entries[i].usCACLow;
+		table->entries[i].us_cac_mid =
+			vddc_lookup_pp_tables->entries[i].usCACMid;
+		table->entries[i].us_cac_high =
+			vddc_lookup_pp_tables->entries[i].usCACHigh;
+	}
+
+	*lookup_table = table;
+
+	return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize Platform Power Management Parameter table
+ * @param hwmgr Pointer to the hardware manager.
+ * @param atom_ppm_table Pointer to PPM table in VBIOS
+ */
+static int get_platform_power_management_table(
+		struct pp_hwmgr *hwmgr,
+		ATOM_Tonga_PPM_Table *atom_ppm_table)
+{
+	struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL);
+	struct phm_ppt_v1_information *pp_table_information =
+		(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (NULL == ptr)
+		return -ENOMEM;
+
+	ptr->ppm_design
+		= atom_ppm_table->ucPpmDesign;
+	ptr->cpu_core_number
+		= atom_ppm_table->usCpuCoreNumber;
+	ptr->platform_tdp
+		= atom_ppm_table->ulPlatformTDP;
+	ptr->small_ac_platform_tdp
+		= atom_ppm_table->ulSmallACPlatformTDP;
+	ptr->platform_tdc
+		= atom_ppm_table->ulPlatformTDC;
+	ptr->small_ac_platform_tdc
+		= atom_ppm_table->ulSmallACPlatformTDC;
+	ptr->apu_tdp
+		= atom_ppm_table->ulApuTDP;
+	ptr->dgpu_tdp
+		= atom_ppm_table->ulDGpuTDP;
+	ptr->dgpu_ulv_power
+		= atom_ppm_table->ulDGpuUlvPower;
+	ptr->tj_max
+		= atom_ppm_table->ulTjmax;
+
+	pp_table_information->ppm_parameter_table = ptr;
+
+	return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize TDP limits for DPM2
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ */
+static int init_dpm_2_parameters(
+		struct pp_hwmgr *hwmgr,
+		const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+		)
+{
+	int result = 0;
+	struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+	ATOM_Tonga_PPM_Table *atom_ppm_table;
+	uint32_t disable_ppm = 0;
+	uint32_t disable_power_control = 0;
+
+	pp_table_information->us_ulv_voltage_offset =
+		le16_to_cpu(powerplay_table->usUlvVoltageOffset);
+
+	pp_table_information->ppm_parameter_table = NULL;
+	pp_table_information->vddc_lookup_table = NULL;
+	pp_table_information->vddgfx_lookup_table = NULL;
+	/* TDP limits */
+	hwmgr->platform_descriptor.TDPODLimit =
+		le16_to_cpu(powerplay_table->usPowerControlLimit);
+	hwmgr->platform_descriptor.TDPAdjustment = 0;
+	hwmgr->platform_descriptor.VidAdjustment = 0;
+	hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
+	hwmgr->platform_descriptor.VidMinLimit = 0;
+	hwmgr->platform_descriptor.VidMaxLimit = 1500000;
+	hwmgr->platform_descriptor.VidStep = 6250;
+
+	disable_power_control = 0;
+	if (0 == disable_power_control) {
+		/* enable TDP overdrive (PowerControl) feature as well if supported */
+		if (hwmgr->platform_descriptor.TDPODLimit != 0)
+			phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_PowerControl);
+	}
+
+	if (0 != powerplay_table->usVddcLookupTableOffset) {
+		const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable =
+			(ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
+			le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
+
+		result = get_vddc_lookup_table(hwmgr,
+			&pp_table_information->vddc_lookup_table, pVddcCACTable, 16);
+	}
+
+	if (0 != powerplay_table->usVddgfxLookupTableOffset) {
+		const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable =
+			(ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
+			le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset));
+
+		result = get_vddc_lookup_table(hwmgr,
+			&pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16);
+	}
+
+	disable_ppm = 0;
+	if (0 == disable_ppm) {
+		atom_ppm_table = (ATOM_Tonga_PPM_Table *)
+			(((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset));
+
+		if (0 != powerplay_table->usPPMTableOffset) {
+			if (1 == get_platform_power_management_table(hwmgr, atom_ppm_table)) {
+				phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+					PHM_PlatformCaps_EnablePlatformPowerManagement);
+			}
+		}
+	}
+
+	return result;
+}
+
+static int get_valid_clk(
+		struct pp_hwmgr *hwmgr,
+		struct phm_clock_array **clk_table,
+		const phm_ppt_v1_clock_voltage_dependency_table  * clk_volt_pp_table
+		)
+{
+	uint32_t table_size, i;
+	struct phm_clock_array *table;
+
+	PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count),
+		"Invalid PowerPlay Table!", return -1);
+
+	table_size = sizeof(uint32_t) +
+		sizeof(uint32_t) * clk_volt_pp_table->count;
+
+	table = (struct phm_clock_array *)kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == table)
+		return -ENOMEM;
+
+	memset(table, 0x00, table_size);
+
+	table->count = (uint32_t)clk_volt_pp_table->count;
+
+	for (i = 0; i < table->count; i++)
+		table->values[i] = (uint32_t)clk_volt_pp_table->entries[i].clk;
+
+	*clk_table = table;
+
+	return 0;
+}
+
+static int get_hard_limits(
+		struct pp_hwmgr *hwmgr,
+		struct phm_clock_and_voltage_limits *limits,
+		const ATOM_Tonga_Hard_Limit_Table * limitable
+		)
+{
+	PP_ASSERT_WITH_CODE((0 != limitable->ucNumEntries), "Invalid PowerPlay Table!", return -1);
+
+	/* currently we always take entries[0] parameters */
+	limits->sclk = (uint32_t)limitable->entries[0].ulSCLKLimit;
+	limits->mclk = (uint32_t)limitable->entries[0].ulMCLKLimit;
+	limits->vddc = (uint16_t)limitable->entries[0].usVddcLimit;
+	limits->vddci = (uint16_t)limitable->entries[0].usVddciLimit;
+	limits->vddgfx = (uint16_t)limitable->entries[0].usVddgfxLimit;
+
+	return 0;
+}
+
+static int get_mclk_voltage_dependency_table(
+		struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_mclk_dep_table,
+		const ATOM_Tonga_MCLK_Dependency_Table * mclk_dep_table
+		)
+{
+	uint32_t table_size, i;
+	phm_ppt_v1_clock_voltage_dependency_table *mclk_table;
+
+	PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
+		"Invalid PowerPlay Table!", return -1);
+
+	table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
+		* mclk_dep_table->ucNumEntries;
+
+	mclk_table = (phm_ppt_v1_clock_voltage_dependency_table *)
+		kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == mclk_table)
+		return -ENOMEM;
+
+	memset(mclk_table, 0x00, table_size);
+
+	mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
+
+	for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
+		mclk_table->entries[i].vddInd =
+			mclk_dep_table->entries[i].ucVddcInd;
+		mclk_table->entries[i].vdd_offset =
+			mclk_dep_table->entries[i].usVddgfxOffset;
+		mclk_table->entries[i].vddci =
+			mclk_dep_table->entries[i].usVddci;
+		mclk_table->entries[i].mvdd =
+			mclk_dep_table->entries[i].usMvdd;
+		mclk_table->entries[i].clk =
+			mclk_dep_table->entries[i].ulMclk;
+	}
+
+	*pp_tonga_mclk_dep_table = mclk_table;
+
+	return 0;
+}
+
+static int get_sclk_voltage_dependency_table(
+		struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_sclk_dep_table,
+		const ATOM_Tonga_SCLK_Dependency_Table * sclk_dep_table
+		)
+{
+	uint32_t table_size, i;
+	phm_ppt_v1_clock_voltage_dependency_table *sclk_table;
+
+	PP_ASSERT_WITH_CODE((0 != sclk_dep_table->ucNumEntries),
+		"Invalid PowerPlay Table!", return -1);
+
+	table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
+		* sclk_dep_table->ucNumEntries;
+
+	sclk_table = (phm_ppt_v1_clock_voltage_dependency_table *)
+		kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == sclk_table)
+		return -ENOMEM;
+
+	memset(sclk_table, 0x00, table_size);
+
+	sclk_table->count = (uint32_t)sclk_dep_table->ucNumEntries;
+
+	for (i = 0; i < sclk_dep_table->ucNumEntries; i++) {
+		sclk_table->entries[i].vddInd =
+			sclk_dep_table->entries[i].ucVddInd;
+		sclk_table->entries[i].vdd_offset =
+			sclk_dep_table->entries[i].usVddcOffset;
+		sclk_table->entries[i].clk =
+			sclk_dep_table->entries[i].ulSclk;
+		sclk_table->entries[i].cks_enable =
+			(((sclk_dep_table->entries[i].ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
+		sclk_table->entries[i].cks_voffset =
+			(sclk_dep_table->entries[i].ucCKSVOffsetandDisable & 0x7F);
+	}
+
+	*pp_tonga_sclk_dep_table = sclk_table;
+
+	return 0;
+}
+
+static int get_pcie_table(
+		struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_pcie_table **pp_tonga_pcie_table,
+		const ATOM_Tonga_PCIE_Table * atom_pcie_table
+		)
+{
+	uint32_t table_size, i, pcie_count;
+	phm_ppt_v1_pcie_table *pcie_table;
+	struct phm_ppt_v1_information *pp_table_information =
+		(struct phm_ppt_v1_information *)(hwmgr->pptable);
+	PP_ASSERT_WITH_CODE((0 != atom_pcie_table->ucNumEntries),
+		"Invalid PowerPlay Table!", return -1);
+
+	table_size = sizeof(uint32_t) +
+		sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
+
+	pcie_table = (phm_ppt_v1_pcie_table *)kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == pcie_table)
+		return -ENOMEM;
+
+	memset(pcie_table, 0x00, table_size);
+
+	/*
+	* Make sure the number of pcie entries are less than or equal to sclk dpm levels.
+	* Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
+	*/
+	pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
+	if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count)
+		pcie_count = (uint32_t)atom_pcie_table->ucNumEntries;
+	else
+		printk(KERN_ERR "[ powerplay ] Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
+		Disregarding the excess entries... \n");
+
+	pcie_table->count = pcie_count;
+
+	for (i = 0; i < pcie_count; i++) {
+		pcie_table->entries[i].gen_speed =
+			atom_pcie_table->entries[i].ucPCIEGenSpeed;
+		pcie_table->entries[i].lane_width =
+			atom_pcie_table->entries[i].usPCIELaneWidth;
+	}
+
+	*pp_tonga_pcie_table = pcie_table;
+
+	return 0;
+}
+
+static int get_cac_tdp_table(
+		struct pp_hwmgr *hwmgr,
+		struct phm_cac_tdp_table **cac_tdp_table,
+		const PPTable_Generic_SubTable_Header * table
+		)
+{
+	uint32_t table_size;
+	struct phm_cac_tdp_table *tdp_table;
+
+	table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table);
+	tdp_table = kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == tdp_table)
+		return -ENOMEM;
+
+	memset(tdp_table, 0x00, table_size);
+
+	hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == hwmgr->dyn_state.cac_dtp_table)
+		return -ENOMEM;
+
+	memset(hwmgr->dyn_state.cac_dtp_table, 0x00, table_size);
+
+	if (table->ucRevId < 3) {
+		const ATOM_Tonga_PowerTune_Table *tonga_table =
+			(ATOM_Tonga_PowerTune_Table *)table;
+		tdp_table->usTDP = tonga_table->usTDP;
+		tdp_table->usConfigurableTDP =
+			tonga_table->usConfigurableTDP;
+		tdp_table->usTDC = tonga_table->usTDC;
+		tdp_table->usBatteryPowerLimit =
+			tonga_table->usBatteryPowerLimit;
+		tdp_table->usSmallPowerLimit =
+			tonga_table->usSmallPowerLimit;
+		tdp_table->usLowCACLeakage =
+			tonga_table->usLowCACLeakage;
+		tdp_table->usHighCACLeakage =
+			tonga_table->usHighCACLeakage;
+		tdp_table->usMaximumPowerDeliveryLimit =
+			tonga_table->usMaximumPowerDeliveryLimit;
+		tdp_table->usDefaultTargetOperatingTemp =
+			tonga_table->usTjMax;
+		tdp_table->usTargetOperatingTemp =
+			tonga_table->usTjMax; /*Set the initial temp to the same as default */
+		tdp_table->usPowerTuneDataSetID =
+			tonga_table->usPowerTuneDataSetID;
+		tdp_table->usSoftwareShutdownTemp =
+			tonga_table->usSoftwareShutdownTemp;
+		tdp_table->usClockStretchAmount =
+			tonga_table->usClockStretchAmount;
+	} else {   /* Fiji and newer */
+		const ATOM_Fiji_PowerTune_Table *fijitable =
+			(ATOM_Fiji_PowerTune_Table *)table;
+		tdp_table->usTDP = fijitable->usTDP;
+		tdp_table->usConfigurableTDP = fijitable->usConfigurableTDP;
+		tdp_table->usTDC = fijitable->usTDC;
+		tdp_table->usBatteryPowerLimit = fijitable->usBatteryPowerLimit;
+		tdp_table->usSmallPowerLimit = fijitable->usSmallPowerLimit;
+		tdp_table->usLowCACLeakage = fijitable->usLowCACLeakage;
+		tdp_table->usHighCACLeakage = fijitable->usHighCACLeakage;
+		tdp_table->usMaximumPowerDeliveryLimit =
+			fijitable->usMaximumPowerDeliveryLimit;
+		tdp_table->usDefaultTargetOperatingTemp =
+			fijitable->usTjMax;
+		tdp_table->usTargetOperatingTemp =
+			fijitable->usTjMax; /*Set the initial temp to the same as default */
+		tdp_table->usPowerTuneDataSetID =
+			fijitable->usPowerTuneDataSetID;
+		tdp_table->usSoftwareShutdownTemp =
+			fijitable->usSoftwareShutdownTemp;
+		tdp_table->usClockStretchAmount =
+			fijitable->usClockStretchAmount;
+		tdp_table->usTemperatureLimitHotspot =
+			fijitable->usTemperatureLimitHotspot;
+		tdp_table->usTemperatureLimitLiquid1 =
+			fijitable->usTemperatureLimitLiquid1;
+		tdp_table->usTemperatureLimitLiquid2 =
+			fijitable->usTemperatureLimitLiquid2;
+		tdp_table->usTemperatureLimitVrVddc =
+			fijitable->usTemperatureLimitVrVddc;
+		tdp_table->usTemperatureLimitVrMvdd =
+			fijitable->usTemperatureLimitVrMvdd;
+		tdp_table->usTemperatureLimitPlx =
+			fijitable->usTemperatureLimitPlx;
+		tdp_table->ucLiquid1_I2C_address =
+			fijitable->ucLiquid1_I2C_address;
+		tdp_table->ucLiquid2_I2C_address =
+			fijitable->ucLiquid2_I2C_address;
+		tdp_table->ucLiquid_I2C_Line =
+			fijitable->ucLiquid_I2C_Line;
+		tdp_table->ucVr_I2C_address = fijitable->ucVr_I2C_address;
+		tdp_table->ucVr_I2C_Line = fijitable->ucVr_I2C_Line;
+		tdp_table->ucPlx_I2C_address = fijitable->ucPlx_I2C_address;
+		tdp_table->ucPlx_I2C_Line = fijitable->ucPlx_I2C_Line;
+	}
+
+	*cac_tdp_table = tdp_table;
+
+	return 0;
+}
+
+static int get_mm_clock_voltage_table(
+		struct pp_hwmgr *hwmgr,
+		phm_ppt_v1_mm_clock_voltage_dependency_table **tonga_mm_table,
+		const ATOM_Tonga_MM_Dependency_Table * mm_dependency_table
+		)
+{
+	uint32_t table_size, i;
+	const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record;
+	phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
+
+	PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
+		"Invalid PowerPlay Table!", return -1);
+	table_size = sizeof(uint32_t) +
+		sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record)
+		* mm_dependency_table->ucNumEntries;
+	mm_table = (phm_ppt_v1_mm_clock_voltage_dependency_table *)
+		kzalloc(table_size, GFP_KERNEL);
+
+	if (NULL == mm_table)
+		return -ENOMEM;
+
+	memset(mm_table, 0x00, table_size);
+
+	mm_table->count = mm_dependency_table->ucNumEntries;
+
+	for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
+		mm_dependency_record = &mm_dependency_table->entries[i];
+		mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd;
+		mm_table->entries[i].vddgfx_offset = mm_dependency_record->usVddgfxOffset;
+		mm_table->entries[i].aclk = mm_dependency_record->ulAClk;
+		mm_table->entries[i].samclock = mm_dependency_record->ulSAMUClk;
+		mm_table->entries[i].eclk = mm_dependency_record->ulEClk;
+		mm_table->entries[i].vclk = mm_dependency_record->ulVClk;
+		mm_table->entries[i].dclk = mm_dependency_record->ulDClk;
+	}
+
+	*tonga_mm_table = mm_table;
+
+	return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize clock voltage dependency
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ */
+static int init_clock_voltage_dependency(
+		struct pp_hwmgr *hwmgr,
+		const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+		)
+{
+	int result = 0;
+	struct phm_ppt_v1_information *pp_table_information =
+		(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table =
+		(const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) +
+		le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
+	const PPTable_Generic_SubTable_Header *pPowerTuneTable =
+		(const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
+		le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
+	const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
+		(const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
+		le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
+	const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
+		(const ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
+		le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
+	const ATOM_Tonga_Hard_Limit_Table *pHardLimits =
+		(const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) +
+		le16_to_cpu(powerplay_table->usHardLimitTableOffset));
+	const ATOM_Tonga_PCIE_Table *pcie_table =
+		(const ATOM_Tonga_PCIE_Table *)(((unsigned long) powerplay_table) +
+		le16_to_cpu(powerplay_table->usPCIETableOffset));
+
+	pp_table_information->vdd_dep_on_sclk = NULL;
+	pp_table_information->vdd_dep_on_mclk = NULL;
+	pp_table_information->mm_dep_table = NULL;
+	pp_table_information->pcie_table = NULL;
+
+	if (powerplay_table->usMMDependencyTableOffset != 0)
+		result = get_mm_clock_voltage_table(hwmgr,
+		&pp_table_information->mm_dep_table, mm_dependency_table);
+
+	if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0)
+		result = get_cac_tdp_table(hwmgr,
+		&pp_table_information->cac_dtp_table, pPowerTuneTable);
+
+	if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0)
+		result = get_sclk_voltage_dependency_table(hwmgr,
+		&pp_table_information->vdd_dep_on_sclk, sclk_dep_table);
+
+	if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0)
+		result = get_mclk_voltage_dependency_table(hwmgr,
+		&pp_table_information->vdd_dep_on_mclk, mclk_dep_table);
+
+	if (result == 0 && powerplay_table->usPCIETableOffset != 0)
+		result = get_pcie_table(hwmgr,
+		&pp_table_information->pcie_table, pcie_table);
+
+	if (result == 0 && powerplay_table->usHardLimitTableOffset != 0)
+		result = get_hard_limits(hwmgr,
+		&pp_table_information->max_clock_voltage_on_dc, pHardLimits);
+
+	hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
+		pp_table_information->max_clock_voltage_on_dc.sclk;
+	hwmgr->dyn_state.max_clock_voltage_on_dc.mclk =
+		pp_table_information->max_clock_voltage_on_dc.mclk;
+	hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
+		pp_table_information->max_clock_voltage_on_dc.vddc;
+	hwmgr->dyn_state.max_clock_voltage_on_dc.vddci =
+		pp_table_information->max_clock_voltage_on_dc.vddci;
+
+	if (result == 0 && (NULL != pp_table_information->vdd_dep_on_mclk)
+		&& (0 != pp_table_information->vdd_dep_on_mclk->count))
+		result = get_valid_clk(hwmgr, &pp_table_information->valid_mclk_values,
+		pp_table_information->vdd_dep_on_mclk);
+
+	if (result == 0 && (NULL != pp_table_information->vdd_dep_on_sclk)
+		&& (0 != pp_table_information->vdd_dep_on_sclk->count))
+		result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values,
+		pp_table_information->vdd_dep_on_sclk);
+
+	return result;
+}
+
+/** Retrieves the (signed) Overdrive limits from VBIOS.
+ * The max engine clock, memory clock and max temperature come from the firmware info table.
+ *
+ * The information is placed into the platform descriptor.
+ *
+ * @param hwmgr source of the VBIOS table and owner of the platform descriptor to be updated.
+ * @param powerplay_table the address of the PowerPlay table.
+ *
+ * @return 1 as long as the firmware info table was present and of a supported version.
+ */
+static int init_over_drive_limits(
+		struct pp_hwmgr *hwmgr,
+		const ATOM_Tonga_POWERPLAYTABLE *powerplay_table)
+{
+	hwmgr->platform_descriptor.overdriveLimit.engineClock =
+		le16_to_cpu(powerplay_table->ulMaxODEngineClock);
+	hwmgr->platform_descriptor.overdriveLimit.memoryClock =
+		le16_to_cpu(powerplay_table->ulMaxODMemoryClock);
+
+	hwmgr->platform_descriptor.minOverdriveVDDC = 0;
+	hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
+	hwmgr->platform_descriptor.overdriveVDDCStep = 0;
+
+	if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 \
+		&& hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) {
+		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_ACOverdriveSupport);
+	}
+
+	return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Inspect the PowerPlay table for obvious signs of corruption.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ * @exception This implementation always returns 1.
+ */
+static int init_thermal_controller(
+		struct pp_hwmgr *hwmgr,
+		const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+		)
+{
+	const PPTable_Generic_SubTable_Header *fan_table;
+	ATOM_Tonga_Thermal_Controller *thermal_controller;
+
+	thermal_controller = (ATOM_Tonga_Thermal_Controller *)
+		(((unsigned long)powerplay_table) +
+		le16_to_cpu(powerplay_table->usThermalControllerOffset));
+	PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset),
+		"Thermal controller table not set!", return -1);
+
+	hwmgr->thermal_controller.ucType = thermal_controller->ucType;
+	hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
+	hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
+
+	hwmgr->thermal_controller.fanInfo.bNoFan =
+		(0 != (thermal_controller->ucFanParameters & ATOM_TONGA_PP_FANPARAMETERS_NOFAN));
+
+	hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
+		thermal_controller->ucFanParameters &
+		ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
+
+	hwmgr->thermal_controller.fanInfo.ulMinRPM
+		= thermal_controller->ucFanMinRPM * 100UL;
+	hwmgr->thermal_controller.fanInfo.ulMaxRPM
+		= thermal_controller->ucFanMaxRPM * 100UL;
+
+	set_hw_cap(
+			hwmgr,
+			ATOM_TONGA_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
+			PHM_PlatformCaps_ThermalController
+		  );
+
+	if (0 == powerplay_table->usFanTableOffset)
+		return 0;
+
+	fan_table = (const PPTable_Generic_SubTable_Header *)
+		(((unsigned long)powerplay_table) +
+		le16_to_cpu(powerplay_table->usFanTableOffset));
+
+	PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset),
+		"Fan table not set!", return -1);
+	PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId),
+		"Unsupported fan table format!", return -1);
+
+	hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay
+		= 100000;
+	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_MicrocodeFanControl);
+
+	if (fan_table->ucRevId < 8) {
+		const ATOM_Tonga_Fan_Table *tonga_fan_table =
+			(ATOM_Tonga_Fan_Table *)fan_table;
+		hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
+			= tonga_fan_table->ucTHyst;
+		hwmgr->thermal_controller.advanceFanControlParameters.usTMin
+			= tonga_fan_table->usTMin;
+		hwmgr->thermal_controller.advanceFanControlParameters.usTMed
+			= tonga_fan_table->usTMed;
+		hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
+			= tonga_fan_table->usTHigh;
+		hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
+			= tonga_fan_table->usPWMMin;
+		hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
+			= tonga_fan_table->usPWMMed;
+		hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
+			= tonga_fan_table->usPWMHigh;
+		hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+			= 10900;                  /* hard coded */
+		hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+			= tonga_fan_table->usTMax;
+		hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
+			= tonga_fan_table->ucFanControlMode;
+		hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
+			= tonga_fan_table->usFanPWMMax;
+		hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
+			= 4836;
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
+			= tonga_fan_table->usFanOutputSensitivity;
+		hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
+			= tonga_fan_table->usFanRPMMax;
+		hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
+			= (tonga_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places.  SMC wants MHz. */
+		hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
+			= tonga_fan_table->ucTargetTemperature;
+		hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
+			= tonga_fan_table->ucMinimumPWMLimit;
+	} else {
+		const ATOM_Fiji_Fan_Table *fiji_fan_table =
+			(ATOM_Fiji_Fan_Table *)fan_table;
+		hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
+			= fiji_fan_table->ucTHyst;
+		hwmgr->thermal_controller.advanceFanControlParameters.usTMin
+			= fiji_fan_table->usTMin;
+		hwmgr->thermal_controller.advanceFanControlParameters.usTMed
+			= fiji_fan_table->usTMed;
+		hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
+			= fiji_fan_table->usTHigh;
+		hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
+			= fiji_fan_table->usPWMMin;
+		hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
+			= fiji_fan_table->usPWMMed;
+		hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
+			= fiji_fan_table->usPWMHigh;
+		hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+			= fiji_fan_table->usTMax;
+		hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
+			= fiji_fan_table->ucFanControlMode;
+		hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
+			= fiji_fan_table->usFanPWMMax;
+		hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
+			= 4836;
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
+			= fiji_fan_table->usFanOutputSensitivity;
+		hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
+			= fiji_fan_table->usFanRPMMax;
+		hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
+			= (fiji_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places.  SMC wants MHz. */
+		hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
+			= fiji_fan_table->ucTargetTemperature;
+		hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
+			= fiji_fan_table->ucMinimumPWMLimit;
+
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge
+			= fiji_fan_table->usFanGainEdge;
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot
+			= fiji_fan_table->usFanGainHotspot;
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid
+			= fiji_fan_table->usFanGainLiquid;
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc
+			= fiji_fan_table->usFanGainVrVddc;
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd
+			= fiji_fan_table->usFanGainVrMvdd;
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx
+			= fiji_fan_table->usFanGainPlx;
+		hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm
+			= fiji_fan_table->usFanGainHbm;
+	}
+
+	return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Inspect the PowerPlay table for obvious signs of corruption.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ * @exception 2 if the powerplay table is incorrect.
+ */
+static int check_powerplay_tables(
+		struct pp_hwmgr *hwmgr,
+		const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+		)
+{
+	const ATOM_Tonga_State_Array *state_arrays;
+
+	state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) +
+		le16_to_cpu(powerplay_table->usStateArrayOffset));
+
+	PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <=
+		powerplay_table->sHeader.ucTableFormatRevision),
+		"Unsupported PPTable format!", return -1);
+	PP_ASSERT_WITH_CODE((0 != powerplay_table->usStateArrayOffset),
+		"State table is not set!", return -1);
+	PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize),
+		"Invalid PowerPlay Table!", return -1);
+	PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
+		"Invalid PowerPlay Table!", return -1);
+
+	return 0;
+}
+
+int tonga_pp_tables_initialize(struct pp_hwmgr *hwmgr)
+{
+	int result = 0;
+	const ATOM_Tonga_POWERPLAYTABLE *powerplay_table;
+
+	hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL);
+
+	PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable),
+			    "Failed to allocate hwmgr->pptable!", return -ENOMEM);
+
+	memset(hwmgr->pptable, 0x00, sizeof(struct phm_ppt_v1_information));
+
+	powerplay_table = get_powerplay_table(hwmgr);
+
+	PP_ASSERT_WITH_CODE((NULL != powerplay_table),
+		"Missing PowerPlay Table!", return -1);
+
+	result = check_powerplay_tables(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "check_powerplay_tables failed", return result);
+
+	result = set_platform_caps(hwmgr,
+				   le32_to_cpu(powerplay_table->ulPlatformCaps));
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "set_platform_caps failed", return result);
+
+	result = init_thermal_controller(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_thermal_controller failed", return result);
+
+	result = init_over_drive_limits(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_over_drive_limits failed", return result);
+
+	result = init_clock_voltage_dependency(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_clock_voltage_dependency failed", return result);
+
+	result = init_dpm_2_parameters(hwmgr, powerplay_table);
+
+	PP_ASSERT_WITH_CODE((result == 0),
+			    "init_dpm_2_parameters failed", return result);
+
+	return result;
+}
+
+int tonga_pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
+{
+	int result = 0;
+	struct phm_ppt_v1_information *pp_table_information =
+		(struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+	if (NULL != hwmgr->soft_pp_table) {
+		kfree(hwmgr->soft_pp_table);
+		hwmgr->soft_pp_table = NULL;
+	}
+
+	if (NULL != pp_table_information->vdd_dep_on_sclk)
+		pp_table_information->vdd_dep_on_sclk = NULL;
+
+	if (NULL != pp_table_information->vdd_dep_on_mclk)
+		pp_table_information->vdd_dep_on_mclk = NULL;
+
+	if (NULL != pp_table_information->valid_mclk_values)
+		pp_table_information->valid_mclk_values = NULL;
+
+	if (NULL != pp_table_information->valid_sclk_values)
+		pp_table_information->valid_sclk_values = NULL;
+
+	if (NULL != pp_table_information->vddc_lookup_table)
+		pp_table_information->vddc_lookup_table = NULL;
+
+	if (NULL != pp_table_information->vddgfx_lookup_table)
+		pp_table_information->vddgfx_lookup_table = NULL;
+
+	if (NULL != pp_table_information->mm_dep_table)
+		pp_table_information->mm_dep_table = NULL;
+
+	if (NULL != pp_table_information->cac_dtp_table)
+		pp_table_information->cac_dtp_table = NULL;
+
+	if (NULL != hwmgr->dyn_state.cac_dtp_table)
+		hwmgr->dyn_state.cac_dtp_table = NULL;
+
+	if (NULL != pp_table_information->ppm_parameter_table)
+		pp_table_information->ppm_parameter_table = NULL;
+
+	if (NULL != pp_table_information->pcie_table)
+		pp_table_information->pcie_table = NULL;
+
+	if (NULL != hwmgr->pptable) {
+		kfree(hwmgr->pptable);
+		hwmgr->pptable = NULL;
+	}
+
+	return result;
+}
+
+const struct pp_table_func tonga_pptable_funcs = {
+	.pptable_init = tonga_pp_tables_initialize,
+	.pptable_fini = tonga_pp_tables_uninitialize,
+};
+
+int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr)
+{
+	const ATOM_Tonga_State_Array * state_arrays;
+	const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+
+	PP_ASSERT_WITH_CODE((NULL != pp_table),
+			"Missing PowerPlay Table!", return -1);
+	PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >=
+			ATOM_Tonga_TABLE_REVISION_TONGA),
+			"Incorrect PowerPlay table revision!", return -1);
+
+	state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
+			le16_to_cpu(pp_table->usStateArrayOffset));
+
+	return (uint32_t)(state_arrays->ucNumEntries);
+}
+
+/**
+* Private function to convert flags stored in the BIOS to software flags in PowerPlay.
+*/
+static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr,
+		uint16_t classification, uint16_t classification2)
+{
+	uint32_t result = 0;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
+		result |= PP_StateClassificationFlag_Boot;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+		result |= PP_StateClassificationFlag_Thermal;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
+		result |= PP_StateClassificationFlag_LimitedPowerSource;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
+		result |= PP_StateClassificationFlag_Rest;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
+		result |= PP_StateClassificationFlag_Forced;
+
+	if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
+		result |= PP_StateClassificationFlag_ACPI;
+
+	if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
+		result |= PP_StateClassificationFlag_LimitedPowerSource_2;
+
+	return result;
+}
+
+/**
+* Create a Power State out of an entry in the PowerPlay table.
+* This function is called by the hardware back-end.
+* @param hwmgr Pointer to the hardware manager.
+* @param entry_index The index of the entry to be extracted from the table.
+* @param power_state The address of the PowerState instance being created.
+* @return -1 if the entry cannot be retrieved.
+*/
+int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr,
+		uint32_t entry_index, struct pp_power_state *power_state,
+		int (*call_back_func)(struct pp_hwmgr *, void *,
+				struct pp_power_state *, void *, uint32_t))
+{
+	int result = 0;
+	const ATOM_Tonga_State_Array * state_arrays;
+	const ATOM_Tonga_State *state_entry;
+	const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+
+	PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;);
+	power_state->classification.bios_index = entry_index;
+
+	if (pp_table->sHeader.ucTableFormatRevision >=
+			ATOM_Tonga_TABLE_REVISION_TONGA) {
+		state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
+				le16_to_cpu(pp_table->usStateArrayOffset));
+
+		PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset),
+				"Invalid PowerPlay Table State Array Offset.", return -1);
+		PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
+				"Invalid PowerPlay Table State Array.", return -1);
+		PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
+				"Invalid PowerPlay Table State Array Entry.", return -1);
+
+		state_entry = &(state_arrays->states[entry_index]);
+
+		result = call_back_func(hwmgr, (void *)state_entry, power_state,
+				(void *)pp_table,
+				make_classification_flags(hwmgr,
+					le16_to_cpu(state_entry->usClassification),
+					le16_to_cpu(state_entry->usClassification2)));
+	}
+
+	if (!result && (power_state->classification.flags &
+			PP_StateClassificationFlag_Boot))
+		result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware));
+
+	return result;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef TONGA_PROCESSPPTABLES_H
+#define TONGA_PROCESSPPTABLES_H
+
+#include "hwmgr.h"
+
+extern const struct pp_table_func tonga_pptable_funcs;
+extern int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr);
+extern int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, uint32_t entry_index,
+		struct pp_power_state *power_state, int (*call_back_func)(struct pp_hwmgr *, void *,
+				struct pp_power_state *, void *, uint32_t));
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <asm/div64.h>
+#include "tonga_thermal.h"
+#include "tonga_hwmgr.h"
+#include "tonga_smumgr.h"
+#include "tonga_ppsmc.h"
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
+
+/**
+* Get Fan Speed Control Parameters.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pSpeed is the address of the structure where the result is to be placed.
+* @exception Always succeeds except if we cannot zero out the output structure.
+*/
+int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info)
+{
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		return 0;
+
+	fan_speed_info->supports_percent_read = true;
+	fan_speed_info->supports_percent_write = true;
+	fan_speed_info->min_percent = 0;
+	fan_speed_info->max_percent = 100;
+
+	if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
+		fan_speed_info->supports_rpm_read = true;
+		fan_speed_info->supports_rpm_write = true;
+		fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
+		fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
+	} else {
+		fan_speed_info->min_rpm = 0;
+		fan_speed_info->max_rpm = 0;
+	}
+
+	return 0;
+}
+
+/**
+* Get Fan Speed in percent.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pSpeed is the address of the structure where the result is to be placed.
+* @exception Fails is the 100% setting appears to be 0.
+*/
+int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed)
+{
+	uint32_t duty100;
+	uint32_t duty;
+	uint64_t tmp64;
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		return 0;
+
+	duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
+	duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY);
+
+	if (0 == duty100)
+		return -EINVAL;
+
+
+	tmp64 = (uint64_t)duty * 100;
+	do_div(tmp64, duty100);
+	*speed = (uint32_t)tmp64;
+
+	if (*speed > 100)
+		*speed = 100;
+
+	return 0;
+}
+
+/**
+* Get Fan Speed in RPM.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    speed is the address of the structure where the result is to be placed.
+* @exception Returns not supported if no fan is found or if pulses per revolution are not set
+*/
+int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
+{
+	return 0;
+}
+
+/**
+* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
+* @param    hwmgr  the address of the powerplay hardware manager.
+*           mode    the fan control mode, 0 default, 1 by percent, 5, by RPM
+* @exception Should always succeed.
+*/
+int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+
+	if (hwmgr->fan_ctrl_is_in_default_mode) {
+		hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE);
+		hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN);
+		hwmgr->fan_ctrl_is_in_default_mode = false;
+	}
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0);
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode);
+
+	return 0;
+}
+
+/**
+* Reset Fan Speed Control to default mode.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @exception Should always succeed.
+*/
+int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
+{
+	if (!hwmgr->fan_ctrl_is_in_default_mode) {
+		PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
+		PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin);
+		hwmgr->fan_ctrl_is_in_default_mode = true;
+	}
+
+	return 0;
+}
+
+int tonga_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+	int result;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
+		cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
+		result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ?  0 : -EINVAL;
+/*
+		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_FanSpeedInTableIsRPM))
+			hwmgr->set_max_fan_rpm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM);
+		else
+			hwmgr->set_max_fan_pwm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM);
+*/
+	} else {
+		cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
+		result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ?  0 : -EINVAL;
+	}
+/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
+	if (result == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature != 0)
+		result = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanTemperatureTarget, \
+								hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature) ? 0 : -EINVAL);
+*/
+	return result;
+}
+
+
+int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+	return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ?  0 : -EINVAL;
+}
+
+/**
+* Set Fan Speed in percent.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    speed is the percentage value (0% - 100%) to be set.
+* @exception Fails is the 100% setting appears to be 0.
+*/
+int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed)
+{
+	uint32_t duty100;
+	uint32_t duty;
+	uint64_t tmp64;
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		return -EINVAL;
+
+	if (speed > 100)
+		speed = 100;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
+		tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
+
+	duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
+
+	if (0 == duty100)
+		return -EINVAL;
+
+	tmp64 = (uint64_t)speed * 100;
+	do_div(tmp64, duty100);
+	duty = (uint32_t)tmp64;
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
+
+	return tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+}
+
+/**
+* Reset Fan Speed to default.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @exception Always succeeds.
+*/
+int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
+{
+	int result;
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		return 0;
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
+		result = tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+		if (0 == result)
+			result = tonga_fan_ctrl_start_smc_fan_control(hwmgr);
+	} else
+		result = tonga_fan_ctrl_set_default_mode(hwmgr);
+
+	return result;
+}
+
+/**
+* Set Fan Speed in RPM.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    speed is the percentage value (min - max) to be set.
+* @exception Fails is the speed not lie between min and max.
+*/
+int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
+{
+	return 0;
+}
+
+/**
+* Reads the remote temperature from the SIslands thermal controller.
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr)
+{
+	int temp;
+
+	temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP);
+
+/* Bit 9 means the reading is lower than the lowest usable value. */
+	if (0 != (0x200 & temp))
+		temp = TONGA_THERMAL_MAXIMUM_TEMP_READING;
+	else
+		temp = (temp & 0x1ff);
+
+	temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+	return temp;
+}
+
+/**
+* Set the requested temperature range for high and low alert signals
+*
+* @param    hwmgr The address of the hardware manager.
+* @param    range Temperature range to be programmed for high and low alert signals
+* @exception PP_Result_BadInput if the input data is not valid.
+*/
+static int tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp)
+{
+	uint32_t low = TONGA_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+	uint32_t high = TONGA_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+	if (low < low_temp)
+		low = low_temp;
+	if (high > high_temp)
+		high = high_temp;
+
+	if (low > high)
+		return -EINVAL;
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+
+	return 0;
+}
+
+/**
+* Programs thermal controller one-time setting registers
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+static int tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+	if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
+		PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+						CG_TACH_CTRL, EDGE_PER_REV,
+						hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1);
+
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
+
+	return 0;
+}
+
+/**
+* Enable thermal alerts on the RV770 thermal controller.
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+static int tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr)
+{
+	uint32_t alert;
+
+	alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
+	alert &= ~(TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+	/* send message to SMU to enable internal thermal interrupts */
+	return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1;
+}
+
+/**
+* Disable thermal alerts on the RV770 thermal controller.
+* @param    hwmgr The address of the hardware manager.
+*/
+static int tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr)
+{
+	uint32_t alert;
+
+	alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
+	alert |= (TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
+	PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+	/* send message to SMU to disable internal thermal interrupts */
+	return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1;
+}
+
+/**
+* Uninitialize the thermal controller.
+* Currently just disables alerts.
+* @param    hwmgr The address of the hardware manager.
+*/
+int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+	int result = tonga_thermal_disable_alert(hwmgr);
+
+	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+		tonga_fan_ctrl_set_default_mode(hwmgr);
+
+	return result;
+}
+
+/**
+* Set up the fan table to control the fan using the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int tf_tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+	struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+	SMU72_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+	uint32_t duty100;
+	uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+	uint16_t fdo_min, slope1, slope2;
+	uint32_t reference_clock;
+	int res;
+	uint64_t tmp64;
+
+	if (0 == data->fan_table_start) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
+		return 0;
+	}
+
+	duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
+
+	if (0 == duty100) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
+		return 0;
+	}
+
+	tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
+	do_div(tmp64, 10000);
+	fdo_min = (uint16_t)tmp64;
+
+	t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
+	t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
+
+	pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
+	pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
+
+	slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+	slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+	fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
+	fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
+	fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
+
+	fan_table.Slope1 = cpu_to_be16(slope1);
+	fan_table.Slope2 = cpu_to_be16(slope2);
+
+	fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+	fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
+
+	fan_table.HystUp = cpu_to_be16(1);
+
+	fan_table.HystSlope = cpu_to_be16(1);
+
+	fan_table.TempRespLim = cpu_to_be16(5);
+
+	reference_clock = tonga_get_xclk(hwmgr);
+
+	fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
+
+	fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
+
+	fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
+
+	fan_table.FanControl_GL_Flag = 1;
+
+	res = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end);
+/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
+	if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0)
+		res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \
+						hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1);
+
+	if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0)
+		res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \
+					hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1);
+
+	if (0 != res)
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
+*/
+	return 0;
+}
+
+/**
+* Start the fan control on the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int tf_tonga_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+/* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table.
+ * Make sure that we still think controlling the fan is OK.
+*/
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
+		tonga_fan_ctrl_start_smc_fan_control(hwmgr);
+		tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+	}
+
+	return 0;
+}
+
+/**
+* Set temperature range for high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+	struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
+
+	if (range == NULL)
+		return -EINVAL;
+
+	return tonga_thermal_set_temperature_range(hwmgr, range->min, range->max);
+}
+
+/**
+* Programs one-time setting registers
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from initialize thermal controller routine
+*/
+int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+    return tonga_thermal_initialize(hwmgr);
+}
+
+/**
+* Enable high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from enable alert routine
+*/
+int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+	return tonga_thermal_enable_alert(hwmgr);
+}
+
+/**
+* Disable high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from disable alert routine
+*/
+static int tf_tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+	return tonga_thermal_disable_alert(hwmgr);
+}
+
+static struct phm_master_table_item tonga_thermal_start_thermal_controller_master_list[] = {
+	{ NULL, tf_tonga_thermal_initialize },
+	{ NULL, tf_tonga_thermal_set_temperature_range },
+	{ NULL, tf_tonga_thermal_enable_alert },
+/* We should restrict performance levels to low before we halt the SMC.
+ * On the other hand we are still in boot state when we do this so it would be pointless.
+ * If this assumption changes we have to revisit this table.
+ */
+	{ NULL, tf_tonga_thermal_setup_fan_table},
+	{ NULL, tf_tonga_thermal_start_smc_fan_control},
+	{ NULL, NULL }
+};
+
+static struct phm_master_table_header tonga_thermal_start_thermal_controller_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	tonga_thermal_start_thermal_controller_master_list
+};
+
+static struct phm_master_table_item tonga_thermal_set_temperature_range_master_list[] = {
+	{ NULL, tf_tonga_thermal_disable_alert},
+	{ NULL, tf_tonga_thermal_set_temperature_range},
+	{ NULL, tf_tonga_thermal_enable_alert},
+	{ NULL, NULL }
+};
+
+struct phm_master_table_header tonga_thermal_set_temperature_range_master = {
+	0,
+	PHM_MasterTableFlag_None,
+	tonga_thermal_set_temperature_range_master_list
+};
+
+int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+	if (!hwmgr->thermal_controller.fanInfo.bNoFan)
+		tonga_fan_ctrl_set_default_mode(hwmgr);
+	return 0;
+}
+
+/**
+* Initializes the thermal controller related functions in the Hardware Manager structure.
+* @param    hwmgr The address of the hardware manager.
+* @exception Any error code from the low-level communication.
+*/
+int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+	int result;
+
+	result = phm_construct_table(hwmgr, &tonga_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range));
+
+	if (0 == result) {
+		result = phm_construct_table(hwmgr,
+						&tonga_thermal_start_thermal_controller_master,
+						&(hwmgr->start_thermal_controller));
+		if (0 != result)
+			phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
+	}
+
+	if (0 == result)
+		hwmgr->fan_ctrl_is_in_default_mode = true;
+	return result;
+}
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef TONGA_THERMAL_H
+#define TONGA_THERMAL_H
+
+#include "hwmgr.h"
+
+#define TONGA_THERMAL_HIGH_ALERT_MASK         0x1
+#define TONGA_THERMAL_LOW_ALERT_MASK          0x2
+
+#define TONGA_THERMAL_MINIMUM_TEMP_READING    -256
+#define TONGA_THERMAL_MAXIMUM_TEMP_READING    255
+
+#define TONGA_THERMAL_MINIMUM_ALERT_TEMP      0
+#define TONGA_THERMAL_MAXIMUM_ALERT_TEMP      255
+
+#define FDO_PWM_MODE_STATIC  1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
+
+extern int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+extern int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+extern int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+
+extern int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr);
+extern int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
+extern int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
+extern int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
+extern int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
+extern int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
+extern int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr);
+extern int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
+extern int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _AMD_POWERPLAY_H_
+#define _AMD_POWERPLAY_H_
+
+#include <linux/seq_file.h>
+#include <linux/types.h>
+#include "amd_shared.h"
+#include "cgs_common.h"
+
+enum amd_pp_event {
+	AMD_PP_EVENT_INITIALIZE = 0,
+	AMD_PP_EVENT_UNINITIALIZE,
+	AMD_PP_EVENT_POWER_SOURCE_CHANGE,
+	AMD_PP_EVENT_SUSPEND,
+	AMD_PP_EVENT_RESUME,
+	AMD_PP_EVENT_ENTER_REST_STATE,
+	AMD_PP_EVENT_EXIT_REST_STATE,
+	AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE,
+	AMD_PP_EVENT_THERMAL_NOTIFICATION,
+	AMD_PP_EVENT_VBIOS_NOTIFICATION,
+	AMD_PP_EVENT_ENTER_THERMAL_STATE,
+	AMD_PP_EVENT_EXIT_THERMAL_STATE,
+	AMD_PP_EVENT_ENTER_FORCED_STATE,
+	AMD_PP_EVENT_EXIT_FORCED_STATE,
+	AMD_PP_EVENT_ENTER_EXCLUSIVE_MODE,
+	AMD_PP_EVENT_EXIT_EXCLUSIVE_MODE,
+	AMD_PP_EVENT_ENTER_SCREEN_SAVER,
+	AMD_PP_EVENT_EXIT_SCREEN_SAVER,
+	AMD_PP_EVENT_VPU_RECOVERY_BEGIN,
+	AMD_PP_EVENT_VPU_RECOVERY_END,
+	AMD_PP_EVENT_ENABLE_POWER_PLAY,
+	AMD_PP_EVENT_DISABLE_POWER_PLAY,
+	AMD_PP_EVENT_CHANGE_POWER_SOURCE_UI_LABEL,
+	AMD_PP_EVENT_ENABLE_USER2D_PERFORMANCE,
+	AMD_PP_EVENT_DISABLE_USER2D_PERFORMANCE,
+	AMD_PP_EVENT_ENABLE_USER3D_PERFORMANCE,
+	AMD_PP_EVENT_DISABLE_USER3D_PERFORMANCE,
+	AMD_PP_EVENT_ENABLE_OVER_DRIVE_TEST,
+	AMD_PP_EVENT_DISABLE_OVER_DRIVE_TEST,
+	AMD_PP_EVENT_ENABLE_REDUCED_REFRESH_RATE,
+	AMD_PP_EVENT_DISABLE_REDUCED_REFRESH_RATE,
+	AMD_PP_EVENT_ENABLE_GFX_CLOCK_GATING,
+	AMD_PP_EVENT_DISABLE_GFX_CLOCK_GATING,
+	AMD_PP_EVENT_ENABLE_CGPG,
+	AMD_PP_EVENT_DISABLE_CGPG,
+	AMD_PP_EVENT_ENTER_TEXT_MODE,
+	AMD_PP_EVENT_EXIT_TEXT_MODE,
+	AMD_PP_EVENT_VIDEO_START,
+	AMD_PP_EVENT_VIDEO_STOP,
+	AMD_PP_EVENT_ENABLE_USER_STATE,
+	AMD_PP_EVENT_DISABLE_USER_STATE,
+	AMD_PP_EVENT_READJUST_POWER_STATE,
+	AMD_PP_EVENT_START_INACTIVITY,
+	AMD_PP_EVENT_STOP_INACTIVITY,
+	AMD_PP_EVENT_LINKED_ADAPTERS_READY,
+	AMD_PP_EVENT_ADAPTER_SAFE_TO_DISABLE,
+	AMD_PP_EVENT_COMPLETE_INIT,
+	AMD_PP_EVENT_CRITICAL_THERMAL_FAULT,
+	AMD_PP_EVENT_BACKLIGHT_CHANGED,
+	AMD_PP_EVENT_ENABLE_VARI_BRIGHT,
+	AMD_PP_EVENT_DISABLE_VARI_BRIGHT,
+	AMD_PP_EVENT_ENABLE_VARI_BRIGHT_ON_POWER_XPRESS,
+	AMD_PP_EVENT_DISABLE_VARI_BRIGHT_ON_POWER_XPRESS,
+	AMD_PP_EVENT_SET_VARI_BRIGHT_LEVEL,
+	AMD_PP_EVENT_VARI_BRIGHT_MONITOR_MEASUREMENT,
+	AMD_PP_EVENT_SCREEN_ON,
+	AMD_PP_EVENT_SCREEN_OFF,
+	AMD_PP_EVENT_PRE_DISPLAY_CONFIG_CHANGE,
+	AMD_PP_EVENT_ENTER_ULP_STATE,
+	AMD_PP_EVENT_EXIT_ULP_STATE,
+	AMD_PP_EVENT_REGISTER_IP_STATE,
+	AMD_PP_EVENT_UNREGISTER_IP_STATE,
+	AMD_PP_EVENT_ENTER_MGPU_MODE,
+	AMD_PP_EVENT_EXIT_MGPU_MODE,
+	AMD_PP_EVENT_ENTER_MULTI_GPU_MODE,
+	AMD_PP_EVENT_PRE_SUSPEND,
+	AMD_PP_EVENT_PRE_RESUME,
+	AMD_PP_EVENT_ENTER_BACOS,
+	AMD_PP_EVENT_EXIT_BACOS,
+	AMD_PP_EVENT_RESUME_BACO,
+	AMD_PP_EVENT_RESET_BACO,
+	AMD_PP_EVENT_PRE_DISPLAY_PHY_ACCESS,
+	AMD_PP_EVENT_POST_DISPLAY_PHY_CCESS,
+	AMD_PP_EVENT_START_COMPUTE_APPLICATION,
+	AMD_PP_EVENT_STOP_COMPUTE_APPLICATION,
+	AMD_PP_EVENT_REDUCE_POWER_LIMIT,
+	AMD_PP_EVENT_ENTER_FRAME_LOCK,
+	AMD_PP_EVENT_EXIT_FRAME_LOOCK,
+	AMD_PP_EVENT_LONG_IDLE_REQUEST_BACO,
+	AMD_PP_EVENT_LONG_IDLE_ENTER_BACO,
+	AMD_PP_EVENT_LONG_IDLE_EXIT_BACO,
+	AMD_PP_EVENT_HIBERNATE,
+	AMD_PP_EVENT_CONNECTED_STANDBY,
+	AMD_PP_EVENT_ENTER_SELF_REFRESH,
+	AMD_PP_EVENT_EXIT_SELF_REFRESH,
+	AMD_PP_EVENT_START_AVFS_BTC,
+	AMD_PP_EVENT_MAX
+};
+
+enum amd_dpm_forced_level {
+	AMD_DPM_FORCED_LEVEL_AUTO = 0,
+	AMD_DPM_FORCED_LEVEL_LOW = 1,
+	AMD_DPM_FORCED_LEVEL_HIGH = 2,
+};
+
+struct amd_pp_init {
+	struct cgs_device *device;
+	uint32_t chip_family;
+	uint32_t chip_id;
+	uint32_t rev_id;
+};
+enum amd_pp_display_config_type{
+	AMD_PP_DisplayConfigType_None = 0,
+	AMD_PP_DisplayConfigType_DP54 ,
+	AMD_PP_DisplayConfigType_DP432 ,
+	AMD_PP_DisplayConfigType_DP324 ,
+	AMD_PP_DisplayConfigType_DP27,
+	AMD_PP_DisplayConfigType_DP243,
+	AMD_PP_DisplayConfigType_DP216,
+	AMD_PP_DisplayConfigType_DP162,
+	AMD_PP_DisplayConfigType_HDMI6G ,
+	AMD_PP_DisplayConfigType_HDMI297 ,
+	AMD_PP_DisplayConfigType_HDMI162,
+	AMD_PP_DisplayConfigType_LVDS,
+	AMD_PP_DisplayConfigType_DVI,
+	AMD_PP_DisplayConfigType_WIRELESS,
+	AMD_PP_DisplayConfigType_VGA
+};
+
+struct single_display_configuration
+{
+	uint32_t controller_index;
+	uint32_t controller_id;
+	uint32_t signal_type;
+	uint32_t display_state;
+	/* phy id for the primary internal transmitter */
+	uint8_t primary_transmitter_phyi_d;
+	/* bitmap with the active lanes */
+	uint8_t primary_transmitter_active_lanemap;
+	/* phy id for the secondary internal transmitter (for dual-link dvi) */
+	uint8_t secondary_transmitter_phy_id;
+	/* bitmap with the active lanes */
+	uint8_t secondary_transmitter_active_lanemap;
+	/* misc phy settings for SMU. */
+	uint32_t config_flags;
+	uint32_t display_type;
+	uint32_t view_resolution_cx;
+	uint32_t view_resolution_cy;
+	enum amd_pp_display_config_type displayconfigtype;
+	uint32_t vertical_refresh; /* for active display */
+};
+
+#define MAX_NUM_DISPLAY 32
+
+struct amd_pp_display_configuration {
+	bool nb_pstate_switch_disable;/* controls NB PState switch */
+	bool cpu_cc6_disable; /* controls CPU CState switch ( on or off) */
+	bool cpu_pstate_disable;
+	uint32_t cpu_pstate_separation_time;
+
+	uint32_t num_display;  /* total number of display*/
+	uint32_t num_path_including_non_display;
+	uint32_t crossfire_display_index;
+	uint32_t min_mem_set_clock;
+	uint32_t min_core_set_clock;
+	/* unit 10KHz x bit*/
+	uint32_t min_bus_bandwidth;
+	/* minimum required stutter sclk, in 10khz uint32_t ulMinCoreSetClk;*/
+	uint32_t min_core_set_clock_in_sr;
+
+	struct single_display_configuration displays[MAX_NUM_DISPLAY];
+
+	uint32_t vrefresh; /* for active display*/
+
+	uint32_t min_vblank_time; /* for active display*/
+	bool multi_monitor_in_sync;
+	/* Controller Index of primary display - used in MCLK SMC switching hang
+	 * SW Workaround*/
+	uint32_t crtc_index;
+	/* htotal*1000/pixelclk - used in MCLK SMC switching hang SW Workaround*/
+	uint32_t line_time_in_us;
+	bool invalid_vblank_time;
+
+	uint32_t display_clk;
+	/*
+	 * for given display configuration if multimonitormnsync == false then
+	 * Memory clock DPMS with this latency or below is allowed, DPMS with
+	 * higher latency not allowed.
+	 */
+	uint32_t dce_tolerable_mclk_in_active_latency;
+};
+
+struct amd_pp_dal_clock_info {
+	uint32_t	engine_max_clock;
+	uint32_t	memory_max_clock;
+	uint32_t	level;
+};
+
+enum {
+	PP_GROUP_UNKNOWN = 0,
+	PP_GROUP_GFX = 1,
+	PP_GROUP_SYS,
+	PP_GROUP_MAX
+};
+
+#define PP_GROUP_MASK        0xF0000000
+#define PP_GROUP_SHIFT       28
+
+#define PP_BLOCK_MASK        0x0FFFFF00
+#define PP_BLOCK_SHIFT       8
+
+#define PP_BLOCK_GFX_CG         0x01
+#define PP_BLOCK_GFX_MG         0x02
+#define PP_BLOCK_SYS_BIF        0x01
+#define PP_BLOCK_SYS_MC         0x02
+#define PP_BLOCK_SYS_ROM        0x04
+#define PP_BLOCK_SYS_DRM        0x08
+#define PP_BLOCK_SYS_HDP        0x10
+#define PP_BLOCK_SYS_SDMA       0x20
+
+#define PP_STATE_MASK           0x0000000F
+#define PP_STATE_SHIFT          0
+#define PP_STATE_SUPPORT_MASK   0x000000F0
+#define PP_STATE_SUPPORT_SHIFT  0
+
+#define PP_STATE_CG             0x01
+#define PP_STATE_LS             0x02
+#define PP_STATE_DS             0x04
+#define PP_STATE_SD             0x08
+#define PP_STATE_SUPPORT_CG     0x10
+#define PP_STATE_SUPPORT_LS     0x20
+#define PP_STATE_SUPPORT_DS     0x40
+#define PP_STATE_SUPPORT_SD     0x80
+
+#define PP_CG_MSG_ID(group, block, support, state) (group << PP_GROUP_SHIFT |\
+								block << PP_BLOCK_SHIFT |\
+								support << PP_STATE_SUPPORT_SHIFT |\
+								state << PP_STATE_SHIFT)
+
+struct amd_powerplay_funcs {
+	int (*get_temperature)(void *handle);
+	int (*load_firmware)(void *handle);
+	int (*wait_for_fw_loading_complete)(void *handle);
+	int (*force_performance_level)(void *handle, enum amd_dpm_forced_level level);
+	enum amd_dpm_forced_level (*get_performance_level)(void *handle);
+	enum amd_pm_state_type (*get_current_power_state)(void *handle);
+	int (*get_sclk)(void *handle, bool low);
+	int (*get_mclk)(void *handle, bool low);
+	int (*powergate_vce)(void *handle, bool gate);
+	int (*powergate_uvd)(void *handle, bool gate);
+	int (*dispatch_tasks)(void *handle, enum amd_pp_event event_id,
+				   void *input, void *output);
+	void (*print_current_performance_level)(void *handle,
+						      struct seq_file *m);
+	int (*set_fan_control_mode)(void *handle, uint32_t mode);
+	int (*get_fan_control_mode)(void *handle);
+	int (*set_fan_speed_percent)(void *handle, uint32_t percent);
+	int (*get_fan_speed_percent)(void *handle, uint32_t *speed);
+};
+
+struct amd_powerplay {
+	void *pp_handle;
+	const struct amd_ip_funcs *ip_funcs;
+	const struct amd_powerplay_funcs *pp_funcs;
+};
+
+int amd_powerplay_init(struct amd_pp_init *pp_init,
+		       struct amd_powerplay *amd_pp);
+int amd_powerplay_fini(void *handle);
+
+int amd_powerplay_display_configuration_change(void *handle, const void *input);
+
+int amd_powerplay_get_display_power_level(void *handle,
+		struct amd_pp_dal_clock_info *output);
+
+
+#endif /* _AMD_POWERPLAY_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/cz_ppsmc.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/cz_ppsmc.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef CZ_PP_SMC_H
+#define CZ_PP_SMC_H
+
+#pragma pack(push, 1)
+
+/* Fan control algorithm:*/
+#define FDO_MODE_HARDWARE 0
+#define FDO_MODE_PIECE_WISE_LINEAR 1
+
+enum FAN_CONTROL {
+    FAN_CONTROL_FUZZY,
+    FAN_CONTROL_TABLE
+};
+
+enum DPM_ARRAY {
+    DPM_ARRAY_HARD_MAX,
+    DPM_ARRAY_HARD_MIN,
+    DPM_ARRAY_SOFT_MAX,
+    DPM_ARRAY_SOFT_MIN
+};
+
+/*
+ * Return codes for driver to SMC communication.
+ * Leave these #define-s, enums might not be exactly 8-bits on the microcontroller.
+ */
+#define PPSMC_Result_OK             ((uint16_t)0x01)
+#define PPSMC_Result_NoMore         ((uint16_t)0x02)
+#define PPSMC_Result_NotNow         ((uint16_t)0x03)
+#define PPSMC_Result_Failed         ((uint16_t)0xFF)
+#define PPSMC_Result_UnknownCmd     ((uint16_t)0xFE)
+#define PPSMC_Result_UnknownVT      ((uint16_t)0xFD)
+
+#define PPSMC_isERROR(x)            ((uint16_t)0x80 & (x))
+
+/*
+ * Supported driver messages
+ */
+#define PPSMC_MSG_Test                        ((uint16_t) 0x1)
+#define PPSMC_MSG_GetFeatureStatus            ((uint16_t) 0x2)
+#define PPSMC_MSG_EnableAllSmuFeatures        ((uint16_t) 0x3)
+#define PPSMC_MSG_DisableAllSmuFeatures       ((uint16_t) 0x4)
+#define PPSMC_MSG_OptimizeBattery             ((uint16_t) 0x5)
+#define PPSMC_MSG_MaximizePerf                ((uint16_t) 0x6)
+#define PPSMC_MSG_UVDPowerOFF                 ((uint16_t) 0x7)
+#define PPSMC_MSG_UVDPowerON                  ((uint16_t) 0x8)
+#define PPSMC_MSG_VCEPowerOFF                 ((uint16_t) 0x9)
+#define PPSMC_MSG_VCEPowerON                  ((uint16_t) 0xA)
+#define PPSMC_MSG_ACPPowerOFF                 ((uint16_t) 0xB)
+#define PPSMC_MSG_ACPPowerON                  ((uint16_t) 0xC)
+#define PPSMC_MSG_SDMAPowerOFF                ((uint16_t) 0xD)
+#define PPSMC_MSG_SDMAPowerON                 ((uint16_t) 0xE)
+#define PPSMC_MSG_XDMAPowerOFF                ((uint16_t) 0xF)
+#define PPSMC_MSG_XDMAPowerON                 ((uint16_t) 0x10)
+#define PPSMC_MSG_SetMinDeepSleepSclk         ((uint16_t) 0x11)
+#define PPSMC_MSG_SetSclkSoftMin              ((uint16_t) 0x12)
+#define PPSMC_MSG_SetSclkSoftMax              ((uint16_t) 0x13)
+#define PPSMC_MSG_SetSclkHardMin              ((uint16_t) 0x14)
+#define PPSMC_MSG_SetSclkHardMax              ((uint16_t) 0x15)
+#define PPSMC_MSG_SetLclkSoftMin              ((uint16_t) 0x16)
+#define PPSMC_MSG_SetLclkSoftMax              ((uint16_t) 0x17)
+#define PPSMC_MSG_SetLclkHardMin              ((uint16_t) 0x18)
+#define PPSMC_MSG_SetLclkHardMax              ((uint16_t) 0x19)
+#define PPSMC_MSG_SetUvdSoftMin               ((uint16_t) 0x1A)
+#define PPSMC_MSG_SetUvdSoftMax               ((uint16_t) 0x1B)
+#define PPSMC_MSG_SetUvdHardMin               ((uint16_t) 0x1C)
+#define PPSMC_MSG_SetUvdHardMax               ((uint16_t) 0x1D)
+#define PPSMC_MSG_SetEclkSoftMin              ((uint16_t) 0x1E)
+#define PPSMC_MSG_SetEclkSoftMax              ((uint16_t) 0x1F)
+#define PPSMC_MSG_SetEclkHardMin              ((uint16_t) 0x20)
+#define PPSMC_MSG_SetEclkHardMax              ((uint16_t) 0x21)
+#define PPSMC_MSG_SetAclkSoftMin              ((uint16_t) 0x22)
+#define PPSMC_MSG_SetAclkSoftMax              ((uint16_t) 0x23)
+#define PPSMC_MSG_SetAclkHardMin              ((uint16_t) 0x24)
+#define PPSMC_MSG_SetAclkHardMax              ((uint16_t) 0x25)
+#define PPSMC_MSG_SetNclkSoftMin              ((uint16_t) 0x26)
+#define PPSMC_MSG_SetNclkSoftMax              ((uint16_t) 0x27)
+#define PPSMC_MSG_SetNclkHardMin              ((uint16_t) 0x28)
+#define PPSMC_MSG_SetNclkHardMax              ((uint16_t) 0x29)
+#define PPSMC_MSG_SetPstateSoftMin            ((uint16_t) 0x2A)
+#define PPSMC_MSG_SetPstateSoftMax            ((uint16_t) 0x2B)
+#define PPSMC_MSG_SetPstateHardMin            ((uint16_t) 0x2C)
+#define PPSMC_MSG_SetPstateHardMax            ((uint16_t) 0x2D)
+#define PPSMC_MSG_DisableLowMemoryPstate      ((uint16_t) 0x2E)
+#define PPSMC_MSG_EnableLowMemoryPstate       ((uint16_t) 0x2F)
+#define PPSMC_MSG_UcodeAddressLow             ((uint16_t) 0x30)
+#define PPSMC_MSG_UcodeAddressHigh            ((uint16_t) 0x31)
+#define PPSMC_MSG_UcodeLoadStatus             ((uint16_t) 0x32)
+#define PPSMC_MSG_DriverDramAddrHi            ((uint16_t) 0x33)
+#define PPSMC_MSG_DriverDramAddrLo            ((uint16_t) 0x34)
+#define PPSMC_MSG_CondExecDramAddrHi          ((uint16_t) 0x35)
+#define PPSMC_MSG_CondExecDramAddrLo          ((uint16_t) 0x36)
+#define PPSMC_MSG_LoadUcodes                  ((uint16_t) 0x37)
+#define PPSMC_MSG_DriverResetMode             ((uint16_t) 0x38)
+#define PPSMC_MSG_PowerStateNotify            ((uint16_t) 0x39)
+#define PPSMC_MSG_SetDisplayPhyConfig         ((uint16_t) 0x3A)
+#define PPSMC_MSG_GetMaxSclkLevel             ((uint16_t) 0x3B)
+#define PPSMC_MSG_GetMaxLclkLevel             ((uint16_t) 0x3C)
+#define PPSMC_MSG_GetMaxUvdLevel              ((uint16_t) 0x3D)
+#define PPSMC_MSG_GetMaxEclkLevel             ((uint16_t) 0x3E)
+#define PPSMC_MSG_GetMaxAclkLevel             ((uint16_t) 0x3F)
+#define PPSMC_MSG_GetMaxNclkLevel             ((uint16_t) 0x40)
+#define PPSMC_MSG_GetMaxPstate                ((uint16_t) 0x41)
+#define PPSMC_MSG_DramAddrHiVirtual           ((uint16_t) 0x42)
+#define PPSMC_MSG_DramAddrLoVirtual           ((uint16_t) 0x43)
+#define PPSMC_MSG_DramAddrHiPhysical          ((uint16_t) 0x44)
+#define PPSMC_MSG_DramAddrLoPhysical          ((uint16_t) 0x45)
+#define PPSMC_MSG_DramBufferSize              ((uint16_t) 0x46)
+#define PPSMC_MSG_SetMmPwrLogDramAddrHi       ((uint16_t) 0x47)
+#define PPSMC_MSG_SetMmPwrLogDramAddrLo       ((uint16_t) 0x48)
+#define PPSMC_MSG_SetClkTableAddrHi           ((uint16_t) 0x49)
+#define PPSMC_MSG_SetClkTableAddrLo           ((uint16_t) 0x4A)
+#define PPSMC_MSG_GetConservativePowerLimit   ((uint16_t) 0x4B)
+
+#define PPSMC_MSG_InitJobs                    ((uint16_t) 0x252)
+#define PPSMC_MSG_ExecuteJob                  ((uint16_t) 0x254)
+
+#define PPSMC_MSG_NBDPM_Enable                ((uint16_t) 0x140)
+#define PPSMC_MSG_NBDPM_Disable               ((uint16_t) 0x141)
+
+#define PPSMC_MSG_DPM_FPS_Mode                ((uint16_t) 0x15d)
+#define PPSMC_MSG_DPM_Activity_Mode           ((uint16_t) 0x15e)
+
+#define PPSMC_MSG_PmStatusLogStart            ((uint16_t) 0x170)
+#define PPSMC_MSG_PmStatusLogSample           ((uint16_t) 0x171)
+
+#define PPSMC_MSG_AllowLowSclkInterrupt       ((uint16_t) 0x184)
+#define PPSMC_MSG_MmPowerMonitorStart         ((uint16_t) 0x18F)
+#define PPSMC_MSG_MmPowerMonitorStop          ((uint16_t) 0x190)
+#define PPSMC_MSG_MmPowerMonitorRestart       ((uint16_t) 0x191)
+
+#define PPSMC_MSG_SetClockGateMask            ((uint16_t) 0x260)
+#define PPSMC_MSG_SetFpsThresholdLo           ((uint16_t) 0x264)
+#define PPSMC_MSG_SetFpsThresholdHi           ((uint16_t) 0x265)
+#define PPSMC_MSG_SetLowSclkIntrThreshold     ((uint16_t) 0x266)
+
+#define PPSMC_MSG_ClkTableXferToDram          ((uint16_t) 0x267)
+#define PPSMC_MSG_ClkTableXferToSmu           ((uint16_t) 0x268)
+#define PPSMC_MSG_GetAverageGraphicsActivity  ((uint16_t) 0x269)
+#define PPSMC_MSG_GetAverageGioActivity       ((uint16_t) 0x26A)
+#define PPSMC_MSG_SetLoggerBufferSize         ((uint16_t) 0x26B)
+#define PPSMC_MSG_SetLoggerAddressHigh        ((uint16_t) 0x26C)
+#define PPSMC_MSG_SetLoggerAddressLow         ((uint16_t) 0x26D)
+#define PPSMC_MSG_SetWatermarkFrequency       ((uint16_t) 0x26E)
+#define PPSMC_MSG_SetDisplaySizePowerParams   ((uint16_t) 0x26F)
+
+/* REMOVE LATER*/
+#define PPSMC_MSG_DPM_ForceState              ((uint16_t) 0x104)
+
+/* Feature Enable Masks*/
+#define NB_DPM_MASK             0x00000800
+#define VDDGFX_MASK             0x00800000
+#define VCE_DPM_MASK            0x00400000
+#define ACP_DPM_MASK            0x00040000
+#define UVD_DPM_MASK            0x00010000
+#define GFX_CU_PG_MASK          0x00004000
+#define SCLK_DPM_MASK           0x00080000
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+
+#endif
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/eventmanager.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/eventmanager.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _EVENT_MANAGER_H_
+#define _EVENT_MANAGER_H_
+
+#include "power_state.h"
+#include "pp_power_source.h"
+#include "hardwaremanager.h"
+#include "pp_asicblocks.h"
+
+struct pp_eventmgr;
+enum amd_pp_event;
+
+enum PEM_EventDataValid {
+	PEM_EventDataValid_RequestedStateID = 0,
+	PEM_EventDataValid_RequestedUILabel,
+	PEM_EventDataValid_NewPowerState,
+	PEM_EventDataValid_RequestedPowerSource,
+	PEM_EventDataValid_RequestedClocks,
+	PEM_EventDataValid_CurrentTemperature,
+	PEM_EventDataValid_AsicBlocks,
+	PEM_EventDataValid_ODParameters,
+	PEM_EventDataValid_PXAdapterPrefs,
+	PEM_EventDataValid_PXUserPrefs,
+	PEM_EventDataValid_PXSwitchReason,
+	PEM_EventDataValid_PXSwitchPhase,
+	PEM_EventDataValid_HdVideo,
+	PEM_EventDataValid_BacklightLevel,
+	PEM_EventDatavalid_VariBrightParams,
+	PEM_EventDataValid_VariBrightLevel,
+	PEM_EventDataValid_VariBrightImmediateChange,
+	PEM_EventDataValid_PercentWhite,
+	PEM_EventDataValid_SdVideo,
+	PEM_EventDataValid_HTLinkChangeReason,
+	PEM_EventDataValid_HWBlocks,
+	PEM_EventDataValid_RequestedThermalState,
+	PEM_EventDataValid_MvcVideo,
+	PEM_EventDataValid_Max
+};
+
+typedef enum PEM_EventDataValid PEM_EventDataValid;
+
+/* Number of bits in ULONG variable */
+#define PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD (sizeof(unsigned long)*8)
+
+/* Number of ULONG entries used by event data valid bits */
+#define PEM_MAX_NUM_EVENTDATAVALID_ULONG_ENTRIES                                 \
+		((PEM_EventDataValid_Max + PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD - 1) /  \
+		PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD)
+
+static inline void pem_set_event_data_valid(unsigned long *fields, PEM_EventDataValid valid_field)
+{
+	fields[valid_field / PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD] |=
+		(1UL << (valid_field % PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD));
+}
+
+static inline void pem_unset_event_data_valid(unsigned long *fields, PEM_EventDataValid valid_field)
+{
+	fields[valid_field / PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD] &=
+		~(1UL << (valid_field % PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD));
+}
+
+static inline unsigned long pem_is_event_data_valid(const unsigned long *fields, PEM_EventDataValid valid_field)
+{
+	return fields[valid_field / PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD] &
+		(1UL << (valid_field % PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD));
+}
+
+struct pem_event_data {
+	unsigned long	valid_fields[100];
+	unsigned long   requested_state_id;
+	enum PP_StateUILabel requested_ui_label;
+	struct pp_power_state  *pnew_power_state;
+	enum pp_power_source  requested_power_source;
+	struct PP_Clocks       requested_clocks;
+	bool         skip_state_adjust_rules;
+	struct phm_asic_blocks  asic_blocks;
+	/* to doPP_ThermalState requestedThermalState;
+	enum ThermalStateRequestSrc requestThermalStateSrc;
+	PP_Temperature  currentTemperature;*/
+
+};
+
+int pem_handle_event(struct pp_eventmgr *eventmgr, enum amd_pp_event event,
+		     struct pem_event_data *event_data);
+
+bool pem_is_hw_access_blocked(struct pp_eventmgr *eventmgr);
+
+#endif /* _EVENT_MANAGER_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _EVENTMGR_H_
+#define _EVENTMGR_H_
+
+#include <linux/mutex.h>
+#include "pp_instance.h"
+#include "hardwaremanager.h"
+#include "eventmanager.h"
+#include "pp_feature.h"
+#include "pp_power_source.h"
+#include "power_state.h"
+
+typedef int (*pem_event_action)(struct pp_eventmgr *eventmgr,
+				struct pem_event_data *event_data);
+
+struct action_chain {
+	const char *description;  /* action chain description for debugging purpose */
+	const pem_event_action **action_chain; /* pointer to chain of event actions */
+};
+
+struct pem_power_source_ui_state_info {
+	enum PP_StateUILabel current_ui_label;
+	enum PP_StateUILabel default_ui_lable;
+	unsigned long    configurable_ui_mapping;
+};
+
+struct pp_clock_range {
+	uint32_t min_sclk_khz;
+	uint32_t max_sclk_khz;
+
+	uint32_t min_mclk_khz;
+	uint32_t max_mclk_khz;
+
+	uint32_t min_vclk_khz;
+	uint32_t max_vclk_khz;
+
+	uint32_t min_dclk_khz;
+	uint32_t max_dclk_khz;
+
+	uint32_t min_aclk_khz;
+	uint32_t max_aclk_khz;
+
+	uint32_t min_eclk_khz;
+	uint32_t max_eclk_khz;
+};
+
+enum pp_state {
+	UNINITIALIZED,
+	INACTIVE,
+	ACTIVE
+};
+
+enum pp_ring_index {
+	PP_RING_TYPE_GFX_INDEX = 0,
+	PP_RING_TYPE_DMA_INDEX,
+	PP_RING_TYPE_DMA1_INDEX,
+	PP_RING_TYPE_UVD_INDEX,
+	PP_RING_TYPE_VCE0_INDEX,
+	PP_RING_TYPE_VCE1_INDEX,
+	PP_RING_TYPE_CP1_INDEX,
+	PP_RING_TYPE_CP2_INDEX,
+	PP_NUM_RINGS,
+};
+
+struct pp_request {
+	uint32_t flags;
+	uint32_t sclk;
+	uint32_t sclk_throttle;
+	uint32_t mclk;
+	uint32_t vclk;
+	uint32_t dclk;
+	uint32_t eclk;
+	uint32_t aclk;
+	uint32_t iclk;
+	uint32_t vp8clk;
+	uint32_t rsv[32];
+};
+
+struct pp_eventmgr {
+	struct pp_hwmgr	*hwmgr;
+	struct pp_smumgr *smumgr;
+
+	struct pp_feature_info features[PP_Feature_Max];
+	const struct action_chain *event_chain[AMD_PP_EVENT_MAX];
+	struct phm_platform_descriptor   *platform_descriptor;
+	struct pp_clock_range clock_range;
+	enum pp_power_source  current_power_source;
+	struct pem_power_source_ui_state_info  ui_state_info[PP_PowerSource_Max];
+	enum pp_state states[PP_NUM_RINGS];
+	struct pp_request hi_req;
+	struct list_head context_list;
+	struct mutex lock;
+	bool  block_adjust_power_state;
+	bool enable_cg;
+	bool enable_gfx_cgpg;
+	int (*pp_eventmgr_init)(struct pp_eventmgr *eventmgr);
+	void (*pp_eventmgr_fini)(struct pp_eventmgr *eventmgr);
+};
+
+int eventmgr_init(struct pp_instance *handle);
+int eventmgr_fini(struct pp_eventmgr *eventmgr);
+
+#endif /* _EVENTMGR_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/fiji_ppsmc.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/fiji_ppsmc.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+#ifndef _FIJI_PP_SMC_H_
+#define _FIJI_PP_SMC_H_
+
+#pragma pack(push, 1)
+
+#define PPSMC_SWSTATE_FLAG_DC                           0x01
+#define PPSMC_SWSTATE_FLAG_UVD                          0x02
+#define PPSMC_SWSTATE_FLAG_VCE                          0x04
+
+#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL             0x00
+#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL             0x01
+#define PPSMC_THERMAL_PROTECT_TYPE_NONE                 0xff
+
+#define PPSMC_SYSTEMFLAG_GPIO_DC                        0x01
+#define PPSMC_SYSTEMFLAG_STEPVDDC                       0x02
+#define PPSMC_SYSTEMFLAG_GDDR5                          0x04
+
+#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP               0x08
+
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT                  0x10
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG           0x20
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK              0x07
+#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK     0x08
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE   0x00
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE  0x01
+
+/* Defines for DPM 2.0 */
+#define PPSMC_DPM2FLAGS_TDPCLMP                         0x01
+#define PPSMC_DPM2FLAGS_PWRSHFT                         0x02
+#define PPSMC_DPM2FLAGS_OCP                             0x04
+
+/* Defines for display watermark level */
+#define PPSMC_DISPLAY_WATERMARK_LOW                     0
+#define PPSMC_DISPLAY_WATERMARK_HIGH                    1
+
+/* In the HW performance level's state flags: */
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP    0x01
+#define PPSMC_STATEFLAG_POWERBOOST         0x02
+#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
+#define PPSMC_STATEFLAG_POWERSHIFT         0x08
+#define PPSMC_STATEFLAG_SLOW_READ_MARGIN   0x10
+#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
+#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS   0x40
+
+/* Fan control algorithm: */
+#define FDO_MODE_HARDWARE 0
+#define FDO_MODE_PIECE_WISE_LINEAR 1
+
+enum FAN_CONTROL {
+  FAN_CONTROL_FUZZY,
+  FAN_CONTROL_TABLE
+};
+
+/* Gemini Modes*/
+#define PPSMC_GeminiModeNone   0  /*Single GPU board*/
+#define PPSMC_GeminiModeMaster 1  /*Master GPU on a Gemini board*/
+#define PPSMC_GeminiModeSlave  2  /*Slave GPU on a Gemini board*/
+
+
+/* Return codes for driver to SMC communication. */
+#define PPSMC_Result_OK             ((uint16_t)0x01)
+#define PPSMC_Result_NoMore         ((uint16_t)0x02)
+
+#define PPSMC_Result_NotNow         ((uint16_t)0x03)
+
+#define PPSMC_Result_Failed         ((uint16_t)0xFF)
+#define PPSMC_Result_UnknownCmd     ((uint16_t)0xFE)
+#define PPSMC_Result_UnknownVT      ((uint16_t)0xFD)
+
+#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
+
+
+#define PPSMC_MSG_Halt                      ((uint16_t)0x10)
+#define PPSMC_MSG_Resume                    ((uint16_t)0x11)
+#define PPSMC_MSG_EnableDPMLevel            ((uint16_t)0x12)
+#define PPSMC_MSG_ZeroLevelsDisabled        ((uint16_t)0x13)
+#define PPSMC_MSG_OneLevelsDisabled         ((uint16_t)0x14)
+#define PPSMC_MSG_TwoLevelsDisabled         ((uint16_t)0x15)
+#define PPSMC_MSG_EnableThermalInterrupt    ((uint16_t)0x16)
+#define PPSMC_MSG_RunningOnAC               ((uint16_t)0x17)
+#define PPSMC_MSG_LevelUp                   ((uint16_t)0x18)
+#define PPSMC_MSG_LevelDown                 ((uint16_t)0x19)
+#define PPSMC_MSG_ResetDPMCounters          ((uint16_t)0x1a)
+#define PPSMC_MSG_SwitchToSwState           ((uint16_t)0x20)
+
+#define PPSMC_MSG_SwitchToSwStateLast       ((uint16_t)0x3f)
+#define PPSMC_MSG_SwitchToInitialState      ((uint16_t)0x40)
+#define PPSMC_MSG_NoForcedLevel             ((uint16_t)0x41)
+#define PPSMC_MSG_ForceHigh                 ((uint16_t)0x42)
+#define PPSMC_MSG_ForceMediumOrHigh         ((uint16_t)0x43)
+
+#define PPSMC_MSG_SwitchToMinimumPower      ((uint16_t)0x51)
+#define PPSMC_MSG_ResumeFromMinimumPower    ((uint16_t)0x52)
+#define PPSMC_MSG_EnableCac                 ((uint16_t)0x53)
+#define PPSMC_MSG_DisableCac                ((uint16_t)0x54)
+#define PPSMC_DPMStateHistoryStart          ((uint16_t)0x55)
+#define PPSMC_DPMStateHistoryStop           ((uint16_t)0x56)
+#define PPSMC_CACHistoryStart               ((uint16_t)0x57)
+#define PPSMC_CACHistoryStop                ((uint16_t)0x58)
+#define PPSMC_TDPClampingActive             ((uint16_t)0x59)
+#define PPSMC_TDPClampingInactive           ((uint16_t)0x5A)
+#define PPSMC_StartFanControl               ((uint16_t)0x5B)
+#define PPSMC_StopFanControl                ((uint16_t)0x5C)
+#define PPSMC_NoDisplay                     ((uint16_t)0x5D)
+#define PPSMC_HasDisplay                    ((uint16_t)0x5E)
+#define PPSMC_MSG_UVDPowerOFF               ((uint16_t)0x60)
+#define PPSMC_MSG_UVDPowerON                ((uint16_t)0x61)
+#define PPSMC_MSG_EnableULV                 ((uint16_t)0x62)
+#define PPSMC_MSG_DisableULV                ((uint16_t)0x63)
+#define PPSMC_MSG_EnterULV                  ((uint16_t)0x64)
+#define PPSMC_MSG_ExitULV                   ((uint16_t)0x65)
+#define PPSMC_PowerShiftActive              ((uint16_t)0x6A)
+#define PPSMC_PowerShiftInactive            ((uint16_t)0x6B)
+#define PPSMC_OCPActive                     ((uint16_t)0x6C)
+#define PPSMC_OCPInactive                   ((uint16_t)0x6D)
+#define PPSMC_CACLongTermAvgEnable          ((uint16_t)0x6E)
+#define PPSMC_CACLongTermAvgDisable         ((uint16_t)0x6F)
+#define PPSMC_MSG_InferredStateSweep_Start  ((uint16_t)0x70)
+#define PPSMC_MSG_InferredStateSweep_Stop   ((uint16_t)0x71)
+#define PPSMC_MSG_SwitchToLowestInfState    ((uint16_t)0x72)
+#define PPSMC_MSG_SwitchToNonInfState       ((uint16_t)0x73)
+#define PPSMC_MSG_AllStateSweep_Start       ((uint16_t)0x74)
+#define PPSMC_MSG_AllStateSweep_Stop        ((uint16_t)0x75)
+#define PPSMC_MSG_SwitchNextLowerInfState   ((uint16_t)0x76)
+#define PPSMC_MSG_SwitchNextHigherInfState  ((uint16_t)0x77)
+#define PPSMC_MSG_MclkRetrainingTest        ((uint16_t)0x78)
+#define PPSMC_MSG_ForceTDPClamping          ((uint16_t)0x79)
+#define PPSMC_MSG_CollectCAC_PowerCorreln   ((uint16_t)0x7A)
+#define PPSMC_MSG_CollectCAC_WeightCalib    ((uint16_t)0x7B)
+#define PPSMC_MSG_CollectCAC_SQonly         ((uint16_t)0x7C)
+#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
+
+#define PPSMC_MSG_ExtremitiesTest_Start     ((uint16_t)0x7E)
+#define PPSMC_MSG_ExtremitiesTest_Stop      ((uint16_t)0x7F)
+#define PPSMC_FlushDataCache                ((uint16_t)0x80)
+#define PPSMC_FlushInstrCache               ((uint16_t)0x81)
+
+#define PPSMC_MSG_SetEnabledLevels          ((uint16_t)0x82)
+#define PPSMC_MSG_SetForcedLevels           ((uint16_t)0x83)
+
+#define PPSMC_MSG_ResetToDefaults           ((uint16_t)0x84)
+
+#define PPSMC_MSG_SetForcedLevelsAndJump      ((uint16_t)0x85)
+#define PPSMC_MSG_SetCACHistoryMode           ((uint16_t)0x86)
+#define PPSMC_MSG_EnableDTE                   ((uint16_t)0x87)
+#define PPSMC_MSG_DisableDTE                  ((uint16_t)0x88)
+
+#define PPSMC_MSG_SmcSpaceSetAddress          ((uint16_t)0x89)
+
+#define PPSMC_MSG_BREAK                       ((uint16_t)0xF8)
+
+/* Trinity Specific Messages*/
+#define PPSMC_MSG_Test                        ((uint16_t) 0x100)
+#define PPSMC_MSG_DPM_Voltage_Pwrmgt          ((uint16_t) 0x101)
+#define PPSMC_MSG_DPM_Config                  ((uint16_t) 0x102)
+#define PPSMC_MSG_PM_Controller_Start         ((uint16_t) 0x103)
+#define PPSMC_MSG_DPM_ForceState              ((uint16_t) 0x104)
+#define PPSMC_MSG_PG_PowerDownSIMD            ((uint16_t) 0x105)
+#define PPSMC_MSG_PG_PowerUpSIMD              ((uint16_t) 0x106)
+#define PPSMC_MSG_PM_Controller_Stop          ((uint16_t) 0x107)
+#define PPSMC_MSG_PG_SIMD_Config              ((uint16_t) 0x108)
+#define PPSMC_MSG_Voltage_Cntl_Enable         ((uint16_t) 0x109)
+#define PPSMC_MSG_Thermal_Cntl_Enable         ((uint16_t) 0x10a)
+#define PPSMC_MSG_Reset_Service               ((uint16_t) 0x10b)
+#define PPSMC_MSG_VCEPowerOFF                 ((uint16_t) 0x10e)
+#define PPSMC_MSG_VCEPowerON                  ((uint16_t) 0x10f)
+#define PPSMC_MSG_DPM_Disable_VCE_HS          ((uint16_t) 0x110)
+#define PPSMC_MSG_DPM_Enable_VCE_HS           ((uint16_t) 0x111)
+#define PPSMC_MSG_DPM_N_LevelsDisabled        ((uint16_t) 0x112)
+#define PPSMC_MSG_DCEPowerOFF                 ((uint16_t) 0x113)
+#define PPSMC_MSG_DCEPowerON                  ((uint16_t) 0x114)
+#define PPSMC_MSG_PCIE_DDIPowerDown           ((uint16_t) 0x117)
+#define PPSMC_MSG_PCIE_DDIPowerUp             ((uint16_t) 0x118)
+#define PPSMC_MSG_PCIE_CascadePLLPowerDown    ((uint16_t) 0x119)
+#define PPSMC_MSG_PCIE_CascadePLLPowerUp      ((uint16_t) 0x11a)
+#define PPSMC_MSG_SYSPLLPowerOff              ((uint16_t) 0x11b)
+#define PPSMC_MSG_SYSPLLPowerOn               ((uint16_t) 0x11c)
+#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint16_t) 0x11d)
+#define PPSMC_MSG_DCE_AllowVoltageAdjustment  ((uint16_t) 0x11e)
+#define PPSMC_MSG_DISPLAYPHYStatusNotify      ((uint16_t) 0x11f)
+#define PPSMC_MSG_EnableBAPM                  ((uint16_t) 0x120)
+#define PPSMC_MSG_DisableBAPM                 ((uint16_t) 0x121)
+#define PPSMC_MSG_Spmi_Enable                 ((uint16_t) 0x122)
+#define PPSMC_MSG_Spmi_Timer                  ((uint16_t) 0x123)
+#define PPSMC_MSG_LCLK_DPM_Config             ((uint16_t) 0x124)
+#define PPSMC_MSG_VddNB_Request               ((uint16_t) 0x125)
+#define PPSMC_MSG_PCIE_DDIPhyPowerDown        ((uint32_t) 0x126)
+#define PPSMC_MSG_PCIE_DDIPhyPowerUp          ((uint32_t) 0x127)
+#define PPSMC_MSG_MCLKDPM_Config              ((uint16_t) 0x128)
+
+#define PPSMC_MSG_UVDDPM_Config               ((uint16_t) 0x129)
+#define PPSMC_MSG_VCEDPM_Config               ((uint16_t) 0x12A)
+#define PPSMC_MSG_ACPDPM_Config               ((uint16_t) 0x12B)
+#define PPSMC_MSG_SAMUDPM_Config              ((uint16_t) 0x12C)
+#define PPSMC_MSG_UVDDPM_SetEnabledMask       ((uint16_t) 0x12D)
+#define PPSMC_MSG_VCEDPM_SetEnabledMask       ((uint16_t) 0x12E)
+#define PPSMC_MSG_ACPDPM_SetEnabledMask       ((uint16_t) 0x12F)
+#define PPSMC_MSG_SAMUDPM_SetEnabledMask      ((uint16_t) 0x130)
+#define PPSMC_MSG_MCLKDPM_ForceState          ((uint16_t) 0x131)
+#define PPSMC_MSG_MCLKDPM_NoForcedLevel       ((uint16_t) 0x132)
+#define PPSMC_MSG_Thermal_Cntl_Disable        ((uint16_t) 0x133)
+#define PPSMC_MSG_SetTDPLimit                 ((uint16_t) 0x134)
+#define PPSMC_MSG_Voltage_Cntl_Disable        ((uint16_t) 0x135)
+#define PPSMC_MSG_PCIeDPM_Enable              ((uint16_t) 0x136)
+#define PPSMC_MSG_ACPPowerOFF                 ((uint16_t) 0x137)
+#define PPSMC_MSG_ACPPowerON                  ((uint16_t) 0x138)
+#define PPSMC_MSG_SAMPowerOFF                 ((uint16_t) 0x139)
+#define PPSMC_MSG_SAMPowerON                  ((uint16_t) 0x13a)
+#define PPSMC_MSG_SDMAPowerOFF                ((uint16_t) 0x13b)
+#define PPSMC_MSG_SDMAPowerON                 ((uint16_t) 0x13c)
+#define PPSMC_MSG_PCIeDPM_Disable             ((uint16_t) 0x13d)
+#define PPSMC_MSG_IOMMUPowerOFF               ((uint16_t) 0x13e)
+#define PPSMC_MSG_IOMMUPowerON                ((uint16_t) 0x13f)
+#define PPSMC_MSG_NBDPM_Enable                ((uint16_t) 0x140)
+#define PPSMC_MSG_NBDPM_Disable               ((uint16_t) 0x141)
+#define PPSMC_MSG_NBDPM_ForceNominal          ((uint16_t) 0x142)
+#define PPSMC_MSG_NBDPM_ForcePerformance      ((uint16_t) 0x143)
+#define PPSMC_MSG_NBDPM_UnForce               ((uint16_t) 0x144)
+#define PPSMC_MSG_SCLKDPM_SetEnabledMask      ((uint16_t) 0x145)
+#define PPSMC_MSG_MCLKDPM_SetEnabledMask      ((uint16_t) 0x146)
+#define PPSMC_MSG_PCIeDPM_ForceLevel          ((uint16_t) 0x147)
+#define PPSMC_MSG_PCIeDPM_UnForceLevel        ((uint16_t) 0x148)
+#define PPSMC_MSG_EnableACDCGPIOInterrupt     ((uint16_t) 0x149)
+#define PPSMC_MSG_EnableVRHotGPIOInterrupt    ((uint16_t) 0x14a)
+#define PPSMC_MSG_SwitchToAC                  ((uint16_t) 0x14b)
+
+#define PPSMC_MSG_XDMAPowerOFF                ((uint16_t) 0x14c)
+#define PPSMC_MSG_XDMAPowerON                 ((uint16_t) 0x14d)
+
+#define PPSMC_MSG_DPM_Enable                  ((uint16_t) 0x14e)
+#define PPSMC_MSG_DPM_Disable                 ((uint16_t) 0x14f)
+#define PPSMC_MSG_MCLKDPM_Enable              ((uint16_t) 0x150)
+#define PPSMC_MSG_MCLKDPM_Disable             ((uint16_t) 0x151)
+#define PPSMC_MSG_LCLKDPM_Enable              ((uint16_t) 0x152)
+#define PPSMC_MSG_LCLKDPM_Disable             ((uint16_t) 0x153)
+#define PPSMC_MSG_UVDDPM_Enable               ((uint16_t) 0x154)
+#define PPSMC_MSG_UVDDPM_Disable              ((uint16_t) 0x155)
+#define PPSMC_MSG_SAMUDPM_Enable              ((uint16_t) 0x156)
+#define PPSMC_MSG_SAMUDPM_Disable             ((uint16_t) 0x157)
+#define PPSMC_MSG_ACPDPM_Enable               ((uint16_t) 0x158)
+#define PPSMC_MSG_ACPDPM_Disable              ((uint16_t) 0x159)
+#define PPSMC_MSG_VCEDPM_Enable               ((uint16_t) 0x15a)
+#define PPSMC_MSG_VCEDPM_Disable              ((uint16_t) 0x15b)
+#define PPSMC_MSG_LCLKDPM_SetEnabledMask      ((uint16_t) 0x15c)
+#define PPSMC_MSG_DPM_FPS_Mode                ((uint16_t) 0x15d)
+#define PPSMC_MSG_DPM_Activity_Mode           ((uint16_t) 0x15e)
+#define PPSMC_MSG_VddC_Request                ((uint16_t) 0x15f)
+#define PPSMC_MSG_MCLKDPM_GetEnabledMask      ((uint16_t) 0x160)
+#define PPSMC_MSG_LCLKDPM_GetEnabledMask      ((uint16_t) 0x161)
+#define PPSMC_MSG_SCLKDPM_GetEnabledMask      ((uint16_t) 0x162)
+#define PPSMC_MSG_UVDDPM_GetEnabledMask       ((uint16_t) 0x163)
+#define PPSMC_MSG_SAMUDPM_GetEnabledMask      ((uint16_t) 0x164)
+#define PPSMC_MSG_ACPDPM_GetEnabledMask       ((uint16_t) 0x165)
+#define PPSMC_MSG_VCEDPM_GetEnabledMask       ((uint16_t) 0x166)
+#define PPSMC_MSG_PCIeDPM_SetEnabledMask      ((uint16_t) 0x167)
+#define PPSMC_MSG_PCIeDPM_GetEnabledMask      ((uint16_t) 0x168)
+#define PPSMC_MSG_TDCLimitEnable              ((uint16_t) 0x169)
+#define PPSMC_MSG_TDCLimitDisable             ((uint16_t) 0x16a)
+#define PPSMC_MSG_DPM_AutoRotate_Mode         ((uint16_t) 0x16b)
+#define PPSMC_MSG_DISPCLK_FROM_FCH            ((uint16_t) 0x16c)
+#define PPSMC_MSG_DISPCLK_FROM_DFS            ((uint16_t) 0x16d)
+#define PPSMC_MSG_DPREFCLK_FROM_FCH           ((uint16_t) 0x16e)
+#define PPSMC_MSG_DPREFCLK_FROM_DFS           ((uint16_t) 0x16f)
+#define PPSMC_MSG_PmStatusLogStart            ((uint16_t) 0x170)
+#define PPSMC_MSG_PmStatusLogSample           ((uint16_t) 0x171)
+#define PPSMC_MSG_SCLK_AutoDPM_ON             ((uint16_t) 0x172)
+#define PPSMC_MSG_MCLK_AutoDPM_ON             ((uint16_t) 0x173)
+#define PPSMC_MSG_LCLK_AutoDPM_ON             ((uint16_t) 0x174)
+#define PPSMC_MSG_UVD_AutoDPM_ON              ((uint16_t) 0x175)
+#define PPSMC_MSG_SAMU_AutoDPM_ON             ((uint16_t) 0x176)
+#define PPSMC_MSG_ACP_AutoDPM_ON              ((uint16_t) 0x177)
+#define PPSMC_MSG_VCE_AutoDPM_ON              ((uint16_t) 0x178)
+#define PPSMC_MSG_PCIe_AutoDPM_ON             ((uint16_t) 0x179)
+#define PPSMC_MSG_MASTER_AutoDPM_ON           ((uint16_t) 0x17a)
+#define PPSMC_MSG_MASTER_AutoDPM_OFF          ((uint16_t) 0x17b)
+#define PPSMC_MSG_DYNAMICDISPPHYPOWER         ((uint16_t) 0x17c)
+#define PPSMC_MSG_CAC_COLLECTION_ON           ((uint16_t) 0x17d)
+#define PPSMC_MSG_CAC_COLLECTION_OFF          ((uint16_t) 0x17e)
+#define PPSMC_MSG_CAC_CORRELATION_ON          ((uint16_t) 0x17f)
+#define PPSMC_MSG_CAC_CORRELATION_OFF         ((uint16_t) 0x180)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_ON        ((uint16_t) 0x181)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_OFF       ((uint16_t) 0x182)
+#define PPSMC_MSG_ALLOW_LOWSCLK_INTERRUPT     ((uint16_t) 0x184)
+#define PPSMC_MSG_PkgPwrLimitEnable           ((uint16_t) 0x185)
+#define PPSMC_MSG_PkgPwrLimitDisable          ((uint16_t) 0x186)
+#define PPSMC_MSG_PkgPwrSetLimit              ((uint16_t) 0x187)
+#define PPSMC_MSG_OverDriveSetTargetTdp       ((uint16_t) 0x188)
+#define PPSMC_MSG_SCLKDPM_FreezeLevel         ((uint16_t) 0x189)
+#define PPSMC_MSG_SCLKDPM_UnfreezeLevel       ((uint16_t) 0x18A)
+#define PPSMC_MSG_MCLKDPM_FreezeLevel         ((uint16_t) 0x18B)
+#define PPSMC_MSG_MCLKDPM_UnfreezeLevel       ((uint16_t) 0x18C)
+#define PPSMC_MSG_START_DRAM_LOGGING          ((uint16_t) 0x18D)
+#define PPSMC_MSG_STOP_DRAM_LOGGING           ((uint16_t) 0x18E)
+#define PPSMC_MSG_MASTER_DeepSleep_ON         ((uint16_t) 0x18F)
+#define PPSMC_MSG_MASTER_DeepSleep_OFF        ((uint16_t) 0x190)
+#define PPSMC_MSG_Remove_DC_Clamp             ((uint16_t) 0x191)
+#define PPSMC_MSG_DisableACDCGPIOInterrupt    ((uint16_t) 0x192)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddc       ((uint16_t) 0x193)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddci      ((uint16_t) 0x194)
+#define PPSMC_MSG_SetVidOffset_1              ((uint16_t) 0x195)
+#define PPSMC_MSG_SetVidOffset_2              ((uint16_t) 0x207)
+#define PPSMC_MSG_GetVidOffset_1              ((uint16_t) 0x196)
+#define PPSMC_MSG_GetVidOffset_2              ((uint16_t) 0x208)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Enable    ((uint16_t) 0x197)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Disable   ((uint16_t) 0x198)
+#define PPSMC_MSG_SetTjMax                    ((uint16_t) 0x199)
+#define PPSMC_MSG_SetFanPwmMax                ((uint16_t) 0x19A)
+#define PPSMC_MSG_WaitForMclkSwitchFinish     ((uint16_t) 0x19B)
+#define PPSMC_MSG_ENABLE_THERMAL_DPM          ((uint16_t) 0x19C)
+#define PPSMC_MSG_DISABLE_THERMAL_DPM         ((uint16_t) 0x19D)
+
+#define PPSMC_MSG_API_GetSclkFrequency        ((uint16_t) 0x200)
+#define PPSMC_MSG_API_GetMclkFrequency        ((uint16_t) 0x201)
+#define PPSMC_MSG_API_GetSclkBusy             ((uint16_t) 0x202)
+#define PPSMC_MSG_API_GetMclkBusy             ((uint16_t) 0x203)
+#define PPSMC_MSG_API_GetAsicPower            ((uint16_t) 0x204)
+#define PPSMC_MSG_SetFanRpmMax                ((uint16_t) 0x205)
+#define PPSMC_MSG_SetFanSclkTarget            ((uint16_t) 0x206)
+#define PPSMC_MSG_SetFanMinPwm                ((uint16_t) 0x209)
+#define PPSMC_MSG_SetFanTemperatureTarget     ((uint16_t) 0x20A)
+
+#define PPSMC_MSG_BACO_StartMonitor           ((uint16_t) 0x240)
+#define PPSMC_MSG_BACO_Cancel                 ((uint16_t) 0x241)
+#define PPSMC_MSG_EnableVddGfx                ((uint16_t) 0x242)
+#define PPSMC_MSG_DisableVddGfx               ((uint16_t) 0x243)
+#define PPSMC_MSG_UcodeAddressLow             ((uint16_t) 0x244)
+#define PPSMC_MSG_UcodeAddressHigh            ((uint16_t) 0x245)
+#define PPSMC_MSG_UcodeLoadStatus             ((uint16_t) 0x246)
+
+#define PPSMC_MSG_DRV_DRAM_ADDR_HI            ((uint16_t) 0x250)
+#define PPSMC_MSG_DRV_DRAM_ADDR_LO            ((uint16_t) 0x251)
+#define PPSMC_MSG_SMU_DRAM_ADDR_HI            ((uint16_t) 0x252)
+#define PPSMC_MSG_SMU_DRAM_ADDR_LO            ((uint16_t) 0x253)
+#define PPSMC_MSG_LoadUcodes                  ((uint16_t) 0x254)
+#define PPSMC_MSG_PowerStateNotify            ((uint16_t) 0x255)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_HI      ((uint16_t) 0x256)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_LO      ((uint16_t) 0x257)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_HI          ((uint16_t) 0x258)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_LO          ((uint16_t) 0x259)
+#define PPSMC_MSG_LoadVBios                   ((uint16_t) 0x25A)
+#define PPSMC_MSG_GetUcodeVersion             ((uint16_t) 0x25B)
+#define DMCUSMC_MSG_PSREntry                  ((uint16_t) 0x25C)
+#define DMCUSMC_MSG_PSRExit                   ((uint16_t) 0x25D)
+#define PPSMC_MSG_EnableClockGatingFeature    ((uint16_t) 0x260)
+#define PPSMC_MSG_DisableClockGatingFeature   ((uint16_t) 0x261)
+#define PPSMC_MSG_IsDeviceRunning             ((uint16_t) 0x262)
+#define PPSMC_MSG_LoadMetaData                ((uint16_t) 0x263)
+#define PPSMC_MSG_TMON_AutoCaliberate_Enable  ((uint16_t) 0x264)
+#define PPSMC_MSG_TMON_AutoCaliberate_Disable ((uint16_t) 0x265)
+#define PPSMC_MSG_GetTelemetry1Slope          ((uint16_t) 0x266)
+#define PPSMC_MSG_GetTelemetry1Offset         ((uint16_t) 0x267)
+#define PPSMC_MSG_GetTelemetry2Slope          ((uint16_t) 0x268)
+#define PPSMC_MSG_GetTelemetry2Offset         ((uint16_t) 0x269)
+#define PPSMC_MSG_EnableAvfs                  ((uint16_t) 0x26A)
+#define PPSMC_MSG_DisableAvfs                 ((uint16_t) 0x26B)
+#define PPSMC_MSG_PerformBtc                  ((uint16_t) 0x26C)
+#define PPSMC_MSG_GetHbmCode                  ((uint16_t) 0x26D)
+#define PPSMC_MSG_GetVrVddcTemperature        ((uint16_t) 0x26E)
+#define PPSMC_MSG_GetVrMvddTemperature        ((uint16_t) 0x26F)
+#define PPSMC_MSG_GetLiquidTemperature        ((uint16_t) 0x270)
+#define PPSMC_MSG_GetPlxTemperature           ((uint16_t) 0x271)
+#define PPSMC_MSG_RequestI2CControl           ((uint16_t) 0x272)
+#define PPSMC_MSG_ReleaseI2CControl           ((uint16_t) 0x273)
+#define PPSMC_MSG_LedConfig                   ((uint16_t) 0x274)
+#define PPSMC_MSG_SetHbmFanCode               ((uint16_t) 0x275)
+#define PPSMC_MSG_SetHbmThrottleCode          ((uint16_t) 0x276)
+
+#define PPSMC_MSG_GetEnabledPsm               ((uint16_t) 0x400)
+#define PPSMC_MSG_AgmStartPsm                 ((uint16_t) 0x401)
+#define PPSMC_MSG_AgmReadPsm                  ((uint16_t) 0x402)
+#define PPSMC_MSG_AgmResetPsm                 ((uint16_t) 0x403)
+#define PPSMC_MSG_ReadVftCell                 ((uint16_t) 0x404)
+
+/* AVFS Only - Remove Later */
+#define PPSMC_MSG_VftTableIsValid             ((uint16_t) 0x666)
+
+/* If the SMC firmware has an event status soft register this is what the individual bits mean.*/
+#define PPSMC_EVENT_STATUS_THERMAL          0x00000001
+#define PPSMC_EVENT_STATUS_REGULATORHOT     0x00000002
+#define PPSMC_EVENT_STATUS_DC               0x00000004
+
+typedef uint16_t PPSMC_Msg;
+
+#pragma pack(pop)
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/fiji_pwrvirus.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/fiji_pwrvirus.h
@@ -0,0 +1,10299 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _FIJI_PWRVIRUS_H_
+#define _FIJI_PWRVIRUS_H_
+
+#define mmCP_HYP_MEC1_UCODE_ADDR	0xf81a
+#define mmCP_HYP_MEC1_UCODE_DATA	0xf81b
+#define mmCP_HYP_MEC2_UCODE_ADDR	0xf81c
+#define mmCP_HYP_MEC2_UCODE_DATA	0xf81d
+
+enum PWR_Command
+{
+   PwrCmdNull = 0,
+   PwrCmdWrite,
+   PwrCmdEnd,
+   PwrCmdMax
+};
+typedef enum PWR_Command PWR_Command;
+
+struct PWR_Command_Table
+{
+   PWR_Command        command;
+   ULONG              data;
+   ULONG              reg;
+};
+typedef struct PWR_Command_Table PWR_Command_Table;
+
+#define PWR_VIRUS_TABLE_SIZE  10243
+static PWR_Command_Table PwrVirusTable[PWR_VIRUS_TABLE_SIZE] =
+{
+    { PwrCmdWrite, 0x100100b6, mmPCIE_INDEX                               },
+    { PwrCmdWrite, 0x00000000, mmPCIE_DATA                                },
+    { PwrCmdWrite, 0x100100b6, mmPCIE_INDEX                               },
+    { PwrCmdWrite, 0x0300078c, mmPCIE_DATA                                },
+    { PwrCmdWrite, 0x00000000, mmBIF_CLK_CTRL                             },
+    { PwrCmdWrite, 0x00000001, mmBIF_CLK_CTRL                             },
+    { PwrCmdWrite, 0x00000000, mmBIF_CLK_CTRL                             },
+    { PwrCmdWrite, 0x00000003, mmBIF_FB_EN                                },
+    { PwrCmdWrite, 0x00000000, mmBIF_FB_EN                                },
+    { PwrCmdWrite, 0x00000001, mmBIF_DOORBELL_APER_EN                     },
+    { PwrCmdWrite, 0x00000000, mmBIF_DOORBELL_APER_EN                     },
+    { PwrCmdWrite, 0x014000c0, mmPCIE_INDEX                               },
+    { PwrCmdWrite, 0x00000000, mmPCIE_DATA                                },
+    { PwrCmdWrite, 0x014000c0, mmPCIE_INDEX                               },
+    { PwrCmdWrite, 0x22000000, mmPCIE_DATA                                },
+    { PwrCmdWrite, 0x014000c0, mmPCIE_INDEX                               },
+    { PwrCmdWrite, 0x00000000, mmPCIE_DATA                                },
+    /*
+    { PwrCmdWrite, 0x009f0090, mmMC_VM_FB_LOCATION                        },
+    { PwrCmdWrite, 0x00000000, mmMC_CITF_CNTL                             },
+    { PwrCmdWrite, 0x00000000, mmMC_VM_FB_LOCATION                        },
+    { PwrCmdWrite, 0x009f0090, mmMC_VM_FB_LOCATION                        },
+    { PwrCmdWrite, 0x00000000, mmMC_VM_FB_LOCATION                        },
+    { PwrCmdWrite, 0x009f0090, mmMC_VM_FB_LOCATION                        },
+    { PwrCmdWrite, 0x00000000, mmMC_VM_FB_OFFSET                          },*/
+    { PwrCmdWrite, 0x00000000, mmRLC_CSIB_ADDR_LO                         },
+    { PwrCmdWrite, 0x00000000, mmRLC_CSIB_ADDR_HI                         },
+    { PwrCmdWrite, 0x00000000, mmRLC_CSIB_LENGTH                          },
+    /*
+    { PwrCmdWrite, 0x00000000, mmMC_VM_MX_L1_TLB_CNTL                     },
+    { PwrCmdWrite, 0x00000001, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR           },
+    { PwrCmdWrite, 0x00000000, mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR          },
+    { PwrCmdWrite, 0x00000000, mmMC_VM_FB_LOCATION                        },
+    { PwrCmdWrite, 0x009f0090, mmMC_VM_FB_LOCATION                        },*/
+    { PwrCmdWrite, 0x00000000, mmVM_CONTEXT0_CNTL                         },
+    { PwrCmdWrite, 0x00000000, mmVM_CONTEXT1_CNTL                         },
+    /*
+    { PwrCmdWrite, 0x00000000, mmMC_VM_AGP_BASE                           },
+    { PwrCmdWrite, 0x00000002, mmMC_VM_AGP_BOT                            },
+    { PwrCmdWrite, 0x00000000, mmMC_VM_AGP_TOP                            },*/
+    { PwrCmdWrite, 0x04000000, mmATC_VM_APERTURE0_LOW_ADDR                },
+    { PwrCmdWrite, 0x0400ff20, mmATC_VM_APERTURE0_HIGH_ADDR               },
+    { PwrCmdWrite, 0x00000002, mmATC_VM_APERTURE0_CNTL                    },
+    { PwrCmdWrite, 0x0000ffff, mmATC_VM_APERTURE0_CNTL2                   },
+    { PwrCmdWrite, 0x00000001, mmATC_VM_APERTURE1_LOW_ADDR                },
+    { PwrCmdWrite, 0x00000000, mmATC_VM_APERTURE1_HIGH_ADDR               },
+    { PwrCmdWrite, 0x00000000, mmATC_VM_APERTURE1_CNTL                    },
+    { PwrCmdWrite, 0x00000000, mmATC_VM_APERTURE1_CNTL2                   },
+    //{ PwrCmdWrite, 0x00000000, mmMC_ARB_RAMCFG                            },
+    { PwrCmdWrite, 0x12011003, mmGB_ADDR_CONFIG                           },
+    { PwrCmdWrite, 0x00800010, mmGB_TILE_MODE0                            },
+    { PwrCmdWrite, 0x00800810, mmGB_TILE_MODE1                            },
+    { PwrCmdWrite, 0x00801010, mmGB_TILE_MODE2                            },
+    { PwrCmdWrite, 0x00801810, mmGB_TILE_MODE3                            },
+    { PwrCmdWrite, 0x00802810, mmGB_TILE_MODE4                            },
+    { PwrCmdWrite, 0x00802808, mmGB_TILE_MODE5                            },
+    { PwrCmdWrite, 0x00802814, mmGB_TILE_MODE6                            },
+    { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE7                            },
+    { PwrCmdWrite, 0x00000004, mmGB_TILE_MODE8                            },
+    { PwrCmdWrite, 0x02000008, mmGB_TILE_MODE9                            },
+    { PwrCmdWrite, 0x02000010, mmGB_TILE_MODE10                           },
+    { PwrCmdWrite, 0x06000014, mmGB_TILE_MODE11                           },
+    { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE12                           },
+    { PwrCmdWrite, 0x02400008, mmGB_TILE_MODE13                           },
+    { PwrCmdWrite, 0x02400010, mmGB_TILE_MODE14                           },
+    { PwrCmdWrite, 0x02400030, mmGB_TILE_MODE15                           },
+    { PwrCmdWrite, 0x06400014, mmGB_TILE_MODE16                           },
+    { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE17                           },
+    { PwrCmdWrite, 0x0040000c, mmGB_TILE_MODE18                           },
+    { PwrCmdWrite, 0x0100000c, mmGB_TILE_MODE19                           },
+    { PwrCmdWrite, 0x0100001c, mmGB_TILE_MODE20                           },
+    { PwrCmdWrite, 0x01000034, mmGB_TILE_MODE21                           },
+    { PwrCmdWrite, 0x01000024, mmGB_TILE_MODE22                           },
+    { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE23                           },
+    { PwrCmdWrite, 0x0040001c, mmGB_TILE_MODE24                           },
+    { PwrCmdWrite, 0x01000020, mmGB_TILE_MODE25                           },
+    { PwrCmdWrite, 0x01000038, mmGB_TILE_MODE26                           },
+    { PwrCmdWrite, 0x02c00008, mmGB_TILE_MODE27                           },
+    { PwrCmdWrite, 0x02c00010, mmGB_TILE_MODE28                           },
+    { PwrCmdWrite, 0x06c00014, mmGB_TILE_MODE29                           },
+    { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE30                           },
+    { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE31                           },
+    { PwrCmdWrite, 0x000000a8, mmGB_MACROTILE_MODE0                       },
+    { PwrCmdWrite, 0x000000a4, mmGB_MACROTILE_MODE1                       },
+    { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE2                       },
+    { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE3                       },
+    { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE4                       },
+    { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE5                       },
+    { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE6                       },
+    { PwrCmdWrite, 0x00000000, mmGB_MACROTILE_MODE7                       },
+    { PwrCmdWrite, 0x000000ee, mmGB_MACROTILE_MODE8                       },
+    { PwrCmdWrite, 0x000000ea, mmGB_MACROTILE_MODE9                       },
+    { PwrCmdWrite, 0x000000e9, mmGB_MACROTILE_MODE10                      },
+    { PwrCmdWrite, 0x000000e5, mmGB_MACROTILE_MODE11                      },
+    { PwrCmdWrite, 0x000000e4, mmGB_MACROTILE_MODE12                      },
+    { PwrCmdWrite, 0x000000e0, mmGB_MACROTILE_MODE13                      },
+    { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE14                      },
+    { PwrCmdWrite, 0x00000000, mmGB_MACROTILE_MODE15                      },
+    { PwrCmdWrite, 0x00900000, mmHDP_NONSURFACE_BASE                      },
+    { PwrCmdWrite, 0x00008000, mmHDP_NONSURFACE_INFO                      },
+    { PwrCmdWrite, 0x3fffffff, mmHDP_NONSURFACE_SIZE                      },
+    { PwrCmdWrite, 0x00000003, mmBIF_FB_EN                                },
+    //{ PwrCmdWrite, 0x00000000, mmMC_VM_FB_OFFSET                          },
+    { PwrCmdWrite, 0x00000000, mmSRBM_CNTL                                },
+    { PwrCmdWrite, 0x00020000, mmSRBM_CNTL                                },
+    { PwrCmdWrite, 0x80000000, mmATC_VMID0_PASID_MAPPING                  },
+    { PwrCmdWrite, 0x00000000, mmATC_VMID_PASID_MAPPING_UPDATE_STATUS     },
+    { PwrCmdWrite, 0x00000000, mmRLC_CNTL                                 },
+    { PwrCmdWrite, 0x00000000, mmRLC_CNTL                                 },
+    { PwrCmdWrite, 0x00000000, mmRLC_CNTL                                 },
+    { PwrCmdWrite, 0xe0000000, mmGRBM_GFX_INDEX                           },
+    { PwrCmdWrite, 0x00000000, mmCGTS_TCC_DISABLE                         },
+    { PwrCmdWrite, 0x00000000, mmTCP_ADDR_CONFIG                          },
+    { PwrCmdWrite, 0x000000ff, mmTCP_ADDR_CONFIG                          },
+    { PwrCmdWrite, 0x76543210, mmTCP_CHAN_STEER_LO                        },
+    { PwrCmdWrite, 0xfedcba98, mmTCP_CHAN_STEER_HI                        },
+    { PwrCmdWrite, 0x00000000, mmDB_DEBUG2                                },
+    { PwrCmdWrite, 0x00000000, mmDB_DEBUG                                 },
+    { PwrCmdWrite, 0x00002b16, mmCP_QUEUE_THRESHOLDS                      },
+    { PwrCmdWrite, 0x00006030, mmCP_MEQ_THRESHOLDS                        },
+    { PwrCmdWrite, 0x01000104, mmSPI_CONFIG_CNTL_1                        },
+    { PwrCmdWrite, 0x98184020, mmPA_SC_FIFO_SIZE                          },
+    { PwrCmdWrite, 0x00000001, mmVGT_NUM_INSTANCES                        },
+    { PwrCmdWrite, 0x00000000, mmCP_PERFMON_CNTL                          },
+    { PwrCmdWrite, 0x01180000, mmSQ_CONFIG                                },
+    { PwrCmdWrite, 0x00000000, mmVGT_CACHE_INVALIDATION                   },
+    { PwrCmdWrite, 0x00000000, mmSQ_THREAD_TRACE_BASE                     },
+    { PwrCmdWrite, 0x0000df80, mmSQ_THREAD_TRACE_MASK                     },
+    { PwrCmdWrite, 0x02249249, mmSQ_THREAD_TRACE_MODE                     },
+    { PwrCmdWrite, 0x00000000, mmPA_SC_LINE_STIPPLE_STATE                 },
+    { PwrCmdWrite, 0x00000000, mmCB_PERFCOUNTER0_SELECT1                  },
+    { PwrCmdWrite, 0x06000100, mmCGTT_VGT_CLK_CTRL                        },
+    { PwrCmdWrite, 0x00000007, mmPA_CL_ENHANCE                            },
+    { PwrCmdWrite, 0x00000001, mmPA_SC_ENHANCE                            },
+    { PwrCmdWrite, 0x00ffffff, mmPA_SC_FORCE_EOV_MAX_CNTS                 },
+    { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000010, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000020, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000030, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000040, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000050, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000060, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000070, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000080, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000090, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x000000a0, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x000000b0, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x000000c0, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x000000d0, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x000000e0, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x000000f0, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmRLC_PG_CNTL                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS2                             },
+    { PwrCmdWrite, 0x15000000, mmCP_ME_CNTL                               },
+    { PwrCmdWrite, 0x50000000, mmCP_MEC_CNTL                              },
+    { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x0000000e, mmSH_MEM_APE1_BASE                         },
+    { PwrCmdWrite, 0x0000020d, mmSH_MEM_APE1_LIMIT                        },
+    { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG                            },
+    { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_RB_VMID                               },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmRLC_CNTL                                 },
+    { PwrCmdWrite, 0x00000000, mmRLC_CNTL                                 },
+    { PwrCmdWrite, 0x00000000, mmRLC_SRM_CNTL                             },
+    { PwrCmdWrite, 0x00000002, mmRLC_SRM_CNTL                             },
+    { PwrCmdWrite, 0x00000000, mmCP_ME_CNTL                               },
+    { PwrCmdWrite, 0x15000000, mmCP_ME_CNTL                               },
+    { PwrCmdWrite, 0x00000000, mmCP_MEC_CNTL                              },
+    { PwrCmdWrite, 0x50000000, mmCP_MEC_CNTL                              },
+    { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL                              },
+    { PwrCmdWrite, 0x0840800a, mmCP_RB0_CNTL                              },
+    { PwrCmdWrite, 0xf30fff0f, mmTCC_CTRL                                 },
+    { PwrCmdWrite, 0x00000002, mmTCC_EXE_DISABLE                          },
+    { PwrCmdWrite, 0x000000ff, mmTCP_ADDR_CONFIG                          },
+    { PwrCmdWrite, 0x540ff000, mmCP_CPC_IC_BASE_LO                        },
+    { PwrCmdWrite, 0x000000b4, mmCP_CPC_IC_BASE_HI                        },
+    { PwrCmdWrite, 0x00010000, mmCP_HYP_MEC1_UCODE_ADDR                   },
+    { PwrCmdWrite, 0x00041b75, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000710e8, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000910dd, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000a1081, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000b016f, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000c0e3c, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000d10ec, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000e0188, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00101b5d, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00150a6c, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00170c5e, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x001d0c8c, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x001e0cfe, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00221408, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00370d7b, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00390dcb, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x003c142f, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x003f0b27, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00400e63, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00500f62, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00460fa7, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00490fa7, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x005811d4, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00680ad6, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00760b00, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00780b0c, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00790af7, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x007d1aba, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x007e1abe, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00591260, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x005a12fb, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00861ac7, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x008c1b01, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x008d1b34, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a014b9, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a1152e, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a216fb, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a41890, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a31906, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a50b14, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00621387, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x005c0b27, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00160a75, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00010000, mmCP_HYP_MEC2_UCODE_ADDR                   },
+    { PwrCmdWrite, 0x00041b75, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000710e8, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000910dd, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000a1081, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000b016f, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000c0e3c, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000d10ec, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000e0188, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00101b5d, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00150a6c, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00170c5e, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x001d0c8c, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x001e0cfe, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00221408, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00370d7b, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00390dcb, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x003c142f, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x003f0b27, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00400e63, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00500f62, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00460fa7, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00490fa7, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x005811d4, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00680ad6, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00760b00, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00780b0c, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00790af7, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x007d1aba, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x007e1abe, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00591260, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x005a12fb, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00861ac7, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x008c1b01, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x008d1b34, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a014b9, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a1152e, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a216fb, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a41890, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a31906, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00a50b14, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00621387, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x005c0b27, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x00160a75, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA                   },
+    { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL                              },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI                           },
+    { PwrCmdWrite, 0x540fe800, mmCP_DFY_ADDR_LO                           },
+    { PwrCmdWrite, 0x7e000200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e020201, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e040204, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e060205, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xbf810000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54106f00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000400b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00004000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00804fac, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL                              },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI                           },
+    { PwrCmdWrite, 0x540fef00, mmCP_DFY_ADDR_LO                           },
+    { PwrCmdWrite, 0xc0031502, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00001e00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL                              },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI                           },
+    { PwrCmdWrite, 0x540ff000, mmCP_DFY_ADDR_LO                           },
+    { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000145, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc810000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdcc10000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdd010000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdd410000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdd810000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4080061, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24ccffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3cd08000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9500fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1cd0ffcf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d018001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4140004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x050c0019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x84c00000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000067, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000006a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000006d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000084, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000008f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000099, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800000a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800000af, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400053, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4080007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x388c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08880002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98800003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000002d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28080001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d808001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc180000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc100000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc080000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc0700, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113255, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d10ffdf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10cc0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d10c017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d0d000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd0130b7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14cc0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9c00036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000005d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00c4000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14d00011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9500fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc030000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c01b10, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00e0080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000013b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00e0800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000013b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400053, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x280c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00052, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28180039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400053, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x280c0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00052, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28180039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400053, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x280c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00052, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28180039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc030000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000069, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28080001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca88004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc00006f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000013b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28180080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00c4000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d10c017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd0130b7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000013b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97400001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc810000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd4c0380, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdcc0388, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55dc0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdcc038c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce0c0390, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce0c0394, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce4c0398, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56640020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce4c039c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce8c03a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56a80020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce8c03a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcecc03a8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcecc03ac, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf0c03b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57300020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf0c03b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf4c03b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57740020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf4c03bc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf8c03c0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57b80020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf8c03c4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfcc03c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57fc0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfcc03cc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05dc002f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc12009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d200a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc012009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25e01c00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25e40300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25e800c0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25ec003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e25c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de5c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xddc10000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02ee000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31100006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9500007b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc1c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc1c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4df0388, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d7038c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d5dc01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4e30390, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d70394, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d62001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4e70398, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d7039c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d66401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4eb03a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d703a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d6a801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4ef03a8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d703ac, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d6ec01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4f303b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d703b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d73001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4f703b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d703bc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d77401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4fb03c0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d703c4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d7b801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4ff03c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d703cc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d7fc01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc080000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4d70380, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4080001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1c88001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc0e0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc01e3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3cd00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0085, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc006a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc01e3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3cd00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900fffa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc180000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc100000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc080000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4080001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1c88001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc180000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc100000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc080000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400051, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04180018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aac0027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce813265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80002f1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04080002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08880001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080228, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000367, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9880fff3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04080010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08880001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80c0309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80c0319, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9880fffc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00e0100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d0003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d4001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x155c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05e80180, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x202c003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000bfc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc410001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000031, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900091a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05280196, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d4fe04, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800001b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000032b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000350, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000352, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000035f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000701, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000047c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000019f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc419325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d98001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4140004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0044, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27fc0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00c4000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9400036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15540008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd40005b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd40005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd40005d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840006d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11540015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19a4003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1998003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1af0007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1264001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15dc000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d65400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a38003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd5c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7df1c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800045, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411326a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc415326b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc419326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425326e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293279, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd000056, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800058, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00059, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x259c8000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce40005a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29988000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd000073, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411326f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17300019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25140fff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001b6d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4153279, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd00005f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000075, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26f00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15100010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d190004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd000035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1af07fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdf430000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4412e01, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0434001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdf430000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdf030000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4412e40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c031, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43dc031, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04343000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf413267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd1c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0160, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc810001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b4c0057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b700213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f4f400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55180020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2198003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x248dfffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc12e00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1af4007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33740003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26d80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ae8003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9680000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26680001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253348, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413348, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253348, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x958000d8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000315, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04303000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26680001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800041, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1714000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25540800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x459801b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d77400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x199c01e2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5e4002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e5c0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e540002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc80c0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54d00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55580020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000282, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc80c0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54d00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8180011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000282, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55580020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000282, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc80c0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8100011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55580020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1334e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01334f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd413350, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813351, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd881334d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193273, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3275, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3271, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4153274, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50cc0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cdcc011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05900008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd00006a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc0006b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3272, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d594002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54d00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc12e23, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd012e24, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc12e25, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15540002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b340057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b280213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980198, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2b000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55e40020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd40000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd40000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x20cc003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc13249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113274, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdd430000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc01e0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29dc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2d540002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x078c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07d40000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001239, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04f80000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x057c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd5c005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840007c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400069, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c018a6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4412e22, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800007c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c018a2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd4c005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9680fffc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800002e3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9680fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800002e3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000069, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013273, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013275, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9540188f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc013cfff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc13249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9680000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x38d00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04cc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdcc30000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c01882, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000304, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840002f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x49980198, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55e40020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x459801a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04302000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000329, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc812e00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04302000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16ec001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1998003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00031, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce00000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a18003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d43c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4093249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1888003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc419324c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x259c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1598001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14d80011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24dc00ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31e00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31dc0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580fff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9c00036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95801827, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840002f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14dc0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800006d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51dc0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32200002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a0000ad, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xde030000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04080000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27fc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1af4003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9740004d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4080060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca88005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24880001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f4b4009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97400046, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313274, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d33400c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97400009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28240100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a4004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1eecffdd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013273, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013275, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800003c3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429326f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aa80030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28240001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a8004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3272, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10cc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19e80042, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc0006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e8e800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de9c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3271, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50cc0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ce8c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd30011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11e80007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce80001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd300001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b30003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240059, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1660001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e320009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0328000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e72400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0430000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02ac000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d310002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa87600, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280222, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4280058, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x22ec003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013273, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce813275, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800007b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8380018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57b00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04343108, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13740008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2374007e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32a80003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18ec0057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e40213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc0199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cecc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ce4c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800003e7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xde030000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xde030000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980104, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x49980104, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55e00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800003f2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000448, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf813279, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf41326e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x254c0700, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10cc0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a641fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0726, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a640200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1237b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2264003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8813260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4280034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xde430000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce40000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c01755, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9680000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce80000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xde830000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce80000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0174c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4393265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bb80040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf813265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100044, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19180024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8100072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x551c003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000043d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00c8000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840006c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28200000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000043f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00c4000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x282000f0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113255, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000053, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x195c00e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2555fff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0360001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32200002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc5e124dc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0aa80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef6c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e624001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80fff9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02ee000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2555fff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55e00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3255, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353259, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980158, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x49980158, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980170, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16200010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d43c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x195400e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1154000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18dc00e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05e80488, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d0006c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18f807f0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e40077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18ec0199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6e400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000048e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000494, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800004de, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000685, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000686, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800006ac, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ccc001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1264000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d79400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e7a400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52a8001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d69401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x202c007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aec0028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d325c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800004cc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc419324e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26e8003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aec003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12f4000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d324d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d75401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d290004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f8f4001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f52800f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50e00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800004d1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d0dc002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x6665fc00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5e401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da1c011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a644000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f534002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x6665fc00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e76401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800004d7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aec003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3257, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213259, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12f4000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d75401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52200002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da1c011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a644000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x202c003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x259c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05e804e3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800004e7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800004f0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000505, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc435325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x277401ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf41325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640fff4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17e00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd84131db, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b301ff8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26edf000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8413260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05a80507, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000050c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000528, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000057d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800005c2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800005f3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bd400e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd40005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c004d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d150005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00063b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2511fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801326f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000624, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1be00fe4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000066, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400068, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bd400e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd40005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c004d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d150005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400067, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00063b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2511fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801326f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000624, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bd400e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ed6c005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113271, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4153270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193272, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3273, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d51401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113274, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213275, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253276, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400061, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2730000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7db1800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00062, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd000063, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000064, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400065, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce813260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc820001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b700057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b680213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x46ec0188, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56240020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17e00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26e01000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9c131fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25140001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x191807e4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x192007ec, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc1334a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x69dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de20014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x561c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013344, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc13345, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425334d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc419334e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d334f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213350, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253351, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b680057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b700213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x46ec01b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce813260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800068, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2010007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1910003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9500fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd00001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc410000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd00001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc410000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2010003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25140001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x191807e4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9540000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2511fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc1334a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013344, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013345, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180050, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0052, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280042, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813273, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc13275, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce813260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000068, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400067, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07d40000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00124f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x057c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b680057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b700213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc820001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x46ec0190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56240020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4153249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2154003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bd800e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd9c005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd80005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420004d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1e000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd413249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01326f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28340001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f598004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1be800e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce80005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801327a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800005f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000075, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424004c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41326e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28240100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a4004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc435325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x277401ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf41325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xda000068, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25140001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9540002d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc1334a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425334d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc419334e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d334f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213350, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253351, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b680057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b700213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x46ec01b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc1334a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1be000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0360001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc63124dc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0aa80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef6c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e724001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80fff9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02ee000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fc14001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x194c1c03, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc0003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c002d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000697, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x194c00e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc0005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c004c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27301fff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce00005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cf0c00d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0007e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b301ff8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25100007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31100005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900008e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000075e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x202c007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a9feff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1374000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1774000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d30b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce813265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00ac006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00e0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28880700, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0006de, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14cc0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30d4000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10cc0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41530b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19980028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800006c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15600008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8380023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11a00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fa38011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d1a0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x282c2002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e280008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd3800025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x202400d0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca48001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28240006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d8003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81a2a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x194c00e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc0005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c004c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27301fff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce00005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cf0c00d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000712, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x194c1c03, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc0003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c002d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05e80714, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000071c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000720, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000747, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000071d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800007c4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000732, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000745, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000744, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000072e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0007e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a64008c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b301fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000075e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c0fff1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0007e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000723, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41f02f1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000743, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8813247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c0ffde, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000072e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0007e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15600008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd84131db, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b301ff8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8413260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc8000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x195800e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd80005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418004c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81326e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc0005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dd7fff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc13265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51e00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1a001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x46200200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04283247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1af80057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1af40213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6f400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2000025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc6990000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x329c325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x329c3269, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x329c3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc01defff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d8009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000078a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25980000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fff2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03e7ff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f3f0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1f30001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03e4000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013255, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001219, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d30b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bf0003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000b80, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x203c003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300700, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf0130b7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x46200008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2000025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4080007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x259c0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31dc0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18ec0057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e40213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc0199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cecc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ce4c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000448, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31980002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19580066, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15600008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0120001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11980003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da18001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d24db, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd9c005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fff8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580137b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00ee000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840004f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113269, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19080070, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x190c00e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2510003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2518000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05a80809, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000080e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000080f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000898, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000946, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800009e1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04a80811, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000815, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000834, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000085e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000085e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04341001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3045, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1c091, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31300021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd84002f1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293059, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56a8001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2b000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000241, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000084a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43130b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02f0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec130b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4252087, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5668001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a80005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80130b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000084a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04341001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431ecaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02e0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec130b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80130b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31300021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd84002f1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293059, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56a8001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2b000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00021d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdd410000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd84802e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001a41, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43b02f1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec80278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56f00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001608, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8813247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80802e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000085e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31100011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x950001fa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02e0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aec0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc01c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11a40006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de6000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10e40008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e2e000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d10ffdf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2110003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013255, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d10ff9e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0245301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801325f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0121fff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29108eff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e524009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0127ff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e524009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0131fff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e524009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801326e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013279, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000866, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000866, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0100010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd2400c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0180003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd1c002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000866, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04a8089a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000089e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800008fa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000945, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000945, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31300022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04183000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d91801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x459801e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2738000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x172c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ec0800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef7400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8300011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8340011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9740002f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13b80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc79d3300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc7a13301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8393300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0260001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce793301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x964012a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c028009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9740001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800008d2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce40001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x242c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06ec0400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02620c0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce81c080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01c082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57240020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0260400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6e400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c084, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae8001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2f0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800008d2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdf93300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce393301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04182000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000903, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31240022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ec30011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32f80000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x67180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0bfc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd981325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000915, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9c1325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0fff6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f818001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001606, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d838001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3259, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16240014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a2801f0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2620ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e2a000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5e400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2264003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013259, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00075e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4af0228, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x66d80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1330000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13f40014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07fc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33e80010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9680ffec, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04a80948, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000094c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000099b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800009e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800009e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04183000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d91801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x459801e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2738000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x172c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ec0800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef7400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8300011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8340011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9740002c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13b80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc79d3300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc7a13301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8393300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0260001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce793301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x964011fe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c028009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9740001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000978, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce40001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x242c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06ec0400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0260010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01c080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57240020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce81c082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0260800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6e400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c084, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae8001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2f0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000978, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdf93300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce393301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04182000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dda801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e838011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd84802e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001802, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x469c0390, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04183000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x172c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ec0800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef7400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4280011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04182000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0014df, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31280014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce8802ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800062, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31280034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04a809e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800009ec, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a45, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a59, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a59, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d91801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4a70250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53300020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e72401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x172c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ec0800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef7400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x66740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97400041, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04383000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4393267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b38007e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33b40003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x4598001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9740002f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf4002eb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf4002ec, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf4002ed, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf4002ee, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04382000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd84802e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001715, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04382000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0aec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffbc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04341001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431ecaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a55, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43130b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x233c0032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc130b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf0130b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49302ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8413247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5198001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193269, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2598000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80002f1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53b8001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7db9801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000a5e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c01106, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e01, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e02, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e03, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c010fd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50640020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ce4c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c00072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc80c0072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x58e801fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce80001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18dc01e2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5e4002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e5c0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e540002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8180011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8100011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8100011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9540000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8180011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x44cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55900020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4140011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x44cc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8100011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd812e01, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd012e02, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd412e03, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2264003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc410001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4140028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1e64001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14d00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ab1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a0010ac, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd880003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c0003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800010de, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc010ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d403f7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d0cc009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41b0367, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d958004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d85800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc1e0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d001fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05280adc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000af1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000adf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ae7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000ace, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd8d2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d803f7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc010ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d0cc009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11940014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29544001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29544003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000af4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd44d2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd44dc000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d0003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000ace, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd8d2c00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000b0a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd44d2c00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28148004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d800ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4593240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0105e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2198003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x199c0034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313255, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef3400c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14e80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a8000af, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c01043, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18a01fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3620005c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2464003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc6290ce7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16ac001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ac003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ee6c00d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2620000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00fff8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000367, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640102e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x199c0037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19a00035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0005d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16f8001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9780000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc035f0ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e764009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19b401f8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13740008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e76400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1000072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8100072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x199c0034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ae4003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000b7c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aec003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19a4003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12ec001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1374000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02e4000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1774000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc01e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13fc0018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dbd800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d98ff15, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x592c00fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd80000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12e00016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da1800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x592c007e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12e00015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da1800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11a0000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1264001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1620000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e32000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12e4001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5924007e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19a4003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013257, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd413258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00fdb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9780f5ca, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001219, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001b6d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d324e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431324d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc435324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07740003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x269c003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5e4004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f67000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f674002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53740002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef6c011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ab42010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ab8c006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16a8000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a80800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b740000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf40001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000bec, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000b47, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b34060b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ec00ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03a8004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef6c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f3b000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc410001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc415325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18580037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x262001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d54001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a80004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14f00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd280200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd680208, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcda80210, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b400014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a80004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc6930200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc6970208, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc69b0210, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd900003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd940003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9400040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800010de, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14fc0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24f800ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33b80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d83c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4093249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1888003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc419324c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x259c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1598001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14d80011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24e000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x321c0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580ffee, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c30, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9480000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800f29, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800f23, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9c00036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800f1a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9600f502, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c0f500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000f05, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1f30001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16e4001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640f4f4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc434000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33740002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40f4f1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aec003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12ec001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1374000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02e4000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1774000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12780001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bb80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00ac005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00e0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc8000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28884900, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ff3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17fc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400ee1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c40a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c40c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c40d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d0007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15580010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x255400ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01c411, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81c40f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41c40e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c410, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e80033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18ec0034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c414, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c415, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81c413, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41c412, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18dc0032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c030011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c038011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431c417, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc435c416, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439c419, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43dc418, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf413261, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013262, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13263, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf813264, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18dc0030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17fc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d77000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000cd6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51b80020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53300020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f97801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f3b000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000cd6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ca7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18dc0031, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc435c40b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9740fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4280032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012c2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb81ff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f8cc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13f4000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bf0060b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc0077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000cf4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc0677, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13fc0017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb81fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc032800b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb7800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ffbc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d42011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17fc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d001e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd4c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800e6c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50580020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x596001fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ce0c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x505c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50600020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc0001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8240010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5e800c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x122c0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0aec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000d1f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8240010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x566c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413261, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13262, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b740008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x566c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce413261, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec13262, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012c2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb81fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f8cc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13f4000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bf0060b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc0077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000d57, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc0677, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13fc0017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb81fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0328009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb7800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ffbc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04143000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd413267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e51001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4153267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d2d0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19640057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19580213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19600199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da6400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1000025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04142000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd413267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4153267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d001e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d40030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d80034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05280d83, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c424001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000d8a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000d95, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000db1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000d95, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000dbc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11540010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e010001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00187c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d75400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4610000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580f3d8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439c040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x526c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e80058, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e2ec01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc82c0072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5ae0073a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ea2800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580f3c6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc3a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80fffb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980fff5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02a0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16200002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01c405, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd441c406, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580f3b1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439c409, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11540010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29540002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4610000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580f3a5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439c040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00da7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50500020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c00072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8280072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5aac007e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12d80017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56a00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2620ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da1800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e82400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e58c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19d4003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28182002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00104f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc011000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11a00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c908009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d614011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca4800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d1a0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cb0800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e280008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x20880188, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cb4800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x20240090, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca48001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28240004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c018001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf80003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd901a2a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1624001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd841325f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27fc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c00038, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429325f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ac0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ac0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13f4000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b301ff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9680000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27fc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c00038, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0001a2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc80003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24b00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1330000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18ac0024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b304000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18a800e5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da9800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1910003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2220003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e2a000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27fc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c00038, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18dc003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d40030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d001e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18fc0034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24e8000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80e71, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000edd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000e91, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000e91, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ea1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000eaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000e7c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000e7f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000e7f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000e87, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000e8f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51dc0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9e001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a200008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213262, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253261, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a200008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213264, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253263, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc820001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e82005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51e00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da1801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1800072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8180072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x59a001fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ea2800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce80001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8200011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15980002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81c400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421c401, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400041, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425c401, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac2580, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac260c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac0800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac0828, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac2440, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac2390, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac0093, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac31dc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac31e6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ede, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39ac7c06, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db07c00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39acc337, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db0c330, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39acc335, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db0c336, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39ac9002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db09001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39ac9012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db09011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39acec70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db0ec6f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc5a10000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc5a50000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05280eea, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ef1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000efe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f11, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f2e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000efe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f1f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce190000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce190000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0f26f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439c040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e80058, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7daec01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc82c0072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5af8073a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eba800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56240020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0f25c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02a0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15980002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81c405, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01c406, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56240020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c406, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0f24e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439c409, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40f247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce190000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce190000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0f240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439c040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac2580, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac260c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac0800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac0828, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac2440, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac2390, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac0093, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac31dc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31ac31e6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ef2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39ac7c06, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db07c00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39acc337, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db0c330, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39acc335, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db0c336, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39acec70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db0ec6f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39ac9002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db09002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39ac9012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3db09012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ef1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c43c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc434000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b740008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b780001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c1325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf80001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c034001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c038001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e0007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32240003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32240000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01c080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41c081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f88, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51640020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e52401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2400072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8280072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce81c080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56ac0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26f0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01c081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1af000fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1334000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24e02000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f63400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e00074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32240003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32240000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81c082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc1c083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000f9d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51e40020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5a401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2400072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8280072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce81c082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56ac0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26f0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01c083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1af000fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13380016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e00039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fa3800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb7800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e0007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1220001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fa3800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e00074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fa3800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf81c078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc1c084, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18dc003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d001e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31140005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31140006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00104f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05280fb7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28140002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000fbe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000fbe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000fc2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000fbe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000fd1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ff2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ff2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1a2a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e80039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52a8003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50580020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d69401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140004b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1a2a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d958004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1a2a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d150005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9500000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x159c0011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x259800ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31a00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31a40001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e25800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0fff5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580fff4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000fef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411326f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d100010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01326f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc011000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33b40003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0340008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000ffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11a00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c908009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d614011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca4800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d1a0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cb0800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x282c2002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x208801a8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e280008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cb4800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x20240030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca48001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28340000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x507c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d7d401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x557c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28342002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000102f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c018001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1cccfe08, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1a2a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00b33, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da2400f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da28002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1ac002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0aec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d2ac002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3ef40010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40f11d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf81325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xde410000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdcc10000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdd010000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdd410000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdd810000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xddc10000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xde010000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c024001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8100086, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5510003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001075, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4140025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15800f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15c002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d520002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cde0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e20001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001071, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9c00036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00b01, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc200000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc1c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc180000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc100000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc240000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc240000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc40003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4080029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc80003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18a800e5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da9800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18a400e5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12500009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x248c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x200c006d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x200c0228, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc410002b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18881fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d4072c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc00d1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd4c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3094000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x38d80000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x311c0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30940007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1620001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800010c4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00041, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25140001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418002c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x259c007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19a00030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc0001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800010cb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x199c0fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc0001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800010cb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000aac, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc434002e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2020002c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17780001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07a810d8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000bfc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000104c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc400040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x200c007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28240007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xde430000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc80003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24b00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1330000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18a800e5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da9800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b304000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x192400fd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50580020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06681110, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18ac0024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19180070, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19100078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18f40058, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5978073a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001117, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001118, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001122, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000112d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001130, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001133, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000117b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24ec0f00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32ec0600, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000117b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24ec0f00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32ec0600, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000117b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55e00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001122, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc81c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55e00020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001122, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00116b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02a0200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e8e8009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x22a8003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x22a80074, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2774001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13740014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eb6800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25ecffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55700020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15f40010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13740002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x275c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c018001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15dc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39e00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dc1c01e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05e40008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dc2001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05e40008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e62000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da58001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001165, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dc2001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1a0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e0d000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95000007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e02401e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06640008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05d80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dc2401e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da58001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05e00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da2000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9600ffe6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00116b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce00001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce81c078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1c080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41c082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01c083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x22640435, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c084, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0528117e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x312c0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001185, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001182, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001182, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03a0400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1198001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d81c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc130b7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf8130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0049, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19a000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de2c00c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26200010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc415326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc420007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce40003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800011a3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d654001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c020001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4140025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800011b6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253279, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc415326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2730003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3b380006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3f38000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800011b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800011b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0430000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb10004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e57000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e578002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d67c002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0be40001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d3a4002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x202c002c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26200010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e640010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce81325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc434002e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17780001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07a811cf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00feb8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x954009a7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000bfc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1c07c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c07d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c08c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01c07e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18f0012f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18f40612, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc00c1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cf7400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x39600004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0140004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11600001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18fc003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9740001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400041, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425c07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x166c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800011ee, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a6c003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800011e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428002c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ac007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ab00030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aac0fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc434000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc434000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001205, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425c07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x166c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11600001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0fffa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27fc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd841c07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc0078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ffbc00c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03a2800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf81c07c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c07d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c08c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c07e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17fc001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0fffa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801c07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03ae000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf81c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03a0800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf81c07c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c07d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c08c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c07e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17fc001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0fffa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03ae000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf81c200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03a4000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf81c07c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c07d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c08c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c07e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17fc001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0fffa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30d00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000052, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640090f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1514001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19180038, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d324e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431324d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc435324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ab0c006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000127f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d3258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313257, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353259, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ab0c012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a0003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e624004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f67800f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53740002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef6c011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ab42010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16a8000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a80800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b740000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf40001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1514001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0012e1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x964008d7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9800036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300677, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012aa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b34060b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ec00ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03a8002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef6c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7edec00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f3b000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4140032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc410001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1858003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99800007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d0cc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d0006c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d407f0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2598003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d190004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d5d4001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d52000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012d8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d514002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012d8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193259, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d958001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd5c002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813259, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc1325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1ccc001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14f00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd980003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9c0003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9800040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd9c00040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800010de, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33f80003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800051, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc80003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24b00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1330000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18a800e5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1d980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7da9800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b74003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b304000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431326c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b4c00f8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50700020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04e81324, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18ac0024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50600020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30e40004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d71401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x596401fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b74008d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e76400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a640000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000132c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000133b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001344, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42530b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a68003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2024003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25980700, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11980014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d19000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd0130b7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce4130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce40001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de6800f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffea, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce40001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8240011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de6800f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffe0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00104f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28182002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340035, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140023, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11a00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d614011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca4800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d1a0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cb0800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3e280008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cb4800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x20240030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ca48001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b4c00f8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28340000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x507c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30e40004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d7d401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x557c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28342002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c018001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf81a2a4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c007eb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50500020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d0d001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1000072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8100072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x591c01fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45140210, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x595801fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11980009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29dc0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc0001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1624001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400069, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a307fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x23304076, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc00e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10cc0015, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x4514020c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a2001e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a204001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a64003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1264001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15dc000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dcdc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5dc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340022, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdf430000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4412e01, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0434001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdf430000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdf030000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4412e40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c030, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41c031, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x248dfffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc12e00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc812e00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45140248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8200011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013257, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0434000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdb000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45540008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8200011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013259, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0337fff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f220009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55300020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d01c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c01d0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06ec0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f01c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50500020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd0c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd0c00072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8240072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd240001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19682011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5a6c01fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12ec0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eeac00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aec0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4180011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99800007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdf830000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfa0000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4380007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17b80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d40038, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9540073d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18c80066, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30880001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00187c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd910000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x4220000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24e80007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24ec0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc5310000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001465, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1000072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc82c0072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2c0001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18f02011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5aec01fc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12ec0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aec0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0aa80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a8146a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f1f0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f1b400f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001478, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f1b400e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001478, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f1b400c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000147a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f1b400d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000147a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f1b400f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000147a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f1b400e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000147a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f334002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97400014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000147b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b400012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e024001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000144a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb81ff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fbfc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94800007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00187c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42c0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd910000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800012c2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13f4000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bf0060b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc0077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800014a9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d325a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc0677, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb81ff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0328007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb7800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13fc0017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ffbc00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc1325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03a0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf8130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd9c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45dc0390, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04183000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b380057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b340213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c424001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c428001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c42c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c430001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04182000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840004f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a0800fd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x109c000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd9c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc13265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2620ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce080228, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9880000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce480250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce880258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0ec75, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0fffb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc80230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce480250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce880258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52a80020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x66580001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0fffb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc80260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec80288, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf080290, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec80298, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf0802a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf4802a8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0fffb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc802b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80802b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x178c000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b8003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cf8c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf8802c0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc802c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf8802d0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf8802d8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bc800ea, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25b8ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd2800c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc5230309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2620ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e3a400c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001539, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd08034b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd880353, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00163f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49b0353, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0228, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd14005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000154f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd080238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd08034b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2598ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3d200008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc80230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd900309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8100319, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340801, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2198003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd910ce7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4190ce6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d918005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d918004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd810ce6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdd1054f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000156e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x090c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdcd050e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x110c0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc4001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41230a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41230b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41230c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc41230d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc480329, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc48032a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc4802e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000055, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f02e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d8003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09940001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x44100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580002c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x69100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000157f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4970290, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49b0288, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49b02a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49f0298, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x041c0040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dcdc002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d924019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d26400c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0fffa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00163f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001579, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d010021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d914019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55580020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd480298, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd8802a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10d40010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12180016, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc51f0309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d95800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d62000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd9c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdd00309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce113320, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f02e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49b02b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18dc01e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd9400e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c0001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00163f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800015aa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4a302b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12240004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e5e400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4ab02a8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04100000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce4c0319, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d9d8002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ea14005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2620000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800015bc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04240001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e624004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d25000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2620000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0fff4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd0d3330, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce0802b8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd8802b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4ab02e0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aa807f0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f02d0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49702d8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49b02c8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49f02c0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96800028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d4e000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9600000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d964002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d694001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800015e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cde4002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de94001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800015e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd64002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d694001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800015e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00163f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800015cd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930238, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d698002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd4802d8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x129c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc50f0319, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11a0000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11140001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1e000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1198000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd953300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e0e000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a8000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce953301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce100319, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b70280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73800a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x536c0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9780eb68, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001608, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001609, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30b40000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b400011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b70258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53780020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb3801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7faf8019, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x67b40001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x57b80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4bb0260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fab8001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf880260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x66f40001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97400005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4353247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f7f4009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fff7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x269c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a00018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a00060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x269c0018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a00007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a40060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11dc0006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29dc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de5c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b70228, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc80230, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f514005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001644, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd080240, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f130005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001688, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001219, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340801, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f130004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01051e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42d051f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ed2c005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96c0fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01051f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000055, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc5170309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x195c07f0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x196007f6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04340001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x6b740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001665, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4a702a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4ab0298, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f634014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e76401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56680020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8113320, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce480298, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce8802a0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc5170319, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b702b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x255c000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f5f4001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8113330, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf4802b0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11340001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x195c07e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x196007ee, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8353300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1e4001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8353301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce4802d0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8100309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8100319, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc48f0250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd4c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x64d80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580005c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dc24001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd2000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3255, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc435324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7df5c00c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25980040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb0003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000049, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33380003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800046, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4393260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb000e4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800016f1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc033ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2f3000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f3b0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b800ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a7003e6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27380003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13b80004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a7000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07b80002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a700064, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800016df, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb30002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4392083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffdf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffca, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd841325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2030007b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800016f2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd841325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940ff9c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001608, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840004f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bc800ea, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd80802e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18fc0064, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00042, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dd9801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x45980400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b380057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b340213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14f4001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4bf02e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x192807fa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4bf0258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4a70250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53fc0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e7e401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x667c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0aec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eebc00c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fff8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x43300007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7db30011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd3000025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc03ec005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfca200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x192807fa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc01f007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d1d0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2110007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x203c003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0017f5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18fc01e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00185b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8413247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40ffd5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4bf02e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0ea24, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14d4001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d52400e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49f0258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4a30250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51dc0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400017, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d534002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4af0270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dae4005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32e0001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec80270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000174f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b740001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00178a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40fff3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001608, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4ab0268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7daa4005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32a0001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001765, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc01f007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d1d0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2110007d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8013256, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c0017f2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4113248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b3034b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f13000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001855, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32a4001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8413247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd080260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce880268, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940ffc0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ec28001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32e0001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253255, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431324f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e72400c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a80040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9680fff7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aa4003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400049, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aa400e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32680003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a800046, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4293260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1aa400e4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800017e2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc027ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2e6400ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a4009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a800ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4240009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19e403e6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26680003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12a80004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ea68001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19e400e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ea68001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ea68001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19e40064, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16a40005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06640003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce412082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a640003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800017d0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16a40005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce412082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ea64002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4292083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ea68005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a80ffdf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc429325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26a400ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40ffca, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd841325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2024007b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800017e3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd841325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4a70280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4ab0278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7eae8014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e6a401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56680020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce480278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce880280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec80270, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800017fe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4bf02e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800017fe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43b02eb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42302ec, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf813245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fa3801a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x47b8020c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x15e00008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1220000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2a206032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x513c001e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e3e001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4bf02e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000180f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b3c0077, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ff3000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1330000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd200000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd3800002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dc30001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc1e0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04380032, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf80000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc413248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3269, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27fc000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33fc0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdfc30000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4413249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c43c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c43c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0bfc0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdfc30000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd441326a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x173c0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300303, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f3f0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ff3c004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13084, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001842, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdfc30000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4413249, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c43c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x23fc003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc1326d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0bb80026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdf830000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd441326e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4393265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1fb8ffc6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xddc30000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf813265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc0000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001852, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc0000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc13252, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013253, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001878, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49f02e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c00018, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc13252, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013253, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c3000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c0012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001878, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41f02ed, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42302ee, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc13252, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013253, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e2a0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013084, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28340001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x313c0bcc, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x393c051f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3d3c050e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x393c0560, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3d3c054f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x393c1538, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3d3c1537, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b740800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bc800ea, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e8007c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c42c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a8189a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000189e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800018c5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800018f2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d0007e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x50580020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09240002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc42130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a24002c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2020002c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1198001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10cc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14cc0004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7cd8c00a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc130b7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce0130b5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x5978073a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bb80002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf800024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9600e8a8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9640e8a5, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800018a9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc55b0309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3d5c0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2598ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09780001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dad800c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0ffd2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580fff9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x442c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x65180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7df9c00c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c13260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd901325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940fff1, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x66d80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x56ec0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26240007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940fff7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000189e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc023007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19e4003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7de1c009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dee000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96000007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c13260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd901325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc421325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x261c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000189e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940fff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000189e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43d3265, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bc800ea, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18e00064, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06281911, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14f4001d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24cc0003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001915, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x800019af, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001a2b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc48032b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc480333, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc48033b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc480343, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98800011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x46640400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04203000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b3c0057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b200213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e3e000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e32000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04180000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f438001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00068, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213254, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a1c003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00065, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc01f007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1e0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97800062, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x43bc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fcbc001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc7df032b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1fc00c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0101, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c0102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb0003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000049, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33380003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800046, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4393260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb000e4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001994, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc033ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2f3000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f3b0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b800ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f003e6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27380003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13b80004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07b80002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f00064, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001982, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb30002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4392083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffdf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffcb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc1325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2030007b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001995, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc1325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98800009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x41bc0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x53fc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e7fc011, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd3c00025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0012, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x653c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dbd8001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940ff8f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x043c2000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc55b0309, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x3d5c0010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2598ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x05540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d91800c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580fff8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09780001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x65180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9580005d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200101, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400058, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dc24001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41d3248, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25dc000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7df9c00c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95c00053, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e41c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a70003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000049, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a7000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33240003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a400046, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1a7000e4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001a21, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc033ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2f3000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f270009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x266400ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f003e6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27240003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12640004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e724001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e724001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e724001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06640002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f00064, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16700005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001a0f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x16700005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e730002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4252083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e724005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a40ffdf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x267000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffca, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2030007b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001a22, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940ff9f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001a31, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213246, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4253245, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e26401a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x46640400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04203000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce013267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4213267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b180057, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b200213, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e1a000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e32000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce000024, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4930250, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x65180001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800060, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4193247, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x25980001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200101, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x30f00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95800056, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb0003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000049, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33380003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b800046, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4393260, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bb000e4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001aa2, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc033ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2f3000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f3b0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b800ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4300009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9700fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f003e6, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27380003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13b80004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f000e8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07b80002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x19f00064, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0b300003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001a90, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb30002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4392083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7fb38005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b80ffdf, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27b000ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b00ffca, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2030007b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf00325b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001aa3, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49b02e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99800005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd2400025, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x4664001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55100001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940ff9c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc49b02e9, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99800008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc430000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2b300008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf000013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04302000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcf013267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x244c00ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc4c0200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc44f0200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc410000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d158010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x059cc000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccdd0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0037, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000049, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c003a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9500e69a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d0003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d40021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd840004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c003c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x14cc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c00028, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000033, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc438000b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x27fc0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd841c07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1bfc0078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7ffbc00c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x97c0fffd, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x99000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0120840, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x282c0040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001ae8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0121841, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x282c001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01c07c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c07d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c08c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c079, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c07e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcec0001b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425c07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x166c001f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04200004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9ac0fffb, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc434000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9b40ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801c07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc425c07f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8000034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940e66b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800004a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0036, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9900fffe, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18cc0021, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc00047, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc000046, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0039, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c003d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24d003ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d47fea, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x18d87ff4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd00004c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd40004e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd80004d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41c405, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc02a0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2aa80001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01c406, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c406, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c406, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc414000e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x295c0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8c1325e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcdc0001a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11980002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x4110000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0160800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7d15000a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0164010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41c078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c080, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c081, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81c082, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc01c083, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01c084, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x98c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400048, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c003b, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801c40a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd901c40d, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801c410, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801c40e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd801c40f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc40c0040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9940ffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04140096, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1c400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc411c401, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9500fffa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424003e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04d00001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x11100002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd01c40c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0180034, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd81c411, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd841c414, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0a540001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcd41c412, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x2468000f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc419c416, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x41980003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc41c003f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7dda0001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x12200002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x10cc0002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xccc1c40c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd901c411, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce41c412, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xce292e40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e01, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e02, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e03, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc412e00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc120000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x31144000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x95400005, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xdc030000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xcc3c000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x33f80003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x9780e601, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x188cfff0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x04e40002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400006, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x96400003, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80001b74, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xbf810000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL                              },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI                           },
+    { PwrCmdWrite, 0x54106500, mmCP_DFY_ADDR_LO                           },
+    { PwrCmdWrite, 0x7e000200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e020204, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc00a0505, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xbf8c007f, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb8900904, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb8911a04, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb8920304, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb8930b44, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x921c0d0c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x921c1c13, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x921d0c12, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x811c1d1c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x811c111c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x921cff1c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000400, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x921dff10, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000100, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x81181d1c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e040218, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050102, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xbf810000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL                              },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI                           },
+    { PwrCmdWrite, 0x54106900, mmCP_DFY_ADDR_LO                           },
+    { PwrCmdWrite, 0x7e080200, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x7e100204, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xbefc00ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00010000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x24200087, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x262200ff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000001f0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x20222282, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x28182111, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xbf810000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL                              },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI                           },
+    { PwrCmdWrite, 0x54116f00, mmCP_DFY_ADDR_LO                           },
+    { PwrCmdWrite, 0xc0310800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb4540fe8, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000041, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000000c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07808000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x540fee40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54116f00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00005301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb4540fef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x540fee20, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0310800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb454105e, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000c0, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07808000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x540fee40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54117300, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00005301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb4540fef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x540fee20, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0310800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb4541065, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000500, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000001c, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07808000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x540fee40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54117700, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00005301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb4540fef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x540fee20, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xc0310800, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000040, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb4541069, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000444, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x0000008a, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x07808000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000002, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x540fee40, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000004, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x54117b00, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00005301, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0xb4540fef, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x540fee20, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x08000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0                            },
+    { PwrCmdWrite, 0x00000000, mmCP_MEC_CNTL                              },
+    { PwrCmdWrite, 0x00000000, mmCP_MEC_CNTL                              },
+    { PwrCmdWrite, 0x00000004, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x54116f00, mmCP_MQD_BASE_ADDR                         },
+    { PwrCmdWrite, 0x000000b4, mmCP_MQD_BASE_ADDR_HI                      },
+    { PwrCmdWrite, 0xb4540fef, mmCP_HQD_PQ_BASE                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_BASE_HI                        },
+    { PwrCmdWrite, 0x540fee20, mmCP_HQD_PQ_WPTR_POLL_ADDR                 },
+    { PwrCmdWrite, 0x000000b4, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI              },
+    { PwrCmdWrite, 0x00005301, mmCP_HQD_PERSISTENT_STATE                  },
+    { PwrCmdWrite, 0x00010000, mmCP_HQD_VMID                              },
+    { PwrCmdWrite, 0xc8318509, mmCP_HQD_PQ_CONTROL                        },
+    { PwrCmdWrite, 0x00000005, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x54117300, mmCP_MQD_BASE_ADDR                         },
+    { PwrCmdWrite, 0x000000b4, mmCP_MQD_BASE_ADDR_HI                      },
+    { PwrCmdWrite, 0xb4540fef, mmCP_HQD_PQ_BASE                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_BASE_HI                        },
+    { PwrCmdWrite, 0x540fee20, mmCP_HQD_PQ_WPTR_POLL_ADDR                 },
+    { PwrCmdWrite, 0x000000b4, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI              },
+    { PwrCmdWrite, 0x00005301, mmCP_HQD_PERSISTENT_STATE                  },
+    { PwrCmdWrite, 0x00010000, mmCP_HQD_VMID                              },
+    { PwrCmdWrite, 0xc8318509, mmCP_HQD_PQ_CONTROL                        },
+    { PwrCmdWrite, 0x00000006, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x54117700, mmCP_MQD_BASE_ADDR                         },
+    { PwrCmdWrite, 0x000000b4, mmCP_MQD_BASE_ADDR_HI                      },
+    { PwrCmdWrite, 0xb4540fef, mmCP_HQD_PQ_BASE                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_BASE_HI                        },
+    { PwrCmdWrite, 0x540fee20, mmCP_HQD_PQ_WPTR_POLL_ADDR                 },
+    { PwrCmdWrite, 0x000000b4, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI              },
+    { PwrCmdWrite, 0x00005301, mmCP_HQD_PERSISTENT_STATE                  },
+    { PwrCmdWrite, 0x00010000, mmCP_HQD_VMID                              },
+    { PwrCmdWrite, 0xc8318509, mmCP_HQD_PQ_CONTROL                        },
+    { PwrCmdWrite, 0x00000007, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x54117b00, mmCP_MQD_BASE_ADDR                         },
+    { PwrCmdWrite, 0x000000b4, mmCP_MQD_BASE_ADDR_HI                      },
+    { PwrCmdWrite, 0xb4540fef, mmCP_HQD_PQ_BASE                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_BASE_HI                        },
+    { PwrCmdWrite, 0x540fee20, mmCP_HQD_PQ_WPTR_POLL_ADDR                 },
+    { PwrCmdWrite, 0x000000b4, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI              },
+    { PwrCmdWrite, 0x00005301, mmCP_HQD_PERSISTENT_STATE                  },
+    { PwrCmdWrite, 0x00010000, mmCP_HQD_VMID                              },
+    { PwrCmdWrite, 0xc8318509, mmCP_HQD_PQ_CONTROL                        },
+    { PwrCmdWrite, 0x00000004, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000104, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000204, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000304, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000404, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000504, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000604, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000704, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000005, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000105, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000205, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000305, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000405, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000505, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000605, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000705, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000006, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000106, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000206, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000306, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000406, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000506, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000606, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000706, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000007, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000107, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000207, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000307, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000407, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000507, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000607, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000707, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000008, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000108, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000208, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000308, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000408, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000508, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000608, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000708, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000009, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000109, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000209, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000309, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000409, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000509, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000609, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000709, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR                           },
+    { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR                           },
+    { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE                            },
+    { PwrCmdWrite, 0x00000004, mmSRBM_GFX_CNTL                            },
+    { PwrCmdWrite, 0x01010101, mmCP_PQ_WPTR_POLL_CNTL1                    },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdWrite, 0x00000000, mmGRBM_STATUS                              },
+    { PwrCmdEnd,   0x00000000, 0x00000000                                 },
+};
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _HARDWARE_MANAGER_H_
+#define _HARDWARE_MANAGER_H_
+
+
+
+struct pp_hwmgr;
+struct pp_hw_power_state;
+struct pp_power_state;
+enum amd_dpm_forced_level;
+struct PP_TemperatureRange;
+
+struct phm_fan_speed_info {
+	uint32_t min_percent;
+	uint32_t max_percent;
+	uint32_t min_rpm;
+	uint32_t max_rpm;
+	bool supports_percent_read;
+	bool supports_percent_write;
+	bool supports_rpm_read;
+	bool supports_rpm_write;
+};
+
+/* Automatic Power State Throttling */
+enum PHM_AutoThrottleSource
+{
+    PHM_AutoThrottleSource_Thermal,
+    PHM_AutoThrottleSource_External
+};
+
+typedef enum PHM_AutoThrottleSource PHM_AutoThrottleSource;
+
+enum phm_platform_caps {
+	PHM_PlatformCaps_AtomBiosPpV1 = 0,
+	PHM_PlatformCaps_PowerPlaySupport,
+	PHM_PlatformCaps_ACOverdriveSupport,
+	PHM_PlatformCaps_BacklightSupport,
+	PHM_PlatformCaps_ThermalController,
+	PHM_PlatformCaps_BiosPowerSourceControl,
+	PHM_PlatformCaps_DisableVoltageTransition,
+	PHM_PlatformCaps_DisableEngineTransition,
+	PHM_PlatformCaps_DisableMemoryTransition,
+	PHM_PlatformCaps_DynamicPowerManagement,
+	PHM_PlatformCaps_EnableASPML0s,
+	PHM_PlatformCaps_EnableASPML1,
+	PHM_PlatformCaps_OD5inACSupport,
+	PHM_PlatformCaps_OD5inDCSupport,
+	PHM_PlatformCaps_SoftStateOD5,
+	PHM_PlatformCaps_NoOD5Support,
+	PHM_PlatformCaps_ContinuousHardwarePerformanceRange,
+	PHM_PlatformCaps_ActivityReporting,
+	PHM_PlatformCaps_EnableBackbias,
+	PHM_PlatformCaps_OverdriveDisabledByPowerBudget,
+	PHM_PlatformCaps_ShowPowerBudgetWarning,
+	PHM_PlatformCaps_PowerBudgetWaiverAvailable,
+	PHM_PlatformCaps_GFXClockGatingSupport,
+	PHM_PlatformCaps_MMClockGatingSupport,
+	PHM_PlatformCaps_AutomaticDCTransition,
+	PHM_PlatformCaps_GeminiPrimary,
+	PHM_PlatformCaps_MemorySpreadSpectrumSupport,
+	PHM_PlatformCaps_EngineSpreadSpectrumSupport,
+	PHM_PlatformCaps_StepVddc,
+	PHM_PlatformCaps_DynamicPCIEGen2Support,
+	PHM_PlatformCaps_SMC,
+	PHM_PlatformCaps_FaultyInternalThermalReading,          /* Internal thermal controller reports faulty temperature value when DAC2 is active */
+	PHM_PlatformCaps_EnableVoltageControl,                  /* indicates voltage can be controlled */
+	PHM_PlatformCaps_EnableSideportControl,                 /* indicates Sideport can be controlled */
+	PHM_PlatformCaps_VideoPlaybackEEUNotification,          /* indicates EEU notification of video start/stop is required */
+	PHM_PlatformCaps_TurnOffPll_ASPML1,                     /* PCIE Turn Off PLL in ASPM L1 */
+	PHM_PlatformCaps_EnableHTLinkControl,                   /* indicates HT Link can be controlled by ACPI or CLMC overrided/automated mode. */
+	PHM_PlatformCaps_PerformanceStateOnly,                  /* indicates only performance power state to be used on current system. */
+	PHM_PlatformCaps_ExclusiveModeAlwaysHigh,               /* In Exclusive (3D) mode always stay in High state. */
+	PHM_PlatformCaps_DisableMGClockGating,                  /* to disable Medium Grain Clock Gating or not */
+	PHM_PlatformCaps_DisableMGCGTSSM,                       /* TO disable Medium Grain Clock Gating Shader Complex control */
+	PHM_PlatformCaps_UVDAlwaysHigh,                         /* In UVD mode always stay in High state */
+	PHM_PlatformCaps_DisablePowerGating,                    /* to disable power gating */
+	PHM_PlatformCaps_CustomThermalPolicy,                   /* indicates only performance power state to be used on current system. */
+	PHM_PlatformCaps_StayInBootState,                       /* Stay in Boot State, do not do clock/voltage or PCIe Lane and Gen switching (RV7xx and up). */
+	PHM_PlatformCaps_SMCAllowSeparateSWThermalState,        /* SMC use separate SW thermal state, instead of the default SMC thermal policy. */
+	PHM_PlatformCaps_MultiUVDStateSupport,                  /* Powerplay state table supports multi UVD states. */
+	PHM_PlatformCaps_EnableSCLKDeepSleepForUVD,             /* With HW ECOs, we don't need to disable SCLK Deep Sleep for UVD state. */
+	PHM_PlatformCaps_EnableMCUHTLinkControl,                /* Enable HT link control by MCU */
+	PHM_PlatformCaps_ABM,                                   /* ABM support.*/
+	PHM_PlatformCaps_KongThermalPolicy,                     /* A thermal policy specific for Kong */
+	PHM_PlatformCaps_SwitchVDDNB,                           /* if the users want to switch VDDNB */
+	PHM_PlatformCaps_ULPS,                                  /* support ULPS mode either through ACPI state or ULPS state */
+	PHM_PlatformCaps_NativeULPS,                            /* hardware capable of ULPS state (other than through the ACPI state) */
+	PHM_PlatformCaps_EnableMVDDControl,                     /* indicates that memory voltage can be controlled */
+	PHM_PlatformCaps_ControlVDDCI,                          /* Control VDDCI separately from VDDC. */
+	PHM_PlatformCaps_DisableDCODT,                          /* indicates if DC ODT apply or not */
+	PHM_PlatformCaps_DynamicACTiming,                       /* if the SMC dynamically re-programs MC SEQ register values */
+	PHM_PlatformCaps_EnableThermalIntByGPIO,                /* enable throttle control through GPIO */
+	PHM_PlatformCaps_BootStateOnAlert,                      /* Go to boot state on alerts, e.g. on an AC->DC transition. */
+	PHM_PlatformCaps_DontWaitForVBlankOnAlert,              /* Do NOT wait for VBLANK during an alert (e.g. AC->DC transition). */
+	PHM_PlatformCaps_Force3DClockSupport,                   /* indicates if the platform supports force 3D clock. */
+	PHM_PlatformCaps_MicrocodeFanControl,                   /* Fan is controlled by the SMC microcode. */
+	PHM_PlatformCaps_AdjustUVDPriorityForSP,
+	PHM_PlatformCaps_DisableLightSleep,                     /* Light sleep for evergreen family. */
+	PHM_PlatformCaps_DisableMCLS,                           /* MC Light sleep */
+	PHM_PlatformCaps_RegulatorHot,                          /* Enable throttling on 'regulator hot' events. */
+	PHM_PlatformCaps_BACO,                                  /* Support Bus Alive Chip Off mode */
+	PHM_PlatformCaps_DisableDPM,                            /* Disable DPM, supported from Llano */
+	PHM_PlatformCaps_DynamicM3Arbiter,                      /* support dynamically change m3 arbitor parameters */
+	PHM_PlatformCaps_SclkDeepSleep,                         /* support sclk deep sleep */
+	PHM_PlatformCaps_DynamicPatchPowerState,                /* this ASIC supports to patch power state dynamically */
+	PHM_PlatformCaps_ThermalAutoThrottling,                 /* enabling auto thermal throttling, */
+	PHM_PlatformCaps_SumoThermalPolicy,                     /* A thermal policy specific for Sumo */
+	PHM_PlatformCaps_PCIEPerformanceRequest,                /* support to change RC voltage */
+	PHM_PlatformCaps_BLControlledByGPU,                     /* support varibright */
+	PHM_PlatformCaps_PowerContainment,                      /* support DPM2 power containment (AKA TDP clamping) */
+	PHM_PlatformCaps_SQRamping,                             /* support DPM2 SQ power throttle */
+	PHM_PlatformCaps_CAC,                                   /* support Capacitance * Activity power estimation */
+	PHM_PlatformCaps_NIChipsets,                            /* Northern Island and beyond chipsets */
+	PHM_PlatformCaps_TrinityChipsets,                       /* Trinity chipset */
+	PHM_PlatformCaps_EvergreenChipsets,                     /* Evergreen family chipset */
+	PHM_PlatformCaps_PowerControl,                          /* Cayman and beyond chipsets */
+	PHM_PlatformCaps_DisableLSClockGating,                  /* to disable Light Sleep control for HDP memories */
+	PHM_PlatformCaps_BoostState,                            /* this ASIC supports boost state */
+	PHM_PlatformCaps_UserMaxClockForMultiDisplays,          /* indicates if max memory clock is used for all status when multiple displays are connected */
+	PHM_PlatformCaps_RegWriteDelay,                         /* indicates if back to back reg write delay is required */
+	PHM_PlatformCaps_NonABMSupportInPPLib,                  /* ABM is not supported in PPLIB, (moved from PPLIB to DAL) */
+	PHM_PlatformCaps_GFXDynamicMGPowerGating,               /* Enable Dynamic MG PowerGating on Trinity */
+	PHM_PlatformCaps_DisableSMUUVDHandshake,                /* Disable SMU UVD Handshake */
+	PHM_PlatformCaps_DTE,                                   /* Support Digital Temperature Estimation */
+	PHM_PlatformCaps_W5100Specifc_SmuSkipMsgDTE,            /* This is for the feature requested by David B., and Tonny W.*/
+	PHM_PlatformCaps_UVDPowerGating,                        /* enable UVD power gating, supported from Llano */
+	PHM_PlatformCaps_UVDDynamicPowerGating,                 /* enable UVD Dynamic power gating, supported from UVD5 */
+	PHM_PlatformCaps_VCEPowerGating,                        /* Enable VCE power gating, supported for TN and later ASICs */
+	PHM_PlatformCaps_SamuPowerGating,                       /* Enable SAMU power gating, supported for KV and later ASICs */
+	PHM_PlatformCaps_UVDDPM,                                /* UVD clock DPM */
+	PHM_PlatformCaps_VCEDPM,                                /* VCE clock DPM */
+	PHM_PlatformCaps_SamuDPM,                               /* SAMU clock DPM */
+	PHM_PlatformCaps_AcpDPM,                                /* ACP clock DPM */
+	PHM_PlatformCaps_SclkDeepSleepAboveLow,                 /* Enable SCLK Deep Sleep on all DPM states */
+	PHM_PlatformCaps_DynamicUVDState,                       /* Dynamic UVD State */
+	PHM_PlatformCaps_WantSAMClkWithDummyBackEnd,            /* Set SAM Clk With Dummy Back End */
+	PHM_PlatformCaps_WantUVDClkWithDummyBackEnd,            /* Set UVD Clk With Dummy Back End */
+	PHM_PlatformCaps_WantVCEClkWithDummyBackEnd,            /* Set VCE Clk With Dummy Back End */
+	PHM_PlatformCaps_WantACPClkWithDummyBackEnd,            /* Set SAM Clk With Dummy Back End */
+	PHM_PlatformCaps_OD6inACSupport,                        /* indicates that the ASIC/back end supports OD6 */
+	PHM_PlatformCaps_OD6inDCSupport,                        /* indicates that the ASIC/back end supports OD6 in DC */
+	PHM_PlatformCaps_EnablePlatformPowerManagement,         /* indicates that Platform Power Management feature is supported */
+	PHM_PlatformCaps_SurpriseRemoval,                       /* indicates that surprise removal feature is requested */
+	PHM_PlatformCaps_NewCACVoltage,                         /* indicates new CAC voltage table support */
+	PHM_PlatformCaps_DBRamping,                             /* for dI/dT feature */
+	PHM_PlatformCaps_TDRamping,                             /* for dI/dT feature */
+	PHM_PlatformCaps_TCPRamping,                            /* for dI/dT feature */
+	PHM_PlatformCaps_EnableSMU7ThermalManagement,           /* SMC will manage thermal events */
+	PHM_PlatformCaps_FPS,                                   /* FPS support */
+	PHM_PlatformCaps_ACP,                                   /* ACP support */
+	PHM_PlatformCaps_SclkThrottleLowNotification,           /* SCLK Throttle Low Notification */
+	PHM_PlatformCaps_XDMAEnabled,                           /* XDMA engine is enabled */
+	PHM_PlatformCaps_UseDummyBackEnd,                       /* use dummy back end */
+	PHM_PlatformCaps_EnableDFSBypass,                       /* Enable DFS bypass */
+	PHM_PlatformCaps_VddNBDirectRequest,
+	PHM_PlatformCaps_PauseMMSessions,
+	PHM_PlatformCaps_UnTabledHardwareInterface,             /* Tableless/direct call hardware interface for CI and newer ASICs */
+	PHM_PlatformCaps_SMU7,                                  /* indicates that vpuRecoveryBegin without SMU shutdown */
+	PHM_PlatformCaps_RevertGPIO5Polarity,                   /* indicates revert GPIO5 plarity table support */
+	PHM_PlatformCaps_Thermal2GPIO17,                        /* indicates thermal2GPIO17 table support */
+	PHM_PlatformCaps_ThermalOutGPIO,                        /* indicates ThermalOutGPIO support, pin number is assigned by VBIOS */
+	PHM_PlatformCaps_DisableMclkSwitchingForFrameLock,      /* Disable memory clock switch during Framelock */
+	PHM_PlatformCaps_VRHotGPIOConfigurable,                 /* indicates VR_HOT GPIO configurable */
+	PHM_PlatformCaps_TempInversion,                         /* enable Temp Inversion feature */
+	PHM_PlatformCaps_IOIC3,
+	PHM_PlatformCaps_ConnectedStandby,
+	PHM_PlatformCaps_EVV,
+	PHM_PlatformCaps_EnableLongIdleBACOSupport,
+	PHM_PlatformCaps_CombinePCCWithThermalSignal,
+	PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc,
+	PHM_PlatformCaps_StablePState,
+	PHM_PlatformCaps_OD6PlusinACSupport,
+	PHM_PlatformCaps_OD6PlusinDCSupport,
+	PHM_PlatformCaps_ODThermalLimitUnlock,
+	PHM_PlatformCaps_ReducePowerLimit,
+	PHM_PlatformCaps_ODFuzzyFanControlSupport,
+	PHM_PlatformCaps_GeminiRegulatorFanControlSupport,
+	PHM_PlatformCaps_ControlVDDGFX,
+	PHM_PlatformCaps_BBBSupported,
+	PHM_PlatformCaps_DisableVoltageIsland,
+	PHM_PlatformCaps_FanSpeedInTableIsRPM,
+	PHM_PlatformCaps_GFXClockGatingManagedInCAIL,
+	PHM_PlatformCaps_IcelandULPSSWWorkAround,
+	PHM_PlatformCaps_FPSEnhancement,
+	PHM_PlatformCaps_LoadPostProductionFirmware,
+	PHM_PlatformCaps_VpuRecoveryInProgress,
+	PHM_PlatformCaps_Falcon_QuickTransition,
+	PHM_PlatformCaps_AVFS,
+	PHM_PlatformCaps_ClockStretcher,
+	PHM_PlatformCaps_TablelessHardwareInterface,
+	PHM_PlatformCaps_EnableDriverEVV,
+	PHM_PlatformCaps_Max
+};
+
+#define PHM_MAX_NUM_CAPS_BITS_PER_FIELD (sizeof(uint32_t)*8)
+
+/* Number of uint32_t entries used by CAPS table */
+#define PHM_MAX_NUM_CAPS_ULONG_ENTRIES \
+	((PHM_PlatformCaps_Max + ((PHM_MAX_NUM_CAPS_BITS_PER_FIELD) - 1)) / (PHM_MAX_NUM_CAPS_BITS_PER_FIELD))
+
+struct pp_hw_descriptor {
+	uint32_t hw_caps[PHM_MAX_NUM_CAPS_ULONG_ENTRIES];
+};
+
+enum PHM_PerformanceLevelDesignation {
+	PHM_PerformanceLevelDesignation_Activity,
+	PHM_PerformanceLevelDesignation_PowerContainment
+};
+
+typedef enum PHM_PerformanceLevelDesignation PHM_PerformanceLevelDesignation;
+
+struct PHM_PerformanceLevel {
+    uint32_t    coreClock;
+    uint32_t    memory_clock;
+    uint32_t  vddc;
+    uint32_t  vddci;
+    uint32_t    nonLocalMemoryFreq;
+    uint32_t nonLocalMemoryWidth;
+};
+
+typedef struct PHM_PerformanceLevel PHM_PerformanceLevel;
+
+/* Function for setting a platform cap */
+static inline void phm_cap_set(uint32_t *caps,
+			enum phm_platform_caps c)
+{
+	caps[c / PHM_MAX_NUM_CAPS_BITS_PER_FIELD] |= (1UL <<
+			     (c & (PHM_MAX_NUM_CAPS_BITS_PER_FIELD - 1)));
+}
+
+static inline void phm_cap_unset(uint32_t *caps,
+			enum phm_platform_caps c)
+{
+	caps[c / PHM_MAX_NUM_CAPS_BITS_PER_FIELD] &= ~(1UL << (c & (PHM_MAX_NUM_CAPS_BITS_PER_FIELD - 1)));
+}
+
+static inline bool phm_cap_enabled(const uint32_t *caps, enum phm_platform_caps c)
+{
+	return (0 != (caps[c / PHM_MAX_NUM_CAPS_BITS_PER_FIELD] &
+		  (1UL << (c & (PHM_MAX_NUM_CAPS_BITS_PER_FIELD - 1)))));
+}
+
+#define PP_PCIEGenInvalid  0xffff
+enum PP_PCIEGen {
+    PP_PCIEGen1 = 0,                /* PCIE 1.0 - Transfer rate of 2.5 GT/s */
+    PP_PCIEGen2,                    /*PCIE 2.0 - Transfer rate of 5.0 GT/s */
+    PP_PCIEGen3                     /*PCIE 3.0 - Transfer rate of 8.0 GT/s */
+};
+
+typedef enum PP_PCIEGen PP_PCIEGen;
+
+#define PP_Min_PCIEGen     PP_PCIEGen1
+#define PP_Max_PCIEGen     PP_PCIEGen3
+#define PP_Min_PCIELane    1
+#define PP_Max_PCIELane    32
+
+enum phm_clock_Type {
+	PHM_DispClock = 1,
+	PHM_SClock,
+	PHM_MemClock
+};
+
+#define MAX_NUM_CLOCKS 16
+
+struct PP_Clocks {
+	uint32_t engineClock;
+	uint32_t memoryClock;
+	uint32_t BusBandwidth;
+	uint32_t engineClockInSR;
+};
+
+struct phm_platform_descriptor {
+	uint32_t platformCaps[PHM_MAX_NUM_CAPS_ULONG_ENTRIES];
+	uint32_t vbiosInterruptId;
+	struct PP_Clocks overdriveLimit;
+	struct PP_Clocks clockStep;
+	uint32_t hardwareActivityPerformanceLevels;
+	uint32_t minimumClocksReductionPercentage;
+	uint32_t minOverdriveVDDC;
+	uint32_t maxOverdriveVDDC;
+	uint32_t overdriveVDDCStep;
+	uint32_t hardwarePerformanceLevels;
+	uint16_t powerBudget;
+	uint32_t TDPLimit;
+	uint32_t nearTDPLimit;
+	uint32_t nearTDPLimitAdjusted;
+	uint32_t SQRampingThreshold;
+	uint32_t CACLeakage;
+	uint16_t TDPODLimit;
+	uint32_t TDPAdjustment;
+	bool TDPAdjustmentPolarity;
+	uint16_t LoadLineSlope;
+	uint32_t  VidMinLimit;
+	uint32_t  VidMaxLimit;
+	uint32_t  VidStep;
+	uint32_t  VidAdjustment;
+	bool VidAdjustmentPolarity;
+};
+
+struct phm_clocks {
+	uint32_t num_of_entries;
+	uint32_t clock[MAX_NUM_CLOCKS];
+};
+
+enum PP_DAL_POWERLEVEL {
+	PP_DAL_POWERLEVEL_INVALID = 0,
+	PP_DAL_POWERLEVEL_ULTRALOW,
+	PP_DAL_POWERLEVEL_LOW,
+	PP_DAL_POWERLEVEL_NOMINAL,
+	PP_DAL_POWERLEVEL_PERFORMANCE,
+
+	PP_DAL_POWERLEVEL_0 = PP_DAL_POWERLEVEL_ULTRALOW,
+	PP_DAL_POWERLEVEL_1 = PP_DAL_POWERLEVEL_LOW,
+	PP_DAL_POWERLEVEL_2 = PP_DAL_POWERLEVEL_NOMINAL,
+	PP_DAL_POWERLEVEL_3 = PP_DAL_POWERLEVEL_PERFORMANCE,
+	PP_DAL_POWERLEVEL_4 = PP_DAL_POWERLEVEL_3+1,
+	PP_DAL_POWERLEVEL_5 = PP_DAL_POWERLEVEL_4+1,
+	PP_DAL_POWERLEVEL_6 = PP_DAL_POWERLEVEL_5+1,
+	PP_DAL_POWERLEVEL_7 = PP_DAL_POWERLEVEL_6+1,
+};
+
+
+extern int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr);
+extern int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate);
+extern int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate);
+extern int phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
+extern int phm_setup_asic(struct pp_hwmgr *hwmgr);
+extern int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr);
+extern void phm_init_dynamic_caps(struct pp_hwmgr *hwmgr);
+extern bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr);
+extern int phm_block_hw_access(struct pp_hwmgr *hwmgr, bool block);
+extern int phm_set_power_state(struct pp_hwmgr *hwmgr,
+		    const struct pp_hw_power_state *pcurrent_state,
+		 const struct pp_hw_power_state *pnew_power_state);
+
+extern int phm_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+				   struct pp_power_state *adjusted_ps,
+			     const struct pp_power_state *current_ps);
+
+extern int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level);
+extern int phm_display_configuration_changed(struct pp_hwmgr *hwmgr);
+extern int phm_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr);
+extern int phm_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info);
+extern int phm_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *temperature_range);
+extern int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr);
+extern bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr);
+
+extern int phm_check_states_equal(struct pp_hwmgr *hwmgr,
+				 const struct pp_hw_power_state *pstate1,
+				 const struct pp_hw_power_state *pstate2,
+				 bool *equal);
+
+extern int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
+		const struct amd_pp_display_configuration *display_config);
+
+extern int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
+		struct amd_pp_dal_clock_info*info);
+
+extern int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr);
+
+extern int phm_power_down_asic(struct pp_hwmgr *hwmgr);
+
+#endif /* _HARDWARE_MANAGER_H_ */
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
@@ -0,0 +1,802 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _HWMGR_H_
+#define _HWMGR_H_
+
+#include <linux/errno.h>
+#include <linux/seq_file.h>
+#include "amd_powerplay.h"
+#include "pp_instance.h"
+#include "hardwaremanager.h"
+#include "pp_power_source.h"
+#include "hwmgr_ppt.h"
+#include "ppatomctrl.h"
+#include "hwmgr_ppt.h"
+
+struct pp_instance;
+struct pp_hwmgr;
+struct pp_hw_power_state;
+struct pp_power_state;
+struct PP_VCEState;
+struct phm_fan_speed_info;
+struct pp_atomctrl_voltage_table;
+
+
+enum DISPLAY_GAP {
+	DISPLAY_GAP_VBLANK_OR_WM = 0,   /* Wait for vblank or MCHG watermark. */
+	DISPLAY_GAP_VBLANK       = 1,   /* Wait for vblank. */
+	DISPLAY_GAP_WATERMARK    = 2,   /* Wait for MCHG watermark. (Note that HW may deassert WM in VBI depending on DC_STUTTER_CNTL.) */
+	DISPLAY_GAP_IGNORE       = 3    /* Do not wait. */
+};
+typedef enum DISPLAY_GAP DISPLAY_GAP;
+
+
+struct vi_dpm_level {
+	bool enabled;
+	uint32_t value;
+	uint32_t param1;
+};
+
+struct vi_dpm_table {
+	uint32_t count;
+	struct vi_dpm_level dpm_level[1];
+};
+
+enum PP_Result {
+	PP_Result_TableImmediateExit = 0x13,
+};
+
+#define PCIE_PERF_REQ_REMOVE_REGISTRY   0
+#define PCIE_PERF_REQ_FORCE_LOWPOWER    1
+#define PCIE_PERF_REQ_GEN1         2
+#define PCIE_PERF_REQ_GEN2         3
+#define PCIE_PERF_REQ_GEN3         4
+
+enum PHM_BackEnd_Magic {
+	PHM_Dummy_Magic       = 0xAA5555AA,
+	PHM_RV770_Magic       = 0xDCBAABCD,
+	PHM_Kong_Magic        = 0x239478DF,
+	PHM_NIslands_Magic    = 0x736C494E,
+	PHM_Sumo_Magic        = 0x8339FA11,
+	PHM_SIslands_Magic    = 0x369431AC,
+	PHM_Trinity_Magic     = 0x96751873,
+	PHM_CIslands_Magic    = 0x38AC78B0,
+	PHM_Kv_Magic          = 0xDCBBABC0,
+	PHM_VIslands_Magic    = 0x20130307,
+	PHM_Cz_Magic          = 0x67DCBA25
+};
+
+
+#define PHM_PCIE_POWERGATING_TARGET_GFX            0
+#define PHM_PCIE_POWERGATING_TARGET_DDI            1
+#define PHM_PCIE_POWERGATING_TARGET_PLLCASCADE     2
+#define PHM_PCIE_POWERGATING_TARGET_PHY            3
+
+typedef int (*phm_table_function)(struct pp_hwmgr *hwmgr, void *input,
+				  void *output, void *storage, int result);
+
+typedef bool (*phm_check_function)(struct pp_hwmgr *hwmgr);
+
+struct phm_set_power_state_input {
+	const struct pp_hw_power_state *pcurrent_state;
+	const struct pp_hw_power_state *pnew_state;
+};
+
+struct phm_acp_arbiter {
+	uint32_t acpclk;
+};
+
+struct phm_uvd_arbiter {
+	uint32_t vclk;
+	uint32_t dclk;
+	uint32_t vclk_ceiling;
+	uint32_t dclk_ceiling;
+};
+
+struct phm_vce_arbiter {
+	uint32_t   evclk;
+	uint32_t   ecclk;
+};
+
+struct phm_gfx_arbiter {
+	uint32_t sclk;
+	uint32_t mclk;
+	uint32_t sclk_over_drive;
+	uint32_t mclk_over_drive;
+	uint32_t sclk_threshold;
+	uint32_t num_cus;
+};
+
+/* Entries in the master tables */
+struct phm_master_table_item {
+	phm_check_function isFunctionNeededInRuntimeTable;
+	phm_table_function tableFunction;
+};
+
+enum phm_master_table_flag {
+	PHM_MasterTableFlag_None         = 0,
+	PHM_MasterTableFlag_ExitOnError  = 1,
+};
+
+/* The header of the master tables */
+struct phm_master_table_header {
+	uint32_t storage_size;
+	uint32_t flags;
+	struct phm_master_table_item *master_list;
+};
+
+struct phm_runtime_table_header {
+	uint32_t storage_size;
+	bool exit_error;
+	phm_table_function *function_list;
+};
+
+struct phm_clock_array {
+	uint32_t count;
+	uint32_t values[1];
+};
+
+struct phm_clock_voltage_dependency_record {
+	uint32_t clk;
+	uint32_t v;
+};
+
+struct phm_vceclock_voltage_dependency_record {
+	uint32_t ecclk;
+	uint32_t evclk;
+	uint32_t v;
+};
+
+struct phm_uvdclock_voltage_dependency_record {
+	uint32_t vclk;
+	uint32_t dclk;
+	uint32_t v;
+};
+
+struct phm_samuclock_voltage_dependency_record {
+	uint32_t samclk;
+	uint32_t v;
+};
+
+struct phm_acpclock_voltage_dependency_record {
+	uint32_t acpclk;
+	uint32_t v;
+};
+
+struct phm_clock_voltage_dependency_table {
+	uint32_t count;										/* Number of entries. */
+	struct phm_clock_voltage_dependency_record entries[1];		/* Dynamically allocate count entries. */
+};
+
+struct phm_phase_shedding_limits_record {
+	uint32_t  Voltage;
+	uint32_t    Sclk;
+	uint32_t    Mclk;
+};
+
+
+extern int phm_dispatch_table(struct pp_hwmgr *hwmgr,
+			      struct phm_runtime_table_header *rt_table,
+			      void *input, void *output);
+
+extern int phm_construct_table(struct pp_hwmgr *hwmgr,
+			       struct phm_master_table_header *master_table,
+			       struct phm_runtime_table_header *rt_table);
+
+extern int phm_destroy_table(struct pp_hwmgr *hwmgr,
+			     struct phm_runtime_table_header *rt_table);
+
+
+struct phm_uvd_clock_voltage_dependency_record {
+	uint32_t vclk;
+	uint32_t dclk;
+	uint32_t v;
+};
+
+struct phm_uvd_clock_voltage_dependency_table {
+	uint8_t count;
+	struct phm_uvd_clock_voltage_dependency_record entries[1];
+};
+
+struct phm_acp_clock_voltage_dependency_record {
+	uint32_t acpclk;
+	uint32_t v;
+};
+
+struct phm_acp_clock_voltage_dependency_table {
+	uint32_t count;
+	struct phm_acp_clock_voltage_dependency_record entries[1];
+};
+
+struct phm_vce_clock_voltage_dependency_record {
+	uint32_t ecclk;
+	uint32_t evclk;
+	uint32_t v;
+};
+
+struct phm_phase_shedding_limits_table {
+	uint32_t                           count;
+	struct phm_phase_shedding_limits_record  entries[1];
+};
+
+struct phm_vceclock_voltage_dependency_table {
+	uint8_t count;                                    /* Number of entries. */
+	struct phm_vceclock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_uvdclock_voltage_dependency_table {
+	uint8_t count;                                    /* Number of entries. */
+	struct phm_uvdclock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_samuclock_voltage_dependency_table {
+	uint8_t count;                                    /* Number of entries. */
+	struct phm_samuclock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_acpclock_voltage_dependency_table {
+	uint32_t count;                                    /* Number of entries. */
+	struct phm_acpclock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_vce_clock_voltage_dependency_table {
+	uint8_t count;
+	struct phm_vce_clock_voltage_dependency_record entries[1];
+};
+
+struct pp_hwmgr_func {
+	int (*backend_init)(struct pp_hwmgr *hw_mgr);
+	int (*backend_fini)(struct pp_hwmgr *hw_mgr);
+	int (*asic_setup)(struct pp_hwmgr *hw_mgr);
+	int (*get_power_state_size)(struct pp_hwmgr *hw_mgr);
+
+	int (*apply_state_adjust_rules)(struct pp_hwmgr *hwmgr,
+				struct pp_power_state  *prequest_ps,
+			const struct pp_power_state *pcurrent_ps);
+
+	int (*force_dpm_level)(struct pp_hwmgr *hw_mgr,
+					enum amd_dpm_forced_level level);
+
+	int (*dynamic_state_management_enable)(
+						struct pp_hwmgr *hw_mgr);
+
+	int (*patch_boot_state)(struct pp_hwmgr *hwmgr,
+				     struct pp_hw_power_state *hw_ps);
+
+	int (*get_pp_table_entry)(struct pp_hwmgr *hwmgr,
+			    unsigned long, struct pp_power_state *);
+	int (*get_num_of_pp_table_entries)(struct pp_hwmgr *hwmgr);
+	int (*powerdown_uvd)(struct pp_hwmgr *hwmgr);
+	int (*powergate_vce)(struct pp_hwmgr *hwmgr, bool bgate);
+	int (*powergate_uvd)(struct pp_hwmgr *hwmgr, bool bgate);
+	int (*get_mclk)(struct pp_hwmgr *hwmgr, bool low);
+	int (*get_sclk)(struct pp_hwmgr *hwmgr, bool low);
+	int (*power_state_set)(struct pp_hwmgr *hwmgr,
+						const void *state);
+	void (*print_current_perforce_level)(struct pp_hwmgr *hwmgr,
+							struct seq_file *m);
+	int (*enable_clock_power_gating)(struct pp_hwmgr *hwmgr);
+	int (*notify_smc_display_config_after_ps_adjustment)(struct pp_hwmgr *hwmgr);
+	int (*display_config_changed)(struct pp_hwmgr *hwmgr);
+	int (*disable_clock_power_gating)(struct pp_hwmgr *hwmgr);
+	int (*update_clock_gatings)(struct pp_hwmgr *hwmgr,
+						const uint32_t *msg_id);
+	int (*set_max_fan_rpm_output)(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm);
+	int (*set_max_fan_pwm_output)(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm);
+	int (*get_temperature)(struct pp_hwmgr *hwmgr);
+	int (*stop_thermal_controller)(struct pp_hwmgr *hwmgr);
+	int (*get_fan_speed_info)(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
+	int (*set_fan_control_mode)(struct pp_hwmgr *hwmgr, uint32_t mode);
+	int (*get_fan_control_mode)(struct pp_hwmgr *hwmgr);
+	int (*set_fan_speed_percent)(struct pp_hwmgr *hwmgr, uint32_t percent);
+	int (*get_fan_speed_percent)(struct pp_hwmgr *hwmgr, uint32_t *speed);
+	int (*set_fan_speed_rpm)(struct pp_hwmgr *hwmgr, uint32_t percent);
+	int (*get_fan_speed_rpm)(struct pp_hwmgr *hwmgr, uint32_t *speed);
+	int (*reset_fan_speed_to_default)(struct pp_hwmgr *hwmgr);
+	int (*uninitialize_thermal_controller)(struct pp_hwmgr *hwmgr);
+	int (*register_internal_thermal_interrupt)(struct pp_hwmgr *hwmgr,
+					const void *thermal_interrupt_info);
+	bool (*check_smc_update_required_for_display_configuration)(struct pp_hwmgr *hwmgr);
+	int (*check_states_equal)(struct pp_hwmgr *hwmgr,
+					const struct pp_hw_power_state *pstate1,
+					const struct pp_hw_power_state *pstate2,
+					bool *equal);
+	int (*set_cpu_power_state)(struct pp_hwmgr *hwmgr);
+	int (*store_cc6_data)(struct pp_hwmgr *hwmgr, uint32_t separation_time,
+				bool cc6_disable, bool pstate_disable,
+				bool pstate_switch_disable);
+	int (*get_dal_power_level)(struct pp_hwmgr *hwmgr,
+				   struct amd_pp_dal_clock_info *info);
+	int (*power_off_asic)(struct pp_hwmgr *hwmgr);
+};
+
+struct pp_table_func {
+	int (*pptable_init)(struct pp_hwmgr *hw_mgr);
+	int (*pptable_fini)(struct pp_hwmgr *hw_mgr);
+	int (*pptable_get_number_of_vce_state_table_entries)(struct pp_hwmgr *hw_mgr);
+	int (*pptable_get_vce_state_table_entry)(
+						struct pp_hwmgr *hwmgr,
+						unsigned long i,
+						struct PP_VCEState *vce_state,
+						void **clock_info,
+						unsigned long *flag);
+};
+
+union phm_cac_leakage_record {
+	struct {
+		uint16_t Vddc;          /* in CI, we use it for StdVoltageHiSidd */
+		uint32_t Leakage;       /* in CI, we use it for StdVoltageLoSidd */
+	};
+	struct {
+		uint16_t Vddc1;
+		uint16_t Vddc2;
+		uint16_t Vddc3;
+	};
+};
+
+struct phm_cac_leakage_table {
+	uint32_t count;
+	union phm_cac_leakage_record entries[1];
+};
+
+struct phm_samu_clock_voltage_dependency_record {
+	uint32_t samclk;
+	uint32_t v;
+};
+
+
+struct phm_samu_clock_voltage_dependency_table {
+	uint8_t count;
+	struct phm_samu_clock_voltage_dependency_record entries[1];
+};
+
+struct phm_cac_tdp_table {
+	uint16_t usTDP;
+	uint16_t usConfigurableTDP;
+	uint16_t usTDC;
+	uint16_t usBatteryPowerLimit;
+	uint16_t usSmallPowerLimit;
+	uint16_t usLowCACLeakage;
+	uint16_t usHighCACLeakage;
+	uint16_t usMaximumPowerDeliveryLimit;
+	uint16_t usOperatingTempMinLimit;
+	uint16_t usOperatingTempMaxLimit;
+	uint16_t usOperatingTempStep;
+	uint16_t usOperatingTempHyst;
+	uint16_t usDefaultTargetOperatingTemp;
+	uint16_t usTargetOperatingTemp;
+	uint16_t usPowerTuneDataSetID;
+	uint16_t usSoftwareShutdownTemp;
+	uint16_t usClockStretchAmount;
+	uint16_t usTemperatureLimitHotspot;
+	uint16_t usTemperatureLimitLiquid1;
+	uint16_t usTemperatureLimitLiquid2;
+	uint16_t usTemperatureLimitVrVddc;
+	uint16_t usTemperatureLimitVrMvdd;
+	uint16_t usTemperatureLimitPlx;
+	uint8_t  ucLiquid1_I2C_address;
+	uint8_t  ucLiquid2_I2C_address;
+	uint8_t  ucLiquid_I2C_Line;
+	uint8_t  ucVr_I2C_address;
+	uint8_t  ucVr_I2C_Line;
+	uint8_t  ucPlx_I2C_address;
+	uint8_t  ucPlx_I2C_Line;
+};
+
+struct phm_ppm_table {
+	uint8_t   ppm_design;
+	uint16_t  cpu_core_number;
+	uint32_t  platform_tdp;
+	uint32_t  small_ac_platform_tdp;
+	uint32_t  platform_tdc;
+	uint32_t  small_ac_platform_tdc;
+	uint32_t  apu_tdp;
+	uint32_t  dgpu_tdp;
+	uint32_t  dgpu_ulv_power;
+	uint32_t  tj_max;
+};
+
+struct phm_vq_budgeting_record {
+	uint32_t ulCUs;
+	uint32_t ulSustainableSOCPowerLimitLow;
+	uint32_t ulSustainableSOCPowerLimitHigh;
+	uint32_t ulMinSclkLow;
+	uint32_t ulMinSclkHigh;
+	uint8_t  ucDispConfig;
+	uint32_t ulDClk;
+	uint32_t ulEClk;
+	uint32_t ulSustainableSclk;
+	uint32_t ulSustainableCUs;
+};
+
+struct phm_vq_budgeting_table {
+	uint8_t numEntries;
+	struct phm_vq_budgeting_record entries[1];
+};
+
+struct phm_clock_and_voltage_limits {
+	uint32_t sclk;
+	uint32_t mclk;
+	uint16_t vddc;
+	uint16_t vddci;
+	uint16_t vddgfx;
+};
+
+/* Structure to hold PPTable information */
+
+struct phm_ppt_v1_information {
+	struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_on_sclk;
+	struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_on_mclk;
+	struct phm_clock_array *valid_sclk_values;
+	struct phm_clock_array *valid_mclk_values;
+	struct phm_clock_and_voltage_limits max_clock_voltage_on_dc;
+	struct phm_clock_and_voltage_limits max_clock_voltage_on_ac;
+	struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
+	struct phm_ppm_table *ppm_parameter_table;
+	struct phm_cac_tdp_table *cac_dtp_table;
+	struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_dep_table;
+	struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table;
+	struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table;
+	struct phm_ppt_v1_pcie_table *pcie_table;
+	uint16_t us_ulv_voltage_offset;
+};
+
+struct phm_dynamic_state_info {
+	struct phm_clock_voltage_dependency_table *vddc_dependency_on_sclk;
+	struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk;
+	struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk;
+	struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk;
+	struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
+	struct phm_clock_array                    *valid_sclk_values;
+	struct phm_clock_array                    *valid_mclk_values;
+	struct phm_clock_and_voltage_limits       max_clock_voltage_on_dc;
+	struct phm_clock_and_voltage_limits       max_clock_voltage_on_ac;
+	uint32_t                                  mclk_sclk_ratio;
+	uint32_t                                  sclk_mclk_delta;
+	uint32_t                                  vddc_vddci_delta;
+	uint32_t                                  min_vddc_for_pcie_gen2;
+	struct phm_cac_leakage_table              *cac_leakage_table;
+	struct phm_phase_shedding_limits_table	  *vddc_phase_shed_limits_table;
+
+	struct phm_vce_clock_voltage_dependency_table
+					    *vce_clock_voltage_dependency_table;
+	struct phm_uvd_clock_voltage_dependency_table
+					    *uvd_clock_voltage_dependency_table;
+	struct phm_acp_clock_voltage_dependency_table
+					    *acp_clock_voltage_dependency_table;
+	struct phm_samu_clock_voltage_dependency_table
+					   *samu_clock_voltage_dependency_table;
+
+	struct phm_ppm_table                          *ppm_parameter_table;
+	struct phm_cac_tdp_table                      *cac_dtp_table;
+	struct phm_clock_voltage_dependency_table	  *vdd_gfx_dependency_on_sclk;
+	struct phm_vq_budgeting_table		  		  *vq_budgeting_table;
+};
+
+struct pp_fan_info {
+	bool bNoFan;
+	uint8_t   ucTachometerPulsesPerRevolution;
+	uint32_t   ulMinRPM;
+	uint32_t   ulMaxRPM;
+};
+
+struct pp_advance_fan_control_parameters {
+	uint16_t  usTMin;                          /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
+	uint16_t  usTMed;                          /* The middle temperature where we change slopes. */
+	uint16_t  usTHigh;                         /* The high temperature for setting the second slope. */
+	uint16_t  usPWMMin;                        /* The minimum PWM value in percent (0.01% increments). */
+	uint16_t  usPWMMed;                        /* The PWM value (in percent) at TMed. */
+	uint16_t  usPWMHigh;                       /* The PWM value at THigh. */
+	uint8_t   ucTHyst;                         /* Temperature hysteresis. Integer. */
+	uint32_t   ulCycleDelay;                   /* The time between two invocations of the fan control routine in microseconds. */
+	uint16_t  usTMax;                          /* The max temperature */
+	uint8_t   ucFanControlMode;
+	uint16_t  usFanPWMMinLimit;
+	uint16_t  usFanPWMMaxLimit;
+	uint16_t  usFanPWMStep;
+	uint16_t  usDefaultMaxFanPWM;
+	uint16_t  usFanOutputSensitivity;
+	uint16_t  usDefaultFanOutputSensitivity;
+	uint16_t  usMaxFanPWM;                     /* The max Fan PWM value for Fuzzy Fan Control feature */
+	uint16_t  usFanRPMMinLimit;                /* Minimum limit range in percentage, need to calculate based on minRPM/MaxRpm */
+	uint16_t  usFanRPMMaxLimit;                /* Maximum limit range in percentage, usually set to 100% by default */
+	uint16_t  usFanRPMStep;                    /* Step increments/decerements, in percent */
+	uint16_t  usDefaultMaxFanRPM;              /* The max Fan RPM value for Fuzzy Fan Control feature, default from PPTable */
+	uint16_t  usMaxFanRPM;                     /* The max Fan RPM value for Fuzzy Fan Control feature, user defined */
+	uint16_t  usFanCurrentLow;                 /* Low current */
+	uint16_t  usFanCurrentHigh;                /* High current */
+	uint16_t  usFanRPMLow;                     /* Low RPM */
+	uint16_t  usFanRPMHigh;                    /* High RPM */
+	uint32_t   ulMinFanSCLKAcousticLimit;      /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
+	uint8_t   ucTargetTemperature;             /* Advanced fan controller target temperature. */
+	uint8_t   ucMinimumPWMLimit;               /* The minimum PWM that the advanced fan controller can set.  This should be set to the highest PWM that will run the fan at its lowest RPM. */
+	uint16_t  usFanGainEdge;                   /* The following is added for Fiji */
+	uint16_t  usFanGainHotspot;
+	uint16_t  usFanGainLiquid;
+	uint16_t  usFanGainVrVddc;
+	uint16_t  usFanGainVrMvdd;
+	uint16_t  usFanGainPlx;
+	uint16_t  usFanGainHbm;
+};
+
+struct pp_thermal_controller_info {
+	uint8_t ucType;
+	uint8_t ucI2cLine;
+	uint8_t ucI2cAddress;
+	struct pp_fan_info fanInfo;
+	struct pp_advance_fan_control_parameters advanceFanControlParameters;
+};
+
+struct phm_microcode_version_info {
+	uint32_t SMC;
+	uint32_t DMCU;
+	uint32_t MC;
+	uint32_t NB;
+};
+
+/**
+ * The main hardware manager structure.
+ */
+struct pp_hwmgr {
+	uint32_t chip_family;
+	uint32_t chip_id;
+	uint32_t hw_revision;
+	uint32_t sub_sys_id;
+	uint32_t sub_vendor_id;
+
+	void *device;
+	struct pp_smumgr *smumgr;
+	const void *soft_pp_table;
+	bool need_pp_table_upload;
+	enum amd_dpm_forced_level dpm_level;
+	bool block_hw_access;
+	struct phm_gfx_arbiter gfx_arbiter;
+	struct phm_acp_arbiter acp_arbiter;
+	struct phm_uvd_arbiter uvd_arbiter;
+	struct phm_vce_arbiter vce_arbiter;
+	uint32_t usec_timeout;
+	void *pptable;
+	struct phm_platform_descriptor platform_descriptor;
+	void *backend;
+	enum PP_DAL_POWERLEVEL dal_power_level;
+	struct phm_dynamic_state_info dyn_state;
+	struct phm_runtime_table_header setup_asic;
+	struct phm_runtime_table_header power_down_asic;
+	struct phm_runtime_table_header disable_dynamic_state_management;
+	struct phm_runtime_table_header enable_dynamic_state_management;
+	struct phm_runtime_table_header set_power_state;
+	struct phm_runtime_table_header enable_clock_power_gatings;
+	struct phm_runtime_table_header display_configuration_changed;
+	struct phm_runtime_table_header start_thermal_controller;
+	struct phm_runtime_table_header set_temperature_range;
+	const struct pp_hwmgr_func *hwmgr_func;
+	const struct pp_table_func *pptable_func;
+	struct pp_power_state    *ps;
+	enum pp_power_source  power_source;
+	uint32_t num_ps;
+	struct pp_thermal_controller_info thermal_controller;
+	bool fan_ctrl_is_in_default_mode;
+	uint32_t fan_ctrl_default_mode;
+	uint32_t tmin;
+	struct phm_microcode_version_info microcode_version_info;
+	uint32_t ps_size;
+	struct pp_power_state    *current_ps;
+	struct pp_power_state    *request_ps;
+	struct pp_power_state    *boot_ps;
+	struct pp_power_state    *uvd_ps;
+	struct amd_pp_display_configuration display_config;
+};
+
+
+extern int hwmgr_init(struct amd_pp_init *pp_init,
+		      struct pp_instance *handle);
+
+extern int hwmgr_fini(struct pp_hwmgr *hwmgr);
+
+extern int hw_init_power_state_table(struct pp_hwmgr *hwmgr);
+
+extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
+				uint32_t value, uint32_t mask);
+
+extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
+				uint32_t index, uint32_t value, uint32_t mask);
+
+extern uint32_t phm_read_indirect_register(struct pp_hwmgr *hwmgr,
+		uint32_t indirect_port, uint32_t index);
+
+extern void phm_write_indirect_register(struct pp_hwmgr *hwmgr,
+		uint32_t indirect_port,
+		uint32_t index,
+		uint32_t value);
+
+extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
+				uint32_t indirect_port,
+				uint32_t index,
+				uint32_t value,
+				uint32_t mask);
+
+extern void phm_wait_for_indirect_register_unequal(
+				struct pp_hwmgr *hwmgr,
+				uint32_t indirect_port,
+				uint32_t index,
+				uint32_t value,
+				uint32_t mask);
+
+extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr);
+extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr);
+extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr);
+
+extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table);
+extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table);
+extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table);
+extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table);
+extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table);
+extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max);
+extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes);
+extern int32_t phm_get_dpm_level_enable_mask_value(void *table);
+extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage);
+extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci);
+extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level);
+extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table,
+								uint16_t virtual_voltage_id, int32_t *sclk);
+extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
+extern int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr);
+extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask);
+
+
+#define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU
+
+#define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
+#define PHM_FIELD_MASK(reg, field) reg##__##field##_MASK
+
+#define PHM_SET_FIELD(origval, reg, field, fieldval)	\
+	(((origval) & ~PHM_FIELD_MASK(reg, field)) |	\
+	 (PHM_FIELD_MASK(reg, field) & ((fieldval) << PHM_FIELD_SHIFT(reg, field))))
+
+#define PHM_GET_FIELD(value, reg, field)	\
+	(((value) & PHM_FIELD_MASK(reg, field)) >>	\
+	 PHM_FIELD_SHIFT(reg, field))
+
+
+#define PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, index, value, mask)	\
+	phm_wait_on_register(hwmgr, index, value, mask)
+
+#define PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, index, value, mask)	\
+	phm_wait_for_register_unequal(hwmgr, index, value, mask)
+
+#define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask)	\
+	phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask)
+
+#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask)	\
+	phm_wait_for_indirect_register_unequal(hwmgr, mm##port##_INDEX, index, value, mask)
+
+#define PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask)	\
+	phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX_0, index, value, mask)
+
+#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask)	\
+	phm_wait_for_indirect_register_unequal(hwmgr, mm##port##_INDEX_0, index, value, mask)
+
+/* Operations on named registers. */
+
+#define PHM_WAIT_REGISTER(hwmgr, reg, value, mask)	\
+	PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg, value, mask)
+
+#define PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, value, mask)	\
+	PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg, value, mask)
+
+#define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask)	\
+	PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
+
+#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask)	\
+	PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
+
+#define PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, value, mask)	\
+	PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
+
+#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask)	\
+	PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
+
+/* Operations on named fields. */
+
+#define PHM_READ_FIELD(device, reg, field)	\
+	PHM_GET_FIELD(cgs_read_register(device, mm##reg), reg, field)
+
+#define PHM_READ_INDIRECT_FIELD(device, port, reg, field)	\
+	PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg),	\
+			reg, field)
+
+#define PHM_READ_VFPF_INDIRECT_FIELD(device, port, reg, field)	\
+	PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg),	\
+			reg, field)
+
+#define PHM_WRITE_FIELD(device, reg, field, fieldval)	\
+	cgs_write_register(device, mm##reg, PHM_SET_FIELD(	\
+				cgs_read_register(device, mm##reg), reg, field, fieldval))
+
+#define PHM_WRITE_INDIRECT_FIELD(device, port, reg, field, fieldval)	\
+	cgs_write_ind_register(device, port, ix##reg,	\
+			PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg),	\
+				reg, field, fieldval))
+
+#define PHM_WRITE_VFPF_INDIRECT_FIELD(device, port, reg, field, fieldval)	\
+	cgs_write_ind_register(device, port, ix##reg,	\
+			PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg),	\
+				reg, field, fieldval))
+
+#define PHM_WAIT_FIELD(hwmgr, reg, field, fieldval)	\
+	PHM_WAIT_REGISTER(hwmgr, reg, (fieldval)	\
+			<< PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval)	\
+	PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval)	\
+			<< PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval)	\
+	PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval)	\
+			<< PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_FIELD_UNEQUAL(hwmgr, reg, field, fieldval)	\
+	PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, (fieldval)	\
+			<< PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval)	\
+	PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, (fieldval)	\
+			<< PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval)	\
+	PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, (fieldval)	\
+			<< PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+/* Operations on arrays of registers & fields. */
+
+#define PHM_READ_ARRAY_REGISTER(device, reg, offset)	\
+	cgs_read_register(device, mm##reg + (offset))
+
+#define PHM_WRITE_ARRAY_REGISTER(device, reg, offset, value)	\
+	cgs_write_register(device, mm##reg + (offset), value)
+
+#define PHM_WAIT_ARRAY_REGISTER(hwmgr, reg, offset, value, mask)	\
+	PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg + (offset), value, mask)
+
+#define PHM_WAIT_ARRAY_REGISTER_UNEQUAL(hwmgr, reg, offset, value, mask)	\
+	PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg + (offset), value, mask)
+
+#define PHM_READ_ARRAY_FIELD(hwmgr, reg, offset, field) \
+	PHM_GET_FIELD(PHM_READ_ARRAY_REGISTER(hwmgr->device, reg, offset), reg, field)
+
+#define PHM_WRITE_ARRAY_FIELD(hwmgr, reg, offset, field, fieldvalue)	\
+	PHM_WRITE_ARRAY_REGISTER(hwmgr->device, reg, offset,	\
+			PHM_SET_FIELD(PHM_READ_ARRAY_REGISTER(hwmgr->device, reg, offset),	\
+				reg, field, fieldvalue))
+
+#define PHM_WAIT_ARRAY_FIELD(hwmgr, reg, offset, field, fieldvalue)	\
+	PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg + (offset),	\
+			(fieldvalue) << PHM_FIELD_SHIFT(reg, field),	\
+			PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_ARRAY_FIELD_UNEQUAL(hwmgr, reg, offset, field, fieldvalue)	\
+	PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg + (offset),	\
+			(fieldvalue) << PHM_FIELD_SHIFT(reg, field),	\
+			PHM_FIELD_MASK(reg, field))
+
+#endif /* _HWMGR_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/power_state.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/power_state.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef PP_POWERSTATE_H
+#define PP_POWERSTATE_H
+
+struct pp_hw_power_state {
+	unsigned int magic;
+};
+
+struct pp_power_state;
+
+
+#define PP_INVALID_POWER_STATE_ID (0)
+
+
+/*
+ * An item of a list containing Power States.
+ */
+
+struct PP_StateLinkedList {
+	struct pp_power_state *next;
+	struct pp_power_state *prev;
+};
+
+
+enum PP_StateUILabel {
+	PP_StateUILabel_None,
+	PP_StateUILabel_Battery,
+	PP_StateUILabel_MiddleLow,
+	PP_StateUILabel_Balanced,
+	PP_StateUILabel_MiddleHigh,
+	PP_StateUILabel_Performance,
+	PP_StateUILabel_BACO
+};
+
+enum PP_StateClassificationFlag {
+	PP_StateClassificationFlag_Boot                = 0x0001,
+	PP_StateClassificationFlag_Thermal             = 0x0002,
+	PP_StateClassificationFlag_LimitedPowerSource  = 0x0004,
+	PP_StateClassificationFlag_Rest                = 0x0008,
+	PP_StateClassificationFlag_Forced              = 0x0010,
+	PP_StateClassificationFlag_User3DPerformance   = 0x0020,
+	PP_StateClassificationFlag_User2DPerformance   = 0x0040,
+	PP_StateClassificationFlag_3DPerformance       = 0x0080,
+	PP_StateClassificationFlag_ACOverdriveTemplate   = 0x0100,
+	PP_StateClassificationFlag_Uvd                 = 0x0200,
+	PP_StateClassificationFlag_3DPerformanceLow    = 0x0400,
+	PP_StateClassificationFlag_ACPI                = 0x0800,
+	PP_StateClassificationFlag_HD2                 = 0x1000,
+	PP_StateClassificationFlag_UvdHD               = 0x2000,
+	PP_StateClassificationFlag_UvdSD               = 0x4000,
+	PP_StateClassificationFlag_UserDCPerformance    = 0x8000,
+	PP_StateClassificationFlag_DCOverdriveTemplate   = 0x10000,
+	PP_StateClassificationFlag_BACO                  = 0x20000,
+	PP_StateClassificationFlag_LimitedPowerSource_2  = 0x40000,
+	PP_StateClassificationFlag_ULV                   = 0x80000,
+	PP_StateClassificationFlag_UvdMVC               = 0x100000,
+};
+
+typedef unsigned int PP_StateClassificationFlags;
+
+struct PP_StateClassificationBlock {
+	enum PP_StateUILabel         ui_label;
+	enum PP_StateClassificationFlag  flags;
+	int                          bios_index;
+	bool                      temporary_state;
+	bool                      to_be_deleted;
+};
+
+struct PP_StatePcieBlock {
+	unsigned int lanes;
+};
+
+enum PP_RefreshrateSource {
+	PP_RefreshrateSource_EDID,
+	PP_RefreshrateSource_Explicit
+};
+
+struct PP_StateDisplayBlock {
+	bool              disableFrameModulation;
+	bool              limitRefreshrate;
+	enum PP_RefreshrateSource refreshrateSource;
+	int                  explicitRefreshrate;
+	int                  edidRefreshrateIndex;
+	bool              enableVariBright;
+};
+
+struct PP_StateMemroyBlock {
+	bool              dllOff;
+	uint8_t                 m3arb;
+	uint8_t                 unused[3];
+};
+
+struct PP_StateSoftwareAlgorithmBlock {
+	bool disableLoadBalancing;
+	bool enableSleepForTimestamps;
+};
+
+#define PP_TEMPERATURE_UNITS_PER_CENTIGRADES 1000
+
+/**
+ * Type to hold a temperature range.
+ */
+struct PP_TemperatureRange {
+	uint32_t min;
+	uint32_t max;
+};
+
+struct PP_StateValidationBlock {
+	bool singleDisplayOnly;
+	bool disallowOnDC;
+	uint8_t supportedPowerLevels;
+};
+
+struct PP_UVD_CLOCKS {
+	uint32_t VCLK;
+	uint32_t DCLK;
+};
+
+/**
+* Structure to hold a PowerPlay Power State.
+*/
+struct pp_power_state {
+	uint32_t                            id;
+	struct PP_StateLinkedList                  orderedList;
+	struct PP_StateLinkedList                  allStatesList;
+
+	struct PP_StateClassificationBlock         classification;
+	struct PP_StateValidationBlock             validation;
+	struct PP_StatePcieBlock                   pcie;
+	struct PP_StateDisplayBlock                display;
+	struct PP_StateMemroyBlock                 memory;
+	struct PP_TemperatureRange                 temperatures;
+	struct PP_StateSoftwareAlgorithmBlock      software;
+	struct PP_UVD_CLOCKS                       uvd_clocks;
+	struct pp_hw_power_state  hardware;
+};
+
+
+/*Structure to hold a VCE state entry*/
+struct PP_VCEState {
+	uint32_t evclk;
+	uint32_t ecclk;
+	uint32_t sclk;
+	uint32_t mclk;
+};
+
+enum PP_MMProfilingState {
+	PP_MMProfilingState_NA = 0,
+	PP_MMProfilingState_Started,
+	PP_MMProfilingState_Stopped
+};
+
+struct PP_Clock_Engine_Request {
+	unsigned long clientType;
+	unsigned long ctxid;
+	uint64_t  context_handle;
+	unsigned long sclk;
+	unsigned long sclkHardMin;
+	unsigned long mclk;
+	unsigned long iclk;
+	unsigned long evclk;
+	unsigned long ecclk;
+	unsigned long ecclkHardMin;
+	unsigned long vclk;
+	unsigned long dclk;
+	unsigned long samclk;
+	unsigned long acpclk;
+	unsigned long sclkOverdrive;
+	unsigned long mclkOverdrive;
+	unsigned long sclk_threshold;
+	unsigned long flag;
+	unsigned long vclk_ceiling;
+	unsigned long dclk_ceiling;
+	unsigned long num_cus;
+	unsigned long pmflag;
+	enum PP_MMProfilingState MMProfilingState;
+};
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+extern bool acpi_atcs_functions_supported(void *device,
+							uint32_t index);
+extern int acpi_pcie_perf_request(void *device,
+						uint8_t perf_req,
+						bool advertise);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/pp_asicblocks.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/pp_asicblocks.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef PP_ASICBLOCKS_H
+#define PP_ASICBLOCKS_H
+
+
+enum PHM_AsicBlock {
+	PHM_AsicBlock_GFX,
+	PHM_AsicBlock_UVD_MVC,
+	PHM_AsicBlock_UVD,
+	PHM_AsicBlock_UVD_HD,
+	PHM_AsicBlock_UVD_SD,
+	PHM_AsicBlock_Count
+};
+
+enum PHM_ClockGateSetting {
+	PHM_ClockGateSetting_StaticOn,
+	PHM_ClockGateSetting_StaticOff,
+	PHM_ClockGateSetting_Dynamic
+};
+
+struct phm_asic_blocks {
+	bool gfx : 1;
+	bool uvd : 1;
+};
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h
@@ -0,0 +1,47 @@
+
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef PP_DEBUG_H
+#define PP_DEBUG_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#define PP_ASSERT_WITH_CODE(cond, msg, code)	\
+	do {					\
+		if (!(cond)) {			\
+			printk("%s\n", msg);	\
+			code;			\
+		}				\
+	} while (0)
+
+
+#define PP_DBG_LOG(fmt, ...) \
+	do { \
+		if(0)printk(KERN_INFO "[ pp_dbg ] " fmt, ##__VA_ARGS__); \
+	} while (0)
+
+
+#endif /* PP_DEBUG_H */
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/pp_feature.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/pp_feature.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _PP_FEATURE_H_
+#define _PP_FEATURE_H_
+
+/**
+ * PowerPlay feature ids.
+ */
+enum pp_feature {
+	PP_Feature_PowerPlay = 0,
+	PP_Feature_User2DPerformance,
+	PP_Feature_User3DPerformance,
+	PP_Feature_VariBright,
+	PP_Feature_VariBrightOnPowerXpress,
+	PP_Feature_ReducedRefreshRate,
+	PP_Feature_GFXClockGating,
+	PP_Feature_OverdriveTest,
+	PP_Feature_OverDrive,
+	PP_Feature_PowerBudgetWaiver,
+	PP_Feature_PowerControl,
+	PP_Feature_PowerControl_2,
+	PP_Feature_MultiUVDState,
+	PP_Feature_Force3DClock,
+	PP_Feature_BACO,
+	PP_Feature_PowerDown,
+	PP_Feature_DynamicUVDState,
+	PP_Feature_VCEDPM,
+	PP_Feature_PPM,
+	PP_Feature_ACP_POWERGATING,
+	PP_Feature_FFC,
+	PP_Feature_FPS,
+	PP_Feature_ViPG,
+	PP_Feature_Max
+};
+
+/**
+ * Struct for PowerPlay feature info.
+ */
+struct pp_feature_info {
+	bool supported;               /* feature supported by PowerPlay */
+	bool enabled;                 /* feature enabled in PowerPlay */
+	bool enabled_default;        /* default enable status of the feature */
+	uint32_t version;             /* feature version */
+};
+
+#endif /* _PP_FEATURE_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _PP_INSTANCE_H_
+#define _PP_INSTANCE_H_
+
+#include "smumgr.h"
+#include "hwmgr.h"
+#include "eventmgr.h"
+
+#define PP_VALID  0x1F1F1F1F
+
+struct pp_instance {
+	uint32_t pp_valid;
+	struct pp_smumgr *smu_mgr;
+	struct pp_hwmgr *hwmgr;
+	struct pp_eventmgr *eventmgr;
+};
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef PP_POWERSOURCE_H
+#define PP_POWERSOURCE_H
+
+enum pp_power_source {
+	PP_PowerSource_AC = 0,
+	PP_PowerSource_DC,
+	PP_PowerSource_LimitedPower,
+	PP_PowerSource_LimitedPower_2,
+	PP_PowerSource_Max
+};
+
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/ppinterrupt.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/ppinterrupt.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _PP_INTERRUPT_H_
+#define _PP_INTERRUPT_H_
+
+enum amd_thermal_irq {
+	AMD_THERMAL_IRQ_LOW_TO_HIGH = 0,
+	AMD_THERMAL_IRQ_HIGH_TO_LOW,
+
+	AMD_THERMAL_IRQ_LAST
+};
+
+/* The type of the interrupt callback functions in PowerPlay */
+typedef int (*irq_handler_func_t)(void *private_data,
+				unsigned src_id, const uint32_t *iv_entry);
+
+/* Event Manager action chain list information */
+struct pp_interrupt_registration_info {
+	irq_handler_func_t call_back; /* Pointer to callback function */
+	void *context;                   /* Pointer to callback function context */
+	uint32_t src_id;               /* Registered interrupt id */
+	const uint32_t *iv_entry;
+};
+
+#endif /* _PP_INTERRUPT_H_ */
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu7.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu7.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SMU7_H
+#define SMU7_H
+
+#pragma pack(push, 1)
+
+#define SMU7_CONTEXT_ID_SMC        1
+#define SMU7_CONTEXT_ID_VBIOS      2
+
+
+#define SMU7_CONTEXT_ID_SMC        1
+#define SMU7_CONTEXT_ID_VBIOS      2
+
+#define SMU7_MAX_LEVELS_VDDC            8
+#define SMU7_MAX_LEVELS_VDDCI           4
+#define SMU7_MAX_LEVELS_MVDD            4
+#define SMU7_MAX_LEVELS_VDDNB           8
+
+#define SMU7_MAX_LEVELS_GRAPHICS        SMU__NUM_SCLK_DPM_STATE   // SCLK + SQ DPM + ULV
+#define SMU7_MAX_LEVELS_MEMORY          SMU__NUM_MCLK_DPM_LEVELS   // MCLK Levels DPM
+#define SMU7_MAX_LEVELS_GIO             SMU__NUM_LCLK_DPM_LEVELS  // LCLK Levels
+#define SMU7_MAX_LEVELS_LINK            SMU__NUM_PCIE_DPM_LEVELS  // PCIe speed and number of lanes.
+#define SMU7_MAX_LEVELS_UVD             8   // VCLK/DCLK levels for UVD.
+#define SMU7_MAX_LEVELS_VCE             8   // ECLK levels for VCE.
+#define SMU7_MAX_LEVELS_ACP             8   // ACLK levels for ACP.
+#define SMU7_MAX_LEVELS_SAMU            8   // SAMCLK levels for SAMU.
+#define SMU7_MAX_ENTRIES_SMIO           32  // Number of entries in SMIO table.
+
+#define DPM_NO_LIMIT 0
+#define DPM_NO_UP 1
+#define DPM_GO_DOWN 2
+#define DPM_GO_UP 3
+
+#define SMU7_FIRST_DPM_GRAPHICS_LEVEL    0
+#define SMU7_FIRST_DPM_MEMORY_LEVEL      0
+
+#define GPIO_CLAMP_MODE_VRHOT      1
+#define GPIO_CLAMP_MODE_THERM      2
+#define GPIO_CLAMP_MODE_DC         4
+
+#define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0
+#define SCRATCH_B_TARG_PCIE_INDEX_MASK  (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3
+#define SCRATCH_B_CURR_PCIE_INDEX_MASK  (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_UVD_INDEX_SHIFT  6
+#define SCRATCH_B_TARG_UVD_INDEX_MASK   (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT)
+#define SCRATCH_B_CURR_UVD_INDEX_SHIFT  9
+#define SCRATCH_B_CURR_UVD_INDEX_MASK   (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT)
+#define SCRATCH_B_TARG_VCE_INDEX_SHIFT  12
+#define SCRATCH_B_TARG_VCE_INDEX_MASK   (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_VCE_INDEX_SHIFT  15
+#define SCRATCH_B_CURR_VCE_INDEX_MASK   (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_ACP_INDEX_SHIFT  18
+#define SCRATCH_B_TARG_ACP_INDEX_MASK   (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT)
+#define SCRATCH_B_CURR_ACP_INDEX_SHIFT  21
+#define SCRATCH_B_CURR_ACP_INDEX_MASK   (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT)
+#define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24
+#define SCRATCH_B_TARG_SAMU_INDEX_MASK  (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT)
+#define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27
+#define SCRATCH_B_CURR_SAMU_INDEX_MASK  (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT)
+
+
+struct SMU7_PIDController
+{
+    uint32_t Ki;
+    int32_t LFWindupUL;
+    int32_t LFWindupLL;
+    uint32_t StatePrecision;
+    uint32_t LfPrecision;
+    uint32_t LfOffset;
+    uint32_t MaxState;
+    uint32_t MaxLfFraction;
+    uint32_t StateShift;
+};
+
+typedef struct SMU7_PIDController SMU7_PIDController;
+
+// -------------------------------------------------------------------------------------------------------------------------
+#define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */
+
+#define SMU7_SCLK_DPM_CONFIG_MASK                        0x01
+#define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK              0x02
+#define SMU7_THERMAL_CONTROLLER_CONFIG_MASK              0x04
+#define SMU7_MCLK_DPM_CONFIG_MASK                        0x08
+#define SMU7_UVD_DPM_CONFIG_MASK                         0x10
+#define SMU7_VCE_DPM_CONFIG_MASK                         0x20
+#define SMU7_ACP_DPM_CONFIG_MASK                         0x40
+#define SMU7_SAMU_DPM_CONFIG_MASK                        0x80
+#define SMU7_PCIEGEN_DPM_CONFIG_MASK                    0x100
+
+#define SMU7_ACP_MCLK_HANDSHAKE_DISABLE                  0x00000001
+#define SMU7_ACP_SCLK_HANDSHAKE_DISABLE                  0x00000002
+#define SMU7_UVD_MCLK_HANDSHAKE_DISABLE                  0x00000100
+#define SMU7_UVD_SCLK_HANDSHAKE_DISABLE                  0x00000200
+#define SMU7_VCE_MCLK_HANDSHAKE_DISABLE                  0x00010000
+#define SMU7_VCE_SCLK_HANDSHAKE_DISABLE                  0x00020000
+
+struct SMU7_Firmware_Header
+{
+    uint32_t Digest[5];
+    uint32_t Version;
+    uint32_t HeaderSize;
+    uint32_t Flags;
+    uint32_t EntryPoint;
+    uint32_t CodeSize;
+    uint32_t ImageSize;
+
+    uint32_t Rtos;
+    uint32_t SoftRegisters;
+    uint32_t DpmTable;
+    uint32_t FanTable;
+    uint32_t CacConfigTable;
+    uint32_t CacStatusTable;
+
+    uint32_t mcRegisterTable;
+
+    uint32_t mcArbDramTimingTable;
+
+    uint32_t PmFuseTable;
+    uint32_t Globals;
+    uint32_t Reserved[42];
+    uint32_t Signature;
+};
+
+typedef struct SMU7_Firmware_Header SMU7_Firmware_Header;
+
+#define SMU7_FIRMWARE_HEADER_LOCATION 0x20000
+
+enum  DisplayConfig {
+    PowerDown = 1,
+    DP54x4,
+    DP54x2,
+    DP54x1,
+    DP27x4,
+    DP27x2,
+    DP27x1,
+    HDMI297,
+    HDMI162,
+    LVDS,
+    DP324x4,
+    DP324x2,
+    DP324x1
+};
+
+#pragma pack(pop)
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu72.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu72.h
@@ -0,0 +1,664 @@
+#ifndef SMU72_H
+#define SMU72_H
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(push, 1)
+#endif
+
+#define SMU__NUM_SCLK_DPM_STATE  8
+#define SMU__NUM_MCLK_DPM_LEVELS 4
+#define SMU__NUM_LCLK_DPM_LEVELS 8
+#define SMU__NUM_PCIE_DPM_LEVELS 8
+
+enum SID_OPTION {
+	SID_OPTION_HI,
+	SID_OPTION_LO,
+	SID_OPTION_COUNT
+};
+
+enum Poly3rdOrderCoeff {
+	LEAKAGE_TEMPERATURE_SCALAR,
+	LEAKAGE_VOLTAGE_SCALAR,
+	DYNAMIC_VOLTAGE_SCALAR,
+	POLY_3RD_ORDER_COUNT
+};
+
+struct SMU7_Poly3rdOrder_Data {
+	int32_t a;
+	int32_t b;
+	int32_t c;
+	int32_t d;
+	uint8_t a_shift;
+	uint8_t b_shift;
+	uint8_t c_shift;
+	uint8_t x_shift;
+};
+
+typedef struct SMU7_Poly3rdOrder_Data SMU7_Poly3rdOrder_Data;
+
+struct Power_Calculator_Data {
+	uint16_t NoLoadVoltage;
+	uint16_t LoadVoltage;
+	uint16_t Resistance;
+	uint16_t Temperature;
+	uint16_t BaseLeakage;
+	uint16_t LkgTempScalar;
+	uint16_t LkgVoltScalar;
+	uint16_t LkgAreaScalar;
+	uint16_t LkgPower;
+	uint16_t DynVoltScalar;
+	uint32_t Cac;
+	uint32_t DynPower;
+	uint32_t TotalCurrent;
+	uint32_t TotalPower;
+};
+
+typedef struct Power_Calculator_Data PowerCalculatorData_t;
+
+struct Gc_Cac_Weight_Data {
+	uint8_t index;
+	uint32_t value;
+};
+
+typedef struct Gc_Cac_Weight_Data GcCacWeight_Data;
+
+
+typedef struct {
+	uint32_t high;
+	uint32_t low;
+} data_64_t;
+
+typedef struct {
+	data_64_t high;
+	data_64_t low;
+} data_128_t;
+
+#define SMU7_CONTEXT_ID_SMC        1
+#define SMU7_CONTEXT_ID_VBIOS      2
+
+#define SMU72_MAX_LEVELS_VDDC            16
+#define SMU72_MAX_LEVELS_VDDGFX          16
+#define SMU72_MAX_LEVELS_VDDCI           8
+#define SMU72_MAX_LEVELS_MVDD            4
+
+#define SMU_MAX_SMIO_LEVELS              4
+
+#define SMU72_MAX_LEVELS_GRAPHICS        SMU__NUM_SCLK_DPM_STATE   /* SCLK + SQ DPM + ULV */
+#define SMU72_MAX_LEVELS_MEMORY          SMU__NUM_MCLK_DPM_LEVELS   /* MCLK Levels DPM */
+#define SMU72_MAX_LEVELS_GIO             SMU__NUM_LCLK_DPM_LEVELS  /* LCLK Levels */
+#define SMU72_MAX_LEVELS_LINK            SMU__NUM_PCIE_DPM_LEVELS  /* PCIe speed and number of lanes. */
+#define SMU72_MAX_LEVELS_UVD             8   /* VCLK/DCLK levels for UVD. */
+#define SMU72_MAX_LEVELS_VCE             8   /* ECLK levels for VCE. */
+#define SMU72_MAX_LEVELS_ACP             8   /* ACLK levels for ACP. */
+#define SMU72_MAX_LEVELS_SAMU            8   /* SAMCLK levels for SAMU. */
+#define SMU72_MAX_ENTRIES_SMIO           32  /* Number of entries in SMIO table. */
+
+#define DPM_NO_LIMIT 0
+#define DPM_NO_UP 1
+#define DPM_GO_DOWN 2
+#define DPM_GO_UP 3
+
+#define SMU7_FIRST_DPM_GRAPHICS_LEVEL    0
+#define SMU7_FIRST_DPM_MEMORY_LEVEL      0
+
+#define GPIO_CLAMP_MODE_VRHOT      1
+#define GPIO_CLAMP_MODE_THERM      2
+#define GPIO_CLAMP_MODE_DC         4
+
+#define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0
+#define SCRATCH_B_TARG_PCIE_INDEX_MASK  (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3
+#define SCRATCH_B_CURR_PCIE_INDEX_MASK  (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_UVD_INDEX_SHIFT  6
+#define SCRATCH_B_TARG_UVD_INDEX_MASK   (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT)
+#define SCRATCH_B_CURR_UVD_INDEX_SHIFT  9
+#define SCRATCH_B_CURR_UVD_INDEX_MASK   (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT)
+#define SCRATCH_B_TARG_VCE_INDEX_SHIFT  12
+#define SCRATCH_B_TARG_VCE_INDEX_MASK   (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_VCE_INDEX_SHIFT  15
+#define SCRATCH_B_CURR_VCE_INDEX_MASK   (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_ACP_INDEX_SHIFT  18
+#define SCRATCH_B_TARG_ACP_INDEX_MASK   (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT)
+#define SCRATCH_B_CURR_ACP_INDEX_SHIFT  21
+#define SCRATCH_B_CURR_ACP_INDEX_MASK   (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT)
+#define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24
+#define SCRATCH_B_TARG_SAMU_INDEX_MASK  (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT)
+#define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27
+#define SCRATCH_B_CURR_SAMU_INDEX_MASK  (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT)
+
+/* Virtualization Defines */
+#define CG_XDMA_MASK  0x1
+#define CG_XDMA_SHIFT 0
+#define CG_UVD_MASK   0x2
+#define CG_UVD_SHIFT  1
+#define CG_VCE_MASK   0x4
+#define CG_VCE_SHIFT  2
+#define CG_SAMU_MASK  0x8
+#define CG_SAMU_SHIFT 3
+#define CG_GFX_MASK   0x10
+#define CG_GFX_SHIFT  4
+#define CG_SDMA_MASK  0x20
+#define CG_SDMA_SHIFT 5
+#define CG_HDP_MASK   0x40
+#define CG_HDP_SHIFT  6
+#define CG_MC_MASK    0x80
+#define CG_MC_SHIFT   7
+#define CG_DRM_MASK   0x100
+#define CG_DRM_SHIFT  8
+#define CG_ROM_MASK   0x200
+#define CG_ROM_SHIFT  9
+#define CG_BIF_MASK   0x400
+#define CG_BIF_SHIFT  10
+
+#define SMU72_DTE_ITERATIONS 5
+#define SMU72_DTE_SOURCES 3
+#define SMU72_DTE_SINKS 1
+#define SMU72_NUM_CPU_TES 0
+#define SMU72_NUM_GPU_TES 1
+#define SMU72_NUM_NON_TES 2
+#define SMU72_DTE_FAN_SCALAR_MIN 0x100
+#define SMU72_DTE_FAN_SCALAR_MAX 0x166
+#define SMU72_DTE_FAN_TEMP_MAX 93
+#define SMU72_DTE_FAN_TEMP_MIN 83
+
+#if defined SMU__FUSION_ONLY
+#define SMU7_DTE_ITERATIONS 5
+#define SMU7_DTE_SOURCES 5
+#define SMU7_DTE_SINKS 3
+#define SMU7_NUM_CPU_TES 2
+#define SMU7_NUM_GPU_TES 1
+#define SMU7_NUM_NON_TES 2
+#endif
+
+struct SMU7_HystController_Data {
+	uint8_t waterfall_up;
+	uint8_t waterfall_down;
+	uint8_t waterfall_limit;
+	uint8_t spare;
+	uint16_t release_cnt;
+	uint16_t release_limit;
+};
+
+typedef struct SMU7_HystController_Data SMU7_HystController_Data;
+
+struct SMU72_PIDController {
+	uint32_t Ki;
+	int32_t LFWindupUpperLim;
+	int32_t LFWindupLowerLim;
+	uint32_t StatePrecision;
+	uint32_t LfPrecision;
+	uint32_t LfOffset;
+	uint32_t MaxState;
+	uint32_t MaxLfFraction;
+	uint32_t StateShift;
+};
+
+typedef struct SMU72_PIDController SMU72_PIDController;
+
+struct SMU7_LocalDpmScoreboard {
+	uint32_t PercentageBusy;
+
+	int32_t  PIDError;
+	int32_t  PIDIntegral;
+	int32_t  PIDOutput;
+
+	uint32_t SigmaDeltaAccum;
+	uint32_t SigmaDeltaOutput;
+	uint32_t SigmaDeltaLevel;
+
+	uint32_t UtilizationSetpoint;
+
+	uint8_t  TdpClampMode;
+	uint8_t  TdcClampMode;
+	uint8_t  ThermClampMode;
+	uint8_t  VoltageBusy;
+
+	int8_t   CurrLevel;
+	int8_t   TargLevel;
+	uint8_t  LevelChangeInProgress;
+	uint8_t  UpHyst;
+
+	uint8_t  DownHyst;
+	uint8_t  VoltageDownHyst;
+	uint8_t  DpmEnable;
+	uint8_t  DpmRunning;
+
+	uint8_t  DpmForce;
+	uint8_t  DpmForceLevel;
+	uint8_t  DisplayWatermark;
+	uint8_t  McArbIndex;
+
+	uint32_t MinimumPerfSclk;
+
+	uint8_t  AcpiReq;
+	uint8_t  AcpiAck;
+	uint8_t  GfxClkSlow;
+	uint8_t  GpioClampMode; /* bit0 = VRHOT: bit1 = THERM: bit2 = DC */
+
+	uint8_t  FpsFilterWeight;
+	uint8_t  EnabledLevelsChange;
+	uint8_t  DteClampMode;
+	uint8_t  FpsClampMode;
+
+	uint16_t LevelResidencyCounters[SMU72_MAX_LEVELS_GRAPHICS];
+	uint16_t LevelSwitchCounters[SMU72_MAX_LEVELS_GRAPHICS];
+
+	void     (*TargetStateCalculator)(uint8_t);
+	void     (*SavedTargetStateCalculator)(uint8_t);
+
+	uint16_t AutoDpmInterval;
+	uint16_t AutoDpmRange;
+
+	uint8_t  FpsEnabled;
+	uint8_t  MaxPerfLevel;
+	uint8_t  AllowLowClkInterruptToHost;
+	uint8_t  FpsRunning;
+
+	uint32_t MaxAllowedFrequency;
+
+	uint32_t FilteredSclkFrequency;
+	uint32_t LastSclkFrequency;
+	uint32_t FilteredSclkFrequencyCnt;
+};
+
+typedef struct SMU7_LocalDpmScoreboard SMU7_LocalDpmScoreboard;
+
+#define SMU7_MAX_VOLTAGE_CLIENTS 12
+
+typedef uint8_t (*VoltageChangeHandler_t)(uint16_t, uint8_t);
+
+struct SMU_VoltageLevel {
+	uint8_t Vddc;
+	uint8_t Vddci;
+	uint8_t VddGfx;
+	uint8_t Phases;
+};
+
+typedef struct SMU_VoltageLevel SMU_VoltageLevel;
+
+struct SMU7_VoltageScoreboard {
+	SMU_VoltageLevel CurrentVoltage;
+	SMU_VoltageLevel TargetVoltage;
+	uint16_t MaxVid;
+	uint8_t  HighestVidOffset;
+	uint8_t  CurrentVidOffset;
+
+	uint8_t  ControllerBusy;
+	uint8_t  CurrentVid;
+	uint8_t  CurrentVddciVid;
+	uint8_t  VddGfxShutdown; /* 0 = normal mode, 1 = shut down */
+
+	SMU_VoltageLevel RequestedVoltage[SMU7_MAX_VOLTAGE_CLIENTS];
+	uint8_t  EnabledRequest[SMU7_MAX_VOLTAGE_CLIENTS];
+
+	uint8_t  TargetIndex;
+	uint8_t  Delay;
+	uint8_t  ControllerEnable;
+	uint8_t  ControllerRunning;
+	uint16_t CurrentStdVoltageHiSidd;
+	uint16_t CurrentStdVoltageLoSidd;
+	uint8_t  OverrideVoltage;
+	uint8_t  VddcUseUlvOffset;
+	uint8_t  VddGfxUseUlvOffset;
+	uint8_t  padding;
+
+	VoltageChangeHandler_t ChangeVddc;
+	VoltageChangeHandler_t ChangeVddGfx;
+	VoltageChangeHandler_t ChangeVddci;
+	VoltageChangeHandler_t ChangePhase;
+	VoltageChangeHandler_t ChangeMvdd;
+
+	VoltageChangeHandler_t functionLinks[6];
+
+	uint8_t *VddcFollower1;
+	uint8_t *VddcFollower2;
+	int16_t  Driver_OD_RequestedVidOffset1;
+	int16_t  Driver_OD_RequestedVidOffset2;
+
+};
+
+typedef struct SMU7_VoltageScoreboard SMU7_VoltageScoreboard;
+
+#define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */
+
+struct SMU7_PCIeLinkSpeedScoreboard {
+	uint8_t     DpmEnable;
+	uint8_t     DpmRunning;
+	uint8_t     DpmForce;
+	uint8_t     DpmForceLevel;
+
+	uint8_t     CurrentLinkSpeed;
+	uint8_t     EnabledLevelsChange;
+	uint16_t    AutoDpmInterval;
+
+	uint16_t    AutoDpmRange;
+	uint16_t    AutoDpmCount;
+
+	uint8_t     DpmMode;
+	uint8_t     AcpiReq;
+	uint8_t     AcpiAck;
+	uint8_t     CurrentLinkLevel;
+
+};
+
+typedef struct SMU7_PCIeLinkSpeedScoreboard SMU7_PCIeLinkSpeedScoreboard;
+
+/* -------------------------------------------------------- CAC table ------------------------------------------------------ */
+#define SMU7_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMU7_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16
+#define SMU7_SCALE_I  7
+#define SMU7_SCALE_R 12
+
+struct SMU7_PowerScoreboard {
+	PowerCalculatorData_t VddGfxPowerData[SID_OPTION_COUNT];
+	PowerCalculatorData_t VddcPowerData[SID_OPTION_COUNT];
+
+	uint32_t TotalGpuPower;
+	uint32_t TdcCurrent;
+
+	uint16_t   VddciTotalPower;
+	uint16_t   sparesasfsdfd;
+	uint16_t   Vddr1Power;
+	uint16_t   RocPower;
+
+	uint16_t   CalcMeasPowerBlend;
+	uint8_t    SidOptionPower;
+	uint8_t    SidOptionCurrent;
+
+	uint32_t   WinTime;
+
+	uint16_t Telemetry_1_slope;
+	uint16_t Telemetry_2_slope;
+	int32_t Telemetry_1_offset;
+	int32_t Telemetry_2_offset;
+
+	uint32_t VddcCurrentTelemetry;
+	uint32_t VddGfxCurrentTelemetry;
+	uint32_t VddcPowerTelemetry;
+	uint32_t VddGfxPowerTelemetry;
+	uint32_t VddciPowerTelemetry;
+
+	uint32_t VddcPower;
+	uint32_t VddGfxPower;
+	uint32_t VddciPower;
+
+	uint32_t TelemetryCurrent[2];
+	uint32_t TelemetryVoltage[2];
+	uint32_t TelemetryPower[2];
+};
+
+typedef struct SMU7_PowerScoreboard SMU7_PowerScoreboard;
+
+struct SMU7_ThermalScoreboard {
+	int16_t  GpuLimit;
+	int16_t  GpuHyst;
+	uint16_t CurrGnbTemp;
+	uint16_t FilteredGnbTemp;
+
+	uint8_t  ControllerEnable;
+	uint8_t  ControllerRunning;
+	uint8_t  AutoTmonCalInterval;
+	uint8_t  AutoTmonCalEnable;
+
+	uint8_t  ThermalDpmEnabled;
+	uint8_t  SclkEnabledMask;
+	uint8_t  spare[2];
+	int32_t  temperature_gradient;
+
+	SMU7_HystController_Data HystControllerData;
+	int32_t  WeightedSensorTemperature;
+	uint16_t TemperatureLimit[SMU72_MAX_LEVELS_GRAPHICS];
+	uint32_t Alpha;
+};
+
+typedef struct SMU7_ThermalScoreboard SMU7_ThermalScoreboard;
+
+/* For FeatureEnables: */
+#define SMU7_SCLK_DPM_CONFIG_MASK                        0x01
+#define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK              0x02
+#define SMU7_THERMAL_CONTROLLER_CONFIG_MASK              0x04
+#define SMU7_MCLK_DPM_CONFIG_MASK                        0x08
+#define SMU7_UVD_DPM_CONFIG_MASK                         0x10
+#define SMU7_VCE_DPM_CONFIG_MASK                         0x20
+#define SMU7_ACP_DPM_CONFIG_MASK                         0x40
+#define SMU7_SAMU_DPM_CONFIG_MASK                        0x80
+#define SMU7_PCIEGEN_DPM_CONFIG_MASK                    0x100
+
+#define SMU7_ACP_MCLK_HANDSHAKE_DISABLE                  0x00000001
+#define SMU7_ACP_SCLK_HANDSHAKE_DISABLE                  0x00000002
+#define SMU7_UVD_MCLK_HANDSHAKE_DISABLE                  0x00000100
+#define SMU7_UVD_SCLK_HANDSHAKE_DISABLE                  0x00000200
+#define SMU7_VCE_MCLK_HANDSHAKE_DISABLE                  0x00010000
+#define SMU7_VCE_SCLK_HANDSHAKE_DISABLE                  0x00020000
+
+/* All 'soft registers' should be uint32_t. */
+struct SMU72_SoftRegisters {
+	uint32_t        RefClockFrequency;
+	uint32_t        PmTimerPeriod;
+	uint32_t        FeatureEnables;
+
+	uint32_t        PreVBlankGap;
+	uint32_t        VBlankTimeout;
+	uint32_t        TrainTimeGap;
+
+	uint32_t        MvddSwitchTime;
+	uint32_t        LongestAcpiTrainTime;
+	uint32_t        AcpiDelay;
+	uint32_t        G5TrainTime;
+	uint32_t        DelayMpllPwron;
+	uint32_t        VoltageChangeTimeout;
+
+	uint32_t        HandshakeDisables;
+
+	uint8_t         DisplayPhy1Config;
+	uint8_t         DisplayPhy2Config;
+	uint8_t         DisplayPhy3Config;
+	uint8_t         DisplayPhy4Config;
+
+	uint8_t         DisplayPhy5Config;
+	uint8_t         DisplayPhy6Config;
+	uint8_t         DisplayPhy7Config;
+	uint8_t         DisplayPhy8Config;
+
+	uint32_t        AverageGraphicsActivity;
+	uint32_t        AverageMemoryActivity;
+	uint32_t        AverageGioActivity;
+
+	uint8_t         SClkDpmEnabledLevels;
+	uint8_t         MClkDpmEnabledLevels;
+	uint8_t         LClkDpmEnabledLevels;
+	uint8_t         PCIeDpmEnabledLevels;
+
+	uint8_t         UVDDpmEnabledLevels;
+	uint8_t         SAMUDpmEnabledLevels;
+	uint8_t         ACPDpmEnabledLevels;
+	uint8_t         VCEDpmEnabledLevels;
+
+	uint32_t        DRAM_LOG_ADDR_H;
+	uint32_t        DRAM_LOG_ADDR_L;
+	uint32_t        DRAM_LOG_PHY_ADDR_H;
+	uint32_t        DRAM_LOG_PHY_ADDR_L;
+	uint32_t        DRAM_LOG_BUFF_SIZE;
+	uint32_t        UlvEnterCount;
+	uint32_t        UlvTime;
+	uint32_t        UcodeLoadStatus;
+	uint32_t        Reserved[2];
+
+};
+
+typedef struct SMU72_SoftRegisters SMU72_SoftRegisters;
+
+struct SMU72_Firmware_Header {
+	uint32_t Digest[5];
+	uint32_t Version;
+	uint32_t HeaderSize;
+	uint32_t Flags;
+	uint32_t EntryPoint;
+	uint32_t CodeSize;
+	uint32_t ImageSize;
+
+	uint32_t Rtos;
+	uint32_t SoftRegisters;
+	uint32_t DpmTable;
+	uint32_t FanTable;
+	uint32_t CacConfigTable;
+	uint32_t CacStatusTable;
+	uint32_t mcRegisterTable;
+	uint32_t mcArbDramTimingTable;
+	uint32_t PmFuseTable;
+	uint32_t Globals;
+	uint32_t ClockStretcherTable;
+	uint32_t Reserved[41];
+	uint32_t Signature;
+};
+
+typedef struct SMU72_Firmware_Header SMU72_Firmware_Header;
+
+#define SMU72_FIRMWARE_HEADER_LOCATION 0x20000
+
+enum  DisplayConfig {
+	PowerDown = 1,
+	DP54x4,
+	DP54x2,
+	DP54x1,
+	DP27x4,
+	DP27x2,
+	DP27x1,
+	HDMI297,
+	HDMI162,
+	LVDS,
+	DP324x4,
+	DP324x2,
+	DP324x1
+};
+
+#define MC_BLOCK_COUNT 1
+#define CPL_BLOCK_COUNT 5
+#define SE_BLOCK_COUNT 15
+#define GC_BLOCK_COUNT 24
+
+struct SMU7_Local_Cac {
+	uint8_t BlockId;
+	uint8_t SignalId;
+	uint8_t Threshold;
+	uint8_t Padding;
+};
+
+typedef struct SMU7_Local_Cac SMU7_Local_Cac;
+
+struct SMU7_Local_Cac_Table {
+	SMU7_Local_Cac CplLocalCac[CPL_BLOCK_COUNT];
+	SMU7_Local_Cac McLocalCac[MC_BLOCK_COUNT];
+	SMU7_Local_Cac SeLocalCac[SE_BLOCK_COUNT];
+	SMU7_Local_Cac GcLocalCac[GC_BLOCK_COUNT];
+};
+
+typedef struct SMU7_Local_Cac_Table SMU7_Local_Cac_Table;
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+#endif
+
+/* Description of Clock Gating bitmask for Tonga: */
+/* System Clock Gating */
+#define CG_SYS_BITMASK_FIRST_BIT      0  /* First bit of Sys CG bitmask */
+#define CG_SYS_BITMASK_LAST_BIT       9  /* Last bit of Sys CG bitmask */
+#define CG_SYS_BIF_MGLS_SHIFT         0
+#define CG_SYS_ROM_SHIFT              1
+#define CG_SYS_MC_MGCG_SHIFT          2
+#define CG_SYS_MC_MGLS_SHIFT          3
+#define CG_SYS_SDMA_MGCG_SHIFT        4
+#define CG_SYS_SDMA_MGLS_SHIFT        5
+#define CG_SYS_DRM_MGCG_SHIFT         6
+#define CG_SYS_HDP_MGCG_SHIFT         7
+#define CG_SYS_HDP_MGLS_SHIFT         8
+#define CG_SYS_DRM_MGLS_SHIFT         9
+
+#define CG_SYS_BIF_MGLS_MASK          0x1
+#define CG_SYS_ROM_MASK               0x2
+#define CG_SYS_MC_MGCG_MASK           0x4
+#define CG_SYS_MC_MGLS_MASK           0x8
+#define CG_SYS_SDMA_MGCG_MASK         0x10
+#define CG_SYS_SDMA_MGLS_MASK         0x20
+#define CG_SYS_DRM_MGCG_MASK          0x40
+#define CG_SYS_HDP_MGCG_MASK          0x80
+#define CG_SYS_HDP_MGLS_MASK          0x100
+#define CG_SYS_DRM_MGLS_MASK          0x200
+
+/* Graphics Clock Gating */
+#define CG_GFX_BITMASK_FIRST_BIT      16 /* First bit of Gfx CG bitmask */
+#define CG_GFX_BITMASK_LAST_BIT       20 /* Last bit of Gfx CG bitmask */
+#define CG_GFX_CGCG_SHIFT             16
+#define CG_GFX_CGLS_SHIFT             17
+#define CG_CPF_MGCG_SHIFT             18
+#define CG_RLC_MGCG_SHIFT             19
+#define CG_GFX_OTHERS_MGCG_SHIFT      20
+
+#define CG_GFX_CGCG_MASK              0x00010000
+#define CG_GFX_CGLS_MASK              0x00020000
+#define CG_CPF_MGCG_MASK              0x00040000
+#define CG_RLC_MGCG_MASK              0x00080000
+#define CG_GFX_OTHERS_MGCG_MASK       0x00100000
+
+/* Voltage Regulator Configuration */
+/* VR Config info is contained in dpmTable.VRConfig */
+
+#define VRCONF_VDDC_MASK         0x000000FF
+#define VRCONF_VDDC_SHIFT        0
+#define VRCONF_VDDGFX_MASK       0x0000FF00
+#define VRCONF_VDDGFX_SHIFT      8
+#define VRCONF_VDDCI_MASK        0x00FF0000
+#define VRCONF_VDDCI_SHIFT       16
+#define VRCONF_MVDD_MASK         0xFF000000
+#define VRCONF_MVDD_SHIFT        24
+
+#define VR_MERGED_WITH_VDDC      0
+#define VR_SVI2_PLANE_1          1
+#define VR_SVI2_PLANE_2          2
+#define VR_SMIO_PATTERN_1        3
+#define VR_SMIO_PATTERN_2        4
+#define VR_STATIC_VOLTAGE        5
+
+/* Clock Stretcher Configuration */
+
+#define CLOCK_STRETCHER_MAX_ENTRIES 0x4
+#define CKS_LOOKUPTable_MAX_ENTRIES 0x4
+
+/* The 'settings' field is subdivided in the following way: */
+#define CLOCK_STRETCHER_SETTING_DDT_MASK             0x01
+#define CLOCK_STRETCHER_SETTING_DDT_SHIFT            0x0
+#define CLOCK_STRETCHER_SETTING_STRETCH_AMOUNT_MASK  0x1E
+#define CLOCK_STRETCHER_SETTING_STRETCH_AMOUNT_SHIFT 0x1
+#define CLOCK_STRETCHER_SETTING_ENABLE_MASK          0x80
+#define CLOCK_STRETCHER_SETTING_ENABLE_SHIFT         0x7
+
+struct SMU_ClockStretcherDataTableEntry {
+	uint8_t minVID;
+	uint8_t maxVID;
+
+	uint16_t setting;
+};
+typedef struct SMU_ClockStretcherDataTableEntry SMU_ClockStretcherDataTableEntry;
+
+struct SMU_ClockStretcherDataTable {
+	SMU_ClockStretcherDataTableEntry ClockStretcherDataTableEntry[CLOCK_STRETCHER_MAX_ENTRIES];
+};
+typedef struct SMU_ClockStretcherDataTable SMU_ClockStretcherDataTable;
+
+struct SMU_CKS_LOOKUPTableEntry {
+	uint16_t minFreq;
+	uint16_t maxFreq;
+
+	uint8_t setting;
+	uint8_t padding[3];
+};
+typedef struct SMU_CKS_LOOKUPTableEntry SMU_CKS_LOOKUPTableEntry;
+
+struct SMU_CKS_LOOKUPTable {
+	SMU_CKS_LOOKUPTableEntry CKS_LOOKUPTableEntry[CKS_LOOKUPTable_MAX_ENTRIES];
+};
+typedef struct SMU_CKS_LOOKUPTable SMU_CKS_LOOKUPTable;
+
+#endif
+
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h
@@ -0,0 +1,760 @@
+#ifndef SMU72_DISCRETE_H
+#define SMU72_DISCRETE_H
+
+#include "smu72.h"
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(push, 1)
+#endif
+
+struct SMIO_Pattern {
+	uint16_t Voltage;
+	uint8_t  Smio;
+	uint8_t  padding;
+};
+
+typedef struct SMIO_Pattern SMIO_Pattern;
+
+struct SMIO_Table {
+	SMIO_Pattern Pattern[SMU_MAX_SMIO_LEVELS];
+};
+
+typedef struct SMIO_Table SMIO_Table;
+
+struct SMU72_Discrete_GraphicsLevel {
+	SMU_VoltageLevel MinVoltage;
+
+	uint32_t    SclkFrequency;
+
+	uint8_t     pcieDpmLevel;
+	uint8_t     DeepSleepDivId;
+	uint16_t    ActivityLevel;
+
+	uint32_t    CgSpllFuncCntl3;
+	uint32_t    CgSpllFuncCntl4;
+	uint32_t    SpllSpreadSpectrum;
+	uint32_t    SpllSpreadSpectrum2;
+	uint32_t    CcPwrDynRm;
+	uint32_t    CcPwrDynRm1;
+	uint8_t     SclkDid;
+	uint8_t     DisplayWatermark;
+	uint8_t     EnabledForActivity;
+	uint8_t     EnabledForThrottle;
+	uint8_t     UpHyst;
+	uint8_t     DownHyst;
+	uint8_t     VoltageDownHyst;
+	uint8_t     PowerThrottle;
+};
+
+typedef struct SMU72_Discrete_GraphicsLevel SMU72_Discrete_GraphicsLevel;
+
+struct SMU72_Discrete_ACPILevel {
+	uint32_t    Flags;
+	SMU_VoltageLevel MinVoltage;
+	uint32_t    SclkFrequency;
+	uint8_t     SclkDid;
+	uint8_t     DisplayWatermark;
+	uint8_t     DeepSleepDivId;
+	uint8_t     padding;
+	uint32_t    CgSpllFuncCntl;
+	uint32_t    CgSpllFuncCntl2;
+	uint32_t    CgSpllFuncCntl3;
+	uint32_t    CgSpllFuncCntl4;
+	uint32_t    SpllSpreadSpectrum;
+	uint32_t    SpllSpreadSpectrum2;
+	uint32_t    CcPwrDynRm;
+	uint32_t    CcPwrDynRm1;
+};
+
+typedef struct SMU72_Discrete_ACPILevel SMU72_Discrete_ACPILevel;
+
+struct SMU72_Discrete_Ulv {
+	uint32_t    CcPwrDynRm;
+	uint32_t    CcPwrDynRm1;
+	uint16_t    VddcOffset;
+	uint8_t     VddcOffsetVid;
+	uint8_t     VddcPhase;
+	uint32_t    Reserved;
+};
+
+typedef struct SMU72_Discrete_Ulv SMU72_Discrete_Ulv;
+
+struct SMU72_Discrete_MemoryLevel {
+	SMU_VoltageLevel MinVoltage;
+	uint32_t    MinMvdd;
+
+	uint32_t    MclkFrequency;
+
+	uint8_t     EdcReadEnable;
+	uint8_t     EdcWriteEnable;
+	uint8_t     RttEnable;
+	uint8_t     StutterEnable;
+
+	uint8_t     StrobeEnable;
+	uint8_t     StrobeRatio;
+	uint8_t     EnabledForThrottle;
+	uint8_t     EnabledForActivity;
+
+	uint8_t     UpHyst;
+	uint8_t     DownHyst;
+	uint8_t     VoltageDownHyst;
+	uint8_t     padding;
+
+	uint16_t    ActivityLevel;
+	uint8_t     DisplayWatermark;
+	uint8_t     padding1;
+
+	uint32_t    MpllFuncCntl;
+	uint32_t    MpllFuncCntl_1;
+	uint32_t    MpllFuncCntl_2;
+	uint32_t    MpllAdFuncCntl;
+	uint32_t    MpllDqFuncCntl;
+	uint32_t    MclkPwrmgtCntl;
+	uint32_t    DllCntl;
+	uint32_t    MpllSs1;
+	uint32_t    MpllSs2;
+};
+
+typedef struct SMU72_Discrete_MemoryLevel SMU72_Discrete_MemoryLevel;
+
+struct SMU72_Discrete_LinkLevel {
+	uint8_t     PcieGenSpeed;           /*< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3 */
+	uint8_t     PcieLaneCount;          /*< 1=x1, 2=x2, 3=x4, 4=x8, 5=x12, 6=x16 */
+	uint8_t     EnabledForActivity;
+	uint8_t     SPC;
+	uint32_t    DownThreshold;
+	uint32_t    UpThreshold;
+	uint32_t    Reserved;
+};
+
+typedef struct SMU72_Discrete_LinkLevel SMU72_Discrete_LinkLevel;
+
+/* MC ARB DRAM Timing registers. */
+struct SMU72_Discrete_MCArbDramTimingTableEntry {
+	uint32_t McArbDramTiming;
+	uint32_t McArbDramTiming2;
+	uint8_t  McArbBurstTime;
+	uint8_t  padding[3];
+};
+
+typedef struct SMU72_Discrete_MCArbDramTimingTableEntry SMU72_Discrete_MCArbDramTimingTableEntry;
+
+struct SMU72_Discrete_MCArbDramTimingTable {
+	SMU72_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS];
+};
+
+typedef struct SMU72_Discrete_MCArbDramTimingTable SMU72_Discrete_MCArbDramTimingTable;
+
+/* UVD VCLK/DCLK state (level) definition. */
+struct SMU72_Discrete_UvdLevel {
+	uint32_t VclkFrequency;
+	uint32_t DclkFrequency;
+	SMU_VoltageLevel MinVoltage;
+	uint8_t  VclkDivider;
+	uint8_t  DclkDivider;
+	uint8_t  padding[2];
+};
+
+typedef struct SMU72_Discrete_UvdLevel SMU72_Discrete_UvdLevel;
+
+/* Clocks for other external blocks (VCE, ACP, SAMU). */
+struct SMU72_Discrete_ExtClkLevel {
+	uint32_t Frequency;
+	SMU_VoltageLevel MinVoltage;
+	uint8_t  Divider;
+	uint8_t  padding[3];
+};
+
+typedef struct SMU72_Discrete_ExtClkLevel SMU72_Discrete_ExtClkLevel;
+
+struct SMU72_Discrete_StateInfo {
+	uint32_t SclkFrequency;
+	uint32_t MclkFrequency;
+	uint32_t VclkFrequency;
+	uint32_t DclkFrequency;
+	uint32_t SamclkFrequency;
+	uint32_t AclkFrequency;
+	uint32_t EclkFrequency;
+	uint16_t MvddVoltage;
+	uint16_t padding16;
+	uint8_t  DisplayWatermark;
+	uint8_t  McArbIndex;
+	uint8_t  McRegIndex;
+	uint8_t  SeqIndex;
+	uint8_t  SclkDid;
+	int8_t   SclkIndex;
+	int8_t   MclkIndex;
+	uint8_t  PCIeGen;
+
+};
+
+typedef struct SMU72_Discrete_StateInfo SMU72_Discrete_StateInfo;
+
+struct SMU72_Discrete_DpmTable {
+	/* Multi-DPM controller settings */
+	SMU72_PIDController                  GraphicsPIDController;
+	SMU72_PIDController                  MemoryPIDController;
+	SMU72_PIDController                  LinkPIDController;
+
+	uint32_t                            SystemFlags;
+
+	/* SMIO masks for voltage and phase controls */
+	uint32_t                            VRConfig;
+	uint32_t                            SmioMask1;
+	uint32_t                            SmioMask2;
+	SMIO_Table                          SmioTable1;
+	SMIO_Table                          SmioTable2;
+
+	uint32_t                            VddcLevelCount;
+	uint32_t                            VddciLevelCount;
+	uint32_t                            VddGfxLevelCount;
+	uint32_t                            MvddLevelCount;
+
+	uint16_t                            VddcTable[SMU72_MAX_LEVELS_VDDC];
+	uint16_t                            VddGfxTable[SMU72_MAX_LEVELS_VDDGFX];
+	uint16_t                            VddciTable[SMU72_MAX_LEVELS_VDDCI];
+
+	uint8_t                             BapmVddGfxVidHiSidd[SMU72_MAX_LEVELS_VDDGFX];
+	uint8_t                             BapmVddGfxVidLoSidd[SMU72_MAX_LEVELS_VDDGFX];
+	uint8_t                             BapmVddGfxVidHiSidd2[SMU72_MAX_LEVELS_VDDGFX];
+
+	uint8_t                             BapmVddcVidHiSidd[SMU72_MAX_LEVELS_VDDC];
+	uint8_t                             BapmVddcVidLoSidd[SMU72_MAX_LEVELS_VDDC];
+	uint8_t                             BapmVddcVidHiSidd2[SMU72_MAX_LEVELS_VDDC];
+
+	uint8_t                             GraphicsDpmLevelCount;
+	uint8_t                             MemoryDpmLevelCount;
+	uint8_t                             LinkLevelCount;
+	uint8_t                             MasterDeepSleepControl;
+
+	uint8_t                             UvdLevelCount;
+	uint8_t                             VceLevelCount;
+	uint8_t                             AcpLevelCount;
+	uint8_t                             SamuLevelCount;
+
+	uint8_t                             ThermOutGpio;
+	uint8_t                             ThermOutPolarity;
+	uint8_t                             ThermOutMode;
+	uint8_t                             DPMFreezeAndForced;
+	uint32_t                            Reserved[4];
+
+	/* State table entries for each DPM state */
+	SMU72_Discrete_GraphicsLevel        GraphicsLevel[SMU72_MAX_LEVELS_GRAPHICS];
+	SMU72_Discrete_MemoryLevel          MemoryACPILevel;
+	SMU72_Discrete_MemoryLevel          MemoryLevel[SMU72_MAX_LEVELS_MEMORY];
+	SMU72_Discrete_LinkLevel            LinkLevel[SMU72_MAX_LEVELS_LINK];
+	SMU72_Discrete_ACPILevel            ACPILevel;
+	SMU72_Discrete_UvdLevel             UvdLevel[SMU72_MAX_LEVELS_UVD];
+	SMU72_Discrete_ExtClkLevel          VceLevel[SMU72_MAX_LEVELS_VCE];
+	SMU72_Discrete_ExtClkLevel          AcpLevel[SMU72_MAX_LEVELS_ACP];
+	SMU72_Discrete_ExtClkLevel          SamuLevel[SMU72_MAX_LEVELS_SAMU];
+	SMU72_Discrete_Ulv                  Ulv;
+
+	uint32_t                            SclkStepSize;
+	uint32_t                            Smio[SMU72_MAX_ENTRIES_SMIO];
+
+	uint8_t                             UvdBootLevel;
+	uint8_t                             VceBootLevel;
+	uint8_t                             AcpBootLevel;
+	uint8_t                             SamuBootLevel;
+
+	uint8_t                             GraphicsBootLevel;
+	uint8_t                             GraphicsVoltageChangeEnable;
+	uint8_t                             GraphicsThermThrottleEnable;
+	uint8_t                             GraphicsInterval;
+
+	uint8_t                             VoltageInterval;
+	uint8_t                             ThermalInterval;
+	uint16_t                            TemperatureLimitHigh;
+
+	uint16_t                            TemperatureLimitLow;
+	uint8_t                             MemoryBootLevel;
+	uint8_t                             MemoryVoltageChangeEnable;
+
+	uint16_t                            BootMVdd;
+	uint8_t                             MemoryInterval;
+	uint8_t                             MemoryThermThrottleEnable;
+
+	uint16_t                            VoltageResponseTime;
+	uint16_t                            PhaseResponseTime;
+
+	uint8_t                             PCIeBootLinkLevel;
+	uint8_t                             PCIeGenInterval;
+	uint8_t                             DTEInterval;
+	uint8_t                             DTEMode;
+
+	uint8_t                             SVI2Enable;
+	uint8_t                             VRHotGpio;
+	uint8_t                             AcDcGpio;
+	uint8_t                             ThermGpio;
+
+	uint16_t                            PPM_PkgPwrLimit;
+	uint16_t                            PPM_TemperatureLimit;
+
+	uint16_t                            DefaultTdp;
+	uint16_t                            TargetTdp;
+
+	uint16_t                            FpsHighThreshold;
+	uint16_t                            FpsLowThreshold;
+
+	uint16_t                            BAPMTI_R[SMU72_DTE_ITERATIONS][SMU72_DTE_SOURCES][SMU72_DTE_SINKS];
+	uint16_t                            BAPMTI_RC[SMU72_DTE_ITERATIONS][SMU72_DTE_SOURCES][SMU72_DTE_SINKS];
+
+	uint8_t                             DTEAmbientTempBase;
+	uint8_t                             DTETjOffset;
+	uint8_t                             GpuTjMax;
+	uint8_t                             GpuTjHyst;
+
+	SMU_VoltageLevel                    BootVoltage;
+
+	uint32_t                            BAPM_TEMP_GRADIENT;
+
+	uint32_t                            LowSclkInterruptThreshold;
+	uint32_t                            VddGfxReChkWait;
+
+	uint8_t                             ClockStretcherAmount;
+
+	uint8_t                             Sclk_CKS_masterEn0_7;
+	uint8_t                             Sclk_CKS_masterEn8_15;
+	uint8_t                             padding[1];
+
+	uint8_t                             Sclk_voltageOffset[8];
+
+	SMU_ClockStretcherDataTable         ClockStretcherDataTable;
+	SMU_CKS_LOOKUPTable                 CKS_LOOKUPTable;
+};
+
+typedef struct SMU72_Discrete_DpmTable SMU72_Discrete_DpmTable;
+
+/* --------------------------------------------------- AC Timing Parameters ------------------------------------------------ */
+#define SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE 16
+#define SMU72_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT SMU72_MAX_LEVELS_MEMORY /* DPM */
+
+struct SMU72_Discrete_MCRegisterAddress {
+	uint16_t s0;
+	uint16_t s1;
+};
+
+typedef struct SMU72_Discrete_MCRegisterAddress SMU72_Discrete_MCRegisterAddress;
+
+struct SMU72_Discrete_MCRegisterSet {
+	uint32_t value[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMU72_Discrete_MCRegisterSet SMU72_Discrete_MCRegisterSet;
+
+struct SMU72_Discrete_MCRegisters {
+	uint8_t                             last;
+	uint8_t                             reserved[3];
+	SMU72_Discrete_MCRegisterAddress     address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+	SMU72_Discrete_MCRegisterSet         data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMU72_Discrete_MCRegisters SMU72_Discrete_MCRegisters;
+
+
+/* --------------------------------------------------- Fan Table ----------------------------------------------------------- */
+
+struct SMU72_Discrete_FanTable {
+	uint16_t FdoMode;
+	int16_t  TempMin;
+	int16_t  TempMed;
+	int16_t  TempMax;
+	int16_t  Slope1;
+	int16_t  Slope2;
+	int16_t  FdoMin;
+	int16_t  HystUp;
+	int16_t  HystDown;
+	int16_t  HystSlope;
+	int16_t  TempRespLim;
+	int16_t  TempCurr;
+	int16_t  SlopeCurr;
+	int16_t  PwmCurr;
+	uint32_t RefreshPeriod;
+	int16_t  FdoMax;
+	uint8_t  TempSrc;
+	int8_t   FanControl_GL_Flag;
+};
+
+typedef struct SMU72_Discrete_FanTable SMU72_Discrete_FanTable;
+
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG             4
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG_BIT         (0x1 << SMU7_DISCRETE_GPIO_SCLK_DEBUG)
+
+struct SMU7_MclkDpmScoreboard {
+
+	uint32_t PercentageBusy;
+
+	int32_t  PIDError;
+	int32_t  PIDIntegral;
+	int32_t  PIDOutput;
+
+	uint32_t SigmaDeltaAccum;
+	uint32_t SigmaDeltaOutput;
+	uint32_t SigmaDeltaLevel;
+
+	uint32_t UtilizationSetpoint;
+
+	uint8_t  TdpClampMode;
+	uint8_t  TdcClampMode;
+	uint8_t  ThermClampMode;
+	uint8_t  VoltageBusy;
+
+	int8_t   CurrLevel;
+	int8_t   TargLevel;
+	uint8_t  LevelChangeInProgress;
+	uint8_t  UpHyst;
+
+	uint8_t  DownHyst;
+	uint8_t  VoltageDownHyst;
+	uint8_t  DpmEnable;
+	uint8_t  DpmRunning;
+
+	uint8_t  DpmForce;
+	uint8_t  DpmForceLevel;
+	uint8_t  DisplayWatermark;
+	uint8_t  McArbIndex;
+
+	uint32_t MinimumPerfMclk;
+
+	uint8_t  AcpiReq;
+	uint8_t  AcpiAck;
+	uint8_t  MclkSwitchInProgress;
+	uint8_t  MclkSwitchCritical;
+
+	uint8_t  IgnoreVBlank;
+	uint8_t  TargetMclkIndex;
+	uint8_t  TargetMvddIndex;
+	uint8_t  MclkSwitchResult;
+
+	uint16_t VbiFailureCount;
+	uint8_t  VbiWaitCounter;
+	uint8_t  EnabledLevelsChange;
+
+	uint16_t LevelResidencyCountersN[SMU72_MAX_LEVELS_MEMORY];
+	uint16_t LevelSwitchCounters[SMU72_MAX_LEVELS_MEMORY];
+
+	void     (*TargetStateCalculator)(uint8_t);
+	void     (*SavedTargetStateCalculator)(uint8_t);
+
+	uint16_t AutoDpmInterval;
+	uint16_t AutoDpmRange;
+
+	uint16_t VbiTimeoutCount;
+	uint16_t MclkSwitchingTime;
+
+	uint8_t  fastSwitch;
+	uint8_t  Save_PIC_VDDGFX_EXIT;
+	uint8_t  Save_PIC_VDDGFX_ENTER;
+	uint8_t  padding;
+
+};
+
+typedef struct SMU7_MclkDpmScoreboard SMU7_MclkDpmScoreboard;
+
+struct SMU7_UlvScoreboard {
+	uint8_t     EnterUlv;
+	uint8_t     ExitUlv;
+	uint8_t     UlvActive;
+	uint8_t     WaitingForUlv;
+	uint8_t     UlvEnable;
+	uint8_t     UlvRunning;
+	uint8_t     UlvMasterEnable;
+	uint8_t     padding;
+	uint32_t    UlvAbortedCount;
+	uint32_t    UlvTimeStamp;
+};
+
+typedef struct SMU7_UlvScoreboard SMU7_UlvScoreboard;
+
+struct VddgfxSavedRegisters {
+	uint32_t GPU_DBG[3];
+	uint32_t MEC_BaseAddress_Hi;
+	uint32_t MEC_BaseAddress_Lo;
+	uint32_t THM_TMON0_CTRL2__RDIR_PRESENT;
+	uint32_t THM_TMON1_CTRL2__RDIR_PRESENT;
+	uint32_t CP_INT_CNTL;
+};
+
+typedef struct VddgfxSavedRegisters VddgfxSavedRegisters;
+
+struct SMU7_VddGfxScoreboard {
+	uint8_t     VddGfxEnable;
+	uint8_t     VddGfxActive;
+	uint8_t     VPUResetOccured;
+	uint8_t     padding;
+
+	uint32_t    VddGfxEnteredCount;
+	uint32_t    VddGfxAbortedCount;
+
+	uint32_t    VddGfxVid;
+
+	VddgfxSavedRegisters SavedRegisters;
+};
+
+typedef struct SMU7_VddGfxScoreboard SMU7_VddGfxScoreboard;
+
+struct SMU7_TdcLimitScoreboard {
+	uint8_t  Enable;
+	uint8_t  Running;
+	uint16_t Alpha;
+	uint32_t FilteredIddc;
+	uint32_t IddcLimit;
+	uint32_t IddcHyst;
+	SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_TdcLimitScoreboard SMU7_TdcLimitScoreboard;
+
+struct SMU7_PkgPwrLimitScoreboard {
+	uint8_t  Enable;
+	uint8_t  Running;
+	uint16_t Alpha;
+	uint32_t FilteredPkgPwr;
+	uint32_t Limit;
+	uint32_t Hyst;
+	uint32_t LimitFromDriver;
+	SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_PkgPwrLimitScoreboard SMU7_PkgPwrLimitScoreboard;
+
+struct SMU7_BapmScoreboard {
+	uint32_t source_powers[SMU72_DTE_SOURCES];
+	uint32_t source_powers_last[SMU72_DTE_SOURCES];
+	int32_t entity_temperatures[SMU72_NUM_GPU_TES];
+	int32_t initial_entity_temperatures[SMU72_NUM_GPU_TES];
+	int32_t Limit;
+	int32_t Hyst;
+	int32_t therm_influence_coeff_table[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS * 2];
+	int32_t therm_node_table[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
+	uint16_t ConfigTDPPowerScalar;
+	uint16_t FanSpeedPowerScalar;
+	uint16_t OverDrivePowerScalar;
+	uint16_t OverDriveLimitScalar;
+	uint16_t FinalPowerScalar;
+	uint8_t VariantID;
+	uint8_t spare997;
+
+	SMU7_HystController_Data HystControllerData;
+
+	int32_t temperature_gradient_slope;
+	int32_t temperature_gradient;
+	uint32_t measured_temperature;
+};
+
+
+typedef struct SMU7_BapmScoreboard SMU7_BapmScoreboard;
+
+struct SMU7_AcpiScoreboard {
+	uint32_t SavedInterruptMask[2];
+	uint8_t LastACPIRequest;
+	uint8_t CgBifResp;
+	uint8_t RequestType;
+	uint8_t Padding;
+	SMU72_Discrete_ACPILevel D0Level;
+};
+
+typedef struct SMU7_AcpiScoreboard SMU7_AcpiScoreboard;
+
+struct SMU72_Discrete_PmFuses {
+	/* dw1  */
+	uint8_t SviLoadLineEn;
+	uint8_t SviLoadLineVddC;
+	uint8_t SviLoadLineTrimVddC;
+	uint8_t SviLoadLineOffsetVddC;
+
+	/* dw2 */
+	uint16_t TDC_VDDC_PkgLimit;
+	uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
+	uint8_t TDC_MAWt;
+
+	/* dw3 */
+	uint8_t TdcWaterfallCtl;
+	uint8_t LPMLTemperatureMin;
+	uint8_t LPMLTemperatureMax;
+	uint8_t Reserved;
+
+	/* dw4-dw7  */
+	uint8_t LPMLTemperatureScaler[16];
+
+	/* dw8-dw9  */
+	int16_t FuzzyFan_ErrorSetDelta;
+	int16_t FuzzyFan_ErrorRateSetDelta;
+	int16_t FuzzyFan_PwmSetDelta;
+	uint16_t Reserved6;
+
+	/* dw10-dw14  */
+	uint8_t GnbLPML[16];
+
+	/* dw15 */
+	uint8_t GnbLPMLMaxVid;
+	uint8_t GnbLPMLMinVid;
+	uint8_t Reserved1[2];
+
+	/* dw16 */
+	uint16_t BapmVddCBaseLeakageHiSidd;
+	uint16_t BapmVddCBaseLeakageLoSidd;
+};
+
+typedef struct SMU72_Discrete_PmFuses SMU72_Discrete_PmFuses;
+
+struct SMU7_Discrete_Log_Header_Table {
+	uint32_t    version;
+	uint32_t    asic_id;
+	uint16_t    flags;
+	uint16_t    entry_size;
+	uint32_t    total_size;
+	uint32_t    num_of_entries;
+	uint8_t     type;
+	uint8_t     mode;
+	uint8_t     filler_0[2];
+	uint32_t    filler_1[2];
+};
+
+typedef struct SMU7_Discrete_Log_Header_Table SMU7_Discrete_Log_Header_Table;
+
+struct SMU7_Discrete_Log_Cntl {
+	uint8_t             Enabled;
+	uint8_t             Type;
+	uint8_t             padding[2];
+	uint32_t            BufferSize;
+	uint32_t            SamplesLogged;
+	uint32_t            SampleSize;
+	uint32_t            AddrL;
+	uint32_t            AddrH;
+};
+
+typedef struct SMU7_Discrete_Log_Cntl SMU7_Discrete_Log_Cntl;
+
+#define CAC_ACC_NW_NUM_OF_SIGNALS 87
+
+struct SMU7_Discrete_Cac_Collection_Table {
+	uint32_t temperature;
+	uint32_t cac_acc_nw[CAC_ACC_NW_NUM_OF_SIGNALS];
+};
+
+typedef struct SMU7_Discrete_Cac_Collection_Table SMU7_Discrete_Cac_Collection_Table;
+
+struct SMU7_Discrete_Cac_Verification_Table {
+	uint32_t VddcTotalPower;
+	uint32_t VddcLeakagePower;
+	uint32_t VddcConstantPower;
+	uint32_t VddcGfxDynamicPower;
+	uint32_t VddcUvdDynamicPower;
+	uint32_t VddcVceDynamicPower;
+	uint32_t VddcAcpDynamicPower;
+	uint32_t VddcPcieDynamicPower;
+	uint32_t VddcDceDynamicPower;
+	uint32_t VddcCurrent;
+	uint32_t VddcVoltage;
+	uint32_t VddciTotalPower;
+	uint32_t VddciLeakagePower;
+	uint32_t VddciConstantPower;
+	uint32_t VddciDynamicPower;
+	uint32_t Vddr1TotalPower;
+	uint32_t Vddr1LeakagePower;
+	uint32_t Vddr1ConstantPower;
+	uint32_t Vddr1DynamicPower;
+	uint32_t spare[4];
+	uint32_t temperature;
+};
+
+typedef struct SMU7_Discrete_Cac_Verification_Table SMU7_Discrete_Cac_Verification_Table;
+
+struct SMU7_Discrete_Pm_Status_Table {
+	/* Thermal entities */
+	int32_t T_meas_max;
+	int32_t T_meas_acc;
+	int32_t T_calc_max;
+	int32_t T_calc_acc;
+	uint32_t P_scalar_acc;
+	uint32_t P_calc_max;
+	uint32_t P_calc_acc;
+
+	/*Voltage domains */
+	uint32_t I_calc_max;
+	uint32_t I_calc_acc;
+	uint32_t I_calc_acc_vddci;
+	uint32_t V_calc_noload_acc;
+	uint32_t V_calc_load_acc;
+	uint32_t V_calc_noload_acc_vddci;
+	uint32_t P_meas_acc;
+	uint32_t V_meas_noload_acc;
+	uint32_t V_meas_load_acc;
+	uint32_t I_meas_acc;
+	uint32_t P_meas_acc_vddci;
+	uint32_t V_meas_noload_acc_vddci;
+	uint32_t V_meas_load_acc_vddci;
+	uint32_t I_meas_acc_vddci;
+
+	/*Frequency */
+	uint16_t Sclk_dpm_residency[8];
+	uint16_t Uvd_dpm_residency[8];
+	uint16_t Vce_dpm_residency[8];
+	uint16_t Mclk_dpm_residency[4];
+
+	/*Chip */
+	uint32_t P_vddci_acc;
+	uint32_t P_vddr1_acc;
+	uint32_t P_nte1_acc;
+	uint32_t PkgPwr_max;
+	uint32_t PkgPwr_acc;
+	uint32_t MclkSwitchingTime_max;
+	uint32_t MclkSwitchingTime_acc;
+	uint32_t FanPwm_acc;
+	uint32_t FanRpm_acc;
+
+	uint32_t AccCnt;
+};
+
+typedef struct SMU7_Discrete_Pm_Status_Table SMU7_Discrete_Pm_Status_Table;
+
+/*FIXME THESE NEED TO BE UPDATED */
+#define SMU7_SCLK_CAC 0x561
+#define SMU7_MCLK_CAC 0xF9
+#define SMU7_VCLK_CAC 0x2DE
+#define SMU7_DCLK_CAC 0x2DE
+#define SMU7_ECLK_CAC 0x25E
+#define SMU7_ACLK_CAC 0x25E
+#define SMU7_SAMCLK_CAC 0x25E
+#define SMU7_DISPCLK_CAC 0x100
+#define SMU7_CAC_CONSTANT 0x2EE3430
+#define SMU7_CAC_CONSTANT_SHIFT 18
+
+#define SMU7_VDDCI_MCLK_CONST        1765
+#define SMU7_VDDCI_MCLK_CONST_SHIFT  16
+#define SMU7_VDDCI_VDDCI_CONST       50958
+#define SMU7_VDDCI_VDDCI_CONST_SHIFT 14
+#define SMU7_VDDCI_CONST             11781
+
+#define SMU7_12C_VDDCI_MCLK_CONST        1623
+#define SMU7_12C_VDDCI_MCLK_CONST_SHIFT  15
+#define SMU7_12C_VDDCI_VDDCI_CONST       40088
+#define SMU7_12C_VDDCI_VDDCI_CONST_SHIFT 13
+#define SMU7_12C_VDDCI_CONST             20856
+
+#define SMU7_VDDCI_STROBE_PWR        1331
+
+#define SMU7_VDDR1_CONST            693
+#define SMU7_VDDR1_CAC_WEIGHT       20
+#define SMU7_VDDR1_CAC_WEIGHT_SHIFT 19
+#define SMU7_VDDR1_STROBE_PWR       512
+
+#define SMU7_AREA_COEFF_UVD 0xA78
+#define SMU7_AREA_COEFF_VCE 0x190A
+#define SMU7_AREA_COEFF_ACP 0x22D1
+#define SMU7_AREA_COEFF_SAMU 0x534
+
+/*ThermOutMode values */
+#define SMU7_THERM_OUT_MODE_DISABLE       0x0
+#define SMU7_THERM_OUT_MODE_THERM_ONLY    0x1
+#define SMU7_THERM_OUT_MODE_THERM_VRHOT   0x2
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+#endif
+
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu73.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu73.h
@@ -0,0 +1,720 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _SMU73_H_
+#define _SMU73_H_
+
+#pragma pack(push, 1)
+enum SID_OPTION {
+  SID_OPTION_HI,
+  SID_OPTION_LO,
+  SID_OPTION_COUNT
+};
+
+enum Poly3rdOrderCoeff {
+    LEAKAGE_TEMPERATURE_SCALAR,
+    LEAKAGE_VOLTAGE_SCALAR,
+    DYNAMIC_VOLTAGE_SCALAR,
+    POLY_3RD_ORDER_COUNT
+};
+
+struct SMU7_Poly3rdOrder_Data
+{
+    int32_t a;
+    int32_t b;
+    int32_t c;
+    int32_t d;
+    uint8_t a_shift;
+    uint8_t b_shift;
+    uint8_t c_shift;
+    uint8_t x_shift;
+};
+
+typedef struct SMU7_Poly3rdOrder_Data SMU7_Poly3rdOrder_Data;
+
+struct Power_Calculator_Data
+{
+  uint16_t NoLoadVoltage;
+  uint16_t LoadVoltage;
+  uint16_t Resistance;
+  uint16_t Temperature;
+  uint16_t BaseLeakage;
+  uint16_t LkgTempScalar;
+  uint16_t LkgVoltScalar;
+  uint16_t LkgAreaScalar;
+  uint16_t LkgPower;
+  uint16_t DynVoltScalar;
+  uint32_t Cac;
+  uint32_t DynPower;
+  uint32_t TotalCurrent;
+  uint32_t TotalPower;
+};
+
+typedef struct Power_Calculator_Data PowerCalculatorData_t;
+
+struct Gc_Cac_Weight_Data
+{
+  uint8_t index;
+  uint32_t value;
+};
+
+typedef struct Gc_Cac_Weight_Data GcCacWeight_Data;
+
+
+typedef struct {
+  uint32_t high;
+  uint32_t low;
+} data_64_t;
+
+typedef struct {
+  data_64_t high;
+  data_64_t low;
+} data_128_t;
+
+#define SMU__NUM_SCLK_DPM_STATE  8
+#define SMU__NUM_MCLK_DPM_LEVELS 4
+#define SMU__NUM_LCLK_DPM_LEVELS 8
+#define SMU__NUM_PCIE_DPM_LEVELS 8
+
+#define SMU7_CONTEXT_ID_SMC        1
+#define SMU7_CONTEXT_ID_VBIOS      2
+
+#define SMU73_MAX_LEVELS_VDDC            16
+#define SMU73_MAX_LEVELS_VDDGFX          16
+#define SMU73_MAX_LEVELS_VDDCI           8
+#define SMU73_MAX_LEVELS_MVDD            4
+
+#define SMU_MAX_SMIO_LEVELS              4
+
+#define SMU73_MAX_LEVELS_GRAPHICS        SMU__NUM_SCLK_DPM_STATE   // SCLK + SQ DPM + ULV
+#define SMU73_MAX_LEVELS_MEMORY          SMU__NUM_MCLK_DPM_LEVELS   // MCLK Levels DPM
+#define SMU73_MAX_LEVELS_GIO             SMU__NUM_LCLK_DPM_LEVELS  // LCLK Levels
+#define SMU73_MAX_LEVELS_LINK            SMU__NUM_PCIE_DPM_LEVELS  // PCIe speed and number of lanes.
+#define SMU73_MAX_LEVELS_UVD             8   // VCLK/DCLK levels for UVD.
+#define SMU73_MAX_LEVELS_VCE             8   // ECLK levels for VCE.
+#define SMU73_MAX_LEVELS_ACP             8   // ACLK levels for ACP.
+#define SMU73_MAX_LEVELS_SAMU            8   // SAMCLK levels for SAMU.
+#define SMU73_MAX_ENTRIES_SMIO           32  // Number of entries in SMIO table.
+
+#define DPM_NO_LIMIT 0
+#define DPM_NO_UP 1
+#define DPM_GO_DOWN 2
+#define DPM_GO_UP 3
+
+#define SMU7_FIRST_DPM_GRAPHICS_LEVEL    0
+#define SMU7_FIRST_DPM_MEMORY_LEVEL      0
+
+#define GPIO_CLAMP_MODE_VRHOT      1
+#define GPIO_CLAMP_MODE_THERM      2
+#define GPIO_CLAMP_MODE_DC         4
+
+#define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0
+#define SCRATCH_B_TARG_PCIE_INDEX_MASK  (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3
+#define SCRATCH_B_CURR_PCIE_INDEX_MASK  (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_UVD_INDEX_SHIFT  6
+#define SCRATCH_B_TARG_UVD_INDEX_MASK   (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT)
+#define SCRATCH_B_CURR_UVD_INDEX_SHIFT  9
+#define SCRATCH_B_CURR_UVD_INDEX_MASK   (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT)
+#define SCRATCH_B_TARG_VCE_INDEX_SHIFT  12
+#define SCRATCH_B_TARG_VCE_INDEX_MASK   (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_VCE_INDEX_SHIFT  15
+#define SCRATCH_B_CURR_VCE_INDEX_MASK   (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_ACP_INDEX_SHIFT  18
+#define SCRATCH_B_TARG_ACP_INDEX_MASK   (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT)
+#define SCRATCH_B_CURR_ACP_INDEX_SHIFT  21
+#define SCRATCH_B_CURR_ACP_INDEX_MASK   (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT)
+#define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24
+#define SCRATCH_B_TARG_SAMU_INDEX_MASK  (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT)
+#define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27
+#define SCRATCH_B_CURR_SAMU_INDEX_MASK  (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT)
+
+// Virtualization Defines
+#define CG_XDMA_MASK  0x1
+#define CG_XDMA_SHIFT 0
+#define CG_UVD_MASK   0x2
+#define CG_UVD_SHIFT  1
+#define CG_VCE_MASK   0x4
+#define CG_VCE_SHIFT  2
+#define CG_SAMU_MASK  0x8
+#define CG_SAMU_SHIFT 3
+#define CG_GFX_MASK   0x10
+#define CG_GFX_SHIFT  4
+#define CG_SDMA_MASK  0x20
+#define CG_SDMA_SHIFT 5
+#define CG_HDP_MASK   0x40
+#define CG_HDP_SHIFT  6
+#define CG_MC_MASK    0x80
+#define CG_MC_SHIFT   7
+#define CG_DRM_MASK   0x100
+#define CG_DRM_SHIFT  8
+#define CG_ROM_MASK   0x200
+#define CG_ROM_SHIFT  9
+#define CG_BIF_MASK   0x400
+#define CG_BIF_SHIFT  10
+
+#define SMU73_DTE_ITERATIONS 5
+#define SMU73_DTE_SOURCES 3
+#define SMU73_DTE_SINKS 1
+#define SMU73_NUM_CPU_TES 0
+#define SMU73_NUM_GPU_TES 1
+#define SMU73_NUM_NON_TES 2
+#define SMU73_DTE_FAN_SCALAR_MIN 0x100
+#define SMU73_DTE_FAN_SCALAR_MAX 0x166
+#define SMU73_DTE_FAN_TEMP_MAX 93
+#define SMU73_DTE_FAN_TEMP_MIN 83
+
+#define SMU73_THERMAL_INPUT_LOOP_COUNT 6
+#define SMU73_THERMAL_CLAMP_MODE_COUNT 8
+
+
+struct SMU7_HystController_Data
+{
+    uint16_t waterfall_up;
+    uint16_t waterfall_down;
+    uint16_t waterfall_limit;
+    uint16_t release_cnt;
+    uint16_t release_limit;
+    uint16_t spare;
+};
+
+typedef struct SMU7_HystController_Data SMU7_HystController_Data;
+
+struct SMU73_PIDController
+{
+    uint32_t Ki;
+    int32_t LFWindupUpperLim;
+    int32_t LFWindupLowerLim;
+    uint32_t StatePrecision;
+
+    uint32_t LfPrecision;
+    uint32_t LfOffset;
+    uint32_t MaxState;
+    uint32_t MaxLfFraction;
+    uint32_t StateShift;
+};
+
+typedef struct SMU73_PIDController SMU73_PIDController;
+
+struct SMU7_LocalDpmScoreboard
+{
+    uint32_t PercentageBusy;
+
+    int32_t  PIDError;
+    int32_t  PIDIntegral;
+    int32_t  PIDOutput;
+
+    uint32_t SigmaDeltaAccum;
+    uint32_t SigmaDeltaOutput;
+    uint32_t SigmaDeltaLevel;
+
+    uint32_t UtilizationSetpoint;
+
+    uint8_t  TdpClampMode;
+    uint8_t  TdcClampMode;
+    uint8_t  ThermClampMode;
+    uint8_t  VoltageBusy;
+
+    int8_t   CurrLevel;
+    int8_t   TargLevel;
+    uint8_t  LevelChangeInProgress;
+    uint8_t  UpHyst;
+
+    uint8_t  DownHyst;
+    uint8_t  VoltageDownHyst;
+    uint8_t  DpmEnable;
+    uint8_t  DpmRunning;
+
+    uint8_t  DpmForce;
+    uint8_t  DpmForceLevel;
+    uint8_t  DisplayWatermark;
+    uint8_t  McArbIndex;
+
+    uint32_t MinimumPerfSclk;
+
+    uint8_t  AcpiReq;
+    uint8_t  AcpiAck;
+    uint8_t  GfxClkSlow;
+    uint8_t  GpioClampMode;
+
+    uint8_t  spare2;
+    uint8_t  EnabledLevelsChange;
+    uint8_t  DteClampMode;
+    uint8_t  FpsClampMode;
+
+    uint16_t LevelResidencyCounters [SMU73_MAX_LEVELS_GRAPHICS];
+    uint16_t LevelSwitchCounters [SMU73_MAX_LEVELS_GRAPHICS];
+
+    void     (*TargetStateCalculator)(uint8_t);
+    void     (*SavedTargetStateCalculator)(uint8_t);
+
+    uint16_t AutoDpmInterval;
+    uint16_t AutoDpmRange;
+
+    uint8_t  FpsEnabled;
+    uint8_t  MaxPerfLevel;
+    uint8_t  AllowLowClkInterruptToHost;
+    uint8_t  FpsRunning;
+
+    uint32_t MaxAllowedFrequency;
+
+    uint32_t FilteredSclkFrequency;
+    uint32_t LastSclkFrequency;
+    uint32_t FilteredSclkFrequencyCnt;
+
+    uint8_t  LedEnable;
+    uint8_t  LedPin0;
+    uint8_t  LedPin1;
+    uint8_t  LedPin2;
+    uint32_t LedAndMask;
+
+    uint16_t FpsAlpha;
+    uint16_t DeltaTime;
+    uint32_t CurrentFps;
+    uint32_t FilteredFps;
+    uint32_t FrameCount;
+    uint32_t FrameCountLast;
+    uint16_t FpsTargetScalar;
+    uint16_t FpsWaterfallLimitScalar;
+    uint16_t FpsAlphaScalar;
+    uint16_t spare8;
+    SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_LocalDpmScoreboard SMU7_LocalDpmScoreboard;
+
+#define SMU7_MAX_VOLTAGE_CLIENTS 12
+
+typedef uint8_t (*VoltageChangeHandler_t)(uint16_t, uint8_t);
+
+#define VDDC_MASK    0x00007FFF
+#define VDDC_SHIFT   0
+#define VDDCI_MASK   0x3FFF8000
+#define VDDCI_SHIFT  15
+#define PHASES_MASK  0xC0000000
+#define PHASES_SHIFT 30
+
+typedef uint32_t SMU_VoltageLevel;
+
+struct SMU7_VoltageScoreboard
+{
+    SMU_VoltageLevel TargetVoltage;
+    uint16_t MaxVid;
+    uint8_t  HighestVidOffset;
+    uint8_t  CurrentVidOffset;
+
+    uint16_t CurrentVddc;
+    uint16_t CurrentVddci;
+
+
+    uint8_t  ControllerBusy;
+    uint8_t  CurrentVid;
+    uint8_t  CurrentVddciVid;
+    uint8_t  padding;
+
+    SMU_VoltageLevel RequestedVoltage[SMU7_MAX_VOLTAGE_CLIENTS];
+    SMU_VoltageLevel TargetVoltageState;
+    uint8_t  EnabledRequest[SMU7_MAX_VOLTAGE_CLIENTS];
+
+    uint8_t  padding2;
+    uint8_t  padding3;
+    uint8_t  ControllerEnable;
+    uint8_t  ControllerRunning;
+    uint16_t CurrentStdVoltageHiSidd;
+    uint16_t CurrentStdVoltageLoSidd;
+    uint8_t  OverrideVoltage;
+    uint8_t  padding4;
+    uint8_t  padding5;
+    uint8_t  CurrentPhases;
+
+    VoltageChangeHandler_t ChangeVddc;
+
+    VoltageChangeHandler_t ChangeVddci;
+    VoltageChangeHandler_t ChangePhase;
+    VoltageChangeHandler_t ChangeMvdd;
+
+    VoltageChangeHandler_t functionLinks[6];
+
+    uint16_t * VddcFollower1;
+
+    int16_t  Driver_OD_RequestedVidOffset1;
+    int16_t  Driver_OD_RequestedVidOffset2;
+
+};
+
+typedef struct SMU7_VoltageScoreboard SMU7_VoltageScoreboard;
+
+// -------------------------------------------------------------------------------------------------------------------------
+#define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */
+
+struct SMU7_PCIeLinkSpeedScoreboard
+{
+    uint8_t     DpmEnable;
+    uint8_t     DpmRunning;
+    uint8_t     DpmForce;
+    uint8_t     DpmForceLevel;
+
+    uint8_t     CurrentLinkSpeed;
+    uint8_t     EnabledLevelsChange;
+    uint16_t    AutoDpmInterval;
+
+    uint16_t    AutoDpmRange;
+    uint16_t    AutoDpmCount;
+
+    uint8_t     DpmMode;
+    uint8_t     AcpiReq;
+    uint8_t     AcpiAck;
+    uint8_t     CurrentLinkLevel;
+
+};
+
+typedef struct SMU7_PCIeLinkSpeedScoreboard SMU7_PCIeLinkSpeedScoreboard;
+
+// -------------------------------------------------------- CAC table ------------------------------------------------------
+#define SMU7_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMU7_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16
+
+#define SMU7_SCALE_I  7
+#define SMU7_SCALE_R 12
+
+struct SMU7_PowerScoreboard
+{
+    uint32_t GpuPower;
+
+    uint32_t VddcPower;
+    uint32_t VddcVoltage;
+    uint32_t VddcCurrent;
+
+    uint32_t MvddPower;
+    uint32_t MvddVoltage;
+    uint32_t MvddCurrent;
+
+    uint32_t RocPower;
+
+    uint16_t Telemetry_1_slope;
+    uint16_t Telemetry_2_slope;
+    int32_t  Telemetry_1_offset;
+    int32_t  Telemetry_2_offset;
+};
+typedef struct SMU7_PowerScoreboard SMU7_PowerScoreboard;
+
+// For FeatureEnables:
+#define SMU7_SCLK_DPM_CONFIG_MASK                        0x01
+#define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK              0x02
+#define SMU7_THERMAL_CONTROLLER_CONFIG_MASK              0x04
+#define SMU7_MCLK_DPM_CONFIG_MASK                        0x08
+#define SMU7_UVD_DPM_CONFIG_MASK                         0x10
+#define SMU7_VCE_DPM_CONFIG_MASK                         0x20
+#define SMU7_ACP_DPM_CONFIG_MASK                         0x40
+#define SMU7_SAMU_DPM_CONFIG_MASK                        0x80
+#define SMU7_PCIEGEN_DPM_CONFIG_MASK                    0x100
+
+#define SMU7_ACP_MCLK_HANDSHAKE_DISABLE                  0x00000001
+#define SMU7_ACP_SCLK_HANDSHAKE_DISABLE                  0x00000002
+#define SMU7_UVD_MCLK_HANDSHAKE_DISABLE                  0x00000100
+#define SMU7_UVD_SCLK_HANDSHAKE_DISABLE                  0x00000200
+#define SMU7_VCE_MCLK_HANDSHAKE_DISABLE                  0x00010000
+#define SMU7_VCE_SCLK_HANDSHAKE_DISABLE                  0x00020000
+
+// All 'soft registers' should be uint32_t.
+struct SMU73_SoftRegisters
+{
+    uint32_t        RefClockFrequency;
+    uint32_t        PmTimerPeriod;
+    uint32_t        FeatureEnables;
+
+    uint32_t        PreVBlankGap;
+    uint32_t        VBlankTimeout;
+    uint32_t        TrainTimeGap;
+
+    uint32_t        MvddSwitchTime;
+    uint32_t        LongestAcpiTrainTime;
+    uint32_t        AcpiDelay;
+    uint32_t        G5TrainTime;
+    uint32_t        DelayMpllPwron;
+    uint32_t        VoltageChangeTimeout;
+
+    uint32_t        HandshakeDisables;
+
+    uint8_t         DisplayPhy1Config;
+    uint8_t         DisplayPhy2Config;
+    uint8_t         DisplayPhy3Config;
+    uint8_t         DisplayPhy4Config;
+
+    uint8_t         DisplayPhy5Config;
+    uint8_t         DisplayPhy6Config;
+    uint8_t         DisplayPhy7Config;
+    uint8_t         DisplayPhy8Config;
+
+    uint32_t        AverageGraphicsActivity;
+    uint32_t        AverageMemoryActivity;
+    uint32_t        AverageGioActivity;
+
+    uint8_t         SClkDpmEnabledLevels;
+    uint8_t         MClkDpmEnabledLevels;
+    uint8_t         LClkDpmEnabledLevels;
+    uint8_t         PCIeDpmEnabledLevels;
+
+    uint8_t         UVDDpmEnabledLevels;
+    uint8_t         SAMUDpmEnabledLevels;
+    uint8_t         ACPDpmEnabledLevels;
+    uint8_t         VCEDpmEnabledLevels;
+
+    uint32_t        DRAM_LOG_ADDR_H;
+    uint32_t        DRAM_LOG_ADDR_L;
+    uint32_t        DRAM_LOG_PHY_ADDR_H;
+    uint32_t        DRAM_LOG_PHY_ADDR_L;
+    uint32_t        DRAM_LOG_BUFF_SIZE;
+    uint32_t        UlvEnterCount;
+    uint32_t        UlvTime;
+    uint32_t        UcodeLoadStatus;
+    uint32_t        Reserved[2];
+
+};
+
+typedef struct SMU73_SoftRegisters SMU73_SoftRegisters;
+
+struct SMU73_Firmware_Header
+{
+    uint32_t Digest[5];
+    uint32_t Version;
+    uint32_t HeaderSize;
+    uint32_t Flags;
+    uint32_t EntryPoint;
+    uint32_t CodeSize;
+    uint32_t ImageSize;
+
+    uint32_t Rtos;
+    uint32_t SoftRegisters;
+    uint32_t DpmTable;
+    uint32_t FanTable;
+    uint32_t CacConfigTable;
+    uint32_t CacStatusTable;
+
+
+    uint32_t mcRegisterTable;
+
+
+    uint32_t mcArbDramTimingTable;
+
+
+
+
+    uint32_t PmFuseTable;
+    uint32_t Globals;
+    uint32_t ClockStretcherTable;
+    uint32_t Reserved[41];
+    uint32_t Signature;
+};
+
+typedef struct SMU73_Firmware_Header SMU73_Firmware_Header;
+
+#define SMU7_FIRMWARE_HEADER_LOCATION 0x20000
+
+enum  DisplayConfig {
+    PowerDown = 1,
+    DP54x4,
+    DP54x2,
+    DP54x1,
+    DP27x4,
+    DP27x2,
+    DP27x1,
+    HDMI297,
+    HDMI162,
+    LVDS,
+    DP324x4,
+    DP324x2,
+    DP324x1
+};
+
+
+#define MC_BLOCK_COUNT 1
+#define CPL_BLOCK_COUNT 5
+#define SE_BLOCK_COUNT 15
+#define GC_BLOCK_COUNT 24
+
+struct SMU7_Local_Cac {
+  uint8_t BlockId;
+  uint8_t SignalId;
+  uint8_t Threshold;
+  uint8_t Padding;
+};
+
+typedef struct SMU7_Local_Cac SMU7_Local_Cac;
+
+struct SMU7_Local_Cac_Table {
+
+  SMU7_Local_Cac CplLocalCac[CPL_BLOCK_COUNT];
+  SMU7_Local_Cac McLocalCac[MC_BLOCK_COUNT];
+  SMU7_Local_Cac SeLocalCac[SE_BLOCK_COUNT];
+  SMU7_Local_Cac GcLocalCac[GC_BLOCK_COUNT];
+};
+
+typedef struct SMU7_Local_Cac_Table SMU7_Local_Cac_Table;
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+#endif
+
+// Description of Clock Gating bitmask for Tonga:
+// System Clock Gating
+#define CG_SYS_BITMASK_FIRST_BIT      0  // First bit of Sys CG bitmask
+#define CG_SYS_BITMASK_LAST_BIT       9  // Last bit of Sys CG bitmask
+#define CG_SYS_BIF_MGLS_SHIFT         0
+#define CG_SYS_ROM_SHIFT              1
+#define CG_SYS_MC_MGCG_SHIFT          2
+#define CG_SYS_MC_MGLS_SHIFT          3
+#define CG_SYS_SDMA_MGCG_SHIFT        4
+#define CG_SYS_SDMA_MGLS_SHIFT        5
+#define CG_SYS_DRM_MGCG_SHIFT         6
+#define CG_SYS_HDP_MGCG_SHIFT         7
+#define CG_SYS_HDP_MGLS_SHIFT         8
+#define CG_SYS_DRM_MGLS_SHIFT         9
+
+#define CG_SYS_BIF_MGLS_MASK          0x1
+#define CG_SYS_ROM_MASK               0x2
+#define CG_SYS_MC_MGCG_MASK           0x4
+#define CG_SYS_MC_MGLS_MASK           0x8
+#define CG_SYS_SDMA_MGCG_MASK         0x10
+#define CG_SYS_SDMA_MGLS_MASK         0x20
+#define CG_SYS_DRM_MGCG_MASK          0x40
+#define CG_SYS_HDP_MGCG_MASK          0x80
+#define CG_SYS_HDP_MGLS_MASK          0x100
+#define CG_SYS_DRM_MGLS_MASK          0x200
+
+// Graphics Clock Gating
+#define CG_GFX_BITMASK_FIRST_BIT      16 // First bit of Gfx CG bitmask
+#define CG_GFX_BITMASK_LAST_BIT       20 // Last bit of Gfx CG bitmask
+#define CG_GFX_CGCG_SHIFT             16
+#define CG_GFX_CGLS_SHIFT             17
+#define CG_CPF_MGCG_SHIFT             18
+#define CG_RLC_MGCG_SHIFT             19
+#define CG_GFX_OTHERS_MGCG_SHIFT      20
+
+#define CG_GFX_CGCG_MASK              0x00010000
+#define CG_GFX_CGLS_MASK              0x00020000
+#define CG_CPF_MGCG_MASK              0x00040000
+#define CG_RLC_MGCG_MASK              0x00080000
+#define CG_GFX_OTHERS_MGCG_MASK       0x00100000
+
+
+
+// Voltage Regulator Configuration
+// VR Config info is contained in dpmTable.VRConfig
+
+#define VRCONF_VDDC_MASK         0x000000FF
+#define VRCONF_VDDC_SHIFT        0
+#define VRCONF_VDDGFX_MASK       0x0000FF00
+#define VRCONF_VDDGFX_SHIFT      8
+#define VRCONF_VDDCI_MASK        0x00FF0000
+#define VRCONF_VDDCI_SHIFT       16
+#define VRCONF_MVDD_MASK         0xFF000000
+#define VRCONF_MVDD_SHIFT        24
+
+#define VR_MERGED_WITH_VDDC      0
+#define VR_SVI2_PLANE_1          1
+#define VR_SVI2_PLANE_2          2
+#define VR_SMIO_PATTERN_1        3
+#define VR_SMIO_PATTERN_2        4
+#define VR_STATIC_VOLTAGE        5
+
+// Clock Stretcher Configuration
+
+#define CLOCK_STRETCHER_MAX_ENTRIES 0x4
+#define CKS_LOOKUPTable_MAX_ENTRIES 0x4
+
+// The 'settings' field is subdivided in the following way:
+#define CLOCK_STRETCHER_SETTING_DDT_MASK             0x01
+#define CLOCK_STRETCHER_SETTING_DDT_SHIFT            0x0
+#define CLOCK_STRETCHER_SETTING_STRETCH_AMOUNT_MASK  0x1E
+#define CLOCK_STRETCHER_SETTING_STRETCH_AMOUNT_SHIFT 0x1
+#define CLOCK_STRETCHER_SETTING_ENABLE_MASK          0x80
+#define CLOCK_STRETCHER_SETTING_ENABLE_SHIFT         0x7
+
+struct SMU_ClockStretcherDataTableEntry {
+  uint8_t minVID;
+  uint8_t maxVID;
+
+
+  uint16_t setting;
+};
+typedef struct SMU_ClockStretcherDataTableEntry SMU_ClockStretcherDataTableEntry;
+
+struct SMU_ClockStretcherDataTable {
+  SMU_ClockStretcherDataTableEntry ClockStretcherDataTableEntry[CLOCK_STRETCHER_MAX_ENTRIES];
+};
+typedef struct SMU_ClockStretcherDataTable SMU_ClockStretcherDataTable;
+
+struct SMU_CKS_LOOKUPTableEntry {
+  uint16_t minFreq;
+  uint16_t maxFreq;
+
+  uint8_t setting;
+  uint8_t padding[3];
+};
+typedef struct SMU_CKS_LOOKUPTableEntry SMU_CKS_LOOKUPTableEntry;
+
+struct SMU_CKS_LOOKUPTable {
+  SMU_CKS_LOOKUPTableEntry CKS_LOOKUPTableEntry[CKS_LOOKUPTable_MAX_ENTRIES];
+};
+typedef struct SMU_CKS_LOOKUPTable SMU_CKS_LOOKUPTable;
+
+struct AgmAvfsData_t {
+  uint16_t avgPsmCount[28];
+  uint16_t minPsmCount[28];
+};
+typedef struct AgmAvfsData_t AgmAvfsData_t;
+
+// AVFS DEFINES
+
+enum VFT_COLUMNS {
+  SCLK0,
+  SCLK1,
+  SCLK2,
+  SCLK3,
+  SCLK4,
+  SCLK5,
+  SCLK6,
+  SCLK7,
+
+  NUM_VFT_COLUMNS
+};
+
+#define TEMP_RANGE_MAXSTEPS 12
+struct VFT_CELL_t {
+  uint16_t Voltage;
+};
+
+typedef struct VFT_CELL_t VFT_CELL_t;
+
+struct VFT_TABLE_t {
+  VFT_CELL_t    Cell[TEMP_RANGE_MAXSTEPS][NUM_VFT_COLUMNS];
+  uint16_t      AvfsGbv [NUM_VFT_COLUMNS];
+  uint16_t      BtcGbv  [NUM_VFT_COLUMNS];
+  uint16_t      Temperature [TEMP_RANGE_MAXSTEPS];
+
+  uint8_t       NumTemperatureSteps;
+  uint8_t       padding[3];
+};
+typedef struct VFT_TABLE_t VFT_TABLE_t;
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu73_discrete.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu73_discrete.h
@@ -0,0 +1,799 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _SMU73_DISCRETE_H_
+#define _SMU73_DISCRETE_H_
+
+#include "smu73.h"
+
+#pragma pack(push, 1)
+
+struct SMIO_Pattern
+{
+  uint16_t Voltage;
+  uint8_t  Smio;
+  uint8_t  padding;
+};
+
+typedef struct SMIO_Pattern SMIO_Pattern;
+
+struct SMIO_Table
+{
+  SMIO_Pattern Pattern[SMU_MAX_SMIO_LEVELS];
+};
+
+typedef struct SMIO_Table SMIO_Table;
+
+struct SMU73_Discrete_GraphicsLevel {
+	uint32_t    MinVoltage;
+
+	uint32_t    SclkFrequency;
+
+	uint8_t     pcieDpmLevel;
+	uint8_t     DeepSleepDivId;
+	uint16_t    ActivityLevel;
+	uint32_t    CgSpllFuncCntl3;
+	uint32_t    CgSpllFuncCntl4;
+	uint32_t    SpllSpreadSpectrum;
+	uint32_t    SpllSpreadSpectrum2;
+	uint32_t    CcPwrDynRm;
+	uint32_t    CcPwrDynRm1;
+	uint8_t     SclkDid;
+	uint8_t     DisplayWatermark;
+	uint8_t     EnabledForActivity;
+	uint8_t     EnabledForThrottle;
+	uint8_t     UpHyst;
+	uint8_t     DownHyst;
+	uint8_t     VoltageDownHyst;
+	uint8_t     PowerThrottle;
+};
+
+typedef struct SMU73_Discrete_GraphicsLevel SMU73_Discrete_GraphicsLevel;
+
+struct SMU73_Discrete_ACPILevel {
+    uint32_t    Flags;
+    uint32_t MinVoltage;
+    uint32_t    SclkFrequency;
+    uint8_t     SclkDid;
+    uint8_t     DisplayWatermark;
+    uint8_t     DeepSleepDivId;
+    uint8_t     padding;
+    uint32_t    CgSpllFuncCntl;
+    uint32_t    CgSpllFuncCntl2;
+    uint32_t    CgSpllFuncCntl3;
+    uint32_t    CgSpllFuncCntl4;
+    uint32_t    SpllSpreadSpectrum;
+    uint32_t    SpllSpreadSpectrum2;
+    uint32_t    CcPwrDynRm;
+    uint32_t    CcPwrDynRm1;
+};
+
+typedef struct SMU73_Discrete_ACPILevel SMU73_Discrete_ACPILevel;
+
+struct SMU73_Discrete_Ulv {
+	uint32_t    CcPwrDynRm;
+	uint32_t    CcPwrDynRm1;
+	uint16_t    VddcOffset;
+	uint8_t     VddcOffsetVid;
+	uint8_t     VddcPhase;
+	uint32_t    Reserved;
+};
+
+typedef struct SMU73_Discrete_Ulv SMU73_Discrete_Ulv;
+
+struct SMU73_Discrete_MemoryLevel
+{
+    uint32_t MinVoltage;
+    uint32_t    MinMvdd;
+
+    uint32_t    MclkFrequency;
+
+    uint8_t     StutterEnable;
+    uint8_t     FreqRange;
+    uint8_t     EnabledForThrottle;
+    uint8_t     EnabledForActivity;
+
+    uint8_t     UpHyst;
+    uint8_t     DownHyst;
+    uint8_t     VoltageDownHyst;
+    uint8_t     padding;
+
+    uint16_t    ActivityLevel;
+    uint8_t     DisplayWatermark;
+    uint8_t     MclkDivider;
+};
+
+typedef struct SMU73_Discrete_MemoryLevel SMU73_Discrete_MemoryLevel;
+
+struct SMU73_Discrete_LinkLevel
+{
+    uint8_t     PcieGenSpeed;           ///< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3
+    uint8_t     PcieLaneCount;          ///< 1=x1, 2=x2, 3=x4, 4=x8, 5=x12, 6=x16 
+    uint8_t     EnabledForActivity;
+    uint8_t     SPC;
+    uint32_t    DownThreshold;
+    uint32_t    UpThreshold;
+    uint32_t    Reserved;
+};
+
+typedef struct SMU73_Discrete_LinkLevel SMU73_Discrete_LinkLevel;
+
+
+// MC ARB DRAM Timing registers.
+struct SMU73_Discrete_MCArbDramTimingTableEntry
+{
+    uint32_t McArbDramTiming;
+    uint32_t McArbDramTiming2;
+    uint8_t  McArbBurstTime;
+    uint8_t  TRRDS;
+    uint8_t  TRRDL;
+    uint8_t  padding;
+};
+
+typedef struct SMU73_Discrete_MCArbDramTimingTableEntry SMU73_Discrete_MCArbDramTimingTableEntry;
+
+struct SMU73_Discrete_MCArbDramTimingTable
+{
+    SMU73_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS];
+};
+
+typedef struct SMU73_Discrete_MCArbDramTimingTable SMU73_Discrete_MCArbDramTimingTable;
+
+// UVD VCLK/DCLK state (level) definition.
+struct SMU73_Discrete_UvdLevel
+{
+    uint32_t VclkFrequency;
+    uint32_t DclkFrequency;
+    uint32_t MinVoltage;
+    uint8_t  VclkDivider;
+    uint8_t  DclkDivider;
+    uint8_t  padding[2];
+};
+
+typedef struct SMU73_Discrete_UvdLevel SMU73_Discrete_UvdLevel;
+
+// Clocks for other external blocks (VCE, ACP, SAMU).
+struct SMU73_Discrete_ExtClkLevel
+{
+    uint32_t Frequency;
+    uint32_t MinVoltage;
+    uint8_t  Divider;
+    uint8_t  padding[3];
+};
+
+typedef struct SMU73_Discrete_ExtClkLevel SMU73_Discrete_ExtClkLevel;
+
+struct SMU73_Discrete_StateInfo
+{
+    uint32_t SclkFrequency;
+    uint32_t MclkFrequency;
+    uint32_t VclkFrequency;
+    uint32_t DclkFrequency;
+    uint32_t SamclkFrequency;
+    uint32_t AclkFrequency;
+    uint32_t EclkFrequency;
+    uint16_t MvddVoltage;
+    uint16_t padding16;
+    uint8_t  DisplayWatermark;
+    uint8_t  McArbIndex;
+    uint8_t  McRegIndex;
+    uint8_t  SeqIndex;
+    uint8_t  SclkDid;
+    int8_t   SclkIndex;
+    int8_t   MclkIndex;
+    uint8_t  PCIeGen;
+
+};
+
+typedef struct SMU73_Discrete_StateInfo SMU73_Discrete_StateInfo;
+
+struct SMU73_Discrete_DpmTable
+{
+    // Multi-DPM controller settings
+    SMU73_PIDController                  GraphicsPIDController;
+    SMU73_PIDController                  MemoryPIDController;
+    SMU73_PIDController                  LinkPIDController;
+
+    uint32_t                            SystemFlags;
+
+    // SMIO masks for voltage and phase controls
+    uint32_t                            VRConfig;
+    uint32_t                            SmioMask1;
+    uint32_t                            SmioMask2;
+    SMIO_Table                          SmioTable1;
+    SMIO_Table                          SmioTable2;
+
+    uint32_t                            MvddLevelCount;
+
+
+    uint8_t                             BapmVddcVidHiSidd        [SMU73_MAX_LEVELS_VDDC];
+    uint8_t                             BapmVddcVidLoSidd        [SMU73_MAX_LEVELS_VDDC];
+    uint8_t                             BapmVddcVidHiSidd2       [SMU73_MAX_LEVELS_VDDC];
+
+    uint8_t                             GraphicsDpmLevelCount;
+    uint8_t                             MemoryDpmLevelCount;
+    uint8_t                             LinkLevelCount;
+    uint8_t                             MasterDeepSleepControl;
+
+    uint8_t                             UvdLevelCount;
+    uint8_t                             VceLevelCount;
+    uint8_t                             AcpLevelCount;
+    uint8_t                             SamuLevelCount;
+
+    uint8_t                             ThermOutGpio;
+    uint8_t                             ThermOutPolarity;
+    uint8_t                             ThermOutMode;
+    uint8_t                             BootPhases;
+    uint32_t                            Reserved[4];
+
+    // State table entries for each DPM state
+    SMU73_Discrete_GraphicsLevel        GraphicsLevel           [SMU73_MAX_LEVELS_GRAPHICS];
+    SMU73_Discrete_MemoryLevel          MemoryACPILevel;
+    SMU73_Discrete_MemoryLevel          MemoryLevel             [SMU73_MAX_LEVELS_MEMORY];
+    SMU73_Discrete_LinkLevel            LinkLevel               [SMU73_MAX_LEVELS_LINK];
+    SMU73_Discrete_ACPILevel            ACPILevel;
+    SMU73_Discrete_UvdLevel             UvdLevel                [SMU73_MAX_LEVELS_UVD];
+    SMU73_Discrete_ExtClkLevel          VceLevel                [SMU73_MAX_LEVELS_VCE];
+    SMU73_Discrete_ExtClkLevel          AcpLevel                [SMU73_MAX_LEVELS_ACP];
+    SMU73_Discrete_ExtClkLevel          SamuLevel               [SMU73_MAX_LEVELS_SAMU];
+    SMU73_Discrete_Ulv                  Ulv;
+
+    uint32_t                            SclkStepSize;
+    uint32_t                            Smio                    [SMU73_MAX_ENTRIES_SMIO];
+
+    uint8_t                             UvdBootLevel;
+    uint8_t                             VceBootLevel;
+    uint8_t                             AcpBootLevel;
+    uint8_t                             SamuBootLevel;
+
+    uint8_t                             GraphicsBootLevel;
+    uint8_t                             GraphicsVoltageChangeEnable;
+    uint8_t                             GraphicsThermThrottleEnable;
+    uint8_t                             GraphicsInterval;
+
+    uint8_t                             VoltageInterval;
+    uint8_t                             ThermalInterval;
+    uint16_t                            TemperatureLimitHigh;
+
+    uint16_t                            TemperatureLimitLow;
+    uint8_t                             MemoryBootLevel;
+    uint8_t                             MemoryVoltageChangeEnable;
+
+    uint16_t                            BootMVdd;
+    uint8_t                             MemoryInterval;
+    uint8_t                             MemoryThermThrottleEnable;
+
+    uint16_t                            VoltageResponseTime;
+    uint16_t                            PhaseResponseTime;
+
+    uint8_t                             PCIeBootLinkLevel;
+    uint8_t                             PCIeGenInterval;
+    uint8_t                             DTEInterval;
+    uint8_t                             DTEMode;
+
+    uint8_t                             SVI2Enable;
+    uint8_t                             VRHotGpio;
+    uint8_t                             AcDcGpio;
+    uint8_t                             ThermGpio;
+
+    uint16_t                            PPM_PkgPwrLimit;
+    uint16_t                            PPM_TemperatureLimit;
+
+    uint16_t                            DefaultTdp;
+    uint16_t                            TargetTdp;
+
+    uint16_t                            FpsHighThreshold;
+    uint16_t                            FpsLowThreshold;
+
+    uint16_t                            TemperatureLimitEdge;
+    uint16_t                            TemperatureLimitHotspot;
+    uint16_t                            TemperatureLimitLiquid1;
+    uint16_t                            TemperatureLimitLiquid2;
+    uint16_t                            TemperatureLimitVrVddc;
+    uint16_t                            TemperatureLimitVrMvdd;
+    uint16_t                            TemperatureLimitPlx;
+
+    uint16_t                            FanGainEdge;
+    uint16_t                            FanGainHotspot;
+    uint16_t                            FanGainLiquid;
+    uint16_t                            FanGainVrVddc;
+    uint16_t                            FanGainVrMvdd;
+    uint16_t                            FanGainPlx;
+    uint16_t                            FanGainHbm;
+
+    uint8_t                             Liquid1_I2C_address;
+    uint8_t                             Liquid2_I2C_address;
+    uint8_t                             Vr_I2C_address;
+    uint8_t                             Plx_I2C_address;
+
+    uint8_t                             GeminiMode;
+    uint8_t                             spare17[3];
+    uint32_t                            GeminiApertureHigh;
+    uint32_t                            GeminiApertureLow;
+
+    uint8_t                             Liquid_I2C_LineSCL;
+    uint8_t                             Liquid_I2C_LineSDA;
+    uint8_t                             Vr_I2C_LineSCL;
+    uint8_t                             Vr_I2C_LineSDA;
+    uint8_t                             Plx_I2C_LineSCL;
+    uint8_t                             Plx_I2C_LineSDA;
+
+    uint8_t                             spare1253[2];
+    uint32_t                            spare123[2];
+
+    uint8_t                             DTEAmbientTempBase;
+    uint8_t                             DTETjOffset;
+    uint8_t                             GpuTjMax;
+    uint8_t                             GpuTjHyst;
+
+    uint16_t                            BootVddc;
+    uint16_t                            BootVddci;
+
+    uint32_t                            BAPM_TEMP_GRADIENT;
+
+    uint32_t                            LowSclkInterruptThreshold;
+    uint32_t                            VddGfxReChkWait;
+
+    uint8_t                             ClockStretcherAmount;
+    uint8_t                             Sclk_CKS_masterEn0_7;
+    uint8_t                             Sclk_CKS_masterEn8_15;
+    uint8_t                             DPMFreezeAndForced;
+
+    uint8_t                             Sclk_voltageOffset[8];
+
+    SMU_ClockStretcherDataTable         ClockStretcherDataTable;
+    SMU_CKS_LOOKUPTable                 CKS_LOOKUPTable;
+};
+
+typedef struct SMU73_Discrete_DpmTable SMU73_Discrete_DpmTable;
+
+
+// --------------------------------------------------- Fan Table -----------------------------------------------------------
+struct SMU73_Discrete_FanTable
+{
+    uint16_t FdoMode;
+    int16_t  TempMin;
+    int16_t  TempMed;
+    int16_t  TempMax;
+    int16_t  Slope1;
+    int16_t  Slope2;
+    int16_t  FdoMin;
+    int16_t  HystUp;
+    int16_t  HystDown;
+    int16_t  HystSlope;
+    int16_t  TempRespLim;
+    int16_t  TempCurr;
+    int16_t  SlopeCurr;
+    int16_t  PwmCurr;
+    uint32_t RefreshPeriod;
+    int16_t  FdoMax;
+    uint8_t  TempSrc;
+    int8_t   Padding;
+};
+
+typedef struct SMU73_Discrete_FanTable SMU73_Discrete_FanTable;
+
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG             4
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG_BIT         (0x1 << SMU7_DISCRETE_GPIO_SCLK_DEBUG)
+
+
+
+struct SMU7_MclkDpmScoreboard
+{
+
+    uint32_t PercentageBusy;
+
+    int32_t  PIDError;
+    int32_t  PIDIntegral;
+    int32_t  PIDOutput;
+
+    uint32_t SigmaDeltaAccum;
+    uint32_t SigmaDeltaOutput;
+    uint32_t SigmaDeltaLevel;
+
+    uint32_t UtilizationSetpoint;
+
+    uint8_t  TdpClampMode;
+    uint8_t  TdcClampMode;
+    uint8_t  ThermClampMode;
+    uint8_t  VoltageBusy;
+
+    int8_t   CurrLevel;
+    int8_t   TargLevel;
+    uint8_t  LevelChangeInProgress;
+    uint8_t  UpHyst;
+
+    uint8_t  DownHyst;
+    uint8_t  VoltageDownHyst;
+    uint8_t  DpmEnable;
+    uint8_t  DpmRunning;
+
+    uint8_t  DpmForce;
+    uint8_t  DpmForceLevel;
+    uint8_t  DisplayWatermark;
+    uint8_t  McArbIndex;
+
+    uint32_t MinimumPerfMclk;
+
+    uint8_t  AcpiReq;
+    uint8_t  AcpiAck;
+    uint8_t  MclkSwitchInProgress;
+    uint8_t  MclkSwitchCritical;
+
+    uint8_t  IgnoreVBlank;
+    uint8_t  TargetMclkIndex;
+    uint8_t  TargetMvddIndex;
+    uint8_t  MclkSwitchResult;
+
+    uint16_t VbiFailureCount;
+    uint8_t  VbiWaitCounter;
+    uint8_t  EnabledLevelsChange;
+
+    uint16_t LevelResidencyCounters [SMU73_MAX_LEVELS_MEMORY];
+    uint16_t LevelSwitchCounters [SMU73_MAX_LEVELS_MEMORY];
+
+    void     (*TargetStateCalculator)(uint8_t);
+    void     (*SavedTargetStateCalculator)(uint8_t);
+
+    uint16_t AutoDpmInterval;
+    uint16_t AutoDpmRange;
+
+    uint16_t VbiTimeoutCount;
+    uint16_t MclkSwitchingTime;
+
+    uint8_t  fastSwitch;
+    uint8_t  Save_PIC_VDDGFX_EXIT;
+    uint8_t  Save_PIC_VDDGFX_ENTER;
+    uint8_t  padding;
+
+};
+
+typedef struct SMU7_MclkDpmScoreboard SMU7_MclkDpmScoreboard;
+
+struct SMU7_UlvScoreboard
+{
+    uint8_t     EnterUlv;
+    uint8_t     ExitUlv;
+    uint8_t     UlvActive;
+    uint8_t     WaitingForUlv;
+    uint8_t     UlvEnable;
+    uint8_t     UlvRunning;
+    uint8_t     UlvMasterEnable;
+    uint8_t     padding;
+    uint32_t    UlvAbortedCount;
+    uint32_t    UlvTimeStamp;
+};
+
+typedef struct SMU7_UlvScoreboard SMU7_UlvScoreboard;
+
+struct VddgfxSavedRegisters
+{
+  uint32_t GPU_DBG[3];
+  uint32_t MEC_BaseAddress_Hi;
+  uint32_t MEC_BaseAddress_Lo;
+  uint32_t THM_TMON0_CTRL2__RDIR_PRESENT;
+  uint32_t THM_TMON1_CTRL2__RDIR_PRESENT;
+  uint32_t CP_INT_CNTL;
+};
+
+typedef struct VddgfxSavedRegisters VddgfxSavedRegisters;
+
+struct SMU7_VddGfxScoreboard
+{
+    uint8_t     VddGfxEnable;
+    uint8_t     VddGfxActive;
+    uint8_t     VPUResetOccured;
+    uint8_t     padding;
+
+    uint32_t    VddGfxEnteredCount;
+    uint32_t    VddGfxAbortedCount;
+
+    uint32_t    VddGfxVid;
+
+    VddgfxSavedRegisters SavedRegisters;
+};
+
+typedef struct SMU7_VddGfxScoreboard SMU7_VddGfxScoreboard;
+
+struct SMU7_TdcLimitScoreboard {
+  uint8_t  Enable;
+  uint8_t  Running;
+  uint16_t Alpha;
+  uint32_t FilteredIddc;
+  uint32_t IddcLimit;
+  uint32_t IddcHyst;
+  SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_TdcLimitScoreboard SMU7_TdcLimitScoreboard;
+
+struct SMU7_PkgPwrLimitScoreboard {
+  uint8_t  Enable;
+  uint8_t  Running;
+  uint16_t Alpha;
+  uint32_t FilteredPkgPwr;
+  uint32_t Limit;
+  uint32_t Hyst;
+  uint32_t LimitFromDriver;
+  SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_PkgPwrLimitScoreboard SMU7_PkgPwrLimitScoreboard;
+
+struct SMU7_BapmScoreboard {
+  uint32_t source_powers[SMU73_DTE_SOURCES];
+  uint32_t source_powers_last[SMU73_DTE_SOURCES];
+  int32_t entity_temperatures[SMU73_NUM_GPU_TES];
+  int32_t initial_entity_temperatures[SMU73_NUM_GPU_TES];
+  int32_t Limit;
+  int32_t Hyst;
+  int32_t therm_influence_coeff_table[SMU73_DTE_ITERATIONS * SMU73_DTE_SOURCES * SMU73_DTE_SINKS * 2];
+  int32_t therm_node_table[SMU73_DTE_ITERATIONS * SMU73_DTE_SOURCES * SMU73_DTE_SINKS];
+  uint16_t ConfigTDPPowerScalar;
+  uint16_t FanSpeedPowerScalar;
+  uint16_t OverDrivePowerScalar;
+  uint16_t OverDriveLimitScalar;
+  uint16_t FinalPowerScalar;
+  uint8_t VariantID;
+  uint8_t spare997;
+
+  SMU7_HystController_Data HystControllerData;
+
+  int32_t temperature_gradient_slope;
+  int32_t temperature_gradient;
+  uint32_t measured_temperature;
+};
+
+
+typedef struct SMU7_BapmScoreboard SMU7_BapmScoreboard;
+
+struct SMU7_AcpiScoreboard {
+  uint32_t SavedInterruptMask[2];
+  uint8_t LastACPIRequest;
+  uint8_t CgBifResp;
+  uint8_t RequestType;
+  uint8_t Padding;
+  SMU73_Discrete_ACPILevel D0Level;
+};
+
+typedef struct SMU7_AcpiScoreboard SMU7_AcpiScoreboard;
+
+struct SMU_QuadraticCoeffs {
+  int32_t m1;
+  uint32_t b;
+
+  int16_t m2;
+  uint8_t m1_shift;
+  uint8_t m2_shift;
+};
+
+typedef struct SMU_QuadraticCoeffs SMU_QuadraticCoeffs;
+
+struct SMU73_Discrete_PmFuses {
+  /* dw0-dw1 */
+  uint8_t BapmVddCVidHiSidd[8];
+
+  /* dw2-dw3 */
+  uint8_t BapmVddCVidLoSidd[8];
+
+  /* dw4-dw5 */
+  uint8_t VddCVid[8];
+
+  /* dw1*/
+  uint8_t SviLoadLineEn;
+  uint8_t SviLoadLineVddC;
+  uint8_t SviLoadLineTrimVddC;
+  uint8_t SviLoadLineOffsetVddC;
+
+  /* dw2 */
+  uint16_t TDC_VDDC_PkgLimit;
+  uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
+  uint8_t TDC_MAWt;
+
+  /* dw3 */
+  uint8_t TdcWaterfallCtl;
+  uint8_t LPMLTemperatureMin;
+  uint8_t LPMLTemperatureMax;
+  uint8_t Reserved;
+
+  /* dw4-dw7 */
+  uint8_t LPMLTemperatureScaler[16];
+
+  /* dw8-dw9 */
+  int16_t FuzzyFan_ErrorSetDelta;
+  int16_t FuzzyFan_ErrorRateSetDelta;
+  int16_t FuzzyFan_PwmSetDelta;
+  uint16_t Reserved6;
+
+  /* dw10-dw14 */
+  uint8_t GnbLPML[16];
+
+  /* dw15 */
+  uint8_t GnbLPMLMaxVid;
+  uint8_t GnbLPMLMinVid;
+  uint8_t Reserved1[2];
+
+  /* dw16 */
+  uint16_t BapmVddCBaseLeakageHiSidd;
+  uint16_t BapmVddCBaseLeakageLoSidd;
+
+  /* AVFS */
+  uint16_t  VFT_Temp[3];
+  uint16_t  padding;
+
+  SMU_QuadraticCoeffs VFT_ATE[3];
+
+  SMU_QuadraticCoeffs AVFS_GB;
+  SMU_QuadraticCoeffs ATE_ACBTC_GB;
+
+  SMU_QuadraticCoeffs P2V;
+
+  uint32_t PsmCharzFreq;
+
+  uint16_t InversionVoltage;
+  uint16_t PsmCharzTemp;
+
+  uint32_t EnabledAvfsModules;
+};
+
+typedef struct SMU73_Discrete_PmFuses SMU73_Discrete_PmFuses;
+
+struct SMU7_Discrete_Log_Header_Table {
+  uint32_t    version;
+  uint32_t    asic_id;
+  uint16_t    flags;
+  uint16_t    entry_size;
+  uint32_t    total_size;
+  uint32_t    num_of_entries;
+  uint8_t     type;
+  uint8_t     mode;
+  uint8_t     filler_0[2];
+  uint32_t    filler_1[2];
+};
+
+typedef struct SMU7_Discrete_Log_Header_Table SMU7_Discrete_Log_Header_Table;
+
+struct SMU7_Discrete_Log_Cntl {
+    uint8_t             Enabled;
+    uint8_t             Type;
+    uint8_t             padding[2];
+    uint32_t            BufferSize;
+    uint32_t            SamplesLogged;
+    uint32_t            SampleSize;
+    uint32_t            AddrL;
+    uint32_t            AddrH;
+};
+
+typedef struct SMU7_Discrete_Log_Cntl SMU7_Discrete_Log_Cntl;
+
+#define CAC_ACC_NW_NUM_OF_SIGNALS 87
+
+struct SMU7_Discrete_Cac_Collection_Table {
+  uint32_t temperature;
+  uint32_t cac_acc_nw[CAC_ACC_NW_NUM_OF_SIGNALS];
+};
+
+typedef struct SMU7_Discrete_Cac_Collection_Table SMU7_Discrete_Cac_Collection_Table;
+
+struct SMU7_Discrete_Cac_Verification_Table {
+  uint32_t VddcTotalPower;
+  uint32_t VddcLeakagePower;
+  uint32_t VddcConstantPower;
+  uint32_t VddcGfxDynamicPower;
+  uint32_t VddcUvdDynamicPower;
+  uint32_t VddcVceDynamicPower;
+  uint32_t VddcAcpDynamicPower;
+  uint32_t VddcPcieDynamicPower;
+  uint32_t VddcDceDynamicPower;
+  uint32_t VddcCurrent;
+  uint32_t VddcVoltage;
+  uint32_t VddciTotalPower;
+  uint32_t VddciLeakagePower;
+  uint32_t VddciConstantPower;
+  uint32_t VddciDynamicPower;
+  uint32_t Vddr1TotalPower;
+  uint32_t Vddr1LeakagePower;
+  uint32_t Vddr1ConstantPower;
+  uint32_t Vddr1DynamicPower;
+  uint32_t spare[4];
+  uint32_t temperature;
+};
+
+typedef struct SMU7_Discrete_Cac_Verification_Table SMU7_Discrete_Cac_Verification_Table;
+
+struct SMU7_Discrete_Pm_Status_Table {
+  //Thermal entities
+  int32_t  T_meas_max[SMU73_THERMAL_INPUT_LOOP_COUNT];
+  int32_t  T_meas_acc[SMU73_THERMAL_INPUT_LOOP_COUNT];
+  int32_t  T_meas_acc_cnt[SMU73_THERMAL_INPUT_LOOP_COUNT];
+  uint32_t T_hbm_acc;
+
+  //Voltage domains
+  uint32_t I_calc_max;
+  uint32_t I_calc_acc;
+  uint32_t P_meas_acc;
+  uint32_t V_meas_load_acc;
+  uint32_t I_meas_acc;
+  uint32_t P_meas_acc_vddci;
+  uint32_t V_meas_load_acc_vddci;
+  uint32_t I_meas_acc_vddci;
+
+  //Frequency
+  uint16_t Sclk_dpm_residency[8];
+  uint16_t Uvd_dpm_residency[8];
+  uint16_t Vce_dpm_residency[8];
+
+  //Chip
+  uint32_t P_roc_acc;
+  uint32_t PkgPwr_max;
+  uint32_t PkgPwr_acc;
+  uint32_t MclkSwitchingTime_max;
+  uint32_t MclkSwitchingTime_acc;
+  uint32_t FanPwm_acc;
+  uint32_t FanRpm_acc;
+  uint32_t Gfx_busy_acc;
+  uint32_t Mc_busy_acc;
+  uint32_t Fps_acc;
+
+  uint32_t AccCnt;
+};
+
+typedef struct SMU7_Discrete_Pm_Status_Table SMU7_Discrete_Pm_Status_Table;
+
+//FIXME THESE NEED TO BE UPDATED
+#define SMU7_SCLK_CAC 0x561
+#define SMU7_MCLK_CAC 0xF9
+#define SMU7_VCLK_CAC 0x2DE
+#define SMU7_DCLK_CAC 0x2DE
+#define SMU7_ECLK_CAC 0x25E
+#define SMU7_ACLK_CAC 0x25E
+#define SMU7_SAMCLK_CAC 0x25E
+#define SMU7_DISPCLK_CAC 0x100
+#define SMU7_CAC_CONSTANT 0x2EE3430
+#define SMU7_CAC_CONSTANT_SHIFT 18
+
+#define SMU7_VDDCI_MCLK_CONST        1765
+#define SMU7_VDDCI_MCLK_CONST_SHIFT  16
+#define SMU7_VDDCI_VDDCI_CONST       50958
+#define SMU7_VDDCI_VDDCI_CONST_SHIFT 14
+#define SMU7_VDDCI_CONST             11781
+#define SMU7_VDDCI_STROBE_PWR        1331
+
+#define SMU7_VDDR1_CONST            693
+#define SMU7_VDDR1_CAC_WEIGHT       20
+#define SMU7_VDDR1_CAC_WEIGHT_SHIFT 19
+#define SMU7_VDDR1_STROBE_PWR       512
+
+#define SMU7_AREA_COEFF_UVD 0xA78
+#define SMU7_AREA_COEFF_VCE 0x190A
+#define SMU7_AREA_COEFF_ACP 0x22D1
+#define SMU7_AREA_COEFF_SAMU 0x534
+
+//ThermOutMode values
+#define SMU7_THERM_OUT_MODE_DISABLE       0x0
+#define SMU7_THERM_OUT_MODE_THERM_ONLY    0x1
+#define SMU7_THERM_OUT_MODE_THERM_VRHOT   0x2
+
+#pragma pack(pop)
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu7_discrete.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu7_discrete.h
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SMU7_DISCRETE_H
+#define SMU7_DISCRETE_H
+
+#include "smu7.h"
+
+#pragma pack(push, 1)
+
+#define SMU7_DTE_ITERATIONS 5
+#define SMU7_DTE_SOURCES 3
+#define SMU7_DTE_SINKS 1
+#define SMU7_NUM_CPU_TES 0
+#define SMU7_NUM_GPU_TES 1
+#define SMU7_NUM_NON_TES 2
+
+struct SMU7_SoftRegisters
+{
+    uint32_t        RefClockFrequency;
+    uint32_t        PmTimerP;
+    uint32_t        FeatureEnables;
+    uint32_t        PreVBlankGap;
+    uint32_t        VBlankTimeout;
+    uint32_t        TrainTimeGap;
+
+    uint32_t        MvddSwitchTime;
+    uint32_t        LongestAcpiTrainTime;
+    uint32_t        AcpiDelay;
+    uint32_t        G5TrainTime;
+    uint32_t        DelayMpllPwron;
+    uint32_t        VoltageChangeTimeout;
+    uint32_t        HandshakeDisables;
+
+    uint8_t         DisplayPhy1Config;
+    uint8_t         DisplayPhy2Config;
+    uint8_t         DisplayPhy3Config;
+    uint8_t         DisplayPhy4Config;
+
+    uint8_t         DisplayPhy5Config;
+    uint8_t         DisplayPhy6Config;
+    uint8_t         DisplayPhy7Config;
+    uint8_t         DisplayPhy8Config;
+
+    uint32_t        AverageGraphicsA;
+    uint32_t        AverageMemoryA;
+    uint32_t        AverageGioA;
+
+    uint8_t         SClkDpmEnabledLevels;
+    uint8_t         MClkDpmEnabledLevels;
+    uint8_t         LClkDpmEnabledLevels;
+    uint8_t         PCIeDpmEnabledLevels;
+
+    uint8_t         UVDDpmEnabledLevels;
+    uint8_t         SAMUDpmEnabledLevels;
+    uint8_t         ACPDpmEnabledLevels;
+    uint8_t         VCEDpmEnabledLevels;
+
+    uint32_t        DRAM_LOG_ADDR_H;
+    uint32_t        DRAM_LOG_ADDR_L;
+    uint32_t        DRAM_LOG_PHY_ADDR_H;
+    uint32_t        DRAM_LOG_PHY_ADDR_L;
+    uint32_t        DRAM_LOG_BUFF_SIZE;
+    uint32_t        UlvEnterC;
+    uint32_t        UlvTime;
+    uint32_t        Reserved[3];
+
+};
+
+typedef struct SMU7_SoftRegisters SMU7_SoftRegisters;
+
+struct SMU7_Discrete_VoltageLevel
+{
+    uint16_t    Voltage;
+    uint16_t    StdVoltageHiSidd;
+    uint16_t    StdVoltageLoSidd;
+    uint8_t     Smio;
+    uint8_t     padding;
+};
+
+typedef struct SMU7_Discrete_VoltageLevel SMU7_Discrete_VoltageLevel;
+
+struct SMU7_Discrete_GraphicsLevel
+{
+    uint32_t    Flags;
+    uint32_t    MinVddc;
+    uint32_t    MinVddcPhases;
+
+    uint32_t    SclkFrequency;
+
+    uint8_t     padding1[2];
+    uint16_t    ActivityLevel;
+
+    uint32_t    CgSpllFuncCntl3;
+    uint32_t    CgSpllFuncCntl4;
+    uint32_t    SpllSpreadSpectrum;
+    uint32_t    SpllSpreadSpectrum2;
+    uint32_t    CcPwrDynRm;
+    uint32_t    CcPwrDynRm1;
+    uint8_t     SclkDid;
+    uint8_t     DisplayWatermark;
+    uint8_t     EnabledForActivity;
+    uint8_t     EnabledForThrottle;
+    uint8_t     UpH;
+    uint8_t     DownH;
+    uint8_t     VoltageDownH;
+    uint8_t     PowerThrottle;
+    uint8_t     DeepSleepDivId;
+    uint8_t     padding[3];
+};
+
+typedef struct SMU7_Discrete_GraphicsLevel SMU7_Discrete_GraphicsLevel;
+
+struct SMU7_Discrete_ACPILevel
+{
+    uint32_t    Flags;
+    uint32_t    MinVddc;
+    uint32_t    MinVddcPhases;
+    uint32_t    SclkFrequency;
+    uint8_t     SclkDid;
+    uint8_t     DisplayWatermark;
+    uint8_t     DeepSleepDivId;
+    uint8_t     padding;
+    uint32_t    CgSpllFuncCntl;
+    uint32_t    CgSpllFuncCntl2;
+    uint32_t    CgSpllFuncCntl3;
+    uint32_t    CgSpllFuncCntl4;
+    uint32_t    SpllSpreadSpectrum;
+    uint32_t    SpllSpreadSpectrum2;
+    uint32_t    CcPwrDynRm;
+    uint32_t    CcPwrDynRm1;
+};
+
+typedef struct SMU7_Discrete_ACPILevel SMU7_Discrete_ACPILevel;
+
+struct SMU7_Discrete_Ulv
+{
+    uint32_t    CcPwrDynRm;
+    uint32_t    CcPwrDynRm1;
+    uint16_t    VddcOffset;
+    uint8_t     VddcOffsetVid;
+    uint8_t     VddcPhase;
+    uint32_t    Reserved;
+};
+
+typedef struct SMU7_Discrete_Ulv SMU7_Discrete_Ulv;
+
+struct SMU7_Discrete_MemoryLevel
+{
+    uint32_t    MinVddc;
+    uint32_t    MinVddcPhases;
+    uint32_t    MinVddci;
+    uint32_t    MinMvdd;
+
+    uint32_t    MclkFrequency;
+
+    uint8_t     EdcReadEnable;
+    uint8_t     EdcWriteEnable;
+    uint8_t     RttEnable;
+    uint8_t     StutterEnable;
+
+    uint8_t     StrobeEnable;
+    uint8_t     StrobeRatio;
+    uint8_t     EnabledForThrottle;
+    uint8_t     EnabledForActivity;
+
+    uint8_t     UpH;
+    uint8_t     DownH;
+    uint8_t     VoltageDownH;
+    uint8_t     padding;
+
+    uint16_t    ActivityLevel;
+    uint8_t     DisplayWatermark;
+    uint8_t     padding1;
+
+    uint32_t    MpllFuncCntl;
+    uint32_t    MpllFuncCntl_1;
+    uint32_t    MpllFuncCntl_2;
+    uint32_t    MpllAdFuncCntl;
+    uint32_t    MpllDqFuncCntl;
+    uint32_t    MclkPwrmgtCntl;
+    uint32_t    DllCntl;
+    uint32_t    MpllSs1;
+    uint32_t    MpllSs2;
+};
+
+typedef struct SMU7_Discrete_MemoryLevel SMU7_Discrete_MemoryLevel;
+
+struct SMU7_Discrete_LinkLevel
+{
+    uint8_t     PcieGenSpeed;
+    uint8_t     PcieLaneCount;
+    uint8_t     EnabledForActivity;
+    uint8_t     Padding;
+    uint32_t    DownT;
+    uint32_t    UpT;
+    uint32_t    Reserved;
+};
+
+typedef struct SMU7_Discrete_LinkLevel SMU7_Discrete_LinkLevel;
+
+
+struct SMU7_Discrete_MCArbDramTimingTableEntry
+{
+    uint32_t McArbDramTiming;
+    uint32_t McArbDramTiming2;
+    uint8_t  McArbBurstTime;
+    uint8_t  padding[3];
+};
+
+typedef struct SMU7_Discrete_MCArbDramTimingTableEntry SMU7_Discrete_MCArbDramTimingTableEntry;
+
+struct SMU7_Discrete_MCArbDramTimingTable
+{
+    SMU7_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS];
+};
+
+typedef struct SMU7_Discrete_MCArbDramTimingTable SMU7_Discrete_MCArbDramTimingTable;
+
+struct SMU7_Discrete_UvdLevel
+{
+    uint32_t VclkFrequency;
+    uint32_t DclkFrequency;
+    uint16_t MinVddc;
+    uint8_t  MinVddcPhases;
+    uint8_t  VclkDivider;
+    uint8_t  DclkDivider;
+    uint8_t  padding[3];
+};
+
+typedef struct SMU7_Discrete_UvdLevel SMU7_Discrete_UvdLevel;
+
+struct SMU7_Discrete_ExtClkLevel
+{
+    uint32_t Frequency;
+    uint16_t MinVoltage;
+    uint8_t  MinPhases;
+    uint8_t  Divider;
+};
+
+typedef struct SMU7_Discrete_ExtClkLevel SMU7_Discrete_ExtClkLevel;
+
+struct SMU7_Discrete_StateInfo
+{
+    uint32_t SclkFrequency;
+    uint32_t MclkFrequency;
+    uint32_t VclkFrequency;
+    uint32_t DclkFrequency;
+    uint32_t SamclkFrequency;
+    uint32_t AclkFrequency;
+    uint32_t EclkFrequency;
+    uint16_t MvddVoltage;
+    uint16_t padding16;
+    uint8_t  DisplayWatermark;
+    uint8_t  McArbIndex;
+    uint8_t  McRegIndex;
+    uint8_t  SeqIndex;
+    uint8_t  SclkDid;
+    int8_t   SclkIndex;
+    int8_t   MclkIndex;
+    uint8_t  PCIeGen;
+
+};
+
+typedef struct SMU7_Discrete_StateInfo SMU7_Discrete_StateInfo;
+
+
+struct SMU7_Discrete_DpmTable
+{
+    SMU7_PIDController                  GraphicsPIDController;
+    SMU7_PIDController                  MemoryPIDController;
+    SMU7_PIDController                  LinkPIDController;
+
+    uint32_t                            SystemFlags;
+
+
+    uint32_t                            SmioMaskVddcVid;
+    uint32_t                            SmioMaskVddcPhase;
+    uint32_t                            SmioMaskVddciVid;
+    uint32_t                            SmioMaskMvddVid;
+
+    uint32_t                            VddcLevelCount;
+    uint32_t                            VddciLevelCount;
+    uint32_t                            MvddLevelCount;
+
+    SMU7_Discrete_VoltageLevel          VddcLevel               [SMU7_MAX_LEVELS_VDDC];
+//    SMU7_Discrete_VoltageLevel          VddcStandardReference   [SMU7_MAX_LEVELS_VDDC];
+    SMU7_Discrete_VoltageLevel          VddciLevel              [SMU7_MAX_LEVELS_VDDCI];
+    SMU7_Discrete_VoltageLevel          MvddLevel               [SMU7_MAX_LEVELS_MVDD];
+
+    uint8_t                             GraphicsDpmLevelCount;
+    uint8_t                             MemoryDpmLevelCount;
+    uint8_t                             LinkLevelCount;
+    uint8_t                             UvdLevelCount;
+    uint8_t                             VceLevelCount;
+    uint8_t                             AcpLevelCount;
+    uint8_t                             SamuLevelCount;
+    uint8_t                             MasterDeepSleepControl;
+    uint32_t                            Reserved[5];
+//    uint32_t                            SamuDefaultLevel;
+
+    SMU7_Discrete_GraphicsLevel         GraphicsLevel           [SMU7_MAX_LEVELS_GRAPHICS];
+    SMU7_Discrete_MemoryLevel           MemoryACPILevel;
+    SMU7_Discrete_MemoryLevel           MemoryLevel             [SMU7_MAX_LEVELS_MEMORY];
+    SMU7_Discrete_LinkLevel             LinkLevel               [SMU7_MAX_LEVELS_LINK];
+    SMU7_Discrete_ACPILevel             ACPILevel;
+    SMU7_Discrete_UvdLevel              UvdLevel                [SMU7_MAX_LEVELS_UVD];
+    SMU7_Discrete_ExtClkLevel           VceLevel                [SMU7_MAX_LEVELS_VCE];
+    SMU7_Discrete_ExtClkLevel           AcpLevel                [SMU7_MAX_LEVELS_ACP];
+    SMU7_Discrete_ExtClkLevel           SamuLevel               [SMU7_MAX_LEVELS_SAMU];
+    SMU7_Discrete_Ulv                   Ulv;
+
+    uint32_t                            SclkStepSize;
+    uint32_t                            Smio                    [SMU7_MAX_ENTRIES_SMIO];
+
+    uint8_t                             UvdBootLevel;
+    uint8_t                             VceBootLevel;
+    uint8_t                             AcpBootLevel;
+    uint8_t                             SamuBootLevel;
+
+    uint8_t                             UVDInterval;
+    uint8_t                             VCEInterval;
+    uint8_t                             ACPInterval;
+    uint8_t                             SAMUInterval;
+
+    uint8_t                             GraphicsBootLevel;
+    uint8_t                             GraphicsVoltageChangeEnable;
+    uint8_t                             GraphicsThermThrottleEnable;
+    uint8_t                             GraphicsInterval;
+
+    uint8_t                             VoltageInterval;
+    uint8_t                             ThermalInterval;
+    uint16_t                            TemperatureLimitHigh;
+
+    uint16_t                            TemperatureLimitLow;
+    uint8_t                             MemoryBootLevel;
+    uint8_t                             MemoryVoltageChangeEnable;
+
+    uint8_t                             MemoryInterval;
+    uint8_t                             MemoryThermThrottleEnable;
+    uint16_t                            VddcVddciDelta;
+
+    uint16_t                            VoltageResponseTime;
+    uint16_t                            PhaseResponseTime;
+
+    uint8_t                             PCIeBootLinkLevel;
+    uint8_t                             PCIeGenInterval;
+    uint8_t                             DTEInterval;
+    uint8_t                             DTEMode;
+
+    uint8_t                             SVI2Enable;
+    uint8_t                             VRHotGpio;
+    uint8_t                             AcDcGpio;
+    uint8_t                             ThermGpio;
+
+    uint16_t                            PPM_PkgPwrLimit;
+    uint16_t                            PPM_TemperatureLimit;
+
+    uint16_t                            DefaultTdp;
+    uint16_t                            TargetTdp;
+
+    uint16_t                            FpsHighT;
+    uint16_t                            FpsLowT;
+
+    uint16_t                            BAPMTI_R  [SMU7_DTE_ITERATIONS][SMU7_DTE_SOURCES][SMU7_DTE_SINKS];
+    uint16_t                            BAPMTI_RC [SMU7_DTE_ITERATIONS][SMU7_DTE_SOURCES][SMU7_DTE_SINKS];
+
+    uint8_t                             DTEAmbientTempBase;
+    uint8_t                             DTETjOffset;
+    uint8_t                             GpuTjMax;
+    uint8_t                             GpuTjHyst;
+
+    uint16_t                            BootVddc;
+    uint16_t                            BootVddci;
+
+    uint16_t                            BootMVdd;
+    uint16_t                            padding;
+
+    uint32_t                            BAPM_TEMP_GRADIENT;
+
+    uint32_t                            LowSclkInterruptT;
+};
+
+typedef struct SMU7_Discrete_DpmTable SMU7_Discrete_DpmTable;
+
+#define SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE 16
+#define SMU7_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT SMU7_MAX_LEVELS_MEMORY
+
+struct SMU7_Discrete_MCRegisterAddress
+{
+    uint16_t s0;
+    uint16_t s1;
+};
+
+typedef struct SMU7_Discrete_MCRegisterAddress SMU7_Discrete_MCRegisterAddress;
+
+struct SMU7_Discrete_MCRegisterSet
+{
+    uint32_t value[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMU7_Discrete_MCRegisterSet SMU7_Discrete_MCRegisterSet;
+
+struct SMU7_Discrete_MCRegisters
+{
+    uint8_t                             last;
+    uint8_t                             reserved[3];
+    SMU7_Discrete_MCRegisterAddress     address[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+    SMU7_Discrete_MCRegisterSet         data[SMU7_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMU7_Discrete_MCRegisters SMU7_Discrete_MCRegisters;
+
+struct SMU7_Discrete_FanTable
+{
+	uint16_t FdoMode;
+	int16_t  TempMin;
+	int16_t  TempMed;
+	int16_t  TempMax;
+	int16_t  Slope1;
+	int16_t  Slope2;
+	int16_t  FdoMin;
+	int16_t  HystUp;
+	int16_t  HystDown;
+	int16_t  HystSlope;
+	int16_t  TempRespLim;
+	int16_t  TempCurr;
+	int16_t  SlopeCurr;
+	int16_t  PwmCurr;
+	uint32_t RefreshPeriod;
+	int16_t  FdoMax;
+	uint8_t  TempSrc;
+	int8_t   Padding;
+};
+
+typedef struct SMU7_Discrete_FanTable SMU7_Discrete_FanTable;
+
+
+struct SMU7_Discrete_PmFuses {
+  // dw0-dw1
+  uint8_t BapmVddCVidHiSidd[8];
+
+  // dw2-dw3
+  uint8_t BapmVddCVidLoSidd[8];
+
+  // dw4-dw5
+  uint8_t VddCVid[8];
+
+  // dw6
+  uint8_t SviLoadLineEn;
+  uint8_t SviLoadLineVddC;
+  uint8_t SviLoadLineTrimVddC;
+  uint8_t SviLoadLineOffsetVddC;
+
+  // dw7
+  uint16_t TDC_VDDC_PkgLimit;
+  uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
+  uint8_t TDC_MAWt;
+
+  // dw8
+  uint8_t TdcWaterfallCtl;
+  uint8_t LPMLTemperatureMin;
+  uint8_t LPMLTemperatureMax;
+  uint8_t Reserved;
+
+  // dw9-dw10
+  uint8_t BapmVddCVidHiSidd2[8];
+
+  // dw11-dw12
+  int16_t FuzzyFan_ErrorSetDelta;
+  int16_t FuzzyFan_ErrorRateSetDelta;
+  int16_t FuzzyFan_PwmSetDelta;
+  uint16_t CalcMeasPowerBlend;
+
+  // dw13-dw16
+  uint8_t GnbLPML[16];
+
+  // dw17
+  uint8_t GnbLPMLMaxVid;
+  uint8_t GnbLPMLMinVid;
+  uint8_t Reserved1[2];
+
+  // dw18
+  uint16_t BapmVddCBaseLeakageHiSidd;
+  uint16_t BapmVddCBaseLeakageLoSidd;
+};
+
+typedef struct SMU7_Discrete_PmFuses SMU7_Discrete_PmFuses;
+
+
+#pragma pack(pop)
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu7_fusion.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu7_fusion.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SMU7_FUSION_H
+#define SMU7_FUSION_H
+
+#include "smu7.h"
+
+#pragma pack(push, 1)
+
+#define SMU7_DTE_ITERATIONS 5
+#define SMU7_DTE_SOURCES 5
+#define SMU7_DTE_SINKS 3
+#define SMU7_NUM_CPU_TES 2
+#define SMU7_NUM_GPU_TES 1
+#define SMU7_NUM_NON_TES 2
+
+// All 'soft registers' should be uint32_t.
+struct SMU7_SoftRegisters
+{
+    uint32_t        RefClockFrequency;
+    uint32_t        PmTimerP;
+    uint32_t        FeatureEnables;
+    uint32_t        HandshakeDisables;
+
+    uint8_t         DisplayPhy1Config;
+    uint8_t         DisplayPhy2Config;
+    uint8_t         DisplayPhy3Config;
+    uint8_t         DisplayPhy4Config;
+
+    uint8_t         DisplayPhy5Config;
+    uint8_t         DisplayPhy6Config;
+    uint8_t         DisplayPhy7Config;
+    uint8_t         DisplayPhy8Config;
+
+    uint32_t        AverageGraphicsA;
+    uint32_t        AverageMemoryA;
+    uint32_t        AverageGioA;
+
+    uint8_t         SClkDpmEnabledLevels;
+    uint8_t         MClkDpmEnabledLevels;
+    uint8_t         LClkDpmEnabledLevels;
+    uint8_t         PCIeDpmEnabledLevels;
+
+    uint8_t         UVDDpmEnabledLevels;
+    uint8_t         SAMUDpmEnabledLevels;
+    uint8_t         ACPDpmEnabledLevels;
+    uint8_t         VCEDpmEnabledLevels;
+
+    uint32_t        DRAM_LOG_ADDR_H;
+    uint32_t        DRAM_LOG_ADDR_L;
+    uint32_t        DRAM_LOG_PHY_ADDR_H;
+    uint32_t        DRAM_LOG_PHY_ADDR_L;
+    uint32_t        DRAM_LOG_BUFF_SIZE;
+    uint32_t        UlvEnterC;
+    uint32_t        UlvTime;
+    uint32_t        Reserved[3];
+
+};
+
+typedef struct SMU7_SoftRegisters SMU7_SoftRegisters;
+
+struct SMU7_Fusion_GraphicsLevel
+{
+    uint32_t    MinVddNb;
+
+    uint32_t    SclkFrequency;
+
+    uint8_t     Vid;
+    uint8_t     VidOffset;
+    uint16_t    AT;
+
+    uint8_t     PowerThrottle;
+    uint8_t     GnbSlow;
+    uint8_t     ForceNbPs1;
+    uint8_t     SclkDid;
+
+    uint8_t     DisplayWatermark;
+    uint8_t     EnabledForActivity;
+    uint8_t     EnabledForThrottle;
+    uint8_t     UpH;
+
+    uint8_t     DownH;
+    uint8_t     VoltageDownH;
+    uint8_t     DeepSleepDivId;
+
+    uint8_t     ClkBypassCntl;
+
+    uint32_t    reserved;
+};
+
+typedef struct SMU7_Fusion_GraphicsLevel SMU7_Fusion_GraphicsLevel;
+
+struct SMU7_Fusion_GIOLevel
+{
+    uint8_t     EnabledForActivity;
+    uint8_t     LclkDid;
+    uint8_t     Vid;
+    uint8_t     VoltageDownH;
+
+    uint32_t    MinVddNb;
+
+    uint16_t    ResidencyCounter;
+    uint8_t     UpH;
+    uint8_t     DownH;
+
+    uint32_t    LclkFrequency;
+
+    uint8_t     ActivityLevel;
+    uint8_t     EnabledForThrottle;
+
+    uint8_t     ClkBypassCntl;
+
+    uint8_t     padding;
+};
+
+typedef struct SMU7_Fusion_GIOLevel SMU7_Fusion_GIOLevel;
+
+// UVD VCLK/DCLK state (level) definition.
+struct SMU7_Fusion_UvdLevel
+{
+    uint32_t VclkFrequency;
+    uint32_t DclkFrequency;
+    uint16_t MinVddNb;
+    uint8_t  VclkDivider;
+    uint8_t  DclkDivider;
+
+    uint8_t     VClkBypassCntl;
+    uint8_t     DClkBypassCntl;
+
+    uint8_t     padding[2];
+
+};
+
+typedef struct SMU7_Fusion_UvdLevel SMU7_Fusion_UvdLevel;
+
+// Clocks for other external blocks (VCE, ACP, SAMU).
+struct SMU7_Fusion_ExtClkLevel
+{
+    uint32_t Frequency;
+    uint16_t MinVoltage;
+    uint8_t  Divider;
+    uint8_t  ClkBypassCntl;
+
+    uint32_t Reserved;
+};
+typedef struct SMU7_Fusion_ExtClkLevel SMU7_Fusion_ExtClkLevel;
+
+struct SMU7_Fusion_ACPILevel
+{
+    uint32_t    Flags;
+    uint32_t    MinVddNb;
+    uint32_t    SclkFrequency;
+    uint8_t     SclkDid;
+    uint8_t     GnbSlow;
+    uint8_t     ForceNbPs1;
+    uint8_t     DisplayWatermark;
+    uint8_t     DeepSleepDivId;
+    uint8_t     padding[3];
+};
+
+typedef struct SMU7_Fusion_ACPILevel SMU7_Fusion_ACPILevel;
+
+struct SMU7_Fusion_NbDpm
+{
+    uint8_t DpmXNbPsHi;
+    uint8_t DpmXNbPsLo;
+    uint8_t Dpm0PgNbPsHi;
+    uint8_t Dpm0PgNbPsLo;
+    uint8_t EnablePsi1;
+    uint8_t SkipDPM0;
+    uint8_t SkipPG;
+    uint8_t Hysteresis;
+    uint8_t EnableDpmPstatePoll;
+    uint8_t padding[3];
+};
+
+typedef struct SMU7_Fusion_NbDpm SMU7_Fusion_NbDpm;
+
+struct SMU7_Fusion_StateInfo
+{
+    uint32_t SclkFrequency;
+    uint32_t LclkFrequency;
+    uint32_t VclkFrequency;
+    uint32_t DclkFrequency;
+    uint32_t SamclkFrequency;
+    uint32_t AclkFrequency;
+    uint32_t EclkFrequency;
+    uint8_t  DisplayWatermark;
+    uint8_t  McArbIndex;
+    int8_t   SclkIndex;
+    int8_t   MclkIndex;
+};
+
+typedef struct SMU7_Fusion_StateInfo SMU7_Fusion_StateInfo;
+
+struct SMU7_Fusion_DpmTable
+{
+    uint32_t                            SystemFlags;
+
+    SMU7_PIDController                  GraphicsPIDController;
+    SMU7_PIDController                  GioPIDController;
+
+    uint8_t                            GraphicsDpmLevelCount;
+    uint8_t                            GIOLevelCount;
+    uint8_t                            UvdLevelCount;
+    uint8_t                            VceLevelCount;
+
+    uint8_t                            AcpLevelCount;
+    uint8_t                            SamuLevelCount;
+    uint16_t                           FpsHighT;
+
+    SMU7_Fusion_GraphicsLevel         GraphicsLevel           [SMU__NUM_SCLK_DPM_STATE];
+    SMU7_Fusion_ACPILevel             ACPILevel;
+    SMU7_Fusion_UvdLevel              UvdLevel                [SMU7_MAX_LEVELS_UVD];
+    SMU7_Fusion_ExtClkLevel           VceLevel                [SMU7_MAX_LEVELS_VCE];
+    SMU7_Fusion_ExtClkLevel           AcpLevel                [SMU7_MAX_LEVELS_ACP];
+    SMU7_Fusion_ExtClkLevel           SamuLevel               [SMU7_MAX_LEVELS_SAMU];
+
+    uint8_t                           UvdBootLevel;
+    uint8_t                           VceBootLevel;
+    uint8_t                           AcpBootLevel;
+    uint8_t                           SamuBootLevel;
+    uint8_t                           UVDInterval;
+    uint8_t                           VCEInterval;
+    uint8_t                           ACPInterval;
+    uint8_t                           SAMUInterval;
+
+    uint8_t                           GraphicsBootLevel;
+    uint8_t                           GraphicsInterval;
+    uint8_t                           GraphicsThermThrottleEnable;
+    uint8_t                           GraphicsVoltageChangeEnable;
+
+    uint8_t                           GraphicsClkSlowEnable;
+    uint8_t                           GraphicsClkSlowDivider;
+    uint16_t                          FpsLowT;
+
+    uint32_t                          DisplayCac;
+    uint32_t                          LowSclkInterruptT;
+
+    uint32_t                          DRAM_LOG_ADDR_H;
+    uint32_t                          DRAM_LOG_ADDR_L;
+    uint32_t                          DRAM_LOG_PHY_ADDR_H;
+    uint32_t                          DRAM_LOG_PHY_ADDR_L;
+    uint32_t                          DRAM_LOG_BUFF_SIZE;
+
+};
+
+struct SMU7_Fusion_GIODpmTable
+{
+
+    SMU7_Fusion_GIOLevel              GIOLevel                [SMU7_MAX_LEVELS_GIO];
+
+    SMU7_PIDController                GioPIDController;
+
+    uint32_t                          GIOLevelCount;
+
+    uint8_t                           Enable;
+    uint8_t                           GIOVoltageChangeEnable;
+    uint8_t                           GIOBootLevel;
+    uint8_t                           padding;
+    uint8_t                           padding1[2];
+    uint8_t                           TargetState;
+    uint8_t                           CurrenttState;
+    uint8_t                           ThrottleOnHtc;
+    uint8_t                           ThermThrottleStatus;
+    uint8_t                           ThermThrottleTempSelect;
+    uint8_t                           ThermThrottleEnable;
+    uint16_t                          TemperatureLimitHigh;
+    uint16_t                          TemperatureLimitLow;
+
+};
+
+typedef struct SMU7_Fusion_DpmTable SMU7_Fusion_DpmTable;
+typedef struct SMU7_Fusion_GIODpmTable SMU7_Fusion_GIODpmTable;
+
+#pragma pack(pop)
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu8.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu8.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SMU8_H
+#define SMU8_H
+
+#pragma pack(push, 1)
+
+#define ENABLE_DEBUG_FEATURES
+
+struct SMU8_Firmware_Header {
+	uint32_t Version;
+	uint32_t ImageSize;
+	uint32_t CodeSize;
+	uint32_t HeaderSize;
+	uint32_t EntryPoint;
+	uint32_t Rtos;
+	uint32_t UcodeLoadStatus;
+	uint32_t DpmTable;
+	uint32_t FanTable;
+	uint32_t PmFuseTable;
+	uint32_t Globals;
+	uint32_t Reserved[20];
+	uint32_t Signature;
+};
+
+struct SMU8_MultimediaPowerLogData {
+	uint32_t avgTotalPower;
+	uint32_t avgGpuPower;
+	uint32_t avgUvdPower;
+	uint32_t avgVcePower;
+
+	uint32_t avgSclk;
+	uint32_t avgDclk;
+	uint32_t avgVclk;
+	uint32_t avgEclk;
+
+	uint32_t startTimeHi;
+	uint32_t startTimeLo;
+
+	uint32_t endTimeHi;
+	uint32_t endTimeLo;
+};
+
+#define SMU8_FIRMWARE_HEADER_LOCATION 0x1FF80
+#define SMU8_UNBCSR_START_ADDR 0xC0100000
+
+#define SMN_MP1_SRAM_START_ADDR 0x10000000
+
+#pragma pack(pop)
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu8_fusion.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu8_fusion.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SMU8_FUSION_H
+#define SMU8_FUSION_H
+
+#include "smu8.h"
+
+#pragma pack(push, 1)
+
+#define SMU8_MAX_CUS 2
+#define SMU8_PSMS_PER_CU 4
+#define SMU8_CACS_PER_CU 4
+
+struct SMU8_GfxCuPgScoreboard {
+    uint8_t Enabled;
+    uint8_t spare[3];
+};
+
+struct SMU8_Port80MonitorTable {
+	uint32_t MmioAddress;
+	uint32_t MemoryBaseHi;
+	uint32_t MemoryBaseLo;
+	uint16_t MemoryBufferSize;
+	uint16_t MemoryPosition;
+	uint16_t PollingInterval;
+	uint8_t  EnableCsrShadow;
+	uint8_t  EnableDramShadow;
+};
+
+/*  Display specific power management parameters */
+#define PWRMGT_SEPARATION_TIME_SHIFT            0
+#define PWRMGT_SEPARATION_TIME_MASK             0xFFFF
+#define PWRMGT_DISABLE_CPU_CSTATES_SHIFT        16
+#define PWRMGT_DISABLE_CPU_CSTATES_MASK         0x1
+#define PWRMGT_DISABLE_CPU_PSTATES_SHIFT        24
+#define PWRMGT_DISABLE_CPU_PSTATES_MASK         0x1
+
+/* Clock Table Definitions */
+#define NUM_SCLK_LEVELS     8
+#define NUM_LCLK_LEVELS     8
+#define NUM_UVD_LEVELS      8
+#define NUM_ECLK_LEVELS     8
+#define NUM_ACLK_LEVELS     8
+
+struct SMU8_Fusion_ClkLevel {
+	uint8_t		GnbVid;
+	uint8_t		GfxVid;
+	uint8_t		DfsDid;
+	uint8_t		DeepSleepDid;
+	uint32_t	DfsBypass;
+	uint32_t	Frequency;
+};
+
+struct SMU8_Fusion_SclkBreakdownTable {
+	struct SMU8_Fusion_ClkLevel ClkLevel[NUM_SCLK_LEVELS];
+	struct SMU8_Fusion_ClkLevel DpmOffLevel;
+	/* SMU8_Fusion_ClkLevel PwrOffLevel; */
+	uint32_t    SclkValidMask;
+	uint32_t    MaxSclkIndex;
+};
+
+struct SMU8_Fusion_LclkBreakdownTable {
+	struct SMU8_Fusion_ClkLevel ClkLevel[NUM_LCLK_LEVELS];
+	struct SMU8_Fusion_ClkLevel DpmOffLevel;
+    /* SMU8_Fusion_ClkLevel PwrOffLevel; */
+	uint32_t    LclkValidMask;
+	uint32_t    MaxLclkIndex;
+};
+
+struct SMU8_Fusion_EclkBreakdownTable {
+	struct SMU8_Fusion_ClkLevel ClkLevel[NUM_ECLK_LEVELS];
+	struct SMU8_Fusion_ClkLevel DpmOffLevel;
+	struct SMU8_Fusion_ClkLevel PwrOffLevel;
+	uint32_t    EclkValidMask;
+	uint32_t    MaxEclkIndex;
+};
+
+struct SMU8_Fusion_VclkBreakdownTable {
+	struct SMU8_Fusion_ClkLevel ClkLevel[NUM_UVD_LEVELS];
+	struct SMU8_Fusion_ClkLevel DpmOffLevel;
+	struct SMU8_Fusion_ClkLevel PwrOffLevel;
+	uint32_t    VclkValidMask;
+	uint32_t    MaxVclkIndex;
+};
+
+struct SMU8_Fusion_DclkBreakdownTable {
+	struct SMU8_Fusion_ClkLevel ClkLevel[NUM_UVD_LEVELS];
+	struct SMU8_Fusion_ClkLevel DpmOffLevel;
+	struct SMU8_Fusion_ClkLevel PwrOffLevel;
+	uint32_t    DclkValidMask;
+	uint32_t    MaxDclkIndex;
+};
+
+struct SMU8_Fusion_AclkBreakdownTable {
+	struct SMU8_Fusion_ClkLevel ClkLevel[NUM_ACLK_LEVELS];
+	struct SMU8_Fusion_ClkLevel DpmOffLevel;
+	struct SMU8_Fusion_ClkLevel PwrOffLevel;
+	uint32_t    AclkValidMask;
+	uint32_t    MaxAclkIndex;
+};
+
+
+struct SMU8_Fusion_ClkTable {
+	struct SMU8_Fusion_SclkBreakdownTable SclkBreakdownTable;
+	struct SMU8_Fusion_LclkBreakdownTable LclkBreakdownTable;
+	struct SMU8_Fusion_EclkBreakdownTable EclkBreakdownTable;
+	struct SMU8_Fusion_VclkBreakdownTable VclkBreakdownTable;
+	struct SMU8_Fusion_DclkBreakdownTable DclkBreakdownTable;
+	struct SMU8_Fusion_AclkBreakdownTable AclkBreakdownTable;
+};
+
+#pragma pack(pop)
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_cz.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_cz.h
@@ -0,0 +1,147 @@
+// CZ Ucode Loading Definitions
+#ifndef SMU_UCODE_XFER_CZ_H
+#define SMU_UCODE_XFER_CZ_H
+
+#define NUM_JOBLIST_ENTRIES      32
+
+#define TASK_TYPE_NO_ACTION      0
+#define TASK_TYPE_UCODE_LOAD     1
+#define TASK_TYPE_UCODE_SAVE     2
+#define TASK_TYPE_REG_LOAD       3
+#define TASK_TYPE_REG_SAVE       4
+#define TASK_TYPE_INITIALIZE     5
+
+#define TASK_ARG_REG_SMCIND      0
+#define TASK_ARG_REG_MMIO        1
+#define TASK_ARG_REG_FCH         2
+#define TASK_ARG_REG_UNB         3
+
+#define TASK_ARG_INIT_MM_PWR_LOG 0
+#define TASK_ARG_INIT_CLK_TABLE  1
+
+#define JOB_GFX_SAVE             0
+#define JOB_GFX_RESTORE          1
+#define JOB_FCH_SAVE             2
+#define JOB_FCH_RESTORE          3
+#define JOB_UNB_SAVE             4
+#define JOB_UNB_RESTORE          5
+#define JOB_GMC_SAVE             6
+#define JOB_GMC_RESTORE          7
+#define JOB_GNB_SAVE             8
+#define JOB_GNB_RESTORE          9
+
+#define IGNORE_JOB               0xff
+#define END_OF_TASK_LIST     (uint16_t)0xffff
+
+// Size of DRAM regions (in bytes) requested by SMU:
+#define SMU_DRAM_REQ_MM_PWR_LOG 48 
+
+#define UCODE_ID_SDMA0           0
+#define UCODE_ID_SDMA1           1
+#define UCODE_ID_CP_CE           2
+#define UCODE_ID_CP_PFP          3
+#define UCODE_ID_CP_ME           4
+#define UCODE_ID_CP_MEC_JT1      5
+#define UCODE_ID_CP_MEC_JT2      6
+#define UCODE_ID_GMCON_RENG      7
+#define UCODE_ID_RLC_G           8
+#define UCODE_ID_RLC_SCRATCH     9
+#define UCODE_ID_RLC_SRM_ARAM    10
+#define UCODE_ID_RLC_SRM_DRAM    11
+#define UCODE_ID_DMCU_ERAM       12
+#define UCODE_ID_DMCU_IRAM       13
+
+#define UCODE_ID_SDMA0_MASK           0x00000001       
+#define UCODE_ID_SDMA1_MASK           0x00000002        
+#define UCODE_ID_CP_CE_MASK           0x00000004      
+#define UCODE_ID_CP_PFP_MASK          0x00000008         
+#define UCODE_ID_CP_ME_MASK           0x00000010          
+#define UCODE_ID_CP_MEC_JT1_MASK      0x00000020             
+#define UCODE_ID_CP_MEC_JT2_MASK      0x00000040          
+#define UCODE_ID_GMCON_RENG_MASK      0x00000080            
+#define UCODE_ID_RLC_G_MASK           0x00000100           
+#define UCODE_ID_RLC_SCRATCH_MASK     0x00000200         
+#define UCODE_ID_RLC_SRM_ARAM_MASK    0x00000400                
+#define UCODE_ID_RLC_SRM_DRAM_MASK    0x00000800                 
+#define UCODE_ID_DMCU_ERAM_MASK       0x00001000             
+#define UCODE_ID_DMCU_IRAM_MASK       0x00002000              
+
+#define UCODE_ID_SDMA0_SIZE_BYTE           10368        
+#define UCODE_ID_SDMA1_SIZE_BYTE           10368          
+#define UCODE_ID_CP_CE_SIZE_BYTE           8576        
+#define UCODE_ID_CP_PFP_SIZE_BYTE          16768           
+#define UCODE_ID_CP_ME_SIZE_BYTE           16768            
+#define UCODE_ID_CP_MEC_JT1_SIZE_BYTE      384               
+#define UCODE_ID_CP_MEC_JT2_SIZE_BYTE      384            
+#define UCODE_ID_GMCON_RENG_SIZE_BYTE      4096              
+#define UCODE_ID_RLC_G_SIZE_BYTE           2048             
+#define UCODE_ID_RLC_SCRATCH_SIZE_BYTE     132           
+#define UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE    8192                  
+#define UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE    4096                   
+#define UCODE_ID_DMCU_ERAM_SIZE_BYTE       24576               
+#define UCODE_ID_DMCU_IRAM_SIZE_BYTE       1024                 
+
+#define NUM_UCODES               14
+
+typedef struct {
+	uint32_t high;
+	uint32_t low;
+} data_64_t;
+
+struct SMU_Task {
+    uint8_t type;
+    uint8_t arg;
+    uint16_t next;
+    data_64_t addr;
+    uint32_t size_bytes;
+};
+typedef struct SMU_Task SMU_Task;
+
+struct TOC {
+    uint8_t JobList[NUM_JOBLIST_ENTRIES];
+    SMU_Task tasks[1];
+};
+
+// META DATA COMMAND Definitions
+#define METADATA_CMD_MODE0         0x00000103 
+#define METADATA_CMD_MODE1         0x00000113 
+#define METADATA_CMD_MODE2         0x00000123 
+#define METADATA_CMD_MODE3         0x00000133
+#define METADATA_CMD_DELAY         0x00000203
+#define METADATA_CMD_CHNG_REGSPACE 0x00000303
+#define METADATA_PERFORM_ON_SAVE   0x00001000
+#define METADATA_PERFORM_ON_LOAD   0x00002000
+#define METADATA_CMD_ARG_MASK      0xFFFF0000
+#define METADATA_CMD_ARG_SHIFT     16
+
+// Simple register addr/data fields
+struct SMU_MetaData_Mode0 {
+    uint32_t register_address;
+    uint32_t register_data;
+};
+typedef struct SMU_MetaData_Mode0 SMU_MetaData_Mode0;
+
+// Register addr/data with mask
+struct SMU_MetaData_Mode1 {
+    uint32_t register_address;
+    uint32_t register_mask;
+    uint32_t register_data;
+};
+typedef struct SMU_MetaData_Mode1 SMU_MetaData_Mode1;
+
+struct SMU_MetaData_Mode2 {
+    uint32_t register_address;
+    uint32_t register_mask;
+    uint32_t target_value;
+};
+typedef struct SMU_MetaData_Mode2 SMU_MetaData_Mode2;
+
+// Always write data (even on a save operation)
+struct SMU_MetaData_Mode3 {
+    uint32_t register_address;
+    uint32_t register_mask;
+    uint32_t register_data;
+};
+typedef struct SMU_MetaData_Mode3 SMU_MetaData_Mode3;
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_vi.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_vi.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SMU_UCODE_XFER_VI_H
+#define SMU_UCODE_XFER_VI_H
+
+#define SMU_DRAMData_TOC_VERSION  1
+#define MAX_IH_REGISTER_COUNT     65535
+#define SMU_DIGEST_SIZE_BYTES     20
+#define SMU_FB_SIZE_BYTES         1048576
+#define SMU_MAX_ENTRIES           12
+
+#define UCODE_ID_SMU              0
+#define UCODE_ID_SDMA0            1
+#define UCODE_ID_SDMA1            2
+#define UCODE_ID_CP_CE            3
+#define UCODE_ID_CP_PFP           4
+#define UCODE_ID_CP_ME            5
+#define UCODE_ID_CP_MEC           6
+#define UCODE_ID_CP_MEC_JT1       7
+#define UCODE_ID_CP_MEC_JT2       8
+#define UCODE_ID_GMCON_RENG       9
+#define UCODE_ID_RLC_G            10
+#define UCODE_ID_IH_REG_RESTORE   11
+#define UCODE_ID_VBIOS            12
+#define UCODE_ID_MISC_METADATA    13
+#define UCODE_ID_RLC_SCRATCH      32
+#define UCODE_ID_RLC_SRM_ARAM     33
+#define UCODE_ID_RLC_SRM_DRAM     34
+#define UCODE_ID_MEC_STORAGE      35
+#define UCODE_ID_VBIOS_PARAMETERS 36
+#define UCODE_META_DATA           0xFF
+
+#define UCODE_ID_SMU_MASK             0x00000001
+#define UCODE_ID_SDMA0_MASK           0x00000002
+#define UCODE_ID_SDMA1_MASK           0x00000004
+#define UCODE_ID_CP_CE_MASK           0x00000008
+#define UCODE_ID_CP_PFP_MASK          0x00000010
+#define UCODE_ID_CP_ME_MASK           0x00000020
+#define UCODE_ID_CP_MEC_MASK          0x00000040
+#define UCODE_ID_CP_MEC_JT1_MASK      0x00000080
+#define UCODE_ID_CP_MEC_JT2_MASK      0x00000100
+#define UCODE_ID_GMCON_RENG_MASK      0x00000200
+#define UCODE_ID_RLC_G_MASK           0x00000400
+#define UCODE_ID_IH_REG_RESTORE_MASK  0x00000800
+#define UCODE_ID_VBIOS_MASK           0x00001000
+
+#define UCODE_FLAG_UNHALT_MASK   0x1
+
+struct SMU_Entry {
+#ifndef __BIG_ENDIAN
+	uint16_t id;
+	uint16_t version;
+	uint32_t image_addr_high;
+	uint32_t image_addr_low;
+	uint32_t meta_data_addr_high;
+	uint32_t meta_data_addr_low;
+	uint32_t data_size_byte;
+	uint16_t flags;
+	uint16_t num_register_entries;
+#else
+	uint16_t version;
+	uint16_t id;
+	uint32_t image_addr_high;
+	uint32_t image_addr_low;
+	uint32_t meta_data_addr_high;
+	uint32_t meta_data_addr_low;
+	uint32_t data_size_byte;
+	uint16_t num_register_entries;
+	uint16_t flags;
+#endif
+};
+
+struct SMU_DRAMData_TOC {
+	uint32_t structure_version;
+	uint32_t num_entries;
+	struct SMU_Entry entry[SMU_MAX_ENTRIES];
+};
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _SMUMGR_H_
+#define _SMUMGR_H_
+#include <linux/types.h>
+#include "pp_instance.h"
+#include "amd_powerplay.h"
+
+struct pp_smumgr;
+struct pp_instance;
+
+#define smu_lower_32_bits(n) ((uint32_t)(n))
+#define smu_upper_32_bits(n) ((uint32_t)(((n)>>16)>>16))
+
+struct pp_smumgr_func {
+	int (*smu_init)(struct pp_smumgr *smumgr);
+	int (*smu_fini)(struct pp_smumgr *smumgr);
+	int (*start_smu)(struct pp_smumgr *smumgr);
+	int (*check_fw_load_finish)(struct pp_smumgr *smumgr,
+				    uint32_t firmware);
+	int (*request_smu_load_fw)(struct pp_smumgr *smumgr);
+	int (*request_smu_load_specific_fw)(struct pp_smumgr *smumgr,
+					    uint32_t firmware);
+	int (*get_argument)(struct pp_smumgr *smumgr);
+	int (*send_msg_to_smc)(struct pp_smumgr *smumgr, uint16_t msg);
+	int (*send_msg_to_smc_with_parameter)(struct pp_smumgr *smumgr,
+					  uint16_t msg, uint32_t parameter);
+	int (*download_pptable_settings)(struct pp_smumgr *smumgr,
+					 void **table);
+	int (*upload_pptable_settings)(struct pp_smumgr *smumgr);
+};
+
+struct pp_smumgr {
+	uint32_t chip_family;
+	uint32_t chip_id;
+	uint32_t hw_revision;
+	void *device;
+	void *backend;
+	uint32_t usec_timeout;
+	bool reload_fw;
+	const struct pp_smumgr_func *smumgr_funcs;
+};
+
+
+extern int smum_init(struct amd_pp_init *pp_init,
+		     struct pp_instance *handle);
+
+extern int smum_fini(struct pp_smumgr *smumgr);
+
+extern int smum_get_argument(struct pp_smumgr *smumgr);
+
+extern int smum_download_powerplay_table(struct pp_smumgr *smumgr, void **table);
+
+extern int smum_upload_powerplay_table(struct pp_smumgr *smumgr);
+
+extern int smum_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg);
+
+extern int smum_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+					uint16_t msg, uint32_t parameter);
+
+extern int smum_wait_on_register(struct pp_smumgr *smumgr,
+				uint32_t index, uint32_t value, uint32_t mask);
+
+extern int smum_wait_for_register_unequal(struct pp_smumgr *smumgr,
+				uint32_t index, uint32_t value, uint32_t mask);
+
+extern int smum_wait_on_indirect_register(struct pp_smumgr *smumgr,
+				uint32_t indirect_port, uint32_t index,
+				uint32_t value, uint32_t mask);
+
+
+extern void smum_wait_for_indirect_register_unequal(
+				struct pp_smumgr *smumgr,
+				uint32_t indirect_port, uint32_t index,
+				uint32_t value, uint32_t mask);
+
+extern int smu_allocate_memory(void *device, uint32_t size,
+			 enum cgs_gpu_mem_type type,
+			 uint32_t byte_align, uint64_t *mc_addr,
+			 void **kptr, void *handle);
+
+extern int smu_free_memory(void *device, void *handle);
+
+#define SMUM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
+
+#define SMUM_FIELD_MASK(reg, field) reg##__##field##_MASK
+
+#define SMUM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(smumgr,			\
+					port, index, value, mask)	\
+	smum_wait_on_indirect_register(smumgr,				\
+				mm##port##_INDEX, index, value, mask)
+
+
+#define SMUM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(smumgr,         \
+							index, value, mask) \
+		smum_wait_for_register_unequal(smumgr,            \
+					index, value, mask)
+
+#define SMUM_WAIT_REGISTER_UNEQUAL(smumgr, reg, value, mask)		\
+	SMUM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(smumgr,			\
+				mm##reg, value, mask)
+
+#define SMUM_WAIT_FIELD_UNEQUAL(smumgr, reg, field, fieldval)		\
+	SMUM_WAIT_REGISTER_UNEQUAL(smumgr, reg,				\
+		(fieldval) << SMUM_FIELD_SHIFT(reg, field),		\
+		SMUM_FIELD_MASK(reg, field))
+
+#define SMUM_GET_FIELD(value, reg, field)				\
+		(((value) & SMUM_FIELD_MASK(reg, field))		\
+		>> SMUM_FIELD_SHIFT(reg, field))
+
+#define SMUM_READ_FIELD(device, reg, field)                           \
+		SMUM_GET_FIELD(cgs_read_register(device, mm##reg), reg, field)
+
+#define SMUM_SET_FIELD(value, reg, field, field_val)                  \
+		(((value) & ~SMUM_FIELD_MASK(reg, field)) |                    \
+		(SMUM_FIELD_MASK(reg, field) & ((field_val) <<                 \
+			SMUM_FIELD_SHIFT(reg, field))))
+
+#define SMUM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(smumgr,		\
+				port, index, value, mask)		\
+	smum_wait_on_indirect_register(smumgr,				\
+		mm##port##_INDEX_0, index, value, mask)
+
+#define SMUM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(smumgr,	\
+				port, index, value, mask)		\
+	smum_wait_for_indirect_register_unequal(smumgr,			\
+		mm##port##_INDEX_0, index, value, mask)
+
+
+#define SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, port, reg, value, mask) \
+	SMUM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(smumgr, port, ix##reg, value, mask)
+
+#define SMUM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(smumgr, port, reg, value, mask)     \
+		SMUM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(smumgr, port, ix##reg, value, mask)
+
+
+/*Operations on named fields.*/
+
+#define SMUM_READ_VFPF_INDIRECT_FIELD(device, port, reg, field) \
+		SMUM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \
+			reg, field)
+
+#define SMUM_WRITE_FIELD(device, reg, field, fieldval)            \
+		cgs_write_register(device, mm##reg, \
+		SMUM_SET_FIELD(cgs_read_register(device, mm##reg), reg, field, fieldval))
+
+#define SMUM_WRITE_VFPF_INDIRECT_FIELD(device, port, reg, field, fieldval)    \
+		cgs_write_ind_register(device, port, ix##reg, \
+			SMUM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \
+			reg, field, fieldval))
+
+#define SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, port, reg, field, fieldval) \
+	SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, port, reg,		\
+		(fieldval) << SMUM_FIELD_SHIFT(reg, field),		\
+		SMUM_FIELD_MASK(reg, field))
+
+#define SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, port, reg, field, fieldval) \
+	SMUM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(smumgr, port, reg,	\
+		(fieldval) << SMUM_FIELD_SHIFT(reg, field),		\
+		SMUM_FIELD_MASK(reg, field))
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/tonga_ppsmc.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/inc/tonga_ppsmc.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef TONGA_PP_SMC_H
+#define TONGA_PP_SMC_H
+
+#pragma pack(push, 1)
+
+#define PPSMC_SWSTATE_FLAG_DC				0x01
+#define PPSMC_SWSTATE_FLAG_UVD				0x02
+#define PPSMC_SWSTATE_FLAG_VCE				0x04
+#define PPSMC_SWSTATE_FLAG_PCIE_X1			0x08
+
+#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL             0x00
+#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL             0x01
+#define PPSMC_THERMAL_PROTECT_TYPE_NONE                 0xff
+
+#define PPSMC_SYSTEMFLAG_GPIO_DC                        0x01
+#define PPSMC_SYSTEMFLAG_STEPVDDC                       0x02
+#define PPSMC_SYSTEMFLAG_GDDR5                          0x04
+
+#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP               0x08
+
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT                  0x10
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG           0x20
+#define PPSMC_SYSTEMFLAG_12CHANNEL                      0x40
+
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK              0x07
+#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK     0x08
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE   0x00
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE  0x01
+
+#define PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH      0x10
+#define PPSMC_EXTRAFLAGS_DRIVER_TO_GPIO17               0x20
+#define PPSMC_EXTRAFLAGS_PCC_TO_GPIO17                  0x40
+
+/* Defines for DPM 2.0 */
+#define PPSMC_DPM2FLAGS_TDPCLMP                         0x01
+#define PPSMC_DPM2FLAGS_PWRSHFT                         0x02
+#define PPSMC_DPM2FLAGS_OCP                             0x04
+
+/* Defines for display watermark level */
+
+#define PPSMC_DISPLAY_WATERMARK_LOW                     0
+#define PPSMC_DISPLAY_WATERMARK_HIGH                    1
+
+/* In the HW performance level's state flags:*/
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP    0x01
+#define PPSMC_STATEFLAG_POWERBOOST         0x02
+#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
+#define PPSMC_STATEFLAG_POWERSHIFT         0x08
+#define PPSMC_STATEFLAG_SLOW_READ_MARGIN   0x10
+#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
+#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS   0x40
+
+/* Fan control algorithm:*/
+#define FDO_MODE_HARDWARE 0
+#define FDO_MODE_PIECE_WISE_LINEAR 1
+
+enum FAN_CONTROL {
+	FAN_CONTROL_FUZZY,
+	FAN_CONTROL_TABLE
+};
+
+/* Return codes for driver to SMC communication.*/
+
+#define PPSMC_Result_OK             ((uint16_t)0x01)
+#define PPSMC_Result_NoMore         ((uint16_t)0x02)
+#define PPSMC_Result_NotNow         ((uint16_t)0x03)
+
+#define PPSMC_Result_Failed         ((uint16_t)0xFF)
+#define PPSMC_Result_UnknownCmd     ((uint16_t)0xFE)
+#define PPSMC_Result_UnknownVT      ((uint16_t)0xFD)
+
+typedef uint16_t PPSMC_Result;
+
+#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
+
+
+#define PPSMC_MSG_Halt                      ((uint16_t)0x10)
+#define PPSMC_MSG_Resume                    ((uint16_t)0x11)
+#define PPSMC_MSG_EnableDPMLevel            ((uint16_t)0x12)
+#define PPSMC_MSG_ZeroLevelsDisabled        ((uint16_t)0x13)
+#define PPSMC_MSG_OneLevelsDisabled         ((uint16_t)0x14)
+#define PPSMC_MSG_TwoLevelsDisabled         ((uint16_t)0x15)
+#define PPSMC_MSG_EnableThermalInterrupt    ((uint16_t)0x16)
+#define PPSMC_MSG_RunningOnAC               ((uint16_t)0x17)
+#define PPSMC_MSG_LevelUp                   ((uint16_t)0x18)
+#define PPSMC_MSG_LevelDown                 ((uint16_t)0x19)
+#define PPSMC_MSG_ResetDPMCounters          ((uint16_t)0x1a)
+#define PPSMC_MSG_SwitchToSwState           ((uint16_t)0x20)
+
+#define PPSMC_MSG_SwitchToSwStateLast       ((uint16_t)0x3f)
+#define PPSMC_MSG_SwitchToInitialState      ((uint16_t)0x40)
+#define PPSMC_MSG_NoForcedLevel             ((uint16_t)0x41)
+#define PPSMC_MSG_ForceHigh                 ((uint16_t)0x42)
+#define PPSMC_MSG_ForceMediumOrHigh         ((uint16_t)0x43)
+
+#define PPSMC_MSG_SwitchToMinimumPower      ((uint16_t)0x51)
+#define PPSMC_MSG_ResumeFromMinimumPower    ((uint16_t)0x52)
+#define PPSMC_MSG_EnableCac                 ((uint16_t)0x53)
+#define PPSMC_MSG_DisableCac                ((uint16_t)0x54)
+#define PPSMC_DPMStateHistoryStart          ((uint16_t)0x55)
+#define PPSMC_DPMStateHistoryStop           ((uint16_t)0x56)
+#define PPSMC_CACHistoryStart               ((uint16_t)0x57)
+#define PPSMC_CACHistoryStop                ((uint16_t)0x58)
+#define PPSMC_TDPClampingActive             ((uint16_t)0x59)
+#define PPSMC_TDPClampingInactive           ((uint16_t)0x5A)
+#define PPSMC_StartFanControl               ((uint16_t)0x5B)
+#define PPSMC_StopFanControl                ((uint16_t)0x5C)
+#define PPSMC_NoDisplay                     ((uint16_t)0x5D)
+#define PPSMC_HasDisplay                    ((uint16_t)0x5E)
+#define PPSMC_MSG_UVDPowerOFF               ((uint16_t)0x60)
+#define PPSMC_MSG_UVDPowerON                ((uint16_t)0x61)
+#define PPSMC_MSG_EnableULV                 ((uint16_t)0x62)
+#define PPSMC_MSG_DisableULV                ((uint16_t)0x63)
+#define PPSMC_MSG_EnterULV                  ((uint16_t)0x64)
+#define PPSMC_MSG_ExitULV                   ((uint16_t)0x65)
+#define PPSMC_PowerShiftActive              ((uint16_t)0x6A)
+#define PPSMC_PowerShiftInactive            ((uint16_t)0x6B)
+#define PPSMC_OCPActive                     ((uint16_t)0x6C)
+#define PPSMC_OCPInactive                   ((uint16_t)0x6D)
+#define PPSMC_CACLongTermAvgEnable          ((uint16_t)0x6E)
+#define PPSMC_CACLongTermAvgDisable         ((uint16_t)0x6F)
+#define PPSMC_MSG_InferredStateSweep_Start  ((uint16_t)0x70)
+#define PPSMC_MSG_InferredStateSweep_Stop   ((uint16_t)0x71)
+#define PPSMC_MSG_SwitchToLowestInfState    ((uint16_t)0x72)
+#define PPSMC_MSG_SwitchToNonInfState       ((uint16_t)0x73)
+#define PPSMC_MSG_AllStateSweep_Start       ((uint16_t)0x74)
+#define PPSMC_MSG_AllStateSweep_Stop        ((uint16_t)0x75)
+#define PPSMC_MSG_SwitchNextLowerInfState   ((uint16_t)0x76)
+#define PPSMC_MSG_SwitchNextHigherInfState  ((uint16_t)0x77)
+#define PPSMC_MSG_MclkRetrainingTest        ((uint16_t)0x78)
+#define PPSMC_MSG_ForceTDPClamping          ((uint16_t)0x79)
+#define PPSMC_MSG_CollectCAC_PowerCorreln   ((uint16_t)0x7A)
+#define PPSMC_MSG_CollectCAC_WeightCalib    ((uint16_t)0x7B)
+#define PPSMC_MSG_CollectCAC_SQonly         ((uint16_t)0x7C)
+#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
+
+#define PPSMC_MSG_ExtremitiesTest_Start     ((uint16_t)0x7E)
+#define PPSMC_MSG_ExtremitiesTest_Stop      ((uint16_t)0x7F)
+#define PPSMC_FlushDataCache                ((uint16_t)0x80)
+#define PPSMC_FlushInstrCache               ((uint16_t)0x81)
+
+#define PPSMC_MSG_SetEnabledLevels          ((uint16_t)0x82)
+#define PPSMC_MSG_SetForcedLevels           ((uint16_t)0x83)
+
+#define PPSMC_MSG_ResetToDefaults           ((uint16_t)0x84)
+
+#define PPSMC_MSG_SetForcedLevelsAndJump    ((uint16_t)0x85)
+#define PPSMC_MSG_SetCACHistoryMode         ((uint16_t)0x86)
+#define PPSMC_MSG_EnableDTE                 ((uint16_t)0x87)
+#define PPSMC_MSG_DisableDTE                ((uint16_t)0x88)
+
+#define PPSMC_MSG_SmcSpaceSetAddress        ((uint16_t)0x89)
+#define PPSMC_MSG_ChangeNearTDPLimit        ((uint16_t)0x90)
+#define PPSMC_MSG_ChangeSafePowerLimit      ((uint16_t)0x91)
+
+#define PPSMC_MSG_DPMStateSweepStart        ((uint16_t)0x92)
+#define PPSMC_MSG_DPMStateSweepStop         ((uint16_t)0x93)
+
+#define PPSMC_MSG_OVRDDisableSCLKDS         ((uint16_t)0x94)
+#define PPSMC_MSG_CancelDisableOVRDSCLKDS   ((uint16_t)0x95)
+#define PPSMC_MSG_ThrottleOVRDSCLKDS        ((uint16_t)0x96)
+#define PPSMC_MSG_CancelThrottleOVRDSCLKDS  ((uint16_t)0x97)
+#define PPSMC_MSG_GPIO17					((uint16_t)0x98)
+
+#define PPSMC_MSG_API_SetSvi2Volt_Vddc      ((uint16_t)0x99)
+#define PPSMC_MSG_API_SetSvi2Volt_Vddci     ((uint16_t)0x9A)
+#define PPSMC_MSG_API_SetSvi2Volt_Mvdd      ((uint16_t)0x9B)
+#define PPSMC_MSG_API_GetSvi2Volt_Vddc      ((uint16_t)0x9C)
+#define PPSMC_MSG_API_GetSvi2Volt_Vddci     ((uint16_t)0x9D)
+#define PPSMC_MSG_API_GetSvi2Volt_Mvdd      ((uint16_t)0x9E)
+
+#define PPSMC_MSG_BREAK                     ((uint16_t)0xF8)
+
+/* Trinity Specific Messages*/
+#define PPSMC_MSG_Test                      ((uint16_t) 0x100)
+#define PPSMC_MSG_DPM_Voltage_Pwrmgt        ((uint16_t) 0x101)
+#define PPSMC_MSG_DPM_Config                ((uint16_t) 0x102)
+#define PPSMC_MSG_PM_Controller_Start       ((uint16_t) 0x103)
+#define PPSMC_MSG_DPM_ForceState            ((uint16_t) 0x104)
+#define PPSMC_MSG_PG_PowerDownSIMD          ((uint16_t) 0x105)
+#define PPSMC_MSG_PG_PowerUpSIMD            ((uint16_t) 0x106)
+#define PPSMC_MSG_PM_Controller_Stop        ((uint16_t) 0x107)
+#define PPSMC_MSG_PG_SIMD_Config            ((uint16_t) 0x108)
+#define PPSMC_MSG_Voltage_Cntl_Enable       ((uint16_t) 0x109)
+#define PPSMC_MSG_Thermal_Cntl_Enable       ((uint16_t) 0x10a)
+#define PPSMC_MSG_Reset_Service             ((uint16_t) 0x10b)
+#define PPSMC_MSG_VCEPowerOFF               ((uint16_t) 0x10e)
+#define PPSMC_MSG_VCEPowerON                ((uint16_t) 0x10f)
+#define PPSMC_MSG_DPM_Disable_VCE_HS        ((uint16_t) 0x110)
+#define PPSMC_MSG_DPM_Enable_VCE_HS         ((uint16_t) 0x111)
+#define PPSMC_MSG_DPM_N_LevelsDisabled      ((uint16_t) 0x112)
+#define PPSMC_MSG_DCEPowerOFF               ((uint16_t) 0x113)
+#define PPSMC_MSG_DCEPowerON                ((uint16_t) 0x114)
+#define PPSMC_MSG_PCIE_DDIPowerDown         ((uint16_t) 0x117)
+#define PPSMC_MSG_PCIE_DDIPowerUp           ((uint16_t) 0x118)
+#define PPSMC_MSG_PCIE_CascadePLLPowerDown  ((uint16_t) 0x119)
+#define PPSMC_MSG_PCIE_CascadePLLPowerUp    ((uint16_t) 0x11a)
+#define PPSMC_MSG_SYSPLLPowerOff            ((uint16_t) 0x11b)
+#define PPSMC_MSG_SYSPLLPowerOn             ((uint16_t) 0x11c)
+#define PPSMC_MSG_DCE_RemoveVoltageAdjustment   ((uint16_t) 0x11d)
+#define PPSMC_MSG_DCE_AllowVoltageAdjustment    ((uint16_t) 0x11e)
+#define PPSMC_MSG_DISPLAYPHYStatusNotify    ((uint16_t) 0x11f)
+#define PPSMC_MSG_EnableBAPM                ((uint16_t) 0x120)
+#define PPSMC_MSG_DisableBAPM               ((uint16_t) 0x121)
+#define PPSMC_MSG_PCIE_PHYPowerDown         ((uint16_t) 0x122)
+#define PPSMC_MSG_PCIE_PHYPowerUp           ((uint16_t) 0x123)
+#define PPSMC_MSG_UVD_DPM_Config            ((uint16_t) 0x124)
+#define PPSMC_MSG_Spmi_Enable               ((uint16_t) 0x122)
+#define PPSMC_MSG_Spmi_Timer                ((uint16_t) 0x123)
+#define PPSMC_MSG_LCLK_DPM_Config           ((uint16_t) 0x124)
+#define PPSMC_MSG_NBDPM_Config             ((uint16_t) 0x125)
+#define PPSMC_MSG_PCIE_DDIPhyPowerDown           ((uint16_t) 0x126)
+#define PPSMC_MSG_PCIE_DDIPhyPowerUp             ((uint16_t) 0x127)
+#define PPSMC_MSG_MCLKDPM_Config                ((uint16_t) 0x128)
+
+#define PPSMC_MSG_UVDDPM_Config               ((uint16_t) 0x129)
+#define PPSMC_MSG_VCEDPM_Config               ((uint16_t) 0x12A)
+#define PPSMC_MSG_ACPDPM_Config               ((uint16_t) 0x12B)
+#define PPSMC_MSG_SAMUDPM_Config              ((uint16_t) 0x12C)
+#define PPSMC_MSG_UVDDPM_SetEnabledMask       ((uint16_t) 0x12D)
+#define PPSMC_MSG_VCEDPM_SetEnabledMask       ((uint16_t) 0x12E)
+#define PPSMC_MSG_ACPDPM_SetEnabledMask       ((uint16_t) 0x12F)
+#define PPSMC_MSG_SAMUDPM_SetEnabledMask      ((uint16_t) 0x130)
+#define PPSMC_MSG_MCLKDPM_ForceState          ((uint16_t) 0x131)
+#define PPSMC_MSG_MCLKDPM_NoForcedLevel       ((uint16_t) 0x132)
+#define PPSMC_MSG_Thermal_Cntl_Disable        ((uint16_t) 0x133)
+#define PPSMC_MSG_SetTDPLimit                 ((uint16_t) 0x134)
+#define PPSMC_MSG_Voltage_Cntl_Disable        ((uint16_t) 0x135)
+#define PPSMC_MSG_PCIeDPM_Enable              ((uint16_t) 0x136)
+#define PPSMC_MSG_ACPPowerOFF                 ((uint16_t) 0x137)
+#define PPSMC_MSG_ACPPowerON                  ((uint16_t) 0x138)
+#define PPSMC_MSG_SAMPowerOFF                 ((uint16_t) 0x139)
+#define PPSMC_MSG_SAMPowerON                  ((uint16_t) 0x13a)
+#define PPSMC_MSG_SDMAPowerOFF                ((uint16_t) 0x13b)
+#define PPSMC_MSG_SDMAPowerON                 ((uint16_t) 0x13c)
+#define PPSMC_MSG_PCIeDPM_Disable             ((uint16_t) 0x13d)
+#define PPSMC_MSG_IOMMUPowerOFF               ((uint16_t) 0x13e)
+#define PPSMC_MSG_IOMMUPowerON                ((uint16_t) 0x13f)
+#define PPSMC_MSG_NBDPM_Enable                ((uint16_t) 0x140)
+#define PPSMC_MSG_NBDPM_Disable               ((uint16_t) 0x141)
+#define PPSMC_MSG_NBDPM_ForceNominal          ((uint16_t) 0x142)
+#define PPSMC_MSG_NBDPM_ForcePerformance      ((uint16_t) 0x143)
+#define PPSMC_MSG_NBDPM_UnForce               ((uint16_t) 0x144)
+#define PPSMC_MSG_SCLKDPM_SetEnabledMask      ((uint16_t) 0x145)
+#define PPSMC_MSG_MCLKDPM_SetEnabledMask      ((uint16_t) 0x146)
+#define PPSMC_MSG_PCIeDPM_ForceLevel          ((uint16_t) 0x147)
+#define PPSMC_MSG_PCIeDPM_UnForceLevel        ((uint16_t) 0x148)
+#define PPSMC_MSG_EnableACDCGPIOInterrupt     ((uint16_t) 0x149)
+#define PPSMC_MSG_EnableVRHotGPIOInterrupt    ((uint16_t) 0x14a)
+#define PPSMC_MSG_SwitchToAC                  ((uint16_t) 0x14b)
+
+#define PPSMC_MSG_XDMAPowerOFF                ((uint16_t) 0x14c)
+#define PPSMC_MSG_XDMAPowerON                 ((uint16_t) 0x14d)
+
+#define PPSMC_MSG_DPM_Enable                  ((uint16_t)0x14e)
+#define PPSMC_MSG_DPM_Disable                 ((uint16_t)0x14f)
+#define PPSMC_MSG_MCLKDPM_Enable              ((uint16_t)0x150)
+#define PPSMC_MSG_MCLKDPM_Disable             ((uint16_t)0x151)
+#define PPSMC_MSG_LCLKDPM_Enable              ((uint16_t)0x152)
+#define PPSMC_MSG_LCLKDPM_Disable             ((uint16_t)0x153)
+#define PPSMC_MSG_UVDDPM_Enable               ((uint16_t)0x154)
+#define PPSMC_MSG_UVDDPM_Disable              ((uint16_t)0x155)
+#define PPSMC_MSG_SAMUDPM_Enable              ((uint16_t)0x156)
+#define PPSMC_MSG_SAMUDPM_Disable             ((uint16_t)0x157)
+#define PPSMC_MSG_ACPDPM_Enable               ((uint16_t)0x158)
+#define PPSMC_MSG_ACPDPM_Disable              ((uint16_t)0x159)
+#define PPSMC_MSG_VCEDPM_Enable               ((uint16_t)0x15a)
+#define PPSMC_MSG_VCEDPM_Disable              ((uint16_t)0x15b)
+#define PPSMC_MSG_LCLKDPM_SetEnabledMask      ((uint16_t)0x15c)
+
+#define PPSMC_MSG_DPM_FPS_Mode                ((uint16_t) 0x15d)
+#define PPSMC_MSG_DPM_Activity_Mode           ((uint16_t) 0x15e)
+#define PPSMC_MSG_VddC_Request                ((uint16_t) 0x15f)
+#define PPSMC_MSG_MCLKDPM_GetEnabledMask      ((uint16_t) 0x160)
+#define PPSMC_MSG_LCLKDPM_GetEnabledMask      ((uint16_t) 0x161)
+#define PPSMC_MSG_SCLKDPM_GetEnabledMask      ((uint16_t) 0x162)
+#define PPSMC_MSG_UVDDPM_GetEnabledMask       ((uint16_t) 0x163)
+#define PPSMC_MSG_SAMUDPM_GetEnabledMask      ((uint16_t) 0x164)
+#define PPSMC_MSG_ACPDPM_GetEnabledMask       ((uint16_t) 0x165)
+#define PPSMC_MSG_VCEDPM_GetEnabledMask       ((uint16_t) 0x166)
+#define PPSMC_MSG_PCIeDPM_SetEnabledMask      ((uint16_t) 0x167)
+#define PPSMC_MSG_PCIeDPM_GetEnabledMask      ((uint16_t) 0x168)
+#define PPSMC_MSG_TDCLimitEnable              ((uint16_t) 0x169)
+#define PPSMC_MSG_TDCLimitDisable             ((uint16_t) 0x16a)
+#define PPSMC_MSG_DPM_AutoRotate_Mode         ((uint16_t) 0x16b)
+#define PPSMC_MSG_DISPCLK_FROM_FCH            ((uint16_t)0x16c)
+#define PPSMC_MSG_DISPCLK_FROM_DFS            ((uint16_t)0x16d)
+#define PPSMC_MSG_DPREFCLK_FROM_FCH           ((uint16_t)0x16e)
+#define PPSMC_MSG_DPREFCLK_FROM_DFS           ((uint16_t)0x16f)
+#define PPSMC_MSG_PmStatusLogStart            ((uint16_t)0x170)
+#define PPSMC_MSG_PmStatusLogSample           ((uint16_t)0x171)
+#define PPSMC_MSG_SCLK_AutoDPM_ON             ((uint16_t) 0x172)
+#define PPSMC_MSG_MCLK_AutoDPM_ON             ((uint16_t) 0x173)
+#define PPSMC_MSG_LCLK_AutoDPM_ON             ((uint16_t) 0x174)
+#define PPSMC_MSG_UVD_AutoDPM_ON              ((uint16_t) 0x175)
+#define PPSMC_MSG_SAMU_AutoDPM_ON             ((uint16_t) 0x176)
+#define PPSMC_MSG_ACP_AutoDPM_ON              ((uint16_t) 0x177)
+#define PPSMC_MSG_VCE_AutoDPM_ON              ((uint16_t) 0x178)
+#define PPSMC_MSG_PCIe_AutoDPM_ON             ((uint16_t) 0x179)
+#define PPSMC_MSG_MASTER_AutoDPM_ON           ((uint16_t) 0x17a)
+#define PPSMC_MSG_MASTER_AutoDPM_OFF          ((uint16_t) 0x17b)
+#define PPSMC_MSG_DYNAMICDISPPHYPOWER         ((uint16_t) 0x17c)
+#define PPSMC_MSG_CAC_COLLECTION_ON           ((uint16_t) 0x17d)
+#define PPSMC_MSG_CAC_COLLECTION_OFF          ((uint16_t) 0x17e)
+#define PPSMC_MSG_CAC_CORRELATION_ON          ((uint16_t) 0x17f)
+#define PPSMC_MSG_CAC_CORRELATION_OFF         ((uint16_t) 0x180)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_ON        ((uint16_t) 0x181)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_OFF       ((uint16_t) 0x182)
+#define PPSMC_MSG_UVD_HANDSHAKE_OFF           ((uint16_t) 0x183)
+#define PPSMC_MSG_ALLOW_LOWSCLK_INTERRUPT     ((uint16_t) 0x184)
+#define PPSMC_MSG_PkgPwrLimitEnable           ((uint16_t) 0x185)
+#define PPSMC_MSG_PkgPwrLimitDisable          ((uint16_t) 0x186)
+#define PPSMC_MSG_PkgPwrSetLimit              ((uint16_t) 0x187)
+#define PPSMC_MSG_OverDriveSetTargetTdp       ((uint16_t) 0x188)
+#define PPSMC_MSG_SCLKDPM_FreezeLevel         ((uint16_t) 0x189)
+#define PPSMC_MSG_SCLKDPM_UnfreezeLevel       ((uint16_t) 0x18A)
+#define PPSMC_MSG_MCLKDPM_FreezeLevel         ((uint16_t) 0x18B)
+#define PPSMC_MSG_MCLKDPM_UnfreezeLevel       ((uint16_t) 0x18C)
+#define PPSMC_MSG_START_DRAM_LOGGING          ((uint16_t) 0x18D)
+#define PPSMC_MSG_STOP_DRAM_LOGGING           ((uint16_t) 0x18E)
+#define PPSMC_MSG_MASTER_DeepSleep_ON         ((uint16_t) 0x18F)
+#define PPSMC_MSG_MASTER_DeepSleep_OFF        ((uint16_t) 0x190)
+#define PPSMC_MSG_Remove_DC_Clamp             ((uint16_t) 0x191)
+#define PPSMC_MSG_DisableACDCGPIOInterrupt    ((uint16_t) 0x192)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddc       ((uint16_t) 0x193)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddci      ((uint16_t) 0x194)
+#define PPSMC_MSG_SetVidOffset_1              ((uint16_t) 0x195)
+#define PPSMC_MSG_SetVidOffset_2              ((uint16_t) 0x207)
+#define PPSMC_MSG_GetVidOffset_1              ((uint16_t) 0x196)
+#define PPSMC_MSG_GetVidOffset_2              ((uint16_t) 0x208)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Enable    ((uint16_t) 0x197)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Disable	  ((uint16_t) 0x198)
+#define PPSMC_MSG_SetTjMax                    ((uint16_t) 0x199)
+#define PPSMC_MSG_SetFanPwmMax                ((uint16_t) 0x19A)
+
+#define PPSMC_MSG_WaitForMclkSwitchFinish	  ((uint16_t) 0x19B)
+#define PPSMC_MSG_ENABLE_THERMAL_DPM          ((uint16_t) 0x19C)
+#define PPSMC_MSG_DISABLE_THERMAL_DPM         ((uint16_t) 0x19D)
+#define PPSMC_MSG_Enable_PCC                  ((uint16_t) 0x19E)
+#define PPSMC_MSG_Disable_PCC                 ((uint16_t) 0x19F)
+
+#define PPSMC_MSG_API_GetSclkFrequency        ((uint16_t) 0x200)
+#define PPSMC_MSG_API_GetMclkFrequency        ((uint16_t) 0x201)
+#define PPSMC_MSG_API_GetSclkBusy             ((uint16_t) 0x202)
+#define PPSMC_MSG_API_GetMclkBusy             ((uint16_t) 0x203)
+#define PPSMC_MSG_API_GetAsicPower            ((uint16_t) 0x204)
+#define PPSMC_MSG_SetFanRpmMax                ((uint16_t) 0x205)
+#define PPSMC_MSG_SetFanSclkTarget            ((uint16_t) 0x206)
+#define PPSMC_MSG_SetFanMinPwm                ((uint16_t) 0x209)
+#define PPSMC_MSG_SetFanTemperatureTarget     ((uint16_t) 0x20A)
+
+#define PPSMC_MSG_BACO_StartMonitor           ((uint16_t) 0x240)
+#define PPSMC_MSG_BACO_Cancel                 ((uint16_t) 0x241)
+#define PPSMC_MSG_EnableVddGfx                ((uint16_t) 0x242)
+#define PPSMC_MSG_DisableVddGfx               ((uint16_t) 0x243)
+#define PPSMC_MSG_UcodeAddressLow             ((uint16_t) 0x244)
+#define PPSMC_MSG_UcodeAddressHigh            ((uint16_t) 0x245)
+#define PPSMC_MSG_UcodeLoadStatus             ((uint16_t) 0x246)
+
+#define PPSMC_MSG_DRV_DRAM_ADDR_HI			  ((uint16_t) 0x250)
+#define PPSMC_MSG_DRV_DRAM_ADDR_LO            ((uint16_t) 0x251)
+#define PPSMC_MSG_SMU_DRAM_ADDR_HI            ((uint16_t) 0x252)
+#define PPSMC_MSG_SMU_DRAM_ADDR_LO            ((uint16_t) 0x253)
+#define PPSMC_MSG_LoadUcodes                  ((uint16_t) 0x254)
+#define PPSMC_MSG_PowerStateNotify            ((uint16_t) 0x255)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_HI      ((uint16_t) 0x256)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_LO      ((uint16_t) 0x257)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_HI          ((uint16_t) 0x258)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_LO          ((uint16_t) 0x259)
+#define PPSMC_MSG_LoadVBios                   ((uint16_t) 0x25A)
+#define PPSMC_MSG_GetUcodeVersion             ((uint16_t) 0x25B)
+#define DMCUSMC_MSG_PSREntry                  ((uint16_t) 0x25C)
+#define DMCUSMC_MSG_PSRExit                   ((uint16_t) 0x25D)
+#define PPSMC_MSG_EnableClockGatingFeature    ((uint16_t) 0x260)
+#define PPSMC_MSG_DisableClockGatingFeature   ((uint16_t) 0x261)
+#define PPSMC_MSG_IsDeviceRunning             ((uint16_t) 0x262)
+#define PPSMC_MSG_LoadMetaData                ((uint16_t) 0x263)
+#define PPSMC_MSG_TMON_AutoCaliberate_Enable  ((uint16_t) 0x264)
+#define PPSMC_MSG_TMON_AutoCaliberate_Disable ((uint16_t) 0x265)
+#define PPSMC_MSG_GetTelemetry1Slope          ((uint16_t) 0x266)
+#define PPSMC_MSG_GetTelemetry1Offset         ((uint16_t) 0x267)
+#define PPSMC_MSG_GetTelemetry2Slope          ((uint16_t) 0x268)
+#define PPSMC_MSG_GetTelemetry2Offset         ((uint16_t) 0x269)
+
+typedef uint16_t PPSMC_Msg;
+
+/* If the SMC firmware has an event status soft register this is what the individual bits mean.*/
+#define PPSMC_EVENT_STATUS_THERMAL          0x00000001
+#define PPSMC_EVENT_STATUS_REGULATORHOT     0x00000002
+#define PPSMC_EVENT_STATUS_DC               0x00000004
+#define PPSMC_EVENT_STATUS_GPIO17           0x00000008
+
+
+#pragma pack(pop)
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/Makefile
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/smumgr/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the 'smu manager' sub-component of powerplay.
+# It provides the smu management services for the driver.
+
+SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o
+
+AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_PP_SMUMGR)
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
@@ -0,0 +1,881 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include "linux/delay.h"
+#include "cgs_common.h"
+#include "smu/smu_8_0_d.h"
+#include "smu/smu_8_0_sh_mask.h"
+#include "smu8.h"
+#include "smu8_fusion.h"
+#include "cz_smumgr.h"
+#include "cz_ppsmc.h"
+#include "smu_ucode_xfer_cz.h"
+#include "gca/gfx_8_0_d.h"
+#include "gca/gfx_8_0_sh_mask.h"
+#include "smumgr.h"
+
+#define SIZE_ALIGN_32(x)    (((x) + 31) / 32 * 32)
+
+static enum cz_scratch_entry firmware_list[] = {
+	CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0,
+	CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
+	CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G,
+};
+
+static int cz_smum_get_argument(struct pp_smumgr *smumgr)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	return cgs_read_register(smumgr->device,
+					mmSMU_MP1_SRBM2P_ARG_0);
+}
+
+static int cz_send_msg_to_smc_async(struct pp_smumgr *smumgr,
+								uint16_t msg)
+{
+	int result = 0;
+
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	result = SMUM_WAIT_FIELD_UNEQUAL(smumgr,
+					SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
+	if (result != 0) {
+		printk(KERN_ERR "[ powerplay ] cz_send_msg_to_smc_async failed\n");
+		return result;
+	}
+
+	cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0);
+	cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg);
+
+	return 0;
+}
+
+/* Send a message to the SMC, and wait for its response.*/
+static int cz_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+	int result = 0;
+
+	result = cz_send_msg_to_smc_async(smumgr, msg);
+	if (result != 0)
+		return result;
+
+	result = SMUM_WAIT_FIELD_UNEQUAL(smumgr,
+					SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
+
+	if (result != 0)
+		return result;
+
+	return 0;
+}
+
+static int cz_set_smc_sram_address(struct pp_smumgr *smumgr,
+				     uint32_t smc_address, uint32_t limit)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	if (0 != (3 & smc_address)) {
+		printk(KERN_ERR "[ powerplay ] SMC address must be 4 byte aligned\n");
+		return -1;
+	}
+
+	if (limit <= (smc_address + 3)) {
+		printk(KERN_ERR "[ powerplay ] SMC address beyond the SMC RAM area\n");
+		return -1;
+	}
+
+	cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX_0,
+				SMN_MP1_SRAM_START_ADDR + smc_address);
+
+	return 0;
+}
+
+static int cz_write_smc_sram_dword(struct pp_smumgr *smumgr,
+		uint32_t smc_address, uint32_t value, uint32_t limit)
+{
+	int result;
+
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	result = cz_set_smc_sram_address(smumgr, smc_address, limit);
+	cgs_write_register(smumgr->device, mmMP0PUB_IND_DATA_0, value);
+
+	return 0;
+}
+
+static int cz_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+					  uint16_t msg, uint32_t parameter)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter);
+
+	return cz_send_msg_to_smc(smumgr, msg);
+}
+
+static int cz_request_smu_load_fw(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)(smumgr->backend);
+	int result = 0;
+	uint32_t smc_address;
+
+	if (!smumgr->reload_fw) {
+		printk(KERN_INFO "[ powerplay ] skip reloading...\n");
+		return 0;
+	}
+
+	smc_address = SMU8_FIRMWARE_HEADER_LOCATION +
+		offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
+
+	cz_write_smc_sram_dword(smumgr, smc_address, 0, smc_address+4);
+
+	cz_send_msg_to_smc_with_parameter(smumgr,
+					PPSMC_MSG_DriverDramAddrHi,
+					cz_smu->toc_buffer.mc_addr_high);
+
+	cz_send_msg_to_smc_with_parameter(smumgr,
+					PPSMC_MSG_DriverDramAddrLo,
+					cz_smu->toc_buffer.mc_addr_low);
+
+	cz_send_msg_to_smc(smumgr, PPSMC_MSG_InitJobs);
+
+	cz_send_msg_to_smc_with_parameter(smumgr,
+					PPSMC_MSG_ExecuteJob,
+					cz_smu->toc_entry_aram);
+	cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
+				cz_smu->toc_entry_power_profiling_index);
+
+	result = cz_send_msg_to_smc_with_parameter(smumgr,
+					PPSMC_MSG_ExecuteJob,
+					cz_smu->toc_entry_initialize_index);
+
+	return result;
+}
+
+static int cz_check_fw_load_finish(struct pp_smumgr *smumgr,
+				   uint32_t firmware)
+{
+	int i;
+	uint32_t index = SMN_MP1_SRAM_START_ADDR +
+			 SMU8_FIRMWARE_HEADER_LOCATION +
+			 offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
+
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	return cgs_read_register(smumgr->device,
+					mmSMU_MP1_SRBM2P_ARG_0);
+
+	cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX, index);
+
+	for (i = 0; i < smumgr->usec_timeout; i++) {
+		if (firmware ==
+			(cgs_read_register(smumgr->device, mmMP0PUB_IND_DATA) & firmware))
+			break;
+		udelay(1);
+	}
+
+	if (i >= smumgr->usec_timeout) {
+		printk(KERN_ERR "[ powerplay ] SMU check loaded firmware failed.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cz_load_mec_firmware(struct pp_smumgr *smumgr)
+{
+	uint32_t reg_data;
+	uint32_t tmp;
+	int ret = 0;
+	struct cgs_firmware_info info = {0};
+	struct cz_smumgr *cz_smu;
+
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	cz_smu = (struct cz_smumgr *)smumgr->backend;
+	ret = cgs_get_firmware_info(smumgr->device,
+						CGS_UCODE_ID_CP_MEC, &info);
+
+	if (ret)
+		return -EINVAL;
+
+	/* Disable MEC parsing/prefetching */
+	tmp = cgs_read_register(smumgr->device,
+					mmCP_MEC_CNTL);
+	tmp = SMUM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1);
+	tmp = SMUM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1);
+	cgs_write_register(smumgr->device, mmCP_MEC_CNTL, tmp);
+
+	tmp = cgs_read_register(smumgr->device,
+					mmCP_CPC_IC_BASE_CNTL);
+
+	tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0);
+	tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0);
+	tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0);
+	tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1);
+	cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_CNTL, tmp);
+
+	reg_data = smu_lower_32_bits(info.mc_addr) &
+			SMUM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO);
+	cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_LO, reg_data);
+
+	reg_data = smu_upper_32_bits(info.mc_addr) &
+			SMUM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI);
+	cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_HI, reg_data);
+
+	return 0;
+}
+
+static int cz_start_smu(struct pp_smumgr *smumgr)
+{
+	int ret = 0;
+	uint32_t fw_to_check = UCODE_ID_RLC_G_MASK |
+				UCODE_ID_SDMA0_MASK |
+				UCODE_ID_SDMA1_MASK |
+				UCODE_ID_CP_CE_MASK |
+				UCODE_ID_CP_ME_MASK |
+				UCODE_ID_CP_PFP_MASK |
+				UCODE_ID_CP_MEC_JT1_MASK |
+				UCODE_ID_CP_MEC_JT2_MASK;
+
+	if (smumgr->chip_id == CHIP_STONEY)
+		fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK);
+
+	cz_request_smu_load_fw(smumgr);
+	cz_check_fw_load_finish(smumgr, fw_to_check);
+
+	ret = cz_load_mec_firmware(smumgr);
+	if (ret)
+		printk(KERN_ERR "[ powerplay ] Mec Firmware load failed\n");
+
+	return ret;
+}
+
+static uint8_t cz_translate_firmware_enum_to_arg(struct pp_smumgr *smumgr,
+			enum cz_scratch_entry firmware_enum)
+{
+	uint8_t ret = 0;
+
+	switch (firmware_enum) {
+	case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0:
+		ret = UCODE_ID_SDMA0;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1:
+		if (smumgr->chip_id == CHIP_STONEY)
+			ret = UCODE_ID_SDMA0;
+		else
+			ret = UCODE_ID_SDMA1;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE:
+		ret = UCODE_ID_CP_CE;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP:
+		ret = UCODE_ID_CP_PFP;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME:
+		ret = UCODE_ID_CP_ME;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1:
+		ret = UCODE_ID_CP_MEC_JT1;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2:
+		if (smumgr->chip_id == CHIP_STONEY)
+			ret = UCODE_ID_CP_MEC_JT1;
+		else
+			ret = UCODE_ID_CP_MEC_JT2;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG:
+		ret = UCODE_ID_GMCON_RENG;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G:
+		ret = UCODE_ID_RLC_G;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH:
+		ret = UCODE_ID_RLC_SCRATCH;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM:
+		ret = UCODE_ID_RLC_SRM_ARAM;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM:
+		ret = UCODE_ID_RLC_SRM_DRAM;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM:
+		ret = UCODE_ID_DMCU_ERAM;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM:
+		ret = UCODE_ID_DMCU_IRAM;
+		break;
+	case CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING:
+		ret = TASK_ARG_INIT_MM_PWR_LOG;
+		break;
+	case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT:
+	case CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING:
+	case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS:
+	case CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT:
+	case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START:
+	case CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS:
+		ret = TASK_ARG_REG_MMIO;
+		break;
+	case CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE:
+		ret = TASK_ARG_INIT_CLK_TABLE;
+		break;
+	}
+
+	return ret;
+}
+
+static enum cgs_ucode_id cz_convert_fw_type_to_cgs(uint32_t fw_type)
+{
+	enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
+
+	switch (fw_type) {
+	case UCODE_ID_SDMA0:
+		result = CGS_UCODE_ID_SDMA0;
+		break;
+	case UCODE_ID_SDMA1:
+		result = CGS_UCODE_ID_SDMA1;
+		break;
+	case UCODE_ID_CP_CE:
+		result = CGS_UCODE_ID_CP_CE;
+		break;
+	case UCODE_ID_CP_PFP:
+		result = CGS_UCODE_ID_CP_PFP;
+		break;
+	case UCODE_ID_CP_ME:
+		result = CGS_UCODE_ID_CP_ME;
+		break;
+	case UCODE_ID_CP_MEC_JT1:
+		result = CGS_UCODE_ID_CP_MEC_JT1;
+		break;
+	case UCODE_ID_CP_MEC_JT2:
+		result = CGS_UCODE_ID_CP_MEC_JT2;
+		break;
+	case UCODE_ID_RLC_G:
+		result = CGS_UCODE_ID_RLC_G;
+		break;
+	default:
+		break;
+	}
+
+	return result;
+}
+
+static int cz_smu_populate_single_scratch_task(
+			struct pp_smumgr *smumgr,
+			enum cz_scratch_entry fw_enum,
+			uint8_t type, bool is_last)
+{
+	uint8_t i;
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+	struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++];
+
+	task->type = type;
+	task->arg = cz_translate_firmware_enum_to_arg(smumgr, fw_enum);
+	task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count;
+
+	for (i = 0; i < cz_smu->scratch_buffer_length; i++)
+		if (cz_smu->scratch_buffer[i].firmware_ID == fw_enum)
+			break;
+
+	if (i >= cz_smu->scratch_buffer_length) {
+		printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n");
+		return -EINVAL;
+	}
+
+	task->addr.low = cz_smu->scratch_buffer[i].mc_addr_low;
+	task->addr.high = cz_smu->scratch_buffer[i].mc_addr_high;
+	task->size_bytes = cz_smu->scratch_buffer[i].data_size;
+
+	if (CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) {
+		struct cz_ih_meta_data *pIHReg_restore =
+		     (struct cz_ih_meta_data *)cz_smu->scratch_buffer[i].kaddr;
+		pIHReg_restore->command =
+			METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD;
+	}
+
+	return 0;
+}
+
+static int cz_smu_populate_single_ucode_load_task(
+					struct pp_smumgr *smumgr,
+					enum cz_scratch_entry fw_enum,
+					bool is_last)
+{
+	uint8_t i;
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+	struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++];
+
+	task->type = TASK_TYPE_UCODE_LOAD;
+	task->arg = cz_translate_firmware_enum_to_arg(smumgr, fw_enum);
+	task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count;
+
+	for (i = 0; i < cz_smu->driver_buffer_length; i++)
+		if (cz_smu->driver_buffer[i].firmware_ID == fw_enum)
+			break;
+
+	if (i >= cz_smu->driver_buffer_length) {
+		printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n");
+		return -EINVAL;
+	}
+
+	task->addr.low = cz_smu->driver_buffer[i].mc_addr_low;
+	task->addr.high = cz_smu->driver_buffer[i].mc_addr_high;
+	task->size_bytes = cz_smu->driver_buffer[i].data_size;
+
+	return 0;
+}
+
+static int cz_smu_construct_toc_for_rlc_aram_save(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+	cz_smu->toc_entry_aram = cz_smu->toc_entry_used_count;
+	cz_smu_populate_single_scratch_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+				TASK_TYPE_UCODE_SAVE, true);
+
+	return 0;
+}
+
+static int cz_smu_initialize_toc_empty_job_list(struct pp_smumgr *smumgr)
+{
+	int i;
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+
+	for (i = 0; i < NUM_JOBLIST_ENTRIES; i++)
+		toc->JobList[i] = (uint8_t)IGNORE_JOB;
+
+	return 0;
+}
+
+static int cz_smu_construct_toc_for_vddgfx_enter(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+
+	toc->JobList[JOB_GFX_SAVE] = (uint8_t)cz_smu->toc_entry_used_count;
+	cz_smu_populate_single_scratch_task(smumgr,
+				    CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+				    TASK_TYPE_UCODE_SAVE, false);
+
+	cz_smu_populate_single_scratch_task(smumgr,
+				    CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+				    TASK_TYPE_UCODE_SAVE, true);
+
+	return 0;
+}
+
+
+static int cz_smu_construct_toc_for_vddgfx_exit(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+
+	toc->JobList[JOB_GFX_RESTORE] = (uint8_t)cz_smu->toc_entry_used_count;
+
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
+
+	if (smumgr->chip_id == CHIP_STONEY)
+		cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
+	else
+		cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
+
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, false);
+
+	/* populate scratch */
+	cz_smu_populate_single_scratch_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+				TASK_TYPE_UCODE_LOAD, false);
+
+	cz_smu_populate_single_scratch_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+				TASK_TYPE_UCODE_LOAD, false);
+
+	cz_smu_populate_single_scratch_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+				TASK_TYPE_UCODE_LOAD, true);
+
+	return 0;
+}
+
+static int cz_smu_construct_toc_for_power_profiling(
+						 struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+	cz_smu->toc_entry_power_profiling_index = cz_smu->toc_entry_used_count;
+
+	cz_smu_populate_single_scratch_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
+				TASK_TYPE_INITIALIZE, true);
+	return 0;
+}
+
+static int cz_smu_construct_toc_for_bootup(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+	cz_smu->toc_entry_initialize_index = cz_smu->toc_entry_used_count;
+
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
+	if (smumgr->chip_id == CHIP_STONEY)
+		cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
+	else
+		cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false);
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
+	if (smumgr->chip_id == CHIP_STONEY)
+		cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
+	else
+		cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
+	cz_smu_populate_single_ucode_load_task(smumgr,
+				CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, true);
+
+	return 0;
+}
+
+static int cz_smu_construct_toc_for_clock_table(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+	cz_smu->toc_entry_clock_table = cz_smu->toc_entry_used_count;
+
+	cz_smu_populate_single_scratch_task(smumgr,
+				CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
+				TASK_TYPE_INITIALIZE, true);
+
+	return 0;
+}
+
+static int cz_smu_construct_toc(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+	cz_smu->toc_entry_used_count = 0;
+
+	cz_smu_initialize_toc_empty_job_list(smumgr);
+
+	cz_smu_construct_toc_for_rlc_aram_save(smumgr);
+
+	cz_smu_construct_toc_for_vddgfx_enter(smumgr);
+
+	cz_smu_construct_toc_for_vddgfx_exit(smumgr);
+
+	cz_smu_construct_toc_for_power_profiling(smumgr);
+
+	cz_smu_construct_toc_for_bootup(smumgr);
+
+	cz_smu_construct_toc_for_clock_table(smumgr);
+
+	return 0;
+}
+
+static int cz_smu_populate_firmware_entries(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	uint32_t firmware_type;
+	uint32_t i;
+	int ret;
+	enum cgs_ucode_id ucode_id;
+	struct cgs_firmware_info info = {0};
+
+	cz_smu->driver_buffer_length = 0;
+
+	for (i = 0; i < sizeof(firmware_list)/sizeof(*firmware_list); i++) {
+
+		firmware_type = cz_translate_firmware_enum_to_arg(smumgr,
+					firmware_list[i]);
+
+		ucode_id = cz_convert_fw_type_to_cgs(firmware_type);
+
+		ret = cgs_get_firmware_info(smumgr->device,
+							ucode_id, &info);
+
+		if (ret == 0) {
+			cz_smu->driver_buffer[i].mc_addr_high =
+					smu_upper_32_bits(info.mc_addr);
+
+			cz_smu->driver_buffer[i].mc_addr_low =
+					smu_lower_32_bits(info.mc_addr);
+
+			cz_smu->driver_buffer[i].data_size = info.image_size;
+
+			cz_smu->driver_buffer[i].firmware_ID = firmware_list[i];
+			cz_smu->driver_buffer_length++;
+		}
+	}
+
+	return 0;
+}
+
+static int cz_smu_populate_single_scratch_entry(
+				struct pp_smumgr *smumgr,
+				enum cz_scratch_entry scratch_type,
+				uint32_t ulsize_byte,
+				struct cz_buffer_entry *entry)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	long long mc_addr =
+			((long long)(cz_smu->smu_buffer.mc_addr_high) << 32)
+			| cz_smu->smu_buffer.mc_addr_low;
+
+	uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte);
+
+	mc_addr += cz_smu->smu_buffer_used_bytes;
+
+	entry->data_size = ulsize_byte;
+	entry->kaddr = (char *) cz_smu->smu_buffer.kaddr +
+				cz_smu->smu_buffer_used_bytes;
+	entry->mc_addr_low = smu_lower_32_bits(mc_addr);
+	entry->mc_addr_high = smu_upper_32_bits(mc_addr);
+	entry->firmware_ID = scratch_type;
+
+	cz_smu->smu_buffer_used_bytes += ulsize_aligned;
+
+	return 0;
+}
+
+static int cz_download_pptable_settings(struct pp_smumgr *smumgr, void **table)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	unsigned long i;
+
+	for (i = 0; i < cz_smu->scratch_buffer_length; i++) {
+		if (cz_smu->scratch_buffer[i].firmware_ID
+			== CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
+			break;
+	}
+
+	*table = (struct SMU8_Fusion_ClkTable *)cz_smu->scratch_buffer[i].kaddr;
+
+	cz_send_msg_to_smc_with_parameter(smumgr,
+				PPSMC_MSG_SetClkTableAddrHi,
+				cz_smu->scratch_buffer[i].mc_addr_high);
+
+	cz_send_msg_to_smc_with_parameter(smumgr,
+				PPSMC_MSG_SetClkTableAddrLo,
+				cz_smu->scratch_buffer[i].mc_addr_low);
+
+	cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
+				cz_smu->toc_entry_clock_table);
+
+	cz_send_msg_to_smc(smumgr, PPSMC_MSG_ClkTableXferToDram);
+
+	return 0;
+}
+
+static int cz_upload_pptable_settings(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	unsigned long i;
+
+	for (i = 0; i < cz_smu->scratch_buffer_length; i++) {
+		if (cz_smu->scratch_buffer[i].firmware_ID
+				== CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
+			break;
+	}
+
+	cz_send_msg_to_smc_with_parameter(smumgr,
+				PPSMC_MSG_SetClkTableAddrHi,
+				cz_smu->scratch_buffer[i].mc_addr_high);
+
+	cz_send_msg_to_smc_with_parameter(smumgr,
+				PPSMC_MSG_SetClkTableAddrLo,
+				cz_smu->scratch_buffer[i].mc_addr_low);
+
+	cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
+				cz_smu->toc_entry_clock_table);
+
+	cz_send_msg_to_smc(smumgr, PPSMC_MSG_ClkTableXferToSmu);
+
+	return 0;
+}
+
+static int cz_smu_init(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+	uint64_t mc_addr = 0;
+	int ret = 0;
+
+	cz_smu->toc_buffer.data_size = 4096;
+	cz_smu->smu_buffer.data_size =
+		ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) +
+		ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) +
+		ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) +
+		ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) +
+		ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32);
+
+	ret = smu_allocate_memory(smumgr->device,
+				cz_smu->toc_buffer.data_size,
+				CGS_GPU_MEM_TYPE__GART_CACHEABLE,
+				PAGE_SIZE,
+				&mc_addr,
+				&cz_smu->toc_buffer.kaddr,
+				&cz_smu->toc_buffer.handle);
+	if (ret != 0)
+		return -1;
+
+	cz_smu->toc_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+	cz_smu->toc_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+	ret = smu_allocate_memory(smumgr->device,
+				cz_smu->smu_buffer.data_size,
+				CGS_GPU_MEM_TYPE__GART_CACHEABLE,
+				PAGE_SIZE,
+				&mc_addr,
+				&cz_smu->smu_buffer.kaddr,
+				&cz_smu->smu_buffer.handle);
+	if (ret != 0)
+		return -1;
+
+	cz_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+	cz_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+	cz_smu_populate_firmware_entries(smumgr);
+	if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+		CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+		UCODE_ID_RLC_SCRATCH_SIZE_BYTE,
+		&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+		printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+		return -1;
+	}
+
+	if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+		CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+		UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE,
+		&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+		printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+		return -1;
+	}
+	if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+		CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+		UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE,
+		&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+		printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+		return -1;
+	}
+
+	if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+		CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
+		sizeof(struct SMU8_MultimediaPowerLogData),
+		&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+		printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+		return -1;
+	}
+
+	if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+		CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
+		sizeof(struct SMU8_Fusion_ClkTable),
+		&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+		printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+		return -1;
+	}
+	cz_smu_construct_toc(smumgr);
+
+	return 0;
+}
+
+static int cz_smu_fini(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu;
+
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	cz_smu = (struct cz_smumgr *)smumgr->backend;
+	if (cz_smu) {
+		cgs_free_gpu_mem(smumgr->device,
+				cz_smu->toc_buffer.handle);
+		cgs_free_gpu_mem(smumgr->device,
+				cz_smu->smu_buffer.handle);
+		kfree(cz_smu);
+		kfree(smumgr);
+	}
+
+	return 0;
+}
+
+static const struct pp_smumgr_func cz_smu_funcs = {
+	.smu_init = cz_smu_init,
+	.smu_fini = cz_smu_fini,
+	.start_smu = cz_start_smu,
+	.check_fw_load_finish = cz_check_fw_load_finish,
+	.request_smu_load_fw = NULL,
+	.request_smu_load_specific_fw = NULL,
+	.get_argument = cz_smum_get_argument,
+	.send_msg_to_smc = cz_send_msg_to_smc,
+	.send_msg_to_smc_with_parameter = cz_send_msg_to_smc_with_parameter,
+	.download_pptable_settings = cz_download_pptable_settings,
+	.upload_pptable_settings = cz_upload_pptable_settings,
+};
+
+int cz_smum_init(struct pp_smumgr *smumgr)
+{
+	struct cz_smumgr *cz_smu;
+
+	cz_smu = kzalloc(sizeof(struct cz_smumgr), GFP_KERNEL);
+	if (cz_smu == NULL)
+		return -ENOMEM;
+
+	smumgr->backend = cz_smu;
+	smumgr->smumgr_funcs = &cz_smu_funcs;
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _CZ_SMUMGR_H_
+#define _CZ_SMUMGR_H_
+
+
+#define MAX_NUM_FIRMWARE                        8
+#define MAX_NUM_SCRATCH                         11
+#define CZ_SCRATCH_SIZE_NONGFX_CLOCKGATING      1024
+#define CZ_SCRATCH_SIZE_NONGFX_GOLDENSETTING    2048
+#define CZ_SCRATCH_SIZE_SDMA_METADATA           1024
+#define CZ_SCRATCH_SIZE_IH                      ((2*256+1)*4)
+
+enum cz_scratch_entry {
+	CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0,
+	CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
+	CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
+	CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG,
+	CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G,
+	CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+	CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+	CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+	CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM,
+	CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM,
+	CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
+	CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT,
+	CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING,
+	CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS,
+	CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT,
+	CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START,
+	CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS,
+	CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE
+};
+
+struct cz_buffer_entry {
+	uint32_t data_size;
+	uint32_t mc_addr_low;
+	uint32_t mc_addr_high;
+	void *kaddr;
+	enum cz_scratch_entry firmware_ID;
+	unsigned long handle; /* as bo handle used when release bo */
+};
+
+struct cz_register_index_data_pair {
+	uint32_t offset;
+	uint32_t value;
+};
+
+struct cz_ih_meta_data {
+	uint32_t command;
+	struct cz_register_index_data_pair register_index_value_pair[1];
+};
+
+struct cz_smumgr {
+	uint8_t driver_buffer_length;
+	uint8_t scratch_buffer_length;
+	uint16_t toc_entry_used_count;
+	uint16_t toc_entry_initialize_index;
+	uint16_t toc_entry_power_profiling_index;
+	uint16_t toc_entry_aram;
+	uint16_t toc_entry_ih_register_restore_task_index;
+	uint16_t toc_entry_clock_table;
+	uint16_t ih_register_restore_task_size;
+	uint16_t smu_buffer_used_bytes;
+
+	struct cz_buffer_entry toc_buffer;
+	struct cz_buffer_entry smu_buffer;
+	struct cz_buffer_entry firmware_buffer;
+	struct cz_buffer_entry driver_buffer[MAX_NUM_FIRMWARE];
+	struct cz_buffer_entry meta_data_buffer[MAX_NUM_FIRMWARE];
+	struct cz_buffer_entry scratch_buffer[MAX_NUM_SCRATCH];
+};
+
+struct pp_smumgr;
+
+extern int cz_smum_init(struct pp_smumgr *smumgr);
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c
@@ -0,0 +1,1042 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "smumgr.h"
+#include "smu73.h"
+#include "smu_ucode_xfer_vi.h"
+#include "fiji_smumgr.h"
+#include "fiji_ppsmc.h"
+#include "smu73_discrete.h"
+#include "ppatomctrl.h"
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+#include "oss/oss_3_0_d.h"
+#include "gca/gfx_8_0_d.h"
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+#include "pp_debug.h"
+#include "fiji_pwrvirus.h"
+
+#define AVFS_EN_MSB                                        1568
+#define AVFS_EN_LSB                                        1568
+
+#define FIJI_SMC_SIZE 0x20000
+
+struct SMU73_Discrete_GraphicsLevel avfs_graphics_level[8] = {
+		/*  Min        Sclk       pcie     DeepSleep Activity  CgSpll      CgSpll    spllSpread  SpllSpread   CcPwr  CcPwr  Sclk   Display     Enabled     Enabled                       Voltage    Power */
+		/* Voltage,  Frequency,  DpmLevel,  DivId,    Level,  FuncCntl3,  FuncCntl4,  Spectrum,   Spectrum2,  DynRm, DynRm1  Did, Watermark, ForActivity, ForThrottle, UpHyst, DownHyst, DownHyst, Throttle */
+		{ 0x3c0fd047, 0x30750000,   0x00,     0x03,   0x1e00, 0x00200410, 0x87020000, 0x21680000, 0x0c000000,   0,      0,   0x16,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
+		{ 0xa00fd047, 0x409c0000,   0x01,     0x04,   0x1e00, 0x00800510, 0x87020000, 0x21680000, 0x11000000,   0,      0,   0x16,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
+		{ 0x0410d047, 0x50c30000,   0x01,     0x00,   0x1e00, 0x00600410, 0x87020000, 0x21680000, 0x0d000000,   0,      0,   0x0e,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
+		{ 0x6810d047, 0x60ea0000,   0x01,     0x00,   0x1e00, 0x00800410, 0x87020000, 0x21680000, 0x0e000000,   0,      0,   0x0c,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
+		{ 0xcc10d047, 0xe8fd0000,   0x01,     0x00,   0x1e00, 0x00e00410, 0x87020000, 0x21680000, 0x0f000000,   0,      0,   0x0c,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
+		{ 0x3011d047, 0x70110100,   0x01,     0x00,   0x1e00, 0x00400510, 0x87020000, 0x21680000, 0x10000000,   0,      0,   0x0c,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
+		{ 0x9411d047, 0xf8240100,   0x01,     0x00,   0x1e00, 0x00a00510, 0x87020000, 0x21680000, 0x11000000,   0,      0,   0x0c,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
+		{ 0xf811d047, 0x80380100,   0x01,     0x00,   0x1e00, 0x00000610, 0x87020000, 0x21680000, 0x12000000,   0,      0,   0x0c,   0x01,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 }
+};
+
+static enum cgs_ucode_id fiji_convert_fw_type_to_cgs(uint32_t fw_type)
+{
+	enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
+
+	switch (fw_type) {
+	case UCODE_ID_SMU:
+		result = CGS_UCODE_ID_SMU;
+		break;
+	case UCODE_ID_SDMA0:
+		result = CGS_UCODE_ID_SDMA0;
+		break;
+	case UCODE_ID_SDMA1:
+		result = CGS_UCODE_ID_SDMA1;
+		break;
+	case UCODE_ID_CP_CE:
+		result = CGS_UCODE_ID_CP_CE;
+		break;
+	case UCODE_ID_CP_PFP:
+		result = CGS_UCODE_ID_CP_PFP;
+		break;
+	case UCODE_ID_CP_ME:
+		result = CGS_UCODE_ID_CP_ME;
+		break;
+	case UCODE_ID_CP_MEC:
+		result = CGS_UCODE_ID_CP_MEC;
+		break;
+	case UCODE_ID_CP_MEC_JT1:
+		result = CGS_UCODE_ID_CP_MEC_JT1;
+		break;
+	case UCODE_ID_CP_MEC_JT2:
+		result = CGS_UCODE_ID_CP_MEC_JT2;
+		break;
+	case UCODE_ID_RLC_G:
+		result = CGS_UCODE_ID_RLC_G;
+		break;
+	default:
+		break;
+	}
+
+	return result;
+}
+/**
+* Set the address for reading/writing the SMC SRAM space.
+* @param    smumgr  the address of the powerplay hardware manager.
+* @param    smc_addr the address in the SMC RAM to access.
+*/
+static int fiji_set_smc_sram_address(struct pp_smumgr *smumgr,
+		uint32_t smc_addr, uint32_t limit)
+{
+	PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)),
+			"SMC address must be 4 byte aligned.", return -EINVAL;);
+	PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)),
+			"SMC address is beyond the SMC RAM area.", return -EINVAL;);
+
+	cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smc_addr);
+	SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
+
+	return 0;
+}
+
+/**
+* Copy bytes from an array into the SMC RAM space.
+*
+* @param    smumgr  the address of the powerplay SMU manager.
+* @param    smcStartAddress the start address in the SMC RAM to copy bytes to.
+* @param    src the byte array to copy the bytes from.
+* @param    byteCount the number of bytes to copy.
+*/
+int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr,
+		uint32_t smcStartAddress, const uint8_t *src,
+		uint32_t byteCount, uint32_t limit)
+{
+	int result;
+	uint32_t data, originalData;
+	uint32_t addr, extraShift;
+
+	PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)),
+			"SMC address must be 4 byte aligned.", return -EINVAL;);
+	PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)),
+			"SMC address is beyond the SMC RAM area.", return -EINVAL;);
+
+	addr = smcStartAddress;
+
+	while (byteCount >= 4) {
+		/* Bytes are written into the SMC addres space with the MSB first. */
+		data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
+
+		result = fiji_set_smc_sram_address(smumgr, addr, limit);
+		if (result)
+			return result;
+
+		cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+
+		src += 4;
+		byteCount -= 4;
+		addr += 4;
+	}
+
+	if (byteCount) {
+		/* Now write the odd bytes left.
+		 * Do a read modify write cycle.
+		 */
+		data = 0;
+
+		result = fiji_set_smc_sram_address(smumgr, addr, limit);
+		if (result)
+			return result;
+
+		originalData = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
+		extraShift = 8 * (4 - byteCount);
+
+		while (byteCount > 0) {
+			/* Bytes are written into the SMC addres
+			 * space with the MSB first.
+			 */
+			data = (0x100 * data) + *src++;
+			byteCount--;
+		}
+		data <<= extraShift;
+		data |= (originalData & ~((~0UL) << extraShift));
+
+		result = fiji_set_smc_sram_address(smumgr, addr, limit);
+		if (!result)
+			return result;
+
+		cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+	}
+	return 0;
+}
+
+int fiji_program_jump_on_start(struct pp_smumgr *smumgr)
+{
+	static unsigned char data[] = { 0xE0, 0x00, 0x80, 0x40 };
+
+	fiji_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data) + 1);
+
+	return 0;
+}
+
+/**
+* Return if the SMC is currently running.
+*
+* @param    smumgr  the address of the powerplay hardware manager.
+*/
+bool fiji_is_smc_ram_running(struct pp_smumgr *smumgr)
+{
+	return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
+			CGS_IND_REG__SMC,
+			SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
+			&& (0x20100 <= cgs_read_ind_register(smumgr->device,
+					CGS_IND_REG__SMC, ixSMC_PC_C)));
+}
+
+/**
+* Send a message to the SMC, and wait for its response.
+*
+* @param    smumgr  the address of the powerplay hardware manager.
+* @param    msg the message to send.
+* @return   The response that came from the SMC.
+*/
+int fiji_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+	if (!fiji_is_smc_ram_running(smumgr))
+		return -1;
+
+	if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
+		printk(KERN_ERR "Failed to send Previous Message.");
+		SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+	}
+
+	cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+	return 0;
+}
+
+/**
+ * Send a message to the SMC with parameter
+ * @param    smumgr:  the address of the powerplay hardware manager.
+ * @param    msg: the message to send.
+ * @param    parameter: the parameter to send
+ * @return   The response that came from the SMC.
+ */
+int fiji_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+		uint16_t msg, uint32_t parameter)
+{
+	if (!fiji_is_smc_ram_running(smumgr))
+		return -1;
+
+	if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
+		printk(KERN_ERR "Failed to send Previous Message.");
+		SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+	}
+
+	cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+	cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+	return 0;
+}
+
+
+/**
+* Send a message to the SMC with parameter, do not wait for response
+*
+* @param    smumgr:  the address of the powerplay hardware manager.
+* @param    msg: the message to send.
+* @param    parameter: the parameter to send
+* @return   The response that came from the SMC.
+*/
+int fiji_send_msg_to_smc_with_parameter_without_waiting(
+		struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
+{
+	if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
+		printk(KERN_ERR "Failed to send Previous Message.");
+		SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+	}
+	cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+	cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+
+	return 0;
+}
+
+/**
+* Uploads the SMU firmware from .hex file
+*
+* @param    smumgr  the address of the powerplay SMU manager.
+* @return   0 or -1.
+*/
+
+static int fiji_upload_smu_firmware_image(struct pp_smumgr *smumgr)
+{
+	const uint8_t *src;
+	uint32_t byte_count;
+	uint32_t *data;
+	struct cgs_firmware_info info = {0};
+
+	cgs_get_firmware_info(smumgr->device,
+			fiji_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
+
+	if (info.image_size & 3) {
+		printk(KERN_ERR "SMC ucode is not 4 bytes aligned\n");
+		return -EINVAL;
+	}
+
+	if (info.image_size > FIJI_SMC_SIZE) {
+		printk(KERN_ERR "SMC address is beyond the SMC RAM area\n");
+		return -EINVAL;
+	}
+
+	cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000);
+	SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
+
+	byte_count = info.image_size;
+	src = (const uint8_t *)info.kptr;
+
+	data = (uint32_t *)src;
+	for (; byte_count >= 4; data++, byte_count -= 4)
+		cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]);
+
+	SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
+	return 0;
+}
+
+/**
+* Read a 32bit value from the SMC SRAM space.
+* ALL PARAMETERS ARE IN HOST BYTE ORDER.
+* @param    smumgr  the address of the powerplay hardware manager.
+* @param    smc_addr the address in the SMC RAM to access.
+* @param    value and output parameter for the data read from the SMC SRAM.
+*/
+int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
+		uint32_t *value, uint32_t limit)
+{
+	int	result = fiji_set_smc_sram_address(smumgr, smc_addr, limit);
+
+	if (result)
+		return result;
+
+	*value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
+	return 0;
+}
+
+/**
+* Write a 32bit value to the SMC SRAM space.
+* ALL PARAMETERS ARE IN HOST BYTE ORDER.
+* @param    smumgr  the address of the powerplay hardware manager.
+* @param    smc_addr the address in the SMC RAM to access.
+* @param    value to write to the SMC SRAM.
+*/
+int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
+		uint32_t value, uint32_t limit)
+{
+	int result;
+
+	result = fiji_set_smc_sram_address(smumgr, smc_addr, limit);
+
+	if (result)
+		return result;
+
+	cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value);
+	return 0;
+}
+
+static uint32_t fiji_get_mask_for_firmware_type(uint32_t fw_type)
+{
+	uint32_t result = 0;
+
+	switch (fw_type) {
+	case UCODE_ID_SDMA0:
+		result = UCODE_ID_SDMA0_MASK;
+		break;
+	case UCODE_ID_SDMA1:
+		result = UCODE_ID_SDMA1_MASK;
+		break;
+	case UCODE_ID_CP_CE:
+		result = UCODE_ID_CP_CE_MASK;
+		break;
+	case UCODE_ID_CP_PFP:
+		result = UCODE_ID_CP_PFP_MASK;
+		break;
+	case UCODE_ID_CP_ME:
+		result = UCODE_ID_CP_ME_MASK;
+		break;
+	case UCODE_ID_CP_MEC_JT1:
+		result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK;
+		break;
+	case UCODE_ID_CP_MEC_JT2:
+		result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT2_MASK;
+		break;
+	case UCODE_ID_RLC_G:
+		result = UCODE_ID_RLC_G_MASK;
+		break;
+	default:
+		printk(KERN_ERR "UCode type is out of range!");
+		result = 0;
+	}
+
+	return result;
+}
+
+/* Populate one firmware image to the data structure */
+static int fiji_populate_single_firmware_entry(struct pp_smumgr *smumgr,
+		uint32_t fw_type, struct SMU_Entry *entry)
+{
+	int result;
+	struct cgs_firmware_info info = {0};
+
+	result = cgs_get_firmware_info(
+			smumgr->device,
+			fiji_convert_fw_type_to_cgs(fw_type),
+			&info);
+
+	if (!result) {
+		entry->version = 0;
+		entry->id = (uint16_t)fw_type;
+		entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
+		entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
+		entry->meta_data_addr_high = 0;
+		entry->meta_data_addr_low = 0;
+		entry->data_size_byte = info.image_size;
+		entry->num_register_entries = 0;
+
+		if (fw_type == UCODE_ID_RLC_G)
+			entry->flags = 1;
+		else
+			entry->flags = 0;
+	}
+
+	return result;
+}
+
+static int fiji_request_smu_load_fw(struct pp_smumgr *smumgr)
+{
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+	uint32_t fw_to_load;
+	struct SMU_DRAMData_TOC *toc;
+
+	if (priv->soft_regs_start)
+		cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+				priv->soft_regs_start +
+				offsetof(SMU73_SoftRegisters, UcodeLoadStatus),
+				0x0);
+
+	toc = (struct SMU_DRAMData_TOC *)priv->header;
+	toc->num_entries = 0;
+	toc->structure_version = 1;
+
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]),
+			"Failed to Get Firmware Entry.\n" , return -1 );
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]),
+			"Failed to Get Firmware Entry.\n" , return -1 );
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
+			"Failed to Get Firmware Entry.\n" , return -1 );
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
+			"Failed to Get Firmware Entry.\n" , return -1 );
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
+			"Failed to Get Firmware Entry.\n" , return -1 );
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
+					"Failed to Get Firmware Entry.\n" , return -1 );
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
+					"Failed to Get Firmware Entry.\n" , return -1 );
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
+					"Failed to Get Firmware Entry.\n" , return -1 );
+	PP_ASSERT_WITH_CODE(
+			0 == fiji_populate_single_firmware_entry(smumgr,
+					UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
+					"Failed to Get Firmware Entry.\n" , return -1 );
+
+	fiji_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI,
+			priv->header_buffer.mc_addr_high);
+	fiji_send_msg_to_smc_with_parameter(smumgr,PPSMC_MSG_DRV_DRAM_ADDR_LO,
+			priv->header_buffer.mc_addr_low);
+
+	fw_to_load = UCODE_ID_RLC_G_MASK
+			+ UCODE_ID_SDMA0_MASK
+			+ UCODE_ID_SDMA1_MASK
+			+ UCODE_ID_CP_CE_MASK
+			+ UCODE_ID_CP_ME_MASK
+			+ UCODE_ID_CP_PFP_MASK
+			+ UCODE_ID_CP_MEC_MASK
+			+ UCODE_ID_CP_MEC_JT1_MASK
+			+ UCODE_ID_CP_MEC_JT2_MASK;
+
+	if (fiji_send_msg_to_smc_with_parameter(smumgr,
+			PPSMC_MSG_LoadUcodes, fw_to_load))
+		printk(KERN_ERR "Fail to Request SMU Load uCode");
+
+	return 0;
+}
+
+
+/* Check if the FW has been loaded, SMU will not return
+ * if loading has not finished.
+ */
+static int fiji_check_fw_load_finish(struct pp_smumgr *smumgr,
+		uint32_t fw_type)
+{
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+	uint32_t mask = fiji_get_mask_for_firmware_type(fw_type);
+
+	/* Check SOFT_REGISTERS_TABLE_28.UcodeLoadStatus */
+	if (smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX,
+			priv->soft_regs_start +
+			offsetof(SMU73_SoftRegisters, UcodeLoadStatus),
+			mask, mask)) {
+		printk(KERN_ERR "check firmware loading failed\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static int fiji_reload_firmware(struct pp_smumgr *smumgr)
+{
+	return smumgr->smumgr_funcs->start_smu(smumgr);
+}
+
+static bool fiji_is_hw_virtualization_enabled(struct pp_smumgr *smumgr)
+{
+	uint32_t value;
+
+	value = cgs_read_register(smumgr->device, mmBIF_IOV_FUNC_IDENTIFIER);
+	if (value & BIF_IOV_FUNC_IDENTIFIER__IOV_ENABLE_MASK) {
+		/* driver reads on SR-IOV enabled PF: 0x80000000
+		 * driver reads on SR-IOV enabled VF: 0x80000001
+		 * driver reads on SR-IOV disabled:   0x00000000
+		 */
+		return true;
+	}
+	return false;
+}
+
+static int fiji_request_smu_specific_fw_load(struct pp_smumgr *smumgr, uint32_t fw_type)
+{
+	if (fiji_is_hw_virtualization_enabled(smumgr)) {
+		uint32_t masks = fiji_get_mask_for_firmware_type(fw_type);
+		if (fiji_send_msg_to_smc_with_parameter_without_waiting(smumgr,
+				PPSMC_MSG_LoadUcodes, masks))
+			printk(KERN_ERR "Fail to Request SMU Load uCode");
+	}
+	/* For non-virtualization cases,
+	 * SMU loads all FWs at once in fiji_request_smu_load_fw.
+	 */
+	return 0;
+}
+
+static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
+{
+	int result = 0;
+
+	/* Wait for smc boot up */
+	/* SMUM_WAIT_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+		RCU_UC_EVENTS, boot_seq_done, 0); */
+
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+			SMC_SYSCON_RESET_CNTL, rst_reg, 1);
+
+	result = fiji_upload_smu_firmware_image(smumgr);
+	if (result)
+		return result;
+
+	/* Clear status */
+	cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+			ixSMU_STATUS, 0);
+
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+			SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
+
+	/* De-assert reset */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+			SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+	/* Wait for ROM firmware to initialize interrupt hendler */
+	/*SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND,
+			SMC_INTR_CNTL_MASK_0, 0x10040, 0xFFFFFFFF); */
+
+	/* Set SMU Auto Start */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+			SMU_INPUT_DATA, AUTO_START, 1);
+
+	/* Clear firmware interrupt enable flag */
+	cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+			ixFIRMWARE_FLAGS, 0);
+
+	SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, RCU_UC_EVENTS,
+			INTERRUPTS_ENABLED, 1);
+
+	cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
+	cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+	/* Wait for done bit to be set */
+	SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+			SMU_STATUS, SMU_DONE, 0);
+
+	/* Check pass/failed indicator */
+	if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+			SMU_STATUS, SMU_PASS)) {
+		PP_ASSERT_WITH_CODE(false,
+				"SMU Firmware start failed!", return -1);
+	}
+
+	/* Wait for firmware to initialize */
+	SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+			FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
+
+	return result;
+}
+
+static int fiji_start_smu_in_non_protection_mode(struct pp_smumgr *smumgr)
+{
+	int result = 0;
+
+	/* wait for smc boot up */
+	SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+			RCU_UC_EVENTS, boot_seq_done, 0);
+
+	/* Clear firmware interrupt enable flag */
+	cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+			ixFIRMWARE_FLAGS, 0);
+
+	/* Assert reset */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+			SMC_SYSCON_RESET_CNTL, rst_reg, 1);
+
+	result = fiji_upload_smu_firmware_image(smumgr);
+	if (result)
+		return result;
+
+	/* Set smc instruct start point at 0x0 */
+	fiji_program_jump_on_start(smumgr);
+
+	/* Enable clock */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+			SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
+
+	/* De-assert reset */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+			SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+	/* Wait for firmware to initialize */
+	SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+			FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
+
+	return result;
+}
+
+int fiji_setup_pwr_virus(struct pp_smumgr *smumgr)
+{
+	int i, result = -1;
+	uint32_t reg, data;
+	PWR_Command_Table *virus = PwrVirusTable;
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+	priv->avfs.AvfsBtcStatus = AVFS_LOAD_VIRUS;
+	for (i = 0; (i < PWR_VIRUS_TABLE_SIZE); i++) {
+		switch (virus->command) {
+		case PwrCmdWrite:
+			reg  = virus->reg;
+			data = virus->data;
+			cgs_write_register(smumgr->device, reg, data);
+			break;
+		case PwrCmdEnd:
+			priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_LOADED;
+			result = 0;
+			break;
+		default:
+			printk(KERN_ERR "Table Exit with Invalid Command!");
+			priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_FAIL;
+			result = -1;
+			break;
+		}
+		virus++;
+	}
+	return result;
+}
+
+static int fiji_start_avfs_btc(struct pp_smumgr *smumgr)
+{
+	int result = 0;
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+	priv->avfs.AvfsBtcStatus = AVFS_BTC_STARTED;
+	if (priv->avfs.AvfsBtcParam) {
+		if (!fiji_send_msg_to_smc_with_parameter(smumgr,
+				PPSMC_MSG_PerformBtc, priv->avfs.AvfsBtcParam)) {
+			if (!fiji_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs)) {
+				priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_UNSAVED;
+				result = 0;
+			} else {
+				printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] Attempt"
+						" to Enable AVFS Failed!");
+				fiji_send_msg_to_smc(smumgr, PPSMC_MSG_DisableAvfs);
+				result = -1;
+			}
+		} else {
+			printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] "
+					"PerformBTC SMU msg failed");
+			result = -1;
+		}
+	}
+	/* Soft-Reset to reset the engine before loading uCode */
+	 /* halt */
+	cgs_write_register(smumgr->device, mmCP_MEC_CNTL, 0x50000000);
+	/* reset everything */
+	cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0xffffffff);
+	/* clear reset */
+	cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0);
+
+	return result;
+}
+
+int fiji_setup_pm_fuse_for_avfs(struct pp_smumgr *smumgr)
+{
+	int result = 0;
+	uint32_t table_start;
+	uint32_t charz_freq_addr, inversion_voltage_addr, charz_freq;
+	uint16_t inversion_voltage;
+
+	charz_freq = 0x30750000; /* In 10KHz units 0x00007530 Actual value */
+	inversion_voltage = 0x1A04; /* mV Q14.2 0x41A Actual value */
+
+	PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU73_Firmware_Header,
+					PmFuseTable), &table_start, 0x40000),
+			"[AVFS][Fiji_SetupGfxLvlStruct] SMU could not communicate "
+			"starting address of PmFuse structure",
+			return -1;);
+
+	charz_freq_addr = table_start +
+			offsetof(struct SMU73_Discrete_PmFuses, PsmCharzFreq);
+	inversion_voltage_addr = table_start +
+			offsetof(struct SMU73_Discrete_PmFuses, InversionVoltage);
+
+	result = fiji_copy_bytes_to_smc(smumgr, charz_freq_addr,
+			(uint8_t *)(&charz_freq), sizeof(charz_freq), 0x40000);
+	PP_ASSERT_WITH_CODE(0 == result,
+			"[AVFS][fiji_setup_pm_fuse_for_avfs] charz_freq could not "
+			"be populated.", return -1;);
+
+	result = fiji_copy_bytes_to_smc(smumgr, inversion_voltage_addr,
+			(uint8_t *)(&inversion_voltage), sizeof(inversion_voltage), 0x40000);
+	PP_ASSERT_WITH_CODE(0 == result, "[AVFS][fiji_setup_pm_fuse_for_avfs] "
+			"charz_freq could not be populated.", return -1;);
+
+	return result;
+}
+
+int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr)
+{
+	int32_t vr_config;
+	uint32_t table_start;
+	uint32_t level_addr, vr_config_addr;
+	uint32_t level_size = sizeof(avfs_graphics_level);
+
+	PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION +
+			offsetof(SMU73_Firmware_Header, DpmTable),
+			&table_start, 0x40000),
+			"[AVFS][Fiji_SetupGfxLvlStruct] SMU could not "
+			"communicate starting address of DPM table",
+			return -1;);
+
+	/* Default value for vr_config =
+	 * VR_MERGED_WITH_VDDC + VR_STATIC_VOLTAGE(VDDCI) */
+	vr_config = 0x01000500;   /* Real value:0x50001 */
+
+	vr_config_addr = table_start +
+			offsetof(SMU73_Discrete_DpmTable, VRConfig);
+
+	PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, vr_config_addr,
+			(uint8_t *)&vr_config, sizeof(int32_t), 0x40000),
+			"[AVFS][Fiji_SetupGfxLvlStruct] Problems copying "
+			"vr_config value over to SMC",
+			return -1;);
+
+	level_addr = table_start + offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
+
+	PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, level_addr,
+			(uint8_t *)(&avfs_graphics_level), level_size, 0x40000),
+			"[AVFS][Fiji_SetupGfxLvlStruct] Copying of DPM table failed!",
+			return -1;);
+
+	return 0;
+}
+
+/* Work in Progress */
+int fiji_restore_vft_table(struct pp_smumgr *smumgr)
+{
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+	if (AVFS_BTC_COMPLETED_SAVED == priv->avfs.AvfsBtcStatus) {
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED;
+		return 0;
+	} else
+		return -EINVAL;
+}
+
+/* Work in Progress */
+int fiji_save_vft_table(struct pp_smumgr *smumgr)
+{
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+	if (AVFS_BTC_COMPLETED_SAVED == priv->avfs.AvfsBtcStatus) {
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED;
+		return 0;
+	} else
+		return -EINVAL;
+}
+
+int fiji_avfs_event_mgr(struct pp_smumgr *smumgr, bool smu_started)
+{
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+	switch (priv->avfs.AvfsBtcStatus) {
+	case AVFS_BTC_COMPLETED_SAVED: /*S3 State - Pre SMU Start */
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_RESTOREVFT_FAILED;
+		PP_ASSERT_WITH_CODE(0 == fiji_restore_vft_table(smumgr),
+				"[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics "
+				"Level table over to SMU",
+				return -1;);
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED;
+		break;
+	case AVFS_BTC_COMPLETED_RESTORED: /*S3 State - Post SMU Start*/
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR;
+		PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr,
+				PPSMC_MSG_VftTableIsValid),
+				"[AVFS][fiji_avfs_event_mgr] SMU did not respond "
+				"correctly to VftTableIsValid Msg",
+				return -1;);
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR;
+		PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr,
+				PPSMC_MSG_EnableAvfs),
+				"[AVFS][fiji_avfs_event_mgr] SMU did not respond "
+				"correctly to EnableAvfs Message Msg",
+				return -1;);
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_SAVED;
+		break;
+	case AVFS_BTC_BOOT: /*Cold Boot State - Post SMU Start*/
+		if (!smu_started)
+			break;
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_FAILED;
+		PP_ASSERT_WITH_CODE(0 == fiji_setup_pm_fuse_for_avfs(smumgr),
+				"[AVFS][fiji_avfs_event_mgr] Failure at "
+				"fiji_setup_pm_fuse_for_avfs",
+				return -1;);
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_DPMTABLESETUP_FAILED;
+		PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(smumgr),
+				"[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level"
+				" table over to SMU",
+				return -1;);
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_FAIL;
+		PP_ASSERT_WITH_CODE(0 == fiji_setup_pwr_virus(smumgr),
+				"[AVFS][fiji_avfs_event_mgr] Could not setup "
+				"Pwr Virus for AVFS ",
+				return -1;);
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_FAILED;
+		PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(smumgr),
+				"[AVFS][fiji_avfs_event_mgr] Failure at "
+				"fiji_start_avfs_btc. AVFS Disabled",
+				return -1;);
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_SAVEVFT_FAILED;
+		PP_ASSERT_WITH_CODE(0 == fiji_save_vft_table(smumgr),
+				"[AVFS][fiji_avfs_event_mgr] Could not save VFT Table",
+				return -1;);
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_SAVED;
+		break;
+	case AVFS_BTC_DISABLED: /* Do nothing */
+		break;
+	case AVFS_BTC_NOTSUPPORTED: /* Do nothing */
+		break;
+	default:
+		printk(KERN_ERR "[AVFS] Something is broken. See log!");
+		break;
+	}
+	return 0;
+}
+
+static int fiji_start_smu(struct pp_smumgr *smumgr)
+{
+	int result = 0;
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+	/* Only start SMC if SMC RAM is not running */
+	if (!fiji_is_smc_ram_running(smumgr)) {
+		fiji_avfs_event_mgr(smumgr, false);
+
+		/* Check if SMU is running in protected mode */
+		if (0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
+				CGS_IND_REG__SMC,
+				SMU_FIRMWARE, SMU_MODE)) {
+			result = fiji_start_smu_in_non_protection_mode(smumgr);
+			if (result)
+				return result;
+		} else {
+			result = fiji_start_smu_in_protection_mode(smumgr);
+			if (result)
+				return result;
+		}
+		fiji_avfs_event_mgr(smumgr, true);
+	}
+
+	/* To initialize all clock gating before RLC loaded and running.*/
+	cgs_set_clockgating_state(smumgr->device,
+			AMD_IP_BLOCK_TYPE_GFX, AMD_CG_STATE_GATE);
+	cgs_set_clockgating_state(smumgr->device,
+			AMD_IP_BLOCK_TYPE_GMC, AMD_CG_STATE_GATE);
+	cgs_set_clockgating_state(smumgr->device,
+			AMD_IP_BLOCK_TYPE_SDMA, AMD_CG_STATE_GATE);
+	cgs_set_clockgating_state(smumgr->device,
+			AMD_IP_BLOCK_TYPE_COMMON, AMD_CG_STATE_GATE);
+
+	/* Setup SoftRegsStart here for register lookup in case
+	 * DummyBackEnd is used and ProcessFirmwareHeader is not executed
+	 */
+	fiji_read_smc_sram_dword(smumgr,
+			SMU7_FIRMWARE_HEADER_LOCATION +
+			offsetof(SMU73_Firmware_Header, SoftRegisters),
+			&(priv->soft_regs_start), 0x40000);
+
+	result = fiji_request_smu_load_fw(smumgr);
+
+	return result;
+}
+
+static bool fiji_is_hw_avfs_present(struct pp_smumgr *smumgr)
+{
+
+	uint32_t efuse = 0;
+	uint32_t mask = (1 << ((AVFS_EN_MSB - AVFS_EN_LSB) + 1)) - 1;
+
+	if (!atomctrl_read_efuse(smumgr->device, AVFS_EN_LSB, AVFS_EN_MSB,
+			mask, &efuse)) {
+		if (efuse)
+			return true;
+	}
+	return false;
+}
+
+/**
+* Write a 32bit value to the SMC SRAM space.
+* ALL PARAMETERS ARE IN HOST BYTE ORDER.
+* @param    smumgr  the address of the powerplay hardware manager.
+* @param    smc_addr the address in the SMC RAM to access.
+* @param    value to write to the SMC SRAM.
+*/
+static int fiji_smu_init(struct pp_smumgr *smumgr)
+{
+	struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+	uint64_t mc_addr;
+
+	priv->header_buffer.data_size =
+			((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
+	smu_allocate_memory(smumgr->device,
+			priv->header_buffer.data_size,
+			CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
+			PAGE_SIZE,
+			&mc_addr,
+			&priv->header_buffer.kaddr,
+			&priv->header_buffer.handle);
+
+	priv->header = priv->header_buffer.kaddr;
+	priv->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+	priv->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+	PP_ASSERT_WITH_CODE((NULL != priv->header),
+			"Out of memory.",
+			kfree(smumgr->backend);
+			cgs_free_gpu_mem(smumgr->device,
+			(cgs_handle_t)priv->header_buffer.handle);
+			return -1);
+
+	priv->avfs.AvfsBtcStatus = AVFS_BTC_BOOT;
+	if (fiji_is_hw_avfs_present(smumgr))
+		/* AVFS Parameter
+		 * 0 - BTC DC disabled, BTC AC disabled
+		 * 1 - BTC DC enabled,  BTC AC disabled
+		 * 2 - BTC DC disabled, BTC AC enabled
+		 * 3 - BTC DC enabled,  BTC AC enabled
+		 * Default is 0 - BTC DC disabled, BTC AC disabled
+		 */
+		priv->avfs.AvfsBtcParam = 0;
+	else
+		priv->avfs.AvfsBtcStatus = AVFS_BTC_NOTSUPPORTED;
+
+	priv->acpi_optimization = 1;
+
+	return 0;
+}
+
+static int fiji_smu_fini(struct pp_smumgr *smumgr)
+{
+	if (smumgr->backend) {
+		kfree(smumgr->backend);
+		smumgr->backend = NULL;
+	}
+	return 0;
+}
+
+static const struct pp_smumgr_func fiji_smu_funcs = {
+	.smu_init = &fiji_smu_init,
+	.smu_fini = &fiji_smu_fini,
+	.start_smu = &fiji_start_smu,
+	.check_fw_load_finish = &fiji_check_fw_load_finish,
+	.request_smu_load_fw = &fiji_reload_firmware,
+	.request_smu_load_specific_fw = &fiji_request_smu_specific_fw_load,
+	.send_msg_to_smc = &fiji_send_msg_to_smc,
+	.send_msg_to_smc_with_parameter = &fiji_send_msg_to_smc_with_parameter,
+	.download_pptable_settings = NULL,
+	.upload_pptable_settings = NULL,
+};
+
+int fiji_smum_init(struct pp_smumgr *smumgr)
+{
+	struct fiji_smumgr *fiji_smu = NULL;
+
+	fiji_smu = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL);
+
+	if (fiji_smu == NULL)
+		return -ENOMEM;
+
+	smumgr->backend = fiji_smu;
+	smumgr->smumgr_funcs = &fiji_smu_funcs;
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _FIJI_SMUMANAGER_H_
+#define _FIJI_SMUMANAGER_H_
+
+enum AVFS_BTC_STATUS {
+	AVFS_BTC_BOOT = 0,
+	AVFS_BTC_BOOT_STARTEDSMU,
+	AVFS_LOAD_VIRUS,
+	AVFS_BTC_VIRUS_LOADED,
+	AVFS_BTC_VIRUS_FAIL,
+	AVFS_BTC_STARTED,
+	AVFS_BTC_FAILED,
+	AVFS_BTC_RESTOREVFT_FAILED,
+	AVFS_BTC_SAVEVFT_FAILED,
+	AVFS_BTC_DPMTABLESETUP_FAILED,
+	AVFS_BTC_COMPLETED_UNSAVED,
+	AVFS_BTC_COMPLETED_SAVED,
+	AVFS_BTC_COMPLETED_RESTORED,
+	AVFS_BTC_DISABLED,
+	AVFS_BTC_NOTSUPPORTED,
+	AVFS_BTC_SMUMSG_ERROR
+};
+
+struct fiji_smu_avfs {
+	enum AVFS_BTC_STATUS AvfsBtcStatus;
+	uint32_t           AvfsBtcParam;
+};
+
+struct fiji_buffer_entry {
+	uint32_t data_size;
+	uint32_t mc_addr_low;
+	uint32_t mc_addr_high;
+	void *kaddr;
+	unsigned long  handle;
+};
+
+struct fiji_smumgr {
+	uint8_t        *header;
+	uint8_t        *mec_image;
+	uint32_t        soft_regs_start;
+	struct fiji_smu_avfs avfs;
+	uint32_t        acpi_optimization;
+
+	struct fiji_buffer_entry header_buffer;
+};
+
+int fiji_smum_init(struct pp_smumgr *smumgr);
+int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
+		uint32_t *value, uint32_t limit);
+int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
+		uint32_t value, uint32_t limit);
+int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smcStartAddress,
+		const uint8_t *src,	uint32_t byteCount, uint32_t limit);
+
+#endif
+
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "pp_instance.h"
+#include "smumgr.h"
+#include "cgs_common.h"
+#include "linux/delay.h"
+#include "cz_smumgr.h"
+#include "tonga_smumgr.h"
+#include "fiji_smumgr.h"
+
+int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
+{
+	struct pp_smumgr *smumgr;
+
+	if ((handle == NULL) || (pp_init == NULL))
+		return -EINVAL;
+
+	smumgr = kzalloc(sizeof(struct pp_smumgr), GFP_KERNEL);
+	if (smumgr == NULL)
+		return -ENOMEM;
+
+	smumgr->device = pp_init->device;
+	smumgr->chip_family = pp_init->chip_family;
+	smumgr->chip_id = pp_init->chip_id;
+	smumgr->hw_revision = pp_init->rev_id;
+	smumgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
+	smumgr->reload_fw = 1;
+	handle->smu_mgr = smumgr;
+
+	switch (smumgr->chip_family) {
+	case AMD_FAMILY_CZ:
+		cz_smum_init(smumgr);
+		break;
+	case AMD_FAMILY_VI:
+		switch (smumgr->chip_id) {
+		case CHIP_TONGA:
+			tonga_smum_init(smumgr);
+			break;
+		case CHIP_FIJI:
+			fiji_smum_init(smumgr);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		kfree(smumgr);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int smum_fini(struct pp_smumgr *smumgr)
+{
+	kfree(smumgr);
+	return 0;
+}
+
+int smum_get_argument(struct pp_smumgr *smumgr)
+{
+	if (NULL != smumgr->smumgr_funcs->get_argument)
+		return smumgr->smumgr_funcs->get_argument(smumgr);
+
+	return 0;
+}
+
+int smum_download_powerplay_table(struct pp_smumgr *smumgr,
+								void **table)
+{
+	if (NULL != smumgr->smumgr_funcs->download_pptable_settings)
+		return smumgr->smumgr_funcs->download_pptable_settings(smumgr,
+									table);
+
+	return 0;
+}
+
+int smum_upload_powerplay_table(struct pp_smumgr *smumgr)
+{
+	if (NULL != smumgr->smumgr_funcs->upload_pptable_settings)
+		return smumgr->smumgr_funcs->upload_pptable_settings(smumgr);
+
+	return 0;
+}
+
+int smum_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+	if (smumgr == NULL || smumgr->smumgr_funcs->send_msg_to_smc == NULL)
+		return -EINVAL;
+
+	return smumgr->smumgr_funcs->send_msg_to_smc(smumgr, msg);
+}
+
+int smum_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+					uint16_t msg, uint32_t parameter)
+{
+	if (smumgr == NULL ||
+		smumgr->smumgr_funcs->send_msg_to_smc_with_parameter == NULL)
+		return -EINVAL;
+	return smumgr->smumgr_funcs->send_msg_to_smc_with_parameter(
+						smumgr, msg, parameter);
+}
+
+/*
+ * Returns once the part of the register indicated by the mask has
+ * reached the given value.
+ */
+int smum_wait_on_register(struct pp_smumgr *smumgr,
+				uint32_t index,
+				uint32_t value, uint32_t mask)
+{
+	uint32_t i;
+	uint32_t cur_value;
+
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < smumgr->usec_timeout; i++) {
+		cur_value = cgs_read_register(smumgr->device, index);
+		if ((cur_value & mask) == (value & mask))
+			break;
+		udelay(1);
+	}
+
+	/* timeout means wrong logic*/
+	if (i == smumgr->usec_timeout)
+		return -1;
+
+	return 0;
+}
+
+int smum_wait_for_register_unequal(struct pp_smumgr *smumgr,
+					uint32_t index,
+					uint32_t value, uint32_t mask)
+{
+	uint32_t i;
+	uint32_t cur_value;
+
+	if (smumgr == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < smumgr->usec_timeout; i++) {
+		cur_value = cgs_read_register(smumgr->device,
+									index);
+		if ((cur_value & mask) != (value & mask))
+			break;
+		udelay(1);
+	}
+
+	/* timeout means wrong logic */
+	if (i == smumgr->usec_timeout)
+		return -1;
+
+	return 0;
+}
+
+
+/*
+ * Returns once the part of the register indicated by the mask
+ * has reached the given value.The indirect space is described by
+ * giving the memory-mapped index of the indirect index register.
+ */
+int smum_wait_on_indirect_register(struct pp_smumgr *smumgr,
+					uint32_t indirect_port,
+					uint32_t index,
+					uint32_t value,
+					uint32_t mask)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	cgs_write_register(smumgr->device, indirect_port, index);
+	return smum_wait_on_register(smumgr, indirect_port + 1,
+						mask, value);
+}
+
+void smum_wait_for_indirect_register_unequal(
+						struct pp_smumgr *smumgr,
+						uint32_t indirect_port,
+						uint32_t index,
+						uint32_t value,
+						uint32_t mask)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return;
+	cgs_write_register(smumgr->device, indirect_port, index);
+	smum_wait_for_register_unequal(smumgr, indirect_port + 1,
+						value, mask);
+}
+
+int smu_allocate_memory(void *device, uint32_t size,
+			 enum cgs_gpu_mem_type type,
+			 uint32_t byte_align, uint64_t *mc_addr,
+			 void **kptr, void *handle)
+{
+	int ret = 0;
+	cgs_handle_t cgs_handle;
+
+	if (device == NULL || handle == NULL ||
+	    mc_addr == NULL || kptr == NULL)
+		return -EINVAL;
+
+	ret = cgs_alloc_gpu_mem(device, type, size, byte_align,
+				0, 0, (cgs_handle_t *)handle);
+	if (ret)
+		return -ENOMEM;
+
+	cgs_handle = *(cgs_handle_t *)handle;
+
+	ret = cgs_gmap_gpu_mem(device, cgs_handle, mc_addr);
+	if (ret)
+		goto error_gmap;
+
+	ret = cgs_kmap_gpu_mem(device, cgs_handle, kptr);
+	if (ret)
+		goto error_kmap;
+
+	return 0;
+
+error_kmap:
+	cgs_gunmap_gpu_mem(device, cgs_handle);
+
+error_gmap:
+	cgs_free_gpu_mem(device, cgs_handle);
+	return ret;
+}
+
+int smu_free_memory(void *device, void *handle)
+{
+	cgs_handle_t cgs_handle = (cgs_handle_t)handle;
+
+	if (device == NULL || handle == NULL)
+		return -EINVAL;
+
+	cgs_kunmap_gpu_mem(device, cgs_handle);
+	cgs_gunmap_gpu_mem(device, cgs_handle);
+	cgs_free_gpu_mem(device, cgs_handle);
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+
+#include "smumgr.h"
+#include "tonga_smumgr.h"
+#include "pp_debug.h"
+#include "smu_ucode_xfer_vi.h"
+#include "tonga_ppsmc.h"
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
+#include "cgs_common.h"
+
+#define TONGA_SMC_SIZE			0x20000
+#define BUFFER_SIZE			80000
+#define MAX_STRING_SIZE			15
+#define BUFFER_SIZETWO              131072 /*128 *1024*/
+
+/**
+* Set the address for reading/writing the SMC SRAM space.
+* @param    smumgr  the address of the powerplay hardware manager.
+* @param    smcAddress the address in the SMC RAM to access.
+*/
+static int tonga_set_smc_sram_address(struct pp_smumgr *smumgr,
+				uint32_t smcAddress, uint32_t limit)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+	PP_ASSERT_WITH_CODE((0 == (3 & smcAddress)),
+		"SMC address must be 4 byte aligned.",
+		return -1;);
+
+	PP_ASSERT_WITH_CODE((limit > (smcAddress + 3)),
+		"SMC address is beyond the SMC RAM area.",
+		return -1;);
+
+	cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smcAddress);
+	SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
+
+	return 0;
+}
+
+/**
+* Copy bytes from an array into the SMC RAM space.
+*
+* @param    smumgr  the address of the powerplay SMU manager.
+* @param    smcStartAddress the start address in the SMC RAM to copy bytes to.
+* @param    src the byte array to copy the bytes from.
+* @param    byteCount the number of bytes to copy.
+*/
+int tonga_copy_bytes_to_smc(struct pp_smumgr *smumgr,
+		uint32_t smcStartAddress, const uint8_t *src,
+		uint32_t byteCount, uint32_t limit)
+{
+	uint32_t addr;
+	uint32_t data, orig_data;
+	int result = 0;
+	uint32_t extra_shift;
+
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+	PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)),
+		"SMC address must be 4 byte aligned.",
+		return 0;);
+
+	PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)),
+		"SMC address is beyond the SMC RAM area.",
+		return 0;);
+
+	addr = smcStartAddress;
+
+	while (byteCount >= 4) {
+		/*
+		 * Bytes are written into the
+		 * SMC address space with the MSB first
+		 */
+		data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
+
+		result = tonga_set_smc_sram_address(smumgr, addr, limit);
+
+		if (result)
+			goto out;
+
+		cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+
+		src += 4;
+		byteCount -= 4;
+		addr += 4;
+	}
+
+	if (0 != byteCount) {
+		/* Now write odd bytes left, do a read modify write cycle */
+		data = 0;
+
+		result = tonga_set_smc_sram_address(smumgr, addr, limit);
+		if (result)
+			goto out;
+
+		orig_data = cgs_read_register(smumgr->device,
+							mmSMC_IND_DATA_0);
+		extra_shift = 8 * (4 - byteCount);
+
+		while (byteCount > 0) {
+			data = (data << 8) + *src++;
+			byteCount--;
+		}
+
+		data <<= extra_shift;
+		data |= (orig_data & ~((~0UL) << extra_shift));
+
+		result = tonga_set_smc_sram_address(smumgr, addr, limit);
+		if (result)
+			goto out;
+
+		cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+	}
+
+out:
+	return result;
+}
+
+
+int tonga_program_jump_on_start(struct pp_smumgr *smumgr)
+{
+	static unsigned char pData[] = { 0xE0, 0x00, 0x80, 0x40 };
+
+	tonga_copy_bytes_to_smc(smumgr, 0x0, pData, 4, sizeof(pData)+1);
+
+	return 0;
+}
+
+/**
+* Return if the SMC is currently running.
+*
+* @param    smumgr  the address of the powerplay hardware manager.
+*/
+static int tonga_is_smc_ram_running(struct pp_smumgr *smumgr)
+{
+	return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+					SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
+			&& (0x20100 <= cgs_read_ind_register(smumgr->device,
+					CGS_IND_REG__SMC, ixSMC_PC_C)));
+}
+
+static int tonga_send_msg_to_smc_offset(struct pp_smumgr *smumgr)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+	cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
+	cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
+
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+	return 0;
+}
+
+/**
+* Send a message to the SMC, and wait for its response.
+*
+* @param    smumgr  the address of the powerplay hardware manager.
+* @param    msg the message to send.
+* @return   The response that came from the SMC.
+*/
+static int tonga_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	if (!tonga_is_smc_ram_running(smumgr))
+		return -1;
+
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+	PP_ASSERT_WITH_CODE(
+		1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
+		"Failed to send Previous Message.",
+		);
+
+	cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+	PP_ASSERT_WITH_CODE(
+		1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
+		"Failed to send Message.",
+		);
+
+	return 0;
+}
+
+/*
+* Send a message to the SMC, and do not wait for its response.
+*
+* @param    smumgr  the address of the powerplay hardware manager.
+* @param    msg the message to send.
+* @return   The response that came from the SMC.
+*/
+static int tonga_send_msg_to_smc_without_waiting
+				(struct pp_smumgr *smumgr, uint16_t msg)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+	PP_ASSERT_WITH_CODE(
+		1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
+		"Failed to send Previous Message.",
+		);
+	cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+
+	return 0;
+}
+
+/*
+* Send a message to the SMC with parameter
+*
+* @param    smumgr:  the address of the powerplay hardware manager.
+* @param    msg: the message to send.
+* @param    parameter: the parameter to send
+* @return   The response that came from the SMC.
+*/
+static int tonga_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+				uint16_t msg, uint32_t parameter)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	if (!tonga_is_smc_ram_running(smumgr))
+		return PPSMC_Result_Failed;
+
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+	cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+
+	return tonga_send_msg_to_smc(smumgr, msg);
+}
+
+/*
+* Send a message to the SMC with parameter, do not wait for response
+*
+* @param    smumgr:  the address of the powerplay hardware manager.
+* @param    msg: the message to send.
+* @param    parameter: the parameter to send
+* @return   The response that came from the SMC.
+*/
+static int tonga_send_msg_to_smc_with_parameter_without_waiting(
+			struct pp_smumgr *smumgr,
+			uint16_t msg, uint32_t parameter)
+{
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+	cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+
+	return tonga_send_msg_to_smc_without_waiting(smumgr, msg);
+}
+
+/*
+ * Read a 32bit value from the SMC SRAM space.
+ * ALL PARAMETERS ARE IN HOST BYTE ORDER.
+ * @param    smumgr  the address of the powerplay hardware manager.
+ * @param    smcAddress the address in the SMC RAM to access.
+ * @param    value and output parameter for the data read from the SMC SRAM.
+ */
+int tonga_read_smc_sram_dword(struct pp_smumgr *smumgr,
+					uint32_t smcAddress, uint32_t *value,
+					uint32_t limit)
+{
+	int result;
+
+	result = tonga_set_smc_sram_address(smumgr, smcAddress, limit);
+
+	if (0 != result)
+		return result;
+
+	*value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
+
+	return 0;
+}
+
+/*
+ * Write a 32bit value to the SMC SRAM space.
+ * ALL PARAMETERS ARE IN HOST BYTE ORDER.
+ * @param    smumgr  the address of the powerplay hardware manager.
+ * @param    smcAddress the address in the SMC RAM to access.
+ * @param    value to write to the SMC SRAM.
+ */
+int tonga_write_smc_sram_dword(struct pp_smumgr *smumgr,
+					uint32_t smcAddress, uint32_t value,
+					uint32_t limit)
+{
+	int result;
+
+	result = tonga_set_smc_sram_address(smumgr, smcAddress, limit);
+
+	if (0 != result)
+		return result;
+
+	cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value);
+
+	return 0;
+}
+
+static int tonga_smu_fini(struct pp_smumgr *smumgr)
+{
+	if (smumgr->backend != NULL) {
+		kfree(smumgr->backend);
+		smumgr->backend = NULL;
+	}
+	return 0;
+}
+
+static enum cgs_ucode_id tonga_convert_fw_type_to_cgs(uint32_t fw_type)
+{
+	enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
+
+	switch (fw_type) {
+	case UCODE_ID_SMU:
+		result = CGS_UCODE_ID_SMU;
+		break;
+	case UCODE_ID_SDMA0:
+		result = CGS_UCODE_ID_SDMA0;
+		break;
+	case UCODE_ID_SDMA1:
+		result = CGS_UCODE_ID_SDMA1;
+		break;
+	case UCODE_ID_CP_CE:
+		result = CGS_UCODE_ID_CP_CE;
+		break;
+	case UCODE_ID_CP_PFP:
+		result = CGS_UCODE_ID_CP_PFP;
+		break;
+	case UCODE_ID_CP_ME:
+		result = CGS_UCODE_ID_CP_ME;
+		break;
+	case UCODE_ID_CP_MEC:
+		result = CGS_UCODE_ID_CP_MEC;
+		break;
+	case UCODE_ID_CP_MEC_JT1:
+		result = CGS_UCODE_ID_CP_MEC_JT1;
+		break;
+	case UCODE_ID_CP_MEC_JT2:
+		result = CGS_UCODE_ID_CP_MEC_JT2;
+		break;
+	case UCODE_ID_RLC_G:
+		result = CGS_UCODE_ID_RLC_G;
+		break;
+	default:
+		break;
+	}
+
+	return result;
+}
+
+/**
+ * Convert the PPIRI firmware type to SMU type mask.
+ * For MEC, we need to check all MEC related type
+*/
+static uint16_t tonga_get_mask_for_firmware_type(uint16_t firmwareType)
+{
+	uint16_t result = 0;
+
+	switch (firmwareType) {
+	case UCODE_ID_SDMA0:
+		result = UCODE_ID_SDMA0_MASK;
+		break;
+	case UCODE_ID_SDMA1:
+		result = UCODE_ID_SDMA1_MASK;
+		break;
+	case UCODE_ID_CP_CE:
+		result = UCODE_ID_CP_CE_MASK;
+		break;
+	case UCODE_ID_CP_PFP:
+		result = UCODE_ID_CP_PFP_MASK;
+		break;
+	case UCODE_ID_CP_ME:
+		result = UCODE_ID_CP_ME_MASK;
+		break;
+	case UCODE_ID_CP_MEC:
+	case UCODE_ID_CP_MEC_JT1:
+	case UCODE_ID_CP_MEC_JT2:
+		result = UCODE_ID_CP_MEC_MASK;
+		break;
+	case UCODE_ID_RLC_G:
+		result = UCODE_ID_RLC_G_MASK;
+		break;
+	default:
+		break;
+	}
+
+	return result;
+}
+
+/**
+ * Check if the FW has been loaded,
+ * SMU will not return if loading has not finished.
+*/
+static int tonga_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fwType)
+{
+	uint16_t fwMask = tonga_get_mask_for_firmware_type(fwType);
+
+	if (0 != SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND,
+				SOFT_REGISTERS_TABLE_28, fwMask, fwMask)) {
+		printk(KERN_ERR "[ powerplay ] check firmware loading failed\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Populate one firmware image to the data structure */
+static int tonga_populate_single_firmware_entry(struct pp_smumgr *smumgr,
+				uint16_t firmware_type,
+				struct SMU_Entry *pentry)
+{
+	int result;
+	struct cgs_firmware_info info = {0};
+
+	result = cgs_get_firmware_info(
+				smumgr->device,
+				tonga_convert_fw_type_to_cgs(firmware_type),
+				&info);
+
+	if (result == 0) {
+		pentry->version = 0;
+		pentry->id = (uint16_t)firmware_type;
+		pentry->image_addr_high = smu_upper_32_bits(info.mc_addr);
+		pentry->image_addr_low = smu_lower_32_bits(info.mc_addr);
+		pentry->meta_data_addr_high = 0;
+		pentry->meta_data_addr_low = 0;
+		pentry->data_size_byte = info.image_size;
+		pentry->num_register_entries = 0;
+
+		if (firmware_type == UCODE_ID_RLC_G)
+			pentry->flags = 1;
+		else
+			pentry->flags = 0;
+	} else {
+		return result;
+	}
+
+	return result;
+}
+
+static int tonga_request_smu_reload_fw(struct pp_smumgr *smumgr)
+{
+	struct tonga_smumgr *tonga_smu =
+		(struct tonga_smumgr *)(smumgr->backend);
+	uint16_t fw_to_load;
+	int result = 0;
+	struct SMU_DRAMData_TOC *toc;
+	/**
+	 * First time this gets called during SmuMgr init,
+	 * we haven't processed SMU header file yet,
+	 * so Soft Register Start offset is unknown.
+	 * However, for this case, UcodeLoadStatus is already 0,
+	 * so we can skip this if the Soft Registers Start offset is 0.
+	 */
+	cgs_write_ind_register(smumgr->device,
+		CGS_IND_REG__SMC, ixSOFT_REGISTERS_TABLE_28, 0);
+
+	tonga_send_msg_to_smc_with_parameter(smumgr,
+		PPSMC_MSG_SMU_DRAM_ADDR_HI,
+		tonga_smu->smu_buffer.mc_addr_high);
+	tonga_send_msg_to_smc_with_parameter(smumgr,
+		PPSMC_MSG_SMU_DRAM_ADDR_LO,
+		tonga_smu->smu_buffer.mc_addr_low);
+
+	toc = (struct SMU_DRAMData_TOC *)tonga_smu->pHeader;
+	toc->num_entries = 0;
+	toc->structure_version = 1;
+
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry(smumgr,
+		UCODE_ID_RLC_G,
+		&toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n",
+		return -1);
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry(smumgr,
+		UCODE_ID_CP_CE,
+		&toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n",
+		return -1);
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry
+		(smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n", return -1);
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry
+		(smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n", return -1);
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry
+		(smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n", return -1);
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry
+		(smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n", return -1);
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry
+		(smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n", return -1);
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry
+		(smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n", return -1);
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_populate_single_firmware_entry
+		(smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
+		"Failed to Get Firmware Entry.\n", return -1);
+
+	tonga_send_msg_to_smc_with_parameter(smumgr,
+		PPSMC_MSG_DRV_DRAM_ADDR_HI,
+		tonga_smu->header_buffer.mc_addr_high);
+	tonga_send_msg_to_smc_with_parameter(smumgr,
+		PPSMC_MSG_DRV_DRAM_ADDR_LO,
+		tonga_smu->header_buffer.mc_addr_low);
+
+	fw_to_load = UCODE_ID_RLC_G_MASK
+			+ UCODE_ID_SDMA0_MASK
+			+ UCODE_ID_SDMA1_MASK
+			+ UCODE_ID_CP_CE_MASK
+			+ UCODE_ID_CP_ME_MASK
+			+ UCODE_ID_CP_PFP_MASK
+			+ UCODE_ID_CP_MEC_MASK;
+
+	PP_ASSERT_WITH_CODE(
+		0 == tonga_send_msg_to_smc_with_parameter_without_waiting(
+		smumgr, PPSMC_MSG_LoadUcodes, fw_to_load),
+		"Fail to Request SMU Load uCode", return 0);
+
+	return result;
+}
+
+static int tonga_request_smu_load_specific_fw(struct pp_smumgr *smumgr,
+				uint32_t firmwareType)
+{
+	return 0;
+}
+
+/**
+ * Upload the SMC firmware to the SMC microcontroller.
+ *
+ * @param    smumgr  the address of the powerplay hardware manager.
+ * @param    pFirmware the data structure containing the various sections of the firmware.
+ */
+static int tonga_smu_upload_firmware_image(struct pp_smumgr *smumgr)
+{
+	const uint8_t *src;
+	uint32_t byte_count;
+	uint32_t *data;
+	struct cgs_firmware_info info = {0};
+
+	if (smumgr == NULL || smumgr->device == NULL)
+		return -EINVAL;
+
+	cgs_get_firmware_info(smumgr->device,
+		tonga_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
+
+	if (info.image_size & 3) {
+		printk(KERN_ERR "[ powerplay ] SMC ucode is not 4 bytes aligned\n");
+		return -EINVAL;
+	}
+
+	if (info.image_size > TONGA_SMC_SIZE) {
+		printk(KERN_ERR "[ powerplay ] SMC address is beyond the SMC RAM area\n");
+		return -EINVAL;
+	}
+
+	cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000);
+	SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
+
+	byte_count = info.image_size;
+	src = (const uint8_t *)info.kptr;
+
+	data = (uint32_t *)src;
+	for (; byte_count >= 4; data++, byte_count -= 4)
+		cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]);
+
+	SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
+
+	return 0;
+}
+
+static int tonga_start_in_protection_mode(struct pp_smumgr *smumgr)
+{
+	int result;
+
+	/* Assert reset */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+		SMC_SYSCON_RESET_CNTL, rst_reg, 1);
+
+	result = tonga_smu_upload_firmware_image(smumgr);
+	if (result)
+		return result;
+
+	/* Clear status */
+	cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+		ixSMU_STATUS, 0);
+
+	/* Enable clock */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+		SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
+
+	/* De-assert reset */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+		SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+	/* Set SMU Auto Start */
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+		SMU_INPUT_DATA, AUTO_START, 1);
+
+	/* Clear firmware interrupt enable flag */
+	cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+		ixFIRMWARE_FLAGS, 0);
+
+	SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+		RCU_UC_EVENTS, INTERRUPTS_ENABLED, 1);
+
+	/**
+	 * Call Test SMU message with 0x20000 offset to trigger SMU start
+	 */
+	tonga_send_msg_to_smc_offset(smumgr);
+
+	/* Wait for done bit to be set */
+	SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+		SMU_STATUS, SMU_DONE, 0);
+
+	/* Check pass/failed indicator */
+	if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
+				CGS_IND_REG__SMC, SMU_STATUS, SMU_PASS)) {
+		printk(KERN_ERR "[ powerplay ] SMU Firmware start failed\n");
+		return -EINVAL;
+	}
+
+	/* Wait for firmware to initialize */
+	SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+		FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
+
+	return 0;
+}
+
+
+static int tonga_start_in_non_protection_mode(struct pp_smumgr *smumgr)
+{
+	int result = 0;
+
+	/* wait for smc boot up */
+	SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+		RCU_UC_EVENTS, boot_seq_done, 0);
+
+	/*Clear firmware interrupt enable flag*/
+	cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+		ixFIRMWARE_FLAGS, 0);
+
+
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+		SMC_SYSCON_RESET_CNTL, rst_reg, 1);
+
+	result = tonga_smu_upload_firmware_image(smumgr);
+
+	if (result != 0)
+		return result;
+
+	/* Set smc instruct start point at 0x0 */
+	tonga_program_jump_on_start(smumgr);
+
+
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+		SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
+
+	/*De-assert reset*/
+	SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+		SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+	/* Wait for firmware to initialize */
+	SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+		FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
+
+	return result;
+}
+
+static int tonga_start_smu(struct pp_smumgr *smumgr)
+{
+	int result;
+
+	/* Only start SMC if SMC RAM is not running */
+	if (!tonga_is_smc_ram_running(smumgr)) {
+		/*Check if SMU is running in protected mode*/
+		if (0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+					SMU_FIRMWARE, SMU_MODE)) {
+			result = tonga_start_in_non_protection_mode(smumgr);
+			if (result)
+				return result;
+		} else {
+			result = tonga_start_in_protection_mode(smumgr);
+			if (result)
+				return result;
+		}
+	}
+
+	result = tonga_request_smu_reload_fw(smumgr);
+
+	return result;
+}
+
+/**
+ * Write a 32bit value to the SMC SRAM space.
+ * ALL PARAMETERS ARE IN HOST BYTE ORDER.
+ * @param    smumgr  the address of the powerplay hardware manager.
+ * @param    smcAddress the address in the SMC RAM to access.
+ * @param    value to write to the SMC SRAM.
+ */
+static int tonga_smu_init(struct pp_smumgr *smumgr)
+{
+	struct tonga_smumgr *tonga_smu;
+	uint8_t *internal_buf;
+	uint64_t mc_addr = 0;
+	/* Allocate memory for backend private data */
+	tonga_smu = (struct tonga_smumgr *)(smumgr->backend);
+	tonga_smu->header_buffer.data_size =
+		((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
+	tonga_smu->smu_buffer.data_size = 200*4096;
+
+	smu_allocate_memory(smumgr->device,
+		tonga_smu->header_buffer.data_size,
+		CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
+		PAGE_SIZE,
+		&mc_addr,
+		&tonga_smu->header_buffer.kaddr,
+		&tonga_smu->header_buffer.handle);
+
+	tonga_smu->pHeader = tonga_smu->header_buffer.kaddr;
+	tonga_smu->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+	tonga_smu->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+	PP_ASSERT_WITH_CODE((NULL != tonga_smu->pHeader),
+		"Out of memory.",
+		kfree(smumgr->backend);
+		cgs_free_gpu_mem(smumgr->device,
+		(cgs_handle_t)tonga_smu->header_buffer.handle);
+		return -1);
+
+	smu_allocate_memory(smumgr->device,
+		tonga_smu->smu_buffer.data_size,
+		CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
+		PAGE_SIZE,
+		&mc_addr,
+		&tonga_smu->smu_buffer.kaddr,
+		&tonga_smu->smu_buffer.handle);
+
+	internal_buf = tonga_smu->smu_buffer.kaddr;
+	tonga_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+	tonga_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+	PP_ASSERT_WITH_CODE((NULL != internal_buf),
+		"Out of memory.",
+		kfree(smumgr->backend);
+		cgs_free_gpu_mem(smumgr->device,
+		(cgs_handle_t)tonga_smu->smu_buffer.handle);
+		return -1;);
+
+	return 0;
+}
+
+static const struct pp_smumgr_func tonga_smu_funcs = {
+	.smu_init = &tonga_smu_init,
+	.smu_fini = &tonga_smu_fini,
+	.start_smu = &tonga_start_smu,
+	.check_fw_load_finish = &tonga_check_fw_load_finish,
+	.request_smu_load_fw = &tonga_request_smu_reload_fw,
+	.request_smu_load_specific_fw = &tonga_request_smu_load_specific_fw,
+	.send_msg_to_smc = &tonga_send_msg_to_smc,
+	.send_msg_to_smc_with_parameter = &tonga_send_msg_to_smc_with_parameter,
+	.download_pptable_settings = NULL,
+	.upload_pptable_settings = NULL,
+};
+
+int tonga_smum_init(struct pp_smumgr *smumgr)
+{
+	struct tonga_smumgr *tonga_smu = NULL;
+
+	tonga_smu = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL);
+
+	if (tonga_smu == NULL)
+		return -ENOMEM;
+
+	smumgr->backend = tonga_smu;
+	smumgr->smumgr_funcs = &tonga_smu_funcs;
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h
+++ linux-4.4.0/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _TONGA_SMUMGR_H_
+#define _TONGA_SMUMGR_H_
+
+struct tonga_buffer_entry {
+	uint32_t data_size;
+	uint32_t mc_addr_low;
+	uint32_t mc_addr_high;
+	void *kaddr;
+	unsigned long  handle;
+};
+
+struct tonga_smumgr {
+	uint8_t *pHeader;
+	uint8_t *pMecImage;
+	uint32_t ulSoftRegsStart;
+
+	struct tonga_buffer_entry header_buffer;
+	struct tonga_buffer_entry smu_buffer;
+};
+
+extern int tonga_smum_init(struct pp_smumgr *smumgr);
+extern int tonga_copy_bytes_to_smc(struct pp_smumgr *smumgr,
+		uint32_t smcStartAddress, const uint8_t *src,
+		uint32_t byteCount, uint32_t limit);
+extern int tonga_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
+		uint32_t *value, uint32_t limit);
+extern int tonga_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
+		uint32_t value, uint32_t limit);
+
+#endif
--- linux-4.4.0.orig/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
+++ linux-4.4.0/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
@@ -47,6 +47,8 @@
 static void amd_sched_rq_add_entity(struct amd_sched_rq *rq,
 				    struct amd_sched_entity *entity)
 {
+	if (!list_empty(&entity->list))
+		return;
 	spin_lock(&rq->lock);
 	list_add_tail(&entity->list, &rq->entities);
 	spin_unlock(&rq->lock);
@@ -55,6 +57,8 @@
 static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq,
 				       struct amd_sched_entity *entity)
 {
+	if (list_empty(&entity->list))
+		return;
 	spin_lock(&rq->lock);
 	list_del_init(&entity->list);
 	if (rq->current_entity == entity)
@@ -138,9 +142,6 @@
 	atomic_set(&entity->fence_seq, 0);
 	entity->fence_context = fence_context_alloc(1);
 
-	/* Add the entity to the run queue */
-	amd_sched_rq_add_entity(rq, entity);
-
 	return 0;
 }
 
@@ -302,9 +303,11 @@
 	spin_unlock(&entity->queue_lock);
 
 	/* first job wakes up scheduler */
-	if (first)
+	if (first) {
+		/* Add the entity to the run queue */
+		amd_sched_rq_add_entity(entity->rq, entity);
 		amd_sched_wakeup(sched);
-
+	}
 	return added;
 }
 
@@ -349,14 +352,17 @@
 amd_sched_select_entity(struct amd_gpu_scheduler *sched)
 {
 	struct amd_sched_entity *entity;
+	int i;
 
 	if (!amd_sched_ready(sched))
 		return NULL;
 
 	/* Kernel run queue has higher priority than normal run queue*/
-	entity = amd_sched_rq_select_entity(&sched->kernel_rq);
-	if (entity == NULL)
-		entity = amd_sched_rq_select_entity(&sched->sched_rq);
+	for (i = 0; i < AMD_SCHED_MAX_PRIORITY; i++) {
+		entity = amd_sched_rq_select_entity(&sched->sched_rq[i]);
+		if (entity)
+			break;
+	}
 
 	return entity;
 }
@@ -478,12 +484,13 @@
 		   struct amd_sched_backend_ops *ops,
 		   unsigned hw_submission, long timeout, const char *name)
 {
+	int i;
 	sched->ops = ops;
 	sched->hw_submission_limit = hw_submission;
 	sched->name = name;
 	sched->timeout = timeout;
-	amd_sched_rq_init(&sched->sched_rq);
-	amd_sched_rq_init(&sched->kernel_rq);
+	for (i = 0; i < AMD_SCHED_MAX_PRIORITY; i++)
+		amd_sched_rq_init(&sched->sched_rq[i]);
 
 	init_waitqueue_head(&sched->wake_up_worker);
 	init_waitqueue_head(&sched->job_scheduled);
--- linux-4.4.0.orig/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
+++ linux-4.4.0/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
@@ -104,6 +104,12 @@
 	struct fence *(*run_job)(struct amd_sched_job *sched_job);
 };
 
+enum amd_sched_priority {
+	AMD_SCHED_PRIORITY_KERNEL = 0,
+	AMD_SCHED_PRIORITY_NORMAL,
+	AMD_SCHED_MAX_PRIORITY
+};
+
 /**
  * One scheduler is implemented for each hardware ring
 */
@@ -112,8 +118,7 @@
 	uint32_t			hw_submission_limit;
 	long				timeout;
 	const char			*name;
-	struct amd_sched_rq		sched_rq;
-	struct amd_sched_rq		kernel_rq;
+	struct amd_sched_rq		sched_rq[AMD_SCHED_MAX_PRIORITY];
 	wait_queue_head_t		wake_up_worker;
 	wait_queue_head_t		job_scheduled;
 	atomic_t			hw_rq_count;
--- linux-4.4.0.orig/drivers/gpu/drm/armada/armada_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/armada/armada_crtc.c
@@ -1182,17 +1182,13 @@
 
 	ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc",
 			       dcrtc);
-	if (ret < 0) {
-		kfree(dcrtc);
-		return ret;
-	}
+	if (ret < 0)
+		goto err_crtc;
 
 	if (dcrtc->variant->init) {
 		ret = dcrtc->variant->init(dcrtc, dev);
-		if (ret) {
-			kfree(dcrtc);
-			return ret;
-		}
+		if (ret)
+			goto err_crtc;
 	}
 
 	/* Ensure AXI pipeline is enabled */
@@ -1203,13 +1199,15 @@
 	dcrtc->crtc.port = port;
 
 	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
-	if (!primary)
-		return -ENOMEM;
+	if (!primary) {
+		ret = -ENOMEM;
+		goto err_crtc;
+	}
 
 	ret = armada_drm_plane_init(primary);
 	if (ret) {
 		kfree(primary);
-		return ret;
+		goto err_crtc;
 	}
 
 	ret = drm_universal_plane_init(drm, &primary->base, 0,
@@ -1219,7 +1217,7 @@
 				       DRM_PLANE_TYPE_PRIMARY);
 	if (ret) {
 		kfree(primary);
-		return ret;
+		goto err_crtc;
 	}
 
 	ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL,
@@ -1238,6 +1236,9 @@
 
 err_crtc_init:
 	primary->base.funcs->destroy(&primary->base);
+err_crtc:
+	kfree(dcrtc);
+
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/armada/armada_hw.h
+++ linux-4.4.0/drivers/gpu/drm/armada/armada_hw.h
@@ -160,6 +160,7 @@
 	CFG_ALPHAM_GRA		= 0x1 << 16,
 	CFG_ALPHAM_CFG		= 0x2 << 16,
 	CFG_ALPHA_MASK		= 0xff << 8,
+#define CFG_ALPHA(x)		((x) << 8)
 	CFG_PIXCMD_MASK		= 0xff,
 };
 
--- linux-4.4.0.orig/drivers/gpu/drm/armada/armada_overlay.c
+++ linux-4.4.0/drivers/gpu/drm/armada/armada_overlay.c
@@ -27,6 +27,7 @@
 	uint16_t contrast;
 	uint16_t saturation;
 	uint32_t colorkey_mode;
+	uint32_t colorkey_enable;
 };
 
 struct armada_ovl_plane {
@@ -62,11 +63,13 @@
 	writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE);
 
 	spin_lock_irq(&dcrtc->irq_lock);
-	armada_updatel(prop->colorkey_mode | CFG_ALPHAM_GRA,
-		     CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK,
-		     dcrtc->base + LCD_SPU_DMA_CTRL1);
-
-	armada_updatel(ADV_GRACOLORKEY, 0, dcrtc->base + LCD_SPU_ADV_REG);
+	armada_updatel(prop->colorkey_mode,
+		       CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK,
+		       dcrtc->base + LCD_SPU_DMA_CTRL1);
+	if (dcrtc->variant->has_spu_adv_reg)
+		armada_updatel(prop->colorkey_enable,
+			       ADV_GRACOLORKEY | ADV_VIDCOLORKEY,
+			       dcrtc->base + LCD_SPU_ADV_REG);
 	spin_unlock_irq(&dcrtc->irq_lock);
 }
 
@@ -339,8 +342,17 @@
 		dplane->prop.colorkey_vb |= K2B(val);
 		update_attr = true;
 	} else if (property == priv->colorkey_mode_prop) {
-		dplane->prop.colorkey_mode &= ~CFG_CKMODE_MASK;
-		dplane->prop.colorkey_mode |= CFG_CKMODE(val);
+		if (val == CKMODE_DISABLE) {
+			dplane->prop.colorkey_mode =
+				CFG_CKMODE(CKMODE_DISABLE) |
+				CFG_ALPHAM_CFG | CFG_ALPHA(255);
+			dplane->prop.colorkey_enable = 0;
+		} else {
+			dplane->prop.colorkey_mode =
+				CFG_CKMODE(val) |
+				CFG_ALPHAM_GRA | CFG_ALPHA(0);
+			dplane->prop.colorkey_enable = ADV_GRACOLORKEY;
+		}
 		update_attr = true;
 	} else if (property == priv->brightness_prop) {
 		dplane->prop.brightness = val - 256;
@@ -469,7 +481,9 @@
 	dplane->prop.colorkey_yr = 0xfefefe00;
 	dplane->prop.colorkey_ug = 0x01010100;
 	dplane->prop.colorkey_vb = 0x01010100;
-	dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB);
+	dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) |
+				     CFG_ALPHAM_GRA | CFG_ALPHA(0);
+	dplane->prop.colorkey_enable = ADV_GRACOLORKEY;
 	dplane->prop.brightness = 0;
 	dplane->prop.contrast = 0x4000;
 	dplane->prop.saturation = 0x4000;
--- linux-4.4.0.orig/drivers/gpu/drm/ast/ast_drv.c
+++ linux-4.4.0/drivers/gpu/drm/ast/ast_drv.c
@@ -60,8 +60,29 @@
 
 MODULE_DEVICE_TABLE(pci, pciidlist);
 
+static void ast_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+	struct apertures_struct *ap;
+	bool primary = false;
+
+	ap = alloc_apertures(1);
+	if (!ap)
+		return;
+
+	ap->ranges[0].base = pci_resource_start(pdev, 0);
+	ap->ranges[0].size = pci_resource_len(pdev, 0);
+
+#ifdef CONFIG_X86
+	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+#endif
+	remove_conflicting_framebuffers(ap, "astdrmfb", primary);
+	kfree(ap);
+}
+
 static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+	ast_kick_out_firmware_fb(pdev);
+
 	return drm_get_pci_dev(pdev, ent, &driver);
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/ast/ast_drv.h
+++ linux-4.4.0/drivers/gpu/drm/ast/ast_drv.h
@@ -113,6 +113,11 @@
 	struct ttm_bo_kmap_obj cache_kmap;
 	int next_cursor;
 	bool support_wide_screen;
+	enum {
+		ast_use_p2a,
+		ast_use_dt,
+		ast_use_defaults
+	} config_mode;
 
 	enum ast_tx_chip tx_chip_type;
 	u8 dp501_maxclk;
--- linux-4.4.0.orig/drivers/gpu/drm/ast/ast_main.c
+++ linux-4.4.0/drivers/gpu/drm/ast/ast_main.c
@@ -62,13 +62,84 @@
 	return ret;
 }
 
+static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev)
+{
+	struct device_node *np = dev->pdev->dev.of_node;
+	struct ast_private *ast = dev->dev_private;
+	uint32_t data, jregd0, jregd1;
+
+	/* Defaults */
+	ast->config_mode = ast_use_defaults;
+	*scu_rev = 0xffffffff;
+
+	/* Check if we have device-tree properties */
+	if (np && !of_property_read_u32(np, "aspeed,scu-revision-id",
+					scu_rev)) {
+		/* We do, disable P2A access */
+		ast->config_mode = ast_use_dt;
+		DRM_INFO("Using device-tree for configuration\n");
+		return;
+	}
+
+	/* Not all families have a P2A bridge */
+	if (dev->pdev->device != PCI_CHIP_AST2000)
+		return;
+
+	/*
+	 * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge
+	 * is disabled. We force using P2A if VGA only mode bit
+	 * is set D[7]
+	 */
+	jregd0 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+	jregd1 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
+	if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) {
+		/* Double check it's actually working */
+		data = ast_read32(ast, 0xf004);
+		if (data != 0xFFFFFFFF) {
+			/* P2A works, grab silicon revision */
+			ast->config_mode = ast_use_p2a;
+
+			DRM_INFO("Using P2A bridge for configuration\n");
+
+			/* Read SCU7c (silicon revision register) */
+			ast_write32(ast, 0xf004, 0x1e6e0000);
+			ast_write32(ast, 0xf000, 0x1);
+			*scu_rev = ast_read32(ast, 0x1207c);
+			return;
+		}
+	}
+
+	/* We have a P2A bridge but it's disabled */
+	DRM_INFO("P2A bridge disabled, using default configuration\n");
+}
 
 static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 {
 	struct ast_private *ast = dev->dev_private;
-	uint32_t data, jreg;
+	uint32_t jreg, scu_rev;
+
+	/*
+	 * If VGA isn't enabled, we need to enable now or subsequent
+	 * access to the scratch registers will fail. We also inform
+	 * our caller that it needs to POST the chip
+	 * (Assumption: VGA not enabled -> need to POST)
+	 */
+	if (!ast_is_vga_enabled(dev)) {
+		ast_enable_vga(dev);
+		DRM_INFO("VGA not enabled on entry, requesting chip POST\n");
+		*need_post = true;
+	} else
+		*need_post = false;
+
+
+	/* Enable extended register access */
+	ast_enable_mmio(dev);
 	ast_open_key(ast);
 
+	/* Find out whether P2A works or whether to use device-tree */
+	ast_detect_config_mode(dev, &scu_rev);
+
+	/* Identify chipset */
 	if (dev->pdev->device == PCI_CHIP_AST1180) {
 		ast->chip = AST1100;
 		DRM_INFO("AST 1180 detected\n");
@@ -80,12 +151,7 @@
 			ast->chip = AST2300;
 			DRM_INFO("AST 2300 detected\n");
 		} else if (dev->pdev->revision >= 0x10) {
-			uint32_t data;
-			ast_write32(ast, 0xf004, 0x1e6e0000);
-			ast_write32(ast, 0xf000, 0x1);
-
-			data = ast_read32(ast, 0x1207c);
-			switch (data & 0x0300) {
+			switch (scu_rev & 0x0300) {
 			case 0x0200:
 				ast->chip = AST1100;
 				DRM_INFO("AST 1100 detected\n");
@@ -110,20 +176,6 @@
 		}
 	}
 
-	/*
-	 * If VGA isn't enabled, we need to enable now or subsequent
-	 * access to the scratch registers will fail. We also inform
-	 * our caller that it needs to POST the chip
-	 * (Assumption: VGA not enabled -> need to POST)
-	 */
-	if (!ast_is_vga_enabled(dev)) {
-		ast_enable_vga(dev);
-		ast_enable_mmio(dev);
-		DRM_INFO("VGA not enabled on entry, requesting chip POST\n");
-		*need_post = true;
-	} else
-		*need_post = false;
-
 	/* Check if we support wide screen */
 	switch (ast->chip) {
 	case AST1180:
@@ -140,14 +192,11 @@
 			ast->support_wide_screen = true;
 		else {
 			ast->support_wide_screen = false;
-			/* Read SCU7c (silicon revision register) */
-			ast_write32(ast, 0xf004, 0x1e6e0000);
-			ast_write32(ast, 0xf000, 0x1);
-			data = ast_read32(ast, 0x1207c);
-			data &= 0x300;
-			if (ast->chip == AST2300 && data == 0x0) /* ast1300 */
+			if (ast->chip == AST2300 &&
+			    (scu_rev & 0x300) == 0x0) /* ast1300 */
 				ast->support_wide_screen = true;
-			if (ast->chip == AST2400 && data == 0x100) /* ast1400 */
+			if (ast->chip == AST2400 &&
+			    (scu_rev & 0x300) == 0x100) /* ast1400 */
 				ast->support_wide_screen = true;
 		}
 		break;
@@ -212,28 +261,49 @@
 
 static int ast_get_dram_info(struct drm_device *dev)
 {
+	struct device_node *np = dev->pdev->dev.of_node;
 	struct ast_private *ast = dev->dev_private;
-	uint32_t data, data2;
-	uint32_t denum, num, div, ref_pll;
-
-	ast_write32(ast, 0xf004, 0x1e6e0000);
-	ast_write32(ast, 0xf000, 0x1);
-
-
-	ast_write32(ast, 0x10000, 0xfc600309);
+	uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap;
+	uint32_t denum, num, div, ref_pll, dsel;
 
-	do {
-		;
-	} while (ast_read32(ast, 0x10000) != 0x01);
-	data = ast_read32(ast, 0x10004);
+	switch (ast->config_mode) {
+	case ast_use_dt:
+		/*
+		 * If some properties are missing, use reasonable
+		 * defaults for AST2400
+		 */
+		if (of_property_read_u32(np, "aspeed,mcr-configuration",
+					 &mcr_cfg))
+			mcr_cfg = 0x00000577;
+		if (of_property_read_u32(np, "aspeed,mcr-scu-mpll",
+					 &mcr_scu_mpll))
+			mcr_scu_mpll = 0x000050C0;
+		if (of_property_read_u32(np, "aspeed,mcr-scu-strap",
+					 &mcr_scu_strap))
+			mcr_scu_strap = 0;
+		break;
+	case ast_use_p2a:
+		ast_write32(ast, 0xf004, 0x1e6e0000);
+		ast_write32(ast, 0xf000, 0x1);
+		mcr_cfg = ast_read32(ast, 0x10004);
+		mcr_scu_mpll = ast_read32(ast, 0x10120);
+		mcr_scu_strap = ast_read32(ast, 0x10170);
+		break;
+	case ast_use_defaults:
+	default:
+		ast->dram_bus_width = 16;
+		ast->dram_type = AST_DRAM_1Gx16;
+		ast->mclk = 396;
+		return 0;
+	}
 
-	if (data & 0x400)
+	if (mcr_cfg & 0x40)
 		ast->dram_bus_width = 16;
 	else
 		ast->dram_bus_width = 32;
 
 	if (ast->chip == AST2300 || ast->chip == AST2400) {
-		switch (data & 0x03) {
+		switch (mcr_cfg & 0x03) {
 		case 0:
 			ast->dram_type = AST_DRAM_512Mx16;
 			break;
@@ -249,13 +319,13 @@
 			break;
 		}
 	} else {
-		switch (data & 0x0c) {
+		switch (mcr_cfg & 0x0c) {
 		case 0:
 		case 4:
 			ast->dram_type = AST_DRAM_512Mx16;
 			break;
 		case 8:
-			if (data & 0x40)
+			if (mcr_cfg & 0x40)
 				ast->dram_type = AST_DRAM_1Gx16;
 			else
 				ast->dram_type = AST_DRAM_512Mx32;
@@ -266,17 +336,15 @@
 		}
 	}
 
-	data = ast_read32(ast, 0x10120);
-	data2 = ast_read32(ast, 0x10170);
-	if (data2 & 0x2000)
+	if (mcr_scu_strap & 0x2000)
 		ref_pll = 14318;
 	else
 		ref_pll = 12000;
 
-	denum = data & 0x1f;
-	num = (data & 0x3fe0) >> 5;
-	data = (data & 0xc000) >> 14;
-	switch (data) {
+	denum = mcr_scu_mpll & 0x1f;
+	num = (mcr_scu_mpll & 0x3fe0) >> 5;
+	dsel = (mcr_scu_mpll & 0xc000) >> 14;
+	switch (dsel) {
 	case 3:
 		div = 0x4;
 		break;
@@ -429,7 +497,9 @@
 	ast_detect_chip(dev, &need_post);
 
 	if (ast->chip != AST1180) {
-		ast_get_dram_info(dev);
+		ret = ast_get_dram_info(dev);
+		if (ret)
+			goto out_free;
 		ast->vram_size = ast_get_vram_info(dev);
 		DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size);
 	}
@@ -487,7 +557,8 @@
 	drm_mode_config_cleanup(dev);
 
 	ast_mm_fini(ast);
-	pci_iounmap(dev->pdev, ast->ioregs);
+	if (ast->ioregs != ast->regs + AST_IO_MM_OFFSET)
+		pci_iounmap(dev->pdev, ast->ioregs);
 	pci_iounmap(dev->pdev, ast->regs);
 	kfree(ast);
 	return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/ast/ast_mode.c
+++ linux-4.4.0/drivers/gpu/drm/ast/ast_mode.c
@@ -552,6 +552,7 @@
 	}
 	ast_bo_unreserve(bo);
 
+	ast_set_offset_reg(crtc);
 	ast_set_start_address_crt1(crtc, (u32)gpu_addr);
 
 	return 0;
@@ -967,9 +968,21 @@
 {
 	struct ast_i2c_chan *i2c = i2c_priv;
 	struct ast_private *ast = i2c->dev->dev_private;
-	uint32_t val;
+	uint32_t val, val2, count, pass;
+
+	count = 0;
+	pass = 0;
+	val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
+	do {
+		val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
+		if (val == val2) {
+			pass++;
+		} else {
+			pass = 0;
+			val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
+		}
+	} while ((pass < 5) && (count++ < 0x10000));
 
-	val = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4;
 	return val & 1 ? 1 : 0;
 }
 
@@ -977,9 +990,21 @@
 {
 	struct ast_i2c_chan *i2c = i2c_priv;
 	struct ast_private *ast = i2c->dev->dev_private;
-	uint32_t val;
+	uint32_t val, val2, count, pass;
+
+	count = 0;
+	pass = 0;
+	val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
+	do {
+		val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
+		if (val == val2) {
+			pass++;
+		} else {
+			pass = 0;
+			val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
+		}
+	} while ((pass < 5) && (count++ < 0x10000));
 
-	val = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5;
 	return val & 1 ? 1 : 0;
 }
 
@@ -992,7 +1017,7 @@
 
 	for (i = 0; i < 0x10000; i++) {
 		ujcrb7 = ((clock & 0x01) ? 0 : 1);
-		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xfe, ujcrb7);
+		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf4, ujcrb7);
 		jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01);
 		if (ujcrb7 == jtemp)
 			break;
@@ -1008,7 +1033,7 @@
 
 	for (i = 0; i < 0x10000; i++) {
 		ujcrb7 = ((data & 0x01) ? 0 : 1) << 2;
-		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xfb, ujcrb7);
+		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf1, ujcrb7);
 		jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04);
 		if (ujcrb7 == jtemp)
 			break;
@@ -1249,7 +1274,7 @@
 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07));
 
 	/* dummy write to fire HWC */
-	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xCB, 0xFF, 0x00);
+	ast_show_cursor(crtc);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/ast/ast_post.c
+++ linux-4.4.0/drivers/gpu/drm/ast/ast_post.c
@@ -58,13 +58,9 @@
 		/* TODO 1180 */
 	} else {
 		ch = ast_io_read8(ast, AST_IO_VGA_ENABLE_PORT);
-		if (ch) {
-			ast_open_key(ast);
-			ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff);
-			return ch & 0x04;
-		}
+		return !!(ch & 0x01);
 	}
-	return 0;
+	return false;
 }
 
 static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff };
@@ -375,16 +371,21 @@
 	pci_write_config_dword(ast->dev->pdev, 0x04, reg);
 
 	ast_enable_vga(dev);
-	ast_enable_mmio(dev);
 	ast_open_key(ast);
+	ast_enable_mmio(dev);
 	ast_set_def_ext_reg(dev);
 
-	if (ast->chip == AST2300 || ast->chip == AST2400)
-		ast_init_dram_2300(dev);
-	else
-		ast_init_dram_reg(dev);
+	if (ast->config_mode == ast_use_p2a) {
+		if (ast->chip == AST2300 || ast->chip == AST2400)
+			ast_init_dram_2300(dev);
+		else
+			ast_init_dram_reg(dev);
 
-	ast_init_3rdtx(dev);
+		ast_init_3rdtx(dev);
+	} else {
+		if (ast->tx_chip_type != AST_TX_NONE)
+			ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80);	/* Enable DVO */
+	}
 }
 
 /* AST 2300 DRAM settings */
@@ -1630,12 +1631,44 @@
 		temp |= 0x73;
 		ast_write32(ast, 0x12008, temp);
 
+		param.dram_freq = 396;
 		param.dram_type = AST_DDR3;
+		temp = ast_mindwm(ast, 0x1e6e2070);
 		if (temp & 0x01000000)
 			param.dram_type = AST_DDR2;
-		param.dram_chipid = ast->dram_type;
-		param.dram_freq = ast->mclk;
-		param.vram_size = ast->vram_size;
+                switch (temp & 0x18000000) {
+		case 0:
+			param.dram_chipid = AST_DRAM_512Mx16;
+			break;
+		default:
+		case 0x08000000:
+			param.dram_chipid = AST_DRAM_1Gx16;
+			break;
+		case 0x10000000:
+			param.dram_chipid = AST_DRAM_2Gx16;
+			break;
+		case 0x18000000:
+			param.dram_chipid = AST_DRAM_4Gx16;
+			break;
+		}
+                switch (temp & 0x0c) {
+                default:
+		case 0x00:
+			param.vram_size = AST_VIDMEM_SIZE_8M;
+			break;
+
+		case 0x04:
+			param.vram_size = AST_VIDMEM_SIZE_16M;
+			break;
+
+		case 0x08:
+			param.vram_size = AST_VIDMEM_SIZE_32M;
+			break;
+
+		case 0x0c:
+			param.vram_size = AST_VIDMEM_SIZE_64M;
+			break;
+		}
 
 		if (param.dram_type == AST_DDR3) {
 			get_ddr3_info(ast, &param);
--- linux-4.4.0.orig/drivers/gpu/drm/ast/ast_ttm.c
+++ linux-4.4.0/drivers/gpu/drm/ast/ast_ttm.c
@@ -275,6 +275,8 @@
 		return ret;
 	}
 
+	arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
+				   pci_resource_len(dev->pdev, 0));
 	ast->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
 					pci_resource_len(dev->pdev, 0));
 
@@ -283,11 +285,15 @@
 
 void ast_mm_fini(struct ast_private *ast)
 {
+	struct drm_device *dev = ast->dev;
+
 	ttm_bo_device_release(&ast->ttm.bdev);
 
 	ast_ttm_global_release(ast);
 
 	arch_phys_wc_del(ast->fb_mtrr);
+	arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
+				pci_resource_len(dev->pdev, 0));
 }
 
 void ast_ttm_placement(struct ast_bo *bo, int domain)
--- linux-4.4.0.orig/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -63,7 +63,11 @@
 	struct videomode vm;
 	unsigned long prate;
 	unsigned int cfg;
-	int div;
+	int div, ret;
+
+	ret = clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
+	if (ret)
+		return;
 
 	vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
 	vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
@@ -119,6 +123,8 @@
 			   ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
 			   ATMEL_HLCDC_GUARDTIME_MASK,
 			   cfg);
+
+	clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
 }
 
 static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
--- linux-4.4.0.orig/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ linux-4.4.0/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -316,25 +316,27 @@
 			u32 *coeff_tab = heo_upscaling_ycoef;
 			u32 max_memsize;
 
-			if (state->crtc_w < state->src_w)
+			if (state->crtc_h < state->src_h)
 				coeff_tab = heo_downscaling_ycoef;
 			for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
 				atmel_hlcdc_layer_update_cfg(&plane->layer,
 							     33 + i,
 							     0xffffffff,
 							     coeff_tab[i]);
-			factor = ((8 * 256 * state->src_w) - (256 * 4)) /
-				 state->crtc_w;
+			factor = ((8 * 256 * state->src_h) - (256 * 4)) /
+				 state->crtc_h;
 			factor++;
-			max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
+			max_memsize = ((factor * state->crtc_h) + (256 * 4)) /
 				      2048;
-			if (max_memsize > state->src_w)
+			if (max_memsize > state->src_h)
 				factor--;
 			factor_reg |= (factor << 16) | 0x80000000;
 		}
 
 		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
 					     factor_reg);
+	} else {
+		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, 0);
 	}
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/bochs/bochs_hw.c
+++ linux-4.4.0/drivers/gpu/drm/bochs/bochs_hw.c
@@ -97,10 +97,8 @@
 		size = min(size, mem);
 	}
 
-	if (pci_request_region(pdev, 0, "bochs-drm") != 0) {
-		DRM_ERROR("Cannot request framebuffer\n");
-		return -EBUSY;
-	}
+	if (pci_request_region(pdev, 0, "bochs-drm") != 0)
+		DRM_WARN("Cannot request framebuffer, boot fb still active?\n");
 
 	bochs->fb_map = ioremap(addr, size);
 	if (bochs->fb_map == NULL) {
--- linux-4.4.0.orig/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ linux-4.4.0/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -275,6 +275,9 @@
 		return ret;
 	}
 
+	arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
+				   pci_resource_len(dev->pdev, 0));
+
 	cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
 					   pci_resource_len(dev->pdev, 0));
 
@@ -284,6 +287,8 @@
 
 void cirrus_mm_fini(struct cirrus_device *cirrus)
 {
+	struct drm_device *dev = cirrus->dev;
+
 	if (!cirrus->mm_inited)
 		return;
 
@@ -293,6 +298,8 @@
 
 	arch_phys_wc_del(cirrus->fb_mtrr);
 	cirrus->fb_mtrr = 0;
+	arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
+				pci_resource_len(dev->pdev, 0));
 }
 
 void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
--- linux-4.4.0.orig/drivers/gpu/drm/drm_atomic.c
+++ linux-4.4.0/drivers/gpu/drm/drm_atomic.c
@@ -28,6 +28,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_mode.h>
 #include <drm/drm_plane_helper.h>
 
 /**
@@ -94,6 +95,12 @@
 	if (!state->connector_states)
 		goto fail;
 
+	/*
+	 * Because drm_atomic_state can be committed asynchronously we need our
+	 * own reference and cannot rely on the on implied by drm_file in the
+	 * ioctl call.
+	 */
+	drm_dev_ref(dev);
 	state->dev = dev;
 
 	DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state);
@@ -150,7 +157,7 @@
 	for (i = 0; i < state->num_connector; i++) {
 		struct drm_connector *connector = state->connectors[i];
 
-		if (!connector)
+		if (!connector || !connector->funcs)
 			continue;
 
 		/*
@@ -247,6 +254,8 @@
 		drm_atomic_state_default_release(state);
 		kfree(state);
 	}
+
+	drm_dev_unref(dev);
 }
 EXPORT_SYMBOL(drm_atomic_state_free);
 
@@ -316,8 +325,7 @@
 	if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
 		return 0;
 
-	if (state->mode_blob)
-		drm_property_unreference_blob(state->mode_blob);
+	drm_property_unreference_blob(state->mode_blob);
 	state->mode_blob = NULL;
 
 	if (mode) {
@@ -363,10 +371,11 @@
 	if (blob == state->mode_blob)
 		return 0;
 
-	if (state->mode_blob)
-		drm_property_unreference_blob(state->mode_blob);
+	drm_property_unreference_blob(state->mode_blob);
 	state->mode_blob = NULL;
 
+	memset(&state->mode, 0, sizeof(state->mode));
+
 	if (blob) {
 		if (blob->length != sizeof(struct drm_mode_modeinfo) ||
 		    drm_mode_convert_umode(&state->mode,
@@ -379,7 +388,6 @@
 		DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n",
 				 state->mode.name, state);
 	} else {
-		memset(&state->mode, 0, sizeof(state->mode));
 		state->enable = false;
 		DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n",
 				 state);
@@ -390,6 +398,59 @@
 EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
 
 /**
+ * drm_atomic_replace_property_blob - replace a blob property
+ * @blob: a pointer to the member blob to be replaced
+ * @new_blob: the new blob to replace with
+ * @expected_size: the expected size of the new blob
+ * @replaced: whether the blob has been replaced
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+static void
+drm_atomic_replace_property_blob(struct drm_property_blob **blob,
+				 struct drm_property_blob *new_blob,
+				 bool *replaced)
+{
+	struct drm_property_blob *old_blob = *blob;
+
+	if (old_blob == new_blob)
+		return;
+
+	if (old_blob)
+		drm_property_unreference_blob(old_blob);
+	if (new_blob)
+		drm_property_reference_blob(new_blob);
+	*blob = new_blob;
+	*replaced = true;
+
+	return;
+}
+
+static int
+drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
+					 struct drm_property_blob **blob,
+					 uint64_t blob_id,
+					 ssize_t expected_size,
+					 bool *replaced)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_property_blob *new_blob = NULL;
+
+	if (blob_id != 0) {
+		new_blob = drm_property_lookup_blob(dev, blob_id);
+		if (new_blob == NULL)
+			return -EINVAL;
+		if (expected_size > 0 && expected_size != new_blob->length)
+			return -EINVAL;
+	}
+
+	drm_atomic_replace_property_blob(blob, new_blob, replaced);
+
+	return 0;
+}
+
+/**
  * drm_atomic_crtc_set_property - set property on CRTC
  * @crtc: the drm CRTC to set a property on
  * @state: the state object to update with the new property value
@@ -411,6 +472,7 @@
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_mode_config *config = &dev->mode_config;
+	bool replaced = false;
 	int ret;
 
 	if (property == config->prop_active)
@@ -419,11 +481,33 @@
 		struct drm_property_blob *mode =
 			drm_property_lookup_blob(dev, val);
 		ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
-		if (mode)
-			drm_property_unreference_blob(mode);
+		drm_property_unreference_blob(mode);
 		return ret;
-	}
-	else if (crtc->funcs->atomic_set_property)
+	} else if (property == config->degamma_lut_property) {
+		ret = drm_atomic_replace_property_blob_from_id(crtc,
+					&state->degamma_lut,
+					val,
+					-1,
+					&replaced);
+		state->color_mgmt_changed = replaced;
+		return ret;
+	} else if (property == config->ctm_property) {
+		ret = drm_atomic_replace_property_blob_from_id(crtc,
+					&state->ctm,
+					val,
+					sizeof(struct drm_color_ctm),
+					&replaced);
+		state->color_mgmt_changed = replaced;
+		return ret;
+	} else if (property == config->gamma_lut_property) {
+		ret = drm_atomic_replace_property_blob_from_id(crtc,
+					&state->gamma_lut,
+					val,
+					-1,
+					&replaced);
+		state->color_mgmt_changed = replaced;
+		return ret;
+	} else if (crtc->funcs->atomic_set_property)
 		return crtc->funcs->atomic_set_property(crtc, state, property, val);
 	else
 		return -EINVAL;
@@ -450,6 +534,12 @@
 		*val = state->active;
 	else if (property == config->prop_mode_id)
 		*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
+	else if (property == config->degamma_lut_property)
+		*val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
+	else if (property == config->ctm_property)
+		*val = (state->ctm) ? state->ctm->base.id : 0;
+	else if (property == config->gamma_lut_property)
+		*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
 	else if (crtc->funcs->atomic_get_property)
 		return crtc->funcs->atomic_get_property(crtc, state, property, val);
 	else
@@ -959,7 +1049,9 @@
 {
 	struct drm_plane *plane = plane_state->plane;
 	struct drm_crtc_state *crtc_state;
-
+	/* Nothing to do for same crtc*/
+	if (plane_state->crtc == crtc)
+		return 0;
 	if (plane_state->crtc) {
 		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
 						       plane_state->crtc);
@@ -1039,10 +1131,21 @@
 {
 	struct drm_crtc_state *crtc_state;
 
+	if (conn_state->crtc && conn_state->crtc != crtc) {
+		crtc_state = drm_atomic_get_existing_crtc_state(conn_state->state,
+								conn_state->crtc);
+
+		crtc_state->connector_mask &=
+			~(1 << drm_connector_index(conn_state->connector));
+	}
+
 	if (crtc) {
 		crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
 		if (IS_ERR(crtc_state))
 			return PTR_ERR(crtc_state);
+
+		crtc_state->connector_mask |=
+			1 << drm_connector_index(conn_state->connector);
 	}
 
 	conn_state->crtc = crtc;
@@ -1148,35 +1251,6 @@
 EXPORT_SYMBOL(drm_atomic_add_affected_planes);
 
 /**
- * drm_atomic_connectors_for_crtc - count number of connected outputs
- * @state: atomic state
- * @crtc: DRM crtc
- *
- * This function counts all connectors which will be connected to @crtc
- * according to @state. Useful to recompute the enable state for @crtc.
- */
-int
-drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
-			       struct drm_crtc *crtc)
-{
-	struct drm_connector *connector;
-	struct drm_connector_state *conn_state;
-
-	int i, num_connected_connectors = 0;
-
-	for_each_connector_in_state(state, connector, conn_state, i) {
-		if (conn_state->crtc == crtc)
-			num_connected_connectors++;
-	}
-
-	DRM_DEBUG_ATOMIC("State %p has %i connectors for [CRTC:%d]\n",
-			 state, num_connected_connectors, crtc->base.id);
-
-	return num_connected_connectors;
-}
-EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
-
-/**
  * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
  * @state: atomic state
  *
@@ -1191,12 +1265,7 @@
 retry:
 	drm_modeset_backoff(state->acquire_ctx);
 
-	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
-			       state->acquire_ctx);
-	if (ret)
-		goto retry;
-	ret = drm_modeset_lock_all_crtcs(state->dev,
-					 state->acquire_ctx);
+	ret = drm_modeset_lock_all_ctx(state->dev, state->acquire_ctx);
 	if (ret)
 		goto retry;
 }
@@ -1246,6 +1315,9 @@
 	if (config->funcs->atomic_check)
 		ret = config->funcs->atomic_check(state->dev, state);
 
+	if (ret)
+		return ret;
+
 	if (!state->allow_modeset) {
 		for_each_crtc_in_state(state, crtc, crtc_state, i) {
 			if (drm_atomic_crtc_needs_modeset(crtc_state)) {
@@ -1256,7 +1328,7 @@
 		}
 	}
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(drm_atomic_check_only);
 
--- linux-4.4.0.orig/drivers/gpu/drm/drm_atomic_helper.c
+++ linux-4.4.0/drivers/gpu/drm/drm_atomic_helper.c
@@ -99,6 +99,47 @@
 	return NULL;
 }
 
+static void
+set_best_encoder(struct drm_atomic_state *state,
+		 struct drm_connector_state *conn_state,
+		 struct drm_encoder *encoder)
+{
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc *crtc;
+
+	if (conn_state->best_encoder) {
+		/* Unset the encoder_mask in the old crtc state. */
+		crtc = conn_state->connector->state->crtc;
+
+		/* A NULL crtc is an error here because we should have
+		 *  duplicated a NULL best_encoder when crtc was NULL.
+		 * As an exception restoring duplicated atomic state
+		 * during resume is allowed, so don't warn when
+		 * best_encoder is equal to encoder we intend to set.
+		 */
+		WARN_ON(!crtc && encoder != conn_state->best_encoder);
+		if (crtc) {
+			crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
+
+			crtc_state->encoder_mask &=
+				~(1 << drm_encoder_index(conn_state->best_encoder));
+		}
+	}
+
+	if (encoder) {
+		crtc = conn_state->crtc;
+		WARN_ON(!crtc);
+		if (crtc) {
+			crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
+
+			crtc_state->encoder_mask |=
+				1 << drm_encoder_index(encoder);
+		}
+	}
+
+	conn_state->best_encoder = encoder;
+}
+
 static int
 steal_encoder(struct drm_atomic_state *state,
 	      struct drm_encoder *encoder,
@@ -108,7 +149,6 @@
 	struct drm_crtc_state *crtc_state;
 	struct drm_connector *connector;
 	struct drm_connector_state *connector_state;
-	int ret;
 
 	/*
 	 * We can only steal an encoder coming from a connector, which means we
@@ -139,10 +179,10 @@
 		if (IS_ERR(connector_state))
 			return PTR_ERR(connector_state);
 
-		ret = drm_atomic_set_crtc_for_connector(connector_state, NULL);
-		if (ret)
-			return ret;
-		connector_state->best_encoder = NULL;
+		if (connector_state->best_encoder != encoder)
+			continue;
+
+		set_best_encoder(state, connector_state, NULL);
 	}
 
 	return 0;
@@ -190,7 +230,7 @@
 				connector->base.id,
 				connector->name);
 
-		connector_state->best_encoder = NULL;
+		set_best_encoder(state, connector_state, NULL);
 
 		return 0;
 	}
@@ -219,6 +259,8 @@
 	}
 
 	if (new_encoder == connector_state->best_encoder) {
+		set_best_encoder(state, connector_state, new_encoder);
+
 		DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n",
 				 connector->base.id,
 				 connector->name,
@@ -245,7 +287,8 @@
 	if (WARN_ON(!connector_state->crtc))
 		return -EINVAL;
 
-	connector_state->best_encoder = new_encoder;
+	set_best_encoder(state, connector_state, new_encoder);
+
 	idx = drm_crtc_index(connector_state->crtc);
 
 	crtc_state = state->crtc_states[idx];
@@ -269,7 +312,7 @@
 	struct drm_connector *connector;
 	struct drm_connector_state *conn_state;
 	int i;
-	bool ret;
+	int ret;
 
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
 		if (!crtc_state->mode_changed &&
@@ -428,7 +471,8 @@
 	 * crtc only changed its mode but has the same set of connectors.
 	 */
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
-		int num_connectors;
+		bool has_connectors =
+			!!crtc_state->connector_mask;
 
 		/*
 		 * We must set ->active_changed after walking connectors for
@@ -457,10 +501,7 @@
 		if (ret != 0)
 			return ret;
 
-		num_connectors = drm_atomic_connectors_for_crtc(state,
-								crtc);
-
-		if (crtc_state->enable != !!num_connectors) {
+		if (crtc_state->enable != has_connectors) {
 			DRM_DEBUG_ATOMIC("[CRTC:%d] enabled/connectors mismatch\n",
 					 crtc->base.id);
 
@@ -913,9 +954,23 @@
 	}
 }
 
-static bool framebuffer_changed(struct drm_device *dev,
-				struct drm_atomic_state *old_state,
-				struct drm_crtc *crtc)
+/**
+ * drm_atomic_helper_framebuffer_changed - check if framebuffer has changed
+ * @dev: DRM device
+ * @old_state: atomic state object with old state structures
+ * @crtc: DRM crtc
+ *
+ * Checks whether the framebuffer used for this CRTC changes as a result of
+ * the atomic update.  This is useful for drivers which cannot use
+ * drm_atomic_helper_wait_for_vblanks() and need to reimplement its
+ * functionality.
+ *
+ * Returns:
+ * true if the framebuffer changed.
+ */
+bool drm_atomic_helper_framebuffer_changed(struct drm_device *dev,
+					   struct drm_atomic_state *old_state,
+					   struct drm_crtc *crtc)
 {
 	struct drm_plane *plane;
 	struct drm_plane_state *old_plane_state;
@@ -932,6 +987,7 @@
 
 	return false;
 }
+EXPORT_SYMBOL(drm_atomic_helper_framebuffer_changed);
 
 /**
  * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs
@@ -966,7 +1022,8 @@
 		if (old_state->legacy_cursor_update)
 			continue;
 
-		if (!framebuffer_changed(dev, old_state, crtc))
+		if (!drm_atomic_helper_framebuffer_changed(dev,
+				old_state, crtc))
 			continue;
 
 		ret = drm_crtc_vblank_get(crtc);
@@ -1676,7 +1733,7 @@
 		if (crtc == set->crtc)
 			continue;
 
-		if (!drm_atomic_connectors_for_crtc(state, crtc)) {
+		if (!crtc_state->connector_mask) {
 			ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
 								NULL);
 			if (ret < 0)
@@ -1818,6 +1875,161 @@
 }
 
 /**
+ * drm_atomic_helper_disable_all - disable all currently active outputs
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * Loops through all connectors, finding those that aren't turned off and then
+ * turns them off by setting their DPMS mode to OFF and deactivating the CRTC
+ * that they are connected to.
+ *
+ * This is used for example in suspend/resume to disable all currently active
+ * functions when suspending.
+ *
+ * Note that if callers haven't already acquired all modeset locks this might
+ * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
+ */
+int drm_atomic_helper_disable_all(struct drm_device *dev,
+				  struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_atomic_state *state;
+	struct drm_connector *conn;
+	int err;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	drm_for_each_connector(conn, dev) {
+		struct drm_crtc *crtc = conn->state->crtc;
+		struct drm_crtc_state *crtc_state;
+
+		if (!crtc || conn->dpms != DRM_MODE_DPMS_ON)
+			continue;
+
+		crtc_state = drm_atomic_get_crtc_state(state, crtc);
+		if (IS_ERR(crtc_state)) {
+			err = PTR_ERR(crtc_state);
+			goto free;
+		}
+
+		crtc_state->active = false;
+	}
+
+	err = drm_atomic_commit(state);
+
+free:
+	if (err < 0)
+		drm_atomic_state_free(state);
+
+	return err;
+}
+EXPORT_SYMBOL(drm_atomic_helper_disable_all);
+
+/**
+ * drm_atomic_helper_suspend - subsystem-level suspend helper
+ * @dev: DRM device
+ *
+ * Duplicates the current atomic state, disables all active outputs and then
+ * returns a pointer to the original atomic state to the caller. Drivers can
+ * pass this pointer to the drm_atomic_helper_resume() helper upon resume to
+ * restore the output configuration that was active at the time the system
+ * entered suspend.
+ *
+ * Note that it is potentially unsafe to use this. The atomic state object
+ * returned by this function is assumed to be persistent. Drivers must ensure
+ * that this holds true. Before calling this function, drivers must make sure
+ * to suspend fbdev emulation so that nothing can be using the device.
+ *
+ * Returns:
+ * A pointer to a copy of the state before suspend on success or an ERR_PTR()-
+ * encoded error code on failure. Drivers should store the returned atomic
+ * state object and pass it to the drm_atomic_helper_resume() helper upon
+ * resume.
+ *
+ * See also:
+ * drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(),
+ * drm_atomic_helper_resume()
+ */
+struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
+{
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_atomic_state *state;
+	int err;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+	err = drm_modeset_lock_all_ctx(dev, &ctx);
+	if (err < 0) {
+		state = ERR_PTR(err);
+		goto unlock;
+	}
+
+	state = drm_atomic_helper_duplicate_state(dev, &ctx);
+	if (IS_ERR(state))
+		goto unlock;
+
+	err = drm_atomic_helper_disable_all(dev, &ctx);
+	if (err < 0) {
+		drm_atomic_state_free(state);
+		state = ERR_PTR(err);
+		goto unlock;
+	}
+
+unlock:
+	if (PTR_ERR(state) == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_suspend);
+
+/**
+ * drm_atomic_helper_resume - subsystem-level resume helper
+ * @dev: DRM device
+ * @state: atomic state to resume to
+ *
+ * Calls drm_mode_config_reset() to synchronize hardware and software states,
+ * grabs all modeset locks and commits the atomic state object. This can be
+ * used in conjunction with the drm_atomic_helper_suspend() helper to
+ * implement suspend/resume for drivers that support atomic mode-setting.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend()
+ */
+int drm_atomic_helper_resume(struct drm_device *dev,
+			     struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &dev->mode_config;
+	int err;
+
+	drm_mode_config_reset(dev);
+	drm_modeset_lock_all(dev);
+	state->acquire_ctx = config->acquire_ctx;
+	err = drm_atomic_commit(state);
+	drm_modeset_unlock_all(dev);
+
+	return err;
+}
+EXPORT_SYMBOL(drm_atomic_helper_resume);
+
+/**
  * drm_atomic_helper_crtc_set_property - helper for crtc properties
  * @crtc: DRM crtc
  * @property: DRM property
@@ -2184,8 +2396,12 @@
  */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
 {
-	if (crtc->state && crtc->state->mode_blob)
+	if (crtc->state) {
 		drm_property_unreference_blob(crtc->state->mode_blob);
+		drm_property_unreference_blob(crtc->state->degamma_lut);
+		drm_property_unreference_blob(crtc->state->ctm);
+		drm_property_unreference_blob(crtc->state->gamma_lut);
+	}
 	kfree(crtc->state);
 	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
 
@@ -2209,10 +2425,17 @@
 
 	if (state->mode_blob)
 		drm_property_reference_blob(state->mode_blob);
+	if (state->degamma_lut)
+		drm_property_reference_blob(state->degamma_lut);
+	if (state->ctm)
+		drm_property_reference_blob(state->ctm);
+	if (state->gamma_lut)
+		drm_property_reference_blob(state->gamma_lut);
 	state->mode_changed = false;
 	state->active_changed = false;
 	state->planes_changed = false;
 	state->connectors_changed = false;
+	state->color_mgmt_changed = false;
 	state->event = NULL;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
@@ -2252,8 +2475,10 @@
 void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
 					    struct drm_crtc_state *state)
 {
-	if (state->mode_blob)
-		drm_property_unreference_blob(state->mode_blob);
+	drm_property_unreference_blob(state->mode_blob);
+	drm_property_unreference_blob(state->degamma_lut);
+	drm_property_unreference_blob(state->ctm);
+	drm_property_unreference_blob(state->gamma_lut);
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
 
@@ -2368,6 +2593,28 @@
 EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
 
 /**
+ * __drm_atomic_helper_connector_reset - reset state on connector
+ * @connector: drm connector
+ * @conn_state: connector state to assign
+ *
+ * Initializes the newly allocated @conn_state and assigns it to
+ * #connector ->state, usually required when initializing the drivers
+ * or when called from the ->reset hook.
+ *
+ * This is useful for drivers that subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_reset(struct drm_connector *connector,
+				    struct drm_connector_state *conn_state)
+{
+	if (conn_state)
+		conn_state->connector = connector;
+
+	connector->state = conn_state;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
+
+/**
  * drm_atomic_helper_connector_reset - default ->reset hook for connectors
  * @connector: drm connector
  *
@@ -2377,11 +2624,11 @@
  */
 void drm_atomic_helper_connector_reset(struct drm_connector *connector)
 {
-	kfree(connector->state);
-	connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);
+	struct drm_connector_state *conn_state =
+		kzalloc(sizeof(*conn_state), GFP_KERNEL);
 
-	if (connector->state)
-		connector->state->connector = connector;
+	kfree(connector->state);
+	__drm_atomic_helper_connector_reset(connector, conn_state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 
@@ -2430,7 +2677,9 @@
  * @ctx: lock acquisition context
  *
  * Makes a copy of the current atomic state by looping over all objects and
- * duplicating their respective states.
+ * duplicating their respective states. This is used for example by suspend/
+ * resume support code to save the state prior to suspend such that it can
+ * be restored upon resume.
  *
  * Note that this treats atomic state as persistent between save and restore.
  * Drivers must make sure that this is possible and won't result in confusion
@@ -2442,6 +2691,9 @@
  * Returns:
  * A pointer to the copy of the atomic state object on success or an
  * ERR_PTR()-encoded error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
  */
 struct drm_atomic_state *
 drm_atomic_helper_duplicate_state(struct drm_device *dev,
@@ -2538,3 +2790,98 @@
 	kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
+
+/**
+ * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
+ * @crtc: CRTC object
+ * @red: red correction table
+ * @green: green correction table
+ * @blue: green correction table
+ * @start:
+ * @size: size of the tables
+ *
+ * Implements support for legacy gamma correction table for drivers
+ * that support color management through the DEGAMMA_LUT/GAMMA_LUT
+ * properties.
+ */
+void drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
+					u16 *red, u16 *green, u16 *blue,
+					uint32_t start, uint32_t size)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_property_blob *blob = NULL;
+	struct drm_color_lut *blob_data;
+	int i, ret = 0;
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return;
+
+	blob = drm_property_create_blob(dev,
+					sizeof(struct drm_color_lut) * size,
+					NULL);
+	if (IS_ERR(blob)) {
+		ret = PTR_ERR(blob);
+		blob = NULL;
+		goto fail;
+	}
+
+	/* Prepare GAMMA_LUT with the legacy values. */
+	blob_data = (struct drm_color_lut *) blob->data;
+	for (i = 0; i < size; i++) {
+		blob_data[i].red = red[i];
+		blob_data[i].green = green[i];
+		blob_data[i].blue = blue[i];
+	}
+
+	state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		goto fail;
+	}
+
+	/* Reset DEGAMMA_LUT and CTM properties. */
+	ret = drm_atomic_crtc_set_property(crtc, crtc_state,
+			config->degamma_lut_property, 0);
+	if (ret)
+		goto fail;
+
+	ret = drm_atomic_crtc_set_property(crtc, crtc_state,
+			config->ctm_property, 0);
+	if (ret)
+		goto fail;
+
+	ret = drm_atomic_crtc_set_property(crtc, crtc_state,
+			config->gamma_lut_property, blob->base.id);
+	if (ret)
+		goto fail;
+
+	ret = drm_atomic_commit(state);
+	if (ret)
+		goto fail;
+
+	/* Driver takes ownership of state on successful commit. */
+
+	drm_property_unreference_blob(blob);
+
+	return;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+	drm_property_unreference_blob(blob);
+
+	return;
+backoff:
+	drm_atomic_state_clear(state);
+	drm_atomic_legacy_backoff(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_bufs.c
+++ linux-4.4.0/drivers/gpu/drm/drm_bufs.c
@@ -36,6 +36,8 @@
 #include <drm/drmP.h>
 #include "drm_legacy.h"
 
+#include <linux/nospec.h>
+
 static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
 						  struct drm_local_map *map)
 {
@@ -1332,6 +1334,7 @@
 				  idx, dma->buf_count - 1);
 			return -EINVAL;
 		}
+		idx = array_index_nospec(idx, dma->buf_count);
 		buf = dma->buflist[idx];
 		if (buf->file_priv != file_priv) {
 			DRM_ERROR("Process %d freeing buffer not owned\n",
--- linux-4.4.0.orig/drivers/gpu/drm/drm_cache.c
+++ linux-4.4.0/drivers/gpu/drm/drm_cache.c
@@ -136,6 +136,7 @@
 		mb();
 		for (; addr < end; addr += size)
 			clflushopt(addr);
+		clflushopt(end - 1); /* force serialisation */
 		mb();
 		return;
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/drm_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/drm_crtc.c
@@ -1121,6 +1121,29 @@
 EXPORT_SYMBOL(drm_encoder_init);
 
 /**
+ * drm_encoder_index - find the index of a registered encoder
+ * @encoder: encoder to find index for
+ *
+ * Given a registered encoder, return the index of that encoder within a DRM
+ * device's list of encoders.
+ */
+unsigned int drm_encoder_index(struct drm_encoder *encoder)
+{
+	unsigned int index = 0;
+	struct drm_encoder *tmp;
+
+	drm_for_each_encoder(tmp, encoder->dev) {
+		if (tmp == encoder)
+			return index;
+
+		index++;
+	}
+
+	BUG();
+}
+EXPORT_SYMBOL(drm_encoder_index);
+
+/**
  * drm_encoder_cleanup - cleans up an initialised encoder
  * @encoder: encoder to cleanup
  *
@@ -1470,6 +1493,41 @@
 		return -ENOMEM;
 	dev->mode_config.prop_mode_id = prop;
 
+	prop = drm_property_create(dev,
+			DRM_MODE_PROP_BLOB,
+			"DEGAMMA_LUT", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.degamma_lut_property = prop;
+
+	prop = drm_property_create_range(dev,
+			DRM_MODE_PROP_IMMUTABLE,
+			"DEGAMMA_LUT_SIZE", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.degamma_lut_size_property = prop;
+
+	prop = drm_property_create(dev,
+			DRM_MODE_PROP_BLOB,
+			"CTM", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.ctm_property = prop;
+
+	prop = drm_property_create(dev,
+			DRM_MODE_PROP_BLOB,
+			"GAMMA_LUT", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.gamma_lut_property = prop;
+
+	prop = drm_property_create_range(dev,
+			DRM_MODE_PROP_IMMUTABLE,
+			"GAMMA_LUT_SIZE", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.gamma_lut_size_property = prop;
+
 	return 0;
 }
 
@@ -2682,8 +2740,6 @@
 			goto out;
 		}
 
-		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
-
 		/*
 		 * Check whether the primary plane supports the fb pixel format.
 		 * Drivers not implementing the universal planes API use a
@@ -3316,6 +3372,24 @@
 	return 0;
 }
 
+struct drm_mode_rmfb_work {
+	struct work_struct work;
+	struct list_head fbs;
+};
+
+static void drm_mode_rmfb_work_fn(struct work_struct *w)
+{
+	struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work);
+
+	while (!list_empty(&arg->fbs)) {
+		struct drm_framebuffer *fb =
+			list_first_entry(&arg->fbs, typeof(*fb), filp_head);
+
+		list_del_init(&fb->filp_head);
+		drm_framebuffer_remove(fb);
+	}
+}
+
 /**
  * drm_mode_rmfb - remove an FB from the configuration
  * @dev: drm device for the ioctl
@@ -3356,7 +3430,25 @@
 	mutex_unlock(&dev->mode_config.fb_lock);
 	mutex_unlock(&file_priv->fbs_lock);
 
-	drm_framebuffer_unreference(fb);
+	/*
+	 * we now own the reference that was stored in the fbs list
+	 *
+	 * drm_framebuffer_remove may fail with -EINTR on pending signals,
+	 * so run this in a separate stack as there's no way to correctly
+	 * handle this after the fb is already removed from the lookup table.
+	 */
+	if (atomic_read(&fb->refcount.refcount) > 1) {
+		struct drm_mode_rmfb_work arg;
+
+		INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
+		INIT_LIST_HEAD(&arg.fbs);
+		list_add_tail(&fb->filp_head, &arg.fbs);
+
+		schedule_work(&arg.work);
+		flush_work(&arg.work);
+		destroy_work_on_stack(&arg.work);
+	} else
+		drm_framebuffer_unreference(fb);
 
 	return 0;
 
@@ -3509,7 +3601,6 @@
 	return ret;
 }
 
-
 /**
  * drm_fb_release - remove and free the FBs on this file
  * @priv: drm file for the ioctl
@@ -3524,6 +3615,9 @@
 void drm_fb_release(struct drm_file *priv)
 {
 	struct drm_framebuffer *fb, *tfb;
+	struct drm_mode_rmfb_work arg;
+
+	INIT_LIST_HEAD(&arg.fbs);
 
 	/*
 	 * When the file gets released that means no one else can access the fb
@@ -3536,10 +3630,22 @@
 	 * at it any more.
 	 */
 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
-		list_del_init(&fb->filp_head);
+		if (atomic_read(&fb->refcount.refcount) > 1) {
+			list_move_tail(&fb->filp_head, &arg.fbs);
+		} else {
+			list_del_init(&fb->filp_head);
 
-		/* This drops the fpriv->fbs reference. */
-		drm_framebuffer_unreference(fb);
+			/* This drops the fpriv->fbs reference. */
+			drm_framebuffer_unreference(fb);
+		}
+	}
+
+	if (!list_empty(&arg.fbs)) {
+		INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
+
+		schedule_work(&arg.work);
+		flush_work(&arg.work);
+		destroy_work_on_stack(&arg.work);
 	}
 }
 
@@ -5183,6 +5289,9 @@
 	unsigned long flags;
 	int ret = -EINVAL;
 
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return -EINVAL;
+
 	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
 	    page_flip->reserved != 0)
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/gpu/drm/drm_crtc_helper.c
+++ linux-4.4.0/drivers/gpu/drm/drm_crtc_helper.c
@@ -63,9 +63,6 @@
  * but need to implement the atomic interface instead, potentially using the
  * atomic helpers for that.
  */
-MODULE_AUTHOR("David Airlie, Jesse Barnes");
-MODULE_DESCRIPTION("DRM KMS helper");
-MODULE_LICENSE("GPL and additional rights");
 
 /**
  * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
@@ -855,6 +852,12 @@
  * due to slight differences in allocating shared resources when the
  * configuration is restored in a different order than when userspace set it up)
  * need to use their own restore logic.
+ *
+ * This function is deprecated. New drivers should implement atomic mode-
+ * setting and use the atomic suspend/resume helpers.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
  */
 void drm_helper_resume_force_mode(struct drm_device *dev)
 {
@@ -1015,3 +1018,36 @@
 	return drm_plane_helper_commit(plane, plane_state, old_fb);
 }
 EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
+
+/**
+ * drm_helper_crtc_enable_color_mgmt - enable color management properties
+ * @crtc: DRM CRTC
+ * @degamma_lut_size: the size of the degamma lut (before CSC)
+ * @gamma_lut_size: the size of the gamma lut (after CSC)
+ *
+ * This function lets the driver enable the color correction properties on a
+ * CRTC. This includes 3 degamma, csc and gamma properties that userspace can
+ * set and 2 size properties to inform the userspace of the lut sizes.
+ */
+void drm_helper_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+				       int degamma_lut_size,
+				       int gamma_lut_size)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	drm_object_attach_property(&crtc->base,
+				   config->degamma_lut_property, 0);
+	drm_object_attach_property(&crtc->base,
+				   config->ctm_property, 0);
+	drm_object_attach_property(&crtc->base,
+				   config->gamma_lut_property, 0);
+
+	drm_object_attach_property(&crtc->base,
+				   config->degamma_lut_size_property,
+				   degamma_lut_size);
+	drm_object_attach_property(&crtc->base,
+				   config->gamma_lut_size_property,
+				   gamma_lut_size);
+}
+EXPORT_SYMBOL(drm_helper_crtc_enable_color_mgmt);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_debugfs.c
+++ linux-4.4.0/drivers/gpu/drm/drm_debugfs.c
@@ -290,13 +290,13 @@
 
 	buf[len] = '\0';
 
-	if (!strcmp(buf, "on"))
+	if (sysfs_streq(buf, "on"))
 		connector->force = DRM_FORCE_ON;
-	else if (!strcmp(buf, "digital"))
+	else if (sysfs_streq(buf, "digital"))
 		connector->force = DRM_FORCE_ON_DIGITAL;
-	else if (!strcmp(buf, "off"))
+	else if (sysfs_streq(buf, "off"))
 		connector->force = DRM_FORCE_OFF;
-	else if (!strcmp(buf, "unspecified"))
+	else if (sysfs_streq(buf, "unspecified"))
 		connector->force = DRM_FORCE_UNSPECIFIED;
 	else
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/gpu/drm/drm_dp_aux_dev.c
+++ linux-4.4.0/drivers/gpu/drm/drm_dp_aux_dev.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drmP.h>
+
+struct drm_dp_aux_dev {
+	unsigned index;
+	struct drm_dp_aux *aux;
+	struct device *dev;
+	struct kref refcount;
+	atomic_t usecount;
+};
+
+#define DRM_AUX_MINORS	256
+#define AUX_MAX_OFFSET	(1 << 20)
+static DEFINE_IDR(aux_idr);
+static DEFINE_MUTEX(aux_idr_mutex);
+static struct class *drm_dp_aux_dev_class;
+static int drm_dev_major = -1;
+
+static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_minor(unsigned index)
+{
+	struct drm_dp_aux_dev *aux_dev = NULL;
+
+	mutex_lock(&aux_idr_mutex);
+	aux_dev = idr_find(&aux_idr, index);
+	if (!kref_get_unless_zero(&aux_dev->refcount))
+		aux_dev = NULL;
+	mutex_unlock(&aux_idr_mutex);
+
+	return aux_dev;
+}
+
+static struct drm_dp_aux_dev *alloc_drm_dp_aux_dev(struct drm_dp_aux *aux)
+{
+	struct drm_dp_aux_dev *aux_dev;
+	int index;
+
+	aux_dev = kzalloc(sizeof(*aux_dev), GFP_KERNEL);
+	if (!aux_dev)
+		return ERR_PTR(-ENOMEM);
+	aux_dev->aux = aux;
+	atomic_set(&aux_dev->usecount, 1);
+	kref_init(&aux_dev->refcount);
+
+	mutex_lock(&aux_idr_mutex);
+	index = idr_alloc_cyclic(&aux_idr, aux_dev, 0, DRM_AUX_MINORS,
+				 GFP_KERNEL);
+	mutex_unlock(&aux_idr_mutex);
+	if (index < 0) {
+		kfree(aux_dev);
+		return ERR_PTR(index);
+	}
+	aux_dev->index = index;
+
+	return aux_dev;
+}
+
+static void release_drm_dp_aux_dev(struct kref *ref)
+{
+	struct drm_dp_aux_dev *aux_dev =
+		container_of(ref, struct drm_dp_aux_dev, refcount);
+
+	kfree(aux_dev);
+}
+
+static ssize_t name_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	ssize_t res;
+	struct drm_dp_aux_dev *aux_dev =
+		drm_dp_aux_dev_get_by_minor(MINOR(dev->devt));
+
+	if (!aux_dev)
+		return -ENODEV;
+
+	res = sprintf(buf, "%s\n", aux_dev->aux->name);
+	kref_put(&aux_dev->refcount, release_drm_dp_aux_dev);
+
+	return res;
+}
+static DEVICE_ATTR_RO(name);
+
+static struct attribute *drm_dp_aux_attrs[] = {
+	&dev_attr_name.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(drm_dp_aux);
+
+static int auxdev_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = iminor(inode);
+	struct drm_dp_aux_dev *aux_dev;
+
+	aux_dev = drm_dp_aux_dev_get_by_minor(minor);
+	if (!aux_dev)
+		return -ENODEV;
+
+	file->private_data = aux_dev;
+	return 0;
+}
+
+static loff_t auxdev_llseek(struct file *file, loff_t offset, int whence)
+{
+	return fixed_size_llseek(file, offset, whence, AUX_MAX_OFFSET);
+}
+
+static ssize_t auxdev_read(struct file *file, char __user *buf, size_t count,
+			   loff_t *offset)
+{
+	size_t bytes_pending, num_bytes_processed = 0;
+	struct drm_dp_aux_dev *aux_dev = file->private_data;
+	ssize_t res = 0;
+
+	if (!atomic_inc_not_zero(&aux_dev->usecount))
+		return -ENODEV;
+
+	bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - (*offset));
+
+	if (!access_ok(VERIFY_WRITE, buf, bytes_pending)) {
+		res = -EFAULT;
+		goto out;
+	}
+
+	while (bytes_pending > 0) {
+		uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES];
+		ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf));
+
+		if (signal_pending(current)) {
+			res = num_bytes_processed ?
+				num_bytes_processed : -ERESTARTSYS;
+			goto out;
+		}
+
+		res = drm_dp_dpcd_read(aux_dev->aux, *offset, localbuf, todo);
+		if (res <= 0) {
+			res = num_bytes_processed ? num_bytes_processed : res;
+			goto out;
+		}
+		if (__copy_to_user(buf + num_bytes_processed, localbuf, res)) {
+			res = num_bytes_processed ?
+				num_bytes_processed : -EFAULT;
+			goto out;
+		}
+		bytes_pending -= res;
+		*offset += res;
+		num_bytes_processed += res;
+		res = num_bytes_processed;
+	}
+
+out:
+	atomic_dec(&aux_dev->usecount);
+	wake_up_atomic_t(&aux_dev->usecount);
+	return res;
+}
+
+static ssize_t auxdev_write(struct file *file, const char __user *buf,
+			    size_t count, loff_t *offset)
+{
+	size_t bytes_pending, num_bytes_processed = 0;
+	struct drm_dp_aux_dev *aux_dev = file->private_data;
+	ssize_t res = 0;
+
+	if (!atomic_inc_not_zero(&aux_dev->usecount))
+		return -ENODEV;
+
+	bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - *offset);
+
+	if (!access_ok(VERIFY_READ, buf, bytes_pending)) {
+		res = -EFAULT;
+		goto out;
+	}
+
+	while (bytes_pending > 0) {
+		uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES];
+		ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf));
+
+		if (signal_pending(current)) {
+			res = num_bytes_processed ?
+				num_bytes_processed : -ERESTARTSYS;
+			goto out;
+		}
+
+		if (__copy_from_user(localbuf,
+				     buf + num_bytes_processed, todo)) {
+			res = num_bytes_processed ?
+				num_bytes_processed : -EFAULT;
+			goto out;
+		}
+
+		res = drm_dp_dpcd_write(aux_dev->aux, *offset, localbuf, todo);
+		if (res <= 0) {
+			res = num_bytes_processed ? num_bytes_processed : res;
+			goto out;
+		}
+		bytes_pending -= res;
+		*offset += res;
+		num_bytes_processed += res;
+		res = num_bytes_processed;
+	}
+
+out:
+	atomic_dec(&aux_dev->usecount);
+	wake_up_atomic_t(&aux_dev->usecount);
+	return res;
+}
+
+static int auxdev_release(struct inode *inode, struct file *file)
+{
+	struct drm_dp_aux_dev *aux_dev = file->private_data;
+
+	kref_put(&aux_dev->refcount, release_drm_dp_aux_dev);
+	return 0;
+}
+
+static const struct file_operations auxdev_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= auxdev_llseek,
+	.read		= auxdev_read,
+	.write		= auxdev_write,
+	.open		= auxdev_open,
+	.release	= auxdev_release,
+};
+
+#define to_auxdev(d) container_of(d, struct drm_dp_aux_dev, aux)
+
+static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_aux(struct drm_dp_aux *aux)
+{
+	struct drm_dp_aux_dev *iter, *aux_dev = NULL;
+	int id;
+
+	/* don't increase kref count here because this function should only be
+	 * used by drm_dp_aux_unregister_devnode. Thus, it will always have at
+	 * least one reference - the one that drm_dp_aux_register_devnode
+	 * created
+	 */
+	mutex_lock(&aux_idr_mutex);
+	idr_for_each_entry(&aux_idr, iter, id) {
+		if (iter->aux == aux) {
+			aux_dev = iter;
+			break;
+		}
+	}
+	mutex_unlock(&aux_idr_mutex);
+	return aux_dev;
+}
+
+static int auxdev_wait_atomic_t(atomic_t *p)
+{
+	schedule();
+	return 0;
+}
+/**
+ * drm_dp_aux_unregister_devnode() - unregister a devnode for this aux channel
+ * @aux: DisplayPort AUX channel
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
+{
+	struct drm_dp_aux_dev *aux_dev;
+	unsigned int minor;
+
+	aux_dev = drm_dp_aux_dev_get_by_aux(aux);
+	if (!aux_dev) /* attach must have failed */
+		return;
+
+	mutex_lock(&aux_idr_mutex);
+	idr_remove(&aux_idr, aux_dev->index);
+	mutex_unlock(&aux_idr_mutex);
+
+	atomic_dec(&aux_dev->usecount);
+	wait_on_atomic_t(&aux_dev->usecount, auxdev_wait_atomic_t,
+			 TASK_UNINTERRUPTIBLE);
+
+	minor = aux_dev->index;
+	if (aux_dev->dev)
+		device_destroy(drm_dp_aux_dev_class,
+			       MKDEV(drm_dev_major, minor));
+
+	DRM_DEBUG("drm_dp_aux_dev: aux [%s] unregistering\n", aux->name);
+	kref_put(&aux_dev->refcount, release_drm_dp_aux_dev);
+}
+EXPORT_SYMBOL(drm_dp_aux_unregister_devnode);
+
+/**
+ * drm_dp_aux_register_devnode() - register a devnode for this aux channel
+ * @aux: DisplayPort AUX channel
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
+{
+	struct drm_dp_aux_dev *aux_dev;
+	int res;
+
+	aux_dev = alloc_drm_dp_aux_dev(aux);
+	if (IS_ERR(aux_dev))
+		return PTR_ERR(aux_dev);
+
+	aux_dev->dev = device_create(drm_dp_aux_dev_class, aux->dev,
+				     MKDEV(drm_dev_major, aux_dev->index), NULL,
+				     "drm_dp_aux%d", aux_dev->index);
+	if (IS_ERR(aux_dev->dev)) {
+		res = PTR_ERR(aux_dev->dev);
+		aux_dev->dev = NULL;
+		goto error;
+	}
+
+	DRM_DEBUG("drm_dp_aux_dev: aux [%s] registered as minor %d\n",
+		  aux->name, aux_dev->index);
+	return 0;
+error:
+	drm_dp_aux_unregister_devnode(aux);
+	return res;
+}
+EXPORT_SYMBOL(drm_dp_aux_register_devnode);
+
+int drm_dp_aux_dev_init(void)
+{
+	int res;
+
+	drm_dp_aux_dev_class = class_create(THIS_MODULE, "drm_dp_aux_dev");
+	if (IS_ERR(drm_dp_aux_dev_class)) {
+		res = PTR_ERR(drm_dp_aux_dev_class);
+		goto out;
+	}
+	drm_dp_aux_dev_class->dev_groups = drm_dp_aux_groups;
+
+	res = register_chrdev(0, "aux", &auxdev_fops);
+	if (res < 0)
+		goto out;
+	drm_dev_major = res;
+
+	return 0;
+out:
+	class_destroy(drm_dp_aux_dev_class);
+	return res;
+}
+EXPORT_SYMBOL(drm_dp_aux_dev_init);
+
+void drm_dp_aux_dev_exit(void)
+{
+	unregister_chrdev(drm_dev_major, "aux");
+	class_destroy(drm_dp_aux_dev_class);
+}
+EXPORT_SYMBOL(drm_dp_aux_dev_exit);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_dp_dual_mode_helper.c
+++ linux-4.4.0/drivers/gpu/drm/drm_dp_dual_mode_helper.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <drm/drm_dp_dual_mode_helper.h>
+#include <drm/drmP.h>
+
+/**
+ * DOC: dp dual mode helpers
+ *
+ * Helper functions to deal with DP dual mode (aka. DP++) adaptors.
+ *
+ * Type 1:
+ * Adaptor registers (if any) and the sink DDC bus may be accessed via I2C.
+ *
+ * Type 2:
+ * Adaptor registers and sink DDC bus can be accessed either via I2C or
+ * I2C-over-AUX. Source devices may choose to implement either of these
+ * access methods.
+ */
+
+#define DP_DUAL_MODE_SLAVE_ADDRESS 0x40
+
+/**
+ * drm_dp_dual_mode_read - Read from the DP dual mode adaptor register(s)
+ * @adapter: I2C adapter for the DDC bus
+ * @offset: register offset
+ * @buffer: buffer for return data
+ * @size: sizo of the buffer
+ *
+ * Reads @size bytes from the DP dual mode adaptor registers
+ * starting at @offset.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure
+ */
+ssize_t drm_dp_dual_mode_read(struct i2c_adapter *adapter,
+			      u8 offset, void *buffer, size_t size)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr = DP_DUAL_MODE_SLAVE_ADDRESS,
+			.flags = 0,
+			.len = 1,
+			.buf = &offset,
+		},
+		{
+			.addr = DP_DUAL_MODE_SLAVE_ADDRESS,
+			.flags = I2C_M_RD,
+			.len = size,
+			.buf = buffer,
+		},
+	};
+	int ret;
+
+	ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(msgs))
+		return -EPROTO;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_dp_dual_mode_read);
+
+/**
+ * drm_dp_dual_mode_write - Write to the DP dual mode adaptor register(s)
+ * @adapter: I2C adapter for the DDC bus
+ * @offset: register offset
+ * @buffer: buffer for write data
+ * @size: sizo of the buffer
+ *
+ * Writes @size bytes to the DP dual mode adaptor registers
+ * starting at @offset.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure
+ */
+ssize_t drm_dp_dual_mode_write(struct i2c_adapter *adapter,
+			       u8 offset, const void *buffer, size_t size)
+{
+	struct i2c_msg msg = {
+		.addr = DP_DUAL_MODE_SLAVE_ADDRESS,
+		.flags = 0,
+		.len = 1 + size,
+		.buf = NULL,
+	};
+	void *data;
+	int ret;
+
+	data = kmalloc(msg.len, GFP_TEMPORARY);
+	if (!data)
+		return -ENOMEM;
+
+	msg.buf = data;
+
+	memcpy(data, &offset, 1);
+	memcpy(data + 1, buffer, size);
+
+	ret = i2c_transfer(adapter, &msg, 1);
+
+	kfree(data);
+
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EPROTO;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_dp_dual_mode_write);
+
+static bool is_hdmi_adaptor(const char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN])
+{
+	static const char dp_dual_mode_hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN] =
+		"DP-HDMI ADAPTOR\x04";
+
+	return memcmp(hdmi_id, dp_dual_mode_hdmi_id,
+		      sizeof(dp_dual_mode_hdmi_id)) == 0;
+}
+
+static bool is_type2_adaptor(uint8_t adaptor_id)
+{
+	return adaptor_id == (DP_DUAL_MODE_TYPE_TYPE2 |
+			      DP_DUAL_MODE_REV_TYPE2);
+}
+
+bool is_lspcon_adaptor(const char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN],
+	const uint8_t adaptor_id)
+{
+	return is_hdmi_adaptor(hdmi_id) &&
+		(adaptor_id == (DP_DUAL_MODE_TYPE_TYPE2 |
+		 DP_DUAL_MODE_TYPE_HAS_DPCD));
+}
+
+/**
+ * drm_dp_dual_mode_detect - Identify the DP dual mode adaptor
+ * @adapter: I2C adapter for the DDC bus
+ *
+ * Attempt to identify the type of the DP dual mode adaptor used.
+ *
+ * Note that when the answer is @DRM_DP_DUAL_MODE_UNKNOWN it's not
+ * certain whether we're dealing with a native HDMI port or
+ * a type 1 DVI dual mode adaptor. The driver will have to use
+ * some other hardware/driver specific mechanism to make that
+ * distinction.
+ *
+ * Returns:
+ * The type of the DP dual mode adaptor used
+ */
+enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(struct i2c_adapter *adapter)
+{
+	char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN] = {};
+	uint8_t adaptor_id = 0x00;
+	ssize_t ret;
+
+	/*
+	 * Let's see if the adaptor is there the by reading the
+	 * HDMI ID registers.
+	 *
+	 * Note that type 1 DVI adaptors are not required to implemnt
+	 * any registers, and that presents a problem for detection.
+	 * If the i2c transfer is nacked, we may or may not be dealing
+	 * with a type 1 DVI adaptor. Some other mechanism of detecting
+	 * the presence of the adaptor is required. One way would be
+	 * to check the state of the CONFIG1 pin, Another method would
+	 * simply require the driver to know whether the port is a DP++
+	 * port or a native HDMI port. Both of these methods are entirely
+	 * hardware/driver specific so we can't deal with them here.
+	 */
+	ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_HDMI_ID,
+				    hdmi_id, sizeof(hdmi_id));
+	if (ret)
+		return DRM_DP_DUAL_MODE_UNKNOWN;
+
+	/*
+	 * Sigh. Some (maybe all?) type 1 adaptors are broken and ack
+	 * the offset but ignore it, and instead they just always return
+	 * data from the start of the HDMI ID buffer. So for a broken
+	 * type 1 HDMI adaptor a single byte read will always give us
+	 * 0x44, and for a type 1 DVI adaptor it should give 0x00
+	 * (assuming it implements any registers). Fortunately neither
+	 * of those values will match the type 2 signature of the
+	 * DP_DUAL_MODE_ADAPTOR_ID register so we can proceed with
+	 * the type 2 adaptor detection safely even in the presence
+	 * of broken type 1 adaptors.
+	 */
+	ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_ADAPTOR_ID,
+				    &adaptor_id, sizeof(adaptor_id));
+	if (ret == 0) {
+		if (is_lspcon_adaptor(hdmi_id, adaptor_id))
+			return DRM_DP_DUAL_MODE_LSPCON;
+		if (is_type2_adaptor(adaptor_id)) {
+			if (is_hdmi_adaptor(hdmi_id))
+				return DRM_DP_DUAL_MODE_TYPE2_HDMI;
+			else
+				return DRM_DP_DUAL_MODE_TYPE2_DVI;
+		}
+	}
+
+	if (is_hdmi_adaptor(hdmi_id))
+		return DRM_DP_DUAL_MODE_TYPE1_HDMI;
+	else
+		return DRM_DP_DUAL_MODE_TYPE1_DVI;
+}
+EXPORT_SYMBOL(drm_dp_dual_mode_detect);
+
+/**
+ * drm_dp_dual_mode_max_tmds_clock - Max TMDS clock for DP dual mode adaptor
+ * @type: DP dual mode adaptor type
+ * @adapter: I2C adapter for the DDC bus
+ *
+ * Determine the max TMDS clock the adaptor supports based on the
+ * type of the dual mode adaptor and the DP_DUAL_MODE_MAX_TMDS_CLOCK
+ * register (on type2 adaptors). As some type 1 adaptors have
+ * problems with registers (see comments in drm_dp_dual_mode_detect())
+ * we don't read the register on those, instead we simply assume
+ * a 165 MHz limit based on the specification.
+ *
+ * Returns:
+ * Maximum supported TMDS clock rate for the DP dual mode adaptor in kHz.
+ */
+int drm_dp_dual_mode_max_tmds_clock(enum drm_dp_dual_mode_type type,
+				    struct i2c_adapter *adapter)
+{
+	uint8_t max_tmds_clock;
+	ssize_t ret;
+
+	/* native HDMI so no limit */
+	if (type == DRM_DP_DUAL_MODE_NONE)
+		return 0;
+
+	/*
+	 * Type 1 adaptors are limited to 165MHz
+	 * Type 2 adaptors can tells us their limit
+	 */
+	if (type < DRM_DP_DUAL_MODE_TYPE2_DVI)
+		return 165000;
+
+	ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_MAX_TMDS_CLOCK,
+				    &max_tmds_clock, sizeof(max_tmds_clock));
+	if (ret || max_tmds_clock == 0x00 || max_tmds_clock == 0xff) {
+		DRM_DEBUG_KMS("Failed to query max TMDS clock\n");
+		return 165000;
+	}
+
+	return max_tmds_clock * 5000 / 2;
+}
+EXPORT_SYMBOL(drm_dp_dual_mode_max_tmds_clock);
+
+/**
+ * drm_dp_dual_mode_get_tmds_output - Get the state of the TMDS output buffers in the DP dual mode adaptor
+ * @type: DP dual mode adaptor type
+ * @adapter: I2C adapter for the DDC bus
+ * @enabled: current state of the TMDS output buffers
+ *
+ * Get the state of the TMDS output buffers in the adaptor. For
+ * type2 adaptors this is queried from the DP_DUAL_MODE_TMDS_OEN
+ * register. As some type 1 adaptors have problems with registers
+ * (see comments in drm_dp_dual_mode_detect()) we don't read the
+ * register on those, instead we simply assume that the buffers
+ * are always enabled.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure
+ */
+int drm_dp_dual_mode_get_tmds_output(enum drm_dp_dual_mode_type type,
+				     struct i2c_adapter *adapter,
+				     bool *enabled)
+{
+	uint8_t tmds_oen;
+	ssize_t ret;
+
+	if (type < DRM_DP_DUAL_MODE_TYPE2_DVI) {
+		*enabled = true;
+		return 0;
+	}
+
+	ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_TMDS_OEN,
+				    &tmds_oen, sizeof(tmds_oen));
+	if (ret) {
+		DRM_DEBUG_KMS("Failed to query state of TMDS output buffers\n");
+		return ret;
+	}
+
+	*enabled = !(tmds_oen & DP_DUAL_MODE_TMDS_DISABLE);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_dp_dual_mode_get_tmds_output);
+
+/**
+ * drm_dp_dual_mode_set_tmds_output - Enable/disable TMDS output buffers in the DP dual mode adaptor
+ * @type: DP dual mode adaptor type
+ * @adapter: I2C adapter for the DDC bus
+ * @enable: enable (as opposed to disable) the TMDS output buffers
+ *
+ * Set the state of the TMDS output buffers in the adaptor. For
+ * type2 this is set via the DP_DUAL_MODE_TMDS_OEN register. As
+ * some type 1 adaptors have problems with registers (see comments
+ * in drm_dp_dual_mode_detect()) we avoid touching the register,
+ * making this function a no-op on type 1 adaptors.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure
+ */
+int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type,
+				     struct i2c_adapter *adapter, bool enable)
+{
+	uint8_t tmds_oen = enable ? 0 : DP_DUAL_MODE_TMDS_DISABLE;
+	ssize_t ret;
+
+	if (type < DRM_DP_DUAL_MODE_TYPE2_DVI)
+		return 0;
+
+	ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN,
+				     &tmds_oen, sizeof(tmds_oen));
+	if (ret) {
+		DRM_DEBUG_KMS("Failed to %s TMDS output buffers\n",
+			      enable ? "enable" : "disable");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_dp_dual_mode_set_tmds_output);
+
+/**
+ * drm_dp_get_dual_mode_type_name - Get the name of the DP dual mode adaptor type as a string
+ * @type: DP dual mode adaptor type
+ *
+ * Returns:
+ * String representation of the DP dual mode adaptor type
+ */
+const char *drm_dp_get_dual_mode_type_name(enum drm_dp_dual_mode_type type)
+{
+	switch (type) {
+	case DRM_DP_DUAL_MODE_NONE:
+		return "none";
+	case DRM_DP_DUAL_MODE_TYPE1_DVI:
+		return "type 1 DVI";
+	case DRM_DP_DUAL_MODE_TYPE1_HDMI:
+		return "type 1 HDMI";
+	case DRM_DP_DUAL_MODE_TYPE2_DVI:
+		return "type 2 DVI";
+	case DRM_DP_DUAL_MODE_TYPE2_HDMI:
+		return "type 2 HDMI";
+	default:
+		WARN_ON(type != DRM_DP_DUAL_MODE_UNKNOWN);
+		return "unknown";
+	}
+}
+EXPORT_SYMBOL(drm_dp_get_dual_mode_type_name);
+
+/**
+ * drm_lspcon_get_mode: Get LSPCON's current mode of operation by
+ * by reading offset (0x80, 0x41)
+ * @i2c_adapter: I2C-over-aux adapter
+ * @current_mode: out vaiable, current lspcon mode of operation
+ *
+ * Returns:
+ * 0 on success, sets the current_mode value to appropriate mode
+ * -error on failure
+ */
+int drm_lspcon_get_mode(struct i2c_adapter *adapter,
+			enum drm_lspcon_mode *mode)
+{
+	u8 data;
+	int ret = 0;
+
+	if (!mode) {
+		DRM_ERROR("NULL input\n");
+		return -EINVAL;
+	}
+
+	/* Read Status: i2c over aux */
+	ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_LSPCON_CURRENT_MODE,
+				    &data, sizeof(data));
+	if (ret < 0) {
+		DRM_ERROR("LSPCON read(0x80, 0x41) failed\n");
+		return -EFAULT;
+	}
+
+	if (data & DP_DUAL_MODE_LSPCON_MODE_PCON)
+		*mode = DRM_LSPCON_MODE_PCON;
+	else
+		*mode = DRM_LSPCON_MODE_LS;
+	return 0;
+}
+EXPORT_SYMBOL(drm_lspcon_get_mode);
+
+/**
+ * drm_lspcon_change_mode: Change LSPCON's mode of operation by
+ * by writing offset (0x80, 0x40)
+ * @i2c_adapter: I2C-over-aux adapter
+ * @reqd_mode: required mode of operation
+ *
+ * Returns:
+ * 0 on success, -error on failure/timeout
+ */
+int drm_lspcon_set_mode(struct i2c_adapter *adapter,
+			enum drm_lspcon_mode mode)
+{
+	u8 data = 0;
+	int ret;
+	int time_out = 200;
+	enum drm_lspcon_mode current_mode;
+
+	if (mode == DRM_LSPCON_MODE_PCON)
+		data = DP_DUAL_MODE_LSPCON_MODE_PCON;
+
+	/* Change mode */
+	ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_LSPCON_MODE_CHANGE,
+				     &data, sizeof(data));
+	if (ret < 0) {
+		DRM_ERROR("LSPCON mode change failed\n");
+		return ret;
+	}
+
+	/*
+	 * Confirm mode change by reading the status bit.
+	 * Sometimes, it takes a while to change the mode,
+	 * so wait and retry until time out or done.
+	 */
+	do {
+		ret = drm_lspcon_get_mode(adapter, &current_mode);
+		if (ret) {
+			DRM_ERROR("can't confirm LSPCON mode change\n");
+			return ret;
+		} else {
+			if (current_mode != mode) {
+				msleep(10);
+				time_out -= 10;
+			} else {
+				DRM_DEBUG_KMS("LSPCON mode changed to %s\n",
+						mode == DRM_LSPCON_MODE_LS ?
+						"LS" : "PCON");
+				return 0;
+			}
+		}
+	} while (time_out);
+
+	DRM_ERROR("LSPCON mode change timed out\n");
+	return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(drm_lspcon_set_mode);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_dp_helper.c
+++ linux-4.4.0/drivers/gpu/drm/drm_dp_helper.c
@@ -28,6 +28,7 @@
 #include <linux/sched.h>
 #include <linux/i2c.h>
 #include <drm/drm_dp_helper.h>
+#include <drm/drm_dp_aux_dev.h>
 #include <drm/drmP.h>
 
 /**
@@ -178,7 +179,7 @@
 {
 	struct drm_dp_aux_msg msg;
 	unsigned int retry;
-	int err;
+	int err = 0;
 
 	memset(&msg, 0, sizeof(msg));
 	msg.address = offset;
@@ -186,6 +187,8 @@
 	msg.buffer = buffer;
 	msg.size = size;
 
+	mutex_lock(&aux->hw_mutex);
+
 	/*
 	 * The specification doesn't give any recommendation on how often to
 	 * retry native transactions. We used to retry 7 times like for
@@ -194,25 +197,24 @@
 	 */
 	for (retry = 0; retry < 32; retry++) {
 
-		mutex_lock(&aux->hw_mutex);
 		err = aux->transfer(aux, &msg);
-		mutex_unlock(&aux->hw_mutex);
 		if (err < 0) {
 			if (err == -EBUSY)
 				continue;
 
-			return err;
+			goto unlock;
 		}
 
 
 		switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) {
 		case DP_AUX_NATIVE_REPLY_ACK:
 			if (err < size)
-				return -EPROTO;
-			return err;
+				err = -EPROTO;
+			goto unlock;
 
 		case DP_AUX_NATIVE_REPLY_NACK:
-			return -EIO;
+			err = -EIO;
+			goto unlock;
 
 		case DP_AUX_NATIVE_REPLY_DEFER:
 			usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
@@ -221,7 +223,11 @@
 	}
 
 	DRM_DEBUG_KMS("too many retries, giving up\n");
-	return -EIO;
+	err = -EIO;
+
+unlock:
+	mutex_unlock(&aux->hw_mutex);
+	return err;
 }
 
 /**
@@ -543,9 +549,7 @@
 	int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz));
 
 	for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) {
-		mutex_lock(&aux->hw_mutex);
 		ret = aux->transfer(aux, msg);
-		mutex_unlock(&aux->hw_mutex);
 		if (ret < 0) {
 			if (ret == -EBUSY)
 				continue;
@@ -684,6 +688,8 @@
 
 	memset(&msg, 0, sizeof(msg));
 
+	mutex_lock(&aux->hw_mutex);
+
 	for (i = 0; i < num; i++) {
 		msg.address = msgs[i].addr;
 		drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
@@ -738,6 +744,8 @@
 	msg.size = 0;
 	(void)drm_dp_i2c_do_msg(aux, &msg);
 
+	mutex_unlock(&aux->hw_mutex);
+
 	return err;
 }
 
@@ -754,6 +762,8 @@
  */
 int drm_dp_aux_register(struct drm_dp_aux *aux)
 {
+	int ret;
+
 	mutex_init(&aux->hw_mutex);
 
 	aux->ddc.algo = &drm_dp_i2c_algo;
@@ -768,7 +778,17 @@
 	strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
 		sizeof(aux->ddc.name));
 
-	return i2c_add_adapter(&aux->ddc);
+	ret = drm_dp_aux_register_devnode(aux);
+	if (ret)
+		return ret;
+
+	ret = i2c_add_adapter(&aux->ddc);
+	if (ret) {
+		drm_dp_aux_unregister_devnode(aux);
+		return ret;
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL(drm_dp_aux_register);
 
@@ -778,6 +798,7 @@
  */
 void drm_dp_aux_unregister(struct drm_dp_aux *aux)
 {
+	drm_dp_aux_unregister_devnode(aux);
 	i2c_del_adapter(&aux->ddc);
 }
 EXPORT_SYMBOL(drm_dp_aux_unregister);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_dp_mst_topology.c
+++ linux-4.4.0/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -29,6 +29,7 @@
 #include <linux/i2c.h>
 #include <drm/drm_dp_mst_helper.h>
 #include <drm/drmP.h>
+#include <linux/iopoll.h>
 
 #include <drm/drm_fixed.h>
 
@@ -272,7 +273,7 @@
 			memcpy(&buf[idx], req->u.i2c_read.transactions[i].bytes, req->u.i2c_read.transactions[i].num_bytes);
 			idx += req->u.i2c_read.transactions[i].num_bytes;
 
-			buf[idx] = (req->u.i2c_read.transactions[i].no_stop_bit & 0x1) << 5;
+			buf[idx] = (req->u.i2c_read.transactions[i].no_stop_bit & 0x1) << 4;
 			buf[idx] |= (req->u.i2c_read.transactions[i].i2c_transaction_delay & 0xf);
 			idx++;
 		}
@@ -330,6 +331,13 @@
 			return false;
 		}
 
+		/*
+		 * ignore out-of-order messages or messages that are part of a
+		 * failed transaction
+		 */
+		if (!recv_hdr.somt && !msg->have_somt)
+			return false;
+
 		/* get length contained in this portion */
 		msg->curchunk_len = recv_hdr.msg_len;
 		msg->curchunk_hdrlen = hdrlen;
@@ -424,6 +432,7 @@
 	if (idx > raw->curlen)
 		goto fail_len;
 	repmsg->u.remote_dpcd_read_ack.num_bytes = raw->msg[idx];
+	idx++;
 	if (idx > raw->curlen)
 		goto fail_len;
 
@@ -666,7 +675,9 @@
 }
 
 static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_num,
-				  u8 vcpi, uint16_t pbn)
+				  u8 vcpi, uint16_t pbn,
+				  u8 number_sdp_streams,
+				  u8 *sdp_stream_sink)
 {
 	struct drm_dp_sideband_msg_req_body req;
 	memset(&req, 0, sizeof(req));
@@ -674,6 +685,9 @@
 	req.u.allocate_payload.port_number = port_num;
 	req.u.allocate_payload.vcpi = vcpi;
 	req.u.allocate_payload.pbn = pbn;
+	req.u.allocate_payload.number_sdp_streams = number_sdp_streams;
+	memcpy(req.u.allocate_payload.sdp_stream_sink, sdp_stream_sink,
+		   number_sdp_streams);
 	drm_dp_encode_sideband_req(&req, msg);
 	msg->path_msg = true;
 	return 0;
@@ -798,6 +812,18 @@
 	return mstb;
 }
 
+static void drm_dp_free_mst_port(struct kref *kref);
+
+static void drm_dp_free_mst_branch_device(struct kref *kref)
+{
+	struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
+	if (mstb->port_parent) {
+		if (list_empty(&mstb->port_parent->next))
+			kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port);
+	}
+	kfree(mstb);
+}
+
 static void drm_dp_destroy_mst_branch_device(struct kref *kref)
 {
 	struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
@@ -805,6 +831,15 @@
 	bool wake_tx = false;
 
 	/*
+	 * init kref again to be used by ports to remove mst branch when it is
+	 * not needed anymore
+	 */
+	kref_init(kref);
+
+	if (mstb->port_parent && list_empty(&mstb->port_parent->next))
+		kref_get(&mstb->port_parent->kref);
+
+	/*
 	 * destroy all ports - don't need lock
 	 * as there are no more references to the mst branch
 	 * device at this point.
@@ -830,7 +865,8 @@
 
 	if (wake_tx)
 		wake_up(&mstb->mgr->tx_waitq);
-	kfree(mstb);
+
+	kref_put(kref, drm_dp_free_mst_branch_device);
 }
 
 static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb)
@@ -878,6 +914,7 @@
 			 * from an EDID retrieval */
 
 			mutex_lock(&mgr->destroy_connector_lock);
+			kref_get(&port->parent->kref);
 			list_add(&port->next, &mgr->destroy_connector_list);
 			mutex_unlock(&mgr->destroy_connector_lock);
 			schedule_work(&mgr->destroy_connector_work);
@@ -886,6 +923,7 @@
 		/* no need to clean up vcpi
 		 * as if we have no connector we never setup a vcpi */
 		drm_dp_port_teardown_pdt(port, port->pdt);
+		port->pdt = DP_PEER_DEVICE_NONE;
 	}
 	kfree(port);
 }
@@ -973,17 +1011,17 @@
 static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port,
 				 u8 *rad)
 {
-	int lct = port->parent->lct;
+	int parent_lct = port->parent->lct;
 	int shift = 4;
-	int idx = lct / 2;
-	if (lct > 1) {
-		memcpy(rad, port->parent->rad, idx);
-		shift = (lct % 2) ? 4 : 0;
+	int idx = (parent_lct - 1) / 2;
+	if (parent_lct > 1) {
+		memcpy(rad, port->parent->rad, idx + 1);
+		shift = (parent_lct % 2) ? 4 : 0;
 	} else
 		rad[0] = 0;
 
 	rad[idx] |= port->port_num << shift;
-	return lct + 1;
+	return parent_lct + 1;
 }
 
 /*
@@ -1004,27 +1042,38 @@
 		lct = drm_dp_calculate_rad(port, rad);
 
 		port->mstb = drm_dp_add_mst_branch_device(lct, rad);
-		port->mstb->mgr = port->mgr;
-		port->mstb->port_parent = port;
+		if (port->mstb) {
+			port->mstb->mgr = port->mgr;
+			port->mstb->port_parent = port;
 
-		send_link = true;
+			send_link = true;
+		}
 		break;
 	}
 	return send_link;
 }
 
-static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb,
-				   struct drm_dp_mst_port *port)
+static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
 {
 	int ret;
-	if (port->dpcd_rev >= 0x12) {
-		port->guid_valid = drm_dp_validate_guid(mstb->mgr, port->guid);
-		if (!port->guid_valid) {
-			ret = drm_dp_send_dpcd_write(mstb->mgr,
-						     port,
-						     DP_GUID,
-						     16, port->guid);
-			port->guid_valid = true;
+
+	memcpy(mstb->guid, guid, 16);
+
+	if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) {
+		if (mstb->port_parent) {
+			ret = drm_dp_send_dpcd_write(
+					mstb->mgr,
+					mstb->port_parent,
+					DP_GUID,
+					16,
+					mstb->guid);
+		} else {
+
+			ret = drm_dp_dpcd_write(
+					mstb->mgr->aux,
+					DP_GUID,
+					mstb->guid,
+					16);
 		}
 	}
 }
@@ -1039,7 +1088,7 @@
 	snprintf(proppath, proppath_size, "mst:%d", mstb->mgr->conn_base_id);
 	for (i = 0; i < (mstb->lct - 1); i++) {
 		int shift = (i % 2) ? 0 : 4;
-		int port_num = mstb->rad[i / 2] >> shift;
+		int port_num = (mstb->rad[i / 2] >> shift) & 0xf;
 		snprintf(temp, sizeof(temp), "-%d", port_num);
 		strlcat(proppath, temp, proppath_size);
 	}
@@ -1081,7 +1130,6 @@
 	port->dpcd_rev = port_msg->dpcd_revision;
 	port->num_sdp_streams = port_msg->num_sdp_streams;
 	port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks;
-	memcpy(port->guid, port_msg->peer_guid, 16);
 
 	/* manage mstb port lists with mgr lock - take a reference
 	   for this list */
@@ -1094,11 +1142,9 @@
 
 	if (old_ddps != port->ddps) {
 		if (port->ddps) {
-			drm_dp_check_port_guid(mstb, port);
 			if (!port->input)
 				drm_dp_send_enum_path_resources(mstb->mgr, mstb, port);
 		} else {
-			port->guid_valid = false;
 			port->available_pbn = 0;
 			}
 	}
@@ -1125,7 +1171,9 @@
 			drm_dp_put_port(port);
 			goto out;
 		}
-		if (port->port_num >= DP_MST_LOGICAL_PORT_0) {
+		if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
+		     port->pdt == DP_PEER_DEVICE_SST_SINK) &&
+		    port->port_num >= DP_MST_LOGICAL_PORT_0) {
 			port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
 			drm_mode_connector_set_tile_property(port->connector);
 		}
@@ -1157,10 +1205,8 @@
 
 	if (old_ddps != port->ddps) {
 		if (port->ddps) {
-			drm_dp_check_port_guid(mstb, port);
 			dowork = true;
 		} else {
-			port->guid_valid = false;
 			port->available_pbn = 0;
 		}
 	}
@@ -1188,9 +1234,12 @@
 	mutex_lock(&mgr->lock);
 	mstb = mgr->mst_primary;
 
+	if (!mstb)
+		goto out;
+
 	for (i = 0; i < lct - 1; i++) {
 		int shift = (i % 2) ? 0 : 4;
-		int port_num = rad[i / 2] >> shift;
+		int port_num = (rad[i / 2] >> shift) & 0xf;
 
 		list_for_each_entry(port, &mstb->ports, next) {
 			if (port->port_num == port_num) {
@@ -1210,6 +1259,48 @@
 	return mstb;
 }
 
+static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
+	struct drm_dp_mst_branch *mstb,
+	uint8_t *guid)
+{
+	struct drm_dp_mst_branch *found_mstb;
+	struct drm_dp_mst_port *port;
+
+	if (memcmp(mstb->guid, guid, 16) == 0)
+		return mstb;
+
+
+	list_for_each_entry(port, &mstb->ports, next) {
+		if (!port->mstb)
+			continue;
+
+		found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
+
+		if (found_mstb)
+			return found_mstb;
+	}
+
+	return NULL;
+}
+
+static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid(
+	struct drm_dp_mst_topology_mgr *mgr,
+	uint8_t *guid)
+{
+	struct drm_dp_mst_branch *mstb;
+
+	/* find the port by iterating down */
+	mutex_lock(&mgr->lock);
+
+	mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid);
+
+	if (mstb)
+		kref_get(&mstb->kref);
+
+	mutex_unlock(&mgr->lock);
+	return mstb;
+}
+
 static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
 					       struct drm_dp_mst_branch *mstb)
 {
@@ -1320,6 +1411,7 @@
 				  struct drm_dp_sideband_msg_tx *txmsg)
 {
 	struct drm_dp_mst_branch *mstb = txmsg->dst;
+	u8 req_type;
 
 	/* both msg slots are full */
 	if (txmsg->seqno == -1) {
@@ -1336,7 +1428,13 @@
 			txmsg->seqno = 1;
 		mstb->tx_slots[txmsg->seqno] = txmsg;
 	}
-	hdr->broadcast = 0;
+
+	req_type = txmsg->msg[0] & 0x7f;
+	if (req_type == DP_CONNECTION_STATUS_NOTIFY ||
+		req_type == DP_RESOURCE_STATUS_NOTIFY)
+		hdr->broadcast = 1;
+	else
+		hdr->broadcast = 0;
 	hdr->path_msg = txmsg->path_msg;
 	hdr->lct = mstb->lct;
 	hdr->lcr = mstb->lct - 1;
@@ -1438,26 +1536,22 @@
 }
 
 /* called holding qlock */
-static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr)
+static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
+				       struct drm_dp_sideband_msg_tx *txmsg)
 {
-	struct drm_dp_sideband_msg_tx *txmsg;
 	int ret;
 
 	/* construct a chunk from the first msg in the tx_msg queue */
-	if (list_empty(&mgr->tx_msg_upq)) {
-		mgr->tx_up_in_progress = false;
-		return;
-	}
-
-	txmsg = list_first_entry(&mgr->tx_msg_upq, struct drm_dp_sideband_msg_tx, next);
 	ret = process_single_tx_qlock(mgr, txmsg, true);
-	if (ret == 1) {
-		/* up txmsgs aren't put in slots - so free after we send it */
-		list_del(&txmsg->next);
-		kfree(txmsg);
-	} else if (ret)
+
+	if (ret != 1)
 		DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
-	mgr->tx_up_in_progress = true;
+
+	if (txmsg->seqno != -1) {
+		WARN_ON((unsigned int)txmsg->seqno >
+			ARRAY_SIZE(txmsg->dst->tx_slots));
+		txmsg->dst->tx_slots[txmsg->seqno] = NULL;
+	}
 }
 
 static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr,
@@ -1507,6 +1601,9 @@
 				       txmsg->reply.u.link_addr.ports[i].num_sdp_streams,
 				       txmsg->reply.u.link_addr.ports[i].num_sdp_stream_sinks);
 			}
+
+			drm_dp_check_mstb_guid(mstb, txmsg->reply.u.link_addr.guid);
+
 			for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) {
 				drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]);
 			}
@@ -1554,6 +1651,37 @@
 	return 0;
 }
 
+static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb)
+{
+	if (!mstb->port_parent)
+		return NULL;
+
+	if (mstb->port_parent->mstb != mstb)
+		return mstb->port_parent;
+
+	return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent);
+}
+
+static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr,
+									 struct drm_dp_mst_branch *mstb,
+									 int *port_num)
+{
+	struct drm_dp_mst_branch *rmstb = NULL;
+	struct drm_dp_mst_port *found_port;
+	mutex_lock(&mgr->lock);
+	if (mgr->mst_primary) {
+		found_port = drm_dp_get_last_connected_port_to_mstb(mstb);
+
+		if (found_port) {
+			rmstb = found_port->parent;
+			kref_get(&rmstb->kref);
+			*port_num = found_port->port_num;
+		}
+	}
+	mutex_unlock(&mgr->lock);
+	return rmstb;
+}
+
 static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
 				   struct drm_dp_mst_port *port,
 				   int id,
@@ -1561,22 +1689,38 @@
 {
 	struct drm_dp_sideband_msg_tx *txmsg;
 	struct drm_dp_mst_branch *mstb;
-	int len, ret;
+	int len, ret, port_num;
+	u8 sinks[DRM_DP_MAX_SDP_STREAMS];
+	int i;
 
-	mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
-	if (!mstb)
+	port = drm_dp_get_validated_port_ref(mgr, port);
+	if (!port)
 		return -EINVAL;
 
+	port_num = port->port_num;
+	mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
+	if (!mstb) {
+		mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num);
+
+		if (!mstb) {
+			drm_dp_put_port(port);
+			return -EINVAL;
+		}
+	}
+
 	txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
 	if (!txmsg) {
 		ret = -ENOMEM;
 		goto fail_put;
 	}
 
+	for (i = 0; i < port->num_sdp_streams; i++)
+		sinks[i] = i;
+
 	txmsg->dst = mstb;
-	len = build_allocate_payload(txmsg, port->port_num,
+	len = build_allocate_payload(txmsg, port_num,
 				     id,
-				     pbn);
+				     pbn, port->num_sdp_streams, sinks);
 
 	drm_dp_queue_down_tx(mgr, txmsg);
 
@@ -1590,6 +1734,7 @@
 	kfree(txmsg);
 fail_put:
 	drm_dp_put_mst_branch_device(mstb);
+	drm_dp_put_port(port);
 	return ret;
 }
 
@@ -1672,7 +1817,13 @@
 		req_payload.start_slot = cur_slots;
 		if (mgr->proposed_vcpis[i]) {
 			port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi);
+			port = drm_dp_get_validated_port_ref(mgr, port);
+			if (!port) {
+				mutex_unlock(&mgr->payload_lock);
+				return -EINVAL;
+			}
 			req_payload.num_slots = mgr->proposed_vcpis[i]->num_slots;
+			req_payload.vcpi = mgr->proposed_vcpis[i]->vcpi;
 		} else {
 			port = NULL;
 			req_payload.num_slots = 0;
@@ -1688,15 +1839,19 @@
 			if (req_payload.num_slots) {
 				drm_dp_create_payload_step1(mgr, mgr->proposed_vcpis[i]->vcpi, &req_payload);
 				mgr->payloads[i].num_slots = req_payload.num_slots;
+				mgr->payloads[i].vcpi = req_payload.vcpi;
 			} else if (mgr->payloads[i].num_slots) {
 				mgr->payloads[i].num_slots = 0;
-				drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]);
+				drm_dp_destroy_payload_step1(mgr, port, mgr->payloads[i].vcpi, &mgr->payloads[i]);
 				req_payload.payload_state = mgr->payloads[i].payload_state;
 				mgr->payloads[i].start_slot = 0;
 			}
 			mgr->payloads[i].payload_state = req_payload.payload_state;
 		}
 		cur_slots += req_payload.num_slots;
+
+		if (port)
+			drm_dp_put_port(port);
 	}
 
 	for (i = 0; i < mgr->max_payloads; i++) {
@@ -1844,11 +1999,12 @@
 	drm_dp_encode_up_ack_reply(txmsg, req_type);
 
 	mutex_lock(&mgr->qlock);
-	list_add_tail(&txmsg->next, &mgr->tx_msg_upq);
-	if (!mgr->tx_up_in_progress) {
-		process_single_up_tx_qlock(mgr);
-	}
+
+	process_single_up_tx_qlock(mgr, txmsg);
+
 	mutex_unlock(&mgr->qlock);
+
+	kfree(txmsg);
 	return 0;
 }
 
@@ -1888,6 +2044,7 @@
 	int ret = 0;
 	struct drm_dp_mst_branch *mstb = NULL;
 
+	mutex_lock(&mgr->payload_lock);
 	mutex_lock(&mgr->lock);
 	if (mst_state == mgr->mst_state)
 		goto out_unlock;
@@ -1927,31 +2084,17 @@
 		mgr->mst_primary = mstb;
 		kref_get(&mgr->mst_primary->kref);
 
-		{
-			struct drm_dp_payload reset_pay;
-			reset_pay.start_slot = 0;
-			reset_pay.num_slots = 0x3f;
-			drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
-		}
-
 		ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
-					 DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
+							 DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
 		if (ret < 0) {
 			goto out_unlock;
 		}
 
-
-		/* sort out guid */
-		ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, mgr->guid, 16);
-		if (ret != 16) {
-			DRM_DEBUG_KMS("failed to read DP GUID %d\n", ret);
-			goto out_unlock;
-		}
-
-		mgr->guid_valid = drm_dp_validate_guid(mgr, mgr->guid);
-		if (!mgr->guid_valid) {
-			ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, mgr->guid, 16);
-			mgr->guid_valid = true;
+		{
+			struct drm_dp_payload reset_pay;
+			reset_pay.start_slot = 0;
+			reset_pay.num_slots = 0x3f;
+			drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
 		}
 
 		queue_work(system_long_wq, &mgr->work);
@@ -1964,7 +2107,10 @@
 		/* this can fail if the device is gone */
 		drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0);
 		ret = 0;
-		memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload));
+		memset(mgr->payloads, 0,
+		       mgr->max_payloads * sizeof(mgr->payloads[0]));
+		memset(mgr->proposed_vcpis, 0,
+		       mgr->max_payloads * sizeof(mgr->proposed_vcpis[0]));
 		mgr->payload_mask = 0;
 		set_bit(0, &mgr->payload_mask);
 		mgr->vcpi_mask = 0;
@@ -1972,6 +2118,7 @@
 
 out_unlock:
 	mutex_unlock(&mgr->lock);
+	mutex_unlock(&mgr->payload_lock);
 	if (mstb)
 		drm_dp_put_mst_branch_device(mstb);
 	return ret;
@@ -2015,6 +2162,8 @@
 
 	if (mgr->mst_primary) {
 		int sret;
+		u8 guid[16];
+
 		sret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, mgr->dpcd, DP_RECEIVER_CAP_SIZE);
 		if (sret != DP_RECEIVER_CAP_SIZE) {
 			DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n");
@@ -2029,6 +2178,16 @@
 			ret = -1;
 			goto out_unlock;
 		}
+
+		/* Some hubs forget their guids after they resume */
+		sret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16);
+		if (sret != 16) {
+			DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n");
+			ret = -1;
+			goto out_unlock;
+		}
+		drm_dp_check_mstb_guid(mgr->mst_primary, guid);
+
 		ret = 0;
 	} else
 		ret = -1;
@@ -2039,7 +2198,7 @@
 }
 EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
 
-static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
+static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
 {
 	int len;
 	u8 replyblock[32];
@@ -2054,12 +2213,12 @@
 			       replyblock, len);
 	if (ret != len) {
 		DRM_DEBUG_KMS("failed to read DPCD down rep %d %d\n", len, ret);
-		return;
+		return false;
 	}
 	ret = drm_dp_sideband_msg_build(msg, replyblock, len, true);
 	if (!ret) {
 		DRM_DEBUG_KMS("sideband msg build failed %d\n", replyblock[0]);
-		return;
+		return false;
 	}
 	replylen = msg->curchunk_len + msg->curchunk_hdrlen;
 
@@ -2071,21 +2230,32 @@
 		ret = drm_dp_dpcd_read(mgr->aux, basereg + curreply,
 				    replyblock, len);
 		if (ret != len) {
-			DRM_DEBUG_KMS("failed to read a chunk\n");
+			DRM_DEBUG_KMS("failed to read a chunk (len %d, ret %d)\n",
+				      len, ret);
+			return false;
 		}
+
 		ret = drm_dp_sideband_msg_build(msg, replyblock, len, false);
-		if (ret == false)
+		if (!ret) {
 			DRM_DEBUG_KMS("failed to build sideband msg\n");
+			return false;
+		}
+
 		curreply += len;
 		replylen -= len;
 	}
+	return true;
 }
 
 static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
 {
 	int ret = 0;
 
-	drm_dp_get_one_sb_msg(mgr, false);
+	if (!drm_dp_get_one_sb_msg(mgr, false)) {
+		memset(&mgr->down_rep_recv, 0,
+		       sizeof(struct drm_dp_sideband_msg_rx));
+		return 0;
+	}
 
 	if (mgr->down_rep_recv.have_eomt) {
 		struct drm_dp_sideband_msg_tx *txmsg;
@@ -2141,36 +2311,66 @@
 static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
 {
 	int ret = 0;
-	drm_dp_get_one_sb_msg(mgr, true);
+
+	if (!drm_dp_get_one_sb_msg(mgr, true)) {
+		memset(&mgr->up_req_recv, 0,
+		       sizeof(struct drm_dp_sideband_msg_rx));
+		return 0;
+	}
 
 	if (mgr->up_req_recv.have_eomt) {
 		struct drm_dp_sideband_msg_req_body msg;
-		struct drm_dp_mst_branch *mstb;
+		struct drm_dp_mst_branch *mstb = NULL;
 		bool seqno;
-		mstb = drm_dp_get_mst_branch_device(mgr,
-						    mgr->up_req_recv.initial_hdr.lct,
-						    mgr->up_req_recv.initial_hdr.rad);
-		if (!mstb) {
-			DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
-			memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
-			return 0;
+
+		if (!mgr->up_req_recv.initial_hdr.broadcast) {
+			mstb = drm_dp_get_mst_branch_device(mgr,
+							    mgr->up_req_recv.initial_hdr.lct,
+							    mgr->up_req_recv.initial_hdr.rad);
+			if (!mstb) {
+				DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
+				memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+				return 0;
+			}
 		}
 
 		seqno = mgr->up_req_recv.initial_hdr.seqno;
 		drm_dp_sideband_parse_req(&mgr->up_req_recv, &msg);
 
 		if (msg.req_type == DP_CONNECTION_STATUS_NOTIFY) {
-			drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false);
+			drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
+
+			if (!mstb)
+				mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.conn_stat.guid);
+
+			if (!mstb) {
+				DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
+				memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+				return 0;
+			}
+
 			drm_dp_update_port(mstb, &msg.u.conn_stat);
+
 			DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type);
 			(*mgr->cbs->hotplug)(mgr);
 
 		} else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) {
-			drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false);
+			drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
+			if (!mstb)
+				mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.resource_stat.guid);
+
+			if (!mstb) {
+				DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
+				memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+				return 0;
+			}
+
 			DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn);
 		}
 
-		drm_dp_put_mst_branch_device(mstb);
+		if (mstb)
+			drm_dp_put_mst_branch_device(mstb);
+
 		memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
 	}
 	return ret;
@@ -2259,6 +2459,27 @@
 EXPORT_SYMBOL(drm_dp_mst_detect_port);
 
 /**
+ * drm_dp_mst_port_has_audio() - Check whether port has audio capability or not
+ * @mgr: manager for this port
+ * @port: unverified pointer to a port.
+ *
+ * This returns whether the port supports audio or not.
+ */
+bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr,
+					struct drm_dp_mst_port *port)
+{
+	bool ret = false;
+
+	port = drm_dp_get_validated_port_ref(mgr, port);
+	if (!port)
+		return ret;
+	ret = port->has_audio;
+	drm_dp_put_port(port);
+	return ret;
+}
+EXPORT_SYMBOL(drm_dp_mst_port_has_audio);
+
+/**
  * drm_dp_mst_get_edid() - get EDID for an MST port
  * @connector: toplevel connector to get EDID for
  * @mgr: manager for this port
@@ -2283,6 +2504,7 @@
 		edid = drm_get_edid(connector, &port->aux.ddc);
 		drm_mode_connector_set_tile_property(connector);
 	}
+	port->has_audio = drm_detect_monitor_audio(edid);
 	drm_dp_put_port(port);
 	return edid;
 }
@@ -2346,6 +2568,7 @@
 		DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn);
 		if (pbn == port->vcpi.pbn) {
 			*slots = port->vcpi.num_slots;
+			drm_dp_put_port(port);
 			return true;
 		}
 	}
@@ -2457,6 +2680,17 @@
 	return ret;
 }
 
+static int do_get_act_status(struct drm_dp_aux *aux)
+{
+	int ret;
+	u8 status;
+
+	ret = drm_dp_dpcd_readb(aux, DP_PAYLOAD_TABLE_UPDATE_STATUS, &status);
+	if (ret < 0)
+		return ret;
+
+	return status;
+}
 
 /**
  * drm_dp_check_act_status() - Check ACT handled status.
@@ -2466,33 +2700,29 @@
  */
 int drm_dp_check_act_status(struct drm_dp_mst_topology_mgr *mgr)
 {
-	u8 status;
-	int ret;
-	int count = 0;
-
-	do {
-		ret = drm_dp_dpcd_readb(mgr->aux, DP_PAYLOAD_TABLE_UPDATE_STATUS, &status);
-
-		if (ret < 0) {
-			DRM_DEBUG_KMS("failed to read payload table status %d\n", ret);
-			goto fail;
-		}
-
-		if (status & DP_PAYLOAD_ACT_HANDLED)
-			break;
-		count++;
-		udelay(100);
-
-	} while (count < 30);
+	/*
+	 * There doesn't seem to be any recommended retry count or timeout in
+	 * the MST specification. Since some hubs have been observed to take
+	 * over 1 second to update their payload allocations under certain
+	 * conditions, we use a rather large timeout value.
+	 */
+	const int timeout_ms = 3000;
+	int ret, status;
 
-	if (!(status & DP_PAYLOAD_ACT_HANDLED)) {
-		DRM_DEBUG_KMS("failed to get ACT bit %d after %d retries\n", status, count);
-		ret = -EINVAL;
-		goto fail;
+	ret = readx_poll_timeout(do_get_act_status, mgr->aux, status,
+				 status & DP_PAYLOAD_ACT_HANDLED || status < 0,
+				 200, timeout_ms * USEC_PER_MSEC);
+	if (ret < 0 && status >= 0) {
+		DRM_DEBUG_KMS("Failed to get ACT after %dms, last status: %02x\n",
+			      timeout_ms, status);
+		return -EINVAL;
+	} else if (status < 0) {
+		DRM_DEBUG_KMS("Failed to read payload table status: %d\n",
+			      status);
+		return status;
 	}
+
 	return 0;
-fail:
-	return ret;
 }
 EXPORT_SYMBOL(drm_dp_check_act_status);
 
@@ -2505,32 +2735,31 @@
  */
 int drm_dp_calc_pbn_mode(int clock, int bpp)
 {
-	fixed20_12 pix_bw;
-	fixed20_12 fbpp;
-	fixed20_12 result;
-	fixed20_12 margin, tmp;
-	u32 res;
-
-	pix_bw.full = dfixed_const(clock);
-	fbpp.full = dfixed_const(bpp);
-	tmp.full = dfixed_const(8);
-	fbpp.full = dfixed_div(fbpp, tmp);
-
-	result.full = dfixed_mul(pix_bw, fbpp);
-	margin.full = dfixed_const(54);
-	tmp.full = dfixed_const(64);
-	margin.full = dfixed_div(margin, tmp);
-	result.full = dfixed_div(result, margin);
-
-	margin.full = dfixed_const(1006);
-	tmp.full = dfixed_const(1000);
-	margin.full = dfixed_div(margin, tmp);
-	result.full = dfixed_mul(result, margin);
-
-	result.full = dfixed_div(result, tmp);
-	result.full = dfixed_ceil(result);
-	res = dfixed_trunc(result);
-	return res;
+	u64 kbps;
+	s64 peak_kbps;
+	u32 numerator;
+	u32 denominator;
+
+	kbps = clock * bpp;
+
+	/*
+	 * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
+	 * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on
+	 * common multiplier to render an integer PBN for all link rate/lane
+	 * counts combinations
+	 * calculate
+	 * peak_kbps *= (1006/1000)
+	 * peak_kbps *= (64/54)
+	 * peak_kbps *= 8    convert to bytes
+	 */
+
+	numerator = 64 * 1006;
+	denominator = 54 * 8 * 1000 * 1000;
+
+	kbps *= numerator;
+	peak_kbps = drm_fixp_from_fraction(kbps, denominator);
+
+	return drm_fixp2int_ceil(peak_kbps);
 }
 EXPORT_SYMBOL(drm_dp_calc_pbn_mode);
 
@@ -2538,11 +2767,23 @@
 {
 	int ret;
 	ret = drm_dp_calc_pbn_mode(154000, 30);
-	if (ret != 689)
+	if (ret != 689) {
+		DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
+				154000, 30, 689, ret);
 		return -EINVAL;
+	}
 	ret = drm_dp_calc_pbn_mode(234000, 30);
-	if (ret != 1047)
+	if (ret != 1047) {
+		DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
+				234000, 30, 1047, ret);
+		return -EINVAL;
+	}
+	ret = drm_dp_calc_pbn_mode(297000, 24);
+	if (ret != 1063) {
+		DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
+				297000, 24, 1063, ret);
 		return -EINVAL;
+	}
 	return 0;
 }
 
@@ -2566,7 +2807,7 @@
 
 	seq_printf(m, "%smst: %p, %d\n", prefix, mstb, mstb->num_ports);
 	list_for_each_entry(port, &mstb->ports, next) {
-		seq_printf(m, "%sport: %d: ddps: %d ldps: %d, %p, conn: %p\n", prefix, port->port_num, port->ddps, port->ldps, port, port->connector);
+		seq_printf(m, "%sport: %d: ddps: %d ldps: %d, sdp: %d/%d, %p, conn: %p\n", prefix, port->port_num, port->ddps, port->ldps, port->num_sdp_streams, port->num_sdp_stream_sinks, port, port->connector);
 		if (port->mstb)
 			drm_dp_mst_dump_mstb(m, port->mstb);
 	}
@@ -2683,6 +2924,13 @@
 	mutex_unlock(&mgr->qlock);
 }
 
+static void drm_dp_free_mst_port(struct kref *kref)
+{
+	struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref);
+	kref_put(&port->parent->kref, drm_dp_free_mst_branch_device);
+	kfree(port);
+}
+
 static void drm_dp_destroy_connector_work(struct work_struct *work)
 {
 	struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
@@ -2703,13 +2951,21 @@
 		list_del(&port->next);
 		mutex_unlock(&mgr->destroy_connector_lock);
 
+		kref_init(&port->kref);
+		INIT_LIST_HEAD(&port->next);
+
 		mgr->cbs->destroy_connector(mgr, port->connector);
 
 		drm_dp_port_teardown_pdt(port, port->pdt);
+		port->pdt = DP_PEER_DEVICE_NONE;
 
-		if (!port->input && port->vcpi.vcpi > 0)
+		if (!port->input && port->vcpi.vcpi > 0) {
+			drm_dp_mst_reset_vcpi_slots(mgr, port);
+			drm_dp_update_payload_part1(mgr);
 			drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
-		kfree(port);
+		}
+
+		kref_put(&port->kref, drm_dp_free_mst_port);
 		send_hotplug = true;
 	}
 	if (send_hotplug)
@@ -2736,7 +2992,6 @@
 	mutex_init(&mgr->qlock);
 	mutex_init(&mgr->payload_lock);
 	mutex_init(&mgr->destroy_connector_lock);
-	INIT_LIST_HEAD(&mgr->tx_msg_upq);
 	INIT_LIST_HEAD(&mgr->tx_msg_downq);
 	INIT_LIST_HEAD(&mgr->destroy_connector_list);
 	INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work);
@@ -2816,6 +3071,7 @@
 		msg.u.i2c_read.transactions[i].i2c_dev_id = msgs[i].addr;
 		msg.u.i2c_read.transactions[i].num_bytes = msgs[i].len;
 		msg.u.i2c_read.transactions[i].bytes = msgs[i].buf;
+		msg.u.i2c_read.transactions[i].no_stop_bit = !(msgs[i].flags & I2C_M_STOP);
 	}
 	msg.u.i2c_read.read_i2c_device_id = msgs[num - 1].addr;
 	msg.u.i2c_read.num_bytes_read = msgs[num - 1].len;
--- linux-4.4.0.orig/drivers/gpu/drm/drm_drv.c
+++ linux-4.4.0/drivers/gpu/drm/drm_drv.c
@@ -312,7 +312,7 @@
 	ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
 	if (ret) {
 		DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
-		return ret;
+		goto err_debugfs;
 	}
 
 	ret = device_add(minor->kdev);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_edid.c
+++ linux-4.4.0/drivers/gpu/drm/drm_edid.c
@@ -73,6 +73,10 @@
 #define EDID_QUIRK_FORCE_8BPC			(1 << 8)
 /* Force 12bpc */
 #define EDID_QUIRK_FORCE_12BPC			(1 << 9)
+/* Force 6bpc */
+#define EDID_QUIRK_FORCE_6BPC			(1 << 10)
+/* Force 10bpc */
+#define EDID_QUIRK_FORCE_10BPC			(1 << 11)
 
 struct detailed_mode_closure {
 	struct drm_connector *connector;
@@ -99,6 +103,12 @@
 	/* Unknown Acer */
 	{ "ACR", 2423, EDID_QUIRK_FIRST_DETAILED_PREFERRED },
 
+	/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
+	{ "AEO", 0, EDID_QUIRK_FORCE_6BPC },
+
+	/* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
+	{ "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC },
+
 	/* Belinea 10 15 55 */
 	{ "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
 	{ "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
@@ -112,6 +122,9 @@
 	{ "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 |
 	  EDID_QUIRK_DETAILED_IN_CM },
 
+	/* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */
+	{ "LGD", 764, EDID_QUIRK_FORCE_10BPC },
+
 	/* LG Philips LCD LP154W01-A5 */
 	{ "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE },
 	{ "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE },
@@ -137,8 +150,14 @@
 	/* Medion MD 30217 PG */
 	{ "MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75 },
 
+	/* Lenovo G50 */
+	{ "SDC", 18514, EDID_QUIRK_FORCE_6BPC },
+
 	/* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */
 	{ "SEC", 0xd033, EDID_QUIRK_FORCE_8BPC },
+
+	/* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/
+	{ "ETR", 13896, EDID_QUIRK_FORCE_8BPC },
 };
 
 /*
@@ -3203,8 +3222,7 @@
  * @edid: EDID to parse
  *
  * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The
- * Conn_Type, HDCP and Port_ID ELD fields are left for the graphics driver to
- * fill in.
+ * HDCP and Port_ID ELD fields are left for the graphics driver to fill in.
  */
 void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
 {
@@ -3277,6 +3295,12 @@
 	}
 	eld[5] |= sad_count << 4;
 
+	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+	    connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+		eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_DP;
+	else
+		eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_HDMI;
+
 	eld[DRM_ELD_BASELINE_ELD_LEN] =
 		DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4);
 
@@ -3820,9 +3844,15 @@
 
 	drm_add_display_info(edid, &connector->display_info, connector);
 
+	if (quirks & EDID_QUIRK_FORCE_6BPC)
+		connector->display_info.bpc = 6;
+
 	if (quirks & EDID_QUIRK_FORCE_8BPC)
 		connector->display_info.bpc = 8;
 
+	if (quirks & EDID_QUIRK_FORCE_10BPC)
+		connector->display_info.bpc = 10;
+
 	if (quirks & EDID_QUIRK_FORCE_12BPC)
 		connector->display_info.bpc = 12;
 
--- linux-4.4.0.orig/drivers/gpu/drm/drm_encoder_slave.c
+++ linux-4.4.0/drivers/gpu/drm/drm_encoder_slave.c
@@ -84,7 +84,7 @@
 
 	err = encoder_drv->encoder_init(client, dev, encoder);
 	if (err)
-		goto fail_unregister;
+		goto fail_module_put;
 
 	if (info->platform_data)
 		encoder->slave_funcs->set_config(&encoder->base,
@@ -92,9 +92,10 @@
 
 	return 0;
 
+fail_module_put:
+	module_put(module);
 fail_unregister:
 	i2c_unregister_device(client);
-	module_put(module);
 fail:
 	return err;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/drm_fb_cma_helper.c
+++ linux-4.4.0/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -348,9 +348,6 @@
 
 	}
 
-	/* disable all the possible outputs/crtcs before entering KMS mode */
-	drm_helper_disable_unused_functions(dev);
-
 	ret = drm_fb_helper_initial_config(helper, preferred_bpp);
 	if (ret < 0) {
 		dev_err(dev->dev, "Failed to set initial hw configuration.\n");
--- linux-4.4.0.orig/drivers/gpu/drm/drm_fb_helper.c
+++ linux-4.4.0/drivers/gpu/drm/drm_fb_helper.c
@@ -1109,9 +1109,14 @@
 	struct drm_framebuffer *fb = fb_helper->fb;
 	int depth;
 
-	if (var->pixclock != 0 || in_dbg_master())
+	if (in_dbg_master())
 		return -EINVAL;
 
+	if (var->pixclock != 0) {
+		DRM_DEBUG("fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n");
+		var->pixclock = 0;
+	}
+
 	/* Need to resize the fb object !!! */
 	if (var->bits_per_pixel > fb->bits_per_pixel ||
 	    var->xres > fb->width || var->yres > fb->height ||
@@ -1251,7 +1256,7 @@
 			goto fail;
 
 		plane = mode_set->crtc->primary;
-		plane_mask |= drm_plane_index(plane);
+		plane_mask |= (1 << drm_plane_index(plane));
 		plane->old_fb = plane->fb;
 	}
 
@@ -1899,7 +1904,6 @@
 			  int n, int width, int height)
 {
 	int c, o;
-	struct drm_device *dev = fb_helper->dev;
 	struct drm_connector *connector;
 	const struct drm_connector_helper_funcs *connector_funcs;
 	struct drm_encoder *encoder;
@@ -1918,7 +1922,7 @@
 	if (modes[n] == NULL)
 		return best_score;
 
-	crtcs = kzalloc(dev->mode_config.num_connector *
+	crtcs = kzalloc(fb_helper->connector_count *
 			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
 	if (!crtcs)
 		return best_score;
@@ -1964,7 +1968,7 @@
 		if (score > best_score) {
 			best_score = score;
 			memcpy(best_crtcs, crtcs,
-			       dev->mode_config.num_connector *
+			       fb_helper->connector_count *
 			       sizeof(struct drm_fb_helper_crtc *));
 		}
 	}
@@ -2175,9 +2179,9 @@
  * but the module doesn't depend on any fb console symbols.  At least
  * attempt to load fbcon to avoid leaving the system without a usable console.
  */
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
-static int __init drm_fb_helper_modinit(void)
+int __init drm_fb_helper_modinit(void)
 {
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
 	const char *name = "fbcon";
 	struct module *fbcon;
 
@@ -2187,8 +2191,7 @@
 
 	if (!fbcon)
 		request_module_nowait(name);
+#endif
 	return 0;
 }
-
-module_init(drm_fb_helper_modinit);
-#endif
+EXPORT_SYMBOL(drm_fb_helper_modinit);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_fops.c
+++ linux-4.4.0/drivers/gpu/drm/drm_fops.c
@@ -209,6 +209,7 @@
 		return -ENOMEM;
 
 	filp->private_data = priv;
+	filp->f_mode |= FMODE_UNSIGNED_OFFSET;
 	priv->filp = filp;
 	priv->uid = current_euid();
 	priv->pid = get_pid(task_pid(current));
--- linux-4.4.0.orig/drivers/gpu/drm/drm_gem.c
+++ linux-4.4.0/drivers/gpu/drm/drm_gem.c
@@ -338,27 +338,32 @@
 	spin_unlock(&file_priv->table_lock);
 	idr_preload_end();
 	mutex_unlock(&dev->object_name_lock);
-	if (ret < 0) {
-		drm_gem_object_handle_unreference_unlocked(obj);
-		return ret;
-	}
+	if (ret < 0)
+		goto err_unref;
+
 	*handlep = ret;
 
 	ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp);
-	if (ret) {
-		drm_gem_handle_delete(file_priv, *handlep);
-		return ret;
-	}
+	if (ret)
+		goto err_remove;
 
 	if (dev->driver->gem_open_object) {
 		ret = dev->driver->gem_open_object(obj, file_priv);
-		if (ret) {
-			drm_gem_handle_delete(file_priv, *handlep);
-			return ret;
-		}
+		if (ret)
+			goto err_revoke;
 	}
 
 	return 0;
+
+err_revoke:
+	drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
+err_remove:
+	spin_lock(&file_priv->table_lock);
+	idr_remove(&file_priv->object_idr, *handlep);
+	spin_unlock(&file_priv->table_lock);
+err_unref:
+	drm_gem_object_handle_unreference_unlocked(obj);
+	return ret;
 }
 
 /**
@@ -647,9 +652,6 @@
  * @file_priv: drm file-private structure
  *
  * Open an object using the global name, returning a handle and the size.
- *
- * This handle (of course) holds a reference to the object, so the object
- * will not go away until the handle is deleted.
  */
 int
 drm_gem_open_ioctl(struct drm_device *dev, void *data,
@@ -674,14 +676,15 @@
 
 	/* drm_gem_handle_create_tail unlocks dev->object_name_lock. */
 	ret = drm_gem_handle_create_tail(file_priv, obj, &handle);
-	drm_gem_object_unreference_unlocked(obj);
 	if (ret)
-		return ret;
+		goto err;
 
 	args->handle = handle;
 	args->size = obj->size;
 
-	return 0;
+err:
+	drm_gem_object_unreference_unlocked(obj);
+	return ret;
 }
 
 /**
@@ -710,13 +713,13 @@
 	struct drm_gem_object *obj = ptr;
 	struct drm_device *dev = obj->dev;
 
+	if (dev->driver->gem_close_object)
+		dev->driver->gem_close_object(obj, file_priv);
+
 	if (drm_core_check_feature(dev, DRIVER_PRIME))
 		drm_gem_remove_prime_handles(obj, file_priv);
 	drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
 
-	if (dev->driver->gem_close_object)
-		dev->driver->gem_close_object(obj, file_priv);
-
 	drm_gem_object_handle_unreference_unlocked(obj);
 
 	return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/drm_ioc32.c
+++ linux-4.4.0/drivers/gpu/drm/drm_ioc32.c
@@ -1015,6 +1015,7 @@
 	return 0;
 }
 
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
 typedef struct drm_mode_fb_cmd232 {
 	u32 fb_id;
 	u32 width;
@@ -1071,6 +1072,7 @@
 
 	return 0;
 }
+#endif
 
 static drm_ioctl_compat_t *drm_compat_ioctls[] = {
 	[DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
@@ -1104,7 +1106,9 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW32)] = compat_drm_update_draw,
 #endif
 	[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
 	[DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB232)] = compat_drm_mode_addfb2,
+#endif
 };
 
 /**
--- linux-4.4.0.orig/drivers/gpu/drm/drm_ioctl.c
+++ linux-4.4.0/drivers/gpu/drm/drm_ioctl.c
@@ -36,6 +36,7 @@
 
 #include <linux/pci.h>
 #include <linux/export.h>
+#include <linux/nospec.h>
 
 static int drm_version(struct drm_device *dev, void *data,
 		       struct drm_file *file_priv);
@@ -702,13 +703,17 @@
 
 	if (is_driver_ioctl) {
 		/* driver ioctl */
-		if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
+		unsigned int index = nr - DRM_COMMAND_BASE;
+
+		if (index >= dev->driver->num_ioctls)
 			goto err_i1;
-		ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
+		index = array_index_nospec(index, dev->driver->num_ioctls);
+		ioctl = &dev->driver->ioctls[index];
 	} else {
 		/* core ioctl */
 		if (nr >= DRM_CORE_IOCTL_COUNT)
 			goto err_i1;
+		nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT);
 		ioctl = &drm_ioctls[nr];
 	}
 
@@ -810,6 +815,7 @@
 
 	if (nr >= DRM_CORE_IOCTL_COUNT)
 		return false;
+	nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT);
 
 	*flags = drm_ioctls[nr].flags;
 	return true;
--- linux-4.4.0.orig/drivers/gpu/drm/drm_irq.c
+++ linux-4.4.0/drivers/gpu/drm/drm_irq.c
@@ -221,6 +221,64 @@
 		diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0;
 	}
 
+	/*
+	 * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset
+	 * interval? If so then vblank irqs keep running and it will likely
+	 * happen that the hardware vblank counter is not trustworthy as it
+	 * might reset at some point in that interval and vblank timestamps
+	 * are not trustworthy either in that interval. Iow. this can result
+	 * in a bogus diff >> 1 which must be avoided as it would cause
+	 * random large forward jumps of the software vblank counter.
+	 */
+	if (diff > 1 && (vblank->inmodeset & 0x2)) {
+		DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u"
+			      " due to pre-modeset.\n", pipe, diff);
+		diff = 1;
+	}
+
+	/*
+	 * FIMXE: Need to replace this hack with proper seqlocks.
+	 *
+	 * Restrict the bump of the software vblank counter to a safe maximum
+	 * value of +1 whenever there is the possibility that concurrent readers
+	 * of vblank timestamps could be active at the moment, as the current
+	 * implementation of the timestamp caching and updating is not safe
+	 * against concurrent readers for calls to store_vblank() with a bump
+	 * of anything but +1. A bump != 1 would very likely return corrupted
+	 * timestamps to userspace, because the same slot in the cache could
+	 * be concurrently written by store_vblank() and read by one of those
+	 * readers without the read-retry logic detecting the collision.
+	 *
+	 * Concurrent readers can exist when we are called from the
+	 * drm_vblank_off() or drm_vblank_on() functions and other non-vblank-
+	 * irq callers. However, all those calls to us are happening with the
+	 * vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount
+	 * can't increase while we are executing. Therefore a zero refcount at
+	 * this point is safe for arbitrary counter bumps if we are called
+	 * outside vblank irq, a non-zero count is not 100% safe. Unfortunately
+	 * we must also accept a refcount of 1, as whenever we are called from
+	 * drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and
+	 * we must let that one pass through in order to not lose vblank counts
+	 * during vblank irq off - which would completely defeat the whole
+	 * point of this routine.
+	 *
+	 * Whenever we are called from vblank irq, we have to assume concurrent
+	 * readers exist or can show up any time during our execution, even if
+	 * the refcount is currently zero, as vblank irqs are usually only
+	 * enabled due to the presence of readers, and because when we are called
+	 * from vblank irq we can't hold the vbl_lock to protect us from sudden
+	 * bumps in vblank refcount. Therefore also restrict bumps to +1 when
+	 * called from vblank irq.
+	 */
+	if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 ||
+	    (flags & DRM_CALLED_FROM_VBLIRQ))) {
+		DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u "
+			      "refcount %u, vblirq %u\n", pipe, diff,
+			      atomic_read(&vblank->refcount),
+			      (flags & DRM_CALLED_FROM_VBLIRQ) != 0);
+		diff = 1;
+	}
+
 	DRM_DEBUG_VBL("updating vblank count on crtc %u:"
 		      " current=%u, diff=%u, hw=%u hw_last=%u\n",
 		      pipe, vblank->count, diff, cur_vblank, vblank->last);
@@ -1213,9 +1271,9 @@
 	if (atomic_dec_and_test(&vblank->refcount)) {
 		if (drm_vblank_offdelay == 0)
 			return;
-		else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0)
+		else if (drm_vblank_offdelay < 0)
 			vblank_disable_fn((unsigned long)vblank);
-		else
+		else if (!dev->vblank_disable_immediate)
 			mod_timer(&vblank->disable_timer,
 				  jiffies + ((drm_vblank_offdelay * HZ)/1000));
 	}
@@ -1313,7 +1371,13 @@
 	spin_lock_irqsave(&dev->event_lock, irqflags);
 
 	spin_lock(&dev->vbl_lock);
-	vblank_disable_and_save(dev, pipe);
+	DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
+		      pipe, vblank->enabled, vblank->inmodeset);
+
+	/* Avoid redundant vblank disables without previous drm_vblank_on(). */
+	if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset)
+		vblank_disable_and_save(dev, pipe);
+
 	wake_up(&vblank->queue);
 
 	/*
@@ -1415,6 +1479,9 @@
 		return;
 
 	spin_lock_irqsave(&dev->vbl_lock, irqflags);
+	DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
+		      pipe, vblank->enabled, vblank->inmodeset);
+
 	/* Drop our private "prevent drm_vblank_get" refcount */
 	if (vblank->inmodeset) {
 		atomic_dec(&vblank->refcount);
@@ -1427,8 +1494,7 @@
 	 * re-enable interrupts if there are users left, or the
 	 * user wishes vblank interrupts to be enabled all the time.
 	 */
-	if (atomic_read(&vblank->refcount) != 0 ||
-	    (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
+	if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0)
 		WARN_ON(drm_vblank_enable(dev, pipe));
 	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
@@ -1523,6 +1589,7 @@
 	if (vblank->inmodeset) {
 		spin_lock_irqsave(&dev->vbl_lock, irqflags);
 		dev->vblank_disable_allowed = true;
+		drm_reset_vblank_timestamp(dev, pipe);
 		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
 		if (vblank->inmodeset & 0x2)
@@ -1835,6 +1902,16 @@
 	wake_up(&vblank->queue);
 	drm_handle_vblank_events(dev, pipe);
 
+	/* With instant-off, we defer disabling the interrupt until after
+	 * we finish processing the following vblank. The disable has to
+	 * be last (after drm_handle_vblank_events) so that the timestamp
+	 * is always accurate.
+	 */
+	if (dev->vblank_disable_immediate &&
+	    drm_vblank_offdelay > 0 &&
+	    !atomic_read(&vblank->refcount))
+		vblank_disable_fn((unsigned long)vblank);
+
 	spin_unlock_irqrestore(&dev->event_lock, irqflags);
 
 	return true;
--- linux-4.4.0.orig/drivers/gpu/drm/drm_kms_helper_common.c
+++ linux-4.4.0/drivers/gpu/drm/drm_kms_helper_common.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_dp_aux_dev.h>
+
+MODULE_AUTHOR("David Airlie, Jesse Barnes");
+MODULE_DESCRIPTION("DRM KMS helper");
+MODULE_LICENSE("GPL and additional rights");
+
+static int __init drm_kms_helper_init(void)
+{
+	int ret;
+
+	/* Call init functions from specific kms helpers here */
+	ret = drm_fb_helper_modinit();
+	if (ret < 0)
+		goto out;
+
+	ret = drm_dp_aux_dev_init();
+	if (ret < 0)
+		goto out;
+
+out:
+	return ret;
+}
+
+static void __exit drm_kms_helper_exit(void)
+{
+	/* Call exit functions from specific kms helpers here */
+	drm_dp_aux_dev_exit();
+}
+
+module_init(drm_kms_helper_init);
+module_exit(drm_kms_helper_exit);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_mm.c
+++ linux-4.4.0/drivers/gpu/drm/drm_mm.c
@@ -262,14 +262,12 @@
 
 	BUG_ON(!hole_node->hole_follows || node->allocated);
 
-	if (adj_start < start)
-		adj_start = start;
-	if (adj_end > end)
-		adj_end = end;
-
 	if (mm->color_adjust)
 		mm->color_adjust(hole_node, color, &adj_start, &adj_end);
 
+	adj_start = max(adj_start, start);
+	adj_end = min(adj_end, end);
+
 	if (flags & DRM_MM_CREATE_TOP)
 		adj_start = adj_end - size;
 
@@ -475,17 +473,15 @@
 			       flags & DRM_MM_SEARCH_BELOW) {
 		u64 hole_size = adj_end - adj_start;
 
-		if (adj_start < start)
-			adj_start = start;
-		if (adj_end > end)
-			adj_end = end;
-
 		if (mm->color_adjust) {
 			mm->color_adjust(entry, color, &adj_start, &adj_end);
 			if (adj_end <= adj_start)
 				continue;
 		}
 
+		adj_start = max(adj_start, start);
+		adj_end = min(adj_end, end);
+
 		if (!check_free_hole(adj_start, adj_end, size, alignment))
 			continue;
 
--- linux-4.4.0.orig/drivers/gpu/drm/drm_modes.c
+++ linux-4.4.0/drivers/gpu/drm/drm_modes.c
@@ -722,7 +722,7 @@
 	if (mode->hsync)
 		return mode->hsync;
 
-	if (mode->htotal < 0)
+	if (mode->htotal <= 0)
 		return 0;
 
 	calc_val = (mode->clock * 1000) / mode->htotal; /* hsync in Hz */
@@ -1401,6 +1401,13 @@
 		return NULL;
 
 	mode->type |= DRM_MODE_TYPE_USERDEF;
+	/* fix up 1368x768: GFT/CVT can't express 1366 width due to alignment */
+	if (cmd->xres == 1366 && mode->hdisplay == 1368) {
+		mode->hdisplay = 1366;
+		mode->hsync_start--;
+		mode->hsync_end--;
+		drm_mode_set_name(mode);
+	}
 	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
 	return mode;
 }
@@ -1487,6 +1494,8 @@
 	if (out->status != MODE_OK)
 		goto out;
 
+	drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
+
 	ret = 0;
 
 out:
--- linux-4.4.0.orig/drivers/gpu/drm/drm_modeset_lock.c
+++ linux-4.4.0/drivers/gpu/drm/drm_modeset_lock.c
@@ -57,11 +57,18 @@
 
 /**
  * drm_modeset_lock_all - take all modeset locks
- * @dev: drm device
+ * @dev: DRM device
  *
  * This function takes all modeset locks, suitable where a more fine-grained
- * scheme isn't (yet) implemented. Locks must be dropped with
- * drm_modeset_unlock_all.
+ * scheme isn't (yet) implemented. Locks must be dropped by calling the
+ * drm_modeset_unlock_all() function.
+ *
+ * This function is deprecated. It allocates a lock acquisition context and
+ * stores it in the DRM device's ->mode_config. This facilitate conversion of
+ * existing code because it removes the need to manually deal with the
+ * acquisition context, but it is also brittle because the context is global
+ * and care must be taken not to nest calls. New code should use the
+ * drm_modeset_lock_all_ctx() function and pass in the context explicitly.
  */
 void drm_modeset_lock_all(struct drm_device *dev)
 {
@@ -69,7 +76,7 @@
 	struct drm_modeset_acquire_ctx *ctx;
 	int ret;
 
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL);
 	if (WARN_ON(!ctx))
 		return;
 
@@ -78,39 +85,43 @@
 	drm_modeset_acquire_init(ctx, 0);
 
 retry:
-	ret = drm_modeset_lock(&config->connection_mutex, ctx);
-	if (ret)
-		goto fail;
-	ret = drm_modeset_lock_all_crtcs(dev, ctx);
-	if (ret)
-		goto fail;
+	ret = drm_modeset_lock_all_ctx(dev, ctx);
+	if (ret < 0) {
+		if (ret == -EDEADLK) {
+			drm_modeset_backoff(ctx);
+			goto retry;
+		}
+
+		drm_modeset_acquire_fini(ctx);
+		kfree(ctx);
+		return;
+	}
 
 	WARN_ON(config->acquire_ctx);
 
-	/* now we hold the locks, so now that it is safe, stash the
-	 * ctx for drm_modeset_unlock_all():
+	/*
+	 * We hold the locks now, so it is safe to stash the acquisition
+	 * context for drm_modeset_unlock_all().
 	 */
 	config->acquire_ctx = ctx;
 
 	drm_warn_on_modeset_not_all_locked(dev);
-
-	return;
-
-fail:
-	if (ret == -EDEADLK) {
-		drm_modeset_backoff(ctx);
-		goto retry;
-	}
-
-	kfree(ctx);
 }
 EXPORT_SYMBOL(drm_modeset_lock_all);
 
 /**
  * drm_modeset_unlock_all - drop all modeset locks
- * @dev: device
+ * @dev: DRM device
  *
- * This function drop all modeset locks taken by drm_modeset_lock_all.
+ * This function drops all modeset locks taken by a previous call to the
+ * drm_modeset_lock_all() function.
+ *
+ * This function is deprecated. It uses the lock acquisition context stored
+ * in the DRM device's ->mode_config. This facilitates conversion of existing
+ * code because it removes the need to manually deal with the acquisition
+ * context, but it is also brittle because the context is global and care must
+ * be taken not to nest calls. New code should pass the acquisition context
+ * directly to the drm_modeset_drop_locks() function.
  */
 void drm_modeset_unlock_all(struct drm_device *dev)
 {
@@ -431,14 +442,34 @@
 }
 EXPORT_SYMBOL(drm_modeset_unlock);
 
-/* In some legacy codepaths it's convenient to just grab all the crtc and plane
- * related locks. */
-int drm_modeset_lock_all_crtcs(struct drm_device *dev,
-		struct drm_modeset_acquire_ctx *ctx)
+/**
+ * drm_modeset_lock_all_ctx - take all modeset locks
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * This function takes all modeset locks, suitable where a more fine-grained
+ * scheme isn't (yet) implemented.
+ *
+ * Unlike drm_modeset_lock_all(), it doesn't take the dev->mode_config.mutex
+ * since that lock isn't required for modeset state changes. Callers which
+ * need to grab that lock too need to do so outside of the acquire context
+ * @ctx.
+ *
+ * Locks acquired with this function should be released by calling the
+ * drm_modeset_drop_locks() function on @ctx.
+ *
+ * Returns: 0 on success or a negative error-code on failure.
+ */
+int drm_modeset_lock_all_ctx(struct drm_device *dev,
+			     struct drm_modeset_acquire_ctx *ctx)
 {
 	struct drm_crtc *crtc;
 	struct drm_plane *plane;
-	int ret = 0;
+	int ret;
+
+	ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+	if (ret)
+		return ret;
 
 	drm_for_each_crtc(crtc, dev) {
 		ret = drm_modeset_lock(&crtc->mutex, ctx);
@@ -454,4 +485,4 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(drm_modeset_lock_all_crtcs);
+EXPORT_SYMBOL(drm_modeset_lock_all_ctx);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_pci.c
+++ linux-4.4.0/drivers/gpu/drm/drm_pci.c
@@ -410,6 +410,26 @@
 }
 EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask);
 
+int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw)
+{
+	struct pci_dev *root;
+	u32 lnkcap;
+
+	*mlw = 0;
+	if (!dev->pdev)
+		return -EINVAL;
+
+	root = dev->pdev->bus->self;
+
+	pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap);
+
+	*mlw = (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4;
+
+	DRM_INFO("probing mlw for device %x:%x = %x\n", root->vendor, root->device, lnkcap);
+	return 0;
+}
+EXPORT_SYMBOL(drm_pcie_get_max_link_width);
+
 #else
 
 int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
--- linux-4.4.0.orig/drivers/gpu/drm/drm_prime.c
+++ linux-4.4.0/drivers/gpu/drm/drm_prime.c
@@ -339,14 +339,17 @@
  * using the PRIME helpers.
  */
 struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
-				     struct drm_gem_object *obj, int flags)
+				     struct drm_gem_object *obj,
+				     int flags)
 {
-	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-
-	exp_info.ops = &drm_gem_prime_dmabuf_ops;
-	exp_info.size = obj->size;
-	exp_info.flags = flags;
-	exp_info.priv = obj;
+	struct dma_buf_export_info exp_info = {
+		.exp_name = KBUILD_MODNAME, /* white lie for debug */
+		.owner = dev->driver->fops->owner,
+		.ops = &drm_gem_prime_dmabuf_ops,
+		.size = obj->size,
+		.flags = flags,
+		.priv = obj,
+	};
 
 	if (dev->driver->gem_prime_res_obj)
 		exp_info.resv = dev->driver->gem_prime_res_obj(obj);
--- linux-4.4.0.orig/drivers/gpu/drm/drm_probe_helper.c
+++ linux-4.4.0/drivers/gpu/drm/drm_probe_helper.c
@@ -338,6 +338,9 @@
 	enum drm_connector_status old_status;
 	bool repoll = false, changed;
 
+	if (!dev->mode_config.poll_enabled)
+		return;
+
 	/* Pick up any changes detected by the probe functions. */
 	changed = dev->mode_config.delayed_event;
 	dev->mode_config.delayed_event = false;
@@ -412,6 +415,26 @@
 }
 
 /**
+ * drm_kms_helper_is_poll_worker - is %current task an output poll worker?
+ *
+ * Determine if %current task is an output poll worker.  This can be used
+ * to select distinct code paths for output polling versus other contexts.
+ *
+ * One use case is to avoid a deadlock between the output poll worker and
+ * the autosuspend worker wherein the latter waits for polling to finish
+ * upon calling drm_kms_helper_poll_disable(), while the former waits for
+ * runtime suspend to finish upon calling pm_runtime_get_sync() in a
+ * connector ->detect hook.
+ */
+bool drm_kms_helper_is_poll_worker(void)
+{
+	struct work_struct *work = current_work();
+
+	return work && work->func == output_poll_execute;
+}
+EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);
+
+/**
  * drm_kms_helper_poll_disable - disable output polling
  * @dev: drm_device
  *
@@ -481,7 +504,11 @@
  */
 void drm_kms_helper_poll_fini(struct drm_device *dev)
 {
-	drm_kms_helper_poll_disable(dev);
+	if (!dev->mode_config.poll_enabled)
+		return;
+
+	dev->mode_config.poll_enabled = false;
+	cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_fini);
 
--- linux-4.4.0.orig/drivers/gpu/drm/drm_rect.c
+++ linux-4.4.0/drivers/gpu/drm/drm_rect.c
@@ -275,22 +275,23 @@
 
 /**
  * drm_rect_debug_print - print the rectangle information
+ * @prefix: prefix string
  * @r: rectangle to print
  * @fixed_point: rectangle is in 16.16 fixed point format
  */
-void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point)
+void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point)
 {
 	int w = drm_rect_width(r);
 	int h = drm_rect_height(r);
 
 	if (fixed_point)
-		DRM_DEBUG_KMS("%d.%06ux%d.%06u%+d.%06u%+d.%06u\n",
+		DRM_DEBUG_KMS("%s%d.%06ux%d.%06u%+d.%06u%+d.%06u\n", prefix,
 			      w >> 16, ((w & 0xffff) * 15625) >> 10,
 			      h >> 16, ((h & 0xffff) * 15625) >> 10,
 			      r->x1 >> 16, ((r->x1 & 0xffff) * 15625) >> 10,
 			      r->y1 >> 16, ((r->y1 & 0xffff) * 15625) >> 10);
 	else
-		DRM_DEBUG_KMS("%dx%d%+d%+d\n", w, h, r->x1, r->y1);
+		DRM_DEBUG_KMS("%s%dx%d%+d%+d\n", prefix, w, h, r->x1, r->y1);
 }
 EXPORT_SYMBOL(drm_rect_debug_print);
 
--- linux-4.4.0.orig/drivers/gpu/drm/drm_sysfs.c
+++ linux-4.4.0/drivers/gpu/drm/drm_sysfs.c
@@ -252,7 +252,7 @@
 			 struct bin_attribute *attr, char *buf, loff_t off,
 			 size_t count)
 {
-	struct device *connector_dev = container_of(kobj, struct device, kobj);
+	struct device *connector_dev = kobj_to_dev(kobj);
 	struct drm_connector *connector = to_drm_connector(connector_dev);
 	unsigned char *edid;
 	size_t size;
--- linux-4.4.0.orig/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ linux-4.4.0/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -180,6 +180,8 @@
 
 	/* enable output and display signal */
 	decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0);
+
+	decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
 }
 
 static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
@@ -188,7 +190,7 @@
 	unsigned long val;
 
 	val = readl(ctx->addr + DECON_WINCONx(win));
-	val &= ~WINCONx_BPPMODE_MASK;
+	val &= WINCONx_ENWIN_F;
 
 	switch (fb->pixel_format) {
 	case DRM_FORMAT_XRGB1555:
@@ -276,8 +278,8 @@
 		COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1);
 	writel(val, ctx->addr + DECON_VIDOSDxB(win));
 
-	val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
-		VIDOSD_Wx_ALPHA_B_F(0x0);
+	val = VIDOSD_Wx_ALPHA_R_F(0xff) | VIDOSD_Wx_ALPHA_G_F(0xff) |
+		VIDOSD_Wx_ALPHA_B_F(0xff);
 	writel(val, ctx->addr + DECON_VIDOSDxC(win));
 
 	val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
--- linux-4.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ linux-4.4.0/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -101,7 +101,7 @@
 	return 0;
 
 err:
-	list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
+	list_for_each_entry_continue_reverse(subdrv, &exynos_drm_subdrv_list, list) {
 		if (subdrv->close)
 			subdrv->close(dev, subdrv->dev, file);
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ linux-4.4.0/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1899,8 +1899,9 @@
 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies),
 				      dsi->supplies);
 	if (ret) {
-		dev_info(dev, "failed to get regulators: %d\n", ret);
-		return -EPROBE_DEFER;
+		if (ret != -EPROBE_DEFER)
+			dev_info(dev, "failed to get regulators: %d\n", ret);
+		return ret;
 	}
 
 	dsi->clks = devm_kzalloc(dev,
@@ -1913,9 +1914,10 @@
 		dsi->clks[i] = devm_clk_get(dev, clk_names[i]);
 		if (IS_ERR(dsi->clks[i])) {
 			if (strcmp(clk_names[i], "sclk_mipi") == 0) {
-				strcpy(clk_names[i], OLD_SCLK_MIPI_CLK_NAME);
-				i--;
-				continue;
+				dsi->clks[i] = devm_clk_get(dev,
+							OLD_SCLK_MIPI_CLK_NAME);
+				if (!IS_ERR(dsi->clks[i]))
+					continue;
 			}
 
 			dev_info(dev, "failed to get the clock: %s\n",
--- linux-4.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ linux-4.4.0/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -471,7 +471,8 @@
 		goto err_free;
 	}
 
-	ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec);
+	ret = get_vaddr_frames(start, npages, FOLL_FORCE | FOLL_WRITE,
+		g2d_userptr->vec);
 	if (ret != npages) {
 		DRM_ERROR("failed to get user pages from userptr.\n");
 		if (ret < 0)
--- linux-4.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ linux-4.4.0/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -245,6 +245,15 @@
 	if (IS_ERR(exynos_gem))
 		return exynos_gem;
 
+	if (!is_drm_iommu_supported(dev) && (flags & EXYNOS_BO_NONCONTIG)) {
+		/*
+		 * when no IOMMU is available, all allocated buffers are
+		 * contiguous anyway, so drop EXYNOS_BO_NONCONTIG flag
+		 */
+		flags &= ~EXYNOS_BO_NONCONTIG;
+		DRM_WARN("Non-contiguous allocation is not supported without IOMMU, falling back to contiguous buffer\n");
+	}
+
 	/* set memory type and cache attribute from user side. */
 	exynos_gem->flags = flags;
 
--- linux-4.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ linux-4.4.0/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -526,21 +526,25 @@
 			GSC_IN_CHROMA_ORDER_CRCB);
 		break;
 	case DRM_FORMAT_NV21:
+		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P);
+		break;
 	case DRM_FORMAT_NV61:
-		cfg |= (GSC_IN_CHROMA_ORDER_CRCB |
-			GSC_IN_YUV420_2P);
+		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P);
 		break;
 	case DRM_FORMAT_YUV422:
 		cfg |= GSC_IN_YUV422_3P;
 		break;
 	case DRM_FORMAT_YUV420:
+		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P);
+		break;
 	case DRM_FORMAT_YVU420:
-		cfg |= GSC_IN_YUV420_3P;
+		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P);
 		break;
 	case DRM_FORMAT_NV12:
+		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P);
+		break;
 	case DRM_FORMAT_NV16:
-		cfg |= (GSC_IN_CHROMA_ORDER_CBCR |
-			GSC_IN_YUV420_2P);
+		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P);
 		break;
 	default:
 		dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
@@ -800,18 +804,25 @@
 			GSC_OUT_CHROMA_ORDER_CRCB);
 		break;
 	case DRM_FORMAT_NV21:
-	case DRM_FORMAT_NV61:
 		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P);
 		break;
+	case DRM_FORMAT_NV61:
+		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P);
+		break;
 	case DRM_FORMAT_YUV422:
+		cfg |= GSC_OUT_YUV422_3P;
+		break;
 	case DRM_FORMAT_YUV420:
+		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P);
+		break;
 	case DRM_FORMAT_YVU420:
-		cfg |= GSC_OUT_YUV420_3P;
+		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P);
 		break;
 	case DRM_FORMAT_NV12:
+		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P);
+		break;
 	case DRM_FORMAT_NV16:
-		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR |
-			GSC_OUT_YUV420_2P);
+		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P);
 		break;
 	default:
 		dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
--- linux-4.4.0.orig/drivers/gpu/drm/exynos/regs-fimc.h
+++ linux-4.4.0/drivers/gpu/drm/exynos/regs-fimc.h
@@ -569,7 +569,7 @@
 #define EXYNOS_CIIMGEFF_FIN_EMBOSSING		(4 << 26)
 #define EXYNOS_CIIMGEFF_FIN_SILHOUETTE		(5 << 26)
 #define EXYNOS_CIIMGEFF_FIN_MASK			(7 << 26)
-#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK		((0xff < 13) | (0xff < 0))
+#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK		((0xff << 13) | (0xff << 0))
 
 /* Real input DMA size register */
 #define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE	(1 << 31)
--- linux-4.4.0.orig/drivers/gpu/drm/exynos/regs-gsc.h
+++ linux-4.4.0/drivers/gpu/drm/exynos/regs-gsc.h
@@ -138,6 +138,7 @@
 #define GSC_OUT_YUV420_3P		(3 << 4)
 #define GSC_OUT_YUV422_1P		(4 << 4)
 #define GSC_OUT_YUV422_2P		(5 << 4)
+#define GSC_OUT_YUV422_3P		(6 << 4)
 #define GSC_OUT_YUV444			(7 << 4)
 #define GSC_OUT_TILE_TYPE_MASK		(1 << 2)
 #define GSC_OUT_TILE_C_16x8		(0 << 2)
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -415,6 +415,8 @@
 	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
 	struct gma_clock_t clock;
 
+	memset(&clock, 0, sizeof(clock));
+
 	switch (refclk) {
 	case 27000:
 		if (target < 200000) {
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -220,7 +220,7 @@
  * FIXME: This is the old dp aux helper, gma500 is the last driver that needs to
  * be ported over to the new helper code in drm_dp_helper.c like i915 or radeon.
  */
-static int __deprecated
+static int
 i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
 {
 	int error;
@@ -2120,12 +2120,12 @@
 					       intel_dp->dpcd,
 					       sizeof(intel_dp->dpcd));
 		cdv_intel_edp_panel_vdd_off(gma_encoder);
-		if (ret == 0) {
+		if (ret <= 0) {
 			/* if this fails, presume the device is a ghost */
 			DRM_INFO("failed to retrieve link info, disabling eDP\n");
 			cdv_intel_dp_encoder_destroy(encoder);
 			cdv_intel_dp_destroy(connector);
-			goto err_priv;
+			goto err_connector;
 		} else {
         		DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n",
 				intel_dp->dpcd[0], intel_dp->dpcd[1], 
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -426,6 +426,9 @@
 	if (mode_dev->panel_fixed_mode != NULL) {
 		struct drm_display_mode *mode =
 		    drm_mode_duplicate(dev, mode_dev->panel_fixed_mode);
+		if (!mode)
+			return 0;
+
 		drm_mode_probed_add(connector, mode);
 		return 1;
 	}
@@ -620,6 +623,9 @@
 	int pipe;
 	u8 pin;
 
+	if (!dev_priv->lvds_enabled_in_vbt)
+		return;
+
 	pin = GMBUS_PORT_PANEL;
 	if (!lvds_is_present_in_vbt(dev, &pin)) {
 		DRM_DEBUG_KMS("LVDS is not present in VBT\n");
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/framebuffer.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/framebuffer.c
@@ -533,6 +533,7 @@
 		container_of(helper, struct psb_fbdev, psb_fb_helper);
 	struct drm_device *dev = psb_fbdev->psb_fb_helper.dev;
 	struct drm_psb_private *dev_priv = dev->dev_private;
+	unsigned int fb_size;
 	int bytespp;
 
 	bytespp = sizes->surface_bpp / 8;
@@ -542,8 +543,11 @@
 	/* If the mode will not fit in 32bit then switch to 16bit to get
 	   a console on full resolution. The X mode setting server will
 	   allocate its own 32bit GEM framebuffer */
-	if (ALIGN(sizes->fb_width * bytespp, 64) * sizes->fb_height >
-	                dev_priv->vram_stolen_size) {
+	fb_size = ALIGN(sizes->surface_width * bytespp, 64) *
+		  sizes->surface_height;
+	fb_size = ALIGN(fb_size, PAGE_SIZE);
+
+	if (fb_size > dev_priv->vram_stolen_size) {
                 sizes->surface_bpp = 16;
                 sizes->surface_depth = 16;
         }
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/gem.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/gem.c
@@ -130,7 +130,7 @@
 		return ret;
 	}
 	/* We have the initial and handle reference but need only one now */
-	drm_gem_object_unreference(&r->gem);
+	drm_gem_object_unreference_unlocked(&r->gem);
 	*handlep = handle;
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/intel_bios.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/intel_bios.c
@@ -436,6 +436,9 @@
 	if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
 		dev_priv->edp.support = 1;
 
+	dev_priv->lvds_enabled_in_vbt = driver->lvds_config != 0;
+	DRM_DEBUG_KMS("LVDS VBT config bits: 0x%x\n", driver->lvds_config);
+
 	/* This bit means to use 96Mhz for DPLL_A or not */
 	if (driver->primary_lfp_id)
 		dev_priv->dplla_96mhz = true;
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
@@ -821,14 +821,18 @@
 	struct drm_device *dev = dsi_config->dev;
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder);
-
 	u32 pipeconf_reg = PIPEACONF;
 	u32 dspcntr_reg = DSPACNTR;
+	u32 pipeconf, dspcntr;
 
-	u32 pipeconf = dev_priv->pipeconf[pipe];
-	u32 dspcntr = dev_priv->dspcntr[pipe];
 	u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
 
+	if (WARN_ON(pipe < 0))
+		return;
+
+	pipeconf = dev_priv->pipeconf[pipe];
+	dspcntr = dev_priv->dspcntr[pipe];
+
 	if (pipe) {
 		pipeconf_reg = PIPECCONF;
 		dspcntr_reg = DSPCCNTR;
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -382,16 +382,6 @@
 	return MODE_OK;
 }
 
-static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode)
-{
-	if (mode == connector->dpms)
-		return;
-
-	/*first, execute dpms*/
-
-	drm_helper_connector_dpms(connector, mode);
-}
-
 static struct drm_encoder *mdfld_dsi_connector_best_encoder(
 				struct drm_connector *connector)
 {
@@ -404,7 +394,7 @@
 
 /*DSI connector funcs*/
 static const struct drm_connector_funcs mdfld_dsi_connector_funcs = {
-	.dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms,
+	.dpms = drm_helper_connector_dpms,
 	.save = mdfld_dsi_connector_save,
 	.restore = mdfld_dsi_connector_restore,
 	.detect = mdfld_dsi_connector_detect,
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
@@ -72,7 +72,7 @@
 	"RX Prot Violation",
 	"HS Generic Write FIFO Full",
 	"LP Generic Write FIFO Full",
-	"Generic Read Data Avail"
+	"Generic Read Data Avail",
 	"Special Packet Sent",
 	"Tearing Effect",
 };
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/mdfld_intel_display.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/mdfld_intel_display.c
@@ -99,7 +99,7 @@
 	/* Wait for for the pipe enable to take effect. */
 	for (count = 0; count < COUNT_MAX; count++) {
 		temp = REG_READ(map->conf);
-		if ((temp & PIPEACONF_PIPE_STATE) == 1)
+		if (temp & PIPEACONF_PIPE_STATE)
 			break;
 	}
 }
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -139,6 +139,7 @@
 	s32 freq_error, min_error = 100000;
 
 	memset(best_clock, 0, sizeof(*best_clock));
+	memset(&clock, 0, sizeof(clock));
 
 	for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
 		for (clock.n = limit->n.min; clock.n <= limit->n.max;
@@ -195,6 +196,7 @@
 	int err = target;
 
 	memset(best_clock, 0, sizeof(*best_clock));
+	memset(&clock, 0, sizeof(clock));
 
 	for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
 		for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max;
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
@@ -279,11 +279,8 @@
 	hdmi_dev = pci_get_drvdata(dev);
 
 	i2c_dev = kzalloc(sizeof(struct hdmi_i2c_dev), GFP_KERNEL);
-	if (i2c_dev == NULL) {
-		DRM_ERROR("Can't allocate interface\n");
-		ret = -ENOMEM;
-		goto exit;
-	}
+	if (!i2c_dev)
+		return -ENOMEM;
 
 	i2c_dev->adap = &oaktrail_hdmi_i2c_adapter;
 	i2c_dev->status = I2C_STAT_INIT;
@@ -300,16 +297,23 @@
 			  oaktrail_hdmi_i2c_adapter.name, hdmi_dev);
 	if (ret) {
 		DRM_ERROR("Failed to request IRQ for I2C controller\n");
-		goto err;
+		goto free_dev;
 	}
 
 	/* Adapter registration */
 	ret = i2c_add_numbered_adapter(&oaktrail_hdmi_i2c_adapter);
-	return ret;
+	if (ret) {
+		DRM_ERROR("Failed to add I2C adapter\n");
+		goto free_irq;
+	}
+
+	return 0;
 
-err:
+free_irq:
+	free_irq(dev->irq, hdmi_dev);
+free_dev:
 	kfree(i2c_dev);
-exit:
+
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/psb_drv.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/psb_drv.c
@@ -325,6 +325,8 @@
 	if (ret)
 		goto out_err;
 
+	ret = -ENOMEM;
+
 	dev_priv->mmu = psb_mmu_driver_init(dev, 1, 0, 0);
 	if (!dev_priv->mmu)
 		goto out_err;
@@ -484,6 +486,9 @@
 	.open = drm_open,
 	.release = drm_release,
 	.unlocked_ioctl = psb_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = drm_compat_ioctl,
+#endif
 	.mmap = drm_gem_mmap,
 	.poll = drm_poll,
 	.read = drm_read,
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/psb_drv.h
+++ linux-4.4.0/drivers/gpu/drm/gma500/psb_drv.h
@@ -536,6 +536,7 @@
 	int lvds_ssc_freq;
 	bool is_lvds_on;
 	bool is_mipi_on;
+	bool lvds_enabled_in_vbt;
 	u32 mipi_ctrl_display;
 
 	unsigned int core_freq;
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ linux-4.4.0/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -252,7 +252,7 @@
 extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder,
 				      const struct drm_display_mode *mode,
 				      struct drm_display_mode *adjusted_mode);
-extern int psb_intel_lvds_mode_valid(struct drm_connector *connector,
+extern enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector,
 				     struct drm_display_mode *mode);
 extern int psb_intel_lvds_set_property(struct drm_connector *connector,
 					struct drm_property *property,
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -343,7 +343,7 @@
 	}
 }
 
-int psb_intel_lvds_mode_valid(struct drm_connector *connector,
+enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector,
 				 struct drm_display_mode *mode)
 {
 	struct drm_psb_private *dev_priv = connector->dev->dev_private;
@@ -542,6 +542,9 @@
 	if (mode_dev->panel_fixed_mode != NULL) {
 		struct drm_display_mode *mode =
 		    drm_mode_duplicate(dev, mode_dev->panel_fixed_mode);
+		if (!mode)
+			return 0;
+
 		drm_mode_probed_add(connector, mode);
 		return 1;
 	}
@@ -783,20 +786,23 @@
 		if (scan->type & DRM_MODE_TYPE_PREFERRED) {
 			mode_dev->panel_fixed_mode =
 			    drm_mode_duplicate(dev, scan);
+			DRM_DEBUG_KMS("Using mode from DDC\n");
 			goto out;	/* FIXME: check for quirks */
 		}
 	}
 
 	/* Failed to get EDID, what about VBT? do we need this? */
-	if (mode_dev->vbt_mode)
+	if (dev_priv->lfp_lvds_vbt_mode) {
 		mode_dev->panel_fixed_mode =
-		    drm_mode_duplicate(dev, mode_dev->vbt_mode);
+			drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
 
-	if (!mode_dev->panel_fixed_mode)
-		if (dev_priv->lfp_lvds_vbt_mode)
-			mode_dev->panel_fixed_mode =
-				drm_mode_duplicate(dev,
-					dev_priv->lfp_lvds_vbt_mode);
+		if (mode_dev->panel_fixed_mode) {
+			mode_dev->panel_fixed_mode->type |=
+				DRM_MODE_TYPE_PREFERRED;
+			DRM_DEBUG_KMS("Using mode from VBT\n");
+			goto out;
+		}
+	}
 
 	/*
 	 * If we didn't get EDID, try checking if the panel is already turned
@@ -813,6 +819,7 @@
 		if (mode_dev->panel_fixed_mode) {
 			mode_dev->panel_fixed_mode->type |=
 			    DRM_MODE_TYPE_PREFERRED;
+			DRM_DEBUG_KMS("Using pre-programmed mode\n");
 			goto out;	/* FIXME: check for quirks */
 		}
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/gma500/psb_irq.c
+++ linux-4.4.0/drivers/gpu/drm/gma500/psb_irq.c
@@ -350,6 +350,7 @@
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	unsigned long irqflags;
+	unsigned int i;
 
 	spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
 
@@ -362,20 +363,12 @@
 	PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
 	PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
 
-	if (dev->vblank[0].enabled)
-		psb_enable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);
-	else
-		psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);
-
-	if (dev->vblank[1].enabled)
-		psb_enable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);
-	else
-		psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);
-
-	if (dev->vblank[2].enabled)
-		psb_enable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
-	else
-		psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
+	for (i = 0; i < dev->num_crtcs; ++i) {
+		if (dev->vblank[i].enabled)
+			psb_enable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
+		else
+			psb_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
+	}
 
 	if (dev_priv->ops->hotplug_enable)
 		dev_priv->ops->hotplug_enable(dev, true);
@@ -388,6 +381,7 @@
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	unsigned long irqflags;
+	unsigned int i;
 
 	spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
 
@@ -396,14 +390,10 @@
 
 	PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
 
-	if (dev->vblank[0].enabled)
-		psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);
-
-	if (dev->vblank[1].enabled)
-		psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);
-
-	if (dev->vblank[2].enabled)
-		psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
+	for (i = 0; i < dev->num_crtcs; ++i) {
+		if (dev->vblank[i].enabled)
+			psb_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
+	}
 
 	dev_priv->vdc_irq_mask &= _PSB_IRQ_SGX_FLAG |
 				  _PSB_IRQ_MSVDX_FLAG |
--- linux-4.4.0.orig/drivers/gpu/drm/i2c/adv7511.c
+++ linux-4.4.0/drivers/gpu/drm/i2c/adv7511.c
@@ -36,7 +36,10 @@
 	bool edid_read;
 
 	wait_queue_head_t wq;
+	struct work_struct hpd_work;
+
 	struct drm_encoder *encoder;
+	struct drm_connector connector;
 
 	bool embedded_sync;
 	enum adv7511_sync_polarity vsync_polarity;
@@ -48,6 +51,10 @@
 	struct gpio_desc *gpio_pd;
 };
 
+static const int edid_i2c_addr = 0x7e;
+static const int packet_i2c_addr = 0x70;
+static const int cec_i2c_addr = 0x78;
+
 static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
 {
 	return to_encoder_slave(encoder)->slave_priv;
@@ -362,12 +369,19 @@
 {
 	adv7511->current_edid_segment = -1;
 
-	regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-		     ADV7511_INT0_EDID_READY);
-	regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
-		     ADV7511_INT1_DDC_ERROR);
 	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
 			   ADV7511_POWER_POWER_DOWN, 0);
+	if (adv7511->i2c_main->irq) {
+		/*
+		 * Documentation says the INT_ENABLE registers are reset in
+		 * POWER_DOWN mode. My 7511w preserved the bits, however.
+		 * Still, let's be safe and stick to the documentation.
+		 */
+		regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
+			     ADV7511_INT0_EDID_READY);
+		regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
+			     ADV7511_INT1_DDC_ERROR);
+	}
 
 	/*
 	 * Per spec it is allowed to pulse the HDP signal to indicate that the
@@ -422,7 +436,39 @@
 	return false;
 }
 
-static int adv7511_irq_process(struct adv7511 *adv7511)
+static void adv7511_hpd_work(struct work_struct *work)
+{
+	struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work);
+	enum drm_connector_status status;
+	unsigned int val;
+	int ret;
+	ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
+	if (ret < 0)
+		status = connector_status_disconnected;
+	else if (val & ADV7511_STATUS_HPD)
+		status = connector_status_connected;
+	else
+		status = connector_status_disconnected;
+
+	/*
+	 * The bridge resets its registers on unplug. So when we get a plug
+	 * event and we're already supposed to be powered, cycle the bridge to
+	 * restore its state.
+	 */
+	if (status == connector_status_connected &&
+	    adv7511->connector.status == connector_status_disconnected &&
+	    adv7511->powered) {
+		regcache_mark_dirty(adv7511->regmap);
+		adv7511_power_on(adv7511);
+	}
+
+	if (adv7511->connector.status != status) {
+		adv7511->connector.status = status;
+		drm_kms_helper_hotplug_event(adv7511->connector.dev);
+	}
+}
+
+static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
 {
 	unsigned int irq0, irq1;
 	int ret;
@@ -438,8 +484,8 @@
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HDP && adv7511->encoder)
-		drm_helper_hpd_irq_event(adv7511->encoder->dev);
+	if (process_hpd && irq0 & ADV7511_INT0_HDP && adv7511->encoder)
+		schedule_work(&adv7511->hpd_work);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
 		adv7511->edid_read = true;
@@ -456,7 +502,7 @@
 	struct adv7511 *adv7511 = devid;
 	int ret;
 
-	ret = adv7511_irq_process(adv7511);
+	ret = adv7511_irq_process(adv7511, true);
 	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
 }
 
@@ -473,7 +519,7 @@
 				adv7511->edid_read, msecs_to_jiffies(timeout));
 	} else {
 		for (; timeout > 0; timeout -= 25) {
-			ret = adv7511_irq_process(adv7511);
+			ret = adv7511_irq_process(adv7511, false);
 			if (ret < 0)
 				break;
 
@@ -567,13 +613,18 @@
 
 	/* Reading the EDID only works if the device is powered */
 	if (!adv7511->powered) {
-		regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-			     ADV7511_INT0_EDID_READY);
-		regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
-			     ADV7511_INT1_DDC_ERROR);
 		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
 				   ADV7511_POWER_POWER_DOWN, 0);
+		if (adv7511->i2c_main->irq) {
+			regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
+				     ADV7511_INT0_EDID_READY);
+			regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
+				     ADV7511_INT1_DDC_ERROR);
+		}
 		adv7511->current_edid_segment = -1;
+		/* Reset the EDID_I2C_ADDR register as it might be cleared */
+		regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
+				edid_i2c_addr);
 	}
 
 	edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
@@ -730,11 +781,11 @@
 			vsync_polarity = 1;
 	}
 
-	if (mode->vrefresh <= 24000)
+	if (drm_mode_vrefresh(mode) <= 24)
 		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ;
-	else if (mode->vrefresh <= 25000)
+	else if (drm_mode_vrefresh(mode) <= 25)
 		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ;
-	else if (mode->vrefresh <= 30000)
+	else if (drm_mode_vrefresh(mode) <= 30)
 		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ;
 	else
 		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
@@ -849,10 +900,6 @@
 	return 0;
 }
 
-static const int edid_i2c_addr = 0x7e;
-static const int packet_i2c_addr = 0x70;
-static const int cec_i2c_addr = 0x78;
-
 static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 {
 	struct adv7511_link_config link_config;
@@ -913,6 +960,8 @@
 	if (!adv7511->i2c_edid)
 		return -ENOMEM;
 
+	INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
+
 	if (i2c->irq) {
 		init_waitqueue_head(&adv7511->wq);
 
--- linux-4.4.0.orig/drivers/gpu/drm/i810/i810_dma.c
+++ linux-4.4.0/drivers/gpu/drm/i810/i810_dma.c
@@ -723,7 +723,7 @@
 	if (nbox > I810_NR_SAREA_CLIPRECTS)
 		nbox = I810_NR_SAREA_CLIPRECTS;
 
-	if (used > 4 * 1024)
+	if (used < 0 || used > 4 * 1024)
 		used = 0;
 
 	if (sarea_priv->dirty)
@@ -1043,7 +1043,7 @@
 	if (u != I810_BUF_CLIENT)
 		DRM_DEBUG("MC found buffer that isn't mine!\n");
 
-	if (used > 4 * 1024)
+	if (used < 0 || used > 4 * 1024)
 		used = 0;
 
 	sarea_priv->dirty = 0x7f;
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_dma.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_dma.c
@@ -402,6 +402,8 @@
 	if (ret)
 		goto cleanup_gem_stolen;
 
+	intel_setup_gmbus(dev);
+
 	/* Important: The output setup functions called by modeset_init need
 	 * working irqs for e.g. gmbus and dp aux transfers. */
 	intel_modeset_init(dev);
@@ -451,6 +453,7 @@
 cleanup_irq:
 	intel_guc_ucode_fini(dev);
 	drm_irq_uninstall(dev);
+	intel_teardown_gmbus(dev);
 cleanup_gem_stolen:
 	i915_gem_cleanup_stolen(dev);
 cleanup_vga_switcheroo:
@@ -1028,7 +1031,6 @@
 
 	/* Try to make sure MCHBAR is enabled before poking at it */
 	intel_setup_mchbar(dev);
-	intel_setup_gmbus(dev);
 	intel_opregion_setup(dev);
 
 	i915_gem_load(dev);
@@ -1099,7 +1101,6 @@
 	if (dev->pdev->msi_enabled)
 		pci_disable_msi(dev->pdev);
 
-	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
 	pm_qos_remove_request(&dev_priv->pm_qos);
 	destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
@@ -1198,7 +1199,6 @@
 
 	intel_csr_ucode_fini(dev);
 
-	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
 
 	destroy_workqueue(dev_priv->hotplug.dp_wq);
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_drv.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_drv.c
@@ -400,44 +400,37 @@
  * and subvendor IDs, we need it to come before the more general IVB
  * PCI ID matches, otherwise we'll use the wrong info struct above.
  */
-#define INTEL_PCI_IDS \
-	INTEL_I830_IDS(&intel_i830_info),	\
-	INTEL_I845G_IDS(&intel_845g_info),	\
-	INTEL_I85X_IDS(&intel_i85x_info),	\
-	INTEL_I865G_IDS(&intel_i865g_info),	\
-	INTEL_I915G_IDS(&intel_i915g_info),	\
-	INTEL_I915GM_IDS(&intel_i915gm_info),	\
-	INTEL_I945G_IDS(&intel_i945g_info),	\
-	INTEL_I945GM_IDS(&intel_i945gm_info),	\
-	INTEL_I965G_IDS(&intel_i965g_info),	\
-	INTEL_G33_IDS(&intel_g33_info),		\
-	INTEL_I965GM_IDS(&intel_i965gm_info),	\
-	INTEL_GM45_IDS(&intel_gm45_info), 	\
-	INTEL_G45_IDS(&intel_g45_info), 	\
-	INTEL_PINEVIEW_IDS(&intel_pineview_info),	\
-	INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info),	\
-	INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info),	\
-	INTEL_SNB_D_IDS(&intel_sandybridge_d_info),	\
-	INTEL_SNB_M_IDS(&intel_sandybridge_m_info),	\
-	INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */ \
-	INTEL_IVB_M_IDS(&intel_ivybridge_m_info),	\
-	INTEL_IVB_D_IDS(&intel_ivybridge_d_info),	\
-	INTEL_HSW_D_IDS(&intel_haswell_d_info), \
-	INTEL_HSW_M_IDS(&intel_haswell_m_info), \
-	INTEL_VLV_M_IDS(&intel_valleyview_m_info),	\
-	INTEL_VLV_D_IDS(&intel_valleyview_d_info),	\
-	INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info),	\
-	INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info),	\
-	INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info),	\
-	INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info), \
-	INTEL_CHV_IDS(&intel_cherryview_info),	\
-	INTEL_SKL_GT1_IDS(&intel_skylake_info),	\
-	INTEL_SKL_GT2_IDS(&intel_skylake_info),	\
-	INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info),	\
-	INTEL_BXT_IDS(&intel_broxton_info)
-
-static const struct pci_device_id pciidlist[] = {		/* aka */
-	INTEL_PCI_IDS,
+static const struct pci_device_id pciidlist[] = {
+	INTEL_I830_IDS(&intel_i830_info),
+	INTEL_I845G_IDS(&intel_845g_info),
+	INTEL_I85X_IDS(&intel_i85x_info),
+	INTEL_I865G_IDS(&intel_i865g_info),
+	INTEL_I915G_IDS(&intel_i915g_info),
+	INTEL_I915GM_IDS(&intel_i915gm_info),
+	INTEL_I945G_IDS(&intel_i945g_info),
+	INTEL_I945GM_IDS(&intel_i945gm_info),
+	INTEL_I965G_IDS(&intel_i965g_info),
+	INTEL_G33_IDS(&intel_g33_info),
+	INTEL_I965GM_IDS(&intel_i965gm_info),
+	INTEL_GM45_IDS(&intel_gm45_info),
+	INTEL_G45_IDS(&intel_g45_info),
+	INTEL_PINEVIEW_IDS(&intel_pineview_info),
+	INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info),
+	INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info),
+	INTEL_SNB_D_IDS(&intel_sandybridge_d_info),
+	INTEL_SNB_M_IDS(&intel_sandybridge_m_info),
+	INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */
+	INTEL_IVB_M_IDS(&intel_ivybridge_m_info),
+	INTEL_IVB_D_IDS(&intel_ivybridge_d_info),
+	INTEL_HSW_D_IDS(&intel_haswell_d_info),
+	INTEL_HSW_M_IDS(&intel_haswell_m_info),
+	INTEL_VLV_M_IDS(&intel_valleyview_m_info),
+	INTEL_VLV_D_IDS(&intel_valleyview_d_info),
+	INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info),
+	INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info),
+	INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info),
+	INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info),
+	INTEL_CHV_IDS(&intel_cherryview_info),
 	{0, 0, 0}
 };
 
@@ -531,7 +524,10 @@
 				dev_priv->pch_type = PCH_SPT;
 				DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n");
 				WARN_ON(!IS_SKYLAKE(dev));
-			} else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE) {
+			} else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) ||
+				   ((id == INTEL_PCH_QEMU_DEVICE_ID_TYPE) &&
+				    pch->subsystem_vendor == 0x1af4 &&
+				    pch->subsystem_device == 0x1100)) {
 				dev_priv->pch_type = intel_virt_detect_pch(dev);
 			} else
 				continue;
@@ -695,6 +691,8 @@
 		return ret;
 	}
 
+	i915_rc6_ctx_wa_suspend(dev_priv);
+
 	pci_disable_device(drm_dev->pdev);
 	/*
 	 * During hibernation on some platforms the BIOS may try to access
@@ -846,6 +844,8 @@
 	intel_uncore_sanitize(dev);
 	intel_power_domains_init_hw(dev_priv);
 
+	i915_rc6_ctx_wa_resume(dev_priv);
+
 	return ret;
 }
 
@@ -1546,6 +1546,9 @@
 
 	assert_forcewakes_inactive(dev_priv);
 
+	if (!IS_VALLEYVIEW(dev_priv) || !IS_CHERRYVIEW(dev_priv))
+		intel_hpd_poll_init(dev_priv);
+
 	DRM_DEBUG_KMS("Device suspended\n");
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_drv.h
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_drv.h
@@ -249,6 +249,9 @@
 	u32 short_port_mask;
 	struct work_struct dig_port_work;
 
+	struct work_struct poll_init_work;
+	bool poll_enabled;
+
 	/*
 	 * if we get a HPD irq from DP and a HPD irq from non-DP
 	 * the non-DP HPD could block the workqueue on a mode config
@@ -1153,13 +1156,14 @@
 	bool client_boost;
 
 	bool enabled;
+	bool ctx_corrupted;
 	struct delayed_work delayed_resume_work;
 	unsigned boosts;
 
 	struct intel_rps_client semaphores, mmioflips;
 
 	/* manual wa residency calculations */
-	struct intel_rps_ei up_ei, down_ei;
+	struct intel_rps_ei ei;
 
 	/*
 	 * Protects RPS/RC6 register access and PCU communication.
@@ -1712,6 +1716,8 @@
 
 	struct intel_uncore uncore;
 
+	struct mutex tlb_invalidate_lock;
+
 	struct i915_virtual_gpu vgpu;
 
 	struct intel_guc guc;
@@ -2059,6 +2065,9 @@
 	 */
 	unsigned int active:I915_NUM_RINGS;
 
+	unsigned long flags;
+#define I915_BO_WAS_BOUND_BIT    0
+
 	/**
 	 * This is set if the object has been written to since last bound
 	 * to the GTT
@@ -2150,21 +2159,19 @@
 	/** Record of address bit 17 of each page at last unbind. */
 	unsigned long *bit_17;
 
-	union {
-		/** for phy allocated objects */
-		struct drm_dma_handle *phys_handle;
-
-		struct i915_gem_userptr {
-			uintptr_t ptr;
-			unsigned read_only :1;
-			unsigned workers :4;
+	struct i915_gem_userptr {
+		uintptr_t ptr;
+		unsigned read_only :1;
+		unsigned workers :4;
 #define I915_GEM_USERPTR_MAX_WORKERS 15
 
-			struct i915_mm_struct *mm;
-			struct i915_mmu_object *mmu_object;
-			struct work_struct *work;
-		} userptr;
-	};
+		struct i915_mm_struct *mm;
+		struct i915_mmu_object *mmu_object;
+		struct work_struct *work;
+	} userptr;
+
+	/** for phys allocated objects */
+	struct drm_dma_handle *phys_handle;
 };
 #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
 
@@ -2557,6 +2564,10 @@
 
 /* Early gen2 have a totally busted CS tlb and require pinned batches. */
 #define HAS_BROKEN_CS_TLB(dev)		(IS_I830(dev) || IS_845G(dev))
+
+#define NEEDS_RC6_CTX_CORRUPTION_WA(dev)	\
+	(IS_BROADWELL(dev) || INTEL_INFO(dev)->gen == 9)
+
 /*
  * dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts
  * even when in MSI mode. This results in spurious interrupt warnings if the
@@ -2614,6 +2625,7 @@
 #define INTEL_PCH_SPT_DEVICE_ID_TYPE		0xA100
 #define INTEL_PCH_SPT_LP_DEVICE_ID_TYPE		0x9D00
 #define INTEL_PCH_P2X_DEVICE_ID_TYPE		0x7100
+#define INTEL_PCH_QEMU_DEVICE_ID_TYPE		0x2900 /* qemu q35 has 2918 */
 
 #define INTEL_PCH_TYPE(dev) (__I915__(dev)->pch_type)
 #define HAS_PCH_SPT(dev) (INTEL_PCH_TYPE(dev) == PCH_SPT)
@@ -2706,6 +2718,8 @@
 void intel_hpd_init_work(struct drm_i915_private *dev_priv);
 void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
 bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port);
+bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
+void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
 
 /* i915_irq.c */
 void i915_queue_hangcheck(struct drm_device *dev);
@@ -3312,6 +3326,9 @@
 }
 extern void intel_i2c_reset(struct drm_device *dev);
 
+/* intel_bios.c */
+bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port);
+
 /* intel_opregion.c */
 #ifdef CONFIG_ACPI
 extern int intel_opregion_setup(struct drm_device *dev);
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_gem.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_gem.c
@@ -2212,6 +2212,85 @@
 	kfree(obj->pages);
 }
 
+#define _wait_for_us(COND, US, W) ({ \
+	unsigned long timeout__ = jiffies + usecs_to_jiffies(US) + 1;   \
+	int ret__;                                                      \
+	for (;;) {                                                      \
+		bool expired__ = time_after(jiffies, timeout__);        \
+		if (COND) {                                             \
+			ret__ = 0;                                      \
+			break;                                          \
+		}                                                       \
+		if (expired__) {                                        \
+			ret__ = -ETIMEDOUT;                             \
+			break;                                          \
+		}                                                       \
+		usleep_range((W), (W)*2);                               \
+	}                                                               \
+	ret__;                                                          \
+})
+
+static int
+__intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
+			     u32 reg,
+			     const u32 mask,
+			     const u32 value,
+			     const unsigned int timeout_us,
+			     const unsigned int timeout_ms)
+{
+#define done ((I915_READ_FW(reg) & mask) == value)
+	int ret = _wait_for_us(done, timeout_us, 2);
+	if (ret)
+		ret = wait_for(done, timeout_ms);
+	return ret;
+#undef done
+}
+
+static void invalidate_tlbs(struct drm_i915_private *dev_priv)
+{
+	static const u32 gen8_regs[] = {
+		[RCS]  = GEN8_RTCR,
+		[VCS]  = GEN8_M1TCR,
+		[VCS2] = GEN8_M2TCR,
+		[VECS] = GEN8_VTCR,
+		[BCS]  = GEN8_BTCR,
+	};
+	enum intel_ring_id id;
+
+	if (INTEL_INFO(dev_priv)->gen < 8)
+		return;
+
+	mutex_lock(&dev_priv->tlb_invalidate_lock);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+	for (id = 0; id < I915_NUM_RINGS; id++) {
+		struct intel_engine_cs *engine = &dev_priv->ring[id];
+		/*
+		 * HW architecture suggest typical invalidation time at 40us,
+		 * with pessimistic cases up to 100us and a recommendation to
+		 * cap at 1ms. We go a bit higher just in case.
+		 */
+		const unsigned int timeout_us = 100;
+		const unsigned int timeout_ms = 4;
+
+		if (!intel_ring_initialized(engine))
+			continue;
+
+		if (WARN_ON_ONCE(id >= ARRAY_SIZE(gen8_regs) || !gen8_regs[id]))
+			continue;
+
+		I915_WRITE_FW(gen8_regs[id], 1);
+		if (__intel_wait_for_register_fw(dev_priv,
+						 gen8_regs[id], 1, 0,
+						 timeout_us, timeout_ms))
+			DRM_ERROR_RATELIMITED("%s TLB invalidation did not complete in %ums!\n",
+					      engine->name, timeout_ms);
+	}
+
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+	mutex_unlock(&dev_priv->tlb_invalidate_lock);
+}
+
 int
 i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
 {
@@ -2230,6 +2309,14 @@
 	 * lists early. */
 	list_del(&obj->global_list);
 
+	if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) {
+		struct drm_i915_private *i915 = to_i915(obj->base.dev);
+
+		intel_runtime_pm_get(i915);
+		invalidate_tlbs(i915);
+		intel_runtime_pm_put(i915);
+	}
+
 	ops->put_pages(obj);
 	obj->pages = NULL;
 
@@ -5050,6 +5137,8 @@
 	i915_gem_shrinker_init(dev_priv);
 
 	mutex_init(&dev_priv->fb_tracking.lock);
+
+	mutex_init(&dev_priv->tlb_invalidate_lock);
 }
 
 void i915_gem_release(struct drm_device *dev, struct drm_file *file)
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_gem_context.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_gem_context.c
@@ -340,6 +340,10 @@
 			i915_gem_context_unreference(lctx);
 			ring->last_context = NULL;
 		}
+
+		/* Force the GPU state to be reinitialised on enabling */
+		if (ring->default_context)
+			ring->default_context->legacy_hw_ctx.initialized = false;
 	}
 }
 
@@ -708,7 +712,7 @@
 	if (ret)
 		goto unpin_out;
 
-	if (!to->legacy_hw_ctx.initialized) {
+	if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to)) {
 		hw_flags |= MI_RESTORE_INHIBIT;
 		/* NB: If we inhibit the restore, the context is not allowed to
 		 * die because future work may end up depending on valid address
@@ -923,6 +927,14 @@
 	case I915_CONTEXT_PARAM_NO_ZEROMAP:
 		args->value = ctx->flags & CONTEXT_NO_ZEROMAP;
 		break;
+	case I915_CONTEXT_PARAM_GTT_SIZE:
+		if (ctx->ppgtt)
+			args->value = ctx->ppgtt->base.total;
+		else if (to_i915(dev)->mm.aliasing_ppgtt)
+			args->value = to_i915(dev)->mm.aliasing_ppgtt->base.total;
+		else
+			args->value = to_i915(dev)->gtt.base.total;
+		break;
 	default:
 		ret = -EINVAL;
 		break;
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2747,6 +2747,7 @@
 		struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
 
 		ppgtt->base.cleanup(&ppgtt->base);
+		kfree(ppgtt);
 	}
 
 	if (drm_mm_initialized(&vm->mm)) {
@@ -3518,6 +3519,9 @@
 
 	vma->bound |= bind_flags;
 
+	if (vma->obj)
+		set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_gem_shrinker.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_gem_shrinker.c
@@ -39,7 +39,7 @@
 	if (!mutex_is_locked(mutex))
 		return false;
 
-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER)
 	return mutex->owner == task;
 #else
 	/* Since UP may be pre-empted, we cannot assume that we own the lock */
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -108,17 +108,28 @@
 		pci_read_config_dword(dev->pdev, 0x5c, &base);
 		base &= ~((1<<20) - 1);
 	} else if (IS_I865G(dev)) {
+		u32 tseg_size = 0;
 		u16 toud = 0;
+		u8 tmp;
+
+		pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+					 I845_ESMRAMC, &tmp);
+
+		if (tmp & TSEG_ENABLE) {
+			switch (tmp & I845_TSEG_SIZE_MASK) {
+			case I845_TSEG_SIZE_512K:
+				tseg_size = KB(512);
+				break;
+			case I845_TSEG_SIZE_1M:
+				tseg_size = MB(1);
+				break;
+			}
+		}
 
-		/*
-		 * FIXME is the graphics stolen memory region
-		 * always at TOUD? Ie. is it always the last
-		 * one to be allocated by the BIOS?
-		 */
 		pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0),
 					 I865_TOUD, &toud);
 
-		base = toud << 16;
+		base = (toud << 16) + tseg_size;
 	} else if (IS_I85X(dev)) {
 		u32 tseg_size = 0;
 		u32 tom;
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -581,13 +581,17 @@
 		pvec = drm_malloc_ab(npages, sizeof(struct page *));
 	if (pvec != NULL) {
 		struct mm_struct *mm = obj->userptr.mm->mm;
+		unsigned int flags = 0;
+
+		if (!obj->userptr.read_only)
+			flags |= FOLL_WRITE;
 
 		down_read(&mm->mmap_sem);
 		while (pinned < npages) {
 			ret = get_user_pages(work->task, mm,
 					     obj->userptr.ptr + pinned * PAGE_SIZE,
 					     npages - pinned,
-					     !obj->userptr.read_only, 0,
+					     flags,
 					     pvec + pinned, NULL);
 			if (ret < 0)
 				break;
@@ -725,6 +729,14 @@
 			}
 		}
 
+		/*
+		 * Using __get_user_pages_fast() with a read-only
+		 * access is questionable. A read-only page may be
+		 * COW-broken, and then this might end up giving
+		 * the wrong side of the COW..
+		 *
+		 * We may or may not care.
+		 */
 		pinned = __get_user_pages_fast(obj->userptr.ptr, num_pages,
 					       !obj->userptr.read_only, pvec);
 	}
@@ -842,6 +854,9 @@
 			    I915_USERPTR_UNSYNCHRONIZED))
 		return -EINVAL;
 
+	if (!args->user_size)
+		return -EINVAL;
+
 	if (offset_in_page(args->user_ptr | args->user_size))
 		return -EINVAL;
 
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_irq.c
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_irq.c
@@ -994,68 +994,51 @@
 	ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
 }
 
-static bool vlv_c0_above(struct drm_i915_private *dev_priv,
-			 const struct intel_rps_ei *old,
-			 const struct intel_rps_ei *now,
-			 int threshold)
-{
-	u64 time, c0;
-	unsigned int mul = 100;
-
-	if (old->cz_clock == 0)
-		return false;
-
-	if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
-		mul <<= 8;
-
-	time = now->cz_clock - old->cz_clock;
-	time *= threshold * dev_priv->czclk_freq;
-
-	/* Workload can be split between render + media, e.g. SwapBuffers
-	 * being blitted in X after being rendered in mesa. To account for
-	 * this we need to combine both engines into our activity counter.
-	 */
-	c0 = now->render_c0 - old->render_c0;
-	c0 += now->media_c0 - old->media_c0;
-	c0 *= mul * VLV_CZ_CLOCK_TO_MILLI_SEC;
-
-	return c0 >= time;
-}
-
 void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
 {
-	vlv_c0_read(dev_priv, &dev_priv->rps.down_ei);
-	dev_priv->rps.up_ei = dev_priv->rps.down_ei;
+	memset(&dev_priv->rps.ei, 0, sizeof(dev_priv->rps.ei));
 }
 
 static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
 {
+	const struct intel_rps_ei *prev = &dev_priv->rps.ei;
 	struct intel_rps_ei now;
 	u32 events = 0;
 
-	if ((pm_iir & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED)) == 0)
+	if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
 		return 0;
 
 	vlv_c0_read(dev_priv, &now);
 	if (now.cz_clock == 0)
 		return 0;
 
-	if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) {
-		if (!vlv_c0_above(dev_priv,
-				  &dev_priv->rps.down_ei, &now,
-				  dev_priv->rps.down_threshold))
-			events |= GEN6_PM_RP_DOWN_THRESHOLD;
-		dev_priv->rps.down_ei = now;
-	}
+	if (prev->cz_clock) {
+		u64 time, c0;
+		unsigned int mul;
+
+		mul = VLV_CZ_CLOCK_TO_MILLI_SEC * 100; /* scale to threshold% */
+		if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
+			mul <<= 8;
+
+		time = now.cz_clock - prev->cz_clock;
+		time *= dev_priv->czclk_freq;
+
+		/* Workload can be split between render + media,
+		 * e.g. SwapBuffers being blitted in X after being rendered in
+		 * mesa. To account for this we need to combine both engines
+		 * into our activity counter.
+		 */
+		c0 = now.render_c0 - prev->render_c0;
+		c0 += now.media_c0 - prev->media_c0;
+		c0 *= mul;
 
-	if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
-		if (vlv_c0_above(dev_priv,
-				 &dev_priv->rps.up_ei, &now,
-				 dev_priv->rps.up_threshold))
-			events |= GEN6_PM_RP_UP_THRESHOLD;
-		dev_priv->rps.up_ei = now;
+		if (c0 > time * dev_priv->rps.up_threshold)
+			events = GEN6_PM_RP_UP_THRESHOLD;
+		else if (c0 < time * dev_priv->rps.down_threshold)
+			events = GEN6_PM_RP_DOWN_THRESHOLD;
 	}
 
+	dev_priv->rps.ei = now;
 	return events;
 }
 
@@ -2354,9 +2337,13 @@
 				spt_irq_handler(dev, pch_iir);
 			else
 				cpt_irq_handler(dev, pch_iir);
-		} else
-			DRM_ERROR("The master control interrupt lied (SDE)!\n");
-
+		} else {
+			/*
+			 * Like on previous PCH there seems to be something
+			 * fishy going on with forwarding PCH interrupts.
+			 */
+			DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n");
+		}
 	}
 
 	I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
@@ -4386,7 +4373,7 @@
 	/* Let's track the enabled rps events */
 	if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
 		/* WaGsvRC0ResidencyMethod:vlv */
-		dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED;
+		dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
 	else
 		dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
 
--- linux-4.4.0.orig/drivers/gpu/drm/i915/i915_reg.h
+++ linux-4.4.0/drivers/gpu/drm/i915/i915_reg.h
@@ -170,6 +170,8 @@
 #define   ECOCHK_PPGTT_WT_HSW		(0x2<<3)
 #define   ECOCHK_PPGTT_WB_HSW		(0x3<<3)
 
+#define GEN8_RC6_CTX_INFO		0x8504
+
 #define GAC_ECO_BITS			0x14090
 #define   ECOBITS_SNB_BIT		(1<<13)
 #define   ECOBITS_PPGTT_CACHE64B	(3<<8)
@@ -1585,6 +1587,12 @@
 
 #define GEN7_TLB_RD_ADDR	0x4700
 
+#define GEN8_RTCR	0x4260
+#define GEN8_M1TCR	0x4264
+#define GEN8_M2TCR	0x4268
+#define GEN8_BTCR	0x426c
+#define GEN8_VTCR	0x4270
+
 #if 0
 #define PRB0_TAIL	0x02030
 #define PRB0_HEAD	0x02034
@@ -2838,7 +2846,14 @@
 #define GEN6_RP_STATE_CAP	(MCHBAR_MIRROR_BASE_SNB + 0x5998)
 #define BXT_RP_STATE_CAP        0x138170
 
-#define INTERVAL_1_28_US(us)	(((us) * 100) >> 7)
+/*
+ * Make these a multiple of magic 25 to avoid SNB (eg. Dell XPS
+ * 8300) freezing up around GPU hangs. Looks as if even
+ * scheduling/timer interrupts start misbehaving if the RPS
+ * EI/thresholds are "bad", leading to a very sluggish or even
+ * frozen machine.
+ */
+#define INTERVAL_1_28_US(us)	roundup(((us) * 100) >> 7, 25)
 #define INTERVAL_1_33_US(us)	(((us) * 3)   >> 2)
 #define INTERVAL_0_833_US(us)	(((us) * 6) / 5)
 #define GT_INTERVAL_FROM_US(dev_priv, us) (IS_GEN9(dev_priv) ? \
@@ -3233,19 +3248,20 @@
 
 #define PORT_HOTPLUG_STAT	(dev_priv->info.display_mmio_offset + 0x61114)
 /*
- * HDMI/DP bits are gen4+
+ * HDMI/DP bits are g4x+
  *
  * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused.
  * Please check the detailed lore in the commit message for for experimental
  * evidence.
  */
-#define   PORTD_HOTPLUG_LIVE_STATUS_G4X		(1 << 29)
+/* Bspec says GM45 should match G4X/VLV/CHV, but reality disagrees */
+#define   PORTD_HOTPLUG_LIVE_STATUS_GM45	(1 << 29)
+#define   PORTC_HOTPLUG_LIVE_STATUS_GM45	(1 << 28)
+#define   PORTB_HOTPLUG_LIVE_STATUS_GM45	(1 << 27)
+/* G4X/VLV/CHV DP/HDMI bits again match Bspec */
+#define   PORTD_HOTPLUG_LIVE_STATUS_G4X		(1 << 27)
 #define   PORTC_HOTPLUG_LIVE_STATUS_G4X		(1 << 28)
-#define   PORTB_HOTPLUG_LIVE_STATUS_G4X		(1 << 27)
-/* VLV DP/HDMI bits again match Bspec */
-#define   PORTD_HOTPLUG_LIVE_STATUS_VLV		(1 << 27)
-#define   PORTC_HOTPLUG_LIVE_STATUS_VLV		(1 << 28)
-#define   PORTB_HOTPLUG_LIVE_STATUS_VLV		(1 << 29)
+#define   PORTB_HOTPLUG_LIVE_STATUS_G4X		(1 << 29)
 #define   PORTD_HOTPLUG_INT_STATUS		(3 << 21)
 #define   PORTD_HOTPLUG_INT_LONG_PULSE		(2 << 21)
 #define   PORTD_HOTPLUG_INT_SHORT_PULSE		(1 << 21)
@@ -7350,6 +7366,8 @@
 #define  TRANS_CLK_SEL_DISABLED		(0x0<<29)
 #define  TRANS_CLK_SEL_PORT(x)		(((x)+1)<<29)
 
+#define CDCLK_FREQ			0x46200
+
 #define TRANSA_MSA_MISC			0x60410
 #define TRANSB_MSA_MISC			0x61410
 #define TRANSC_MSA_MISC			0x62410
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_audio.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_audio.c
@@ -76,6 +76,9 @@
 /* HDMI N/CTS table */
 #define TMDS_297M 297000
 #define TMDS_296M 296703
+#define TMDS_594M 594000
+#define TMDS_593M 593407
+
 static const struct {
 	int sample_rate;
 	int clock;
@@ -96,6 +99,20 @@
 	{ 176400, TMDS_297M, 18816, 247500 },
 	{ 192000, TMDS_296M, 23296, 281250 },
 	{ 192000, TMDS_297M, 20480, 247500 },
+	{ 44100, TMDS_593M, 8918, 937500 },
+	{ 44100, TMDS_594M, 9408, 990000 },
+	{ 48000, TMDS_593M, 5824, 562500 },
+	{ 48000, TMDS_594M, 6144, 594000 },
+	{ 32000, TMDS_593M, 5824, 843750 },
+	{ 32000, TMDS_594M, 3072, 445500 },
+	{ 88200, TMDS_593M, 17836, 937500 },
+	{ 88200, TMDS_594M, 18816, 990000 },
+	{ 96000, TMDS_593M, 11648, 562500 },
+	{ 96000, TMDS_594M, 12288, 594000 },
+	{ 176400, TMDS_593M, 35672, 937500 },
+	{ 176400, TMDS_594M, 37632, 990000 },
+	{ 192000, TMDS_593M, 23296, 562500 },
+	{ 192000, TMDS_594M, 24576, 594000 },
 };
 
 /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
@@ -503,6 +520,7 @@
 	struct i915_audio_component *acomp = dev_priv->audio_component;
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 	enum port port = intel_dig_port->port;
+	enum pipe pipe = -1;
 
 	connector = drm_select_eld(encoder);
 	if (!connector)
@@ -525,8 +543,13 @@
 		dev_priv->display.audio_codec_enable(connector, intel_encoder,
 						     adjusted_mode);
 
+	mutex_lock(&dev_priv->av_mutex);
+	intel_dig_port->audio_connector = connector;
+	mutex_unlock(&dev_priv->av_mutex);
+
 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
-		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
+		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+						(int) port, (int) pipe);
 }
 
 /**
@@ -544,12 +567,18 @@
 	struct i915_audio_component *acomp = dev_priv->audio_component;
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 	enum port port = intel_dig_port->port;
+	enum pipe pipe = -1;
 
 	if (dev_priv->display.audio_codec_disable)
 		dev_priv->display.audio_codec_disable(intel_encoder);
 
+	mutex_lock(&dev_priv->av_mutex);
+	intel_dig_port->audio_connector = NULL;
+	mutex_unlock(&dev_priv->av_mutex);
+
 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
-		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
+		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+						(int) port, (int) pipe);
 }
 
 /**
@@ -706,6 +735,39 @@
 	return 0;
 }
 
+static int i915_audio_component_get_eld(struct device *dev, int port,
+					bool *enabled,
+					unsigned char *buf, int max_bytes)
+{
+	struct drm_i915_private *dev_priv = dev_to_i915(dev);
+	struct drm_device *drm_dev = dev_priv->dev;
+	struct intel_encoder *intel_encoder;
+	struct intel_digital_port *intel_dig_port;
+	const u8 *eld;
+	int ret = -EINVAL;
+
+	mutex_lock(&dev_priv->av_mutex);
+	for_each_intel_encoder(drm_dev, intel_encoder) {
+		if (intel_encoder->type != INTEL_OUTPUT_DISPLAYPORT &&
+		    intel_encoder->type != INTEL_OUTPUT_HDMI)
+			continue;
+		intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+		if (port == intel_dig_port->port) {
+			ret = 0;
+			*enabled = intel_dig_port->audio_connector != NULL;
+			if (!*enabled)
+				break;
+			eld = intel_dig_port->audio_connector->eld;
+			ret = drm_eld_size(eld);
+			memcpy(buf, eld, min(max_bytes, ret));
+			break;
+		}
+	}
+
+	mutex_unlock(&dev_priv->av_mutex);
+	return ret;
+}
+
 static const struct i915_audio_component_ops i915_audio_component_ops = {
 	.owner		= THIS_MODULE,
 	.get_power	= i915_audio_component_get_power,
@@ -713,6 +775,7 @@
 	.codec_wake_override = i915_audio_component_codec_wake_override,
 	.get_cdclk_freq	= i915_audio_component_get_cdclk_freq,
 	.sync_audio_rate = i915_audio_component_sync_audio_rate,
+	.get_eld	= i915_audio_component_get_eld,
 };
 
 static int i915_audio_component_bind(struct device *i915_dev,
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_bios.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_bios.c
@@ -957,6 +957,13 @@
 	is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0;
 	is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR);
 
+	if (port == PORT_A && is_dvi) {
+		DRM_DEBUG_KMS("VBT claims port A supports DVI%s, ignoring\n",
+			      is_hdmi ? "/HDMI" : "");
+		is_dvi = false;
+		is_hdmi = false;
+	}
+
 	info->supports_dvi = is_dvi;
 	info->supports_hdmi = is_hdmi;
 	info->supports_dp = is_dp;
@@ -1351,3 +1358,42 @@
 
 	return 0;
 }
+
+/**
+ * intel_bios_is_port_present - is the specified digital port present
+ * @dev_priv:	i915 device instance
+ * @port:	port to check
+ *
+ * Return true if the device in %port is present.
+ */
+bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port)
+{
+	static const struct {
+		u16 dp, hdmi;
+	} port_mapping[] = {
+		[PORT_B] = { DVO_PORT_DPB, DVO_PORT_HDMIB, },
+		[PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, },
+		[PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, },
+		[PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, },
+	};
+	int i;
+
+	/* FIXME maybe deal with port A as well? */
+	if (WARN_ON(port == PORT_A) || port >= ARRAY_SIZE(port_mapping))
+		return false;
+
+	if (!dev_priv->vbt.child_dev_num)
+		return false;
+
+	for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
+		const union child_device_config *p_child =
+			&dev_priv->vbt.child_dev[i];
+		if ((p_child->common.dvo_port == port_mapping[port].dp ||
+		     p_child->common.dvo_port == port_mapping[port].hdmi) &&
+		    (p_child->common.device_type & (DEVICE_TYPE_TMDS_DVI_SIGNALING |
+						    DEVICE_TYPE_DISPLAYPORT_OUTPUT)))
+			return true;
+	}
+
+	return false;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_crt.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_crt.c
@@ -248,8 +248,14 @@
 		pipe_config->has_pch_encoder = true;
 
 	/* LPT FDI RX only supports 8bpc. */
-	if (HAS_PCH_LPT(dev))
+	if (HAS_PCH_LPT(dev)) {
+		if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) {
+			DRM_DEBUG_KMS("LPT only supports 24bpp\n");
+			return false;
+		}
+
 		pipe_config->pipe_bpp = 24;
+	}
 
 	/* FDI must always be 2.7 GHz */
 	if (HAS_DDI(dev)) {
@@ -314,10 +320,25 @@
 	struct drm_device *dev = connector->dev;
 	struct intel_crt *crt = intel_attached_crt(connector);
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	bool reenable_hpd;
 	u32 adpa;
 	bool ret;
 	u32 save_adpa;
 
+	/*
+	 * Doing a force trigger causes a hpd interrupt to get sent, which can
+	 * get us stuck in a loop if we're polling:
+	 *  - We enable power wells and reset the ADPA
+	 *  - output_poll_exec does force probe on VGA, triggering a hpd
+	 *  - HPD handler waits for poll to unlock dev->mode_config.mutex
+	 *  - output_poll_exec shuts off the ADPA, unlocks
+	 *    dev->mode_config.mutex
+	 *  - HPD handler runs, resets ADPA and brings us back to the start
+	 *
+	 * Just disable HPD interrupts here to prevent this
+	 */
+	reenable_hpd = intel_hpd_disable(dev_priv, crt->base.hpd_pin);
+
 	save_adpa = adpa = I915_READ(crt->adpa_reg);
 	DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
 
@@ -340,6 +361,9 @@
 
 	DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret);
 
+	if (reenable_hpd)
+		intel_hpd_enable(dev_priv, crt->base.hpd_pin);
+
 	return ret;
 }
 
@@ -439,6 +463,7 @@
 	struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
 	struct edid *edid;
 	struct i2c_adapter *i2c;
+	bool ret = false;
 
 	BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
 
@@ -455,17 +480,17 @@
 		 */
 		if (!is_digital) {
 			DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
-			return true;
+			ret = true;
+		} else {
+			DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
 		}
-
-		DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
 	} else {
 		DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n");
 	}
 
 	kfree(edid);
 
-	return false;
+	return ret;
 }
 
 static enum drm_connector_status
@@ -702,11 +727,11 @@
 	return 0;
 }
 
-static void intel_crt_reset(struct drm_connector *connector)
+void intel_crt_reset(struct drm_encoder *encoder)
 {
-	struct drm_device *dev = connector->dev;
+	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crt *crt = intel_attached_crt(connector);
+	struct intel_crt *crt = intel_encoder_to_crt(to_intel_encoder(encoder));
 
 	if (INTEL_INFO(dev)->gen >= 5) {
 		u32 adpa;
@@ -728,7 +753,6 @@
  */
 
 static const struct drm_connector_funcs intel_crt_connector_funcs = {
-	.reset = intel_crt_reset,
 	.dpms = drm_atomic_helper_connector_dpms,
 	.detect = intel_crt_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
@@ -746,6 +770,7 @@
 };
 
 static const struct drm_encoder_funcs intel_crt_enc_funcs = {
+	.reset = intel_crt_reset,
 	.destroy = intel_encoder_destroy,
 };
 
@@ -870,5 +895,5 @@
 		dev_priv->fdi_rx_config = I915_READ(FDI_RX_CTL(PIPE_A)) & fdi_config;
 	}
 
-	intel_crt_reset(connector);
+	intel_crt_reset(&crt->base.base);
 }
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_csr.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_csr.c
@@ -180,7 +180,8 @@
 static const struct stepping_info skl_stepping_info[] = {
 		{'A', '0'}, {'B', '0'}, {'C', '0'},
 		{'D', '0'}, {'E', '0'}, {'F', '0'},
-		{'G', '0'}, {'H', '0'}, {'I', '0'}
+		{'G', '0'}, {'H', '0'}, {'I', '0'},
+		{'J', '0'}, {'K', '0'}
 };
 
 static struct stepping_info bxt_stepping_info[] = {
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_ddi.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_ddi.c
@@ -464,9 +464,17 @@
 	} else if (IS_BROADWELL(dev)) {
 		ddi_translations_fdi = bdw_ddi_translations_fdi;
 		ddi_translations_dp = bdw_ddi_translations_dp;
-		ddi_translations_edp = bdw_ddi_translations_edp;
+
+		if (dev_priv->edp_low_vswing) {
+			ddi_translations_edp = bdw_ddi_translations_edp;
+			n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
+		} else {
+			ddi_translations_edp = bdw_ddi_translations_dp;
+			n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
+		}
+
 		ddi_translations_hdmi = bdw_ddi_translations_hdmi;
-		n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
+
 		n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
 		n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
 		hdmi_default_entry = 7;
@@ -1582,7 +1590,8 @@
 			 DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
 			 DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
 			 wrpll_params.central_freq;
-	} else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
+	} else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+		   intel_encoder->type == INTEL_OUTPUT_DP_MST) {
 		switch (crtc_state->port_clock / 2) {
 		case 81000:
 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
@@ -3187,12 +3196,6 @@
 	intel_ddi_clock_get(encoder, pipe_config);
 }
 
-static void intel_ddi_destroy(struct drm_encoder *encoder)
-{
-	/* HDMI has nothing special to destroy, so we can go with this. */
-	intel_dp_encoder_destroy(encoder);
-}
-
 static bool intel_ddi_compute_config(struct intel_encoder *encoder,
 				     struct intel_crtc_state *pipe_config)
 {
@@ -3211,7 +3214,8 @@
 }
 
 static const struct drm_encoder_funcs intel_ddi_funcs = {
-	.destroy = intel_ddi_destroy,
+	.reset = intel_dp_encoder_reset,
+	.destroy = intel_dp_encoder_destroy,
 };
 
 static struct intel_connector *
@@ -3283,6 +3287,7 @@
 	intel_encoder->post_disable = intel_ddi_post_disable;
 	intel_encoder->get_hw_state = intel_ddi_get_hw_state;
 	intel_encoder->get_config = intel_ddi_get_config;
+	intel_encoder->suspend = intel_dp_encoder_suspend;
 
 	intel_dig_port->port = port;
 	intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_display.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_display.c
@@ -2950,13 +2950,13 @@
 	}
 }
 
-unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
-				     struct drm_i915_gem_object *obj,
-				     unsigned int plane)
+u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
+			   struct drm_i915_gem_object *obj,
+			   unsigned int plane)
 {
 	const struct i915_ggtt_view *view = &i915_ggtt_view_normal;
 	struct i915_vma *vma;
-	unsigned char *offset;
+	u64 offset;
 
 	if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
 		view = &i915_ggtt_view_rotated;
@@ -2966,14 +2966,16 @@
 		view->type))
 		return -1;
 
-	offset = (unsigned char *)vma->node.start;
+	offset = vma->node.start;
 
 	if (plane == 1) {
 		offset += vma->ggtt_view.rotation_info.uv_start_page *
 			  PAGE_SIZE;
 	}
 
-	return (unsigned long)offset;
+	WARN_ON(upper_32_bits(offset));
+
+	return lower_32_bits(offset);
 }
 
 static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@ -3099,7 +3101,7 @@
 	u32 tile_height, plane_offset, plane_size;
 	unsigned int rotation;
 	int x_offset, y_offset;
-	unsigned long surf_addr;
+	u32 surf_addr;
 	struct intel_crtc_state *crtc_state = intel_crtc->config;
 	struct intel_plane_state *plane_state;
 	int src_x = 0, src_y = 0, src_w = 0, src_h = 0;
@@ -3946,10 +3948,10 @@
 	drm_crtc_vblank_put(&intel_crtc->base);
 
 	wake_up_all(&dev_priv->pending_flip_queue);
-	queue_work(dev_priv->wq, &work->work);
-
 	trace_i915_flip_complete(intel_crtc->plane,
 				 work->pending_flip_obj);
+
+	queue_work(dev_priv->wq, &work->work);
 }
 
 void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
@@ -4447,7 +4449,7 @@
 		      intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX);
 
 	return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX,
-		&state->scaler_state.scaler_id, DRM_ROTATE_0,
+		&state->scaler_state.scaler_id, BIT(DRM_ROTATE_0),
 		state->pipe_src_w, state->pipe_src_h,
 		adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay);
 }
@@ -6447,13 +6449,11 @@
 
 int intel_connector_init(struct intel_connector *connector)
 {
-	struct drm_connector_state *connector_state;
+	drm_atomic_helper_connector_reset(&connector->base);
 
-	connector_state = kzalloc(sizeof *connector_state, GFP_KERNEL);
-	if (!connector_state)
+	if (!connector->base.state)
 		return -ENOMEM;
 
-	connector->base.state = connector_state;
 	return 0;
 }
 
@@ -8228,12 +8228,14 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;
+	int i;
 	u32 val, final;
 	bool has_lvds = false;
 	bool has_cpu_edp = false;
 	bool has_panel = false;
 	bool has_ck505 = false;
 	bool can_ssc = false;
+	bool using_ssc_source = false;
 
 	/* We need to take the global config into account */
 	for_each_intel_encoder(dev, encoder) {
@@ -8260,8 +8262,22 @@
 		can_ssc = true;
 	}
 
-	DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d\n",
-		      has_panel, has_lvds, has_ck505);
+	/* Check if any DPLLs are using the SSC source */
+	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+		u32 temp = I915_READ(PCH_DPLL(i));
+
+		if (!(temp & DPLL_VCO_ENABLE))
+			continue;
+
+		if ((temp & PLL_REF_INPUT_MASK) ==
+		    PLLB_REF_INPUT_SPREADSPECTRUMIN) {
+			using_ssc_source = true;
+			break;
+		}
+	}
+
+	DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n",
+		      has_panel, has_lvds, has_ck505, using_ssc_source);
 
 	/* Ironlake: try to setup display ref clock before DPLL
 	 * enabling. This is only under driver's control after
@@ -8298,9 +8314,9 @@
 				final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
 		} else
 			final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
-	} else {
-		final |= DREF_SSC_SOURCE_DISABLE;
-		final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+	} else if (using_ssc_source) {
+		final |= DREF_SSC_SOURCE_ENABLE;
+		final |= DREF_SSC1_ENABLE;
 	}
 
 	if (final == val)
@@ -8346,7 +8362,7 @@
 		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
 	} else {
-		DRM_DEBUG_KMS("Disabling SSC entirely\n");
+		DRM_DEBUG_KMS("Disabling CPU source output\n");
 
 		val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
@@ -8357,16 +8373,20 @@
 		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
 
-		/* Turn off the SSC source */
-		val &= ~DREF_SSC_SOURCE_MASK;
-		val |= DREF_SSC_SOURCE_DISABLE;
+		if (!using_ssc_source) {
+			DRM_DEBUG_KMS("Disabling SSC source\n");
 
-		/* Turn off SSC1 */
-		val &= ~DREF_SSC1_ENABLE;
+			/* Turn off the SSC source */
+			val &= ~DREF_SSC_SOURCE_MASK;
+			val |= DREF_SSC_SOURCE_DISABLE;
 
-		I915_WRITE(PCH_DREF_CONTROL, val);
-		POSTING_READ(PCH_DREF_CONTROL);
-		udelay(200);
+			/* Turn off SSC1 */
+			val &= ~DREF_SSC1_ENABLE;
+
+			I915_WRITE(PCH_DREF_CONTROL, val);
+			POSTING_READ(PCH_DREF_CONTROL);
+			udelay(200);
+		}
 	}
 
 	BUG_ON(val != final);
@@ -9669,6 +9689,8 @@
 	sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, data);
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
+	I915_WRITE(CDCLK_FREQ, DIV_ROUND_CLOSEST(cdclk, 1000) - 1);
+
 	intel_update_cdclk(dev);
 
 	WARN(cdclk != dev_priv->cdclk_freq,
@@ -10723,6 +10745,10 @@
 		return;
 
 	intel_runtime_pm_get(dev_priv);
+
+	if (NEEDS_RC6_CTX_CORRUPTION_WA(dev_priv))
+		intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
 	i915_update_gfx_val(dev_priv);
 	if (INTEL_INFO(dev)->gen >= 6)
 		gen6_rps_busy(dev_priv);
@@ -10741,6 +10767,11 @@
 	if (INTEL_INFO(dev)->gen >= 6)
 		gen6_rps_idle(dev->dev_private);
 
+	if (NEEDS_RC6_CTX_CORRUPTION_WA(dev_priv)) {
+		i915_rc6_ctx_wa_check(dev_priv);
+		intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+	}
+
 	intel_runtime_pm_put(dev_priv);
 }
 
@@ -13537,11 +13568,12 @@
 	int max_scale = DRM_PLANE_HELPER_NO_SCALING;
 	bool can_position = false;
 
-	/* use scaler when colorkey is not required */
-	if (INTEL_INFO(plane->dev)->gen >= 9 &&
-	    state->ckey.flags == I915_SET_COLORKEY_NONE) {
-		min_scale = 1;
-		max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state);
+	if (INTEL_INFO(plane->dev)->gen >= 9) {
+		/* use scaler when colorkey is not required */
+		if (state->ckey.flags == I915_SET_COLORKEY_NONE) {
+			min_scale = 1;
+			max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state);
+		}
 		can_position = true;
 	}
 
@@ -14137,6 +14169,8 @@
 		if (I915_READ(PCH_DP_D) & DP_DETECTED)
 			intel_dp_init(dev, PCH_DP_D, PORT_D);
 	} else if (IS_VALLEYVIEW(dev)) {
+		bool has_edp, has_port;
+
 		/*
 		 * The DP_DETECTED bit is the latched state of the DDC
 		 * SDA pin at boot. However since eDP doesn't require DDC
@@ -14145,27 +14179,37 @@
 		 * Thus we can't rely on the DP_DETECTED bit alone to detect
 		 * eDP ports. Consult the VBT as well as DP_DETECTED to
 		 * detect eDP ports.
+		 *
+		 * Sadly the straps seem to be missing sometimes even for HDMI
+		 * ports (eg. on Voyo V3 - CHT x7-Z8700), so check both strap
+		 * and VBT for the presence of the port. Additionally we can't
+		 * trust the port type the VBT declares as we've seen at least
+		 * HDMI ports that the VBT claim are DP or eDP.
 		 */
-		if (I915_READ(VLV_HDMIB) & SDVO_DETECTED &&
-		    !intel_dp_is_edp(dev, PORT_B))
+		has_edp = intel_dp_is_edp(dev, PORT_B);
+		has_port = intel_bios_is_port_present(dev_priv, PORT_B);
+		if (I915_READ(VLV_DP_B) & DP_DETECTED || has_port)
+			has_edp &= intel_dp_init(dev, VLV_DP_B, PORT_B);
+		if ((I915_READ(VLV_HDMIB) & SDVO_DETECTED || has_port) && !has_edp)
 			intel_hdmi_init(dev, VLV_HDMIB, PORT_B);
-		if (I915_READ(VLV_DP_B) & DP_DETECTED ||
-		    intel_dp_is_edp(dev, PORT_B))
-			intel_dp_init(dev, VLV_DP_B, PORT_B);
 
-		if (I915_READ(VLV_HDMIC) & SDVO_DETECTED &&
-		    !intel_dp_is_edp(dev, PORT_C))
+		has_edp = intel_dp_is_edp(dev, PORT_C);
+		has_port = intel_bios_is_port_present(dev_priv, PORT_C);
+		if (I915_READ(VLV_DP_C) & DP_DETECTED || has_port)
+			has_edp &= intel_dp_init(dev, VLV_DP_C, PORT_C);
+		if ((I915_READ(VLV_HDMIC) & SDVO_DETECTED || has_port) && !has_edp)
 			intel_hdmi_init(dev, VLV_HDMIC, PORT_C);
-		if (I915_READ(VLV_DP_C) & DP_DETECTED ||
-		    intel_dp_is_edp(dev, PORT_C))
-			intel_dp_init(dev, VLV_DP_C, PORT_C);
 
 		if (IS_CHERRYVIEW(dev)) {
-			/* eDP not supported on port D, so don't check VBT */
-			if (I915_READ(CHV_HDMID) & SDVO_DETECTED)
-				intel_hdmi_init(dev, CHV_HDMID, PORT_D);
-			if (I915_READ(CHV_DP_D) & DP_DETECTED)
+			/*
+			 * eDP not supported on port D,
+			 * so no need to worry about it
+			 */
+			has_port = intel_bios_is_port_present(dev_priv, PORT_D);
+			if (I915_READ(CHV_DP_D) & DP_DETECTED || has_port)
 				intel_dp_init(dev, CHV_DP_D, PORT_D);
+			if (I915_READ(CHV_HDMID) & SDVO_DETECTED || has_port)
+				intel_hdmi_init(dev, CHV_HDMID, PORT_D);
 		}
 
 		intel_dsi_init(dev);
@@ -15113,6 +15157,8 @@
 		WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0);
 		crtc->base.state->active = crtc->active;
 		crtc->base.enabled = crtc->active;
+		crtc->base.state->connector_mask = 0;
+		crtc->base.state->encoder_mask = 0;
 
 		/* Because we only establish the connector -> encoder ->
 		 * crtc links if something is active, this means the
@@ -15315,7 +15361,23 @@
 	for_each_intel_connector(dev, connector) {
 		if (connector->get_hw_state(connector)) {
 			connector->base.dpms = DRM_MODE_DPMS_ON;
-			connector->base.encoder = &connector->encoder->base;
+
+			encoder = connector->encoder;
+			connector->base.encoder = &encoder->base;
+
+			if (encoder->base.crtc &&
+			    encoder->base.crtc->state->active) {
+				/*
+				 * This has to be done during hardware readout
+				 * because anything calling .crtc_disable may
+				 * rely on the connector_mask being accurate.
+				 */
+				encoder->base.crtc->state->connector_mask |=
+					1 << drm_connector_index(&connector->base);
+				encoder->base.crtc->state->encoder_mask |=
+					1 << drm_encoder_index(&encoder->base);
+			}
+
 		} else {
 			connector->base.dpms = DRM_MODE_DPMS_OFF;
 			connector->base.encoder = NULL;
@@ -15565,6 +15627,8 @@
 	mutex_lock(&dev->struct_mutex);
 	intel_cleanup_gt_powersave(dev);
 	mutex_unlock(&dev->struct_mutex);
+
+	intel_teardown_gmbus(dev);
 }
 
 /*
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_dp.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_dp.c
@@ -3628,8 +3628,7 @@
 intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP,
 			uint8_t dp_train_pat)
 {
-	if (!intel_dp->train_set_valid)
-		memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
+	memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
 	intel_dp_set_signal_levels(intel_dp, DP);
 	return intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
 }
@@ -3746,22 +3745,6 @@
 			break;
 		}
 
-		/*
-		 * if we used previously trained voltage and pre-emphasis values
-		 * and we don't get clock recovery, reset link training values
-		 */
-		if (intel_dp->train_set_valid) {
-			DRM_DEBUG_KMS("clock recovery not ok, reset");
-			/* clear the flag as we are not reusing train set */
-			intel_dp->train_set_valid = false;
-			if (!intel_dp_reset_link_train(intel_dp, &DP,
-						       DP_TRAINING_PATTERN_1 |
-						       DP_LINK_SCRAMBLING_DISABLE)) {
-				DRM_ERROR("failed to enable link training\n");
-				return;
-			}
-			continue;
-		}
 
 		/* Check to see if we've tried the max voltage */
 		for (i = 0; i < intel_dp->lane_count; i++)
@@ -3854,7 +3837,6 @@
 		/* Make sure clock is still ok */
 		if (!drm_dp_clock_recovery_ok(link_status,
 					      intel_dp->lane_count)) {
-			intel_dp->train_set_valid = false;
 			intel_dp_link_training_clock_recovery(intel_dp);
 			intel_dp_set_link_train(intel_dp, &DP,
 						training_pattern |
@@ -3871,7 +3853,6 @@
 
 		/* Try 5 times, then try clock recovery if that fails */
 		if (tries > 5) {
-			intel_dp->train_set_valid = false;
 			intel_dp_link_training_clock_recovery(intel_dp);
 			intel_dp_set_link_train(intel_dp, &DP,
 						training_pattern |
@@ -3893,10 +3874,8 @@
 
 	intel_dp->DP = DP;
 
-	if (channel_eq) {
-		intel_dp->train_set_valid = true;
+	if (channel_eq)
 		DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
-	}
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
@@ -4613,20 +4592,20 @@
 	return I915_READ(PORT_HOTPLUG_STAT) & bit;
 }
 
-static bool vlv_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool gm45_digital_port_connected(struct drm_i915_private *dev_priv,
+					struct intel_digital_port *port)
 {
 	u32 bit;
 
 	switch (port->port) {
 	case PORT_B:
-		bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
+		bit = PORTB_HOTPLUG_LIVE_STATUS_GM45;
 		break;
 	case PORT_C:
-		bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
+		bit = PORTC_HOTPLUG_LIVE_STATUS_GM45;
 		break;
 	case PORT_D:
-		bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
+		bit = PORTD_HOTPLUG_LIVE_STATUS_GM45;
 		break;
 	default:
 		MISSING_CASE(port->port);
@@ -4669,7 +4648,7 @@
  *
  * Return %true if @port is connected, %false otherwise.
  */
-bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
+static bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
 					 struct intel_digital_port *port)
 {
 	if (HAS_PCH_IBX(dev_priv))
@@ -4678,8 +4657,8 @@
 		return cpt_digital_port_connected(dev_priv, port);
 	else if (IS_BROXTON(dev_priv))
 		return bxt_digital_port_connected(dev_priv, port);
-	else if (IS_VALLEYVIEW(dev_priv))
-		return vlv_digital_port_connected(dev_priv, port);
+	else if (IS_GM45(dev_priv))
+		return gm45_digital_port_connected(dev_priv, port);
 	else
 		return g4x_digital_port_connected(dev_priv, port);
 }
@@ -5035,7 +5014,7 @@
 	kfree(intel_dig_port);
 }
 
-static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
+void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
 
@@ -5077,15 +5056,17 @@
 	edp_panel_vdd_schedule_off(intel_dp);
 }
 
-static void intel_dp_encoder_reset(struct drm_encoder *encoder)
+void intel_dp_encoder_reset(struct drm_encoder *encoder)
 {
-	struct intel_dp *intel_dp;
+	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+	if (!HAS_DDI(dev_priv))
+		intel_dp->DP = I915_READ(intel_dp->output_reg);
 
 	if (to_intel_encoder(encoder)->type != INTEL_OUTPUT_EDP)
 		return;
 
-	intel_dp = enc_to_intel_dp(encoder);
-
 	pps_lock(intel_dp);
 
 	/*
@@ -5157,9 +5138,6 @@
 	intel_display_power_get(dev_priv, power_domain);
 
 	if (long_hpd) {
-		/* indicate that we need to restart link training */
-		intel_dp->train_set_valid = false;
-
 		if (!intel_digital_port_connected(dev_priv, intel_dig_port))
 			goto mst_fail;
 
@@ -6135,8 +6113,9 @@
 	return true;
 }
 
-void
-intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
+bool intel_dp_init(struct drm_device *dev,
+		   int output_reg,
+		   enum port port)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_digital_port *intel_dig_port;
@@ -6146,7 +6125,7 @@
 
 	intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
 	if (!intel_dig_port)
-		return;
+		return false;
 
 	intel_connector = intel_connector_alloc();
 	if (!intel_connector)
@@ -6201,15 +6180,14 @@
 	if (!intel_dp_init_connector(intel_dig_port, intel_connector))
 		goto err_init_connector;
 
-	return;
+	return true;
 
 err_init_connector:
 	drm_encoder_cleanup(encoder);
 	kfree(intel_connector);
 err_connector_alloc:
 	kfree(intel_dig_port);
-
-	return;
+	return false;
 }
 
 void intel_dp_mst_suspend(struct drm_device *dev)
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_dp_mst.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -477,6 +477,8 @@
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 	struct drm_device *dev = connector->dev;
 
+	intel_connector->unregister(intel_connector);
+
 	/* need to nuke the connector */
 	drm_modeset_lock_all(dev);
 	if (connector->state->crtc) {
@@ -490,11 +492,7 @@
 
 		WARN(ret, "Disabling mst crtc failed with %i\n", ret);
 	}
-	drm_modeset_unlock_all(dev);
 
-	intel_connector->unregister(intel_connector);
-
-	drm_modeset_lock_all(dev);
 	intel_connector_remove_from_fbdev(intel_connector);
 	drm_connector_cleanup(connector);
 	drm_modeset_unlock_all(dev);
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_drv.h
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_drv.h
@@ -783,7 +783,6 @@
 				     bool has_aux_irq,
 				     int send_bytes,
 				     uint32_t aux_clock_divider);
-	bool train_set_valid;
 
 	/* Displayport compliance testing */
 	unsigned long compliance_test_type;
@@ -799,6 +798,8 @@
 	struct intel_hdmi hdmi;
 	enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool);
 	bool release_cl2_override;
+	/* for communication with audio component; protected by av_mutex */
+	const struct drm_connector *audio_connector;
 };
 
 struct intel_dp_mst_encoder {
@@ -970,7 +971,7 @@
 
 /* intel_crt.c */
 void intel_crt_init(struct drm_device *dev);
-
+void intel_crt_reset(struct drm_encoder *encoder);
 
 /* intel_ddi.c */
 void intel_prepare_ddi(struct drm_device *dev);
@@ -1178,9 +1179,9 @@
 int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
 int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
 
-unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
-				     struct drm_i915_gem_object *obj,
-				     unsigned int plane);
+u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
+			   struct drm_i915_gem_object *obj,
+			   unsigned int plane);
 
 u32 skl_plane_ctl_format(uint32_t pixel_format);
 u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
@@ -1196,7 +1197,7 @@
 void assert_csr_loaded(struct drm_i915_private *dev_priv);
 
 /* intel_dp.c */
-void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
+bool intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
 bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 			     struct intel_connector *intel_connector);
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
@@ -1204,6 +1205,8 @@
 void intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
+void intel_dp_encoder_reset(struct drm_encoder *encoder);
+void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
 void intel_dp_encoder_destroy(struct drm_encoder *encoder);
 int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
 bool intel_dp_compute_config(struct intel_encoder *encoder,
@@ -1230,8 +1233,6 @@
 void intel_edp_drrs_invalidate(struct drm_device *dev,
 		unsigned frontbuffer_bits);
 void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
-bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
-					 struct intel_digital_port *port);
 void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
 
 /* intel_dp_mst.c */
@@ -1243,6 +1244,8 @@
 
 /* intel_dvo.c */
 void intel_dvo_init(struct drm_device *dev);
+/* intel_hotplug.c */
+void intel_hpd_poll_init(struct drm_i915_private *dev_priv);
 
 
 /* legacy fbdev emulation in intel_fbdev.c */
@@ -1411,6 +1414,9 @@
 void intel_disable_gt_powersave(struct drm_device *dev);
 void intel_suspend_gt_powersave(struct drm_device *dev);
 void intel_reset_gt_powersave(struct drm_device *dev);
+bool i915_rc6_ctx_wa_check(struct drm_i915_private *i915);
+void i915_rc6_ctx_wa_suspend(struct drm_i915_private *i915);
+void i915_rc6_ctx_wa_resume(struct drm_i915_private *i915);
 void gen6_update_ring_freq(struct drm_device *dev);
 void gen6_rps_busy(struct drm_i915_private *dev_priv);
 void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
@@ -207,7 +207,12 @@
 	gpio = *data++;
 
 	/* pull up/down */
-	action = *data++;
+	action = *data++ & 1;
+
+	if (gpio >= ARRAY_SIZE(gtable)) {
+		DRM_DEBUG_KMS("unknown gpio %u\n", gpio);
+		goto out;
+	}
 
 	function = gtable[gpio].function_reg;
 	pad = gtable[gpio].pad_reg;
@@ -226,6 +231,7 @@
 	vlv_gpio_nc_write(dev_priv, pad, val);
 	mutex_unlock(&dev_priv->sb_lock);
 
+out:
 	return data;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_fbdev.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_fbdev.c
@@ -362,12 +362,12 @@
 	uint64_t conn_configured = 0, mask;
 	int pass = 0;
 
-	save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool),
+	save_enabled = kcalloc(fb_helper->connector_count, sizeof(bool),
 			       GFP_KERNEL);
 	if (!save_enabled)
 		return false;
 
-	memcpy(save_enabled, enabled, dev->mode_config.num_connector);
+	memcpy(save_enabled, enabled, fb_helper->connector_count);
 	mask = (1 << fb_helper->connector_count) - 1;
 retry:
 	for (i = 0; i < fb_helper->connector_count; i++) {
@@ -501,7 +501,7 @@
 	if (fallback) {
 bail:
 		DRM_DEBUG_KMS("Not using firmware configuration\n");
-		memcpy(enabled, save_enabled, dev->mode_config.num_connector);
+		memcpy(enabled, save_enabled, fb_helper->connector_count);
 		kfree(save_enabled);
 		return false;
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_hdmi.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1331,19 +1331,18 @@
 }
 
 static bool
-intel_hdmi_set_edid(struct drm_connector *connector, bool force)
+intel_hdmi_set_edid(struct drm_connector *connector)
 {
 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-	struct edid *edid = NULL;
+	struct edid *edid;
 	bool connected = false;
 
 	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-	if (force)
-		edid = drm_get_edid(connector,
-				    intel_gmbus_get_adapter(dev_priv,
-				    intel_hdmi->ddc_bus));
+	edid = drm_get_edid(connector,
+			    intel_gmbus_get_adapter(dev_priv,
+			    intel_hdmi->ddc_bus));
 
 	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
 
@@ -1371,29 +1370,16 @@
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
 	enum drm_connector_status status;
-	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
-	bool live_status = false;
-	unsigned int try;
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
 
 	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-	for (try = 0; !live_status && try < 9; try++) {
-		if (try)
-			msleep(10);
-		live_status = intel_digital_port_connected(dev_priv,
-				hdmi_to_dig_port(intel_hdmi));
-	}
-
-	if (!live_status)
-		DRM_DEBUG_KMS("Live status not up!");
-
 	intel_hdmi_unset_edid(connector);
 
-	if (intel_hdmi_set_edid(connector, live_status)) {
+	if (intel_hdmi_set_edid(connector)) {
 		struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 
 		hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
@@ -1419,7 +1405,7 @@
 	if (connector->status != connector_status_connected)
 		return;
 
-	intel_hdmi_set_edid(connector, true);
+	intel_hdmi_set_edid(connector);
 	hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
 }
 
@@ -2011,6 +1997,50 @@
 	intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
 }
 
+static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
+			     enum port port)
+{
+	const struct ddi_vbt_port_info *info =
+		&dev_priv->vbt.ddi_port_info[port];
+	u8 ddc_pin;
+
+	if (info->alternate_ddc_pin) {
+		DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (VBT)\n",
+			      info->alternate_ddc_pin, port_name(port));
+		return info->alternate_ddc_pin;
+	}
+
+	switch (port) {
+	case PORT_B:
+		if (IS_BROXTON(dev_priv))
+			ddc_pin = GMBUS_PIN_1_BXT;
+		else
+			ddc_pin = GMBUS_PIN_DPB;
+		break;
+	case PORT_C:
+		if (IS_BROXTON(dev_priv))
+			ddc_pin = GMBUS_PIN_2_BXT;
+		else
+			ddc_pin = GMBUS_PIN_DPC;
+		break;
+	case PORT_D:
+		if (IS_CHERRYVIEW(dev_priv))
+			ddc_pin = GMBUS_PIN_DPD_CHV;
+		else
+			ddc_pin = GMBUS_PIN_DPD;
+		break;
+	default:
+		MISSING_CASE(port);
+		ddc_pin = GMBUS_PIN_DPB;
+		break;
+	}
+
+	DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (platform default)\n",
+		      ddc_pin, port_name(port));
+
+	return ddc_pin;
+}
+
 void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
 			       struct intel_connector *intel_connector)
 {
@@ -2020,7 +2050,9 @@
 	struct drm_device *dev = intel_encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum port port = intel_dig_port->port;
-	uint8_t alternate_ddc_pin;
+
+	DRM_DEBUG_KMS("Adding HDMI connector on port %c\n",
+		      port_name(port));
 
 	drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
 			   DRM_MODE_CONNECTOR_HDMIA);
@@ -2030,12 +2062,10 @@
 	connector->doublescan_allowed = 0;
 	connector->stereo_allowed = 1;
 
+	intel_hdmi->ddc_bus = intel_hdmi_ddc_pin(dev_priv, port);
+
 	switch (port) {
 	case PORT_B:
-		if (IS_BROXTON(dev_priv))
-			intel_hdmi->ddc_bus = GMBUS_PIN_1_BXT;
-		else
-			intel_hdmi->ddc_bus = GMBUS_PIN_DPB;
 		/*
 		 * On BXT A0/A1, sw needs to activate DDIA HPD logic and
 		 * interrupts to check the external panel connection.
@@ -2046,46 +2076,17 @@
 			intel_encoder->hpd_pin = HPD_PORT_B;
 		break;
 	case PORT_C:
-		if (IS_BROXTON(dev_priv))
-			intel_hdmi->ddc_bus = GMBUS_PIN_2_BXT;
-		else
-			intel_hdmi->ddc_bus = GMBUS_PIN_DPC;
 		intel_encoder->hpd_pin = HPD_PORT_C;
 		break;
 	case PORT_D:
-		if (WARN_ON(IS_BROXTON(dev_priv)))
-			intel_hdmi->ddc_bus = GMBUS_PIN_DISABLED;
-		else if (IS_CHERRYVIEW(dev_priv))
-			intel_hdmi->ddc_bus = GMBUS_PIN_DPD_CHV;
-		else
-			intel_hdmi->ddc_bus = GMBUS_PIN_DPD;
 		intel_encoder->hpd_pin = HPD_PORT_D;
 		break;
 	case PORT_E:
-		/* On SKL PORT E doesn't have seperate GMBUS pin
-		 *  We rely on VBT to set a proper alternate GMBUS pin. */
-		alternate_ddc_pin =
-			dev_priv->vbt.ddi_port_info[PORT_E].alternate_ddc_pin;
-		switch (alternate_ddc_pin) {
-		case DDC_PIN_B:
-			intel_hdmi->ddc_bus = GMBUS_PIN_DPB;
-			break;
-		case DDC_PIN_C:
-			intel_hdmi->ddc_bus = GMBUS_PIN_DPC;
-			break;
-		case DDC_PIN_D:
-			intel_hdmi->ddc_bus = GMBUS_PIN_DPD;
-			break;
-		default:
-			MISSING_CASE(alternate_ddc_pin);
-		}
 		intel_encoder->hpd_pin = HPD_PORT_E;
 		break;
-	case PORT_A:
-		intel_encoder->hpd_pin = HPD_PORT_A;
-		/* Internal port only for eDP. */
 	default:
-		BUG();
+		MISSING_CASE(port);
+		return;
 	}
 
 	if (IS_VALLEYVIEW(dev)) {
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_hotplug.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_hotplug.c
@@ -453,26 +453,20 @@
  *
  * This is a separate step from interrupt enabling to simplify the locking rules
  * in the driver load and resume code.
+ *
+ * Also see: intel_hpd_poll_init(), which enables connector polling
  */
 void intel_hpd_init(struct drm_i915_private *dev_priv)
 {
-	struct drm_device *dev = dev_priv->dev;
-	struct drm_mode_config *mode_config = &dev->mode_config;
-	struct drm_connector *connector;
 	int i;
 
 	for_each_hpd_pin(i) {
 		dev_priv->hotplug.stats[i].count = 0;
 		dev_priv->hotplug.stats[i].state = HPD_ENABLED;
 	}
-	list_for_each_entry(connector, &mode_config->connector_list, head) {
-		struct intel_connector *intel_connector = to_intel_connector(connector);
-		connector->polled = intel_connector->polled;
-		if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
-			connector->polled = DRM_CONNECTOR_POLL_HPD;
-		if (intel_connector->mst_port)
-			connector->polled = DRM_CONNECTOR_POLL_HPD;
-	}
+
+	WRITE_ONCE(dev_priv->hotplug.poll_enabled, false);
+	schedule_work(&dev_priv->hotplug.poll_init_work);
 
 	/*
 	 * Interrupt setup is already guaranteed to be single-threaded, this is
@@ -480,14 +474,90 @@
 	 */
 	spin_lock_irq(&dev_priv->irq_lock);
 	if (dev_priv->display.hpd_irq_setup)
-		dev_priv->display.hpd_irq_setup(dev);
+		dev_priv->display.hpd_irq_setup(dev_priv->dev);
 	spin_unlock_irq(&dev_priv->irq_lock);
 }
 
+void i915_hpd_poll_init_work(struct work_struct *work) {
+	struct drm_i915_private *dev_priv =
+		container_of(work, struct drm_i915_private,
+			     hotplug.poll_init_work);
+	struct drm_device *dev = dev_priv->dev;
+	struct drm_mode_config *mode_config = &dev->mode_config;
+	struct drm_connector *connector;
+	bool enabled;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	enabled = READ_ONCE(dev_priv->hotplug.poll_enabled);
+
+	list_for_each_entry(connector, &mode_config->connector_list, head) {
+		struct intel_connector *intel_connector =
+			to_intel_connector(connector);
+		connector->polled = intel_connector->polled;
+
+		/* MST has a dynamic intel_connector->encoder and it's reprobing
+		 * is all handled by the MST helpers. */
+		if (intel_connector->mst_port)
+			continue;
+
+		if (!connector->polled && I915_HAS_HOTPLUG(dev) &&
+		    intel_connector->encoder->hpd_pin > HPD_NONE) {
+			connector->polled = enabled ?
+				DRM_CONNECTOR_POLL_CONNECT |
+				DRM_CONNECTOR_POLL_DISCONNECT :
+				DRM_CONNECTOR_POLL_HPD;
+		}
+	}
+
+	if (enabled)
+		drm_kms_helper_poll_enable_locked(dev);
+
+	mutex_unlock(&dev->mode_config.mutex);
+
+	/*
+	 * We might have missed any hotplugs that happened while we were
+	 * in the middle of disabling polling
+	 */
+	if (!enabled)
+		drm_helper_hpd_irq_event(dev);
+}
+
+/**
+ * intel_hpd_poll_init - enables/disables polling for connectors with hpd
+ * @dev_priv: i915 device instance
+ * @enabled: Whether to enable or disable polling
+ *
+ * This function enables polling for all connectors, regardless of whether or
+ * not they support hotplug detection. Under certain conditions HPD may not be
+ * functional. On most Intel GPUs, this happens when we enter runtime suspend.
+ * On Valleyview and Cherryview systems, this also happens when we shut off all
+ * of the powerwells.
+ *
+ * Since this function can get called in contexts where we're already holding
+ * dev->mode_config.mutex, we do the actual hotplug enabling in a seperate
+ * worker.
+ *
+ * Also see: intel_hpd_init(), which restores hpd handling.
+ */
+void intel_hpd_poll_init(struct drm_i915_private *dev_priv)
+{
+	WRITE_ONCE(dev_priv->hotplug.poll_enabled, true);
+
+	/*
+	 * We might already be holding dev->mode_config.mutex, so do this in a
+	 * seperate worker
+	 * As well, there's no issue if we race here since we always reschedule
+	 * this worker anyway
+	 */
+	schedule_work(&dev_priv->hotplug.poll_init_work);
+}
+
 void intel_hpd_init_work(struct drm_i915_private *dev_priv)
 {
 	INIT_WORK(&dev_priv->hotplug.hotplug_work, i915_hotplug_work_func);
 	INIT_WORK(&dev_priv->hotplug.dig_port_work, i915_digport_work_func);
+	INIT_WORK(&dev_priv->hotplug.poll_init_work, i915_hpd_poll_init_work);
 	INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work,
 			  intel_hpd_irq_storm_reenable_work);
 }
@@ -504,5 +574,33 @@
 
 	cancel_work_sync(&dev_priv->hotplug.dig_port_work);
 	cancel_work_sync(&dev_priv->hotplug.hotplug_work);
+	cancel_work_sync(&dev_priv->hotplug.poll_init_work);
 	cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work);
 }
+
+bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
+{
+	bool ret = false;
+
+	if (pin == HPD_NONE)
+		return false;
+
+	spin_lock_irq(&dev_priv->irq_lock);
+	if (dev_priv->hotplug.stats[pin].state == HPD_ENABLED) {
+		dev_priv->hotplug.stats[pin].state = HPD_DISABLED;
+		ret = true;
+	}
+	spin_unlock_irq(&dev_priv->irq_lock);
+
+	return ret;
+}
+
+void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
+{
+	if (pin == HPD_NONE)
+		return;
+
+	spin_lock_irq(&dev_priv->irq_lock);
+	dev_priv->hotplug.stats[pin].state = HPD_ENABLED;
+	spin_unlock_irq(&dev_priv->irq_lock);
+}
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_i2c.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_i2c.c
@@ -440,7 +440,9 @@
 gmbus_is_index_read(struct i2c_msg *msgs, int i, int num)
 {
 	return (i + 1 < num &&
-		!(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 &&
+		msgs[i].addr == msgs[i + 1].addr &&
+		!(msgs[i].flags & I2C_M_RD) &&
+		(msgs[i].len == 1 || msgs[i].len == 2) &&
 		(msgs[i + 1].flags & I2C_M_RD));
 }
 
@@ -675,7 +677,7 @@
 	return 0;
 
 err:
-	while (--pin) {
+	while (pin--) {
 		if (!intel_gmbus_is_valid_pin(dev_priv, pin))
 			continue;
 
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_lrc.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_lrc.c
@@ -776,11 +776,11 @@
 		if (unlikely(total_bytes > remain_usable)) {
 			/*
 			 * The base request will fit but the reserved space
-			 * falls off the end. So only need to to wait for the
-			 * reserved size after flushing out the remainder.
+			 * falls off the end. So don't need an immediate wrap
+			 * and only need to effectively wait for the reserved
+			 * size space from the start of ringbuffer.
 			 */
 			wait_bytes = remain_actual + ringbuf->reserved_size;
-			need_wrap = true;
 		} else if (total_bytes > ringbuf->space) {
 			/* No wrapping required, just waiting. */
 			wait_bytes = total_bytes;
@@ -1706,6 +1706,7 @@
 	if (flush_domains) {
 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_lvds.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_lvds.c
@@ -768,6 +768,14 @@
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"),
 		},
 	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Radiant P845",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P845"),
+		},
+	},
 
 	{ }	/* terminating entry */
 };
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_opregion.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_opregion.c
@@ -682,7 +682,7 @@
 	}
 
 	if (!acpi_video_bus) {
-		DRM_ERROR("No ACPI video bus found\n");
+		DRM_DEBUG_KMS("No ACPI video bus found\n");
 		return;
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_pm.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_pm.c
@@ -1789,16 +1789,20 @@
 				   const struct intel_plane_state *pstate,
 				   uint32_t mem_value)
 {
-	int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
+	/*
+	 * We treat the cursor plane as always-on for the purposes of watermark
+	 * calculation.  Until we have two-stage watermark programming merged,
+	 * this is necessary to avoid flickering.
+	 */
+	int cpp = 4;
+	int width = pstate->visible ? pstate->base.crtc_w : 64;
 
-	if (!cstate->base.active || !pstate->visible)
+	if (!cstate->base.active)
 		return 0;
 
 	return ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
 			      cstate->base.adjusted_mode.crtc_htotal,
-			      drm_rect_width(&pstate->dst),
-			      bpp,
-			      mem_value);
+			      width, cpp, mem_value);
 }
 
 /* Only for WM_LP. */
@@ -2093,32 +2097,34 @@
 				GEN9_MEM_LATENCY_LEVEL_MASK;
 
 		/*
+		 * If a level n (n > 1) has a 0us latency, all levels m (m >= n)
+		 * need to be disabled. We make sure to sanitize the values out
+		 * of the punit to satisfy this requirement.
+		 */
+		for (level = 1; level <= max_level; level++) {
+			if (wm[level] == 0) {
+				for (i = level + 1; i <= max_level; i++)
+					wm[i] = 0;
+				break;
+			}
+		}
+
+		/*
 		 * WaWmMemoryReadLatency:skl
 		 *
 		 * punit doesn't take into account the read latency so we need
-		 * to add 2us to the various latency levels we retrieve from
-		 * the punit.
-		 *   - W0 is a bit special in that it's the only level that
-		 *   can't be disabled if we want to have display working, so
-		 *   we always add 2us there.
-		 *   - For levels >=1, punit returns 0us latency when they are
-		 *   disabled, so we respect that and don't add 2us then
-		 *
-		 * Additionally, if a level n (n > 1) has a 0us latency, all
-		 * levels m (m >= n) need to be disabled. We make sure to
-		 * sanitize the values out of the punit to satisfy this
-		 * requirement.
+		 * to add 2us to the various latency levels we retrieve from the
+		 * punit when level 0 response data us 0us.
 		 */
-		wm[0] += 2;
-		for (level = 1; level <= max_level; level++)
-			if (wm[level] != 0)
+		if (wm[0] == 0) {
+			wm[0] += 2;
+			for (level = 1; level <= max_level; level++) {
+				if (wm[level] == 0)
+					break;
 				wm[level] += 2;
-			else {
-				for (i = level + 1; i <= max_level; i++)
-					wm[i] = 0;
-
-				break;
 			}
+		}
+
 	} else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
 		uint64_t sskpd = I915_READ64(MCH_SSKPD);
 
@@ -3880,6 +3886,8 @@
 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
 		hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe));
 
+	memset(active, 0, sizeof(*active));
+
 	active->pipe_enabled = intel_crtc->active;
 
 	if (active->pipe_enabled) {
@@ -4368,6 +4376,12 @@
 		break;
 	}
 
+	/* When byt can survive without system hang with dynamic
+	 * sw freq adjustments, this restriction can be lifted.
+	 */
+	if (IS_VALLEYVIEW(dev_priv))
+		goto skip_hw_write;
+
 	I915_WRITE(GEN6_RP_UP_EI,
 		GT_INTERVAL_FROM_US(dev_priv, ei_up));
 	I915_WRITE(GEN6_RP_UP_THRESHOLD,
@@ -4386,6 +4400,7 @@
 		    GEN6_RP_UP_BUSY_AVG |
 		    GEN6_RP_DOWN_IDLE_AVG);
 
+skip_hw_write:
 	dev_priv->rps.power = new_power;
 	dev_priv->rps.up_threshold = threshold_up;
 	dev_priv->rps.down_threshold = threshold_down;
@@ -4396,8 +4411,9 @@
 {
 	u32 mask = 0;
 
+	/* We use UP_EI_EXPIRED interupts for both up/down in manual mode */
 	if (val > dev_priv->rps.min_freq_softlimit)
-		mask |= GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
+		mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
 	if (val < dev_priv->rps.max_freq_softlimit)
 		mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
 
@@ -4501,7 +4517,7 @@
 {
 	mutex_lock(&dev_priv->rps.hw_lock);
 	if (dev_priv->rps.enabled) {
-		if (dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED))
+		if (dev_priv->pm_rps_events & GEN6_PM_RP_UP_EI_EXPIRED)
 			gen6_rps_reset_ei(dev_priv);
 		I915_WRITE(GEN6_PMINTRMSK,
 			   gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
@@ -4520,7 +4536,8 @@
 		else
 			gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
 		dev_priv->rps.last_adj = 0;
-		I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+		I915_WRITE(GEN6_PMINTRMSK,
+			   gen6_sanitize_rps_pm_mask(dev_priv, ~0));
 	}
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -4574,30 +4591,42 @@
 		gen6_set_rps(dev, val);
 }
 
-static void gen9_disable_rps(struct drm_device *dev)
+static void gen9_disable_rc6(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	I915_WRITE(GEN6_RC_CONTROL, 0);
+}
+
+static void gen9_disable_rps(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
 	I915_WRITE(GEN9_PG_ENABLE, 0);
 }
 
-static void gen6_disable_rps(struct drm_device *dev)
+static void gen6_disable_rc6(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	I915_WRITE(GEN6_RC_CONTROL, 0);
+}
+
+static void gen6_disable_rps(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
 	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
 }
 
-static void cherryview_disable_rps(struct drm_device *dev)
+static void cherryview_disable_rc6(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	I915_WRITE(GEN6_RC_CONTROL, 0);
 }
 
-static void valleyview_disable_rps(struct drm_device *dev)
+static void valleyview_disable_rc6(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -4801,7 +4830,8 @@
 	I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 25);
 
 	/* 3a: Enable RC6 */
-	if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
+	if (!dev_priv->rps.ctx_corrupted &&
+	    intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
 		rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
 	DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
 			"on" : "off");
@@ -4824,7 +4854,7 @@
 	 * WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6.
 	 */
 	if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
-	    ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_F0)))
+	    INTEL_INFO(dev)->gen == 9)
 		I915_WRITE(GEN9_PG_ENABLE, 0);
 	else
 		I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
@@ -4867,7 +4897,8 @@
 		I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */
 
 	/* 3: Enable RC6 */
-	if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
+	if (!dev_priv->rps.ctx_corrupted &&
+	    intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
 		rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
 	intel_print_rc6_info(dev, rc6_mask);
 	if (IS_BROADWELL(dev))
@@ -6111,10 +6142,101 @@
 	dev_priv->ips.corr = (lcfuse & LCFUSE_HIV_MASK);
 }
 
+static bool i915_rc6_ctx_corrupted(struct drm_i915_private *dev_priv)
+{
+	return !I915_READ(GEN8_RC6_CTX_INFO);
+}
+
+static void i915_rc6_ctx_wa_init(struct drm_i915_private *i915)
+{
+	if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
+		return;
+
+	if (i915_rc6_ctx_corrupted(i915)) {
+		DRM_INFO("RC6 context corrupted, disabling runtime power management\n");
+		i915->rps.ctx_corrupted = true;
+		intel_runtime_pm_get(i915);
+	}
+}
+
+static void i915_rc6_ctx_wa_cleanup(struct drm_i915_private *i915)
+{
+	if (i915->rps.ctx_corrupted) {
+		intel_runtime_pm_put(i915);
+		i915->rps.ctx_corrupted = false;
+	}
+}
+
+/**
+ * i915_rc6_ctx_wa_suspend - system suspend sequence for the RC6 CTX WA
+ * @i915: i915 device
+ *
+ * Perform any steps needed to clean up the RC6 CTX WA before system suspend.
+ */
+void i915_rc6_ctx_wa_suspend(struct drm_i915_private *i915)
+{
+	if (i915->rps.ctx_corrupted)
+		intel_runtime_pm_put(i915);
+}
+
+/**
+ * i915_rc6_ctx_wa_resume - system resume sequence for the RC6 CTX WA
+ * @i915: i915 device
+ *
+ * Perform any steps needed to re-init the RC6 CTX WA after system resume.
+ */
+void i915_rc6_ctx_wa_resume(struct drm_i915_private *i915)
+{
+	if (!i915->rps.ctx_corrupted)
+		return;
+
+	if (i915_rc6_ctx_corrupted(i915)) {
+		intel_runtime_pm_get(i915);
+		return;
+	}
+
+	DRM_INFO("RC6 context restored, re-enabling runtime power management\n");
+	i915->rps.ctx_corrupted = false;
+}
+
+static void intel_disable_rc6(struct drm_device *dev);
+
+/**
+ * i915_rc6_ctx_wa_check - check for a new RC6 CTX corruption
+ * @i915: i915 device
+ *
+ * Check if an RC6 CTX corruption has happened since the last check and if so
+ * disable RC6 and runtime power management.
+ *
+ * Return false if no context corruption has happened since the last call of
+ * this function, true otherwise.
+*/
+bool i915_rc6_ctx_wa_check(struct drm_i915_private *i915)
+{
+	if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
+		return false;
+
+	if (i915->rps.ctx_corrupted)
+		return false;
+
+	if (!i915_rc6_ctx_corrupted(i915))
+		return false;
+
+	DRM_NOTE("RC6 context corruption, disabling runtime power management\n");
+
+	intel_disable_rc6(i915->dev);
+	i915->rps.ctx_corrupted = true;
+	intel_runtime_pm_get_noresume(i915);
+
+	return true;
+}
+
 void intel_init_gt_powersave(struct drm_device *dev)
 {
 	i915.enable_rc6 = sanitize_rc6_option(dev, i915.enable_rc6);
 
+	i915_rc6_ctx_wa_init(to_i915(dev));
+
 	if (IS_CHERRYVIEW(dev))
 		cherryview_init_gt_powersave(dev);
 	else if (IS_VALLEYVIEW(dev))
@@ -6127,6 +6249,8 @@
 		return;
 	else if (IS_VALLEYVIEW(dev))
 		valleyview_cleanup_gt_powersave(dev);
+
+	i915_rc6_ctx_wa_cleanup(to_i915(dev));
 }
 
 static void gen6_suspend_rps(struct drm_device *dev)
@@ -6159,6 +6283,38 @@
 	gen6_rps_idle(dev_priv);
 }
 
+static void __intel_disable_rc6(struct drm_device *dev)
+{
+	if (INTEL_INFO(dev)->gen >= 9)
+		gen9_disable_rc6(dev);
+	else if (IS_CHERRYVIEW(dev))
+		cherryview_disable_rc6(dev);
+	else if (IS_VALLEYVIEW(dev))
+		valleyview_disable_rc6(dev);
+	else
+		gen6_disable_rc6(dev);
+}
+
+static void intel_disable_rc6(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = to_i915(dev);
+
+	mutex_lock(&dev_priv->rps.hw_lock);
+	__intel_disable_rc6(dev);
+	mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void intel_disable_rps(struct drm_device *dev)
+{
+	if (IS_CHERRYVIEW(dev) || IS_VALLEYVIEW(dev))
+		return;
+
+	if (INTEL_INFO(dev)->gen >= 9)
+		gen9_disable_rps(dev);
+	else
+		gen6_disable_rps(dev);
+}
+
 void intel_disable_gt_powersave(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6169,16 +6325,12 @@
 		intel_suspend_gt_powersave(dev);
 
 		mutex_lock(&dev_priv->rps.hw_lock);
-		if (INTEL_INFO(dev)->gen >= 9)
-			gen9_disable_rps(dev);
-		else if (IS_CHERRYVIEW(dev))
-			cherryview_disable_rps(dev);
-		else if (IS_VALLEYVIEW(dev))
-			valleyview_disable_rps(dev);
-		else
-			gen6_disable_rps(dev);
+
+		__intel_disable_rc6(dev);
+		intel_disable_rps(dev);
 
 		dev_priv->rps.enabled = false;
+
 		mutex_unlock(&dev_priv->rps.hw_lock);
 	}
 }
@@ -6620,6 +6772,12 @@
 	misccpctl = I915_READ(GEN7_MISCCPCTL);
 	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
 	I915_WRITE(GEN8_L3SQCREG1, BDW_WA_L3SQCREG1_DEFAULT);
+	/*
+	 * Wait at least 100 clocks before re-enabling clock gating. See
+	 * the definition of L3SQCREG1 in BSpec.
+	 */
+	POSTING_READ(GEN8_L3SQCREG1);
+	udelay(1);
 	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
 
 	/*
@@ -6788,7 +6946,18 @@
 
 static void vlv_init_display_clock_gating(struct drm_i915_private *dev_priv)
 {
-	I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
+        u32 val;
+
+        /*
+        * On driver load, a pipe may be active and driving a DSI display.
+        * Preserve DPOUNIT_CLOCK_GATE_DISABLE to avoid the pipe getting stuck
+        * (and never recovering) in this case. intel_dsi_post_disable() will
+        * clear it when we turn off the display.
+        */
+        val = I915_READ(DSPCLK_GATE_D);
+        val &= DPOUNIT_CLOCK_GATE_DISABLE;
+        val |= VRHUNIT_CLOCK_GATE_DISABLE;
+        I915_WRITE(DSPCLK_GATE_D, val);
 
 	/*
 	 * Disable trickle feed and enable pnd deadline calculation
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -347,6 +347,7 @@
 	if (flush_domains) {
 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
 	}
 	if (invalidate_domains) {
@@ -419,6 +420,7 @@
 	if (flush_domains) {
 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
 	}
 	if (invalidate_domains) {
@@ -1920,6 +1922,17 @@
 	return 0;
 }
 
+static void cleanup_phys_status_page(struct intel_engine_cs *ring)
+{
+	struct drm_i915_private *dev_priv = to_i915(ring->dev);
+
+	if (!dev_priv->status_page_dmah)
+		return;
+
+	drm_pci_free(ring->dev, dev_priv->status_page_dmah);
+	ring->status_page.page_addr = NULL;
+}
+
 static void cleanup_status_page(struct intel_engine_cs *ring)
 {
 	struct drm_i915_gem_object *obj;
@@ -1936,9 +1949,9 @@
 
 static int init_status_page(struct intel_engine_cs *ring)
 {
-	struct drm_i915_gem_object *obj;
+	struct drm_i915_gem_object *obj = ring->status_page.obj;
 
-	if ((obj = ring->status_page.obj) == NULL) {
+	if (obj == NULL) {
 		unsigned flags;
 		int ret;
 
@@ -2132,7 +2145,7 @@
 		if (ret)
 			goto error;
 	} else {
-		BUG_ON(ring->id != RCS);
+		WARN_ON(ring->id != RCS);
 		ret = init_phys_status_page(ring);
 		if (ret)
 			goto error;
@@ -2177,7 +2190,12 @@
 	if (ring->cleanup)
 		ring->cleanup(ring);
 
-	cleanup_status_page(ring);
+	if (I915_NEED_GFX_HWS(ring->dev)) {
+		cleanup_status_page(ring);
+	} else {
+		WARN_ON(ring->id != RCS);
+		cleanup_phys_status_page(ring);
+	}
 
 	i915_cmd_parser_fini_ring(ring);
 	i915_gem_batch_pool_fini(&ring->batch_pool);
@@ -2339,11 +2357,11 @@
 		if (unlikely(total_bytes > remain_usable)) {
 			/*
 			 * The base request will fit but the reserved space
-			 * falls off the end. So only need to to wait for the
-			 * reserved size after flushing out the remainder.
+			 * falls off the end. So don't need an immediate wrap
+			 * and only need to effectively wait for the reserved
+			 * size space from the start of ringbuffer.
 			 */
 			wait_bytes = remain_actual + ringbuf->reserved_size;
-			need_wrap = true;
 		} else if (total_bytes > ringbuf->space) {
 			/* No wrapping required, just waiting. */
 			wait_bytes = total_bytes;
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -863,6 +863,7 @@
 
 static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
 {
+	struct intel_encoder *encoder;
 	enum pipe pipe;
 
 	/*
@@ -896,6 +897,12 @@
 
 	intel_hpd_init(dev_priv);
 
+	/* Re-enable the ADPA, if we have one */
+	for_each_intel_encoder(dev_priv->dev, encoder) {
+		if (encoder->type == INTEL_OUTPUT_ANALOG)
+			intel_crt_reset(&encoder->base);
+	}
+
 	i915_redisable_vga_power_on(dev_priv->dev);
 }
 
@@ -906,6 +913,8 @@
 	spin_unlock_irq(&dev_priv->irq_lock);
 
 	vlv_power_sequencer_reset(dev_priv);
+
+	intel_hpd_poll_init(dev_priv);
 }
 
 static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_sprite.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_sprite.c
@@ -195,7 +195,7 @@
 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 	const struct drm_intel_sprite_colorkey *key =
 		&to_intel_plane_state(drm_plane->state)->ckey;
-	unsigned long surf_addr;
+	u32 surf_addr;
 	u32 tile_height, plane_offset, plane_size;
 	unsigned int rotation;
 	int x_offset, y_offset;
@@ -832,8 +832,8 @@
 		hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
 		if (hscale < 0) {
 			DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
-			drm_rect_debug_print(src, true);
-			drm_rect_debug_print(dst, false);
+			drm_rect_debug_print("src: ", src, true);
+			drm_rect_debug_print("dst: ", dst, false);
 
 			return hscale;
 		}
@@ -841,8 +841,8 @@
 		vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
 		if (vscale < 0) {
 			DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
-			drm_rect_debug_print(src, true);
-			drm_rect_debug_print(dst, false);
+			drm_rect_debug_print("src: ", src, true);
+			drm_rect_debug_print("dst: ", dst, false);
 
 			return vscale;
 		}
--- linux-4.4.0.orig/drivers/gpu/drm/i915/intel_uncore.c
+++ linux-4.4.0/drivers/gpu/drm/i915/intel_uncore.c
@@ -635,7 +635,8 @@
 			  "enabling oneshot unclaimed register reporting. "
 			  "Please use i915.mmio_debug=N for more information.\n");
 		__raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
-		i915.mmio_debug = mmio_debug_once--;
+		i915.mmio_debug = mmio_debug_once;
+		mmio_debug_once = false;
 	}
 }
 
@@ -1132,7 +1133,11 @@
 	} else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
 		dev_priv->uncore.funcs.force_wake_get =
 			fw_domains_get_with_thread_status;
-		dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
+		if (IS_HASWELL(dev))
+			dev_priv->uncore.funcs.force_wake_put =
+				fw_domains_put_with_fifo;
+		else
+			dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
 		fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
 			       FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
 	} else if (IS_IVYBRIDGE(dev)) {
--- linux-4.4.0.orig/drivers/gpu/drm/imx/imx-drm-core.c
+++ linux-4.4.0/drivers/gpu/drm/imx/imx-drm-core.c
@@ -26,6 +26,7 @@
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_of.h>
+#include <video/imx-ipu-v3.h>
 
 #include "imx-drm.h"
 
@@ -312,6 +313,7 @@
 		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
 		legacyfb_depth = 16;
 	}
+	drm_helper_disable_unused_functions(drm);
 	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
 				drm->mode_config.num_crtc, MAX_CRTC);
 	if (IS_ERR(imxdrm->fbhelper)) {
@@ -504,6 +506,13 @@
 {
 	struct device_node *np = data;
 
+	/* Special case for DI, dev->of_node may not be set yet */
+	if (strcmp(dev->driver->name, "imx-ipuv3-crtc") == 0) {
+		struct ipu_client_platformdata *pdata = dev->platform_data;
+
+		return pdata->of_node == np;
+	}
+
 	/* Special case for LDB, one device for two channels */
 	if (of_node_cmp(np->name, "lvds-channel") == 0) {
 		np = of_get_parent(np);
--- linux-4.4.0.orig/drivers/gpu/drm/imx/imx-ldb.c
+++ linux-4.4.0/drivers/gpu/drm/imx/imx-ldb.c
@@ -305,6 +305,7 @@
 {
 	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
 	struct imx_ldb *ldb = imx_ldb_ch->ldb;
+	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
 	int mux, ret;
 
 	/*
@@ -321,14 +322,14 @@
 
 	drm_panel_disable(imx_ldb_ch->panel);
 
-	if (imx_ldb_ch == &ldb->channel[0])
+	if (imx_ldb_ch == &ldb->channel[0] || dual)
 		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
-	else if (imx_ldb_ch == &ldb->channel[1])
+	if (imx_ldb_ch == &ldb->channel[1] || dual)
 		ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
 
 	regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
 
-	if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
+	if (dual) {
 		clk_disable_unprepare(ldb->clk[0]);
 		clk_disable_unprepare(ldb->clk[1]);
 	}
@@ -526,6 +527,9 @@
 		return PTR_ERR(imx_ldb->regmap);
 	}
 
+	/* disable LDB by resetting the control register to POR default */
+	regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0);
+
 	imx_ldb->dev = dev;
 
 	if (of_id)
@@ -566,14 +570,14 @@
 		if (ret || i < 0 || i > 1)
 			return -EINVAL;
 
+		if (!of_device_is_available(child))
+			continue;
+
 		if (dual && i > 0) {
 			dev_warn(dev, "dual-channel mode, ignoring second output\n");
 			continue;
 		}
 
-		if (!of_device_is_available(child))
-			continue;
-
 		channel = &imx_ldb->channel[i];
 		channel->ldb = imx_ldb;
 		channel->chno = i;
--- linux-4.4.0.orig/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ linux-4.4.0/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -369,7 +369,7 @@
 
 	ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
 			&ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs,
-			ipu_crtc->dev->of_node);
+			pdata->of_node);
 	if (ret) {
 		dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
 		goto err_put_resources;
--- linux-4.4.0.orig/drivers/gpu/drm/mgag200/mgag200_main.c
+++ linux-4.4.0/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -145,6 +145,8 @@
 	}
 
 	mem = pci_iomap(mdev->dev->pdev, 0, 0);
+	if (!mem)
+		return -ENOMEM;
 
 	mdev->mc.vram_size = mga_probe_vram(mdev, mem);
 
--- linux-4.4.0.orig/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ linux-4.4.0/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -194,7 +194,7 @@
 			}
 		}
 
-		fvv = pllreffreq * testn / testm;
+		fvv = pllreffreq * (n + 1) / (m + 1);
 		fvv = (fvv - 800000) / 50000;
 
 		if (fvv > 15)
@@ -214,6 +214,14 @@
 	WREG_DAC(MGA1064_PIX_PLLC_M, m);
 	WREG_DAC(MGA1064_PIX_PLLC_N, n);
 	WREG_DAC(MGA1064_PIX_PLLC_P, p);
+
+	if (mdev->unique_rev_id >= 0x04) {
+		WREG_DAC(0x1a, 0x09);
+		msleep(20);
+		WREG_DAC(0x1a, 0x01);
+
+	}
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/mgag200/mgag200_ttm.c
+++ linux-4.4.0/drivers/gpu/drm/mgag200/mgag200_ttm.c
@@ -274,6 +274,9 @@
 		return ret;
 	}
 
+	arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
+				   pci_resource_len(dev->pdev, 0));
+
 	mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
 					 pci_resource_len(dev->pdev, 0));
 
@@ -282,10 +285,14 @@
 
 void mgag200_mm_fini(struct mga_device *mdev)
 {
+	struct drm_device *dev = mdev->dev;
+
 	ttm_bo_device_release(&mdev->ttm.bdev);
 
 	mgag200_ttm_global_release(mdev);
 
+	arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
+				pci_resource_len(dev->pdev, 0));
 	arch_phys_wc_del(mdev->fb_mtrr);
 	mdev->fb_mtrr = 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ linux-4.4.0/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -383,19 +383,17 @@
 	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
 	0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
 	0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
-	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
-	0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
-	0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472,
-	0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
-	0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
-	0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed,
-	0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
-	0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
-	0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
-	0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
-	0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d,
-	0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036,
-	0x303c, 0x303c, 0x305e, 0x305f,
+	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2440, 0x2440, 0x2444, 0x2444,
+	0x2448, 0x244d, 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470,
+	0x2472, 0x2472, 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3,
+	0x24e4, 0x24ef, 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e,
+	0x2510, 0x2511, 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea,
+	0x25ec, 0x25ed, 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617,
+	0x261a, 0x261a, 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0,
+	0x26c4, 0x26ce, 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9,
+	0x26ec, 0x26ec, 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743,
+	0x300c, 0x300e, 0x301c, 0x301d, 0x302a, 0x302a, 0x302c, 0x302d,
+	0x3030, 0x3031, 0x3034, 0x3036, 0x303c, 0x303c, 0x305e, 0x305f,
 	~0   /* sentinel */
 };
 
--- linux-4.4.0.orig/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ linux-4.4.0/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -204,7 +204,14 @@
 void adreno_flush(struct msm_gpu *gpu)
 {
 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
-	uint32_t wptr = get_wptr(gpu->rb);
+	uint32_t wptr;
+
+	/*
+	 * Mask wptr value that we calculate to fit in the HW range. This is
+	 * to account for the possibility that the last command fit exactly into
+	 * the ringbuffer and rb->next hasn't wrapped to zero yet
+	 */
+	wptr = get_wptr(gpu->rb) & ((gpu->rb->size / 4) - 1);
 
 	/* ensure writes to ringbuffer have hit system memory: */
 	mb();
--- linux-4.4.0.orig/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ linux-4.4.0/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -30,6 +30,8 @@
 #include "dsi.xml.h"
 #include "dsi_cfg.h"
 
+#define DSI_RESET_TOGGLE_DELAY_MS 20
+
 static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
 {
 	u32 ver;
@@ -764,7 +766,7 @@
 	wmb(); /* clocks need to be enabled before reset */
 
 	dsi_write(msm_host, REG_DSI_RESET, 1);
-	wmb(); /* make sure reset happen */
+	msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */
 	dsi_write(msm_host, REG_DSI_RESET, 0);
 }
 
@@ -1111,7 +1113,7 @@
 
 	/* dsi controller can only be reset while clocks are running */
 	dsi_write(msm_host, REG_DSI_RESET, 1);
-	wmb();	/* make sure reset happen */
+	msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */
 	dsi_write(msm_host, REG_DSI_RESET, 0);
 	wmb();	/* controller out of reset */
 	dsi_write(msm_host, REG_DSI_CTRL, data0);
--- linux-4.4.0.orig/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ linux-4.4.0/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -302,7 +302,7 @@
 	return num;
 }
 
-static int dsi_mgr_connector_mode_valid(struct drm_connector *connector,
+static enum drm_mode_status dsi_mgr_connector_mode_valid(struct drm_connector *connector,
 				struct drm_display_mode *mode)
 {
 	int id = dsi_mgr_connector_get_id(connector);
@@ -434,6 +434,7 @@
 	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
 	struct mipi_dsi_host *host = msm_dsi->host;
 	struct drm_panel *panel = msm_dsi->panel;
+	struct msm_dsi_pll *src_pll;
 	bool is_dual_dsi = IS_DUAL_DSI();
 	int ret;
 
@@ -467,6 +468,10 @@
 								id, ret);
 	}
 
+	/* Save PLL status if it is a clock source */
+	src_pll = msm_dsi_phy_get_pll(msm_dsi->phy);
+	msm_dsi_pll_save_state(src_pll);
+
 	ret = msm_dsi_host_power_off(host);
 	if (ret)
 		pr_err("%s: host %d power off failed,%d\n", __func__, id, ret);
--- linux-4.4.0.orig/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
+++ linux-4.4.0/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
@@ -547,7 +547,7 @@
 	if (cfg_handler)
 		mdp5_cfg_destroy(cfg_handler);
 
-	return NULL;
+	return ERR_PTR(ret);
 }
 
 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
--- linux-4.4.0.orig/drivers/gpu/drm/msm/msm_atomic.c
+++ linux-4.4.0/drivers/gpu/drm/msm/msm_atomic.c
@@ -107,7 +107,12 @@
 		if (old_state->legacy_cursor_update)
 			continue;
 
+		if (drm_crtc_vblank_get(crtc))
+			continue;
+
 		kms->funcs->wait_for_crtc_commit_done(kms, crtc);
+
+		drm_crtc_vblank_put(crtc);
 	}
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/msm/msm_drv.c
+++ linux-4.4.0/drivers/gpu/drm/msm/msm_drv.c
@@ -986,6 +986,7 @@
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 	.gem_prime_export   = drm_gem_prime_export,
 	.gem_prime_import   = drm_gem_prime_import,
+	.gem_prime_res_obj  = msm_gem_prime_res_obj,
 	.gem_prime_pin      = msm_gem_prime_pin,
 	.gem_prime_unpin    = msm_gem_prime_unpin,
 	.gem_prime_get_sg_table = msm_gem_prime_get_sg_table,
--- linux-4.4.0.orig/drivers/gpu/drm/msm/msm_drv.h
+++ linux-4.4.0/drivers/gpu/drm/msm/msm_drv.h
@@ -212,6 +212,7 @@
 void *msm_gem_prime_vmap(struct drm_gem_object *obj);
 void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
 int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
+struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj);
 struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
 		struct dma_buf_attachment *attach, struct sg_table *sg);
 int msm_gem_prime_pin(struct drm_gem_object *obj);
--- linux-4.4.0.orig/drivers/gpu/drm/msm/msm_gem.c
+++ linux-4.4.0/drivers/gpu/drm/msm/msm_gem.c
@@ -89,14 +89,17 @@
 			return p;
 		}
 
+		msm_obj->pages = p;
+
 		msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
 		if (IS_ERR(msm_obj->sgt)) {
+			void *ptr = ERR_CAST(msm_obj->sgt);
+
 			dev_err(dev->dev, "failed to allocate sgt\n");
-			return ERR_CAST(msm_obj->sgt);
+			msm_obj->sgt = NULL;
+			return ptr;
 		}
 
-		msm_obj->pages = p;
-
 		/* For non-cached buffers, ensure the new pages are clean
 		 * because display controller, GPU, etc. are not coherent:
 		 */
@@ -113,14 +116,19 @@
 	struct msm_gem_object *msm_obj = to_msm_bo(obj);
 
 	if (msm_obj->pages) {
-		/* For non-cached buffers, ensure the new pages are clean
-		 * because display controller, GPU, etc. are not coherent:
-		 */
-		if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
-			dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl,
-					msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
-		sg_free_table(msm_obj->sgt);
-		kfree(msm_obj->sgt);
+		if (msm_obj->sgt) {
+			/* For non-cached buffers, ensure the new
+			 * pages are clean because display controller,
+			 * GPU, etc. are not coherent:
+			 */
+			if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
+				dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl,
+					     msm_obj->sgt->nents,
+					     DMA_BIDIRECTIONAL);
+
+			sg_free_table(msm_obj->sgt);
+			kfree(msm_obj->sgt);
+		}
 
 		if (use_pages(obj))
 			drm_gem_put_pages(obj, msm_obj->pages, true, false);
--- linux-4.4.0.orig/drivers/gpu/drm/msm/msm_gem_prime.c
+++ linux-4.4.0/drivers/gpu/drm/msm/msm_gem_prime.c
@@ -70,3 +70,10 @@
 	if (!obj->import_attach)
 		msm_gem_put_pages(obj);
 }
+
+struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj)
+{
+	struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+	return msm_obj->resv;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/msm/msm_gem_submit.c
+++ linux-4.4.0/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -34,10 +34,13 @@
 }
 
 static struct msm_gem_submit *submit_create(struct drm_device *dev,
-		struct msm_gpu *gpu, int nr)
+		struct msm_gpu *gpu, uint32_t nr)
 {
 	struct msm_gem_submit *submit;
-	int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0]));
+	uint64_t sz = sizeof(*submit) + ((u64)nr * sizeof(submit->bos[0]));
+
+	if (sz > SIZE_MAX)
+		return NULL;
 
 	submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
 	if (submit) {
@@ -55,6 +58,14 @@
 	return submit;
 }
 
+static inline unsigned long __must_check
+copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
+{
+	if (access_ok(VERIFY_READ, from, n))
+		return __copy_from_user_inatomic(to, from, n);
+	return -EFAULT;
+}
+
 static int submit_lookup_objects(struct msm_gem_submit *submit,
 		struct drm_msm_gem_submit *args, struct drm_file *file)
 {
@@ -62,6 +73,7 @@
 	int ret = 0;
 
 	spin_lock(&file->table_lock);
+	pagefault_disable();
 
 	for (i = 0; i < args->nr_bos; i++) {
 		struct drm_msm_gem_submit_bo submit_bo;
@@ -70,13 +82,19 @@
 		void __user *userptr =
 			to_user_ptr(args->bos + (i * sizeof(submit_bo)));
 
-		ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
-		if (ret) {
-			ret = -EFAULT;
-			goto out_unlock;
+		ret = copy_from_user_inatomic(&submit_bo, userptr, sizeof(submit_bo));
+		if (unlikely(ret)) {
+			pagefault_enable();
+			spin_unlock(&file->table_lock);
+			ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
+			if (ret)
+				goto out;
+			spin_lock(&file->table_lock);
+			pagefault_disable();
 		}
 
-		if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
+		if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) ||
+			!(submit_bo.flags & MSM_SUBMIT_BO_FLAGS)) {
 			DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
 			ret = -EINVAL;
 			goto out_unlock;
@@ -113,9 +131,12 @@
 	}
 
 out_unlock:
-	submit->nr_bos = i;
+	pagefault_enable();
 	spin_unlock(&file->table_lock);
 
+out:
+	submit->nr_bos = i;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/msm/msm_rd.c
+++ linux-4.4.0/drivers/gpu/drm/msm/msm_rd.c
@@ -103,7 +103,9 @@
 		char *fptr = &fifo->buf[fifo->head];
 		int n;
 
-		wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0);
+		wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0 || !rd->open);
+		if (!rd->open)
+			return;
 
 		n = min(sz, circ_space_to_end(&rd->fifo));
 		memcpy(fptr, ptr, n);
@@ -192,7 +194,10 @@
 static int rd_release(struct inode *inode, struct file *file)
 {
 	struct msm_rd_state *rd = inode->i_private;
+
 	rd->open = false;
+	wake_up_all(&rd->fifo_event);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ linux-4.4.0/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -23,7 +23,8 @@
 	struct msm_ringbuffer *ring;
 	int ret;
 
-	size = ALIGN(size, 4);   /* size should be dword aligned */
+	if (WARN_ON(!is_power_of_2(size)))
+		return ERR_PTR(-EINVAL);
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 	if (!ring) {
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/dispnv04/hw.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/dispnv04/hw.c
@@ -222,6 +222,7 @@
 		uint32_t mpllP;
 
 		pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP);
+		mpllP = (mpllP >> 8) & 0xf;
 		if (!mpllP)
 			mpllP = 4;
 
@@ -232,7 +233,7 @@
 		uint32_t clock;
 
 		pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock);
-		return clock;
+		return clock / 1000;
 	}
 
 	ret = nouveau_hw_get_pllvals(dev, plltype, &pllvals);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -208,6 +208,8 @@
 		struct drm_display_mode *mode;
 
 		mode = drm_mode_duplicate(encoder->dev, tv_mode);
+		if (!mode)
+			continue;
 
 		mode->clock = tv_norm->tv_enc_mode.vrefresh *
 			mode->htotal / 1000 *
@@ -257,6 +259,8 @@
 		if (modes[i].hdisplay == output_mode->hdisplay &&
 		    modes[i].vdisplay == output_mode->vdisplay) {
 			mode = drm_mode_duplicate(encoder->dev, output_mode);
+			if (!mode)
+				continue;
 			mode->type |= DRM_MODE_TYPE_PREFERRED;
 
 		} else {
@@ -264,6 +268,8 @@
 					    modes[i].vdisplay, 60, false,
 					    (output_mode->flags &
 					     DRM_MODE_FLAG_INTERLACE), false);
+			if (!mode)
+				continue;
 		}
 
 		/* CVT modes are sometimes unsuitable... */
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
+++ linux-4.4.0/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
@@ -37,6 +37,7 @@
 	struct mutex mutex;
 	struct list_head head;
 	struct i2c_adapter i2c;
+	u8 enabled;
 };
 
 int nvkm_i2c_bus_acquire(struct nvkm_i2c_bus *);
@@ -56,6 +57,7 @@
 	struct mutex mutex;
 	struct list_head head;
 	struct i2c_adapter i2c;
+	u8 enabled;
 
 	u32 intr;
 };
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
+++ linux-4.4.0/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
@@ -4,6 +4,7 @@
 
 struct nvkm_alarm {
 	struct list_head head;
+	struct list_head exec;
 	u64 timestamp;
 	void (*func)(struct nvkm_alarm *);
 };
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -333,6 +333,9 @@
 	if (bios->major_version < 5 && bios->data[0x48] & 0x4)
 		return NVReadVgaCrtc5758(dev, 0, 0xf) & 0xf;
 
+	if (drm->device.info.family >= NV_DEVICE_INFO_V0_MAXWELL)
+		return nvif_rd32(device, 0x001800) & 0x0000000f;
+	else
 	if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA)
 		return (nvif_rd32(device, NV_PEXTDEV_BOOT_0) >> 24) & 0xf;
 	else
@@ -351,7 +354,7 @@
 		/* Apple cards don't have the fp table; the laptops use DDC */
 		/* The table is also missing on some x86 IGPs */
 #ifndef __powerpc__
-		NV_ERROR(drm, "Pointer to flat panel table invalid\n");
+		NV_WARN(drm, "Pointer to flat panel table invalid\n");
 #endif
 		bios->digital_min_front_porch = 0x4b;
 		return 0;
@@ -935,7 +938,7 @@
 
 	tmdstableptr = ROM16(bios->data[bitentry->offset]);
 	if (!tmdstableptr) {
-		NV_ERROR(drm, "Pointer to TMDS table invalid\n");
+		NV_WARN(drm, "Pointer to TMDS table invalid\n");
 		return -EINVAL;
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -253,9 +253,21 @@
 		nv_connector->edid = NULL;
 	}
 
-	ret = pm_runtime_get_sync(connector->dev->dev);
-	if (ret < 0 && ret != -EACCES)
-		return conn_status;
+	/* Outputs are only polled while runtime active, so resuming the
+	 * device here is unnecessary (and would deadlock upon runtime suspend
+	 * because it waits for polling to finish). We do however, want to
+	 * prevent the autosuspend timer from elapsing during this operation
+	 * if possible.
+	 */
+	if (drm_kms_helper_is_poll_worker()) {
+		pm_runtime_get_noresume(dev->dev);
+	} else {
+		ret = pm_runtime_get_sync(dev->dev);
+		if (ret < 0 && ret != -EACCES) {
+			pm_runtime_put_autosuspend(dev->dev);
+			return conn_status;
+		}
+	}
 
 	nv_encoder = nouveau_connector_ddc_detect(connector);
 	if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
@@ -323,8 +335,8 @@
 
  out:
 
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	pm_runtime_mark_last_busy(dev->dev);
+	pm_runtime_put_autosuspend(dev->dev);
 
 	return conn_status;
 }
@@ -786,6 +798,9 @@
 		struct drm_display_mode *mode;
 
 		mode = drm_mode_duplicate(dev, nv_connector->native_mode);
+		if (!mode)
+			return 0;
+
 		drm_mode_probed_add(connector, mode);
 		ret = 1;
 	}
@@ -969,10 +984,13 @@
 
 		NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
 
+		mutex_lock(&drm->dev->mode_config.mutex);
 		if (plugged)
 			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
 		else
 			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+		mutex_unlock(&drm->dev->mode_config.mutex);
+
 		drm_helper_hpd_irq_event(connector->dev);
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_display.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -104,7 +104,7 @@
 	};
 	struct nouveau_display *disp = nouveau_display(crtc->dev);
 	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
-	int ret, retry = 1;
+	int ret, retry = 20;
 
 	do {
 		ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args));
@@ -370,7 +370,8 @@
 		return ret;
 
 	/* enable polling for external displays */
-	drm_kms_helper_poll_enable(dev);
+	if (!dev->mode_config.poll_enabled)
+		drm_kms_helper_poll_enable(dev);
 
 	/* enable hotplug interrupts */
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -634,10 +635,6 @@
 		nv_crtc->lut.depth = 0;
 	}
 
-	/* Make sure that drm and hw vblank irqs get resumed if needed. */
-	for (head = 0; head < dev->mode_config.num_crtc; head++)
-		drm_vblank_on(dev, head);
-
 	/* This should ensure we don't hit a locking problem when someone
 	 * wakes us up via a connector.  We should never go into suspend
 	 * while the display is on anyways.
@@ -647,6 +644,10 @@
 
 	drm_helper_resume_force_mode(dev);
 
+	/* Make sure that drm and hw vblank irqs get resumed if needed. */
+	for (head = 0; head < dev->mode_config.num_crtc; head++)
+		drm_vblank_on(dev, head);
+
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -308,7 +308,16 @@
 	bool boot = false;
 	int ret;
 
-	/* remove conflicting drivers (vesafb, efifb etc) */
+	/* We need to check that the chipset is supported before booting
+	 * fbdev off the hardware, as there's no way to put it back.
+	 */
+	ret = nvkm_device_pci_new(pdev, NULL, "error", true, false, 0, &device);
+	if (ret)
+		return ret;
+
+	nvkm_device_del(&device);
+
+	/* Remove conflicting drivers (vesafb, efifb etc). */
 	aper = alloc_apertures(3);
 	if (!aper)
 		return -ENOMEM;
@@ -734,7 +743,10 @@
 	pci_set_master(pdev);
 
 	ret = nouveau_do_resume(drm_dev, true);
-	drm_kms_helper_poll_enable(drm_dev);
+
+	if (!drm_dev->mode_config.poll_enabled)
+		drm_kms_helper_poll_enable(drm_dev);
+
 	/* do magic */
 	nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25));
 	vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
@@ -793,8 +805,10 @@
 
 	/* need to bring up power immediately if opening device */
 	ret = pm_runtime_get_sync(dev->dev);
-	if (ret < 0 && ret != -EACCES)
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put_autosuspend(dev->dev);
 		return ret;
+	}
 
 	get_task_comm(tmpname, current);
 	snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid));
@@ -882,8 +896,10 @@
 	long ret;
 
 	ret = pm_runtime_get_sync(dev->dev);
-	if (ret < 0 && ret != -EACCES)
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put_autosuspend(dev->dev);
 		return ret;
+	}
 
 	switch (_IOC_NR(cmd) - DRM_COMMAND_BASE) {
 	case DRM_NOUVEAU_NVIF:
@@ -1024,7 +1040,10 @@
 	.id_table = nouveau_drm_pci_table,
 	.probe = nouveau_drm_probe,
 	.remove = nouveau_drm_remove,
-	.driver.pm = &nouveau_pm_ops,
+	.driver = {
+		.pm = &nouveau_pm_ops,
+		.suppress_bind_attrs = true,
+	},
 };
 
 struct drm_device *
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -184,8 +184,10 @@
 	struct nouveau_fbdev *fbcon = info->par;
 	struct nouveau_drm *drm = nouveau_drm(fbcon->dev);
 	int ret = pm_runtime_get_sync(drm->dev->dev);
-	if (ret < 0 && ret != -EACCES)
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put(drm->dev->dev);
 		return ret;
+	}
 	return 0;
 }
 
@@ -235,7 +237,7 @@
 nouveau_fbcon_accel_save_disable(struct drm_device *dev)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	if (drm->fbcon) {
+	if (drm->fbcon && drm->fbcon->helper.fbdev) {
 		drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
 		drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
 	}
@@ -245,7 +247,7 @@
 nouveau_fbcon_accel_restore(struct drm_device *dev)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	if (drm->fbcon) {
+	if (drm->fbcon && drm->fbcon->helper.fbdev) {
 		drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
 	}
 }
@@ -257,7 +259,8 @@
 	struct nouveau_fbdev *fbcon = drm->fbcon;
 	if (fbcon && drm->channel) {
 		console_lock();
-		fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+		if (fbcon->helper.fbdev)
+			fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
 		console_unlock();
 		nouveau_channel_idle(drm->channel);
 		nvif_object_fini(&fbcon->twod);
@@ -557,12 +560,15 @@
 	if (ret)
 		goto fini;
 
+	if (fbcon->helper.fbdev)
+		fbcon->helper.fbdev->pixmap.buf_align = 4;
 	return 0;
 
 fini:
 	drm_fb_helper_fini(&fbcon->helper);
 free:
 	kfree(fbcon);
+	drm->fbcon = NULL;
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -157,7 +157,7 @@
 
 		fence = list_entry(fctx->pending.next, typeof(*fence), head);
 		chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
-		if (nouveau_fence_update(fence->channel, fctx))
+		if (nouveau_fence_update(chan, fctx))
 			ret = NVIF_NOTIFY_DROP;
 	}
 	spin_unlock_irqrestore(&fctx->lock, flags);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -99,6 +99,7 @@
 	struct nouveau_bo *bo;
 	struct nouveau_bo *bo_gart;
 	u32 *suspend;
+	struct mutex mutex;
 };
 
 u64  nv84_fence_crtc(struct nouveau_channel *, int);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -42,8 +42,10 @@
 	int ret;
 
 	ret = pm_runtime_get_sync(dev);
-	if (WARN_ON(ret < 0 && ret != -EACCES))
+	if (WARN_ON(ret < 0 && ret != -EACCES)) {
+		pm_runtime_put_autosuspend(dev);
 		return;
+	}
 
 	if (gem->import_attach)
 		drm_prime_gem_destroy(gem, nvbo->bo.sg);
@@ -370,7 +372,7 @@
 	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	struct drm_device *dev = chan->drm->dev;
 	int trycnt = 0;
-	int ret, i;
+	int ret = -EINVAL, i;
 	struct nouveau_bo *res_bo = NULL;
 	LIST_HEAD(gart_list);
 	LIST_HEAD(vram_list);
@@ -602,7 +604,7 @@
 		struct nouveau_bo *nvbo;
 		uint32_t data;
 
-		if (unlikely(r->bo_index > req->nr_buffers)) {
+		if (unlikely(r->bo_index >= req->nr_buffers)) {
 			NV_PRINTK(err, cli, "reloc bo index invalid\n");
 			ret = -EINVAL;
 			break;
@@ -612,7 +614,7 @@
 		if (b->presumed.valid)
 			continue;
 
-		if (unlikely(r->reloc_bo_index > req->nr_buffers)) {
+		if (unlikely(r->reloc_bo_index >= req->nr_buffers)) {
 			NV_PRINTK(err, cli, "reloc container bo index invalid\n");
 			ret = -EINVAL;
 			break;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_platform.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_platform.c
@@ -24,7 +24,7 @@
 static int nouveau_platform_probe(struct platform_device *pdev)
 {
 	const struct nvkm_device_tegra_func *func;
-	struct nvkm_device *device;
+	struct nvkm_device *device = NULL;
 	struct drm_device *drm;
 	int ret;
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -105,12 +105,9 @@
 	else
 		nvbe->ttm.ttm.func = &nv50_sgdma_backend;
 
-	if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page))
-		/*
-		 * A failing ttm_dma_tt_init() will call ttm_tt_destroy()
-		 * and thus our nouveau_sgdma_destroy() hook, so we don't need
-		 * to free nvbe here.
-		 */
+	if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page)) {
+		kfree(nvbe);
 		return NULL;
+	}
 	return &nvbe->ttm.ttm;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -397,6 +397,9 @@
 	/* VRAM init */
 	drm->gem.vram_available = drm->device.info.ram_user;
 
+	arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1),
+				   device->func->resource_size(device, 1));
+
 	ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
 			      drm->gem.vram_available >> PAGE_SHIFT);
 	if (ret) {
@@ -429,6 +432,8 @@
 void
 nouveau_ttm_fini(struct nouveau_drm *drm)
 {
+	struct nvkm_device *device = nvxx_device(&drm->device);
+
 	ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM);
 	ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT);
 
@@ -438,4 +443,7 @@
 
 	arch_phys_wc_del(drm->ttm.mtrr);
 	drm->ttm.mtrr = 0;
+	arch_io_free_memtype_wc(device->func->resource_addr(device, 1),
+				device->func->resource_size(device, 1));
+
 }
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nouveau_usif.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nouveau_usif.c
@@ -313,7 +313,8 @@
 	if (nvif_unpack(argv->v0, 0, 0, true)) {
 		/* block access to objects not created via this interface */
 		owner = argv->v0.owner;
-		if (argv->v0.object == 0ULL)
+		if (argv->v0.object == 0ULL &&
+		    argv->v0.type != NVIF_IOCTL_V0_DEL)
 			argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */
 		else
 			argv->v0.owner = NVDRM_OBJECT_USIF;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -82,7 +82,6 @@
 	uint32_t fg;
 	uint32_t bg;
 	uint32_t dsize;
-	uint32_t width;
 	uint32_t *data = (uint32_t *)image->data;
 	int ret;
 
@@ -93,9 +92,6 @@
 	if (ret)
 		return ret;
 
-	width = ALIGN(image->width, 8);
-	dsize = ALIGN(width * image->height, 32) >> 5;
-
 	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 		fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
@@ -111,10 +107,11 @@
 			 ((image->dx + image->width) & 0xffff));
 	OUT_RING(chan, bg);
 	OUT_RING(chan, fg);
-	OUT_RING(chan, (image->height << 16) | width);
+	OUT_RING(chan, (image->height << 16) | ALIGN(image->width, 8));
 	OUT_RING(chan, (image->height << 16) | image->width);
 	OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
 
+	dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
 	while (dsize) {
 		int iter_len = dsize > 128 ? 128 : dsize;
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -95,7 +95,7 @@
 	struct nouveau_fbdev *nfbdev = info->par;
 	struct nouveau_drm *drm = nouveau_drm(nfbdev->dev);
 	struct nouveau_channel *chan = drm->channel;
-	uint32_t width, dwords, *data = (uint32_t *)image->data;
+	uint32_t dwords, *data = (uint32_t *)image->data;
 	uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
 	uint32_t *palette = info->pseudo_palette;
 	int ret;
@@ -107,9 +107,6 @@
 	if (ret)
 		return ret;
 
-	width = ALIGN(image->width, 32);
-	dwords = (width * image->height) >> 5;
-
 	BEGIN_NV04(chan, NvSub2D, 0x0814, 2);
 	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
@@ -128,6 +125,7 @@
 	OUT_RING(chan, 0);
 	OUT_RING(chan, image->dy);
 
+	dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
 	while (dwords) {
 		int push = dwords > 2047 ? 2047 : dwords;
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nv84_fence.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -121,8 +121,10 @@
 	}
 
 	nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence);
+	mutex_lock(&priv->mutex);
 	nouveau_bo_vma_del(priv->bo, &fctx->vma_gart);
 	nouveau_bo_vma_del(priv->bo, &fctx->vma);
+	mutex_unlock(&priv->mutex);
 	nouveau_fence_context_del(&fctx->base);
 	chan->fence = NULL;
 	nouveau_fence_context_free(&fctx->base);
@@ -148,11 +150,13 @@
 	fctx->base.sync32 = nv84_fence_sync32;
 	fctx->base.sequence = nv84_fence_read(chan);
 
+	mutex_lock(&priv->mutex);
 	ret = nouveau_bo_vma_add(priv->bo, cli->vm, &fctx->vma);
 	if (ret == 0) {
 		ret = nouveau_bo_vma_add(priv->bo_gart, cli->vm,
 					&fctx->vma_gart);
 	}
+	mutex_unlock(&priv->mutex);
 
 	/* map display semaphore buffers into channel's vm */
 	for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
@@ -232,6 +236,8 @@
 	priv->base.context_base = fence_context_alloc(priv->base.contexts);
 	priv->base.uevent = true;
 
+	mutex_init(&priv->mutex);
+
 	/* Use VRAM if there is any ; otherwise fallback to system memory */
 	domain = drm->device.info.ram_size != 0 ? TTM_PL_FLAG_VRAM :
 			 /*
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvc0_fbcon.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvc0_fbcon.c
@@ -95,7 +95,7 @@
 	struct nouveau_fbdev *nfbdev = info->par;
 	struct nouveau_drm *drm = nouveau_drm(nfbdev->dev);
 	struct nouveau_channel *chan = drm->channel;
-	uint32_t width, dwords, *data = (uint32_t *)image->data;
+	uint32_t dwords, *data = (uint32_t *)image->data;
 	uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
 	uint32_t *palette = info->pseudo_palette;
 	int ret;
@@ -107,9 +107,6 @@
 	if (ret)
 		return ret;
 
-	width = ALIGN(image->width, 32);
-	dwords = (width * image->height) >> 5;
-
 	BEGIN_NVC0(chan, NvSub2D, 0x0814, 2);
 	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
@@ -128,6 +125,7 @@
 	OUT_RING  (chan, 0);
 	OUT_RING  (chan, image->dy);
 
+	dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
 	while (dwords) {
 		int push = dwords > 2047 ? 2047 : dwords;
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/core/ramht.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/core/ramht.c
@@ -131,7 +131,7 @@
 	struct nvkm_ramht *ramht = *pramht;
 	if (ramht) {
 		nvkm_gpuobj_del(&ramht->gpuobj);
-		kfree(*pramht);
+		vfree(*pramht);
 		*pramht = NULL;
 	}
 }
@@ -143,8 +143,8 @@
 	struct nvkm_ramht *ramht;
 	int ret, i;
 
-	if (!(ramht = *pramht = kzalloc(sizeof(*ramht) + (size >> 3) *
-					sizeof(*ramht->data), GFP_KERNEL)))
+	if (!(ramht = *pramht = vzalloc(sizeof(*ramht) +
+					(size >> 3) * sizeof(*ramht->data))))
 		return -ENOMEM;
 
 	ramht->device = device;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c
@@ -40,5 +40,5 @@
 g84_bsp_new(struct nvkm_device *device, int index, struct nvkm_engine **pengine)
 {
 	return nvkm_xtensa_new_(&g84_bsp, device, index,
-				true, 0x103000, pengine);
+				device->chipset != 0x92, 0x103000, pengine);
 }
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -714,7 +714,7 @@
 	.i2c = nv04_i2c_new,
 	.imem = nv40_instmem_new,
 	.mc = nv44_mc_new,
-	.mmu = nv44_mmu_new,
+	.mmu = nv04_mmu_new,
 	.pci = nv40_pci_new,
 	.therm = nv40_therm_new,
 	.timer = nv41_timer_new,
@@ -1833,7 +1833,7 @@
 	.fb = gk104_fb_new,
 	.fuse = gf100_fuse_new,
 	.gpio = gk104_gpio_new,
-	.i2c = gf119_i2c_new,
+	.i2c = gk104_i2c_new,
 	.ibus = gk104_ibus_new,
 	.imem = nv50_instmem_new,
 	.ltc = gk104_ltc_new,
@@ -1941,7 +1941,7 @@
 	.fb = gm107_fb_new,
 	.fuse = gm107_fuse_new,
 	.gpio = gk104_gpio_new,
-	.i2c = gf119_i2c_new,
+	.i2c = gk104_i2c_new,
 	.ibus = gk104_ibus_new,
 	.imem = nv50_instmem_new,
 	.ltc = gm107_ltc_new,
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
@@ -23,6 +23,10 @@
 #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER
 #include "priv.h"
 
+#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
+#include <asm/dma-iommu.h>
+#endif
+
 static int
 nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev)
 {
@@ -85,6 +89,15 @@
 	unsigned long pgsize_bitmap;
 	int ret;
 
+#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
+	if (dev->archdata.mapping) {
+		struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+
+		arm_iommu_detach_device(dev);
+		arm_iommu_release_mapping(mapping);
+	}
+#endif
+
 	if (!tdev->func->iommu_bit)
 		return;
 
@@ -252,32 +265,40 @@
 
 	if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL)))
 		return -ENOMEM;
-	*pdevice = &tdev->device;
+
 	tdev->func = func;
 	tdev->pdev = pdev;
 	tdev->irq = -1;
 
 	tdev->vdd = devm_regulator_get(&pdev->dev, "vdd");
-	if (IS_ERR(tdev->vdd))
-		return PTR_ERR(tdev->vdd);
+	if (IS_ERR(tdev->vdd)) {
+		ret = PTR_ERR(tdev->vdd);
+		goto free;
+	}
 
 	tdev->rst = devm_reset_control_get(&pdev->dev, "gpu");
-	if (IS_ERR(tdev->rst))
-		return PTR_ERR(tdev->rst);
+	if (IS_ERR(tdev->rst)) {
+		ret = PTR_ERR(tdev->rst);
+		goto free;
+	}
 
 	tdev->clk = devm_clk_get(&pdev->dev, "gpu");
-	if (IS_ERR(tdev->clk))
-		return PTR_ERR(tdev->clk);
+	if (IS_ERR(tdev->clk)) {
+		ret = PTR_ERR(tdev->clk);
+		goto free;
+	}
 
 	tdev->clk_pwr = devm_clk_get(&pdev->dev, "pwr");
-	if (IS_ERR(tdev->clk_pwr))
-		return PTR_ERR(tdev->clk_pwr);
+	if (IS_ERR(tdev->clk_pwr)) {
+		ret = PTR_ERR(tdev->clk_pwr);
+		goto free;
+	}
 
 	nvkm_device_tegra_probe_iommu(tdev);
 
 	ret = nvkm_device_tegra_power_up(tdev);
 	if (ret)
-		return ret;
+		goto remove;
 
 	tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value;
 	ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev,
@@ -285,9 +306,19 @@
 			       cfg, dbg, detect, mmio, subdev_mask,
 			       &tdev->device);
 	if (ret)
-		return ret;
+		goto powerdown;
+
+	*pdevice = &tdev->device;
 
 	return 0;
+
+powerdown:
+	nvkm_device_tegra_power_down(tdev);
+remove:
+	nvkm_device_tegra_remove_iommu(tdev);
+free:
+	kfree(tdev);
+	return ret;
 }
 #else
 int
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
@@ -72,6 +72,8 @@
 
 	if (debug > subdev->debug)
 		return;
+	if (!mthd)
+		return;
 
 	for (i = 0; (list = mthd->data[i].mthd) != NULL; i++) {
 		u32 base = chan->head * mthd->addr;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
@@ -328,6 +328,7 @@
 		.outp = outp,
 	}, *dp = &_dp;
 	u32 datarate = 0;
+	u8  pwr;
 	int ret;
 
 	if (!outp->base.info.location && disp->func->sor.magic)
@@ -355,6 +356,15 @@
 	/* disable link interrupt handling during link training */
 	nvkm_notify_put(&outp->irq);
 
+	/* ensure sink is not in a low-power state */
+	if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) {
+		if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
+			pwr &= ~DPCD_SC00_SET_POWER;
+			pwr |=  DPCD_SC00_SET_POWER_D0;
+			nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1);
+		}
+	}
+
 	/* enable down-spreading and execute pre-train script from vbios */
 	dp_link_train_init(dp, outp->dpcd[3] & 0x01);
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
@@ -71,5 +71,11 @@
 #define DPCD_LS0C_LANE1_POST_CURSOR2                                       0x0c
 #define DPCD_LS0C_LANE0_POST_CURSOR2                                       0x03
 
+/* DPCD Sink Control */
+#define DPCD_SC00                                                       0x00600
+#define DPCD_SC00_SET_POWER                                                0x03
+#define DPCD_SC00_SET_POWER_D0                                             0x01
+#define DPCD_SC00_SET_POWER_D3                                             0x03
+
 void nvkm_dp_train(struct work_struct *);
 #endif
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
@@ -59,7 +59,7 @@
 			);
 		}
 		for (i = 0; i < size; i++)
-			nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
+			nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[i]);
 		for (; i < 0x60; i++)
 			nvkm_wr32(device, 0x61c440 + soff, (i << 8));
 		nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
@@ -40,8 +40,8 @@
 gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
 {
 	struct nvkm_device *device = outp->base.disp->engine.subdev.device;
-	const u32 loff = gf119_sor_loff(outp);
-	nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
+	const u32 soff = gf119_sor_soff(outp);
+	nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c
@@ -36,7 +36,10 @@
 {
 	struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
 	struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem;
+
+	mutex_lock(&chan->fifo->base.engine.subdev.mutex);
 	nvkm_ramht_remove(imem->ramht, cookie);
+	mutex_unlock(&chan->fifo->base.engine.subdev.mutex);
 }
 
 static int
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c
@@ -59,6 +59,7 @@
 	struct nvkm_gpuobj *inst = chan->base.inst;
 	int ret = 0;
 
+	mutex_lock(&subdev->mutex);
 	nvkm_wr32(device, 0x002634, chan->base.chid);
 	if (nvkm_msec(device, 2000,
 		if (nvkm_rd32(device, 0x002634) == chan->base.chid)
@@ -66,10 +67,12 @@
 	) < 0) {
 		nvkm_error(subdev, "channel %d [%s] kick timeout\n",
 			   chan->base.chid, chan->base.object.client->name);
-		ret = -EBUSY;
-		if (suspend)
-			return ret;
+		ret = -ETIMEDOUT;
 	}
+	mutex_unlock(&subdev->mutex);
+
+	if (ret && suspend)
+		return ret;
 
 	if (offset) {
 		nvkm_kmap(inst);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
@@ -39,7 +39,9 @@
 	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
 	struct nvkm_device *device = subdev->device;
 	struct nvkm_client *client = chan->base.object.client;
+	int ret = 0;
 
+	mutex_lock(&subdev->mutex);
 	nvkm_wr32(device, 0x002634, chan->base.chid);
 	if (nvkm_msec(device, 2000,
 		if (!(nvkm_rd32(device, 0x002634) & 0x00100000))
@@ -47,10 +49,10 @@
 	) < 0) {
 		nvkm_error(subdev, "channel %d [%s] kick timeout\n",
 			   chan->base.chid, client->name);
-		return -EBUSY;
+		ret = -ETIMEDOUT;
 	}
-
-	return 0;
+	mutex_unlock(&subdev->mutex);
+	return ret;
 }
 
 static u32
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -874,22 +874,41 @@
 }
 
 static const struct nvkm_enum gf100_mp_warp_error[] = {
-	{ 0x00, "NO_ERROR" },
-	{ 0x01, "STACK_MISMATCH" },
+	{ 0x01, "STACK_ERROR" },
+	{ 0x02, "API_STACK_ERROR" },
+	{ 0x03, "RET_EMPTY_STACK_ERROR" },
+	{ 0x04, "PC_WRAP" },
 	{ 0x05, "MISALIGNED_PC" },
-	{ 0x08, "MISALIGNED_GPR" },
-	{ 0x09, "INVALID_OPCODE" },
-	{ 0x0d, "GPR_OUT_OF_BOUNDS" },
-	{ 0x0e, "MEM_OUT_OF_BOUNDS" },
-	{ 0x0f, "UNALIGNED_MEM_ACCESS" },
+	{ 0x06, "PC_OVERFLOW" },
+	{ 0x07, "MISALIGNED_IMMC_ADDR" },
+	{ 0x08, "MISALIGNED_REG" },
+	{ 0x09, "ILLEGAL_INSTR_ENCODING" },
+	{ 0x0a, "ILLEGAL_SPH_INSTR_COMBO" },
+	{ 0x0b, "ILLEGAL_INSTR_PARAM" },
+	{ 0x0c, "INVALID_CONST_ADDR" },
+	{ 0x0d, "OOR_REG" },
+	{ 0x0e, "OOR_ADDR" },
+	{ 0x0f, "MISALIGNED_ADDR" },
 	{ 0x10, "INVALID_ADDR_SPACE" },
-	{ 0x11, "INVALID_PARAM" },
+	{ 0x11, "ILLEGAL_INSTR_PARAM2" },
+	{ 0x12, "INVALID_CONST_ADDR_LDC" },
+	{ 0x13, "GEOMETRY_SM_ERROR" },
+	{ 0x14, "DIVERGENT" },
+	{ 0x15, "WARP_EXIT" },
 	{}
 };
 
 static const struct nvkm_bitfield gf100_mp_global_error[] = {
+	{ 0x00000001, "SM_TO_SM_FAULT" },
+	{ 0x00000002, "L1_ERROR" },
 	{ 0x00000004, "MULTIPLE_WARP_ERRORS" },
-	{ 0x00000008, "OUT_OF_STACK_SPACE" },
+	{ 0x00000008, "PHYSICAL_STACK_OVERFLOW" },
+	{ 0x00000010, "BPT_INT" },
+	{ 0x00000020, "BPT_PAUSE" },
+	{ 0x00000040, "SINGLE_STEP_COMPLETE" },
+	{ 0x20000000, "ECC_SEC_ERROR" },
+	{ 0x40000000, "ECC_DED_ERROR" },
+	{ 0x80000000, "TIMEOUT" },
 	{}
 };
 
@@ -1717,6 +1736,8 @@
 
 	gf100_gr_mmio(gr, gr->func->mmio);
 
+	nvkm_mask(device, TPC_UNIT(0, 0, 0x05c), 0x00000001, 0x00000001);
+
 	memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr));
 	for (i = 0, gpc = -1; i < gr->tpc_total; i++) {
 		do {
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
@@ -76,8 +76,8 @@
 		nvkm_wo32(chan->inst, i, 0x00040004);
 	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
 		nvkm_wo32(chan->inst, i + 0, 0x10700ff9);
-		nvkm_wo32(chan->inst, i + 1, 0x0436086c);
-		nvkm_wo32(chan->inst, i + 2, 0x000c001b);
+		nvkm_wo32(chan->inst, i + 4, 0x0436086c);
+		nvkm_wo32(chan->inst, i + 8, 0x000c001b);
 	}
 	for (i = 0x30b8; i < 0x30c8; i += 4)
 		nvkm_wo32(chan->inst, i, 0x0000ffff);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
@@ -75,8 +75,8 @@
 		nvkm_wo32(chan->inst, i, 0x00040004);
 	for (i = 0x15ac; i <= 0x271c ; i += 16) {
 		nvkm_wo32(chan->inst, i + 0, 0x10700ff9);
-		nvkm_wo32(chan->inst, i + 1, 0x0436086c);
-		nvkm_wo32(chan->inst, i + 2, 0x000c001b);
+		nvkm_wo32(chan->inst, i + 4, 0x0436086c);
+		nvkm_wo32(chan->inst, i + 8, 0x000c001b);
 	}
 	for (i = 0x274c; i < 0x275c; i += 4)
 		nvkm_wo32(chan->inst, i, 0x0000ffff);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
@@ -198,7 +198,7 @@
 		}
 
 		if (type == 0x00000010) {
-			if (!nv31_mpeg_mthd(mpeg, mthd, data))
+			if (nv31_mpeg_mthd(mpeg, mthd, data))
 				show &= ~0x01000000;
 		}
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
@@ -172,7 +172,7 @@
 		}
 
 		if (type == 0x00000010) {
-			if (!nv44_mpeg_mthd(subdev->device, mthd, data))
+			if (nv44_mpeg_mthd(subdev->device, mthd, data))
 				show &= ~0x01000000;
 		}
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
@@ -59,9 +59,11 @@
 nv40_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom)
 {
 	struct nvkm_device *device = pm->engine.subdev.device;
-	if (pm->sequence != pm->sequence) {
+	struct nv40_pm *nv40pm = container_of(pm, struct nv40_pm, base);
+
+	if (nv40pm->sequence != pm->sequence) {
 		nvkm_wr32(device, 0x400084, 0x00000020);
-		pm->sequence = pm->sequence;
+		nv40pm->sequence = pm->sequence;
 	}
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
@@ -129,7 +129,7 @@
 
 	if (bar->bar[0].mem) {
 		addr = nvkm_memory_addr(bar->bar[0].mem) >> 12;
-		nvkm_wr32(device, 0x001714, 0xc0000000 | addr);
+		nvkm_wr32(device, 0x001714, 0x80000000 | addr);
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h
@@ -12,6 +12,7 @@
 	bool rw;
 	bool ignore_checksum;
 	bool no_pcir;
+	bool require_checksum;
 };
 
 int nvbios_extend(struct nvkm_bios *, u32 length);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
@@ -75,7 +75,7 @@
 	nvkm_debug(subdev, "%08x: type %02x, %d bytes\n",
 		   image.base, image.type, image.size);
 
-	if (!shadow_fetch(bios, mthd, image.size)) {
+	if (!shadow_fetch(bios, mthd, image.base + image.size)) {
 		nvkm_debug(subdev, "%08x: fetch failed\n", image.base);
 		return 0;
 	}
@@ -86,9 +86,12 @@
 		    nvbios_checksum(&bios->data[image.base], image.size)) {
 			nvkm_debug(subdev, "%08x: checksum failed\n",
 				   image.base);
-			if (mthd->func->rw)
+			if (!mthd->func->require_checksum) {
+				if (mthd->func->rw)
+					score += 1;
 				score += 1;
-			score += 1;
+			} else
+				return 0;
 		} else {
 			score += 3;
 		}
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c
@@ -99,6 +99,7 @@
 	.init = acpi_init,
 	.read = acpi_read_fast,
 	.rw = false,
+	.require_checksum = true,
 };
 
 const struct nvbios_source
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c
@@ -161,7 +161,8 @@
 	}
 
 	/* load and execute some other ucode image (bios therm?) */
-	return pmu_load(init, 0x01, post, NULL, NULL);
+	pmu_load(init, 0x01, post, NULL, NULL);
+	return 0;
 }
 
 static const struct nvkm_devinit_func
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
@@ -87,7 +87,7 @@
 		WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
 		/* XXX: Get these values from the VBIOS instead */
 		DLL = !(ram->mr[1] & 0x1);
-		RON = !(ram->mr[1] & 0x300) >> 8;
+		RON = !((ram->mr[1] & 0x300) >> 8);
 		break;
 	default:
 		return -ENOSYS;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
@@ -105,9 +105,15 @@
 {
 	struct nvkm_i2c_pad *pad = aux->pad;
 	int ret;
+
 	AUX_TRACE(aux, "acquire");
 	mutex_lock(&aux->mutex);
-	ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX);
+
+	if (aux->enabled)
+		ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX);
+	else
+		ret = -EIO;
+
 	if (ret)
 		mutex_unlock(&aux->mutex);
 	return ret;
@@ -141,6 +147,24 @@
 	}
 }
 
+void
+nvkm_i2c_aux_init(struct nvkm_i2c_aux *aux)
+{
+	AUX_TRACE(aux, "init");
+	mutex_lock(&aux->mutex);
+	aux->enabled = true;
+	mutex_unlock(&aux->mutex);
+}
+
+void
+nvkm_i2c_aux_fini(struct nvkm_i2c_aux *aux)
+{
+	AUX_TRACE(aux, "fini");
+	mutex_lock(&aux->mutex);
+	aux->enabled = false;
+	mutex_unlock(&aux->mutex);
+}
+
 int
 nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func,
 		  struct nvkm_i2c_pad *pad, int id,
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
@@ -14,6 +14,8 @@
 int nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *,
 		      int id, struct nvkm_i2c_aux **);
 void nvkm_i2c_aux_del(struct nvkm_i2c_aux **);
+void nvkm_i2c_aux_init(struct nvkm_i2c_aux *);
+void nvkm_i2c_aux_fini(struct nvkm_i2c_aux *);
 int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type,
 		      u32 addr, u8 *data, u8 size);
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
@@ -118,10 +118,10 @@
 		if (retries)
 			udelay(400);
 
-		/* transaction request, wait up to 1ms for it to complete */
+		/* transaction request, wait up to 2ms for it to complete */
 		nvkm_wr32(device, 0x00e4e4 + base, 0x00010000 | ctrl);
 
-		timeout = 1000;
+		timeout = 2000;
 		do {
 			ctrl = nvkm_rd32(device, 0x00e4e4 + base);
 			udelay(1);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c
@@ -33,7 +33,7 @@
 gm204_i2c_aux_fini(struct gm204_i2c_aux *aux)
 {
 	struct nvkm_device *device = aux->base.pad->i2c->subdev.device;
-	nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00310000, 0x00000000);
+	nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00710000, 0x00000000);
 }
 
 static int
@@ -54,10 +54,10 @@
 			AUX_ERR(&aux->base, "begin idle timeout %08x", ctrl);
 			return -EBUSY;
 		}
-	} while (ctrl & 0x03010000);
+	} while (ctrl & 0x07010000);
 
 	/* set some magic, and wait up to 1ms for it to appear */
-	nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00300000, ureq);
+	nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00700000, ureq);
 	timeout = 1000;
 	do {
 		ctrl = nvkm_rd32(device, 0x00d954 + (aux->ch * 0x50));
@@ -67,7 +67,7 @@
 			gm204_i2c_aux_fini(aux);
 			return -EBUSY;
 		}
-	} while ((ctrl & 0x03000000) != urep);
+	} while ((ctrl & 0x07000000) != urep);
 
 	return 0;
 }
@@ -118,10 +118,10 @@
 		if (retries)
 			udelay(400);
 
-		/* transaction request, wait up to 1ms for it to complete */
+		/* transaction request, wait up to 2ms for it to complete */
 		nvkm_wr32(device, 0x00d954 + base, 0x00010000 | ctrl);
 
-		timeout = 1000;
+		timeout = 2000;
 		do {
 			ctrl = nvkm_rd32(device, 0x00d954 + base);
 			udelay(1);
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
@@ -160,8 +160,18 @@
 {
 	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
 	struct nvkm_i2c_pad *pad;
+	struct nvkm_i2c_bus *bus;
+	struct nvkm_i2c_aux *aux;
 	u32 mask;
 
+	list_for_each_entry(aux, &i2c->aux, head) {
+		nvkm_i2c_aux_fini(aux);
+	}
+
+	list_for_each_entry(bus, &i2c->bus, head) {
+		nvkm_i2c_bus_fini(bus);
+	}
+
 	if ((mask = (1 << i2c->func->aux) - 1), i2c->func->aux_stat) {
 		i2c->func->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
 		i2c->func->aux_stat(i2c, &mask, &mask, &mask, &mask);
@@ -175,11 +185,31 @@
 }
 
 static int
+nvkm_i2c_preinit(struct nvkm_subdev *subdev)
+{
+	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
+	struct nvkm_i2c_bus *bus;
+	struct nvkm_i2c_pad *pad;
+
+	/*
+	 * We init our i2c busses as early as possible, since they may be
+	 * needed by the vbios init scripts on some cards
+	 */
+	list_for_each_entry(pad, &i2c->pad, head)
+		nvkm_i2c_pad_init(pad);
+	list_for_each_entry(bus, &i2c->bus, head)
+		nvkm_i2c_bus_init(bus);
+
+	return 0;
+}
+
+static int
 nvkm_i2c_init(struct nvkm_subdev *subdev)
 {
 	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
 	struct nvkm_i2c_bus *bus;
 	struct nvkm_i2c_pad *pad;
+	struct nvkm_i2c_aux *aux;
 
 	list_for_each_entry(pad, &i2c->pad, head) {
 		nvkm_i2c_pad_init(pad);
@@ -189,6 +219,10 @@
 		nvkm_i2c_bus_init(bus);
 	}
 
+	list_for_each_entry(aux, &i2c->aux, head) {
+		nvkm_i2c_aux_init(aux);
+	}
+
 	return 0;
 }
 
@@ -223,6 +257,7 @@
 static const struct nvkm_subdev_func
 nvkm_i2c = {
 	.dtor = nvkm_i2c_dtor,
+	.preinit = nvkm_i2c_preinit,
 	.init = nvkm_i2c_init,
 	.fini = nvkm_i2c_fini,
 	.intr = nvkm_i2c_intr,
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c
@@ -110,6 +110,19 @@
 	BUS_TRACE(bus, "init");
 	if (bus->func->init)
 		bus->func->init(bus);
+
+	mutex_lock(&bus->mutex);
+	bus->enabled = true;
+	mutex_unlock(&bus->mutex);
+}
+
+void
+nvkm_i2c_bus_fini(struct nvkm_i2c_bus *bus)
+{
+	BUS_TRACE(bus, "fini");
+	mutex_lock(&bus->mutex);
+	bus->enabled = false;
+	mutex_unlock(&bus->mutex);
 }
 
 void
@@ -126,9 +139,15 @@
 {
 	struct nvkm_i2c_pad *pad = bus->pad;
 	int ret;
+
 	BUS_TRACE(bus, "acquire");
 	mutex_lock(&bus->mutex);
-	ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_I2C);
+
+	if (bus->enabled)
+		ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_I2C);
+	else
+		ret = -EIO;
+
 	if (ret)
 		mutex_unlock(&bus->mutex);
 	return ret;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
@@ -17,6 +17,7 @@
 		      int id, struct nvkm_i2c_bus **);
 void nvkm_i2c_bus_del(struct nvkm_i2c_bus **);
 void nvkm_i2c_bus_init(struct nvkm_i2c_bus *);
+void nvkm_i2c_bus_fini(struct nvkm_i2c_bus *);
 
 int nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *, struct i2c_msg *, int);
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
@@ -47,8 +47,10 @@
 
 	BUG_ON((first > limit) || (limit >= ltc->num_tags));
 
+	mutex_lock(&ltc->subdev.mutex);
 	ltc->func->cbc_clear(ltc, first, limit);
 	ltc->func->cbc_wait(ltc);
+	mutex_unlock(&ltc->subdev.mutex);
 }
 
 int
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
@@ -240,6 +240,8 @@
 			mmu->func->map_pgt(vpgd->obj, pde, vpgt->mem);
 		}
 
+		mmu->func->flush(vm);
+
 		nvkm_memory_del(&pgt);
 	}
 }
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
@@ -127,6 +127,13 @@
 		return ret;
 
 	pci->irq = pdev->irq;
+
+	/* Ensure MSI interrupts are armed, for the case where there are
+	 * already interrupts pending (for whatever reason) at load time.
+	 */
+	if (pci->msi)
+		pci->func->msi_rearm(pci);
+
 	return ret;
 }
 
@@ -180,6 +187,10 @@
 		}
 	}
 
+#ifdef __BIG_ENDIAN
+	pci->msi = false;
+#endif
+
 	pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi);
 	if (pci->msi && func->msi_rearm) {
 		pci->msi = pci_enable_msi(pci->pdev) == 0;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
@@ -87,10 +87,10 @@
 	if (exec) {
 		nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC,
 			      memx->base, finish);
+		nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n",
+			   reply[0], reply[1]);
 	}
 
-	nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n",
-		   reply[0], reply[1]);
 	kfree(memx);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
@@ -130,7 +130,7 @@
 		poll = false;
 	}
 
-	if (list_empty(&therm->alarm.head) && poll)
+	if (poll)
 		nvkm_timer_alarm(tmr, 1000000000ULL, &therm->alarm);
 	spin_unlock_irqrestore(&therm->lock, flags);
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
@@ -83,7 +83,7 @@
 	spin_unlock_irqrestore(&fan->lock, flags);
 
 	/* schedule next fan update, if not at target speed already */
-	if (list_empty(&fan->alarm.head) && target != duty) {
+	if (target != duty) {
 		u16 bump_period = fan->bios.bump_period;
 		u16 slow_down_period = fan->bios.slow_down_period;
 		u64 delay;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c
@@ -53,7 +53,7 @@
 	duty = !nvkm_gpio_get(gpio, 0, DCB_GPIO_FAN, 0xff);
 	nvkm_gpio_set(gpio, 0, DCB_GPIO_FAN, 0xff, duty);
 
-	if (list_empty(&fan->alarm.head) && percent != (duty * 100)) {
+	if (percent != (duty * 100)) {
 		u64 next_change = (percent * fan->period_us) / 100;
 		if (!duty)
 			next_change = fan->period_us - next_change;
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
@@ -185,7 +185,7 @@
 	spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags);
 
 	/* schedule the next poll in one second */
-	if (therm->func->temp_get(therm) >= 0 && list_empty(&alarm->head))
+	if (therm->func->temp_get(therm) >= 0)
 		nvkm_timer_alarm(tmr, 1000000000ULL, alarm);
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
@@ -36,25 +36,32 @@
 	unsigned long flags;
 	LIST_HEAD(exec);
 
-	/* move any due alarms off the pending list */
+	/* Process pending alarms. */
 	spin_lock_irqsave(&tmr->lock, flags);
 	list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) {
-		if (alarm->timestamp <= nvkm_timer_read(tmr))
-			list_move_tail(&alarm->head, &exec);
+		/* Have we hit the earliest alarm that hasn't gone off? */
+		if (alarm->timestamp > nvkm_timer_read(tmr)) {
+			/* Schedule it.  If we didn't race, we're done. */
+			tmr->func->alarm_init(tmr, alarm->timestamp);
+			if (alarm->timestamp > nvkm_timer_read(tmr))
+				break;
+		}
+
+		/* Move to completed list.  We'll drop the lock before
+		 * executing the callback so it can reschedule itself.
+		 */
+		list_del_init(&alarm->head);
+		list_add(&alarm->exec, &exec);
 	}
 
-	/* reschedule interrupt for next alarm time */
-	if (!list_empty(&tmr->alarms)) {
-		alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head);
-		tmr->func->alarm_init(tmr, alarm->timestamp);
-	} else {
+	/* Shut down interrupt if no more pending alarms. */
+	if (list_empty(&tmr->alarms))
 		tmr->func->alarm_fini(tmr);
-	}
 	spin_unlock_irqrestore(&tmr->lock, flags);
 
-	/* execute any pending alarm handlers */
-	list_for_each_entry_safe(alarm, atemp, &exec, head) {
-		list_del_init(&alarm->head);
+	/* Execute completed callbacks. */
+	list_for_each_entry_safe(alarm, atemp, &exec, exec) {
+		list_del(&alarm->exec);
 		alarm->func(alarm);
 	}
 }
@@ -65,24 +72,37 @@
 	struct nvkm_alarm *list;
 	unsigned long flags;
 
-	alarm->timestamp = nvkm_timer_read(tmr) + nsec;
-
-	/* append new alarm to list, in soonest-alarm-first order */
+	/* Remove alarm from pending list.
+	 *
+	 * This both protects against the corruption of the list,
+	 * and implements alarm rescheduling/cancellation.
+	 */
 	spin_lock_irqsave(&tmr->lock, flags);
-	if (!nsec) {
-		if (!list_empty(&alarm->head))
-			list_del(&alarm->head);
-	} else {
+	list_del_init(&alarm->head);
+
+	if (nsec) {
+		/* Insert into pending list, ordered earliest to latest. */
+		alarm->timestamp = nvkm_timer_read(tmr) + nsec;
 		list_for_each_entry(list, &tmr->alarms, head) {
 			if (list->timestamp > alarm->timestamp)
 				break;
 		}
+
 		list_add_tail(&alarm->head, &list->head);
+
+		/* Update HW if this is now the earliest alarm. */
+		list = list_first_entry(&tmr->alarms, typeof(*list), head);
+		if (list == alarm) {
+			tmr->func->alarm_init(tmr, alarm->timestamp);
+			/* This shouldn't happen if callers aren't stupid.
+			 *
+			 * Worst case scenario is that it'll take roughly
+			 * 4 seconds for the next alarm to trigger.
+			 */
+			WARN_ON(alarm->timestamp <= nvkm_timer_read(tmr));
+		}
 	}
 	spin_unlock_irqrestore(&tmr->lock, flags);
-
-	/* process pending alarms */
-	nvkm_timer_alarm_trigger(tmr);
 }
 
 void
--- linux-4.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c
+++ linux-4.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c
@@ -76,8 +76,8 @@
 	u32 stat = nvkm_rd32(device, NV04_PTIMER_INTR_0);
 
 	if (stat & 0x00000001) {
-		nvkm_timer_alarm_trigger(tmr);
 		nvkm_wr32(device, NV04_PTIMER_INTR_0, 0x00000001);
+		nvkm_timer_alarm_trigger(tmr);
 		stat &= ~0x00000001;
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ linux-4.4.0/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -262,6 +262,17 @@
 	}
 
 	txn->last_pat->next_pa = 0;
+	/* ensure that the written descriptors are visible to DMM */
+	wmb();
+
+	/*
+	 * NOTE: the wmb() above should be enough, but there seems to be a bug
+	 * in OMAP's memory barrier implementation, which in some rare cases may
+	 * cause the writes not to be observable after wmb().
+	 */
+
+	/* read back to ensure the data is in RAM */
+	readl(&txn->last_pat->next_pa);
 
 	/* write to PAT_DESCR to clear out any pending transaction */
 	writel(0x0, dmm->base + reg[PAT_DESCR][engine->id]);
@@ -288,7 +299,12 @@
 				msecs_to_jiffies(100))) {
 			dev_err(dmm->dev, "timed out waiting for done\n");
 			ret = -ETIMEDOUT;
+			goto cleanup;
 		}
+
+		/* Check the engine status before continue */
+		ret = wait_status(engine, DMM_PATSTATUS_READY |
+				  DMM_PATSTATUS_VALID | DMM_PATSTATUS_DONE);
 	}
 
 cleanup:
@@ -611,7 +627,8 @@
 		match = of_match_node(dmm_of_match, dev->dev.of_node);
 		if (!match) {
 			dev_err(&dev->dev, "failed to find matching device node\n");
-			return -ENODEV;
+			ret = -ENODEV;
+			goto fail;
 		}
 
 		omap_dmm->plat_data = match->data;
@@ -703,6 +720,7 @@
 				&omap_dmm->refill_pa, GFP_KERNEL);
 	if (!omap_dmm->refill_va) {
 		dev_err(&dev->dev, "could not allocate refill memory\n");
+		ret = -ENOMEM;
 		goto fail;
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/omapdrm/omap_gem.c
+++ linux-4.4.0/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -158,7 +158,7 @@
 	size_t size = PAGE_SIZE * n;
 	loff_t off = mmap_offset(obj) +
 			(entry->obj_pgoff << PAGE_SHIFT);
-	const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
+	const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
 
 	if (m > 1) {
 		int i;
@@ -415,7 +415,7 @@
 	 * into account in some of the math, so figure out virtual stride
 	 * in pages
 	 */
-	const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
+	const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
 
 	/* We don't use vmf->pgoff since that has the fake offset: */
 	pgoff = ((unsigned long)vmf->virtual_address -
--- linux-4.4.0.orig/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
+++ linux-4.4.0/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
@@ -142,9 +142,6 @@
 	struct drm_gem_object *obj = buffer->priv;
 	int ret = 0;
 
-	if (WARN_ON(!obj->filp))
-		return -EINVAL;
-
 	ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma);
 	if (ret < 0)
 		return ret;
--- linux-4.4.0.orig/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
+++ linux-4.4.0/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
@@ -823,7 +823,7 @@
 	int ret, i;
 
 	ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id));
-	if (ret < ARRAY_SIZE(id) || id[0] == 0x00) {
+	if (ret < 0 || ret < ARRAY_SIZE(id) || id[0] == 0x00) {
 		dev_err(ctx->dev, "read id failed\n");
 		ctx->error = -EIO;
 		return;
--- linux-4.4.0.orig/drivers/gpu/drm/panel/panel-simple.c
+++ linux-4.4.0/drivers/gpu/drm/panel/panel-simple.c
@@ -352,6 +352,7 @@
 	drm_panel_remove(&panel->base);
 
 	panel_simple_disable(&panel->base);
+	panel_simple_unprepare(&panel->base);
 
 	if (panel->ddc)
 		put_device(&panel->ddc->dev);
@@ -367,6 +368,7 @@
 	struct panel_simple *panel = dev_get_drvdata(dev);
 
 	panel_simple_disable(&panel->base);
+	panel_simple_unprepare(&panel->base);
 }
 
 static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = {
@@ -918,7 +920,7 @@
 static const struct panel_desc lg_lb070wv8 = {
 	.modes = &lg_lb070wv8_mode,
 	.num_modes = 1,
-	.bpc = 16,
+	.bpc = 8,
 	.size = {
 		.width = 151,
 		.height = 91,
@@ -1387,7 +1389,14 @@
 	dsi->format = desc->format;
 	dsi->lanes = desc->lanes;
 
-	return mipi_dsi_attach(dsi);
+	err = mipi_dsi_attach(dsi);
+	if (err) {
+		struct panel_simple *panel = dev_get_drvdata(&dsi->dev);
+
+		drm_panel_remove(&panel->base);
+	}
+
+	return err;
 }
 
 static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi)
--- linux-4.4.0.orig/drivers/gpu/drm/qxl/qxl_cmd.c
+++ linux-4.4.0/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -500,9 +500,10 @@
 		return ret;
 
 	ret = qxl_release_reserve_list(release, true);
-	if (ret)
+	if (ret) {
+		qxl_release_free(qdev, release);
 		return ret;
-
+	}
 	cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release);
 	cmd->type = QXL_SURFACE_CMD_CREATE;
 	cmd->flags = QXL_SURF_FLAG_KEEP_DATA;
@@ -528,8 +529,8 @@
 	/* no need to add a release to the fence for this surface bo,
 	   since it is only released when we ask to destroy the surface
 	   and it would never signal otherwise */
-	qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
 
 	surf->hw_surf_alloc = true;
 	spin_lock(&qdev->surf_id_idr_lock);
@@ -571,9 +572,8 @@
 	cmd->surface_id = id;
 	qxl_release_unmap(qdev, release, &cmd->release_info);
 
-	qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
-
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/qxl/qxl_display.c
+++ linux-4.4.0/drivers/gpu/drm/qxl/qxl_display.c
@@ -292,8 +292,8 @@
 	cmd->type = QXL_CURSOR_HIDE;
 	qxl_release_unmap(qdev, release, &cmd->release_info);
 
-	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
 	return 0;
 }
 
@@ -375,18 +375,23 @@
 
 	qxl_bo_kunmap(user_bo);
 
+	qcrtc->cur_x += qcrtc->hot_spot_x - hot_x;
+	qcrtc->cur_y += qcrtc->hot_spot_y - hot_y;
+	qcrtc->hot_spot_x = hot_x;
+	qcrtc->hot_spot_y = hot_y;
+
 	cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
 	cmd->type = QXL_CURSOR_SET;
-	cmd->u.set.position.x = qcrtc->cur_x;
-	cmd->u.set.position.y = qcrtc->cur_y;
+	cmd->u.set.position.x = qcrtc->cur_x + qcrtc->hot_spot_x;
+	cmd->u.set.position.y = qcrtc->cur_y + qcrtc->hot_spot_y;
 
 	cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0);
 
 	cmd->u.set.visible = 1;
 	qxl_release_unmap(qdev, release, &cmd->release_info);
 
-	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
 
 	/* finish with the userspace bo */
 	ret = qxl_bo_reserve(user_bo, false);
@@ -441,12 +446,12 @@
 
 	cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
 	cmd->type = QXL_CURSOR_MOVE;
-	cmd->u.position.x = qcrtc->cur_x;
-	cmd->u.position.y = qcrtc->cur_y;
+	cmd->u.position.x = qcrtc->cur_x + qcrtc->hot_spot_x;
+	cmd->u.position.y = qcrtc->cur_y + qcrtc->hot_spot_y;
 	qxl_release_unmap(qdev, release, &cmd->release_info);
 
-	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/qxl/qxl_draw.c
+++ linux-4.4.0/drivers/gpu/drm/qxl/qxl_draw.c
@@ -136,6 +136,8 @@
 				 * correctly globaly, since that would require
 				 * tracking all of our palettes. */
 	ret = qxl_bo_kmap(palette_bo, (void **)&pal);
+	if (ret)
+		return ret;
 	pal->num_ents = 2;
 	pal->unique = unique++;
 	if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) {
@@ -243,8 +245,8 @@
 		qxl_bo_physical_address(qdev, dimage->bo, 0);
 	qxl_release_unmap(qdev, release, &drawable->release_info);
 
-	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 
 out_free_palette:
 	if (palette_bo)
@@ -350,9 +352,10 @@
 		goto out_release_backoff;
 
 	rects = drawable_set_clipping(qdev, drawable, num_clips, clips_bo);
-	if (!rects)
+	if (!rects) {
+		ret = -EINVAL;
 		goto out_release_backoff;
-
+	}
 	drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
 
 	drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
@@ -383,8 +386,8 @@
 	}
 	qxl_bo_kunmap(clips_bo);
 
-	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 
 out_release_backoff:
 	if (ret)
@@ -434,8 +437,8 @@
 	drawable->u.copy_bits.src_pos.y = sy;
 	qxl_release_unmap(qdev, release, &drawable->release_info);
 
-	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 
 out_free_release:
 	if (ret)
@@ -478,8 +481,8 @@
 
 	qxl_release_unmap(qdev, release, &drawable->release_info);
 
-	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 	qxl_release_fence_buffer_objects(release);
+	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 
 out_free_release:
 	if (ret)
--- linux-4.4.0.orig/drivers/gpu/drm/qxl/qxl_drv.h
+++ linux-4.4.0/drivers/gpu/drm/qxl/qxl_drv.h
@@ -135,6 +135,8 @@
 	int index;
 	int cur_x;
 	int cur_y;
+	int hot_spot_x;
+	int hot_spot_y;
 };
 
 struct qxl_output {
--- linux-4.4.0.orig/drivers/gpu/drm/qxl/qxl_fb.c
+++ linux-4.4.0/drivers/gpu/drm/qxl/qxl_fb.c
@@ -494,9 +494,11 @@
 
 int qxl_fbdev_init(struct qxl_device *qdev)
 {
+	int ret = 0;
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct qxl_fbdev *qfbdev;
 	int bpp_sel = 32; /* TODO: parameter from somewhere? */
-	int ret;
 
 	qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL);
 	if (!qfbdev)
@@ -531,6 +533,8 @@
 	drm_fb_helper_fini(&qfbdev->helper);
 free:
 	kfree(qfbdev);
+#endif
+
 	return ret;
 }
 
@@ -546,6 +550,9 @@
 
 void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)
 {
+	if (!qdev->mode_info.qfbdev)
+		return;
+
 	drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state);
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/qxl/qxl_image.c
+++ linux-4.4.0/drivers/gpu/drm/qxl/qxl_image.c
@@ -210,7 +210,8 @@
 		break;
 	default:
 		DRM_ERROR("unsupported image bit depth\n");
-		return -EINVAL; /* TODO: cleanup */
+		qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
+		return -EINVAL;
 	}
 	image->u.bitmap.flags = QXL_BITMAP_TOP_DOWN;
 	image->u.bitmap.x = width;
--- linux-4.4.0.orig/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ linux-4.4.0/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -168,7 +168,8 @@
 		       cmd->command_size))
 		return -EFAULT;
 
-	reloc_info = kmalloc(sizeof(struct qxl_reloc_info) * cmd->relocs_num, GFP_KERNEL);
+	reloc_info = kmalloc_array(cmd->relocs_num,
+				   sizeof(struct qxl_reloc_info), GFP_KERNEL);
 	if (!reloc_info)
 		return -ENOMEM;
 
@@ -256,11 +257,8 @@
 			apply_surf_reloc(qdev, &reloc_info[i]);
 	}
 
+	qxl_release_fence_buffer_objects(release);
 	ret = qxl_push_command_ring_release(qdev, release, cmd->type, true);
-	if (ret)
-		qxl_release_backoff_reserve_list(release);
-	else
-		qxl_release_fence_buffer_objects(release);
 
 out_free_bos:
 out_free_release:
--- linux-4.4.0.orig/drivers/gpu/drm/qxl/qxl_kms.c
+++ linux-4.4.0/drivers/gpu/drm/qxl/qxl_kms.c
@@ -199,7 +199,7 @@
 				&(qdev->ram_header->cursor_ring_hdr),
 				sizeof(struct qxl_command),
 				QXL_CURSOR_RING_SIZE,
-				qdev->io_base + QXL_IO_NOTIFY_CMD,
+				qdev->io_base + QXL_IO_NOTIFY_CURSOR,
 				false,
 				&qdev->cursor_event);
 
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/atombios_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -275,6 +275,8 @@
 			atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
 		atombios_blank_crtc(crtc, ATOM_DISABLE);
 		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
+		/* Make sure vblank interrupt is still enabled if needed */
+		radeon_irq_set(rdev);
 		radeon_crtc_load_lut(crtc);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
@@ -1739,6 +1741,7 @@
 static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
+	struct radeon_device *rdev = dev->dev_private;
 	struct drm_crtc *test_crtc;
 	struct radeon_crtc *test_radeon_crtc;
 
@@ -1748,6 +1751,10 @@
 		test_radeon_crtc = to_radeon_crtc(test_crtc);
 		if (test_radeon_crtc->encoder &&
 		    ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) {
+			/* PPLL2 is exclusive to UNIPHYA on DCE61 */
+			if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) &&
+			    test_radeon_crtc->pll_id == ATOM_PPLL2)
+				continue;
 			/* for DP use the same PLL for all */
 			if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
 				return test_radeon_crtc->pll_id;
@@ -1769,6 +1776,7 @@
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
+	struct radeon_device *rdev = dev->dev_private;
 	struct drm_crtc *test_crtc;
 	struct radeon_crtc *test_radeon_crtc;
 	u32 adjusted_clock, test_adjusted_clock;
@@ -1784,6 +1792,10 @@
 		test_radeon_crtc = to_radeon_crtc(test_crtc);
 		if (test_radeon_crtc->encoder &&
 		    !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) {
+			/* PPLL2 is exclusive to UNIPHYA on DCE61 */
+			if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) &&
+			    test_radeon_crtc->pll_id == ATOM_PPLL2)
+				continue;
 			/* check if we are already driving this connector with another crtc */
 			if (test_radeon_crtc->connector == radeon_crtc->connector) {
 				/* if we are, return that pll */
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/atombios_dp.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/atombios_dp.c
@@ -45,34 +45,32 @@
 
 /***** radeon AUX functions *****/
 
-/* Atom needs data in little endian format
- * so swap as appropriate when copying data to
- * or from atom. Note that atom operates on
- * dw units.
+/* Atom needs data in little endian format so swap as appropriate when copying
+ * data to or from atom. Note that atom operates on dw units.
+ *
+ * Use to_le=true when sending data to atom and provide at least
+ * ALIGN(num_bytes,4) bytes in the dst buffer.
+ *
+ * Use to_le=false when receiving data from atom and provide ALIGN(num_bytes,4)
+ * byes in the src buffer.
  */
 void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
 {
 #ifdef __BIG_ENDIAN
-	u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
-	u32 *dst32, *src32;
+	u32 src_tmp[5], dst_tmp[5];
 	int i;
+	u8 align_num_bytes = ALIGN(num_bytes, 4);
 
-	memcpy(src_tmp, src, num_bytes);
-	src32 = (u32 *)src_tmp;
-	dst32 = (u32 *)dst_tmp;
 	if (to_le) {
-		for (i = 0; i < ((num_bytes + 3) / 4); i++)
-			dst32[i] = cpu_to_le32(src32[i]);
-		memcpy(dst, dst_tmp, num_bytes);
+		memcpy(src_tmp, src, num_bytes);
+		for (i = 0; i < align_num_bytes / 4; i++)
+			dst_tmp[i] = cpu_to_le32(src_tmp[i]);
+		memcpy(dst, dst_tmp, align_num_bytes);
 	} else {
-		u8 dws = num_bytes & ~3;
-		for (i = 0; i < ((num_bytes + 3) / 4); i++)
-			dst32[i] = le32_to_cpu(src32[i]);
-		memcpy(dst, dst_tmp, dws);
-		if (num_bytes % 4) {
-			for (i = 0; i < (num_bytes % 4); i++)
-				dst[dws+i] = dst_tmp[dws+i];
-		}
+		memcpy(src_tmp, src, align_num_bytes);
+		for (i = 0; i < align_num_bytes / 4; i++)
+			dst_tmp[i] = le32_to_cpu(src_tmp[i]);
+		memcpy(dst, dst_tmp, num_bytes);
 	}
 #else
 	memcpy(dst, src, num_bytes);
@@ -302,77 +300,43 @@
 		return bpc * 3;
 }
 
-/* get the max pix clock supported by the link rate and lane num */
-static int dp_get_max_dp_pix_clock(int link_rate,
-				   int lane_num,
-				   int bpp)
-{
-	return (link_rate * lane_num * 8) / bpp;
-}
-
 /***** radeon specific DP functions *****/
 
-int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-				const u8 dpcd[DP_DPCD_SIZE])
-{
-	int max_link_rate;
-
-	if (radeon_connector_is_dp12_capable(connector))
-		max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000);
-	else
-		max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000);
-
-	return max_link_rate;
-}
-
-/* First get the min lane# when low rate is used according to pixel clock
- * (prefer low rate), second check max lane# supported by DP panel,
- * if the max lane# < low rate lane# then use max lane# instead.
- */
-static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
-					const u8 dpcd[DP_DPCD_SIZE],
-					int pix_clock)
-{
-	int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
-	int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd);
-	int max_lane_num = drm_dp_max_lane_count(dpcd);
-	int lane_num;
-	int max_dp_pix_clock;
-
-	for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
-		max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
-		if (pix_clock <= max_dp_pix_clock)
-			break;
-	}
-
-	return lane_num;
-}
-
-static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
-				       const u8 dpcd[DP_DPCD_SIZE],
-				       int pix_clock)
+int radeon_dp_get_dp_link_config(struct drm_connector *connector,
+				 const u8 dpcd[DP_DPCD_SIZE],
+				 unsigned pix_clock,
+				 unsigned *dp_lanes, unsigned *dp_rate)
 {
 	int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
-	int lane_num, max_pix_clock;
+	static const unsigned link_rates[3] = { 162000, 270000, 540000 };
+	unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
+	unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+	unsigned lane_num, i, max_pix_clock;
 
 	if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
-	    ENCODER_OBJECT_ID_NUTMEG)
-		return 270000;
-
-	lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
-	max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
-	if (pix_clock <= max_pix_clock)
-		return 162000;
-	max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
-	if (pix_clock <= max_pix_clock)
-		return 270000;
-	if (radeon_connector_is_dp12_capable(connector)) {
-		max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
-		if (pix_clock <= max_pix_clock)
-			return 540000;
+	    ENCODER_OBJECT_ID_NUTMEG) {
+		for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+			max_pix_clock = (lane_num * 270000 * 8) / bpp;
+			if (max_pix_clock >= pix_clock) {
+				*dp_lanes = lane_num;
+				*dp_rate = 270000;
+				return 0;
+			}
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
+			for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+				max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+				if (max_pix_clock >= pix_clock) {
+					*dp_lanes = lane_num;
+					*dp_rate = link_rates[i];
+					return 0;
+				}
+			}
+		}
 	}
 
-	return radeon_dp_get_max_link_rate(connector, dpcd);
+	return -EINVAL;
 }
 
 static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
@@ -491,6 +455,7 @@
 {
 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 	struct radeon_connector_atom_dig *dig_connector;
+	int ret;
 
 	if (!radeon_connector->con_priv)
 		return;
@@ -498,10 +463,14 @@
 
 	if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
 	    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
-		dig_connector->dp_clock =
-			radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
-		dig_connector->dp_lane_count =
-			radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+		ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
+						   mode->clock,
+						   &dig_connector->dp_lane_count,
+						   &dig_connector->dp_clock);
+		if (ret) {
+			dig_connector->dp_clock = 0;
+			dig_connector->dp_lane_count = 0;
+		}
 	}
 }
 
@@ -510,7 +479,8 @@
 {
 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 	struct radeon_connector_atom_dig *dig_connector;
-	int dp_clock;
+	unsigned dp_clock, dp_lanes;
+	int ret;
 
 	if ((mode->clock > 340000) &&
 	    (!radeon_connector_is_dp12_capable(connector)))
@@ -520,8 +490,12 @@
 		return MODE_CLOCK_HIGH;
 	dig_connector = radeon_connector->con_priv;
 
-	dp_clock =
-		radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+	ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
+					   mode->clock,
+					   &dp_lanes,
+					   &dp_clock);
+	if (ret)
+		return MODE_CLOCK_HIGH;
 
 	if ((dp_clock == 540000) &&
 	    (!radeon_connector_is_dp12_capable(connector)))
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/atombios_encoders.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -30,6 +30,7 @@
 #include "radeon_audio.h"
 #include "atom.h"
 #include <linux/backlight.h>
+#include <linux/dmi.h>
 
 extern int atom_debug;
 
@@ -120,6 +121,7 @@
 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 			if (dig->backlight_level == 0)
 				atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
 			else {
@@ -310,6 +312,10 @@
 	    && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
 		adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
 
+	/* vertical FP must be at least 1 */
+	if (mode->crtc_vsync_start == mode->crtc_vdisplay)
+		adjusted_mode->crtc_vsync_start++;
+
 	/* get the native mode for scaling */
 	if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
 		radeon_panel_mode_fixup(encoder, adjusted_mode);
@@ -892,8 +898,6 @@
 			else
 				args.v1.ucLaneNum = 4;
 
-			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000))
-				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
 			switch (radeon_encoder->encoder_id) {
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
@@ -910,6 +914,10 @@
 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
 			else
 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
+
+			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000))
+				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+
 			break;
 		case 2:
 		case 3:
@@ -2176,9 +2184,17 @@
 		goto assigned;
 	}
 
-	/* on DCE32 and encoder can driver any block so just crtc id */
+	/*
+	 * On DCE32 any encoder can drive any block so usually just use crtc id,
+	 * but Apple thinks different at least on iMac10,1, so there use linkb,
+	 * otherwise the internal eDP panel will stay dark.
+	 */
 	if (ASIC_IS_DCE32(rdev)) {
-		enc_idx = radeon_crtc->crtc_id;
+		if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1"))
+			enc_idx = (dig->linkb) ? 1 : 0;
+		else
+			enc_idx = radeon_crtc->crtc_id;
+
 		goto assigned;
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/ci_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/ci_dpm.c
@@ -776,6 +776,18 @@
 	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
 	u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
 
+	/* disable mclk switching if the refresh is >120Hz, even if the
+        * blanking period would allow it
+        */
+	if (r600_dpm_get_vrefresh(rdev) > 120)
+		return true;
+
+	/* disable mclk switching if the refresh is >120Hz, even if the
+        * blanking period would allow it
+        */
+	if (r600_dpm_get_vrefresh(rdev) > 120)
+		return true;
+
 	if (vblank_time < switch_limit)
 		return true;
 	else
@@ -4333,7 +4345,7 @@
 					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
 			}
 			j++;
-			if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+			if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
 				return -EINVAL;
 
 			if (!pi->mem_gddr5) {
@@ -5542,6 +5554,7 @@
 	if (!rdev->pm.dpm.ps)
 		return -ENOMEM;
 	power_state_offset = (u8 *)state_array->states;
+	rdev->pm.dpm.num_ps = 0;
 	for (i = 0; i < state_array->ucNumEntries; i++) {
 		u8 *idx;
 		power_state = (union pplib_power_state *)power_state_offset;
@@ -5551,10 +5564,8 @@
 		if (!rdev->pm.power_state[i].clock_info)
 			return -EINVAL;
 		ps = kzalloc(sizeof(struct ci_ps), GFP_KERNEL);
-		if (ps == NULL) {
-			kfree(rdev->pm.dpm.ps);
+		if (ps == NULL)
 			return -ENOMEM;
-		}
 		rdev->pm.dpm.ps[i].ps_priv = ps;
 		ci_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
 					      non_clock_info,
@@ -5576,8 +5587,8 @@
 			k++;
 		}
 		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+		rdev->pm.dpm.num_ps = i + 1;
 	}
-	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
 
 	/* fill in the vce power states */
 	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/cik.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/cik.c
@@ -3599,35 +3599,8 @@
 	case CHIP_KAVERI:
 		rdev->config.cik.max_shader_engines = 1;
 		rdev->config.cik.max_tile_pipes = 4;
-		if ((rdev->pdev->device == 0x1304) ||
-		    (rdev->pdev->device == 0x1305) ||
-		    (rdev->pdev->device == 0x130C) ||
-		    (rdev->pdev->device == 0x130F) ||
-		    (rdev->pdev->device == 0x1310) ||
-		    (rdev->pdev->device == 0x1311) ||
-		    (rdev->pdev->device == 0x131C)) {
-			rdev->config.cik.max_cu_per_sh = 8;
-			rdev->config.cik.max_backends_per_se = 2;
-		} else if ((rdev->pdev->device == 0x1309) ||
-			   (rdev->pdev->device == 0x130A) ||
-			   (rdev->pdev->device == 0x130D) ||
-			   (rdev->pdev->device == 0x1313) ||
-			   (rdev->pdev->device == 0x131D)) {
-			rdev->config.cik.max_cu_per_sh = 6;
-			rdev->config.cik.max_backends_per_se = 2;
-		} else if ((rdev->pdev->device == 0x1306) ||
-			   (rdev->pdev->device == 0x1307) ||
-			   (rdev->pdev->device == 0x130B) ||
-			   (rdev->pdev->device == 0x130E) ||
-			   (rdev->pdev->device == 0x1315) ||
-			   (rdev->pdev->device == 0x1318) ||
-			   (rdev->pdev->device == 0x131B)) {
-			rdev->config.cik.max_cu_per_sh = 4;
-			rdev->config.cik.max_backends_per_se = 1;
-		} else {
-			rdev->config.cik.max_cu_per_sh = 3;
-			rdev->config.cik.max_backends_per_se = 1;
-		}
+		rdev->config.cik.max_cu_per_sh = 8;
+		rdev->config.cik.max_backends_per_se = 2;
 		rdev->config.cik.max_sh_per_se = 1;
 		rdev->config.cik.max_texture_channel_caches = 4;
 		rdev->config.cik.max_gprs = 256;
@@ -7399,8 +7372,8 @@
 	}
 
 	/* setup interrupt control */
-	/* XXX this should actually be a bus address, not an MC address. same on older asics */
-	WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8);
+	/* set dummy read address to dummy page address */
+	WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8);
 	interrupt_cntl = RREG32(INTERRUPT_CNTL);
 	/* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi
 	 * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN
@@ -7762,7 +7735,7 @@
 		WREG32(DC_HPD5_INT_CONTROL, tmp);
 	}
 	if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp = RREG32(DC_HPD6_INT_CONTROL);
 		tmp |= DC_HPDx_INT_ACK;
 		WREG32(DC_HPD6_INT_CONTROL, tmp);
 	}
@@ -7792,7 +7765,7 @@
 		WREG32(DC_HPD5_INT_CONTROL, tmp);
 	}
 	if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp = RREG32(DC_HPD6_INT_CONTROL);
 		tmp |= DC_HPDx_RX_INT_ACK;
 		WREG32(DC_HPD6_INT_CONTROL, tmp);
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/dce6_afmt.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/dce6_afmt.c
@@ -301,6 +301,14 @@
 	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
 	 */
 	if (ASIC_IS_DCE8(rdev)) {
+		unsigned int div = (RREG32(DENTIST_DISPCLK_CNTL) &
+			DENTIST_DPREFCLK_WDIVIDER_MASK) >>
+			DENTIST_DPREFCLK_WDIVIDER_SHIFT;
+		div = radeon_audio_decode_dfs_div(div);
+
+		if (div)
+			clock = clock * 100 / div;
+
 		WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000);
 		WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock);
 	} else {
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/evergreen.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/evergreen.c
@@ -2608,10 +2608,152 @@
 	WREG32(VM_CONTEXT1_CNTL, 0);
 }
 
+static const unsigned ni_dig_offsets[] =
+{
+	NI_DIG0_REGISTER_OFFSET,
+	NI_DIG1_REGISTER_OFFSET,
+	NI_DIG2_REGISTER_OFFSET,
+	NI_DIG3_REGISTER_OFFSET,
+	NI_DIG4_REGISTER_OFFSET,
+	NI_DIG5_REGISTER_OFFSET
+};
+
+static const unsigned ni_tx_offsets[] =
+{
+	NI_DCIO_UNIPHY0_UNIPHY_TX_CONTROL1,
+	NI_DCIO_UNIPHY1_UNIPHY_TX_CONTROL1,
+	NI_DCIO_UNIPHY2_UNIPHY_TX_CONTROL1,
+	NI_DCIO_UNIPHY3_UNIPHY_TX_CONTROL1,
+	NI_DCIO_UNIPHY4_UNIPHY_TX_CONTROL1,
+	NI_DCIO_UNIPHY5_UNIPHY_TX_CONTROL1
+};
+
+static const unsigned evergreen_dp_offsets[] =
+{
+	EVERGREEN_DP0_REGISTER_OFFSET,
+	EVERGREEN_DP1_REGISTER_OFFSET,
+	EVERGREEN_DP2_REGISTER_OFFSET,
+	EVERGREEN_DP3_REGISTER_OFFSET,
+	EVERGREEN_DP4_REGISTER_OFFSET,
+	EVERGREEN_DP5_REGISTER_OFFSET
+};
+
+
+/*
+ * Assumption is that EVERGREEN_CRTC_MASTER_EN enable for requested crtc
+ * We go from crtc to connector and it is not relible  since it
+ * should be an opposite direction .If crtc is enable then
+ * find the dig_fe which selects this crtc and insure that it enable.
+ * if such dig_fe is found then find dig_be which selects found dig_be and
+ * insure that it enable and in DP_SST mode.
+ * if UNIPHY_PLL_CONTROL1.enable then we should disconnect timing
+ * from dp symbols clocks .
+ */
+static bool evergreen_is_dp_sst_stream_enabled(struct radeon_device *rdev,
+					       unsigned crtc_id, unsigned *ret_dig_fe)
+{
+	unsigned i;
+	unsigned dig_fe;
+	unsigned dig_be;
+	unsigned dig_en_be;
+	unsigned uniphy_pll;
+	unsigned digs_fe_selected;
+	unsigned dig_be_mode;
+	unsigned dig_fe_mask;
+	bool is_enabled = false;
+	bool found_crtc = false;
+
+	/* loop through all running dig_fe to find selected crtc */
+	for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) {
+		dig_fe = RREG32(NI_DIG_FE_CNTL + ni_dig_offsets[i]);
+		if (dig_fe & NI_DIG_FE_CNTL_SYMCLK_FE_ON &&
+		    crtc_id == NI_DIG_FE_CNTL_SOURCE_SELECT(dig_fe)) {
+			/* found running pipe */
+			found_crtc = true;
+			dig_fe_mask = 1 << i;
+			dig_fe = i;
+			break;
+		}
+	}
+
+	if (found_crtc) {
+		/* loop through all running dig_be to find selected dig_fe */
+		for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) {
+			dig_be = RREG32(NI_DIG_BE_CNTL + ni_dig_offsets[i]);
+			/* if dig_fe_selected by dig_be? */
+			digs_fe_selected = NI_DIG_BE_CNTL_FE_SOURCE_SELECT(dig_be);
+			dig_be_mode = NI_DIG_FE_CNTL_MODE(dig_be);
+			if (dig_fe_mask &  digs_fe_selected &&
+			    /* if dig_be in sst mode? */
+			    dig_be_mode == NI_DIG_BE_DPSST) {
+				dig_en_be = RREG32(NI_DIG_BE_EN_CNTL +
+						   ni_dig_offsets[i]);
+				uniphy_pll = RREG32(NI_DCIO_UNIPHY0_PLL_CONTROL1 +
+						    ni_tx_offsets[i]);
+				/* dig_be enable and tx is running */
+				if (dig_en_be & NI_DIG_BE_EN_CNTL_ENABLE &&
+				    dig_en_be & NI_DIG_BE_EN_CNTL_SYMBCLK_ON &&
+				    uniphy_pll & NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE) {
+					is_enabled = true;
+					*ret_dig_fe = dig_fe;
+					break;
+				}
+			}
+		}
+	}
+
+	return is_enabled;
+}
+
+/*
+ * Blank dig when in dp sst mode
+ * Dig ignores crtc timing
+ */
+static void evergreen_blank_dp_output(struct radeon_device *rdev,
+				      unsigned dig_fe)
+{
+	unsigned stream_ctrl;
+	unsigned fifo_ctrl;
+	unsigned counter = 0;
+
+	if (dig_fe >= ARRAY_SIZE(evergreen_dp_offsets)) {
+		DRM_ERROR("invalid dig_fe %d\n", dig_fe);
+		return;
+	}
+
+	stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL +
+			     evergreen_dp_offsets[dig_fe]);
+	if (!(stream_ctrl & EVERGREEN_DP_VID_STREAM_CNTL_ENABLE)) {
+		DRM_ERROR("dig %d , should be enable\n", dig_fe);
+		return;
+	}
+
+	stream_ctrl &=~EVERGREEN_DP_VID_STREAM_CNTL_ENABLE;
+	WREG32(EVERGREEN_DP_VID_STREAM_CNTL +
+	       evergreen_dp_offsets[dig_fe], stream_ctrl);
+
+	stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL +
+			     evergreen_dp_offsets[dig_fe]);
+	while (counter < 32 && stream_ctrl & EVERGREEN_DP_VID_STREAM_STATUS) {
+		msleep(1);
+		counter++;
+		stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL +
+				     evergreen_dp_offsets[dig_fe]);
+	}
+	if (counter >= 32 )
+		DRM_ERROR("counter exceeds %d\n", counter);
+
+	fifo_ctrl = RREG32(EVERGREEN_DP_STEER_FIFO + evergreen_dp_offsets[dig_fe]);
+	fifo_ctrl |= EVERGREEN_DP_STEER_FIFO_RESET;
+	WREG32(EVERGREEN_DP_STEER_FIFO + evergreen_dp_offsets[dig_fe], fifo_ctrl);
+
+}
+
 void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
 {
 	u32 crtc_enabled, tmp, frame_count, blackout;
 	int i, j;
+	unsigned dig_fe;
 
 	if (!ASIC_IS_NODCE(rdev)) {
 		save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
@@ -2651,7 +2793,17 @@
 					break;
 				udelay(1);
 			}
-
+			/*we should disable dig if it drives dp sst*/
+			/*but we are in radeon_device_init and the topology is unknown*/
+			/*and it is available after radeon_modeset_init*/
+			/*the following method radeon_atom_encoder_dpms_dig*/
+			/*does the job if we initialize it properly*/
+			/*for now we do it this manually*/
+			/**/
+			if (ASIC_IS_DCE5(rdev) &&
+			    evergreen_is_dp_sst_stream_enabled(rdev, i ,&dig_fe))
+				evergreen_blank_dp_output(rdev, dig_fe);
+			/*we could remove 6 lines below*/
 			/* XXX this is a hack to avoid strange behavior with EFI on certain systems */
 			WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
 			tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
@@ -4772,7 +4924,7 @@
 		WREG32(DC_HPD5_INT_CONTROL, tmp);
 	}
 	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp = RREG32(DC_HPD6_INT_CONTROL);
 		tmp |= DC_HPDx_INT_ACK;
 		WREG32(DC_HPD6_INT_CONTROL, tmp);
 	}
@@ -4803,7 +4955,7 @@
 		WREG32(DC_HPD5_INT_CONTROL, tmp);
 	}
 	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp = RREG32(DC_HPD6_INT_CONTROL);
 		tmp |= DC_HPDx_RX_INT_ACK;
 		WREG32(DC_HPD6_INT_CONTROL, tmp);
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/evergreen_cs.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -1299,6 +1299,7 @@
 			return -EINVAL;
 		}
 		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
+		break;
 	case CB_TARGET_MASK:
 		track->cb_target_mask = radeon_get_ib_value(p, idx);
 		track->cb_dirty = true;
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -289,6 +289,16 @@
 	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
 	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
 	 */
+	if (ASIC_IS_DCE41(rdev)) {
+		unsigned int div = (RREG32(DCE41_DENTIST_DISPCLK_CNTL) &
+			DENTIST_DPREFCLK_WDIVIDER_MASK) >>
+			DENTIST_DPREFCLK_WDIVIDER_SHIFT;
+		div = radeon_audio_decode_dfs_div(div);
+
+		if (div)
+			clock = 100 * clock / div;
+	}
+
 	WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
 	WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
 }
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/evergreen_reg.h
+++ linux-4.4.0/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -250,8 +250,43 @@
 
 /* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */
 #define EVERGREEN_HDMI_BASE				0x7030
+/*DIG block*/
+#define NI_DIG0_REGISTER_OFFSET                 (0x7000  - 0x7000)
+#define NI_DIG1_REGISTER_OFFSET                 (0x7C00  - 0x7000)
+#define NI_DIG2_REGISTER_OFFSET                 (0x10800 - 0x7000)
+#define NI_DIG3_REGISTER_OFFSET                 (0x11400 - 0x7000)
+#define NI_DIG4_REGISTER_OFFSET                 (0x12000 - 0x7000)
+#define NI_DIG5_REGISTER_OFFSET                 (0x12C00 - 0x7000)
+
+
+#define NI_DIG_FE_CNTL                               0x7000
+#       define NI_DIG_FE_CNTL_SOURCE_SELECT(x)        ((x) & 0x3)
+#       define NI_DIG_FE_CNTL_SYMCLK_FE_ON            (1<<24)
+
+
+#define NI_DIG_BE_CNTL                    0x7140
+#       define NI_DIG_BE_CNTL_FE_SOURCE_SELECT(x)     (((x) >> 8 ) & 0x3F)
+#       define NI_DIG_FE_CNTL_MODE(x)                 (((x) >> 16) & 0x7 )
+
+#define NI_DIG_BE_EN_CNTL                              0x7144
+#       define NI_DIG_BE_EN_CNTL_ENABLE               (1 << 0)
+#       define NI_DIG_BE_EN_CNTL_SYMBCLK_ON           (1 << 8)
+#       define NI_DIG_BE_DPSST 0
 
 /* Display Port block */
+#define EVERGREEN_DP0_REGISTER_OFFSET                 (0x730C  - 0x730C)
+#define EVERGREEN_DP1_REGISTER_OFFSET                 (0x7F0C  - 0x730C)
+#define EVERGREEN_DP2_REGISTER_OFFSET                 (0x10B0C - 0x730C)
+#define EVERGREEN_DP3_REGISTER_OFFSET                 (0x1170C - 0x730C)
+#define EVERGREEN_DP4_REGISTER_OFFSET                 (0x1230C - 0x730C)
+#define EVERGREEN_DP5_REGISTER_OFFSET                 (0x12F0C - 0x730C)
+
+
+#define EVERGREEN_DP_VID_STREAM_CNTL                    0x730C
+#       define EVERGREEN_DP_VID_STREAM_CNTL_ENABLE     (1 << 0)
+#       define EVERGREEN_DP_VID_STREAM_STATUS          (1 <<16)
+#define EVERGREEN_DP_STEER_FIFO                         0x7310
+#       define EVERGREEN_DP_STEER_FIFO_RESET           (1 << 0)
 #define EVERGREEN_DP_SEC_CNTL                           0x7280
 #       define EVERGREEN_DP_SEC_STREAM_ENABLE           (1 << 0)
 #       define EVERGREEN_DP_SEC_ASP_ENABLE              (1 << 4)
@@ -266,4 +301,15 @@
 #       define EVERGREEN_DP_SEC_N_BASE_MULTIPLE(x)      (((x) & 0xf) << 24)
 #       define EVERGREEN_DP_SEC_SS_EN                   (1 << 28)
 
+/*DCIO_UNIPHY block*/
+#define NI_DCIO_UNIPHY0_UNIPHY_TX_CONTROL1            (0x6600  -0x6600)
+#define NI_DCIO_UNIPHY1_UNIPHY_TX_CONTROL1            (0x6640  -0x6600)
+#define NI_DCIO_UNIPHY2_UNIPHY_TX_CONTROL1            (0x6680 - 0x6600)
+#define NI_DCIO_UNIPHY3_UNIPHY_TX_CONTROL1            (0x66C0 - 0x6600)
+#define NI_DCIO_UNIPHY4_UNIPHY_TX_CONTROL1            (0x6700 - 0x6600)
+#define NI_DCIO_UNIPHY5_UNIPHY_TX_CONTROL1            (0x6740 - 0x6600)
+
+#define NI_DCIO_UNIPHY0_PLL_CONTROL1                   0x6618
+#       define NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE     (1 << 0)
+
 #endif
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/evergreend.h
+++ linux-4.4.0/drivers/gpu/drm/radeon/evergreend.h
@@ -511,6 +511,11 @@
 #define DCCG_AUDIO_DTO1_CNTL              0x05cc
 #       define DCCG_AUDIO_DTO1_USE_512FBR_DTO (1 << 3)
 
+#define DCE41_DENTIST_DISPCLK_CNTL			0x049c
+#       define DENTIST_DPREFCLK_WDIVIDER(x)		(((x) & 0x7f) << 24)
+#       define DENTIST_DPREFCLK_WDIVIDER_MASK		(0x7f << 24)
+#       define DENTIST_DPREFCLK_WDIVIDER_SHIFT		24
+
 /* DCE 4.0 AFMT */
 #define HDMI_CONTROL                         0x7030
 #       define HDMI_KEEPOUT_MODE             (1 << 0)
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/ni.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/ni.c
@@ -1396,9 +1396,7 @@
 void cayman_cp_int_cntl_setup(struct radeon_device *rdev,
 			      int ring, u32 cp_int_cntl)
 {
-	u32 srbm_gfx_cntl = RREG32(SRBM_GFX_CNTL) & ~3;
-
-	WREG32(SRBM_GFX_CNTL, srbm_gfx_cntl | (ring & 3));
+	WREG32(SRBM_GFX_CNTL, RINGID(ring));
 	WREG32(CP_INT_CNTL, cp_int_cntl);
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/ni_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/ni_dpm.c
@@ -2128,7 +2128,7 @@
 		if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
 			ret = -EINVAL;
 
-		if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
+		if (fb_div & ~(SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT))
 			ret = -EINVAL;
 
 		if (clk_v & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT))
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/r100.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/r100.c
@@ -1826,8 +1826,8 @@
 			track->textures[i].use_pitch = 1;
 		} else {
 			track->textures[i].use_pitch = 0;
-			track->textures[i].width = 1 << ((idx_value >> RADEON_TXFORMAT_WIDTH_SHIFT) & RADEON_TXFORMAT_WIDTH_MASK);
-			track->textures[i].height = 1 << ((idx_value >> RADEON_TXFORMAT_HEIGHT_SHIFT) & RADEON_TXFORMAT_HEIGHT_MASK);
+			track->textures[i].width = 1 << ((idx_value & RADEON_TXFORMAT_WIDTH_MASK) >> RADEON_TXFORMAT_WIDTH_SHIFT);
+			track->textures[i].height = 1 << ((idx_value & RADEON_TXFORMAT_HEIGHT_MASK) >> RADEON_TXFORMAT_HEIGHT_SHIFT);
 		}
 		if (idx_value & RADEON_TXFORMAT_CUBIC_MAP_ENABLE)
 			track->textures[i].tex_coord_type = 2;
@@ -3150,7 +3150,8 @@
 {
 	fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff;
 	fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff;
-	fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff;
+	fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff;
+	fixed20_12 crit_point_ff = {0};
 	uint32_t temp, data, mem_trcd, mem_trp, mem_tras;
 	fixed20_12 memtcas_ff[8] = {
 		dfixed_init(1),
@@ -3204,7 +3205,7 @@
 	fixed20_12 min_mem_eff;
 	fixed20_12 mc_latency_sclk, mc_latency_mclk, k1;
 	fixed20_12 cur_latency_mclk, cur_latency_sclk;
-	fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate,
+	fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate = {0},
 		disp_drain_rate2, read_return_rate;
 	fixed20_12 time_disp1_drop_priority;
 	int c;
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/r200.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/r200.c
@@ -476,8 +476,8 @@
 			track->textures[i].use_pitch = 1;
 		} else {
 			track->textures[i].use_pitch = 0;
-			track->textures[i].width = 1 << ((idx_value >> RADEON_TXFORMAT_WIDTH_SHIFT) & RADEON_TXFORMAT_WIDTH_MASK);
-			track->textures[i].height = 1 << ((idx_value >> RADEON_TXFORMAT_HEIGHT_SHIFT) & RADEON_TXFORMAT_HEIGHT_MASK);
+			track->textures[i].width = 1 << ((idx_value & RADEON_TXFORMAT_WIDTH_MASK) >> RADEON_TXFORMAT_WIDTH_SHIFT);
+			track->textures[i].height = 1 << ((idx_value & RADEON_TXFORMAT_HEIGHT_MASK) >> RADEON_TXFORMAT_HEIGHT_SHIFT);
 		}
 		if (idx_value & R200_TXFORMAT_LOOKUP_DISABLE)
 			track->textures[i].lookup_disable = true;
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/r600.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/r600.c
@@ -3647,8 +3647,8 @@
 	}
 
 	/* setup interrupt control */
-	/* set dummy read address to ring address */
-	WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8);
+	/* set dummy read address to dummy page address */
+	WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8);
 	interrupt_cntl = RREG32(INTERRUPT_CNTL);
 	/* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi
 	 * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN
@@ -3945,7 +3945,7 @@
 			WREG32(DC_HPD5_INT_CONTROL, tmp);
 		}
 		if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) {
-			tmp = RREG32(DC_HPD5_INT_CONTROL);
+			tmp = RREG32(DC_HPD6_INT_CONTROL);
 			tmp |= DC_HPDx_INT_ACK;
 			WREG32(DC_HPD6_INT_CONTROL, tmp);
 		}
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/r600_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/r600_dpm.c
@@ -156,19 +156,20 @@
 	struct drm_device *dev = rdev->ddev;
 	struct drm_crtc *crtc;
 	struct radeon_crtc *radeon_crtc;
-	u32 line_time_us, vblank_lines;
+	u32 vblank_in_pixels;
 	u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
 
 	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 			radeon_crtc = to_radeon_crtc(crtc);
 			if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
-				line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) /
-					radeon_crtc->hw_mode.clock;
-				vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end -
-					radeon_crtc->hw_mode.crtc_vdisplay +
-					(radeon_crtc->v_border * 2);
-				vblank_time_us = vblank_lines * line_time_us;
+				vblank_in_pixels =
+					radeon_crtc->hw_mode.crtc_htotal *
+					(radeon_crtc->hw_mode.crtc_vblank_end -
+					 radeon_crtc->hw_mode.crtc_vdisplay +
+					 (radeon_crtc->v_border * 2));
+
+				vblank_time_us = vblank_in_pixels * 1000 / radeon_crtc->hw_mode.clock;
 				break;
 			}
 		}
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon.h
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon.h
@@ -268,6 +268,7 @@
 	uint32_t current_dispclk;
 	uint32_t dp_extclk;
 	uint32_t max_pixel_clock;
+	uint32_t vco_freq;
 };
 
 /*
@@ -1889,7 +1890,7 @@
 		void (*pad_ib)(struct radeon_ib *ib);
 	} vm;
 	/* ring specific callbacks */
-	struct radeon_asic_ring *ring[RADEON_NUM_RINGS];
+	const struct radeon_asic_ring *ring[RADEON_NUM_RINGS];
 	/* irqs */
 	struct {
 		int (*set)(struct radeon_device *rdev);
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_asic.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_asic.c
@@ -179,7 +179,7 @@
  * ASIC
  */
 
-static struct radeon_asic_ring r100_gfx_ring = {
+static const struct radeon_asic_ring r100_gfx_ring = {
 	.ib_execute = &r100_ring_ib_execute,
 	.emit_fence = &r100_fence_ring_emit,
 	.emit_semaphore = &r100_semaphore_ring_emit,
@@ -329,7 +329,7 @@
 	},
 };
 
-static struct radeon_asic_ring r300_gfx_ring = {
+static const struct radeon_asic_ring r300_gfx_ring = {
 	.ib_execute = &r100_ring_ib_execute,
 	.emit_fence = &r300_fence_ring_emit,
 	.emit_semaphore = &r100_semaphore_ring_emit,
@@ -343,7 +343,7 @@
 	.set_wptr = &r100_gfx_set_wptr,
 };
 
-static struct radeon_asic_ring rv515_gfx_ring = {
+static const struct radeon_asic_ring rv515_gfx_ring = {
 	.ib_execute = &r100_ring_ib_execute,
 	.emit_fence = &r300_fence_ring_emit,
 	.emit_semaphore = &r100_semaphore_ring_emit,
@@ -901,7 +901,7 @@
 	},
 };
 
-static struct radeon_asic_ring r600_gfx_ring = {
+static const struct radeon_asic_ring r600_gfx_ring = {
 	.ib_execute = &r600_ring_ib_execute,
 	.emit_fence = &r600_fence_ring_emit,
 	.emit_semaphore = &r600_semaphore_ring_emit,
@@ -914,7 +914,7 @@
 	.set_wptr = &r600_gfx_set_wptr,
 };
 
-static struct radeon_asic_ring r600_dma_ring = {
+static const struct radeon_asic_ring r600_dma_ring = {
 	.ib_execute = &r600_dma_ring_ib_execute,
 	.emit_fence = &r600_dma_fence_ring_emit,
 	.emit_semaphore = &r600_dma_semaphore_ring_emit,
@@ -999,7 +999,7 @@
 	},
 };
 
-static struct radeon_asic_ring rv6xx_uvd_ring = {
+static const struct radeon_asic_ring rv6xx_uvd_ring = {
 	.ib_execute = &uvd_v1_0_ib_execute,
 	.emit_fence = &uvd_v1_0_fence_emit,
 	.emit_semaphore = &uvd_v1_0_semaphore_emit,
@@ -1198,7 +1198,7 @@
 	},
 };
 
-static struct radeon_asic_ring rv770_uvd_ring = {
+static const struct radeon_asic_ring rv770_uvd_ring = {
 	.ib_execute = &uvd_v1_0_ib_execute,
 	.emit_fence = &uvd_v2_2_fence_emit,
 	.emit_semaphore = &uvd_v2_2_semaphore_emit,
@@ -1305,7 +1305,7 @@
 	},
 };
 
-static struct radeon_asic_ring evergreen_gfx_ring = {
+static const struct radeon_asic_ring evergreen_gfx_ring = {
 	.ib_execute = &evergreen_ring_ib_execute,
 	.emit_fence = &r600_fence_ring_emit,
 	.emit_semaphore = &r600_semaphore_ring_emit,
@@ -1318,7 +1318,7 @@
 	.set_wptr = &r600_gfx_set_wptr,
 };
 
-static struct radeon_asic_ring evergreen_dma_ring = {
+static const struct radeon_asic_ring evergreen_dma_ring = {
 	.ib_execute = &evergreen_dma_ring_ib_execute,
 	.emit_fence = &evergreen_dma_fence_ring_emit,
 	.emit_semaphore = &r600_dma_semaphore_ring_emit,
@@ -1612,7 +1612,7 @@
 	},
 };
 
-static struct radeon_asic_ring cayman_gfx_ring = {
+static const struct radeon_asic_ring cayman_gfx_ring = {
 	.ib_execute = &cayman_ring_ib_execute,
 	.ib_parse = &evergreen_ib_parse,
 	.emit_fence = &cayman_fence_ring_emit,
@@ -1627,7 +1627,7 @@
 	.set_wptr = &cayman_gfx_set_wptr,
 };
 
-static struct radeon_asic_ring cayman_dma_ring = {
+static const struct radeon_asic_ring cayman_dma_ring = {
 	.ib_execute = &cayman_dma_ring_ib_execute,
 	.ib_parse = &evergreen_dma_ib_parse,
 	.emit_fence = &evergreen_dma_fence_ring_emit,
@@ -1642,7 +1642,7 @@
 	.set_wptr = &cayman_dma_set_wptr
 };
 
-static struct radeon_asic_ring cayman_uvd_ring = {
+static const struct radeon_asic_ring cayman_uvd_ring = {
 	.ib_execute = &uvd_v1_0_ib_execute,
 	.emit_fence = &uvd_v2_2_fence_emit,
 	.emit_semaphore = &uvd_v3_1_semaphore_emit,
@@ -1760,7 +1760,7 @@
 	},
 };
 
-static struct radeon_asic_ring trinity_vce_ring = {
+static const struct radeon_asic_ring trinity_vce_ring = {
 	.ib_execute = &radeon_vce_ib_execute,
 	.emit_fence = &radeon_vce_fence_emit,
 	.emit_semaphore = &radeon_vce_semaphore_emit,
@@ -1881,7 +1881,7 @@
 	},
 };
 
-static struct radeon_asic_ring si_gfx_ring = {
+static const struct radeon_asic_ring si_gfx_ring = {
 	.ib_execute = &si_ring_ib_execute,
 	.ib_parse = &si_ib_parse,
 	.emit_fence = &si_fence_ring_emit,
@@ -1896,7 +1896,7 @@
 	.set_wptr = &cayman_gfx_set_wptr,
 };
 
-static struct radeon_asic_ring si_dma_ring = {
+static const struct radeon_asic_ring si_dma_ring = {
 	.ib_execute = &cayman_dma_ring_ib_execute,
 	.ib_parse = &evergreen_dma_ib_parse,
 	.emit_fence = &evergreen_dma_fence_ring_emit,
@@ -2023,7 +2023,7 @@
 	},
 };
 
-static struct radeon_asic_ring ci_gfx_ring = {
+static const struct radeon_asic_ring ci_gfx_ring = {
 	.ib_execute = &cik_ring_ib_execute,
 	.ib_parse = &cik_ib_parse,
 	.emit_fence = &cik_fence_gfx_ring_emit,
@@ -2038,7 +2038,7 @@
 	.set_wptr = &cik_gfx_set_wptr,
 };
 
-static struct radeon_asic_ring ci_cp_ring = {
+static const struct radeon_asic_ring ci_cp_ring = {
 	.ib_execute = &cik_ring_ib_execute,
 	.ib_parse = &cik_ib_parse,
 	.emit_fence = &cik_fence_compute_ring_emit,
@@ -2053,7 +2053,7 @@
 	.set_wptr = &cik_compute_set_wptr,
 };
 
-static struct radeon_asic_ring ci_dma_ring = {
+static const struct radeon_asic_ring ci_dma_ring = {
 	.ib_execute = &cik_sdma_ring_ib_execute,
 	.ib_parse = &cik_ib_parse,
 	.emit_fence = &cik_sdma_fence_ring_emit,
@@ -2068,7 +2068,7 @@
 	.set_wptr = &cik_sdma_set_wptr,
 };
 
-static struct radeon_asic_ring ci_vce_ring = {
+static const struct radeon_asic_ring ci_vce_ring = {
 	.ib_execute = &radeon_vce_ib_execute,
 	.emit_fence = &radeon_vce_fence_emit,
 	.emit_semaphore = &radeon_vce_semaphore_emit,
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_atombios.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -437,7 +437,9 @@
 	}
 
 	/* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */
-	if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) &&
+	if (((dev->pdev->device == 0x9802) ||
+	     (dev->pdev->device == 0x9805) ||
+	     (dev->pdev->device == 0x9806)) &&
 	    (dev->pdev->subsystem_vendor == 0x1734) &&
 	    (dev->pdev->subsystem_device == 0x11bd)) {
 		if (*connector_type == DRM_MODE_CONNECTOR_VGA) {
@@ -448,14 +450,6 @@
 		}
 	}
 
-	/* Fujitsu D3003-S2 board lists DVI-I as DVI-I and VGA */
-	if ((dev->pdev->device == 0x9805) &&
-	    (dev->pdev->subsystem_vendor == 0x1734) &&
-	    (dev->pdev->subsystem_device == 0x11bd)) {
-		if (*connector_type == DRM_MODE_CONNECTOR_VGA)
-			return false;
-	}
-
 	return true;
 }
 
@@ -1112,6 +1106,31 @@
 	ATOM_FIRMWARE_INFO_V2_2 info_22;
 };
 
+union igp_info {
+	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
+};
+
+static void radeon_atombios_get_dentist_vco_freq(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+	union igp_info *igp_info;
+	u8 frev, crev;
+	u16 data_offset;
+
+	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
+			&frev, &crev, &data_offset)) {
+		igp_info = (union igp_info *)(mode_info->atom_context->bios +
+			data_offset);
+		rdev->clock.vco_freq =
+			le32_to_cpu(igp_info->info_6.ulDentistVCOFreq);
+	}
+}
+
 bool radeon_atom_get_clock_info(struct drm_device *dev)
 {
 	struct radeon_device *rdev = dev->dev_private;
@@ -1136,7 +1155,7 @@
 		    le16_to_cpu(firmware_info->info.usReferenceClock);
 		p1pll->reference_div = 0;
 
-		if (crev < 2)
+		if ((frev < 2) && (crev < 2))
 			p1pll->pll_out_min =
 				le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
 		else
@@ -1145,7 +1164,7 @@
 		p1pll->pll_out_max =
 		    le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
 
-		if (crev >= 4) {
+		if (((frev < 2) && (crev >= 4)) || (frev >= 2)) {
 			p1pll->lcd_pll_out_min =
 				le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
 			if (p1pll->lcd_pll_out_min == 0)
@@ -1263,20 +1282,25 @@
 		rdev->mode_info.firmware_flags =
 			le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);
 
+		if (ASIC_IS_DCE8(rdev))
+			rdev->clock.vco_freq =
+				le32_to_cpu(firmware_info->info_22.ulGPUPLL_OutputFreq);
+		else if (ASIC_IS_DCE5(rdev))
+			rdev->clock.vco_freq = rdev->clock.current_dispclk;
+		else if (ASIC_IS_DCE41(rdev))
+			radeon_atombios_get_dentist_vco_freq(rdev);
+		else
+			rdev->clock.vco_freq = rdev->clock.current_dispclk;
+
+		if (rdev->clock.vco_freq == 0)
+			rdev->clock.vco_freq = 360000;	/* 3.6 GHz */
+
 		return true;
 	}
 
 	return false;
 }
 
-union igp_info {
-	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
-	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
-	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
-	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
-	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
-};
-
 bool radeon_atombios_sideport_present(struct radeon_device *rdev)
 {
 	struct radeon_mode_info *mode_info = &rdev->mode_info;
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_atpx_handler.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -10,6 +10,7 @@
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 
 #include "radeon_acpi.h"
 
@@ -255,6 +256,10 @@
 		if (!info)
 			return -EIO;
 		kfree(info);
+
+		/* 200ms delay is required after off */
+		if (state == 0)
+			msleep(200);
 	}
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_audio.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_audio.c
@@ -739,9 +739,6 @@
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
-	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
-	struct radeon_connector_atom_dig *dig_connector =
-		radeon_connector->con_priv;
 
 	if (!dig || !dig->afmt)
 		return;
@@ -753,10 +750,7 @@
 		radeon_audio_write_speaker_allocation(encoder);
 		radeon_audio_write_sad_regs(encoder);
 		radeon_audio_write_latency_fields(encoder, mode);
-		if (rdev->clock.dp_extclk || ASIC_IS_DCE5(rdev))
-			radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
-		else
-			radeon_audio_set_dto(encoder, dig_connector->dp_clock);
+		radeon_audio_set_dto(encoder, rdev->clock.vco_freq * 10);
 		radeon_audio_set_audio_packet(encoder);
 		radeon_audio_select_pin(encoder);
 
@@ -781,3 +775,15 @@
 	if (radeon_encoder->audio && radeon_encoder->audio->dpms)
 		radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON);
 }
+
+unsigned int radeon_audio_decode_dfs_div(unsigned int div)
+{
+	if (div >= 8 && div < 64)
+		return (div - 8) * 25 + 200;
+	else if (div >= 64 && div < 96)
+		return (div - 64) * 50 + 1600;
+	else if (div >= 96 && div < 128)
+		return (div - 96) * 100 + 3200;
+	else
+		return 0;
+}
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_audio.h
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_audio.h
@@ -79,5 +79,6 @@
 void radeon_audio_mode_set(struct drm_encoder *encoder,
 	struct drm_display_mode *mode);
 void radeon_audio_dpms(struct drm_encoder *encoder, int mode);
+unsigned int radeon_audio_decode_dfs_div(unsigned int div);
 
 #endif
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_combios.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_combios.c
@@ -3394,6 +3394,13 @@
 	    rdev->pdev->subsystem_vendor == 0x103c &&
 	    rdev->pdev->subsystem_device == 0x280a)
 		return;
+	/* quirk for rs4xx Toshiba Sattellite L20-183 latop to make it resume
+	 * - it hangs on resume inside the dynclk 1 table.
+	 */
+	if (rdev->family == CHIP_RS400 &&
+	    rdev->pdev->subsystem_vendor == 0x1179 &&
+	    rdev->pdev->subsystem_device == 0xff31)
+	        return;
 
 	/* DYN CLK 1 */
 	table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_connectors.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -89,25 +89,18 @@
 		/* don't do anything if sink is not display port, i.e.,
 		 * passive dp->(dvi|hdmi) adaptor
 		 */
-		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-			int saved_dpms = connector->dpms;
-			/* Only turn off the display if it's physically disconnected */
-			if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
-				drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
-			} else if (radeon_dp_needs_link_train(radeon_connector)) {
-				/* Don't try to start link training before we
-				 * have the dpcd */
-				if (!radeon_dp_getdpcd(radeon_connector))
-					return;
-
-				/* set it to OFF so that drm_helper_connector_dpms()
-				 * won't return immediately since the current state
-				 * is ON at this point.
-				 */
-				connector->dpms = DRM_MODE_DPMS_OFF;
-				drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-			}
-			connector->dpms = saved_dpms;
+		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
+		    radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
+		    radeon_dp_needs_link_train(radeon_connector)) {
+			/* Don't start link training before we have the DPCD */
+			if (!radeon_dp_getdpcd(radeon_connector))
+				return;
+
+			/* Turn the connector off and back on immediately, which
+			 * will trigger link training
+			 */
+			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
 		}
 	}
 }
@@ -765,7 +758,7 @@
 
 		radeon_encoder->output_csc = val;
 
-		if (connector->encoder->crtc) {
+		if (connector->encoder && connector->encoder->crtc) {
 			struct drm_crtc *crtc  = connector->encoder->crtc;
 			const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
 			struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -851,7 +844,7 @@
 	return ret;
 }
 
-static int radeon_lvds_mode_valid(struct drm_connector *connector,
+static enum drm_mode_status radeon_lvds_mode_valid(struct drm_connector *connector,
 				  struct drm_display_mode *mode)
 {
 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
@@ -891,9 +884,13 @@
 	enum drm_connector_status ret = connector_status_disconnected;
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	if (encoder) {
 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -916,8 +913,12 @@
 	/* check acpi lid status ??? */
 
 	radeon_connector_update_scratch_regs(connector, ret);
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
+
 	return ret;
 }
 
@@ -994,7 +995,7 @@
 	return ret;
 }
 
-static int radeon_vga_mode_valid(struct drm_connector *connector,
+static enum drm_mode_status radeon_vga_mode_valid(struct drm_connector *connector,
 				  struct drm_display_mode *mode)
 {
 	struct drm_device *dev = connector->dev;
@@ -1020,9 +1021,13 @@
 	enum drm_connector_status ret = connector_status_disconnected;
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	encoder = radeon_best_single_encoder(connector);
 	if (!encoder)
@@ -1089,8 +1094,10 @@
 	radeon_connector_update_scratch_regs(connector, ret);
 
 out:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -1133,7 +1140,7 @@
 	return 1;
 }
 
-static int radeon_tv_mode_valid(struct drm_connector *connector,
+static enum drm_mode_status radeon_tv_mode_valid(struct drm_connector *connector,
 				struct drm_display_mode *mode)
 {
 	if ((mode->hdisplay > 1024) || (mode->vdisplay > 768))
@@ -1153,9 +1160,13 @@
 	if (!radeon_connector->dac_load_detect)
 		return ret;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	encoder = radeon_best_single_encoder(connector);
 	if (!encoder)
@@ -1167,8 +1178,12 @@
 	if (ret == connector_status_connected)
 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
 	radeon_connector_update_scratch_regs(connector, ret);
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
+
 	return ret;
 }
 
@@ -1230,9 +1245,13 @@
 	enum drm_connector_status ret = connector_status_disconnected;
 	bool dret = false, broken_edid = false;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	if (radeon_connector->detected_hpd_without_ddc) {
 		force = true;
@@ -1415,8 +1434,10 @@
 	}
 
 exit:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -1464,7 +1485,7 @@
 		radeon_connector->use_digital = true;
 }
 
-static int radeon_dvi_mode_valid(struct drm_connector *connector,
+static enum drm_mode_status radeon_dvi_mode_valid(struct drm_connector *connector,
 				  struct drm_display_mode *mode)
 {
 	struct drm_device *dev = connector->dev;
@@ -1666,9 +1687,13 @@
 	if (radeon_dig_connector->is_mst)
 		return connector_status_disconnected;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
+			return connector_status_disconnected;
+		}
+	}
 
 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
 		ret = connector->status;
@@ -1755,13 +1780,15 @@
 	}
 
 out:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
 
-static int radeon_dp_mode_valid(struct drm_connector *connector,
+static enum drm_mode_status radeon_dp_mode_valid(struct drm_connector *connector,
 				  struct drm_display_mode *mode)
 {
 	struct drm_device *dev = connector->dev;
@@ -1996,10 +2023,12 @@
 						   rdev->mode_info.dither_property,
 						   RADEON_FMT_DITHER_DISABLE);
 
-			if (radeon_audio != 0)
+			if (radeon_audio != 0) {
 				drm_object_attach_property(&radeon_connector->base.base,
 							   rdev->mode_info.audio_property,
 							   RADEON_AUDIO_AUTO);
+				radeon_connector->audio = RADEON_AUDIO_AUTO;
+			}
 			if (ASIC_IS_DCE5(rdev))
 				drm_object_attach_property(&radeon_connector->base.base,
 							   rdev->mode_info.output_csc_property,
@@ -2056,7 +2085,6 @@
 							   RADEON_OUTPUT_CSC_BYPASS);
 			/* no HPD on analog connectors */
 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 			connector->interlace_allowed = true;
 			connector->doublescan_allowed = true;
 			break;
@@ -2124,6 +2152,7 @@
 				drm_object_attach_property(&radeon_connector->base.base,
 							   rdev->mode_info.audio_property,
 							   RADEON_AUDIO_AUTO);
+				radeon_connector->audio = RADEON_AUDIO_AUTO;
 			}
 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
 				radeon_connector->dac_load_detect = true;
@@ -2179,6 +2208,7 @@
 				drm_object_attach_property(&radeon_connector->base.base,
 							   rdev->mode_info.audio_property,
 							   RADEON_AUDIO_AUTO);
+				radeon_connector->audio = RADEON_AUDIO_AUTO;
 			}
 			if (ASIC_IS_DCE5(rdev))
 				drm_object_attach_property(&radeon_connector->base.base,
@@ -2231,6 +2261,7 @@
 				drm_object_attach_property(&radeon_connector->base.base,
 							   rdev->mode_info.audio_property,
 							   RADEON_AUDIO_AUTO);
+				radeon_connector->audio = RADEON_AUDIO_AUTO;
 			}
 			if (ASIC_IS_DCE5(rdev))
 				drm_object_attach_property(&radeon_connector->base.base,
@@ -2303,8 +2334,10 @@
 	}
 
 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
-		if (i2c_bus->valid)
-			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+		if (i2c_bus->valid) {
+			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+			                    DRM_CONNECTOR_POLL_DISCONNECT;
+		}
 	} else
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
 
@@ -2380,7 +2413,6 @@
 					      1);
 		/* no HPD on analog connectors */
 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 		connector->interlace_allowed = true;
 		connector->doublescan_allowed = true;
 		break;
@@ -2465,10 +2497,13 @@
 	}
 
 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
-		if (i2c_bus->valid)
-			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+		if (i2c_bus->valid) {
+			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+			                    DRM_CONNECTOR_POLL_DISCONNECT;
+		}
 	} else
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
+
 	connector->display_info.subpixel_order = subpixel_order;
 	drm_connector_register(connector);
 }
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_cursor.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -90,6 +90,9 @@
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 	struct radeon_device *rdev = crtc->dev->dev_private;
 
+	if (radeon_crtc->cursor_out_of_bounds)
+		return;
+
 	if (ASIC_IS_DCE4(rdev)) {
 		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
 		       upper_32_bits(radeon_crtc->cursor_addr));
@@ -143,21 +146,25 @@
 	int xorigin = 0, yorigin = 0;
 	int w = radeon_crtc->cursor_width;
 
+	radeon_crtc->cursor_x = x;
+	radeon_crtc->cursor_y = y;
+
 	if (ASIC_IS_AVIVO(rdev)) {
 		/* avivo cursor are offset into the total surface */
 		x += crtc->x;
 		y += crtc->y;
 	}
-	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
 
-	if (x < 0) {
+	if (x < 0)
 		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
-		x = 0;
-	}
-	if (y < 0) {
+	if (y < 0)
 		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
-		y = 0;
+
+	if (!ASIC_IS_AVIVO(rdev)) {
+		x += crtc->x;
+		y += crtc->y;
 	}
+	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
 
 	/* fixed on DCE6 and newer */
 	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
@@ -180,27 +187,31 @@
 		if (i > 1) {
 			int cursor_end, frame_end;
 
-			cursor_end = x - xorigin + w;
+			cursor_end = x + w;
 			frame_end = crtc->x + crtc->mode.crtc_hdisplay;
 			if (cursor_end >= frame_end) {
 				w = w - (cursor_end - frame_end);
 				if (!(frame_end & 0x7f))
 					w--;
-			} else {
-				if (!(cursor_end & 0x7f))
-					w--;
+			} else if (cursor_end <= 0) {
+				goto out_of_bounds;
+			} else if (!(cursor_end & 0x7f)) {
+				w--;
 			}
 			if (w <= 0) {
-				w = 1;
-				cursor_end = x - xorigin + w;
-				if (!(cursor_end & 0x7f)) {
-					x--;
-					WARN_ON_ONCE(x < 0);
-				}
+				goto out_of_bounds;
 			}
 		}
 	}
 
+	if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
+	    x >= (crtc->x + crtc->mode.hdisplay) ||
+	    y >= (crtc->y + crtc->mode.vdisplay))
+		goto out_of_bounds;
+
+	x += xorigin;
+	y += yorigin;
+
 	if (ASIC_IS_DCE4(rdev)) {
 		WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
 		WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
@@ -212,6 +223,9 @@
 		WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
 		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
 	} else {
+		x -= crtc->x;
+		y -= crtc->y;
+
 		if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
 			y *= 2;
 
@@ -229,10 +243,20 @@
 		       yorigin * 256);
 	}
 
-	radeon_crtc->cursor_x = x;
-	radeon_crtc->cursor_y = y;
+	if (radeon_crtc->cursor_out_of_bounds) {
+		radeon_crtc->cursor_out_of_bounds = false;
+		if (radeon_crtc->cursor_bo)
+			radeon_show_cursor(crtc);
+	}
 
 	return 0;
+
+ out_of_bounds:
+	if (!radeon_crtc->cursor_out_of_bounds) {
+		radeon_hide_cursor(crtc);
+		radeon_crtc->cursor_out_of_bounds = true;
+	}
+	return 0;
 }
 
 int radeon_crtc_cursor_move(struct drm_crtc *crtc,
@@ -297,22 +321,23 @@
 		return ret;
 	}
 
-	radeon_crtc->cursor_width = width;
-	radeon_crtc->cursor_height = height;
-
 	radeon_lock_cursor(crtc, true);
 
-	if (hot_x != radeon_crtc->cursor_hot_x ||
+	if (width != radeon_crtc->cursor_width ||
+	    height != radeon_crtc->cursor_height ||
+	    hot_x != radeon_crtc->cursor_hot_x ||
 	    hot_y != radeon_crtc->cursor_hot_y) {
 		int x, y;
 
 		x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
 		y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
 
-		radeon_cursor_move_locked(crtc, x, y);
-
+		radeon_crtc->cursor_width = width;
+		radeon_crtc->cursor_height = height;
 		radeon_crtc->cursor_hot_x = hot_x;
 		radeon_crtc->cursor_hot_y = hot_y;
+
+		radeon_cursor_move_locked(crtc, x, y);
 	}
 
 	radeon_show_cursor(crtc);
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_device.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_device.c
@@ -127,6 +127,10 @@
 	 * https://bugzilla.kernel.org/show_bug.cgi?id=51381
 	 */
 	{ PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX },
+	/* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU
+	 * https://bugs.freedesktop.org/show_bug.cgi?id=101491
+	 */
+	{ PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX },
 	/* macbook pro 8.2 */
 	{ PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP },
 	{ 0, 0, 0, 0, 0 },
@@ -630,6 +634,23 @@
 /*
  * GPU helpers function.
  */
+
+/**
+ * radeon_device_is_virtual - check if we are running is a virtual environment
+ *
+ * Check if the asic has been passed through to a VM (all asics).
+ * Used at driver startup.
+ * Returns true if virtual or false if not.
+ */
+static bool radeon_device_is_virtual(void)
+{
+#ifdef CONFIG_X86
+	return boot_cpu_has(X86_FEATURE_HYPERVISOR);
+#else
+	return false;
+#endif
+}
+
 /**
  * radeon_card_posted - check if the hw has already been initialized
  *
@@ -643,6 +664,11 @@
 {
 	uint32_t reg;
 
+	/* for pass through, always force asic_init for CI */
+	if (rdev->family >= CHIP_BONAIRE &&
+	    radeon_device_is_virtual())
+		return false;
+
 	/* required for EFI mode on macbook2,1 which uses an r5xx asic */
 	if (efi_enabled(EFI_BOOT) &&
 	    (rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_display.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_display.c
@@ -110,6 +110,8 @@
 
 	DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id);
 
+	msleep(10);
+
 	WREG32(NI_INPUT_CSC_CONTROL + radeon_crtc->crtc_offset,
 	       (NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS) |
 		NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS)));
@@ -403,7 +405,8 @@
 	struct drm_crtc *crtc = &radeon_crtc->base;
 	unsigned long flags;
 	int r;
-	int vpos, hpos, stat, min_udelay;
+	int vpos, hpos, stat, min_udelay = 0;
+	unsigned repcnt = 4;
 	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
 
         down_read(&rdev->exclusive_lock);
@@ -454,7 +457,7 @@
 	 * In practice this won't execute very often unless on very fast
 	 * machines because the time window for this to happen is very small.
 	 */
-	for (;;) {
+	while (radeon_crtc->enabled && --repcnt) {
 		/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
 		 * start in hpos, and to the "fudged earlier" vblank start in
 		 * vpos.
@@ -470,12 +473,24 @@
 			break;
 
 		/* Sleep at least until estimated real start of hw vblank */
-		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 		min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+		if (min_udelay > vblank->framedur_ns / 2000) {
+			/* Don't wait ridiculously long - something is wrong */
+			repcnt = 0;
+			break;
+		}
+		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 		usleep_range(min_udelay, 2 * min_udelay);
 		spin_lock_irqsave(&crtc->dev->event_lock, flags);
 	};
 
+	if (!repcnt)
+		DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
+				 "framedur %d, linedur %d, stat %d, vpos %d, "
+				 "hpos %d\n", work->crtc_id, min_udelay,
+				 vblank->framedur_ns / 1000,
+				 vblank->linedur_ns / 1000, stat, vpos, hpos);
+
 	/* do the flip (mmio) */
 	radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base);
 
@@ -645,8 +660,10 @@
 	dev = set->crtc->dev;
 
 	ret = pm_runtime_get_sync(dev->dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_autosuspend(dev->dev);
 		return ret;
+	}
 
 	ret = drm_crtc_helper_set_config(set);
 
@@ -693,11 +710,16 @@
 	if (radeon_crtc == NULL)
 		return;
 
+	radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0);
+	if (!radeon_crtc->flip_queue) {
+		kfree(radeon_crtc);
+		return;
+	}
+
 	drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
 	radeon_crtc->crtc_id = index;
-	radeon_crtc->flip_queue = create_singlethread_workqueue("radeon-crtc");
 	rdev->mode_info.crtcs[index] = radeon_crtc;
 
 	if (rdev->family >= CHIP_BONAIRE) {
@@ -1361,6 +1383,12 @@
 		return ERR_PTR(-ENOENT);
 	}
 
+	/* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */
+	if (obj->import_attach) {
+		DRM_DEBUG_KMS("Cannot create framebuffer from imported dma_buf\n");
+		return ERR_PTR(-EINVAL);
+	}
+
 	radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
 	if (radeon_fb == NULL) {
 		drm_gem_object_unreference_unlocked(obj);
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_dp_mst.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_dp_mst.c
@@ -525,11 +525,9 @@
 	drm_mode_set_crtcinfo(adjusted_mode, 0);
 	{
 	  struct radeon_connector_atom_dig *dig_connector;
-
 	  dig_connector = mst_enc->connector->con_priv;
 	  dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
-	  dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
-								dig_connector->dpcd);
+	  dig_connector->dp_clock = drm_dp_max_link_rate(dig_connector->dpcd);
 	  DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
 			dig_connector->dp_lane_count, dig_connector->dp_clock);
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_drv.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_drv.c
@@ -527,8 +527,10 @@
 	long ret;
 	dev = file_priv->minor->dev;
 	ret = pm_runtime_get_sync(dev->dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_autosuspend(dev->dev);
 		return ret;
+	}
 
 	ret = drm_ioctl(filp, cmd, arg);
 	
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_fb.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_fb.c
@@ -226,7 +226,6 @@
 	}
 
 	info->par = rfbdev;
-	info->skip_vt_switch = true;
 
 	ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
 	if (ret) {
@@ -283,7 +282,7 @@
 
 	}
 	if (fb && ret) {
-		drm_gem_object_unreference(gobj);
+		drm_gem_object_unreference_unlocked(gobj);
 		drm_framebuffer_unregister_private(fb);
 		drm_framebuffer_cleanup(fb);
 		kfree(fb);
@@ -293,7 +292,8 @@
 
 void radeon_fb_output_poll_changed(struct radeon_device *rdev)
 {
-	drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper);
+	if (rdev->mode_info.rfbdev)
+		drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper);
 }
 
 static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
@@ -326,6 +326,10 @@
 	int bpp_sel = 32;
 	int ret;
 
+	/* don't enable fbdev if no connectors */
+	if (list_empty(&rdev->ddev->mode_config.connector_list))
+		return 0;
+
 	/* select 8 bpp console on RN50 or 16MB cards */
 	if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
 		bpp_sel = 8;
@@ -378,11 +382,15 @@
 
 void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
 {
-	fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
+	if (rdev->mode_info.rfbdev)
+		fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
 }
 
 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
 {
+	if (!rdev->mode_info.rfbdev)
+		return false;
+
 	if (robj == gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj))
 		return true;
 	return false;
@@ -390,12 +398,14 @@
 
 void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector)
 {
-	drm_fb_helper_add_one_connector(&rdev->mode_info.rfbdev->helper, connector);
+	if (rdev->mode_info.rfbdev)
+		drm_fb_helper_add_one_connector(&rdev->mode_info.rfbdev->helper, connector);
 }
 
 void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector)
 {
-	drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector);
+	if (rdev->mode_info.rfbdev)
+		drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector);
 }
 
 void radeon_fbdev_restore_mode(struct radeon_device *rdev)
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_fence.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_fence.c
@@ -130,7 +130,7 @@
 		      struct radeon_fence **fence,
 		      int ring)
 {
-	u64 seq = ++rdev->fence_drv[ring].sync_seq[ring];
+	u64 seq;
 
 	/* we are protected by the ring emission mutex */
 	*fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL);
@@ -138,7 +138,7 @@
 		return -ENOMEM;
 	}
 	(*fence)->rdev = rdev;
-	(*fence)->seq = seq;
+	(*fence)->seq = seq = ++rdev->fence_drv[ring].sync_seq[ring];
 	(*fence)->ring = ring;
 	(*fence)->is_vm_update = false;
 	fence_init(&(*fence)->base, &radeon_fence_ops,
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_gem.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_gem.c
@@ -663,6 +663,7 @@
 	bo_va = radeon_vm_bo_find(&fpriv->vm, rbo);
 	if (!bo_va) {
 		args->operation = RADEON_VA_RESULT_ERROR;
+		radeon_bo_unreserve(rbo);
 		drm_gem_object_unreference_unlocked(gobj);
 		return -ENOENT;
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_kms.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_kms.c
@@ -631,8 +631,10 @@
 	file_priv->driver_priv = NULL;
 
 	r = pm_runtime_get_sync(dev->dev);
-	if (r < 0)
+	if (r < 0) {
+		pm_runtime_put_autosuspend(dev->dev);
 		return r;
+	}
 
 	/* new gpu have virtual address space support */
 	if (rdev->family >= CHIP_CAYMAN) {
@@ -748,19 +750,19 @@
  * radeon_get_vblank_counter_kms - get frame count
  *
  * @dev: drm dev pointer
- * @crtc: crtc to get the frame count from
+ * @pipe: crtc to get the frame count from
  *
  * Gets the frame count on the requested crtc (all asics).
  * Returns frame count on success, -EINVAL on failure.
  */
-u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
+u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
 {
 	int vpos, hpos, stat;
 	u32 count;
 	struct radeon_device *rdev = dev->dev_private;
 
-	if (crtc < 0 || crtc >= rdev->num_crtc) {
-		DRM_ERROR("Invalid crtc %d\n", crtc);
+	if (pipe < 0 || pipe >= rdev->num_crtc) {
+		DRM_ERROR("Invalid crtc %u\n", pipe);
 		return -EINVAL;
 	}
 
@@ -772,29 +774,29 @@
 	 * and start of vsync, so vpos >= 0 means to bump the hw frame counter
 	 * result by 1 to give the proper appearance to caller.
 	 */
-	if (rdev->mode_info.crtcs[crtc]) {
+	if (rdev->mode_info.crtcs[pipe]) {
 		/* Repeat readout if needed to provide stable result if
 		 * we cross start of vsync during the queries.
 		 */
 		do {
-			count = radeon_get_vblank_counter(rdev, crtc);
+			count = radeon_get_vblank_counter(rdev, pipe);
 			/* Ask radeon_get_crtc_scanoutpos to return vpos as
 			 * distance to start of vblank, instead of regular
 			 * vertical scanout pos.
 			 */
 			stat = radeon_get_crtc_scanoutpos(
-				dev, crtc, GET_DISTANCE_TO_VBLANKSTART,
+				dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
 				&vpos, &hpos, NULL, NULL,
-				&rdev->mode_info.crtcs[crtc]->base.hwmode);
-		} while (count != radeon_get_vblank_counter(rdev, crtc));
+				&rdev->mode_info.crtcs[pipe]->base.hwmode);
+		} while (count != radeon_get_vblank_counter(rdev, pipe));
 
 		if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
 		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
 			DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
 		}
 		else {
-			DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n",
-				      crtc, vpos);
+			DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n",
+				      pipe, vpos);
 
 			/* Bump counter if we are at >= leading edge of vblank,
 			 * but before vsync where vpos would turn negative and
@@ -806,7 +808,7 @@
 	}
 	else {
 	    /* Fallback to use value as is. */
-	    count = radeon_get_vblank_counter(rdev, crtc);
+	    count = radeon_get_vblank_counter(rdev, pipe);
 	    DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -331,6 +331,8 @@
 			WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl));
 		}
 		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
+		/* Make sure vblank interrupt is still enabled if needed */
+		radeon_irq_set(rdev);
 		radeon_crtc_load_lut(crtc);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_mode.h
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_mode.h
@@ -330,6 +330,7 @@
 	u16 lut_r[256], lut_g[256], lut_b[256];
 	bool enabled;
 	bool can_tile;
+	bool cursor_out_of_bounds;
 	uint32_t crtc_offset;
 	struct drm_gem_object *cursor_bo;
 	uint64_t cursor_addr;
@@ -757,8 +758,10 @@
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
 				    struct drm_connector *connector);
-int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-				const u8 *dpcd);
+extern int radeon_dp_get_dp_link_config(struct drm_connector *connector,
+					const u8 *dpcd,
+					unsigned pix_clock,
+					unsigned *dp_lanes, unsigned *dp_rate);
 extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
 					 u8 power_state);
 extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_object.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_object.c
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <drm/drmP.h>
 #include <drm/radeon_drm.h>
+#include <drm/drm_cache.h>
 #include "radeon.h"
 #include "radeon_trace.h"
 
@@ -237,14 +238,21 @@
 	 * may be slow
 	 * See https://bugs.freedesktop.org/show_bug.cgi?id=88758
 	 */
-
+#ifndef CONFIG_COMPILE_TEST
 #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
 	 thanks to write-combining
+#endif
 
 	if (bo->flags & RADEON_GEM_GTT_WC)
 		DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
 			      "better performance thanks to write-combining\n");
 	bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
+#else
+	/* For architectures that don't support WC memory,
+	 * mask out the WC flag from the BO
+	 */
+	if (!drm_arch_can_wc_memory())
+		bo->flags &= ~RADEON_GEM_GTT_WC;
 #endif
 
 	radeon_ttm_placement_from_domain(bo, domain);
@@ -439,6 +447,10 @@
 
 int radeon_bo_init(struct radeon_device *rdev)
 {
+	/* reserve PAT memory space to WC for VRAM */
+	arch_io_reserve_memtype_wc(rdev->mc.aper_base,
+				   rdev->mc.aper_size);
+
 	/* Add an MTRR for the VRAM */
 	if (!rdev->fastfb_working) {
 		rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base,
@@ -456,6 +468,7 @@
 {
 	radeon_ttm_fini(rdev);
 	arch_phys_wc_del(rdev->mc.vram_mtrr);
+	arch_io_free_memtype_wc(rdev->mc.aper_base, rdev->mc.aper_size);
 }
 
 /* Returns how many bytes TTM can move per IB.
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_pm.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_pm.c
@@ -713,7 +713,7 @@
 static umode_t hwmon_attributes_visible(struct kobject *kobj,
 					struct attribute *attr, int index)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
+	struct device *dev = kobj_to_dev(kobj);
 	struct radeon_device *rdev = dev_get_drvdata(dev);
 	umode_t effective_mode = attr->mode;
 
@@ -1078,10 +1078,6 @@
 	/* update displays */
 	radeon_dpm_display_configuration_changed(rdev);
 
-	rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
-	rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
-	rdev->pm.dpm.single_display = single_display;
-
 	/* wait for the rings to drain */
 	for (i = 0; i < RADEON_NUM_RINGS; i++) {
 		struct radeon_ring *ring = &rdev->ring[i];
@@ -1097,6 +1093,10 @@
 
 	radeon_dpm_post_set_power_state(rdev);
 
+	rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+	rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+	rdev->pm.dpm.single_display = single_display;
+
 	if (rdev->asic->dpm.force_performance_level) {
 		if (rdev->pm.dpm.thermal_active) {
 			enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_sa.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_sa.c
@@ -349,8 +349,13 @@
 			/* see if we can skip over some allocations */
 		} while (radeon_sa_bo_next_hole(sa_manager, fences, tries));
 
+		for (i = 0; i < RADEON_NUM_RINGS; ++i)
+			radeon_fence_ref(fences[i]);
+
 		spin_unlock(&sa_manager->wq.lock);
 		r = radeon_fence_wait_any(rdev, fences, false);
+		for (i = 0; i < RADEON_NUM_RINGS; ++i)
+			radeon_fence_unref(&fences[i]);
 		spin_lock(&sa_manager->wq.lock);
 		/* if we have nothing to wait for block */
 		if (r == -ENOENT) {
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_ttm.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -213,8 +213,8 @@
 			rbo->placement.num_busy_placement = 0;
 			for (i = 0; i < rbo->placement.num_placement; i++) {
 				if (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) {
-					if (rbo->placements[0].fpfn < fpfn)
-						rbo->placements[0].fpfn = fpfn;
+					if (rbo->placements[i].fpfn < fpfn)
+						rbo->placements[i].fpfn = fpfn;
 				} else {
 					rbo->placement.busy_placement =
 						&rbo->placements[i];
@@ -235,6 +235,8 @@
 {
 	struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo);
 
+	if (radeon_ttm_tt_has_userptr(bo->ttm))
+		return -EPERM;
 	return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp);
 }
 
@@ -261,8 +263,8 @@
 
 	rdev = radeon_get_rdev(bo->bdev);
 	ridx = radeon_copy_ring_index(rdev);
-	old_start = old_mem->start << PAGE_SHIFT;
-	new_start = new_mem->start << PAGE_SHIFT;
+	old_start = (u64)old_mem->start << PAGE_SHIFT;
+	new_start = (u64)new_mem->start << PAGE_SHIFT;
 
 	switch (old_mem->mem_type) {
 	case TTM_PL_VRAM:
@@ -555,7 +557,7 @@
 		struct page **pages = ttm->pages + pinned;
 
 		r = get_user_pages(current, current->mm, userptr, num_pages,
-				   write, 0, pages, NULL);
+				   write ? FOLL_WRITE : 0, pages, NULL);
 		if (r < 0)
 			goto release_pages;
 
@@ -758,7 +760,7 @@
 						       0, PAGE_SIZE,
 						       PCI_DMA_BIDIRECTIONAL);
 		if (pci_dma_mapping_error(rdev->pdev, gtt->ttm.dma_address[i])) {
-			while (--i) {
+			while (i--) {
 				pci_unmap_page(rdev->pdev, gtt->ttm.dma_address[i],
 					       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
 				gtt->ttm.dma_address[i] = 0;
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_uvd.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -946,7 +946,7 @@
 		/* calc dclk divider with current vco freq */
 		dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk,
 							 pd_min, pd_even);
-		if (vclk_div > pd_max)
+		if (dclk_div > pd_max)
 			break; /* vco is too big, it has to stop */
 
 		/* calc score with current vco freq */
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/radeon_vm.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/radeon_vm.c
@@ -455,15 +455,15 @@
 
 	if (soffset) {
 		/* make sure object fit at this offset */
-		eoffset = soffset + size;
+		eoffset = soffset + size - 1;
 		if (soffset >= eoffset) {
 			r = -EINVAL;
 			goto error_unreserve;
 		}
 
 		last_pfn = eoffset / RADEON_GPU_PAGE_SIZE;
-		if (last_pfn > rdev->vm_manager.max_pfn) {
-			dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
+		if (last_pfn >= rdev->vm_manager.max_pfn) {
+			dev_err(rdev->dev, "va above limit (0x%08X >= 0x%08X)\n",
 				last_pfn, rdev->vm_manager.max_pfn);
 			r = -EINVAL;
 			goto error_unreserve;
@@ -478,7 +478,7 @@
 	eoffset /= RADEON_GPU_PAGE_SIZE;
 	if (soffset || eoffset) {
 		struct interval_tree_node *it;
-		it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1);
+		it = interval_tree_iter_first(&vm->va, soffset, eoffset);
 		if (it && it != &bo_va->it) {
 			struct radeon_bo_va *tmp;
 			tmp = container_of(it, struct radeon_bo_va, it);
@@ -518,7 +518,7 @@
 	if (soffset || eoffset) {
 		spin_lock(&vm->status_lock);
 		bo_va->it.start = soffset;
-		bo_va->it.last = eoffset - 1;
+		bo_va->it.last = eoffset;
 		list_add(&bo_va->vm_status, &vm->cleared);
 		spin_unlock(&vm->status_lock);
 		interval_tree_insert(&bo_va->it, &vm->va);
@@ -888,7 +888,7 @@
 	unsigned i;
 
 	start >>= radeon_vm_block_size;
-	end >>= radeon_vm_block_size;
+	end = (end - 1) >> radeon_vm_block_size;
 
 	for (i = start; i <= end; ++i)
 		radeon_bo_fence(vm->page_tables[i].bo, fence, true);
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/si.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/si.c
@@ -6013,8 +6013,8 @@
 	}
 
 	/* setup interrupt control */
-	/* set dummy read address to ring address */
-	WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8);
+	/* set dummy read address to dummy page address */
+	WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8);
 	interrupt_cntl = RREG32(INTERRUPT_CNTL);
 	/* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi
 	 * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN
@@ -6335,7 +6335,7 @@
 		WREG32(DC_HPD5_INT_CONTROL, tmp);
 	}
 	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp = RREG32(DC_HPD6_INT_CONTROL);
 		tmp |= DC_HPDx_INT_ACK;
 		WREG32(DC_HPD6_INT_CONTROL, tmp);
 	}
@@ -6366,7 +6366,7 @@
 		WREG32(DC_HPD5_INT_CONTROL, tmp);
 	}
 	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
-		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp = RREG32(DC_HPD6_INT_CONTROL);
 		tmp |= DC_HPDx_RX_INT_ACK;
 		WREG32(DC_HPD6_INT_CONTROL, tmp);
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/si_dpm.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/si_dpm.c
@@ -1956,6 +1956,7 @@
 		case 0x682C:
 			si_pi->cac_weights = cac_weights_cape_verde_pro;
 			si_pi->dte_data = dte_data_sun_xt;
+			update_dte_from_pl2 = true;
 			break;
 		case 0x6825:
 		case 0x6827:
@@ -2926,9 +2927,12 @@
 	/* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */
 	{ PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
 	{ PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
+	{ PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0x2015, 0, 120000 },
 	{ PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 },
 	{ PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 },
 	{ PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 },
+	{ PCI_VENDOR_ID_ATI, 0x6811, 0x148c, 0x2015, 0, 120000 },
+	{ PCI_VENDOR_ID_ATI, 0x6810, 0x1682, 0x9275, 0, 120000 },
 	{ 0, 0, 0, 0 },
 };
 
@@ -2996,6 +3000,47 @@
 	int i;
 	struct si_dpm_quirk *p = si_dpm_quirk_list;
 
+	/* limit all SI kickers */
+	if (rdev->family == CHIP_PITCAIRN) {
+		if ((rdev->pdev->revision == 0x81) ||
+		    (rdev->pdev->device == 0x6810) ||
+		    (rdev->pdev->device == 0x6811) ||
+		    (rdev->pdev->device == 0x6816) ||
+		    (rdev->pdev->device == 0x6817) ||
+		    (rdev->pdev->device == 0x6806))
+			max_mclk = 120000;
+	} else if (rdev->family == CHIP_OLAND) {
+		if ((rdev->pdev->revision == 0xC7) ||
+		    (rdev->pdev->revision == 0x80) ||
+		    (rdev->pdev->revision == 0x81) ||
+		    (rdev->pdev->revision == 0x83) ||
+		    (rdev->pdev->revision == 0x87) ||
+		    (rdev->pdev->device == 0x6604) ||
+		    (rdev->pdev->device == 0x6605)) {
+			max_sclk = 75000;
+			max_mclk = 80000;
+		}
+	} else if (rdev->family == CHIP_HAINAN) {
+		if ((rdev->pdev->revision == 0x81) ||
+		    (rdev->pdev->revision == 0x83) ||
+		    (rdev->pdev->revision == 0xC3) ||
+		    (rdev->pdev->device == 0x6664) ||
+		    (rdev->pdev->device == 0x6665) ||
+		    (rdev->pdev->device == 0x6667)) {
+			max_sclk = 75000;
+			max_mclk = 80000;
+		}
+	} else if (rdev->family == CHIP_OLAND) {
+		if ((rdev->pdev->revision == 0xC7) ||
+		    (rdev->pdev->revision == 0x80) ||
+		    (rdev->pdev->revision == 0x81) ||
+		    (rdev->pdev->revision == 0x83) ||
+		    (rdev->pdev->revision == 0x87) ||
+		    (rdev->pdev->device == 0x6604) ||
+		    (rdev->pdev->device == 0x6605)) {
+			max_sclk = 75000;
+		}
+	}
 	/* Apply dpm quirks */
 	while (p && p->chip_device != 0) {
 		if (rdev->pdev->vendor == p->chip_vendor &&
@@ -4099,7 +4144,7 @@
 							      &rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
 				si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table);
 
-				table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
+				table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING] =
 					cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
 
 				si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
@@ -5920,9 +5965,9 @@
 {
 	u32 lane_width;
 	u32 new_lane_width =
-		(radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+		((radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
 	u32 current_lane_width =
-		(radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+		((radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
 
 	if (new_lane_width != current_lane_width) {
 		radeon_set_pcie_lanes(rdev, new_lane_width);
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/sid.h
+++ linux-4.4.0/drivers/gpu/drm/radeon/sid.h
@@ -915,6 +915,11 @@
 #define DCCG_AUDIO_DTO1_PHASE                           0x05c0
 #define DCCG_AUDIO_DTO1_MODULE                          0x05c4
 
+#define DENTIST_DISPCLK_CNTL				0x0490
+#	define DENTIST_DPREFCLK_WDIVIDER(x)		(((x) & 0x7f) << 24)
+#	define DENTIST_DPREFCLK_WDIVIDER_MASK		(0x7f << 24)
+#	define DENTIST_DPREFCLK_WDIVIDER_SHIFT		24
+
 #define AFMT_AUDIO_SRC_CONTROL                          0x713c
 #define		AFMT_AUDIO_SRC_SELECT(x)		(((x) & 7) << 0)
 /* AFMT_AUDIO_SRC_SELECT
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/sislands_smc.h
+++ linux-4.4.0/drivers/gpu/drm/radeon/sislands_smc.h
@@ -194,6 +194,7 @@
 #define SISLANDS_SMC_VOLTAGEMASK_VDDC  0
 #define SISLANDS_SMC_VOLTAGEMASK_MVDD  1
 #define SISLANDS_SMC_VOLTAGEMASK_VDDCI 2
+#define SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING 3
 #define SISLANDS_SMC_VOLTAGEMASK_MAX   4
 
 struct SISLANDS_SMC_VOLTAGEMASKTABLE
--- linux-4.4.0.orig/drivers/gpu/drm/radeon/vce_v1_0.c
+++ linux-4.4.0/drivers/gpu/drm/radeon/vce_v1_0.c
@@ -178,12 +178,12 @@
 		return -EINVAL;
 	}
 
-	for (i = 0; i < sign->num; ++i) {
-		if (sign->val[i].chip_id == chip_id)
+	for (i = 0; i < le32_to_cpu(sign->num); ++i) {
+		if (le32_to_cpu(sign->val[i].chip_id) == chip_id)
 			break;
 	}
 
-	if (i == sign->num)
+	if (i == le32_to_cpu(sign->num))
 		return -EINVAL;
 
 	data += (256 - 64) / 4;
@@ -191,18 +191,18 @@
 	data[1] = sign->val[i].nonce[1];
 	data[2] = sign->val[i].nonce[2];
 	data[3] = sign->val[i].nonce[3];
-	data[4] = sign->len + 64;
+	data[4] = cpu_to_le32(le32_to_cpu(sign->len) + 64);
 
 	memset(&data[5], 0, 44);
 	memcpy(&data[16], &sign[1], rdev->vce_fw->size - sizeof(*sign));
 
-	data += data[4] / 4;
+	data += le32_to_cpu(data[4]) / 4;
 	data[0] = sign->val[i].sigval[0];
 	data[1] = sign->val[i].sigval[1];
 	data[2] = sign->val[i].sigval[2];
 	data[3] = sign->val[i].sigval[3];
 
-	rdev->vce.keyselect = sign->val[i].keyselect;
+	rdev->vce.keyselect = le32_to_cpu(sign->val[i].keyselect);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -148,8 +148,8 @@
 	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
 
 	/* Signal polarities */
-	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
-	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
+	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
+	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
 	      | DSMR_DIPM_DE | DSMR_CSPM;
 	rcar_du_crtc_write(rcrtc, DSMR, value);
 
@@ -171,7 +171,7 @@
 					mode->crtc_vsync_start - 1);
 	rcar_du_crtc_write(rcrtc, VCR,  mode->crtc_vtotal - 1);
 
-	rcar_du_crtc_write(rcrtc, DESR,  mode->htotal - mode->hsync_start);
+	rcar_du_crtc_write(rcrtc, DESR,  mode->htotal - mode->hsync_start - 1);
 	rcar_du_crtc_write(rcrtc, DEWR,  mode->hdisplay);
 }
 
@@ -282,26 +282,6 @@
  * Page Flip
  */
 
-void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
-				   struct drm_file *file)
-{
-	struct drm_pending_vblank_event *event;
-	struct drm_device *dev = rcrtc->crtc.dev;
-	unsigned long flags;
-
-	/* Destroy the pending vertical blanking event associated with the
-	 * pending page flip, if any, and disable vertical blanking interrupts.
-	 */
-	spin_lock_irqsave(&dev->event_lock, flags);
-	event = rcrtc->event;
-	if (event && event->base.file_priv == file) {
-		rcrtc->event = NULL;
-		event->base.destroy(&event->base);
-		drm_crtc_vblank_put(&rcrtc->crtc);
-	}
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
 static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
 {
 	struct drm_pending_vblank_event *event;
@@ -391,6 +371,31 @@
 	rcrtc->started = true;
 }
 
+static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_device *rcdu = rcrtc->group->dev;
+	struct drm_crtc *crtc = &rcrtc->crtc;
+	u32 status;
+	/* Make sure vblank interrupts are enabled. */
+	drm_crtc_vblank_get(crtc);
+	/*
+	 * Disable planes and calculate how many vertical blanking interrupts we
+	 * have to wait for. If a vertical blanking interrupt has been triggered
+	 * but not processed yet, we don't know whether it occurred before or
+	 * after the planes got disabled. We thus have to wait for two vblank
+	 * interrupts in that case.
+	 */
+	spin_lock_irq(&rcrtc->vblank_lock);
+	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+	status = rcar_du_crtc_read(rcrtc, DSSR);
+	rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1;
+	spin_unlock_irq(&rcrtc->vblank_lock);
+	if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0,
+	                        msecs_to_jiffies(100)))
+		dev_warn(rcdu->dev, "vertical blanking timeout\n");
+	drm_crtc_vblank_put(crtc);
+}
+
 static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
 {
 	struct drm_crtc *crtc = &rcrtc->crtc;
@@ -399,17 +404,16 @@
 		return;
 
 	/* Disable all planes and wait for the change to take effect. This is
-	 * required as the DSnPR registers are updated on vblank, and no vblank
-	 * will occur once the CRTC is stopped. Disabling planes when starting
-	 * the CRTC thus wouldn't be enough as it would start scanning out
-	 * immediately from old frame buffers until the next vblank.
+	 * required as the plane enable registers are updated on vblank, and no
+	 * vblank will occur once the CRTC is stopped. Disabling planes when
+	 * starting the CRTC thus wouldn't be enough as it would start scanning
+	 * out immediately from old frame buffers until the next vblank.
 	 *
 	 * This increases the CRTC stop delay, especially when multiple CRTCs
 	 * are stopped in one operation as we now wait for one vblank per CRTC.
 	 * Whether this can be improved needs to be researched.
 	 */
-	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
-	drm_crtc_wait_one_vblank(crtc);
+	rcar_du_crtc_disable_planes(rcrtc);
 
 	/* Disable vertical blanking interrupt reporting. We first need to wait
 	 * for page flip completion before stopping the CRTC as userspace
@@ -548,10 +552,26 @@
 	irqreturn_t ret = IRQ_NONE;
 	u32 status;
 
+	spin_lock(&rcrtc->vblank_lock);
+
 	status = rcar_du_crtc_read(rcrtc, DSSR);
 	rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
 
-	if (status & DSSR_FRM) {
+	if (status & DSSR_VBK) {
+		/*
+		 * Wake up the vblank wait if the counter reaches 0. This must
+		 * be protected by the vblank_lock to avoid races in
+		 * rcar_du_crtc_disable_planes().
+		 */
+		if (rcrtc->vblank_count) {
+			if (--rcrtc->vblank_count == 0)
+				wake_up(&rcrtc->vblank_wait);
+		}
+	}
+
+	spin_unlock(&rcrtc->vblank_lock);
+
+	if (status & DSSR_VBK) {
 		drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
 		rcar_du_crtc_finish_page_flip(rcrtc);
 		ret = IRQ_HANDLED;
@@ -605,6 +625,8 @@
 	}
 
 	init_waitqueue_head(&rcrtc->flip_wait);
+	init_waitqueue_head(&rcrtc->vblank_wait);
+	spin_lock_init(&rcrtc->vblank_lock);
 
 	rcrtc->group = rgrp;
 	rcrtc->mmio_offset = mmio_offsets[index];
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -15,6 +15,7 @@
 #define __RCAR_DU_CRTC_H__
 
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/wait.h>
 
 #include <drm/drmP.h>
@@ -32,6 +33,9 @@
  * @started: whether the CRTC has been started and is running
  * @event: event to post when the pending page flip completes
  * @flip_wait: wait queue used to signal page flip completion
+ * @vblank_lock: protects vblank_wait and vblank_count
+ * @vblank_wait: wait queue used to signal vertical blanking
+ * @vblank_count: number of vertical blanking interrupts to wait for
  * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
  * @enabled: whether the CRTC is enabled, used to control system resume
  * @group: CRTC group this CRTC belongs to
@@ -48,6 +52,10 @@
 	struct drm_pending_vblank_event *event;
 	wait_queue_head_t flip_wait;
 
+	spinlock_t vblank_lock;
+	wait_queue_head_t vblank_wait;
+	unsigned int vblank_count;
+
 	unsigned int outputs;
 	bool enabled;
 
@@ -67,8 +75,6 @@
 
 int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index);
 void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable);
-void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
-				   struct drm_file *file);
 void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc);
 void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
 
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -144,91 +144,6 @@
  * DRM operations
  */
 
-static int rcar_du_unload(struct drm_device *dev)
-{
-	struct rcar_du_device *rcdu = dev->dev_private;
-
-	if (rcdu->fbdev)
-		drm_fbdev_cma_fini(rcdu->fbdev);
-
-	drm_kms_helper_poll_fini(dev);
-	drm_mode_config_cleanup(dev);
-	drm_vblank_cleanup(dev);
-
-	dev->irq_enabled = 0;
-	dev->dev_private = NULL;
-
-	return 0;
-}
-
-static int rcar_du_load(struct drm_device *dev, unsigned long flags)
-{
-	struct platform_device *pdev = dev->platformdev;
-	struct device_node *np = pdev->dev.of_node;
-	struct rcar_du_device *rcdu;
-	struct resource *mem;
-	int ret;
-
-	if (np == NULL) {
-		dev_err(dev->dev, "no platform data\n");
-		return -ENODEV;
-	}
-
-	rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
-	if (rcdu == NULL) {
-		dev_err(dev->dev, "failed to allocate private data\n");
-		return -ENOMEM;
-	}
-
-	init_waitqueue_head(&rcdu->commit.wait);
-
-	rcdu->dev = &pdev->dev;
-	rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data;
-	rcdu->ddev = dev;
-	dev->dev_private = rcdu;
-
-	/* I/O resources */
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
-	if (IS_ERR(rcdu->mmio))
-		return PTR_ERR(rcdu->mmio);
-
-	/* Initialize vertical blanking interrupts handling. Start with vblank
-	 * disabled for all CRTCs.
-	 */
-	ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to initialize vblank\n");
-		goto done;
-	}
-
-	/* DRM/KMS objects */
-	ret = rcar_du_modeset_init(rcdu);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret);
-		goto done;
-	}
-
-	dev->irq_enabled = 1;
-
-	platform_set_drvdata(pdev, rcdu);
-
-done:
-	if (ret)
-		rcar_du_unload(dev);
-
-	return ret;
-}
-
-static void rcar_du_preclose(struct drm_device *dev, struct drm_file *file)
-{
-	struct rcar_du_device *rcdu = dev->dev_private;
-	unsigned int i;
-
-	for (i = 0; i < rcdu->num_crtcs; ++i)
-		rcar_du_crtc_cancel_page_flip(&rcdu->crtcs[i], file);
-}
-
 static void rcar_du_lastclose(struct drm_device *dev)
 {
 	struct rcar_du_device *rcdu = dev->dev_private;
@@ -269,11 +184,7 @@
 static struct drm_driver rcar_du_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
 				| DRIVER_ATOMIC,
-	.load			= rcar_du_load,
-	.unload			= rcar_du_unload,
-	.preclose		= rcar_du_preclose,
 	.lastclose		= rcar_du_lastclose,
-	.set_busid		= drm_platform_set_busid,
 	.get_vblank_counter	= drm_vblank_no_hw_counter,
 	.enable_vblank		= rcar_du_enable_vblank,
 	.disable_vblank		= rcar_du_disable_vblank,
@@ -333,18 +244,104 @@
  * Platform driver
  */
 
-static int rcar_du_probe(struct platform_device *pdev)
+static int rcar_du_remove(struct platform_device *pdev)
 {
-	return drm_platform_init(&rcar_du_driver, pdev);
+	struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
+	struct drm_device *ddev = rcdu->ddev;
+
+	mutex_lock(&ddev->mode_config.mutex);
+	drm_connector_unplug_all(ddev);
+	mutex_unlock(&ddev->mode_config.mutex);
+
+	drm_dev_unregister(ddev);
+
+	if (rcdu->fbdev)
+		drm_fbdev_cma_fini(rcdu->fbdev);
+
+	drm_kms_helper_poll_fini(ddev);
+	drm_mode_config_cleanup(ddev);
+
+	drm_dev_unref(ddev);
+
+	return 0;
 }
 
-static int rcar_du_remove(struct platform_device *pdev)
+static int rcar_du_probe(struct platform_device *pdev)
 {
-	struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
+	struct device_node *np = pdev->dev.of_node;
+	struct rcar_du_device *rcdu;
+	struct drm_connector *connector;
+	struct drm_device *ddev;
+	struct resource *mem;
+	int ret;
+
+	if (np == NULL) {
+		dev_err(&pdev->dev, "no device tree node\n");
+		return -ENODEV;
+	}
 
-	drm_put_dev(rcdu->ddev);
+	/* Allocate and initialize the DRM and R-Car device structures. */
+	rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
+	if (rcdu == NULL)
+		return -ENOMEM;
+
+	init_waitqueue_head(&rcdu->commit.wait);
+
+	rcdu->dev = &pdev->dev;
+	rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data;
+
+	platform_set_drvdata(pdev, rcdu);
+
+	/* I/O resources */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(rcdu->mmio))
+		return PTR_ERR(rcdu->mmio);
+
+	/* DRM/KMS objects */
+	ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev);
+	if (!ddev)
+		return -ENOMEM;
+
+	drm_dev_set_unique(ddev, dev_name(&pdev->dev));
+
+	rcdu->ddev = ddev;
+	ddev->dev_private = rcdu;
+
+	ret = rcar_du_modeset_init(rcdu);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret);
+		goto error;
+	}
+
+	ddev->irq_enabled = 1;
+
+	/* Register the DRM device with the core and the connectors with
+	 * sysfs.
+	 */
+	ret = drm_dev_register(ddev, 0);
+	if (ret)
+		goto error;
+
+	mutex_lock(&ddev->mode_config.mutex);
+	drm_for_each_connector(connector, ddev) {
+		ret = drm_connector_register(connector);
+		if (ret < 0)
+			break;
+	}
+	mutex_unlock(&ddev->mode_config.mutex);
+
+	if (ret < 0)
+		goto error;
+
+	DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
 
 	return 0;
+
+error:
+	rcar_du_remove(pdev);
+
+	return ret;
 }
 
 static struct platform_driver rcar_du_platform_driver = {
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
@@ -55,12 +55,6 @@
 	.best_encoder = rcar_du_connector_best_encoder,
 };
 
-static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector)
-{
-	drm_connector_unregister(connector);
-	drm_connector_cleanup(connector);
-}
-
 static enum drm_connector_status
 rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)
 {
@@ -79,7 +73,7 @@
 	.reset = drm_atomic_helper_connector_reset,
 	.detect = rcar_du_hdmi_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = rcar_du_hdmi_connector_destroy,
+	.destroy = drm_connector_cleanup,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
@@ -108,9 +102,6 @@
 		return ret;
 
 	drm_connector_helper_add(connector, &connector_helper_funcs);
-	ret = drm_connector_register(connector);
-	if (ret < 0)
-		return ret;
 
 	connector->dpms = DRM_MODE_DPMS_OFF;
 	drm_object_property_set_value(&connector->base,
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -642,13 +642,13 @@
 	}
 
 	ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector);
-	of_node_put(encoder);
-	of_node_put(connector);
-
 	if (ret && ret != -EPROBE_DEFER)
 		dev_warn(rcdu->dev,
-			 "failed to initialize encoder %s (%d), skipping\n",
-			 encoder->full_name, ret);
+			 "failed to initialize encoder %s on output %u (%d), skipping\n",
+			 of_node_full_name(encoder), output, ret);
+
+	of_node_put(encoder);
+	of_node_put(connector);
 
 	return ret;
 }
@@ -761,6 +761,13 @@
 	if (ret < 0)
 		return ret;
 
+	/* Initialize vertical blanking interrupts handling. Start with vblank
+	* disabled for all CRTCs.
+	*/
+	ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
+	if (ret < 0)
+		return ret;
+
 	/* Initialize the groups. */
 	num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
 
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
@@ -62,12 +62,6 @@
 	.best_encoder = rcar_du_connector_best_encoder,
 };
 
-static void rcar_du_lvds_connector_destroy(struct drm_connector *connector)
-{
-	drm_connector_unregister(connector);
-	drm_connector_cleanup(connector);
-}
-
 static enum drm_connector_status
 rcar_du_lvds_connector_detect(struct drm_connector *connector, bool force)
 {
@@ -79,7 +73,7 @@
 	.reset = drm_atomic_helper_connector_reset,
 	.detect = rcar_du_lvds_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = rcar_du_lvds_connector_destroy,
+	.destroy = drm_connector_cleanup,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
@@ -117,9 +111,6 @@
 		return ret;
 
 	drm_connector_helper_add(connector, &connector_helper_funcs);
-	ret = drm_connector_register(connector);
-	if (ret < 0)
-		return ret;
 
 	connector->dpms = DRM_MODE_DPMS_OFF;
 	drm_object_property_set_value(&connector->base,
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
@@ -56,11 +56,11 @@
 		return ret;
 
 	/* PLL clock configuration */
-	if (freq <= 38000)
+	if (freq < 39000)
 		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
-	else if (freq <= 60000)
+	else if (freq < 61000)
 		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
-	else if (freq <= 121000)
+	else if (freq < 121000)
 		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
 	else
 		pllcr = LVDPLLCR_PLLDLYCNT_150M;
@@ -102,7 +102,7 @@
 	/* Turn the PLL on, wait for the startup delay, and turn the output
 	 * on.
 	 */
-	lvdcr0 |= LVDCR0_PLLEN;
+	lvdcr0 |= LVDCR0_PLLON;
 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 
 	usleep_range(100, 150);
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
@@ -31,12 +31,6 @@
 	.best_encoder = rcar_du_connector_best_encoder,
 };
 
-static void rcar_du_vga_connector_destroy(struct drm_connector *connector)
-{
-	drm_connector_unregister(connector);
-	drm_connector_cleanup(connector);
-}
-
 static enum drm_connector_status
 rcar_du_vga_connector_detect(struct drm_connector *connector, bool force)
 {
@@ -48,7 +42,7 @@
 	.reset = drm_atomic_helper_connector_reset,
 	.detect = rcar_du_vga_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = rcar_du_vga_connector_destroy,
+	.destroy = drm_connector_cleanup,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
@@ -76,9 +70,6 @@
 		return ret;
 
 	drm_connector_helper_add(connector, &connector_helper_funcs);
-	ret = drm_connector_register(connector);
-	if (ret < 0)
-		return ret;
 
 	connector->dpms = DRM_MODE_DPMS_OFF;
 	drm_object_property_set_value(&connector->base,
--- linux-4.4.0.orig/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
+++ linux-4.4.0/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
@@ -18,7 +18,7 @@
 #define LVDCR0_DMD			(1 << 12)
 #define LVDCR0_LVMD_MASK		(0xf << 8)
 #define LVDCR0_LVMD_SHIFT		8
-#define LVDCR0_PLLEN			(1 << 4)
+#define LVDCR0_PLLON			(1 << 4)
 #define LVDCR0_BEN			(1 << 2)
 #define LVDCR0_LVEN			(1 << 1)
 #define LVDCR0_LVRES			(1 << 0)
--- linux-4.4.0.orig/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ linux-4.4.0/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -67,7 +67,6 @@
 	 * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
 	 */
 	vma->vm_flags &= ~VM_PFNMAP;
-	vma->vm_pgoff = 0;
 
 	ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
 			     obj->size, &rk_obj->dma_attrs);
@@ -99,6 +98,12 @@
 	if (ret)
 		return ret;
 
+	/*
+	 * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the
+	 * whole buffer from the start.
+	 */
+	vma->vm_pgoff = 0;
+
 	obj = vma->vm_private_data;
 
 	return rockchip_drm_gem_object_mmap(obj, vma);
--- linux-4.4.0.orig/drivers/gpu/drm/sti/sti_drv.c
+++ linux-4.4.0/drivers/gpu/drm/sti/sti_drv.c
@@ -160,6 +160,7 @@
 
 	drm_mode_config_reset(dev);
 
+	drm_helper_disable_unused_functions(dev);
 	drm_fbdev_cma_init(dev, 32,
 			   dev->mode_config.num_crtc,
 			   dev->mode_config.num_connector);
--- linux-4.4.0.orig/drivers/gpu/drm/sti/sti_vtg.c
+++ linux-4.4.0/drivers/gpu/drm/sti/sti_vtg.c
@@ -346,6 +346,10 @@
 		return -ENOMEM;
 	}
 	vtg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!vtg->regs) {
+		DRM_ERROR("failed to remap I/O memory\n");
+		return -ENOMEM;
+	}
 
 	np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0);
 	if (np) {
--- linux-4.4.0.orig/drivers/gpu/drm/tegra/dsi.c
+++ linux-4.4.0/drivers/gpu/drm/tegra/dsi.c
@@ -1442,9 +1442,11 @@
 	np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0);
 	if (np) {
 		struct platform_device *gangster = of_find_device_by_node(np);
+		of_node_put(np);
+		if (!gangster)
+			return -EPROBE_DEFER;
 
 		dsi->slave = platform_get_drvdata(gangster);
-		of_node_put(np);
 
 		if (!dsi->slave)
 			return -EPROBE_DEFER;
--- linux-4.4.0.orig/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ linux-4.4.0/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -294,6 +294,7 @@
 			break;
 	}
 
+	drm_helper_disable_unused_functions(dev);
 	priv->fbdev = drm_fbdev_cma_init(dev, bpp,
 			dev->mode_config.num_crtc,
 			dev->mode_config.num_connector);
--- linux-4.4.0.orig/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ linux-4.4.0/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -177,12 +177,16 @@
 	int i;
 
 	for (i = 0; i < timings->num_timings; i++) {
-		struct drm_display_mode *mode = drm_mode_create(dev);
+		struct drm_display_mode *mode;
 		struct videomode vm;
 
 		if (videomode_from_timings(timings, &vm, i))
 			break;
 
+		mode = drm_mode_create(dev);
+		if (!mode)
+			break;
+
 		drm_display_mode_from_videomode(&vm, mode);
 
 		mode->type = DRM_MODE_TYPE_DRIVER;
--- linux-4.4.0.orig/drivers/gpu/drm/ttm/ttm_bo.c
+++ linux-4.4.0/drivers/gpu/drm/ttm/ttm_bo.c
@@ -176,7 +176,7 @@
 		list_add_tail(&bo->lru, &man->lru);
 		kref_get(&bo->list_kref);
 
-		if (bo->ttm != NULL) {
+		if (bo->ttm && !(bo->ttm->page_flags & TTM_PAGE_FLAG_SG)) {
 			list_add_tail(&bo->swap, &bo->glob->swap_lru);
 			kref_get(&bo->list_kref);
 		}
@@ -228,6 +228,18 @@
 }
 EXPORT_SYMBOL(ttm_bo_del_sub_from_lru);
 
+void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo)
+{
+	int put_count = 0;
+
+	lockdep_assert_held(&bo->resv->lock.base);
+
+	put_count = ttm_bo_del_from_lru(bo);
+	ttm_bo_list_ref_sub(bo, put_count, true);
+	ttm_bo_add_to_lru(bo);
+}
+EXPORT_SYMBOL(ttm_bo_move_to_lru_tail);
+
 /*
  * Call bo->mutex locked.
  */
@@ -1004,9 +1016,9 @@
 	return ret;
 }
 
-static bool ttm_bo_mem_compat(struct ttm_placement *placement,
-			      struct ttm_mem_reg *mem,
-			      uint32_t *new_flags)
+bool ttm_bo_mem_compat(struct ttm_placement *placement,
+		       struct ttm_mem_reg *mem,
+		       uint32_t *new_flags)
 {
 	int i;
 
@@ -1038,6 +1050,7 @@
 
 	return false;
 }
+EXPORT_SYMBOL(ttm_bo_mem_compat);
 
 int ttm_bo_validate(struct ttm_buffer_object *bo,
 			struct ttm_placement *placement,
@@ -1170,9 +1183,15 @@
 	if (likely(!ret))
 		ret = ttm_bo_validate(bo, placement, interruptible, false);
 
-	if (!resv)
+	if (!resv) {
 		ttm_bo_unreserve(bo);
 
+	} else if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
+		spin_lock(&bo->glob->lru_lock);
+		ttm_bo_add_to_lru(bo);
+		spin_unlock(&bo->glob->lru_lock);
+	}
+
 	if (unlikely(ret))
 		ttm_bo_unref(&bo);
 
@@ -1620,7 +1639,6 @@
 	struct ttm_buffer_object *bo;
 	int ret = -EBUSY;
 	int put_count;
-	uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM);
 
 	spin_lock(&glob->lru_lock);
 	list_for_each_entry(bo, &glob->swap_lru, swap) {
@@ -1656,7 +1674,8 @@
 	if (unlikely(ret != 0))
 		goto out;
 
-	if ((bo->mem.placement & swap_placement) != swap_placement) {
+	if (bo->mem.mem_type != TTM_PL_SYSTEM ||
+	    bo->ttm->caching_state != tt_cached) {
 		struct ttm_mem_reg evict_mem;
 
 		evict_mem = bo->mem;
--- linux-4.4.0.orig/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ linux-4.4.0/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -66,8 +66,11 @@
 		if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT)
 			goto out_unlock;
 
+		ttm_bo_reference(bo);
 		up_read(&vma->vm_mm->mmap_sem);
 		(void) ttm_bo_wait(bo, false, true, false);
+		ttm_bo_unreserve(bo);
+		ttm_bo_unref(&bo);
 		goto out_unlock;
 	}
 
@@ -114,8 +117,10 @@
 
 		if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) {
 			if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
+				ttm_bo_reference(bo);
 				up_read(&vma->vm_mm->mmap_sem);
 				(void) ttm_bo_wait_unreserved(bo);
+				ttm_bo_unref(&bo);
 			}
 
 			return VM_FAULT_RETRY;
@@ -160,6 +165,13 @@
 	ret = ttm_bo_vm_fault_idle(bo, vma, vmf);
 	if (unlikely(ret != 0)) {
 		retval = ret;
+
+		if (retval == VM_FAULT_RETRY &&
+		    !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
+			/* The BO has already been unreserved. */
+			return retval;
+		}
+
 		goto out_unlock;
 	}
 
--- linux-4.4.0.orig/drivers/gpu/drm/ttm/ttm_object.c
+++ linux-4.4.0/drivers/gpu/drm/ttm/ttm_object.c
@@ -179,7 +179,7 @@
 	if (unlikely(ret != 0))
 		goto out_err0;
 
-	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
+	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
 	if (unlikely(ret != 0))
 		goto out_err1;
 
@@ -318,7 +318,8 @@
 
 int ttm_ref_object_add(struct ttm_object_file *tfile,
 		       struct ttm_base_object *base,
-		       enum ttm_ref_type ref_type, bool *existed)
+		       enum ttm_ref_type ref_type, bool *existed,
+		       bool require_existed)
 {
 	struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
 	struct ttm_ref_object *ref;
@@ -345,6 +346,9 @@
 		}
 
 		rcu_read_unlock();
+		if (require_existed)
+			return -EPERM;
+
 		ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
 					   false, false);
 		if (unlikely(ret != 0))
@@ -635,7 +639,7 @@
 	prime = (struct ttm_prime_object *) dma_buf->priv;
 	base = &prime->base;
 	*handle = base->hash.key;
-	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
+	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
 
 	dma_buf_put(dma_buf);
 
--- linux-4.4.0.orig/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ linux-4.4.0/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -612,7 +612,7 @@
 		} else {
 			pr_err("Failed to fill pool (%p)\n", pool);
 			/* If we have any pages left put them to the pool. */
-			list_for_each_entry(p, &pool->list, lru) {
+			list_for_each_entry(p, &new_pages, lru) {
 				++cpages;
 			}
 			list_splice(&new_pages, &pool->list);
@@ -818,6 +818,8 @@
 	pr_info("Initializing pool allocator\n");
 
 	_manager = kzalloc(sizeof(*_manager), GFP_KERNEL);
+	if (!_manager)
+		return -ENOMEM;
 
 	ttm_page_pool_init_locked(&_manager->wc_pool, GFP_HIGHUSER, "wc");
 
--- linux-4.4.0.orig/drivers/gpu/drm/ttm/ttm_tt.c
+++ linux-4.4.0/drivers/gpu/drm/ttm/ttm_tt.c
@@ -199,7 +199,6 @@
 
 	ttm_tt_alloc_page_directory(ttm);
 	if (!ttm->pages) {
-		ttm_tt_destroy(ttm);
 		pr_err("Failed allocating page table\n");
 		return -ENOMEM;
 	}
@@ -232,7 +231,6 @@
 	INIT_LIST_HEAD(&ttm_dma->pages_list);
 	ttm_dma_tt_alloc_page_directory(ttm_dma);
 	if (!ttm->pages) {
-		ttm_tt_destroy(ttm);
 		pr_err("Failed allocating page table\n");
 		return -ENOMEM;
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/udl/udl_fb.c
+++ linux-4.4.0/drivers/gpu/drm/udl/udl_fb.c
@@ -256,10 +256,15 @@
 {
 	unsigned long start = vma->vm_start;
 	unsigned long size = vma->vm_end - vma->vm_start;
-	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long offset;
 	unsigned long page, pos;
 
-	if (offset + size > info->fix.smem_len)
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+
+	offset = vma->vm_pgoff << PAGE_SHIFT;
+
+	if (offset > info->fix.smem_len || size > info->fix.smem_len - offset)
 		return -EINVAL;
 
 	pos = (unsigned long)info->fix.smem_start + offset;
@@ -336,7 +341,7 @@
 
 		struct fb_deferred_io *fbdefio;
 
-		fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+		fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
 
 		if (fbdefio) {
 			fbdefio->delay = DL_DEFIO_WRITE_DELAY;
@@ -539,7 +544,7 @@
 out_destroy_fbi:
 	drm_fb_helper_release_fbi(helper);
 out_gfree:
-	drm_gem_object_unreference(&ufbdev->ufb.obj->base);
+	drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base);
 out:
 	return ret;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/udl/udl_gem.c
+++ linux-4.4.0/drivers/gpu/drm/udl/udl_gem.c
@@ -52,7 +52,7 @@
 		return ret;
 	}
 
-	drm_gem_object_unreference(&obj->base);
+	drm_gem_object_unreference_unlocked(&obj->base);
 	*handle_p = handle;
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/udl/udl_main.c
+++ linux-4.4.0/drivers/gpu/drm/udl/udl_main.c
@@ -141,18 +141,13 @@
 	struct list_head *node;
 	struct urb_node *unode;
 	struct urb *urb;
-	int ret;
 	unsigned long flags;
 
 	DRM_DEBUG("Waiting for completes and freeing all render urbs\n");
 
 	/* keep waiting and freeing, until we've got 'em all */
 	while (count--) {
-
-		/* Getting interrupted means a leak, but ok at shutdown*/
-		ret = down_interruptible(&udl->urbs.limit_sem);
-		if (ret)
-			break;
+		down(&udl->urbs.limit_sem);
 
 		spin_lock_irqsave(&udl->urbs.lock, flags);
 
@@ -176,17 +171,22 @@
 static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
 {
 	struct udl_device *udl = dev->dev_private;
-	int i = 0;
 	struct urb *urb;
 	struct urb_node *unode;
 	char *buf;
+	size_t wanted_size = count * size;
 
 	spin_lock_init(&udl->urbs.lock);
 
+retry:
 	udl->urbs.size = size;
 	INIT_LIST_HEAD(&udl->urbs.list);
 
-	while (i < count) {
+	sema_init(&udl->urbs.limit_sem, 0);
+	udl->urbs.count = 0;
+	udl->urbs.available = 0;
+
+	while (udl->urbs.count * size < wanted_size) {
 		unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
 		if (!unode)
 			break;
@@ -202,11 +202,16 @@
 		}
 		unode->urb = urb;
 
-		buf = usb_alloc_coherent(udl->udev, MAX_TRANSFER, GFP_KERNEL,
+		buf = usb_alloc_coherent(udl->udev, size, GFP_KERNEL,
 					 &urb->transfer_dma);
 		if (!buf) {
 			kfree(unode);
 			usb_free_urb(urb);
+			if (size > PAGE_SIZE) {
+				size /= 2;
+				udl_free_urb_list(dev);
+				goto retry;
+			}
 			break;
 		}
 
@@ -217,16 +222,14 @@
 
 		list_add_tail(&unode->entry, &udl->urbs.list);
 
-		i++;
+		up(&udl->urbs.limit_sem);
+		udl->urbs.count++;
+		udl->urbs.available++;
 	}
 
-	sema_init(&udl->urbs.limit_sem, i);
-	udl->urbs.count = i;
-	udl->urbs.available = i;
-
-	DRM_DEBUG("allocated %d %d byte urbs\n", i, (int) size);
+	DRM_DEBUG("allocated %d %d byte urbs\n", udl->urbs.count, (int) size);
 
-	return i;
+	return udl->urbs.count;
 }
 
 struct urb *udl_get_urb(struct drm_device *dev)
--- linux-4.4.0.orig/drivers/gpu/drm/vc4/vc4_crtc.c
+++ linux-4.4.0/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -327,7 +327,7 @@
 	/* The pixelvalve can only feed one encoder (and encoders are
 	 * 1:1 with connectors.)
 	 */
-	if (drm_atomic_connectors_for_crtc(state->state, crtc) > 1)
+	if (hweight32(state->connector_mask) > 1)
 		return -EINVAL;
 
 	drm_atomic_crtc_state_for_each_plane(plane, state) {
--- linux-4.4.0.orig/drivers/gpu/drm/vgem/vgem_drv.c
+++ linux-4.4.0/drivers/gpu/drm/vgem/vgem_drv.c
@@ -158,8 +158,6 @@
 	if (err)
 		goto handle_out;
 
-	drm_gem_object_unreference_unlocked(gem_object);
-
 	return gem_object;
 
 handle_out:
@@ -190,7 +188,9 @@
 	args->size = gem_object->size;
 	args->pitch = pitch;
 
-	DRM_DEBUG_DRIVER("Created object of size %lld\n", size);
+	drm_gem_object_unreference_unlocked(gem_object);
+
+	DRM_DEBUG("Created object of size %llu\n", args->size);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/via/via_dmablit.c
+++ linux-4.4.0/drivers/gpu/drm/via/via_dmablit.c
@@ -242,8 +242,8 @@
 	ret = get_user_pages(current, current->mm,
 			     (unsigned long)xfer->mem_addr,
 			     vsg->num_pages,
-			     (vsg->direction == DMA_FROM_DEVICE),
-			     0, vsg->pages, NULL);
+			     (vsg->direction == DMA_FROM_DEVICE) ? FOLL_WRITE : 0,
+			     vsg->pages, NULL);
 
 	up_read(&current->mm->mmap_sem);
 	if (ret != vsg->num_pages) {
--- linux-4.4.0.orig/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ linux-4.4.0/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -338,7 +338,7 @@
 	info->fbops = &virtio_gpufb_ops;
 	info->pixmap.flags = FB_PIXMAP_SYSTEM;
 
-	info->screen_base = obj->vmap;
+	info->screen_buffer = obj->vmap;
 	info->screen_size = obj->gem_base.size;
 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
 	drm_fb_helper_fill_var(info, &vfbdev->helper,
--- linux-4.4.0.orig/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ linux-4.4.0/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -208,6 +208,9 @@
 	case VIRTGPU_PARAM_3D_FEATURES:
 		value = vgdev->has_virgl_3d == true ? 1 : 0;
 		break;
+	case VIRTGPU_PARAM_CAPSET_QUERY_FIX:
+		value = 1;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -483,7 +486,7 @@
 {
 	struct virtio_gpu_device *vgdev = dev->dev_private;
 	struct drm_virtgpu_get_caps *args = data;
-	int size;
+	unsigned size, host_caps_size;
 	int i;
 	int found_valid = -1;
 	int ret;
@@ -492,6 +495,10 @@
 	if (vgdev->num_capsets == 0)
 		return -ENOSYS;
 
+	/* don't allow userspace to pass 0 */
+	if (args->size == 0)
+		return -EINVAL;
+
 	spin_lock(&vgdev->display_info_lock);
 	for (i = 0; i < vgdev->num_capsets; i++) {
 		if (vgdev->capsets[i].id == args->cap_set_id) {
@@ -507,11 +514,9 @@
 		return -EINVAL;
 	}
 
-	size = vgdev->capsets[found_valid].max_size;
-	if (args->size > size) {
-		spin_unlock(&vgdev->display_info_lock);
-		return -EINVAL;
-	}
+	host_caps_size = vgdev->capsets[found_valid].max_size;
+	/* only copy to user the minimum of the host caps size or the guest caps size */
+	size = min(args->size, host_caps_size);
 
 	list_for_each_entry(cache_ent, &vgdev->cap_cache, head) {
 		if (cache_ent->id == args->cap_set_id &&
@@ -530,6 +535,9 @@
 	ret = wait_event_timeout(vgdev->resp_wq,
 				 atomic_read(&cache_ent->is_valid), 5 * HZ);
 
+	/* is_valid check must proceed before copy of the cache entry. */
+	smp_rmb();
+
 	ptr = cache_ent->caps_cache;
 
 copy_exit:
--- linux-4.4.0.orig/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ linux-4.4.0/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -113,8 +113,10 @@
 					 vgdev->capsets[i].id > 0, 5 * HZ);
 		if (ret == 0) {
 			DRM_ERROR("timed out waiting for cap set %d\n", i);
+			spin_lock(&vgdev->display_info_lock);
 			kfree(vgdev->capsets);
 			vgdev->capsets = NULL;
+			spin_unlock(&vgdev->display_info_lock);
 			return;
 		}
 		DRM_INFO("cap set %d: id %d, max-version %d, max-size %d\n",
--- linux-4.4.0.orig/drivers/gpu/drm/virtio/virtgpu_object.c
+++ linux-4.4.0/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -81,8 +81,10 @@
 		return -ENOMEM;
 	size = roundup(size, PAGE_SIZE);
 	ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size);
-	if (ret != 0)
+	if (ret != 0) {
+		kfree(bo);
 		return ret;
+	}
 	bo->dumb = false;
 	virtio_gpu_init_ttm_placement(bo, pinned);
 
--- linux-4.4.0.orig/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ linux-4.4.0/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -324,7 +324,7 @@
 	ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC);
 	if (ret == -ENOSPC) {
 		spin_unlock(&vgdev->ctrlq.qlock);
-		wait_event(vgdev->ctrlq.ack_queue, vq->num_free);
+		wait_event(vgdev->ctrlq.ack_queue, vq->num_free >= outcnt + incnt);
 		spin_lock(&vgdev->ctrlq.qlock);
 		goto retry;
 	} else {
@@ -399,7 +399,7 @@
 	ret = virtqueue_add_sgs(vq, sgs, outcnt, 0, vbuf, GFP_ATOMIC);
 	if (ret == -ENOSPC) {
 		spin_unlock(&vgdev->cursorq.qlock);
-		wait_event(vgdev->cursorq.ack_queue, vq->num_free);
+		wait_event(vgdev->cursorq.ack_queue, vq->num_free >= outcnt);
 		spin_lock(&vgdev->cursorq.qlock);
 		goto retry;
 	} else {
@@ -596,9 +596,13 @@
 	int i = le32_to_cpu(cmd->capset_index);
 
 	spin_lock(&vgdev->display_info_lock);
-	vgdev->capsets[i].id = le32_to_cpu(resp->capset_id);
-	vgdev->capsets[i].max_version = le32_to_cpu(resp->capset_max_version);
-	vgdev->capsets[i].max_size = le32_to_cpu(resp->capset_max_size);
+	if (vgdev->capsets) {
+		vgdev->capsets[i].id = le32_to_cpu(resp->capset_id);
+		vgdev->capsets[i].max_version = le32_to_cpu(resp->capset_max_version);
+		vgdev->capsets[i].max_size = le32_to_cpu(resp->capset_max_size);
+	} else {
+		DRM_ERROR("invalid capset memory.");
+	}
 	spin_unlock(&vgdev->display_info_lock);
 	wake_up(&vgdev->resp_wq);
 }
@@ -618,6 +622,8 @@
 		    cache_ent->id == le32_to_cpu(cmd->capset_id)) {
 			memcpy(cache_ent->caps_cache, resp->capset_data,
 			       cache_ent->size);
+			/* Copy must occur before is_valid is signalled. */
+			smp_wmb();
 			atomic_set(&cache_ent->is_valid, 1);
 			break;
 		}
@@ -679,11 +685,11 @@
 {
 	struct virtio_gpu_get_capset *cmd_p;
 	struct virtio_gpu_vbuffer *vbuf;
-	int max_size = vgdev->capsets[idx].max_size;
+	int max_size;
 	struct virtio_gpu_drv_cap_cache *cache_ent;
 	void *resp_buf;
 
-	if (idx > vgdev->num_capsets)
+	if (idx >= vgdev->num_capsets)
 		return -EINVAL;
 
 	if (version > vgdev->capsets[idx].max_version)
@@ -693,6 +699,7 @@
 	if (!cache_ent)
 		return -ENOMEM;
 
+	max_size = vgdev->capsets[idx].max_size;
 	cache_ent->caps_cache = kmalloc(max_size, GFP_KERNEL);
 	if (!cache_ent->caps_cache) {
 		kfree(cache_ent);
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
@@ -247,7 +247,7 @@
 {
 	struct vmw_cmdbuf_man *man = header->man;
 
-	BUG_ON(!spin_is_locked(&man->lock));
+	lockdep_assert_held_once(&man->lock);
 
 	if (header->inline_space) {
 		vmw_cmdbuf_header_inline_free(header);
@@ -293,13 +293,10 @@
 	struct vmw_cmdbuf_man *man = header->man;
 	u32 val;
 
-	if (sizeof(header->handle) > 4)
-		val = (header->handle >> 32);
-	else
-		val = 0;
+	val = upper_32_bits(header->handle);
 	vmw_write(man->dev_priv, SVGA_REG_COMMAND_HIGH, val);
 
-	val = (header->handle & 0xFFFFFFFFULL);
+	val = lower_32_bits(header->handle);
 	val |= header->cb_context & SVGA_CB_CONTEXT_MASK;
 	vmw_write(man->dev_priv, SVGA_REG_COMMAND_LOW, val);
 
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
@@ -210,8 +210,10 @@
 
 	cres->hash.key = user_key | (res_type << 24);
 	ret = drm_ht_insert_item(&man->resources, &cres->hash);
-	if (unlikely(ret != 0))
+	if (unlikely(ret != 0)) {
+		kfree(cres);
 		goto out_invalid_key;
+	}
 
 	cres->state = VMW_CMDBUF_RES_ADD;
 	cres->res = vmw_resource_reference(res);
@@ -321,6 +323,7 @@
 	list_for_each_entry_safe(entry, next, &man->list, head)
 		vmw_cmdbuf_res_free(man, entry);
 
+	drm_ht_remove(&man->resources);
 	kfree(man);
 }
 
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
@@ -747,7 +747,7 @@
 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
 	int ret;
 
-	if (!dev_priv->has_dx && dx) {
+	if (!has_sm4_context(dev_priv) && dx) {
 		DRM_ERROR("DX contexts not supported by device.\n");
 		return -EINVAL;
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
@@ -49,6 +49,7 @@
 {
 	struct ttm_buffer_object *bo = &buf->base;
 	int ret;
+	uint32_t new_flags;
 
 	ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
 	if (unlikely(ret != 0))
@@ -60,7 +61,12 @@
 	if (unlikely(ret != 0))
 		goto err;
 
-	ret = ttm_bo_validate(bo, placement, interruptible, false);
+	if (buf->pin_count > 0)
+		ret = ttm_bo_mem_compat(placement, &bo->mem,
+					&new_flags) == true ? 0 : -EINVAL;
+	else
+		ret = ttm_bo_validate(bo, placement, interruptible, false);
+
 	if (!ret)
 		vmw_bo_pin_reserved(buf, true);
 
@@ -91,6 +97,7 @@
 {
 	struct ttm_buffer_object *bo = &buf->base;
 	int ret;
+	uint32_t new_flags;
 
 	ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
 	if (unlikely(ret != 0))
@@ -102,6 +109,12 @@
 	if (unlikely(ret != 0))
 		goto err;
 
+	if (buf->pin_count > 0) {
+		ret = ttm_bo_mem_compat(&vmw_vram_gmr_placement, &bo->mem,
+					&new_flags) == true ? 0 : -EINVAL;
+		goto out_unreserve;
+	}
+
 	ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible,
 			      false);
 	if (likely(ret == 0) || ret == -ERESTARTSYS)
@@ -161,6 +174,7 @@
 	struct ttm_placement placement;
 	struct ttm_place place;
 	int ret = 0;
+	uint32_t new_flags;
 
 	place = vmw_vram_placement.placement[0];
 	place.lpfn = bo->num_pages;
@@ -185,10 +199,15 @@
 	 */
 	if (bo->mem.mem_type == TTM_PL_VRAM &&
 	    bo->mem.start < bo->num_pages &&
-	    bo->mem.start > 0)
+	    bo->mem.start > 0 &&
+	    buf->pin_count == 0)
 		(void) ttm_bo_validate(bo, &vmw_sys_placement, false, false);
 
-	ret = ttm_bo_validate(bo, &placement, interruptible, false);
+	if (buf->pin_count > 0)
+		ret = ttm_bo_mem_compat(&placement, &bo->mem,
+					&new_flags) == true ? 0 : -EINVAL;
+	else
+		ret = ttm_bo_validate(bo, &placement, interruptible, false);
 
 	/* For some reason we didn't end up at the start of vram */
 	WARN_ON(ret == 0 && bo->offset != 0);
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -25,6 +25,7 @@
  *
  **************************************************************************/
 #include <linux/module.h>
+#include <linux/console.h>
 
 #include <drm/drmP.h>
 #include "vmwgfx_drv.h"
@@ -226,6 +227,7 @@
 static int vmw_restrict_iommu;
 static int vmw_force_coherent;
 static int vmw_restrict_dma_mask;
+static int vmw_assume_16bpp;
 
 static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
 static void vmw_master_init(struct vmw_master *);
@@ -242,6 +244,8 @@
 module_param_named(force_coherent, vmw_force_coherent, int, 0600);
 MODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU");
 module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600);
+MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes");
+module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600);
 
 
 static void vmw_print_capabilities(uint32_t capabilities)
@@ -399,7 +403,7 @@
 	dev_priv->cman = vmw_cmdbuf_man_create(dev_priv);
 	if (IS_ERR(dev_priv->cman)) {
 		dev_priv->cman = NULL;
-		dev_priv->has_dx = false;
+		dev_priv->sm_type = VMW_SM_LEGACY;
 	}
 
 	ret = vmw_request_device_late(dev_priv);
@@ -590,13 +594,16 @@
 static int vmw_dma_masks(struct vmw_private *dev_priv)
 {
 	struct drm_device *dev = dev_priv->dev;
+	int ret = 0;
 
-	if (intel_iommu_enabled &&
+	ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64));
+	if (dev_priv->map_mode != vmw_dma_phys &&
 	    (sizeof(unsigned long) == 4 || vmw_restrict_dma_mask)) {
 		DRM_INFO("Restricting DMA addresses to 44 bits.\n");
-		return dma_set_mask(dev->dev, DMA_BIT_MASK(44));
+		return dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(44));
 	}
-	return 0;
+
+	return ret;
 }
 #else
 static int vmw_dma_masks(struct vmw_private *dev_priv)
@@ -651,6 +658,8 @@
 	dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
 	dev_priv->mmio_start = pci_resource_start(dev->pdev, 2);
 
+	dev_priv->assume_16bpp = !!vmw_assume_16bpp;
+
 	dev_priv->enable_fb = enable_fbdev;
 
 	vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
@@ -697,6 +706,13 @@
 			vmw_read(dev_priv,
 				 SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB);
 
+		/*
+		 * Workaround for low memory 2D VMs to compensate for the
+		 * allocation taken by fbdev
+		 */
+		if (!(dev_priv->capabilities & SVGA_CAP_3D))
+			mem_size *= 3;
+
 		dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE;
 		dev_priv->prim_bb_mem =
 			vmw_read(dev_priv,
@@ -856,7 +872,8 @@
 	if (dev_priv->has_mob) {
 		spin_lock(&dev_priv->cap_lock);
 		vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DX);
-		dev_priv->has_dx = !!vmw_read(dev_priv, SVGA_REG_DEV_CAP);
+		if (vmw_read(dev_priv, SVGA_REG_DEV_CAP))
+			dev_priv->sm_type = VMW_SM_4;
 		spin_unlock(&dev_priv->cap_lock);
 	}
 
@@ -870,7 +887,8 @@
 	if (ret)
 		goto out_no_fifo;
 
-	DRM_INFO("DX: %s\n", dev_priv->has_dx ? "yes." : "no.");
+	if (dev_priv->sm_type == VMW_SM_4)
+		DRM_INFO("SM4 support available.\n");
 
 	if (dev_priv->enable_fb) {
 		vmw_fifo_resource_inc(dev_priv);
@@ -1538,6 +1556,12 @@
 static int __init vmwgfx_init(void)
 {
 	int ret;
+
+#ifdef CONFIG_VGA_CONSOLE
+	if (vgacon_text_force())
+		return -EINVAL;
+#endif
+
 	ret = drm_pci_init(&driver, &vmw_pci_driver);
 	if (ret)
 		DRM_ERROR("Failed initializing DRM.\n");
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -352,6 +352,18 @@
 	struct ttm_buffer_object *otable_bo;
 };
 
+/**
+ * enum vmw_sm_type - Graphics context capability supported by device.
+ * @VMW_SM_LEGACY: Pre DX context.
+ * @VMW_SM_4: Context support upto SM4.
+ * @VMW_SM_MAX: Should be the last.
+ */
+enum vmw_sm_type {
+	VMW_SM_LEGACY = 0,
+	VMW_SM_4,
+	VMW_SM_MAX
+};
+
 struct vmw_private {
 	struct ttm_bo_device bdev;
 	struct ttm_bo_global_ref bo_global_ref;
@@ -386,7 +398,8 @@
 	bool has_mob;
 	spinlock_t hw_lock;
 	spinlock_t cap_lock;
-	bool has_dx;
+	bool assume_16bpp;
+	enum vmw_sm_type sm_type;
 
 	/*
 	 * VGA registers.
@@ -578,6 +591,17 @@
 	return val;
 }
 
+/**
+ * has_sm4_context - Does the device support SM4 context.
+ * @dev_priv: Device private.
+ *
+ * Return: Bool value if device support SM4 context or not.
+ */
+static inline bool has_sm4_context(const struct vmw_private *dev_priv)
+{
+	return (dev_priv->sm_type >= VMW_SM_4);
+}
+
 extern void vmw_svga_enable(struct vmw_private *dev_priv);
 extern void vmw_svga_disable(struct vmw_private *dev_priv);
 
@@ -1232,4 +1256,15 @@
 {
 	WRITE_ONCE(*addr, value);
 }
+
+static inline bool vmw_shadertype_is_valid(enum vmw_sm_type shader_model,
+					   u32 shader_type)
+{
+	SVGA3dShaderType max_allowed = SVGA3D_SHADERTYPE_PREDX_MAX;
+
+	if (shader_model >= VMW_SM_4)
+		max_allowed = SVGA3D_SHADERTYPE_DX10_MAX;
+	return shader_type >= SVGA3D_SHADERTYPE_MIN && shader_type < max_allowed;
+}
+
 #endif
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -355,7 +355,8 @@
 	u32 i;
 
 	/* Add all cotables to the validation list. */
-	if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) {
+	if (has_sm4_context(dev_priv) &&
+	    vmw_res_type(ctx) == vmw_res_dx_context) {
 		for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
 			res = vmw_context_cotable(ctx, i);
 			if (IS_ERR(res))
@@ -389,7 +390,8 @@
 			break;
 	}
 
-	if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) {
+	if (has_sm4_context(dev_priv) &&
+	    vmw_res_type(ctx) == vmw_res_dx_context) {
 		struct vmw_dma_buffer *dx_query_mob;
 
 		dx_query_mob = vmw_context_get_dx_query_mob(ctx);
@@ -471,7 +473,7 @@
 			   struct vmw_sw_context *sw_context,
 			   SVGA3dCmdHeader *header)
 {
-	return capable(CAP_SYS_ADMIN) ? : -EINVAL;
+	return -EINVAL;
 }
 
 static int vmw_cmd_ok(struct vmw_private *dev_priv,
@@ -2218,7 +2220,7 @@
 	cmd = container_of(header, struct vmw_set_shader_cmd,
 			   header);
 
-	if (cmd->body.type >= SVGA3D_SHADERTYPE_PREDX_MAX) {
+	if (!vmw_shadertype_is_valid(VMW_SM_LEGACY, cmd->body.type)) {
 		DRM_ERROR("Illegal shader type %u.\n",
 			  (unsigned) cmd->body.type);
 		return -EINVAL;
@@ -2359,6 +2361,14 @@
 	if (unlikely(ret != 0))
 		return ret;
 
+	if (!vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type) ||
+	    cmd->body.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
+		DRM_ERROR("Illegal const buffer shader %u slot %u.\n",
+			  (unsigned int) cmd->body.type,
+			  (unsigned int) cmd->body.slot);
+		return -EINVAL;
+	}
+
 	binding.bi.ctx = ctx_node->res;
 	binding.bi.res = res_node ? res_node->res : NULL;
 	binding.bi.bt = vmw_ctx_binding_cb;
@@ -2367,14 +2377,6 @@
 	binding.size = cmd->body.sizeInBytes;
 	binding.slot = cmd->body.slot;
 
-	if (binding.shader_slot >= SVGA3D_NUM_SHADERTYPE_DX10 ||
-	    binding.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
-		DRM_ERROR("Illegal const buffer shader %u slot %u.\n",
-			  (unsigned) cmd->body.type,
-			  (unsigned) binding.slot);
-		return -EINVAL;
-	}
-
 	vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
 			binding.shader_slot, binding.slot);
 
@@ -2402,7 +2404,7 @@
 
 	if ((u64) cmd->body.startView + (u64) num_sr_view >
 	    (u64) SVGA3D_DX_MAX_SRVIEWS ||
-	    cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) {
+	    !vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type)) {
 		DRM_ERROR("Invalid shader binding.\n");
 		return -EINVAL;
 	}
@@ -2442,7 +2444,7 @@
 
 	cmd = container_of(header, typeof(*cmd), header);
 
-	if (cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) {
+	if (!vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type)) {
 		DRM_ERROR("Illegal shader type %u.\n",
 			  (unsigned) cmd->body.type);
 		return -EINVAL;
@@ -2678,7 +2680,13 @@
 	}
 
 	view_type = vmw_view_cmd_to_type(header->id);
+	if (view_type == vmw_view_max)
+		return -EINVAL;
 	cmd = container_of(header, typeof(*cmd), header);
+	if (unlikely(cmd->sid == SVGA3D_INVALID_ID)) {
+		DRM_ERROR("Invalid surface id.\n");
+		return -EINVAL;
+	}
 	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
 				user_surface_converter,
 				&cmd->sid, &srf_node);
@@ -3273,19 +3281,19 @@
 		    &vmw_cmd_dx_cid_check, true, false, true),
 	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_QUERY, &vmw_cmd_dx_define_query,
 		    true, false, true),
-	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_QUERY, &vmw_cmd_ok,
+	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_QUERY, &vmw_cmd_dx_cid_check,
 		    true, false, true),
 	VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_QUERY, &vmw_cmd_dx_bind_query,
 		    true, false, true),
 	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_QUERY_OFFSET,
-		    &vmw_cmd_ok, true, false, true),
-	VMW_CMD_DEF(SVGA_3D_CMD_DX_BEGIN_QUERY, &vmw_cmd_ok,
+		    &vmw_cmd_dx_cid_check, true, false, true),
+	VMW_CMD_DEF(SVGA_3D_CMD_DX_BEGIN_QUERY, &vmw_cmd_dx_cid_check,
 		    true, false, true),
-	VMW_CMD_DEF(SVGA_3D_CMD_DX_END_QUERY, &vmw_cmd_ok,
+	VMW_CMD_DEF(SVGA_3D_CMD_DX_END_QUERY, &vmw_cmd_dx_cid_check,
 		    true, false, true),
 	VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_QUERY, &vmw_cmd_invalid,
 		    true, false, true),
-	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_PREDICATION, &vmw_cmd_invalid,
+	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_PREDICATION, &vmw_cmd_dx_cid_check,
 		    true, false, true),
 	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VIEWPORTS, &vmw_cmd_dx_cid_check,
 		    true, false, true),
@@ -3661,7 +3669,7 @@
 		*p_fence = NULL;
 	}
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -3830,14 +3838,14 @@
 	int ret;
 
 	*header = NULL;
-	if (!dev_priv->cman || kernel_commands)
-		return kernel_commands;
-
 	if (command_size > SVGA_CB_MAX_SIZE) {
 		DRM_ERROR("Command buffer is too large.\n");
 		return ERR_PTR(-EINVAL);
 	}
 
+	if (!dev_priv->cman || kernel_commands)
+		return kernel_commands;
+
 	/* If possible, add a little space for fencing. */
 	cmdbuf_size = command_size + 512;
 	cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE);
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -433,7 +433,7 @@
 		set.y = 0;
 		set.mode = NULL;
 		set.fb = NULL;
-		set.num_connectors = 1;
+		set.num_connectors = 0;
 		set.connectors = &par->con;
 		ret = drm_mode_set_config_internal(&set);
 		if (ret) {
@@ -517,28 +517,6 @@
 
 	par->set_fb = &vfb->base;
 
-	if (!par->bo_ptr) {
-		/*
-		 * Pin before mapping. Since we don't know in what placement
-		 * to pin, call into KMS to do it for us.
-		 */
-		ret = vfb->pin(vfb);
-		if (ret) {
-			DRM_ERROR("Could not pin the fbdev framebuffer.\n");
-			return ret;
-		}
-
-		ret = ttm_bo_kmap(&par->vmw_bo->base, 0,
-				  par->vmw_bo->base.num_pages, &par->map);
-		if (ret) {
-			vfb->unpin(vfb);
-			DRM_ERROR("Could not map the fbdev framebuffer.\n");
-			return ret;
-		}
-
-		par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite);
-	}
-
 	return 0;
 }
 
@@ -553,11 +531,9 @@
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 		DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
 	};
-	struct drm_display_mode *old_mode;
 	struct drm_display_mode *mode;
 	int ret;
 
-	old_mode = par->set_mode;
 	mode = drm_mode_duplicate(vmw_priv->dev, &new_mode);
 	if (!mode) {
 		DRM_ERROR("Could not create new fb mode.\n");
@@ -568,14 +544,10 @@
 	mode->vdisplay = var->yres;
 	vmw_guess_mode_timing(mode);
 
-	if (old_mode && drm_mode_equal(old_mode, mode)) {
-		drm_mode_destroy(vmw_priv->dev, mode);
-		mode = old_mode;
-		old_mode = NULL;
-	} else if (!vmw_kms_validate_mode_vram(vmw_priv,
-					       mode->hdisplay *
-					       (var->bits_per_pixel + 7) / 8,
-					       mode->vdisplay)) {
+	if (!vmw_kms_validate_mode_vram(vmw_priv,
+					mode->hdisplay *
+					DIV_ROUND_UP(var->bits_per_pixel, 8),
+					mode->vdisplay)) {
 		drm_mode_destroy(vmw_priv->dev, mode);
 		return -EINVAL;
 	}
@@ -601,6 +573,31 @@
 	if (ret)
 		goto out_unlock;
 
+	if (!par->bo_ptr) {
+		struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(set.fb);
+
+		/*
+		 * Pin before mapping. Since we don't know in what placement
+		 * to pin, call into KMS to do it for us.
+		 */
+		ret = vfb->pin(vfb);
+		if (ret) {
+			DRM_ERROR("Could not pin the fbdev framebuffer.\n");
+			goto out_unlock;
+		}
+
+		ret = ttm_bo_kmap(&par->vmw_bo->base, 0,
+				  par->vmw_bo->base.num_pages, &par->map);
+		if (ret) {
+			vfb->unpin(vfb);
+			DRM_ERROR("Could not map the fbdev framebuffer.\n");
+			goto out_unlock;
+		}
+
+		par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite);
+	}
+
+
 	vmw_fb_dirty_mark(par, par->fb_x, par->fb_y,
 			  par->set_fb->width, par->set_fb->height);
 
@@ -610,8 +607,8 @@
 	schedule_delayed_work(&par->local_work, 0);
 
 out_unlock:
-	if (old_mode)
-		drm_mode_destroy(vmw_priv->dev, old_mode);
+	if (par->set_mode)
+		drm_mode_destroy(vmw_priv->dev, par->set_mode);
 	par->set_mode = mode;
 
 	drm_modeset_unlock_all(vmw_priv->dev);
@@ -818,7 +815,9 @@
 	flush_delayed_work(&par->local_work);
 
 	mutex_lock(&par->bo_mutex);
+	drm_modeset_lock_all(vmw_priv->dev);
 	(void) vmw_fb_kms_detach(par, true, false);
+	drm_modeset_unlock_all(vmw_priv->dev);
 	mutex_unlock(&par->bo_mutex);
 
 	return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -31,7 +31,6 @@
 #define VMW_FENCE_WRAP (1 << 31)
 
 struct vmw_fence_manager {
-	int num_fence_objects;
 	struct vmw_private *dev_priv;
 	spinlock_t lock;
 	struct list_head fence_list;
@@ -113,14 +112,14 @@
 {
 	struct vmw_fence_obj *fence =
 		container_of(f, struct vmw_fence_obj, base);
-
 	struct vmw_fence_manager *fman = fman_from_fence(fence);
 	unsigned long irq_flags;
 
-	spin_lock_irqsave(&fman->lock, irq_flags);
-	list_del_init(&fence->head);
-	--fman->num_fence_objects;
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	if (!list_empty(&fence->head)) {
+		spin_lock_irqsave(&fman->lock, irq_flags);
+		list_del_init(&fence->head);
+		spin_unlock_irqrestore(&fman->lock, irq_flags);
+	}
 	fence->destroy(fence);
 }
 
@@ -338,7 +337,6 @@
 		goto out_unlock;
 	}
 	list_add_tail(&fence->head, &fman->fence_list);
-	++fman->num_fence_objects;
 
 out_unlock:
 	spin_unlock_irqrestore(&fman->lock, irq_flags);
@@ -387,7 +385,7 @@
 {
 	u32 goal_seqno;
 	u32 *fifo_mem;
-	struct vmw_fence_obj *fence;
+	struct vmw_fence_obj *fence, *next_fence;
 
 	if (likely(!fman->seqno_valid))
 		return false;
@@ -398,7 +396,7 @@
 		return false;
 
 	fman->seqno_valid = false;
-	list_for_each_entry(fence, &fman->fence_list, head) {
+	list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
 		if (!list_empty(&fence->seq_passed_actions)) {
 			fman->seqno_valid = true;
 			vmw_mmio_write(fence->base.seqno,
@@ -539,7 +537,7 @@
 		     struct vmw_fence_obj **p_fence)
 {
 	struct vmw_fence_obj *fence;
-	int ret;
+ 	int ret;
 
 	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
 	if (unlikely(fence == NULL))
@@ -702,6 +700,41 @@
 }
 
 
+/**
+ * vmw_fence_obj_lookup - Look up a user-space fence object
+ *
+ * @tfile: A struct ttm_object_file identifying the caller.
+ * @handle: A handle identifying the fence object.
+ * @return: A struct vmw_user_fence base ttm object on success or
+ * an error pointer on failure.
+ *
+ * The fence object is looked up and type-checked. The caller needs
+ * to have opened the fence object first, but since that happens on
+ * creation and fence objects aren't shareable, that's not an
+ * issue currently.
+ */
+static struct ttm_base_object *
+vmw_fence_obj_lookup(struct ttm_object_file *tfile, u32 handle)
+{
+	struct ttm_base_object *base = ttm_base_object_lookup(tfile, handle);
+
+	if (!base) {
+		pr_err("Invalid fence object handle 0x%08lx.\n",
+		       (unsigned long)handle);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (base->refcount_release != vmw_user_fence_base_release) {
+		pr_err("Invalid fence object handle 0x%08lx.\n",
+		       (unsigned long)handle);
+		ttm_base_object_unref(&base);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return base;
+}
+
+
 int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv)
 {
@@ -727,13 +760,9 @@
 		arg->kernel_cookie = jiffies + wait_timeout;
 	}
 
-	base = ttm_base_object_lookup(tfile, arg->handle);
-	if (unlikely(base == NULL)) {
-		printk(KERN_ERR "Wait invalid fence object handle "
-		       "0x%08lx.\n",
-		       (unsigned long)arg->handle);
-		return -EINVAL;
-	}
+	base = vmw_fence_obj_lookup(tfile, arg->handle);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
 
 	fence = &(container_of(base, struct vmw_user_fence, base)->fence);
 
@@ -772,13 +801,9 @@
 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
 	struct vmw_private *dev_priv = vmw_priv(dev);
 
-	base = ttm_base_object_lookup(tfile, arg->handle);
-	if (unlikely(base == NULL)) {
-		printk(KERN_ERR "Fence signaled invalid fence object handle "
-		       "0x%08lx.\n",
-		       (unsigned long)arg->handle);
-		return -EINVAL;
-	}
+	base = vmw_fence_obj_lookup(tfile, arg->handle);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
 
 	fence = &(container_of(base, struct vmw_user_fence, base)->fence);
 	fman = fman_from_fence(fence);
@@ -1093,6 +1118,7 @@
 		(struct drm_vmw_fence_event_arg *) data;
 	struct vmw_fence_obj *fence = NULL;
 	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+	struct ttm_object_file *tfile = vmw_fp->tfile;
 	struct drm_vmw_fence_rep __user *user_fence_rep =
 		(struct drm_vmw_fence_rep __user *)(unsigned long)
 		arg->fence_rep;
@@ -1106,24 +1132,18 @@
 	 */
 	if (arg->handle) {
 		struct ttm_base_object *base =
-			ttm_base_object_lookup_for_ref(dev_priv->tdev,
-						       arg->handle);
+			vmw_fence_obj_lookup(tfile, arg->handle);
+
+		if (IS_ERR(base))
+			return PTR_ERR(base);
 
-		if (unlikely(base == NULL)) {
-			DRM_ERROR("Fence event invalid fence object handle "
-				  "0x%08lx.\n",
-				  (unsigned long)arg->handle);
-			return -EINVAL;
-		}
 		fence = &(container_of(base, struct vmw_user_fence,
 				       base)->fence);
 		(void) vmw_fence_obj_reference(fence);
 
 		if (user_fence_rep != NULL) {
-			bool existed;
-
 			ret = ttm_ref_object_add(vmw_fp->tfile, base,
-						 TTM_REF_USAGE, &existed);
+						 TTM_REF_USAGE, NULL, false);
 			if (unlikely(ret != 0)) {
 				DRM_ERROR("Failed to reference a fence "
 					  "object.\n");
@@ -1166,8 +1186,7 @@
 	return 0;
 out_no_create:
 	if (user_fence_rep != NULL)
-		ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
-					  handle, TTM_REF_USAGE);
+		ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE);
 out_no_ref_obj:
 	vmw_fence_obj_unreference(&fence);
 	return ret;
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -368,6 +368,8 @@
 				return fifo_state->static_buffer;
 			else {
 				fifo_state->dynamic_buffer = vmalloc(bytes);
+				if (!fifo_state->dynamic_buffer)
+					goto out_err;
 				return fifo_state->dynamic_buffer;
 			}
 		}
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -111,11 +111,9 @@
 			(dev_priv->active_display_unit == vmw_du_screen_target);
 		break;
 	case DRM_VMW_PARAM_DX:
-		param->value = dev_priv->has_dx;
+		param->value = has_sm4_context(dev_priv);
 		break;
 	default:
-		DRM_ERROR("Illegal vmwgfx get param request: %d\n",
-			  param->param);
 		return -EINVAL;
 	}
 
@@ -186,7 +184,7 @@
 	bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS);
 	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
 
-	if (unlikely(arg->pad64 != 0)) {
+	if (unlikely(arg->pad64 != 0 || arg->max_size == 0)) {
 		DRM_ERROR("Illegal GET_3D_CAP argument.\n");
 		return -EINVAL;
 	}
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -27,7 +27,6 @@
 
 #include "vmwgfx_kms.h"
 
-
 /* Might need a hrtimer here? */
 #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
 
@@ -302,7 +301,8 @@
 	if (cmd->dma.guest.ptr.offset % PAGE_SIZE ||
 	    box->x != 0    || box->y != 0    || box->z != 0    ||
 	    box->srcx != 0 || box->srcy != 0 || box->srcz != 0 ||
-	    box->d != 1    || box_count != 1) {
+	    box->d != 1    || box_count != 1 ||
+	    box->w > 64 || box->h > 64) {
 		/* TODO handle none page aligned offsets */
 		/* TODO handle more dst & src != 0 */
 		/* TODO handle more then one copy */
@@ -570,7 +570,7 @@
 	 * For DX, surface format validation is done when surface->scanout
 	 * is set.
 	 */
-	if (!dev_priv->has_dx && format != surface->format) {
+	if (!has_sm4_context(dev_priv) && format != surface->format) {
 		DRM_ERROR("Invalid surface format for requested mode.\n");
 		return -EINVAL;
 	}
@@ -763,21 +763,25 @@
 	uint32_t format;
 	struct drm_vmw_size content_base_size;
 	struct vmw_resource *res;
+	unsigned int bytes_pp;
 	int ret;
 
 	switch (mode_cmd->depth) {
 	case 32:
 	case 24:
 		format = SVGA3D_X8R8G8B8;
+		bytes_pp = 4;
 		break;
 
 	case 16:
 	case 15:
 		format = SVGA3D_R5G6B5;
+		bytes_pp = 2;
 		break;
 
 	case 8:
 		format = SVGA3D_P8;
+		bytes_pp = 1;
 		break;
 
 	default:
@@ -785,7 +789,7 @@
 		return -EINVAL;
 	}
 
-	content_base_size.width  = mode_cmd->width;
+	content_base_size.width  = mode_cmd->pitch / bytes_pp;
 	content_base_size.height = mode_cmd->height;
 	content_base_size.depth  = 1;
 
@@ -1534,14 +1538,10 @@
 		DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
 	};
 	int i;
-	u32 assumed_bpp = 2;
+	u32 assumed_bpp = 4;
 
-	/*
-	 * If using screen objects, then assume 32-bpp because that's what the
-	 * SVGA device is assuming
-	 */
-	if (dev_priv->active_display_unit == vmw_du_screen_object)
-		assumed_bpp = 4;
+	if (dev_priv->assume_16bpp)
+		assumed_bpp = 2;
 
 	if (dev_priv->active_display_unit == vmw_du_screen_target) {
 		max_width  = min(max_width,  dev_priv->stdu_max_width);
@@ -1910,9 +1910,12 @@
  * Helper to be used if an error forces the caller to undo the actions of
  * vmw_kms_helper_resource_prepare.
  */
-void vmw_kms_helper_resource_revert(struct vmw_resource *res)
+void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx)
 {
-	vmw_kms_helper_buffer_revert(res->backup);
+	struct vmw_resource *res = ctx->res;
+
+	vmw_kms_helper_buffer_revert(ctx->buf);
+	vmw_dmabuf_unreference(&ctx->buf);
 	vmw_resource_unreserve(res, false, NULL, 0);
 	mutex_unlock(&res->dev_priv->cmdbuf_mutex);
 }
@@ -1929,10 +1932,14 @@
  * interrupted by a signal.
  */
 int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
-				    bool interruptible)
+				    bool interruptible,
+				    struct vmw_validation_ctx *ctx)
 {
 	int ret = 0;
 
+	ctx->buf = NULL;
+	ctx->res = res;
+
 	if (interruptible)
 		ret = mutex_lock_interruptible(&res->dev_priv->cmdbuf_mutex);
 	else
@@ -1951,6 +1958,8 @@
 						    res->dev_priv->has_mob);
 		if (ret)
 			goto out_unreserve;
+
+		ctx->buf = vmw_dmabuf_reference(res->backup);
 	}
 	ret = vmw_resource_validate(res);
 	if (ret)
@@ -1958,7 +1967,7 @@
 	return 0;
 
 out_revert:
-	vmw_kms_helper_buffer_revert(res->backup);
+	vmw_kms_helper_buffer_revert(ctx->buf);
 out_unreserve:
 	vmw_resource_unreserve(res, false, NULL, 0);
 out_unlock:
@@ -1974,13 +1983,16 @@
  * @out_fence: Optional pointer to a fence pointer. If non-NULL, a
  * ref-counted fence pointer is returned here.
  */
-void vmw_kms_helper_resource_finish(struct vmw_resource *res,
-			     struct vmw_fence_obj **out_fence)
+void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx,
+				    struct vmw_fence_obj **out_fence)
 {
-	if (res->backup || out_fence)
-		vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup,
+	struct vmw_resource *res = ctx->res;
+
+	if (ctx->buf || out_fence)
+		vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf,
 					     out_fence, NULL);
 
+	vmw_dmabuf_unreference(&ctx->buf);
 	vmw_resource_unreserve(res, false, NULL, 0);
 	mutex_unlock(&res->dev_priv->cmdbuf_mutex);
 }
@@ -2075,7 +2087,7 @@
 		++i;
 	}
 
-	if (i != unit) {
+	if (&con->head == &dev_priv->dev->mode_config.connector_list) {
 		DRM_ERROR("Could not find initial display unit.\n");
 		return -EINVAL;
 	}
@@ -2097,13 +2109,13 @@
 			break;
 	}
 
-	if (mode->type & DRM_MODE_TYPE_PREFERRED)
-		*p_mode = mode;
-	else {
+	if (&mode->head == &con->modes) {
 		WARN_ONCE(true, "Could not find initial preferred mode.\n");
 		*p_mode = list_first_entry(&con->modes,
 					   struct drm_display_mode,
 					   head);
+	} else {
+		*p_mode = mode;
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -180,6 +180,11 @@
 	bool is_implicit;
 };
 
+struct vmw_validation_ctx {
+	struct vmw_resource *res;
+	struct vmw_dma_buffer *buf;
+};
+
 #define vmw_crtc_to_du(x) \
 	container_of(x, struct vmw_display_unit, crtc)
 #define vmw_connector_to_du(x) \
@@ -230,9 +235,10 @@
 				  struct drm_vmw_fence_rep __user *
 				  user_fence_rep);
 int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
-				    bool interruptible);
-void vmw_kms_helper_resource_revert(struct vmw_resource *res);
-void vmw_kms_helper_resource_finish(struct vmw_resource *res,
+				    bool interruptible,
+				    struct vmw_validation_ctx *ctx);
+void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx);
+void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx,
 				    struct vmw_fence_obj **out_fence);
 int vmw_kms_readback(struct vmw_private *dev_priv,
 		     struct drm_file *file_priv,
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
@@ -318,7 +318,7 @@
 	struct vmw_otable **otables = &dev_priv->otable_batch.otables;
 	int ret;
 
-	if (dev_priv->has_dx) {
+	if (has_sm4_context(dev_priv)) {
 		*otables = kmalloc(sizeof(dx_tables), GFP_KERNEL);
 		if (*otables == NULL)
 			return -ENOMEM;
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -591,7 +591,7 @@
 		return ret;
 
 	ret = ttm_ref_object_add(tfile, &user_bo->prime.base,
-				 TTM_REF_SYNCCPU_WRITE, &existed);
+				 TTM_REF_SYNCCPU_WRITE, &existed, false);
 	if (ret != 0 || existed)
 		ttm_bo_synccpu_write_release(&user_bo->dma.base);
 
@@ -775,7 +775,7 @@
 
 	*handle = user_bo->prime.base.hash.key;
 	return ttm_ref_object_add(tfile, &user_bo->prime.base,
-				  TTM_REF_USAGE, NULL);
+				  TTM_REF_USAGE, NULL, false);
 }
 
 /*
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -841,12 +841,13 @@
 	struct vmw_framebuffer_surface *vfbs =
 		container_of(framebuffer, typeof(*vfbs), base);
 	struct vmw_kms_sou_surface_dirty sdirty;
+	struct vmw_validation_ctx ctx;
 	int ret;
 
 	if (!srf)
 		srf = &vfbs->surface->res;
 
-	ret = vmw_kms_helper_resource_prepare(srf, true);
+	ret = vmw_kms_helper_resource_prepare(srf, true, &ctx);
 	if (ret)
 		return ret;
 
@@ -865,7 +866,7 @@
 	ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
 				   dest_x, dest_y, num_clips, inc,
 				   &sdirty.base);
-	vmw_kms_helper_resource_finish(srf, out_fence);
+	vmw_kms_helper_resource_finish(&ctx, out_fence);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1003,12 +1003,13 @@
 	struct vmw_framebuffer_surface *vfbs =
 		container_of(framebuffer, typeof(*vfbs), base);
 	struct vmw_stdu_dirty sdirty;
+	struct vmw_validation_ctx ctx;
 	int ret;
 
 	if (!srf)
 		srf = &vfbs->surface->res;
 
-	ret = vmw_kms_helper_resource_prepare(srf, true);
+	ret = vmw_kms_helper_resource_prepare(srf, true, &ctx);
 	if (ret)
 		return ret;
 
@@ -1031,7 +1032,7 @@
 				   dest_x, dest_y, num_clips, inc,
 				   &sdirty.base);
 out_finish:
-	vmw_kms_helper_resource_finish(srf, out_fence);
+	vmw_kms_helper_resource_finish(&ctx, out_fence);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ linux-4.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -715,11 +715,14 @@
 			128;
 
 	num_sizes = 0;
-	for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
+	for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
+		if (req->mip_levels[i] > DRM_VMW_MAX_MIP_LEVELS)
+			return -EINVAL;
 		num_sizes += req->mip_levels[i];
+	}
 
-	if (num_sizes > DRM_VMW_MAX_SURFACE_FACES *
-	    DRM_VMW_MAX_MIP_LEVELS)
+	if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS ||
+	    num_sizes == 0)
 		return -EINVAL;
 
 	size = vmw_user_surface_size + 128 +
@@ -904,17 +907,16 @@
 	uint32_t handle;
 	struct ttm_base_object *base;
 	int ret;
+	bool require_exist = false;
 
 	if (handle_type == DRM_VMW_HANDLE_PRIME) {
 		ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle);
 		if (unlikely(ret != 0))
 			return ret;
 	} else {
-		if (unlikely(drm_is_render_client(file_priv))) {
-			DRM_ERROR("Render client refused legacy "
-				  "surface reference.\n");
-			return -EACCES;
-		}
+		if (unlikely(drm_is_render_client(file_priv)))
+			require_exist = true;
+
 		if (ACCESS_ONCE(vmw_fpriv(file_priv)->locked_master)) {
 			DRM_ERROR("Locked master refused legacy "
 				  "surface reference.\n");
@@ -942,17 +944,14 @@
 
 		/*
 		 * Make sure the surface creator has the same
-		 * authenticating master.
+		 * authenticating master, or is already registered with us.
 		 */
 		if (drm_is_primary_client(file_priv) &&
-		    user_srf->master != file_priv->master) {
-			DRM_ERROR("Trying to reference surface outside of"
-				  " master domain.\n");
-			ret = -EACCES;
-			goto out_bad_resource;
-		}
+		    user_srf->master != file_priv->master)
+			require_exist = true;
 
-		ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
+		ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL,
+					 require_exist);
 		if (unlikely(ret != 0)) {
 			DRM_ERROR("Could not add a reference to a surface.\n");
 			goto out_bad_resource;
@@ -1060,7 +1059,7 @@
 	}
 
 	if (srf->array_size > 0) {
-		/* has_dx checked on creation time. */
+		/* VMW_SM_4 support verified at creation time. */
 		cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V2;
 		cmd_len = sizeof(cmd2->body);
 		submit_len = sizeof(*cmd2);
@@ -1289,11 +1288,14 @@
 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
 	int ret;
 	uint32_t size;
-	uint32_t backup_handle;
+	uint32_t backup_handle = 0;
 
 	if (req->multisample_count != 0)
 		return -EINVAL;
 
+	if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS)
+		return -EINVAL;
+
 	if (unlikely(vmw_user_surface_size == 0))
 		vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
 			128;
@@ -1329,12 +1331,16 @@
 		ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
 					     &res->backup,
 					     &user_srf->backup_base);
-		if (ret == 0 && res->backup->base.num_pages * PAGE_SIZE <
-		    res->backup_size) {
-			DRM_ERROR("Surface backup buffer is too small.\n");
-			vmw_dmabuf_unreference(&res->backup);
-			ret = -EINVAL;
-			goto out_unlock;
+		if (ret == 0) {
+			if (res->backup->base.num_pages * PAGE_SIZE <
+			    res->backup_size) {
+				DRM_ERROR("Surface backup buffer is too small.\n");
+				vmw_dmabuf_unreference(&res->backup);
+				ret = -EINVAL;
+				goto out_unlock;
+			} else {
+				backup_handle = req->buffer_handle;
+			}
 		}
 	} else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer)
 		ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
@@ -1508,7 +1514,7 @@
 	}
 
 	/* array_size must be null for non-GL3 host. */
-	if (array_size > 0 && !dev_priv->has_dx) {
+	if (array_size > 0 && !has_sm4_context(dev_priv)) {
 		DRM_ERROR("Tried to create DX surface on non-DX host.\n");
 		return -EINVAL;
 	}
--- linux-4.4.0.orig/drivers/gpu/host1x/dev.c
+++ linux-4.4.0/drivers/gpu/host1x/dev.c
@@ -116,8 +116,8 @@
 
 	syncpt_irq = platform_get_irq(pdev, 0);
 	if (syncpt_irq < 0) {
-		dev_err(&pdev->dev, "failed to get IRQ\n");
-		return -ENXIO;
+		dev_err(&pdev->dev, "failed to get IRQ: %d\n", syncpt_irq);
+		return syncpt_irq;
 	}
 
 	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
--- linux-4.4.0.orig/drivers/gpu/ipu-v3/ipu-common.c
+++ linux-4.4.0/drivers/gpu/ipu-v3/ipu-common.c
@@ -746,8 +746,8 @@
 	.cpmem_ofs = 0x1f000000,
 	.srm_ofs = 0x1f040000,
 	.tpm_ofs = 0x1f060000,
-	.csi0_ofs = 0x1f030000,
-	.csi1_ofs = 0x1f038000,
+	.csi0_ofs = 0x1e030000,
+	.csi1_ofs = 0x1e038000,
 	.ic_ofs = 0x1e020000,
 	.disp0_ofs = 0x1e040000,
 	.disp1_ofs = 0x1e048000,
@@ -762,8 +762,8 @@
 	.cpmem_ofs = 0x07000000,
 	.srm_ofs = 0x07040000,
 	.tpm_ofs = 0x07060000,
-	.csi0_ofs = 0x07030000,
-	.csi1_ofs = 0x07038000,
+	.csi0_ofs = 0x06030000,
+	.csi1_ofs = 0x06038000,
 	.ic_ofs = 0x06020000,
 	.disp0_ofs = 0x06040000,
 	.disp1_ofs = 0x06048000,
@@ -997,7 +997,7 @@
 };
 
 /* These must be in the order of the corresponding device tree port nodes */
-static const struct ipu_platform_reg client_reg[] = {
+static struct ipu_platform_reg client_reg[] = {
 	{
 		.pdata = {
 			.csi = 0,
@@ -1048,8 +1048,19 @@
 	mutex_unlock(&ipu_client_id_mutex);
 
 	for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
-		const struct ipu_platform_reg *reg = &client_reg[i];
+		struct ipu_platform_reg *reg = &client_reg[i];
 		struct platform_device *pdev;
+		struct device_node *of_node;
+
+		/* Associate subdevice with the corresponding port node */
+		of_node = of_graph_get_port_by_id(dev->of_node, i);
+		if (!of_node) {
+			dev_info(dev,
+				 "no port@%d node in %s, not using %s%d\n",
+				 i, dev->of_node->full_name,
+				 (i / 2) ? "DI" : "CSI", i % 2);
+			continue;
+		}
 
 		pdev = platform_device_alloc(reg->name, id++);
 		if (!pdev) {
@@ -1059,15 +1070,7 @@
 
 		pdev->dev.parent = dev;
 
-		/* Associate subdevice with the corresponding port node */
-		pdev->dev.of_node = of_graph_get_port_by_id(dev->of_node, i);
-		if (!pdev->dev.of_node) {
-			dev_err(dev, "missing port@%d node in %s\n", i,
-				dev->of_node->full_name);
-			ret = -ENODEV;
-			goto err_register;
-		}
-
+		reg->pdata.of_node = of_node;
 		ret = platform_device_add_data(pdev, &reg->pdata,
 					       sizeof(reg->pdata));
 		if (!ret)
@@ -1076,6 +1079,12 @@
 			platform_device_put(pdev);
 			goto err_register;
 		}
+
+		/*
+		 * Set of_node only after calling platform_device_add. Otherwise
+		 * the platform:imx-ipuv3-crtc modalias won't be used.
+		 */
+		pdev->dev.of_node = of_node;
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/gpu/ipu-v3/ipu-dp.c
+++ linux-4.4.0/drivers/gpu/ipu-v3/ipu-dp.c
@@ -195,7 +195,8 @@
 		ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
 				DP_COM_CONF_CSC_DEF_BOTH);
 	} else {
-		if (flow->foreground.in_cs == flow->out_cs)
+		if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
+		    flow->foreground.in_cs == flow->out_cs)
 			/*
 			 * foreground identical to output, apply color
 			 * conversion on background
@@ -261,6 +262,8 @@
 	struct ipu_dp_priv *priv = flow->priv;
 	u32 reg, csc;
 
+	dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
+
 	if (!dp->foreground)
 		return;
 
@@ -268,8 +271,9 @@
 
 	reg = readl(flow->base + DP_COM_CONF);
 	csc = reg & DP_COM_CONF_CSC_DEF_MASK;
-	if (csc == DP_COM_CONF_CSC_DEF_FG)
-		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+	reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+	if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
+		reg |= DP_COM_CONF_CSC_DEF_BG;
 
 	reg &= ~DP_COM_CONF_FG_EN;
 	writel(reg, flow->base + DP_COM_CONF);
@@ -350,6 +354,8 @@
 	mutex_init(&priv->mutex);
 
 	for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
+		priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
+		priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
 		priv->flow[i].foreground.foreground = true;
 		priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
 		priv->flow[i].priv = priv;
--- linux-4.4.0.orig/drivers/gpu/ipu-v3/ipu-ic.c
+++ linux-4.4.0/drivers/gpu/ipu-v3/ipu-ic.c
@@ -255,7 +255,7 @@
 	writel(param, base++);
 
 	param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
-		(params->sat << 9);
+		(params->sat << 10);
 	writel(param, base++);
 
 	param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
--- linux-4.4.0.orig/drivers/hid/Kconfig
+++ linux-4.4.0/drivers/hid/Kconfig
@@ -165,11 +165,11 @@
 	Support for Cherry Cymotion keyboard.
 
 config HID_CHICONY
-	tristate "Chicony Tactical pad"
+	tristate "Chicony devices"
 	depends on HID
 	default !EXPERT
 	---help---
-	Support for Chicony Tactical pad.
+	Support for Chicony Tactical pad and special keys on Chicony keyboards.
 
 config HID_CORSAIR
 	tristate "Corsair devices"
@@ -920,6 +920,14 @@
 	  standard sensors.
 	  Select this config option for custom/generic sensor support.
 
+config HID_ALPS
+	tristate "Alps HID device support"
+	depends on HID
+	---help---
+	Support for Alps I2C HID touchpads and StickPointer.
+	Say Y here if you have a Alps touchpads over i2c-hid or usbhid
+	and want support for its special functionalities.
+
 endmenu
 
 endif # HID
--- linux-4.4.0.orig/drivers/hid/Makefile
+++ linux-4.4.0/drivers/hid/Makefile
@@ -21,6 +21,7 @@
 hid-wiimote-$(CONFIG_DEBUG_FS)	+= hid-wiimote-debug.o
 
 obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
+obj-$(CONFIG_HID_ALPS)		+= hid-alps.o
 obj-$(CONFIG_HID_ACRUX)		+= hid-axff.o
 obj-$(CONFIG_HID_APPLE)		+= hid-apple.o
 obj-$(CONFIG_HID_APPLEIR)	+= hid-appleir.o
--- linux-4.4.0.orig/drivers/hid/hid-alps.c
+++ linux-4.4.0/drivers/hid/hid-alps.c
@@ -0,0 +1,506 @@
+/*
+ *  Copyright (c) 2016 Masaki Ota <masaki.ota@jp.alps.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+#include "hid-ids.h"
+
+/* ALPS Device Product ID */
+#define HID_PRODUCT_ID_T3_BTNLESS	0xD0C0
+#define HID_PRODUCT_ID_COSMO		0x1202
+#define HID_PRODUCT_ID_U1_PTP_1		0x1207
+#define HID_PRODUCT_ID_U1			0x1209
+#define HID_PRODUCT_ID_U1_PTP_2		0x120A
+#define HID_PRODUCT_ID_U1_DUAL		0x120B
+#define HID_PRODUCT_ID_T4_BTNLESS	0x120C
+
+#define DEV_SINGLEPOINT				0x01
+#define DEV_DUALPOINT				0x02
+
+#define U1_MOUSE_REPORT_ID			0x01 /* Mouse data ReportID */
+#define U1_ABSOLUTE_REPORT_ID		0x03 /* Absolute data ReportID */
+#define U1_FEATURE_REPORT_ID		0x05 /* Feature ReportID */
+#define U1_SP_ABSOLUTE_REPORT_ID	0x06 /* Feature ReportID */
+
+#define U1_FEATURE_REPORT_LEN		0x08 /* Feature Report Length */
+#define U1_FEATURE_REPORT_LEN_ALL	0x0A
+#define U1_CMD_REGISTER_READ		0xD1
+#define U1_CMD_REGISTER_WRITE		0xD2
+
+#define	U1_DEVTYPE_SP_SUPPORT		0x10 /* SP Support */
+#define	U1_DISABLE_DEV				0x01
+#define U1_TP_ABS_MODE				0x02
+#define	U1_SP_ABS_MODE				0x80
+
+#define ADDRESS_U1_DEV_CTRL_1	0x00800040
+#define ADDRESS_U1_DEVICE_TYP	0x00800043
+#define ADDRESS_U1_NUM_SENS_X	0x00800047
+#define ADDRESS_U1_NUM_SENS_Y	0x00800048
+#define ADDRESS_U1_PITCH_SENS_X	0x00800049
+#define ADDRESS_U1_PITCH_SENS_Y	0x0080004A
+#define ADDRESS_U1_RESO_DWN_ABS 0x0080004E
+#define ADDRESS_U1_PAD_BTN		0x00800052
+#define ADDRESS_U1_SP_BTN		0x0080009F
+
+#define MAX_TOUCHES	5
+
+/**
+ * struct u1_data
+ *
+ * @input: pointer to the kernel input device
+ * @input2: pointer to the kernel input2 device
+ * @hdev: pointer to the struct hid_device
+ *
+ * @dev_ctrl: device control parameter
+ * @dev_type: device type
+ * @sen_line_num_x: number of sensor line of X
+ * @sen_line_num_y: number of sensor line of Y
+ * @pitch_x: sensor pitch of X
+ * @pitch_y: sensor pitch of Y
+ * @resolution: resolution
+ * @btn_info: button information
+ * @x_active_len_mm: active area length of X (mm)
+ * @y_active_len_mm: active area length of Y (mm)
+ * @x_max: maximum x coordinate value
+ * @y_max: maximum y coordinate value
+ * @btn_cnt: number of buttons
+ * @sp_btn_cnt: number of stick buttons
+ */
+struct u1_dev {
+	struct input_dev *input;
+	struct input_dev *input2;
+	struct hid_device *hdev;
+
+	u8	dev_ctrl;
+	u8	dev_type;
+	u8	sen_line_num_x;
+	u8	sen_line_num_y;
+	u8	pitch_x;
+	u8	pitch_y;
+	u8	resolution;
+	u8	btn_info;
+	u8	sp_btn_info;
+	u32	x_active_len_mm;
+	u32	y_active_len_mm;
+	u32	x_max;
+	u32	y_max;
+	u32	btn_cnt;
+	u32	sp_btn_cnt;
+};
+
+static int u1_read_write_register(struct hid_device *hdev, u32 address,
+	u8 *read_val, u8 write_val, bool read_flag)
+{
+	int ret, i;
+	u8 check_sum;
+	u8 *input;
+	u8 *readbuf;
+
+	input = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
+	if (!input)
+		return -ENOMEM;
+
+	input[0] = U1_FEATURE_REPORT_ID;
+	if (read_flag) {
+		input[1] = U1_CMD_REGISTER_READ;
+		input[6] = 0x00;
+	} else {
+		input[1] = U1_CMD_REGISTER_WRITE;
+		input[6] = write_val;
+	}
+
+	put_unaligned_le32(address, input + 2);
+
+	/* Calculate the checksum */
+	check_sum = U1_FEATURE_REPORT_LEN_ALL;
+	for (i = 0; i < U1_FEATURE_REPORT_LEN - 1; i++)
+		check_sum += input[i];
+
+	input[7] = check_sum;
+	ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, input,
+			U1_FEATURE_REPORT_LEN,
+			HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed to read command (%d)\n", ret);
+		goto exit;
+	}
+
+	if (read_flag) {
+		readbuf = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
+		if (!readbuf) {
+			kfree(input);
+			return -ENOMEM;
+		}
+
+		ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, readbuf,
+				U1_FEATURE_REPORT_LEN,
+				HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+
+		if (ret < 0) {
+			dev_err(&hdev->dev, "failed read register (%d)\n", ret);
+			goto exit;
+		}
+
+		*read_val = readbuf[6];
+
+		kfree(readbuf);
+	}
+
+	ret = 0;
+
+exit:
+	kfree(input);
+	return ret;
+}
+
+static int alps_raw_event(struct hid_device *hdev,
+		struct hid_report *report, u8 *data, int size)
+{
+	unsigned int x, y, z;
+	int i;
+	short sp_x, sp_y;
+	struct u1_dev *hdata = hid_get_drvdata(hdev);
+
+	switch (data[0]) {
+	case U1_MOUSE_REPORT_ID:
+		break;
+	case U1_FEATURE_REPORT_ID:
+		break;
+	case U1_ABSOLUTE_REPORT_ID:
+		for (i = 0; i < MAX_TOUCHES; i++) {
+			u8 *contact = &data[i * 5];
+
+			x = get_unaligned_le16(contact + 3);
+			y = get_unaligned_le16(contact + 5);
+			z = contact[7] & 0x7F;
+
+			input_mt_slot(hdata->input, i);
+
+			if (z != 0) {
+				input_mt_report_slot_state(hdata->input,
+					MT_TOOL_FINGER, 1);
+				input_report_abs(hdata->input,
+					ABS_MT_POSITION_X, x);
+				input_report_abs(hdata->input,
+					ABS_MT_POSITION_Y, y);
+				input_report_abs(hdata->input,
+					ABS_MT_PRESSURE, z);
+			} else {
+				input_mt_report_slot_state(hdata->input,
+					MT_TOOL_FINGER, 0);
+			}
+		}
+
+		input_mt_sync_frame(hdata->input);
+
+		input_report_key(hdata->input, BTN_LEFT,
+			data[1] & 0x1);
+		input_report_key(hdata->input, BTN_RIGHT,
+			(data[1] & 0x2));
+		input_report_key(hdata->input, BTN_MIDDLE,
+			(data[1] & 0x4));
+
+		input_sync(hdata->input);
+
+		return 1;
+
+	case U1_SP_ABSOLUTE_REPORT_ID:
+		sp_x = get_unaligned_le16(data+2);
+		sp_y = get_unaligned_le16(data+4);
+
+		sp_x = sp_x / 8;
+		sp_y = sp_y / 8;
+
+		input_report_rel(hdata->input2, REL_X, sp_x);
+		input_report_rel(hdata->input2, REL_Y, sp_y);
+
+		input_report_key(hdata->input2, BTN_LEFT,
+			data[1] & 0x1);
+		input_report_key(hdata->input2, BTN_RIGHT,
+			(data[1] & 0x2));
+		input_report_key(hdata->input2, BTN_MIDDLE,
+			(data[1] & 0x4));
+
+		input_sync(hdata->input2);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int alps_post_reset(struct hid_device *hdev)
+{
+	return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+				NULL, U1_TP_ABS_MODE | U1_SP_ABS_MODE, false);
+}
+
+static int alps_post_resume(struct hid_device *hdev)
+{
+	return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+				NULL, U1_TP_ABS_MODE | U1_SP_ABS_MODE, false);
+}
+#endif /* CONFIG_PM */
+
+static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
+{
+	struct u1_dev *data = hid_get_drvdata(hdev);
+	struct input_dev *input = hi->input, *input2;
+	struct u1_dev devInfo;
+	int ret;
+	int res_x, res_y, i;
+
+	data->input = input;
+
+	hid_dbg(hdev, "Opening low level driver\n");
+	ret = hid_hw_open(hdev);
+	if (ret)
+		return ret;
+
+	/* Allow incoming hid reports */
+	hid_device_io_start(hdev);
+
+	/* Device initialization */
+	ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+			&devInfo.dev_ctrl, 0, true);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret);
+		goto exit;
+	}
+
+	devInfo.dev_ctrl &= ~U1_DISABLE_DEV;
+	devInfo.dev_ctrl |= U1_TP_ABS_MODE;
+	ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+			NULL, devInfo.dev_ctrl, false);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X,
+			&devInfo.sen_line_num_x, 0, true);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y,
+			&devInfo.sen_line_num_y, 0, true);
+		if (ret < 0) {
+		dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X,
+			&devInfo.pitch_x, 0, true);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y,
+			&devInfo.pitch_y, 0, true);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS,
+		&devInfo.resolution, 0, true);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN,
+			&devInfo.btn_info, 0, true);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret);
+		goto exit;
+	}
+
+	/* Check StickPointer device */
+	ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP,
+			&devInfo.dev_type, 0, true);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret);
+		goto exit;
+	}
+
+	devInfo.x_active_len_mm =
+		(devInfo.pitch_x * (devInfo.sen_line_num_x - 1)) / 10;
+	devInfo.y_active_len_mm =
+		(devInfo.pitch_y * (devInfo.sen_line_num_y - 1)) / 10;
+
+	devInfo.x_max =
+		(devInfo.resolution << 2) * (devInfo.sen_line_num_x - 1);
+	devInfo.y_max =
+		(devInfo.resolution << 2) * (devInfo.sen_line_num_y - 1);
+
+	__set_bit(EV_ABS, input->evbit);
+	input_set_abs_params(input, ABS_MT_POSITION_X, 1, devInfo.x_max, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 1, devInfo.y_max, 0, 0);
+
+	if (devInfo.x_active_len_mm && devInfo.y_active_len_mm) {
+		res_x = (devInfo.x_max - 1) / devInfo.x_active_len_mm;
+		res_y = (devInfo.y_max - 1) / devInfo.y_active_len_mm;
+
+		input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
+		input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
+	}
+
+	input_set_abs_params(input, ABS_MT_PRESSURE, 0, 64, 0, 0);
+
+	input_mt_init_slots(input, MAX_TOUCHES, INPUT_MT_POINTER);
+
+	__set_bit(EV_KEY, input->evbit);
+	if ((devInfo.btn_info & 0x0F) == (devInfo.btn_info & 0xF0) >> 4) {
+		devInfo.btn_cnt = (devInfo.btn_info & 0x0F);
+	} else {
+		/* Button pad */
+		devInfo.btn_cnt = 1;
+		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+	}
+
+	for (i = 0; i < devInfo.btn_cnt; i++)
+		__set_bit(BTN_LEFT + i, input->keybit);
+
+
+	/* Stick device initialization */
+	if (devInfo.dev_type & U1_DEVTYPE_SP_SUPPORT) {
+
+		input2 = input_allocate_device();
+		if (!input2) {
+			input_free_device(input2);
+			goto exit;
+		}
+
+		data->input2 = input2;
+
+		devInfo.dev_ctrl |= U1_SP_ABS_MODE;
+		ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+			NULL, devInfo.dev_ctrl, false);
+		if (ret < 0) {
+			dev_err(&hdev->dev, "failed SP mode (%d)\n", ret);
+			input_free_device(input2);
+			goto exit;
+		}
+
+		ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN,
+			&devInfo.sp_btn_info, 0, true);
+		if (ret < 0) {
+			dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret);
+			input_free_device(input2);
+			goto exit;
+		}
+
+		input2->phys = input->phys;
+		input2->name = "DualPoint Stick";
+		input2->id.bustype = BUS_I2C;
+		input2->id.vendor  = input->id.vendor;
+		input2->id.product = input->id.product;
+		input2->id.version = input->id.version;
+		input2->dev.parent = input->dev.parent;
+
+		__set_bit(EV_KEY, input2->evbit);
+		devInfo.sp_btn_cnt = (devInfo.sp_btn_info & 0x0F);
+		for (i = 0; i < devInfo.sp_btn_cnt; i++)
+			__set_bit(BTN_LEFT + i, input2->keybit);
+
+		__set_bit(EV_REL, input2->evbit);
+		__set_bit(REL_X, input2->relbit);
+		__set_bit(REL_Y, input2->relbit);
+		__set_bit(INPUT_PROP_POINTER, input2->propbit);
+		__set_bit(INPUT_PROP_POINTING_STICK, input2->propbit);
+
+		if (input_register_device(data->input2)) {
+			input_free_device(input2);
+			goto exit;
+		}
+	}
+
+exit:
+	hid_device_io_stop(hdev);
+	hid_hw_close(hdev);
+	return ret;
+}
+
+static int alps_input_mapping(struct hid_device *hdev,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	return -1;
+}
+
+static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	struct u1_dev *data = NULL;
+	int ret;
+
+	data = devm_kzalloc(&hdev->dev, sizeof(struct u1_dev), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->hdev = hdev;
+	hid_set_drvdata(hdev, data);
+
+	hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		return ret;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void alps_remove(struct hid_device *hdev)
+{
+	hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id alps_id[] = {
+	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
+		USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, alps_id);
+
+static struct hid_driver alps_driver = {
+	.name = "hid-alps",
+	.id_table		= alps_id,
+	.probe			= alps_probe,
+	.remove			= alps_remove,
+	.raw_event		= alps_raw_event,
+	.input_mapping		= alps_input_mapping,
+	.input_configured	= alps_input_configured,
+#ifdef CONFIG_PM
+	.resume			= alps_post_resume,
+	.reset_resume		= alps_post_reset,
+#endif
+};
+
+module_hid_driver(alps_driver);
+
+MODULE_AUTHOR("Masaki Ota <masaki.ota@jp.alps.com>");
+MODULE_DESCRIPTION("ALPS HID driver");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/hid/hid-apple.c
+++ linux-4.4.0/drivers/hid/hid-apple.c
@@ -55,7 +55,6 @@
 struct apple_sc {
 	unsigned long quirks;
 	unsigned int fn_on;
-	DECLARE_BITMAP(pressed_fn, KEY_CNT);
 	DECLARE_BITMAP(pressed_numlock, KEY_CNT);
 };
 
@@ -182,6 +181,8 @@
 {
 	struct apple_sc *asc = hid_get_drvdata(hid);
 	const struct apple_key_translation *trans, *table;
+	bool do_translate;
+	u16 code = 0;
 
 	if (usage->code == KEY_FN) {
 		asc->fn_on = !!value;
@@ -190,8 +191,6 @@
 	}
 
 	if (fnmode) {
-		int do_translate;
-
 		if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
 				hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
 			table = macbookair_fn_keys;
@@ -203,25 +202,33 @@
 		trans = apple_find_translation (table, usage->code);
 
 		if (trans) {
-			if (test_bit(usage->code, asc->pressed_fn))
-				do_translate = 1;
-			else if (trans->flags & APPLE_FLAG_FKEY)
-				do_translate = (fnmode == 2 && asc->fn_on) ||
-					(fnmode == 1 && !asc->fn_on);
-			else
-				do_translate = asc->fn_on;
-
-			if (do_translate) {
-				if (value)
-					set_bit(usage->code, asc->pressed_fn);
-				else
-					clear_bit(usage->code, asc->pressed_fn);
-
-				input_event(input, usage->type, trans->to,
-						value);
+			if (test_bit(trans->from, input->key))
+				code = trans->from;
+			else if (test_bit(trans->to, input->key))
+				code = trans->to;
+
+			if (!code) {
+				if (trans->flags & APPLE_FLAG_FKEY) {
+					switch (fnmode) {
+					case 1:
+						do_translate = !asc->fn_on;
+						break;
+					case 2:
+						do_translate = asc->fn_on;
+						break;
+					default:
+						/* should never happen */
+						do_translate = false;
+					}
+				} else {
+					do_translate = asc->fn_on;
+				}
 
-				return 1;
+				code = do_translate ? trans->to : trans->from;
 			}
+
+			input_event(input, usage->type, code, value);
+			return 1;
 		}
 
 		if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
--- linux-4.4.0.orig/drivers/hid/hid-axff.c
+++ linux-4.4.0/drivers/hid/hid-axff.c
@@ -75,13 +75,20 @@
 {
 	struct axff_device *axff;
 	struct hid_report *report;
-	struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+	struct hid_input *hidinput;
 	struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct input_dev *dev = hidinput->input;
+	struct input_dev *dev;
 	int field_count = 0;
 	int i, j;
 	int error;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+	dev = hidinput->input;
+
 	if (list_empty(report_list)) {
 		hid_err(hid, "no output reports found\n");
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/hid/hid-chicony.c
+++ linux-4.4.0/drivers/hid/hid-chicony.c
@@ -61,8 +61,12 @@
 static __u8 *ch_switch12_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
-	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-	
+	struct usb_interface *intf;
+
+	if (!hid_is_usb(hdev))
+		return rdesc;
+
+	intf = to_usb_interface(hdev->dev.parent);
 	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
 		/* Change usage maximum and logical maximum from 0x7fff to
 		 * 0x2fff, so they don't exceed HID_MAX_USAGES */
@@ -86,6 +90,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_JESS_ZEN_AIO_KBD) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, ch_devices);
--- linux-4.4.0.orig/drivers/hid/hid-core.c
+++ linux-4.4.0/drivers/hid/hid-core.c
@@ -91,7 +91,7 @@
  * Register a new field for this report.
  */
 
-static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
+static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages)
 {
 	struct hid_field *field;
 
@@ -102,7 +102,7 @@
 
 	field = kzalloc((sizeof(struct hid_field) +
 			 usages * sizeof(struct hid_usage) +
-			 values * sizeof(unsigned)), GFP_KERNEL);
+			 usages * sizeof(unsigned)), GFP_KERNEL);
 	if (!field)
 		return NULL;
 
@@ -197,16 +197,37 @@
 }
 
 /*
+ * Concatenate usage which defines 16 bits or less with the
+ * currently defined usage page to form a 32 bit usage
+ */
+
+static void complete_usage(struct hid_parser *parser, unsigned int index)
+{
+	parser->local.usage[index] &= 0xFFFF;
+	parser->local.usage[index] |=
+		(parser->global.usage_page & 0xFFFF) << 16;
+}
+
+/*
  * Add a usage to the temporary parser table.
  */
 
-static int hid_add_usage(struct hid_parser *parser, unsigned usage)
+static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
 {
 	if (parser->local.usage_index >= HID_MAX_USAGES) {
 		hid_err(parser->device, "usage index exceeded\n");
 		return -1;
 	}
 	parser->local.usage[parser->local.usage_index] = usage;
+
+	/*
+	 * If Usage item only includes usage id, concatenate it with
+	 * currently defined usage page
+	 */
+	if (size <= 2)
+		complete_usage(parser, parser->local.usage_index);
+
+	parser->local.usage_size[parser->local.usage_index] = size;
 	parser->local.collection_index[parser->local.usage_index] =
 		parser->collection_stack_ptr ?
 		parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
@@ -248,13 +269,19 @@
 	offset = report->size;
 	report->size += parser->global.report_size * parser->global.report_count;
 
+	/* Total size check: Allow for possible report index byte */
+	if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) {
+		hid_err(parser->device, "report is too long\n");
+		return -1;
+	}
+
 	if (!parser->local.usage_index) /* Ignore padding fields */
 		return 0;
 
 	usages = max_t(unsigned, parser->local.usage_index,
 				 parser->global.report_count);
 
-	field = hid_register_field(report, usages, parser->global.report_count);
+	field = hid_register_field(report, usages);
 	if (!field)
 		return 0;
 
@@ -463,10 +490,7 @@
 			return 0;
 		}
 
-		if (item->size <= 2)
-			data = (parser->global.usage_page << 16) + data;
-
-		return hid_add_usage(parser, data);
+		return hid_add_usage(parser, data, item->size);
 
 	case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
 
@@ -475,9 +499,6 @@
 			return 0;
 		}
 
-		if (item->size <= 2)
-			data = (parser->global.usage_page << 16) + data;
-
 		parser->local.usage_minimum = data;
 		return 0;
 
@@ -488,9 +509,6 @@
 			return 0;
 		}
 
-		if (item->size <= 2)
-			data = (parser->global.usage_page << 16) + data;
-
 		count = data - parser->local.usage_minimum;
 		if (count + parser->local.usage_index >= HID_MAX_USAGES) {
 			/*
@@ -510,7 +528,7 @@
 		}
 
 		for (n = parser->local.usage_minimum; n <= data; n++)
-			if (hid_add_usage(parser, n)) {
+			if (hid_add_usage(parser, n, item->size)) {
 				dbg_hid("hid_add_usage failed\n");
 				return -1;
 			}
@@ -525,6 +543,41 @@
 }
 
 /*
+ * Concatenate Usage Pages into Usages where relevant:
+ * As per specification, 6.2.2.8: "When the parser encounters a main item it
+ * concatenates the last declared Usage Page with a Usage to form a complete
+ * usage value."
+ */
+
+static void hid_concatenate_last_usage_page(struct hid_parser *parser)
+{
+	int i;
+	unsigned int usage_page;
+	unsigned int current_page;
+
+	if (!parser->local.usage_index)
+		return;
+
+	usage_page = parser->global.usage_page;
+
+	/*
+	 * Concatenate usage page again only if last declared Usage Page
+	 * has not been already used in previous usages concatenation
+	 */
+	for (i = parser->local.usage_index - 1; i >= 0; i--) {
+		if (parser->local.usage_size[i] > 2)
+			/* Ignore extended usages */
+			continue;
+
+		current_page = parser->local.usage[i] >> 16;
+		if (current_page == usage_page)
+			break;
+
+		complete_usage(parser, i);
+	}
+}
+
+/*
  * Process a main item.
  */
 
@@ -533,6 +586,8 @@
 	__u32 data;
 	int ret;
 
+	hid_concatenate_last_usage_page(parser);
+
 	data = item_udata(item);
 
 	switch (item->tag) {
@@ -712,6 +767,10 @@
 	if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
 	    parser->global.report_size == 8)
 		parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
+
+	if (usage == 0xff0000c6 && parser->global.report_count == 1 &&
+	    parser->global.report_size == 8)
+		parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
 }
 
 static void hid_scan_collection(struct hid_parser *parser, unsigned type)
@@ -746,6 +805,8 @@
 	__u32 data;
 	int i;
 
+	hid_concatenate_last_usage_page(parser);
+
 	data = item_udata(item);
 
 	switch (item->tag) {
@@ -903,8 +964,8 @@
 		 * Validating on id 0 means we should examine the first
 		 * report in the list.
 		 */
-		report = list_entry(
-				hid->report_enum[type].report_list.next,
+		report = list_first_entry_or_null(
+				&hid->report_enum[type].report_list,
 				struct hid_report, list);
 	} else {
 		report = hid->report_enum[type].report_id_hash[id];
@@ -947,6 +1008,7 @@
 	__u8 *start;
 	__u8 *buf;
 	__u8 *end;
+	__u8 *next;
 	int ret;
 	static int (*dispatch_type[])(struct hid_parser *parser,
 				      struct hid_item *item) = {
@@ -1000,7 +1062,8 @@
 	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 
 	ret = -EINVAL;
-	while ((start = fetch_item(start, end, &item)) != NULL) {
+	while ((next = fetch_item(start, end, &item)) != NULL) {
+		start = next;
 
 		if (item.format != HID_ITEM_FORMAT_SHORT) {
 			hid_err(device, "unexpected long global item\n");
@@ -1029,7 +1092,8 @@
 		}
 	}
 
-	hid_err(device, "item fetching failed at offset %d\n", (int)(end - start));
+	hid_err(device, "item fetching failed at offset %u/%u\n",
+		size - (unsigned int)(end - start), size);
 err:
 	vfree(parser);
 	hid_close_report(device);
@@ -1045,6 +1109,9 @@
 
 static s32 snto32(__u32 value, unsigned n)
 {
+	if (!value || !n)
+		return 0;
+
 	switch (n) {
 	case 8:  return ((__s8)value);
 	case 16: return ((__s16)value);
@@ -1251,6 +1318,7 @@
 		/* Ignore report if ErrorRollOver */
 		if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
 		    value[n] >= min && value[n] <= max &&
+		    value[n] - min < field->maxusage &&
 		    field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
 			goto exit;
 	}
@@ -1263,11 +1331,13 @@
 		}
 
 		if (field->value[n] >= min && field->value[n] <= max
+			&& field->value[n] - min < field->maxusage
 			&& field->usage[field->value[n] - min].hid
 			&& search(value, field->value[n], count))
 				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
 
 		if (value[n] >= min && value[n] <= max
+			&& value[n] - min < field->maxusage
 			&& field->usage[value[n] - min].hid
 			&& search(field->value, value[n], count))
 				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
@@ -1301,6 +1371,17 @@
 }
 
 /*
+ * Compute the size of a report.
+ */
+static size_t hid_compute_report_size(struct hid_report *report)
+{
+	if (report->size)
+		return ((report->size - 1) >> 3) + 1;
+
+	return 0;
+}
+
+/*
  * Create a report. 'data' has to be allocated using
  * hid_alloc_report_buf() so that it has proper size.
  */
@@ -1312,7 +1393,7 @@
 	if (report->id > 0)
 		*data++ = report->id;
 
-	memset(data, 0, ((report->size - 1) >> 3) + 1);
+	memset(data, 0, hid_compute_report_size(report));
 	for (n = 0; n < report->maxfield; n++)
 		hid_output_field(report->device, report->field[n], data);
 }
@@ -1328,9 +1409,9 @@
 	 * of implement() working on 8 byte chunks
 	 */
 
-	int len = hid_report_len(report) + 7;
+	u32 len = hid_report_len(report) + 7;
 
-	return kmalloc(len, flags);
+	return kzalloc(len, flags);
 }
 EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
 
@@ -1393,7 +1474,7 @@
 {
 	char *buf;
 	int ret;
-	int len;
+	u32 len;
 
 	buf = hid_alloc_report_buf(report, GFP_KERNEL);
 	if (!buf)
@@ -1419,14 +1500,14 @@
 }
 EXPORT_SYMBOL_GPL(__hid_request);
 
-int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
 		int interrupt)
 {
 	struct hid_report_enum *report_enum = hid->report_enum + type;
 	struct hid_report *report;
 	struct hid_driver *hdrv;
 	unsigned int a;
-	int rsize, csize = size;
+	u32 rsize, csize = size;
 	u8 *cdata = data;
 	int ret = 0;
 
@@ -1439,9 +1520,11 @@
 		csize--;
 	}
 
-	rsize = ((report->size - 1) >> 3) + 1;
+	rsize = hid_compute_report_size(report);
 
-	if (rsize > HID_MAX_BUFFER_SIZE)
+	if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
+		rsize = HID_MAX_BUFFER_SIZE - 1;
+	else if (rsize > HID_MAX_BUFFER_SIZE)
 		rsize = HID_MAX_BUFFER_SIZE;
 
 	if (csize < rsize) {
@@ -1484,7 +1567,7 @@
  *
  * This is data entry for lower layers.
  */
-int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt)
 {
 	struct hid_report_enum *report_enum;
 	struct hid_driver *hdrv;
@@ -1736,6 +1819,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) },
+	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
@@ -1864,6 +1948,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_JESS_ZEN_AIO_KBD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
@@ -1897,6 +1982,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
@@ -2006,6 +2092,9 @@
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
@@ -2048,6 +2137,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_THT_2P_ARCADE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
@@ -2302,7 +2392,6 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
 	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
-	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
@@ -2381,6 +2470,9 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
@@ -2423,6 +2515,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PETZL, USB_DEVICE_ID_PETZL_HEADLAMP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
 #if defined(CONFIG_MOUSE_SYNAPTICS_USB) || defined(CONFIG_MOUSE_SYNAPTICS_USB_MODULE)
@@ -2571,6 +2664,17 @@
 			strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
 			return true;
 		break;
+	case USB_VENDOR_ID_ELAN:
+		/*
+		 * Many Elan devices have a product id of 0x0401 and are handled
+		 * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
+		 * is not (and cannot be) handled by that driver ->
+		 * Ignore all 0x0401 devs except for the ELAN0800 dev.
+		 */
+		if (hdev->product == 0x0401 &&
+		    strncmp(hdev->name, "ELAN0800", 8) != 0)
+			return true;
+		break;
 	}
 
 	if (hdev->type == HID_TYPE_USBMOUSE &&
@@ -2615,9 +2719,10 @@
 	/*
 	 * Scan generic devices for group information
 	 */
-	if (hid_ignore_special_drivers ||
-	    (!hdev->group &&
-	     !hid_match_id(hdev, hid_have_special_driver))) {
+	if (hid_ignore_special_drivers) {
+		hdev->group = HID_GROUP_GENERIC;
+	} else if (!hdev->group &&
+		   !hid_match_id(hdev, hid_have_special_driver)) {
 		ret = hid_scan_report(hdev);
 		if (ret)
 			hid_warn(hdev, "bad device descriptor (%d)\n", ret);
--- linux-4.4.0.orig/drivers/hid/hid-corsair.c
+++ linux-4.4.0/drivers/hid/hid-corsair.c
@@ -148,26 +148,36 @@
 	struct usb_interface *usbif = to_usb_interface(dev->parent);
 	struct usb_device *usbdev = interface_to_usbdev(usbif);
 	int brightness;
-	char data[8];
+	char *data;
+
+	data = kmalloc(8, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
 			      K90_REQUEST_STATUS,
 			      USB_DIR_IN | USB_TYPE_VENDOR |
 			      USB_RECIP_DEVICE, 0, 0, data, 8,
 			      USB_CTRL_SET_TIMEOUT);
-	if (ret < 0) {
+	if (ret < 5) {
 		dev_warn(dev, "Failed to get K90 initial state (error %d).\n",
 			 ret);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 	brightness = data[4];
 	if (brightness < 0 || brightness > 3) {
 		dev_warn(dev,
 			 "Read invalid backlight brightness: %02hhx.\n",
 			 data[4]);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
-	return brightness;
+	ret = brightness;
+out:
+	kfree(data);
+
+	return ret;
 }
 
 static enum led_brightness k90_record_led_get(struct led_classdev *led_cdev)
@@ -253,17 +263,22 @@
 	struct usb_interface *usbif = to_usb_interface(dev->parent);
 	struct usb_device *usbdev = interface_to_usbdev(usbif);
 	const char *macro_mode;
-	char data[8];
+	char *data;
+
+	data = kmalloc(2, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
 			      K90_REQUEST_GET_MODE,
 			      USB_DIR_IN | USB_TYPE_VENDOR |
 			      USB_RECIP_DEVICE, 0, 0, data, 2,
 			      USB_CTRL_SET_TIMEOUT);
-	if (ret < 0) {
+	if (ret < 1) {
 		dev_warn(dev, "Failed to get K90 initial mode (error %d).\n",
 			 ret);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 
 	switch (data[0]) {
@@ -277,10 +292,15 @@
 	default:
 		dev_warn(dev, "K90 in unknown mode: %02hhx.\n",
 			 data[0]);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 
-	return snprintf(buf, PAGE_SIZE, "%s\n", macro_mode);
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", macro_mode);
+out:
+	kfree(data);
+
+	return ret;
 }
 
 static ssize_t k90_store_macro_mode(struct device *dev,
@@ -320,26 +340,36 @@
 	struct usb_interface *usbif = to_usb_interface(dev->parent);
 	struct usb_device *usbdev = interface_to_usbdev(usbif);
 	int current_profile;
-	char data[8];
+	char *data;
+
+	data = kmalloc(8, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
 			      K90_REQUEST_STATUS,
 			      USB_DIR_IN | USB_TYPE_VENDOR |
 			      USB_RECIP_DEVICE, 0, 0, data, 8,
 			      USB_CTRL_SET_TIMEOUT);
-	if (ret < 0) {
+	if (ret < 8) {
 		dev_warn(dev, "Failed to get K90 initial state (error %d).\n",
 			 ret);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 	current_profile = data[7];
 	if (current_profile < 1 || current_profile > 3) {
 		dev_warn(dev, "Read invalid current profile: %02hhx.\n",
 			 data[7]);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", current_profile);
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", current_profile);
+out:
+	kfree(data);
+
+	return ret;
 }
 
 static ssize_t k90_store_current_profile(struct device *dev,
@@ -521,7 +551,12 @@
 	int ret;
 	unsigned long quirks = id->driver_data;
 	struct corsair_drvdata *drvdata;
-	struct usb_interface *usbif = to_usb_interface(dev->dev.parent);
+	struct usb_interface *usbif;
+
+	if (!hid_is_usb(dev))
+		return -EINVAL;
+
+	usbif = to_usb_interface(dev->dev.parent);
 
 	drvdata = devm_kzalloc(&dev->dev, sizeof(struct corsair_drvdata),
 			       GFP_KERNEL);
--- linux-4.4.0.orig/drivers/hid/hid-cypress.c
+++ linux-4.4.0/drivers/hid/hid-cypress.c
@@ -26,17 +26,18 @@
 #define CP_2WHEEL_MOUSE_HACK		0x02
 #define CP_2WHEEL_MOUSE_HACK_ON		0x04
 
+#define VA_INVAL_LOGICAL_BOUNDARY	0x08
+
 /*
  * Some USB barcode readers from cypress have usage min and usage max in
  * the wrong order
  */
-static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+static __u8 *cp_rdesc_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
-	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 	unsigned int i;
 
-	if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
+	if (*rsize < 4)
 		return rdesc;
 
 	for (i = 0; i < *rsize - 4; i++)
@@ -48,6 +49,40 @@
 	return rdesc;
 }
 
+static __u8 *va_logical_boundary_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
+{
+	/*
+	 * Varmilo VA104M (with VID Cypress and device ID 07B1) incorrectly
+	 * reports Logical Minimum of its Consumer Control device as 572
+	 * (0x02 0x3c). Fix this by setting its Logical Minimum to zero.
+	 */
+	if (*rsize == 25 &&
+			rdesc[0] == 0x05 && rdesc[1] == 0x0c &&
+			rdesc[2] == 0x09 && rdesc[3] == 0x01 &&
+			rdesc[6] == 0x19 && rdesc[7] == 0x00 &&
+			rdesc[11] == 0x16 && rdesc[12] == 0x3c && rdesc[13] == 0x02) {
+		hid_info(hdev,
+			 "fixing up varmilo VA104M consumer control report descriptor\n");
+		rdesc[12] = 0x00;
+		rdesc[13] = 0x00;
+	}
+	return rdesc;
+}
+
+static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if (quirks & CP_RDESC_SWAPPED_MIN_MAX)
+		rdesc = cp_rdesc_fixup(hdev, rdesc, rsize);
+	if (quirks & VA_INVAL_LOGICAL_BOUNDARY)
+		rdesc = va_logical_boundary_fixup(hdev, rdesc, rsize);
+
+	return rdesc;
+}
+
 static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
@@ -128,6 +163,8 @@
 		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
 		.driver_data = CP_2WHEEL_MOUSE_HACK },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1),
+		.driver_data = VA_INVAL_LOGICAL_BOUNDARY },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, cp_devices);
--- linux-4.4.0.orig/drivers/hid/hid-debug.c
+++ linux-4.4.0/drivers/hid/hid-debug.c
@@ -30,6 +30,7 @@
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/kfifo.h>
 #include <linux/sched.h>
 #include <linux/export.h>
 #include <linux/slab.h>
@@ -455,7 +456,7 @@
 	char *buf = NULL;
 
 	if (!f) {
-		buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
+		buf = kzalloc(HID_DEBUG_BUFSIZE, GFP_ATOMIC);
 		if (!buf)
 			return ERR_PTR(-ENOMEM);
 	}
@@ -659,17 +660,12 @@
 /* enqueue string to 'events' ring buffer */
 void hid_debug_event(struct hid_device *hdev, char *buf)
 {
-	int i;
 	struct hid_debug_list *list;
 	unsigned long flags;
 
 	spin_lock_irqsave(&hdev->debug_list_lock, flags);
-	list_for_each_entry(list, &hdev->debug_list, node) {
-		for (i = 0; i < strlen(buf); i++)
-			list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
-				buf[i];
-		list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
-        }
+	list_for_each_entry(list, &hdev->debug_list, node)
+		kfifo_in(&list->hid_debug_fifo, buf, strlen(buf));
 	spin_unlock_irqrestore(&hdev->debug_list_lock, flags);
 
 	wake_up_interruptible(&hdev->debug_wait);
@@ -720,8 +716,7 @@
 	hid_debug_event(hdev, buf);
 
 	kfree(buf);
-        wake_up_interruptible(&hdev->debug_wait);
-
+	wake_up_interruptible(&hdev->debug_wait);
 }
 EXPORT_SYMBOL_GPL(hid_dump_input);
 
@@ -1063,10 +1058,15 @@
 	seq_printf(f, "\n\n");
 
 	/* dump parsed data and input mappings */
+	if (down_interruptible(&hdev->driver_input_lock))
+		return 0;
+
 	hid_dump_device(hdev, f);
 	seq_printf(f, "\n");
 	hid_dump_input_mapping(hdev, f);
 
+	up(&hdev->driver_input_lock);
+
 	return 0;
 }
 
@@ -1086,8 +1086,8 @@
 		goto out;
 	}
 
-	if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) {
-		err = -ENOMEM;
+	err = kfifo_alloc(&list->hid_debug_fifo, HID_DEBUG_FIFOSIZE, GFP_KERNEL);
+	if (err) {
 		kfree(list);
 		goto out;
 	}
@@ -1107,71 +1107,57 @@
 		size_t count, loff_t *ppos)
 {
 	struct hid_debug_list *list = file->private_data;
-	int ret = 0, len;
+	int ret = 0, copied;
 	DECLARE_WAITQUEUE(wait, current);
 
 	mutex_lock(&list->read_mutex);
-	while (ret == 0) {
-		if (list->head == list->tail) {
-			add_wait_queue(&list->hdev->debug_wait, &wait);
-			set_current_state(TASK_INTERRUPTIBLE);
-
-			while (list->head == list->tail) {
-				if (file->f_flags & O_NONBLOCK) {
-					ret = -EAGAIN;
-					break;
-				}
-				if (signal_pending(current)) {
-					ret = -ERESTARTSYS;
-					break;
-				}
-
-				if (!list->hdev || !list->hdev->debug) {
-					ret = -EIO;
-					set_current_state(TASK_RUNNING);
-					goto out;
-				}
-
-				/* allow O_NONBLOCK from other threads */
-				mutex_unlock(&list->read_mutex);
-				schedule();
-				mutex_lock(&list->read_mutex);
-				set_current_state(TASK_INTERRUPTIBLE);
+	if (kfifo_is_empty(&list->hid_debug_fifo)) {
+		add_wait_queue(&list->hdev->debug_wait, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		while (kfifo_is_empty(&list->hid_debug_fifo)) {
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				break;
 			}
 
-			set_current_state(TASK_RUNNING);
-			remove_wait_queue(&list->hdev->debug_wait, &wait);
-		}
-
-		if (ret)
-			goto out;
-
-		/* pass the ringbuffer contents to userspace */
-copy_rest:
-		if (list->tail == list->head)
-			goto out;
-		if (list->tail > list->head) {
-			len = list->tail - list->head;
-
-			if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) {
-				ret = -EFAULT;
-				goto out;
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
 			}
-			ret += len;
-			list->head += len;
-		} else {
-			len = HID_DEBUG_BUFSIZE - list->head;
 
-			if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) {
-				ret = -EFAULT;
+			/* if list->hdev is NULL we cannot remove_wait_queue().
+			 * if list->hdev->debug is 0 then hid_debug_unregister()
+			 * was already called and list->hdev is being destroyed.
+			 * if we add remove_wait_queue() here we can hit a race.
+			 */
+			if (!list->hdev || !list->hdev->debug) {
+				ret = -EIO;
+				set_current_state(TASK_RUNNING);
 				goto out;
 			}
-			list->head = 0;
-			ret += len;
-			goto copy_rest;
+
+			/* allow O_NONBLOCK from other threads */
+			mutex_unlock(&list->read_mutex);
+			schedule();
+			mutex_lock(&list->read_mutex);
+			set_current_state(TASK_INTERRUPTIBLE);
 		}
 
+		__set_current_state(TASK_RUNNING);
+		remove_wait_queue(&list->hdev->debug_wait, &wait);
+
+		if (ret)
+			goto out;
 	}
+
+	/* pass the fifo content to userspace, locking is not needed with only
+	 * one concurrent reader and one concurrent writer
+	 */
+	ret = kfifo_to_user(&list->hid_debug_fifo, buffer, count, &copied);
+	if (ret)
+		goto out;
+	ret = copied;
 out:
 	mutex_unlock(&list->read_mutex);
 	return ret;
@@ -1182,7 +1168,7 @@
 	struct hid_debug_list *list = file->private_data;
 
 	poll_wait(file, &list->hdev->debug_wait, wait);
-	if (list->head != list->tail)
+	if (!kfifo_is_empty(&list->hid_debug_fifo))
 		return POLLIN | POLLRDNORM;
 	if (!list->hdev->debug)
 		return POLLERR | POLLHUP;
@@ -1197,7 +1183,7 @@
 	spin_lock_irqsave(&list->hdev->debug_list_lock, flags);
 	list_del(&list->node);
 	spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags);
-	kfree(list->hid_debug_buf);
+	kfifo_free(&list->hid_debug_fifo);
 	kfree(list);
 
 	return 0;
@@ -1248,4 +1234,3 @@
 {
 	debugfs_remove_recursive(hid_debug_root);
 }
-
--- linux-4.4.0.orig/drivers/hid/hid-dr.c
+++ linux-4.4.0/drivers/hid/hid-dr.c
@@ -87,13 +87,19 @@
 {
 	struct drff_device *drff;
 	struct hid_report *report;
-	struct hid_input *hidinput = list_first_entry(&hid->inputs,
-						struct hid_input, list);
+	struct hid_input *hidinput;
 	struct list_head *report_list =
 			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct input_dev *dev = hidinput->input;
+	struct input_dev *dev;
 	int error;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+	dev = hidinput->input;
+
 	if (list_empty(report_list)) {
 		hid_err(hid, "no output reports found\n");
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/hid/hid-elo.c
+++ linux-4.4.0/drivers/hid/hid-elo.c
@@ -42,6 +42,12 @@
 {
 	struct input_dev *input = hidinput->input;
 
+	/*
+	 * ELO devices have one Button usage in GenDesk field, which makes
+	 * hid-input map it to BTN_LEFT; that confuses userspace, which then
+	 * considers the device to be a mouse/touchpad instead of touchscreen.
+	 */
+	clear_bit(BTN_LEFT, input->keybit);
 	set_bit(BTN_TOUCH, input->keybit);
 	set_bit(ABS_PRESSURE, input->absbit);
 	input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
@@ -224,6 +230,9 @@
 	struct elo_priv *priv;
 	int ret;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
@@ -261,7 +270,7 @@
 	struct elo_priv *priv = hid_get_drvdata(hdev);
 
 	hid_hw_stop(hdev);
-	flush_workqueue(wq);
+	cancel_delayed_work_sync(&priv->work);
 	kfree(priv);
 }
 
--- linux-4.4.0.orig/drivers/hid/hid-emsff.c
+++ linux-4.4.0/drivers/hid/hid-emsff.c
@@ -59,13 +59,19 @@
 {
 	struct emsff_device *emsff;
 	struct hid_report *report;
-	struct hid_input *hidinput = list_first_entry(&hid->inputs,
-						struct hid_input, list);
+	struct hid_input *hidinput;
 	struct list_head *report_list =
 			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct input_dev *dev = hidinput->input;
+	struct input_dev *dev;
 	int error;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+	dev = hidinput->input;
+
 	if (list_empty(report_list)) {
 		hid_err(hid, "no output reports found\n");
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/hid/hid-gaff.c
+++ linux-4.4.0/drivers/hid/hid-gaff.c
@@ -77,14 +77,20 @@
 {
 	struct gaff_device *gaff;
 	struct hid_report *report;
-	struct hid_input *hidinput = list_entry(hid->inputs.next,
-						struct hid_input, list);
+	struct hid_input *hidinput;
 	struct list_head *report_list =
 			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct list_head *report_ptr = report_list;
-	struct input_dev *dev = hidinput->input;
+	struct input_dev *dev;
 	int error;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	dev = hidinput->input;
+
 	if (list_empty(report_list)) {
 		hid_err(hid, "no output reports found\n");
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/hid/hid-holtek-kbd.c
+++ linux-4.4.0/drivers/hid/hid-holtek-kbd.c
@@ -126,9 +126,14 @@
 
 	/* Locate the boot interface, to receive the LED change events */
 	struct usb_interface *boot_interface = usb_ifnum_to_if(usb_dev, 0);
+	struct hid_device *boot_hid;
+	struct hid_input *boot_hid_input;
 
-	struct hid_device *boot_hid = usb_get_intfdata(boot_interface);
-	struct hid_input *boot_hid_input = list_first_entry(&boot_hid->inputs,
+	if (unlikely(boot_interface == NULL))
+		return -ENODEV;
+
+	boot_hid = usb_get_intfdata(boot_interface);
+	boot_hid_input = list_first_entry(&boot_hid->inputs,
 		struct hid_input, list);
 
 	return boot_hid_input->input->event(boot_hid_input->input, type, code,
@@ -138,12 +143,17 @@
 static int holtek_kbd_probe(struct hid_device *hdev,
 		const struct hid_device_id *id)
 {
-	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-	int ret = hid_parse(hdev);
+	struct usb_interface *intf;
+	int ret;
+
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
 
+	ret = hid_parse(hdev);
 	if (!ret)
 		ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 
+	intf = to_usb_interface(hdev->dev.parent);
 	if (!ret && intf->cur_altsetting->desc.bInterfaceNumber == 1) {
 		struct hid_input *hidinput;
 		list_for_each_entry(hidinput, &hdev->inputs, list) {
--- linux-4.4.0.orig/drivers/hid/hid-holtek-mouse.c
+++ linux-4.4.0/drivers/hid/hid-holtek-mouse.c
@@ -65,6 +65,29 @@
 	return rdesc;
 }
 
+static int holtek_mouse_probe(struct hid_device *hdev,
+			      const struct hid_device_id *id)
+{
+	int ret;
+
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "hid parse failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hw start failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static const struct hid_device_id holtek_mouse_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
 			USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
@@ -86,6 +109,7 @@
 	.name = "holtek_mouse",
 	.id_table = holtek_mouse_devices,
 	.report_fixup = holtek_mouse_report_fixup,
+	.probe = holtek_mouse_probe,
 };
 
 module_hid_driver(holtek_mouse_driver);
--- linux-4.4.0.orig/drivers/hid/hid-holtekff.c
+++ linux-4.4.0/drivers/hid/hid-holtekff.c
@@ -140,13 +140,19 @@
 {
 	struct holtekff_device *holtekff;
 	struct hid_report *report;
-	struct hid_input *hidinput = list_entry(hid->inputs.next,
-						struct hid_input, list);
+	struct hid_input *hidinput;
 	struct list_head *report_list =
 			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct input_dev *dev = hidinput->input;
+	struct input_dev *dev;
 	int error;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	dev = hidinput->input;
+
 	if (list_empty(report_list)) {
 		hid_err(hid, "no output report found\n");
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/hid/hid-ids.h
+++ linux-4.4.0/drivers/hid/hid-ids.h
@@ -67,6 +67,14 @@
 #define USB_VENDOR_ID_ALPS		0x0433
 #define USB_DEVICE_ID_IBM_GAMEPAD	0x1101
 
+#define USB_VENDOR_ID_ALPS_JP		0x044E
+#define HID_DEVICE_ID_ALPS_U1_DUAL	0x120B
+#define HID_DEVICE_ID_ALPS_U1_DUAL_PTP	0x121F
+#define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP	0x1220
+
+#define USB_VENDOR_ID_AMI		0x046b
+#define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE	0xff10
+
 #define USB_VENDOR_ID_ANTON		0x1130
 #define USB_DEVICE_ID_ANTON_TOUCH_PAD	0x3101
 
@@ -168,6 +176,7 @@
 #define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
 #define USB_DEVICE_ID_ATEN_4PORTKVMC	0x2208
 #define USB_DEVICE_ID_ATEN_CS682	0x2213
+#define USB_DEVICE_ID_ATEN_CS692	0x8021
 
 #define USB_VENDOR_ID_ATMEL		0x03eb
 #define USB_DEVICE_ID_ATMEL_MULTITOUCH	0x211c
@@ -255,6 +264,7 @@
 #define USB_DEVICE_ID_CORSAIR_K90	0x1b02
 
 #define USB_VENDOR_ID_CREATIVELABS	0x041e
+#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51	0x322c
 #define USB_DEVICE_ID_PRODIKEYS_PCMIDI	0x2801
 
 #define USB_VENDOR_ID_CVTOUCH		0x1ff7
@@ -277,12 +287,17 @@
 #define USB_DEVICE_ID_CYPRESS_BARCODE_4	0xed81
 #define USB_DEVICE_ID_CYPRESS_TRUETOUCH	0xc001
 
+#define USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1   0X07b1
+
 #define USB_VENDOR_ID_DATA_MODUL	0x7374
 #define USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH	0x1201
 
 #define USB_VENDOR_ID_DEALEXTREAME	0x10c5
 #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701	0x819a
 
+#define USB_VENDOR_ID_DELL				0x413c
+#define USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE	0x301a
+
 #define USB_VENDOR_ID_DELORME		0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE	0x0100
 #define USB_DEVICE_ID_DELORME_EM_LT20	0x0200
@@ -314,6 +329,7 @@
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349	0x7349
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7	0x73f7
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001	0xa001
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002	0xc002
 
 #define USB_VENDOR_ID_ELAN		0x04f3
 
@@ -465,6 +481,7 @@
 #define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A	0x0a4a
 #define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A	0x0b4a
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE		0x134a
+#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641	0x0641
 
 #define USB_VENDOR_ID_HUION		0x256c
 #define USB_DEVICE_ID_HUION_TABLET	0x006e
@@ -507,6 +524,9 @@
 #define USB_VENDOR_ID_IRTOUCHSYSTEMS	0x6615
 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB	0x0070
 
+#define USB_VENDOR_ID_INNOMEDIA			0x1292
+#define USB_DEVICE_ID_INNEX_GENESIS_ATARI	0x4745
+
 #define USB_VENDOR_ID_ITE               0x048d
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA   0x8386
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA2  0x8350
@@ -518,6 +538,7 @@
 
 #define USB_VENDOR_ID_JESS		0x0c45
 #define USB_DEVICE_ID_JESS_YUREX	0x1010
+#define USB_DEVICE_ID_JESS_ZEN_AIO_KBD	0x5112
 
 #define USB_VENDOR_ID_JESS2		0x0f30
 #define USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD 0x0111
@@ -564,6 +585,9 @@
 #define USB_DEVICE_ID_LD_MICROCASSYTIME		0x1033
 #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE	0x1035
 #define USB_DEVICE_ID_LD_MICROCASSYPH		0x1038
+#define USB_DEVICE_ID_LD_POWERANALYSERCASSY	0x1040
+#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY	0x1042
+#define USB_DEVICE_ID_LD_MACHINETESTCASSY	0x1043
 #define USB_DEVICE_ID_LD_JWM		0x1080
 #define USB_DEVICE_ID_LD_DMMP		0x1081
 #define USB_DEVICE_ID_LD_UMIP		0x1090
@@ -772,6 +796,9 @@
 #define USB_VENDOR_ID_PETALYNX		0x18b1
 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE	0x0037
 
+#define USB_VENDOR_ID_PETZL		0x2122
+#define USB_DEVICE_ID_PETZL_HEADLAMP	0x1234
+
 #define USB_VENDOR_ID_PHILIPS		0x0471
 #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
 
@@ -864,6 +891,8 @@
 #define USB_DEVICE_ID_SONY_PS3_BDREMOTE		0x0306
 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
 #define USB_DEVICE_ID_SONY_PS4_CONTROLLER	0x05c4
+#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2	0x09cc
+#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE	0x0ba0
 #define USB_DEVICE_ID_SONY_MOTION_CONTROLLER	0x03d5
 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER	0x042f
 #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER		0x0002
@@ -1012,6 +1041,7 @@
 
 #define USB_VENDOR_ID_XIN_MO			0x16c0
 #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE	0x05e1
+#define USB_DEVICE_ID_THT_2P_ARCADE		0x75e1
 
 #define USB_VENDOR_ID_XIROKU		0x1477
 #define USB_DEVICE_ID_XIROKU_SPX	0x1006
--- linux-4.4.0.orig/drivers/hid/hid-input.c
+++ linux-4.4.0/drivers/hid/hid-input.c
@@ -783,6 +783,10 @@
 		case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX);		break;
 		case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO);		break;
 
+		case 0x079: map_key_clear(KEY_KBDILLUMUP);	break;
+		case 0x07a: map_key_clear(KEY_KBDILLUMDOWN);	break;
+		case 0x07c: map_key_clear(KEY_KBDILLUMTOGGLE);	break;
+
 		case 0x082: map_key_clear(KEY_VIDEO_NEXT);	break;
 		case 0x083: map_key_clear(KEY_LAST);		break;
 		case 0x084: map_key_clear(KEY_ENTER);		break;
@@ -913,6 +917,8 @@
 		case 0x2cb: map_key_clear(KEY_KBDINPUTASSIST_ACCEPT);	break;
 		case 0x2cc: map_key_clear(KEY_KBDINPUTASSIST_CANCEL);	break;
 
+		case 0x29f: map_key_clear(KEY_SCALE);		break;
+
 		default: map_key_clear(KEY_UNKNOWN);
 		}
 		break;
@@ -946,6 +952,7 @@
 	case HID_UP_HPVENDOR2:
 		set_bit(EV_REP, input->evbit);
 		switch (usage->hid & HID_USAGE) {
+		case 0x001: map_key_clear(KEY_MICMUTE);		break;
 		case 0x003: map_key_clear(KEY_BRIGHTNESSDOWN);	break;
 		case 0x004: map_key_clear(KEY_BRIGHTNESSUP);	break;
 		default:    goto ignore;
@@ -988,9 +995,19 @@
 	}
 
 mapped:
-	if (device->driver->input_mapped && device->driver->input_mapped(device,
-				hidinput, field, usage, &bit, &max) < 0)
-		goto ignore;
+	/* Mapping failed, bail out */
+	if (!bit)
+		return;
+
+	if (device->driver->input_mapped &&
+	    device->driver->input_mapped(device, hidinput, field, usage,
+					 &bit, &max) < 0) {
+		/*
+		 * The driver indicated that no further generic handling
+		 * of the usage is desired.
+		 */
+		return;
+	}
 
 	set_bit(usage->type, input->evbit);
 
@@ -1049,9 +1066,11 @@
 		set_bit(MSC_SCAN, input->mscbit);
 	}
 
-ignore:
 	return;
 
+ignore:
+	usage->type = 0;
+	usage->code = 0;
 }
 
 void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
@@ -1128,18 +1147,26 @@
 
 	/*
 	 * Ignore out-of-range values as per HID specification,
-	 * section 5.10 and 6.2.25.
+	 * section 5.10 and 6.2.25, when NULL state bit is present.
+	 * When it's not, clamp the value to match Microsoft's input
+	 * driver as mentioned in "Required HID usages for digitizers":
+	 * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp
 	 *
 	 * The logical_minimum < logical_maximum check is done so that we
 	 * don't unintentionally discard values sent by devices which
 	 * don't specify logical min and max.
 	 */
 	if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
-	    (field->logical_minimum < field->logical_maximum) &&
-	    (value < field->logical_minimum ||
-	     value > field->logical_maximum)) {
-		dbg_hid("Ignoring out-of-range value %x\n", value);
-		return;
+	    (field->logical_minimum < field->logical_maximum)) {
+		if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
+		    (value < field->logical_minimum ||
+		     value > field->logical_maximum)) {
+			dbg_hid("Ignoring out-of-range value %x\n", value);
+			return;
+		}
+		value = clamp(value,
+			      field->logical_minimum,
+			      field->logical_maximum);
 	}
 
 	/*
@@ -1250,7 +1277,8 @@
 					      led_work);
 	struct hid_field *field;
 	struct hid_report *report;
-	int len, ret;
+	int ret;
+	u32 len;
 	__u8 *buf;
 
 	field = hidinput_get_led_field(hid);
--- linux-4.4.0.orig/drivers/hid/hid-lenovo.c
+++ linux-4.4.0/drivers/hid/hid-lenovo.c
@@ -703,7 +703,9 @@
 	data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd;
 	data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd;
 	data_pointer->led_mute.dev = dev;
-	led_classdev_register(dev, &data_pointer->led_mute);
+	ret = led_classdev_register(dev, &data_pointer->led_mute);
+	if (ret < 0)
+		goto err;
 
 	data_pointer->led_micmute.name = name_micmute;
 	data_pointer->led_micmute.brightness_get =
@@ -711,7 +713,11 @@
 	data_pointer->led_micmute.brightness_set =
 		lenovo_led_brightness_set_tpkbd;
 	data_pointer->led_micmute.dev = dev;
-	led_classdev_register(dev, &data_pointer->led_micmute);
+	ret = led_classdev_register(dev, &data_pointer->led_micmute);
+	if (ret < 0) {
+		led_classdev_unregister(&data_pointer->led_mute);
+		goto err;
+	}
 
 	lenovo_features_set_tpkbd(hdev);
 
--- linux-4.4.0.orig/drivers/hid/hid-lg.c
+++ linux-4.4.0/drivers/hid/hid-lg.c
@@ -659,12 +659,18 @@
 
 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
-	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
-	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+	struct usb_interface *iface;
+	__u8 iface_num;
 	unsigned int connect_mask = HID_CONNECT_DEFAULT;
 	struct lg_drv_data *drv_data;
 	int ret;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
+	iface = to_usb_interface(hdev->dev.parent);
+	iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
 	/* G29 only work with the 1st interface */
 	if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
 	    (iface_num != 0)) {
@@ -701,11 +707,16 @@
 
 	/* Setup wireless link with Logitech Wii wheel */
 	if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
-		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+		const unsigned char cbuf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+		u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
 
-		ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
-					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+		if (!buf) {
+			ret = -ENOMEM;
+			goto err_stop;
+		}
 
+		ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
+					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 		if (ret >= 0) {
 			/* insert a little delay of 10 jiffies ~ 40ms */
 			wait_queue_head_t wait;
@@ -717,9 +728,10 @@
 			buf[1] = 0xB2;
 			get_random_bytes(&buf[2], 2);
 
-			ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+			ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
 					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 		}
+		kfree(buf);
 	}
 
 	if (drv_data->quirks & LG_FF)
@@ -732,9 +744,12 @@
 		ret = lg4ff_init(hdev);
 
 	if (ret)
-		goto err_free;
+		goto err_stop;
 
 	return 0;
+
+err_stop:
+	hid_hw_stop(hdev);
 err_free:
 	kfree(drv_data);
 	return ret;
@@ -745,8 +760,7 @@
 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 	if (drv_data->quirks & LG_FF4)
 		lg4ff_deinit(hdev);
-	else
-		hid_hw_stop(hdev);
+	hid_hw_stop(hdev);
 	kfree(drv_data);
 }
 
--- linux-4.4.0.orig/drivers/hid/hid-lg2ff.c
+++ linux-4.4.0/drivers/hid/hid-lg2ff.c
@@ -62,11 +62,17 @@
 {
 	struct lg2ff_device *lg2ff;
 	struct hid_report *report;
-	struct hid_input *hidinput = list_entry(hid->inputs.next,
-						struct hid_input, list);
-	struct input_dev *dev = hidinput->input;
+	struct hid_input *hidinput;
+	struct input_dev *dev;
 	int error;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	dev = hidinput->input;
+
 	/* Check that the report looks ok */
 	report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
 	if (!report)
--- linux-4.4.0.orig/drivers/hid/hid-lg3ff.c
+++ linux-4.4.0/drivers/hid/hid-lg3ff.c
@@ -129,12 +129,19 @@
 
 int lg3ff_init(struct hid_device *hid)
 {
-	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-	struct input_dev *dev = hidinput->input;
+	struct hid_input *hidinput;
+	struct input_dev *dev;
 	const signed short *ff_bits = ff3_joystick_ac;
 	int error;
 	int i;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	dev = hidinput->input;
+
 	/* Check that the report looks ok */
 	if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35))
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/hid/hid-lg4ff.c
+++ linux-4.4.0/drivers/hid/hid-lg4ff.c
@@ -1158,8 +1158,8 @@
 
 int lg4ff_init(struct hid_device *hid)
 {
-	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-	struct input_dev *dev = hidinput->input;
+	struct hid_input *hidinput;
+	struct input_dev *dev;
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
 	const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor);
@@ -1171,6 +1171,13 @@
 	int mmode_ret, mmode_idx = -1;
 	u16 real_product_id;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	dev = hidinput->input;
+
 	/* Check that the report looks ok */
 	if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
 		return -1;
@@ -1378,7 +1385,6 @@
 		}
 	}
 #endif
-	hid_hw_stop(hid);
 	drv_data->device_props = NULL;
 
 	kfree(entry);
--- linux-4.4.0.orig/drivers/hid/hid-lgff.c
+++ linux-4.4.0/drivers/hid/hid-lgff.c
@@ -127,12 +127,19 @@
 
 int lgff_init(struct hid_device* hid)
 {
-	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-	struct input_dev *dev = hidinput->input;
+	struct hid_input *hidinput;
+	struct input_dev *dev;
 	const signed short *ff_bits = ff_joystick;
 	int error;
 	int i;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	dev = hidinput->input;
+
 	/* Check that the report looks ok */
 	if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/hid/hid-logitech-hidpp.c
+++ linux-4.4.0/drivers/hid/hid-logitech-hidpp.c
@@ -414,13 +414,16 @@
 
 static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
 {
+	const u8 ping_byte = 0x5a;
+	u8 ping_data[3] = { 0, 0, ping_byte };
 	struct hidpp_report response;
 	int ret;
 
-	ret = hidpp_send_fap_command_sync(hidpp,
+	ret = hidpp_send_rap_command_sync(hidpp,
+			REPORT_ID_HIDPP_SHORT,
 			HIDPP_PAGE_ROOT_IDX,
 			CMD_ROOT_GET_PROTOCOL_VERSION,
-			NULL, 0, &response);
+			ping_data, sizeof(ping_data), &response);
 
 	if (ret == HIDPP_ERROR_INVALID_SUBID) {
 		hidpp->protocol_major = 1;
@@ -440,8 +443,14 @@
 	if (ret)
 		return ret;
 
-	hidpp->protocol_major = response.fap.params[0];
-	hidpp->protocol_minor = response.fap.params[1];
+	if (response.rap.params[2] != ping_byte) {
+		hid_err(hidpp->hid_dev, "%s: ping mismatch 0x%02x != 0x%02x\n",
+			__func__, response.rap.params[2], ping_byte);
+		return -EPROTO;
+	}
+
+	hidpp->protocol_major = response.rap.params[0];
+	hidpp->protocol_minor = response.rap.params[1];
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/hid/hid-magicmouse.c
+++ linux-4.4.0/drivers/hid/hid-magicmouse.c
@@ -451,6 +451,12 @@
 		__set_bit(MSC_RAW, input->mscbit);
 	}
 
+	/*
+	 * hid-input may mark device as using autorepeat, but neither
+	 * the trackpad, nor the mouse actually want it.
+	 */
+	__clear_bit(EV_REP, input->evbit);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/hid/hid-multitouch.c
+++ linux-4.4.0/drivers/hid/hid-multitouch.c
@@ -61,6 +61,7 @@
 #define MT_QUIRK_ALWAYS_VALID		(1 << 4)
 #define MT_QUIRK_VALID_IS_INRANGE	(1 << 5)
 #define MT_QUIRK_VALID_IS_CONFIDENCE	(1 << 6)
+#define MT_QUIRK_CONFIDENCE		(1 << 7)
 #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE	(1 << 8)
 #define MT_QUIRK_NO_AREA		(1 << 9)
 #define MT_QUIRK_IGNORE_DUPLICATES	(1 << 10)
@@ -78,6 +79,7 @@
 	__s32 contactid;	/* the device ContactID assigned to this slot */
 	bool touch_state;	/* is the touch valid? */
 	bool inrange_state;	/* is the finger in proximity of the sensor? */
+	bool confidence_state;  /* is the touch made by a finger? */
 };
 
 struct mt_class {
@@ -143,6 +145,7 @@
 /* reserved					0x0011 */
 #define MT_CLS_WIN_8				0x0012
 #define MT_CLS_EXPORT_ALL_INPUTS		0x0013
+#define MT_CLS_WIN_8_DUAL			0x0014
 
 /* vendor specific classes */
 #define MT_CLS_3M				0x0101
@@ -211,6 +214,12 @@
 		.quirks = MT_QUIRK_ALWAYS_VALID |
 			MT_QUIRK_CONTACT_CNT_ACCURATE,
 		.export_all_inputs = true },
+	{ .name = MT_CLS_WIN_8_DUAL,
+		.quirks = MT_QUIRK_ALWAYS_VALID |
+			MT_QUIRK_IGNORE_DUPLICATES |
+			MT_QUIRK_HOVERING |
+			MT_QUIRK_CONTACT_CNT_ACCURATE,
+		.export_all_inputs = true },
 
 	/*
 	 * vendor specific classes
@@ -312,7 +321,8 @@
 static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
-	int ret, size = hid_report_len(report);
+	int ret;
+	u32 size = hid_report_len(report);
 	u8 *buf;
 
 	/*
@@ -357,8 +367,19 @@
 			break;
 		}
 
-		td->inputmode = field->report->id;
-		td->inputmode_index = usage->usage_index;
+		if (td->inputmode < 0) {
+			td->inputmode = field->report->id;
+			td->inputmode_index = usage->usage_index;
+		} else {
+			/*
+			 * Some elan panels wrongly declare 2 input mode
+			 * features, and silently ignore when we set the
+			 * value in the second field. Skip the second feature
+			 * and hope for the best.
+			 */
+			dev_info(&hdev->dev,
+				 "Ignoring the extra HID_DG_INPUTMODE\n");
+		}
 
 		break;
 	case HID_DG_CONTACTMAX:
@@ -385,6 +406,11 @@
 			td->is_buttonpad = true;
 
 		break;
+	case 0xff0000c5:
+		/* Retrieve the Win8 blob once to enable some devices */
+		if (usage->usage_index == 0)
+			mt_get_feature(hdev, field->report);
+		break;
 	}
 }
 
@@ -486,6 +512,10 @@
 			mt_store_field(usage, td, hi);
 			return 1;
 		case HID_DG_CONFIDENCE:
+			if ((cls->name == MT_CLS_WIN_8 ||
+				cls->name == MT_CLS_WIN_8_DUAL) &&
+				field->application == HID_DG_TOUCHPAD)
+				cls->quirks |= MT_QUIRK_CONFIDENCE;
 			mt_store_field(usage, td, hi);
 			return 1;
 		case HID_DG_TIPSWITCH:
@@ -546,7 +576,18 @@
 
 	case HID_UP_BUTTON:
 		code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE);
+		/*
+		 * MS PTP spec says that external buttons left and right have
+		 * usages 2 and 3.
+		 */
+		if ((cls->name == MT_CLS_WIN_8 ||
+			cls->name == MT_CLS_WIN_8_DUAL) &&
+		    field->application == HID_DG_TOUCHPAD &&
+		    (usage->hid & HID_USAGE) > 1)
+			code--;
 		hid_map_usage(hi, usage, bit, max, EV_KEY, code);
+		if (!*bit)
+			return -1;
 		input_set_capability(hi->input, EV_KEY, code);
 		return 1;
 
@@ -598,6 +639,7 @@
 		return;
 
 	if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
+		int active;
 		int slotnum = mt_compute_slot(td, input);
 		struct mt_slot *s = &td->curdata;
 		struct input_mt *mt = input->mt;
@@ -612,10 +654,14 @@
 				return;
 		}
 
+		if (!(td->mtclass.quirks & MT_QUIRK_CONFIDENCE))
+			s->confidence_state = 1;
+		active = (s->touch_state || s->inrange_state) &&
+							s->confidence_state;
+
 		input_mt_slot(input, slotnum);
-		input_mt_report_slot_state(input, MT_TOOL_FINGER,
-			s->touch_state || s->inrange_state);
-		if (s->touch_state || s->inrange_state) {
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
+		if (active) {
 			/* this finger is in proximity of the sensor */
 			int wide = (s->w > s->h);
 			/* divided by two to match visual scale of touch */
@@ -680,6 +726,8 @@
 			td->curdata.touch_state = value;
 			break;
 		case HID_DG_CONFIDENCE:
+			if (quirks & MT_QUIRK_CONFIDENCE)
+				td->curdata.confidence_state = value;
 			if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
 				td->curvalid = value;
 			break;
@@ -891,7 +939,7 @@
 	struct hid_report_enum *re;
 	struct mt_class *cls = &td->mtclass;
 	char *buf;
-	int report_len;
+	u32 report_len;
 
 	if (td->inputmode < 0)
 		return;
@@ -1173,6 +1221,16 @@
 		MT_USB_DEVICE(USB_VENDOR_ID_3M,
 			USB_DEVICE_ID_3M3266) },
 
+	/* Alps devices */
+	{ .driver_data = MT_CLS_WIN_8_DUAL,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_ALPS_JP,
+			HID_DEVICE_ID_ALPS_U1_DUAL_PTP) },
+	{ .driver_data = MT_CLS_WIN_8_DUAL,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_ALPS_JP,
+			HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
+
 	/* Anton devices */
 	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
 		MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
@@ -1271,6 +1329,9 @@
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
+	{ .driver_data = MT_CLS_EGALAX,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
 
 	/* Elitegroup panel */
 	{ .driver_data = MT_CLS_SERIAL,
--- linux-4.4.0.orig/drivers/hid/hid-ntrig.c
+++ linux-4.4.0/drivers/hid/hid-ntrig.c
@@ -955,6 +955,8 @@
 
 	ret = sysfs_create_group(&hdev->dev.kobj,
 			&ntrig_attribute_group);
+	if (ret)
+		hid_err(hdev, "cannot create sysfs group\n");
 
 	return 0;
 err_free:
--- linux-4.4.0.orig/drivers/hid/hid-plantronics.c
+++ linux-4.4.0/drivers/hid/hid-plantronics.c
@@ -2,7 +2,7 @@
  *  Plantronics USB HID Driver
  *
  *  Copyright (c) 2014 JD Cole <jd.cole@plantronics.com>
- *  Copyright (c) 2015 Terry Junge <terry.junge@plantronics.com>
+ *  Copyright (c) 2015-2018 Terry Junge <terry.junge@plantronics.com>
  */
 
 /*
@@ -48,6 +48,10 @@
 	unsigned short mapped_key;
 	unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev);
 
+	/* special case for PTT products */
+	if (field->application == HID_GD_JOYSTICK)
+		goto defaulted;
+
 	/* handle volume up/down mapping */
 	/* non-standard types or multi-HID interfaces - plt_type is PID */
 	if (!(plt_type & HID_USAGE_PAGE)) {
--- linux-4.4.0.orig/drivers/hid/hid-prodikeys.c
+++ linux-4.4.0/drivers/hid/hid-prodikeys.c
@@ -556,10 +556,14 @@
 
 static int pcmidi_set_operational(struct pcmidi_snd *pm)
 {
+	int rc;
+
 	if (pm->ifnum != 1)
 		return 0; /* only set up ONCE for interace 1 */
 
-	pcmidi_get_output_report(pm);
+	rc = pcmidi_get_output_report(pm);
+	if (rc < 0)
+		return rc;
 	pcmidi_submit_output_report(pm, 0xc1);
 	return 0;
 }
@@ -688,7 +692,11 @@
 	spin_lock_init(&pm->rawmidi_in_lock);
 
 	init_sustain_timers(pm);
-	pcmidi_set_operational(pm);
+	err = pcmidi_set_operational(pm);
+	if (err < 0) {
+		pk_error("failed to find output report\n");
+		goto fail_register;
+	}
 
 	/* register it */
 	err = snd_card_register(card);
@@ -795,12 +803,18 @@
 static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	int ret;
-	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-	unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	struct usb_interface *intf;
+	unsigned short ifnum;
 	unsigned long quirks = id->driver_data;
 	struct pk_device *pk;
 	struct pcmidi_snd *pm = NULL;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
+	intf = to_usb_interface(hdev->dev.parent);
+	ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
 	pk = kzalloc(sizeof(*pk), GFP_KERNEL);
 	if (pk == NULL) {
 		hid_err(hdev, "can't alloc descriptor\n");
--- linux-4.4.0.orig/drivers/hid/hid-rmi.c
+++ linux-4.4.0/drivers/hid/hid-rmi.c
@@ -110,8 +110,8 @@
 	u8 *writeReport;
 	u8 *readReport;
 
-	int input_report_size;
-	int output_report_size;
+	u32 input_report_size;
+	u32 output_report_size;
 
 	unsigned long flags;
 
--- linux-4.4.0.orig/drivers/hid/hid-roccat-arvo.c
+++ linux-4.4.0/drivers/hid/hid-roccat-arvo.c
@@ -349,6 +349,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-isku.c
+++ linux-4.4.0/drivers/hid/hid-roccat-isku.c
@@ -329,6 +329,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-kone.c
+++ linux-4.4.0/drivers/hid/hid-roccat-kone.c
@@ -299,31 +299,40 @@
 	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 	int retval = 0, difference, old_profile;
+	struct kone_settings *settings = (struct kone_settings *)buf;
 
 	/* I need to get my data in one piece */
 	if (off != 0 || count != sizeof(struct kone_settings))
 		return -EINVAL;
 
 	mutex_lock(&kone->kone_lock);
-	difference = memcmp(buf, &kone->settings, sizeof(struct kone_settings));
+	difference = memcmp(settings, &kone->settings,
+			    sizeof(struct kone_settings));
 	if (difference) {
-		retval = kone_set_settings(usb_dev,
-				(struct kone_settings const *)buf);
-		if (retval) {
-			mutex_unlock(&kone->kone_lock);
-			return retval;
+		if (settings->startup_profile < 1 ||
+		    settings->startup_profile > 5) {
+			retval = -EINVAL;
+			goto unlock;
 		}
 
+		retval = kone_set_settings(usb_dev, settings);
+		if (retval)
+			goto unlock;
+
 		old_profile = kone->settings.startup_profile;
-		memcpy(&kone->settings, buf, sizeof(struct kone_settings));
+		memcpy(&kone->settings, settings, sizeof(struct kone_settings));
 
 		kone_profile_activated(kone, kone->settings.startup_profile);
 
 		if (kone->settings.startup_profile != old_profile)
 			kone_profile_report(kone, kone->settings.startup_profile);
 	}
+unlock:
 	mutex_unlock(&kone->kone_lock);
 
+	if (retval)
+		return retval;
+
 	return sizeof(struct kone_settings);
 }
 static BIN_ATTR(settings, 0660, kone_sysfs_read_settings,
@@ -747,6 +756,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-koneplus.c
+++ linux-4.4.0/drivers/hid/hid-roccat-koneplus.c
@@ -438,6 +438,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-konepure.c
+++ linux-4.4.0/drivers/hid/hid-roccat-konepure.c
@@ -136,6 +136,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-kovaplus.c
+++ linux-4.4.0/drivers/hid/hid-roccat-kovaplus.c
@@ -37,6 +37,8 @@
 static void kovaplus_profile_activated(struct kovaplus_device *kovaplus,
 		uint new_profile_index)
 {
+	if (new_profile_index >= ARRAY_SIZE(kovaplus->profile_settings))
+		return;
 	kovaplus->actual_profile = new_profile_index;
 	kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level;
 	kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x;
@@ -506,6 +508,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-lua.c
+++ linux-4.4.0/drivers/hid/hid-roccat-lua.c
@@ -163,6 +163,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-pyra.c
+++ linux-4.4.0/drivers/hid/hid-roccat-pyra.c
@@ -457,6 +457,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-ryos.c
+++ linux-4.4.0/drivers/hid/hid-roccat-ryos.c
@@ -144,6 +144,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat-savu.c
+++ linux-4.4.0/drivers/hid/hid-roccat-savu.c
@@ -116,6 +116,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-roccat.c
+++ linux-4.4.0/drivers/hid/hid-roccat.c
@@ -260,6 +260,8 @@
 	if (!new_value)
 		return -ENOMEM;
 
+	mutex_lock(&device->cbuf_lock);
+
 	report = &device->cbuf[device->cbuf_end];
 
 	/* passing NULL is safe */
@@ -279,6 +281,8 @@
 			reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE;
 	}
 
+	mutex_unlock(&device->cbuf_lock);
+
 	wake_up_interruptible(&device->wait);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/hid/hid-samsung.c
+++ linux-4.4.0/drivers/hid/hid-samsung.c
@@ -157,6 +157,9 @@
 	int ret;
 	unsigned int cmask = HID_CONNECT_DEFAULT;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	ret = hid_parse(hdev);
 	if (ret) {
 		hid_err(hdev, "parse failed\n");
--- linux-4.4.0.orig/drivers/hid/hid-sensor-hub.c
+++ linux-4.4.0/drivers/hid/hid-sensor-hub.c
@@ -218,7 +218,8 @@
 		goto done_proc;
 	}
 
-	remaining_bytes = do_div(buffer_size, sizeof(__s32));
+	remaining_bytes = buffer_size % sizeof(__s32);
+	buffer_size = buffer_size / sizeof(__s32);
 	if (buffer_size) {
 		for (i = 0; i < buffer_size; ++i) {
 			hid_set_field(report->field[field_index], i,
@@ -472,7 +473,8 @@
 		return 1;
 
 	ptr = raw_data;
-	ptr++; /* Skip report id */
+	if (report->id)
+		ptr++; /* Skip report id */
 
 	spin_lock_irqsave(&pdata->lock, flags);
 
--- linux-4.4.0.orig/drivers/hid/hid-sony.c
+++ linux-4.4.0/drivers/hid/hid-sony.c
@@ -1418,8 +1418,10 @@
 	}
 
 	ret = hid_hw_output_report(hdev, buf, 1);
-	if (ret < 0)
-		hid_err(hdev, "can't set operational mode: step 3\n");
+	if (ret < 0) {
+		hid_info(hdev, "can't set operational mode: step 3, ignoring\n");
+		ret = 0;
+	}
 
 out:
 	kfree(buf);
@@ -1958,9 +1960,15 @@
 
 static int sony_init_ff(struct sony_sc *sc)
 {
-	struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
-						struct hid_input, list);
-	struct input_dev *input_dev = hidinput->input;
+	struct hid_input *hidinput;
+	struct input_dev *input_dev;
+
+	if (list_empty(&sc->hdev->inputs)) {
+		hid_err(sc->hdev, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(sc->hdev->inputs.next, struct hid_input, list);
+	input_dev = hidinput->input;
 
 	input_set_capability(input_dev, EV_FF, FF_RUMBLE);
 	return input_ff_create_memless(input_dev, NULL, sony_play_effect);
@@ -2458,6 +2466,12 @@
 		.driver_data = DUALSHOCK4_CONTROLLER_USB },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
 		.driver_data = DUALSHOCK4_CONTROLLER_BT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
+		.driver_data = DUALSHOCK4_CONTROLLER_USB },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
+		.driver_data = DUALSHOCK4_CONTROLLER_BT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE),
+		.driver_data = DUALSHOCK4_CONTROLLER_USB },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, sony_devices);
--- linux-4.4.0.orig/drivers/hid/hid-tmff.c
+++ linux-4.4.0/drivers/hid/hid-tmff.c
@@ -34,6 +34,8 @@
 
 #include "hid-ids.h"
 
+#define THRUSTMASTER_DEVICE_ID_2_IN_1_DT	0xb320
+
 static const signed short ff_rumble[] = {
 	FF_RUMBLE,
 	-1
@@ -88,6 +90,7 @@
 	struct hid_field *ff_field = tmff->ff_field;
 	int x, y;
 	int left, right;	/* Rumbling */
+	int motor_swap;
 
 	switch (effect->type) {
 	case FF_CONSTANT:
@@ -112,6 +115,13 @@
 					ff_field->logical_minimum,
 					ff_field->logical_maximum);
 
+		/* 2-in-1 strong motor is left */
+		if (hid->product == THRUSTMASTER_DEVICE_ID_2_IN_1_DT) {
+			motor_swap = left;
+			left = right;
+			right = motor_swap;
+		}
+
 		dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
 		ff_field->value[0] = left;
 		ff_field->value[1] = right;
@@ -126,12 +136,18 @@
 	struct tmff_device *tmff;
 	struct hid_report *report;
 	struct list_head *report_list;
-	struct hid_input *hidinput = list_entry(hid->inputs.next,
-							struct hid_input, list);
-	struct input_dev *input_dev = hidinput->input;
+	struct hid_input *hidinput;
+	struct input_dev *input_dev;
 	int error;
 	int i;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	input_dev = hidinput->input;
+
 	tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
 	if (!tmff)
 		return -ENOMEM;
@@ -238,6 +254,8 @@
 		.driver_data = (unsigned long)ff_rumble },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304),   /* FireStorm Dual Power 2 (and 3) */
 		.driver_data = (unsigned long)ff_rumble },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, THRUSTMASTER_DEVICE_ID_2_IN_1_DT),   /* Dual Trigger 2-in-1 */
+		.driver_data = (unsigned long)ff_rumble },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323),   /* Dual Trigger 3-in-1 (PC Mode) */
 		.driver_data = (unsigned long)ff_rumble },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324),   /* Dual Trigger 3-in-1 (PS3 Mode) */
--- linux-4.4.0.orig/drivers/hid/hid-uclogic.c
+++ linux-4.4.0/drivers/hid/hid-uclogic.c
@@ -795,6 +795,9 @@
 	__u8 *p;
 	s32 v;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	/*
 	 * Read string descriptor containing tablet parameters. The specific
 	 * string descriptor and data were discovered by sniffing the Windows
--- linux-4.4.0.orig/drivers/hid/hid-xinmo.c
+++ linux-4.4.0/drivers/hid/hid-xinmo.c
@@ -46,6 +46,7 @@
 
 static const struct hid_device_id xinmo_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_THT_2P_ARCADE) },
 	{ }
 };
 
--- linux-4.4.0.orig/drivers/hid/hid-zpff.c
+++ linux-4.4.0/drivers/hid/hid-zpff.c
@@ -66,11 +66,17 @@
 {
 	struct zpff_device *zpff;
 	struct hid_report *report;
-	struct hid_input *hidinput = list_entry(hid->inputs.next,
-						struct hid_input, list);
-	struct input_dev *dev = hidinput->input;
+	struct hid_input *hidinput;
+	struct input_dev *dev;
 	int i, error;
 
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	dev = hidinput->input;
+
 	for (i = 0; i < 4; i++) {
 		report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1);
 		if (!report)
--- linux-4.4.0.orig/drivers/hid/hidraw.c
+++ linux-4.4.0/drivers/hid/hidraw.c
@@ -197,6 +197,11 @@
 	int ret = 0, len;
 	unsigned char report_number;
 
+	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
+		ret = -ENODEV;
+		goto out;
+	}
+
 	dev = hidraw_table[minor]->hid;
 
 	if (!dev->ll_driver->raw_request) {
@@ -257,13 +262,14 @@
 static unsigned int hidraw_poll(struct file *file, poll_table *wait)
 {
 	struct hidraw_list *list = file->private_data;
+	unsigned int mask = POLLOUT | POLLWRNORM; /* hidraw is always writable */
 
 	poll_wait(file, &list->hidraw->wait, wait);
 	if (list->head != list->tail)
-		return POLLIN | POLLRDNORM;
+		mask |= POLLIN | POLLRDNORM;
 	if (!list->hidraw->exist)
-		return POLLERR | POLLHUP;
-	return 0;
+		mask |= POLLERR | POLLHUP;
+	return mask;
 }
 
 static int hidraw_open(struct inode *inode, struct file *file)
@@ -378,7 +384,7 @@
 
 	mutex_lock(&minors_lock);
 	dev = hidraw_table[minor];
-	if (!dev) {
+	if (!dev || !dev->exist) {
 		ret = -ENODEV;
 		goto out;
 	}
--- linux-4.4.0.orig/drivers/hid/i2c-hid/i2c-hid.c
+++ linux-4.4.0/drivers/hid/i2c-hid/i2c-hid.c
@@ -44,7 +44,6 @@
 /* flags */
 #define I2C_HID_STARTED		0
 #define I2C_HID_RESET_PENDING	1
-#define I2C_HID_READ_PENDING	2
 
 #define I2C_HID_PWR_ON		0x00
 #define I2C_HID_PWR_SLEEP	0x01
@@ -137,10 +136,10 @@
 						   * register of the HID
 						   * descriptor. */
 	unsigned int		bufsize;	/* i2c buffer size */
-	char			*inbuf;		/* Input buffer */
-	char			*rawbuf;	/* Raw Input buffer */
-	char			*cmdbuf;	/* Command buffer */
-	char			*argsbuf;	/* Command arguments buffer */
+	u8			*inbuf;		/* Input buffer */
+	u8			*rawbuf;	/* Raw Input buffer */
+	u8			*cmdbuf;	/* Command buffer */
+	u8			*argsbuf;	/* Command arguments buffer */
 
 	unsigned long		flags;		/* device flags */
 
@@ -197,7 +196,6 @@
 		msg[1].len = data_len;
 		msg[1].buf = buf_recv;
 		msg_num = 2;
-		set_bit(I2C_HID_READ_PENDING, &ihid->flags);
 	}
 
 	if (wait)
@@ -205,9 +203,6 @@
 
 	ret = i2c_transfer(client->adapter, msg, msg_num);
 
-	if (data_len > 0)
-		clear_bit(I2C_HID_READ_PENDING, &ihid->flags);
-
 	if (ret != msg_num)
 		return ret < 0 ? ret : -EIO;
 
@@ -282,17 +277,21 @@
 	u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
 	u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
 	u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
+	u16 size;
+	int args_len;
+	int index = 0;
 
-	/* hid_hw_* already checked that data_len < HID_MAX_BUFFER_SIZE */
-	u16 size =	2			/* size */ +
+	i2c_hid_dbg(ihid, "%s\n", __func__);
+
+	if (data_len > ihid->bufsize)
+		return -EINVAL;
+
+	size =		2			/* size */ +
 			(reportID ? 1 : 0)	/* reportID */ +
 			data_len		/* buf */;
-	int args_len =	(reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
+	args_len =	(reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
 			2			/* dataRegister */ +
 			size			/* args */;
-	int index = 0;
-
-	i2c_hid_dbg(ihid, "%s\n", __func__);
 
 	if (!use_data && maxOutputLength == 0)
 		return -ENOSYS;
@@ -360,6 +359,15 @@
 	if (ret)
 		return ret;
 
+	/*
+	 * The HID over I2C specification states that if a DEVICE needs time
+	 * after the PWR_ON request, it should utilise CLOCK stretching.
+	 * However, it has been observered that the Windows driver provides a
+	 * 1ms sleep between the PWR_ON and RESET requests and that some devices
+	 * rely on this.
+	 */
+	usleep_range(1000, 5000);
+
 	i2c_hid_dbg(ihid, "resetting...\n");
 
 	ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0);
@@ -374,7 +382,8 @@
 
 static void i2c_hid_get_input(struct i2c_hid *ihid)
 {
-	int ret, ret_size;
+	int ret;
+	u32 ret_size;
 	int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
 
 	if (size > ihid->bufsize)
@@ -399,7 +408,7 @@
 		return;
 	}
 
-	if (ret_size > size) {
+	if ((ret_size > size) || (ret_size < 2)) {
 		dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
 			__func__, size, ret_size);
 		return;
@@ -418,9 +427,6 @@
 {
 	struct i2c_hid *ihid = dev_id;
 
-	if (test_bit(I2C_HID_READ_PENDING, &ihid->flags))
-		return IRQ_HANDLED;
-
 	i2c_hid_get_input(ihid);
 
 	return IRQ_HANDLED;
@@ -527,7 +533,8 @@
 {
 	/* the worst case is computed from the set_report command with a
 	 * reportID > 15 and the maximum report length */
-	int args_len = sizeof(__u8) + /* optional ReportID byte */
+	int args_len = sizeof(__u8) + /* ReportID */
+		       sizeof(__u8) + /* optional ReportID byte */
 		       sizeof(__u16) + /* data register */
 		       sizeof(__u16) + /* size of the report */
 		       report_size; /* report */
@@ -774,7 +781,7 @@
 	return 0;
 }
 
-static struct hid_ll_driver i2c_hid_ll_driver = {
+struct hid_ll_driver i2c_hid_ll_driver = {
 	.parse = i2c_hid_parse,
 	.start = i2c_hid_start,
 	.stop = i2c_hid_stop,
@@ -784,6 +791,7 @@
 	.output_report = i2c_hid_output_report,
 	.raw_request = i2c_hid_raw_request,
 };
+EXPORT_SYMBOL_GPL(i2c_hid_ll_driver);
 
 static int i2c_hid_init_irq(struct i2c_client *client)
 {
@@ -1002,6 +1010,14 @@
 	pm_runtime_set_active(&client->dev);
 	pm_runtime_enable(&client->dev);
 
+	/* Make sure there is something at this address */
+	ret = i2c_smbus_read_byte(client);
+	if (ret < 0) {
+		dev_dbg(&client->dev, "nothing at this address: %d\n", ret);
+		ret = -ENXIO;
+		goto err_pm;
+	}
+
 	ret = i2c_hid_fetch_hid_descriptor(ihid);
 	if (ret < 0)
 		goto err_pm;
--- linux-4.4.0.orig/drivers/hid/uhid.c
+++ linux-4.4.0/drivers/hid/uhid.c
@@ -12,6 +12,7 @@
 
 #include <linux/atomic.h>
 #include <linux/compat.h>
+#include <linux/cred.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/hid.h>
@@ -24,6 +25,8 @@
 #include <linux/spinlock.h>
 #include <linux/uhid.h>
 #include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/eventpoll.h>
 
 #define UHID_NAME	"uhid"
 #define UHID_BUFSIZE	32
@@ -51,10 +54,26 @@
 	u32 report_id;
 	u32 report_type;
 	struct uhid_event report_buf;
+	struct work_struct worker;
 };
 
 static struct miscdevice uhid_misc;
 
+static void uhid_device_add_worker(struct work_struct *work)
+{
+	struct uhid_device *uhid = container_of(work, struct uhid_device, worker);
+	int ret;
+
+	ret = hid_add_device(uhid->hid);
+	if (ret) {
+		hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret);
+
+		hid_destroy_device(uhid->hid);
+		uhid->hid = NULL;
+		uhid->running = false;
+	}
+}
+
 static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
 {
 	__u8 newhead;
@@ -353,7 +372,7 @@
 	return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
 }
 
-static struct hid_ll_driver uhid_hid_driver = {
+struct hid_ll_driver uhid_hid_driver = {
 	.start = uhid_hid_start,
 	.stop = uhid_hid_stop,
 	.open = uhid_hid_open,
@@ -362,6 +381,7 @@
 	.raw_request = uhid_hid_raw_request,
 	.output_report = uhid_hid_output_report,
 };
+EXPORT_SYMBOL_GPL(uhid_hid_driver);
 
 #ifdef CONFIG_COMPAT
 
@@ -498,18 +518,14 @@
 	uhid->hid = hid;
 	uhid->running = true;
 
-	ret = hid_add_device(hid);
-	if (ret) {
-		hid_err(hid, "Cannot register HID device\n");
-		goto err_hid;
-	}
+	/* Adding of a HID device is done through a worker, to allow HID drivers
+	 * which use feature requests during .probe to work, without they would
+	 * be blocked on devlock, which is held by uhid_char_write.
+	 */
+	schedule_work(&uhid->worker);
 
 	return 0;
 
-err_hid:
-	hid_destroy_device(hid);
-	uhid->hid = NULL;
-	uhid->running = false;
 err_free:
 	kfree(uhid->rd_data);
 	uhid->rd_data = NULL;
@@ -550,6 +566,8 @@
 	uhid->running = false;
 	wake_up_interruptible(&uhid->report_wait);
 
+	cancel_work_sync(&uhid->worker);
+
 	hid_destroy_device(uhid->hid);
 	kfree(uhid->rd_data);
 
@@ -612,6 +630,7 @@
 	init_waitqueue_head(&uhid->waitq);
 	init_waitqueue_head(&uhid->report_wait);
 	uhid->running = false;
+	INIT_WORK(&uhid->worker, uhid_device_add_worker);
 
 	file->private_data = uhid;
 	nonseekable_open(inode, file);
@@ -706,6 +725,17 @@
 
 	switch (uhid->input_buf.type) {
 	case UHID_CREATE:
+		/*
+		 * 'struct uhid_create_req' contains a __user pointer which is
+		 * copied from, so it's unsafe to allow this with elevated
+		 * privileges (e.g. from a setuid binary) or via kernel_write().
+		 */
+		if (file->f_cred != current_cred() || uaccess_kernel()) {
+			pr_err_once("UHID_CREATE from different security context by process %d (%s), this is not allowed.\n",
+				    task_tgid_vnr(current), current->comm);
+			ret = -EACCES;
+			goto unlock;
+		}
 		ret = uhid_dev_create(uhid, &uhid->input_buf);
 		break;
 	case UHID_CREATE2:
@@ -740,13 +770,14 @@
 static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
 {
 	struct uhid_device *uhid = file->private_data;
+	unsigned int mask = POLLOUT | POLLWRNORM; /* uhid is always writable */
 
 	poll_wait(file, &uhid->waitq, wait);
 
 	if (uhid->head != uhid->tail)
-		return POLLIN | POLLRDNORM;
+		mask |= POLLIN | POLLRDNORM;
 
-	return 0;
+	return mask;
 }
 
 static const struct file_operations uhid_fops = {
--- linux-4.4.0.orig/drivers/hid/usbhid/hid-core.c
+++ linux-4.4.0/drivers/hid/usbhid/hid-core.c
@@ -372,7 +372,7 @@
 	raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
 	dir = usbhid->ctrl[usbhid->ctrltail].dir;
 
-	len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+	len = hid_report_len(report);
 	if (dir == USB_DIR_OUT) {
 		usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
 		usbhid->urbctrl->transfer_buffer_length = len;
@@ -477,8 +477,6 @@
 	struct usbhid_device *usbhid = hid->driver_data;
 	int unplug = 0, status = urb->status;
 
-	spin_lock(&usbhid->lock);
-
 	switch (status) {
 	case 0:			/* success */
 		if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
@@ -498,6 +496,8 @@
 		hid_warn(urb->dev, "ctrl urb status %d received\n", status);
 	}
 
+	spin_lock(&usbhid->lock);
+
 	if (unplug) {
 		usbhid->ctrltail = usbhid->ctrlhead;
 	} else {
@@ -951,14 +951,6 @@
 	return ret;
 }
 
-static void usbhid_restart_queues(struct usbhid_device *usbhid)
-{
-	if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
-		usbhid_restart_out_queue(usbhid);
-	if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
-		usbhid_restart_ctrl_queue(usbhid);
-}
-
 static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
 	struct usbhid_device *usbhid = hid->driver_data;
@@ -979,6 +971,8 @@
 	unsigned int rsize = 0;
 	char *rdesc;
 	int ret, n;
+	int num_descriptors;
+	size_t offset = offsetof(struct hid_descriptor, desc);
 
 	quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
 			le16_to_cpu(dev->descriptor.idProduct));
@@ -1001,10 +995,18 @@
 		return -ENODEV;
 	}
 
+	if (hdesc->bLength < sizeof(struct hid_descriptor)) {
+		dbg_hid("hid descriptor is too short\n");
+		return -EINVAL;
+	}
+
 	hid->version = le16_to_cpu(hdesc->bcdHID);
 	hid->country = hdesc->bCountryCode;
 
-	for (n = 0; n < hdesc->bNumDescriptors; n++)
+	num_descriptors = min_t(int, hdesc->bNumDescriptors,
+	       (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor));
+
+	for (n = 0; n < num_descriptors; n++)
 		if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
 			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
 
@@ -1259,7 +1261,7 @@
 	return hid_set_idle(dev, ifnum, report, idle);
 }
 
-static struct hid_ll_driver usb_hid_driver = {
+struct hid_ll_driver usb_hid_driver = {
 	.parse = usbhid_parse,
 	.start = usbhid_start,
 	.stop = usbhid_stop,
@@ -1272,6 +1274,7 @@
 	.output_report = usbhid_output_report,
 	.idle = usbhid_idle,
 };
+EXPORT_SYMBOL_GPL(usb_hid_driver);
 
 static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
@@ -1404,6 +1407,37 @@
 	usb_kill_urb(usbhid->urbout);
 }
 
+static void hid_restart_io(struct hid_device *hid)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+	int clear_halt = test_bit(HID_CLEAR_HALT, &usbhid->iofl);
+	int reset_pending = test_bit(HID_RESET_PENDING, &usbhid->iofl);
+
+	spin_lock_irq(&usbhid->lock);
+	clear_bit(HID_SUSPENDED, &usbhid->iofl);
+	usbhid_mark_busy(usbhid);
+
+	if (clear_halt || reset_pending)
+		schedule_work(&usbhid->reset_work);
+	usbhid->retry_delay = 0;
+	spin_unlock_irq(&usbhid->lock);
+
+	if (reset_pending || !test_bit(HID_STARTED, &usbhid->iofl))
+		return;
+
+	if (!clear_halt) {
+		if (hid_start_in(hid) < 0)
+			hid_io_error(hid);
+	}
+
+	spin_lock_irq(&usbhid->lock);
+	if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+		usbhid_restart_out_queue(usbhid);
+	if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+		usbhid_restart_ctrl_queue(usbhid);
+	spin_unlock_irq(&usbhid->lock);
+}
+
 /* Treat USB reset pretty much the same as suspend/resume */
 static int hid_pre_reset(struct usb_interface *intf)
 {
@@ -1453,14 +1487,14 @@
 		return 1;
 	}
 
+	/* No need to do another reset or clear a halted endpoint */
 	spin_lock_irq(&usbhid->lock);
 	clear_bit(HID_RESET_PENDING, &usbhid->iofl);
+	clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
 	spin_unlock_irq(&usbhid->lock);
 	hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
-	status = hid_start_in(hid);
-	if (status < 0)
-		hid_io_error(hid);
-	usbhid_restart_queues(usbhid);
+
+	hid_restart_io(hid);
 
 	return 0;
 }
@@ -1483,25 +1517,9 @@
 #ifdef CONFIG_PM
 static int hid_resume_common(struct hid_device *hid, bool driver_suspended)
 {
-	struct usbhid_device *usbhid = hid->driver_data;
-	int status;
-
-	spin_lock_irq(&usbhid->lock);
-	clear_bit(HID_SUSPENDED, &usbhid->iofl);
-	usbhid_mark_busy(usbhid);
-
-	if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) ||
-			test_bit(HID_RESET_PENDING, &usbhid->iofl))
-		schedule_work(&usbhid->reset_work);
-	usbhid->retry_delay = 0;
-
-	usbhid_restart_queues(usbhid);
-	spin_unlock_irq(&usbhid->lock);
-
-	status = hid_start_in(hid);
-	if (status < 0)
-		hid_io_error(hid);
+	int status = 0;
 
+	hid_restart_io(hid);
 	if (driver_suspended && hid->driver && hid->driver->resume)
 		status = hid->driver->resume(hid);
 	return status;
@@ -1570,12 +1588,8 @@
 static int hid_resume(struct usb_interface *intf)
 {
 	struct hid_device *hid = usb_get_intfdata (intf);
-	struct usbhid_device *usbhid = hid->driver_data;
 	int status;
 
-	if (!test_bit(HID_STARTED, &usbhid->iofl))
-		return 0;
-
 	status = hid_resume_common(hid, true);
 	dev_dbg(&intf->dev, "resume status %d\n", status);
 	return 0;
@@ -1584,10 +1598,8 @@
 static int hid_reset_resume(struct usb_interface *intf)
 {
 	struct hid_device *hid = usb_get_intfdata(intf);
-	struct usbhid_device *usbhid = hid->driver_data;
 	int status;
 
-	clear_bit(HID_SUSPENDED, &usbhid->iofl);
 	status = hid_post_reset(intf);
 	if (status >= 0 && hid->driver && hid->driver->reset_resume) {
 		int ret = hid->driver->reset_resume(hid);
--- linux-4.4.0.orig/drivers/hid/usbhid/hid-quirks.c
+++ linux-4.4.0/drivers/hid/usbhid/hid-quirks.c
@@ -55,12 +55,14 @@
 	{ USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
 
 	{ USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE, HID_QUIRK_ALWAYS_POLL },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE, HID_QUIRK_NOGET },
@@ -70,6 +72,8 @@
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
+	{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
 	{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL },
@@ -79,6 +83,7 @@
 	{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL },
 	{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
 	{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
+	{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641, HID_QUIRK_ALWAYS_POLL },
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A, HID_QUIRK_ALWAYS_POLL },
@@ -149,6 +154,7 @@
 	{ USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES, HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI, HID_QUIRK_MULTI_INPUT },
 
 	{ 0, 0 }
 };
--- linux-4.4.0.orig/drivers/hid/usbhid/hiddev.c
+++ linux-4.4.0/drivers/hid/usbhid/hiddev.c
@@ -35,6 +35,7 @@
 #include <linux/hiddev.h>
 #include <linux/compat.h>
 #include <linux/vmalloc.h>
+#include <linux/nospec.h>
 #include "usbhid.h"
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -307,6 +308,14 @@
 	spin_unlock_irq(&list->hiddev->list_lock);
 
 	mutex_lock(&hiddev->existancelock);
+	/*
+	 * recheck exist with existance lock held to
+	 * avoid opening a disconnected device
+	 */
+	if (!list->hiddev->exist) {
+		res = -ENODEV;
+		goto bail_unlock;
+	}
 	if (!list->hiddev->open++)
 		if (list->hiddev->exist) {
 			struct hid_device *hid = hiddev->hid;
@@ -321,6 +330,10 @@
 	return 0;
 bail_unlock:
 	mutex_unlock(&hiddev->existancelock);
+
+	spin_lock_irq(&list->hiddev->list_lock);
+	list_del(&list->node);
+	spin_unlock_irq(&list->hiddev->list_lock);
 bail:
 	file->private_data = NULL;
 	vfree(list);
@@ -478,10 +491,14 @@
 
 		if (uref->field_index >= report->maxfield)
 			goto inval;
+		uref->field_index = array_index_nospec(uref->field_index,
+						       report->maxfield);
 
 		field = report->field[uref->field_index];
 		if (uref->usage_index >= field->maxusage)
 			goto inval;
+		uref->usage_index = array_index_nospec(uref->usage_index,
+						       field->maxusage);
 
 		uref->usage_code = field->usage[uref->usage_index].hid;
 
@@ -508,29 +525,45 @@
 
 			if (uref->field_index >= report->maxfield)
 				goto inval;
+			uref->field_index = array_index_nospec(uref->field_index,
+							       report->maxfield);
 
 			field = report->field[uref->field_index];
 
 			if (cmd == HIDIOCGCOLLECTIONINDEX) {
 				if (uref->usage_index >= field->maxusage)
 					goto inval;
+				uref->usage_index =
+					array_index_nospec(uref->usage_index,
+							   field->maxusage);
 			} else if (uref->usage_index >= field->report_count)
 				goto inval;
+		}
 
-			else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
-				 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
-				  uref->usage_index + uref_multi->num_values > field->report_count))
+		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+			if (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
+			    uref->usage_index + uref_multi->num_values >
+			    field->report_count)
 				goto inval;
+
+			uref->usage_index =
+				array_index_nospec(uref->usage_index,
+						   field->report_count -
+						   uref_multi->num_values);
 		}
 
 		switch (cmd) {
 		case HIDIOCGUSAGE:
+			if (uref->usage_index >= field->report_count)
+				goto inval;
 			uref->value = field->value[uref->usage_index];
 			if (copy_to_user(user_arg, uref, sizeof(*uref)))
 				goto fault;
 			goto goodreturn;
 
 		case HIDIOCSUSAGE:
+			if (uref->usage_index >= field->report_count)
+				goto inval;
 			field->value[uref->usage_index] = uref->value;
 			goto goodreturn;
 
@@ -761,6 +794,8 @@
 
 		if (finfo.field_index >= report->maxfield)
 			break;
+		finfo.field_index = array_index_nospec(finfo.field_index,
+						       report->maxfield);
 
 		field = report->field[finfo.field_index];
 		memset(&finfo, 0, sizeof(finfo));
@@ -801,6 +836,8 @@
 
 		if (cinfo.index >= hid->maxcollection)
 			break;
+		cinfo.index = array_index_nospec(cinfo.index,
+						 hid->maxcollection);
 
 		cinfo.type = hid->collection[cinfo.index].type;
 		cinfo.usage = hid->collection[cinfo.index].usage;
@@ -929,9 +966,9 @@
 	hiddev->exist = 0;
 
 	if (hiddev->open) {
-		mutex_unlock(&hiddev->existancelock);
 		usbhid_close(hiddev->hid);
 		wake_up_interruptible(&hiddev->wait);
+		mutex_unlock(&hiddev->existancelock);
 	} else {
 		mutex_unlock(&hiddev->existancelock);
 		kfree(hiddev);
--- linux-4.4.0.orig/drivers/hid/wacom_sys.c
+++ linux-4.4.0/drivers/hid/wacom_sys.c
@@ -152,6 +152,25 @@
 		hid_data->inputmode = field->report->id;
 		hid_data->inputmode_index = usage->usage_index;
 		break;
+
+	case HID_UP_DIGITIZER:
+		if (field->report->id == 0x0B &&
+		    (field->application == WACOM_G9_DIGITIZER ||
+		     field->application == WACOM_G11_DIGITIZER)) {
+			wacom->wacom_wac.mode_report = field->report->id;
+			wacom->wacom_wac.mode_value = 0;
+		}
+		break;
+
+	case WACOM_G9_PAGE:
+	case WACOM_G11_PAGE:
+		if (field->report->id == 0x03 &&
+		    (field->application == WACOM_G9_TOUCHSCREEN ||
+		     field->application == WACOM_G11_TOUCHSCREEN)) {
+			wacom->wacom_wac.mode_report = field->report->id;
+			wacom->wacom_wac.mode_value = 0;
+		}
+		break;
 	}
 }
 
@@ -322,26 +341,41 @@
 	return 0;
 }
 
-static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
-		int length, int mode)
+static int wacom_set_device_mode(struct hid_device *hdev,
+				 struct wacom_wac *wacom_wac)
 {
-	unsigned char *rep_data;
+	u8 *rep_data;
+	struct hid_report *r;
+	struct hid_report_enum *re;
+	int length;
 	int error = -ENOMEM, limit = 0;
 
-	rep_data = kzalloc(length, GFP_KERNEL);
+	if (wacom_wac->mode_report < 0)
+		return 0;
+
+	re = &(hdev->report_enum[HID_FEATURE_REPORT]);
+	r = re->report_id_hash[wacom_wac->mode_report];
+	if (!r)
+		return -EINVAL;
+
+	rep_data = hid_alloc_report_buf(r, GFP_KERNEL);
 	if (!rep_data)
-		return error;
+		return -ENOMEM;
+
+	length = hid_report_len(r);
 
 	do {
-		rep_data[0] = report_id;
-		rep_data[1] = mode;
+		rep_data[0] = wacom_wac->mode_report;
+		rep_data[1] = wacom_wac->mode_value;
 
 		error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
 					 length, 1);
 		if (error >= 0)
 			error = wacom_get_report(hdev, HID_FEATURE_REPORT,
 			                         rep_data, length, 1);
-	} while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES);
+	} while (error >= 0 &&
+		 rep_data[1] != wacom_wac->mode_report &&
+		 limit++ < WAC_MSG_RETRIES);
 
 	kfree(rep_data);
 
@@ -411,32 +445,41 @@
 static int wacom_query_tablet_data(struct hid_device *hdev,
 		struct wacom_features *features)
 {
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
 	if (hdev->bus == BUS_BLUETOOTH)
 		return wacom_bt_query_tablet_data(hdev, 1, features);
 
-	if (features->type == HID_GENERIC)
-		return wacom_hid_set_device_mode(hdev);
-
-	if (features->device_type & WACOM_DEVICETYPE_TOUCH) {
-		if (features->type > TABLETPC) {
-			/* MT Tablet PC touch */
-			return wacom_set_device_mode(hdev, 3, 4, 4);
-		}
-		else if (features->type == WACOM_24HDT) {
-			return wacom_set_device_mode(hdev, 18, 3, 2);
-		}
-		else if (features->type == WACOM_27QHDT) {
-			return wacom_set_device_mode(hdev, 131, 3, 2);
-		}
-		else if (features->type == BAMBOO_PAD) {
-			return wacom_set_device_mode(hdev, 2, 2, 2);
-		}
-	} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
-		if (features->type <= BAMBOO_PT) {
-			return wacom_set_device_mode(hdev, 2, 2, 2);
+	if (features->type != HID_GENERIC) {
+		if (features->device_type & WACOM_DEVICETYPE_TOUCH) {
+			if (features->type > TABLETPC) {
+				/* MT Tablet PC touch */
+				wacom_wac->mode_report = 3;
+				wacom_wac->mode_value = 4;
+			} else if (features->type == WACOM_24HDT) {
+				wacom_wac->mode_report = 18;
+				wacom_wac->mode_value = 2;
+			} else if (features->type == WACOM_27QHDT) {
+				wacom_wac->mode_report = 131;
+				wacom_wac->mode_value = 2;
+			} else if (features->type == BAMBOO_PAD) {
+				wacom_wac->mode_report = 2;
+				wacom_wac->mode_value = 2;
+			}
+		} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
+			if (features->type <= BAMBOO_PT) {
+				wacom_wac->mode_report = 2;
+				wacom_wac->mode_value = 2;
+			}
 		}
 	}
 
+	wacom_set_device_mode(hdev, wacom_wac);
+
+	if (features->type == HID_GENERIC)
+		return wacom_hid_set_device_mode(hdev);
+
 	return 0;
 }
 
@@ -458,7 +501,7 @@
 	 * Skip the query for this type and modify defaults based on
 	 * interface number.
 	 */
-	if (features->type == WIRELESS) {
+	if (features->type == WIRELESS && intf) {
 		if (intf->cur_altsetting->desc.bInterfaceNumber == 0)
 			features->device_type = WACOM_DEVICETYPE_WL_MONITOR;
 		else
@@ -1512,6 +1555,9 @@
 
 	wacom_destroy_battery(wacom);
 
+	if (!usbdev)
+		return;
+
 	/* Stylus interface */
 	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
 	wacom1 = hid_get_drvdata(hdev1);
@@ -1686,61 +1732,21 @@
 		"%s Pad", name);
 }
 
-static int wacom_probe(struct hid_device *hdev,
-		const struct hid_device_id *id)
+static int wacom_parse_and_register(struct wacom *wacom)
 {
-	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct wacom *wacom;
-	struct wacom_wac *wacom_wac;
-	struct wacom_features *features;
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct wacom_features *features = &wacom_wac->features;
+	struct hid_device *hdev = wacom->hdev;
 	int error;
 	unsigned int connect_mask = HID_CONNECT_HIDRAW;
 
-	if (!id->driver_data)
-		return -EINVAL;
-
-	hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
-
-	/* hid-core sets this quirk for the boot interface */
-	hdev->quirks &= ~HID_QUIRK_NOGET;
-
-	wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
-	if (!wacom)
-		return -ENOMEM;
-
-	hid_set_drvdata(hdev, wacom);
-	wacom->hdev = hdev;
-
-	/* ask for the report descriptor to be loaded by HID */
-	error = hid_parse(hdev);
-	if (error) {
-		hid_err(hdev, "parse failed\n");
-		goto fail_parse;
-	}
-
-	wacom_wac = &wacom->wacom_wac;
-	wacom_wac->features = *((struct wacom_features *)id->driver_data);
-	features = &wacom_wac->features;
 	features->pktlen = wacom_compute_pktlen(hdev);
-	if (features->pktlen > WACOM_PKGLEN_MAX) {
-		error = -EINVAL;
-		goto fail_pktlen;
-	}
-
-	if (features->check_for_hid_type && features->hid_type != hdev->type) {
-		error = -ENODEV;
-		goto fail_type;
-	}
-
-	wacom->usbdev = dev;
-	wacom->intf = intf;
-	mutex_init(&wacom->lock);
-	INIT_WORK(&wacom->work, wacom_wireless_work);
+	if (features->pktlen > WACOM_PKGLEN_MAX)
+		return -EINVAL;
 
 	error = wacom_allocate_inputs(wacom);
 	if (error)
-		goto fail_allocate_inputs;
+		return error;
 
 	/*
 	 * Bamboo Pad has a generic hid handling for the Pen, and we switch it
@@ -1753,7 +1759,7 @@
 		} else if ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) &&
 			   (features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) {
 			error = -ENODEV;
-			goto fail_shared_data;
+			goto fail_allocate_inputs;
 		}
 	}
 
@@ -1773,7 +1779,7 @@
 			 error ? "Ignoring" : "Assuming pen");
 
 		if (error)
-			goto fail_shared_data;
+			goto fail_parsed;
 
 		features->device_type |= WACOM_DEVICETYPE_PEN;
 	}
@@ -1797,14 +1803,6 @@
 	if (error)
 		goto fail_register_inputs;
 
-	if (hdev->bus == BUS_BLUETOOTH) {
-		error = device_create_file(&hdev->dev, &dev_attr_speed);
-		if (error)
-			hid_warn(hdev,
-				 "can't create sysfs speed attribute err: %d\n",
-				 error);
-	}
-
 	if (features->type == HID_GENERIC)
 		connect_mask |= HID_CONNECT_DRIVER;
 
@@ -1845,18 +1843,87 @@
 	return 0;
 
 fail_hw_start:
-	if (hdev->bus == BUS_BLUETOOTH)
-		device_remove_file(&hdev->dev, &dev_attr_speed);
+	hid_hw_stop(hdev);
 fail_register_inputs:
 	wacom_clean_inputs(wacom);
 	wacom_destroy_battery(wacom);
 fail_battery:
 	wacom_remove_shared_data(wacom);
 fail_shared_data:
-	wacom_clean_inputs(wacom);
+fail_parsed:
 fail_allocate_inputs:
+	wacom_clean_inputs(wacom);
+	return error;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	struct wacom *wacom;
+	struct wacom_wac *wacom_wac;
+	struct wacom_features *features;
+	int error;
+
+	if (!id->driver_data)
+		return -EINVAL;
+
+	hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
+
+	/* hid-core sets this quirk for the boot interface */
+	hdev->quirks &= ~HID_QUIRK_NOGET;
+
+	wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+	if (!wacom)
+		return -ENOMEM;
+
+	hid_set_drvdata(hdev, wacom);
+	wacom->hdev = hdev;
+
+	wacom_wac = &wacom->wacom_wac;
+	wacom_wac->features = *((struct wacom_features *)id->driver_data);
+	features = &wacom_wac->features;
+
+	if (features->check_for_hid_type && features->hid_type != hdev->type) {
+		error = -ENODEV;
+		goto fail_type;
+	}
+
+	wacom_wac->hid_data.inputmode = -1;
+	wacom_wac->mode_report = -1;
+
+	if (hid_is_usb(hdev)) {
+		struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+		struct usb_device *dev = interface_to_usbdev(intf);
+
+		wacom->usbdev = dev;
+		wacom->intf = intf;
+	}
+
+	mutex_init(&wacom->lock);
+	INIT_WORK(&wacom->work, wacom_wireless_work);
+
+	/* ask for the report descriptor to be loaded by HID */
+	error = hid_parse(hdev);
+	if (error) {
+		hid_err(hdev, "parse failed\n");
+		goto fail_parse;
+	}
+
+	error = wacom_parse_and_register(wacom);
+	if (error)
+		goto fail_parse;
+
+	if (hdev->bus == BUS_BLUETOOTH) {
+		error = device_create_file(&hdev->dev, &dev_attr_speed);
+		if (error)
+			hid_warn(hdev,
+				 "can't create sysfs speed attribute err: %d\n",
+				 error);
+	}
+
+	return 0;
+
 fail_type:
-fail_pktlen:
 fail_parse:
 	kfree(wacom);
 	hid_set_drvdata(hdev, NULL);
--- linux-4.4.0.orig/drivers/hid/wacom_wac.c
+++ linux-4.4.0/drivers/hid/wacom_wac.c
@@ -148,19 +148,21 @@
 		wacom->id[0] = STYLUS_DEVICE_ID;
 	}
 
-	pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
-	if (features->pressure_max > 255)
-		pressure = (pressure << 1) | ((data[4] >> 6) & 1);
-	pressure += (features->pressure_max + 1) / 2;
-
-	input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
-	input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
-	input_report_abs(input, ABS_PRESSURE, pressure);
-
-	input_report_key(input, BTN_TOUCH, data[4] & 0x08);
-	input_report_key(input, BTN_STYLUS, data[4] & 0x10);
-	/* Only allow the stylus2 button to be reported for the pen tool. */
-	input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
+	if (prox) {
+		pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+		if (features->pressure_max > 255)
+			pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+		pressure += (features->pressure_max + 1) / 2;
+
+		input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+		input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
+		input_report_abs(input, ABS_PRESSURE, pressure);
+
+		input_report_key(input, BTN_TOUCH, data[4] & 0x08);
+		input_report_key(input, BTN_STYLUS, data[4] & 0x10);
+		/* Only allow the stylus2 button to be reported for the pen tool. */
+		input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
+	}
 
 	if (!prox)
 		wacom->id[0] = 0;
@@ -672,7 +674,7 @@
 	input_report_key(input, BTN_BASE2, (data[11] & 0x02));
 
 	if (data[12] & 0x80)
-		input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
+		input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f) - 1);
 	else
 		input_report_abs(input, ABS_WHEEL, 0);
 
@@ -1438,37 +1440,38 @@
 {
 	unsigned char *data = wacom->data;
 
-	if (wacom->pen_input)
+	if (wacom->pen_input) {
 		dev_dbg(wacom->pen_input->dev.parent,
 			"%s: received report #%d\n", __func__, data[0]);
-	else if (wacom->touch_input)
+
+		if (len == WACOM_PKGLEN_PENABLED ||
+		    data[0] == WACOM_REPORT_PENABLED)
+			return wacom_tpc_pen(wacom);
+	}
+	else if (wacom->touch_input) {
 		dev_dbg(wacom->touch_input->dev.parent,
 			"%s: received report #%d\n", __func__, data[0]);
 
-	switch (len) {
-	case WACOM_PKGLEN_TPC1FG:
-		return wacom_tpc_single_touch(wacom, len);
-
-	case WACOM_PKGLEN_TPC2FG:
-		return wacom_tpc_mt_touch(wacom);
-
-	case WACOM_PKGLEN_PENABLED:
-		return wacom_tpc_pen(wacom);
-
-	default:
-		switch (data[0]) {
-		case WACOM_REPORT_TPC1FG:
-		case WACOM_REPORT_TPCHID:
-		case WACOM_REPORT_TPCST:
-		case WACOM_REPORT_TPC1FGE:
+		switch (len) {
+		case WACOM_PKGLEN_TPC1FG:
 			return wacom_tpc_single_touch(wacom, len);
 
-		case WACOM_REPORT_TPCMT:
-		case WACOM_REPORT_TPCMT2:
-			return wacom_mt_touch(wacom);
+		case WACOM_PKGLEN_TPC2FG:
+			return wacom_tpc_mt_touch(wacom);
 
-		case WACOM_REPORT_PENABLED:
-			return wacom_tpc_pen(wacom);
+		default:
+			switch (data[0]) {
+			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:
+			case WACOM_REPORT_TPCMT2:
+				return wacom_mt_touch(wacom);
+
+			}
 		}
 	}
 
@@ -2484,8 +2487,14 @@
 			if (features->type >= INTUOSHT && features->type <= BAMBOO_PT)
 				features->device_type |= WACOM_DEVICETYPE_PAD;
 
-			features->x_max = 4096;
-			features->y_max = 4096;
+			if (features->type == INTUOSHT2) {
+				features->x_max = features->x_max / 10;
+				features->y_max = features->y_max / 10;
+			}
+			else {
+				features->x_max = 4096;
+				features->y_max = 4096;
+			}
 		}
 		else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) {
 			features->device_type |= WACOM_DEVICETYPE_PAD;
@@ -2493,6 +2502,17 @@
 	}
 
 	/*
+	 * Hack for the Bamboo One:
+	 * the device presents a PAD/Touch interface as most Bamboos and even
+	 * sends ghosts PAD data on it. However, later, we must disable this
+	 * ghost interface, and we can not detect it unless we set it here
+	 * to WACOM_DEVICETYPE_PAD or WACOM_DEVICETYPE_TOUCH.
+	 */
+	if (features->type == BAMBOO_PEN &&
+	    features->pktlen == WACOM_PKGLEN_BBTOUCH3)
+		features->device_type |= WACOM_DEVICETYPE_PAD;
+
+	/*
 	 * Raw Wacom-mode pen and touch events both come from interface
 	 * 0, whose HID descriptor has an application usage of 0xFF0D
 	 * (i.e., WACOM_VENDORDEFINED_PEN). We route pen packets back
@@ -3438,6 +3458,10 @@
 	{ "Wacom Intuos PT M 2", 21600, 13500, 2047, 63,
 	  INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x343 =
+	{ "Wacom DTK1651", 34616, 19559, 1023, 0,
+	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
+	  WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
 
 static const struct wacom_features wacom_features_HID_ANY_ID =
 	{ "Wacom HID", .type = HID_GENERIC };
@@ -3603,6 +3627,7 @@
 	{ USB_DEVICE_WACOM(0x33C) },
 	{ USB_DEVICE_WACOM(0x33D) },
 	{ USB_DEVICE_WACOM(0x33E) },
+	{ USB_DEVICE_WACOM(0x343) },
 	{ USB_DEVICE_WACOM(0x4001) },
 	{ USB_DEVICE_WACOM(0x4004) },
 	{ USB_DEVICE_WACOM(0x5000) },
--- linux-4.4.0.orig/drivers/hid/wacom_wac.h
+++ linux-4.4.0/drivers/hid/wacom_wac.h
@@ -83,6 +83,12 @@
 #define WACOM_DEVICETYPE_WL_MONITOR     0x0008
 
 #define WACOM_VENDORDEFINED_PEN		0xff0d0001
+#define WACOM_G9_PAGE			0xff090000
+#define WACOM_G9_DIGITIZER		(WACOM_G9_PAGE | 0x02)
+#define WACOM_G9_TOUCHSCREEN		(WACOM_G9_PAGE | 0x11)
+#define WACOM_G11_PAGE			0xff110000
+#define WACOM_G11_DIGITIZER		(WACOM_G11_PAGE | 0x02)
+#define WACOM_G11_TOUCHSCREEN		(WACOM_G11_PAGE | 0x11)
 
 #define WACOM_PEN_FIELD(f)	(((f)->logical == HID_DG_STYLUS) || \
 				 ((f)->physical == HID_DG_STYLUS) || \
@@ -237,6 +243,8 @@
 	int ps_connected;
 	u8 bt_features;
 	u8 bt_high_speed;
+	int mode_report;
+	int mode_value;
 	struct hid_data hid_data;
 };
 
--- linux-4.4.0.orig/drivers/hsi/clients/ssi_protocol.c
+++ linux-4.4.0/drivers/hsi/clients/ssi_protocol.c
@@ -410,6 +410,7 @@
 	del_timer(&ssi->rx_wd);
 	del_timer(&ssi->tx_wd);
 	del_timer(&ssi->keep_alive);
+	cancel_work_sync(&ssi->work);
 	ssi->main_state = 0;
 	ssi->send_state = 0;
 	ssi->recv_state = 0;
@@ -976,7 +977,7 @@
 		goto drop;
 	/* Pad to 32-bits - FIXME: Revisit*/
 	if ((skb->len & 3) && skb_pad(skb, 4 - (skb->len & 3)))
-		goto drop;
+		goto inc_dropped;
 
 	/*
 	 * Modem sends Phonet messages over SSI with its own endianess...
@@ -1028,8 +1029,9 @@
 drop2:
 	hsi_free_msg(msg);
 drop:
-	dev->stats.tx_dropped++;
 	dev_kfree_skb(skb);
+inc_dropped:
+	dev->stats.tx_dropped++;
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/hv/channel.c
+++ linux-4.4.0/drivers/hv/channel.c
@@ -28,6 +28,7 @@
 #include <linux/module.h>
 #include <linux/hyperv.h>
 #include <linux/uio.h>
+#include <linux/interrupt.h>
 
 #include "hyperv_vmbus.h"
 
@@ -38,11 +39,16 @@
  * vmbus_setevent- Trigger an event notification on the specified
  * channel.
  */
-static void vmbus_setevent(struct vmbus_channel *channel)
+void vmbus_setevent(struct vmbus_channel *channel)
 {
 	struct hv_monitor_page *monitorpage;
 
-	if (channel->offermsg.monitor_allocated) {
+	/*
+	 * For channels marked as in "low latency" mode
+	 * bypass the monitor page mechanism.
+	 */
+	if ((channel->offermsg.monitor_allocated) &&
+	    (!channel->low_latency)) {
 		/* Each u32 represents 32 channels */
 		sync_set_bit(channel->offermsg.child_relid & 31,
 			(unsigned long *) vmbus_connection.send_int_page +
@@ -59,6 +65,7 @@
 		vmbus_set_event(channel);
 	}
 }
+EXPORT_SYMBOL_GPL(vmbus_setevent);
 
 /*
  * vmbus_open - Open the specified channel.
@@ -69,12 +76,14 @@
 {
 	struct vmbus_channel_open_channel *open_msg;
 	struct vmbus_channel_msginfo *open_info = NULL;
-	void *in, *out;
 	unsigned long flags;
 	int ret, err = 0;
-	unsigned long t;
 	struct page *page;
 
+	if (send_ringbuffer_size % PAGE_SIZE ||
+	    recv_ringbuffer_size % PAGE_SIZE)
+		return -EINVAL;
+
 	spin_lock_irqsave(&newchannel->lock, flags);
 	if (newchannel->state == CHANNEL_OPEN_STATE) {
 		newchannel->state = CHANNEL_OPENING_STATE;
@@ -94,36 +103,33 @@
 				recv_ringbuffer_size));
 
 	if (!page)
-		out = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
-					       get_order(send_ringbuffer_size +
-					       recv_ringbuffer_size));
-	else
-		out = (void *)page_address(page);
+		page = alloc_pages(GFP_KERNEL|__GFP_ZERO,
+				   get_order(send_ringbuffer_size +
+					     recv_ringbuffer_size));
 
-	if (!out) {
+	if (!page) {
 		err = -ENOMEM;
-		goto error0;
+		goto error_set_chnstate;
 	}
 
-	in = (void *)((unsigned long)out + send_ringbuffer_size);
-
-	newchannel->ringbuffer_pages = out;
+	newchannel->ringbuffer_pages = page_address(page);
 	newchannel->ringbuffer_pagecount = (send_ringbuffer_size +
 					   recv_ringbuffer_size) >> PAGE_SHIFT;
 
-	ret = hv_ringbuffer_init(
-		&newchannel->outbound, out, send_ringbuffer_size);
+	ret = hv_ringbuffer_init(&newchannel->outbound, page,
+				 send_ringbuffer_size >> PAGE_SHIFT);
 
 	if (ret != 0) {
 		err = ret;
-		goto error0;
+		goto error_free_pages;
 	}
 
-	ret = hv_ringbuffer_init(
-		&newchannel->inbound, in, recv_ringbuffer_size);
+	ret = hv_ringbuffer_init(&newchannel->inbound,
+				 &page[send_ringbuffer_size >> PAGE_SHIFT],
+				 recv_ringbuffer_size >> PAGE_SHIFT);
 	if (ret != 0) {
 		err = ret;
-		goto error0;
+		goto error_free_pages;
 	}
 
 
@@ -131,14 +137,14 @@
 	newchannel->ringbuffer_gpadlhandle = 0;
 
 	ret = vmbus_establish_gpadl(newchannel,
-					 newchannel->outbound.ring_buffer,
-					 send_ringbuffer_size +
-					 recv_ringbuffer_size,
-					 &newchannel->ringbuffer_gpadlhandle);
+				    page_address(page),
+				    send_ringbuffer_size +
+				    recv_ringbuffer_size,
+				    &newchannel->ringbuffer_gpadlhandle);
 
 	if (ret != 0) {
 		err = ret;
-		goto error0;
+		goto error_free_pages;
 	}
 
 	/* Create and init the channel open message */
@@ -147,7 +153,7 @@
 			   GFP_KERNEL);
 	if (!open_info) {
 		err = -ENOMEM;
-		goto error_gpadl;
+		goto error_free_gpadl;
 	}
 
 	init_completion(&open_info->waitevent);
@@ -163,7 +169,7 @@
 
 	if (userdatalen > MAX_USER_DEFINED_BYTES) {
 		err = -EINVAL;
-		goto error_gpadl;
+		goto error_free_gpadl;
 	}
 
 	if (userdatalen)
@@ -175,18 +181,14 @@
 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
 	ret = vmbus_post_msg(open_msg,
-			       sizeof(struct vmbus_channel_open_channel));
+			     sizeof(struct vmbus_channel_open_channel), true);
 
 	if (ret != 0) {
 		err = ret;
-		goto error1;
+		goto error_clean_msglist;
 	}
 
-	t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
-	if (t == 0) {
-		err = -ETIMEDOUT;
-		goto error1;
-	}
+	wait_for_completion(&open_info->waitevent);
 
 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 	list_del(&open_info->msglistentry);
@@ -194,36 +196,52 @@
 
 	if (open_info->response.open_result.status) {
 		err = -EAGAIN;
-		goto error_gpadl;
+		goto error_free_gpadl;
 	}
 
 	newchannel->state = CHANNEL_OPENED_STATE;
 	kfree(open_info);
 	return 0;
 
-error1:
+error_clean_msglist:
 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 	list_del(&open_info->msglistentry);
 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
-error_gpadl:
+error_free_gpadl:
 	vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
-
-error0:
-	free_pages((unsigned long)out,
-		get_order(send_ringbuffer_size + recv_ringbuffer_size));
 	kfree(open_info);
+error_free_pages:
+	hv_ringbuffer_cleanup(&newchannel->outbound);
+	hv_ringbuffer_cleanup(&newchannel->inbound);
+	__free_pages(page,
+		     get_order(send_ringbuffer_size + recv_ringbuffer_size));
+error_set_chnstate:
 	newchannel->state = CHANNEL_OPEN_STATE;
 	return err;
 }
 EXPORT_SYMBOL_GPL(vmbus_open);
 
+/* Used for Hyper-V Socket: a guest client's connect() to the host */
+int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id,
+				  const uuid_le *shv_host_servie_id)
+{
+	struct vmbus_channel_tl_connect_request conn_msg;
+
+	memset(&conn_msg, 0, sizeof(conn_msg));
+	conn_msg.header.msgtype = CHANNELMSG_TL_CONNECT_REQUEST;
+	conn_msg.guest_endpoint_id = *shv_guest_servie_id;
+	conn_msg.host_service_id = *shv_host_servie_id;
+
+	return vmbus_post_msg(&conn_msg, sizeof(conn_msg), true);
+}
+EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request);
+
 /*
  * create_gpadl_header - Creates a gpadl for the specified buffer
  */
 static int create_gpadl_header(void *kbuffer, u32 size,
-					 struct vmbus_channel_msginfo **msginfo,
-					 u32 *messagecount)
+			       struct vmbus_channel_msginfo **msginfo)
 {
 	int i;
 	int pagecount;
@@ -267,7 +285,6 @@
 			gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys(
 				kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT;
 		*msginfo = msgheader;
-		*messagecount = 1;
 
 		pfnsum = pfncount;
 		pfnleft = pagecount - pfncount;
@@ -307,7 +324,6 @@
 			}
 
 			msgbody->msgsize = msgsize;
-			(*messagecount)++;
 			gpadl_body =
 				(struct vmbus_channel_gpadl_body *)msgbody->msg;
 
@@ -336,6 +352,8 @@
 		msgheader = kzalloc(msgsize, GFP_KERNEL);
 		if (msgheader == NULL)
 			goto nomem;
+
+		INIT_LIST_HEAD(&msgheader->submsglist);
 		msgheader->msgsize = msgsize;
 
 		gpadl_header = (struct vmbus_channel_gpadl_header *)
@@ -350,7 +368,6 @@
 				kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT;
 
 		*msginfo = msgheader;
-		*messagecount = 1;
 	}
 
 	return 0;
@@ -374,8 +391,7 @@
 	struct vmbus_channel_gpadl_header *gpadlmsg;
 	struct vmbus_channel_gpadl_body *gpadl_body;
 	struct vmbus_channel_msginfo *msginfo = NULL;
-	struct vmbus_channel_msginfo *submsginfo;
-	u32 msgcount;
+	struct vmbus_channel_msginfo *submsginfo, *tmp;
 	struct list_head *curr;
 	u32 next_gpadl_handle;
 	unsigned long flags;
@@ -384,7 +400,7 @@
 	next_gpadl_handle =
 		(atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);
 
-	ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
+	ret = create_gpadl_header(kbuffer, size, &msginfo);
 	if (ret)
 		return ret;
 
@@ -403,28 +419,25 @@
 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
 	ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize -
-			       sizeof(*msginfo));
+			     sizeof(*msginfo), true);
 	if (ret != 0)
 		goto cleanup;
 
-	if (msgcount > 1) {
-		list_for_each(curr, &msginfo->submsglist) {
-
-			submsginfo = (struct vmbus_channel_msginfo *)curr;
-			gpadl_body =
-			     (struct vmbus_channel_gpadl_body *)submsginfo->msg;
-
-			gpadl_body->header.msgtype =
-				CHANNELMSG_GPADL_BODY;
-			gpadl_body->gpadl = next_gpadl_handle;
-
-			ret = vmbus_post_msg(gpadl_body,
-					       submsginfo->msgsize -
-					       sizeof(*submsginfo));
-			if (ret != 0)
-				goto cleanup;
+	list_for_each(curr, &msginfo->submsglist) {
+		submsginfo = (struct vmbus_channel_msginfo *)curr;
+		gpadl_body =
+			(struct vmbus_channel_gpadl_body *)submsginfo->msg;
+
+		gpadl_body->header.msgtype =
+			CHANNELMSG_GPADL_BODY;
+		gpadl_body->gpadl = next_gpadl_handle;
+
+		ret = vmbus_post_msg(gpadl_body,
+				     submsginfo->msgsize - sizeof(*submsginfo),
+				     true);
+		if (ret != 0)
+			goto cleanup;
 
-		}
 	}
 	wait_for_completion(&msginfo->waitevent);
 
@@ -435,6 +448,10 @@
 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 	list_del(&msginfo->msglistentry);
 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+	list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist,
+				 msglistentry) {
+		kfree(submsginfo);
+	}
 
 	kfree(msginfo);
 	return ret;
@@ -468,8 +485,8 @@
 	list_add_tail(&info->msglistentry,
 		      &vmbus_connection.chn_msg_list);
 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
-	ret = vmbus_post_msg(msg,
-			       sizeof(struct vmbus_channel_gpadl_teardown));
+	ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_gpadl_teardown),
+			     true);
 
 	if (ret)
 		goto post_msg_err;
@@ -498,6 +515,29 @@
 	struct vmbus_channel_close_channel *msg;
 	int ret;
 
+	/*
+	 * process_chn_event(), running in the tasklet, can race
+	 * with vmbus_close_internal() in the case of SMP guest, e.g., when
+	 * the former is accessing channel->inbound.ring_buffer, the latter
+	 * could be freeing the ring_buffer pages.
+	 *
+	 * To resolve the race, we can serialize them by disabling the
+	 * tasklet when the latter is running here.
+	 */
+	hv_event_tasklet_disable(channel);
+
+	/*
+	 * In case a device driver's probe() fails (e.g.,
+	 * util_probe() -> vmbus_open() returns -ENOMEM) and the device is
+	 * rescinded later (e.g., we dynamically disble an Integrated Service
+	 * in Hyper-V Manager), the driver's remove() invokes vmbus_close():
+	 * here we should skip most of the below cleanup work.
+	 */
+	if (channel->state != CHANNEL_OPENED_STATE) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	channel->state = CHANNEL_OPEN_STATE;
 	channel->sc_creation_callback = NULL;
 	/* Stop callback and cancel the timer asap */
@@ -517,7 +557,8 @@
 	msg->header.msgtype = CHANNELMSG_CLOSECHANNEL;
 	msg->child_relid = channel->offermsg.child_relid;
 
-	ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel));
+	ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel),
+			     true);
 
 	if (ret) {
 		pr_err("Close failed: close post msg return is %d\n", ret);
@@ -525,7 +566,7 @@
 		 * If we failed to post the close msg,
 		 * it is perhaps better to leak memory.
 		 */
-		return ret;
+		goto out;
 	}
 
 	/* Tear down the gpadl for the channel's ring buffer */
@@ -538,7 +579,7 @@
 			 * If we failed to teardown gpadl,
 			 * it is perhaps better to leak memory.
 			 */
-			return ret;
+			goto out;
 		}
 	}
 
@@ -549,12 +590,9 @@
 	free_pages((unsigned long)channel->ringbuffer_pages,
 		get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
 
-	/*
-	 * If the channel has been rescinded; process device removal.
-	 */
-	if (channel->rescind)
-		hv_process_channel_removal(channel,
-					   channel->offermsg.child_relid);
+out:
+	hv_event_tasklet_enable(channel);
+
 	return ret;
 }
 
@@ -599,8 +637,7 @@
 	u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
 	struct kvec bufferlist[3];
 	u64 aligned_data = 0;
-	int ret;
-	bool signal = false;
+	bool lock = channel->acquire_ring_lock;
 	int num_vecs = ((bufferlen != 0) ? 3 : 1);
 
 
@@ -619,25 +656,9 @@
 	bufferlist[2].iov_base = &aligned_data;
 	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
-	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs,
-				  &signal);
-
-	/*
-	 * Signalling the host is conditional on many factors:
-	 * 1. The ring state changed from being empty to non-empty.
-	 *    This is tracked by the variable "signal".
-	 * 2. The variable kick_q tracks if more data will be placed
-	 *    on the ring. We will not signal if more data is
-	 *    to be placed.
-	 *
-	 * If we cannot write to the ring-buffer; signal the host
-	 * even if we may not have written anything. This is a rare
-	 * enough condition that it should not matter.
-	 */
-	if (((ret == 0) && kick_q && signal) || (ret))
-		vmbus_setevent(channel);
+	return hv_ringbuffer_write(channel, bufferlist, num_vecs,
+				   lock, kick_q);
 
-	return ret;
 }
 EXPORT_SYMBOL(vmbus_sendpacket_ctl);
 
@@ -678,7 +699,6 @@
 				     u32 flags,
 				     bool kick_q)
 {
-	int ret;
 	int i;
 	struct vmbus_channel_packet_page_buffer desc;
 	u32 descsize;
@@ -686,7 +706,7 @@
 	u32 packetlen_aligned;
 	struct kvec bufferlist[3];
 	u64 aligned_data = 0;
-	bool signal = false;
+	bool lock = channel->acquire_ring_lock;
 
 	if (pagecount > MAX_PAGE_BUFFER_COUNT)
 		return -EINVAL;
@@ -723,24 +743,8 @@
 	bufferlist[2].iov_base = &aligned_data;
 	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
-	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
-
-	/*
-	 * Signalling the host is conditional on many factors:
-	 * 1. The ring state changed from being empty to non-empty.
-	 *    This is tracked by the variable "signal".
-	 * 2. The variable kick_q tracks if more data will be placed
-	 *    on the ring. We will not signal if more data is
-	 *    to be placed.
-	 *
-	 * If we cannot write to the ring-buffer; signal the host
-	 * even if we may not have written anything. This is a rare
-	 * enough condition that it should not matter.
-	 */
-	if (((ret == 0) && kick_q && signal) || (ret))
-		vmbus_setevent(channel);
-
-	return ret;
+	return hv_ringbuffer_write(channel, bufferlist, 3,
+				   lock, kick_q);
 }
 EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer_ctl);
 
@@ -771,12 +775,11 @@
 			      u32 desc_size,
 			      void *buffer, u32 bufferlen, u64 requestid)
 {
-	int ret;
 	u32 packetlen;
 	u32 packetlen_aligned;
 	struct kvec bufferlist[3];
 	u64 aligned_data = 0;
-	bool signal = false;
+	bool lock = channel->acquire_ring_lock;
 
 	packetlen = desc_size + bufferlen;
 	packetlen_aligned = ALIGN(packetlen, sizeof(u64));
@@ -796,12 +799,8 @@
 	bufferlist[2].iov_base = &aligned_data;
 	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
-	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
-
-	if (ret == 0 && signal)
-		vmbus_setevent(channel);
-
-	return ret;
+	return hv_ringbuffer_write(channel, bufferlist, 3,
+				   lock, true);
 }
 EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
 
@@ -813,14 +812,13 @@
 				struct hv_multipage_buffer *multi_pagebuffer,
 				void *buffer, u32 bufferlen, u64 requestid)
 {
-	int ret;
 	struct vmbus_channel_packet_multipage_buffer desc;
 	u32 descsize;
 	u32 packetlen;
 	u32 packetlen_aligned;
 	struct kvec bufferlist[3];
 	u64 aligned_data = 0;
-	bool signal = false;
+	bool lock = channel->acquire_ring_lock;
 	u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
 					 multi_pagebuffer->len);
 
@@ -859,12 +857,8 @@
 	bufferlist[2].iov_base = &aligned_data;
 	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
-	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
-
-	if (ret == 0 && signal)
-		vmbus_setevent(channel);
-
-	return ret;
+	return hv_ringbuffer_write(channel, bufferlist, 3,
+				   lock, true);
 }
 EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
 
@@ -881,46 +875,22 @@
  *
  * Mainly used by Hyper-V drivers.
  */
-int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
-			u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
+static inline int
+__vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+		   u32 bufferlen, u32 *buffer_actual_len, u64 *requestid,
+		   bool raw)
 {
-	struct vmpacket_descriptor desc;
-	u32 packetlen;
-	u32 userlen;
-	int ret;
-	bool signal = false;
-
-	*buffer_actual_len = 0;
-	*requestid = 0;
-
-
-	ret = hv_ringbuffer_peek(&channel->inbound, &desc,
-			     sizeof(struct vmpacket_descriptor));
-	if (ret != 0)
-		return 0;
-
-	packetlen = desc.len8 << 3;
-	userlen = packetlen - (desc.offset8 << 3);
-
-	*buffer_actual_len = userlen;
-
-	if (userlen > bufferlen) {
-
-		pr_err("Buffer too small - got %d needs %d\n",
-			   bufferlen, userlen);
-		return -ETOOSMALL;
-	}
-
-	*requestid = desc.trans_id;
+	return hv_ringbuffer_read(channel, buffer, bufferlen,
+				  buffer_actual_len, requestid, raw);
 
-	/* Copy over the packet to the user buffer */
-	ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen,
-			     (desc.offset8 << 3), &signal);
-
-	if (signal)
-		vmbus_setevent(channel);
+}
 
-	return 0;
+int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+		     u32 bufferlen, u32 *buffer_actual_len,
+		     u64 *requestid)
+{
+	return __vmbus_recvpacket(channel, buffer, bufferlen,
+				  buffer_actual_len, requestid, false);
 }
 EXPORT_SYMBOL(vmbus_recvpacket);
 
@@ -931,37 +901,7 @@
 			      u32 bufferlen, u32 *buffer_actual_len,
 			      u64 *requestid)
 {
-	struct vmpacket_descriptor desc;
-	u32 packetlen;
-	int ret;
-	bool signal = false;
-
-	*buffer_actual_len = 0;
-	*requestid = 0;
-
-
-	ret = hv_ringbuffer_peek(&channel->inbound, &desc,
-			     sizeof(struct vmpacket_descriptor));
-	if (ret != 0)
-		return 0;
-
-
-	packetlen = desc.len8 << 3;
-
-	*buffer_actual_len = packetlen;
-
-	if (packetlen > bufferlen)
-		return -ENOBUFS;
-
-	*requestid = desc.trans_id;
-
-	/* Copy over the entire packet to the user buffer */
-	ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0,
-				 &signal);
-
-	if (signal)
-		vmbus_setevent(channel);
-
-	return ret;
+	return __vmbus_recvpacket(channel, buffer, bufferlen,
+				  buffer_actual_len, requestid, true);
 }
 EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
--- linux-4.4.0.orig/drivers/hv/channel_mgmt.c
+++ linux-4.4.0/drivers/hv/channel_mgmt.c
@@ -21,6 +21,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/mm.h>
@@ -28,12 +29,149 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/completion.h>
+#include <linux/delay.h>
 #include <linux/hyperv.h>
 
 #include "hyperv_vmbus.h"
 
-static void init_vp_index(struct vmbus_channel *channel,
-			  const uuid_le *type_guid);
+static void init_vp_index(struct vmbus_channel *channel, u16 dev_type);
+
+static const struct vmbus_device vmbus_devs[] = {
+	/* IDE */
+	{ .dev_type = HV_IDE,
+	  HV_IDE_GUID,
+	  .perf_device = true,
+	},
+
+	/* SCSI */
+	{ .dev_type = HV_SCSI,
+	  HV_SCSI_GUID,
+	  .perf_device = true,
+	},
+
+	/* Fibre Channel */
+	{ .dev_type = HV_FC,
+	  HV_SYNTHFC_GUID,
+	  .perf_device = true,
+	},
+
+	/* Synthetic NIC */
+	{ .dev_type = HV_NIC,
+	  HV_NIC_GUID,
+	  .perf_device = true,
+	},
+
+	/* Network Direct */
+	{ .dev_type = HV_ND,
+	  HV_ND_GUID,
+	  .perf_device = true,
+	},
+
+	/* PCIE */
+	{ .dev_type = HV_PCIE,
+	  HV_PCIE_GUID,
+	  .perf_device = true,
+	},
+
+	/* Synthetic Frame Buffer */
+	{ .dev_type = HV_FB,
+	  HV_SYNTHVID_GUID,
+	  .perf_device = false,
+	},
+
+	/* Synthetic Keyboard */
+	{ .dev_type = HV_KBD,
+	  HV_KBD_GUID,
+	  .perf_device = false,
+	},
+
+	/* Synthetic MOUSE */
+	{ .dev_type = HV_MOUSE,
+	  HV_MOUSE_GUID,
+	  .perf_device = false,
+	},
+
+	/* KVP */
+	{ .dev_type = HV_KVP,
+	  HV_KVP_GUID,
+	  .perf_device = false,
+	},
+
+	/* Time Synch */
+	{ .dev_type = HV_TS,
+	  HV_TS_GUID,
+	  .perf_device = false,
+	},
+
+	/* Heartbeat */
+	{ .dev_type = HV_HB,
+	  HV_HEART_BEAT_GUID,
+	  .perf_device = false,
+	},
+
+	/* Shutdown */
+	{ .dev_type = HV_SHUTDOWN,
+	  HV_SHUTDOWN_GUID,
+	  .perf_device = false,
+	},
+
+	/* File copy */
+	{ .dev_type = HV_FCOPY,
+	  HV_FCOPY_GUID,
+	  .perf_device = false,
+	},
+
+	/* Backup */
+	{ .dev_type = HV_BACKUP,
+	  HV_VSS_GUID,
+	  .perf_device = false,
+	},
+
+	/* Dynamic Memory */
+	{ .dev_type = HV_DM,
+	  HV_DM_GUID,
+	  .perf_device = false,
+	},
+
+	/* Unknown GUID */
+	{ .dev_type = HV_UNKOWN,
+	  .perf_device = false,
+	},
+};
+
+static const struct {
+	uuid_le guid;
+} vmbus_unsupported_devs[] = {
+	{ HV_AVMA1_GUID },
+	{ HV_AVMA2_GUID },
+	{ HV_RDV_GUID	},
+};
+
+static bool is_unsupported_vmbus_devs(const uuid_le *guid)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vmbus_unsupported_devs); i++)
+		if (!uuid_le_cmp(*guid, vmbus_unsupported_devs[i].guid))
+			return true;
+	return false;
+}
+
+static u16 hv_get_dev_type(const struct vmbus_channel *channel)
+{
+	const uuid_le *guid = &channel->offermsg.offer.if_type;
+	u16 i;
+
+	if (is_hvsock_channel(channel) || is_unsupported_vmbus_devs(guid))
+		return HV_UNKOWN;
+
+	for (i = HV_IDE; i < HV_UNKOWN; i++) {
+		if (!uuid_le_cmp(*guid, vmbus_devs[i].guid))
+			return i;
+	}
+	pr_info("Unknown GUID: %pUl\n", guid);
+	return i;
+}
 
 /**
  * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
@@ -136,14 +274,13 @@
  */
 static struct vmbus_channel *alloc_channel(void)
 {
-	static atomic_t chan_num = ATOMIC_INIT(0);
 	struct vmbus_channel *channel;
 
 	channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
 	if (!channel)
 		return NULL;
 
-	channel->id = atomic_inc_return(&chan_num);
+	channel->acquire_ring_lock = true;
 	spin_lock_init(&channel->inbound_lock);
 	spin_lock_init(&channel->lock);
 
@@ -177,20 +314,43 @@
 }
 
 
-void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
+static void vmbus_release_relid(u32 relid)
 {
 	struct vmbus_channel_relid_released msg;
-	unsigned long flags;
-	struct vmbus_channel *primary_channel;
 
 	memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
 	msg.child_relid = relid;
 	msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
-	vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
+	vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released),
+		       true);
+}
 
-	if (channel == NULL)
-		return;
+void hv_event_tasklet_disable(struct vmbus_channel *channel)
+{
+	struct tasklet_struct *tasklet;
+	tasklet = hv_context.event_dpc[channel->target_cpu];
+	tasklet_disable(tasklet);
+}
+
+void hv_event_tasklet_enable(struct vmbus_channel *channel)
+{
+	struct tasklet_struct *tasklet;
+	tasklet = hv_context.event_dpc[channel->target_cpu];
+	tasklet_enable(tasklet);
+
+	/* In case there is any pending event */
+	tasklet_schedule(tasklet);
+}
 
+void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
+{
+	unsigned long flags;
+	struct vmbus_channel *primary_channel;
+
+	BUG_ON(!channel->rescind);
+	BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
+
+	hv_event_tasklet_disable(channel);
 	if (channel->target_cpu != get_cpu()) {
 		put_cpu();
 		smp_call_function_single(channel->target_cpu,
@@ -199,11 +359,10 @@
 		percpu_channel_deq(channel);
 		put_cpu();
 	}
+	hv_event_tasklet_enable(channel);
 
 	if (channel->primary_channel == NULL) {
-		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
 		list_del(&channel->listentry);
-		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
 
 		primary_channel = channel;
 	} else {
@@ -218,8 +377,11 @@
 	 * We need to free the bit for init_vp_index() to work in the case
 	 * of sub-channel, when we reload drivers like hv_netvsc.
 	 */
-	cpumask_clear_cpu(channel->target_cpu,
-			  &primary_channel->alloced_cpus_in_node);
+	if (channel->affinity_policy == HV_LOCALIZED)
+		cpumask_clear_cpu(channel->target_cpu,
+				  &primary_channel->alloced_cpus_in_node);
+
+	vmbus_release_relid(relid);
 
 	free_channel(channel);
 }
@@ -230,9 +392,7 @@
 
 	list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
 		listentry) {
-		/* if we don't set rescind to true, vmbus_close_internal()
-		 * won't invoke hv_process_channel_removal().
-		 */
+		/* hv_process_channel_removal() needs this */
 		channel->rescind = true;
 
 		vmbus_device_unregister(channel->device_obj);
@@ -248,9 +408,11 @@
 	struct vmbus_channel *channel;
 	bool fnew = true;
 	unsigned long flags;
+	u16 dev_type;
+	int ret;
 
 	/* Make sure this is a new offer */
-	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+	mutex_lock(&vmbus_connection.channel_mutex);
 
 	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
 		if (!uuid_le_cmp(channel->offermsg.offer.if_type,
@@ -266,7 +428,7 @@
 		list_add_tail(&newchannel->listentry,
 			      &vmbus_connection.chn_list);
 
-	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+	mutex_unlock(&vmbus_connection.channel_mutex);
 
 	if (!fnew) {
 		/*
@@ -285,8 +447,11 @@
 			goto err_free_chan;
 	}
 
-	init_vp_index(newchannel, &newchannel->offermsg.offer.if_type);
+	dev_type = hv_get_dev_type(newchannel);
 
+	init_vp_index(newchannel, dev_type);
+
+	hv_event_tasklet_disable(newchannel);
 	if (newchannel->target_cpu != get_cpu()) {
 		put_cpu();
 		smp_call_function_single(newchannel->target_cpu,
@@ -296,6 +461,7 @@
 		percpu_channel_enq(newchannel);
 		put_cpu();
 	}
+	hv_event_tasklet_enable(newchannel);
 
 	/*
 	 * This state is used to indicate a successful open
@@ -322,12 +488,17 @@
 	if (!newchannel->device_obj)
 		goto err_deq_chan;
 
+	newchannel->device_obj->device_id = dev_type;
 	/*
 	 * Add the new device to the bus. This will kick off device-driver
 	 * binding which eventually invokes the device driver's AddDevice()
 	 * method.
 	 */
-	if (vmbus_device_register(newchannel->device_obj) != 0) {
+	mutex_lock(&vmbus_connection.channel_mutex);
+	ret = vmbus_device_register(newchannel->device_obj);
+	mutex_unlock(&vmbus_connection.channel_mutex);
+
+	if (ret != 0) {
 		pr_err("unable to add child device object (relid %d)\n",
 			newchannel->offermsg.child_relid);
 		kfree(newchannel->device_obj);
@@ -336,10 +507,11 @@
 	return;
 
 err_deq_chan:
-	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+	mutex_lock(&vmbus_connection.channel_mutex);
 	list_del(&newchannel->listentry);
-	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+	mutex_unlock(&vmbus_connection.channel_mutex);
 
+	hv_event_tasklet_disable(newchannel);
 	if (newchannel->target_cpu != get_cpu()) {
 		put_cpu();
 		smp_call_function_single(newchannel->target_cpu,
@@ -348,36 +520,14 @@
 		percpu_channel_deq(newchannel);
 		put_cpu();
 	}
+	hv_event_tasklet_enable(newchannel);
+
+	vmbus_release_relid(newchannel->offermsg.child_relid);
 
 err_free_chan:
 	free_channel(newchannel);
 }
 
-enum {
-	IDE = 0,
-	SCSI,
-	NIC,
-	ND_NIC,
-	MAX_PERF_CHN,
-};
-
-/*
- * This is an array of device_ids (device types) that are performance critical.
- * We attempt to distribute the interrupt load for these devices across
- * all available CPUs.
- */
-static const struct hv_vmbus_device_id hp_devs[] = {
-	/* IDE */
-	{ HV_IDE_GUID, },
-	/* Storage - SCSI */
-	{ HV_SCSI_GUID, },
-	/* Network */
-	{ HV_NIC_GUID, },
-	/* NetworkDirect Guest RDMA */
-	{ HV_ND_GUID, },
-};
-
-
 /*
  * We use this state to statically distribute the channel interrupt load.
  */
@@ -394,23 +544,15 @@
  * For pre-win8 hosts or non-performance critical channels we assign the
  * first CPU in the first NUMA node.
  */
-static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_guid)
+static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
 {
 	u32 cur_cpu;
-	int i;
-	bool perf_chn = false;
+	bool perf_chn = vmbus_devs[dev_type].perf_device;
 	struct vmbus_channel *primary = channel->primary_channel;
 	int next_node;
 	struct cpumask available_mask;
 	struct cpumask *alloced_mask;
 
-	for (i = IDE; i < MAX_PERF_CHN; i++) {
-		if (!memcmp(type_guid->b, hp_devs[i].guid,
-				 sizeof(uuid_le))) {
-			perf_chn = true;
-			break;
-		}
-	}
 	if ((vmbus_proto_version == VERSION_WS2008) ||
 	    (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) {
 		/*
@@ -426,17 +568,17 @@
 	}
 
 	/*
-	 * We distribute primary channels evenly across all the available
-	 * NUMA nodes and within the assigned NUMA node we will assign the
-	 * first available CPU to the primary channel.
-	 * The sub-channels will be assigned to the CPUs available in the
-	 * NUMA node evenly.
+	 * Based on the channel affinity policy, we will assign the NUMA
+	 * nodes.
 	 */
-	if (!primary) {
+
+	if ((channel->affinity_policy == HV_BALANCED) || (!primary)) {
 		while (true) {
 			next_node = next_numa_node_id++;
-			if (next_node == nr_node_ids)
+			if (next_node == nr_node_ids) {
 				next_node = next_numa_node_id = 0;
+				continue;
+			}
 			if (cpumask_empty(cpumask_of_node(next_node)))
 				continue;
 			break;
@@ -459,6 +601,19 @@
 		    cpumask_of_node(primary->numa_node));
 
 	cur_cpu = -1;
+
+	if (primary->affinity_policy == HV_LOCALIZED) {
+		/*
+		 * Normally Hyper-V host doesn't create more subchannels
+		 * than there are VCPUs on the node but it is possible when not
+		 * all present VCPUs on the node are initialized by guest.
+		 * Clear the alloced_cpus_in_node to start over.
+		 */
+		if (cpumask_equal(&primary->alloced_cpus_in_node,
+				  cpumask_of_node(primary->numa_node)))
+			cpumask_clear(&primary->alloced_cpus_in_node);
+	}
+
 	while (true) {
 		cur_cpu = cpumask_next(cur_cpu, &available_mask);
 		if (cur_cpu >= nr_cpu_ids) {
@@ -468,17 +623,24 @@
 			continue;
 		}
 
-		/*
-		 * NOTE: in the case of sub-channel, we clear the sub-channel
-		 * related bit(s) in primary->alloced_cpus_in_node in
-		 * hv_process_channel_removal(), so when we reload drivers
-		 * like hv_netvsc in SMP guest, here we're able to re-allocate
-		 * bit from primary->alloced_cpus_in_node.
-		 */
-		if (!cpumask_test_cpu(cur_cpu,
-				&primary->alloced_cpus_in_node)) {
-			cpumask_set_cpu(cur_cpu,
-					&primary->alloced_cpus_in_node);
+		if (primary->affinity_policy == HV_LOCALIZED) {
+			/*
+			 * NOTE: in the case of sub-channel, we clear the
+			 * sub-channel related bit(s) in
+			 * primary->alloced_cpus_in_node in
+			 * hv_process_channel_removal(), so when we
+			 * reload drivers like hv_netvsc in SMP guest, here
+			 * we're able to re-allocate
+			 * bit from primary->alloced_cpus_in_node.
+			 */
+			if (!cpumask_test_cpu(cur_cpu,
+					      &primary->alloced_cpus_in_node)) {
+				cpumask_set_cpu(cur_cpu,
+						&primary->alloced_cpus_in_node);
+				cpumask_set_cpu(cur_cpu, alloced_mask);
+				break;
+			}
+		} else {
 			cpumask_set_cpu(cur_cpu, alloced_mask);
 			break;
 		}
@@ -488,6 +650,60 @@
 	channel->target_vp = hv_context.vp_index[cur_cpu];
 }
 
+static void vmbus_wait_for_unload(void)
+{
+	int cpu;
+	void *page_addr;
+	struct hv_message *msg;
+	struct vmbus_channel_message_header *hdr;
+	u32 message_type;
+
+	/*
+	 * CHANNELMSG_UNLOAD_RESPONSE is always delivered to the CPU which was
+	 * used for initial contact or to CPU0 depending on host version. When
+	 * we're crashing on a different CPU let's hope that IRQ handler on
+	 * the cpu which receives CHANNELMSG_UNLOAD_RESPONSE is still
+	 * functional and vmbus_unload_response() will complete
+	 * vmbus_connection.unload_event. If not, the last thing we can do is
+	 * read message pages for all CPUs directly.
+	 */
+	while (1) {
+		if (completion_done(&vmbus_connection.unload_event))
+			break;
+
+		for_each_online_cpu(cpu) {
+			page_addr = hv_context.synic_message_page[cpu];
+			msg = (struct hv_message *)page_addr +
+				VMBUS_MESSAGE_SINT;
+
+			message_type = READ_ONCE(msg->header.message_type);
+			if (message_type == HVMSG_NONE)
+				continue;
+
+			hdr = (struct vmbus_channel_message_header *)
+				msg->u.payload;
+
+			if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE)
+				complete(&vmbus_connection.unload_event);
+
+			vmbus_signal_eom(msg, message_type);
+		}
+
+		mdelay(10);
+	}
+
+	/*
+	 * We're crashing and already got the UNLOAD_RESPONSE, cleanup all
+	 * maybe-pending messages on all CPUs to be able to receive new
+	 * messages after we reconnect.
+	 */
+	for_each_online_cpu(cpu) {
+		page_addr = hv_context.synic_message_page[cpu];
+		msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
+		msg->header.message_type = HVMSG_NONE;
+	}
+}
+
 /*
  * vmbus_unload_response - Handler for the unload response.
  */
@@ -500,7 +716,7 @@
 	complete(&vmbus_connection.unload_event);
 }
 
-void vmbus_initiate_unload(void)
+void vmbus_initiate_unload(bool crash)
 {
 	struct vmbus_channel_message_header hdr;
 
@@ -511,9 +727,17 @@
 	init_completion(&vmbus_connection.unload_event);
 	memset(&hdr, 0, sizeof(struct vmbus_channel_message_header));
 	hdr.msgtype = CHANNELMSG_UNLOAD;
-	vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header));
+	vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header),
+		       !crash);
 
-	wait_for_completion(&vmbus_connection.unload_event);
+	/*
+	 * vmbus_initiate_unload() is also called on crash and the crash can be
+	 * happening in an interrupt context, where scheduling is impossible.
+	 */
+	if (!crash)
+		wait_for_completion(&vmbus_connection.unload_event);
+	else
+		vmbus_wait_for_unload();
 }
 
 /*
@@ -582,11 +806,17 @@
 	struct device *dev;
 
 	rescind = (struct vmbus_channel_rescind_offer *)hdr;
+
+	mutex_lock(&vmbus_connection.channel_mutex);
 	channel = relid2channel(rescind->child_relid);
 
 	if (channel == NULL) {
-		hv_process_channel_removal(NULL, rescind->child_relid);
-		return;
+		/*
+		 * This is very impossible, because in
+		 * vmbus_process_offer(), we have already invoked
+		 * vmbus_release_relid() on error.
+		 */
+		goto out;
 	}
 
 	spin_lock_irqsave(&channel->lock, flags);
@@ -594,6 +824,10 @@
 	spin_unlock_irqrestore(&channel->lock, flags);
 
 	if (channel->device_obj) {
+		if (channel->chn_rescind_callback) {
+			channel->chn_rescind_callback(channel);
+			goto out;
+		}
 		/*
 		 * We will have to unregister this device from the
 		 * driver core.
@@ -607,8 +841,25 @@
 		hv_process_channel_removal(channel,
 			channel->offermsg.child_relid);
 	}
+
+out:
+	mutex_unlock(&vmbus_connection.channel_mutex);
 }
 
+void vmbus_hvsock_device_unregister(struct vmbus_channel *channel)
+{
+	mutex_lock(&vmbus_connection.channel_mutex);
+
+	BUG_ON(!is_hvsock_channel(channel));
+
+	channel->rescind = true;
+	vmbus_device_unregister(channel->device_obj);
+
+	mutex_unlock(&vmbus_connection.channel_mutex);
+}
+EXPORT_SYMBOL_GPL(vmbus_hvsock_device_unregister);
+
+
 /*
  * vmbus_onoffers_delivered -
  * This is invoked when all offers have been delivered.
@@ -811,6 +1062,10 @@
 	{CHANNELMSG_VERSION_RESPONSE,		1, vmbus_onversion_response},
 	{CHANNELMSG_UNLOAD,			0, NULL},
 	{CHANNELMSG_UNLOAD_RESPONSE,		1, vmbus_unload_response},
+	{CHANNELMSG_18,				0, NULL},
+	{CHANNELMSG_19,				0, NULL},
+	{CHANNELMSG_20,				0, NULL},
+	{CHANNELMSG_TL_CONNECT_REQUEST,		0, NULL},
 };
 
 /*
@@ -861,8 +1116,8 @@
 	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
 
 
-	ret = vmbus_post_msg(msg,
-			       sizeof(struct vmbus_channel_message_header));
+	ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_message_header),
+			     true);
 	if (ret != 0) {
 		pr_err("Unable to request offers - %d\n", ret);
 
@@ -959,3 +1214,10 @@
 	return ret;
 }
 EXPORT_SYMBOL_GPL(vmbus_are_subchannels_present);
+
+void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel,
+		void (*chn_rescind_cb)(struct vmbus_channel *))
+{
+	channel->chn_rescind_callback = chn_rescind_cb;
+}
+EXPORT_SYMBOL_GPL(vmbus_set_chn_rescind_callback);
--- linux-4.4.0.orig/drivers/hv/connection.c
+++ linux-4.4.0/drivers/hv/connection.c
@@ -83,9 +83,20 @@
 	msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
 	msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
 	msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
+	/*
+	 * We want all channel messages to be delivered on CPU 0.
+	 * This has been the behavior pre-win8. This is not
+	 * perf issue and having all channel messages delivered on CPU 0
+	 * would be ok.
+	 * For post win8 hosts, we support receiving channel messagges on
+	 * all the CPUs. This is needed for kexec to work correctly where
+	 * the CPU attempting to connect may not be CPU 0.
+	 */
 	if (version >= VERSION_WIN8_1) {
 		msg->target_vcpu = hv_context.vp_index[get_cpu()];
 		put_cpu();
+	} else {
+		msg->target_vcpu = 0;
 	}
 
 	/*
@@ -99,7 +110,8 @@
 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
 	ret = vmbus_post_msg(msg,
-			       sizeof(struct vmbus_channel_initiate_contact));
+			     sizeof(struct vmbus_channel_initiate_contact),
+			     true);
 	if (ret != 0) {
 		spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 		list_del(&msginfo->msglistentry);
@@ -146,7 +158,7 @@
 	spin_lock_init(&vmbus_connection.channelmsg_lock);
 
 	INIT_LIST_HEAD(&vmbus_connection.chn_list);
-	spin_lock_init(&vmbus_connection.channel_lock);
+	mutex_init(&vmbus_connection.channel_mutex);
 
 	/*
 	 * Setup the vmbus event connection for channel interrupt
@@ -233,7 +245,7 @@
 	/*
 	 * First send the unload request to the host.
 	 */
-	vmbus_initiate_unload();
+	vmbus_initiate_unload(false);
 
 	if (vmbus_connection.work_queue) {
 		drain_workqueue(vmbus_connection.work_queue);
@@ -282,11 +294,11 @@
 {
 	struct vmbus_channel *channel;
 	struct vmbus_channel *found_channel  = NULL;
-	unsigned long flags;
 	struct list_head *cur, *tmp;
 	struct vmbus_channel *cur_sc;
 
-	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+	BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
+
 	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
 		if (channel->offermsg.child_relid == relid) {
 			found_channel = channel;
@@ -305,7 +317,6 @@
 			}
 		}
 	}
-	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
 
 	return found_channel;
 }
@@ -424,12 +435,12 @@
 /*
  * vmbus_post_msg - Send a msg on the vmbus's message connection
  */
-int vmbus_post_msg(void *buffer, size_t buflen)
+int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
 {
 	union hv_connection_id conn_id;
 	int ret = 0;
 	int retries = 0;
-	u32 msec = 1;
+	u32 usec = 1;
 
 	conn_id.asu32 = 0;
 	conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
@@ -439,7 +450,7 @@
 	 * insufficient resources. Retry the operation a couple of
 	 * times before giving up.
 	 */
-	while (retries < 20) {
+	while (retries < 100) {
 		ret = hv_post_message(conn_id, 1, buffer, buflen);
 
 		switch (ret) {
@@ -462,9 +473,15 @@
 		}
 
 		retries++;
-		msleep(msec);
-		if (msec < 2048)
-			msec *= 2;
+		if (can_sleep && usec > 1000)
+			msleep(usec / 1000);
+		else if (usec < MAX_UDELAY_MS * 1000)
+			udelay(usec);
+		else
+			mdelay(usec / 1000);
+
+		if (usec < 256000)
+			usec *= 2;
 	}
 	return ret;
 }
@@ -472,7 +489,7 @@
 /*
  * vmbus_set_event - Send an event notification to the parent
  */
-int vmbus_set_event(struct vmbus_channel *channel)
+void vmbus_set_event(struct vmbus_channel *channel)
 {
 	u32 child_relid = channel->offermsg.child_relid;
 
@@ -483,5 +500,6 @@
 			(child_relid >> 5));
 	}
 
-	return hv_signal_event(channel->sig_event);
+	hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL);
 }
+EXPORT_SYMBOL_GPL(vmbus_set_event);
--- linux-4.4.0.orig/drivers/hv/hv.c
+++ linux-4.4.0/drivers/hv/hv.c
@@ -31,8 +31,17 @@
 #include <linux/clockchips.h>
 #include <asm/hyperv.h>
 #include <asm/mshyperv.h>
+#include <asm/nospec-branch.h>
 #include "hyperv_vmbus.h"
 
+#ifndef PKG_ABI
+/*
+ * Preserve the ability to 'make deb-pkg' since PKG_ABI is provided
+ * by the Ubuntu build rules.
+ */
+#define PKG_ABI 0
+#endif
+
 /* The one and only */
 struct hv_context hv_context = {
 	.synic_initialized	= false,
@@ -89,9 +98,9 @@
 }
 
 /*
- * do_hypercall- Invoke the specified hypercall
+ * hv_do_hypercall- Invoke the specified hypercall
  */
-static u64 do_hypercall(u64 control, void *input, void *output)
+u64 hv_do_hypercall(u64 control, void *input, void *output)
 {
 	u64 input_address = (input) ? virt_to_phys(input) : 0;
 	u64 output_address = (output) ? virt_to_phys(output) : 0;
@@ -103,9 +112,10 @@
 		return (u64)ULLONG_MAX;
 
 	__asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
-	__asm__ __volatile__("call *%3" : "=a" (hv_status) :
+	__asm__ __volatile__(CALL_NOSPEC :
+			     "=a" (hv_status) :
 			     "c" (control), "d" (input_address),
-			     "m" (hypercall_page));
+			     THUNK_TARGET(hypercall_page));
 
 	return hv_status;
 
@@ -123,15 +133,17 @@
 	if (!hypercall_page)
 		return (u64)ULLONG_MAX;
 
-	__asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
+	__asm__ __volatile__ (CALL_NOSPEC : "=d"(hv_status_hi),
 			      "=a"(hv_status_lo) : "d" (control_hi),
 			      "a" (control_lo), "b" (input_address_hi),
 			      "c" (input_address_lo), "D"(output_address_hi),
-			      "S"(output_address_lo), "m" (hypercall_page));
+			      "S"(output_address_lo),
+			      THUNK_TARGET(hypercall_page));
 
 	return hv_status_lo | ((u64)hv_status_hi << 32);
 #endif /* !x86_64 */
 }
+EXPORT_SYMBOL_GPL(hv_do_hypercall);
 
 #ifdef CONFIG_X86_64
 static cycle_t read_hv_clock_tsc(struct clocksource *arg)
@@ -139,7 +151,7 @@
 	cycle_t current_tick;
 	struct ms_hyperv_tsc_page *tsc_pg = hv_context.tsc_page;
 
-	if (tsc_pg->tsc_sequence != -1) {
+	if (tsc_pg->tsc_sequence != 0) {
 		/*
 		 * Use the tsc page to compute the value.
 		 */
@@ -161,7 +173,7 @@
 			if (tsc_pg->tsc_sequence == sequence)
 				return current_tick;
 
-			if (tsc_pg->tsc_sequence != -1)
+			if (tsc_pg->tsc_sequence != 0)
 				continue;
 			/*
 			 * Fallback using MSR method.
@@ -182,6 +194,28 @@
 };
 #endif
 
+static cycle_t read_hv_clock_msr(struct clocksource *arg)
+{
+	cycle_t current_tick;
+	/*
+	 * Read the partition counter to get the current tick count. This count
+	 * is set to 0 when the partition is created and is incremented in
+	 * 100 nanosecond units.
+	 */
+	rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+	return current_tick;
+}
+
+static struct clocksource hyperv_cs_msr = {
+	.name		= "hyperv_clocksource_msr",
+	.rating		= 400, /* use this when running on Hyperv*/
+	.read		= read_hv_clock_msr,
+	.mask		= CLOCKSOURCE_MASK(64),
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+struct clocksource *hyperv_cs;
+EXPORT_SYMBOL_GPL(hyperv_cs);
 
 /*
  * hv_init - Main initialization routine.
@@ -192,9 +226,7 @@
 {
 	int max_leaf;
 	union hv_x64_msr_hypercall_contents hypercall_msr;
-	union hv_x64_msr_hypercall_contents tsc_msr;
 	void *virtaddr = NULL;
-	void *va_tsc = NULL;
 
 	memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
 	memset(hv_context.synic_message_page, 0,
@@ -205,6 +237,8 @@
 	       sizeof(int) * NR_CPUS);
 	memset(hv_context.event_dpc, 0,
 	       sizeof(void *) * NR_CPUS);
+	memset(hv_context.msg_dpc, 0,
+	       sizeof(void *) * NR_CPUS);
 	memset(hv_context.clk_evt, 0,
 	       sizeof(void *) * NR_CPUS);
 
@@ -213,13 +247,13 @@
 	/*
 	 * Write our OS ID.
 	 */
-	hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0);
+	hv_context.guestid = generate_guest_id(0x80 /*Canonical*/, LINUX_VERSION_CODE, PKG_ABI);
 	wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
 
 	/* See if the hypercall page is already set */
 	rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 
-	virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
+	virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX);
 
 	if (!virtaddr)
 		goto cleanup;
@@ -240,11 +274,16 @@
 
 #ifdef CONFIG_X86_64
 	if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
+		union hv_x64_msr_hypercall_contents tsc_msr;
+		void *va_tsc;
+
 		va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
 		if (!va_tsc)
-			goto cleanup;
+			goto register_msr_cs;
 		hv_context.tsc_page = va_tsc;
 
+		hyperv_cs = &hyperv_cs_tsc;
+
 		rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
 
 		tsc_msr.enable = 1;
@@ -253,7 +292,17 @@
 		wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
 		clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
 	}
+register_msr_cs:
 #endif
+	/*
+	 * For 32 bit guests just use the MSR based mechanism for reading
+	 * the partition counter.
+	 */
+
+	hyperv_cs = &hyperv_cs_msr;
+	if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
+		clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
+
 	return 0;
 
 cleanup:
@@ -274,7 +323,7 @@
  *
  * This routine is called normally during driver unloading or exiting.
  */
-void hv_cleanup(void)
+void hv_cleanup(bool crash)
 {
 	union hv_x64_msr_hypercall_contents hypercall_msr;
 
@@ -284,7 +333,8 @@
 	if (hv_context.hypercall_page) {
 		hypercall_msr.as_uint64 = 0;
 		wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-		vfree(hv_context.hypercall_page);
+		if (!crash)
+			vfree(hv_context.hypercall_page);
 		hv_context.hypercall_page = NULL;
 	}
 
@@ -293,13 +343,21 @@
 	 * Cleanup the TSC page based CS.
 	 */
 	if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
-		clocksource_change_rating(&hyperv_cs_tsc, 10);
-		clocksource_unregister(&hyperv_cs_tsc);
+		/*
+		 * Crash can happen in an interrupt context and unregistering
+		 * a clocksource is impossible and redundant in this case.
+		 */
+		if (!oops_in_progress) {
+			clocksource_change_rating(&hyperv_cs_tsc, 10);
+			clocksource_unregister(&hyperv_cs_tsc);
+		}
 
 		hypercall_msr.as_uint64 = 0;
 		wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
-		vfree(hv_context.tsc_page);
-		hv_context.tsc_page = NULL;
+		if (!crash) {
+			vfree(hv_context.tsc_page);
+			hv_context.tsc_page = NULL;
+		}
 	}
 #endif
 }
@@ -315,7 +373,7 @@
 {
 
 	struct hv_input_post_message *aligned_msg;
-	u16 status;
+	u64 status;
 
 	if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
 		return -EMSGSIZE;
@@ -329,27 +387,10 @@
 	aligned_msg->payload_size = payload_size;
 	memcpy((void *)aligned_msg->payload, payload, payload_size);
 
-	status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
-		& 0xFFFF;
+	status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL);
 
 	put_cpu();
-	return status;
-}
-
-
-/*
- * hv_signal_event -
- * Signal an event on the specified connection using the hypervisor event IPC.
- *
- * This involves a hypercall.
- */
-u16 hv_signal_event(void *con_id)
-{
-	u16 status;
-
-	status = (do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL) & 0xFFFF);
-
-	return status;
+	return status & 0xFFFF;
 }
 
 static int hv_ce_set_next_event(unsigned long delta,
@@ -416,7 +457,7 @@
 		goto err;
 	}
 
-	for_each_online_cpu(cpu) {
+	for_each_present_cpu(cpu) {
 		hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
 		if (hv_context.event_dpc[cpu] == NULL) {
 			pr_err("Unable to allocate event dpc\n");
@@ -424,6 +465,13 @@
 		}
 		tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
 
+		hv_context.msg_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
+		if (hv_context.msg_dpc[cpu] == NULL) {
+			pr_err("Unable to allocate event dpc\n");
+			goto err;
+		}
+		tasklet_init(hv_context.msg_dpc[cpu], vmbus_on_msg_dpc, cpu);
+
 		hv_context.clk_evt[cpu] = kzalloc(ced_size, GFP_ATOMIC);
 		if (hv_context.clk_evt[cpu] == NULL) {
 			pr_err("Unable to allocate clock event device\n");
@@ -455,6 +503,8 @@
 			pr_err("Unable to allocate post msg page\n");
 			goto err;
 		}
+
+		INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
 	}
 
 	return 0;
@@ -465,6 +515,7 @@
 static void hv_synic_free_cpu(int cpu)
 {
 	kfree(hv_context.event_dpc[cpu]);
+	kfree(hv_context.msg_dpc[cpu]);
 	kfree(hv_context.clk_evt[cpu]);
 	if (hv_context.synic_event_page[cpu])
 		free_page((unsigned long)hv_context.synic_event_page[cpu]);
@@ -479,7 +530,7 @@
 	int cpu;
 
 	kfree(hv_context.hv_numa_map);
-	for_each_online_cpu(cpu)
+	for_each_present_cpu(cpu)
 		hv_synic_free_cpu(cpu);
 }
 
@@ -549,8 +600,6 @@
 	rdmsrl(HV_X64_MSR_VP_INDEX, vp_index);
 	hv_context.vp_index[cpu] = (u32)vp_index;
 
-	INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
-
 	/*
 	 * Register the per-cpu clockevent source.
 	 */
--- linux-4.4.0.orig/drivers/hv/hv_balloon.c
+++ linux-4.4.0/drivers/hv/hv_balloon.c
@@ -430,16 +430,27 @@
  * currently hot added. We hot add in multiples of 128M
  * chunks; it is possible that we may not be able to bring
  * online all the pages in the region. The range
- * covered_end_pfn defines the pages that can
+ * covered_start_pfn:covered_end_pfn defines the pages that can
  * be brough online.
  */
 
 struct hv_hotadd_state {
 	struct list_head list;
 	unsigned long start_pfn;
+	unsigned long covered_start_pfn;
 	unsigned long covered_end_pfn;
 	unsigned long ha_end_pfn;
 	unsigned long end_pfn;
+	/*
+	 * A list of gaps.
+	 */
+	struct list_head gap_list;
+};
+
+struct hv_hotadd_gap {
+	struct list_head list;
+	unsigned long start_pfn;
+	unsigned long end_pfn;
 };
 
 struct balloon_state {
@@ -536,7 +547,11 @@
 	 */
 	struct task_struct *thread;
 
-	struct mutex ha_region_mutex;
+	/*
+	 * Protects ha_region_list, num_pages_onlined counter and individual
+	 * regions from ha_region_list.
+	 */
+	spinlock_t ha_lock;
 
 	/*
 	 * A list of hot-add regions.
@@ -560,18 +575,14 @@
 			      void *v)
 {
 	struct memory_notify *mem = (struct memory_notify *)v;
+	unsigned long flags;
 
 	switch (val) {
-	case MEM_GOING_ONLINE:
-		mutex_lock(&dm_device.ha_region_mutex);
-		break;
-
 	case MEM_ONLINE:
+		spin_lock_irqsave(&dm_device.ha_lock, flags);
 		dm_device.num_pages_onlined += mem->nr_pages;
+		spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 	case MEM_CANCEL_ONLINE:
-		if (val == MEM_ONLINE ||
-		    mutex_is_locked(&dm_device.ha_region_mutex))
-			mutex_unlock(&dm_device.ha_region_mutex);
 		if (dm_device.ha_waiting) {
 			dm_device.ha_waiting = false;
 			complete(&dm_device.ol_waitevent);
@@ -579,10 +590,11 @@
 		break;
 
 	case MEM_OFFLINE:
-		mutex_lock(&dm_device.ha_region_mutex);
+		spin_lock_irqsave(&dm_device.ha_lock, flags);
 		dm_device.num_pages_onlined -= mem->nr_pages;
-		mutex_unlock(&dm_device.ha_region_mutex);
+		spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 		break;
+	case MEM_GOING_ONLINE:
 	case MEM_GOING_OFFLINE:
 	case MEM_CANCEL_OFFLINE:
 		break;
@@ -595,18 +607,46 @@
 	.priority = 0
 };
 
+/* Check if the particular page is backed and can be onlined and online it. */
+static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
+{
+	unsigned long cur_start_pgp;
+	unsigned long cur_end_pgp;
+	struct hv_hotadd_gap *gap;
+
+	cur_start_pgp = (unsigned long)pfn_to_page(has->covered_start_pfn);
+	cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+
+	/* The page is not backed. */
+	if (((unsigned long)pg < cur_start_pgp) ||
+	    ((unsigned long)pg >= cur_end_pgp))
+		return;
 
-static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
+	/* Check for gaps. */
+	list_for_each_entry(gap, &has->gap_list, list) {
+		cur_start_pgp = (unsigned long)
+			pfn_to_page(gap->start_pfn);
+		cur_end_pgp = (unsigned long)
+			pfn_to_page(gap->end_pfn);
+		if (((unsigned long)pg >= cur_start_pgp) &&
+		    ((unsigned long)pg < cur_end_pgp)) {
+			return;
+		}
+	}
+
+	/* This frame is currently backed; online the page. */
+	__online_page_set_limits(pg);
+	__online_page_increment_counters(pg);
+	__online_page_free(pg);
+}
+
+static void hv_bring_pgs_online(struct hv_hotadd_state *has,
+				unsigned long start_pfn, unsigned long size)
 {
 	int i;
 
-	for (i = 0; i < size; i++) {
-		struct page *pg;
-		pg = pfn_to_page(start_pfn + i);
-		__online_page_set_limits(pg);
-		__online_page_increment_counters(pg);
-		__online_page_free(pg);
-	}
+	for (i = 0; i < size; i++)
+		hv_page_online_one(has, pfn_to_page(start_pfn + i));
 }
 
 static void hv_mem_hot_add(unsigned long start, unsigned long size,
@@ -618,9 +658,12 @@
 	unsigned long start_pfn;
 	unsigned long processed_pfn;
 	unsigned long total_pfn = pfn_count;
+	unsigned long flags;
 
 	for (i = 0; i < (size/HA_CHUNK); i++) {
 		start_pfn = start + (i * HA_CHUNK);
+
+		spin_lock_irqsave(&dm_device.ha_lock, flags);
 		has->ha_end_pfn +=  HA_CHUNK;
 
 		if (total_pfn > HA_CHUNK) {
@@ -632,11 +675,11 @@
 		}
 
 		has->covered_end_pfn +=  processed_pfn;
+		spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 
 		init_completion(&dm_device.ol_waitevent);
-		dm_device.ha_waiting = true;
+		dm_device.ha_waiting = !memhp_auto_online;
 
-		mutex_unlock(&dm_device.ha_region_mutex);
 		nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn));
 		ret = add_memory(nid, PFN_PHYS((start_pfn)),
 				(HA_CHUNK << PAGE_SHIFT));
@@ -653,20 +696,23 @@
 				 */
 				do_hot_add = false;
 			}
+			spin_lock_irqsave(&dm_device.ha_lock, flags);
 			has->ha_end_pfn -= HA_CHUNK;
 			has->covered_end_pfn -=  processed_pfn;
-			mutex_lock(&dm_device.ha_region_mutex);
+			spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 			break;
 		}
 
 		/*
-		 * Wait for the memory block to be onlined.
-		 * Since the hot add has succeeded, it is ok to
-		 * proceed even if the pages in the hot added region
-		 * have not been "onlined" within the allowed time.
+		 * Wait for the memory block to be onlined when memory onlining
+		 * is done outside of kernel (memhp_auto_online). Since the hot
+		 * add has succeeded, it is ok to proceed even if the pages in
+		 * the hot added region have not been "onlined" within the
+		 * allowed time.
 		 */
-		wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
-		mutex_lock(&dm_device.ha_region_mutex);
+		if (dm_device.ha_waiting)
+			wait_for_completion_timeout(&dm_device.ol_waitevent,
+						    5*HZ);
 		post_status(&dm_device);
 	}
 
@@ -675,47 +721,64 @@
 
 static void hv_online_page(struct page *pg)
 {
-	struct list_head *cur;
 	struct hv_hotadd_state *has;
 	unsigned long cur_start_pgp;
 	unsigned long cur_end_pgp;
+	unsigned long flags;
 
-	list_for_each(cur, &dm_device.ha_region_list) {
-		has = list_entry(cur, struct hv_hotadd_state, list);
-		cur_start_pgp = (unsigned long)pfn_to_page(has->start_pfn);
-		cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+	spin_lock_irqsave(&dm_device.ha_lock, flags);
+	list_for_each_entry(has, &dm_device.ha_region_list, list) {
+		cur_start_pgp = (unsigned long)
+			pfn_to_page(has->start_pfn);
+		cur_end_pgp = (unsigned long)pfn_to_page(has->end_pfn);
+
+		/* The page belongs to a different HAS. */
+		if (((unsigned long)pg < cur_start_pgp) ||
+		    ((unsigned long)pg >= cur_end_pgp))
+			continue;
 
-		if (((unsigned long)pg >= cur_start_pgp) &&
-			((unsigned long)pg < cur_end_pgp)) {
-			/*
-			 * This frame is currently backed; online the
-			 * page.
-			 */
-			__online_page_set_limits(pg);
-			__online_page_increment_counters(pg);
-			__online_page_free(pg);
-		}
+		hv_page_online_one(has, pg);
+		break;
 	}
+	spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 }
 
-static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
+static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
 {
-	struct list_head *cur;
 	struct hv_hotadd_state *has;
+	struct hv_hotadd_gap *gap;
 	unsigned long residual, new_inc;
+	int ret = 0;
+	unsigned long flags;
 
-	if (list_empty(&dm_device.ha_region_list))
-		return false;
-
-	list_for_each(cur, &dm_device.ha_region_list) {
-		has = list_entry(cur, struct hv_hotadd_state, list);
-
+	spin_lock_irqsave(&dm_device.ha_lock, flags);
+	list_for_each_entry(has, &dm_device.ha_region_list, list) {
 		/*
 		 * If the pfn range we are dealing with is not in the current
 		 * "hot add block", move on.
 		 */
-		if ((start_pfn >= has->end_pfn))
+		if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
 			continue;
+
+		/*
+		 * If the current start pfn is not where the covered_end
+		 * is, create a gap and update covered_end_pfn.
+		 */
+		if (has->covered_end_pfn != start_pfn) {
+			gap = kzalloc(sizeof(struct hv_hotadd_gap), GFP_ATOMIC);
+			if (!gap) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			INIT_LIST_HEAD(&gap->list);
+			gap->start_pfn = has->covered_end_pfn;
+			gap->end_pfn = start_pfn;
+			list_add_tail(&gap->list, &has->gap_list);
+
+			has->covered_end_pfn = start_pfn;
+		}
+
 		/*
 		 * If the current hot add-request extends beyond
 		 * our current limit; extend it.
@@ -732,19 +795,12 @@
 			has->end_pfn += new_inc;
 		}
 
-		/*
-		 * If the current start pfn is not where the covered_end
-		 * is, update it.
-		 */
-
-		if (has->covered_end_pfn != start_pfn)
-			has->covered_end_pfn = start_pfn;
-
-		return true;
-
+		ret = 1;
+		break;
 	}
+	spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 
-	return false;
+	return ret;
 }
 
 static unsigned long handle_pg_range(unsigned long pg_start,
@@ -753,22 +809,18 @@
 	unsigned long start_pfn = pg_start;
 	unsigned long pfn_cnt = pg_count;
 	unsigned long size;
-	struct list_head *cur;
 	struct hv_hotadd_state *has;
 	unsigned long pgs_ol = 0;
 	unsigned long old_covered_state;
+	unsigned long res = 0, flags;
 
-	if (list_empty(&dm_device.ha_region_list))
-		return 0;
-
-	list_for_each(cur, &dm_device.ha_region_list) {
-		has = list_entry(cur, struct hv_hotadd_state, list);
-
+	spin_lock_irqsave(&dm_device.ha_lock, flags);
+	list_for_each_entry(has, &dm_device.ha_region_list, list) {
 		/*
 		 * If the pfn range we are dealing with is not in the current
 		 * "hot add block", move on.
 		 */
-		if ((start_pfn >= has->end_pfn))
+		if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
 			continue;
 
 		old_covered_state = has->covered_end_pfn;
@@ -783,6 +835,8 @@
 			if (pgs_ol > pfn_cnt)
 				pgs_ol = pfn_cnt;
 
+			has->covered_end_pfn +=  pgs_ol;
+			pfn_cnt -= pgs_ol;
 			/*
 			 * Check if the corresponding memory block is already
 			 * online by checking its last previously backed page.
@@ -791,10 +845,8 @@
 			 */
 			if (start_pfn > has->start_pfn &&
 			    !PageReserved(pfn_to_page(start_pfn - 1)))
-				hv_bring_pgs_online(start_pfn, pgs_ol);
+				hv_bring_pgs_online(has, start_pfn, pgs_ol);
 
-			has->covered_end_pfn +=  pgs_ol;
-			pfn_cnt -= pgs_ol;
 		}
 
 		if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) {
@@ -813,17 +865,20 @@
 			} else {
 				pfn_cnt = size;
 			}
+			spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 			hv_mem_hot_add(has->ha_end_pfn, size, pfn_cnt, has);
+			spin_lock_irqsave(&dm_device.ha_lock, flags);
 		}
 		/*
 		 * If we managed to online any pages that were given to us,
 		 * we declare success.
 		 */
-		return has->covered_end_pfn - old_covered_state;
-
+		res = has->covered_end_pfn - old_covered_state;
+		break;
 	}
+	spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 
-	return 0;
+	return res;
 }
 
 static unsigned long process_hot_add(unsigned long pg_start,
@@ -832,13 +887,20 @@
 					unsigned long rg_size)
 {
 	struct hv_hotadd_state *ha_region = NULL;
+	int covered;
+	unsigned long flags;
 
 	if (pfn_cnt == 0)
 		return 0;
 
-	if (!dm_device.host_specified_ha_region)
-		if (pfn_covered(pg_start, pfn_cnt))
+	if (!dm_device.host_specified_ha_region) {
+		covered = pfn_covered(pg_start, pfn_cnt);
+		if (covered < 0)
+			return 0;
+
+		if (covered)
 			goto do_pg_range;
+	}
 
 	/*
 	 * If the host has specified a hot-add range; deal with it first.
@@ -850,12 +912,17 @@
 			return 0;
 
 		INIT_LIST_HEAD(&ha_region->list);
+		INIT_LIST_HEAD(&ha_region->gap_list);
 
-		list_add_tail(&ha_region->list, &dm_device.ha_region_list);
 		ha_region->start_pfn = rg_start;
 		ha_region->ha_end_pfn = rg_start;
+		ha_region->covered_start_pfn = pg_start;
 		ha_region->covered_end_pfn = pg_start;
 		ha_region->end_pfn = rg_start + rg_size;
+
+		spin_lock_irqsave(&dm_device.ha_lock, flags);
+		list_add_tail(&ha_region->list, &dm_device.ha_region_list);
+		spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 	}
 
 do_pg_range:
@@ -882,7 +949,6 @@
 	resp.hdr.size = sizeof(struct dm_hot_add_response);
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-	mutex_lock(&dm_device.ha_region_mutex);
 	pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
 	pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt;
 
@@ -916,7 +982,6 @@
 						rg_start, rg_sz);
 
 	dm->num_pages_added += resp.page_count;
-	mutex_unlock(&dm_device.ha_region_mutex);
 #endif
 	/*
 	 * The result field of the response structure has the
@@ -1010,7 +1075,6 @@
 static void post_status(struct hv_dynmem_device *dm)
 {
 	struct dm_status status;
-	struct sysinfo val;
 	unsigned long now = jiffies;
 	unsigned long last_post = last_post_time;
 
@@ -1022,7 +1086,6 @@
 	if (!time_after(now, (last_post_time + HZ)))
 		return;
 
-	si_meminfo(&val);
 	memset(&status, 0, sizeof(struct dm_status));
 	status.hdr.type = DM_STATUS_REPORT;
 	status.hdr.size = sizeof(struct dm_status);
@@ -1038,7 +1101,7 @@
 	 * num_pages_onlined) as committed to the host, otherwise it can try
 	 * asking us to balloon them out.
 	 */
-	status.num_avail = val.freeram;
+	status.num_avail = si_mem_available();
 	status.num_committed = vm_memory_committed() +
 		dm->num_pages_ballooned +
 		(dm->num_pages_added > dm->num_pages_onlined ?
@@ -1144,7 +1207,7 @@
 	int ret;
 	bool done = false;
 	int i;
-	struct sysinfo val;
+	long avail_pages;
 	unsigned long floor;
 
 	/* The host balloons pages in 2M granularity. */
@@ -1156,12 +1219,12 @@
 	 */
 	alloc_unit = 512;
 
-	si_meminfo(&val);
+	avail_pages = si_mem_available();
 	floor = compute_balloon_floor();
 
 	/* Refuse to balloon below the floor, keep the 2M granularity. */
-	if (val.freeram < num_pages || val.freeram - num_pages < floor) {
-		num_pages = val.freeram > floor ? (val.freeram - floor) : 0;
+	if (avail_pages < num_pages || avail_pages - num_pages < floor) {
+		num_pages = avail_pages > floor ? (avail_pages - floor) : 0;
 		num_pages -= num_pages % PAGES_IN_2M;
 	}
 
@@ -1172,7 +1235,6 @@
 		bl_resp->hdr.size = sizeof(struct dm_balloon_response);
 		bl_resp->more_pages = 1;
 
-
 		num_pages -= num_ballooned;
 		num_ballooned = alloc_balloon_pages(&dm_device, num_pages,
 						    bl_resp, alloc_unit);
@@ -1400,6 +1462,7 @@
 				 * This is a normal hot-add request specifying
 				 * hot-add memory.
 				 */
+				dm->host_specified_ha_region = false;
 				ha_pg_range = &ha_msg->range;
 				dm->ha_wrk.ha_page_range = *ha_pg_range;
 				dm->ha_wrk.ha_region_range.page_range = 0;
@@ -1460,7 +1523,7 @@
 	init_completion(&dm_device.host_event);
 	init_completion(&dm_device.config_event);
 	INIT_LIST_HEAD(&dm_device.ha_region_list);
-	mutex_init(&dm_device.ha_region_mutex);
+	spin_lock_init(&dm_device.ha_lock);
 	INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up);
 	INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req);
 	dm_device.host_specified_ha_region = false;
@@ -1579,8 +1642,9 @@
 static int balloon_remove(struct hv_device *dev)
 {
 	struct hv_dynmem_device *dm = hv_get_drvdata(dev);
-	struct list_head *cur, *tmp;
-	struct hv_hotadd_state *has;
+	struct hv_hotadd_state *has, *tmp;
+	struct hv_hotadd_gap *gap, *tmp_gap;
+	unsigned long flags;
 
 	if (dm->num_pages_ballooned != 0)
 		pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned);
@@ -1595,11 +1659,16 @@
 	restore_online_page_callback(&hv_online_page);
 	unregister_memory_notifier(&hv_memory_nb);
 #endif
-	list_for_each_safe(cur, tmp, &dm->ha_region_list) {
-		has = list_entry(cur, struct hv_hotadd_state, list);
+	spin_lock_irqsave(&dm_device.ha_lock, flags);
+	list_for_each_entry_safe(has, tmp, &dm->ha_region_list, list) {
+		list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) {
+			list_del(&gap->list);
+			kfree(gap);
+		}
 		list_del(&has->list);
 		kfree(has);
 	}
+	spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/hv/hv_fcopy.c
+++ linux-4.4.0/drivers/hv/hv_fcopy.c
@@ -51,7 +51,6 @@
 	struct hv_fcopy_hdr  *fcopy_msg; /* current message */
 	struct vmbus_channel *recv_channel; /* chn we got the request */
 	u64 recv_req_id; /* request ID. */
-	void *fcopy_context; /* for the channel callback */
 } fcopy_transaction;
 
 static void fcopy_respond_to_host(int error);
@@ -67,6 +66,13 @@
  */
 static int dm_reg_value;
 
+static void fcopy_poll_wrapper(void *channel)
+{
+	/* Transaction is finished, reset the state here to avoid races. */
+	fcopy_transaction.state = HVUTIL_READY;
+	hv_fcopy_onchannelcallback(channel);
+}
+
 static void fcopy_timeout_func(struct work_struct *dummy)
 {
 	/*
@@ -74,13 +80,13 @@
 	 * process the pending transaction.
 	 */
 	fcopy_respond_to_host(HV_E_FAIL);
+	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
+}
 
-	/* Transaction is finished, reset the state. */
-	if (fcopy_transaction.state > HVUTIL_READY)
-		fcopy_transaction.state = HVUTIL_READY;
-
-	hv_poll_channel(fcopy_transaction.fcopy_context,
-			hv_fcopy_onchannelcallback);
+static void fcopy_register_done(void)
+{
+	pr_debug("FCP: userspace daemon registered\n");
+	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
 }
 
 static int fcopy_handle_handshake(u32 version)
@@ -94,7 +100,8 @@
 		break;
 	case FCOPY_VERSION_1:
 		/* Daemon expects us to reply with our own version */
-		if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
+		if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
+		    fcopy_register_done))
 			return -EFAULT;
 		dm_reg_value = version;
 		break;
@@ -107,10 +114,7 @@
 		 */
 		return -EINVAL;
 	}
-	pr_debug("FCP: userspace daemon ver. %d registered\n", version);
-	fcopy_transaction.state = HVUTIL_READY;
-	hv_poll_channel(fcopy_transaction.fcopy_context,
-			hv_fcopy_onchannelcallback);
+	pr_debug("FCP: userspace daemon ver. %d connected\n", version);
 	return 0;
 }
 
@@ -156,6 +160,10 @@
 		out_src = smsg_out;
 		break;
 
+	case WRITE_TO_FILE:
+		out_src = fcopy_transaction.fcopy_msg;
+		out_len = sizeof(struct hv_do_fcopy);
+		break;
 	default:
 		out_src = fcopy_transaction.fcopy_msg;
 		out_len = fcopy_transaction.recv_len;
@@ -163,7 +171,7 @@
 	}
 
 	fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
-	rc = hvutil_transport_send(hvt, out_src, out_len);
+	rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
 	if (rc) {
 		pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
 		if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
@@ -227,15 +235,8 @@
 	int util_fw_version;
 	int fcopy_srv_version;
 
-	if (fcopy_transaction.state > HVUTIL_READY) {
-		/*
-		 * We will defer processing this callback once
-		 * the current transaction is complete.
-		 */
-		fcopy_transaction.fcopy_context = context;
+	if (fcopy_transaction.state > HVUTIL_READY)
 		return;
-	}
-	fcopy_transaction.fcopy_context = NULL;
 
 	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 			 &requestid);
@@ -260,7 +261,6 @@
 		 */
 
 		fcopy_transaction.recv_len = recvlen;
-		fcopy_transaction.recv_channel = channel;
 		fcopy_transaction.recv_req_id = requestid;
 		fcopy_transaction.fcopy_msg = fcopy_msg;
 
@@ -275,7 +275,8 @@
 		 * Send the information to the user-level daemon.
 		 */
 		schedule_work(&fcopy_send_work);
-		schedule_delayed_work(&fcopy_timeout_work, 5*HZ);
+		schedule_delayed_work(&fcopy_timeout_work,
+				      HV_UTIL_TIMEOUT * HZ);
 		return;
 	}
 	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
@@ -304,9 +305,8 @@
 	if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
 		fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
 		fcopy_respond_to_host(*val);
-		fcopy_transaction.state = HVUTIL_READY;
-		hv_poll_channel(fcopy_transaction.fcopy_context,
-				hv_fcopy_onchannelcallback);
+		hv_poll_channel(fcopy_transaction.recv_channel,
+				fcopy_poll_wrapper);
 	}
 
 	return 0;
@@ -326,6 +326,7 @@
 int hv_fcopy_init(struct hv_util_service *srv)
 {
 	recv_buffer = srv->recv_buffer;
+	fcopy_transaction.recv_channel = srv->channel;
 
 	/*
 	 * When this driver loads, the user level daemon that
--- linux-4.4.0.orig/drivers/hv/hv_kvp.c
+++ linux-4.4.0/drivers/hv/hv_kvp.c
@@ -66,7 +66,6 @@
 	struct hv_kvp_msg  *kvp_msg; /* current message */
 	struct vmbus_channel *recv_channel; /* chn we got the request */
 	u64 recv_req_id; /* request ID. */
-	void *kvp_context; /* for the channel callback */
 } kvp_transaction;
 
 /*
@@ -79,9 +78,11 @@
 
 static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
 static void kvp_timeout_func(struct work_struct *dummy);
+static void kvp_host_handshake_func(struct work_struct *dummy);
 static void kvp_register(int);
 
 static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func);
+static DECLARE_DELAYED_WORK(kvp_host_handshake_work, kvp_host_handshake_func);
 static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
 
 static const char kvp_devname[] = "vmbus/hv_kvp";
@@ -94,6 +95,24 @@
  */
 #define HV_DRV_VERSION           "3.1"
 
+static void kvp_poll_wrapper(void *channel)
+{
+	/* Transaction is finished, reset the state here to avoid races. */
+	kvp_transaction.state = HVUTIL_READY;
+	hv_kvp_onchannelcallback(channel);
+}
+
+static void kvp_register_done(void)
+{
+	/*
+	 * If we're still negotiating with the host cancel the timeout
+	 * work to not poll the channel twice.
+	 */
+	pr_debug("KVP: userspace daemon registered\n");
+	cancel_delayed_work_sync(&kvp_host_handshake_work);
+	hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
+}
+
 static void
 kvp_register(int reg_value)
 {
@@ -108,7 +127,8 @@
 		kvp_msg->kvp_hdr.operation = reg_value;
 		strcpy(version, HV_DRV_VERSION);
 
-		hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg));
+		hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg),
+				      kvp_register_done);
 		kfree(kvp_msg);
 	}
 }
@@ -121,12 +141,12 @@
 	 */
 	kvp_respond_to_host(NULL, HV_E_FAIL);
 
-	/* Transaction is finished, reset the state. */
-	if (kvp_transaction.state > HVUTIL_READY)
-		kvp_transaction.state = HVUTIL_READY;
+	hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
+}
 
-	hv_poll_channel(kvp_transaction.kvp_context,
-			hv_kvp_onchannelcallback);
+static void kvp_host_handshake_func(struct work_struct *dummy)
+{
+	hv_poll_channel(kvp_transaction.recv_channel, hv_kvp_onchannelcallback);
 }
 
 static int kvp_handle_handshake(struct hv_kvp_msg *msg)
@@ -150,10 +170,9 @@
 	/*
 	 * We have a compatible daemon; complete the handshake.
 	 */
-	pr_debug("KVP: userspace daemon ver. %d registered\n",
-		 KVP_OP_REGISTER);
+	pr_debug("KVP: userspace daemon ver. %d connected\n",
+		 msg->kvp_hdr.operation);
 	kvp_register(dm_reg_value);
-	kvp_transaction.state = HVUTIL_READY;
 
 	return 0;
 }
@@ -218,9 +237,7 @@
 	 */
 	if (cancel_delayed_work_sync(&kvp_timeout_work)) {
 		kvp_respond_to_host(message, error);
-		kvp_transaction.state = HVUTIL_READY;
-		hv_poll_channel(kvp_transaction.kvp_context,
-				hv_kvp_onchannelcallback);
+		hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
 	}
 
 	return 0;
@@ -443,7 +460,7 @@
 	}
 
 	kvp_transaction.state = HVUTIL_USERSPACE_REQ;
-	rc = hvutil_transport_send(hvt, message, sizeof(*message));
+	rc = hvutil_transport_send(hvt, message, sizeof(*message), NULL);
 	if (rc) {
 		pr_debug("KVP: failed to communicate to the daemon: %d\n", rc);
 		if (cancel_delayed_work_sync(&kvp_timeout_work)) {
@@ -595,17 +612,26 @@
 	struct icmsg_negotiate *negop = NULL;
 	int util_fw_version;
 	int kvp_srv_version;
+	static enum {NEGO_NOT_STARTED,
+		     NEGO_IN_PROGRESS,
+		     NEGO_FINISHED} host_negotiatied = NEGO_NOT_STARTED;
 
-	if (kvp_transaction.state > HVUTIL_READY) {
+	if (kvp_transaction.state < HVUTIL_READY) {
 		/*
-		 * We will defer processing this callback once
-		 * the current transaction is complete.
+		 * If userspace daemon is not connected and host is asking
+		 * us to negotiate we need to delay to not lose messages.
+		 * This is important for Failover IP setting.
 		 */
-		kvp_transaction.kvp_context = context;
+		if (host_negotiatied == NEGO_NOT_STARTED) {
+			host_negotiatied = NEGO_IN_PROGRESS;
+			schedule_delayed_work(&kvp_host_handshake_work,
+				      HV_UTIL_NEGO_TIMEOUT * HZ);
+		}
 		return;
 	}
-	kvp_transaction.kvp_context = NULL;
-
+	if (kvp_transaction.state > HVUTIL_READY)
+		return;
+recheck:
 	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
 			 &requestid);
 
@@ -647,7 +673,6 @@
 			 */
 
 			kvp_transaction.recv_len = recvlen;
-			kvp_transaction.recv_channel = channel;
 			kvp_transaction.recv_req_id = requestid;
 			kvp_transaction.kvp_msg = kvp_msg;
 
@@ -668,7 +693,8 @@
 			 * user-mode not responding.
 			 */
 			schedule_work(&kvp_sendkey_work);
-			schedule_delayed_work(&kvp_timeout_work, 5*HZ);
+			schedule_delayed_work(&kvp_timeout_work,
+					      HV_UTIL_TIMEOUT * HZ);
 
 			return;
 
@@ -680,6 +706,10 @@
 		vmbus_sendpacket(channel, recv_buffer,
 				       recvlen, requestid,
 				       VM_PKT_DATA_INBAND, 0);
+
+		host_negotiatied = NEGO_FINISHED;
+
+		goto recheck;
 	}
 
 }
@@ -695,6 +725,7 @@
 hv_kvp_init(struct hv_util_service *srv)
 {
 	recv_buffer = srv->recv_buffer;
+	kvp_transaction.recv_channel = srv->channel;
 
 	/*
 	 * When this driver loads, the user level daemon that
@@ -715,6 +746,7 @@
 void hv_kvp_deinit(void)
 {
 	kvp_transaction.state = HVUTIL_DEVICE_DYING;
+	cancel_delayed_work_sync(&kvp_host_handshake_work);
 	cancel_delayed_work_sync(&kvp_timeout_work);
 	cancel_work_sync(&kvp_sendkey_work);
 	hvutil_transport_destroy(hvt);
--- linux-4.4.0.orig/drivers/hv/hv_snapshot.c
+++ linux-4.4.0/drivers/hv/hv_snapshot.c
@@ -31,7 +31,10 @@
 #define VSS_MINOR  0
 #define VSS_VERSION    (VSS_MAJOR << 16 | VSS_MINOR)
 
-#define VSS_USERSPACE_TIMEOUT (msecs_to_jiffies(10 * 1000))
+/*
+ * Timeout values are based on expecations from host
+ */
+#define VSS_FREEZE_TIMEOUT (15 * 60)
 
 /*
  * Global state maintained for transaction that is being processed. For a class
@@ -53,7 +56,6 @@
 	struct vmbus_channel *recv_channel; /* chn we got the request */
 	u64 recv_req_id; /* request ID. */
 	struct hv_vss_msg  *msg; /* current message */
-	void *vss_context; /* for the channel callback */
 } vss_transaction;
 
 
@@ -68,11 +70,18 @@
 static __u8 *recv_buffer;
 static struct hvutil_transport *hvt;
 
-static void vss_send_op(struct work_struct *dummy);
 static void vss_timeout_func(struct work_struct *dummy);
+static void vss_handle_request(struct work_struct *dummy);
 
 static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func);
-static DECLARE_WORK(vss_send_op_work, vss_send_op);
+static DECLARE_WORK(vss_handle_request_work, vss_handle_request);
+
+static void vss_poll_wrapper(void *channel)
+{
+	/* Transaction is finished, reset the state here to avoid races. */
+	vss_transaction.state = HVUTIL_READY;
+	hv_vss_onchannelcallback(channel);
+}
 
 /*
  * Callback when data is received from user mode.
@@ -86,12 +95,13 @@
 	pr_warn("VSS: timeout waiting for daemon to reply\n");
 	vss_respond_to_host(HV_E_FAIL);
 
-	/* Transaction is finished, reset the state. */
-	if (vss_transaction.state > HVUTIL_READY)
-		vss_transaction.state = HVUTIL_READY;
+	hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
+}
 
-	hv_poll_channel(vss_transaction.vss_context,
-			hv_vss_onchannelcallback);
+static void vss_register_done(void)
+{
+	hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
+	pr_debug("VSS: userspace daemon registered\n");
 }
 
 static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
@@ -104,16 +114,16 @@
 		dm_reg_value = VSS_OP_REGISTER;
 		break;
 	case VSS_OP_REGISTER1:
-		/* Daemon expects us to reply with our own version*/
-		if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
+		/* Daemon expects us to reply with our own version */
+		if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
+					  vss_register_done))
 			return -EFAULT;
 		dm_reg_value = VSS_OP_REGISTER1;
 		break;
 	default:
 		return -EINVAL;
 	}
-	vss_transaction.state = HVUTIL_READY;
-	pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value);
+	pr_debug("VSS: userspace daemon ver. %d connected\n", dm_reg_value);
 	return 0;
 }
 
@@ -135,12 +145,16 @@
 		return vss_handle_handshake(vss_msg);
 	} else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) {
 		vss_transaction.state = HVUTIL_USERSPACE_RECV;
+
+		if (vss_msg->vss_hdr.operation == VSS_OP_HOT_BACKUP)
+			vss_transaction.msg->vss_cf.flags =
+				VSS_HBU_NO_AUTO_RECOVERY;
+
 		if (cancel_delayed_work_sync(&vss_timeout_work)) {
 			vss_respond_to_host(vss_msg->error);
 			/* Transaction is finished, reset the state. */
-			vss_transaction.state = HVUTIL_READY;
-			hv_poll_channel(vss_transaction.vss_context,
-					hv_vss_onchannelcallback);
+			hv_poll_channel(vss_transaction.recv_channel,
+					vss_poll_wrapper);
 		}
 	} else {
 		/* This is a spurious call! */
@@ -150,8 +164,7 @@
 	return 0;
 }
 
-
-static void vss_send_op(struct work_struct *dummy)
+static void vss_send_op(void)
 {
 	int op = vss_transaction.msg->vss_hdr.operation;
 	int rc;
@@ -168,7 +181,11 @@
 	vss_msg->vss_hdr.operation = op;
 
 	vss_transaction.state = HVUTIL_USERSPACE_REQ;
-	rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg));
+
+	schedule_delayed_work(&vss_timeout_work, op == VSS_OP_FREEZE ?
+			VSS_FREEZE_TIMEOUT * HZ : HV_UTIL_TIMEOUT * HZ);
+
+	rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg), NULL);
 	if (rc) {
 		pr_warn("VSS: failed to communicate to the daemon: %d\n", rc);
 		if (cancel_delayed_work_sync(&vss_timeout_work)) {
@@ -182,6 +199,38 @@
 	return;
 }
 
+static void vss_handle_request(struct work_struct *dummy)
+{
+	switch (vss_transaction.msg->vss_hdr.operation) {
+	/*
+	 * Initiate a "freeze/thaw" operation in the guest.
+	 * We respond to the host once the operation is complete.
+	 *
+	 * We send the message to the user space daemon and the operation is
+	 * performed in the daemon.
+	 */
+	case VSS_OP_THAW:
+	case VSS_OP_FREEZE:
+	case VSS_OP_HOT_BACKUP:
+		if (vss_transaction.state < HVUTIL_READY) {
+			/* Userspace is not registered yet */
+			vss_respond_to_host(HV_E_FAIL);
+			return;
+		}
+		vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
+		vss_send_op();
+		return;
+	case VSS_OP_GET_DM_INFO:
+		vss_transaction.msg->dm_info.flags = 0;
+		break;
+	default:
+		break;
+	}
+
+	vss_respond_to_host(0);
+	hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
+}
+
 /*
  * Send a response back to the host.
  */
@@ -238,15 +287,8 @@
 	struct icmsg_hdr *icmsghdrp;
 	struct icmsg_negotiate *negop = NULL;
 
-	if (vss_transaction.state > HVUTIL_READY) {
-		/*
-		 * We will defer processing this callback once
-		 * the current transaction is complete.
-		 */
-		vss_transaction.vss_context = context;
+	if (vss_transaction.state > HVUTIL_READY)
 		return;
-	}
-	vss_transaction.vss_context = NULL;
 
 	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 			 &requestid);
@@ -270,52 +312,11 @@
 			 */
 
 			vss_transaction.recv_len = recvlen;
-			vss_transaction.recv_channel = channel;
 			vss_transaction.recv_req_id = requestid;
 			vss_transaction.msg = (struct hv_vss_msg *)vss_msg;
 
-			switch (vss_msg->vss_hdr.operation) {
-				/*
-				 * Initiate a "freeze/thaw"
-				 * operation in the guest.
-				 * We respond to the host once
-				 * the operation is complete.
-				 *
-				 * We send the message to the
-				 * user space daemon and the
-				 * operation is performed in
-				 * the daemon.
-				 */
-			case VSS_OP_FREEZE:
-			case VSS_OP_THAW:
-				if (vss_transaction.state < HVUTIL_READY) {
-					/* Userspace is not registered yet */
-					vss_respond_to_host(HV_E_FAIL);
-					return;
-				}
-				vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
-				schedule_work(&vss_send_op_work);
-				schedule_delayed_work(&vss_timeout_work,
-						      VSS_USERSPACE_TIMEOUT);
-				return;
-
-			case VSS_OP_HOT_BACKUP:
-				vss_msg->vss_cf.flags =
-					 VSS_HBU_NO_AUTO_RECOVERY;
-				vss_respond_to_host(0);
-				return;
-
-			case VSS_OP_GET_DM_INFO:
-				vss_msg->dm_info.flags = 0;
-				vss_respond_to_host(0);
-				return;
-
-			default:
-				vss_respond_to_host(0);
-				return;
-
-			}
-
+			schedule_work(&vss_handle_request_work);
+			return;
 		}
 
 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
@@ -338,7 +339,13 @@
 int
 hv_vss_init(struct hv_util_service *srv)
 {
+	if (vmbus_proto_version < VERSION_WIN8_1) {
+		pr_warn("Integration service 'Backup (volume snapshot)'"
+			" not supported on this host version.\n");
+		return -ENOTSUPP;
+	}
 	recv_buffer = srv->recv_buffer;
+	vss_transaction.recv_channel = srv->channel;
 
 	/*
 	 * When this driver loads, the user level daemon that
@@ -360,6 +367,6 @@
 {
 	vss_transaction.state = HVUTIL_DEVICE_DYING;
 	cancel_delayed_work_sync(&vss_timeout_work);
-	cancel_work_sync(&vss_send_op_work);
+	cancel_work_sync(&vss_handle_request_work);
 	hvutil_transport_destroy(hvt);
 }
--- linux-4.4.0.orig/drivers/hv/hv_util.c
+++ linux-4.4.0/drivers/hv/hv_util.c
@@ -27,6 +27,9 @@
 #include <linux/sysctl.h>
 #include <linux/reboot.h>
 #include <linux/hyperv.h>
+#include <linux/clockchips.h>
+#include <linux/ptp_clock_kernel.h>
+#include <asm/mshyperv.h>
 
 #include "hyperv_vmbus.h"
 
@@ -34,22 +37,25 @@
 #define SD_MINOR	0
 #define SD_VERSION	(SD_MAJOR << 16 | SD_MINOR)
 
-#define SD_WS2008_MAJOR		1
-#define SD_WS2008_VERSION	(SD_WS2008_MAJOR << 16 | SD_MINOR)
+#define SD_MAJOR_1	1
+#define SD_VERSION_1	(SD_MAJOR_1 << 16 | SD_MINOR)
 
-#define TS_MAJOR	3
+#define TS_MAJOR	4
 #define TS_MINOR	0
 #define TS_VERSION	(TS_MAJOR << 16 | TS_MINOR)
 
-#define TS_WS2008_MAJOR		1
-#define TS_WS2008_VERSION	(TS_WS2008_MAJOR << 16 | TS_MINOR)
+#define TS_MAJOR_1	1
+#define TS_VERSION_1	(TS_MAJOR_1 << 16 | TS_MINOR)
+
+#define TS_MAJOR_3	3
+#define TS_VERSION_3	(TS_MAJOR_3 << 16 | TS_MINOR)
 
 #define HB_MAJOR	3
-#define HB_MINOR 0
+#define HB_MINOR	0
 #define HB_VERSION	(HB_MAJOR << 16 | HB_MINOR)
 
-#define HB_WS2008_MAJOR	1
-#define HB_WS2008_VERSION	(HB_WS2008_MAJOR << 16 | HB_MINOR)
+#define HB_MAJOR_1	1
+#define HB_VERSION_1	(HB_MAJOR_1 << 16 | HB_MINOR)
 
 static int sd_srv_version;
 static int ts_srv_version;
@@ -61,9 +67,14 @@
 	.util_cb = shutdown_onchannelcallback,
 };
 
+static int hv_timesync_init(struct hv_util_service *srv);
+static void hv_timesync_deinit(void);
+
 static void timesync_onchannelcallback(void *context);
 static struct hv_util_service util_timesynch = {
 	.util_cb = timesync_onchannelcallback,
+	.util_init = hv_timesync_init,
+	.util_deinit = hv_timesync_deinit,
 };
 
 static void heartbeat_onchannelcallback(void *context);
@@ -161,35 +172,41 @@
 }
 
 /*
- * Set guest time to host UTC time.
+ * Set the host time in a process context.
  */
-static inline void do_adj_guesttime(u64 hosttime)
-{
-	s64 host_tns;
-	struct timespec host_ts;
-
-	host_tns = (hosttime - WLTIMEDELTA) * 100;
-	host_ts = ns_to_timespec(host_tns);
-
-	do_settimeofday(&host_ts);
-}
+static struct work_struct adj_time_work;
 
 /*
- * Set the host time in a process context.
+ * The last time sample, received from the host. PTP device responds to
+ * requests by using this data and the current partition-wide time reference
+ * count.
  */
+static struct {
+	u64				host_time;
+	u64				ref_time;
+	spinlock_t			lock;
+} host_ts;
 
-struct adj_time_work {
-	struct work_struct work;
-	u64	host_time;
-};
+static struct timespec64 hv_get_adj_host_time(void)
+{
+	struct timespec64 ts;
+	u64 newtime, reftime;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host_ts.lock, flags);
+	reftime = hyperv_cs->read(hyperv_cs);
+	newtime = host_ts.host_time + (reftime - host_ts.ref_time);
+	ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
+	spin_unlock_irqrestore(&host_ts.lock, flags);
+
+	return ts;
+}
 
 static void hv_set_host_time(struct work_struct *work)
 {
-	struct adj_time_work	*wrk;
+	struct timespec64 ts = hv_get_adj_host_time();
 
-	wrk = container_of(work, struct adj_time_work, work);
-	do_adj_guesttime(wrk->host_time);
-	kfree(wrk);
+	do_settimeofday64(&ts);
 }
 
 /*
@@ -198,33 +215,42 @@
  * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
  * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
  * message after the timesync channel is opened. Since the hv_utils module is
- * loaded after hv_vmbus, the first message is usually missed. The other
- * thing is, systime is automatically set to emulated hardware clock which may
- * not be UTC time or in the same time zone. So, to override these effects, we
- * use the first 50 time samples for initial system time setting.
+ * loaded after hv_vmbus, the first message is usually missed. This bit is
+ * considered a hard request to discipline the clock.
+ *
+ * ICTIMESYNCFLAG_SAMPLE bit indicates a time sample from host. This is
+ * typically used as a hint to the guest. The guest is under no obligation
+ * to discipline the clock.
  */
-static inline void adj_guesttime(u64 hosttime, u8 flags)
+static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags)
 {
-	struct adj_time_work    *wrk;
-	static s32 scnt = 50;
+	unsigned long flags;
+	u64 cur_reftime;
 
-	wrk = kmalloc(sizeof(struct adj_time_work), GFP_ATOMIC);
-	if (wrk == NULL)
-		return;
-
-	wrk->host_time = hosttime;
-	if ((flags & ICTIMESYNCFLAG_SYNC) != 0) {
-		INIT_WORK(&wrk->work, hv_set_host_time);
-		schedule_work(&wrk->work);
-		return;
-	}
+	/*
+	 * Save the adjusted time sample from the host and the snapshot
+	 * of the current system time.
+	 */
+	spin_lock_irqsave(&host_ts.lock, flags);
+
+	cur_reftime = hyperv_cs->read(hyperv_cs);
+	host_ts.host_time = hosttime;
+	host_ts.ref_time = cur_reftime;
+
+	/*
+	 * TimeSync v4 messages contain reference time (guest's Hyper-V
+	 * clocksource read when the time sample was generated), we can
+	 * improve the precision by adding the delta between now and the
+	 * time of generation. For older protocols we set
+	 * reftime == cur_reftime on call.
+	 */
+	host_ts.host_time += (cur_reftime - reftime);
+
+	spin_unlock_irqrestore(&host_ts.lock, flags);
 
-	if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) {
-		scnt--;
-		INIT_WORK(&wrk->work, hv_set_host_time);
-		schedule_work(&wrk->work);
-	} else
-		kfree(wrk);
+	/* Schedule work to do do_settimeofday64() */
+	if (adj_flags & ICTIMESYNCFLAG_SYNC)
+		schedule_work(&adj_time_work);
 }
 
 /*
@@ -237,6 +263,7 @@
 	u64 requestid;
 	struct icmsg_hdr *icmsghdrp;
 	struct ictimesync_data *timedatap;
+	struct ictimesync_ref_data *refdata;
 	u8 *time_txf_buf = util_timesynch.recv_buffer;
 	struct icmsg_negotiate *negop = NULL;
 
@@ -252,11 +279,27 @@
 						time_txf_buf,
 						util_fw_version,
 						ts_srv_version);
+			pr_info("Using TimeSync version %d.%d\n",
+				ts_srv_version >> 16, ts_srv_version & 0xFFFF);
 		} else {
-			timedatap = (struct ictimesync_data *)&time_txf_buf[
-				sizeof(struct vmbuspipe_hdr) +
-				sizeof(struct icmsg_hdr)];
-			adj_guesttime(timedatap->parenttime, timedatap->flags);
+			if (ts_srv_version > TS_VERSION_3) {
+				refdata = (struct ictimesync_ref_data *)
+					&time_txf_buf[
+					sizeof(struct vmbuspipe_hdr) +
+					sizeof(struct icmsg_hdr)];
+
+				adj_guesttime(refdata->parenttime,
+						refdata->vmreferencetime,
+						refdata->flags);
+			} else {
+				timedatap = (struct ictimesync_data *)
+					&time_txf_buf[
+					sizeof(struct vmbuspipe_hdr) +
+					sizeof(struct icmsg_hdr)];
+				adj_guesttime(timedatap->parenttime,
+					      hyperv_cs->read(hyperv_cs),
+					      timedatap->flags);
+			}
 		}
 
 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
@@ -283,10 +326,14 @@
 	u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
 	struct icmsg_negotiate *negop = NULL;
 
-	vmbus_recvpacket(channel, hbeat_txf_buf,
-			 PAGE_SIZE, &recvlen, &requestid);
+	while (1) {
+
+		vmbus_recvpacket(channel, hbeat_txf_buf,
+				 PAGE_SIZE, &recvlen, &requestid);
+
+		if (!recvlen)
+			break;
 
-	if (recvlen > 0) {
 		icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
 				sizeof(struct vmbuspipe_hdr)];
 
@@ -322,6 +369,7 @@
 	srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
 	if (!srv->recv_buffer)
 		return -ENOMEM;
+	srv->channel = dev->channel;
 	if (srv->util_init) {
 		ret = srv->util_init(srv);
 		if (ret) {
@@ -349,16 +397,21 @@
 	switch (vmbus_proto_version) {
 	case (VERSION_WS2008):
 		util_fw_version = UTIL_WS2K8_FW_VERSION;
-		sd_srv_version = SD_WS2008_VERSION;
-		ts_srv_version = TS_WS2008_VERSION;
-		hb_srv_version = HB_WS2008_VERSION;
+		sd_srv_version = SD_VERSION_1;
+		ts_srv_version = TS_VERSION_1;
+		hb_srv_version = HB_VERSION_1;
 		break;
-
-	default:
+	case(VERSION_WIN10):
 		util_fw_version = UTIL_FW_VERSION;
 		sd_srv_version = SD_VERSION;
 		ts_srv_version = TS_VERSION;
 		hb_srv_version = HB_VERSION;
+		break;
+	default:
+		util_fw_version = UTIL_FW_VERSION;
+		sd_srv_version = SD_VERSION;
+		ts_srv_version = TS_VERSION_3;
+		hb_srv_version = HB_VERSION;
 	}
 
 	ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
@@ -426,6 +479,77 @@
 	.remove =  util_remove,
 };
 
+static int hv_ptp_enable(struct ptp_clock_info *info,
+			 struct ptp_clock_request *request, int on)
+{
+	return -EOPNOTSUPP;
+}
+
+static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts)
+{
+	return -EOPNOTSUPP;
+}
+
+static int hv_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
+{
+	return -EOPNOTSUPP;
+}
+static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+	return -EOPNOTSUPP;
+}
+
+static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
+{
+	*ts = hv_get_adj_host_time();
+
+	return 0;
+}
+
+static struct ptp_clock_info ptp_hyperv_info = {
+	.name		= "hyperv",
+	.enable         = hv_ptp_enable,
+	.adjtime        = hv_ptp_adjtime,
+	.adjfreq        = hv_ptp_adjfreq,
+	.gettime64      = hv_ptp_gettime,
+	.settime64      = hv_ptp_settime,
+	.owner		= THIS_MODULE,
+};
+
+static struct ptp_clock *hv_ptp_clock;
+
+static int hv_timesync_init(struct hv_util_service *srv)
+{
+	/* TimeSync requires Hyper-V clocksource. */
+	if (!hyperv_cs)
+		return -ENODEV;
+
+	spin_lock_init(&host_ts.lock);
+
+	INIT_WORK(&adj_time_work, hv_set_host_time);
+
+	/*
+	 * ptp_clock_register() returns NULL when CONFIG_PTP_1588_CLOCK is
+	 * disabled but the driver is still useful without the PTP device
+	 * as it still handles the ICTIMESYNCFLAG_SYNC case.
+	 */
+	hv_ptp_clock = ptp_clock_register(&ptp_hyperv_info, NULL);
+	if (IS_ERR_OR_NULL(hv_ptp_clock)) {
+		pr_err("cannot register PTP clock: %ld\n",
+		       PTR_ERR(hv_ptp_clock));
+		hv_ptp_clock = NULL;
+	}
+
+	return 0;
+}
+
+static void hv_timesync_deinit(void)
+{
+	if (hv_ptp_clock)
+		ptp_clock_unregister(hv_ptp_clock);
+	cancel_work_sync(&adj_time_work);
+}
+
 static int __init init_hyperv_utils(void)
 {
 	pr_info("Registering HyperV Utility Driver\n");
--- linux-4.4.0.orig/drivers/hv/hv_utils_transport.c
+++ linux-4.4.0/drivers/hv/hv_utils_transport.c
@@ -27,11 +27,9 @@
 
 static void hvt_reset(struct hvutil_transport *hvt)
 {
-	mutex_lock(&hvt->outmsg_lock);
 	kfree(hvt->outmsg);
 	hvt->outmsg = NULL;
 	hvt->outmsg_len = 0;
-	mutex_unlock(&hvt->outmsg_lock);
 	if (hvt->on_reset)
 		hvt->on_reset();
 }
@@ -44,10 +42,17 @@
 
 	hvt = container_of(file->f_op, struct hvutil_transport, fops);
 
-	if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0))
+	if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0 ||
+				     hvt->mode != HVUTIL_TRANSPORT_CHARDEV))
 		return -EINTR;
 
-	mutex_lock(&hvt->outmsg_lock);
+	mutex_lock(&hvt->lock);
+
+	if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
+		ret = -EBADF;
+		goto out_unlock;
+	}
+
 	if (!hvt->outmsg) {
 		ret = -EAGAIN;
 		goto out_unlock;
@@ -67,8 +72,12 @@
 	hvt->outmsg = NULL;
 	hvt->outmsg_len = 0;
 
+	if (hvt->on_read)
+		hvt->on_read();
+	hvt->on_read = NULL;
+
 out_unlock:
-	mutex_unlock(&hvt->outmsg_lock);
+	mutex_unlock(&hvt->lock);
 	return ret;
 }
 
@@ -77,19 +86,22 @@
 {
 	struct hvutil_transport *hvt;
 	u8 *inmsg;
+	int ret;
 
 	hvt = container_of(file->f_op, struct hvutil_transport, fops);
 
-	inmsg = kzalloc(count, GFP_KERNEL);
-	if (copy_from_user(inmsg, buf, count)) {
-		kfree(inmsg);
-		return -EFAULT;
-	}
-	if (hvt->on_msg(inmsg, count))
-		return -EFAULT;
+	inmsg = memdup_user(buf, count);
+	if (IS_ERR(inmsg))
+		return PTR_ERR(inmsg);
+
+	if (hvt->mode == HVUTIL_TRANSPORT_DESTROY)
+		ret = -EBADF;
+	else
+		ret = hvt->on_msg(inmsg, count);
+
 	kfree(inmsg);
 
-	return count;
+	return ret ? ret : count;
 }
 
 static unsigned int hvt_op_poll(struct file *file, poll_table *wait)
@@ -99,6 +111,10 @@
 	hvt = container_of(file->f_op, struct hvutil_transport, fops);
 
 	poll_wait(file, &hvt->outmsg_q, wait);
+
+	if (hvt->mode == HVUTIL_TRANSPORT_DESTROY)
+		return POLLERR | POLLHUP;
+
 	if (hvt->outmsg_len > 0)
 		return POLLIN | POLLRDNORM;
 
@@ -108,41 +124,70 @@
 static int hvt_op_open(struct inode *inode, struct file *file)
 {
 	struct hvutil_transport *hvt;
+	int ret = 0;
+	bool issue_reset = false;
 
 	hvt = container_of(file->f_op, struct hvutil_transport, fops);
 
-	/*
-	 * Switching to CHARDEV mode. We switch bach to INIT when device
-	 * gets released.
-	 */
-	if (hvt->mode == HVUTIL_TRANSPORT_INIT)
+	mutex_lock(&hvt->lock);
+
+	if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
+		ret = -EBADF;
+	} else if (hvt->mode == HVUTIL_TRANSPORT_INIT) {
+		/*
+		 * Switching to CHARDEV mode. We switch bach to INIT when
+		 * device gets released.
+		 */
 		hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
+	}
 	else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) {
 		/*
 		 * We're switching from netlink communication to using char
 		 * device. Issue the reset first.
 		 */
-		hvt_reset(hvt);
+		issue_reset = true;
 		hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
-	} else
-		return -EBUSY;
+	} else {
+		ret = -EBUSY;
+	}
 
-	return 0;
+	if (issue_reset)
+		hvt_reset(hvt);
+
+	mutex_unlock(&hvt->lock);
+
+	return ret;
+}
+
+static void hvt_transport_free(struct hvutil_transport *hvt)
+{
+	misc_deregister(&hvt->mdev);
+	kfree(hvt->outmsg);
+	kfree(hvt);
 }
 
 static int hvt_op_release(struct inode *inode, struct file *file)
 {
 	struct hvutil_transport *hvt;
+	int mode_old;
 
 	hvt = container_of(file->f_op, struct hvutil_transport, fops);
 
-	hvt->mode = HVUTIL_TRANSPORT_INIT;
+	mutex_lock(&hvt->lock);
+	mode_old = hvt->mode;
+	if (hvt->mode != HVUTIL_TRANSPORT_DESTROY)
+		hvt->mode = HVUTIL_TRANSPORT_INIT;
 	/*
 	 * Cleanup message buffers to avoid spurious messages when the daemon
 	 * connects back.
 	 */
 	hvt_reset(hvt);
 
+	if (mode_old == HVUTIL_TRANSPORT_DESTROY)
+		complete(&hvt->release);
+
+	mutex_unlock(&hvt->lock);
+
 	return 0;
 }
 
@@ -168,6 +213,7 @@
 	 * Switching to NETLINK mode. Switching to CHARDEV happens when someone
 	 * opens the device.
 	 */
+	mutex_lock(&hvt->lock);
 	if (hvt->mode == HVUTIL_TRANSPORT_INIT)
 		hvt->mode = HVUTIL_TRANSPORT_NETLINK;
 
@@ -175,14 +221,17 @@
 		hvt_found->on_msg(msg->data, msg->len);
 	else
 		pr_warn("hvt_cn_callback: unexpected netlink message!\n");
+	mutex_unlock(&hvt->lock);
 }
 
-int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
+int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len,
+			  void (*on_read_cb)(void))
 {
 	struct cn_msg *cn_msg;
 	int ret = 0;
 
-	if (hvt->mode == HVUTIL_TRANSPORT_INIT) {
+	if (hvt->mode == HVUTIL_TRANSPORT_INIT ||
+	    hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
 		return -EINVAL;
 	} else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) {
 		cn_msg = kzalloc(sizeof(*cn_msg) + len, GFP_ATOMIC);
@@ -194,21 +243,37 @@
 		memcpy(cn_msg->data, msg, len);
 		ret = cn_netlink_send(cn_msg, 0, 0, GFP_ATOMIC);
 		kfree(cn_msg);
+		/*
+		 * We don't know when netlink messages are delivered but unlike
+		 * in CHARDEV mode we're not blocked and we can send next
+		 * messages right away.
+		 */
+		if (on_read_cb)
+			on_read_cb();
 		return ret;
 	}
 	/* HVUTIL_TRANSPORT_CHARDEV */
-	mutex_lock(&hvt->outmsg_lock);
+	mutex_lock(&hvt->lock);
+	if (hvt->mode != HVUTIL_TRANSPORT_CHARDEV) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
 	if (hvt->outmsg) {
 		/* Previous message wasn't received */
 		ret = -EFAULT;
 		goto out_unlock;
 	}
 	hvt->outmsg = kzalloc(len, GFP_KERNEL);
-	memcpy(hvt->outmsg, msg, len);
-	hvt->outmsg_len = len;
-	wake_up_interruptible(&hvt->outmsg_q);
+	if (hvt->outmsg) {
+		memcpy(hvt->outmsg, msg, len);
+		hvt->outmsg_len = len;
+		hvt->on_read = on_read_cb;
+		wake_up_interruptible(&hvt->outmsg_q);
+	} else
+		ret = -ENOMEM;
 out_unlock:
-	mutex_unlock(&hvt->outmsg_lock);
+	mutex_unlock(&hvt->lock);
 	return ret;
 }
 
@@ -239,7 +304,8 @@
 	hvt->mdev.fops = &hvt->fops;
 
 	init_waitqueue_head(&hvt->outmsg_q);
-	mutex_init(&hvt->outmsg_lock);
+	mutex_init(&hvt->lock);
+	init_completion(&hvt->release);
 
 	spin_lock(&hvt_list_lock);
 	list_add(&hvt->list, &hvt_list);
@@ -259,18 +325,36 @@
 	return hvt;
 
 err_free_hvt:
+	spin_lock(&hvt_list_lock);
+	list_del(&hvt->list);
+	spin_unlock(&hvt_list_lock);
 	kfree(hvt);
 	return NULL;
 }
 
 void hvutil_transport_destroy(struct hvutil_transport *hvt)
 {
+	int mode_old;
+
+	mutex_lock(&hvt->lock);
+	mode_old = hvt->mode;
+	hvt->mode = HVUTIL_TRANSPORT_DESTROY;
+	wake_up_interruptible(&hvt->outmsg_q);
+	mutex_unlock(&hvt->lock);
+
+	/*
+	 * In case we were in 'chardev' mode we still have an open fd so we
+	 * have to defer freeing the device. Netlink interface can be freed
+	 * now.
+	 */
 	spin_lock(&hvt_list_lock);
 	list_del(&hvt->list);
 	spin_unlock(&hvt_list_lock);
 	if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0)
 		cn_del_callback(&hvt->cn_id);
-	misc_deregister(&hvt->mdev);
-	kfree(hvt->outmsg);
-	kfree(hvt);
+
+	if (mode_old == HVUTIL_TRANSPORT_CHARDEV)
+		wait_for_completion(&hvt->release);
+
+	hvt_transport_free(hvt);
 }
--- linux-4.4.0.orig/drivers/hv/hv_utils_transport.h
+++ linux-4.4.0/drivers/hv/hv_utils_transport.h
@@ -25,6 +25,7 @@
 	HVUTIL_TRANSPORT_INIT = 0,
 	HVUTIL_TRANSPORT_NETLINK,
 	HVUTIL_TRANSPORT_CHARDEV,
+	HVUTIL_TRANSPORT_DESTROY,
 };
 
 struct hvutil_transport {
@@ -35,17 +36,20 @@
 	struct list_head list;              /* hvt_list */
 	int (*on_msg)(void *, int);         /* callback on new user message */
 	void (*on_reset)(void);             /* callback when userspace drops */
+	void (*on_read)(void);              /* callback on message read */
 	u8 *outmsg;                         /* message to the userspace */
 	int outmsg_len;                     /* its length */
 	wait_queue_head_t outmsg_q;         /* poll/read wait queue */
-	struct mutex outmsg_lock;           /* protects outmsg */
+	struct mutex lock;                  /* protects struct members */
+	struct completion release;          /* synchronize with fd release */
 };
 
 struct hvutil_transport *hvutil_transport_init(const char *name,
 					       u32 cn_idx, u32 cn_val,
 					       int (*on_msg)(void *, int),
 					       void (*on_reset)(void));
-int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len);
+int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len,
+			  void (*on_read_cb)(void));
 void hvutil_transport_destroy(struct hvutil_transport *hvt);
 
 #endif /* _HV_UTILS_TRANSPORT_H */
--- linux-4.4.0.orig/drivers/hv/hyperv_vmbus.h
+++ linux-4.4.0/drivers/hv/hyperv_vmbus.h
@@ -29,6 +29,17 @@
 #include <asm/sync_bitops.h>
 #include <linux/atomic.h>
 #include <linux/hyperv.h>
+#include <linux/clocksource.h>
+
+/*
+ * Timeout for services such as KVP and fcopy.
+ */
+#define HV_UTIL_TIMEOUT 30
+
+/*
+ * Timeout for guest-host handshake for services.
+ */
+#define HV_UTIL_NEGO_TIMEOUT 60
 
 /*
  * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
@@ -63,10 +74,6 @@
 /* Define version of the synthetic interrupt controller. */
 #define HV_SYNIC_VERSION		(1)
 
-/* Define synthetic interrupt controller message constants. */
-#define HV_MESSAGE_SIZE			(256)
-#define HV_MESSAGE_PAYLOAD_BYTE_COUNT	(240)
-#define HV_MESSAGE_PAYLOAD_QWORD_COUNT	(30)
 #define HV_ANY_VP			(0xFFFFFFFF)
 
 /* Define synthetic interrupt controller flag constants. */
@@ -74,48 +81,9 @@
 #define HV_EVENT_FLAGS_BYTE_COUNT	(256)
 #define HV_EVENT_FLAGS_DWORD_COUNT	(256 / sizeof(u32))
 
-/* Define hypervisor message types. */
-enum hv_message_type {
-	HVMSG_NONE			= 0x00000000,
-
-	/* Memory access messages. */
-	HVMSG_UNMAPPED_GPA		= 0x80000000,
-	HVMSG_GPA_INTERCEPT		= 0x80000001,
-
-	/* Timer notification messages. */
-	HVMSG_TIMER_EXPIRED			= 0x80000010,
-
-	/* Error messages. */
-	HVMSG_INVALID_VP_REGISTER_VALUE	= 0x80000020,
-	HVMSG_UNRECOVERABLE_EXCEPTION	= 0x80000021,
-	HVMSG_UNSUPPORTED_FEATURE		= 0x80000022,
-
-	/* Trace buffer complete messages. */
-	HVMSG_EVENTLOG_BUFFERCOMPLETE	= 0x80000040,
-
-	/* Platform-specific processor intercept messages. */
-	HVMSG_X64_IOPORT_INTERCEPT		= 0x80010000,
-	HVMSG_X64_MSR_INTERCEPT		= 0x80010001,
-	HVMSG_X64_CPUID_INTERCEPT		= 0x80010002,
-	HVMSG_X64_EXCEPTION_INTERCEPT	= 0x80010003,
-	HVMSG_X64_APIC_EOI			= 0x80010004,
-	HVMSG_X64_LEGACY_FP_ERROR		= 0x80010005
-};
-
-#define HV_SYNIC_STIMER_COUNT		(4)
-
 /* Define invalid partition identifier. */
 #define HV_PARTITION_ID_INVALID		((u64)0x0)
 
-/* Define port identifier type. */
-union hv_port_id {
-	u32 asu32;
-	struct {
-		u32 id:24;
-		u32 reserved:8;
-	} u ;
-};
-
 /* Define port type. */
 enum hv_port_type {
 	HVPORT_MSG	= 1,
@@ -163,27 +131,6 @@
 	};
 };
 
-/* Define synthetic interrupt controller message flags. */
-union hv_message_flags {
-	u8 asu8;
-	struct {
-		u8 msg_pending:1;
-		u8 reserved:7;
-	};
-};
-
-/* Define synthetic interrupt controller message header. */
-struct hv_message_header {
-	enum hv_message_type message_type;
-	u8 payload_size;
-	union hv_message_flags message_flags;
-	u8 reserved[2];
-	union {
-		u64 sender;
-		union hv_port_id port;
-	};
-};
-
 /*
  * Timer configuration register.
  */
@@ -200,31 +147,9 @@
 	};
 };
 
-
-/* Define timer message payload structure. */
-struct hv_timer_message_payload {
-	u32 timer_index;
-	u32 reserved;
-	u64 expiration_time;	/* When the timer expired */
-	u64 delivery_time;	/* When the message was delivered */
-};
-
-/* Define synthetic interrupt controller message format. */
-struct hv_message {
-	struct hv_message_header header;
-	union {
-		u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
-	} u ;
-};
-
 /* Define the number of message buffers associated with each port. */
 #define HV_PORT_MESSAGE_BUFFER_COUNT	(16)
 
-/* Define the synthetic interrupt message page layout. */
-struct hv_message_page {
-	struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
-};
-
 /* Define the synthetic interrupt controller event flags format. */
 union hv_synic_event_flags {
 	u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT];
@@ -337,17 +262,11 @@
 	u8 rsvdz4[1984];
 };
 
-/* Declare the various hypercall operations. */
-enum hv_call_code {
-	HVCALL_POST_MESSAGE	= 0x005c,
-	HVCALL_SIGNAL_EVENT	= 0x005d,
-};
-
 /* Definition of the hv_post_message hypercall input structure. */
 struct hv_input_post_message {
 	union hv_connection_id connectionid;
 	u32 reserved;
-	enum hv_message_type message_type;
+	u32 message_type;
 	u32 payload_size;
 	u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
 };
@@ -530,10 +449,11 @@
 	u32 vp_index[NR_CPUS];
 	/*
 	 * Starting with win8, we can take channel interrupts on any CPU;
-	 * we will manage the tasklet that handles events on a per CPU
+	 * we will manage the tasklet that handles events messages on a per CPU
 	 * basis.
 	 */
 	struct tasklet_struct *event_dpc[NR_CPUS];
+	struct tasklet_struct *msg_dpc[NR_CPUS];
 	/*
 	 * To optimize the mapping of relid to channel, maintain
 	 * per-cpu list of the channels based on their CPU affinity.
@@ -576,14 +496,12 @@
 
 extern int hv_init(void);
 
-extern void hv_cleanup(void);
+extern void hv_cleanup(bool crash);
 
 extern int hv_post_message(union hv_connection_id connection_id,
 			 enum hv_message_type message_type,
 			 void *payload, size_t payload_size);
 
-extern u16 hv_signal_event(void *con_id);
-
 extern int hv_synic_alloc(void);
 
 extern void hv_synic_free(void);
@@ -605,23 +523,19 @@
 /* Interface */
 
 
-int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
-		   u32 buflen);
+int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
+		       struct page *pages, u32 pagecnt);
 
 void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
 
-int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
+int hv_ringbuffer_write(struct vmbus_channel *channel,
 		    struct kvec *kv_list,
-		    u32 kv_count, bool *signal);
-
-int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
-		   u32 buflen);
-
-int hv_ringbuffer_read(struct hv_ring_buffer_info *ring_info,
-		   void *buffer,
-		   u32 buflen,
-		   u32 offset, bool *signal);
+		    u32 kv_count, bool lock,
+		    bool kick_q);
 
+int hv_ringbuffer_read(struct vmbus_channel *channel,
+		       void *buffer, u32 buflen, u32 *buffer_actual_len,
+		       u64 *requestid, bool raw);
 
 void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
 			    struct hv_ring_buffer_debug_info *debug_info);
@@ -678,7 +592,7 @@
 
 	/* List of channels */
 	struct list_head chn_list;
-	spinlock_t channel_lock;
+	struct mutex channel_mutex;
 
 	struct workqueue_struct *work_queue;
 };
@@ -712,6 +626,42 @@
 extern struct vmbus_channel_message_table_entry
 	channel_message_table[CHANNELMSG_COUNT];
 
+/* Free the message slot and signal end-of-message if required */
+static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
+{
+	/*
+	 * On crash we're reading some other CPU's message page and we need
+	 * to be careful: this other CPU may already had cleared the header
+	 * and the host may already had delivered some other message there.
+	 * In case we blindly write msg->header.message_type we're going
+	 * to lose it. We can still lose a message of the same type but
+	 * we count on the fact that there can only be one
+	 * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
+	 * on crash.
+	 */
+	if (cmpxchg(&msg->header.message_type, old_msg_type,
+		    HVMSG_NONE) != old_msg_type)
+		return;
+
+	/*
+	 * Make sure the write to MessageType (ie set to
+	 * HVMSG_NONE) happens before we read the
+	 * MessagePending and EOMing. Otherwise, the EOMing
+	 * will not deliver any more messages since there is
+	 * no empty slot
+	 */
+	mb();
+
+	if (msg->header.message_flags.msg_pending) {
+		/*
+		 * This will cause message queue rescan to
+		 * possibly deliver another msg from the
+		 * hypervisor
+		 */
+		wrmsrl(HV_X64_MSR_EOM, 0);
+	}
+}
+
 /* General vmbus interface */
 
 struct hv_device *vmbus_device_create(const uuid_le *type,
@@ -734,11 +684,10 @@
 int vmbus_connect(void);
 void vmbus_disconnect(void);
 
-int vmbus_post_msg(void *buffer, size_t buflen);
-
-int vmbus_set_event(struct vmbus_channel *channel);
+int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep);
 
 void vmbus_on_event(unsigned long data);
+void vmbus_on_msg_dpc(unsigned long data);
 
 int hv_kvp_init(struct hv_util_service *);
 void hv_kvp_deinit(void);
@@ -751,7 +700,7 @@
 int hv_fcopy_init(struct hv_util_service *);
 void hv_fcopy_deinit(void);
 void hv_fcopy_onchannelcallback(void *);
-void vmbus_initiate_unload(void);
+void vmbus_initiate_unload(bool crash);
 
 static inline void hv_poll_channel(struct vmbus_channel *channel,
 				   void (*cb)(void *))
@@ -759,11 +708,7 @@
 	if (!channel)
 		return;
 
-	if (channel->target_cpu != smp_processor_id())
-		smp_call_function_single(channel->target_cpu,
-					 cb, channel, true);
-	else
-		cb(channel);
+	smp_call_function_single(channel->target_cpu, cb, channel, true);
 }
 
 enum hvutil_device_state {
@@ -775,4 +720,6 @@
 	HVUTIL_DEVICE_DYING,     /* driver unload is in progress */
 };
 
+extern struct clocksource *hyperv_cs;
+
 #endif /* _HYPERV_VMBUS_H */
--- linux-4.4.0.orig/drivers/hv/ring_buffer.c
+++ linux-4.4.0/drivers/hv/ring_buffer.c
@@ -27,31 +27,29 @@
 #include <linux/mm.h>
 #include <linux/hyperv.h>
 #include <linux/uio.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
 
 #include "hyperv_vmbus.h"
 
 void hv_begin_read(struct hv_ring_buffer_info *rbi)
 {
 	rbi->ring_buffer->interrupt_mask = 1;
-	mb();
+	virt_mb();
 }
 
 u32 hv_end_read(struct hv_ring_buffer_info *rbi)
 {
-	u32 read;
-	u32 write;
 
 	rbi->ring_buffer->interrupt_mask = 0;
-	mb();
+	virt_mb();
 
 	/*
 	 * Now check to see if the ring buffer is still empty.
 	 * If it is not, we raced and we need to process new
 	 * incoming messages.
 	 */
-	hv_get_ringbuffer_availbytes(rbi, &read, &write);
-
-	return read;
+	return hv_get_bytes_to_read(rbi);
 }
 
 /*
@@ -68,72 +66,39 @@
  *	   once the ring buffer is empty, it will clear the
  *	   interrupt_mask and re-check to see if new data has
  *	   arrived.
- */
-
-static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
-{
-	mb();
-	if (rbi->ring_buffer->interrupt_mask)
-		return false;
+ *
+ * KYS: Oct. 30, 2016:
+ * It looks like Windows hosts have logic to deal with DOS attacks that
+ * can be triggered if it receives interrupts when it is not expecting
+ * the interrupt. The host expects interrupts only when the ring
+ * transitions from empty to non-empty (or full to non full on the guest
+ * to host ring).
+ * So, base the signaling decision solely on the ring state until the
+ * host logic is fixed.
+ */
+
+static void hv_signal_on_write(u32 old_write, struct vmbus_channel *channel,
+			       bool kick_q)
+{
+	struct hv_ring_buffer_info *rbi = &channel->outbound;
+
+	virt_mb();
+	if (READ_ONCE(rbi->ring_buffer->interrupt_mask))
+		return;
 
 	/* check interrupt_mask before read_index */
-	rmb();
+	virt_rmb();
 	/*
 	 * This is the only case we need to signal when the
 	 * ring transitions from being empty to non-empty.
 	 */
-	if (old_write == rbi->ring_buffer->read_index)
-		return true;
-
-	return false;
-}
-
-/*
- * To optimize the flow management on the send-side,
- * when the sender is blocked because of lack of
- * sufficient space in the ring buffer, potential the
- * consumer of the ring buffer can signal the producer.
- * This is controlled by the following parameters:
- *
- * 1. pending_send_sz: This is the size in bytes that the
- *    producer is trying to send.
- * 2. The feature bit feat_pending_send_sz set to indicate if
- *    the consumer of the ring will signal when the ring
- *    state transitions from being full to a state where
- *    there is room for the producer to send the pending packet.
- */
-
-static bool hv_need_to_signal_on_read(u32 prev_write_sz,
-				      struct hv_ring_buffer_info *rbi)
-{
-	u32 cur_write_sz;
-	u32 r_size;
-	u32 write_loc = rbi->ring_buffer->write_index;
-	u32 read_loc = rbi->ring_buffer->read_index;
-	u32 pending_sz = rbi->ring_buffer->pending_send_sz;
-
-	/*
-	 * If the other end is not blocked on write don't bother.
-	 */
-	if (pending_sz == 0)
-		return false;
-
-	r_size = rbi->ring_datasize;
-	cur_write_sz = write_loc >= read_loc ? r_size - (write_loc - read_loc) :
-			read_loc - write_loc;
-
-	if ((prev_write_sz < pending_sz) && (cur_write_sz >= pending_sz))
-		return true;
+	if (old_write == READ_ONCE(rbi->ring_buffer->read_index))
+		vmbus_setevent(channel);
 
-	return false;
+	return;
 }
 
-/*
- * hv_get_next_write_location()
- *
- * Get the next write location for the specified ring buffer
- *
- */
+/* Get the next write location for the specified ring buffer. */
 static inline u32
 hv_get_next_write_location(struct hv_ring_buffer_info *ring_info)
 {
@@ -142,12 +107,7 @@
 	return next;
 }
 
-/*
- * hv_set_next_write_location()
- *
- * Set the next write location for the specified ring buffer
- *
- */
+/* Set the next write location for the specified ring buffer. */
 static inline void
 hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
 		     u32 next_write_location)
@@ -155,11 +115,7 @@
 	ring_info->ring_buffer->write_index = next_write_location;
 }
 
-/*
- * hv_get_next_read_location()
- *
- * Get the next read location for the specified ring buffer
- */
+/* Get the next read location for the specified ring buffer. */
 static inline u32
 hv_get_next_read_location(struct hv_ring_buffer_info *ring_info)
 {
@@ -169,10 +125,8 @@
 }
 
 /*
- * hv_get_next_readlocation_withoffset()
- *
  * Get the next read location + offset for the specified ring buffer.
- * This allows the caller to skip
+ * This allows the caller to skip.
  */
 static inline u32
 hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
@@ -186,53 +140,23 @@
 	return next;
 }
 
-/*
- *
- * hv_set_next_read_location()
- *
- * Set the next read location for the specified ring buffer
- *
- */
+/* Set the next read location for the specified ring buffer. */
 static inline void
 hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
 		    u32 next_read_location)
 {
 	ring_info->ring_buffer->read_index = next_read_location;
+	ring_info->priv_read_index = next_read_location;
 }
 
-
-/*
- *
- * hv_get_ring_buffer()
- *
- * Get the start of the ring buffer
- */
-static inline void *
-hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
-{
-	return (void *)ring_info->ring_buffer->buffer;
-}
-
-
-/*
- *
- * hv_get_ring_buffersize()
- *
- * Get the size of the ring buffer
- */
+/* Get the size of the ring buffer. */
 static inline u32
 hv_get_ring_buffersize(struct hv_ring_buffer_info *ring_info)
 {
 	return ring_info->ring_datasize;
 }
 
-/*
- *
- * hv_get_ring_bufferindices()
- *
- * Get the read and write indices as u64 of the specified ring buffer
- *
- */
+/* Get the read and write indices as u64 of the specified ring buffer. */
 static inline u64
 hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
 {
@@ -240,12 +164,8 @@
 }
 
 /*
- *
- * hv_copyfrom_ringbuffer()
- *
  * Helper routine to copy to source from ring buffer.
  * Assume there is enough room. Handles wrap-around in src case only!!
- *
  */
 static u32 hv_copyfrom_ringbuffer(
 	struct hv_ring_buffer_info	*ring_info,
@@ -256,18 +176,7 @@
 	void *ring_buffer = hv_get_ring_buffer(ring_info);
 	u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
 
-	u32 frag_len;
-
-	/* wrap-around detected at the src */
-	if (destlen > ring_buffer_size - start_read_offset) {
-		frag_len = ring_buffer_size - start_read_offset;
-
-		memcpy(dest, ring_buffer + start_read_offset, frag_len);
-		memcpy(dest + frag_len, ring_buffer, destlen - frag_len);
-	} else
-
-		memcpy(dest, ring_buffer + start_read_offset, destlen);
-
+	memcpy(dest, ring_buffer + start_read_offset, destlen);
 
 	start_read_offset += destlen;
 	start_read_offset %= ring_buffer_size;
@@ -277,12 +186,8 @@
 
 
 /*
- *
- * hv_copyto_ringbuffer()
- *
  * Helper routine to copy from source to ring buffer.
  * Assume there is enough room. Handles wrap-around in dest case only!!
- *
  */
 static u32 hv_copyto_ringbuffer(
 	struct hv_ring_buffer_info	*ring_info,
@@ -292,15 +197,8 @@
 {
 	void *ring_buffer = hv_get_ring_buffer(ring_info);
 	u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
-	u32 frag_len;
 
-	/* wrap-around detected! */
-	if (srclen > ring_buffer_size - start_write_offset) {
-		frag_len = ring_buffer_size - start_write_offset;
-		memcpy(ring_buffer + start_write_offset, src, frag_len);
-		memcpy(ring_buffer, src + frag_len, srclen - frag_len);
-	} else
-		memcpy(ring_buffer + start_write_offset, src, srclen);
+	memcpy(ring_buffer + start_write_offset, src, srclen);
 
 	start_write_offset += srclen;
 	start_write_offset %= ring_buffer_size;
@@ -308,13 +206,7 @@
 	return start_write_offset;
 }
 
-/*
- *
- * hv_ringbuffer_get_debuginfo()
- *
- * Get various debug metrics for the specified ring buffer
- *
- */
+/* Get various debug metrics for the specified ring buffer. */
 void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
 			    struct hv_ring_buffer_debug_info *debug_info)
 {
@@ -337,86 +229,93 @@
 	}
 }
 
-/*
- *
- * hv_ringbuffer_init()
- *
- *Initialize the ring buffer
- *
- */
+/* Initialize the ring buffer. */
 int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
-		   void *buffer, u32 buflen)
+		       struct page *pages, u32 page_cnt)
 {
-	if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
-		return -EINVAL;
+	int i;
+	struct page **pages_wraparound;
+
+	BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE));
 
 	memset(ring_info, 0, sizeof(struct hv_ring_buffer_info));
 
-	ring_info->ring_buffer = (struct hv_ring_buffer *)buffer;
+	/*
+	 * First page holds struct hv_ring_buffer, do wraparound mapping for
+	 * the rest.
+	 */
+	pages_wraparound = kzalloc(sizeof(struct page *) * (page_cnt * 2 - 1),
+				   GFP_KERNEL);
+	if (!pages_wraparound)
+		return -ENOMEM;
+
+	pages_wraparound[0] = pages;
+	for (i = 0; i < 2 * (page_cnt - 1); i++)
+		pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1];
+
+	ring_info->ring_buffer = (struct hv_ring_buffer *)
+		vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL);
+
+	kfree(pages_wraparound);
+
+
+	if (!ring_info->ring_buffer)
+		return -ENOMEM;
+
 	ring_info->ring_buffer->read_index =
 		ring_info->ring_buffer->write_index = 0;
 
-	/*
-	 * Set the feature bit for enabling flow control.
-	 */
+	/* Set the feature bit for enabling flow control. */
 	ring_info->ring_buffer->feature_bits.value = 1;
 
-	ring_info->ring_size = buflen;
-	ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer);
+	ring_info->ring_size = page_cnt << PAGE_SHIFT;
+	ring_info->ring_datasize = ring_info->ring_size -
+		sizeof(struct hv_ring_buffer);
 
 	spin_lock_init(&ring_info->ring_lock);
 
 	return 0;
 }
 
-/*
- *
- * hv_ringbuffer_cleanup()
- *
- * Cleanup the ring buffer
- *
- */
+/* Cleanup the ring buffer. */
 void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
 {
+	vunmap(ring_info->ring_buffer);
 }
 
-/*
- *
- * hv_ringbuffer_write()
- *
- * Write to the ring buffer
- *
- */
-int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
-		    struct kvec *kv_list, u32 kv_count, bool *signal)
+/* Write to the ring buffer. */
+int hv_ringbuffer_write(struct vmbus_channel *channel,
+		    struct kvec *kv_list, u32 kv_count, bool lock,
+		    bool kick_q)
 {
 	int i = 0;
 	u32 bytes_avail_towrite;
-	u32 bytes_avail_toread;
 	u32 totalbytes_towrite = 0;
 
 	u32 next_write_location;
 	u32 old_write;
 	u64 prev_indices = 0;
-	unsigned long flags;
+	unsigned long flags = 0;
+	struct hv_ring_buffer_info *outring_info = &channel->outbound;
 
 	for (i = 0; i < kv_count; i++)
 		totalbytes_towrite += kv_list[i].iov_len;
 
 	totalbytes_towrite += sizeof(u64);
 
-	spin_lock_irqsave(&outring_info->ring_lock, flags);
+	if (lock)
+		spin_lock_irqsave(&outring_info->ring_lock, flags);
 
-	hv_get_ringbuffer_availbytes(outring_info,
-				&bytes_avail_toread,
-				&bytes_avail_towrite);
+	bytes_avail_towrite = hv_get_bytes_to_write(outring_info);
 
-
-	/* If there is only room for the packet, assume it is full. */
-	/* Otherwise, the next time around, we think the ring buffer */
-	/* is empty since the read index == write index */
+	/*
+	 * If there is only room for the packet, assume it is full.
+	 * Otherwise, the next time around, we think the ring buffer
+	 * is empty since the read index == write index.
+	 */
 	if (bytes_avail_towrite <= totalbytes_towrite) {
-		spin_unlock_irqrestore(&outring_info->ring_lock, flags);
+		if (lock)
+			spin_unlock_irqrestore(&outring_info->ring_lock, flags);
 		return -EAGAIN;
 	}
 
@@ -441,100 +340,72 @@
 					     sizeof(u64));
 
 	/* Issue a full memory barrier before updating the write index */
-	mb();
+	virt_mb();
 
 	/* Now, update the write location */
 	hv_set_next_write_location(outring_info, next_write_location);
 
 
-	spin_unlock_irqrestore(&outring_info->ring_lock, flags);
-
-	*signal = hv_need_to_signal(old_write, outring_info);
-	return 0;
-}
-
-
-/*
- *
- * hv_ringbuffer_peek()
- *
- * Read without advancing the read index
- *
- */
-int hv_ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
-		   void *Buffer, u32 buflen)
-{
-	u32 bytes_avail_towrite;
-	u32 bytes_avail_toread;
-	u32 next_read_location = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&Inring_info->ring_lock, flags);
-
-	hv_get_ringbuffer_availbytes(Inring_info,
-				&bytes_avail_toread,
-				&bytes_avail_towrite);
-
-	/* Make sure there is something to read */
-	if (bytes_avail_toread < buflen) {
-
-		spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
-
-		return -EAGAIN;
-	}
-
-	/* Convert to byte offset */
-	next_read_location = hv_get_next_read_location(Inring_info);
-
-	next_read_location = hv_copyfrom_ringbuffer(Inring_info,
-						Buffer,
-						buflen,
-						next_read_location);
-
-	spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
+	if (lock)
+		spin_unlock_irqrestore(&outring_info->ring_lock, flags);
 
+	hv_signal_on_write(old_write, channel, kick_q);
 	return 0;
 }
 
-
-/*
- *
- * hv_ringbuffer_read()
- *
- * Read and advance the read index
- *
- */
-int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
-		   u32 buflen, u32 offset, bool *signal)
+int hv_ringbuffer_read(struct vmbus_channel *channel,
+		       void *buffer, u32 buflen, u32 *buffer_actual_len,
+		       u64 *requestid, bool raw)
 {
-	u32 bytes_avail_towrite;
 	u32 bytes_avail_toread;
 	u32 next_read_location = 0;
 	u64 prev_indices = 0;
-	unsigned long flags;
+	struct vmpacket_descriptor desc;
+	u32 offset;
+	u32 packetlen;
+	int ret = 0;
+	struct hv_ring_buffer_info *inring_info = &channel->inbound;
 
 	if (buflen <= 0)
 		return -EINVAL;
 
-	spin_lock_irqsave(&inring_info->ring_lock, flags);
 
-	hv_get_ringbuffer_availbytes(inring_info,
-				&bytes_avail_toread,
-				&bytes_avail_towrite);
+	*buffer_actual_len = 0;
+	*requestid = 0;
 
+	bytes_avail_toread = hv_get_bytes_to_read(inring_info);
 	/* Make sure there is something to read */
-	if (bytes_avail_toread < buflen) {
-		spin_unlock_irqrestore(&inring_info->ring_lock, flags);
+	if (bytes_avail_toread < sizeof(desc)) {
+		/*
+		 * No error is set when there is even no header, drivers are
+		 * supposed to analyze buffer_actual_len.
+		 */
+		return ret;
+	}
+
+	init_cached_read_index(channel);
+	next_read_location = hv_get_next_read_location(inring_info);
+	next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
+						    sizeof(desc),
+						    next_read_location);
+
+	offset = raw ? 0 : (desc.offset8 << 3);
+	packetlen = (desc.len8 << 3) - offset;
+	*buffer_actual_len = packetlen;
+	*requestid = desc.trans_id;
 
+	if (bytes_avail_toread < packetlen + offset)
 		return -EAGAIN;
-	}
+
+	if (packetlen > buflen)
+		return -ENOBUFS;
 
 	next_read_location =
 		hv_get_next_readlocation_withoffset(inring_info, offset);
 
 	next_read_location = hv_copyfrom_ringbuffer(inring_info,
 						buffer,
-						buflen,
+						packetlen,
 						next_read_location);
 
 	next_read_location = hv_copyfrom_ringbuffer(inring_info,
@@ -542,17 +413,17 @@
 						sizeof(u64),
 						next_read_location);
 
-	/* Make sure all reads are done before we update the read index since */
-	/* the writer may start writing to the read area once the read index */
-	/*is updated */
-	mb();
+	/*
+	 * Make sure all reads are done before we update the read index since
+	 * the writer may start writing to the read area once the read index
+	 * is updated.
+	 */
+	virt_mb();
 
 	/* Update the read index */
 	hv_set_next_read_location(inring_info, next_read_location);
 
-	spin_unlock_irqrestore(&inring_info->ring_lock, flags);
+	hv_signal_on_read(channel);
 
-	*signal = hv_need_to_signal_on_read(bytes_avail_towrite, inring_info);
-
-	return 0;
+	return ret;
 }
--- linux-4.4.0.orig/drivers/hv/vmbus_drv.c
+++ linux-4.4.0/drivers/hv/vmbus_drv.c
@@ -41,13 +41,13 @@
 #include <linux/ptrace.h>
 #include <linux/screen_info.h>
 #include <linux/kdebug.h>
+#include <linux/efi.h>
+#include <linux/random.h>
 #include "hyperv_vmbus.h"
 
 static struct acpi_device  *hv_acpi_dev;
 
-static struct tasklet_struct msg_dpc;
 static struct completion probe_event;
-static int irq;
 
 
 static void hyperv_report_panic(struct pt_regs *regs)
@@ -103,7 +103,10 @@
 	.notifier_call = hyperv_panic_event,
 };
 
-struct resource *hyperv_mmio;
+static const char *fb_mmio_name = "fb_range";
+static struct resource *fb_mmio;
+static struct resource *hyperv_mmio;
+static DEFINE_SEMAPHORE(hyperv_mmio_lock);
 
 static int vmbus_exists(void)
 {
@@ -314,6 +317,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
 	return sprintf(buf, "%d\n", outbound.current_interrupt_mask);
 }
@@ -327,6 +332,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
 	return sprintf(buf, "%d\n", outbound.current_read_index);
 }
@@ -341,6 +348,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
 	return sprintf(buf, "%d\n", outbound.current_write_index);
 }
@@ -355,6 +364,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
 	return sprintf(buf, "%d\n", outbound.bytes_avail_toread);
 }
@@ -369,6 +380,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
 	return sprintf(buf, "%d\n", outbound.bytes_avail_towrite);
 }
@@ -382,6 +395,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
 	return sprintf(buf, "%d\n", inbound.current_interrupt_mask);
 }
@@ -395,6 +410,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
 	return sprintf(buf, "%d\n", inbound.current_read_index);
 }
@@ -408,6 +425,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
 	return sprintf(buf, "%d\n", inbound.current_write_index);
 }
@@ -422,6 +441,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
 	return sprintf(buf, "%d\n", inbound.bytes_avail_toread);
 }
@@ -436,6 +457,8 @@
 
 	if (!hv_dev->channel)
 		return -ENODEV;
+	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+		return -EINVAL;
 	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
 	return sprintf(buf, "%d\n", inbound.bytes_avail_towrite);
 }
@@ -478,6 +501,24 @@
 }
 static DEVICE_ATTR_RO(channel_vp_mapping);
 
+static ssize_t vendor_show(struct device *dev,
+			   struct device_attribute *dev_attr,
+			   char *buf)
+{
+	struct hv_device *hv_dev = device_to_hv_device(dev);
+	return sprintf(buf, "0x%x\n", hv_dev->vendor_id);
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t device_show(struct device *dev,
+			   struct device_attribute *dev_attr,
+			   char *buf)
+{
+	struct hv_device *hv_dev = device_to_hv_device(dev);
+	return sprintf(buf, "0x%x\n", hv_dev->device_id);
+}
+static DEVICE_ATTR_RO(device);
+
 /* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
 static struct attribute *vmbus_attrs[] = {
 	&dev_attr_id.attr,
@@ -503,6 +544,8 @@
 	&dev_attr_in_read_bytes_avail.attr,
 	&dev_attr_in_write_bytes_avail.attr,
 	&dev_attr_channel_vp_mapping.attr,
+	&dev_attr_vendor.attr,
+	&dev_attr_device.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(vmbus);
@@ -531,9 +574,9 @@
 
 static const uuid_le null_guid;
 
-static inline bool is_null_guid(const __u8 *guid)
+static inline bool is_null_guid(const uuid_le *guid)
 {
-	if (memcmp(guid, &null_guid, sizeof(uuid_le)))
+	if (uuid_le_cmp(*guid, null_guid))
 		return false;
 	return true;
 }
@@ -544,10 +587,10 @@
  */
 static const struct hv_vmbus_device_id *hv_vmbus_get_id(
 					const struct hv_vmbus_device_id *id,
-					const __u8 *guid)
+					const uuid_le *guid)
 {
-	for (; !is_null_guid(id->guid); id++)
-		if (!memcmp(&id->guid, guid, sizeof(uuid_le)))
+	for (; !is_null_guid(&id->guid); id++)
+		if (!uuid_le_cmp(id->guid, *guid))
 			return id;
 
 	return NULL;
@@ -563,7 +606,11 @@
 	struct hv_driver *drv = drv_to_hv_drv(driver);
 	struct hv_device *hv_dev = device_to_hv_device(device);
 
-	if (hv_vmbus_get_id(drv->id_table, hv_dev->dev_type.b))
+	/* The hv_sock driver handles all hv_sock offers. */
+	if (is_hvsock_channel(hv_dev->channel))
+		return drv->hvsock;
+
+	if (hv_vmbus_get_id(drv->id_table, &hv_dev->dev_type))
 		return 1;
 
 	return 0;
@@ -580,7 +627,7 @@
 	struct hv_device *dev = device_to_hv_device(child_device);
 	const struct hv_vmbus_device_id *dev_id;
 
-	dev_id = hv_vmbus_get_id(drv->id_table, dev->dev_type.b);
+	dev_id = hv_vmbus_get_id(drv->id_table, &dev->dev_type);
 	if (drv->probe) {
 		ret = drv->probe(dev, dev_id);
 		if (ret != 0)
@@ -602,23 +649,11 @@
 {
 	struct hv_driver *drv;
 	struct hv_device *dev = device_to_hv_device(child_device);
-	u32 relid = dev->channel->offermsg.child_relid;
 
 	if (child_device->driver) {
 		drv = drv_to_hv_drv(child_device->driver);
 		if (drv->remove)
 			drv->remove(dev);
-		else {
-			hv_process_channel_removal(dev->channel, relid);
-			pr_err("remove not set for driver %s\n",
-				dev_name(child_device));
-		}
-	} else {
-		/*
-		 * We don't have a driver for this device; deal with the
-		 * rescind message by removing the channel.
-		 */
-		hv_process_channel_removal(dev->channel, relid);
 	}
 
 	return 0;
@@ -653,7 +688,10 @@
 static void vmbus_device_release(struct device *device)
 {
 	struct hv_device *hv_dev = device_to_hv_device(device);
+	struct vmbus_channel *channel = hv_dev->channel;
 
+	hv_process_channel_removal(channel,
+				   channel->offermsg.child_relid);
 	kfree(hv_dev);
 
 }
@@ -695,28 +733,10 @@
 	if (dev->event_handler)
 		dev->event_handler(dev);
 
-	msg->header.message_type = HVMSG_NONE;
-
-	/*
-	 * Make sure the write to MessageType (ie set to
-	 * HVMSG_NONE) happens before we read the
-	 * MessagePending and EOMing. Otherwise, the EOMing
-	 * will not deliver any more messages since there is
-	 * no empty slot
-	 */
-	mb();
-
-	if (msg->header.message_flags.msg_pending) {
-		/*
-		 * This will cause message queue rescan to
-		 * possibly deliver another msg from the
-		 * hypervisor
-		 */
-		wrmsrl(HV_X64_MSR_EOM, 0);
-	}
+	vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
 }
 
-static void vmbus_on_msg_dpc(unsigned long data)
+void vmbus_on_msg_dpc(unsigned long data)
 {
 	int cpu = smp_processor_id();
 	void *page_addr = hv_context.synic_message_page[cpu];
@@ -725,53 +745,34 @@
 	struct vmbus_channel_message_header *hdr;
 	struct vmbus_channel_message_table_entry *entry;
 	struct onmessage_work_context *ctx;
+	u32 message_type = msg->header.message_type;
 
-	while (1) {
-		if (msg->header.message_type == HVMSG_NONE)
-			/* no msg */
-			break;
-
-		hdr = (struct vmbus_channel_message_header *)msg->u.payload;
-
-		if (hdr->msgtype >= CHANNELMSG_COUNT) {
-			WARN_ONCE(1, "unknown msgtype=%d\n", hdr->msgtype);
-			goto msg_handled;
-		}
+	if (message_type == HVMSG_NONE)
+		/* no msg */
+		return;
 
-		entry = &channel_message_table[hdr->msgtype];
-		if (entry->handler_type	== VMHT_BLOCKING) {
-			ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
-			if (ctx == NULL)
-				continue;
+	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
 
-			INIT_WORK(&ctx->work, vmbus_onmessage_work);
-			memcpy(&ctx->msg, msg, sizeof(*msg));
+	if (hdr->msgtype >= CHANNELMSG_COUNT) {
+		WARN_ONCE(1, "unknown msgtype=%d\n", hdr->msgtype);
+		goto msg_handled;
+	}
 
-			queue_work(vmbus_connection.work_queue, &ctx->work);
-		} else
-			entry->message_handler(hdr);
+	entry = &channel_message_table[hdr->msgtype];
+	if (entry->handler_type	== VMHT_BLOCKING) {
+		ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+		if (ctx == NULL)
+			return;
+
+		INIT_WORK(&ctx->work, vmbus_onmessage_work);
+		memcpy(&ctx->msg, msg, sizeof(*msg));
+
+		queue_work(vmbus_connection.work_queue, &ctx->work);
+	} else
+		entry->message_handler(hdr);
 
 msg_handled:
-		msg->header.message_type = HVMSG_NONE;
-
-		/*
-		 * Make sure the write to MessageType (ie set to
-		 * HVMSG_NONE) happens before we read the
-		 * MessagePending and EOMing. Otherwise, the EOMing
-		 * will not deliver any more messages since there is
-		 * no empty slot
-		 */
-		mb();
-
-		if (msg->header.message_flags.msg_pending) {
-			/*
-			 * This will cause message queue rescan to
-			 * possibly deliver another msg from the
-			 * hypervisor
-			 */
-			wrmsrl(HV_X64_MSR_EOM, 0);
-		}
-	}
+	vmbus_signal_eom(msg, message_type);
 }
 
 static void vmbus_isr(void)
@@ -824,8 +825,10 @@
 		if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
 			hv_process_timer_expiration(msg, cpu);
 		else
-			tasklet_schedule(&msg_dpc);
+			tasklet_schedule(hv_context.msg_dpc[cpu]);
 	}
+
+	add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0);
 }
 
 
@@ -835,10 +838,9 @@
  * Here, we
  *	- initialize the vmbus driver context
  *	- invoke the vmbus hv main init routine
- *	- get the irq resource
  *	- retrieve the channel offers
  */
-static int vmbus_bus_init(int irq)
+static int vmbus_bus_init(void)
 {
 	int ret;
 
@@ -849,8 +851,6 @@
 		return ret;
 	}
 
-	tasklet_init(&msg_dpc, vmbus_on_msg_dpc, 0);
-
 	ret = bus_register(&hv_bus);
 	if (ret)
 		goto err_cleanup;
@@ -867,7 +867,7 @@
 	on_each_cpu(hv_synic_init, NULL, 1);
 	ret = vmbus_connect();
 	if (ret)
-		goto err_alloc;
+		goto err_connect;
 
 	if (vmbus_proto_version > VERSION_WIN7)
 		cpu_hotplug_disable();
@@ -885,6 +885,8 @@
 
 	return 0;
 
+err_connect:
+	on_each_cpu(hv_synic_cleanup, NULL, 1);
 err_alloc:
 	hv_synic_free();
 	hv_remove_vmbus_irq();
@@ -892,7 +894,7 @@
 	bus_unregister(&hv_bus);
 
 err_cleanup:
-	hv_cleanup();
+	hv_cleanup(false);
 
 	return ret;
 }
@@ -966,6 +968,7 @@
 	memcpy(&child_device_obj->dev_type, type, sizeof(uuid_le));
 	memcpy(&child_device_obj->dev_instance, instance,
 	       sizeof(uuid_le));
+	child_device_obj->vendor_id = 0x1414; /* MSFT vendor ID */
 
 
 	return child_device_obj;
@@ -978,8 +981,8 @@
 {
 	int ret = 0;
 
-	dev_set_name(&child_device_obj->device, "vmbus_%d",
-		     child_device_obj->channel->id);
+	dev_set_name(&child_device_obj->device, "%pUl",
+		     child_device_obj->channel->offermsg.offer.if_instance.b);
 
 	child_device_obj->device.bus = &hv_bus;
 	child_device_obj->device.parent = &hv_acpi_dev->dev;
@@ -1031,9 +1034,6 @@
 	struct resource **prev_res = NULL;
 
 	switch (res->type) {
-	case ACPI_RESOURCE_TYPE_IRQ:
-		irq = res->data.irq.interrupts[0];
-		return AE_OK;
 
 	/*
 	 * "Address" descriptors are for bus windows. Ignore
@@ -1075,13 +1075,28 @@
 	new_res->start = start;
 	new_res->end = end;
 
+	/*
+	 * If two ranges are adjacent, merge them.
+	 */
 	do {
 		if (!*old_res) {
 			*old_res = new_res;
 			break;
 		}
 
-		if ((*old_res)->end < new_res->start) {
+		if (((*old_res)->end + 1) == new_res->start) {
+			(*old_res)->end = new_res->end;
+			kfree(new_res);
+			break;
+		}
+
+		if ((*old_res)->start == new_res->end + 1) {
+			(*old_res)->start = new_res->start;
+			kfree(new_res);
+			break;
+		}
+
+		if ((*old_res)->start > new_res->end) {
 			new_res->sibling = *old_res;
 			if (prev_res)
 				(*prev_res)->sibling = new_res;
@@ -1103,6 +1118,12 @@
 	struct resource *next_res;
 
 	if (hyperv_mmio) {
+		if (fb_mmio) {
+			__release_region(hyperv_mmio, fb_mmio->start,
+					 resource_size(fb_mmio));
+			fb_mmio = NULL;
+		}
+
 		for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) {
 			next_res = cur_res->sibling;
 			kfree(cur_res);
@@ -1112,6 +1133,30 @@
 	return 0;
 }
 
+static void vmbus_reserve_fb(void)
+{
+	int size;
+	/*
+	 * Make a claim for the frame buffer in the resource tree under the
+	 * first node, which will be the one below 4GB.  The length seems to
+	 * be underreported, particularly in a Generation 1 VM.  So start out
+	 * reserving a larger area and make it smaller until it succeeds.
+	 */
+
+	if (screen_info.lfb_base) {
+		if (efi_enabled(EFI_BOOT))
+			size = max_t(__u32, screen_info.lfb_size, 0x800000);
+		else
+			size = max_t(__u32, screen_info.lfb_size, 0x4000000);
+
+		for (; !fb_mmio && (size >= 0x100000); size >>= 1) {
+			fb_mmio = __request_region(hyperv_mmio,
+						   screen_info.lfb_base, size,
+						   fb_mmio_name, 0);
+		}
+	}
+}
+
 /**
  * vmbus_allocate_mmio() - Pick a memory-mapped I/O range.
  * @new:		If successful, supplied a pointer to the
@@ -1140,11 +1185,33 @@
 			resource_size_t size, resource_size_t align,
 			bool fb_overlap_ok)
 {
-	struct resource *iter;
-	resource_size_t range_min, range_max, start, local_min, local_max;
+	struct resource *iter, *shadow;
+	resource_size_t range_min, range_max, start;
 	const char *dev_n = dev_name(&device_obj->device);
-	u32 fb_end = screen_info.lfb_base + (screen_info.lfb_size << 1);
-	int i;
+	int retval;
+
+	retval = -ENXIO;
+	down(&hyperv_mmio_lock);
+
+	/*
+	 * If overlaps with frame buffers are allowed, then first attempt to
+	 * make the allocation from within the reserved region.  Because it
+	 * is already reserved, no shadow allocation is necessary.
+	 */
+	if (fb_overlap_ok && fb_mmio && !(min > fb_mmio->end) &&
+	    !(max < fb_mmio->start)) {
+
+		range_min = fb_mmio->start;
+		range_max = fb_mmio->end;
+		start = (range_min + align - 1) & ~(align - 1);
+		for (; start + size - 1 <= range_max; start += align) {
+			*new = request_mem_region_exclusive(start, size, dev_n);
+			if (*new) {
+				retval = 0;
+				goto exit;
+			}
+		}
+	}
 
 	for (iter = hyperv_mmio; iter; iter = iter->sibling) {
 		if ((iter->start >= max) || (iter->end <= min))
@@ -1152,45 +1219,72 @@
 
 		range_min = iter->start;
 		range_max = iter->end;
+		start = (range_min + align - 1) & ~(align - 1);
+		for (; start + size - 1 <= range_max; start += align) {
+			shadow = __request_region(iter, start, size, NULL,
+						  IORESOURCE_BUSY);
+			if (!shadow)
+				continue;
 
-		/* If this range overlaps the frame buffer, split it into
-		   two tries. */
-		for (i = 0; i < 2; i++) {
-			local_min = range_min;
-			local_max = range_max;
-			if (fb_overlap_ok || (range_min >= fb_end) ||
-			    (range_max <= screen_info.lfb_base)) {
-				i++;
-			} else {
-				if ((range_min <= screen_info.lfb_base) &&
-				    (range_max >= screen_info.lfb_base)) {
-					/*
-					 * The frame buffer is in this window,
-					 * so trim this into the part that
-					 * preceeds the frame buffer.
-					 */
-					local_max = screen_info.lfb_base - 1;
-					range_min = fb_end;
-				} else {
-					range_min = fb_end;
-					continue;
-				}
+			*new = request_mem_region_exclusive(start, size, dev_n);
+			if (*new) {
+				shadow->name = (char *)*new;
+				retval = 0;
+				goto exit;
 			}
 
-			start = (local_min + align - 1) & ~(align - 1);
-			for (; start + size - 1 <= local_max; start += align) {
-				*new = request_mem_region_exclusive(start, size,
-								    dev_n);
-				if (*new)
-					return 0;
-			}
+			__release_region(iter, start, size);
 		}
 	}
 
-	return -ENXIO;
+exit:
+	up(&hyperv_mmio_lock);
+	return retval;
 }
 EXPORT_SYMBOL_GPL(vmbus_allocate_mmio);
 
+/**
+ * vmbus_free_mmio() - Free a memory-mapped I/O range.
+ * @start:		Base address of region to release.
+ * @size:		Size of the range to be allocated
+ *
+ * This function releases anything requested by
+ * vmbus_mmio_allocate().
+ */
+void vmbus_free_mmio(resource_size_t start, resource_size_t size)
+{
+	struct resource *iter;
+
+	down(&hyperv_mmio_lock);
+	for (iter = hyperv_mmio; iter; iter = iter->sibling) {
+		if ((iter->start >= start + size) || (iter->end <= start))
+			continue;
+
+		__release_region(iter, start, size);
+	}
+	release_mem_region(start, size);
+	up(&hyperv_mmio_lock);
+
+}
+EXPORT_SYMBOL_GPL(vmbus_free_mmio);
+
+/**
+ * vmbus_cpu_number_to_vp_number() - Map CPU to VP.
+ * @cpu_number: CPU number in Linux terms
+ *
+ * This function returns the mapping between the Linux processor
+ * number and the hypervisor's virtual processor number, useful
+ * in making hypercalls and such that talk about specific
+ * processors.
+ *
+ * Return: Virtual processor number in Hyper-V terms
+ */
+int vmbus_cpu_number_to_vp_number(int cpu_number)
+{
+	return hv_context.vp_index[cpu_number];
+}
+EXPORT_SYMBOL_GPL(vmbus_cpu_number_to_vp_number);
+
 static int vmbus_acpi_add(struct acpi_device *device)
 {
 	acpi_status result;
@@ -1214,8 +1308,10 @@
 
 		if (ACPI_FAILURE(result))
 			continue;
-		if (hyperv_mmio)
+		if (hyperv_mmio) {
+			vmbus_reserve_fb();
 			break;
+		}
 	}
 	ret_val = 0;
 
@@ -1247,22 +1343,22 @@
 	int cpu;
 
 	hv_synic_clockevents_cleanup();
-	vmbus_initiate_unload();
+	vmbus_initiate_unload(false);
 	for_each_online_cpu(cpu)
 		smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
-	hv_cleanup();
+	hv_cleanup(false);
 };
 
 static void hv_crash_handler(struct pt_regs *regs)
 {
-	vmbus_initiate_unload();
+	vmbus_initiate_unload(true);
 	/*
 	 * In crash handler we can't schedule synic cleanup for all CPUs,
 	 * doing the cleanup for current CPU only. This should be sufficient
 	 * for kdump.
 	 */
 	hv_synic_cleanup(NULL);
-	hv_cleanup();
+	hv_cleanup(true);
 };
 
 static int __init hv_acpi_init(void)
@@ -1275,7 +1371,7 @@
 	init_completion(&probe_event);
 
 	/*
-	 * Get irq resources first.
+	 * Get ACPI resources first.
 	 */
 	ret = acpi_bus_register_driver(&vmbus_acpi_driver);
 
@@ -1288,12 +1384,7 @@
 		goto cleanup;
 	}
 
-	if (irq <= 0) {
-		ret = -ENODEV;
-		goto cleanup;
-	}
-
-	ret = vmbus_bus_init(irq);
+	ret = vmbus_bus_init();
 	if (ret)
 		goto cleanup;
 
@@ -1318,7 +1409,8 @@
 	hv_synic_clockevents_cleanup();
 	vmbus_disconnect();
 	hv_remove_vmbus_irq();
-	tasklet_kill(&msg_dpc);
+	for_each_online_cpu(cpu)
+		tasklet_kill(hv_context.msg_dpc[cpu]);
 	vmbus_free_channels();
 	if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
 		unregister_die_notifier(&hyperv_die_block);
@@ -1326,7 +1418,7 @@
 						 &hyperv_panic_block);
 	}
 	bus_unregister(&hv_bus);
-	hv_cleanup();
+	hv_cleanup(false);
 	for_each_online_cpu(cpu) {
 		tasklet_kill(hv_context.event_dpc[cpu]);
 		smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
--- linux-4.4.0.orig/drivers/hwmon/acpi_power_meter.c
+++ linux-4.4.0/drivers/hwmon/acpi_power_meter.c
@@ -693,8 +693,8 @@
 
 	if (resource->caps.flags & POWER_METER_CAN_CAP) {
 		if (!can_cap_in_hardware()) {
-			dev_err(&resource->acpi_dev->dev,
-				"Ignoring unsafe software power cap!\n");
+			dev_warn(&resource->acpi_dev->dev,
+				 "Ignoring unsafe software power cap!\n");
 			goto skip_unsafe_cap;
 		}
 
@@ -895,7 +895,7 @@
 
 	res = setup_attrs(resource);
 	if (res)
-		goto exit_free;
+		goto exit_free_capability;
 
 	resource->hwmon_dev = hwmon_device_register(&device->dev);
 	if (IS_ERR(resource->hwmon_dev)) {
@@ -908,6 +908,8 @@
 
 exit_remove:
 	remove_attrs(resource);
+exit_free_capability:
+	free_capabilities(resource);
 exit_free:
 	kfree(resource);
 exit:
--- linux-4.4.0.orig/drivers/hwmon/adc128d818.c
+++ linux-4.4.0/drivers/hwmon/adc128d818.c
@@ -171,7 +171,7 @@
 
 	mutex_lock(&data->update_lock);
 	/* 10 mV LSB on limit registers */
-	regval = clamp_val(DIV_ROUND_CLOSEST(val, 10), 0, 255);
+	regval = DIV_ROUND_CLOSEST(clamp_val(val, 0, 2550), 10);
 	data->in[index][nr] = regval << 4;
 	reg = index == 1 ? ADC128_REG_IN_MIN(nr) : ADC128_REG_IN_MAX(nr);
 	i2c_smbus_write_byte_data(data->client, reg, regval);
@@ -209,7 +209,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	regval = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+	regval = DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), 1000);
 	data->temp[index] = regval << 1;
 	i2c_smbus_write_byte_data(data->client,
 				  index == 1 ? ADC128_REG_TEMP_MAX
--- linux-4.4.0.orig/drivers/hwmon/ads1015.c
+++ linux-4.4.0/drivers/hwmon/ads1015.c
@@ -126,7 +126,7 @@
 	struct ads1015_data *data = i2c_get_clientdata(client);
 	unsigned int pga = data->channel_data[channel].pga;
 	int fullscale = fullscale_table[pga];
-	const unsigned mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
+	const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
 
 	return DIV_ROUND_CLOSEST(reg * fullscale, mask);
 }
--- linux-4.4.0.orig/drivers/hwmon/ads7828.c
+++ linux-4.4.0/drivers/hwmon/ads7828.c
@@ -120,6 +120,7 @@
 	unsigned int vref_mv = ADS7828_INT_VREF_MV;
 	bool diff_input = false;
 	bool ext_vref = false;
+	unsigned int regval;
 
 	data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
 	if (!data)
@@ -154,6 +155,15 @@
 	if (!diff_input)
 		data->cmd_byte |= ADS7828_CMD_SD_SE;
 
+	/*
+	 * Datasheet specifies internal reference voltage is disabled by
+	 * default. The internal reference voltage needs to be enabled and
+	 * voltage needs to settle before getting valid ADC data. So perform a
+	 * dummy read to enable the internal reference voltage.
+	 */
+	if (!ext_vref)
+		regmap_read(data->regmap, data->cmd_byte, &regval);
+
 	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
 							   data,
 							   ads7828_groups);
--- linux-4.4.0.orig/drivers/hwmon/adt7411.c
+++ linux-4.4.0/drivers/hwmon/adt7411.c
@@ -30,6 +30,7 @@
 
 #define ADT7411_REG_CFG1			0x18
 #define ADT7411_CFG1_START_MONITOR		(1 << 0)
+#define ADT7411_CFG1_RESERVED_BIT3		(1 << 3)
 
 #define ADT7411_REG_CFG2			0x19
 #define ADT7411_CFG2_DISABLE_AVG		(1 << 5)
@@ -296,8 +297,10 @@
 	mutex_init(&data->device_lock);
 	mutex_init(&data->update_lock);
 
+	/* According to the datasheet, we must only write 1 to bit 3 */
 	ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
-				 ADT7411_CFG1_START_MONITOR, 1);
+				 ADT7411_CFG1_RESERVED_BIT3
+				 | ADT7411_CFG1_START_MONITOR, 1);
 	if (ret < 0)
 		return ret;
 
--- linux-4.4.0.orig/drivers/hwmon/adt7462.c
+++ linux-4.4.0/drivers/hwmon/adt7462.c
@@ -426,7 +426,7 @@
 			return 0x95;
 		break;
 	}
-	return -ENODEV;
+	return 0;
 }
 
 /* Provide labels for sysfs */
--- linux-4.4.0.orig/drivers/hwmon/adt7475.c
+++ linux-4.4.0/drivers/hwmon/adt7475.c
@@ -268,20 +268,25 @@
 	long reg;
 
 	if (bypass_attn & (1 << channel))
-		reg = (volt * 1024) / 2250;
+		reg = DIV_ROUND_CLOSEST(volt * 1024, 2250);
 	else
-		reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250);
+		reg = DIV_ROUND_CLOSEST(volt * r[1] * 1024,
+					(r[0] + r[1]) * 2250);
 	return clamp_val(reg, 0, 1023) & (0xff << 2);
 }
 
-static u16 adt7475_read_word(struct i2c_client *client, int reg)
+static int adt7475_read_word(struct i2c_client *client, int reg)
 {
-	u16 val;
+	int val1, val2;
 
-	val = i2c_smbus_read_byte_data(client, reg);
-	val |= (i2c_smbus_read_byte_data(client, reg + 1) << 8);
+	val1 = i2c_smbus_read_byte_data(client, reg);
+	if (val1 < 0)
+		return val1;
+	val2 = i2c_smbus_read_byte_data(client, reg + 1);
+	if (val2 < 0)
+		return val2;
 
-	return val;
+	return val1 | (val2 << 8);
 }
 
 static void adt7475_write_word(struct i2c_client *client, int reg, u16 val)
--- linux-4.4.0.orig/drivers/hwmon/amc6821.c
+++ linux-4.4.0/drivers/hwmon/amc6821.c
@@ -188,8 +188,8 @@
 			!data->valid) {
 
 		for (i = 0; i < TEMP_IDX_LEN; i++)
-			data->temp[i] = i2c_smbus_read_byte_data(client,
-				temp_reg[i]);
+			data->temp[i] = (int8_t)i2c_smbus_read_byte_data(
+				client, temp_reg[i]);
 
 		data->stat1 = i2c_smbus_read_byte_data(client,
 			AMC6821_REG_STAT1);
--- linux-4.4.0.orig/drivers/hwmon/applesmc.c
+++ linux-4.4.0/drivers/hwmon/applesmc.c
@@ -758,15 +758,18 @@
 	}
 
 	ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
+	if (ret)
+		goto out;
 	/* newer macbooks report a single 10-bit bigendian value */
 	if (data_length == 10) {
 		left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
 		goto out;
 	}
 	left = buffer[2];
+
+	ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
 	if (ret)
 		goto out;
-	ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
 	right = buffer[2];
 
 out:
@@ -814,12 +817,11 @@
 	sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
 
 	ret = applesmc_read_key(newkey, buffer, 2);
-	speed = ((buffer[0] << 8 | buffer[1]) >> 2);
-
 	if (ret)
 		return ret;
-	else
-		return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
+
+	speed = ((buffer[0] << 8 | buffer[1]) >> 2);
+	return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
 }
 
 static ssize_t applesmc_store_fan_speed(struct device *dev,
@@ -854,12 +856,11 @@
 	u8 buffer[2];
 
 	ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
-	manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
-
 	if (ret)
 		return ret;
-	else
-		return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
+
+	manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
+	return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
 }
 
 static ssize_t applesmc_store_fan_manual(struct device *dev,
@@ -875,10 +876,11 @@
 		return -EINVAL;
 
 	ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
-	val = (buffer[0] << 8 | buffer[1]);
 	if (ret)
 		goto out;
 
+	val = (buffer[0] << 8 | buffer[1]);
+
 	if (input)
 		val = val | (0x01 << to_index(attr));
 	else
@@ -954,13 +956,12 @@
 	u32 count;
 
 	ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
-	count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
-						((u32)buffer[2]<<8) + buffer[3];
-
 	if (ret)
 		return ret;
-	else
-		return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
+
+	count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
+						((u32)buffer[2]<<8) + buffer[3];
+	return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
 }
 
 static ssize_t applesmc_key_at_index_read_show(struct device *dev,
--- linux-4.4.0.orig/drivers/hwmon/asus_atk0110.c
+++ linux-4.4.0/drivers/hwmon/asus_atk0110.c
@@ -646,6 +646,9 @@
 		else
 			err = atk_read_value_new(sensor, value);
 
+		if (err)
+			return err;
+
 		sensor->is_valid = true;
 		sensor->last_updated = jiffies;
 		sensor->cached_value = *value;
--- linux-4.4.0.orig/drivers/hwmon/coretemp.c
+++ linux-4.4.0/drivers/hwmon/coretemp.c
@@ -269,13 +269,13 @@
 	for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) {
 		const struct tjmax_model *tm = &tjmax_model_table[i];
 		if (c->x86_model == tm->model &&
-		    (tm->mask == ANY || c->x86_mask == tm->mask))
+		    (tm->mask == ANY || c->x86_stepping == tm->mask))
 			return tm->tjmax;
 	}
 
 	/* Early chips have no MSR for TjMax */
 
-	if (c->x86_model == 0xf && c->x86_mask < 4)
+	if (c->x86_model == 0xf && c->x86_stepping < 4)
 		usemsr_ee = 0;
 
 	if (c->x86_model > 0xe && usemsr_ee) {
@@ -426,7 +426,7 @@
 	 * Readings might stop update when processor visited too deep sleep,
 	 * fixed for stepping D0 (6EC).
 	 */
-	if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
+	if (c->x86_model == 0xe && c->x86_stepping < 0xc && c->microcode < 0x39) {
 		pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
 		return -ENODEV;
 	}
--- linux-4.4.0.orig/drivers/hwmon/dell-smm-hwmon.c
+++ linux-4.4.0/drivers/hwmon/dell-smm-hwmon.c
@@ -66,11 +66,13 @@
 
 static DEFINE_MUTEX(i8k_mutex);
 static char bios_version[4];
+static char bios_machineid[16];
 static struct device *i8k_hwmon_dev;
 static u32 i8k_hwmon_flags;
 static uint i8k_fan_mult = I8K_FAN_MULT;
 static uint i8k_pwm_mult;
 static uint i8k_fan_max = I8K_FAN_HIGH;
+static bool disallow_fan_type_call;
 
 #define I8K_HWMON_HAVE_TEMP1	(1 << 0)
 #define I8K_HWMON_HAVE_TEMP2	(1 << 1)
@@ -94,13 +96,13 @@
 MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
 
 #if IS_ENABLED(CONFIG_I8K)
-static bool restricted;
+static bool restricted = true;
 module_param(restricted, bool, 0);
-MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
+MODULE_PARM_DESC(restricted, "Restrict fan control and serial number to CAP_SYS_ADMIN (default: 1)");
 
 static bool power_status;
 module_param(power_status, bool, 0600);
-MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
+MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k (default: 0)");
 #endif
 
 static uint fan_mult;
@@ -235,14 +237,28 @@
 /*
  * Read the fan type.
  */
-static int i8k_get_fan_type(int fan)
+static int _i8k_get_fan_type(int fan)
 {
 	struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
 
+	if (disallow_fan_type_call)
+		return -EINVAL;
+
 	regs.ebx = fan & 0xff;
 	return i8k_smm(&regs) ? : regs.eax & 0xff;
 }
 
+static int i8k_get_fan_type(int fan)
+{
+	/* I8K_SMM_GET_FAN_TYPE SMM call is expensive, so cache values */
+	static int types[2] = { INT_MIN, INT_MIN };
+
+	if (types[fan] == INT_MIN)
+		types[fan] = _i8k_get_fan_type(fan);
+
+	return types[fan];
+}
+
 /*
  * Read the fan nominal rpm for specific fan speed.
  */
@@ -392,9 +408,11 @@
 		break;
 
 	case I8K_MACHINE_ID:
-		memset(buff, 0, 16);
-		strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL),
-			sizeof(buff));
+		if (restricted && !capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		memset(buff, 0, sizeof(buff));
+		strlcpy(buff, bios_machineid, sizeof(buff));
 		break;
 
 	case I8K_FN_STATUS:
@@ -511,7 +529,7 @@
 	seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
 		   I8K_PROC_FMT,
 		   bios_version,
-		   i8k_get_dmi_data(DMI_PRODUCT_SERIAL),
+		   (restricted && !capable(CAP_SYS_ADMIN)) ? "-1" : bios_machineid,
 		   cpu_temp,
 		   left_fan, right_fan, left_speed, right_speed,
 		   ac_power, fn_key);
@@ -718,6 +736,9 @@
 static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
 			      int index)
 {
+	if (disallow_fan_type_call &&
+	    (index == 9 || index == 12))
+		return 0;
 	if (index >= 0 && index <= 1 &&
 	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
 		return 0;
@@ -767,13 +788,17 @@
 	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;
 
-	/* First fan attributes, if fan type is OK */
-	err = i8k_get_fan_type(0);
+	/* First fan attributes, if fan status or type is OK */
+	err = i8k_get_fan_status(0);
+	if (err < 0)
+		err = i8k_get_fan_type(0);
 	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;
 
-	/* Second fan attributes, if fan type is OK */
-	err = i8k_get_fan_type(1);
+	/* Second fan attributes, if fan status or type is OK */
+	err = i8k_get_fan_status(1);
+	if (err < 0)
+		err = i8k_get_fan_type(1);
 	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;
 
@@ -929,18 +954,34 @@
 
 MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
 
-static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = {
+/*
+ * On some machines once I8K_SMM_GET_FAN_TYPE is issued then CPU fan speed
+ * randomly going up and down due to bug in Dell SMM or BIOS. Here is blacklist
+ * of affected Dell machines for which we disallow I8K_SMM_GET_FAN_TYPE call.
+ * See bug: https://bugzilla.kernel.org/show_bug.cgi?id=100121
+ */
+static struct dmi_system_id i8k_blacklist_fan_type_dmi_table[] __initdata = {
+	{
+		.ident = "Dell Studio XPS 8000",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8000"),
+		},
+	},
 	{
-		/*
-		 * CPU fan speed going up and down on Dell Studio XPS 8100
-		 * for unknown reasons.
-		 */
 		.ident = "Dell Studio XPS 8100",
 		.matches = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"),
 		},
 	},
+	{
+		.ident = "Dell Inspiron 580",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Inspiron 580 "),
+		},
+	},
 	{ }
 };
 
@@ -955,8 +996,7 @@
 	/*
 	 * Get DMI information
 	 */
-	if (!dmi_check_system(i8k_dmi_table) ||
-	    dmi_check_system(i8k_blacklist_dmi_table)) {
+	if (!dmi_check_system(i8k_dmi_table)) {
 		if (!ignore_dmi && !force)
 			return -ENODEV;
 
@@ -967,8 +1007,13 @@
 			i8k_get_dmi_data(DMI_BIOS_VERSION));
 	}
 
+	if (dmi_check_system(i8k_blacklist_fan_type_dmi_table))
+		disallow_fan_type_call = true;
+
 	strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION),
 		sizeof(bios_version));
+	strlcpy(bios_machineid, i8k_get_dmi_data(DMI_PRODUCT_SERIAL),
+		sizeof(bios_machineid));
 
 	/*
 	 * Get SMM Dell signature
--- linux-4.4.0.orig/drivers/hwmon/ds620.c
+++ linux-4.4.0/drivers/hwmon/ds620.c
@@ -166,7 +166,7 @@
 	if (res)
 		return res;
 
-	val = (val * 10 / 625) * 8;
+	val = (clamp_val(val, -128000, 128000) * 10 / 625) * 8;
 
 	mutex_lock(&data->update_lock);
 	data->temp[attr->index] = val;
--- linux-4.4.0.orig/drivers/hwmon/emc2103.c
+++ linux-4.4.0/drivers/hwmon/emc2103.c
@@ -452,7 +452,7 @@
 	}
 
 	result = read_u8_from_i2c(client, REG_FAN_CONF1, &conf_reg);
-	if (result) {
+	if (result < 0) {
 		count = result;
 		goto err;
 	}
--- linux-4.4.0.orig/drivers/hwmon/f71805f.c
+++ linux-4.4.0/drivers/hwmon/f71805f.c
@@ -96,17 +96,23 @@
 	outb(ld, base + 1);
 }
 
-static inline void
+static inline int
 superio_enter(int base)
 {
+	if (!request_muxed_region(base, 2, DRVNAME))
+		return -EBUSY;
+
 	outb(0x87, base);
 	outb(0x87, base);
+
+	return 0;
 }
 
 static inline void
 superio_exit(int base)
 {
 	outb(0xaa, base);
+	release_region(base, 2);
 }
 
 /*
@@ -1561,7 +1567,7 @@
 static int __init f71805f_find(int sioaddr, unsigned short *address,
 			       struct f71805f_sio_data *sio_data)
 {
-	int err = -ENODEV;
+	int err;
 	u16 devid;
 
 	static const char * const names[] = {
@@ -1569,8 +1575,11 @@
 		"F71872F/FG or F71806F/FG",
 	};
 
-	superio_enter(sioaddr);
+	err = superio_enter(sioaddr);
+	if (err)
+		return err;
 
+	err = -ENODEV;
 	devid = superio_inw(sioaddr, SIO_REG_MANID);
 	if (devid != SIO_FINTEK_ID)
 		goto exit;
--- linux-4.4.0.orig/drivers/hwmon/g762.c
+++ linux-4.4.0/drivers/hwmon/g762.c
@@ -193,14 +193,17 @@
  * Convert fan RPM value from sysfs into count value for fan controller
  * register (FAN_SET_CNT).
  */
-static inline unsigned char cnt_from_rpm(u32 rpm, u32 clk_freq, u16 p,
+static inline unsigned char cnt_from_rpm(unsigned long rpm, u32 clk_freq, u16 p,
 					 u8 clk_div, u8 gear_mult)
 {
-	if (!rpm)         /* to stop the fan, set cnt to 255 */
+	unsigned long f1 = clk_freq * 30 * gear_mult;
+	unsigned long f2 = p * clk_div;
+
+	if (!rpm)	/* to stop the fan, set cnt to 255 */
 		return 0xff;
 
-	return clamp_val(((clk_freq * 30 * gear_mult) / (rpm * p * clk_div)),
-			 0, 255);
+	rpm = clamp_val(rpm, f1 / (255 * f2), ULONG_MAX / f2);
+	return DIV_ROUND_CLOSEST(f1, rpm * f2);
 }
 
 /* helper to grab and cache data, at most one time per second */
--- linux-4.4.0.orig/drivers/hwmon/gl520sm.c
+++ linux-4.4.0/drivers/hwmon/gl520sm.c
@@ -208,11 +208,13 @@
 }
 static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
 
-#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4)
-#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255)
-
-#define IN_FROM_REG(val) ((val) * 19)
-#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255)
+#define VDD_FROM_REG(val)	DIV_ROUND_CLOSEST((val) * 95, 4)
+#define VDD_CLAMP(val)		clamp_val(val, 0, 255 * 95 / 4)
+#define VDD_TO_REG(val)		DIV_ROUND_CLOSEST(VDD_CLAMP(val) * 4, 95)
+
+#define IN_FROM_REG(val)	((val) * 19)
+#define IN_CLAMP(val)		clamp_val(val, 0, 255 * 19)
+#define IN_TO_REG(val)		DIV_ROUND_CLOSEST(IN_CLAMP(val), 19)
 
 static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
 			    char *buf)
@@ -349,8 +351,13 @@
 
 #define DIV_FROM_REG(val) (1 << (val))
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div))))
-#define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \
-	clamp_val((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255))
+
+#define FAN_BASE(div)		(480000 >> (div))
+#define FAN_CLAMP(val, div)	clamp_val(val, FAN_BASE(div) / 255, \
+					  FAN_BASE(div))
+#define FAN_TO_REG(val, div)	((val) == 0 ? 0 : \
+				 DIV_ROUND_CLOSEST(480000, \
+						FAN_CLAMP(val, div) << (div)))
 
 static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
 			     char *buf)
@@ -513,9 +520,9 @@
 static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR,
 		get_fan_off, set_fan_off);
 
-#define TEMP_FROM_REG(val) (((val) - 130) * 1000)
-#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \
-			(val) - 500 : (val) + 500) / 1000) + 130), 0, 255)
+#define TEMP_FROM_REG(val)	(((val) - 130) * 1000)
+#define TEMP_CLAMP(val)		clamp_val(val, -130000, 125000)
+#define TEMP_TO_REG(val)	(DIV_ROUND_CLOSEST(TEMP_CLAMP(val), 1000) + 130)
 
 static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
 			      char *buf)
--- linux-4.4.0.orig/drivers/hwmon/gpio-fan.c
+++ linux-4.4.0/drivers/hwmon/gpio-fan.c
@@ -406,16 +406,11 @@
 				  unsigned long *state)
 {
 	struct gpio_fan_data *fan_data = cdev->devdata;
-	int r;
 
 	if (!fan_data)
 		return -EINVAL;
 
-	r = get_fan_speed_index(fan_data);
-	if (r < 0)
-		return r;
-
-	*state = r;
+	*state = fan_data->speed_index;
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/hwmon/hwmon-vid.c
+++ linux-4.4.0/drivers/hwmon/hwmon-vid.c
@@ -293,7 +293,7 @@
 	if (c->x86 < 6)		/* Any CPU with family lower than 6 */
 		return 0;	/* doesn't have VID */
 
-	vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_mask, c->x86_vendor);
+	vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_stepping, c->x86_vendor);
 	if (vrm_ret == 134)
 		vrm_ret = get_via_model_d_vrm();
 	if (vrm_ret == 0)
--- linux-4.4.0.orig/drivers/hwmon/ibmpowernv.c
+++ linux-4.4.0/drivers/hwmon/ibmpowernv.c
@@ -114,7 +114,7 @@
 	return sprintf(buf, "%s\n", sdata->label);
 }
 
-static int __init get_logical_cpu(int hwcpu)
+static int get_logical_cpu(int hwcpu)
 {
 	int cpu;
 
@@ -125,9 +125,8 @@
 	return -ENOENT;
 }
 
-static void __init make_sensor_label(struct device_node *np,
-				     struct sensor_data *sdata,
-				     const char *label)
+static void make_sensor_label(struct device_node *np,
+			      struct sensor_data *sdata, const char *label)
 {
 	u32 id;
 	size_t n;
--- linux-4.4.0.orig/drivers/hwmon/iio_hwmon.c
+++ linux-4.4.0/drivers/hwmon/iio_hwmon.c
@@ -109,24 +109,24 @@
 
 		switch (type) {
 		case IIO_VOLTAGE:
-			a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
-							  "in%d_input",
-							  in_i++);
+			a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+							       "in%d_input",
+							       in_i++);
 			break;
 		case IIO_TEMP:
-			a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
-							  "temp%d_input",
-							  temp_i++);
+			a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+							       "temp%d_input",
+							       temp_i++);
 			break;
 		case IIO_CURRENT:
-			a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
-							  "curr%d_input",
-							  curr_i++);
+			a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+							       "curr%d_input",
+							       curr_i++);
 			break;
 		case IIO_HUMIDITYRELATIVE:
-			a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
-							  "humidity%d_input",
-							  humidity_i++);
+			a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+							       "humidity%d_input",
+							       humidity_i++);
 			break;
 		default:
 			ret = -EINVAL;
--- linux-4.4.0.orig/drivers/hwmon/ina2xx.c
+++ linux-4.4.0/drivers/hwmon/ina2xx.c
@@ -17,7 +17,7 @@
  * Bi-directional Current/Power Monitor with I2C Interface
  * Datasheet: http://www.ti.com/product/ina230
  *
- * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ * Copyright (C) 2012 Lothar Felten <lothar.felten@gmail.com>
  * Thanks to Jan Volkering
  *
  * This program is free software; you can redistribute it and/or modify
@@ -94,18 +94,20 @@
 
 struct ina2xx_config {
 	u16 config_default;
-	int calibration_factor;
+	int calibration_value;
 	int registers;
 	int shunt_div;
 	int bus_voltage_shift;
 	int bus_voltage_lsb;	/* uV */
-	int power_lsb;		/* uW */
+	int power_lsb_factor;
 };
 
 struct ina2xx_data {
 	const struct ina2xx_config *config;
 
 	long rshunt;
+	long current_lsb_uA;
+	long power_lsb_uW;
 	struct mutex config_lock;
 	struct regmap *regmap;
 
@@ -115,21 +117,21 @@
 static const struct ina2xx_config ina2xx_config[] = {
 	[ina219] = {
 		.config_default = INA219_CONFIG_DEFAULT,
-		.calibration_factor = 40960000,
+		.calibration_value = 4096,
 		.registers = INA219_REGISTERS,
 		.shunt_div = 100,
 		.bus_voltage_shift = 3,
 		.bus_voltage_lsb = 4000,
-		.power_lsb = 20000,
+		.power_lsb_factor = 20,
 	},
 	[ina226] = {
 		.config_default = INA226_CONFIG_DEFAULT,
-		.calibration_factor = 5120000,
+		.calibration_value = 2048,
 		.registers = INA226_REGISTERS,
 		.shunt_div = 400,
 		.bus_voltage_shift = 0,
 		.bus_voltage_lsb = 1250,
-		.power_lsb = 25000,
+		.power_lsb_factor = 25,
 	},
 };
 
@@ -168,12 +170,16 @@
 	return INA226_SHIFT_AVG(avg_bits);
 }
 
+/*
+ * Calibration register is set to the best value, which eliminates
+ * truncation errors on calculating current register in hardware.
+ * According to datasheet (eq. 3) the best values are 2048 for
+ * ina226 and 4096 for ina219. They are hardcoded as calibration_value.
+ */
 static int ina2xx_calibrate(struct ina2xx_data *data)
 {
-	u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
-				    data->rshunt);
-
-	return regmap_write(data->regmap, INA2XX_CALIBRATION, val);
+	return regmap_write(data->regmap, INA2XX_CALIBRATION,
+			    data->config->calibration_value);
 }
 
 /*
@@ -186,10 +192,6 @@
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Set current LSB to 1mA, shunt is in uOhms
-	 * (equation 13 in datasheet).
-	 */
 	return ina2xx_calibrate(data);
 }
 
@@ -267,15 +269,15 @@
 		val = DIV_ROUND_CLOSEST(val, 1000);
 		break;
 	case INA2XX_POWER:
-		val = regval * data->config->power_lsb;
+		val = regval * data->power_lsb_uW;
 		break;
 	case INA2XX_CURRENT:
-		/* signed register, LSB=1mA (selected), in mA */
-		val = (s16)regval;
+		/* signed register, result in mA */
+		val = (s16)regval * data->current_lsb_uA;
+		val = DIV_ROUND_CLOSEST(val, 1000);
 		break;
 	case INA2XX_CALIBRATION:
-		val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
-					regval);
+		val = regval;
 		break;
 	default:
 		/* programmer goofed */
@@ -303,9 +305,41 @@
 			ina2xx_get_value(data, attr->index, regval));
 }
 
-static ssize_t ina2xx_set_shunt(struct device *dev,
-				struct device_attribute *da,
-				const char *buf, size_t count)
+/*
+ * In order to keep calibration register value fixed, the product
+ * of current_lsb and shunt_resistor should also be fixed and equal
+ * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order
+ * to keep the scale.
+ */
+static int ina2xx_set_shunt(struct ina2xx_data *data, long val)
+{
+	unsigned int dividend = DIV_ROUND_CLOSEST(1000000000,
+						  data->config->shunt_div);
+	if (val <= 0 || val > dividend)
+		return -EINVAL;
+
+	mutex_lock(&data->config_lock);
+	data->rshunt = val;
+	data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val);
+	data->power_lsb_uW = data->config->power_lsb_factor *
+			     data->current_lsb_uA;
+	mutex_unlock(&data->config_lock);
+
+	return 0;
+}
+
+static ssize_t ina2xx_show_shunt(struct device *dev,
+			      struct device_attribute *da,
+			      char *buf)
+{
+	struct ina2xx_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%li\n", data->rshunt);
+}
+
+static ssize_t ina2xx_store_shunt(struct device *dev,
+				  struct device_attribute *da,
+				  const char *buf, size_t count)
 {
 	unsigned long val;
 	int status;
@@ -315,18 +349,9 @@
 	if (status < 0)
 		return status;
 
-	if (val == 0 ||
-	    /* Values greater than the calibration factor make no sense. */
-	    val > data->config->calibration_factor)
-		return -EINVAL;
-
-	mutex_lock(&data->config_lock);
-	data->rshunt = val;
-	status = ina2xx_calibrate(data);
-	mutex_unlock(&data->config_lock);
+	status = ina2xx_set_shunt(data, val);
 	if (status < 0)
 		return status;
-
 	return count;
 }
 
@@ -386,7 +411,7 @@
 
 /* shunt resistance */
 static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
-			  ina2xx_show_value, ina2xx_set_shunt,
+			  ina2xx_show_shunt, ina2xx_store_shunt,
 			  INA2XX_CALIBRATION);
 
 /* update interval (ina226 only) */
@@ -431,6 +456,7 @@
 
 	/* set the device type */
 	data->config = &ina2xx_config[id->driver_data];
+	mutex_init(&data->config_lock);
 
 	if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) {
 		struct ina2xx_platform_data *pdata = dev_get_platdata(dev);
@@ -441,10 +467,7 @@
 			val = INA2XX_RSHUNT_DEFAULT;
 	}
 
-	if (val <= 0 || val > data->config->calibration_factor)
-		return -ENODEV;
-
-	data->rshunt = val;
+	ina2xx_set_shunt(data, val);
 
 	ina2xx_regmap_config.max_register = data->config->registers;
 
@@ -460,8 +483,6 @@
 		return -ENODEV;
 	}
 
-	mutex_init(&data->config_lock);
-
 	data->groups[group++] = &ina2xx_group;
 	if (id->driver_data == ina226)
 		data->groups[group++] = &ina226_group;
--- linux-4.4.0.orig/drivers/hwmon/k10temp.c
+++ linux-4.4.0/drivers/hwmon/k10temp.c
@@ -179,7 +179,7 @@
 	 * and AM3 formats, but that's the best we can do.
 	 */
 	return boot_cpu_data.x86_model < 4 ||
-	       (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask <= 2);
+	       (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2);
 }
 
 static int k10temp_probe(struct pci_dev *pdev,
--- linux-4.4.0.orig/drivers/hwmon/k8temp.c
+++ linux-4.4.0/drivers/hwmon/k8temp.c
@@ -187,7 +187,7 @@
 		return -ENOMEM;
 
 	model = boot_cpu_data.x86_model;
-	stepping = boot_cpu_data.x86_mask;
+	stepping = boot_cpu_data.x86_stepping;
 
 	/* feature available since SH-C0, exclude older revisions */
 	if ((model == 4 && stepping == 0) ||
--- linux-4.4.0.orig/drivers/hwmon/lm80.c
+++ linux-4.4.0/drivers/hwmon/lm80.c
@@ -360,9 +360,11 @@
 	struct i2c_client *client = data->client;
 	unsigned long min, val;
 	u8 reg;
-	int err = kstrtoul(buf, 10, &val);
-	if (err < 0)
-		return err;
+	int rv;
+
+	rv = kstrtoul(buf, 10, &val);
+	if (rv < 0)
+		return rv;
 
 	/* Save fan_min */
 	mutex_lock(&data->update_lock);
@@ -390,8 +392,13 @@
 		return -EINVAL;
 	}
 
-	reg = (lm80_read_value(client, LM80_REG_FANDIV) &
-	       ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1)));
+	rv = lm80_read_value(client, LM80_REG_FANDIV);
+	if (rv < 0) {
+		mutex_unlock(&data->update_lock);
+		return rv;
+	}
+	reg = (rv & ~(3 << (2 * (nr + 1))))
+	    | (data->fan_div[nr] << (2 * (nr + 1)));
 	lm80_write_value(client, LM80_REG_FANDIV, reg);
 
 	/* Restore fan_min */
@@ -623,6 +630,7 @@
 	struct device *dev = &client->dev;
 	struct device *hwmon_dev;
 	struct lm80_data *data;
+	int rv;
 
 	data = devm_kzalloc(dev, sizeof(struct lm80_data), GFP_KERNEL);
 	if (!data)
@@ -635,8 +643,14 @@
 	lm80_init_client(client);
 
 	/* A few vars need to be filled upon startup */
-	data->fan[f_min][0] = lm80_read_value(client, LM80_REG_FAN_MIN(1));
-	data->fan[f_min][1] = lm80_read_value(client, LM80_REG_FAN_MIN(2));
+	rv = lm80_read_value(client, LM80_REG_FAN_MIN(1));
+	if (rv < 0)
+		return rv;
+	data->fan[f_min][0] = rv;
+	rv = lm80_read_value(client, LM80_REG_FAN_MIN(2));
+	if (rv < 0)
+		return rv;
+	data->fan[f_min][1] = rv;
 
 	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
 							   data, lm80_groups);
--- linux-4.4.0.orig/drivers/hwmon/lm95234.c
+++ linux-4.4.0/drivers/hwmon/lm95234.c
@@ -310,7 +310,8 @@
 	if (ret < 0)
 		return ret;
 
-	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, index ? 255 : 127);
+	val = DIV_ROUND_CLOSEST(clamp_val(val, 0, (index ? 255 : 127) * 1000),
+				1000);
 
 	mutex_lock(&data->update_lock);
 	data->tcrit2[index] = val;
@@ -359,7 +360,7 @@
 	if (ret < 0)
 		return ret;
 
-	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
+	val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 255000), 1000);
 
 	mutex_lock(&data->update_lock);
 	data->tcrit1[index] = val;
@@ -400,7 +401,7 @@
 	if (ret < 0)
 		return ret;
 
-	val = DIV_ROUND_CLOSEST(val, 1000);
+	val = DIV_ROUND_CLOSEST(clamp_val(val, -255000, 255000), 1000);
 	val = clamp_val((int)data->tcrit1[index] - val, 0, 31);
 
 	mutex_lock(&data->update_lock);
@@ -440,7 +441,7 @@
 		return ret;
 
 	/* Accuracy is 1/2 degrees C */
-	val = clamp_val(DIV_ROUND_CLOSEST(val, 500), -128, 127);
+	val = DIV_ROUND_CLOSEST(clamp_val(val, -64000, 63500), 500);
 
 	mutex_lock(&data->update_lock);
 	data->toffset[index] = val;
--- linux-4.4.0.orig/drivers/hwmon/max1111.c
+++ linux-4.4.0/drivers/hwmon/max1111.c
@@ -85,6 +85,9 @@
 
 int max1111_read_channel(int channel)
 {
+	if (!the_max1111 || !the_max1111->spi)
+		return -ENODEV;
+
 	return max1111_read(&the_max1111->spi->dev, channel);
 }
 EXPORT_SYMBOL(max1111_read_channel);
@@ -258,6 +261,9 @@
 {
 	struct max1111_data *data = spi_get_drvdata(spi);
 
+#ifdef CONFIG_SHARPSL_PM
+	the_max1111 = NULL;
+#endif
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
 	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
--- linux-4.4.0.orig/drivers/hwmon/max6697.c
+++ linux-4.4.0/drivers/hwmon/max6697.c
@@ -46,8 +46,9 @@
  * Map device tree / platform data register bit map to chip bit map.
  * Applies to alert register and over-temperature register.
  */
-#define MAX6697_MAP_BITS(reg)	((((reg) & 0x7e) >> 1) | \
+#define MAX6697_ALERT_MAP_BITS(reg)	((((reg) & 0x7e) >> 1) | \
 				 (((reg) & 0x01) << 6) | ((reg) & 0x80))
+#define MAX6697_OVERT_MAP_BITS(reg) (((reg) >> 1) | (((reg) & 0x01) << 7))
 
 #define MAX6697_REG_STAT(n)		(0x44 + (n))
 
@@ -586,12 +587,12 @@
 		return ret;
 
 	ret = i2c_smbus_write_byte_data(client, MAX6697_REG_ALERT_MASK,
-					MAX6697_MAP_BITS(pdata->alert_mask));
+				MAX6697_ALERT_MAP_BITS(pdata->alert_mask));
 	if (ret < 0)
 		return ret;
 
 	ret = i2c_smbus_write_byte_data(client, MAX6697_REG_OVERT_MASK,
-				MAX6697_MAP_BITS(pdata->over_temperature_mask));
+			MAX6697_OVERT_MAP_BITS(pdata->over_temperature_mask));
 	if (ret < 0)
 		return ret;
 
--- linux-4.4.0.orig/drivers/hwmon/nct6775.c
+++ linux-4.4.0/drivers/hwmon/nct6775.c
@@ -60,6 +60,7 @@
 #include <linux/acpi.h>
 #include <linux/dmi.h>
 #include <linux/io.h>
+#include <linux/nospec.h>
 #include "lm75.h"
 
 #define USE_ALTERNATE
@@ -696,7 +697,7 @@
 static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
 static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
 static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
-static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
+static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b };
 static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
 static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
 
@@ -1390,7 +1391,7 @@
 		duty_is_dc = data->REG_PWM_MODE[i] &&
 		  (nct6775_read_value(data, data->REG_PWM_MODE[i])
 		   & data->PWM_MODE_MASK[i]);
-		data->pwm_mode[i] = duty_is_dc;
+		data->pwm_mode[i] = !duty_is_dc;
 
 		fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
 		for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
@@ -2119,7 +2120,7 @@
 	if (err < 0)
 		return err;
 
-	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+	val = DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), 1000);
 
 	mutex_lock(&data->update_lock);
 	data->temp_offset[nr] = val;
@@ -2267,7 +2268,7 @@
 	struct nct6775_data *data = nct6775_update_device(dev);
 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
 
-	return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
+	return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
 }
 
 static ssize_t
@@ -2288,9 +2289,9 @@
 	if (val > 1)
 		return -EINVAL;
 
-	/* Setting DC mode is not supported for all chips/channels */
+	/* Setting DC mode (0) is not supported for all chips/channels */
 	if (data->REG_PWM_MODE[nr] == 0) {
-		if (val)
+		if (!val)
 			return -EINVAL;
 		return count;
 	}
@@ -2299,7 +2300,7 @@
 	data->pwm_mode[nr] = val;
 	reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
 	reg &= ~data->PWM_MODE_MASK[nr];
-	if (val)
+	if (!val)
 		reg |= data->PWM_MODE_MASK[nr];
 	nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
 	mutex_unlock(&data->update_lock);
@@ -2559,6 +2560,7 @@
 		return err;
 	if (val > NUM_TEMP)
 		return -EINVAL;
+	val = array_index_nospec(val, NUM_TEMP + 1);
 	if (val && (!(data->have_temp & (1 << (val - 1))) ||
 		    !data->temp_src[val - 1]))
 		return -EINVAL;
@@ -3478,6 +3480,7 @@
 		data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
 		data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
 		data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
+		data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
 		data->REG_PWM[0] = NCT6106_REG_PWM;
 		data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
 		data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
--- linux-4.4.0.orig/drivers/hwmon/nct7802.c
+++ linux-4.4.0/drivers/hwmon/nct7802.c
@@ -32,8 +32,8 @@
 static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e };
 
 static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = {
-	{ 0x40, 0x00, 0x42, 0x44, 0x46 },
-	{ 0x3f, 0x00, 0x41, 0x43, 0x45 },
+	{ 0x46, 0x00, 0x40, 0x42, 0x44 },
+	{ 0x45, 0x00, 0x3f, 0x41, 0x43 },
 };
 
 static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 };
@@ -259,13 +259,15 @@
 		ret = 0;
 	else if (ret)
 		ret = DIV_ROUND_CLOSEST(1350000U, ret);
+	else
+		ret = 1350000U;
 abort:
 	mutex_unlock(&data->access_lock);
 	return ret;
 }
 
 static int nct7802_write_fan_min(struct nct7802_data *data, u8 reg_fan_low,
-				 u8 reg_fan_high, unsigned int limit)
+				 u8 reg_fan_high, unsigned long limit)
 {
 	int err;
 
@@ -326,8 +328,8 @@
 	int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
 	int err;
 
+	voltage = clamp_val(voltage, 0, 0x3ff * nct7802_vmul[nr]);
 	voltage = DIV_ROUND_CLOSEST(voltage, nct7802_vmul[nr]);
-	voltage = clamp_val(voltage, 0, 0x3ff);
 
 	mutex_lock(&data->access_lock);
 	err = regmap_write(data->regmap,
@@ -402,7 +404,7 @@
 	if (err < 0)
 		return err;
 
-	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+	val = DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), 1000);
 
 	err = regmap_write(data->regmap, nr, val & 0xff);
 	return err ? : count;
@@ -766,7 +768,7 @@
 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
 	&sensor_dev_attr_in3_beep.dev_attr.attr,
 
-	&sensor_dev_attr_in4_input.dev_attr.attr,	/* 17 */
+	&sensor_dev_attr_in4_input.dev_attr.attr,	/* 16 */
 	&sensor_dev_attr_in4_min.dev_attr.attr,
 	&sensor_dev_attr_in4_max.dev_attr.attr,
 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
@@ -792,9 +794,9 @@
 
 	if (index >= 6 && index < 11 && (reg & 0x03) != 0x03)	/* VSEN1 */
 		return 0;
-	if (index >= 11 && index < 17 && (reg & 0x0c) != 0x0c)	/* VSEN2 */
+	if (index >= 11 && index < 16 && (reg & 0x0c) != 0x0c)	/* VSEN2 */
 		return 0;
-	if (index >= 17 && (reg & 0x30) != 0x30)		/* VSEN3 */
+	if (index >= 16 && (reg & 0x30) != 0x30)		/* VSEN3 */
 		return 0;
 
 	return attr->mode;
--- linux-4.4.0.orig/drivers/hwmon/pc87427.c
+++ linux-4.4.0/drivers/hwmon/pc87427.c
@@ -106,6 +106,13 @@
 #define LD_IN		1
 #define LD_TEMP		1
 
+static inline int superio_enter(int sioaddr)
+{
+	if (!request_muxed_region(sioaddr, 2, DRVNAME))
+		return -EBUSY;
+	return 0;
+}
+
 static inline void superio_outb(int sioaddr, int reg, int val)
 {
 	outb(reg, sioaddr);
@@ -122,6 +129,7 @@
 {
 	outb(0x02, sioaddr);
 	outb(0x02, sioaddr + 1);
+	release_region(sioaddr, 2);
 }
 
 /*
@@ -1220,7 +1228,11 @@
 {
 	u16 val;
 	u8 cfg, cfg_b;
-	int i, err = 0;
+	int i, err;
+
+	err = superio_enter(sioaddr);
+	if (err)
+		return err;
 
 	/* Identify device */
 	val = force_id ? force_id : superio_inb(sioaddr, SIOREG_DEVID);
--- linux-4.4.0.orig/drivers/hwmon/pmbus/adm1275.c
+++ linux-4.4.0/drivers/hwmon/pmbus/adm1275.c
@@ -95,8 +95,8 @@
 	[0] = { 27169, 0, -1 },		/* voltage */
 	[1] = { 806, 20475, -1 },	/* current, irange25 */
 	[2] = { 404, 20475, -1 },	/* current, irange50 */
-	[3] = { 0, -1, 8549 },		/* power, irange25 */
-	[4] = { 0, -1, 4279 },		/* power, irange50 */
+	[3] = { 8549, 0, -1 },		/* power, irange25 */
+	[4] = { 4279, 0, -1 },		/* power, irange50 */
 };
 
 static const struct coefficients adm1275_coefficients[] = {
@@ -141,7 +141,7 @@
 	const struct adm1275_data *data = to_adm1275_data(info);
 	int ret = 0;
 
-	if (page)
+	if (page > 0)
 		return -ENXIO;
 
 	switch (reg) {
@@ -218,7 +218,7 @@
 	const struct adm1275_data *data = to_adm1275_data(info);
 	int ret;
 
-	if (page)
+	if (page > 0)
 		return -ENXIO;
 
 	switch (reg) {
--- linux-4.4.0.orig/drivers/hwmon/pmbus/ltc2978.c
+++ linux-4.4.0/drivers/hwmon/pmbus/ltc2978.c
@@ -89,8 +89,8 @@
 
 #define LTC_POLL_TIMEOUT		100	/* in milli-seconds */
 
-#define LTC_NOT_BUSY			BIT(5)
-#define LTC_NOT_PENDING			BIT(4)
+#define LTC_NOT_BUSY			BIT(6)
+#define LTC_NOT_PENDING			BIT(5)
 
 /*
  * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
--- linux-4.4.0.orig/drivers/hwmon/pmbus/max8688.c
+++ linux-4.4.0/drivers/hwmon/pmbus/max8688.c
@@ -45,7 +45,7 @@
 {
 	int ret;
 
-	if (page)
+	if (page > 0)
 		return -ENXIO;
 
 	switch (reg) {
--- linux-4.4.0.orig/drivers/hwmon/pmbus/pmbus.c
+++ linux-4.4.0/drivers/hwmon/pmbus/pmbus.c
@@ -117,6 +117,8 @@
 		} else {
 			info->pages = 1;
 		}
+
+		pmbus_clear_faults(client);
 	}
 
 	if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
--- linux-4.4.0.orig/drivers/hwmon/pmbus/pmbus_core.c
+++ linux-4.4.0/drivers/hwmon/pmbus/pmbus_core.c
@@ -20,6 +20,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -476,8 +477,8 @@
 static long pmbus_reg2data_direct(struct pmbus_data *data,
 				  struct pmbus_sensor *sensor)
 {
-	long val = (s16) sensor->data;
-	long m, b, R;
+	s64 b, val = (s16)sensor->data;
+	s32 m, R;
 
 	m = data->info->m[sensor->class];
 	b = data->info->b[sensor->class];
@@ -505,11 +506,12 @@
 		R--;
 	}
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val = div_s64(val + 5LL, 10L);  /* round closest */
 		R++;
 	}
 
-	return (val - b) / m;
+	val = div_s64(val - b, m);
+	return clamp_val(val, LONG_MIN, LONG_MAX);
 }
 
 /*
@@ -629,7 +631,8 @@
 static u16 pmbus_data2reg_direct(struct pmbus_data *data,
 				 struct pmbus_sensor *sensor, long val)
 {
-	long m, b, R;
+	s64 b, val64 = val;
+	s32 m, R;
 
 	m = data->info->m[sensor->class];
 	b = data->info->b[sensor->class];
@@ -646,18 +649,18 @@
 		R -= 3;		/* Adjust R and b for data in milli-units */
 		b *= 1000;
 	}
-	val = val * m + b;
+	val64 = val64 * m + b;
 
 	while (R > 0) {
-		val *= 10;
+		val64 *= 10;
 		R--;
 	}
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val64 = div_s64(val64 + 5LL, 10L);  /* round closest */
 		R++;
 	}
 
-	return val;
+	return (u16)clamp_val(val64, S16_MIN, S16_MAX);
 }
 
 static u16 pmbus_data2reg_vid(struct pmbus_data *data,
@@ -1025,14 +1028,15 @@
 				      const struct pmbus_driver_info *info,
 				      const char *name,
 				      int index, int page,
-				      const struct pmbus_sensor_attr *attr)
+				      const struct pmbus_sensor_attr *attr,
+				      bool paged)
 {
 	struct pmbus_sensor *base;
 	int ret;
 
 	if (attr->label) {
 		ret = pmbus_add_label(data, name, index, attr->label,
-				      attr->paged ? page + 1 : 0);
+				      paged ? page + 1 : 0);
 		if (ret)
 			return ret;
 	}
@@ -1064,6 +1068,30 @@
 	return 0;
 }
 
+static bool pmbus_sensor_is_paged(const struct pmbus_driver_info *info,
+				  const struct pmbus_sensor_attr *attr)
+{
+	int p;
+
+	if (attr->paged)
+		return true;
+
+	/*
+	 * Some attributes may be present on more than one page despite
+	 * not being marked with the paged attribute. If that is the case,
+	 * then treat the sensor as being paged and add the page suffix to the
+	 * attribute name.
+	 * We don't just add the paged attribute to all such attributes, in
+	 * order to maintain the un-suffixed labels in the case where the
+	 * attribute is only on page 0.
+	 */
+	for (p = 1; p < info->pages; p++) {
+		if (info->func[p] & attr->func)
+			return true;
+	}
+	return false;
+}
+
 static int pmbus_add_sensor_attrs(struct i2c_client *client,
 				  struct pmbus_data *data,
 				  const char *name,
@@ -1077,14 +1105,15 @@
 	index = 1;
 	for (i = 0; i < nattrs; i++) {
 		int page, pages;
+		bool paged = pmbus_sensor_is_paged(info, attrs);
 
-		pages = attrs->paged ? info->pages : 1;
+		pages = paged ? info->pages : 1;
 		for (page = 0; page < pages; page++) {
 			if (!(info->func[page] & attrs->func))
 				continue;
 			ret = pmbus_add_sensor_attrs_one(client, data, info,
 							 name, index, page,
-							 attrs);
+							 attrs, paged);
 			if (ret)
 				return ret;
 			index++;
@@ -1756,7 +1785,10 @@
 	if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK))
 		client->flags |= I2C_CLIENT_PEC;
 
-	pmbus_clear_faults(client);
+	if (data->info->pages)
+		pmbus_clear_faults(client);
+	else
+		pmbus_clear_fault_page(client, -1);
 
 	if (info->identify) {
 		ret = (*info->identify)(client, info);
--- linux-4.4.0.orig/drivers/hwmon/pwm-fan.c
+++ linux-4.4.0/drivers/hwmon/pwm-fan.c
@@ -227,8 +227,12 @@
 
 	ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL);
 	if (IS_ERR(ctx->pwm)) {
-		dev_err(&pdev->dev, "Could not get PWM\n");
-		return PTR_ERR(ctx->pwm);
+		ret = PTR_ERR(ctx->pwm);
+
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Could not get PWM: %d\n", ret);
+
+		return ret;
 	}
 
 	platform_set_drvdata(pdev, ctx);
--- linux-4.4.0.orig/drivers/hwmon/scpi-hwmon.c
+++ linux-4.4.0/drivers/hwmon/scpi-hwmon.c
@@ -272,6 +272,7 @@
 	{.compatible = "arm,scpi-sensors"},
 	{},
 };
+MODULE_DEVICE_TABLE(of, scpi_of_match);
 
 static struct platform_driver scpi_hwmon_platdrv = {
 	.driver = {
--- linux-4.4.0.orig/drivers/hwmon/shtc1.c
+++ linux-4.4.0/drivers/hwmon/shtc1.c
@@ -38,7 +38,7 @@
 
 /* constants for reading the ID register */
 #define SHTC1_ID	  0x07
-#define SHTC1_ID_REG_MASK 0x1f
+#define SHTC1_ID_REG_MASK 0x3f
 
 /* delays for non-blocking i2c commands, both in us */
 #define SHTC1_NONBLOCKING_WAIT_TIME_HPM  14400
--- linux-4.4.0.orig/drivers/hwmon/smsc47b397.c
+++ linux-4.4.0/drivers/hwmon/smsc47b397.c
@@ -72,14 +72,19 @@
 	superio_outb(0x07, ld);
 }
 
-static inline void superio_enter(void)
+static inline int superio_enter(void)
 {
+	if (!request_muxed_region(REG, 2, DRVNAME))
+		return -EBUSY;
+
 	outb(0x55, REG);
+	return 0;
 }
 
 static inline void superio_exit(void)
 {
 	outb(0xAA, REG);
+	release_region(REG, 2);
 }
 
 #define SUPERIO_REG_DEVID	0x20
@@ -300,8 +305,12 @@
 	u8 id, rev;
 	char *name;
 	unsigned short addr;
+	int err;
+
+	err = superio_enter();
+	if (err)
+		return err;
 
-	superio_enter();
 	id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
 
 	switch (id) {
--- linux-4.4.0.orig/drivers/hwmon/smsc47m1.c
+++ linux-4.4.0/drivers/hwmon/smsc47m1.c
@@ -73,16 +73,21 @@
 /* logical device for fans is 0x0A */
 #define superio_select() superio_outb(0x07, 0x0A)
 
-static inline void
+static inline int
 superio_enter(void)
 {
+	if (!request_muxed_region(REG, 2, DRVNAME))
+		return -EBUSY;
+
 	outb(0x55, REG);
+	return 0;
 }
 
 static inline void
 superio_exit(void)
 {
 	outb(0xAA, REG);
+	release_region(REG, 2);
 }
 
 #define SUPERIO_REG_ACT		0x30
@@ -531,8 +536,12 @@
 {
 	u8 val;
 	unsigned short addr;
+	int err;
+
+	err = superio_enter();
+	if (err)
+		return err;
 
-	superio_enter();
 	val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
 
 	/*
@@ -608,13 +617,14 @@
 static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
 {
 	if ((sio_data->activate & 0x01) == 0) {
-		superio_enter();
-		superio_select();
-
-		pr_info("Disabling device\n");
-		superio_outb(SUPERIO_REG_ACT, sio_data->activate);
-
-		superio_exit();
+		if (!superio_enter()) {
+			superio_select();
+			pr_info("Disabling device\n");
+			superio_outb(SUPERIO_REG_ACT, sio_data->activate);
+			superio_exit();
+		} else {
+			pr_warn("Failed to disable device\n");
+		}
 	}
 }
 
--- linux-4.4.0.orig/drivers/hwmon/vt1211.c
+++ linux-4.4.0/drivers/hwmon/vt1211.c
@@ -226,15 +226,21 @@
 	outb(ldn, sio_cip + 1);
 }
 
-static inline void superio_enter(int sio_cip)
+static inline int superio_enter(int sio_cip)
 {
+	if (!request_muxed_region(sio_cip, 2, DRVNAME))
+		return -EBUSY;
+
 	outb(0x87, sio_cip);
 	outb(0x87, sio_cip);
+
+	return 0;
 }
 
 static inline void superio_exit(int sio_cip)
 {
 	outb(0xaa, sio_cip);
+	release_region(sio_cip, 2);
 }
 
 /* ---------------------------------------------------------------------
@@ -1282,11 +1288,14 @@
 
 static int __init vt1211_find(int sio_cip, unsigned short *address)
 {
-	int err = -ENODEV;
+	int err;
 	int devid;
 
-	superio_enter(sio_cip);
+	err = superio_enter(sio_cip);
+	if (err)
+		return err;
 
+	err = -ENODEV;
 	devid = force_id ? force_id : superio_inb(sio_cip, SIO_VT1211_DEVID);
 	if (devid != SIO_VT1211_ID)
 		goto EXIT;
--- linux-4.4.0.orig/drivers/hwmon/w83627ehf.c
+++ linux-4.4.0/drivers/hwmon/w83627ehf.c
@@ -1513,7 +1513,7 @@
 	if (err < 0)
 		return err;
 
-	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
+	val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000);
 
 	mutex_lock(&data->update_lock);
 	data->target_temp[nr] = val;
@@ -1539,7 +1539,7 @@
 		return err;
 
 	/* Limit the temp to 0C - 15C */
-	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
+	val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 15000), 1000);
 
 	mutex_lock(&data->update_lock);
 	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
--- linux-4.4.0.orig/drivers/hwmon/w83627hf.c
+++ linux-4.4.0/drivers/hwmon/w83627hf.c
@@ -130,17 +130,23 @@
 	outb(ld,  sio->sioaddr + 1);
 }
 
-static inline void
+static inline int
 superio_enter(struct w83627hf_sio_data *sio)
 {
+	if (!request_muxed_region(sio->sioaddr, 2, DRVNAME))
+		return -EBUSY;
+
 	outb(0x87, sio->sioaddr);
 	outb(0x87, sio->sioaddr);
+
+	return 0;
 }
 
 static inline void
 superio_exit(struct w83627hf_sio_data *sio)
 {
 	outb(0xAA, sio->sioaddr);
+	release_region(sio->sioaddr, 2);
 }
 
 #define W627_DEVID 0x52
@@ -1275,7 +1281,7 @@
 static int __init w83627hf_find(int sioaddr, unsigned short *addr,
 				struct w83627hf_sio_data *sio_data)
 {
-	int err = -ENODEV;
+	int err;
 	u16 val;
 
 	static __initconst char *const names[] = {
@@ -1287,7 +1293,11 @@
 	};
 
 	sio_data->sioaddr = sioaddr;
-	superio_enter(sio_data);
+	err = superio_enter(sio_data);
+	if (err)
+		return err;
+
+	err = -ENODEV;
 	val = force_id ? force_id : superio_inb(sio_data, DEVID);
 	switch (val) {
 	case W627_DEVID:
@@ -1641,9 +1651,21 @@
 	struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
 	int res = 0xff, sel;
 
-	superio_enter(sio_data);
+	if (superio_enter(sio_data)) {
+		/*
+		 * Some other driver reserved the address space for itself.
+		 * We don't want to fail driver instantiation because of that,
+		 * so display a warning and keep going.
+		 */
+		dev_warn(&pdev->dev,
+			 "Can not read VID data: Failed to enable SuperIO access\n");
+		return res;
+	}
+
 	superio_select(sio_data, W83627HF_LD_GPIO5);
 
+	res = 0xff;
+
 	/* Make sure these GPIO pins are enabled */
 	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
 		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
@@ -1674,7 +1696,17 @@
 	struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
 	int res = 0xff;
 
-	superio_enter(sio_data);
+	if (superio_enter(sio_data)) {
+		/*
+		 * Some other driver reserved the address space for itself.
+		 * We don't want to fail driver instantiation because of that,
+		 * so display a warning and keep going.
+		 */
+		dev_warn(&pdev->dev,
+			 "Can not read VID data: Failed to enable SuperIO access\n");
+		return res;
+	}
+
 	superio_select(sio_data, W83627HF_LD_HWM);
 
 	/* Make sure these GPIO pins are enabled */
--- linux-4.4.0.orig/drivers/hwmon/w83792d.c
+++ linux-4.4.0/drivers/hwmon/w83792d.c
@@ -937,7 +937,7 @@
 static int
 w83792d_detect_subclients(struct i2c_client *new_client)
 {
-	int i, id, err;
+	int i, id;
 	int address = new_client->addr;
 	u8 val;
 	struct i2c_adapter *adapter = new_client->adapter;
@@ -951,8 +951,7 @@
 				dev_err(&new_client->dev,
 					"invalid subclient address %d; must be 0x48-0x4f\n",
 					force_subclients[i]);
-				err = -ENODEV;
-				goto ERROR_SC_0;
+				return -ENODEV;
 			}
 		}
 		w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
@@ -961,30 +960,19 @@
 	}
 
 	val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
-	if (!(val & 0x08))
-		data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
-	if (!(val & 0x80)) {
-		if ((data->lm75[0] != NULL) &&
-			((val & 0x7) == ((val >> 4) & 0x7))) {
-			dev_err(&new_client->dev,
-				"duplicate addresses 0x%x, use force_subclient\n",
-				data->lm75[0]->addr);
-			err = -ENODEV;
-			goto ERROR_SC_1;
-		}
-		data->lm75[1] = i2c_new_dummy(adapter,
-					      0x48 + ((val >> 4) & 0x7));
-	}
+	if (!(val & 0x88) && (val & 0x7) == ((val >> 4) & 0x7)) {
+		dev_err(&new_client->dev,
+			"duplicate addresses 0x%x, use force_subclient\n", 0x48 + (val & 0x7));
+		return -ENODEV;
+ 	}
 
-	return 0;
+ 	if (!(val & 0x08))
+ 		data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
 
-/* Undo inits in case of errors */
+ 	if (!(val & 0x80))
+ 		data->lm75[1] = i2c_new_dummy(adapter, 0x48 + ((val >> 4) & 0x7));
 
-ERROR_SC_1:
-	if (data->lm75[0] != NULL)
-		i2c_unregister_device(data->lm75[0]);
-ERROR_SC_0:
-	return err;
+	return 0;
 }
 
 static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
--- linux-4.4.0.orig/drivers/hwmon/w83795.c
+++ linux-4.4.0/drivers/hwmon/w83795.c
@@ -1691,7 +1691,7 @@
  * somewhere else in the code
  */
 #define SENSOR_ATTR_TEMP(index) {					\
-	SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \
+	SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 5 ? S_IWUSR : 0), \
 		show_temp_mode, store_temp_mode, NOT_USED, index - 1),	\
 	SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp,		\
 		NULL, TEMP_READ, index - 1),				\
--- linux-4.4.0.orig/drivers/hwspinlock/hwspinlock_core.c
+++ linux-4.4.0/drivers/hwspinlock/hwspinlock_core.c
@@ -313,6 +313,10 @@
 		hwlock = radix_tree_deref_slot(slot);
 		if (unlikely(!hwlock))
 			continue;
+		if (radix_tree_deref_retry(hwlock)) {
+			slot = radix_tree_iter_retry(&iter);
+			continue;
+		}
 
 		if (hwlock->bank->dev->of_node == args.np) {
 			ret = 0;
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight-etb10.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight-etb10.c
@@ -489,15 +489,6 @@
 	return ret;
 }
 
-static int etb_remove(struct amba_device *adev)
-{
-	struct etb_drvdata *drvdata = amba_get_drvdata(adev);
-
-	misc_deregister(&drvdata->miscdev);
-	coresight_unregister(drvdata->csdev);
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int etb_runtime_suspend(struct device *dev)
 {
@@ -537,10 +528,10 @@
 		.name	= "coresight-etb10",
 		.owner	= THIS_MODULE,
 		.pm	= &etb_dev_pm_ops,
+		.suppress_bind_attrs = true,
 
 	},
 	.probe		= etb_probe,
-	.remove		= etb_remove,
 	.id_table	= etb_ids,
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight-etm3x.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -1877,17 +1877,6 @@
 	return ret;
 }
 
-static int etm_remove(struct amba_device *adev)
-{
-	struct etm_drvdata *drvdata = amba_get_drvdata(adev);
-
-	coresight_unregister(drvdata->csdev);
-	if (--etm_count == 0)
-		unregister_hotcpu_notifier(&etm_cpu_notifier);
-
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int etm_runtime_suspend(struct device *dev)
 {
@@ -1948,9 +1937,9 @@
 		.name	= "coresight-etm3x",
 		.owner	= THIS_MODULE,
 		.pm	= &etm_dev_pm_ops,
+		.suppress_bind_attrs = true,
 	},
 	.probe		= etm_probe,
-	.remove		= etm_remove,
 	.id_table	= etm_ids,
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight-etm4x.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -54,7 +54,8 @@
 
 static bool etm4_arch_supported(u8 arch)
 {
-	switch (arch) {
+	/* Mask out the minor version number */
+	switch (arch & 0xf0) {
 	case ETM_ARCH_V4:
 		break;
 	default:
@@ -2219,7 +2220,7 @@
 	return scnprintf(buf, PAGE_SIZE, "0x%x\n",			\
 			 readl_relaxed(drvdata->base + offset));	\
 }									\
-DEVICE_ATTR_RO(name)
+static DEVICE_ATTR_RO(name)
 
 coresight_simple_func(trcoslsr, TRCOSLSR);
 coresight_simple_func(trcpdcr, TRCPDCR);
@@ -2684,17 +2685,6 @@
 	return ret;
 }
 
-static int etm4_remove(struct amba_device *adev)
-{
-	struct etmv4_drvdata *drvdata = amba_get_drvdata(adev);
-
-	coresight_unregister(drvdata->csdev);
-	if (--etm4_count == 0)
-		unregister_hotcpu_notifier(&etm4_cpu_notifier);
-
-	return 0;
-}
-
 static struct amba_id etm4_ids[] = {
 	{       /* ETM 4.0 - Qualcomm */
 		.id	= 0x0003b95d,
@@ -2712,9 +2702,9 @@
 static struct amba_driver etm4x_driver = {
 	.drv = {
 		.name   = "coresight-etm4x",
+		.suppress_bind_attrs = true,
 	},
 	.probe		= etm4_probe,
-	.remove		= etm4_remove,
 	.id_table	= etm4_ids,
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight-funnel.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight-funnel.c
@@ -226,14 +226,6 @@
 	return 0;
 }
 
-static int funnel_remove(struct amba_device *adev)
-{
-	struct funnel_drvdata *drvdata = amba_get_drvdata(adev);
-
-	coresight_unregister(drvdata->csdev);
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int funnel_runtime_suspend(struct device *dev)
 {
@@ -273,9 +265,9 @@
 		.name	= "coresight-funnel",
 		.owner	= THIS_MODULE,
 		.pm	= &funnel_dev_pm_ops,
+		.suppress_bind_attrs = true,
 	},
 	.probe		= funnel_probe,
-	.remove		= funnel_remove,
 	.id_table	= funnel_ids,
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight-replicator-qcom.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight-replicator-qcom.c
@@ -156,15 +156,6 @@
 	return 0;
 }
 
-static int replicator_remove(struct amba_device *adev)
-{
-	struct replicator_state *drvdata = amba_get_drvdata(adev);
-
-	pm_runtime_disable(&adev->dev);
-	coresight_unregister(drvdata->csdev);
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int replicator_runtime_suspend(struct device *dev)
 {
@@ -206,9 +197,9 @@
 	.drv = {
 		.name	= "coresight-replicator-qcom",
 		.pm	= &replicator_dev_pm_ops,
+		.suppress_bind_attrs = true,
 	},
 	.probe		= replicator_probe,
-	.remove		= replicator_remove,
 	.id_table	= replicator_ids,
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight-replicator.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight-replicator.c
@@ -127,20 +127,6 @@
 	return ret;
 }
 
-static int replicator_remove(struct platform_device *pdev)
-{
-	struct replicator_drvdata *drvdata = platform_get_drvdata(pdev);
-
-	coresight_unregister(drvdata->csdev);
-	pm_runtime_get_sync(&pdev->dev);
-	if (!IS_ERR(drvdata->atclk))
-		clk_disable_unprepare(drvdata->atclk);
-	pm_runtime_put_noidle(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int replicator_runtime_suspend(struct device *dev)
 {
@@ -175,11 +161,11 @@
 
 static struct platform_driver replicator_driver = {
 	.probe          = replicator_probe,
-	.remove         = replicator_remove,
 	.driver         = {
 		.name   = "coresight-replicator",
 		.of_match_table = replicator_match,
 		.pm	= &replicator_dev_pm_ops,
+		.suppress_bind_attrs = true,
 	},
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight-tmc.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight-tmc.c
@@ -124,7 +124,7 @@
 	bool			reading;
 	char			*buf;
 	dma_addr_t		paddr;
-	void __iomem		*vaddr;
+	void			*vaddr;
 	u32			size;
 	bool			enable;
 	enum tmc_config_type	config_type;
@@ -766,23 +766,10 @@
 err_devm_kzalloc:
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
 		dma_free_coherent(dev, drvdata->size,
-				&drvdata->paddr, GFP_KERNEL);
+				drvdata->vaddr, drvdata->paddr);
 	return ret;
 }
 
-static int tmc_remove(struct amba_device *adev)
-{
-	struct tmc_drvdata *drvdata = amba_get_drvdata(adev);
-
-	misc_deregister(&drvdata->miscdev);
-	coresight_unregister(drvdata->csdev);
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
-		dma_free_coherent(drvdata->dev, drvdata->size,
-				  &drvdata->paddr, GFP_KERNEL);
-
-	return 0;
-}
-
 static struct amba_id tmc_ids[] = {
 	{
 		.id     = 0x0003b961,
@@ -795,9 +782,9 @@
 	.drv = {
 		.name   = "coresight-tmc",
 		.owner  = THIS_MODULE,
+		.suppress_bind_attrs = true,
 	},
 	.probe		= tmc_probe,
-	.remove		= tmc_remove,
 	.id_table	= tmc_ids,
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight-tpiu.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -45,8 +45,12 @@
 #define TPIU_ITATBCTR0		0xef8
 
 /** register definition **/
+/* FFSR - 0x300 */
+#define FFSR_FT_STOPPED_BIT	1
 /* FFCR - 0x304 */
+#define FFCR_FON_MAN_BIT	6
 #define FFCR_FON_MAN		BIT(6)
+#define FFCR_STOP_FI		BIT(12)
 
 /**
  * @base:	memory mapped base address for this component.
@@ -85,10 +89,14 @@
 {
 	CS_UNLOCK(drvdata->base);
 
-	/* Clear formatter controle reg. */
-	writel_relaxed(0x0, drvdata->base + TPIU_FFCR);
+	/* Clear formatter and stop on flush */
+	writel_relaxed(FFCR_STOP_FI, drvdata->base + TPIU_FFCR);
 	/* Generate manual flush */
-	writel_relaxed(FFCR_FON_MAN, drvdata->base + TPIU_FFCR);
+	writel_relaxed(FFCR_STOP_FI | FFCR_FON_MAN, drvdata->base + TPIU_FFCR);
+	/* Wait for flush to complete */
+	coresight_timeout(drvdata->base, TPIU_FFCR, FFCR_FON_MAN_BIT, 0);
+	/* Wait for formatter to stop */
+	coresight_timeout(drvdata->base, TPIU_FFSR, FFSR_FT_STOPPED_BIT, 1);
 
 	CS_LOCK(drvdata->base);
 }
@@ -172,14 +180,6 @@
 	return 0;
 }
 
-static int tpiu_remove(struct amba_device *adev)
-{
-	struct tpiu_drvdata *drvdata = amba_get_drvdata(adev);
-
-	coresight_unregister(drvdata->csdev);
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int tpiu_runtime_suspend(struct device *dev)
 {
@@ -223,9 +223,9 @@
 		.name	= "coresight-tpiu",
 		.owner	= THIS_MODULE,
 		.pm	= &tpiu_dev_pm_ops,
+		.suppress_bind_attrs = true,
 	},
 	.probe		= tpiu_probe,
-	.remove		= tpiu_remove,
 	.id_table	= tpiu_ids,
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/coresight.c
+++ linux-4.4.0/drivers/hwtracing/coresight/coresight.c
@@ -86,7 +86,7 @@
 	dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
 		dev_name(&parent->dev), dev_name(&csdev->dev));
 
-	return 0;
+	return -ENODEV;
 }
 
 static int coresight_find_link_outport(struct coresight_device *csdev)
@@ -107,7 +107,7 @@
 	dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
 		dev_name(&csdev->dev), dev_name(&child->dev));
 
-	return 0;
+	return -ENODEV;
 }
 
 static int coresight_enable_sink(struct coresight_device *csdev)
@@ -155,6 +155,9 @@
 	else
 		refport = 0;
 
+	if (refport < 0)
+		return refport;
+
 	if (atomic_inc_return(&csdev->refcnt[refport]) == 1) {
 		if (link_ops(csdev)->enable) {
 			ret = link_ops(csdev)->enable(csdev, inport, outport);
@@ -481,6 +484,8 @@
 {
 	struct coresight_device *csdev = to_coresight_device(dev);
 
+	kfree(csdev->conns);
+	kfree(csdev->refcnt);
 	kfree(csdev);
 }
 
@@ -548,7 +553,7 @@
 	to_match = data;
 	i_csdev = to_coresight_device(dev);
 
-	if (!strcmp(to_match, dev_name(&i_csdev->dev)))
+	if (to_match && !strcmp(to_match, dev_name(&i_csdev->dev)))
 		return 1;
 
 	return 0;
@@ -568,6 +573,8 @@
 
 		if (dev) {
 			conn->child_dev = to_coresight_device(dev);
+			/* and put reference from 'bus_find_device()' */
+			put_device(dev);
 		} else {
 			csdev->orphan = true;
 			conn->child_dev = NULL;
@@ -575,6 +582,50 @@
 	}
 }
 
+static int coresight_remove_match(struct device *dev, void *data)
+{
+	int i;
+	struct coresight_device *csdev, *iterator;
+	struct coresight_connection *conn;
+
+	csdev = data;
+	iterator = to_coresight_device(dev);
+
+	/* No need to check oneself */
+	if (csdev == iterator)
+		return 0;
+
+	/*
+	 * Circle throuch all the connection of that component.  If we find
+	 * a connection whose name matches @csdev, remove it.
+	 */
+	for (i = 0; i < iterator->nr_outport; i++) {
+		conn = &iterator->conns[i];
+
+		if (conn->child_dev == NULL)
+			continue;
+
+		if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
+			iterator->orphan = true;
+			conn->child_dev = NULL;
+			/* No need to continue */
+			break;
+		}
+	}
+
+	/*
+	 * Returning '0' ensures that all known component on the
+	 * bus will be checked.
+	 */
+	return 0;
+}
+
+static void coresight_remove_conns(struct coresight_device *csdev)
+{
+	bus_for_each_dev(&coresight_bustype, NULL,
+			 csdev, coresight_remove_match);
+}
+
 /**
  * coresight_timeout - loop until a bit has changed to a specific state.
  * @addr: base address of the area of interest.
@@ -713,12 +764,9 @@
 
 void coresight_unregister(struct coresight_device *csdev)
 {
-	mutex_lock(&coresight_mutex);
-
-	kfree(csdev->conns);
+	/* Remove references of that device in the topology */
+	coresight_remove_conns(csdev);
 	device_unregister(&csdev->dev);
-
-	mutex_unlock(&coresight_mutex);
 }
 EXPORT_SYMBOL_GPL(coresight_unregister);
 
--- linux-4.4.0.orig/drivers/hwtracing/coresight/of_coresight.c
+++ linux-4.4.0/drivers/hwtracing/coresight/of_coresight.c
@@ -86,7 +86,7 @@
 		return -ENOMEM;
 
 	/* Children connected to this component via @outports */
-	 pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
+	pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
 					  sizeof(*pdata->child_names),
 					  GFP_KERNEL);
 	if (!pdata->child_names)
@@ -150,7 +150,7 @@
 				continue;
 
 			/* The local out port number */
-			pdata->outports[i] = endpoint.id;
+			pdata->outports[i] = endpoint.port;
 
 			/*
 			 * Get a handle on the remote port and parent
--- linux-4.4.0.orig/drivers/hwtracing/intel_th/core.c
+++ linux-4.4.0/drivers/hwtracing/intel_th/core.c
@@ -419,6 +419,38 @@
 	},
 };
 
+#ifdef CONFIG_MODULES
+static void __intel_th_request_hub_module(struct work_struct *work)
+{
+	struct intel_th *th = container_of(work, struct intel_th,
+					   request_module_work);
+
+	request_module("intel_th_%s", th->hub->name);
+}
+
+static int intel_th_request_hub_module(struct intel_th *th)
+{
+	INIT_WORK(&th->request_module_work, __intel_th_request_hub_module);
+	schedule_work(&th->request_module_work);
+
+	return 0;
+}
+
+static void intel_th_request_hub_module_flush(struct intel_th *th)
+{
+	flush_work(&th->request_module_work);
+}
+#else
+static inline int intel_th_request_hub_module(struct intel_th *th)
+{
+	return -EINVAL;
+}
+
+static inline void intel_th_request_hub_module_flush(struct intel_th *th)
+{
+}
+#endif /* CONFIG_MODULES */
+
 static int intel_th_populate(struct intel_th *th, struct resource *devres,
 			     unsigned int ndevres, int irq)
 {
@@ -488,7 +520,7 @@
 		/* need switch driver to be loaded to enumerate the rest */
 		if (subdev->type == INTEL_TH_SWITCH && !req) {
 			th->hub = thdev;
-			err = request_module("intel_th_%s", subdev->name);
+			err = intel_th_request_hub_module(th);
 			if (!err)
 				req++;
 		}
@@ -603,6 +635,7 @@
 {
 	int i;
 
+	intel_th_request_hub_module_flush(th);
 	for (i = 0; i < TH_SUBDEVICE_MAX; i++)
 		if (th->thdev[i] != th->hub)
 			intel_th_device_remove(th->thdev[i]);
--- linux-4.4.0.orig/drivers/hwtracing/intel_th/gth.c
+++ linux-4.4.0/drivers/hwtracing/intel_th/gth.c
@@ -591,11 +591,15 @@
 {
 	struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 	int port = othdev->output.port;
+	int master;
 
 	spin_lock(&gth->gth_lock);
 	othdev->output.port = -1;
 	othdev->output.active = false;
 	gth->output[port].output = NULL;
+	for (master = 0; master <= TH_CONFIGURABLE_MASTERS; master++)
+		if (gth->master[master] == port)
+			gth->master[master] = -1;
 	spin_unlock(&gth->gth_lock);
 }
 
--- linux-4.4.0.orig/drivers/hwtracing/intel_th/intel_th.h
+++ linux-4.4.0/drivers/hwtracing/intel_th/intel_th.h
@@ -197,6 +197,9 @@
 
 	int			id;
 	int			major;
+#ifdef CONFIG_MODULES
+	struct work_struct	request_module_work;
+#endif /* CONFIG_MODULES */
 #ifdef CONFIG_INTEL_TH_DEBUG
 	struct dentry		*dbg;
 #endif
--- linux-4.4.0.orig/drivers/hwtracing/intel_th/msu.c
+++ linux-4.4.0/drivers/hwtracing/intel_th/msu.c
@@ -90,6 +90,7 @@
  * @reg_base:		register window base address
  * @thdev:		intel_th_device pointer
  * @win_list:		list of windows in multiblock mode
+ * @single_sgt:		single mode buffer
  * @nr_pages:		total number of pages allocated for this buffer
  * @single_sz:		amount of data in single mode
  * @single_wrap:	single mode wrap occurred
@@ -110,6 +111,7 @@
 	struct intel_th_device	*thdev;
 
 	struct list_head	win_list;
+	struct sg_table		single_sgt;
 	unsigned long		nr_pages;
 	unsigned long		single_sz;
 	unsigned int		single_wrap : 1;
@@ -481,7 +483,7 @@
 	u32 reg;
 
 	if (msc->mode > MSC_MODE_MULTI)
-		return -ENOTSUPP;
+		return -EINVAL;
 
 	if (msc->mode == MSC_MODE_MULTI)
 		msc_buffer_clear_hw_header(msc);
@@ -610,22 +612,45 @@
  */
 static int msc_buffer_contig_alloc(struct msc *msc, unsigned long size)
 {
+	unsigned long nr_pages = size >> PAGE_SHIFT;
 	unsigned int order = get_order(size);
 	struct page *page;
+	int ret;
 
 	if (!size)
 		return 0;
 
-	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+	ret = sg_alloc_table(&msc->single_sgt, 1, GFP_KERNEL);
+	if (ret)
+		goto err_out;
+
+	ret = -ENOMEM;
+	page = alloc_pages(GFP_KERNEL | __GFP_ZERO | GFP_DMA32, order);
 	if (!page)
-		return -ENOMEM;
+		goto err_free_sgt;
 
 	split_page(page, order);
-	msc->nr_pages = size >> PAGE_SHIFT;
+	sg_set_buf(msc->single_sgt.sgl, page_address(page), size);
+
+	ret = dma_map_sg(msc_dev(msc)->parent->parent, msc->single_sgt.sgl, 1,
+			 DMA_FROM_DEVICE);
+	if (ret < 0)
+		goto err_free_pages;
+
+	msc->nr_pages = nr_pages;
 	msc->base = page_address(page);
-	msc->base_addr = page_to_phys(page);
+	msc->base_addr = sg_dma_address(msc->single_sgt.sgl);
 
 	return 0;
+
+err_free_pages:
+	__free_pages(page, order);
+
+err_free_sgt:
+	sg_free_table(&msc->single_sgt);
+
+err_out:
+	return ret;
 }
 
 /**
@@ -636,6 +661,10 @@
 {
 	unsigned long off;
 
+	dma_unmap_sg(msc_dev(msc)->parent->parent, msc->single_sgt.sgl,
+		     1, DMA_FROM_DEVICE);
+	sg_free_table(&msc->single_sgt);
+
 	for (off = 0; off < msc->nr_pages << PAGE_SHIFT; off += PAGE_SIZE) {
 		struct page *page = virt_to_page(msc->base + off);
 
@@ -906,7 +935,7 @@
 	} else if (msc->mode == MSC_MODE_MULTI) {
 		ret = msc_buffer_multi_alloc(msc, nr_pages, nr_wins);
 	} else {
-		ret = -ENOTSUPP;
+		ret = -EINVAL;
 	}
 
 	if (!ret) {
@@ -1135,7 +1164,7 @@
 		if (ret >= 0)
 			*ppos = iter->offset;
 	} else {
-		ret = -ENOTSUPP;
+		ret = -EINVAL;
 	}
 
 put_count:
@@ -1418,7 +1447,8 @@
 		if (!end)
 			break;
 
-		len -= end - p;
+		/* consume the number and the following comma, hence +1 */
+		len -= end - p + 1;
 		p = end + 1;
 	} while (len);
 
--- linux-4.4.0.orig/drivers/hwtracing/intel_th/pci.c
+++ linux-4.4.0/drivers/hwtracing/intel_th/pci.c
@@ -67,6 +67,26 @@
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa126),
 		.driver_data = (kernel_ulong_t)0,
 	},
+	{
+		/* Kaby Lake PCH-H */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6),
+		.driver_data = (kernel_ulong_t)0,
+	},
+	{
+		/* Cannon Lake H */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa326),
+		.driver_data = (kernel_ulong_t)0,
+	},
+	{
+		/* Cannon Lake LP */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9da6),
+		.driver_data = (kernel_ulong_t)0,
+	},
+	{
+		/* Gemini Lake */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x318e),
+		.driver_data = (kernel_ulong_t)0,
+	},
 	{ 0 },
 };
 
--- linux-4.4.0.orig/drivers/hwtracing/stm/Kconfig
+++ linux-4.4.0/drivers/hwtracing/stm/Kconfig
@@ -1,6 +1,7 @@
 config STM
 	tristate "System Trace Module devices"
 	select CONFIGFS_FS
+	select SRCU
 	help
 	  A System Trace Module (STM) is a device exporting data in System
 	  Trace Protocol (STP) format as defined by MIPI STP standards.
@@ -8,6 +9,8 @@
 
 	  Say Y here to enable System Trace Module device support.
 
+if STM
+
 config STM_DUMMY
 	tristate "Dummy STM driver"
 	help
@@ -24,3 +27,5 @@
 
 	  If you want to send kernel console messages over STM devices,
 	  say Y.
+
+endif
--- linux-4.4.0.orig/drivers/hwtracing/stm/core.c
+++ linux-4.4.0/drivers/hwtracing/stm/core.c
@@ -26,6 +26,7 @@
 #include <linux/stm.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/vmalloc.h>
 #include "stm.h"
 
 #include <uapi/linux/stm.h>
@@ -113,6 +114,7 @@
 
 	stm = to_stm_device(dev);
 	if (!try_module_get(stm->owner)) {
+		/* matches class_find_device() above */
 		put_device(dev);
 		return NULL;
 	}
@@ -125,7 +127,7 @@
  * @stm:	stm device, previously acquired by stm_find_device()
  *
  * This drops the module reference and device reference taken by
- * stm_find_device().
+ * stm_find_device() or stm_char_open().
  */
 void stm_put_device(struct stm_device *stm)
 {
@@ -185,6 +187,9 @@
 {
 	struct stp_master *master = stm_master(stm, output->master);
 
+	lockdep_assert_held(&stm->mc_lock);
+	lockdep_assert_held(&output->lock);
+
 	if (WARN_ON_ONCE(master->nr_free < output->nr_chans))
 		return;
 
@@ -199,11 +204,14 @@
 {
 	struct stp_master *master = stm_master(stm, output->master);
 
+	lockdep_assert_held(&stm->mc_lock);
+	lockdep_assert_held(&output->lock);
+
 	bitmap_release_region(&master->chan_map[0], output->channel,
 			      ilog2(output->nr_chans));
 
-	output->nr_chans = 0;
 	master->nr_free += output->nr_chans;
+	output->nr_chans = 0;
 }
 
 /*
@@ -228,6 +236,9 @@
 			;
 		if (i == width)
 			return pos;
+
+		/* step over [pos..pos+i) to continue search */
+		pos += i;
 	}
 
 	return -1;
@@ -288,6 +299,7 @@
 	}
 
 	spin_lock(&stm->mc_lock);
+	spin_lock(&output->lock);
 	/* output is already assigned -- shouldn't happen */
 	if (WARN_ON_ONCE(output->nr_chans))
 		goto unlock;
@@ -304,6 +316,7 @@
 
 	ret = 0;
 unlock:
+	spin_unlock(&output->lock);
 	spin_unlock(&stm->mc_lock);
 
 	return ret;
@@ -312,11 +325,18 @@
 static void stm_output_free(struct stm_device *stm, struct stm_output *output)
 {
 	spin_lock(&stm->mc_lock);
+	spin_lock(&output->lock);
 	if (output->nr_chans)
 		stm_output_disclaim(stm, output);
+	spin_unlock(&output->lock);
 	spin_unlock(&stm->mc_lock);
 }
 
+static void stm_output_init(struct stm_output *output)
+{
+	spin_lock_init(&output->lock);
+}
+
 static int major_match(struct device *dev, const void *data)
 {
 	unsigned int major = *(unsigned int *)data;
@@ -339,6 +359,7 @@
 	if (!stmf)
 		return -ENOMEM;
 
+	stm_output_init(&stmf->output);
 	stmf->stm = to_stm_device(dev);
 
 	if (!try_module_get(stmf->stm->owner))
@@ -349,6 +370,8 @@
 	return nonseekable_open(inode, file);
 
 err_free:
+	/* matches class_find_device() above */
+	put_device(dev);
 	kfree(stmf);
 
 	return err;
@@ -359,6 +382,11 @@
 	struct stm_file *stmf = file->private_data;
 
 	stm_output_free(stmf->stm, &stmf->output);
+
+	/*
+	 * matches the stm_char_open()'s
+	 * class_find_device() + try_module_get()
+	 */
 	stm_put_device(stmf->stm);
 	kfree(stmf);
 
@@ -406,6 +434,9 @@
 	char *kbuf;
 	int err;
 
+	if (count + 1 > PAGE_SIZE)
+		count = PAGE_SIZE - 1;
+
 	/*
 	 * if no m/c have been assigned to this writer up to this
 	 * point, use "default" policy entry
@@ -473,7 +504,7 @@
 {
 	struct stm_device *stm = stmf->stm;
 	struct stp_policy_id *id;
-	int ret = -EINVAL;
+	int ret = -EINVAL, wlimit = 1;
 	u32 size;
 
 	if (stmf->output.nr_chans)
@@ -501,8 +532,10 @@
 	if (id->__reserved_0 || id->__reserved_1)
 		goto err_free;
 
-	if (id->width < 1 ||
-	    id->width > PAGE_SIZE / stm->data->sw_mmiosz)
+	if (stm->data->sw_mmiosz)
+		wlimit = PAGE_SIZE / stm->data->sw_mmiosz;
+
+	if (id->width < 1 || id->width > wlimit)
 		goto err_free;
 
 	ret = stm_file_assign(stmf, id->id, id->width);
@@ -515,10 +548,8 @@
 		ret = stm->data->link(stm->data, stmf->output.master,
 				      stmf->output.channel);
 
-	if (ret) {
+	if (ret)
 		stm_output_free(stmf->stm, &stmf->output);
-		stm_put_device(stmf->stm);
-	}
 
 err_free:
 	kfree(id);
@@ -602,7 +633,7 @@
 {
 	struct stm_device *stm = to_stm_device(dev);
 
-	kfree(stm);
+	vfree(stm);
 }
 
 int stm_register_device(struct device *parent, struct stm_data *stm_data,
@@ -619,13 +650,16 @@
 		return -EINVAL;
 
 	nmasters = stm_data->sw_end - stm_data->sw_start;
-	stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL);
+	stm = vzalloc(sizeof(*stm) + nmasters * sizeof(void *));
 	if (!stm)
 		return -ENOMEM;
 
 	stm->major = register_chrdev(0, stm_data->name, &stm_fops);
-	if (stm->major < 0)
-		goto err_free;
+	if (stm->major < 0) {
+		err = stm->major;
+		vfree(stm);
+		return err;
+	}
 
 	device_initialize(&stm->dev);
 	stm->dev.devt = MKDEV(stm->major, 0);
@@ -633,17 +667,11 @@
 	stm->dev.parent = parent;
 	stm->dev.release = stm_device_release;
 
-	err = kobject_set_name(&stm->dev.kobj, "%s", stm_data->name);
-	if (err)
-		goto err_device;
-
-	err = device_add(&stm->dev);
-	if (err)
-		goto err_device;
-
+	mutex_init(&stm->link_mutex);
 	spin_lock_init(&stm->link_lock);
 	INIT_LIST_HEAD(&stm->link_list);
 
+	/* initialize the object before it is accessible via sysfs */
 	spin_lock_init(&stm->mc_lock);
 	mutex_init(&stm->policy_mutex);
 	stm->sw_nmasters = nmasters;
@@ -651,31 +679,48 @@
 	stm->data = stm_data;
 	stm_data->stm = stm;
 
+	err = kobject_set_name(&stm->dev.kobj, "%s", stm_data->name);
+	if (err)
+		goto err_device;
+
+	err = device_add(&stm->dev);
+	if (err)
+		goto err_device;
+
 	return 0;
 
 err_device:
+	unregister_chrdev(stm->major, stm_data->name);
+
+	/* calls stm_device_release() */
 	put_device(&stm->dev);
-err_free:
-	kfree(stm);
 
 	return err;
 }
 EXPORT_SYMBOL_GPL(stm_register_device);
 
-static void __stm_source_link_drop(struct stm_source_device *src,
-				   struct stm_device *stm);
+static int __stm_source_link_drop(struct stm_source_device *src,
+				  struct stm_device *stm);
 
 void stm_unregister_device(struct stm_data *stm_data)
 {
 	struct stm_device *stm = stm_data->stm;
 	struct stm_source_device *src, *iter;
-	int i;
+	int i, ret;
 
-	spin_lock(&stm->link_lock);
+	mutex_lock(&stm->link_mutex);
 	list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) {
-		__stm_source_link_drop(src, stm);
+		ret = __stm_source_link_drop(src, stm);
+		/*
+		 * src <-> stm link must not change under the same
+		 * stm::link_mutex, so complain loudly if it has;
+		 * also in this situation ret!=0 means this src is
+		 * not connected to this stm and it should be otherwise
+		 * safe to proceed with the tear-down of stm.
+		 */
+		WARN_ON_ONCE(ret);
 	}
-	spin_unlock(&stm->link_lock);
+	mutex_unlock(&stm->link_mutex);
 
 	synchronize_srcu(&stm_source_srcu);
 
@@ -694,6 +739,17 @@
 }
 EXPORT_SYMBOL_GPL(stm_unregister_device);
 
+/*
+ * stm::link_list access serialization uses a spinlock and a mutex; holding
+ * either of them guarantees that the list is stable; modification requires
+ * holding both of them.
+ *
+ * Lock ordering is as follows:
+ *   stm::link_mutex
+ *     stm::link_lock
+ *       src::link_lock
+ */
+
 /**
  * stm_source_link_add() - connect an stm_source device to an stm device
  * @src:	stm_source device
@@ -710,6 +766,7 @@
 	char *id;
 	int err;
 
+	mutex_lock(&stm->link_mutex);
 	spin_lock(&stm->link_lock);
 	spin_lock(&src->link_lock);
 
@@ -719,6 +776,7 @@
 
 	spin_unlock(&src->link_lock);
 	spin_unlock(&stm->link_lock);
+	mutex_unlock(&stm->link_mutex);
 
 	id = kstrdup(src->data->name, GFP_KERNEL);
 	if (id) {
@@ -753,9 +811,9 @@
 
 fail_free_output:
 	stm_output_free(stm, &src->output);
-	stm_put_device(stm);
 
 fail_detach:
+	mutex_lock(&stm->link_mutex);
 	spin_lock(&stm->link_lock);
 	spin_lock(&src->link_lock);
 
@@ -764,6 +822,7 @@
 
 	spin_unlock(&src->link_lock);
 	spin_unlock(&stm->link_lock);
+	mutex_unlock(&stm->link_mutex);
 
 	return err;
 }
@@ -776,28 +835,45 @@
  * If @stm is @src::link, disconnect them from one another and put the
  * reference on the @stm device.
  *
- * Caller must hold stm::link_lock.
+ * Caller must hold stm::link_mutex.
  */
-static void __stm_source_link_drop(struct stm_source_device *src,
-				   struct stm_device *stm)
+static int __stm_source_link_drop(struct stm_source_device *src,
+				  struct stm_device *stm)
 {
 	struct stm_device *link;
+	int ret = 0;
 
+	lockdep_assert_held(&stm->link_mutex);
+
+	/* for stm::link_list modification, we hold both mutex and spinlock */
+	spin_lock(&stm->link_lock);
 	spin_lock(&src->link_lock);
 	link = srcu_dereference_check(src->link, &stm_source_srcu, 1);
-	if (WARN_ON_ONCE(link != stm)) {
-		spin_unlock(&src->link_lock);
-		return;
+
+	/*
+	 * The linked device may have changed since we last looked, because
+	 * we weren't holding the src::link_lock back then; if this is the
+	 * case, tell the caller to retry.
+	 */
+	if (link != stm) {
+		ret = -EAGAIN;
+		goto unlock;
 	}
 
 	stm_output_free(link, &src->output);
-	/* caller must hold stm::link_lock */
 	list_del_init(&src->link_entry);
 	/* matches stm_find_device() from stm_source_link_store() */
 	stm_put_device(link);
 	rcu_assign_pointer(src->link, NULL);
 
+unlock:
 	spin_unlock(&src->link_lock);
+	spin_unlock(&stm->link_lock);
+
+	if (!ret && src->data->unlink)
+		src->data->unlink(src->data);
+
+	return ret;
 }
 
 /**
@@ -813,21 +889,29 @@
 static void stm_source_link_drop(struct stm_source_device *src)
 {
 	struct stm_device *stm;
-	int idx;
+	int idx, ret;
 
+retry:
 	idx = srcu_read_lock(&stm_source_srcu);
+	/*
+	 * The stm device will be valid for the duration of this
+	 * read section, but the link may change before we grab
+	 * the src::link_lock in __stm_source_link_drop().
+	 */
 	stm = srcu_dereference(src->link, &stm_source_srcu);
 
+	ret = 0;
 	if (stm) {
-		if (src->data->unlink)
-			src->data->unlink(src->data);
-
-		spin_lock(&stm->link_lock);
-		__stm_source_link_drop(src, stm);
-		spin_unlock(&stm->link_lock);
+		mutex_lock(&stm->link_mutex);
+		ret = __stm_source_link_drop(src, stm);
+		mutex_unlock(&stm->link_mutex);
 	}
 
 	srcu_read_unlock(&stm_source_srcu, idx);
+
+	/* if it did change, retry */
+	if (ret == -EAGAIN)
+		goto retry;
 }
 
 static ssize_t stm_source_link_show(struct device *dev,
@@ -862,8 +946,10 @@
 		return -EINVAL;
 
 	err = stm_source_link_add(src, link);
-	if (err)
+	if (err) {
+		/* matches the stm_find_device() above */
 		stm_put_device(link);
+	}
 
 	return err ? : count;
 }
@@ -925,6 +1011,7 @@
 	if (err)
 		goto err;
 
+	stm_output_init(&src->output);
 	spin_lock_init(&src->link_lock);
 	INIT_LIST_HEAD(&src->link_entry);
 	src->data = data;
@@ -934,7 +1021,6 @@
 
 err:
 	put_device(&src->dev);
-	kfree(src);
 
 	return err;
 }
@@ -952,7 +1038,7 @@
 
 	stm_source_link_drop(src);
 
-	device_destroy(&stm_source_class, src->dev.devt);
+	device_unregister(&src->dev);
 }
 EXPORT_SYMBOL_GPL(stm_source_unregister_device);
 
--- linux-4.4.0.orig/drivers/hwtracing/stm/policy.c
+++ linux-4.4.0/drivers/hwtracing/stm/policy.c
@@ -272,13 +272,17 @@
 {
 	struct stm_device *stm = policy->stm;
 
+	/*
+	 * stp_policy_release() will not call here if the policy is already
+	 * unbound; other users should not either, as no link exists between
+	 * this policy and anything else in that case
+	 */
 	if (WARN_ON_ONCE(!policy->stm))
 		return;
 
-	mutex_lock(&stm->policy_mutex);
-	stm->policy = NULL;
-	mutex_unlock(&stm->policy_mutex);
+	lockdep_assert_held(&stm->policy_mutex);
 
+	stm->policy = NULL;
 	policy->stm = NULL;
 
 	stm_put_device(stm);
@@ -287,8 +291,16 @@
 static void stp_policy_release(struct config_item *item)
 {
 	struct stp_policy *policy = to_stp_policy(item);
+	struct stm_device *stm = policy->stm;
+
+	/* a policy *can* be unbound and still exist in configfs tree */
+	if (!stm)
+		return;
 
+	mutex_lock(&stm->policy_mutex);
 	stp_policy_unbind(policy);
+	mutex_unlock(&stm->policy_mutex);
+
 	kfree(policy);
 }
 
@@ -320,10 +332,11 @@
 
 	/*
 	 * node must look like <device_name>.<policy_name>, where
-	 * <device_name> is the name of an existing stm device and
-	 * <policy_name> is an arbitrary string
+	 * <device_name> is the name of an existing stm device; may
+	 *               contain dots;
+	 * <policy_name> is an arbitrary string; may not contain dots
 	 */
-	p = strchr(devname, '.');
+	p = strrchr(devname, '.');
 	if (!p) {
 		kfree(devname);
 		return ERR_PTR(-EINVAL);
--- linux-4.4.0.orig/drivers/hwtracing/stm/stm.h
+++ linux-4.4.0/drivers/hwtracing/stm/stm.h
@@ -45,6 +45,7 @@
 	int			major;
 	unsigned int		sw_nmasters;
 	struct stm_data		*data;
+	struct mutex		link_mutex;
 	spinlock_t		link_lock;
 	struct list_head	link_list;
 	/* master allocation */
@@ -56,6 +57,7 @@
 	container_of((_d), struct stm_device, dev)
 
 struct stm_output {
+	spinlock_t		lock;
 	unsigned int		master;
 	unsigned int		channel;
 	unsigned int		nr_chans;
--- linux-4.4.0.orig/drivers/i2c/Kconfig
+++ linux-4.4.0/drivers/i2c/Kconfig
@@ -59,7 +59,6 @@
 
 config I2C_MUX
 	tristate "I2C bus multiplexing support"
-	depends on HAS_IOMEM
 	help
 	  Say Y here if you want the I2C core to support the ability to
 	  handle multiplexed I2C bus topologies, by presenting each
--- linux-4.4.0.orig/drivers/i2c/algos/i2c-algo-pca.c
+++ linux-4.4.0/drivers/i2c/algos/i2c-algo-pca.c
@@ -50,8 +50,22 @@
 		pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
 		pca_outw(adap, I2C_PCA_IND, 0xA5);
 		pca_outw(adap, I2C_PCA_IND, 0x5A);
+
+		/*
+		 * After a reset we need to re-apply any configuration
+		 * (calculated in pca_init) to get the bus in a working state.
+		 */
+		pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IMODE);
+		pca_outw(adap, I2C_PCA_IND, adap->bus_settings.mode);
+		pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_ISCLL);
+		pca_outw(adap, I2C_PCA_IND, adap->bus_settings.tlow);
+		pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_ISCLH);
+		pca_outw(adap, I2C_PCA_IND, adap->bus_settings.thi);
+
+		pca_set_con(adap, I2C_PCA_CON_ENSIO);
 	} else {
 		adap->reset_chip(adap->data);
+		pca_set_con(adap, I2C_PCA_CON_ENSIO | adap->bus_settings.clock_freq);
 	}
 }
 
@@ -326,7 +340,8 @@
 			DEB2("BUS ERROR - SDA Stuck low\n");
 			pca_reset(adap);
 			goto out;
-		case 0x90: /* Bus error - SCL stuck low */
+		case 0x78: /* Bus error - SCL stuck low (PCA9665) */
+		case 0x90: /* Bus error - SCL stuck low (PCA9564) */
 			DEB2("BUS ERROR - SCL Stuck low\n");
 			pca_reset(adap);
 			goto out;
@@ -434,13 +449,14 @@
 				" Use the nominal frequency.\n", adap->name);
 		}
 
-		pca_reset(pca_data);
-
 		clock = pca_clock(pca_data);
 		printk(KERN_INFO "%s: Clock frequency is %dkHz\n",
 		     adap->name, freqs[clock]);
 
-		pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+		/* Store settings as these will be needed when the PCA chip is reset */
+		pca_data->bus_settings.clock_freq = clock;
+
+		pca_reset(pca_data);
 	} else {
 		int clock;
 		int mode;
@@ -507,19 +523,15 @@
 			thi = tlow * min_thi / min_tlow;
 		}
 
+		/* Store settings as these will be needed when the PCA chip is reset */
+		pca_data->bus_settings.mode = mode;
+		pca_data->bus_settings.tlow = tlow;
+		pca_data->bus_settings.thi = thi;
+
 		pca_reset(pca_data);
 
 		printk(KERN_INFO
 		     "%s: Clock frequency is %dHz\n", adap->name, clock * 100);
-
-		pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IMODE);
-		pca_outw(pca_data, I2C_PCA_IND, mode);
-		pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLL);
-		pca_outw(pca_data, I2C_PCA_IND, tlow);
-		pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLH);
-		pca_outw(pca_data, I2C_PCA_IND, thi);
-
-		pca_set_con(pca_data, I2C_PCA_CON_ENSIO);
 	}
 	udelay(500); /* 500 us for oscillator to stabilise */
 
--- linux-4.4.0.orig/drivers/i2c/busses/Kconfig
+++ linux-4.4.0/drivers/i2c/busses/Kconfig
@@ -952,6 +952,17 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-octeon.
 
+config I2C_THUNDERX
+	tristate "Cavium ThunderX I2C bus support"
+	depends on 64BIT && PCI && (ARM64 || COMPILE_TEST)
+	select I2C_SMBUS
+	help
+	  Say yes if you want to support the I2C serial bus on Cavium
+	  ThunderX SOC.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-thunderx.
+
 config I2C_XILINX
 	tristate "Xilinx I2C Controller"
 	depends on HAS_IOMEM
--- linux-4.4.0.orig/drivers/i2c/busses/Makefile
+++ linux-4.4.0/drivers/i2c/busses/Makefile
@@ -91,7 +91,10 @@
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
+i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
+i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
+obj-$(CONFIG_I2C_THUNDERX)	+= i2c-thunderx.o
 obj-$(CONFIG_I2C_XILINX)	+= i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)		+= i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)	+= i2c-xlp9xx.o
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-acorn.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-acorn.c
@@ -83,6 +83,7 @@
 
 static struct i2c_adapter ioc_ops = {
 	.nr			= 0,
+	.name			= "ioc",
 	.algo_data		= &ioc_data,
 };
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-ali15x3.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-ali15x3.c
@@ -119,7 +119,7 @@
 /* If force_addr is set to anything different from 0, we forcibly enable
    the device at the given address. */
 static u16 force_addr;
-module_param(force_addr, ushort, 0);
+module_param_hw(force_addr, ushort, ioport, 0);
 MODULE_PARM_DESC(force_addr,
 		 "Initialize the base address of the i2c controller");
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-at91.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-at91.c
@@ -1131,6 +1131,7 @@
 
 static int at91_twi_resume_noirq(struct device *dev)
 {
+	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
 	int ret;
 
 	if (!pm_runtime_status_suspended(dev)) {
@@ -1142,6 +1143,8 @@
 	pm_runtime_mark_last_busy(dev);
 	pm_request_autosuspend(dev);
 
+	at91_init_twi_bus(twi_dev);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-axxia.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-axxia.c
@@ -74,8 +74,7 @@
 				 MST_STATUS_ND)
 #define   MST_STATUS_ERR	(MST_STATUS_NAK | \
 				 MST_STATUS_AL  | \
-				 MST_STATUS_IP  | \
-				 MST_STATUS_TSS)
+				 MST_STATUS_IP)
 #define MST_TX_BYTES_XFRD	0x50
 #define MST_RX_BYTES_XFRD	0x54
 #define SCL_HIGH_PERIOD		0x80
@@ -241,7 +240,7 @@
 			 */
 			if (c <= 0 || c > I2C_SMBUS_BLOCK_MAX) {
 				idev->msg_err = -EPROTO;
-				i2c_int_disable(idev, ~0);
+				i2c_int_disable(idev, ~MST_STATUS_TSS);
 				complete(&idev->msg_complete);
 				break;
 			}
@@ -297,17 +296,7 @@
 			i2c_int_disable(idev, MST_STATUS_TFL);
 	}
 
-	if (status & MST_STATUS_SCC) {
-		/* Stop completed */
-		i2c_int_disable(idev, ~0);
-		complete(&idev->msg_complete);
-	} else if (status & MST_STATUS_SNS) {
-		/* Transfer done */
-		i2c_int_disable(idev, ~0);
-		if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
-			axxia_i2c_empty_rx_fifo(idev);
-		complete(&idev->msg_complete);
-	} else if (unlikely(status & MST_STATUS_ERR)) {
+	if (unlikely(status & MST_STATUS_ERR)) {
 		/* Transfer error */
 		i2c_int_disable(idev, ~0);
 		if (status & MST_STATUS_AL)
@@ -324,6 +313,21 @@
 			readl(idev->base + MST_TX_BYTES_XFRD),
 			readl(idev->base + MST_TX_XFER));
 		complete(&idev->msg_complete);
+	} else if (status & MST_STATUS_SCC) {
+		/* Stop completed */
+		i2c_int_disable(idev, ~MST_STATUS_TSS);
+		complete(&idev->msg_complete);
+	} else if (status & MST_STATUS_SNS) {
+		/* Transfer done */
+		i2c_int_disable(idev, ~MST_STATUS_TSS);
+		if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
+			axxia_i2c_empty_rx_fifo(idev);
+		complete(&idev->msg_complete);
+	} else if (status & MST_STATUS_TSS) {
+		/* Transfer timeout */
+		idev->msg_err = -ETIMEDOUT;
+		i2c_int_disable(idev, ~MST_STATUS_TSS);
+		complete(&idev->msg_complete);
 	}
 
 out:
@@ -339,10 +343,10 @@
 	u32 rx_xfer, tx_xfer;
 	u32 addr_1, addr_2;
 	unsigned long time_left;
+	unsigned int wt_value;
 
 	idev->msg = msg;
 	idev->msg_xfrd = 0;
-	idev->msg_err = 0;
 	reinit_completion(&idev->msg_complete);
 
 	if (i2c_m_ten(msg)) {
@@ -382,9 +386,18 @@
 	else if (axxia_i2c_fill_tx_fifo(idev) != 0)
 		int_mask |= MST_STATUS_TFL;
 
+	wt_value = WT_VALUE(readl(idev->base + WAIT_TIMER_CONTROL));
+	/* Disable wait timer temporarly */
+	writel(wt_value, idev->base + WAIT_TIMER_CONTROL);
+	/* Check if timeout error happened */
+	if (idev->msg_err)
+		goto out;
+
 	/* Start manual mode */
 	writel(CMD_MANUAL, idev->base + MST_COMMAND);
 
+	writel(WT_EN | wt_value, idev->base + WAIT_TIMER_CONTROL);
+
 	i2c_int_enable(idev, int_mask);
 
 	time_left = wait_for_completion_timeout(&idev->msg_complete,
@@ -395,13 +408,15 @@
 	if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
 		dev_warn(idev->dev, "busy after xfer\n");
 
-	if (time_left == 0)
+	if (time_left == 0) {
 		idev->msg_err = -ETIMEDOUT;
-
-	if (idev->msg_err == -ETIMEDOUT)
 		i2c_recover_bus(&idev->adapter);
+		axxia_i2c_init(idev);
+	}
 
-	if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
+out:
+	if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO &&
+			idev->msg_err != -ETIMEDOUT)
 		axxia_i2c_init(idev);
 
 	return idev->msg_err;
@@ -409,7 +424,7 @@
 
 static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
 {
-	u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC;
+	u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC | MST_STATUS_TSS;
 	unsigned long time_left;
 
 	reinit_completion(&idev->msg_complete);
@@ -436,6 +451,9 @@
 	int i;
 	int ret = 0;
 
+	idev->msg_err = 0;
+	i2c_int_enable(idev, MST_STATUS_TSS);
+
 	for (i = 0; ret == 0 && i < num; ++i)
 		ret = axxia_i2c_xfer_msg(idev, &msgs[i]);
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-brcmstb.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-brcmstb.c
@@ -304,7 +304,7 @@
 		goto cmd_out;
 	}
 
-	if ((CMD_RD || CMD_WR) &&
+	if ((cmd == CMD_RD || cmd == CMD_WR) &&
 	    bsc_readl(dev, iic_enable) & BSC_IIC_EN_NOACK_MASK) {
 		rc = -EREMOTEIO;
 		dev_dbg(dev->device, "controller received NOACK intr for %s\n",
@@ -562,8 +562,7 @@
 	if (!dev)
 		return -ENOMEM;
 
-	dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(struct bsc_regs *),
-				       GFP_KERNEL);
+	dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(*dev->bsc_regmap), GFP_KERNEL);
 	if (!dev->bsc_regmap)
 		return -ENOMEM;
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-cpm.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-cpm.c
@@ -74,6 +74,9 @@
 	char    res1[4];	/* Reserved */
 	ushort  rpbase;		/* Relocation pointer */
 	char    res2[2];	/* Reserved */
+	/* The following elements are only for CPM2 */
+	char    res3[4];	/* Reserved */
+	uint    sdmatmp;	/* Internal */
 };
 
 #define I2COM_START	0x80
@@ -116,8 +119,8 @@
 	cbd_t __iomem *rbase;
 	u_char *txbuf[CPM_MAXBD];
 	u_char *rxbuf[CPM_MAXBD];
-	u32 txdma[CPM_MAXBD];
-	u32 rxdma[CPM_MAXBD];
+	dma_addr_t txdma[CPM_MAXBD];
+	dma_addr_t rxdma[CPM_MAXBD];
 };
 
 static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id)
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-cros-ec-tunnel.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-cros-ec-tunnel.c
@@ -215,7 +215,7 @@
 	msg->outsize = request_len;
 	msg->insize = response_len;
 
-	result = cros_ec_cmd_xfer(bus->ec, msg);
+	result = cros_ec_cmd_xfer_status(bus->ec, msg);
 	if (result < 0) {
 		dev_err(dev, "Error transferring EC i2c message %d\n", result);
 		goto exit;
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-davinci.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-davinci.c
@@ -234,12 +234,16 @@
 	/*
 	 * It's not always possible to have 1 to 2 ratio when d=7, so fall back
 	 * to minimal possible clkh in this case.
+	 *
+	 * Note:
+	 * CLKH is not allowed to be 0, in this case I2C clock is not generated
+	 * at all
 	 */
-	if (clk >= clkl + d) {
+	if (clk > clkl + d) {
 		clkh = clk - clkl - d;
 		clkl -= d;
 	} else {
-		clkh = 0;
+		clkh = 1;
 		clkl = clk - (d << 1);
 	}
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-designware-core.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-designware-core.c
@@ -271,6 +271,17 @@
 		 enable ? "en" : "dis");
 }
 
+static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
+{
+	/*
+	 * Clock is not necessary if we got LCNT/HCNT values directly from
+	 * the platform code.
+	 */
+	if (WARN_ON_ONCE(!dev->get_clk_rate_khz))
+		return 0;
+	return dev->get_clk_rate_khz(dev);
+}
+
 /**
  * i2c_dw_init() - initialize the designware i2c master hardware
  * @dev: device private data
@@ -281,7 +292,6 @@
  */
 int i2c_dw_init(struct dw_i2c_dev *dev)
 {
-	u32 input_clock_khz;
 	u32 hcnt, lcnt;
 	u32 reg;
 	u32 sda_falling_time, scl_falling_time;
@@ -295,8 +305,6 @@
 		}
 	}
 
-	input_clock_khz = dev->get_clk_rate_khz(dev);
-
 	reg = dw_readl(dev, DW_IC_COMP_TYPE);
 	if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
 		/* Configure register endianess access */
@@ -325,12 +333,12 @@
 		hcnt = dev->ss_hcnt;
 		lcnt = dev->ss_lcnt;
 	} else {
-		hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+		hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
 					4000,	/* tHD;STA = tHIGH = 4.0 us */
 					sda_falling_time,
 					0,	/* 0: DW default, 1: Ideal */
 					0);	/* No offset */
-		lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+		lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
 					4700,	/* tLOW = 4.7 us */
 					scl_falling_time,
 					0);	/* No offset */
@@ -344,12 +352,12 @@
 		hcnt = dev->fs_hcnt;
 		lcnt = dev->fs_lcnt;
 	} else {
-		hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+		hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
 					600,	/* tHD;STA = tHIGH = 0.6 us */
 					sda_falling_time,
 					0,	/* 0: DW default, 1: Ideal */
 					0);	/* No offset */
-		lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+		lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
 					1300,	/* tLOW = 1.3 us */
 					scl_falling_time,
 					0);	/* No offset */
@@ -656,7 +664,7 @@
 	i2c_dw_xfer_init(dev);
 
 	/* wait for tx to complete */
-	if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) {
+	if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
 		dev_err(dev->dev, "controller timed out\n");
 		/* i2c_dw_init implicitly disables the adapter */
 		i2c_dw_init(dev);
@@ -865,7 +873,8 @@
 	i2c_set_adapdata(adap, dev);
 
 	i2c_dw_disable_int(dev);
-	r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
+	r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
+			     IRQF_SHARED | IRQF_COND_SUSPEND,
 			     dev_name(dev->dev), dev);
 	if (r) {
 		dev_err(dev->dev, "failure requesting irq %i: %d\n",
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-designware-platdrv.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -36,6 +36,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/property.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
@@ -132,12 +133,24 @@
 }
 #endif
 
+static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
+{
+	if (IS_ERR(i_dev->clk))
+		return PTR_ERR(i_dev->clk);
+
+	if (prepare)
+		return clk_prepare_enable(i_dev->clk);
+
+	clk_disable_unprepare(i_dev->clk);
+	return 0;
+}
+
 static int dw_i2c_plat_probe(struct platform_device *pdev)
 {
+	struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct dw_i2c_dev *dev;
 	struct i2c_adapter *adap;
 	struct resource *mem;
-	struct dw_i2c_platform_data *pdata;
 	int irq, r;
 	u32 clk_freq, ht = 0;
 
@@ -161,33 +174,28 @@
 	/* fast mode by default because of legacy reasons */
 	clk_freq = 400000;
 
-	if (has_acpi_companion(&pdev->dev)) {
-		dw_i2c_acpi_configure(pdev);
-	} else if (pdev->dev.of_node) {
-		of_property_read_u32(pdev->dev.of_node,
-					"i2c-sda-hold-time-ns", &ht);
-
-		of_property_read_u32(pdev->dev.of_node,
-				     "i2c-sda-falling-time-ns",
-				     &dev->sda_falling_time);
-		of_property_read_u32(pdev->dev.of_node,
-				     "i2c-scl-falling-time-ns",
-				     &dev->scl_falling_time);
-
-		of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-				     &clk_freq);
-
-		/* Only standard mode at 100kHz and fast mode at 400kHz
-		 * are supported.
-		 */
-		if (clk_freq != 100000 && clk_freq != 400000) {
-			dev_err(&pdev->dev, "Only 100kHz and 400kHz supported");
-			return -EINVAL;
-		}
+	if (pdata) {
+		clk_freq = pdata->i2c_scl_freq;
 	} else {
-		pdata = dev_get_platdata(&pdev->dev);
-		if (pdata)
-			clk_freq = pdata->i2c_scl_freq;
+		device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns",
+					 &ht);
+		device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns",
+					 &dev->sda_falling_time);
+		device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns",
+					 &dev->scl_falling_time);
+		device_property_read_u32(&pdev->dev, "clock-frequency",
+					 &clk_freq);
+	}
+
+	if (has_acpi_companion(&pdev->dev))
+		dw_i2c_acpi_configure(pdev);
+
+	/*
+	 * Only standard mode at 100kHz and fast mode at 400kHz are supported.
+	 */
+	if (clk_freq != 100000 && clk_freq != 400000) {
+		dev_err(&pdev->dev, "Only 100kHz and 400kHz supported");
+		return -EINVAL;
 	}
 
 	r = i2c_dw_eval_lock_support(dev);
@@ -209,16 +217,13 @@
 			DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
 
 	dev->clk = devm_clk_get(&pdev->dev, NULL);
-	dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
-	if (IS_ERR(dev->clk))
-		return PTR_ERR(dev->clk);
-	clk_prepare_enable(dev->clk);
-
-	if (!dev->sda_hold_time && ht) {
-		u32 ic_clk = dev->get_clk_rate_khz(dev);
+	if (!i2c_dw_plat_prepare_clk(dev, true)) {
+		dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
 
-		dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
-					     1000000);
+		if (!dev->sda_hold_time && ht)
+			dev->sda_hold_time = div_u64(
+				(u64)dev->get_clk_rate_khz(dev) * ht + 500000,
+				1000000);
 	}
 
 	if (!dev->tx_fifo_depth) {
@@ -294,13 +299,13 @@
 #endif
 
 #ifdef CONFIG_PM
-static int dw_i2c_plat_suspend(struct device *dev)
+static int dw_i2c_plat_runtime_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
 
 	i2c_dw_disable(i_dev);
-	clk_disable_unprepare(i_dev->clk);
+	i2c_dw_plat_prepare_clk(i_dev, false);
 
 	return 0;
 }
@@ -310,7 +315,7 @@
 	struct platform_device *pdev = to_platform_device(dev);
 	struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
 
-	clk_prepare_enable(i_dev->clk);
+	i2c_dw_plat_prepare_clk(i_dev, true);
 
 	if (!i_dev->pm_runtime_disabled)
 		i2c_dw_init(i_dev);
@@ -318,11 +323,21 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int dw_i2c_plat_suspend(struct device *dev)
+{
+	pm_runtime_resume(dev);
+	return dw_i2c_plat_runtime_suspend(dev);
+}
+#endif
+
 static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
 	.prepare = dw_i2c_plat_prepare,
 	.complete = dw_i2c_plat_complete,
 	SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
-	SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
+	SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend,
+			   dw_i2c_plat_resume,
+			   NULL)
 };
 
 #define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-efm32.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-efm32.c
@@ -433,7 +433,7 @@
 	ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
-		return ret;
+		goto err_disable_clk;
 	}
 
 	ret = i2c_add_adapter(&ddata->adapter);
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-eg20t.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-eg20t.c
@@ -189,6 +189,7 @@
 	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, },
 	{0,}
 };
+MODULE_DEVICE_TABLE(pci, pch_pcidev_id);
 
 static irqreturn_t pch_i2c_handler(int irq, void *pData);
 
@@ -773,13 +774,6 @@
 	/* Set the number of I2C channel instance */
 	adap_info->ch_num = id->driver_data;
 
-	ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
-		  KBUILD_MODNAME, adap_info);
-	if (ret) {
-		pch_pci_err(pdev, "request_irq FAILED\n");
-		goto err_request_irq;
-	}
-
 	for (i = 0; i < adap_info->ch_num; i++) {
 		pch_adap = &adap_info->pch_data[i].pch_adapter;
 		adap_info->pch_i2c_suspended = false;
@@ -796,6 +790,17 @@
 		adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
 
 		pch_adap->dev.parent = &pdev->dev;
+	}
+
+	ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
+		  KBUILD_MODNAME, adap_info);
+	if (ret) {
+		pch_pci_err(pdev, "request_irq FAILED\n");
+		goto err_request_irq;
+	}
+
+	for (i = 0; i < adap_info->ch_num; i++) {
+		pch_adap = &adap_info->pch_data[i].pch_adapter;
 
 		pch_i2c_init(&adap_info->pch_data[i]);
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-elektor.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-elektor.c
@@ -333,11 +333,11 @@
 MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
 MODULE_LICENSE("GPL");
 
-module_param(base, int, 0);
-module_param(irq, int, 0);
+module_param_hw(base, int, ioport_or_iomem, 0);
+module_param_hw(irq, int, irq, 0);
 module_param(clock, int, 0);
 module_param(own, int, 0);
-module_param(mmapped, int, 0);
+module_param_hw(mmapped, int, other, 0);
 
 module_init(i2c_pcfisa_init);
 module_exit(i2c_pcfisa_exit);
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-exynos5.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-exynos5.c
@@ -671,7 +671,9 @@
 		return -EIO;
 	}
 
-	clk_prepare_enable(i2c->clk);
+	ret = clk_enable(i2c->clk);
+	if (ret)
+		return ret;
 
 	for (i = 0; i < num; i++, msgs++) {
 		stop = (i == num - 1);
@@ -695,7 +697,7 @@
 	}
 
  out:
-	clk_disable_unprepare(i2c->clk);
+	clk_disable(i2c->clk);
 	return ret;
 }
 
@@ -747,7 +749,9 @@
 		return -ENOENT;
 	}
 
-	clk_prepare_enable(i2c->clk);
+	ret = clk_prepare_enable(i2c->clk);
+	if (ret)
+		return ret;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
@@ -799,6 +803,10 @@
 
 	platform_set_drvdata(pdev, i2c);
 
+	clk_disable(i2c->clk);
+
+	return 0;
+
  err_clk:
 	clk_disable_unprepare(i2c->clk);
 	return ret;
@@ -810,6 +818,8 @@
 
 	i2c_del_adapter(&i2c->adap);
 
+	clk_unprepare(i2c->clk);
+
 	return 0;
 }
 
@@ -821,6 +831,8 @@
 
 	i2c->suspended = 1;
 
+	clk_unprepare(i2c->clk);
+
 	return 0;
 }
 
@@ -830,7 +842,9 @@
 	struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
 	int ret = 0;
 
-	clk_prepare_enable(i2c->clk);
+	ret = clk_prepare_enable(i2c->clk);
+	if (ret)
+		return ret;
 
 	ret = exynos5_hsi2c_clock_setup(i2c);
 	if (ret) {
@@ -839,7 +853,7 @@
 	}
 
 	exynos5_i2c_init(i2c);
-	clk_disable_unprepare(i2c->clk);
+	clk_disable(i2c->clk);
 	i2c->suspended = 0;
 
 	return 0;
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-hix5hd2.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-hix5hd2.c
@@ -500,6 +500,7 @@
 	i2c_del_adapter(&priv->adap);
 	pm_runtime_disable(priv->dev);
 	pm_runtime_set_suspended(priv->dev);
+	clk_disable_unprepare(priv->clk);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-i801.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-i801.c
@@ -128,6 +128,7 @@
 
 #define SBREG_BAR		0x10
 #define SBREG_SMBCTRL		0xc6000c
+#define SBREG_SMBCTRL_DNV	0xcf000c
 
 /* Host status bits for SMBPCISTS */
 #define SMBPCISTS_INTS		0x08
@@ -210,6 +211,7 @@
 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS		0x5ad4
 #define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS		0xa1a3
 #define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS	0xa223
+#define PCI_DEVICE_ID_INTEL_KABYPOINT_H_SMBUS		0xa2a3
 
 struct i801_mux_config {
 	char *gpio_chip;
@@ -244,6 +246,13 @@
 	struct platform_device *mux_pdev;
 #endif
 	struct platform_device *tco_pdev;
+
+	/*
+	 * If set to true the host controller registers are reserved for
+	 * ACPI AML use. Protected by acpi_lock.
+	 */
+	bool acpi_reserved;
+	struct mutex acpi_lock;
 };
 
 #define FEATURE_SMBUS_PEC	(1 << 0)
@@ -714,9 +723,15 @@
 {
 	int hwpec;
 	int block = 0;
-	int ret, xact = 0;
+	int ret = 0, xact = 0;
 	struct i801_priv *priv = i2c_get_adapdata(adap);
 
+	mutex_lock(&priv->acpi_lock);
+	if (priv->acpi_reserved) {
+		mutex_unlock(&priv->acpi_lock);
+		return -EBUSY;
+	}
+
 	hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
 		&& size != I2C_SMBUS_QUICK
 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
@@ -773,7 +788,8 @@
 	default:
 		dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
 			size);
-		return -EOPNOTSUPP;
+		ret = -EOPNOTSUPP;
+		goto out;
 	}
 
 	if (hwpec)	/* enable/disable hardware PEC */
@@ -796,11 +812,11 @@
 		       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
 
 	if (block)
-		return ret;
+		goto out;
 	if (ret)
-		return ret;
+		goto out;
 	if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
-		return 0;
+		goto out;
 
 	switch (xact & 0x7f) {
 	case I801_BYTE:	/* Result put in SMBHSTDAT0 */
@@ -812,7 +828,10 @@
 			     (inb_p(SMBHSTDAT1(priv)) << 8);
 		break;
 	}
-	return 0;
+
+out:
+	mutex_unlock(&priv->acpi_lock);
+	return ret;
 }
 
 
@@ -875,6 +894,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYPOINT_H_SMBUS) },
 	{ 0, }
 };
 
@@ -1234,7 +1254,11 @@
 	spin_unlock(&p2sb_spinlock);
 
 	res = &tco_res[ICH_RES_MEM_OFF];
-	res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL;
+	if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS)
+		res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV;
+	else
+		res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL;
+
 	res->end = res->start + 3;
 	res->flags = IORESOURCE_MEM;
 
@@ -1249,6 +1273,79 @@
 	priv->tco_pdev = pdev;
 }
 
+#ifdef CONFIG_ACPI
+static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
+				      acpi_physical_address address)
+{
+	return address >= priv->smba &&
+	       address <= pci_resource_end(priv->pci_dev, SMBBAR);
+}
+
+static acpi_status
+i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
+		     u64 *value, void *handler_context, void *region_context)
+{
+	struct i801_priv *priv = handler_context;
+	struct pci_dev *pdev = priv->pci_dev;
+	acpi_status status;
+
+	/*
+	 * Once BIOS AML code touches the OpRegion we warn and inhibit any
+	 * further access from the driver itself. This device is now owned
+	 * by the system firmware.
+	 */
+	mutex_lock(&priv->acpi_lock);
+
+	if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
+		priv->acpi_reserved = true;
+
+		dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
+		dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n");
+	}
+
+	if ((function & ACPI_IO_MASK) == ACPI_READ)
+		status = acpi_os_read_port(address, (u32 *)value, bits);
+	else
+		status = acpi_os_write_port(address, (u32)*value, bits);
+
+	mutex_unlock(&priv->acpi_lock);
+
+	return status;
+}
+
+static int i801_acpi_probe(struct i801_priv *priv)
+{
+	struct acpi_device *adev;
+	acpi_status status;
+
+	adev = ACPI_COMPANION(&priv->pci_dev->dev);
+	if (adev) {
+		status = acpi_install_address_space_handler(adev->handle,
+				ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler,
+				NULL, priv);
+		if (ACPI_SUCCESS(status))
+			return 0;
+	}
+
+	return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]);
+}
+
+static void i801_acpi_remove(struct i801_priv *priv)
+{
+	struct acpi_device *adev;
+
+	adev = ACPI_COMPANION(&priv->pci_dev->dev);
+	if (!adev)
+		return;
+
+	acpi_remove_address_space_handler(adev->handle,
+		ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler);
+}
+#else
+static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
+static inline void i801_acpi_remove(struct i801_priv *priv) { }
+#endif
+
 static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	unsigned char temp;
@@ -1266,12 +1363,16 @@
 	priv->adapter.dev.parent = &dev->dev;
 	ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
 	priv->adapter.retries = 3;
+	mutex_init(&priv->acpi_lock);
 
 	priv->pci_dev = dev;
 	switch (dev->device) {
 	case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS:
 	case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS:
+	case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS:
+	case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
 	case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
+	case PCI_DEVICE_ID_INTEL_KABYPOINT_H_SMBUS:
 		priv->features |= FEATURE_I2C_BLOCK_READ;
 		priv->features |= FEATURE_IRQ;
 		priv->features |= FEATURE_SMBUS_PEC;
@@ -1326,10 +1427,8 @@
 		return -ENODEV;
 	}
 
-	err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
-	if (err) {
+	if (i801_acpi_probe(priv))
 		return -ENODEV;
-	}
 
 	err = pcim_iomap_regions(dev, 1 << SMBBAR,
 				 dev_driver_string(&dev->dev));
@@ -1338,6 +1437,7 @@
 			"Failed to request SMBus region 0x%lx-0x%Lx\n",
 			priv->smba,
 			(unsigned long long)pci_resource_end(dev, SMBBAR));
+		i801_acpi_remove(priv);
 		return err;
 	}
 
@@ -1402,6 +1502,7 @@
 	err = i2c_add_adapter(&priv->adapter);
 	if (err) {
 		dev_err(&dev->dev, "Failed to add SMBus adapter\n");
+		i801_acpi_remove(priv);
 		return err;
 	}
 
@@ -1420,6 +1521,7 @@
 
 	i801_del_mux(priv);
 	i2c_del_adapter(&priv->adapter);
+	i801_acpi_remove(priv);
 	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 
 	platform_device_unregister(priv->tco_pdev);
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-img-scb.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-img-scb.c
@@ -816,9 +816,9 @@
  * Timer function to check if something has gone wrong in automatic mode (so we
  * don't have to handle so many interrupts just to catch an exception).
  */
-static void img_i2c_check_timer(unsigned long arg)
+static void img_i2c_check_timer(struct timer_list *t)
 {
-	struct img_i2c *i2c = (struct img_i2c *)arg;
+	struct img_i2c *i2c = from_timer(i2c, t, check_timer);
 	unsigned long flags;
 	unsigned int line_status;
 
@@ -1322,9 +1322,7 @@
 	}
 
 	/* Set up the exception check timer */
-	init_timer(&i2c->check_timer);
-	i2c->check_timer.function = img_i2c_check_timer;
-	i2c->check_timer.data = (unsigned long)i2c;
+	timer_setup(&i2c->check_timer, img_i2c_check_timer, 0);
 
 	i2c->bitrate = timings[0].max_bitrate;
 	if (!of_property_read_u32(node, "clock-frequency", &val))
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-imx.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-imx.c
@@ -382,6 +382,7 @@
 		goto err_desc;
 	}
 
+	reinit_completion(&dma->cmd_complete);
 	txdesc->callback = i2c_imx_dma_callback;
 	txdesc->callback_param = i2c_imx;
 	if (dma_submit_error(dmaengine_submit(txdesc))) {
@@ -419,6 +420,19 @@
 /** Functions for IMX I2C adapter driver ***************************************
 *******************************************************************************/
 
+static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits)
+{
+	unsigned int temp;
+
+	/*
+	 * i2sr_clr_opcode is the value to clear all interrupts. Here we want to
+	 * clear only <bits>, so we write ~i2sr_clr_opcode with just <bits>
+	 * toggled. This is required because i.MX needs W0C and Vybrid uses W1C.
+	 */
+	temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits;
+	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
+}
+
 static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
 {
 	unsigned long orig_jiffies = jiffies;
@@ -431,8 +445,7 @@
 
 		/* check for arbitration lost */
 		if (temp & I2SR_IAL) {
-			temp &= ~I2SR_IAL;
-			imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
+			i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
 			return -EAGAIN;
 		}
 
@@ -459,6 +472,16 @@
 		dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
 		return -ETIMEDOUT;
 	}
+
+	/* check for arbitration lost */
+	if (i2c_imx->i2csr & I2SR_IAL) {
+		dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__);
+		i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
+
+		i2c_imx->i2csr = 0;
+		return -EAGAIN;
+	}
+
 	dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__);
 	i2c_imx->i2csr = 0;
 	return 0;
@@ -594,9 +617,7 @@
 	if (temp & I2SR_IIF) {
 		/* save status register */
 		i2c_imx->i2csr = temp;
-		temp &= ~I2SR_IIF;
-		temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
-		imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
+		i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
 		wake_up(&i2c_imx->queue);
 		return IRQ_HANDLED;
 	}
@@ -631,7 +652,6 @@
 	 * The first byte must be transmitted by the CPU.
 	 */
 	imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
-	reinit_completion(&i2c_imx->dma->cmd_complete);
 	time_left = wait_for_completion_timeout(
 				&i2c_imx->dma->cmd_complete,
 				msecs_to_jiffies(DMA_TIMEOUT));
@@ -677,9 +697,6 @@
 	struct imx_i2c_dma *dma = i2c_imx->dma;
 	struct device *dev = &i2c_imx->adapter.dev;
 
-	temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
-	temp |= I2CR_DMAEN;
-	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
 
 	dma->chan_using = dma->chan_rx;
 	dma->dma_transfer_dir = DMA_DEV_TO_MEM;
@@ -690,7 +707,6 @@
 	if (result)
 		return result;
 
-	reinit_completion(&i2c_imx->dma->cmd_complete);
 	time_left = wait_for_completion_timeout(
 				&i2c_imx->dma->cmd_complete,
 				msecs_to_jiffies(DMA_TIMEOUT));
@@ -793,6 +809,7 @@
 	int i, result;
 	unsigned int temp;
 	int block_data = msgs->flags & I2C_M_RECV_LEN;
+	int use_dma = i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data;
 
 	dev_dbg(&i2c_imx->adapter.dev,
 		"<%s> write slave address: addr=0x%x\n",
@@ -819,12 +836,14 @@
 	 */
 	if ((msgs->len - 1) || block_data)
 		temp &= ~I2CR_TXAK;
+	if (use_dma)
+		temp |= I2CR_DMAEN;
 	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
 	imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
 
 	dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
 
-	if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data)
+	if (use_dma)
 		return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg);
 
 	/* read data */
@@ -1077,7 +1096,8 @@
 	/* Get I2C clock */
 	i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(i2c_imx->clk)) {
-		dev_err(&pdev->dev, "can't get I2C clock\n");
+		if (PTR_ERR(i2c_imx->clk) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "can't get I2C clock\n");
 		return PTR_ERR(i2c_imx->clk);
 	}
 
@@ -1093,20 +1113,20 @@
 		goto clk_disable;
 	}
 
-	/* Request IRQ */
-	ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
-				pdev->name, i2c_imx);
-	if (ret) {
-		dev_err(&pdev->dev, "can't claim irq %d\n", irq);
-		goto clk_disable;
-	}
-
 	/* Init queue */
 	init_waitqueue_head(&i2c_imx->queue);
 
 	/* Set up adapter data */
 	i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
 
+	/* Request IRQ */
+	ret = request_threaded_irq(irq, i2c_imx_isr, NULL, 0,
+				   pdev->name, i2c_imx);
+	if (ret) {
+		dev_err(&pdev->dev, "can't claim irq %d\n", irq);
+		goto clk_disable;
+	}
+
 	/* Set up clock divider */
 	i2c_imx->bitrate = IMX_I2C_BIT_RATE;
 	ret = of_property_read_u32(pdev->dev.of_node,
@@ -1125,7 +1145,7 @@
 	ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "registration failed\n");
-		goto clk_disable;
+		goto clk_free_irq;
 	}
 
 	/* Set up platform driver data */
@@ -1143,6 +1163,8 @@
 
 	return 0;   /* Return OK */
 
+clk_free_irq:
+	free_irq(irq, i2c_imx);
 clk_disable:
 	clk_disable_unprepare(i2c_imx->clk);
 	return ret;
@@ -1151,6 +1173,7 @@
 static int i2c_imx_remove(struct platform_device *pdev)
 {
 	struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
+	int irq;
 
 	/* remove adapter */
 	dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
@@ -1165,6 +1188,10 @@
 	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
 	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
 
+	irq = platform_get_irq(pdev, 0);
+	if (irq >= 0)
+		free_irq(irq, i2c_imx);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-ismt.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-ismt.c
@@ -338,6 +338,11 @@
 			data->word = dma_buffer[0] | (dma_buffer[1] << 8);
 			break;
 		case I2C_SMBUS_BLOCK_DATA:
+			if (desc->rxbytes != dma_buffer[0] + 1)
+				return -EMSGSIZE;
+
+			memcpy(data->block, dma_buffer, desc->rxbytes);
+			break;
 		case I2C_SMBUS_I2C_BLOCK_DATA:
 			memcpy(&data->block[1], dma_buffer, desc->rxbytes);
 			data->block[0] = desc->rxbytes;
@@ -582,7 +587,7 @@
 
 	/* unmap the data buffer */
 	if (dma_size != 0)
-		dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction);
+		dma_unmap_single(dev, dma_addr, dma_size, dma_direction);
 
 	if (unlikely(!time_left)) {
 		dev_err(dev, "completion wait timed out\n");
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-jz4780.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-jz4780.c
@@ -82,25 +82,6 @@
 #define JZ4780_I2C_STA_TFNF		BIT(1)
 #define JZ4780_I2C_STA_ACT		BIT(0)
 
-static const char * const jz4780_i2c_abrt_src[] = {
-	"ABRT_7B_ADDR_NOACK",
-	"ABRT_10ADDR1_NOACK",
-	"ABRT_10ADDR2_NOACK",
-	"ABRT_XDATA_NOACK",
-	"ABRT_GCALL_NOACK",
-	"ABRT_GCALL_READ",
-	"ABRT_HS_ACKD",
-	"SBYTE_ACKDET",
-	"ABRT_HS_NORSTRT",
-	"SBYTE_NORSTRT",
-	"ABRT_10B_RD_NORSTRT",
-	"ABRT_MASTER_DIS",
-	"ARB_LOST",
-	"SLVFLUSH_TXFIFO",
-	"SLV_ARBLOST",
-	"SLVRD_INTX",
-};
-
 #define JZ4780_I2C_INTST_IGC		BIT(11)
 #define JZ4780_I2C_INTST_ISTT		BIT(10)
 #define JZ4780_I2C_INTST_ISTP		BIT(9)
@@ -538,21 +519,8 @@
 
 static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src)
 {
-	int i;
-
-	dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src);
-	dev_err(&i2c->adap.dev, "device addr=%x\n",
-		jz4780_i2c_readw(i2c, JZ4780_I2C_TAR));
-	dev_err(&i2c->adap.dev, "send cmd count:%d  %d\n",
-		i2c->cmd, i2c->cmd_buf[i2c->cmd]);
-	dev_err(&i2c->adap.dev, "receive data count:%d  %d\n",
-		i2c->cmd, i2c->data_buf[i2c->cmd]);
-
-	for (i = 0; i < 16; i++) {
-		if (src & BIT(i))
-			dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n",
-				i, jz4780_i2c_abrt_src[i]);
-	}
+	dev_dbg(&i2c->adap.dev, "txabrt: 0x%08x, cmd: %d, send: %d, recv: %d\n",
+		src, i2c->cmd, i2c->cmd_buf[i2c->cmd], i2c->data_buf[i2c->cmd]);
 }
 
 static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
@@ -786,10 +754,6 @@
 
 	jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
 
-	i2c->cmd = 0;
-	memset(i2c->cmd_buf, 0, BUFSIZE);
-	memset(i2c->data_buf, 0, BUFSIZE);
-
 	i2c->irq = platform_get_irq(pdev, 0);
 	ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
 			       dev_name(&pdev->dev), i2c);
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-meson.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-meson.c
@@ -175,7 +175,7 @@
 		wdata1 |= *buf++ << ((i - 4) * 8);
 
 	writel(wdata0, i2c->regs + REG_TOK_WDATA0);
-	writel(wdata0, i2c->regs + REG_TOK_WDATA1);
+	writel(wdata1, i2c->regs + REG_TOK_WDATA1);
 
 	dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__,
 		wdata0, wdata1, len);
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-mv64xxx.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-mv64xxx.c
@@ -856,12 +856,16 @@
 	 */
 	if (of_device_is_compatible(np, "marvell,mv78230-i2c")) {
 		drv_data->offload_enabled = true;
-		drv_data->errata_delay = true;
+		/* The delay is only needed in standard mode (100kHz) */
+		if (bus_freq <= 100000)
+			drv_data->errata_delay = true;
 	}
 
 	if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) {
 		drv_data->offload_enabled = false;
-		drv_data->errata_delay = true;
+		/* The delay is only needed in standard mode (100kHz) */
+		if (bus_freq <= 100000)
+			drv_data->errata_delay = true;
 	}
 
 	if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c"))
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-octeon-core.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-octeon-core.c
@@ -0,0 +1,792 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This file contains the shared part of the driver for the i2c adapter in
+ * Cavium Networks' OCTEON processors and ThunderX SOCs.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "i2c-octeon-core.h"
+
+/* interrupt service routine */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+	struct octeon_i2c *i2c = dev_id;
+
+	i2c->int_disable(i2c);
+	wake_up(&i2c->queue);
+
+	return IRQ_HANDLED;
+}
+
+static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
+{
+	return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG);
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+	long time_left;
+
+	/*
+	 * Some chip revisions don't assert the irq in the interrupt
+	 * controller. So we must poll for the IFLG change.
+	 */
+	if (i2c->broken_irq_mode) {
+		u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+		while (!octeon_i2c_test_iflg(i2c) &&
+		       time_before64(get_jiffies_64(), end))
+			usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
+
+		return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+	}
+
+	i2c->int_enable(i2c);
+	time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
+				       i2c->adap.timeout);
+	i2c->int_disable(i2c);
+
+	if (i2c->broken_irq_check && !time_left &&
+	    octeon_i2c_test_iflg(i2c)) {
+		dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
+		i2c->broken_irq_mode = true;
+		return 0;
+	}
+
+	if (!time_left)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c)
+{
+	return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0;
+}
+
+static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
+{
+	/* clear ST/TS events, listen for neither */
+	octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT);
+}
+
+/*
+ * Cleanup low-level state & enable high-level controller.
+ */
+static void octeon_i2c_hlc_enable(struct octeon_i2c *i2c)
+{
+	int try = 0;
+	u64 val;
+
+	if (i2c->hlc_enabled)
+		return;
+	i2c->hlc_enabled = true;
+
+	while (1) {
+		val = octeon_i2c_ctl_read(i2c);
+		if (!(val & (TWSI_CTL_STA | TWSI_CTL_STP)))
+			break;
+
+		/* clear IFLG event */
+		if (val & TWSI_CTL_IFLG)
+			octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+		if (try++ > 100) {
+			pr_err("%s: giving up\n", __func__);
+			break;
+		}
+
+		/* spin until any start/stop has finished */
+		udelay(10);
+	}
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_CE | TWSI_CTL_AAK | TWSI_CTL_ENAB);
+}
+
+static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
+{
+	if (!i2c->hlc_enabled)
+		return;
+
+	i2c->hlc_enabled = false;
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+}
+
+/**
+ * octeon_i2c_hlc_wait - wait for an HLC operation to complete
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise -ETIMEDOUT.
+ */
+static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
+{
+	int time_left;
+
+	/*
+	 * Some cn38xx boards don't assert the irq in the interrupt
+	 * controller. So we must poll for the valid bit change.
+	 */
+	if (i2c->broken_irq_mode) {
+		u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+		while (!octeon_i2c_hlc_test_valid(i2c) &&
+		       time_before64(get_jiffies_64(), end))
+			usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
+
+		return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT;
+	}
+
+	i2c->hlc_int_enable(i2c);
+	time_left = wait_event_timeout(i2c->queue,
+				       octeon_i2c_hlc_test_valid(i2c),
+				       i2c->adap.timeout);
+	i2c->hlc_int_disable(i2c);
+	if (!time_left)
+		octeon_i2c_hlc_int_clear(i2c);
+
+	if (i2c->broken_irq_check && !time_left &&
+	    octeon_i2c_hlc_test_valid(i2c)) {
+		dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
+		i2c->broken_irq_mode = true;
+		return 0;
+	}
+
+	if (!time_left)
+		return -ETIMEDOUT;
+	return 0;
+}
+
+static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
+{
+	u8 stat;
+
+	/*
+	 * This is ugly... in HLC mode the status is not in the status register
+	 * but in the lower 8 bits of SW_TWSI.
+	 */
+	if (i2c->hlc_enabled)
+		stat = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+	else
+		stat = octeon_i2c_stat_read(i2c);
+
+	switch (stat) {
+	/* Everything is fine */
+	case STAT_IDLE:
+	case STAT_AD2W_ACK:
+	case STAT_RXADDR_ACK:
+	case STAT_TXADDR_ACK:
+	case STAT_TXDATA_ACK:
+		return 0;
+
+	/* ACK allowed on pre-terminal bytes only */
+	case STAT_RXDATA_ACK:
+		if (!final_read)
+			return 0;
+		return -EIO;
+
+	/* NAK allowed on terminal byte only */
+	case STAT_RXDATA_NAK:
+		if (final_read)
+			return 0;
+		return -EIO;
+
+	/* Arbitration lost */
+	case STAT_LOST_ARB_38:
+	case STAT_LOST_ARB_68:
+	case STAT_LOST_ARB_78:
+	case STAT_LOST_ARB_B0:
+		return -EAGAIN;
+
+	/* Being addressed as slave, should back off & listen */
+	case STAT_SLAVE_60:
+	case STAT_SLAVE_70:
+	case STAT_GENDATA_ACK:
+	case STAT_GENDATA_NAK:
+		return -EOPNOTSUPP;
+
+	/* Core busy as slave */
+	case STAT_SLAVE_80:
+	case STAT_SLAVE_88:
+	case STAT_SLAVE_A0:
+	case STAT_SLAVE_A8:
+	case STAT_SLAVE_LOST:
+	case STAT_SLAVE_NAK:
+	case STAT_SLAVE_ACK:
+		return -EOPNOTSUPP;
+
+	case STAT_TXDATA_NAK:
+	case STAT_BUS_ERROR:
+		return -EIO;
+	case STAT_TXADDR_NAK:
+	case STAT_RXADDR_NAK:
+	case STAT_AD2W_NAK:
+		return -ENXIO;
+	default:
+		dev_err(i2c->dev, "unhandled state: %d\n", stat);
+		return -EIO;
+	}
+}
+
+static int octeon_i2c_recovery(struct octeon_i2c *i2c)
+{
+	int ret;
+
+	ret = i2c_recover_bus(&i2c->adap);
+	if (ret)
+		/* recover failed, try hardware re-init */
+		ret = octeon_i2c_init_lowlevel(i2c);
+	return ret;
+}
+
+/**
+ * octeon_i2c_start - send START to the bus
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_start(struct octeon_i2c *i2c)
+{
+	int ret;
+	u8 stat;
+
+	octeon_i2c_hlc_disable(i2c);
+
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
+	ret = octeon_i2c_wait(i2c);
+	if (ret)
+		goto error;
+
+	stat = octeon_i2c_stat_read(i2c);
+	if (stat == STAT_START || stat == STAT_REP_START)
+		/* START successful, bail out */
+		return 0;
+
+error:
+	/* START failed, try to recover */
+	ret = octeon_i2c_recovery(i2c);
+	return (ret) ? ret : -EAGAIN;
+}
+
+/* send STOP to the bus */
+static void octeon_i2c_stop(struct octeon_i2c *i2c)
+{
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP);
+}
+
+/**
+ * octeon_i2c_read - receive data from the bus via low-level controller
+ * @i2c: The struct octeon_i2c
+ * @target: Target address
+ * @data: Pointer to the location to store the data
+ * @rlength: Length of the data
+ * @recv_len: flag for length byte
+ *
+ * The address is sent over the bus, then the data is read.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
+			   u8 *data, u16 *rlength, bool recv_len)
+{
+	int i, result, length = *rlength;
+	bool final_read = false;
+
+	octeon_i2c_data_write(i2c, (target << 1) | 1);
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+	result = octeon_i2c_wait(i2c);
+	if (result)
+		return result;
+
+	/* address OK ? */
+	result = octeon_i2c_check_status(i2c, false);
+	if (result)
+		return result;
+
+	for (i = 0; i < length; i++) {
+		/*
+		 * For the last byte to receive TWSI_CTL_AAK must not be set.
+		 *
+		 * A special case is I2C_M_RECV_LEN where we don't know the
+		 * additional length yet. If recv_len is set we assume we're
+		 * not reading the final byte and therefore need to set
+		 * TWSI_CTL_AAK.
+		 */
+		if ((i + 1 == length) && !(recv_len && i == 0))
+			final_read = true;
+
+		/* clear iflg to allow next event */
+		if (final_read)
+			octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+		else
+			octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_AAK);
+
+		result = octeon_i2c_wait(i2c);
+		if (result)
+			return result;
+
+		data[i] = octeon_i2c_data_read(i2c, &result);
+		if (result)
+			return result;
+		if (recv_len && i == 0) {
+			if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
+				return -EPROTO;
+			length += data[i];
+		}
+
+		result = octeon_i2c_check_status(i2c, final_read);
+		if (result)
+			return result;
+	}
+	*rlength = length;
+	return 0;
+}
+
+/**
+ * octeon_i2c_write - send data to the bus via low-level controller
+ * @i2c: The struct octeon_i2c
+ * @target: Target address
+ * @data: Pointer to the data to be sent
+ * @length: Length of the data
+ *
+ * The address is sent over the bus, then the data.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
+			    const u8 *data, int length)
+{
+	int i, result;
+
+	octeon_i2c_data_write(i2c, target << 1);
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+	result = octeon_i2c_wait(i2c);
+	if (result)
+		return result;
+
+	for (i = 0; i < length; i++) {
+		result = octeon_i2c_check_status(i2c, false);
+		if (result)
+			return result;
+
+		octeon_i2c_data_write(i2c, data[i]);
+		octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+		result = octeon_i2c_wait(i2c);
+		if (result)
+			return result;
+	}
+
+	return 0;
+}
+
+/* high-level-controller pure read of up to 8 bytes */
+static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+	int i, j, ret = 0;
+	u64 cmd;
+
+	octeon_i2c_hlc_enable(i2c);
+	octeon_i2c_hlc_int_clear(i2c);
+
+	cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+	/* SIZE */
+	cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
+	/* A */
+	cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+	if (msgs[0].flags & I2C_M_TEN)
+		cmd |= SW_TWSI_OP_10;
+	else
+		cmd |= SW_TWSI_OP_7;
+
+	octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
+	ret = octeon_i2c_hlc_wait(i2c);
+	if (ret)
+		goto err;
+
+	cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+	if ((cmd & SW_TWSI_R) == 0)
+		return octeon_i2c_check_status(i2c, false);
+
+	for (i = 0, j = msgs[0].len - 1; i  < msgs[0].len && i < 4; i++, j--)
+		msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
+
+	if (msgs[0].len > 4) {
+		cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c));
+		for (i = 0; i  < msgs[0].len - 4 && i < 4; i++, j--)
+			msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
+	}
+
+err:
+	return ret;
+}
+
+/* high-level-controller pure write of up to 8 bytes */
+static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+	int i, j, ret = 0;
+	u64 cmd;
+
+	octeon_i2c_hlc_enable(i2c);
+	octeon_i2c_hlc_int_clear(i2c);
+
+	cmd = SW_TWSI_V | SW_TWSI_SOVR;
+	/* SIZE */
+	cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
+	/* A */
+	cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+	if (msgs[0].flags & I2C_M_TEN)
+		cmd |= SW_TWSI_OP_10;
+	else
+		cmd |= SW_TWSI_OP_7;
+
+	for (i = 0, j = msgs[0].len - 1; i  < msgs[0].len && i < 4; i++, j--)
+		cmd |= (u64)msgs[0].buf[j] << (8 * i);
+
+	if (msgs[0].len > 4) {
+		u64 ext = 0;
+
+		for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
+			ext |= (u64)msgs[0].buf[j] << (8 * i);
+		octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
+	}
+
+	octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
+	ret = octeon_i2c_hlc_wait(i2c);
+	if (ret)
+		goto err;
+
+	cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+	if ((cmd & SW_TWSI_R) == 0)
+		return octeon_i2c_check_status(i2c, false);
+
+err:
+	return ret;
+}
+
+/* high-level-controller composite write+read, msg0=addr, msg1=data */
+static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+	int i, j, ret = 0;
+	u64 cmd;
+
+	octeon_i2c_hlc_enable(i2c);
+
+	cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+	/* SIZE */
+	cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
+	/* A */
+	cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+	if (msgs[0].flags & I2C_M_TEN)
+		cmd |= SW_TWSI_OP_10_IA;
+	else
+		cmd |= SW_TWSI_OP_7_IA;
+
+	if (msgs[0].len == 2) {
+		u64 ext = 0;
+
+		cmd |= SW_TWSI_EIA;
+		ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+		cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
+		octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
+	} else {
+		cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+	}
+
+	octeon_i2c_hlc_int_clear(i2c);
+	octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
+
+	ret = octeon_i2c_hlc_wait(i2c);
+	if (ret)
+		goto err;
+
+	cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+	if ((cmd & SW_TWSI_R) == 0)
+		return octeon_i2c_check_status(i2c, false);
+
+	for (i = 0, j = msgs[1].len - 1; i  < msgs[1].len && i < 4; i++, j--)
+		msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
+
+	if (msgs[1].len > 4) {
+		cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c));
+		for (i = 0; i  < msgs[1].len - 4 && i < 4; i++, j--)
+			msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
+	}
+
+err:
+	return ret;
+}
+
+/* high-level-controller composite write+write, m[0]len<=2, m[1]len<=8 */
+static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+	bool set_ext = false;
+	int i, j, ret = 0;
+	u64 cmd, ext = 0;
+
+	octeon_i2c_hlc_enable(i2c);
+
+	cmd = SW_TWSI_V | SW_TWSI_SOVR;
+	/* SIZE */
+	cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
+	/* A */
+	cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+	if (msgs[0].flags & I2C_M_TEN)
+		cmd |= SW_TWSI_OP_10_IA;
+	else
+		cmd |= SW_TWSI_OP_7_IA;
+
+	if (msgs[0].len == 2) {
+		cmd |= SW_TWSI_EIA;
+		ext |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+		set_ext = true;
+		cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
+	} else {
+		cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+	}
+
+	for (i = 0, j = msgs[1].len - 1; i  < msgs[1].len && i < 4; i++, j--)
+		cmd |= (u64)msgs[1].buf[j] << (8 * i);
+
+	if (msgs[1].len > 4) {
+		for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--)
+			ext |= (u64)msgs[1].buf[j] << (8 * i);
+		set_ext = true;
+	}
+	if (set_ext)
+		octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
+
+	octeon_i2c_hlc_int_clear(i2c);
+	octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
+
+	ret = octeon_i2c_hlc_wait(i2c);
+	if (ret)
+		goto err;
+
+	cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+	if ((cmd & SW_TWSI_R) == 0)
+		return octeon_i2c_check_status(i2c, false);
+
+err:
+	return ret;
+}
+
+/**
+ * octeon_i2c_xfer - The driver's master_xfer function
+ * @adap: Pointer to the i2c_adapter structure
+ * @msgs: Pointer to the messages to be processed
+ * @num: Length of the MSGS array
+ *
+ * Returns the number of messages processed, or a negative errno on failure.
+ */
+int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+	int i, ret = 0;
+
+	if (num == 1) {
+		if (msgs[0].len > 0 && msgs[0].len <= 8) {
+			if (msgs[0].flags & I2C_M_RD)
+				ret = octeon_i2c_hlc_read(i2c, msgs);
+			else
+				ret = octeon_i2c_hlc_write(i2c, msgs);
+			goto out;
+		}
+	} else if (num == 2) {
+		if ((msgs[0].flags & I2C_M_RD) == 0 &&
+		    (msgs[1].flags & I2C_M_RECV_LEN) == 0 &&
+		    msgs[0].len > 0 && msgs[0].len <= 2 &&
+		    msgs[1].len > 0 && msgs[1].len <= 8 &&
+		    msgs[0].addr == msgs[1].addr) {
+			if (msgs[1].flags & I2C_M_RD)
+				ret = octeon_i2c_hlc_comp_read(i2c, msgs);
+			else
+				ret = octeon_i2c_hlc_comp_write(i2c, msgs);
+			goto out;
+		}
+	}
+
+	for (i = 0; ret == 0 && i < num; i++) {
+		struct i2c_msg *pmsg = &msgs[i];
+
+		/* zero-length messages are not supported */
+		if (!pmsg->len) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		ret = octeon_i2c_start(i2c);
+		if (ret)
+			return ret;
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
+					      &pmsg->len, pmsg->flags & I2C_M_RECV_LEN);
+		else
+			ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
+					       pmsg->len);
+	}
+	octeon_i2c_stop(i2c);
+out:
+	return (ret != 0) ? ret : num;
+}
+
+/* calculate and set clock divisors */
+void octeon_i2c_set_clock(struct octeon_i2c *i2c)
+{
+	int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
+	int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
+
+	for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
+		/*
+		 * An mdiv value of less than 2 seems to not work well
+		 * with ds1337 RTCs, so we constrain it to larger values.
+		 */
+		for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
+			/*
+			 * For given ndiv and mdiv values check the
+			 * two closest thp values.
+			 */
+			tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
+			tclk *= (1 << ndiv_idx);
+			thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+
+			for (inc = 0; inc <= 1; inc++) {
+				thp_idx = thp_base + inc;
+				if (thp_idx < 5 || thp_idx > 0xff)
+					continue;
+
+				foscl = i2c->sys_freq / (2 * (thp_idx + 1));
+				foscl = foscl / (1 << ndiv_idx);
+				foscl = foscl / (mdiv_idx + 1) / 10;
+				diff = abs(foscl - i2c->twsi_freq);
+				if (diff < delta_hz) {
+					delta_hz = diff;
+					thp = thp_idx;
+					mdiv = mdiv_idx;
+					ndiv = ndiv_idx;
+				}
+			}
+		}
+	}
+	octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+}
+
+int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
+{
+	u8 status = 0;
+	int tries;
+
+	/* reset controller */
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+
+	for (tries = 10; tries && status != STAT_IDLE; tries--) {
+		udelay(1);
+		status = octeon_i2c_stat_read(i2c);
+		if (status == STAT_IDLE)
+			break;
+	}
+
+	if (status != STAT_IDLE) {
+		dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n",
+			__func__, status);
+		return -EIO;
+	}
+
+	/* toggle twice to force both teardowns */
+	octeon_i2c_hlc_enable(i2c);
+	octeon_i2c_hlc_disable(i2c);
+	return 0;
+}
+
+static int octeon_i2c_get_scl(struct i2c_adapter *adap)
+{
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+	u64 state;
+
+	state = octeon_i2c_read_int(i2c);
+	return state & TWSI_INT_SCL;
+}
+
+static void octeon_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+	octeon_i2c_write_int(i2c, val ? 0 : TWSI_INT_SCL_OVR);
+}
+
+static int octeon_i2c_get_sda(struct i2c_adapter *adap)
+{
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+	u64 state;
+
+	state = octeon_i2c_read_int(i2c);
+	return state & TWSI_INT_SDA;
+}
+
+static void octeon_i2c_prepare_recovery(struct i2c_adapter *adap)
+{
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+	octeon_i2c_hlc_disable(i2c);
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+	/* wait for software reset to settle */
+	udelay(5);
+
+	/*
+	 * Bring control register to a good state regardless
+	 * of HLC state.
+	 */
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+	octeon_i2c_write_int(i2c, 0);
+}
+
+static void octeon_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+	/*
+	 * Generate STOP to finish the unfinished transaction.
+	 * Can't generate STOP via the TWSI CTL register
+	 * since it could bring the TWSI controller into an inoperable state.
+	 */
+	octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR | TWSI_INT_SCL_OVR);
+	udelay(5);
+	octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR);
+	udelay(5);
+	octeon_i2c_write_int(i2c, 0);
+}
+
+struct i2c_bus_recovery_info octeon_i2c_recovery_info = {
+	.recover_bus = i2c_generic_scl_recovery,
+	.get_scl = octeon_i2c_get_scl,
+	.set_scl = octeon_i2c_set_scl,
+	.get_sda = octeon_i2c_get_sda,
+	.prepare_recovery = octeon_i2c_prepare_recovery,
+	.unprepare_recovery = octeon_i2c_unprepare_recovery,
+};
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-octeon-core.h
+++ linux-4.4.0/drivers/i2c/busses/i2c-octeon-core.h
@@ -0,0 +1,222 @@
+#include <linux/atomic.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/* Controller command patterns */
+#define SW_TWSI_V		BIT_ULL(63)	/* Valid bit */
+#define SW_TWSI_EIA		BIT_ULL(61)	/* Extended internal address */
+#define SW_TWSI_R		BIT_ULL(56)	/* Result or read bit */
+#define SW_TWSI_SOVR		BIT_ULL(55)	/* Size override */
+#define SW_TWSI_SIZE_SHIFT	52
+#define SW_TWSI_ADDR_SHIFT	40
+#define SW_TWSI_IA_SHIFT	32		/* Internal address */
+
+/* Controller opcode word (bits 60:57) */
+#define SW_TWSI_OP_SHIFT	57
+#define SW_TWSI_OP_7		(0ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_7_IA		(1ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10		(2ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10_IA	(3ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_TWSI_CLK	(4ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_EOP		(6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
+
+/* Controller extended opcode word (bits 34:32) */
+#define SW_TWSI_EOP_SHIFT	32
+#define SW_TWSI_EOP_TWSI_DATA	(SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CTL	(SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CLKCTL	(SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_STAT	(SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_RST	(SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
+
+/* Controller command and status bits */
+#define TWSI_CTL_CE		0x80	/* High level controller enable */
+#define TWSI_CTL_ENAB		0x40	/* Bus enable */
+#define TWSI_CTL_STA		0x20	/* Master-mode start, HW clears when done */
+#define TWSI_CTL_STP		0x10	/* Master-mode stop, HW clears when done */
+#define TWSI_CTL_IFLG		0x08	/* HW event, SW writes 0 to ACK */
+#define TWSI_CTL_AAK		0x04	/* Assert ACK */
+
+/* Status values */
+#define STAT_BUS_ERROR		0x00
+#define STAT_START		0x08
+#define STAT_REP_START		0x10
+#define STAT_TXADDR_ACK		0x18
+#define STAT_TXADDR_NAK		0x20
+#define STAT_TXDATA_ACK		0x28
+#define STAT_TXDATA_NAK		0x30
+#define STAT_LOST_ARB_38	0x38
+#define STAT_RXADDR_ACK		0x40
+#define STAT_RXADDR_NAK		0x48
+#define STAT_RXDATA_ACK		0x50
+#define STAT_RXDATA_NAK		0x58
+#define STAT_SLAVE_60		0x60
+#define STAT_LOST_ARB_68	0x68
+#define STAT_SLAVE_70		0x70
+#define STAT_LOST_ARB_78	0x78
+#define STAT_SLAVE_80		0x80
+#define STAT_SLAVE_88		0x88
+#define STAT_GENDATA_ACK	0x90
+#define STAT_GENDATA_NAK	0x98
+#define STAT_SLAVE_A0		0xA0
+#define STAT_SLAVE_A8		0xA8
+#define STAT_LOST_ARB_B0	0xB0
+#define STAT_SLAVE_LOST		0xB8
+#define STAT_SLAVE_NAK		0xC0
+#define STAT_SLAVE_ACK		0xC8
+#define STAT_AD2W_ACK		0xD0
+#define STAT_AD2W_NAK		0xD8
+#define STAT_IDLE		0xF8
+
+/* TWSI_INT values */
+#define TWSI_INT_ST_INT		BIT_ULL(0)
+#define TWSI_INT_TS_INT		BIT_ULL(1)
+#define TWSI_INT_CORE_INT	BIT_ULL(2)
+#define TWSI_INT_ST_EN		BIT_ULL(4)
+#define TWSI_INT_TS_EN		BIT_ULL(5)
+#define TWSI_INT_CORE_EN	BIT_ULL(6)
+#define TWSI_INT_SDA_OVR	BIT_ULL(8)
+#define TWSI_INT_SCL_OVR	BIT_ULL(9)
+#define TWSI_INT_SDA		BIT_ULL(10)
+#define TWSI_INT_SCL		BIT_ULL(11)
+
+#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */
+
+/* Register offsets */
+struct octeon_i2c_reg_offset {
+	unsigned int sw_twsi;
+	unsigned int twsi_int;
+	unsigned int sw_twsi_ext;
+};
+
+#define SW_TWSI(x)	(x->roff.sw_twsi)
+#define TWSI_INT(x)	(x->roff.twsi_int)
+#define SW_TWSI_EXT(x)	(x->roff.sw_twsi_ext)
+
+struct octeon_i2c {
+	wait_queue_head_t queue;
+	struct i2c_adapter adap;
+	struct octeon_i2c_reg_offset roff;
+	struct clk *clk;
+	int irq;
+	int hlc_irq;		/* For cn7890 only */
+	u32 twsi_freq;
+	int sys_freq;
+	void __iomem *twsi_base;
+	struct device *dev;
+	bool hlc_enabled;
+	bool broken_irq_mode;
+	bool broken_irq_check;
+	void (*int_enable)(struct octeon_i2c *);
+	void (*int_disable)(struct octeon_i2c *);
+	void (*hlc_int_enable)(struct octeon_i2c *);
+	void (*hlc_int_disable)(struct octeon_i2c *);
+	atomic_t int_enable_cnt;
+	atomic_t hlc_int_enable_cnt;
+#if IS_ENABLED(CONFIG_I2C_THUNDERX)
+	struct msix_entry i2c_msix;
+#endif
+	struct i2c_smbus_alert_setup alert_data;
+	struct i2c_client *ara;
+};
+
+static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
+{
+	__raw_writeq(val, addr);
+	__raw_readq(addr);	/* wait for write to land */
+}
+
+/**
+ * octeon_i2c_reg_write - write an I2C core register
+ * @i2c: The struct octeon_i2c
+ * @eop_reg: Register selector
+ * @data: Value to be written
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+{
+	int tries = 1000;
+	u64 tmp;
+
+	__raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c));
+	do {
+		tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+		if (--tries < 0)
+			return;
+	} while ((tmp & SW_TWSI_V) != 0);
+}
+
+#define octeon_i2c_ctl_write(i2c, val)					\
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val)
+#define octeon_i2c_data_write(i2c, val)					\
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val)
+
+/**
+ * octeon_i2c_reg_read - read lower bits of an I2C core register
+ * @i2c: The struct octeon_i2c
+ * @eop_reg: Register selector
+ *
+ * Returns the data.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
+				      int *error)
+{
+	int tries = 1000;
+	u64 tmp;
+
+	__raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c));
+	do {
+		tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+		if (--tries < 0) {
+			/* signal that the returned data is invalid */
+			if (error)
+				*error = -EIO;
+			return 0;
+		}
+	} while ((tmp & SW_TWSI_V) != 0);
+
+	return tmp & 0xFF;
+}
+
+#define octeon_i2c_ctl_read(i2c)					\
+	octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL)
+#define octeon_i2c_data_read(i2c, error)				\
+	octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error)
+#define octeon_i2c_stat_read(i2c)					\
+	octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL)
+
+/**
+ * octeon_i2c_read_int - read the TWSI_INT register
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns the value of the register.
+ */
+static inline u64 octeon_i2c_read_int(struct octeon_i2c *i2c)
+{
+	return __raw_readq(i2c->twsi_base + TWSI_INT(i2c));
+}
+
+/**
+ * octeon_i2c_write_int - write the TWSI_INT register
+ * @i2c: The struct octeon_i2c
+ * @data: Value to be written
+ */
+static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
+{
+	octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c));
+}
+
+/* Prototypes */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id);
+int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
+int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c);
+void octeon_i2c_set_clock(struct octeon_i2c *i2c);
+extern struct i2c_bus_recovery_info octeon_i2c_recovery_info;
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-octeon-platdrv.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-octeon-platdrv.c
@@ -0,0 +1,288 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
+ *
+ * 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/atomic.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/octeon/octeon.h>
+#include "i2c-octeon-core.h"
+
+#define DRV_NAME "i2c-octeon"
+
+/**
+ * octeon_i2c_int_enable - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
+{
+	/* clear TS/ST/IFLG events */
+	octeon_i2c_write_int(i2c, 0);
+}
+
+/**
+ * octeon_i2c_int_enable78 - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable78(struct octeon_i2c *i2c)
+{
+	atomic_inc_return(&i2c->int_enable_cnt);
+	enable_irq(i2c->irq);
+}
+
+static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq)
+{
+	int count;
+
+	/*
+	 * The interrupt can be disabled in two places, but we only
+	 * want to make the disable_irq_nosync() call once, so keep
+	 * track with the atomic variable.
+	 */
+	count = atomic_dec_if_positive(cnt);
+	if (count >= 0)
+		disable_irq_nosync(irq);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable78(struct octeon_i2c *i2c)
+{
+	__octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq);
+}
+
+/**
+ * octeon_i2c_hlc_int_enable78 - enable the ST interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c)
+{
+	atomic_inc_return(&i2c->hlc_int_enable_cnt);
+	enable_irq(i2c->hlc_irq);
+}
+
+/* disable the ST interrupt */
+static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c)
+{
+	__octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq);
+}
+
+/* HLC interrupt service routine */
+static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
+{
+	struct octeon_i2c *i2c = dev_id;
+
+	i2c->hlc_int_disable(i2c);
+	wake_up(&i2c->queue);
+
+	return IRQ_HANDLED;
+}
+
+static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_write_int(i2c, TWSI_INT_ST_EN);
+}
+
+static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm octeon_i2c_algo = {
+	.master_xfer = octeon_i2c_xfer,
+	.functionality = octeon_i2c_functionality,
+};
+
+static struct i2c_adapter octeon_i2c_ops = {
+	.owner = THIS_MODULE,
+	.name = "OCTEON adapter",
+	.algo = &octeon_i2c_algo,
+};
+
+static int octeon_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	int irq, result = 0, hlc_irq = 0;
+	struct resource *res_mem;
+	struct octeon_i2c *i2c;
+	bool cn78xx_style;
+
+	cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi");
+	if (cn78xx_style) {
+		hlc_irq = platform_get_irq(pdev, 0);
+		if (hlc_irq < 0)
+			return hlc_irq;
+
+		irq = platform_get_irq(pdev, 2);
+		if (irq < 0)
+			return irq;
+	} else {
+		/* All adaptors have an irq.  */
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0)
+			return irq;
+	}
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c) {
+		result = -ENOMEM;
+		goto out;
+	}
+	i2c->dev = &pdev->dev;
+
+	i2c->roff.sw_twsi = 0x00;
+	i2c->roff.twsi_int = 0x10;
+	i2c->roff.sw_twsi_ext = 0x18;
+
+	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem);
+	if (IS_ERR(i2c->twsi_base)) {
+		result = PTR_ERR(i2c->twsi_base);
+		goto out;
+	}
+
+	/*
+	 * "clock-rate" is a legacy binding, the official binding is
+	 * "clock-frequency".  Try the official one first and then
+	 * fall back if it doesn't exist.
+	 */
+	if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) &&
+	    of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) {
+		dev_err(i2c->dev,
+			"no I2C 'clock-rate' or 'clock-frequency' property\n");
+		result = -ENXIO;
+		goto out;
+	}
+
+	i2c->sys_freq = octeon_get_io_clock_rate();
+
+	init_waitqueue_head(&i2c->queue);
+
+	i2c->irq = irq;
+
+	if (cn78xx_style) {
+		i2c->hlc_irq = hlc_irq;
+
+		i2c->int_enable = octeon_i2c_int_enable78;
+		i2c->int_disable = octeon_i2c_int_disable78;
+		i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78;
+		i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78;
+
+		irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN);
+		irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN);
+
+		result = devm_request_irq(&pdev->dev, i2c->hlc_irq,
+					  octeon_i2c_hlc_isr78, 0,
+					  DRV_NAME, i2c);
+		if (result < 0) {
+			dev_err(i2c->dev, "failed to attach interrupt\n");
+			goto out;
+		}
+	} else {
+		i2c->int_enable = octeon_i2c_int_enable;
+		i2c->int_disable = octeon_i2c_int_disable;
+		i2c->hlc_int_enable = octeon_i2c_hlc_int_enable;
+		i2c->hlc_int_disable = octeon_i2c_int_disable;
+	}
+
+	result = devm_request_irq(&pdev->dev, i2c->irq,
+				  octeon_i2c_isr, 0, DRV_NAME, i2c);
+	if (result < 0) {
+		dev_err(i2c->dev, "failed to attach interrupt\n");
+		goto out;
+	}
+
+	if (OCTEON_IS_MODEL(OCTEON_CN38XX))
+		i2c->broken_irq_check = true;
+
+	result = octeon_i2c_init_lowlevel(i2c);
+	if (result) {
+		dev_err(i2c->dev, "init low level failed\n");
+		goto  out;
+	}
+
+	octeon_i2c_set_clock(i2c);
+
+	i2c->adap = octeon_i2c_ops;
+	i2c->adap.timeout = msecs_to_jiffies(2);
+	i2c->adap.retries = 5;
+	i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
+	i2c->adap.dev.parent = &pdev->dev;
+	i2c->adap.dev.of_node = node;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	platform_set_drvdata(pdev, i2c);
+
+	result = i2c_add_adapter(&i2c->adap);
+	if (result < 0) {
+		dev_err(i2c->dev, "failed to add adapter\n");
+		goto out;
+	}
+	dev_info(i2c->dev, "probed\n");
+	return 0;
+
+out:
+	return result;
+};
+
+static int octeon_i2c_remove(struct platform_device *pdev)
+{
+	struct octeon_i2c *i2c = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&i2c->adap);
+	return 0;
+};
+
+static const struct of_device_id octeon_i2c_match[] = {
+	{ .compatible = "cavium,octeon-3860-twsi", },
+	{ .compatible = "cavium,octeon-7890-twsi", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, octeon_i2c_match);
+
+static struct platform_driver octeon_i2c_driver = {
+	.probe		= octeon_i2c_probe,
+	.remove		= octeon_i2c_remove,
+	.driver		= {
+		.name	= DRV_NAME,
+		.of_match_table = octeon_i2c_match,
+	},
+};
+
+module_platform_driver(octeon_i2c_driver);
+
+MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-parport-light.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-parport-light.c
@@ -38,11 +38,11 @@
 static struct platform_device *pdev;
 
 static u16 base;
-module_param(base, ushort, 0);
+module_param_hw(base, ushort, ioport, 0);
 MODULE_PARM_DESC(base, "Base I/O address");
 
 static int irq;
-module_param(irq, int, 0);
+module_param_hw(irq, int, irq, 0);
 MODULE_PARM_DESC(irq, "IRQ (optional)");
 
 /* ----- Low-level parallel port access ----------------------------------- */
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-pca-isa.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-pca-isa.c
@@ -207,10 +207,10 @@
 MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
 MODULE_LICENSE("GPL");
 
-module_param(base, ulong, 0);
+module_param_hw(base, ulong, ioport, 0);
 MODULE_PARM_DESC(base, "I/O base address");
 
-module_param(irq, int, 0);
+module_param_hw(irq, int, irq, 0);
 MODULE_PARM_DESC(irq, "IRQ");
 module_param(clock, int, 0);
 MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t"
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-piix4.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-piix4.c
@@ -54,7 +54,7 @@
 #define SMBSLVDAT	(0xC + piix4_smba)
 
 /* count for request_region */
-#define SMBIOSIZE	8
+#define SMBIOSIZE	9
 
 /* PCI Address Constants */
 #define SMBBA		0x090
@@ -86,7 +86,7 @@
 /* If force_addr is set to anything different from 0, we forcibly enable
    the PIIX4 at the given address. VERY DANGEROUS! */
 static int force_addr;
-module_param (force_addr, int, 0);
+module_param_hw(force_addr, int, ioport, 0);
 MODULE_PARM_DESC(force_addr,
 		 "Forcibly enable the PIIX4 at the given address. "
 		 "EXTREMELY DANGEROUS!");
@@ -647,7 +647,8 @@
 	}
 
 	if (dev->vendor == PCI_VENDOR_ID_AMD &&
-	    dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) {
+	    (dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS ||
+	     dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) {
 		retval = piix4_setup_sb800(dev, id, 1);
 	}
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-pnx.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-pnx.c
@@ -15,7 +15,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/timer.h>
 #include <linux/completion.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-pnx.h>
@@ -98,25 +97,6 @@
 	return (timeout <= 0);
 }
 
-static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
-{
-	struct timer_list *timer = &alg_data->mif.timer;
-	unsigned long expires = msecs_to_jiffies(alg_data->timeout);
-
-	if (expires <= 1)
-		expires = 2;
-
-	del_timer_sync(timer);
-
-	dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n",
-		jiffies, expires);
-
-	timer->expires = jiffies + expires;
-	timer->data = (unsigned long)alg_data;
-
-	add_timer(timer);
-}
-
 /**
  * i2c_pnx_start - start a device
  * @slave_addr:		slave address
@@ -241,8 +221,6 @@
 				~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
 				  I2C_REG_CTL(alg_data));
 
-			del_timer_sync(&alg_data->mif.timer);
-
 			dev_dbg(&alg_data->adapter.dev,
 				"%s(): Waking up xfer routine.\n",
 				__func__);
@@ -258,8 +236,6 @@
 			~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
 			  I2C_REG_CTL(alg_data));
 
-		/* Stop timer. */
-		del_timer_sync(&alg_data->mif.timer);
 		dev_dbg(&alg_data->adapter.dev,
 			"%s(): Waking up xfer routine after zero-xfer.\n",
 			__func__);
@@ -346,8 +322,6 @@
 				 mcntrl_drmie | mcntrl_daie);
 			iowrite32(ctl, I2C_REG_CTL(alg_data));
 
-			/* Kill timer. */
-			del_timer_sync(&alg_data->mif.timer);
 			complete(&alg_data->mif.complete);
 		}
 	}
@@ -382,8 +356,6 @@
 			 mcntrl_drmie);
 		iowrite32(ctl, I2C_REG_CTL(alg_data));
 
-		/* Stop timer, to prevent timeout. */
-		del_timer_sync(&alg_data->mif.timer);
 		complete(&alg_data->mif.complete);
 	} else if (stat & mstatus_nai) {
 		/* Slave did not acknowledge, generate a STOP */
@@ -401,8 +373,6 @@
 		/* Our return value. */
 		alg_data->mif.ret = -EIO;
 
-		/* Stop timer, to prevent timeout. */
-		del_timer_sync(&alg_data->mif.timer);
 		complete(&alg_data->mif.complete);
 	} else {
 		/*
@@ -435,9 +405,8 @@
 	return IRQ_HANDLED;
 }
 
-static void i2c_pnx_timeout(unsigned long data)
+static void i2c_pnx_timeout(struct i2c_pnx_algo_data *alg_data)
 {
-	struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data;
 	u32 ctl;
 
 	dev_err(&alg_data->adapter.dev,
@@ -454,7 +423,6 @@
 	iowrite32(ctl, I2C_REG_CTL(alg_data));
 	wait_reset(alg_data);
 	alg_data->mif.ret = -EIO;
-	complete(&alg_data->mif.complete);
 }
 
 static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
@@ -496,6 +464,7 @@
 	struct i2c_msg *pmsg;
 	int rc = 0, completed = 0, i;
 	struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+	unsigned long time_left;
 	u32 stat;
 
 	dev_dbg(&alg_data->adapter.dev,
@@ -530,7 +499,6 @@
 		dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
 			__func__, alg_data->mif.mode, alg_data->mif.len);
 
-		i2c_pnx_arm_timer(alg_data);
 
 		/* initialize the completion var */
 		init_completion(&alg_data->mif.complete);
@@ -546,7 +514,10 @@
 			break;
 
 		/* Wait for completion */
-		wait_for_completion(&alg_data->mif.complete);
+		time_left = wait_for_completion_timeout(&alg_data->mif.complete,
+							alg_data->timeout);
+		if (time_left == 0)
+			i2c_pnx_timeout(alg_data);
 
 		if (!(rc = alg_data->mif.ret))
 			completed++;
@@ -639,7 +610,10 @@
 	alg_data->adapter.algo_data = alg_data;
 	alg_data->adapter.nr = pdev->id;
 
-	alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT;
+	alg_data->timeout = msecs_to_jiffies(I2C_PNX_TIMEOUT_DEFAULT);
+	if (alg_data->timeout <= 1)
+		alg_data->timeout = 2;
+
 #ifdef CONFIG_OF
 	alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
 	if (pdev->dev.of_node) {
@@ -659,9 +633,6 @@
 	if (IS_ERR(alg_data->clk))
 		return PTR_ERR(alg_data->clk);
 
-	setup_timer(&alg_data->mif.timer, i2c_pnx_timeout,
-			(unsigned long)alg_data);
-
 	snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
 		 "%s", pdev->name);
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-pxa.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-pxa.c
@@ -297,11 +297,10 @@
 	dev_err(dev, "IBMR: %08x IDBR: %08x ICR: %08x ISR: %08x\n",
 		readl(_IBMR(i2c)), readl(_IDBR(i2c)), readl(_ICR(i2c)),
 		readl(_ISR(i2c)));
-	dev_dbg(dev, "log: ");
+	dev_err(dev, "log:");
 	for (i = 0; i < i2c->irqlogidx; i++)
-		pr_debug("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]);
-
-	pr_debug("\n");
+		pr_cont(" [%03x:%05x]", i2c->isrlog[i], i2c->icrlog[i]);
+	pr_cont("\n");
 }
 
 #else /* ifdef DEBUG */
@@ -691,11 +690,9 @@
 {
 	u32 icr;
 
-	/*
-	 * Clear the STOP and ACK flags
-	 */
+	/* Clear the START, STOP, ACK, TB and MA flags */
 	icr = readl(_ICR(i2c));
-	icr &= ~(ICR_STOP | ICR_ACKNAK);
+	icr &= ~(ICR_START | ICR_STOP | ICR_ACKNAK | ICR_TB | ICR_MA);
 	writel(icr, _ICR(i2c));
 }
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-qup.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-qup.c
@@ -727,7 +727,8 @@
 #ifdef CONFIG_PM_SLEEP
 static int qup_i2c_suspend(struct device *device)
 {
-	qup_i2c_pm_suspend_runtime(device);
+	if (!pm_runtime_suspended(device))
+		return qup_i2c_pm_suspend_runtime(device);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-rcar.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-rcar.c
@@ -33,7 +33,6 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
-#include <linux/spinlock.h>
 
 /* register offsets */
 #define ICSCR	0x00	/* slave ctrl */
@@ -84,6 +83,7 @@
 
 #define RCAR_BUS_PHASE_START	(MDBS | MIE | ESG)
 #define RCAR_BUS_PHASE_DATA	(MDBS | MIE)
+#define RCAR_BUS_MASK_DATA	(~(ESG | FSB) & 0xFF)
 #define RCAR_BUS_PHASE_STOP	(MDBS | MIE | FSB)
 
 #define RCAR_IRQ_SEND	(MNR | MAL | MST | MAT | MDE)
@@ -94,7 +94,6 @@
 #define RCAR_IRQ_ACK_RECV	(~(MAT | MDR) & 0xFF)
 
 #define ID_LAST_MSG	(1 << 0)
-#define ID_IOERROR	(1 << 1)
 #define ID_DONE		(1 << 2)
 #define ID_ARBLOST	(1 << 3)
 #define ID_NACK		(1 << 4)
@@ -108,10 +107,10 @@
 struct rcar_i2c_priv {
 	void __iomem *io;
 	struct i2c_adapter adap;
-	struct i2c_msg	*msg;
+	struct i2c_msg *msg;
+	int msgs_left;
 	struct clk *clk;
 
-	spinlock_t lock;
 	wait_queue_head_t wait;
 
 	int pos;
@@ -144,9 +143,10 @@
 {
 	/* reset master mode */
 	rcar_i2c_write(priv, ICMIER, 0);
-	rcar_i2c_write(priv, ICMCR, 0);
+	rcar_i2c_write(priv, ICMCR, MDBS);
 	rcar_i2c_write(priv, ICMSR, 0);
-	rcar_i2c_write(priv, ICMAR, 0);
+	/* start clock */
+	rcar_i2c_write(priv, ICCCR, priv->icccr);
 }
 
 static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
@@ -257,16 +257,28 @@
 {
 	int read = !!rcar_i2c_is_recv(priv);
 
+	priv->pos = 0;
+	priv->flags = 0;
+	if (priv->msgs_left == 1)
+		rcar_i2c_flags_set(priv, ID_LAST_MSG);
+
 	rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read);
 	rcar_i2c_write(priv, ICMSR, 0);
 	rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
 	rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
 }
 
+static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
+{
+	priv->msg++;
+	priv->msgs_left--;
+	rcar_i2c_prepare_msg(priv);
+}
+
 /*
  *		interrupt functions
  */
-static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
+static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
 {
 	struct i2c_msg *msg = priv->msg;
 
@@ -276,14 +288,7 @@
 	 * Do nothing
 	 */
 	if (!(msr & MDE))
-		return 0;
-
-	/*
-	 * If address transfer phase finished,
-	 * goto data phase.
-	 */
-	if (msr & MAT)
-		rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
+		return;
 
 	if (priv->pos < msg->len) {
 		/*
@@ -305,29 +310,23 @@
 		 * [ICRXTX] -> [SHIFT] -> [I2C bus]
 		 */
 
-		if (priv->flags & ID_LAST_MSG)
+		if (priv->flags & ID_LAST_MSG) {
 			/*
 			 * If current msg is the _LAST_ msg,
 			 * prepare stop condition here.
 			 * ID_DONE will be set on STOP irq.
 			 */
 			rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
-		else
-			/*
-			 * If current msg is _NOT_ last msg,
-			 * it doesn't call stop phase.
-			 * thus, there is no STOP irq.
-			 * return ID_DONE here.
-			 */
-			return ID_DONE;
+		} else {
+			rcar_i2c_next_msg(priv);
+			return;
+		}
 	}
 
 	rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND);
-
-	return 0;
 }
 
-static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
+static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
 {
 	struct i2c_msg *msg = priv->msg;
 
@@ -337,14 +336,10 @@
 	 * Do nothing
 	 */
 	if (!(msr & MDR))
-		return 0;
+		return;
 
 	if (msr & MAT) {
-		/*
-		 * Address transfer phase finished,
-		 * but, there is no data at this point.
-		 * Do nothing.
-		 */
+		/* Address transfer phase finished, but no data at this point. */
 	} else if (priv->pos < msg->len) {
 		/*
 		 * get received data
@@ -360,12 +355,11 @@
 	 */
 	if (priv->pos + 1 >= msg->len)
 		rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
-	else
-		rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
 
-	rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
-
-	return 0;
+	if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
+		rcar_i2c_next_msg(priv);
+	else
+		rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
 }
 
 static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
@@ -392,13 +386,15 @@
 			rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
 		}
 
-		rcar_i2c_write(priv, ICSSR, ~SAR & 0xff);
+		/* Clear SSR, too, because of old STOPs to other clients than us */
+		rcar_i2c_write(priv, ICSSR, ~(SAR | SSR) & 0xff);
 	}
 
 	/* master sent stop */
 	if (ssr_filtered & SSR) {
 		i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
-		rcar_i2c_write(priv, ICSIER, SAR | SSR);
+		rcar_i2c_write(priv, ICSCR, SIE | SDBS); /* clear our NACK */
+		rcar_i2c_write(priv, ICSIER, SAR);
 		rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
 	}
 
@@ -426,22 +422,21 @@
 static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
 {
 	struct rcar_i2c_priv *priv = ptr;
-	irqreturn_t result = IRQ_HANDLED;
-	u32 msr;
+	u32 msr, val;
 
-	/*-------------- spin lock -----------------*/
-	spin_lock(&priv->lock);
-
-	if (rcar_i2c_slave_irq(priv))
-		goto exit;
+	/* Clear START or STOP as soon as we can */
+	val = rcar_i2c_read(priv, ICMCR);
+	rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
 
 	msr = rcar_i2c_read(priv, ICMSR);
 
 	/* Only handle interrupts that are currently enabled */
 	msr &= rcar_i2c_read(priv, ICMIER);
 	if (!msr) {
-		result = IRQ_NONE;
-		goto exit;
+		if (rcar_i2c_slave_irq(priv))
+			return IRQ_HANDLED;
+
+		return IRQ_NONE;
 	}
 
 	/* Arbitration lost */
@@ -452,8 +447,7 @@
 
 	/* Nack */
 	if (msr & MNR) {
-		/* go to stop phase */
-		rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
+		/* HW automatically sends STOP after received NACK */
 		rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
 		rcar_i2c_flags_set(priv, ID_NACK);
 		goto out;
@@ -461,14 +455,15 @@
 
 	/* Stop */
 	if (msr & MST) {
+		priv->msgs_left--; /* The last message also made it */
 		rcar_i2c_flags_set(priv, ID_DONE);
 		goto out;
 	}
 
 	if (rcar_i2c_is_recv(priv))
-		rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
+		rcar_i2c_irq_recv(priv, msr);
 	else
-		rcar_i2c_flags_set(priv, rcar_i2c_irq_send(priv, msr));
+		rcar_i2c_irq_send(priv, msr);
 
 out:
 	if (rcar_i2c_flags_has(priv, ID_DONE)) {
@@ -477,11 +472,7 @@
 		wake_up(&priv->wait);
 	}
 
-exit:
-	spin_unlock(&priv->lock);
-	/*-------------- spin unlock -----------------*/
-
-	return result;
+	return IRQ_HANDLED;
 }
 
 static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
@@ -490,21 +481,12 @@
 {
 	struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
 	struct device *dev = rcar_i2c_priv_to_dev(priv);
-	unsigned long flags;
 	int i, ret;
-	long timeout;
+	long time_left;
 
 	pm_runtime_get_sync(dev);
 
-	/*-------------- spin lock -----------------*/
-	spin_lock_irqsave(&priv->lock, flags);
-
 	rcar_i2c_init(priv);
-	/* start clock */
-	rcar_i2c_write(priv, ICCCR, priv->icccr);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-	/*-------------- spin unlock -----------------*/
 
 	ret = rcar_i2c_bus_barrier(priv);
 	if (ret < 0)
@@ -514,48 +496,28 @@
 		/* This HW can't send STOP after address phase */
 		if (msgs[i].len == 0) {
 			ret = -EOPNOTSUPP;
-			break;
-		}
-
-		/*-------------- spin lock -----------------*/
-		spin_lock_irqsave(&priv->lock, flags);
-
-		/* init each data */
-		priv->msg	= &msgs[i];
-		priv->pos	= 0;
-		priv->flags	= 0;
-		if (i == num - 1)
-			rcar_i2c_flags_set(priv, ID_LAST_MSG);
-
-		rcar_i2c_prepare_msg(priv);
-
-		spin_unlock_irqrestore(&priv->lock, flags);
-		/*-------------- spin unlock -----------------*/
-
-		timeout = wait_event_timeout(priv->wait,
-					     rcar_i2c_flags_has(priv, ID_DONE),
-					     adap->timeout);
-		if (!timeout) {
-			ret = -ETIMEDOUT;
-			break;
-		}
-
-		if (rcar_i2c_flags_has(priv, ID_NACK)) {
-			ret = -ENXIO;
-			break;
-		}
-
-		if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
-			ret = -EAGAIN;
-			break;
-		}
-
-		if (rcar_i2c_flags_has(priv, ID_IOERROR)) {
-			ret = -EIO;
-			break;
+			goto out;
 		}
+	}
 
-		ret = i + 1; /* The number of transfer */
+	/* init data */
+	priv->msg = msgs;
+	priv->msgs_left = num;
+
+	rcar_i2c_prepare_msg(priv);
+
+	time_left = wait_event_timeout(priv->wait,
+				     rcar_i2c_flags_has(priv, ID_DONE),
+				     num * adap->timeout);
+	if (!time_left) {
+		rcar_i2c_init(priv);
+		ret = -ETIMEDOUT;
+	} else if (rcar_i2c_flags_has(priv, ID_NACK)) {
+		ret = -ENXIO;
+	} else if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
+		ret = -EAGAIN;
+	} else {
+		ret = num - priv->msgs_left; /* The number of transfer */
 	}
 out:
 	pm_runtime_put(dev);
@@ -581,7 +543,7 @@
 	priv->slave = slave;
 	rcar_i2c_write(priv, ICSAR, slave->addr);
 	rcar_i2c_write(priv, ICSSR, 0);
-	rcar_i2c_write(priv, ICSIER, SAR | SSR);
+	rcar_i2c_write(priv, ICSIER, SAR);
 	rcar_i2c_write(priv, ICSCR, SIE | SDBS);
 
 	return 0;
@@ -650,23 +612,26 @@
 		return PTR_ERR(priv->clk);
 	}
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->io = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->io))
+		return PTR_ERR(priv->io);
+
 	bus_speed = 100000; /* default 100 kHz */
 	of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
 
 	priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data;
 
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
 	ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
 	if (ret < 0)
-		return ret;
+		goto out_pm_put;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	priv->io = devm_ioremap_resource(dev, res);
-	if (IS_ERR(priv->io))
-		return PTR_ERR(priv->io);
+	pm_runtime_put(dev);
 
 	irq = platform_get_irq(pdev, 0);
 	init_waitqueue_head(&priv->wait);
-	spin_lock_init(&priv->lock);
 
 	adap = &priv->adap;
 	adap->nr = pdev->id;
@@ -682,22 +647,26 @@
 			       dev_name(dev), priv);
 	if (ret < 0) {
 		dev_err(dev, "cannot get irq %d\n", irq);
-		return ret;
+		goto out_pm_disable;
 	}
 
-	pm_runtime_enable(dev);
 	platform_set_drvdata(pdev, priv);
 
 	ret = i2c_add_numbered_adapter(adap);
 	if (ret < 0) {
 		dev_err(dev, "reg adap failed: %d\n", ret);
-		pm_runtime_disable(dev);
-		return ret;
+		goto out_pm_disable;
 	}
 
 	dev_info(dev, "probed\n");
 
 	return 0;
+
+ out_pm_put:
+	pm_runtime_put(dev);
+ out_pm_disable:
+	pm_runtime_disable(dev);
+	return ret;
 }
 
 static int rcar_i2c_remove(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-riic.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-riic.c
@@ -80,6 +80,7 @@
 #define ICIER_TEIE	0x40
 #define ICIER_RIE	0x20
 #define ICIER_NAKIE	0x10
+#define ICIER_SPIE	0x08
 
 #define ICSR2_NACKF	0x10
 
@@ -211,16 +212,20 @@
 	if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) {
 		/* We got a NACKIE */
 		readb(riic->base + RIIC_ICDRR);	/* dummy read */
+		riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2);
 		riic->err = -ENXIO;
 	} else if (riic->bytes_left) {
 		return IRQ_NONE;
 	}
 
-	if (riic->is_last || riic->err)
+	if (riic->is_last || riic->err) {
+		riic_clear_set_bit(riic, ICIER_TEIE, ICIER_SPIE, RIIC_ICIER);
 		writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
-
-	writeb(0, riic->base + RIIC_ICIER);
-	complete(&riic->msg_done);
+	} else {
+		/* Transfer is complete, but do not send STOP */
+		riic_clear_set_bit(riic, ICIER_TEIE, 0, RIIC_ICIER);
+		complete(&riic->msg_done);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -240,13 +245,13 @@
 
 	if (riic->bytes_left == 1) {
 		/* STOP must come before we set ACKBT! */
-		if (riic->is_last)
+		if (riic->is_last) {
+			riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER);
 			writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
+		}
 
 		riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3);
 
-		writeb(0, riic->base + RIIC_ICIER);
-		complete(&riic->msg_done);
 	} else {
 		riic_clear_set_bit(riic, ICMR3_ACKBT, 0, RIIC_ICMR3);
 	}
@@ -259,6 +264,21 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t riic_stop_isr(int irq, void *data)
+{
+	struct riic_dev *riic = data;
+
+	/* read back registers to confirm writes have fully propagated */
+	writeb(0, riic->base + RIIC_ICSR2);
+	readb(riic->base + RIIC_ICSR2);
+	writeb(0, riic->base + RIIC_ICIER);
+	readb(riic->base + RIIC_ICIER);
+
+	complete(&riic->msg_done);
+
+	return IRQ_HANDLED;
+}
+
 static u32 riic_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -326,6 +346,7 @@
 	{ .res_num = 0, .isr = riic_tend_isr, .name = "riic-tend" },
 	{ .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" },
 	{ .res_num = 2, .isr = riic_tdre_isr, .name = "riic-tdre" },
+	{ .res_num = 3, .isr = riic_stop_isr, .name = "riic-stop" },
 	{ .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" },
 };
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-scmi.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-scmi.c
@@ -18,6 +18,9 @@
 #define ACPI_SMBUS_HC_CLASS		"smbus"
 #define ACPI_SMBUS_HC_DEVICE_NAME	"cmi"
 
+/* SMBUS HID definition as supported by Microsoft Windows */
+#define ACPI_SMBUS_MS_HID		"SMB0001"
+
 ACPI_MODULE_NAME("smbus_cmi");
 
 struct smbus_methods_t {
@@ -51,6 +54,7 @@
 static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
 	{"SMBUS01", (kernel_ulong_t)&smbus_methods},
 	{ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
+	{ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods},
 	{"", 0}
 };
 MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
@@ -148,6 +152,7 @@
 			mt_params[3].type = ACPI_TYPE_INTEGER;
 			mt_params[3].integer.value = len;
 			mt_params[4].type = ACPI_TYPE_BUFFER;
+			mt_params[4].buffer.length = len;
 			mt_params[4].buffer.pointer = data->block + 1;
 		}
 		break;
@@ -359,6 +364,7 @@
 {
 	struct acpi_smbus_cmi *smbus_cmi;
 	const struct acpi_device_id *id;
+	int ret;
 
 	smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
 	if (!smbus_cmi)
@@ -380,8 +386,10 @@
 	acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
 			    acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
 
-	if (smbus_cmi->cap_info == 0)
+	if (smbus_cmi->cap_info == 0) {
+		ret = -ENODEV;
 		goto err;
+	}
 
 	snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
 		"SMBus CMI adapter %s",
@@ -392,7 +400,8 @@
 	smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
 	smbus_cmi->adapter.dev.parent = &device->dev;
 
-	if (i2c_add_adapter(&smbus_cmi->adapter)) {
+	ret = i2c_add_adapter(&smbus_cmi->adapter);
+	if (ret) {
 		dev_err(&device->dev, "Couldn't register adapter!\n");
 		goto err;
 	}
@@ -402,7 +411,7 @@
 err:
 	kfree(smbus_cmi);
 	device->driver_data = NULL;
-	return -EIO;
+	return ret;
 }
 
 static int acpi_smbus_cmi_remove(struct acpi_device *device)
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-sis5595.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-sis5595.c
@@ -119,7 +119,7 @@
 /* If force_addr is set to anything different from 0, we forcibly enable
    the device at the given address. */
 static u16 force_addr;
-module_param(force_addr, ushort, 0);
+module_param_hw(force_addr, ushort, ioport, 0);
 MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller");
 
 static struct pci_driver sis5595_driver;
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-st.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-st.c
@@ -399,6 +399,7 @@
 /**
  * st_i2c_rd_fill_tx_fifo() - Fill the Tx FIFO in read mode
  * @i2c_dev: Controller's private data
+ * @max: Maximum amount of data to fill into the Tx FIFO
  *
  * This functions fills the Tx FIFO with fixed pattern when
  * in read mode to trigger clock.
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-tegra.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-tegra.c
@@ -696,7 +696,7 @@
 /* payload size is only 12 bit */
 static struct i2c_adapter_quirks tegra_i2c_quirks = {
 	.max_read_len = 4096,
-	.max_write_len = 4096,
+	.max_write_len = 4096 - 12,
 };
 
 static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-thunderx-pcidrv.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-thunderx-pcidrv.c
@@ -0,0 +1,260 @@
+/*
+ * Cavium ThunderX i2c driver.
+ *
+ * Copyright (C) 2015,2016 Cavium Inc.
+ * Authors: Fred Martin <fmartin@caviumnetworks.com>
+ *	    Jan Glauber <jglauber@cavium.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/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+
+#include "i2c-octeon-core.h"
+
+#define DRV_NAME "i2c-thunderx"
+
+#define PCI_DEVICE_ID_THUNDER_TWSI	0xa012
+
+#define SYS_FREQ_DEFAULT		700000000
+
+#define TWSI_INT_ENA_W1C		0x1028
+#define TWSI_INT_ENA_W1S		0x1030
+
+/*
+ * Enable the CORE interrupt.
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void thunder_i2c_int_enable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_writeq_flush(TWSI_INT_CORE_INT,
+				i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+/*
+ * Disable the CORE interrupt.
+ */
+static void thunder_i2c_int_disable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_writeq_flush(TWSI_INT_CORE_INT,
+				i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+				i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+static void thunder_i2c_hlc_int_disable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+				i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static u32 thunderx_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm thunderx_i2c_algo = {
+	.master_xfer = octeon_i2c_xfer,
+	.functionality = thunderx_i2c_functionality,
+};
+
+static struct i2c_adapter thunderx_i2c_ops = {
+	.owner	= THIS_MODULE,
+	.name	= "ThunderX adapter",
+	.algo	= &thunderx_i2c_algo,
+};
+
+static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c)
+{
+	int ret;
+
+	i2c->clk = clk_get(dev, NULL);
+	if (IS_ERR(i2c->clk)) {
+		i2c->clk = NULL;
+		goto skip;
+	}
+
+	ret = clk_prepare_enable(i2c->clk);
+	if (ret)
+		goto skip;
+	i2c->sys_freq = clk_get_rate(i2c->clk);
+
+skip:
+	if (!i2c->sys_freq)
+		i2c->sys_freq = SYS_FREQ_DEFAULT;
+}
+
+static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
+{
+	if (!clk)
+		return;
+	clk_disable_unprepare(clk);
+	clk_put(clk);
+}
+
+static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
+				      struct device_node *node)
+{
+	u32 type;
+
+	if (!node)
+		return -EINVAL;
+
+	i2c->alert_data.irq = irq_of_parse_and_map(node, 0);
+	if (!i2c->alert_data.irq)
+		return -EINVAL;
+
+	type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
+	i2c->alert_data.alert_edge_triggered =
+		(type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
+
+	i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
+	if (!i2c->ara)
+		return -ENODEV;
+	return 0;
+}
+
+static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
+				   struct device_node *node)
+{
+	/* TODO: ACPI support */
+	if (!acpi_disabled)
+		return -EOPNOTSUPP;
+
+	return thunder_i2c_smbus_setup_of(i2c, node);
+}
+
+static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
+{
+	if (i2c->ara)
+		i2c_unregister_device(i2c->ara);
+}
+
+static int thunder_i2c_probe_pci(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
+{
+	struct device *dev = &pdev->dev;
+	struct octeon_i2c *i2c;
+	int ret;
+
+	i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->roff.sw_twsi = 0x1000;
+	i2c->roff.twsi_int = 0x1010;
+	i2c->roff.sw_twsi_ext = 0x1018;
+
+	i2c->dev = dev;
+	pci_set_drvdata(pdev, i2c);
+	ret = pcim_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	ret = pci_request_regions(pdev, DRV_NAME);
+	if (ret)
+		return ret;
+
+	i2c->twsi_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!i2c->twsi_base)
+		return -EINVAL;
+
+	thunder_i2c_clock_enable(dev, i2c);
+	ret = device_property_read_u32(dev, "clock-frequency", &i2c->twsi_freq);
+	if (ret)
+		i2c->twsi_freq = 100000;
+
+	init_waitqueue_head(&i2c->queue);
+
+	i2c->int_enable = thunder_i2c_int_enable;
+	i2c->int_disable = thunder_i2c_int_disable;
+	i2c->hlc_int_enable = thunder_i2c_hlc_int_enable;
+	i2c->hlc_int_disable = thunder_i2c_hlc_int_disable;
+
+	ret = pci_enable_msix(pdev, &i2c->i2c_msix, 1);
+	if (ret)
+		goto error;
+
+	ret = devm_request_irq(dev, i2c->i2c_msix.vector, octeon_i2c_isr, 0,
+			       DRV_NAME, i2c);
+	if (ret)
+		goto error;
+
+	ret = octeon_i2c_init_lowlevel(i2c);
+	if (ret)
+		goto error;
+
+	octeon_i2c_set_clock(i2c);
+
+	i2c->adap = thunderx_i2c_ops;
+	i2c->adap.retries = 5;
+	i2c->adap.class = I2C_CLASS_HWMON;
+	i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
+	i2c->adap.dev.parent = dev;
+	i2c->adap.dev.of_node = pdev->dev.of_node;
+	snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+		 "Cavium ThunderX i2c adapter at %s", dev_name(dev));
+	i2c_set_adapdata(&i2c->adap, i2c);
+
+	ret = i2c_add_adapter(&i2c->adap);
+	if (ret)
+		goto error;
+
+	dev_info(i2c->dev, "Probed. Set system clock to %u\n", i2c->sys_freq);
+
+	ret = thunder_i2c_smbus_setup(i2c, pdev->dev.of_node);
+	if (ret)
+		dev_info(dev, "SMBUS alert not active on this bus\n");
+
+	return 0;
+
+error:
+	thunder_i2c_clock_disable(dev, i2c->clk);
+	return ret;
+}
+
+static void thunder_i2c_remove_pci(struct pci_dev *pdev)
+{
+	struct octeon_i2c *i2c = pci_get_drvdata(pdev);
+
+	thunder_i2c_smbus_remove(i2c);
+	thunder_i2c_clock_disable(&pdev->dev, i2c->clk);
+	i2c_del_adapter(&i2c->adap);
+}
+
+static const struct pci_device_id thunder_i2c_pci_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_TWSI) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, thunder_i2c_pci_id_table);
+
+static struct pci_driver thunder_i2c_pci_driver = {
+	.name		= DRV_NAME,
+	.id_table	= thunder_i2c_pci_id_table,
+	.probe		= thunder_i2c_probe_pci,
+	.remove		= thunder_i2c_remove_pci,
+};
+
+module_pci_driver(thunder_i2c_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fred Martin <fmartin@caviumnetworks.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium ThunderX SOC");
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-tiny-usb.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-tiny-usb.c
@@ -178,22 +178,39 @@
 		    int value, int index, void *data, int len)
 {
 	struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+	void *dmadata = kmalloc(len, GFP_KERNEL);
+	int ret;
+
+	if (!dmadata)
+		return -ENOMEM;
 
 	/* do control transfer */
-	return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
+	ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
 			       cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
-			       USB_DIR_IN, value, index, data, len, 2000);
+			       USB_DIR_IN, value, index, dmadata, len, 2000);
+
+	memcpy(data, dmadata, len);
+	kfree(dmadata);
+	return ret;
 }
 
 static int usb_write(struct i2c_adapter *adapter, int cmd,
 		     int value, int index, void *data, int len)
 {
 	struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+	void *dmadata = kmemdup(data, len, GFP_KERNEL);
+	int ret;
+
+	if (!dmadata)
+		return -ENOMEM;
 
 	/* do control transfer */
-	return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
+	ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
 			       cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-			       value, index, data, len, 2000);
+			       value, index, dmadata, len, 2000);
+
+	kfree(dmadata);
+	return ret;
 }
 
 static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-uniphier-f.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-uniphier-f.c
@@ -394,11 +394,8 @@
 		return ret;
 
 	for (msg = msgs; msg < emsg; msg++) {
-		/* If next message is read, skip the stop condition */
-		bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD);
-		/* but, force it if I2C_M_STOP is set */
-		if (msg->flags & I2C_M_STOP)
-			stop = true;
+		/* Emit STOP if it is the last message or I2C_M_STOP is set. */
+		bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP);
 
 		ret = uniphier_fi2c_master_xfer_one(adap, msg, stop);
 		if (ret)
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-uniphier.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-uniphier.c
@@ -247,11 +247,8 @@
 		return ret;
 
 	for (msg = msgs; msg < emsg; msg++) {
-		/* If next message is read, skip the stop condition */
-		bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD);
-		/* but, force it if I2C_M_STOP is set */
-		if (msg->flags & I2C_M_STOP)
-			stop = true;
+		/* Emit STOP if it is the last message or I2C_M_STOP is set. */
+		bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP);
 
 		ret = uniphier_i2c_master_xfer_one(adap, msg, stop);
 		if (ret)
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-viapro.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-viapro.c
@@ -94,7 +94,7 @@
 /* If force_addr is set to anything different from 0, we forcibly enable
    the VT596 at the given address. VERY DANGEROUS! */
 static u16 force_addr;
-module_param(force_addr, ushort, 0);
+module_param_hw(force_addr, ushort, ioport, 0);
 MODULE_PARM_DESC(force_addr,
 		 "Forcibly enable the SMBus at the given address. "
 		 "EXTREMELY DANGEROUS!");
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-xgene-slimpro.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-xgene-slimpro.c
@@ -105,7 +105,7 @@
 	struct mbox_chan *mbox_chan;
 	struct mbox_client mbox_client;
 	struct completion rd_complete;
-	u8 dma_buffer[I2C_SMBUS_BLOCK_MAX];
+	u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* dma_buffer[0] is used for length */
 	u32 *resp_msg;
 };
 
--- linux-4.4.0.orig/drivers/i2c/busses/i2c-xiic.c
+++ linux-4.4.0/drivers/i2c/busses/i2c-xiic.c
@@ -533,6 +533,7 @@
 {
 	u8 rx_watermark;
 	struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
+	unsigned long flags;
 
 	/* Clear and enable Rx full interrupt. */
 	xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
@@ -548,6 +549,7 @@
 		rx_watermark = IIC_RX_FIFO_DEPTH;
 	xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1);
 
+	local_irq_save(flags);
 	if (!(msg->flags & I2C_M_NOSTART))
 		/* write the address */
 		xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
@@ -558,6 +560,8 @@
 
 	xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
 		msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
+	local_irq_restore(flags);
+
 	if (i2c->nmsgs == 1)
 		/* very last, enable bus not busy as well */
 		xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
--- linux-4.4.0.orig/drivers/i2c/busses/scx200_acb.c
+++ linux-4.4.0/drivers/i2c/busses/scx200_acb.c
@@ -42,7 +42,7 @@
 
 #define MAX_DEVICES 4
 static int base[MAX_DEVICES] = { 0x820, 0x840 };
-module_param_array(base, int, NULL, 0);
+module_param_hw_array(base, int, ioport, NULL, 0);
 MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
 
 #define POLL_TIMEOUT	(HZ/5)
--- linux-4.4.0.orig/drivers/i2c/i2c-boardinfo.c
+++ linux-4.4.0/drivers/i2c/i2c-boardinfo.c
@@ -56,9 +56,7 @@
  * The board info passed can safely be __initdata, but be careful of embedded
  * pointers (for platform_data, functions, etc) since that won't be copied.
  */
-int __init
-i2c_register_board_info(int busnum,
-	struct i2c_board_info const *info, unsigned len)
+int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
 {
 	int status;
 
--- linux-4.4.0.orig/drivers/i2c/i2c-core.c
+++ linux-4.4.0/drivers/i2c/i2c-core.c
@@ -1400,7 +1400,7 @@
 
 	if (i2c_check_addr_validity(addr, info.flags)) {
 		dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
-			info.addr, node->full_name);
+			addr, node->full_name);
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -1876,6 +1876,7 @@
 	/* add the driver to the list of i2c drivers in the driver core */
 	driver->driver.owner = owner;
 	driver->driver.bus = &i2c_bus_type;
+	INIT_LIST_HEAD(&driver->clients);
 
 	/* When registration returns, the driver core
 	 * will have called probe() for all matching-but-unbound devices.
@@ -1886,7 +1887,6 @@
 
 	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
-	INIT_LIST_HEAD(&driver->clients);
 	/* Walk the adapters that are already present */
 	i2c_for_each_dev(driver, __process_new_driver);
 
@@ -2165,13 +2165,21 @@
  * Returns negative errno, else the number of messages executed.
  *
  * Adapter lock must be held when calling this function. No debug logging
- * takes place. adap->algo->master_xfer existence isn't checked.
+ * takes place.
  */
 int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
 	unsigned long orig_jiffies;
 	int ret, try;
 
+	if (!adap->algo->master_xfer) {
+		dev_dbg(&adap->dev, "I2C level transfers not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (WARN_ON(!msgs || num < 1))
+		return -EINVAL;
+
 	if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
 		return -EOPNOTSUPP;
 
@@ -2557,8 +2565,9 @@
 	if (!adap)
 		return;
 
-	put_device(&adap->dev);
 	module_put(adap->owner);
+	/* Should be last, otherwise we risk use-after-free with 'adap' */
+	put_device(&adap->dev);
 }
 EXPORT_SYMBOL(i2c_put_adapter);
 
@@ -2936,16 +2945,16 @@
 				   the underlying bus driver */
 		break;
 	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+			dev_err(&adapter->dev, "Invalid block %s size %d\n",
+				read_write == I2C_SMBUS_READ ? "read" : "write",
+				data->block[0]);
+			return -EINVAL;
+		}
 		if (read_write == I2C_SMBUS_READ) {
 			msg[1].len = data->block[0];
 		} else {
 			msg[0].len = data->block[0] + 1;
-			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
-				dev_err(&adapter->dev,
-					"Invalid block write size %d\n",
-					data->block[0]);
-				return -EINVAL;
-			}
 			for (i = 1; i <= data->block[0]; i++)
 				msgbuf0[i] = data->block[i];
 		}
--- linux-4.4.0.orig/drivers/i2c/i2c-dev.c
+++ linux-4.4.0/drivers/i2c/i2c-dev.c
@@ -22,6 +22,7 @@
 
 /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
 
+#include <linux/cdev.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/device.h>
@@ -46,10 +47,11 @@
 struct i2c_dev {
 	struct list_head list;
 	struct i2c_adapter *adap;
-	struct device *dev;
+	struct device dev;
+	struct cdev cdev;
 };
 
-#define I2C_MINORS	256
+#define I2C_MINORS	MINORMASK
 static LIST_HEAD(i2c_dev_list);
 static DEFINE_SPINLOCK(i2c_dev_list_lock);
 
@@ -89,12 +91,14 @@
 	return i2c_dev;
 }
 
-static void return_i2c_dev(struct i2c_dev *i2c_dev)
+static void put_i2c_dev(struct i2c_dev *i2c_dev, bool del_cdev)
 {
 	spin_lock(&i2c_dev_list_lock);
 	list_del(&i2c_dev->list);
 	spin_unlock(&i2c_dev_list_lock);
-	kfree(i2c_dev);
+	if (del_cdev)
+		cdev_device_del(&i2c_dev->cdev, &i2c_dev->dev);
+	put_device(&i2c_dev->dev);
 }
 
 static ssize_t name_show(struct device *dev,
@@ -295,6 +299,7 @@
 			    rdwr_pa[i].buf[0] < 1 ||
 			    rdwr_pa[i].len < rdwr_pa[i].buf[0] +
 					     I2C_SMBUS_BLOCK_MAX) {
+				i++;
 				res = -EINVAL;
 				break;
 			}
@@ -329,7 +334,7 @@
 		unsigned long arg)
 {
 	struct i2c_smbus_ioctl_data data_arg;
-	union i2c_smbus_data temp;
+	union i2c_smbus_data temp = {};
 	int datasize, res;
 
 	if (copy_from_user(&data_arg,
@@ -459,9 +464,15 @@
 		return i2cdev_ioctl_smbus(client, arg);
 
 	case I2C_RETRIES:
+		if (arg > INT_MAX)
+			return -EINVAL;
+
 		client->adapter->retries = arg;
 		break;
 	case I2C_TIMEOUT:
+		if (arg > INT_MAX)
+			return -EINVAL;
+
 		/* For historical reasons, user-space sets the timeout
 		 * value in units of 10 ms.
 		 */
@@ -483,13 +494,8 @@
 	unsigned int minor = iminor(inode);
 	struct i2c_client *client;
 	struct i2c_adapter *adap;
-	struct i2c_dev *i2c_dev;
-
-	i2c_dev = i2c_dev_get_by_minor(minor);
-	if (!i2c_dev)
-		return -ENODEV;
 
-	adap = i2c_get_adapter(i2c_dev->adap->nr);
+	adap = i2c_get_adapter(minor);
 	if (!adap)
 		return -ENODEV;
 
@@ -538,6 +544,14 @@
 
 static struct class *i2c_dev_class;
 
+static void i2cdev_dev_release(struct device *dev)
+{
+	struct i2c_dev *i2c_dev;
+
+	i2c_dev = container_of(dev, struct i2c_dev, dev);
+	kfree(i2c_dev);
+}
+
 static int i2cdev_attach_adapter(struct device *dev, void *dummy)
 {
 	struct i2c_adapter *adap;
@@ -552,21 +566,25 @@
 	if (IS_ERR(i2c_dev))
 		return PTR_ERR(i2c_dev);
 
-	/* register this i2c device with the driver core */
-	i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
-				     MKDEV(I2C_MAJOR, adap->nr), NULL,
-				     "i2c-%d", adap->nr);
-	if (IS_ERR(i2c_dev->dev)) {
-		res = PTR_ERR(i2c_dev->dev);
-		goto error;
+	cdev_init(&i2c_dev->cdev, &i2cdev_fops);
+	i2c_dev->cdev.owner = THIS_MODULE;
+
+	device_initialize(&i2c_dev->dev);
+	i2c_dev->dev.devt = MKDEV(I2C_MAJOR, adap->nr);
+	i2c_dev->dev.class = i2c_dev_class;
+	i2c_dev->dev.parent = &adap->dev;
+	i2c_dev->dev.release = i2cdev_dev_release;
+	dev_set_name(&i2c_dev->dev, "i2c-%d", adap->nr);
+
+	res = cdev_device_add(&i2c_dev->cdev, &i2c_dev->dev);
+	if (res) {
+		put_i2c_dev(i2c_dev, false);
+		return res;
 	}
 
 	pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
 		 adap->name, adap->nr);
 	return 0;
-error:
-	return_i2c_dev(i2c_dev);
-	return res;
 }
 
 static int i2cdev_detach_adapter(struct device *dev, void *dummy)
@@ -582,8 +600,7 @@
 	if (!i2c_dev) /* attach_adapter must have failed */
 		return 0;
 
-	return_i2c_dev(i2c_dev);
-	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+	put_i2c_dev(i2c_dev, true);
 
 	pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
 	return 0;
@@ -620,7 +637,7 @@
 
 	printk(KERN_INFO "i2c /dev entries driver\n");
 
-	res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
+	res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c");
 	if (res)
 		goto out;
 
@@ -644,7 +661,7 @@
 out_unreg_class:
 	class_destroy(i2c_dev_class);
 out_unreg_chrdev:
-	unregister_chrdev(I2C_MAJOR, "i2c");
+	unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
 out:
 	printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
 	return res;
@@ -655,7 +672,7 @@
 	bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
 	i2c_for_each_dev(NULL, i2cdev_detach_adapter);
 	class_destroy(i2c_dev_class);
-	unregister_chrdev(I2C_MAJOR, "i2c");
+	unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
--- linux-4.4.0.orig/drivers/i2c/muxes/Kconfig
+++ linux-4.4.0/drivers/i2c/muxes/Kconfig
@@ -63,6 +63,7 @@
 
 config I2C_MUX_REG
 	tristate "Register-based I2C multiplexer"
+	depends on HAS_IOMEM
 	help
 	  If you say yes to this option, support will be included for a
 	  register based I2C multiplexer. This driver provides access to
--- linux-4.4.0.orig/drivers/i2c/muxes/i2c-mux-reg.c
+++ linux-4.4.0/drivers/i2c/muxes/i2c-mux-reg.c
@@ -150,7 +150,7 @@
 		mux->data.idle_in_use = true;
 
 	/* map address from "reg" if exists */
-	if (of_address_to_resource(np, 0, &res)) {
+	if (of_address_to_resource(np, 0, &res) == 0) {
 		mux->data.reg_size = resource_size(&res);
 		mux->data.reg = devm_ioremap_resource(&pdev->dev, &res);
 		if (IS_ERR(mux->data.reg))
--- linux-4.4.0.orig/drivers/ide/cmd64x.c
+++ linux-4.4.0/drivers/ide/cmd64x.c
@@ -65,6 +65,9 @@
 	struct ide_timing t;
 	u8 arttim = 0;
 
+	if (drive->dn >= ARRAY_SIZE(drwtim_regs))
+		return;
+
 	ide_timing_compute(drive, mode, &t, T, 0);
 
 	/*
--- linux-4.4.0.orig/drivers/ide/ide-cd.c
+++ linux-4.4.0/drivers/ide/ide-cd.c
@@ -704,7 +704,7 @@
 	struct request_queue *q = drive->queue;
 	int write = rq_data_dir(rq) == WRITE;
 	unsigned short sectors_per_frame =
-		queue_logical_block_size(q) >> SECTOR_BITS;
+		queue_logical_block_size(q) >> SECTOR_SHIFT;
 
 	ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
 				  "secs_per_frame: %u",
@@ -900,7 +900,7 @@
 	 * end up being bogus.
 	 */
 	blocklen = be32_to_cpu(capbuf.blocklen);
-	blocklen = (blocklen >> SECTOR_BITS) << SECTOR_BITS;
+	blocklen = (blocklen >> SECTOR_SHIFT) << SECTOR_SHIFT;
 	switch (blocklen) {
 	case 512:
 	case 1024:
@@ -916,7 +916,7 @@
 	}
 
 	*capacity = 1 + be32_to_cpu(capbuf.lba);
-	*sectors_per_frame = blocklen >> SECTOR_BITS;
+	*sectors_per_frame = blocklen >> SECTOR_SHIFT;
 
 	ide_debug_log(IDE_DBG_PROBE, "cap: %lu, sectors_per_frame: %lu",
 				     *capacity, *sectors_per_frame);
@@ -993,7 +993,7 @@
 	drive->probed_capacity = toc->capacity * sectors_per_frame;
 
 	blk_queue_logical_block_size(drive->queue,
-				     sectors_per_frame << SECTOR_BITS);
+				     sectors_per_frame << SECTOR_SHIFT);
 
 	/* first read just the header, so we know how long the TOC is */
 	stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
@@ -1593,6 +1593,8 @@
 	struct cdrom_info *info;
 	int rc = -ENXIO;
 
+	check_disk_change(bdev);
+
 	mutex_lock(&ide_cd_mutex);
 	info = ide_cd_get(bdev->bd_disk);
 	if (!info)
--- linux-4.4.0.orig/drivers/ide/ide-cd.h
+++ linux-4.4.0/drivers/ide/ide-cd.h
@@ -20,11 +20,7 @@
 
 /************************************************************************/
 
-#define SECTOR_BITS 		9
-#ifndef SECTOR_SIZE
-#define SECTOR_SIZE		(1 << SECTOR_BITS)
-#endif
-#define SECTORS_PER_FRAME	(CD_FRAMESIZE >> SECTOR_BITS)
+#define SECTORS_PER_FRAME	(CD_FRAMESIZE >> SECTOR_SHIFT)
 #define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
 
 /* Capabilities Page size including 8 bytes of Mode Page Header */
--- linux-4.4.0.orig/drivers/ide/pmac.c
+++ linux-4.4.0/drivers/ide/pmac.c
@@ -920,6 +920,7 @@
 	struct device_node *root = of_find_node_by_path("/");
 	const char *model = of_get_property(root, "model", NULL);
 
+	of_node_put(root);
 	/* Get cable type from device-tree. */
 	if (cable && !strncmp(cable, "80-", 3)) {
 		/* Some drives fail to detect 80c cable in PowerBook */
--- linux-4.4.0.orig/drivers/ide/serverworks.c
+++ linux-4.4.0/drivers/ide/serverworks.c
@@ -114,6 +114,9 @@
 	struct pci_dev *dev = to_pci_dev(hwif->dev);
 	const u8 pio = drive->pio_mode - XFER_PIO_0;
 
+	if (drive->dn >= ARRAY_SIZE(drive_pci))
+		return;
+
 	pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
 
 	if (svwks_csb_check(dev)) {
@@ -140,6 +143,9 @@
 
 	u8 ultra_enable	 = 0, ultra_timing = 0, dma_timing = 0;
 
+	if (drive->dn >= ARRAY_SIZE(drive_pci2))
+		return;
+
 	pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
 	pci_read_config_byte(dev, 0x54, &ultra_enable);
 
--- linux-4.4.0.orig/drivers/idle/Kconfig
+++ linux-4.4.0/drivers/idle/Kconfig
@@ -17,6 +17,7 @@
 
 config I7300_IDLE
 	tristate "Intel chipset idle memory power saving driver"
+	depends on PCI
 	select I7300_IDLE_IOAT_CHANNEL
 	help
 	  Enable memory power savings when idle with certain Intel server
--- linux-4.4.0.orig/drivers/idle/intel_idle.c
+++ linux-4.4.0/drivers/idle/intel_idle.c
@@ -58,14 +58,16 @@
 #include <linux/tick.h>
 #include <trace/events/power.h>
 #include <linux/sched.h>
+#include <linux/sched/smt.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
 #include <asm/cpu_device_id.h>
+#include <asm/nospec-branch.h>
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
-#define INTEL_IDLE_VERSION "0.4"
+#define INTEL_IDLE_VERSION "0.4.1"
 #define PREFIX "intel_idle: "
 
 static struct cpuidle_driver intel_idle_driver = {
@@ -97,6 +99,8 @@
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
 static int intel_idle(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv, int index);
+static int intel_idle_ibrs(struct cpuidle_device *dev,
+			   struct cpuidle_driver *drv, int index);
 static void intel_idle_freeze(struct cpuidle_device *dev,
 			      struct cpuidle_driver *drv, int index);
 static int intel_idle_cpu_init(int cpu);
@@ -112,6 +116,12 @@
 #define CPUIDLE_FLAG_TLB_FLUSHED	0x10000
 
 /*
+ * Disable IBRS across idle (when KERNEL_IBRS), is exclusive vs IRQ_ENABLE
+ * above.
+ */
+#define CPUIDLE_FLAG_IBRS		BIT(16)
+
+/*
  * MWAIT takes an 8-bit "hint" in EAX "suggesting"
  * the C-state (top nibble) and sub-state (bottom nibble)
  * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc.
@@ -619,7 +629,7 @@
 	{
 		.name = "C6-SKL",
 		.desc = "MWAIT 0x20",
-		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
 		.exit_latency = 85,
 		.target_residency = 200,
 		.enter = &intel_idle,
@@ -627,7 +637,7 @@
 	{
 		.name = "C7s-SKL",
 		.desc = "MWAIT 0x33",
-		.flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
 		.exit_latency = 124,
 		.target_residency = 800,
 		.enter = &intel_idle,
@@ -635,7 +645,7 @@
 	{
 		.name = "C8-SKL",
 		.desc = "MWAIT 0x40",
-		.flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
 		.exit_latency = 200,
 		.target_residency = 800,
 		.enter = &intel_idle,
@@ -643,7 +653,7 @@
 	{
 		.name = "C9-SKL",
 		.desc = "MWAIT 0x50",
-		.flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
 		.exit_latency = 480,
 		.target_residency = 5000,
 		.enter = &intel_idle,
@@ -651,7 +661,7 @@
 	{
 		.name = "C10-SKL",
 		.desc = "MWAIT 0x60",
-		.flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
 		.exit_latency = 890,
 		.target_residency = 5000,
 		.enter = &intel_idle,
@@ -660,6 +670,35 @@
 		.enter = NULL }
 };
 
+static struct cpuidle_state skx_cstates[] = {
+	{
+		.name = "C1-SKX",
+		.desc = "MWAIT 0x00",
+		.flags = MWAIT2flg(0x00),
+		.exit_latency = 2,
+		.target_residency = 2,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.name = "C1E-SKX",
+		.desc = "MWAIT 0x01",
+		.flags = MWAIT2flg(0x01),
+		.exit_latency = 10,
+		.target_residency = 20,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.name = "C6-SKX",
+		.desc = "MWAIT 0x20",
+		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
+		.exit_latency = 133,
+		.target_residency = 600,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.enter = NULL }
+};
+
 static struct cpuidle_state atom_cstates[] = {
 	{
 		.name = "C1E-ATM",
@@ -716,6 +755,87 @@
 	{
 		.enter = NULL }
 };
+static struct cpuidle_state knl_cstates[] = {
+	{
+		.name = "C1-KNL",
+		.desc = "MWAIT 0x00",
+		.flags = MWAIT2flg(0x00),
+		.exit_latency = 1,
+		.target_residency = 2,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze },
+	{
+		.name = "C6-KNL",
+		.desc = "MWAIT 0x10",
+		.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 120,
+		.target_residency = 500,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze },
+	{
+		.enter = NULL }
+};
+
+static struct cpuidle_state bxt_cstates[] = {
+	{
+		.name = "C1-BXT",
+		.desc = "MWAIT 0x00",
+		.flags = MWAIT2flg(0x00),
+		.exit_latency = 2,
+		.target_residency = 2,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.name = "C1E-BXT",
+		.desc = "MWAIT 0x01",
+		.flags = MWAIT2flg(0x01),
+		.exit_latency = 10,
+		.target_residency = 20,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.name = "C6-BXT",
+		.desc = "MWAIT 0x20",
+		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 133,
+		.target_residency = 133,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.name = "C7s-BXT",
+		.desc = "MWAIT 0x31",
+		.flags = MWAIT2flg(0x31) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 155,
+		.target_residency = 155,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.name = "C8-BXT",
+		.desc = "MWAIT 0x40",
+		.flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 1000,
+		.target_residency = 1000,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.name = "C9-BXT",
+		.desc = "MWAIT 0x50",
+		.flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 2000,
+		.target_residency = 2000,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.name = "C10-BXT",
+		.desc = "MWAIT 0x60",
+		.flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 10000,
+		.target_residency = 10000,
+		.enter = &intel_idle,
+		.enter_freeze = intel_idle_freeze, },
+	{
+		.enter = NULL }
+};
 
 /**
  * intel_idle
@@ -754,6 +874,24 @@
 	return index;
 }
 
+static int intel_idle_ibrs(struct cpuidle_device *dev,
+			   struct cpuidle_driver *drv, int index)
+{
+	bool smt_active = sched_smt_active();
+	u64 spec_ctrl = spec_ctrl_current();
+	int ret;
+
+	if (smt_active)
+		wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
+	ret = intel_idle(dev, drv, index);
+
+	if (smt_active)
+		wrmsrl(MSR_IA32_SPEC_CTRL, spec_ctrl);
+
+	return ret;
+}
+
 /**
  * intel_idle_freeze - simplified "enter" callback routine for suspend-to-idle
  * @dev: cpuidle_device
@@ -884,12 +1022,25 @@
 	.disable_promotion_to_c1e = true,
 };
 
+static const struct idle_cpu idle_cpu_skx = {
+	.state_table = skx_cstates,
+	.disable_promotion_to_c1e = true,
+};
 
 static const struct idle_cpu idle_cpu_avn = {
 	.state_table = avn_cstates,
 	.disable_promotion_to_c1e = true,
 };
 
+static const struct idle_cpu idle_cpu_knl = {
+	.state_table = knl_cstates,
+};
+
+static const struct idle_cpu idle_cpu_bxt = {
+	.state_table = bxt_cstates,
+	.disable_promotion_to_c1e = true,
+};
+
 #define ICPU(model, cpu) \
 	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
 
@@ -921,6 +1072,11 @@
 	ICPU(0x56, idle_cpu_bdw),
 	ICPU(0x4e, idle_cpu_skl),
 	ICPU(0x5e, idle_cpu_skl),
+	ICPU(0x8e, idle_cpu_skl),
+	ICPU(0x9e, idle_cpu_skl),
+	ICPU(0x55, idle_cpu_skx),
+	ICPU(0x57, idle_cpu_knl),
+	ICPU(0x5c, idle_cpu_bxt),
 	{}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
@@ -994,36 +1150,162 @@
 }
 
 /*
- * intel_idle_state_table_update()
+ * ivt_idle_state_table_update(void)
  *
- * Update the default state_table for this CPU-id
- *
- * Currently used to access tuned IVT multi-socket targets
+ * Tune IVT multi-socket targets
  * Assumption: num_sockets == (max_package_num + 1)
  */
-void intel_idle_state_table_update(void)
+static void ivt_idle_state_table_update(void)
 {
 	/* IVT uses a different table for 1-2, 3-4, and > 4 sockets */
-	if (boot_cpu_data.x86_model == 0x3e) { /* IVT */
-		int cpu, package_num, num_sockets = 1;
+	int cpu, package_num, num_sockets = 1;
 
-		for_each_online_cpu(cpu) {
-			package_num = topology_physical_package_id(cpu);
-			if (package_num + 1 > num_sockets) {
-				num_sockets = package_num + 1;
-
-				if (num_sockets > 4) {
-					cpuidle_state_table = ivt_cstates_8s;
-					return;
-				}
+	for_each_online_cpu(cpu) {
+		package_num = topology_physical_package_id(cpu);
+		if (package_num + 1 > num_sockets) {
+			num_sockets = package_num + 1;
+
+			if (num_sockets > 4) {
+				cpuidle_state_table = ivt_cstates_8s;
+				return;
 			}
 		}
+	}
 
-		if (num_sockets > 2)
-			cpuidle_state_table = ivt_cstates_4s;
-		/* else, 1 and 2 socket systems use default ivt_cstates */
+	if (num_sockets > 2)
+		cpuidle_state_table = ivt_cstates_4s;
+
+	/* else, 1 and 2 socket systems use default ivt_cstates */
+}
+
+/*
+ * Translate IRTL (Interrupt Response Time Limit) MSR to usec
+ */
+
+static unsigned int irtl_ns_units[] = {
+	1, 32, 1024, 32768, 1048576, 33554432, 0, 0 };
+
+static unsigned long long irtl_2_usec(unsigned long long irtl)
+{
+	unsigned long long ns;
+
+	ns = irtl_ns_units[(irtl >> 10) & 0x3];
+
+	return div64_u64((irtl & 0x3FF) * ns, 1000);
+}
+/*
+ * bxt_idle_state_table_update(void)
+ *
+ * On BXT, we trust the IRTL to show the definitive maximum latency
+ * We use the same value for target_residency.
+ */
+static void bxt_idle_state_table_update(void)
+{
+	unsigned long long msr;
+
+	rdmsrl(MSR_PKGC6_IRTL, msr);
+	if (msr) {
+		unsigned int usec = irtl_2_usec(msr);
+
+		bxt_cstates[2].exit_latency = usec;
+		bxt_cstates[2].target_residency = usec;
+	}
+
+	rdmsrl(MSR_PKGC7_IRTL, msr);
+	if (msr) {
+		unsigned int usec = irtl_2_usec(msr);
+
+		bxt_cstates[3].exit_latency = usec;
+		bxt_cstates[3].target_residency = usec;
+	}
+
+	rdmsrl(MSR_PKGC8_IRTL, msr);
+	if (msr) {
+		unsigned int usec = irtl_2_usec(msr);
+
+		bxt_cstates[4].exit_latency = usec;
+		bxt_cstates[4].target_residency = usec;
+	}
+
+	rdmsrl(MSR_PKGC9_IRTL, msr);
+	if (msr) {
+		unsigned int usec = irtl_2_usec(msr);
+
+		bxt_cstates[5].exit_latency = usec;
+		bxt_cstates[5].target_residency = usec;
+	}
+
+	rdmsrl(MSR_PKGC10_IRTL, msr);
+	if (msr) {
+		unsigned int usec = irtl_2_usec(msr);
+
+		bxt_cstates[6].exit_latency = usec;
+		bxt_cstates[6].target_residency = usec;
+	}
+
+}
+/*
+ * sklh_idle_state_table_update(void)
+ *
+ * On SKL-H (model 0x5e) disable C8 and C9 if:
+ * C10 is enabled and SGX disabled
+ */
+static void sklh_idle_state_table_update(void)
+{
+	unsigned long long msr;
+	unsigned int eax, ebx, ecx, edx;
+
+
+	/* if PC10 disabled via cmdline intel_idle.max_cstate=7 or shallower */
+	if (max_cstate <= 7)
+		return;
+
+	/* if PC10 not present in CPUID.MWAIT.EDX */
+	if ((mwait_substates & (0xF << 28)) == 0)
+		return;
+
+	rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr);
+
+	/* PC10 is not enabled in PKG C-state limit */
+	if ((msr & 0xF) != 8)
+		return;
+
+	ecx = 0;
+	cpuid(7, &eax, &ebx, &ecx, &edx);
+
+	/* if SGX is present */
+	if (ebx & (1 << 2)) {
+
+		rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
+
+		/* if SGX is enabled */
+		if (msr & (1 << 18))
+			return;
+	}
+
+	skl_cstates[5].disabled = 1;	/* C8-SKL */
+	skl_cstates[6].disabled = 1;	/* C9-SKL */
+}
+/*
+ * intel_idle_state_table_update()
+ *
+ * Update the default state_table for this CPU-id
+ */
+
+static void intel_idle_state_table_update(void)
+{
+	switch (boot_cpu_data.x86_model) {
+
+	case 0x3e: /* IVT */
+		ivt_idle_state_table_update();
+		break;
+	case 0x5c: /* BXT */
+		bxt_idle_state_table_update();
+		break;
+	case 0x5e: /* SKL-H */
+		sklh_idle_state_table_update();
+		break;
 	}
-	return;
 }
 
 /*
@@ -1063,11 +1345,24 @@
 		if (num_substates == 0)
 			continue;
 
+		/* if state marked as disabled, skip it */
+		if (cpuidle_state_table[cstate].disabled != 0) {
+			pr_debug(PREFIX "state %s is disabled",
+				cpuidle_state_table[cstate].name);
+			continue;
+		}
+
+
 		if (((mwait_cstate + 1) > 2) &&
 			!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
 			mark_tsc_unstable("TSC halts in idle"
 					" states deeper than C2");
 
+		if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) &&
+		    cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) {
+			drv->states[drv->state_count].enter = intel_idle_ibrs;
+		}
+
 		drv->states[drv->state_count] =	/* structure copy */
 			cpuidle_state_table[cstate];
 
--- linux-4.4.0.orig/drivers/iio/accel/Kconfig
+++ linux-4.4.0/drivers/iio/accel/Kconfig
@@ -64,7 +64,8 @@
 	help
 	  Say yes here to build support for STMicroelectronics accelerometers:
 	  LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
-	  LIS331DLH, LSM303DL, LSM303DLM, LSM330.
+	  LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL,
+	  LNG2DM
 
 	  This driver can also be built as a module. If so, these modules
 	  will be created:
@@ -173,6 +174,7 @@
 config STK8BA50
 	tristate "Sensortek STK8BA50 3-Axis Accelerometer Driver"
 	depends on I2C
+	depends on IIO_TRIGGER
 	help
 	  Say yes here to get support for the Sensortek STK8BA50 3-axis
 	  accelerometer.
--- linux-4.4.0.orig/drivers/iio/accel/bmc150-accel-core.c
+++ linux-4.4.0/drivers/iio/accel/bmc150-accel-core.c
@@ -68,6 +68,9 @@
 #define BMC150_ACCEL_REG_PMU_BW		0x10
 #define BMC150_ACCEL_DEF_BW			125
 
+#define BMC150_ACCEL_REG_RESET			0x14
+#define BMC150_ACCEL_RESET_VAL			0xB6
+
 #define BMC150_ACCEL_REG_INT_MAP_0		0x19
 #define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE	BIT(2)
 
@@ -123,7 +126,7 @@
 #define BMC150_ACCEL_SLEEP_1_SEC		0x0F
 
 #define BMC150_ACCEL_REG_TEMP			0x08
-#define BMC150_ACCEL_TEMP_CENTER_VAL		24
+#define BMC150_ACCEL_TEMP_CENTER_VAL		23
 
 #define BMC150_ACCEL_AXIS_TO_REG(axis)	(BMC150_ACCEL_REG_XOUT_L + (axis * 2))
 #define BMC150_AUTO_SUSPEND_DELAY_MS		2000
@@ -191,11 +194,18 @@
 	struct device *dev;
 	int irq;
 	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
-	atomic_t active_intr;
 	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
 	struct mutex mutex;
 	u8 fifo_mode, watermark;
 	s16 buffer[8];
+	/*
+	 * Ensure there is sufficient space and correct alignment for
+	 * the timestamp if enabled
+	 */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 	u8 bw_bits;
 	u32 slope_dur;
 	u32 slope_thres;
@@ -486,11 +496,6 @@
 		goto out_fix_power_state;
 	}
 
-	if (state)
-		atomic_inc(&data->active_intr);
-	else
-		atomic_dec(&data->active_intr);
-
 	return 0;
 
 out_fix_power_state:
@@ -547,7 +552,7 @@
 {
 	int ret;
 	int axis = chan->scan_index;
-	unsigned int raw_val;
+	__le16 raw_val;
 
 	mutex_lock(&data->mutex);
 	ret = bmc150_accel_set_power_state(data, true);
@@ -557,14 +562,14 @@
 	}
 
 	ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis),
-			       &raw_val, 2);
+			       &raw_val, sizeof(raw_val));
 	if (ret < 0) {
 		dev_err(data->dev, "Error reading axis %d\n", axis);
 		bmc150_accel_set_power_state(data, false);
 		mutex_unlock(&data->mutex);
 		return ret;
 	}
-	*val = sign_extend32(raw_val >> chan->scan_type.shift,
+	*val = sign_extend32(le16_to_cpu(raw_val) >> chan->scan_type.shift,
 			     chan->scan_type.realbits - 1);
 	ret = bmc150_accel_set_power_state(data, false);
 	mutex_unlock(&data->mutex);
@@ -927,15 +932,16 @@
 	 * now.
 	 */
 	for (i = 0; i < count; i++) {
-		u16 sample[8];
 		int j, bit;
 
 		j = 0;
 		for_each_set_bit(bit, indio_dev->active_scan_mask,
 				 indio_dev->masklength)
-			memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
+			memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
+			       sizeof(data->scan.channels[0]));
 
-		iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
+		iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+						   tstamp);
 
 		tstamp += sample_period;
 	}
@@ -988,6 +994,7 @@
 		.realbits = (bits),					\
 		.storagebits = 16,					\
 		.shift = 16 - (bits),					\
+		.endianness = IIO_LE,					\
 	},								\
 	.event_spec = &bmc150_accel_event,				\
 	.num_event_specs = 1						\
@@ -1486,6 +1493,14 @@
 	int ret, i;
 	unsigned int val;
 
+	/*
+	 * Reset chip to get it in a known good state. A delay of 1.8ms after
+	 * reset is required according to the data sheets of supported chips.
+	 */
+	regmap_write(data->regmap, BMC150_ACCEL_REG_RESET,
+		     BMC150_ACCEL_RESET_VAL);
+	usleep_range(1800, 2500);
+
 	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val);
 	if (ret < 0) {
 		dev_err(data->dev,
@@ -1692,8 +1707,7 @@
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
 
 	mutex_lock(&data->mutex);
-	if (atomic_read(&data->active_intr))
-		bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
+	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
 	bmc150_accel_fifo_set_mode(data);
 	mutex_unlock(&data->mutex);
 
--- linux-4.4.0.orig/drivers/iio/accel/kxcjk-1013.c
+++ linux-4.4.0/drivers/iio/accel/kxcjk-1013.c
@@ -1343,6 +1343,8 @@
 
 	mutex_lock(&data->mutex);
 	ret = kxcjk1013_set_mode(data, OPERATION);
+	if (ret == 0)
+		ret = kxcjk1013_set_range(data, data->range);
 	mutex_unlock(&data->mutex);
 
 	return ret;
--- linux-4.4.0.orig/drivers/iio/accel/kxsd9.c
+++ linux-4.4.0/drivers/iio/accel/kxsd9.c
@@ -81,7 +81,7 @@
 
 	mutex_lock(&st->buf_lock);
 	ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
-	if (ret)
+	if (ret < 0)
 		goto error_ret;
 	st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C);
 	st->tx[1] = (ret & ~KXSD9_FS_MASK) | i;
@@ -160,11 +160,13 @@
 		if (ret < 0)
 			goto error_ret;
 		*val = ret;
+		ret = IIO_VAL_INT;
 		break;
 	case IIO_CHAN_INFO_SCALE:
 		ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
-		if (ret)
+		if (ret < 0)
 			goto error_ret;
+		*val = 0;
 		*val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK];
 		ret = IIO_VAL_INT_PLUS_MICRO;
 		break;
--- linux-4.4.0.orig/drivers/iio/accel/mma8452.c
+++ linux-4.4.0/drivers/iio/accel/mma8452.c
@@ -96,6 +96,12 @@
 	u8 ctrl_reg1;
 	u8 data_cfg;
 	const struct mma_chip_info *chip_info;
+
+	/* Ensure correct alignment of time stamp when present */
+	struct {
+		__be16 channels[3];
+		s64 ts __aligned(8);
+	} buffer;
 };
 
 /**
@@ -700,14 +706,13 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mma8452_data *data = iio_priv(indio_dev);
-	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
 	int ret;
 
-	ret = mma8452_read(data, (__be16 *)buffer);
+	ret = mma8452_read(data, data->buffer.channels);
 	if (ret < 0)
 		goto done;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
 					   iio_get_time_ns());
 
 done:
@@ -1006,7 +1011,7 @@
 	if (ret)
 		return ret;
 
-	indio_dev->trig = trig;
+	indio_dev->trig = iio_trigger_get(trig);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/iio/accel/st_accel.h
+++ linux-4.4.0/drivers/iio/accel/st_accel.h
@@ -14,6 +14,25 @@
 #include <linux/types.h>
 #include <linux/iio/common/st_sensors.h>
 
+enum st_accel_type {
+	LSM303DLH,
+	LSM303DLHC,
+	LIS3DH,
+	LSM330D,
+	LSM330DL,
+	LSM330DLC,
+	LIS331DLH,
+	LSM303DL,
+	LSM303DLM,
+	LSM330,
+	LSM303AGR,
+	LIS2DH12,
+	LIS3L02DQ,
+	LNG2DM,
+	ST_ACCEL_MAX,
+};
+
+#define H3LIS331DL_DRIVER_NAME		"h3lis331dl_accel"
 #define LIS3LV02DL_ACCEL_DEV_NAME	"lis3lv02dl_accel"
 #define LSM303DLHC_ACCEL_DEV_NAME	"lsm303dlhc_accel"
 #define LIS3DH_ACCEL_DEV_NAME		"lis3dh"
@@ -27,6 +46,9 @@
 #define LSM303DLM_ACCEL_DEV_NAME	"lsm303dlm_accel"
 #define LSM330_ACCEL_DEV_NAME		"lsm330_accel"
 #define LSM303AGR_ACCEL_DEV_NAME	"lsm303agr_accel"
+#define LIS2DH12_ACCEL_DEV_NAME		"lis2dh12_accel"
+#define LIS3L02DQ_ACCEL_DEV_NAME	"lis3l02dq"
+#define LNG2DM_ACCEL_DEV_NAME		"lng2dm"
 
 /**
 * struct st_sensors_platform_data - default accel platform data
--- linux-4.4.0.orig/drivers/iio/accel/st_accel_buffer.c
+++ linux-4.4.0/drivers/iio/accel/st_accel_buffer.c
@@ -91,7 +91,7 @@
 
 int st_accel_allocate_ring(struct iio_dev *indio_dev)
 {
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+	return iio_triggered_buffer_setup(indio_dev, NULL,
 		&st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
 }
 
--- linux-4.4.0.orig/drivers/iio/accel/st_accel_core.c
+++ linux-4.4.0/drivers/iio/accel/st_accel_core.c
@@ -39,139 +39,9 @@
 #define ST_ACCEL_FS_AVL_6G			6
 #define ST_ACCEL_FS_AVL_8G			8
 #define ST_ACCEL_FS_AVL_16G			16
-
-/* CUSTOM VALUES FOR SENSOR 1 */
-#define ST_ACCEL_1_WAI_EXP			0x33
-#define ST_ACCEL_1_ODR_ADDR			0x20
-#define ST_ACCEL_1_ODR_MASK			0xf0
-#define ST_ACCEL_1_ODR_AVL_1HZ_VAL		0x01
-#define ST_ACCEL_1_ODR_AVL_10HZ_VAL		0x02
-#define ST_ACCEL_1_ODR_AVL_25HZ_VAL		0x03
-#define ST_ACCEL_1_ODR_AVL_50HZ_VAL		0x04
-#define ST_ACCEL_1_ODR_AVL_100HZ_VAL		0x05
-#define ST_ACCEL_1_ODR_AVL_200HZ_VAL		0x06
-#define ST_ACCEL_1_ODR_AVL_400HZ_VAL		0x07
-#define ST_ACCEL_1_ODR_AVL_1600HZ_VAL		0x08
-#define ST_ACCEL_1_FS_ADDR			0x23
-#define ST_ACCEL_1_FS_MASK			0x30
-#define ST_ACCEL_1_FS_AVL_2_VAL			0x00
-#define ST_ACCEL_1_FS_AVL_4_VAL			0x01
-#define ST_ACCEL_1_FS_AVL_8_VAL			0x02
-#define ST_ACCEL_1_FS_AVL_16_VAL		0x03
-#define ST_ACCEL_1_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(1000)
-#define ST_ACCEL_1_FS_AVL_4_GAIN		IIO_G_TO_M_S_2(2000)
-#define ST_ACCEL_1_FS_AVL_8_GAIN		IIO_G_TO_M_S_2(4000)
-#define ST_ACCEL_1_FS_AVL_16_GAIN		IIO_G_TO_M_S_2(12000)
-#define ST_ACCEL_1_BDU_ADDR			0x23
-#define ST_ACCEL_1_BDU_MASK			0x80
-#define ST_ACCEL_1_DRDY_IRQ_ADDR		0x22
-#define ST_ACCEL_1_DRDY_IRQ_INT1_MASK		0x10
-#define ST_ACCEL_1_DRDY_IRQ_INT2_MASK		0x08
-#define ST_ACCEL_1_MULTIREAD_BIT		true
-
-/* CUSTOM VALUES FOR SENSOR 2 */
-#define ST_ACCEL_2_WAI_EXP			0x32
-#define ST_ACCEL_2_ODR_ADDR			0x20
-#define ST_ACCEL_2_ODR_MASK			0x18
-#define ST_ACCEL_2_ODR_AVL_50HZ_VAL		0x00
-#define ST_ACCEL_2_ODR_AVL_100HZ_VAL		0x01
-#define ST_ACCEL_2_ODR_AVL_400HZ_VAL		0x02
-#define ST_ACCEL_2_ODR_AVL_1000HZ_VAL		0x03
-#define ST_ACCEL_2_PW_ADDR			0x20
-#define ST_ACCEL_2_PW_MASK			0xe0
-#define ST_ACCEL_2_FS_ADDR			0x23
-#define ST_ACCEL_2_FS_MASK			0x30
-#define ST_ACCEL_2_FS_AVL_2_VAL			0X00
-#define ST_ACCEL_2_FS_AVL_4_VAL			0X01
-#define ST_ACCEL_2_FS_AVL_8_VAL			0x03
-#define ST_ACCEL_2_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(1000)
-#define ST_ACCEL_2_FS_AVL_4_GAIN		IIO_G_TO_M_S_2(2000)
-#define ST_ACCEL_2_FS_AVL_8_GAIN		IIO_G_TO_M_S_2(3900)
-#define ST_ACCEL_2_BDU_ADDR			0x23
-#define ST_ACCEL_2_BDU_MASK			0x80
-#define ST_ACCEL_2_DRDY_IRQ_ADDR		0x22
-#define ST_ACCEL_2_DRDY_IRQ_INT1_MASK		0x02
-#define ST_ACCEL_2_DRDY_IRQ_INT2_MASK		0x10
-#define ST_ACCEL_2_MULTIREAD_BIT		true
-
-/* CUSTOM VALUES FOR SENSOR 3 */
-#define ST_ACCEL_3_WAI_EXP			0x40
-#define ST_ACCEL_3_ODR_ADDR			0x20
-#define ST_ACCEL_3_ODR_MASK			0xf0
-#define ST_ACCEL_3_ODR_AVL_3HZ_VAL		0x01
-#define ST_ACCEL_3_ODR_AVL_6HZ_VAL		0x02
-#define ST_ACCEL_3_ODR_AVL_12HZ_VAL		0x03
-#define ST_ACCEL_3_ODR_AVL_25HZ_VAL		0x04
-#define ST_ACCEL_3_ODR_AVL_50HZ_VAL		0x05
-#define ST_ACCEL_3_ODR_AVL_100HZ_VAL		0x06
-#define ST_ACCEL_3_ODR_AVL_200HZ_VAL		0x07
-#define ST_ACCEL_3_ODR_AVL_400HZ_VAL		0x08
-#define ST_ACCEL_3_ODR_AVL_800HZ_VAL		0x09
-#define ST_ACCEL_3_ODR_AVL_1600HZ_VAL		0x0a
-#define ST_ACCEL_3_FS_ADDR			0x24
-#define ST_ACCEL_3_FS_MASK			0x38
-#define ST_ACCEL_3_FS_AVL_2_VAL			0X00
-#define ST_ACCEL_3_FS_AVL_4_VAL			0X01
-#define ST_ACCEL_3_FS_AVL_6_VAL			0x02
-#define ST_ACCEL_3_FS_AVL_8_VAL			0x03
-#define ST_ACCEL_3_FS_AVL_16_VAL		0x04
-#define ST_ACCEL_3_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(61)
-#define ST_ACCEL_3_FS_AVL_4_GAIN		IIO_G_TO_M_S_2(122)
-#define ST_ACCEL_3_FS_AVL_6_GAIN		IIO_G_TO_M_S_2(183)
-#define ST_ACCEL_3_FS_AVL_8_GAIN		IIO_G_TO_M_S_2(244)
-#define ST_ACCEL_3_FS_AVL_16_GAIN		IIO_G_TO_M_S_2(732)
-#define ST_ACCEL_3_BDU_ADDR			0x20
-#define ST_ACCEL_3_BDU_MASK			0x08
-#define ST_ACCEL_3_DRDY_IRQ_ADDR		0x23
-#define ST_ACCEL_3_DRDY_IRQ_INT1_MASK		0x80
-#define ST_ACCEL_3_DRDY_IRQ_INT2_MASK		0x00
-#define ST_ACCEL_3_IG1_EN_ADDR			0x23
-#define ST_ACCEL_3_IG1_EN_MASK			0x08
-#define ST_ACCEL_3_MULTIREAD_BIT		false
-
-/* CUSTOM VALUES FOR SENSOR 4 */
-#define ST_ACCEL_4_WAI_EXP			0x3a
-#define ST_ACCEL_4_ODR_ADDR			0x20
-#define ST_ACCEL_4_ODR_MASK			0x30 /* DF1 and DF0 */
-#define ST_ACCEL_4_ODR_AVL_40HZ_VAL		0x00
-#define ST_ACCEL_4_ODR_AVL_160HZ_VAL		0x01
-#define ST_ACCEL_4_ODR_AVL_640HZ_VAL		0x02
-#define ST_ACCEL_4_ODR_AVL_2560HZ_VAL		0x03
-#define ST_ACCEL_4_PW_ADDR			0x20
-#define ST_ACCEL_4_PW_MASK			0xc0
-#define ST_ACCEL_4_FS_ADDR			0x21
-#define ST_ACCEL_4_FS_MASK			0x80
-#define ST_ACCEL_4_FS_AVL_2_VAL			0X00
-#define ST_ACCEL_4_FS_AVL_6_VAL			0X01
-#define ST_ACCEL_4_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(1024)
-#define ST_ACCEL_4_FS_AVL_6_GAIN		IIO_G_TO_M_S_2(340)
-#define ST_ACCEL_4_BDU_ADDR			0x21
-#define ST_ACCEL_4_BDU_MASK			0x40
-#define ST_ACCEL_4_DRDY_IRQ_ADDR		0x21
-#define ST_ACCEL_4_DRDY_IRQ_INT1_MASK		0x04
-#define ST_ACCEL_4_MULTIREAD_BIT		true
-
-/* CUSTOM VALUES FOR SENSOR 5 */
-#define ST_ACCEL_5_WAI_EXP			0x3b
-#define ST_ACCEL_5_ODR_ADDR			0x20
-#define ST_ACCEL_5_ODR_MASK			0x80
-#define ST_ACCEL_5_ODR_AVL_100HZ_VAL		0x00
-#define ST_ACCEL_5_ODR_AVL_400HZ_VAL		0x01
-#define ST_ACCEL_5_PW_ADDR			0x20
-#define ST_ACCEL_5_PW_MASK			0x40
-#define ST_ACCEL_5_FS_ADDR			0x20
-#define ST_ACCEL_5_FS_MASK			0x20
-#define ST_ACCEL_5_FS_AVL_2_VAL			0X00
-#define ST_ACCEL_5_FS_AVL_8_VAL			0X01
-/* TODO: check these resulting gain settings, these are not in the datsheet */
-#define ST_ACCEL_5_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(18000)
-#define ST_ACCEL_5_FS_AVL_8_GAIN		IIO_G_TO_M_S_2(72000)
-#define ST_ACCEL_5_DRDY_IRQ_ADDR		0x22
-#define ST_ACCEL_5_DRDY_IRQ_INT1_MASK		0x04
-#define ST_ACCEL_5_DRDY_IRQ_INT2_MASK		0x20
-#define ST_ACCEL_5_IG1_EN_ADDR			0x21
-#define ST_ACCEL_5_IG1_EN_MASK			0x08
-#define ST_ACCEL_5_MULTIREAD_BIT		false
+#define ST_ACCEL_FS_AVL_100G			100
+#define ST_ACCEL_FS_AVL_200G			200
+#define ST_ACCEL_FS_AVL_400G			400
 
 static const struct iio_chan_spec st_accel_8bit_channels[] = {
 	ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
@@ -223,7 +93,7 @@
 
 static const struct st_sensor_settings st_accel_sensors_settings[] = {
 	{
-		.wai = ST_ACCEL_1_WAI_EXP,
+		.wai = 0x33,
 		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
 		.sensors_supported = {
 			[0] = LIS3DH_ACCEL_DEV_NAME,
@@ -232,25 +102,26 @@
 			[3] = LSM330DL_ACCEL_DEV_NAME,
 			[4] = LSM330DLC_ACCEL_DEV_NAME,
 			[5] = LSM303AGR_ACCEL_DEV_NAME,
+			[6] = LIS2DH12_ACCEL_DEV_NAME,
 		},
 		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
 		.odr = {
-			.addr = ST_ACCEL_1_ODR_ADDR,
-			.mask = ST_ACCEL_1_ODR_MASK,
+			.addr = 0x20,
+			.mask = 0xf0,
 			.odr_avl = {
-				{ 1, ST_ACCEL_1_ODR_AVL_1HZ_VAL, },
-				{ 10, ST_ACCEL_1_ODR_AVL_10HZ_VAL, },
-				{ 25, ST_ACCEL_1_ODR_AVL_25HZ_VAL, },
-				{ 50, ST_ACCEL_1_ODR_AVL_50HZ_VAL, },
-				{ 100, ST_ACCEL_1_ODR_AVL_100HZ_VAL, },
-				{ 200, ST_ACCEL_1_ODR_AVL_200HZ_VAL, },
-				{ 400, ST_ACCEL_1_ODR_AVL_400HZ_VAL, },
-				{ 1600, ST_ACCEL_1_ODR_AVL_1600HZ_VAL, },
+				{ .hz = 1, .value = 0x01, },
+				{ .hz = 10, .value = 0x02, },
+				{ .hz = 25, .value = 0x03, },
+				{ .hz = 50, .value = 0x04, },
+				{ .hz = 100, .value = 0x05, },
+				{ .hz = 200, .value = 0x06, },
+				{ .hz = 400, .value = 0x07, },
+				{ .hz = 1600, .value = 0x08, },
 			},
 		},
 		.pw = {
-			.addr = ST_ACCEL_1_ODR_ADDR,
-			.mask = ST_ACCEL_1_ODR_MASK,
+			.addr = 0x20,
+			.mask = 0xf0,
 			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
 		},
 		.enable_axis = {
@@ -258,45 +129,48 @@
 			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
 		},
 		.fs = {
-			.addr = ST_ACCEL_1_FS_ADDR,
-			.mask = ST_ACCEL_1_FS_MASK,
+			.addr = 0x23,
+			.mask = 0x30,
 			.fs_avl = {
 				[0] = {
 					.num = ST_ACCEL_FS_AVL_2G,
-					.value = ST_ACCEL_1_FS_AVL_2_VAL,
-					.gain = ST_ACCEL_1_FS_AVL_2_GAIN,
+					.value = 0x00,
+					.gain = IIO_G_TO_M_S_2(1000),
 				},
 				[1] = {
 					.num = ST_ACCEL_FS_AVL_4G,
-					.value = ST_ACCEL_1_FS_AVL_4_VAL,
-					.gain = ST_ACCEL_1_FS_AVL_4_GAIN,
+					.value = 0x01,
+					.gain = IIO_G_TO_M_S_2(2000),
 				},
 				[2] = {
 					.num = ST_ACCEL_FS_AVL_8G,
-					.value = ST_ACCEL_1_FS_AVL_8_VAL,
-					.gain = ST_ACCEL_1_FS_AVL_8_GAIN,
+					.value = 0x02,
+					.gain = IIO_G_TO_M_S_2(4000),
 				},
 				[3] = {
 					.num = ST_ACCEL_FS_AVL_16G,
-					.value = ST_ACCEL_1_FS_AVL_16_VAL,
-					.gain = ST_ACCEL_1_FS_AVL_16_GAIN,
+					.value = 0x03,
+					.gain = IIO_G_TO_M_S_2(12000),
 				},
 			},
 		},
 		.bdu = {
-			.addr = ST_ACCEL_1_BDU_ADDR,
-			.mask = ST_ACCEL_1_BDU_MASK,
+			.addr = 0x23,
+			.mask = 0x80,
 		},
 		.drdy_irq = {
-			.addr = ST_ACCEL_1_DRDY_IRQ_ADDR,
-			.mask_int1 = ST_ACCEL_1_DRDY_IRQ_INT1_MASK,
-			.mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK,
+			.addr = 0x22,
+			.mask_int1 = 0x10,
+			.mask_int2 = 0x08,
+			.addr_ihl = 0x25,
+			.mask_ihl = 0x02,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
-		.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
+		.multi_read_bit = true,
 		.bootime = 2,
 	},
 	{
-		.wai = ST_ACCEL_2_WAI_EXP,
+		.wai = 0x32,
 		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
 		.sensors_supported = {
 			[0] = LIS331DLH_ACCEL_DEV_NAME,
@@ -306,18 +180,18 @@
 		},
 		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
 		.odr = {
-			.addr = ST_ACCEL_2_ODR_ADDR,
-			.mask = ST_ACCEL_2_ODR_MASK,
+			.addr = 0x20,
+			.mask = 0x18,
 			.odr_avl = {
-				{ 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, },
-				{ 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, },
-				{ 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, },
-				{ 1000, ST_ACCEL_2_ODR_AVL_1000HZ_VAL, },
+				{ .hz = 50, .value = 0x00, },
+				{ .hz = 100, .value = 0x01, },
+				{ .hz = 400, .value = 0x02, },
+				{ .hz = 1000, .value = 0x03, },
 			},
 		},
 		.pw = {
-			.addr = ST_ACCEL_2_PW_ADDR,
-			.mask = ST_ACCEL_2_PW_MASK,
+			.addr = 0x20,
+			.mask = 0xe0,
 			.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
 			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
 		},
@@ -326,64 +200,69 @@
 			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
 		},
 		.fs = {
-			.addr = ST_ACCEL_2_FS_ADDR,
-			.mask = ST_ACCEL_2_FS_MASK,
+			.addr = 0x23,
+			.mask = 0x30,
 			.fs_avl = {
 				[0] = {
 					.num = ST_ACCEL_FS_AVL_2G,
-					.value = ST_ACCEL_2_FS_AVL_2_VAL,
-					.gain = ST_ACCEL_2_FS_AVL_2_GAIN,
+					.value = 0x00,
+					.gain = IIO_G_TO_M_S_2(1000),
 				},
 				[1] = {
 					.num = ST_ACCEL_FS_AVL_4G,
-					.value = ST_ACCEL_2_FS_AVL_4_VAL,
-					.gain = ST_ACCEL_2_FS_AVL_4_GAIN,
+					.value = 0x01,
+					.gain = IIO_G_TO_M_S_2(2000),
 				},
 				[2] = {
 					.num = ST_ACCEL_FS_AVL_8G,
-					.value = ST_ACCEL_2_FS_AVL_8_VAL,
-					.gain = ST_ACCEL_2_FS_AVL_8_GAIN,
+					.value = 0x03,
+					.gain = IIO_G_TO_M_S_2(3900),
 				},
 			},
 		},
 		.bdu = {
-			.addr = ST_ACCEL_2_BDU_ADDR,
-			.mask = ST_ACCEL_2_BDU_MASK,
+			.addr = 0x23,
+			.mask = 0x80,
 		},
 		.drdy_irq = {
-			.addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
-			.mask_int1 = ST_ACCEL_2_DRDY_IRQ_INT1_MASK,
-			.mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
+			.addr = 0x22,
+			.mask_int1 = 0x02,
+			.mask_int2 = 0x10,
+			.addr_ihl = 0x22,
+			.mask_ihl = 0x80,
+			.addr_od = 0x22,
+			.mask_od = 0x40,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
-		.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
+		.multi_read_bit = true,
 		.bootime = 2,
 	},
 	{
-		.wai = ST_ACCEL_3_WAI_EXP,
+		.wai = 0x40,
 		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
 		.sensors_supported = {
 			[0] = LSM330_ACCEL_DEV_NAME,
 		},
 		.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
 		.odr = {
-			.addr = ST_ACCEL_3_ODR_ADDR,
-			.mask = ST_ACCEL_3_ODR_MASK,
+			.addr = 0x20,
+			.mask = 0xf0,
 			.odr_avl = {
-				{ 3, ST_ACCEL_3_ODR_AVL_3HZ_VAL },
-				{ 6, ST_ACCEL_3_ODR_AVL_6HZ_VAL, },
-				{ 12, ST_ACCEL_3_ODR_AVL_12HZ_VAL, },
-				{ 25, ST_ACCEL_3_ODR_AVL_25HZ_VAL, },
-				{ 50, ST_ACCEL_3_ODR_AVL_50HZ_VAL, },
-				{ 100, ST_ACCEL_3_ODR_AVL_100HZ_VAL, },
-				{ 200, ST_ACCEL_3_ODR_AVL_200HZ_VAL, },
-				{ 400, ST_ACCEL_3_ODR_AVL_400HZ_VAL, },
-				{ 800, ST_ACCEL_3_ODR_AVL_800HZ_VAL, },
-				{ 1600, ST_ACCEL_3_ODR_AVL_1600HZ_VAL, },
+				{ .hz = 3, .value = 0x01, },
+				{ .hz = 6, .value = 0x02, },
+				{ .hz = 12, .value = 0x03, },
+				{ .hz = 25, .value = 0x04, },
+				{ .hz = 50, .value = 0x05, },
+				{ .hz = 100, .value = 0x06, },
+				{ .hz = 200, .value = 0x07, },
+				{ .hz = 400, .value = 0x08, },
+				{ .hz = 800, .value = 0x09, },
+				{ .hz = 1600, .value = 0x0a, },
 			},
 		},
 		.pw = {
-			.addr = ST_ACCEL_3_ODR_ADDR,
-			.mask = ST_ACCEL_3_ODR_MASK,
+			.addr = 0x20,
+			.mask = 0xf0,
 			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
 		},
 		.enable_axis = {
@@ -391,72 +270,75 @@
 			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
 		},
 		.fs = {
-			.addr = ST_ACCEL_3_FS_ADDR,
-			.mask = ST_ACCEL_3_FS_MASK,
+			.addr = 0x24,
+			.mask = 0x38,
 			.fs_avl = {
 				[0] = {
 					.num = ST_ACCEL_FS_AVL_2G,
-					.value = ST_ACCEL_3_FS_AVL_2_VAL,
-					.gain = ST_ACCEL_3_FS_AVL_2_GAIN,
+					.value = 0x00,
+					.gain = IIO_G_TO_M_S_2(61),
 				},
 				[1] = {
 					.num = ST_ACCEL_FS_AVL_4G,
-					.value = ST_ACCEL_3_FS_AVL_4_VAL,
-					.gain = ST_ACCEL_3_FS_AVL_4_GAIN,
+					.value = 0x01,
+					.gain = IIO_G_TO_M_S_2(122),
 				},
 				[2] = {
 					.num = ST_ACCEL_FS_AVL_6G,
-					.value = ST_ACCEL_3_FS_AVL_6_VAL,
-					.gain = ST_ACCEL_3_FS_AVL_6_GAIN,
+					.value = 0x02,
+					.gain = IIO_G_TO_M_S_2(183),
 				},
 				[3] = {
 					.num = ST_ACCEL_FS_AVL_8G,
-					.value = ST_ACCEL_3_FS_AVL_8_VAL,
-					.gain = ST_ACCEL_3_FS_AVL_8_GAIN,
+					.value = 0x03,
+					.gain = IIO_G_TO_M_S_2(244),
 				},
 				[4] = {
 					.num = ST_ACCEL_FS_AVL_16G,
-					.value = ST_ACCEL_3_FS_AVL_16_VAL,
-					.gain = ST_ACCEL_3_FS_AVL_16_GAIN,
+					.value = 0x04,
+					.gain = IIO_G_TO_M_S_2(732),
 				},
 			},
 		},
 		.bdu = {
-			.addr = ST_ACCEL_3_BDU_ADDR,
-			.mask = ST_ACCEL_3_BDU_MASK,
+			.addr = 0x20,
+			.mask = 0x08,
 		},
 		.drdy_irq = {
-			.addr = ST_ACCEL_3_DRDY_IRQ_ADDR,
-			.mask_int1 = ST_ACCEL_3_DRDY_IRQ_INT1_MASK,
-			.mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK,
+			.addr = 0x23,
+			.mask_int1 = 0x80,
+			.mask_int2 = 0x00,
+			.addr_ihl = 0x23,
+			.mask_ihl = 0x40,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 			.ig1 = {
-				.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
-				.en_mask = ST_ACCEL_3_IG1_EN_MASK,
+				.en_addr = 0x23,
+				.en_mask = 0x08,
 			},
 		},
-		.multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT,
+		.multi_read_bit = false,
 		.bootime = 2,
 	},
 	{
-		.wai = ST_ACCEL_4_WAI_EXP,
+		.wai = 0x3a,
 		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
 		.sensors_supported = {
 			[0] = LIS3LV02DL_ACCEL_DEV_NAME,
 		},
 		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
 		.odr = {
-			.addr = ST_ACCEL_4_ODR_ADDR,
-			.mask = ST_ACCEL_4_ODR_MASK,
+			.addr = 0x20,
+			.mask = 0x30, /* DF1 and DF0 */
 			.odr_avl = {
-				{ 40, ST_ACCEL_4_ODR_AVL_40HZ_VAL },
-				{ 160, ST_ACCEL_4_ODR_AVL_160HZ_VAL, },
-				{ 640, ST_ACCEL_4_ODR_AVL_640HZ_VAL, },
-				{ 2560, ST_ACCEL_4_ODR_AVL_2560HZ_VAL, },
+				{ .hz = 40, .value = 0x00, },
+				{ .hz = 160, .value = 0x01, },
+				{ .hz = 640, .value = 0x02, },
+				{ .hz = 2560, .value = 0x03, },
 			},
 		},
 		.pw = {
-			.addr = ST_ACCEL_4_PW_ADDR,
-			.mask = ST_ACCEL_4_PW_MASK,
+			.addr = 0x20,
+			.mask = 0xc0,
 			.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
 			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
 		},
@@ -465,50 +347,51 @@
 			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
 		},
 		.fs = {
-			.addr = ST_ACCEL_4_FS_ADDR,
-			.mask = ST_ACCEL_4_FS_MASK,
+			.addr = 0x21,
+			.mask = 0x80,
 			.fs_avl = {
 				[0] = {
 					.num = ST_ACCEL_FS_AVL_2G,
-					.value = ST_ACCEL_4_FS_AVL_2_VAL,
-					.gain = ST_ACCEL_4_FS_AVL_2_GAIN,
+					.value = 0x00,
+					.gain = IIO_G_TO_M_S_2(1024),
 				},
 				[1] = {
 					.num = ST_ACCEL_FS_AVL_6G,
-					.value = ST_ACCEL_4_FS_AVL_6_VAL,
-					.gain = ST_ACCEL_4_FS_AVL_6_GAIN,
+					.value = 0x01,
+					.gain = IIO_G_TO_M_S_2(340),
 				},
 			},
 		},
 		.bdu = {
-			.addr = ST_ACCEL_4_BDU_ADDR,
-			.mask = ST_ACCEL_4_BDU_MASK,
+			.addr = 0x21,
+			.mask = 0x40,
 		},
 		.drdy_irq = {
-			.addr = ST_ACCEL_4_DRDY_IRQ_ADDR,
-			.mask_int1 = ST_ACCEL_4_DRDY_IRQ_INT1_MASK,
+			.addr = 0x21,
+			.mask_int1 = 0x04,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
-		.multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT,
+		.multi_read_bit = true,
 		.bootime = 2, /* guess */
 	},
 	{
-		.wai = ST_ACCEL_5_WAI_EXP,
+		.wai = 0x3b,
 		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
 		.sensors_supported = {
 			[0] = LIS331DL_ACCEL_DEV_NAME,
 		},
 		.ch = (struct iio_chan_spec *)st_accel_8bit_channels,
 		.odr = {
-			.addr = ST_ACCEL_5_ODR_ADDR,
-			.mask = ST_ACCEL_5_ODR_MASK,
+			.addr = 0x20,
+			.mask = 0x80,
 			.odr_avl = {
-				{ 100, ST_ACCEL_5_ODR_AVL_100HZ_VAL },
-				{ 400, ST_ACCEL_5_ODR_AVL_400HZ_VAL, },
+				{ .hz = 100, .value = 0x00, },
+				{ .hz = 400, .value = 0x01, },
 			},
 		},
 		.pw = {
-			.addr = ST_ACCEL_5_PW_ADDR,
-			.mask = ST_ACCEL_5_PW_MASK,
+			.addr = 0x20,
+			.mask = 0x40,
 			.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
 			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
 		},
@@ -517,29 +400,215 @@
 			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
 		},
 		.fs = {
-			.addr = ST_ACCEL_5_FS_ADDR,
-			.mask = ST_ACCEL_5_FS_MASK,
+			.addr = 0x20,
+			.mask = 0x20,
+			/*
+			 * TODO: check these resulting gain settings, these are
+			 * not in the datsheet
+			 */
 			.fs_avl = {
 				[0] = {
 					.num = ST_ACCEL_FS_AVL_2G,
-					.value = ST_ACCEL_5_FS_AVL_2_VAL,
-					.gain = ST_ACCEL_5_FS_AVL_2_GAIN,
+					.value = 0x00,
+					.gain = IIO_G_TO_M_S_2(18000),
 				},
 				[1] = {
 					.num = ST_ACCEL_FS_AVL_8G,
-					.value = ST_ACCEL_5_FS_AVL_8_VAL,
-					.gain = ST_ACCEL_5_FS_AVL_8_GAIN,
+					.value = 0x01,
+					.gain = IIO_G_TO_M_S_2(72000),
 				},
 			},
 		},
 		.drdy_irq = {
-			.addr = ST_ACCEL_5_DRDY_IRQ_ADDR,
-			.mask_int1 = ST_ACCEL_5_DRDY_IRQ_INT1_MASK,
-			.mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK,
+			.addr = 0x22,
+			.mask_int1 = 0x04,
+			.mask_int2 = 0x20,
+			.addr_ihl = 0x22,
+			.mask_ihl = 0x80,
+			.addr_od = 0x22,
+			.mask_od = 0x40,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
-		.multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
+		.multi_read_bit = false,
 		.bootime = 2, /* guess */
 	},
+	{
+		.wai = 0x32,
+		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+		.sensors_supported = {
+			[0] = H3LIS331DL_DRIVER_NAME,
+		},
+		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
+		.odr = {
+			.addr = 0x20,
+			.mask = 0x18,
+			.odr_avl = {
+				{ .hz = 50, .value = 0x00, },
+				{ .hz = 100, .value = 0x01, },
+				{ .hz = 400, .value = 0x02, },
+				{ .hz = 1000, .value = 0x03, },
+			},
+		},
+		.pw = {
+			.addr = 0x20,
+			.mask = 0x20,
+			.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+		},
+		.enable_axis = {
+			.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+		},
+		.fs = {
+			.addr = 0x23,
+			.mask = 0x30,
+			.fs_avl = {
+				[0] = {
+					.num = ST_ACCEL_FS_AVL_100G,
+					.value = 0x00,
+					.gain = IIO_G_TO_M_S_2(49000),
+				},
+				[1] = {
+					.num = ST_ACCEL_FS_AVL_200G,
+					.value = 0x01,
+					.gain = IIO_G_TO_M_S_2(98000),
+				},
+				[2] = {
+					.num = ST_ACCEL_FS_AVL_400G,
+					.value = 0x03,
+					.gain = IIO_G_TO_M_S_2(195000),
+				},
+			},
+		},
+		.bdu = {
+			.addr = 0x23,
+			.mask = 0x80,
+		},
+		.drdy_irq = {
+			.addr = 0x22,
+			.mask_int1 = 0x02,
+			.mask_int2 = 0x10,
+			.addr_ihl = 0x22,
+			.mask_ihl = 0x80,
+		},
+		.multi_read_bit = true,
+		.bootime = 2,
+	},
+	{
+		/* No WAI register present */
+		.sensors_supported = {
+			[0] = LIS3L02DQ_ACCEL_DEV_NAME,
+		},
+		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
+		.odr = {
+			.addr = 0x20,
+			.mask = 0x30,
+			.odr_avl = {
+				{ .hz = 280, .value = 0x00, },
+				{ .hz = 560, .value = 0x01, },
+				{ .hz = 1120, .value = 0x02, },
+				{ .hz = 4480, .value = 0x03, },
+			},
+		},
+		.pw = {
+			.addr = 0x20,
+			.mask = 0xc0,
+			.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+		},
+		.enable_axis = {
+			.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+		},
+		.fs = {
+			.fs_avl = {
+				[0] = {
+					.num = ST_ACCEL_FS_AVL_2G,
+					.gain = IIO_G_TO_M_S_2(488),
+				},
+			},
+		},
+		/*
+		 * The part has a BDU bit but if set the data is never
+		 * updated so don't set it.
+		 */
+		.bdu = {
+		},
+		.drdy_irq = {
+			.addr = 0x21,
+			.mask_int1 = 0x04,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
+		},
+		.multi_read_bit = false,
+		.bootime = 2,
+	},
+	{
+		.wai = 0x33,
+		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+		.sensors_supported = {
+			[0] = LNG2DM_ACCEL_DEV_NAME,
+		},
+		.ch = (struct iio_chan_spec *)st_accel_8bit_channels,
+		.odr = {
+			.addr = 0x20,
+			.mask = 0xf0,
+			.odr_avl = {
+				{ .hz = 1, .value = 0x01, },
+				{ .hz = 10, .value = 0x02, },
+				{ .hz = 25, .value = 0x03, },
+				{ .hz = 50, .value = 0x04, },
+				{ .hz = 100, .value = 0x05, },
+				{ .hz = 200, .value = 0x06, },
+				{ .hz = 400, .value = 0x07, },
+				{ .hz = 1600, .value = 0x08, },
+			},
+		},
+		.pw = {
+			.addr = 0x20,
+			.mask = 0xf0,
+			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+		},
+		.enable_axis = {
+			.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+		},
+		.fs = {
+			.addr = 0x23,
+			.mask = 0x30,
+			.fs_avl = {
+				[0] = {
+					.num = ST_ACCEL_FS_AVL_2G,
+					.value = 0x00,
+					.gain = IIO_G_TO_M_S_2(15600),
+				},
+				[1] = {
+					.num = ST_ACCEL_FS_AVL_4G,
+					.value = 0x01,
+					.gain = IIO_G_TO_M_S_2(31200),
+				},
+				[2] = {
+					.num = ST_ACCEL_FS_AVL_8G,
+					.value = 0x02,
+					.gain = IIO_G_TO_M_S_2(62500),
+				},
+				[3] = {
+					.num = ST_ACCEL_FS_AVL_16G,
+					.value = 0x03,
+					.gain = IIO_G_TO_M_S_2(187500),
+				},
+			},
+		},
+		.drdy_irq = {
+			.addr = 0x22,
+			.mask_int1 = 0x10,
+			.mask_int2 = 0x08,
+			.addr_ihl = 0x25,
+			.mask_ihl = 0x02,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
+		},
+		.multi_read_bit = true,
+		.bootime = 2,
+	},
 };
 
 static int st_accel_read_raw(struct iio_dev *indio_dev,
@@ -557,8 +626,8 @@
 
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-		*val2 = adata->current_fullscale->gain;
+		*val = adata->current_fullscale->gain / 1000000;
+		*val2 = adata->current_fullscale->gain % 1000000;
 		return IIO_VAL_INT_PLUS_MICRO;
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		*val = adata->odr;
@@ -577,9 +646,13 @@
 	int err;
 
 	switch (mask) {
-	case IIO_CHAN_INFO_SCALE:
-		err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
+	case IIO_CHAN_INFO_SCALE: {
+		int gain;
+
+		gain = val * 1000000 + val2;
+		err = st_sensors_set_fullscale_by_gain(indio_dev, gain);
 		break;
+	}
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		if (val2)
 			return -EINVAL;
@@ -619,6 +692,7 @@
 static const struct iio_trigger_ops st_accel_trigger_ops = {
 	.owner = THIS_MODULE,
 	.set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE,
+	.validate_device = st_sensors_validate_device,
 };
 #define ST_ACCEL_TRIGGER_OPS (&st_accel_trigger_ops)
 #else
@@ -628,6 +702,8 @@
 int st_accel_common_probe(struct iio_dev *indio_dev)
 {
 	struct st_sensor_data *adata = iio_priv(indio_dev);
+	struct st_sensors_platform_data *pdata =
+		(struct st_sensors_platform_data *)adata->dev->platform_data;
 	int irq = adata->get_irq_data_ready(indio_dev);
 	int err;
 
@@ -635,13 +711,15 @@
 	indio_dev->info = &accel_info;
 	mutex_init(&adata->tb.buf_lock);
 
-	st_sensors_power_enable(indio_dev);
+	err = st_sensors_power_enable(indio_dev);
+	if (err)
+		return err;
 
 	err = st_sensors_check_device_support(indio_dev,
 					ARRAY_SIZE(st_accel_sensors_settings),
 					st_accel_sensors_settings);
 	if (err < 0)
-		return err;
+		goto st_accel_power_off;
 
 	adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
 	adata->multiread_bit = adata->sensor_settings->multi_read_bit;
@@ -652,17 +730,16 @@
 					&adata->sensor_settings->fs.fs_avl[0];
 	adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
 
-	if (!adata->dev->platform_data)
-		adata->dev->platform_data =
-			(struct st_sensors_platform_data *)&default_accel_pdata;
+	if (!pdata)
+		pdata = (struct st_sensors_platform_data *)&default_accel_pdata;
 
-	err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
+	err = st_sensors_init_sensor(indio_dev, pdata);
 	if (err < 0)
-		return err;
+		goto st_accel_power_off;
 
 	err = st_accel_allocate_ring(indio_dev);
 	if (err < 0)
-		return err;
+		goto st_accel_power_off;
 
 	if (irq > 0) {
 		err = st_sensors_allocate_trigger(indio_dev,
@@ -685,6 +762,8 @@
 		st_sensors_deallocate_trigger(indio_dev);
 st_accel_probe_trigger_error:
 	st_accel_deallocate_ring(indio_dev);
+st_accel_power_off:
+	st_sensors_power_disable(indio_dev);
 
 	return err;
 }
--- linux-4.4.0.orig/drivers/iio/accel/st_accel_i2c.c
+++ linux-4.4.0/drivers/iio/accel/st_accel_i2c.c
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
 
@@ -72,6 +73,22 @@
 		.compatible = "st,lsm303agr-accel",
 		.data = LSM303AGR_ACCEL_DEV_NAME,
 	},
+	{
+		.compatible = "st,lis2dh12-accel",
+		.data = LIS2DH12_ACCEL_DEV_NAME,
+	},
+	{
+		.compatible = "st,h3lis331dl-accel",
+		.data = H3LIS331DL_DRIVER_NAME,
+	},
+	{
+		.compatible = "st,lis3l02dq",
+		.data = LIS3L02DQ_ACCEL_DEV_NAME,
+	},
+	{
+		.compatible = "st,lng2dm-accel",
+		.data = LNG2DM_ACCEL_DEV_NAME,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -79,25 +96,67 @@
 #define st_accel_of_match NULL
 #endif
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id st_accel_acpi_match[] = {
+	{"SMO8A90", LNG2DM},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
+#else
+#define st_accel_acpi_match NULL
+#endif
+
+static const struct i2c_device_id st_accel_id_table[] = {
+	{ LSM303DLH_ACCEL_DEV_NAME, LSM303DLH },
+	{ LSM303DLHC_ACCEL_DEV_NAME, LSM303DLHC },
+	{ LIS3DH_ACCEL_DEV_NAME, LIS3DH },
+	{ LSM330D_ACCEL_DEV_NAME, LSM330D },
+	{ LSM330DL_ACCEL_DEV_NAME, LSM330DL },
+	{ LSM330DLC_ACCEL_DEV_NAME, LSM330DLC },
+	{ LIS331DLH_ACCEL_DEV_NAME, LIS331DLH },
+	{ LSM303DL_ACCEL_DEV_NAME, LSM303DL },
+	{ LSM303DLM_ACCEL_DEV_NAME, LSM303DLM },
+	{ LSM330_ACCEL_DEV_NAME, LSM330 },
+	{ LSM303AGR_ACCEL_DEV_NAME, LSM303AGR },
+	{ LIS2DH12_ACCEL_DEV_NAME, LIS2DH12 },
+	{ LIS3L02DQ_ACCEL_DEV_NAME, LIS3L02DQ },
+	{ LNG2DM_ACCEL_DEV_NAME, LNG2DM },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
+
 static int st_accel_i2c_probe(struct i2c_client *client,
 						const struct i2c_device_id *id)
 {
 	struct iio_dev *indio_dev;
 	struct st_sensor_data *adata;
-	int err;
+	int ret;
 
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
 	if (!indio_dev)
 		return -ENOMEM;
 
 	adata = iio_priv(indio_dev);
-	st_sensors_of_i2c_probe(client, st_accel_of_match);
+
+	if (client->dev.of_node) {
+		st_sensors_of_i2c_probe(client, st_accel_of_match);
+	} else if (ACPI_HANDLE(&client->dev)) {
+		ret = st_sensors_match_acpi_device(&client->dev);
+		if ((ret < 0) || (ret >= ST_ACCEL_MAX))
+			return -ENODEV;
+
+		strncpy(client->name, st_accel_id_table[ret].name,
+				sizeof(client->name));
+		client->name[sizeof(client->name) - 1] = '\0';
+	} else if (!id)
+		return -ENODEV;
+
 
 	st_sensors_i2c_configure(indio_dev, client, adata);
 
-	err = st_accel_common_probe(indio_dev);
-	if (err < 0)
-		return err;
+	ret = st_accel_common_probe(indio_dev);
+	if (ret < 0)
+		return ret;
 
 	return 0;
 }
@@ -109,26 +168,11 @@
 	return 0;
 }
 
-static const struct i2c_device_id st_accel_id_table[] = {
-	{ LSM303DLH_ACCEL_DEV_NAME },
-	{ LSM303DLHC_ACCEL_DEV_NAME },
-	{ LIS3DH_ACCEL_DEV_NAME },
-	{ LSM330D_ACCEL_DEV_NAME },
-	{ LSM330DL_ACCEL_DEV_NAME },
-	{ LSM330DLC_ACCEL_DEV_NAME },
-	{ LIS331DLH_ACCEL_DEV_NAME },
-	{ LSM303DL_ACCEL_DEV_NAME },
-	{ LSM303DLM_ACCEL_DEV_NAME },
-	{ LSM330_ACCEL_DEV_NAME },
-	{ LSM303AGR_ACCEL_DEV_NAME },
-	{},
-};
-MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
-
 static struct i2c_driver st_accel_driver = {
 	.driver = {
 		.name = "st-accel-i2c",
 		.of_match_table = of_match_ptr(st_accel_of_match),
+		.acpi_match_table = ACPI_PTR(st_accel_acpi_match),
 	},
 	.probe = st_accel_i2c_probe,
 	.remove = st_accel_i2c_remove,
--- linux-4.4.0.orig/drivers/iio/accel/st_accel_spi.c
+++ linux-4.4.0/drivers/iio/accel/st_accel_spi.c
@@ -58,6 +58,9 @@
 	{ LSM303DLM_ACCEL_DEV_NAME },
 	{ LSM330_ACCEL_DEV_NAME },
 	{ LSM303AGR_ACCEL_DEV_NAME },
+	{ LIS2DH12_ACCEL_DEV_NAME },
+	{ LIS3L02DQ_ACCEL_DEV_NAME },
+	{ LNG2DM_ACCEL_DEV_NAME },
 	{},
 };
 MODULE_DEVICE_TABLE(spi, st_accel_id_table);
--- linux-4.4.0.orig/drivers/iio/adc/Kconfig
+++ linux-4.4.0/drivers/iio/adc/Kconfig
@@ -306,6 +306,7 @@
 config ROCKCHIP_SARADC
 	tristate "Rockchip SARADC driver"
 	depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
+	depends on RESET_CONTROLLER
 	help
 	  Say yes here to build support for the SARADC found in SoCs from
 	  Rockchip.
@@ -372,6 +373,7 @@
 config VF610_ADC
 	tristate "Freescale vf610 ADC driver"
 	depends on OF
+	depends on HAS_IOMEM
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	help
--- linux-4.4.0.orig/drivers/iio/adc/ad7266.c
+++ linux-4.4.0/drivers/iio/adc/ad7266.c
@@ -396,8 +396,8 @@
 
 	st = iio_priv(indio_dev);
 
-	st->reg = devm_regulator_get(&spi->dev, "vref");
-	if (!IS_ERR_OR_NULL(st->reg)) {
+	st->reg = devm_regulator_get_optional(&spi->dev, "vref");
+	if (!IS_ERR(st->reg)) {
 		ret = regulator_enable(st->reg);
 		if (ret)
 			return ret;
@@ -408,6 +408,9 @@
 
 		st->vref_mv = ret / 1000;
 	} else {
+		/* Any other error indicates that the regulator does exist */
+		if (PTR_ERR(st->reg) != -ENODEV)
+			return PTR_ERR(st->reg);
 		/* Use internal reference */
 		st->vref_mv = 2500;
 	}
--- linux-4.4.0.orig/drivers/iio/adc/ad7793.c
+++ linux-4.4.0/drivers/iio/adc/ad7793.c
@@ -257,7 +257,7 @@
 	unsigned int vref_mv)
 {
 	struct ad7793_state *st = iio_priv(indio_dev);
-	int i, ret = -1;
+	int i, ret;
 	unsigned long long scale_uv;
 	u32 id;
 
@@ -266,7 +266,7 @@
 		return ret;
 
 	/* reset the serial interface */
-	ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret));
+	ret = ad_sd_reset(&st->sd, 32);
 	if (ret < 0)
 		goto out;
 	usleep_range(500, 2000); /* Wait for at least 500us */
@@ -579,7 +579,7 @@
 	.read_raw = &ad7793_read_raw,
 	.write_raw = &ad7793_write_raw,
 	.write_raw_get_fmt = &ad7793_write_raw_get_fmt,
-	.attrs = &ad7793_attribute_group,
+	.attrs = &ad7797_attribute_group,
 	.validate_trigger = ad_sd_validate_trigger,
 	.driver_module = THIS_MODULE,
 };
--- linux-4.4.0.orig/drivers/iio/adc/ad799x.c
+++ linux-4.4.0/drivers/iio/adc/ad799x.c
@@ -533,6 +533,7 @@
 static const struct iio_info ad7991_info = {
 	.read_raw = &ad799x_read_raw,
 	.driver_module = THIS_MODULE,
+	.update_scan_mode = ad799x_update_scan_mode,
 };
 
 static const struct iio_info ad7993_4_7_8_noirq_info = {
@@ -821,10 +822,10 @@
 
 	ret = ad799x_write_config(st, st->chip_config->default_config);
 	if (ret < 0)
-		goto error_disable_reg;
+		goto error_disable_vref;
 	ret = ad799x_read_config(st);
 	if (ret < 0)
-		goto error_disable_reg;
+		goto error_disable_vref;
 	st->config = ret;
 
 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
--- linux-4.4.0.orig/drivers/iio/adc/ad_sigma_delta.c
+++ linux-4.4.0/drivers/iio/adc/ad_sigma_delta.c
@@ -62,7 +62,7 @@
 	struct spi_transfer t = {
 		.tx_buf		= data,
 		.len		= size + 1,
-		.cs_change	= sigma_delta->bus_locked,
+		.cs_change	= sigma_delta->keep_cs_asserted,
 	};
 	struct spi_message m;
 	int ret;
@@ -121,6 +121,7 @@
 	if (sigma_delta->info->has_registers) {
 		data[0] = reg << sigma_delta->info->addr_shift;
 		data[0] |= sigma_delta->info->read_mask;
+		data[0] |= sigma_delta->comm;
 		spi_message_add_tail(&t[0], &m);
 	}
 	spi_message_add_tail(&t[1], &m);
@@ -177,6 +178,34 @@
 }
 EXPORT_SYMBOL_GPL(ad_sd_read_reg);
 
+/**
+ * ad_sd_reset() - Reset the serial interface
+ *
+ * @sigma_delta: The sigma delta device
+ * @reset_length: Number of SCLKs with DIN = 1
+ *
+ * Returns 0 on success, an error code otherwise.
+ **/
+int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
+	unsigned int reset_length)
+{
+	uint8_t *buf;
+	unsigned int size;
+	int ret;
+
+	size = DIV_ROUND_UP(reset_length, 8);
+	buf = kcalloc(size, sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	memset(buf, 0xff, size);
+	ret = spi_write(sigma_delta->spi, buf, size);
+	kfree(buf);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ad_sd_reset);
+
 static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
 	unsigned int mode, unsigned int channel)
 {
@@ -188,6 +217,7 @@
 
 	spi_bus_lock(sigma_delta->spi->master);
 	sigma_delta->bus_locked = true;
+	sigma_delta->keep_cs_asserted = true;
 	reinit_completion(&sigma_delta->completion);
 
 	ret = ad_sigma_delta_set_mode(sigma_delta, mode);
@@ -205,9 +235,10 @@
 		ret = 0;
 	}
 out:
+	sigma_delta->keep_cs_asserted = false;
+	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
 	sigma_delta->bus_locked = false;
 	spi_bus_unlock(sigma_delta->spi->master);
-	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
 
 	return ret;
 }
@@ -259,6 +290,7 @@
 
 	spi_bus_lock(sigma_delta->spi->master);
 	sigma_delta->bus_locked = true;
+	sigma_delta->keep_cs_asserted = true;
 	reinit_completion(&sigma_delta->completion);
 
 	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
@@ -268,9 +300,6 @@
 	ret = wait_for_completion_interruptible_timeout(
 			&sigma_delta->completion, HZ);
 
-	sigma_delta->bus_locked = false;
-	spi_bus_unlock(sigma_delta->spi->master);
-
 	if (ret == 0)
 		ret = -EIO;
 	if (ret < 0)
@@ -286,7 +315,10 @@
 		sigma_delta->irq_dis = true;
 	}
 
+	sigma_delta->keep_cs_asserted = false;
 	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+	sigma_delta->bus_locked = false;
+	spi_bus_unlock(sigma_delta->spi->master);
 	mutex_unlock(&indio_dev->mlock);
 
 	if (ret)
@@ -323,6 +355,8 @@
 
 	spi_bus_lock(sigma_delta->spi->master);
 	sigma_delta->bus_locked = true;
+	sigma_delta->keep_cs_asserted = true;
+
 	ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
 	if (ret)
 		goto err_unlock;
@@ -351,6 +385,7 @@
 		sigma_delta->irq_dis = true;
 	}
 
+	sigma_delta->keep_cs_asserted = false;
 	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
 
 	sigma_delta->bus_locked = false;
--- linux-4.4.0.orig/drivers/iio/adc/at91_adc.c
+++ linux-4.4.0/drivers/iio/adc/at91_adc.c
@@ -245,12 +245,14 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *idev = pf->indio_dev;
 	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_chan_spec const *chan;
 	int i, j = 0;
 
 	for (i = 0; i < idev->masklength; i++) {
 		if (!test_bit(i, idev->active_scan_mask))
 			continue;
-		st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i));
+		chan = idev->channels + i;
+		st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, chan->channel));
 		j++;
 	}
 
@@ -276,6 +278,8 @@
 		iio_trigger_poll(idev->trig);
 	} else {
 		st->last_value = at91_adc_readl(st, AT91_ADC_CHAN(st, st->chnb));
+		/* Needed to ACK the DRDY interruption */
+		at91_adc_readl(st, AT91_ADC_LCDR);
 		st->done = true;
 		wake_up_interruptible(&st->wq_data_avail);
 	}
@@ -381,8 +385,8 @@
 		st->ts_bufferedmeasure = false;
 		input_report_key(st->ts_input, BTN_TOUCH, 0);
 		input_sync(st->ts_input);
-	} else if (status & AT91_ADC_EOC(3)) {
-		/* Conversion finished */
+	} else if (status & AT91_ADC_EOC(3) && st->ts_input) {
+		/* Conversion finished and we've a touchscreen */
 		if (st->ts_bufferedmeasure) {
 			/*
 			 * Last measurement is always discarded, since it can
@@ -698,23 +702,29 @@
 		ret = wait_event_interruptible_timeout(st->wq_data_avail,
 						       st->done,
 						       msecs_to_jiffies(1000));
-		if (ret == 0)
-			ret = -ETIMEDOUT;
-		if (ret < 0) {
-			mutex_unlock(&st->lock);
-			return ret;
-		}
-
-		*val = st->last_value;
 
+		/* Disable interrupts, regardless if adc conversion was
+		 * successful or not
+		 */
 		at91_adc_writel(st, AT91_ADC_CHDR,
 				AT91_ADC_CH(chan->channel));
 		at91_adc_writel(st, AT91_ADC_IDR, BIT(chan->channel));
 
-		st->last_value = 0;
-		st->done = false;
+		if (ret > 0) {
+			/* a valid conversion took place */
+			*val = st->last_value;
+			st->last_value = 0;
+			st->done = false;
+			ret = IIO_VAL_INT;
+		} else if (ret == 0) {
+			/* conversion timeout */
+			dev_err(&idev->dev, "ADC Channel %d timeout.\n",
+				chan->channel);
+			ret = -ETIMEDOUT;
+		}
+
 		mutex_unlock(&st->lock);
-		return IIO_VAL_INT;
+		return ret;
 
 	case IIO_CHAN_INFO_SCALE:
 		*val = st->vref_mv;
--- linux-4.4.0.orig/drivers/iio/adc/axp288_adc.c
+++ linux-4.4.0/drivers/iio/adc/axp288_adc.c
@@ -28,8 +28,6 @@
 #include <linux/iio/driver.h>
 
 #define AXP288_ADC_EN_MASK		0xF1
-#define AXP288_ADC_TS_PIN_GPADC		0xF2
-#define AXP288_ADC_TS_PIN_ON		0xF3
 
 enum axp288_adc_id {
 	AXP288_ADC_TS,
@@ -46,7 +44,7 @@
 	struct regmap *regmap;
 };
 
-static const struct iio_chan_spec const axp288_adc_channels[] = {
+static const struct iio_chan_spec axp288_adc_channels[] = {
 	{
 		.indexed = 1,
 		.type = IIO_TEMP,
@@ -123,16 +121,6 @@
 	return IIO_VAL_INT;
 }
 
-static int axp288_adc_set_ts(struct regmap *regmap, unsigned int mode,
-				unsigned long address)
-{
-	/* channels other than GPADC do not need to switch TS pin */
-	if (address != AXP288_GP_ADC_H)
-		return 0;
-
-	return regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, mode);
-}
-
 static int axp288_adc_read_raw(struct iio_dev *indio_dev,
 			struct iio_chan_spec const *chan,
 			int *val, int *val2, long mask)
@@ -143,16 +131,7 @@
 	mutex_lock(&indio_dev->mlock);
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_GPADC,
-					chan->address)) {
-			dev_err(&indio_dev->dev, "GPADC mode\n");
-			ret = -EINVAL;
-			break;
-		}
 		ret = axp288_adc_read_channel(val, chan->address, info->regmap);
-		if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_ON,
-						chan->address))
-			dev_err(&indio_dev->dev, "TS pin restore\n");
 		break;
 	default:
 		ret = -EINVAL;
@@ -162,15 +141,6 @@
 	return ret;
 }
 
-static int axp288_adc_set_state(struct regmap *regmap)
-{
-	/* ADC should be always enabled for internal FG to function */
-	if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON))
-		return -EIO;
-
-	return regmap_write(regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
-}
-
 static const struct iio_info axp288_adc_iio_info = {
 	.read_raw = &axp288_adc_read_raw,
 	.driver_module = THIS_MODULE,
@@ -199,7 +169,7 @@
 	 * Set ADC to enabled state at all time, including system suspend.
 	 * otherwise internal fuel gauge functionality may be affected.
 	 */
-	ret = axp288_adc_set_state(axp20x->regmap);
+	ret = regmap_write(info->regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to enable ADC device\n");
 		return ret;
--- linux-4.4.0.orig/drivers/iio/adc/hi8435.c
+++ linux-4.4.0/drivers/iio/adc/hi8435.c
@@ -121,10 +121,21 @@
 				     enum iio_event_direction dir, int state)
 {
 	struct hi8435_priv *priv = iio_priv(idev);
+	int ret;
+	u32 tmp;
+
+	if (state) {
+		ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
+		if (ret < 0)
+			return ret;
+		if (tmp & BIT(chan->channel))
+			priv->event_prev_val |= BIT(chan->channel);
+		else
+			priv->event_prev_val &= ~BIT(chan->channel);
 
-	priv->event_scan_mask &= ~BIT(chan->channel);
-	if (state)
 		priv->event_scan_mask |= BIT(chan->channel);
+	} else
+		priv->event_scan_mask &= ~BIT(chan->channel);
 
 	return 0;
 }
@@ -442,13 +453,15 @@
 	priv->spi = spi;
 
 	reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW);
-	if (IS_ERR(reset_gpio)) {
-		/* chip s/w reset if h/w reset failed */
+	if (!IS_ERR(reset_gpio)) {
+		/* need >=100ns low pulse to reset chip */
+		gpiod_set_raw_value_cansleep(reset_gpio, 0);
+		udelay(1);
+		gpiod_set_raw_value_cansleep(reset_gpio, 1);
+	} else {
+		/* s/w reset chip if h/w reset is not available */
 		hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST);
 		hi8435_writeb(priv, HI8435_CTRL_REG, 0);
-	} else {
-		udelay(5);
-		gpiod_set_value(reset_gpio, 1);
 	}
 
 	spi_set_drvdata(spi, idev);
--- linux-4.4.0.orig/drivers/iio/adc/max1027.c
+++ linux-4.4.0/drivers/iio/adc/max1027.c
@@ -470,6 +470,14 @@
 		goto fail_dev_register;
 	}
 
+	/* Internal reset */
+	st->reg = MAX1027_RST_REG;
+	ret = spi_write(st->spi, &st->reg, 1);
+	if (ret < 0) {
+		dev_err(&indio_dev->dev, "Failed to reset the ADC\n");
+		return ret;
+	}
+
 	/* Disable averaging */
 	st->reg = MAX1027_AVG_REG;
 	ret = spi_write(st->spi, &st->reg, 1);
--- linux-4.4.0.orig/drivers/iio/adc/mcp320x.c
+++ linux-4.4.0/drivers/iio/adc/mcp320x.c
@@ -17,6 +17,8 @@
  * MCP3204
  * MCP3208
  * ------------
+ * 13 bit converter
+ * MCP3301
  *
  * Datasheet can be found here:
  * http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf  mcp3001
@@ -96,7 +98,7 @@
 }
 
 static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
-				  bool differential, int device_index)
+				  bool differential, int device_index, int *val)
 {
 	int ret;
 
@@ -117,19 +119,25 @@
 
 	switch (device_index) {
 	case mcp3001:
-		return (adc->rx_buf[0] << 5 | adc->rx_buf[1] >> 3);
+		*val = (adc->rx_buf[0] << 5 | adc->rx_buf[1] >> 3);
+		return 0;
 	case mcp3002:
 	case mcp3004:
 	case mcp3008:
-		return (adc->rx_buf[0] << 2 | adc->rx_buf[1] >> 6);
+		*val = (adc->rx_buf[0] << 2 | adc->rx_buf[1] >> 6);
+		return 0;
 	case mcp3201:
-		return (adc->rx_buf[0] << 7 | adc->rx_buf[1] >> 1);
+		*val = (adc->rx_buf[0] << 7 | adc->rx_buf[1] >> 1);
+		return 0;
 	case mcp3202:
 	case mcp3204:
 	case mcp3208:
-		return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4);
+		*val = (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4);
+		return 0;
 	case mcp3301:
-		return sign_extend32((adc->rx_buf[0] & 0x1f) << 8 | adc->rx_buf[1], 12);
+		*val = sign_extend32((adc->rx_buf[0] & 0x1f) << 8
+				    | adc->rx_buf[1], 12);
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -150,12 +158,10 @@
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
 		ret = mcp320x_adc_conversion(adc, channel->address,
-			channel->differential, device_index);
-
+			channel->differential, device_index, val);
 		if (ret < 0)
 			goto out;
 
-		*val = ret;
 		ret = IIO_VAL_INT;
 		break;
 
@@ -304,6 +310,7 @@
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &mcp320x_info;
+	spi_set_drvdata(spi, indio_dev);
 
 	chip_info = &mcp320x_chip_infos[spi_get_device_id(spi)->driver_data];
 	indio_dev->channels = chip_info->channels;
--- linux-4.4.0.orig/drivers/iio/adc/mcp3422.c
+++ linux-4.4.0/drivers/iio/adc/mcp3422.c
@@ -98,16 +98,12 @@
 {
 	int ret;
 
-	mutex_lock(&adc->lock);
-
 	ret = i2c_master_send(adc->i2c, &newconfig, 1);
 	if (ret > 0) {
 		adc->config = newconfig;
 		ret = 0;
 	}
 
-	mutex_unlock(&adc->lock);
-
 	return ret;
 }
 
@@ -140,6 +136,8 @@
 	u8 config;
 	u8 req_channel = channel->channel;
 
+	mutex_lock(&adc->lock);
+
 	if (req_channel != MCP3422_CHANNEL(adc->config)) {
 		config = adc->config;
 		config &= ~MCP3422_CHANNEL_MASK;
@@ -147,12 +145,18 @@
 		config &= ~MCP3422_PGA_MASK;
 		config |= MCP3422_PGA_VALUE(adc->pga[req_channel]);
 		ret = mcp3422_update_config(adc, config);
-		if (ret < 0)
+		if (ret < 0) {
+			mutex_unlock(&adc->lock);
 			return ret;
+		}
 		msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]);
 	}
 
-	return mcp3422_read(adc, value, &config);
+	ret = mcp3422_read(adc, value, &config);
+
+	mutex_unlock(&adc->lock);
+
+	return ret;
 }
 
 static int mcp3422_read_raw(struct iio_dev *iio,
--- linux-4.4.0.orig/drivers/iio/adc/rockchip_saradc.c
+++ linux-4.4.0/drivers/iio/adc/rockchip_saradc.c
@@ -21,6 +21,8 @@
 #include <linux/of_device.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/reset.h>
 #include <linux/regulator/consumer.h>
 #include <linux/iio/iio.h>
 
@@ -53,6 +55,7 @@
 	struct clk		*clk;
 	struct completion	completion;
 	struct regulator	*vref;
+	struct reset_control	*reset;
 	const struct rockchip_saradc_data *data;
 	u16			last_val;
 };
@@ -171,6 +174,16 @@
 };
 MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
 
+/**
+ * Reset SARADC Controller.
+ */
+static void rockchip_saradc_reset_controller(struct reset_control *reset)
+{
+	reset_control_assert(reset);
+	usleep_range(10, 20);
+	reset_control_deassert(reset);
+}
+
 static int rockchip_saradc_probe(struct platform_device *pdev)
 {
 	struct rockchip_saradc *info = NULL;
@@ -199,6 +212,20 @@
 	if (IS_ERR(info->regs))
 		return PTR_ERR(info->regs);
 
+	/*
+	 * The reset should be an optional property, as it should work
+	 * with old devicetrees as well
+	 */
+	info->reset = devm_reset_control_get(&pdev->dev, "saradc-apb");
+	if (IS_ERR(info->reset)) {
+		ret = PTR_ERR(info->reset);
+		if (ret != -ENOENT)
+			return ret;
+
+		dev_dbg(&pdev->dev, "no reset control found\n");
+		info->reset = NULL;
+	}
+
 	init_completion(&info->completion);
 
 	irq = platform_get_irq(pdev, 0);
@@ -233,6 +260,9 @@
 		return PTR_ERR(info->vref);
 	}
 
+	if (info->reset)
+		rockchip_saradc_reset_controller(info->reset);
+
 	/*
 	 * Use a default value for the converter clock.
 	 * This may become user-configurable in the future.
@@ -329,7 +359,7 @@
 
 	ret = clk_prepare_enable(info->clk);
 	if (ret)
-		return ret;
+		clk_disable_unprepare(info->pclk);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/iio/adc/ti_am335x_adc.c
+++ linux-4.4.0/drivers/iio/adc/ti_am335x_adc.c
@@ -32,6 +32,7 @@
 
 struct tiadc_device {
 	struct ti_tscadc_dev *mfd_tscadc;
+	struct mutex fifo1_lock; /* to protect fifo access */
 	int channels;
 	u8 channel_line[8];
 	u8 channel_step[8];
@@ -150,7 +151,9 @@
 {
 	struct iio_dev *indio_dev = private;
 	struct tiadc_device *adc_dev = iio_priv(indio_dev);
-	unsigned int status, config;
+	unsigned int status, config, adc_fsm;
+	unsigned short count = 0;
+
 	status = tiadc_readl(adc_dev, REG_IRQSTATUS);
 
 	/*
@@ -164,6 +167,15 @@
 		tiadc_writel(adc_dev, REG_CTRL, config);
 		tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN
 				| IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES);
+
+		/* wait for idle state.
+		 * ADC needs to finish the current conversion
+		 * before disabling the module
+		 */
+		do {
+			adc_fsm = tiadc_readl(adc_dev, REG_ADCFSM);
+		} while (adc_fsm != 0x10 && count++ < 100);
+
 		tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
 		return IRQ_HANDLED;
 	} else if (status & IRQENB_FIFO1THRES) {
@@ -289,7 +301,7 @@
 		goto error_kfifo_free;
 
 	indio_dev->setup_ops = setup_ops;
-	indio_dev->modes |= INDIO_BUFFER_HARDWARE;
+	indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
 
 	return 0;
 
@@ -360,6 +372,7 @@
 		int *val, int *val2, long mask)
 {
 	struct tiadc_device *adc_dev = iio_priv(indio_dev);
+	int ret = IIO_VAL_INT;
 	int i, map_val;
 	unsigned int fifo1count, read, stepid;
 	bool found = false;
@@ -373,13 +386,14 @@
 	if (!step_en)
 		return -EINVAL;
 
+	mutex_lock(&adc_dev->fifo1_lock);
 	fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
 	while (fifo1count--)
 		tiadc_readl(adc_dev, REG_FIFO1);
 
 	am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en);
 
-	timeout = jiffies + usecs_to_jiffies
+	timeout = jiffies + msecs_to_jiffies
 				(IDLE_TIMEOUT * adc_dev->channels);
 	/* Wait for Fifo threshold interrupt */
 	while (1) {
@@ -389,7 +403,8 @@
 
 		if (time_after(jiffies, timeout)) {
 			am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
-			return -EAGAIN;
+			ret = -EAGAIN;
+			goto err_unlock;
 		}
 	}
 	map_val = adc_dev->channel_step[chan->scan_index];
@@ -415,8 +430,11 @@
 	am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
 
 	if (found == false)
-		return -EBUSY;
-	return IIO_VAL_INT;
+		ret =  -EBUSY;
+
+err_unlock:
+	mutex_unlock(&adc_dev->fifo1_lock);
+	return ret;
 }
 
 static const struct iio_info tiadc_info = {
@@ -485,6 +503,7 @@
 
 	tiadc_step_config(indio_dev);
 	tiadc_writel(adc_dev, REG_FIFO1THR, FIFO1_THRESHOLD);
+	mutex_init(&adc_dev->fifo1_lock);
 
 	err = tiadc_channel_init(indio_dev, adc_dev->channels);
 	if (err < 0)
--- linux-4.4.0.orig/drivers/iio/adc/twl4030-madc.c
+++ linux-4.4.0/drivers/iio/adc/twl4030-madc.c
@@ -866,8 +866,10 @@
 
 	/* Enable 3v1 bias regulator for MADC[3:6] */
 	madc->usb3v1 = devm_regulator_get(madc->dev, "vusb3v1");
-	if (IS_ERR(madc->usb3v1))
-		return -ENODEV;
+	if (IS_ERR(madc->usb3v1)) {
+		ret = -ENODEV;
+		goto err_i2c;
+	}
 
 	ret = regulator_enable(madc->usb3v1);
 	if (ret)
@@ -876,11 +878,13 @@
 	ret = iio_device_register(iio_dev);
 	if (ret) {
 		dev_err(&pdev->dev, "could not register iio device\n");
-		goto err_i2c;
+		goto err_usb3v1;
 	}
 
 	return 0;
 
+err_usb3v1:
+	regulator_disable(madc->usb3v1);
 err_i2c:
 	twl4030_madc_set_current_generator(madc, 0, 0);
 err_current_generator:
--- linux-4.4.0.orig/drivers/iio/adc/vf610_adc.c
+++ linux-4.4.0/drivers/iio/adc/vf610_adc.c
@@ -77,7 +77,7 @@
 #define VF610_ADC_ADSTS_MASK		0x300
 #define VF610_ADC_ADLPC_EN		0x80
 #define VF610_ADC_ADHSC_EN		0x400
-#define VF610_ADC_REFSEL_VALT		0x100
+#define VF610_ADC_REFSEL_VALT		0x800
 #define VF610_ADC_REFSEL_VBG		0x1000
 #define VF610_ADC_ADTRG_HARD		0x2000
 #define VF610_ADC_AVGS_8		0x4000
--- linux-4.4.0.orig/drivers/iio/adc/xilinx-xadc-core.c
+++ linux-4.4.0/drivers/iio/adc/xilinx-xadc-core.c
@@ -660,7 +660,7 @@
 
 	spin_lock_irqsave(&xadc->lock, flags);
 	xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val);
-	xadc_write_reg(xadc, XADC_AXI_REG_IPISR, val & XADC_AXI_INT_EOS);
+	xadc_write_reg(xadc, XADC_AXI_REG_IPISR, XADC_AXI_INT_EOS);
 	if (state)
 		val |= XADC_AXI_INT_EOS;
 	else
@@ -709,13 +709,14 @@
 {
 	uint16_t val;
 
+	/* Powerdown the ADC-B when it is not needed. */
 	switch (seq_mode) {
 	case XADC_CONF1_SEQ_SIMULTANEOUS:
 	case XADC_CONF1_SEQ_INDEPENDENT:
-		val = XADC_CONF2_PD_ADC_B;
+		val = 0;
 		break;
 	default:
-		val = 0;
+		val = XADC_CONF2_PD_ADC_B;
 		break;
 	}
 
@@ -784,6 +785,16 @@
 	if (ret)
 		goto err;
 
+	/*
+	 * In simultaneous mode the upper and lower aux channels are samples at
+	 * the same time. In this mode the upper 8 bits in the sequencer
+	 * register are don't care and the lower 8 bits control two channels
+	 * each. As such we must set the bit if either the channel in the lower
+	 * group or the upper group is enabled.
+	 */
+	if (seq_mode == XADC_CONF1_SEQ_SIMULTANEOUS)
+		scan_mask = ((scan_mask >> 8) | scan_mask) & 0xff0000;
+
 	ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16);
 	if (ret)
 		goto err;
@@ -1208,7 +1219,7 @@
 
 	ret = xadc->ops->setup(pdev, indio_dev, irq);
 	if (ret)
-		goto err_free_samplerate_trigger;
+		goto err_clk_disable_unprepare;
 
 	ret = request_irq(irq, xadc->ops->interrupt_handler, 0,
 			dev_name(&pdev->dev), indio_dev);
@@ -1268,6 +1279,8 @@
 
 err_free_irq:
 	free_irq(irq, indio_dev);
+err_clk_disable_unprepare:
+	clk_disable_unprepare(xadc->clk);
 err_free_samplerate_trigger:
 	if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
 		iio_trigger_free(xadc->samplerate_trigger);
@@ -1277,8 +1290,6 @@
 err_triggered_buffer_cleanup:
 	if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
 		iio_triggered_buffer_cleanup(indio_dev);
-err_clk_disable_unprepare:
-	clk_disable_unprepare(xadc->clk);
 err_device_free:
 	kfree(indio_dev->channels);
 
@@ -1299,7 +1310,7 @@
 	}
 	free_irq(irq, indio_dev);
 	clk_disable_unprepare(xadc->clk);
-	cancel_delayed_work(&xadc->zynq_unmask_work);
+	cancel_delayed_work_sync(&xadc->zynq_unmask_work);
 	kfree(xadc->data);
 	kfree(indio_dev->channels);
 
--- linux-4.4.0.orig/drivers/iio/buffer/kfifo_buf.c
+++ linux-4.4.0/drivers/iio/buffer/kfifo_buf.c
@@ -19,11 +19,18 @@
 #define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer)
 
 static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
-				int bytes_per_datum, int length)
+			size_t bytes_per_datum, unsigned int length)
 {
 	if ((length == 0) || (bytes_per_datum == 0))
 		return -EINVAL;
 
+	/*
+	 * Make sure we don't overflow an unsigned int after kfifo rounds up to
+	 * the next power of 2.
+	 */
+	if (roundup_pow_of_two(length) > UINT_MAX / bytes_per_datum)
+		return -EINVAL;
+
 	return __kfifo_alloc((struct __kfifo *)&buf->kf, length,
 			     bytes_per_datum, GFP_KERNEL);
 }
@@ -64,7 +71,7 @@
 	return 0;
 }
 
-static int iio_set_length_kfifo(struct iio_buffer *r, int length)
+static int iio_set_length_kfifo(struct iio_buffer *r, unsigned int length)
 {
 	/* Avoid an invalid state */
 	if (length < 2)
--- linux-4.4.0.orig/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
+++ linux-4.4.0/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -30,34 +30,34 @@
 	u32 usage_id;
 	int unit; /* 0 for default others from HID sensor spec */
 	int scale_val0; /* scale, whole number */
-	int scale_val1; /* scale, fraction in micros */
+	int scale_val1; /* scale, fraction in nanos */
 } unit_conversion[] = {
-	{HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650},
+	{HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650000},
 	{HID_USAGE_SENSOR_ACCEL_3D,
 		HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0},
 	{HID_USAGE_SENSOR_ACCEL_3D,
-		HID_USAGE_SENSOR_UNITS_G, 9, 806650},
+		HID_USAGE_SENSOR_UNITS_G, 9, 806650000},
 
-	{HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453},
+	{HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453293},
 	{HID_USAGE_SENSOR_GYRO_3D,
 		HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0},
 	{HID_USAGE_SENSOR_GYRO_3D,
-		HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453},
+		HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453293},
 
-	{HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000},
+	{HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000000},
 	{HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0},
 
-	{HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453},
+	{HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453293},
 	{HID_USAGE_SENSOR_INCLINOMETER_3D,
-		HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453},
+		HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453293},
 	{HID_USAGE_SENSOR_INCLINOMETER_3D,
 		HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0},
 
 	{HID_USAGE_SENSOR_ALS, 0, 1, 0},
 	{HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0},
 
-	{HID_USAGE_SENSOR_PRESSURE, 0, 100000, 0},
-	{HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 1, 0},
+	{HID_USAGE_SENSOR_PRESSURE, 0, 100, 0},
+	{HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 0, 1000000},
 };
 
 static int pow_10(unsigned power)
@@ -266,15 +266,15 @@
 /*
  * This fuction applies the unit exponent to the scale.
  * For example:
- * 9.806650 ->exp:2-> val0[980]val1[665000]
- * 9.000806 ->exp:2-> val0[900]val1[80600]
- * 0.174535 ->exp:2-> val0[17]val1[453500]
- * 1.001745 ->exp:0-> val0[1]val1[1745]
- * 1.001745 ->exp:2-> val0[100]val1[174500]
- * 1.001745 ->exp:4-> val0[10017]val1[450000]
- * 9.806650 ->exp:-2-> val0[0]val1[98066]
+ * 9.806650000 ->exp:2-> val0[980]val1[665000000]
+ * 9.000806000 ->exp:2-> val0[900]val1[80600000]
+ * 0.174535293 ->exp:2-> val0[17]val1[453529300]
+ * 1.001745329 ->exp:0-> val0[1]val1[1745329]
+ * 1.001745329 ->exp:2-> val0[100]val1[174532900]
+ * 1.001745329 ->exp:4-> val0[10017]val1[453290000]
+ * 9.806650000 ->exp:-2-> val0[0]val1[98066500]
  */
-static void adjust_exponent_micro(int *val0, int *val1, int scale0,
+static void adjust_exponent_nano(int *val0, int *val1, int scale0,
 				  int scale1, int exp)
 {
 	int i;
@@ -285,32 +285,32 @@
 	if (exp > 0) {
 		*val0 = scale0 * pow_10(exp);
 		res = 0;
-		if (exp > 6) {
+		if (exp > 9) {
 			*val1 = 0;
 			return;
 		}
 		for (i = 0; i < exp; ++i) {
-			x = scale1 / pow_10(5 - i);
+			x = scale1 / pow_10(8 - i);
 			res += (pow_10(exp - 1 - i) * x);
-			scale1 = scale1 % pow_10(5 - i);
+			scale1 = scale1 % pow_10(8 - i);
 		}
 		*val0 += res;
 			*val1 = scale1 * pow_10(exp);
 	} else if (exp < 0) {
 		exp = abs(exp);
-		if (exp > 6) {
+		if (exp > 9) {
 			*val0 = *val1 = 0;
 			return;
 		}
 		*val0 = scale0 / pow_10(exp);
 		rem = scale0 % pow_10(exp);
 		res = 0;
-		for (i = 0; i < (6 - exp); ++i) {
-			x = scale1 / pow_10(5 - i);
-			res += (pow_10(5 - exp - i) * x);
-			scale1 = scale1 % pow_10(5 - i);
+		for (i = 0; i < (9 - exp); ++i) {
+			x = scale1 / pow_10(8 - i);
+			res += (pow_10(8 - exp - i) * x);
+			scale1 = scale1 % pow_10(8 - i);
 		}
-		*val1 = rem * pow_10(6 - exp) + res;
+		*val1 = rem * pow_10(9 - exp) + res;
 	} else {
 		*val0 = scale0;
 		*val1 = scale1;
@@ -332,14 +332,14 @@
 			unit_conversion[i].unit == attr_info->units) {
 			exp  = hid_sensor_convert_exponent(
 						attr_info->unit_expo);
-			adjust_exponent_micro(val0, val1,
+			adjust_exponent_nano(val0, val1,
 					unit_conversion[i].scale_val0,
 					unit_conversion[i].scale_val1, exp);
 			break;
 		}
 	}
 
-	return IIO_VAL_INT_PLUS_MICRO;
+	return IIO_VAL_INT_PLUS_NANO;
 }
 EXPORT_SYMBOL(hid_sensor_format_scale);
 
--- linux-4.4.0.orig/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ linux-4.4.0/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -36,8 +36,6 @@
 	s32 poll_value = 0;
 
 	if (state) {
-		if (!atomic_read(&st->user_requested_state))
-			return 0;
 		if (sensor_hub_device_open(st->hsdev))
 			return -EIO;
 
@@ -51,8 +49,6 @@
 			st->report_state.report_id,
 			st->report_state.index,
 			HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
-
-		poll_value = hid_sensor_read_poll_value(st);
 	} else {
 		int val;
 
@@ -86,10 +82,15 @@
 				       &report_val);
 	}
 
+	pr_debug("HID_SENSOR %s set power_state %d report_state %d\n",
+		 st->pdev->name, state_val, report_val);
+
 	sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
 			       st->power_state.index,
 			       sizeof(state_val), &state_val);
-	if (state && poll_value)
+	if (state)
+		poll_value = hid_sensor_read_poll_value(st);
+	if (poll_value > 0)
 		msleep_interruptible(poll_value * 2);
 
 	return 0;
@@ -107,6 +108,7 @@
 		ret = pm_runtime_get_sync(&st->pdev->dev);
 	else {
 		pm_runtime_mark_last_busy(&st->pdev->dev);
+		pm_runtime_use_autosuspend(&st->pdev->dev);
 		ret = pm_runtime_put_autosuspend(&st->pdev->dev);
 	}
 	if (ret < 0) {
@@ -175,8 +177,6 @@
 	/* Default to 3 seconds, but can be changed from sysfs */
 	pm_runtime_set_autosuspend_delay(&attrb->pdev->dev,
 					 3000);
-	pm_runtime_use_autosuspend(&attrb->pdev->dev);
-
 	return ret;
 error_unreg_trigger:
 	iio_trigger_unregister(trig);
--- linux-4.4.0.orig/drivers/iio/common/ssp_sensors/ssp_iio.c
+++ linux-4.4.0/drivers/iio/common/ssp_sensors/ssp_iio.c
@@ -80,7 +80,7 @@
 			    unsigned int len, int64_t timestamp)
 {
 	__le32 time;
-	int64_t calculated_time;
+	int64_t calculated_time = 0;
 	struct ssp_sensor_data *spd = iio_priv(indio_dev);
 
 	if (indio_dev->scan_bytes == 0)
--- linux-4.4.0.orig/drivers/iio/common/st_sensors/st_sensors_buffer.c
+++ linux-4.4.0/drivers/iio/common/st_sensors/st_sensors_buffer.c
@@ -24,81 +24,32 @@
 
 int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
 {
-	u8 *addr;
-	int i, n = 0, len;
+	int i;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 	unsigned int num_data_channels = sdata->num_data_channels;
 	unsigned int byte_for_channel =
-			indio_dev->channels[0].scan_type.storagebits >> 3;
+		DIV_ROUND_UP(indio_dev->channels[0].scan_type.realbits +
+				indio_dev->channels[0].scan_type.shift, 8);
 
-	addr = kmalloc(num_data_channels, GFP_KERNEL);
-	if (!addr) {
-		len = -ENOMEM;
-		goto st_sensors_get_buffer_element_error;
-	}
+	for_each_set_bit(i, indio_dev->active_scan_mask, num_data_channels) {
+		const struct iio_chan_spec *channel = &indio_dev->channels[i];
+		unsigned int bytes_to_read = channel->scan_type.realbits >> 3;
+		unsigned int storage_bytes =
+			channel->scan_type.storagebits >> 3;
+
+		buf = PTR_ALIGN(buf, storage_bytes);
+		if (sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
+						  channel->address,
+						  bytes_to_read, buf,
+						  sdata->multiread_bit) <
+		    bytes_to_read)
+			return -EIO;
 
-	for (i = 0; i < num_data_channels; i++) {
-		if (test_bit(i, indio_dev->active_scan_mask)) {
-			addr[n] = indio_dev->channels[i].address;
-			n++;
-		}
-	}
-	switch (n) {
-	case 1:
-		len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
-			addr[0], byte_for_channel, buf, sdata->multiread_bit);
-		break;
-	case 2:
-		if ((addr[1] - addr[0]) == byte_for_channel) {
-			len = sdata->tf->read_multiple_byte(&sdata->tb,
-				sdata->dev, addr[0], byte_for_channel * n,
-				buf, sdata->multiread_bit);
-		} else {
-			u8 *rx_array;
-			rx_array = kmalloc(byte_for_channel * num_data_channels,
-					   GFP_KERNEL);
-			if (!rx_array) {
-				len = -ENOMEM;
-				goto st_sensors_free_memory;
-			}
-
-			len = sdata->tf->read_multiple_byte(&sdata->tb,
-				sdata->dev, addr[0],
-				byte_for_channel * num_data_channels,
-				rx_array, sdata->multiread_bit);
-			if (len < 0) {
-				kfree(rx_array);
-				goto st_sensors_free_memory;
-			}
-
-			for (i = 0; i < n * byte_for_channel; i++) {
-				if (i < n)
-					buf[i] = rx_array[i];
-				else
-					buf[i] = rx_array[n + i];
-			}
-			kfree(rx_array);
-			len = byte_for_channel * n;
-		}
-		break;
-	case 3:
-		len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
-			addr[0], byte_for_channel * num_data_channels,
-			buf, sdata->multiread_bit);
-		break;
-	default:
-		len = -EINVAL;
-		goto st_sensors_free_memory;
-	}
-	if (len != byte_for_channel * n) {
-		len = -EIO;
-		goto st_sensors_free_memory;
+		/* Advance the buffer pointer */
+		buf += storage_bytes;
 	}
 
-st_sensors_free_memory:
-	kfree(addr);
-st_sensors_get_buffer_element_error:
-	return len;
+	return 0;
 }
 EXPORT_SYMBOL(st_sensors_get_buffer_element);
 
@@ -108,13 +59,20 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
+	s64 timestamp;
+
+	/* If we do timetamping here, do it before reading the values */
+	if (sdata->hw_irq_trigger)
+		timestamp = sdata->hw_timestamp;
+	else
+		timestamp = iio_get_time_ns();
 
 	len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
 	if (len < 0)
 		goto st_sensors_get_buffer_element_error;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, sdata->buffer_data,
-		pf->timestamp);
+					   timestamp);
 
 st_sensors_get_buffer_element_error:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-4.4.0.orig/drivers/iio/common/st_sensors/st_sensors_core.c
+++ linux-4.4.0/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -18,16 +18,15 @@
 #include <asm/unaligned.h>
 #include <linux/iio/common/st_sensors.h>
 
-
-#define ST_SENSORS_WAI_ADDRESS		0x0f
+#include "st_sensors_core.h"
 
 static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
 {
 	return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
 }
 
-static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
-						u8 reg_addr, u8 mask, u8 data)
+int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
+				    u8 reg_addr, u8 mask, u8 data)
 {
 	int err;
 	u8 new_data;
@@ -229,7 +228,7 @@
 }
 EXPORT_SYMBOL(st_sensors_set_axis_enable);
 
-void st_sensors_power_enable(struct iio_dev *indio_dev)
+int st_sensors_power_enable(struct iio_dev *indio_dev)
 {
 	struct st_sensor_data *pdata = iio_priv(indio_dev);
 	int err;
@@ -238,18 +237,37 @@
 	pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd");
 	if (!IS_ERR(pdata->vdd)) {
 		err = regulator_enable(pdata->vdd);
-		if (err != 0)
+		if (err != 0) {
 			dev_warn(&indio_dev->dev,
 				 "Failed to enable specified Vdd supply\n");
+			return err;
+		}
+	} else {
+		err = PTR_ERR(pdata->vdd);
+		if (err != -ENODEV)
+			return err;
 	}
 
 	pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio");
 	if (!IS_ERR(pdata->vdd_io)) {
 		err = regulator_enable(pdata->vdd_io);
-		if (err != 0)
+		if (err != 0) {
 			dev_warn(&indio_dev->dev,
 				 "Failed to enable specified Vdd_IO supply\n");
+			goto st_sensors_disable_vdd;
+		}
+	} else {
+		err = PTR_ERR(pdata->vdd_io);
+		if (err != -ENODEV)
+			goto st_sensors_disable_vdd;
 	}
+
+	return 0;
+
+st_sensors_disable_vdd:
+	if (!IS_ERR_OR_NULL(pdata->vdd))
+		regulator_disable(pdata->vdd);
+	return err;
 }
 EXPORT_SYMBOL(st_sensors_power_enable);
 
@@ -257,10 +275,10 @@
 {
 	struct st_sensor_data *pdata = iio_priv(indio_dev);
 
-	if (!IS_ERR(pdata->vdd))
+	if (!IS_ERR_OR_NULL(pdata->vdd))
 		regulator_disable(pdata->vdd);
 
-	if (!IS_ERR(pdata->vdd_io))
+	if (!IS_ERR_OR_NULL(pdata->vdd_io))
 		regulator_disable(pdata->vdd_io);
 }
 EXPORT_SYMBOL(st_sensors_power_disable);
@@ -302,6 +320,14 @@
 		return -EINVAL;
 	}
 
+	if (pdata->open_drain) {
+		if (!sdata->sensor_settings->drdy_irq.addr_od)
+			dev_err(&indio_dev->dev,
+				"open drain requested but unsupported.\n");
+		else
+			sdata->int_pin_open_drain = true;
+	}
+
 	return 0;
 }
 
@@ -322,6 +348,8 @@
 	else
 		pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;
 
+	pdata->open_drain = of_property_read_bool(np, "drive-open-drain");
+
 	return pdata;
 }
 #else
@@ -375,6 +403,16 @@
 			return err;
 	}
 
+	if (sdata->int_pin_open_drain) {
+		dev_info(&indio_dev->dev,
+			 "set interrupt line to open drain mode\n");
+		err = st_sensors_write_data_with_mask(indio_dev,
+				sdata->sensor_settings->drdy_irq.addr_od,
+				sdata->sensor_settings->drdy_irq.mask_od, 1);
+		if (err < 0)
+			return err;
+	}
+
 	err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
 
 	return err;
@@ -405,6 +443,9 @@
 	else
 		drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;
 
+	/* Flag to the poll function that the hardware trigger is in use */
+	sdata->hw_irq_trigger = enable;
+
 	/* Enable/Disable the interrupt generator for data ready. */
 	err = st_sensors_write_data_with_mask(indio_dev,
 					sdata->sensor_settings->drdy_irq.addr,
@@ -444,8 +485,10 @@
 	int err;
 	u8 *outdata;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
-	unsigned int byte_for_channel = ch->scan_type.storagebits >> 3;
+	unsigned int byte_for_channel = ch->scan_type.realbits >> 3;
 
+	byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits +
+					ch->scan_type.shift, 8);
 	outdata = kmalloc(byte_for_channel, GFP_KERNEL);
 	if (!outdata)
 		return -ENOMEM;
@@ -504,7 +547,7 @@
 			int num_sensors_list,
 			const struct st_sensor_settings *sensor_settings)
 {
-	int i, n, err;
+	int i, n, err = 0;
 	u8 wai;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
@@ -524,17 +567,21 @@
 		return -ENODEV;
 	}
 
-	err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-					sensor_settings[i].wai_addr, &wai);
-	if (err < 0) {
-		dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
-		return err;
-	}
+	if (sensor_settings[i].wai_addr) {
+		err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
+					   sensor_settings[i].wai_addr, &wai);
+		if (err < 0) {
+			dev_err(&indio_dev->dev,
+				"failed to read Who-Am-I register.\n");
+			return err;
+		}
 
-	if (sensor_settings[i].wai != wai) {
-		dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n",
-						indio_dev->name, wai);
-		return -EINVAL;
+		if (sensor_settings[i].wai != wai) {
+			dev_err(&indio_dev->dev,
+				"%s: WhoAmI mismatch (0x%x).\n",
+				indio_dev->name, wai);
+			return -EINVAL;
+		}
 	}
 
 	sdata->sensor_settings =
@@ -569,7 +616,7 @@
 ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	int i, len = 0;
+	int i, len = 0, q, r;
 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
@@ -578,8 +625,10 @@
 		if (sdata->sensor_settings->fs.fs_avl[i].num == 0)
 			break;
 
-		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
-				sdata->sensor_settings->fs.fs_avl[i].gain);
+		q = sdata->sensor_settings->fs.fs_avl[i].gain / 1000000;
+		r = sdata->sensor_settings->fs.fs_avl[i].gain % 1000000;
+
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ", q, r);
 	}
 	mutex_unlock(&indio_dev->mlock);
 	buf[len - 1] = '\n';
--- linux-4.4.0.orig/drivers/iio/common/st_sensors/st_sensors_core.h
+++ linux-4.4.0/drivers/iio/common/st_sensors/st_sensors_core.h
@@ -0,0 +1,8 @@
+/*
+ * Local functions in the ST Sensors core
+ */
+#ifndef __ST_SENSORS_CORE_H
+#define __ST_SENSORS_CORE_H
+int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
+				    u8 reg_addr, u8 mask, u8 data);
+#endif
--- linux-4.4.0.orig/drivers/iio/common/st_sensors/st_sensors_i2c.c
+++ linux-4.4.0/drivers/iio/common/st_sensors/st_sensors_i2c.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/iio/iio.h>
 #include <linux/of_device.h>
+#include <linux/acpi.h>
 
 #include <linux/iio/common/st_sensors_i2c.h>
 
@@ -48,8 +49,8 @@
 	if (multiread_bit)
 		reg_addr |= ST_SENSORS_I2C_MULTIREAD;
 
-	return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
-							reg_addr, len, data);
+	return i2c_smbus_read_i2c_block_data_or_emulated(to_i2c_client(dev),
+							 reg_addr, len, data);
 }
 
 static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
@@ -107,6 +108,25 @@
 EXPORT_SYMBOL(st_sensors_of_i2c_probe);
 #endif
 
+#ifdef CONFIG_ACPI
+int st_sensors_match_acpi_device(struct device *dev)
+{
+	const struct acpi_device_id *acpi_id;
+	kernel_ulong_t driver_data = 0;
+
+	if (ACPI_HANDLE(dev)) {
+		acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+		if (!acpi_id) {
+			dev_err(dev, "No driver data\n");
+			return -EINVAL;
+		}
+		driver_data = acpi_id->driver_data;
+	}
+	return driver_data;
+}
+EXPORT_SYMBOL(st_sensors_match_acpi_device);
+#endif
+
 MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
 MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
 MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/common/st_sensors/st_sensors_trigger.c
+++ linux-4.4.0/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -14,32 +14,148 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
 #include <linux/interrupt.h>
-
 #include <linux/iio/common/st_sensors.h>
+#include "st_sensors_core.h"
+
+/**
+ * st_sensors_irq_handler() - top half of the IRQ-based triggers
+ * @irq: irq number
+ * @p: private handler data
+ */
+irqreturn_t st_sensors_irq_handler(int irq, void *p)
+{
+	struct iio_trigger *trig = p;
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+	/* Get the time stamp as close in time as possible */
+	sdata->hw_timestamp = iio_get_time_ns();
+	return IRQ_WAKE_THREAD;
+}
+
+/**
+ * st_sensors_irq_thread() - bottom half of the IRQ-based triggers
+ * @irq: irq number
+ * @p: private handler data
+ */
+irqreturn_t st_sensors_irq_thread(int irq, void *p)
+{
+	struct iio_trigger *trig = p;
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+	int ret;
+
+	/*
+	 * If this trigger is backed by a hardware interrupt and we have a
+	 * status register, check if this IRQ came from us
+	 */
+	if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) {
+		u8 status;
+
+		ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
+			   sdata->sensor_settings->drdy_irq.addr_stat_drdy,
+			   &status);
+		if (ret < 0) {
+			dev_err(sdata->dev, "could not read channel status\n");
+			goto out_poll;
+		}
+		/*
+		 * the lower bits of .active_scan_mask[0] is directly mapped
+		 * to the channels on the sensor: either bit 0 for
+		 * one-dimensional sensors, or e.g. x,y,z for accelerometers,
+		 * gyroscopes or magnetometers. No sensor use more than 3
+		 * channels, so cut the other status bits here.
+		 */
+		status &= 0x07;
+
+		/*
+		 * If this was not caused by any channels on this sensor,
+		 * return IRQ_NONE
+		 */
+		if (!indio_dev->active_scan_mask)
+			return IRQ_NONE;
+		if (!(status & (u8)indio_dev->active_scan_mask[0]))
+			return IRQ_NONE;
+	}
 
+out_poll:
+	/* It's our IRQ: proceed to handle the register polling */
+	iio_trigger_poll_chained(p);
+	return IRQ_HANDLED;
+}
 
 int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 				const struct iio_trigger_ops *trigger_ops)
 {
-	int err;
+	int err, irq;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
+	unsigned long irq_trig;
 
 	sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
 	if (sdata->trig == NULL) {
-		err = -ENOMEM;
 		dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
-		goto iio_trigger_alloc_error;
+		return -ENOMEM;
+	}
+
+	irq = sdata->get_irq_data_ready(indio_dev);
+	irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
+	/*
+	 * If the IRQ is triggered on falling edge, we need to mark the
+	 * interrupt as active low, if the hardware supports this.
+	 */
+	if (irq_trig == IRQF_TRIGGER_FALLING) {
+		if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
+			dev_err(&indio_dev->dev,
+				"falling edge specified for IRQ but hardware "
+				"only support rising edge, will request "
+				"rising edge\n");
+			irq_trig = IRQF_TRIGGER_RISING;
+		} else {
+			/* Set up INT active low i.e. falling edge */
+			err = st_sensors_write_data_with_mask(indio_dev,
+				sdata->sensor_settings->drdy_irq.addr_ihl,
+				sdata->sensor_settings->drdy_irq.mask_ihl, 1);
+			if (err < 0)
+				goto iio_trigger_free;
+			dev_info(&indio_dev->dev,
+				 "interrupts on the falling edge\n");
+		}
+	} else if (irq_trig == IRQF_TRIGGER_RISING) {
+		dev_info(&indio_dev->dev,
+			 "interrupts on the rising edge\n");
+
+	} else {
+		dev_err(&indio_dev->dev,
+		"unsupported IRQ trigger specified (%lx), only "
+			"rising and falling edges supported, enforce "
+			"rising edge\n", irq_trig);
+		irq_trig = IRQF_TRIGGER_RISING;
 	}
 
+	/*
+	 * If the interrupt pin is Open Drain, by definition this
+	 * means that the interrupt line may be shared with other
+	 * peripherals. But to do this we also need to have a status
+	 * register and mask to figure out if this sensor was firing
+	 * the IRQ or not, so we can tell the interrupt handle that
+	 * it was "our" interrupt.
+	 */
+	if (sdata->int_pin_open_drain &&
+	    sdata->sensor_settings->drdy_irq.addr_stat_drdy)
+		irq_trig |= IRQF_SHARED;
+
+	/* Let's create an interrupt thread masking the hard IRQ here */
+	irq_trig |= IRQF_ONESHOT;
+
 	err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
-			iio_trigger_generic_data_rdy_poll,
-			NULL,
-			IRQF_TRIGGER_RISING,
+			st_sensors_irq_handler,
+			st_sensors_irq_thread,
+			irq_trig,
 			sdata->trig->name,
 			sdata->trig);
 	if (err) {
 		dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n");
-		goto request_irq_error;
+		goto iio_trigger_free;
 	}
 
 	iio_trigger_set_drvdata(sdata->trig, indio_dev);
@@ -57,9 +173,8 @@
 
 iio_trigger_register_error:
 	free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
-request_irq_error:
+iio_trigger_free:
 	iio_trigger_free(sdata->trig);
-iio_trigger_alloc_error:
 	return err;
 }
 EXPORT_SYMBOL(st_sensors_allocate_trigger);
@@ -74,6 +189,18 @@
 }
 EXPORT_SYMBOL(st_sensors_deallocate_trigger);
 
+int st_sensors_validate_device(struct iio_trigger *trig,
+			       struct iio_dev *indio_dev)
+{
+	struct iio_dev *indio = iio_trigger_get_drvdata(trig);
+
+	if (indio != indio_dev)
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(st_sensors_validate_device);
+
 MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
 MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
 MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/dac/Kconfig
+++ linux-4.4.0/drivers/iio/dac/Kconfig
@@ -72,6 +72,33 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5449.
 
+config AD5592R_BASE
+	tristate
+
+config AD5592R
+	tristate "Analog Devices AD5592R ADC/DAC driver"
+	depends on SPI_MASTER
+	select GPIOLIB
+	select AD5592R_BASE
+	help
+	  Say yes here to build support for Analog Devices AD5592R
+	  Digital to Analog / Analog to Digital Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5592r.
+
+config AD5593R
+	tristate "Analog Devices AD5593R ADC/DAC driver"
+	depends on I2C
+	select GPIOLIB
+	select AD5592R_BASE
+	help
+	  Say yes here to build support for Analog Devices AD5593R
+	  Digital to Analog / Analog to Digital Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5593r.
+
 config AD5504
 	tristate "Analog Devices AD5504/AD5501 DAC SPI driver"
 	depends on SPI
--- linux-4.4.0.orig/drivers/iio/dac/Makefile
+++ linux-4.4.0/drivers/iio/dac/Makefile
@@ -11,6 +11,9 @@
 obj-$(CONFIG_AD5504) += ad5504.o
 obj-$(CONFIG_AD5446) += ad5446.o
 obj-$(CONFIG_AD5449) += ad5449.o
+obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
+obj-$(CONFIG_AD5592R) += ad5592r.o
+obj-$(CONFIG_AD5593R) += ad5593r.o
 obj-$(CONFIG_AD5755) += ad5755.o
 obj-$(CONFIG_AD5764) += ad5764.o
 obj-$(CONFIG_AD5791) += ad5791.o
--- linux-4.4.0.orig/drivers/iio/dac/ad5380.c
+++ linux-4.4.0/drivers/iio/dac/ad5380.c
@@ -221,7 +221,7 @@
 		if (ret)
 			return ret;
 		*val >>= chan->scan_type.shift;
-		val -= (1 << chan->scan_type.realbits) / 2;
+		*val -= (1 << chan->scan_type.realbits) / 2;
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
 		*val = 2 * st->vref;
--- linux-4.4.0.orig/drivers/iio/dac/ad5504.c
+++ linux-4.4.0/drivers/iio/dac/ad5504.c
@@ -189,9 +189,9 @@
 		return ret;
 
 	if (pwr_down)
-		st->pwr_down_mask |= (1 << chan->channel);
-	else
 		st->pwr_down_mask &= ~(1 << chan->channel);
+	else
+		st->pwr_down_mask |= (1 << chan->channel);
 
 	ret = ad5504_spi_write(st, AD5504_ADDR_CTRL,
 				AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
--- linux-4.4.0.orig/drivers/iio/dac/ad5592r-base.c
+++ linux-4.4.0/drivers/iio/dac/ad5592r-base.c
@@ -0,0 +1,696 @@
+/*
+ * AD5592R Digital <-> Analog converters driver
+ *
+ * Copyright 2014-2016 Analog Devices Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio.h>
+#include <linux/property.h>
+
+#include <dt-bindings/iio/adi,ad5592r.h>
+
+#include "ad5592r-base.h"
+
+static struct ad5592r_state *gpiochip_to_ad5592r(struct gpio_chip *chip)
+{
+	return container_of(chip, struct ad5592r_state, gpiochip);
+}
+
+static int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct ad5592r_state *st = gpiochip_to_ad5592r(chip);
+	int ret = 0;
+	u8 val;
+
+	mutex_lock(&st->gpio_lock);
+
+	if (st->gpio_out & BIT(offset))
+		val = st->gpio_val;
+	else
+		ret = st->ops->gpio_read(st, &val);
+
+	mutex_unlock(&st->gpio_lock);
+
+	if (ret < 0)
+		return ret;
+
+	return !!(val & BIT(offset));
+}
+
+static void ad5592r_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct ad5592r_state *st = gpiochip_to_ad5592r(chip);
+
+	mutex_lock(&st->gpio_lock);
+
+	if (value)
+		st->gpio_val |= BIT(offset);
+	else
+		st->gpio_val &= ~BIT(offset);
+
+	st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
+
+	mutex_unlock(&st->gpio_lock);
+}
+
+static int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct ad5592r_state *st = gpiochip_to_ad5592r(chip);
+	int ret;
+
+	mutex_lock(&st->gpio_lock);
+
+	st->gpio_out &= ~BIT(offset);
+	st->gpio_in |= BIT(offset);
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
+	if (ret < 0)
+		goto err_unlock;
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
+
+err_unlock:
+	mutex_unlock(&st->gpio_lock);
+
+	return ret;
+}
+
+static int ad5592r_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int value)
+{
+	struct ad5592r_state *st = gpiochip_to_ad5592r(chip);
+	int ret;
+
+	mutex_lock(&st->gpio_lock);
+
+	if (value)
+		st->gpio_val |= BIT(offset);
+	else
+		st->gpio_val &= ~BIT(offset);
+
+	st->gpio_in &= ~BIT(offset);
+	st->gpio_out |= BIT(offset);
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
+	if (ret < 0)
+		goto err_unlock;
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
+	if (ret < 0)
+		goto err_unlock;
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
+
+err_unlock:
+	mutex_unlock(&st->gpio_lock);
+
+	return ret;
+}
+
+static int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct ad5592r_state *st = gpiochip_to_ad5592r(chip);
+
+	if (!(st->gpio_map & BIT(offset))) {
+		dev_err(st->dev, "GPIO %d is reserved by alternate function\n",
+			offset);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int ad5592r_gpio_init(struct ad5592r_state *st)
+{
+	if (!st->gpio_map)
+		return 0;
+
+	st->gpiochip.label = dev_name(st->dev);
+	st->gpiochip.base = -1;
+	st->gpiochip.ngpio = 8;
+	st->gpiochip.dev = st->dev;
+	st->gpiochip.can_sleep = true;
+	st->gpiochip.direction_input = ad5592r_gpio_direction_input;
+	st->gpiochip.direction_output = ad5592r_gpio_direction_output;
+	st->gpiochip.get = ad5592r_gpio_get;
+	st->gpiochip.set = ad5592r_gpio_set;
+	st->gpiochip.request = ad5592r_gpio_request;
+	st->gpiochip.owner = THIS_MODULE;
+
+	mutex_init(&st->gpio_lock);
+
+	return gpiochip_add(&st->gpiochip);
+}
+
+static void ad5592r_gpio_cleanup(struct ad5592r_state *st)
+{
+	if (st->gpio_map)
+		gpiochip_remove(&st->gpiochip);
+}
+
+static int ad5592r_reset(struct ad5592r_state *st)
+{
+	struct gpio_desc *gpio;
+	struct iio_dev *iio_dev = iio_priv_to_dev(st);
+
+	gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(gpio))
+		return PTR_ERR(gpio);
+
+	if (gpio) {
+		udelay(1);
+		gpiod_set_value(gpio, 1);
+	} else {
+		mutex_lock(&iio_dev->mlock);
+		/* Writing this magic value resets the device */
+		st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac);
+		mutex_unlock(&iio_dev->mlock);
+	}
+
+	udelay(250);
+
+	return 0;
+}
+
+static int ad5592r_get_vref(struct ad5592r_state *st)
+{
+	int ret;
+
+	if (st->reg) {
+		ret = regulator_get_voltage(st->reg);
+		if (ret < 0)
+			return ret;
+
+		return ret / 1000;
+	} else {
+		return 2500;
+	}
+}
+
+static int ad5592r_set_channel_modes(struct ad5592r_state *st)
+{
+	const struct ad5592r_rw_ops *ops = st->ops;
+	int ret;
+	unsigned i;
+	struct iio_dev *iio_dev = iio_priv_to_dev(st);
+	u8 pulldown = 0, tristate = 0, dac = 0, adc = 0;
+	u16 read_back;
+
+	for (i = 0; i < st->num_channels; i++) {
+		switch (st->channel_modes[i]) {
+		case CH_MODE_DAC:
+			dac |= BIT(i);
+			break;
+
+		case CH_MODE_ADC:
+			adc |= BIT(i);
+			break;
+
+		case CH_MODE_DAC_AND_ADC:
+			dac |= BIT(i);
+			adc |= BIT(i);
+			break;
+
+		case CH_MODE_GPIO:
+			st->gpio_map |= BIT(i);
+			st->gpio_in |= BIT(i); /* Default to input */
+			break;
+
+		case CH_MODE_UNUSED:
+			/* fall-through */
+		default:
+			switch (st->channel_offstate[i]) {
+			case CH_OFFSTATE_OUT_TRISTATE:
+				tristate |= BIT(i);
+				break;
+
+			case CH_OFFSTATE_OUT_LOW:
+				st->gpio_out |= BIT(i);
+				break;
+
+			case CH_OFFSTATE_OUT_HIGH:
+				st->gpio_out |= BIT(i);
+				st->gpio_val |= BIT(i);
+				break;
+
+			case CH_OFFSTATE_PULLDOWN:
+				/* fall-through */
+			default:
+				pulldown |= BIT(i);
+				break;
+			}
+		}
+	}
+
+	mutex_lock(&iio_dev->mlock);
+
+	/* Pull down unused pins to GND */
+	ret = ops->reg_write(st, AD5592R_REG_PULLDOWN, pulldown);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_TRISTATE, tristate);
+	if (ret)
+		goto err_unlock;
+
+	/* Configure pins that we use */
+	ret = ops->reg_write(st, AD5592R_REG_DAC_EN, dac);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_ADC_EN, adc);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
+	if (ret)
+		goto err_unlock;
+
+	/* Verify that we can read back at least one register */
+	ret = ops->reg_read(st, AD5592R_REG_ADC_EN, &read_back);
+	if (!ret && (read_back & 0xff) != adc)
+		ret = -EIO;
+
+err_unlock:
+	mutex_unlock(&iio_dev->mlock);
+	return ret;
+}
+
+static int ad5592r_reset_channel_modes(struct ad5592r_state *st)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(st->channel_modes); i++)
+		st->channel_modes[i] = CH_MODE_UNUSED;
+
+	return ad5592r_set_channel_modes(st);
+}
+
+static int ad5592r_write_raw(struct iio_dev *iio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	struct ad5592r_state *st = iio_priv(iio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		if (!chan->output)
+			return -EINVAL;
+
+		mutex_lock(&iio_dev->mlock);
+		ret = st->ops->write_dac(st, chan->channel, val);
+		if (!ret)
+			st->cached_dac[chan->channel] = val;
+		mutex_unlock(&iio_dev->mlock);
+		return ret;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_VOLTAGE) {
+			bool gain;
+
+			if (val == st->scale_avail[0][0] &&
+				val2 == st->scale_avail[0][1])
+				gain = false;
+			else if (val == st->scale_avail[1][0] &&
+				 val2 == st->scale_avail[1][1])
+				gain = true;
+			else
+				return -EINVAL;
+
+			mutex_lock(&iio_dev->mlock);
+
+			ret = st->ops->reg_read(st, AD5592R_REG_CTRL,
+						&st->cached_gp_ctrl);
+			if (ret < 0) {
+				mutex_unlock(&iio_dev->mlock);
+				return ret;
+			}
+
+			if (chan->output) {
+				if (gain)
+					st->cached_gp_ctrl |=
+						AD5592R_REG_CTRL_DAC_RANGE;
+				else
+					st->cached_gp_ctrl &=
+						~AD5592R_REG_CTRL_DAC_RANGE;
+			} else {
+				if (gain)
+					st->cached_gp_ctrl |=
+						AD5592R_REG_CTRL_ADC_RANGE;
+				else
+					st->cached_gp_ctrl &=
+						~AD5592R_REG_CTRL_ADC_RANGE;
+			}
+
+			ret = st->ops->reg_write(st, AD5592R_REG_CTRL,
+						 st->cached_gp_ctrl);
+			mutex_unlock(&iio_dev->mlock);
+
+			return ret;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ad5592r_read_raw(struct iio_dev *iio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long m)
+{
+	struct ad5592r_state *st = iio_priv(iio_dev);
+	u16 read_val;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&iio_dev->mlock);
+
+		if (!chan->output) {
+			ret = st->ops->read_adc(st, chan->channel, &read_val);
+			if (ret)
+				goto unlock;
+
+			if ((read_val >> 12 & 0x7) != (chan->channel & 0x7)) {
+				dev_err(st->dev, "Error while reading channel %u\n",
+						chan->channel);
+				ret = -EIO;
+				goto unlock;
+			}
+
+			read_val &= GENMASK(11, 0);
+
+		} else {
+			read_val = st->cached_dac[chan->channel];
+		}
+
+		dev_dbg(st->dev, "Channel %u read: 0x%04hX\n",
+				chan->channel, read_val);
+
+		*val = (int) read_val;
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = ad5592r_get_vref(st);
+
+		if (chan->type == IIO_TEMP) {
+			s64 tmp = *val * (3767897513LL / 25LL);
+			*val = div_s64_rem(tmp, 1000000000LL, val2);
+
+			ret = IIO_VAL_INT_PLUS_MICRO;
+		} else {
+			int mult;
+
+			mutex_lock(&iio_dev->mlock);
+
+			if (chan->output)
+				mult = !!(st->cached_gp_ctrl &
+					AD5592R_REG_CTRL_DAC_RANGE);
+			else
+				mult = !!(st->cached_gp_ctrl &
+					AD5592R_REG_CTRL_ADC_RANGE);
+
+			*val *= ++mult;
+
+			*val2 = chan->scan_type.realbits;
+			ret = IIO_VAL_FRACTIONAL_LOG2;
+		}
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		ret = ad5592r_get_vref(st);
+
+		mutex_lock(&iio_dev->mlock);
+
+		if (st->cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE)
+			*val = (-34365 * 25) / ret;
+		else
+			*val = (-75365 * 25) / ret;
+		ret =  IIO_VAL_INT;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+unlock:
+	mutex_unlock(&iio_dev->mlock);
+	return ret;
+}
+
+static int ad5592r_write_raw_get_fmt(struct iio_dev *indio_dev,
+				 struct iio_chan_spec const *chan, long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+
+	default:
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ad5592r_info = {
+	.read_raw = ad5592r_read_raw,
+	.write_raw = ad5592r_write_raw,
+	.write_raw_get_fmt = ad5592r_write_raw_get_fmt,
+	.driver_module = THIS_MODULE,
+};
+
+static ssize_t ad5592r_show_scale_available(struct iio_dev *iio_dev,
+					   uintptr_t private,
+					   const struct iio_chan_spec *chan,
+					   char *buf)
+{
+	struct ad5592r_state *st = iio_priv(iio_dev);
+
+	return sprintf(buf, "%d.%09u %d.%09u\n",
+		st->scale_avail[0][0], st->scale_avail[0][1],
+		st->scale_avail[1][0], st->scale_avail[1][1]);
+}
+
+static struct iio_chan_spec_ext_info ad5592r_ext_info[] = {
+	{
+	 .name = "scale_available",
+	 .read = ad5592r_show_scale_available,
+	 .shared = true,
+	 },
+	{},
+};
+
+static void ad5592r_setup_channel(struct iio_dev *iio_dev,
+		struct iio_chan_spec *chan, bool output, unsigned id)
+{
+	chan->type = IIO_VOLTAGE;
+	chan->indexed = 1;
+	chan->output = output;
+	chan->channel = id;
+	chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+	chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+	chan->scan_type.sign = 'u';
+	chan->scan_type.realbits = 12;
+	chan->scan_type.storagebits = 16;
+	chan->ext_info = ad5592r_ext_info;
+}
+
+static int ad5592r_alloc_channels(struct ad5592r_state *st)
+{
+	unsigned i, curr_channel = 0,
+		 num_channels = st->num_channels;
+	struct iio_dev *iio_dev = iio_priv_to_dev(st);
+	struct iio_chan_spec *channels;
+	struct fwnode_handle *child;
+	u32 reg, tmp;
+	int ret;
+
+	device_for_each_child_node(st->dev, child) {
+		ret = fwnode_property_read_u32(child, "reg", &reg);
+		if (ret || reg >= ARRAY_SIZE(st->channel_modes))
+			continue;
+
+		ret = fwnode_property_read_u32(child, "adi,mode", &tmp);
+		if (!ret)
+			st->channel_modes[reg] = tmp;
+
+		fwnode_property_read_u32(child, "adi,off-state", &tmp);
+		if (!ret)
+			st->channel_offstate[reg] = tmp;
+	}
+
+	channels = devm_kzalloc(st->dev,
+			(1 + 2 * num_channels) * sizeof(*channels), GFP_KERNEL);
+	if (!channels)
+		return -ENOMEM;
+
+	for (i = 0; i < num_channels; i++) {
+		switch (st->channel_modes[i]) {
+		case CH_MODE_DAC:
+			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
+					true, i);
+			curr_channel++;
+			break;
+
+		case CH_MODE_ADC:
+			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
+					false, i);
+			curr_channel++;
+			break;
+
+		case CH_MODE_DAC_AND_ADC:
+			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
+					true, i);
+			curr_channel++;
+			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
+					false, i);
+			curr_channel++;
+			break;
+
+		default:
+			continue;
+		}
+	}
+
+	channels[curr_channel].type = IIO_TEMP;
+	channels[curr_channel].channel = 8;
+	channels[curr_channel].info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				   BIT(IIO_CHAN_INFO_SCALE) |
+				   BIT(IIO_CHAN_INFO_OFFSET);
+	curr_channel++;
+
+	iio_dev->num_channels = curr_channel;
+	iio_dev->channels = channels;
+
+	return 0;
+}
+
+static void ad5592r_init_scales(struct ad5592r_state *st, int vref_mV)
+{
+	s64 tmp = (s64)vref_mV * 1000000000LL >> 12;
+
+	st->scale_avail[0][0] =
+		div_s64_rem(tmp, 1000000000LL, &st->scale_avail[0][1]);
+	st->scale_avail[1][0] =
+		div_s64_rem(tmp * 2, 1000000000LL, &st->scale_avail[1][1]);
+}
+
+int ad5592r_probe(struct device *dev, const char *name,
+		const struct ad5592r_rw_ops *ops)
+{
+	struct iio_dev *iio_dev;
+	struct ad5592r_state *st;
+	int ret;
+
+	iio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+	if (!iio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(iio_dev);
+	st->dev = dev;
+	st->ops = ops;
+	st->num_channels = 8;
+	dev_set_drvdata(dev, iio_dev);
+
+	st->reg = devm_regulator_get_optional(dev, "vref");
+	if (IS_ERR(st->reg)) {
+		if ((PTR_ERR(st->reg) != -ENODEV) && dev->of_node)
+			return PTR_ERR(st->reg);
+
+		st->reg = NULL;
+	} else {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			return ret;
+	}
+
+	iio_dev->dev.parent = dev;
+	iio_dev->name = name;
+	iio_dev->info = &ad5592r_info;
+	iio_dev->modes = INDIO_DIRECT_MODE;
+
+	ad5592r_init_scales(st, ad5592r_get_vref(st));
+
+	ret = ad5592r_reset(st);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = ops->reg_write(st, AD5592R_REG_PD,
+		     (st->reg == NULL) ? AD5592R_REG_PD_EN_REF : 0);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = ad5592r_alloc_channels(st);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = ad5592r_set_channel_modes(st);
+	if (ret)
+		goto error_reset_ch_modes;
+
+	ret = iio_device_register(iio_dev);
+	if (ret)
+		goto error_reset_ch_modes;
+
+	ret = ad5592r_gpio_init(st);
+	if (ret)
+		goto error_dev_unregister;
+
+	return 0;
+
+error_dev_unregister:
+	iio_device_unregister(iio_dev);
+
+error_reset_ch_modes:
+	ad5592r_reset_channel_modes(st);
+
+error_disable_reg:
+	if (st->reg)
+		regulator_disable(st->reg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ad5592r_probe);
+
+int ad5592r_remove(struct device *dev)
+{
+	struct iio_dev *iio_dev = dev_get_drvdata(dev);
+	struct ad5592r_state *st = iio_priv(iio_dev);
+
+	iio_device_unregister(iio_dev);
+	ad5592r_reset_channel_modes(st);
+	ad5592r_gpio_cleanup(st);
+
+	if (st->reg)
+		regulator_disable(st->reg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ad5592r_remove);
+
+MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/dac/ad5592r-base.h
+++ linux-4.4.0/drivers/iio/dac/ad5592r-base.h
@@ -0,0 +1,76 @@
+/*
+ * AD5592R / AD5593R Digital <-> Analog converters driver
+ *
+ * Copyright 2015-2016 Analog Devices Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __DRIVERS_IIO_DAC_AD5592R_BASE_H__
+#define __DRIVERS_IIO_DAC_AD5592R_BASE_H__
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include <linux/gpio/driver.h>
+
+struct device;
+struct ad5592r_state;
+
+enum ad5592r_registers {
+	AD5592R_REG_NOOP		= 0x0,
+	AD5592R_REG_DAC_READBACK	= 0x1,
+	AD5592R_REG_ADC_SEQ		= 0x2,
+	AD5592R_REG_CTRL		= 0x3,
+	AD5592R_REG_ADC_EN		= 0x4,
+	AD5592R_REG_DAC_EN		= 0x5,
+	AD5592R_REG_PULLDOWN		= 0x6,
+	AD5592R_REG_LDAC		= 0x7,
+	AD5592R_REG_GPIO_OUT_EN		= 0x8,
+	AD5592R_REG_GPIO_SET		= 0x9,
+	AD5592R_REG_GPIO_IN_EN		= 0xA,
+	AD5592R_REG_PD			= 0xB,
+	AD5592R_REG_OPEN_DRAIN		= 0xC,
+	AD5592R_REG_TRISTATE		= 0xD,
+	AD5592R_REG_RESET		= 0xF,
+};
+
+#define AD5592R_REG_PD_EN_REF		BIT(9)
+#define AD5592R_REG_CTRL_ADC_RANGE	BIT(5)
+#define AD5592R_REG_CTRL_DAC_RANGE	BIT(4)
+
+struct ad5592r_rw_ops {
+	int (*write_dac)(struct ad5592r_state *st, unsigned chan, u16 value);
+	int (*read_adc)(struct ad5592r_state *st, unsigned chan, u16 *value);
+	int (*reg_write)(struct ad5592r_state *st, u8 reg, u16 value);
+	int (*reg_read)(struct ad5592r_state *st, u8 reg, u16 *value);
+	int (*gpio_read)(struct ad5592r_state *st, u8 *value);
+};
+
+struct ad5592r_state {
+	struct device *dev;
+	struct regulator *reg;
+	struct gpio_chip gpiochip;
+	struct mutex gpio_lock;	/* Protect cached gpio_out, gpio_val, etc. */
+	unsigned int num_channels;
+	const struct ad5592r_rw_ops *ops;
+	int scale_avail[2][2];
+	u16 cached_dac[8];
+	u16 cached_gp_ctrl;
+	u8 channel_modes[8];
+	u8 channel_offstate[8];
+	u8 gpio_map;
+	u8 gpio_out;
+	u8 gpio_in;
+	u8 gpio_val;
+
+	__be16 spi_msg ____cacheline_aligned;
+	__be16 spi_msg_nop;
+};
+
+int ad5592r_probe(struct device *dev, const char *name,
+		const struct ad5592r_rw_ops *ops);
+int ad5592r_remove(struct device *dev);
+
+#endif /* __DRIVERS_IIO_DAC_AD5592R_BASE_H__ */
--- linux-4.4.0.orig/drivers/iio/dac/ad5592r.c
+++ linux-4.4.0/drivers/iio/dac/ad5592r.c
@@ -0,0 +1,172 @@
+/*
+ * AD5592R Digital <-> Analog converters driver
+ *
+ * Copyright 2015-2016 Analog Devices Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include "ad5592r-base.h"
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+
+#define AD5592R_GPIO_READBACK_EN	BIT(10)
+#define AD5592R_LDAC_READBACK_EN	BIT(6)
+
+static int ad5592r_spi_wnop_r16(struct ad5592r_state *st, u16 *buf)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+	struct spi_transfer t = {
+			.tx_buf	= &st->spi_msg_nop,
+			.rx_buf	= buf,
+			.len = 2
+		};
+
+	st->spi_msg_nop = 0; /* NOP */
+
+	return spi_sync_transfer(spi, &t, 1);
+}
+
+static int ad5592r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+
+	st->spi_msg = cpu_to_be16(BIT(15) | (chan << 12) | value);
+
+	return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
+}
+
+static int ad5592r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+	int ret;
+
+	st->spi_msg = cpu_to_be16((AD5592R_REG_ADC_SEQ << 11) | BIT(chan));
+
+	ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
+	if (ret)
+		return ret;
+
+	/*
+	 * Invalid data:
+	 * See Figure 40. Single-Channel ADC Conversion Sequence
+	 */
+	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
+	if (ret)
+		return ret;
+
+	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
+	if (ret)
+		return ret;
+
+	*value = be16_to_cpu(st->spi_msg);
+
+	return 0;
+}
+
+static int ad5592r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+
+	st->spi_msg = cpu_to_be16((reg << 11) | value);
+
+	return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
+}
+
+static int ad5592r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+	int ret;
+
+	st->spi_msg = cpu_to_be16((AD5592R_REG_LDAC << 11) |
+				   AD5592R_LDAC_READBACK_EN | (reg << 2));
+
+	ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
+	if (ret)
+		return ret;
+
+	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
+	if (ret)
+		return ret;
+
+	*value = be16_to_cpu(st->spi_msg);
+
+	return 0;
+}
+
+static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
+{
+	int ret;
+
+	ret = ad5592r_reg_write(st, AD5592R_REG_GPIO_IN_EN,
+				AD5592R_GPIO_READBACK_EN | st->gpio_in);
+	if (ret)
+		return ret;
+
+	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
+	if (ret)
+		return ret;
+
+	*value = (u8) be16_to_cpu(st->spi_msg);
+
+	return 0;
+}
+
+static const struct ad5592r_rw_ops ad5592r_rw_ops = {
+	.write_dac = ad5592r_write_dac,
+	.read_adc = ad5592r_read_adc,
+	.reg_write = ad5592r_reg_write,
+	.reg_read = ad5592r_reg_read,
+	.gpio_read = ad5593r_gpio_read,
+};
+
+static int ad5592r_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+
+	return ad5592r_probe(&spi->dev, id->name, &ad5592r_rw_ops);
+}
+
+static int ad5592r_spi_remove(struct spi_device *spi)
+{
+	return ad5592r_remove(&spi->dev);
+}
+
+static const struct spi_device_id ad5592r_spi_ids[] = {
+	{ .name = "ad5592r", },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5592r_spi_ids);
+
+static const struct of_device_id ad5592r_of_match[] = {
+	{ .compatible = "adi,ad5592r", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ad5592r_of_match);
+
+static const struct acpi_device_id ad5592r_acpi_match[] = {
+	{"ADS5592", },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, ad5592r_acpi_match);
+
+static struct spi_driver ad5592r_spi_driver = {
+	.driver = {
+		.name = "ad5592r",
+		.of_match_table = of_match_ptr(ad5592r_of_match),
+		.acpi_match_table = ACPI_PTR(ad5592r_acpi_match),
+	},
+	.probe = ad5592r_spi_probe,
+	.remove = ad5592r_spi_remove,
+	.id_table = ad5592r_spi_ids,
+};
+module_spi_driver(ad5592r_spi_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/dac/ad5593r.c
+++ linux-4.4.0/drivers/iio/dac/ad5593r.c
@@ -0,0 +1,139 @@
+/*
+ * AD5593R Digital <-> Analog converters driver
+ *
+ * Copyright 2015-2016 Analog Devices Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include "ad5592r-base.h"
+
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/acpi.h>
+
+#define AD5593R_MODE_CONF		(0 << 4)
+#define AD5593R_MODE_DAC_WRITE		(1 << 4)
+#define AD5593R_MODE_ADC_READBACK	(4 << 4)
+#define AD5593R_MODE_DAC_READBACK	(5 << 4)
+#define AD5593R_MODE_GPIO_READBACK	(6 << 4)
+#define AD5593R_MODE_REG_READBACK	(7 << 4)
+
+static int ad5593r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+
+	return i2c_smbus_write_word_swapped(i2c,
+			AD5593R_MODE_DAC_WRITE | chan, value);
+}
+
+static int ad5593r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+	s32 val;
+
+	val = i2c_smbus_write_word_swapped(i2c,
+			AD5593R_MODE_CONF | AD5592R_REG_ADC_SEQ, BIT(chan));
+	if (val < 0)
+		return (int) val;
+
+	val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_ADC_READBACK);
+	if (val < 0)
+		return (int) val;
+
+	*value = (u16) val;
+
+	return 0;
+}
+
+static int ad5593r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+
+	return i2c_smbus_write_word_swapped(i2c,
+			AD5593R_MODE_CONF | reg, value);
+}
+
+static int ad5593r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+	s32 val;
+
+	val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_REG_READBACK | reg);
+	if (val < 0)
+		return (int) val;
+
+	*value = (u16) val;
+
+	return 0;
+}
+
+static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+	s32 val;
+
+	val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_GPIO_READBACK);
+	if (val < 0)
+		return (int) val;
+
+	*value = (u8) val;
+
+	return 0;
+}
+
+static const struct ad5592r_rw_ops ad5593r_rw_ops = {
+	.write_dac = ad5593r_write_dac,
+	.read_adc = ad5593r_read_adc,
+	.reg_write = ad5593r_reg_write,
+	.reg_read = ad5593r_reg_read,
+	.gpio_read = ad5593r_gpio_read,
+};
+
+static int ad5593r_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	return ad5592r_probe(&i2c->dev, id->name, &ad5593r_rw_ops);
+}
+
+static int ad5593r_i2c_remove(struct i2c_client *i2c)
+{
+	return ad5592r_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id ad5593r_i2c_ids[] = {
+	{ .name = "ad5593r", },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ad5593r_i2c_ids);
+
+static const struct of_device_id ad5593r_of_match[] = {
+	{ .compatible = "adi,ad5593r", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ad5593r_of_match);
+
+static const struct acpi_device_id ad5593r_acpi_match[] = {
+	{"ADS5593", },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, ad5593r_acpi_match);
+
+static struct i2c_driver ad5593r_driver = {
+	.driver = {
+		.name = "ad5593r",
+		.of_match_table = of_match_ptr(ad5593r_of_match),
+		.acpi_match_table = ACPI_PTR(ad5593r_acpi_match),
+	},
+	.probe = ad5593r_i2c_probe,
+	.remove = ad5593r_i2c_remove,
+	.id_table = ad5593r_i2c_ids,
+};
+module_i2c_driver(ad5593r_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/dac/ad7303.c
+++ linux-4.4.0/drivers/iio/dac/ad7303.c
@@ -184,9 +184,9 @@
 	.address = (chan),					\
 	.scan_type = {						\
 		.sign = 'u',					\
-		.realbits = '8',				\
-		.storagebits = '8',				\
-		.shift = '0',					\
+		.realbits = 8,					\
+		.storagebits = 8,				\
+		.shift = 0,					\
 	},							\
 	.ext_info = ad7303_ext_info,				\
 }
--- linux-4.4.0.orig/drivers/iio/dac/mcp4725.c
+++ linux-4.4.0/drivers/iio/dac/mcp4725.c
@@ -300,6 +300,7 @@
 	data->client = client;
 
 	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = id->name;
 	indio_dev->info = &mcp4725_info;
 	indio_dev->channels = &mcp4725_channel;
 	indio_dev->num_channels = 1;
--- linux-4.4.0.orig/drivers/iio/dac/mcp4922.c
+++ linux-4.4.0/drivers/iio/dac/mcp4922.c
@@ -94,17 +94,22 @@
 		long mask)
 {
 	struct mcp4922_state *state = iio_priv(indio_dev);
+	int ret;
 
 	if (val2 != 0)
 		return -EINVAL;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		if (val > GENMASK(chan->scan_type.realbits-1, 0))
+		if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
 			return -EINVAL;
 		val <<= chan->scan_type.shift;
-		state->value[chan->channel] = val;
-		return mcp4922_spi_write(state, chan->channel, val);
+
+		ret = mcp4922_spi_write(state, chan->channel, val);
+		if (!ret)
+			state->value[chan->channel] = val;
+		return ret;
+
 	default:
 		return -EINVAL;
 	}
--- linux-4.4.0.orig/drivers/iio/frequency/ad9523.c
+++ linux-4.4.0/drivers/iio/frequency/ad9523.c
@@ -507,7 +507,7 @@
 		return ret;
 
 	if (!state)
-		return 0;
+		return len;
 
 	mutex_lock(&indio_dev->mlock);
 	switch ((u32)this_attr->address) {
@@ -641,7 +641,7 @@
 		code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) /
 			AD9523_CLK_DIST_DIV_REV(ret);
 		*val = code / 1000000;
-		*val2 = (code % 1000000) * 10;
+		*val2 = code % 1000000;
 		return IIO_VAL_INT_PLUS_MICRO;
 	default:
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/iio/gyro/bmg160_core.c
+++ linux-4.4.0/drivers/iio/gyro/bmg160_core.c
@@ -28,6 +28,7 @@
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
 #include <linux/regmap.h>
+#include <linux/delay.h>
 #include "bmg160.h"
 
 #define BMG160_IRQ_NAME		"bmg160_event"
@@ -53,6 +54,9 @@
 #define BMG160_NO_FILTER		0
 #define BMG160_DEF_BW			100
 
+#define BMG160_GYRO_REG_RESET		0x14
+#define BMG160_GYRO_RESET_VAL		0xb6
+
 #define BMG160_REG_INT_MAP_0		0x17
 #define BMG160_INT_MAP_0_BIT_ANY	BIT(1)
 
@@ -186,6 +190,14 @@
 	int ret;
 	unsigned int val;
 
+	/*
+	 * Reset chip to get it in a known good state. A delay of 30ms after
+	 * reset is required according to the datasheet.
+	 */
+	regmap_write(data->regmap, BMG160_GYRO_REG_RESET,
+		     BMG160_GYRO_RESET_VAL);
+	usleep_range(30000, 30700);
+
 	ret = regmap_read(data->regmap, BMG160_REG_CHIP_ID, &val);
 	if (ret < 0) {
 		dev_err(data->dev, "Error reading reg_chip_id\n");
@@ -452,7 +464,7 @@
 static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
 {
 	int ret;
-	unsigned int raw_val;
+	__le16 raw_val;
 
 	mutex_lock(&data->mutex);
 	ret = bmg160_set_power_state(data, true);
@@ -462,7 +474,7 @@
 	}
 
 	ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(axis), &raw_val,
-			       2);
+			       sizeof(raw_val));
 	if (ret < 0) {
 		dev_err(data->dev, "Error reading axis %d\n", axis);
 		bmg160_set_power_state(data, false);
@@ -470,7 +482,7 @@
 		return ret;
 	}
 
-	*val = sign_extend32(raw_val, 15);
+	*val = sign_extend32(le16_to_cpu(raw_val), 15);
 	ret = bmg160_set_power_state(data, false);
 	mutex_unlock(&data->mutex);
 	if (ret < 0)
@@ -507,11 +519,10 @@
 		} else
 			return -EINVAL;
 	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
 		switch (chan->type) {
 		case IIO_TEMP:
-			*val2 = 500000;
-			return IIO_VAL_INT_PLUS_MICRO;
+			*val = 500;
+			return IIO_VAL_INT;
 		case IIO_ANGL_VEL:
 		{
 			int i;
@@ -519,6 +530,7 @@
 			for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) {
 				if (bmg160_scale_table[i].dps_range ==
 							data->dps_range) {
+					*val = 0;
 					*val2 = bmg160_scale_table[i].scale;
 					return IIO_VAL_INT_PLUS_MICRO;
 				}
@@ -733,6 +745,7 @@
 		.sign = 's',						\
 		.realbits = 16,					\
 		.storagebits = 16,					\
+		.endianness = IIO_LE,					\
 	},								\
 	.event_spec = &bmg160_event,					\
 	.num_event_specs = 1						\
@@ -780,7 +793,7 @@
 			mutex_unlock(&data->mutex);
 			goto err;
 		}
-		data->buffer[i++] = ret;
+		data->buffer[i++] = val;
 	}
 	mutex_unlock(&data->mutex);
 
--- linux-4.4.0.orig/drivers/iio/gyro/itg3200_buffer.c
+++ linux-4.4.0/drivers/iio/gyro/itg3200_buffer.c
@@ -49,13 +49,20 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct itg3200 *st = iio_priv(indio_dev);
-	__be16 buf[ITG3200_SCAN_ELEMENTS + sizeof(s64)/sizeof(u16)];
+	/*
+	 * Ensure correct alignment and padding including for the
+	 * timestamp that may be inserted.
+	 */
+	struct {
+		__be16 buf[ITG3200_SCAN_ELEMENTS];
+		s64 ts __aligned(8);
+	} scan;
 
-	int ret = itg3200_read_all_channels(st->i2c, buf);
+	int ret = itg3200_read_all_channels(st->i2c, scan.buf);
 	if (ret < 0)
 		goto error_ret;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp);
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp);
 
 	iio_trigger_notify_done(indio_dev->trig);
 
--- linux-4.4.0.orig/drivers/iio/gyro/st_gyro_buffer.c
+++ linux-4.4.0/drivers/iio/gyro/st_gyro_buffer.c
@@ -91,7 +91,7 @@
 
 int st_gyro_allocate_ring(struct iio_dev *indio_dev)
 {
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+	return iio_triggered_buffer_setup(indio_dev, NULL,
 		&st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
 }
 
--- linux-4.4.0.orig/drivers/iio/gyro/st_gyro_core.c
+++ linux-4.4.0/drivers/iio/gyro/st_gyro_core.c
@@ -185,6 +185,12 @@
 		.drdy_irq = {
 			.addr = ST_GYRO_1_DRDY_IRQ_ADDR,
 			.mask_int2 = ST_GYRO_1_DRDY_IRQ_INT2_MASK,
+			/*
+			 * The sensor has IHL (active low) and open
+			 * drain settings, but only for INT1 and not
+			 * for the DRDY line on INT2.
+			 */
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_GYRO_1_MULTIREAD_BIT,
 		.bootime = 2,
@@ -248,6 +254,12 @@
 		.drdy_irq = {
 			.addr = ST_GYRO_2_DRDY_IRQ_ADDR,
 			.mask_int2 = ST_GYRO_2_DRDY_IRQ_INT2_MASK,
+			/*
+			 * The sensor has IHL (active low) and open
+			 * drain settings, but only for INT1 and not
+			 * for the DRDY line on INT2.
+			 */
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
 		.bootime = 2,
@@ -307,6 +319,12 @@
 		.drdy_irq = {
 			.addr = ST_GYRO_3_DRDY_IRQ_ADDR,
 			.mask_int2 = ST_GYRO_3_DRDY_IRQ_INT2_MASK,
+			/*
+			 * The sensor has IHL (active low) and open
+			 * drain settings, but only for INT1 and not
+			 * for the DRDY line on INT2.
+			 */
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_GYRO_3_MULTIREAD_BIT,
 		.bootime = 2,
@@ -390,6 +408,7 @@
 static const struct iio_trigger_ops st_gyro_trigger_ops = {
 	.owner = THIS_MODULE,
 	.set_trigger_state = ST_GYRO_TRIGGER_SET_STATE,
+	.validate_device = st_sensors_validate_device,
 };
 #define ST_GYRO_TRIGGER_OPS (&st_gyro_trigger_ops)
 #else
@@ -406,13 +425,15 @@
 	indio_dev->info = &gyro_info;
 	mutex_init(&gdata->tb.buf_lock);
 
-	st_sensors_power_enable(indio_dev);
+	err = st_sensors_power_enable(indio_dev);
+	if (err)
+		return err;
 
 	err = st_sensors_check_device_support(indio_dev,
 					ARRAY_SIZE(st_gyro_sensors_settings),
 					st_gyro_sensors_settings);
 	if (err < 0)
-		return err;
+		goto st_gyro_power_off;
 
 	gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS;
 	gdata->multiread_bit = gdata->sensor_settings->multi_read_bit;
@@ -426,11 +447,11 @@
 	err = st_sensors_init_sensor(indio_dev,
 				(struct st_sensors_platform_data *)&gyro_pdata);
 	if (err < 0)
-		return err;
+		goto st_gyro_power_off;
 
 	err = st_gyro_allocate_ring(indio_dev);
 	if (err < 0)
-		return err;
+		goto st_gyro_power_off;
 
 	if (irq > 0) {
 		err = st_sensors_allocate_trigger(indio_dev,
@@ -453,6 +474,8 @@
 		st_sensors_deallocate_trigger(indio_dev);
 st_gyro_probe_trigger_error:
 	st_gyro_deallocate_ring(indio_dev);
+st_gyro_power_off:
+	st_sensors_power_disable(indio_dev);
 
 	return err;
 }
--- linux-4.4.0.orig/drivers/iio/humidity/Kconfig
+++ linux-4.4.0/drivers/iio/humidity/Kconfig
@@ -22,6 +22,28 @@
 	 To compile this driver as a module, choose M here: the module
 	 will be called hdc100x.
 
+config HTS221
+	tristate "STMicroelectronics HTS221 sensor Driver"
+	depends on (I2C || SPI)
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HTS221_I2C if (I2C)
+	select HTS221_SPI if (SPI_MASTER)
+	help
+	  Say yes here to build support for STMicroelectronics HTS221
+	  temperature-humidity sensor
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called hts221.
+
+config HTS221_I2C
+	tristate
+	depends on HTS221
+
+config HTS221_SPI
+	tristate
+	depends on HTS221
+
 config HTU21
 	tristate "Measurement Specialties HTU21 humidity & temperature sensor"
 	depends on I2C
--- linux-4.4.0.orig/drivers/iio/humidity/Makefile
+++ linux-4.4.0/drivers/iio/humidity/Makefile
@@ -4,6 +4,13 @@
 
 obj-$(CONFIG_DHT11) += dht11.o
 obj-$(CONFIG_HDC100X) += hdc100x.o
+
+hts221-y := hts221_core.o \
+	    hts221_buffer.o
+obj-$(CONFIG_HTS221) += hts221.o
+obj-$(CONFIG_HTS221_I2C) += hts221_i2c.o
+obj-$(CONFIG_HTS221_SPI) += hts221_spi.o
+
 obj-$(CONFIG_HTU21) += htu21.o
 obj-$(CONFIG_SI7005) += si7005.o
 obj-$(CONFIG_SI7020) += si7020.o
--- linux-4.4.0.orig/drivers/iio/humidity/hdc100x.c
+++ linux-4.4.0/drivers/iio/humidity/hdc100x.c
@@ -55,7 +55,7 @@
 	},
 	{ /* IIO_HUMIDITYRELATIVE channel */
 		.shift = 8,
-		.mask = 2,
+		.mask = 3,
 	},
 };
 
@@ -164,14 +164,14 @@
 		dev_err(&client->dev, "cannot read high byte measurement");
 		return ret;
 	}
-	val = ret << 6;
+	val = ret << 8;
 
 	ret = i2c_smbus_read_byte(client);
 	if (ret < 0) {
 		dev_err(&client->dev, "cannot read low byte measurement");
 		return ret;
 	}
-	val |= ret >> 2;
+	val |= ret;
 
 	return val;
 }
@@ -211,18 +211,18 @@
 		return IIO_VAL_INT_PLUS_MICRO;
 	case IIO_CHAN_INFO_SCALE:
 		if (chan->type == IIO_TEMP) {
-			*val = 165;
-			*val2 = 65536 >> 2;
+			*val = 165000;
+			*val2 = 65536;
 			return IIO_VAL_FRACTIONAL;
 		} else {
-			*val = 0;
-			*val2 = 10000;
-			return IIO_VAL_INT_PLUS_MICRO;
+			*val = 100000;
+			*val2 = 65536;
+			return IIO_VAL_FRACTIONAL;
 		}
 		break;
 	case IIO_CHAN_INFO_OFFSET:
-		*val = -3971;
-		*val2 = 879096;
+		*val = -15887;
+		*val2 = 515151;
 		return IIO_VAL_INT_PLUS_MICRO;
 	default:
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/iio/humidity/hts221.h
+++ linux-4.4.0/drivers/iio/humidity/hts221.h
@@ -0,0 +1,73 @@
+/*
+ * STMicroelectronics hts221 sensor driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef HTS221_H
+#define HTS221_H
+
+#define HTS221_DEV_NAME		"hts221"
+
+#include <linux/iio/iio.h>
+
+#define HTS221_RX_MAX_LENGTH	8
+#define HTS221_TX_MAX_LENGTH	8
+
+#define HTS221_DATA_SIZE	2
+
+struct hts221_transfer_buffer {
+	u8 rx_buf[HTS221_RX_MAX_LENGTH];
+	u8 tx_buf[HTS221_TX_MAX_LENGTH] ____cacheline_aligned;
+};
+
+struct hts221_transfer_function {
+	int (*read)(struct device *dev, u8 addr, int len, u8 *data);
+	int (*write)(struct device *dev, u8 addr, int len, u8 *data);
+};
+
+#define HTS221_AVG_DEPTH	8
+struct hts221_avg_avl {
+	u16 avg;
+	u8 val;
+};
+
+enum hts221_sensor_type {
+	HTS221_SENSOR_H,
+	HTS221_SENSOR_T,
+	HTS221_SENSOR_MAX,
+};
+
+struct hts221_sensor {
+	u8 cur_avg_idx;
+	int slope, b_gen;
+};
+
+struct hts221_hw {
+	const char *name;
+	struct device *dev;
+
+	struct mutex lock;
+	struct iio_trigger *trig;
+	int irq;
+
+	struct hts221_sensor sensors[HTS221_SENSOR_MAX];
+
+	u8 odr;
+
+	const struct hts221_transfer_function *tf;
+	struct hts221_transfer_buffer tb;
+};
+
+int hts221_config_drdy(struct hts221_hw *hw, bool enable);
+int hts221_probe(struct iio_dev *iio_dev);
+int hts221_power_on(struct hts221_hw *hw);
+int hts221_power_off(struct hts221_hw *hw);
+int hts221_allocate_buffers(struct hts221_hw *hw);
+int hts221_allocate_trigger(struct hts221_hw *hw);
+
+#endif /* HTS221_H */
--- linux-4.4.0.orig/drivers/iio/humidity/hts221_buffer.c
+++ linux-4.4.0/drivers/iio/humidity/hts221_buffer.c
@@ -0,0 +1,168 @@
+/*
+ * STMicroelectronics hts221 sensor driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/buffer.h>
+
+#include "hts221.h"
+
+#define HTS221_REG_STATUS_ADDR		0x27
+#define HTS221_RH_DRDY_MASK		BIT(1)
+#define HTS221_TEMP_DRDY_MASK		BIT(0)
+
+static int hts221_trig_set_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig);
+	struct hts221_hw *hw = iio_priv(iio_dev);
+
+	return hts221_config_drdy(hw, state);
+}
+
+static const struct iio_trigger_ops hts221_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = hts221_trig_set_state,
+};
+
+static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)
+{
+	struct hts221_hw *hw = (struct hts221_hw *)private;
+	u8 status;
+	int err;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_STATUS_ADDR, sizeof(status),
+			   &status);
+	if (err < 0)
+		return IRQ_HANDLED;
+
+	/* 
+	 * H_DA bit (humidity data available) is routed to DRDY line.
+	 * Humidity sample is computed after temperature one.
+	 * Here we can assume data channels are both available if H_DA bit
+	 * is set in status register
+	 */
+	if (!(status & HTS221_RH_DRDY_MASK))
+		return IRQ_NONE;
+
+	iio_trigger_poll_chained(hw->trig);
+
+	return IRQ_HANDLED;
+}
+
+int hts221_allocate_trigger(struct hts221_hw *hw)
+{
+	struct iio_dev *iio_dev = iio_priv_to_dev(hw);
+	unsigned long irq_type;
+	int err;
+
+	irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
+
+	switch (irq_type) {
+	case IRQF_TRIGGER_HIGH:
+	case IRQF_TRIGGER_RISING:
+		break;
+	default:
+		dev_info(hw->dev,
+			 "mode %lx unsupported, using IRQF_TRIGGER_RISING\n",
+			 irq_type);
+		irq_type = IRQF_TRIGGER_RISING;
+		break;
+	}
+
+	err = devm_request_threaded_irq(hw->dev, hw->irq, NULL,
+					hts221_trigger_handler_thread,
+					irq_type | IRQF_ONESHOT,
+					hw->name, hw);
+	if (err) {
+		dev_err(hw->dev, "failed to request trigger irq %d\n",
+			hw->irq);
+		return err;
+	}
+
+	hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger",
+					  iio_dev->name);
+	if (!hw->trig)
+		return -ENOMEM;
+
+	iio_trigger_set_drvdata(hw->trig, iio_dev);
+	hw->trig->ops = &hts221_trigger_ops;
+	hw->trig->dev.parent = hw->dev;
+	iio_dev->trig = iio_trigger_get(hw->trig);
+
+	return iio_trigger_register(hw->trig);
+}
+
+static int hts221_buffer_preenable(struct iio_dev *iio_dev)
+{
+	return hts221_power_on(iio_priv(iio_dev));
+}
+
+static int hts221_buffer_postdisable(struct iio_dev *iio_dev)
+{
+	return hts221_power_off(iio_priv(iio_dev));
+}
+
+static const struct iio_buffer_setup_ops hts221_buffer_ops = {
+	.preenable = hts221_buffer_preenable,
+	.postenable = iio_triggered_buffer_postenable,
+	.predisable = iio_triggered_buffer_predisable,
+	.postdisable = hts221_buffer_postdisable,
+};
+
+static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
+{
+	u8 buffer[ALIGN(2 * HTS221_DATA_SIZE, sizeof(s64)) + sizeof(s64)];
+	struct iio_poll_func *pf = p;
+	struct iio_dev *iio_dev = pf->indio_dev;
+	struct hts221_hw *hw = iio_priv(iio_dev);
+	struct iio_chan_spec const *ch;
+	int err;
+
+	/* humidity data */
+	ch = &iio_dev->channels[HTS221_SENSOR_H];
+	err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE,
+			   buffer);
+	if (err < 0)
+		goto out;
+
+	/* temperature data */
+	ch = &iio_dev->channels[HTS221_SENSOR_T];
+	err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE,
+			   buffer + HTS221_DATA_SIZE);
+	if (err < 0)
+		goto out;
+
+	iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+					   iio_get_time_ns());
+
+out:
+	iio_trigger_notify_done(hw->trig);
+
+	return IRQ_HANDLED;
+}
+
+int hts221_allocate_buffers(struct hts221_hw *hw)
+{
+	return iio_triggered_buffer_setup(iio_priv_to_dev(hw),
+					NULL, hts221_buffer_handler_thread,
+					&hts221_buffer_ops);
+}
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics hts221 buffer driver");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/humidity/hts221_core.c
+++ linux-4.4.0/drivers/iio/humidity/hts221_core.c
@@ -0,0 +1,691 @@
+/*
+ * STMicroelectronics hts221 sensor driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/iio/sysfs.h>
+#include <linux/delay.h>
+#include <asm/unaligned.h>
+
+#include "hts221.h"
+
+#define HTS221_REG_WHOAMI_ADDR		0x0f
+#define HTS221_REG_WHOAMI_VAL		0xbc
+
+#define HTS221_REG_CNTRL1_ADDR		0x20
+#define HTS221_REG_CNTRL2_ADDR		0x21
+#define HTS221_REG_CNTRL3_ADDR		0x22
+
+#define HTS221_REG_AVG_ADDR		0x10
+#define HTS221_REG_H_OUT_L		0x28
+#define HTS221_REG_T_OUT_L		0x2a
+
+#define HTS221_HUMIDITY_AVG_MASK	0x07
+#define HTS221_TEMP_AVG_MASK		0x38
+
+#define HTS221_ODR_MASK			0x87
+#define HTS221_BDU_MASK			BIT(2)
+
+#define HTS221_DRDY_MASK		BIT(2)
+
+#define HTS221_ENABLE_SENSOR		BIT(7)
+
+#define HTS221_HUMIDITY_AVG_4		0x00 /* 0.4 %RH */
+#define HTS221_HUMIDITY_AVG_8		0x01 /* 0.3 %RH */
+#define HTS221_HUMIDITY_AVG_16		0x02 /* 0.2 %RH */
+#define HTS221_HUMIDITY_AVG_32		0x03 /* 0.15 %RH */
+#define HTS221_HUMIDITY_AVG_64		0x04 /* 0.1 %RH */
+#define HTS221_HUMIDITY_AVG_128		0x05 /* 0.07 %RH */
+#define HTS221_HUMIDITY_AVG_256		0x06 /* 0.05 %RH */
+#define HTS221_HUMIDITY_AVG_512		0x07 /* 0.03 %RH */
+
+#define HTS221_TEMP_AVG_2		0x00 /* 0.08 degC */
+#define HTS221_TEMP_AVG_4		0x08 /* 0.05 degC */
+#define HTS221_TEMP_AVG_8		0x10 /* 0.04 degC */
+#define HTS221_TEMP_AVG_16		0x18 /* 0.03 degC */
+#define HTS221_TEMP_AVG_32		0x20 /* 0.02 degC */
+#define HTS221_TEMP_AVG_64		0x28 /* 0.015 degC */
+#define HTS221_TEMP_AVG_128		0x30 /* 0.01 degC */
+#define HTS221_TEMP_AVG_256		0x38 /* 0.007 degC */
+
+/* calibration registers */
+#define HTS221_REG_0RH_CAL_X_H		0x36
+#define HTS221_REG_1RH_CAL_X_H		0x3a
+#define HTS221_REG_0RH_CAL_Y_H		0x30
+#define HTS221_REG_1RH_CAL_Y_H		0x31
+#define HTS221_REG_0T_CAL_X_L		0x3c
+#define HTS221_REG_1T_CAL_X_L		0x3e
+#define HTS221_REG_0T_CAL_Y_H		0x32
+#define HTS221_REG_1T_CAL_Y_H		0x33
+#define HTS221_REG_T1_T0_CAL_Y_H	0x35
+
+struct hts221_odr {
+	u8 hz;
+	u8 val;
+};
+
+struct hts221_avg {
+	u8 addr;
+	u8 mask;
+	struct hts221_avg_avl avg_avl[HTS221_AVG_DEPTH];
+};
+
+static const struct hts221_odr hts221_odr_table[] = {
+	{  1, 0x01 },	/* 1Hz */
+	{  7, 0x02 },	/* 7Hz */
+	{ 13, 0x03 },	/* 12.5Hz */
+};
+
+static const struct hts221_avg hts221_avg_list[] = {
+	{
+		.addr = HTS221_REG_AVG_ADDR,
+		.mask = HTS221_HUMIDITY_AVG_MASK,
+		.avg_avl = {
+			{ 4, HTS221_HUMIDITY_AVG_4 },
+			{ 8, HTS221_HUMIDITY_AVG_8 },
+			{ 16, HTS221_HUMIDITY_AVG_16 },
+			{ 32, HTS221_HUMIDITY_AVG_32 },
+			{ 64, HTS221_HUMIDITY_AVG_64 },
+			{ 128, HTS221_HUMIDITY_AVG_128 },
+			{ 256, HTS221_HUMIDITY_AVG_256 },
+			{ 512, HTS221_HUMIDITY_AVG_512 },
+		},
+	},
+	{
+		.addr = HTS221_REG_AVG_ADDR,
+		.mask = HTS221_TEMP_AVG_MASK,
+		.avg_avl = {
+			{ 2, HTS221_TEMP_AVG_2 },
+			{ 4, HTS221_TEMP_AVG_4 },
+			{ 8, HTS221_TEMP_AVG_8 },
+			{ 16, HTS221_TEMP_AVG_16 },
+			{ 32, HTS221_TEMP_AVG_32 },
+			{ 64, HTS221_TEMP_AVG_64 },
+			{ 128, HTS221_TEMP_AVG_128 },
+			{ 256, HTS221_TEMP_AVG_256 },
+		},
+	},
+};
+
+static const struct iio_chan_spec hts221_channels[] = {
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.address = HTS221_REG_H_OUT_L,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_OFFSET) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_LE,
+		},
+	},
+	{
+		.type = IIO_TEMP,
+		.address = HTS221_REG_T_OUT_L,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_OFFSET) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_LE,
+		},
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+static int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask,
+				  u8 val)
+{
+	u8 data;
+	int err;
+
+	mutex_lock(&hw->lock);
+
+	err = hw->tf->read(hw->dev, addr, sizeof(data), &data);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to read %02x register\n", addr);
+		goto unlock;
+	}
+
+	data = (data & ~mask) | (val & mask);
+
+	err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
+	if (err < 0)
+		dev_err(hw->dev, "failed to write %02x register\n", addr);
+
+unlock:
+	mutex_unlock(&hw->lock);
+
+	return err;
+}
+
+static int hts221_check_whoami(struct hts221_hw *hw)
+{
+	u8 data;
+	int err;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_WHOAMI_ADDR, sizeof(data),
+			   &data);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to read whoami register\n");
+		return err;
+	}
+
+	if (data != HTS221_REG_WHOAMI_VAL) {
+		dev_err(hw->dev, "wrong whoami {%02x vs %02x}\n",
+			data, HTS221_REG_WHOAMI_VAL);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+int hts221_config_drdy(struct hts221_hw *hw, bool enable)
+{
+	u8 val = enable ? BIT(2) : 0;
+	int err;
+
+	err = hts221_write_with_mask(hw, HTS221_REG_CNTRL3_ADDR,
+				     HTS221_DRDY_MASK, val);
+
+	return err < 0 ? err : 0;
+}
+
+static int hts221_update_odr(struct hts221_hw *hw, u8 odr)
+{
+	int i, err;
+	u8 val;
+
+	for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)
+		if (hts221_odr_table[i].hz == odr)
+			break;
+
+	if (i == ARRAY_SIZE(hts221_odr_table))
+		return -EINVAL;
+
+	val = HTS221_ENABLE_SENSOR | HTS221_BDU_MASK | hts221_odr_table[i].val;
+	err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
+				     HTS221_ODR_MASK, val);
+	if (err < 0)
+		return err;
+
+	hw->odr = odr;
+
+	return 0;
+}
+
+static int hts221_update_avg(struct hts221_hw *hw,
+			     enum hts221_sensor_type type,
+			     u16 val)
+{
+	int i, err;
+	const struct hts221_avg *avg = &hts221_avg_list[type];
+
+	for (i = 0; i < HTS221_AVG_DEPTH; i++)
+		if (avg->avg_avl[i].avg == val)
+			break;
+
+	if (i == HTS221_AVG_DEPTH)
+		return -EINVAL;
+
+	err = hts221_write_with_mask(hw, avg->addr, avg->mask,
+				     avg->avg_avl[i].val);
+	if (err < 0)
+		return err;
+
+	hw->sensors[type].cur_avg_idx = i;
+
+	return 0;
+}
+
+static ssize_t hts221_sysfs_sampling_freq(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	int i;
+	ssize_t len = 0;
+
+	for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+				 hts221_odr_table[i].hz);
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static ssize_t
+hts221_sysfs_rh_oversampling_avail(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_H];
+	ssize_t len = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+				 avg->avg_avl[i].avg);
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static ssize_t
+hts221_sysfs_temp_oversampling_avail(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_T];
+	ssize_t len = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+				 avg->avg_avl[i].avg);
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+int hts221_power_on(struct hts221_hw *hw)
+{
+	return hts221_update_odr(hw, hw->odr);
+}
+
+int hts221_power_off(struct hts221_hw *hw)
+{
+	u8 data[] = {0x00, 0x00};
+
+	return hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data),
+			     data);
+}
+
+static int hts221_parse_temp_caldata(struct hts221_hw *hw)
+{
+	int err, *slope, *b_gen;
+	s16 cal_x0, cal_x1, cal_y0, cal_y1;
+	u8 cal0, cal1;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_Y_H,
+			   sizeof(cal0), &cal0);
+	if (err < 0)
+		return err;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_T1_T0_CAL_Y_H,
+			   sizeof(cal1), &cal1);
+	if (err < 0)
+		return err;
+	cal_y0 = (le16_to_cpu(cal1 & 0x3) << 8) | cal0;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_Y_H,
+			   sizeof(cal0), &cal0);
+	if (err < 0)
+		return err;
+	cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_X_L, sizeof(cal_x0),
+			   (u8 *)&cal_x0);
+	if (err < 0)
+		return err;
+	cal_x0 = le16_to_cpu(cal_x0);
+
+	err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_X_L, sizeof(cal_x1),
+			   (u8 *)&cal_x1);
+	if (err < 0)
+		return err;
+	cal_x1 = le16_to_cpu(cal_x1);
+
+	slope = &hw->sensors[HTS221_SENSOR_T].slope;
+	b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen;
+
+	*slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0);
+	*b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) /
+		 (cal_x1 - cal_x0);
+	*b_gen *= 8;
+
+	return 0;
+}
+
+static int hts221_parse_rh_caldata(struct hts221_hw *hw)
+{
+	int err, *slope, *b_gen;
+	s16 cal_x0, cal_x1, cal_y0, cal_y1;
+	u8 data;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_Y_H, sizeof(data),
+			   &data);
+	if (err < 0)
+		return err;
+	cal_y0 = data;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_Y_H, sizeof(data),
+			   &data);
+	if (err < 0)
+		return err;
+	cal_y1 = data;
+
+	err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_X_H, sizeof(cal_x0),
+			   (u8 *)&cal_x0);
+	if (err < 0)
+		return err;
+	cal_x0 = le16_to_cpu(cal_x0);
+
+	err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_X_H, sizeof(cal_x1),
+			   (u8 *)&cal_x1);
+	if (err < 0)
+		return err;
+	cal_x1 = le16_to_cpu(cal_x1);
+
+	slope = &hw->sensors[HTS221_SENSOR_H].slope;
+	b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen;
+
+	*slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0);
+	*b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) /
+		 (cal_x1 - cal_x0);
+	*b_gen *= 8;
+
+	return 0;
+}
+
+static int hts221_get_sensor_scale(struct hts221_hw *hw,
+				   enum iio_chan_type ch_type,
+				   int *val, int *val2)
+{
+	s64 tmp;
+	s32 rem, div, data;
+
+	switch (ch_type) {
+	case IIO_HUMIDITYRELATIVE:
+		data = hw->sensors[HTS221_SENSOR_H].slope;
+		div = (1 << 4) * 1000;
+		break;
+	case IIO_TEMP:
+		data = hw->sensors[HTS221_SENSOR_T].slope;
+		div = (1 << 6) * 1000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tmp = div_s64(data * 1000000000LL, div);
+	tmp = div_s64_rem(tmp, 1000000000LL, &rem);
+
+	*val = tmp;
+	*val2 = rem;
+
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int hts221_get_sensor_offset(struct hts221_hw *hw,
+				    enum iio_chan_type ch_type,
+				    int *val, int *val2)
+{
+	s64 tmp;
+	s32 rem, div, data;
+
+	switch (ch_type) {
+	case IIO_HUMIDITYRELATIVE:
+		data = hw->sensors[HTS221_SENSOR_H].b_gen;
+		div = hw->sensors[HTS221_SENSOR_H].slope;
+		break;
+	case IIO_TEMP:
+		data = hw->sensors[HTS221_SENSOR_T].b_gen;
+		div = hw->sensors[HTS221_SENSOR_T].slope;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tmp = div_s64(data * 1000000000LL, div);
+	tmp = div_s64_rem(tmp, 1000000000LL, &rem);
+
+	*val = tmp;
+	*val2 = rem;
+
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
+{
+	u8 data[HTS221_DATA_SIZE];
+	int err;
+
+	err = hts221_power_on(hw);
+	if (err < 0)
+		return err;
+
+	msleep(50);
+
+	err = hw->tf->read(hw->dev, addr, sizeof(data), data);
+	if (err < 0)
+		return err;
+
+	hts221_power_off(hw);
+
+	*val = (s16)get_unaligned_le16(data);
+
+	return IIO_VAL_INT;
+}
+
+static int hts221_read_raw(struct iio_dev *iio_dev,
+			   struct iio_chan_spec const *ch,
+			   int *val, int *val2, long mask)
+{
+	struct hts221_hw *hw = iio_priv(iio_dev);
+	int ret;
+
+	mutex_lock(&iio_dev->mlock);
+	if (iio_buffer_enabled(iio_dev)) {
+		mutex_unlock(&iio_dev->mlock);
+		return -EBUSY;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = hts221_read_oneshot(hw, ch->address, val);
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		ret = hts221_get_sensor_scale(hw, ch->type, val, val2);
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		ret = hts221_get_sensor_offset(hw, ch->type, val, val2);
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val = hw->odr;
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
+		u8 idx;
+		const struct hts221_avg *avg;
+
+		switch (ch->type) {
+		case IIO_HUMIDITYRELATIVE:
+			avg = &hts221_avg_list[HTS221_SENSOR_H];
+			idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx;
+			*val = avg->avg_avl[idx].avg;
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_TEMP:
+			avg = &hts221_avg_list[HTS221_SENSOR_T];
+			idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx;
+			*val = avg->avg_avl[idx].avg;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	}
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&iio_dev->mlock);
+
+	return ret;
+}
+
+static int hts221_write_raw(struct iio_dev *iio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	struct hts221_hw *hw = iio_priv(iio_dev);
+	int ret;
+
+	mutex_lock(&iio_dev->mlock);
+	if (iio_buffer_enabled(iio_dev)) {
+		mutex_unlock(&iio_dev->mlock);
+		return -EBUSY;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hts221_update_odr(hw, val);
+		break;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		switch (chan->type) {
+		case IIO_HUMIDITYRELATIVE:
+			ret = hts221_update_avg(hw, HTS221_SENSOR_H, val);
+			break;
+		case IIO_TEMP:
+			ret = hts221_update_avg(hw, HTS221_SENSOR_T, val);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&iio_dev->mlock);
+
+	return ret;
+}
+
+static int hts221_validate_trigger(struct iio_dev *iio_dev,
+				   struct iio_trigger *trig)
+{
+	struct hts221_hw *hw = iio_priv(iio_dev);
+
+	return hw->trig == trig ? 0 : -EINVAL;
+}
+
+static IIO_DEVICE_ATTR(in_humidity_oversampling_ratio_available, S_IRUGO,
+		       hts221_sysfs_rh_oversampling_avail, NULL, 0);
+static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, S_IRUGO,
+		       hts221_sysfs_temp_oversampling_avail, NULL, 0);
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hts221_sysfs_sampling_freq);
+
+static struct attribute *hts221_attributes[] = {
+	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_in_humidity_oversampling_ratio_available.dev_attr.attr,
+	&iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group hts221_attribute_group = {
+	.attrs = hts221_attributes,
+};
+
+static const struct iio_info hts221_info = {
+	.driver_module = THIS_MODULE,
+	.attrs = &hts221_attribute_group,
+	.read_raw = hts221_read_raw,
+	.write_raw = hts221_write_raw,
+	.validate_trigger = hts221_validate_trigger,
+};
+
+static const unsigned long hts221_scan_masks[] = {0x3, 0x0};
+
+int hts221_probe(struct iio_dev *iio_dev)
+{
+	struct hts221_hw *hw = iio_priv(iio_dev);
+	int err;
+	u8 data;
+
+	mutex_init(&hw->lock);
+
+	err = hts221_check_whoami(hw);
+	if (err < 0)
+		return err;
+
+	hw->odr = hts221_odr_table[0].hz;
+
+	iio_dev->modes = INDIO_DIRECT_MODE;
+	iio_dev->dev.parent = hw->dev;
+	iio_dev->available_scan_masks = hts221_scan_masks;
+	iio_dev->channels = hts221_channels;
+	iio_dev->num_channels = ARRAY_SIZE(hts221_channels);
+	iio_dev->name = HTS221_DEV_NAME;
+	iio_dev->info = &hts221_info;
+
+	/* configure humidity sensor */
+	err = hts221_parse_rh_caldata(hw);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to get rh calibration data\n");
+		return err;
+	}
+
+	data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3].avg;
+	err = hts221_update_avg(hw, HTS221_SENSOR_H, data);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to set rh oversampling ratio\n");
+		return err;
+	}
+
+	/* configure temperature sensor */
+	err = hts221_parse_temp_caldata(hw);
+	if (err < 0) {
+		dev_err(hw->dev,
+			"failed to get temperature calibration data\n");
+		return err;
+	}
+
+	data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3].avg;
+	err = hts221_update_avg(hw, HTS221_SENSOR_T, data);
+	if (err < 0) {
+		dev_err(hw->dev,
+			"failed to set temperature oversampling ratio\n");
+		return err;
+	}
+
+	if (hw->irq > 0) {
+		err = hts221_allocate_buffers(hw);
+		if (err < 0)
+			return err;
+
+		err = hts221_allocate_trigger(hw);
+		if (err)
+			return err;
+	}
+
+	return devm_iio_device_register(hw->dev, iio_dev);
+}
+EXPORT_SYMBOL(hts221_probe);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/humidity/hts221_i2c.c
+++ linux-4.4.0/drivers/iio/humidity/hts221_i2c.c
@@ -0,0 +1,118 @@
+/*
+ * STMicroelectronics hts221 i2c driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include "hts221.h"
+
+#define I2C_AUTO_INCREMENT	0x80
+
+static int hts221_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
+{
+	struct i2c_msg msg[2];
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (len > 1)
+		addr |= I2C_AUTO_INCREMENT;
+
+	msg[0].addr = client->addr;
+	msg[0].flags = client->flags;
+	msg[0].len = 1;
+	msg[0].buf = &addr;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = client->flags | I2C_M_RD;
+	msg[1].len = len;
+	msg[1].buf = data;
+
+	return i2c_transfer(client->adapter, msg, 2);
+}
+
+static int hts221_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
+{
+	u8 send[len + 1];
+	struct i2c_msg msg;
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (len > 1)
+		addr |= I2C_AUTO_INCREMENT;
+
+	send[0] = addr;
+	memcpy(&send[1], data, len * sizeof(u8));
+
+	msg.addr = client->addr;
+	msg.flags = client->flags;
+	msg.len = len + 1;
+	msg.buf = send;
+
+	return i2c_transfer(client->adapter, &msg, 1);
+}
+
+static const struct hts221_transfer_function hts221_transfer_fn = {
+	.read = hts221_i2c_read,
+	.write = hts221_i2c_write,
+};
+
+static int hts221_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct hts221_hw *hw;
+	struct iio_dev *iio_dev;
+
+	iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*hw));
+	if (!iio_dev)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, iio_dev);
+
+	hw = iio_priv(iio_dev);
+	hw->name = client->name;
+	hw->dev = &client->dev;
+	hw->irq = client->irq;
+	hw->tf = &hts221_transfer_fn;
+
+	return hts221_probe(iio_dev);
+}
+
+static const struct acpi_device_id hts221_acpi_match[] = {
+	{"SMO9100", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, hts221_acpi_match);
+
+static const struct of_device_id hts221_i2c_of_match[] = {
+	{ .compatible = "st,hts221", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hts221_i2c_of_match);
+
+static const struct i2c_device_id hts221_i2c_id_table[] = {
+	{ HTS221_DEV_NAME },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table);
+
+static struct i2c_driver hts221_driver = {
+	.driver = {
+		.name = "hts221_i2c",
+		.of_match_table = of_match_ptr(hts221_i2c_of_match),
+		.acpi_match_table = ACPI_PTR(hts221_acpi_match),
+	},
+	.probe = hts221_i2c_probe,
+	.id_table = hts221_i2c_id_table,
+};
+module_i2c_driver(hts221_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics hts221 i2c driver");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/humidity/hts221_spi.c
+++ linux-4.4.0/drivers/iio/humidity/hts221_spi.c
@@ -0,0 +1,125 @@
+/*
+ * STMicroelectronics hts221 spi driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include "hts221.h"
+
+#define SENSORS_SPI_READ	0x80
+#define SPI_AUTO_INCREMENT	0x40
+
+static int hts221_spi_read(struct device *dev, u8 addr, int len, u8 *data)
+{
+	int err;
+	struct spi_device *spi = to_spi_device(dev);
+	struct iio_dev *iio_dev = spi_get_drvdata(spi);
+	struct hts221_hw *hw = iio_priv(iio_dev);
+
+	struct spi_transfer xfers[] = {
+		{
+			.tx_buf = hw->tb.tx_buf,
+			.bits_per_word = 8,
+			.len = 1,
+		},
+		{
+			.rx_buf = hw->tb.rx_buf,
+			.bits_per_word = 8,
+			.len = len,
+		}
+	};
+
+	if (len > 1)
+		addr |= SPI_AUTO_INCREMENT;
+	hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ;
+
+	err = spi_sync_transfer(spi, xfers,  ARRAY_SIZE(xfers));
+	if (err < 0)
+		return err;
+
+	memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
+
+	return len;
+}
+
+static int hts221_spi_write(struct device *dev, u8 addr, int len, u8 *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct iio_dev *iio_dev = spi_get_drvdata(spi);
+	struct hts221_hw *hw = iio_priv(iio_dev);
+
+	struct spi_transfer xfers = {
+		.tx_buf = hw->tb.tx_buf,
+		.bits_per_word = 8,
+		.len = len + 1,
+	};
+
+	if (len >= HTS221_TX_MAX_LENGTH)
+		return -ENOMEM;
+
+	if (len > 1)
+		addr |= SPI_AUTO_INCREMENT;
+	hw->tb.tx_buf[0] = addr;
+	memcpy(&hw->tb.tx_buf[1], data, len);
+
+	return spi_sync_transfer(spi, &xfers, 1);
+}
+
+static const struct hts221_transfer_function hts221_transfer_fn = {
+	.read = hts221_spi_read,
+	.write = hts221_spi_write,
+};
+
+static int hts221_spi_probe(struct spi_device *spi)
+{
+	struct hts221_hw *hw;
+	struct iio_dev *iio_dev;
+
+	iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*hw));
+	if (!iio_dev)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, iio_dev);
+
+	hw = iio_priv(iio_dev);
+	hw->name = spi->modalias;
+	hw->dev = &spi->dev;
+	hw->irq = spi->irq;
+	hw->tf = &hts221_transfer_fn;
+
+	return hts221_probe(iio_dev);
+}
+
+static const struct of_device_id hts221_spi_of_match[] = {
+	{ .compatible = "st,hts221", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hts221_spi_of_match);
+
+static const struct spi_device_id hts221_spi_id_table[] = {
+	{ HTS221_DEV_NAME },
+	{},
+};
+MODULE_DEVICE_TABLE(spi, hts221_spi_id_table);
+
+static struct spi_driver hts221_driver = {
+	.driver = {
+		.name = "hts221_spi",
+		.of_match_table = of_match_ptr(hts221_spi_of_match),
+	},
+	.probe = hts221_spi_probe,
+	.id_table = hts221_spi_id_table,
+};
+module_spi_driver(hts221_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics hts221 spi driver");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/iio/imu/adis16400_buffer.c
+++ linux-4.4.0/drivers/iio/imu/adis16400_buffer.c
@@ -37,8 +37,11 @@
 		return -ENOMEM;
 
 	adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL);
-	if (!adis->buffer)
+	if (!adis->buffer) {
+		kfree(adis->xfer);
+		adis->xfer = NULL;
 		return -ENOMEM;
+	}
 
 	tx = adis->buffer + burst_length;
 	tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
--- linux-4.4.0.orig/drivers/iio/imu/adis16480.c
+++ linux-4.4.0/drivers/iio/imu/adis16480.c
@@ -266,8 +266,11 @@
 	struct adis16480 *st = iio_priv(indio_dev);
 	unsigned int t;
 
+	if (val < 0 || val2 < 0)
+		return -EINVAL;
+
 	t =  val * 1000 + val2 / 1000;
-	if (t <= 0)
+	if (t == 0)
 		return -EINVAL;
 
 	t = 2460000 / t;
@@ -369,12 +372,14 @@
 	case IIO_MAGN:
 	case IIO_PRESSURE:
 		ret = adis_read_reg_16(&st->adis, reg, &val16);
-		*bias = sign_extend32(val16, 15);
+		if (ret == 0)
+			*bias = sign_extend32(val16, 15);
 		break;
 	case IIO_ANGL_VEL:
 	case IIO_ACCEL:
 		ret = adis_read_reg_32(&st->adis, reg, &val32);
-		*bias = sign_extend32(val32, 31);
+		if (ret == 0)
+			*bias = sign_extend32(val32, 31);
 		break;
 	default:
 			ret = -EINVAL;
@@ -696,7 +701,7 @@
 		.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
 		.gyro_max_scale = 450,
 		.accel_max_val = IIO_M_S_2_TO_G(12500),
-		.accel_max_scale = 5,
+		.accel_max_scale = 10,
 	},
 	[ADIS16485] = {
 		.channels = adis16485_channels,
@@ -721,6 +726,7 @@
 	.write_raw = &adis16480_write_raw,
 	.update_scan_mode = adis_update_scan_mode,
 	.driver_module = THIS_MODULE,
+	.debugfs_reg_access = adis_debugfs_reg_access,
 };
 
 static int adis16480_stop_device(struct iio_dev *indio_dev)
--- linux-4.4.0.orig/drivers/iio/imu/adis_buffer.c
+++ linux-4.4.0/drivers/iio/imu/adis_buffer.c
@@ -39,11 +39,14 @@
 		return -ENOMEM;
 
 	adis->buffer = kzalloc(indio_dev->scan_bytes * 2, GFP_KERNEL);
-	if (!adis->buffer)
+	if (!adis->buffer) {
+		kfree(adis->xfer);
+		adis->xfer = NULL;
 		return -ENOMEM;
+	}
 
 	rx = adis->buffer;
-	tx = rx + indio_dev->scan_bytes;
+	tx = rx + scan_count;
 
 	spi_message_init(&adis->msg);
 
--- linux-4.4.0.orig/drivers/iio/imu/adis_trigger.c
+++ linux-4.4.0/drivers/iio/imu/adis_trigger.c
@@ -47,6 +47,10 @@
 	if (adis->trig == NULL)
 		return -ENOMEM;
 
+	adis->trig->dev.parent = &adis->spi->dev;
+	adis->trig->ops = &adis_trigger_ops;
+	iio_trigger_set_drvdata(adis->trig, adis);
+
 	ret = request_irq(adis->spi->irq,
 			  &iio_trigger_generic_data_rdy_poll,
 			  IRQF_TRIGGER_RISING,
@@ -55,9 +59,6 @@
 	if (ret)
 		goto error_free_trig;
 
-	adis->trig->dev.parent = &adis->spi->dev;
-	adis->trig->ops = &adis_trigger_ops;
-	iio_trigger_set_drvdata(adis->trig, adis);
 	ret = iio_trigger_register(adis->trig);
 
 	indio_dev->trig = iio_trigger_get(adis->trig);
--- linux-4.4.0.orig/drivers/iio/industrialio-buffer.c
+++ linux-4.4.0/drivers/iio/industrialio-buffer.c
@@ -107,9 +107,10 @@
 {
 	struct iio_dev *indio_dev = filp->private_data;
 	struct iio_buffer *rb = indio_dev->buffer;
+	DEFINE_WAIT_FUNC(wait, woken_wake_function);
 	size_t datum_size;
 	size_t to_wait;
-	int ret;
+	int ret = 0;
 
 	if (!indio_dev->info)
 		return -ENODEV;
@@ -131,19 +132,29 @@
 	else
 		to_wait = min_t(size_t, n / datum_size, rb->watermark);
 
+	add_wait_queue(&rb->pollq, &wait);
 	do {
-		ret = wait_event_interruptible(rb->pollq,
-		      iio_buffer_ready(indio_dev, rb, to_wait, n / datum_size));
-		if (ret)
-			return ret;
+		if (!indio_dev->info) {
+			ret = -ENODEV;
+			break;
+		}
 
-		if (!indio_dev->info)
-			return -ENODEV;
+		if (!iio_buffer_ready(indio_dev, rb, to_wait, n / datum_size)) {
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+
+			wait_woken(&wait, TASK_INTERRUPTIBLE,
+				   MAX_SCHEDULE_TIMEOUT);
+			continue;
+		}
 
 		ret = rb->access->read_first_n(rb, n, buf);
 		if (ret == 0 && (filp->f_flags & O_NONBLOCK))
 			ret = -EAGAIN;
-	 } while (ret == 0);
+	} while (ret == 0);
+	remove_wait_queue(&rb->pollq, &wait);
 
 	return ret;
 }
@@ -163,7 +174,7 @@
 	struct iio_dev *indio_dev = filp->private_data;
 	struct iio_buffer *rb = indio_dev->buffer;
 
-	if (!indio_dev->info)
+	if (!indio_dev->info || rb == NULL)
 		return 0;
 
 	poll_wait(filp, &rb->pollq, wait);
@@ -516,7 +527,7 @@
 {
 	const struct iio_chan_spec *ch;
 	unsigned bytes = 0;
-	int length, i;
+	int length, i, largest = 0;
 
 	/* How much space will the demuxed element take? */
 	for_each_set_bit(i, mask,
@@ -529,6 +540,7 @@
 			length = ch->scan_type.storagebits / 8;
 		bytes = ALIGN(bytes, length);
 		bytes += length;
+		largest = max(largest, length);
 	}
 	if (timestamp) {
 		ch = iio_find_channel_from_si(indio_dev,
@@ -540,7 +552,10 @@
 			length = ch->scan_type.storagebits / 8;
 		bytes = ALIGN(bytes, length);
 		bytes += length;
+		largest = max(largest, length);
 	}
+
+	bytes = ALIGN(bytes, largest);
 	return bytes;
 }
 
@@ -1266,9 +1281,6 @@
 				       indio_dev->masklength,
 				       in_ind + 1);
 		while (in_ind != out_ind) {
-			in_ind = find_next_bit(indio_dev->active_scan_mask,
-					       indio_dev->masklength,
-					       in_ind + 1);
 			ch = iio_find_channel_from_si(indio_dev, in_ind);
 			if (ch->scan_type.repeat > 1)
 				length = ch->scan_type.storagebits / 8 *
@@ -1277,6 +1289,9 @@
 				length = ch->scan_type.storagebits / 8;
 			/* Make sure we are aligned */
 			in_loc = roundup(in_loc, length) + length;
+			in_ind = find_next_bit(indio_dev->active_scan_mask,
+					       indio_dev->masklength,
+					       in_ind + 1);
 		}
 		ch = iio_find_channel_from_si(indio_dev, in_ind);
 		if (ch->scan_type.repeat > 1)
--- linux-4.4.0.orig/drivers/iio/industrialio-core.c
+++ linux-4.4.0/drivers/iio/industrialio-core.c
@@ -221,8 +221,10 @@
 	ret = indio_dev->info->debugfs_reg_access(indio_dev,
 						  indio_dev->cached_reg_addr,
 						  0, &val);
-	if (ret)
+	if (ret) {
 		dev_err(indio_dev->dev.parent, "%s: read failed\n", __func__);
+		return ret;
+	}
 
 	len = snprintf(buf, sizeof(buf), "0x%X\n", val);
 
@@ -433,23 +435,21 @@
 		scale_db = true;
 	case IIO_VAL_INT_PLUS_MICRO:
 		if (vals[1] < 0)
-			return sprintf(buf, "-%ld.%06u%s\n", abs(vals[0]),
-					-vals[1],
-				scale_db ? " dB" : "");
+			return sprintf(buf, "-%d.%06u%s\n", abs(vals[0]),
+				       -vals[1], scale_db ? " dB" : "");
 		else
 			return sprintf(buf, "%d.%06u%s\n", vals[0], vals[1],
 				scale_db ? " dB" : "");
 	case IIO_VAL_INT_PLUS_NANO:
 		if (vals[1] < 0)
-			return sprintf(buf, "-%ld.%09u\n", abs(vals[0]),
-					-vals[1]);
+			return sprintf(buf, "-%d.%09u\n", abs(vals[0]),
+				       -vals[1]);
 		else
 			return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
 	case IIO_VAL_FRACTIONAL:
 		tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
-		vals[1] = do_div(tmp, 1000000000LL);
-		vals[0] = tmp;
-		return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
+		vals[0] = (int)div_s64_rem(tmp, 1000000000, &vals[1]);
+		return sprintf(buf, "%d.%09u\n", vals[0], abs(vals[1]));
 	case IIO_VAL_FRACTIONAL_LOG2:
 		tmp = (s64)vals[0] * 1000000000LL >> vals[1];
 		vals[1] = do_div(tmp, 1000000000LL);
@@ -512,6 +512,12 @@
 	int i = 0, f = 0;
 	bool integer_part = true, negative = false;
 
+	if (fract_mult == 0) {
+		*fract = 0;
+
+		return kstrtoint(str, 0, integer);
+	}
+
 	if (str[0] == '-') {
 		negative = true;
 		str++;
@@ -571,6 +577,9 @@
 	if (indio_dev->info->write_raw_get_fmt)
 		switch (indio_dev->info->write_raw_get_fmt(indio_dev,
 			this_attr->c, this_attr->address)) {
+		case IIO_VAL_INT:
+			fract_mult = 0;
+			break;
 		case IIO_VAL_INT_PLUS_MICRO:
 			fract_mult = 100000;
 			break;
--- linux-4.4.0.orig/drivers/iio/industrialio-trigger.c
+++ linux-4.4.0/drivers/iio/industrialio-trigger.c
@@ -210,22 +210,35 @@
 
 	/* Prevent the module from being removed whilst attached to a trigger */
 	__module_get(pf->indio_dev->info->driver_module);
+
+	/* Get irq number */
 	pf->irq = iio_trigger_get_irq(trig);
+	if (pf->irq < 0)
+		goto out_put_module;
+
+	/* Request irq */
 	ret = request_threaded_irq(pf->irq, pf->h, pf->thread,
 				   pf->type, pf->name,
 				   pf);
-	if (ret < 0) {
-		module_put(pf->indio_dev->info->driver_module);
-		return ret;
-	}
+	if (ret < 0)
+		goto out_put_irq;
 
+	/* Enable trigger in driver */
 	if (trig->ops && trig->ops->set_trigger_state && notinuse) {
 		ret = trig->ops->set_trigger_state(trig, true);
 		if (ret < 0)
-			module_put(pf->indio_dev->info->driver_module);
+			goto out_free_irq;
 	}
 
 	return ret;
+
+out_free_irq:
+	free_irq(pf->irq, pf);
+out_put_irq:
+	iio_trigger_put_irq(trig, pf->irq);
+out_put_module:
+	module_put(pf->indio_dev->info->driver_module);
+	return ret;
 }
 
 static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
--- linux-4.4.0.orig/drivers/iio/inkern.c
+++ linux-4.4.0/drivers/iio/inkern.c
@@ -351,6 +351,8 @@
 
 void iio_channel_release(struct iio_channel *channel)
 {
+	if (!channel)
+		return;
 	iio_device_put(channel->indio_dev);
 	kfree(channel);
 }
--- linux-4.4.0.orig/drivers/iio/light/acpi-als.c
+++ linux-4.4.0/drivers/iio/light/acpi-als.c
@@ -54,7 +54,9 @@
 			.realbits	= 32,
 			.storagebits	= 32,
 		},
-		.info_mask_separate	= BIT(IIO_CHAN_INFO_RAW),
+		/* _RAW is here for backward ABI compatibility */
+		.info_mask_separate	= BIT(IIO_CHAN_INFO_RAW) |
+					  BIT(IIO_CHAN_INFO_PROCESSED),
 	},
 };
 
@@ -152,7 +154,7 @@
 	s32 temp_val;
 	int ret;
 
-	if (mask != IIO_CHAN_INFO_RAW)
+	if ((mask != IIO_CHAN_INFO_PROCESSED) && (mask != IIO_CHAN_INFO_RAW))
 		return -EINVAL;
 
 	/* we support only illumination (_ALI) so far. */
--- linux-4.4.0.orig/drivers/iio/light/apds9960.c
+++ linux-4.4.0/drivers/iio/light/apds9960.c
@@ -1005,6 +1005,7 @@
 
 	iio_device_attach_buffer(indio_dev, buffer);
 
+	indio_dev->dev.parent = &client->dev;
 	indio_dev->info = &apds9960_info;
 	indio_dev->name = APDS9960_DRV_NAME;
 	indio_dev->channels = apds9960_channels;
--- linux-4.4.0.orig/drivers/iio/light/bh1750.c
+++ linux-4.4.0/drivers/iio/light/bh1750.c
@@ -62,9 +62,9 @@
 
 	u16 int_time_low_mask;
 	u16 int_time_high_mask;
-}
+};
 
-static const bh1750_chip_info_tbl[] = {
+static const struct bh1750_chip_info bh1750_chip_info_tbl[] = {
 	[BH1710] = { 140, 1022, 300, 400,  250000000, 2, 0x001F, 0x03E0 },
 	[BH1721] = { 140, 1020, 300, 400,  250000000, 2, 0x0010, 0x03E0 },
 	[BH1750] = { 31,  254,  69,  1740, 57500000,  1, 0x001F, 0x00E0 },
--- linux-4.4.0.orig/drivers/iio/light/cm3232.c
+++ linux-4.4.0/drivers/iio/light/cm3232.c
@@ -119,7 +119,7 @@
 	if (ret < 0)
 		dev_err(&chip->client->dev, "Error writing reg_cmd\n");
 
-	return 0;
+	return ret;
 }
 
 /**
--- linux-4.4.0.orig/drivers/iio/light/ltr501.c
+++ linux-4.4.0/drivers/iio/light/ltr501.c
@@ -74,9 +74,9 @@
 static const struct reg_field reg_field_it =
 				REG_FIELD(LTR501_ALS_MEAS_RATE, 3, 4);
 static const struct reg_field reg_field_als_intr =
-				REG_FIELD(LTR501_INTR, 0, 0);
-static const struct reg_field reg_field_ps_intr =
 				REG_FIELD(LTR501_INTR, 1, 1);
+static const struct reg_field reg_field_ps_intr =
+				REG_FIELD(LTR501_INTR, 0, 0);
 static const struct reg_field reg_field_als_rate =
 				REG_FIELD(LTR501_ALS_MEAS_RATE, 0, 2);
 static const struct reg_field reg_field_ps_rate =
@@ -180,7 +180,7 @@
 			{500000, 2000000}
 };
 
-static unsigned int ltr501_match_samp_freq(const struct ltr501_samp_table *tab,
+static int ltr501_match_samp_freq(const struct ltr501_samp_table *tab,
 					   int len, int val, int val2)
 {
 	int i, freq;
@@ -1218,13 +1218,16 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ltr501_data *data = iio_priv(indio_dev);
-	u16 buf[8];
+	struct {
+		u16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 	__le16 als_buf[2];
 	u8 mask = 0;
 	int j = 0;
 	int ret, psdata;
 
-	memset(buf, 0, sizeof(buf));
+	memset(&scan, 0, sizeof(scan));
 
 	/* figure out which data needs to be ready */
 	if (test_bit(0, indio_dev->active_scan_mask) ||
@@ -1243,9 +1246,9 @@
 		if (ret < 0)
 			return ret;
 		if (test_bit(0, indio_dev->active_scan_mask))
-			buf[j++] = le16_to_cpu(als_buf[1]);
+			scan.channels[j++] = le16_to_cpu(als_buf[1]);
 		if (test_bit(1, indio_dev->active_scan_mask))
-			buf[j++] = le16_to_cpu(als_buf[0]);
+			scan.channels[j++] = le16_to_cpu(als_buf[0]);
 	}
 
 	if (mask & LTR501_STATUS_PS_RDY) {
@@ -1253,10 +1256,10 @@
 				       &psdata, 2);
 		if (ret < 0)
 			goto done;
-		buf[j++] = psdata & LTR501_PS_DATA_MASK;
+		scan.channels[j++] = psdata & LTR501_PS_DATA_MASK;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns());
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-4.4.0.orig/drivers/iio/light/opt3001.c
+++ linux-4.4.0/drivers/iio/light/opt3001.c
@@ -646,6 +646,7 @@
 	struct iio_dev *iio = _iio;
 	struct opt3001 *opt = iio_priv(iio);
 	int ret;
+	bool wake_result_ready_queue = false;
 
 	if (!opt->ok_to_ignore_lock)
 		mutex_lock(&opt->lock);
@@ -680,13 +681,16 @@
 		}
 		opt->result = ret;
 		opt->result_ready = true;
-		wake_up(&opt->result_ready_queue);
+		wake_result_ready_queue = true;
 	}
 
 out:
 	if (!opt->ok_to_ignore_lock)
 		mutex_unlock(&opt->lock);
 
+	if (wake_result_ready_queue)
+		wake_up(&opt->result_ready_queue);
+
 	return IRQ_HANDLED;
 }
 
--- linux-4.4.0.orig/drivers/iio/light/tsl2563.c
+++ linux-4.4.0/drivers/iio/light/tsl2563.c
@@ -626,7 +626,7 @@
 	struct tsl2563_chip *chip = iio_priv(dev_info);
 
 	iio_push_event(dev_info,
-		       IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+		       IIO_UNMOD_EVENT_CODE(IIO_INTENSITY,
 					    0,
 					    IIO_EV_TYPE_THRESH,
 					    IIO_EV_DIR_EITHER),
--- linux-4.4.0.orig/drivers/iio/light/vcnl4000.c
+++ linux-4.4.0/drivers/iio/light/vcnl4000.c
@@ -56,7 +56,6 @@
 				u8 rdy_mask, u8 data_reg, int *val)
 {
 	int tries = 20;
-	__be16 buf;
 	int ret;
 
 	ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
@@ -80,12 +79,11 @@
 		return -EIO;
 	}
 
-	ret = i2c_smbus_read_i2c_block_data(data->client,
-		data_reg, sizeof(buf), (u8 *) &buf);
+	ret = i2c_smbus_read_word_swapped(data->client, data_reg);
 	if (ret < 0)
 		return ret;
 
-	*val = be16_to_cpu(buf);
+	*val = ret;
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/iio/magnetometer/ak8975.c
+++ linux-4.4.0/drivers/iio/magnetometer/ak8975.c
@@ -462,6 +462,8 @@
 	int rc;
 	int irq;
 
+	init_waitqueue_head(&data->data_ready_queue);
+	clear_bit(0, &data->flags);
 	if (client->irq)
 		irq = client->irq;
 	else
@@ -477,8 +479,6 @@
 		return rc;
 	}
 
-	init_waitqueue_head(&data->data_ready_queue);
-	clear_bit(0, &data->flags);
 	data->eoc_irq = irq;
 
 	return rc;
@@ -732,7 +732,7 @@
 	int eoc_gpio;
 	int err;
 	const char *name = NULL;
-	enum asahi_compass_chipset chipset;
+	enum asahi_compass_chipset chipset = AK_MAX_TYPE;
 
 	/* Grab and set up the supplied GPIO. */
 	if (client->dev.platform_data)
--- linux-4.4.0.orig/drivers/iio/magnetometer/mag3110.c
+++ linux-4.4.0/drivers/iio/magnetometer/mag3110.c
@@ -52,6 +52,12 @@
 	struct i2c_client *client;
 	struct mutex lock;
 	u8 ctrl_reg1;
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__be16 channels[3];
+		u8 temperature;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static int mag3110_request(struct mag3110_data *data)
@@ -245,10 +251,9 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mag3110_data *data = iio_priv(indio_dev);
-	u8 buffer[16]; /* 3 16-bit channels + 1 byte temp + padding + ts */
 	int ret;
 
-	ret = mag3110_read(data, (__be16 *) buffer);
+	ret = mag3110_read(data, data->scan.channels);
 	if (ret < 0)
 		goto done;
 
@@ -257,10 +262,10 @@
 			MAG3110_DIE_TEMP);
 		if (ret < 0)
 			goto done;
-		buffer[6] = ret;
+		data->scan.temperature = ret;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 		iio_get_time_ns());
 
 done:
--- linux-4.4.0.orig/drivers/iio/magnetometer/st_magn.h
+++ linux-4.4.0/drivers/iio/magnetometer/st_magn.h
@@ -44,6 +44,7 @@
 static inline void st_magn_deallocate_ring(struct iio_dev *indio_dev)
 {
 }
+#define ST_MAGN_TRIGGER_SET_STATE NULL
 #endif /* CONFIG_IIO_BUFFER */
 
 #endif /* ST_MAGN_H */
--- linux-4.4.0.orig/drivers/iio/magnetometer/st_magn_buffer.c
+++ linux-4.4.0/drivers/iio/magnetometer/st_magn_buffer.c
@@ -82,7 +82,7 @@
 
 int st_magn_allocate_ring(struct iio_dev *indio_dev)
 {
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+	return iio_triggered_buffer_setup(indio_dev, NULL,
 		&st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
 }
 
--- linux-4.4.0.orig/drivers/iio/magnetometer/st_magn_core.c
+++ linux-4.4.0/drivers/iio/magnetometer/st_magn_core.c
@@ -175,6 +175,8 @@
 #define ST_MAGN_3_BDU_MASK			0x10
 #define ST_MAGN_3_DRDY_IRQ_ADDR			0x62
 #define ST_MAGN_3_DRDY_INT_MASK			0x01
+#define ST_MAGN_3_IHL_IRQ_ADDR			0x63
+#define ST_MAGN_3_IHL_IRQ_MASK			0x04
 #define ST_MAGN_3_FS_AVL_15000_GAIN		1500
 #define ST_MAGN_3_MULTIREAD_BIT			false
 #define ST_MAGN_3_OUT_X_L_ADDR			0x68
@@ -480,6 +482,9 @@
 		.drdy_irq = {
 			.addr = ST_MAGN_3_DRDY_IRQ_ADDR,
 			.mask_int1 = ST_MAGN_3_DRDY_INT_MASK,
+			.addr_ihl = ST_MAGN_3_IHL_IRQ_ADDR,
+			.mask_ihl = ST_MAGN_3_IHL_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_MAGN_3_MULTIREAD_BIT,
 		.bootime = 2,
@@ -567,6 +572,7 @@
 static const struct iio_trigger_ops st_magn_trigger_ops = {
 	.owner = THIS_MODULE,
 	.set_trigger_state = ST_MAGN_TRIGGER_SET_STATE,
+	.validate_device = st_sensors_validate_device,
 };
 #define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops)
 #else
@@ -583,13 +589,15 @@
 	indio_dev->info = &magn_info;
 	mutex_init(&mdata->tb.buf_lock);
 
-	st_sensors_power_enable(indio_dev);
+	err = st_sensors_power_enable(indio_dev);
+	if (err)
+		return err;
 
 	err = st_sensors_check_device_support(indio_dev,
 					ARRAY_SIZE(st_magn_sensors_settings),
 					st_magn_sensors_settings);
 	if (err < 0)
-		return err;
+		goto st_magn_power_off;
 
 	mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS;
 	mdata->multiread_bit = mdata->sensor_settings->multi_read_bit;
@@ -602,11 +610,11 @@
 
 	err = st_sensors_init_sensor(indio_dev, NULL);
 	if (err < 0)
-		return err;
+		goto st_magn_power_off;
 
 	err = st_magn_allocate_ring(indio_dev);
 	if (err < 0)
-		return err;
+		goto st_magn_power_off;
 
 	if (irq > 0) {
 		err = st_sensors_allocate_trigger(indio_dev,
@@ -629,6 +637,8 @@
 		st_sensors_deallocate_trigger(indio_dev);
 st_magn_probe_trigger_error:
 	st_magn_deallocate_ring(indio_dev);
+st_magn_power_off:
+	st_sensors_power_disable(indio_dev);
 
 	return err;
 }
--- linux-4.4.0.orig/drivers/iio/magnetometer/st_magn_spi.c
+++ linux-4.4.0/drivers/iio/magnetometer/st_magn_spi.c
@@ -48,8 +48,6 @@
 }
 
 static const struct spi_device_id st_magn_id_table[] = {
-	{ LSM303DLHC_MAGN_DEV_NAME },
-	{ LSM303DLM_MAGN_DEV_NAME },
 	{ LIS3MDL_MAGN_DEV_NAME },
 	{ LSM303AGR_MAGN_DEV_NAME },
 	{},
--- linux-4.4.0.orig/drivers/iio/orientation/hid-sensor-rotation.c
+++ linux-4.4.0/drivers/iio/orientation/hid-sensor-rotation.c
@@ -335,6 +335,7 @@
 	.id_table = hid_dev_rot_ids,
 	.driver = {
 		.name	= KBUILD_MODNAME,
+		.pm     = &hid_sensor_pm_ops,
 	},
 	.probe		= hid_dev_rot_probe,
 	.remove		= hid_dev_rot_remove,
--- linux-4.4.0.orig/drivers/iio/pressure/Kconfig
+++ linux-4.4.0/drivers/iio/pressure/Kconfig
@@ -101,7 +101,7 @@
 	select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
 	help
 	  Say yes here to build support for STMicroelectronics pressure
-	  sensors: LPS001WP, LPS25H, LPS331AP.
+	  sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB.
 
 	  This driver can also be built as a module. If so, these modules
 	  will be created:
--- linux-4.4.0.orig/drivers/iio/pressure/mpl115.c
+++ linux-4.4.0/drivers/iio/pressure/mpl115.c
@@ -117,7 +117,7 @@
 		*val = ret >> 6;
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_OFFSET:
-		*val = 605;
+		*val = -605;
 		*val2 = 750000;
 		return IIO_VAL_INT_PLUS_MICRO;
 	case IIO_CHAN_INFO_SCALE:
@@ -136,6 +136,7 @@
 	{
 		.type = IIO_TEMP,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type =
 			BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
 	},
 };
--- linux-4.4.0.orig/drivers/iio/pressure/mpl3115.c
+++ linux-4.4.0/drivers/iio/pressure/mpl3115.c
@@ -139,7 +139,14 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mpl3115_data *data = iio_priv(indio_dev);
-	u8 buffer[16]; /* 32-bit channel + 16-bit channel + padding + ts */
+	/*
+	 * 32-bit channel + 16-bit channel + padding + ts
+	 * Note that it is possible for only one of the first 2
+	 * channels to be enabled. If that happens, the first element
+	 * of the buffer may be either 16 or 32-bits.  As such we cannot
+	 * use a simple structure definition to express this data layout.
+	 */
+	u8 buffer[16] __aligned(8);
 	int ret, pos = 0;
 
 	mutex_lock(&data->lock);
@@ -182,7 +189,7 @@
 	{
 		.type = IIO_PRESSURE,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-			BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
 		.scan_index = 0,
 		.scan_type = {
 			.sign = 'u',
@@ -195,7 +202,7 @@
 	{
 		.type = IIO_TEMP,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-			BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
 		.scan_index = 1,
 		.scan_type = {
 			.sign = 's',
--- linux-4.4.0.orig/drivers/iio/pressure/st_pressure.h
+++ linux-4.4.0/drivers/iio/pressure/st_pressure.h
@@ -14,9 +14,18 @@
 #include <linux/types.h>
 #include <linux/iio/common/st_sensors.h>
 
+enum st_press_type {
+	LPS001WP,
+	LPS25H,
+	LPS331AP,
+	LPS22HB,
+	ST_PRESS_MAX,
+};
+
 #define LPS001WP_PRESS_DEV_NAME		"lps001wp"
 #define LPS25H_PRESS_DEV_NAME		"lps25h"
 #define LPS331AP_PRESS_DEV_NAME		"lps331ap"
+#define LPS22HB_PRESS_DEV_NAME		"lps22hb"
 
 /**
  * struct st_sensors_platform_data - default press platform data
--- linux-4.4.0.orig/drivers/iio/pressure/st_pressure_buffer.c
+++ linux-4.4.0/drivers/iio/pressure/st_pressure_buffer.c
@@ -82,7 +82,7 @@
 
 int st_press_allocate_ring(struct iio_dev *indio_dev)
 {
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+	return iio_triggered_buffer_setup(indio_dev, NULL,
 		&st_sensors_trigger_handler, &st_press_buffer_setup_ops);
 }
 
--- linux-4.4.0.orig/drivers/iio/pressure/st_pressure_core.c
+++ linux-4.4.0/drivers/iio/pressure/st_pressure_core.c
@@ -28,21 +28,95 @@
 #include <linux/iio/common/st_sensors.h>
 #include "st_pressure.h"
 
+/*
+ * About determining pressure scaling factors
+ * ------------------------------------------
+ *
+ * Datasheets specify typical pressure sensitivity so that pressure is computed
+ * according to the following equation :
+ *     pressure[mBar] = raw / sensitivity
+ * where :
+ *     raw          the 24 bits long raw sampled pressure
+ *     sensitivity  a scaling factor specified by the datasheet in LSB/mBar
+ *
+ * IIO ABI expects pressure to be expressed as kPascal, hence pressure should be
+ * computed according to :
+ *     pressure[kPascal] = pressure[mBar] / 10
+ *                       = raw / (sensitivity * 10)                          (1)
+ *
+ * Finally, st_press_read_raw() returns pressure scaling factor as an
+ * IIO_VAL_INT_PLUS_NANO with a zero integral part and "gain" as decimal part.
+ * Therefore, from (1), "gain" becomes :
+ *     gain = 10^9 / (sensitivity * 10)
+ *          = 10^8 / sensitivity
+ *
+ * About determining temperature scaling factors and offsets
+ * ---------------------------------------------------------
+ *
+ * Datasheets specify typical temperature sensitivity and offset so that
+ * temperature is computed according to the following equation :
+ *     temp[Celsius] = offset[Celsius] + (raw / sensitivity)
+ * where :
+ *     raw          the 16 bits long raw sampled temperature
+ *     offset       a constant specified by the datasheet in degree Celsius
+ *                  (sometimes zero)
+ *     sensitivity  a scaling factor specified by the datasheet in LSB/Celsius
+ *
+ * IIO ABI expects temperature to be expressed as milli degree Celsius such as
+ * user space should compute temperature according to :
+ *     temp[mCelsius] = temp[Celsius] * 10^3
+ *                    = (offset[Celsius] + (raw / sensitivity)) * 10^3
+ *                    = ((offset[Celsius] * sensitivity) + raw) *
+ *                      (10^3 / sensitivity)                                 (2)
+ *
+ * IIO ABI expects user space to apply offset and scaling factors to raw samples
+ * according to :
+ *     temp[mCelsius] = (OFFSET + raw) * SCALE
+ * where :
+ *     OFFSET an arbitrary constant exposed by device
+ *     SCALE  an arbitrary scaling factor exposed by device
+ *
+ * Matching OFFSET and SCALE with members of (2) gives :
+ *     OFFSET = offset[Celsius] * sensitivity                                (3)
+ *     SCALE  = 10^3 / sensitivity                                           (4)
+ *
+ * st_press_read_raw() returns temperature scaling factor as an
+ * IIO_VAL_FRACTIONAL with a 10^3 numerator and "gain2" as denominator.
+ * Therefore, from (3), "gain2" becomes :
+ *     gain2 = sensitivity
+ *
+ * When declared within channel, i.e. for a non zero specified offset,
+ * st_press_read_raw() will return the latter as an IIO_VAL_FRACTIONAL such as :
+ *     numerator = OFFSET * 10^3
+ *     denominator = 10^3
+ * giving from (4):
+ *     numerator = offset[Celsius] * 10^3 * sensitivity
+ *               = offset[mCelsius] * gain2
+ */
+
+#define MCELSIUS_PER_CELSIUS			1000
+
+/* Default pressure sensitivity */
 #define ST_PRESS_LSB_PER_MBAR			4096UL
 #define ST_PRESS_KPASCAL_NANO_SCALE		(100000000UL / \
 						 ST_PRESS_LSB_PER_MBAR)
+
+/* Default temperature sensitivity */
 #define ST_PRESS_LSB_PER_CELSIUS		480UL
-#define ST_PRESS_CELSIUS_NANO_SCALE		(1000000000UL / \
-						 ST_PRESS_LSB_PER_CELSIUS)
-#define ST_PRESS_NUMBER_DATA_CHANNELS		1
+#define ST_PRESS_MILLI_CELSIUS_OFFSET		42500UL
 
 /* FULLSCALE */
+#define ST_PRESS_FS_AVL_1100MB			1100
 #define ST_PRESS_FS_AVL_1260MB			1260
 
 #define ST_PRESS_1_OUT_XL_ADDR			0x28
 #define ST_TEMP_1_OUT_L_ADDR			0x2b
 
-/* CUSTOM VALUES FOR LPS331AP SENSOR */
+/*
+ * CUSTOM VALUES FOR LPS331AP SENSOR
+ * See LPS331AP datasheet:
+ * http://www2.st.com/resource/en/datasheet/lps331ap.pdf
+ */
 #define ST_PRESS_LPS331AP_WAI_EXP		0xbb
 #define ST_PRESS_LPS331AP_ODR_ADDR		0x20
 #define ST_PRESS_LPS331AP_ODR_MASK		0x70
@@ -54,18 +128,26 @@
 #define ST_PRESS_LPS331AP_PW_MASK		0x80
 #define ST_PRESS_LPS331AP_FS_ADDR		0x23
 #define ST_PRESS_LPS331AP_FS_MASK		0x30
-#define ST_PRESS_LPS331AP_FS_AVL_1260_VAL	0x00
-#define ST_PRESS_LPS331AP_FS_AVL_1260_GAIN	ST_PRESS_KPASCAL_NANO_SCALE
-#define ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN	ST_PRESS_CELSIUS_NANO_SCALE
 #define ST_PRESS_LPS331AP_BDU_ADDR		0x20
 #define ST_PRESS_LPS331AP_BDU_MASK		0x04
 #define ST_PRESS_LPS331AP_DRDY_IRQ_ADDR		0x22
 #define ST_PRESS_LPS331AP_DRDY_IRQ_INT1_MASK	0x04
 #define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK	0x20
+#define ST_PRESS_LPS331AP_IHL_IRQ_ADDR		0x22
+#define ST_PRESS_LPS331AP_IHL_IRQ_MASK		0x80
+#define ST_PRESS_LPS331AP_OD_IRQ_ADDR		0x22
+#define ST_PRESS_LPS331AP_OD_IRQ_MASK		0x40
 #define ST_PRESS_LPS331AP_MULTIREAD_BIT		true
-#define ST_PRESS_LPS331AP_TEMP_OFFSET		42500
 
-/* CUSTOM VALUES FOR LPS001WP SENSOR */
+/*
+ * CUSTOM VALUES FOR THE OBSOLETE LPS001WP SENSOR
+ */
+
+/* LPS001WP pressure resolution */
+#define ST_PRESS_LPS001WP_LSB_PER_MBAR		16UL
+/* LPS001WP temperature resolution */
+#define ST_PRESS_LPS001WP_LSB_PER_CELSIUS	64UL
+
 #define ST_PRESS_LPS001WP_WAI_EXP		0xba
 #define ST_PRESS_LPS001WP_ODR_ADDR		0x20
 #define ST_PRESS_LPS001WP_ODR_MASK		0x30
@@ -74,13 +156,19 @@
 #define ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL	0x03
 #define ST_PRESS_LPS001WP_PW_ADDR		0x20
 #define ST_PRESS_LPS001WP_PW_MASK		0x40
+#define ST_PRESS_LPS001WP_FS_AVL_PRESS_GAIN \
+	(100000000UL / ST_PRESS_LPS001WP_LSB_PER_MBAR)
 #define ST_PRESS_LPS001WP_BDU_ADDR		0x20
 #define ST_PRESS_LPS001WP_BDU_MASK		0x04
 #define ST_PRESS_LPS001WP_MULTIREAD_BIT		true
 #define ST_PRESS_LPS001WP_OUT_L_ADDR		0x28
 #define ST_TEMP_LPS001WP_OUT_L_ADDR		0x2a
 
-/* CUSTOM VALUES FOR LPS25H SENSOR */
+/*
+ * CUSTOM VALUES FOR LPS25H SENSOR
+ * See LPS25H datasheet:
+ * http://www2.st.com/resource/en/datasheet/lps25h.pdf
+ */
 #define ST_PRESS_LPS25H_WAI_EXP			0xbd
 #define ST_PRESS_LPS25H_ODR_ADDR		0x20
 #define ST_PRESS_LPS25H_ODR_MASK		0x70
@@ -90,44 +178,67 @@
 #define ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL	0x04
 #define ST_PRESS_LPS25H_PW_ADDR			0x20
 #define ST_PRESS_LPS25H_PW_MASK			0x80
-#define ST_PRESS_LPS25H_FS_ADDR			0x00
-#define ST_PRESS_LPS25H_FS_MASK			0x00
-#define ST_PRESS_LPS25H_FS_AVL_1260_VAL		0x00
-#define ST_PRESS_LPS25H_FS_AVL_1260_GAIN	ST_PRESS_KPASCAL_NANO_SCALE
-#define ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN	ST_PRESS_CELSIUS_NANO_SCALE
 #define ST_PRESS_LPS25H_BDU_ADDR		0x20
 #define ST_PRESS_LPS25H_BDU_MASK		0x04
 #define ST_PRESS_LPS25H_DRDY_IRQ_ADDR		0x23
 #define ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK	0x01
 #define ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK	0x10
+#define ST_PRESS_LPS25H_IHL_IRQ_ADDR		0x22
+#define ST_PRESS_LPS25H_IHL_IRQ_MASK		0x80
+#define ST_PRESS_LPS25H_OD_IRQ_ADDR		0x22
+#define ST_PRESS_LPS25H_OD_IRQ_MASK		0x40
 #define ST_PRESS_LPS25H_MULTIREAD_BIT		true
-#define ST_PRESS_LPS25H_TEMP_OFFSET		42500
 #define ST_PRESS_LPS25H_OUT_XL_ADDR		0x28
 #define ST_TEMP_LPS25H_OUT_L_ADDR		0x2b
 
+/*
+ * CUSTOM VALUES FOR LPS22HB SENSOR
+ * See LPS22HB datasheet:
+ * http://www2.st.com/resource/en/datasheet/lps22hb.pdf
+ */
+
+/* LPS22HB temperature sensitivity */
+#define ST_PRESS_LPS22HB_LSB_PER_CELSIUS	100UL
+
+#define ST_PRESS_LPS22HB_WAI_EXP		0xb1
+#define ST_PRESS_LPS22HB_ODR_ADDR		0x10
+#define ST_PRESS_LPS22HB_ODR_MASK		0x70
+#define ST_PRESS_LPS22HB_ODR_AVL_1HZ_VAL	0x01
+#define ST_PRESS_LPS22HB_ODR_AVL_10HZ_VAL	0x02
+#define ST_PRESS_LPS22HB_ODR_AVL_25HZ_VAL	0x03
+#define ST_PRESS_LPS22HB_ODR_AVL_50HZ_VAL	0x04
+#define ST_PRESS_LPS22HB_ODR_AVL_75HZ_VAL	0x05
+#define ST_PRESS_LPS22HB_PW_ADDR		0x10
+#define ST_PRESS_LPS22HB_PW_MASK		0x70
+#define ST_PRESS_LPS22HB_BDU_ADDR		0x10
+#define ST_PRESS_LPS22HB_BDU_MASK		0x02
+#define ST_PRESS_LPS22HB_DRDY_IRQ_ADDR		0x12
+#define ST_PRESS_LPS22HB_DRDY_IRQ_INT1_MASK	0x04
+#define ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK	0x08
+#define ST_PRESS_LPS22HB_IHL_IRQ_ADDR		0x12
+#define ST_PRESS_LPS22HB_IHL_IRQ_MASK		0x80
+#define ST_PRESS_LPS22HB_MULTIREAD_BIT		true
+
 static const struct iio_chan_spec st_press_1_channels[] = {
 	{
 		.type = IIO_PRESSURE,
-		.channel2 = IIO_NO_MOD,
 		.address = ST_PRESS_1_OUT_XL_ADDR,
-		.scan_index = ST_SENSORS_SCAN_X,
+		.scan_index = 0,
 		.scan_type = {
-			.sign = 'u',
+			.sign = 's',
 			.realbits = 24,
-			.storagebits = 24,
+			.storagebits = 32,
 			.endianness = IIO_LE,
 		},
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
-		.modified = 0,
 	},
 	{
 		.type = IIO_TEMP,
-		.channel2 = IIO_NO_MOD,
 		.address = ST_TEMP_1_OUT_L_ADDR,
-		.scan_index = -1,
+		.scan_index = 1,
 		.scan_type = {
-			.sign = 'u',
+			.sign = 's',
 			.realbits = 16,
 			.storagebits = 16,
 			.endianness = IIO_LE,
@@ -136,43 +247,74 @@
 			BIT(IIO_CHAN_INFO_RAW) |
 			BIT(IIO_CHAN_INFO_SCALE) |
 			BIT(IIO_CHAN_INFO_OFFSET),
-		.modified = 0,
 	},
-	IIO_CHAN_SOFT_TIMESTAMP(1)
+	IIO_CHAN_SOFT_TIMESTAMP(2)
 };
 
 static const struct iio_chan_spec st_press_lps001wp_channels[] = {
 	{
 		.type = IIO_PRESSURE,
-		.channel2 = IIO_NO_MOD,
 		.address = ST_PRESS_LPS001WP_OUT_L_ADDR,
-		.scan_index = ST_SENSORS_SCAN_X,
+		.scan_index = 0,
 		.scan_type = {
-			.sign = 'u',
+			.sign = 's',
 			.realbits = 16,
 			.storagebits = 16,
 			.endianness = IIO_LE,
 		},
-		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-		.modified = 0,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
 	},
 	{
 		.type = IIO_TEMP,
-		.channel2 = IIO_NO_MOD,
 		.address = ST_TEMP_LPS001WP_OUT_L_ADDR,
-		.scan_index = -1,
+		.scan_index = 1,
 		.scan_type = {
-			.sign = 'u',
+			.sign = 's',
 			.realbits = 16,
 			.storagebits = 16,
 			.endianness = IIO_LE,
 		},
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) |
-			BIT(IIO_CHAN_INFO_OFFSET),
-		.modified = 0,
+			BIT(IIO_CHAN_INFO_SCALE),
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(2)
+};
+
+static const struct iio_chan_spec st_press_lps22hb_channels[] = {
+	{
+		.type = IIO_PRESSURE,
+		.address = ST_PRESS_1_OUT_XL_ADDR,
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 24,
+			.storagebits = 32,
+			.endianness = IIO_LE,
+		},
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
 	},
-	IIO_CHAN_SOFT_TIMESTAMP(1)
+	{
+		.type = IIO_TEMP,
+		.address = ST_TEMP_1_OUT_L_ADDR,
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_LE,
+		},
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(2)
 };
 
 static const struct st_sensor_settings st_press_sensors_settings[] = {
@@ -204,11 +346,14 @@
 			.addr = ST_PRESS_LPS331AP_FS_ADDR,
 			.mask = ST_PRESS_LPS331AP_FS_MASK,
 			.fs_avl = {
+				/*
+				 * Pressure and temperature sensitivity values
+				 * as defined in table 3 of LPS331AP datasheet.
+				 */
 				[0] = {
 					.num = ST_PRESS_FS_AVL_1260MB,
-					.value = ST_PRESS_LPS331AP_FS_AVL_1260_VAL,
-					.gain = ST_PRESS_LPS331AP_FS_AVL_1260_GAIN,
-					.gain2 = ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN,
+					.gain = ST_PRESS_KPASCAL_NANO_SCALE,
+					.gain2 = ST_PRESS_LSB_PER_CELSIUS,
 				},
 			},
 		},
@@ -220,6 +365,11 @@
 			.addr = ST_PRESS_LPS331AP_DRDY_IRQ_ADDR,
 			.mask_int1 = ST_PRESS_LPS331AP_DRDY_IRQ_INT1_MASK,
 			.mask_int2 = ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK,
+			.addr_ihl = ST_PRESS_LPS331AP_IHL_IRQ_ADDR,
+			.mask_ihl = ST_PRESS_LPS331AP_IHL_IRQ_MASK,
+			.addr_od = ST_PRESS_LPS331AP_OD_IRQ_ADDR,
+			.mask_od = ST_PRESS_LPS331AP_OD_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_PRESS_LPS331AP_MULTIREAD_BIT,
 		.bootime = 2,
@@ -248,7 +398,17 @@
 			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
 		},
 		.fs = {
-			.addr = 0,
+			.fs_avl = {
+				/*
+				 * Pressure and temperature resolution values
+				 * as defined in table 3 of LPS001WP datasheet.
+				 */
+				[0] = {
+					.num = ST_PRESS_FS_AVL_1100MB,
+					.gain = ST_PRESS_LPS001WP_FS_AVL_PRESS_GAIN,
+					.gain2 = ST_PRESS_LPS001WP_LSB_PER_CELSIUS,
+				},
+			},
 		},
 		.bdu = {
 			.addr = ST_PRESS_LPS001WP_BDU_ADDR,
@@ -285,14 +445,15 @@
 			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
 		},
 		.fs = {
-			.addr = ST_PRESS_LPS25H_FS_ADDR,
-			.mask = ST_PRESS_LPS25H_FS_MASK,
 			.fs_avl = {
+				/*
+				 * Pressure and temperature sensitivity values
+				 * as defined in table 3 of LPS25H datasheet.
+				 */
 				[0] = {
 					.num = ST_PRESS_FS_AVL_1260MB,
-					.value = ST_PRESS_LPS25H_FS_AVL_1260_VAL,
-					.gain = ST_PRESS_LPS25H_FS_AVL_1260_GAIN,
-					.gain2 = ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN,
+					.gain = ST_PRESS_KPASCAL_NANO_SCALE,
+					.gain2 = ST_PRESS_LSB_PER_CELSIUS,
 				},
 			},
 		},
@@ -304,10 +465,64 @@
 			.addr = ST_PRESS_LPS25H_DRDY_IRQ_ADDR,
 			.mask_int1 = ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK,
 			.mask_int2 = ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK,
+			.addr_ihl = ST_PRESS_LPS25H_IHL_IRQ_ADDR,
+			.mask_ihl = ST_PRESS_LPS25H_IHL_IRQ_MASK,
+			.addr_od = ST_PRESS_LPS25H_OD_IRQ_ADDR,
+			.mask_od = ST_PRESS_LPS25H_OD_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT,
 		.bootime = 2,
 	},
+	{
+		.wai = ST_PRESS_LPS22HB_WAI_EXP,
+		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+		.sensors_supported = {
+			[0] = LPS22HB_PRESS_DEV_NAME,
+		},
+		.ch = (struct iio_chan_spec *)st_press_lps22hb_channels,
+		.num_ch = ARRAY_SIZE(st_press_lps22hb_channels),
+		.odr = {
+			.addr = ST_PRESS_LPS22HB_ODR_ADDR,
+			.mask = ST_PRESS_LPS22HB_ODR_MASK,
+			.odr_avl = {
+				{ 1, ST_PRESS_LPS22HB_ODR_AVL_1HZ_VAL, },
+				{ 10, ST_PRESS_LPS22HB_ODR_AVL_10HZ_VAL, },
+				{ 25, ST_PRESS_LPS22HB_ODR_AVL_25HZ_VAL, },
+				{ 50, ST_PRESS_LPS22HB_ODR_AVL_50HZ_VAL, },
+				{ 75, ST_PRESS_LPS22HB_ODR_AVL_75HZ_VAL, },
+			},
+		},
+		.pw = {
+			.addr = ST_PRESS_LPS22HB_PW_ADDR,
+			.mask = ST_PRESS_LPS22HB_PW_MASK,
+			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+		},
+		.fs = {
+			.fs_avl = {
+				/*
+				 * Pressure and temperature sensitivity values
+				 * as defined in table 3 of LPS22HB datasheet.
+				 */
+				[0] = {
+					.num = ST_PRESS_FS_AVL_1260MB,
+					.gain = ST_PRESS_KPASCAL_NANO_SCALE,
+					.gain2 = ST_PRESS_LPS22HB_LSB_PER_CELSIUS,
+				},
+			},
+		},
+		.bdu = {
+			.addr = ST_PRESS_LPS22HB_BDU_ADDR,
+			.mask = ST_PRESS_LPS22HB_BDU_MASK,
+		},
+		.drdy_irq = {
+			.addr = ST_PRESS_LPS22HB_DRDY_IRQ_ADDR,
+			.mask_int1 = ST_PRESS_LPS22HB_DRDY_IRQ_INT1_MASK,
+			.mask_int2 = ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK,
+		},
+		.multi_read_bit = ST_PRESS_LPS22HB_MULTIREAD_BIT,
+		.bootime = 2,
+	},
 };
 
 static int st_press_write_raw(struct iio_dev *indio_dev,
@@ -346,26 +561,26 @@
 
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-
 		switch (ch->type) {
 		case IIO_PRESSURE:
+			*val = 0;
 			*val2 = press_data->current_fullscale->gain;
-			break;
+			return IIO_VAL_INT_PLUS_NANO;
 		case IIO_TEMP:
+			*val = MCELSIUS_PER_CELSIUS;
 			*val2 = press_data->current_fullscale->gain2;
-			break;
+			return IIO_VAL_FRACTIONAL;
 		default:
 			err = -EINVAL;
 			goto read_error;
 		}
 
-		return IIO_VAL_INT_PLUS_NANO;
 	case IIO_CHAN_INFO_OFFSET:
 		switch (ch->type) {
 		case IIO_TEMP:
-			*val = 425;
-			*val2 = 10;
+			*val = ST_PRESS_MILLI_CELSIUS_OFFSET *
+			       press_data->current_fullscale->gain2;
+			*val2 = MCELSIUS_PER_CELSIUS;
 			break;
 		default:
 			err = -EINVAL;
@@ -407,6 +622,7 @@
 static const struct iio_trigger_ops st_press_trigger_ops = {
 	.owner = THIS_MODULE,
 	.set_trigger_state = ST_PRESS_TRIGGER_SET_STATE,
+	.validate_device = st_sensors_validate_device,
 };
 #define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops)
 #else
@@ -416,6 +632,8 @@
 int st_press_common_probe(struct iio_dev *indio_dev)
 {
 	struct st_sensor_data *press_data = iio_priv(indio_dev);
+	struct st_sensors_platform_data *pdata =
+		(struct st_sensors_platform_data *)press_data->dev->platform_data;
 	int irq = press_data->get_irq_data_ready(indio_dev);
 	int err;
 
@@ -423,39 +641,44 @@
 	indio_dev->info = &press_info;
 	mutex_init(&press_data->tb.buf_lock);
 
-	st_sensors_power_enable(indio_dev);
+	err = st_sensors_power_enable(indio_dev);
+	if (err)
+		return err;
 
 	err = st_sensors_check_device_support(indio_dev,
 					ARRAY_SIZE(st_press_sensors_settings),
 					st_press_sensors_settings);
 	if (err < 0)
-		return err;
+		goto st_press_power_off;
 
-	press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
+	/*
+	 * Skip timestamping channel while declaring available channels to
+	 * common st_sensor layer. Look at st_sensors_get_buffer_element() to
+	 * see how timestamps are explicitly pushed as last samples block
+	 * element.
+	 */
+	press_data->num_data_channels = press_data->sensor_settings->num_ch - 1;
 	press_data->multiread_bit = press_data->sensor_settings->multi_read_bit;
 	indio_dev->channels = press_data->sensor_settings->ch;
 	indio_dev->num_channels = press_data->sensor_settings->num_ch;
 
-	if (press_data->sensor_settings->fs.addr != 0)
-		press_data->current_fullscale =
-			(struct st_sensor_fullscale_avl *)
-				&press_data->sensor_settings->fs.fs_avl[0];
+	press_data->current_fullscale =
+		(struct st_sensor_fullscale_avl *)
+			&press_data->sensor_settings->fs.fs_avl[0];
 
 	press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
 
 	/* Some devices don't support a data ready pin. */
-	if (!press_data->dev->platform_data &&
-				press_data->sensor_settings->drdy_irq.addr)
-		press_data->dev->platform_data =
-			(struct st_sensors_platform_data *)&default_press_pdata;
+	if (!pdata && press_data->sensor_settings->drdy_irq.addr)
+		pdata =	(struct st_sensors_platform_data *)&default_press_pdata;
 
-	err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
+	err = st_sensors_init_sensor(indio_dev, pdata);
 	if (err < 0)
-		return err;
+		goto st_press_power_off;
 
 	err = st_press_allocate_ring(indio_dev);
 	if (err < 0)
-		return err;
+		goto st_press_power_off;
 
 	if (irq > 0) {
 		err = st_sensors_allocate_trigger(indio_dev,
@@ -478,6 +701,8 @@
 		st_sensors_deallocate_trigger(indio_dev);
 st_press_probe_trigger_error:
 	st_press_deallocate_ring(indio_dev);
+st_press_power_off:
+	st_sensors_power_disable(indio_dev);
 
 	return err;
 }
--- linux-4.4.0.orig/drivers/iio/pressure/st_pressure_i2c.c
+++ linux-4.4.0/drivers/iio/pressure/st_pressure_i2c.c
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
 
@@ -32,6 +33,10 @@
 		.compatible = "st,lps331ap-press",
 		.data = LPS331AP_PRESS_DEV_NAME,
 	},
+	{
+		.compatible = "st,lps22hb-press",
+		.data = LPS22HB_PRESS_DEV_NAME,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, st_press_of_match);
@@ -39,25 +44,56 @@
 #define st_press_of_match NULL
 #endif
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id st_press_acpi_match[] = {
+	{"SNO9210", LPS22HB},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, st_press_acpi_match);
+#else
+#define st_press_acpi_match NULL
+#endif
+
+static const struct i2c_device_id st_press_id_table[] = {
+	{ LPS001WP_PRESS_DEV_NAME, LPS001WP },
+	{ LPS25H_PRESS_DEV_NAME,  LPS25H },
+	{ LPS331AP_PRESS_DEV_NAME, LPS331AP },
+	{ LPS22HB_PRESS_DEV_NAME, LPS22HB },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, st_press_id_table);
+
 static int st_press_i2c_probe(struct i2c_client *client,
 						const struct i2c_device_id *id)
 {
 	struct iio_dev *indio_dev;
 	struct st_sensor_data *press_data;
-	int err;
+	int ret;
 
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*press_data));
 	if (!indio_dev)
 		return -ENOMEM;
 
 	press_data = iio_priv(indio_dev);
-	st_sensors_of_i2c_probe(client, st_press_of_match);
+
+	if (client->dev.of_node) {
+		st_sensors_of_i2c_probe(client, st_press_of_match);
+	} else if (ACPI_HANDLE(&client->dev)) {
+		ret = st_sensors_match_acpi_device(&client->dev);
+		if ((ret < 0) || (ret >= ST_PRESS_MAX))
+			return -ENODEV;
+
+		strncpy(client->name, st_press_id_table[ret].name,
+				sizeof(client->name));
+		client->name[sizeof(client->name) - 1] = '\0';
+	} else if (!id)
+		return -ENODEV;
 
 	st_sensors_i2c_configure(indio_dev, client, press_data);
 
-	err = st_press_common_probe(indio_dev);
-	if (err < 0)
-		return err;
+	ret = st_press_common_probe(indio_dev);
+	if (ret < 0)
+		return ret;
 
 	return 0;
 }
@@ -69,18 +105,11 @@
 	return 0;
 }
 
-static const struct i2c_device_id st_press_id_table[] = {
-	{ LPS001WP_PRESS_DEV_NAME },
-	{ LPS25H_PRESS_DEV_NAME },
-	{ LPS331AP_PRESS_DEV_NAME },
-	{},
-};
-MODULE_DEVICE_TABLE(i2c, st_press_id_table);
-
 static struct i2c_driver st_press_driver = {
 	.driver = {
 		.name = "st-press-i2c",
 		.of_match_table = of_match_ptr(st_press_of_match),
+		.acpi_match_table = ACPI_PTR(st_press_acpi_match),
 	},
 	.probe = st_press_i2c_probe,
 	.remove = st_press_i2c_remove,
--- linux-4.4.0.orig/drivers/iio/pressure/st_pressure_spi.c
+++ linux-4.4.0/drivers/iio/pressure/st_pressure_spi.c
@@ -50,6 +50,7 @@
 	{ LPS001WP_PRESS_DEV_NAME },
 	{ LPS25H_PRESS_DEV_NAME },
 	{ LPS331AP_PRESS_DEV_NAME },
+	{ LPS22HB_PRESS_DEV_NAME },
 	{},
 };
 MODULE_DEVICE_TABLE(spi, st_press_id_table);
--- linux-4.4.0.orig/drivers/iio/proximity/as3935.c
+++ linux-4.4.0/drivers/iio/proximity/as3935.c
@@ -40,9 +40,9 @@
 #define AS3935_AFE_PWR_BIT	BIT(0)
 
 #define AS3935_INT		0x03
-#define AS3935_INT_MASK		0x07
+#define AS3935_INT_MASK		0x0f
 #define AS3935_EVENT_INT	BIT(3)
-#define AS3935_NOISE_INT	BIT(1)
+#define AS3935_NOISE_INT	BIT(0)
 
 #define AS3935_DATA		0x07
 #define AS3935_DATA_MASK	0x3F
@@ -50,7 +50,6 @@
 #define AS3935_TUNE_CAP		0x08
 #define AS3935_CALIBRATE	0x3D
 
-#define AS3935_WRITE_DATA	BIT(15)
 #define AS3935_READ_DATA	BIT(14)
 #define AS3935_ADDRESS(x)	((x) << 8)
 
@@ -64,6 +63,7 @@
 	struct delayed_work work;
 
 	u32 tune_cap;
+	u8 buffer[16]; /* 8-bit data + 56-bit padding + 64-bit timestamp */
 	u8 buf[2] ____cacheline_aligned;
 };
 
@@ -72,7 +72,8 @@
 		.type           = IIO_PROXIMITY,
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) |
-			BIT(IIO_CHAN_INFO_PROCESSED),
+			BIT(IIO_CHAN_INFO_PROCESSED) |
+			BIT(IIO_CHAN_INFO_SCALE),
 		.scan_index     = 0,
 		.scan_type = {
 			.sign           = 'u',
@@ -103,7 +104,7 @@
 {
 	u8 *buf = st->buf;
 
-	buf[0] = (AS3935_WRITE_DATA | AS3935_ADDRESS(reg)) >> 8;
+	buf[0] = AS3935_ADDRESS(reg) >> 8;
 	buf[1] = val;
 
 	return spi_write(st->spi, buf, 2);
@@ -181,7 +182,12 @@
 		/* storm out of range */
 		if (*val == AS3935_DATA_MASK)
 			return -EINVAL;
-		*val *= 1000;
+
+		if (m == IIO_CHAN_INFO_PROCESSED)
+			*val *= 1000;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 1000;
 		break;
 	default:
 		return -EINVAL;
@@ -206,10 +212,10 @@
 	ret = as3935_read(st, AS3935_DATA, &val);
 	if (ret)
 		goto err_read;
-	val &= AS3935_DATA_MASK;
-	val *= 1000;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, &val, pf->timestamp);
+	st->buffer[0] = val & AS3935_DATA_MASK;
+	iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer,
+					   pf->timestamp);
 err_read:
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -257,8 +263,6 @@
 
 static void calibrate_as3935(struct as3935_state *st)
 {
-	mutex_lock(&st->lock);
-
 	/* mask disturber interrupt bit */
 	as3935_write(st, AS3935_INT, BIT(5));
 
@@ -268,8 +272,6 @@
 
 	mdelay(2);
 	as3935_write(st, AS3935_TUNE_CAP, (st->tune_cap / TUNE_CAP_DIV));
-
-	mutex_unlock(&st->lock);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -306,6 +308,8 @@
 	val &= ~AS3935_AFE_PWR_BIT;
 	ret = as3935_write(st, AS3935_AFE_GAIN, val);
 
+	calibrate_as3935(st);
+
 err_resume:
 	mutex_unlock(&st->lock);
 
@@ -385,7 +389,7 @@
 		return ret;
 	}
 
-	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+	ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
 		&as3935_trigger_handler, NULL);
 
 	if (ret) {
--- linux-4.4.0.orig/drivers/iio/trigger/iio-trig-interrupt.c
+++ linux-4.4.0/drivers/iio/trigger/iio-trig-interrupt.c
@@ -58,7 +58,7 @@
 	trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
 	if (!trig_info) {
 		ret = -ENOMEM;
-		goto error_put_trigger;
+		goto error_free_trigger;
 	}
 	iio_trigger_set_drvdata(trig, trig_info);
 	trig_info->irq = irq;
@@ -83,8 +83,8 @@
 	free_irq(irq, trig);
 error_free_trig_info:
 	kfree(trig_info);
-error_put_trigger:
-	iio_trigger_put(trig);
+error_free_trigger:
+	iio_trigger_free(trig);
 error_ret:
 	return ret;
 }
@@ -99,7 +99,7 @@
 	iio_trigger_unregister(trig);
 	free_irq(trig_info->irq, trig);
 	kfree(trig_info);
-	iio_trigger_put(trig);
+	iio_trigger_free(trig);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/iio/trigger/iio-trig-sysfs.c
+++ linux-4.4.0/drivers/iio/trigger/iio-trig-sysfs.c
@@ -174,7 +174,7 @@
 	return 0;
 
 out2:
-	iio_trigger_put(t->trig);
+	iio_trigger_free(t->trig);
 free_t:
 	kfree(t);
 out1:
--- linux-4.4.0.orig/drivers/infiniband/core/addr.c
+++ linux-4.4.0/drivers/infiniband/core/addr.c
@@ -86,6 +86,22 @@
 }
 EXPORT_SYMBOL(rdma_addr_size);
 
+int rdma_addr_size_in6(struct sockaddr_in6 *addr)
+{
+	int ret = rdma_addr_size((struct sockaddr *) addr);
+
+	return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_in6);
+
+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr)
+{
+	int ret = rdma_addr_size((struct sockaddr *) addr);
+
+	return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_kss);
+
 static struct rdma_addr_client self;
 
 void rdma_addr_register_client(struct rdma_addr_client *client)
@@ -277,9 +293,9 @@
 	fl6.saddr = src_in->sin6_addr;
 	fl6.flowi6_oif = addr->bound_dev_if;
 
-	dst = ip6_route_output(addr->net, NULL, &fl6);
-	if ((ret = dst->error))
-		goto put;
+	dst = ipv6_stub->ipv6_dst_lookup_flow(addr->net, NULL, &fl6, NULL);
+	if (IS_ERR(dst))
+		return PTR_ERR(dst);
 
 	if (ipv6_addr_any(&fl6.saddr)) {
 		ret = ipv6_dev_get_saddr(addr->net, ip6_dst_idev(dst)->dev,
@@ -465,14 +481,13 @@
 	struct net_device *dev;
 
 	union {
-		struct sockaddr     _sockaddr;
 		struct sockaddr_in  _sockaddr_in;
 		struct sockaddr_in6 _sockaddr_in6;
 	} sgid_addr, dgid_addr;
 
 
-	rdma_gid2ip(&sgid_addr._sockaddr, sgid);
-	rdma_gid2ip(&dgid_addr._sockaddr, dgid);
+	rdma_gid2ip((struct sockaddr *)&sgid_addr, sgid);
+	rdma_gid2ip((struct sockaddr *)&dgid_addr, dgid);
 
 	memset(&dev_addr, 0, sizeof(dev_addr));
 	dev_addr.bound_dev_if = if_index;
@@ -480,8 +495,9 @@
 
 	ctx.addr = &dev_addr;
 	init_completion(&ctx.comp);
-	ret = rdma_resolve_ip(&self, &sgid_addr._sockaddr, &dgid_addr._sockaddr,
-			&dev_addr, 1000, resolve_cb, &ctx);
+	ret = rdma_resolve_ip(&self, (struct sockaddr *)&sgid_addr,
+			      (struct sockaddr *)&dgid_addr, &dev_addr, 1000,
+			      resolve_cb, &ctx);
 	if (ret)
 		return ret;
 
@@ -503,16 +519,15 @@
 	int ret = 0;
 	struct rdma_dev_addr dev_addr;
 	union {
-		struct sockaddr     _sockaddr;
 		struct sockaddr_in  _sockaddr_in;
 		struct sockaddr_in6 _sockaddr_in6;
 	} gid_addr;
 
-	rdma_gid2ip(&gid_addr._sockaddr, sgid);
+	rdma_gid2ip((struct sockaddr *)&gid_addr, sgid);
 
 	memset(&dev_addr, 0, sizeof(dev_addr));
 	dev_addr.net = &init_net;
-	ret = rdma_translate_ip(&gid_addr._sockaddr, &dev_addr, vlan_id);
+	ret = rdma_translate_ip((struct sockaddr *)&gid_addr, &dev_addr, vlan_id);
 	if (ret)
 		return ret;
 
--- linux-4.4.0.orig/drivers/infiniband/core/cm.c
+++ linux-4.4.0/drivers/infiniband/core/cm.c
@@ -80,6 +80,8 @@
 	__be32 random_id_operand;
 	struct list_head timewait_list;
 	struct workqueue_struct *wq;
+	/* Sync on cm change port state */
+	spinlock_t state_lock;
 } cm;
 
 /* Counter indexes ordered by attribute ID */
@@ -161,6 +163,8 @@
 	struct ib_mad_agent *mad_agent;
 	struct kobject port_obj;
 	u8 port_num;
+	struct list_head cm_priv_prim_list;
+	struct list_head cm_priv_altr_list;
 	struct cm_counter_group counter_group[CM_COUNTER_GROUPS];
 };
 
@@ -241,6 +245,12 @@
 	u8 service_timeout;
 	u8 target_ack_delay;
 
+	struct list_head prim_list;
+	struct list_head altr_list;
+	/* Indicates that the send port mad is registered and av is set */
+	int prim_send_port_not_ready;
+	int altr_send_port_not_ready;
+
 	struct list_head work_list;
 	atomic_t work_count;
 };
@@ -259,20 +269,47 @@
 	struct ib_mad_agent *mad_agent;
 	struct ib_mad_send_buf *m;
 	struct ib_ah *ah;
+	struct cm_av *av;
+	unsigned long flags, flags2;
+	int ret = 0;
 
+	/* don't let the port to be released till the agent is down */
+	spin_lock_irqsave(&cm.state_lock, flags2);
+	spin_lock_irqsave(&cm.lock, flags);
+	if (!cm_id_priv->prim_send_port_not_ready)
+		av = &cm_id_priv->av;
+	else if (!cm_id_priv->altr_send_port_not_ready &&
+		 (cm_id_priv->alt_av.port))
+		av = &cm_id_priv->alt_av;
+	else {
+		pr_info("%s: not valid CM id\n", __func__);
+		ret = -ENODEV;
+		spin_unlock_irqrestore(&cm.lock, flags);
+		goto out;
+	}
+	spin_unlock_irqrestore(&cm.lock, flags);
+	/* Make sure the port haven't released the mad yet */
 	mad_agent = cm_id_priv->av.port->mad_agent;
-	ah = ib_create_ah(mad_agent->qp->pd, &cm_id_priv->av.ah_attr);
-	if (IS_ERR(ah))
-		return PTR_ERR(ah);
+	if (!mad_agent) {
+		pr_info("%s: not a valid MAD agent\n", __func__);
+		ret = -ENODEV;
+		goto out;
+	}
+	ah = ib_create_ah(mad_agent->qp->pd, &av->ah_attr);
+	if (IS_ERR(ah)) {
+		ret = PTR_ERR(ah);
+		goto out;
+	}
 
 	m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
-			       cm_id_priv->av.pkey_index,
+			       av->pkey_index,
 			       0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
 			       GFP_ATOMIC,
 			       IB_MGMT_BASE_VERSION);
 	if (IS_ERR(m)) {
 		ib_destroy_ah(ah);
-		return PTR_ERR(m);
+		ret = PTR_ERR(m);
+		goto out;
 	}
 
 	/* Timeout set by caller if response is expected. */
@@ -282,7 +319,10 @@
 	atomic_inc(&cm_id_priv->refcount);
 	m->context[0] = cm_id_priv;
 	*msg = m;
-	return 0;
+
+out:
+	spin_unlock_irqrestore(&cm.state_lock, flags2);
+	return ret;
 }
 
 static int cm_alloc_response_msg(struct cm_port *port,
@@ -352,7 +392,8 @@
 			   grh, &av->ah_attr);
 }
 
-static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
+static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av,
+			      struct cm_id_private *cm_id_priv)
 {
 	struct cm_device *cm_dev;
 	struct cm_port *port = NULL;
@@ -387,7 +428,17 @@
 			     &av->ah_attr);
 	av->timeout = path->packet_life_time + 1;
 
-	return 0;
+	spin_lock_irqsave(&cm.lock, flags);
+	if (&cm_id_priv->av == av)
+		list_add_tail(&cm_id_priv->prim_list, &port->cm_priv_prim_list);
+	else if (&cm_id_priv->alt_av == av)
+		list_add_tail(&cm_id_priv->altr_list, &port->cm_priv_altr_list);
+	else
+		ret = -EINVAL;
+
+	spin_unlock_irqrestore(&cm.lock, flags);
+
+	return ret;
 }
 
 static int cm_alloc_id(struct cm_id_private *cm_id_priv)
@@ -677,6 +728,8 @@
 	spin_lock_init(&cm_id_priv->lock);
 	init_completion(&cm_id_priv->comp);
 	INIT_LIST_HEAD(&cm_id_priv->work_list);
+	INIT_LIST_HEAD(&cm_id_priv->prim_list);
+	INIT_LIST_HEAD(&cm_id_priv->altr_list);
 	atomic_set(&cm_id_priv->work_count, -1);
 	atomic_set(&cm_id_priv->refcount, 1);
 	return &cm_id_priv->id;
@@ -782,11 +835,11 @@
 	wait_time = cm_convert_to_ms(cm_id_priv->av.timeout);
 
 	/* Check if the device started its remove_one */
-	spin_lock_irq(&cm.lock);
+	spin_lock_irqsave(&cm.lock, flags);
 	if (!cm_dev->going_down)
 		queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,
 				   msecs_to_jiffies(wait_time));
-	spin_unlock_irq(&cm.lock);
+	spin_unlock_irqrestore(&cm.lock, flags);
 
 	cm_id_priv->timewait_info = NULL;
 }
@@ -892,6 +945,15 @@
 		break;
 	}
 
+	spin_lock_irq(&cm.lock);
+	if (!list_empty(&cm_id_priv->altr_list) &&
+	    (!cm_id_priv->altr_send_port_not_ready))
+		list_del(&cm_id_priv->altr_list);
+	if (!list_empty(&cm_id_priv->prim_list) &&
+	    (!cm_id_priv->prim_send_port_not_ready))
+		list_del(&cm_id_priv->prim_list);
+	spin_unlock_irq(&cm.lock);
+
 	cm_free_id(cm_id->local_id);
 	cm_deref_id(cm_id_priv);
 	wait_for_completion(&cm_id_priv->comp);
@@ -1011,6 +1073,7 @@
 			/* Sharing an ib_cm_id with different handlers is not
 			 * supported */
 			spin_unlock_irqrestore(&cm.lock, flags);
+			ib_destroy_cm_id(cm_id);
 			return ERR_PTR(-EINVAL);
 		}
 		atomic_inc(&cm_id_priv->refcount);
@@ -1189,15 +1252,17 @@
 							    id.local_id);
 	if (IS_ERR(cm_id_priv->timewait_info)) {
 		ret = PTR_ERR(cm_id_priv->timewait_info);
+		cm_id_priv->timewait_info = NULL;
 		goto out;
 	}
 
-	ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av);
+	ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av,
+				 cm_id_priv);
 	if (ret)
 		goto error1;
 	if (param->alternate_path) {
 		ret = cm_init_av_by_path(param->alternate_path,
-					 &cm_id_priv->alt_av);
+					 &cm_id_priv->alt_av, cm_id_priv);
 		if (ret)
 			goto error1;
 	}
@@ -1617,6 +1682,7 @@
 							    id.local_id);
 	if (IS_ERR(cm_id_priv->timewait_info)) {
 		ret = PTR_ERR(cm_id_priv->timewait_info);
+		cm_id_priv->timewait_info = NULL;
 		goto destroy;
 	}
 	cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id;
@@ -1639,7 +1705,8 @@
 	cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
 
 	memcpy(work->path[0].dmac, cm_id_priv->av.ah_attr.dmac, ETH_ALEN);
-	ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
+	ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av,
+				 cm_id_priv);
 	if (ret) {
 		ib_get_cached_gid(work->port->cm_dev->ib_device,
 				  work->port->port_num, 0, &work->path[0].sgid,
@@ -1650,7 +1717,8 @@
 		goto rejected;
 	}
 	if (req_msg->alt_local_lid) {
-		ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av);
+		ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av,
+					 cm_id_priv);
 		if (ret) {
 			ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID,
 				       &work->path[0].sgid,
@@ -2705,7 +2773,8 @@
 		goto out;
 	}
 
-	ret = cm_init_av_by_path(alternate_path, &cm_id_priv->alt_av);
+	ret = cm_init_av_by_path(alternate_path, &cm_id_priv->alt_av,
+				 cm_id_priv);
 	if (ret)
 		goto out;
 	cm_id_priv->alt_av.timeout =
@@ -2817,7 +2886,8 @@
 	cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
 				work->mad_recv_wc->recv_buf.grh,
 				&cm_id_priv->av);
-	cm_init_av_by_path(param->alternate_path, &cm_id_priv->alt_av);
+	cm_init_av_by_path(param->alternate_path, &cm_id_priv->alt_av,
+			   cm_id_priv);
 	ret = atomic_inc_and_test(&cm_id_priv->work_count);
 	if (!ret)
 		list_add_tail(&work->list, &cm_id_priv->work_list);
@@ -3009,7 +3079,7 @@
 		return -EINVAL;
 
 	cm_id_priv = container_of(cm_id, struct cm_id_private, id);
-	ret = cm_init_av_by_path(param->path, &cm_id_priv->av);
+	ret = cm_init_av_by_path(param->path, &cm_id_priv->av, cm_id_priv);
 	if (ret)
 		goto out;
 
@@ -3430,14 +3500,14 @@
 	work->cm_event.event = IB_CM_USER_ESTABLISHED;
 
 	/* Check if the device started its remove_one */
-	spin_lock_irq(&cm.lock);
+	spin_lock_irqsave(&cm.lock, flags);
 	if (!cm_dev->going_down) {
 		queue_delayed_work(cm.wq, &work->work, 0);
 	} else {
 		kfree(work);
 		ret = -ENODEV;
 	}
-	spin_unlock_irq(&cm.lock);
+	spin_unlock_irqrestore(&cm.lock, flags);
 
 out:
 	return ret;
@@ -3446,7 +3516,9 @@
 static int cm_migrate(struct ib_cm_id *cm_id)
 {
 	struct cm_id_private *cm_id_priv;
+	struct cm_av tmp_av;
 	unsigned long flags;
+	int tmp_send_port_not_ready;
 	int ret = 0;
 
 	cm_id_priv = container_of(cm_id, struct cm_id_private, id);
@@ -3455,7 +3527,14 @@
 	    (cm_id->lap_state == IB_CM_LAP_UNINIT ||
 	     cm_id->lap_state == IB_CM_LAP_IDLE)) {
 		cm_id->lap_state = IB_CM_LAP_IDLE;
+		/* Swap address vector */
+		tmp_av = cm_id_priv->av;
 		cm_id_priv->av = cm_id_priv->alt_av;
+		cm_id_priv->alt_av = tmp_av;
+		/* Swap port send ready state */
+		tmp_send_port_not_ready = cm_id_priv->prim_send_port_not_ready;
+		cm_id_priv->prim_send_port_not_ready = cm_id_priv->altr_send_port_not_ready;
+		cm_id_priv->altr_send_port_not_ready = tmp_send_port_not_ready;
 	} else
 		ret = -EINVAL;
 	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -3482,6 +3561,7 @@
 EXPORT_SYMBOL(ib_cm_notify);
 
 static void cm_recv_handler(struct ib_mad_agent *mad_agent,
+			    struct ib_mad_send_buf *send_buf,
 			    struct ib_mad_recv_wc *mad_recv_wc)
 {
 	struct cm_port *port = mad_agent->context;
@@ -3875,6 +3955,9 @@
 		port->cm_dev = cm_dev;
 		port->port_num = i;
 
+		INIT_LIST_HEAD(&port->cm_priv_prim_list);
+		INIT_LIST_HEAD(&port->cm_priv_altr_list);
+
 		ret = cm_create_port_fs(port);
 		if (ret)
 			goto error1;
@@ -3932,6 +4015,8 @@
 {
 	struct cm_device *cm_dev = client_data;
 	struct cm_port *port;
+	struct cm_id_private *cm_id_priv;
+	struct ib_mad_agent *cur_mad_agent;
 	struct ib_port_modify port_modify = {
 		.clr_port_cap_mask = IB_PORT_CM_SUP
 	};
@@ -3955,15 +4040,27 @@
 
 		port = cm_dev->port[i-1];
 		ib_modify_port(ib_device, port->port_num, 0, &port_modify);
+		/* Mark all the cm_id's as not valid */
+		spin_lock_irq(&cm.lock);
+		list_for_each_entry(cm_id_priv, &port->cm_priv_altr_list, altr_list)
+			cm_id_priv->altr_send_port_not_ready = 1;
+		list_for_each_entry(cm_id_priv, &port->cm_priv_prim_list, prim_list)
+			cm_id_priv->prim_send_port_not_ready = 1;
+		spin_unlock_irq(&cm.lock);
 		/*
 		 * We flush the queue here after the going_down set, this
 		 * verify that no new works will be queued in the recv handler,
 		 * after that we can call the unregister_mad_agent
 		 */
 		flush_workqueue(cm.wq);
-		ib_unregister_mad_agent(port->mad_agent);
+		spin_lock_irq(&cm.state_lock);
+		cur_mad_agent = port->mad_agent;
+		port->mad_agent = NULL;
+		spin_unlock_irq(&cm.state_lock);
+		ib_unregister_mad_agent(cur_mad_agent);
 		cm_remove_port_fs(port);
 	}
+
 	device_unregister(cm_dev->device);
 	kfree(cm_dev);
 }
@@ -3976,6 +4073,7 @@
 	INIT_LIST_HEAD(&cm.device_list);
 	rwlock_init(&cm.device_lock);
 	spin_lock_init(&cm.lock);
+	spin_lock_init(&cm.state_lock);
 	cm.listen_service_table = RB_ROOT;
 	cm.listen_service_id = be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID);
 	cm.remote_id_table = RB_ROOT;
--- linux-4.4.0.orig/drivers/infiniband/core/cma.c
+++ linux-4.4.0/drivers/infiniband/core/cma.c
@@ -453,7 +453,7 @@
 	if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port))
 		return ret;
 
-	if (dev_type == ARPHRD_ETHER)
+	if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port))
 		ndev = dev_get_by_index(&init_net, bound_if_index);
 
 	ret = ib_find_cached_gid_by_port(device, gid, port, ndev, NULL);
@@ -544,6 +544,7 @@
 	dgid = (union ib_gid *) &addr->sib_addr;
 	pkey = ntohs(addr->sib_pkey);
 
+	mutex_lock(&lock);
 	list_for_each_entry(cur_dev, &dev_list, list) {
 		for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
 			if (!rdma_cap_af_ib(cur_dev->device, p))
@@ -567,18 +568,19 @@
 					cma_dev = cur_dev;
 					sgid = gid;
 					id_priv->id.port_num = p;
+					goto found;
 				}
 			}
 		}
 	}
-
-	if (!cma_dev)
-		return -ENODEV;
+	mutex_unlock(&lock);
+	return -ENODEV;
 
 found:
 	cma_attach_to_dev(id_priv, cma_dev);
-	addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
-	memcpy(&addr->sib_addr, &sgid, sizeof sgid);
+	mutex_unlock(&lock);
+	addr = (struct sockaddr_ib *)cma_src_addr(id_priv);
+	memcpy(&addr->sib_addr, &sgid, sizeof(sgid));
 	cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
 	return 0;
 }
@@ -626,6 +628,7 @@
 	INIT_LIST_HEAD(&id_priv->mc_list);
 	get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num);
 	id_priv->id.route.addr.dev_addr.net = get_net(net);
+	id_priv->seq_num &= 0x00ffffff;
 
 	return &id_priv->id;
 }
@@ -857,6 +860,8 @@
 		} else
 			ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
 						 qp_attr_mask);
+		qp_attr->port_num = id_priv->id.port_num;
+		*qp_attr_mask |= IB_QP_PORT;
 	} else
 		ret = -ENOSYS;
 
@@ -1277,9 +1282,16 @@
 		       (addr->src_addr.ss_family == AF_IB ||
 			cma_protocol_roce_dev_port(id->device, port_num));
 
-	return !addr->dev_addr.bound_dev_if ||
-	       (net_eq(dev_net(net_dev), addr->dev_addr.net) &&
-		addr->dev_addr.bound_dev_if == net_dev->ifindex);
+	/*
+	 * Net namespaces must match, and if the listner is listening
+	 * on a specific netdevice than netdevice must match as well.
+	 */
+	if (net_eq(dev_net(net_dev), addr->dev_addr.net) &&
+	    (!!addr->dev_addr.bound_dev_if ==
+	     (addr->dev_addr.bound_dev_if == net_dev->ifindex)))
+		return true;
+	else
+		return false;
 }
 
 static struct rdma_id_private *cma_find_listener(
@@ -1351,7 +1363,7 @@
 	return id_priv;
 }
 
-static inline int cma_user_data_offset(struct rdma_id_private *id_priv)
+static inline u8 cma_user_data_offset(struct rdma_id_private *id_priv)
 {
 	return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr);
 }
@@ -1729,7 +1741,8 @@
 	struct rdma_id_private *listen_id, *conn_id;
 	struct rdma_cm_event event;
 	struct net_device *net_dev;
-	int offset, ret;
+	u8 offset;
+	int ret;
 
 	listen_id = cma_id_from_event(cm_id, ib_event, &net_dev);
 	if (IS_ERR(listen_id))
@@ -1963,9 +1976,10 @@
 		conn_id->cm_id.iw = NULL;
 		cma_exch(conn_id, RDMA_CM_DESTROYING);
 		mutex_unlock(&conn_id->handler_mutex);
+		mutex_unlock(&listen_id->handler_mutex);
 		cma_deref_id(conn_id);
 		rdma_destroy_id(&conn_id->id);
-		goto out;
+		return ret;
 	}
 
 	mutex_unlock(&conn_id->handler_mutex);
@@ -2213,7 +2227,8 @@
 	work->new_state = RDMA_CM_ROUTE_RESOLVED;
 	work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
 
-	route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
+	if (!route->path_rec)
+		route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
 	if (!route->path_rec) {
 		ret = -ENOMEM;
 		goto err1;
@@ -2364,6 +2379,7 @@
 err2:
 	kfree(route->path_rec);
 	route->path_rec = NULL;
+	route->num_paths = 0;
 err1:
 	kfree(work);
 	return ret;
@@ -2578,7 +2594,8 @@
 	if (!src_addr || !src_addr->sa_family) {
 		src_addr = (struct sockaddr *) &id->route.addr.src_addr;
 		src_addr->sa_family = dst_addr->sa_family;
-		if (dst_addr->sa_family == AF_INET6) {
+		if (IS_ENABLED(CONFIG_IPV6) &&
+		    dst_addr->sa_family == AF_INET6) {
 			struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr;
 			struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr;
 			src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
@@ -3115,7 +3132,8 @@
 	struct ib_cm_sidr_req_param req;
 	struct ib_cm_id	*id;
 	void *private_data;
-	int offset, ret;
+	u8 offset;
+	int ret;
 
 	memset(&req, 0, sizeof req);
 	offset = cma_user_data_offset(id_priv);
@@ -3172,7 +3190,8 @@
 	struct rdma_route *route;
 	void *private_data;
 	struct ib_cm_id	*id;
-	int offset, ret;
+	u8 offset;
+	int ret;
 
 	memset(&req, 0, sizeof req);
 	offset = cma_user_data_offset(id_priv);
@@ -3348,6 +3367,9 @@
 	struct iw_cm_conn_param iw_param;
 	int ret;
 
+	if (!conn_param)
+		return -EINVAL;
+
 	ret = cma_modify_qp_rtr(id_priv, conn_param);
 	if (ret)
 		return ret;
@@ -3388,14 +3410,15 @@
 
 int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
 {
-	struct rdma_id_private *id_priv;
+	struct rdma_id_private *id_priv =
+		container_of(id, struct rdma_id_private, id);
 	int ret;
 
-	id_priv = container_of(id, struct rdma_id_private, id);
+	lockdep_assert_held(&id_priv->handler_mutex);
 
 	id_priv->owner = task_pid_nr(current);
 
-	if (!cma_comp(id_priv, RDMA_CM_CONNECT))
+	if (READ_ONCE(id_priv->state) != RDMA_CM_CONNECT)
 		return -EINVAL;
 
 	if (!id->qp && conn_param) {
@@ -3435,6 +3458,24 @@
 }
 EXPORT_SYMBOL(rdma_accept);
 
+void rdma_lock_handler(struct rdma_cm_id *id)
+{
+	struct rdma_id_private *id_priv =
+		container_of(id, struct rdma_id_private, id);
+
+	mutex_lock(&id_priv->handler_mutex);
+}
+EXPORT_SYMBOL(rdma_lock_handler);
+
+void rdma_unlock_handler(struct rdma_cm_id *id)
+{
+	struct rdma_id_private *id_priv =
+		container_of(id, struct rdma_id_private, id);
+
+	mutex_unlock(&id_priv->handler_mutex);
+}
+EXPORT_SYMBOL(rdma_unlock_handler);
+
 int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event)
 {
 	struct rdma_id_private *id_priv;
@@ -3733,6 +3774,9 @@
 	struct cma_multicast *mc;
 	int ret;
 
+	if (!id->device)
+		return -EINVAL;
+
 	id_priv = container_of(id, struct rdma_id_private, id);
 	if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) &&
 	    !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))
@@ -3997,7 +4041,7 @@
 					  RDMA_NL_RDMA_CM_ATTR_SRC_ADDR))
 				goto out;
 			if (ibnl_put_attr(skb, nlh,
-					  rdma_addr_size(cma_src_addr(id_priv)),
+					  rdma_addr_size(cma_dst_addr(id_priv)),
 					  cma_dst_addr(id_priv),
 					  RDMA_NL_RDMA_CM_ATTR_DST_ADDR))
 				goto out;
@@ -4086,6 +4130,7 @@
 	unregister_netdevice_notifier(&cma_nb);
 	rdma_addr_unregister_client(&addr_client);
 	ib_sa_unregister_client(&sa_client);
+	unregister_pernet_subsys(&cma_pernet_operations);
 err_wq:
 	destroy_workqueue(cma_wq);
 	return ret;
--- linux-4.4.0.orig/drivers/infiniband/core/iwcm.c
+++ linux-4.4.0/drivers/infiniband/core/iwcm.c
@@ -125,8 +125,10 @@
 {
 	struct list_head *e, *tmp;
 
-	list_for_each_safe(e, tmp, &cm_id_priv->work_free_list)
+	list_for_each_safe(e, tmp, &cm_id_priv->work_free_list) {
+		list_del(e);
 		kfree(list_entry(e, struct iwcm_work, free_list));
+	}
 }
 
 static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count)
--- linux-4.4.0.orig/drivers/infiniband/core/iwpm_util.c
+++ linux-4.4.0/drivers/infiniband/core/iwpm_util.c
@@ -634,6 +634,7 @@
 	if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
 			   RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
 		pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
+		dev_kfree_skb(skb);
 		return -ENOMEM;
 	}
 	nlh->nlmsg_type = NLMSG_DONE;
@@ -662,6 +663,7 @@
 	}
 	skb_num++;
 	spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
+	ret = -EINVAL;
 	for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
 		hlist_for_each_entry(map_info, &iwpm_hash_bucket[i],
 				     hlist_node) {
--- linux-4.4.0.orig/drivers/infiniband/core/mad.c
+++ linux-4.4.0/drivers/infiniband/core/mad.c
@@ -681,7 +681,7 @@
 
 		atomic_inc(&mad_snoop_priv->refcount);
 		spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
-		mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent,
+		mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent, NULL,
 						   mad_recv_wc);
 		deref_snoop_agent(mad_snoop_priv);
 		spin_lock_irqsave(&qp_info->snoop_lock, flags);
@@ -1284,7 +1284,7 @@
 			spin_lock_irqsave(&mad_agent_priv->lock, flags);
 			list_del(&mad_send_wr->agent_list);
 			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
-			atomic_dec(&mad_agent_priv->refcount);
+			deref_mad_agent(mad_agent_priv);
 			goto error;
 		}
 	}
@@ -1548,7 +1548,8 @@
 			    mad_reg_req->oui, 3)) {
 			method = &(*vendor_table)->vendor_class[
 						vclass]->method_table[i];
-			BUG_ON(!*method);
+			if (!*method)
+				goto error3;
 			goto check_in_use;
 		}
 	}
@@ -1558,10 +1559,12 @@
 				vclass]->oui[i])) {
 			method = &(*vendor_table)->vendor_class[
 				vclass]->method_table[i];
-			BUG_ON(*method);
 			/* Allocate method table for this OUI */
-			if ((ret = allocate_method_table(method)))
-				goto error3;
+			if (!*method) {
+				ret = allocate_method_table(method);
+				if (ret)
+					goto error3;
+			}
 			memcpy((*vendor_table)->vendor_class[vclass]->oui[i],
 			       mad_reg_req->oui, 3);
 			goto check_in_use;
@@ -1745,7 +1748,7 @@
 			if (!class)
 				goto out;
 			if (convert_mgmt_class(mad_hdr->mgmt_class) >=
-			    IB_MGMT_MAX_METHODS)
+			    ARRAY_SIZE(class->method_table))
 				goto out;
 			method = class->method_table[convert_mgmt_class(
 							mad_hdr->mgmt_class)];
@@ -1982,10 +1985,10 @@
 				/* user rmpp is in effect
 				 * and this is an active RMPP MAD
 				 */
-				mad_recv_wc->wc->wr_id = 0;
-				mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent,
-								   mad_recv_wc);
-				atomic_dec(&mad_agent_priv->refcount);
+				mad_agent_priv->agent.recv_handler(
+						&mad_agent_priv->agent, NULL,
+						mad_recv_wc);
+				deref_mad_agent(mad_agent_priv);
 			} else {
 				/* not user rmpp, revert to normal behavior and
 				 * drop the mad */
@@ -1998,10 +2001,11 @@
 			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 
 			/* Defined behavior is to complete response before request */
-			mad_recv_wc->wc->wr_id = (unsigned long) &mad_send_wr->send_buf;
-			mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent,
-							   mad_recv_wc);
-			atomic_dec(&mad_agent_priv->refcount);
+			mad_agent_priv->agent.recv_handler(
+					&mad_agent_priv->agent,
+					&mad_send_wr->send_buf,
+					mad_recv_wc);
+			deref_mad_agent(mad_agent_priv);
 
 			mad_send_wc.status = IB_WC_SUCCESS;
 			mad_send_wc.vendor_err = 0;
@@ -2009,7 +2013,7 @@
 			ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc);
 		}
 	} else {
-		mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent,
+		mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, NULL,
 						   mad_recv_wc);
 		deref_mad_agent(mad_agent_priv);
 	}
@@ -2609,7 +2613,7 @@
 		list_del(&mad_send_wr->agent_list);
 		mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
 						   &mad_send_wc);
-		atomic_dec(&mad_agent_priv->refcount);
+		deref_mad_agent(mad_agent_priv);
 	}
 }
 
@@ -2744,9 +2748,10 @@
 					   IB_MAD_SNOOP_RECVS);
 			recv_mad_agent->agent.recv_handler(
 						&recv_mad_agent->agent,
+						&local->mad_send_wr->send_buf,
 						&local->mad_priv->header.recv_wc);
 			spin_lock_irqsave(&recv_mad_agent->lock, flags);
-			atomic_dec(&recv_mad_agent->refcount);
+			deref_mad_agent(recv_mad_agent);
 			spin_unlock_irqrestore(&recv_mad_agent->lock, flags);
 		}
 
@@ -2763,7 +2768,7 @@
 						   &mad_send_wc);
 
 		spin_lock_irqsave(&mad_agent_priv->lock, flags);
-		atomic_dec(&mad_agent_priv->refcount);
+		deref_mad_agent(mad_agent_priv);
 		if (free_mad)
 			kfree(local->mad_priv);
 		kfree(local);
@@ -2809,14 +2814,16 @@
 
 static void timeout_sends(struct work_struct *work)
 {
+	struct ib_mad_send_wr_private *mad_send_wr, *n;
 	struct ib_mad_agent_private *mad_agent_priv;
-	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wc mad_send_wc;
+	struct list_head local_list;
 	unsigned long flags, delay;
 
 	mad_agent_priv = container_of(work, struct ib_mad_agent_private,
 				      timed_work.work);
 	mad_send_wc.vendor_err = 0;
+	INIT_LIST_HEAD(&local_list);
 
 	spin_lock_irqsave(&mad_agent_priv->lock, flags);
 	while (!list_empty(&mad_agent_priv->wait_list)) {
@@ -2834,13 +2841,16 @@
 			break;
 		}
 
-		list_del(&mad_send_wr->agent_list);
+		list_del_init(&mad_send_wr->agent_list);
 		if (mad_send_wr->status == IB_WC_SUCCESS &&
 		    !retry_send(mad_send_wr))
 			continue;
 
-		spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
+		list_add_tail(&mad_send_wr->agent_list, &local_list);
+	}
+	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 
+	list_for_each_entry_safe(mad_send_wr, n, &local_list, agent_list) {
 		if (mad_send_wr->status == IB_WC_SUCCESS)
 			mad_send_wc.status = IB_WC_RESP_TIMEOUT_ERR;
 		else
@@ -2848,11 +2858,8 @@
 		mad_send_wc.send_buf = &mad_send_wr->send_buf;
 		mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
 						   &mad_send_wc);
-
-		atomic_dec(&mad_agent_priv->refcount);
-		spin_lock_irqsave(&mad_agent_priv->lock, flags);
+		deref_mad_agent(mad_agent_priv);
 	}
-	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 }
 
 static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg)
@@ -2909,6 +2916,7 @@
 						 DMA_FROM_DEVICE);
 		if (unlikely(ib_dma_mapping_error(qp_info->port_priv->device,
 						  sg_list.addr))) {
+			kfree(mad_priv);
 			ret = -ENOMEM;
 			break;
 		}
--- linux-4.4.0.orig/drivers/infiniband/core/multicast.c
+++ linux-4.4.0/drivers/infiniband/core/multicast.c
@@ -106,7 +106,6 @@
 	atomic_t		refcount;
 	enum mcast_group_state	state;
 	struct ib_sa_query	*query;
-	int			query_id;
 	u16			pkey_index;
 	u8			leave_state;
 	int			retries;
@@ -339,11 +338,7 @@
 				       member->multicast.comp_mask,
 				       3000, GFP_KERNEL, join_handler, group,
 				       &group->query);
-	if (ret >= 0) {
-		group->query_id = ret;
-		ret = 0;
-	}
-	return ret;
+	return (ret > 0) ? 0 : ret;
 }
 
 static int send_leave(struct mcast_group *group, u8 leave_state)
@@ -363,11 +358,7 @@
 				       IB_SA_MCMEMBER_REC_JOIN_STATE,
 				       3000, GFP_KERNEL, leave_handler,
 				       group, &group->query);
-	if (ret >= 0) {
-		group->query_id = ret;
-		ret = 0;
-	}
-	return ret;
+	return (ret > 0) ? 0 : ret;
 }
 
 static void join_group(struct mcast_group *group, struct mcast_member *member,
@@ -526,8 +517,11 @@
 		process_join_error(group, status);
 	else {
 		int mgids_changed, is_mgid0;
-		ib_find_pkey(group->port->dev->device, group->port->port_num,
-			     be16_to_cpu(rec->pkey), &pkey_index);
+
+		if (ib_find_pkey(group->port->dev->device,
+				 group->port->port_num, be16_to_cpu(rec->pkey),
+				 &pkey_index))
+			pkey_index = MCAST_INVALID_PKEY_INDEX;
 
 		spin_lock_irq(&group->port->lock);
 		if (group->state == MCAST_BUSY &&
--- linux-4.4.0.orig/drivers/infiniband/core/sa_query.c
+++ linux-4.4.0/drivers/infiniband/core/sa_query.c
@@ -534,7 +534,7 @@
 	data = ibnl_put_msg(skb, &nlh, query->seq, 0, RDMA_NL_LS,
 			    RDMA_NL_LS_OP_RESOLVE, NLM_F_REQUEST);
 	if (!data) {
-		kfree_skb(skb);
+		nlmsg_free(skb);
 		return -EMSGSIZE;
 	}
 
@@ -1609,14 +1609,15 @@
 }
 
 static void recv_handler(struct ib_mad_agent *mad_agent,
+			 struct ib_mad_send_buf *send_buf,
 			 struct ib_mad_recv_wc *mad_recv_wc)
 {
 	struct ib_sa_query *query;
-	struct ib_mad_send_buf *mad_buf;
 
-	mad_buf = (void *) (unsigned long) mad_recv_wc->wc->wr_id;
-	query = mad_buf->context[0];
+	if (!send_buf)
+		return;
 
+	query = send_buf->context[0];
 	if (query->callback) {
 		if (mad_recv_wc->wc->status == IB_WC_SUCCESS)
 			query->callback(query,
--- linux-4.4.0.orig/drivers/infiniband/core/sysfs.c
+++ linux-4.4.0/drivers/infiniband/core/sysfs.c
@@ -863,7 +863,7 @@
 	free_port_list_attributes(device);
 
 err_unregister:
-	device_unregister(class_dev);
+	device_del(class_dev);
 
 err:
 	return ret;
--- linux-4.4.0.orig/drivers/infiniband/core/ucm.c
+++ linux-4.4.0/drivers/infiniband/core/ucm.c
@@ -46,8 +46,11 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 
+#include <linux/nospec.h>
+
 #include <asm/uaccess.h>
 
+#include <rdma/ib.h>
 #include <rdma/ib_cm.h>
 #include <rdma/ib_user_cm.h>
 #include <rdma/ib_marshall.h>
@@ -1103,6 +1106,9 @@
 	struct ib_ucm_cmd_hdr hdr;
 	ssize_t result;
 
+	if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
+		return -EACCES;
+
 	if (len < sizeof(hdr))
 		return -EINVAL;
 
@@ -1111,6 +1117,7 @@
 
 	if (hdr.cmd >= ARRAY_SIZE(ucm_cmd_table))
 		return -EINVAL;
+	hdr.cmd = array_index_nospec(hdr.cmd, ARRAY_SIZE(ucm_cmd_table));
 
 	if (hdr.in + sizeof(hdr) > len)
 		return -EINVAL;
@@ -1344,6 +1351,11 @@
 		printk(KERN_ERR "ucm: couldn't register client\n");
 		goto error3;
 	}
+
+	printk(KERN_ERR "ucm: This module is DEPRECATED and can expose your\n");
+	printk(KERN_ERR "ucm: system to attacks! Use at your own risk!!!\n");
+	add_taint(TAINT_FORCED_MODULE, LOCKDEP_STILL_OK);
+
 	return 0;
 
 error3:
--- linux-4.4.0.orig/drivers/infiniband/core/ucma.c
+++ linux-4.4.0/drivers/infiniband/core/ucma.c
@@ -44,6 +44,8 @@
 #include <linux/module.h>
 #include <linux/nsproxy.h>
 
+#include <linux/nospec.h>
+
 #include <rdma/rdma_user_cm.h>
 #include <rdma/ib_marshall.h>
 #include <rdma/rdma_cm.h>
@@ -87,6 +89,7 @@
 
 	struct ucma_file	*file;
 	struct rdma_cm_id	*cm_id;
+	struct mutex		mutex;
 	u64			uid;
 
 	struct list_head	list;
@@ -123,6 +126,8 @@
 static DEFINE_IDR(ctx_idr);
 static DEFINE_IDR(multicast_idr);
 
+static const struct file_operations ucma_fops;
+
 static inline struct ucma_context *_ucma_find_context(int id,
 						      struct ucma_file *file)
 {
@@ -131,7 +136,7 @@
 	ctx = idr_find(&ctx_idr, id);
 	if (!ctx)
 		ctx = ERR_PTR(-ENOENT);
-	else if (ctx->file != file)
+	else if (ctx->file != file || !ctx->cm_id)
 		ctx = ERR_PTR(-EINVAL);
 	return ctx;
 }
@@ -193,6 +198,7 @@
 	init_completion(&ctx->comp);
 	INIT_LIST_HEAD(&ctx->mc_list);
 	ctx->file = file;
+	mutex_init(&ctx->mutex);
 
 	mutex_lock(&mut);
 	ctx->id = idr_alloc(&ctx_idr, ctx, 0, 0, GFP_KERNEL);
@@ -217,7 +223,7 @@
 		return NULL;
 
 	mutex_lock(&mut);
-	mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL);
+	mc->id = idr_alloc(&multicast_idr, NULL, 0, 0, GFP_KERNEL);
 	mutex_unlock(&mut);
 	if (mc->id < 0)
 		goto error;
@@ -453,6 +459,7 @@
 	struct rdma_ucm_create_id cmd;
 	struct rdma_ucm_create_id_resp resp;
 	struct ucma_context *ctx;
+	struct rdma_cm_id *cm_id;
 	enum ib_qp_type qp_type;
 	int ret;
 
@@ -473,10 +480,10 @@
 		return -ENOMEM;
 
 	ctx->uid = cmd.uid;
-	ctx->cm_id = rdma_create_id(current->nsproxy->net_ns,
-				    ucma_event_handler, ctx, cmd.ps, qp_type);
-	if (IS_ERR(ctx->cm_id)) {
-		ret = PTR_ERR(ctx->cm_id);
+	cm_id = rdma_create_id(current->nsproxy->net_ns,
+			       ucma_event_handler, ctx, cmd.ps, qp_type);
+	if (IS_ERR(cm_id)) {
+		ret = PTR_ERR(cm_id);
 		goto err1;
 	}
 
@@ -486,14 +493,19 @@
 		ret = -EFAULT;
 		goto err2;
 	}
+
+	ctx->cm_id = cm_id;
 	return 0;
 
 err2:
-	rdma_destroy_id(ctx->cm_id);
+	rdma_destroy_id(cm_id);
 err1:
 	mutex_lock(&mut);
 	idr_remove(&ctx_idr, ctx->id);
 	mutex_unlock(&mut);
+	mutex_lock(&file->mut);
+	list_del(&ctx->list);
+	mutex_unlock(&file->mut);
 	kfree(ctx);
 	return ret;
 }
@@ -515,6 +527,7 @@
 {
 	struct ucma_event *uevent, *tmp;
 
+	rdma_lock_handler(mc->ctx->cm_id);
 	list_for_each_entry_safe(uevent, tmp, &mc->ctx->file->event_list, list) {
 		if (uevent->mc != mc)
 			continue;
@@ -522,6 +535,7 @@
 		list_del(&uevent->list);
 		kfree(uevent);
 	}
+	rdma_unlock_handler(mc->ctx->cm_id);
 }
 
 /*
@@ -561,6 +575,7 @@
 	}
 
 	events_reported = ctx->events_reported;
+	mutex_destroy(&ctx->mutex);
 	kfree(ctx);
 	return events_reported;
 }
@@ -623,11 +638,17 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if (!rdma_addr_size_in6(&cmd.addr))
+		return -EINVAL;
+
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	mutex_lock(&ctx->mutex);
 	ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
+	mutex_unlock(&ctx->mutex);
+
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -636,22 +657,23 @@
 			 int in_len, int out_len)
 {
 	struct rdma_ucm_bind cmd;
-	struct sockaddr *addr;
 	struct ucma_context *ctx;
 	int ret;
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
-	addr = (struct sockaddr *) &cmd.addr;
-	if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
+	if (cmd.reserved || !cmd.addr_size ||
+	    cmd.addr_size != rdma_addr_size_kss(&cmd.addr))
 		return -EINVAL;
 
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ret = rdma_bind_addr(ctx->cm_id, addr);
+	mutex_lock(&ctx->mutex);
+	ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -667,13 +689,18 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if ((cmd.src_addr.sin6_family && !rdma_addr_size_in6(&cmd.src_addr)) ||
+	    !rdma_addr_size_in6(&cmd.dst_addr))
+		return -EINVAL;
+
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	mutex_lock(&ctx->mutex);
 	ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
-				(struct sockaddr *) &cmd.dst_addr,
-				cmd.timeout_ms);
+				(struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -683,24 +710,25 @@
 				 int in_len, int out_len)
 {
 	struct rdma_ucm_resolve_addr cmd;
-	struct sockaddr *src, *dst;
 	struct ucma_context *ctx;
 	int ret;
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
-	src = (struct sockaddr *) &cmd.src_addr;
-	dst = (struct sockaddr *) &cmd.dst_addr;
-	if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
-	    !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
+	if (cmd.reserved ||
+	    (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) ||
+	    !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr)))
 		return -EINVAL;
 
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
+	mutex_lock(&ctx->mutex);
+	ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+				(struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -720,7 +748,9 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	mutex_lock(&ctx->mutex);
 	ret = rdma_resolve_route(ctx->cm_id, cmd.timeout_ms);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -809,6 +839,7 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	mutex_lock(&ctx->mutex);
 	memset(&resp, 0, sizeof resp);
 	addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr;
 	memcpy(&resp.src_addr, addr, addr->sa_family == AF_INET ?
@@ -832,6 +863,7 @@
 		ucma_copy_iw_route(&resp, &ctx->cm_id->route);
 
 out:
+	mutex_unlock(&ctx->mutex);
 	if (copy_to_user((void __user *)(unsigned long)cmd.response,
 			 &resp, sizeof(resp)))
 		ret = -EFAULT;
@@ -975,6 +1007,7 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	mutex_lock(&ctx->mutex);
 	switch (cmd.option) {
 	case RDMA_USER_CM_QUERY_ADDR:
 		ret = ucma_query_addr(ctx, response, out_len);
@@ -989,6 +1022,7 @@
 		ret = -ENOSYS;
 		break;
 	}
+	mutex_unlock(&ctx->mutex);
 
 	ucma_put_ctx(ctx);
 	return ret;
@@ -1029,7 +1063,9 @@
 		return PTR_ERR(ctx);
 
 	ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
+	mutex_lock(&ctx->mutex);
 	ret = rdma_connect(ctx->cm_id, &conn_param);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1050,7 +1086,9 @@
 
 	ctx->backlog = cmd.backlog > 0 && cmd.backlog < max_backlog ?
 		       cmd.backlog : max_backlog;
+	mutex_lock(&ctx->mutex);
 	ret = rdma_listen(ctx->cm_id, ctx->backlog);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1072,14 +1110,22 @@
 
 	if (cmd.conn_param.valid) {
 		ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
-		mutex_lock(&file->mut);
+		mutex_lock(&ctx->mutex);
+		rdma_lock_handler(ctx->cm_id);
 		ret = rdma_accept(ctx->cm_id, &conn_param);
-		if (!ret)
+		if (!ret) {
+			/* The uid must be set atomically with the handler */
 			ctx->uid = cmd.uid;
-		mutex_unlock(&file->mut);
-	} else
+		}
+		rdma_unlock_handler(ctx->cm_id);
+		mutex_unlock(&ctx->mutex);
+	} else {
+		mutex_lock(&ctx->mutex);
+		rdma_lock_handler(ctx->cm_id);
 		ret = rdma_accept(ctx->cm_id, NULL);
-
+		rdma_unlock_handler(ctx->cm_id);
+		mutex_unlock(&ctx->mutex);
+	}
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1098,7 +1144,9 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	mutex_lock(&ctx->mutex);
 	ret = rdma_reject(ctx->cm_id, cmd.private_data, cmd.private_data_len);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1117,7 +1165,9 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	mutex_lock(&ctx->mutex);
 	ret = rdma_disconnect(ctx->cm_id);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1138,14 +1188,24 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if (cmd.qp_state > IB_QPS_ERR)
+		return -EINVAL;
+
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	if (!ctx->cm_id->device) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	resp.qp_attr_mask = 0;
 	memset(&qp_attr, 0, sizeof qp_attr);
 	qp_attr.qp_state = cmd.qp_state;
+	mutex_lock(&ctx->mutex);
 	ret = rdma_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask);
+	mutex_unlock(&ctx->mutex);
 	if (ret)
 		goto out;
 
@@ -1212,10 +1272,15 @@
 	if (!optlen)
 		return -EINVAL;
 
+	if (!ctx->cm_id->device)
+		return -EINVAL;
+
 	memset(&sa_path, 0, sizeof(sa_path));
 
 	ib_sa_unpack_path(path_data->path_rec, &sa_path);
+	mutex_lock(&ctx->mutex);
 	ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1);
+	mutex_unlock(&ctx->mutex);
 	if (ret)
 		return ret;
 
@@ -1247,7 +1312,9 @@
 
 	switch (level) {
 	case RDMA_OPTION_ID:
+		mutex_lock(&ctx->mutex);
 		ret = ucma_set_option_id(ctx, optname, optval, optlen);
+		mutex_unlock(&ctx->mutex);
 		break;
 	case RDMA_OPTION_IB:
 		ret = ucma_set_option_ib(ctx, optname, optval, optlen);
@@ -1270,6 +1337,9 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if (unlikely(cmd.optlen > KMALLOC_MAX_SIZE))
+		return -EINVAL;
+
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
@@ -1295,7 +1365,7 @@
 {
 	struct rdma_ucm_notify cmd;
 	struct ucma_context *ctx;
-	int ret;
+	int ret = -EINVAL;
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
@@ -1304,7 +1374,11 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event);
+	mutex_lock(&ctx->mutex);
+	if (ctx->cm_id->device)
+		ret = rdma_notify(ctx->cm_id, (enum ib_event_type)cmd.event);
+	mutex_unlock(&ctx->mutex);
+
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1322,7 +1396,7 @@
 		return -ENOSPC;
 
 	addr = (struct sockaddr *) &cmd->addr;
-	if (cmd->reserved || !cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr)))
+	if (cmd->reserved || (cmd->addr_size != rdma_addr_size(addr)))
 		return -EINVAL;
 
 	ctx = ucma_get_ctx(file, cmd->id);
@@ -1338,7 +1412,9 @@
 
 	mc->uid = cmd->uid;
 	memcpy(&mc->addr, addr, cmd->addr_size);
+	mutex_lock(&ctx->mutex);
 	ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc);
+	mutex_unlock(&ctx->mutex);
 	if (ret)
 		goto err2;
 
@@ -1349,6 +1425,10 @@
 		goto err3;
 	}
 
+	mutex_lock(&mut);
+	idr_replace(&multicast_idr, mc, mc->id);
+	mutex_unlock(&mut);
+
 	mutex_unlock(&file->mut);
 	ucma_put_ctx(ctx);
 	return 0;
@@ -1381,7 +1461,10 @@
 	join_cmd.response = cmd.response;
 	join_cmd.uid = cmd.uid;
 	join_cmd.id = cmd.id;
-	join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
+	join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr);
+	if (!join_cmd.addr_size)
+		return -EINVAL;
+
 	join_cmd.reserved = 0;
 	memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size);
 
@@ -1397,6 +1480,9 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if (!rdma_addr_size_kss(&cmd.addr))
+		return -EINVAL;
+
 	return ucma_process_join(file, &cmd, out_len);
 }
 
@@ -1419,7 +1505,7 @@
 	mc = idr_find(&multicast_idr, cmd.id);
 	if (!mc)
 		mc = ERR_PTR(-ENOENT);
-	else if (mc->ctx->file != file)
+	else if (READ_ONCE(mc->ctx->file) != file)
 		mc = ERR_PTR(-EINVAL);
 	else if (!atomic_inc_not_zero(&mc->ctx->ref))
 		mc = ERR_PTR(-ENXIO);
@@ -1432,7 +1518,10 @@
 		goto out;
 	}
 
+	mutex_lock(&mc->ctx->mutex);
 	rdma_leave_multicast(mc->ctx->cm_id, (struct sockaddr *) &mc->addr);
+	mutex_unlock(&mc->ctx->mutex);
+
 	mutex_lock(&mc->ctx->file->mut);
 	ucma_cleanup_mc_events(mc);
 	list_del(&mc->list);
@@ -1449,45 +1538,15 @@
 	return ret;
 }
 
-static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
-{
-	/* Acquire mutex's based on pointer comparison to prevent deadlock. */
-	if (file1 < file2) {
-		mutex_lock(&file1->mut);
-		mutex_lock_nested(&file2->mut, SINGLE_DEPTH_NESTING);
-	} else {
-		mutex_lock(&file2->mut);
-		mutex_lock_nested(&file1->mut, SINGLE_DEPTH_NESTING);
-	}
-}
-
-static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
-{
-	if (file1 < file2) {
-		mutex_unlock(&file2->mut);
-		mutex_unlock(&file1->mut);
-	} else {
-		mutex_unlock(&file1->mut);
-		mutex_unlock(&file2->mut);
-	}
-}
-
-static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file)
-{
-	struct ucma_event *uevent, *tmp;
-
-	list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list)
-		if (uevent->ctx == ctx)
-			list_move_tail(&uevent->list, &file->event_list);
-}
-
 static ssize_t ucma_migrate_id(struct ucma_file *new_file,
 			       const char __user *inbuf,
 			       int in_len, int out_len)
 {
 	struct rdma_ucm_migrate_id cmd;
 	struct rdma_ucm_migrate_resp resp;
+	struct ucma_event *uevent, *tmp;
 	struct ucma_context *ctx;
+	LIST_HEAD(event_list);
 	struct fd f;
 	struct ucma_file *cur_file;
 	int ret = 0;
@@ -1499,40 +1558,59 @@
 	f = fdget(cmd.fd);
 	if (!f.file)
 		return -ENOENT;
+	if (f.file->f_op != &ucma_fops) {
+		ret = -EINVAL;
+		goto file_put;
+	}
+	cur_file = f.file->private_data;
 
 	/* Validate current fd and prevent destruction of id. */
-	ctx = ucma_get_ctx(f.file->private_data, cmd.id);
+	ctx = ucma_get_ctx(cur_file, cmd.id);
 	if (IS_ERR(ctx)) {
 		ret = PTR_ERR(ctx);
 		goto file_put;
 	}
 
-	cur_file = ctx->file;
-	if (cur_file == new_file) {
-		resp.events_reported = ctx->events_reported;
-		goto response;
-	}
-
+	rdma_lock_handler(ctx->cm_id);
 	/*
-	 * Migrate events between fd's, maintaining order, and avoiding new
-	 * events being added before existing events.
+	 * ctx->file can only be changed under the handler & xa_lock. xa_load()
+	 * must be checked again to ensure the ctx hasn't begun destruction
+	 * since the ucma_get_ctx().
 	 */
-	ucma_lock_files(cur_file, new_file);
 	mutex_lock(&mut);
 
-	list_move_tail(&ctx->list, &new_file->ctx_list);
-	ucma_move_events(ctx, new_file);
+	if (_ucma_find_context(cmd.id, cur_file) != ctx) {
+		mutex_unlock(&mut);
+		ret = -ENOENT;
+		goto err_unlock;
+	}
+
 	ctx->file = new_file;
+	mutex_unlock(&mut);
+
+	mutex_lock(&cur_file->mut);
+	list_del(&ctx->list);
+	/*
+	 * At this point lock_handler() prevents addition of new uevents for
+	 * this ctx.
+	 */
+	list_for_each_entry_safe(uevent, tmp, &cur_file->event_list, list)
+		if (uevent->ctx == ctx)
+			list_move_tail(&uevent->list, &event_list);
 	resp.events_reported = ctx->events_reported;
+	mutex_unlock(&cur_file->mut);
 
-	mutex_unlock(&mut);
-	ucma_unlock_files(cur_file, new_file);
+	mutex_lock(&new_file->mut);
+	list_add_tail(&ctx->list, &new_file->ctx_list);
+	list_splice_tail(&event_list, &new_file->event_list);
+	mutex_unlock(&new_file->mut);
 
-response:
 	if (copy_to_user((void __user *)(unsigned long)cmd.response,
 			 &resp, sizeof(resp)))
 		ret = -EFAULT;
 
+err_unlock:
+	rdma_unlock_handler(ctx->cm_id);
 	ucma_put_ctx(ctx);
 file_put:
 	fdput(f);
@@ -1574,6 +1652,9 @@
 	struct rdma_ucm_cmd_hdr hdr;
 	ssize_t ret;
 
+	if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
+		return -EACCES;
+
 	if (len < sizeof(hdr))
 		return -EINVAL;
 
@@ -1582,6 +1663,7 @@
 
 	if (hdr.cmd >= ARRAY_SIZE(ucma_cmd_table))
 		return -EINVAL;
+	hdr.cmd = array_index_nospec(hdr.cmd, ARRAY_SIZE(ucma_cmd_table));
 
 	if (hdr.in + sizeof(hdr) > len)
 		return -EINVAL;
@@ -1664,6 +1746,8 @@
 		mutex_lock(&mut);
 		if (!ctx->closing) {
 			mutex_unlock(&mut);
+			ucma_put_ctx(ctx);
+			wait_for_completion(&ctx->comp);
 			/* rdma_destroy_id ensures that no event handlers are
 			 * inflight for that id before releasing it.
 			 */
--- linux-4.4.0.orig/drivers/infiniband/core/umem.c
+++ linux-4.4.0/drivers/infiniband/core/umem.c
@@ -95,6 +95,7 @@
 	DEFINE_DMA_ATTRS(attrs);
 	struct scatterlist *sg, *sg_list_start;
 	int need_release = 0;
+	unsigned int gup_flags = FOLL_WRITE;
 
 	if (dmasync)
 		dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
@@ -122,18 +123,10 @@
 	umem->address   = addr;
 	umem->page_size = PAGE_SIZE;
 	umem->pid       = get_task_pid(current, PIDTYPE_PID);
-	/*
-	 * We ask for writable memory if any of the following
-	 * access flags are set.  "Local write" and "remote write"
-	 * obviously require write access.  "Remote atomic" can do
-	 * things like fetch and add, which will modify memory, and
-	 * "MW bind" can change permissions by binding a window.
-	 */
-	umem->writable  = !!(access &
-		(IB_ACCESS_LOCAL_WRITE   | IB_ACCESS_REMOTE_WRITE |
-		 IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_MW_BIND));
+	umem->writable   = ib_access_writable(access);
 
 	if (access & IB_ACCESS_ON_DEMAND) {
+		put_pid(umem->pid);
 		ret = ib_umem_odp_get(context, umem);
 		if (ret) {
 			kfree(umem);
@@ -149,6 +142,7 @@
 
 	page_list = (struct page **) __get_free_page(GFP_KERNEL);
 	if (!page_list) {
+		put_pid(umem->pid);
 		kfree(umem);
 		return ERR_PTR(-ENOMEM);
 	}
@@ -175,7 +169,7 @@
 
 	cur_base = addr & PAGE_MASK;
 
-	if (npages == 0) {
+	if (npages == 0 || npages > UINT_MAX) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -184,6 +178,9 @@
 	if (ret)
 		goto out;
 
+	if (!umem->writable)
+		gup_flags |= FOLL_FORCE;
+
 	need_release = 1;
 	sg_list_start = umem->sg_head.sgl;
 
@@ -191,7 +188,7 @@
 		ret = get_user_pages(current, current->mm, cur_base,
 				     min_t(unsigned long, npages,
 					   PAGE_SIZE / sizeof (struct page *)),
-				     1, !umem->writable, page_list, vma_list);
+				     gup_flags, page_list, vma_list);
 
 		if (ret < 0)
 			goto out;
@@ -352,7 +349,7 @@
 		return -EINVAL;
 	}
 
-	ret = sg_pcopy_to_buffer(umem->sg_head.sgl, umem->nmap, dst, length,
+	ret = sg_pcopy_to_buffer(umem->sg_head.sgl, umem->npages, dst, length,
 				 offset + ib_umem_offset(umem));
 
 	if (ret < 0)
--- linux-4.4.0.orig/drivers/infiniband/core/umem_odp.c
+++ linux-4.4.0/drivers/infiniband/core/umem_odp.c
@@ -527,6 +527,7 @@
 	u64 off;
 	int j, k, ret = 0, start_idx, npages = 0;
 	u64 base_virt_addr;
+	unsigned int flags = 0;
 
 	if (access_mask == 0)
 		return -EINVAL;
@@ -556,6 +557,9 @@
 		goto out_put_task;
 	}
 
+	if (access_mask & ODP_WRITE_ALLOWED_BIT)
+		flags |= FOLL_WRITE;
+
 	start_idx = (user_virt - ib_umem_start(umem)) >> PAGE_SHIFT;
 	k = start_idx;
 
@@ -574,8 +578,7 @@
 		 */
 		npages = get_user_pages(owning_process, owning_mm, user_virt,
 					gup_num_pages,
-					access_mask & ODP_WRITE_ALLOWED_BIT, 0,
-					local_page_list, NULL);
+					flags, local_page_list, NULL);
 		up_read(&owning_mm->mmap_sem);
 
 		if (npages < 0)
--- linux-4.4.0.orig/drivers/infiniband/core/user_mad.c
+++ linux-4.4.0/drivers/infiniband/core/user_mad.c
@@ -49,6 +49,7 @@
 #include <linux/sched.h>
 #include <linux/semaphore.h>
 #include <linux/slab.h>
+#include <linux/nospec.h>
 
 #include <asm/uaccess.h>
 
@@ -210,6 +211,7 @@
 }
 
 static void recv_handler(struct ib_mad_agent *agent,
+			 struct ib_mad_send_buf *send_buf,
 			 struct ib_mad_recv_wc *mad_recv_wc)
 {
 	struct ib_umad_file *file = agent->context;
@@ -341,6 +343,11 @@
 
 	mutex_lock(&file->mutex);
 
+	if (file->agents_dead) {
+		mutex_unlock(&file->mutex);
+		return -EIO;
+	}
+
 	while (list_empty(&file->recv_list)) {
 		mutex_unlock(&file->mutex);
 
@@ -483,7 +490,7 @@
 
 	agent = __get_agent(file, packet->mad.hdr.id);
 	if (!agent) {
-		ret = -EINVAL;
+		ret = -EIO;
 		goto err_up;
 	}
 
@@ -842,11 +849,14 @@
 
 	if (get_user(id, arg))
 		return -EFAULT;
+	if (id >= IB_UMAD_MAX_AGENTS)
+		return -EINVAL;
 
 	mutex_lock(&file->port->file_mutex);
 	mutex_lock(&file->mutex);
 
-	if (id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
+	id = array_index_nospec(id, IB_UMAD_MAX_AGENTS);
+	if (!__get_agent(file, id)) {
 		ret = -EINVAL;
 		goto out;
 	}
--- linux-4.4.0.orig/drivers/infiniband/core/uverbs.h
+++ linux-4.4.0/drivers/infiniband/core/uverbs.h
@@ -116,6 +116,7 @@
 struct ib_uverbs_file {
 	struct kref				ref;
 	struct mutex				mutex;
+	struct mutex                            cleanup_mutex; /* protect cleanup */
 	struct ib_uverbs_device		       *device;
 	struct ib_ucontext		       *ucontext;
 	struct ib_event_handler			event_handler;
--- linux-4.4.0.orig/drivers/infiniband/core/uverbs_cmd.c
+++ linux-4.4.0/drivers/infiniband/core/uverbs_cmd.c
@@ -2287,6 +2287,11 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
+	if ((cmd.attr_mask & IB_QP_PORT) &&
+	    (cmd.port_num < rdma_start_port(ib_dev) ||
+	     cmd.port_num > rdma_end_port(ib_dev)))
+		return -EINVAL;
+
 	INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
 		   out_len);
 
@@ -2431,9 +2436,13 @@
 
 static void *alloc_wr(size_t wr_size, __u32 num_sge)
 {
+	if (num_sge >= (U32_MAX - ALIGN(wr_size, sizeof (struct ib_sge))) /
+		       sizeof (struct ib_sge))
+		return NULL;
+
 	return kmalloc(ALIGN(wr_size, sizeof (struct ib_sge)) +
 			 num_sge * sizeof (struct ib_sge), GFP_KERNEL);
-};
+}
 
 ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
 			    struct ib_device *ib_dev,
@@ -2660,6 +2669,13 @@
 			goto err;
 		}
 
+		if (user_wr->num_sge >=
+		    (U32_MAX - ALIGN(sizeof *next, sizeof (struct ib_sge))) /
+		    sizeof (struct ib_sge)) {
+			ret = -EINVAL;
+			goto err;
+		}
+
 		next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) +
 			       user_wr->num_sge * sizeof (struct ib_sge),
 			       GFP_KERNEL);
@@ -2827,6 +2843,10 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
+	if (cmd.attr.port_num < rdma_start_port(ib_dev) ||
+	    cmd.attr.port_num > rdma_end_port(ib_dev))
+		return -EINVAL;
+
 	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
 	if (!uobj)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/infiniband/core/uverbs_main.c
+++ linux-4.4.0/drivers/infiniband/core/uverbs_main.c
@@ -48,6 +48,8 @@
 
 #include <asm/uaccess.h>
 
+#include <rdma/ib.h>
+
 #include "uverbs.h"
 
 MODULE_AUTHOR("Roland Dreier");
@@ -242,12 +244,9 @@
 			container_of(uobj, struct ib_uqp_object, uevent.uobject);
 
 		idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
-		if (qp != qp->real_qp) {
-			ib_close_qp(qp);
-		} else {
+		if (qp == qp->real_qp)
 			ib_uverbs_detach_umcast(qp, uqp);
-			ib_destroy_qp(qp);
-		}
+		ib_destroy_qp(qp);
 		ib_uverbs_release_uevent(file, &uqp->uevent);
 		kfree(uqp);
 	}
@@ -682,6 +681,9 @@
 	int srcu_key;
 	ssize_t ret;
 
+	if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
+		return -EACCES;
+
 	if (count < sizeof hdr)
 		return -EINVAL;
 
@@ -917,6 +919,7 @@
 	file->async_file = NULL;
 	kref_init(&file->ref);
 	mutex_init(&file->mutex);
+	mutex_init(&file->cleanup_mutex);
 
 	filp->private_data = file;
 	kobject_get(&dev->kobj);
@@ -942,18 +945,20 @@
 {
 	struct ib_uverbs_file *file = filp->private_data;
 	struct ib_uverbs_device *dev = file->device;
-	struct ib_ucontext *ucontext = NULL;
+
+	mutex_lock(&file->cleanup_mutex);
+	if (file->ucontext) {
+		ib_uverbs_cleanup_ucontext(file, file->ucontext);
+		file->ucontext = NULL;
+	}
+	mutex_unlock(&file->cleanup_mutex);
 
 	mutex_lock(&file->device->lists_mutex);
-	ucontext = file->ucontext;
-	file->ucontext = NULL;
 	if (!file->is_closed) {
 		list_del(&file->list);
 		file->is_closed = 1;
 	}
 	mutex_unlock(&file->device->lists_mutex);
-	if (ucontext)
-		ib_uverbs_cleanup_ucontext(file, ucontext);
 
 	if (file->async_file)
 		kref_put(&file->async_file->ref, ib_uverbs_release_event_file);
@@ -1167,22 +1172,30 @@
 	mutex_lock(&uverbs_dev->lists_mutex);
 	while (!list_empty(&uverbs_dev->uverbs_file_list)) {
 		struct ib_ucontext *ucontext;
-
 		file = list_first_entry(&uverbs_dev->uverbs_file_list,
 					struct ib_uverbs_file, list);
 		file->is_closed = 1;
-		ucontext = file->ucontext;
 		list_del(&file->list);
-		file->ucontext = NULL;
 		kref_get(&file->ref);
 		mutex_unlock(&uverbs_dev->lists_mutex);
-		/* We must release the mutex before going ahead and calling
-		 * disassociate_ucontext. disassociate_ucontext might end up
-		 * indirectly calling uverbs_close, for example due to freeing
-		 * the resources (e.g mmput).
-		 */
+
 		ib_uverbs_event_handler(&file->event_handler, &event);
+
+		mutex_lock(&file->cleanup_mutex);
+		ucontext = file->ucontext;
+		file->ucontext = NULL;
+		mutex_unlock(&file->cleanup_mutex);
+
+		/* At this point ib_uverbs_close cannot be running
+		 * ib_uverbs_cleanup_ucontext
+		 */
 		if (ucontext) {
+			/* We must release the mutex before going ahead and
+			 * calling disassociate_ucontext. disassociate_ucontext
+			 * might end up indirectly calling uverbs_close,
+			 * for example due to freeing the resources
+			 * (e.g mmput).
+			 */
 			ib_dev->disassociate_ucontext(ucontext);
 			ib_uverbs_cleanup_ucontext(file, ucontext);
 		}
--- linux-4.4.0.orig/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ linux-4.4.0/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -327,7 +327,7 @@
 	kfree(cq->sw_queue);
 	dma_free_coherent(&(rdev_p->rnic_info.pdev->dev),
 			  (1UL << (cq->size_log2))
-			  * sizeof(struct t3_cqe), cq->queue,
+			  * sizeof(struct t3_cqe) + 1, cq->queue,
 			  dma_unmap_addr(cq, mapping));
 	cxio_hal_put_cqid(rdev_p->rscp, cq->cqid);
 	return err;
--- linux-4.4.0.orig/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ linux-4.4.0/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -149,7 +149,7 @@
 	error = l2t_send(tdev, skb, l2e);
 	if (error < 0)
 		kfree_skb(skb);
-	return error;
+	return error < 0 ? error : 0;
 }
 
 int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb)
@@ -165,7 +165,7 @@
 	error = cxgb3_ofld_send(tdev, skb);
 	if (error < 0)
 		kfree_skb(skb);
-	return error;
+	return error < 0 ? error : 0;
 }
 
 static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb)
--- linux-4.4.0.orig/drivers/infiniband/hw/cxgb4/cm.c
+++ linux-4.4.0/drivers/infiniband/hw/cxgb4/cm.c
@@ -360,6 +360,8 @@
 		skb_reset_transport_header(skb);
 	} else {
 		skb = alloc_skb(len, gfp);
+		if (!skb)
+			return NULL;
 	}
 	t4_set_arp_err_handler(skb, NULL, NULL);
 	return skb;
--- linux-4.4.0.orig/drivers/infiniband/hw/cxgb4/cq.c
+++ linux-4.4.0/drivers/infiniband/hw/cxgb4/cq.c
@@ -162,7 +162,7 @@
 	cq->bar2_va = c4iw_bar2_addrs(rdev, cq->cqid, T4_BAR2_QTYPE_INGRESS,
 				      &cq->bar2_qid,
 				      user ? &cq->bar2_pa : NULL);
-	if (user && !cq->bar2_va) {
+	if (user && !cq->bar2_pa) {
 		pr_warn(MOD "%s: cqid %u not in BAR2 range.\n",
 			pci_name(rdev->lldi.pdev), cq->cqid);
 		ret = -EINVAL;
@@ -579,10 +579,10 @@
 			ret = -EAGAIN;
 			goto skip_cqe;
 		}
-		if (unlikely((CQE_WRID_MSN(hw_cqe) != (wq->rq.msn)))) {
+		if (unlikely(!CQE_STATUS(hw_cqe) &&
+			     CQE_WRID_MSN(hw_cqe) != wq->rq.msn)) {
 			t4_set_wq_in_error(wq);
-			hw_cqe->header |= htonl(CQE_STATUS_V(T4_ERR_MSN));
-			goto proc_cqe;
+			hw_cqe->header |= cpu_to_be32(CQE_STATUS_V(T4_ERR_MSN));
 		}
 		goto proc_cqe;
 	}
--- linux-4.4.0.orig/drivers/infiniband/hw/cxgb4/device.c
+++ linux-4.4.0/drivers/infiniband/hw/cxgb4/device.c
@@ -809,10 +809,9 @@
 	     rdev->lldi.vr->qp.size,
 	     rdev->lldi.vr->cq.start,
 	     rdev->lldi.vr->cq.size);
-	PDBG("udb len 0x%x udb base %p db_reg %p gts_reg %p "
+	PDBG("udb %pR db_reg %p gts_reg %p "
 	     "qpmask 0x%x cqmask 0x%x\n",
-	     (unsigned)pci_resource_len(rdev->lldi.pdev, 2),
-	     (void *)pci_resource_start(rdev->lldi.pdev, 2),
+		&rdev->lldi.pdev->resource[2],
 	     rdev->lldi.db_reg, rdev->lldi.gts_reg,
 	     rdev->qpmask, rdev->cqmask);
 
--- linux-4.4.0.orig/drivers/infiniband/hw/cxgb4/mem.c
+++ linux-4.4.0/drivers/infiniband/hw/cxgb4/mem.c
@@ -254,13 +254,17 @@
 			   u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr)
 {
 	int err;
-	struct fw_ri_tpte tpt;
+	struct fw_ri_tpte *tpt;
 	u32 stag_idx;
 	static atomic_t key;
 
 	if (c4iw_fatal_error(rdev))
 		return -EIO;
 
+	tpt = kmalloc(sizeof(*tpt), GFP_KERNEL);
+	if (!tpt)
+		return -ENOMEM;
+
 	stag_state = stag_state > 0;
 	stag_idx = (*stag) >> 8;
 
@@ -270,6 +274,7 @@
 			mutex_lock(&rdev->stats.lock);
 			rdev->stats.stag.fail++;
 			mutex_unlock(&rdev->stats.lock);
+			kfree(tpt);
 			return -ENOMEM;
 		}
 		mutex_lock(&rdev->stats.lock);
@@ -284,28 +289,28 @@
 
 	/* write TPT entry */
 	if (reset_tpt_entry)
-		memset(&tpt, 0, sizeof(tpt));
+		memset(tpt, 0, sizeof(*tpt));
 	else {
-		tpt.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
+		tpt->valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
 			FW_RI_TPTE_STAGKEY_V((*stag & FW_RI_TPTE_STAGKEY_M)) |
 			FW_RI_TPTE_STAGSTATE_V(stag_state) |
 			FW_RI_TPTE_STAGTYPE_V(type) | FW_RI_TPTE_PDID_V(pdid));
-		tpt.locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) |
+		tpt->locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) |
 			(bind_enabled ? FW_RI_TPTE_MWBINDEN_F : 0) |
 			FW_RI_TPTE_ADDRTYPE_V((zbva ? FW_RI_ZERO_BASED_TO :
 						      FW_RI_VA_BASED_TO))|
 			FW_RI_TPTE_PS_V(page_size));
-		tpt.nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32(
+		tpt->nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32(
 			FW_RI_TPTE_PBLADDR_V(PBL_OFF(rdev, pbl_addr)>>3));
-		tpt.len_lo = cpu_to_be32((u32)(len & 0xffffffffUL));
-		tpt.va_hi = cpu_to_be32((u32)(to >> 32));
-		tpt.va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL));
-		tpt.dca_mwbcnt_pstag = cpu_to_be32(0);
-		tpt.len_hi = cpu_to_be32((u32)(len >> 32));
+		tpt->len_lo = cpu_to_be32((u32)(len & 0xffffffffUL));
+		tpt->va_hi = cpu_to_be32((u32)(to >> 32));
+		tpt->va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL));
+		tpt->dca_mwbcnt_pstag = cpu_to_be32(0);
+		tpt->len_hi = cpu_to_be32((u32)(len >> 32));
 	}
 	err = write_adapter_mem(rdev, stag_idx +
 				(rdev->lldi.vr->stag.start >> 5),
-				sizeof(tpt), &tpt);
+				sizeof(*tpt), tpt);
 
 	if (reset_tpt_entry) {
 		c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
@@ -313,6 +318,7 @@
 		rdev->stats.stag.cur -= 32;
 		mutex_unlock(&rdev->stats.lock);
 	}
+	kfree(tpt);
 	return err;
 }
 
@@ -926,7 +932,7 @@
 {
 	struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
 
-	if (unlikely(mhp->mpl_len == mhp->max_mpl_len))
+	if (unlikely(mhp->mpl_len == mhp->attr.pbl_size))
 		return -ENOMEM;
 
 	mhp->mpl[mhp->mpl_len++] = addr;
--- linux-4.4.0.orig/drivers/infiniband/hw/cxgb4/qp.c
+++ linux-4.4.0/drivers/infiniband/hw/cxgb4/qp.c
@@ -185,6 +185,10 @@
 
 	if (pbar2_pa)
 		*pbar2_pa = (rdev->bar2_pa + bar2_qoffset) & PAGE_MASK;
+
+	if (is_t4(rdev->lldi.adapter_type))
+		return NULL;
+
 	return rdev->bar2_kva + bar2_qoffset;
 }
 
@@ -270,7 +274,7 @@
 	/*
 	 * User mode must have bar2 access.
 	 */
-	if (user && (!wq->sq.bar2_va || !wq->rq.bar2_va)) {
+	if (user && (!wq->sq.bar2_pa || !wq->rq.bar2_pa)) {
 		pr_warn(MOD "%s: sqid %u or rqid %u not in BAR2 range.\n",
 			pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid);
 		goto free_dma;
@@ -1179,6 +1183,12 @@
 
 	t4_set_wq_in_error(&qhp->wq);
 	if (qhp->ibqp.uobject) {
+
+		/* for user qps, qhp->wq.flushed is protected by qhp->mutex */
+		if (qhp->wq.flushed)
+			return;
+
+		qhp->wq.flushed = 1;
 		t4_set_cq_in_error(&rchp->cq);
 		spin_lock_irqsave(&rchp->comp_handler_lock, flag);
 		(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
@@ -1888,7 +1898,7 @@
 	init_attr->cap.max_send_wr = qhp->attr.sq_num_entries;
 	init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries;
 	init_attr->cap.max_send_sge = qhp->attr.sq_max_sges;
-	init_attr->cap.max_recv_sge = qhp->attr.sq_max_sges;
+	init_attr->cap.max_recv_sge = qhp->attr.rq_max_sges;
 	init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE;
 	init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0;
 	return 0;
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/ah.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/ah.c
@@ -47,6 +47,7 @@
 
 	ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
 	ah->av.ib.g_slid  = ah_attr->src_path_bits;
+	ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
 	if (ah_attr->ah_flags & IB_AH_GRH) {
 		ah->av.ib.g_slid   |= 0x80;
 		ah->av.ib.gid_index = ah_attr->grh.sgid_index;
@@ -64,7 +65,6 @@
 		       !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support))
 			--ah->av.ib.stat_rate;
 	}
-	ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
 
 	return &ah->ibah;
 }
@@ -102,15 +102,21 @@
 	if (vlan_tag < 0x1000)
 		vlan_tag |= (ah_attr->sl & 7) << 13;
 	ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
-	ah->av.eth.gid_index = mlx4_ib_gid_index_to_real_index(ibdev, ah_attr->port_num, ah_attr->grh.sgid_index);
+	ret = mlx4_ib_gid_index_to_real_index(ibdev, ah_attr->port_num, ah_attr->grh.sgid_index);
+	if (ret < 0)
+		return ERR_PTR(ret);
+	ah->av.eth.gid_index = ret;
 	ah->av.eth.vlan = cpu_to_be16(vlan_tag);
+	ah->av.eth.hop_limit = ah_attr->grh.hop_limit;
 	if (ah_attr->static_rate) {
 		ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
 		while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
 		       !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support))
 			--ah->av.eth.stat_rate;
 	}
-
+	ah->av.eth.sl_tclass_flowlabel |=
+			cpu_to_be32((ah_attr->grh.traffic_class << 20) |
+				    ah_attr->grh.flow_label);
 	/*
 	 * HW requires multicast LID so we just choose one.
 	 */
@@ -118,7 +124,7 @@
 		ah->av.ib.dlid = cpu_to_be16(0xc000);
 
 	memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16);
-	ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 29);
+	ah->av.eth.sl_tclass_flowlabel |= cpu_to_be32(ah_attr->sl << 29);
 
 	return &ah->ibah;
 }
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/alias_GUID.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/alias_GUID.c
@@ -805,8 +805,8 @@
 	unsigned long flags;
 
 	for (i = 0 ; i < dev->num_ports; i++) {
-		cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work);
 		det = &sriov->alias_guid.ports_guid[i];
+		cancel_delayed_work_sync(&det->alias_guid_work);
 		spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
 		while (!list_empty(&det->cb_list)) {
 			cb_ctx = list_entry(det->cb_list.next,
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/cm.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/cm.c
@@ -39,7 +39,7 @@
 
 #include "mlx4_ib.h"
 
-#define CM_CLEANUP_CACHE_TIMEOUT  (5 * HZ)
+#define CM_CLEANUP_CACHE_TIMEOUT  (30 * HZ)
 
 struct id_map_entry {
 	struct rb_node node;
@@ -309,6 +309,9 @@
 	if (!sriov->is_going_down) {
 		id->scheduled_delete = 1;
 		schedule_delayed_work(&id->timeout, CM_CLEANUP_CACHE_TIMEOUT);
+	} else if (id->scheduled_delete) {
+		/* Adjust timeout if already scheduled */
+		mod_delayed_work(system_wq, &id->timeout, CM_CLEANUP_CACHE_TIMEOUT);
 	}
 	spin_unlock_irqrestore(&sriov->going_down_lock, flags);
 	spin_unlock(&sriov->id_map_lock);
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/cq.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/cq.c
@@ -253,11 +253,14 @@
 	if (context)
 		if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof (__u32))) {
 			err = -EFAULT;
-			goto err_dbmap;
+			goto err_cq_free;
 		}
 
 	return &cq->ibcq;
 
+err_cq_free:
+	mlx4_cq_free(dev->dev, &cq->mcq);
+
 err_dbmap:
 	if (context)
 		mlx4_ib_db_unmap_user(to_mucontext(context), &cq->db);
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/mad.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/mad.c
@@ -526,7 +526,7 @@
 		tun_tx_ix = (++tun_qp->tx_ix_head) & (MLX4_NUM_TUNNEL_BUFS - 1);
 	spin_unlock(&tun_qp->tx_lock);
 	if (ret)
-		goto out;
+		goto end;
 
 	tun_mad = (struct mlx4_rcv_tunnel_mad *) (tun_qp->tx_ring[tun_tx_ix].buf.addr);
 	if (tun_qp->tx_ring[tun_tx_ix].ah)
@@ -595,9 +595,15 @@
 	wr.wr.send_flags = IB_SEND_SIGNALED;
 
 	ret = ib_post_send(src_qp, &wr.wr, &bad_wr);
-out:
-	if (ret)
-		ib_destroy_ah(ah);
+	if (!ret)
+		return 0;
+ out:
+	spin_lock(&tun_qp->tx_lock);
+	tun_qp->tx_ix_tail++;
+	spin_unlock(&tun_qp->tx_lock);
+	tun_qp->tx_ring[tun_tx_ix].ah = NULL;
+end:
+	ib_destroy_ah(ah);
 	return ret;
 }
 
@@ -1074,6 +1080,27 @@
 
 		/* Generate GUID changed event */
 		if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK) {
+			if (mlx4_is_master(dev->dev)) {
+				union ib_gid gid;
+				int err = 0;
+
+				if (!eqe->event.port_mgmt_change.params.port_info.gid_prefix)
+					err = __mlx4_ib_query_gid(&dev->ib_dev, port, 0, &gid, 1);
+				else
+					gid.global.subnet_prefix =
+						eqe->event.port_mgmt_change.params.port_info.gid_prefix;
+				if (err) {
+					pr_warn("Could not change QP1 subnet prefix for port %d: query_gid error (%d)\n",
+						port, err);
+				} else {
+					pr_debug("Changing QP1 subnet prefix for port %d. old=0x%llx. new=0x%llx\n",
+						 port,
+						 (u64)atomic64_read(&dev->sriov.demux[port - 1].subnet_prefix),
+						 be64_to_cpu(gid.global.subnet_prefix));
+					atomic64_set(&dev->sriov.demux[port - 1].subnet_prefix,
+						     be64_to_cpu(gid.global.subnet_prefix));
+				}
+			}
 			mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE);
 			/*if master, notify all slaves*/
 			if (mlx4_is_master(dev->dev))
@@ -1278,9 +1305,15 @@
 
 
 	ret = ib_post_send(send_qp, &wr.wr, &bad_wr);
+	if (!ret)
+		return 0;
+
+	spin_lock(&sqp->tx_lock);
+	sqp->tx_ix_tail++;
+	spin_unlock(&sqp->tx_lock);
+	sqp->tx_ring[wire_tx_ix].ah = NULL;
 out:
-	if (ret)
-		ib_destroy_ah(ah);
+	ib_destroy_ah(ah);
 	return ret;
 }
 
@@ -1493,8 +1526,6 @@
 				    tx_buf_size, DMA_TO_DEVICE);
 		kfree(tun_qp->tx_ring[i].buf.addr);
 	}
-	kfree(tun_qp->tx_ring);
-	tun_qp->tx_ring = NULL;
 	i = MLX4_NUM_TUNNEL_BUFS;
 err:
 	while (i > 0) {
@@ -1503,6 +1534,8 @@
 				    rx_buf_size, DMA_FROM_DEVICE);
 		kfree(tun_qp->ring[i].addr);
 	}
+	kfree(tun_qp->tx_ring);
+	tun_qp->tx_ring = NULL;
 	kfree(tun_qp->ring);
 	tun_qp->ring = NULL;
 	return -ENOMEM;
@@ -1747,7 +1780,6 @@
 					       "buf:%lld\n", wc.wr_id);
 				break;
 			default:
-				BUG_ON(1);
 				break;
 			}
 		} else  {
@@ -2142,6 +2174,8 @@
 		if (err)
 			goto demux_err;
 		dev->sriov.demux[i].guid_cache[0] = gid.global.interface_id;
+		atomic64_set(&dev->sriov.demux[i].subnet_prefix,
+			     be64_to_cpu(gid.global.subnet_prefix));
 		err = alloc_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1,
 				      &dev->sriov.sqps[i]);
 		if (err)
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/main.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/main.c
@@ -630,9 +630,11 @@
 	if (err)
 		goto out;
 
-	props->active_width	=  (((u8 *)mailbox->buf)[5] == 0x40) ?
-						IB_WIDTH_4X : IB_WIDTH_1X;
-	props->active_speed	= IB_SPEED_QDR;
+	props->active_width	=  (((u8 *)mailbox->buf)[5] == 0x40) ||
+				   (((u8 *)mailbox->buf)[5] == 0x20 /*56Gb*/) ?
+					   IB_WIDTH_4X : IB_WIDTH_1X;
+	props->active_speed	=  (((u8 *)mailbox->buf)[5] == 0x20 /*56Gb*/) ?
+					   IB_SPEED_FDR : IB_SPEED_QDR;
 	props->port_cap_flags	= IB_PORT_CM_SUP | IB_PORT_IP_BASED_GIDS;
 	props->gid_tbl_len	= mdev->dev->caps.gid_table_len[port];
 	props->max_msg_sz	= mdev->dev->caps.max_msg_sz;
@@ -1039,7 +1041,9 @@
 	/* need to protect from a race on closing the vma as part of
 	 * mlx4_ib_vma_close().
 	 */
-	down_read(&owning_mm->mmap_sem);
+	down_write(&owning_mm->mmap_sem);
+	if (!mmget_still_valid(owning_mm))
+		goto skip_mm;
 	for (i = 0; i < HW_BAR_COUNT; i++) {
 		vma = context->hw_bar_info[i].vma;
 		if (!vma)
@@ -1053,11 +1057,14 @@
 			BUG_ON(1);
 		}
 
+		context->hw_bar_info[i].vma->vm_flags &=
+			~(VM_SHARED | VM_MAYSHARE);
 		/* context going to be destroyed, should not access ops any more */
 		context->hw_bar_info[i].vma->vm_ops = NULL;
 	}
 
-	up_read(&owning_mm->mmap_sem);
+skip_mm:
+	up_write(&owning_mm->mmap_sem);
 	mmput(owning_mm);
 	put_task_struct(owning_process);
 }
@@ -1428,8 +1435,9 @@
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(pdefault_rules->rules_create_list); i++) {
+		union ib_flow_spec ib_spec = {};
 		int ret;
-		union ib_flow_spec ib_spec;
+
 		switch (pdefault_rules->rules_create_list[i]) {
 		case 0:
 			/* no rule */
@@ -2401,14 +2409,19 @@
 			goto err_steer_qp_release;
 		}
 
-		bitmap_zero(ibdev->ib_uc_qpns_bitmap, ibdev->steer_qpn_count);
-
-		err = mlx4_FLOW_STEERING_IB_UC_QP_RANGE(
-				dev, ibdev->steer_qpn_base,
-				ibdev->steer_qpn_base +
-				ibdev->steer_qpn_count - 1);
-		if (err)
-			goto err_steer_free_bitmap;
+		if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB) {
+			bitmap_zero(ibdev->ib_uc_qpns_bitmap,
+				    ibdev->steer_qpn_count);
+			err = mlx4_FLOW_STEERING_IB_UC_QP_RANGE(
+					dev, ibdev->steer_qpn_base,
+					ibdev->steer_qpn_base +
+					ibdev->steer_qpn_count - 1);
+			if (err)
+				goto err_steer_free_bitmap;
+		} else {
+			bitmap_fill(ibdev->ib_uc_qpns_bitmap,
+				    ibdev->steer_qpn_count);
+		}
 	}
 
 	for (j = 1; j <= ibdev->dev->caps.num_ports; j++)
@@ -2476,14 +2489,14 @@
 	kfree(ibdev->ib_uc_qpns_bitmap);
 
 err_steer_qp_release:
-	if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED)
-		mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
-				      ibdev->steer_qpn_count);
+	mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
+			      ibdev->steer_qpn_count);
 err_counter:
 	for (i = 0; i < ibdev->num_ports; ++i)
 		mlx4_ib_delete_counters_table(ibdev, &ibdev->counters_table[i]);
 
 err_map:
+	mlx4_ib_free_eqs(dev, ibdev);
 	iounmap(ibdev->uar_map);
 
 err_uar:
@@ -2578,11 +2591,9 @@
 		ibdev->iboe.nb.notifier_call = NULL;
 	}
 
-	if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) {
-		mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
-				      ibdev->steer_qpn_count);
-		kfree(ibdev->ib_uc_qpns_bitmap);
-	}
+	mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
+			      ibdev->steer_qpn_count);
+	kfree(ibdev->ib_uc_qpns_bitmap);
 
 	iounmap(ibdev->uar_map);
 	for (p = 0; p < ibdev->num_ports; ++p)
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/mcg.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/mcg.c
@@ -489,7 +489,7 @@
 		if (!group->members[i])
 			leave_state |= (1 << i);
 
-	return leave_state & (group->rec.scope_join_state & 7);
+	return leave_state & (group->rec.scope_join_state & 0xf);
 }
 
 static int join_group(struct mcast_group *group, int slave, u8 join_mask)
@@ -564,8 +564,8 @@
 		} else
 			mcg_warn_group(group, "DRIVER BUG\n");
 	} else if (group->state == MCAST_LEAVE_SENT) {
-		if (group->rec.scope_join_state & 7)
-			group->rec.scope_join_state &= 0xf8;
+		if (group->rec.scope_join_state & 0xf)
+			group->rec.scope_join_state &= 0xf0;
 		group->state = MCAST_IDLE;
 		mutex_unlock(&group->lock);
 		if (release_group(group, 1))
@@ -605,7 +605,7 @@
 static int handle_join_req(struct mcast_group *group, u8 join_mask,
 			   struct mcast_req *req)
 {
-	u8 group_join_state = group->rec.scope_join_state & 7;
+	u8 group_join_state = group->rec.scope_join_state & 0xf;
 	int ref = 0;
 	u16 status;
 	struct ib_sa_mcmember_data *sa_data = (struct ib_sa_mcmember_data *)req->sa_mad.data;
@@ -690,8 +690,8 @@
 			u8 cur_join_state;
 
 			resp_join_state = ((struct ib_sa_mcmember_data *)
-						group->response_sa_mad.data)->scope_join_state & 7;
-			cur_join_state = group->rec.scope_join_state & 7;
+						group->response_sa_mad.data)->scope_join_state & 0xf;
+			cur_join_state = group->rec.scope_join_state & 0xf;
 
 			if (method == IB_MGMT_METHOD_GET_RESP) {
 				/* successfull join */
@@ -710,7 +710,7 @@
 		req = list_first_entry(&group->pending_list, struct mcast_req,
 				       group_list);
 		sa_data = (struct ib_sa_mcmember_data *)req->sa_mad.data;
-		req_join_state = sa_data->scope_join_state & 0x7;
+		req_join_state = sa_data->scope_join_state & 0xf;
 
 		/* For a leave request, we will immediately answer the VF, and
 		 * update our internal counters. The actual leave will be sent
@@ -1105,7 +1105,8 @@
 	while ((p = rb_first(&ctx->mcg_table)) != NULL) {
 		group = rb_entry(p, struct mcast_group, node);
 		if (atomic_read(&group->refcount))
-			mcg_warn_group(group, "group refcount %d!!! (pointer %p)\n", atomic_read(&group->refcount), group);
+			mcg_debug_group(group, "group refcount %d!!! (pointer %p)\n",
+					atomic_read(&group->refcount), group);
 
 		force_clean_group(group);
 	}
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -441,7 +441,7 @@
 	struct workqueue_struct *wq;
 	struct workqueue_struct *ud_wq;
 	spinlock_t ud_lock;
-	__be64 subnet_prefix;
+	atomic64_t subnet_prefix;
 	__be64 guid_cache[128];
 	struct mlx4_ib_dev *dev;
 	/* the following lock protects both mcg_table and mcg_mgid0_list */
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/mr.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/mr.c
@@ -130,6 +130,40 @@
 	return err;
 }
 
+static struct ib_umem *mlx4_get_umem_mr(struct ib_ucontext *context, u64 start,
+					u64 length, u64 virt_addr,
+					int access_flags)
+{
+	/*
+	 * Force registering the memory as writable if the underlying pages
+	 * are writable.  This is so rereg can change the access permissions
+	 * from readable to writable without having to run through ib_umem_get
+	 * again
+	 */
+	if (!ib_access_writable(access_flags)) {
+		struct vm_area_struct *vma;
+
+		down_read(&current->mm->mmap_sem);
+		/*
+		 * FIXME: Ideally this would iterate over all the vmas that
+		 * cover the memory, but for now it requires a single vma to
+		 * entirely cover the MR to support RO mappings.
+		 */
+		vma = find_vma(current->mm, start);
+		if (vma && vma->vm_end >= start + length &&
+		    vma->vm_start <= start) {
+			if (vma->vm_flags & VM_WRITE)
+				access_flags |= IB_ACCESS_LOCAL_WRITE;
+		} else {
+			access_flags |= IB_ACCESS_LOCAL_WRITE;
+		}
+
+		up_read(&current->mm->mmap_sem);
+	}
+
+	return ib_umem_get(context, start, length, access_flags, 0);
+}
+
 struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
 				  u64 virt_addr, int access_flags,
 				  struct ib_udata *udata)
@@ -144,10 +178,8 @@
 	if (!mr)
 		return ERR_PTR(-ENOMEM);
 
-	/* Force registering the memory as writable. */
-	/* Used for memory re-registeration. HCA protects the access */
-	mr->umem = ib_umem_get(pd->uobject->context, start, length,
-			       access_flags | IB_ACCESS_LOCAL_WRITE, 0);
+	mr->umem = mlx4_get_umem_mr(pd->uobject->context, start, length,
+				    virt_addr, access_flags);
 	if (IS_ERR(mr->umem)) {
 		err = PTR_ERR(mr->umem);
 		goto err_free;
@@ -214,6 +246,12 @@
 	}
 
 	if (flags & IB_MR_REREG_ACCESS) {
+		if (ib_access_writable(mr_access_flags) &&
+		    !mmr->umem->writable) {
+			err = -EPERM;
+			goto release_mpt_entry;
+		}
+
 		err = mlx4_mr_hw_change_access(dev->dev, *pmpt_entry,
 					       convert_access(mr_access_flags));
 
@@ -227,10 +265,9 @@
 
 		mlx4_mr_rereg_mem_cleanup(dev->dev, &mmr->mmr);
 		ib_umem_release(mmr->umem);
-		mmr->umem = ib_umem_get(mr->uobject->context, start, length,
-					mr_access_flags |
-					IB_ACCESS_LOCAL_WRITE,
-					0);
+		mmr->umem =
+			mlx4_get_umem_mr(mr->uobject->context, start, length,
+					 virt_addr, mr_access_flags);
 		if (IS_ERR(mmr->umem)) {
 			err = PTR_ERR(mmr->umem);
 			/* Prevent mlx4_ib_dereg_mr from free'ing invalid pointer */
@@ -424,7 +461,6 @@
 		goto err_free_mr;
 
 	mr->max_pages = max_num_sg;
-
 	err = mlx4_mr_enable(dev->dev, &mr->mmr);
 	if (err)
 		goto err_free_pl;
@@ -435,6 +471,7 @@
 	return &mr->ibmr;
 
 err_free_pl:
+	mr->ibmr.device = pd->device;
 	mlx4_free_priv_pages(mr);
 err_free_mr:
 	(void) mlx4_mr_free(dev->dev, &mr->mmr);
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/qp.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/qp.c
@@ -357,7 +357,7 @@
 			sizeof (struct mlx4_wqe_raddr_seg);
 	case MLX4_IB_QPT_RC:
 		return sizeof (struct mlx4_wqe_ctrl_seg) +
-			sizeof (struct mlx4_wqe_atomic_seg) +
+			sizeof (struct mlx4_wqe_masked_atomic_seg) +
 			sizeof (struct mlx4_wqe_raddr_seg);
 	case MLX4_IB_QPT_SMI:
 	case MLX4_IB_QPT_GSI:
@@ -1162,8 +1162,10 @@
 	{
 		err = create_qp_common(to_mdev(pd->device), pd, init_attr,
 				       udata, 0, &qp, gfp);
-		if (err)
+		if (err) {
+			kfree(qp);
 			return ERR_PTR(err);
+		}
 
 		qp->ibqp.qp_num = qp->mqp.qpn;
 		qp->xrcdn = xrcdn;
@@ -1205,7 +1207,8 @@
 	if (is_qp0(dev, mqp))
 		mlx4_CLOSE_PORT(dev->dev, mqp->port);
 
-	if (dev->qp1_proxy[mqp->port - 1] == mqp) {
+	if (mqp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI &&
+	    dev->qp1_proxy[mqp->port - 1] == mqp) {
 		mutex_lock(&dev->qp1_proxy_lock[mqp->port - 1]);
 		dev->qp1_proxy[mqp->port - 1] = NULL;
 		mutex_unlock(&dev->qp1_proxy_lock[mqp->port - 1]);
@@ -1561,7 +1564,7 @@
 			context->mtu_msgmax = (IB_MTU_4096 << 5) |
 					      ilog2(dev->dev->caps.max_gso_sz);
 		else
-			context->mtu_msgmax = (IB_MTU_4096 << 5) | 12;
+			context->mtu_msgmax = (IB_MTU_4096 << 5) | 13;
 	} else if (attr_mask & IB_QP_PATH_MTU) {
 		if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) {
 			pr_err("path MTU (%u) is invalid\n",
@@ -1591,9 +1594,12 @@
 	}
 
 	if (qp->ibqp.uobject)
-		context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index);
+		context->usr_page = cpu_to_be32(
+			mlx4_to_hw_uar_index(dev->dev,
+					     to_mucontext(ibqp->uobject->context)->uar.index));
 	else
-		context->usr_page = cpu_to_be32(dev->priv_uar.index);
+		context->usr_page = cpu_to_be32(
+			mlx4_to_hw_uar_index(dev->dev, dev->priv_uar.index));
 
 	if (attr_mask & IB_QP_DEST_QPN)
 		context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
@@ -2153,6 +2159,7 @@
 	int send_size;
 	int header_size;
 	int spc;
+	int err;
 	int i;
 
 	if (wr->wr.opcode != IB_WR_SEND)
@@ -2187,7 +2194,9 @@
 
 	sqp->ud_header.lrh.virtual_lane    = 0;
 	sqp->ud_header.bth.solicited_event = !!(wr->wr.send_flags & IB_SEND_SOLICITED);
-	ib_get_cached_pkey(ib_dev, sqp->qp.port, 0, &pkey);
+	err = ib_get_cached_pkey(ib_dev, sqp->qp.port, 0, &pkey);
+	if (err)
+		return err;
 	sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
 	if (sqp->qp.mlx4_ib_qp_type == MLX4_IB_QPT_TUN_SMI_OWNER)
 		sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->remote_qpn);
@@ -2329,24 +2338,27 @@
 		sqp->ud_header.grh.flow_label    =
 			ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
 		sqp->ud_header.grh.hop_limit     = ah->av.ib.hop_limit;
-		if (is_eth)
+		if (is_eth) {
 			memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16);
-		else {
-		if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
-			/* When multi-function is enabled, the ib_core gid
-			 * indexes don't necessarily match the hw ones, so
-			 * we must use our own cache */
-			sqp->ud_header.grh.source_gid.global.subnet_prefix =
-				to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
-						       subnet_prefix;
-			sqp->ud_header.grh.source_gid.global.interface_id =
-				to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
-					       guid_cache[ah->av.ib.gid_index];
-		} else
-			ib_get_cached_gid(ib_dev,
-					  be32_to_cpu(ah->av.ib.port_pd) >> 24,
-					  ah->av.ib.gid_index,
-					  &sqp->ud_header.grh.source_gid, NULL);
+		} else {
+			if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
+				/* When multi-function is enabled, the ib_core gid
+				 * indexes don't necessarily match the hw ones, so
+				 * we must use our own cache
+				 */
+				sqp->ud_header.grh.source_gid.global.subnet_prefix =
+					cpu_to_be64(atomic64_read(&(to_mdev(ib_dev)->sriov.
+								    demux[sqp->qp.port - 1].
+								    subnet_prefix)));
+				sqp->ud_header.grh.source_gid.global.interface_id =
+					to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
+						       guid_cache[ah->av.ib.gid_index];
+			} else {
+				ib_get_cached_gid(ib_dev,
+						  be32_to_cpu(ah->av.ib.port_pd) >> 24,
+						  ah->av.ib.gid_index,
+						  &sqp->ud_header.grh.source_gid, NULL);
+			}
 		}
 		memcpy(sqp->ud_header.grh.destination_gid.raw,
 		       ah->av.ib.dgid, 16);
@@ -2417,9 +2429,14 @@
 	}
 	sqp->ud_header.bth.solicited_event = !!(wr->wr.send_flags & IB_SEND_SOLICITED);
 	if (!sqp->qp.ibqp.qp_num)
-		ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey);
+		err = ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index,
+					 &pkey);
 	else
-		ib_get_cached_pkey(ib_dev, sqp->qp.port, wr->pkey_index, &pkey);
+		err = ib_get_cached_pkey(ib_dev, sqp->qp.port, wr->pkey_index,
+					 &pkey);
+	if (err)
+		return err;
+
 	sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
 	sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->remote_qpn);
 	sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx4/sysfs.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx4/sysfs.c
@@ -352,16 +352,12 @@
 
 static void get_name(struct mlx4_ib_dev *dev, char *name, int i, int max)
 {
-	char base_name[9];
-
-	/* pci_name format is: bus:dev:func -> xxxx:yy:zz.n */
-	strlcpy(name, pci_name(dev->dev->persist->pdev), max);
-	strncpy(base_name, name, 8); /*till xxxx:yy:*/
-	base_name[8] = '\0';
-	/* with no ARI only 3 last bits are used so when the fn is higher than 8
+	/* pci_name format is: bus:dev:func -> xxxx:yy:zz.n
+	 * with no ARI only 3 last bits are used so when the fn is higher than 8
 	 * need to add it to the dev num, so count in the last number will be
 	 * modulo 8 */
-	sprintf(name, "%s%.2d.%d", base_name, (i/8), (i%8));
+	snprintf(name, max, "%.8s%.2d.%d", pci_name(dev->dev->persist->pdev),
+		 i / 8, i % 8);
 }
 
 struct mlx4_port {
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx5/cq.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx5/cq.c
@@ -756,14 +756,15 @@
 	int uninitialized_var(index);
 	int uninitialized_var(inlen);
 	int cqe_size;
-	int irqn;
+	unsigned int irqn;
 	int eqn;
 	int err;
 
 	if (attr->flags)
 		return ERR_PTR(-EINVAL);
 
-	if (entries < 0)
+	if (entries < 0 ||
+	    (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz))))
 		return ERR_PTR(-EINVAL);
 
 	entries = roundup_pow_of_two(entries + 1);
@@ -786,8 +787,7 @@
 		if (err)
 			goto err_create;
 	} else {
-		/* for now choose 64 bytes till we have a proper interface */
-		cqe_size = 64;
+		cqe_size = cache_line_size() == 128 ? 128 : 64;
 		err = create_cq_kernel(dev, cq, entries, cqe_size, &cqb,
 				       &index, &inlen);
 		if (err)
@@ -972,7 +972,12 @@
 	if (ucmd.reserved0 || ucmd.reserved1)
 		return -EINVAL;
 
-	umem = ib_umem_get(context, ucmd.buf_addr, entries * ucmd.cqe_size,
+	/* check multiplication overflow */
+	if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1)
+		return -EINVAL;
+
+	umem = ib_umem_get(context, ucmd.buf_addr,
+			   (size_t)ucmd.cqe_size * entries,
 			   IB_ACCESS_LOCAL_WRITE, 1);
 	if (IS_ERR(umem)) {
 		err = PTR_ERR(umem);
@@ -1094,11 +1099,16 @@
 		return -ENOSYS;
 	}
 
-	if (entries < 1)
+	if (entries < 1 ||
+	    entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz))) {
+		mlx5_ib_warn(dev, "wrong entries number %d, max %d\n",
+			     entries,
+			     1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz));
 		return -EINVAL;
+	}
 
 	entries = roundup_pow_of_two(entries + 1);
-	if (entries >  (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)) + 1)
+	if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)) + 1)
 		return -EINVAL;
 
 	if (entries == ibcq->cqe + 1)
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx5/main.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx5/main.c
@@ -40,6 +40,7 @@
 #include <linux/io-mapping.h>
 #include <linux/sched.h>
 #include <rdma/ib_user_verbs.h>
+#include <linux/mlx5/port.h>
 #include <linux/mlx5/vport.h>
 #include <rdma/ib_smi.h>
 #include <rdma/ib_umem.h>
@@ -273,9 +274,9 @@
 		     sizeof(struct mlx5_wqe_ctrl_seg)) /
 		     sizeof(struct mlx5_wqe_data_seg);
 	props->max_sge = min(max_rq_sg, max_sq_sg);
-	props->max_sge_rd = props->max_sge;
+	props->max_sge_rd	   = MLX5_MAX_SGE_RD;
 	props->max_cq		   = 1 << MLX5_CAP_GEN(mdev, log_max_cq);
-	props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_eq_sz)) - 1;
+	props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_cq_sz)) - 1;
 	props->max_mr		   = 1 << MLX5_CAP_GEN(mdev, log_max_mkey);
 	props->max_pd		   = 1 << MLX5_CAP_GEN(mdev, log_max_pd);
 	props->max_qp_rd_atom	   = 1 << MLX5_CAP_GEN(mdev, log_max_ra_req_qp);
@@ -405,8 +406,8 @@
 	struct mlx5_ib_dev *dev = to_mdev(ibdev);
 	struct mlx5_core_dev *mdev = dev->mdev;
 	struct mlx5_hca_vport_context *rep;
-	int max_mtu;
-	int oper_mtu;
+	u16 max_mtu;
+	u16 oper_mtu;
 	int err;
 	u8 ib_link_width_oper;
 	u8 vl_hw_cap;
@@ -905,7 +906,7 @@
 {
 	struct mlx5_ib_dev *dev =
 		container_of(device, struct mlx5_ib_dev, ib_dev.dev);
-	return sprintf(buf, "%d.%d.%d\n", fw_rev_maj(dev->mdev),
+	return sprintf(buf, "%d.%d.%04d\n", fw_rev_maj(dev->mdev),
 		       fw_rev_min(dev->mdev), fw_rev_sub(dev->mdev));
 }
 
@@ -947,13 +948,13 @@
 {
 	struct mlx5_ib_dev *ibdev = (struct mlx5_ib_dev *)context;
 	struct ib_event ibev;
-
+	bool fatal = false;
 	u8 port = 0;
 
 	switch (event) {
 	case MLX5_DEV_EVENT_SYS_ERROR:
-		ibdev->ib_active = false;
 		ibev.event = IB_EVENT_DEVICE_FATAL;
+		fatal = true;
 		break;
 
 	case MLX5_DEV_EVENT_PORT_UP:
@@ -962,14 +963,11 @@
 		break;
 
 	case MLX5_DEV_EVENT_PORT_DOWN:
+	case MLX5_DEV_EVENT_PORT_INITIALIZED:
 		ibev.event = IB_EVENT_PORT_ERR;
 		port = (u8)param;
 		break;
 
-	case MLX5_DEV_EVENT_PORT_INITIALIZED:
-		/* not used by ULPs */
-		return;
-
 	case MLX5_DEV_EVENT_LID_CHANGE:
 		ibev.event = IB_EVENT_LID_CHANGE;
 		port = (u8)param;
@@ -1001,6 +999,9 @@
 
 	if (ibdev->ib_active)
 		ib_dispatch_event(&ibev);
+
+	if (fatal)
+		ibdev->ib_active = false;
 }
 
 static void get_ext_port_caps(struct mlx5_ib_dev *dev)
@@ -1123,6 +1124,8 @@
 	qp->real_qp    = qp;
 	qp->uobject    = NULL;
 	qp->qp_type    = MLX5_IB_QPT_REG_UMR;
+	qp->send_cq    = init_attr->send_cq;
+	qp->recv_cq    = init_attr->recv_cq;
 
 	attr->qp_state = IB_QPS_INIT;
 	attr->port_num = 1;
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx5/mr.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx5/mr.c
@@ -614,6 +614,33 @@
 	return 0;
 }
 
+static void wait_for_async_commands(struct mlx5_ib_dev *dev)
+{
+	struct mlx5_mr_cache *cache = &dev->cache;
+	struct mlx5_cache_ent *ent;
+	int total = 0;
+	int i;
+	int j;
+
+	for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
+		ent = &cache->ent[i];
+		for (j = 0 ; j < 1000; j++) {
+			if (!ent->pending)
+				break;
+			msleep(50);
+		}
+	}
+	for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
+		ent = &cache->ent[i];
+		total += ent->pending;
+	}
+
+	if (total)
+		mlx5_ib_warn(dev, "aborted while there are %d pending mr requests\n", total);
+	else
+		mlx5_ib_warn(dev, "done with all pending requests\n");
+}
+
 int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
 {
 	int i;
@@ -627,6 +654,7 @@
 		clean_keys(dev, i);
 
 	destroy_workqueue(dev->cache.wq);
+	wait_for_async_commands(dev);
 	del_timer_sync(&dev->delay_timer);
 
 	return 0;
@@ -764,7 +792,7 @@
 	struct device *ddev = dev->ib_dev.dma_device;
 	struct umr_common *umrc = &dev->umrc;
 	struct mlx5_ib_umr_context umr_context;
-	struct mlx5_umr_wr umrwr;
+	struct mlx5_umr_wr umrwr = {};
 	struct ib_send_wr *bad;
 	struct mlx5_ib_mr *mr;
 	struct ib_sge sg;
@@ -811,7 +839,6 @@
 		goto free_pas;
 	}
 
-	memset(&umrwr, 0, sizeof(umrwr));
 	umrwr.wr.wr_id = (u64)(unsigned long)&umr_context;
 	prep_umr_reg_wqe(pd, &umrwr.wr, &sg, dma, npages, mr->mmr.key,
 			 page_shift, virt_addr, len, access_flags);
@@ -1135,11 +1162,10 @@
 {
 	struct umr_common *umrc = &dev->umrc;
 	struct mlx5_ib_umr_context umr_context;
-	struct mlx5_umr_wr umrwr;
+	struct mlx5_umr_wr umrwr = {};
 	struct ib_send_wr *bad;
 	int err;
 
-	memset(&umrwr.wr, 0, sizeof(umrwr));
 	umrwr.wr.wr_id = (u64)(unsigned long)&umr_context;
 	prep_umr_unreg_wqe(dev, &umrwr.wr, mr->mmr.key);
 
--- linux-4.4.0.orig/drivers/infiniband/hw/mlx5/qp.c
+++ linux-4.4.0/drivers/infiniband/hw/mlx5/qp.c
@@ -226,10 +226,16 @@
 		qp->rq.max_gs = 0;
 		qp->rq.wqe_cnt = 0;
 		qp->rq.wqe_shift = 0;
+		cap->max_recv_wr = 0;
+		cap->max_recv_sge = 0;
 	} else {
 		if (ucmd) {
 			qp->rq.wqe_cnt = ucmd->rq_wqe_count;
+			if (ucmd->rq_wqe_shift > BITS_PER_BYTE * sizeof(ucmd->rq_wqe_shift))
+				return -EINVAL;
 			qp->rq.wqe_shift = ucmd->rq_wqe_shift;
+			if ((1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) < qp->wq_sig)
+				return -EINVAL;
 			qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig;
 			qp->rq.max_post = qp->rq.wqe_cnt;
 		} else {
@@ -265,8 +271,10 @@
 		/* fall through */
 	case IB_QPT_RC:
 		size += sizeof(struct mlx5_wqe_ctrl_seg) +
-			sizeof(struct mlx5_wqe_atomic_seg) +
-			sizeof(struct mlx5_wqe_raddr_seg);
+			max(sizeof(struct mlx5_wqe_atomic_seg) +
+			    sizeof(struct mlx5_wqe_raddr_seg),
+			    sizeof(struct mlx5_wqe_umr_ctrl_seg) +
+			    sizeof(struct mlx5_mkey_seg));
 		break;
 
 	case IB_QPT_XRC_TGT:
@@ -274,9 +282,9 @@
 
 	case IB_QPT_UC:
 		size += sizeof(struct mlx5_wqe_ctrl_seg) +
-			sizeof(struct mlx5_wqe_raddr_seg) +
-			sizeof(struct mlx5_wqe_umr_ctrl_seg) +
-			sizeof(struct mlx5_mkey_seg);
+			max(sizeof(struct mlx5_wqe_raddr_seg),
+			    sizeof(struct mlx5_wqe_umr_ctrl_seg) +
+			    sizeof(struct mlx5_mkey_seg));
 		break;
 
 	case IB_QPT_UD:
@@ -1346,18 +1354,18 @@
 
 static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate)
 {
-	if (rate == IB_RATE_PORT_CURRENT) {
+	if (rate == IB_RATE_PORT_CURRENT)
 		return 0;
-	} else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) {
+
+	if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS)
 		return -EINVAL;
-	} else {
-		while (rate != IB_RATE_2_5_GBPS &&
-		       !(1 << (rate + MLX5_STAT_RATE_OFFSET) &
-			 MLX5_CAP_GEN(dev->mdev, stat_rate_support)))
-			--rate;
-	}
 
-	return rate + MLX5_STAT_RATE_OFFSET;
+	while (rate != IB_RATE_PORT_CURRENT &&
+	       !(1 << (rate + MLX5_STAT_RATE_OFFSET) &
+		 MLX5_CAP_GEN(dev->mdev, stat_rate_support)))
+		--rate;
+
+	return rate ? rate + MLX5_STAT_RATE_OFFSET : rate;
 }
 
 static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah,
@@ -1420,6 +1428,11 @@
 			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX	|
 					  MLX5_QP_OPTPAR_Q_KEY		|
 					  MLX5_QP_OPTPAR_PRI_PORT,
+			[MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE		|
+					  MLX5_QP_OPTPAR_RAE		|
+					  MLX5_QP_OPTPAR_RWE		|
+					  MLX5_QP_OPTPAR_PKEY_INDEX	|
+					  MLX5_QP_OPTPAR_PRI_PORT,
 		},
 		[MLX5_QP_STATE_RTR] = {
 			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
@@ -1453,6 +1466,12 @@
 					  MLX5_QP_OPTPAR_RWE		|
 					  MLX5_QP_OPTPAR_PM_STATE,
 			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY,
+			[MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH	|
+					  MLX5_QP_OPTPAR_RRE		|
+					  MLX5_QP_OPTPAR_RAE		|
+					  MLX5_QP_OPTPAR_RWE		|
+					  MLX5_QP_OPTPAR_PM_STATE	|
+					  MLX5_QP_OPTPAR_RNR_TIMEOUT,
 		},
 	},
 	[MLX5_QP_STATE_RTS] = {
@@ -1469,6 +1488,12 @@
 			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY		|
 					  MLX5_QP_OPTPAR_SRQN		|
 					  MLX5_QP_OPTPAR_CQN_RCV,
+			[MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE		|
+					  MLX5_QP_OPTPAR_RAE		|
+					  MLX5_QP_OPTPAR_RWE		|
+					  MLX5_QP_OPTPAR_RNR_TIMEOUT	|
+					  MLX5_QP_OPTPAR_PM_STATE	|
+					  MLX5_QP_OPTPAR_ALT_ADDR_PATH,
 		},
 	},
 	[MLX5_QP_STATE_SQER] = {
@@ -1480,6 +1505,10 @@
 					   MLX5_QP_OPTPAR_RWE		|
 					   MLX5_QP_OPTPAR_RAE		|
 					   MLX5_QP_OPTPAR_RRE,
+			[MLX5_QP_ST_XRC]  = MLX5_QP_OPTPAR_RNR_TIMEOUT	|
+					   MLX5_QP_OPTPAR_RWE		|
+					   MLX5_QP_OPTPAR_RAE		|
+					   MLX5_QP_OPTPAR_RRE,
 		},
 	},
 };
@@ -2525,10 +2554,11 @@
 			return MLX5_FENCE_MODE_SMALL_AND_FENCE;
 		else
 			return fence;
-
-	} else {
-		return 0;
+	} else if (unlikely(wr->send_flags & IB_SEND_FENCE)) {
+		return MLX5_FENCE_MODE_FENCE;
 	}
+
+	return 0;
 }
 
 static int begin_wqe(struct mlx5_ib_qp *qp, void **seg,
@@ -3092,17 +3122,19 @@
 	qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
 
 	if (!ibqp->uobject) {
-		qp_attr->cap.max_send_wr  = qp->sq.wqe_cnt;
+		qp_attr->cap.max_send_wr  = qp->sq.max_post;
 		qp_attr->cap.max_send_sge = qp->sq.max_gs;
+		qp_init_attr->qp_context = ibqp->qp_context;
 	} else {
 		qp_attr->cap.max_send_wr  = 0;
 		qp_attr->cap.max_send_sge = 0;
 	}
 
-	/* We don't support inline sends for kernel QPs (yet), and we
-	 * don't know what userspace's value should be.
-	 */
-	qp_attr->cap.max_inline_data = 0;
+	qp_init_attr->qp_type = ibqp->qp_type;
+	qp_init_attr->recv_cq = ibqp->recv_cq;
+	qp_init_attr->send_cq = ibqp->send_cq;
+	qp_init_attr->srq = ibqp->srq;
+	qp_attr->cap.max_inline_data = qp->max_inline_data;
 
 	qp_init_attr->cap	     = qp_attr->cap;
 
@@ -3152,12 +3184,9 @@
 	int err;
 
 	err = mlx5_core_xrcd_dealloc(dev->mdev, xrcdn);
-	if (err) {
+	if (err)
 		mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn);
-		return err;
-	}
 
 	kfree(xrcd);
-
 	return 0;
 }
--- linux-4.4.0.orig/drivers/infiniband/hw/mthca/mthca_cq.c
+++ linux-4.4.0/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -612,7 +612,7 @@
 			entry->opcode    = IB_WC_BIND_MW;
 			break;
 		default:
-			entry->opcode    = MTHCA_OPCODE_INVALID;
+			entry->opcode = 0xFF;
 			break;
 		}
 	} else {
@@ -811,8 +811,10 @@
 	}
 
 	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
-	if (IS_ERR(mailbox))
+	if (IS_ERR(mailbox)) {
+		err = PTR_ERR(mailbox);
 		goto err_out_arm;
+	}
 
 	cq_context = mailbox->buf;
 
@@ -854,9 +856,9 @@
 	}
 
 	spin_lock_irq(&dev->cq_table.lock);
-	if (mthca_array_set(&dev->cq_table.cq,
-			    cq->cqn & (dev->limits.num_cqs - 1),
-			    cq)) {
+	err = mthca_array_set(&dev->cq_table.cq,
+			      cq->cqn & (dev->limits.num_cqs - 1), cq);
+	if (err) {
 		spin_unlock_irq(&dev->cq_table.lock);
 		goto err_out_free_mr;
 	}
--- linux-4.4.0.orig/drivers/infiniband/hw/mthca/mthca_dev.h
+++ linux-4.4.0/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -105,7 +105,6 @@
 	MTHCA_OPCODE_ATOMIC_CS      = 0x11,
 	MTHCA_OPCODE_ATOMIC_FA      = 0x12,
 	MTHCA_OPCODE_BIND_MW        = 0x18,
-	MTHCA_OPCODE_INVALID        = 0xff
 };
 
 enum {
--- linux-4.4.0.orig/drivers/infiniband/hw/mthca/mthca_main.c
+++ linux-4.4.0/drivers/infiniband/hw/mthca/mthca_main.c
@@ -989,7 +989,8 @@
 		goto err_free_dev;
 	}
 
-	if (mthca_cmd_init(mdev)) {
+	err = mthca_cmd_init(mdev);
+	if (err) {
 		mthca_err(mdev, "Failed to init command interface, aborting.\n");
 		goto err_free_dev;
 	}
--- linux-4.4.0.orig/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ linux-4.4.0/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -472,8 +472,8 @@
 		goto out;
 	}
 
-	ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0,
-			     pages, NULL);
+	ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1,
+			     FOLL_WRITE, pages, NULL);
 	if (ret < 0)
 		goto out;
 
--- linux-4.4.0.orig/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
+++ linux-4.4.0/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
@@ -643,7 +643,7 @@
 	struct ocrdma_stats *pstats = filp->private_data;
 	struct ocrdma_dev *dev = pstats->dev;
 
-	if (count > 32)
+	if (*ppos != 0 || count == 0 || count > sizeof(tmp_str))
 		goto err;
 
 	if (copy_from_user(tmp_str, buffer, count))
@@ -834,7 +834,7 @@
 
 	dev->reset_stats.type = OCRDMA_RESET_STATS;
 	dev->reset_stats.dev = dev;
-	if (!debugfs_create_file("reset_stats", S_IRUSR, dev->dir,
+	if (!debugfs_create_file("reset_stats", 0200, dev->dir,
 				&dev->reset_stats, &ocrdma_dbg_ops))
 		goto err;
 
--- linux-4.4.0.orig/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ linux-4.4.0/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -55,7 +55,7 @@
 
 int ocrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
 {
-	if (index > 1)
+	if (index > 0)
 		return -EINVAL;
 
 	*pkey = 0xffff;
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib.h
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib.h
@@ -1451,8 +1451,7 @@
 /*
  * dma_addr wrappers - all 0's invalid for hw
  */
-dma_addr_t qib_map_page(struct pci_dev *, struct page *, unsigned long,
-			  size_t, int);
+int qib_map_page(struct pci_dev *d, struct page *p, dma_addr_t *daddr);
 const char *qib_get_unit_name(int unit);
 
 /*
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_file_ops.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -45,6 +45,8 @@
 #include <linux/export.h>
 #include <linux/uio.h>
 
+#include <rdma/ib.h>
+
 #include "qib.h"
 #include "qib_common.h"
 #include "qib_user_sdma.h"
@@ -362,6 +364,8 @@
 		goto done;
 	}
 	for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) {
+		dma_addr_t daddr;
+
 		for (; ntids--; tid++) {
 			if (tid == tidcnt)
 				tid = 0;
@@ -378,12 +382,14 @@
 			ret = -ENOMEM;
 			break;
 		}
+		ret = qib_map_page(dd->pcidev, pagep[i], &daddr);
+		if (ret)
+			break;
+
 		tidlist[i] = tid + tidoff;
 		/* we "know" system pages and TID pages are same size */
 		dd->pageshadow[ctxttid + tid] = pagep[i];
-		dd->physshadow[ctxttid + tid] =
-			qib_map_page(dd->pcidev, pagep[i], 0, PAGE_SIZE,
-				     PCI_DMA_FROMDEVICE);
+		dd->physshadow[ctxttid + tid] = daddr;
 		/*
 		 * don't need atomic or it's overhead
 		 */
@@ -2067,6 +2073,9 @@
 	ssize_t ret = 0;
 	void *dest;
 
+	if (WARN_ON_ONCE(!ib_safe_file_access(fp)))
+		return -EACCES;
+
 	if (count < sizeof(cmd.type)) {
 		ret = -EINVAL;
 		goto bail;
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_iba7322.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -7097,7 +7097,7 @@
 	unsigned long flags;
 
 	while (wait) {
-		unsigned long shadow;
+		unsigned long shadow = 0;
 		int cstart, previ = -1;
 
 		/*
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_qp.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_qp.c
@@ -41,13 +41,13 @@
 
 #include "qib.h"
 
-#define BITS_PER_PAGE           (PAGE_SIZE*BITS_PER_BYTE)
-#define BITS_PER_PAGE_MASK      (BITS_PER_PAGE-1)
+#define RVT_BITS_PER_PAGE           (PAGE_SIZE*BITS_PER_BYTE)
+#define RVT_BITS_PER_PAGE_MASK      (RVT_BITS_PER_PAGE-1)
 
 static inline unsigned mk_qpn(struct qib_qpn_table *qpt,
 			      struct qpn_map *map, unsigned off)
 {
-	return (map - qpt->map) * BITS_PER_PAGE + off;
+	return (map - qpt->map) * RVT_BITS_PER_PAGE + off;
 }
 
 static inline unsigned find_next_offset(struct qib_qpn_table *qpt,
@@ -59,7 +59,7 @@
 		if (((off & qpt->mask) >> 1) >= n)
 			off = (off | qpt->mask) + 2;
 	} else
-		off = find_next_zero_bit(map->page, BITS_PER_PAGE, off);
+		off = find_next_zero_bit(map->page, RVT_BITS_PER_PAGE, off);
 	return off;
 }
 
@@ -100,9 +100,10 @@
 	32768                   /* 1E */
 };
 
-static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map)
+static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map,
+			 gfp_t gfp)
 {
-	unsigned long page = get_zeroed_page(GFP_KERNEL);
+	unsigned long page = get_zeroed_page(gfp);
 
 	/*
 	 * Free the page if someone raced with us installing it.
@@ -121,7 +122,7 @@
  * zero/one for QP type IB_QPT_SMI/IB_QPT_GSI.
  */
 static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
-		     enum ib_qp_type type, u8 port)
+		     enum ib_qp_type type, u8 port, gfp_t gfp)
 {
 	u32 i, offset, max_scan, qpn;
 	struct qpn_map *map;
@@ -146,12 +147,12 @@
 		qpn = 2;
 	if (qpt->mask && ((qpn & qpt->mask) >> 1) >= dd->n_krcv_queues)
 		qpn = (qpn | qpt->mask) + 2;
-	offset = qpn & BITS_PER_PAGE_MASK;
-	map = &qpt->map[qpn / BITS_PER_PAGE];
+	offset = qpn & RVT_BITS_PER_PAGE_MASK;
+	map = &qpt->map[qpn / RVT_BITS_PER_PAGE];
 	max_scan = qpt->nmaps - !offset;
 	for (i = 0;;) {
 		if (unlikely(!map->page)) {
-			get_map_page(qpt, map);
+			get_map_page(qpt, map, gfp);
 			if (unlikely(!map->page))
 				break;
 		}
@@ -172,7 +173,7 @@
 			 * We just need to be sure we don't loop
 			 * forever.
 			 */
-		} while (offset < BITS_PER_PAGE && qpn < QPN_MAX);
+		} while (offset < RVT_BITS_PER_PAGE && qpn < QPN_MAX);
 		/*
 		 * In order to keep the number of pages allocated to a
 		 * minimum, we scan the all existing pages before increasing
@@ -203,9 +204,9 @@
 {
 	struct qpn_map *map;
 
-	map = qpt->map + qpn / BITS_PER_PAGE;
+	map = qpt->map + qpn / RVT_BITS_PER_PAGE;
 	if (map->page)
-		clear_bit(qpn & BITS_PER_PAGE_MASK, map->page);
+		clear_bit(qpn & RVT_BITS_PER_PAGE_MASK, map->page);
 }
 
 static inline unsigned qpn_hash(struct qib_ibdev *dev, u32 qpn)
@@ -983,13 +984,21 @@
 	size_t sz;
 	size_t sg_list_sz;
 	struct ib_qp *ret;
+	gfp_t gfp;
+
 
 	if (init_attr->cap.max_send_sge > ib_qib_max_sges ||
 	    init_attr->cap.max_send_wr > ib_qib_max_qp_wrs ||
-	    init_attr->create_flags) {
-		ret = ERR_PTR(-EINVAL);
-		goto bail;
-	}
+	    init_attr->create_flags & ~(IB_QP_CREATE_USE_GFP_NOIO))
+		return ERR_PTR(-EINVAL);
+
+	/* GFP_NOIO is applicable in RC QPs only */
+	if (init_attr->create_flags & IB_QP_CREATE_USE_GFP_NOIO &&
+	    init_attr->qp_type != IB_QPT_RC)
+		return ERR_PTR(-EINVAL);
+
+	gfp = init_attr->create_flags & IB_QP_CREATE_USE_GFP_NOIO ?
+			GFP_NOIO : GFP_KERNEL;
 
 	/* Check receive queue parameters if no SRQ is specified. */
 	if (!init_attr->srq) {
@@ -1021,7 +1030,8 @@
 		sz = sizeof(struct qib_sge) *
 			init_attr->cap.max_send_sge +
 			sizeof(struct qib_swqe);
-		swq = vmalloc((init_attr->cap.max_send_wr + 1) * sz);
+		swq = __vmalloc((init_attr->cap.max_send_wr + 1) * sz,
+				gfp, PAGE_KERNEL);
 		if (swq == NULL) {
 			ret = ERR_PTR(-ENOMEM);
 			goto bail;
@@ -1037,13 +1047,13 @@
 		} else if (init_attr->cap.max_recv_sge > 1)
 			sg_list_sz = sizeof(*qp->r_sg_list) *
 				(init_attr->cap.max_recv_sge - 1);
-		qp = kzalloc(sz + sg_list_sz, GFP_KERNEL);
+		qp = kzalloc(sz + sg_list_sz, gfp);
 		if (!qp) {
 			ret = ERR_PTR(-ENOMEM);
 			goto bail_swq;
 		}
 		RCU_INIT_POINTER(qp->next, NULL);
-		qp->s_hdr = kzalloc(sizeof(*qp->s_hdr), GFP_KERNEL);
+		qp->s_hdr = kzalloc(sizeof(*qp->s_hdr), gfp);
 		if (!qp->s_hdr) {
 			ret = ERR_PTR(-ENOMEM);
 			goto bail_qp;
@@ -1058,8 +1068,16 @@
 			qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
 			sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
 				sizeof(struct qib_rwqe);
-			qp->r_rq.wq = vmalloc_user(sizeof(struct qib_rwq) +
-						   qp->r_rq.size * sz);
+			if (gfp != GFP_NOIO)
+				qp->r_rq.wq = vmalloc_user(
+						sizeof(struct qib_rwq) +
+						qp->r_rq.size * sz);
+			else
+				qp->r_rq.wq = __vmalloc(
+						sizeof(struct qib_rwq) +
+						qp->r_rq.size * sz,
+						gfp, PAGE_KERNEL);
+
 			if (!qp->r_rq.wq) {
 				ret = ERR_PTR(-ENOMEM);
 				goto bail_qp;
@@ -1090,7 +1108,7 @@
 		dev = to_idev(ibpd->device);
 		dd = dd_from_dev(dev);
 		err = alloc_qpn(dd, &dev->qpn_table, init_attr->qp_type,
-				init_attr->port_num);
+				init_attr->port_num, gfp);
 		if (err < 0) {
 			ret = ERR_PTR(err);
 			vfree(qp->r_rq.wq);
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_rc.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_rc.c
@@ -2088,8 +2088,10 @@
 		ret = qib_get_rwqe(qp, 1);
 		if (ret < 0)
 			goto nack_op_err;
-		if (!ret)
+		if (!ret) {
+			qib_put_ss(&qp->r_sge);
 			goto rnr_nak;
+		}
 		wc.ex.imm_data = ohdr->u.rc.imm_data;
 		hdrsize += 4;
 		wc.wc_flags = IB_WC_WITH_IMM;
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_sdma.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_sdma.c
@@ -597,8 +597,10 @@
 		dw = (len + 3) >> 2;
 		addr = dma_map_single(&ppd->dd->pcidev->dev, sge->vaddr,
 				      dw << 2, DMA_TO_DEVICE);
-		if (dma_mapping_error(&ppd->dd->pcidev->dev, addr))
+		if (dma_mapping_error(&ppd->dd->pcidev->dev, addr)) {
+			ret = -ENOMEM;
 			goto unmap;
+		}
 		sdmadesc[0] = 0;
 		make_sdma_desc(ppd, sdmadesc, (u64) addr, dw, dwoffset);
 		/* SDmaUseLargeBuf has to be set in every descriptor */
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_sysfs.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_sysfs.c
@@ -301,6 +301,9 @@
 	struct qib_pportdata *ppd =
 		container_of(kobj, struct qib_pportdata, pport_kobj);
 
+	if (!pattr->show)
+		return -EIO;
+
 	return pattr->show(ppd, buf);
 }
 
@@ -312,6 +315,9 @@
 	struct qib_pportdata *ppd =
 		container_of(kobj, struct qib_pportdata, pport_kobj);
 
+	if (!pattr->store)
+		return -EIO;
+
 	return pattr->store(ppd, buf, len);
 }
 
@@ -697,7 +703,7 @@
 		qib_dev_err(dd,
 			"Skipping linkcontrol sysfs info, (err %d) port %u\n",
 			ret, port_num);
-		goto bail;
+		goto bail_link;
 	}
 	kobject_uevent(&ppd->pport_kobj, KOBJ_ADD);
 
@@ -707,7 +713,7 @@
 		qib_dev_err(dd,
 			"Skipping sl2vl sysfs info, (err %d) port %u\n",
 			ret, port_num);
-		goto bail_link;
+		goto bail_sl;
 	}
 	kobject_uevent(&ppd->sl2vl_kobj, KOBJ_ADD);
 
@@ -717,7 +723,7 @@
 		qib_dev_err(dd,
 			"Skipping diag_counters sysfs info, (err %d) port %u\n",
 			ret, port_num);
-		goto bail_sl;
+		goto bail_diagc;
 	}
 	kobject_uevent(&ppd->diagc_kobj, KOBJ_ADD);
 
@@ -730,7 +736,7 @@
 		qib_dev_err(dd,
 		 "Skipping Congestion Control sysfs info, (err %d) port %u\n",
 		 ret, port_num);
-		goto bail_diagc;
+		goto bail_cc;
 	}
 
 	kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD);
@@ -812,6 +818,7 @@
 				&cc_table_bin_attr);
 			kobject_put(&ppd->pport_cc_kobj);
 		}
+		kobject_put(&ppd->diagc_kobj);
 		kobject_put(&ppd->sl2vl_kobj);
 		kobject_put(&ppd->pport_kobj);
 	}
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_ud.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_ud.c
@@ -515,7 +515,6 @@
 	    opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
 		wc.ex.imm_data = ohdr->u.ud.imm_data;
 		wc.wc_flags = IB_WC_WITH_IMM;
-		tlen -= sizeof(u32);
 	} else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
 		wc.ex.imm_data = 0;
 		wc.wc_flags = 0;
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_user_pages.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_user_pages.c
@@ -68,7 +68,8 @@
 	for (got = 0; got < num_pages; got += ret) {
 		ret = get_user_pages(current, current->mm,
 				     start_page + got * PAGE_SIZE,
-				     num_pages - got, 1, 1,
+				     num_pages - got,
+				     FOLL_WRITE | FOLL_FORCE,
 				     p + got, NULL);
 		if (ret < 0)
 			goto bail_release;
@@ -98,23 +99,27 @@
  *
  * I'm sure we won't be so lucky with other iommu's, so FIXME.
  */
-dma_addr_t qib_map_page(struct pci_dev *hwdev, struct page *page,
-			unsigned long offset, size_t size, int direction)
+int qib_map_page(struct pci_dev *hwdev, struct page *page, dma_addr_t *daddr)
 {
 	dma_addr_t phys;
 
-	phys = pci_map_page(hwdev, page, offset, size, direction);
-
-	if (phys == 0) {
-		pci_unmap_page(hwdev, phys, size, direction);
-		phys = pci_map_page(hwdev, page, offset, size, direction);
+	phys = pci_map_page(hwdev, page, 0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(hwdev, phys))
+		return -ENOMEM;
+
+	if (!phys) {
+		pci_unmap_page(hwdev, phys, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+		phys = pci_map_page(hwdev, page, 0, PAGE_SIZE,
+				    PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(hwdev, phys))
+			return -ENOMEM;
 		/*
 		 * FIXME: If we get 0 again, we should keep this page,
 		 * map another, then free the 0 page.
 		 */
 	}
-
-	return phys;
+	*daddr = phys;
+	return 0;
 }
 
 /**
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_user_sdma.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_user_sdma.c
@@ -41,6 +41,7 @@
 #include <linux/rbtree.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
+#include <linux/overflow.h>
 
 #include "qib.h"
 #include "qib_user_sdma.h"
@@ -606,7 +607,7 @@
 /*
  * How many pages in this iovec element?
  */
-static int qib_user_sdma_num_pages(const struct iovec *iov)
+static size_t qib_user_sdma_num_pages(const struct iovec *iov)
 {
 	const unsigned long addr  = (unsigned long) iov->iov_base;
 	const unsigned long  len  = iov->iov_len;
@@ -662,7 +663,7 @@
 static int qib_user_sdma_pin_pages(const struct qib_devdata *dd,
 				   struct qib_user_sdma_queue *pq,
 				   struct qib_user_sdma_pkt *pkt,
-				   unsigned long addr, int tlen, int npages)
+				   unsigned long addr, int tlen, size_t npages)
 {
 	struct page *pages[8];
 	int i, j;
@@ -726,7 +727,7 @@
 	unsigned long idx;
 
 	for (idx = 0; idx < niov; idx++) {
-		const int npages = qib_user_sdma_num_pages(iov + idx);
+		const size_t npages = qib_user_sdma_num_pages(iov + idx);
 		const unsigned long addr = (unsigned long) iov[idx].iov_base;
 
 		ret = qib_user_sdma_pin_pages(dd, pq, pkt, addr,
@@ -828,8 +829,8 @@
 		unsigned pktnw;
 		unsigned pktnwc;
 		int nfrags = 0;
-		int npages = 0;
-		int bytes_togo = 0;
+		size_t npages = 0;
+		size_t bytes_togo = 0;
 		int tiddma = 0;
 		int cfur;
 
@@ -889,7 +890,11 @@
 
 			npages += qib_user_sdma_num_pages(&iov[idx]);
 
-			bytes_togo += slen;
+			if (check_add_overflow(bytes_togo, slen, &bytes_togo) ||
+			    bytes_togo > type_max(typeof(pkt->bytes_togo))) {
+				ret = -EINVAL;
+				goto free_pbc;
+			}
 			pktnwc += slen >> 2;
 			idx++;
 			nfrags++;
@@ -908,7 +913,7 @@
 		}
 
 		if (frag_size) {
-			int pktsize, tidsmsize, n;
+			size_t tidsmsize, n, pktsize, sz, addrlimit;
 
 			n = npages*((2*PAGE_SIZE/frag_size)+1);
 			pktsize = sizeof(*pkt) + sizeof(pkt->addr[0])*n;
@@ -926,14 +931,24 @@
 			else
 				tidsmsize = 0;
 
-			pkt = kmalloc(pktsize+tidsmsize, GFP_KERNEL);
+			if (check_add_overflow(pktsize, tidsmsize, &sz)) {
+				ret = -EINVAL;
+				goto free_pbc;
+			}
+			pkt = kmalloc(sz, GFP_KERNEL);
 			if (!pkt) {
 				ret = -ENOMEM;
 				goto free_pbc;
 			}
 			pkt->largepkt = 1;
 			pkt->frag_size = frag_size;
-			pkt->addrlimit = n + ARRAY_SIZE(pkt->addr);
+			if (check_add_overflow(n, ARRAY_SIZE(pkt->addr),
+					       &addrlimit) ||
+			    addrlimit > type_max(typeof(pkt->addrlimit))) {
+				ret = -EINVAL;
+				goto free_pkt;
+			}
+			pkt->addrlimit = addrlimit;
 
 			if (tiddma) {
 				char *tidsm = (char *)pkt + pktsize;
--- linux-4.4.0.orig/drivers/infiniband/hw/qib/qib_verbs_mcast.c
+++ linux-4.4.0/drivers/infiniband/hw/qib/qib_verbs_mcast.c
@@ -286,15 +286,13 @@
 	struct qib_ibdev *dev = to_idev(ibqp->device);
 	struct qib_ibport *ibp = to_iport(ibqp->device, qp->port_num);
 	struct qib_mcast *mcast = NULL;
-	struct qib_mcast_qp *p, *tmp;
+	struct qib_mcast_qp *p, *tmp, *delp = NULL;
 	struct rb_node *n;
 	int last = 0;
 	int ret;
 
-	if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) {
-		ret = -EINVAL;
-		goto bail;
-	}
+	if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET)
+		return -EINVAL;
 
 	spin_lock_irq(&ibp->lock);
 
@@ -303,8 +301,7 @@
 	while (1) {
 		if (n == NULL) {
 			spin_unlock_irq(&ibp->lock);
-			ret = -EINVAL;
-			goto bail;
+			return -EINVAL;
 		}
 
 		mcast = rb_entry(n, struct qib_mcast, rb_node);
@@ -328,6 +325,7 @@
 		 */
 		list_del_rcu(&p->list);
 		mcast->n_attached--;
+		delp = p;
 
 		/* If this was the last attached QP, remove the GID too. */
 		if (list_empty(&mcast->qp_list)) {
@@ -338,15 +336,16 @@
 	}
 
 	spin_unlock_irq(&ibp->lock);
+	/* QP not attached */
+	if (!delp)
+		return -EINVAL;
+	/*
+	 * Wait for any list walkers to finish before freeing the
+	 * list element.
+	 */
+	wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1);
+	qib_mcast_qp_free(delp);
 
-	if (p) {
-		/*
-		 * Wait for any list walkers to finish before freeing the
-		 * list element.
-		 */
-		wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1);
-		qib_mcast_qp_free(p);
-	}
 	if (last) {
 		atomic_dec(&mcast->refcount);
 		wait_event(mcast->wait, !atomic_read(&mcast->refcount));
@@ -355,11 +354,7 @@
 		dev->n_mcast_grps_allocated--;
 		spin_unlock_irq(&dev->n_mcast_grps_lock);
 	}
-
-	ret = 0;
-
-bail:
-	return ret;
+	return 0;
 }
 
 int qib_mcast_tree_empty(struct qib_ibport *ibp)
--- linux-4.4.0.orig/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
+++ linux-4.4.0/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
@@ -180,6 +180,7 @@
 
 		}
 		usnic_uiom_free_dev_list(dev_list);
+		dev_list = NULL;
 	}
 
 	if (!found) {
@@ -207,6 +208,8 @@
 	spin_unlock(&vf->lock);
 	if (IS_ERR_OR_NULL(qp_grp)) {
 		usnic_err("Failed to allocate qp_grp\n");
+		if (usnic_ib_share_vf)
+			usnic_uiom_free_dev_list(dev_list);
 		return ERR_PTR(qp_grp ? PTR_ERR(qp_grp) : -ENOMEM);
 	}
 
@@ -427,7 +430,7 @@
 int usnic_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
 				u16 *pkey)
 {
-	if (index > 1)
+	if (index > 0)
 		return -EINVAL;
 
 	*pkey = 0xffff;
--- linux-4.4.0.orig/drivers/infiniband/hw/usnic/usnic_uiom.c
+++ linux-4.4.0/drivers/infiniband/hw/usnic/usnic_uiom.c
@@ -113,6 +113,7 @@
 	int flags;
 	dma_addr_t pa;
 	DEFINE_DMA_ATTRS(attrs);
+	unsigned int gup_flags;
 
 	if (dmasync)
 		dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
@@ -140,6 +141,8 @@
 
 	flags = IOMMU_READ | IOMMU_CACHE;
 	flags |= (writable) ? IOMMU_WRITE : 0;
+	gup_flags = FOLL_WRITE;
+	gup_flags |= (writable) ? 0 : FOLL_FORCE;
 	cur_base = addr & PAGE_MASK;
 	ret = 0;
 
@@ -147,7 +150,7 @@
 		ret = get_user_pages(current, current->mm, cur_base,
 					min_t(unsigned long, npages,
 					PAGE_SIZE / sizeof(struct page *)),
-					1, !writable, page_list, NULL);
+					gup_flags, page_list, NULL);
 
 		if (ret < 0)
 			goto out;
--- linux-4.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib.h
+++ linux-4.4.0/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -63,6 +63,8 @@
 
 enum {
 	IPOIB_ENCAP_LEN		  = 4,
+	IPOIB_PSEUDO_LEN	  = 20,
+	IPOIB_HARD_LEN		  = IPOIB_ENCAP_LEN + IPOIB_PSEUDO_LEN,
 
 	IPOIB_UD_HEAD_SIZE	  = IB_GRH_BYTES + IPOIB_ENCAP_LEN,
 	IPOIB_UD_RX_SG		  = 2, /* max buffer needed for 4K mtu */
@@ -131,15 +133,21 @@
 	u16	reserved;
 };
 
-struct ipoib_cb {
-	struct qdisc_skb_cb	qdisc_cb;
-	u8			hwaddr[INFINIBAND_ALEN];
+struct ipoib_pseudo_header {
+	u8	hwaddr[INFINIBAND_ALEN];
 };
 
-static inline struct ipoib_cb *ipoib_skb_cb(const struct sk_buff *skb)
+static inline void skb_add_pseudo_hdr(struct sk_buff *skb)
 {
-	BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct ipoib_cb));
-	return (struct ipoib_cb *)skb->cb;
+	char *data = skb_push(skb, IPOIB_PSEUDO_LEN);
+
+	/*
+	 * only the ipoib header is present now, make room for a dummy
+	 * pseudo header and set skb field accordingly
+	 */
+	memset(data, 0, IPOIB_PSEUDO_LEN);
+	skb_reset_mac_header(skb);
+	skb_pull(skb, IPOIB_HARD_LEN);
 }
 
 /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
@@ -472,6 +480,7 @@
 		struct ipoib_ah *address, u32 qpn);
 void ipoib_reap_ah(struct work_struct *work);
 
+struct ipoib_path *__path_find(struct net_device *dev, void *gid);
 void ipoib_mark_paths_invalid(struct net_device *dev);
 void ipoib_flush_paths(struct net_device *dev);
 struct ipoib_dev_priv *ipoib_intf_alloc(const char *format);
--- linux-4.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ linux-4.4.0/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -63,6 +63,8 @@
 #define IPOIB_CM_RX_DELAY       (3 * 256 * HZ)
 #define IPOIB_CM_RX_UPDATE_MASK (0x3)
 
+#define IPOIB_CM_RX_RESERVE     (ALIGN(IPOIB_HARD_LEN, 16) - IPOIB_ENCAP_LEN)
+
 static struct ib_qp_attr ipoib_cm_err_attr = {
 	.qp_state = IB_QPS_ERR
 };
@@ -147,15 +149,15 @@
 	struct sk_buff *skb;
 	int i;
 
-	skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12);
+	skb = dev_alloc_skb(ALIGN(IPOIB_CM_HEAD_SIZE + IPOIB_PSEUDO_LEN, 16));
 	if (unlikely(!skb))
 		return NULL;
 
 	/*
-	 * IPoIB adds a 4 byte header. So we need 12 more bytes to align the
+	 * IPoIB adds a IPOIB_ENCAP_LEN byte header, this will align the
 	 * IP header to a multiple of 16.
 	 */
-	skb_reserve(skb, 12);
+	skb_reserve(skb, IPOIB_CM_RX_RESERVE);
 
 	mapping[0] = ib_dma_map_single(priv->ca, skb->data, IPOIB_CM_HEAD_SIZE,
 				       DMA_FROM_DEVICE);
@@ -624,9 +626,9 @@
 	if (wc->byte_len < IPOIB_CM_COPYBREAK) {
 		int dlen = wc->byte_len;
 
-		small_skb = dev_alloc_skb(dlen + 12);
+		small_skb = dev_alloc_skb(dlen + IPOIB_CM_RX_RESERVE);
 		if (small_skb) {
-			skb_reserve(small_skb, 12);
+			skb_reserve(small_skb, IPOIB_CM_RX_RESERVE);
 			ib_dma_sync_single_for_cpu(priv->ca, rx_ring[wr_id].mapping[0],
 						   dlen, DMA_FROM_DEVICE);
 			skb_copy_from_linear_data(skb, small_skb->data, dlen);
@@ -663,8 +665,7 @@
 
 copied:
 	skb->protocol = ((struct ipoib_header *) skb->data)->proto;
-	skb_reset_mac_header(skb);
-	skb_pull(skb, IPOIB_ENCAP_LEN);
+	skb_add_pseudo_hdr(skb);
 
 	++dev->stats.rx_packets;
 	dev->stats.rx_bytes += skb->len;
@@ -991,12 +992,14 @@
 
 	skb_queue_head_init(&skqueue);
 
+	netif_tx_lock_bh(p->dev);
 	spin_lock_irq(&priv->lock);
 	set_bit(IPOIB_FLAG_OPER_UP, &p->flags);
 	if (p->neigh)
 		while ((skb = __skb_dequeue(&p->neigh->queue)))
 			__skb_queue_tail(&skqueue, skb);
 	spin_unlock_irq(&priv->lock);
+	netif_tx_unlock_bh(p->dev);
 
 	while ((skb = __skb_dequeue(&skqueue))) {
 		skb->dev = p->dev;
@@ -1035,8 +1038,6 @@
 
 	tx_qp = ib_create_qp(priv->pd, &attr);
 	if (PTR_ERR(tx_qp) == -EINVAL) {
-		ipoib_warn(priv, "can't use GFP_NOIO for QPs on device %s, using GFP_KERNEL\n",
-			   priv->ca->name);
 		attr.create_flags &= ~IB_QP_CREATE_USE_GFP_NOIO;
 		tx_qp = ib_create_qp(priv->pd, &attr);
 	}
@@ -1299,6 +1300,8 @@
 	}
 }
 
+#define QPN_AND_OPTIONS_OFFSET	4
+
 static void ipoib_cm_tx_start(struct work_struct *work)
 {
 	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
@@ -1307,6 +1310,7 @@
 	struct ipoib_neigh *neigh;
 	struct ipoib_cm_tx *p;
 	unsigned long flags;
+	struct ipoib_path *path;
 	int ret;
 
 	struct ib_sa_path_rec pathrec;
@@ -1319,7 +1323,19 @@
 		p = list_entry(priv->cm.start_list.next, typeof(*p), list);
 		list_del_init(&p->list);
 		neigh = p->neigh;
+
 		qpn = IPOIB_QPN(neigh->daddr);
+		/*
+		 * As long as the search is with these 2 locks,
+		 * path existence indicates its validity.
+		 */
+		path = __path_find(dev, neigh->daddr + QPN_AND_OPTIONS_OFFSET);
+		if (!path) {
+			pr_info("%s ignore not valid path %pI6\n",
+				__func__,
+				neigh->daddr + QPN_AND_OPTIONS_OFFSET);
+			goto free_neigh;
+		}
 		memcpy(&pathrec, &p->path->pathrec, sizeof pathrec);
 
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -1331,6 +1347,7 @@
 		spin_lock_irqsave(&priv->lock, flags);
 
 		if (ret) {
+free_neigh:
 			neigh = p->neigh;
 			if (neigh) {
 				neigh->cm = NULL;
@@ -1358,7 +1375,7 @@
 
 	while (!list_empty(&priv->cm.reap_list)) {
 		p = list_entry(priv->cm.reap_list.next, typeof(*p), list);
-		list_del(&p->list);
+		list_del_init(&p->list);
 		spin_unlock_irqrestore(&priv->lock, flags);
 		netif_tx_unlock_bh(dev);
 		ipoib_cm_tx_destroy(p);
@@ -1473,12 +1490,14 @@
 
 	ret = ipoib_set_mode(dev, buf);
 
-	rtnl_unlock();
-
-	if (!ret)
-		return count;
+	/* The assumption is that the function ipoib_set_mode returned
+	 * with the rtnl held by it, if not the value -EBUSY returned,
+	 * then no need to rtnl_unlock
+	 */
+	if (ret != -EBUSY)
+		rtnl_unlock();
 
-	return ret;
+	return (!ret || ret == -EBUSY) ? count : ret;
 }
 
 static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode);
--- linux-4.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ linux-4.4.0/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -283,6 +283,7 @@
 
 	debugfs_remove(priv->mcg_dentry);
 	debugfs_remove(priv->path_dentry);
+	priv->mcg_dentry = priv->path_dentry = NULL;
 }
 
 int ipoib_register_debugfs(void)
--- linux-4.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ linux-4.4.0/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -130,16 +130,15 @@
 
 	buf_size = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu);
 
-	skb = dev_alloc_skb(buf_size + IPOIB_ENCAP_LEN);
+	skb = dev_alloc_skb(buf_size + IPOIB_HARD_LEN);
 	if (unlikely(!skb))
 		return NULL;
 
 	/*
-	 * IB will leave a 40 byte gap for a GRH and IPoIB adds a 4 byte
-	 * header.  So we need 4 more bytes to get to 48 and align the
-	 * IP header to a multiple of 16.
+	 * the IP header will be at IPOIP_HARD_LEN + IB_GRH_BYTES, that is
+	 * 64 bytes aligned
 	 */
-	skb_reserve(skb, 4);
+	skb_reserve(skb, sizeof(struct ipoib_pseudo_header));
 
 	mapping = priv->rx_ring[id].mapping;
 	mapping[0] = ib_dma_map_single(priv->ca, skb->data, buf_size,
@@ -242,10 +241,7 @@
 	skb_pull(skb, IB_GRH_BYTES);
 
 	skb->protocol = ((struct ipoib_header *) skb->data)->proto;
-	skb_reset_mac_header(skb);
-	skb_pull(skb, IPOIB_ENCAP_LEN);
-
-	skb->truesize = SKB_TRUESIZE(skb->len);
+	skb_add_pseudo_hdr(skb);
 
 	++dev->stats.rx_packets;
 	dev->stats.rx_bytes += skb->len;
@@ -1030,8 +1026,17 @@
 	}
 
 	if (level == IPOIB_FLUSH_LIGHT) {
+		int oper_up;
 		ipoib_mark_paths_invalid(dev);
+		/* Set IPoIB operation as down to prevent races between:
+		 * the flush flow which leaves MCG and on the fly joins
+		 * which can happen during that time. mcast restart task
+		 * should deal with join requests we missed.
+		 */
+		oper_up = test_and_clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags);
 		ipoib_mcast_dev_flush(dev);
+		if (oper_up)
+			set_bit(IPOIB_FLAG_OPER_UP, &priv->flags);
 		ipoib_flush_ah(dev);
 	}
 
@@ -1041,8 +1046,10 @@
 	if (level == IPOIB_FLUSH_HEAVY) {
 		if (test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
 			ipoib_ib_dev_stop(dev);
-		if (ipoib_ib_dev_open(dev) != 0)
+
+		if (ipoib_ib_dev_open(dev))
 			return;
+
 		if (netif_queue_stopped(dev))
 			netif_start_queue(dev);
 	}
@@ -1079,7 +1086,9 @@
 	struct ipoib_dev_priv *priv =
 		container_of(work, struct ipoib_dev_priv, flush_heavy);
 
+	rtnl_lock();
 	__ipoib_ib_dev_flush(priv, IPOIB_FLUSH_HEAVY, 0);
+	rtnl_unlock();
 }
 
 void ipoib_ib_dev_cleanup(struct net_device *dev)
--- linux-4.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ linux-4.4.0/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -106,6 +106,33 @@
 	.get_net_dev_by_params = ipoib_get_net_dev_by_params,
 };
 
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+static int ipoib_netdev_event(struct notifier_block *this,
+			      unsigned long event, void *ptr)
+{
+	struct netdev_notifier_info *ni = ptr;
+	struct net_device *dev = ni->dev;
+
+	if (dev->netdev_ops->ndo_open != ipoib_open)
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_REGISTER:
+		ipoib_create_debug_files(dev);
+		break;
+	case NETDEV_CHANGENAME:
+		ipoib_delete_debug_files(dev);
+		ipoib_create_debug_files(dev);
+		break;
+	case NETDEV_UNREGISTER:
+		ipoib_delete_debug_files(dev);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+#endif
+
 int ipoib_open(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -464,8 +491,7 @@
 		priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM;
 
 		ipoib_flush_paths(dev);
-		rtnl_lock();
-		return 0;
+		return (!rtnl_trylock()) ? -EBUSY : 0;
 	}
 
 	if (!strcmp(buf, "datagram\n")) {
@@ -474,14 +500,13 @@
 		dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu));
 		rtnl_unlock();
 		ipoib_flush_paths(dev);
-		rtnl_lock();
-		return 0;
+		return (!rtnl_trylock()) ? -EBUSY : 0;
 	}
 
 	return -EINVAL;
 }
 
-static struct ipoib_path *__path_find(struct net_device *dev, void *gid)
+struct ipoib_path *__path_find(struct net_device *dev, void *gid)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct rb_node *n = priv->path_tree.rb_node;
@@ -628,6 +653,14 @@
 	spin_unlock_irq(&priv->lock);
 }
 
+static void push_pseudo_header(struct sk_buff *skb, const char *daddr)
+{
+	struct ipoib_pseudo_header *phdr;
+
+	phdr = (struct ipoib_pseudo_header *)skb_push(skb, sizeof(*phdr));
+	memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
+}
+
 void ipoib_flush_paths(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -691,6 +724,22 @@
 	spin_lock_irqsave(&priv->lock, flags);
 
 	if (!IS_ERR_OR_NULL(ah)) {
+		/*
+		 * pathrec.dgid is used as the database key from the LLADDR,
+		 * it must remain unchanged even if the SA returns a different
+		 * GID to use in the AH.
+		 */
+		if (memcmp(pathrec->dgid.raw, path->pathrec.dgid.raw,
+			   sizeof(union ib_gid))) {
+			ipoib_dbg(
+				priv,
+				"%s got PathRec for gid %pI6 while asked for %pI6\n",
+				dev->name, pathrec->dgid.raw,
+				path->pathrec.dgid.raw);
+			memcpy(pathrec->dgid.raw, path->pathrec.dgid.raw,
+			       sizeof(union ib_gid));
+		}
+
 		path->pathrec = *pathrec;
 
 		old_ah   = path->ah;
@@ -811,8 +860,8 @@
 	return 0;
 }
 
-static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
-			   struct net_device *dev)
+static struct ipoib_neigh *neigh_add_path(struct sk_buff *skb, u8 *daddr,
+					  struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_path *path;
@@ -825,7 +874,15 @@
 		spin_unlock_irqrestore(&priv->lock, flags);
 		++dev->stats.tx_dropped;
 		dev_kfree_skb_any(skb);
-		return;
+		return NULL;
+	}
+
+	/* To avoid race condition, make sure that the
+	 * neigh will be added only once.
+	 */
+	if (unlikely(!list_empty(&neigh->list))) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return neigh;
 	}
 
 	path = __path_find(dev, daddr + 4);
@@ -850,9 +907,11 @@
 				ipoib_neigh_free(neigh);
 				goto err_drop;
 			}
-			if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)
+			if (skb_queue_len(&neigh->queue) <
+			    IPOIB_MAX_PATH_REC_QUEUE) {
+				push_pseudo_header(skb, neigh->daddr);
 				__skb_queue_tail(&neigh->queue, skb);
-			else {
+			} else {
 				ipoib_warn(priv, "queue length limit %d. Packet drop.\n",
 					   skb_queue_len(&neigh->queue));
 				goto err_drop;
@@ -861,22 +920,24 @@
 			spin_unlock_irqrestore(&priv->lock, flags);
 			ipoib_send(dev, skb, path->ah, IPOIB_QPN(daddr));
 			ipoib_neigh_put(neigh);
-			return;
+			return NULL;
 		}
 	} else {
 		neigh->ah  = NULL;
 
 		if (!path->query && path_rec_start(dev, path))
 			goto err_path;
-		if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)
+		if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+			push_pseudo_header(skb, neigh->daddr);
 			__skb_queue_tail(&neigh->queue, skb);
-		else
+		} else {
 			goto err_drop;
+		}
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 	ipoib_neigh_put(neigh);
-	return;
+	return NULL;
 
 err_path:
 	ipoib_neigh_free(neigh);
@@ -886,10 +947,12 @@
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 	ipoib_neigh_put(neigh);
+
+	return NULL;
 }
 
 static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
-			     struct ipoib_cb *cb)
+			     struct ipoib_pseudo_header *phdr)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_path *path;
@@ -897,16 +960,17 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	path = __path_find(dev, cb->hwaddr + 4);
+	path = __path_find(dev, phdr->hwaddr + 4);
 	if (!path || !path->valid) {
 		int new_path = 0;
 
 		if (!path) {
-			path = path_rec_create(dev, cb->hwaddr + 4);
+			path = path_rec_create(dev, phdr->hwaddr + 4);
 			new_path = 1;
 		}
 		if (path) {
 			if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+				push_pseudo_header(skb, phdr->hwaddr);
 				__skb_queue_tail(&path->queue, skb);
 			} else {
 				++dev->stats.tx_dropped;
@@ -934,10 +998,11 @@
 			  be16_to_cpu(path->pathrec.dlid));
 
 		spin_unlock_irqrestore(&priv->lock, flags);
-		ipoib_send(dev, skb, path->ah, IPOIB_QPN(cb->hwaddr));
+		ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr));
 		return;
 	} else if ((path->query || !path_rec_start(dev, path)) &&
 		   skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+		push_pseudo_header(skb, phdr->hwaddr);
 		__skb_queue_tail(&path->queue, skb);
 	} else {
 		++dev->stats.tx_dropped;
@@ -951,13 +1016,15 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_neigh *neigh;
-	struct ipoib_cb *cb = ipoib_skb_cb(skb);
+	struct ipoib_pseudo_header *phdr;
 	struct ipoib_header *header;
 	unsigned long flags;
 
+	phdr = (struct ipoib_pseudo_header *) skb->data;
+	skb_pull(skb, sizeof(*phdr));
 	header = (struct ipoib_header *) skb->data;
 
-	if (unlikely(cb->hwaddr[4] == 0xff)) {
+	if (unlikely(phdr->hwaddr[4] == 0xff)) {
 		/* multicast, arrange "if" according to probability */
 		if ((header->proto != htons(ETH_P_IP)) &&
 		    (header->proto != htons(ETH_P_IPV6)) &&
@@ -970,13 +1037,13 @@
 			return NETDEV_TX_OK;
 		}
 		/* Add in the P_Key for multicast*/
-		cb->hwaddr[8] = (priv->pkey >> 8) & 0xff;
-		cb->hwaddr[9] = priv->pkey & 0xff;
+		phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
+		phdr->hwaddr[9] = priv->pkey & 0xff;
 
-		neigh = ipoib_neigh_get(dev, cb->hwaddr);
+		neigh = ipoib_neigh_get(dev, phdr->hwaddr);
 		if (likely(neigh))
 			goto send_using_neigh;
-		ipoib_mcast_send(dev, cb->hwaddr, skb);
+		ipoib_mcast_send(dev, phdr->hwaddr, skb);
 		return NETDEV_TX_OK;
 	}
 
@@ -985,16 +1052,17 @@
 	case htons(ETH_P_IP):
 	case htons(ETH_P_IPV6):
 	case htons(ETH_P_TIPC):
-		neigh = ipoib_neigh_get(dev, cb->hwaddr);
+		neigh = ipoib_neigh_get(dev, phdr->hwaddr);
 		if (unlikely(!neigh)) {
-			neigh_add_path(skb, cb->hwaddr, dev);
-			return NETDEV_TX_OK;
+			neigh = neigh_add_path(skb, phdr->hwaddr, dev);
+			if (likely(!neigh))
+				return NETDEV_TX_OK;
 		}
 		break;
 	case htons(ETH_P_ARP):
 	case htons(ETH_P_RARP):
 		/* for unicast ARP and RARP should always perform path find */
-		unicast_arp_send(skb, dev, cb);
+		unicast_arp_send(skb, dev, phdr);
 		return NETDEV_TX_OK;
 	default:
 		/* ethertype not supported by IPoIB */
@@ -1011,11 +1079,12 @@
 			goto unref;
 		}
 	} else if (neigh->ah) {
-		ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(cb->hwaddr));
+		ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(phdr->hwaddr));
 		goto unref;
 	}
 
 	if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+		push_pseudo_header(skb, phdr->hwaddr);
 		spin_lock_irqsave(&priv->lock, flags);
 		__skb_queue_tail(&neigh->queue, skb);
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -1048,7 +1117,6 @@
 			     const void *daddr, const void *saddr, unsigned len)
 {
 	struct ipoib_header *header;
-	struct ipoib_cb *cb = ipoib_skb_cb(skb);
 
 	header = (struct ipoib_header *) skb_push(skb, sizeof *header);
 
@@ -1057,12 +1125,12 @@
 
 	/*
 	 * we don't rely on dst_entry structure,  always stuff the
-	 * destination address into skb->cb so we can figure out where
+	 * destination address into skb hard header so we can figure out where
 	 * to send the packet later.
 	 */
-	memcpy(cb->hwaddr, daddr, INFINIBAND_ALEN);
+	push_pseudo_header(skb, daddr);
 
-	return sizeof *header;
+	return IPOIB_HARD_LEN;
 }
 
 static void ipoib_set_mcast_list(struct net_device *dev)
@@ -1131,7 +1199,9 @@
 				neigh = NULL;
 				goto out_unlock;
 			}
-			neigh->alive = jiffies;
+
+			if (likely(skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE))
+				neigh->alive = jiffies;
 			goto out_unlock;
 		}
 	}
@@ -1196,7 +1266,7 @@
 						   rcu_dereference_protected(neigh->hnext,
 									     lockdep_is_held(&priv->lock)));
 				/* remove from path/mc list */
-				list_del(&neigh->list);
+				list_del_init(&neigh->list);
 				call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
 			} else {
 				np = &neigh->hnext;
@@ -1363,7 +1433,7 @@
 					   rcu_dereference_protected(neigh->hnext,
 								     lockdep_is_held(&priv->lock)));
 			/* remove from parent list */
-			list_del(&neigh->list);
+			list_del_init(&neigh->list);
 			call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
 			return;
 		} else {
@@ -1448,7 +1518,7 @@
 						   rcu_dereference_protected(neigh->hnext,
 									     lockdep_is_held(&priv->lock)));
 				/* remove from parent list */
-				list_del(&neigh->list);
+				list_del_init(&neigh->list);
 				call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
 			} else {
 				np = &neigh->hnext;
@@ -1490,7 +1560,7 @@
 					   rcu_dereference_protected(neigh->hnext,
 								     lockdep_is_held(&priv->lock)));
 			/* remove from path/mc list */
-			list_del(&neigh->list);
+			list_del_init(&neigh->list);
 			call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
 		}
 	}
@@ -1579,8 +1649,6 @@
 
 	ASSERT_RTNL();
 
-	ipoib_delete_debug_files(dev);
-
 	/* Delete any child interfaces first */
 	list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) {
 		/* Stop GC on child */
@@ -1636,7 +1704,7 @@
 
 	dev->flags		|= IFF_BROADCAST | IFF_MULTICAST;
 
-	dev->hard_header_len	 = IPOIB_ENCAP_LEN;
+	dev->hard_header_len	 = IPOIB_HARD_LEN;
 	dev->addr_len		 = INFINIBAND_ALEN;
 	dev->type		 = ARPHRD_INFINIBAND;
 	dev->tx_queue_len	 = ipoib_sendq_size * 2;
@@ -1885,6 +1953,9 @@
 		goto event_failed;
 	}
 
+	/* call event handler to ensure pkey in sync */
+	queue_work(ipoib_workqueue, &priv->flush_heavy);
+
 	result = register_netdev(priv->dev);
 	if (result) {
 		printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n",
@@ -1892,8 +1963,6 @@
 		goto register_failed;
 	}
 
-	ipoib_create_debug_files(priv->dev);
-
 	if (ipoib_cm_add_mode_attr(priv->dev))
 		goto sysfs_failed;
 	if (ipoib_add_pkey_attr(priv->dev))
@@ -1908,7 +1977,6 @@
 	return priv->dev;
 
 sysfs_failed:
-	ipoib_delete_debug_files(priv->dev);
 	unregister_netdev(priv->dev);
 
 register_failed:
@@ -1990,6 +2058,12 @@
 	kfree(dev_list);
 }
 
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+static struct notifier_block ipoib_netdev_notifier = {
+	.notifier_call = ipoib_netdev_event,
+};
+#endif
+
 static int __init ipoib_init_module(void)
 {
 	int ret;
@@ -2041,6 +2115,9 @@
 	if (ret)
 		goto err_client;
 
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+	register_netdevice_notifier(&ipoib_netdev_notifier);
+#endif
 	return 0;
 
 err_client:
@@ -2058,6 +2135,9 @@
 
 static void __exit ipoib_cleanup_module(void)
 {
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+	unregister_netdevice_notifier(&ipoib_netdev_notifier);
+#endif
 	ipoib_netlink_fini();
 	ib_unregister_client(&ipoib_client);
 	ib_sa_unregister_client(&ipoib_sa_client);
--- linux-4.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ linux-4.4.0/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -456,7 +456,10 @@
 	return status;
 }
 
-static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
+/*
+ * Caller must hold 'priv->lock'
+ */
+static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ib_sa_multicast *multicast;
@@ -466,6 +469,13 @@
 	ib_sa_comp_mask comp_mask;
 	int ret = 0;
 
+	if (!priv->broadcast ||
+	    !test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
+		return -EINVAL;
+
+	init_completion(&mcast->done);
+	set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+
 	ipoib_dbg_mcast(priv, "joining MGID %pI6\n", mcast->mcmember.mgid.raw);
 
 	rec.mgid     = mcast->mcmember.mgid;
@@ -525,20 +535,23 @@
 			rec.join_state = 4;
 #endif
 	}
+	spin_unlock_irq(&priv->lock);
 
 	multicast = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
 					 &rec, comp_mask, GFP_KERNEL,
 					 ipoib_mcast_join_complete, mcast);
+	spin_lock_irq(&priv->lock);
 	if (IS_ERR(multicast)) {
 		ret = PTR_ERR(multicast);
 		ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret);
-		spin_lock_irq(&priv->lock);
 		/* Requeue this join task with a backoff delay */
 		__ipoib_mcast_schedule_join_thread(priv, mcast, 1);
 		clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
 		spin_unlock_irq(&priv->lock);
 		complete(&mcast->done);
+		spin_lock_irq(&priv->lock);
 	}
+	return 0;
 }
 
 void ipoib_mcast_join_task(struct work_struct *work)
@@ -553,8 +566,11 @@
 	if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
 		return;
 
-	if (ib_query_port(priv->ca, priv->port, &port_attr) ||
-	    port_attr.state != IB_PORT_ACTIVE) {
+	if (ib_query_port(priv->ca, priv->port, &port_attr)) {
+		ipoib_dbg(priv, "ib_query_port() failed\n");
+		return;
+	}
+	if (port_attr.state != IB_PORT_ACTIVE) {
 		ipoib_dbg(priv, "port state is not ACTIVE (state = %d) suspending join task\n",
 			  port_attr.state);
 		return;
@@ -618,11 +634,10 @@
 			if (mcast->backoff == 1 ||
 			    time_after_eq(jiffies, mcast->delay_until)) {
 				/* Found the next unjoined group */
-				init_completion(&mcast->done);
-				set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
-				spin_unlock_irq(&priv->lock);
-				ipoib_mcast_join(dev, mcast);
-				spin_lock_irq(&priv->lock);
+				if (ipoib_mcast_join(dev, mcast)) {
+					spin_unlock_irq(&priv->lock);
+					return;
+				}
 			} else if (!delay_until ||
 				 time_before(mcast->delay_until, delay_until))
 				delay_until = mcast->delay_until;
@@ -638,13 +653,10 @@
 		queue_delayed_work(priv->wq, &priv->mcast_task,
 				   delay_until - jiffies);
 	}
-	if (mcast) {
-		init_completion(&mcast->done);
-		set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
-	}
-	spin_unlock_irq(&priv->lock);
 	if (mcast)
 		ipoib_mcast_join(dev, mcast);
+
+	spin_unlock_irq(&priv->lock);
 }
 
 int ipoib_mcast_start_thread(struct net_device *dev)
@@ -743,9 +755,11 @@
 			__ipoib_mcast_add(dev, mcast);
 			list_add_tail(&mcast->list, &priv->multicast_list);
 		}
-		if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
+		if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE) {
+			/* put pseudoheader back on for next time */
+			skb_push(skb, sizeof(struct ipoib_pseudo_header));
 			skb_queue_tail(&mcast->pkt_queue, skb);
-		else {
+		} else {
 			++dev->stats.tx_dropped;
 			dev_kfree_skb_any(skb);
 		}
@@ -760,7 +774,10 @@
 		spin_lock_irqsave(&priv->lock, flags);
 		if (!neigh) {
 			neigh = ipoib_neigh_alloc(daddr, dev);
-			if (neigh) {
+			/* Make sure that the neigh will be added only
+			 * once to mcast list.
+			 */
+			if (neigh && list_empty(&neigh->list)) {
 				kref_get(&mcast->ah->ref);
 				neigh->ah	= mcast->ah;
 				list_add_tail(&neigh->list, &mcast->neigh_list);
--- linux-4.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ linux-4.4.0/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -85,8 +85,6 @@
 		goto register_failed;
 	}
 
-	ipoib_create_debug_files(priv->dev);
-
 	/* RTNL childs don't need proprietary sysfs entries */
 	if (type == IPOIB_LEGACY_CHILD) {
 		if (ipoib_cm_add_mode_attr(priv->dev))
@@ -107,7 +105,6 @@
 
 sysfs_failed:
 	result = -ENOMEM;
-	ipoib_delete_debug_files(priv->dev);
 	unregister_netdevice(priv->dev);
 
 register_failed:
@@ -163,11 +160,11 @@
 out:
 	up_write(&ppriv->vlan_rwsem);
 
+	rtnl_unlock();
+
 	if (result)
 		free_netdev(priv->dev);
 
-	rtnl_unlock();
-
 	return result;
 }
 
@@ -188,7 +185,6 @@
 	list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
 		if (priv->pkey == pkey &&
 		    priv->child_type == IPOIB_LEGACY_CHILD) {
-			unregister_netdevice(priv->dev);
 			list_del(&priv->list);
 			dev = priv->dev;
 			break;
@@ -196,6 +192,11 @@
 	}
 	up_write(&ppriv->vlan_rwsem);
 
+	if (dev) {
+		ipoib_dbg(ppriv, "delete child vlan %s\n", dev->name);
+		unregister_netdevice(dev);
+	}
+
 	rtnl_unlock();
 
 	if (dev) {
--- linux-4.4.0.orig/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ linux-4.4.0/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -646,6 +646,7 @@
 		if (ib_conn->pi_support) {
 			u32 sig_caps = ib_conn->device->dev_attr.sig_prot_cap;
 
+			shost->sg_prot_tablesize = shost->sg_tablesize;
 			scsi_host_set_prot(shost, iser_dif_prot_caps(sig_caps));
 			scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP |
 						   SHOST_DIX_GUARD_CRC);
--- linux-4.4.0.orig/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ linux-4.4.0/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -450,6 +450,7 @@
 	struct list_head		  list;
 	struct iser_reg_resources	  rsc;
 	struct iser_pi_context		 *pi_ctx;
+	struct list_head                  all_list;
 };
 
 /**
@@ -463,6 +464,7 @@
 	struct list_head        list;
 	spinlock_t              lock;
 	int                     size;
+	struct list_head        all_list;
 };
 
 /**
--- linux-4.4.0.orig/drivers/infiniband/ulp/iser/iser_verbs.c
+++ linux-4.4.0/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -405,6 +405,7 @@
 	int i, ret;
 
 	INIT_LIST_HEAD(&fr_pool->list);
+	INIT_LIST_HEAD(&fr_pool->all_list);
 	spin_lock_init(&fr_pool->lock);
 	fr_pool->size = 0;
 	for (i = 0; i < cmds_max; i++) {
@@ -416,6 +417,7 @@
 		}
 
 		list_add_tail(&desc->list, &fr_pool->list);
+		list_add_tail(&desc->all_list, &fr_pool->all_list);
 		fr_pool->size++;
 	}
 
@@ -435,13 +437,13 @@
 	struct iser_fr_desc *desc, *tmp;
 	int i = 0;
 
-	if (list_empty(&fr_pool->list))
+	if (list_empty(&fr_pool->all_list))
 		return;
 
 	iser_info("freeing conn %p fr pool\n", ib_conn);
 
-	list_for_each_entry_safe(desc, tmp, &fr_pool->list, list) {
-		list_del(&desc->list);
+	list_for_each_entry_safe(desc, tmp, &fr_pool->all_list, all_list) {
+		list_del(&desc->all_list);
 		iser_free_reg_res(&desc->rsc);
 		if (desc->pi_ctx)
 			iser_free_pi_ctx(desc->pi_ctx);
@@ -1287,7 +1289,9 @@
 					 IB_MR_CHECK_SIG_STATUS, &mr_status);
 		if (ret) {
 			pr_err("ib_check_mr_status failed, ret %d\n", ret);
-			goto err;
+			/* Not a lot we can do, return ambiguous guard error */
+			*sector = 0;
+			return 0x1;
 		}
 
 		if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) {
@@ -1315,7 +1319,4 @@
 	}
 
 	return 0;
-err:
-	/* Not alot we can do here, return ambiguous guard error */
-	return 0x1;
 }
--- linux-4.4.0.orig/drivers/infiniband/ulp/isert/ib_isert.c
+++ linux-4.4.0/drivers/infiniband/ulp/isert/ib_isert.c
@@ -66,6 +66,7 @@
 struct rdma_cm_id *isert_setup_id(struct isert_np *isert_np);
 
 static void isert_release_work(struct work_struct *work);
+static void isert_wait4flush(struct isert_conn *isert_conn);
 
 static inline bool
 isert_prot_cmd(struct isert_conn *conn, struct se_cmd *cmd)
@@ -815,12 +816,31 @@
 	kref_put(&isert_conn->kref, isert_release_kref);
 }
 
+static void
+isert_handle_unbound_conn(struct isert_conn *isert_conn)
+{
+	struct isert_np *isert_np = isert_conn->cm_id->context;
+
+	mutex_lock(&isert_np->mutex);
+	if (!list_empty(&isert_conn->node)) {
+		/*
+		 * This means iscsi doesn't know this connection
+		 * so schedule a cleanup ourselves
+		 */
+		list_del_init(&isert_conn->node);
+		isert_put_conn(isert_conn);
+		complete(&isert_conn->wait);
+		queue_work(isert_release_wq, &isert_conn->release_work);
+	}
+	mutex_unlock(&isert_np->mutex);
+}
+
 /**
  * isert_conn_terminate() - Initiate connection termination
  * @isert_conn: isert connection struct
  *
  * Notes:
- * In case the connection state is FULL_FEATURE, move state
+ * In case the connection state is BOUND, move state
  * to TEMINATING and start teardown sequence (rdma_disconnect).
  * In case the connection state is UP, complete flush as well.
  *
@@ -832,23 +852,19 @@
 {
 	int err;
 
-	switch (isert_conn->state) {
-	case ISER_CONN_TERMINATING:
-		break;
-	case ISER_CONN_UP:
-	case ISER_CONN_FULL_FEATURE: /* FALLTHRU */
-		isert_info("Terminating conn %p state %d\n",
-			   isert_conn, isert_conn->state);
-		isert_conn->state = ISER_CONN_TERMINATING;
-		err = rdma_disconnect(isert_conn->cm_id);
-		if (err)
-			isert_warn("Failed rdma_disconnect isert_conn %p\n",
-				   isert_conn);
-		break;
-	default:
-		isert_warn("conn %p teminating in state %d\n",
-			   isert_conn, isert_conn->state);
-	}
+	if (isert_conn->state >= ISER_CONN_TERMINATING)
+		return;
+
+	isert_info("Terminating conn %p state %d\n",
+		   isert_conn, isert_conn->state);
+	isert_conn->state = ISER_CONN_TERMINATING;
+	err = rdma_disconnect(isert_conn->cm_id);
+	if (err)
+		isert_warn("Failed rdma_disconnect isert_conn %p\n",
+			   isert_conn);
+
+	isert_info("conn %p completing wait\n", isert_conn);
+	complete(&isert_conn->wait);
 }
 
 static int
@@ -882,35 +898,27 @@
 isert_disconnected_handler(struct rdma_cm_id *cma_id,
 			   enum rdma_cm_event_type event)
 {
-	struct isert_np *isert_np = cma_id->context;
-	struct isert_conn *isert_conn;
-	bool terminating = false;
-
-	if (isert_np->cm_id == cma_id)
-		return isert_np_cma_handler(cma_id->context, event);
-
-	isert_conn = cma_id->qp->qp_context;
+	struct isert_conn *isert_conn = cma_id->qp->qp_context;
 
 	mutex_lock(&isert_conn->mutex);
-	terminating = (isert_conn->state == ISER_CONN_TERMINATING);
-	isert_conn_terminate(isert_conn);
-	mutex_unlock(&isert_conn->mutex);
-
-	isert_info("conn %p completing wait\n", isert_conn);
-	complete(&isert_conn->wait);
-
-	if (terminating)
-		goto out;
-
-	mutex_lock(&isert_np->mutex);
-	if (!list_empty(&isert_conn->node)) {
-		list_del_init(&isert_conn->node);
-		isert_put_conn(isert_conn);
-		queue_work(isert_release_wq, &isert_conn->release_work);
+	switch (isert_conn->state) {
+	case ISER_CONN_TERMINATING:
+		break;
+	case ISER_CONN_UP:
+		isert_conn_terminate(isert_conn);
+		isert_wait4flush(isert_conn);
+		isert_handle_unbound_conn(isert_conn);
+		break;
+	case ISER_CONN_BOUND:
+	case ISER_CONN_FULL_FEATURE: /* FALLTHRU */
+		iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
+		break;
+	default:
+		isert_warn("conn %p teminating in state %d\n",
+			   isert_conn, isert_conn->state);
 	}
-	mutex_unlock(&isert_np->mutex);
+	mutex_unlock(&isert_conn->mutex);
 
-out:
 	return 0;
 }
 
@@ -929,12 +937,16 @@
 static int
 isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 {
+	struct isert_np *isert_np = cma_id->context;
 	int ret = 0;
 
 	isert_info("%s (%d): status %d id %p np %p\n",
 		   rdma_event_msg(event->event), event->event,
 		   event->status, cma_id, cma_id->context);
 
+	if (isert_np->cm_id == cma_id)
+		return isert_np_cma_handler(cma_id->context, event->event);
+
 	switch (event->event) {
 	case RDMA_CM_EVENT_CONNECT_REQUEST:
 		ret = isert_connect_request(cma_id, event);
@@ -980,13 +992,10 @@
 	rx_wr--;
 	rx_wr->next = NULL; /* mark end of work requests list */
 
-	isert_conn->post_recv_buf_count += count;
 	ret = ib_post_recv(isert_conn->qp, isert_conn->rx_wr,
 			   &rx_wr_failed);
-	if (ret) {
+	if (ret)
 		isert_err("ib_post_recv() failed with ret: %d\n", ret);
-		isert_conn->post_recv_buf_count -= count;
-	}
 
 	return ret;
 }
@@ -1002,12 +1011,9 @@
 	rx_wr.num_sge = 1;
 	rx_wr.next = NULL;
 
-	isert_conn->post_recv_buf_count++;
 	ret = ib_post_recv(isert_conn->qp, &rx_wr, &rx_wr_failed);
-	if (ret) {
+	if (ret)
 		isert_err("ib_post_recv() failed with ret: %d\n", ret);
-		isert_conn->post_recv_buf_count--;
-	}
 
 	return ret;
 }
@@ -1120,12 +1126,9 @@
 	rx_wr.sg_list = &sge;
 	rx_wr.num_sge = 1;
 
-	isert_conn->post_recv_buf_count++;
 	ret = ib_post_recv(isert_conn->qp, &rx_wr, &rx_wr_fail);
-	if (ret) {
+	if (ret)
 		isert_err("ib_post_recv() failed: %d\n", ret);
-		isert_conn->post_recv_buf_count--;
-	}
 
 	return ret;
 }
@@ -1578,7 +1581,7 @@
 		     struct isert_conn *isert_conn,
 		     u32 xfer_len)
 {
-	struct ib_device *ib_dev = isert_conn->cm_id->device;
+	struct ib_device *ib_dev = isert_conn->device->ib_device;
 	struct iscsi_hdr *hdr;
 	u64 rx_dma;
 	int rx_buflen;
@@ -1620,7 +1623,6 @@
 	ib_dma_sync_single_for_device(ib_dev, rx_dma, rx_buflen,
 				      DMA_FROM_DEVICE);
 
-	isert_conn->post_recv_buf_count--;
 }
 
 static int
@@ -2035,7 +2037,8 @@
 	void *start = isert_conn->rx_descs;
 	int len = ISERT_QP_MAX_RECV_DTOS * sizeof(*isert_conn->rx_descs);
 
-	if (wr_id >= start && wr_id < start + len)
+	if ((wr_id >= start && wr_id < start + len) ||
+	    (wr_id == isert_conn->login_req_buf))
 		return false;
 
 	return true;
@@ -2059,10 +2062,6 @@
 			isert_unmap_tx_desc(desc, ib_dev);
 		else
 			isert_completion_put(desc, isert_cmd, ib_dev, true);
-	} else {
-		isert_conn->post_recv_buf_count--;
-		if (!isert_conn->post_recv_buf_count)
-			iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
 	}
 }
 
@@ -3193,6 +3192,7 @@
 
 	conn->context = isert_conn;
 	isert_conn->conn = conn;
+	isert_conn->state = ISER_CONN_BOUND;
 
 	isert_set_conn_info(np, conn, isert_conn);
 
@@ -3278,17 +3278,6 @@
 }
 
 static void
-isert_wait4cmds(struct iscsi_conn *conn)
-{
-	isert_info("iscsi_conn %p\n", conn);
-
-	if (conn->sess) {
-		target_sess_cmd_list_set_waiting(conn->sess->se_sess);
-		target_wait_for_sess_cmds(conn->sess->se_sess);
-	}
-}
-
-static void
 isert_wait4flush(struct isert_conn *isert_conn)
 {
 	struct ib_recv_wr *bad_wr;
@@ -3306,6 +3295,17 @@
 	wait_for_completion(&isert_conn->wait_comp_err);
 }
 
+static void
+isert_wait4cmds(struct iscsi_conn *conn)
+{
+	isert_info("iscsi_conn %p\n", conn);
+
+	if (conn->sess) {
+		target_sess_cmd_list_set_waiting(conn->sess->se_sess);
+		target_wait_for_sess_cmds(conn->sess->se_sess);
+	}
+}
+
 /**
  * isert_put_unsol_pending_cmds() - Drop commands waiting for
  *     unsolicitate dataout
--- linux-4.4.0.orig/drivers/infiniband/ulp/isert/ib_isert.h
+++ linux-4.4.0/drivers/infiniband/ulp/isert/ib_isert.h
@@ -50,6 +50,7 @@
 enum iser_conn_state {
 	ISER_CONN_INIT,
 	ISER_CONN_UP,
+	ISER_CONN_BOUND,
 	ISER_CONN_FULL_FEATURE,
 	ISER_CONN_TERMINATING,
 	ISER_CONN_DOWN,
@@ -144,7 +145,6 @@
 
 struct isert_conn {
 	enum iser_conn_state	state;
-	int			post_recv_buf_count;
 	u32			responder_resources;
 	u32			initiator_depth;
 	bool			pi_support;
--- linux-4.4.0.orig/drivers/infiniband/ulp/srp/ib_srp.c
+++ linux-4.4.0/drivers/infiniband/ulp/srp/ib_srp.c
@@ -670,12 +670,19 @@
 static int srp_lookup_path(struct srp_rdma_ch *ch)
 {
 	struct srp_target_port *target = ch->target;
-	int ret;
+	int ret = -ENODEV;
 
 	ch->path.numb_path = 1;
 
 	init_completion(&ch->done);
 
+	/*
+	 * Avoid that the SCSI host can be removed by srp_remove_target()
+	 * before srp_path_rec_completion() is called.
+	 */
+	if (!scsi_host_get(target->scsi_host))
+		goto out;
+
 	ch->path_query_id = ib_sa_path_rec_get(&srp_sa_client,
 					       target->srp_host->srp_dev->dev,
 					       target->srp_host->port,
@@ -689,18 +696,24 @@
 					       GFP_KERNEL,
 					       srp_path_rec_completion,
 					       ch, &ch->path_query);
-	if (ch->path_query_id < 0)
-		return ch->path_query_id;
+	ret = ch->path_query_id;
+	if (ret < 0)
+		goto put;
 
 	ret = wait_for_completion_interruptible(&ch->done);
 	if (ret < 0)
-		return ret;
+		goto put;
 
-	if (ch->status < 0)
+	ret = ch->status;
+	if (ret < 0)
 		shost_printk(KERN_WARNING, target->scsi_host,
 			     PFX "Path record query failed\n");
 
-	return ch->status;
+put:
+	scsi_host_put(target->scsi_host);
+
+out:
+	return ret;
 }
 
 static int srp_send_req(struct srp_rdma_ch *ch, bool multich)
@@ -1519,7 +1532,7 @@
 
 	if (dev->use_fast_reg) {
 		state.sg = idb_sg;
-		sg_set_buf(idb_sg, req->indirect_desc, idb_len);
+		sg_init_one(idb_sg, req->indirect_desc, idb_len);
 		idb_sg->dma_address = req->indirect_dma_addr; /* hack! */
 #ifdef CONFIG_NEED_SG_DMA_LENGTH
 		idb_sg->dma_length = idb_sg->length;	      /* hack^2 */
@@ -1787,17 +1800,24 @@
 	if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) {
 		spin_lock_irqsave(&ch->lock, flags);
 		ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
+		if (rsp->tag == ch->tsk_mgmt_tag) {
+			ch->tsk_mgmt_status = -1;
+			if (be32_to_cpu(rsp->resp_data_len) >= 4)
+				ch->tsk_mgmt_status = rsp->data[3];
+			complete(&ch->tsk_mgmt_done);
+		} else {
+			shost_printk(KERN_ERR, target->scsi_host,
+				     "Received tsk mgmt response too late for tag %#llx\n",
+				     rsp->tag);
+		}
 		spin_unlock_irqrestore(&ch->lock, flags);
-
-		ch->tsk_mgmt_status = -1;
-		if (be32_to_cpu(rsp->resp_data_len) >= 4)
-			ch->tsk_mgmt_status = rsp->data[3];
-		complete(&ch->tsk_mgmt_done);
 	} else {
 		scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag);
-		if (scmnd) {
+		if (scmnd && scmnd->host_scribble) {
 			req = (void *)scmnd->host_scribble;
 			scmnd = srp_claim_req(ch, req, NULL, scmnd);
+		} else {
+			scmnd = NULL;
 		}
 		if (!scmnd) {
 			shost_printk(KERN_ERR, target->scsi_host,
@@ -2115,6 +2135,7 @@
 
 	if (srp_post_send(ch, iu, len)) {
 		shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
+		scmnd->result = DID_ERROR << 16;
 		goto err_unmap;
 	}
 
@@ -2469,19 +2490,18 @@
 }
 
 static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun,
-			     u8 func)
+			     u8 func, u8 *status)
 {
 	struct srp_target_port *target = ch->target;
 	struct srp_rport *rport = target->rport;
 	struct ib_device *dev = target->srp_host->srp_dev->dev;
 	struct srp_iu *iu;
 	struct srp_tsk_mgmt *tsk_mgmt;
+	int res;
 
 	if (!ch->connected || target->qp_in_error)
 		return -1;
 
-	init_completion(&ch->tsk_mgmt_done);
-
 	/*
 	 * Lock the rport mutex to avoid that srp_create_ch_ib() is
 	 * invoked while a task management function is being sent.
@@ -2504,10 +2524,16 @@
 
 	tsk_mgmt->opcode 	= SRP_TSK_MGMT;
 	int_to_scsilun(lun, &tsk_mgmt->lun);
-	tsk_mgmt->tag		= req_tag | SRP_TAG_TSK_MGMT;
 	tsk_mgmt->tsk_mgmt_func = func;
 	tsk_mgmt->task_tag	= req_tag;
 
+	spin_lock_irq(&ch->lock);
+	ch->tsk_mgmt_tag = (ch->tsk_mgmt_tag + 1) | SRP_TAG_TSK_MGMT;
+	tsk_mgmt->tag = ch->tsk_mgmt_tag;
+	spin_unlock_irq(&ch->lock);
+
+	init_completion(&ch->tsk_mgmt_done);
+
 	ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt,
 				      DMA_TO_DEVICE);
 	if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) {
@@ -2516,13 +2542,15 @@
 
 		return -1;
 	}
+	res = wait_for_completion_timeout(&ch->tsk_mgmt_done,
+					msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS));
+	if (res > 0 && status)
+		*status = ch->tsk_mgmt_status;
 	mutex_unlock(&rport->mutex);
 
-	if (!wait_for_completion_timeout(&ch->tsk_mgmt_done,
-					 msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)))
-		return -1;
+	WARN_ON_ONCE(res < 0);
 
-	return 0;
+	return res > 0 ? 0 : -1;
 }
 
 static int srp_abort(struct scsi_cmnd *scmnd)
@@ -2548,15 +2576,17 @@
 	shost_printk(KERN_ERR, target->scsi_host,
 		     "Sending SRP abort for tag %#x\n", tag);
 	if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun,
-			      SRP_TSK_ABORT_TASK) == 0)
+			      SRP_TSK_ABORT_TASK, NULL) == 0)
 		ret = SUCCESS;
 	else if (target->rport->state == SRP_RPORT_LOST)
 		ret = FAST_IO_FAIL;
 	else
 		ret = FAILED;
-	srp_free_req(ch, req, scmnd, 0);
-	scmnd->result = DID_ABORT << 16;
-	scmnd->scsi_done(scmnd);
+	if (ret == SUCCESS) {
+		srp_free_req(ch, req, scmnd, 0);
+		scmnd->result = DID_ABORT << 16;
+		scmnd->scsi_done(scmnd);
+	}
 
 	return ret;
 }
@@ -2565,26 +2595,17 @@
 {
 	struct srp_target_port *target = host_to_target(scmnd->device->host);
 	struct srp_rdma_ch *ch;
-	int i;
+	u8 status;
 
 	shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
 
 	ch = &target->ch[0];
 	if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun,
-			      SRP_TSK_LUN_RESET))
+			      SRP_TSK_LUN_RESET, &status))
 		return FAILED;
-	if (ch->tsk_mgmt_status)
+	if (status)
 		return FAILED;
 
-	for (i = 0; i < target->ch_count; i++) {
-		ch = &target->ch[i];
-		for (i = 0; i < target->req_ring_size; ++i) {
-			struct srp_request *req = &ch->req_ring[i];
-
-			srp_finish_req(ch, req, scmnd->device, DID_RESET << 16);
-		}
-	}
-
 	return SUCCESS;
 }
 
@@ -3281,12 +3302,10 @@
 				      num_online_nodes());
 		const int ch_end = ((node_idx + 1) * target->ch_count /
 				    num_online_nodes());
-		const int cv_start = (node_idx * ibdev->num_comp_vectors /
-				      num_online_nodes() + target->comp_vector)
-				     % ibdev->num_comp_vectors;
-		const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors /
-				    num_online_nodes() + target->comp_vector)
-				   % ibdev->num_comp_vectors;
+		const int cv_start = node_idx * ibdev->num_comp_vectors /
+				     num_online_nodes();
+		const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors /
+				   num_online_nodes();
 		int cpu_idx = 0;
 
 		for_each_online_cpu(cpu) {
--- linux-4.4.0.orig/drivers/infiniband/ulp/srp/ib_srp.h
+++ linux-4.4.0/drivers/infiniband/ulp/srp/ib_srp.h
@@ -168,6 +168,7 @@
 	int			max_ti_iu_len;
 	int			comp_vector;
 
+	u64			tsk_mgmt_tag;
 	struct completion	tsk_mgmt_done;
 	u8			tsk_mgmt_status;
 	bool			connected;
--- linux-4.4.0.orig/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ linux-4.4.0/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -453,6 +453,7 @@
  * srpt_mad_recv_handler() - MAD reception callback function.
  */
 static void srpt_mad_recv_handler(struct ib_mad_agent *mad_agent,
+				  struct ib_mad_send_buf *send_buf,
 				  struct ib_mad_recv_wc *mad_wc)
 {
 	struct srpt_port *sport = (struct srpt_port *)mad_agent->context;
@@ -957,8 +958,7 @@
 		return -ENOMEM;
 
 	attr->qp_state = IB_QPS_INIT;
-	attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ |
-	    IB_ACCESS_REMOTE_WRITE;
+	attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE;
 	attr->port_num = ch->sport->port;
 	attr->pkey_index = 0;
 
@@ -1514,9 +1514,11 @@
 			      struct srpt_send_ioctx *ioctx, u64 tag,
 			      int status)
 {
+	struct se_cmd *cmd = &ioctx->cmd;
 	struct srp_rsp *srp_rsp;
 	const u8 *sense_data;
 	int sense_data_len, max_sense_len;
+	u32 resid = cmd->residual_count;
 
 	/*
 	 * The lowest bit of all SAM-3 status codes is zero (see also
@@ -1538,6 +1540,28 @@
 	srp_rsp->tag = tag;
 	srp_rsp->status = status;
 
+	if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+		if (cmd->data_direction == DMA_TO_DEVICE) {
+			/* residual data from an underflow write */
+			srp_rsp->flags = SRP_RSP_FLAG_DOUNDER;
+			srp_rsp->data_out_res_cnt = cpu_to_be32(resid);
+		} else if (cmd->data_direction == DMA_FROM_DEVICE) {
+			/* residual data from an underflow read */
+			srp_rsp->flags = SRP_RSP_FLAG_DIUNDER;
+			srp_rsp->data_in_res_cnt = cpu_to_be32(resid);
+		}
+	} else if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+		if (cmd->data_direction == DMA_TO_DEVICE) {
+			/* residual data from an overflow write */
+			srp_rsp->flags = SRP_RSP_FLAG_DOOVER;
+			srp_rsp->data_out_res_cnt = cpu_to_be32(resid);
+		} else if (cmd->data_direction == DMA_FROM_DEVICE) {
+			/* residual data from an overflow read */
+			srp_rsp->flags = SRP_RSP_FLAG_DIOVER;
+			srp_rsp->data_in_res_cnt = cpu_to_be32(resid);
+		}
+	}
+
 	if (sense_data_len) {
 		BUILD_BUG_ON(MIN_MAX_RSP_SIZE <= sizeof(*srp_rsp));
 		max_sense_len = ch->max_ti_iu_len - sizeof(*srp_rsp);
@@ -1737,47 +1761,6 @@
 	return -1;
 }
 
-/**
- * srpt_rx_mgmt_fn_tag() - Process a task management function by tag.
- * @ch: RDMA channel of the task management request.
- * @fn: Task management function to perform.
- * @req_tag: Tag of the SRP task management request.
- * @mgmt_ioctx: I/O context of the task management request.
- *
- * Returns zero if the target core will process the task management
- * request asynchronously.
- *
- * Note: It is assumed that the initiator serializes tag-based task management
- * requests.
- */
-static int srpt_rx_mgmt_fn_tag(struct srpt_send_ioctx *ioctx, u64 tag)
-{
-	struct srpt_device *sdev;
-	struct srpt_rdma_ch *ch;
-	struct srpt_send_ioctx *target;
-	int ret, i;
-
-	ret = -EINVAL;
-	ch = ioctx->ch;
-	BUG_ON(!ch);
-	BUG_ON(!ch->sport);
-	sdev = ch->sport->sdev;
-	BUG_ON(!sdev);
-	spin_lock_irq(&sdev->spinlock);
-	for (i = 0; i < ch->rq_size; ++i) {
-		target = ch->ioctx_ring[i];
-		if (target->cmd.se_lun == ioctx->cmd.se_lun &&
-		    target->cmd.tag == tag &&
-		    srpt_get_cmd_state(target) != SRPT_STATE_DONE) {
-			ret = 0;
-			/* now let the target core abort &target->cmd; */
-			break;
-		}
-	}
-	spin_unlock_irq(&sdev->spinlock);
-	return ret;
-}
-
 static int srp_tmr_to_tcm(int fn)
 {
 	switch (fn) {
@@ -1812,7 +1795,6 @@
 	struct se_cmd *cmd;
 	struct se_session *sess = ch->sess;
 	uint64_t unpacked_lun;
-	uint32_t tag = 0;
 	int tcm_tmr;
 	int rc;
 
@@ -1828,25 +1810,10 @@
 	srpt_set_cmd_state(send_ioctx, SRPT_STATE_MGMT);
 	send_ioctx->cmd.tag = srp_tsk->tag;
 	tcm_tmr = srp_tmr_to_tcm(srp_tsk->tsk_mgmt_func);
-	if (tcm_tmr < 0) {
-		send_ioctx->cmd.se_tmr_req->response =
-			TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
-		goto fail;
-	}
 	unpacked_lun = srpt_unpack_lun((uint8_t *)&srp_tsk->lun,
 				       sizeof(srp_tsk->lun));
-
-	if (srp_tsk->tsk_mgmt_func == SRP_TSK_ABORT_TASK) {
-		rc = srpt_rx_mgmt_fn_tag(send_ioctx, srp_tsk->task_tag);
-		if (rc < 0) {
-			send_ioctx->cmd.se_tmr_req->response =
-					TMR_TASK_DOES_NOT_EXIST;
-			goto fail;
-		}
-		tag = srp_tsk->task_tag;
-	}
 	rc = target_submit_tmr(&send_ioctx->cmd, sess, NULL, unpacked_lun,
-				srp_tsk, tcm_tmr, GFP_KERNEL, tag,
+				srp_tsk, tcm_tmr, GFP_KERNEL, srp_tsk->task_tag,
 				TARGET_SCF_ACK_KREF);
 	if (rc != 0) {
 		send_ioctx->cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED;
@@ -3032,12 +2999,8 @@
 	}
 	spin_unlock_irqrestore(&ioctx->spinlock, flags);
 
-	if (unlikely(transport_check_aborted_status(&ioctx->cmd, false)
-		     || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) {
-		atomic_inc(&ch->req_lim_delta);
-		srpt_abort_cmd(ioctx);
+	if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT)))
 		return;
-	}
 
 	dir = ioctx->cmd.data_direction;
 
@@ -3482,7 +3445,7 @@
 {
 	const char *p;
 	unsigned len, count, leading_zero_bytes;
-	int ret, rc;
+	int ret;
 
 	p = name;
 	if (strncasecmp(p, "0x", 2) == 0)
@@ -3494,10 +3457,9 @@
 	count = min(len / 2, 16U);
 	leading_zero_bytes = 16 - count;
 	memset(i_port_id, 0, leading_zero_bytes);
-	rc = hex2bin(i_port_id + leading_zero_bytes, p, count);
-	if (rc < 0)
-		pr_debug("hex2bin failed for srpt_parse_i_port_id: %d\n", rc);
-	ret = 0;
+	ret = hex2bin(i_port_id + leading_zero_bytes, p, count);
+	if (ret < 0)
+		pr_debug("hex2bin failed for srpt_parse_i_port_id: %d\n", ret);
 out:
 	return ret;
 }
--- linux-4.4.0.orig/drivers/input/evdev.c
+++ linux-4.4.0/drivers/input/evdev.c
@@ -342,20 +342,6 @@
 	return fasync_helper(fd, file, on, &client->fasync);
 }
 
-static int evdev_flush(struct file *file, fl_owner_t id)
-{
-	struct evdev_client *client = file->private_data;
-	struct evdev *evdev = client->evdev;
-
-	mutex_lock(&evdev->mutex);
-
-	if (evdev->exist && !client->revoked)
-		input_flush_device(&evdev->handle, file);
-
-	mutex_unlock(&evdev->mutex);
-	return 0;
-}
-
 static void evdev_free(struct device *dev)
 {
 	struct evdev *evdev = container_of(dev, struct evdev, dev);
@@ -469,6 +455,10 @@
 	unsigned int i;
 
 	mutex_lock(&evdev->mutex);
+
+	if (evdev->exist && !client->revoked)
+		input_flush_device(&evdev->handle, file);
+
 	evdev_ungrab(evdev, client);
 	mutex_unlock(&evdev->mutex);
 
@@ -1331,7 +1321,6 @@
 	.compat_ioctl	= evdev_ioctl_compat,
 #endif
 	.fasync		= evdev_fasync,
-	.flush		= evdev_flush,
 	.llseek		= no_llseek,
 };
 
--- linux-4.4.0.orig/drivers/input/ff-core.c
+++ linux-4.4.0/drivers/input/ff-core.c
@@ -237,9 +237,15 @@
 EXPORT_SYMBOL_GPL(input_ff_erase);
 
 /*
- * flush_effects - erase all effects owned by a file handle
+ * input_ff_flush - erase all effects owned by a file handle
+ * @dev: input device to erase effect from
+ * @file: purported owner of the effects
+ *
+ * This function erases all force-feedback effects associated with
+ * the given owner from specified device. Note that @file may be %NULL,
+ * in which case all effects will be erased.
  */
-static int flush_effects(struct input_dev *dev, struct file *file)
+int input_ff_flush(struct input_dev *dev, struct file *file)
 {
 	struct ff_device *ff = dev->ff;
 	int i;
@@ -255,6 +261,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(input_ff_flush);
 
 /**
  * input_ff_event() - generic handler for force-feedback events
@@ -343,7 +350,7 @@
 	mutex_init(&ff->mutex);
 
 	dev->ff = ff;
-	dev->flush = flush_effects;
+	dev->flush = input_ff_flush;
 	dev->event = input_ff_event;
 	__set_bit(EV_FF, dev->evbit);
 
--- linux-4.4.0.orig/drivers/input/ff-memless.c
+++ linux-4.4.0/drivers/input/ff-memless.c
@@ -501,6 +501,15 @@
 {
 	struct ml_device *ml = ff->private;
 
+	/*
+	 * Even though we stop all playing effects when tearing down
+	 * an input device (via input_device_flush() that calls into
+	 * input_ff_flush() that stops and erases all effects), we
+	 * do not actually stop the timer, and therefore we should
+	 * do it here.
+	 */
+	del_timer_sync(&ml->timer);
+
 	kfree(ml->private);
 }
 
--- linux-4.4.0.orig/drivers/input/input-leds.c
+++ linux-4.4.0/drivers/input/input-leds.c
@@ -88,6 +88,7 @@
 			      const struct input_device_id *id)
 {
 	struct input_leds *leds;
+	struct input_led *led;
 	unsigned int num_leds;
 	unsigned int led_code;
 	int led_no;
@@ -119,14 +120,13 @@
 
 	led_no = 0;
 	for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
-		struct input_led *led = &leds->leds[led_no];
+		if (!input_led_info[led_code].name)
+			continue;
 
+		led = &leds->leds[led_no];
 		led->handle = &leds->handle;
 		led->code = led_code;
 
-		if (!input_led_info[led_code].name)
-			continue;
-
 		led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
 					   dev_name(&dev->dev),
 					   input_led_info[led_code].name);
--- linux-4.4.0.orig/drivers/input/input.c
+++ linux-4.4.0/drivers/input/input.c
@@ -50,6 +50,17 @@
 
 static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };
 
+static const unsigned int input_max_code[EV_CNT] = {
+	[EV_KEY] = KEY_MAX,
+	[EV_REL] = REL_MAX,
+	[EV_ABS] = ABS_MAX,
+	[EV_MSC] = MSC_MAX,
+	[EV_SW] = SW_MAX,
+	[EV_LED] = LED_MAX,
+	[EV_SND] = SND_MAX,
+	[EV_FF] = FF_MAX,
+};
+
 static inline int is_event_supported(unsigned int code,
 				     unsigned long *bm, unsigned int max)
 {
@@ -851,16 +862,18 @@
 		}
 	}
 
-	__clear_bit(*old_keycode, dev->keybit);
-	__set_bit(ke->keycode, dev->keybit);
-
-	for (i = 0; i < dev->keycodemax; i++) {
-		if (input_fetch_keycode(dev, i) == *old_keycode) {
-			__set_bit(*old_keycode, dev->keybit);
-			break; /* Setting the bit twice is useless, so break */
+	if (*old_keycode <= KEY_MAX) {
+		__clear_bit(*old_keycode, dev->keybit);
+		for (i = 0; i < dev->keycodemax; i++) {
+			if (input_fetch_keycode(dev, i) == *old_keycode) {
+				__set_bit(*old_keycode, dev->keybit);
+				/* Setting the bit twice is useless, so break */
+				break;
+			}
 		}
 	}
 
+	__set_bit(ke->keycode, dev->keybit);
 	return 0;
 }
 
@@ -916,9 +929,13 @@
 	 * Simulate keyup event if keycode is not present
 	 * in the keymap anymore
 	 */
-	if (test_bit(EV_KEY, dev->evbit) &&
-	    !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
-	    __test_and_clear_bit(old_keycode, dev->key)) {
+	if (old_keycode > KEY_MAX) {
+		dev_warn(dev->dev.parent ?: &dev->dev,
+			 "%s: got too big old keycode %#x\n",
+			 __func__, old_keycode);
+	} else if (test_bit(EV_KEY, dev->evbit) &&
+		   !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
+		   __test_and_clear_bit(old_keycode, dev->key)) {
 		struct input_value vals[] =  {
 			{ EV_KEY, old_keycode, 0 },
 			input_value_sync
@@ -1908,6 +1925,14 @@
  */
 void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
 {
+	if (type < EV_CNT && input_max_code[type] &&
+	    code > input_max_code[type]) {
+		pr_err("%s: invalid code %u for type %u\n", __func__, code,
+		       type);
+		dump_stack();
+		return;
+	}
+
 	switch (type) {
 	case EV_KEY:
 		__set_bit(code, dev->keybit);
--- linux-4.4.0.orig/drivers/input/joydev.c
+++ linux-4.4.0/drivers/input/joydev.c
@@ -448,7 +448,7 @@
 	if (IS_ERR(abspam))
 		return PTR_ERR(abspam);
 
-	for (i = 0; i < joydev->nabs; i++) {
+	for (i = 0; i < len && i < joydev->nabs; i++) {
 		if (abspam[i] > ABS_MAX) {
 			retval = -EINVAL;
 			goto out;
@@ -472,6 +472,9 @@
 	int i;
 	int retval = 0;
 
+	if (len % sizeof(*keypam))
+		return -EINVAL;
+
 	len = min(len, sizeof(joydev->keypam));
 
 	/* Validate the map. */
@@ -479,7 +482,7 @@
 	if (IS_ERR(keypam))
 		return PTR_ERR(keypam);
 
-	for (i = 0; i < joydev->nkey; i++) {
+	for (i = 0; i < (len / 2) && i < joydev->nkey; i++) {
 		if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
 			retval = -EINVAL;
 			goto out;
@@ -489,7 +492,7 @@
 	memcpy(joydev->keypam, keypam, len);
 
 	for (i = 0; i < joydev->nkey; i++)
-		joydev->keymap[keypam[i] - BTN_MISC] = i;
+		joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
 
  out:
 	kfree(keypam);
--- linux-4.4.0.orig/drivers/input/joystick/iforce/iforce-usb.c
+++ linux-4.4.0/drivers/input/joystick/iforce/iforce-usb.c
@@ -141,8 +141,16 @@
 
 	interface = intf->cur_altsetting;
 
+	if (interface->desc.bNumEndpoints < 2)
+		return -ENODEV;
+
 	epirq = &interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(epirq))
+		return -ENODEV;
+
 	epout = &interface->endpoint[1].desc;
+	if (!usb_endpoint_is_int_out(epout))
+		return -ENODEV;
 
 	if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL)))
 		goto fail;
--- linux-4.4.0.orig/drivers/input/joystick/xpad.c
+++ linux-4.4.0/drivers/input/joystick/xpad.c
@@ -76,18 +76,23 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/rcupdate.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/module.h>
 #include <linux/usb/input.h>
+#include <linux/usb/quirks.h>
 
 #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
 #define DRIVER_DESC "X-Box pad driver"
 
-#define XPAD_PKT_LEN 32
+#define XPAD_PKT_LEN 64
 
-/* xbox d-pads should map to buttons, as is required for DDR pads
-   but we map them to axes when possible to simplify things */
+/*
+ * xbox d-pads should map to buttons, as is required for DDR pads
+ * but we map them to axes when possible to simplify things
+ */
 #define MAP_DPAD_TO_BUTTONS		(1 << 0)
 #define MAP_TRIGGERS_TO_BUTTONS		(1 << 1)
 #define MAP_STICKS_TO_NULL		(1 << 2)
@@ -112,6 +117,10 @@
 module_param(sticks_to_null, bool, S_IRUGO);
 MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
 
+static bool auto_poweroff = true;
+module_param(auto_poweroff, bool, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(auto_poweroff, "Power off wireless controllers on suspend");
+
 static const struct xpad_device {
 	u16 idVendor;
 	u16 idProduct;
@@ -119,43 +128,77 @@
 	u8 mapping;
 	u8 xtype;
 } xpad_device[] = {
+	{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
+	{ 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
+	{ 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX },
+	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
+	{ 0x044f, 0x0f10, "Thrustmaster Modena GT Wheel", 0, XTYPE_XBOX },
+	{ 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 },
 	{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
 	{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
 	{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
+	{ 0x045e, 0x0288, "Microsoft Xbox Controller S v2", 0, XTYPE_XBOX },
 	{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
 	{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
-	{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
-	{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Covert Forces)", 0, XTYPE_XBOXONE },
+	{ 0x045e, 0x028f, "Microsoft X-Box 360 pad v2", 0, XTYPE_XBOX360 },
 	{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
+	{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
+	{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
+	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
+	{ 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
 	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
-	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
-	{ 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 },
 	{ 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 },
 	{ 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 },
 	{ 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 },
 	{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
 	{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
 	{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
+	{ 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX },
+	{ 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 },
+	{ 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 },
 	{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
 	{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
+	{ 0x05fe, 0x3030, "Chic Controller", 0, XTYPE_XBOX },
+	{ 0x05fe, 0x3031, "Chic Controller", 0, XTYPE_XBOX },
+	{ 0x062a, 0x0020, "Logic3 Xbox GamePad", 0, XTYPE_XBOX },
+	{ 0x062a, 0x0033, "Competition Pro Steering Wheel", 0, XTYPE_XBOX },
+	{ 0x06a3, 0x0200, "Saitek Racing Wheel", 0, XTYPE_XBOX },
+	{ 0x06a3, 0x0201, "Saitek Adrenalin", 0, XTYPE_XBOX },
+	{ 0x06a3, 0xf51a, "Saitek P3600", 0, XTYPE_XBOX360 },
+	{ 0x0738, 0x4506, "Mad Catz 4506 Wireless Controller", 0, XTYPE_XBOX },
 	{ 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX },
+	{ 0x0738, 0x4520, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
 	{ 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX },
 	{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
+	{ 0x0738, 0x4530, "Mad Catz Universal MC2 Racing Wheel and Pedals", 0, XTYPE_XBOX },
 	{ 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX },
 	{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
 	{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
+	{ 0x0738, 0x4586, "Mad Catz MicroCon Wireless Controller", 0, XTYPE_XBOX },
+	{ 0x0738, 0x4588, "Mad Catz Blaster", 0, XTYPE_XBOX },
+	{ 0x0738, 0x45ff, "Mad Catz Beat Pad (w/ Handle)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
 	{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
 	{ 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE", 0, XTYPE_XBOX360 },
 	{ 0x0738, 0x4726, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
 	{ 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x0738, 0x4736, "Mad Catz MicroCon Gamepad", 0, XTYPE_XBOX360 },
 	{ 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 },
+	{ 0x0738, 0x4743, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+	{ 0x0738, 0x4758, "Mad Catz Arcade Game Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x0738, 0x4a01, "Mad Catz FightStick TE 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
 	{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+	{ 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 },
 	{ 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 },
+	{ 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 },
 	{ 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 },
 	{ 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 },
+	{ 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 },
 	{ 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 },
+	{ 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 },
+	{ 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX },
+	{ 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX },
 	{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
 	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
 	{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
@@ -163,56 +206,149 @@
 	{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
 	{ 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
 	{ 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
+	{ 0x0e4c, 0x1103, "Radica Gamester Reflex", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX },
 	{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
+	{ 0x0e4c, 0x3510, "Radica Gamester", 0, XTYPE_XBOX },
 	{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
 	{ 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
 	{ 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
+	{ 0x0e6f, 0x0008, "After Glow Pro Controller", 0, XTYPE_XBOX },
 	{ 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0x011f, "Rock Candy Gamepad Wired Controller", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0x0131, "PDP EA Sports Controller", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0x0133, "Xbox 360 Wired Controller", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x013a, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x0164, "PDP Battlefield One", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x0165, "PDP Titanfall 2", 0, XTYPE_XBOXONE },
 	{ 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
 	{ 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
 	{ 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02a0, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02a1, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02a2, "PDP Wired Controller for Xbox One - Crimson Red", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02a6, "PDP Wired Controller for Xbox One - Camo Series", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02a7, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02a8, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02ad, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02b3, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
+	{ 0x0e6f, 0x02b8, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
 	{ 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE },
 	{ 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0x0413, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0x0501, "PDP Xbox 360 Controller", 0, XTYPE_XBOX360 },
+	{ 0x0e6f, 0xf900, "PDP Afterglow AX.1", 0, XTYPE_XBOX360 },
 	{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
 	{ 0x0e8f, 0x3008, "Generic xbox control (dealextreme)", 0, XTYPE_XBOX },
 	{ 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick", 0, XTYPE_XBOX360 },
+	{ 0x0f0d, 0x000c, "Hori PadEX Turbo", 0, XTYPE_XBOX360 },
 	{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x0f0d, 0x001b, "Hori Real Arcade Pro VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x0f0d, 0x0063, "Hori Real Arcade Pro Hayabusa (USA) Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
+	{ 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE },
+	{ 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
+	{ 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX },
 	{ 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
 	{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
 	{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
+	{ 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
+	{ 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
+	{ 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
+	{ 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 },
 	{ 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 },
+	{ 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
 	{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
 	{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+	{ 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 },
 	{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
 	{ 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 },
+	{ 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
+	{ 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
 	{ 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 },
 	{ 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
 	{ 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 },
 	{ 0x162e, 0xbeef, "Joytech Neo-Se Take2", 0, XTYPE_XBOX360 },
 	{ 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 },
 	{ 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 },
-	{ 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 },
+	{ 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf018, "Mad Catz Street Fighter IV SE Fighting Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf019, "Mad Catz Brawlstick for Xbox 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf021, "Mad Cats Ghost Recon FS GamePad", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0xf023, "MLG Pro Circuit Controller (Xbox)", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf025, "Mad Catz Call Of Duty", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf027, "Mad Catz FPS Pro", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf02e, "Mad Catz Fightpad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf030, "Mad Catz Xbox 360 MC2 MicroCon Racing Wheel", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf036, "Mad Catz MicroCon GamePad Pro", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0xf038, "Street Fighter IV FightStick TE", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf039, "Mad Catz MvC2 TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf03a, "Mad Catz SFxT Fightstick Pro", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf03d, "Street Fighter IV Arcade Stick TE - Chun Li", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf03e, "Mad Catz MLG FightStick TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf03f, "Mad Catz FightStick SoulCaliber", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf042, "Mad Catz FightStick TES+", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf080, "Mad Catz FightStick TE2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf501, "HoriPad EX2 Turbo", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf502, "Hori Real Arcade Pro.VX SA", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf503, "Hori Fighting Stick VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf504, "Hori Real Arcade Pro. EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf505, "Hori Fighting Stick EX2B", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf506, "Hori Real Arcade Pro.EX Premium VLX", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf904, "PDP Versus Fighting Pad", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xf906, "MortalKombat FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
+	{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
+	{ 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
+	{ 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
+	{ 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
+	{ 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
 	{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
 	{ 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0x530a, "Xbox 360 Pro EX Controller", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0x531a, "PowerA Pro Ex", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0x5397, "FUS1ON Tournament Controller", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0x541a, "PowerA Xbox One Mini Wired Controller", 0, XTYPE_XBOXONE },
+	{ 0x24c6, 0x542a, "Xbox ONE spectra", 0, XTYPE_XBOXONE },
+	{ 0x24c6, 0x543a, "PowerA Xbox One wired controller", 0, XTYPE_XBOXONE },
 	{ 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 },
 	{ 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE },
+	{ 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE },
+	{ 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
 	{ 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 },
 	{ 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 },
+	{ 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
+	{ 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX },
 	{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
 	{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
@@ -273,15 +409,15 @@
  * match against vendor id as well. Wired Xbox 360 devices have protocol 1,
  * wireless controllers have protocol 129.
  */
-#define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \
+#define XPAD_XBOX360_VENDOR_PROTOCOL(vend, pr) \
 	.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
 	.idVendor = (vend), \
 	.bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
 	.bInterfaceSubClass = 93, \
 	.bInterfaceProtocol = (pr)
 #define XPAD_XBOX360_VENDOR(vend) \
-	{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
-	{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
+	{ XPAD_XBOX360_VENDOR_PROTOCOL((vend), 1) }, \
+	{ XPAD_XBOX360_VENDOR_PROTOCOL((vend), 129) }
 
 /* The Xbox One controller uses subclass 71 and protocol 208. */
 #define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) \
@@ -291,47 +427,189 @@
 	.bInterfaceSubClass = 71, \
 	.bInterfaceProtocol = (pr)
 #define XPAD_XBOXONE_VENDOR(vend) \
-	{ XPAD_XBOXONE_VENDOR_PROTOCOL(vend, 208) }
+	{ XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) }
 
-static struct usb_device_id xpad_table[] = {
+static const struct usb_device_id xpad_table[] = {
 	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* X-Box USB-IF not approved class */
+	XPAD_XBOX360_VENDOR(0x0079),		/* GPD Win 2 Controller */
 	XPAD_XBOX360_VENDOR(0x044f),		/* Thrustmaster X-Box 360 controllers */
 	XPAD_XBOX360_VENDOR(0x045e),		/* Microsoft X-Box 360 controllers */
 	XPAD_XBOXONE_VENDOR(0x045e),		/* Microsoft X-Box One controllers */
 	XPAD_XBOX360_VENDOR(0x046d),		/* Logitech X-Box 360 style controllers */
+	XPAD_XBOX360_VENDOR(0x056e),		/* Elecom JC-U3613M */
+	XPAD_XBOX360_VENDOR(0x06a3),		/* Saitek P3600 */
 	XPAD_XBOX360_VENDOR(0x0738),		/* Mad Catz X-Box 360 controllers */
 	{ USB_DEVICE(0x0738, 0x4540) },		/* Mad Catz Beat Pad */
+	XPAD_XBOXONE_VENDOR(0x0738),		/* Mad Catz FightStick TE 2 */
+	XPAD_XBOX360_VENDOR(0x07ff),		/* Mad Catz GamePad */
 	XPAD_XBOX360_VENDOR(0x0e6f),		/* 0x0e6f X-Box 360 controllers */
+	XPAD_XBOXONE_VENDOR(0x0e6f),		/* 0x0e6f X-Box One controllers */
+	XPAD_XBOX360_VENDOR(0x0f0d),		/* Hori Controllers */
+	XPAD_XBOXONE_VENDOR(0x0f0d),		/* Hori Controllers */
+	XPAD_XBOX360_VENDOR(0x1038),		/* SteelSeries Controllers */
+	XPAD_XBOX360_VENDOR(0x11c9),		/* Nacon GC100XF */
+	XPAD_XBOX360_VENDOR(0x1209),		/* Ardwiino Controllers */
 	XPAD_XBOX360_VENDOR(0x12ab),		/* X-Box 360 dance pads */
 	XPAD_XBOX360_VENDOR(0x1430),		/* RedOctane X-Box 360 controllers */
 	XPAD_XBOX360_VENDOR(0x146b),		/* BigBen Interactive Controllers */
-	XPAD_XBOX360_VENDOR(0x1bad),		/* Harminix Rock Band Guitar and Drums */
-	XPAD_XBOX360_VENDOR(0x0f0d),		/* Hori Controllers */
-	XPAD_XBOX360_VENDOR(0x1689),		/* Razer Onza */
-	XPAD_XBOX360_VENDOR(0x24c6),		/* PowerA Controllers */
 	XPAD_XBOX360_VENDOR(0x1532),		/* Razer Sabertooth */
+	XPAD_XBOXONE_VENDOR(0x1532),		/* Razer Wildcat */
 	XPAD_XBOX360_VENDOR(0x15e4),		/* Numark X-Box 360 controllers */
 	XPAD_XBOX360_VENDOR(0x162e),		/* Joytech X-Box 360 controllers */
+	XPAD_XBOX360_VENDOR(0x1689),		/* Razer Onza */
+	XPAD_XBOX360_VENDOR(0x1bad),		/* Harminix Rock Band Guitar and Drums */
+	XPAD_XBOX360_VENDOR(0x20d6),		/* PowerA Controllers */
+	XPAD_XBOXONE_VENDOR(0x20d6),		/* PowerA Controllers */
+	XPAD_XBOX360_VENDOR(0x24c6),		/* PowerA Controllers */
+	XPAD_XBOXONE_VENDOR(0x24c6),		/* PowerA Controllers */
+	XPAD_XBOXONE_VENDOR(0x2e24),		/* Hyperkin Duke X-Box One pad */
+	XPAD_XBOX360_VENDOR(0x2f24),		/* GameSir Controllers */
 	{ }
 };
 
 MODULE_DEVICE_TABLE(usb, xpad_table);
 
+struct xboxone_init_packet {
+	u16 idVendor;
+	u16 idProduct;
+	const u8 *data;
+	u8 len;
+};
+
+#define XBOXONE_INIT_PKT(_vid, _pid, _data)		\
+	{						\
+		.idVendor	= (_vid),		\
+		.idProduct	= (_pid),		\
+		.data		= (_data),		\
+		.len		= ARRAY_SIZE(_data),	\
+	}
+
+
+/*
+ * This packet is required for all Xbox One pads with 2015
+ * or later firmware installed (or present from the factory).
+ */
+static const u8 xboxone_fw2015_init[] = {
+	0x05, 0x20, 0x00, 0x01, 0x00
+};
+
+/*
+ * This packet is required for Xbox One S (0x045e:0x02ea)
+ * and Xbox One Elite Series 2 (0x045e:0x0b00) pads to
+ * initialize the controller that was previously used in
+ * Bluetooth mode.
+ */
+static const u8 xboxone_s_init[] = {
+	0x05, 0x20, 0x00, 0x0f, 0x06
+};
+
+/*
+ * This packet is required for the Titanfall 2 Xbox One pads
+ * (0x0e6f:0x0165) to finish initialization and for Hori pads
+ * (0x0f0d:0x0067) to make the analog sticks work.
+ */
+static const u8 xboxone_hori_init[] = {
+	0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
+	0x00, 0x00, 0x00, 0x80, 0x00
+};
+
+/*
+ * This packet is required for most (all?) of the PDP pads to start
+ * sending input reports. These pads include: (0x0e6f:0x02ab),
+ * (0x0e6f:0x02a4), (0x0e6f:0x02a6).
+ */
+static const u8 xboxone_pdp_init1[] = {
+	0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
+};
+
+/*
+ * This packet is required for most (all?) of the PDP pads to start
+ * sending input reports. These pads include: (0x0e6f:0x02ab),
+ * (0x0e6f:0x02a4), (0x0e6f:0x02a6).
+ */
+static const u8 xboxone_pdp_init2[] = {
+	0x06, 0x20, 0x00, 0x02, 0x01, 0x00
+};
+
+/*
+ * A specific rumble packet is required for some PowerA pads to start
+ * sending input reports. One of those pads is (0x24c6:0x543a).
+ */
+static const u8 xboxone_rumblebegin_init[] = {
+	0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
+	0x1D, 0x1D, 0xFF, 0x00, 0x00
+};
+
+/*
+ * A rumble packet with zero FF intensity will immediately
+ * terminate the rumbling required to init PowerA pads.
+ * This should happen fast enough that the motors don't
+ * spin up to enough speed to actually vibrate the gamepad.
+ */
+static const u8 xboxone_rumbleend_init[] = {
+	0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+ * This specifies the selection of init packets that a gamepad
+ * will be sent on init *and* the order in which they will be
+ * sent. The correct sequence number will be added when the
+ * packet is going to be sent.
+ */
+static const struct xboxone_init_packet xboxone_init_packets[] = {
+	XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init),
+	XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init),
+	XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init),
+	XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init),
+	XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init),
+	XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init1),
+	XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init2),
+	XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
+	XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
+	XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init),
+	XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumbleend_init),
+	XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumbleend_init),
+	XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumbleend_init),
+};
+
+struct xpad_output_packet {
+	u8 data[XPAD_PKT_LEN];
+	u8 len;
+	bool pending;
+};
+
+#define XPAD_OUT_CMD_IDX	0
+#define XPAD_OUT_FF_IDX		1
+#define XPAD_OUT_LED_IDX	(1 + IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF))
+#define XPAD_NUM_OUT_PACKETS	(1 + \
+				 IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF) + \
+				 IS_ENABLED(CONFIG_JOYSTICK_XPAD_LEDS))
+
 struct usb_xpad {
 	struct input_dev *dev;		/* input device interface */
+	struct input_dev __rcu *x360w_dev;
 	struct usb_device *udev;	/* usb device */
 	struct usb_interface *intf;	/* usb interface */
 
-	int pad_present;
+	bool pad_present;
+	bool input_created;
 
 	struct urb *irq_in;		/* urb for interrupt in report */
 	unsigned char *idata;		/* input data */
 	dma_addr_t idata_dma;
 
 	struct urb *irq_out;		/* urb for interrupt out report */
+	struct usb_anchor irq_out_anchor;
+	bool irq_out_active;		/* we must not use an active URB */
+	u8 odata_serial;		/* serial number for xbox one protocol */
 	unsigned char *odata;		/* output data */
 	dma_addr_t odata_dma;
-	struct mutex odata_mutex;
+	spinlock_t odata_lock;
+
+	struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS];
+	int last_out_packet;
+	int init_seq;
 
 #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
 	struct xpad_led *led;
@@ -343,8 +621,13 @@
 	int xtype;			/* type of xbox device */
 	int pad_nr;			/* the order x360 pads were attached */
 	const char *name;		/* name of the device */
+	struct work_struct work;	/* init/remove device from callback */
 };
 
+static int xpad_init_input(struct usb_xpad *xpad);
+static void xpad_deinit_input(struct usb_xpad *xpad);
+static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
+
 /*
  *	xpad_process_packet
  *
@@ -424,10 +707,12 @@
  *		http://www.free60.org/wiki/Gamepad
  */
 
-static void xpad360_process_packet(struct usb_xpad *xpad,
+static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
 				   u16 cmd, unsigned char *data)
 {
-	struct input_dev *dev = xpad->dev;
+	/* valid pad data */
+	if (data[0] != 0x00)
+		return;
 
 	/* digital pad */
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
@@ -495,7 +780,30 @@
 	input_sync(dev);
 }
 
-static void xpad_identify_controller(struct usb_xpad *xpad);
+static void xpad_presence_work(struct work_struct *work)
+{
+	struct usb_xpad *xpad = container_of(work, struct usb_xpad, work);
+	int error;
+
+	if (xpad->pad_present) {
+		error = xpad_init_input(xpad);
+		if (error) {
+			/* complain only, not much else we can do here */
+			dev_err(&xpad->dev->dev,
+				"unable to init device: %d\n", error);
+		} else {
+			rcu_assign_pointer(xpad->x360w_dev, xpad->dev);
+		}
+	} else {
+		RCU_INIT_POINTER(xpad->x360w_dev, NULL);
+		synchronize_rcu();
+		/*
+		 * Now that we are sure xpad360w_process_packet is not
+		 * using input device we can get rid of it.
+		 */
+		xpad_deinit_input(xpad);
+	}
+}
 
 /*
  * xpad360w_process_packet
@@ -513,35 +821,61 @@
  */
 static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
 {
+	struct input_dev *dev;
+	bool present;
+
 	/* Presence change */
 	if (data[0] & 0x08) {
-		if (data[1] & 0x80) {
-			xpad->pad_present = 1;
-			/*
-			 * Light up the segment corresponding to
-			 * controller number.
-			 */
-			xpad_identify_controller(xpad);
-		} else
-			xpad->pad_present = 0;
+		present = (data[1] & 0x80) != 0;
+
+		if (xpad->pad_present != present) {
+			xpad->pad_present = present;
+			schedule_work(&xpad->work);
+		}
 	}
 
 	/* Valid pad data */
-	if (!(data[1] & 0x1))
+	if (data[1] != 0x1)
 		return;
 
-	xpad360_process_packet(xpad, cmd, &data[4]);
+	rcu_read_lock();
+	dev = rcu_dereference(xpad->x360w_dev);
+	if (dev)
+		xpad360_process_packet(xpad, dev, cmd, &data[4]);
+	rcu_read_unlock();
 }
 
 /*
- *	xpadone_process_buttons
+ *	xpadone_process_packet
  *
- *	Process a button update packet from an Xbox one controller.
+ *	Completes a request by converting the data into events for the
+ *	input subsystem. This version is for the Xbox One controller.
+ *
+ *	The report format was gleaned from
+ *	https://github.com/kylelemons/xbox/blob/master/xbox.go
  */
-static void xpadone_process_buttons(struct usb_xpad *xpad,
-				struct input_dev *dev,
-				unsigned char *data)
+static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
 {
+	struct input_dev *dev = xpad->dev;
+
+	/* the xbox button has its own special report */
+	if (data[0] == 0X07) {
+		/*
+		 * The Xbox One S controller requires these reports to be
+		 * acked otherwise it continues sending them forever and
+		 * won't report further mode button events.
+		 */
+		if (data[1] == 0x30)
+			xpadone_ack_mode_report(xpad, data[2]);
+
+		input_report_key(dev, BTN_MODE, data[4] & 0x01);
+		input_sync(dev);
+		return;
+	}
+	/* check invalid packet */
+	else if (data[0] != 0X20)
+		return;
+
 	/* menu/view buttons */
 	input_report_key(dev, BTN_START,  data[4] & 0x04);
 	input_report_key(dev, BTN_SELECT, data[4] & 0x08);
@@ -604,34 +938,6 @@
 	input_sync(dev);
 }
 
-/*
- *	xpadone_process_packet
- *
- *	Completes a request by converting the data into events for the
- *	input subsystem. This version is for the Xbox One controller.
- *
- *	The report format was gleaned from
- *	https://github.com/kylelemons/xbox/blob/master/xbox.go
- */
-
-static void xpadone_process_packet(struct usb_xpad *xpad,
-				u16 cmd, unsigned char *data)
-{
-	struct input_dev *dev = xpad->dev;
-
-	switch (data[0]) {
-	case 0x20:
-		xpadone_process_buttons(xpad, dev, data);
-		break;
-
-	case 0x07:
-		/* the xbox button has its own special report */
-		input_report_key(dev, BTN_MODE, data[4] & 0x01);
-		input_sync(dev);
-		break;
-	}
-}
-
 static void xpad_irq_in(struct urb *urb)
 {
 	struct usb_xpad *xpad = urb->context;
@@ -659,7 +965,7 @@
 
 	switch (xpad->xtype) {
 	case XTYPE_XBOX360:
-		xpad360_process_packet(xpad, 0, xpad->idata);
+		xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata);
 		break;
 	case XTYPE_XBOX360W:
 		xpad360w_process_packet(xpad, 0, xpad->idata);
@@ -678,18 +984,109 @@
 			__func__, retval);
 }
 
+/* Callers must hold xpad->odata_lock spinlock */
+static bool xpad_prepare_next_init_packet(struct usb_xpad *xpad)
+{
+	const struct xboxone_init_packet *init_packet;
+
+	if (xpad->xtype != XTYPE_XBOXONE)
+		return false;
+
+	/* Perform initialization sequence for Xbox One pads that require it */
+	while (xpad->init_seq < ARRAY_SIZE(xboxone_init_packets)) {
+		init_packet = &xboxone_init_packets[xpad->init_seq++];
+
+		if (init_packet->idVendor != 0 &&
+		    init_packet->idVendor != xpad->dev->id.vendor)
+			continue;
+
+		if (init_packet->idProduct != 0 &&
+		    init_packet->idProduct != xpad->dev->id.product)
+			continue;
+
+		/* This packet applies to our device, so prepare to send it */
+		memcpy(xpad->odata, init_packet->data, init_packet->len);
+		xpad->irq_out->transfer_buffer_length = init_packet->len;
+
+		/* Update packet with current sequence number */
+		xpad->odata[2] = xpad->odata_serial++;
+		return true;
+	}
+
+	return false;
+}
+
+/* Callers must hold xpad->odata_lock spinlock */
+static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad)
+{
+	struct xpad_output_packet *pkt, *packet = NULL;
+	int i;
+
+	/* We may have init packets to send before we can send user commands */
+	if (xpad_prepare_next_init_packet(xpad))
+		return true;
+
+	for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) {
+		if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS)
+			xpad->last_out_packet = 0;
+
+		pkt = &xpad->out_packets[xpad->last_out_packet];
+		if (pkt->pending) {
+			dev_dbg(&xpad->intf->dev,
+				"%s - found pending output packet %d\n",
+				__func__, xpad->last_out_packet);
+			packet = pkt;
+			break;
+		}
+	}
+
+	if (packet) {
+		memcpy(xpad->odata, packet->data, packet->len);
+		xpad->irq_out->transfer_buffer_length = packet->len;
+		packet->pending = false;
+		return true;
+	}
+
+	return false;
+}
+
+/* Callers must hold xpad->odata_lock spinlock */
+static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad)
+{
+	int error;
+
+	if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) {
+		usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor);
+		error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+		if (error) {
+			dev_err(&xpad->intf->dev,
+				"%s - usb_submit_urb failed with result %d\n",
+				__func__, error);
+			usb_unanchor_urb(xpad->irq_out);
+			return -EIO;
+		}
+
+		xpad->irq_out_active = true;
+	}
+
+	return 0;
+}
+
 static void xpad_irq_out(struct urb *urb)
 {
 	struct usb_xpad *xpad = urb->context;
 	struct device *dev = &xpad->intf->dev;
-	int retval, status;
+	int status = urb->status;
+	int error;
+	unsigned long flags;
 
-	status = urb->status;
+	spin_lock_irqsave(&xpad->odata_lock, flags);
 
 	switch (status) {
 	case 0:
 		/* success */
-		return;
+		xpad->irq_out_active = xpad_prepare_next_out_packet(xpad);
+		break;
 
 	case -ECONNRESET:
 	case -ENOENT:
@@ -697,49 +1094,53 @@
 		/* this urb is terminated, clean up */
 		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
 			__func__, status);
-		return;
+		xpad->irq_out_active = false;
+		break;
 
 	default:
 		dev_dbg(dev, "%s - nonzero urb status received: %d\n",
 			__func__, status);
-		goto exit;
+		break;
 	}
 
-exit:
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval)
-		dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
-			__func__, retval);
+	if (xpad->irq_out_active) {
+		usb_anchor_urb(urb, &xpad->irq_out_anchor);
+		error = usb_submit_urb(urb, GFP_ATOMIC);
+		if (error) {
+			dev_err(dev,
+				"%s - usb_submit_urb failed with result %d\n",
+				__func__, error);
+			usb_unanchor_urb(urb);
+			xpad->irq_out_active = false;
+		}
+	}
+
+	spin_unlock_irqrestore(&xpad->odata_lock, flags);
 }
 
-static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad,
+			struct usb_endpoint_descriptor *ep_irq_out)
 {
-	struct usb_endpoint_descriptor *ep_irq_out;
-	int ep_irq_out_idx;
 	int error;
 
 	if (xpad->xtype == XTYPE_UNKNOWN)
 		return 0;
 
+	init_usb_anchor(&xpad->irq_out_anchor);
+
 	xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
 					 GFP_KERNEL, &xpad->odata_dma);
-	if (!xpad->odata) {
-		error = -ENOMEM;
-		goto fail1;
-	}
+	if (!xpad->odata)
+		return -ENOMEM;
 
-	mutex_init(&xpad->odata_mutex);
+	spin_lock_init(&xpad->odata_lock);
 
 	xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
 	if (!xpad->irq_out) {
 		error = -ENOMEM;
-		goto fail2;
+		goto err_free_coherent;
 	}
 
-	/* Xbox One controller has in/out endpoints swapped. */
-	ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1;
-	ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc;
-
 	usb_fill_int_urb(xpad->irq_out, xpad->udev,
 			 usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
 			 xpad->odata, XPAD_PKT_LEN,
@@ -749,14 +1150,21 @@
 
 	return 0;
 
- fail2:	usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
- fail1:	return error;
+err_free_coherent:
+	usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
+	return error;
 }
 
 static void xpad_stop_output(struct usb_xpad *xpad)
 {
-	if (xpad->xtype != XTYPE_UNKNOWN)
-		usb_kill_urb(xpad->irq_out);
+	if (xpad->xtype != XTYPE_UNKNOWN) {
+		if (!usb_wait_anchor_empty_timeout(&xpad->irq_out_anchor,
+						   5000)) {
+			dev_warn(&xpad->intf->dev,
+				 "timed out waiting for output URB to complete, killing\n");
+			usb_kill_anchored_urbs(&xpad->irq_out_anchor);
+		}
+	}
 }
 
 static void xpad_deinit_output(struct usb_xpad *xpad)
@@ -770,37 +1178,90 @@
 
 static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
 {
+	struct xpad_output_packet *packet =
+			&xpad->out_packets[XPAD_OUT_CMD_IDX];
+	unsigned long flags;
 	int retval;
 
-	mutex_lock(&xpad->odata_mutex);
+	spin_lock_irqsave(&xpad->odata_lock, flags);
+
+	packet->data[0] = 0x08;
+	packet->data[1] = 0x00;
+	packet->data[2] = 0x0F;
+	packet->data[3] = 0xC0;
+	packet->data[4] = 0x00;
+	packet->data[5] = 0x00;
+	packet->data[6] = 0x00;
+	packet->data[7] = 0x00;
+	packet->data[8] = 0x00;
+	packet->data[9] = 0x00;
+	packet->data[10] = 0x00;
+	packet->data[11] = 0x00;
+	packet->len = 12;
+	packet->pending = true;
+
+	/* Reset the sequence so we send out presence first */
+	xpad->last_out_packet = -1;
+	retval = xpad_try_sending_next_out_packet(xpad);
+
+	spin_unlock_irqrestore(&xpad->odata_lock, flags);
+
+	return retval;
+}
 
-	xpad->odata[0] = 0x08;
-	xpad->odata[1] = 0x00;
-	xpad->odata[2] = 0x0F;
-	xpad->odata[3] = 0xC0;
-	xpad->odata[4] = 0x00;
-	xpad->odata[5] = 0x00;
-	xpad->odata[6] = 0x00;
-	xpad->odata[7] = 0x00;
-	xpad->odata[8] = 0x00;
-	xpad->odata[9] = 0x00;
-	xpad->odata[10] = 0x00;
-	xpad->odata[11] = 0x00;
-	xpad->irq_out->transfer_buffer_length = 12;
+static int xpad_start_xbox_one(struct usb_xpad *xpad)
+{
+	unsigned long flags;
+	int retval;
 
-	retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+	spin_lock_irqsave(&xpad->odata_lock, flags);
 
-	mutex_unlock(&xpad->odata_mutex);
+	/*
+	 * Begin the init sequence by attempting to send a packet.
+	 * We will cycle through the init packet sequence before
+	 * sending any packets from the output ring.
+	 */
+	xpad->init_seq = 0;
+	retval = xpad_try_sending_next_out_packet(xpad);
+
+	spin_unlock_irqrestore(&xpad->odata_lock, flags);
 
 	return retval;
 }
 
+static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num)
+{
+	unsigned long flags;
+	struct xpad_output_packet *packet =
+			&xpad->out_packets[XPAD_OUT_CMD_IDX];
+	static const u8 mode_report_ack[] = {
+		0x01, 0x20, 0x00, 0x09, 0x00, 0x07, 0x20, 0x02,
+		0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+	spin_lock_irqsave(&xpad->odata_lock, flags);
+
+	packet->len = sizeof(mode_report_ack);
+	memcpy(packet->data, mode_report_ack, packet->len);
+	packet->data[2] = seq_num;
+	packet->pending = true;
+
+	/* Reset the sequence so we send out the ack now */
+	xpad->last_out_packet = -1;
+	xpad_try_sending_next_out_packet(xpad);
+
+	spin_unlock_irqrestore(&xpad->odata_lock, flags);
+}
+
 #ifdef CONFIG_JOYSTICK_XPAD_FF
 static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
 	struct usb_xpad *xpad = input_get_drvdata(dev);
+	struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX];
 	__u16 strong;
 	__u16 weak;
+	int retval;
+	unsigned long flags;
 
 	if (effect->type != FF_RUMBLE)
 		return 0;
@@ -808,69 +1269,81 @@
 	strong = effect->u.rumble.strong_magnitude;
 	weak = effect->u.rumble.weak_magnitude;
 
+	spin_lock_irqsave(&xpad->odata_lock, flags);
+
 	switch (xpad->xtype) {
 	case XTYPE_XBOX:
-		xpad->odata[0] = 0x00;
-		xpad->odata[1] = 0x06;
-		xpad->odata[2] = 0x00;
-		xpad->odata[3] = strong / 256;	/* left actuator */
-		xpad->odata[4] = 0x00;
-		xpad->odata[5] = weak / 256;	/* right actuator */
-		xpad->irq_out->transfer_buffer_length = 6;
+		packet->data[0] = 0x00;
+		packet->data[1] = 0x06;
+		packet->data[2] = 0x00;
+		packet->data[3] = strong / 256;	/* left actuator */
+		packet->data[4] = 0x00;
+		packet->data[5] = weak / 256;	/* right actuator */
+		packet->len = 6;
+		packet->pending = true;
 		break;
 
 	case XTYPE_XBOX360:
-		xpad->odata[0] = 0x00;
-		xpad->odata[1] = 0x08;
-		xpad->odata[2] = 0x00;
-		xpad->odata[3] = strong / 256;  /* left actuator? */
-		xpad->odata[4] = weak / 256;	/* right actuator? */
-		xpad->odata[5] = 0x00;
-		xpad->odata[6] = 0x00;
-		xpad->odata[7] = 0x00;
-		xpad->irq_out->transfer_buffer_length = 8;
+		packet->data[0] = 0x00;
+		packet->data[1] = 0x08;
+		packet->data[2] = 0x00;
+		packet->data[3] = strong / 256;  /* left actuator? */
+		packet->data[4] = weak / 256;	/* right actuator? */
+		packet->data[5] = 0x00;
+		packet->data[6] = 0x00;
+		packet->data[7] = 0x00;
+		packet->len = 8;
+		packet->pending = true;
 		break;
 
 	case XTYPE_XBOX360W:
-		xpad->odata[0] = 0x00;
-		xpad->odata[1] = 0x01;
-		xpad->odata[2] = 0x0F;
-		xpad->odata[3] = 0xC0;
-		xpad->odata[4] = 0x00;
-		xpad->odata[5] = strong / 256;
-		xpad->odata[6] = weak / 256;
-		xpad->odata[7] = 0x00;
-		xpad->odata[8] = 0x00;
-		xpad->odata[9] = 0x00;
-		xpad->odata[10] = 0x00;
-		xpad->odata[11] = 0x00;
-		xpad->irq_out->transfer_buffer_length = 12;
+		packet->data[0] = 0x00;
+		packet->data[1] = 0x01;
+		packet->data[2] = 0x0F;
+		packet->data[3] = 0xC0;
+		packet->data[4] = 0x00;
+		packet->data[5] = strong / 256;
+		packet->data[6] = weak / 256;
+		packet->data[7] = 0x00;
+		packet->data[8] = 0x00;
+		packet->data[9] = 0x00;
+		packet->data[10] = 0x00;
+		packet->data[11] = 0x00;
+		packet->len = 12;
+		packet->pending = true;
 		break;
 
 	case XTYPE_XBOXONE:
-		xpad->odata[0] = 0x09; /* activate rumble */
-		xpad->odata[1] = 0x08;
-		xpad->odata[2] = 0x00;
-		xpad->odata[3] = 0x08; /* continuous effect */
-		xpad->odata[4] = 0x00; /* simple rumble mode */
-		xpad->odata[5] = 0x03; /* L and R actuator only */
-		xpad->odata[6] = 0x00; /* TODO: LT actuator */
-		xpad->odata[7] = 0x00; /* TODO: RT actuator */
-		xpad->odata[8] = strong / 256;	/* left actuator */
-		xpad->odata[9] = weak / 256;	/* right actuator */
-		xpad->odata[10] = 0x80;	/* length of pulse */
-		xpad->odata[11] = 0x00;	/* stop period of pulse */
-		xpad->irq_out->transfer_buffer_length = 12;
+		packet->data[0] = 0x09; /* activate rumble */
+		packet->data[1] = 0x00;
+		packet->data[2] = xpad->odata_serial++;
+		packet->data[3] = 0x09;
+		packet->data[4] = 0x00;
+		packet->data[5] = 0x0F;
+		packet->data[6] = 0x00;
+		packet->data[7] = 0x00;
+		packet->data[8] = strong / 512;	/* left actuator */
+		packet->data[9] = weak / 512;	/* right actuator */
+		packet->data[10] = 0xFF; /* on period */
+		packet->data[11] = 0x00; /* off period */
+		packet->data[12] = 0xFF; /* repeat count */
+		packet->len = 13;
+		packet->pending = true;
 		break;
 
 	default:
 		dev_dbg(&xpad->dev->dev,
 			"%s - rumble command sent to unsupported xpad type: %d\n",
 			__func__, xpad->xtype);
-		return -EINVAL;
+		retval = -EINVAL;
+		goto out;
 	}
 
-	return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+	retval = xpad_try_sending_next_out_packet(xpad);
+
+out:
+	spin_unlock_irqrestore(&xpad->odata_lock, flags);
+	return retval;
 }
 
 static int xpad_init_ff(struct usb_xpad *xpad)
@@ -921,36 +1394,44 @@
  */
 static void xpad_send_led_command(struct usb_xpad *xpad, int command)
 {
+	struct xpad_output_packet *packet =
+			&xpad->out_packets[XPAD_OUT_LED_IDX];
+	unsigned long flags;
+
 	command %= 16;
 
-	mutex_lock(&xpad->odata_mutex);
+	spin_lock_irqsave(&xpad->odata_lock, flags);
 
 	switch (xpad->xtype) {
 	case XTYPE_XBOX360:
-		xpad->odata[0] = 0x01;
-		xpad->odata[1] = 0x03;
-		xpad->odata[2] = command;
-		xpad->irq_out->transfer_buffer_length = 3;
+		packet->data[0] = 0x01;
+		packet->data[1] = 0x03;
+		packet->data[2] = command;
+		packet->len = 3;
+		packet->pending = true;
 		break;
+
 	case XTYPE_XBOX360W:
-		xpad->odata[0] = 0x00;
-		xpad->odata[1] = 0x00;
-		xpad->odata[2] = 0x08;
-		xpad->odata[3] = 0x40 + command;
-		xpad->odata[4] = 0x00;
-		xpad->odata[5] = 0x00;
-		xpad->odata[6] = 0x00;
-		xpad->odata[7] = 0x00;
-		xpad->odata[8] = 0x00;
-		xpad->odata[9] = 0x00;
-		xpad->odata[10] = 0x00;
-		xpad->odata[11] = 0x00;
-		xpad->irq_out->transfer_buffer_length = 12;
+		packet->data[0] = 0x00;
+		packet->data[1] = 0x00;
+		packet->data[2] = 0x08;
+		packet->data[3] = 0x40 + command;
+		packet->data[4] = 0x00;
+		packet->data[5] = 0x00;
+		packet->data[6] = 0x00;
+		packet->data[7] = 0x00;
+		packet->data[8] = 0x00;
+		packet->data[9] = 0x00;
+		packet->data[10] = 0x00;
+		packet->data[11] = 0x00;
+		packet->len = 12;
+		packet->pending = true;
 		break;
 	}
 
-	usb_submit_urb(xpad->irq_out, GFP_KERNEL);
-	mutex_unlock(&xpad->odata_mutex);
+	xpad_try_sending_next_out_packet(xpad);
+
+	spin_unlock_irqrestore(&xpad->odata_lock, flags);
 }
 
 /*
@@ -959,7 +1440,7 @@
  */
 static void xpad_identify_controller(struct usb_xpad *xpad)
 {
-	xpad_send_led_command(xpad, (xpad->pad_nr % 4) + 2);
+	led_set_brightness(&xpad->led->led_cdev, (xpad->pad_nr % 4) + 2);
 }
 
 static void xpad_led_set(struct led_classdev *led_cdev,
@@ -996,19 +1477,13 @@
 	led_cdev = &led->led_cdev;
 	led_cdev->name = led->name;
 	led_cdev->brightness_set = xpad_led_set;
+	led_cdev->flags = LED_CORE_SUSPENDRESUME;
 
 	error = led_classdev_register(&xpad->udev->dev, led_cdev);
 	if (error)
 		goto err_free_id;
 
-	if (xpad->xtype == XTYPE_XBOX360) {
-		/*
-		 * Light up the segment corresponding to controller
-		 * number on wired devices. On wireless we'll do that
-		 * when they respond to "presence" packet.
-		 */
-		xpad_identify_controller(xpad);
-	}
+	xpad_identify_controller(xpad);
 
 	return 0;
 
@@ -1033,46 +1508,110 @@
 #else
 static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
 static void xpad_led_disconnect(struct usb_xpad *xpad) { }
-static void xpad_identify_controller(struct usb_xpad *xpad) { }
 #endif
 
-static int xpad_open(struct input_dev *dev)
+static int xpad_start_input(struct usb_xpad *xpad)
 {
-	struct usb_xpad *xpad = input_get_drvdata(dev);
-
-	/* URB was submitted in probe */
-	if (xpad->xtype == XTYPE_XBOX360W)
-		return 0;
+	int error;
 
-	xpad->irq_in->dev = xpad->udev;
 	if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
 		return -EIO;
 
 	if (xpad->xtype == XTYPE_XBOXONE) {
-		/* Xbox one controller needs to be initialized. */
-		xpad->odata[0] = 0x05;
-		xpad->odata[1] = 0x20;
-		xpad->irq_out->transfer_buffer_length = 2;
-		return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+		error = xpad_start_xbox_one(xpad);
+		if (error) {
+			usb_kill_urb(xpad->irq_in);
+			return error;
+		}
 	}
 
 	return 0;
 }
 
-static void xpad_close(struct input_dev *dev)
+static void xpad_stop_input(struct usb_xpad *xpad)
 {
-	struct usb_xpad *xpad = input_get_drvdata(dev);
+	usb_kill_urb(xpad->irq_in);
+}
 
-	if (xpad->xtype != XTYPE_XBOX360W)
+static void xpad360w_poweroff_controller(struct usb_xpad *xpad)
+{
+	unsigned long flags;
+	struct xpad_output_packet *packet =
+			&xpad->out_packets[XPAD_OUT_CMD_IDX];
+
+	spin_lock_irqsave(&xpad->odata_lock, flags);
+
+	packet->data[0] = 0x00;
+	packet->data[1] = 0x00;
+	packet->data[2] = 0x08;
+	packet->data[3] = 0xC0;
+	packet->data[4] = 0x00;
+	packet->data[5] = 0x00;
+	packet->data[6] = 0x00;
+	packet->data[7] = 0x00;
+	packet->data[8] = 0x00;
+	packet->data[9] = 0x00;
+	packet->data[10] = 0x00;
+	packet->data[11] = 0x00;
+	packet->len = 12;
+	packet->pending = true;
+
+	/* Reset the sequence so we send out poweroff now */
+	xpad->last_out_packet = -1;
+	xpad_try_sending_next_out_packet(xpad);
+
+	spin_unlock_irqrestore(&xpad->odata_lock, flags);
+}
+
+static int xpad360w_start_input(struct usb_xpad *xpad)
+{
+	int error;
+
+	error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
+	if (error)
+		return -EIO;
+
+	/*
+	 * Send presence packet.
+	 * This will force the controller to resend connection packets.
+	 * This is useful in the case we activate the module after the
+	 * adapter has been plugged in, as it won't automatically
+	 * send us info about the controllers.
+	 */
+	error = xpad_inquiry_pad_presence(xpad);
+	if (error) {
 		usb_kill_urb(xpad->irq_in);
+		return error;
+	}
 
-	xpad_stop_output(xpad);
+	return 0;
+}
+
+static void xpad360w_stop_input(struct usb_xpad *xpad)
+{
+	usb_kill_urb(xpad->irq_in);
+
+	/* Make sure we are done with presence work if it was scheduled */
+	flush_work(&xpad->work);
+}
+
+static int xpad_open(struct input_dev *dev)
+{
+	struct usb_xpad *xpad = input_get_drvdata(dev);
+
+	return xpad_start_input(xpad);
+}
+
+static void xpad_close(struct input_dev *dev)
+{
+	struct usb_xpad *xpad = input_get_drvdata(dev);
+
+	xpad_stop_input(xpad);
 }
 
 static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
 {
 	struct usb_xpad *xpad = input_get_drvdata(input_dev);
-	set_bit(abs, input_dev->absbit);
 
 	switch (abs) {
 	case ABS_X:
@@ -1092,13 +1631,19 @@
 	case ABS_HAT0Y:	/* the d-pad (only if dpad is mapped to axes */
 		input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
 		break;
+	default:
+		input_set_abs_params(input_dev, abs, 0, 0, 0, 0);
+		break;
 	}
 }
 
 static void xpad_deinit_input(struct usb_xpad *xpad)
 {
-	xpad_led_disconnect(xpad);
-	input_unregister_device(xpad->dev);
+	if (xpad->input_created) {
+		xpad->input_created = false;
+		xpad_led_disconnect(xpad);
+		input_unregister_device(xpad->dev);
+	}
 }
 
 static int xpad_init_input(struct usb_xpad *xpad)
@@ -1114,17 +1659,22 @@
 	input_dev->name = xpad->name;
 	input_dev->phys = xpad->phys;
 	usb_to_input_id(xpad->udev, &input_dev->id);
+
+	if (xpad->xtype == XTYPE_XBOX360W) {
+		/* x360w controllers and the receiver have different ids */
+		input_dev->id.product = 0x02a1;
+	}
+
 	input_dev->dev.parent = &xpad->intf->dev;
 
 	input_set_drvdata(input_dev, xpad);
 
-	input_dev->open = xpad_open;
-	input_dev->close = xpad_close;
-
-	__set_bit(EV_KEY, input_dev->evbit);
+	if (xpad->xtype != XTYPE_XBOX360W) {
+		input_dev->open = xpad_open;
+		input_dev->close = xpad_close;
+	}
 
 	if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
-		__set_bit(EV_ABS, input_dev->evbit);
 		/* set up axes */
 		for (i = 0; xpad_abs[i] >= 0; i++)
 			xpad_set_up_abs(input_dev, xpad_abs[i]);
@@ -1132,21 +1682,22 @@
 
 	/* set up standard buttons */
 	for (i = 0; xpad_common_btn[i] >= 0; i++)
-		__set_bit(xpad_common_btn[i], input_dev->keybit);
+		input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]);
 
 	/* set up model-specific ones */
 	if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
 	    xpad->xtype == XTYPE_XBOXONE) {
 		for (i = 0; xpad360_btn[i] >= 0; i++)
-			__set_bit(xpad360_btn[i], input_dev->keybit);
+			input_set_capability(input_dev, EV_KEY, xpad360_btn[i]);
 	} else {
 		for (i = 0; xpad_btn[i] >= 0; i++)
-			__set_bit(xpad_btn[i], input_dev->keybit);
+			input_set_capability(input_dev, EV_KEY, xpad_btn[i]);
 	}
 
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
 		for (i = 0; xpad_btn_pad[i] >= 0; i++)
-			__set_bit(xpad_btn_pad[i], input_dev->keybit);
+			input_set_capability(input_dev, EV_KEY,
+					     xpad_btn_pad[i]);
 	}
 
 	/*
@@ -1163,7 +1714,8 @@
 
 	if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
 		for (i = 0; xpad_btn_triggers[i] >= 0; i++)
-			__set_bit(xpad_btn_triggers[i], input_dev->keybit);
+			input_set_capability(input_dev, EV_KEY,
+					     xpad_btn_triggers[i]);
 	} else {
 		for (i = 0; xpad_abs_triggers[i] >= 0; i++)
 			xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
@@ -1181,6 +1733,7 @@
 	if (error)
 		goto err_disconnect_led;
 
+	xpad->input_created = true;
 	return 0;
 
 err_disconnect_led:
@@ -1196,26 +1749,18 @@
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct usb_xpad *xpad;
-	struct usb_endpoint_descriptor *ep_irq_in;
-	int ep_irq_in_idx;
+	struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out;
 	int i, error;
 
+	if (intf->cur_altsetting->desc.bNumEndpoints != 2)
+		return -ENODEV;
+
 	for (i = 0; xpad_device[i].idVendor; i++) {
 		if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
 		    (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
 			break;
 	}
 
-	if (xpad_device[i].xtype == XTYPE_XBOXONE &&
-	    intf->cur_altsetting->desc.bInterfaceNumber != 0) {
-		/*
-		 * The Xbox One controller lists three interfaces all with the
-		 * same interface class, subclass and protocol. Differentiate by
-		 * interface number.
-		 */
-		return -ENODEV;
-	}
-
 	xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
 	if (!xpad)
 		return -ENOMEM;
@@ -1241,11 +1786,14 @@
 	xpad->mapping = xpad_device[i].mapping;
 	xpad->xtype = xpad_device[i].xtype;
 	xpad->name = xpad_device[i].name;
+	INIT_WORK(&xpad->work, xpad_presence_work);
 
 	if (xpad->xtype == XTYPE_UNKNOWN) {
 		if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
 			if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
 				xpad->xtype = XTYPE_XBOX360W;
+			else if (intf->cur_altsetting->desc.bInterfaceProtocol == 208)
+				xpad->xtype = XTYPE_XBOXONE;
 			else
 				xpad->xtype = XTYPE_XBOX360;
 		} else {
@@ -1260,13 +1808,39 @@
 			xpad->mapping |= MAP_STICKS_TO_NULL;
 	}
 
-	error = xpad_init_output(intf, xpad);
-	if (error)
+	if (xpad->xtype == XTYPE_XBOXONE &&
+	    intf->cur_altsetting->desc.bInterfaceNumber != 0) {
+		/*
+		 * The Xbox One controller lists three interfaces all with the
+		 * same interface class, subclass and protocol. Differentiate by
+		 * interface number.
+		 */
+		error = -ENODEV;
+		goto err_free_in_urb;
+	}
+
+	ep_irq_in = ep_irq_out = NULL;
+
+	for (i = 0; i < 2; i++) {
+		struct usb_endpoint_descriptor *ep =
+				&intf->cur_altsetting->endpoint[i].desc;
+
+		if (usb_endpoint_xfer_int(ep)) {
+			if (usb_endpoint_dir_in(ep))
+				ep_irq_in = ep;
+			else
+				ep_irq_out = ep;
+		}
+	}
+
+	if (!ep_irq_in || !ep_irq_out) {
+		error = -ENODEV;
 		goto err_free_in_urb;
+	}
 
-	/* Xbox One controller has in/out endpoints swapped. */
-	ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0;
-	ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc;
+	error = xpad_init_output(intf, xpad, ep_irq_out);
+	if (error)
+		goto err_free_in_urb;
 
 	usb_fill_int_urb(xpad->irq_in, udev,
 			 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
@@ -1277,10 +1851,6 @@
 
 	usb_set_intfdata(intf, xpad);
 
-	error = xpad_init_input(xpad);
-	if (error)
-		goto err_deinit_output;
-
 	if (xpad->xtype == XTYPE_XBOX360W) {
 		/*
 		 * Submit the int URB immediately rather than waiting for open
@@ -1289,28 +1859,24 @@
 		 * exactly the message that a controller has arrived that
 		 * we're waiting for.
 		 */
-		xpad->irq_in->dev = xpad->udev;
-		error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
+		error = xpad360w_start_input(xpad);
 		if (error)
-			goto err_deinit_input;
-
+			goto err_deinit_output;
 		/*
-		 * Send presence packet.
-		 * This will force the controller to resend connection packets.
-		 * This is useful in the case we activate the module after the
-		 * adapter has been plugged in, as it won't automatically
-		 * send us info about the controllers.
+		 * Wireless controllers require RESET_RESUME to work properly
+		 * after suspend. Ideally this quirk should be in usb core
+		 * quirk list, but we have too many vendors producing these
+		 * controllers and we'd need to maintain 2 identical lists
+		 * here in this driver and in usb core.
 		 */
-		error = xpad_inquiry_pad_presence(xpad);
+		udev->quirks |= USB_QUIRK_RESET_RESUME;
+	} else {
+		error = xpad_init_input(xpad);
 		if (error)
-			goto err_kill_in_urb;
+			goto err_deinit_output;
 	}
 	return 0;
 
-err_kill_in_urb:
-	usb_kill_urb(xpad->irq_in);
-err_deinit_input:
-	xpad_deinit_input(xpad);
 err_deinit_output:
 	xpad_deinit_output(xpad);
 err_free_in_urb:
@@ -1320,19 +1886,24 @@
 err_free_mem:
 	kfree(xpad);
 	return error;
-
 }
 
 static void xpad_disconnect(struct usb_interface *intf)
 {
-	struct usb_xpad *xpad = usb_get_intfdata (intf);
+	struct usb_xpad *xpad = usb_get_intfdata(intf);
+
+	if (xpad->xtype == XTYPE_XBOX360W)
+		xpad360w_stop_input(xpad);
 
 	xpad_deinit_input(xpad);
-	xpad_deinit_output(xpad);
 
-	if (xpad->xtype == XTYPE_XBOX360W) {
-		usb_kill_urb(xpad->irq_in);
-	}
+	/*
+	 * Now that both input device and LED device are gone we can
+	 * stop output URB.
+	 */
+	xpad_stop_output(xpad);
+
+	xpad_deinit_output(xpad);
 
 	usb_free_urb(xpad->irq_in);
 	usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
@@ -1343,10 +1914,72 @@
 	usb_set_intfdata(intf, NULL);
 }
 
+static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct usb_xpad *xpad = usb_get_intfdata(intf);
+	struct input_dev *input = xpad->dev;
+
+	if (xpad->xtype == XTYPE_XBOX360W) {
+		/*
+		 * Wireless controllers always listen to input so
+		 * they are notified when controller shows up
+		 * or goes away.
+		 */
+		xpad360w_stop_input(xpad);
+
+		/*
+		 * The wireless adapter is going off now, so the
+		 * gamepads are going to become disconnected.
+		 * Unless explicitly disabled, power them down
+		 * so they don't just sit there flashing.
+		 */
+		if (auto_poweroff && xpad->pad_present)
+			xpad360w_poweroff_controller(xpad);
+	} else {
+		mutex_lock(&input->mutex);
+		if (input->users)
+			xpad_stop_input(xpad);
+		mutex_unlock(&input->mutex);
+	}
+
+	xpad_stop_output(xpad);
+
+	return 0;
+}
+
+static int xpad_resume(struct usb_interface *intf)
+{
+	struct usb_xpad *xpad = usb_get_intfdata(intf);
+	struct input_dev *input = xpad->dev;
+	int retval = 0;
+
+	if (xpad->xtype == XTYPE_XBOX360W) {
+		retval = xpad360w_start_input(xpad);
+	} else {
+		mutex_lock(&input->mutex);
+		if (input->users) {
+			retval = xpad_start_input(xpad);
+		} else if (xpad->xtype == XTYPE_XBOXONE) {
+			/*
+			 * Even if there are no users, we'll send Xbox One pads
+			 * the startup sequence so they don't sit there and
+			 * blink until somebody opens the input device again.
+			 */
+			retval = xpad_start_xbox_one(xpad);
+		}
+		mutex_unlock(&input->mutex);
+	}
+
+	return retval;
+}
+
 static struct usb_driver xpad_driver = {
 	.name		= "xpad",
 	.probe		= xpad_probe,
 	.disconnect	= xpad_disconnect,
+	.suspend	= xpad_suspend,
+	.resume		= xpad_resume,
+	.reset_resume	= xpad_resume,
 	.id_table	= xpad_table,
 };
 
--- linux-4.4.0.orig/drivers/input/keyboard/atakbd.c
+++ linux-4.4.0/drivers/input/keyboard/atakbd.c
@@ -79,8 +79,7 @@
  */
 
 
-static unsigned char atakbd_keycode[0x72] = {	/* American layout */
-	[0]	 = KEY_GRAVE,
+static unsigned char atakbd_keycode[0x73] = {	/* American layout */
 	[1]	 = KEY_ESC,
 	[2]	 = KEY_1,
 	[3]	 = KEY_2,
@@ -121,9 +120,9 @@
 	[38]	 = KEY_L,
 	[39]	 = KEY_SEMICOLON,
 	[40]	 = KEY_APOSTROPHE,
-	[41]	 = KEY_BACKSLASH,	/* FIXME, '#' */
+	[41]	 = KEY_GRAVE,
 	[42]	 = KEY_LEFTSHIFT,
-	[43]	 = KEY_GRAVE,		/* FIXME: '~' */
+	[43]	 = KEY_BACKSLASH,
 	[44]	 = KEY_Z,
 	[45]	 = KEY_X,
 	[46]	 = KEY_C,
@@ -149,45 +148,34 @@
 	[66]	 = KEY_F8,
 	[67]	 = KEY_F9,
 	[68]	 = KEY_F10,
-	[69]	 = KEY_ESC,
-	[70]	 = KEY_DELETE,
-	[71]	 = KEY_KP7,
-	[72]	 = KEY_KP8,
-	[73]	 = KEY_KP9,
+	[71]	 = KEY_HOME,
+	[72]	 = KEY_UP,
 	[74]	 = KEY_KPMINUS,
-	[75]	 = KEY_KP4,
-	[76]	 = KEY_KP5,
-	[77]	 = KEY_KP6,
+	[75]	 = KEY_LEFT,
+	[77]	 = KEY_RIGHT,
 	[78]	 = KEY_KPPLUS,
-	[79]	 = KEY_KP1,
-	[80]	 = KEY_KP2,
-	[81]	 = KEY_KP3,
-	[82]	 = KEY_KP0,
-	[83]	 = KEY_KPDOT,
-	[90]	 = KEY_KPLEFTPAREN,
-	[91]	 = KEY_KPRIGHTPAREN,
-	[92]	 = KEY_KPASTERISK,	/* FIXME */
-	[93]	 = KEY_KPASTERISK,
-	[94]	 = KEY_KPPLUS,
-	[95]	 = KEY_HELP,
+	[80]	 = KEY_DOWN,
+	[82]	 = KEY_INSERT,
+	[83]	 = KEY_DELETE,
 	[96]	 = KEY_102ND,
-	[97]	 = KEY_KPASTERISK,	/* FIXME */
-	[98]	 = KEY_KPSLASH,
+	[97]	 = KEY_UNDO,
+	[98]	 = KEY_HELP,
 	[99]	 = KEY_KPLEFTPAREN,
 	[100]	 = KEY_KPRIGHTPAREN,
 	[101]	 = KEY_KPSLASH,
 	[102]	 = KEY_KPASTERISK,
-	[103]	 = KEY_UP,
-	[104]	 = KEY_KPASTERISK,	/* FIXME */
-	[105]	 = KEY_LEFT,
-	[106]	 = KEY_RIGHT,
-	[107]	 = KEY_KPASTERISK,	/* FIXME */
-	[108]	 = KEY_DOWN,
-	[109]	 = KEY_KPASTERISK,	/* FIXME */
-	[110]	 = KEY_KPASTERISK,	/* FIXME */
-	[111]	 = KEY_KPASTERISK,	/* FIXME */
-	[112]	 = KEY_KPASTERISK,	/* FIXME */
-	[113]	 = KEY_KPASTERISK	/* FIXME */
+	[103]	 = KEY_KP7,
+	[104]	 = KEY_KP8,
+	[105]	 = KEY_KP9,
+	[106]	 = KEY_KP4,
+	[107]	 = KEY_KP5,
+	[108]	 = KEY_KP6,
+	[109]	 = KEY_KP1,
+	[110]	 = KEY_KP2,
+	[111]	 = KEY_KP3,
+	[112]	 = KEY_KP0,
+	[113]	 = KEY_KPDOT,
+	[114]	 = KEY_KPENTER,
 };
 
 static struct input_dev *atakbd_dev;
@@ -195,21 +183,15 @@
 static void atakbd_interrupt(unsigned char scancode, char down)
 {
 
-	if (scancode < 0x72) {		/* scancodes < 0xf2 are keys */
+	if (scancode < 0x73) {		/* scancodes < 0xf3 are keys */
 
 		// report raw events here?
 
 		scancode = atakbd_keycode[scancode];
 
-		if (scancode == KEY_CAPSLOCK) {	/* CapsLock is a toggle switch key on Amiga */
-			input_report_key(atakbd_dev, scancode, 1);
-			input_report_key(atakbd_dev, scancode, 0);
-			input_sync(atakbd_dev);
-		} else {
-			input_report_key(atakbd_dev, scancode, down);
-			input_sync(atakbd_dev);
-		}
-	} else				/* scancodes >= 0xf2 are mouse data, most likely */
+		input_report_key(atakbd_dev, scancode, down);
+		input_sync(atakbd_dev);
+	} else				/* scancodes >= 0xf3 are mouse data, most likely */
 		printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode);
 
 	return;
--- linux-4.4.0.orig/drivers/input/keyboard/cros_ec_keyb.c
+++ linux-4.4.0/drivers/input/keyboard/cros_ec_keyb.c
@@ -137,6 +137,7 @@
 					"changed: [r%d c%d]: byte %02x\n",
 					row, col, new_state);
 
+				input_event(idev, EV_MSC, MSC_SCAN, pos);
 				input_report_key(idev, keycodes[pos],
 						 new_state);
 			}
--- linux-4.4.0.orig/drivers/input/keyboard/ep93xx_keypad.c
+++ linux-4.4.0/drivers/input/keyboard/ep93xx_keypad.c
@@ -257,8 +257,8 @@
 	}
 
 	keypad->irq = platform_get_irq(pdev, 0);
-	if (!keypad->irq) {
-		err = -ENXIO;
+	if (keypad->irq < 0) {
+		err = keypad->irq;
 		goto failed_free;
 	}
 
--- linux-4.4.0.orig/drivers/input/keyboard/gpio_keys.c
+++ linux-4.4.0/drivers/input/keyboard/gpio_keys.c
@@ -96,7 +96,7 @@
  * Return value of this function can be used to allocate bitmap
  * large enough to hold all bits for given type.
  */
-static inline int get_n_events_by_type(int type)
+static int get_n_events_by_type(int type)
 {
 	BUG_ON(type != EV_SW && type != EV_KEY);
 
@@ -104,6 +104,22 @@
 }
 
 /**
+ * get_bm_events_by_type() - returns bitmap of supported events per @type
+ * @input: input device from which bitmap is retrieved
+ * @type: type of button (%EV_KEY, %EV_SW)
+ *
+ * Return value of this function can be used to allocate bitmap
+ * large enough to hold all bits for given type.
+ */
+static const unsigned long *get_bm_events_by_type(struct input_dev *dev,
+						  int type)
+{
+	BUG_ON(type != EV_SW && type != EV_KEY);
+
+	return (type == EV_KEY) ? dev->keybit : dev->swbit;
+}
+
+/**
  * gpio_keys_disable_button() - disables given GPIO button
  * @bdata: button data for button to be disabled
  *
@@ -213,6 +229,7 @@
 					   const char *buf, unsigned int type)
 {
 	int n_events = get_n_events_by_type(type);
+	const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
 	unsigned long *bits;
 	ssize_t error;
 	int i;
@@ -226,6 +243,11 @@
 		goto out;
 
 	/* First validate */
+	if (!bitmap_subset(bits, bitmap, n_events)) {
+		error = -EINVAL;
+		goto out;
+	}
+
 	for (i = 0; i < ddata->pdata->nbuttons; i++) {
 		struct gpio_button_data *bdata = &ddata->data[i];
 
@@ -239,11 +261,6 @@
 		}
 	}
 
-	if (i == ddata->pdata->nbuttons) {
-		error = -EINVAL;
-		goto out;
-	}
-
 	mutex_lock(&ddata->disable_lock);
 
 	for (i = 0; i < ddata->pdata->nbuttons; i++) {
--- linux-4.4.0.orig/drivers/input/keyboard/imx_keypad.c
+++ linux-4.4.0/drivers/input/keyboard/imx_keypad.c
@@ -530,11 +530,12 @@
 	return 0;
 }
 
-static int __maybe_unused imx_kbd_suspend(struct device *dev)
+static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct imx_keypad *kbd = platform_get_drvdata(pdev);
 	struct input_dev *input_dev = kbd->input_dev;
+	unsigned short reg_val = readw(kbd->mmio_base + KPSR);
 
 	/* imx kbd can wake up system even clock is disabled */
 	mutex_lock(&input_dev->mutex);
@@ -544,13 +545,20 @@
 
 	mutex_unlock(&input_dev->mutex);
 
-	if (device_may_wakeup(&pdev->dev))
+	if (device_may_wakeup(&pdev->dev)) {
+		if (reg_val & KBD_STAT_KPKD)
+			reg_val |= KBD_STAT_KRIE;
+		if (reg_val & KBD_STAT_KPKR)
+			reg_val |= KBD_STAT_KDIE;
+		writew(reg_val, kbd->mmio_base + KPSR);
+
 		enable_irq_wake(kbd->irq);
+	}
 
 	return 0;
 }
 
-static int __maybe_unused imx_kbd_resume(struct device *dev)
+static int __maybe_unused imx_kbd_noirq_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct imx_keypad *kbd = platform_get_drvdata(pdev);
@@ -574,7 +582,9 @@
 	return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
+static const struct dev_pm_ops imx_kbd_pm_ops = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_kbd_noirq_suspend, imx_kbd_noirq_resume)
+};
 
 static struct platform_driver imx_keypad_driver = {
 	.driver		= {
--- linux-4.4.0.orig/drivers/input/keyboard/matrix_keypad.c
+++ linux-4.4.0/drivers/input/keyboard/matrix_keypad.c
@@ -216,9 +216,11 @@
 {
 	struct matrix_keypad *keypad = input_get_drvdata(dev);
 
+	spin_lock_irq(&keypad->lock);
 	keypad->stopped = true;
-	mb();
-	flush_work(&keypad->work.work);
+	spin_unlock_irq(&keypad->lock);
+
+	flush_delayed_work(&keypad->work);
 	/*
 	 * matrix_keypad_scan() will leave IRQs enabled;
 	 * we should disable them now.
@@ -403,7 +405,7 @@
 	struct matrix_keypad_platform_data *pdata;
 	struct device_node *np = dev->of_node;
 	unsigned int *gpios;
-	int i, nrow, ncol;
+	int ret, i, nrow, ncol;
 
 	if (!np) {
 		dev_err(dev, "device lacks DT data\n");
@@ -445,12 +447,19 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
-	for (i = 0; i < pdata->num_row_gpios; i++)
-		gpios[i] = of_get_named_gpio(np, "row-gpios", i);
+	for (i = 0; i < nrow; i++) {
+		ret = of_get_named_gpio(np, "row-gpios", i);
+		if (ret < 0)
+			return ERR_PTR(ret);
+		gpios[i] = ret;
+	}
 
-	for (i = 0; i < pdata->num_col_gpios; i++)
-		gpios[pdata->num_row_gpios + i] =
-			of_get_named_gpio(np, "col-gpios", i);
+	for (i = 0; i < ncol; i++) {
+		ret = of_get_named_gpio(np, "col-gpios", i);
+		if (ret < 0)
+			return ERR_PTR(ret);
+		gpios[nrow + i] = ret;
+	}
 
 	pdata->row_gpios = gpios;
 	pdata->col_gpios = &gpios[pdata->num_row_gpios];
@@ -477,10 +486,8 @@
 	pdata = dev_get_platdata(&pdev->dev);
 	if (!pdata) {
 		pdata = matrix_keypad_parse_dt(&pdev->dev);
-		if (IS_ERR(pdata)) {
-			dev_err(&pdev->dev, "no platform data defined\n");
+		if (IS_ERR(pdata))
 			return PTR_ERR(pdata);
-		}
 	} else if (!pdata->keymap_data) {
 		dev_err(&pdev->dev, "no keymap data defined\n");
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/input/keyboard/mpr121_touchkey.c
+++ linux-4.4.0/drivers/input/keyboard/mpr121_touchkey.c
@@ -87,7 +87,8 @@
 	struct mpr121_touchkey *mpr121 = dev_id;
 	struct i2c_client *client = mpr121->client;
 	struct input_dev *input = mpr121->input_dev;
-	unsigned int key_num, key_val, pressed;
+	unsigned long bit_changed;
+	unsigned int key_num;
 	int reg;
 
 	reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
@@ -105,18 +106,22 @@
 
 	reg &= TOUCH_STATUS_MASK;
 	/* use old press bit to figure out which bit changed */
-	key_num = ffs(reg ^ mpr121->statusbits) - 1;
-	pressed = reg & (1 << key_num);
+	bit_changed = reg ^ mpr121->statusbits;
 	mpr121->statusbits = reg;
+	for_each_set_bit(key_num, &bit_changed, mpr121->keycount) {
+		unsigned int key_val, pressed;
 
-	key_val = mpr121->keycodes[key_num];
+		pressed = reg & BIT(key_num);
+		key_val = mpr121->keycodes[key_num];
 
-	input_event(input, EV_MSC, MSC_SCAN, key_num);
-	input_report_key(input, key_val, pressed);
-	input_sync(input);
+		input_event(input, EV_MSC, MSC_SCAN, key_num);
+		input_report_key(input, key_val, pressed);
+
+		dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
+			pressed ? "pressed" : "released");
 
-	dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
-		pressed ? "pressed" : "released");
+	}
+	input_sync(input);
 
 out:
 	return IRQ_HANDLED;
@@ -231,6 +236,7 @@
 	input_dev->id.bustype = BUS_I2C;
 	input_dev->dev.parent = &client->dev;
 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 
 	input_dev->keycode = mpr121->keycodes;
 	input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
--- linux-4.4.0.orig/drivers/input/keyboard/nomadik-ske-keypad.c
+++ linux-4.4.0/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -100,7 +100,7 @@
 	while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
 		cpu_relax();
 
-	if (!timeout)
+	if (timeout == -1)
 		return -EINVAL;
 
 	/*
--- linux-4.4.0.orig/drivers/input/keyboard/omap4-keypad.c
+++ linux-4.4.0/drivers/input/keyboard/omap4-keypad.c
@@ -60,8 +60,18 @@
 
 /* OMAP4 values */
 #define OMAP4_VAL_IRQDISABLE		0x0
-#define OMAP4_VAL_DEBOUNCINGTIME	0x7
-#define OMAP4_VAL_PVT			0x7
+
+/*
+ * Errata i689: If a key is released for a time shorter than debounce time,
+ * the keyboard will idle and never detect the key release. The workaround
+ * is to use at least a 12ms debounce time. See omap5432 TRM chapter
+ * "26.4.6.2 Keyboard Controller Timer" for more information.
+ */
+#define OMAP4_KEYPAD_PTV_DIV_128        0x6
+#define OMAP4_KEYPAD_DEBOUNCINGTIME_MS(dbms, ptv)     \
+	((((dbms) * 1000) / ((1 << ((ptv) + 1)) * (1000000 / 32768))) - 1)
+#define OMAP4_VAL_DEBOUNCINGTIME_16MS					\
+	OMAP4_KEYPAD_DEBOUNCINGTIME_MS(16, OMAP4_KEYPAD_PTV_DIV_128)
 
 enum {
 	KBD_REVISION_OMAP4 = 0,
@@ -116,12 +126,8 @@
 {
 	struct omap4_keypad *keypad_data = dev_id;
 
-	if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) {
-		/* Disable interrupts */
-		kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
-				 OMAP4_VAL_IRQDISABLE);
+	if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS))
 		return IRQ_WAKE_THREAD;
-	}
 
 	return IRQ_NONE;
 }
@@ -163,11 +169,6 @@
 	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
 			 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
 
-	/* enable interrupts */
-	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
-		OMAP4_DEF_IRQENABLE_EVENTEN |
-				OMAP4_DEF_IRQENABLE_LONGKEY);
-
 	return IRQ_HANDLED;
 }
 
@@ -181,9 +182,9 @@
 
 	kbd_writel(keypad_data, OMAP4_KBD_CTRL,
 			OMAP4_DEF_CTRL_NOSOFTMODE |
-			(OMAP4_VAL_PVT << OMAP4_DEF_CTRL_PTV_SHIFT));
+			(OMAP4_KEYPAD_PTV_DIV_128 << OMAP4_DEF_CTRL_PTV_SHIFT));
 	kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME,
-			OMAP4_VAL_DEBOUNCINGTIME);
+			OMAP4_VAL_DEBOUNCINGTIME_16MS);
 	/* clear pending interrupts */
 	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
 			 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
@@ -204,9 +205,10 @@
 
 	disable_irq(keypad_data->irq);
 
-	/* Disable interrupts */
+	/* Disable interrupts and wake-up events */
 	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
 			 OMAP4_VAL_IRQDISABLE);
+	kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE, 0);
 
 	/* clear pending interrupts */
 	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
@@ -251,10 +253,8 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		dev_err(&pdev->dev, "no keyboard irq assigned\n");
-		return -EINVAL;
-	}
+	if (irq < 0)
+		return irq;
 
 	keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);
 	if (!keypad_data) {
@@ -354,7 +354,7 @@
 	}
 
 	error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
-				     omap4_keypad_irq_thread_fn, 0,
+				     omap4_keypad_irq_thread_fn, IRQF_ONESHOT,
 				     "omap4-keypad", keypad_data);
 	if (error) {
 		dev_err(&pdev->dev, "failed to register interrupt\n");
--- linux-4.4.0.orig/drivers/input/keyboard/qt1070.c
+++ linux-4.4.0/drivers/input/keyboard/qt1070.c
@@ -274,9 +274,18 @@
 };
 MODULE_DEVICE_TABLE(i2c, qt1070_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id qt1070_of_match[] = {
+	{ .compatible = "qt1070", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, qt1070_of_match);
+#endif
+
 static struct i2c_driver qt1070_driver = {
 	.driver	= {
 		.name	= "qt1070",
+		.of_match_table = of_match_ptr(qt1070_of_match),
 		.pm	= &qt1070_pm_ops,
 	},
 	.id_table	= qt1070_id,
--- linux-4.4.0.orig/drivers/input/keyboard/snvs_pwrkey.c
+++ linux-4.4.0/drivers/input/keyboard/snvs_pwrkey.c
@@ -156,6 +156,9 @@
 		return error;
 	}
 
+	pdata->input = input;
+	platform_set_drvdata(pdev, pdata);
+
 	error = devm_request_irq(&pdev->dev, pdata->irq,
 			       imx_snvs_pwrkey_interrupt,
 			       0, pdev->name, pdev);
@@ -172,9 +175,6 @@
 		return error;
 	}
 
-	pdata->input = input;
-	platform_set_drvdata(pdev, pdata);
-
 	device_init_wakeup(&pdev->dev, pdata->wakeup);
 
 	return 0;
--- linux-4.4.0.orig/drivers/input/keyboard/st-keyscan.c
+++ linux-4.4.0/drivers/input/keyboard/st-keyscan.c
@@ -153,6 +153,8 @@
 
 	input_dev->id.bustype = BUS_HOST;
 
+	keypad_data->input_dev = input_dev;
+
 	error = keypad_matrix_key_parse_dt(keypad_data);
 	if (error)
 		return error;
@@ -168,8 +170,6 @@
 
 	input_set_drvdata(input_dev, keypad_data);
 
-	keypad_data->input_dev = input_dev;
-
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(keypad_data->base))
--- linux-4.4.0.orig/drivers/input/keyboard/sunkbd.c
+++ linux-4.4.0/drivers/input/keyboard/sunkbd.c
@@ -115,7 +115,8 @@
 	switch (data) {
 
 	case SUNKBD_RET_RESET:
-		schedule_work(&sunkbd->tq);
+		if (sunkbd->enabled)
+			schedule_work(&sunkbd->tq);
 		sunkbd->reset = -1;
 		break;
 
@@ -216,16 +217,12 @@
 }
 
 /*
- * sunkbd_reinit() sets leds and beeps to a state the computer remembers they
- * were in.
+ * sunkbd_set_leds_beeps() sets leds and beeps to a state the computer remembers
+ * they were in.
  */
 
-static void sunkbd_reinit(struct work_struct *work)
+static void sunkbd_set_leds_beeps(struct sunkbd *sunkbd)
 {
-	struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq);
-
-	wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
-
 	serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
 	serio_write(sunkbd->serio,
 		(!!test_bit(LED_CAPSL,   sunkbd->dev->led) << 3) |
@@ -238,11 +235,39 @@
 		SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
 }
 
+
+/*
+ * sunkbd_reinit() wait for the keyboard reset to complete and restores state
+ * of leds and beeps.
+ */
+
+static void sunkbd_reinit(struct work_struct *work)
+{
+	struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq);
+
+	/*
+	 * It is OK that we check sunkbd->enabled without pausing serio,
+	 * as we only want to catch true->false transition that will
+	 * happen once and we will be woken up for it.
+	 */
+	wait_event_interruptible_timeout(sunkbd->wait,
+					 sunkbd->reset >= 0 || !sunkbd->enabled,
+					 HZ);
+
+	if (sunkbd->reset >= 0 && sunkbd->enabled)
+		sunkbd_set_leds_beeps(sunkbd);
+}
+
 static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
 {
 	serio_pause_rx(sunkbd->serio);
 	sunkbd->enabled = enable;
 	serio_continue_rx(sunkbd->serio);
+
+	if (!enable) {
+		wake_up_interruptible(&sunkbd->wait);
+		cancel_work_sync(&sunkbd->tq);
+	}
 }
 
 /*
--- linux-4.4.0.orig/drivers/input/keyboard/tca8418_keypad.c
+++ linux-4.4.0/drivers/input/keyboard/tca8418_keypad.c
@@ -164,11 +164,18 @@
 	int error, col, row;
 	u8 reg, state, code;
 
-	/* Initial read of the key event FIFO */
-	error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+	do {
+		error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+		if (error < 0) {
+			dev_err(&keypad_data->client->dev,
+				"unable to read REG_KEY_EVENT_A\n");
+			break;
+		}
+
+		/* Assume that key code 0 signifies empty FIFO */
+		if (reg <= 0)
+			break;
 
-	/* Assume that key code 0 signifies empty FIFO */
-	while (error >= 0 && reg > 0) {
 		state = reg & KEY_EVENT_VALUE;
 		code  = reg & KEY_EVENT_CODE;
 
@@ -182,13 +189,7 @@
 		input_event(input, EV_MSC, MSC_SCAN, code);
 		input_report_key(input, keymap[code], state);
 
-		/* Read for next loop */
-		error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
-	}
-
-	if (error < 0)
-		dev_err(&keypad_data->client->dev,
-			"unable to read REG_KEY_EVENT_A\n");
+	} while (1);
 
 	input_sync(input);
 }
--- linux-4.4.0.orig/drivers/input/keyboard/tegra-kbc.c
+++ linux-4.4.0/drivers/input/keyboard/tegra-kbc.c
@@ -376,7 +376,7 @@
 	/* Reset the KBC controller to clear all previous status.*/
 	reset_control_assert(kbc->rst);
 	udelay(100);
-	reset_control_assert(kbc->rst);
+	reset_control_deassert(kbc->rst);
 	udelay(100);
 
 	tegra_kbc_config_pins(kbc);
--- linux-4.4.0.orig/drivers/input/misc/adxl34x.c
+++ linux-4.4.0/drivers/input/misc/adxl34x.c
@@ -696,7 +696,7 @@
 	struct input_dev *input_dev;
 	const struct adxl34x_platform_data *pdata;
 	int err, range, i;
-	unsigned char revid;
+	int revid;
 
 	if (!irq) {
 		dev_err(dev, "no IRQ?\n");
--- linux-4.4.0.orig/drivers/input/misc/ati_remote2.c
+++ linux-4.4.0/drivers/input/misc/ati_remote2.c
@@ -817,26 +817,49 @@
 
 	ar2->udev = udev;
 
+	/* Sanity check, first interface must have an endpoint */
+	if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
+		dev_err(&interface->dev,
+			"%s(): interface 0 must have an endpoint\n", __func__);
+		r = -ENODEV;
+		goto fail1;
+	}
 	ar2->intf[0] = interface;
 	ar2->ep[0] = &alt->endpoint[0].desc;
 
+	/* Sanity check, the device must have two interfaces */
 	ar2->intf[1] = usb_ifnum_to_if(udev, 1);
+	if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) {
+		dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n",
+			__func__, udev->actconfig->desc.bNumInterfaces);
+		r = -ENODEV;
+		goto fail1;
+	}
+
 	r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
 	if (r)
 		goto fail1;
+
+	/* Sanity check, second interface must have an endpoint */
 	alt = ar2->intf[1]->cur_altsetting;
+	if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
+		dev_err(&interface->dev,
+			"%s(): interface 1 must have an endpoint\n", __func__);
+		r = -ENODEV;
+		goto fail2;
+	}
 	ar2->ep[1] = &alt->endpoint[0].desc;
 
 	r = ati_remote2_urb_init(ar2);
 	if (r)
-		goto fail2;
+		goto fail3;
 
 	ar2->channel_mask = channel_mask;
 	ar2->mode_mask = mode_mask;
 
 	r = ati_remote2_setup(ar2, ar2->channel_mask);
 	if (r)
-		goto fail2;
+		goto fail3;
 
 	usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
 	strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
@@ -845,11 +868,11 @@
 
 	r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);
 	if (r)
-		goto fail2;
+		goto fail3;
 
 	r = ati_remote2_input_init(ar2);
 	if (r)
-		goto fail3;
+		goto fail4;
 
 	usb_set_intfdata(interface, ar2);
 
@@ -857,10 +880,11 @@
 
 	return 0;
 
- fail3:
+ fail4:
 	sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);
- fail2:
+ fail3:
 	ati_remote2_urb_cleanup(ar2);
+ fail2:
 	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
  fail1:
 	kfree(ar2);
--- linux-4.4.0.orig/drivers/input/misc/bma150.c
+++ linux-4.4.0/drivers/input/misc/bma150.c
@@ -482,13 +482,14 @@
 	idev->close = bma150_irq_close;
 	input_set_drvdata(idev, bma150);
 
+	bma150->input = idev;
+
 	error = input_register_device(idev);
 	if (error) {
 		input_free_device(idev);
 		return error;
 	}
 
-	bma150->input = idev;
 	return 0;
 }
 
@@ -511,15 +512,15 @@
 
 	bma150_init_input_device(bma150, ipoll_dev->input);
 
+	bma150->input_polled = ipoll_dev;
+	bma150->input = ipoll_dev->input;
+
 	error = input_register_polled_device(ipoll_dev);
 	if (error) {
 		input_free_polled_device(ipoll_dev);
 		return error;
 	}
 
-	bma150->input_polled = ipoll_dev;
-	bma150->input = ipoll_dev->input;
-
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/input/misc/cm109.c
+++ linux-4.4.0/drivers/input/misc/cm109.c
@@ -546,12 +546,15 @@
 	dev->ctl_data->byte[HID_OR2] = dev->keybit;
 	dev->ctl_data->byte[HID_OR3] = 0x00;
 
+	dev->ctl_urb_pending = 1;
 	error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
-	if (error)
+	if (error) {
+		dev->ctl_urb_pending = 0;
 		dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n",
 			__func__, error);
-	else
+	} else {
 		dev->open = 1;
+	}
 
 	mutex_unlock(&dev->pm_mutex);
 
@@ -675,6 +678,10 @@
 	int error = -ENOMEM;
 
 	interface = intf->cur_altsetting;
+
+	if (interface->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	endpoint = &interface->endpoint[0].desc;
 
 	if (!usb_endpoint_is_int_in(endpoint))
--- linux-4.4.0.orig/drivers/input/misc/drv260x.c
+++ linux-4.4.0/drivers/input/misc/drv260x.c
@@ -521,7 +521,7 @@
 	if (!haptics)
 		return -ENOMEM;
 
-	haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
+	haptics->overdrive_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
 	haptics->rated_voltage = DRV260X_DEF_RATED_VOLT;
 
 	if (pdata) {
@@ -592,7 +592,6 @@
 	}
 
 	haptics->input_dev->name = "drv260x:haptics";
-	haptics->input_dev->dev.parent = client->dev.parent;
 	haptics->input_dev->close = drv260x_close;
 	input_set_drvdata(haptics->input_dev, haptics);
 	input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
--- linux-4.4.0.orig/drivers/input/misc/ims-pcu.c
+++ linux-4.4.0/drivers/input/misc/ims-pcu.c
@@ -1635,13 +1635,25 @@
 		return NULL;
 	}
 
-	while (buflen > 0) {
+	while (buflen >= sizeof(*union_desc)) {
 		union_desc = (struct usb_cdc_union_desc *)buf;
 
+		if (union_desc->bLength > buflen) {
+			dev_err(&intf->dev, "Too large descriptor\n");
+			return NULL;
+		}
+
 		if (union_desc->bDescriptorType == USB_DT_CS_INTERFACE &&
 		    union_desc->bDescriptorSubType == USB_CDC_UNION_TYPE) {
 			dev_dbg(&intf->dev, "Found union header\n");
-			return union_desc;
+
+			if (union_desc->bLength >= sizeof(*union_desc))
+				return union_desc;
+
+			dev_err(&intf->dev,
+				"Union descriptor to short (%d vs %zd\n)",
+				union_desc->bLength, sizeof(*union_desc));
+			return NULL;
 		}
 
 		buflen -= union_desc->bLength;
@@ -1663,13 +1675,21 @@
 
 	pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev,
 					 union_desc->bMasterInterface0);
+	if (!pcu->ctrl_intf)
+		return -EINVAL;
 
 	alt = pcu->ctrl_intf->cur_altsetting;
+
+	if (alt->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	pcu->ep_ctrl = &alt->endpoint[0].desc;
 	pcu->max_ctrl_size = usb_endpoint_maxp(pcu->ep_ctrl);
 
 	pcu->data_intf = usb_ifnum_to_if(pcu->udev,
 					 union_desc->bSlaveInterface0);
+	if (!pcu->data_intf)
+		return -EINVAL;
 
 	alt = pcu->data_intf->cur_altsetting;
 	if (alt->desc.bNumEndpoints != 2) {
--- linux-4.4.0.orig/drivers/input/misc/keyspan_remote.c
+++ linux-4.4.0/drivers/input/misc/keyspan_remote.c
@@ -344,7 +344,8 @@
 	int retval = 0;
 
 	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-				 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0);
+				 0x11, 0x40, 0x5601, 0x0, NULL, 0,
+				 USB_CTRL_SET_TIMEOUT);
 	if (retval) {
 		dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n",
 			__func__, retval);
@@ -352,7 +353,8 @@
 	}
 
 	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-				 0x44, 0x40, 0x0, 0x0, NULL, 0, 0);
+				 0x44, 0x40, 0x0, 0x0, NULL, 0,
+				 USB_CTRL_SET_TIMEOUT);
 	if (retval) {
 		dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n",
 			__func__, retval);
@@ -360,7 +362,8 @@
 	}
 
 	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-				 0x22, 0x40, 0x0, 0x0, NULL, 0, 0);
+				 0x22, 0x40, 0x0, 0x0, NULL, 0,
+				 USB_CTRL_SET_TIMEOUT);
 	if (retval) {
 		dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n",
 			__func__, retval);
--- linux-4.4.0.orig/drivers/input/misc/max8997_haptic.c
+++ linux-4.4.0/drivers/input/misc/max8997_haptic.c
@@ -255,12 +255,14 @@
 	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
 	const struct max8997_platform_data *pdata =
 					dev_get_platdata(iodev->dev);
-	const struct max8997_haptic_platform_data *haptic_pdata =
-					pdata->haptic_pdata;
+	const struct max8997_haptic_platform_data *haptic_pdata = NULL;
 	struct max8997_haptic *chip;
 	struct input_dev *input_dev;
 	int error;
 
+	if (pdata)
+		haptic_pdata = pdata->haptic_pdata;
+
 	if (!haptic_pdata) {
 		dev_err(&pdev->dev, "no haptic platform data\n");
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/input/misc/pmic8xxx-pwrkey.c
+++ linux-4.4.0/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -353,7 +353,8 @@
 	if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
 		kpd_delay = 15625;
 
-	if (kpd_delay > 62500 || kpd_delay == 0) {
+	/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
+	if (kpd_delay > USEC_PER_SEC * 2 || kpd_delay < USEC_PER_SEC / 64) {
 		dev_err(&pdev->dev, "invalid power key trigger delay\n");
 		return -EINVAL;
 	}
@@ -385,8 +386,8 @@
 	pwr->name = "pmic8xxx_pwrkey";
 	pwr->phys = "pmic8xxx_pwrkey/input0";
 
-	delay = (kpd_delay << 10) / USEC_PER_SEC;
-	delay = 1 + ilog2(delay);
+	delay = (kpd_delay << 6) / USEC_PER_SEC;
+	delay = ilog2(delay);
 
 	err = regmap_read(regmap, PON_CNTL_1, &pon_cntl);
 	if (err < 0) {
--- linux-4.4.0.orig/drivers/input/misc/powermate.c
+++ linux-4.4.0/drivers/input/misc/powermate.c
@@ -307,6 +307,9 @@
 	int error = -ENOMEM;
 
 	interface = intf->cur_altsetting;
+	if (interface->desc.bNumEndpoints < 1)
+		return -EINVAL;
+
 	endpoint = &interface->endpoint[0].desc;
 	if (!usb_endpoint_is_int_in(endpoint))
 		return -EIO;
--- linux-4.4.0.orig/drivers/input/misc/pwm-beeper.c
+++ linux-4.4.0/drivers/input/misc/pwm-beeper.c
@@ -20,21 +20,40 @@
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 
 struct pwm_beeper {
 	struct input_dev *input;
 	struct pwm_device *pwm;
+	struct work_struct work;
 	unsigned long period;
 };
 
 #define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
 
+static void __pwm_beeper_set(struct pwm_beeper *beeper)
+{
+	unsigned long period = beeper->period;
+
+	if (period) {
+		pwm_config(beeper->pwm, period / 2, period);
+		pwm_enable(beeper->pwm);
+	} else
+		pwm_disable(beeper->pwm);
+}
+
+static void pwm_beeper_work(struct work_struct *work)
+{
+	struct pwm_beeper *beeper =
+		container_of(work, struct pwm_beeper, work);
+
+	__pwm_beeper_set(beeper);
+}
+
 static int pwm_beeper_event(struct input_dev *input,
 			    unsigned int type, unsigned int code, int value)
 {
-	int ret = 0;
 	struct pwm_beeper *beeper = input_get_drvdata(input);
-	unsigned long period;
 
 	if (type != EV_SND || value < 0)
 		return -EINVAL;
@@ -49,22 +68,31 @@
 		return -EINVAL;
 	}
 
-	if (value == 0) {
-		pwm_disable(beeper->pwm);
-	} else {
-		period = HZ_TO_NANOSECONDS(value);
-		ret = pwm_config(beeper->pwm, period / 2, period);
-		if (ret)
-			return ret;
-		ret = pwm_enable(beeper->pwm);
-		if (ret)
-			return ret;
-		beeper->period = period;
-	}
+	if (value == 0)
+		beeper->period = 0;
+	else
+		beeper->period = HZ_TO_NANOSECONDS(value);
+
+	schedule_work(&beeper->work);
 
 	return 0;
 }
 
+static void pwm_beeper_stop(struct pwm_beeper *beeper)
+{
+	cancel_work_sync(&beeper->work);
+
+	if (beeper->period)
+		pwm_disable(beeper->pwm);
+}
+
+static void pwm_beeper_close(struct input_dev *input)
+{
+	struct pwm_beeper *beeper = input_get_drvdata(input);
+
+	pwm_beeper_stop(beeper);
+}
+
 static int pwm_beeper_probe(struct platform_device *pdev)
 {
 	unsigned long pwm_id = (unsigned long)dev_get_platdata(&pdev->dev);
@@ -87,6 +115,8 @@
 		goto err_free;
 	}
 
+	INIT_WORK(&beeper->work, pwm_beeper_work);
+
 	beeper->input = input_allocate_device();
 	if (!beeper->input) {
 		dev_err(&pdev->dev, "Failed to allocate input device\n");
@@ -106,6 +136,7 @@
 	beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
 
 	beeper->input->event = pwm_beeper_event;
+	beeper->input->close = pwm_beeper_close;
 
 	input_set_drvdata(beeper->input, beeper);
 
@@ -135,7 +166,6 @@
 
 	input_unregister_device(beeper->input);
 
-	pwm_disable(beeper->pwm);
 	pwm_free(beeper->pwm);
 
 	kfree(beeper);
@@ -147,8 +177,7 @@
 {
 	struct pwm_beeper *beeper = dev_get_drvdata(dev);
 
-	if (beeper->period)
-		pwm_disable(beeper->pwm);
+	pwm_beeper_stop(beeper);
 
 	return 0;
 }
@@ -157,10 +186,8 @@
 {
 	struct pwm_beeper *beeper = dev_get_drvdata(dev);
 
-	if (beeper->period) {
-		pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
-		pwm_enable(beeper->pwm);
-	}
+	if (beeper->period)
+		__pwm_beeper_set(beeper);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/input/misc/twl4030-pwrbutton.c
+++ linux-4.4.0/drivers/input/misc/twl4030-pwrbutton.c
@@ -70,7 +70,7 @@
 	pwr->phys = "twl4030_pwrbutton/input0";
 	pwr->dev.parent = &pdev->dev;
 
-	err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq,
+	err = devm_request_threaded_irq(&pdev->dev, irq, NULL, powerbutton_irq,
 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
 			IRQF_ONESHOT,
 			"twl4030_pwrbutton", pwr);
--- linux-4.4.0.orig/drivers/input/misc/twl4030-vibra.c
+++ linux-4.4.0/drivers/input/misc/twl4030-vibra.c
@@ -178,12 +178,14 @@
 			 twl4030_vibra_suspend, twl4030_vibra_resume);
 
 static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
-			      struct device_node *node)
+			      struct device_node *parent)
 {
+	struct device_node *node;
+
 	if (pdata && pdata->coexist)
 		return true;
 
-	node = of_find_node_by_name(node, "codec");
+	node = of_get_child_by_name(parent, "codec");
 	if (node) {
 		of_node_put(node);
 		return true;
--- linux-4.4.0.orig/drivers/input/misc/twl6040-vibra.c
+++ linux-4.4.0/drivers/input/misc/twl6040-vibra.c
@@ -262,7 +262,7 @@
 	int vddvibr_uV = 0;
 	int error;
 
-	twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
+	twl6040_core_node = of_get_child_by_name(twl6040_core_dev->of_node,
 						 "vibra");
 	if (!twl6040_core_node) {
 		dev_err(&pdev->dev, "parent of node is missing?\n");
--- linux-4.4.0.orig/drivers/input/misc/uinput.c
+++ linux-4.4.0/drivers/input/misc/uinput.c
@@ -230,6 +230,18 @@
 	return uinput_request_submit(udev, &request);
 }
 
+static int uinput_dev_flush(struct input_dev *dev, struct file *file)
+{
+	/*
+	 * If we are called with file == NULL that means we are tearing
+	 * down the device, and therefore we can not handle FF erase
+	 * requests: either we are handling UI_DEV_DESTROY (and holding
+	 * the udev->mutex), or the file descriptor is closed and there is
+	 * nobody on the other side anymore.
+	 */
+	return file ? input_ff_flush(dev, file) : 0;
+}
+
 static void uinput_destroy_device(struct uinput_device *udev)
 {
 	const char *name, *phys;
@@ -273,6 +285,12 @@
 		dev->ff->playback = uinput_dev_playback;
 		dev->ff->set_gain = uinput_dev_set_gain;
 		dev->ff->set_autocenter = uinput_dev_set_autocenter;
+		/*
+		 * The standard input_ff_flush() implementation does
+		 * not quite work for uinput as we can't reasonably
+		 * handle FF requests during device teardown.
+		 */
+		dev->flush = uinput_dev_flush;
 	}
 
 	error = input_register_device(udev->dev);
@@ -893,9 +911,33 @@
 }
 
 #ifdef CONFIG_COMPAT
+
+/*
+ * These IOCTLs change their size and thus their numbers between
+ * 32 and 64 bits.
+ */
+#define UI_SET_PHYS_COMPAT		\
+	_IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
+#define UI_BEGIN_FF_UPLOAD_COMPAT	\
+	_IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload_compat)
+#define UI_END_FF_UPLOAD_COMPAT		\
+	_IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload_compat)
+
 static long uinput_compat_ioctl(struct file *file,
 				unsigned int cmd, unsigned long arg)
 {
+	switch (cmd) {
+	case UI_SET_PHYS_COMPAT:
+		cmd = UI_SET_PHYS;
+		break;
+	case UI_BEGIN_FF_UPLOAD_COMPAT:
+		cmd = UI_BEGIN_FF_UPLOAD;
+		break;
+	case UI_END_FF_UPLOAD_COMPAT:
+		cmd = UI_END_FF_UPLOAD;
+		break;
+	}
+
 	return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
 }
 #endif
--- linux-4.4.0.orig/drivers/input/misc/yealink.c
+++ linux-4.4.0/drivers/input/misc/yealink.c
@@ -875,6 +875,10 @@
 	int ret, pipe, i;
 
 	interface = intf->cur_altsetting;
+
+	if (interface->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	endpoint = &interface->endpoint[0].desc;
 	if (!usb_endpoint_is_int_in(endpoint))
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/input/mouse/alps.c
+++ linux-4.4.0/drivers/input/mouse/alps.c
@@ -102,6 +102,7 @@
 					   6-byte ALPS packet */
 #define ALPS_STICK_BITS		0x100	/* separate stick button bits */
 #define ALPS_BUTTONPAD		0x200	/* device is a clickpad */
+#define ALPS_DUALPOINT_WITH_PRESSURE	0x400	/* device can report trackpoint pressure */
 
 static const struct alps_model_info alps_model_data[] = {
 	{ { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } },	/* Toshiba Salellite Pro M10 */
@@ -1155,15 +1156,28 @@
 {
 	unsigned char pkt_id = SS4_PACKET_ID_IDLE;
 
-	if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
-	    (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && byte[5] == 0x00) {
-		pkt_id = SS4_PACKET_ID_IDLE;
-	} else if (!(byte[3] & 0x10)) {
-		pkt_id = SS4_PACKET_ID_ONE;
-	} else if (!(byte[3] & 0x20)) {
+	switch (byte[3] & 0x30) {
+	case 0x00:
+		if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
+		    (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
+		    byte[5] == 0x00) {
+			pkt_id = SS4_PACKET_ID_IDLE;
+		} else {
+			pkt_id = SS4_PACKET_ID_ONE;
+		}
+		break;
+	case 0x10:
+		/* two-finger finger positions */
 		pkt_id = SS4_PACKET_ID_TWO;
-	} else {
+		break;
+	case 0x20:
+		/* stick pointer */
+		pkt_id = SS4_PACKET_ID_STICK;
+		break;
+	case 0x30:
+		/* third and fourth finger positions */
 		pkt_id = SS4_PACKET_ID_MULTI;
+		break;
 	}
 
 	return pkt_id;
@@ -1184,7 +1198,13 @@
 		f->mt[0].x = SS4_1F_X_V2(p);
 		f->mt[0].y = SS4_1F_Y_V2(p);
 		f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f;
-		f->fingers = 1;
+		/*
+		 * When a button is held the device will give us events
+		 * with x, y, and pressure of 0. This causes annoying jumps
+		 * if a touch is released while the button is held.
+		 * Handle this by claiming zero contacts.
+		 */
+		f->fingers = f->pressure > 0 ? 1 : 0;
 		f->first_mp = 0;
 		f->is_mp = 0;
 		break;
@@ -1245,16 +1265,40 @@
 		}
 		break;
 
+	case SS4_PACKET_ID_STICK:
+		if (!(priv->flags & ALPS_DUALPOINT)) {
+			psmouse_warn(psmouse,
+				     "Rejected trackstick packet from non DualPoint device");
+		} else {
+			int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f));
+			int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f));
+			int pressure = (s8)(p[4] & 0x7f);
+
+			input_report_rel(priv->dev2, REL_X, x);
+			input_report_rel(priv->dev2, REL_Y, -y);
+			input_report_abs(priv->dev2, ABS_PRESSURE, pressure);
+		}
+		break;
+
 	case SS4_PACKET_ID_IDLE:
 	default:
 		memset(f, 0, sizeof(struct alps_fields));
 		break;
 	}
 
-	f->left = !!(SS4_BTN_V2(p) & 0x01);
-	if (!(priv->flags & ALPS_BUTTONPAD)) {
-		f->right = !!(SS4_BTN_V2(p) & 0x02);
-		f->middle = !!(SS4_BTN_V2(p) & 0x04);
+	/* handle buttons */
+	if (pkt_id == SS4_PACKET_ID_STICK) {
+		f->ts_left = !!(SS4_BTN_V2(p) & 0x01);
+		if (!(priv->flags & ALPS_BUTTONPAD)) {
+			f->ts_right = !!(SS4_BTN_V2(p) & 0x02);
+			f->ts_middle = !!(SS4_BTN_V2(p) & 0x04);
+		}
+	} else {
+		f->left = !!(SS4_BTN_V2(p) & 0x01);
+		if (!(priv->flags & ALPS_BUTTONPAD)) {
+			f->right = !!(SS4_BTN_V2(p) & 0x02);
+			f->middle = !!(SS4_BTN_V2(p) & 0x04);
+		}
 	}
 
 	return 0;
@@ -1265,6 +1309,7 @@
 	struct alps_data *priv = psmouse->private;
 	unsigned char *packet = psmouse->packet;
 	struct input_dev *dev = psmouse->dev;
+	struct input_dev *dev2 = priv->dev2;
 	struct alps_fields *f = &priv->f;
 
 	memset(f, 0, sizeof(struct alps_fields));
@@ -1310,6 +1355,13 @@
 
 	input_report_abs(dev, ABS_PRESSURE, f->pressure);
 	input_sync(dev);
+
+	if (priv->flags & ALPS_DUALPOINT) {
+		input_report_key(dev2, BTN_LEFT, f->ts_left);
+		input_report_key(dev2, BTN_RIGHT, f->ts_right);
+		input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
+		input_sync(dev2);
+	}
 }
 
 static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
@@ -2406,14 +2458,34 @@
 	int num_y_electrode;
 	int x_pitch, y_pitch, x_phys, y_phys;
 
-	num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
-	num_y_electrode = SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F);
+	if (IS_SS4PLUS_DEV(priv->dev_id)) {
+		num_x_electrode =
+			SS4PLUS_NUMSENSOR_XOFFSET + (otp[0][2] & 0x0F);
+		num_y_electrode =
+			SS4PLUS_NUMSENSOR_YOFFSET + ((otp[0][2] >> 4) & 0x0F);
+
+		priv->x_max =
+			(num_x_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE;
+		priv->y_max =
+			(num_y_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE;
 
-	priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
-	priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+		x_pitch = (otp[0][1] & 0x0F) + SS4PLUS_MIN_PITCH_MM;
+		y_pitch = ((otp[0][1] >> 4) & 0x0F) + SS4PLUS_MIN_PITCH_MM;
 
-	x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM;
-	y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM;
+	} else {
+		num_x_electrode =
+			SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
+		num_y_electrode =
+			SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F);
+
+		priv->x_max =
+			(num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+		priv->y_max =
+			(num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+
+		x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM;
+		y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM;
+	}
 
 	x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */
 	y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */
@@ -2429,7 +2501,10 @@
 {
 	unsigned char is_btnless;
 
-	is_btnless = (otp[1][1] >> 3) & 0x01;
+	if (IS_SS4PLUS_DEV(priv->dev_id))
+		is_btnless = (otp[1][0] >> 1) & 0x01;
+	else
+		is_btnless = (otp[1][1] >> 3) & 0x01;
 
 	if (is_btnless)
 		priv->flags |= ALPS_BUTTONPAD;
@@ -2437,6 +2512,21 @@
 	return 0;
 }
 
+static int alps_update_dual_info_ss4_v2(unsigned char otp[][4],
+				       struct alps_data *priv)
+{
+	bool is_dual = false;
+
+	if (IS_SS4PLUS_DEV(priv->dev_id))
+		is_dual = (otp[0][0] >> 4) & 0x01;
+
+	if (is_dual)
+		priv->flags |= ALPS_DUALPOINT |
+					ALPS_DUALPOINT_WITH_PRESSURE;
+
+	return 0;
+}
+
 static int alps_set_defaults_ss4_v2(struct psmouse *psmouse,
 				    struct alps_data *priv)
 {
@@ -2452,6 +2542,8 @@
 
 	alps_update_btn_info_ss4_v2(otp, priv);
 
+	alps_update_dual_info_ss4_v2(otp, priv);
+
 	return 0;
 }
 
@@ -2759,7 +2851,7 @@
 			   ec[2] >= 0x90 && ec[2] <= 0x9d) {
 			protocol = &alps_v3_protocol_data;
 		} else if (e7[0] == 0x73 && e7[1] == 0x03 &&
-			   e7[2] == 0x14 && ec[1] == 0x02) {
+			   (e7[2] == 0x14 || e7[2] == 0x28)) {
 			protocol = &alps_v8_protocol_data;
 		} else {
 			psmouse_dbg(psmouse,
@@ -2769,7 +2861,8 @@
 	}
 
 	if (priv) {
-		/* Save the Firmware version */
+		/* Save Device ID and Firmware version */
+		memcpy(priv->dev_id, e7, 3);
 		memcpy(priv->fw_ver, ec, 3);
 		error = alps_set_protocol(psmouse, priv, protocol);
 		if (error)
@@ -2943,6 +3036,10 @@
 
 		input_set_capability(dev2, EV_REL, REL_X);
 		input_set_capability(dev2, EV_REL, REL_Y);
+		if (priv->flags & ALPS_DUALPOINT_WITH_PRESSURE) {
+			input_set_capability(dev2, EV_ABS, ABS_PRESSURE);
+			input_set_abs_params(dev2, ABS_PRESSURE, 0, 127, 0, 0);
+		}
 		input_set_capability(dev2, EV_KEY, BTN_LEFT);
 		input_set_capability(dev2, EV_KEY, BTN_RIGHT);
 		input_set_capability(dev2, EV_KEY, BTN_MIDDLE);
--- linux-4.4.0.orig/drivers/input/mouse/alps.h
+++ linux-4.4.0/drivers/input/mouse/alps.h
@@ -37,12 +37,14 @@
  *  or there's button activities.
  * SS4_PACKET_ID_TWO: There's two or more fingers on touchpad
  * SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad
+ * SS4_PACKET_ID_STICK: A stick pointer packet
 */
 enum SS4_PACKET_ID {
 	SS4_PACKET_ID_IDLE = 0,
 	SS4_PACKET_ID_ONE,
 	SS4_PACKET_ID_TWO,
 	SS4_PACKET_ID_MULTI,
+	SS4_PACKET_ID_STICK,
 };
 
 #define SS4_COUNT_PER_ELECTRODE		256
@@ -52,7 +54,25 @@
 
 #define SS4_MASK_NORMAL_BUTTONS		0x07
 
-#define SS4_1F_X_V2(_b)		((_b[0] & 0x0007) |		\
+#define SS4PLUS_COUNT_PER_ELECTRODE	128
+#define SS4PLUS_NUMSENSOR_XOFFSET	16
+#define SS4PLUS_NUMSENSOR_YOFFSET	5
+#define SS4PLUS_MIN_PITCH_MM		37
+
+#define IS_SS4PLUS_DEV(_b)	(((_b[0]) == 0x73) &&	\
+				 ((_b[1]) == 0x03) &&	\
+				 ((_b[2]) == 0x28)		\
+				)
+
+#define SS4_IS_IDLE_V2(_b)	(((_b[0]) == 0x18) &&		\
+				 ((_b[1]) == 0x10) &&		\
+				 ((_b[2]) == 0x00) &&		\
+				 ((_b[3] & 0x88) == 0x08) &&	\
+				 ((_b[4]) == 0x10) &&		\
+				 ((_b[5]) == 0x00)		\
+				)
+
+#define SS4_1F_X_V2(_b)		(((_b[0]) & 0x0007) |		\
 				 ((_b[1] << 3) & 0x0078) |	\
 				 ((_b[1] << 2) & 0x0380) |	\
 				 ((_b[2] << 5) & 0x1C00)	\
@@ -261,6 +281,7 @@
 	int addr_command;
 	u16 proto_version;
 	u8 byte0, mask0;
+	u8 dev_id[3];
 	u8 fw_ver[3];
 	int flags;
 	int x_max;
--- linux-4.4.0.orig/drivers/input/mouse/appletouch.c
+++ linux-4.4.0/drivers/input/mouse/appletouch.c
@@ -929,6 +929,8 @@
 	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 	set_bit(BTN_LEFT, input_dev->keybit);
 
+	INIT_WORK(&dev->work, atp_reinit);
+
 	error = input_register_device(dev->input);
 	if (error)
 		goto err_free_buffer;
@@ -936,8 +938,6 @@
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(iface, dev);
 
-	INIT_WORK(&dev->work, atp_reinit);
-
 	return 0;
 
  err_free_buffer:
--- linux-4.4.0.orig/drivers/input/mouse/cyapa_gen6.c
+++ linux-4.4.0/drivers/input/mouse/cyapa_gen6.c
@@ -573,7 +573,7 @@
 
 	memset(&cmd, 0, sizeof(cmd));
 	put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd.head.addr);
-	put_unaligned_le16(sizeof(cmd), &cmd.head.length - 2);
+	put_unaligned_le16(sizeof(cmd) - 2, &cmd.head.length);
 	cmd.head.report_id = PIP_APP_CMD_REPORT_ID;
 	cmd.head.cmd_code = PIP_RETRIEVE_DATA_STRUCTURE;
 	put_unaligned_le16(read_offset, &cmd.read_offset);
--- linux-4.4.0.orig/drivers/input/mouse/cypress_ps2.c
+++ linux-4.4.0/drivers/input/mouse/cypress_ps2.c
@@ -390,7 +390,9 @@
 	if (ret < 0)
 		return ret;
 
+#if ( CYPRESS_SIMULATED_MT != 1 )
 	__set_bit(INPUT_PROP_SEMI_MT, input->propbit);
+#endif
 
 	input_abs_set_res(input, ABS_X, cytp->tp_res_x);
 	input_abs_set_res(input, ABS_Y, cytp->tp_res_y);
@@ -478,6 +480,22 @@
 			((packet[5] & 0x0f) << 8) | packet[7];
 		if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
 			report_data->contacts[1].z = report_data->contacts[0].z;
+#if ( CYPRESS_SIMULATED_MT == 1 )
+		/* simulate contact positions for >2 fingers */
+		if ( report_data->contact_cnt >= 3 ) {
+			int i;
+			for ( i=1; i<report_data->contact_cnt; i++ ) {
+			    report_data->contacts[i].x =
+					    report_data->contacts[0].x
+					    + 100*(i)*((i%2)?-1:1);
+			    report_data->contacts[i].y =
+					    report_data->contacts[0].y;
+			    if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
+				    report_data->contacts[i].z =
+					    report_data->contacts[0].z;
+			}
+		}
+#endif
 	}
 
 	report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0;
--- linux-4.4.0.orig/drivers/input/mouse/cypress_ps2.h
+++ linux-4.4.0/drivers/input/mouse/cypress_ps2.h
@@ -130,7 +130,18 @@
 #define RESP_REMOTE_BIT     0x40
 #define RESP_SMBUS_BIT      0x80
 
-#define CYTP_MAX_MT_SLOTS 2
+/*
+ * CYPRESS_SIMULATED_MT
+ *   set to 1 for simulated multitouch (up to 5 contact points)
+ *   set to 0 for SEMI_MT (only 2 corner points, and count of fingers)
+ */
+#define CYPRESS_SIMULATED_MT 1
+
+#if ( CYPRESS_SIMULATED_MT == 1 )
+# define CYTP_MAX_MT_SLOTS 5
+#else
+# define CYTP_MAX_MT_SLOTS 2
+#endif
 
 struct cytp_contact {
 	int x;
--- linux-4.4.0.orig/drivers/input/mouse/elan_i2c.h
+++ linux-4.4.0/drivers/input/mouse/elan_i2c.h
@@ -27,6 +27,8 @@
 #define ETP_DISABLE_POWER	0x0001
 #define ETP_PRESSURE_OFFSET	25
 
+#define ETP_CALIBRATE_MAX_LEN	3
+
 /* IAP Firmware handling */
 #define ETP_PRODUCT_ID_FORMAT_STRING	"%d.0"
 #define ETP_FW_NAME		"elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
--- linux-4.4.0.orig/drivers/input/mouse/elan_i2c_core.c
+++ linux-4.4.0/drivers/input/mouse/elan_i2c_core.c
@@ -4,7 +4,8 @@
  * Copyright (c) 2013 ELAN Microelectronics Corp.
  *
  * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.6.0
+ * Author: KT Liao <kt.liao@emc.com.tw>
+ * Version: 1.6.2
  *
  * Based on cyapa driver:
  * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,7 +41,7 @@
 #include "elan_i2c.h"
 
 #define DRIVER_NAME		"elan_i2c"
-#define ELAN_DRIVER_VERSION	"1.6.1"
+#define ELAN_DRIVER_VERSION	"1.6.2"
 #define ELAN_VENDOR_ID		0x04f3
 #define ETP_MAX_PRESSURE	255
 #define ETP_FWIDTH_REDUCE	90
@@ -199,9 +200,43 @@
 	return error;
 }
 
+static int elan_query_product(struct elan_tp_data *data)
+{
+	int error;
+
+	error = data->ops->get_product_id(data->client, &data->product_id);
+	if (error)
+		return error;
+
+	error = data->ops->get_sm_version(data->client, &data->ic_type,
+					  &data->sm_version);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static int elan_check_ASUS_special_fw(struct elan_tp_data *data)
+{
+	if (data->ic_type == 0x0E) {
+		switch (data->product_id) {
+		case 0x05 ... 0x07:
+		case 0x09:
+		case 0x13:
+			return true;
+		}
+	} else if (data->ic_type == 0x08 && data->product_id == 0x26) {
+		/* ASUS EeeBook X205TA */
+		return true;
+	}
+
+	return false;
+}
+
 static int __elan_initialize(struct elan_tp_data *data)
 {
 	struct i2c_client *client = data->client;
+	bool woken_up = false;
 	int error;
 
 	error = data->ops->initialize(client);
@@ -210,6 +245,27 @@
 		return error;
 	}
 
+	error = elan_query_product(data);
+	if (error)
+		return error;
+
+	/*
+	 * Some ASUS devices were shipped with firmware that requires
+	 * touchpads to be woken up first, before attempting to switch
+	 * them into absolute reporting mode.
+	 */
+	if (elan_check_ASUS_special_fw(data)) {
+		error = data->ops->sleep_control(client, false);
+		if (error) {
+			dev_err(&client->dev,
+				"failed to wake device up: %d\n", error);
+			return error;
+		}
+
+		msleep(200);
+		woken_up = true;
+	}
+
 	data->mode |= ETP_ENABLE_ABS;
 	error = data->ops->set_mode(client, data->mode);
 	if (error) {
@@ -218,11 +274,13 @@
 		return error;
 	}
 
-	error = data->ops->sleep_control(client, false);
-	if (error) {
-		dev_err(&client->dev,
-			"failed to wake device up: %d\n", error);
-		return error;
+	if (!woken_up) {
+		error = data->ops->sleep_control(client, false);
+		if (error) {
+			dev_err(&client->dev,
+				"failed to wake device up: %d\n", error);
+			return error;
+		}
 	}
 
 	return 0;
@@ -248,10 +306,6 @@
 {
 	int error;
 
-	error = data->ops->get_product_id(data->client, &data->product_id);
-	if (error)
-		return error;
-
 	error = data->ops->get_version(data->client, false, &data->fw_version);
 	if (error)
 		return error;
@@ -261,11 +315,6 @@
 	if (error)
 		return error;
 
-	error = data->ops->get_sm_version(data->client, &data->ic_type,
-					  &data->sm_version);
-	if (error)
-		return error;
-
 	error = data->ops->get_version(data->client, true, &data->iap_version);
 	if (error)
 		return error;
@@ -546,7 +595,7 @@
 	int tries = 20;
 	int retval;
 	int error;
-	u8 val[3];
+	u8 val[ETP_CALIBRATE_MAX_LEN];
 
 	retval = mutex_lock_interruptible(&data->sysfs_mutex);
 	if (retval)
@@ -1033,6 +1082,13 @@
 		return error;
 	}
 
+	/* Make sure there is something at this address */
+	error = i2c_smbus_read_byte(client);
+	if (error < 0) {
+		dev_dbg(&client->dev, "nothing at this address: %d\n", error);
+		return -ENXIO;
+	}
+
 	/* Initialize the touchpad. */
 	error = elan_initialize(data);
 	if (error)
@@ -1185,6 +1241,24 @@
 	{ "ELAN0000", 0 },
 	{ "ELAN0100", 0 },
 	{ "ELAN0600", 0 },
+	{ "ELAN0601", 0 },
+	{ "ELAN0602", 0 },
+	{ "ELAN0605", 0 },
+	{ "ELAN0608", 0 },
+	{ "ELAN0605", 0 },
+	{ "ELAN0609", 0 },
+	{ "ELAN060B", 0 },
+	{ "ELAN060C", 0 },
+	{ "ELAN0611", 0 },
+	{ "ELAN0612", 0 },
+	{ "ELAN0617", 0 },
+	{ "ELAN0618", 0 },
+	{ "ELAN061C", 0 },
+	{ "ELAN061D", 0 },
+	{ "ELAN061E", 0 },
+	{ "ELAN0620", 0 },
+	{ "ELAN0621", 0 },
+	{ "ELAN0622", 0 },
 	{ "ELAN1000", 0 },
 	{ }
 };
--- linux-4.4.0.orig/drivers/input/mouse/elan_i2c_i2c.c
+++ linux-4.4.0/drivers/input/mouse/elan_i2c_i2c.c
@@ -557,7 +557,14 @@
 	long ret;
 	int error;
 	int len;
-	u8 buffer[ETP_I2C_INF_LENGTH];
+	u8 buffer[ETP_I2C_REPORT_LEN];
+
+	len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN);
+	if (len != ETP_I2C_REPORT_LEN) {
+		error = len < 0 ? len : -EIO;
+		dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n",
+			error, len);
+	}
 
 	reinit_completion(completion);
 	enable_irq(client->irq);
--- linux-4.4.0.orig/drivers/input/mouse/elan_i2c_smbus.c
+++ linux-4.4.0/drivers/input/mouse/elan_i2c_smbus.c
@@ -56,7 +56,7 @@
 static int elan_smbus_initialize(struct i2c_client *client)
 {
 	u8 check[ETP_SMBUS_HELLOPACKET_LEN] = { 0x55, 0x55, 0x55, 0x55, 0x55 };
-	u8 values[ETP_SMBUS_HELLOPACKET_LEN] = { 0, 0, 0, 0, 0 };
+	u8 values[I2C_SMBUS_BLOCK_MAX] = {0};
 	int len, error;
 
 	/* Get hello packet */
@@ -117,12 +117,16 @@
 static int elan_smbus_calibrate_result(struct i2c_client *client, u8 *val)
 {
 	int error;
+	u8 buf[I2C_SMBUS_BLOCK_MAX] = {0};
+
+	BUILD_BUG_ON(ETP_CALIBRATE_MAX_LEN > sizeof(buf));
 
 	error = i2c_smbus_read_block_data(client,
-					  ETP_SMBUS_CALIBRATE_QUERY, val);
+					  ETP_SMBUS_CALIBRATE_QUERY, buf);
 	if (error < 0)
 		return error;
 
+	memcpy(val, buf, ETP_CALIBRATE_MAX_LEN);
 	return 0;
 }
 
@@ -130,7 +134,7 @@
 					bool max_baseline, u8 *value)
 {
 	int error;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client,
 					  max_baseline ?
@@ -149,7 +153,7 @@
 				  bool iap, u8 *version)
 {
 	int error;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client,
 					  iap ? ETP_SMBUS_IAP_VERSION_CMD :
@@ -169,7 +173,7 @@
 				     u8 *ic_type, u8 *version)
 {
 	int error;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client,
 					  ETP_SMBUS_SM_VERSION_CMD, val);
@@ -186,7 +190,7 @@
 static int elan_smbus_get_product_id(struct i2c_client *client, u16 *id)
 {
 	int error;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client,
 					  ETP_SMBUS_UNIQUEID_CMD, val);
@@ -203,7 +207,7 @@
 				   bool iap, u16 *csum)
 {
 	int error;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client,
 					  iap ? ETP_SMBUS_FW_CHECKSUM_CMD :
@@ -223,7 +227,7 @@
 			      unsigned int *max_x, unsigned int *max_y)
 {
 	int error;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val);
 	if (error) {
@@ -241,7 +245,7 @@
 				     u8 *hw_res_x, u8 *hw_res_y)
 {
 	int error;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client,
 					  ETP_SMBUS_RESOLUTION_CMD, val);
@@ -261,7 +265,7 @@
 				     unsigned int *y_traces)
 {
 	int error;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client,
 					  ETP_SMBUS_XY_TRACENUM_CMD, val);
@@ -288,7 +292,7 @@
 {
 	int error;
 	u16 constant;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	error = i2c_smbus_read_block_data(client, ETP_SMBUS_IAP_CTRL_CMD, val);
 	if (error < 0) {
@@ -339,7 +343,7 @@
 	int len;
 	int error;
 	enum tp_mode mode;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 	u8 cmd[4] = {0x0F, 0x78, 0x00, 0x06};
 	u16 password;
 
@@ -413,7 +417,7 @@
 	struct device *dev = &client->dev;
 	int error;
 	u16 result;
-	u8 val[3];
+	u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
 
 	/*
 	 * Due to the limitation of smbus protocol limiting
@@ -466,6 +470,8 @@
 {
 	int len;
 
+	BUILD_BUG_ON(I2C_SMBUS_BLOCK_MAX > ETP_SMBUS_REPORT_LEN);
+
 	len = i2c_smbus_read_block_data(client,
 					ETP_SMBUS_PACKET_QUERY,
 					&report[ETP_SMBUS_REPORT_OFFSET]);
--- linux-4.4.0.orig/drivers/input/mouse/elantech.c
+++ linux-4.4.0/drivers/input/mouse/elantech.c
@@ -804,7 +804,7 @@
 	else if (ic_version == 7 && etd->samples[1] == 0x2A)
 		sanity_check = ((packet[3] & 0x1c) == 0x10);
 	else
-		sanity_check = ((packet[0] & 0x0c) == 0x04 &&
+		sanity_check = ((packet[0] & 0x08) == 0x00 &&
 				(packet[3] & 0x1c) == 0x10);
 
 	if (!sanity_check)
@@ -1121,8 +1121,13 @@
  * Asus UX31               0x361f00        20, 15, 0e      clickpad
  * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
+ * Fujitsu CELSIUS H760    0x570f02        40, 14, 0c      3 hw buttons (**)
+ * Fujitsu CELSIUS H780    0x5d0f02        41, 16, 0d      3 hw buttons (**)
  * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
+ * Fujitsu LIFEBOOK E546   0x470f00        50, 12, 09      2 hw buttons
+ * Fujitsu LIFEBOOK E547   0x470f00        50, 12, 09      2 hw buttons
  * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
+ * Fujitsu LIFEBOOK E557   0x570f01        40, 14, 0c      2 hw buttons
  * Fujitsu T725            0x470f01        05, 12, 09      2 hw buttons
  * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
@@ -1163,10 +1168,34 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"),
 		},
 	},
+	{
+		/* Fujitsu H760 also has a middle button */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
+		},
+	},
+	{
+		/* Fujitsu H780 also has a middle button */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H780"),
+		},
+	},
 #endif
 	{ }
 };
 
+static const char * const middle_button_pnp_ids[] = {
+	"LEN2131", /* ThinkPad P52 w/ NFC */
+	"LEN2132", /* ThinkPad P52 */
+	"LEN2133", /* ThinkPad P72 w/ NFC */
+	"LEN2134", /* ThinkPad P72 */
+	"LEN0407",
+	"LEN0408",
+	NULL
+};
+
 /*
  * Set the appropriate event bits for the input subsystem
  */
@@ -1186,7 +1215,8 @@
 	__clear_bit(EV_REL, dev->evbit);
 
 	__set_bit(BTN_LEFT, dev->keybit);
-	if (dmi_check_system(elantech_dmi_has_middle_button))
+	if (dmi_check_system(elantech_dmi_has_middle_button) ||
+			psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids))
 		__set_bit(BTN_MIDDLE, dev->keybit);
 	__set_bit(BTN_RIGHT, dev->keybit);
 
@@ -1222,7 +1252,7 @@
 			input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
 					     ETP_WMAX_V2, 0, 0);
 		}
-		input_mt_init_slots(dev, 2, 0);
+		input_mt_init_slots(dev, 2, INPUT_MT_SEMI_MT);
 		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
 		break;
@@ -1507,10 +1537,10 @@
 		},
 	},
 	{
-		/* Fujitsu LIFEBOOK E554  does not work with crc_enabled == 0 */
+		/* Fujitsu H760 does not work with crc_enabled == 0 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
 		},
 	},
 	{
@@ -1521,6 +1551,41 @@
 		},
 	},
 	{
+		/* Fujitsu LIFEBOOK E546  does not work with crc_enabled == 0 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E546"),
+		},
+	},
+	{
+		/* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E547"),
+		},
+	},
+	{
+		/* Fujitsu LIFEBOOK E554  does not work with crc_enabled == 0 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
+		},
+	},
+	{
+		/* Fujitsu LIFEBOOK E556 does not work with crc_enabled == 0 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E556"),
+		},
+	},
+	{
+		/* Fujitsu LIFEBOOK E557 does not work with crc_enabled == 0 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E557"),
+		},
+	},
+	{
 		/* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
@@ -1568,13 +1633,7 @@
 		case 5:
 			etd->hw_version = 3;
 			break;
-		case 6:
-		case 7:
-		case 8:
-		case 9:
-		case 10:
-		case 13:
-		case 14:
+		case 6 ... 15:
 			etd->hw_version = 4;
 			break;
 		default:
@@ -1676,6 +1735,17 @@
 			     etd->samples[0], etd->samples[1], etd->samples[2]);
 	}
 
+	if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) {
+		/*
+		 * This module has a bug which makes absolute mode
+		 * unusable, so let's abort so we'll be using standard
+		 * PS/2 protocol.
+		 */
+		psmouse_info(psmouse,
+			     "absolute mode broken, forcing standard PS/2 protocol\n");
+		goto init_fail;
+	}
+
 	if (elantech_set_absolute_mode(psmouse)) {
 		psmouse_err(psmouse,
 			    "failed to put touchpad into absolute mode.\n");
--- linux-4.4.0.orig/drivers/input/mouse/inport.c
+++ linux-4.4.0/drivers/input/mouse/inport.c
@@ -78,7 +78,7 @@
 #define INPORT_IRQ		5
 
 static int inport_irq = INPORT_IRQ;
-module_param_named(irq, inport_irq, uint, 0);
+module_param_hw_named(irq, inport_irq, uint, irq, 0);
 MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 
 static struct input_dev *inport_dev;
--- linux-4.4.0.orig/drivers/input/mouse/logibm.c
+++ linux-4.4.0/drivers/input/mouse/logibm.c
@@ -69,7 +69,7 @@
 #define LOGIBM_IRQ		5
 
 static int logibm_irq = LOGIBM_IRQ;
-module_param_named(irq, logibm_irq, uint, 0);
+module_param_hw_named(irq, logibm_irq, uint, irq, 0);
 MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 
 static struct input_dev *logibm_dev;
--- linux-4.4.0.orig/drivers/input/mouse/psmouse-base.c
+++ linux-4.4.0/drivers/input/mouse/psmouse-base.c
@@ -1911,7 +1911,7 @@
 {
 	int type = *((unsigned int *)kp->arg);
 
-	return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name);
+	return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
 }
 
 static int __init psmouse_init(void)
--- linux-4.4.0.orig/drivers/input/mouse/sentelic.c
+++ linux-4.4.0/drivers/input/mouse/sentelic.c
@@ -454,7 +454,7 @@
 
 	fsp_reg_write_enable(psmouse, false);
 
-	return count;
+	return retval;
 }
 
 PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
--- linux-4.4.0.orig/drivers/input/mouse/synaptics.c
+++ linux-4.4.0/drivers/input/mouse/synaptics.c
@@ -862,8 +862,9 @@
 	if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
 		return;
 
-	/* Bug in FW 8.1, buttons are reported only when ExtBit is 1 */
-	if (SYN_ID_FULL(priv->identity) == 0x801 &&
+	/* Bug in FW 8.1 & 8.2, buttons are reported only when ExtBit is 1 */
+	if ((SYN_ID_FULL(priv->identity) == 0x801 ||
+	     SYN_ID_FULL(priv->identity) == 0x802) &&
 	    !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
 		return;
 
@@ -1250,7 +1251,9 @@
 		/* Clickpads report only left button */
 		__clear_bit(BTN_RIGHT, dev->keybit);
 		__clear_bit(BTN_MIDDLE, dev->keybit);
-	}
+	} else if (SYN_CAP_CLICKPAD2BTN(priv->ext_cap_0c) ||
+		   SYN_CAP_CLICKPAD2BTN2(priv->ext_cap_0c))
+		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
 }
 
 static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse,
--- linux-4.4.0.orig/drivers/input/mouse/synaptics.h
+++ linux-4.4.0/drivers/input/mouse/synaptics.h
@@ -85,6 +85,7 @@
  */
 #define SYN_CAP_CLICKPAD(ex0c)		((ex0c) & 0x100000) /* 1-button ClickPad */
 #define SYN_CAP_CLICKPAD2BTN(ex0c)	((ex0c) & 0x000100) /* 2-button ClickPad */
+#define SYN_CAP_CLICKPAD2BTN2(ex0c)	((ex0c) & 0x200000) /* 2-button ClickPad */
 #define SYN_CAP_MAX_DIMENSIONS(ex0c)	((ex0c) & 0x020000)
 #define SYN_CAP_MIN_DIMENSIONS(ex0c)	((ex0c) & 0x002000)
 #define SYN_CAP_ADV_GESTURE(ex0c)	((ex0c) & 0x080000)
--- linux-4.4.0.orig/drivers/input/mouse/trackpoint.c
+++ linux-4.4.0/drivers/input/mouse/trackpoint.c
@@ -265,7 +265,8 @@
 	if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
 		return -1;
 
-	if (param[0] != TP_MAGIC_IDENT)
+	/* add new TP ID. */
+	if (!(param[0] & TP_MAGIC_IDENT))
 		return -1;
 
 	if (firmware_id)
@@ -380,8 +381,11 @@
 		return 0;
 
 	if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
-		psmouse_warn(psmouse, "failed to get extended button data\n");
-		button_info = 0;
+		psmouse_warn(psmouse, "failed to get extended button data, assuming 3 buttons\n");
+		button_info = 0x33;
+	} else if (!button_info) {
+		psmouse_warn(psmouse, "got 0 in extended button data, assuming 3 buttons\n");
+		button_info = 0x33;
 	}
 
 	psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
--- linux-4.4.0.orig/drivers/input/mouse/trackpoint.h
+++ linux-4.4.0/drivers/input/mouse/trackpoint.h
@@ -21,8 +21,9 @@
 #define TP_COMMAND		0xE2	/* Commands start with this */
 
 #define TP_READ_ID		0xE1	/* Sent for device identification */
-#define TP_MAGIC_IDENT		0x01	/* Sent after a TP_READ_ID followed */
+#define TP_MAGIC_IDENT		0x03	/* Sent after a TP_READ_ID followed */
 					/* by the firmware ID */
+					/* Firmware ID includes 0x1, 0x2, 0x3 */
 
 
 /*
@@ -152,7 +153,8 @@
 #ifdef CONFIG_MOUSE_PS2_TRACKPOINT
 int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
 #else
-inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
+static inline int trackpoint_detect(struct psmouse *psmouse,
+				    bool set_properties)
 {
 	return -ENOSYS;
 }
--- linux-4.4.0.orig/drivers/input/mouse/vmmouse.c
+++ linux-4.4.0/drivers/input/mouse/vmmouse.c
@@ -355,18 +355,11 @@
 		return -ENXIO;
 	}
 
-	if (!request_region(VMMOUSE_PROTO_PORT, 4, "vmmouse")) {
-		psmouse_dbg(psmouse, "VMMouse port in use.\n");
-		return -EBUSY;
-	}
-
 	/* Check if the device is present */
 	response = ~VMMOUSE_PROTO_MAGIC;
 	VMMOUSE_CMD(GETVERSION, 0, version, response, dummy1, dummy2);
-	if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU) {
-		release_region(VMMOUSE_PROTO_PORT, 4);
+	if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU)
 		return -ENXIO;
-	}
 
 	if (set_properties) {
 		psmouse->vendor = VMMOUSE_VENDOR;
@@ -374,8 +367,6 @@
 		psmouse->model = version;
 	}
 
-	release_region(VMMOUSE_PROTO_PORT, 4);
-
 	return 0;
 }
 
@@ -394,7 +385,6 @@
 	psmouse_reset(psmouse);
 	input_unregister_device(priv->abs_dev);
 	kfree(priv);
-	release_region(VMMOUSE_PROTO_PORT, 4);
 }
 
 /**
@@ -438,15 +428,10 @@
 	struct input_dev *rel_dev = psmouse->dev, *abs_dev;
 	int error;
 
-	if (!request_region(VMMOUSE_PROTO_PORT, 4, "vmmouse")) {
-		psmouse_dbg(psmouse, "VMMouse port in use.\n");
-		return -EBUSY;
-	}
-
 	psmouse_reset(psmouse);
 	error = vmmouse_enable(psmouse);
 	if (error)
-		goto release_region;
+		return error;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	abs_dev = input_allocate_device();
@@ -458,8 +443,6 @@
 	priv->abs_dev = abs_dev;
 	psmouse->private = priv;
 
-	input_set_capability(rel_dev, EV_REL, REL_WHEEL);
-
 	/* Set up and register absolute device */
 	snprintf(priv->phys, sizeof(priv->phys), "%s/input1",
 		 psmouse->ps2dev.serio->phys);
@@ -475,10 +458,6 @@
 	abs_dev->id.version = psmouse->model;
 	abs_dev->dev.parent = &psmouse->ps2dev.serio->dev;
 
-	error = input_register_device(priv->abs_dev);
-	if (error)
-		goto init_fail;
-
 	/* Set absolute device capabilities */
 	input_set_capability(abs_dev, EV_KEY, BTN_LEFT);
 	input_set_capability(abs_dev, EV_KEY, BTN_RIGHT);
@@ -488,6 +467,13 @@
 	input_set_abs_params(abs_dev, ABS_X, 0, VMMOUSE_MAX_X, 0, 0);
 	input_set_abs_params(abs_dev, ABS_Y, 0, VMMOUSE_MAX_Y, 0, 0);
 
+	error = input_register_device(priv->abs_dev);
+	if (error)
+		goto init_fail;
+
+	/* Add wheel capability to the relative device */
+	input_set_capability(rel_dev, EV_REL, REL_WHEEL);
+
 	psmouse->protocol_handler = vmmouse_process_byte;
 	psmouse->disconnect = vmmouse_disconnect;
 	psmouse->reconnect = vmmouse_reconnect;
@@ -501,8 +487,5 @@
 	kfree(priv);
 	psmouse->private = NULL;
 
-release_region:
-	release_region(VMMOUSE_PROTO_PORT, 4);
-
 	return error;
 }
--- linux-4.4.0.orig/drivers/input/mousedev.c
+++ linux-4.4.0/drivers/input/mousedev.c
@@ -15,6 +15,7 @@
 #define MOUSEDEV_MINORS		31
 #define MOUSEDEV_MIX		63
 
+#include <linux/bitops.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
@@ -103,7 +104,7 @@
 	spinlock_t packet_lock;
 	int pos_x, pos_y;
 
-	signed char ps2[6];
+	u8 ps2[6];
 	unsigned char ready, buffer, bufsiz;
 	unsigned char imexseq, impsseq;
 	enum mousedev_emul mode;
@@ -291,11 +292,10 @@
 		}
 
 		client->pos_x += packet->dx;
-		client->pos_x = client->pos_x < 0 ?
-			0 : (client->pos_x >= xres ? xres : client->pos_x);
+		client->pos_x = clamp_val(client->pos_x, 0, xres);
+
 		client->pos_y += packet->dy;
-		client->pos_y = client->pos_y < 0 ?
-			0 : (client->pos_y >= yres ? yres : client->pos_y);
+		client->pos_y = clamp_val(client->pos_y, 0, yres);
 
 		p->dx += packet->dx;
 		p->dy += packet->dy;
@@ -571,44 +571,50 @@
 	return error;
 }
 
-static inline int mousedev_limit_delta(int delta, int limit)
-{
-	return delta > limit ? limit : (delta < -limit ? -limit : delta);
-}
-
-static void mousedev_packet(struct mousedev_client *client,
-			    signed char *ps2_data)
+static void mousedev_packet(struct mousedev_client *client, u8 *ps2_data)
 {
 	struct mousedev_motion *p = &client->packets[client->tail];
+	s8 dx, dy, dz;
+
+	dx = clamp_val(p->dx, -127, 127);
+	p->dx -= dx;
+
+	dy = clamp_val(p->dy, -127, 127);
+	p->dy -= dy;
 
-	ps2_data[0] = 0x08 |
-		((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
-	ps2_data[1] = mousedev_limit_delta(p->dx, 127);
-	ps2_data[2] = mousedev_limit_delta(p->dy, 127);
-	p->dx -= ps2_data[1];
-	p->dy -= ps2_data[2];
+	ps2_data[0] = BIT(3);
+	ps2_data[0] |= ((dx & BIT(7)) >> 3) | ((dy & BIT(7)) >> 2);
+	ps2_data[0] |= p->buttons & 0x07;
+	ps2_data[1] = dx;
+	ps2_data[2] = dy;
 
 	switch (client->mode) {
 	case MOUSEDEV_EMUL_EXPS:
-		ps2_data[3] = mousedev_limit_delta(p->dz, 7);
-		p->dz -= ps2_data[3];
-		ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
+		dz = clamp_val(p->dz, -7, 7);
+		p->dz -= dz;
+
+		ps2_data[3] = (dz & 0x0f) | ((p->buttons & 0x18) << 1);
 		client->bufsiz = 4;
 		break;
 
 	case MOUSEDEV_EMUL_IMPS:
-		ps2_data[0] |=
-			((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
-		ps2_data[3] = mousedev_limit_delta(p->dz, 127);
-		p->dz -= ps2_data[3];
+		dz = clamp_val(p->dz, -127, 127);
+		p->dz -= dz;
+
+		ps2_data[0] |= ((p->buttons & 0x10) >> 3) |
+			       ((p->buttons & 0x08) >> 1);
+		ps2_data[3] = dz;
+
 		client->bufsiz = 4;
 		break;
 
 	case MOUSEDEV_EMUL_PS2:
 	default:
-		ps2_data[0] |=
-			((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
 		p->dz = 0;
+
+		ps2_data[0] |= ((p->buttons & 0x10) >> 3) |
+			       ((p->buttons & 0x08) >> 1);
+
 		client->bufsiz = 3;
 		break;
 	}
@@ -714,7 +720,7 @@
 {
 	struct mousedev_client *client = file->private_data;
 	struct mousedev *mousedev = client->mousedev;
-	signed char data[sizeof(client->ps2)];
+	u8 data[sizeof(client->ps2)];
 	int retval = 0;
 
 	if (!client->ready && !client->buffer && mousedev->exist &&
--- linux-4.4.0.orig/drivers/input/serio/gscps2.c
+++ linux-4.4.0/drivers/input/serio/gscps2.c
@@ -382,9 +382,9 @@
 		goto fail;
 #endif
 
-	printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n",
+	pr_info("serio: %s port at 0x%08lx irq %d @ %s\n",
 		ps2port->port->name,
-		ps2port->addr,
+		hpa,
 		ps2port->padev->irq,
 		ps2port->port->phys);
 
--- linux-4.4.0.orig/drivers/input/serio/hil_mlc.c
+++ linux-4.4.0/drivers/input/serio/hil_mlc.c
@@ -74,7 +74,7 @@
 static LIST_HEAD(hil_mlcs);
 static DEFINE_RWLOCK(hil_mlcs_lock);
 static struct timer_list	hil_mlcs_kicker;
-static int			hil_mlcs_probe;
+static int			hil_mlcs_probe, hil_mlc_stop;
 
 static void hil_mlcs_process(unsigned long unused);
 static DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
@@ -704,9 +704,13 @@
 		if (!mlc->ostarted) {
 			mlc->ostarted = 1;
 			mlc->opacket = pack;
-			mlc->out(mlc);
+			rc = mlc->out(mlc);
 			nextidx = HILSEN_DOZE;
 			write_unlock_irqrestore(&mlc->lock, flags);
+			if (rc) {
+				hil_mlc_stop = 1;
+				return 1;
+			}
 			break;
 		}
 		mlc->ostarted = 0;
@@ -717,8 +721,13 @@
 
 	case HILSE_CTS:
 		write_lock_irqsave(&mlc->lock, flags);
-		nextidx = mlc->cts(mlc) ? node->bad : node->good;
+		rc = mlc->cts(mlc);
+		nextidx = rc ? node->bad : node->good;
 		write_unlock_irqrestore(&mlc->lock, flags);
+		if (rc) {
+			hil_mlc_stop = 1;
+			return 1;
+		}
 		break;
 
 	default:
@@ -786,6 +795,12 @@
 
 static void hil_mlcs_timer(unsigned long data)
 {
+	if (hil_mlc_stop) {
+		/* could not send packet - stop immediately. */
+		pr_warn(PREFIX "HIL seems stuck - Disabling HIL MLC.\n");
+		return;
+	}
+
 	hil_mlcs_probe = 1;
 	tasklet_schedule(&hil_mlcs_tasklet);
 	/* Re-insert the periodic task. */
--- linux-4.4.0.orig/drivers/input/serio/hp_sdc.c
+++ linux-4.4.0/drivers/input/serio/hp_sdc.c
@@ -887,8 +887,8 @@
 			"HP SDC NMI", &hp_sdc))
 		goto err2;
 
-	printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n",
-	       (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
+	pr_info(PREFIX "HP SDC at 0x%08lx, IRQ %d (NMI IRQ %d)\n",
+	       hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
 
 	hp_sdc_status_in8();
 	hp_sdc_data_in8();
--- linux-4.4.0.orig/drivers/input/serio/hp_sdc_mlc.c
+++ linux-4.4.0/drivers/input/serio/hp_sdc_mlc.c
@@ -213,7 +213,7 @@
 	priv->tseq[2] = 1;
 	priv->tseq[3] = 0;
 	priv->tseq[4] = 0;
-	__hp_sdc_enqueue_transaction(&priv->trans);
+	return __hp_sdc_enqueue_transaction(&priv->trans);
  busy:
 	return 1;
  done:
@@ -222,7 +222,7 @@
 	return 0;
 }
 
-static void hp_sdc_mlc_out(hil_mlc *mlc)
+static int hp_sdc_mlc_out(hil_mlc *mlc)
 {
 	struct hp_sdc_mlc_priv_s *priv;
 
@@ -237,7 +237,7 @@
  do_data:
 	if (priv->emtestmode) {
 		up(&mlc->osem);
-		return;
+		return 0;
 	}
 	/* Shouldn't be sending commands when loop may be busy */
 	BUG_ON(down_trylock(&mlc->csem));
@@ -299,7 +299,7 @@
 		BUG_ON(down_trylock(&mlc->csem));
 	}
  enqueue:
-	hp_sdc_enqueue_transaction(&priv->trans);
+	return hp_sdc_enqueue_transaction(&priv->trans);
 }
 
 static int __init hp_sdc_mlc_init(void)
--- linux-4.4.0.orig/drivers/input/serio/hyperv-keyboard.c
+++ linux-4.4.0/drivers/input/serio/hyperv-keyboard.c
@@ -412,16 +412,6 @@
 	return 0;
 }
 
-/*
- * Keyboard GUID
- * {f912ad6d-2b17-48ea-bd65-f927a61c7684}
- */
-#define HV_KBD_GUID \
-	.guid = { \
-			0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48, \
-			0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84 \
-	}
-
 static const struct hv_vmbus_device_id id_table[] = {
 	/* Keyboard guid */
 	{ HV_KBD_GUID, },
--- linux-4.4.0.orig/drivers/input/serio/i8042-io.h
+++ linux-4.4.0/drivers/input/serio/i8042-io.h
@@ -81,7 +81,7 @@
 		return -EBUSY;
 #endif
 
-	i8042_reset = 1;
+	i8042_reset = I8042_RESET_ALWAYS;
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/input/serio/i8042-ip22io.h
+++ linux-4.4.0/drivers/input/serio/i8042-ip22io.h
@@ -61,7 +61,7 @@
 		return -EBUSY;
 #endif
 
-	i8042_reset = 1;
+	i8042_reset = I8042_RESET_ALWAYS;
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/input/serio/i8042-ppcio.h
+++ linux-4.4.0/drivers/input/serio/i8042-ppcio.h
@@ -44,7 +44,7 @@
 
 static inline int i8042_platform_init(void)
 {
-	i8042_reset = 1;
+	i8042_reset = I8042_RESET_ALWAYS;
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/input/serio/i8042-sparcio.h
+++ linux-4.4.0/drivers/input/serio/i8042-sparcio.h
@@ -130,7 +130,7 @@
 		}
 	}
 
-	i8042_reset = 1;
+	i8042_reset = I8042_RESET_ALWAYS;
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/input/serio/i8042-unicore32io.h
+++ linux-4.4.0/drivers/input/serio/i8042-unicore32io.h
@@ -61,7 +61,7 @@
 	if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
 		return -EBUSY;
 
-	i8042_reset = 1;
+	i8042_reset = I8042_RESET_ALWAYS;
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/input/serio/i8042-x86ia64io.h
+++ linux-4.4.0/drivers/input/serio/i8042-x86ia64io.h
@@ -120,6 +120,13 @@
 		},
 	},
 	{
+		/* Dell Embedded Box PC 3000 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"),
+		},
+	},
+	{
 		/* OQO Model 01 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
@@ -211,6 +218,18 @@
 			DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"),
 		},
 	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"),
+		},
+	},
 	{ }
 };
 
@@ -258,6 +277,13 @@
 		},
 	},
 	{
+		/* Fujitsu Lifebook U745 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"),
+		},
+	},
+	{
 		/* Fujitsu T70H */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
@@ -410,6 +436,13 @@
 		},
 	},
 	{
+		/* Lenovo XiaoXin Air 12 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "80UN"),
+		},
+	},
+	{
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
@@ -500,9 +533,144 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"),
 		},
 	},
+	{
+		/* TUXEDO BU1406 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"),
+		},
+	},
+	{
+		/* Lenovo LaVie Z */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"),
+		},
+	},
+	{
+		/*
+		 * Acer Aspire 5738z
+		 * Touchpad stops working in mux mode when dis- + re-enabled
+		 * with the touchpad enable/disable toggle hotkey
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
+		},
+	},
+	{
+		/* Entroware Proteus */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Entroware"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"),
+		},
+	},
 	{ }
 };
 
+static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = {
+	{
+		/*
+		 * Sony Vaio VGN-CS series require MUX or the touch sensor
+		 * buttons will disturb touchpad operation
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
+		},
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */
+		},
+	},
+	{ }
+};
+
+/*
+ * On some Asus laptops, just running self tests cause problems.
+ */
+static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
+		},
+	},
+	{ }
+};
 static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
 	{
 		/* MSI Wind U-100 */
@@ -526,6 +694,48 @@
 		},
 	},
 	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A114-31"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A314-31"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A315-31"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-132"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-332"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-432"),
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate Spin B118-RN"),
+		},
+	},
+	{
 		/* Advent 4211 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"),
@@ -581,6 +791,35 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "20046"),
 		},
 	},
+	{
+		/* Lenovo ThinkPad L460 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"),
+		},
+	},
+	{
+		/* Clevo P650RS, 650RP6, Sager NP8152-S, and others */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"),
+		},
+	},
+	{
+		/* Lenovo ThinkPad Twist S230u */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "33474HU"),
+		},
+	},
+	{
+		/* Entroware Proteus */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Entroware"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"),
+		},
+	},
 	{ }
 };
 
@@ -610,6 +849,13 @@
 			DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
 		},
 	},
+	{
+		/* Acer Aspire 5 A515 */
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "Grumpy_PK"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "PK"),
+		},
+	},
 	{ }
 };
 
@@ -677,6 +923,13 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"),
 		},
 	},
+	{
+		/* Fujitsu UH554 laptop */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK UH544"),
+		},
+	},
 	{ }
 };
 
@@ -786,6 +1039,20 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
 		},
 	},
+	{
+		/* Gigabyte P57 - Elantech touchpad */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P57"),
+		},
+	},
+	{
+		/* Schenker XMG C504 - Elantech touchpad */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "XMG"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "C504"),
+		},
+	},
 	{ }
 };
 
@@ -1065,12 +1332,18 @@
 		return retval;
 
 #if defined(__ia64__)
-        i8042_reset = true;
+        i8042_reset = I8042_RESET_ALWAYS;
 #endif
 
 #ifdef CONFIG_X86
-	if (dmi_check_system(i8042_dmi_reset_table))
-		i8042_reset = true;
+	/* Honor module parameter when value is not default */
+	if (i8042_reset == I8042_RESET_DEFAULT) {
+		if (dmi_check_system(i8042_dmi_reset_table))
+			i8042_reset = I8042_RESET_ALWAYS;
+
+		if (dmi_check_system(i8042_dmi_noselftest_table))
+			i8042_reset = I8042_RESET_NEVER;
+	}
 
 	if (dmi_check_system(i8042_dmi_noloop_table))
 		i8042_noloop = true;
@@ -1078,6 +1351,9 @@
 	if (dmi_check_system(i8042_dmi_nomux_table))
 		i8042_nomux = true;
 
+	if (dmi_check_system(i8042_dmi_forcemux_table))
+		i8042_nomux = false;
+
 	if (dmi_check_system(i8042_dmi_notimeout_table))
 		i8042_notimeout = true;
 
--- linux-4.4.0.orig/drivers/input/serio/i8042.c
+++ linux-4.4.0/drivers/input/serio/i8042.c
@@ -48,9 +48,39 @@
 module_param_named(unlock, i8042_unlock, bool, 0);
 MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
 
-static bool i8042_reset;
-module_param_named(reset, i8042_reset, bool, 0);
-MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
+enum i8042_controller_reset_mode {
+	I8042_RESET_NEVER,
+	I8042_RESET_ALWAYS,
+	I8042_RESET_ON_S2RAM,
+#define I8042_RESET_DEFAULT	I8042_RESET_ON_S2RAM
+};
+static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
+static int i8042_set_reset(const char *val, const struct kernel_param *kp)
+{
+	enum i8042_controller_reset_mode *arg = kp->arg;
+	int error;
+	bool reset;
+
+	if (val) {
+		error = kstrtobool(val, &reset);
+		if (error)
+			return error;
+	} else {
+		reset = true;
+	}
+
+	*arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
+	return 0;
+}
+
+static const struct kernel_param_ops param_ops_reset_param = {
+	.flags = KERNEL_PARAM_OPS_FL_NOARG,
+	.set = i8042_set_reset,
+};
+#define param_check_reset_param(name, p)	\
+	__param_check(name, p, enum i8042_controller_reset_mode)
+module_param_named(reset, i8042_reset, reset_param, 0);
+MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
 
 static bool i8042_direct;
 module_param_named(direct, i8042_direct, bool, 0);
@@ -95,6 +125,7 @@
 MODULE_PARM_DESC(unmask_kbd_data, "Unconditional enable (may reveal sensitive data) of normally sanitize-filtered kbd data traffic debug log [pre-condition: i8042.debug=1 enabled]");
 #endif
 
+static bool i8042_present;
 static bool i8042_bypass_aux_irq_test;
 static char i8042_kbd_firmware_id[128];
 static char i8042_aux_firmware_id[128];
@@ -313,6 +344,9 @@
 	unsigned long flags;
 	int retval;
 
+	if (!i8042_present)
+		return -1;
+
 	spin_lock_irqsave(&i8042_lock, flags);
 	retval = __i8042_command(param, command);
 	spin_unlock_irqrestore(&i8042_lock, flags);
@@ -404,8 +438,10 @@
 {
 	struct i8042_port *port = serio->port_data;
 
+	spin_lock_irq(&i8042_lock);
 	port->exists = true;
-	mb();
+	spin_unlock_irq(&i8042_lock);
+
 	return 0;
 }
 
@@ -418,16 +454,20 @@
 {
 	struct i8042_port *port = serio->port_data;
 
+	spin_lock_irq(&i8042_lock);
 	port->exists = false;
+	port->serio = NULL;
+	spin_unlock_irq(&i8042_lock);
 
 	/*
+	 * We need to make sure that interrupt handler finishes using
+	 * our serio port before we return from this function.
 	 * We synchronize with both AUX and KBD IRQs because there is
 	 * a (very unlikely) chance that AUX IRQ is raised for KBD port
 	 * and vice versa.
 	 */
 	synchronize_irq(I8042_AUX_IRQ);
 	synchronize_irq(I8042_KBD_IRQ);
-	port->serio = NULL;
 }
 
 /*
@@ -544,7 +584,7 @@
 
 	spin_unlock_irqrestore(&i8042_lock, flags);
 
-	if (likely(port->exists && !filtered))
+	if (likely(serio && !filtered))
 		serio_interrupt(serio, data, dfl);
 
  out:
@@ -1019,7 +1059,7 @@
  * Reset the controller and reset CRT to the original value set by BIOS.
  */
 
-static void i8042_controller_reset(bool force_reset)
+static void i8042_controller_reset(bool s2r_wants_reset)
 {
 	i8042_flush();
 
@@ -1044,8 +1084,10 @@
  * Reset the controller if requested.
  */
 
-	if (i8042_reset || force_reset)
+	if (i8042_reset == I8042_RESET_ALWAYS ||
+	    (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
 		i8042_controller_selftest();
+	}
 
 /*
  * Restore the original control register setting.
@@ -1110,7 +1152,7 @@
  * before suspending.
  */
 
-static int i8042_controller_resume(bool force_reset)
+static int i8042_controller_resume(bool s2r_wants_reset)
 {
 	int error;
 
@@ -1118,7 +1160,8 @@
 	if (error)
 		return error;
 
-	if (i8042_reset || force_reset) {
+	if (i8042_reset == I8042_RESET_ALWAYS ||
+	    (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
 		error = i8042_controller_selftest();
 		if (error)
 			return error;
@@ -1195,7 +1238,7 @@
 
 static int i8042_pm_resume(struct device *dev)
 {
-	bool force_reset;
+	bool want_reset;
 	int i;
 
 	for (i = 0; i < I8042_NUM_PORTS; i++) {
@@ -1218,9 +1261,9 @@
 	 * off control to the platform firmware, otherwise we can simply restore
 	 * the mode.
 	 */
-	force_reset = pm_resume_via_firmware();
+	want_reset = pm_resume_via_firmware();
 
-	return i8042_controller_resume(force_reset);
+	return i8042_controller_resume(want_reset);
 }
 
 static int i8042_pm_thaw(struct device *dev)
@@ -1277,6 +1320,7 @@
 	serio->start		= i8042_start;
 	serio->stop		= i8042_stop;
 	serio->close		= i8042_port_close;
+	serio->ps2_cmd_mutex	= &i8042_mutex;
 	serio->port_data	= port;
 	serio->dev.parent	= &i8042_platform_device->dev;
 	strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
@@ -1304,6 +1348,7 @@
 	serio->write		= i8042_aux_write;
 	serio->start		= i8042_start;
 	serio->stop		= i8042_stop;
+	serio->ps2_cmd_mutex	= &i8042_mutex;
 	serio->port_data	= port;
 	serio->dev.parent	= &i8042_platform_device->dev;
 	if (idx < 0) {
@@ -1373,21 +1418,6 @@
 	}
 }
 
-/*
- * Checks whether port belongs to i8042 controller.
- */
-bool i8042_check_port_owner(const struct serio *port)
-{
-	int i;
-
-	for (i = 0; i < I8042_NUM_PORTS; i++)
-		if (i8042_ports[i].serio == port)
-			return true;
-
-	return false;
-}
-EXPORT_SYMBOL(i8042_check_port_owner);
-
 static void i8042_free_irqs(void)
 {
 	if (i8042_aux_irq_registered)
@@ -1426,7 +1456,8 @@
 	if (error)
 		goto err_free_ports;
 
-	if (aux_enable())
+	error = aux_enable();
+	if (error)
 		goto err_free_irq;
 
 	i8042_aux_irq_registered = true;
@@ -1495,7 +1526,7 @@
 
 	i8042_platform_device = dev;
 
-	if (i8042_reset) {
+	if (i8042_reset == I8042_RESET_ALWAYS) {
 		error = i8042_controller_selftest();
 		if (error)
 			return error;
@@ -1571,12 +1602,15 @@
 
 	err = i8042_platform_init();
 	if (err)
-		return err;
+		return (err == -ENODEV) ? 0 : err;
 
 	err = i8042_controller_check();
 	if (err)
 		goto err_platform_exit;
 
+	/* Set this before creating the dev to allow i8042_command to work right away */
+	i8042_present = true;
+
 	pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
 	if (IS_ERR(pdev)) {
 		err = PTR_ERR(pdev);
@@ -1595,6 +1629,9 @@
 
 static void __exit i8042_exit(void)
 {
+	if (!i8042_present)
+		return;
+
 	platform_device_unregister(i8042_platform_device);
 	platform_driver_unregister(&i8042_driver);
 	i8042_platform_exit();
--- linux-4.4.0.orig/drivers/input/serio/libps2.c
+++ linux-4.4.0/drivers/input/serio/libps2.c
@@ -56,19 +56,17 @@
 
 void ps2_begin_command(struct ps2dev *ps2dev)
 {
-	mutex_lock(&ps2dev->cmd_mutex);
+	struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
 
-	if (i8042_check_port_owner(ps2dev->serio))
-		i8042_lock_chip();
+	mutex_lock(m);
 }
 EXPORT_SYMBOL(ps2_begin_command);
 
 void ps2_end_command(struct ps2dev *ps2dev)
 {
-	if (i8042_check_port_owner(ps2dev->serio))
-		i8042_unlock_chip();
+	struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
 
-	mutex_unlock(&ps2dev->cmd_mutex);
+	mutex_unlock(m);
 }
 EXPORT_SYMBOL(ps2_end_command);
 
--- linux-4.4.0.orig/drivers/input/serio/sun4i-ps2.c
+++ linux-4.4.0/drivers/input/serio/sun4i-ps2.c
@@ -210,7 +210,6 @@
 	struct sun4i_ps2data *drvdata;
 	struct serio *serio;
 	struct device *dev = &pdev->dev;
-	unsigned int irq;
 	int error;
 
 	drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL);
@@ -263,14 +262,12 @@
 	writel(0, drvdata->reg_base + PS2_REG_GCTL);
 
 	/* Get IRQ for the device */
-	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		dev_err(dev, "no IRQ found\n");
-		error = -ENXIO;
+	drvdata->irq = platform_get_irq(pdev, 0);
+	if (drvdata->irq < 0) {
+		error = drvdata->irq;
 		goto err_disable_clk;
 	}
 
-	drvdata->irq = irq;
 	drvdata->serio = serio;
 	drvdata->dev = dev;
 
--- linux-4.4.0.orig/drivers/input/tablet/aiptek.c
+++ linux-4.4.0/drivers/input/tablet/aiptek.c
@@ -1819,15 +1819,13 @@
 	input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
 	input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
 
-	/* Verify that a device really has an endpoint */
-	if (intf->altsetting[0].desc.bNumEndpoints < 1) {
+	err = usb_find_common_endpoints(intf->cur_altsetting,
+					NULL, NULL, &endpoint, NULL);
+	if (err) {
 		dev_err(&intf->dev,
-			"interface has %d endpoints, but must have minimum 1\n",
-			intf->altsetting[0].desc.bNumEndpoints);
-		err = -EINVAL;
+			"interface has no int in endpoints, but must have minimum 1\n");
 		goto fail3;
 	}
-	endpoint = &intf->altsetting[0].endpoint[0].desc;
 
 	/* Go set up our URB, which is called when the tablet receives
 	 * input.
--- linux-4.4.0.orig/drivers/input/tablet/gtco.c
+++ linux-4.4.0/drivers/input/tablet/gtco.c
@@ -78,6 +78,7 @@
 
 /* Max size of a single report */
 #define REPORT_MAX_SIZE       10
+#define MAX_COLLECTION_LEVELS  10
 
 
 /* Bitmask whether pen is in range */
@@ -224,20 +225,23 @@
 	char  maintype = 'x';
 	char  globtype[12];
 	int   indent = 0;
-	char  indentstr[10] = "";
-
+	char  indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 };
 
 	dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");
 
 	/* Walk  this report and pull out the info we need */
 	while (i < length) {
-		prefix = report[i];
-
-		/* Skip over prefix */
-		i++;
+		prefix = report[i++];
 
 		/* Determine data size and save the data in the proper variable */
-		size = PREF_SIZE(prefix);
+		size = (1U << PREF_SIZE(prefix)) >> 1;
+		if (i + size > length) {
+			dev_err(ddev,
+				"Not enough data (need %d, have %d)\n",
+				i + size, length);
+			break;
+		}
+
 		switch (size) {
 		case 1:
 			data = report[i];
@@ -245,8 +249,7 @@
 		case 2:
 			data16 = get_unaligned_le16(&report[i]);
 			break;
-		case 3:
-			size = 4;
+		case 4:
 			data32 = get_unaligned_le32(&report[i]);
 			break;
 		}
@@ -348,6 +351,13 @@
 			case TAG_MAIN_COL_START:
 				maintype = 'S';
 
+				if (indent == MAX_COLLECTION_LEVELS) {
+					dev_err(ddev, "Collection level %d would exceed limit of %d\n",
+						indent + 1,
+						MAX_COLLECTION_LEVELS);
+					break;
+				}
+
 				if (data == 0) {
 					dev_dbg(ddev, "======>>>>>> Physical\n");
 					strcpy(globtype, "Physical");
@@ -367,8 +377,15 @@
 				break;
 
 			case TAG_MAIN_COL_END:
-				dev_dbg(ddev, "<<<<<<======\n");
 				maintype = 'E';
+
+				if (indent == 0) {
+					dev_err(ddev, "Collection level already at zero\n");
+					break;
+				}
+
+				dev_dbg(ddev, "<<<<<<======\n");
+
 				indent--;
 				for (x = 0; x < indent; x++)
 					indentstr[x] = '-';
@@ -858,11 +875,15 @@
 		goto err_free_buf;
 	}
 
-	/*
-	 * The endpoint is always altsetting 0, we know this since we know
-	 * this device only has one interrupt endpoint
-	 */
-	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+	/* Sanity check that a device has an endpoint */
+	if (usbinterface->cur_altsetting->desc.bNumEndpoints < 1) {
+		dev_err(&usbinterface->dev,
+			"Invalid number of endpoints\n");
+		error = -EINVAL;
+		goto err_free_urb;
+	}
+
+	endpoint = &usbinterface->cur_altsetting->endpoint[0].desc;
 
 	/* Some debug */
 	dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting);
@@ -879,7 +900,7 @@
 	 * HID report descriptor
 	 */
 	if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
-				     HID_DEVICE_TYPE, &hid_desc) != 0){
+				     HID_DEVICE_TYPE, &hid_desc) != 0) {
 		dev_err(&usbinterface->dev,
 			"Can't retrieve exta USB descriptor to get hid report descriptor length\n");
 		error = -EIO;
@@ -949,7 +970,7 @@
 	input_dev->dev.parent = &usbinterface->dev;
 
 	/* Setup the URB, it will be posted later on open of input device */
-	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+	endpoint = &usbinterface->cur_altsetting->endpoint[0].desc;
 
 	usb_fill_int_urb(gtco->urbinfo,
 			 gtco->usbdev,
--- linux-4.4.0.orig/drivers/input/tablet/hanwang.c
+++ linux-4.4.0/drivers/input/tablet/hanwang.c
@@ -340,6 +340,9 @@
 	int error;
 	int i;
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!hanwang || !input_dev) {
--- linux-4.4.0.orig/drivers/input/tablet/kbtab.c
+++ linux-4.4.0/drivers/input/tablet/kbtab.c
@@ -122,6 +122,13 @@
 	struct input_dev *input_dev;
 	int error = -ENOMEM;
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
 	kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!kbtab || !input_dev)
@@ -161,8 +168,6 @@
 	input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
 
-	endpoint = &intf->cur_altsetting->endpoint[0].desc;
-
 	usb_fill_int_urb(kbtab->irq, dev,
 			 usb_rcvintpipe(dev, endpoint->bEndpointAddress),
 			 kbtab->data, 8,
--- linux-4.4.0.orig/drivers/input/tablet/wacom_serial4.c
+++ linux-4.4.0/drivers/input/tablet/wacom_serial4.c
@@ -187,6 +187,7 @@
 	MODEL_DIGITIZER_II	= 0x5544, /* UD */
 	MODEL_GRAPHIRE		= 0x4554, /* ET */
 	MODEL_PENPARTNER	= 0x4354, /* CT */
+	MODEL_ARTPAD_II		= 0x4B54, /* KT */
 };
 
 static void wacom_handle_model_response(struct wacom *wacom)
@@ -245,6 +246,7 @@
 		wacom->flags = F_HAS_STYLUS2 | F_HAS_SCROLLWHEEL;
 		break;
 
+	case MODEL_ARTPAD_II:
 	case MODEL_DIGITIZER_II:
 		wacom->dev->name = "Wacom Digitizer II";
 		wacom->dev->id.version = MODEL_DIGITIZER_II;
--- linux-4.4.0.orig/drivers/input/touchscreen/88pm860x-ts.c
+++ linux-4.4.0/drivers/input/touchscreen/88pm860x-ts.c
@@ -126,7 +126,7 @@
 	int data, n, ret;
 	if (!np)
 		return -ENODEV;
-	np = of_find_node_by_name(np, "touch");
+	np = of_get_child_by_name(np, "touch");
 	if (!np) {
 		dev_err(&pdev->dev, "Can't find touch node\n");
 		return -EINVAL;
@@ -144,13 +144,13 @@
 	if (data) {
 		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	/* set tsi prebias time */
 	if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) {
 		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	/* set prebias & prechg time of pen detect */
 	data = 0;
@@ -161,10 +161,18 @@
 	if (data) {
 		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x);
+
+	of_node_put(np);
+
 	return 0;
+
+err_put_node:
+	of_node_put(np);
+
+	return -EINVAL;
 }
 #else
 #define pm860x_touch_dt_init(x, y, z)	(-1)
--- linux-4.4.0.orig/drivers/input/touchscreen/ads7846.c
+++ linux-4.4.0/drivers/input/touchscreen/ads7846.c
@@ -35,6 +35,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
 #include <asm/irq.h>
+#include <asm/unaligned.h>
 
 /*
  * This code has been heavily tested on a Nokia 770, and lightly
@@ -410,7 +411,7 @@
 
 	if (status == 0) {
 		/* BE12 value, then padding */
-		status = be16_to_cpu(*((u16 *)&req->sample[1]));
+		status = get_unaligned_be16(&req->sample[1]);
 		status = status >> 3;
 		status &= 0x0fff;
 	}
@@ -785,10 +786,11 @@
 		/* compute touch pressure resistance using equation #2 */
 		Rt = z2;
 		Rt -= z1;
-		Rt *= x;
 		Rt *= ts->x_plate_ohms;
+		Rt = DIV_ROUND_CLOSEST(Rt, 16);
+		Rt *= x;
 		Rt /= z1;
-		Rt = (Rt + 2047) >> 12;
+		Rt = DIV_ROUND_CLOSEST(Rt, 256);
 	} else {
 		Rt = 0;
 	}
--- linux-4.4.0.orig/drivers/input/touchscreen/ar1021_i2c.c
+++ linux-4.4.0/drivers/input/touchscreen/ar1021_i2c.c
@@ -152,7 +152,7 @@
 static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume);
 
 static const struct i2c_device_id ar1021_i2c_id[] = {
-	{ "MICROCHIP_AR1021_I2C", 0 },
+	{ "ar1021", 0 },
 	{ },
 };
 MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
--- linux-4.4.0.orig/drivers/input/touchscreen/atmel_mxt_ts.c
+++ linux-4.4.0/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1593,10 +1593,11 @@
 			break;
 		case MXT_TOUCH_MULTI_T9:
 			data->multitouch = MXT_TOUCH_MULTI_T9;
+			/* Only handle messages from first T9 instance */
 			data->T9_reportid_min = min_id;
-			data->T9_reportid_max = max_id;
-			data->num_touchids = object->num_report_ids
-						* mxt_obj_instances(object);
+			data->T9_reportid_max = min_id +
+						object->num_report_ids - 1;
+			data->num_touchids = object->num_report_ids;
 			break;
 		case MXT_SPT_MESSAGECOUNT_T44:
 			data->T44_address = object->start_address;
@@ -2523,6 +2524,15 @@
 		.driver_data = samus_platform_data,
 	},
 	{
+		/* Samsung Chromebook Pro */
+		.ident = "Samsung Chromebook Pro",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"),
+		},
+		.driver_data = samus_platform_data,
+	},
+	{
 		/* Other Google Chromebooks */
 		.ident = "Chromebook",
 		.matches = {
@@ -2691,6 +2701,8 @@
 
 	mutex_unlock(&input_dev->mutex);
 
+	disable_irq(data->irq);
+
 	return 0;
 }
 
@@ -2703,6 +2715,8 @@
 	if (!input_dev)
 		return 0;
 
+	enable_irq(data->irq);
+
 	mutex_lock(&input_dev->mutex);
 
 	if (input_dev->users)
--- linux-4.4.0.orig/drivers/input/touchscreen/cyttsp4_core.c
+++ linux-4.4.0/drivers/input/touchscreen/cyttsp4_core.c
@@ -1972,11 +1972,6 @@
 
 	/* get sysinfo */
 	md->si = &cd->sysinfo;
-	if (!md->si) {
-		dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
-			__func__, md->si);
-		goto error_get_sysinfo;
-	}
 
 	rc = cyttsp4_setup_input_device(cd);
 	if (rc)
@@ -1986,8 +1981,6 @@
 
 error_init_input:
 	input_free_device(md->input);
-error_get_sysinfo:
-	input_set_drvdata(md->input, NULL);
 error_alloc_failed:
 	dev_err(dev, "%s failed.\n", __func__);
 	return rc;
--- linux-4.4.0.orig/drivers/input/touchscreen/edt-ft5x06.c
+++ linux-4.4.0/drivers/input/touchscreen/edt-ft5x06.c
@@ -822,16 +822,22 @@
 	int error;
 
 	error = device_property_read_u32(dev, "threshold", &val);
-	if (!error)
-		reg_addr->reg_threshold = val;
+	if (!error) {
+		edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, val);
+		tsdata->threshold = val;
+	}
 
 	error = device_property_read_u32(dev, "gain", &val);
-	if (!error)
-		reg_addr->reg_gain = val;
+	if (!error) {
+		edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, val);
+		tsdata->gain = val;
+	}
 
 	error = device_property_read_u32(dev, "offset", &val);
-	if (!error)
-		reg_addr->reg_offset = val;
+	if (!error) {
+		edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val);
+		tsdata->offset = val;
+	}
 }
 
 static void
@@ -880,6 +886,7 @@
 {
 	const struct edt_i2c_chip_data *chip_data;
 	struct edt_ft5x06_ts_data *tsdata;
+	u8 buf[2] = { 0xfc, 0x00 };
 	struct input_dev *input;
 	unsigned long irq_flags;
 	int error;
@@ -949,6 +956,12 @@
 		return error;
 	}
 
+	/*
+	 * Dummy read access. EP0700MLP1 returns bogus data on the first
+	 * register read access and ignores writes.
+	 */
+	edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf);
+
 	edt_ft5x06_ts_set_regs(tsdata);
 	edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
 	edt_ft5x06_ts_get_parameters(tsdata);
--- linux-4.4.0.orig/drivers/input/touchscreen/elants_i2c.c
+++ linux-4.4.0/drivers/input/touchscreen/elants_i2c.c
@@ -905,9 +905,9 @@
 
 		case QUEUE_HEADER_NORMAL:
 			report_count = ts->buf[FW_HDR_COUNT];
-			if (report_count > 3) {
+			if (report_count == 0 || report_count > 3) {
 				dev_err(&client->dev,
-					"too large report count: %*ph\n",
+					"bad report count: %*ph\n",
 					HEADER_SIZE, ts->buf);
 				break;
 			}
--- linux-4.4.0.orig/drivers/input/touchscreen/elo.c
+++ linux-4.4.0/drivers/input/touchscreen/elo.c
@@ -345,8 +345,10 @@
 	switch (elo->id) {
 
 	case 0: /* 10-byte protocol */
-		if (elo_setup_10(elo))
+		if (elo_setup_10(elo)) {
+			err = -EIO;
 			goto fail3;
+		}
 
 		break;
 
--- linux-4.4.0.orig/drivers/input/touchscreen/goodix.c
+++ linux-4.4.0/drivers/input/touchscreen/goodix.c
@@ -69,6 +69,27 @@
 static const struct dmi_system_id rotated_screen[] = {
 #if defined(CONFIG_DMI) && defined(CONFIG_X86)
 	{
+		.ident = "Teclast X89",
+		.matches = {
+			/* tPAD is too generic, also match on bios date */
+			DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
+			DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
+			DMI_MATCH(DMI_BIOS_DATE, "12/19/2014"),
+		},
+	},
+	{
+		.ident = "Teclast X98 Pro",
+		.matches = {
+			/*
+			 * Only match BIOS date, because the manufacturers
+			 * BIOS does not report the board name at all
+			 * (sometimes)...
+			 */
+			DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
+			DMI_MATCH(DMI_BIOS_DATE, "10/28/2015"),
+		},
+	},
+	{
 		.ident = "WinBook TW100",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
@@ -425,6 +446,7 @@
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id goodix_acpi_match[] = {
 	{ "GDIX1001", 0 },
+	{ "GDIX1002", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
--- linux-4.4.0.orig/drivers/input/touchscreen/imx6ul_tsc.c
+++ linux-4.4.0/drivers/input/touchscreen/imx6ul_tsc.c
@@ -490,20 +490,25 @@
 
 	mutex_lock(&input_dev->mutex);
 
-	if (input_dev->users) {
-		retval = clk_prepare_enable(tsc->adc_clk);
-		if (retval)
-			goto out;
+	if (!input_dev->users)
+		goto out;
 
-		retval = clk_prepare_enable(tsc->tsc_clk);
-		if (retval) {
-			clk_disable_unprepare(tsc->adc_clk);
-			goto out;
-		}
+	retval = clk_prepare_enable(tsc->adc_clk);
+	if (retval)
+		goto out;
 
-		retval = imx6ul_tsc_init(tsc);
+	retval = clk_prepare_enable(tsc->tsc_clk);
+	if (retval) {
+		clk_disable_unprepare(tsc->adc_clk);
+		goto out;
 	}
 
+	retval = imx6ul_tsc_init(tsc);
+	if (retval) {
+		clk_disable_unprepare(tsc->tsc_clk);
+		clk_disable_unprepare(tsc->adc_clk);
+		goto out;
+	}
 out:
 	mutex_unlock(&input_dev->mutex);
 	return retval;
--- linux-4.4.0.orig/drivers/input/touchscreen/mk712.c
+++ linux-4.4.0/drivers/input/touchscreen/mk712.c
@@ -50,11 +50,11 @@
 MODULE_LICENSE("GPL");
 
 static unsigned int mk712_io = 0x260;	/* Also 0x200, 0x208, 0x300 */
-module_param_named(io, mk712_io, uint, 0);
+module_param_hw_named(io, mk712_io, uint, ioport, 0);
 MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
 
 static unsigned int mk712_irq = 10;	/* Also 12, 14, 15 */
-module_param_named(irq, mk712_irq, uint, 0);
+module_param_hw_named(irq, mk712_irq, uint, irq, 0);
 MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
 
 /* eight 8-bit registers */
--- linux-4.4.0.orig/drivers/input/touchscreen/st1232.c
+++ linux-4.4.0/drivers/input/touchscreen/st1232.c
@@ -203,6 +203,7 @@
 	input_dev->id.bustype = BUS_I2C;
 	input_dev->dev.parent = &client->dev;
 
+	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 	__set_bit(EV_SYN, input_dev->evbit);
 	__set_bit(EV_KEY, input_dev->evbit);
 	__set_bit(EV_ABS, input_dev->evbit);
--- linux-4.4.0.orig/drivers/input/touchscreen/sur40.c
+++ linux-4.4.0/drivers/input/touchscreen/sur40.c
@@ -126,7 +126,7 @@
 #define VIDEO_PACKET_SIZE  16384
 
 /* polling interval (ms) */
-#define POLL_INTERVAL 4
+#define POLL_INTERVAL 1
 
 /* maximum number of contacts FIXME: this is a guess? */
 #define MAX_CONTACTS 64
@@ -441,7 +441,7 @@
 
 	/* return error if streaming was stopped in the meantime */
 	if (sur40->sequence == -1)
-		goto err_poll;
+		return;
 
 	/* mark as finished */
 	v4l2_get_timestamp(&new_buf->vb.timestamp);
@@ -496,10 +496,13 @@
 	int error;
 
 	/* Check if we really have the right interface. */
-	iface_desc = &interface->altsetting[0];
+	iface_desc = interface->cur_altsetting;
 	if (iface_desc->desc.bInterfaceClass != 0xFF)
 		return -ENODEV;
 
+	if (iface_desc->desc.bNumEndpoints < 5)
+		return -ENODEV;
+
 	/* Use endpoint #4 (0x86). */
 	endpoint = &iface_desc->endpoint[4].desc;
 	if (endpoint->bEndpointAddress != TOUCH_ENDPOINT)
@@ -730,6 +733,7 @@
 static void sur40_stop_streaming(struct vb2_queue *vq)
 {
 	struct sur40_state *sur40 = vb2_get_drv_priv(vq);
+	vb2_wait_for_all_buffers(vq);
 	sur40->sequence = -1;
 
 	/* Release all active buffers */
--- linux-4.4.0.orig/drivers/input/touchscreen/tsc2004.c
+++ linux-4.4.0/drivers/input/touchscreen/tsc2004.c
@@ -22,6 +22,11 @@
 #include <linux/regmap.h>
 #include "tsc200x-core.h"
 
+static const struct input_id tsc2004_input_id = {
+	.bustype = BUS_I2C,
+	.product = 2004,
+};
+
 static int tsc2004_cmd(struct device *dev, u8 cmd)
 {
 	u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd;
@@ -42,7 +47,7 @@
 			 const struct i2c_device_id *id)
 
 {
-	return tsc200x_probe(&i2c->dev, i2c->irq, BUS_I2C,
+	return tsc200x_probe(&i2c->dev, i2c->irq, &tsc2004_input_id,
 			     devm_regmap_init_i2c(i2c, &tsc200x_regmap_config),
 			     tsc2004_cmd);
 }
--- linux-4.4.0.orig/drivers/input/touchscreen/tsc2005.c
+++ linux-4.4.0/drivers/input/touchscreen/tsc2005.c
@@ -24,6 +24,11 @@
 #include <linux/regmap.h>
 #include "tsc200x-core.h"
 
+static const struct input_id tsc2005_input_id = {
+	.bustype = BUS_SPI,
+	.product = 2005,
+};
+
 static int tsc2005_cmd(struct device *dev, u8 cmd)
 {
 	u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd;
@@ -62,7 +67,7 @@
 	if (error)
 		return error;
 
-	return tsc200x_probe(&spi->dev, spi->irq, BUS_SPI,
+	return tsc200x_probe(&spi->dev, spi->irq, &tsc2005_input_id,
 			     devm_regmap_init_spi(spi, &tsc200x_regmap_config),
 			     tsc2005_cmd);
 }
--- linux-4.4.0.orig/drivers/input/touchscreen/tsc2007.c
+++ linux-4.4.0/drivers/input/touchscreen/tsc2007.c
@@ -455,6 +455,14 @@
 
 	tsc2007_stop(ts);
 
+	/* power down the chip (TSC2007_SETUP does not ACK on I2C) */
+	err = tsc2007_xfer(ts, PWRDOWN);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to setup chip: %d\n", err);
+		return err;	/* usually, chip does not respond */
+	}
+
 	err = input_register_device(input_dev);
 	if (err) {
 		dev_err(&client->dev,
--- linux-4.4.0.orig/drivers/input/touchscreen/tsc200x-core.c
+++ linux-4.4.0/drivers/input/touchscreen/tsc200x-core.c
@@ -450,7 +450,7 @@
 	mutex_unlock(&ts->mutex);
 }
 
-int tsc200x_probe(struct device *dev, int irq, __u16 bustype,
+int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
 		  struct regmap *regmap,
 		  int (*tsc200x_cmd)(struct device *dev, u8 cmd))
 {
@@ -547,9 +547,18 @@
 	snprintf(ts->phys, sizeof(ts->phys),
 		 "%s/input-ts", dev_name(dev));
 
-	input_dev->name = "TSC200X touchscreen";
+	if (tsc_id->product == 2004) {
+		input_dev->name = "TSC200X touchscreen";
+	} else {
+		input_dev->name = devm_kasprintf(dev, GFP_KERNEL,
+						 "TSC%04d touchscreen",
+						 tsc_id->product);
+		if (!input_dev->name)
+			return -ENOMEM;
+	}
+
 	input_dev->phys = ts->phys;
-	input_dev->id.bustype = bustype;
+	input_dev->id = *tsc_id;
 	input_dev->dev.parent = dev;
 	input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
--- linux-4.4.0.orig/drivers/input/touchscreen/tsc200x-core.h
+++ linux-4.4.0/drivers/input/touchscreen/tsc200x-core.h
@@ -70,7 +70,7 @@
 extern const struct regmap_config tsc200x_regmap_config;
 extern const struct dev_pm_ops tsc200x_pm_ops;
 
-int tsc200x_probe(struct device *dev, int irq, __u16 bustype,
+int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
 		  struct regmap *regmap,
 		  int (*tsc200x_cmd)(struct device *dev, u8 cmd));
 int tsc200x_remove(struct device *dev);
--- linux-4.4.0.orig/drivers/input/touchscreen/usbtouchscreen.c
+++ linux-4.4.0/drivers/input/touchscreen/usbtouchscreen.c
@@ -197,6 +197,7 @@
 #endif
 
 #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+	{USB_DEVICE(0x255e, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
 	{USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
 	{USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
 	{USB_DEVICE(0x6615, 0x0012), .driver_info = DEVTYPE_IRTOUCH_HIRES},
--- linux-4.4.0.orig/drivers/input/touchscreen/wacom_w8001.c
+++ linux-4.4.0/drivers/input/touchscreen/wacom_w8001.c
@@ -27,7 +27,7 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#define W8001_MAX_LENGTH	11
+#define W8001_MAX_LENGTH	13
 #define W8001_LEAD_MASK		0x80
 #define W8001_LEAD_BYTE		0x80
 #define W8001_TAB_MASK		0x40
@@ -80,7 +80,8 @@
  */
 
 struct w8001 {
-	struct input_dev *dev;
+	struct input_dev *pen_dev;
+	struct input_dev *touch_dev;
 	struct serio *serio;
 	struct completion cmd_done;
 	int id;
@@ -95,7 +96,10 @@
 	u16 max_touch_y;
 	u16 max_pen_x;
 	u16 max_pen_y;
-	char name[64];
+	char pen_name[64];
+	char touch_name[64];
+	int open_count;
+	struct mutex mutex;
 };
 
 static void parse_pen_data(u8 *data, struct w8001_coord *coord)
@@ -141,7 +145,7 @@
 
 static void parse_multi_touch(struct w8001 *w8001)
 {
-	struct input_dev *dev = w8001->dev;
+	struct input_dev *dev = w8001->touch_dev;
 	unsigned char *data = w8001->data;
 	unsigned int x, y;
 	int i;
@@ -151,7 +155,6 @@
 		bool touch = data[0] & (1 << i);
 
 		input_mt_slot(dev, i);
-		input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
 		if (touch) {
 			x = (data[6 * i + 1] << 7) | data[6 * i + 2];
 			y = (data[6 * i + 3] << 7) | data[6 * i + 4];
@@ -207,7 +210,7 @@
 
 static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
 {
-	struct input_dev *dev = w8001->dev;
+	struct input_dev *dev = w8001->pen_dev;
 
 	/*
 	 * We have 1 bit for proximity (rdy) and 3 bits for tip, side,
@@ -233,11 +236,6 @@
 		break;
 
 	case BTN_TOOL_FINGER:
-		input_report_key(dev, BTN_TOUCH, 0);
-		input_report_key(dev, BTN_TOOL_FINGER, 0);
-		input_sync(dev);
-		/* fall through */
-
 	case KEY_RESERVED:
 		w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
 		break;
@@ -261,7 +259,7 @@
 
 static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
 {
-	struct input_dev *dev = w8001->dev;
+	struct input_dev *dev = w8001->touch_dev;
 	unsigned int x = coord->x;
 	unsigned int y = coord->y;
 
@@ -271,7 +269,6 @@
 	input_report_abs(dev, ABS_X, x);
 	input_report_abs(dev, ABS_Y, y);
 	input_report_key(dev, BTN_TOUCH, coord->tsw);
-	input_report_key(dev, BTN_TOOL_FINGER, coord->tsw);
 
 	input_sync(dev);
 
@@ -369,22 +366,36 @@
 static int w8001_open(struct input_dev *dev)
 {
 	struct w8001 *w8001 = input_get_drvdata(dev);
+	int err;
+
+	err = mutex_lock_interruptible(&w8001->mutex);
+	if (err)
+		return err;
 
-	return w8001_command(w8001, W8001_CMD_START, false);
+	if (w8001->open_count++ == 0) {
+		err = w8001_command(w8001, W8001_CMD_START, false);
+		if (err)
+			w8001->open_count--;
+	}
+
+	mutex_unlock(&w8001->mutex);
+	return err;
 }
 
 static void w8001_close(struct input_dev *dev)
 {
 	struct w8001 *w8001 = input_get_drvdata(dev);
 
-	w8001_command(w8001, W8001_CMD_STOP, false);
+	mutex_lock(&w8001->mutex);
+
+	if (--w8001->open_count == 0)
+		w8001_command(w8001, W8001_CMD_STOP, false);
+
+	mutex_unlock(&w8001->mutex);
 }
 
-static int w8001_setup(struct w8001 *w8001)
+static int w8001_detect(struct w8001 *w8001)
 {
-	struct input_dev *dev = w8001->dev;
-	struct w8001_coord coord;
-	struct w8001_touch_query touch;
 	int error;
 
 	error = w8001_command(w8001, W8001_CMD_STOP, false);
@@ -393,105 +404,145 @@
 
 	msleep(250);	/* wait 250ms before querying the device */
 
-	dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-	strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
+	return 0;
+}
 
-	__set_bit(INPUT_PROP_DIRECT, dev->propbit);
+static int w8001_setup_pen(struct w8001 *w8001, char *basename,
+			   size_t basename_sz)
+{
+	struct input_dev *dev = w8001->pen_dev;
+	struct w8001_coord coord;
+	int error;
 
 	/* penabled? */
 	error = w8001_command(w8001, W8001_CMD_QUERY, true);
-	if (!error) {
-		__set_bit(BTN_TOUCH, dev->keybit);
-		__set_bit(BTN_TOOL_PEN, dev->keybit);
-		__set_bit(BTN_TOOL_RUBBER, dev->keybit);
-		__set_bit(BTN_STYLUS, dev->keybit);
-		__set_bit(BTN_STYLUS2, dev->keybit);
-
-		parse_pen_data(w8001->response, &coord);
-		w8001->max_pen_x = coord.x;
-		w8001->max_pen_y = coord.y;
-
-		input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
-		input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
-		input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
-		input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
-		input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
-		if (coord.tilt_x && coord.tilt_y) {
-			input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
-			input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
-		}
-		w8001->id = 0x90;
-		strlcat(w8001->name, " Penabled", sizeof(w8001->name));
+	if (error)
+		return error;
+
+	__set_bit(EV_KEY, dev->evbit);
+	__set_bit(EV_ABS, dev->evbit);
+	__set_bit(BTN_TOUCH, dev->keybit);
+	__set_bit(BTN_TOOL_PEN, dev->keybit);
+	__set_bit(BTN_TOOL_RUBBER, dev->keybit);
+	__set_bit(BTN_STYLUS, dev->keybit);
+	__set_bit(BTN_STYLUS2, dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, dev->propbit);
+
+	parse_pen_data(w8001->response, &coord);
+	w8001->max_pen_x = coord.x;
+	w8001->max_pen_y = coord.y;
+
+	input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
+	input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
+	input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
+	input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
+	input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
+	if (coord.tilt_x && coord.tilt_y) {
+		input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
+		input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
 	}
 
+	w8001->id = 0x90;
+	strlcat(basename, " Penabled", basename_sz);
+
+	return 0;
+}
+
+static int w8001_setup_touch(struct w8001 *w8001, char *basename,
+			     size_t basename_sz)
+{
+	struct input_dev *dev = w8001->touch_dev;
+	struct w8001_touch_query touch;
+	int error;
+
+
 	/* Touch enabled? */
 	error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
-
+	if (error)
+		return error;
 	/*
 	 * Some non-touch devices may reply to the touch query. But their
 	 * second byte is empty, which indicates touch is not supported.
 	 */
-	if (!error && w8001->response[1]) {
-		__set_bit(BTN_TOUCH, dev->keybit);
-		__set_bit(BTN_TOOL_FINGER, dev->keybit);
-
-		parse_touchquery(w8001->response, &touch);
-		w8001->max_touch_x = touch.x;
-		w8001->max_touch_y = touch.y;
-
-		if (w8001->max_pen_x && w8001->max_pen_y) {
-			/* if pen is supported scale to pen maximum */
-			touch.x = w8001->max_pen_x;
-			touch.y = w8001->max_pen_y;
-			touch.panel_res = W8001_PEN_RESOLUTION;
-		}
+	if (!w8001->response[1])
+		return -ENXIO;
 
-		input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
-		input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
-		input_abs_set_res(dev, ABS_X, touch.panel_res);
-		input_abs_set_res(dev, ABS_Y, touch.panel_res);
-
-		switch (touch.sensor_id) {
-		case 0:
-		case 2:
-			w8001->pktlen = W8001_PKTLEN_TOUCH93;
-			w8001->id = 0x93;
-			strlcat(w8001->name, " 1FG", sizeof(w8001->name));
-			break;
+	__set_bit(EV_KEY, dev->evbit);
+	__set_bit(EV_ABS, dev->evbit);
+	__set_bit(BTN_TOUCH, dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, dev->propbit);
 
-		case 1:
-		case 3:
-		case 4:
-			w8001->pktlen = W8001_PKTLEN_TOUCH9A;
-			strlcat(w8001->name, " 1FG", sizeof(w8001->name));
-			w8001->id = 0x9a;
-			break;
+	parse_touchquery(w8001->response, &touch);
+	w8001->max_touch_x = touch.x;
+	w8001->max_touch_y = touch.y;
+
+	if (w8001->max_pen_x && w8001->max_pen_y) {
+		/* if pen is supported scale to pen maximum */
+		touch.x = w8001->max_pen_x;
+		touch.y = w8001->max_pen_y;
+		touch.panel_res = W8001_PEN_RESOLUTION;
+	}
 
-		case 5:
-			w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
+	input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
+	input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
+	input_abs_set_res(dev, ABS_X, touch.panel_res);
+	input_abs_set_res(dev, ABS_Y, touch.panel_res);
 
-			input_mt_init_slots(dev, 2, 0);
-			input_set_abs_params(dev, ABS_MT_POSITION_X,
-						0, touch.x, 0, 0);
-			input_set_abs_params(dev, ABS_MT_POSITION_Y,
-						0, touch.y, 0, 0);
-			input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
-						0, MT_TOOL_MAX, 0, 0);
-
-			strlcat(w8001->name, " 2FG", sizeof(w8001->name));
-			if (w8001->max_pen_x && w8001->max_pen_y)
-				w8001->id = 0xE3;
-			else
-				w8001->id = 0xE2;
-			break;
-		}
+	switch (touch.sensor_id) {
+	case 0:
+	case 2:
+		w8001->pktlen = W8001_PKTLEN_TOUCH93;
+		w8001->id = 0x93;
+		strlcat(basename, " 1FG", basename_sz);
+		break;
+
+	case 1:
+	case 3:
+	case 4:
+		w8001->pktlen = W8001_PKTLEN_TOUCH9A;
+		strlcat(basename, " 1FG", basename_sz);
+		w8001->id = 0x9a;
+		break;
+
+	case 5:
+		w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
+
+		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+		input_mt_init_slots(dev, 2, 0);
+		input_set_abs_params(dev, ABS_MT_POSITION_X,
+					0, touch.x, 0, 0);
+		input_set_abs_params(dev, ABS_MT_POSITION_Y,
+					0, touch.y, 0, 0);
+
+		strlcat(basename, " 2FG", basename_sz);
+		if (w8001->max_pen_x && w8001->max_pen_y)
+			w8001->id = 0xE3;
+		else
+			w8001->id = 0xE2;
+		break;
 	}
 
-	strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
+	strlcat(basename, " Touchscreen", basename_sz);
 
 	return 0;
 }
 
+static void w8001_set_devdata(struct input_dev *dev, struct w8001 *w8001,
+			      struct serio *serio)
+{
+	dev->phys = w8001->phys;
+	dev->id.bustype = BUS_RS232;
+	dev->id.product = w8001->id;
+	dev->id.vendor = 0x056a;
+	dev->id.version = 0x0100;
+	dev->open = w8001_open;
+	dev->close = w8001_close;
+
+	dev->dev.parent = &serio->dev;
+
+	input_set_drvdata(dev, w8001);
+}
+
 /*
  * w8001_disconnect() is the opposite of w8001_connect()
  */
@@ -502,7 +553,10 @@
 
 	serio_close(serio);
 
-	input_unregister_device(w8001->dev);
+	if (w8001->pen_dev)
+		input_unregister_device(w8001->pen_dev);
+	if (w8001->touch_dev)
+		input_unregister_device(w8001->touch_dev);
 	kfree(w8001);
 
 	serio_set_drvdata(serio, NULL);
@@ -517,18 +571,23 @@
 static int w8001_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct w8001 *w8001;
-	struct input_dev *input_dev;
-	int err;
+	struct input_dev *input_dev_pen;
+	struct input_dev *input_dev_touch;
+	char basename[64];
+	int err, err_pen, err_touch;
 
 	w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!w8001 || !input_dev) {
+	input_dev_pen = input_allocate_device();
+	input_dev_touch = input_allocate_device();
+	if (!w8001 || !input_dev_pen || !input_dev_touch) {
 		err = -ENOMEM;
 		goto fail1;
 	}
 
 	w8001->serio = serio;
-	w8001->dev = input_dev;
+	w8001->pen_dev = input_dev_pen;
+	w8001->touch_dev = input_dev_touch;
+	mutex_init(&w8001->mutex);
 	init_completion(&w8001->cmd_done);
 	snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
 
@@ -537,35 +596,67 @@
 	if (err)
 		goto fail2;
 
-	err = w8001_setup(w8001);
+	err = w8001_detect(w8001);
 	if (err)
 		goto fail3;
 
-	input_dev->name = w8001->name;
-	input_dev->phys = w8001->phys;
-	input_dev->id.product = w8001->id;
-	input_dev->id.bustype = BUS_RS232;
-	input_dev->id.vendor = 0x056a;
-	input_dev->id.version = 0x0100;
-	input_dev->dev.parent = &serio->dev;
+	/* For backwards-compatibility we compose the basename based on
+	 * capabilities and then just append the tool type
+	 */
+	strlcpy(basename, "Wacom Serial", sizeof(basename));
 
-	input_dev->open = w8001_open;
-	input_dev->close = w8001_close;
+	err_pen = w8001_setup_pen(w8001, basename, sizeof(basename));
+	err_touch = w8001_setup_touch(w8001, basename, sizeof(basename));
+	if (err_pen && err_touch) {
+		err = -ENXIO;
+		goto fail3;
+	}
 
-	input_set_drvdata(input_dev, w8001);
+	if (!err_pen) {
+		strlcpy(w8001->pen_name, basename, sizeof(w8001->pen_name));
+		strlcat(w8001->pen_name, " Pen", sizeof(w8001->pen_name));
+		input_dev_pen->name = w8001->pen_name;
+
+		w8001_set_devdata(input_dev_pen, w8001, serio);
+
+		err = input_register_device(w8001->pen_dev);
+		if (err)
+			goto fail3;
+	} else {
+		input_free_device(input_dev_pen);
+		input_dev_pen = NULL;
+		w8001->pen_dev = NULL;
+	}
 
-	err = input_register_device(w8001->dev);
-	if (err)
-		goto fail3;
+	if (!err_touch) {
+		strlcpy(w8001->touch_name, basename, sizeof(w8001->touch_name));
+		strlcat(w8001->touch_name, " Finger",
+			sizeof(w8001->touch_name));
+		input_dev_touch->name = w8001->touch_name;
+
+		w8001_set_devdata(input_dev_touch, w8001, serio);
+
+		err = input_register_device(w8001->touch_dev);
+		if (err)
+			goto fail4;
+	} else {
+		input_free_device(input_dev_touch);
+		input_dev_touch = NULL;
+		w8001->touch_dev = NULL;
+	}
 
 	return 0;
 
+fail4:
+	if (w8001->pen_dev)
+		input_unregister_device(w8001->pen_dev);
 fail3:
 	serio_close(serio);
 fail2:
 	serio_set_drvdata(serio, NULL);
 fail1:
-	input_free_device(input_dev);
+	input_free_device(input_dev_pen);
+	input_free_device(input_dev_touch);
 	kfree(w8001);
 	return err;
 }
--- linux-4.4.0.orig/drivers/input/touchscreen/zforce_ts.c
+++ linux-4.4.0/drivers/input/touchscreen/zforce_ts.c
@@ -370,8 +370,8 @@
 			point.coord_x = point.coord_y = 0;
 		}
 
-		point.state = payload[9 * i + 5] & 0x03;
-		point.id = (payload[9 * i + 5] & 0xfc) >> 2;
+		point.state = payload[9 * i + 5] & 0x0f;
+		point.id = (payload[9 * i + 5] & 0xf0) >> 4;
 
 		/* determine touch major, minor and orientation */
 		point.area_major = max(payload[9 * i + 6],
--- linux-4.4.0.orig/drivers/iommu/amd_iommu.c
+++ linux-4.4.0/drivers/iommu/amd_iommu.c
@@ -91,6 +91,7 @@
 	struct list_head dev_data_list;	  /* For global dev_data_list */
 	struct protection_domain *domain; /* Domain the device is bound to */
 	u16 devid;			  /* PCI Device ID */
+	u16 alias;			  /* Alias Device ID */
 	bool iommu_v2;			  /* Device can make use of IOMMUv2 */
 	bool passthrough;		  /* Device is identity mapped */
 	struct {
@@ -125,6 +126,13 @@
 	return container_of(dom, struct protection_domain, domain);
 }
 
+static inline u16 get_device_id(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	return PCI_DEVID(pdev->bus->number, pdev->devfn);
+}
+
 static struct iommu_dev_data *alloc_dev_data(u16 devid)
 {
 	struct iommu_dev_data *dev_data;
@@ -162,6 +170,68 @@
 	return dev_data;
 }
 
+static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
+{
+	*(u16 *)data = alias;
+	return 0;
+}
+
+static u16 get_alias(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u16 devid, ivrs_alias, pci_alias;
+
+	devid = get_device_id(dev);
+	ivrs_alias = amd_iommu_alias_table[devid];
+	pci_for_each_dma_alias(pdev, __last_alias, &pci_alias);
+
+	if (ivrs_alias == pci_alias)
+		return ivrs_alias;
+
+	/*
+	 * DMA alias showdown
+	 *
+	 * The IVRS is fairly reliable in telling us about aliases, but it
+	 * can't know about every screwy device.  If we don't have an IVRS
+	 * reported alias, use the PCI reported alias.  In that case we may
+	 * still need to initialize the rlookup and dev_table entries if the
+	 * alias is to a non-existent device.
+	 */
+	if (ivrs_alias == devid) {
+		if (!amd_iommu_rlookup_table[pci_alias]) {
+			amd_iommu_rlookup_table[pci_alias] =
+				amd_iommu_rlookup_table[devid];
+			memcpy(amd_iommu_dev_table[pci_alias].data,
+			       amd_iommu_dev_table[devid].data,
+			       sizeof(amd_iommu_dev_table[pci_alias].data));
+		}
+
+		return pci_alias;
+	}
+
+	pr_info("AMD-Vi: Using IVRS reported alias %02x:%02x.%d "
+		"for device %s[%04x:%04x], kernel reported alias "
+		"%02x:%02x.%d\n", PCI_BUS_NUM(ivrs_alias), PCI_SLOT(ivrs_alias),
+		PCI_FUNC(ivrs_alias), dev_name(dev), pdev->vendor, pdev->device,
+		PCI_BUS_NUM(pci_alias), PCI_SLOT(pci_alias),
+		PCI_FUNC(pci_alias));
+
+	/*
+	 * If we don't have a PCI DMA alias and the IVRS alias is on the same
+	 * bus, then the IVRS table may know about a quirk that we don't.
+	 */
+	if (pci_alias == devid &&
+	    PCI_BUS_NUM(ivrs_alias) == pdev->bus->number) {
+		pdev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
+		pdev->dma_alias_devfn = ivrs_alias & 0xff;
+		pr_info("AMD-Vi: Added PCI DMA alias %02x.%d for %s\n",
+			PCI_SLOT(ivrs_alias), PCI_FUNC(ivrs_alias),
+			dev_name(dev));
+	}
+
+	return ivrs_alias;
+}
+
 static struct iommu_dev_data *find_dev_data(u16 devid)
 {
 	struct iommu_dev_data *dev_data;
@@ -174,13 +244,6 @@
 	return dev_data;
 }
 
-static inline u16 get_device_id(struct device *dev)
-{
-	struct pci_dev *pdev = to_pci_dev(dev);
-
-	return PCI_DEVID(pdev->bus->number, pdev->devfn);
-}
-
 static struct iommu_dev_data *get_dev_data(struct device *dev)
 {
 	return dev->archdata.iommu;
@@ -289,9 +352,11 @@
 	if (!domain)
 		goto out;
 
-	dma_domain = to_pdomain(domain)->priv;
+	if (to_pdomain(domain)->flags == PD_DMA_OPS_MASK) {
+		dma_domain = to_pdomain(domain)->priv;
+		init_unity_mappings_for_device(dev, dma_domain);
+	}
 
-	init_unity_mappings_for_device(dev, dma_domain);
 out:
 	iommu_group_put(group);
 }
@@ -308,6 +373,8 @@
 	if (!dev_data)
 		return -ENOMEM;
 
+	dev_data->alias = get_alias(dev);
+
 	if (pci_iommuv2_capable(pdev)) {
 		struct amd_iommu *iommu;
 
@@ -328,7 +395,7 @@
 	u16 devid, alias;
 
 	devid = get_device_id(dev);
-	alias = amd_iommu_alias_table[devid];
+	alias = get_alias(dev);
 
 	memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
 	memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry));
@@ -859,7 +926,7 @@
 	next_tail = (tail + sizeof(*cmd)) % CMD_BUFFER_SIZE;
 	left      = (head - next_tail) % CMD_BUFFER_SIZE;
 
-	if (left <= 2) {
+	if (left <= 0x20) {
 		struct iommu_cmd sync_cmd;
 		volatile u64 sem = 0;
 		int ret;
@@ -1017,7 +1084,7 @@
 	int ret;
 
 	iommu = amd_iommu_rlookup_table[dev_data->devid];
-	alias = amd_iommu_alias_table[dev_data->devid];
+	alias = dev_data->alias;
 
 	ret = iommu_flush_dte(iommu, dev_data->devid);
 	if (!ret && alias != dev_data->devid)
@@ -1766,6 +1833,9 @@
 		kfree(dom->aperture[i]);
 	}
 
+	if (dom->domain.id)
+		domain_id_free(dom->domain.id);
+
 	kfree(dom);
 }
 
@@ -1891,7 +1961,7 @@
 	bool ats;
 
 	iommu = amd_iommu_rlookup_table[dev_data->devid];
-	alias = amd_iommu_alias_table[dev_data->devid];
+	alias = dev_data->alias;
 	ats   = dev_data->ats.enabled;
 
 	/* Update data structures */
@@ -1905,13 +1975,14 @@
 	/* Update device table */
 	set_dte_entry(dev_data->devid, domain, ats);
 	if (alias != dev_data->devid)
-		set_dte_entry(dev_data->devid, domain, ats);
+		set_dte_entry(alias, domain, ats);
 
 	device_flush_dte(dev_data);
 }
 
 static void do_detach(struct iommu_dev_data *dev_data)
 {
+	struct protection_domain *domain = dev_data->domain;
 	struct amd_iommu *iommu;
 	u16 alias;
 
@@ -1925,11 +1996,7 @@
 		return;
 
 	iommu = amd_iommu_rlookup_table[dev_data->devid];
-	alias = amd_iommu_alias_table[dev_data->devid];
-
-	/* decrease reference counters */
-	dev_data->domain->dev_iommu[iommu->index] -= 1;
-	dev_data->domain->dev_cnt                 -= 1;
+	alias = dev_data->alias;
 
 	/* Update data structures */
 	dev_data->domain = NULL;
@@ -1940,6 +2007,16 @@
 
 	/* Flush the DTE entry */
 	device_flush_dte(dev_data);
+
+	/* Flush IOTLB */
+	domain_flush_tlb_pde(domain);
+
+	/* Wait for the flushes to finish */
+	domain_flush_complete(domain);
+
+	/* decrease reference counters - needs to happen after the flushes */
+	domain->dev_iommu[iommu->index] -= 1;
+	domain->dev_cnt                 -= 1;
 }
 
 /*
@@ -2107,6 +2184,8 @@
 	 */
 	domain_flush_tlb_pde(domain);
 
+	domain_flush_complete(domain);
+
 	return ret;
 }
 
@@ -2257,8 +2336,15 @@
 {
 	struct iommu_dev_data *dev_data;
 
-	list_for_each_entry(dev_data, &domain->dev_list, list)
+	list_for_each_entry(dev_data, &domain->dev_list, list) {
 		set_dte_entry(dev_data->devid, domain, dev_data->ats.enabled);
+
+		if (dev_data->devid == dev_data->alias)
+			continue;
+
+		/* There is an alias, update device table entry for it */
+		set_dte_entry(dev_data->alias, domain, dev_data->ats.enabled);
+	}
 }
 
 static void update_domain(struct protection_domain *domain)
@@ -2905,9 +2991,7 @@
 static void amd_iommu_domain_free(struct iommu_domain *dom)
 {
 	struct protection_domain *domain;
-
-	if (!dom)
-		return;
+	struct dma_ops_domain *dma_dom;
 
 	domain = to_pdomain(dom);
 
@@ -2916,13 +3000,24 @@
 
 	BUG_ON(domain->dev_cnt != 0);
 
-	if (domain->mode != PAGE_MODE_NONE)
-		free_pagetable(domain);
+	if (!dom)
+		return;
+
+	switch (dom->type) {
+	case IOMMU_DOMAIN_DMA:
+		dma_dom = domain->priv;
+		dma_ops_domain_free(dma_dom);
+		break;
+	default:
+		if (domain->mode != PAGE_MODE_NONE)
+			free_pagetable(domain);
 
-	if (domain->flags & PD_IOMMUV2_MASK)
-		free_gcr3_table(domain);
+		if (domain->flags & PD_IOMMUV2_MASK)
+			free_gcr3_table(domain);
 
-	protection_domain_free(domain);
+		protection_domain_free(domain);
+		break;
+	}
 }
 
 static void amd_iommu_detach_device(struct iommu_domain *dom,
@@ -3010,6 +3105,7 @@
 	mutex_unlock(&domain->api_lock);
 
 	domain_flush_tlb_pde(domain);
+	domain_flush_complete(domain);
 
 	return unmap_size;
 }
@@ -3529,7 +3625,7 @@
 
 #define DTE_IRQ_PHYS_ADDR_MASK	(((1ULL << 45)-1) << 6)
 #define DTE_IRQ_REMAP_INTCTL    (2ULL << 60)
-#define DTE_IRQ_TABLE_LEN       (8ULL << 1)
+#define DTE_IRQ_TABLE_LEN       (9ULL << 1)
 #define DTE_IRQ_REMAP_ENABLE    1ULL
 
 static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
--- linux-4.4.0.orig/drivers/iommu/amd_iommu_init.c
+++ linux-4.4.0/drivers/iommu/amd_iommu_init.c
@@ -228,6 +228,10 @@
 static int __init iommu_go_to_state(enum iommu_init_state state);
 static void init_device_table_dma(void);
 
+static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
+				    u8 bank, u8 cntr, u8 fxn,
+				    u64 *value, bool is_write);
+
 static inline void update_last_devid(u16 devid)
 {
 	if (devid > amd_iommu_last_bdf)
@@ -291,7 +295,7 @@
 static void iommu_set_exclusion_range(struct amd_iommu *iommu)
 {
 	u64 start = iommu->exclusion_start & PAGE_MASK;
-	u64 limit = (start + iommu->exclusion_length) & PAGE_MASK;
+	u64 limit = (start + iommu->exclusion_length - 1) & PAGE_MASK;
 	u64 entry;
 
 	if (!iommu->exclusion_start)
@@ -356,6 +360,9 @@
 
 static void iommu_disable(struct amd_iommu *iommu)
 {
+	if (!iommu->mmio_base)
+		return;
+
 	/* Disable command buffer */
 	iommu_feature_disable(iommu, CONTROL_CMDBUF_EN);
 
@@ -1016,6 +1023,34 @@
 }
 
 /*
+ * Family15h Model 30h-3fh (IOMMU Mishandles ATS Write Permission)
+ * Workaround:
+ *     BIOS should enable ATS write permission check by setting
+ *     L2_DEBUG_3[AtsIgnoreIWDis](D0F2xF4_x47[0]) = 1b
+ */
+static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu)
+{
+	u32 value;
+
+	if ((boot_cpu_data.x86 != 0x15) ||
+	    (boot_cpu_data.x86_model < 0x30) ||
+	    (boot_cpu_data.x86_model > 0x3f))
+		return;
+
+	/* Test L2_DEBUG_3[AtsIgnoreIWDis] == 1 */
+	value = iommu_read_l2(iommu, 0x47);
+
+	if (value & BIT(0))
+		return;
+
+	/* Set L2_DEBUG_3[AtsIgnoreIWDis] = 1 */
+	iommu_write_l2(iommu, 0x47, value | BIT(0));
+
+	pr_info("AMD-Vi: Applying ATS write check workaround for IOMMU at %s\n",
+		dev_name(&iommu->dev->dev));
+}
+
+/*
  * This function clues the initialization function for one IOMMU
  * together and also allocates the command buffer and programs the
  * hardware. It does NOT enable the IOMMU. This is done afterwards.
@@ -1142,8 +1177,8 @@
 	amd_iommu_pc_present = true;
 
 	/* Check if the performance counters can be written to */
-	if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) ||
-	    (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) ||
+	if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) ||
+	    (0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) ||
 	    (val != val2)) {
 		pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n");
 		amd_iommu_pc_present = false;
@@ -1191,7 +1226,7 @@
 	NULL,
 };
 
-static int iommu_init_pci(struct amd_iommu *iommu)
+static int __init iommu_init_pci(struct amd_iommu *iommu)
 {
 	int cap_ptr = iommu->cap_ptr;
 	u32 range, misc, low, high;
@@ -1284,6 +1319,7 @@
 	}
 
 	amd_iommu_erratum_746_workaround(iommu);
+	amd_iommu_ats_write_check_workaround(iommu);
 
 	iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
 					       amd_iommu_groups, "ivhd%d",
@@ -1330,13 +1366,23 @@
 			break;
 	}
 
+	/*
+	 * Order is important here to make sure any unity map requirements are
+	 * fulfilled. The unity mappings are created and written to the device
+	 * table during the amd_iommu_init_api() call.
+	 *
+	 * After that we call init_device_table_dma() to make sure any
+	 * uninitialized DTE will block DMA, and in the end we flush the caches
+	 * of all IOMMUs to make sure the changes to the device table are
+	 * active.
+	 */
+	ret = amd_iommu_init_api();
+
 	init_device_table_dma();
 
 	for_each_iommu(iommu)
 		iommu_flush_all_caches(iommu);
 
-	ret = amd_iommu_init_api();
-
 	if (!ret)
 		print_iommu_info();
 
@@ -2283,22 +2329,15 @@
 }
 EXPORT_SYMBOL(amd_iommu_pc_get_max_counters);
 
-int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
+static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
+				    u8 bank, u8 cntr, u8 fxn,
 				    u64 *value, bool is_write)
 {
-	struct amd_iommu *iommu;
 	u32 offset;
 	u32 max_offset_lim;
 
-	/* Make sure the IOMMU PC resource is available */
-	if (!amd_iommu_pc_present)
-		return -ENODEV;
-
-	/* Locate the iommu associated with the device ID */
-	iommu = amd_iommu_rlookup_table[devid];
-
 	/* Check for valid iommu and pc register indexing */
-	if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7)))
+	if (WARN_ON((fxn > 0x28) || (fxn & 7)))
 		return -ENODEV;
 
 	offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn);
@@ -2322,3 +2361,16 @@
 	return 0;
 }
 EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val);
+
+int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
+				    u64 *value, bool is_write)
+{
+	struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
+
+	/* Make sure the IOMMU PC resource is available */
+	if (!amd_iommu_pc_present || iommu == NULL)
+		return -ENODEV;
+
+	return iommu_pc_get_set_reg_val(iommu, bank, cntr, fxn,
+					value, is_write);
+}
--- linux-4.4.0.orig/drivers/iommu/amd_iommu_types.h
+++ linux-4.4.0/drivers/iommu/amd_iommu_types.h
@@ -303,7 +303,7 @@
 
 #define DTE_GCR3_VAL_A(x)	(((x) >> 12) & 0x00007ULL)
 #define DTE_GCR3_VAL_B(x)	(((x) >> 15) & 0x0ffffULL)
-#define DTE_GCR3_VAL_C(x)	(((x) >> 31) & 0xfffffULL)
+#define DTE_GCR3_VAL_C(x)	(((x) >> 31) & 0x1fffffULL)
 
 #define DTE_GCR3_INDEX_A	0
 #define DTE_GCR3_INDEX_B	1
@@ -351,7 +351,11 @@
 /* Only true if all IOMMUs support device IOTLBs */
 extern bool amd_iommu_iotlb_sup;
 
-#define MAX_IRQS_PER_TABLE	256
+/*
+ * AMD IOMMU hardware only support 512 IRTEs despite
+ * the architectural limitation of 2048 entries.
+ */
+#define MAX_IRQS_PER_TABLE	512
 #define IRQ_TABLE_ALIGNMENT	128
 
 struct irq_remap_table {
--- linux-4.4.0.orig/drivers/iommu/amd_iommu_v2.c
+++ linux-4.4.0/drivers/iommu/amd_iommu_v2.c
@@ -699,9 +699,9 @@
 
 out_unregister:
 	mmu_notifier_unregister(&pasid_state->mn, mm);
+	mmput(mm);
 
 out_free:
-	mmput(mm);
 	free_pasid_state(pasid_state);
 
 out:
@@ -809,8 +809,10 @@
 		goto out_free_domain;
 
 	group = iommu_group_get(&pdev->dev);
-	if (!group)
+	if (!group) {
+		ret = -EINVAL;
 		goto out_free_domain;
+	}
 
 	ret = iommu_attach_group(dev_state->domain, group);
 	if (ret != 0)
--- linux-4.4.0.orig/drivers/iommu/arm-smmu-v3.c
+++ linux-4.4.0/drivers/iommu/arm-smmu-v3.c
@@ -683,7 +683,13 @@
 	u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1;
 
 	q->cons = Q_OVF(q, q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
-	writel(q->cons, q->cons_reg);
+
+	/*
+	 * Ensure that all CPU accesses (reads and writes) to the queue
+	 * are complete before we update the cons pointer.
+	 */
+	mb();
+	writel_relaxed(q->cons, q->cons_reg);
 }
 
 static int queue_sync_prod(struct arm_smmu_queue *q)
@@ -870,7 +876,7 @@
 	 * We may have concurrent producers, so we need to be careful
 	 * not to touch any of the shadow cmdq state.
 	 */
-	queue_read(cmd, Q_ENT(q, idx), q->ent_dwords);
+	queue_read(cmd, Q_ENT(q, cons), q->ent_dwords);
 	dev_err(smmu->dev, "skipping command in error state:\n");
 	for (i = 0; i < ARRAY_SIZE(cmd); ++i)
 		dev_err(smmu->dev, "\t0x%016llx\n", (unsigned long long)cmd[i]);
@@ -881,7 +887,7 @@
 		return;
 	}
 
-	queue_write(cmd, Q_ENT(q, idx), q->ent_dwords);
+	queue_write(Q_ENT(q, cons), cmd, q->ent_dwords);
 }
 
 static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
@@ -1025,18 +1031,16 @@
 		case STRTAB_STE_0_CFG_S2_TRANS:
 			ste_live = true;
 			break;
+		case STRTAB_STE_0_CFG_ABORT:
+			if (disable_bypass)
+				break;
 		default:
 			BUG(); /* STE corruption */
 		}
 	}
 
-	/* Nuke the existing Config, as we're going to rewrite it */
-	val &= ~(STRTAB_STE_0_CFG_MASK << STRTAB_STE_0_CFG_SHIFT);
-
-	if (ste->valid)
-		val |= STRTAB_STE_0_V;
-	else
-		val &= ~STRTAB_STE_0_V;
+	/* Nuke the existing STE_0 value, as we're going to rewrite it */
+	val = ste->valid ? STRTAB_STE_0_V : 0;
 
 	if (ste->bypass) {
 		val |= disable_bypass ? STRTAB_STE_0_CFG_ABORT
@@ -1065,7 +1069,6 @@
 		val |= (ste->s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK
 		        << STRTAB_STE_0_S1CTXPTR_SHIFT) |
 			STRTAB_STE_0_CFG_S1_TRANS;
-
 	}
 
 	if (ste->s2_cfg) {
@@ -1087,7 +1090,8 @@
 	}
 
 	arm_smmu_sync_ste_for_sid(smmu, sid);
-	dst[0] = cpu_to_le64(val);
+	/* See comment in arm_smmu_write_ctx_desc() */
+	WRITE_ONCE(dst[0], cpu_to_le64(val));
 	arm_smmu_sync_ste_for_sid(smmu, sid);
 
 	/* It's likely that we'll want to use the new STE soon */
@@ -1222,6 +1226,7 @@
 
 	/* Sync our overflow flag, as we believe we're up to speed */
 	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
+	writel(q->cons, q->cons_reg);
 	return IRQ_HANDLED;
 }
 
@@ -1544,13 +1549,15 @@
 		return -ENOMEM;
 
 	arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
-	smmu_domain->pgtbl_ops = pgtbl_ops;
 
 	ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg);
-	if (IS_ERR_VALUE(ret))
+	if (IS_ERR_VALUE(ret)) {
 		free_io_pgtable_ops(pgtbl_ops);
+		return ret;
+	}
 
-	return ret;
+	smmu_domain->pgtbl_ops = pgtbl_ops;
+	return 0;
 }
 
 static struct arm_smmu_group *arm_smmu_group_get(struct device *dev)
@@ -1919,6 +1926,7 @@
 	.detach_dev		= arm_smmu_detach_dev,
 	.map			= arm_smmu_map,
 	.unmap			= arm_smmu_unmap,
+	.map_sg			= default_iommu_map_sg,
 	.iova_to_phys		= arm_smmu_iova_to_phys,
 	.add_device		= arm_smmu_add_device,
 	.remove_device		= arm_smmu_remove_device,
--- linux-4.4.0.orig/drivers/iommu/dma-iommu.c
+++ linux-4.4.0/drivers/iommu/dma-iommu.c
@@ -68,7 +68,8 @@
 	if (!iovad)
 		return;
 
-	put_iova_domain(iovad);
+	if (iovad->granule)
+		put_iova_domain(iovad);
 	kfree(iovad);
 	domain->iova_cookie = NULL;
 }
@@ -151,12 +152,15 @@
 	}
 }
 
-static struct iova *__alloc_iova(struct iova_domain *iovad, size_t size,
+static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size,
 		dma_addr_t dma_limit)
 {
+	struct iova_domain *iovad = domain->iova_cookie;
 	unsigned long shift = iova_shift(iovad);
 	unsigned long length = iova_align(iovad, size) >> shift;
 
+	if (domain->geometry.force_aperture)
+		dma_limit = min(dma_limit, domain->geometry.aperture_end);
 	/*
 	 * Enforce size-alignment to be safe - there could perhaps be an
 	 * attribute to control this per-device, or at least per-domain...
@@ -296,7 +300,7 @@
 	if (!pages)
 		return NULL;
 
-	iova = __alloc_iova(iovad, size, dev->coherent_dma_mask);
+	iova = __alloc_iova(domain, size, dev->coherent_dma_mask);
 	if (!iova)
 		goto out_free_pages;
 
@@ -368,7 +372,7 @@
 	phys_addr_t phys = page_to_phys(page) + offset;
 	size_t iova_off = iova_offset(iovad, phys);
 	size_t len = iova_align(iovad, size + iova_off);
-	struct iova *iova = __alloc_iova(iovad, len, dma_get_mask(dev));
+	struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev));
 
 	if (!iova)
 		return DMA_ERROR_CODE;
@@ -403,7 +407,7 @@
 		unsigned int s_length = sg_dma_len(s);
 		unsigned int s_dma_len = s->length;
 
-		s->offset = s_offset;
+		s->offset += s_offset;
 		s->length = s_length;
 		sg_dma_address(s) = dma_addr + s_offset;
 		dma_addr += s_dma_len;
@@ -422,7 +426,7 @@
 
 	for_each_sg(sg, s, nents, i) {
 		if (sg_dma_address(s) != DMA_ERROR_CODE)
-			s->offset = sg_dma_address(s);
+			s->offset += sg_dma_address(s);
 		if (sg_dma_len(s))
 			s->length = sg_dma_len(s);
 		sg_dma_address(s) = DMA_ERROR_CODE;
@@ -482,7 +486,7 @@
 		prev = s;
 	}
 
-	iova = __alloc_iova(iovad, iova_len, dma_get_mask(dev));
+	iova = __alloc_iova(domain, iova_len, dma_get_mask(dev));
 	if (!iova)
 		goto out_restore_sg;
 
--- linux-4.4.0.orig/drivers/iommu/dmar.c
+++ linux-4.4.0/drivers/iommu/dmar.c
@@ -39,6 +39,7 @@
 #include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/iommu.h>
+#include <linux/limits.h>
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
@@ -138,12 +139,19 @@
 
 	BUG_ON(dev->is_virtfn);
 
+	/*
+	 * Ignore devices that have a domain number higher than what can
+	 * be looked up in DMAR, e.g. VMD subdevices with domain 0x10000
+	 */
+	if (pci_domain_nr(dev->bus) > U16_MAX)
+		return NULL;
+
 	/* Only generate path[] for device addition event */
 	if (event == BUS_NOTIFY_ADD_DEVICE)
 		for (tmp = dev; tmp; tmp = tmp->bus->self)
 			level++;
 
-	size = sizeof(*info) + level * sizeof(struct acpi_dmar_pci_path);
+	size = sizeof(*info) + level * sizeof(info->path[0]);
 	if (size <= sizeof(dmar_pci_notify_info_buf)) {
 		info = (struct dmar_pci_notify_info *)dmar_pci_notify_info_buf;
 	} else {
@@ -326,10 +334,13 @@
 	struct pci_dev *pdev = to_pci_dev(data);
 	struct dmar_pci_notify_info *info;
 
-	/* Only care about add/remove events for physical functions */
+	/* Only care about add/remove events for physical functions.
+	 * For VFs we actually do the lookup based on the corresponding
+	 * PF in device_to_iommu() anyway. */
 	if (pdev->is_virtfn)
 		return NOTIFY_DONE;
-	if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE)
+	if (action != BUS_NOTIFY_ADD_DEVICE &&
+	    action != BUS_NOTIFY_REMOVED_DEVICE)
 		return NOTIFY_DONE;
 
 	info = dmar_alloc_pci_notify_info(pdev, action);
@@ -339,7 +350,7 @@
 	down_write(&dmar_global_lock);
 	if (action == BUS_NOTIFY_ADD_DEVICE)
 		dmar_pci_bus_add_dev(info);
-	else if (action == BUS_NOTIFY_DEL_DEVICE)
+	else if (action == BUS_NOTIFY_REMOVED_DEVICE)
 		dmar_pci_bus_del_dev(info);
 	up_write(&dmar_global_lock);
 
@@ -435,12 +446,13 @@
 
 	/* Check for NUL termination within the designated length */
 	if (strnlen(andd->device_name, header->length - 8) == header->length - 8) {
-		WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND,
+		pr_warn(FW_BUG
 			   "Your BIOS is broken; ANDD object name is not NUL-terminated\n"
 			   "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
 			   dmi_get_system_info(DMI_BIOS_VENDOR),
 			   dmi_get_system_info(DMI_BIOS_VERSION),
 			   dmi_get_system_info(DMI_PRODUCT_VERSION));
+		add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
 		return -EINVAL;
 	}
 	pr_info("ANDD device: %x name: %s\n", andd->device_number,
@@ -466,14 +478,14 @@
 			return 0;
 		}
 	}
-	WARN_TAINT(
-		1, TAINT_FIRMWARE_WORKAROUND,
+	pr_warn(FW_BUG
 		"Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
 		"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-		drhd->reg_base_addr,
+		rhsa->base_address,
 		dmi_get_system_info(DMI_BIOS_VENDOR),
 		dmi_get_system_info(DMI_BIOS_VERSION),
 		dmi_get_system_info(DMI_PRODUCT_VERSION));
+	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
 
 	return 0;
 }
@@ -819,14 +831,14 @@
 
 static void warn_invalid_dmar(u64 addr, const char *message)
 {
-	WARN_TAINT_ONCE(
-		1, TAINT_FIRMWARE_WORKAROUND,
+	pr_warn_once(FW_BUG
 		"Your BIOS is broken; DMAR reported at address %llx%s!\n"
 		"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
 		addr, message,
 		dmi_get_system_info(DMI_BIOS_VENDOR),
 		dmi_get_system_info(DMI_BIOS_VERSION),
 		dmi_get_system_info(DMI_PRODUCT_VERSION));
+	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
 }
 
 static int __ref
@@ -1000,8 +1012,8 @@
 {
 	struct intel_iommu *iommu;
 	u32 ver, sts;
-	int agaw = 0;
-	int msagaw = 0;
+	int agaw = -1;
+	int msagaw = -1;
 	int err;
 
 	if (!drhd->reg_base_addr) {
@@ -1026,17 +1038,28 @@
 	}
 
 	err = -EINVAL;
-	agaw = iommu_calculate_agaw(iommu);
-	if (agaw < 0) {
-		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) {
-		pr_err("Cannot get a valid max agaw for iommu (seq_id = %d)\n",
-			iommu->seq_id);
-		goto err_unmap;
+	if (cap_sagaw(iommu->cap) == 0) {
+		pr_info("%s: No supported address widths. Not attempting DMA translation.\n",
+			iommu->name);
+		drhd->ignored = 1;
+	}
+
+	if (!drhd->ignored) {
+		agaw = iommu_calculate_agaw(iommu);
+		if (agaw < 0) {
+			pr_err("Cannot get a valid agaw for iommu (seq_id = %d)\n",
+			       iommu->seq_id);
+			drhd->ignored = 1;
+		}
+	}
+	if (!drhd->ignored) {
+		msagaw = iommu_calculate_max_sagaw(iommu);
+		if (msagaw < 0) {
+			pr_err("Cannot get a valid max agaw for iommu (seq_id = %d)\n",
+			       iommu->seq_id);
+			drhd->ignored = 1;
+			agaw = -1;
+		}
 	}
 	iommu->agaw = agaw;
 	iommu->msagaw = msagaw;
@@ -1064,16 +1087,15 @@
 	raw_spin_lock_init(&iommu->register_lock);
 
 	drhd->iommu = iommu;
+	iommu->drhd = drhd;
 
-	if (intel_iommu_enabled)
+	if (intel_iommu_enabled && !drhd->ignored)
 		iommu->iommu_dev = iommu_device_create(NULL, iommu,
 						       intel_iommu_groups,
 						       "%s", iommu->name);
 
 	return 0;
 
-err_unmap:
-	unmap_iommu(iommu);
 error_free_seq_id:
 	dmar_free_seq_id(iommu);
 error:
@@ -1083,7 +1105,8 @@
 
 static void free_iommu(struct intel_iommu *iommu)
 {
-	iommu_device_destroy(iommu->iommu_dev);
+	if (intel_iommu_enabled && !iommu->drhd->ignored)
+		iommu_device_destroy(iommu->iommu_dev);
 
 	if (iommu->irq) {
 		if (iommu->pr_irq) {
@@ -1312,8 +1335,8 @@
 	qi_submit_sync(&desc, iommu);
 }
 
-void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep,
-			u64 addr, unsigned mask)
+void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid,
+			u16 qdep, u64 addr, unsigned mask)
 {
 	struct qi_desc desc;
 
@@ -1328,7 +1351,7 @@
 		qdep = 0;
 
 	desc.low = QI_DEV_IOTLB_SID(sid) | QI_DEV_IOTLB_QDEP(qdep) |
-		   QI_DIOTLB_TYPE;
+		   QI_DIOTLB_TYPE | QI_DEV_IOTLB_PFSID(pfsid);
 
 	qi_submit_sync(&desc, iommu);
 }
@@ -1347,7 +1370,7 @@
 
 	raw_spin_lock_irqsave(&iommu->register_lock, flags);
 
-	sts =  dmar_readq(iommu->reg + DMAR_GSTS_REG);
+	sts =  readl(iommu->reg + DMAR_GSTS_REG);
 	if (!(sts & DMA_GSTS_QIES))
 		goto end;
 
@@ -1857,10 +1880,11 @@
 	/*
 	 * All PCI devices managed by this unit should have been destroyed.
 	 */
-	if (!dmaru->include_all && dmaru->devices && dmaru->devices_cnt)
+	if (!dmaru->include_all && dmaru->devices && dmaru->devices_cnt) {
 		for_each_active_dev_scope(dmaru->devices,
 					  dmaru->devices_cnt, i, dev)
 			return -EBUSY;
+	}
 
 	ret = dmar_ir_hotplug(dmaru, false);
 	if (ret == 0)
--- linux-4.4.0.orig/drivers/iommu/exynos-iommu.c
+++ linux-4.4.0/drivers/iommu/exynos-iommu.c
@@ -647,6 +647,7 @@
 		.name		= "exynos-sysmmu",
 		.of_match_table	= sysmmu_of_match,
 		.pm		= &sysmmu_pm_ops,
+		.suppress_bind_attrs = true,
 	}
 };
 
@@ -1157,13 +1158,17 @@
 		return -ENODEV;
 
 	data = platform_get_drvdata(sysmmu);
-	if (!data)
+	if (!data) {
+		put_device(&sysmmu->dev);
 		return -ENODEV;
+	}
 
 	if (!owner) {
 		owner = kzalloc(sizeof(*owner), GFP_KERNEL);
-		if (!owner)
+		if (!owner) {
+			put_device(&sysmmu->dev);
 			return -ENOMEM;
+		}
 
 		INIT_LIST_HEAD(&owner->controllers);
 		dev->archdata.iommu = owner;
--- linux-4.4.0.orig/drivers/iommu/intel-iommu.c
+++ linux-4.4.0/drivers/iommu/intel-iommu.c
@@ -419,6 +419,7 @@
 	struct list_head global; /* link to global list */
 	u8 bus;			/* PCI bus number */
 	u8 devfn;		/* PCI devfn number */
+	u16 pfsid;		/* SRIOV physical function source ID */
 	u8 pasid_supported:3;
 	u8 pasid_enabled:1;
 	u8 pri_supported:1;
@@ -885,7 +886,13 @@
 		return NULL;
 
 	if (dev_is_pci(dev)) {
+		struct pci_dev *pf_pdev;
+
 		pdev = to_pci_dev(dev);
+		/* VFs aren't listed in scope tables; we need to look up
+		 * the PF instead to find the IOMMU. */
+		pf_pdev = pci_physfn(pdev);
+		dev = &pf_pdev->dev;
 		segment = pci_domain_nr(pdev->bus);
 	} else if (has_acpi_companion(dev))
 		dev = &ACPI_COMPANION(dev)->dev;
@@ -898,6 +905,13 @@
 		for_each_active_dev_scope(drhd->devices,
 					  drhd->devices_cnt, i, tmp) {
 			if (tmp == dev) {
+				/* For a VF use its original BDF# not that of the PF
+				 * which we used for the IOMMU lookup. Strictly speaking
+				 * we could do this for all PCI devices; we only need to
+				 * get the BDF# from the scope table for ACPI matches. */
+				if (pdev && pdev->is_virtfn)
+					goto got_pdev;
+
 				*bus = drhd->devices[i].bus;
 				*devfn = drhd->devices[i].devfn;
 				goto out;
@@ -1124,7 +1138,7 @@
 		if (!dma_pte_present(pte) || dma_pte_superpage(pte))
 			goto next;
 
-		level_pfn = pfn & level_mask(level - 1);
+		level_pfn = pfn & level_mask(level);
 		level_pte = phys_to_virt(dma_pte_addr(pte));
 
 		if (level > 2)
@@ -1466,6 +1480,20 @@
 		return;
 
 	pdev = to_pci_dev(info->dev);
+	/* For IOMMU that supports device IOTLB throttling (DIT), we assign
+	 * PFSID to the invalidation desc of a VF such that IOMMU HW can gauge
+	 * queue depth at PF level. If DIT is not set, PFSID will be treated as
+	 * reserved, which should be set to 0.
+	 */
+	if (!ecap_dit(info->iommu->ecap))
+		info->pfsid = 0;
+	else {
+		struct pci_dev *pf_pdev;
+
+		/* pdev will be returned if device is not a vf */
+		pf_pdev = pci_physfn(pdev);
+		info->pfsid = PCI_DEVID(pf_pdev->bus->number, pf_pdev->devfn);
+	}
 
 #ifdef CONFIG_INTEL_IOMMU_SVM
 	/* The PCIe spec, in its wisdom, declares that the behaviour of
@@ -1489,7 +1517,7 @@
 {
 	struct pci_dev *pdev;
 
-	if (dev_is_pci(info->dev))
+	if (!dev_is_pci(info->dev))
 		return;
 
 	pdev = to_pci_dev(info->dev);
@@ -1524,7 +1552,8 @@
 
 		sid = info->bus << 8 | info->devfn;
 		qdep = info->ats_qdep;
-		qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
+		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
+				qdep, addr, mask);
 	}
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 }
@@ -1569,6 +1598,9 @@
 	u32 pmen;
 	unsigned long flags;
 
+	if (!cap_plmr(iommu->cap) && !cap_phmr(iommu->cap))
+		return;
+
 	raw_spin_lock_irqsave(&iommu->register_lock, flags);
 	pmen = readl(iommu->reg + DMAR_PMEN_REG);
 	pmen &= ~DMA_PMEN_EPM;
@@ -1672,6 +1704,7 @@
 	if (!iommu->domains || !iommu->domain_ids)
 		return;
 
+again:
 	spin_lock_irqsave(&device_domain_lock, flags);
 	list_for_each_entry_safe(info, tmp, &device_domain_list, global) {
 		struct dmar_domain *domain;
@@ -1684,10 +1717,19 @@
 
 		domain = info->domain;
 
-		dmar_remove_one_dev_info(domain, info->dev);
+		__dmar_remove_one_dev_info(info);
 
-		if (!domain_type_is_vm_or_si(domain))
+		if (!domain_type_is_vm_or_si(domain)) {
+			/*
+			 * The domain_exit() function  can't be called under
+			 * device_domain_lock, as it takes this lock itself.
+			 * So release the lock here and re-run the loop
+			 * afterwards.
+			 */
+			spin_unlock_irqrestore(&device_domain_lock, flags);
 			domain_exit(domain);
+			goto again;
+		}
 	}
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 
@@ -1970,6 +2012,28 @@
 	if (context_present(context))
 		goto out_unlock;
 
+	/*
+	 * For kdump cases, old valid entries may be cached due to the
+	 * in-flight DMA and copied pgtable, but there is no unmapping
+	 * behaviour for them, thus we need an explicit cache flush for
+	 * the newly-mapped device. For kdump, at this point, the device
+	 * is supposed to finish reset at its driver probe stage, so no
+	 * in-flight DMA will exist, and we don't need to worry anymore
+	 * hereafter.
+	 */
+	if (context_copied(context)) {
+		u16 did_old = context_domain_id(context);
+
+		if (did_old >= 0 && did_old < cap_ndoms(iommu->cap)) {
+			iommu->flush.flush_context(iommu, did_old,
+						   (((u16)bus) << 8) | devfn,
+						   DMA_CCMD_MASK_NOBIT,
+						   DMA_CCMD_DEVICE_INVL);
+			iommu->flush.flush_iotlb(iommu, did_old, 0, 0,
+						 DMA_TLB_DSI_FLUSH);
+		}
+	}
+
 	pgd = domain->pgd;
 
 	context_clear_entry(context);
@@ -1980,7 +2044,7 @@
 	 * than default.  Unnecessary for PT mode.
 	 */
 	if (translation != CONTEXT_TT_PASS_THROUGH) {
-		for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
+		for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) {
 			ret = -ENOMEM;
 			pgd = phys_to_virt(dma_pte_addr(pgd));
 			if (!dma_pte_present(pgd))
@@ -1994,7 +2058,7 @@
 			translation = CONTEXT_TT_MULTI_LEVEL;
 
 		context_set_address_root(context, virt_to_phys(pgd));
-		context_set_address_width(context, iommu->agaw);
+		context_set_address_width(context, agaw);
 	} else {
 		/*
 		 * In pass through mode, AW must be programmed to
@@ -2032,7 +2096,7 @@
 	spin_unlock(&iommu->lock);
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 
-	return 0;
+	return ret;
 }
 
 struct domain_context_mapping_data {
@@ -2156,10 +2220,12 @@
 		uint64_t tmp;
 
 		if (!sg_res) {
+			unsigned int pgoff = sg->offset & ~PAGE_MASK;
+
 			sg_res = aligned_nrpages(sg->offset, sg->length);
-			sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
+			sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + pgoff;
 			sg->dma_length = sg->length;
-			pteval = page_to_phys(sg_page(sg)) | prot;
+			pteval = (sg_phys(sg) - pgoff) | prot;
 			phys_pfn = pteval >> VTD_PAGE_SHIFT;
 		}
 
@@ -2914,7 +2980,7 @@
 			}
 
 			if (old_ce)
-				iounmap(old_ce);
+				memunmap(old_ce);
 
 			ret = 0;
 			if (devfn < 0x80)
@@ -3169,11 +3235,6 @@
 			}
 		}
 
-		iommu_flush_write_buffer(iommu);
-		iommu_set_root_entry(iommu);
-		iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
-		iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
-
 		if (!ecap_pass_through(iommu->ecap))
 			hw_pass_through = 0;
 #ifdef CONFIG_INTEL_IOMMU_SVM
@@ -3182,20 +3243,36 @@
 #endif
 	}
 
+	/*
+	 * Now that qi is enabled on all iommus, set the root entry and flush
+	 * caches. This is required on some Intel X58 chipsets, otherwise the
+	 * flush_context function will loop forever and the boot hangs.
+	 */
+	for_each_active_iommu(iommu, drhd) {
+		iommu_flush_write_buffer(iommu);
+		iommu_set_root_entry(iommu);
+		iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
+		iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
+	}
+
 	if (iommu_pass_through)
 		iommu_identity_mapping |= IDENTMAP_ALL;
 
 #ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
-	iommu_identity_mapping |= IDENTMAP_GFX;
+	dmar_map_gfx = 0;
 #endif
 
+	if (!dmar_map_gfx)
+		iommu_identity_mapping |= IDENTMAP_GFX;
+
+	check_tylersburg_isoch();
+
 	if (iommu_identity_mapping) {
 		ret = si_domain_init(hw_pass_through);
 		if (ret)
 			goto free_iommu;
 	}
 
-	check_tylersburg_isoch();
 
 	/*
 	 * If we copied translations from a previous kernel in the kdump
@@ -3704,7 +3781,7 @@
 
 	for_each_sg(sglist, sg, nelems, i) {
 		BUG_ON(!sg_page(sg));
-		sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
+		sg->dma_address = sg_phys(sg);
 		sg->dma_length = sg->length;
 	}
 	return nelems;
@@ -3872,10 +3949,11 @@
 
 	/* we know that the this iommu should be at offset 0xa000 from vtbar */
 	drhd = dmar_find_matched_drhd_unit(pdev);
-	if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
-			    TAINT_FIRMWARE_WORKAROUND,
-			    "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
+	if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
+		pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
+		add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
 		pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
+	}
 }
 DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
 
@@ -3909,9 +3987,7 @@
 
 		/* This IOMMU has *only* gfx devices. Either bypass it or
 		   set the gfx_mapped flag, as appropriate */
-		if (dmar_map_gfx) {
-			intel_iommu_gfx_mapped = 1;
-		} else {
+		if (!dmar_map_gfx) {
 			drhd->ignored = 1;
 			for_each_active_dev_scope(drhd->devices,
 						  drhd->devices_cnt, i, dev)
@@ -4175,10 +4251,11 @@
 	if (!atsru)
 		return 0;
 
-	if (!atsru->include_all && atsru->devices && atsru->devices_cnt)
+	if (!atsru->include_all && atsru->devices && atsru->devices_cnt) {
 		for_each_active_dev_scope(atsru->devices, atsru->devices_cnt,
 					  i, dev)
 			return -EBUSY;
+	}
 
 	return 0;
 }
@@ -4367,7 +4444,7 @@
 				rmrru->devices_cnt);
 			if(ret < 0)
 				return ret;
-		} else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
+		} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
 			dmar_remove_dev_scope(info, rmrr->segment,
 				rmrru->devices, rmrru->devices_cnt);
 		}
@@ -4387,7 +4464,7 @@
 				break;
 			else if(ret < 0)
 				return ret;
-		} else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
+		} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
 			if (dmar_remove_dev_scope(info, atsr->segment,
 					atsru->devices, atsru->devices_cnt))
 				break;
@@ -4576,6 +4653,15 @@
 	NULL,
 };
 
+static void intel_disable_iommus(void)
+{
+	struct intel_iommu *iommu = NULL;
+	struct dmar_drhd_unit *drhd;
+
+	for_each_iommu(iommu, drhd)
+		iommu_disable_translation(iommu);
+}
+
 int __init intel_iommu_init(void)
 {
 	int ret = -ENODEV;
@@ -4604,8 +4690,15 @@
 		goto out_free_dmar;
 	}
 
-	if (no_iommu || dmar_disabled)
+	if (no_iommu || dmar_disabled) {
+		/*
+		 * Make sure the IOMMUs are switched off, even when we
+		 * boot into a kexec kernel and the previous kernel left
+		 * them enabled
+		 */
+		intel_disable_iommus();
 		goto out_free_dmar;
+	}
 
 	if (list_empty(&dmar_rmrr_units))
 		pr_info("No RMRR found\n");
@@ -4619,6 +4712,9 @@
 		goto out_free_reserved_range;
 	}
 
+	if (dmar_map_gfx)
+		intel_iommu_gfx_mapped = 1;
+
 	init_no_remapping_devices();
 
 	ret = init_dmars();
@@ -4937,8 +5033,10 @@
 	u64 phys = 0;
 
 	pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
-	if (pte)
-		phys = dma_pte_addr(pte);
+	if (pte && dma_pte_present(pte))
+		phys = dma_pte_addr(pte) +
+			(iova & (BIT_MASK(level_to_offset_bits(level) +
+						VTD_PAGE_SHIFT) - 1));
 
 	return phys;
 }
@@ -4989,6 +5087,25 @@
 }
 
 #ifdef CONFIG_INTEL_IOMMU_SVM
+#define MAX_NR_PASID_BITS (20)
+static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu)
+{
+	/*
+	 * Convert ecap_pss to extend context entry pts encoding, also
+	 * respect the soft pasid_max value set by the iommu.
+	 * - number of PASID bits = ecap_pss + 1
+	 * - number of PASID table entries = 2^(pts + 5)
+	 * Therefore, pts = ecap_pss - 4
+	 * e.g. KBL ecap_pss = 0x13, PASID has 20 bits, pts = 15
+	 */
+	if (ecap_pss(iommu->ecap) < 5)
+		return 0;
+
+	/* pasid_max is encoded as actual number of entries not the bits */
+	return find_first_bit((unsigned long *)&iommu->pasid_max,
+			MAX_NR_PASID_BITS) - 5;
+}
+
 int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev)
 {
 	struct device_domain_info *info;
@@ -5021,7 +5138,9 @@
 
 	if (!(ctx_lo & CONTEXT_PASIDE)) {
 		context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table);
-		context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | ecap_pss(iommu->ecap);
+		context[1].lo = (u64)virt_to_phys(iommu->pasid_table) |
+			intel_iommu_get_pts(iommu);
+
 		wmb();
 		/* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both
 		 * extended to permit requests-with-PASID if the PASIDE bit
--- linux-4.4.0.orig/drivers/iommu/intel-svm.c
+++ linux-4.4.0/drivers/iommu/intel-svm.c
@@ -39,10 +39,18 @@
 	struct page *pages;
 	int order;
 
-	order = ecap_pss(iommu->ecap) + 7 - PAGE_SHIFT;
-	if (order < 0)
-		order = 0;
+	/* Start at 2 because it's defined as 2^(1+PSS) */
+	iommu->pasid_max = 2 << ecap_pss(iommu->ecap);
 
+	/* Eventually I'm promised we will get a multi-level PASID table
+	 * and it won't have to be physically contiguous. Until then,
+	 * limit the size because 8MiB contiguous allocations can be hard
+	 * to come by. The limit of 0x20000, which is 1MiB for each of
+	 * the PASID and PASID-state tables, is somewhat arbitrary. */
+	if (iommu->pasid_max > 0x20000)
+		iommu->pasid_max = 0x20000;
+
+	order = get_order(sizeof(struct pasid_entry) * iommu->pasid_max);
 	pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
 	if (!pages) {
 		pr_warn("IOMMU: %s: Failed to allocate PASID table\n",
@@ -53,6 +61,8 @@
 	pr_info("%s: Allocated order %d PASID table.\n", iommu->name, order);
 
 	if (ecap_dis(iommu->ecap)) {
+		/* Just making it explicit... */
+		BUILD_BUG_ON(sizeof(struct pasid_entry) != sizeof(struct pasid_state_entry));
 		pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
 		if (pages)
 			iommu->pasid_state_table = page_address(pages);
@@ -68,11 +78,7 @@
 
 int intel_svm_free_pasid_tables(struct intel_iommu *iommu)
 {
-	int order;
-
-	order = ecap_pss(iommu->ecap) + 7 - PAGE_SHIFT;
-	if (order < 0)
-		order = 0;
+	int order = get_order(sizeof(struct pasid_entry) * iommu->pasid_max);
 
 	if (iommu->pasid_table) {
 		free_pages((unsigned long)iommu->pasid_table, order);
@@ -121,6 +127,7 @@
 		pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n",
 		       iommu->name);
 		dmar_free_hwirq(irq);
+		iommu->pr_irq = 0;
 		goto err;
 	}
 	dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL);
@@ -136,9 +143,11 @@
 	dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL);
 	dmar_writeq(iommu->reg + DMAR_PQA_REG, 0ULL);
 
-	free_irq(iommu->pr_irq, iommu);
-	dmar_free_hwirq(iommu->pr_irq);
-	iommu->pr_irq = 0;
+	if (iommu->pr_irq) {
+		free_irq(iommu->pr_irq, iommu);
+		dmar_free_hwirq(iommu->pr_irq);
+		iommu->pr_irq = 0;
+	}
 
 	free_pages((unsigned long)iommu->prq, PRQ_ORDER);
 	iommu->prq = NULL;
@@ -249,12 +258,30 @@
 static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 {
 	struct intel_svm *svm = container_of(mn, struct intel_svm, notifier);
+	struct intel_svm_dev *sdev;
 
+	/* This might end up being called from exit_mmap(), *before* the page
+	 * tables are cleared. And __mmu_notifier_release() will delete us from
+	 * the list of notifiers so that our invalidate_range() callback doesn't
+	 * get called when the page tables are cleared. So we need to protect
+	 * against hardware accessing those page tables.
+	 *
+	 * We do it by clearing the entry in the PASID table and then flushing
+	 * the IOTLB and the PASID table caches. This might upset hardware;
+	 * perhaps we'll want to point the PASID to a dummy PGD (like the zero
+	 * page) so that we end up taking a fault that the hardware really
+	 * *has* to handle gracefully without affecting other processes.
+	 */
 	svm->iommu->pasid_table[svm->pasid].val = 0;
+	wmb();
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdev, &svm->devs, list) {
+		intel_flush_pasid_dev(svm, sdev, svm->pasid);
+		intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm);
+	}
+	rcu_read_unlock();
 
-	/* There's no need to do any flush because we can't get here if there
-	 * are any devices left anyway. */
-	WARN_ON(!list_empty(&svm->devs));
 }
 
 static const struct mmu_notifier_ops intel_mmuops = {
@@ -353,8 +380,8 @@
 		}
 		svm->iommu = iommu;
 
-		if (pasid_max > 2 << ecap_pss(iommu->ecap))
-			pasid_max = 2 << ecap_pss(iommu->ecap);
+		if (pasid_max > iommu->pasid_max)
+			pasid_max = iommu->pasid_max;
 
 		/* Do not use PASID 0 in caching mode (virtualised IOMMU) */
 		ret = idr_alloc(&iommu->pasid_idr, svm,
@@ -362,6 +389,7 @@
 				pasid_max - 1, GFP_KERNEL);
 		if (ret < 0) {
 			kfree(svm);
+			kfree(sdev);
 			goto out;
 		}
 		svm->pasid = ret;
@@ -379,7 +407,6 @@
 				goto out;
 			}
 			iommu->pasid_table[svm->pasid].val = (u64)__pa(mm->pgd) | 1;
-			mm = NULL;
 		} else
 			iommu->pasid_table[svm->pasid].val = (u64)__pa(init_mm.pgd) | 1 | (1ULL << 11);
 		wmb();
@@ -442,11 +469,11 @@
 				kfree_rcu(sdev, rcu);
 
 				if (list_empty(&svm->devs)) {
-					mmu_notifier_unregister(&svm->notifier, svm->mm);
 
 					idr_remove(&svm->iommu->pasid_idr, svm->pasid);
 					if (svm->mm)
-						mmput(svm->mm);
+						mmu_notifier_unregister(&svm->notifier, svm->mm);
+
 					/* We mandate that no page faults may be outstanding
 					 * for the PASID when intel_svm_unbind_mm() is called.
 					 * If that is not obeyed, subtle errors will happen.
@@ -507,6 +534,10 @@
 	struct intel_svm *svm = NULL;
 	int head, tail, handled = 0;
 
+	/* Clear PPR bit before reading head/tail registers, to
+	 * ensure that we get a new interrupt if needed. */
+	writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG);
+
 	tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
 	head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
 	while (head != tail) {
@@ -527,7 +558,7 @@
 			pr_err("%s: Page request without PASID: %08llx %08llx\n",
 			       iommu->name, ((unsigned long long *)req)[0],
 			       ((unsigned long long *)req)[1]);
-			goto bad_req;
+			goto no_pasid;
 		}
 
 		if (!svm || svm->pasid != req->pasid) {
@@ -551,6 +582,9 @@
 		 * any faults on kernel addresses. */
 		if (!svm->mm)
 			goto bad_req;
+		/* If the mm is already defunct, don't handle faults. */
+		if (!atomic_inc_not_zero(&svm->mm->mm_users))
+			goto bad_req;
 		down_read(&svm->mm->mmap_sem);
 		vma = find_extend_vma(svm->mm, address);
 		if (!vma || address < vma->vm_start)
@@ -567,6 +601,7 @@
 		result = QI_RESP_SUCCESS;
 	invalid:
 		up_read(&svm->mm->mmap_sem);
+		mmput(svm->mm);
 	bad_req:
 		/* Accounting for major/minor faults? */
 		rcu_read_lock();
--- linux-4.4.0.orig/drivers/iommu/intel_irq_remapping.c
+++ linux-4.4.0/drivers/iommu/intel_irq_remapping.c
@@ -486,12 +486,18 @@
 
 	/* Enable interrupt-remapping */
 	iommu->gcmd |= DMA_GCMD_IRE;
-	iommu->gcmd &= ~DMA_GCMD_CFI;  /* Block compatibility-format MSIs */
 	writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
-
 	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
 		      readl, (sts & DMA_GSTS_IRES), sts);
 
+	/* Block compatibility-format MSIs */
+	if (sts & DMA_GSTS_CFIS) {
+		iommu->gcmd &= ~DMA_GCMD_CFI;
+		writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
+		IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+			      readl, !(sts & DMA_GSTS_CFIS), sts);
+	}
+
 	/*
 	 * With CFI clear in the Global Command register, we should be
 	 * protected from dangerous (i.e. compatibility) interrupts
@@ -629,7 +635,7 @@
 
 	raw_spin_lock_irqsave(&iommu->register_lock, flags);
 
-	sts = dmar_readq(iommu->reg + DMAR_GSTS_REG);
+	sts = readl(iommu->reg + DMAR_GSTS_REG);
 	if (!(sts & DMA_GSTS_IRES))
 		goto end;
 
@@ -753,7 +759,7 @@
 		 * should have X86_FEATURE_CX16 support, this has been confirmed
 		 * with Intel hardware guys.
 		 */
-		if ( cpu_has_cx16 )
+		if (boot_cpu_has(X86_FEATURE_CX16))
 			intel_irq_remap_ops.capability |= 1 << IRQ_POSTING_CAP;
 
 		for_each_iommu(iommu, drhd)
@@ -1344,6 +1350,8 @@
 		irq_data = irq_domain_get_irq_data(domain, virq + i);
 		irq_cfg = irqd_cfg(irq_data);
 		if (!irq_data || !irq_cfg) {
+			if (!i)
+				kfree(data);
 			ret = -EINVAL;
 			goto out_free_data;
 		}
--- linux-4.4.0.orig/drivers/iommu/io-pgtable-arm.c
+++ linux-4.4.0/drivers/iommu/io-pgtable-arm.c
@@ -335,8 +335,12 @@
 		if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
 			pte |= ARM_LPAE_PTE_NSTABLE;
 		__arm_lpae_set_pte(ptep, pte, cfg);
-	} else {
+	} else if (!iopte_leaf(pte, lvl)) {
 		cptep = iopte_deref(pte, data);
+	} else {
+		/* We require an unmap first */
+		WARN_ON(!selftest_running);
+		return -EEXIST;
 	}
 
 	/* Rinse, repeat */
@@ -405,17 +409,18 @@
 	arm_lpae_iopte *start, *end;
 	unsigned long table_size;
 
-	/* Only leaf entries at the last level */
-	if (lvl == ARM_LPAE_MAX_LEVELS - 1)
-		return;
-
 	if (lvl == ARM_LPAE_START_LVL(data))
 		table_size = data->pgd_size;
 	else
 		table_size = 1UL << data->pg_shift;
 
 	start = ptep;
-	end = (void *)ptep + table_size;
+
+	/* Only leaf entries at the last level */
+	if (lvl == ARM_LPAE_MAX_LEVELS - 1)
+		end = ptep;
+	else
+		end = (void *)ptep + table_size;
 
 	while (ptep != end) {
 		arm_lpae_iopte pte = *ptep++;
--- linux-4.4.0.orig/drivers/iommu/iommu.c
+++ linux-4.4.0/drivers/iommu/iommu.c
@@ -206,7 +206,7 @@
 		mutex_lock(&iommu_group_mutex);
 		ida_remove(&iommu_group_ida, group->id);
 		mutex_unlock(&iommu_group_mutex);
-		kfree(group);
+		kobject_put(&group->kobj);
 		return ERR_PTR(ret);
 	}
 
@@ -391,36 +391,30 @@
 	device->dev = dev;
 
 	ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group");
-	if (ret) {
-		kfree(device);
-		return ret;
-	}
+	if (ret)
+		goto err_free_device;
 
 	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 = -ENOMEM;
+		goto err_remove_link;
 	}
 
 	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.
 			 */
+			kfree(device->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;
+		goto err_free_name;
 	}
 
 	kobject_get(group->devices_kobj);
@@ -432,8 +426,10 @@
 	mutex_lock(&group->mutex);
 	list_add_tail(&device->list, &group->devices);
 	if (group->domain)
-		__iommu_attach_device(group->domain, dev);
+		ret = __iommu_attach_device(group->domain, dev);
 	mutex_unlock(&group->mutex);
+	if (ret)
+		goto err_put_group;
 
 	/* Notify any listeners about change to group. */
 	blocking_notifier_call_chain(&group->notifier,
@@ -444,6 +440,22 @@
 	pr_info("Adding device %s to group %d\n", dev_name(dev), group->id);
 
 	return 0;
+
+err_put_group:
+	mutex_lock(&group->mutex);
+	list_del(&device->list);
+	mutex_unlock(&group->mutex);
+	dev->iommu_group = NULL;
+	kobject_put(group->devices_kobj);
+	sysfs_remove_link(group->devices_kobj, device->name);
+err_free_name:
+	kfree(device->name);
+err_remove_link:
+	sysfs_remove_link(&dev->kobj, "iommu_group");
+err_free_device:
+	kfree(device);
+	pr_err("Failed to add device %s to group %d: %d\n", dev_name(dev), group->id, ret);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(iommu_group_add_device);
 
@@ -848,7 +860,8 @@
 	if (!group->default_domain) {
 		group->default_domain = __iommu_domain_alloc(dev->bus,
 							     IOMMU_DOMAIN_DMA);
-		group->domain = group->default_domain;
+		if (!group->domain)
+			group->domain = group->default_domain;
 	}
 
 	ret = iommu_group_add_device(group, dev);
@@ -1581,9 +1594,9 @@
 	int ret;
 
 	/* Device must already be in a group before calling this function */
-	group = iommu_group_get_for_dev(dev);
-	if (IS_ERR(group))
-		return PTR_ERR(group);
+	group = iommu_group_get(dev);
+	if (!group)
+		return -EINVAL;
 
 	mutex_lock(&group->mutex);
 
--- linux-4.4.0.orig/drivers/iommu/iova.c
+++ linux-4.4.0/drivers/iommu/iova.c
@@ -126,7 +126,7 @@
 				break;	/* found a free slot */
 		}
 adjust_limit_pfn:
-		limit_pfn = curr_iova->pfn_lo - 1;
+		limit_pfn = curr_iova->pfn_lo ? (curr_iova->pfn_lo - 1) : 0;
 move_left:
 		prev = curr;
 		curr = rb_prev(curr);
--- linux-4.4.0.orig/drivers/iommu/ipmmu-vmsa.c
+++ linux-4.4.0/drivers/iommu/ipmmu-vmsa.c
@@ -44,7 +44,7 @@
 	struct io_pgtable_ops *iop;
 
 	unsigned int context_id;
-	spinlock_t lock;			/* Protects mappings */
+	struct mutex mutex;			/* Protects mappings */
 };
 
 struct ipmmu_vmsa_archdata {
@@ -372,6 +372,9 @@
 
 static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain)
 {
+	if (!domain->mmu)
+		return;
+
 	/*
 	 * Disable the context. Flush the TLB as required when modifying the
 	 * context registers.
@@ -464,7 +467,7 @@
 	if (!domain)
 		return NULL;
 
-	spin_lock_init(&domain->lock);
+	mutex_init(&domain->mutex);
 
 	return &domain->io_domain;
 }
@@ -488,7 +491,6 @@
 	struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
 	struct ipmmu_vmsa_device *mmu = archdata->mmu;
 	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
-	unsigned long flags;
 	unsigned int i;
 	int ret = 0;
 
@@ -497,7 +499,7 @@
 		return -ENXIO;
 	}
 
-	spin_lock_irqsave(&domain->lock, flags);
+	mutex_lock(&domain->mutex);
 
 	if (!domain->mmu) {
 		/* The domain hasn't been used yet, initialize it. */
@@ -513,7 +515,7 @@
 		ret = -EINVAL;
 	}
 
-	spin_unlock_irqrestore(&domain->lock, flags);
+	mutex_unlock(&domain->mutex);
 
 	if (ret < 0)
 		return ret;
--- linux-4.4.0.orig/drivers/iommu/omap-iommu-debug.c
+++ linux-4.4.0/drivers/iommu/omap-iommu-debug.c
@@ -101,8 +101,11 @@
 	mutex_lock(&iommu_debug_lock);
 
 	bytes = omap_iommu_dump_ctx(obj, p, count);
+	if (bytes < 0)
+		goto err;
 	bytes = simple_read_from_buffer(userbuf, count, ppos, buf, bytes);
 
+err:
 	mutex_unlock(&iommu_debug_lock);
 	kfree(buf);
 
--- linux-4.4.0.orig/drivers/iommu/omap-iommu.c
+++ linux-4.4.0/drivers/iommu/omap-iommu.c
@@ -1295,6 +1295,7 @@
 	const unsigned long flags = SLAB_HWCACHE_ALIGN;
 	size_t align = 1 << 10; /* L2 pagetable alignement */
 	struct device_node *np;
+	int ret;
 
 	np = of_find_matching_node(NULL, omap_iommu_of_match);
 	if (!np)
@@ -1308,11 +1309,25 @@
 		return -ENOMEM;
 	iopte_cachep = p;
 
-	bus_set_iommu(&platform_bus_type, &omap_iommu_ops);
-
 	omap_iommu_debugfs_init();
 
-	return platform_driver_register(&omap_iommu_driver);
+	ret = platform_driver_register(&omap_iommu_driver);
+	if (ret) {
+		pr_err("%s: failed to register driver\n", __func__);
+		goto fail_driver;
+	}
+
+	ret = bus_set_iommu(&platform_bus_type, &omap_iommu_ops);
+	if (ret)
+		goto fail_bus;
+
+	return 0;
+
+fail_bus:
+	platform_driver_unregister(&omap_iommu_driver);
+fail_driver:
+	kmem_cache_destroy(iopte_cachep);
+	return ret;
 }
 subsys_initcall(omap_iommu_init);
 /* must be ready before omap3isp is probed */
--- linux-4.4.0.orig/drivers/iommu/tegra-smmu.c
+++ linux-4.4.0/drivers/iommu/tegra-smmu.c
@@ -91,7 +91,6 @@
 #define  SMMU_TLB_FLUSH_VA_MATCH_ALL     (0 << 0)
 #define  SMMU_TLB_FLUSH_VA_MATCH_SECTION (2 << 0)
 #define  SMMU_TLB_FLUSH_VA_MATCH_GROUP   (3 << 0)
-#define  SMMU_TLB_FLUSH_ASID(x)          (((x) & 0x7f) << 24)
 #define  SMMU_TLB_FLUSH_VA_SECTION(addr) ((((addr) & 0xffc00000) >> 12) | \
 					  SMMU_TLB_FLUSH_VA_MATCH_SECTION)
 #define  SMMU_TLB_FLUSH_VA_GROUP(addr)   ((((addr) & 0xffffc000) >> 12) | \
@@ -154,9 +153,9 @@
 	return (addr & smmu->pfn_mask) == addr;
 }
 
-static dma_addr_t smmu_pde_to_dma(u32 pde)
+static dma_addr_t smmu_pde_to_dma(struct tegra_smmu *smmu, u32 pde)
 {
-	return pde << 12;
+	return (dma_addr_t)(pde & smmu->pfn_mask) << 12;
 }
 
 static void smmu_flush_ptc_all(struct tegra_smmu *smmu)
@@ -194,8 +193,12 @@
 {
 	u32 value;
 
-	value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
-		SMMU_TLB_FLUSH_VA_MATCH_ALL;
+	if (smmu->soc->num_asids == 4)
+		value = (asid & 0x3) << 29;
+	else
+		value = (asid & 0x7f) << 24;
+
+	value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_MATCH_ALL;
 	smmu_writel(smmu, value, SMMU_TLB_FLUSH);
 }
 
@@ -205,8 +208,12 @@
 {
 	u32 value;
 
-	value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
-		SMMU_TLB_FLUSH_VA_SECTION(iova);
+	if (smmu->soc->num_asids == 4)
+		value = (asid & 0x3) << 29;
+	else
+		value = (asid & 0x7f) << 24;
+
+	value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_SECTION(iova);
 	smmu_writel(smmu, value, SMMU_TLB_FLUSH);
 }
 
@@ -216,8 +223,12 @@
 {
 	u32 value;
 
-	value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
-		SMMU_TLB_FLUSH_VA_GROUP(iova);
+	if (smmu->soc->num_asids == 4)
+		value = (asid & 0x3) << 29;
+	else
+		value = (asid & 0x7f) << 24;
+
+	value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_GROUP(iova);
 	smmu_writel(smmu, value, SMMU_TLB_FLUSH);
 }
 
@@ -529,6 +540,7 @@
 				  dma_addr_t *dmap)
 {
 	unsigned int pd_index = iova_pd_index(iova);
+	struct tegra_smmu *smmu = as->smmu;
 	struct page *pt_page;
 	u32 *pd;
 
@@ -537,7 +549,7 @@
 		return NULL;
 
 	pd = page_address(as->pd);
-	*dmap = smmu_pde_to_dma(pd[pd_index]);
+	*dmap = smmu_pde_to_dma(smmu, pd[pd_index]);
 
 	return tegra_smmu_pte_offset(pt_page, iova);
 }
@@ -579,7 +591,7 @@
 	} else {
 		u32 *pd = page_address(as->pd);
 
-		*dmap = smmu_pde_to_dma(pd[pde]);
+		*dmap = smmu_pde_to_dma(smmu, pd[pde]);
 	}
 
 	return tegra_smmu_pte_offset(as->pts[pde], iova);
@@ -604,7 +616,7 @@
 	if (--as->count[pde] == 0) {
 		struct tegra_smmu *smmu = as->smmu;
 		u32 *pd = page_address(as->pd);
-		dma_addr_t pte_dma = smmu_pde_to_dma(pd[pde]);
+		dma_addr_t pte_dma = smmu_pde_to_dma(smmu, pd[pde]);
 
 		tegra_smmu_set_pde(as, iova, 0);
 
--- linux-4.4.0.orig/drivers/irqchip/irq-atmel-aic-common.c
+++ linux-4.4.0/drivers/irqchip/irq-atmel-aic-common.c
@@ -86,7 +86,7 @@
 	    priority > AT91_AIC_IRQ_MAX_PRIORITY)
 		return -EINVAL;
 
-	*val &= AT91_AIC_PRIOR;
+	*val &= ~AT91_AIC_PRIOR;
 	*val |= priority;
 
 	return 0;
@@ -148,9 +148,9 @@
 	struct device_node *np;
 	void __iomem *regs;
 
-	np = of_find_compatible_node(root, NULL, "atmel,at91rm9200-rtc");
+	np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-rtc");
 	if (!np)
-		np = of_find_compatible_node(root, NULL,
+		np = of_find_compatible_node(NULL, NULL,
 					     "atmel,at91sam9x5-rtc");
 
 	if (!np)
@@ -202,7 +202,6 @@
 		return;
 
 	match = of_match_node(matches, root);
-	of_node_put(root);
 
 	if (match) {
 		void (*fixup)(struct device_node *) = match->data;
--- linux-4.4.0.orig/drivers/irqchip/irq-atmel-aic.c
+++ linux-4.4.0/drivers/irqchip/irq-atmel-aic.c
@@ -176,6 +176,7 @@
 {
 	struct irq_domain_chip_generic *dgc = d->gc;
 	struct irq_chip_generic *gc;
+	unsigned long flags;
 	unsigned smr;
 	int idx;
 	int ret;
@@ -194,12 +195,12 @@
 
 	gc = dgc->gc[idx];
 
-	irq_gc_lock(gc);
+	irq_gc_lock_irqsave(gc, flags);
 	smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq));
 	ret = aic_common_set_priority(intspec[2], &smr);
 	if (!ret)
 		irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq));
-	irq_gc_unlock(gc);
+	irq_gc_unlock_irqrestore(gc, flags);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/irqchip/irq-atmel-aic5.c
+++ linux-4.4.0/drivers/irqchip/irq-atmel-aic5.c
@@ -258,6 +258,7 @@
 				 unsigned int *out_type)
 {
 	struct irq_chip_generic *bgc = irq_get_domain_generic_chip(d, 0);
+	unsigned long flags;
 	unsigned smr;
 	int ret;
 
@@ -269,13 +270,13 @@
 	if (ret)
 		return ret;
 
-	irq_gc_lock(bgc);
+	irq_gc_lock_irqsave(bgc, flags);
 	irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR);
 	smr = irq_reg_readl(bgc, AT91_AIC5_SMR);
 	ret = aic_common_set_priority(intspec[2], &smr);
 	if (!ret)
 		irq_reg_writel(bgc, intspec[2] | smr, AT91_AIC5_SMR);
-	irq_gc_unlock(bgc);
+	irq_gc_unlock_irqrestore(bgc, flags);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/irqchip/irq-bcm7038-l1.c
+++ linux-4.4.0/drivers/irqchip/irq-bcm7038-l1.c
@@ -216,6 +216,33 @@
 	return 0;
 }
 
+#ifdef CONFIG_SMP
+static void bcm7038_l1_cpu_offline(struct irq_data *d)
+{
+	struct cpumask *mask = irq_data_get_affinity_mask(d);
+	int cpu = smp_processor_id();
+	cpumask_t new_affinity;
+
+	/* This CPU was not on the affinity mask */
+	if (!cpumask_test_cpu(cpu, mask))
+		return;
+
+	if (cpumask_weight(mask) > 1) {
+		/*
+		 * Multiple CPU affinity, remove this CPU from the affinity
+		 * mask
+		 */
+		cpumask_copy(&new_affinity, mask);
+		cpumask_clear_cpu(cpu, &new_affinity);
+	} else {
+		/* Only CPU, put on the lowest online CPU */
+		cpumask_clear(&new_affinity);
+		cpumask_set_cpu(cpumask_first(cpu_online_mask), &new_affinity);
+	}
+	irq_set_affinity_locked(d, &new_affinity, false);
+}
+#endif
+
 static int __init bcm7038_l1_init_one(struct device_node *dn,
 				      unsigned int idx,
 				      struct bcm7038_l1_chip *intc)
@@ -256,6 +283,10 @@
 		pr_err("failed to map parent interrupt %d\n", parent_irq);
 		return -EINVAL;
 	}
+
+	if (of_property_read_bool(dn, "brcm,irq-can-wake"))
+		enable_irq_wake(parent_irq);
+
 	irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle,
 					 intc);
 
@@ -267,6 +298,9 @@
 	.irq_mask		= bcm7038_l1_mask,
 	.irq_unmask		= bcm7038_l1_unmask,
 	.irq_set_affinity	= bcm7038_l1_set_affinity,
+#ifdef CONFIG_SMP
+	.irq_cpu_offline	= bcm7038_l1_cpu_offline,
+#endif
 };
 
 static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq,
--- linux-4.4.0.orig/drivers/irqchip/irq-crossbar.c
+++ linux-4.4.0/drivers/irqchip/irq-crossbar.c
@@ -198,7 +198,8 @@
 
 static int __init crossbar_of_init(struct device_node *node)
 {
-	int i, size, max = 0, reserved = 0, entry;
+	int i, size, reserved = 0;
+	u32 max = 0, entry, reg_size;
 	const __be32 *irqsr;
 	int ret = -ENOMEM;
 
@@ -275,9 +276,9 @@
 	if (!cb->register_offsets)
 		goto err_irq_map;
 
-	of_property_read_u32(node, "ti,reg-size", &size);
+	of_property_read_u32(node, "ti,reg-size", &reg_size);
 
-	switch (size) {
+	switch (reg_size) {
 	case 1:
 		cb->write = crossbar_writeb;
 		break;
@@ -303,7 +304,7 @@
 			continue;
 
 		cb->register_offsets[i] = reserved;
-		reserved += size;
+		reserved += reg_size;
 	}
 
 	of_property_read_u32(node, "ti,irqs-safe-map", &cb->safe_map);
--- linux-4.4.0.orig/drivers/irqchip/irq-gic-v2m.c
+++ linux-4.4.0/drivers/irqchip/irq-gic-v2m.c
@@ -15,9 +15,11 @@
 
 #define pr_fmt(fmt) "GICv2m: " fmt
 
+#include <linux/acpi.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
+#include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 #include <linux/slab.h>
@@ -55,7 +57,7 @@
 
 struct v2m_data {
 	struct list_head entry;
-	struct device_node *node;
+	struct fwnode_handle *fwnode;
 	struct resource res;	/* GICv2m resource */
 	void __iomem *base;	/* GICv2m virt address */
 	u32 spi_start;		/* The SPI number that MSIs start */
@@ -138,6 +140,11 @@
 		fwspec.param[0] = 0;
 		fwspec.param[1] = hwirq - 32;
 		fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+	} else if (is_fwnode_irqchip(domain->parent->fwnode)) {
+		fwspec.fwnode = domain->parent->fwnode;
+		fwspec.param_count = 2;
+		fwspec.param[0] = hwirq;
+		fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
 	} else {
 		return -EINVAL;
 	}
@@ -254,7 +261,9 @@
 		list_del(&v2m->entry);
 		kfree(v2m->bm);
 		iounmap(v2m->base);
-		of_node_put(v2m->node);
+		of_node_put(to_of_node(v2m->fwnode));
+		if (is_fwnode_irqchip(v2m->fwnode))
+			irq_domain_free_fwnode(v2m->fwnode);
 		kfree(v2m);
 	}
 }
@@ -268,7 +277,7 @@
 	if (!v2m)
 		return 0;
 
-	inner_domain = irq_domain_create_tree(of_node_to_fwnode(v2m->node),
+	inner_domain = irq_domain_create_tree(v2m->fwnode,
 					      &gicv2m_domain_ops, v2m);
 	if (!inner_domain) {
 		pr_err("Failed to create GICv2m domain\n");
@@ -277,10 +286,10 @@
 
 	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
 	inner_domain->parent = parent;
-	pci_domain = pci_msi_create_irq_domain(of_node_to_fwnode(v2m->node),
+	pci_domain = pci_msi_create_irq_domain(v2m->fwnode,
 					       &gicv2m_msi_domain_info,
 					       inner_domain);
-	plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(v2m->node),
+	plat_domain = platform_msi_create_irq_domain(v2m->fwnode,
 						     &gicv2m_pmsi_domain_info,
 						     inner_domain);
 	if (!pci_domain || !plat_domain) {
@@ -296,8 +305,9 @@
 	return 0;
 }
 
-static int __init gicv2m_init_one(struct device_node *node,
-				  struct irq_domain *parent)
+static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
+				  u32 spi_start, u32 nr_spis,
+				  struct resource *res)
 {
 	int ret;
 	struct v2m_data *v2m;
@@ -309,13 +319,9 @@
 	}
 
 	INIT_LIST_HEAD(&v2m->entry);
-	v2m->node = node;
+	v2m->fwnode = fwnode;
 
-	ret = of_address_to_resource(node, 0, &v2m->res);
-	if (ret) {
-		pr_err("Failed to allocate v2m resource.\n");
-		goto err_free_v2m;
-	}
+	memcpy(&v2m->res, res, sizeof(struct resource));
 
 	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
 	if (!v2m->base) {
@@ -324,10 +330,9 @@
 		goto err_free_v2m;
 	}
 
-	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
-	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
-		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
-			v2m->spi_start, v2m->nr_spis);
+	if (spi_start && nr_spis) {
+		v2m->spi_start = spi_start;
+		v2m->nr_spis = nr_spis;
 	} else {
 		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
 
@@ -359,10 +364,10 @@
 	}
 
 	list_add_tail(&v2m->entry, &v2m_nodes);
-	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
-		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
-		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
 
+	pr_info("range[%#lx:%#lx], SPI[%d:%d]\n",
+		(unsigned long)res->start, (unsigned long)res->end,
+		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
 	return 0;
 
 err_iounmap:
@@ -377,17 +382,34 @@
 	{},
 };
 
-int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
+static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
+				 struct irq_domain *parent)
 {
 	int ret = 0;
+	struct device_node *node = to_of_node(parent_handle);
 	struct device_node *child;
 
 	for (child = of_find_matching_node(node, gicv2m_device_id); child;
 	     child = of_find_matching_node(child, gicv2m_device_id)) {
+		u32 spi_start = 0, nr_spis = 0;
+		struct resource res;
+
 		if (!of_find_property(child, "msi-controller", NULL))
 			continue;
 
-		ret = gicv2m_init_one(child, parent);
+		ret = of_address_to_resource(child, 0, &res);
+		if (ret) {
+			pr_err("Failed to allocate v2m resource.\n");
+			break;
+		}
+
+		if (!of_property_read_u32(child, "arm,msi-base-spi",
+					  &spi_start) &&
+		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
+			pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+				spi_start, nr_spis);
+
+		ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res);
 		if (ret) {
 			of_node_put(node);
 			break;
@@ -400,3 +422,100 @@
 		gicv2m_teardown();
 	return ret;
 }
+
+#ifdef CONFIG_ACPI
+static int acpi_num_msi;
+
+static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
+{
+	struct v2m_data *data;
+
+	if (WARN_ON(acpi_num_msi <= 0))
+		return NULL;
+
+	/* We only return the fwnode of the first MSI frame. */
+	data = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry);
+	if (!data)
+		return NULL;
+
+	return data->fwnode;
+}
+
+static int __init
+acpi_parse_madt_msi(struct acpi_subtable_header *header,
+		    const unsigned long end)
+{
+	int ret;
+	struct resource res;
+	u32 spi_start = 0, nr_spis = 0;
+	struct acpi_madt_generic_msi_frame *m;
+	struct fwnode_handle *fwnode;
+
+	m = (struct acpi_madt_generic_msi_frame *)header;
+	if (BAD_MADT_ENTRY(m, end))
+		return -EINVAL;
+
+	res.start = m->base_address;
+	res.end = m->base_address + SZ_4K;
+
+	if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
+		spi_start = m->spi_base;
+		nr_spis = m->spi_count;
+
+		pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+			spi_start, nr_spis);
+	}
+
+	fwnode = irq_domain_alloc_fwnode((void *)m->base_address);
+	if (!fwnode) {
+		pr_err("Unable to allocate GICv2m domain token\n");
+		return -EINVAL;
+	}
+
+	ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res);
+	if (ret)
+		irq_domain_free_fwnode(fwnode);
+
+	return ret;
+}
+
+static int __init gicv2m_acpi_init(struct irq_domain *parent)
+{
+	int ret;
+
+	if (acpi_num_msi > 0)
+		return 0;
+
+	acpi_num_msi = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_MSI_FRAME,
+				      acpi_parse_madt_msi, 0);
+
+	if (acpi_num_msi <= 0)
+		goto err_out;
+
+	ret = gicv2m_allocate_domains(parent);
+	if (ret)
+		goto err_out;
+
+	pci_msi_register_fwnode_provider(&gicv2m_get_fwnode);
+
+	return 0;
+
+err_out:
+	gicv2m_teardown();
+	return -EINVAL;
+}
+#else /* CONFIG_ACPI */
+static int __init gicv2m_acpi_init(struct irq_domain *parent)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_ACPI */
+
+int __init gicv2m_init(struct fwnode_handle *parent_handle,
+		       struct irq_domain *parent)
+{
+	if (is_of_node(parent_handle))
+		return gicv2m_of_init(parent_handle, parent);
+
+	return gicv2m_acpi_init(parent);
+}
--- linux-4.4.0.orig/drivers/irqchip/irq-gic-v3-its.c
+++ linux-4.4.0/drivers/irqchip/irq-gic-v3-its.c
@@ -41,6 +41,7 @@
 
 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING		(1ULL << 0)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375	(1ULL << 1)
+#define ITS_FLAGS_WORKAROUND_CAVIUM_23144	(1ULL << 2)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING	(1 << 0)
 
@@ -66,15 +67,22 @@
 	unsigned long		phys_base;
 	struct its_cmd_block	*cmd_base;
 	struct its_cmd_block	*cmd_write;
-	void			*tables[GITS_BASER_NR_REGS];
+	struct {
+		void		*base;
+		u32		order;
+	} tables[GITS_BASER_NR_REGS];
 	struct its_collection	*collections;
 	struct list_head	its_device_list;
 	u64			flags;
 	u32			ite_size;
+	int			numa_node;
 };
 
 #define ITS_ITT_ALIGN		SZ_256
 
+/* Convert page order to size in bytes */
+#define PAGE_ORDER_TO_SIZE(o)	(PAGE_SIZE << (o))
+
 struct event_lpi_map {
 	unsigned long		*lpi_map;
 	u16			*col_map;
@@ -97,7 +105,6 @@
 
 static LIST_HEAD(its_nodes);
 static DEFINE_SPINLOCK(its_lock);
-static struct device_node *gic_root_node;
 static struct rdists *gic_rdists;
 
 #define gic_data_rdist()		(raw_cpu_ptr(gic_rdists->rdist))
@@ -344,7 +351,7 @@
 						   struct its_cmd_desc *desc)
 {
 	its_encode_cmd(cmd, GITS_CMD_INVALL);
-	its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id);
+	its_encode_collection(cmd, desc->its_invall_cmd.col->col_id);
 
 	its_fixup_cmd(cmd);
 
@@ -597,19 +604,26 @@
 	lpi_set_config(d, true);
 }
 
-static void its_eoi_irq(struct irq_data *d)
-{
-	gic_write_eoir(d->hwirq);
-}
-
 static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 			    bool force)
 {
-	unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
+	unsigned int cpu;
+	const struct cpumask *cpu_mask = cpu_online_mask;
 	struct its_device *its_dev = irq_data_get_irq_chip_data(d);
 	struct its_collection *target_col;
 	u32 id = its_get_event_id(d);
 
+       /* lpi cannot be routed to a redistributor that is on a foreign node */
+	if (its_dev->its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
+		if (its_dev->its->numa_node >= 0) {
+			cpu_mask = cpumask_of_node(its_dev->its->numa_node);
+			if (!cpumask_intersects(mask_val, cpu_mask))
+				return -EINVAL;
+		}
+	}
+
+	cpu = cpumask_any_and(mask_val, cpu_mask);
+
 	if (cpu >= nr_cpu_ids)
 		return -EINVAL;
 
@@ -638,7 +652,7 @@
 	.name			= "ITS",
 	.irq_mask		= its_mask_irq,
 	.irq_unmask		= its_unmask_irq,
-	.irq_eoi		= its_eoi_irq,
+	.irq_eoi		= irq_chip_eoi_parent,
 	.irq_set_affinity	= its_set_affinity,
 	.irq_compose_msi_msg	= its_irq_compose_msi_msg,
 };
@@ -654,7 +668,7 @@
  * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
  */
 #define IRQS_PER_CHUNK_SHIFT	5
-#define IRQS_PER_CHUNK		(1 << IRQS_PER_CHUNK_SHIFT)
+#define IRQS_PER_CHUNK		(1UL << IRQS_PER_CHUNK_SHIFT)
 
 static unsigned long *lpi_bitmap;
 static u32 lpi_chunks;
@@ -670,7 +684,7 @@
 	return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
 }
 
-static int its_lpi_init(u32 id_bits)
+static int __init its_lpi_init(u32 id_bits)
 {
 	lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
 
@@ -807,9 +821,10 @@
 	int i;
 
 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
-		if (its->tables[i]) {
-			free_page((unsigned long)its->tables[i]);
-			its->tables[i] = NULL;
+		if (its->tables[i].base) {
+			free_pages((unsigned long)its->tables[i].base,
+				   its->tables[i].order);
+			its->tables[i].base = NULL;
 		}
 	}
 }
@@ -842,7 +857,6 @@
 		u64 type = GITS_BASER_TYPE(val);
 		u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
 		int order = get_order(psz);
-		int alloc_size;
 		int alloc_pages;
 		u64 tmp;
 		void *base;
@@ -874,8 +888,8 @@
 			}
 		}
 
-		alloc_size = (1 << order) * PAGE_SIZE;
-		alloc_pages = (alloc_size / psz);
+retry_alloc_baser:
+		alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz);
 		if (alloc_pages > GITS_BASER_PAGES_MAX) {
 			alloc_pages = GITS_BASER_PAGES_MAX;
 			order = get_order(GITS_BASER_PAGES_MAX * psz);
@@ -889,7 +903,8 @@
 			goto out_free;
 		}
 
-		its->tables[i] = base;
+		its->tables[i].base = base;
+		its->tables[i].order = order;
 
 retry_baser:
 		val = (virt_to_phys(base) 				 |
@@ -927,7 +942,7 @@
 			shr = tmp & GITS_BASER_SHAREABILITY_MASK;
 			if (!shr) {
 				cache = GITS_BASER_nC;
-				__flush_dcache_area(base, alloc_size);
+				__flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order));
 			}
 			goto retry_baser;
 		}
@@ -938,13 +953,16 @@
 			 * size and retry. If we reach 4K, then
 			 * something is horribly wrong...
 			 */
+			free_pages((unsigned long)base, order);
+			its->tables[i].base = NULL;
+
 			switch (psz) {
 			case SZ_16K:
 				psz = SZ_4K;
-				goto retry_baser;
+				goto retry_alloc_baser;
 			case SZ_64K:
 				psz = SZ_16K;
-				goto retry_baser;
+				goto retry_alloc_baser;
 			}
 		}
 
@@ -957,7 +975,7 @@
 		}
 
 		pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
-			(int)(alloc_size / entry_size),
+			(int)(PAGE_ORDER_TO_SIZE(order) / entry_size),
 			its_base_type_string[type],
 			(unsigned long)virt_to_phys(base),
 			psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
@@ -1086,6 +1104,16 @@
 	list_for_each_entry(its, &its_nodes, entry) {
 		u64 target;
 
+		/* avoid cross node collections and its mapping */
+		if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
+			struct device_node *cpu_node;
+
+			cpu_node = of_get_cpu_node(cpu, NULL);
+			if (its->numa_node != NUMA_NO_NODE &&
+				its->numa_node != of_node_to_nid(cpu_node))
+				continue;
+		}
+
 		/*
 		 * We now have to bind each collection to its target
 		 * redistributor.
@@ -1149,11 +1177,10 @@
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	/*
-	 * At least one bit of EventID is being used, hence a minimum
-	 * of two entries. No, the architecture doesn't let you
-	 * express an ITT with a single entry.
+	 * We allocate at least one chunk worth of LPIs bet device,
+	 * and thus that many ITEs. The device may require less though.
 	 */
-	nr_ites = max(2UL, roundup_pow_of_two(nvecs));
+	nr_ites = max(IRQS_PER_CHUNK, roundup_pow_of_two(nvecs));
 	sz = nr_ites * its->ite_size;
 	sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
 	itt = kzalloc(sz, GFP_KERNEL);
@@ -1202,13 +1229,14 @@
 	kfree(its_dev);
 }
 
-static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
+static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number_t *hwirq)
 {
 	int idx;
 
-	idx = find_first_zero_bit(dev->event_map.lpi_map,
-				  dev->event_map.nr_lpis);
-	if (idx == dev->event_map.nr_lpis)
+	idx = bitmap_find_free_region(dev->event_map.lpi_map,
+				      dev->event_map.nr_lpis,
+				      get_count_order(nvecs));
+	if (idx < 0)
 		return -ENOSPC;
 
 	*hwirq = dev->event_map.lpi_base + idx;
@@ -1289,20 +1317,20 @@
 	int err;
 	int i;
 
-	for (i = 0; i < nr_irqs; i++) {
-		err = its_alloc_device_irq(its_dev, &hwirq);
-		if (err)
-			return err;
+	err = its_alloc_device_irq(its_dev, nr_irqs, &hwirq);
+	if (err)
+		return err;
 
-		err = its_irq_gic_domain_alloc(domain, virq + i, hwirq);
+	for (i = 0; i < nr_irqs; i++) {
+		err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
 		if (err)
 			return err;
 
 		irq_domain_set_hwirq_and_chip(domain, virq + i,
-					      hwirq, &its_irq_chip, its_dev);
+					      hwirq + i, &its_irq_chip, its_dev);
 		pr_debug("ID:%d pID:%d vID:%d\n",
-			 (int)(hwirq - its_dev->event_map.lpi_base),
-			 (int) hwirq, virq + i);
+			 (int)(hwirq + i - its_dev->event_map.lpi_base),
+			 (int)(hwirq + i), virq + i);
 	}
 
 	return 0;
@@ -1313,9 +1341,14 @@
 {
 	struct its_device *its_dev = irq_data_get_irq_chip_data(d);
 	u32 event = its_get_event_id(d);
+	const struct cpumask *cpu_mask = cpu_online_mask;
+
+	/* get the cpu_mask of local node */
+	if (its_dev->its->numa_node >= 0)
+		cpu_mask = cpumask_of_node(its_dev->its->numa_node);
 
 	/* Bind the LPI to the first possible CPU */
-	its_dev->event_map.col_map[event] = cpumask_first(cpu_online_mask);
+	its_dev->event_map.col_map[event] = cpumask_first(cpu_mask);
 
 	/* Map the GIC IRQ and event to the device */
 	its_send_mapvi(its_dev, d->hwirq, event);
@@ -1338,14 +1371,13 @@
 	struct its_device *its_dev = irq_data_get_irq_chip_data(d);
 	int i;
 
+	bitmap_release_region(its_dev->event_map.lpi_map,
+			      its_get_event_id(irq_domain_get_irq_data(domain, virq)),
+			      get_count_order(nr_irqs));
+
 	for (i = 0; i < nr_irqs; i++) {
 		struct irq_data *data = irq_domain_get_irq_data(domain,
 								virq + i);
-		u32 event = its_get_event_id(data);
-
-		/* Mark interrupt index as unused */
-		clear_bit(event, its_dev->event_map.lpi_map);
-
 		/* Nuke the entry in the domain */
 		irq_domain_reset_irq_data(data);
 	}
@@ -1405,6 +1437,13 @@
 	its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375;
 }
 
+static void __maybe_unused its_enable_quirk_cavium_23144(void *data)
+{
+	struct its_node *its = data;
+
+	its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_23144;
+}
+
 static const struct gic_quirk its_quirks[] = {
 #ifdef CONFIG_CAVIUM_ERRATUM_22375
 	{
@@ -1414,6 +1453,14 @@
 		.init	= its_enable_quirk_cavium_22375,
 	},
 #endif
+#ifdef CONFIG_CAVIUM_ERRATUM_23144
+	{
+		.desc	= "ITS: Cavium erratum 23144",
+		.iidr	= 0xa100034c,	/* ThunderX pass 1.x */
+		.mask	= 0xffff0fff,
+		.init	= its_enable_quirk_cavium_23144,
+	},
+#endif
 	{
 	}
 };
@@ -1425,7 +1472,8 @@
 	gic_enable_quirks(iidr, its_quirks, its);
 }
 
-static int its_probe(struct device_node *node, struct irq_domain *parent)
+static int __init its_probe(struct device_node *node,
+			    struct irq_domain *parent)
 {
 	struct resource res;
 	struct its_node *its;
@@ -1475,6 +1523,7 @@
 	its->base = its_base;
 	its->phys_base = res.start;
 	its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
+	its->numa_node = of_node_to_nid(node);
 
 	its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
 	if (!its->cmd_base) {
@@ -1586,7 +1635,7 @@
 	{},
 };
 
-int its_init(struct device_node *node, struct rdists *rdists,
+int __init its_init(struct device_node *node, struct rdists *rdists,
 	     struct irq_domain *parent_domain)
 {
 	struct device_node *np;
@@ -1602,8 +1651,6 @@
 	}
 
 	gic_rdists = rdists;
-	gic_root_node = node;
-
 	its_alloc_lpi_tables();
 	its_lpi_init(rdists->id_bits);
 
--- linux-4.4.0.orig/drivers/irqchip/irq-gic-v3.c
+++ linux-4.4.0/drivers/irqchip/irq-gic-v3.c
@@ -15,10 +15,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/acpi.h>
 #include <linux/cpu.h>
 #include <linux/cpu_pm.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -38,6 +40,7 @@
 struct redist_region {
 	void __iomem		*redist_base;
 	phys_addr_t		phys_base;
+	bool			single_redist;
 };
 
 struct gic_chip_data {
@@ -142,7 +145,7 @@
 			return;	/* No PM support in this redistributor */
 	}
 
-	while (count--) {
+	while (--count) {
 		val = readl_relaxed(rbase + GICR_WAKER);
 		if (enable ^ (val & GICR_WAKER_ChildrenAsleep))
 			break;
@@ -361,6 +364,13 @@
 			if (static_key_true(&supports_deactivate))
 				gic_write_dir(irqnr);
 #ifdef CONFIG_SMP
+			/*
+			 * Unlike GICv2, we don't need an smp_rmb() here.
+			 * The control dependency from gic_read_iar to
+			 * the ISB in gic_write_eoir is enough to ensure
+			 * that any shared data read by handle_IPI will
+			 * be read after the ACK.
+			 */
 			handle_IPI(irqnr, regs);
 #else
 			WARN_ONCE(true, "Unexpected SGI received!\n");
@@ -380,6 +390,15 @@
 	writel_relaxed(0, base + GICD_CTLR);
 	gic_dist_wait_for_rwp();
 
+	/*
+	 * Configure SPIs as non-secure Group-1. This will only matter
+	 * if the GIC only has a single security state. This will not
+	 * do the right thing if the kernel is running in secure mode,
+	 * but that's not the intended use case anyway.
+	 */
+	for (i = 32; i < gic_data.irq_nr; i += 32)
+		writel_relaxed(~0, base + GICD_IGROUPR + i / 8);
+
 	gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
 
 	/* Enable distributor with ARE, Group1 */
@@ -434,6 +453,9 @@
 				return 0;
 			}
 
+			if (gic_data.redist_regions[i].single_redist)
+				break;
+
 			if (gic_data.redist_stride) {
 				ptr += gic_data.redist_stride;
 			} else {
@@ -494,6 +516,9 @@
 
 	rbase = gic_data_rdist_sgi_base();
 
+	/* Configure SGIs/PPIs as non-secure Group-1 */
+	writel_relaxed(~0, rbase + GICR_IGROUPR0);
+
 	gic_cpu_config(rbase, gic_redist_wait_for_rwp);
 
 	/* Give LPIs a spin */
@@ -525,7 +550,7 @@
 static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
 				   unsigned long cluster_id)
 {
-	int cpu = *base_cpu;
+	int next_cpu, cpu = *base_cpu;
 	unsigned long mpidr = cpu_logical_map(cpu);
 	u16 tlist = 0;
 
@@ -539,9 +564,10 @@
 
 		tlist |= 1 << (mpidr & 0xf);
 
-		cpu = cpumask_next(cpu, mask);
-		if (cpu >= nr_cpu_ids)
+		next_cpu = cpumask_next(cpu, mask);
+		if (next_cpu >= nr_cpu_ids)
 			goto out;
+		cpu = next_cpu;
 
 		mpidr = cpu_logical_map(cpu);
 
@@ -569,7 +595,7 @@
 	       MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
 	       tlist << ICC_SGI1R_TARGET_LIST_SHIFT);
 
-	pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
+	pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
 	gic_write_sgi1r(val);
 }
 
@@ -584,7 +610,7 @@
 	 * Ensure that stores to Normal memory are visible to the
 	 * other CPUs before issuing the IPI.
 	 */
-	smp_wmb();
+	wmb();
 
 	for_each_cpu(cpu, mask) {
 		unsigned long cluster_id = cpu_logical_map(cpu) & ~0xffUL;
@@ -612,6 +638,9 @@
 	int enabled;
 	u64 val;
 
+	if (cpu >= nr_cpu_ids)
+		return -EINVAL;
+
 	if (gic_irq_in_rdist(d))
 		return -EINVAL;
 
@@ -764,6 +793,15 @@
 		return 0;
 	}
 
+	if (is_fwnode_irqchip(fwspec->fwnode)) {
+		if(fwspec->param_count != 2)
+			return -EINVAL;
+
+		*hwirq = fwspec->param[0];
+		*type = fwspec->param[1];
+		return 0;
+	}
+
 	return -EINVAL;
 }
 
@@ -811,17 +849,88 @@
 #endif
 }
 
+static int __init gic_init_bases(void __iomem *dist_base,
+				 struct redist_region *rdist_regs,
+				 u32 nr_redist_regions,
+				 u64 redist_stride,
+				 struct fwnode_handle *handle)
+{
+	struct device_node *node;
+	u32 typer;
+	int gic_irqs;
+	int err;
+
+	if (!is_hyp_mode_available())
+		static_key_slow_dec(&supports_deactivate);
+
+	if (static_key_true(&supports_deactivate))
+		pr_info("GIC: Using split EOI/Deactivate mode\n");
+
+	gic_data.dist_base = dist_base;
+	gic_data.redist_regions = rdist_regs;
+	gic_data.nr_redist_regions = nr_redist_regions;
+	gic_data.redist_stride = redist_stride;
+
+	gicv3_enable_quirks();
+
+	/*
+	 * Find out how many interrupts are supported.
+	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
+	 */
+	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
+	gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
+	gic_irqs = GICD_TYPER_IRQS(typer);
+	if (gic_irqs > 1020)
+		gic_irqs = 1020;
+	gic_data.irq_nr = gic_irqs;
+
+	gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
+						 &gic_data);
+	gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
+
+	if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	set_handle_irq(gic_handle_irq);
+
+	node = to_of_node(handle);
+	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
+	    node) /* Temp hack to prevent ITS init for ACPI */
+		its_init(node, &gic_data.rdists, gic_data.domain);
+
+	gic_smp_init();
+	gic_dist_init();
+	gic_cpu_init();
+	gic_cpu_pm_init();
+
+	return 0;
+
+out_free:
+	if (gic_data.domain)
+		irq_domain_remove(gic_data.domain);
+	free_percpu(gic_data.rdists.rdist);
+	return err;
+}
+
+static int __init gic_validate_dist_version(void __iomem *dist_base)
+{
+	u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
+
+	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4)
+		return -ENODEV;
+
+	return 0;
+}
+
 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
 {
 	void __iomem *dist_base;
 	struct redist_region *rdist_regs;
 	u64 redist_stride;
 	u32 nr_redist_regions;
-	u32 typer;
-	u32 reg;
-	int gic_irqs;
-	int err;
-	int i;
+	int err, i;
 
 	dist_base = of_iomap(node, 0);
 	if (!dist_base) {
@@ -830,11 +939,10 @@
 		return -ENXIO;
 	}
 
-	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
-	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
+	err = gic_validate_dist_version(dist_base);
+	if (err) {
 		pr_err("%s: no distributor detected, giving up\n",
 			node->full_name);
-		err = -ENODEV;
 		goto out_unmap_dist;
 	}
 
@@ -865,63 +973,229 @@
 	if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
 		redist_stride = 0;
 
-	if (!is_hyp_mode_available())
-		static_key_slow_dec(&supports_deactivate);
+	err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
+			     redist_stride, &node->fwnode);
+	if (!err)
+		return 0;
 
-	if (static_key_true(&supports_deactivate))
-		pr_info("GIC: Using split EOI/Deactivate mode\n");
+out_unmap_rdist:
+	for (i = 0; i < nr_redist_regions; i++)
+		if (rdist_regs[i].redist_base)
+			iounmap(rdist_regs[i].redist_base);
+	kfree(rdist_regs);
+out_unmap_dist:
+	iounmap(dist_base);
+	return err;
+}
 
-	gic_data.dist_base = dist_base;
-	gic_data.redist_regions = rdist_regs;
-	gic_data.nr_redist_regions = nr_redist_regions;
-	gic_data.redist_stride = redist_stride;
+IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
 
-	gicv3_enable_quirks();
+#ifdef CONFIG_ACPI
+static void __iomem *dist_base;
+static struct redist_region *redist_regs __initdata;
+static u32 nr_redist_regions __initdata;
+static bool single_redist;
+
+static void __init
+gic_acpi_register_redist(phys_addr_t phys_base, void __iomem *redist_base)
+{
+	static int count = 0;
+
+	redist_regs[count].phys_base = phys_base;
+	redist_regs[count].redist_base = redist_base;
+	redist_regs[count].single_redist = single_redist;
+	count++;
+}
+
+static int __init
+gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
+			   const unsigned long end)
+{
+	struct acpi_madt_generic_redistributor *redist =
+			(struct acpi_madt_generic_redistributor *)header;
+	void __iomem *redist_base;
+
+	redist_base = ioremap(redist->base_address, redist->length);
+	if (!redist_base) {
+		pr_err("Couldn't map GICR region @%llx\n", redist->base_address);
+		return -ENOMEM;
+	}
+
+	gic_acpi_register_redist(redist->base_address, redist_base);
+	return 0;
+}
+
+static int __init
+gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
+			 const unsigned long end)
+{
+	struct acpi_madt_generic_interrupt *gicc =
+				(struct acpi_madt_generic_interrupt *)header;
+	u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
+	u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
+	void __iomem *redist_base;
+
+	redist_base = ioremap(gicc->gicr_base_address, size);
+	if (!redist_base)
+		return -ENOMEM;
+
+	gic_acpi_register_redist(gicc->gicr_base_address, redist_base);
+	return 0;
+}
+
+static int __init gic_acpi_collect_gicr_base(void)
+{
+	acpi_tbl_entry_handler redist_parser;
+	enum acpi_madt_type type;
+
+	if (single_redist) {
+		type = ACPI_MADT_TYPE_GENERIC_INTERRUPT;
+		redist_parser = gic_acpi_parse_madt_gicc;
+	} else {
+		type = ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR;
+		redist_parser = gic_acpi_parse_madt_redist;
+	}
+
+	/* Collect redistributor base addresses in GICR entries */
+	if (acpi_table_parse_madt(type, redist_parser, 0) > 0)
+		return 0;
+
+	pr_info("No valid GICR entries exist\n");
+	return -ENODEV;
+}
+
+static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header,
+				  const unsigned long end)
+{
+	/* Subtable presence means that redist exists, that's it */
+	return 0;
+}
+
+static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header,
+				      const unsigned long end)
+{
+	struct acpi_madt_generic_interrupt *gicc =
+				(struct acpi_madt_generic_interrupt *)header;
 
 	/*
-	 * Find out how many interrupts are supported.
-	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
+	 * If GICC is enabled and has valid gicr base address, then it means
+	 * GICR base is presented via GICC
 	 */
-	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
-	gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
-	gic_irqs = GICD_TYPER_IRQS(typer);
-	if (gic_irqs > 1020)
-		gic_irqs = 1020;
-	gic_data.irq_nr = gic_irqs;
+	if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
+		return 0;
 
-	gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
-					      &gic_data);
-	gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
+	return -ENODEV;
+}
 
-	if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
+static int __init gic_acpi_count_gicr_regions(void)
+{
+	int count;
+
+	/*
+	 * Count how many redistributor regions we have. It is not allowed
+	 * to mix redistributor description, GICR and GICC subtables have to be
+	 * mutually exclusive.
+	 */
+	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+				      gic_acpi_match_gicr, 0);
+	if (count > 0) {
+		single_redist = false;
+		return count;
+	}
+
+	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+				      gic_acpi_match_gicc, 0);
+	if (count > 0)
+		single_redist = true;
+
+	return count;
+}
+
+static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
+					   struct acpi_probe_entry *ape)
+{
+	struct acpi_madt_generic_distributor *dist;
+	int count;
+
+	dist = (struct acpi_madt_generic_distributor *)header;
+	if (dist->version != ape->driver_data)
+		return false;
+
+	/* We need to do that exercise anyway, the sooner the better */
+	count = gic_acpi_count_gicr_regions();
+	if (count <= 0)
+		return false;
+
+	nr_redist_regions = count;
+	return true;
+}
+
+#define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K)
+
+static int __init
+gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
+{
+	struct acpi_madt_generic_distributor *dist;
+	struct fwnode_handle *domain_handle;
+	int i, err;
+
+	/* Get distributor base address */
+	dist = (struct acpi_madt_generic_distributor *)header;
+	dist_base = ioremap(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE);
+	if (!dist_base) {
+		pr_err("Unable to map GICD registers\n");
+		return -ENOMEM;
+	}
+
+	err = gic_validate_dist_version(dist_base);
+	if (err) {
+		pr_err("No distributor detected at @%p, giving up", dist_base);
+		goto out_dist_unmap;
+	}
+
+	redist_regs = kzalloc(sizeof(*redist_regs) * nr_redist_regions,
+			      GFP_KERNEL);
+	if (!redist_regs) {
 		err = -ENOMEM;
-		goto out_free;
+		goto out_dist_unmap;
 	}
 
-	set_handle_irq(gic_handle_irq);
+	err = gic_acpi_collect_gicr_base();
+	if (err)
+		goto out_redist_unmap;
 
-	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
-		its_init(node, &gic_data.rdists, gic_data.domain);
+	domain_handle = irq_domain_alloc_fwnode(dist_base);
+	if (!domain_handle) {
+		err = -ENOMEM;
+		goto out_redist_unmap;
+	}
 
-	gic_smp_init();
-	gic_dist_init();
-	gic_cpu_init();
-	gic_cpu_pm_init();
+	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
+			     domain_handle);
+	if (err)
+		goto out_fwhandle_free;
 
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
 	return 0;
 
-out_free:
-	if (gic_data.domain)
-		irq_domain_remove(gic_data.domain);
-	free_percpu(gic_data.rdists.rdist);
-out_unmap_rdist:
+out_fwhandle_free:
+	irq_domain_free_fwnode(domain_handle);
+out_redist_unmap:
 	for (i = 0; i < nr_redist_regions; i++)
-		if (rdist_regs[i].redist_base)
-			iounmap(rdist_regs[i].redist_base);
-	kfree(rdist_regs);
-out_unmap_dist:
+		if (redist_regs[i].redist_base)
+			iounmap(redist_regs[i].redist_base);
+	kfree(redist_regs);
+out_dist_unmap:
 	iounmap(dist_base);
 	return err;
 }
-
-IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
+IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V3,
+		     gic_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V4,
+		     gic_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v3_or_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_NONE,
+		     gic_acpi_init);
+#endif
--- linux-4.4.0.orig/drivers/irqchip/irq-gic.c
+++ linux-4.4.0/drivers/irqchip/irq-gic.c
@@ -336,7 +336,7 @@
 		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
-		if (likely(irqnr > 15 && irqnr < 1021)) {
+		if (likely(irqnr > 15 && irqnr < 1020)) {
 			if (static_key_true(&supports_deactivate))
 				writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
 			handle_domain_irq(gic->domain, irqnr, regs);
@@ -347,6 +347,14 @@
 			if (static_key_true(&supports_deactivate))
 				writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE);
 #ifdef CONFIG_SMP
+			/*
+			 * Ensure any shared data written by the CPU sending
+			 * the IPI is read after we've read the ACK register
+			 * on the GIC.
+			 *
+			 * Pairs with the write barrier in gic_raise_softirq
+			 */
+			smp_rmb();
 			handle_IPI(irqnr, regs);
 #endif
 			continue;
@@ -972,7 +980,7 @@
 		return 0;
 	}
 
-	if (fwspec->fwnode->type == FWNODE_IRQCHIP) {
+	if (is_fwnode_irqchip(fwspec->fwnode)) {
 		if(fwspec->param_count != 2)
 			return -EINVAL;
 
@@ -1234,7 +1242,7 @@
 	}
 
 	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
-		gicv2m_of_init(node, gic_data[gic_cnt].domain);
+		gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain);
 
 	gic_cnt++;
 	return 0;
@@ -1359,6 +1367,10 @@
 	__gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
 
 	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
+
+	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
+		gicv2m_init(NULL, gic_data[0].domain);
+
 	return 0;
 }
 IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
--- linux-4.4.0.orig/drivers/irqchip/irq-imx-gpcv2.c
+++ linux-4.4.0/drivers/irqchip/irq-imx-gpcv2.c
@@ -145,6 +145,7 @@
 	.irq_unmask		= imx_gpcv2_irq_unmask,
 	.irq_set_wake		= imx_gpcv2_irq_set_wake,
 	.irq_retrigger		= irq_chip_retrigger_hierarchy,
+	.irq_set_type		= irq_chip_set_type_parent,
 #ifdef CONFIG_SMP
 	.irq_set_affinity	= irq_chip_set_affinity_parent,
 #endif
@@ -230,6 +231,8 @@
 		return -ENOMEM;
 	}
 
+	raw_spin_lock_init(&cd->rlock);
+
 	cd->gpc_base = of_iomap(node, 0);
 	if (!cd->gpc_base) {
 		pr_err("fsl-gpcv2: unable to map gpc registers\n");
--- linux-4.4.0.orig/drivers/irqchip/irq-ingenic.c
+++ linux-4.4.0/drivers/irqchip/irq-ingenic.c
@@ -117,6 +117,14 @@
 		goto out_unmap_irq;
 	}
 
+	domain = irq_domain_add_legacy(node, num_chips * 32,
+				       JZ4740_IRQ_BASE, 0,
+				       &irq_domain_simple_ops, NULL);
+	if (!domain) {
+		err = -ENOMEM;
+		goto out_unmap_base;
+	}
+
 	for (i = 0; i < num_chips; i++) {
 		/* Mask all irqs */
 		writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
@@ -143,14 +151,11 @@
 				       IRQ_NOPROBE | IRQ_LEVEL);
 	}
 
-	domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0,
-				       &irq_domain_simple_ops, NULL);
-	if (!domain)
-		pr_warn("unable to register IRQ domain\n");
-
 	setup_irq(parent_irq, &intc_cascade_action);
 	return 0;
 
+out_unmap_base:
+	iounmap(intc->base);
 out_unmap_irq:
 	irq_dispose_mapping(parent_irq);
 out_free:
--- linux-4.4.0.orig/drivers/irqchip/irq-keystone.c
+++ linux-4.4.0/drivers/irqchip/irq-keystone.c
@@ -19,9 +19,9 @@
 #include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip.h>
-#include <linux/irqchip/chained_irq.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/mfd/syscon.h>
@@ -39,6 +39,7 @@
 	struct irq_domain	*irqd;
 	struct regmap		*devctrl_regs;
 	u32			devctrl_offset;
+	raw_spinlock_t		wa_lock;
 };
 
 static inline u32 keystone_irq_readl(struct keystone_irq_device *kirq)
@@ -83,17 +84,15 @@
 	/* nothing to do here */
 }
 
-static void keystone_irq_handler(struct irq_desc *desc)
+static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq)
 {
-	unsigned int irq = irq_desc_get_irq(desc);
-	struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc);
+	struct keystone_irq_device *kirq = keystone_irq;
+	unsigned long wa_lock_flags;
 	unsigned long pending;
 	int src, virq;
 
 	dev_dbg(kirq->dev, "start irq %d\n", irq);
 
-	chained_irq_enter(irq_desc_get_chip(desc), desc);
-
 	pending = keystone_irq_readl(kirq);
 	keystone_irq_writel(kirq, pending);
 
@@ -111,13 +110,15 @@
 			if (!virq)
 				dev_warn(kirq->dev, "sporious irq detected hwirq %d, virq %d\n",
 					 src, virq);
+			raw_spin_lock_irqsave(&kirq->wa_lock, wa_lock_flags);
 			generic_handle_irq(virq);
+			raw_spin_unlock_irqrestore(&kirq->wa_lock,
+						   wa_lock_flags);
 		}
 	}
 
-	chained_irq_exit(irq_desc_get_chip(desc), desc);
-
 	dev_dbg(kirq->dev, "end irq %d\n", irq);
+	return IRQ_HANDLED;
 }
 
 static int keystone_irq_map(struct irq_domain *h, unsigned int virq,
@@ -182,9 +183,16 @@
 		return -ENODEV;
 	}
 
+	raw_spin_lock_init(&kirq->wa_lock);
+
 	platform_set_drvdata(pdev, kirq);
 
-	irq_set_chained_handler_and_data(kirq->irq, keystone_irq_handler, kirq);
+	ret = request_irq(kirq->irq, keystone_irq_handler,
+			  0, dev_name(dev), kirq);
+	if (ret) {
+		irq_domain_remove(kirq->irqd);
+		return ret;
+	}
 
 	/* clear all source bits */
 	keystone_irq_writel(kirq, ~0x0);
@@ -199,6 +207,8 @@
 	struct keystone_irq_device *kirq = platform_get_drvdata(pdev);
 	int hwirq;
 
+	free_irq(kirq->irq, kirq);
+
 	for (hwirq = 0; hwirq < KEYSTONE_N_IRQ; hwirq++)
 		irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq));
 
--- linux-4.4.0.orig/drivers/irqchip/irq-mips-gic.c
+++ linux-4.4.0/drivers/irqchip/irq-mips-gic.c
@@ -915,8 +915,11 @@
 		gic_len = resource_size(&res);
 	}
 
-	if (mips_cm_present())
+	if (mips_cm_present()) {
 		write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK);
+		/* Ensure GIC region is enabled before trying to access it */
+		__sync();
+	}
 	gic_present = true;
 
 	__gic_init(gic_base, gic_len, cpu_vec, 0, node);
--- linux-4.4.0.orig/drivers/irqchip/irq-mmp.c
+++ linux-4.4.0/drivers/irqchip/irq-mmp.c
@@ -34,6 +34,9 @@
 #define SEL_INT_PENDING		(1 << 6)
 #define SEL_INT_NUM_MASK	0x3f
 
+#define MMP2_ICU_INT_ROUTE_PJ4_IRQ	(1 << 5)
+#define MMP2_ICU_INT_ROUTE_PJ4_FIQ	(1 << 6)
+
 struct icu_chip_data {
 	int			nr_irqs;
 	unsigned int		virq_base;
@@ -190,7 +193,8 @@
 static struct mmp_intc_conf mmp2_conf = {
 	.conf_enable	= 0x20,
 	.conf_disable	= 0x0,
-	.conf_mask	= 0x7f,
+	.conf_mask	= MMP2_ICU_INT_ROUTE_PJ4_IRQ |
+			  MMP2_ICU_INT_ROUTE_PJ4_FIQ,
 };
 
 static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
--- linux-4.4.0.orig/drivers/irqchip/irq-mxs.c
+++ linux-4.4.0/drivers/irqchip/irq-mxs.c
@@ -131,12 +131,16 @@
 	.irq_ack = icoll_ack_irq,
 	.irq_mask = icoll_mask_irq,
 	.irq_unmask = icoll_unmask_irq,
+	.flags = IRQCHIP_MASK_ON_SUSPEND |
+		 IRQCHIP_SKIP_SET_WAKE,
 };
 
 static struct irq_chip asm9260_icoll_chip = {
 	.irq_ack = icoll_ack_irq,
 	.irq_mask = asm9260_mask_irq,
 	.irq_unmask = asm9260_unmask_irq,
+	.flags = IRQCHIP_MASK_ON_SUSPEND |
+		 IRQCHIP_SKIP_SET_WAKE,
 };
 
 asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
@@ -183,7 +187,7 @@
 	void __iomem *icoll_base;
 
 	icoll_base = of_io_request_and_map(np, 0, np->name);
-	if (!icoll_base)
+	if (IS_ERR(icoll_base))
 		panic("%s: unable to map resource", np->full_name);
 	return icoll_base;
 }
@@ -241,6 +245,7 @@
 		writel(0, icoll_priv.intr + i);
 
 	icoll_add_domain(np, ASM9260_NUM_IRQS);
+	set_handle_irq(icoll_handle_irq);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/irqchip/irq-omap-intc.c
+++ linux-4.4.0/drivers/irqchip/irq-omap-intc.c
@@ -47,6 +47,7 @@
 #define INTC_ILR0		0x0100
 
 #define ACTIVEIRQ_MASK		0x7f	/* omap2/3 active interrupt bits */
+#define SPURIOUSIRQ_MASK	(0x1ffffff << 7)
 #define INTCPS_NR_ILR_REGS	128
 #define INTCPS_NR_MIR_REGS	4
 
@@ -330,11 +331,35 @@
 static asmlinkage void __exception_irq_entry
 omap_intc_handle_irq(struct pt_regs *regs)
 {
+	extern unsigned long irq_err_count;
 	u32 irqnr;
 
 	irqnr = intc_readl(INTC_SIR);
+
+	/*
+	 * A spurious IRQ can result if interrupt that triggered the
+	 * sorting is no longer active during the sorting (10 INTC
+	 * functional clock cycles after interrupt assertion). Or a
+	 * change in interrupt mask affected the result during sorting
+	 * time. There is no special handling required except ignoring
+	 * the SIR register value just read and retrying.
+	 * See section 6.2.5 of AM335x TRM Literature Number: SPRUH73K
+	 *
+	 * Many a times, a spurious interrupt situation has been fixed
+	 * by adding a flush for the posted write acking the IRQ in
+	 * the device driver. Typically, this is going be the device
+	 * driver whose interrupt was handled just before the spurious
+	 * IRQ occurred. Pay attention to those device drivers if you
+	 * run into hitting the spurious IRQ condition below.
+	 */
+	if (unlikely((irqnr & SPURIOUSIRQ_MASK) == SPURIOUSIRQ_MASK)) {
+		pr_err_once("%s: spurious irq!\n", __func__);
+		irq_err_count++;
+		omap_ack_irq(NULL);
+		return;
+	}
+
 	irqnr &= ACTIVEIRQ_MASK;
-	WARN_ONCE(!irqnr, "Spurious IRQ ?\n");
 	handle_domain_irq(domain, irqnr, regs);
 }
 
--- linux-4.4.0.orig/drivers/irqchip/irq-sunxi-nmi.c
+++ linux-4.4.0/drivers/irqchip/irq-sunxi-nmi.c
@@ -154,9 +154,9 @@
 
 	gc = irq_get_domain_generic_chip(domain, 0);
 	gc->reg_base = of_io_request_and_map(node, 0, of_node_full_name(node));
-	if (!gc->reg_base) {
+	if (IS_ERR(gc->reg_base)) {
 		pr_err("unable to map resource\n");
-		ret = -ENOMEM;
+		ret = PTR_ERR(gc->reg_base);
 		goto fail_irqd_remove;
 	}
 
--- linux-4.4.0.orig/drivers/irqchip/irq-versatile-fpga.c
+++ linux-4.4.0/drivers/irqchip/irq-versatile-fpga.c
@@ -5,6 +5,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/versatile-fpga.h>
 #include <linux/irqdomain.h>
 #include <linux/module.h>
@@ -67,12 +68,16 @@
 
 static void fpga_irq_handle(struct irq_desc *desc)
 {
+	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct fpga_irq_data *f = irq_desc_get_handler_data(desc);
-	u32 status = readl(f->base + IRQ_STATUS);
+	u32 status;
+
+	chained_irq_enter(chip, desc);
 
+	status = readl(f->base + IRQ_STATUS);
 	if (status == 0) {
 		do_bad_IRQ(desc);
-		return;
+		goto out;
 	}
 
 	do {
@@ -81,6 +86,9 @@
 		status &= ~(1 << irq);
 		generic_handle_irq(irq_find_mapping(f->domain, irq));
 	} while (status);
+
+out:
+	chained_irq_exit(chip, desc);
 }
 
 /*
@@ -203,6 +211,9 @@
 	if (of_property_read_u32(node, "valid-mask", &valid_mask))
 		valid_mask = 0;
 
+	writel(clear_mask, base + IRQ_ENABLE_CLEAR);
+	writel(clear_mask, base + FIQ_ENABLE_CLEAR);
+
 	/* Some chips are cascaded from a parent IRQ */
 	parent_irq = irq_of_parse_and_map(node, 0);
 	if (!parent_irq) {
@@ -217,9 +228,6 @@
 	fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node);
 #endif
 
-	writel(clear_mask, base + IRQ_ENABLE_CLEAR);
-	writel(clear_mask, base + FIQ_ENABLE_CLEAR);
-
 	/*
 	 * On Versatile AB/PB, some secondary interrupts have a direct
 	 * pass-thru to the primary controller for IRQs 20 and 22-31 which need
--- linux-4.4.0.orig/drivers/irqchip/irq-xtensa-mx.c
+++ linux-4.4.0/drivers/irqchip/irq-xtensa-mx.c
@@ -142,7 +142,7 @@
 int __init xtensa_mx_init_legacy(struct device_node *interrupt_parent)
 {
 	struct irq_domain *root_domain =
-		irq_domain_add_legacy(NULL, NR_IRQS, 0, 0,
+		irq_domain_add_legacy(NULL, NR_IRQS - 1, 1, 0,
 				&xtensa_mx_irq_domain_ops,
 				&xtensa_mx_irq_chip);
 	irq_set_default_host(root_domain);
--- linux-4.4.0.orig/drivers/irqchip/irq-xtensa-pic.c
+++ linux-4.4.0/drivers/irqchip/irq-xtensa-pic.c
@@ -89,7 +89,7 @@
 int __init xtensa_pic_init_legacy(struct device_node *interrupt_parent)
 {
 	struct irq_domain *root_domain =
-		irq_domain_add_legacy(NULL, NR_IRQS, 0, 0,
+		irq_domain_add_legacy(NULL, NR_IRQS - 1, 1, 0,
 				&xtensa_irq_domain_ops, &xtensa_irq_chip);
 	irq_set_default_host(root_domain);
 	return 0;
--- linux-4.4.0.orig/drivers/isdn/capi/capi.c
+++ linux-4.4.0/drivers/isdn/capi/capi.c
@@ -687,6 +687,9 @@
 	if (!cdev->ap.applid)
 		return -ENODEV;
 
+	if (count < CAPIMSG_BASELEN)
+		return -EINVAL;
+
 	skb = alloc_skb(count, GFP_USER);
 	if (!skb)
 		return -ENOMEM;
@@ -697,7 +700,8 @@
 	}
 	mlen = CAPIMSG_LEN(skb->data);
 	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
-		if ((size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
+		if (count < CAPI_DATA_B3_REQ_LEN ||
+		    (size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
 			kfree_skb(skb);
 			return -EINVAL;
 		}
@@ -710,6 +714,10 @@
 	CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
 
 	if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
+		if (count < CAPI_DISCONNECT_B3_RESP_LEN) {
+			kfree_skb(skb);
+			return -EINVAL;
+		}
 		mutex_lock(&cdev->lock);
 		capincci_free(cdev, CAPIMSG_NCCI(skb->data));
 		mutex_unlock(&cdev->lock);
--- linux-4.4.0.orig/drivers/isdn/capi/kcapi.c
+++ linux-4.4.0/drivers/isdn/capi/kcapi.c
@@ -564,6 +564,11 @@
 
 	ctr_down(ctr, CAPI_CTR_DETACHED);
 
+	if (ctr->cnr < 1 || ctr->cnr - 1 >= CAPI_MAXCONTR) {
+		err = -EINVAL;
+		goto unlock_out;
+	}
+
 	if (capi_controller[ctr->cnr - 1] != ctr) {
 		err = -EINVAL;
 		goto unlock_out;
@@ -851,7 +856,7 @@
 	u16 ret;
 
 	if (contr == 0) {
-		strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
+		strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
 		return CAPI_NOERROR;
 	}
 
@@ -859,7 +864,7 @@
 
 	ctr = get_capi_ctr_by_nr(contr);
 	if (ctr && ctr->state == CAPI_CTR_RUNNING) {
-		strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
+		strncpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
 		ret = CAPI_NOERROR;
 	} else
 		ret = CAPI_REGNOTINSTALLED;
@@ -1032,6 +1037,7 @@
 						     sizeof(avmb1_carddef))))
 				return -EFAULT;
 			cdef.cardtype = AVM_CARDTYPE_B1;
+			cdef.cardnr = 0;
 		} else {
 			if ((retval = copy_from_user(&cdef, data,
 						     sizeof(avmb1_extcarddef))))
--- linux-4.4.0.orig/drivers/isdn/gigaset/bas-gigaset.c
+++ linux-4.4.0/drivers/isdn/gigaset/bas-gigaset.c
@@ -2317,6 +2317,9 @@
 		return -ENODEV;
 	}
 
+	if (hostif->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	dev_info(&udev->dev,
 		 "%s: Device matched (Vendor: 0x%x, Product: 0x%x)\n",
 		 __func__, le16_to_cpu(udev->descriptor.idVendor),
--- linux-4.4.0.orig/drivers/isdn/gigaset/ser-gigaset.c
+++ linux-4.4.0/drivers/isdn/gigaset/ser-gigaset.c
@@ -373,13 +373,7 @@
 
 static void gigaset_device_release(struct device *dev)
 {
-	struct cardstate *cs = dev_get_drvdata(dev);
-
-	if (!cs)
-		return;
-	dev_set_drvdata(dev, NULL);
-	kfree(cs->hw.ser);
-	cs->hw.ser = NULL;
+	kfree(container_of(dev, struct ser_cardstate, dev.dev));
 }
 
 /*
@@ -408,7 +402,6 @@
 		cs->hw.ser = NULL;
 		return rc;
 	}
-	dev_set_drvdata(&cs->hw.ser->dev.dev, cs);
 
 	tasklet_init(&cs->write_tasklet,
 		     gigaset_modem_fill, (unsigned long) cs);
@@ -762,8 +755,10 @@
 	driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
 				    GIGASET_MODULENAME, GIGASET_DEVNAME,
 				    &ops, THIS_MODULE);
-	if (!driver)
+	if (!driver) {
+		rc = -ENOMEM;
 		goto error;
+	}
 
 	rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc);
 	if (rc != 0) {
--- linux-4.4.0.orig/drivers/isdn/gigaset/usb-gigaset.c
+++ linux-4.4.0/drivers/isdn/gigaset/usb-gigaset.c
@@ -574,8 +574,7 @@
 {
 	struct usb_cardstate *ucs;
 
-	cs->hw.usb = ucs =
-		kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL);
+	cs->hw.usb = ucs = kzalloc(sizeof(struct usb_cardstate), GFP_KERNEL);
 	if (!ucs) {
 		pr_err("out of memory\n");
 		return -ENOMEM;
@@ -587,9 +586,6 @@
 	ucs->bchars[3] = 0;
 	ucs->bchars[4] = 0x11;
 	ucs->bchars[5] = 0x13;
-	ucs->bulk_out_buffer = NULL;
-	ucs->bulk_out_urb = NULL;
-	ucs->read_urb = NULL;
 	tasklet_init(&cs->write_tasklet,
 		     gigaset_modem_fill, (unsigned long) cs);
 
@@ -688,6 +684,11 @@
 		return -ENODEV;
 	}
 
+	if (hostif->desc.bNumEndpoints < 2) {
+		dev_err(&interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
 	dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
 
 	/* allocate memory for our device state and initialize it */
@@ -707,6 +708,12 @@
 
 	endpoint = &hostif->endpoint[0].desc;
 
+	if (!usb_endpoint_is_bulk_out(endpoint)) {
+		dev_err(&interface->dev, "missing bulk-out endpoint\n");
+		retval = -ENODEV;
+		goto error;
+	}
+
 	buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
 	ucs->bulk_out_size = buffer_size;
 	ucs->bulk_out_epnum = usb_endpoint_num(endpoint);
@@ -726,6 +733,12 @@
 
 	endpoint = &hostif->endpoint[1].desc;
 
+	if (!usb_endpoint_is_int_in(endpoint)) {
+		dev_err(&interface->dev, "missing int-in endpoint\n");
+		retval = -ENODEV;
+		goto error;
+	}
+
 	ucs->busy = 0;
 
 	ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL);
--- linux-4.4.0.orig/drivers/isdn/hardware/avm/b1.c
+++ linux-4.4.0/drivers/isdn/hardware/avm/b1.c
@@ -423,7 +423,7 @@
 	int i, j;
 
 	for (j = 0; j < AVM_MAXVERSION; j++)
-		cinfo->version[j] = "\0\0" + 1;
+		cinfo->version[j] = "";
 	for (i = 0, j = 0;
 	     j < AVM_MAXVERSION && i < cinfo->versionlen;
 	     j++, i += cinfo->versionbuf[i] + 1)
--- linux-4.4.0.orig/drivers/isdn/hardware/avm/b1isa.c
+++ linux-4.4.0/drivers/isdn/hardware/avm/b1isa.c
@@ -169,8 +169,8 @@
 static int io[MAX_CARDS];
 static int irq[MAX_CARDS];
 
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
 
--- linux-4.4.0.orig/drivers/isdn/hardware/avm/t1isa.c
+++ linux-4.4.0/drivers/isdn/hardware/avm/t1isa.c
@@ -516,8 +516,8 @@
 static int irq[MAX_CARDS];
 static int cardnr[MAX_CARDS];
 
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param_array(cardnr, int, NULL, 0);
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
--- linux-4.4.0.orig/drivers/isdn/hardware/eicon/diva.c
+++ linux-4.4.0/drivers/isdn/hardware/eicon/diva.c
@@ -387,10 +387,10 @@
 **  Receive and process command from user mode utility
 */
 void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
-			    int length,
+			    int length, void *mptr,
 			    divas_xdi_copy_from_user_fn_t cp_fn)
 {
-	diva_xdi_um_cfg_cmd_t msg;
+	diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr;
 	diva_os_xdi_adapter_t *a = NULL;
 	diva_os_spin_lock_magic_t old_irql;
 	struct list_head *tmp;
@@ -400,21 +400,21 @@
 			 length, sizeof(diva_xdi_um_cfg_cmd_t)))
 			return NULL;
 	}
-	if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
+	if ((*cp_fn) (os_handle, msg, src, sizeof(*msg)) <= 0) {
 		DBG_ERR(("A: A(?) open, write error"))
 			return NULL;
 	}
 	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
 	list_for_each(tmp, &adapter_queue) {
 		a = list_entry(tmp, diva_os_xdi_adapter_t, link);
-		if (a->controller == (int)msg.adapter)
+		if (a->controller == (int)msg->adapter)
 			break;
 		a = NULL;
 	}
 	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
 
 	if (!a) {
-		DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
+		DBG_ERR(("A: A(%d) open, adapter not found", msg->adapter))
 			}
 
 	return (a);
@@ -436,8 +436,10 @@
 
 int
 diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
-	       int length, divas_xdi_copy_from_user_fn_t cp_fn)
+	       int length, void *mptr,
+	       divas_xdi_copy_from_user_fn_t cp_fn)
 {
+	diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr;
 	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
 	void *data;
 
@@ -458,7 +460,13 @@
 			return (-2);
 	}
 
-	length = (*cp_fn) (os_handle, data, src, length);
+	if (msg) {
+		*(diva_xdi_um_cfg_cmd_t *)data = *msg;
+		length = (*cp_fn) (os_handle, (char *)data + sizeof(*msg),
+				   src + sizeof(*msg), length - sizeof(*msg));
+	} else {
+		length = (*cp_fn) (os_handle, data, src, length);
+	}
 	if (length > 0) {
 		if ((*(a->interface.cmd_proc))
 		    (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
--- linux-4.4.0.orig/drivers/isdn/hardware/eicon/diva.h
+++ linux-4.4.0/drivers/isdn/hardware/eicon/diva.h
@@ -19,10 +19,11 @@
 		  int max_length, divas_xdi_copy_to_user_fn_t cp_fn);
 
 int diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
-		   int length, divas_xdi_copy_from_user_fn_t cp_fn);
+		   int length, void *msg,
+		   divas_xdi_copy_from_user_fn_t cp_fn);
 
 void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
-			    int length,
+			    int length, void *msg,
 			    divas_xdi_copy_from_user_fn_t cp_fn);
 
 void diva_xdi_close_adapter(void *adapter, void *os_handle);
--- linux-4.4.0.orig/drivers/isdn/hardware/eicon/divasmain.c
+++ linux-4.4.0/drivers/isdn/hardware/eicon/divasmain.c
@@ -591,19 +591,22 @@
 static ssize_t divas_write(struct file *file, const char __user *buf,
 			   size_t count, loff_t *ppos)
 {
+	diva_xdi_um_cfg_cmd_t msg;
 	int ret = -EINVAL;
 
 	if (!file->private_data) {
 		file->private_data = diva_xdi_open_adapter(file, buf,
-							   count,
+							   count, &msg,
 							   xdi_copy_from_user);
-	}
-	if (!file->private_data) {
-		return (-ENODEV);
+		if (!file->private_data)
+			return (-ENODEV);
+		ret = diva_xdi_write(file->private_data, file,
+				     buf, count, &msg, xdi_copy_from_user);
+	} else {
+		ret = diva_xdi_write(file->private_data, file,
+				     buf, count, NULL, xdi_copy_from_user);
 	}
 
-	ret = diva_xdi_write(file->private_data, file,
-			     buf, count, xdi_copy_from_user);
 	switch (ret) {
 	case -1:		/* Message should be removed from rx mailbox first */
 		ret = -EBUSY;
@@ -622,11 +625,12 @@
 static ssize_t divas_read(struct file *file, char __user *buf,
 			  size_t count, loff_t *ppos)
 {
+	diva_xdi_um_cfg_cmd_t msg;
 	int ret = -EINVAL;
 
 	if (!file->private_data) {
 		file->private_data = diva_xdi_open_adapter(file, buf,
-							   count,
+							   count, &msg,
 							   xdi_copy_from_user);
 	}
 	if (!file->private_data) {
--- linux-4.4.0.orig/drivers/isdn/hardware/eicon/message.c
+++ linux-4.4.0/drivers/isdn/hardware/eicon/message.c
@@ -147,7 +147,7 @@
 static void listen_check(DIVA_CAPI_ADAPTER *);
 static byte AddInfo(byte **, byte **, byte *, byte *);
 static byte getChannel(API_PARSE *);
-static void IndParse(PLCI *, word *, byte **, byte);
+static void IndParse(PLCI *, const word *, byte **, byte);
 static byte ie_compare(byte *, byte *);
 static word find_cip(DIVA_CAPI_ADAPTER *, byte *, byte *);
 static word CPN_filter_ok(byte *cpn, DIVA_CAPI_ADAPTER *, word);
@@ -4860,7 +4860,7 @@
 	/* included before the ESC_MSGTYPE and MAXPARMSIDS has to be incremented */
 	/* SMSG is situated at the end because its 0 (for compatibility reasons */
 	/* (see Info_Mask Bit 4, first IE. then the message type)           */
-	word parms_id[] =
+	static const word parms_id[] =
 		{MAXPARMSIDS, CPN, 0xff, DSA, OSA, BC, LLC, HLC, ESC_CAUSE, DSP, DT, CHA,
 		 UUI, CONG_RR, CONG_RNR, ESC_CHI, KEY, CHI, CAU, ESC_LAW,
 		 RDN, RDX, CONN_NR, RIN, NI, CAI, ESC_CR,
@@ -4868,12 +4868,12 @@
 	/* 14 FTY repl by ESC_CHI */
 	/* 18 PI  repl by ESC_LAW */
 	/* removed OAD changed to 0xff for future use, OAD is multiIE now */
-	word multi_fac_id[] = {1, FTY};
-	word multi_pi_id[]  = {1, PI};
-	word multi_CiPN_id[]  = {1, OAD};
-	word multi_ssext_id[]  = {1, ESC_SSEXT};
+	static const word multi_fac_id[] = {1, FTY};
+	static const word multi_pi_id[]  = {1, PI};
+	static const word multi_CiPN_id[]  = {1, OAD};
+	static const word multi_ssext_id[]  = {1, ESC_SSEXT};
 
-	word multi_vswitch_id[]  = {1, ESC_VSWITCH};
+	static const word multi_vswitch_id[]  = {1, ESC_VSWITCH};
 
 	byte *cau;
 	word ncci;
@@ -8926,7 +8926,7 @@
 /* functions for all parameters sent in INDs                        */
 /*------------------------------------------------------------------*/
 
-static void IndParse(PLCI *plci, word *parms_id, byte **parms, byte multiIEsize)
+static void IndParse(PLCI *plci, const word *parms_id, byte **parms, byte multiIEsize)
 {
 	word ploc;            /* points to current location within packet */
 	byte w;
@@ -11304,7 +11304,8 @@
 				((CAPI_MSG *) msg)->header.ncci = 0;
 				((CAPI_MSG *) msg)->info.facility_req.Selector = SELECTOR_LINE_INTERCONNECT;
 				((CAPI_MSG *) msg)->info.facility_req.structs[0] = 3;
-				PUT_WORD(&(((CAPI_MSG *) msg)->info.facility_req.structs[1]), LI_REQ_SILENT_UPDATE);
+				((CAPI_MSG *) msg)->info.facility_req.structs[1] = LI_REQ_SILENT_UPDATE & 0xff;
+				((CAPI_MSG *) msg)->info.facility_req.structs[2] = LI_REQ_SILENT_UPDATE >> 8;
 				((CAPI_MSG *) msg)->info.facility_req.structs[3] = 0;
 				w = api_put(notify_plci->appl, (CAPI_MSG *) msg);
 				if (w != _QUEUE_FULL)
--- linux-4.4.0.orig/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ linux-4.4.0/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -1945,7 +1945,7 @@
 static void
 hfcmulti_tx(struct hfc_multi *hc, int ch)
 {
-	int i, ii, temp, len = 0;
+	int i, ii, temp, tmp_len, len = 0;
 	int Zspace, z1, z2; /* must be int for calculation */
 	int Fspace, f1, f2;
 	u_char *d;
@@ -2166,14 +2166,15 @@
 		HFC_wait_nodebug(hc);
 	}
 
+	tmp_len = (*sp)->len;
 	dev_kfree_skb(*sp);
 	/* check for next frame */
 	if (bch && get_next_bframe(bch)) {
-		len = (*sp)->len;
+		len = tmp_len;
 		goto next_frame;
 	}
 	if (dch && get_next_dframe(dch)) {
-		len = (*sp)->len;
+		len = tmp_len;
 		goto next_frame;
 	}
 
@@ -4370,7 +4371,8 @@
 	if (m->clock2)
 		test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip);
 
-	if (ent->device == 0xB410) {
+	if (ent->vendor == PCI_VENDOR_ID_DIGIUM &&
+	    ent->device == PCI_DEVICE_ID_DIGIUM_HFC4S) {
 		test_and_set_bit(HFC_CHIP_B410P, &hc->chip);
 		test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip);
 		test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
--- linux-4.4.0.orig/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ linux-4.4.0/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1402,6 +1402,7 @@
 				printk(KERN_DEBUG
 				       "%s: %s: alloc urb for fifo %i failed",
 				       hw->name, __func__, fifo->fifonum);
+				continue;
 			}
 			fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
 			fifo->iso[i].indx = i;
@@ -1700,13 +1701,23 @@
 static int
 setup_hfcsusb(struct hfcsusb *hw)
 {
+	void *dmabuf = kmalloc(sizeof(u_char), GFP_KERNEL);
 	u_char b;
+	int ret;
 
 	if (debug & DBG_HFC_CALL_TRACE)
 		printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
 
+	if (!dmabuf)
+		return -ENOMEM;
+
+	ret = read_reg_atomic(hw, HFCUSB_CHIP_ID, dmabuf);
+
+	memcpy(&b, dmabuf, sizeof(u_char));
+	kfree(dmabuf);
+
 	/* check the chip id */
-	if (read_reg_atomic(hw, HFCUSB_CHIP_ID, &b) != 1) {
+	if (ret != 1) {
 		printk(KERN_DEBUG "%s: %s: cannot read chip id\n",
 		       hw->name, __func__);
 		return 1;
@@ -1963,6 +1974,9 @@
 
 				/* get endpoint base */
 				idx = ((ep_addr & 0x7f) - 1) * 2;
+				if (idx > 15)
+					return -EIO;
+
 				if (ep_addr & 0x80)
 					idx++;
 				attr = ep->desc.bmAttributes;
--- linux-4.4.0.orig/drivers/isdn/hisax/config.c
+++ linux-4.4.0/drivers/isdn/hisax/config.c
@@ -350,13 +350,13 @@
 MODULE_LICENSE("GPL");
 module_param_array(type, int, NULL, 0);
 module_param_array(protocol, int, NULL, 0);
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
+module_param_hw_array(mem, int, iomem, NULL, 0);
 module_param(id, charp, 0);
 #ifdef IO0_IO1
-module_param_array(io0, int, NULL, 0);
-module_param_array(io1, int, NULL, 0);
+module_param_hw_array(io0, int, ioport, NULL, 0);
+module_param_hw_array(io1, int, ioport, NULL, 0);
 #endif
 #endif /* MODULE */
 
--- linux-4.4.0.orig/drivers/isdn/hisax/hfc_pci.c
+++ linux-4.4.0/drivers/isdn/hisax/hfc_pci.c
@@ -1169,11 +1169,13 @@
 		if (cs->debug & L1_DEB_LAPD)
 			debugl1(cs, "-> PH_REQUEST_PULL");
 #endif
+		spin_lock_irqsave(&cs->lock, flags);
 		if (!cs->tx_skb) {
 			test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 		} else
 			test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+		spin_unlock_irqrestore(&cs->lock, flags);
 		break;
 	case (HW_RESET | REQUEST):
 		spin_lock_irqsave(&cs->lock, flags);
--- linux-4.4.0.orig/drivers/isdn/i4l/isdn_common.c
+++ linux-4.4.0/drivers/isdn/i4l/isdn_common.c
@@ -1379,6 +1379,7 @@
 			if (arg) {
 				if (copy_from_user(bname, argp, sizeof(bname) - 1))
 					return -EFAULT;
+				bname[sizeof(bname)-1] = 0;
 			} else
 				return -EINVAL;
 			ret = mutex_lock_interruptible(&dev->mtx);
@@ -1654,13 +1655,7 @@
 			} else
 				return -EINVAL;
 		case IIOCDBGVAR:
-			if (arg) {
-				if (copy_to_user(argp, &dev, sizeof(ulong)))
-					return -EFAULT;
-				return 0;
-			} else
-				return -EINVAL;
-			break;
+			return -EINVAL;
 		default:
 			if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
 				cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
--- linux-4.4.0.orig/drivers/isdn/i4l/isdn_net.c
+++ linux-4.4.0/drivers/isdn/i4l/isdn_net.c
@@ -2611,10 +2611,9 @@
 	char newname[10];
 
 	if (p) {
-		/* Slave-Name MUST not be empty */
-		if (!strlen(p + 1))
+		/* Slave-Name MUST not be empty or overflow 'newname' */
+		if (strscpy(newname, p + 1, sizeof(newname)) <= 0)
 			return NULL;
-		strcpy(newname, p + 1);
 		*p = 0;
 		/* Master must already exist */
 		if (!(n = isdn_net_findif(parm)))
--- linux-4.4.0.orig/drivers/isdn/i4l/isdn_ppp.c
+++ linux-4.4.0/drivers/isdn/i4l/isdn_ppp.c
@@ -828,7 +828,6 @@
 	isdn_net_local *lp;
 	struct ippp_struct *is;
 	int proto;
-	unsigned char protobuf[4];
 
 	is = file->private_data;
 
@@ -842,24 +841,28 @@
 	if (!lp)
 		printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
 	else {
-		/*
-		 * Don't reset huptimer for
-		 * LCP packets. (Echo requests).
-		 */
-		if (copy_from_user(protobuf, buf, 4))
-			return -EFAULT;
-		proto = PPP_PROTOCOL(protobuf);
-		if (proto != PPP_LCP)
-			lp->huptimer = 0;
+		if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
+			unsigned char protobuf[4];
+			/*
+			 * Don't reset huptimer for
+			 * LCP packets. (Echo requests).
+			 */
+			if (copy_from_user(protobuf, buf, 4))
+				return -EFAULT;
+
+			proto = PPP_PROTOCOL(protobuf);
+			if (proto != PPP_LCP)
+				lp->huptimer = 0;
 
-		if (lp->isdn_device < 0 || lp->isdn_channel < 0)
 			return 0;
+		}
 
 		if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
 		    lp->dialstate == 0 &&
 		    (lp->flags & ISDN_NET_CONNECTED)) {
 			unsigned short hl;
 			struct sk_buff *skb;
+			unsigned char *cpy_buf;
 			/*
 			 * we need to reserve enough space in front of
 			 * sk_buff. old call to dev_alloc_skb only reserved
@@ -872,11 +875,21 @@
 				return count;
 			}
 			skb_reserve(skb, hl);
-			if (copy_from_user(skb_put(skb, count), buf, count))
+			cpy_buf = skb_put(skb, count);
+			if (copy_from_user(cpy_buf, buf, count))
 			{
 				kfree_skb(skb);
 				return -EFAULT;
 			}
+
+			/*
+			 * Don't reset huptimer for
+			 * LCP packets. (Echo requests).
+			 */
+			proto = PPP_PROTOCOL(cpy_buf);
+			if (proto != PPP_LCP)
+				lp->huptimer = 0;
+
 			if (is->debug & 0x40) {
 				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
 				isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
@@ -2364,7 +2377,7 @@
 		       id);
 		return NULL;
 	} else {
-		rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
+		rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_ATOMIC);
 		if (!rs)
 			return NULL;
 		rs->state = CCPResetIdle;
--- linux-4.4.0.orig/drivers/isdn/i4l/isdn_tty.c
+++ linux-4.4.0/drivers/isdn/i4l/isdn_tty.c
@@ -786,7 +786,7 @@
 		cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
 		cmd.parm.cmsg.para[4] = 0;
 		cmd.parm.cmsg.para[5] = l;
-		strncpy(&cmd.parm.cmsg.para[6], id, l);
+		strscpy(&cmd.parm.cmsg.para[6], id, l);
 		cmd.command = CAPI_PUT_MESSAGE;
 		cmd.driver = info->isdn_driver;
 		cmd.arg = info->isdn_channel;
@@ -1459,15 +1459,19 @@
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 
+	mutex_lock(&modem_info_mutex);
 	if (!old_termios)
 		isdn_tty_change_speed(info);
 	else {
 		if (tty->termios.c_cflag == old_termios->c_cflag &&
 		    tty->termios.c_ispeed == old_termios->c_ispeed &&
-		    tty->termios.c_ospeed == old_termios->c_ospeed)
+		    tty->termios.c_ospeed == old_termios->c_ospeed) {
+			mutex_unlock(&modem_info_mutex);
 			return;
+		}
 		isdn_tty_change_speed(info);
 	}
+	mutex_unlock(&modem_info_mutex);
 }
 
 /*
--- linux-4.4.0.orig/drivers/isdn/icn/icn.c
+++ linux-4.4.0/drivers/isdn/icn/icn.c
@@ -718,7 +718,7 @@
 			return 0;
 		if (card->sndcount[channel] > ICN_MAX_SQUEUE)
 			return 0;
-#warning TODO test headroom or use skb->nb to flag ACK
+		/* TODO test headroom or use skb->nb to flag ACK */
 		nskb = skb_clone(skb, GFP_ATOMIC);
 		if (nskb) {
 			/* Push ACK flag as one
--- linux-4.4.0.orig/drivers/isdn/mISDN/Kconfig
+++ linux-4.4.0/drivers/isdn/mISDN/Kconfig
@@ -12,6 +12,7 @@
 config MISDN_DSP
 	tristate "Digital Audio Processing of transparent data"
 	depends on MISDN
+	select BITREVERSE
 	help
 	  Enable support for digital audio processing capability.
 
--- linux-4.4.0.orig/drivers/isdn/mISDN/dsp_pipeline.c
+++ linux-4.4.0/drivers/isdn/mISDN/dsp_pipeline.c
@@ -236,7 +236,7 @@
 int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
 {
 	int incomplete = 0, found = 0;
-	char *dup, *tok, *name, *args;
+	char *dup, *next, *tok, *name, *args;
 	struct dsp_element_entry *entry, *n;
 	struct dsp_pipeline_entry *pipeline_entry;
 	struct mISDN_dsp_element *elem;
@@ -247,10 +247,10 @@
 	if (!list_empty(&pipeline->list))
 		_dsp_pipeline_destroy(pipeline);
 
-	dup = kstrdup(cfg, GFP_ATOMIC);
+	dup = next = kstrdup(cfg, GFP_ATOMIC);
 	if (!dup)
 		return 0;
-	while ((tok = strsep(&dup, "|"))) {
+	while ((tok = strsep(&next, "|"))) {
 		if (!strlen(tok))
 			continue;
 		name = strsep(&tok, "(");
--- linux-4.4.0.orig/drivers/isdn/mISDN/l1oip.h
+++ linux-4.4.0/drivers/isdn/mISDN/l1oip.h
@@ -58,6 +58,7 @@
 	int			bundle;		/* bundle channels in one frm */
 	int			codec;		/* codec to use for transmis. */
 	int			limit;		/* limit number of bchannels */
+	bool			shutdown;	/* if card is released */
 
 	/* timer */
 	struct timer_list	keep_tl;
--- linux-4.4.0.orig/drivers/isdn/mISDN/l1oip_core.c
+++ linux-4.4.0/drivers/isdn/mISDN/l1oip_core.c
@@ -287,7 +287,7 @@
 	p = frame;
 
 	/* restart timer */
-	if (time_before(hc->keep_tl.expires, jiffies + 5 * HZ))
+	if (time_before(hc->keep_tl.expires, jiffies + 5 * HZ) && !hc->shutdown)
 		mod_timer(&hc->keep_tl, jiffies + L1OIP_KEEPALIVE * HZ);
 	else
 		hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE * HZ;
@@ -619,7 +619,9 @@
 		goto multiframe;
 
 	/* restart timer */
-	if (time_before(hc->timeout_tl.expires, jiffies + 5 * HZ) || !hc->timeout_on) {
+	if ((time_before(hc->timeout_tl.expires, jiffies + 5 * HZ) ||
+	     !hc->timeout_on) &&
+	    !hc->shutdown) {
 		hc->timeout_on = 1;
 		mod_timer(&hc->timeout_tl, jiffies + L1OIP_TIMEOUT * HZ);
 	} else /* only adjust timer */
@@ -1246,11 +1248,10 @@
 {
 	int	ch;
 
-	if (timer_pending(&hc->keep_tl))
-		del_timer(&hc->keep_tl);
+	hc->shutdown = true;
 
-	if (timer_pending(&hc->timeout_tl))
-		del_timer(&hc->timeout_tl);
+	del_timer_sync(&hc->keep_tl);
+	del_timer_sync(&hc->timeout_tl);
 
 	cancel_work_sync(&hc->workq);
 
--- linux-4.4.0.orig/drivers/isdn/mISDN/socket.c
+++ linux-4.4.0/drivers/isdn/mISDN/socket.c
@@ -394,7 +394,7 @@
 			memcpy(di.channelmap, dev->channelmap,
 			       sizeof(di.channelmap));
 			di.nrbchan = dev->nrbchan;
-			strcpy(di.name, dev_name(&dev->dev));
+			strscpy(di.name, dev_name(&dev->dev), sizeof(di.name));
 			if (copy_to_user((void __user *)arg, &di, sizeof(di)))
 				err = -EFAULT;
 		} else
@@ -678,7 +678,7 @@
 			memcpy(di.channelmap, dev->channelmap,
 			       sizeof(di.channelmap));
 			di.nrbchan = dev->nrbchan;
-			strcpy(di.name, dev_name(&dev->dev));
+			strscpy(di.name, dev_name(&dev->dev), sizeof(di.name));
 			if (copy_to_user((void __user *)arg, &di, sizeof(di)))
 				err = -EFAULT;
 		} else
@@ -692,6 +692,7 @@
 			err = -EFAULT;
 			break;
 		}
+		dn.name[sizeof(dn.name) - 1] = '\0';
 		dev = get_mdevice(dn.id);
 		if (dev)
 			err = device_rename(&dev->dev, dn.name);
@@ -762,6 +763,8 @@
 
 	if (sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
+	if (!capable(CAP_NET_RAW))
+		return -EPERM;
 
 	sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
 	if (!sk)
--- linux-4.4.0.orig/drivers/isdn/mISDN/stack.c
+++ linux-4.4.0/drivers/isdn/mISDN/stack.c
@@ -72,7 +72,7 @@
 		if (sk->sk_state != MISDN_BOUND)
 			continue;
 		if (!cskb)
-			cskb = skb_copy(skb, GFP_KERNEL);
+			cskb = skb_copy(skb, GFP_ATOMIC);
 		if (!cskb) {
 			printk(KERN_WARNING "%s no skb\n", __func__);
 			break;
--- linux-4.4.0.orig/drivers/isdn/mISDN/tei.c
+++ linux-4.4.0/drivers/isdn/mISDN/tei.c
@@ -1180,8 +1180,7 @@
 ctrl_teimanager(struct manager *mgr, void *arg)
 {
 	/* currently we only have one option */
-	int	*val = (int *)arg;
-	int	ret = 0;
+	unsigned int *val = (unsigned int *)arg;
 
 	switch (val[0]) {
 	case IMCLEAR_L2:
@@ -1197,9 +1196,9 @@
 			test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
 		break;
 	default:
-		ret = -EINVAL;
+		return -EINVAL;
 	}
-	return ret;
+	return 0;
 }
 
 /* This function does create a L2 for fixed TEI in NT Mode */
--- linux-4.4.0.orig/drivers/isdn/mISDN/timerdev.c
+++ linux-4.4.0/drivers/isdn/mISDN/timerdev.c
@@ -168,8 +168,8 @@
 	spin_lock_irqsave(&timer->dev->lock, flags);
 	if (timer->id >= 0)
 		list_move_tail(&timer->list, &timer->dev->expired);
-	spin_unlock_irqrestore(&timer->dev->lock, flags);
 	wake_up_interruptible(&timer->dev->wait);
+	spin_unlock_irqrestore(&timer->dev->lock, flags);
 }
 
 static int
--- linux-4.4.0.orig/drivers/isdn/sc/init.c
+++ linux-4.4.0/drivers/isdn/sc/init.c
@@ -441,6 +441,7 @@
 	RspMessage rcvmsg;
 	ReqMessage sndmsg;
 	HWConfig_pl hwci;
+	void __iomem *rambase_sig = (void __iomem *)rambase + SIG_OFFSET;
 	int x;
 
 	pr_debug("Attempting to identify adapter @ 0x%lx io 0x%x\n",
@@ -481,7 +482,7 @@
 	 */
 	outb(PRI_BASEPG_VAL, pgport);
 	msleep_interruptible(1000);
-	sig = readl(rambase + SIG_OFFSET);
+	sig = readl(rambase_sig);
 	pr_debug("Looking for a signature, got 0x%lx\n", sig);
 	if (sig == SIGNATURE)
 		return PRI_BOARD;
@@ -491,7 +492,7 @@
 	 */
 	outb(BRI_BASEPG_VAL, pgport);
 	msleep_interruptible(1000);
-	sig = readl(rambase + SIG_OFFSET);
+	sig = readl(rambase_sig);
 	pr_debug("Looking for a signature, got 0x%lx\n", sig);
 	if (sig == SIGNATURE)
 		return BRI_BOARD;
@@ -501,7 +502,7 @@
 	/*
 	 * Try to spot a card
 	 */
-	sig = readl(rambase + SIG_OFFSET);
+	sig = readl(rambase_sig);
 	pr_debug("Looking for a signature, got 0x%lx\n", sig);
 	if (sig != SIGNATURE)
 		return -1;
--- linux-4.4.0.orig/drivers/leds/Kconfig
+++ linux-4.4.0/drivers/leds/Kconfig
@@ -230,7 +230,6 @@
 	tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
 	depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501
 	select FW_LOADER
-	select FW_LOADER_USER_HELPER
 	help
 	  This option supports common operations for LP5521/5523/55231/5562/8501
 	  devices.
--- linux-4.4.0.orig/drivers/leds/led-class.c
+++ linux-4.4.0/drivers/leds/led-class.c
@@ -247,12 +247,13 @@
 	up_write(&led_cdev->trigger_lock);
 #endif
 
-	cancel_work_sync(&led_cdev->set_brightness_work);
-
 	/* Stop blinking */
 	led_stop_software_blink(led_cdev);
+
 	led_set_brightness(led_cdev, LED_OFF);
 
+	flush_work(&led_cdev->set_brightness_work);
+
 	device_unregister(led_cdev->dev);
 
 	down_write(&leds_list_lock);
--- linux-4.4.0.orig/drivers/leds/led-triggers.c
+++ linux-4.4.0/drivers/leds/led-triggers.c
@@ -88,21 +88,23 @@
 	down_read(&led_cdev->trigger_lock);
 
 	if (!led_cdev->trigger)
-		len += sprintf(buf+len, "[none] ");
+		len += scnprintf(buf+len, PAGE_SIZE - len, "[none] ");
 	else
-		len += sprintf(buf+len, "none ");
+		len += scnprintf(buf+len, PAGE_SIZE - len, "none ");
 
 	list_for_each_entry(trig, &trigger_list, next_trig) {
 		if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
 							trig->name))
-			len += sprintf(buf+len, "[%s] ", trig->name);
+			len += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ",
+					 trig->name);
 		else
-			len += sprintf(buf+len, "%s ", trig->name);
+			len += scnprintf(buf+len, PAGE_SIZE - len, "%s ",
+					 trig->name);
 	}
 	up_read(&led_cdev->trigger_lock);
 	up_read(&triggers_list_lock);
 
-	len += sprintf(len+buf, "\n");
+	len += scnprintf(len+buf, PAGE_SIZE - len, "\n");
 	return len;
 }
 EXPORT_SYMBOL_GPL(led_trigger_show);
--- linux-4.4.0.orig/drivers/leds/leds-bcm6328.c
+++ linux-4.4.0/drivers/leds/leds-bcm6328.c
@@ -325,7 +325,7 @@
 	led->cdev.brightness_set = bcm6328_led_set;
 	led->cdev.blink_set = bcm6328_blink_set;
 
-	rc = led_classdev_register(dev, &led->cdev);
+	rc = devm_led_classdev_register(dev, &led->cdev);
 	if (rc < 0)
 		return rc;
 
--- linux-4.4.0.orig/drivers/leds/leds-bcm6358.c
+++ linux-4.4.0/drivers/leds/leds-bcm6358.c
@@ -146,7 +146,7 @@
 
 	led->cdev.brightness_set = bcm6358_led_set;
 
-	rc = led_classdev_register(dev, &led->cdev);
+	rc = devm_led_classdev_register(dev, &led->cdev);
 	if (rc < 0)
 		return rc;
 
--- linux-4.4.0.orig/drivers/leds/leds-gpio.c
+++ linux-4.4.0/drivers/leds/leds-gpio.c
@@ -118,8 +118,8 @@
 			return ret;
 
 		led_dat->gpiod = gpio_to_desc(template->gpio);
-		if (IS_ERR(led_dat->gpiod))
-			return PTR_ERR(led_dat->gpiod);
+		if (!led_dat->gpiod)
+			return -EINVAL;
 	}
 
 	led_dat->cdev.name = template->name;
--- linux-4.4.0.orig/drivers/leds/leds-ktd2692.c
+++ linux-4.4.0/drivers/leds/leds-ktd2692.c
@@ -296,15 +296,15 @@
 		return -ENXIO;
 
 	led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
-	if (IS_ERR(led->ctrl_gpio)) {
-		ret = PTR_ERR(led->ctrl_gpio);
+	ret = PTR_ERR_OR_ZERO(led->ctrl_gpio);
+	if (ret) {
 		dev_err(dev, "cannot get ctrl-gpios %d\n", ret);
 		return ret;
 	}
 
 	led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS);
-	if (IS_ERR(led->aux_gpio)) {
-		ret = PTR_ERR(led->aux_gpio);
+	ret = PTR_ERR_OR_ZERO(led->aux_gpio);
+	if (ret) {
 		dev_err(dev, "cannot get aux-gpios %d\n", ret);
 		return ret;
 	}
--- linux-4.4.0.orig/drivers/leds/leds-lm355x.c
+++ linux-4.4.0/drivers/leds/leds-lm355x.c
@@ -177,18 +177,19 @@
 	/* input and output pins configuration */
 	switch (chip->type) {
 	case CHIP_LM3554:
-		reg_val = pdata->pin_tx2 | pdata->ntc_pin;
+		reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin;
 		ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val);
 		if (ret < 0)
 			goto out;
-		reg_val = pdata->pass_mode;
+		reg_val = (u32)pdata->pass_mode;
 		ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val);
 		if (ret < 0)
 			goto out;
 		break;
 
 	case CHIP_LM3556:
-		reg_val = pdata->pin_tx2 | pdata->ntc_pin | pdata->pass_mode;
+		reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin |
+		          (u32)pdata->pass_mode;
 		ret = regmap_update_bits(chip->regmap, 0x0A, 0xC4, reg_val);
 		if (ret < 0)
 			goto out;
--- linux-4.4.0.orig/drivers/leds/leds-lp5523.c
+++ linux-4.4.0/drivers/leds/leds-lp5523.c
@@ -318,7 +318,9 @@
 
 	/* Let the programs run for couple of ms and check the engine status */
 	usleep_range(3000, 6000);
-	lp55xx_read(chip, LP5523_REG_STATUS, &status);
+	ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
+	if (ret)
+		return ret;
 	status &= LP5523_ENG_STATUS_MASK;
 
 	if (status != LP5523_ENG_STATUS_MASK) {
--- linux-4.4.0.orig/drivers/leds/leds-lp5562.c
+++ linux-4.4.0/drivers/leds/leds-lp5562.c
@@ -263,7 +263,11 @@
 {
 	const struct firmware *fw = chip->fw;
 
-	if (fw->size > LP5562_PROGRAM_LENGTH) {
+	/*
+	 * the firmware is encoded in ascii hex character, with 2 chars
+	 * per byte
+	 */
+	if (fw->size > (LP5562_PROGRAM_LENGTH * 2)) {
 		dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
 			fw->size);
 		return;
--- linux-4.4.0.orig/drivers/leds/leds-lp55xx-common.c
+++ linux-4.4.0/drivers/leds/leds-lp55xx-common.c
@@ -200,7 +200,7 @@
 
 	if (!fw) {
 		dev_err(dev, "firmware request failed\n");
-		goto out;
+		return;
 	}
 
 	/* handling firmware data is chip dependent */
@@ -213,9 +213,9 @@
 
 	mutex_unlock(&chip->lock);
 
-out:
 	/* firmware should be released for other channel use */
 	release_firmware(chip->fw);
+	chip->fw = NULL;
 }
 
 static int lp55xx_request_firmware(struct lp55xx_chip *chip)
--- linux-4.4.0.orig/drivers/leds/leds-pca955x.c
+++ linux-4.4.0/drivers/leds/leds-pca955x.c
@@ -281,7 +281,7 @@
 			"slave address 0x%02x\n",
 			id->name, chip->bits, client->addr);
 
-	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
 
 	if (pdata) {
--- linux-4.4.0.orig/drivers/leds/leds-pwm.c
+++ linux-4.4.0/drivers/leds/leds-pwm.c
@@ -132,6 +132,7 @@
 	ret = led_classdev_register(dev, &led_data->cdev);
 	if (ret == 0) {
 		priv->num_leds++;
+		led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
 	} else {
 		dev_err(dev, "failed to register PWM led for %s: %d\n",
 			led->name, ret);
--- linux-4.4.0.orig/drivers/lightnvm/Kconfig
+++ linux-4.4.0/drivers/lightnvm/Kconfig
@@ -4,7 +4,7 @@
 
 menuconfig NVM
 	bool "Open-Channel SSD target support"
-	depends on BLOCK
+	depends on BLOCK && BROKEN
 	help
 	  Say Y here to get to enable Open-channel SSDs.
 
--- linux-4.4.0.orig/drivers/lightnvm/Makefile
+++ linux-4.4.0/drivers/lightnvm/Makefile
@@ -2,6 +2,6 @@
 # Makefile for Open-Channel SSDs.
 #
 
-obj-$(CONFIG_NVM)		:= core.o
+obj-$(CONFIG_NVM)		:= core.o sysblk.o
 obj-$(CONFIG_NVM_GENNVM) 	+= gennvm.o
 obj-$(CONFIG_NVM_RRPC)		+= rrpc.o
--- linux-4.4.0.orig/drivers/lightnvm/core.c
+++ linux-4.4.0/drivers/lightnvm/core.c
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/miscdevice.h>
 #include <linux/lightnvm.h>
+#include <linux/sched/sysctl.h>
 #include <uapi/linux/lightnvm.h>
 
 static LIST_HEAD(nvm_targets);
@@ -105,6 +106,9 @@
 	lockdep_assert_held(&nvm_lock);
 
 	list_for_each_entry(mt, &nvm_mgrs, list) {
+		if (strncmp(dev->sb.mmtype, mt->name, NVM_MMTYPE_LEN))
+			continue;
+
 		ret = mt->register_mgr(dev);
 		if (ret < 0) {
 			pr_err("nvm: media mgr failed to init (%d) on dev %s\n",
@@ -166,6 +170,20 @@
 	return NULL;
 }
 
+struct nvm_block *nvm_get_blk_unlocked(struct nvm_dev *dev, struct nvm_lun *lun,
+							unsigned long flags)
+{
+	return dev->mt->get_blk_unlocked(dev, lun, flags);
+}
+EXPORT_SYMBOL(nvm_get_blk_unlocked);
+
+/* Assumes that all valid pages have already been moved on release to bm */
+void nvm_put_blk_unlocked(struct nvm_dev *dev, struct nvm_block *blk)
+{
+	return dev->mt->put_blk_unlocked(dev, blk);
+}
+EXPORT_SYMBOL(nvm_put_blk_unlocked);
+
 struct nvm_block *nvm_get_blk(struct nvm_dev *dev, struct nvm_lun *lun,
 							unsigned long flags)
 {
@@ -192,6 +210,206 @@
 }
 EXPORT_SYMBOL(nvm_erase_blk);
 
+void nvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
+{
+	int i;
+
+	if (rqd->nr_pages > 1) {
+		for (i = 0; i < rqd->nr_pages; i++)
+			rqd->ppa_list[i] = dev_to_generic_addr(dev,
+							rqd->ppa_list[i]);
+	} else {
+		rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr);
+	}
+}
+EXPORT_SYMBOL(nvm_addr_to_generic_mode);
+
+void nvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
+{
+	int i;
+
+	if (rqd->nr_pages > 1) {
+		for (i = 0; i < rqd->nr_pages; i++)
+			rqd->ppa_list[i] = generic_to_dev_addr(dev,
+							rqd->ppa_list[i]);
+	} else {
+		rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr);
+	}
+}
+EXPORT_SYMBOL(nvm_generic_to_addr_mode);
+
+int nvm_set_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd,
+					struct ppa_addr *ppas, int nr_ppas)
+{
+	int i, plane_cnt, pl_idx;
+
+	if (dev->plane_mode == NVM_PLANE_SINGLE && nr_ppas == 1) {
+		rqd->nr_pages = 1;
+		rqd->ppa_addr = ppas[0];
+
+		return 0;
+	}
+
+	plane_cnt = (1 << dev->plane_mode);
+	rqd->nr_pages = plane_cnt * nr_ppas;
+
+	if (dev->ops->max_phys_sect < rqd->nr_pages)
+		return -EINVAL;
+
+	rqd->ppa_list = nvm_dev_dma_alloc(dev, GFP_KERNEL, &rqd->dma_ppa_list);
+	if (!rqd->ppa_list) {
+		pr_err("nvm: failed to allocate dma memory\n");
+		return -ENOMEM;
+	}
+
+	for (pl_idx = 0; pl_idx < plane_cnt; pl_idx++) {
+		for (i = 0; i < nr_ppas; i++) {
+			ppas[i].g.pl = pl_idx;
+			rqd->ppa_list[(pl_idx * nr_ppas) + i] = ppas[i];
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(nvm_set_rqd_ppalist);
+
+void nvm_free_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd)
+{
+	if (!rqd->ppa_list)
+		return;
+
+	nvm_dev_dma_free(dev, rqd->ppa_list, rqd->dma_ppa_list);
+}
+EXPORT_SYMBOL(nvm_free_rqd_ppalist);
+
+int nvm_erase_ppa(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas)
+{
+	struct nvm_rq rqd;
+	int ret;
+
+	if (!dev->ops->erase_block)
+		return 0;
+
+	memset(&rqd, 0, sizeof(struct nvm_rq));
+
+	ret = nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas);
+	if (ret)
+		return ret;
+
+	nvm_generic_to_addr_mode(dev, &rqd);
+
+	ret = dev->ops->erase_block(dev, &rqd);
+
+	nvm_free_rqd_ppalist(dev, &rqd);
+
+	return ret;
+}
+EXPORT_SYMBOL(nvm_erase_ppa);
+
+void nvm_end_io(struct nvm_rq *rqd, int error)
+{
+	rqd->error = error;
+	rqd->end_io(rqd);
+}
+EXPORT_SYMBOL(nvm_end_io);
+
+static void nvm_end_io_sync(struct nvm_rq *rqd)
+{
+	struct completion *waiting = rqd->wait;
+
+	rqd->wait = NULL;
+
+	complete(waiting);
+}
+
+int nvm_submit_ppa(struct nvm_dev *dev, struct ppa_addr *ppa, int nr_ppas,
+				int opcode, int flags, void *buf, int len)
+{
+	DECLARE_COMPLETION_ONSTACK(wait);
+	struct nvm_rq rqd;
+	struct bio *bio;
+	int ret;
+	unsigned long hang_check;
+
+	bio = bio_map_kern(dev->q, buf, len, GFP_KERNEL);
+	if (IS_ERR_OR_NULL(bio))
+		return -ENOMEM;
+
+	memset(&rqd, 0, sizeof(struct nvm_rq));
+	ret = nvm_set_rqd_ppalist(dev, &rqd, ppa, nr_ppas);
+	if (ret) {
+		bio_put(bio);
+		return ret;
+	}
+
+	rqd.opcode = opcode;
+	rqd.bio = bio;
+	rqd.wait = &wait;
+	rqd.dev = dev;
+	rqd.end_io = nvm_end_io_sync;
+	rqd.flags = flags;
+	nvm_generic_to_addr_mode(dev, &rqd);
+
+	ret = dev->ops->submit_io(dev, &rqd);
+
+	/* Prevent hang_check timer from firing at us during very long I/O */
+	hang_check = sysctl_hung_task_timeout_secs;
+	if (hang_check)
+		while (!wait_for_completion_io_timeout(&wait, hang_check * (HZ/2)));
+	else
+		wait_for_completion_io(&wait);
+
+	nvm_free_rqd_ppalist(dev, &rqd);
+
+	return rqd.error;
+}
+EXPORT_SYMBOL(nvm_submit_ppa);
+
+static int nvm_init_slc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp)
+{
+	int i;
+
+	dev->lps_per_blk = dev->pgs_per_blk;
+	dev->lptbl = kcalloc(dev->lps_per_blk, sizeof(int), GFP_KERNEL);
+	if (!dev->lptbl)
+		return -ENOMEM;
+
+	/* Just a linear array */
+	for (i = 0; i < dev->lps_per_blk; i++)
+		dev->lptbl[i] = i;
+
+	return 0;
+}
+
+static int nvm_init_mlc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp)
+{
+	int i, p;
+	struct nvm_id_lp_mlc *mlc = &grp->lptbl.mlc;
+
+	if (!mlc->num_pairs)
+		return 0;
+
+	dev->lps_per_blk = mlc->num_pairs;
+	dev->lptbl = kcalloc(dev->lps_per_blk, sizeof(int), GFP_KERNEL);
+	if (!dev->lptbl)
+		return -ENOMEM;
+
+	/* The lower page table encoding consists of a list of bytes, where each
+	 * has a lower and an upper half. The first half byte maintains the
+	 * increment value and every value after is an offset added to the
+	 * previous incrementation value */
+	dev->lptbl[0] = mlc->pairs[0] & 0xF;
+	for (i = 1; i < dev->lps_per_blk; i++) {
+		p = mlc->pairs[i >> 1];
+		if (i & 0x1) /* upper */
+			dev->lptbl[i] = dev->lptbl[i - 1] + ((p & 0xF0) >> 4);
+		else /* lower */
+			dev->lptbl[i] = dev->lptbl[i - 1] + (p & 0xF);
+	}
+
+	return 0;
+}
+
 static int nvm_core_init(struct nvm_dev *dev)
 {
 	struct nvm_id *id = &dev->identity;
@@ -206,6 +424,7 @@
 	dev->sec_size = grp->csecs;
 	dev->oob_size = grp->sos;
 	dev->sec_per_pg = grp->fpg_sz / grp->csecs;
+	dev->mccap = grp->mccap;
 	memcpy(&dev->ppaf, &id->ppaf, sizeof(struct nvm_addr_format));
 
 	dev->plane_mode = NVM_PLANE_SINGLE;
@@ -216,11 +435,23 @@
 		return -EINVAL;
 	}
 
-	if (grp->fmtype != 0 && grp->fmtype != 1) {
+	switch (grp->fmtype) {
+	case NVM_ID_FMTYPE_SLC:
+		if (nvm_init_slc_tbl(dev, grp))
+			return -ENOMEM;
+		break;
+	case NVM_ID_FMTYPE_MLC:
+		if (nvm_init_mlc_tbl(dev, grp))
+			return -ENOMEM;
+		break;
+	default:
 		pr_err("nvm: flash type not supported\n");
 		return -EINVAL;
 	}
 
+	if (!dev->lps_per_blk)
+		pr_info("nvm: lower page programming table missing\n");
+
 	if (grp->mpos & 0x020202)
 		dev->plane_mode = NVM_PLANE_DOUBLE;
 	if (grp->mpos & 0x040404)
@@ -238,6 +469,7 @@
 				dev->nr_chnls;
 	dev->total_pages = dev->total_blocks * dev->pgs_per_blk;
 	INIT_LIST_HEAD(&dev->online_targets);
+	mutex_init(&dev->mlock);
 
 	return 0;
 }
@@ -249,6 +481,8 @@
 
 	if (dev->mt)
 		dev->mt->unregister_mgr(dev);
+
+	kfree(dev->lptbl);
 }
 
 static int nvm_init(struct nvm_dev *dev)
@@ -338,9 +572,16 @@
 		}
 	}
 
+	ret = nvm_get_sysblock(dev, &dev->sb);
+	if (!ret)
+		pr_err("nvm: device not initialized.\n");
+	else if (ret < 0)
+		pr_err("nvm: err (%d) on device initialization\n", ret);
+
 	/* register device with a supported media manager */
 	down_write(&nvm_lock);
-	dev->mt = nvm_init_mgr(dev);
+	if (ret > 0)
+		dev->mt = nvm_init_mgr(dev);
 	list_add(&dev->devices, &nvm_devices);
 	up_write(&nvm_lock);
 
@@ -788,6 +1029,97 @@
 	return __nvm_configure_remove(&remove);
 }
 
+static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info)
+{
+	info->seqnr = 1;
+	info->erase_cnt = 0;
+	info->version = 1;
+}
+
+static long __nvm_ioctl_dev_init(struct nvm_ioctl_dev_init *init)
+{
+	struct nvm_dev *dev;
+	struct nvm_sb_info info;
+	int ret;
+
+	down_write(&nvm_lock);
+	dev = nvm_find_nvm_dev(init->dev);
+	up_write(&nvm_lock);
+	if (!dev) {
+		pr_err("nvm: device not found\n");
+		return -EINVAL;
+	}
+
+	nvm_setup_nvm_sb_info(&info);
+
+	strncpy(info.mmtype, init->mmtype, NVM_MMTYPE_LEN);
+	info.fs_ppa.ppa = -1;
+
+	ret = nvm_init_sysblock(dev, &info);
+	if (ret)
+		return ret;
+
+	memcpy(&dev->sb, &info, sizeof(struct nvm_sb_info));
+
+	down_write(&nvm_lock);
+	dev->mt = nvm_init_mgr(dev);
+	up_write(&nvm_lock);
+
+	return 0;
+}
+
+static long nvm_ioctl_dev_init(struct file *file, void __user *arg)
+{
+	struct nvm_ioctl_dev_init init;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (copy_from_user(&init, arg, sizeof(struct nvm_ioctl_dev_init)))
+		return -EFAULT;
+
+	if (init.flags != 0) {
+		pr_err("nvm: no flags supported\n");
+		return -EINVAL;
+	}
+
+	init.dev[DISK_NAME_LEN - 1] = '\0';
+
+	return __nvm_ioctl_dev_init(&init);
+}
+
+static long nvm_ioctl_dev_factory(struct file *file, void __user *arg)
+{
+	struct nvm_ioctl_dev_factory fact;
+	struct nvm_dev *dev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (copy_from_user(&fact, arg, sizeof(struct nvm_ioctl_dev_factory)))
+		return -EFAULT;
+
+	fact.dev[DISK_NAME_LEN - 1] = '\0';
+
+	if (fact.flags & ~(NVM_FACTORY_NR_BITS - 1))
+		return -EINVAL;
+
+	down_write(&nvm_lock);
+	dev = nvm_find_nvm_dev(fact.dev);
+	up_write(&nvm_lock);
+	if (!dev) {
+		pr_err("nvm: device not found\n");
+		return -EINVAL;
+	}
+
+	if (dev->mt) {
+		dev->mt->unregister_mgr(dev);
+		dev->mt = NULL;
+	}
+
+	return nvm_dev_factory(dev, fact.flags);
+}
+
 static long nvm_ctl_ioctl(struct file *file, uint cmd, unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
@@ -801,6 +1133,10 @@
 		return nvm_ioctl_dev_create(file, argp);
 	case NVM_DEV_REMOVE:
 		return nvm_ioctl_dev_remove(file, argp);
+	case NVM_DEV_INIT:
+		return nvm_ioctl_dev_init(file, argp);
+	case NVM_DEV_FACTORY:
+		return nvm_ioctl_dev_factory(file, argp);
 	}
 	return 0;
 }
--- linux-4.4.0.orig/drivers/lightnvm/gennvm.c
+++ linux-4.4.0/drivers/lightnvm/gennvm.c
@@ -60,7 +60,8 @@
 		lun->vlun.lun_id = i % dev->luns_per_chnl;
 		lun->vlun.chnl_id = i / dev->luns_per_chnl;
 		lun->vlun.nr_free_blocks = dev->blks_per_lun;
-		lun->vlun.nr_inuse_blocks = 0;
+		lun->vlun.nr_open_blocks = 0;
+		lun->vlun.nr_closed_blocks = 0;
 		lun->vlun.nr_bad_blocks = 0;
 	}
 	return 0;
@@ -89,6 +90,7 @@
 
 		list_move_tail(&blk->list, &lun->bb_list);
 		lun->vlun.nr_bad_blocks++;
+		lun->vlun.nr_free_blocks--;
 	}
 
 	return 0;
@@ -133,15 +135,15 @@
 		pba = pba - (dev->sec_per_lun * lun_id);
 		blk = &lun->vlun.blocks[div_u64(pba, dev->sec_per_blk)];
 
-		if (!blk->type) {
+		if (!blk->state) {
 			/* at this point, we don't know anything about the
 			 * block. It's up to the FTL on top to re-etablish the
-			 * block state
+			 * block state. The block is assumed to be open.
 			 */
 			list_move_tail(&blk->list, &lun->used_list);
-			blk->type = 1;
+			blk->state = NVM_BLK_ST_OPEN;
 			lun->vlun.nr_free_blocks--;
-			lun->vlun.nr_inuse_blocks++;
+			lun->vlun.nr_open_blocks++;
 		}
 	}
 
@@ -255,14 +257,14 @@
 	module_put(THIS_MODULE);
 }
 
-static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev,
+static struct nvm_block *gennvm_get_blk_unlocked(struct nvm_dev *dev,
 				struct nvm_lun *vlun, unsigned long flags)
 {
 	struct gen_lun *lun = container_of(vlun, struct gen_lun, vlun);
 	struct nvm_block *blk = NULL;
 	int is_gc = flags & NVM_IOTYPE_GC;
 
-	spin_lock(&vlun->lock);
+	assert_spin_locked(&vlun->lock);
 
 	if (list_empty(&lun->free_list)) {
 		pr_err_ratelimited("gennvm: lun %u have no free pages available",
@@ -275,83 +277,64 @@
 
 	blk = list_first_entry(&lun->free_list, struct nvm_block, list);
 	list_move_tail(&blk->list, &lun->used_list);
-	blk->type = 1;
+	blk->state = NVM_BLK_ST_OPEN;
 
 	lun->vlun.nr_free_blocks--;
-	lun->vlun.nr_inuse_blocks++;
+	lun->vlun.nr_open_blocks++;
 
 out:
+	return blk;
+}
+
+static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev,
+				struct nvm_lun *vlun, unsigned long flags)
+{
+	struct nvm_block *blk;
+
+	spin_lock(&vlun->lock);
+	blk = gennvm_get_blk_unlocked(dev, vlun, flags);
 	spin_unlock(&vlun->lock);
 	return blk;
 }
 
-static void gennvm_put_blk(struct nvm_dev *dev, struct nvm_block *blk)
+static void gennvm_put_blk_unlocked(struct nvm_dev *dev, struct nvm_block *blk)
 {
 	struct nvm_lun *vlun = blk->lun;
 	struct gen_lun *lun = container_of(vlun, struct gen_lun, vlun);
 
-	spin_lock(&vlun->lock);
+	assert_spin_locked(&vlun->lock);
 
-	switch (blk->type) {
-	case 1:
+	if (blk->state & NVM_BLK_ST_OPEN) {
 		list_move_tail(&blk->list, &lun->free_list);
+		lun->vlun.nr_open_blocks--;
 		lun->vlun.nr_free_blocks++;
-		lun->vlun.nr_inuse_blocks--;
-		blk->type = 0;
-		break;
-	case 2:
+		blk->state = NVM_BLK_ST_FREE;
+	} else if (blk->state & NVM_BLK_ST_CLOSED) {
+		list_move_tail(&blk->list, &lun->free_list);
+		lun->vlun.nr_closed_blocks--;
+		lun->vlun.nr_free_blocks++;
+		blk->state = NVM_BLK_ST_FREE;
+	} else if (blk->state & NVM_BLK_ST_BAD) {
 		list_move_tail(&blk->list, &lun->bb_list);
 		lun->vlun.nr_bad_blocks++;
-		lun->vlun.nr_inuse_blocks--;
-		break;
-	default:
+		blk->state = NVM_BLK_ST_BAD;
+	} else {
 		WARN_ON_ONCE(1);
 		pr_err("gennvm: erroneous block type (%lu -> %u)\n",
-							blk->id, blk->type);
+							blk->id, blk->state);
 		list_move_tail(&blk->list, &lun->bb_list);
 		lun->vlun.nr_bad_blocks++;
-		lun->vlun.nr_inuse_blocks--;
-	}
-
-	spin_unlock(&vlun->lock);
-}
-
-static void gennvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
-{
-	int i;
-
-	if (rqd->nr_pages > 1) {
-		for (i = 0; i < rqd->nr_pages; i++)
-			rqd->ppa_list[i] = dev_to_generic_addr(dev,
-							rqd->ppa_list[i]);
-	} else {
-		rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr);
-	}
-}
-
-static void gennvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
-{
-	int i;
-
-	if (rqd->nr_pages > 1) {
-		for (i = 0; i < rqd->nr_pages; i++)
-			rqd->ppa_list[i] = generic_to_dev_addr(dev,
-							rqd->ppa_list[i]);
-	} else {
-		rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr);
+		blk->state = NVM_BLK_ST_BAD;
 	}
 }
 
-static int gennvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
+static void gennvm_put_blk(struct nvm_dev *dev, struct nvm_block *blk)
 {
-	if (!dev->ops->submit_io)
-		return 0;
-
-	/* Convert address space */
-	gennvm_generic_to_addr_mode(dev, rqd);
+	struct nvm_lun *vlun = blk->lun;
 
-	rqd->dev = dev;
-	return dev->ops->submit_io(dev, rqd);
+	spin_lock(&vlun->lock);
+	gennvm_put_blk_unlocked(dev, blk);
+	spin_unlock(&vlun->lock);
 }
 
 static void gennvm_blk_set_type(struct nvm_dev *dev, struct ppa_addr *ppa,
@@ -376,7 +359,7 @@
 	blk = &lun->vlun.blocks[ppa->g.blk];
 
 	/* will be moved to bb list on put_blk from target */
-	blk->type = type;
+	blk->state = type;
 }
 
 /* mark block bad. It is expected the target recover from the error. */
@@ -390,77 +373,51 @@
 	if (dev->ops->set_bb_tbl(dev, rqd, 1))
 		return;
 
-	gennvm_addr_to_generic_mode(dev, rqd);
+	nvm_addr_to_generic_mode(dev, rqd);
 
 	/* look up blocks and mark them as bad */
 	if (rqd->nr_pages > 1)
 		for (i = 0; i < rqd->nr_pages; i++)
-			gennvm_blk_set_type(dev, &rqd->ppa_list[i], 2);
+			gennvm_blk_set_type(dev, &rqd->ppa_list[i],
+						NVM_BLK_ST_BAD);
 	else
-		gennvm_blk_set_type(dev, &rqd->ppa_addr, 2);
+		gennvm_blk_set_type(dev, &rqd->ppa_addr, NVM_BLK_ST_BAD);
 }
 
-static int gennvm_end_io(struct nvm_rq *rqd, int error)
+static void gennvm_end_io(struct nvm_rq *rqd)
 {
 	struct nvm_tgt_instance *ins = rqd->ins;
-	int ret = 0;
 
-	switch (error) {
+	switch (rqd->error) {
 	case NVM_RSP_SUCCESS:
-		break;
 	case NVM_RSP_ERR_EMPTYPAGE:
 		break;
 	case NVM_RSP_ERR_FAILWRITE:
 		gennvm_mark_blk_bad(rqd->dev, rqd);
-	default:
-		ret++;
 	}
 
-	ret += ins->tt->end_io(rqd, error);
-
-	return ret;
+	ins->tt->end_io(rqd);
 }
 
-static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk,
-							unsigned long flags)
+static int gennvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
 {
-	int plane_cnt = 0, pl_idx, ret;
-	struct ppa_addr addr;
-	struct nvm_rq rqd;
-
-	if (!dev->ops->erase_block)
-		return 0;
-
-	addr = block_to_ppa(dev, blk);
-
-	if (dev->plane_mode == NVM_PLANE_SINGLE) {
-		rqd.nr_pages = 1;
-		rqd.ppa_addr = addr;
-	} else {
-		plane_cnt = (1 << dev->plane_mode);
-		rqd.nr_pages = plane_cnt;
-
-		rqd.ppa_list = nvm_dev_dma_alloc(dev, GFP_KERNEL,
-							&rqd.dma_ppa_list);
-		if (!rqd.ppa_list) {
-			pr_err("gennvm: failed to allocate dma memory\n");
-			return -ENOMEM;
-		}
-
-		for (pl_idx = 0; pl_idx < plane_cnt; pl_idx++) {
-			addr.g.pl = pl_idx;
-			rqd.ppa_list[pl_idx] = addr;
-		}
-	}
+	if (!dev->ops->submit_io)
+		return -ENODEV;
 
-	gennvm_generic_to_addr_mode(dev, &rqd);
+	/* Convert address space */
+	nvm_generic_to_addr_mode(dev, rqd);
 
-	ret = dev->ops->erase_block(dev, &rqd);
+	rqd->dev = dev;
+	rqd->end_io = gennvm_end_io;
+	return dev->ops->submit_io(dev, rqd);
+}
 
-	if (plane_cnt)
-		nvm_dev_dma_free(dev, rqd.ppa_list, rqd.dma_ppa_list);
+static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk,
+							unsigned long flags)
+{
+	struct ppa_addr addr = block_to_ppa(dev, blk);
 
-	return ret;
+	return nvm_erase_ppa(dev, &addr, 1);
 }
 
 static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
@@ -480,10 +437,11 @@
 	gennvm_for_each_lun(gn, lun, i) {
 		spin_lock(&lun->vlun.lock);
 
-		pr_info("%s: lun%8u\t%u\t%u\t%u\n",
+		pr_info("%s: lun%8u\t%u\t%u\t%u\t%u\n",
 				dev->name, i,
 				lun->vlun.nr_free_blocks,
-				lun->vlun.nr_inuse_blocks,
+				lun->vlun.nr_open_blocks,
+				lun->vlun.nr_closed_blocks,
 				lun->vlun.nr_bad_blocks);
 
 		spin_unlock(&lun->vlun.lock);
@@ -491,21 +449,23 @@
 }
 
 static struct nvmm_type gennvm = {
-	.name		= "gennvm",
-	.version	= {0, 1, 0},
+	.name			= "gennvm",
+	.version		= {0, 1, 0},
+
+	.register_mgr		= gennvm_register,
+	.unregister_mgr		= gennvm_unregister,
 
-	.register_mgr	= gennvm_register,
-	.unregister_mgr	= gennvm_unregister,
+	.get_blk_unlocked	= gennvm_get_blk_unlocked,
+	.put_blk_unlocked	= gennvm_put_blk_unlocked,
 
-	.get_blk	= gennvm_get_blk,
-	.put_blk	= gennvm_put_blk,
+	.get_blk		= gennvm_get_blk,
+	.put_blk		= gennvm_put_blk,
 
-	.submit_io	= gennvm_submit_io,
-	.end_io		= gennvm_end_io,
-	.erase_blk	= gennvm_erase_blk,
+	.submit_io		= gennvm_submit_io,
+	.erase_blk		= gennvm_erase_blk,
 
-	.get_lun	= gennvm_get_lun,
-	.lun_info_print = gennvm_lun_info_print,
+	.get_lun		= gennvm_get_lun,
+	.lun_info_print		= gennvm_lun_info_print,
 };
 
 static int __init gennvm_module_init(void)
--- linux-4.4.0.orig/drivers/lightnvm/rrpc.c
+++ linux-4.4.0/drivers/lightnvm/rrpc.c
@@ -179,16 +179,23 @@
 static struct rrpc_block *rrpc_get_blk(struct rrpc *rrpc, struct rrpc_lun *rlun,
 							unsigned long flags)
 {
+	struct nvm_lun *lun = rlun->parent;
 	struct nvm_block *blk;
 	struct rrpc_block *rblk;
 
-	blk = nvm_get_blk(rrpc->dev, rlun->parent, flags);
-	if (!blk)
+	spin_lock(&lun->lock);
+	blk = nvm_get_blk_unlocked(rrpc->dev, rlun->parent, flags);
+	if (!blk) {
+		pr_err("nvm: rrpc: cannot get new block from media manager\n");
+		spin_unlock(&lun->lock);
 		return NULL;
+	}
 
 	rblk = &rlun->blocks[blk->id];
-	blk->priv = rblk;
+	list_add_tail(&rblk->list, &rlun->open_list);
+	spin_unlock(&lun->lock);
 
+	blk->priv = rblk;
 	bitmap_zero(rblk->invalid_pages, rrpc->dev->pgs_per_blk);
 	rblk->next_page = 0;
 	rblk->nr_invalid_pages = 0;
@@ -199,7 +206,13 @@
 
 static void rrpc_put_blk(struct rrpc *rrpc, struct rrpc_block *rblk)
 {
-	nvm_put_blk(rrpc->dev, rblk->parent);
+	struct rrpc_lun *rlun = rblk->rlun;
+	struct nvm_lun *lun = rlun->parent;
+
+	spin_lock(&lun->lock);
+	nvm_put_blk_unlocked(rrpc->dev, rblk->parent);
+	list_del(&rblk->list);
+	spin_unlock(&lun->lock);
 }
 
 static void rrpc_put_blks(struct rrpc *rrpc)
@@ -287,6 +300,10 @@
 	}
 
 	page = mempool_alloc(rrpc->page_pool, GFP_NOIO);
+	if (!page) {
+		bio_put(bio);
+		return -ENOMEM;
+	}
 
 	while ((slot = find_first_zero_bit(rblk->invalid_pages,
 					    nr_pgs_per_blk)) < nr_pgs_per_blk) {
@@ -328,6 +345,10 @@
 			goto finished;
 		}
 		wait_for_completion_io(&wait);
+		if (bio->bi_error) {
+			rrpc_inflight_laddr_release(rrpc, rqd);
+			goto finished;
+		}
 
 		bio_reset(bio);
 		reinit_completion(&wait);
@@ -350,6 +371,8 @@
 		wait_for_completion_io(&wait);
 
 		rrpc_inflight_laddr_release(rrpc, rqd);
+		if (bio->bi_error)
+			goto finished;
 
 		bio_reset(bio);
 	}
@@ -373,16 +396,26 @@
 	struct rrpc *rrpc = gcb->rrpc;
 	struct rrpc_block *rblk = gcb->rblk;
 	struct nvm_dev *dev = rrpc->dev;
+	struct nvm_lun *lun = rblk->parent->lun;
+	struct rrpc_lun *rlun = &rrpc->luns[lun->id - rrpc->lun_offset];
 
+	mempool_free(gcb, rrpc->gcb_pool);
 	pr_debug("nvm: block '%lu' being reclaimed\n", rblk->parent->id);
 
 	if (rrpc_move_valid_pages(rrpc, rblk))
-		goto done;
+		goto put_back;
+
+	if (nvm_erase_blk(dev, rblk->parent))
+		goto put_back;
 
-	nvm_erase_blk(dev, rblk->parent);
 	rrpc_put_blk(rrpc, rblk);
-done:
-	mempool_free(gcb, rrpc->gcb_pool);
+
+	return;
+
+put_back:
+	spin_lock(&rlun->lock);
+	list_add_tail(&rblk->prio, &rlun->prio_list);
+	spin_unlock(&rlun->lock);
 }
 
 /* the block with highest number of invalid pages, will be in the beginning
@@ -427,7 +460,7 @@
 	if (nr_blocks_need < rrpc->nr_luns)
 		nr_blocks_need = rrpc->nr_luns;
 
-	spin_lock(&lun->lock);
+	spin_lock(&rlun->lock);
 	while (nr_blocks_need > lun->nr_free_blocks &&
 					!list_empty(&rlun->prio_list)) {
 		struct rrpc_block *rblock = block_prio_find_max(rlun);
@@ -436,16 +469,16 @@
 		if (!rblock->nr_invalid_pages)
 			break;
 
+		gcb = mempool_alloc(rrpc->gcb_pool, GFP_ATOMIC);
+		if (!gcb)
+			break;
+
 		list_del_init(&rblock->prio);
 
 		BUG_ON(!block_is_full(rrpc, rblock));
 
 		pr_debug("rrpc: selected block '%lu' for GC\n", block->id);
 
-		gcb = mempool_alloc(rrpc->gcb_pool, GFP_ATOMIC);
-		if (!gcb)
-			break;
-
 		gcb->rrpc = rrpc;
 		gcb->rblk = rblock;
 		INIT_WORK(&gcb->ws_gc, rrpc_block_gc);
@@ -454,7 +487,7 @@
 
 		nr_blocks_need--;
 	}
-	spin_unlock(&lun->lock);
+	spin_unlock(&rlun->lock);
 
 	/* TODO: Hint that request queue can be started again */
 }
@@ -635,12 +668,24 @@
 		lun = rblk->parent->lun;
 
 		cmnt_size = atomic_inc_return(&rblk->data_cmnt_size);
-		if (unlikely(cmnt_size == rrpc->dev->pgs_per_blk))
+		if (unlikely(cmnt_size == rrpc->dev->pgs_per_blk)) {
+			struct nvm_block *blk = rblk->parent;
+			struct rrpc_lun *rlun = rblk->rlun;
+
+			spin_lock(&lun->lock);
+			lun->nr_open_blocks--;
+			lun->nr_closed_blocks++;
+			blk->state &= ~NVM_BLK_ST_OPEN;
+			blk->state |= NVM_BLK_ST_CLOSED;
+			list_move_tail(&rblk->list, &rlun->closed_list);
+			spin_unlock(&lun->lock);
+
 			rrpc_run_gc(rrpc, rblk);
+		}
 	}
 }
 
-static int rrpc_end_io(struct nvm_rq *rqd, int error)
+static void rrpc_end_io(struct nvm_rq *rqd)
 {
 	struct rrpc *rrpc = container_of(rqd->ins, struct rrpc, instance);
 	struct rrpc_rq *rrqd = nvm_rq_to_pdu(rqd);
@@ -650,11 +695,12 @@
 	if (bio_data_dir(rqd->bio) == WRITE)
 		rrpc_end_io_write(rrpc, rrqd, laddr, npages);
 
+	bio_put(rqd->bio);
+
 	if (rrqd->flags & NVM_IOTYPE_GC)
-		return 0;
+		return;
 
 	rrpc_unlock_rq(rrpc, rqd);
-	bio_put(rqd->bio);
 
 	if (npages > 1)
 		nvm_dev_dma_free(rrpc->dev, rqd->ppa_list, rqd->dma_ppa_list);
@@ -662,8 +708,6 @@
 		nvm_dev_dma_free(rrpc->dev, rqd->metadata, rqd->dma_metadata);
 
 	mempool_free(rqd, rrpc->rq_pool);
-
-	return 0;
 }
 
 static int rrpc_read_ppalist_rq(struct rrpc *rrpc, struct bio *bio,
@@ -841,6 +885,13 @@
 	err = nvm_submit_io(rrpc->dev, rqd);
 	if (err) {
 		pr_err("rrpc: I/O submission failed: %d\n", err);
+		bio_put(bio);
+		if (!(flags & NVM_IOTYPE_GC)) {
+			rrpc_unlock_rq(rrpc, rqd);
+			if (rqd->nr_pages > 1)
+				nvm_dev_dma_free(rrpc->dev,
+			rqd->ppa_list, rqd->dma_ppa_list);
+		}
 		return NVM_IO_ERR;
 	}
 
@@ -1090,6 +1141,11 @@
 	struct rrpc_lun *rlun;
 	int i, j;
 
+	if (dev->pgs_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) {
+		pr_err("rrpc: number of pages per block too high.");
+		return -EINVAL;
+	}
+
 	spin_lock_init(&rrpc->rev_lock);
 
 	rrpc->luns = kcalloc(rrpc->nr_luns, sizeof(struct rrpc_lun),
@@ -1101,16 +1157,13 @@
 	for (i = 0; i < rrpc->nr_luns; i++) {
 		struct nvm_lun *lun = dev->mt->get_lun(dev, lun_begin + i);
 
-		if (dev->pgs_per_blk >
-				MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) {
-			pr_err("rrpc: number of pages per block too high.");
-			goto err;
-		}
-
 		rlun = &rrpc->luns[i];
 		rlun->rrpc = rrpc;
 		rlun->parent = lun;
 		INIT_LIST_HEAD(&rlun->prio_list);
+		INIT_LIST_HEAD(&rlun->open_list);
+		INIT_LIST_HEAD(&rlun->closed_list);
+
 		INIT_WORK(&rlun->ws_gc, rrpc_lun_gc);
 		spin_lock_init(&rlun->lock);
 
@@ -1127,6 +1180,7 @@
 			struct nvm_block *blk = &lun->blocks[j];
 
 			rblk->parent = blk;
+			rblk->rlun = rlun;
 			INIT_LIST_HEAD(&rblk->prio);
 			spin_lock_init(&rblk->lock);
 		}
--- linux-4.4.0.orig/drivers/lightnvm/rrpc.h
+++ linux-4.4.0/drivers/lightnvm/rrpc.h
@@ -54,7 +54,9 @@
 
 struct rrpc_block {
 	struct nvm_block *parent;
+	struct rrpc_lun *rlun;
 	struct list_head prio;
+	struct list_head list;
 
 #define MAX_INVALID_PAGES_STORAGE 8
 	/* Bitmap for invalid page intries */
@@ -73,7 +75,16 @@
 	struct nvm_lun *parent;
 	struct rrpc_block *cur, *gc_cur;
 	struct rrpc_block *blocks;	/* Reference to block allocation */
-	struct list_head prio_list;		/* Blocks that may be GC'ed */
+
+	struct list_head prio_list;	/* Blocks that may be GC'ed */
+	struct list_head open_list;	/* In-use open blocks. These are blocks
+					 * that can be both written to and read
+					 * from
+					 */
+	struct list_head closed_list;	/* In-use closed blocks. These are
+					 * blocks that can _only_ be read from
+					 */
+
 	struct work_struct ws_gc;
 
 	spinlock_t lock;
--- linux-4.4.0.orig/drivers/lightnvm/sysblk.c
+++ linux-4.4.0/drivers/lightnvm/sysblk.c
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2015 Matias Bjorling. 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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ */
+
+#include <linux/lightnvm.h>
+
+#define MAX_SYSBLKS 3	/* remember to update mapping scheme on change */
+#define MAX_BLKS_PR_SYSBLK 2 /* 2 blks with 256 pages and 3000 erases
+			      * enables ~1.5M updates per sysblk unit
+			      */
+
+struct sysblk_scan {
+	/* A row is a collection of flash blocks for a system block. */
+	int nr_rows;
+	int row;
+	int act_blk[MAX_SYSBLKS];
+
+	int nr_ppas;
+	struct ppa_addr ppas[MAX_SYSBLKS * MAX_BLKS_PR_SYSBLK];/* all sysblks */
+};
+
+static inline int scan_ppa_idx(int row, int blkid)
+{
+	return (row * MAX_BLKS_PR_SYSBLK) + blkid;
+}
+
+void nvm_sysblk_to_cpu(struct nvm_sb_info *info, struct nvm_system_block *sb)
+{
+	info->seqnr = be32_to_cpu(sb->seqnr);
+	info->erase_cnt = be32_to_cpu(sb->erase_cnt);
+	info->version = be16_to_cpu(sb->version);
+	strncpy(info->mmtype, sb->mmtype, NVM_MMTYPE_LEN);
+	info->fs_ppa.ppa = be64_to_cpu(sb->fs_ppa);
+}
+
+void nvm_cpu_to_sysblk(struct nvm_system_block *sb, struct nvm_sb_info *info)
+{
+	sb->magic = cpu_to_be32(NVM_SYSBLK_MAGIC);
+	sb->seqnr = cpu_to_be32(info->seqnr);
+	sb->erase_cnt = cpu_to_be32(info->erase_cnt);
+	sb->version = cpu_to_be16(info->version);
+	strncpy(sb->mmtype, info->mmtype, NVM_MMTYPE_LEN);
+	sb->fs_ppa = cpu_to_be64(info->fs_ppa.ppa);
+}
+
+static int nvm_setup_sysblks(struct nvm_dev *dev, struct ppa_addr *sysblk_ppas)
+{
+	int nr_rows = min_t(int, MAX_SYSBLKS, dev->nr_chnls);
+	int i;
+
+	for (i = 0; i < nr_rows; i++)
+		sysblk_ppas[i].ppa = 0;
+
+	/* if possible, place sysblk at first channel, middle channel and last
+	 * channel of the device. If not, create only one or two sys blocks
+	 */
+	switch (dev->nr_chnls) {
+	case 2:
+		sysblk_ppas[1].g.ch = 1;
+		/* fall-through */
+	case 1:
+		sysblk_ppas[0].g.ch = 0;
+		break;
+	default:
+		sysblk_ppas[0].g.ch = 0;
+		sysblk_ppas[1].g.ch = dev->nr_chnls / 2;
+		sysblk_ppas[2].g.ch = dev->nr_chnls - 1;
+		break;
+	}
+
+	return nr_rows;
+}
+
+void nvm_setup_sysblk_scan(struct nvm_dev *dev, struct sysblk_scan *s,
+						struct ppa_addr *sysblk_ppas)
+{
+	memset(s, 0, sizeof(struct sysblk_scan));
+	s->nr_rows = nvm_setup_sysblks(dev, sysblk_ppas);
+}
+
+static int sysblk_get_host_blks(struct ppa_addr ppa, int nr_blks, u8 *blks,
+								void *private)
+{
+	struct sysblk_scan *s = private;
+	int i, nr_sysblk = 0;
+
+	for (i = 0; i < nr_blks; i++) {
+		if (blks[i] != NVM_BLK_T_HOST)
+			continue;
+
+		if (s->nr_ppas == MAX_BLKS_PR_SYSBLK * MAX_SYSBLKS) {
+			pr_err("nvm: too many host blks\n");
+			return -EINVAL;
+		}
+
+		ppa.g.blk = i;
+
+		s->ppas[scan_ppa_idx(s->row, nr_sysblk)] = ppa;
+		s->nr_ppas++;
+		nr_sysblk++;
+	}
+
+	return 0;
+}
+
+static int nvm_get_all_sysblks(struct nvm_dev *dev, struct sysblk_scan *s,
+				struct ppa_addr *ppas, nvm_bb_update_fn *fn)
+{
+	struct ppa_addr dppa;
+	int i, ret;
+
+	s->nr_ppas = 0;
+
+	for (i = 0; i < s->nr_rows; i++) {
+		dppa = generic_to_dev_addr(dev, ppas[i]);
+		s->row = i;
+
+		ret = dev->ops->get_bb_tbl(dev, dppa, dev->blks_per_lun, fn, s);
+		if (ret) {
+			pr_err("nvm: failed bb tbl for ppa (%u %u)\n",
+							ppas[i].g.ch,
+							ppas[i].g.blk);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * scans a block for latest sysblk.
+ * Returns:
+ *	0 - newer sysblk not found. PPA is updated to latest page.
+ *	1 - newer sysblk found and stored in *cur. PPA is updated to
+ *	    next valid page.
+ *	<0- error.
+ */
+static int nvm_scan_block(struct nvm_dev *dev, struct ppa_addr *ppa,
+						struct nvm_system_block *sblk)
+{
+	struct nvm_system_block *cur;
+	int pg, cursz, ret, found = 0;
+
+	/* the full buffer for a flash page is allocated. Only the first of it
+	 * contains the system block information
+	 */
+	cursz = dev->sec_size * dev->sec_per_pg * dev->nr_planes;
+	cur = kmalloc(cursz, GFP_KERNEL);
+	if (!cur)
+		return -ENOMEM;
+
+	/* perform linear scan through the block */
+	for (pg = 0; pg < dev->lps_per_blk; pg++) {
+		ppa->g.pg = ppa_to_slc(dev, pg);
+
+		ret = nvm_submit_ppa(dev, ppa, 1, NVM_OP_PREAD, NVM_IO_SLC_MODE,
+								cur, cursz);
+		if (ret) {
+			if (ret == NVM_RSP_ERR_EMPTYPAGE) {
+				pr_debug("nvm: sysblk scan empty ppa (%u %u %u %u)\n",
+							ppa->g.ch,
+							ppa->g.lun,
+							ppa->g.blk,
+							ppa->g.pg);
+				break;
+			}
+			pr_err("nvm: read failed (%x) for ppa (%u %u %u %u)",
+							ret,
+							ppa->g.ch,
+							ppa->g.lun,
+							ppa->g.blk,
+							ppa->g.pg);
+			break; /* if we can't read a page, continue to the
+				* next blk
+				*/
+		}
+
+		if (be32_to_cpu(cur->magic) != NVM_SYSBLK_MAGIC) {
+			pr_debug("nvm: scan break for ppa (%u %u %u %u)\n",
+							ppa->g.ch,
+							ppa->g.lun,
+							ppa->g.blk,
+							ppa->g.pg);
+			break; /* last valid page already found */
+		}
+
+		if (be32_to_cpu(cur->seqnr) < be32_to_cpu(sblk->seqnr))
+			continue;
+
+		memcpy(sblk, cur, sizeof(struct nvm_system_block));
+		found = 1;
+	}
+
+	kfree(cur);
+
+	return found;
+}
+
+static int nvm_set_bb_tbl(struct nvm_dev *dev, struct sysblk_scan *s, int type)
+{
+	struct nvm_rq rqd;
+	int ret;
+
+	if (s->nr_ppas > dev->ops->max_phys_sect) {
+		pr_err("nvm: unable to update all sysblocks atomically\n");
+		return -EINVAL;
+	}
+
+	memset(&rqd, 0, sizeof(struct nvm_rq));
+
+	nvm_set_rqd_ppalist(dev, &rqd, s->ppas, s->nr_ppas);
+	nvm_generic_to_addr_mode(dev, &rqd);
+
+	ret = dev->ops->set_bb_tbl(dev, &rqd, type);
+	nvm_free_rqd_ppalist(dev, &rqd);
+	if (ret) {
+		pr_err("nvm: sysblk failed bb mark\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sysblk_get_free_blks(struct ppa_addr ppa, int nr_blks, u8 *blks,
+								void *private)
+{
+	struct sysblk_scan *s = private;
+	struct ppa_addr *sppa;
+	int i, blkid = 0;
+
+	for (i = 0; i < nr_blks; i++) {
+		if (blks[i] == NVM_BLK_T_HOST)
+			return -EEXIST;
+
+		if (blks[i] != NVM_BLK_T_FREE)
+			continue;
+
+		sppa = &s->ppas[scan_ppa_idx(s->row, blkid)];
+		sppa->g.ch = ppa.g.ch;
+		sppa->g.lun = ppa.g.lun;
+		sppa->g.blk = i;
+		s->nr_ppas++;
+		blkid++;
+
+		pr_debug("nvm: use (%u %u %u) as sysblk\n",
+					sppa->g.ch, sppa->g.lun, sppa->g.blk);
+		if (blkid > MAX_BLKS_PR_SYSBLK - 1)
+			return 0;
+	}
+
+	pr_err("nvm: sysblk failed get sysblk\n");
+	return -EINVAL;
+}
+
+static int nvm_write_and_verify(struct nvm_dev *dev, struct nvm_sb_info *info,
+							struct sysblk_scan *s)
+{
+	struct nvm_system_block nvmsb;
+	void *buf;
+	int i, sect, ret, bufsz;
+	struct ppa_addr *ppas;
+
+	nvm_cpu_to_sysblk(&nvmsb, info);
+
+	/* buffer for flash page */
+	bufsz = dev->sec_size * dev->sec_per_pg * dev->nr_planes;
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	memcpy(buf, &nvmsb, sizeof(struct nvm_system_block));
+
+	ppas = kcalloc(dev->sec_per_pg, sizeof(struct ppa_addr), GFP_KERNEL);
+	if (!ppas) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/* Write and verify */
+	for (i = 0; i < s->nr_rows; i++) {
+		ppas[0] = s->ppas[scan_ppa_idx(i, s->act_blk[i])];
+
+		pr_debug("nvm: writing sysblk to ppa (%u %u %u %u)\n",
+							ppas[0].g.ch,
+							ppas[0].g.lun,
+							ppas[0].g.blk,
+							ppas[0].g.pg);
+
+		/* Expand to all sectors within a flash page */
+		if (dev->sec_per_pg > 1) {
+			for (sect = 1; sect < dev->sec_per_pg; sect++) {
+				ppas[sect].ppa = ppas[0].ppa;
+				ppas[sect].g.sec = sect;
+			}
+		}
+
+		ret = nvm_submit_ppa(dev, ppas, dev->sec_per_pg, NVM_OP_PWRITE,
+						NVM_IO_SLC_MODE, buf, bufsz);
+		if (ret) {
+			pr_err("nvm: sysblk failed program (%u %u %u)\n",
+							ppas[0].g.ch,
+							ppas[0].g.lun,
+							ppas[0].g.blk);
+			break;
+		}
+
+		ret = nvm_submit_ppa(dev, ppas, dev->sec_per_pg, NVM_OP_PREAD,
+						NVM_IO_SLC_MODE, buf, bufsz);
+		if (ret) {
+			pr_err("nvm: sysblk failed read (%u %u %u)\n",
+							ppas[0].g.ch,
+							ppas[0].g.lun,
+							ppas[0].g.blk);
+			break;
+		}
+
+		if (memcmp(buf, &nvmsb, sizeof(struct nvm_system_block))) {
+			pr_err("nvm: sysblk failed verify (%u %u %u)\n",
+							ppas[0].g.ch,
+							ppas[0].g.lun,
+							ppas[0].g.blk);
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+	kfree(ppas);
+err:
+	kfree(buf);
+
+	return ret;
+}
+
+static int nvm_prepare_new_sysblks(struct nvm_dev *dev, struct sysblk_scan *s)
+{
+	int i, ret;
+	unsigned long nxt_blk;
+	struct ppa_addr *ppa;
+
+	for (i = 0; i < s->nr_rows; i++) {
+		nxt_blk = (s->act_blk[i] + 1) % MAX_BLKS_PR_SYSBLK;
+		ppa = &s->ppas[scan_ppa_idx(i, nxt_blk)];
+		ppa->g.pg = ppa_to_slc(dev, 0);
+
+		ret = nvm_erase_ppa(dev, ppa, 1);
+		if (ret)
+			return ret;
+
+		s->act_blk[i] = nxt_blk;
+	}
+
+	return 0;
+}
+
+int nvm_get_sysblock(struct nvm_dev *dev, struct nvm_sb_info *info)
+{
+	struct ppa_addr sysblk_ppas[MAX_SYSBLKS];
+	struct sysblk_scan s;
+	struct nvm_system_block *cur;
+	int i, j, found = 0;
+	int ret = -ENOMEM;
+
+	/*
+	 * 1. setup sysblk locations
+	 * 2. get bad block list
+	 * 3. filter on host-specific (type 3)
+	 * 4. iterate through all and find the highest seq nr.
+	 * 5. return superblock information
+	 */
+
+	if (!dev->ops->get_bb_tbl)
+		return -EINVAL;
+
+	nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
+
+	mutex_lock(&dev->mlock);
+	ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, sysblk_get_host_blks);
+	if (ret)
+		goto err_sysblk;
+
+	/* no sysblocks initialized */
+	if (!s.nr_ppas)
+		goto err_sysblk;
+
+	cur = kzalloc(sizeof(struct nvm_system_block), GFP_KERNEL);
+	if (!cur)
+		goto err_sysblk;
+
+	/* find the latest block across all sysblocks */
+	for (i = 0; i < s.nr_rows; i++) {
+		for (j = 0; j < MAX_BLKS_PR_SYSBLK; j++) {
+			struct ppa_addr ppa = s.ppas[scan_ppa_idx(i, j)];
+
+			ret = nvm_scan_block(dev, &ppa, cur);
+			if (ret > 0)
+				found = 1;
+			else if (ret < 0)
+				break;
+		}
+	}
+
+	nvm_sysblk_to_cpu(info, cur);
+
+	kfree(cur);
+err_sysblk:
+	mutex_unlock(&dev->mlock);
+
+	if (found)
+		return 1;
+	return ret;
+}
+
+int nvm_update_sysblock(struct nvm_dev *dev, struct nvm_sb_info *new)
+{
+	/* 1. for each latest superblock
+	 * 2. if room
+	 *    a. write new flash page entry with the updated information
+	 * 3. if no room
+	 *    a. find next available block on lun (linear search)
+	 *       if none, continue to next lun
+	 *       if none at all, report error. also report that it wasn't
+	 *       possible to write to all superblocks.
+	 *    c. write data to block.
+	 */
+	struct ppa_addr sysblk_ppas[MAX_SYSBLKS];
+	struct sysblk_scan s;
+	struct nvm_system_block *cur;
+	int i, j, ppaidx, found = 0;
+	int ret = -ENOMEM;
+
+	if (!dev->ops->get_bb_tbl)
+		return -EINVAL;
+
+	nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
+
+	mutex_lock(&dev->mlock);
+	ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, sysblk_get_host_blks);
+	if (ret)
+		goto err_sysblk;
+
+	cur = kzalloc(sizeof(struct nvm_system_block), GFP_KERNEL);
+	if (!cur)
+		goto err_sysblk;
+
+	/* Get the latest sysblk for each sysblk row */
+	for (i = 0; i < s.nr_rows; i++) {
+		found = 0;
+		for (j = 0; j < MAX_BLKS_PR_SYSBLK; j++) {
+			ppaidx = scan_ppa_idx(i, j);
+			ret = nvm_scan_block(dev, &s.ppas[ppaidx], cur);
+			if (ret > 0) {
+				s.act_blk[i] = j;
+				found = 1;
+			} else if (ret < 0)
+				break;
+		}
+	}
+
+	if (!found) {
+		pr_err("nvm: no valid sysblks found to update\n");
+		ret = -EINVAL;
+		goto err_cur;
+	}
+
+	/*
+	 * All sysblocks found. Check that they have same page id in their flash
+	 * blocks
+	 */
+	for (i = 1; i < s.nr_rows; i++) {
+		struct ppa_addr l = s.ppas[scan_ppa_idx(0, s.act_blk[0])];
+		struct ppa_addr r = s.ppas[scan_ppa_idx(i, s.act_blk[i])];
+
+		if (l.g.pg != r.g.pg) {
+			pr_err("nvm: sysblks not on same page. Previous update failed.\n");
+			ret = -EINVAL;
+			goto err_cur;
+		}
+	}
+
+	/*
+	 * Check that there haven't been another update to the seqnr since we
+	 * began
+	 */
+	if ((new->seqnr - 1) != be32_to_cpu(cur->seqnr)) {
+		pr_err("nvm: seq is not sequential\n");
+		ret = -EINVAL;
+		goto err_cur;
+	}
+
+	/*
+	 * When all pages in a block has been written, a new block is selected
+	 * and writing is performed on the new block.
+	 */
+	if (s.ppas[scan_ppa_idx(0, s.act_blk[0])].g.pg ==
+						dev->lps_per_blk - 1) {
+		ret = nvm_prepare_new_sysblks(dev, &s);
+		if (ret)
+			goto err_cur;
+	}
+
+	ret = nvm_write_and_verify(dev, new, &s);
+err_cur:
+	kfree(cur);
+err_sysblk:
+	mutex_unlock(&dev->mlock);
+
+	return ret;
+}
+
+int nvm_init_sysblock(struct nvm_dev *dev, struct nvm_sb_info *info)
+{
+	struct ppa_addr sysblk_ppas[MAX_SYSBLKS];
+	struct sysblk_scan s;
+	int ret;
+
+	/*
+	 * 1. select master blocks and select first available blks
+	 * 2. get bad block list
+	 * 3. mark MAX_SYSBLKS block as host-based device allocated.
+	 * 4. write and verify data to block
+	 */
+
+	if (!dev->ops->get_bb_tbl || !dev->ops->set_bb_tbl)
+		return -EINVAL;
+
+	if (!(dev->mccap & NVM_ID_CAP_SLC) || !dev->lps_per_blk) {
+		pr_err("nvm: memory does not support SLC access\n");
+		return -EINVAL;
+	}
+
+	/* Index all sysblocks and mark them as host-driven */
+	nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
+
+	mutex_lock(&dev->mlock);
+	ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, sysblk_get_free_blks);
+	if (ret)
+		goto err_mark;
+
+	ret = nvm_set_bb_tbl(dev, &s, NVM_BLK_T_HOST);
+	if (ret)
+		goto err_mark;
+
+	/* Write to the first block of each row */
+	ret = nvm_write_and_verify(dev, info, &s);
+err_mark:
+	mutex_unlock(&dev->mlock);
+	return ret;
+}
+
+struct factory_blks {
+	struct nvm_dev *dev;
+	int flags;
+	unsigned long *blks;
+};
+
+static int factory_nblks(int nblks)
+{
+	/* Round up to nearest BITS_PER_LONG */
+	return (nblks + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
+}
+
+static unsigned int factory_blk_offset(struct nvm_dev *dev, int ch, int lun)
+{
+	int nblks = factory_nblks(dev->blks_per_lun);
+
+	return ((ch * dev->luns_per_chnl * nblks) + (lun * nblks)) /
+								BITS_PER_LONG;
+}
+
+static int nvm_factory_blks(struct ppa_addr ppa, int nr_blks, u8 *blks,
+								void *private)
+{
+	struct factory_blks *f = private;
+	struct nvm_dev *dev = f->dev;
+	int i, lunoff;
+
+	lunoff = factory_blk_offset(dev, ppa.g.ch, ppa.g.lun);
+
+	/* non-set bits correspond to the block must be erased */
+	for (i = 0; i < nr_blks; i++) {
+		switch (blks[i]) {
+		case NVM_BLK_T_FREE:
+			if (f->flags & NVM_FACTORY_ERASE_ONLY_USER)
+				set_bit(i, &f->blks[lunoff]);
+			break;
+		case NVM_BLK_T_HOST:
+			if (!(f->flags & NVM_FACTORY_RESET_HOST_BLKS))
+				set_bit(i, &f->blks[lunoff]);
+			break;
+		case NVM_BLK_T_GRWN_BAD:
+			if (!(f->flags & NVM_FACTORY_RESET_GRWN_BBLKS))
+				set_bit(i, &f->blks[lunoff]);
+			break;
+		default:
+			set_bit(i, &f->blks[lunoff]);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int nvm_fact_get_blks(struct nvm_dev *dev, struct ppa_addr *erase_list,
+					int max_ppas, struct factory_blks *f)
+{
+	struct ppa_addr ppa;
+	int ch, lun, blkid, idx, done = 0, ppa_cnt = 0;
+	unsigned long *offset;
+
+	while (!done) {
+		done = 1;
+		for (ch = 0; ch < dev->nr_chnls; ch++) {
+			for (lun = 0; lun < dev->luns_per_chnl; lun++) {
+				idx = factory_blk_offset(dev, ch, lun);
+				offset = &f->blks[idx];
+
+				blkid = find_first_zero_bit(offset,
+							dev->blks_per_lun);
+				if (blkid >= dev->blks_per_lun)
+					continue;
+				set_bit(blkid, offset);
+
+				ppa.ppa = 0;
+				ppa.g.ch = ch;
+				ppa.g.lun = lun;
+				ppa.g.blk = blkid;
+				pr_debug("nvm: erase ppa (%u %u %u)\n",
+								ppa.g.ch,
+								ppa.g.lun,
+								ppa.g.blk);
+
+				erase_list[ppa_cnt] = ppa;
+				ppa_cnt++;
+				done = 0;
+
+				if (ppa_cnt == max_ppas)
+					return ppa_cnt;
+			}
+		}
+	}
+
+	return ppa_cnt;
+}
+
+static int nvm_fact_get_bb_tbl(struct nvm_dev *dev, struct ppa_addr ppa,
+					nvm_bb_update_fn *fn, void *priv)
+{
+	struct ppa_addr dev_ppa;
+	int ret;
+
+	dev_ppa = generic_to_dev_addr(dev, ppa);
+
+	ret = dev->ops->get_bb_tbl(dev, dev_ppa, dev->blks_per_lun, fn, priv);
+	if (ret)
+		pr_err("nvm: failed bb tbl for ch%u lun%u\n",
+							ppa.g.ch, ppa.g.blk);
+	return ret;
+}
+
+static int nvm_fact_select_blks(struct nvm_dev *dev, struct factory_blks *f)
+{
+	int ch, lun, ret;
+	struct ppa_addr ppa;
+
+	ppa.ppa = 0;
+	for (ch = 0; ch < dev->nr_chnls; ch++) {
+		for (lun = 0; lun < dev->luns_per_chnl; lun++) {
+			ppa.g.ch = ch;
+			ppa.g.lun = lun;
+
+			ret = nvm_fact_get_bb_tbl(dev, ppa, nvm_factory_blks,
+									f);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+int nvm_dev_factory(struct nvm_dev *dev, int flags)
+{
+	struct factory_blks f;
+	struct ppa_addr *ppas;
+	int ppa_cnt, ret = -ENOMEM;
+	int max_ppas = dev->ops->max_phys_sect / dev->nr_planes;
+	struct ppa_addr sysblk_ppas[MAX_SYSBLKS];
+	struct sysblk_scan s;
+
+	f.blks = kzalloc(factory_nblks(dev->blks_per_lun) * dev->nr_luns,
+								GFP_KERNEL);
+	if (!f.blks)
+		return ret;
+
+	ppas = kcalloc(max_ppas, sizeof(struct ppa_addr), GFP_KERNEL);
+	if (!ppas)
+		goto err_blks;
+
+	f.dev = dev;
+	f.flags = flags;
+
+	/* create list of blks to be erased */
+	ret = nvm_fact_select_blks(dev, &f);
+	if (ret)
+		goto err_ppas;
+
+	/* continue to erase until list of blks until empty */
+	while ((ppa_cnt = nvm_fact_get_blks(dev, ppas, max_ppas, &f)) > 0)
+		nvm_erase_ppa(dev, ppas, ppa_cnt);
+
+	/* mark host reserved blocks free */
+	if (flags & NVM_FACTORY_RESET_HOST_BLKS) {
+		nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
+		mutex_lock(&dev->mlock);
+		ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas,
+							sysblk_get_host_blks);
+		if (!ret)
+			ret = nvm_set_bb_tbl(dev, &s, NVM_BLK_T_FREE);
+		mutex_unlock(&dev->mlock);
+	}
+err_ppas:
+	kfree(ppas);
+err_blks:
+	kfree(f.blks);
+	return ret;
+}
+EXPORT_SYMBOL(nvm_dev_factory);
--- linux-4.4.0.orig/drivers/macintosh/via-pmu.c
+++ linux-4.4.0/drivers/macintosh/via-pmu.c
@@ -530,8 +530,9 @@
 	int timeout;
 	struct adb_request req;
 
-	out_8(&via[B], via[B] | TREQ);			/* negate TREQ */
-	out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK);	/* TACK in, TREQ out */
+	/* Negate TREQ. Set TACK to input and TREQ to output. */
+	out_8(&via[B], in_8(&via[B]) | TREQ);
+	out_8(&via[DIRB], (in_8(&via[DIRB]) | TREQ) & ~TACK);
 
 	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
 	timeout =  100000;
@@ -1453,8 +1454,8 @@
 	struct adb_request *req;
 	int bite = 0;
 
-	if (via[B] & TREQ) {
-		printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
+	if (in_8(&via[B]) & TREQ) {
+		printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B]));
 		out_8(&via[IFR], SR_INT);
 		return NULL;
 	}
--- linux-4.4.0.orig/drivers/macintosh/windfarm_pm112.c
+++ linux-4.4.0/drivers/macintosh/windfarm_pm112.c
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/reboot.h>
+#include <linux/slab.h>
 #include <asm/prom.h>
 #include <asm/smu.h>
 
@@ -133,14 +134,6 @@
 	s32 tmax;
 	int fmin;
 
-	/* Get PID params from the appropriate SAT */
-	hdr = smu_sat_get_sdb_partition(chip, 0xC8 + core, NULL);
-	if (hdr == NULL) {
-		printk(KERN_WARNING"windfarm: can't get CPU PID fan config\n");
-		return -EINVAL;
-	}
-	piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
-
 	/* Get FVT params to get Tmax; if not found, assume default */
 	hdr = smu_sat_get_sdb_partition(chip, 0xC4 + core, NULL);
 	if (hdr) {
@@ -153,6 +146,16 @@
 	if (tmax < cpu_all_tmax)
 		cpu_all_tmax = tmax;
 
+	kfree(hdr);
+
+	/* Get PID params from the appropriate SAT */
+	hdr = smu_sat_get_sdb_partition(chip, 0xC8 + core, NULL);
+	if (hdr == NULL) {
+		printk(KERN_WARNING"windfarm: can't get CPU PID fan config\n");
+		return -EINVAL;
+	}
+	piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
+
 	/*
 	 * Darwin has a minimum fan speed of 1000 rpm for the 4-way and
 	 * 515 for the 2-way.  That appears to be overkill, so for now,
@@ -175,6 +178,9 @@
 		pid.min = fmin;
 
 	wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+
+	kfree(hdr);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/macintosh/windfarm_smu_sat.c
+++ linux-4.4.0/drivers/macintosh/windfarm_smu_sat.c
@@ -22,14 +22,6 @@
 
 #define VERSION "1.0"
 
-#define DEBUG
-
-#ifdef DEBUG
-#define DBG(args...)	printk(args)
-#else
-#define DBG(args...)	do { } while(0)
-#endif
-
 /* If the cache is older than 800ms we'll refetch it */
 #define MAX_AGE		msecs_to_jiffies(800)
 
@@ -106,13 +98,10 @@
 		buf[i+2] = data[3];
 		buf[i+3] = data[2];
 	}
-#ifdef DEBUG
-	DBG(KERN_DEBUG "sat %d partition %x:", sat_id, id);
-	for (i = 0; i < len; ++i)
-		DBG(" %x", buf[i]);
-	DBG("\n");
-#endif
 
+	printk(KERN_DEBUG "sat %d partition %x:", sat_id, id);
+	print_hex_dump(KERN_DEBUG, "  ", DUMP_PREFIX_OFFSET,
+		       16, 1, buf, len, false);
 	if (size)
 		*size = len;
 	return (struct smu_sdbp_header *) buf;
@@ -132,13 +121,13 @@
 	if (err < 0)
 		return err;
 	sat->last_read = jiffies;
+
 #ifdef LOTSA_DEBUG
 	{
 		int i;
-		DBG(KERN_DEBUG "wf_sat_get: data is");
-		for (i = 0; i < 16; ++i)
-			DBG(" %.2x", sat->cache[i]);
-		DBG("\n");
+		printk(KERN_DEBUG "wf_sat_get: data is");
+		print_hex_dump(KERN_DEBUG, "  ", DUMP_PREFIX_OFFSET,
+			       16, 1, sat->cache, 16, false);
 	}
 #endif
 	return 0;
--- linux-4.4.0.orig/drivers/mailbox/Kconfig
+++ linux-4.4.0/drivers/mailbox/Kconfig
@@ -85,4 +85,13 @@
 	  Test client to help with testing new Controller driver
 	  implementations.
 
+config XGENE_SLIMPRO_MBOX
+	tristate "APM SoC X-Gene SLIMpro Mailbox Controller"
+	depends on ARCH_XGENE
+	help
+	  An implementation of the APM X-Gene Interprocessor Communication
+	  Mailbox (IPCM) between the ARM 64-bit cores and SLIMpro controller.
+	  It is used to send short messages between ARM64-bit cores and
+	  the SLIMpro Management Engine, primarily for PM. Say Y here if you
+	  want to use the APM X-Gene SLIMpro IPCM support.
 endif
--- linux-4.4.0.orig/drivers/mailbox/Makefile
+++ linux-4.4.0/drivers/mailbox/Makefile
@@ -17,3 +17,5 @@
 obj-$(CONFIG_BCM2835_MBOX)	+= bcm2835-mailbox.o
 
 obj-$(CONFIG_STI_MBOX)		+= mailbox-sti.o
+
+obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o
--- linux-4.4.0.orig/drivers/mailbox/mailbox-xgene-slimpro.c
+++ linux-4.4.0/drivers/mailbox/mailbox-xgene-slimpro.c
@@ -0,0 +1,284 @@
+/*
+ * APM X-Gene SLIMpro MailBox Driver
+ *
+ * Copyright (c) 2015, Applied Micro Circuits Corporation
+ * Author: Feng Kan fkan@apm.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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define MBOX_CON_NAME			"slimpro-mbox"
+#define MBOX_REG_SET_OFFSET		0x1000
+#define MBOX_CNT			8
+#define MBOX_STATUS_AVAIL_MASK		BIT(16)
+#define MBOX_STATUS_ACK_MASK		BIT(0)
+
+/* Configuration and Status Registers */
+#define REG_DB_IN		0x00
+#define REG_DB_DIN0		0x04
+#define REG_DB_DIN1		0x08
+#define REG_DB_OUT		0x10
+#define REG_DB_DOUT0		0x14
+#define REG_DB_DOUT1		0x18
+#define REG_DB_STAT		0x20
+#define REG_DB_STATMASK		0x24
+
+/**
+ * X-Gene SlimPRO mailbox channel information
+ *
+ * @dev:	Device to which it is attached
+ * @chan:	Pointer to mailbox communication channel
+ * @reg:	Base address to access channel registers
+ * @irq:	Interrupt number of the channel
+ * @rx_msg:	Received message storage
+ */
+struct slimpro_mbox_chan {
+	struct device		*dev;
+	struct mbox_chan	*chan;
+	void __iomem		*reg;
+	int			irq;
+	u32			rx_msg[3];
+};
+
+/**
+ * X-Gene SlimPRO Mailbox controller data
+ *
+ * X-Gene SlimPRO Mailbox controller has 8 commnunication channels.
+ * Each channel has a separate IRQ number assgined to it.
+ *
+ * @mb_ctrl:	Representation of the commnunication channel controller
+ * @mc:		Array of SlimPRO mailbox channels of the controller
+ * @chans:	Array of mailbox communication channels
+ *
+ */
+struct slimpro_mbox {
+	struct mbox_controller		mb_ctrl;
+	struct slimpro_mbox_chan	mc[MBOX_CNT];
+	struct mbox_chan		chans[MBOX_CNT];
+};
+
+static void mb_chan_send_msg(struct slimpro_mbox_chan *mb_chan, u32 *msg)
+{
+	writel(msg[1], mb_chan->reg + REG_DB_DOUT0);
+	writel(msg[2], mb_chan->reg + REG_DB_DOUT1);
+	writel(msg[0], mb_chan->reg + REG_DB_OUT);
+}
+
+static void mb_chan_recv_msg(struct slimpro_mbox_chan *mb_chan)
+{
+	mb_chan->rx_msg[1] = readl(mb_chan->reg + REG_DB_DIN0);
+	mb_chan->rx_msg[2] = readl(mb_chan->reg + REG_DB_DIN1);
+	mb_chan->rx_msg[0] = readl(mb_chan->reg + REG_DB_IN);
+}
+
+static int mb_chan_status_ack(struct slimpro_mbox_chan *mb_chan)
+{
+	u32 val = readl(mb_chan->reg + REG_DB_STAT);
+
+	if (val & MBOX_STATUS_ACK_MASK) {
+		writel(MBOX_STATUS_ACK_MASK, mb_chan->reg + REG_DB_STAT);
+		return 1;
+	}
+	return 0;
+}
+
+static int mb_chan_status_avail(struct slimpro_mbox_chan *mb_chan)
+{
+	u32 val = readl(mb_chan->reg + REG_DB_STAT);
+
+	if (val & MBOX_STATUS_AVAIL_MASK) {
+		mb_chan_recv_msg(mb_chan);
+		writel(MBOX_STATUS_AVAIL_MASK, mb_chan->reg + REG_DB_STAT);
+		return 1;
+	}
+	return 0;
+}
+
+static irqreturn_t slimpro_mbox_irq(int irq, void *id)
+{
+	struct slimpro_mbox_chan *mb_chan = id;
+
+	if (mb_chan_status_ack(mb_chan))
+		mbox_chan_txdone(mb_chan->chan, 0);
+
+	if (mb_chan_status_avail(mb_chan))
+		mbox_chan_received_data(mb_chan->chan, mb_chan->rx_msg);
+
+	return IRQ_HANDLED;
+}
+
+static int slimpro_mbox_send_data(struct mbox_chan *chan, void *msg)
+{
+	struct slimpro_mbox_chan *mb_chan = chan->con_priv;
+
+	mb_chan_send_msg(mb_chan, msg);
+	return 0;
+}
+
+static int slimpro_mbox_startup(struct mbox_chan *chan)
+{
+	struct slimpro_mbox_chan *mb_chan = chan->con_priv;
+	int rc;
+	u32 val;
+
+	rc = devm_request_irq(mb_chan->dev, mb_chan->irq, slimpro_mbox_irq, 0,
+			      MBOX_CON_NAME, mb_chan);
+	if (unlikely(rc)) {
+		dev_err(mb_chan->dev, "failed to register mailbox interrupt %d\n",
+			mb_chan->irq);
+		return rc;
+	}
+
+	/* Enable HW interrupt */
+	writel(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK,
+	       mb_chan->reg + REG_DB_STAT);
+	/* Unmask doorbell status interrupt */
+	val = readl(mb_chan->reg + REG_DB_STATMASK);
+	val &= ~(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
+	writel(val, mb_chan->reg + REG_DB_STATMASK);
+
+	return 0;
+}
+
+static void slimpro_mbox_shutdown(struct mbox_chan *chan)
+{
+	struct slimpro_mbox_chan *mb_chan = chan->con_priv;
+	u32 val;
+
+	/* Mask doorbell status interrupt */
+	val = readl(mb_chan->reg + REG_DB_STATMASK);
+	val |= (MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
+	writel(val, mb_chan->reg + REG_DB_STATMASK);
+
+	devm_free_irq(mb_chan->dev, mb_chan->irq, mb_chan);
+}
+
+static struct mbox_chan_ops slimpro_mbox_ops = {
+	.send_data = slimpro_mbox_send_data,
+	.startup = slimpro_mbox_startup,
+	.shutdown = slimpro_mbox_shutdown,
+};
+
+static int slimpro_mbox_probe(struct platform_device *pdev)
+{
+	struct slimpro_mbox *ctx;
+	struct resource *regs;
+	void __iomem *mb_base;
+	int rc;
+	int i;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(struct slimpro_mbox), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, ctx);
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mb_base = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
+	if (!mb_base)
+		return -ENOMEM;
+
+	/* Setup mailbox links */
+	for (i = 0; i < MBOX_CNT; i++) {
+		ctx->mc[i].irq = platform_get_irq(pdev, i);
+		if (ctx->mc[i].irq < 0) {
+			if (i == 0) {
+				dev_err(&pdev->dev, "no available IRQ\n");
+				return -EINVAL;
+			}
+			dev_info(&pdev->dev, "no IRQ for channel %d\n", i);
+			break;
+		}
+
+		ctx->mc[i].dev = &pdev->dev;
+		ctx->mc[i].reg = mb_base + i * MBOX_REG_SET_OFFSET;
+		ctx->mc[i].chan = &ctx->chans[i];
+		ctx->chans[i].con_priv = &ctx->mc[i];
+	}
+
+	/* Setup mailbox controller */
+	ctx->mb_ctrl.dev = &pdev->dev;
+	ctx->mb_ctrl.chans = ctx->chans;
+	ctx->mb_ctrl.txdone_irq = true;
+	ctx->mb_ctrl.ops = &slimpro_mbox_ops;
+	ctx->mb_ctrl.num_chans = i;
+
+	rc = mbox_controller_register(&ctx->mb_ctrl);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"APM X-Gene SLIMpro MailBox register failed:%d\n", rc);
+		return rc;
+	}
+
+	dev_info(&pdev->dev, "APM X-Gene SLIMpro MailBox registered\n");
+	return 0;
+}
+
+static int slimpro_mbox_remove(struct platform_device *pdev)
+{
+	struct slimpro_mbox *smb = platform_get_drvdata(pdev);
+
+	mbox_controller_unregister(&smb->mb_ctrl);
+	return 0;
+}
+
+static const struct of_device_id slimpro_of_match[] = {
+	{.compatible = "apm,xgene-slimpro-mbox" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, slimpro_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id slimpro_acpi_ids[] = {
+	{"APMC0D01", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids);
+#endif
+
+static struct platform_driver slimpro_mbox_driver = {
+	.probe	= slimpro_mbox_probe,
+	.remove = slimpro_mbox_remove,
+	.driver	= {
+		.name = "xgene-slimpro-mbox",
+		.of_match_table = of_match_ptr(slimpro_of_match),
+		.acpi_match_table = ACPI_PTR(slimpro_acpi_ids)
+	},
+};
+
+static int __init slimpro_mbox_init(void)
+{
+	return platform_driver_register(&slimpro_mbox_driver);
+}
+
+static void __exit slimpro_mbox_exit(void)
+{
+	platform_driver_unregister(&slimpro_mbox_driver);
+}
+
+subsys_initcall(slimpro_mbox_init);
+module_exit(slimpro_mbox_exit);
+
+MODULE_DESCRIPTION("APM X-Gene SLIMpro Mailbox Driver");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/mailbox/mailbox.c
+++ linux-4.4.0/drivers/mailbox/mailbox.c
@@ -104,11 +104,14 @@
 	/* Submit next message */
 	msg_submit(chan);
 
+	if (!mssg)
+		return;
+
 	/* Notify the client */
-	if (mssg && chan->cl->tx_done)
+	if (chan->cl->tx_done)
 		chan->cl->tx_done(chan->cl, mssg, r);
 
-	if (chan->cl->tx_block)
+	if (r != -ETIME && chan->cl->tx_block)
 		complete(&chan->tx_complete);
 }
 
@@ -261,7 +264,7 @@
 
 	msg_submit(chan);
 
-	if (chan->cl->tx_block && chan->active_req) {
+	if (chan->cl->tx_block) {
 		unsigned long wait;
 		int ret;
 
@@ -272,8 +275,8 @@
 
 		ret = wait_for_completion_timeout(&chan->tx_complete, wait);
 		if (ret == 0) {
-			t = -EIO;
-			tx_tick(chan, -EIO);
+			t = -ETIME;
+			tx_tick(chan, t);
 		}
 	}
 
@@ -386,11 +389,13 @@
 
 	of_property_for_each_string(np, "mbox-names", prop, mbox_name) {
 		if (!strncmp(name, mbox_name, strlen(name)))
-			break;
+			return mbox_request_channel(cl, index);
 		index++;
 	}
 
-	return mbox_request_channel(cl, index);
+	dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n",
+		__func__, name);
+	return ERR_PTR(-EINVAL);
 }
 EXPORT_SYMBOL_GPL(mbox_request_channel_byname);
 
--- linux-4.4.0.orig/drivers/mcb/mcb-parse.c
+++ linux-4.4.0/drivers/mcb/mcb-parse.c
@@ -57,7 +57,7 @@
 	mdev->id = GDD_DEV(reg1);
 	mdev->rev = GDD_REV(reg1);
 	mdev->var = GDD_VAR(reg1);
-	mdev->bar = GDD_BAR(reg1);
+	mdev->bar = GDD_BAR(reg2);
 	mdev->group = GDD_GRP(reg2);
 	mdev->inst = GDD_INS(reg2);
 
--- linux-4.4.0.orig/drivers/md/Kconfig
+++ linux-4.4.0/drivers/md/Kconfig
@@ -357,6 +357,7 @@
 config DM_RAID
        tristate "RAID 1/4/5/6/10 target"
        depends on BLK_DEV_DM
+       select MD_RAID0
        select MD_RAID1
        select MD_RAID10
        select MD_RAID456
--- linux-4.4.0.orig/drivers/md/bcache/alloc.c
+++ linux-4.4.0/drivers/md/bcache/alloc.c
@@ -285,8 +285,10 @@
 			break;						\
 									\
 		mutex_unlock(&(ca)->set->bucket_lock);			\
-		if (kthread_should_stop())				\
+		if (kthread_should_stop()) {				\
+			set_current_state(TASK_RUNNING);		\
 			return 0;					\
+		}							\
 									\
 		try_to_freeze();					\
 		schedule();						\
@@ -322,10 +324,11 @@
 		 * possibly issue discards to them, then we add the bucket to
 		 * the free list:
 		 */
-		while (!fifo_empty(&ca->free_inc)) {
+		while (1) {
 			long bucket;
 
-			fifo_pop(&ca->free_inc, bucket);
+			if (!fifo_pop(&ca->free_inc, bucket))
+				break;
 
 			if (ca->discard) {
 				mutex_unlock(&ca->set->bucket_lock);
@@ -371,7 +374,10 @@
 			if (!fifo_full(&ca->free_inc))
 				goto retry_invalidate;
 
-			bch_prio_write(ca);
+			if (bch_prio_write(ca, false) < 0) {
+				ca->invalidate_needs_gc = 1;
+				wake_up_gc(ca->set);
+			}
 		}
 	}
 }
@@ -406,7 +412,8 @@
 
 	finish_wait(&ca->set->bucket_wait, &w);
 out:
-	wake_up_process(ca->alloc_thread);
+	if (ca->alloc_thread)
+		wake_up_process(ca->alloc_thread);
 
 	trace_bcache_alloc(ca, reserve);
 
@@ -478,7 +485,7 @@
 		if (b == -1)
 			goto err;
 
-		k->ptr[i] = PTR(ca->buckets[b].gen,
+		k->ptr[i] = MAKE_PTR(ca->buckets[b].gen,
 				bucket_to_sector(c, b),
 				ca->sb.nr_this_dev);
 
@@ -513,15 +520,21 @@
 
 /*
  * We keep multiple buckets open for writes, and try to segregate different
- * write streams for better cache utilization: first we look for a bucket where
- * the last write to it was sequential with the current write, and failing that
- * we look for a bucket that was last used by the same task.
+ * write streams for better cache utilization: first we try to segregate flash
+ * only volume write streams from cached devices, secondly we look for a bucket
+ * where the last write to it was sequential with the current write, and
+ * failing that we look for a bucket that was last used by the same task.
  *
  * The ideas is if you've got multiple tasks pulling data into the cache at the
  * same time, you'll get better cache utilization if you try to segregate their
  * data and preserve locality.
  *
- * For example, say you've starting Firefox at the same time you're copying a
+ * For example, dirty sectors of flash only volume is not reclaimable, if their
+ * dirty sectors mixed with dirty sectors of cached device, such buckets will
+ * be marked as dirty and won't be reclaimed, though the dirty data of cached
+ * device have been written back to backend device.
+ *
+ * And say you've starting Firefox at the same time you're copying a
  * bunch of files. Firefox will likely end up being fairly hot and stay in the
  * cache awhile, but the data you copied might not be; if you wrote all that
  * data to the same buckets it'd get invalidated at the same time.
@@ -538,7 +551,10 @@
 	struct open_bucket *ret, *ret_task = NULL;
 
 	list_for_each_entry_reverse(ret, &c->data_buckets, list)
-		if (!bkey_cmp(&ret->key, search))
+		if (UUID_FLASH_ONLY(&c->uuids[KEY_INODE(&ret->key)]) !=
+		    UUID_FLASH_ONLY(&c->uuids[KEY_INODE(search)]))
+			continue;
+		else if (!bkey_cmp(&ret->key, search))
 			goto found;
 		else if (ret->last_write_point == write_point)
 			ret_task = ret;
--- linux-4.4.0.orig/drivers/md/bcache/bcache.h
+++ linux-4.4.0/drivers/md/bcache/bcache.h
@@ -333,6 +333,7 @@
 	/* Limit number of writeback bios in flight */
 	struct semaphore	in_flight;
 	struct task_struct	*writeback_thread;
+	struct workqueue_struct	*writeback_write_wq;
 
 	struct keybuf		writeback_keys;
 
@@ -425,7 +426,7 @@
 	 * until a gc finishes - otherwise we could pointlessly burn a ton of
 	 * cpu
 	 */
-	unsigned		invalidate_needs_gc:1;
+	unsigned		invalidate_needs_gc;
 
 	bool			discard; /* Get rid of? */
 
@@ -546,6 +547,7 @@
 	 */
 	wait_queue_head_t	btree_cache_wait;
 	struct task_struct	*btree_cache_alloc_lock;
+	spinlock_t		btree_cannibalize_lock;
 
 	/*
 	 * When we free a btree node, we increment the gen of the bucket the
@@ -593,8 +595,8 @@
 
 	/* Counts how many sectors bio_insert has added to the cache */
 	atomic_t		sectors_to_gc;
+	wait_queue_head_t	gc_wait;
 
-	wait_queue_head_t	moving_gc_wait;
 	struct keybuf		moving_gc_keys;
 	/* Number of moving GC bios in flight */
 	struct semaphore	moving_in_flight;
@@ -645,6 +647,10 @@
 	atomic_long_t		writeback_keys_done;
 	atomic_long_t		writeback_keys_failed;
 
+	atomic_long_t		reclaim;
+	atomic_long_t		flush_write;
+	atomic_long_t		retry_flush_write;
+
 	enum			{
 		ON_ERROR_UNREGISTER,
 		ON_ERROR_PANIC,
@@ -662,6 +668,8 @@
 
 #define BUCKET_HASH_BITS	12
 	struct hlist_head	bucket_hash[1 << BUCKET_HASH_BITS];
+
+	DECLARE_HEAP(struct btree *, flush_btree);
 };
 
 struct bbio {
@@ -879,7 +887,7 @@
 __printf(2, 3)
 bool bch_cache_set_error(struct cache_set *, const char *, ...);
 
-void bch_prio_write(struct cache *);
+int bch_prio_write(struct cache *ca, bool wait);
 void bch_write_bdev_super(struct cached_dev *, struct closure *);
 
 extern struct workqueue_struct *bcache_wq;
@@ -903,8 +911,9 @@
 
 int bch_flash_dev_create(struct cache_set *c, uint64_t size);
 
-int bch_cached_dev_attach(struct cached_dev *, struct cache_set *);
+int bch_cached_dev_attach(struct cached_dev *, struct cache_set *, uint8_t *);
 void bch_cached_dev_detach(struct cached_dev *);
+void bch_cached_dev_emit_change(struct cached_dev *);
 void bch_cached_dev_run(struct cached_dev *);
 void bcache_device_stop(struct bcache_device *);
 
--- linux-4.4.0.orig/drivers/md/bcache/bset.c
+++ linux-4.4.0/drivers/md/bcache/bset.c
@@ -317,7 +317,7 @@
 
 	b->page_order = page_order;
 
-	t->data = (void *) __get_free_pages(gfp, b->page_order);
+	t->data = (void *) __get_free_pages(__GFP_COMP|gfp, b->page_order);
 	if (!t->data)
 		goto err;
 
@@ -823,12 +823,22 @@
 	struct bset *i = bset_tree_last(b)->data;
 	struct bkey *m, *prev = NULL;
 	struct btree_iter iter;
+	struct bkey preceding_key_on_stack = ZERO_KEY;
+	struct bkey *preceding_key_p = &preceding_key_on_stack;
 
 	BUG_ON(b->ops->is_extents && !KEY_SIZE(k));
 
-	m = bch_btree_iter_init(b, &iter, b->ops->is_extents
-				? PRECEDING_KEY(&START_KEY(k))
-				: PRECEDING_KEY(k));
+	/*
+	 * If k has preceding key, preceding_key_p will be set to address
+	 *  of k's preceding key; otherwise preceding_key_p will be set
+	 * to NULL inside preceding_key().
+	 */
+	if (b->ops->is_extents)
+		preceding_key(&START_KEY(k), &preceding_key_p);
+	else
+		preceding_key(k, &preceding_key_p);
+
+	m = bch_btree_iter_init(b, &iter, preceding_key_p);
 
 	if (b->ops->insert_fixup(b, k, &iter, replace_key))
 		return status;
@@ -1070,7 +1080,7 @@
 static inline struct bkey *__bch_btree_iter_next(struct btree_iter *iter,
 						 btree_iter_cmp_fn *cmp)
 {
-	struct btree_iter_set unused;
+	struct btree_iter_set b __maybe_unused;
 	struct bkey *ret = NULL;
 
 	if (!btree_iter_end(iter)) {
@@ -1085,7 +1095,7 @@
 		}
 
 		if (iter->data->k == iter->data->end)
-			heap_pop(iter, unused, cmp);
+			heap_pop(iter, b, cmp);
 		else
 			heap_sift(iter, 0, cmp);
 	}
--- linux-4.4.0.orig/drivers/md/bcache/bset.h
+++ linux-4.4.0/drivers/md/bcache/bset.h
@@ -380,7 +380,8 @@
 
 /* Bkey utility code */
 
-#define bset_bkey_last(i)	bkey_idx((struct bkey *) (i)->d, (i)->keys)
+#define bset_bkey_last(i)	bkey_idx((struct bkey *) (i)->d, \
+					 (unsigned int)(i)->keys)
 
 static inline struct bkey *bset_bkey_idx(struct bset *i, unsigned idx)
 {
@@ -417,20 +418,26 @@
 	return __bch_cut_back(where, k);
 }
 
-#define PRECEDING_KEY(_k)					\
-({								\
-	struct bkey *_ret = NULL;				\
-								\
-	if (KEY_INODE(_k) || KEY_OFFSET(_k)) {			\
-		_ret = &KEY(KEY_INODE(_k), KEY_OFFSET(_k), 0);	\
-								\
-		if (!_ret->low)					\
-			_ret->high--;				\
-		_ret->low--;					\
-	}							\
-								\
-	_ret;							\
-})
+/*
+ * Pointer '*preceding_key_p' points to a memory object to store preceding
+ * key of k. If the preceding key does not exist, set '*preceding_key_p' to
+ * NULL. So the caller of preceding_key() needs to take care of memory
+ * which '*preceding_key_p' pointed to before calling preceding_key().
+ * Currently the only caller of preceding_key() is bch_btree_insert_key(),
+ * and it points to an on-stack variable, so the memory release is handled
+ * by stackframe itself.
+ */
+static inline void preceding_key(struct bkey *k, struct bkey **preceding_key_p)
+{
+	if (KEY_INODE(k) || KEY_OFFSET(k)) {
+		(**preceding_key_p) = KEY(KEY_INODE(k), KEY_OFFSET(k), 0);
+		if (!(*preceding_key_p)->low)
+			(*preceding_key_p)->high--;
+		(*preceding_key_p)->low--;
+	} else {
+		(*preceding_key_p) = NULL;
+	}
+}
 
 static inline bool bch_ptr_invalid(struct btree_keys *b, const struct bkey *k)
 {
@@ -530,14 +537,15 @@
 #ifdef CONFIG_BCACHE_DEBUG
 
 int __bch_count_data(struct btree_keys *);
-void __bch_check_keys(struct btree_keys *, const char *, ...);
+void __printf(2, 3) __bch_check_keys(struct btree_keys *, const char *, ...);
 void bch_dump_bset(struct btree_keys *, struct bset *, unsigned);
 void bch_dump_bucket(struct btree_keys *);
 
 #else
 
 static inline int __bch_count_data(struct btree_keys *b) { return -1; }
-static inline void __bch_check_keys(struct btree_keys *b, const char *fmt, ...) {}
+static inline void __printf(2, 3)
+	__bch_check_keys(struct btree_keys *b, const char *fmt, ...) {}
 static inline void bch_dump_bucket(struct btree_keys *b) {}
 void bch_dump_bset(struct btree_keys *, struct bset *, unsigned);
 
--- linux-4.4.0.orig/drivers/md/bcache/btree.c
+++ linux-4.4.0/drivers/md/bcache/btree.c
@@ -665,6 +665,7 @@
 	struct btree *b, *t;
 	unsigned long i, nr = sc->nr_to_scan;
 	unsigned long freed = 0;
+	unsigned int btree_cache_used;
 
 	if (c->shrinker_disabled)
 		return SHRINK_STOP;
@@ -686,12 +687,15 @@
 	 * IO can always make forward progress:
 	 */
 	nr /= c->btree_pages;
+	if (nr == 0)
+		nr = 1;
 	nr = min_t(unsigned long, nr, mca_can_free(c));
 
 	i = 0;
+	btree_cache_used = c->btree_cache_used;
 	list_for_each_entry_safe(b, t, &c->btree_cache_freeable, list) {
-		if (freed >= nr)
-			break;
+		if (nr <= 0)
+			goto out;
 
 		if (++i > 3 &&
 		    !mca_reap(b, 0, false)) {
@@ -699,9 +703,10 @@
 			rw_unlock(true, b);
 			freed++;
 		}
+		nr--;
 	}
 
-	for (i = 0; (nr--) && i < c->btree_cache_used; i++) {
+	for (;  (nr--) && i < btree_cache_used; i++) {
 		if (list_empty(&c->btree_cache))
 			goto out;
 
@@ -719,7 +724,7 @@
 	}
 out:
 	mutex_unlock(&c->bucket_lock);
-	return freed;
+	return freed * c->btree_pages;
 }
 
 static unsigned long bch_mca_count(struct shrinker *shrink,
@@ -793,7 +798,7 @@
 	mutex_init(&c->verify_lock);
 
 	c->verify_ondisk = (void *)
-		__get_free_pages(GFP_KERNEL, ilog2(bucket_pages(c)));
+		__get_free_pages(GFP_KERNEL|__GFP_COMP, ilog2(bucket_pages(c)));
 
 	c->verify_data = mca_bucket_alloc(c, &ZERO_KEY, GFP_KERNEL);
 
@@ -808,7 +813,10 @@
 	c->shrink.scan_objects = bch_mca_scan;
 	c->shrink.seeks = 4;
 	c->shrink.batch = c->btree_pages * 2;
-	register_shrinker(&c->shrink);
+
+	if (register_shrinker(&c->shrink))
+		pr_warn("bcache: %s: could not register shrinker",
+				__func__);
 
 	return 0;
 }
@@ -836,15 +844,17 @@
 
 static int mca_cannibalize_lock(struct cache_set *c, struct btree_op *op)
 {
-	struct task_struct *old;
-
-	old = cmpxchg(&c->btree_cache_alloc_lock, NULL, current);
-	if (old && old != current) {
+	spin_lock(&c->btree_cannibalize_lock);
+	if (likely(c->btree_cache_alloc_lock == NULL)) {
+		c->btree_cache_alloc_lock = current;
+	} else if (c->btree_cache_alloc_lock != current) {
 		if (op)
 			prepare_to_wait(&c->btree_cache_wait, &op->wait,
 					TASK_UNINTERRUPTIBLE);
+		spin_unlock(&c->btree_cannibalize_lock);
 		return -EINTR;
 	}
+	spin_unlock(&c->btree_cannibalize_lock);
 
 	return 0;
 }
@@ -879,10 +889,12 @@
  */
 static void bch_cannibalize_unlock(struct cache_set *c)
 {
+	spin_lock(&c->btree_cannibalize_lock);
 	if (c->btree_cache_alloc_lock == current) {
 		c->btree_cache_alloc_lock = NULL;
 		wake_up(&c->btree_cache_wait);
 	}
+	spin_unlock(&c->btree_cannibalize_lock);
 }
 
 static struct btree *mca_alloc(struct cache_set *c, struct btree_op *op,
@@ -956,7 +968,7 @@
 	return b;
 }
 
-/**
+/*
  * bch_btree_node_get - find a btree node in the cache and lock it, reading it
  * in from disk if necessary.
  *
@@ -1370,7 +1382,7 @@
 			if (__set_blocks(n1, n1->keys + n2->keys,
 					 block_bytes(b->c)) >
 			    btree_blocks(new_nodes[i]))
-				goto out_nocoalesce;
+				goto out_unlock_nocoalesce;
 
 			keys = n2->keys;
 			/* Take the key of the node we're getting rid of */
@@ -1399,7 +1411,7 @@
 
 		if (__bch_keylist_realloc(&keylist,
 					  bkey_u64s(&new_nodes[i]->key)))
-			goto out_nocoalesce;
+			goto out_unlock_nocoalesce;
 
 		bch_btree_node_write(new_nodes[i], &cl);
 		bch_keylist_add(&keylist, &new_nodes[i]->key);
@@ -1445,6 +1457,10 @@
 	/* Invalidated our iterator */
 	return -EINTR;
 
+out_unlock_nocoalesce:
+	for (i = 0; i < nodes; i++)
+		mutex_unlock(&new_nodes[i]->write_lock);
+
 out_nocoalesce:
 	closure_sync(&cl);
 	bch_keylist_free(&keylist);
@@ -1741,6 +1757,7 @@
 	do {
 		ret = btree_root(gc_root, c, &op, &writes, &stats);
 		closure_sync(&writes);
+		cond_resched();
 
 		if (ret && ret != -EAGAIN)
 			pr_warn("gc failed!");
@@ -1761,33 +1778,34 @@
 	bch_moving_gc(c);
 }
 
-static int bch_gc_thread(void *arg)
+static bool gc_should_run(struct cache_set *c)
 {
-	struct cache_set *c = arg;
 	struct cache *ca;
 	unsigned i;
 
-	while (1) {
-again:
-		bch_btree_gc(c);
+	for_each_cache(ca, c, i)
+		if (ca->invalidate_needs_gc)
+			return true;
 
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (kthread_should_stop())
-			break;
+	if (atomic_read(&c->sectors_to_gc) < 0)
+		return true;
 
-		mutex_lock(&c->bucket_lock);
+	return false;
+}
 
-		for_each_cache(ca, c, i)
-			if (ca->invalidate_needs_gc) {
-				mutex_unlock(&c->bucket_lock);
-				set_current_state(TASK_RUNNING);
-				goto again;
-			}
+static int bch_gc_thread(void *arg)
+{
+	struct cache_set *c = arg;
 
-		mutex_unlock(&c->bucket_lock);
+	while (1) {
+		wait_event_interruptible(c->gc_wait,
+			   kthread_should_stop() || gc_should_run(c));
 
-		try_to_freeze();
-		schedule();
+		if (kthread_should_stop())
+			break;
+
+		set_gc_sectors(c);
+		bch_btree_gc(c);
 	}
 
 	return 0;
@@ -1795,11 +1813,10 @@
 
 int bch_gc_thread_start(struct cache_set *c)
 {
-	c->gc_thread = kthread_create(bch_gc_thread, c, "bcache_gc");
+	c->gc_thread = kthread_run(bch_gc_thread, c, "bcache_gc");
 	if (IS_ERR(c->gc_thread))
 		return PTR_ERR(c->gc_thread);
 
-	set_task_state(c->gc_thread, TASK_INTERRUPTIBLE);
 	return 0;
 }
 
@@ -1865,14 +1882,17 @@
 	 */
 	for_each_cache(ca, c, i) {
 		for_each_bucket(b, ca) {
-			if (fifo_full(&ca->free[RESERVE_PRIO]))
+			if (fifo_full(&ca->free[RESERVE_PRIO]) &&
+			    fifo_full(&ca->free[RESERVE_BTREE]))
 				break;
 
 			if (bch_can_invalidate_bucket(ca, b) &&
 			    !GC_MARK(b)) {
 				__bch_invalidate_one_bucket(ca, b);
-				fifo_push(&ca->free[RESERVE_PRIO],
-					  b - ca->buckets);
+				if (!fifo_push(&ca->free[RESERVE_PRIO],
+				   b - ca->buckets))
+					fifo_push(&ca->free[RESERVE_BTREE],
+						  b - ca->buckets);
 			}
 		}
 	}
@@ -2162,8 +2182,10 @@
 		rw_lock(true, b, b->level);
 
 		if (b->key.ptr[0] != btree_ptr ||
-		    b->seq != seq + 1)
+                   b->seq != seq + 1) {
+			op->lock = b->level;
 			goto out;
+               }
 	}
 
 	SET_KEY_PTRS(check_key, 1);
@@ -2363,7 +2385,7 @@
 	struct keybuf *buf = refill->buf;
 	int ret = MAP_CONTINUE;
 
-	if (bkey_cmp(k, refill->end) >= 0) {
+	if (bkey_cmp(k, refill->end) > 0) {
 		ret = MAP_DONE;
 		goto out;
 	}
--- linux-4.4.0.orig/drivers/md/bcache/btree.h
+++ linux-4.4.0/drivers/md/bcache/btree.h
@@ -260,8 +260,7 @@
 
 static inline void wake_up_gc(struct cache_set *c)
 {
-	if (c->gc_thread)
-		wake_up_process(c->gc_thread);
+	wake_up(&c->gc_wait);
 }
 
 #define MAP_DONE	0
--- linux-4.4.0.orig/drivers/md/bcache/closure.c
+++ linux-4.4.0/drivers/md/bcache/closure.c
@@ -15,14 +15,20 @@
 {
 	int r = flags & CLOSURE_REMAINING_MASK;
 
-	BUG_ON(flags & CLOSURE_GUARD_MASK);
-	BUG_ON(!r && (flags & ~CLOSURE_DESTRUCTOR));
+	if (WARN(flags & CLOSURE_GUARD_MASK,
+		 "closure has guard bits set: %x (%u)",
+		 flags & CLOSURE_GUARD_MASK, (unsigned) __fls(r)))
+		r &= ~CLOSURE_GUARD_MASK;
 
 	/* Must deliver precisely one wakeup */
 	if (r == 1 && (flags & CLOSURE_SLEEPING))
 		wake_up_process(cl->task);
 
 	if (!r) {
+		WARN(flags & ~CLOSURE_DESTRUCTOR,
+		     "closure ref hit 0 with incorrect flags set: %x (%u)",
+		     flags & ~CLOSURE_DESTRUCTOR, (unsigned) __fls(flags));
+
 		if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) {
 			atomic_set(&cl->remaining,
 				   CLOSURE_REMAINING_INITIALIZER);
@@ -49,7 +55,7 @@
 }
 EXPORT_SYMBOL(closure_sub);
 
-/**
+/*
  * closure_put - decrement a closure's refcount
  */
 void closure_put(struct closure *cl)
@@ -58,7 +64,7 @@
 }
 EXPORT_SYMBOL(closure_put);
 
-/**
+/*
  * closure_wake_up - wake up all closures on a wait list, without memory barrier
  */
 void __closure_wake_up(struct closure_waitlist *wait_list)
@@ -93,9 +99,9 @@
 
 /**
  * closure_wait - add a closure to a waitlist
- *
- * @waitlist will own a ref on @cl, which will be released when
+ * @waitlist: will own a ref on @cl, which will be released when
  * closure_wake_up() is called on @waitlist.
+ * @cl: closure pointer.
  *
  */
 bool closure_wait(struct closure_waitlist *waitlist, struct closure *cl)
--- linux-4.4.0.orig/drivers/md/bcache/extents.c
+++ linux-4.4.0/drivers/md/bcache/extents.c
@@ -533,7 +533,6 @@
 static bool bch_extent_bad(struct btree_keys *bk, const struct bkey *k)
 {
 	struct btree *b = container_of(bk, struct btree, keys);
-	struct bucket *g;
 	unsigned i, stale;
 
 	if (!KEY_PTRS(k) ||
@@ -548,7 +547,6 @@
 		return false;
 
 	for (i = 0; i < KEY_PTRS(k); i++) {
-		g = PTR_BUCKET(b->c, k, i);
 		stale = ptr_stale(b->c, k, i);
 
 		btree_bug_on(stale > 96, b,
@@ -584,7 +582,7 @@
 		return false;
 
 	for (i = 0; i < KEY_PTRS(l); i++)
-		if (l->ptr[i] + PTR(0, KEY_SIZE(l), 0) != r->ptr[i] ||
+		if (l->ptr[i] + MAKE_PTR(0, KEY_SIZE(l), 0) != r->ptr[i] ||
 		    PTR_BUCKET_NR(b->c, l, i) != PTR_BUCKET_NR(b->c, r, i))
 			return false;
 
--- linux-4.4.0.orig/drivers/md/bcache/journal.c
+++ linux-4.4.0/drivers/md/bcache/journal.c
@@ -309,6 +309,18 @@
 	}
 }
 
+bool is_discard_enabled(struct cache_set *s)
+{
+	struct cache *ca;
+	unsigned int i;
+
+	for_each_cache(ca, s, i)
+		if (ca->discard)
+			return true;
+
+	return false;
+}
+
 int bch_journal_replay(struct cache_set *s, struct list_head *list)
 {
 	int ret = 0, keys = 0, entries = 0;
@@ -322,9 +334,17 @@
 	list_for_each_entry(i, list, list) {
 		BUG_ON(i->pin && atomic_read(i->pin) != 1);
 
-		cache_set_err_on(n != i->j.seq, s,
-"bcache: journal entries %llu-%llu missing! (replaying %llu-%llu)",
-				 n, i->j.seq - 1, start, end);
+		if (n != i->j.seq) {
+			if (n == start && is_discard_enabled(s))
+				pr_info("bcache: journal entries %llu-%llu may be discarded! (replaying %llu-%llu)",
+					n, i->j.seq - 1, start, end);
+			else {
+				pr_err("bcache: journal entries %llu-%llu missing! (replaying %llu-%llu)",
+					n, i->j.seq - 1, start, end);
+				ret = -EIO;
+				goto err;
+			}
+		}
 
 		for (k = i->j.start;
 		     k < bset_bkey_last(&i->j);
@@ -362,6 +382,12 @@
 }
 
 /* Journalling */
+#define journal_max_cmp(l, r) \
+	(fifo_idx(&c->journal.pin, btree_current_write(l)->journal) < \
+	 fifo_idx(&(c)->journal.pin, btree_current_write(r)->journal))
+#define journal_min_cmp(l, r) \
+	(fifo_idx(&c->journal.pin, btree_current_write(l)->journal) > \
+	 fifo_idx(&(c)->journal.pin, btree_current_write(r)->journal))
 
 static void btree_flush_write(struct cache_set *c)
 {
@@ -369,28 +395,41 @@
 	 * Try to find the btree node with that references the oldest journal
 	 * entry, best is our current candidate and is locked if non NULL:
 	 */
-	struct btree *b, *best;
-	unsigned i;
-retry:
-	best = NULL;
+	struct btree *b;
+	int i;
+
+	atomic_long_inc(&c->flush_write);
 
-	for_each_cached_btree(b, c, i)
-		if (btree_current_write(b)->journal) {
-			if (!best)
-				best = b;
-			else if (journal_pin_cmp(c,
-					btree_current_write(best)->journal,
-					btree_current_write(b)->journal)) {
-				best = b;
+retry:
+	spin_lock(&c->journal.lock);
+	if (heap_empty(&c->flush_btree)) {
+		for_each_cached_btree(b, c, i)
+			if (btree_current_write(b)->journal) {
+				if (!heap_full(&c->flush_btree))
+					heap_add(&c->flush_btree, b,
+						 journal_max_cmp);
+				else if (journal_max_cmp(b,
+					 heap_peek(&c->flush_btree))) {
+					c->flush_btree.data[0] = b;
+					heap_sift(&c->flush_btree, 0,
+						  journal_max_cmp);
+				}
 			}
-		}
 
-	b = best;
+		for (i = c->flush_btree.used / 2 - 1; i >= 0; --i)
+			heap_sift(&c->flush_btree, i, journal_min_cmp);
+	}
+
+	b = NULL;
+	heap_pop(&c->flush_btree, b, journal_min_cmp);
+	spin_unlock(&c->journal.lock);
+
 	if (b) {
 		mutex_lock(&b->write_lock);
 		if (!btree_current_write(b)->journal) {
 			mutex_unlock(&b->write_lock);
 			/* We raced */
+			atomic_long_inc(&c->retry_flush_write);
 			goto retry;
 		}
 
@@ -470,7 +509,9 @@
 	struct cache *ca;
 	uint64_t last_seq;
 	unsigned iter, n = 0;
-	atomic_t p;
+	atomic_t p __maybe_unused;
+
+	atomic_long_inc(&c->reclaim);
 
 	while (!atomic_read(&fifo_front(&c->journal.pin)))
 		fifo_pop(&c->journal.pin, p);
@@ -508,16 +549,16 @@
 			continue;
 
 		ja->cur_idx = next;
-		k->ptr[n++] = PTR(0,
+		k->ptr[n++] = MAKE_PTR(0,
 				  bucket_to_sector(c, ca->sb.d[ja->cur_idx]),
 				  ca->sb.nr_this_dev);
 	}
 
-	bkey_init(k);
-	SET_KEY_PTRS(k, n);
-
-	if (n)
+	if (n) {
+		bkey_init(k);
+		SET_KEY_PTRS(k, n);
 		c->journal.blocks_free = c->sb.bucket_size >> c->block_bits;
+	}
 out:
 	if (!journal_full(&c->journal))
 		__closure_wake_up(&c->journal.wait);
@@ -569,6 +610,7 @@
 }
 
 static void journal_write_unlock(struct closure *cl)
+	__releases(&c->journal.lock)
 {
 	struct cache_set *c = container_of(cl, struct cache_set, journal.io);
 
@@ -641,6 +683,9 @@
 		ca->journal.seq[ca->journal.cur_idx] = w->data->seq;
 	}
 
+	/* If KEY_PTRS(k) == 0, this jset gets lost in air */
+	BUG_ON(i == 0);
+
 	atomic_dec_bug(&fifo_back(&c->journal.pin));
 	bch_journal_next(&c->journal);
 	journal_reclaim(c);
@@ -679,6 +724,7 @@
 
 static struct journal_write *journal_wait_for_write(struct cache_set *c,
 						    unsigned nkeys)
+	__acquires(&c->journal.lock)
 {
 	size_t sectors;
 	struct closure cl;
@@ -814,9 +860,10 @@
 	j->w[0].c = c;
 	j->w[1].c = c;
 
-	if (!(init_fifo(&j->pin, JOURNAL_PIN, GFP_KERNEL)) ||
-	    !(j->w[0].data = (void *) __get_free_pages(GFP_KERNEL, JSET_BITS)) ||
-	    !(j->w[1].data = (void *) __get_free_pages(GFP_KERNEL, JSET_BITS)))
+	if (!(init_heap(&c->flush_btree, 128, GFP_KERNEL)) ||
+	    !(init_fifo(&j->pin, JOURNAL_PIN, GFP_KERNEL)) ||
+	    !(j->w[0].data = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP, JSET_BITS)) ||
+	    !(j->w[1].data = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP, JSET_BITS)))
 		return -ENOMEM;
 
 	return 0;
--- linux-4.4.0.orig/drivers/md/bcache/request.c
+++ linux-4.4.0/drivers/md/bcache/request.c
@@ -196,14 +196,12 @@
 	struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
 	struct bio *bio = op->bio, *n;
 
-	if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) {
-		set_gc_sectors(op->c);
-		wake_up_gc(op->c);
-	}
-
 	if (op->bypass)
 		return bch_data_invalidate(cl);
 
+	if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0)
+		wake_up_gc(op->c);
+
 	/*
 	 * Journal writes are marked REQ_FLUSH; if the original write was a
 	 * flush, it'll wait on the journal write.
@@ -296,6 +294,7 @@
 
 /**
  * bch_data_insert - stick some data in the cache
+ * @cl: closure pointer.
  *
  * This is the starting point for any data to end up in a cache device; it could
  * be from a normal write, or a writeback write, or a write to a flash only
@@ -470,6 +469,7 @@
 	unsigned		recoverable:1;
 	unsigned		write:1;
 	unsigned		read_dirty_data:1;
+	unsigned		cache_missed:1;
 
 	unsigned long		start_time;
 
@@ -634,11 +634,11 @@
 static void search_free(struct closure *cl)
 {
 	struct search *s = container_of(cl, struct search, cl);
-	bio_complete(s);
 
 	if (s->iop.bio)
 		bio_put(s->iop.bio);
 
+	bio_complete(s);
 	closure_debug_destroy(cl);
 	mempool_free(s, s->d->c->search);
 }
@@ -655,6 +655,7 @@
 
 	s->orig_bio		= bio;
 	s->cache_miss		= NULL;
+	s->cache_missed		= 0;
 	s->d			= d;
 	s->recoverable		= 1;
 	s->write		= (bio->bi_rw & REQ_WRITE) != 0;
@@ -710,7 +711,14 @@
 	struct search *s = container_of(cl, struct search, cl);
 	struct bio *bio = &s->bio.bio;
 
-	if (s->recoverable) {
+	/*
+	 * If read request hit dirty data (s->read_dirty_data is true),
+	 * then recovery a failed read request from cached device may
+	 * get a stale data back. So read failure recovery is only
+	 * permitted when read request hit clean data in cache device,
+	 * or when cache read race happened.
+	 */
+	if (s->recoverable && !s->read_dirty_data) {
 		/* Retry from the backing device: */
 		trace_bcache_read_retry(s->orig_bio);
 
@@ -771,7 +779,7 @@
 	struct cached_dev *dc = container_of(s->d, struct cached_dev, disk);
 
 	bch_mark_cache_accounting(s->iop.c, s->d,
-				  !s->cache_miss, s->iop.bypass);
+				  !s->cache_missed, s->iop.bypass);
 	trace_bcache_read(s->orig_bio, !s->cache_miss, s->iop.bypass);
 
 	if (s->iop.error)
@@ -790,6 +798,8 @@
 	struct cached_dev *dc = container_of(s->d, struct cached_dev, disk);
 	struct bio *miss, *cache_bio;
 
+	s->cache_missed = 1;
+
 	if (s->cache_miss || s->iop.bypass) {
 		miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split);
 		ret = miss == bio ? MAP_DONE : MAP_CONTINUE;
@@ -1016,7 +1026,7 @@
 	struct request_queue *q = bdev_get_queue(dc->bdev);
 	int ret = 0;
 
-	if (bdi_congested(&q->backing_dev_info, bits))
+	if (bdi_congested(q->backing_dev_info, bits))
 		return 1;
 
 	if (cached_dev_get(dc)) {
@@ -1025,7 +1035,7 @@
 
 		for_each_cache(ca, d->c, i) {
 			q = bdev_get_queue(ca->bdev);
-			ret |= bdi_congested(&q->backing_dev_info, bits);
+			ret |= bdi_congested(q->backing_dev_info, bits);
 		}
 
 		cached_dev_put(dc);
@@ -1039,7 +1049,7 @@
 	struct gendisk *g = dc->disk.disk;
 
 	g->queue->make_request_fn		= cached_dev_make_request;
-	g->queue->backing_dev_info.congested_fn = cached_dev_congested;
+	g->queue->backing_dev_info->congested_fn = cached_dev_congested;
 	dc->disk.cache_miss			= cached_dev_cache_miss;
 	dc->disk.ioctl				= cached_dev_ioctl;
 }
@@ -1132,7 +1142,7 @@
 
 	for_each_cache(ca, d->c, i) {
 		q = bdev_get_queue(ca->bdev);
-		ret |= bdi_congested(&q->backing_dev_info, bits);
+		ret |= bdi_congested(q->backing_dev_info, bits);
 	}
 
 	return ret;
@@ -1143,7 +1153,7 @@
 	struct gendisk *g = d->disk;
 
 	g->queue->make_request_fn		= flash_dev_make_request;
-	g->queue->backing_dev_info.congested_fn = flash_dev_congested;
+	g->queue->backing_dev_info->congested_fn = flash_dev_congested;
 	d->cache_miss				= flash_dev_cache_miss;
 	d->ioctl				= flash_dev_ioctl;
 }
--- linux-4.4.0.orig/drivers/md/bcache/super.c
+++ linux-4.4.0/drivers/md/bcache/super.c
@@ -518,12 +518,29 @@
 	closure_sync(cl);
 }
 
-void bch_prio_write(struct cache *ca)
+int bch_prio_write(struct cache *ca, bool wait)
 {
 	int i;
 	struct bucket *b;
 	struct closure cl;
 
+	pr_debug("free_prio=%zu, free_none=%zu, free_inc=%zu",
+		 fifo_used(&ca->free[RESERVE_PRIO]),
+		 fifo_used(&ca->free[RESERVE_NONE]),
+		 fifo_used(&ca->free_inc));
+
+	/*
+	 * Pre-check if there are enough free buckets. In the non-blocking
+	 * scenario it's better to fail early rather than starting to allocate
+	 * buckets and do a cleanup later in case of failure.
+	 */
+	if (!wait) {
+		size_t avail = fifo_used(&ca->free[RESERVE_PRIO]) +
+			       fifo_used(&ca->free[RESERVE_NONE]);
+		if (prio_buckets(ca) > avail)
+			return -ENOMEM;
+	}
+
 	closure_init_stack(&cl);
 
 	lockdep_assert_held(&ca->set->bucket_lock);
@@ -533,9 +550,6 @@
 	atomic_long_add(ca->sb.bucket_size * prio_buckets(ca),
 			&ca->meta_sectors_written);
 
-	//pr_debug("free %zu, free_inc %zu, unused %zu", fifo_used(&ca->free),
-	//	 fifo_used(&ca->free_inc), fifo_used(&ca->unused));
-
 	for (i = prio_buckets(ca) - 1; i >= 0; --i) {
 		long bucket;
 		struct prio_set *p = ca->disk_buckets;
@@ -553,7 +567,7 @@
 		p->magic	= pset_magic(&ca->sb);
 		p->csum		= bch_crc64(&p->magic, bucket_bytes(ca) - 8);
 
-		bucket = bch_bucket_alloc(ca, RESERVE_PRIO, true);
+		bucket = bch_bucket_alloc(ca, RESERVE_PRIO, wait);
 		BUG_ON(bucket == -1);
 
 		mutex_unlock(&ca->set->bucket_lock);
@@ -582,6 +596,7 @@
 
 		ca->prio_last_buckets[i] = ca->prio_buckets[i];
 	}
+	return 0;
 }
 
 static void prio_read(struct cache *ca, uint64_t bucket)
@@ -685,6 +700,8 @@
 	WARN(sysfs_create_link(&d->kobj, &c->kobj, "cache") ||
 	     sysfs_create_link(&c->kobj, &d->kobj, d->name),
 	     "Couldn't create device <-> cache set symlinks");
+
+	clear_bit(BCACHE_DEV_UNLINK_DONE, &d->flags);
 }
 
 static void bcache_device_detach(struct bcache_device *d)
@@ -743,7 +760,7 @@
 }
 
 static int bcache_device_init(struct bcache_device *d, unsigned block_size,
-			      sector_t sectors)
+			      sector_t sectors, struct block_device *cached_bdev)
 {
 	struct request_queue *q;
 	size_t n;
@@ -800,7 +817,7 @@
 	blk_queue_make_request(q, NULL);
 	d->disk->queue			= q;
 	q->queuedata			= d;
-	q->backing_dev_info.congested_data = d;
+	q->backing_dev_info->congested_data = d;
 	q->limits.max_hw_sectors	= UINT_MAX;
 	q->limits.max_sectors		= UINT_MAX;
 	q->limits.max_segment_size	= UINT_MAX;
@@ -810,6 +827,21 @@
 	q->limits.io_min		= block_size;
 	q->limits.logical_block_size	= block_size;
 	q->limits.physical_block_size	= block_size;
+
+	if (q->limits.logical_block_size > PAGE_SIZE && cached_bdev) {
+		/*
+		 * This should only happen with BCACHE_SB_VERSION_BDEV.
+		 * Block/page size is checked for BCACHE_SB_VERSION_CDEV.
+		 */
+		pr_info("%s: sb/logical block size (%u) greater than page size "
+			"(%lu) falling back to device logical block size (%u)",
+			d->disk->disk_name, q->limits.logical_block_size,
+			PAGE_SIZE, bdev_logical_block_size(cached_bdev));
+
+		/* This also adjusts physical block size/min io size if needed */
+		blk_queue_logical_block_size(q, bdev_logical_block_size(cached_bdev));
+	}
+
 	set_bit(QUEUE_FLAG_NONROT,	&d->disk->queue->queue_flags);
 	clear_bit(QUEUE_FLAG_ADD_RANDOM, &d->disk->queue->queue_flags);
 	set_bit(QUEUE_FLAG_DISCARD,	&d->disk->queue->queue_flags);
@@ -832,7 +864,7 @@
 	c->cached_dev_sectors = sectors;
 }
 
-void bch_cached_dev_run(struct cached_dev *dc)
+void bch_cached_dev_emit_change(struct cached_dev *dc)
 {
 	struct bcache_device *d = &dc->disk;
 	char buf[SB_LABEL_SIZE + 1];
@@ -847,8 +879,20 @@
 	buf[SB_LABEL_SIZE] = '\0';
 	env[2] = kasprintf(GFP_KERNEL, "CACHED_LABEL=%s", buf);
 
-	if (atomic_xchg(&dc->running, 1))
+	/* won't show up in the uevent file, use udevadm monitor -e instead
+	 * only class / kset properties are persistent */
+	kobject_uevent_env(&disk_to_dev(d->disk)->kobj, KOBJ_CHANGE, env);
+	kfree(env[1]);
+	kfree(env[2]);
+
+}
+
+void bch_cached_dev_run(struct cached_dev *dc)
+{
+	struct bcache_device *d = &dc->disk;
+	if (atomic_xchg(&dc->running, 1)) {
 		return;
+	}
 
 	if (!d->c &&
 	    BDEV_STATE(&dc->sb) != BDEV_STATE_NONE) {
@@ -862,11 +906,9 @@
 
 	add_disk(d->disk);
 	bd_link_disk_holder(dc->bdev, dc->disk.disk);
-	/* won't show up in the uevent file, use udevadm monitor -e instead
-	 * only class / kset properties are persistent */
-	kobject_uevent_env(&disk_to_dev(d->disk)->kobj, KOBJ_CHANGE, env);
-	kfree(env[1]);
-	kfree(env[2]);
+
+	/* emit change event */
+	bch_cached_dev_emit_change(dc);
 
 	if (sysfs_create_link(&d->kobj, &disk_to_dev(d->disk)->kobj, "dev") ||
 	    sysfs_create_link(&disk_to_dev(d->disk)->kobj, &d->kobj, "bcache"))
@@ -885,12 +927,19 @@
 
 	mutex_lock(&bch_register_lock);
 
+	cancel_delayed_work_sync(&dc->writeback_rate_update);
+	if (!IS_ERR_OR_NULL(dc->writeback_thread)) {
+		kthread_stop(dc->writeback_thread);
+		dc->writeback_thread = NULL;
+	}
+
 	memset(&dc->sb.set_uuid, 0, 16);
 	SET_BDEV_STATE(&dc->sb, BDEV_STATE_NONE);
 
 	bch_write_bdev_super(dc, &cl);
 	closure_sync(&cl);
 
+	calc_cached_dev_sectors(dc->disk.c);
 	bcache_device_detach(&dc->disk);
 	list_move(&dc->list, &uncached_devices);
 
@@ -925,15 +974,18 @@
 	cached_dev_put(dc);
 }
 
-int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
+int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
+			  uint8_t *set_uuid)
 {
 	uint32_t rtime = cpu_to_le32(get_seconds());
 	struct uuid_entry *u;
 	char buf[BDEVNAME_SIZE];
+	struct cached_dev *exist_dc, *t;
 
 	bdevname(dc->bdev, buf);
 
-	if (memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16))
+	if ((set_uuid && memcmp(set_uuid, c->sb.set_uuid, 16)) ||
+	    (!set_uuid && memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16)))
 		return -ENOENT;
 
 	if (dc->disk.c) {
@@ -953,6 +1005,16 @@
 		return -EINVAL;
 	}
 
+	/* Check whether already attached */
+	list_for_each_entry_safe(exist_dc, t, &c->cached_devs, list) {
+		if (!memcmp(dc->sb.uuid, exist_dc->sb.uuid, 16)) {
+			pr_err("Tried to attach %s but duplicate UUID already attached",
+				buf);
+
+			return -EINVAL;
+		}
+	}
+
 	u = uuid_find(c, dc->sb.uuid);
 
 	if (u &&
@@ -1010,11 +1072,15 @@
 	 */
 	atomic_set(&dc->count, 1);
 
-	if (bch_cached_dev_writeback_start(dc))
+	/* Block writeback thread, but spawn it */
+	down_write(&dc->writeback_lock);
+	if (bch_cached_dev_writeback_start(dc)) {
+		up_write(&dc->writeback_lock);
 		return -ENOMEM;
+	}
 
 	if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
-		bch_sectors_dirty_init(dc);
+		bch_sectors_dirty_init(&dc->disk);
 		atomic_set(&dc->has_dirty, 1);
 		atomic_inc(&dc->count);
 		bch_writeback_queue(dc);
@@ -1023,6 +1089,9 @@
 	bch_cached_dev_run(dc);
 	bcache_device_link(&dc->disk, c, "bdev");
 
+	/* Allow the writeback thread to proceed */
+	up_write(&dc->writeback_lock);
+
 	pr_info("Caching %s as %s on set %pU",
 		bdevname(dc->bdev, buf), dc->disk.disk->disk_name,
 		dc->disk.c->sb.set_uuid);
@@ -1044,6 +1113,8 @@
 	cancel_delayed_work_sync(&dc->writeback_rate_update);
 	if (!IS_ERR_OR_NULL(dc->writeback_thread))
 		kthread_stop(dc->writeback_thread);
+	if (dc->writeback_write_wq)
+		destroy_workqueue(dc->writeback_write_wq);
 
 	mutex_lock(&bch_register_lock);
 
@@ -1108,16 +1179,16 @@
 			q->limits.raid_partial_stripes_expensive;
 
 	ret = bcache_device_init(&dc->disk, block_size,
-			 dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
+			 dc->bdev->bd_part->nr_sects - dc->sb.data_offset, dc->bdev);
 	if (ret)
 		return ret;
 
 	set_capacity(dc->disk.disk,
 		     dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
 
-	dc->disk.disk->queue->backing_dev_info.ra_pages =
-		max(dc->disk.disk->queue->backing_dev_info.ra_pages,
-		    q->backing_dev_info.ra_pages);
+	dc->disk.disk->queue->backing_dev_info->ra_pages =
+		max(dc->disk.disk->queue->backing_dev_info->ra_pages,
+		    q->backing_dev_info->ra_pages);
 
 	bch_cached_dev_request_init(dc);
 	bch_cached_dev_writeback_init(dc);
@@ -1158,7 +1229,7 @@
 
 	list_add(&dc->list, &uncached_devices);
 	list_for_each_entry(c, &bch_cache_sets, list)
-		bch_cached_dev_attach(dc, c);
+		bch_cached_dev_attach(dc, c, NULL);
 
 	if (BDEV_STATE(&dc->sb) == BDEV_STATE_NONE ||
 	    BDEV_STATE(&dc->sb) == BDEV_STATE_STALE)
@@ -1211,10 +1282,11 @@
 
 	kobject_init(&d->kobj, &bch_flash_dev_ktype);
 
-	if (bcache_device_init(d, block_bytes(c), u->sectors))
+	if (bcache_device_init(d, block_bytes(c), u->sectors, NULL))
 		goto err;
 
 	bcache_device_attach(d, c, u - c->uuids);
+	bch_sectors_dirty_init(d);
 	bch_flash_dev_request_init(d);
 	add_disk(d->disk);
 
@@ -1321,6 +1393,7 @@
 	bch_btree_cache_free(c);
 	bch_journal_free(c);
 
+	mutex_lock(&bch_register_lock);
 	for_each_cache(ca, c, i)
 		if (ca) {
 			ca->set = NULL;
@@ -1343,7 +1416,6 @@
 		mempool_destroy(c->search);
 	kfree(c->devices);
 
-	mutex_lock(&bch_register_lock);
 	list_del(&c->list);
 	mutex_unlock(&bch_register_lock);
 
@@ -1361,12 +1433,15 @@
 	struct btree *b;
 	unsigned i;
 
+	if (!c)
+		closure_return(cl);
+
 	bch_cache_accounting_destroy(&c->accounting);
 
 	kobject_put(&c->internal);
 	kobject_del(&c->kobj);
 
-	if (c->gc_thread)
+	if (!IS_ERR_OR_NULL(c->gc_thread))
 		kthread_stop(c->gc_thread);
 
 	if (!IS_ERR_OR_NULL(c->root))
@@ -1431,7 +1506,7 @@
 }
 
 #define alloc_bucket_pages(gfp, c)			\
-	((void *) __get_free_pages(__GFP_ZERO|gfp, ilog2(bucket_pages(c))))
+	((void *) __get_free_pages(__GFP_ZERO|__GFP_COMP|gfp, ilog2(bucket_pages(c))))
 
 struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
 {
@@ -1473,7 +1548,9 @@
 	sema_init(&c->sb_write_mutex, 1);
 	mutex_init(&c->bucket_lock);
 	init_waitqueue_head(&c->btree_cache_wait);
+	spin_lock_init(&c->btree_cannibalize_lock);
 	init_waitqueue_head(&c->bucket_wait);
+	init_waitqueue_head(&c->gc_wait);
 	sema_init(&c->uuid_write_mutex, 1);
 
 	spin_lock_init(&c->btree_gc_time.lock);
@@ -1520,7 +1597,7 @@
 	return NULL;
 }
 
-static void run_cache_set(struct cache_set *c)
+static int run_cache_set(struct cache_set *c)
 {
 	const char *err = "cannot allocate memory";
 	struct cached_dev *dc, *t;
@@ -1532,6 +1609,7 @@
 
 	for_each_cache(ca, c, i)
 		c->nbuckets += ca->sb.nbuckets;
+	set_gc_sectors(c);
 
 	if (CACHE_SYNC(&c->sb)) {
 		LIST_HEAD(journal);
@@ -1611,7 +1689,9 @@
 		if (j->version < BCACHE_JSET_VERSION_UUID)
 			__uuid_write(c);
 
-		bch_journal_replay(c, &journal);
+		err = "bcache: replay journal failed";
+		if (bch_journal_replay(c, &journal))
+			goto err;
 	} else {
 		pr_notice("invalidating existing data");
 
@@ -1634,7 +1714,7 @@
 
 		mutex_lock(&c->bucket_lock);
 		for_each_cache(ca, c, i)
-			bch_prio_write(ca);
+			bch_prio_write(ca, true);
 		mutex_unlock(&c->bucket_lock);
 
 		err = "cannot allocate new UUID bucket";
@@ -1674,16 +1754,18 @@
 	bcache_write_super(c);
 
 	list_for_each_entry_safe(dc, t, &uncached_devices, list)
-		bch_cached_dev_attach(dc, c);
+		bch_cached_dev_attach(dc, c, NULL);
 
 	flash_devs_run(c);
 
 	set_bit(CACHE_SET_RUNNING, &c->flags);
-	return;
+	return 0;
 err:
 	closure_sync(&cl);
 	/* XXX: test this, it's broken */
 	bch_cache_set_error(c, "%s", err);
+
+	return -EIO;
 }
 
 static bool can_attach_cache(struct cache *ca, struct cache_set *c)
@@ -1734,7 +1816,14 @@
 	    sysfs_create_link(&c->kobj, &ca->kobj, buf))
 		goto err;
 
-	if (ca->sb.seq > c->sb.seq) {
+	/*
+	 * A special case is both ca->sb.seq and c->sb.seq are 0,
+	 * such condition happens on a new created cache device whose
+	 * super block is never flushed yet. In this case c->sb.version
+	 * and other members should be updated too, otherwise we will
+	 * have a mistaken super block version in cache set.
+	 */
+	if (ca->sb.seq > c->sb.seq || c->sb.seq == 0) {
 		c->sb.version		= ca->sb.version;
 		memcpy(c->sb.set_uuid, ca->sb.set_uuid, 16);
 		c->sb.flags             = ca->sb.flags;
@@ -1747,8 +1836,11 @@
 	ca->set->cache[ca->sb.nr_this_dev] = ca;
 	c->cache_by_alloc[c->caches_loaded++] = ca;
 
-	if (c->caches_loaded == c->sb.nr_in_set)
-		run_cache_set(c);
+	if (c->caches_loaded == c->sb.nr_in_set) {
+		err = "failed to run cache set";
+		if (run_cache_set(c) < 0)
+			goto err;
+	}
 
 	return NULL;
 err:
@@ -1791,6 +1883,7 @@
 static int cache_alloc(struct cache_sb *sb, struct cache *ca)
 {
 	size_t free;
+	size_t btree_buckets;
 	struct bucket *b;
 
 	__module_get(THIS_MODULE);
@@ -1800,10 +1893,20 @@
 	ca->journal.bio.bi_max_vecs = 8;
 	ca->journal.bio.bi_io_vec = ca->journal.bio.bi_inline_vecs;
 
+	/*
+	 * when ca->sb.njournal_buckets is not zero, journal exists,
+	 * and in bch_journal_replay(), tree node may split,
+	 * so bucket of RESERVE_BTREE type is needed,
+	 * the worst situation is all journal buckets are valid journal,
+	 * and all the keys need to replay,
+	 * so the number of  RESERVE_BTREE type buckets should be as much
+	 * as journal buckets
+	 */
+	btree_buckets = ca->sb.njournal_buckets ?: 8;
 	free = roundup_pow_of_two(ca->sb.nbuckets) >> 10;
 
-	if (!init_fifo(&ca->free[RESERVE_BTREE], 8, GFP_KERNEL) ||
-	    !init_fifo(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
+	if (!init_fifo(&ca->free[RESERVE_BTREE], btree_buckets, GFP_KERNEL) ||
+	    !init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
 	    !init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) ||
 	    !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) ||
 	    !init_fifo(&ca->free_inc,	free << 2, GFP_KERNEL) ||
@@ -1823,11 +1926,12 @@
 	return 0;
 }
 
-static void register_cache(struct cache_sb *sb, struct page *sb_page,
+static int register_cache(struct cache_sb *sb, struct page *sb_page,
 				struct block_device *bdev, struct cache *ca)
 {
 	char name[BDEVNAME_SIZE];
-	const char *err = "cannot allocate memory";
+	const char *err = NULL;
+	int ret = 0;
 
 	memcpy(&ca->sb, sb, sizeof(struct cache_sb));
 	ca->bdev = bdev;
@@ -1842,27 +1946,35 @@
 	if (blk_queue_discard(bdev_get_queue(ca->bdev)))
 		ca->discard = CACHE_DISCARD(&ca->sb);
 
-	if (cache_alloc(sb, ca) != 0)
+	ret = cache_alloc(sb, ca);
+	if (ret != 0)
 		goto err;
 
-	err = "error creating kobject";
-	if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache"))
-		goto err;
+	if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache")) {
+		err = "error calling kobject_add";
+		ret = -ENOMEM;
+		goto out;
+	}
 
 	mutex_lock(&bch_register_lock);
 	err = register_cache_set(ca);
 	mutex_unlock(&bch_register_lock);
 
-	if (err)
-		goto err;
+	if (err) {
+		ret = -ENODEV;
+		goto out;
+	}
 
 	pr_info("registered cache device %s", bdevname(bdev, name));
+
 out:
 	kobject_put(&ca->kobj);
-	return;
+
 err:
-	pr_notice("error opening %s: %s", bdevname(bdev, name), err);
-	goto out;
+	if (err)
+		pr_notice("error opening %s: %s", bdevname(bdev, name), err);
+
+	return ret;
 }
 
 /* Global interfaces/init */
@@ -1887,6 +1999,21 @@
 	return false;
 }
 
+static struct cached_dev *bch_find_cached_dev(struct block_device *bdev) {
+	struct cache_set *c, *tc;
+	struct cached_dev *dc, *t;
+
+	list_for_each_entry_safe(c, tc, &bch_cache_sets, list)
+		list_for_each_entry_safe(dc, t, &c->cached_devs, list)
+			if (dc->bdev == bdev)
+				return dc;
+	list_for_each_entry_safe(dc, t, &uncached_devices, list)
+		if (dc->bdev == bdev)
+			return dc;
+
+	return NULL;
+}
+
 static bool bch_is_open_cache(struct block_device *bdev) {
 	struct cache_set *c, *tc;
 	struct cache *ca;
@@ -1912,6 +2039,7 @@
 	struct cache_sb *sb = NULL;
 	struct block_device *bdev = NULL;
 	struct page *sb_page = NULL;
+	struct cached_dev *dc = NULL;
 
 	if (!try_module_get(THIS_MODULE))
 		return -EBUSY;
@@ -1926,13 +2054,27 @@
 				  sb);
 	if (IS_ERR(bdev)) {
 		if (bdev == ERR_PTR(-EBUSY)) {
-			bdev = lookup_bdev(strim(path));
+			bdev = lookup_bdev(strim(path), 0);
 			mutex_lock(&bch_register_lock);
-			if (!IS_ERR(bdev) && bch_is_open(bdev))
+			if (!IS_ERR(bdev) && bch_is_open(bdev)) {
 				err = "device already registered";
-			else
+				/* emit CHANGE event for backing devices to export
+				 * CACHED_{UUID/LABEL} values to udev */
+				if (bch_is_open_backing(bdev)) {
+					dc = bch_find_cached_dev(bdev);
+					if (dc) {
+						bch_cached_dev_emit_change(dc);
+						err = "device already registered (emitting change event)";
+					}
+				}
+			} else {
 				err = "device busy";
+            }
 			mutex_unlock(&bch_register_lock);
+			if (!IS_ERR(bdev))
+				bdput(bdev);
+			if (attr == &ksysfs_register_quiet)
+				goto out;
 		}
 		goto err;
 	}
@@ -1958,7 +2100,8 @@
 		if (!ca)
 			goto err_close;
 
-		register_cache(sb, sb_page, bdev, ca);
+		if (register_cache(sb, sb_page, bdev, ca) != 0)
+			goto err_close;
 	}
 out:
 	if (sb_page)
@@ -1971,8 +2114,7 @@
 err_close:
 	blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
 err:
-	if (attr != &ksysfs_register_quiet)
-		pr_info("error opening %s: %s", path, err);
+	pr_info("error opening %s: %s", path, err);
 	ret = -EINVAL;
 	goto out;
 }
@@ -2003,10 +2145,19 @@
 		list_for_each_entry_safe(dc, tdc, &uncached_devices, list)
 			bcache_device_stop(&dc->disk);
 
+		mutex_unlock(&bch_register_lock);
+
+		/*
+		 * Give an early chance for other kthreads and
+		 * kworkers to stop themselves
+		 */
+		schedule();
+
 		/* What's a condition variable? */
 		while (1) {
-			long timeout = start + 2 * HZ - jiffies;
+			long timeout = start + 10 * HZ - jiffies;
 
+			mutex_lock(&bch_register_lock);
 			stopped = list_empty(&bch_cache_sets) &&
 				list_empty(&uncached_devices);
 
@@ -2018,7 +2169,6 @@
 
 			mutex_unlock(&bch_register_lock);
 			schedule_timeout(timeout);
-			mutex_lock(&bch_register_lock);
 		}
 
 		finish_wait(&unregister_wait, &wait);
@@ -2050,6 +2200,7 @@
 	if (bcache_major)
 		unregister_blkdev(bcache_major, "bcache");
 	unregister_reboot_notifier(&reboot);
+	mutex_destroy(&bch_register_lock);
 }
 
 static int __init bcache_init(void)
@@ -2066,14 +2217,17 @@
 	closure_debug_init();
 
 	bcache_major = register_blkdev(0, "bcache");
-	if (bcache_major < 0)
+	if (bcache_major < 0) {
+		unregister_reboot_notifier(&reboot);
+		mutex_destroy(&bch_register_lock);
 		return bcache_major;
+	}
 
 	if (!(bcache_wq = create_workqueue("bcache")) ||
 	    !(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) ||
-	    sysfs_create_files(bcache_kobj, files) ||
 	    bch_request_init() ||
-	    bch_debug_init(bcache_kobj))
+	    bch_debug_init(bcache_kobj) ||
+	    sysfs_create_files(bcache_kobj, files))
 		goto err;
 
 	return 0;
--- linux-4.4.0.orig/drivers/md/bcache/sysfs.c
+++ linux-4.4.0/drivers/md/bcache/sysfs.c
@@ -63,6 +63,9 @@
 
 read_attribute(state);
 read_attribute(cache_read_races);
+read_attribute(reclaim);
+read_attribute(flush_write);
+read_attribute(retry_flush_write);
 read_attribute(writeback_keys_done);
 read_attribute(writeback_keys_failed);
 read_attribute(io_errors);
@@ -106,6 +109,41 @@
 rw_attribute(copy_gc_enabled);
 rw_attribute(size);
 
+static ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[],
+			    size_t selected)
+{
+	char *out = buf;
+	size_t i;
+
+	for (i = 0; list[i]; i++)
+		out += snprintf(out, buf + size - out,
+				i == selected ? "[%s] " : "%s ", list[i]);
+
+	out[-1] = '\n';
+	return out - buf;
+}
+
+static ssize_t bch_read_string_list(const char *buf, const char * const list[])
+{
+	size_t i;
+	char *s, *d = kstrndup(buf, PAGE_SIZE - 1, GFP_KERNEL);
+	if (!d)
+		return -ENOMEM;
+
+	s = strim(d);
+
+	for (i = 0; list[i]; i++)
+		if (!strcmp(list[i], s))
+			break;
+
+	kfree(d);
+
+	if (!list[i])
+		return -EINVAL;
+
+	return i;
+}
+
 SHOW(__bch_cached_dev)
 {
 	struct cached_dev *dc = container_of(kobj, struct cached_dev,
@@ -166,7 +204,7 @@
 	sysfs_hprint(dirty_data,
 		     bcache_dev_sectors_dirty(&dc->disk) << 9);
 
-	sysfs_hprint(stripe_size,	dc->disk.stripe_size << 9);
+	sysfs_hprint(stripe_size,	 ((uint64_t)dc->disk.stripe_size) << 9);
 	var_printf(partial_stripes_expensive,	"%u");
 
 	var_hprint(sequential_cutoff);
@@ -191,7 +229,7 @@
 {
 	struct cached_dev *dc = container_of(kobj, struct cached_dev,
 					     disk.kobj);
-	unsigned v = size;
+	ssize_t v;
 	struct cache_set *c;
 	struct kobj_uevent_env *env;
 
@@ -215,7 +253,9 @@
 	d_strtoul(writeback_rate_d_term);
 	d_strtoul_nonzero(writeback_rate_p_term_inverse);
 
-	d_strtoi_h(sequential_cutoff);
+	sysfs_strtoul_clamp(sequential_cutoff,
+			    dc->sequential_cutoff,
+			    0, UINT_MAX);
 	d_strtoi_h(readahead);
 
 	if (attr == &sysfs_clear_stats)
@@ -226,7 +266,7 @@
 		bch_cached_dev_run(dc);
 
 	if (attr == &sysfs_cache_mode) {
-		ssize_t v = bch_read_string_list(buf, bch_cache_modes + 1);
+		v = bch_read_string_list(buf, bch_cache_modes + 1);
 
 		if (v < 0)
 			return v;
@@ -263,17 +303,20 @@
 	}
 
 	if (attr == &sysfs_attach) {
-		if (bch_parse_uuid(buf, dc->sb.set_uuid) < 16)
+		uint8_t		set_uuid[16];
+
+		if (bch_parse_uuid(buf, set_uuid) < 16)
 			return -EINVAL;
 
+		v = -ENOENT;
 		list_for_each_entry(c, &bch_cache_sets, list) {
-			v = bch_cached_dev_attach(dc, c);
+			v = bch_cached_dev_attach(dc, c, set_uuid);
 			if (!v)
 				return size;
 		}
 
 		pr_err("Can't attach %s: cache set not found", buf);
-		size = v;
+		return v;
 	}
 
 	if (attr == &sysfs_detach && dc->disk.c)
@@ -541,6 +584,15 @@
 	sysfs_print(cache_read_races,
 		    atomic_long_read(&c->cache_read_races));
 
+	sysfs_print(reclaim,
+		    atomic_long_read(&c->reclaim));
+
+	sysfs_print(flush_write,
+		    atomic_long_read(&c->flush_write));
+
+	sysfs_print(retry_flush_write,
+		    atomic_long_read(&c->retry_flush_write));
+
 	sysfs_print(writeback_keys_done,
 		    atomic_long_read(&c->writeback_keys_done));
 	sysfs_print(writeback_keys_failed,
@@ -642,8 +694,17 @@
 		c->error_limit = strtoul_or_return(buf) << IO_ERROR_SHIFT;
 
 	/* See count_io_errors() for why 88 */
-	if (attr == &sysfs_io_error_halflife)
-		c->error_decay = strtoul_or_return(buf) / 88;
+	if (attr == &sysfs_io_error_halflife) {
+		unsigned long v = 0;
+		ssize_t ret;
+
+		ret = strtoul_safe_clamp(buf, v, 0, UINT_MAX);
+		if (!ret) {
+			c->error_decay = v / 88;
+			return size;
+		}
+		return ret;
+	}
 
 	sysfs_strtoul(journal_delay_ms,		c->journal_delay_ms);
 	sysfs_strtoul(verify,			c->verify);
@@ -714,6 +775,9 @@
 
 	&sysfs_bset_tree_stats,
 	&sysfs_cache_read_races,
+	&sysfs_reclaim,
+	&sysfs_flush_write,
+	&sysfs_retry_flush_write,
 	&sysfs_writeback_keys_done,
 	&sysfs_writeback_keys_failed,
 
@@ -756,7 +820,7 @@
 
 	if (attr == &sysfs_priority_stats) {
 		int cmp(const void *l, const void *r)
-		{	return *((uint16_t *) r) - *((uint16_t *) l); }
+		{	cond_resched(); return *((uint16_t *) r) - *((uint16_t *) l); }
 
 		struct bucket *b;
 		size_t n = ca->sb.nbuckets, i;
--- linux-4.4.0.orig/drivers/md/bcache/sysfs.h
+++ linux-4.4.0/drivers/md/bcache/sysfs.h
@@ -80,9 +80,16 @@
 
 #define sysfs_strtoul_clamp(file, var, min, max)			\
 do {									\
-	if (attr == &sysfs_ ## file)					\
-		return strtoul_safe_clamp(buf, var, min, max)		\
-			?: (ssize_t) size;				\
+	if (attr == &sysfs_ ## file) {					\
+		unsigned long v = 0;					\
+		ssize_t ret;						\
+		ret = strtoul_safe_clamp(buf, v, min, max);		\
+		if (!ret) {						\
+			var = v;					\
+			return size;					\
+		}							\
+		return ret;						\
+	}								\
 } while (0)
 
 #define strtoul_or_return(cp)						\
--- linux-4.4.0.orig/drivers/md/bcache/util.c
+++ linux-4.4.0/drivers/md/bcache/util.c
@@ -31,20 +31,27 @@
 	case 'y':						\
 	case 'z':						\
 		u++;						\
+		/* fall through */				\
 	case 'e':						\
 		u++;						\
+		/* fall through */				\
 	case 'p':						\
 		u++;						\
+		/* fall through */				\
 	case 't':						\
 		u++;						\
+		/* fall through */				\
 	case 'g':						\
 		u++;						\
+		/* fall through */				\
 	case 'm':						\
 		u++;						\
+		/* fall through */				\
 	case 'k':						\
 		u++;						\
 		if (e++ == cp)					\
 			return -EINVAL;				\
+		/* fall through */				\
 	case '\n':						\
 	case '\0':						\
 		if (*e == '\n')					\
@@ -73,59 +80,43 @@
 STRTO_H(strtoll, long long)
 STRTO_H(strtoull, unsigned long long)
 
+/**
+ * bch_hprint - formats @v to human readable string for sysfs.
+ * @buf: the (at least 8 byte) buffer to format the result into.
+ * @v: signed 64 bit integer
+ *
+ * Returns the number of bytes used by format.
+ */
 ssize_t bch_hprint(char *buf, int64_t v)
 {
 	static const char units[] = "?kMGTPEZY";
-	char dec[4] = "";
-	int u, t = 0;
-
-	for (u = 0; v >= 1024 || v <= -1024; u++) {
-		t = v & ~(~0 << 10);
-		v >>= 10;
-	}
-
-	if (!u)
-		return sprintf(buf, "%llu", v);
-
-	if (v < 100 && v > -100)
-		snprintf(dec, sizeof(dec), ".%i", t / 100);
-
-	return sprintf(buf, "%lli%s%c", v, dec, units[u]);
-}
-
-ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[],
-			    size_t selected)
-{
-	char *out = buf;
-	size_t i;
+	int u = 0, t;
 
-	for (i = 0; list[i]; i++)
-		out += snprintf(out, buf + size - out,
-				i == selected ? "[%s] " : "%s ", list[i]);
+	uint64_t q;
 
-	out[-1] = '\n';
-	return out - buf;
-}
-
-ssize_t bch_read_string_list(const char *buf, const char * const list[])
-{
-	size_t i;
-	char *s, *d = kstrndup(buf, PAGE_SIZE - 1, GFP_KERNEL);
-	if (!d)
-		return -ENOMEM;
-
-	s = strim(d);
-
-	for (i = 0; list[i]; i++)
-		if (!strcmp(list[i], s))
-			break;
-
-	kfree(d);
-
-	if (!list[i])
-		return -EINVAL;
-
-	return i;
+	if (v < 0)
+		q = -v;
+	else
+		q = v;
+
+	/* For as long as the number is more than 3 digits, but at least
+	 * once, shift right / divide by 1024.  Keep the remainder for
+	 * a digit after the decimal point.
+	 */
+	do {
+		u++;
+
+		t = q & ~(~0 << 10);
+		q >>= 10;
+	} while (q >= 1000);
+
+	if (v < 0)
+		/* '-', up to 3 digits, '.', 1 digit, 1 character, null;
+		 * yields 8 bytes.
+		 */
+		return sprintf(buf, "-%llu.%i%c", q, t * 10 / 1024, units[u]);
+	else
+		return sprintf(buf, "%llu.%i%c", q, t * 10 / 1024, units[u]);
 }
 
 bool bch_is_zero(const char *p, size_t n)
@@ -197,13 +188,12 @@
 }
 
 /**
- * bch_next_delay() - increment @d by the amount of work done, and return how
- * long to delay until the next time to do some work.
- *
- * @d - the struct bch_ratelimit to update
- * @done - the amount of work done, in arbitrary units
+ * bch_next_delay() - update ratelimiting statistics and calculate next delay
+ * @d: the struct bch_ratelimit to update
+ * @done: the amount of work done, in arbitrary units
  *
- * Returns the amount of time to delay by, in jiffies
+ * Increment @d by the amount of work done, and return how long to delay in
+ * jiffies until the next time to do some work.
  */
 uint64_t bch_next_delay(struct bch_ratelimit *d, uint64_t done)
 {
--- linux-4.4.0.orig/drivers/md/bcache/util.h
+++ linux-4.4.0/drivers/md/bcache/util.h
@@ -115,6 +115,8 @@
 
 #define heap_full(h)	((h)->used == (h)->size)
 
+#define heap_empty(h)	((h)->used == 0)
+
 #define DECLARE_FIFO(type, name)					\
 	struct {							\
 		size_t front, back, size, mask;				\
@@ -370,11 +372,6 @@
 bool bch_is_zero(const char *p, size_t n);
 int bch_parse_uuid(const char *s, char *uuid);
 
-ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[],
-			    size_t selected);
-
-ssize_t bch_read_string_list(const char *buf, const char * const list[]);
-
 struct time_stats {
 	spinlock_t	lock;
 	/*
--- linux-4.4.0.orig/drivers/md/bcache/writeback.c
+++ linux-4.4.0/drivers/md/bcache/writeback.c
@@ -21,7 +21,8 @@
 static void __update_writeback_rate(struct cached_dev *dc)
 {
 	struct cache_set *c = dc->disk.c;
-	uint64_t cache_sectors = c->nbuckets * c->sb.bucket_size;
+	uint64_t cache_sectors = c->nbuckets * c->sb.bucket_size -
+				bcache_flash_devs_sectors_dirty(c);
 	uint64_t cache_dirty_target =
 		div_u64(cache_sectors * dc->writeback_percent, 100);
 
@@ -190,7 +191,7 @@
 
 	closure_bio_submit(&io->bio, cl);
 
-	continue_at(cl, write_dirty_finish, system_wq);
+	continue_at(cl, write_dirty_finish, io->dc->writeback_write_wq);
 }
 
 static void read_dirty_endio(struct bio *bio)
@@ -210,7 +211,7 @@
 
 	closure_bio_submit(&io->bio, cl);
 
-	continue_at(cl, write_dirty, system_wq);
+	continue_at(cl, write_dirty, io->dc->writeback_write_wq);
 }
 
 static void read_dirty(struct cached_dev *dc)
@@ -323,6 +324,10 @@
 
 static bool dirty_pred(struct keybuf *buf, struct bkey *k)
 {
+	struct cached_dev *dc = container_of(buf, struct cached_dev, writeback_keys);
+
+	BUG_ON(KEY_INODE(k) != dc->disk.id);
+
 	return KEY_DIRTY(k);
 }
 
@@ -372,11 +377,24 @@
 	}
 }
 
+/*
+ * Returns true if we scanned the entire disk
+ */
 static bool refill_dirty(struct cached_dev *dc)
 {
 	struct keybuf *buf = &dc->writeback_keys;
+	struct bkey start = KEY(dc->disk.id, 0, 0);
 	struct bkey end = KEY(dc->disk.id, MAX_KEY_OFFSET, 0);
-	bool searched_from_start = false;
+	struct bkey start_pos;
+
+	/*
+	 * make sure keybuf pos is inside the range for this disk - at bringup
+	 * we might not be attached yet so this disk's inode nr isn't
+	 * initialized then
+	 */
+	if (bkey_cmp(&buf->last_scanned, &start) < 0 ||
+	    bkey_cmp(&buf->last_scanned, &end) > 0)
+		buf->last_scanned = start;
 
 	if (dc->partial_stripes_expensive) {
 		refill_full_stripes(dc);
@@ -384,14 +402,20 @@
 			return false;
 	}
 
-	if (bkey_cmp(&buf->last_scanned, &end) >= 0) {
-		buf->last_scanned = KEY(dc->disk.id, 0, 0);
-		searched_from_start = true;
-	}
-
+	start_pos = buf->last_scanned;
 	bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred);
 
-	return bkey_cmp(&buf->last_scanned, &end) >= 0 && searched_from_start;
+	if (bkey_cmp(&buf->last_scanned, &end) < 0)
+		return false;
+
+	/*
+	 * If we get to the end start scanning again from the beginning, and
+	 * only scan up to where we initially started scanning from:
+	 */
+	buf->last_scanned = start;
+	bch_refill_keybuf(dc->disk.c, buf, &start_pos, dirty_pred);
+
+	return bkey_cmp(&buf->last_scanned, &start_pos) >= 0;
 }
 
 static int bch_writeback_thread(void *arg)
@@ -401,19 +425,28 @@
 
 	while (!kthread_should_stop()) {
 		down_write(&dc->writeback_lock);
-		if (!atomic_read(&dc->has_dirty) ||
-		    (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) &&
-		     !dc->writeback_running)) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		/*
+		 * If the bache device is detaching, skip here and continue
+		 * to perform writeback. Otherwise, if no dirty data on cache,
+		 * or there is dirty data on cache but writeback is disabled,
+		 * the writeback thread should sleep here and wait for others
+		 * to wake up it.
+		 */
+		if (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) &&
+		    (!atomic_read(&dc->has_dirty) || !dc->writeback_running)) {
 			up_write(&dc->writeback_lock);
-			set_current_state(TASK_INTERRUPTIBLE);
 
-			if (kthread_should_stop())
+			if (kthread_should_stop()) {
+				set_current_state(TASK_RUNNING);
 				return 0;
+			}
 
 			try_to_freeze();
 			schedule();
 			continue;
 		}
+		set_current_state(TASK_RUNNING);
 
 		searched_full_index = refill_dirty(dc);
 
@@ -423,6 +456,16 @@
 			cached_dev_put(dc);
 			SET_BDEV_STATE(&dc->sb, BDEV_STATE_CLEAN);
 			bch_write_bdev_super(dc, NULL);
+			/*
+			 * If bcache device is detaching via sysfs interface,
+			 * writeback thread should stop after there is no dirty
+			 * data on cache. BCACHE_DEV_DETACHING flag is set in
+			 * bch_cached_dev_detach().
+			 */
+			if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) {
+				up_write(&dc->writeback_lock);
+				break;
+			}
 		}
 
 		up_write(&dc->writeback_lock);
@@ -465,17 +508,17 @@
 	return MAP_CONTINUE;
 }
 
-void bch_sectors_dirty_init(struct cached_dev *dc)
+void bch_sectors_dirty_init(struct bcache_device *d)
 {
 	struct sectors_dirty_init op;
 
 	bch_btree_op_init(&op.op, -1);
-	op.inode = dc->disk.id;
+	op.inode = d->id;
 
-	bch_btree_map_keys(&op.op, dc->disk.c, &KEY(op.inode, 0, 0),
+	bch_btree_map_keys(&op.op, d->c, &KEY(op.inode, 0, 0),
 			   sectors_dirty_init_fn, 0);
 
-	dc->disk.sectors_dirty_last = bcache_dev_sectors_dirty(&dc->disk);
+	d->sectors_dirty_last = bcache_dev_sectors_dirty(d);
 }
 
 void bch_cached_dev_writeback_init(struct cached_dev *dc)
@@ -499,6 +542,11 @@
 
 int bch_cached_dev_writeback_start(struct cached_dev *dc)
 {
+	dc->writeback_write_wq = alloc_workqueue("bcache_writeback_wq",
+						WQ_MEM_RECLAIM, 0);
+	if (!dc->writeback_write_wq)
+		return -ENOMEM;
+
 	dc->writeback_thread = kthread_create(bch_writeback_thread, dc,
 					      "bcache_writeback");
 	if (IS_ERR(dc->writeback_thread))
--- linux-4.4.0.orig/drivers/md/bcache/writeback.h
+++ linux-4.4.0/drivers/md/bcache/writeback.h
@@ -14,6 +14,25 @@
 	return ret;
 }
 
+static inline uint64_t  bcache_flash_devs_sectors_dirty(struct cache_set *c)
+{
+	uint64_t i, ret = 0;
+
+	mutex_lock(&bch_register_lock);
+
+	for (i = 0; i < c->nr_uuids; i++) {
+		struct bcache_device *d = c->devices[i];
+
+		if (!d || !UUID_FLASH_ONLY(&c->uuids[i]))
+			continue;
+		ret += bcache_dev_sectors_dirty(d);
+	}
+
+	mutex_unlock(&bch_register_lock);
+
+	return ret;
+}
+
 static inline unsigned offset_to_stripe(struct bcache_device *d,
 					uint64_t offset)
 {
@@ -49,6 +68,9 @@
 	    in_use > CUTOFF_WRITEBACK_SYNC)
 		return false;
 
+	if (bio->bi_rw & REQ_DISCARD)
+		return false;
+
 	if (dc->partial_stripes_expensive &&
 	    bcache_dev_stripe_dirty(dc, bio->bi_iter.bi_sector,
 				    bio_sectors(bio)))
@@ -63,7 +85,8 @@
 
 static inline void bch_writeback_queue(struct cached_dev *dc)
 {
-	wake_up_process(dc->writeback_thread);
+	if (!IS_ERR_OR_NULL(dc->writeback_thread))
+		wake_up_process(dc->writeback_thread);
 }
 
 static inline void bch_writeback_add(struct cached_dev *dc)
@@ -84,7 +107,7 @@
 
 void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int);
 
-void bch_sectors_dirty_init(struct cached_dev *dc);
+void bch_sectors_dirty_init(struct bcache_device *);
 void bch_cached_dev_writeback_init(struct cached_dev *);
 int bch_cached_dev_writeback_start(struct cached_dev *);
 
--- linux-4.4.0.orig/drivers/md/bitmap.c
+++ linux-4.4.0/drivers/md/bitmap.c
@@ -1332,7 +1332,7 @@
 	if (bitmap->bp[page].hijacked ||
 	    bitmap->bp[page].map == NULL)
 		csize = ((sector_t)1) << (bitmap->chunkshift +
-					  PAGE_COUNTER_SHIFT - 1);
+					  PAGE_COUNTER_SHIFT);
 	else
 		csize = ((sector_t)1) << bitmap->chunkshift;
 	*blocks = csize - (offset & (csize - 1));
@@ -1671,7 +1671,7 @@
 /*
  * free memory that was allocated
  */
-static void bitmap_free(struct bitmap *bitmap)
+static void md_bitmap_free(struct bitmap *bitmap)
 {
 	unsigned long k, pages;
 	struct bitmap_page *bp;
@@ -1721,7 +1721,7 @@
 	if (bitmap->sysfs_can_clear)
 		sysfs_put(bitmap->sysfs_can_clear);
 
-	bitmap_free(bitmap);
+	md_bitmap_free(bitmap);
 }
 
 /*
@@ -1805,7 +1805,7 @@
 
 	return bitmap;
  error:
-	bitmap_free(bitmap);
+	md_bitmap_free(bitmap);
 	return ERR_PTR(err);
 }
 
@@ -1904,7 +1904,7 @@
 	*low = lo;
 	*high = hi;
 err:
-	bitmap_free(bitmap);
+	md_bitmap_free(bitmap);
 	return rv;
 }
 EXPORT_SYMBOL_GPL(bitmap_copy_from_slot);
@@ -1960,6 +1960,11 @@
 	long pages;
 	struct bitmap_page *new_bp;
 
+	if (bitmap->storage.file && !init) {
+		pr_info("md: cannot resize file-based bitmap\n");
+		return -EINVAL;
+	}
+
 	if (chunksize == 0) {
 		/* If there is enough space, leave the chunk size unchanged,
 		 * else increase by factor of two until there is enough space.
--- linux-4.4.0.orig/drivers/md/dm-bio-prison.c
+++ linux-4.4.0/drivers/md/dm-bio-prison.c
@@ -32,7 +32,7 @@
  */
 struct dm_bio_prison *dm_bio_prison_create(void)
 {
-	struct dm_bio_prison *prison = kmalloc(sizeof(*prison), GFP_KERNEL);
+	struct dm_bio_prison *prison = kzalloc(sizeof(*prison), GFP_KERNEL);
 
 	if (!prison)
 		return NULL;
--- linux-4.4.0.orig/drivers/md/dm-bufio.c
+++ linux-4.4.0/drivers/md/dm-bufio.c
@@ -222,7 +222,7 @@
  * Buffers are freed after this timeout
  */
 static unsigned dm_bufio_max_age = DM_BUFIO_DEFAULT_AGE_SECS;
-static unsigned dm_bufio_retain_bytes = DM_BUFIO_DEFAULT_RETAIN_BYTES;
+static unsigned long dm_bufio_retain_bytes = DM_BUFIO_DEFAULT_RETAIN_BYTES;
 
 static unsigned long dm_bufio_peak_allocated;
 static unsigned long dm_bufio_allocated_kmem_cache;
@@ -813,12 +813,14 @@
 static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf)
 {
 	struct dm_buffer *b;
+	bool tried_noio_alloc = false;
 
 	/*
 	 * dm-bufio is resistant to allocation failures (it just keeps
 	 * one buffer reserved in cases all the allocations fail).
 	 * So set flags to not try too hard:
-	 *	GFP_NOIO: don't recurse into the I/O layer
+	 *	GFP_NOWAIT: don't wait; if we need to sleep we'll release our
+	 *		    mutex and wait ourselves.
 	 *	__GFP_NORETRY: don't retry and rather return failure
 	 *	__GFP_NOMEMALLOC: don't use emergency reserves
 	 *	__GFP_NOWARN: don't print a warning in case of failure
@@ -828,7 +830,7 @@
 	 */
 	while (1) {
 		if (dm_bufio_cache_size_latch != 1) {
-			b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
+			b = alloc_buffer(c, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
 			if (b)
 				return b;
 		}
@@ -836,6 +838,15 @@
 		if (nf == NF_PREFETCH)
 			return NULL;
 
+		if (dm_bufio_cache_size_latch != 1 && !tried_noio_alloc) {
+			dm_bufio_unlock(c);
+			b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
+			dm_bufio_lock(c);
+			if (b)
+				return b;
+			tried_noio_alloc = true;
+		}
+
 		if (!list_empty(&c->reserved_buffers)) {
 			b = list_entry(c->reserved_buffers.next,
 				       struct dm_buffer, lru_list);
@@ -914,10 +925,11 @@
 {
 	unsigned long buffers;
 
-	if (ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch) {
-		mutex_lock(&dm_bufio_clients_lock);
-		__cache_size_refresh();
-		mutex_unlock(&dm_bufio_clients_lock);
+	if (unlikely(ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch)) {
+		if (mutex_trylock(&dm_bufio_clients_lock)) {
+			__cache_size_refresh();
+			mutex_unlock(&dm_bufio_clients_lock);
+		}
 	}
 
 	buffers = dm_bufio_cache_size_per_client >>
@@ -927,7 +939,8 @@
 		buffers = c->minimum_buffers;
 
 	*limit_buffers = buffers;
-	*threshold_buffers = buffers * DM_BUFIO_WRITEBACK_PERCENT / 100;
+	*threshold_buffers = mult_frac(buffers,
+				       DM_BUFIO_WRITEBACK_PERCENT, 100);
 }
 
 /*
@@ -1513,10 +1526,10 @@
 	return true;
 }
 
-static unsigned get_retain_buffers(struct dm_bufio_client *c)
+static unsigned long get_retain_buffers(struct dm_bufio_client *c)
 {
-        unsigned retain_bytes = ACCESS_ONCE(dm_bufio_retain_bytes);
-        return retain_bytes / c->block_size;
+        unsigned long retain_bytes = ACCESS_ONCE(dm_bufio_retain_bytes);
+        return retain_bytes >> (c->sectors_per_block_bits + SECTOR_SHIFT);
 }
 
 static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
@@ -1525,8 +1538,9 @@
 	int l;
 	struct dm_buffer *b, *tmp;
 	unsigned long freed = 0;
-	unsigned long count = nr_to_scan;
-	unsigned retain_target = get_retain_buffers(c);
+	unsigned long count = c->n_buffers[LIST_CLEAN] +
+			      c->n_buffers[LIST_DIRTY];
+	unsigned long retain_target = get_retain_buffers(c);
 
 	for (l = 0; l < LIST_SIZE; l++) {
 		list_for_each_entry_safe_reverse(b, tmp, &c->lru[l], lru_list) {
@@ -1560,18 +1574,12 @@
 static unsigned long
 dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
 {
-	struct dm_bufio_client *c;
-	unsigned long count;
+	struct dm_bufio_client *c = container_of(shrink, struct dm_bufio_client, shrinker);
+	unsigned long count = READ_ONCE(c->n_buffers[LIST_CLEAN]) +
+			      READ_ONCE(c->n_buffers[LIST_DIRTY]);
+	unsigned long retain_target = get_retain_buffers(c);
 
-	c = container_of(shrink, struct dm_bufio_client, shrinker);
-	if (sc->gfp_mask & __GFP_FS)
-		dm_bufio_lock(c);
-	else if (!dm_bufio_trylock(c))
-		return 0;
-
-	count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY];
-	dm_bufio_unlock(c);
-	return count;
+	return (count < retain_target) ? 0 : (count - retain_target);
 }
 
 /*
@@ -1752,11 +1760,19 @@
 static void __evict_old_buffers(struct dm_bufio_client *c, unsigned long age_hz)
 {
 	struct dm_buffer *b, *tmp;
-	unsigned retain_target = get_retain_buffers(c);
-	unsigned count;
+	unsigned long retain_target = get_retain_buffers(c);
+	unsigned long count;
+	LIST_HEAD(write_list);
 
 	dm_bufio_lock(c);
 
+	__check_watermark(c, &write_list);
+	if (unlikely(!list_empty(&write_list))) {
+		dm_bufio_unlock(c);
+		__flush_write_list(&write_list);
+		dm_bufio_lock(c);
+	}
+
 	count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY];
 	list_for_each_entry_safe_reverse(b, tmp, &c->lru[LIST_CLEAN], lru_list) {
 		if (count <= retain_target)
@@ -1781,6 +1797,8 @@
 
 	mutex_lock(&dm_bufio_clients_lock);
 
+	__cache_size_refresh();
+
 	list_for_each_entry(c, &dm_bufio_all_clients, client_list)
 		__evict_old_buffers(c, max_age_hz);
 
@@ -1818,19 +1836,15 @@
 	memset(&dm_bufio_caches, 0, sizeof dm_bufio_caches);
 	memset(&dm_bufio_cache_names, 0, sizeof dm_bufio_cache_names);
 
-	mem = (__u64)((totalram_pages - totalhigh_pages) *
-		      DM_BUFIO_MEMORY_PERCENT / 100) << PAGE_SHIFT;
+	mem = (__u64)mult_frac(totalram_pages - totalhigh_pages,
+			       DM_BUFIO_MEMORY_PERCENT, 100) << PAGE_SHIFT;
 
 	if (mem > ULONG_MAX)
 		mem = ULONG_MAX;
 
 #ifdef CONFIG_MMU
-	/*
-	 * Get the size of vmalloc space the same way as VMALLOC_TOTAL
-	 * in fs/proc/internal.h
-	 */
-	if (mem > (VMALLOC_END - VMALLOC_START) * DM_BUFIO_VMALLOC_PERCENT / 100)
-		mem = (VMALLOC_END - VMALLOC_START) * DM_BUFIO_VMALLOC_PERCENT / 100;
+	if (mem > mult_frac(VMALLOC_TOTAL, DM_BUFIO_VMALLOC_PERCENT, 100))
+		mem = mult_frac(VMALLOC_TOTAL, DM_BUFIO_VMALLOC_PERCENT, 100);
 #endif
 
 	dm_bufio_default_cache_size = mem;
@@ -1904,7 +1918,7 @@
 module_param_named(max_age_seconds, dm_bufio_max_age, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(max_age_seconds, "Max age of a buffer in seconds");
 
-module_param_named(retain_bytes, dm_bufio_retain_bytes, uint, S_IRUGO | S_IWUSR);
+module_param_named(retain_bytes, dm_bufio_retain_bytes, ulong, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(retain_bytes, "Try to keep at least this many bytes cached in memory");
 
 module_param_named(peak_allocated_bytes, dm_bufio_peak_allocated, ulong, S_IRUGO | S_IWUSR);
--- linux-4.4.0.orig/drivers/md/dm-cache-metadata.c
+++ linux-4.4.0/drivers/md/dm-cache-metadata.c
@@ -337,7 +337,7 @@
 	disk_super->version = cpu_to_le32(MAX_CACHE_VERSION);
 	memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name));
 	memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version));
-	disk_super->policy_hint_size = 0;
+	disk_super->policy_hint_size = cpu_to_le32(0);
 
 	__copy_sm_root(cmd, disk_super);
 
@@ -501,12 +501,16 @@
 					  CACHE_MAX_CONCURRENT_LOCKS);
 	if (IS_ERR(cmd->bm)) {
 		DMERR("could not create block manager");
-		return PTR_ERR(cmd->bm);
+		r = PTR_ERR(cmd->bm);
+		cmd->bm = NULL;
+		return r;
 	}
 
 	r = __open_or_format_metadata(cmd, may_format_device);
-	if (r)
+	if (r) {
 		dm_block_manager_destroy(cmd->bm);
+		cmd->bm = NULL;
+	}
 
 	return r;
 }
@@ -652,6 +656,7 @@
 	disk_super->policy_version[0] = cpu_to_le32(cmd->policy_version[0]);
 	disk_super->policy_version[1] = cpu_to_le32(cmd->policy_version[1]);
 	disk_super->policy_version[2] = cpu_to_le32(cmd->policy_version[2]);
+	disk_super->policy_hint_size = cpu_to_le32(cmd->policy_hint_size);
 
 	disk_super->read_hits = cpu_to_le32(cmd->stats.read_hits);
 	disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses);
@@ -867,18 +872,55 @@
 	return 0;
 }
 
-#define WRITE_LOCK(cmd) \
-	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
-		return -EINVAL; \
-	down_write(&cmd->root_lock)
-
-#define WRITE_LOCK_VOID(cmd) \
-	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
-		return; \
-	down_write(&cmd->root_lock)
+static bool cmd_write_lock(struct dm_cache_metadata *cmd)
+{
+	down_write(&cmd->root_lock);
+	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) {
+		up_write(&cmd->root_lock);
+		return false;
+	}
+	return true;
+}
+
+#define WRITE_LOCK(cmd)				\
+	do {					\
+		if (!cmd_write_lock((cmd)))	\
+			return -EINVAL;		\
+	} while(0)
+
+#define WRITE_LOCK_VOID(cmd)			\
+	do {					\
+		if (!cmd_write_lock((cmd)))	\
+			return;			\
+	} while(0)
 
 #define WRITE_UNLOCK(cmd) \
-	up_write(&cmd->root_lock)
+	up_write(&(cmd)->root_lock)
+
+static bool cmd_read_lock(struct dm_cache_metadata *cmd)
+{
+	down_read(&cmd->root_lock);
+	if (cmd->fail_io) {
+		up_read(&cmd->root_lock);
+		return false;
+	}
+	return true;
+}
+
+#define READ_LOCK(cmd)				\
+	do {					\
+		if (!cmd_read_lock((cmd)))	\
+			return -EINVAL;		\
+	} while(0)
+
+#define READ_LOCK_VOID(cmd)			\
+	do {					\
+		if (!cmd_read_lock((cmd)))	\
+			return;			\
+	} while(0)
+
+#define READ_UNLOCK(cmd) \
+	up_read(&(cmd)->root_lock)
 
 int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size)
 {
@@ -1015,22 +1057,20 @@
 {
 	int r;
 
-	down_read(&cmd->root_lock);
+	READ_LOCK(cmd);
 	r = __load_discards(cmd, fn, context);
-	up_read(&cmd->root_lock);
+	READ_UNLOCK(cmd);
 
 	return r;
 }
 
-dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd)
+int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result)
 {
-	dm_cblock_t r;
+	READ_LOCK(cmd);
+	*result = cmd->cache_blocks;
+	READ_UNLOCK(cmd);
 
-	down_read(&cmd->root_lock);
-	r = cmd->cache_blocks;
-	up_read(&cmd->root_lock);
-
-	return r;
+	return 0;
 }
 
 static int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock)
@@ -1188,9 +1228,9 @@
 {
 	int r;
 
-	down_read(&cmd->root_lock);
+	READ_LOCK(cmd);
 	r = __load_mappings(cmd, policy, fn, context);
-	up_read(&cmd->root_lock);
+	READ_UNLOCK(cmd);
 
 	return r;
 }
@@ -1215,18 +1255,18 @@
 
 void dm_cache_dump(struct dm_cache_metadata *cmd)
 {
-	down_read(&cmd->root_lock);
+	READ_LOCK_VOID(cmd);
 	__dump_mappings(cmd);
-	up_read(&cmd->root_lock);
+	READ_UNLOCK(cmd);
 }
 
 int dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd)
 {
 	int r;
 
-	down_read(&cmd->root_lock);
+	READ_LOCK(cmd);
 	r = cmd->changed;
-	up_read(&cmd->root_lock);
+	READ_UNLOCK(cmd);
 
 	return r;
 }
@@ -1276,9 +1316,9 @@
 void dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd,
 				 struct dm_cache_statistics *stats)
 {
-	down_read(&cmd->root_lock);
+	READ_LOCK_VOID(cmd);
 	*stats = cmd->stats;
-	up_read(&cmd->root_lock);
+	READ_UNLOCK(cmd);
 }
 
 void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd,
@@ -1291,17 +1331,19 @@
 
 int dm_cache_commit(struct dm_cache_metadata *cmd, bool clean_shutdown)
 {
-	int r;
+	int r = -EINVAL;
 	flags_mutator mutator = (clean_shutdown ? set_clean_shutdown :
 				 clear_clean_shutdown);
 
 	WRITE_LOCK(cmd);
+	if (cmd->fail_io)
+		goto out;
+
 	r = __commit_transaction(cmd, mutator);
 	if (r)
 		goto out;
 
 	r = __begin_transaction(cmd);
-
 out:
 	WRITE_UNLOCK(cmd);
 	return r;
@@ -1312,9 +1354,10 @@
 {
 	int r = -EINVAL;
 
-	down_read(&cmd->root_lock);
-	r = dm_sm_get_nr_free(cmd->metadata_sm, result);
-	up_read(&cmd->root_lock);
+	READ_LOCK(cmd);
+	if (!cmd->fail_io)
+		r = dm_sm_get_nr_free(cmd->metadata_sm, result);
+	READ_UNLOCK(cmd);
 
 	return r;
 }
@@ -1324,9 +1367,10 @@
 {
 	int r = -EINVAL;
 
-	down_read(&cmd->root_lock);
-	r = dm_sm_get_nr_blocks(cmd->metadata_sm, result);
-	up_read(&cmd->root_lock);
+	READ_LOCK(cmd);
+	if (!cmd->fail_io)
+		r = dm_sm_get_nr_blocks(cmd->metadata_sm, result);
+	READ_UNLOCK(cmd);
 
 	return r;
 }
@@ -1417,7 +1461,13 @@
 
 int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result)
 {
-	return blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
+	int r;
+
+	READ_LOCK(cmd);
+	r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
+	READ_UNLOCK(cmd);
+
+	return r;
 }
 
 void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd)
@@ -1440,10 +1490,7 @@
 	struct dm_block *sblock;
 	struct cache_disk_superblock *disk_super;
 
-	/*
-	 * We ignore fail_io for this function.
-	 */
-	down_write(&cmd->root_lock);
+	WRITE_LOCK(cmd);
 	set_bit(NEEDS_CHECK, &cmd->flags);
 
 	r = superblock_lock(cmd, &sblock);
@@ -1458,19 +1505,17 @@
 	dm_bm_unlock(sblock);
 
 out:
-	up_write(&cmd->root_lock);
+	WRITE_UNLOCK(cmd);
 	return r;
 }
 
-bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd)
+int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result)
 {
-	bool needs_check;
+	READ_LOCK(cmd);
+	*result = !!test_bit(NEEDS_CHECK, &cmd->flags);
+	READ_UNLOCK(cmd);
 
-	down_read(&cmd->root_lock);
-	needs_check = !!test_bit(NEEDS_CHECK, &cmd->flags);
-	up_read(&cmd->root_lock);
-
-	return needs_check;
+	return 0;
 }
 
 int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
--- linux-4.4.0.orig/drivers/md/dm-cache-metadata.h
+++ linux-4.4.0/drivers/md/dm-cache-metadata.h
@@ -66,7 +66,7 @@
  * origin blocks to map to.
  */
 int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size);
-dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd);
+int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result);
 
 int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
 				   sector_t discard_block_size,
@@ -137,7 +137,7 @@
  */
 int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result);
 
-bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd);
+int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result);
 int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd);
 void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd);
 void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd);
--- linux-4.4.0.orig/drivers/md/dm-cache-target.c
+++ linux-4.4.0/drivers/md/dm-cache-target.c
@@ -251,7 +251,7 @@
 	/*
 	 * Fields for converting from sectors to blocks.
 	 */
-	uint32_t sectors_per_block;
+	sector_t sectors_per_block;
 	int sectors_per_block_shift;
 
 	spinlock_t lock;
@@ -987,9 +987,14 @@
 
 static void set_cache_mode(struct cache *cache, enum cache_metadata_mode new_mode)
 {
-	bool needs_check = dm_cache_metadata_needs_check(cache->cmd);
+	bool needs_check;
 	enum cache_metadata_mode old_mode = get_cache_mode(cache);
 
+	if (dm_cache_metadata_needs_check(cache->cmd, &needs_check)) {
+		DMERR("unable to read needs_check flag, setting failure mode");
+		new_mode = CM_FAIL;
+	}
+
 	if (new_mode == CM_WRITE && needs_check) {
 		DMERR("%s: unable to switch cache to write mode until repaired.",
 		      cache_device_name(cache));
@@ -2188,8 +2193,8 @@
 
 static void stop_worker(struct cache *cache)
 {
-	cancel_delayed_work(&cache->waker);
-	flush_workqueue(cache->wq);
+	cancel_delayed_work_sync(&cache->waker);
+	drain_workqueue(cache->wq);
 }
 
 static void requeue_deferred_cells(struct cache *cache)
@@ -2286,7 +2291,7 @@
 static int is_congested(struct dm_dev *dev, int bdi_bits)
 {
 	struct request_queue *q = bdev_get_queue(dev->bdev);
-	return bdi_congested(&q->backing_dev_info, bdi_bits);
+	return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static int cache_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
@@ -3386,8 +3391,13 @@
 
 static bool can_resize(struct cache *cache, dm_cblock_t new_size)
 {
-	if (from_cblock(new_size) > from_cblock(cache->cache_size))
-		return true;
+	if (from_cblock(new_size) > from_cblock(cache->cache_size)) {
+		if (cache->sized) {
+			DMERR("%s: unable to extend cache due to missing cache table reload",
+			      cache_device_name(cache));
+			return false;
+		}
+	}
 
 	/*
 	 * We can't drop a dirty block when shrinking the cache.
@@ -3513,6 +3523,7 @@
 	char buf[BDEVNAME_SIZE];
 	struct cache *cache = ti->private;
 	dm_cblock_t residency;
+	bool needs_check;
 
 	switch (type) {
 	case STATUSTYPE_INFO:
@@ -3541,11 +3552,11 @@
 
 		residency = policy_residency(cache->policy);
 
-		DMEMIT("%u %llu/%llu %u %llu/%llu %u %u %u %u %u %u %lu ",
+		DMEMIT("%u %llu/%llu %llu %llu/%llu %u %u %u %u %u %u %lu ",
 		       (unsigned)DM_CACHE_METADATA_BLOCK_SIZE,
 		       (unsigned long long)(nr_blocks_metadata - nr_free_blocks_metadata),
 		       (unsigned long long)nr_blocks_metadata,
-		       cache->sectors_per_block,
+		       (unsigned long long)cache->sectors_per_block,
 		       (unsigned long long) from_cblock(residency),
 		       (unsigned long long) from_cblock(cache->cache_size),
 		       (unsigned) atomic_read(&cache->stats.read_hit),
@@ -3586,7 +3597,9 @@
 		else
 			DMEMIT("rw ");
 
-		if (dm_cache_metadata_needs_check(cache->cmd))
+		r = dm_cache_metadata_needs_check(cache->cmd, &needs_check);
+
+		if (r || needs_check)
 			DMEMIT("needs_check ");
 		else
 			DMEMIT("- ");
--- linux-4.4.0.orig/drivers/md/dm-crypt.c
+++ linux-4.4.0/drivers/md/dm-crypt.c
@@ -112,8 +112,7 @@
  * and encrypts / decrypts at the same time.
  */
 enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
-	     DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD,
-	     DM_CRYPT_EXIT_THREAD};
+	     DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
 
 /*
  * The fields in here must be read only after initialization.
@@ -1204,18 +1203,20 @@
 		if (!RB_EMPTY_ROOT(&cc->write_tree))
 			goto pop_from_list;
 
-		if (unlikely(test_bit(DM_CRYPT_EXIT_THREAD, &cc->flags))) {
-			spin_unlock_irq(&cc->write_thread_wait.lock);
-			break;
-		}
-
-		__set_current_state(TASK_INTERRUPTIBLE);
+		set_current_state(TASK_INTERRUPTIBLE);
 		__add_wait_queue(&cc->write_thread_wait, &wait);
 
 		spin_unlock_irq(&cc->write_thread_wait.lock);
 
+		if (unlikely(kthread_should_stop())) {
+			set_task_state(current, TASK_RUNNING);
+			remove_wait_queue(&cc->write_thread_wait, &wait);
+			break;
+		}
+
 		schedule();
 
+		set_task_state(current, TASK_RUNNING);
 		spin_lock_irq(&cc->write_thread_wait.lock);
 		__remove_wait_queue(&cc->write_thread_wait, &wait);
 		goto continue_locked;
@@ -1499,12 +1500,15 @@
 	if (!cc->key_size && strcmp(key, "-"))
 		goto out;
 
+	/* clear the flag since following operations may invalidate previously valid key */
+	clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
+
 	if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0)
 		goto out;
 
-	set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
-
 	r = crypt_setkey_allcpus(cc);
+	if (!r)
+		set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
 
 out:
 	/* Hex key string not needed after here, so wipe it. */
@@ -1530,13 +1534,8 @@
 	if (!cc)
 		return;
 
-	if (cc->write_thread) {
-		spin_lock_irq(&cc->write_thread_wait.lock);
-		set_bit(DM_CRYPT_EXIT_THREAD, &cc->flags);
-		wake_up_locked(&cc->write_thread_wait);
-		spin_unlock_irq(&cc->write_thread_wait.lock);
+	if (cc->write_thread)
 		kthread_stop(cc->write_thread);
-	}
 
 	if (cc->io_queue)
 		destroy_workqueue(cc->io_queue);
@@ -1920,6 +1919,13 @@
 		return DM_MAPIO_REMAPPED;
 	}
 
+	/*
+	 * Check if bio is too large, split as needed.
+	 */
+	if (unlikely(bio->bi_iter.bi_size > (BIO_MAX_PAGES << PAGE_SHIFT)) &&
+	    bio_data_dir(bio) == WRITE)
+		dm_accept_partial_bio(bio, ((BIO_MAX_PAGES << PAGE_SHIFT) >> SECTOR_SHIFT));
+
 	io = dm_per_bio_data(bio, cc->per_bio_data_size);
 	crypt_io_init(io, cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector));
 	io->ctx.req = (struct ablkcipher_request *)(io + 1);
--- linux-4.4.0.orig/drivers/md/dm-delay.c
+++ linux-4.4.0/drivers/md/dm-delay.c
@@ -222,7 +222,8 @@
 {
 	struct delay_c *dc = ti->private;
 
-	destroy_workqueue(dc->kdelayd_wq);
+	if (dc->kdelayd_wq)
+		destroy_workqueue(dc->kdelayd_wq);
 
 	dm_put_device(ti, dc->dev_read);
 
--- linux-4.4.0.orig/drivers/md/dm-era-target.c
+++ linux-4.4.0/drivers/md/dm-era-target.c
@@ -46,6 +46,7 @@
 static void writeset_free(struct writeset *ws)
 {
 	vfree(ws->bits);
+	ws->bits = NULL;
 }
 
 static int setup_on_disk_bitset(struct dm_disk_bitset *info,
@@ -70,8 +71,6 @@
  */
 static int writeset_alloc(struct writeset *ws, dm_block_t nr_blocks)
 {
-	ws->md.nr_bits = nr_blocks;
-	ws->md.root = INVALID_WRITESET_ROOT;
 	ws->bits = vzalloc(bitset_size(nr_blocks));
 	if (!ws->bits) {
 		DMERR("%s: couldn't allocate in memory bitset", __func__);
@@ -84,12 +83,14 @@
 /*
  * Wipes the in-core bitset, and creates a new on disk bitset.
  */
-static int writeset_init(struct dm_disk_bitset *info, struct writeset *ws)
+static int writeset_init(struct dm_disk_bitset *info, struct writeset *ws,
+			 dm_block_t nr_blocks)
 {
 	int r;
 
-	memset(ws->bits, 0, bitset_size(ws->md.nr_bits));
+	memset(ws->bits, 0, bitset_size(nr_blocks));
 
+	ws->md.nr_bits = nr_blocks;
 	r = setup_on_disk_bitset(info, ws->md.nr_bits, &ws->md.root);
 	if (r) {
 		DMERR("%s: setup_on_disk_bitset failed", __func__);
@@ -133,7 +134,7 @@
 {
 	int r;
 
-	if (!test_and_set_bit(block, ws->bits)) {
+	if (!test_bit(block, ws->bits)) {
 		r = dm_bitset_set_bit(info, ws->md.root, block, &ws->md.root);
 		if (r) {
 			/* FIXME: fail mode */
@@ -388,7 +389,7 @@
 
 static int ws_eq(void *context, const void *value1, const void *value2)
 {
-	return !memcmp(value1, value2, sizeof(struct writeset_metadata));
+	return !memcmp(value1, value2, sizeof(struct writeset_disk));
 }
 
 /*----------------------------------------------------------------*/
@@ -564,6 +565,15 @@
 	}
 
 	disk = dm_block_data(sblock);
+
+	/* Verify the data block size hasn't changed */
+	if (le32_to_cpu(disk->data_block_size) != md->block_size) {
+		DMERR("changing the data block size (from %u to %llu) is not supported",
+		      le32_to_cpu(disk->data_block_size), md->block_size);
+		r = -EINVAL;
+		goto bad;
+	}
+
 	r = dm_tm_open_with_sm(md->bm, SUPERBLOCK_LOCATION,
 			       disk->metadata_space_map_root,
 			       sizeof(disk->metadata_space_map_root),
@@ -575,10 +585,10 @@
 
 	setup_infos(md);
 
-	md->block_size = le32_to_cpu(disk->data_block_size);
 	md->nr_blocks = le32_to_cpu(disk->nr_blocks);
 	md->current_era = le32_to_cpu(disk->current_era);
 
+	ws_unpack(&disk->current_writeset, &md->current_writeset->md);
 	md->writeset_tree_root = le64_to_cpu(disk->writeset_tree_root);
 	md->era_array_root = le64_to_cpu(disk->era_array_root);
 	md->metadata_snap = le64_to_cpu(disk->metadata_snap);
@@ -747,6 +757,12 @@
 	ws_unpack(&disk, &d->writeset);
 	d->value = cpu_to_le32(key);
 
+	/*
+	 * We initialise another bitset info to avoid any caching side effects
+	 * with the previous one.
+	 */
+	dm_disk_bitset_init(md->tm, &d->info);
+
 	d->nr_bits = min(d->writeset.nr_bits, md->nr_blocks);
 	d->current_bit = 0;
 	d->step = metadata_digest_transcribe_writeset;
@@ -760,12 +776,6 @@
 		return 0;
 
 	memset(d, 0, sizeof(*d));
-
-	/*
-	 * We initialise another bitset info to avoid any caching side
-	 * effects with the previous one.
-	 */
-	dm_disk_bitset_init(md->tm, &d->info);
 	d->step = metadata_digest_lookup_writeset;
 
 	return 0;
@@ -803,6 +813,8 @@
 
 static void metadata_close(struct era_metadata *md)
 {
+	writeset_free(&md->writesets[0]);
+	writeset_free(&md->writesets[1]);
 	destroy_persistent_data_objects(md);
 	kfree(md);
 }
@@ -840,6 +852,7 @@
 	r = writeset_alloc(&md->writesets[1], *new_size);
 	if (r) {
 		DMERR("%s: writeset_alloc failed for writeset 1", __func__);
+		writeset_free(&md->writesets[0]);
 		return r;
 	}
 
@@ -850,6 +863,8 @@
 			    &value, &md->era_array_root);
 	if (r) {
 		DMERR("%s: dm_array_resize failed", __func__);
+		writeset_free(&md->writesets[0]);
+		writeset_free(&md->writesets[1]);
 		return r;
 	}
 
@@ -871,7 +886,6 @@
 	}
 
 	ws_pack(&md->current_writeset->md, &value);
-	md->current_writeset->md.root = INVALID_WRITESET_ROOT;
 
 	keys[0] = md->current_era;
 	__dm_bless_for_disk(&value);
@@ -883,6 +897,7 @@
 		return r;
 	}
 
+	md->current_writeset->md.root = INVALID_WRITESET_ROOT;
 	md->archived_writesets = true;
 
 	return 0;
@@ -899,7 +914,7 @@
 	int r;
 	struct writeset *new_writeset = next_writeset(md);
 
-	r = writeset_init(&md->bitset_info, new_writeset);
+	r = writeset_init(&md->bitset_info, new_writeset, md->nr_blocks);
 	if (r) {
 		DMERR("%s: writeset_init failed", __func__);
 		return r;
@@ -952,7 +967,7 @@
 	int r;
 	struct dm_block *sblock;
 
-	if (md->current_writeset->md.root != SUPERBLOCK_LOCATION) {
+	if (md->current_writeset->md.root != INVALID_WRITESET_ROOT) {
 		r = dm_bitset_flush(&md->bitset_info, md->current_writeset->md.root,
 				    &md->current_writeset->md.root);
 		if (r) {
@@ -961,15 +976,15 @@
 		}
 	}
 
-	r = save_sm_root(md);
+	r = dm_tm_pre_commit(md->tm);
 	if (r) {
-		DMERR("%s: save_sm_root failed", __func__);
+		DMERR("%s: pre commit failed", __func__);
 		return r;
 	}
 
-	r = dm_tm_pre_commit(md->tm);
+	r = save_sm_root(md);
 	if (r) {
-		DMERR("%s: pre commit failed", __func__);
+		DMERR("%s: save_sm_root failed", __func__);
 		return r;
 	}
 
@@ -1227,8 +1242,10 @@
 	int r;
 	struct bio_list deferred_bios, marked_bios;
 	struct bio *bio;
+	struct blk_plug plug;
 	bool commit_needed = false;
 	bool failed = false;
+	struct writeset *ws = era->md->current_writeset;
 
 	bio_list_init(&deferred_bios);
 	bio_list_init(&marked_bios);
@@ -1238,9 +1255,11 @@
 	bio_list_init(&era->deferred_bios);
 	spin_unlock(&era->deferred_lock);
 
+	if (bio_list_empty(&deferred_bios))
+		return;
+
 	while ((bio = bio_list_pop(&deferred_bios))) {
-		r = writeset_test_and_set(&era->md->bitset_info,
-					  era->md->current_writeset,
+		r = writeset_test_and_set(&era->md->bitset_info, ws,
 					  get_block(era, bio));
 		if (r < 0) {
 			/*
@@ -1248,7 +1267,6 @@
 			 * FIXME: finish.
 			 */
 			failed = true;
-
 		} else if (r == 0)
 			commit_needed = true;
 
@@ -1264,9 +1282,19 @@
 	if (failed)
 		while ((bio = bio_list_pop(&marked_bios)))
 			bio_io_error(bio);
-	else
-		while ((bio = bio_list_pop(&marked_bios)))
+	else {
+		blk_start_plug(&plug);
+		while ((bio = bio_list_pop(&marked_bios))) {
+			/*
+			 * Only update the in-core writeset if the on-disk one
+			 * was updated too.
+			 */
+			if (commit_needed)
+				set_bit(get_block(era, bio), ws->bits);
 			generic_make_request(bio);
+		}
+		blk_finish_plug(&plug);
+	}
 }
 
 static void process_rpc_calls(struct era *era)
@@ -1379,7 +1407,7 @@
 static int dev_is_congested(struct dm_dev *dev, int bdi_bits)
 {
 	struct request_queue *q = bdev_get_queue(dev->bdev);
-	return bdi_congested(&q->backing_dev_info, bdi_bits);
+	return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static int era_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
@@ -1487,15 +1515,6 @@
 	}
 	era->md = md;
 
-	era->nr_blocks = calc_nr_blocks(era);
-
-	r = metadata_resize(era->md, &era->nr_blocks);
-	if (r) {
-		ti->error = "couldn't resize metadata";
-		era_destroy(era);
-		return -ENOMEM;
-	}
-
 	era->wq = alloc_ordered_workqueue("dm-" DM_MSG_PREFIX, WQ_MEM_RECLAIM);
 	if (!era->wq) {
 		ti->error = "could not create workqueue for metadata object";
@@ -1573,16 +1592,24 @@
 	dm_block_t new_size = calc_nr_blocks(era);
 
 	if (era->nr_blocks != new_size) {
-		r = in_worker1(era, metadata_resize, &new_size);
-		if (r)
+		r = metadata_resize(era->md, &new_size);
+		if (r) {
+			DMERR("%s: metadata_resize failed", __func__);
 			return r;
+		}
+
+		r = metadata_commit(era->md);
+		if (r) {
+			DMERR("%s: metadata_commit failed", __func__);
+			return r;
+		}
 
 		era->nr_blocks = new_size;
 	}
 
 	start_worker(era);
 
-	r = in_worker0(era, metadata_new_era);
+	r = in_worker0(era, metadata_era_rollover);
 	if (r) {
 		DMERR("%s: metadata_era_rollover failed", __func__);
 		return r;
--- linux-4.4.0.orig/drivers/md/dm-exception-store.h
+++ linux-4.4.0/drivers/md/dm-exception-store.h
@@ -69,7 +69,7 @@
 	 * Update the metadata with this exception.
 	 */
 	void (*commit_exception) (struct dm_exception_store *store,
-				  struct dm_exception *e,
+				  struct dm_exception *e, int valid,
 				  void (*callback) (void *, int success),
 				  void *callback_context);
 
--- linux-4.4.0.orig/drivers/md/dm-flakey.c
+++ linux-4.4.0/drivers/md/dm-flakey.c
@@ -69,6 +69,11 @@
 		arg_name = dm_shift_arg(as);
 		argc--;
 
+		if (!arg_name) {
+			ti->error = "Insufficient feature arguments";
+			return -EINVAL;
+		}
+
 		/*
 		 * drop_writes
 		 */
@@ -200,11 +205,13 @@
 
 	if (!(fc->up_interval + fc->down_interval)) {
 		ti->error = "Total (up + down) interval is zero";
+		r = -EINVAL;
 		goto bad;
 	}
 
 	if (fc->up_interval + fc->down_interval < fc->up_interval) {
 		ti->error = "Interval overflow";
+		r = -EINVAL;
 		goto bad;
 	}
 
@@ -289,10 +296,14 @@
 		pb->bio_submitted = true;
 
 		/*
-		 * Map reads as normal.
+		 * Error reads if neither corrupt_bio_byte or drop_writes are set.
+		 * Otherwise, flakey_end_io() will decide if the reads should be modified.
 		 */
-		if (bio_data_dir(bio) == READ)
+		if (bio_data_dir(bio) == READ) {
+			if (!fc->corrupt_bio_byte && !test_bit(DROP_WRITES, &fc->flags))
+				return -EIO;
 			goto map_bio;
+		}
 
 		/*
 		 * Drop writes?
@@ -328,14 +339,22 @@
 	struct flakey_c *fc = ti->private;
 	struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
 
-	/*
-	 * Corrupt successful READs while in down state.
-	 * If flags were specified, only corrupt those that match.
-	 */
-	if (fc->corrupt_bio_byte && !error && pb->bio_submitted &&
-	    (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
-	    all_corrupt_bio_flags_match(bio, fc))
-		corrupt_bio_data(bio, fc);
+	if (!error && pb->bio_submitted && (bio_data_dir(bio) == READ)) {
+		if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) &&
+		    all_corrupt_bio_flags_match(bio, fc)) {
+			/*
+			 * Corrupt successful matching READs while in down state.
+			 */
+			corrupt_bio_data(bio, fc);
+
+		} else if (!test_bit(DROP_WRITES, &fc->flags)) {
+			/*
+			 * Error read during the down_interval if drop_writes
+			 * wasn't configured.
+			 */
+			return -EIO;
+		}
+	}
 
 	return error;
 }
--- linux-4.4.0.orig/drivers/md/dm-io.c
+++ linux-4.4.0/drivers/md/dm-io.c
@@ -50,7 +50,7 @@
 	struct dm_io_client *client;
 	unsigned min_ios = dm_get_reserved_bio_based_ios();
 
-	client = kmalloc(sizeof(*client), GFP_KERNEL);
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
 	if (!client)
 		return ERR_PTR(-ENOMEM);
 
@@ -300,6 +300,7 @@
 	else if (rw & REQ_WRITE_SAME)
 		special_cmd_max_sectors = q->limits.max_write_same_sectors;
 	if ((rw & (REQ_DISCARD | REQ_WRITE_SAME)) && special_cmd_max_sectors == 0) {
+		atomic_inc(&io->count);
 		dec_count(io, region, -EOPNOTSUPP);
 		return;
 	}
--- linux-4.4.0.orig/drivers/md/dm-ioctl.c
+++ linux-4.4.0/drivers/md/dm-ioctl.c
@@ -524,7 +524,7 @@
 	 * Grab our output buffer.
 	 */
 	nl = get_result_buffer(param, param_size, &len);
-	if (len < needed) {
+	if (len < needed || len < sizeof(nl->dev)) {
 		param->flags |= DM_BUFFER_FULL_FLAG;
 		goto out;
 	}
@@ -771,15 +771,21 @@
 	struct hash_cell *hc = NULL;
 
 	if (*param->uuid) {
-		if (*param->name || param->dev)
+		if (*param->name || param->dev) {
+			DMERR("Invalid ioctl structure: uuid %s, name %s, dev %llx",
+			      param->uuid, param->name, (unsigned long long)param->dev);
 			return NULL;
+		}
 
 		hc = __get_uuid_cell(param->uuid);
 		if (!hc)
 			return NULL;
 	} else if (*param->name) {
-		if (param->dev)
+		if (param->dev) {
+			DMERR("Invalid ioctl structure: name %s, dev %llx",
+			      param->name, (unsigned long long)param->dev);
 			return NULL;
+		}
 
 		hc = __get_name_cell(param->name);
 		if (!hc)
@@ -1373,11 +1379,12 @@
 		hc->new_map = NULL;
 	}
 
-	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
-
-	__dev_status(hc->md, param);
 	md = hc->md;
 	up_write(&_hash_lock);
+
+	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+	__dev_status(md, param);
+
 	if (old_map) {
 		dm_sync_table(md);
 		dm_table_destroy(old_map);
@@ -1539,6 +1546,7 @@
 
 	if (!argc) {
 		DMWARN("Empty message received.");
+		r = -EINVAL;
 		goto out_argv;
 	}
 
@@ -1685,8 +1693,7 @@
 }
 
 static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kernel,
-		       int ioctl_flags,
-		       struct dm_ioctl **param, int *param_flags)
+		       int ioctl_flags, struct dm_ioctl **param, int *param_flags)
 {
 	struct dm_ioctl *dmi;
 	int secure_data;
@@ -1695,8 +1702,12 @@
 	if (copy_from_user(param_kernel, user, minimum_data_size))
 		return -EFAULT;
 
-	if (param_kernel->data_size < minimum_data_size)
+	if (unlikely(param_kernel->data_size < minimum_data_size) ||
+	    unlikely(param_kernel->data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS)) {
+		DMERR("Invalid data size in the ioctl structure: %u",
+		      param_kernel->data_size);
 		return -EINVAL;
+	}
 
 	secure_data = param_kernel->flags & DM_SECURE_DATA_FLAG;
 
@@ -1734,18 +1745,13 @@
 		return -ENOMEM;
 	}
 
-	if (copy_from_user(dmi, user, param_kernel->data_size))
-		goto bad;
+	/* Copy from param_kernel (which was already copied from user) */
+	memcpy(dmi, param_kernel, minimum_data_size);
 
-data_copied:
-	/*
-	 * Abort if something changed the ioctl data while it was being copied.
-	 */
-	if (dmi->data_size != param_kernel->data_size) {
-		DMERR("rejecting ioctl: data size modified while processing parameters");
+	if (copy_from_user(&dmi->data, (char __user *)user + minimum_data_size,
+			   param_kernel->data_size - minimum_data_size))
 		goto bad;
-	}
-
+data_copied:
 	/* Wipe the user buffer so we do not return it to userspace */
 	if (secure_data && clear_user(user, param_kernel->data_size))
 		goto bad;
@@ -1773,12 +1779,12 @@
 	    cmd == DM_LIST_VERSIONS_CMD)
 		return 0;
 
-	if ((cmd == DM_DEV_CREATE_CMD)) {
+	if (cmd == DM_DEV_CREATE_CMD) {
 		if (!*param->name) {
 			DMWARN("name not supplied when creating device");
 			return -EINVAL;
 		}
-	} else if ((*param->uuid && *param->name)) {
+	} else if (*param->uuid && *param->name) {
 		DMWARN("only supply one of name or uuid, cmd(%u)", cmd);
 		return -EINVAL;
 	}
@@ -1843,7 +1849,7 @@
 	if (r)
 		goto out;
 
-	param->data_size = sizeof(*param);
+	param->data_size = offsetof(struct dm_ioctl, data);
 	r = fn(param, input_param_size);
 
 	if (unlikely(param->flags & DM_BUFFER_FULL_FLAG) &&
--- linux-4.4.0.orig/drivers/md/dm-kcopyd.c
+++ linux-4.4.0/drivers/md/dm-kcopyd.c
@@ -55,15 +55,17 @@
 	struct dm_kcopyd_throttle *throttle;
 
 /*
- * We maintain three lists of jobs:
+ * We maintain four lists of jobs:
  *
  * i)   jobs waiting for pages
  * ii)  jobs that have pages, and are waiting for the io to be issued.
- * iii) jobs that have completed.
+ * iii) jobs that don't need to do any IO and just run a callback
+ * iv) jobs that have completed.
  *
- * All three of these are protected by job_lock.
+ * All four of these are protected by job_lock.
  */
 	spinlock_t job_lock;
+	struct list_head callback_jobs;
 	struct list_head complete_jobs;
 	struct list_head io_jobs;
 	struct list_head pages_jobs;
@@ -454,6 +456,8 @@
 	if (atomic_dec_and_test(&kc->nr_jobs))
 		wake_up(&kc->destroyq);
 
+	cond_resched();
+
 	return 0;
 }
 
@@ -581,6 +585,7 @@
 	struct dm_kcopyd_client *kc = container_of(work,
 					struct dm_kcopyd_client, kcopyd_work);
 	struct blk_plug plug;
+	unsigned long flags;
 
 	/*
 	 * The order that these are called is *very* important.
@@ -589,6 +594,10 @@
 	 * list.  io jobs call wake when they complete and it all
 	 * starts again.
 	 */
+	spin_lock_irqsave(&kc->job_lock, flags);
+	list_splice_tail_init(&kc->callback_jobs, &kc->complete_jobs);
+	spin_unlock_irqrestore(&kc->job_lock, flags);
+
 	blk_start_plug(&plug);
 	process_jobs(&kc->complete_jobs, kc, run_complete_job);
 	process_jobs(&kc->pages_jobs, kc, run_pages_job);
@@ -606,7 +615,7 @@
 	struct dm_kcopyd_client *kc = job->kc;
 	atomic_inc(&kc->nr_jobs);
 	if (unlikely(!job->source.count))
-		push(&kc->complete_jobs, job);
+		push(&kc->callback_jobs, job);
 	else if (job->pages == &zero_page_list)
 		push(&kc->io_jobs, job);
 	else
@@ -793,7 +802,7 @@
 	job->read_err = read_err;
 	job->write_err = write_err;
 
-	push(&kc->complete_jobs, job);
+	push(&kc->callback_jobs, job);
 	wake(kc);
 }
 EXPORT_SYMBOL(dm_kcopyd_do_callback);
@@ -818,11 +827,12 @@
 	int r = -ENOMEM;
 	struct dm_kcopyd_client *kc;
 
-	kc = kmalloc(sizeof(*kc), GFP_KERNEL);
+	kc = kzalloc(sizeof(*kc), GFP_KERNEL);
 	if (!kc)
 		return ERR_PTR(-ENOMEM);
 
 	spin_lock_init(&kc->job_lock);
+	INIT_LIST_HEAD(&kc->callback_jobs);
 	INIT_LIST_HEAD(&kc->complete_jobs);
 	INIT_LIST_HEAD(&kc->io_jobs);
 	INIT_LIST_HEAD(&kc->pages_jobs);
@@ -872,6 +882,7 @@
 	/* Wait for completion of all jobs submitted by this client. */
 	wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
 
+	BUG_ON(!list_empty(&kc->callback_jobs));
 	BUG_ON(!list_empty(&kc->complete_jobs));
 	BUG_ON(!list_empty(&kc->io_jobs));
 	BUG_ON(!list_empty(&kc->pages_jobs));
--- linux-4.4.0.orig/drivers/md/dm-log-writes.c
+++ linux-4.4.0/drivers/md/dm-log-writes.c
@@ -258,12 +258,12 @@
 		goto out;
 	sector++;
 
-	bio = bio_alloc(GFP_KERNEL, block->vec_cnt);
+	atomic_inc(&lc->io_blocks);
+	bio = bio_alloc(GFP_KERNEL, min(block->vec_cnt, BIO_MAX_PAGES));
 	if (!bio) {
 		DMERR("Couldn't alloc log bio");
 		goto error;
 	}
-	atomic_inc(&lc->io_blocks);
 	bio->bi_iter.bi_size = 0;
 	bio->bi_iter.bi_sector = sector;
 	bio->bi_bdev = lc->logdev->bdev;
@@ -280,7 +280,7 @@
 		if (ret != block->vecs[i].bv_len) {
 			atomic_inc(&lc->io_blocks);
 			submit_bio(WRITE, bio);
-			bio = bio_alloc(GFP_KERNEL, block->vec_cnt - i);
+			bio = bio_alloc(GFP_KERNEL, min(block->vec_cnt - i, BIO_MAX_PAGES));
 			if (!bio) {
 				DMERR("Couldn't alloc log bio");
 				goto error;
@@ -456,9 +456,9 @@
 		goto bad;
 	}
 
-	ret = -EINVAL;
 	lc->log_kthread = kthread_run(log_writes_kthread, lc, "log-write");
-	if (!lc->log_kthread) {
+	if (IS_ERR(lc->log_kthread)) {
+		ret = PTR_ERR(lc->log_kthread);
 		ti->error = "Couldn't alloc kthread";
 		dm_put_device(ti, lc->dev);
 		dm_put_device(ti, lc->logdev);
--- linux-4.4.0.orig/drivers/md/dm-mpath.c
+++ linux-4.4.0/drivers/md/dm-mpath.c
@@ -1220,10 +1220,10 @@
 {
 	struct pgpath *pgpath =
 		container_of(work, struct pgpath, activate_path.work);
+	struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev);
 
-	if (pgpath->is_active)
-		scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev),
-				 pg_init_done, pgpath);
+	if (pgpath->is_active && !blk_queue_dying(q))
+		scsi_dh_activate(q, pg_init_done, pgpath);
 	else
 		pg_init_done(pgpath, SCSI_DH_DEV_OFFLINED);
 }
--- linux-4.4.0.orig/drivers/md/dm-raid1.c
+++ linux-4.4.0/drivers/md/dm-raid1.c
@@ -1288,6 +1288,7 @@
 
 			dm_bio_restore(bd, bio);
 			bio_record->details.bi_bdev = NULL;
+			bio->bi_error = 0;
 
 			queue_bio(ms, bio, rw);
 			return DM_ENDIO_INCOMPLETE;
--- linux-4.4.0.orig/drivers/md/dm-region-hash.c
+++ linux-4.4.0/drivers/md/dm-region-hash.c
@@ -179,7 +179,7 @@
 		;
 	nr_buckets >>= 1;
 
-	rh = kmalloc(sizeof(*rh), GFP_KERNEL);
+	rh = kzalloc(sizeof(*rh), GFP_KERNEL);
 	if (!rh) {
 		DMERR("unable to allocate region hash memory");
 		return ERR_PTR(-ENOMEM);
--- linux-4.4.0.orig/drivers/md/dm-snap-persistent.c
+++ linux-4.4.0/drivers/md/dm-snap-persistent.c
@@ -17,7 +17,7 @@
 #include "dm-bufio.h"
 
 #define DM_MSG_PREFIX "persistent snapshot"
-#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32	/* 16KB */
+#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32U	/* 16KB */
 
 #define DM_PREFETCH_CHUNKS		12
 
@@ -695,7 +695,7 @@
 }
 
 static void persistent_commit_exception(struct dm_exception_store *store,
-					struct dm_exception *e,
+					struct dm_exception *e, int valid,
 					void (*callback) (void *, int success),
 					void *callback_context)
 {
@@ -704,6 +704,9 @@
 	struct core_exception ce;
 	struct commit_callback *cb;
 
+	if (!valid)
+		ps->valid = 0;
+
 	ce.old_chunk = e->old_chunk;
 	ce.new_chunk = e->new_chunk;
 	write_exception(ps, ps->current_committed++, &ce);
--- linux-4.4.0.orig/drivers/md/dm-snap-transient.c
+++ linux-4.4.0/drivers/md/dm-snap-transient.c
@@ -52,12 +52,12 @@
 }
 
 static void transient_commit_exception(struct dm_exception_store *store,
-				       struct dm_exception *e,
+				       struct dm_exception *e, int valid,
 				       void (*callback) (void *, int success),
 				       void *callback_context)
 {
 	/* Just succeed */
-	callback(callback_context, 1);
+	callback(callback_context, valid);
 }
 
 static void transient_usage(struct dm_exception_store *store,
--- linux-4.4.0.orig/drivers/md/dm-snap.c
+++ linux-4.4.0/drivers/md/dm-snap.c
@@ -47,7 +47,7 @@
 };
 
 struct dm_snapshot {
-	struct rw_semaphore lock;
+	struct mutex lock;
 
 	struct dm_dev *origin;
 	struct dm_dev *cow;
@@ -105,6 +105,9 @@
 	/* The on disk metadata handler */
 	struct dm_exception_store *store;
 
+	unsigned in_progress;
+	wait_queue_head_t in_progress_wait;
+
 	struct dm_kcopyd_client *kcopyd_client;
 
 	/* Wait for events based on state_bits */
@@ -145,6 +148,19 @@
 #define RUNNING_MERGE          0
 #define SHUTDOWN_MERGE         1
 
+/*
+ * Maximum number of chunks being copied on write.
+ *
+ * The value was decided experimentally as a trade-off between memory
+ * consumption, stalling the kernel's workqueues and maintaining a high enough
+ * throughput.
+ */
+#define DEFAULT_COW_THRESHOLD 2048
+
+static unsigned cow_threshold = DEFAULT_COW_THRESHOLD;
+module_param_named(snapshot_cow_threshold, cow_threshold, uint, 0644);
+MODULE_PARM_DESC(snapshot_cow_threshold, "Maximum number of chunks being copied on write");
+
 DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(snapshot_copy_throttle,
 		"A percentage of time allocated for copy on write");
 
@@ -440,9 +456,9 @@
 		if (!bdev_equal(s->cow->bdev, snap->cow->bdev))
 			continue;
 
-		down_read(&s->lock);
+		mutex_lock(&s->lock);
 		active = s->active;
-		up_read(&s->lock);
+		mutex_unlock(&s->lock);
 
 		if (active) {
 			if (snap_src)
@@ -910,7 +926,7 @@
 	int r;
 	chunk_t old_chunk = s->first_merging_chunk + s->num_merging_chunks - 1;
 
-	down_write(&s->lock);
+	mutex_lock(&s->lock);
 
 	/*
 	 * Process chunks (and associated exceptions) in reverse order
@@ -925,7 +941,7 @@
 	b = __release_queued_bios_after_merge(s);
 
 out:
-	up_write(&s->lock);
+	mutex_unlock(&s->lock);
 	if (b)
 		flush_bios(b);
 
@@ -984,9 +1000,9 @@
 		if (linear_chunks < 0) {
 			DMERR("Read error in exception store: "
 			      "shutting down merge");
-			down_write(&s->lock);
+			mutex_lock(&s->lock);
 			s->merge_failed = 1;
-			up_write(&s->lock);
+			mutex_unlock(&s->lock);
 		}
 		goto shut;
 	}
@@ -1027,10 +1043,10 @@
 		previous_count = read_pending_exceptions_done_count();
 	}
 
-	down_write(&s->lock);
+	mutex_lock(&s->lock);
 	s->first_merging_chunk = old_chunk;
 	s->num_merging_chunks = linear_chunks;
-	up_write(&s->lock);
+	mutex_unlock(&s->lock);
 
 	/* Wait until writes to all 'linear_chunks' drain */
 	for (i = 0; i < linear_chunks; i++)
@@ -1072,10 +1088,10 @@
 	return;
 
 shut:
-	down_write(&s->lock);
+	mutex_lock(&s->lock);
 	s->merge_failed = 1;
 	b = __release_queued_bios_after_merge(s);
-	up_write(&s->lock);
+	mutex_unlock(&s->lock);
 	error_bios(b);
 
 	merge_shutdown(s);
@@ -1106,6 +1122,7 @@
 	int i;
 	int r = -EINVAL;
 	char *origin_path, *cow_path;
+	dev_t origin_dev, cow_dev;
 	unsigned args_used, num_flush_bios = 1;
 	fmode_t origin_mode = FMODE_READ;
 
@@ -1120,7 +1137,7 @@
 		origin_mode = FMODE_WRITE;
 	}
 
-	s = kmalloc(sizeof(*s), GFP_KERNEL);
+	s = kzalloc(sizeof(*s), GFP_KERNEL);
 	if (!s) {
 		ti->error = "Cannot allocate private snapshot structure";
 		r = -ENOMEM;
@@ -1136,11 +1153,19 @@
 		ti->error = "Cannot get origin device";
 		goto bad_origin;
 	}
+	origin_dev = s->origin->bdev->bd_dev;
 
 	cow_path = argv[0];
 	argv++;
 	argc--;
 
+	cow_dev = dm_get_dev_t(cow_path);
+	if (cow_dev && cow_dev == origin_dev) {
+		ti->error = "COW device cannot be the same as origin device";
+		r = -EINVAL;
+		goto bad_cow;
+	}
+
 	r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow);
 	if (r) {
 		ti->error = "Cannot get COW device";
@@ -1165,7 +1190,7 @@
 	s->exception_start_sequence = 0;
 	s->exception_complete_sequence = 0;
 	INIT_LIST_HEAD(&s->out_of_order_list);
-	init_rwsem(&s->lock);
+	mutex_init(&s->lock);
 	INIT_LIST_HEAD(&s->list);
 	spin_lock_init(&s->pe_lock);
 	s->state_bits = 0;
@@ -1181,6 +1206,8 @@
 		goto bad_hash_tables;
 	}
 
+	init_waitqueue_head(&s->in_progress_wait);
+
 	s->kcopyd_client = dm_kcopyd_client_create(&dm_kcopyd_throttle);
 	if (IS_ERR(s->kcopyd_client)) {
 		r = PTR_ERR(s->kcopyd_client);
@@ -1330,9 +1357,9 @@
 	/* Check whether exception handover must be cancelled */
 	(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
 	if (snap_src && snap_dest && (s == snap_src)) {
-		down_write(&snap_dest->lock);
+		mutex_lock(&snap_dest->lock);
 		snap_dest->valid = 0;
-		up_write(&snap_dest->lock);
+		mutex_unlock(&snap_dest->lock);
 		DMERR("Cancelling snapshot handover.");
 	}
 	up_read(&_origins_lock);
@@ -1363,13 +1390,62 @@
 
 	dm_exception_store_destroy(s->store);
 
+	mutex_destroy(&s->lock);
+
 	dm_put_device(ti, s->cow);
 
 	dm_put_device(ti, s->origin);
 
+	WARN_ON(s->in_progress);
+
 	kfree(s);
 }
 
+static void account_start_copy(struct dm_snapshot *s)
+{
+	spin_lock(&s->in_progress_wait.lock);
+	s->in_progress++;
+	spin_unlock(&s->in_progress_wait.lock);
+}
+
+static void account_end_copy(struct dm_snapshot *s)
+{
+	spin_lock(&s->in_progress_wait.lock);
+	BUG_ON(!s->in_progress);
+	s->in_progress--;
+	if (likely(s->in_progress <= cow_threshold) &&
+	    unlikely(waitqueue_active(&s->in_progress_wait)))
+		wake_up_locked(&s->in_progress_wait);
+	spin_unlock(&s->in_progress_wait.lock);
+}
+
+static bool wait_for_in_progress(struct dm_snapshot *s, bool unlock_origins)
+{
+	if (unlikely(s->in_progress > cow_threshold)) {
+		spin_lock(&s->in_progress_wait.lock);
+		if (likely(s->in_progress > cow_threshold)) {
+			/*
+			 * NOTE: this throttle doesn't account for whether
+			 * the caller is servicing an IO that will trigger a COW
+			 * so excess throttling may result for chunks not required
+			 * to be COW'd.  But if cow_threshold was reached, extra
+			 * throttling is unlikely to negatively impact performance.
+			 */
+			DECLARE_WAITQUEUE(wait, current);
+			__add_wait_queue(&s->in_progress_wait, &wait);
+			__set_current_state(TASK_UNINTERRUPTIBLE);
+			spin_unlock(&s->in_progress_wait.lock);
+			if (unlock_origins)
+				up_read(&_origins_lock);
+			io_schedule();
+			remove_wait_queue(&s->in_progress_wait, &wait);
+			return false;
+		}
+		spin_unlock(&s->in_progress_wait.lock);
+	}
+	return true;
+}
+
 /*
  * Flush a list of buffers.
  */
@@ -1385,7 +1461,7 @@
 	}
 }
 
-static int do_origin(struct dm_dev *origin, struct bio *bio);
+static int do_origin(struct dm_dev *origin, struct bio *bio, bool limit);
 
 /*
  * Flush a list of buffers.
@@ -1398,7 +1474,7 @@
 	while (bio) {
 		n = bio->bi_next;
 		bio->bi_next = NULL;
-		r = do_origin(s->origin, bio);
+		r = do_origin(s->origin, bio, false);
 		if (r == DM_MAPIO_REMAPPED)
 			generic_make_request(bio);
 		bio = n;
@@ -1438,8 +1514,9 @@
 	dm_table_event(s->ti->table);
 }
 
-static void pending_complete(struct dm_snap_pending_exception *pe, int success)
+static void pending_complete(void *context, int success)
 {
+	struct dm_snap_pending_exception *pe = context;
 	struct dm_exception *e;
 	struct dm_snapshot *s = pe->snap;
 	struct bio *origin_bios = NULL;
@@ -1449,7 +1526,7 @@
 
 	if (!success) {
 		/* Read/write error - snapshot is unusable */
-		down_write(&s->lock);
+		mutex_lock(&s->lock);
 		__invalidate_snapshot(s, -EIO);
 		error = 1;
 		goto out;
@@ -1457,14 +1534,14 @@
 
 	e = alloc_completed_exception(GFP_NOIO);
 	if (!e) {
-		down_write(&s->lock);
+		mutex_lock(&s->lock);
 		__invalidate_snapshot(s, -ENOMEM);
 		error = 1;
 		goto out;
 	}
 	*e = pe->e;
 
-	down_write(&s->lock);
+	mutex_lock(&s->lock);
 	if (!s->valid) {
 		free_completed_exception(e);
 		error = 1;
@@ -1491,7 +1568,7 @@
 	}
 	increment_pending_exceptions_done_count();
 
-	up_write(&s->lock);
+	mutex_unlock(&s->lock);
 
 	/* Submit any pending write bios */
 	if (error) {
@@ -1509,24 +1586,13 @@
 	free_pending_exception(pe);
 }
 
-static void commit_callback(void *context, int success)
-{
-	struct dm_snap_pending_exception *pe = context;
-
-	pending_complete(pe, success);
-}
-
 static void complete_exception(struct dm_snap_pending_exception *pe)
 {
 	struct dm_snapshot *s = pe->snap;
 
-	if (unlikely(pe->copy_error))
-		pending_complete(pe, 0);
-
-	else
-		/* Update the metadata if we are persistent */
-		s->store->type->commit_exception(s->store, &pe->e,
-						 commit_callback, pe);
+	/* Update the metadata if we are persistent */
+	s->store->type->commit_exception(s->store, &pe->e, !pe->copy_error,
+					 pending_complete, pe);
 }
 
 /*
@@ -1564,6 +1630,7 @@
 		}
 		list_add(&pe->out_of_order_entry, lh);
 	}
+	account_end_copy(s);
 }
 
 /*
@@ -1587,6 +1654,7 @@
 	dest.count = src.count;
 
 	/* Hand over to kcopyd */
+	account_start_copy(s);
 	dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe);
 }
 
@@ -1607,6 +1675,7 @@
 	pe->full_bio_end_io = bio->bi_end_io;
 	pe->full_bio_private = bio->bi_private;
 
+	account_start_copy(s);
 	callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client,
 						   copy_callback, pe);
 
@@ -1697,9 +1766,12 @@
 	if (!s->valid)
 		return -EIO;
 
-	/* FIXME: should only take write lock if we need
-	 * to copy an exception */
-	down_write(&s->lock);
+	if (bio_data_dir(bio) == WRITE) {
+		while (unlikely(!wait_for_in_progress(s, false)))
+			; /* wait_for_in_progress() has slept */
+	}
+
+	mutex_lock(&s->lock);
 
 	if (!s->valid || (unlikely(s->snapshot_overflowed) && bio_rw(bio) == WRITE)) {
 		r = -EIO;
@@ -1721,9 +1793,9 @@
 	if (bio_rw(bio) == WRITE) {
 		pe = __lookup_pending_exception(s, chunk);
 		if (!pe) {
-			up_write(&s->lock);
+			mutex_unlock(&s->lock);
 			pe = alloc_pending_exception(s);
-			down_write(&s->lock);
+			mutex_lock(&s->lock);
 
 			if (!s->valid || s->snapshot_overflowed) {
 				free_pending_exception(pe);
@@ -1758,7 +1830,7 @@
 		    bio->bi_iter.bi_size ==
 		    (s->store->chunk_size << SECTOR_SHIFT)) {
 			pe->started = 1;
-			up_write(&s->lock);
+			mutex_unlock(&s->lock);
 			start_full_bio(pe, bio);
 			goto out;
 		}
@@ -1768,7 +1840,7 @@
 		if (!pe->started) {
 			/* this is protected by snap->lock */
 			pe->started = 1;
-			up_write(&s->lock);
+			mutex_unlock(&s->lock);
 			start_copy(pe);
 			goto out;
 		}
@@ -1778,7 +1850,7 @@
 	}
 
 out_unlock:
-	up_write(&s->lock);
+	mutex_unlock(&s->lock);
 out:
 	return r;
 }
@@ -1814,7 +1886,7 @@
 
 	chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector);
 
-	down_write(&s->lock);
+	mutex_lock(&s->lock);
 
 	/* Full merging snapshots are redirected to the origin */
 	if (!s->valid)
@@ -1845,12 +1917,12 @@
 	bio->bi_bdev = s->origin->bdev;
 
 	if (bio_rw(bio) == WRITE) {
-		up_write(&s->lock);
-		return do_origin(s->origin, bio);
+		mutex_unlock(&s->lock);
+		return do_origin(s->origin, bio, false);
 	}
 
 out_unlock:
-	up_write(&s->lock);
+	mutex_unlock(&s->lock);
 
 	return r;
 }
@@ -1881,7 +1953,7 @@
 	down_read(&_origins_lock);
 	(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
 	if (snap_src && snap_dest) {
-		down_read(&snap_src->lock);
+		mutex_lock(&snap_src->lock);
 		if (s == snap_src) {
 			DMERR("Unable to resume snapshot source until "
 			      "handover completes.");
@@ -1891,7 +1963,7 @@
 			      "source is suspended.");
 			r = -EINVAL;
 		}
-		up_read(&snap_src->lock);
+		mutex_unlock(&snap_src->lock);
 	}
 	up_read(&_origins_lock);
 
@@ -1937,11 +2009,11 @@
 
 	(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
 	if (snap_src && snap_dest) {
-		down_write(&snap_src->lock);
-		down_write_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING);
+		mutex_lock(&snap_src->lock);
+		mutex_lock_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING);
 		__handover_exceptions(snap_src, snap_dest);
-		up_write(&snap_dest->lock);
-		up_write(&snap_src->lock);
+		mutex_unlock(&snap_dest->lock);
+		mutex_unlock(&snap_src->lock);
 	}
 
 	up_read(&_origins_lock);
@@ -1956,9 +2028,9 @@
 	/* Now we have correct chunk size, reregister */
 	reregister_snapshot(s);
 
-	down_write(&s->lock);
+	mutex_lock(&s->lock);
 	s->active = 1;
-	up_write(&s->lock);
+	mutex_unlock(&s->lock);
 }
 
 static uint32_t get_origin_minimum_chunksize(struct block_device *bdev)
@@ -1998,7 +2070,7 @@
 	switch (type) {
 	case STATUSTYPE_INFO:
 
-		down_write(&snap->lock);
+		mutex_lock(&snap->lock);
 
 		if (!snap->valid)
 			DMEMIT("Invalid");
@@ -2023,7 +2095,7 @@
 				DMEMIT("Unknown");
 		}
 
-		up_write(&snap->lock);
+		mutex_unlock(&snap->lock);
 
 		break;
 
@@ -2089,7 +2161,7 @@
 		if (dm_target_is_snapshot_merge(snap->ti))
 			continue;
 
-		down_write(&snap->lock);
+		mutex_lock(&snap->lock);
 
 		/* Only deal with valid and active snapshots */
 		if (!snap->valid || !snap->active)
@@ -2116,9 +2188,9 @@
 
 		pe = __lookup_pending_exception(snap, chunk);
 		if (!pe) {
-			up_write(&snap->lock);
+			mutex_unlock(&snap->lock);
 			pe = alloc_pending_exception(snap);
-			down_write(&snap->lock);
+			mutex_lock(&snap->lock);
 
 			if (!snap->valid) {
 				free_pending_exception(pe);
@@ -2161,7 +2233,7 @@
 		}
 
 next_snapshot:
-		up_write(&snap->lock);
+		mutex_unlock(&snap->lock);
 
 		if (pe_to_start_now) {
 			start_copy(pe_to_start_now);
@@ -2182,15 +2254,24 @@
 /*
  * Called on a write from the origin driver.
  */
-static int do_origin(struct dm_dev *origin, struct bio *bio)
+static int do_origin(struct dm_dev *origin, struct bio *bio, bool limit)
 {
 	struct origin *o;
 	int r = DM_MAPIO_REMAPPED;
 
+again:
 	down_read(&_origins_lock);
 	o = __lookup_origin(origin->bdev);
-	if (o)
+	if (o) {
+		if (limit) {
+			struct dm_snapshot *s;
+			list_for_each_entry(s, &o->snapshots, list)
+				if (unlikely(!wait_for_in_progress(s, true)))
+					goto again;
+		}
+
 		r = __origin_write(&o->snapshots, bio->bi_iter.bi_sector, bio);
+	}
 	up_read(&_origins_lock);
 
 	return r;
@@ -2303,7 +2384,7 @@
 		dm_accept_partial_bio(bio, available_sectors);
 
 	/* Only tell snapshots if this is a write */
-	return do_origin(o->dev, bio);
+	return do_origin(o->dev, bio, true);
 }
 
 /*
--- linux-4.4.0.orig/drivers/md/dm-stats.c
+++ linux-4.4.0/drivers/md/dm-stats.c
@@ -175,6 +175,7 @@
 	int cpu;
 	struct dm_stat *s = container_of(head, struct dm_stat, rcu_head);
 
+	kfree(s->histogram_boundaries);
 	kfree(s->program_id);
 	kfree(s->aux_data);
 	for_each_possible_cpu(cpu) {
--- linux-4.4.0.orig/drivers/md/dm-table.c
+++ linux-4.4.0/drivers/md/dm-table.c
@@ -183,7 +183,12 @@
 int dm_table_create(struct dm_table **result, fmode_t mode,
 		    unsigned num_targets, struct mapped_device *md)
 {
-	struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
+	struct dm_table *t;
+
+	if (num_targets > DM_MAX_TARGETS)
+		return -EOVERFLOW;
+
+	t = kzalloc(sizeof(*t), GFP_KERNEL);
 
 	if (!t)
 		return -ENOMEM;
@@ -198,7 +203,7 @@
 
 	if (!num_targets) {
 		kfree(t);
-		return -ENOMEM;
+		return -EOVERFLOW;
 	}
 
 	if (alloc_targets(t, num_targets)) {
@@ -365,6 +370,26 @@
 }
 
 /*
+ * Convert the path to a device
+ */
+dev_t dm_get_dev_t(const char *path)
+{
+	dev_t uninitialized_var(dev);
+	struct block_device *bdev;
+
+	bdev = lookup_bdev(path, 0);
+	if (IS_ERR(bdev))
+		dev = name_to_dev_t(path);
+	else {
+		dev = bdev->bd_dev;
+		bdput(bdev);
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(dm_get_dev_t);
+
+/*
  * Add a device to the list, or just increment the usage count if
  * it's already present.
  */
@@ -372,22 +397,23 @@
 		  struct dm_dev **result)
 {
 	int r;
-	dev_t uninitialized_var(dev);
+	dev_t dev;
+	unsigned int major, minor;
+	char dummy;
 	struct dm_dev_internal *dd;
 	struct dm_table *t = ti->table;
-	struct block_device *bdev;
 
 	BUG_ON(!t);
 
-	/* convert the path to a device */
-	bdev = lookup_bdev(path);
-	if (IS_ERR(bdev)) {
-		dev = name_to_dev_t(path);
+	if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) {
+		/* Extract the major/minor numbers */
+		dev = MKDEV(major, minor);
+		if (MAJOR(dev) != major || MINOR(dev) != minor)
+			return -EOVERFLOW;
+	} else {
+		dev = dm_get_dev_t(path);
 		if (!dev)
 			return -ENODEV;
-	} else {
-		dev = bdev->bd_dev;
-		bdput(bdev);
 	}
 
 	dd = find_device(&t->devices, dev);
@@ -1142,12 +1168,6 @@
 
 void dm_table_event(struct dm_table *t)
 {
-	/*
-	 * You can no longer call dm_table_event() from interrupt
-	 * context, use a bottom half instead.
-	 */
-	BUG_ON(in_interrupt());
-
 	mutex_lock(&_event_lock);
 	if (t->event_fn)
 		t->event_fn(t->event_context);
@@ -1155,7 +1175,7 @@
 }
 EXPORT_SYMBOL(dm_table_event);
 
-sector_t dm_table_get_size(struct dm_table *t)
+inline sector_t dm_table_get_size(struct dm_table *t)
 {
 	return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0;
 }
@@ -1180,6 +1200,9 @@
 	unsigned int l, n = 0, k = 0;
 	sector_t *node;
 
+	if (unlikely(sector >= dm_table_get_size(t)))
+		return &t->targets[t->num_targets];
+
 	for (l = 0; l < t->depth; l++) {
 		n = get_child(n, k);
 		node = get_node(t, l, n);
@@ -1192,6 +1215,46 @@
 	return &t->targets[(KEYS_PER_NODE * n) + k];
 }
 
+/*
+ * type->iterate_devices() should be called when the sanity check needs to
+ * iterate and check all underlying data devices. iterate_devices() will
+ * iterate all underlying data devices until it encounters a non-zero return
+ * code, returned by whether the input iterate_devices_callout_fn, or
+ * iterate_devices() itself internally.
+ *
+ * For some target type (e.g. dm-stripe), one call of iterate_devices() may
+ * iterate multiple underlying devices internally, in which case a non-zero
+ * return code returned by iterate_devices_callout_fn will stop the iteration
+ * in advance.
+ *
+ * Cases requiring _any_ underlying device supporting some kind of attribute,
+ * should use the iteration structure like dm_table_any_dev_attr(), or call
+ * it directly. @func should handle semantics of positive examples, e.g.
+ * capable of something.
+ *
+ * Cases requiring _all_ underlying devices supporting some kind of attribute,
+ * should use the iteration structure like dm_table_supports_nowait() or
+ * dm_table_supports_discards(). Or introduce dm_table_all_devs_attr() that
+ * uses an @anti_func that handle semantics of counter examples, e.g. not
+ * capable of something. So: return !dm_table_any_dev_attr(t, anti_func);
+ */
+static bool dm_table_any_dev_attr(struct dm_table *t,
+				  iterate_devices_callout_fn func)
+{
+	struct dm_target *ti;
+	unsigned int i;
+
+	for (i = 0; i < dm_table_get_num_targets(t); i++) {
+		ti = dm_table_get_target(t, i);
+
+		if (ti->type->iterate_devices &&
+		    ti->type->iterate_devices(ti, func, NULL))
+			return true;
+        }
+
+	return false;
+}
+
 static int count_device(struct dm_target *ti, struct dm_dev *dev,
 			sector_t start, sector_t len, void *data)
 {
@@ -1362,12 +1425,12 @@
 	return true;
 }
 
-static int device_is_nonrot(struct dm_target *ti, struct dm_dev *dev,
-			    sector_t start, sector_t len, void *data)
+static int device_is_rotational(struct dm_target *ti, struct dm_dev *dev,
+				sector_t start, sector_t len, void *data)
 {
 	struct request_queue *q = bdev_get_queue(dev->bdev);
 
-	return q && blk_queue_nonrot(q);
+	return q && !blk_queue_nonrot(q);
 }
 
 static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev,
@@ -1378,29 +1441,12 @@
 	return q && !blk_queue_add_random(q);
 }
 
-static int queue_supports_sg_merge(struct dm_target *ti, struct dm_dev *dev,
-				   sector_t start, sector_t len, void *data)
+static int queue_no_sg_merge(struct dm_target *ti, struct dm_dev *dev,
+			     sector_t start, sector_t len, void *data)
 {
 	struct request_queue *q = bdev_get_queue(dev->bdev);
 
-	return q && !test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags);
-}
-
-static bool dm_table_all_devices_attribute(struct dm_table *t,
-					   iterate_devices_callout_fn func)
-{
-	struct dm_target *ti;
-	unsigned i = 0;
-
-	while (i < dm_table_get_num_targets(t)) {
-		ti = dm_table_get_target(t, i++);
-
-		if (!ti->type->iterate_devices ||
-		    !ti->type->iterate_devices(ti, func, NULL))
-			return false;
-	}
-
-	return true;
+	return q && test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags);
 }
 
 static int device_not_write_same_capable(struct dm_target *ti, struct dm_dev *dev,
@@ -1493,18 +1539,18 @@
 		q->limits.discard_zeroes_data = 0;
 
 	/* Ensure that all underlying devices are non-rotational. */
-	if (dm_table_all_devices_attribute(t, device_is_nonrot))
-		queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
-	else
+	if (dm_table_any_dev_attr(t, device_is_rotational))
 		queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q);
+	else
+		queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
 
 	if (!dm_table_supports_write_same(t))
 		q->limits.max_write_same_sectors = 0;
 
-	if (dm_table_all_devices_attribute(t, queue_supports_sg_merge))
-		queue_flag_clear_unlocked(QUEUE_FLAG_NO_SG_MERGE, q);
-	else
+	if (dm_table_any_dev_attr(t, queue_no_sg_merge))
 		queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q);
+	else
+		queue_flag_clear_unlocked(QUEUE_FLAG_NO_SG_MERGE, q);
 
 	dm_table_verify_integrity(t);
 
@@ -1514,7 +1560,7 @@
 	 * Clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not
 	 * have it set.
 	 */
-	if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random))
+	if (blk_queue_add_random(q) && dm_table_any_dev_attr(t, device_is_not_random))
 		queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q);
 
 	/*
@@ -1647,7 +1693,7 @@
 		char b[BDEVNAME_SIZE];
 
 		if (likely(q))
-			r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+			r |= bdi_congested(q->backing_dev_info, bdi_bits);
 		else
 			DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
 				     dm_device_name(t->md),
--- linux-4.4.0.orig/drivers/md/dm-thin-metadata.c
+++ linux-4.4.0/drivers/md/dm-thin-metadata.c
@@ -81,10 +81,14 @@
 #define SECTOR_TO_BLOCK_SHIFT 3
 
 /*
+ * For btree insert:
  *  3 for btree insert +
  *  2 for btree lookup used within space map
+ * For btree remove:
+ *  2 for shadow spine +
+ *  4 for rebalance 3 child node
  */
-#define THIN_MAX_CONCURRENT_LOCKS 5
+#define THIN_MAX_CONCURRENT_LOCKS 6
 
 /* This should be plenty */
 #define SPACE_MAP_ROOT_SIZE 128
@@ -186,6 +190,12 @@
 	sector_t data_block_size;
 
 	/*
+	 * We reserve a section of the metadata for commit overhead.
+	 * All reported space does *not* include this.
+	 */
+	dm_block_t metadata_reserve;
+
+	/*
 	 * Set if a transaction has to be aborted but the attempt to roll back
 	 * to the previous (good) transaction failed.  The only pool metadata
 	 * operation possible in this state is the closing of the device.
@@ -485,11 +495,11 @@
 	if (r < 0)
 		return r;
 
-	r = save_sm_roots(pmd);
+	r = dm_tm_pre_commit(pmd->tm);
 	if (r < 0)
 		return r;
 
-	r = dm_tm_pre_commit(pmd->tm);
+	r = save_sm_roots(pmd);
 	if (r < 0)
 		return r;
 
@@ -690,12 +700,16 @@
 					  THIN_MAX_CONCURRENT_LOCKS);
 	if (IS_ERR(pmd->bm)) {
 		DMERR("could not create block manager");
-		return PTR_ERR(pmd->bm);
+		r = PTR_ERR(pmd->bm);
+		pmd->bm = NULL;
+		return r;
 	}
 
 	r = __open_or_format_metadata(pmd, format_device);
-	if (r)
+	if (r) {
 		dm_block_manager_destroy(pmd->bm);
+		pmd->bm = NULL;
+	}
 
 	return r;
 }
@@ -823,6 +837,20 @@
 	return dm_tm_commit(pmd->tm, sblock);
 }
 
+static void __set_metadata_reserve(struct dm_pool_metadata *pmd)
+{
+	int r;
+	dm_block_t total;
+	dm_block_t max_blocks = 4096; /* 16M */
+
+	r = dm_sm_get_nr_blocks(pmd->metadata_sm, &total);
+	if (r) {
+		DMERR("could not get size of metadata device");
+		pmd->metadata_reserve = max_blocks;
+	} else
+		pmd->metadata_reserve = min(max_blocks, div_u64(total, 10));
+}
+
 struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
 					       sector_t data_block_size,
 					       bool format_device)
@@ -856,6 +884,8 @@
 		return ERR_PTR(r);
 	}
 
+	__set_metadata_reserve(pmd);
+
 	return pmd;
 }
 
@@ -1759,6 +1789,13 @@
 	down_read(&pmd->root_lock);
 	if (!pmd->fail_io)
 		r = dm_sm_get_nr_free(pmd->metadata_sm, result);
+
+	if (!r) {
+		if (*result < pmd->metadata_reserve)
+			*result = 0;
+		else
+			*result -= pmd->metadata_reserve;
+	}
 	up_read(&pmd->root_lock);
 
 	return r;
@@ -1871,8 +1908,11 @@
 	int r = -EINVAL;
 
 	down_write(&pmd->root_lock);
-	if (!pmd->fail_io)
+	if (!pmd->fail_io) {
 		r = __resize_space_map(pmd->metadata_sm, new_count);
+		if (!r)
+			__set_metadata_reserve(pmd);
+	}
 	up_write(&pmd->root_lock);
 
 	return r;
@@ -1943,5 +1983,8 @@
 
 void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd)
 {
-	dm_tm_issue_prefetches(pmd->tm);
+	down_read(&pmd->root_lock);
+	if (!pmd->fail_io)
+		dm_tm_issue_prefetches(pmd->tm);
+	up_read(&pmd->root_lock);
 }
--- linux-4.4.0.orig/drivers/md/dm-thin.c
+++ linux-4.4.0/drivers/md/dm-thin.c
@@ -200,7 +200,13 @@
 enum pool_mode {
 	PM_WRITE,		/* metadata may be changed */
 	PM_OUT_OF_DATA_SPACE,	/* metadata may be changed, though data may not be allocated */
+
+	/*
+	 * Like READ_ONLY, except may switch back to WRITE on metadata resize. Reported as READ_ONLY.
+	 */
+	PM_OUT_OF_METADATA_SPACE,
 	PM_READ_ONLY,		/* metadata may not be changed */
+
 	PM_FAIL,		/* all I/O fails */
 };
 
@@ -250,6 +256,7 @@
 
 	spinlock_t lock;
 	struct bio_list deferred_flush_bios;
+	struct bio_list deferred_flush_completions;
 	struct list_head prepared_mappings;
 	struct list_head prepared_discards;
 	struct list_head active_thins;
@@ -914,6 +921,39 @@
 	mempool_free(m, m->tc->pool->mapping_pool);
 }
 
+static void complete_overwrite_bio(struct thin_c *tc, struct bio *bio)
+{
+	struct pool *pool = tc->pool;
+	unsigned long flags;
+
+	/*
+	 * If the bio has the REQ_FUA flag set we must commit the metadata
+	 * before signaling its completion.
+	 */
+	if (!bio_triggers_commit(tc, bio)) {
+		bio_endio(bio);
+		return;
+	}
+
+	/*
+	 * Complete bio with an error if earlier I/O caused changes to the
+	 * metadata that can't be committed, e.g, due to I/O errors on the
+	 * metadata device.
+	 */
+	if (dm_thin_aborted_changes(tc->td)) {
+		bio_io_error(bio);
+		return;
+	}
+
+	/*
+	 * Batch together any bios that trigger commits and then issue a
+	 * single commit for them in process_deferred_bios().
+	 */
+	spin_lock_irqsave(&pool->lock, flags);
+	bio_list_add(&pool->deferred_flush_completions, bio);
+	spin_unlock_irqrestore(&pool->lock, flags);
+}
+
 static void process_prepared_mapping(struct dm_thin_new_mapping *m)
 {
 	struct thin_c *tc = m->tc;
@@ -946,7 +986,7 @@
 	 */
 	if (bio) {
 		inc_remap_and_issue_cell(tc, m->cell, m->data_block);
-		bio_endio(bio);
+		complete_overwrite_bio(tc, bio);
 	} else {
 		inc_all_io_entry(tc->pool, m->cell->holder);
 		remap_and_issue(tc, m->cell->holder, m->data_block);
@@ -1299,7 +1339,37 @@
 
 static void set_pool_mode(struct pool *pool, enum pool_mode new_mode);
 
-static void check_for_space(struct pool *pool)
+static void requeue_bios(struct pool *pool);
+
+static bool is_read_only_pool_mode(enum pool_mode mode)
+{
+	return (mode == PM_OUT_OF_METADATA_SPACE || mode == PM_READ_ONLY);
+}
+
+static bool is_read_only(struct pool *pool)
+{
+	return is_read_only_pool_mode(get_pool_mode(pool));
+}
+
+static void check_for_metadata_space(struct pool *pool)
+{
+	int r;
+	const char *ooms_reason = NULL;
+	dm_block_t nr_free;
+
+	r = dm_pool_get_free_metadata_block_count(pool->pmd, &nr_free);
+	if (r)
+		ooms_reason = "Could not get free metadata blocks";
+	else if (!nr_free)
+		ooms_reason = "No free metadata blocks";
+
+	if (ooms_reason && !is_read_only(pool)) {
+		DMERR("%s", ooms_reason);
+		set_pool_mode(pool, PM_OUT_OF_METADATA_SPACE);
+	}
+}
+
+static void check_for_data_space(struct pool *pool)
 {
 	int r;
 	dm_block_t nr_free;
@@ -1311,8 +1381,10 @@
 	if (r)
 		return;
 
-	if (nr_free)
+	if (nr_free) {
 		set_pool_mode(pool, PM_WRITE);
+		requeue_bios(pool);
+	}
 }
 
 /*
@@ -1323,14 +1395,16 @@
 {
 	int r;
 
-	if (get_pool_mode(pool) >= PM_READ_ONLY)
+	if (get_pool_mode(pool) >= PM_OUT_OF_METADATA_SPACE)
 		return -EINVAL;
 
 	r = dm_pool_commit_metadata(pool->pmd);
 	if (r)
 		metadata_operation_failed(pool, "dm_pool_commit_metadata", r);
-	else
-		check_for_space(pool);
+	else {
+		check_for_metadata_space(pool);
+		check_for_data_space(pool);
+	}
 
 	return r;
 }
@@ -1389,10 +1463,26 @@
 
 	r = dm_pool_alloc_data_block(pool->pmd, result);
 	if (r) {
-		metadata_operation_failed(pool, "dm_pool_alloc_data_block", r);
+		if (r == -ENOSPC)
+			set_pool_mode(pool, PM_OUT_OF_DATA_SPACE);
+		else
+			metadata_operation_failed(pool, "dm_pool_alloc_data_block", r);
+		return r;
+	}
+
+	r = dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks);
+	if (r) {
+		metadata_operation_failed(pool, "dm_pool_get_free_metadata_block_count", r);
 		return r;
 	}
 
+	if (!free_blocks) {
+		/* Let's commit before we use up the metadata reserve. */
+		r = commit(pool);
+		if (r)
+			return r;
+	}
+
 	return 0;
 }
 
@@ -1424,6 +1514,7 @@
 	case PM_OUT_OF_DATA_SPACE:
 		return pool->pf.error_if_no_space ? -ENOSPC : 0;
 
+	case PM_OUT_OF_METADATA_SPACE:
 	case PM_READ_ONLY:
 	case PM_FAIL:
 		return -EIO;
@@ -2171,7 +2262,7 @@
 {
 	unsigned long flags;
 	struct bio *bio;
-	struct bio_list bios;
+	struct bio_list bios, bio_completions;
 	struct thin_c *tc;
 
 	tc = get_first_thin(pool);
@@ -2182,26 +2273,36 @@
 	}
 
 	/*
-	 * If there are any deferred flush bios, we must commit
-	 * the metadata before issuing them.
+	 * If there are any deferred flush bios, we must commit the metadata
+	 * before issuing them or signaling their completion.
 	 */
 	bio_list_init(&bios);
+	bio_list_init(&bio_completions);
+
 	spin_lock_irqsave(&pool->lock, flags);
 	bio_list_merge(&bios, &pool->deferred_flush_bios);
 	bio_list_init(&pool->deferred_flush_bios);
+
+	bio_list_merge(&bio_completions, &pool->deferred_flush_completions);
+	bio_list_init(&pool->deferred_flush_completions);
 	spin_unlock_irqrestore(&pool->lock, flags);
 
-	if (bio_list_empty(&bios) &&
+	if (bio_list_empty(&bios) && bio_list_empty(&bio_completions) &&
 	    !(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool)))
 		return;
 
 	if (commit(pool)) {
+		bio_list_merge(&bios, &bio_completions);
+
 		while ((bio = bio_list_pop(&bios)))
 			bio_io_error(bio);
 		return;
 	}
 	pool->last_commit_jiffies = jiffies;
 
+	while ((bio = bio_list_pop(&bio_completions)))
+		bio_endio(bio);
+
 	while ((bio = bio_list_pop(&bios)))
 		generic_make_request(bio);
 }
@@ -2394,8 +2495,9 @@
 		error_retry_list(pool);
 		break;
 
+	case PM_OUT_OF_METADATA_SPACE:
 	case PM_READ_ONLY:
-		if (old_mode != new_mode)
+		if (!is_read_only_pool_mode(old_mode))
 			notify_of_pool_mode_change(pool, "read-only");
 		dm_pool_metadata_read_only(pool->pmd);
 		pool->process_bio = process_bio_read_only;
@@ -2634,7 +2736,7 @@
 		return 1;
 
 	q = bdev_get_queue(pt->data_dev->bdev);
-	return bdi_congested(&q->backing_dev_info, bdi_bits);
+	return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static void requeue_bios(struct pool *pool)
@@ -2780,7 +2882,7 @@
 		return (struct pool *)pmd;
 	}
 
-	pool = kmalloc(sizeof(*pool), GFP_KERNEL);
+	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
 	if (!pool) {
 		*error = "Error allocating memory for pool";
 		err_p = ERR_PTR(-ENOMEM);
@@ -2827,6 +2929,7 @@
 	INIT_DELAYED_WORK(&pool->no_space_timeout, do_no_space_timeout);
 	spin_lock_init(&pool->lock);
 	bio_list_init(&pool->deferred_flush_bios);
+	bio_list_init(&pool->deferred_flush_completions);
 	INIT_LIST_HEAD(&pool->prepared_mappings);
 	INIT_LIST_HEAD(&pool->prepared_discards);
 	INIT_LIST_HEAD(&pool->active_thins);
@@ -3107,6 +3210,13 @@
 	as.argc = argc;
 	as.argv = argv;
 
+	/* make sure metadata and data are different devices */
+	if (!strcmp(argv[0], argv[1])) {
+		ti->error = "Error setting metadata or data device";
+		r = -EINVAL;
+		goto out_unlock;
+	}
+
 	/*
 	 * Set default pool features.
 	 */
@@ -3326,6 +3436,10 @@
 		DMINFO("%s: growing the metadata device from %llu to %llu blocks",
 		       dm_device_name(pool->pool_md),
 		       sb_metadata_dev_size, metadata_dev_size);
+
+		if (get_pool_mode(pool) == PM_OUT_OF_METADATA_SPACE)
+			set_pool_mode(pool, PM_WRITE);
+
 		r = dm_pool_resize_metadata_dev(pool->pmd, metadata_dev_size);
 		if (r) {
 			metadata_operation_failed(pool, "dm_pool_resize_metadata_dev", r);
@@ -3453,8 +3567,8 @@
 	struct pool_c *pt = ti->private;
 	struct pool *pool = pt->pool;
 
-	cancel_delayed_work(&pool->waker);
-	cancel_delayed_work(&pool->no_space_timeout);
+	cancel_delayed_work_sync(&pool->waker);
+	cancel_delayed_work_sync(&pool->no_space_timeout);
 	flush_workqueue(pool->wq);
 	(void) commit(pool);
 }
@@ -3629,7 +3743,7 @@
 	struct pool_c *pt = ti->private;
 	struct pool *pool = pt->pool;
 
-	if (get_pool_mode(pool) >= PM_READ_ONLY) {
+	if (get_pool_mode(pool) >= PM_OUT_OF_METADATA_SPACE) {
 		DMERR("%s: unable to service pool target messages in READ_ONLY or FAIL mode",
 		      dm_device_name(pool->pool_md));
 		return -EOPNOTSUPP;
@@ -3703,6 +3817,7 @@
 	dm_block_t nr_blocks_data;
 	dm_block_t nr_blocks_metadata;
 	dm_block_t held_root;
+	enum pool_mode mode;
 	char buf[BDEVNAME_SIZE];
 	char buf2[BDEVNAME_SIZE];
 	struct pool_c *pt = ti->private;
@@ -3773,9 +3888,10 @@
 		else
 			DMEMIT("- ");
 
-		if (pool->pf.mode == PM_OUT_OF_DATA_SPACE)
+		mode = get_pool_mode(pool);
+		if (mode == PM_OUT_OF_DATA_SPACE)
 			DMEMIT("out_of_data_space ");
-		else if (pool->pf.mode == PM_READ_ONLY)
+		else if (is_read_only_pool_mode(mode))
 			DMEMIT("ro ");
 		else
 			DMEMIT("rw ");
@@ -3983,6 +4099,12 @@
 	tc->sort_bio_list = RB_ROOT;
 
 	if (argc == 3) {
+		if (!strcmp(argv[0], argv[2])) {
+			ti->error = "Error setting origin device";
+			r = -EINVAL;
+			goto bad_origin_dev;
+		}
+
 		r = dm_get_device(ti, argv[2], FMODE_READ, &origin_dev);
 		if (r) {
 			ti->error = "Error opening origin device";
--- linux-4.4.0.orig/drivers/md/dm-verity.c
+++ linux-4.4.0/drivers/md/dm-verity.c
@@ -221,8 +221,8 @@
 		BUG();
 	}
 
-	DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
-		block);
+	DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
+		    type_str, block);
 
 	if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
 		DMERR("%s: reached maximum errors", v->data_dev->name);
@@ -958,6 +958,7 @@
 
 static struct target_type verity_target = {
 	.name		= "verity",
+	.features	= DM_TARGET_IMMUTABLE,
 	.version	= {1, 2, 0},
 	.module		= THIS_MODULE,
 	.ctr		= verity_ctr,
--- linux-4.4.0.orig/drivers/md/dm.c
+++ linux-4.4.0/drivers/md/dm.c
@@ -974,7 +974,8 @@
 		} else {
 			/* done with normal IO or empty flush */
 			trace_block_bio_complete(md->queue, bio, io_error);
-			bio->bi_error = io_error;
+			if (io_error)
+				bio->bi_error = io_error;
 			bio_endio(bio);
 		}
 	}
@@ -1109,12 +1110,8 @@
 	 * back into ->request_fn() could deadlock attempting to grab the
 	 * queue lock again.
 	 */
-	if (run_queue) {
-		if (md->queue->mq_ops)
-			blk_mq_run_hw_queues(md->queue, true);
-		else
-			blk_run_queue_async(md->queue);
-	}
+	if (!md->queue->mq_ops && run_queue)
+		blk_run_queue_async(md->queue);
 
 	/*
 	 * dm_put() must be at the end of this function. See the comment above
@@ -1191,6 +1188,8 @@
 
 	if (clone)
 		free_rq_clone(clone);
+	else if (!tio->md->queue->mq_ops)
+		free_rq_tio(tio);
 }
 
 /*
@@ -1212,9 +1211,9 @@
 {
 	int rw = rq_data_dir(rq);
 
+	rq_end_stats(md, rq);
 	dm_unprep_request(rq);
 
-	rq_end_stats(md, rq);
 	if (!rq->q->mq_ops)
 		old_requeue_request(rq);
 	else {
@@ -1334,7 +1333,10 @@
 	struct dm_rq_target_io *tio = tio_from_request(rq);
 
 	tio->error = error;
-	blk_complete_request(rq);
+	if (!rq->q->mq_ops)
+		blk_complete_request(rq);
+	else
+		blk_mq_complete_request(rq, error);
 }
 
 /*
@@ -1466,11 +1468,65 @@
 }
 EXPORT_SYMBOL_GPL(dm_accept_partial_bio);
 
+/*
+ * Flush current->bio_list when the target map method blocks.
+ * This fixes deadlocks in snapshot and possibly in other targets.
+ */
+struct dm_offload {
+	struct blk_plug plug;
+	struct blk_plug_cb cb;
+};
+
+static void flush_current_bio_list(struct blk_plug_cb *cb, bool from_schedule)
+{
+	struct dm_offload *o = container_of(cb, struct dm_offload, cb);
+	struct bio_list list;
+	struct bio *bio;
+	int i;
+
+	INIT_LIST_HEAD(&o->cb.list);
+
+	if (unlikely(!current->bio_list))
+		return;
+
+	for (i = 0; i < 2; i++) {
+		list = current->bio_list[i];
+		bio_list_init(&current->bio_list[i]);
+
+		while ((bio = bio_list_pop(&list))) {
+			struct bio_set *bs = bio->bi_pool;
+			if (unlikely(!bs) || bs == fs_bio_set) {
+				bio_list_add(&current->bio_list[i], bio);
+				continue;
+			}
+
+			spin_lock(&bs->rescue_lock);
+			bio_list_add(&bs->rescue_list, bio);
+			queue_work(bs->rescue_workqueue, &bs->rescue_work);
+			spin_unlock(&bs->rescue_lock);
+		}
+	}
+}
+
+static void dm_offload_start(struct dm_offload *o)
+{
+	blk_start_plug(&o->plug);
+	o->cb.callback = flush_current_bio_list;
+	list_add(&o->cb.list, &current->plug->cb_list);
+}
+
+static void dm_offload_end(struct dm_offload *o)
+{
+	list_del(&o->cb.list);
+	blk_finish_plug(&o->plug);
+}
+
 static void __map_bio(struct dm_target_io *tio)
 {
 	int r;
 	sector_t sector;
 	struct mapped_device *md;
+	struct dm_offload o;
 	struct bio *clone = &tio->clone;
 	struct dm_target *ti = tio->ti;
 
@@ -1483,7 +1539,11 @@
 	 */
 	atomic_inc(&tio->io->io_count);
 	sector = clone->bi_iter.bi_sector;
+
+	dm_offload_start(&o);
 	r = ti->type->map(ti, clone);
+	dm_offload_end(&o);
+
 	if (r == DM_MAPIO_REMAPPED) {
 		/* the bio has been remapped so dispatch it */
 
@@ -2132,7 +2192,7 @@
 	goto out;
 
 delay_and_out:
-	blk_delay_queue(q, HZ / 100);
+	blk_delay_queue(q, 10);
 out:
 	dm_put_live_table(md, srcu_idx);
 }
@@ -2151,7 +2211,7 @@
 			 * the query about congestion status of request_queue
 			 */
 			if (dm_request_based(md))
-				r = md->queue->backing_dev_info.wb.state &
+				r = md->queue->backing_dev_info->wb.state &
 				    bdi_bits;
 			else
 				r = dm_table_any_congested(map, bdi_bits);
@@ -2233,7 +2293,6 @@
 	 * - must do so here (in alloc_dev callchain) before queue is used
 	 */
 	md->queue->queuedata = md;
-	md->queue->backing_dev_info.congested_data = md;
 }
 
 static void dm_init_old_md_queue(struct mapped_device *md)
@@ -2244,7 +2303,8 @@
 	/*
 	 * Initialize aspects of queue that aren't relevant for blk-mq
 	 */
-	md->queue->backing_dev_info.congested_fn = dm_any_congested;
+	md->queue->backing_dev_info->congested_data = md;
+	md->queue->backing_dev_info->congested_fn = dm_any_congested;
 	blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
 }
 
@@ -2259,8 +2319,6 @@
 	if (md->bs)
 		bioset_free(md->bs);
 
-	cleanup_srcu_struct(&md->io_barrier);
-
 	if (md->disk) {
 		spin_lock(&_minor_lock);
 		md->disk->private_data = NULL;
@@ -2272,6 +2330,8 @@
 	if (md->queue)
 		blk_cleanup_queue(md->queue);
 
+	cleanup_srcu_struct(&md->io_barrier);
+
 	if (md->bdev) {
 		bdput(md->bdev);
 		md->bdev = NULL;
@@ -2326,6 +2386,12 @@
 		goto bad;
 
 	dm_init_md_queue(md);
+	/*
+	 * default to bio-based required ->make_request_fn until DM
+	 * table is loaded and md->type established. If request-based
+	 * table is loaded: blk-mq will override accordingly.
+	 */
+	blk_queue_make_request(md->queue, dm_make_request);
 
 	md->disk = alloc_disk(1);
 	if (!md->disk)
@@ -2789,7 +2855,6 @@
 		break;
 	case DM_TYPE_BIO_BASED:
 		dm_init_old_md_queue(md);
-		blk_queue_make_request(md->queue, dm_make_request);
 		/*
 		 * DM handles splitting bios as needed.  Free the bio_split bioset
 		 * since it won't be used (saves 1 process per bio-based DM device).
@@ -2868,6 +2933,7 @@
 
 static void __dm_destroy(struct mapped_device *md, bool wait)
 {
+	struct request_queue *q = dm_get_md_queue(md);
 	struct dm_table *map;
 	int srcu_idx;
 
@@ -2878,6 +2944,8 @@
 	set_bit(DMF_FREEING, &md->flags);
 	spin_unlock(&_minor_lock);
 
+	blk_set_queue_dying(q);
+
 	if (dm_request_based(md) && md->kworker_task)
 		flush_kthread_worker(&md->kworker);
 
@@ -3077,7 +3145,8 @@
  * Caller must hold md->suspend_lock
  */
 static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
-			unsigned suspend_flags, int interruptible)
+			unsigned suspend_flags, int interruptible,
+			int dmf_suspended_flag)
 {
 	bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
 	bool noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG;
@@ -3144,6 +3213,8 @@
 	 * to finish.
 	 */
 	r = dm_wait_for_completion(md, interruptible);
+	if (!r)
+		set_bit(dmf_suspended_flag, &md->flags);
 
 	if (noflush)
 		clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
@@ -3205,12 +3276,10 @@
 
 	map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
 
-	r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE);
+	r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE, DMF_SUSPENDED);
 	if (r)
 		goto out_unlock;
 
-	set_bit(DMF_SUSPENDED, &md->flags);
-
 	dm_table_postsuspend_targets(map);
 
 out_unlock:
@@ -3243,10 +3312,11 @@
 
 int dm_resume(struct mapped_device *md)
 {
-	int r = -EINVAL;
+	int r;
 	struct dm_table *map = NULL;
 
 retry:
+	r = -EINVAL;
 	mutex_lock_nested(&md->suspend_lock, SINGLE_DEPTH_NESTING);
 
 	if (!dm_suspended_md(md))
@@ -3270,8 +3340,6 @@
 		goto out;
 
 	clear_bit(DMF_SUSPENDED, &md->flags);
-
-	r = 0;
 out:
 	mutex_unlock(&md->suspend_lock);
 
@@ -3304,15 +3372,17 @@
 	 * would require changing .presuspend to return an error -- avoid this
 	 * until there is a need for more elaborate variants of internal suspend.
 	 */
-	(void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE);
-
-	set_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
+	(void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE,
+			    DMF_SUSPENDED_INTERNALLY);
 
 	dm_table_postsuspend_targets(map);
 }
 
 static void __dm_internal_resume(struct mapped_device *md)
 {
+	int r;
+	struct dm_table *map;
+
 	BUG_ON(!md->internal_suspend_count);
 
 	if (--md->internal_suspend_count)
@@ -3321,12 +3391,23 @@
 	if (dm_suspended_md(md))
 		goto done; /* resume from nested suspend */
 
-	/*
-	 * NOTE: existing callers don't need to call dm_table_resume_targets
-	 * (which may fail -- so best to avoid it for now by passing NULL map)
-	 */
-	(void) __dm_resume(md, NULL);
-
+	map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
+	r = __dm_resume(md, map);
+	if (r) {
+		/*
+		 * If a preresume method of some target failed, we are in a
+		 * tricky situation. We can't return an error to the caller. We
+		 * can't fake success because then the "resume" and
+		 * "postsuspend" methods would not be paired correctly, and it
+		 * would break various targets, for example it would cause list
+		 * corruption in the "origin" target.
+		 *
+		 * So, we fake normal suspend here, to make sure that the
+		 * "resume" and "postsuspend" methods will be paired correctly.
+		 */
+		DMERR("Preresume method failed: %d", r);
+		set_bit(DMF_SUSPENDED, &md->flags);
+	}
 done:
 	clear_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
 	smp_mb__after_atomic();
@@ -3444,11 +3525,15 @@
 
 	md = container_of(kobj, struct mapped_device, kobj_holder.kobj);
 
-	if (test_bit(DMF_FREEING, &md->flags) ||
-	    dm_deleting_md(md))
-		return NULL;
-
+	spin_lock(&_minor_lock);
+	if (test_bit(DMF_FREEING, &md->flags) || dm_deleting_md(md)) {
+		md = NULL;
+		goto out;
+	}
 	dm_get(md);
+out:
+	spin_unlock(&_minor_lock);
+
 	return md;
 }
 
--- linux-4.4.0.orig/drivers/md/dm.h
+++ linux-4.4.0/drivers/md/dm.h
@@ -40,6 +40,9 @@
 #define DM_TYPE_REQUEST_BASED		2
 #define DM_TYPE_MQ_REQUEST_BASED	3
 
+#define DM_MAX_TARGETS			1048576
+#define DM_MAX_TARGET_PARAMS		1024
+
 /*
  * List of devices that a metadevice uses and should open/close.
  */
--- linux-4.4.0.orig/drivers/md/linear.c
+++ linux-4.4.0/drivers/md/linear.c
@@ -52,18 +52,26 @@
 	return conf->disks + lo;
 }
 
+/*
+ * In linear_congested() conf->raid_disks is used as a copy of
+ * mddev->raid_disks to iterate conf->disks[], because conf->raid_disks
+ * and conf->disks[] are created in linear_conf(), they are always
+ * consitent with each other, but mddev->raid_disks does not.
+ */
 static int linear_congested(struct mddev *mddev, int bits)
 {
 	struct linear_conf *conf;
 	int i, ret = 0;
 
-	conf = mddev->private;
+	rcu_read_lock();
+	conf = rcu_dereference(mddev->private);
 
-	for (i = 0; i < mddev->raid_disks && !ret ; i++) {
+	for (i = 0; i < conf->raid_disks && !ret ; i++) {
 		struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
-		ret |= bdi_congested(&q->backing_dev_info, bits);
+		ret |= bdi_congested(q->backing_dev_info, bits);
 	}
 
+	rcu_read_unlock();
 	return ret;
 }
 
@@ -143,6 +151,19 @@
 			conf->disks[i-1].end_sector +
 			conf->disks[i].rdev->sectors;
 
+	/*
+	 * conf->raid_disks is copy of mddev->raid_disks. The reason to
+	 * keep a copy of mddev->raid_disks in struct linear_conf is,
+	 * mddev->raid_disks may not be consistent with pointers number of
+	 * conf->disks[] when it is updated in linear_add() and used to
+	 * iterate old conf->disks[] earray in linear_congested().
+	 * Here conf->raid_disks is always consitent with number of
+	 * pointers in conf->disks[] array, and mddev->private is updated
+	 * with rcu_assign_pointer() in linear_addr(), such race can be
+	 * avoided.
+	 */
+	conf->raid_disks = raid_disks;
+
 	return conf;
 
 out:
@@ -195,15 +216,24 @@
 	if (!newconf)
 		return -ENOMEM;
 
+	/* newconf->raid_disks already keeps a copy of * the increased
+	 * value of mddev->raid_disks, WARN_ONCE() is just used to make
+	 * sure of this. It is possible that oldconf is still referenced
+	 * in linear_congested(), therefore kfree_rcu() is used to free
+	 * oldconf until no one uses it anymore.
+	 */
 	mddev_suspend(mddev);
-	oldconf = mddev->private;
+	oldconf = rcu_dereference_protected(mddev->private,
+			lockdep_is_held(&mddev->reconfig_mutex));
 	mddev->raid_disks++;
-	mddev->private = newconf;
+	WARN_ONCE(mddev->raid_disks != newconf->raid_disks,
+		"copied raid_disks doesn't match mddev->raid_disks");
+	rcu_assign_pointer(mddev->private, newconf);
 	md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
 	set_capacity(mddev->gendisk, mddev->array_sectors);
 	mddev_resume(mddev);
 	revalidate_disk(mddev->gendisk);
-	kfree(oldconf);
+	kfree_rcu(oldconf, rcu);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/md/linear.h
+++ linux-4.4.0/drivers/md/linear.h
@@ -10,6 +10,7 @@
 {
 	struct rcu_head		rcu;
 	sector_t		array_sectors;
+	int			raid_disks; /* a copy of mddev->raid_disks */
 	struct dev_info		disks[0];
 };
 #endif
--- linux-4.4.0.orig/drivers/md/md-cluster.c
+++ linux-4.4.0/drivers/md/md-cluster.c
@@ -239,15 +239,6 @@
 	while (cinfo->recovery_map) {
 		slot = fls64((u64)cinfo->recovery_map) - 1;
 
-		/* Clear suspend_area associated with the bitmap */
-		spin_lock_irq(&cinfo->suspend_lock);
-		list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list)
-			if (slot == s->slot) {
-				list_del(&s->list);
-				kfree(s);
-			}
-		spin_unlock_irq(&cinfo->suspend_lock);
-
 		snprintf(str, 64, "bitmap%04d", slot);
 		bm_lockres = lockres_init(mddev, str, NULL, 1);
 		if (!bm_lockres) {
@@ -266,6 +257,16 @@
 			pr_err("md-cluster: Could not copy data from bitmap %d\n", slot);
 			goto dlm_unlock;
 		}
+
+		/* Clear suspend_area associated with the bitmap */
+		spin_lock_irq(&cinfo->suspend_lock);
+		list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list)
+			if (slot == s->slot) {
+				list_del(&s->list);
+				kfree(s);
+			}
+		spin_unlock_irq(&cinfo->suspend_lock);
+
 		if (hi > 0) {
 			/* TODO:Wait for current resync to get over */
 			set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -821,6 +822,7 @@
 	lockres_free(cinfo->no_new_dev_lockres);
 	lockres_free(cinfo->bitmap_lockres);
 	dlm_release_lockspace(cinfo->lockspace, 2);
+	kfree(cinfo);
 	return 0;
 }
 
@@ -944,8 +946,10 @@
 	cmsg.raid_slot = cpu_to_le32(rdev->desc_nr);
 	lock_comm(cinfo);
 	ret = __sendmsg(cinfo, &cmsg);
-	if (ret)
+	if (ret) {
+		unlock_comm(cinfo);
 		return ret;
+	}
 	cinfo->no_new_dev_lockres->flags |= DLM_LKF_NOQUEUE;
 	ret = dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_EX);
 	cinfo->no_new_dev_lockres->flags &= ~DLM_LKF_NOQUEUE;
--- linux-4.4.0.orig/drivers/md/md.c
+++ linux-4.4.0/drivers/md/md.c
@@ -293,6 +293,8 @@
 	 * go away inside make_request
 	 */
 	sectors = bio_sectors(bio);
+	/* bio could be mergeable after passing to underlayer */
+	bio->bi_rw &= ~REQ_NOMERGE;
 	mddev->pers->make_request(mddev, bio);
 
 	cpu = part_stat_lock();
@@ -1026,8 +1028,9 @@
 	 * (not needed for Linear and RAID0 as metadata doesn't
 	 * record this size)
 	 */
-	if (rdev->sectors >= (2ULL << 32) && sb->level >= 1)
-		rdev->sectors = (2ULL << 32) - 2;
+	if (IS_ENABLED(CONFIG_LBDAF) && (u64)rdev->sectors >= (2ULL << 32) &&
+	    sb->level >= 1)
+		rdev->sectors = (sector_t)(2ULL << 32) - 2;
 
 	if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
 		/* "this cannot possibly happen" ... */
@@ -1088,6 +1091,8 @@
 			mddev->new_layout = mddev->layout;
 			mddev->new_chunk_sectors = mddev->chunk_sectors;
 		}
+		if (mddev->level == 0)
+			mddev->layout = -1;
 
 		if (sb->state & (1<<MD_SB_CLEAN))
 			mddev->recovery_cp = MaxSector;
@@ -1320,8 +1325,9 @@
 	/* Limit to 4TB as metadata cannot record more than that.
 	 * 4TB == 2^32 KB, or 2*2^32 sectors.
 	 */
-	if (num_sectors >= (2ULL << 32) && rdev->mddev->level >= 1)
-		num_sectors = (2ULL << 32) - 2;
+	if (IS_ENABLED(CONFIG_LBDAF) && (u64)num_sectors >= (2ULL << 32) &&
+	    rdev->mddev->level >= 1)
+		num_sectors = (sector_t)(2ULL << 32) - 2;
 	md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
 		       rdev->sb_page);
 	md_super_wait(rdev->mddev);
@@ -1494,6 +1500,10 @@
 	} else if (sb->bblog_offset != 0)
 		rdev->badblocks.shift = 0;
 
+	if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RAID0_LAYOUT) &&
+	    sb->level != 0)
+		return -EINVAL;
+
 	if (!refdev) {
 		ret = 1;
 	} else {
@@ -1605,6 +1615,10 @@
 			mddev->new_chunk_sectors = mddev->chunk_sectors;
 		}
 
+		if (mddev->level == 0 &&
+		    !(le32_to_cpu(sb->feature_map) & MD_FEATURE_RAID0_LAYOUT))
+			mddev->layout = -1;
+
 	} else if (mddev->pers == NULL) {
 		/* Insist of good event counter while assembling, except for
 		 * spares (which don't need an event count) */
@@ -1663,8 +1677,15 @@
 				if (!(le32_to_cpu(sb->feature_map) &
 				      MD_FEATURE_RECOVERY_BITMAP))
 					rdev->saved_raid_disk = -1;
-			} else
-				set_bit(In_sync, &rdev->flags);
+			} else {
+				/*
+				 * If the array is FROZEN, then the device can't
+				 * be in_sync with rest of array.
+				 */
+				if (!test_bit(MD_RECOVERY_FROZEN,
+					      &mddev->recovery))
+					set_bit(In_sync, &rdev->flags);
+			}
 			rdev->raid_disk = role;
 			break;
 		}
@@ -1864,7 +1885,7 @@
 	}
 	sb = page_address(rdev->sb_page);
 	sb->data_size = cpu_to_le64(num_sectors);
-	sb->super_offset = rdev->sb_start;
+	sb->super_offset = cpu_to_le64(rdev->sb_start);
 	sb->sb_csum = calc_sb_1_csum(sb);
 	md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
 		       rdev->sb_page);
@@ -2017,28 +2038,32 @@
 }
 EXPORT_SYMBOL(md_integrity_register);
 
-/* Disable data integrity if non-capable/non-matching disk is being added */
-void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
+/*
+ * Attempt to add an rdev, but only if it is consistent with the current
+ * integrity profile
+ */
+int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
 {
 	struct blk_integrity *bi_rdev;
 	struct blk_integrity *bi_mddev;
+	char name[BDEVNAME_SIZE];
 
 	if (!mddev->gendisk)
-		return;
+		return 0;
 
 	bi_rdev = bdev_get_integrity(rdev->bdev);
 	bi_mddev = blk_get_integrity(mddev->gendisk);
 
 	if (!bi_mddev) /* nothing to do */
-		return;
-	if (rdev->raid_disk < 0) /* skip spares */
-		return;
-	if (bi_rdev && blk_integrity_compare(mddev->gendisk,
-					     rdev->bdev->bd_disk) >= 0)
-		return;
-	WARN_ON_ONCE(!mddev->suspended);
-	printk(KERN_NOTICE "disabling data integrity on %s\n", mdname(mddev));
-	blk_integrity_unregister(mddev->gendisk);
+		return 0;
+
+	if (blk_integrity_compare(mddev->gendisk, rdev->bdev->bd_disk) != 0) {
+		printk(KERN_NOTICE "%s: incompatible integrity profile for %s\n",
+				mdname(mddev), bdevname(rdev->bdev, name));
+		return -ENXIO;
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL(md_integrity_add_rdev);
 
@@ -2267,7 +2292,7 @@
 	/* Check if any mddev parameters have changed */
 	if ((mddev->dev_sectors != le64_to_cpu(sb->size)) ||
 	    (mddev->reshape_position != le64_to_cpu(sb->reshape_position)) ||
-	    (mddev->layout != le64_to_cpu(sb->layout)) ||
+	    (mddev->layout != le32_to_cpu(sb->layout)) ||
 	    (mddev->raid_disks != le32_to_cpu(sb->raid_disks)) ||
 	    (mddev->chunk_sectors != le32_to_cpu(sb->chunksize)))
 		return true;
@@ -2682,7 +2707,10 @@
 			err = 0;
 		}
 	} else if (cmd_match(buf, "re-add")) {
-		if (test_bit(Faulty, &rdev->flags) && (rdev->raid_disk == -1)) {
+		if (!rdev->mddev->pers)
+			err = -EINVAL;
+		else if (test_bit(Faulty, &rdev->flags) && (rdev->raid_disk == -1) &&
+				rdev->saved_raid_disk >= 0) {
 			/* clear_bit is performed _after_ all the devices
 			 * have their local Faulty bit cleared. If any writes
 			 * happen in the meantime in the local node, they
@@ -5278,8 +5306,8 @@
 		return err;
 	}
 	if (mddev->queue) {
-		mddev->queue->backing_dev_info.congested_data = mddev;
-		mddev->queue->backing_dev_info.congested_fn = md_congested;
+		mddev->queue->backing_dev_info->congested_data = mddev;
+		mddev->queue->backing_dev_info->congested_fn = md_congested;
 	}
 	if (pers->sync_request) {
 		if (mddev->kobj.sd &&
@@ -5636,7 +5664,7 @@
 
 		__md_stop_writes(mddev);
 		__md_stop(mddev);
-		mddev->queue->backing_dev_info.congested_fn = NULL;
+		mddev->queue->backing_dev_info->congested_fn = NULL;
 
 		/* tell userspace to handle 'inactive' */
 		sysfs_notify_dirent_safe(mddev->sysfs_state);
@@ -6136,6 +6164,9 @@
 	struct md_rdev *rdev;
 	int ret = -1;
 
+	if (!mddev->pers)
+		return -ENODEV;
+
 	rdev = find_rdev(mddev, dev);
 	if (!rdev)
 		return -ENXIO;
@@ -6381,6 +6412,9 @@
 	mddev->external	     = 0;
 
 	mddev->layout        = info->layout;
+	if (mddev->level == 0)
+		/* Cannot trust RAID0 layout info here */
+		mddev->layout = -1;
 	mddev->chunk_sectors = info->chunk_size >> 9;
 
 	mddev->max_disks     = MD_SB_DISKS;
@@ -6765,7 +6799,7 @@
 		/* need to ensure recovery thread has run */
 		wait_event_interruptible_timeout(mddev->sb_wait,
 						 !test_bit(MD_RECOVERY_NEEDED,
-							   &mddev->flags),
+							   &mddev->recovery),
 						 msecs_to_jiffies(5000));
 	if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
 		/* Need to flush page cache, and ensure no-one else opens
@@ -7017,7 +7051,8 @@
 		 */
 		mddev_put(mddev);
 		/* Wait until bdev->bd_disk is definitely gone */
-		flush_workqueue(md_misc_wq);
+		if (work_pending(&mddev->del_work))
+			flush_workqueue(md_misc_wq);
 		/* Then retry the open from the top */
 		return -ERESTARTSYS;
 	}
@@ -7212,9 +7247,9 @@
 static int status_resync(struct seq_file *seq, struct mddev *mddev)
 {
 	sector_t max_sectors, resync, res;
-	unsigned long dt, db;
-	sector_t rt;
-	int scale;
+	unsigned long dt, db = 0;
+	sector_t rt, curr_mark_cnt, resync_mark_cnt;
+	int scale, recovery_active;
 	unsigned int per_milli;
 
 	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
@@ -7284,22 +7319,30 @@
 	 * db: blocks written from mark until now
 	 * rt: remaining time
 	 *
-	 * rt is a sector_t, so could be 32bit or 64bit.
-	 * So we divide before multiply in case it is 32bit and close
-	 * to the limit.
-	 * We scale the divisor (db) by 32 to avoid losing precision
-	 * near the end of resync when the number of remaining sectors
-	 * is close to 'db'.
-	 * We then divide rt by 32 after multiplying by db to compensate.
-	 * The '+1' avoids division by zero if db is very small.
+	 * rt is a sector_t, which is always 64bit now. We are keeping
+	 * the original algorithm, but it is not really necessary.
+	 *
+	 * Original algorithm:
+	 *   So we divide before multiply in case it is 32bit and close
+	 *   to the limit.
+	 *   We scale the divisor (db) by 32 to avoid losing precision
+	 *   near the end of resync when the number of remaining sectors
+	 *   is close to 'db'.
+	 *   We then divide rt by 32 after multiplying by db to compensate.
+	 *   The '+1' avoids division by zero if db is very small.
 	 */
 	dt = ((jiffies - mddev->resync_mark) / HZ);
 	if (!dt) dt++;
-	db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active))
-		- mddev->resync_mark_cnt;
+
+	curr_mark_cnt = mddev->curr_mark_cnt;
+	recovery_active = atomic_read(&mddev->recovery_active);
+	resync_mark_cnt = mddev->resync_mark_cnt;
+
+	if (curr_mark_cnt >= (recovery_active + resync_mark_cnt))
+		db = curr_mark_cnt - (recovery_active + resync_mark_cnt);
 
 	rt = max_sectors - resync;    /* number of remaining sectors */
-	sector_div(rt, db/32+1);
+	rt = div64_u64(rt, db/32+1);
 	rt *= dt;
 	rt >>= 5;
 
@@ -7566,16 +7609,12 @@
 
 int md_setup_cluster(struct mddev *mddev, int nodes)
 {
-	int err;
-
-	err = request_module("md-cluster");
-	if (err) {
-		pr_err("md-cluster module not found.\n");
-		return -ENOENT;
-	}
-
+	if (!md_cluster_ops)
+		request_module("md-cluster");
 	spin_lock(&pers_lock);
+	/* ensure module won't be unloaded */
 	if (!md_cluster_ops || !try_module_get(md_cluster_mod)) {
+		pr_err("can't find md-cluster module or get it's reference.\n");
 		spin_unlock(&pers_lock);
 		return -ENOENT;
 	}
@@ -8149,6 +8188,7 @@
 			if (mddev->pers->hot_remove_disk(
 				    mddev, rdev) == 0) {
 				sysfs_unlink_rdev(mddev, rdev);
+				rdev->saved_raid_disk = rdev->raid_disk;
 				rdev->raid_disk = -1;
 				removed++;
 			}
@@ -8426,7 +8466,8 @@
 	/* resync has finished, collect result */
 	md_unregister_thread(&mddev->sync_thread);
 	if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
-	    !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
+	    !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
+	    mddev->degraded != mddev->raid_disks) {
 		/* success...*/
 		/* activate any spares */
 		if (mddev->pers->spare_active(mddev)) {
--- linux-4.4.0.orig/drivers/md/md.h
+++ linux-4.4.0/drivers/md/md.h
@@ -657,7 +657,7 @@
 extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors);
 extern int md_check_no_bitmap(struct mddev *mddev);
 extern int md_integrity_register(struct mddev *mddev);
-extern void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev);
+extern int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev);
 extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
 
 extern void mddev_init(struct mddev *mddev);
--- linux-4.4.0.orig/drivers/md/multipath.c
+++ linux-4.4.0/drivers/md/multipath.c
@@ -129,7 +129,9 @@
 	}
 	multipath = conf->multipaths + mp_bh->path;
 
-	mp_bh->bio = *bio;
+	bio_init(&mp_bh->bio);
+	__bio_clone_fast(&mp_bh->bio, bio);
+
 	mp_bh->bio.bi_iter.bi_sector += multipath->rdev->data_offset;
 	mp_bh->bio.bi_bdev = multipath->rdev->bdev;
 	mp_bh->bio.bi_rw |= REQ_FAILFAST_TRANSPORT;
@@ -164,7 +166,7 @@
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct request_queue *q = bdev_get_queue(rdev->bdev);
 
-			ret |= bdi_congested(&q->backing_dev_info, bits);
+			ret |= bdi_congested(q->backing_dev_info, bits);
 			/* Just like multipath_map, we just check the
 			 * first available device
 			 */
@@ -257,6 +259,9 @@
 			disk_stack_limits(mddev->gendisk, rdev->bdev,
 					  rdev->data_offset << 9);
 
+			err = md_integrity_add_rdev(rdev, mddev);
+			if (err)
+				break;
 			spin_lock_irq(&conf->device_lock);
 			mddev->degraded--;
 			rdev->raid_disk = path;
@@ -264,9 +269,6 @@
 			spin_unlock_irq(&conf->device_lock);
 			rcu_assign_pointer(p->rdev, rdev);
 			err = 0;
-			mddev_suspend(mddev);
-			md_integrity_add_rdev(rdev, mddev);
-			mddev_resume(mddev);
 			break;
 		}
 
--- linux-4.4.0.orig/drivers/md/persistent-data/dm-btree-remove.c
+++ linux-4.4.0/drivers/md/persistent-data/dm-btree-remove.c
@@ -203,7 +203,13 @@
 	struct btree_node *right = r->n;
 	uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
 	uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
-	unsigned threshold = 2 * merge_threshold(left) + 1;
+	/*
+	 * Ensure the number of entries in each child will be greater
+	 * than or equal to (max_entries / 3 + 1), so no matter which
+	 * child is used for removal, the number will still be not
+	 * less than (max_entries / 3).
+	 */
+	unsigned int threshold = 2 * (merge_threshold(left) + 1);
 
 	if (nr_left + nr_right < threshold) {
 		/*
--- linux-4.4.0.orig/drivers/md/persistent-data/dm-btree.c
+++ linux-4.4.0/drivers/md/persistent-data/dm-btree.c
@@ -616,39 +616,40 @@
 
 	new_parent = shadow_current(s);
 
+	pn = dm_block_data(new_parent);
+	size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
+		sizeof(__le64) : s->info->value_type.size;
+
+	/* create & init the left block */
 	r = new_block(s->info, &left);
 	if (r < 0)
 		return r;
 
+	ln = dm_block_data(left);
+	nr_left = le32_to_cpu(pn->header.nr_entries) / 2;
+
+	ln->header.flags = pn->header.flags;
+	ln->header.nr_entries = cpu_to_le32(nr_left);
+	ln->header.max_entries = pn->header.max_entries;
+	ln->header.value_size = pn->header.value_size;
+	memcpy(ln->keys, pn->keys, nr_left * sizeof(pn->keys[0]));
+	memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
+
+	/* create & init the right block */
 	r = new_block(s->info, &right);
 	if (r < 0) {
 		unlock_block(s->info, left);
 		return r;
 	}
 
-	pn = dm_block_data(new_parent);
-	ln = dm_block_data(left);
 	rn = dm_block_data(right);
-
-	nr_left = le32_to_cpu(pn->header.nr_entries) / 2;
 	nr_right = le32_to_cpu(pn->header.nr_entries) - nr_left;
 
-	ln->header.flags = pn->header.flags;
-	ln->header.nr_entries = cpu_to_le32(nr_left);
-	ln->header.max_entries = pn->header.max_entries;
-	ln->header.value_size = pn->header.value_size;
-
 	rn->header.flags = pn->header.flags;
 	rn->header.nr_entries = cpu_to_le32(nr_right);
 	rn->header.max_entries = pn->header.max_entries;
 	rn->header.value_size = pn->header.value_size;
-
-	memcpy(ln->keys, pn->keys, nr_left * sizeof(pn->keys[0]));
 	memcpy(rn->keys, pn->keys + nr_left, nr_right * sizeof(pn->keys[0]));
-
-	size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
-		sizeof(__le64) : s->info->value_type.size;
-	memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
 	memcpy(value_ptr(rn, 0), value_ptr(pn, nr_left),
 	       nr_right * size);
 
@@ -671,23 +672,8 @@
 	pn->keys[1] = rn->keys[0];
 	memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64));
 
-	/*
-	 * rejig the spine.  This is ugly, since it knows too
-	 * much about the spine
-	 */
-	if (s->nodes[0] != new_parent) {
-		unlock_block(s->info, s->nodes[0]);
-		s->nodes[0] = new_parent;
-	}
-	if (key < le64_to_cpu(rn->keys[0])) {
-		unlock_block(s->info, right);
-		s->nodes[1] = left;
-	} else {
-		unlock_block(s->info, left);
-		s->nodes[1] = right;
-	}
-	s->count = 2;
-
+	unlock_block(s->info, left);
+	unlock_block(s->info, right);
 	return 0;
 }
 
@@ -887,8 +873,12 @@
 		else
 			*result_key = le64_to_cpu(ro_node(s)->keys[0]);
 
-		if (next_block || flags & INTERNAL_NODE)
-			block = value64(ro_node(s), i);
+		if (next_block || flags & INTERNAL_NODE) {
+			if (find_highest)
+				block = value64(ro_node(s), i);
+			else
+				block = value64(ro_node(s), 0);
+		}
 
 	} while (flags & INTERNAL_NODE);
 
--- linux-4.4.0.orig/drivers/md/persistent-data/dm-space-map-common.c
+++ linux-4.4.0/drivers/md/persistent-data/dm-space-map-common.c
@@ -382,6 +382,33 @@
 	return -ENOSPC;
 }
 
+int sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll,
+	                         dm_block_t begin, dm_block_t end, dm_block_t *b)
+{
+	int r;
+	uint32_t count;
+
+	do {
+		r = sm_ll_find_free_block(new_ll, begin, new_ll->nr_blocks, b);
+		if (r)
+			break;
+
+		/* double check this block wasn't used in the old transaction */
+		if (*b >= old_ll->nr_blocks)
+			count = 0;
+		else {
+			r = sm_ll_lookup(old_ll, *b, &count);
+			if (r)
+				break;
+
+			if (count)
+				begin = *b + 1;
+		}
+	} while (count);
+
+	return r;
+}
+
 static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
 			int (*mutator)(void *context, uint32_t old, uint32_t *new),
 			void *context, enum allocation_event *ev)
--- linux-4.4.0.orig/drivers/md/persistent-data/dm-space-map-common.h
+++ linux-4.4.0/drivers/md/persistent-data/dm-space-map-common.h
@@ -109,6 +109,8 @@
 int sm_ll_lookup(struct ll_disk *ll, dm_block_t b, uint32_t *result);
 int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
 			  dm_block_t end, dm_block_t *result);
+int sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll,
+	                         dm_block_t begin, dm_block_t end, dm_block_t *result);
 int sm_ll_insert(struct ll_disk *ll, dm_block_t b, uint32_t ref_count, enum allocation_event *ev);
 int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev);
 int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev);
--- linux-4.4.0.orig/drivers/md/persistent-data/dm-space-map-disk.c
+++ linux-4.4.0/drivers/md/persistent-data/dm-space-map-disk.c
@@ -142,10 +142,23 @@
 
 static int sm_disk_dec_block(struct dm_space_map *sm, dm_block_t b)
 {
+	int r;
+	uint32_t old_count;
 	enum allocation_event ev;
 	struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
 
-	return sm_ll_dec(&smd->ll, b, &ev);
+	r = sm_ll_dec(&smd->ll, b, &ev);
+	if (!r && (ev == SM_FREE)) {
+		/*
+		 * It's only free if it's also free in the last
+		 * transaction.
+		 */
+		r = sm_ll_lookup(&smd->old_ll, b, &old_count);
+		if (!r && !old_count)
+			smd->nr_allocated_this_transaction--;
+	}
+
+	return r;
 }
 
 static int sm_disk_new_block(struct dm_space_map *sm, dm_block_t *b)
@@ -154,8 +167,10 @@
 	enum allocation_event ev;
 	struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
 
-	/* FIXME: we should loop round a couple of times */
-	r = sm_ll_find_free_block(&smd->old_ll, smd->begin, smd->old_ll.nr_blocks, b);
+	/*
+	 * Any block we allocate has to be free in both the old and current ll.
+	 */
+	r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, smd->begin, smd->ll.nr_blocks, b);
 	if (r)
 		return r;
 
--- linux-4.4.0.orig/drivers/md/persistent-data/dm-space-map-metadata.c
+++ linux-4.4.0/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -152,12 +152,9 @@
 
 static int brb_pop(struct bop_ring_buffer *brb)
 {
-	struct block_op *bop;
-
 	if (brb_empty(brb))
 		return -ENODATA;
 
-	bop = brb->bops + brb->begin;
 	brb->begin = brb_next(brb, brb->begin);
 
 	return 0;
@@ -251,7 +248,7 @@
 	}
 
 	if (smm->recursion_count == 1)
-		apply_bops(smm);
+		r = apply_bops(smm);
 
 	smm->recursion_count--;
 
@@ -450,7 +447,10 @@
 	enum allocation_event ev;
 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
 
-	r = sm_ll_find_free_block(&smm->old_ll, smm->begin, smm->old_ll.nr_blocks, b);
+	/*
+	 * Any block we allocate has to be free in both the old and current ll.
+	 */
+	r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, smm->begin, smm->ll.nr_blocks, b);
 	if (r)
 		return r;
 
@@ -778,17 +778,15 @@
 	memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm));
 
 	r = sm_ll_new_metadata(&smm->ll, tm);
+	if (!r) {
+		if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS)
+			nr_blocks = DM_SM_METADATA_MAX_BLOCKS;
+		r = sm_ll_extend(&smm->ll, nr_blocks);
+	}
+	memcpy(&smm->sm, &ops, sizeof(smm->sm));
 	if (r)
 		return r;
 
-	if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS)
-		nr_blocks = DM_SM_METADATA_MAX_BLOCKS;
-	r = sm_ll_extend(&smm->ll, nr_blocks);
-	if (r)
-		return r;
-
-	memcpy(&smm->sm, &ops, sizeof(smm->sm));
-
 	/*
 	 * Now we need to update the newly created data structures with the
 	 * allocated blocks that they were built from.
--- linux-4.4.0.orig/drivers/md/raid0.c
+++ linux-4.4.0/drivers/md/raid0.c
@@ -25,6 +25,9 @@
 #include "raid0.h"
 #include "raid5.h"
 
+static int default_layout = 0;
+module_param(default_layout, int, 0644);
+
 static int raid0_congested(struct mddev *mddev, int bits)
 {
 	struct r0conf *conf = mddev->private;
@@ -35,7 +38,7 @@
 	for (i = 0; i < raid_disks && !ret ; i++) {
 		struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
 
-		ret |= bdi_congested(&q->backing_dev_info, bits);
+		ret |= bdi_congested(q->backing_dev_info, bits);
 	}
 	return ret;
 }
@@ -83,7 +86,7 @@
 	char b[BDEVNAME_SIZE];
 	char b2[BDEVNAME_SIZE];
 	struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
-	unsigned short blksize = 512;
+	unsigned blksize = 512;
 
 	if (!conf)
 		return -ENOMEM;
@@ -137,6 +140,23 @@
 	}
 	pr_debug("md/raid0:%s: FINAL %d zones\n",
 		 mdname(mddev), conf->nr_strip_zones);
+
+	if (conf->nr_strip_zones == 1) {
+		conf->layout = RAID0_ORIG_LAYOUT;
+	} else if (mddev->layout == RAID0_ORIG_LAYOUT ||
+		   mddev->layout == RAID0_ALT_MULTIZONE_LAYOUT) {
+			conf->layout = mddev->layout;
+	} else if (default_layout == RAID0_ORIG_LAYOUT ||
+		   default_layout == RAID0_ALT_MULTIZONE_LAYOUT) {
+		conf->layout = default_layout;
+	} else {
+		conf->layout = RAID0_ALT_MULTIZONE_LAYOUT;
+		pr_warn("md/raid0:%s: !!! DEFAULTING TO ALTERNATE LAYOUT !!!\n",
+		       mdname(mddev));
+		pr_warn("md/raid0: Please set raid0.default_layout to 1 or 2\n");
+		pr_warn("md/raid0: Read the following page for more information:\n");
+		pr_warn("md/raid0: https://wiki.ubuntu.com/Kernel/Raid0LayoutMigration\n");
+	}
 	/*
 	 * now since we have the hard sector sizes, we can make sure
 	 * chunk size is a multiple of that sector size
@@ -415,8 +435,8 @@
 		 */
 		int stripe = mddev->raid_disks *
 			(mddev->chunk_sectors << 9) / PAGE_SIZE;
-		if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+		if (mddev->queue->backing_dev_info->ra_pages < 2* stripe)
+			mddev->queue->backing_dev_info->ra_pages = 2* stripe;
 	}
 
 	dump_zones(mddev);
@@ -454,6 +474,7 @@
 
 static void raid0_make_request(struct mddev *mddev, struct bio *bio)
 {
+	struct r0conf *conf = mddev->private;
 	struct strip_zone *zone;
 	struct md_rdev *tmp_dev;
 	struct bio *split;
@@ -465,6 +486,7 @@
 
 	do {
 		sector_t sector = bio->bi_iter.bi_sector;
+		sector_t orig_sector;
 		unsigned chunk_sects = mddev->chunk_sectors;
 
 		unsigned sectors = chunk_sects -
@@ -482,8 +504,20 @@
 			split = bio;
 		}
 
+		orig_sector = sector;
 		zone = find_zone(mddev->private, &sector);
-		tmp_dev = map_sector(mddev, zone, sector, &sector);
+		switch (conf->layout) {
+		case RAID0_ORIG_LAYOUT:
+			tmp_dev = map_sector(mddev, zone, orig_sector, &sector);
+			break;
+		case RAID0_ALT_MULTIZONE_LAYOUT:
+			tmp_dev = map_sector(mddev, zone, sector, &sector);
+			break;
+		default:
+			WARN(1, "md/raid0:%s: Invalid layout\n", mdname(mddev));
+			bio_io_error(bio);
+			return true;
+		}
 		split->bi_bdev = tmp_dev->bdev;
 		split->bi_iter.bi_sector = sector + zone->dev_start +
 			tmp_dev->data_offset;
--- linux-4.4.0.orig/drivers/md/raid0.h
+++ linux-4.4.0/drivers/md/raid0.h
@@ -7,11 +7,25 @@
 	int	 nb_dev;	/* # of devices attached to the zone */
 };
 
+/* Linux 3.14 (20d0189b101) made an unintended change to
+ * the RAID0 layout for multi-zone arrays (where devices aren't all
+ * the same size.
+ * RAID0_ORIG_LAYOUT restores the original layout
+ * RAID0_ALT_MULTIZONE_LAYOUT uses the altered layout
+ * The layouts are identical when there is only one zone (all
+ * devices the same size).
+ */
+enum r0layout {
+	RAID0_ORIG_LAYOUT = 1,
+	RAID0_ALT_MULTIZONE_LAYOUT = 2,
+};
+
 struct r0conf {
 	struct strip_zone	*strip_zone;
 	struct md_rdev		**devlist; /* lists of rdevs, pointed to
 					    * by strip_zone->dev */
 	int			nr_strip_zones;
+	enum r0layout		layout;
 };
 
 #endif
--- linux-4.4.0.orig/drivers/md/raid1.c
+++ linux-4.4.0/drivers/md/raid1.c
@@ -570,7 +570,7 @@
 			if (best_dist_disk < 0) {
 				if (is_badblock(rdev, this_sector, sectors,
 						&first_bad, &bad_sectors)) {
-					if (first_bad < this_sector)
+					if (first_bad <= this_sector)
 						/* Cannot use this */
 						continue;
 					best_good_sectors = first_bad - this_sector;
@@ -730,9 +730,9 @@
 			 * non-congested targets, it can be removed
 			 */
 			if ((bits & (1 << WB_async_congested)) || 1)
-				ret |= bdi_congested(&q->backing_dev_info, bits);
+				ret |= bdi_congested(q->backing_dev_info, bits);
 			else
-				ret &= bdi_congested(&q->backing_dev_info, bits);
+				ret &= bdi_congested(q->backing_dev_info, bits);
 		}
 	}
 	rcu_read_unlock();
@@ -877,7 +877,8 @@
 				     ((conf->start_next_window <
 				       conf->next_resync + RESYNC_SECTORS) &&
 				      current->bio_list &&
-				      !bio_list_empty(current->bio_list))),
+				     (!bio_list_empty(&current->bio_list[0]) ||
+				      !bio_list_empty(&current->bio_list[1])))),
 				    conf->resync_lock);
 		conf->nr_waiting--;
 	}
@@ -1087,7 +1088,7 @@
 		 */
 		DEFINE_WAIT(w);
 		for (;;) {
-			flush_signals(current);
+			sigset_t full, old;
 			prepare_to_wait(&conf->wait_barrier,
 					&w, TASK_INTERRUPTIBLE);
 			if (bio_end_sector(bio) <= mddev->suspend_lo ||
@@ -1096,7 +1097,10 @@
 			     !md_cluster_ops->area_resyncing(mddev, WRITE,
 				     bio->bi_iter.bi_sector, bio_end_sector(bio))))
 				break;
+			sigfillset(&full);
+			sigprocmask(SIG_BLOCK, &full, &old);
 			schedule();
+			sigprocmask(SIG_SETMASK, &old, NULL);
 		}
 		finish_wait(&conf->wait_barrier, &w);
 	}
@@ -1589,6 +1593,9 @@
 	if (mddev->recovery_disabled == conf->recovery_disabled)
 		return -EBUSY;
 
+	if (md_integrity_add_rdev(rdev, mddev))
+		return -ENXIO;
+
 	if (rdev->raid_disk >= 0)
 		first = last = rdev->raid_disk;
 
@@ -1598,6 +1605,7 @@
 	 */
 	if (rdev->saved_raid_disk >= 0 &&
 	    rdev->saved_raid_disk >= first &&
+	    rdev->saved_raid_disk < conf->raid_disks &&
 	    conf->mirrors[rdev->saved_raid_disk].rdev == NULL)
 		first = last = rdev->saved_raid_disk;
 
@@ -1632,9 +1640,6 @@
 			break;
 		}
 	}
-	mddev_suspend(mddev);
-	md_integrity_add_rdev(rdev, mddev);
-	mddev_resume(mddev);
 	if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev)))
 		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
 	print_conf(conf);
@@ -1682,6 +1687,17 @@
 			struct md_rdev *repl =
 				conf->mirrors[conf->raid_disks + number].rdev;
 			freeze_array(conf, 0);
+			if (atomic_read(&repl->nr_pending)) {
+				/* It means that some queued IO of retry_list
+				 * hold repl. Thus, we cannot set replacement
+				 * as NULL, avoiding rdev NULL pointer
+				 * dereference in sync_request_write and
+				 * handle_write_finished.
+				 */
+				err = -EBUSY;
+				unfreeze_array(conf);
+				goto abort;
+			}
 			clear_bit(Replacement, &repl->flags);
 			p->rdev = repl;
 			conf->mirrors[conf->raid_disks + number].rdev = NULL;
@@ -2274,6 +2290,7 @@
 	if (fail) {
 		spin_lock_irq(&conf->device_lock);
 		list_add(&r1_bio->retry_list, &conf->bio_end_io_list);
+		conf->nr_queued++;
 		spin_unlock_irq(&conf->device_lock);
 		md_wakeup_thread(conf->mddev->thread);
 	} else {
@@ -2391,8 +2408,10 @@
 		LIST_HEAD(tmp);
 		spin_lock_irqsave(&conf->device_lock, flags);
 		if (!test_bit(MD_CHANGE_PENDING, &mddev->flags)) {
-			list_add(&tmp, &conf->bio_end_io_list);
-			list_del_init(&conf->bio_end_io_list);
+			while (!list_empty(&conf->bio_end_io_list)) {
+				list_move(conf->bio_end_io_list.prev, &tmp);
+				conf->nr_queued--;
+			}
 		}
 		spin_unlock_irqrestore(&conf->device_lock, flags);
 		while (!list_empty(&tmp)) {
@@ -2611,7 +2630,7 @@
 				write_targets++;
 			}
 		}
-		if (bio->bi_end_io) {
+		if (rdev && bio->bi_end_io) {
 			atomic_inc(&rdev->nr_pending);
 			bio->bi_iter.bi_sector = sector_nr + rdev->data_offset;
 			bio->bi_bdev = rdev->bdev;
@@ -2939,6 +2958,13 @@
 		    !test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
 		    test_bit(Faulty, &conf->mirrors[i].rdev->flags))
 			mddev->degraded++;
+	/*
+	 * RAID1 needs at least one disk in active
+	 */
+	if (conf->raid_disks - mddev->degraded < 1) {
+		ret = -EINVAL;
+		goto abort;
+	}
 
 	if (conf->raid_disks - mddev->degraded == 1)
 		mddev->recovery_cp = MaxSector;
@@ -2973,8 +2999,12 @@
 	ret =  md_integrity_register(mddev);
 	if (ret) {
 		md_unregister_thread(&mddev->thread);
-		raid1_free(mddev, conf);
+		goto abort;
 	}
+	return 0;
+
+abort:
+	raid1_free(mddev, conf);
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/md/raid10.c
+++ linux-4.4.0/drivers/md/raid10.c
@@ -838,7 +838,7 @@
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct request_queue *q = bdev_get_queue(rdev->bdev);
 
-			ret |= bdi_congested(&q->backing_dev_info, bits);
+			ret |= bdi_congested(q->backing_dev_info, bits);
 		}
 	}
 	rcu_read_unlock();
@@ -946,7 +946,8 @@
 				    !conf->barrier ||
 				    (conf->nr_pending &&
 				     current->bio_list &&
-				     !bio_list_empty(current->bio_list)),
+				     (!bio_list_empty(&current->bio_list[0]) ||
+				      !bio_list_empty(&current->bio_list[1]))),
 				    conf->resync_lock);
 		conf->nr_waiting--;
 	}
@@ -1072,6 +1073,8 @@
 	int max_sectors;
 	int sectors;
 
+	md_write_start(mddev, bio);
+
 	/*
 	 * Register the new request and wait if the reconstruction
 	 * thread has put up a bar for new requests.
@@ -1411,11 +1414,24 @@
 			mbio->bi_private = r10_bio;
 
 			atomic_inc(&r10_bio->remaining);
+
+			cb = blk_check_plugged(raid10_unplug, mddev,
+					       sizeof(*plug));
+			if (cb)
+				plug = container_of(cb, struct raid10_plug_cb,
+						    cb);
+			else
+				plug = NULL;
 			spin_lock_irqsave(&conf->device_lock, flags);
-			bio_list_add(&conf->pending_bio_list, mbio);
-			conf->pending_count++;
+			if (plug) {
+				bio_list_add(&plug->pending, mbio);
+				plug->pending_cnt++;
+			} else {
+				bio_list_add(&conf->pending_bio_list, mbio);
+				conf->pending_count++;
+			}
 			spin_unlock_irqrestore(&conf->device_lock, flags);
-			if (!mddev_check_plugged(mddev))
+			if (!plug)
 				md_wakeup_thread(mddev->thread);
 		}
 	}
@@ -1455,8 +1471,6 @@
 		return;
 	}
 
-	md_write_start(mddev, bio);
-
 	do {
 
 		/*
@@ -1477,7 +1491,25 @@
 			split = bio;
 		}
 
+		/*
+		 * If a bio is splitted, the first part of bio will pass
+		 * barrier but the bio is queued in current->bio_list (see
+		 * generic_make_request). If there is a raise_barrier() called
+		 * here, the second part of bio can't pass barrier. But since
+		 * the first part bio isn't dispatched to underlaying disks
+		 * yet, the barrier is never released, hence raise_barrier will
+		 * alays wait. We have a deadlock.
+		 * Note, this only happens in read path. For write path, the
+		 * first part of bio is dispatched in a schedule() call
+		 * (because of blk plug) or offloaded to raid10d.
+		 * Quitting from the function immediately can change the bio
+		 * order queued in bio_list and avoid the deadlock.
+		 */
 		__make_request(mddev, split);
+		if (split != bio && bio_data_dir(bio) == READ) {
+			generic_make_request(bio);
+			break;
+		}
 	} while (split != bio);
 
 	/* In case raid10d snuck in to freeze_array */
@@ -1698,10 +1730,14 @@
 	if (rdev->saved_raid_disk < 0 && !_enough(conf, 1, -1))
 		return -EINVAL;
 
+	if (md_integrity_add_rdev(rdev, mddev))
+		return -ENXIO;
+
 	if (rdev->raid_disk >= 0)
 		first = last = rdev->raid_disk;
 
 	if (rdev->saved_raid_disk >= first &&
+	    rdev->saved_raid_disk < conf->geo.raid_disks &&
 	    conf->mirrors[rdev->saved_raid_disk].rdev == NULL)
 		mirror = rdev->saved_raid_disk;
 	else
@@ -1739,9 +1775,6 @@
 		rcu_assign_pointer(p->rdev, rdev);
 		break;
 	}
-	mddev_suspend(mddev);
-	md_integrity_add_rdev(rdev, mddev);
-	mddev_resume(mddev);
 	if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev)))
 		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
 
@@ -2598,7 +2631,8 @@
 		for (m = 0; m < conf->copies; m++) {
 			int dev = r10_bio->devs[m].devnum;
 			rdev = conf->mirrors[dev].rdev;
-			if (r10_bio->devs[m].bio == NULL)
+			if (r10_bio->devs[m].bio == NULL ||
+				r10_bio->devs[m].bio->bi_end_io == NULL)
 				continue;
 			if (!r10_bio->devs[m].bio->bi_error) {
 				rdev_clear_badblocks(
@@ -2613,7 +2647,8 @@
 					md_error(conf->mddev, rdev);
 			}
 			rdev = conf->mirrors[dev].replacement;
-			if (r10_bio->devs[m].repl_bio == NULL)
+			if (r10_bio->devs[m].repl_bio == NULL ||
+				r10_bio->devs[m].repl_bio->bi_end_io == NULL)
 				continue;
 
 			if (!r10_bio->devs[m].repl_bio->bi_error) {
@@ -2664,7 +2699,13 @@
 		if (fail) {
 			spin_lock_irq(&conf->device_lock);
 			list_add(&r10_bio->retry_list, &conf->bio_end_io_list);
+			conf->nr_queued++;
 			spin_unlock_irq(&conf->device_lock);
+			/*
+			 * In case freeze_array() is waiting for condition
+			 * nr_pending == nr_queued + extra to be true.
+			 */
+			wake_up(&conf->wait_barrier);
 			md_wakeup_thread(conf->mddev->thread);
 		} else {
 			if (test_bit(R10BIO_WriteError,
@@ -2691,8 +2732,10 @@
 		LIST_HEAD(tmp);
 		spin_lock_irqsave(&conf->device_lock, flags);
 		if (!test_bit(MD_CHANGE_PENDING, &mddev->flags)) {
-			list_add(&tmp, &conf->bio_end_io_list);
-			list_del_init(&conf->bio_end_io_list);
+			while (!list_empty(&conf->bio_end_io_list)) {
+				list_move(conf->bio_end_io_list.prev, &tmp);
+				conf->nr_queued--;
+			}
 		}
 		spin_unlock_irqrestore(&conf->device_lock, flags);
 		while (!list_empty(&tmp)) {
@@ -3598,6 +3641,7 @@
 
 		if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
 			discard_supported = true;
+		first = 0;
 	}
 
 	if (mddev->queue) {
@@ -3648,6 +3692,13 @@
 			    disk->rdev->saved_raid_disk < 0)
 				conf->fullsync = 1;
 		}
+
+		if (disk->replacement &&
+		    !test_bit(In_sync, &disk->replacement->flags) &&
+		    disk->replacement->saved_raid_disk < 0) {
+			conf->fullsync = 1;
+		}
+
 		disk->recovery_disabled = mddev->recovery_disabled - 1;
 	}
 
@@ -3676,8 +3727,8 @@
 		 * maybe...
 		 */
 		stripe /= conf->geo.near_copies;
-		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+		if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+			mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 	}
 
 	if (md_integrity_register(mddev))
@@ -3704,6 +3755,8 @@
 		set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
 		mddev->sync_thread = md_register_thread(md_do_sync, mddev,
 							"reshape");
+		if (!mddev->sync_thread)
+			goto out_free_conf;
 	}
 
 	return 0;
@@ -4004,6 +4057,7 @@
 				diff = 0;
 			if (first || diff < min_offset_diff)
 				min_offset_diff = diff;
+			first = 0;
 		}
 	}
 
@@ -4285,11 +4339,12 @@
 		allow_barrier(conf);
 	}
 
+	raise_barrier(conf, 0);
 read_more:
 	/* Now schedule reads for blocks from sector_nr to last */
 	r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
 	r10_bio->state = 0;
-	raise_barrier(conf, sectors_done != 0);
+	raise_barrier(conf, 1);
 	atomic_set(&r10_bio->remaining, 0);
 	r10_bio->mddev = mddev;
 	r10_bio->sector = sector_nr;
@@ -4389,11 +4444,12 @@
 	atomic_inc(&r10_bio->remaining);
 	read_bio->bi_next = NULL;
 	generic_make_request(read_bio);
-	sector_nr += nr_sectors;
 	sectors_done += nr_sectors;
 	if (sector_nr <= last)
 		goto read_more;
 
+	lower_barrier(conf);
+
 	/* Now that we have done the whole section we can
 	 * update reshape_progress
 	 */
@@ -4471,8 +4527,8 @@
 		int stripe = conf->geo.raid_disks *
 			((conf->mddev->chunk_sectors << 9) / PAGE_SIZE);
 		stripe /= conf->geo.near_copies;
-		if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-			conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+		if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+			conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 	}
 	conf->fullsync = 0;
 }
--- linux-4.4.0.orig/drivers/md/raid5.c
+++ linux-4.4.0/drivers/md/raid5.c
@@ -110,8 +110,7 @@
 static inline void lock_all_device_hash_locks_irq(struct r5conf *conf)
 {
 	int i;
-	local_irq_disable();
-	spin_lock(conf->hash_locks);
+	spin_lock_irq(conf->hash_locks);
 	for (i = 1; i < NR_STRIPE_HASH_LOCKS; i++)
 		spin_lock_nest_lock(conf->hash_locks + i, conf->hash_locks);
 	spin_lock(&conf->device_lock);
@@ -121,9 +120,9 @@
 {
 	int i;
 	spin_unlock(&conf->device_lock);
-	for (i = NR_STRIPE_HASH_LOCKS; i; i--)
-		spin_unlock(conf->hash_locks + i - 1);
-	local_irq_enable();
+	for (i = NR_STRIPE_HASH_LOCKS - 1; i; i--)
+		spin_unlock(conf->hash_locks + i);
+	spin_unlock_irq(conf->hash_locks);
 }
 
 /* bio's attached to a stripe+device for I/O are linked together in bi_sector
@@ -340,8 +339,7 @@
 					 int hash)
 {
 	int size;
-	unsigned long do_wakeup = 0;
-	int i = 0;
+	bool do_wakeup = false;
 	unsigned long flags;
 
 	if (hash == NR_STRIPE_HASH_LOCKS) {
@@ -362,19 +360,15 @@
 			    !list_empty(list))
 				atomic_dec(&conf->empty_inactive_list_nr);
 			list_splice_tail_init(list, conf->inactive_list + hash);
-			do_wakeup |= 1 << hash;
+			do_wakeup = true;
 			spin_unlock_irqrestore(conf->hash_locks + hash, flags);
 		}
 		size--;
 		hash--;
 	}
 
-	for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++) {
-		if (do_wakeup & (1 << i))
-			wake_up(&conf->wait_for_stripe[i]);
-	}
-
 	if (do_wakeup) {
+		wake_up(&conf->wait_for_stripe);
 		if (atomic_read(&conf->active_stripes) == 0)
 			wake_up(&conf->wait_for_quiescent);
 		if (conf->retry_read_aligned)
@@ -687,15 +681,14 @@
 			if (!sh) {
 				set_bit(R5_INACTIVE_BLOCKED,
 					&conf->cache_state);
-				wait_event_exclusive_cmd(
-					conf->wait_for_stripe[hash],
+				wait_event_lock_irq(
+					conf->wait_for_stripe,
 					!list_empty(conf->inactive_list + hash) &&
 					(atomic_read(&conf->active_stripes)
 					 < (conf->max_nr_stripes * 3 / 4)
 					 || !test_bit(R5_INACTIVE_BLOCKED,
 						      &conf->cache_state)),
-					spin_unlock_irq(conf->hash_locks + hash),
-					spin_lock_irq(conf->hash_locks + hash));
+					*(conf->hash_locks + hash));
 				clear_bit(R5_INACTIVE_BLOCKED,
 					  &conf->cache_state);
 			} else {
@@ -720,9 +713,6 @@
 		}
 	} while (sh == NULL);
 
-	if (!list_empty(conf->inactive_list + hash))
-		wake_up(&conf->wait_for_stripe[hash]);
-
 	spin_unlock_irq(conf->hash_locks + hash);
 	return sh;
 }
@@ -735,12 +725,11 @@
 
 static void lock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2)
 {
-	local_irq_disable();
 	if (sh1 > sh2) {
-		spin_lock(&sh2->stripe_lock);
+		spin_lock_irq(&sh2->stripe_lock);
 		spin_lock_nested(&sh1->stripe_lock, 1);
 	} else {
-		spin_lock(&sh1->stripe_lock);
+		spin_lock_irq(&sh1->stripe_lock);
 		spin_lock_nested(&sh2->stripe_lock, 1);
 	}
 }
@@ -748,8 +737,7 @@
 static void unlock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2)
 {
 	spin_unlock(&sh1->stripe_lock);
-	spin_unlock(&sh2->stripe_lock);
-	local_irq_enable();
+	spin_unlock_irq(&sh2->stripe_lock);
 }
 
 /* Only freshly new full stripe normal write stripe can be added to a batch list */
@@ -827,6 +815,14 @@
 			spin_unlock(&head->batch_head->batch_lock);
 			goto unlock_out;
 		}
+		/*
+		 * We must assign batch_head of this stripe within the
+		 * batch_lock, otherwise clear_batch_ready of batch head
+		 * stripe could clear BATCH_READY bit of this stripe and
+		 * this stripe->batch_head doesn't get assigned, which
+		 * could confuse clear_batch_ready for this stripe
+		 */
+		sh->batch_head = head->batch_head;
 
 		/*
 		 * at this point, head's BATCH_READY could be cleared, but we
@@ -834,8 +830,6 @@
 		 */
 		list_add(&sh->batch_list, &head->batch_list);
 		spin_unlock(&head->batch_head->batch_lock);
-
-		sh->batch_head = head->batch_head;
 	} else {
 		head->batch_head = head;
 		sh->batch_head = head->batch_head;
@@ -1684,8 +1678,11 @@
 		struct r5dev *dev = &sh->dev[i];
 
 		if (dev->written || i == pd_idx || i == qd_idx) {
-			if (!discard && !test_bit(R5_SkipCopy, &dev->flags))
+			if (!discard && !test_bit(R5_SkipCopy, &dev->flags)) {
 				set_bit(R5_UPTODATE, &dev->flags);
+				if (test_bit(STRIPE_EXPAND_READY, &sh->state))
+					set_bit(R5_Expanded, &dev->flags);
+			}
 			if (fua)
 				set_bit(R5_WantFUA, &dev->flags);
 			if (sync)
@@ -2024,22 +2021,23 @@
 	atomic_inc(&conf->active_stripes);
 
 	raid5_release_stripe(sh);
-	conf->max_nr_stripes++;
+	WRITE_ONCE(conf->max_nr_stripes, conf->max_nr_stripes + 1);
 	return 1;
 }
 
 static int grow_stripes(struct r5conf *conf, int num)
 {
 	struct kmem_cache *sc;
+	size_t namelen = sizeof(conf->cache_name[0]);
 	int devs = max(conf->raid_disks, conf->previous_raid_disks);
 
 	if (conf->mddev->gendisk)
-		sprintf(conf->cache_name[0],
+		snprintf(conf->cache_name[0], namelen,
 			"raid%d-%s", conf->level, mdname(conf->mddev));
 	else
-		sprintf(conf->cache_name[0],
+		snprintf(conf->cache_name[0], namelen,
 			"raid%d-%p", conf->level, conf->mddev);
-	sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]);
+	snprintf(conf->cache_name[1], namelen, "%.27s-alt", conf->cache_name[0]);
 
 	conf->active_name = 0;
 	sc = kmem_cache_create(conf->cache_name[conf->active_name],
@@ -2091,6 +2089,14 @@
 	unsigned long cpu;
 	int err = 0;
 
+	/*
+	 * Never shrink. And mddev_suspend() could deadlock if this is called
+	 * from raid5d. In that case, scribble_disks and scribble_sectors
+	 * should equal to new_disks and new_sectors
+	 */
+	if (conf->scribble_disks >= new_disks &&
+	    conf->scribble_sectors >= new_sectors)
+		return 0;
 	mddev_suspend(conf->mddev);
 	get_online_cpus();
 	for_each_present_cpu(cpu) {
@@ -2112,6 +2118,10 @@
 	}
 	put_online_cpus();
 	mddev_resume(conf->mddev);
+	if (!err) {
+		conf->scribble_disks = new_disks;
+		conf->scribble_sectors = new_sectors;
+	}
 	return err;
 }
 
@@ -2192,7 +2202,7 @@
 	cnt = 0;
 	list_for_each_entry(nsh, &newstripes, lru) {
 		lock_device_hash_lock(conf, hash);
-		wait_event_exclusive_cmd(conf->wait_for_stripe[hash],
+		wait_event_cmd(conf->wait_for_stripe,
 				    !list_empty(conf->inactive_list + hash),
 				    unlock_device_hash_lock(conf, hash),
 				    lock_device_hash_lock(conf, hash));
@@ -2228,7 +2238,9 @@
 	} else
 		err = -ENOMEM;
 
-	mutex_unlock(&conf->cache_size_mutex);
+	conf->slab_cache = sc;
+	conf->active_name = 1-conf->active_name;
+
 	/* Step 4, return new stripes to service */
 	while(!list_empty(&newstripes)) {
 		nsh = list_entry(newstripes.next, struct stripe_head, lru);
@@ -2246,10 +2258,10 @@
 	}
 	/* critical section pass, GFP_NOIO no longer needed */
 
-	conf->slab_cache = sc;
-	conf->active_name = 1-conf->active_name;
 	if (!err)
 		conf->pool_size = newsize;
+	mutex_unlock(&conf->cache_size_mutex);
+
 	return err;
 }
 
@@ -2267,7 +2279,7 @@
 	shrink_buffers(sh);
 	kmem_cache_free(conf->slab_cache, sh);
 	atomic_dec(&conf->active_stripes);
-	conf->max_nr_stripes--;
+	WRITE_ONCE(conf->max_nr_stripes, conf->max_nr_stripes - 1);
 	return 1;
 }
 
@@ -2382,7 +2394,9 @@
 		    && !test_bit(R5_ReadNoMerge, &sh->dev[i].flags))
 			retry = 1;
 		if (retry)
-			if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) {
+			if (sh->qd_idx >= 0 && sh->pd_idx == i)
+				set_bit(R5_ReadError, &sh->dev[i].flags);
+			else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) {
 				set_bit(R5_ReadError, &sh->dev[i].flags);
 				clear_bit(R5_ReadNoMerge, &sh->dev[i].flags);
 			} else
@@ -3331,6 +3345,7 @@
 	 * is missing/faulty, then we need to read everything we can.
 	 */
 	if (sh->raid_conf->level != 6 &&
+	    sh->raid_conf->rmw_level != PARITY_DISABLE_RMW &&
 	    sh->sector < sh->raid_conf->mddev->recovery_cp)
 		/* reconstruct-write isn't being forced */
 		return 0;
@@ -3358,9 +3373,20 @@
 		BUG_ON(test_bit(R5_Wantcompute, &dev->flags));
 		BUG_ON(test_bit(R5_Wantread, &dev->flags));
 		BUG_ON(sh->batch_head);
+
+		/*
+		 * In the raid6 case if the only non-uptodate disk is P
+		 * then we already trusted P to compute the other failed
+		 * drives. It is safe to compute rather than re-read P.
+		 * In other cases we only compute blocks from failed
+		 * devices, otherwise check/repair might fail to detect
+		 * a real inconsistency.
+		 */
+
 		if ((s->uptodate == disks - 1) &&
+		    ((sh->qd_idx >= 0 && sh->pd_idx == disk_idx) ||
 		    (s->failed && (disk_idx == s->failed_num[0] ||
-				   disk_idx == s->failed_num[1]))) {
+				   disk_idx == s->failed_num[1])))) {
 			/* have disk failed, and we're requested to fetch it;
 			 * do compute it
 			 */
@@ -3838,7 +3864,7 @@
 		/* now write out any block on a failed drive,
 		 * or P or Q if they were recomputed
 		 */
-		BUG_ON(s->uptodate < disks - 1); /* We don't need Q to recover */
+		dev = NULL;
 		if (s->failed == 2) {
 			dev = &sh->dev[s->failed_num[1]];
 			s->locked++;
@@ -3863,6 +3889,14 @@
 			set_bit(R5_LOCKED, &dev->flags);
 			set_bit(R5_Wantwrite, &dev->flags);
 		}
+		if (WARN_ONCE(dev && !test_bit(R5_UPTODATE, &dev->flags),
+			      "%s: disk%td not up to date\n",
+			      mdname(conf->mddev),
+			      dev - (struct r5dev *) &sh->dev)) {
+			clear_bit(R5_LOCKED, &dev->flags);
+			clear_bit(R5_Wantwrite, &dev->flags);
+			s->locked--;
+		}
 		clear_bit(STRIPE_DEGRADED, &sh->state);
 
 		set_bit(STRIPE_INSYNC, &sh->state);
@@ -4167,6 +4201,12 @@
 			s->failed++;
 			if (rdev && !test_bit(Faulty, &rdev->flags))
 				do_recovery = 1;
+			else if (!rdev) {
+				rdev = rcu_dereference(
+				    conf->disks[i].replacement);
+				if (rdev && !test_bit(Faulty, &rdev->flags))
+					do_recovery = 1;
+			}
 		}
 	}
 	if (test_bit(STRIPE_SYNCING, &sh->state)) {
@@ -4238,7 +4278,6 @@
 		WARN_ON_ONCE(sh->state & ((1 << STRIPE_ACTIVE) |
 					  (1 << STRIPE_SYNCING) |
 					  (1 << STRIPE_REPLACED) |
-					  (1 << STRIPE_PREREAD_ACTIVE) |
 					  (1 << STRIPE_DELAYED) |
 					  (1 << STRIPE_BIT_DELAY) |
 					  (1 << STRIPE_FULL_WRITE) |
@@ -4253,7 +4292,9 @@
 					      (1 << STRIPE_REPLACED)));
 
 		set_mask_bits(&sh->state, ~(STRIPE_EXPAND_SYNC_FLAGS |
-					    (1 << STRIPE_DEGRADED)),
+					    (1 << STRIPE_PREREAD_ACTIVE) |
+					    (1 << STRIPE_DEGRADED) |
+					    (1 << STRIPE_ON_UNPLUG_LIST)),
 			      head_sh->state & (1 << STRIPE_INSYNC));
 
 		sh->check_state = head_sh->check_state;
@@ -4439,7 +4480,7 @@
 	 * or to load a block that is being partially written.
 	 */
 	if (s.to_read || s.non_overwrite
-	    || (conf->level == 6 && s.to_write && s.failed)
+	    || (s.to_write && s.failed)
 	    || (s.syncing && (s.uptodate + s.compute < disks))
 	    || s.replacing
 	    || s.expanding)
@@ -5274,12 +5315,15 @@
 				 * userspace, we want an interruptible
 				 * wait.
 				 */
-				flush_signals(current);
 				prepare_to_wait(&conf->wait_for_overlap,
 						&w, TASK_INTERRUPTIBLE);
 				if (logical_sector >= mddev->suspend_lo &&
 				    logical_sector < mddev->suspend_hi) {
+					sigset_t full, old;
+					sigfillset(&full);
+					sigprocmask(SIG_BLOCK, &full, &old);
 					schedule();
+					sigprocmask(SIG_SETMASK, &old, NULL);
 					do_prepare = true;
 				}
 				goto retry;
@@ -5394,7 +5438,9 @@
 	safepos = conf->reshape_safe;
 	sector_div(safepos, data_disks);
 	if (mddev->reshape_backwards) {
-		BUG_ON(writepos < reshape_sectors);
+		if (WARN_ON(writepos < reshape_sectors))
+			return MaxSector;
+
 		writepos -= reshape_sectors;
 		readpos += reshape_sectors;
 		safepos += reshape_sectors;
@@ -5412,14 +5458,18 @@
 	 * to set 'stripe_addr' which is where we will write to.
 	 */
 	if (mddev->reshape_backwards) {
-		BUG_ON(conf->reshape_progress == 0);
+		if (WARN_ON(conf->reshape_progress == 0))
+			return MaxSector;
+
 		stripe_addr = writepos;
-		BUG_ON((mddev->dev_sectors &
-			~((sector_t)reshape_sectors - 1))
-		       - reshape_sectors - stripe_addr
-		       != sector_nr);
+		if (WARN_ON((mddev->dev_sectors &
+		    ~((sector_t)reshape_sectors - 1)) -
+		    reshape_sectors - stripe_addr != sector_nr))
+			return MaxSector;
 	} else {
-		BUG_ON(writepos != sector_nr + reshape_sectors);
+		if (WARN_ON(writepos != sector_nr + reshape_sectors))
+			return MaxSector;
+
 		stripe_addr = sector_nr;
 	}
 
@@ -5813,6 +5863,10 @@
 	pr_debug("%d stripes handled\n", handled);
 
 	spin_unlock_irq(&conf->device_lock);
+
+	r5l_flush_stripe_to_raid(conf->log);
+
+	async_tx_issue_pending_all();
 	blk_finish_plug(&plug);
 
 	pr_debug("--- raid5worker inactive\n");
@@ -5936,7 +5990,7 @@
 	if (size <= 16 || size > 32768)
 		return -EINVAL;
 
-	conf->min_nr_stripes = size;
+	WRITE_ONCE(conf->min_nr_stripes, size);
 	mutex_lock(&conf->cache_size_mutex);
 	while (size < conf->max_nr_stripes &&
 	       drop_one_stripe(conf))
@@ -6111,10 +6165,10 @@
 		mddev_suspend(mddev);
 		conf->skip_copy = new;
 		if (new)
-			mddev->queue->backing_dev_info.capabilities |=
+			mddev->queue->backing_dev_info->capabilities |=
 				BDI_CAP_STABLE_WRITES;
 		else
-			mddev->queue->backing_dev_info.capabilities &=
+			mddev->queue->backing_dev_info->capabilities &=
 				~BDI_CAP_STABLE_WRITES;
 		mddev_resume(mddev);
 	}
@@ -6414,6 +6468,12 @@
 	}
 	put_online_cpus();
 
+	if (!err) {
+		conf->scribble_disks = max(conf->raid_disks,
+			conf->previous_raid_disks);
+		conf->scribble_sectors = max(conf->chunk_sectors,
+			conf->prev_chunk_sectors);
+	}
 	return err;
 }
 
@@ -6442,11 +6502,13 @@
 				       struct shrink_control *sc)
 {
 	struct r5conf *conf = container_of(shrink, struct r5conf, shrinker);
+	int max_stripes = READ_ONCE(conf->max_nr_stripes);
+	int min_stripes = READ_ONCE(conf->min_nr_stripes);
 
-	if (conf->max_nr_stripes < conf->min_nr_stripes)
+	if (max_stripes < min_stripes)
 		/* unlikely, but not impossible */
 		return 0;
-	return conf->max_nr_stripes - conf->min_nr_stripes;
+	return max_stripes - min_stripes;
 }
 
 static struct r5conf *setup_conf(struct mddev *mddev)
@@ -6504,9 +6566,7 @@
 	seqcount_init(&conf->gen_lock);
 	mutex_init(&conf->cache_size_mutex);
 	init_waitqueue_head(&conf->wait_for_quiescent);
-	for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++) {
-		init_waitqueue_head(&conf->wait_for_stripe[i]);
-	}
+	init_waitqueue_head(&conf->wait_for_stripe);
 	init_waitqueue_head(&conf->wait_for_overlap);
 	INIT_LIST_HEAD(&conf->handle_list);
 	INIT_LIST_HEAD(&conf->hold_list);
@@ -6932,6 +6992,8 @@
 		set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
 		mddev->sync_thread = md_register_thread(md_do_sync, mddev,
 							"reshape");
+		if (!mddev->sync_thread)
+			goto abort;
 	}
 
 	/* Ok, everything is just fine now */
@@ -6954,8 +7016,8 @@
 		int data_disks = conf->previous_raid_disks - conf->max_degraded;
 		int stripe = data_disks *
 			((mddev->chunk_sectors << 9) / PAGE_SIZE);
-		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+		if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+			mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 
 		chunk_size = mddev->chunk_sectors << 9;
 		blk_queue_io_min(mddev->queue, chunk_size);
@@ -6973,6 +7035,15 @@
 			stripe = (stripe | (stripe-1)) + 1;
 		mddev->queue->limits.discard_alignment = stripe;
 		mddev->queue->limits.discard_granularity = stripe;
+
+		/*
+		 * We use 16-bit counter of active stripes in bi_phys_segments
+		 * (minus one for over-loaded initialization)
+		 */
+		blk_queue_max_hw_sectors(mddev->queue, 0xfffe * STRIPE_SECTORS);
+		blk_queue_max_discard_sectors(mddev->queue,
+					      0xfffe * STRIPE_SECTORS);
+
 		/*
 		 * unaligned part of discard request will be ignored, so can't
 		 * guarantee discard_zeroes_data
@@ -7015,8 +7086,8 @@
 		}
 
 		if (discard_supported &&
-		   mddev->queue->limits.max_discard_sectors >= stripe &&
-		   mddev->queue->limits.discard_granularity >= stripe)
+		    mddev->queue->limits.max_discard_sectors >= (stripe >> 9) &&
+		    mddev->queue->limits.discard_granularity >= stripe)
 			queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
 						mddev->queue);
 		else
@@ -7510,12 +7581,10 @@
 {
 
 	if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
-		struct md_rdev *rdev;
 
 		spin_lock_irq(&conf->device_lock);
 		conf->previous_raid_disks = conf->raid_disks;
-		rdev_for_each(rdev, conf->mddev)
-			rdev->data_offset = rdev->new_data_offset;
+		md_finish_reshape(conf->mddev);
 		smp_wmb();
 		conf->reshape_progress = MaxSector;
 		conf->mddev->reshape_position = MaxSector;
@@ -7529,8 +7598,8 @@
 			int data_disks = conf->raid_disks - conf->max_degraded;
 			int stripe = data_disks * ((conf->chunk_sectors << 9)
 						   / PAGE_SIZE);
-			if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-				conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+			if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+				conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 		}
 	}
 }
--- linux-4.4.0.orig/drivers/md/raid5.h
+++ linux-4.4.0/drivers/md/raid5.h
@@ -510,6 +510,8 @@
 					      * conversions
 					      */
 	} __percpu *percpu;
+	int scribble_disks;
+	int scribble_sectors;
 #ifdef CONFIG_HOTPLUG_CPU
 	struct notifier_block	cpu_notify;
 #endif
@@ -522,7 +524,7 @@
 	atomic_t		empty_inactive_list_nr;
 	struct llist_head	released_stripes;
 	wait_queue_head_t	wait_for_quiescent;
-	wait_queue_head_t	wait_for_stripe[NR_STRIPE_HASH_LOCKS];
+	wait_queue_head_t	wait_for_stripe;
 	wait_queue_head_t	wait_for_overlap;
 	unsigned long		cache_state;
 #define R5_INACTIVE_BLOCKED	1	/* release of inactive stripes blocked,
--- linux-4.4.0.orig/drivers/media/common/b2c2/flexcop-fe-tuner.c
+++ linux-4.4.0/drivers/media/common/b2c2/flexcop-fe-tuner.c
@@ -38,7 +38,7 @@
 #endif
 
 /* lnb control */
-#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
+#if (FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)) && FE_SUPPORTED(PLL)
 static int flexcop_set_voltage(struct dvb_frontend *fe,
 			       enum fe_sec_voltage voltage)
 {
@@ -68,7 +68,7 @@
 #endif
 
 #if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
-static int flexcop_sleep(struct dvb_frontend* fe)
+static int __maybe_unused flexcop_sleep(struct dvb_frontend* fe)
 {
 	struct flexcop_device *fc = fe->dvb->priv;
 	if (fc->fe_sleep)
--- linux-4.4.0.orig/drivers/media/common/siano/smsendian.c
+++ linux-4.4.0/drivers/media/common/siano/smsendian.c
@@ -35,7 +35,7 @@
 	switch (msg->x_msg_header.msg_type) {
 	case MSG_SMS_DATA_DOWNLOAD_REQ:
 	{
-		msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]);
+		msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0]));
 		break;
 	}
 
@@ -44,7 +44,7 @@
 				sizeof(struct sms_msg_hdr))/4;
 
 		for (i = 0; i < msg_words; i++)
-			msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]);
+			msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]);
 
 		break;
 	}
@@ -64,7 +64,7 @@
 	{
 		struct sms_version_res *ver =
 			(struct sms_version_res *) msg;
-		ver->chip_model = le16_to_cpu(ver->chip_model);
+		ver->chip_model = le16_to_cpu((__force __le16)ver->chip_model);
 		break;
 	}
 
@@ -81,7 +81,7 @@
 				sizeof(struct sms_msg_hdr))/4;
 
 		for (i = 0; i < msg_words; i++)
-			msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]);
+			msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]);
 
 		break;
 	}
@@ -95,9 +95,9 @@
 #ifdef __BIG_ENDIAN
 	struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg;
 
-	phdr->msg_type = le16_to_cpu(phdr->msg_type);
-	phdr->msg_length = le16_to_cpu(phdr->msg_length);
-	phdr->msg_flags = le16_to_cpu(phdr->msg_flags);
+	phdr->msg_type = le16_to_cpu((__force __le16)phdr->msg_type);
+	phdr->msg_length = le16_to_cpu((__force __le16)phdr->msg_length);
+	phdr->msg_flags = le16_to_cpu((__force __le16)phdr->msg_flags);
 #endif /* __BIG_ENDIAN */
 }
 EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
--- linux-4.4.0.orig/drivers/media/dvb-core/dmxdev.c
+++ linux-4.4.0/drivers/media/dvb-core/dmxdev.c
@@ -734,6 +734,11 @@
 	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
+	if (dmxdev->exit) {
+		mutex_unlock(&dmxdev->mutex);
+		return -ENODEV;
+	}
+
 	for (i = 0; i < dmxdev->filternum; i++)
 		if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
 			break;
@@ -1071,7 +1076,7 @@
 		break;
 
 	default:
-		ret = -EINVAL;
+		ret = -ENOTTY;
 		break;
 	}
 	mutex_unlock(&dmxdev->mutex);
@@ -1257,7 +1262,10 @@
 
 void dvb_dmxdev_release(struct dmxdev *dmxdev)
 {
-	dmxdev->exit=1;
+	mutex_lock(&dmxdev->mutex);
+	dmxdev->exit = 1;
+	mutex_unlock(&dmxdev->mutex);
+
 	if (dmxdev->dvbdev->users > 1) {
 		wait_event(dmxdev->dvbdev->wait_queue,
 				dmxdev->dvbdev->users==1);
--- linux-4.4.0.orig/drivers/media/dvb-core/dvb_ca_en50221.c
+++ linux-4.4.0/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/nospec.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
@@ -750,6 +751,29 @@
 		goto exit;
 	}
 
+	/*
+	 * It may need some time for the CAM to settle down, or there might
+	 * be a race condition between the CAM, writing HC and our last
+	 * check for DA. This happens, if the CAM asserts DA, just after
+	 * checking DA before we are setting HC. In this case it might be
+	 * a bug in the CAM to keep the FR bit, the lower layer/HW
+	 * communication requires a longer timeout or the CAM needs more
+	 * time internally. But this happens in reality!
+	 * We need to read the status from the HW again and do the same
+	 * we did for the previous check for DA
+	 */
+	status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+	if (status < 0)
+		goto exit;
+
+	if (status & (STATUSREG_DA | STATUSREG_RE)) {
+		if (status & STATUSREG_DA)
+			dvb_ca_en50221_thread_wakeup(ca);
+
+		status = -EAGAIN;
+		goto exit;
+	}
+
 	/* send the amount of data */
 	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
 		goto exit;
@@ -1310,6 +1334,10 @@
 	buf += 2;
 	count -= 2;
 
+	if (slot >= ca->slot_count)
+		return -EINVAL;
+	slot = array_index_nospec(slot, ca->slot_count);
+
 	/* check if the slot is actually running */
 	if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/media/dvb-core/dvb_frontend.c
+++ linux-4.4.0/drivers/media/dvb-core/dvb_frontend.c
@@ -230,8 +230,20 @@
 	wake_up_interruptible (&events->wait_queue);
 }
 
+static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv,
+				   struct dvb_fe_events *events)
+{
+	int ret;
+
+	up(&fepriv->sem);
+	ret = events->eventw != events->eventr;
+	down(&fepriv->sem);
+
+	return ret;
+}
+
 static int dvb_frontend_get_event(struct dvb_frontend *fe,
-			    struct dvb_frontend_event *event, int flags)
+			          struct dvb_frontend_event *event, int flags)
 {
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	struct dvb_fe_events *events = &fepriv->events;
@@ -244,19 +256,22 @@
 	}
 
 	if (events->eventw == events->eventr) {
-		int ret;
+		wait_queue_t wait;
+		int ret = 0;
 
 		if (flags & O_NONBLOCK)
 			return -EWOULDBLOCK;
 
-		up(&fepriv->sem);
-
-		ret = wait_event_interruptible (events->wait_queue,
-						events->eventw != events->eventr);
-
-		if (down_interruptible (&fepriv->sem))
-			return -ERESTARTSYS;
-
+		init_waitqueue_entry(&wait, current);
+		add_wait_queue(&events->wait_queue, &wait);
+		while (!dvb_frontend_test_event(fepriv, events)) {
+			wait_woken(&wait, TASK_INTERRUPTIBLE, 0);
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+		remove_wait_queue(&events->wait_queue, &wait);
 		if (ret < 0)
 			return ret;
 	}
@@ -2313,9 +2328,9 @@
 		dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n",
 				 __func__, c->delivery_system, fe->ops.info.type);
 
-		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
-		 * do it, it is done for it. */
-		info->caps |= FE_CAN_INVERSION_AUTO;
+		/* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */
+		if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT))
+			info->caps |= FE_CAN_INVERSION_AUTO;
 		err = 0;
 		break;
 	}
--- linux-4.4.0.orig/drivers/media/dvb-core/dvb_ringbuffer.c
+++ linux-4.4.0/drivers/media/dvb-core/dvb_ringbuffer.c
@@ -55,7 +55,13 @@
 
 int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
 {
-	return (rbuf->pread==rbuf->pwrite);
+	/* smp_load_acquire() to load write pointer on reader side
+	 * this pairs with smp_store_release() in dvb_ringbuffer_write(),
+	 * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
+	 *
+	 * for memory barriers also see Documentation/circular-buffers.txt
+	 */
+	return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
 }
 
 
@@ -64,7 +70,12 @@
 {
 	ssize_t free;
 
-	free = rbuf->pread - rbuf->pwrite;
+	/* ACCESS_ONCE() to load read pointer on writer side
+	 * this pairs with smp_store_release() in dvb_ringbuffer_read(),
+	 * dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(),
+	 * or dvb_ringbuffer_reset()
+	 */
+	free = ACCESS_ONCE(rbuf->pread) - rbuf->pwrite;
 	if (free <= 0)
 		free += rbuf->size;
 	return free-1;
@@ -76,7 +87,11 @@
 {
 	ssize_t avail;
 
-	avail = rbuf->pwrite - rbuf->pread;
+	/* smp_load_acquire() to load write pointer on reader side
+	 * this pairs with smp_store_release() in dvb_ringbuffer_write(),
+	 * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
+	 */
+	avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread;
 	if (avail < 0)
 		avail += rbuf->size;
 	return avail;
@@ -86,14 +101,25 @@
 
 void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
 {
-	rbuf->pread = rbuf->pwrite;
+	/* dvb_ringbuffer_flush() counts as read operation
+	 * smp_load_acquire() to load write pointer
+	 * smp_store_release() to update read pointer, this ensures that the
+	 * correct pointer is visible for subsequent dvb_ringbuffer_free()
+	 * calls on other cpu cores
+	 */
+	smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite));
 	rbuf->error = 0;
 }
 EXPORT_SYMBOL(dvb_ringbuffer_flush);
 
 void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
 {
-	rbuf->pread = rbuf->pwrite = 0;
+	/* dvb_ringbuffer_reset() counts as read and write operation
+	 * smp_store_release() to update read pointer
+	 */
+	smp_store_release(&rbuf->pread, 0);
+	/* smp_store_release() to update write pointer */
+	smp_store_release(&rbuf->pwrite, 0);
 	rbuf->error = 0;
 }
 
@@ -119,12 +145,17 @@
 			return -EFAULT;
 		buf += split;
 		todo -= split;
-		rbuf->pread = 0;
+		/* smp_store_release() for read pointer update to ensure
+		 * that buf is not overwritten until read is complete,
+		 * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
+		 */
+		smp_store_release(&rbuf->pread, 0);
 	}
 	if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
 		return -EFAULT;
 
-	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+	/* smp_store_release() to update read pointer, see above */
+	smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
 
 	return len;
 }
@@ -139,11 +170,16 @@
 		memcpy(buf, rbuf->data+rbuf->pread, split);
 		buf += split;
 		todo -= split;
-		rbuf->pread = 0;
+		/* smp_store_release() for read pointer update to ensure
+		 * that buf is not overwritten until read is complete,
+		 * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
+		 */
+		smp_store_release(&rbuf->pread, 0);
 	}
 	memcpy(buf, rbuf->data+rbuf->pread, todo);
 
-	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+	/* smp_store_release() to update read pointer, see above */
+	smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
 }
 
 
@@ -158,10 +194,16 @@
 		memcpy(rbuf->data+rbuf->pwrite, buf, split);
 		buf += split;
 		todo -= split;
-		rbuf->pwrite = 0;
+		/* smp_store_release() for write pointer update to ensure that
+		 * written data is visible on other cpu cores before the pointer
+		 * update, this pairs with smp_load_acquire() in
+		 * dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
+		 */
+		smp_store_release(&rbuf->pwrite, 0);
 	}
 	memcpy(rbuf->data+rbuf->pwrite, buf, todo);
-	rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+	/* smp_store_release() for write pointer update, see above */
+	smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
 
 	return len;
 }
@@ -181,12 +223,18 @@
 			return len - todo;
 		buf += split;
 		todo -= split;
-		rbuf->pwrite = 0;
+		/* smp_store_release() for write pointer update to ensure that
+		 * written data is visible on other cpu cores before the pointer
+		 * update, this pairs with smp_load_acquire() in
+		 * dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
+		 */
+		smp_store_release(&rbuf->pwrite, 0);
 	}
 	status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
 	if (status)
 		return len - todo;
-	rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+	/* smp_store_release() for write pointer update, see above */
+	smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
 
 	return len;
 }
--- linux-4.4.0.orig/drivers/media/dvb-core/dvbdev.c
+++ linux-4.4.0/drivers/media/dvb-core/dvbdev.c
@@ -67,10 +67,15 @@
 static int dvb_device_open(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev;
+	unsigned int minor = iminor(inode);
+
+	if (minor >= MAX_DVB_MINORS)
+		return -ENODEV;
 
 	mutex_lock(&dvbdev_mutex);
 	down_read(&minor_rwsem);
-	dvbdev = dvb_minors[iminor(inode)];
+
+	dvbdev = dvb_minors[minor];
 
 	if (dvbdev && dvbdev->fops) {
 		int err = 0;
@@ -319,17 +324,18 @@
 	for (minor = 0; minor < MAX_DVB_MINORS; minor++)
 		if (dvb_minors[minor] == NULL)
 			break;
-
-	if (minor == MAX_DVB_MINORS) {
+#else
+	minor = nums2minor(adap->num, type, id);
+#endif
+	if (minor >= MAX_DVB_MINORS) {
+		list_del(&dvbdev->list_head);
 		kfree(dvbdevfops);
 		kfree(dvbdev);
+		*pdvbdev = NULL;
 		up_write(&minor_rwsem);
 		mutex_unlock(&dvbdev_register_lock);
 		return -EINVAL;
 	}
-#else
-	minor = nums2minor(adap->num, type, id);
-#endif
 
 	dvbdev->minor = minor;
 	dvb_minors[minor] = dvbdev;
--- linux-4.4.0.orig/drivers/media/dvb-frontends/Kconfig
+++ linux-4.4.0/drivers/media/dvb-frontends/Kconfig
@@ -264,7 +264,7 @@
 config DVB_TDA10071
 	tristate "NXP TDA10071"
 	depends on DVB_CORE && I2C
-	select REGMAP
+	select REGMAP_I2C
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	  Say Y when you want to support this frontend.
--- linux-4.4.0.orig/drivers/media/dvb-frontends/ascot2e.c
+++ linux-4.4.0/drivers/media/dvb-frontends/ascot2e.c
@@ -155,7 +155,9 @@
 
 static int ascot2e_write_reg(struct ascot2e_priv *priv, u8 reg, u8 val)
 {
-	return ascot2e_write_regs(priv, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return ascot2e_write_regs(priv, reg, &tmp, 1);
 }
 
 static int ascot2e_read_regs(struct ascot2e_priv *priv,
--- linux-4.4.0.orig/drivers/media/dvb-frontends/cxd2841er.c
+++ linux-4.4.0/drivers/media/dvb-frontends/cxd2841er.c
@@ -241,7 +241,9 @@
 static int cxd2841er_write_reg(struct cxd2841er_priv *priv,
 			       u8 addr, u8 reg, u8 val)
 {
-	return cxd2841er_write_regs(priv, addr, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return cxd2841er_write_regs(priv, addr, reg, &tmp, 1);
 }
 
 static int cxd2841er_read_regs(struct cxd2841er_priv *priv,
@@ -2678,7 +2680,9 @@
 			FE_CAN_MUTE_TS |
 			FE_CAN_2G_MODULATION,
 		.frequency_min = 42000000,
-		.frequency_max = 1002000000
+		.frequency_max = 1002000000,
+		.symbol_rate_min = 870000,
+		.symbol_rate_max = 11700000
 	},
 	.init = cxd2841er_init_tc,
 	.sleep = cxd2841er_sleep_tc,
--- linux-4.4.0.orig/drivers/media/dvb-frontends/horus3a.c
+++ linux-4.4.0/drivers/media/dvb-frontends/horus3a.c
@@ -89,7 +89,9 @@
 
 static int horus3a_write_reg(struct horus3a_priv *priv, u8 reg, u8 val)
 {
-	return horus3a_write_regs(priv, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return horus3a_write_regs(priv, reg, &tmp, 1);
 }
 
 static int horus3a_enter_power_save(struct horus3a_priv *priv)
--- linux-4.4.0.orig/drivers/media/dvb-frontends/itd1000.c
+++ linux-4.4.0/drivers/media/dvb-frontends/itd1000.c
@@ -99,8 +99,9 @@
 
 static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v)
 {
-	int ret = itd1000_write_regs(state, r, &v, 1);
-	state->shadow[r] = v;
+	u8 tmp = v; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+	int ret = itd1000_write_regs(state, r, &tmp, 1);
+	state->shadow[r] = tmp;
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/media/dvb-frontends/m88ds3103.c
+++ linux-4.4.0/drivers/media/dvb-frontends/m88ds3103.c
@@ -309,6 +309,9 @@
 	u16 u16tmp, divide_ratio = 0;
 	u32 tuner_frequency, target_mclk;
 	s32 s32tmp;
+	static const struct reg_sequence reset_buf[] = {
+		{0x07, 0x80}, {0x07, 0x00}
+	};
 
 	dev_dbg(&client->dev,
 		"delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
@@ -321,11 +324,7 @@
 	}
 
 	/* reset */
-	ret = regmap_write(dev->regmap, 0x07, 0x80);
-	if (ret)
-		goto err;
-
-	ret = regmap_write(dev->regmap, 0x07, 0x00);
+	ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2);
 	if (ret)
 		goto err;
 
@@ -1281,11 +1280,12 @@
  * New users must use I2C client binding directly!
  */
 struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
-		struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter)
+				      struct i2c_adapter *i2c,
+				      struct i2c_adapter **tuner_i2c_adapter)
 {
 	struct i2c_client *client;
 	struct i2c_board_info board_info;
-	struct m88ds3103_platform_data pdata;
+	struct m88ds3103_platform_data pdata = {};
 
 	pdata.clk = cfg->clock;
 	pdata.i2c_wr_max = cfg->i2c_wr_max;
@@ -1428,6 +1428,8 @@
 	case M88DS3103_CHIP_ID:
 		break;
 	default:
+		ret = -ENODEV;
+		dev_err(&client->dev, "Unknown device. Chip_id=%02x\n", dev->chip_id);
 		goto err_kfree;
 	}
 
--- linux-4.4.0.orig/drivers/media/dvb-frontends/mb86a20s.c
+++ linux-4.4.0/drivers/media/dvb-frontends/mb86a20s.c
@@ -71,25 +71,27 @@
 };
 
 static struct regdata mb86a20s_init2[] = {
-	{ 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 },
+	{ 0x50, 0xd1 }, { 0x51, 0x22 },
+	{ 0x39, 0x01 },
+	{ 0x71, 0x00 },
 	{ 0x3b, 0x21 },
-	{ 0x3c, 0x38 },
+	{ 0x3c, 0x3a },
 	{ 0x01, 0x0d },
-	{ 0x04, 0x08 }, { 0x05, 0x03 },
+	{ 0x04, 0x08 }, { 0x05, 0x05 },
 	{ 0x04, 0x0e }, { 0x05, 0x00 },
-	{ 0x04, 0x0f }, { 0x05, 0x37 },
-	{ 0x04, 0x0b }, { 0x05, 0x78 },
+	{ 0x04, 0x0f }, { 0x05, 0x14 },
+	{ 0x04, 0x0b }, { 0x05, 0x8c },
 	{ 0x04, 0x00 }, { 0x05, 0x00 },
-	{ 0x04, 0x01 }, { 0x05, 0x1e },
-	{ 0x04, 0x02 }, { 0x05, 0x07 },
-	{ 0x04, 0x03 }, { 0x05, 0xd0 },
+	{ 0x04, 0x01 }, { 0x05, 0x07 },
+	{ 0x04, 0x02 }, { 0x05, 0x0f },
+	{ 0x04, 0x03 }, { 0x05, 0xa0 },
 	{ 0x04, 0x09 }, { 0x05, 0x00 },
 	{ 0x04, 0x0a }, { 0x05, 0xff },
-	{ 0x04, 0x27 }, { 0x05, 0x00 },
+	{ 0x04, 0x27 }, { 0x05, 0x64 },
 	{ 0x04, 0x28 }, { 0x05, 0x00 },
-	{ 0x04, 0x1e }, { 0x05, 0x00 },
-	{ 0x04, 0x29 }, { 0x05, 0x64 },
-	{ 0x04, 0x32 }, { 0x05, 0x02 },
+	{ 0x04, 0x1e }, { 0x05, 0xff },
+	{ 0x04, 0x29 }, { 0x05, 0x0a },
+	{ 0x04, 0x32 }, { 0x05, 0x0a },
 	{ 0x04, 0x14 }, { 0x05, 0x02 },
 	{ 0x04, 0x04 }, { 0x05, 0x00 },
 	{ 0x04, 0x05 }, { 0x05, 0x22 },
@@ -97,8 +99,6 @@
 	{ 0x04, 0x07 }, { 0x05, 0xd8 },
 	{ 0x04, 0x12 }, { 0x05, 0x00 },
 	{ 0x04, 0x13 }, { 0x05, 0xff },
-	{ 0x04, 0x15 }, { 0x05, 0x4e },
-	{ 0x04, 0x16 }, { 0x05, 0x20 },
 
 	/*
 	 * On this demod, when the bit count reaches the count below,
@@ -152,42 +152,36 @@
 	{ 0x50, 0x51 }, { 0x51, 0x04 },		/* MER symbol 4 */
 	{ 0x45, 0x04 },				/* CN symbol 4 */
 	{ 0x48, 0x04 },				/* CN manual mode */
-
+	{ 0x50, 0xd5 }, { 0x51, 0x01 },
 	{ 0x50, 0xd6 }, { 0x51, 0x1f },
 	{ 0x50, 0xd2 }, { 0x51, 0x03 },
-	{ 0x50, 0xd7 }, { 0x51, 0xbf },
-	{ 0x28, 0x74 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xff },
-	{ 0x28, 0x46 }, { 0x29, 0x00 }, { 0x2a, 0x1a }, { 0x2b, 0x0c },
-
-	{ 0x04, 0x40 }, { 0x05, 0x00 },
-	{ 0x28, 0x00 }, { 0x2b, 0x08 },
-	{ 0x28, 0x05 }, { 0x2b, 0x00 },
+	{ 0x50, 0xd7 }, { 0x51, 0x3f },
 	{ 0x1c, 0x01 },
-	{ 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x1f },
-	{ 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x18 },
-	{ 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x12 },
-	{ 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x30 },
-	{ 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x37 },
-	{ 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
-	{ 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x09 },
-	{ 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x06 },
-	{ 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7b },
-	{ 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x76 },
-	{ 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7d },
-	{ 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x08 },
-	{ 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0b },
-	{ 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
-	{ 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf2 },
-	{ 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf3 },
-	{ 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x05 },
-	{ 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
-	{ 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
-	{ 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xef },
-	{ 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xd8 },
-	{ 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xf1 },
-	{ 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x3d },
-	{ 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x94 },
-	{ 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xba },
+	{ 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 },
+	{ 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d },
+	{ 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
+	{ 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 },
+	{ 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 },
+	{ 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 },
+	{ 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
+	{ 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 },
+	{ 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e },
+	{ 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e },
+	{ 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 },
+	{ 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
+	{ 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 },
+	{ 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 },
+	{ 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe },
+	{ 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 },
+	{ 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee },
+	{ 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 },
+	{ 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f },
+	{ 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 },
+	{ 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 },
+	{ 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a },
+	{ 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc },
+	{ 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba },
+	{ 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 },
 	{ 0x50, 0x1e }, { 0x51, 0x5d },
 	{ 0x50, 0x22 }, { 0x51, 0x00 },
 	{ 0x50, 0x23 }, { 0x51, 0xc8 },
@@ -196,9 +190,7 @@
 	{ 0x50, 0x26 }, { 0x51, 0x00 },
 	{ 0x50, 0x27 }, { 0x51, 0xc3 },
 	{ 0x50, 0x39 }, { 0x51, 0x02 },
-	{ 0xec, 0x0f },
-	{ 0xeb, 0x1f },
-	{ 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
+	{ 0x50, 0xd5 }, { 0x51, 0x01 },
 	{ 0xd0, 0x00 },
 };
 
@@ -317,7 +309,11 @@
 	if (val >= 7)
 		*status |= FE_HAS_SYNC;
 
-	if (val >= 8)				/* Maybe 9? */
+	/*
+	 * Actually, on state S8, it starts receiving TS, but the TS
+	 * output is only on normal state after the transition to S9.
+	 */
+	if (val >= 9)
 		*status |= FE_HAS_LOCK;
 
 	dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n",
@@ -2067,6 +2063,11 @@
 	kfree(state);
 }
 
+static int mb86a20s_get_frontend_algo(struct dvb_frontend *fe)
+{
+        return DVBFE_ALGO_HW;
+}
+
 static struct dvb_frontend_ops mb86a20s_ops;
 
 struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
@@ -2140,6 +2141,7 @@
 	.read_status = mb86a20s_read_status_and_stats,
 	.read_signal_strength = mb86a20s_read_signal_strength_from_cache,
 	.tune = mb86a20s_tune,
+	.get_frontend_algo = mb86a20s_get_frontend_algo,
 };
 
 MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
--- linux-4.4.0.orig/drivers/media/dvb-frontends/mt312.c
+++ linux-4.4.0/drivers/media/dvb-frontends/mt312.c
@@ -142,7 +142,10 @@
 static inline int mt312_writereg(struct mt312_state *state,
 				 const enum mt312_reg_addr reg, const u8 val)
 {
-	return mt312_write(state, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+
+	return mt312_write(state, reg, &tmp, 1);
 }
 
 static inline u32 mt312_div(u32 a, u32 b)
--- linux-4.4.0.orig/drivers/media/dvb-frontends/si2168.c
+++ linux-4.4.0/drivers/media/dvb-frontends/si2168.c
@@ -14,6 +14,8 @@
  *    GNU General Public License for more details.
  */
 
+#include <linux/delay.h>
+
 #include "si2168_priv.h"
 
 static const struct dvb_frontend_ops si2168_ops;
@@ -420,6 +422,7 @@
 		if (ret)
 			goto err;
 
+		udelay(100);
 		memcpy(cmd.args, "\x85", 1);
 		cmd.wlen = 1;
 		cmd.rlen = 1;
--- linux-4.4.0.orig/drivers/media/dvb-frontends/stb0899_drv.c
+++ linux-4.4.0/drivers/media/dvb-frontends/stb0899_drv.c
@@ -552,7 +552,8 @@
 
 int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data)
 {
-	return stb0899_write_regs(state, reg, &data, 1);
+	u8 tmp = data;
+	return stb0899_write_regs(state, reg, &tmp, 1);
 }
 
 /*
--- linux-4.4.0.orig/drivers/media/dvb-frontends/stb6100.c
+++ linux-4.4.0/drivers/media/dvb-frontends/stb6100.c
@@ -226,12 +226,14 @@
 
 static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
 {
+	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
 	if (unlikely(reg >= STB6100_NUMREGS)) {
 		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
 		return -EREMOTEIO;
 	}
-	data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
-	return stb6100_write_reg_range(state, &data, reg, 1);
+	tmp = (tmp & stb6100_template[reg].mask) | stb6100_template[reg].set;
+	return stb6100_write_reg_range(state, &tmp, reg, 1);
 }
 
 
--- linux-4.4.0.orig/drivers/media/dvb-frontends/stv0367.c
+++ linux-4.4.0/drivers/media/dvb-frontends/stv0367.c
@@ -804,7 +804,9 @@
 
 static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data)
 {
-	return stv0367_writeregs(state, reg, &data, 1);
+	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return stv0367_writeregs(state, reg, &tmp, 1);
 }
 
 static u8 stv0367_readreg(struct stv0367_state *state, u16 reg)
--- linux-4.4.0.orig/drivers/media/dvb-frontends/stv090x.c
+++ linux-4.4.0/drivers/media/dvb-frontends/stv090x.c
@@ -761,7 +761,9 @@
 
 static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
 {
-	return stv090x_write_regs(state, reg, &data, 1);
+	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return stv090x_write_regs(state, reg, &tmp, 1);
 }
 
 static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
--- linux-4.4.0.orig/drivers/media/dvb-frontends/stv6110x.c
+++ linux-4.4.0/drivers/media/dvb-frontends/stv6110x.c
@@ -97,7 +97,9 @@
 
 static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
 {
-	return stv6110x_write_regs(stv6110x, reg, &data, 1);
+	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return stv6110x_write_regs(stv6110x, reg, &tmp, 1);
 }
 
 static int stv6110x_init(struct dvb_frontend *fe)
--- linux-4.4.0.orig/drivers/media/dvb-frontends/tda10048.c
+++ linux-4.4.0/drivers/media/dvb-frontends/tda10048.c
@@ -422,6 +422,7 @@
 	struct tda10048_config *config = &state->config;
 	int i;
 	u32 if_freq_khz;
+	u64 sample_freq;
 
 	dprintk(1, "%s(bw = %d)\n", __func__, bw);
 
@@ -463,9 +464,11 @@
 	dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
 
 	/* Calculate the sample frequency */
-	state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);
-	state->sample_freq /= (state->pll_nfactor + 1);
-	state->sample_freq /= (state->pll_pfactor + 4);
+	sample_freq = state->xtal_hz;
+	sample_freq *= state->pll_mfactor + 45;
+	do_div(sample_freq, state->pll_nfactor + 1);
+	do_div(sample_freq, state->pll_pfactor + 4);
+	state->sample_freq = sample_freq;
 	dprintk(1, "- sample_freq = %d\n", state->sample_freq);
 
 	/* Update the I/F */
--- linux-4.4.0.orig/drivers/media/dvb-frontends/tda1004x.c
+++ linux-4.4.0/drivers/media/dvb-frontends/tda1004x.c
@@ -903,9 +903,18 @@
 {
 	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
 	struct tda1004x_state* state = fe->demodulator_priv;
+	int status;
 
 	dprintk("%s\n", __func__);
 
+	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
+	if (status == -1)
+		return -EIO;
+
+	/* Only update the properties cache if device is locked */
+	if (!(status & 8))
+		return 0;
+
 	// inversion status
 	fe_params->inversion = INVERSION_OFF;
 	if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
--- linux-4.4.0.orig/drivers/media/dvb-frontends/tda10071.c
+++ linux-4.4.0/drivers/media/dvb-frontends/tda10071.c
@@ -483,10 +483,11 @@
 			goto error;
 
 		if (dev->delivery_system == SYS_DVBS) {
-			dev->dvbv3_ber = buf[0] << 24 | buf[1] << 16 |
-					 buf[2] << 8 | buf[3] << 0;
-			dev->post_bit_error += buf[0] << 24 | buf[1] << 16 |
-					       buf[2] << 8 | buf[3] << 0;
+			u32 bit_error = buf[0] << 24 | buf[1] << 16 |
+					buf[2] << 8 | buf[3] << 0;
+
+			dev->dvbv3_ber = bit_error;
+			dev->post_bit_error += bit_error;
 			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
 			c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
 			dev->block_error += buf[4] << 8 | buf[5] << 0;
--- linux-4.4.0.orig/drivers/media/dvb-frontends/ts2020.c
+++ linux-4.4.0/drivers/media/dvb-frontends/ts2020.c
@@ -369,7 +369,7 @@
 		gain2 = clamp_t(long, gain2, 0, 13);
 		v_agc = clamp_t(long, v_agc, 400, 1100);
 
-		*_gain = -(gain1 * 2330 +
+		*_gain = -((__s64)gain1 * 2330 +
 			   gain2 * 3500 +
 			   v_agc * 24 / 10 * 10 +
 			   10000);
@@ -387,7 +387,7 @@
 		gain3 = clamp_t(long, gain3, 0, 6);
 		v_agc = clamp_t(long, v_agc, 600, 1600);
 
-		*_gain = -(gain1 * 2650 +
+		*_gain = -((__s64)gain1 * 2650 +
 			   gain2 * 3380 +
 			   gain3 * 2850 +
 			   v_agc * 176 / 100 * 10 -
--- linux-4.4.0.orig/drivers/media/dvb-frontends/tua6100.c
+++ linux-4.4.0/drivers/media/dvb-frontends/tua6100.c
@@ -80,8 +80,8 @@
 	struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
 	struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
 
-#define _R 4
-#define _P 32
+#define _R_VAL 4
+#define _P_VAL 32
 #define _ri 4000000
 
 	// setup register 0
@@ -96,14 +96,14 @@
 	else
 		reg1[1] = 0x0c;
 
-	if (_P == 64)
+	if (_P_VAL == 64)
 		reg1[1] |= 0x40;
 	if (c->frequency >= 1525000)
 		reg1[1] |= 0x80;
 
 	// register 2
-	reg2[1] = (_R >> 8) & 0x03;
-	reg2[2] = _R;
+	reg2[1] = (_R_VAL >> 8) & 0x03;
+	reg2[2] = _R_VAL;
 	if (c->frequency < 1455000)
 		reg2[1] |= 0x1c;
 	else if (c->frequency < 1630000)
@@ -115,18 +115,18 @@
 	 * The N divisor ratio (note: c->frequency is in kHz, but we
 	 * need it in Hz)
 	 */
-	prediv = (c->frequency * _R) / (_ri / 1000);
-	div = prediv / _P;
+	prediv = (c->frequency * _R_VAL) / (_ri / 1000);
+	div = prediv / _P_VAL;
 	reg1[1] |= (div >> 9) & 0x03;
 	reg1[2] = div >> 1;
 	reg1[3] = (div << 7);
-	priv->frequency = ((div * _P) * (_ri / 1000)) / _R;
+	priv->frequency = ((div * _P_VAL) * (_ri / 1000)) / _R_VAL;
 
 	// Finally, calculate and store the value for A
-	reg1[3] |= (prediv - (div*_P)) & 0x7f;
+	reg1[3] |= (prediv - (div*_P_VAL)) & 0x7f;
 
-#undef _R
-#undef _P
+#undef _R_VAL
+#undef _P_VAL
 #undef _ri
 
 	if (fe->ops.i2c_gate_ctrl)
--- linux-4.4.0.orig/drivers/media/dvb-frontends/zl10039.c
+++ linux-4.4.0/drivers/media/dvb-frontends/zl10039.c
@@ -138,7 +138,9 @@
 				const enum zl10039_reg_addr reg,
 				const u8 val)
 {
-	return zl10039_write(state, reg, &val, 1);
+	const u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return zl10039_write(state, reg, &tmp, 1);
 }
 
 static int zl10039_init(struct dvb_frontend *fe)
--- linux-4.4.0.orig/drivers/media/firewire/firedtv-avc.c
+++ linux-4.4.0/drivers/media/firewire/firedtv-avc.c
@@ -968,7 +968,8 @@
 	return r->operand[7];
 }
 
-int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
+int avc_ca_app_info(struct firedtv *fdtv, unsigned char *app_info,
+		    unsigned int *len)
 {
 	struct avc_command_frame *c = (void *)fdtv->avc_data;
 	struct avc_response_frame *r = (void *)fdtv->avc_data;
@@ -1009,7 +1010,8 @@
 	return ret;
 }
 
-int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
+int avc_ca_info(struct firedtv *fdtv, unsigned char *app_info,
+		unsigned int *len)
 {
 	struct avc_command_frame *c = (void *)fdtv->avc_data;
 	struct avc_response_frame *r = (void *)fdtv->avc_data;
@@ -1167,7 +1169,11 @@
 		read_pos += program_info_length;
 		write_pos += program_info_length;
 	}
-	while (read_pos < length) {
+	while (read_pos + 4 < length) {
+		if (write_pos + 4 >= sizeof(c->operand) - 4) {
+			ret = -EINVAL;
+			goto out;
+		}
 		c->operand[write_pos++] = msg[read_pos++];
 		c->operand[write_pos++] = msg[read_pos++];
 		c->operand[write_pos++] = msg[read_pos++];
@@ -1179,13 +1185,17 @@
 		c->operand[write_pos++] = es_info_length >> 8;
 		c->operand[write_pos++] = es_info_length & 0xff;
 		if (es_info_length > 0) {
+			if (read_pos >= length) {
+				ret = -EINVAL;
+				goto out;
+			}
 			pmt_cmd_id = msg[read_pos++];
 			if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
 				dev_err(fdtv->device, "invalid pmt_cmd_id %d "
 					"at stream level\n", pmt_cmd_id);
 
-			if (es_info_length > sizeof(c->operand) - 4 -
-					     write_pos) {
+			if (es_info_length > sizeof(c->operand) - 4 - write_pos ||
+			    es_info_length > length - read_pos) {
 				ret = -EINVAL;
 				goto out;
 			}
--- linux-4.4.0.orig/drivers/media/firewire/firedtv-ci.c
+++ linux-4.4.0/drivers/media/firewire/firedtv-ci.c
@@ -138,6 +138,8 @@
 	} else {
 		data_length = msg->msg[3];
 	}
+	if (data_length > sizeof(msg->msg) - data_pos)
+		return -EINVAL;
 
 	return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
 }
--- linux-4.4.0.orig/drivers/media/firewire/firedtv-fw.c
+++ linux-4.4.0/drivers/media/firewire/firedtv-fw.c
@@ -271,6 +271,10 @@
 
 	name_len = fw_csr_string(unit->directory, CSR_MODEL,
 				 name, sizeof(name));
+	if (name_len < 0) {
+		err = name_len;
+		goto fail_free;
+	}
 	for (i = ARRAY_SIZE(model_names); --i; )
 		if (strlen(model_names[i]) <= name_len &&
 		    strncmp(name, model_names[i], name_len) == 0)
--- linux-4.4.0.orig/drivers/media/firewire/firedtv.h
+++ linux-4.4.0/drivers/media/firewire/firedtv.h
@@ -124,8 +124,10 @@
 		    struct dvb_diseqc_master_cmd *diseqcmd);
 void avc_remote_ctrl_work(struct work_struct *work);
 int avc_register_remote_control(struct firedtv *fdtv);
-int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
-int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
+int avc_ca_app_info(struct firedtv *fdtv, unsigned char *app_info,
+		    unsigned int *len);
+int avc_ca_info(struct firedtv *fdtv, unsigned char *app_info,
+		unsigned int *len);
 int avc_ca_reset(struct firedtv *fdtv);
 int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
 int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
--- linux-4.4.0.orig/drivers/media/i2c/Kconfig
+++ linux-4.4.0/drivers/media/i2c/Kconfig
@@ -607,6 +607,7 @@
 config VIDEO_S5K4ECGX
         tristate "Samsung S5K4ECGX sensor support"
         depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	select CRC32
         ---help---
           This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M
           camera sensor with an embedded SoC image signal processor.
--- linux-4.4.0.orig/drivers/media/i2c/Makefile
+++ linux-4.4.0/drivers/media/i2c/Makefile
@@ -28,7 +28,7 @@
 obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o
 obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
 obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
-obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o
+obj-$(CONFIG_VIDEO_ADV7511) += adv7511-v4l2.o
 obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
 obj-$(CONFIG_VIDEO_VS6624)  += vs6624.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
--- linux-4.4.0.orig/drivers/media/i2c/adv7511-v4l2.c
+++ linux-4.4.0/drivers/media/i2c/adv7511-v4l2.c
@@ -0,0 +1,1600 @@
+/*
+ * Analog Devices ADV7511 HDMI Transmitter Device Driver
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This file is named adv7511-v4l2.c so it doesn't conflict with the Analog
+ * Device ADV7511 (config fragment CONFIG_DRM_I2C_ADV7511).
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/hdmi.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/adv7511.h>
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+
+MODULE_DESCRIPTION("Analog Devices ADV7511 HDMI Transmitter Device Driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL v2");
+
+#define MASK_ADV7511_EDID_RDY_INT   0x04
+#define MASK_ADV7511_MSEN_INT       0x40
+#define MASK_ADV7511_HPD_INT        0x80
+
+#define MASK_ADV7511_HPD_DETECT     0x40
+#define MASK_ADV7511_MSEN_DETECT    0x20
+#define MASK_ADV7511_EDID_RDY       0x10
+
+#define EDID_MAX_RETRIES (8)
+#define EDID_DELAY 250
+#define EDID_MAX_SEGM 8
+
+#define ADV7511_MAX_WIDTH 1920
+#define ADV7511_MAX_HEIGHT 1200
+#define ADV7511_MIN_PIXELCLOCK 20000000
+#define ADV7511_MAX_PIXELCLOCK 225000000
+
+/*
+**********************************************************************
+*
+*  Arrays with configuration parameters for the ADV7511
+*
+**********************************************************************
+*/
+
+struct i2c_reg_value {
+	unsigned char reg;
+	unsigned char value;
+};
+
+struct adv7511_state_edid {
+	/* total number of blocks */
+	u32 blocks;
+	/* Number of segments read */
+	u32 segments;
+	u8 data[EDID_MAX_SEGM * 256];
+	/* Number of EDID read retries left */
+	unsigned read_retries;
+	bool complete;
+};
+
+struct adv7511_state {
+	struct adv7511_platform_data pdata;
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct v4l2_ctrl_handler hdl;
+	int chip_revision;
+	u8 i2c_edid_addr;
+	u8 i2c_cec_addr;
+	u8 i2c_pktmem_addr;
+	/* Is the adv7511 powered on? */
+	bool power_on;
+	/* Did we receive hotplug and rx-sense signals? */
+	bool have_monitor;
+	/* timings from s_dv_timings */
+	struct v4l2_dv_timings dv_timings;
+	u32 fmt_code;
+	u32 colorspace;
+	u32 ycbcr_enc;
+	u32 quantization;
+	u32 xfer_func;
+	/* controls */
+	struct v4l2_ctrl *hdmi_mode_ctrl;
+	struct v4l2_ctrl *hotplug_ctrl;
+	struct v4l2_ctrl *rx_sense_ctrl;
+	struct v4l2_ctrl *have_edid0_ctrl;
+	struct v4l2_ctrl *rgb_quantization_range_ctrl;
+	struct i2c_client *i2c_edid;
+	struct i2c_client *i2c_pktmem;
+	struct adv7511_state_edid edid;
+	/* Running counter of the number of detected EDIDs (for debugging) */
+	unsigned edid_detect_counter;
+	struct workqueue_struct *work_queue;
+	struct delayed_work edid_handler; /* work entry */
+};
+
+static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd);
+static bool adv7511_check_edid_status(struct v4l2_subdev *sd);
+static void adv7511_setup(struct v4l2_subdev *sd);
+static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq);
+static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
+
+
+static const struct v4l2_dv_timings_cap adv7511_timings_cap = {
+	.type = V4L2_DV_BT_656_1120,
+	/* keep this initialization for compatibility with GCC < 4.4.6 */
+	.reserved = { 0 },
+	V4L2_INIT_BT_TIMINGS(0, ADV7511_MAX_WIDTH, 0, ADV7511_MAX_HEIGHT,
+		ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK,
+		V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+			V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
+		V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
+			V4L2_DV_BT_CAP_CUSTOM)
+};
+
+static inline struct adv7511_state *get_adv7511_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7511_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct adv7511_state, hdl)->sd;
+}
+
+/* ------------------------ I2C ----------------------------------------------- */
+
+static s32 adv_smbus_read_byte_data_check(struct i2c_client *client,
+					  u8 command, bool check)
+{
+	union i2c_smbus_data data;
+
+	if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+			    I2C_SMBUS_READ, command,
+			    I2C_SMBUS_BYTE_DATA, &data))
+		return data.byte;
+	if (check)
+		v4l_err(client, "error reading %02x, %02x\n",
+			client->addr, command);
+	return -1;
+}
+
+static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command)
+{
+	int i;
+	for (i = 0; i < 3; i++) {
+		int ret = adv_smbus_read_byte_data_check(client, command, true);
+		if (ret >= 0) {
+			if (i)
+				v4l_err(client, "read ok after %d retries\n", i);
+			return ret;
+		}
+	}
+	v4l_err(client, "read failed\n");
+	return -1;
+}
+
+static int adv7511_rd(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return adv_smbus_read_byte_data(client, reg);
+}
+
+static int adv7511_wr(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		ret = i2c_smbus_write_byte_data(client, reg, val);
+		if (ret == 0)
+			return 0;
+	}
+	v4l2_err(sd, "%s: i2c write error\n", __func__);
+	return ret;
+}
+
+/* To set specific bits in the register, a clear-mask is given (to be AND-ed),
+   and then the value-mask (to be OR-ed). */
+static inline void adv7511_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask)
+{
+	adv7511_wr(sd, reg, (adv7511_rd(sd, reg) & clr_mask) | val_mask);
+}
+
+static int adv_smbus_read_i2c_block_data(struct i2c_client *client,
+					 u8 command, unsigned length, u8 *values)
+{
+	union i2c_smbus_data data;
+	int ret;
+
+	if (length > I2C_SMBUS_BLOCK_MAX)
+		length = I2C_SMBUS_BLOCK_MAX;
+	data.block[0] = length;
+
+	ret = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+			     I2C_SMBUS_READ, command,
+			     I2C_SMBUS_I2C_BLOCK_DATA, &data);
+	memcpy(values, data.block + 1, length);
+	return ret;
+}
+
+static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	int i;
+	int err = 0;
+
+	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+	for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX)
+		err = adv_smbus_read_i2c_block_data(state->i2c_edid, i,
+						    I2C_SMBUS_BLOCK_MAX, buf + i);
+	if (err)
+		v4l2_err(sd, "%s: i2c read error\n", __func__);
+}
+
+static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	return adv_smbus_read_byte_data(state->i2c_pktmem, reg);
+}
+
+static int adv7511_pktmem_wr(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	int ret;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		ret = i2c_smbus_write_byte_data(state->i2c_pktmem, reg, val);
+		if (ret == 0)
+			return 0;
+	}
+	v4l2_err(sd, "%s: i2c write error\n", __func__);
+	return ret;
+}
+
+/* To set specific bits in the register, a clear-mask is given (to be AND-ed),
+   and then the value-mask (to be OR-ed). */
+static inline void adv7511_pktmem_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask)
+{
+	adv7511_pktmem_wr(sd, reg, (adv7511_pktmem_rd(sd, reg) & clr_mask) | val_mask);
+}
+
+static inline bool adv7511_have_hotplug(struct v4l2_subdev *sd)
+{
+	return adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT;
+}
+
+static inline bool adv7511_have_rx_sense(struct v4l2_subdev *sd)
+{
+	return adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT;
+}
+
+static void adv7511_csc_conversion_mode(struct v4l2_subdev *sd, u8 mode)
+{
+	adv7511_wr_and_or(sd, 0x18, 0x9f, (mode & 0x3)<<5);
+}
+
+static void adv7511_csc_coeff(struct v4l2_subdev *sd,
+			      u16 A1, u16 A2, u16 A3, u16 A4,
+			      u16 B1, u16 B2, u16 B3, u16 B4,
+			      u16 C1, u16 C2, u16 C3, u16 C4)
+{
+	/* A */
+	adv7511_wr_and_or(sd, 0x18, 0xe0, A1>>8);
+	adv7511_wr(sd, 0x19, A1);
+	adv7511_wr_and_or(sd, 0x1A, 0xe0, A2>>8);
+	adv7511_wr(sd, 0x1B, A2);
+	adv7511_wr_and_or(sd, 0x1c, 0xe0, A3>>8);
+	adv7511_wr(sd, 0x1d, A3);
+	adv7511_wr_and_or(sd, 0x1e, 0xe0, A4>>8);
+	adv7511_wr(sd, 0x1f, A4);
+
+	/* B */
+	adv7511_wr_and_or(sd, 0x20, 0xe0, B1>>8);
+	adv7511_wr(sd, 0x21, B1);
+	adv7511_wr_and_or(sd, 0x22, 0xe0, B2>>8);
+	adv7511_wr(sd, 0x23, B2);
+	adv7511_wr_and_or(sd, 0x24, 0xe0, B3>>8);
+	adv7511_wr(sd, 0x25, B3);
+	adv7511_wr_and_or(sd, 0x26, 0xe0, B4>>8);
+	adv7511_wr(sd, 0x27, B4);
+
+	/* C */
+	adv7511_wr_and_or(sd, 0x28, 0xe0, C1>>8);
+	adv7511_wr(sd, 0x29, C1);
+	adv7511_wr_and_or(sd, 0x2A, 0xe0, C2>>8);
+	adv7511_wr(sd, 0x2B, C2);
+	adv7511_wr_and_or(sd, 0x2C, 0xe0, C3>>8);
+	adv7511_wr(sd, 0x2D, C3);
+	adv7511_wr_and_or(sd, 0x2E, 0xe0, C4>>8);
+	adv7511_wr(sd, 0x2F, C4);
+}
+
+static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable)
+{
+	if (enable) {
+		u8 csc_mode = 0;
+		adv7511_csc_conversion_mode(sd, csc_mode);
+		adv7511_csc_coeff(sd,
+				  4096-564, 0, 0, 256,
+				  0, 4096-564, 0, 256,
+				  0, 0, 4096-564, 256);
+		/* enable CSC */
+		adv7511_wr_and_or(sd, 0x18, 0x7f, 0x80);
+		/* AVI infoframe: Limited range RGB (16-235) */
+		adv7511_wr_and_or(sd, 0x57, 0xf3, 0x04);
+	} else {
+		/* disable CSC */
+		adv7511_wr_and_or(sd, 0x18, 0x7f, 0x0);
+		/* AVI infoframe: Full range RGB (0-255) */
+		adv7511_wr_and_or(sd, 0x57, 0xf3, 0x08);
+	}
+}
+
+static void adv7511_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
+		/* CE format, not IT  */
+		adv7511_wr_and_or(sd, 0x57, 0x7f, 0x00);
+	} else {
+		/* IT format */
+		adv7511_wr_and_or(sd, 0x57, 0x7f, 0x80);
+	}
+}
+
+static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl)
+{
+	switch (ctrl->val) {
+	default:
+		return -EINVAL;
+		break;
+	case V4L2_DV_RGB_RANGE_AUTO: {
+		/* automatic */
+		struct adv7511_state *state = get_adv7511_state(sd);
+
+		if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
+			/* CE format, RGB limited range (16-235) */
+			adv7511_csc_rgb_full2limit(sd, true);
+		} else {
+			/* not CE format, RGB full range (0-255) */
+			adv7511_csc_rgb_full2limit(sd, false);
+		}
+	}
+		break;
+	case V4L2_DV_RGB_RANGE_LIMITED:
+		/* RGB limited range (16-235) */
+		adv7511_csc_rgb_full2limit(sd, true);
+		break;
+	case V4L2_DV_RGB_RANGE_FULL:
+		/* RGB full range (0-255) */
+		adv7511_csc_rgb_full2limit(sd, false);
+		break;
+	}
+	return 0;
+}
+
+/* ------------------------------ CTRL OPS ------------------------------ */
+
+static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	v4l2_dbg(1, debug, sd, "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
+
+	if (state->hdmi_mode_ctrl == ctrl) {
+		/* Set HDMI or DVI-D */
+		adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
+		return 0;
+	}
+	if (state->rgb_quantization_range_ctrl == ctrl)
+		return adv7511_set_rgb_quantization_mode(sd, ctrl);
+
+	return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops adv7511_ctrl_ops = {
+	.s_ctrl = adv7511_s_ctrl,
+};
+
+/* ---------------------------- CORE OPS ------------------------------------------- */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static void adv7511_inv_register(struct v4l2_subdev *sd)
+{
+	v4l2_info(sd, "0x000-0x0ff: Main Map\n");
+}
+
+static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	reg->size = 1;
+	switch (reg->reg >> 8) {
+	case 0:
+		reg->val = adv7511_rd(sd, reg->reg & 0xff);
+		break;
+	default:
+		v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
+		adv7511_inv_register(sd);
+		break;
+	}
+	return 0;
+}
+
+static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
+{
+	switch (reg->reg >> 8) {
+	case 0:
+		adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff);
+		break;
+	default:
+		v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
+		adv7511_inv_register(sd);
+		break;
+	}
+	return 0;
+}
+#endif
+
+struct adv7511_cfg_read_infoframe {
+	const char *desc;
+	u8 present_reg;
+	u8 present_mask;
+	u8 header[3];
+	u16 payload_addr;
+};
+
+static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
+{
+	u8 csum = 0;
+	size_t i;
+
+	/* compute checksum */
+	for (i = 0; i < size; i++)
+		csum += ptr[i];
+
+	return 256 - csum;
+}
+
+static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
+	union hdmi_infoframe frame;
+	u8 buffer[32];
+	u8 len;
+	int i;
+
+	if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) {
+		v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc);
+		return;
+	}
+
+	memcpy(buffer, cri->header, sizeof(cri->header));
+
+	len = buffer[2];
+
+	if (len + 4 > sizeof(buffer)) {
+		v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len);
+		return;
+	}
+
+	if (cri->payload_addr >= 0x100) {
+		for (i = 0; i < len; i++)
+			buffer[i + 4] = adv7511_pktmem_rd(sd, cri->payload_addr + i - 0x100);
+	} else {
+		for (i = 0; i < len; i++)
+			buffer[i + 4] = adv7511_rd(sd, cri->payload_addr + i);
+	}
+	buffer[3] = 0;
+	buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
+
+	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
+		return;
+	}
+
+	hdmi_infoframe_log(KERN_INFO, dev, &frame);
+}
+
+static void adv7511_log_infoframes(struct v4l2_subdev *sd)
+{
+	static const struct adv7511_cfg_read_infoframe cri[] = {
+		{ "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 },
+		{ "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 },
+		{ "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cri); i++)
+		log_infoframe(sd, &cri[i]);
+}
+
+static int adv7511_log_status(struct v4l2_subdev *sd)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	struct adv7511_state_edid *edid = &state->edid;
+
+	static const char * const states[] = {
+		"in reset",
+		"reading EDID",
+		"idle",
+		"initializing HDCP",
+		"HDCP enabled",
+		"initializing HDCP repeater",
+		"6", "7", "8", "9", "A", "B", "C", "D", "E", "F"
+	};
+	static const char * const errors[] = {
+		"no error",
+		"bad receiver BKSV",
+		"Ri mismatch",
+		"Pj mismatch",
+		"i2c error",
+		"timed out",
+		"max repeater cascade exceeded",
+		"hash check failed",
+		"too many devices",
+		"9", "A", "B", "C", "D", "E", "F"
+	};
+
+	v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off");
+	v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n",
+		  (adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT) ? "detected" : "no",
+		  (adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT) ? "detected" : "no",
+		  edid->segments ? "found" : "no",
+		  edid->blocks);
+	v4l2_info(sd, "%s output %s\n",
+		  (adv7511_rd(sd, 0xaf) & 0x02) ?
+		  "HDMI" : "DVI-D",
+		  (adv7511_rd(sd, 0xa1) & 0x3c) ?
+		  "disabled" : "enabled");
+	v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n",
+			  states[adv7511_rd(sd, 0xc8) & 0xf],
+			  errors[adv7511_rd(sd, 0xc8) >> 4], state->edid_detect_counter,
+			  adv7511_rd(sd, 0x94), adv7511_rd(sd, 0x96));
+	v4l2_info(sd, "RGB quantization: %s range\n", adv7511_rd(sd, 0x18) & 0x80 ? "limited" : "full");
+	if (adv7511_rd(sd, 0xaf) & 0x02) {
+		/* HDMI only */
+		u8 manual_cts = adv7511_rd(sd, 0x0a) & 0x80;
+		u32 N = (adv7511_rd(sd, 0x01) & 0xf) << 16 |
+			adv7511_rd(sd, 0x02) << 8 |
+			adv7511_rd(sd, 0x03);
+		u8 vic_detect = adv7511_rd(sd, 0x3e) >> 2;
+		u8 vic_sent = adv7511_rd(sd, 0x3d) & 0x3f;
+		u32 CTS;
+
+		if (manual_cts)
+			CTS = (adv7511_rd(sd, 0x07) & 0xf) << 16 |
+			      adv7511_rd(sd, 0x08) << 8 |
+			      adv7511_rd(sd, 0x09);
+		else
+			CTS = (adv7511_rd(sd, 0x04) & 0xf) << 16 |
+			      adv7511_rd(sd, 0x05) << 8 |
+			      adv7511_rd(sd, 0x06);
+		v4l2_info(sd, "CTS %s mode: N %d, CTS %d\n",
+			  manual_cts ? "manual" : "automatic", N, CTS);
+		v4l2_info(sd, "VIC: detected %d, sent %d\n",
+			  vic_detect, vic_sent);
+		adv7511_log_infoframes(sd);
+	}
+	if (state->dv_timings.type == V4L2_DV_BT_656_1120)
+		v4l2_print_dv_timings(sd->name, "timings: ",
+				&state->dv_timings, false);
+	else
+		v4l2_info(sd, "no timings set\n");
+	v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr);
+	v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr);
+	v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr);
+	return 0;
+}
+
+/* Power up/down adv7511 */
+static int adv7511_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	const int retries = 20;
+	int i;
+
+	v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off");
+
+	state->power_on = on;
+
+	if (!on) {
+		/* Power down */
+		adv7511_wr_and_or(sd, 0x41, 0xbf, 0x40);
+		return true;
+	}
+
+	/* Power up */
+	/* The adv7511 does not always come up immediately.
+	   Retry multiple times. */
+	for (i = 0; i < retries; i++) {
+		adv7511_wr_and_or(sd, 0x41, 0xbf, 0x0);
+		if ((adv7511_rd(sd, 0x41) & 0x40) == 0)
+			break;
+		adv7511_wr_and_or(sd, 0x41, 0xbf, 0x40);
+		msleep(10);
+	}
+	if (i == retries) {
+		v4l2_dbg(1, debug, sd, "%s: failed to powerup the adv7511!\n", __func__);
+		adv7511_s_power(sd, 0);
+		return false;
+	}
+	if (i > 1)
+		v4l2_dbg(1, debug, sd, "%s: needed %d retries to powerup the adv7511\n", __func__, i);
+
+	/* Reserved registers that must be set */
+	adv7511_wr(sd, 0x98, 0x03);
+	adv7511_wr_and_or(sd, 0x9a, 0xfe, 0x70);
+	adv7511_wr(sd, 0x9c, 0x30);
+	adv7511_wr_and_or(sd, 0x9d, 0xfc, 0x01);
+	adv7511_wr(sd, 0xa2, 0xa4);
+	adv7511_wr(sd, 0xa3, 0xa4);
+	adv7511_wr(sd, 0xe0, 0xd0);
+	adv7511_wr(sd, 0xf9, 0x00);
+
+	adv7511_wr(sd, 0x43, state->i2c_edid_addr);
+	adv7511_wr(sd, 0x45, state->i2c_pktmem_addr);
+
+	/* Set number of attempts to read the EDID */
+	adv7511_wr(sd, 0xc9, 0xf);
+	return true;
+}
+
+/* Enable interrupts */
+static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)
+{
+	u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT;
+	u8 irqs_rd;
+	int retries = 100;
+
+	v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable");
+
+	/* The datasheet says that the EDID ready interrupt should be
+	   disabled if there is no hotplug. */
+	if (!enable)
+		irqs = 0;
+	else if (adv7511_have_hotplug(sd))
+		irqs |= MASK_ADV7511_EDID_RDY_INT;
+
+	/*
+	 * This i2c write can fail (approx. 1 in 1000 writes). But it
+	 * is essential that this register is correct, so retry it
+	 * multiple times.
+	 *
+	 * Note that the i2c write does not report an error, but the readback
+	 * clearly shows the wrong value.
+	 */
+	do {
+		adv7511_wr(sd, 0x94, irqs);
+		irqs_rd = adv7511_rd(sd, 0x94);
+	} while (retries-- && irqs_rd != irqs);
+
+	if (irqs_rd == irqs)
+		return;
+	v4l2_err(sd, "Could not set interrupts: hw failure?\n");
+}
+
+/* Interrupt handler */
+static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
+{
+	u8 irq_status;
+
+	/* disable interrupts to prevent a race condition */
+	adv7511_set_isr(sd, false);
+	irq_status = adv7511_rd(sd, 0x96);
+	/* clear detected interrupts */
+	adv7511_wr(sd, 0x96, irq_status);
+
+	v4l2_dbg(1, debug, sd, "%s: irq 0x%x\n", __func__, irq_status);
+
+	if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT))
+		adv7511_check_monitor_present_status(sd);
+	if (irq_status & MASK_ADV7511_EDID_RDY_INT)
+		adv7511_check_edid_status(sd);
+
+	/* enable interrupts */
+	adv7511_set_isr(sd, true);
+
+	if (handled)
+		*handled = true;
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops adv7511_core_ops = {
+	.log_status = adv7511_log_status,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = adv7511_g_register,
+	.s_register = adv7511_s_register,
+#endif
+	.s_power = adv7511_s_power,
+	.interrupt_service_routine = adv7511_isr,
+};
+
+/* ------------------------------ VIDEO OPS ------------------------------ */
+
+/* Enable/disable adv7511 output */
+static int adv7511_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
+	adv7511_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c));
+	if (enable) {
+		adv7511_check_monitor_present_status(sd);
+	} else {
+		adv7511_s_power(sd, 0);
+		state->have_monitor = false;
+	}
+	return 0;
+}
+
+static int adv7511_s_dv_timings(struct v4l2_subdev *sd,
+			       struct v4l2_dv_timings *timings)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+	/* quick sanity check */
+	if (!v4l2_valid_dv_timings(timings, &adv7511_timings_cap, NULL, NULL))
+		return -EINVAL;
+
+	/* Fill the optional fields .standards and .flags in struct v4l2_dv_timings
+	   if the format is one of the CEA or DMT timings. */
+	v4l2_find_dv_timings_cap(timings, &adv7511_timings_cap, 0, NULL, NULL);
+
+	timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS;
+
+	/* save timings */
+	state->dv_timings = *timings;
+
+	/* update quantization range based on new dv_timings */
+	adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl);
+
+	/* update AVI infoframe */
+	adv7511_set_IT_content_AVI_InfoFrame(sd);
+
+	return 0;
+}
+
+static int adv7511_g_dv_timings(struct v4l2_subdev *sd,
+				struct v4l2_dv_timings *timings)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+	if (!timings)
+		return -EINVAL;
+
+	*timings = state->dv_timings;
+
+	return 0;
+}
+
+static int adv7511_enum_dv_timings(struct v4l2_subdev *sd,
+				   struct v4l2_enum_dv_timings *timings)
+{
+	if (timings->pad != 0)
+		return -EINVAL;
+
+	return v4l2_enum_dv_timings_cap(timings, &adv7511_timings_cap, NULL, NULL);
+}
+
+static int adv7511_dv_timings_cap(struct v4l2_subdev *sd,
+				  struct v4l2_dv_timings_cap *cap)
+{
+	if (cap->pad != 0)
+		return -EINVAL;
+
+	*cap = adv7511_timings_cap;
+	return 0;
+}
+
+static const struct v4l2_subdev_video_ops adv7511_video_ops = {
+	.s_stream = adv7511_s_stream,
+	.s_dv_timings = adv7511_s_dv_timings,
+	.g_dv_timings = adv7511_g_dv_timings,
+};
+
+/* ------------------------------ AUDIO OPS ------------------------------ */
+static int adv7511_s_audio_stream(struct v4l2_subdev *sd, int enable)
+{
+	v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
+
+	if (enable)
+		adv7511_wr_and_or(sd, 0x4b, 0x3f, 0x80);
+	else
+		adv7511_wr_and_or(sd, 0x4b, 0x3f, 0x40);
+
+	return 0;
+}
+
+static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+	u32 N;
+
+	switch (freq) {
+	case 32000:  N = 4096;  break;
+	case 44100:  N = 6272;  break;
+	case 48000:  N = 6144;  break;
+	case 88200:  N = 12544; break;
+	case 96000:  N = 12288; break;
+	case 176400: N = 25088; break;
+	case 192000: N = 24576; break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set N (used with CTS to regenerate the audio clock) */
+	adv7511_wr(sd, 0x01, (N >> 16) & 0xf);
+	adv7511_wr(sd, 0x02, (N >> 8) & 0xff);
+	adv7511_wr(sd, 0x03, N & 0xff);
+
+	return 0;
+}
+
+static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+	u32 i2s_sf;
+
+	switch (freq) {
+	case 32000:  i2s_sf = 0x30; break;
+	case 44100:  i2s_sf = 0x00; break;
+	case 48000:  i2s_sf = 0x20; break;
+	case 88200:  i2s_sf = 0x80; break;
+	case 96000:  i2s_sf = 0xa0; break;
+	case 176400: i2s_sf = 0xc0; break;
+	case 192000: i2s_sf = 0xe0; break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set sampling frequency for I2S audio to 48 kHz */
+	adv7511_wr_and_or(sd, 0x15, 0xf, i2s_sf);
+
+	return 0;
+}
+
+static int adv7511_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config)
+{
+	/* Only 2 channels in use for application */
+	adv7511_wr_and_or(sd, 0x73, 0xf8, 0x1);
+	/* Speaker mapping */
+	adv7511_wr(sd, 0x76, 0x00);
+
+	/* 16 bit audio word length */
+	adv7511_wr_and_or(sd, 0x14, 0xf0, 0x02);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_audio_ops adv7511_audio_ops = {
+	.s_stream = adv7511_s_audio_stream,
+	.s_clock_freq = adv7511_s_clock_freq,
+	.s_i2s_clock_freq = adv7511_s_i2s_clock_freq,
+	.s_routing = adv7511_s_routing,
+};
+
+/* ---------------------------- PAD OPS ------------------------------------- */
+
+static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	memset(edid->reserved, 0, sizeof(edid->reserved));
+
+	if (edid->pad != 0)
+		return -EINVAL;
+
+	if (edid->start_block == 0 && edid->blocks == 0) {
+		edid->blocks = state->edid.segments * 2;
+		return 0;
+	}
+
+	if (state->edid.segments == 0)
+		return -ENODATA;
+
+	if (edid->start_block >= state->edid.segments * 2)
+		return -EINVAL;
+
+	if (edid->start_block + edid->blocks > state->edid.segments * 2)
+		edid->blocks = state->edid.segments * 2 - edid->start_block;
+
+	memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
+			128 * edid->blocks);
+
+	return 0;
+}
+
+static int adv7511_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad != 0)
+		return -EINVAL;
+
+	switch (code->index) {
+	case 0:
+		code->code = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+	case 1:
+		code->code = MEDIA_BUS_FMT_YUYV8_1X16;
+		break;
+	case 2:
+		code->code = MEDIA_BUS_FMT_UYVY8_1X16;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void adv7511_fill_format(struct adv7511_state *state,
+				struct v4l2_mbus_framefmt *format)
+{
+	memset(format, 0, sizeof(*format));
+
+	format->width = state->dv_timings.bt.width;
+	format->height = state->dv_timings.bt.height;
+	format->field = V4L2_FIELD_NONE;
+}
+
+static int adv7511_get_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_pad_config *cfg,
+			   struct v4l2_subdev_format *format)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	if (format->pad != 0)
+		return -EINVAL;
+
+	adv7511_fill_format(state, &format->format);
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		struct v4l2_mbus_framefmt *fmt;
+
+		fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+		format->format.code = fmt->code;
+		format->format.colorspace = fmt->colorspace;
+		format->format.ycbcr_enc = fmt->ycbcr_enc;
+		format->format.quantization = fmt->quantization;
+		format->format.xfer_func = fmt->xfer_func;
+	} else {
+		format->format.code = state->fmt_code;
+		format->format.colorspace = state->colorspace;
+		format->format.ycbcr_enc = state->ycbcr_enc;
+		format->format.quantization = state->quantization;
+		format->format.xfer_func = state->xfer_func;
+	}
+
+	return 0;
+}
+
+static int adv7511_set_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_pad_config *cfg,
+			   struct v4l2_subdev_format *format)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	/*
+	 * Bitfield namings come the CEA-861-F standard, table 8 "Auxiliary
+	 * Video Information (AVI) InfoFrame Format"
+	 *
+	 * c = Colorimetry
+	 * ec = Extended Colorimetry
+	 * y = RGB or YCbCr
+	 * q = RGB Quantization Range
+	 * yq = YCC Quantization Range
+	 */
+	u8 c = HDMI_COLORIMETRY_NONE;
+	u8 ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+	u8 y = HDMI_COLORSPACE_RGB;
+	u8 q = HDMI_QUANTIZATION_RANGE_DEFAULT;
+	u8 yq = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+
+	if (format->pad != 0)
+		return -EINVAL;
+	switch (format->format.code) {
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+	case MEDIA_BUS_FMT_YUYV8_1X16:
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	adv7511_fill_format(state, &format->format);
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		struct v4l2_mbus_framefmt *fmt;
+
+		fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+		fmt->code = format->format.code;
+		fmt->colorspace = format->format.colorspace;
+		fmt->ycbcr_enc = format->format.ycbcr_enc;
+		fmt->quantization = format->format.quantization;
+		fmt->xfer_func = format->format.xfer_func;
+		return 0;
+	}
+
+	switch (format->format.code) {
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+		adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01);
+		adv7511_wr_and_or(sd, 0x16, 0x03, 0xb8);
+		y = HDMI_COLORSPACE_YUV422;
+		break;
+	case MEDIA_BUS_FMT_YUYV8_1X16:
+		adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01);
+		adv7511_wr_and_or(sd, 0x16, 0x03, 0xbc);
+		y = HDMI_COLORSPACE_YUV422;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	default:
+		adv7511_wr_and_or(sd, 0x15, 0xf0, 0x00);
+		adv7511_wr_and_or(sd, 0x16, 0x03, 0x00);
+		break;
+	}
+	state->fmt_code = format->format.code;
+	state->colorspace = format->format.colorspace;
+	state->ycbcr_enc = format->format.ycbcr_enc;
+	state->quantization = format->format.quantization;
+	state->xfer_func = format->format.xfer_func;
+
+	switch (format->format.colorspace) {
+	case V4L2_COLORSPACE_ADOBERGB:
+		c = HDMI_COLORIMETRY_EXTENDED;
+		ec = y ? HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601 :
+			 HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB;
+		break;
+	case V4L2_COLORSPACE_SMPTE170M:
+		c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE;
+		if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV601) {
+			c = HDMI_COLORIMETRY_EXTENDED;
+			ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+		}
+		break;
+	case V4L2_COLORSPACE_REC709:
+		c = y ? HDMI_COLORIMETRY_ITU_709 : HDMI_COLORIMETRY_NONE;
+		if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
+			c = HDMI_COLORIMETRY_EXTENDED;
+			ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
+		}
+		break;
+	case V4L2_COLORSPACE_SRGB:
+		c = y ? HDMI_COLORIMETRY_EXTENDED : HDMI_COLORIMETRY_NONE;
+		ec = y ? HDMI_EXTENDED_COLORIMETRY_S_YCC_601 :
+			 HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+		break;
+	case V4L2_COLORSPACE_BT2020:
+		c = HDMI_COLORIMETRY_EXTENDED;
+		if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM)
+			ec = 5; /* Not yet available in hdmi.h */
+		else
+			ec = 6; /* Not yet available in hdmi.h */
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * CEA-861-F says that for RGB formats the YCC range must match the
+	 * RGB range, although sources should ignore the YCC range.
+	 *
+	 * The RGB quantization range shouldn't be non-zero if the EDID doesn't
+	 * have the Q bit set in the Video Capabilities Data Block, however this
+	 * isn't checked at the moment. The assumption is that the application
+	 * knows the EDID and can detect this.
+	 *
+	 * The same is true for the YCC quantization range: non-standard YCC
+	 * quantization ranges should only be sent if the EDID has the YQ bit
+	 * set in the Video Capabilities Data Block.
+	 */
+	switch (format->format.quantization) {
+	case V4L2_QUANTIZATION_FULL_RANGE:
+		q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT :
+			HDMI_QUANTIZATION_RANGE_FULL;
+		yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_FULL;
+		break;
+	case V4L2_QUANTIZATION_LIM_RANGE:
+		q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT :
+			HDMI_QUANTIZATION_RANGE_LIMITED;
+		yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+		break;
+	}
+
+	adv7511_wr_and_or(sd, 0x4a, 0xbf, 0);
+	adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5);
+	adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6);
+	adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2));
+	adv7511_wr_and_or(sd, 0x59, 0x0f, yq << 4);
+	adv7511_wr_and_or(sd, 0x4a, 0xff, 1);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops adv7511_pad_ops = {
+	.get_edid = adv7511_get_edid,
+	.enum_mbus_code = adv7511_enum_mbus_code,
+	.get_fmt = adv7511_get_fmt,
+	.set_fmt = adv7511_set_fmt,
+	.enum_dv_timings = adv7511_enum_dv_timings,
+	.dv_timings_cap = adv7511_dv_timings_cap,
+};
+
+/* --------------------- SUBDEV OPS --------------------------------------- */
+
+static const struct v4l2_subdev_ops adv7511_ops = {
+	.core  = &adv7511_core_ops,
+	.pad  = &adv7511_pad_ops,
+	.video = &adv7511_video_ops,
+	.audio = &adv7511_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+static void adv7511_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, int segment, u8 *buf)
+{
+	if (debug >= lvl) {
+		int i, j;
+		v4l2_dbg(lvl, debug, sd, "edid segment %d\n", segment);
+		for (i = 0; i < 256; i += 16) {
+			u8 b[128];
+			u8 *bp = b;
+			if (i == 128)
+				v4l2_dbg(lvl, debug, sd, "\n");
+			for (j = i; j < i + 16; j++) {
+				sprintf(bp, "0x%02x, ", buf[j]);
+				bp += 6;
+			}
+			bp[0] = '\0';
+			v4l2_dbg(lvl, debug, sd, "%s\n", b);
+		}
+	}
+}
+
+static void adv7511_notify_no_edid(struct v4l2_subdev *sd)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	struct adv7511_edid_detect ed;
+
+	/* We failed to read the EDID, so send an event for this. */
+	ed.present = false;
+	ed.segment = adv7511_rd(sd, 0xc4);
+	v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
+	v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0);
+}
+
+static void adv7511_edid_handler(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct adv7511_state *state = container_of(dwork, struct adv7511_state, edid_handler);
+	struct v4l2_subdev *sd = &state->sd;
+
+	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+	if (adv7511_check_edid_status(sd)) {
+		/* Return if we received the EDID. */
+		return;
+	}
+
+	if (adv7511_have_hotplug(sd)) {
+		/* We must retry reading the EDID several times, it is possible
+		 * that initially the EDID couldn't be read due to i2c errors
+		 * (DVI connectors are particularly prone to this problem). */
+		if (state->edid.read_retries) {
+			state->edid.read_retries--;
+			v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__);
+			state->have_monitor = false;
+			adv7511_s_power(sd, false);
+			adv7511_s_power(sd, true);
+			queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY);
+			return;
+		}
+	}
+
+	/* We failed to read the EDID, so send an event for this. */
+	adv7511_notify_no_edid(sd);
+	v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__);
+}
+
+static void adv7511_audio_setup(struct v4l2_subdev *sd)
+{
+	v4l2_dbg(1, debug, sd, "%s\n", __func__);
+
+	adv7511_s_i2s_clock_freq(sd, 48000);
+	adv7511_s_clock_freq(sd, 48000);
+	adv7511_s_routing(sd, 0, 0, 0);
+}
+
+/* Configure hdmi transmitter. */
+static void adv7511_setup(struct v4l2_subdev *sd)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	v4l2_dbg(1, debug, sd, "%s\n", __func__);
+
+	/* Input format: RGB 4:4:4 */
+	adv7511_wr_and_or(sd, 0x15, 0xf0, 0x0);
+	/* Output format: RGB 4:4:4 */
+	adv7511_wr_and_or(sd, 0x16, 0x7f, 0x0);
+	/* 1st order interpolation 4:2:2 -> 4:4:4 up conversion, Aspect ratio: 16:9 */
+	adv7511_wr_and_or(sd, 0x17, 0xf9, 0x06);
+	/* Disable pixel repetition */
+	adv7511_wr_and_or(sd, 0x3b, 0x9f, 0x0);
+	/* Disable CSC */
+	adv7511_wr_and_or(sd, 0x18, 0x7f, 0x0);
+	/* Output format: RGB 4:4:4, Active Format Information is valid,
+	 * underscanned */
+	adv7511_wr_and_or(sd, 0x55, 0x9c, 0x12);
+	/* AVI Info frame packet enable, Audio Info frame disable */
+	adv7511_wr_and_or(sd, 0x44, 0xe7, 0x10);
+	/* Colorimetry, Active format aspect ratio: same as picure. */
+	adv7511_wr(sd, 0x56, 0xa8);
+	/* No encryption */
+	adv7511_wr_and_or(sd, 0xaf, 0xed, 0x0);
+
+	/* Positive clk edge capture for input video clock */
+	adv7511_wr_and_or(sd, 0xba, 0x1f, 0x60);
+
+	adv7511_audio_setup(sd);
+
+	v4l2_ctrl_handler_setup(&state->hdl);
+}
+
+static void adv7511_notify_monitor_detect(struct v4l2_subdev *sd)
+{
+	struct adv7511_monitor_detect mdt;
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	mdt.present = state->have_monitor;
+	v4l2_subdev_notify(sd, ADV7511_MONITOR_DETECT, (void *)&mdt);
+}
+
+static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	/* read hotplug and rx-sense state */
+	u8 status = adv7511_rd(sd, 0x42);
+
+	v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n",
+			 __func__,
+			 status,
+			 status & MASK_ADV7511_HPD_DETECT ? ", hotplug" : "",
+			 status & MASK_ADV7511_MSEN_DETECT ? ", rx-sense" : "");
+
+	/* update read only ctrls */
+	v4l2_ctrl_s_ctrl(state->hotplug_ctrl, adv7511_have_hotplug(sd) ? 0x1 : 0x0);
+	v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, adv7511_have_rx_sense(sd) ? 0x1 : 0x0);
+
+	if ((status & MASK_ADV7511_HPD_DETECT) && ((status & MASK_ADV7511_MSEN_DETECT) || state->edid.segments)) {
+		v4l2_dbg(1, debug, sd, "%s: hotplug and (rx-sense or edid)\n", __func__);
+		if (!state->have_monitor) {
+			v4l2_dbg(1, debug, sd, "%s: monitor detected\n", __func__);
+			state->have_monitor = true;
+			adv7511_set_isr(sd, true);
+			if (!adv7511_s_power(sd, true)) {
+				v4l2_dbg(1, debug, sd, "%s: monitor detected, powerup failed\n", __func__);
+				return;
+			}
+			adv7511_setup(sd);
+			adv7511_notify_monitor_detect(sd);
+			state->edid.read_retries = EDID_MAX_RETRIES;
+			queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY);
+		}
+	} else if (status & MASK_ADV7511_HPD_DETECT) {
+		v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__);
+		state->edid.read_retries = EDID_MAX_RETRIES;
+		queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY);
+	} else if (!(status & MASK_ADV7511_HPD_DETECT)) {
+		v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__);
+		if (state->have_monitor) {
+			v4l2_dbg(1, debug, sd, "%s: monitor not detected\n", __func__);
+			state->have_monitor = false;
+			adv7511_notify_monitor_detect(sd);
+		}
+		adv7511_s_power(sd, false);
+		memset(&state->edid, 0, sizeof(struct adv7511_state_edid));
+		adv7511_notify_no_edid(sd);
+	}
+}
+
+static bool edid_block_verify_crc(u8 *edid_block)
+{
+	u8 sum = 0;
+	int i;
+
+	for (i = 0; i < 128; i++)
+		sum += edid_block[i];
+	return sum == 0;
+}
+
+static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	u32 blocks = state->edid.blocks;
+	u8 *data = state->edid.data;
+
+	if (!edid_block_verify_crc(&data[segment * 256]))
+		return false;
+	if ((segment + 1) * 2 <= blocks)
+		return edid_block_verify_crc(&data[segment * 256 + 128]);
+	return true;
+}
+
+static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
+{
+	static const u8 hdmi_header[] = {
+		0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
+	};
+	struct adv7511_state *state = get_adv7511_state(sd);
+	u8 *data = state->edid.data;
+
+	if (segment != 0)
+		return true;
+	return !memcmp(data, hdmi_header, sizeof(hdmi_header));
+}
+
+static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	u8 edidRdy = adv7511_rd(sd, 0xc5);
+
+	v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n",
+			 __func__, EDID_MAX_RETRIES - state->edid.read_retries);
+
+	if (state->edid.complete)
+		return true;
+
+	if (edidRdy & MASK_ADV7511_EDID_RDY) {
+		int segment = adv7511_rd(sd, 0xc4);
+		struct adv7511_edid_detect ed;
+
+		if (segment >= EDID_MAX_SEGM) {
+			v4l2_err(sd, "edid segment number too big\n");
+			return false;
+		}
+		v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment);
+		adv7511_edid_rd(sd, 256, &state->edid.data[segment * 256]);
+		adv7511_dbg_dump_edid(2, debug, sd, segment, &state->edid.data[segment * 256]);
+		if (segment == 0) {
+			state->edid.blocks = state->edid.data[0x7e] + 1;
+			v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", __func__, state->edid.blocks);
+		}
+		if (!edid_verify_crc(sd, segment) ||
+		    !edid_verify_header(sd, segment)) {
+			/* edid crc error, force reread of edid segment */
+			v4l2_err(sd, "%s: edid crc or header error\n", __func__);
+			state->have_monitor = false;
+			adv7511_s_power(sd, false);
+			adv7511_s_power(sd, true);
+			return false;
+		}
+		/* one more segment read ok */
+		state->edid.segments = segment + 1;
+		v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x1);
+		if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) {
+			/* Request next EDID segment */
+			v4l2_dbg(1, debug, sd, "%s: request segment %d\n", __func__, state->edid.segments);
+			adv7511_wr(sd, 0xc9, 0xf);
+			adv7511_wr(sd, 0xc4, state->edid.segments);
+			state->edid.read_retries = EDID_MAX_RETRIES;
+			queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY);
+			return false;
+		}
+
+		v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments);
+		state->edid.complete = true;
+
+		/* report when we have all segments
+		   but report only for segment 0
+		 */
+		ed.present = true;
+		ed.segment = 0;
+		state->edid_detect_counter++;
+		v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
+		return ed.present;
+	}
+
+	return false;
+}
+
+/* ----------------------------------------------------------------------- */
+/* Setup ADV7511 */
+static void adv7511_init_setup(struct v4l2_subdev *sd)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	struct adv7511_state_edid *edid = &state->edid;
+
+	v4l2_dbg(1, debug, sd, "%s\n", __func__);
+
+	/* clear all interrupts */
+	adv7511_wr(sd, 0x96, 0xff);
+	/*
+	 * Stop HPD from resetting a lot of registers.
+	 * It might leave the chip in a partly un-initialized state,
+	 * in particular with regards to hotplug bounces.
+	 */
+	adv7511_wr_and_or(sd, 0xd6, 0x3f, 0xc0);
+	memset(edid, 0, sizeof(struct adv7511_state_edid));
+	state->have_monitor = false;
+	adv7511_set_isr(sd, false);
+	adv7511_s_stream(sd, false);
+	adv7511_s_audio_stream(sd, false);
+}
+
+static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct adv7511_state *state;
+	struct adv7511_platform_data *pdata = client->dev.platform_data;
+	struct v4l2_ctrl_handler *hdl;
+	struct v4l2_subdev *sd;
+	u8 chip_id[2];
+	int err = -EIO;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	state = devm_kzalloc(&client->dev, sizeof(struct adv7511_state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	/* Platform data */
+	if (!pdata) {
+		v4l_err(client, "No platform data!\n");
+		return -ENODEV;
+	}
+	memcpy(&state->pdata, pdata, sizeof(state->pdata));
+	state->fmt_code = MEDIA_BUS_FMT_RGB888_1X24;
+	state->colorspace = V4L2_COLORSPACE_SRGB;
+
+	sd = &state->sd;
+
+	v4l2_dbg(1, debug, sd, "detecting adv7511 client on address 0x%x\n",
+			 client->addr << 1);
+
+	v4l2_i2c_subdev_init(sd, client, &adv7511_ops);
+
+	hdl = &state->hdl;
+	v4l2_ctrl_handler_init(hdl, 10);
+	/* add in ascending ID order */
+	state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops,
+			V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
+			0, V4L2_DV_TX_MODE_DVI_D);
+	state->hotplug_ctrl = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_DV_TX_HOTPLUG, 0, 1, 0, 0);
+	state->rx_sense_ctrl = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_DV_TX_RXSENSE, 0, 1, 0, 0);
+	state->have_edid0_ctrl = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_DV_TX_EDID_PRESENT, 0, 1, 0, 0);
+	state->rgb_quantization_range_ctrl =
+		v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops,
+			V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
+			0, V4L2_DV_RGB_RANGE_AUTO);
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		err = hdl->error;
+		goto err_hdl;
+	}
+	state->hdmi_mode_ctrl->is_private = true;
+	state->hotplug_ctrl->is_private = true;
+	state->rx_sense_ctrl->is_private = true;
+	state->have_edid0_ctrl->is_private = true;
+	state->rgb_quantization_range_ctrl->is_private = true;
+
+	state->pad.flags = MEDIA_PAD_FL_SINK;
+	err = media_entity_init(&sd->entity, 1, &state->pad, 0);
+	if (err)
+		goto err_hdl;
+
+	/* EDID and CEC i2c addr */
+	state->i2c_edid_addr = state->pdata.i2c_edid << 1;
+	state->i2c_cec_addr = state->pdata.i2c_cec << 1;
+	state->i2c_pktmem_addr = state->pdata.i2c_pktmem << 1;
+
+	state->chip_revision = adv7511_rd(sd, 0x0);
+	chip_id[0] = adv7511_rd(sd, 0xf5);
+	chip_id[1] = adv7511_rd(sd, 0xf6);
+	if (chip_id[0] != 0x75 || chip_id[1] != 0x11) {
+		v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], chip_id[1]);
+		err = -EIO;
+		goto err_entity;
+	}
+
+	state->i2c_edid = i2c_new_dummy(client->adapter, state->i2c_edid_addr >> 1);
+	if (state->i2c_edid == NULL) {
+		v4l2_err(sd, "failed to register edid i2c client\n");
+		err = -ENOMEM;
+		goto err_entity;
+	}
+
+	state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1);
+	if (state->i2c_pktmem == NULL) {
+		v4l2_err(sd, "failed to register pktmem i2c client\n");
+		err = -ENOMEM;
+		goto err_unreg_edid;
+	}
+
+	adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */
+	state->work_queue = create_singlethread_workqueue(sd->name);
+	if (state->work_queue == NULL) {
+		v4l2_err(sd, "could not create workqueue\n");
+		err = -ENOMEM;
+		goto err_unreg_pktmem;
+	}
+
+	INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler);
+
+	adv7511_init_setup(sd);
+	adv7511_set_isr(sd, true);
+	adv7511_check_monitor_present_status(sd);
+
+	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
+			  client->addr << 1, client->adapter->name);
+	return 0;
+
+err_unreg_pktmem:
+	i2c_unregister_device(state->i2c_pktmem);
+err_unreg_edid:
+	i2c_unregister_device(state->i2c_edid);
+err_entity:
+	media_entity_cleanup(&sd->entity);
+err_hdl:
+	v4l2_ctrl_handler_free(&state->hdl);
+	return err;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int adv7511_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	state->chip_revision = -1;
+
+	v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,
+		 client->addr << 1, client->adapter->name);
+
+	adv7511_init_setup(sd);
+	cancel_delayed_work(&state->edid_handler);
+	i2c_unregister_device(state->i2c_edid);
+	i2c_unregister_device(state->i2c_pktmem);
+	destroy_workqueue(state->work_queue);
+	v4l2_device_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_device_id adv7511_id[] = {
+	{ "adv7511", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adv7511_id);
+
+static struct i2c_driver adv7511_driver = {
+	.driver = {
+		.name = "adv7511",
+	},
+	.probe = adv7511_probe,
+	.remove = adv7511_remove,
+	.id_table = adv7511_id,
+};
+
+module_i2c_driver(adv7511_driver);
--- linux-4.4.0.orig/drivers/media/i2c/adv7604.c
+++ linux-4.4.0/drivers/media/i2c/adv7604.c
@@ -1960,10 +1960,9 @@
 	}
 
 	/* tx 5v detect */
-	tx_5v = io_read(sd, 0x70) & info->cable_det_mask;
+	tx_5v = irq_reg_0x70 & info->cable_det_mask;
 	if (tx_5v) {
 		v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v);
-		io_write(sd, 0x71, tx_5v);
 		adv76xx_s_detect_tx_5v_ctrl(sd);
 		if (handled)
 			*handled = true;
@@ -2857,6 +2856,9 @@
 	state->pdata.alt_data_sat = 1;
 	state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0;
 	state->pdata.bus_order = ADV7604_BUS_ORDER_RGB;
+	state->pdata.dr_str_data = ADV76XX_DR_STR_MEDIUM_HIGH;
+	state->pdata.dr_str_clk = ADV76XX_DR_STR_MEDIUM_HIGH;
+	state->pdata.dr_str_sync = ADV76XX_DR_STR_MEDIUM_HIGH;
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/media/i2c/cx25840/cx25840-core.c
+++ linux-4.4.0/drivers/media/i2c/cx25840/cx25840-core.c
@@ -420,11 +420,13 @@
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
-	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
-	queue_work(q, &state->fw_work);
-	schedule();
-	finish_wait(&state->fw_wait, &wait);
-	destroy_workqueue(q);
+	if (q) {
+		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+		queue_work(q, &state->fw_work);
+		schedule();
+		finish_wait(&state->fw_wait, &wait);
+		destroy_workqueue(q);
+	}
 
 	/* 6. */
 	cx25840_write(client, 0x115, 0x8c);
@@ -465,8 +467,13 @@
 {
 	DEFINE_WAIT(wait);
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	u32 clk_freq = 0;
 	struct workqueue_struct *q;
 
+	/* cx23885 sets hostdata to clk_freq pointer */
+	if (v4l2_get_subdev_hostdata(&state->sd))
+		clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd));
+
 	/*
 	 * Come out of digital power down
 	 * The CX23888, at least, needs this, otherwise registers aside from
@@ -502,8 +509,13 @@
 		 * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
 		 * 572.73 MHz before post divide
 		 */
-		/* HVR1850 or 50MHz xtal */
-		cx25840_write(client, 0x2, 0x71);
+		if (clk_freq == 25000000) {
+			/* 888/ImpactVCBe or 25Mhz xtal */
+			; /* nothing to do */
+		} else {
+			/* HVR1850 or 50MHz xtal */
+			cx25840_write(client, 0x2, 0x71);
+		}
 		cx25840_write4(client, 0x11c, 0x01d1744c);
 		cx25840_write4(client, 0x118, 0x00000416);
 		cx25840_write4(client, 0x404, 0x0010253e);
@@ -546,9 +558,15 @@
 	/* HVR1850 */
 	switch (state->id) {
 	case CX23888_AV:
-		/* 888/HVR1250 specific */
-		cx25840_write4(client, 0x10c, 0x13333333);
-		cx25840_write4(client, 0x108, 0x00000515);
+		if (clk_freq == 25000000) {
+			/* 888/ImpactVCBe or 25MHz xtal */
+			cx25840_write4(client, 0x10c, 0x01b6db7b);
+			cx25840_write4(client, 0x108, 0x00000512);
+		} else {
+			/* 888/HVR1250 or 50MHz xtal */
+			cx25840_write4(client, 0x10c, 0x13333333);
+			cx25840_write4(client, 0x108, 0x00000515);
+		}
 		break;
 	default:
 		cx25840_write4(client, 0x10c, 0x002be2c9);
@@ -575,7 +593,7 @@
 		 * 368.64 MHz before post divide
 		 * 122.88 MHz / 0xa = 12.288 MHz
 		 */
-		/* HVR1850  or 50MHz xtal */
+		/* HVR1850 or 50MHz xtal or 25MHz xtal */
 		cx25840_write4(client, 0x114, 0x017dbf48);
 		cx25840_write4(client, 0x110, 0x000a030e);
 		break;
@@ -631,11 +649,13 @@
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
-	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
-	queue_work(q, &state->fw_work);
-	schedule();
-	finish_wait(&state->fw_wait, &wait);
-	destroy_workqueue(q);
+	if (q) {
+		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+		queue_work(q, &state->fw_work);
+		schedule();
+		finish_wait(&state->fw_wait, &wait);
+		destroy_workqueue(q);
+	}
 
 	/* Call the cx23888 specific std setup func, we no longer rely on
 	 * the generic cx24840 func.
@@ -746,11 +766,13 @@
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
-	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
-	queue_work(q, &state->fw_work);
-	schedule();
-	finish_wait(&state->fw_wait, &wait);
-	destroy_workqueue(q);
+	if (q) {
+		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+		queue_work(q, &state->fw_work);
+		schedule();
+		finish_wait(&state->fw_wait, &wait);
+		destroy_workqueue(q);
+	}
 
 	cx25840_std_setup(client);
 
--- linux-4.4.0.orig/drivers/media/i2c/ir-kbd-i2c.c
+++ linux-4.4.0/drivers/media/i2c/ir-kbd-i2c.c
@@ -478,7 +478,6 @@
 	{ "ir_rx_z8f0811_hdpvr", 0 },
 	{ }
 };
-MODULE_DEVICE_TABLE(i2c, ir_kbd_id);
 
 static struct i2c_driver ir_kbd_driver = {
 	.driver = {
--- linux-4.4.0.orig/drivers/media/i2c/m5mols/m5mols_core.c
+++ linux-4.4.0/drivers/media/i2c/m5mols/m5mols_core.c
@@ -754,7 +754,8 @@
 
 		ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
 		if (ret) {
-			info->set_power(&client->dev, 0);
+			if (info->set_power)
+				info->set_power(&client->dev, 0);
 			return ret;
 		}
 
--- linux-4.4.0.orig/drivers/media/i2c/mt9v032.c
+++ linux-4.4.0/drivers/media/i2c/mt9v032.c
@@ -454,10 +454,12 @@
 				  struct v4l2_subdev_pad_config *cfg,
 				  struct v4l2_subdev_mbus_code_enum *code)
 {
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
 	if (code->index > 0)
 		return -EINVAL;
 
-	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+	code->code = mt9v032->format.code;
 	return 0;
 }
 
@@ -465,7 +467,11 @@
 				   struct v4l2_subdev_pad_config *cfg,
 				   struct v4l2_subdev_frame_size_enum *fse)
 {
-	if (fse->index >= 3 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+	if (fse->index >= 3)
+		return -EINVAL;
+	if (mt9v032->format.code != fse->code)
 		return -EINVAL;
 
 	fse->min_width = MT9V032_WINDOW_WIDTH_DEF / (1 << fse->index);
--- linux-4.4.0.orig/drivers/media/i2c/ov2659.c
+++ linux-4.4.0/drivers/media/i2c/ov2659.c
@@ -419,10 +419,14 @@
 	{ REG_TIMING_YINC, 0x11 },
 	{ REG_TIMING_VERT_FORMAT, 0x80 },
 	{ REG_TIMING_HORIZ_FORMAT, 0x00 },
+	{ 0x370a, 0x12 },
 	{ 0x3a03, 0xe8 },
 	{ 0x3a09, 0x6f },
 	{ 0x3a0b, 0x5d },
 	{ 0x3a15, 0x9a },
+	{ REG_VFIFO_READ_START_H, 0x00 },
+	{ REG_VFIFO_READ_START_L, 0x80 },
+	{ REG_ISP_CTRL02, 0x00 },
 	{ REG_NULL, 0x00 },
 };
 
@@ -1117,8 +1121,10 @@
 		if (ov2659_formats[index].code == mf->code)
 			break;
 
-	if (index < 0)
-		return -EINVAL;
+	if (index < 0) {
+		index = 0;
+		mf->code = ov2659_formats[index].code;
+	}
 
 	mf->colorspace = V4L2_COLORSPACE_SRGB;
 	mf->code = ov2659_formats[index].code;
@@ -1131,7 +1137,7 @@
 		mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
 		*mf = fmt->format;
 #else
-		return -ENOTTY;
+		ret = -ENOTTY;
 #endif
 	} else {
 		s64 val;
@@ -1202,11 +1208,15 @@
 		goto unlock;
 	}
 
-	ov2659_set_pixel_clock(ov2659);
-	ov2659_set_frame_size(ov2659);
-	ov2659_set_format(ov2659);
-	ov2659_set_streaming(ov2659, 1);
-	ov2659->streaming = on;
+	ret = ov2659_set_pixel_clock(ov2659);
+	if (!ret)
+		ret = ov2659_set_frame_size(ov2659);
+	if (!ret)
+		ret = ov2659_set_format(ov2659);
+	if (!ret) {
+		ov2659_set_streaming(ov2659, 1);
+		ov2659->streaming = on;
+	}
 
 unlock:
 	mutex_unlock(&ov2659->lock);
--- linux-4.4.0.orig/drivers/media/i2c/ov7670.c
+++ linux-4.4.0/drivers/media/i2c/ov7670.c
@@ -155,10 +155,10 @@
 #define REG_GFIX	0x69	/* Fix gain control */
 
 #define REG_DBLV	0x6b	/* PLL control an debugging */
-#define   DBLV_BYPASS	  0x00	  /* Bypass PLL */
-#define   DBLV_X4	  0x01	  /* clock x4 */
-#define   DBLV_X6	  0x10	  /* clock x6 */
-#define   DBLV_X8	  0x11	  /* clock x8 */
+#define   DBLV_BYPASS	  0x0a	  /* Bypass PLL */
+#define   DBLV_X4	  0x4a	  /* clock x4 */
+#define   DBLV_X6	  0x8a	  /* clock x6 */
+#define   DBLV_X8	  0xca	  /* clock x8 */
 
 #define REG_REG76	0x76	/* OV's name */
 #define   R76_BLKPCOR	  0x80	  /* Black pixel correction enable */
@@ -833,7 +833,7 @@
 	if (ret < 0)
 		return ret;
 
-	return ov7670_write(sd, REG_DBLV, DBLV_X4);
+	return 0;
 }
 
 static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd,
@@ -1578,11 +1578,7 @@
 		if (config->clock_speed)
 			info->clock_speed = config->clock_speed;
 
-		/*
-		 * It should be allowed for ov7670 too when it is migrated to
-		 * the new frame rate formula.
-		 */
-		if (config->pll_bypass && id->driver_data != MODEL_OV7670)
+		if (config->pll_bypass)
 			info->pll_bypass = true;
 
 		if (config->pclk_hb_disable)
--- linux-4.4.0.orig/drivers/media/i2c/ov9650.c
+++ linux-4.4.0/drivers/media/i2c/ov9650.c
@@ -707,6 +707,11 @@
 		for (m = 6; m >= 0; m--)
 			if (gain >= (1 << m) * 16)
 				break;
+
+		/* Sanity check: don't adjust the gain with a negative value */
+		if (m < 0)
+			return -EINVAL;
+
 		rgain = (gain - ((1 << m) * 16)) / (1 << m);
 		rgain |= (((1 << m) - 1) << 4);
 
--- linux-4.4.0.orig/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
+++ linux-4.4.0/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -211,7 +211,7 @@
 	}
 
 	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
-		ret = s5c73m3_af_run(state, ~af_lock);
+		ret = s5c73m3_af_run(state, !af_lock);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/media/i2c/s5k6aa.c
+++ linux-4.4.0/drivers/media/i2c/s5k6aa.c
@@ -421,6 +421,7 @@
 
 /**
  * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
  *
  * Configure the internal ISP PLL for the required output frequency.
  * Locking: called with s5k6aa.lock mutex held.
@@ -669,6 +670,7 @@
 
 /**
  * s5k6aa_configure_video_bus - configure the video output interface
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
  * @bus_type: video bus type: parallel or MIPI-CSI
  * @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
  *
@@ -724,6 +726,8 @@
 
 /**
  * s5k6aa_set_prev_config - write user preview register set
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
+ * @preset: s5kaa preset to be applied
  *
  * Configure output resolution and color fromat, pixel clock
  * frequency range, device frame rate type and frame period range.
@@ -777,6 +781,7 @@
 
 /**
  * s5k6aa_initialize_isp - basic ISP MCU initialization
+ * @sd: pointer to V4L2 sub-device descriptor
  *
  * Configure AHB addresses for registers read/write; configure PLLs for
  * required output pixel clock. The ISP power supply needs to be already
--- linux-4.4.0.orig/drivers/media/i2c/smiapp/smiapp-core.c
+++ linux-4.4.0/drivers/media/i2c/smiapp/smiapp-core.c
@@ -981,7 +981,7 @@
 		if (rval)
 			goto out;
 
-		for (i = 0; i < 1000; i++) {
+		for (i = 1000; i > 0; i--) {
 			rval = smiapp_read(
 				sensor,
 				SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
@@ -992,11 +992,10 @@
 			if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
 				break;
 
-			if (--i == 0) {
-				rval = -ETIMEDOUT;
-				goto out;
-			}
-
+		}
+		if (!i) {
+			rval = -ETIMEDOUT;
+			goto out;
 		}
 
 		for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {
--- linux-4.4.0.orig/drivers/media/i2c/soc_camera/mt9m111.c
+++ linux-4.4.0/drivers/media/i2c/soc_camera/mt9m111.c
@@ -988,6 +988,8 @@
 	mt9m111->rect.top	= MT9M111_MIN_DARK_ROWS;
 	mt9m111->rect.width	= MT9M111_MAX_WIDTH;
 	mt9m111->rect.height	= MT9M111_MAX_HEIGHT;
+	mt9m111->width		= mt9m111->rect.width;
+	mt9m111->height		= mt9m111->rect.height;
 	mt9m111->fmt		= &mt9m111_colour_fmts[0];
 	mt9m111->lastpage	= -1;
 	mutex_init(&mt9m111->power_lock);
--- linux-4.4.0.orig/drivers/media/i2c/soc_camera/ov6650.c
+++ linux-4.4.0/drivers/media/i2c/soc_camera/ov6650.c
@@ -203,7 +203,6 @@
 	unsigned long		pclk_max;	/* from resolution and format */
 	struct v4l2_fract	tpf;		/* as requested with s_parm */
 	u32 code;
-	enum v4l2_colorspace	colorspace;
 };
 
 
@@ -216,6 +215,17 @@
 	MEDIA_BUS_FMT_Y8_1X8,
 };
 
+static const struct v4l2_mbus_framefmt ov6650_def_fmt = {
+	.width		= W_CIF,
+	.height		= H_CIF,
+	.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
+	.colorspace	= V4L2_COLORSPACE_SRGB,
+	.field		= V4L2_FIELD_NONE,
+	.ycbcr_enc	= V4L2_YCBCR_ENC_DEFAULT,
+	.quantization	= V4L2_QUANTIZATION_DEFAULT,
+	.xfer_func	= V4L2_XFER_FUNC_DEFAULT,
+};
+
 /* read a register */
 static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
 {
@@ -510,12 +520,20 @@
 	if (format->pad)
 		return -EINVAL;
 
-	mf->width	= priv->rect.width >> priv->half_scale;
-	mf->height	= priv->rect.height >> priv->half_scale;
-	mf->code	= priv->code;
-	mf->colorspace	= priv->colorspace;
-	mf->field	= V4L2_FIELD_NONE;
+	/* initialize response with default media bus frame format */
+	*mf = ov6650_def_fmt;
+
+	/* update media bus format code and frame size */
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf->width = cfg->try_fmt.width;
+		mf->height = cfg->try_fmt.height;
+		mf->code = cfg->try_fmt.code;
 
+	} else {
+		mf->width = priv->rect.width >> priv->half_scale;
+		mf->height = priv->rect.height >> priv->half_scale;
+		mf->code = priv->code;
+	}
 	return 0;
 }
 
@@ -611,7 +629,6 @@
 		dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
 		return -EINVAL;
 	}
-	priv->code = code;
 
 	if (code == MEDIA_BUS_FMT_Y8_1X8 ||
 			code == MEDIA_BUS_FMT_SBGGR8_1X8) {
@@ -624,11 +641,6 @@
 		priv->pclk_max = 8000000;
 	}
 
-	if (code == MEDIA_BUS_FMT_SBGGR8_1X8)
-		priv->colorspace = V4L2_COLORSPACE_SRGB;
-	else if (code != 0)
-		priv->colorspace = V4L2_COLORSPACE_JPEG;
-
 	if (half_scale) {
 		dev_dbg(&client->dev, "max resolution: QCIF\n");
 		coma_set |= COMA_QCIF;
@@ -637,7 +649,6 @@
 		dev_dbg(&client->dev, "max resolution: CIF\n");
 		coma_mask |= COMA_QCIF;
 	}
-	priv->half_scale = half_scale;
 
 	if (sense) {
 		if (sense->master_clock == 8000000) {
@@ -677,14 +688,14 @@
 		ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
 	if (!ret)
 		ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
-	if (!ret)
-		ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
-
 	if (!ret) {
-		mf->colorspace	= priv->colorspace;
-		mf->width = priv->rect.width >> half_scale;
-		mf->height = priv->rect.height >> half_scale;
+		priv->half_scale = half_scale;
+
+		ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
 	}
+	if (!ret)
+		priv->code = code;
+
 	return ret;
 }
 
@@ -703,8 +714,6 @@
 		v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
 				&mf->height, 2, H_CIF, 1, 0);
 
-	mf->field = V4L2_FIELD_NONE;
-
 	switch (mf->code) {
 	case MEDIA_BUS_FMT_Y10_1X10:
 		mf->code = MEDIA_BUS_FMT_Y8_1X8;
@@ -713,19 +722,38 @@
 	case MEDIA_BUS_FMT_YUYV8_2X8:
 	case MEDIA_BUS_FMT_VYUY8_2X8:
 	case MEDIA_BUS_FMT_UYVY8_2X8:
-		mf->colorspace = V4L2_COLORSPACE_JPEG;
 		break;
 	default:
 		mf->code = MEDIA_BUS_FMT_SBGGR8_1X8;
 	case MEDIA_BUS_FMT_SBGGR8_1X8:
-		mf->colorspace = V4L2_COLORSPACE_SRGB;
 		break;
 	}
 
-	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-		return ov6650_s_fmt(sd, mf);
-	cfg->try_fmt = *mf;
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		/* store media bus format code and frame size in pad config */
+		cfg->try_fmt.width = mf->width;
+		cfg->try_fmt.height = mf->height;
+		cfg->try_fmt.code = mf->code;
+
+		/* return default mbus frame format updated with pad config */
+		*mf = ov6650_def_fmt;
+		mf->width = cfg->try_fmt.width;
+		mf->height = cfg->try_fmt.height;
+		mf->code = cfg->try_fmt.code;
+
+	} else {
+		/* apply new media bus format code and frame size */
+		int ret = ov6650_s_fmt(sd, mf);
+
+		if (ret)
+			return ret;
 
+		/* return default format updated with active size and code */
+		*mf = ov6650_def_fmt;
+		mf->width = priv->rect.width >> priv->half_scale;
+		mf->height = priv->rect.height >> priv->half_scale;
+		mf->code = priv->code;
+	}
 	return 0;
 }
 
@@ -839,9 +867,18 @@
 	u8		pidh, pidl, midh, midl;
 	int		ret;
 
+	priv->clk = v4l2_clk_get(&client->dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		ret = PTR_ERR(priv->clk);
+		dev_err(&client->dev, "v4l2_clk request err: %d\n", ret);
+		return ret;
+	}
+
 	ret = ov6650_s_power(&priv->subdev, 1);
 	if (ret < 0)
-		return ret;
+		goto eclkput;
+
+	msleep(20);
 
 	/*
 	 * check and show product ID and manufacturer ID
@@ -876,6 +913,11 @@
 
 done:
 	ov6650_s_power(&priv->subdev, 0);
+	if (!ret)
+		return 0;
+eclkput:
+	v4l2_clk_put(priv->clk);
+
 	return ret;
 }
 
@@ -1031,20 +1073,10 @@
 	priv->rect.height = H_CIF;
 	priv->half_scale  = false;
 	priv->code	  = MEDIA_BUS_FMT_YUYV8_2X8;
-	priv->colorspace  = V4L2_COLORSPACE_JPEG;
-
-	priv->clk = v4l2_clk_get(&client->dev, "mclk");
-	if (IS_ERR(priv->clk)) {
-		ret = PTR_ERR(priv->clk);
-		goto eclkget;
-	}
 
 	ret = ov6650_video_probe(client);
-	if (ret) {
-		v4l2_clk_put(priv->clk);
-eclkget:
+	if (ret)
 		v4l2_ctrl_handler_free(&priv->hdl);
-	}
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/media/i2c/soc_camera/ov772x.c
+++ linux-4.4.0/drivers/media/i2c/soc_camera/ov772x.c
@@ -834,7 +834,7 @@
 	 * set COM8
 	 */
 	if (priv->band_filter) {
-		ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
+		ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF);
 		if (!ret)
 			ret = ov772x_mask_set(client, BDBASE,
 					      0xff, 256 - priv->band_filter);
--- linux-4.4.0.orig/drivers/media/i2c/tc358743.c
+++ linux-4.4.0/drivers/media/i2c/tc358743.c
@@ -197,57 +197,61 @@
 	}
 }
 
-static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
+static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
 {
-	u8 val;
+	__le32 val = 0;
 
-	i2c_rd(sd, reg, &val, 1);
+	i2c_rd(sd, reg, (u8 __force *)&val, n);
 
-	return val;
+	return le32_to_cpu(val);
+}
+
+static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
+{
+	__le32 raw = cpu_to_le32(val);
+
+	i2c_wr(sd, reg, (u8 __force *)&raw, n);
+}
+
+static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
+{
+	return i2c_rdreg(sd, reg, 1);
 }
 
 static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val)
 {
-	i2c_wr(sd, reg, &val, 1);
+	i2c_wrreg(sd, reg, val, 1);
 }
 
 static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg,
 		u8 mask, u8 val)
 {
-	i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val);
+	i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 1) & mask) | val, 1);
 }
 
 static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg)
 {
-	u16 val;
-
-	i2c_rd(sd, reg, (u8 *)&val, 2);
-
-	return val;
+	return i2c_rdreg(sd, reg, 2);
 }
 
 static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
 {
-	i2c_wr(sd, reg, (u8 *)&val, 2);
+	i2c_wrreg(sd, reg, val, 2);
 }
 
 static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val)
 {
-	i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val);
+	i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2);
 }
 
 static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg)
 {
-	u32 val;
-
-	i2c_rd(sd, reg, (u8 *)&val, 4);
-
-	return val;
+	return i2c_rdreg(sd, reg, 4);
 }
 
 static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val)
 {
-	i2c_wr(sd, reg, (u8 *)&val, 4);
+	i2c_wrreg(sd, reg, val, 4);
 }
 
 /* --------------- STATUS --------------- */
@@ -1240,7 +1244,7 @@
 
 	reg->size = tc358743_get_reg_size(reg->reg);
 
-	i2c_rd(sd, reg->reg, (u8 *)&reg->val, reg->size);
+	reg->val = i2c_rdreg(sd, reg->reg, reg->size);
 
 	return 0;
 }
@@ -1266,7 +1270,7 @@
 	    reg->reg == BCAPS)
 		return 0;
 
-	i2c_wr(sd, (u16)reg->reg, (u8 *)&reg->val,
+	i2c_wrreg(sd, (u16)reg->reg, reg->val,
 			tc358743_get_reg_size(reg->reg));
 
 	return 0;
@@ -1321,7 +1325,7 @@
 static irqreturn_t tc358743_irq_handler(int irq, void *dev_id)
 {
 	struct tc358743_state *state = dev_id;
-	bool handled;
+	bool handled = false;
 
 	tc358743_isr(&state->sd, 0, &handled);
 
--- linux-4.4.0.orig/drivers/media/i2c/tvp5150.c
+++ linux-4.4.0/drivers/media/i2c/tvp5150.c
@@ -870,9 +870,6 @@
 
 	/* tvp5150 has some special limits */
 	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
-	rect.width = clamp_t(unsigned int, rect.width,
-			     TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
-			     TVP5150_H_MAX - rect.left);
 	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
 
 	/* Calculate height based on current standard */
@@ -886,9 +883,16 @@
 	else
 		hmax = TVP5150_V_MAX_OTHERS;
 
-	rect.height = clamp_t(unsigned int, rect.height,
+	/*
+	 * alignments:
+	 *  - width = 2 due to UYVY colorspace
+	 *  - height, image = no special alignment
+	 */
+	v4l_bound_align_image(&rect.width,
+			      TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
+			      TVP5150_H_MAX - rect.left, 1, &rect.height,
 			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
-			      hmax - rect.top);
+			      hmax - rect.top, 0, 0);
 
 	tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
 	tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
--- linux-4.4.0.orig/drivers/media/media-device.c
+++ linux-4.4.0/drivers/media/media-device.c
@@ -24,6 +24,7 @@
 #include <linux/export.h>
 #include <linux/ioctl.h>
 #include <linux/media.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 
 #include <media/media-device.h>
@@ -234,7 +235,7 @@
 			       unsigned long arg)
 {
 	struct media_devnode *devnode = media_devnode_data(filp);
-	struct media_device *dev = to_media_device(devnode);
+	struct media_device *dev = devnode->media_dev;
 	long ret;
 
 	switch (cmd) {
@@ -303,7 +304,7 @@
 				      unsigned long arg)
 {
 	struct media_devnode *devnode = media_devnode_data(filp);
-	struct media_device *dev = to_media_device(devnode);
+	struct media_device *dev = devnode->media_dev;
 	long ret;
 
 	switch (cmd) {
@@ -344,7 +345,8 @@
 static ssize_t show_model(struct device *cd,
 			  struct device_attribute *attr, char *buf)
 {
-	struct media_device *mdev = to_media_device(to_media_devnode(cd));
+	struct media_devnode *devnode = to_media_devnode(cd);
+	struct media_device *mdev = devnode->media_dev;
 
 	return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
 }
@@ -372,6 +374,7 @@
 int __must_check __media_device_register(struct media_device *mdev,
 					 struct module *owner)
 {
+	struct media_devnode *devnode;
 	int ret;
 
 	if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
@@ -382,17 +385,28 @@
 	spin_lock_init(&mdev->lock);
 	mutex_init(&mdev->graph_mutex);
 
+	devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
+	if (!devnode)
+		return -ENOMEM;
+
 	/* Register the device node. */
-	mdev->devnode.fops = &media_device_fops;
-	mdev->devnode.parent = mdev->dev;
-	mdev->devnode.release = media_device_release;
-	ret = media_devnode_register(&mdev->devnode, owner);
-	if (ret < 0)
+	mdev->devnode = devnode;
+	devnode->fops = &media_device_fops;
+	devnode->parent = mdev->dev;
+	devnode->release = media_device_release;
+	ret = media_devnode_register(mdev, devnode, owner);
+	if (ret < 0) {
+		/* devnode free is handled in media_devnode_*() */
+		mdev->devnode = NULL;
 		return ret;
+	}
 
-	ret = device_create_file(&mdev->devnode.dev, &dev_attr_model);
+	ret = device_create_file(&devnode->dev, &dev_attr_model);
 	if (ret < 0) {
-		media_devnode_unregister(&mdev->devnode);
+		/* devnode free is handled in media_devnode_*() */
+		mdev->devnode = NULL;
+		media_devnode_unregister_prepare(devnode);
+		media_devnode_unregister(devnode);
 		return ret;
 	}
 
@@ -410,11 +424,16 @@
 	struct media_entity *entity;
 	struct media_entity *next;
 
+	/* Clear the devnode register bit to avoid races with media dev open */
+	media_devnode_unregister_prepare(mdev->devnode);
+
 	list_for_each_entry_safe(entity, next, &mdev->entities, list)
 		media_device_unregister_entity(entity);
 
-	device_remove_file(&mdev->devnode.dev, &dev_attr_model);
-	media_devnode_unregister(&mdev->devnode);
+	device_remove_file(&mdev->devnode->dev, &dev_attr_model);
+	media_devnode_unregister(mdev->devnode);
+	/* devnode free is handled in media_devnode_*() */
+	mdev->devnode = NULL;
 }
 EXPORT_SYMBOL_GPL(media_device_unregister);
 
--- linux-4.4.0.orig/drivers/media/media-devnode.c
+++ linux-4.4.0/drivers/media/media-devnode.c
@@ -44,6 +44,7 @@
 #include <linux/uaccess.h>
 
 #include <media/media-devnode.h>
+#include <media/media-device.h>
 
 #define MEDIA_NUM_DEVICES	256
 #define MEDIA_NAME		"media"
@@ -59,21 +60,19 @@
 /* Called when the last user of the media device exits. */
 static void media_devnode_release(struct device *cd)
 {
-	struct media_devnode *mdev = to_media_devnode(cd);
+	struct media_devnode *devnode = to_media_devnode(cd);
 
 	mutex_lock(&media_devnode_lock);
-
-	/* Delete the cdev on this minor as well */
-	cdev_del(&mdev->cdev);
-
 	/* Mark device node number as free */
-	clear_bit(mdev->minor, media_devnode_nums);
-
+	clear_bit(devnode->minor, media_devnode_nums);
 	mutex_unlock(&media_devnode_lock);
 
 	/* Release media_devnode and perform other cleanups as needed. */
-	if (mdev->release)
-		mdev->release(mdev);
+	if (devnode->release)
+		devnode->release(devnode);
+
+	kfree(devnode);
+	pr_debug("%s: Media Devnode Deallocated\n", __func__);
 }
 
 static struct bus_type media_bus_type = {
@@ -83,37 +82,37 @@
 static ssize_t media_read(struct file *filp, char __user *buf,
 		size_t sz, loff_t *off)
 {
-	struct media_devnode *mdev = media_devnode_data(filp);
+	struct media_devnode *devnode = media_devnode_data(filp);
 
-	if (!mdev->fops->read)
+	if (!devnode->fops->read)
 		return -EINVAL;
-	if (!media_devnode_is_registered(mdev))
+	if (!media_devnode_is_registered(devnode))
 		return -EIO;
-	return mdev->fops->read(filp, buf, sz, off);
+	return devnode->fops->read(filp, buf, sz, off);
 }
 
 static ssize_t media_write(struct file *filp, const char __user *buf,
 		size_t sz, loff_t *off)
 {
-	struct media_devnode *mdev = media_devnode_data(filp);
+	struct media_devnode *devnode = media_devnode_data(filp);
 
-	if (!mdev->fops->write)
+	if (!devnode->fops->write)
 		return -EINVAL;
-	if (!media_devnode_is_registered(mdev))
+	if (!media_devnode_is_registered(devnode))
 		return -EIO;
-	return mdev->fops->write(filp, buf, sz, off);
+	return devnode->fops->write(filp, buf, sz, off);
 }
 
 static unsigned int media_poll(struct file *filp,
 			       struct poll_table_struct *poll)
 {
-	struct media_devnode *mdev = media_devnode_data(filp);
+	struct media_devnode *devnode = media_devnode_data(filp);
 
-	if (!media_devnode_is_registered(mdev))
+	if (!media_devnode_is_registered(devnode))
 		return POLLERR | POLLHUP;
-	if (!mdev->fops->poll)
+	if (!devnode->fops->poll)
 		return DEFAULT_POLLMASK;
-	return mdev->fops->poll(filp, poll);
+	return devnode->fops->poll(filp, poll);
 }
 
 static long
@@ -121,12 +120,12 @@
 	      long (*ioctl_func)(struct file *filp, unsigned int cmd,
 				 unsigned long arg))
 {
-	struct media_devnode *mdev = media_devnode_data(filp);
+	struct media_devnode *devnode = media_devnode_data(filp);
 
 	if (!ioctl_func)
 		return -ENOTTY;
 
-	if (!media_devnode_is_registered(mdev))
+	if (!media_devnode_is_registered(devnode))
 		return -EIO;
 
 	return ioctl_func(filp, cmd, arg);
@@ -134,9 +133,9 @@
 
 static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-	struct media_devnode *mdev = media_devnode_data(filp);
+	struct media_devnode *devnode = media_devnode_data(filp);
 
-	return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl);
+	return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl);
 }
 
 #ifdef CONFIG_COMPAT
@@ -144,9 +143,9 @@
 static long media_compat_ioctl(struct file *filp, unsigned int cmd,
 			       unsigned long arg)
 {
-	struct media_devnode *mdev = media_devnode_data(filp);
+	struct media_devnode *devnode = media_devnode_data(filp);
 
-	return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl);
+	return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl);
 }
 
 #endif /* CONFIG_COMPAT */
@@ -154,7 +153,7 @@
 /* Override for the open function */
 static int media_open(struct inode *inode, struct file *filp)
 {
-	struct media_devnode *mdev;
+	struct media_devnode *devnode;
 	int ret;
 
 	/* Check if the media device is available. This needs to be done with
@@ -164,23 +163,24 @@
 	 * a crash.
 	 */
 	mutex_lock(&media_devnode_lock);
-	mdev = container_of(inode->i_cdev, struct media_devnode, cdev);
+	devnode = container_of(inode->i_cdev, struct media_devnode, cdev);
 	/* return ENXIO if the media device has been removed
 	   already or if it is not registered anymore. */
-	if (!media_devnode_is_registered(mdev)) {
+	if (!media_devnode_is_registered(devnode)) {
 		mutex_unlock(&media_devnode_lock);
 		return -ENXIO;
 	}
 	/* and increase the device refcount */
-	get_device(&mdev->dev);
+	get_device(&devnode->dev);
 	mutex_unlock(&media_devnode_lock);
 
-	filp->private_data = mdev;
+	filp->private_data = devnode;
 
-	if (mdev->fops->open) {
-		ret = mdev->fops->open(filp);
+	if (devnode->fops->open) {
+		ret = devnode->fops->open(filp);
 		if (ret) {
-			put_device(&mdev->dev);
+			put_device(&devnode->dev);
+			filp->private_data = NULL;
 			return ret;
 		}
 	}
@@ -191,15 +191,18 @@
 /* Override for the release function */
 static int media_release(struct inode *inode, struct file *filp)
 {
-	struct media_devnode *mdev = media_devnode_data(filp);
+	struct media_devnode *devnode = media_devnode_data(filp);
+
+	if (devnode->fops->release)
+		devnode->fops->release(filp);
 
-	if (mdev->fops->release)
-		mdev->fops->release(filp);
+	filp->private_data = NULL;
 
 	/* decrease the refcount unconditionally since the release()
 	   return value is ignored. */
-	put_device(&mdev->dev);
-	filp->private_data = NULL;
+	put_device(&devnode->dev);
+
+	pr_debug("%s: Media Release\n", __func__);
 	return 0;
 }
 
@@ -219,7 +222,8 @@
 
 /**
  * media_devnode_register - register a media device node
- * @mdev: media device node structure we want to register
+ * @media_dev: struct media_device we want to register a device node
+ * @devnode: media device node structure we want to register
  *
  * The registration code assigns minor numbers and registers the new device node
  * with the kernel. An error is returned if no free minor number can be found,
@@ -231,7 +235,8 @@
  * the media_devnode structure is *not* called, so the caller is responsible for
  * freeing any data.
  */
-int __must_check media_devnode_register(struct media_devnode *mdev,
+int __must_check media_devnode_register(struct media_device *mdev,
+					struct media_devnode *devnode,
 					struct module *owner)
 {
 	int minor;
@@ -243,68 +248,89 @@
 	if (minor == MEDIA_NUM_DEVICES) {
 		mutex_unlock(&media_devnode_lock);
 		pr_err("could not get a free minor\n");
+		kfree(devnode);
 		return -ENFILE;
 	}
 
 	set_bit(minor, media_devnode_nums);
 	mutex_unlock(&media_devnode_lock);
 
-	mdev->minor = minor;
+	devnode->minor = minor;
+	devnode->media_dev = mdev;
+
+	/* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */
+	devnode->dev.bus = &media_bus_type;
+	devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
+	devnode->dev.release = media_devnode_release;
+	if (devnode->parent)
+		devnode->dev.parent = devnode->parent;
+	dev_set_name(&devnode->dev, "media%d", devnode->minor);
+	device_initialize(&devnode->dev);
 
 	/* Part 2: Initialize and register the character device */
-	cdev_init(&mdev->cdev, &media_devnode_fops);
-	mdev->cdev.owner = owner;
+	cdev_init(&devnode->cdev, &media_devnode_fops);
+	devnode->cdev.owner = owner;
+	devnode->cdev.kobj.parent = &devnode->dev.kobj;
 
-	ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
+	ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1);
 	if (ret < 0) {
 		pr_err("%s: cdev_add failed\n", __func__);
-		goto error;
+		goto cdev_add_error;
 	}
 
-	/* Part 3: Register the media device */
-	mdev->dev.bus = &media_bus_type;
-	mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor);
-	mdev->dev.release = media_devnode_release;
-	if (mdev->parent)
-		mdev->dev.parent = mdev->parent;
-	dev_set_name(&mdev->dev, "media%d", mdev->minor);
-	ret = device_register(&mdev->dev);
+	/* Part 3: Add the media device */
+	ret = device_add(&devnode->dev);
 	if (ret < 0) {
-		pr_err("%s: device_register failed\n", __func__);
-		goto error;
+		pr_err("%s: device_add failed\n", __func__);
+		goto device_add_error;
 	}
 
 	/* Part 4: Activate this minor. The char device can now be used. */
-	set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+	set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
 
 	return 0;
 
-error:
-	cdev_del(&mdev->cdev);
-	clear_bit(mdev->minor, media_devnode_nums);
+device_add_error:
+	cdev_del(&devnode->cdev);
+cdev_add_error:
+	mutex_lock(&media_devnode_lock);
+	clear_bit(devnode->minor, media_devnode_nums);
+	devnode->media_dev = NULL;
+	mutex_unlock(&media_devnode_lock);
+
+	put_device(&devnode->dev);
 	return ret;
 }
 
+void media_devnode_unregister_prepare(struct media_devnode *devnode)
+{
+	/* Check if devnode was ever registered at all */
+	if (!media_devnode_is_registered(devnode))
+		return;
+
+	mutex_lock(&media_devnode_lock);
+	clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+	mutex_unlock(&media_devnode_lock);
+}
+
 /**
  * media_devnode_unregister - unregister a media device node
- * @mdev: the device node to unregister
+ * @devnode: the device node to unregister
  *
  * This unregisters the passed device. Future open calls will be met with
  * errors.
  *
- * This function can safely be called if the device node has never been
- * registered or has already been unregistered.
+ * Should be called after media_devnode_unregister_prepare()
  */
-void media_devnode_unregister(struct media_devnode *mdev)
+void media_devnode_unregister(struct media_devnode *devnode)
 {
-	/* Check if mdev was ever registered at all */
-	if (!media_devnode_is_registered(mdev))
-		return;
-
 	mutex_lock(&media_devnode_lock);
-	clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+	/* Delete the cdev on this minor as well */
+	cdev_del(&devnode->cdev);
 	mutex_unlock(&media_devnode_lock);
-	device_unregister(&mdev->dev);
+	device_del(&devnode->dev);
+	devnode->media_dev = NULL;
+	put_device(&devnode->dev);
 }
 
 /*
--- linux-4.4.0.orig/drivers/media/pci/bt8xx/bt878.c
+++ linux-4.4.0/drivers/media/pci/bt8xx/bt878.c
@@ -422,8 +422,7 @@
 	       bt878_num);
 	if (bt878_num >= BT878_MAX) {
 		printk(KERN_ERR "bt878: Too many devices inserted\n");
-		result = -ENOMEM;
-		goto fail0;
+		return -ENOMEM;
 	}
 	if (pci_enable_device(dev))
 		return -EIO;
--- linux-4.4.0.orig/drivers/media/pci/bt8xx/bttv-driver.c
+++ linux-4.4.0/drivers/media/pci/bt8xx/bttv-driver.c
@@ -2334,6 +2334,19 @@
 	return 0;
 }
 
+static void bttv_get_width_mask_vid_cap(const struct bttv_format *fmt,
+					unsigned int *width_mask,
+					unsigned int *width_bias)
+{
+	if (fmt->flags & FORMAT_FLAGS_PLANAR) {
+		*width_mask = ~15; /* width must be a multiple of 16 pixels */
+		*width_bias = 8;   /* nearest */
+	} else {
+		*width_mask = ~3; /* width must be a multiple of 4 pixels */
+		*width_bias = 2;  /* nearest */
+	}
+}
+
 static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
 						struct v4l2_format *f)
 {
@@ -2343,6 +2356,7 @@
 	enum v4l2_field field;
 	__s32 width, height;
 	__s32 height2;
+	unsigned int width_mask, width_bias;
 	int rc;
 
 	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -2375,9 +2389,9 @@
 	width = f->fmt.pix.width;
 	height = f->fmt.pix.height;
 
+	bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias);
 	rc = limit_scaled_size_lock(fh, &width, &height, field,
-			       /* width_mask: 4 pixels */ ~3,
-			       /* width_bias: nearest */ 2,
+			       width_mask, width_bias,
 			       /* adjust_size */ 1,
 			       /* adjust_crop */ 0);
 	if (0 != rc)
@@ -2410,6 +2424,7 @@
 	struct bttv_fh *fh = priv;
 	struct bttv *btv = fh->btv;
 	__s32 width, height;
+	unsigned int width_mask, width_bias;
 	enum v4l2_field field;
 
 	retval = bttv_switch_type(fh, f->type);
@@ -2424,9 +2439,10 @@
 	height = f->fmt.pix.height;
 	field = f->fmt.pix.field;
 
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias);
 	retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,
-			       /* width_mask: 4 pixels */ ~3,
-			       /* width_bias: nearest */ 2,
+			       width_mask, width_bias,
 			       /* adjust_size */ 1,
 			       /* adjust_crop */ 1);
 	if (0 != retval)
@@ -2434,8 +2450,6 @@
 
 	f->fmt.pix.field = field;
 
-	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-
 	/* update our state informations */
 	fh->fmt              = fmt;
 	fh->cap.field        = f->fmt.pix.field;
@@ -4039,11 +4053,13 @@
 	btv->id  = dev->device;
 	if (pci_enable_device(dev)) {
 		pr_warn("%d: Can't enable device\n", btv->c.nr);
-		return -EIO;
+		result = -EIO;
+		goto free_mem;
 	}
 	if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {
 		pr_warn("%d: No suitable DMA available\n", btv->c.nr);
-		return -EIO;
+		result = -EIO;
+		goto free_mem;
 	}
 	if (!request_mem_region(pci_resource_start(dev,0),
 				pci_resource_len(dev,0),
@@ -4051,7 +4067,8 @@
 		pr_warn("%d: can't request iomem (0x%llx)\n",
 			btv->c.nr,
 			(unsigned long long)pci_resource_start(dev, 0));
-		return -EBUSY;
+		result = -EBUSY;
+		goto free_mem;
 	}
 	pci_set_master(dev);
 	pci_set_command(dev);
@@ -4237,6 +4254,10 @@
 	release_mem_region(pci_resource_start(btv->c.pci,0),
 			   pci_resource_len(btv->c.pci,0));
 	pci_disable_device(btv->c.pci);
+
+free_mem:
+	bttvs[btv->c.nr] = NULL;
+	kfree(btv);
 	return result;
 }
 
--- linux-4.4.0.orig/drivers/media/pci/bt8xx/dvb-bt8xx.c
+++ linux-4.4.0/drivers/media/pci/bt8xx/dvb-bt8xx.c
@@ -680,6 +680,7 @@
 		/*	DST is not a frontend, attaching the ASIC	*/
 		if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
 			pr_err("%s: Could not find a Twinhan DST\n", __func__);
+			kfree(state);
 			break;
 		}
 		/*	Attach other DST peripherals if any		*/
--- linux-4.4.0.orig/drivers/media/pci/cx18/cx18-fileops.c
+++ linux-4.4.0/drivers/media/pci/cx18/cx18-fileops.c
@@ -490,7 +490,7 @@
 
 	CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
 	if (rc > 0)
-		pos += rc;
+		*pos += rc;
 	return rc;
 }
 
--- linux-4.4.0.orig/drivers/media/pci/cx23885/altera-ci.c
+++ linux-4.4.0/drivers/media/pci/cx23885/altera-ci.c
@@ -660,6 +660,10 @@
 		}
 
 		temp_int = append_internal(inter);
+		if (!temp_int) {
+			ret = -ENOMEM;
+			goto err;
+		}
 		inter->filts_used = 1;
 		inter->dev = config->dev;
 		inter->fpga_rw = config->fpga_rw;
@@ -694,6 +698,7 @@
 		     __func__, ret);
 
 	kfree(pid_filt);
+	kfree(inter);
 
 	return ret;
 }
@@ -728,6 +733,10 @@
 		}
 
 		temp_int = append_internal(inter);
+		if (!temp_int) {
+			ret = -ENOMEM;
+			goto err;
+		}
 		inter->cis_used = 1;
 		inter->dev = config->dev;
 		inter->fpga_rw = config->fpga_rw;
@@ -796,6 +805,7 @@
 	ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
 
 	kfree(state);
+	kfree(inter);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/media/pci/cx23885/cx23885-av.c
+++ linux-4.4.0/drivers/media/pci/cx23885/cx23885-av.c
@@ -24,7 +24,7 @@
 {
 	struct cx23885_dev *dev =
 			   container_of(work, struct cx23885_dev, cx25840_work);
-	bool handled;
+	bool handled = false;
 
 	v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine,
 			 PCI_MSK_AV_CORE, &handled);
--- linux-4.4.0.orig/drivers/media/pci/cx23885/cx23885-cards.c
+++ linux-4.4.0/drivers/media/pci/cx23885/cx23885-cards.c
@@ -2124,6 +2124,10 @@
 				&dev->i2c_bus[2].i2c_adap,
 				"cx25840", 0x88 >> 1, NULL);
 		if (dev->sd_cx25840) {
+			/* set host data for clk_freq configuration */
+			v4l2_set_subdev_hostdata(dev->sd_cx25840,
+						&dev->clk_freq);
+
 			dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
 			v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
 		}
--- linux-4.4.0.orig/drivers/media/pci/cx23885/cx23885-core.c
+++ linux-4.4.0/drivers/media/pci/cx23885/cx23885-core.c
@@ -872,6 +872,16 @@
 	if (cx23885_boards[dev->board].clk_freq > 0)
 		dev->clk_freq = cx23885_boards[dev->board].clk_freq;
 
+	if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE &&
+		dev->pci->subsystem_device == 0x7137) {
+		/* Hauppauge ImpactVCBe device ID 0x7137 is populated
+		 * with an 888, and a 25Mhz crystal, instead of the
+		 * usual third overtone 50Mhz. The default clock rate must
+		 * be overridden so the cx25840 is properly configured
+		 */
+		dev->clk_freq = 25000000;
+	}
+
 	dev->pci_bus  = dev->pci->bus->number;
 	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
 	cx23885_irq_add(dev, 0x001f00);
--- linux-4.4.0.orig/drivers/media/pci/cx23885/cx23885-dvb.c
+++ linux-4.4.0/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -1452,8 +1452,9 @@
 		if (fe0->dvb.frontend != NULL) {
 			struct i2c_adapter *tun_i2c;
 
-			fe0->dvb.frontend->sec_priv = kmalloc(sizeof(dib7000p_ops), GFP_KERNEL);
-			memcpy(fe0->dvb.frontend->sec_priv, &dib7000p_ops, sizeof(dib7000p_ops));
+			fe0->dvb.frontend->sec_priv = kmemdup(&dib7000p_ops, sizeof(dib7000p_ops), GFP_KERNEL);
+			if (!fe0->dvb.frontend->sec_priv)
+				return -ENOMEM;
 			tun_i2c = dib7000p_ops.get_i2c_master(fe0->dvb.frontend, DIBX000_I2C_INTERFACE_TUNER, 1);
 			if (!dvb_attach(dib0070_attach, fe0->dvb.frontend, tun_i2c, &dib7070p_dib0070_config))
 				return -ENODEV;
@@ -2168,11 +2169,12 @@
 		}
 		port->i2c_client_tuner = client_tuner;
 		break;
-	case CX23885_BOARD_HAUPPAUGE_HVR5525:
-		switch (port->nr) {
+	case CX23885_BOARD_HAUPPAUGE_HVR5525: {
 		struct m88rs6000t_config m88rs6000t_config;
 		struct a8293_platform_data a8293_pdata = {};
 
+		switch (port->nr) {
+
 		/* port b - satellite */
 		case 1:
 			/* attach frontend */
@@ -2267,6 +2269,7 @@
 			break;
 		}
 		break;
+	}
 	default:
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
 			" isn't supported yet\n",
--- linux-4.4.0.orig/drivers/media/pci/cx23885/cx23888-ir.c
+++ linux-4.4.0/drivers/media/pci/cx23885/cx23888-ir.c
@@ -1179,8 +1179,11 @@
 		return -ENOMEM;
 
 	spin_lock_init(&state->rx_kfifo_lock);
-	if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL))
+	if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE,
+			GFP_KERNEL)) {
+		kfree(state);
 		return -ENOMEM;
+	}
 
 	state->dev = dev;
 	sd = &state->sd;
--- linux-4.4.0.orig/drivers/media/pci/cx25821/cx25821-core.c
+++ linux-4.4.0/drivers/media/pci/cx25821/cx25821-core.c
@@ -871,6 +871,10 @@
 	dev->nr = ++cx25821_devcount;
 	sprintf(dev->name, "cx25821[%d]", dev->nr);
 
+	if (dev->nr >= ARRAY_SIZE(card)) {
+		CX25821_INFO("dev->nr >= %zd", ARRAY_SIZE(card));
+		return -ENODEV;
+	}
 	if (dev->pci->device != 0x8210) {
 		pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n",
 			__func__, dev->pci->device);
@@ -886,9 +890,6 @@
 		dev->channels[i].sram_channels = &cx25821_sram_channels[i];
 	}
 
-	if (dev->nr > 1)
-		CX25821_INFO("dev->nr > 1!");
-
 	/* board config */
 	dev->board = 1;		/* card[dev->nr]; */
 	dev->_max_num_decoders = MAX_DECODERS;
@@ -989,8 +990,10 @@
 	__le32 *cpu;
 	dma_addr_t dma = 0;
 
-	if (NULL != risc->cpu && risc->size < size)
+	if (risc->cpu && risc->size < size) {
 		pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
+		risc->cpu = NULL;
+	}
 	if (NULL == risc->cpu) {
 		cpu = pci_zalloc_consistent(pci, size, &dma);
 		if (NULL == cpu)
--- linux-4.4.0.orig/drivers/media/pci/cx88/cx88-cards.c
+++ linux-4.4.0/drivers/media/pci/cx88/cx88-cards.c
@@ -3691,7 +3691,14 @@
 	core->nr = nr;
 	sprintf(core->name, "cx88[%d]", core->nr);
 
-	core->tvnorm = V4L2_STD_NTSC_M;
+	/*
+	 * Note: Setting initial standard here would cause first call to
+	 * cx88_set_tvnorm() to return without programming any registers.  Leave
+	 * it blank for at this point and it will get set later in
+	 * cx8800_initdev()
+	 */
+	core->tvnorm  = 0;
+
 	core->width   = 320;
 	core->height  = 240;
 	core->field   = V4L2_FIELD_INTERLACED;
--- linux-4.4.0.orig/drivers/media/pci/cx88/cx88-video.c
+++ linux-4.4.0/drivers/media/pci/cx88/cx88-video.c
@@ -1429,7 +1429,7 @@
 
 	/* initial device configuration */
 	mutex_lock(&core->lock);
-	cx88_set_tvnorm(core, core->tvnorm);
+	cx88_set_tvnorm(core, V4L2_STD_NTSC_M);
 	v4l2_ctrl_handler_setup(&core->video_hdl);
 	v4l2_ctrl_handler_setup(&core->audio_hdl);
 	cx88_video_mux(core, 0);
--- linux-4.4.0.orig/drivers/media/pci/dm1105/Kconfig
+++ linux-4.4.0/drivers/media/pci/dm1105/Kconfig
@@ -1,6 +1,6 @@
 config DVB_DM1105
 	tristate "SDMC DM1105 based PCI cards"
-	depends on DVB_CORE && PCI && I2C
+	depends on DVB_CORE && PCI && I2C && I2C_ALGOBIT
 	select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
--- linux-4.4.0.orig/drivers/media/pci/ivtv/ivtv-fileops.c
+++ linux-4.4.0/drivers/media/pci/ivtv/ivtv-fileops.c
@@ -420,7 +420,7 @@
 
 	IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
 	if (rc > 0)
-		pos += rc;
+		*pos += rc;
 	return rc;
 }
 
--- linux-4.4.0.orig/drivers/media/pci/ivtv/ivtv-udma.c
+++ linux-4.4.0/drivers/media/pci/ivtv/ivtv-udma.c
@@ -125,7 +125,8 @@
 
 	/* Get user pages for DMA Xfer */
 	err = get_user_pages_unlocked(current, current->mm,
-			user_dma.uaddr, user_dma.page_count, 0, 1, dma->map);
+			user_dma.uaddr, user_dma.page_count, dma->map,
+			FOLL_FORCE);
 
 	if (user_dma.page_count != err) {
 		IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
--- linux-4.4.0.orig/drivers/media/pci/ivtv/ivtv-yuv.c
+++ linux-4.4.0/drivers/media/pci/ivtv/ivtv-yuv.c
@@ -76,13 +76,13 @@
 
 	/* Get user pages for DMA Xfer */
 	y_pages = get_user_pages_unlocked(current, current->mm,
-				y_dma.uaddr, y_dma.page_count, 0, 1,
-				&dma->map[0]);
+				y_dma.uaddr, y_dma.page_count,
+				&dma->map[0], FOLL_FORCE);
 	uv_pages = 0; /* silence gcc. value is set and consumed only if: */
 	if (y_pages == y_dma.page_count) {
 		uv_pages = get_user_pages_unlocked(current, current->mm,
-					uv_dma.uaddr, uv_dma.page_count, 0, 1,
-					&dma->map[y_pages]);
+					uv_dma.uaddr, uv_dma.page_count,
+					&dma->map[y_pages], FOLL_FORCE);
 	}
 
 	if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
@@ -936,7 +936,7 @@
 	}
 
 	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
-	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
+	yi->blanking_ptr = kzalloc(720 * 16, GFP_ATOMIC|__GFP_NOWARN);
 	if (yi->blanking_ptr) {
 		yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
 	} else {
--- linux-4.4.0.orig/drivers/media/pci/meye/meye.c
+++ linux-4.4.0/drivers/media/pci/meye/meye.c
@@ -1469,7 +1469,7 @@
 	unsigned long page, pos;
 
 	mutex_lock(&meye.lock);
-	if (size > gbuffers * gbufsize) {
+	if (size > gbuffers * gbufsize || offset > gbuffers * gbufsize - size) {
 		mutex_unlock(&meye.lock);
 		return -EINVAL;
 	}
--- linux-4.4.0.orig/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c
+++ linux-4.4.0/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c
@@ -184,7 +184,7 @@
 	struct spi_master *master;
 	struct netup_spi *nspi;
 
-	master = spi_alloc_master(&ndev->pci_dev->dev,
+	master = devm_spi_alloc_master(&ndev->pci_dev->dev,
 		sizeof(struct netup_spi));
 	if (!master) {
 		dev_err(&ndev->pci_dev->dev,
@@ -217,6 +217,7 @@
 		ndev->pci_slot,
 		ndev->pci_func);
 	if (!spi_new_device(master, &netup_spi_board)) {
+		spi_unregister_master(master);
 		ndev->spi = NULL;
 		dev_err(&ndev->pci_dev->dev,
 			"%s(): unable to create SPI device\n", __func__);
@@ -235,13 +236,13 @@
 	if (!spi)
 		return;
 
+	spi_unregister_master(spi->master);
 	spin_lock_irqsave(&spi->lock, flags);
 	reg = readw(&spi->regs->control_stat);
 	writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat);
 	reg = readw(&spi->regs->control_stat);
 	writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat);
 	spin_unlock_irqrestore(&spi->lock, flags);
-	spi_unregister_master(spi->master);
 	ndev->spi = NULL;
 }
 
--- linux-4.4.0.orig/drivers/media/pci/saa7134/saa7134-alsa.c
+++ linux-4.4.0/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -1211,6 +1211,8 @@
 
 static int alsa_device_exit(struct saa7134_dev *dev)
 {
+	if (!snd_saa7134_cards[dev->nr])
+		return 1;
 
 	snd_card_free(snd_saa7134_cards[dev->nr]);
 	snd_saa7134_cards[dev->nr] = NULL;
@@ -1260,7 +1262,8 @@
 	int idx;
 
 	for (idx = 0; idx < SNDRV_CARDS; idx++) {
-		snd_card_free(snd_saa7134_cards[idx]);
+		if (snd_saa7134_cards[idx])
+			snd_card_free(snd_saa7134_cards[idx]);
 	}
 
 	saa7134_dmasound_init = NULL;
--- linux-4.4.0.orig/drivers/media/pci/saa7134/saa7134-empress.c
+++ linux-4.4.0/drivers/media/pci/saa7134/saa7134-empress.c
@@ -295,8 +295,11 @@
 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 	q->lock = &dev->lock;
 	err = vb2_queue_init(q);
-	if (err)
+	if (err) {
+		video_device_release(dev->empress_dev);
+		dev->empress_dev = NULL;
 		return err;
+	}
 	dev->empress_dev->queue = q;
 
 	video_set_drvdata(dev->empress_dev, dev);
--- linux-4.4.0.orig/drivers/media/pci/saa7134/saa7134-i2c.c
+++ linux-4.4.0/drivers/media/pci/saa7134/saa7134-i2c.c
@@ -355,12 +355,47 @@
 
 /* ----------------------------------------------------------- */
 
+/*
+ * On Medion 7134 reading the SAA7134 chip config EEPROM needs DVB-T
+ * demod i2c gate closed due to an address clash between this EEPROM
+ * and the demod one.
+ */
+static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev)
+{
+	u8 subaddr = 0x7, dmdregval;
+	u8 data[2];
+	int ret;
+	struct i2c_msg i2cgatemsg_r[] = { {.addr = 0x08, .flags = 0,
+					   .buf = &subaddr, .len = 1},
+					  {.addr = 0x08,
+					   .flags = I2C_M_RD,
+					   .buf = &dmdregval, .len = 1}
+					};
+	struct i2c_msg i2cgatemsg_w[] = { {.addr = 0x08, .flags = 0,
+					   .buf = data, .len = 2} };
+
+	ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2);
+	if ((ret == 2) && (dmdregval & 0x2)) {
+		pr_debug("%s: DVB-T demod i2c gate was left open\n",
+			 dev->name);
+
+		data[0] = subaddr;
+		data[1] = (dmdregval & ~0x2);
+		if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1)
+			pr_err("%s: EEPROM i2c gate close failure\n",
+			       dev->name);
+	}
+}
+
 static int
 saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len)
 {
 	unsigned char buf;
 	int i,err;
 
+	if (dev->board == SAA7134_BOARD_MD7134)
+		saa7134_i2c_eeprom_md7134_gate(dev);
+
 	dev->i2c_client.addr = 0xa0 >> 1;
 	buf = 0;
 	if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) {
--- linux-4.4.0.orig/drivers/media/pci/saa7134/saa7134-tvaudio.c
+++ linux-4.4.0/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -696,7 +696,8 @@
 {
 	int err;
 
-	audio_dbg(2, "dsp write reg 0x%x = 0x%06x\n", reg << 2, value);
+	audio_dbg(2, "dsp write reg 0x%x = 0x%06x\n",
+		  (reg << 2) & 0xffffffff, value);
 	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
 	if (err < 0)
 		return err;
--- linux-4.4.0.orig/drivers/media/pci/saa7134/saa7134-video.c
+++ linux-4.4.0/drivers/media/pci/saa7134/saa7134-video.c
@@ -1219,10 +1219,13 @@
 	f->fmt.pix.height       = dev->height;
 	f->fmt.pix.field        = dev->field;
 	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
-	f->fmt.pix.bytesperline =
-		(f->fmt.pix.width * dev->fmt->depth) >> 3;
+	if (dev->fmt->planar)
+		f->fmt.pix.bytesperline = f->fmt.pix.width;
+	else
+		f->fmt.pix.bytesperline =
+			(f->fmt.pix.width * dev->fmt->depth) / 8;
 	f->fmt.pix.sizeimage =
-		f->fmt.pix.height * f->fmt.pix.bytesperline;
+		(f->fmt.pix.height * f->fmt.pix.width * dev->fmt->depth) / 8;
 	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
 	return 0;
 }
@@ -1298,10 +1301,13 @@
 	if (f->fmt.pix.height > maxh)
 		f->fmt.pix.height = maxh;
 	f->fmt.pix.width &= ~0x03;
-	f->fmt.pix.bytesperline =
-		(f->fmt.pix.width * fmt->depth) >> 3;
+	if (fmt->planar)
+		f->fmt.pix.bytesperline = f->fmt.pix.width;
+	else
+		f->fmt.pix.bytesperline =
+			(f->fmt.pix.width * fmt->depth) / 8;
 	f->fmt.pix.sizeimage =
-		f->fmt.pix.height * f->fmt.pix.bytesperline;
+		(f->fmt.pix.height * f->fmt.pix.width * fmt->depth) / 8;
 	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
 
 	return 0;
--- linux-4.4.0.orig/drivers/media/pci/saa7146/hexium_gemini.c
+++ linux-4.4.0/drivers/media/pci/saa7146/hexium_gemini.c
@@ -270,9 +270,8 @@
 	/* enable i2c-port pins */
 	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 
-	hexium->i2c_adapter = (struct i2c_adapter) {
-		.name = "hexium gemini",
-	};
+	strscpy(hexium->i2c_adapter.name, "hexium gemini",
+		sizeof(hexium->i2c_adapter.name));
 	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 		DEB_S("cannot register i2c-device. skipping.\n");
@@ -305,6 +304,9 @@
 	ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
 	if (ret < 0) {
 		pr_err("cannot register capture v4l2 device. skipping.\n");
+		saa7146_vv_release(dev);
+		i2c_del_adapter(&hexium->i2c_adapter);
+		kfree(hexium);
 		return ret;
 	}
 
--- linux-4.4.0.orig/drivers/media/pci/saa7146/hexium_orion.c
+++ linux-4.4.0/drivers/media/pci/saa7146/hexium_orion.c
@@ -232,9 +232,8 @@
 	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
 	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
-	hexium->i2c_adapter = (struct i2c_adapter) {
-		.name = "hexium orion",
-	};
+	strscpy(hexium->i2c_adapter.name, "hexium orion",
+		sizeof(hexium->i2c_adapter.name));
 	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 		DEB_S("cannot register i2c-device. skipping.\n");
--- linux-4.4.0.orig/drivers/media/pci/saa7146/mxb.c
+++ linux-4.4.0/drivers/media/pci/saa7146/mxb.c
@@ -652,16 +652,17 @@
 	struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
 	DEB_D("VIDIOC_S_AUDIO %d\n", a->index);
-	if (mxb_inputs[mxb->cur_input].audioset & (1 << a->index)) {
-		if (mxb->cur_audinput != a->index) {
-			mxb->cur_audinput = a->index;
-			tea6420_route(mxb, a->index);
-			if (mxb->cur_audinput == 0)
-				mxb_update_audmode(mxb);
-		}
-		return 0;
+	if (a->index >= 32 ||
+	    !(mxb_inputs[mxb->cur_input].audioset & (1 << a->index)))
+		return -EINVAL;
+
+	if (mxb->cur_audinput != a->index) {
+		mxb->cur_audinput = a->index;
+		tea6420_route(mxb, a->index);
+		if (mxb->cur_audinput == 0)
+			mxb_update_audmode(mxb);
 	}
-	return -EINVAL;
+	return 0;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
--- linux-4.4.0.orig/drivers/media/pci/saa7164/saa7164-bus.c
+++ linux-4.4.0/drivers/media/pci/saa7164/saa7164-bus.c
@@ -393,11 +393,11 @@
 	msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
 	msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
 	msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
+	memcpy(msg, &msg_tmp, sizeof(*msg));
 
 	/* No need to update the read positions, because this was a peek */
 	/* If the caller specifically want to peek, return */
 	if (peekonly) {
-		memcpy(msg, &msg_tmp, sizeof(*msg));
 		goto peekout;
 	}
 
@@ -442,21 +442,15 @@
 		space_rem = bus->m_dwSizeGetRing - curr_grp;
 
 		if (space_rem < sizeof(*msg)) {
-			/* msg wraps around the ring */
-			memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, space_rem);
-			memcpy_fromio((u8 *)msg + space_rem, bus->m_pdwGetRing,
-				sizeof(*msg) - space_rem);
 			if (buf)
 				memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
 					space_rem, buf_size);
 
 		} else if (space_rem == sizeof(*msg)) {
-			memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
 			if (buf)
 				memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
 		} else {
 			/* Additional data wraps around the ring */
-			memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
 			if (buf) {
 				memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
 					sizeof(*msg), space_rem - sizeof(*msg));
@@ -469,15 +463,10 @@
 
 	} else {
 		/* No wrapping */
-		memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
 		if (buf)
 			memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
 				buf_size);
 	}
-	/* Convert from little endian to CPU */
-	msg->size = le16_to_cpu((__force __le16)msg->size);
-	msg->command = le32_to_cpu((__force __le32)msg->command);
-	msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
 
 	/* Update the read positions, adjusting the ring */
 	saa7164_writel(bus->m_dwGetReadPos, new_grp);
--- linux-4.4.0.orig/drivers/media/pci/saa7164/saa7164-fw.c
+++ linux-4.4.0/drivers/media/pci/saa7164/saa7164-fw.c
@@ -430,7 +430,8 @@
 			__func__, fw->size);
 
 		if (fw->size != fwlength) {
-			printk(KERN_ERR "xc5000: firmware incorrect size\n");
+			printk(KERN_ERR "saa7164: firmware incorrect size %zu != %u\n",
+				fw->size, fwlength);
 			ret = -ENOMEM;
 			goto out;
 		}
--- linux-4.4.0.orig/drivers/media/pci/solo6x10/solo6x10-g723.c
+++ linux-4.4.0/drivers/media/pci/solo6x10/solo6x10-g723.c
@@ -385,7 +385,7 @@
 
 	ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
 	if (ret < 0)
-		return ret;
+		goto snd_error;
 
 	ret = solo_snd_pcm_init(solo_dev);
 	if (ret < 0)
--- linux-4.4.0.orig/drivers/media/pci/solo6x10/solo6x10-v4l2.c
+++ linux-4.4.0/drivers/media/pci/solo6x10/solo6x10-v4l2.c
@@ -342,6 +342,17 @@
 	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
 
 	solo_stop_thread(solo_dev);
+
+	spin_lock(&solo_dev->slock);
+	while (!list_empty(&solo_dev->vidq_active)) {
+		struct solo_vb2_buf *buf = list_entry(
+				solo_dev->vidq_active.next,
+				struct solo_vb2_buf, list);
+
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+	}
+	spin_unlock(&solo_dev->slock);
 	INIT_LIST_HEAD(&solo_dev->vidq_active);
 }
 
--- linux-4.4.0.orig/drivers/media/pci/solo6x10/solo6x10.h
+++ linux-4.4.0/drivers/media/pci/solo6x10/solo6x10.h
@@ -286,7 +286,10 @@
 static inline void solo_reg_write(struct solo_dev *solo_dev, int reg,
 				  u32 data)
 {
+	u16 val;
+
 	writel(data, solo_dev->reg_base + reg);
+	pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
 }
 
 static inline void solo_irq_on(struct solo_dev *dev, u32 mask)
--- linux-4.4.0.orig/drivers/media/pci/ttpci/av7110.c
+++ linux-4.4.0/drivers/media/pci/ttpci/av7110.c
@@ -426,14 +426,15 @@
 	case DATA_CI_GET:
 	{
 		u8 *data = av7110->debi_virt;
+		u8 data_0 = data[0];
 
-		if ((data[0] < 2) && data[2] == 0xff) {
+		if (data_0 < 2 && data[2] == 0xff) {
 			int flags = 0;
 			if (data[5] > 0)
 				flags |= CA_CI_MODULE_PRESENT;
 			if (data[5] > 5)
 				flags |= CA_CI_MODULE_READY;
-			av7110->ci_slot[data[0]].flags = flags;
+			av7110->ci_slot[data_0].flags = flags;
 		} else
 			ci_get_data(&av7110->ci_rbuffer,
 				    av7110->debi_virt,
--- linux-4.4.0.orig/drivers/media/pci/ttpci/av7110_hw.c
+++ linux-4.4.0/drivers/media/pci/ttpci/av7110_hw.c
@@ -56,11 +56,11 @@
    by Nathan Laredo <laredo@gnu.org> */
 
 int av7110_debiwrite(struct av7110 *av7110, u32 config,
-		     int addr, u32 val, int count)
+		     int addr, u32 val, unsigned int count)
 {
 	struct saa7146_dev *dev = av7110->dev;
 
-	if (count <= 0 || count > 32764) {
+	if (count > 32764) {
 		printk("%s: invalid count %d\n", __func__, count);
 		return -1;
 	}
@@ -78,12 +78,12 @@
 	return 0;
 }
 
-u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
+u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count)
 {
 	struct saa7146_dev *dev = av7110->dev;
 	u32 result = 0;
 
-	if (count > 32764 || count <= 0) {
+	if (count > 32764) {
 		printk("%s: invalid count %d\n", __func__, count);
 		return 0;
 	}
--- linux-4.4.0.orig/drivers/media/pci/ttpci/av7110_hw.h
+++ linux-4.4.0/drivers/media/pci/ttpci/av7110_hw.h
@@ -377,14 +377,14 @@
 
 /* DEBI (saa7146 data extension bus interface) access */
 extern int av7110_debiwrite(struct av7110 *av7110, u32 config,
-			    int addr, u32 val, int count);
+			    int addr, u32 val, unsigned int count);
 extern u32 av7110_debiread(struct av7110 *av7110, u32 config,
-			   int addr, int count);
+			   int addr, unsigned int count);
 
 
 /* DEBI during interrupt */
 /* single word writes */
-static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count)
 {
 	av7110_debiwrite(av7110, config, addr, val, count);
 }
@@ -397,7 +397,7 @@
 	av7110_debiwrite(av7110, config, addr, 0, count);
 }
 
-static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count)
 {
 	u32 res;
 
@@ -408,7 +408,7 @@
 }
 
 /* DEBI outside interrupts, only for count <= 4! */
-static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count)
 {
 	unsigned long flags;
 
@@ -417,7 +417,7 @@
 	spin_unlock_irqrestore(&av7110->debilock, flags);
 }
 
-static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count)
 {
 	unsigned long flags;
 	u32 res;
--- linux-4.4.0.orig/drivers/media/pci/ttpci/budget-core.c
+++ linux-4.4.0/drivers/media/pci/ttpci/budget-core.c
@@ -386,20 +386,25 @@
 	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend);
 
 	if (ret < 0)
-		return ret;
+		goto err_release_dmx;
 
 	budget->mem_frontend.source = DMX_MEMORY_FE;
 	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
 	if (ret < 0)
-		return ret;
+		goto err_release_dmx;
 
 	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
 	if (ret < 0)
-		return ret;
+		goto err_release_dmx;
 
 	dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);
 
 	return 0;
+
+err_release_dmx:
+	dvb_dmxdev_release(&budget->dmxdev);
+	dvb_dmx_release(&budget->demux);
+	return ret;
 }
 
 static void budget_unregister(struct budget *budget)
--- linux-4.4.0.orig/drivers/media/pci/zoran/zoran_card.c
+++ linux-4.4.0/drivers/media/pci/zoran/zoran_card.c
@@ -73,7 +73,7 @@
  */
 
 static unsigned long vidmem;	/* default = 0 - Video memory base address */
-module_param(vidmem, ulong, 0444);
+module_param_hw(vidmem, ulong, iomem, 0444);
 MODULE_PARM_DESC(vidmem, "Default video memory base address");
 
 /*
--- linux-4.4.0.orig/drivers/media/platform/am437x/am437x-vpfe.c
+++ linux-4.4.0/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1047,7 +1047,7 @@
 static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe)
 {
 	enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
-	int ret;
+	int ret = 0;
 
 	vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n");
 
@@ -1576,7 +1576,7 @@
 		return -EBUSY;
 	}
 
-	ret = vpfe_try_fmt(file, priv, &format);
+	ret = __vpfe_get_format(vpfe, &format, &bpp);
 	if (ret)
 		return ret;
 
@@ -1706,7 +1706,7 @@
 		sdinfo = &cfg->sub_devs[i];
 		client = v4l2_get_subdevdata(sdinfo->sd);
 		if (client->addr == curr_client->addr &&
-		    client->adapter->nr == client->adapter->nr) {
+		    client->adapter->nr == curr_client->adapter->nr) {
 			if (vpfe->current_input >= 1)
 				return -1;
 			*app_input_index = j + vpfe->current_input;
@@ -1847,6 +1847,10 @@
 	if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD))
 		return -ENODATA;
 
+	/* if trying to set the same std then nothing to do */
+	if (vpfe_standards[vpfe->std_index].std_id == std_id)
+		return 0;
+
 	/* If streaming is started, return error */
 	if (vb2_is_busy(&vpfe->buffer_queue)) {
 		vpfe_err(vpfe, "%s device busy\n", __func__);
--- linux-4.4.0.orig/drivers/media/platform/blackfin/ppi.c
+++ linux-4.4.0/drivers/media/platform/blackfin/ppi.c
@@ -214,6 +214,8 @@
 	if (params->dlen > 24 || params->dlen <= 0)
 		return -EINVAL;
 	pctrl = devm_pinctrl_get(ppi->dev);
+	if (IS_ERR(pctrl))
+		return PTR_ERR(pctrl);
 	pstate = pinctrl_lookup_state(pctrl,
 				      pin_state[(params->dlen + 7) / 8 - 1]);
 	if (pinctrl_select_state(pctrl, pstate))
--- linux-4.4.0.orig/drivers/media/platform/coda/coda-bit.c
+++ linux-4.4.0/drivers/media/platform/coda/coda-bit.c
@@ -1342,7 +1342,7 @@
 
 	/* Calculate bytesused field */
 	if (dst_buf->sequence == 0) {
-		vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
+		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr +
 					ctx->vpu_header_size[0] +
 					ctx->vpu_header_size[1] +
 					ctx->vpu_header_size[2]);
@@ -1581,6 +1581,7 @@
 		coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
 		return -ETIMEDOUT;
 	}
+	ctx->sequence_offset = ~0U;
 	ctx->initialized = 1;
 
 	/* Update kfifo out pointer from coda bitstream read pointer */
@@ -1829,6 +1830,9 @@
 	/* Clear decode success flag */
 	coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS);
 
+	/* Clear error return value */
+	coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB);
+
 	trace_coda_dec_pic_run(ctx, meta);
 
 	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
@@ -1963,12 +1967,17 @@
 		else if (ctx->display_idx < 0)
 			ctx->hold = true;
 	} else if (decoded_idx == -2) {
+		if (ctx->display_idx >= 0 &&
+		    ctx->display_idx < ctx->num_internal_frames)
+			ctx->sequence_offset++;
 		/* no frame was decoded, we still return remaining buffers */
 	} else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
 		v4l2_err(&dev->v4l2_dev,
 			 "decoded frame index out of range: %d\n", decoded_idx);
 	} else {
-		val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
+		val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM);
+		if (ctx->sequence_offset == -1)
+			ctx->sequence_offset = val;
 		val -= ctx->sequence_offset;
 		spin_lock_irqsave(&ctx->buffer_meta_lock, flags);
 		if (!list_empty(&ctx->buffer_meta_list)) {
@@ -2098,7 +2107,6 @@
 	if (ctx == NULL) {
 		v4l2_err(&dev->v4l2_dev,
 			 "Instance released before the end of transaction\n");
-		mutex_unlock(&dev->coda_mutex);
 		return IRQ_HANDLED;
 	}
 
--- linux-4.4.0.orig/drivers/media/platform/coda/coda-common.c
+++ linux-4.4.0/drivers/media/platform/coda/coda-common.c
@@ -2119,14 +2119,12 @@
 
 	pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
 
-	if (of_id) {
+	if (of_id)
 		dev->devtype = of_id->data;
-	} else if (pdev_id) {
+	else if (pdev_id)
 		dev->devtype = &coda_devdata[pdev_id->driver_data];
-	} else {
-		ret = -EINVAL;
-		goto err_v4l2_register;
-	}
+	else
+		return -EINVAL;
 
 	spin_lock_init(&dev->irqlock);
 	INIT_LIST_HEAD(&dev->instances);
--- linux-4.4.0.orig/drivers/media/platform/davinci/isif.c
+++ linux-4.4.0/drivers/media/platform/davinci/isif.c
@@ -890,9 +890,7 @@
 static int isif_config_ycbcr(void)
 {
 	struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
-	struct vpss_pg_frame_size frame_size;
 	u32 modeset = 0, ccdcfg = 0;
-	struct vpss_sync_pol sync;
 
 	dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
 
@@ -980,13 +978,6 @@
 		/* two fields are interleaved in memory */
 		regw(0x00000249, SDOFST);
 
-	/* Setup test pattern if enabled */
-	if (isif_cfg.bayer.config_params.test_pat_gen) {
-		sync.ccdpg_hdpol = params->hd_pol;
-		sync.ccdpg_vdpol = params->vd_pol;
-		dm365_vpss_set_sync_pol(sync);
-		dm365_vpss_set_pg_frame_size(frame_size);
-	}
 	return 0;
 }
 
@@ -1106,7 +1097,8 @@
 
 	while (i >= 0) {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-		release_mem_region(res->start, resource_size(res));
+		if (res)
+			release_mem_region(res->start, resource_size(res));
 		i--;
 	}
 	vpfe_unregister_ccdc_device(&isif_hw_dev);
--- linux-4.4.0.orig/drivers/media/platform/davinci/vpbe.c
+++ linux-4.4.0/drivers/media/platform/davinci/vpbe.c
@@ -130,7 +130,7 @@
 			     struct v4l2_output *output)
 {
 	struct vpbe_config *cfg = vpbe_dev->cfg;
-	int temp_index = output->index;
+	unsigned int temp_index = output->index;
 
 	if (temp_index >= cfg->num_outputs)
 		return -EINVAL;
@@ -753,7 +753,7 @@
 	if (ret) {
 		v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s",
 			 def_output);
-		return ret;
+		goto fail_kfree_amp;
 	}
 
 	printk(KERN_NOTICE "Setting default mode to %s\n", def_mode);
@@ -761,12 +761,15 @@
 	if (ret) {
 		v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s",
 			 def_mode);
-		return ret;
+		goto fail_kfree_amp;
 	}
 	vpbe_dev->initialized = 1;
 	/* TBD handling of bootargs for default output and mode */
 	return 0;
 
+fail_kfree_amp:
+	mutex_lock(&vpbe_dev->lock);
+	kfree(vpbe_dev->amp);
 fail_kfree_encoders:
 	kfree(vpbe_dev->encoders);
 fail_dev_unregister:
--- linux-4.4.0.orig/drivers/media/platform/davinci/vpbe_display.c
+++ linux-4.4.0/drivers/media/platform/davinci/vpbe_display.c
@@ -520,7 +520,7 @@
 		else if (v_scale == 4)
 			layer_info->v_zoom = ZOOM_X4;
 		if (v_exp)
-			layer_info->h_exp = V_EXP_6_OVER_5;
+			layer_info->v_exp = V_EXP_6_OVER_5;
 	} else {
 		/* no scaling, only cropping. Set display area to crop area */
 		cfg->ysize = expected_ysize;
--- linux-4.4.0.orig/drivers/media/platform/davinci/vpfe_capture.c
+++ linux-4.4.0/drivers/media/platform/davinci/vpfe_capture.c
@@ -1709,27 +1709,9 @@
 
 	switch (cmd) {
 	case VPFE_CMD_S_CCDC_RAW_PARAMS:
+		ret = -EINVAL;
 		v4l2_warn(&vpfe_dev->v4l2_dev,
-			  "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
-		if (ccdc_dev->hw_ops.set_params) {
-			ret = ccdc_dev->hw_ops.set_params(param);
-			if (ret) {
-				v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
-					"Error setting parameters in CCDC\n");
-				goto unlock_out;
-			}
-			ret = vpfe_get_ccdc_image_format(vpfe_dev,
-							 &vpfe_dev->fmt);
-			if (ret < 0) {
-				v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
-					"Invalid image format at CCDC\n");
-				goto unlock_out;
-			}
-		} else {
-			ret = -EINVAL;
-			v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
-				"VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
-		}
+			"VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
 		break;
 	default:
 		ret = -ENOTTY;
--- linux-4.4.0.orig/drivers/media/platform/davinci/vpif_capture.c
+++ linux-4.4.0/drivers/media/platform/davinci/vpif_capture.c
@@ -1417,8 +1417,6 @@
 		/* Unregister video device */
 		video_unregister_device(&ch->video_dev);
 	}
-	kfree(vpif_obj.sd);
-	v4l2_device_unregister(&vpif_obj.v4l2_dev);
 
 	return err;
 }
--- linux-4.4.0.orig/drivers/media/platform/davinci/vpss.c
+++ linux-4.4.0/drivers/media/platform/davinci/vpss.c
@@ -519,14 +519,31 @@
 
 static int __init vpss_init(void)
 {
+	int ret;
+
 	if (!request_mem_region(VPSS_CLK_CTRL, 4, "vpss_clock_control"))
 		return -EBUSY;
 
 	oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4);
+	if (unlikely(!oper_cfg.vpss_regs_base2)) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
 	writel(VPSS_CLK_CTRL_VENCCLKEN |
-		     VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2);
+	       VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2);
+
+	ret = platform_driver_register(&vpss_driver);
+	if (ret)
+		goto err_pd_register;
+
+	return 0;
 
-	return platform_driver_register(&vpss_driver);
+err_pd_register:
+	iounmap(oper_cfg.vpss_regs_base2);
+err_ioremap:
+	release_mem_region(VPSS_CLK_CTRL, 4);
+	return ret;
 }
 subsys_initcall(vpss_init);
 module_exit(vpss_exit);
--- linux-4.4.0.orig/drivers/media/platform/exynos-gsc/gsc-core.c
+++ linux-4.4.0/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -849,9 +849,7 @@
 
 	if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) ||
 		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_NV61) ||
 		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_NV21) ||
 		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
 		swap(addr->cb, addr->cr);
 
--- linux-4.4.0.orig/drivers/media/platform/exynos4-is/fimc-is.c
+++ linux-4.4.0/drivers/media/platform/exynos4-is/fimc-is.c
@@ -815,12 +815,13 @@
 	is->irq = irq_of_parse_and_map(dev->of_node, 0);
 	if (!is->irq) {
 		dev_err(dev, "no irq found\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_iounmap;
 	}
 
 	ret = fimc_is_get_clocks(is);
 	if (ret < 0)
-		return ret;
+		goto err_iounmap;
 
 	platform_set_drvdata(pdev, is);
 
@@ -880,6 +881,8 @@
 	free_irq(is->irq, is);
 err_clk:
 	fimc_is_put_clocks(is);
+err_iounmap:
+	iounmap(is->pmu_regs);
 	return ret;
 }
 
@@ -935,6 +938,7 @@
 	fimc_is_unregister_subdevs(is);
 	vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
 	fimc_is_put_clocks(is);
+	iounmap(is->pmu_regs);
 	fimc_is_debugfs_remove(is);
 	release_firmware(is->fw.f_w);
 	fimc_is_free_cpu_memory(is);
--- linux-4.4.0.orig/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ linux-4.4.0/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -221,8 +221,8 @@
 							ivb->dma_addr[i];
 
 			isp_dbg(2, &video->ve.vdev,
-				"dma_buf %pad (%d/%d/%d) addr: %pad\n",
-				&buf_index, ivb->index, i, vb->index,
+				"dma_buf %d (%d/%d/%d) addr: %pad\n",
+				buf_index, ivb->index, i, vb->index,
 				&ivb->dma_addr[i]);
 		}
 
@@ -323,7 +323,7 @@
 		ivc->streaming = 0;
 	}
 
-	vb2_fop_release(file);
+	_vb2_fop_release(file, NULL);
 
 	if (v4l2_fh_is_singular_file(file)) {
 		fimc_pipeline_call(&ivc->ve, close);
@@ -391,12 +391,17 @@
 				struct v4l2_pix_format_mplane *pixm,
 				const struct fimc_fmt **fmt)
 {
-	*fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2);
+	const struct fimc_fmt *__fmt;
+
+	__fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2);
+
+	if (fmt)
+		*fmt = __fmt;
 
 	pixm->colorspace = V4L2_COLORSPACE_SRGB;
 	pixm->field = V4L2_FIELD_NONE;
-	pixm->num_planes = (*fmt)->memplanes;
-	pixm->pixelformat = (*fmt)->fourcc;
+	pixm->num_planes = __fmt->memplanes;
+	pixm->pixelformat = __fmt->fourcc;
 	/*
 	 * TODO: double check with the docmentation these width/height
 	 * constraints are correct.
--- linux-4.4.0.orig/drivers/media/platform/exynos4-is/fimc-isp.c
+++ linux-4.4.0/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -311,8 +311,10 @@
 
 	if (on) {
 		ret = pm_runtime_get_sync(&is->pdev->dev);
-		if (ret < 0)
+		if (ret < 0) {
+			pm_runtime_put(&is->pdev->dev);
 			return ret;
+		}
 		set_bit(IS_ST_PWR_ON, &is->state);
 
 		ret = fimc_is_start_firmware(is);
--- linux-4.4.0.orig/drivers/media/platform/exynos4-is/fimc-lite.c
+++ linux-4.4.0/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -487,7 +487,7 @@
 	set_bit(ST_FLITE_IN_USE, &fimc->state);
 	ret = pm_runtime_get_sync(&fimc->pdev->dev);
 	if (ret < 0)
-		goto unlock;
+		goto err_pm;
 
 	ret = v4l2_fh_open(file);
 	if (ret < 0)
--- linux-4.4.0.orig/drivers/media/platform/exynos4-is/media-dev.c
+++ linux-4.4.0/drivers/media/platform/exynos4-is/media-dev.c
@@ -413,8 +413,10 @@
 		return -ENXIO;
 
 	ret = pm_runtime_get_sync(fmd->pmf);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put(fmd->pmf);
 		return ret;
+	}
 
 	fmd->num_sensors = 0;
 
@@ -1170,6 +1172,7 @@
 	if (IS_ERR(pctl->state_default))
 		return PTR_ERR(pctl->state_default);
 
+	/* PINCTRL_STATE_IDLE is optional */
 	pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl,
 					PINCTRL_STATE_IDLE);
 	return 0;
--- linux-4.4.0.orig/drivers/media/platform/exynos4-is/mipi-csis.c
+++ linux-4.4.0/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -513,8 +513,10 @@
 	if (enable) {
 		s5pcsis_clear_counters(state);
 		ret = pm_runtime_get_sync(&state->pdev->dev);
-		if (ret && ret != 1)
+		if (ret && ret != 1) {
+			pm_runtime_put_noidle(&state->pdev->dev);
 			return ret;
+		}
 	}
 
 	mutex_lock(&state->lock);
--- linux-4.4.0.orig/drivers/media/platform/fsl-viu.c
+++ linux-4.4.0/drivers/media/platform/fsl-viu.c
@@ -1417,7 +1417,7 @@
 				     sizeof(struct viu_reg), DRV_NAME)) {
 		dev_err(&op->dev, "Error while requesting mem region\n");
 		ret = -EBUSY;
-		goto err;
+		goto err_irq;
 	}
 
 	/* remap registers */
@@ -1425,7 +1425,7 @@
 	if (!viu_regs) {
 		dev_err(&op->dev, "Can't map register set\n");
 		ret = -ENOMEM;
-		goto err;
+		goto err_irq;
 	}
 
 	/* Prepare our private structure */
@@ -1433,7 +1433,7 @@
 	if (!viu_dev) {
 		dev_err(&op->dev, "Can't allocate private structure\n");
 		ret = -ENOMEM;
-		goto err;
+		goto err_irq;
 	}
 
 	viu_dev->vr = viu_regs;
@@ -1449,16 +1449,21 @@
 	ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
 	if (ret < 0) {
 		dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
-		goto err;
+		goto err_irq;
 	}
 
 	ad = i2c_get_adapter(0);
+	if (!ad) {
+		ret = -EFAULT;
+		dev_err(&op->dev, "couldn't get i2c adapter\n");
+		goto err_v4l2;
+	}
 
 	v4l2_ctrl_handler_init(&viu_dev->hdl, 5);
 	if (viu_dev->hdl.error) {
 		ret = viu_dev->hdl.error;
 		dev_err(&op->dev, "couldn't register control\n");
-		goto err_vdev;
+		goto err_i2c;
 	}
 	/* This control handler will inherit the control(s) from the
 	   sub-device(s). */
@@ -1476,7 +1481,7 @@
 	vdev = video_device_alloc();
 	if (vdev == NULL) {
 		ret = -ENOMEM;
-		goto err_vdev;
+		goto err_hdl;
 	}
 
 	*vdev = viu_template;
@@ -1497,7 +1502,7 @@
 	ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
 	if (ret < 0) {
 		video_device_release(viu_dev->vdev);
-		goto err_vdev;
+		goto err_unlock;
 	}
 
 	/* enable VIU clock */
@@ -1505,12 +1510,12 @@
 	if (IS_ERR(clk)) {
 		dev_err(&op->dev, "failed to lookup the clock!\n");
 		ret = PTR_ERR(clk);
-		goto err_clk;
+		goto err_vdev;
 	}
 	ret = clk_prepare_enable(clk);
 	if (ret) {
 		dev_err(&op->dev, "failed to enable the clock!\n");
-		goto err_clk;
+		goto err_vdev;
 	}
 	viu_dev->clk = clk;
 
@@ -1521,7 +1526,7 @@
 	if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
 		dev_err(&op->dev, "Request VIU IRQ failed.\n");
 		ret = -ENODEV;
-		goto err_irq;
+		goto err_clk;
 	}
 
 	mutex_unlock(&viu_dev->lock);
@@ -1529,16 +1534,19 @@
 	dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
 	return ret;
 
-err_irq:
-	clk_disable_unprepare(viu_dev->clk);
 err_clk:
-	video_unregister_device(viu_dev->vdev);
+	clk_disable_unprepare(viu_dev->clk);
 err_vdev:
-	v4l2_ctrl_handler_free(&viu_dev->hdl);
+	video_unregister_device(viu_dev->vdev);
+err_unlock:
 	mutex_unlock(&viu_dev->lock);
+err_hdl:
+	v4l2_ctrl_handler_free(&viu_dev->hdl);
+err_i2c:
 	i2c_put_adapter(ad);
+err_v4l2:
 	v4l2_device_unregister(&viu_dev->v4l2_dev);
-err:
+err_irq:
 	irq_dispose_mapping(viu_irq);
 	return ret;
 }
--- linux-4.4.0.orig/drivers/media/platform/marvell-ccic/mcam-core.c
+++ linux-4.4.0/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -209,7 +209,6 @@
 	struct list_head queue;
 	struct mcam_dma_desc *dma_desc;	/* Descriptor virtual address */
 	dma_addr_t dma_desc_pa;		/* Descriptor physical address */
-	int dma_desc_nent;		/* Number of mapped descriptors */
 };
 
 static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_v4l2_buffer *vb)
@@ -616,9 +615,11 @@
 static void mcam_sg_next_buffer(struct mcam_camera *cam)
 {
 	struct mcam_vb_buffer *buf;
+	struct sg_table *sg_table;
 
 	buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
 	list_del_init(&buf->queue);
+	sg_table = vb2_dma_sg_plane_desc(&buf->vb_buf.vb2_buf, 0);
 	/*
 	 * Very Bad Not Good Things happen if you don't clear
 	 * C1_DESC_ENA before making any descriptor changes.
@@ -626,7 +627,7 @@
 	mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
 	mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
 	mcam_reg_write(cam, REG_DESC_LEN_Y,
-			buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
+			sg_table->nents * sizeof(struct mcam_dma_desc));
 	mcam_reg_write(cam, REG_DESC_LEN_U, 0);
 	mcam_reg_write(cam, REG_DESC_LEN_V, 0);
 	mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
--- linux-4.4.0.orig/drivers/media/platform/mx2_emmaprp.c
+++ linux-4.4.0/drivers/media/platform/mx2_emmaprp.c
@@ -289,7 +289,7 @@
 {
 	struct emmaprp_ctx *ctx = priv;
 	struct emmaprp_q_data *s_q_data, *d_q_data;
-	struct vb2_buffer *src_buf, *dst_buf;
+	struct vb2_v4l2_buffer *src_buf, *dst_buf;
 	struct emmaprp_dev *pcdev = ctx->dev;
 	unsigned int s_width, s_height;
 	unsigned int d_width, d_height;
@@ -309,8 +309,8 @@
 	d_height = d_q_data->height;
 	d_size = d_width * d_height;
 
-	p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0);
-	p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	p_in = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	p_out = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
 	if (!p_in || !p_out) {
 		v4l2_err(&pcdev->v4l2_dev,
 			 "Acquiring kernel pointers to buffers failed\n");
--- linux-4.4.0.orig/drivers/media/platform/omap/omap_vout.c
+++ linux-4.4.0/drivers/media/platform/omap/omap_vout.c
@@ -214,7 +214,7 @@
 	if (!vec)
 		return -ENOMEM;
 
-	ret = get_vaddr_frames(virtp, 1, true, false, vec);
+	ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec);
 	if (ret != 1) {
 		frame_vector_destroy(vec);
 		return -EINVAL;
@@ -1580,23 +1580,20 @@
 	unsigned long size;
 	struct videobuf_buffer *vb;
 
-	vb = q->bufs[b->index];
-
 	if (!vout->streaming)
 		return -EINVAL;
 
-	if (file->f_flags & O_NONBLOCK)
-		/* Call videobuf_dqbuf for non blocking mode */
-		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
-	else
-		/* Call videobuf_dqbuf for  blocking mode */
-		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+	ret = videobuf_dqbuf(q, b, !!(file->f_flags & O_NONBLOCK));
+	if (ret)
+		return ret;
+
+	vb = q->bufs[b->index];
 
 	addr = (unsigned long) vout->buf_phy_addr[vb->i];
 	size = (unsigned long) vb->size;
 	dma_unmap_single(vout->vid_dev->v4l2_dev.dev,  addr,
 				size, DMA_TO_DEVICE);
-	return ret;
+	return 0;
 }
 
 static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
--- linux-4.4.0.orig/drivers/media/platform/omap3isp/isp.c
+++ linux-4.4.0/drivers/media/platform/omap3isp/isp.c
@@ -303,7 +303,7 @@
 static int isp_xclk_init(struct isp_device *isp)
 {
 	struct device_node *np = isp->dev->of_node;
-	struct clk_init_data init;
+	struct clk_init_data init = { 0 };
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i)
@@ -917,6 +917,10 @@
 					s_stream, mode);
 			pipe->do_propagation = true;
 		}
+
+		/* Stop at the first external sub-device. */
+		if (subdev->dev != isp->dev)
+			break;
 	}
 
 	return 0;
@@ -1031,6 +1035,10 @@
 				isp->crashed |= 1U << subdev->entity.id;
 			failure = -ETIMEDOUT;
 		}
+
+		/* Stop at the first external sub-device. */
+		if (subdev->dev != isp->dev)
+			break;
 	}
 
 	return failure;
@@ -2077,6 +2085,7 @@
 
 static void isp_detach_iommu(struct isp_device *isp)
 {
+	arm_iommu_detach_device(isp->dev);
 	arm_iommu_release_mapping(isp->mapping);
 	isp->mapping = NULL;
 	iommu_group_remove_device(isp->dev);
@@ -2110,8 +2119,7 @@
 	mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G);
 	if (IS_ERR(mapping)) {
 		dev_err(isp->dev, "failed to create ARM IOMMU mapping\n");
-		ret = PTR_ERR(mapping);
-		goto error;
+		return PTR_ERR(mapping);
 	}
 
 	isp->mapping = mapping;
@@ -2126,7 +2134,8 @@
 	return 0;
 
 error:
-	isp_detach_iommu(isp);
+	arm_iommu_release_mapping(isp->mapping);
+	isp->mapping = NULL;
 	return ret;
 }
 
@@ -2379,8 +2388,10 @@
 		mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
 		isp->mmio_base[map_idx] =
 			devm_ioremap_resource(isp->dev, mem);
-		if (IS_ERR(isp->mmio_base[map_idx]))
-			return PTR_ERR(isp->mmio_base[map_idx]);
+		if (IS_ERR(isp->mmio_base[map_idx])) {
+			ret = PTR_ERR(isp->mmio_base[map_idx]);
+			goto error;
+		}
 	}
 
 	ret = isp_get_clocks(isp);
--- linux-4.4.0.orig/drivers/media/platform/omap3isp/ispccdc.c
+++ linux-4.4.0/drivers/media/platform/omap3isp/ispccdc.c
@@ -2603,6 +2603,7 @@
 	int ret;
 
 	/* Register the subdev and video node. */
+	ccdc->subdev.dev = vdev->mdev->dev;
 	ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
 	if (ret < 0)
 		goto error;
--- linux-4.4.0.orig/drivers/media/platform/omap3isp/ispccp2.c
+++ linux-4.4.0/drivers/media/platform/omap3isp/ispccp2.c
@@ -1025,6 +1025,7 @@
 	int ret;
 
 	/* Register the subdev and video nodes. */
+	ccp2->subdev.dev = vdev->mdev->dev;
 	ret = v4l2_device_register_subdev(vdev, &ccp2->subdev);
 	if (ret < 0)
 		goto error;
--- linux-4.4.0.orig/drivers/media/platform/omap3isp/ispcsi2.c
+++ linux-4.4.0/drivers/media/platform/omap3isp/ispcsi2.c
@@ -1201,6 +1201,7 @@
 	int ret;
 
 	/* Register the subdev and video nodes. */
+	csi2->subdev.dev = vdev->mdev->dev;
 	ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
 	if (ret < 0)
 		goto error;
--- linux-4.4.0.orig/drivers/media/platform/omap3isp/isppreview.c
+++ linux-4.4.0/drivers/media/platform/omap3isp/isppreview.c
@@ -2223,6 +2223,7 @@
 	int ret;
 
 	/* Register the subdev and video nodes. */
+	prev->subdev.dev = vdev->mdev->dev;
 	ret = v4l2_device_register_subdev(vdev, &prev->subdev);
 	if (ret < 0)
 		goto error;
@@ -2284,7 +2285,7 @@
 	me->ops = &preview_media_ops;
 	ret = media_entity_init(me, PREV_PADS_NUM, pads, 0);
 	if (ret < 0)
-		return ret;
+		goto error_handler_free;
 
 	preview_init_formats(sd, NULL);
 
@@ -2330,6 +2331,8 @@
 	omap3isp_video_cleanup(&prev->video_in);
 error_video_in:
 	media_entity_cleanup(&prev->subdev.entity);
+error_handler_free:
+	v4l2_ctrl_handler_free(&prev->ctrls);
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/media/platform/omap3isp/ispresizer.c
+++ linux-4.4.0/drivers/media/platform/omap3isp/ispresizer.c
@@ -1679,6 +1679,7 @@
 	int ret;
 
 	/* Register the subdev and video nodes. */
+	res->subdev.dev = vdev->mdev->dev;
 	ret = v4l2_device_register_subdev(vdev, &res->subdev);
 	if (ret < 0)
 		goto error;
--- linux-4.4.0.orig/drivers/media/platform/omap3isp/ispstat.c
+++ linux-4.4.0/drivers/media/platform/omap3isp/ispstat.c
@@ -1010,6 +1010,8 @@
 int omap3isp_stat_register_entities(struct ispstat *stat,
 				    struct v4l2_device *vdev)
 {
+	stat->subdev.dev = vdev->mdev->dev;
+
 	return v4l2_device_register_subdev(vdev, &stat->subdev);
 }
 
--- linux-4.4.0.orig/drivers/media/platform/rcar_jpu.c
+++ linux-4.4.0/drivers/media/platform/rcar_jpu.c
@@ -1278,7 +1278,7 @@
 		/* ...issue software reset */
 		ret = jpu_reset(jpu);
 		if (ret)
-			goto device_prepare_rollback;
+			goto jpu_reset_rollback;
 	}
 
 	jpu->ref_count++;
@@ -1286,6 +1286,8 @@
 	mutex_unlock(&jpu->mutex);
 	return 0;
 
+jpu_reset_rollback:
+	clk_disable_unprepare(jpu->clk);
 device_prepare_rollback:
 	mutex_unlock(&jpu->mutex);
 v4l_prepare_rollback:
--- linux-4.4.0.orig/drivers/media/platform/s3c-camif/camif-capture.c
+++ linux-4.4.0/drivers/media/platform/s3c-camif/camif-capture.c
@@ -117,6 +117,8 @@
 
 	if (camif->sensor.power_count == !on)
 		err = v4l2_subdev_call(sensor->sd, core, s_power, on);
+	if (err == -ENOIOCTLCMD)
+		err = 0;
 	if (!err)
 		sensor->power_count += on ? 1 : -1;
 
@@ -1268,16 +1270,17 @@
 {
 	const struct s3c_camif_variant *variant = camif->variant;
 	const struct vp_pix_limits *pix_lim;
-	int i = ARRAY_SIZE(camif_mbus_formats);
+	unsigned int i;
 
 	/* FIXME: constraints against codec or preview path ? */
 	pix_lim = &variant->vp_pix_limits[VP_CODEC];
 
-	while (i-- >= 0)
+	for (i = 0; i < ARRAY_SIZE(camif_mbus_formats); i++)
 		if (camif_mbus_formats[i] == mf->code)
 			break;
 
-	mf->code = camif_mbus_formats[i];
+	if (i == ARRAY_SIZE(camif_mbus_formats))
+		mf->code = camif_mbus_formats[0];
 
 	if (pad == CAMIF_SD_PAD_SINK) {
 		v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH,
--- linux-4.4.0.orig/drivers/media/platform/s5p-g2d/g2d.c
+++ linux-4.4.0/drivers/media/platform/s5p-g2d/g2d.c
@@ -497,7 +497,7 @@
 {
 	struct g2d_ctx *ctx = prv;
 	struct g2d_dev *dev = ctx->dev;
-	struct vb2_buffer *src, *dst;
+	struct vb2_v4l2_buffer *src, *dst;
 	unsigned long flags;
 	u32 cmd = 0;
 
@@ -512,10 +512,10 @@
 	spin_lock_irqsave(&dev->ctrl_lock, flags);
 
 	g2d_set_src_size(dev, &ctx->in);
-	g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0));
+	g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0));
 
 	g2d_set_dst_size(dev, &ctx->out);
-	g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0));
+	g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0));
 
 	g2d_set_rop4(dev, ctx->rop);
 	g2d_set_flip(dev, ctx->flip);
--- linux-4.4.0.orig/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ linux-4.4.0/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -788,14 +788,14 @@
 static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
 {
 	struct s5p_jpeg *jpeg = ctx->jpeg;
-	struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	struct s5p_jpeg_buffer jpeg_buffer;
 	unsigned int word;
 	int c, x, components;
 
 	jpeg_buffer.size = 2; /* Ls */
 	jpeg_buffer.data =
-		(unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sos + 2;
+		(unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2;
 	jpeg_buffer.curr = 0;
 
 	word = 0;
@@ -825,14 +825,14 @@
 static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
 {
 	struct s5p_jpeg *jpeg = ctx->jpeg;
-	struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	struct s5p_jpeg_buffer jpeg_buffer;
 	unsigned int word;
 	int c, i, n, j;
 
 	for (j = 0; j < ctx->out_q.dht.n; ++j) {
 		jpeg_buffer.size = ctx->out_q.dht.len[j];
-		jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
+		jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) +
 				   ctx->out_q.dht.marker[j];
 		jpeg_buffer.curr = 0;
 
@@ -884,13 +884,13 @@
 static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx)
 {
 	struct s5p_jpeg *jpeg = ctx->jpeg;
-	struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	struct s5p_jpeg_buffer jpeg_buffer;
 	int c, x, components;
 
 	jpeg_buffer.size = ctx->out_q.sof_len;
 	jpeg_buffer.data =
-		(unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sof;
+		(unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sof;
 	jpeg_buffer.curr = 0;
 
 	skip(&jpeg_buffer, 5); /* P, Y, X */
@@ -915,14 +915,14 @@
 static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx)
 {
 	struct s5p_jpeg *jpeg = ctx->jpeg;
-	struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	struct s5p_jpeg_buffer jpeg_buffer;
 	unsigned int word;
 	int c, i, j;
 
 	for (j = 0; j < ctx->out_q.dqt.n; ++j) {
 		jpeg_buffer.size = ctx->out_q.dqt.len[j];
-		jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
+		jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) +
 				   ctx->out_q.dqt.marker[j];
 		jpeg_buffer.curr = 0;
 
@@ -1098,10 +1098,10 @@
 			       struct s5p_jpeg_ctx *ctx)
 {
 	int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
-	unsigned int height, width, word, subsampling = 0, sos = 0, sof = 0,
-		     sof_len = 0;
-	unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER],
-		     dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
+	unsigned int height = 0, width = 0, word, subsampling = 0;
+	unsigned int sos = 0, sof = 0, sof_len = 0;
+	unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER];
+	unsigned int dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
 	long length;
 	struct s5p_jpeg_buffer jpeg_buffer;
 
@@ -1262,13 +1262,16 @@
 	return 0;
 }
 
-static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
+static int enum_fmt(struct s5p_jpeg_ctx *ctx,
+		    struct s5p_jpeg_fmt *sjpeg_formats, int n,
 		    struct v4l2_fmtdesc *f, u32 type)
 {
 	int i, num = 0;
+	unsigned int fmt_ver_flag = ctx->jpeg->variant->fmt_ver_flag;
 
 	for (i = 0; i < n; ++i) {
-		if (sjpeg_formats[i].flags & type) {
+		if (sjpeg_formats[i].flags & type &&
+		    sjpeg_formats[i].flags & fmt_ver_flag) {
 			/* index-th format of type type found ? */
 			if (num == f->index)
 				break;
@@ -1294,11 +1297,11 @@
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (ctx->mode == S5P_JPEG_ENCODE)
-		return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+		return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f,
 				SJPEG_FMT_FLAG_ENC_CAPTURE);
 
-	return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
-					SJPEG_FMT_FLAG_DEC_CAPTURE);
+	return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f,
+			SJPEG_FMT_FLAG_DEC_CAPTURE);
 }
 
 static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
@@ -1307,11 +1310,11 @@
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (ctx->mode == S5P_JPEG_ENCODE)
-		return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+		return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f,
 				SJPEG_FMT_FLAG_ENC_OUTPUT);
 
-	return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
-					SJPEG_FMT_FLAG_DEC_OUTPUT);
+	return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f,
+			SJPEG_FMT_FLAG_DEC_OUTPUT);
 }
 
 static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
@@ -1949,7 +1952,7 @@
 
 		v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
 				  V4L2_CID_JPEG_RESTART_INTERVAL,
-				  0, 3, 0xffff, 0);
+				  0, 0xffff, 1, 0);
 		if (ctx->jpeg->variant->version == SJPEG_S5P)
 			mask = ~0x06; /* 422, 420 */
 	}
@@ -2016,15 +2019,15 @@
 {
 	struct s5p_jpeg_ctx *ctx = priv;
 	struct s5p_jpeg *jpeg = ctx->jpeg;
-	struct vb2_buffer *src_buf, *dst_buf;
+	struct vb2_v4l2_buffer *src_buf, *dst_buf;
 	unsigned long src_addr, dst_addr, flags;
 
 	spin_lock_irqsave(&ctx->jpeg->slock, flags);
 
 	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-	src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
-	dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	src_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
 
 	s5p_jpeg_reset(jpeg->regs);
 	s5p_jpeg_poweron(jpeg->regs);
@@ -2097,7 +2100,7 @@
 {
 	struct s5p_jpeg *jpeg = ctx->jpeg;
 	struct s5p_jpeg_fmt *fmt;
-	struct vb2_buffer *vb;
+	struct vb2_v4l2_buffer *vb;
 	struct s5p_jpeg_addr jpeg_addr = {};
 	u32 pix_size, padding_bytes = 0;
 
@@ -2116,7 +2119,7 @@
 		vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 	}
 
-	jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
+	jpeg_addr.y = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0);
 
 	if (fmt->colplanes == 2) {
 		jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
@@ -2134,7 +2137,7 @@
 static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
 {
 	struct s5p_jpeg *jpeg = ctx->jpeg;
-	struct vb2_buffer *vb;
+	struct vb2_v4l2_buffer *vb;
 	unsigned int jpeg_addr = 0;
 
 	if (ctx->mode == S5P_JPEG_ENCODE)
@@ -2142,7 +2145,7 @@
 	else
 		vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 
-	jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+	jpeg_addr = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0);
 	if (jpeg->variant->version == SJPEG_EXYNOS5433 &&
 	    ctx->mode == S5P_JPEG_DECODE)
 		jpeg_addr += ctx->out_q.sos;
@@ -2257,7 +2260,7 @@
 {
 	struct s5p_jpeg *jpeg = ctx->jpeg;
 	struct s5p_jpeg_fmt *fmt;
-	struct vb2_buffer *vb;
+	struct vb2_v4l2_buffer *vb;
 	struct s5p_jpeg_addr jpeg_addr = {};
 	u32 pix_size;
 
@@ -2271,7 +2274,7 @@
 		fmt = ctx->cap_q.fmt;
 	}
 
-	jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
+	jpeg_addr.y = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0);
 
 	if (fmt->colplanes == 2) {
 		jpeg_addr.cb = jpeg_addr.y + pix_size;
@@ -2289,7 +2292,7 @@
 static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
 {
 	struct s5p_jpeg *jpeg = ctx->jpeg;
-	struct vb2_buffer *vb;
+	struct vb2_v4l2_buffer *vb;
 	unsigned int jpeg_addr = 0;
 
 	if (ctx->mode == S5P_JPEG_ENCODE)
@@ -2297,7 +2300,7 @@
 	else
 		vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 
-	jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+	jpeg_addr = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0);
 	exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
 }
 
--- linux-4.4.0.orig/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ linux-4.4.0/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -173,6 +173,7 @@
 		}
 		s5p_mfc_clock_on();
 		ret = s5p_mfc_init_hw(dev);
+		s5p_mfc_clock_off();
 		if (ret)
 			mfc_err("Failed to reinit FW\n");
 	}
@@ -1029,6 +1030,11 @@
 	return !strcmp(dev_name(dev), (char *)data);
 }
 
+static void s5p_mfc_memdev_release(struct device *dev)
+{
+	dma_release_declared_memory(dev);
+}
+
 static void *mfc_get_drv_data(struct platform_device *pdev);
 
 static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev)
@@ -1041,6 +1047,9 @@
 		mfc_err("Not enough memory\n");
 		return -ENOMEM;
 	}
+
+	dev_set_name(dev->mem_dev_l, "%s", "s5p-mfc-l");
+	dev->mem_dev_l->release = s5p_mfc_memdev_release;
 	device_initialize(dev->mem_dev_l);
 	of_property_read_u32_array(dev->plat_dev->dev.of_node,
 			"samsung,mfc-l", mem_info, 2);
@@ -1058,6 +1067,9 @@
 		mfc_err("Not enough memory\n");
 		return -ENOMEM;
 	}
+
+	dev_set_name(dev->mem_dev_r, "%s", "s5p-mfc-r");
+	dev->mem_dev_r->release = s5p_mfc_memdev_release;
 	device_initialize(dev->mem_dev_r);
 	of_property_read_u32_array(dev->plat_dev->dev.of_node,
 			"samsung,mfc-r", mem_info, 2);
--- linux-4.4.0.orig/drivers/media/platform/sh_veu.c
+++ linux-4.4.0/drivers/media/platform/sh_veu.c
@@ -277,13 +277,13 @@
 static void sh_veu_device_run(void *priv)
 {
 	struct sh_veu_dev *veu = priv;
-	struct vb2_buffer *src_buf, *dst_buf;
+	struct vb2_v4l2_buffer *src_buf, *dst_buf;
 
 	src_buf = v4l2_m2m_next_src_buf(veu->m2m_ctx);
 	dst_buf = v4l2_m2m_next_dst_buf(veu->m2m_ctx);
 
 	if (src_buf && dst_buf)
-		sh_veu_process(veu, src_buf, dst_buf);
+		sh_veu_process(veu, &src_buf->vb2_buf, &dst_buf->vb2_buf);
 }
 
 		/* ========== video ioctls ========== */
--- linux-4.4.0.orig/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ linux-4.4.0/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -405,3 +405,7 @@
 	mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
 }
 EXPORT_SYMBOL(soc_camera_calc_client_output);
+
+MODULE_DESCRIPTION("soc-camera scaling-cropping functions");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/media/platform/sti/bdisp/bdisp-hw.c
+++ linux-4.4.0/drivers/media/platform/sti/bdisp/bdisp-hw.c
@@ -14,8 +14,8 @@
 #define MAX_SRC_WIDTH           2048
 
 /* Reset & boot poll config */
-#define POLL_RST_MAX            50
-#define POLL_RST_DELAY_MS       20
+#define POLL_RST_MAX            500
+#define POLL_RST_DELAY_MS       2
 
 enum bdisp_target_plan {
 	BDISP_RGB,
@@ -77,7 +77,7 @@
 	for (i = 0; i < POLL_RST_MAX; i++) {
 		if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE)
 			break;
-		msleep(POLL_RST_DELAY_MS);
+		udelay(POLL_RST_DELAY_MS * 1000);
 	}
 	if (i == POLL_RST_MAX)
 		dev_err(bdisp->dev, "Reset timeout\n");
--- linux-4.4.0.orig/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
+++ linux-4.4.0/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
@@ -652,8 +652,7 @@
 
 	dev_dbg(bdisp->dev, "%s\n", __func__);
 
-	if (mutex_lock_interruptible(&bdisp->lock))
-		return -ERESTARTSYS;
+	mutex_lock(&bdisp->lock);
 
 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
 
@@ -1370,7 +1369,7 @@
 	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
 		dev_err(dev, "failed to set PM\n");
-		goto err_dbg;
+		goto err_pm;
 	}
 
 	/* Continuous memory allocator */
@@ -1407,7 +1406,6 @@
 	vb2_dma_contig_cleanup_ctx(bdisp->alloc_ctx);
 err_pm:
 	pm_runtime_put(dev);
-err_dbg:
 	bdisp_debugfs_remove(bdisp);
 err_v4l2:
 	v4l2_device_unregister(&bdisp->v4l2_dev);
--- linux-4.4.0.orig/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
+++ linux-4.4.0/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
@@ -49,7 +49,7 @@
 #define PID_TABLE_SIZE 1024
 #define POLL_MSECS 50
 
-static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei);
+static int load_c8sectpfe_fw(struct c8sectpfei *fei);
 
 #define TS_PKT_SIZE 188
 #define HEADER_SIZE (4)
@@ -83,7 +83,7 @@
 static void channel_swdemux_tsklet(unsigned long data)
 {
 	struct channel_info *channel = (struct channel_info *)data;
-	struct c8sectpfei *fei = channel->fei;
+	struct c8sectpfei *fei;
 	unsigned long wp, rp;
 	int pos, num_packets, n, size;
 	u8 *buf;
@@ -91,6 +91,8 @@
 	if (unlikely(!channel || !channel->irec))
 		return;
 
+	fei = channel->fei;
+
 	wp = readl(channel->irec + DMA_PRDS_BUSWP_TP(0));
 	rp = readl(channel->irec + DMA_PRDS_BUSRP_TP(0));
 
@@ -141,6 +143,7 @@
 	struct channel_info *channel;
 	u32 tmp;
 	unsigned long *bitmap;
+	int ret;
 
 	switch (dvbdmxfeed->type) {
 	case DMX_TYPE_TS:
@@ -169,8 +172,9 @@
 	}
 
 	if (!atomic_read(&fei->fw_loaded)) {
-		dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__);
-		return -EINVAL;
+		ret = load_c8sectpfe_fw(fei);
+		if (ret)
+			return ret;
 	}
 
 	mutex_lock(&fei->lock);
@@ -265,8 +269,9 @@
 	unsigned long *bitmap;
 
 	if (!atomic_read(&fei->fw_loaded)) {
-		dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__);
-		return -EINVAL;
+		ret = load_c8sectpfe_fw(fei);
+		if (ret)
+			return ret;
 	}
 
 	mutex_lock(&fei->lock);
@@ -880,13 +885,6 @@
 		goto err_clk_disable;
 	}
 
-	/* ensure all other init has been done before requesting firmware */
-	ret = load_c8sectpfe_fw_step1(fei);
-	if (ret) {
-		dev_err(dev, "Couldn't load slim core firmware\n");
-		goto err_clk_disable;
-	}
-
 	c8sectpfe_debugfs_init(fei);
 
 	return 0;
@@ -1091,15 +1089,14 @@
 		phdr->p_memsz - phdr->p_filesz);
 }
 
-static int load_slim_core_fw(const struct firmware *fw, void *context)
+static int load_slim_core_fw(const struct firmware *fw, struct c8sectpfei *fei)
 {
-	struct c8sectpfei *fei = context;
 	Elf32_Ehdr *ehdr;
 	Elf32_Phdr *phdr;
 	u8 __iomem *dst;
 	int err = 0, i;
 
-	if (!fw || !context)
+	if (!fw || !fei)
 		return -EINVAL;
 
 	ehdr = (Elf32_Ehdr *)fw->data;
@@ -1151,29 +1148,35 @@
 	return err;
 }
 
-static void load_c8sectpfe_fw_cb(const struct firmware *fw, void *context)
+static int load_c8sectpfe_fw(struct c8sectpfei *fei)
 {
-	struct c8sectpfei *fei = context;
+	const struct firmware *fw;
 	int err;
 
+	dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA);
+
+	err = request_firmware(&fw, FIRMWARE_MEMDMA, fei->dev);
+	if (err)
+		return err;
+
 	err = c8sectpfe_elf_sanity_check(fei, fw);
 	if (err) {
 		dev_err(fei->dev, "c8sectpfe_elf_sanity_check failed err=(%d)\n"
 			, err);
-		goto err;
+		return err;
 	}
 
-	err = load_slim_core_fw(fw, context);
+	err = load_slim_core_fw(fw, fei);
 	if (err) {
 		dev_err(fei->dev, "load_slim_core_fw failed err=(%d)\n", err);
-		goto err;
+		return err;
 	}
 
 	/* now the firmware is loaded configure the input blocks */
 	err = configure_channels(fei);
 	if (err) {
 		dev_err(fei->dev, "configure_channels failed err=(%d)\n", err);
-		goto err;
+		return err;
 	}
 
 	/*
@@ -1186,28 +1189,6 @@
 	writel(0x1,  fei->io + DMA_CPU_RUN);
 
 	atomic_set(&fei->fw_loaded, 1);
-err:
-	complete_all(&fei->fw_ack);
-}
-
-static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei)
-{
-	int err;
-
-	dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA);
-
-	init_completion(&fei->fw_ack);
-	atomic_set(&fei->fw_loaded, 0);
-
-	err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
-				FIRMWARE_MEMDMA, fei->dev, GFP_KERNEL, fei,
-				load_c8sectpfe_fw_cb);
-
-	if (err) {
-		dev_err(fei->dev, "request_firmware_nowait err: %d.\n", err);
-		complete_all(&fei->fw_ack);
-		return err;
-	}
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/media/platform/ti-vpe/vpe.c
+++ linux-4.4.0/drivers/media/platform/ti-vpe/vpe.c
@@ -330,20 +330,25 @@
 };
 
 /* find our format description corresponding to the passed v4l2_format */
-static struct vpe_fmt *find_format(struct v4l2_format *f)
+static struct vpe_fmt *__find_format(u32 fourcc)
 {
 	struct vpe_fmt *fmt;
 	unsigned int k;
 
 	for (k = 0; k < ARRAY_SIZE(vpe_formats); k++) {
 		fmt = &vpe_formats[k];
-		if (fmt->fourcc == f->fmt.pix.pixelformat)
+		if (fmt->fourcc == fourcc)
 			return fmt;
 	}
 
 	return NULL;
 }
 
+static struct vpe_fmt *find_format(struct v4l2_format *f)
+{
+	return __find_format(f->fmt.pix.pixelformat);
+}
+
 /*
  * there is one vpe_dev structure in the driver, it is shared by
  * all instances.
@@ -1294,6 +1299,7 @@
 		d_vb->timecode = s_vb->timecode;
 
 	d_vb->sequence = ctx->sequence;
+	s_vb->sequence = ctx->sequence;
 
 	d_q_data = &ctx->q_data[Q_DATA_DST];
 	if (d_q_data->flags & Q_DATA_INTERLACED) {
@@ -1434,9 +1440,9 @@
 	int i, depth, depth_bytes;
 
 	if (!fmt || !(fmt->types & type)) {
-		vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
+		vpe_dbg(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
 			pix->pixelformat);
-		return -EINVAL;
+		fmt = __find_format(V4L2_PIX_FMT_YUYV);
 	}
 
 	if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE)
@@ -1994,7 +2000,7 @@
 	v4l2_ctrl_handler_setup(hdl);
 
 	s_q_data = &ctx->q_data[Q_DATA_SRC];
-	s_q_data->fmt = &vpe_formats[2];
+	s_q_data->fmt = __find_format(V4L2_PIX_FMT_YUYV);
 	s_q_data->width = 1920;
 	s_q_data->height = 1080;
 	s_q_data->bytesperline[VPE_LUMA] = (s_q_data->width *
@@ -2129,6 +2135,8 @@
 
 	r = pm_runtime_get_sync(&pdev->dev);
 	WARN_ON(r < 0);
+	if (r)
+		pm_runtime_put_noidle(&pdev->dev);
 	return r < 0 ? r : 0;
 }
 
--- linux-4.4.0.orig/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ linux-4.4.0/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -763,7 +763,11 @@
 		if (kthread_should_stop())
 			break;
 
-		mutex_lock(&dev->mutex);
+		if (!mutex_trylock(&dev->mutex)) {
+			schedule_timeout_uninterruptible(1);
+			continue;
+		}
+
 		cur_jiffies = jiffies;
 		if (dev->cap_seq_resync) {
 			dev->jiffies_vid_cap = cur_jiffies;
@@ -863,8 +867,11 @@
 			"%s-vid-cap", dev->v4l2_dev.name);
 
 	if (IS_ERR(dev->kthread_vid_cap)) {
+		int err = PTR_ERR(dev->kthread_vid_cap);
+
+		dev->kthread_vid_cap = NULL;
 		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-		return PTR_ERR(dev->kthread_vid_cap);
+		return err;
 	}
 	*pstreaming = true;
 	vivid_grab_controls(dev, true);
@@ -913,8 +920,6 @@
 
 	/* shutdown control thread */
 	vivid_grab_controls(dev, false);
-	mutex_unlock(&dev->mutex);
 	kthread_stop(dev->kthread_vid_cap);
 	dev->kthread_vid_cap = NULL;
-	mutex_lock(&dev->mutex);
 }
--- linux-4.4.0.orig/drivers/media/platform/vivid/vivid-kthread-out.c
+++ linux-4.4.0/drivers/media/platform/vivid/vivid-kthread-out.c
@@ -147,7 +147,11 @@
 		if (kthread_should_stop())
 			break;
 
-		mutex_lock(&dev->mutex);
+		if (!mutex_trylock(&dev->mutex)) {
+			schedule_timeout_uninterruptible(1);
+			continue;
+		}
+
 		cur_jiffies = jiffies;
 		if (dev->out_seq_resync) {
 			dev->jiffies_vid_out = cur_jiffies;
@@ -248,8 +252,11 @@
 			"%s-vid-out", dev->v4l2_dev.name);
 
 	if (IS_ERR(dev->kthread_vid_out)) {
+		int err = PTR_ERR(dev->kthread_vid_out);
+
+		dev->kthread_vid_out = NULL;
 		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-		return PTR_ERR(dev->kthread_vid_out);
+		return err;
 	}
 	*pstreaming = true;
 	vivid_grab_controls(dev, true);
@@ -298,8 +305,6 @@
 
 	/* shutdown control thread */
 	vivid_grab_controls(dev, false);
-	mutex_unlock(&dev->mutex);
 	kthread_stop(dev->kthread_vid_out);
 	dev->kthread_vid_out = NULL;
-	mutex_lock(&dev->mutex);
 }
--- linux-4.4.0.orig/drivers/media/platform/vivid/vivid-osd.c
+++ linux-4.4.0/drivers/media/platform/vivid/vivid-osd.c
@@ -167,7 +167,7 @@
 	var->nonstd = 0;
 
 	var->vmode &= ~FB_VMODE_MASK;
-	var->vmode = FB_VMODE_NONINTERLACED;
+	var->vmode |= FB_VMODE_NONINTERLACED;
 
 	/* Dummy values */
 	var->hsync_len = 24;
--- linux-4.4.0.orig/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ linux-4.4.0/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -151,7 +151,11 @@
 		if (kthread_should_stop())
 			break;
 
-		mutex_lock(&dev->mutex);
+		if (!mutex_trylock(&dev->mutex)) {
+			schedule_timeout_uninterruptible(1);
+			continue;
+		}
+
 		cur_jiffies = jiffies;
 		if (dev->sdr_cap_seq_resync) {
 			dev->jiffies_sdr_cap = cur_jiffies;
@@ -311,10 +315,8 @@
 	}
 
 	/* shutdown control thread */
-	mutex_unlock(&dev->mutex);
 	kthread_stop(dev->kthread_sdr_cap);
 	dev->kthread_sdr_cap = NULL;
-	mutex_lock(&dev->mutex);
 }
 
 const struct vb2_ops vivid_sdr_cap_qops = {
--- linux-4.4.0.orig/drivers/media/platform/vivid/vivid-tpg.c
+++ linux-4.4.0/drivers/media/platform/vivid/vivid-tpg.c
@@ -119,36 +119,73 @@
 {
 	unsigned pat;
 	unsigned plane;
+	int ret = 0;
 
 	tpg->max_line_width = max_w;
 	for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
 		for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
 			unsigned pixelsz = plane ? 2 : 4;
 
-			tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
-			if (!tpg->lines[pat][plane])
-				return -ENOMEM;
+			tpg->lines[pat][plane] =
+				vzalloc(max_w * 2 * pixelsz);
+			if (!tpg->lines[pat][plane]) {
+				ret = -ENOMEM;
+				goto free_lines;
+			}
 			if (plane == 0)
 				continue;
-			tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
-			if (!tpg->downsampled_lines[pat][plane])
-				return -ENOMEM;
+			tpg->downsampled_lines[pat][plane] =
+				vzalloc(max_w * 2 * pixelsz);
+			if (!tpg->downsampled_lines[pat][plane]) {
+				ret = -ENOMEM;
+				goto free_lines;
+			}
 		}
 	}
 	for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
 		unsigned pixelsz = plane ? 2 : 4;
 
-		tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
-		if (!tpg->contrast_line[plane])
-			return -ENOMEM;
-		tpg->black_line[plane] = vzalloc(max_w * pixelsz);
-		if (!tpg->black_line[plane])
-			return -ENOMEM;
-		tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
-		if (!tpg->random_line[plane])
-			return -ENOMEM;
+		tpg->contrast_line[plane] =
+			vzalloc(max_w * pixelsz);
+		if (!tpg->contrast_line[plane]) {
+			ret = -ENOMEM;
+			goto free_contrast_line;
+		}
+		tpg->black_line[plane] =
+			vzalloc(max_w * pixelsz);
+		if (!tpg->black_line[plane]) {
+			ret = -ENOMEM;
+			goto free_contrast_line;
+		}
+		tpg->random_line[plane] =
+			vzalloc(max_w * 2 * pixelsz);
+		if (!tpg->random_line[plane]) {
+			ret = -ENOMEM;
+			goto free_contrast_line;
+		}
 	}
 	return 0;
+
+free_contrast_line:
+	for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+		vfree(tpg->contrast_line[plane]);
+		vfree(tpg->black_line[plane]);
+		vfree(tpg->random_line[plane]);
+		tpg->contrast_line[plane] = NULL;
+		tpg->black_line[plane] = NULL;
+		tpg->random_line[plane] = NULL;
+	}
+free_lines:
+	for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
+		for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+			vfree(tpg->lines[pat][plane]);
+			tpg->lines[pat][plane] = NULL;
+			if (plane == 0)
+				continue;
+			vfree(tpg->downsampled_lines[pat][plane]);
+			tpg->downsampled_lines[pat][plane] = NULL;
+		}
+	return ret;
 }
 
 void tpg_free(struct tpg_data *tpg)
--- linux-4.4.0.orig/drivers/media/platform/vivid/vivid-vid-cap.c
+++ linux-4.4.0/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -253,9 +253,6 @@
 	if (vb2_is_streaming(&dev->vb_vid_out_q))
 		dev->can_loop_video = vivid_vid_can_loop(dev);
 
-	if (dev->kthread_vid_cap)
-		return 0;
-
 	dev->vid_cap_seq_count = 0;
 	dprintk(dev, 1, "%s\n", __func__);
 	for (i = 0; i < VIDEO_MAX_FRAME; i++)
@@ -461,6 +458,8 @@
 		tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap));
 		break;
 	}
+	vfree(dev->bitmap_cap);
+	dev->bitmap_cap = NULL;
 	vivid_update_quality(dev);
 	tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap);
 	dev->crop_cap = dev->src_rect;
@@ -991,7 +990,7 @@
 		rect_map_inside(&s->r, &dev->fmt_cap_rect);
 		if (dev->bitmap_cap && (compose->width != s->r.width ||
 					compose->height != s->r.height)) {
-			kfree(dev->bitmap_cap);
+			vfree(dev->bitmap_cap);
 			dev->bitmap_cap = NULL;
 		}
 		*compose = s->r;
--- linux-4.4.0.orig/drivers/media/platform/vivid/vivid-vid-common.c
+++ linux-4.4.0/drivers/media/platform/vivid/vivid-vid-common.c
@@ -33,7 +33,7 @@
 	.type = V4L2_DV_BT_656_1120,
 	/* keep this initialization for compatibility with GCC < 4.4.6 */
 	.reserved = { 0 },
-	V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 14000000, 775000000,
+	V4L2_INIT_BT_TIMINGS(16, MAX_WIDTH, 16, MAX_HEIGHT, 14000000, 775000000,
 		V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
 		V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF,
 		V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED)
--- linux-4.4.0.orig/drivers/media/platform/vivid/vivid-vid-out.c
+++ linux-4.4.0/drivers/media/platform/vivid/vivid-vid-out.c
@@ -173,9 +173,6 @@
 	if (vb2_is_streaming(&dev->vb_vid_cap_q))
 		dev->can_loop_video = vivid_vid_can_loop(dev);
 
-	if (dev->kthread_vid_out)
-		return 0;
-
 	dev->vid_out_seq_count = 0;
 	dprintk(dev, 1, "%s\n", __func__);
 	if (dev->start_streaming_error) {
--- linux-4.4.0.orig/drivers/media/platform/vsp1/vsp1_sru.c
+++ linux-4.4.0/drivers/media/platform/vsp1/vsp1_sru.c
@@ -154,6 +154,7 @@
 	mutex_lock(sru->ctrls.lock);
 	ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0)
 	       & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK);
+	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
 	mutex_unlock(sru->ctrls.lock);
 
 	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
--- linux-4.4.0.orig/drivers/media/radio/radio-raremono.c
+++ linux-4.4.0/drivers/media/radio/radio-raremono.c
@@ -283,6 +283,14 @@
 	return 0;
 }
 
+static void raremono_device_release(struct v4l2_device *v4l2_dev)
+{
+	struct raremono_device *radio = to_raremono_dev(v4l2_dev);
+
+	kfree(radio->buffer);
+	kfree(radio);
+}
+
 /* File system interface */
 static const struct v4l2_file_operations usb_raremono_fops = {
 	.owner		= THIS_MODULE,
@@ -307,12 +315,14 @@
 	struct raremono_device *radio;
 	int retval = 0;
 
-	radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL);
-	if (radio)
-		radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL);
-
-	if (!radio || !radio->buffer)
+	radio = kzalloc(sizeof(*radio), GFP_KERNEL);
+	if (!radio)
+		return -ENOMEM;
+	radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+	if (!radio->buffer) {
+		kfree(radio);
 		return -ENOMEM;
+	}
 
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->intf = intf;
@@ -336,7 +346,8 @@
 	if (retval != 3 ||
 	    (get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) {
 		dev_info(&intf->dev, "this is not Thanko's Raremono.\n");
-		return -ENODEV;
+		retval = -ENODEV;
+		goto free_mem;
 	}
 
 	dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n",
@@ -345,7 +356,7 @@
 	retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
 	if (retval < 0) {
 		dev_err(&intf->dev, "couldn't register v4l2_device\n");
-		return retval;
+		goto free_mem;
 	}
 
 	mutex_init(&radio->lock);
@@ -357,6 +368,7 @@
 	radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops;
 	radio->vdev.lock = &radio->lock;
 	radio->vdev.release = video_device_release_empty;
+	radio->v4l2_dev.release = raremono_device_release;
 
 	usb_set_intfdata(intf, &radio->v4l2_dev);
 
@@ -372,6 +384,10 @@
 	}
 	dev_err(&intf->dev, "could not register video device\n");
 	v4l2_device_unregister(&radio->v4l2_dev);
+
+free_mem:
+	kfree(radio->buffer);
+	kfree(radio);
 	return retval;
 }
 
--- linux-4.4.0.orig/drivers/media/radio/radio-wl1273.c
+++ linux-4.4.0/drivers/media/radio/radio-wl1273.c
@@ -1149,8 +1149,7 @@
 	if (radio->rds_users > 0) {
 		radio->rds_users--;
 		if (radio->rds_users == 0) {
-			if (mutex_lock_interruptible(&core->lock))
-				return -EINTR;
+			mutex_lock(&core->lock);
 
 			radio->irq_flags &= ~WL1273_RDS_EVENT;
 
--- linux-4.4.0.orig/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ linux-4.4.0/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -96,7 +96,7 @@
  */
 int si470x_get_register(struct si470x_device *radio, int regnr)
 {
-	u16 buf[READ_REG_NUM];
+	__be16 buf[READ_REG_NUM];
 	struct i2c_msg msgs[1] = {
 		{
 			.addr = radio->client->addr,
@@ -121,7 +121,7 @@
 int si470x_set_register(struct si470x_device *radio, int regnr)
 {
 	int i;
-	u16 buf[WRITE_REG_NUM];
+	__be16 buf[WRITE_REG_NUM];
 	struct i2c_msg msgs[1] = {
 		{
 			.addr = radio->client->addr,
@@ -151,7 +151,7 @@
 static int si470x_get_all_registers(struct si470x_device *radio)
 {
 	int i;
-	u16 buf[READ_REG_NUM];
+	__be16 buf[READ_REG_NUM];
 	struct i2c_msg msgs[1] = {
 		{
 			.addr = radio->client->addr,
@@ -458,8 +458,10 @@
 
 	free_irq(client->irq, radio);
 	video_unregister_device(&radio->videodev);
-	kfree(radio);
 
+	v4l2_ctrl_handler_free(&radio->hdl);
+	v4l2_device_unregister(&radio->v4l2_dev);
+	kfree(radio);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/media/radio/si470x/radio-si470x-usb.c
+++ linux-4.4.0/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -743,7 +743,7 @@
 	/* start radio */
 	retval = si470x_start_usb(radio);
 	if (retval < 0)
-		goto err_all;
+		goto err_buf;
 
 	/* set initial frequency */
 	si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
@@ -758,6 +758,8 @@
 
 	return 0;
 err_all:
+	usb_kill_urb(radio->int_in_urb);
+err_buf:
 	kfree(radio->buffer);
 err_ctrl:
 	v4l2_ctrl_handler_free(&radio->hdl);
@@ -831,6 +833,7 @@
 	mutex_lock(&radio->lock);
 	v4l2_device_disconnect(&radio->v4l2_dev);
 	video_unregister_device(&radio->videodev);
+	usb_kill_urb(radio->int_in_urb);
 	usb_set_intfdata(intf, NULL);
 	mutex_unlock(&radio->lock);
 	v4l2_device_put(&radio->v4l2_dev);
--- linux-4.4.0.orig/drivers/media/radio/wl128x/fmdrv_common.c
+++ linux-4.4.0/drivers/media/radio/wl128x/fmdrv_common.c
@@ -494,7 +494,8 @@
 		return -EIO;
 	}
 	/* Send response data to caller */
-	if (response != NULL && response_len != NULL && evt_hdr->dlen) {
+	if (response != NULL && response_len != NULL && evt_hdr->dlen &&
+	    evt_hdr->dlen <= payload_len) {
 		/* Skip header info and copy only response data */
 		skb_pull(skb, sizeof(struct fm_event_msg_hdr));
 		memcpy(response, skb->data, evt_hdr->dlen);
@@ -590,6 +591,8 @@
 		return;
 
 	fm_evt_hdr = (void *)skb->data;
+	if (fm_evt_hdr->dlen > sizeof(fmdev->irq_info.flag))
+		return;
 
 	/* Skip header info and copy only response data */
 	skb_pull(skb, sizeof(struct fm_event_msg_hdr));
@@ -1275,8 +1278,9 @@
 
 		switch (action->type) {
 		case ACTION_SEND_COMMAND:	/* Send */
-			if (fmc_send_cmd(fmdev, 0, 0, action->data,
-						action->size, NULL, NULL))
+			ret = fmc_send_cmd(fmdev, 0, 0, action->data,
+					   action->size, NULL, NULL);
+			if (ret)
 				goto rel_fw;
 
 			cmd_cnt++;
@@ -1315,7 +1319,7 @@
 static int fm_power_up(struct fmdev *fmdev, u8 mode)
 {
 	u16 payload;
-	__be16 asic_id, asic_ver;
+	__be16 asic_id = 0, asic_ver = 0;
 	int resp_len, ret;
 	u8 fw_name[50];
 
--- linux-4.4.0.orig/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ linux-4.4.0/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -553,6 +553,7 @@
 
 	/* Register with V4L2 subsystem as RADIO device */
 	if (video_register_device(&gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
+		v4l2_device_unregister(&fmdev->v4l2_dev);
 		fmerr("Could not register video device\n");
 		return -ENOMEM;
 	}
@@ -566,6 +567,8 @@
 	if (ret < 0) {
 		fmerr("(fmdev): Can't init ctrl handler\n");
 		v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
+		video_unregister_device(fmdev->radio_dev);
+		v4l2_device_unregister(&fmdev->v4l2_dev);
 		return -EBUSY;
 	}
 
--- linux-4.4.0.orig/drivers/media/rc/ati_remote.c
+++ linux-4.4.0/drivers/media/rc/ati_remote.c
@@ -843,6 +843,10 @@
 		err("%s: endpoint_in message size==0? \n", __func__);
 		return -ENODEV;
 	}
+	if (!usb_endpoint_is_int_out(endpoint_out)) {
+		err("%s: Unexpected endpoint_out\n", __func__);
+		return -ENODEV;
+	}
 
 	ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
 	rc_dev = rc_allocate_device();
--- linux-4.4.0.orig/drivers/media/rc/ene_ir.c
+++ linux-4.4.0/drivers/media/rc/ene_ir.c
@@ -1123,6 +1123,8 @@
 	struct ene_device *dev = pnp_get_drvdata(pnp_dev);
 	unsigned long flags;
 
+	rc_unregister_device(dev->rdev);
+	del_timer_sync(&dev->tx_sim_timer);
 	spin_lock_irqsave(&dev->hw_lock, flags);
 	ene_rx_disable(dev);
 	ene_rx_restore_hw_buffer(dev);
@@ -1130,7 +1132,6 @@
 
 	free_irq(dev->irq, dev);
 	release_region(dev->hw_io, ENE_IO_SIZE);
-	rc_unregister_device(dev->rdev);
 	kfree(dev);
 }
 
--- linux-4.4.0.orig/drivers/media/rc/iguanair.c
+++ linux-4.4.0/drivers/media/rc/iguanair.c
@@ -430,6 +430,10 @@
 	int ret, pipein, pipeout;
 	struct usb_host_interface *idesc;
 
+	idesc = intf->cur_altsetting;
+	if (idesc->desc.bNumEndpoints < 2)
+		return -ENODEV;
+
 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
 	rc = rc_allocate_device();
 	if (!ir || !rc) {
@@ -444,18 +448,13 @@
 	ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
 	ir->urb_out = usb_alloc_urb(0, GFP_KERNEL);
 
-	if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) {
+	if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out ||
+	    !usb_endpoint_is_int_in(&idesc->endpoint[0].desc) ||
+	    !usb_endpoint_is_int_out(&idesc->endpoint[1].desc)) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	idesc = intf->altsetting;
-
-	if (idesc->desc.bNumEndpoints < 2) {
-		ret = -ENODEV;
-		goto out;
-	}
-
 	ir->rc = rc;
 	ir->dev = &intf->dev;
 	ir->udev = udev;
--- linux-4.4.0.orig/drivers/media/rc/imon.c
+++ linux-4.4.0/drivers/media/rc/imon.c
@@ -164,6 +164,24 @@
 	int touch_y;			/* y coordinate on touchscreen */
 	struct imon_usb_dev_descr *dev_descr; /* device description with key
 						 table for front panels */
+	/*
+	 * Fields for deferring free_imon_context().
+	 *
+	 * Since reference to "struct imon_context" is stored into
+	 * "struct file"->private_data, we need to remember
+	 * how many file descriptors might access this "struct imon_context".
+	 */
+	atomic_t users;
+	/*
+	 * Use a flag for telling display_open()/vfd_write()/lcd_write() that
+	 * imon_disconnect() was already called.
+	 */
+	bool disconnected;
+	/*
+	 * We need to wait for RCU grace period in order to allow
+	 * display_open() to safely check ->disconnected and increment ->users.
+	 */
+	struct rcu_head rcu;
 };
 
 #define TOUCH_TIMEOUT	(HZ/30)
@@ -171,18 +189,18 @@
 /* vfd character device file operations */
 static const struct file_operations vfd_fops = {
 	.owner		= THIS_MODULE,
-	.open		= &display_open,
-	.write		= &vfd_write,
-	.release	= &display_close,
+	.open		= display_open,
+	.write		= vfd_write,
+	.release	= display_close,
 	.llseek		= noop_llseek,
 };
 
 /* lcd character device file operations */
 static const struct file_operations lcd_fops = {
 	.owner		= THIS_MODULE,
-	.open		= &display_open,
-	.write		= &lcd_write,
-	.release	= &display_close,
+	.open		= display_open,
+	.write		= lcd_write,
+	.release	= display_close,
 	.llseek		= noop_llseek,
 };
 
@@ -424,9 +442,6 @@
 	.id_table	= imon_usb_id_table,
 };
 
-/* to prevent races between open() and disconnect(), probing, etc */
-static DEFINE_MUTEX(driver_lock);
-
 /* Module bookkeeping bits */
 MODULE_AUTHOR(MOD_AUTHOR);
 MODULE_DESCRIPTION(MOD_DESC);
@@ -470,9 +485,11 @@
 	struct device *dev = ictx->dev;
 
 	usb_free_urb(ictx->tx_urb);
+	WARN_ON(ictx->dev_present_intf0);
 	usb_free_urb(ictx->rx_urb_intf0);
+	WARN_ON(ictx->dev_present_intf1);
 	usb_free_urb(ictx->rx_urb_intf1);
-	kfree(ictx);
+	kfree_rcu(ictx, rcu);
 
 	dev_dbg(dev, "%s: iMON context freed\n", __func__);
 }
@@ -488,9 +505,6 @@
 	int subminor;
 	int retval = 0;
 
-	/* prevent races with disconnect */
-	mutex_lock(&driver_lock);
-
 	subminor = iminor(inode);
 	interface = usb_find_interface(&imon_driver, subminor);
 	if (!interface) {
@@ -498,17 +512,22 @@
 		retval = -ENODEV;
 		goto exit;
 	}
-	ictx = usb_get_intfdata(interface);
 
-	if (!ictx) {
+	rcu_read_lock();
+	ictx = usb_get_intfdata(interface);
+	if (!ictx || ictx->disconnected || !atomic_inc_not_zero(&ictx->users)) {
+		rcu_read_unlock();
 		pr_err("no context found for minor %d\n", subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
+	rcu_read_unlock();
 
 	mutex_lock(&ictx->lock);
 
-	if (!ictx->display_supported) {
+	if (ictx->disconnected) {
+		retval = -ENODEV;
+	} else if (!ictx->display_supported) {
 		pr_err("display not supported by device\n");
 		retval = -ENODEV;
 	} else if (ictx->display_isopen) {
@@ -522,8 +541,10 @@
 
 	mutex_unlock(&ictx->lock);
 
+	if (retval && atomic_dec_and_test(&ictx->users))
+		free_imon_context(ictx);
+
 exit:
-	mutex_unlock(&driver_lock);
 	return retval;
 }
 
@@ -533,16 +554,9 @@
  */
 static int display_close(struct inode *inode, struct file *file)
 {
-	struct imon_context *ictx = NULL;
+	struct imon_context *ictx = file->private_data;
 	int retval = 0;
 
-	ictx = file->private_data;
-
-	if (!ictx) {
-		pr_err("no context for device\n");
-		return -ENODEV;
-	}
-
 	mutex_lock(&ictx->lock);
 
 	if (!ictx->display_supported) {
@@ -557,6 +571,8 @@
 	}
 
 	mutex_unlock(&ictx->lock);
+	if (atomic_dec_and_test(&ictx->users))
+		free_imon_context(ictx);
 	return retval;
 }
 
@@ -573,6 +589,9 @@
 	int retval = 0;
 	struct usb_ctrlrequest *control_req = NULL;
 
+	if (ictx->disconnected)
+		return -ENODEV;
+
 	/* Check if we need to use control or interrupt urb */
 	if (!ictx->tx_control) {
 		pipe = usb_sndintpipe(ictx->usbdev_intf0,
@@ -929,18 +948,17 @@
 	int offset;
 	int seq;
 	int retval = 0;
-	struct imon_context *ictx;
+	struct imon_context *ictx = file->private_data;
 	const unsigned char vfd_packet6[] = {
 		0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
 
-	ictx = file->private_data;
-	if (!ictx) {
-		pr_err_ratelimited("no context for device\n");
-		return -ENODEV;
-	}
-
 	mutex_lock(&ictx->lock);
 
+	if (ictx->disconnected) {
+		retval = -ENODEV;
+		goto exit;
+	}
+
 	if (!ictx->dev_present_intf0) {
 		pr_err_ratelimited("no iMON device present\n");
 		retval = -ENODEV;
@@ -1013,16 +1031,15 @@
 			 size_t n_bytes, loff_t *pos)
 {
 	int retval = 0;
-	struct imon_context *ictx;
-
-	ictx = file->private_data;
-	if (!ictx) {
-		pr_err_ratelimited("no context for device\n");
-		return -ENODEV;
-	}
+	struct imon_context *ictx = file->private_data;
 
 	mutex_lock(&ictx->lock);
 
+	if (ictx->disconnected) {
+		retval = -ENODEV;
+		goto exit;
+	}
+
 	if (!ictx->display_supported) {
 		pr_err_ratelimited("no iMON display present\n");
 		retval = -ENODEV;
@@ -1629,7 +1646,7 @@
 	if (kc == KEY_KEYBOARD && !ictx->release_code) {
 		ictx->last_keycode = kc;
 		if (!nomouse) {
-			ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
+			ictx->pad_mouse = !ictx->pad_mouse;
 			dev_dbg(dev, "toggling to %s mode\n",
 				ictx->pad_mouse ? "mouse" : "keyboard");
 			spin_unlock_irqrestore(&ictx->kc_lock, flags);
@@ -1644,8 +1661,7 @@
 	spin_unlock_irqrestore(&ictx->kc_lock, flags);
 
 	/* send touchscreen events through input subsystem if touchpad data */
-	if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
-	    buf[7] == 0x86) {
+	if (ictx->touch && len == 8 && buf[7] == 0x86) {
 		imon_touch_event(ictx, buf);
 		return;
 
@@ -2403,7 +2419,6 @@
 	int ifnum, sysfs_err;
 	int ret = 0;
 	struct imon_context *ictx = NULL;
-	struct imon_context *first_if_ctx = NULL;
 	u16 vendor, product;
 
 	usbdev     = usb_get_dev(interface_to_usbdev(interface));
@@ -2415,11 +2430,11 @@
 	dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
 		__func__, vendor, product, ifnum);
 
-	/* prevent races probing devices w/multiple interfaces */
-	mutex_lock(&driver_lock);
-
 	first_if = usb_ifnum_to_if(usbdev, 0);
-	first_if_ctx = usb_get_intfdata(first_if);
+	if (!first_if) {
+		ret = -ENODEV;
+		goto fail;
+	}
 
 	if (ifnum == 0) {
 		ictx = imon_init_intf0(interface, id);
@@ -2428,9 +2443,11 @@
 			ret = -ENODEV;
 			goto fail;
 		}
+		atomic_set(&ictx->users, 1);
 
 	} else {
 		/* this is the secondary interface on the device */
+		struct imon_context *first_if_ctx = usb_get_intfdata(first_if);
 
 		/* fail early if first intf failed to register */
 		if (!first_if_ctx) {
@@ -2444,14 +2461,13 @@
 			ret = -ENODEV;
 			goto fail;
 		}
+		atomic_inc(&ictx->users);
 
 	}
 
 	usb_set_intfdata(interface, ictx);
 
 	if (ifnum == 0) {
-		mutex_lock(&ictx->lock);
-
 		if (product == 0xffdc && ictx->rf_device) {
 			sysfs_err = sysfs_create_group(&interface->dev.kobj,
 						       &imon_rf_attr_group);
@@ -2462,21 +2478,17 @@
 
 		if (ictx->display_supported)
 			imon_init_display(ictx, interface);
-
-		mutex_unlock(&ictx->lock);
 	}
 
 	dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
 		 "usb<%d:%d> initialized\n", vendor, product, ifnum,
 		 usbdev->bus->busnum, usbdev->devnum);
 
-	mutex_unlock(&driver_lock);
 	usb_put_dev(usbdev);
 
 	return 0;
 
 fail:
-	mutex_unlock(&driver_lock);
 	usb_put_dev(usbdev);
 	dev_err(dev, "unable to register, err %d\n", ret);
 
@@ -2492,10 +2504,12 @@
 	struct device *dev;
 	int ifnum;
 
-	/* prevent races with multi-interface device probing and display_open */
-	mutex_lock(&driver_lock);
-
 	ictx = usb_get_intfdata(interface);
+
+	mutex_lock(&ictx->lock);
+	ictx->disconnected = true;
+	mutex_unlock(&ictx->lock);
+
 	dev = ictx->dev;
 	ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
 
@@ -2536,11 +2550,9 @@
 		}
 	}
 
-	if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1)
+	if (atomic_dec_and_test(&ictx->users))
 		free_imon_context(ictx);
 
-	mutex_unlock(&driver_lock);
-
 	dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n",
 		__func__, ifnum);
 }
--- linux-4.4.0.orig/drivers/media/rc/ir-lirc-codec.c
+++ linux-4.4.0/drivers/media/rc/ir-lirc-codec.c
@@ -254,7 +254,7 @@
 		return 0;
 
 	case LIRC_GET_REC_RESOLUTION:
-		val = dev->rx_resolution;
+		val = dev->rx_resolution / 1000;
 		break;
 
 	case LIRC_SET_WIDEBAND_RECEIVER:
@@ -286,11 +286,14 @@
 		if (!dev->max_timeout)
 			return -ENOSYS;
 
+		/* Check for multiply overflow */
+		if (val > U32_MAX / 1000)
+			return -EINVAL;
+
 		tmp = val * 1000;
 
-		if (tmp < dev->min_timeout ||
-		    tmp > dev->max_timeout)
-				return -EINVAL;
+		if (tmp < dev->min_timeout || tmp > dev->max_timeout)
+			return -EINVAL;
 
 		dev->timeout = tmp;
 		break;
--- linux-4.4.0.orig/drivers/media/rc/ir-rc5-decoder.c
+++ linux-4.4.0/drivers/media/rc/ir-rc5-decoder.c
@@ -29,7 +29,7 @@
 #define RC5_BIT_START		(1 * RC5_UNIT)
 #define RC5_BIT_END		(1 * RC5_UNIT)
 #define RC5X_SPACE		(4 * RC5_UNIT)
-#define RC5_TRAILER		(10 * RC5_UNIT) /* In reality, approx 100 */
+#define RC5_TRAILER		(6 * RC5_UNIT) /* In reality, approx 100 */
 
 enum rc5_state {
 	STATE_INACTIVE,
--- linux-4.4.0.orig/drivers/media/rc/ite-cir.c
+++ linux-4.4.0/drivers/media/rc/ite-cir.c
@@ -263,6 +263,8 @@
 
 			if (allowance > ITE_RXDCR_MAX)
 				allowance = ITE_RXDCR_MAX;
+
+			use_demodulator = true;
 		}
 	}
 
--- linux-4.4.0.orig/drivers/media/rc/mceusb.c
+++ linux-4.4.0/drivers/media/rc/mceusb.c
@@ -1103,42 +1103,37 @@
 {
 	int ret;
 	struct device *dev = ir->dev;
-	char *data;
-
-	data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL);
-	if (!data) {
-		dev_err(dev, "%s: memory allocation failed!", __func__);
-		return;
-	}
+	char data[USB_CTRL_MSG_SZ];
 
 	/*
 	 * This is a strange one. Windows issues a set address to the device
 	 * on the receive control pipe and expect a certain value pair back
 	 */
-	ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
-			      USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
-			      data, USB_CTRL_MSG_SZ, HZ * 3);
+	ret = usb_control_msg_recv(ir->usbdev, 0, USB_REQ_SET_ADDRESS,
+				   USB_DIR_IN | USB_TYPE_VENDOR,
+				   0, 0, data, USB_CTRL_MSG_SZ, 3000,
+				   GFP_KERNEL);
 	dev_dbg(dev, "set address - ret = %d", ret);
 	dev_dbg(dev, "set address - data[0] = %d, data[1] = %d",
 						data[0], data[1]);
 
 	/* set feature: bit rate 38400 bps */
-	ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
-			      USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
-			      0xc04e, 0x0000, NULL, 0, HZ * 3);
+	ret = usb_control_msg_send(ir->usbdev, 0,
+				   USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
+				   0xc04e, 0x0000, NULL, 0, 3000, GFP_KERNEL);
 
 	dev_dbg(dev, "set feature - ret = %d", ret);
 
 	/* bRequest 4: set char length to 8 bits */
-	ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
-			      4, USB_TYPE_VENDOR,
-			      0x0808, 0x0000, NULL, 0, HZ * 3);
+	ret = usb_control_msg_send(ir->usbdev, 0,
+				   4, USB_TYPE_VENDOR,
+				   0x0808, 0x0000, NULL, 0, 3000, GFP_KERNEL);
 	dev_dbg(dev, "set char length - retB = %d", ret);
 
 	/* bRequest 2: set handshaking to use DTR/DSR */
-	ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
-			      2, USB_TYPE_VENDOR,
-			      0x0000, 0x0100, NULL, 0, HZ * 3);
+	ret = usb_control_msg_send(ir->usbdev, 0,
+				   2, USB_TYPE_VENDOR,
+				   0x0000, 0x0100, NULL, 0, 3000, GFP_KERNEL);
 	dev_dbg(dev, "set handshake  - retC = %d", ret);
 
 	/* device resume */
@@ -1146,8 +1141,6 @@
 
 	/* get hw/sw revision? */
 	mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
-
-	kfree(data);
 }
 
 static void mceusb_gen2_init(struct mceusb_dev *ir)
@@ -1321,8 +1314,8 @@
 			}
 		}
 	}
-	if (ep_in == NULL) {
-		dev_dbg(&intf->dev, "inbound and/or endpoint not found");
+	if (!ep_in || !ep_out) {
+		dev_dbg(&intf->dev, "required endpoints not found\n");
 		return -ENODEV;
 	}
 
@@ -1370,8 +1363,13 @@
 		goto rc_dev_fail;
 
 	/* wire up inbound data handler */
-	usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
-				mceusb_dev_recv, ir, ep_in->bInterval);
+	if (usb_endpoint_xfer_int(ep_in))
+		usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+				 mceusb_dev_recv, ir, ep_in->bInterval);
+	else
+		usb_fill_bulk_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+				  mceusb_dev_recv, ir);
+
 	ir->urb_in->transfer_dma = ir->dma_in;
 	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
--- linux-4.4.0.orig/drivers/media/rc/rc-main.c
+++ linux-4.4.0/drivers/media/rc/rc-main.c
@@ -61,7 +61,7 @@
 	struct rc_map_list *map;
 
 	map = seek_rc_map(name);
-#ifdef MODULE
+#ifdef CONFIG_MODULES
 	if (!map) {
 		int rc = request_module("%s", name);
 		if (rc < 0) {
--- linux-4.4.0.orig/drivers/media/rc/sunxi-cir.c
+++ linux-4.4.0/drivers/media/rc/sunxi-cir.c
@@ -132,6 +132,8 @@
 	} else if (status & REG_RXINT_RPEI_EN) {
 		ir_raw_event_set_idle(ir->rc, true);
 		ir_raw_event_handle(ir->rc);
+	} else {
+		ir_raw_event_handle(ir->rc);
 	}
 
 	spin_unlock(&ir->ir_lock);
@@ -153,6 +155,8 @@
 	if (!ir)
 		return -ENOMEM;
 
+	spin_lock_init(&ir->ir_lock);
+
 	if (of_device_is_compatible(dn, "allwinner,sun5i-a13-ir"))
 		ir->fifo_size = 64;
 	else
--- linux-4.4.0.orig/drivers/media/tuners/r820t.c
+++ linux-4.4.0/drivers/media/tuners/r820t.c
@@ -410,9 +410,11 @@
 	return 0;
 }
 
-static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
+static inline int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
 {
-	return r820t_write(priv, reg, &val, 1);
+	u8 tmp = val; /* work around GCC PR81715 with asan-stack=1 */
+
+	return r820t_write(priv, reg, &tmp, 1);
 }
 
 static int r820t_read_cache_reg(struct r820t_priv *priv, int reg)
@@ -425,17 +427,18 @@
 		return -EINVAL;
 }
 
-static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
+static inline int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
 				u8 bit_mask)
 {
+	u8 tmp = val;
 	int rc = r820t_read_cache_reg(priv, reg);
 
 	if (rc < 0)
 		return rc;
 
-	val = (rc & ~bit_mask) | (val & bit_mask);
+	tmp = (rc & ~bit_mask) | (tmp & bit_mask);
 
-	return r820t_write(priv, reg, &val, 1);
+	return r820t_write(priv, reg, &tmp, 1);
 }
 
 static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len)
--- linux-4.4.0.orig/drivers/media/tuners/si2157.c
+++ linux-4.4.0/drivers/media/tuners/si2157.c
@@ -168,6 +168,7 @@
 		len = fw->data[fw->size - remaining];
 		if (len > SI2157_ARGLEN) {
 			dev_err(&client->dev, "Bad firmware length\n");
+			ret = -EINVAL;
 			goto err_release_firmware;
 		}
 		memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
--- linux-4.4.0.orig/drivers/media/tuners/tuner-xc2028.c
+++ linux-4.4.0/drivers/media/tuners/tuner-xc2028.c
@@ -281,6 +281,14 @@
 	int i;
 	tuner_dbg("%s called\n", __func__);
 
+	/* free allocated f/w string */
+	if (priv->fname != firmware_name)
+		kfree(priv->fname);
+	priv->fname = NULL;
+
+	priv->state = XC2028_NO_FIRMWARE;
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
 	if (!priv->firm)
 		return;
 
@@ -291,9 +299,6 @@
 
 	priv->firm = NULL;
 	priv->firm_size = 0;
-	priv->state = XC2028_NO_FIRMWARE;
-
-	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 }
 
 static int load_all_firmwares(struct dvb_frontend *fe,
@@ -884,9 +889,8 @@
 	return 0;
 
 fail:
-	priv->state = XC2028_NO_FIRMWARE;
+	free_firmware(priv);
 
-	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 	if (retry_count < 8) {
 		msleep(50);
 		retry_count++;
@@ -1332,11 +1336,8 @@
 	mutex_lock(&xc2028_list_mutex);
 
 	/* only perform final cleanup if this is the last instance */
-	if (hybrid_tuner_report_instance_count(priv) == 1) {
+	if (hybrid_tuner_report_instance_count(priv) == 1)
 		free_firmware(priv);
-		kfree(priv->ctrl.fname);
-		priv->ctrl.fname = NULL;
-	}
 
 	if (priv)
 		hybrid_tuner_release_state(priv);
@@ -1368,9 +1369,16 @@
 			     void *context)
 {
 	struct dvb_frontend *fe = context;
-	struct xc2028_data *priv = fe->tuner_priv;
+	struct xc2028_data *priv;
 	int rc;
 
+	if (!fe) {
+		pr_warn("xc2028: No frontend in %s\n", __func__);
+		return;
+	}
+
+	priv = fe->tuner_priv;
+
 	tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
 	if (!fw) {
 		tuner_err("Could not load firmware %s.\n", priv->fname);
@@ -1399,16 +1407,8 @@
 
 	/*
 	 * Copy the config data.
-	 * For the firmware name, keep a local copy of the string,
-	 * in order to avoid troubles during device release.
 	 */
-	kfree(priv->ctrl.fname);
 	memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
-	if (p->fname) {
-		priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
-		if (priv->ctrl.fname == NULL)
-			rc = -ENOMEM;
-	}
 
 	/*
 	 * If firmware name changed, frees firmware. As free_firmware will
@@ -1423,10 +1423,15 @@
 
 	if (priv->state == XC2028_NO_FIRMWARE) {
 		if (!firmware_name[0])
-			priv->fname = priv->ctrl.fname;
+			priv->fname = kstrdup(p->fname, GFP_KERNEL);
 		else
 			priv->fname = firmware_name;
 
+		if (!priv->fname) {
+			rc = -ENOMEM;
+			goto unlock;
+		}
+
 		rc = request_firmware_nowait(THIS_MODULE, 1,
 					     priv->fname,
 					     priv->i2c_props.adap->dev.parent,
@@ -1439,6 +1444,7 @@
 		} else
 			priv->state = XC2028_WAITING_FIRMWARE;
 	}
+unlock:
 	mutex_unlock(&priv->lock);
 
 	return rc;
--- linux-4.4.0.orig/drivers/media/tuners/xc4000.c
+++ linux-4.4.0/drivers/media/tuners/xc4000.c
@@ -1537,10 +1537,10 @@
 {
 	struct xc4000_priv *priv = fe->tuner_priv;
 
+	mutex_lock(&priv->lock);
 	*freq = priv->freq_hz + priv->freq_offset;
 
 	if (debug) {
-		mutex_lock(&priv->lock);
 		if ((priv->cur_fw.type
 		     & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
 			u16	snr = 0;
@@ -1551,8 +1551,8 @@
 				return 0;
 			}
 		}
-		mutex_unlock(&priv->lock);
 	}
+	mutex_unlock(&priv->lock);
 
 	dprintk(1, "%s()\n", __func__);
 
--- linux-4.4.0.orig/drivers/media/usb/airspy/airspy.c
+++ linux-4.4.0/drivers/media/usb/airspy/airspy.c
@@ -1073,7 +1073,7 @@
 	if (ret) {
 		dev_err(s->dev, "Failed to register as video device (%d)\n",
 				ret);
-		goto err_unregister_v4l2_dev;
+		goto err_free_controls;
 	}
 	dev_info(s->dev, "Registered as %s\n",
 			video_device_node_name(&s->vdev));
@@ -1082,7 +1082,6 @@
 
 err_free_controls:
 	v4l2_ctrl_handler_free(&s->hdl);
-err_unregister_v4l2_dev:
 	v4l2_device_unregister(&s->v4l2_dev);
 err_free_mem:
 	kfree(s);
--- linux-4.4.0.orig/drivers/media/usb/as102/as102_fw.c
+++ linux-4.4.0/drivers/media/usb/as102/as102_fw.c
@@ -101,18 +101,23 @@
 				 unsigned char *cmd,
 				 const struct firmware *firmware) {
 
-	struct as10x_fw_pkt_t fw_pkt;
+	struct as10x_fw_pkt_t *fw_pkt;
 	int total_read_bytes = 0, errno = 0;
 	unsigned char addr_has_changed = 0;
 
+	fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL);
+	if (!fw_pkt)
+		return -ENOMEM;
+
+
 	for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
 		int read_bytes = 0, data_len = 0;
 
 		/* parse intel hex line */
 		read_bytes = parse_hex_line(
 				(u8 *) (firmware->data + total_read_bytes),
-				fw_pkt.raw.address,
-				fw_pkt.raw.data,
+				fw_pkt->raw.address,
+				fw_pkt->raw.data,
 				&data_len,
 				&addr_has_changed);
 
@@ -122,28 +127,28 @@
 		/* detect the end of file */
 		total_read_bytes += read_bytes;
 		if (total_read_bytes == firmware->size) {
-			fw_pkt.u.request[0] = 0x00;
-			fw_pkt.u.request[1] = 0x03;
+			fw_pkt->u.request[0] = 0x00;
+			fw_pkt->u.request[1] = 0x03;
 
 			/* send EOF command */
 			errno = bus_adap->ops->upload_fw_pkt(bus_adap,
 							     (uint8_t *)
-							     &fw_pkt, 2, 0);
+							     fw_pkt, 2, 0);
 			if (errno < 0)
 				goto error;
 		} else {
 			if (!addr_has_changed) {
 				/* prepare command to send */
-				fw_pkt.u.request[0] = 0x00;
-				fw_pkt.u.request[1] = 0x01;
+				fw_pkt->u.request[0] = 0x00;
+				fw_pkt->u.request[1] = 0x01;
 
-				data_len += sizeof(fw_pkt.u.request);
-				data_len += sizeof(fw_pkt.raw.address);
+				data_len += sizeof(fw_pkt->u.request);
+				data_len += sizeof(fw_pkt->raw.address);
 
 				/* send cmd to device */
 				errno = bus_adap->ops->upload_fw_pkt(bus_adap,
 								     (uint8_t *)
-								     &fw_pkt,
+								     fw_pkt,
 								     data_len,
 								     0);
 				if (errno < 0)
@@ -152,6 +157,7 @@
 		}
 	}
 error:
+	kfree(fw_pkt);
 	return (errno == 0) ? total_read_bytes : errno;
 }
 
--- linux-4.4.0.orig/drivers/media/usb/au0828/au0828-core.c
+++ linux-4.4.0/drivers/media/usb/au0828/au0828-core.c
@@ -159,7 +159,7 @@
 	   Set the status so poll routines can check and avoid
 	   access after disconnect.
 	*/
-	dev->dev_state = DEV_DISCONNECTED;
+	set_bit(DEV_DISCONNECTED, &dev->dev_state);
 
 	au0828_rc_unregister(dev);
 	/* Digital TV */
--- linux-4.4.0.orig/drivers/media/usb/au0828/au0828-input.c
+++ linux-4.4.0/drivers/media/usb/au0828/au0828-input.c
@@ -130,7 +130,7 @@
 	bool first = true;
 
 	/* do nothing if device is disconnected */
-	if (ir->dev->dev_state == DEV_DISCONNECTED)
+	if (test_bit(DEV_DISCONNECTED, &ir->dev->dev_state))
 		return 0;
 
 	/* Check IR int */
@@ -260,7 +260,7 @@
 	cancel_delayed_work_sync(&ir->work);
 
 	/* do nothing if device is disconnected */
-	if (ir->dev->dev_state != DEV_DISCONNECTED) {
+	if (!test_bit(DEV_DISCONNECTED, &ir->dev->dev_state)) {
 		/* Disable IR */
 		au8522_rc_clear(ir, 0xe0, 1 << 4);
 	}
--- linux-4.4.0.orig/drivers/media/usb/au0828/au0828-video.c
+++ linux-4.4.0/drivers/media/usb/au0828/au0828-video.c
@@ -104,14 +104,13 @@
 
 static int check_dev(struct au0828_dev *dev)
 {
-	if (dev->dev_state & DEV_DISCONNECTED) {
+	if (test_bit(DEV_DISCONNECTED, &dev->dev_state)) {
 		pr_info("v4l2 ioctl: device not present\n");
 		return -ENODEV;
 	}
 
-	if (dev->dev_state & DEV_MISCONFIGURED) {
-		pr_info("v4l2 ioctl: device is misconfigured; "
-		       "close and open it again\n");
+	if (test_bit(DEV_MISCONFIGURED, &dev->dev_state)) {
+		pr_info("v4l2 ioctl: device is misconfigured; close and open it again\n");
 		return -EIO;
 	}
 	return 0;
@@ -519,8 +518,8 @@
 	if (!dev)
 		return 0;
 
-	if ((dev->dev_state & DEV_DISCONNECTED) ||
-	    (dev->dev_state & DEV_MISCONFIGURED))
+	if (test_bit(DEV_DISCONNECTED, &dev->dev_state) ||
+	    test_bit(DEV_MISCONFIGURED, &dev->dev_state))
 		return 0;
 
 	if (urb->status < 0) {
@@ -712,6 +711,9 @@
 
 	dprintk(1, "au0828_analog_stream_enable called\n");
 
+	if (test_bit(DEV_DISCONNECTED, &d->dev_state))
+		return -ENODEV;
+
 	iface = usb_ifnum_to_if(d->usbdev, 0);
 	if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) {
 		dprintk(1, "Changing intf#0 to alt 5\n");
@@ -766,10 +768,10 @@
 	int ret = 0;
 
 	dev->stream_state = STREAM_INTERRUPT;
-	if (dev->dev_state == DEV_DISCONNECTED)
+	if (test_bit(DEV_DISCONNECTED, &dev->dev_state))
 		return -ENODEV;
 	else if (ret) {
-		dev->dev_state = DEV_MISCONFIGURED;
+		set_bit(DEV_MISCONFIGURED, &dev->dev_state);
 		dprintk(1, "%s device is misconfigured!\n", __func__);
 		return ret;
 	}
@@ -800,9 +802,9 @@
 			return rc;
 		}
 
+		v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
+
 		if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			v4l2_device_call_all(&dev->v4l2_dev, 0, video,
-						s_stream, 1);
 			dev->vid_timeout_running = 1;
 			mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
 		} else if (vq->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
@@ -822,10 +824,11 @@
 
 	dprintk(1, "au0828_stop_streaming called %d\n", dev->streaming_users);
 
-	if (dev->streaming_users-- == 1)
+	if (dev->streaming_users-- == 1) {
 		au0828_uninit_isoc(dev);
+		v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+	}
 
-	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
 	dev->vid_timeout_running = 0;
 	del_timer_sync(&dev->vid_timeout);
 
@@ -854,8 +857,10 @@
 	dprintk(1, "au0828_stop_vbi_streaming called %d\n",
 		dev->streaming_users);
 
-	if (dev->streaming_users-- == 1)
+	if (dev->streaming_users-- == 1) {
 		au0828_uninit_isoc(dev);
+		v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+	}
 
 	spin_lock_irqsave(&dev->slock, flags);
 	if (dev->isoc_ctl.vbi_buf != NULL) {
@@ -958,7 +963,7 @@
 	int ret;
 
 	dprintk(1,
-		"%s called std_set %d dev_state %d stream users %d users %d\n",
+		"%s called std_set %d dev_state %ld stream users %d users %d\n",
 		__func__, dev->std_set_in_tuner_core, dev->dev_state,
 		dev->streaming_users, dev->users);
 
@@ -977,7 +982,7 @@
 		au0828_analog_stream_enable(dev);
 		au0828_analog_stream_reset(dev);
 		dev->stream_state = STREAM_OFF;
-		dev->dev_state |= DEV_INITIALIZED;
+		set_bit(DEV_INITIALIZED, &dev->dev_state);
 	}
 	dev->users++;
 	mutex_unlock(&dev->lock);
@@ -991,7 +996,7 @@
 	struct video_device *vdev = video_devdata(filp);
 
 	dprintk(1,
-		"%s called std_set %d dev_state %d stream users %d users %d\n",
+		"%s called std_set %d dev_state %ld stream users %d users %d\n",
 		__func__, dev->std_set_in_tuner_core, dev->dev_state,
 		dev->streaming_users, dev->users);
 
@@ -1007,7 +1012,7 @@
 		del_timer_sync(&dev->vbi_timeout);
 	}
 
-	if (dev->dev_state == DEV_DISCONNECTED)
+	if (test_bit(DEV_DISCONNECTED, &dev->dev_state))
 		goto end;
 
 	if (dev->users == 1) {
@@ -1036,7 +1041,7 @@
 		.type = V4L2_TUNER_ANALOG_TV,
 	};
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	if (dev->std_set_in_tuner_core)
@@ -1108,7 +1113,7 @@
 	struct video_device *vdev = video_devdata(file);
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	strlcpy(cap->driver, "au0828", sizeof(cap->driver));
@@ -1151,7 +1156,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	f->fmt.pix.width = dev->width;
@@ -1170,7 +1175,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
@@ -1182,7 +1187,7 @@
 	struct au0828_dev *dev = video_drvdata(file);
 	int rc;
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	rc = check_dev(dev);
@@ -1204,7 +1209,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	if (norm == dev->std)
@@ -1236,7 +1241,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	*norm = dev->std;
@@ -1259,7 +1264,7 @@
 		[AU0828_VMUX_DEBUG] = "tv debug"
 	};
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	tmp = input->index;
@@ -1289,7 +1294,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	*i = dev->ctrl_input;
@@ -1300,7 +1305,7 @@
 {
 	int i;
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	switch (AUVI_INPUT(index).type) {
@@ -1385,7 +1390,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	a->index = dev->ctrl_ainput;
@@ -1405,7 +1410,7 @@
 	if (a->index != dev->ctrl_ainput)
 		return -EINVAL;
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 	return 0;
 }
@@ -1417,7 +1422,7 @@
 	if (t->index != 0)
 		return -EINVAL;
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	strcpy(t->name, "Auvitek tuner");
@@ -1437,7 +1442,7 @@
 	if (t->index != 0)
 		return -EINVAL;
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	au0828_init_tuner(dev);
@@ -1459,7 +1464,7 @@
 
 	if (freq->tuner != 0)
 		return -EINVAL;
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 	freq->frequency = dev->ctrl_freq;
 	return 0;
@@ -1474,7 +1479,7 @@
 	if (freq->tuner != 0)
 		return -EINVAL;
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	au0828_init_tuner(dev);
@@ -1500,7 +1505,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	format->fmt.vbi.samples_per_line = dev->vbi_width;
@@ -1526,7 +1531,7 @@
 	if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	cc->bounds.left = 0;
@@ -1548,7 +1553,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	reg->val = au0828_read(dev, reg->reg);
@@ -1561,7 +1566,7 @@
 {
 	struct au0828_dev *dev = video_drvdata(file);
 
-	dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+	dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
 		dev->std_set_in_tuner_core, dev->dev_state);
 
 	return au0828_writereg(dev, reg->reg, reg->val);
--- linux-4.4.0.orig/drivers/media/usb/au0828/au0828.h
+++ linux-4.4.0/drivers/media/usb/au0828/au0828.h
@@ -21,6 +21,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/bitops.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -122,9 +123,9 @@
 
 /* device state */
 enum au0828_dev_state {
-	DEV_INITIALIZED = 0x01,
-	DEV_DISCONNECTED = 0x02,
-	DEV_MISCONFIGURED = 0x04
+	DEV_INITIALIZED = 0,
+	DEV_DISCONNECTED = 1,
+	DEV_MISCONFIGURED = 2
 };
 
 struct au0828_dev;
@@ -248,7 +249,7 @@
 	int input_type;
 	int std_set_in_tuner_core;
 	unsigned int ctrl_input;
-	enum au0828_dev_state dev_state;
+	long unsigned int dev_state; /* defined at enum au0828_dev_state */;
 	enum au0828_stream_state stream_state;
 	wait_queue_head_t open;
 
--- linux-4.4.0.orig/drivers/media/usb/b2c2/flexcop-usb.c
+++ linux-4.4.0/drivers/media/usb/b2c2/flexcop-usb.c
@@ -474,7 +474,16 @@
 static int flexcop_usb_init(struct flexcop_usb *fc_usb)
 {
 	/* use the alternate setting with the larges buffer */
-	usb_set_interface(fc_usb->udev,0,1);
+	int ret = usb_set_interface(fc_usb->udev, 0, 1);
+
+	if (ret) {
+		err("set interface failed.");
+		return ret;
+	}
+
+	if (fc_usb->uintf->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	switch (fc_usb->udev->speed) {
 	case USB_SPEED_LOW:
 		err("cannot handle USB speed because it is too slow.");
--- linux-4.4.0.orig/drivers/media/usb/cpia2/cpia2_usb.c
+++ linux-4.4.0/drivers/media/usb/cpia2/cpia2_usb.c
@@ -665,6 +665,10 @@
 			ERR("%s: usb_alloc_urb error!\n", __func__);
 			for (j = 0; j < i; j++)
 				usb_free_urb(cam->sbuf[j].urb);
+			for (j = 0; j < NUM_SBUF; j++) {
+				kfree(cam->sbuf[j].data);
+				cam->sbuf[j].data = NULL;
+			}
 			return -ENOMEM;
 		}
 
@@ -884,7 +888,6 @@
 	cpia2_unregister_camera(cam);
 	v4l2_device_disconnect(&cam->v4l2_dev);
 	mutex_unlock(&cam->v4l2_lock);
-	v4l2_device_put(&cam->v4l2_dev);
 
 	if(cam->buffers) {
 		DBG("Wakeup waiting processes\n");
@@ -897,6 +900,8 @@
 	DBG("Releasing interface\n");
 	usb_driver_release_interface(&cpia2_driver, intf);
 
+	v4l2_device_put(&cam->v4l2_dev);
+
 	LOG("CPiA2 camera disconnected.\n");
 }
 
--- linux-4.4.0.orig/drivers/media/usb/cpia2/cpia2_v4l.c
+++ linux-4.4.0/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -812,7 +812,7 @@
 	struct camera_data *cam = video_drvdata(file);
 
 	if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-	   buf->index > cam->num_frames)
+	   buf->index >= cam->num_frames)
 		return -EINVAL;
 
 	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
@@ -863,7 +863,7 @@
 
 	if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
 	   buf->memory != V4L2_MEMORY_MMAP ||
-	   buf->index > cam->num_frames)
+	   buf->index >= cam->num_frames)
 		return -EINVAL;
 
 	DBG("QBUF #%d\n", buf->index);
@@ -1248,8 +1248,7 @@
 	LOG("%s v%s\n",
 	    ABOUT, CPIA_VERSION);
 	check_parameters();
-	cpia2_usb_init();
-	return 0;
+	return cpia2_usb_init();
 }
 
 
--- linux-4.4.0.orig/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ linux-4.4.0/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -671,10 +671,8 @@
 
 	spin_lock_init(&adev->slock);
 	err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto err_free_card;
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 			&snd_cx231xx_pcm_capture);
@@ -688,10 +686,9 @@
 	INIT_WORK(&dev->wq_trigger, audio_trigger);
 
 	err = snd_card_register(card);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto err_free_card;
+
 	adev->sndcard = card;
 	adev->udev = dev->udev;
 
@@ -701,6 +698,11 @@
 					    hs_config_info[0].interface_info.
 					    audio_index + 1];
 
+	if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) {
+		err = -ENODEV;
+		goto err_free_card;
+	}
+
 	adev->end_point_addr =
 	    uif->altsetting[0].endpoint[isoc_pipe].desc.
 			bEndpointAddress;
@@ -710,13 +712,20 @@
 		"audio EndPoint Addr 0x%x, Alternate settings: %i\n",
 		adev->end_point_addr, adev->num_alt);
 	adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL);
-
-	if (adev->alt_max_pkt_size == NULL)
-		return -ENOMEM;
+	if (!adev->alt_max_pkt_size) {
+		err = -ENOMEM;
+		goto err_free_card;
+	}
 
 	for (i = 0; i < adev->num_alt; i++) {
-		u16 tmp =
-		    le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
+		u16 tmp;
+
+		if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) {
+			err = -ENODEV;
+			goto err_free_pkt_size;
+		}
+
+		tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
 				wMaxPacketSize);
 		adev->alt_max_pkt_size[i] =
 		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
@@ -726,6 +735,13 @@
 	}
 
 	return 0;
+
+err_free_pkt_size:
+	kfree(adev->alt_max_pkt_size);
+err_free_card:
+	snd_card_free(card);
+
+	return err;
 }
 
 static int cx231xx_audio_fini(struct cx231xx *dev)
--- linux-4.4.0.orig/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ linux-4.4.0/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -1264,7 +1264,10 @@
 				   dev->board.agc_analog_digital_select_gpio,
 				   analog_or_digital);
 
-	return status;
+	if (status < 0)
+		return status;
+
+	return 0;
 }
 
 int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3)
--- linux-4.4.0.orig/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ linux-4.4.0/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -486,7 +486,7 @@
 		.output_mode = OUT_MODE_VIP11,
 		.demod_xfer_mode = 0,
 		.ctl_pin_status_mask = 0xFFFFFFC4,
-		.agc_analog_digital_select_gpio = 0x00,	/* According with PV cxPolaris.inf file */
+		.agc_analog_digital_select_gpio = 0x1c,
 		.tuner_sif_gpio = -1,
 		.tuner_scl_gpio = -1,
 		.tuner_sda_gpio = -1,
@@ -864,6 +864,9 @@
 	 .driver_info = CX231XX_BOARD_CNXT_RDE_250},
 	{USB_DEVICE(0x0572, 0x58A0),
 	 .driver_info = CX231XX_BOARD_CNXT_RDU_250},
+	/* AverMedia DVD EZMaker 7 */
+	{USB_DEVICE(0x07ca, 0xc039),
+	 .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER},
 	{USB_DEVICE(0x2040, 0xb110),
 	 .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL},
 	{USB_DEVICE(0x2040, 0xb111),
@@ -1447,6 +1450,9 @@
 
 	uif = udev->actconfig->interface[idx];
 
+	if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1)
+		return -ENODEV;
+
 	dev->video_mode.end_point_addr = uif->altsetting[0].endpoint[isoc_pipe].desc.bEndpointAddress;
 	dev->video_mode.num_alt = uif->num_altsetting;
 
@@ -1460,7 +1466,12 @@
 		return -ENOMEM;
 
 	for (i = 0; i < dev->video_mode.num_alt; i++) {
-		u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
+		u16 tmp;
+
+		if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1)
+			return -ENODEV;
+
+		tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
 		dev->video_mode.alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
 		dev_dbg(dev->dev,
 			"Alternate setting %i, max size= %i\n", i,
@@ -1477,6 +1488,9 @@
 	}
 	uif = udev->actconfig->interface[idx];
 
+	if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1)
+		return -ENODEV;
+
 	dev->vbi_mode.end_point_addr =
 	    uif->altsetting[0].endpoint[isoc_pipe].desc.
 			bEndpointAddress;
@@ -1493,8 +1507,12 @@
 		return -ENOMEM;
 
 	for (i = 0; i < dev->vbi_mode.num_alt; i++) {
-		u16 tmp =
-		    le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+		u16 tmp;
+
+		if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1)
+			return -ENODEV;
+
+		tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
 				desc.wMaxPacketSize);
 		dev->vbi_mode.alt_max_pkt_size[i] =
 		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
@@ -1514,6 +1532,9 @@
 	}
 	uif = udev->actconfig->interface[idx];
 
+	if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1)
+		return -ENODEV;
+
 	dev->sliced_cc_mode.end_point_addr =
 	    uif->altsetting[0].endpoint[isoc_pipe].desc.
 			bEndpointAddress;
@@ -1528,7 +1549,12 @@
 		return -ENOMEM;
 
 	for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) {
-		u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+		u16 tmp;
+
+		if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1)
+			return -ENODEV;
+
+		tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
 				desc.wMaxPacketSize);
 		dev->sliced_cc_mode.alt_max_pkt_size[i] =
 		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
@@ -1649,7 +1675,7 @@
 	nr = dev->devno;
 
 	assoc_desc = udev->actconfig->intf_assoc[0];
-	if (assoc_desc->bFirstInterface != ifnum) {
+	if (!assoc_desc || assoc_desc->bFirstInterface != ifnum) {
 		dev_err(d, "Not found matching IAD interface\n");
 		retval = -ENODEV;
 		goto err_if;
@@ -1693,6 +1719,11 @@
 		}
 		uif = udev->actconfig->interface[idx];
 
+		if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) {
+			retval = -ENODEV;
+			goto err_video_alt;
+		}
+
 		dev->ts1_mode.end_point_addr =
 		    uif->altsetting[0].endpoint[isoc_pipe].
 				desc.bEndpointAddress;
@@ -1710,7 +1741,14 @@
 		}
 
 		for (i = 0; i < dev->ts1_mode.num_alt; i++) {
-			u16 tmp = le16_to_cpu(uif->altsetting[i].
+			u16 tmp;
+
+			if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) {
+				retval = -ENODEV;
+				goto err_video_alt;
+			}
+
+			tmp = le16_to_cpu(uif->altsetting[i].
 						endpoint[isoc_pipe].desc.
 						wMaxPacketSize);
 			dev->ts1_mode.alt_max_pkt_size[i] =
--- linux-4.4.0.orig/drivers/media/usb/cx231xx/cx231xx-core.c
+++ linux-4.4.0/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -356,7 +356,12 @@
 	 */
 	if ((ven_req->wLength > 4) && ((ven_req->bRequest == 0x4) ||
 					(ven_req->bRequest == 0x5) ||
-					(ven_req->bRequest == 0x6))) {
+					(ven_req->bRequest == 0x6) ||
+
+					/* Internal Master 3 Bus can send
+					 * and receive only 4 bytes per time
+					 */
+					(ven_req->bRequest == 0x2))) {
 		unsend_size = 0;
 		pdata = ven_req->pBuff;
 
@@ -712,6 +717,7 @@
 			break;
 		case CX231XX_BOARD_CNXT_RDE_253S:
 		case CX231XX_BOARD_CNXT_RDU_253S:
+		case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
 			errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
 			break;
 		case CX231XX_BOARD_HAUPPAUGE_EXETER:
@@ -738,7 +744,7 @@
 		case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
 		case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
 		case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
-		errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+			errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
 			break;
 		default:
 			break;
--- linux-4.4.0.orig/drivers/media/usb/cx231xx/cx231xx-video.c
+++ linux-4.4.0/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -1346,7 +1346,7 @@
 		ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
 				(u16)reg->reg, value, 4);
 		reg->val = value[0] | value[1] << 8 |
-			value[2] << 16 | value[3] << 24;
+			value[2] << 16 | (u32)value[3] << 24;
 		reg->size = 4;
 		break;
 	case 1:	/* AFE - read byte */
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb-v2/af9035.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -389,8 +389,10 @@
 			    msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
 				reg |= 0x100000;
 
-			ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
-					msg[0].len - 3);
+			ret = (msg[0].len >= 3) ? af9035_wr_regs(d, reg,
+							         &msg[0].buf[3],
+							         msg[0].len - 3)
+					        : -EOPNOTSUPP;
 		} else {
 			/* I2C write */
 			u8 buf[MAX_XFER_SIZE];
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -1010,8 +1010,8 @@
 void dvb_usbv2_disconnect(struct usb_interface *intf)
 {
 	struct dvb_usb_device *d = usb_get_intfdata(intf);
-	const char *name = d->name;
-	struct device dev = d->udev->dev;
+	const char *devname = kstrdup(dev_name(&d->udev->dev), GFP_KERNEL);
+	const char *drvname = d->name;
 
 	dev_dbg(&d->udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
 			intf->cur_altsetting->desc.bInterfaceNumber);
@@ -1021,8 +1021,9 @@
 
 	dvb_usbv2_exit(d);
 
-	dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n",
-			KBUILD_MODNAME, name);
+	pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n",
+		KBUILD_MODNAME, drvname, devname);
+	kfree(devname);
 }
 EXPORT_SYMBOL(dvb_usbv2_disconnect);
 
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -445,7 +445,7 @@
 	ep = usb_pipe_endpoint(d->udev, lme_int->lme_urb->pipe);
 
 	if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)
-		lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa),
+		lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa);
 
 	lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -503,18 +503,23 @@
 
 static int lme2510_return_status(struct dvb_usb_device *d)
 {
-	int ret = 0;
+	int ret;
 	u8 *data;
 
-	data = kzalloc(10, GFP_KERNEL);
+	data = kzalloc(6, GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
-	ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
-			0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
-	info("Firmware Status: %x (%x)", ret , data[2]);
+	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+			      0x06, 0x80, 0x0302, 0x00,
+			      data, 0x6, 200);
+	if (ret != 6)
+		ret = -EINVAL;
+	else
+		ret = data[2];
+
+	info("Firmware Status: %6ph", data);
 
-	ret = (ret < 0) ? -ENODEV : data[2];
 	kfree(data);
 	return ret;
 }
@@ -1078,8 +1083,6 @@
 
 		if (adap->fe[0]) {
 			info("FE Found M88RS2000");
-			dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config,
-					&d->i2c_adap);
 			st->i2c_tuner_gate_w = 5;
 			st->i2c_tuner_gate_r = 5;
 			st->i2c_tuner_addr = 0x60;
@@ -1145,17 +1148,18 @@
 			ret = st->tuner_config;
 		break;
 	case TUNER_RS2000:
-		ret = st->tuner_config;
+		if (dvb_attach(ts2020_attach, adap->fe[0],
+			       &ts2020_config, &d->i2c_adap))
+			ret = st->tuner_config;
 		break;
 	default:
 		break;
 	}
 
-	if (ret)
+	if (ret) {
 		info("TUN Found %s tuner", tun_msg[ret]);
-	else {
-		info("TUN No tuner found --- resetting device");
-		lme_coldreset(d);
+	} else {
+		info("TUN No tuner found");
 		return -ENODEV;
 	}
 
@@ -1199,6 +1203,7 @@
 static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
 {
 	struct lme2510_state *st = d->priv;
+	int status;
 
 	usb_reset_configuration(d->udev);
 
@@ -1207,12 +1212,16 @@
 
 	st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
 
-	if (lme2510_return_status(d) == 0x44) {
+	status = lme2510_return_status(d);
+	if (status == 0x44) {
 		*name = lme_firmware_switch(d, 0);
 		return COLD;
 	}
 
-	return 0;
+	if (status != 0x47)
+		return -EINVAL;
+
+	return WARM;
 }
 
 static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/az6027.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/az6027.c
@@ -977,6 +977,10 @@
 		if (msg[i].addr == 0x99) {
 			req = 0xBE;
 			index = 0;
+			if (msg[i].len < 1) {
+				i = -EOPNOTSUPP;
+				break;
+			}
 			value = msg[i].buf[0] & 0x00ff;
 			length = 1;
 			az6027_usb_out_op(d, req, value, index, data, length);
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/cxusb.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/cxusb.c
@@ -435,7 +435,8 @@
 	u8 ircode[4];
 	int i;
 
-	cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
+	if (cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4) < 0)
+		return 0;
 
 	*event = 0;
 	*state = REMOTE_NO_KEY_PRESSED;
@@ -818,6 +819,8 @@
 	case XC2028_RESET_CLK:
 		deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
 		break;
+	case XC2028_I2C_FLUSH:
+		break;
 	default:
 		deb_info("%s: unknown command %d, arg %d\n", __func__,
 			 command, arg);
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/dib0700_core.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -677,7 +677,7 @@
 	struct dvb_usb_device *d = purb->context;
 	struct dib0700_rc_response *poll_reply;
 	enum rc_type protocol;
-	u32 uninitialized_var(keycode);
+	u32 keycode;
 	u8 toggle;
 
 	deb_info("%s()\n", __func__);
@@ -719,7 +719,8 @@
 		    poll_reply->nec.data       == 0x00 &&
 		    poll_reply->nec.not_data   == 0xff) {
 			poll_reply->data_state = 2;
-			break;
+			rc_repeat(d->rc_dev);
+			goto resubmit;
 		}
 
 		if ((poll_reply->nec.data ^ poll_reply->nec.not_data) != 0xff) {
@@ -782,6 +783,9 @@
 
 	/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < rc_ep + 1)
+		return -ENODEV;
+
 	purb = usb_alloc_urb(0, GFP_KERNEL);
 	if (purb == NULL) {
 		err("rc usb alloc urb failed");
@@ -801,7 +805,7 @@
 	 * Some devices like the Hauppauge NovaTD model 52009 use an interrupt
 	 * endpoint, while others use a bulk one.
 	 */
-	e = &intf->altsetting[0].endpoint[rc_ep].desc;
+	e = &intf->cur_altsetting->endpoint[rc_ep].desc;
 	if (usb_endpoint_dir_in(e)) {
 		if (usb_endpoint_xfer_bulk(e)) {
 			pipe = usb_rcvbulkpipe(d->udev, rc_ep);
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -292,7 +292,7 @@
 					     stk7700d_dib7000p_mt2266_config)
 		    != 0) {
 			err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__);
-			dvb_detach(&state->dib7000p_ops);
+			dvb_detach(state->dib7000p_ops.set_wbd_ref);
 			return -ENODEV;
 		}
 	}
@@ -326,7 +326,7 @@
 					     stk7700d_dib7000p_mt2266_config)
 		    != 0) {
 			err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__);
-			dvb_detach(&state->dib7000p_ops);
+			dvb_detach(state->dib7000p_ops.set_wbd_ref);
 			return -ENODEV;
 		}
 	}
@@ -431,6 +431,7 @@
 		state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
 		break;
 	case XC2028_RESET_CLK:
+	case XC2028_I2C_FLUSH:
 		break;
 	default:
 		err("%s: unknown command %d, arg %d\n", __func__,
@@ -479,7 +480,7 @@
 				     &stk7700ph_dib7700_xc3028_config) != 0) {
 		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n",
 		    __func__);
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 
@@ -1010,7 +1011,7 @@
 				     &dib7070p_dib7000p_config) != 0) {
 		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n",
 		    __func__);
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 
@@ -1068,7 +1069,7 @@
 				     &dib7770p_dib7000p_config) != 0) {
 		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n",
 		    __func__);
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 
@@ -2417,9 +2418,13 @@
 		8, 0x0486,
 	};
 
+	if (!IS_ENABLED(CONFIG_DVB_DIB9000))
+		return -ENODEV;
 	if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL)
 		return -ENODEV;
 	i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+	if (!i2c)
+		return -ENODEV;
 	if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
 		return -ENODEV;
 	dib0700_set_i2c_speed(adap->dev, 1500);
@@ -2495,10 +2500,14 @@
 		0, 0x00ef,
 		8, 0x0406,
 	};
+	if (!IS_ENABLED(CONFIG_DVB_DIB9000))
+		return -ENODEV;
 	i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe);
 	if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL)
 		return -ENODEV;
 	i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+	if (!i2c)
+		return -ENODEV;
 	if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
 		return -ENODEV;
 
@@ -3036,7 +3045,7 @@
 
 	if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) {
 		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__);
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 	adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
@@ -3089,7 +3098,7 @@
 	/* initialize IC 0 */
 	if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) {
 		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__);
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 
@@ -3119,7 +3128,7 @@
 	i2c = state->dib7000p_ops.get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
 	if (state->dib7000p_ops.i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) {
 		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__);
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 
@@ -3194,7 +3203,7 @@
 				1, 0x10, &tfe7790p_dib7000p_config) != 0) {
 		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n",
 				__func__);
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 	adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap,
@@ -3289,7 +3298,7 @@
 				     stk7070pd_dib7000p_config) != 0) {
 		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n",
 		    __func__);
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 
@@ -3364,7 +3373,7 @@
 					     stk7070pd_dib7000p_config) != 0) {
 			err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n",
 			    __func__);
-			dvb_detach(&state->dib7000p_ops);
+			dvb_detach(state->dib7000p_ops.set_wbd_ref);
 			return -ENODEV;
 		}
 	}
@@ -3600,7 +3609,7 @@
 
 	if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap) == 0) {
 		/* Demodulator not found for some reason? */
-		dvb_detach(&state->dib7000p_ops);
+		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 		return -ENODEV;
 	}
 
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/dibusb-common.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -179,8 +179,20 @@
 
 int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
 {
-	u8 wbuf[1] = { offs };
-	return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
+	u8 *buf;
+	int rc;
+
+	buf = kmalloc(2, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf[0] = offs;
+
+	rc = dibusb_i2c_msg(d, 0x50, &buf[0], 1, &buf[1], 1);
+	*val = buf[1];
+	kfree(buf);
+
+	return rc;
 }
 EXPORT_SYMBOL(dibusb_read_eeprom_byte);
 
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/dibusb-mb.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/dibusb-mb.c
@@ -84,7 +84,7 @@
 
 	if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
 		err("tuner i2c write failed.");
-		ret = -EREMOTEIO;
+		return -EREMOTEIO;
 	}
 
 	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/digitv.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/digitv.c
@@ -226,18 +226,22 @@
 
 static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-	int i;
+	int ret, i;
 	u8 key[5];
 	u8 b[4] = { 0 };
 
 	*event = 0;
 	*state = REMOTE_NO_KEY_PRESSED;
 
-	digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
+	ret = digitv_ctrl_msg(d, USB_READ_REMOTE, 0, NULL, 0, &key[1], 4);
+	if (ret)
+		return ret;
 
 	/* Tell the device we've read the remote. Not sure how necessary
 	   this is, but the Nebula SDK does it. */
-	digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
+	ret = digitv_ctrl_msg(d, USB_WRITE_REMOTE, 0, b, 4, NULL, 0);
+	if (ret)
+		return ret;
 
 	/* if something is inside the buffer, simulate key press */
 	if (key[1] != 0)
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
@@ -35,42 +35,51 @@
 
 int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
 {
-	struct hexline hx;
-	u8 reset;
-	int ret,pos=0;
+	struct hexline *hx;
+	u8 *buf;
+	int ret, pos = 0;
+	u16 cpu_cs_register = cypress[type].cpu_cs_register;
+
+	buf = kmalloc(sizeof(*hx), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	hx = (struct hexline *)buf;
 
 	/* stop the CPU */
-	reset = 1;
-	if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+	buf[0] = 1;
+	if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1)
 		err("could not stop the USB controller CPU.");
 
-	while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
-		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
-		ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+	while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
+		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", hx->addr, hx->len, hx->chk);
+		ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
 
-		if (ret != hx.len) {
+		if (ret != hx->len) {
 			err("error while transferring firmware "
 				"(transferred size: %d, block size: %d)",
-				ret,hx.len);
+				ret, hx->len);
 			ret = -EINVAL;
 			break;
 		}
 	}
 	if (ret < 0) {
 		err("firmware download failed at %d with %d",pos,ret);
+		kfree(buf);
 		return ret;
 	}
 
 	if (ret == 0) {
 		/* restart the CPU */
-		reset = 0;
-		if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+		buf[0] = 0;
+		if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) {
 			err("could not restart the USB controller CPU.");
 			ret = -EINVAL;
 		}
 	} else
 		ret = -EIO;
 
+	kfree(buf);
+
 	return ret;
 }
 EXPORT_SYMBOL(usb_cypress_load_firmware);
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -286,12 +286,15 @@
 void dvb_usb_device_exit(struct usb_interface *intf)
 {
 	struct dvb_usb_device *d = usb_get_intfdata(intf);
-	const char *name = "generic DVB-USB module";
+	const char *default_name = "generic DVB-USB module";
+	char name[40];
 
 	usb_set_intfdata(intf, NULL);
 	if (d != NULL && d->desc != NULL) {
-		name = d->desc->name;
+		strscpy(name, d->desc->name, sizeof(name));
 		dvb_usb_exit(d);
+	} else {
+		strscpy(name, default_name, sizeof(name));
 	}
 	info("%s successfully deinitialized and disconnected.", name);
 
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/dvb-usb-urb.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/dvb-usb-urb.c
@@ -11,7 +11,7 @@
 int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
 	u16 rlen, int delay_ms)
 {
-	int actlen,ret = -ENOMEM;
+	int actlen = 0, ret = -ENOMEM;
 
 	if (!d || wbuf == NULL || wlen == 0)
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/gp8psk.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/gp8psk.c
@@ -163,7 +163,7 @@
 
 static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
-	u8 status, buf;
+	u8 status = 0, buf;
 	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
 
 	if (onoff) {
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -594,9 +594,9 @@
 
 static int technisat_usb2_get_ir(struct dvb_usb_device *d)
 {
-	u8 buf[62], *b;
-	int ret;
+	u8 buf[62];
 	struct ir_raw_event ev;
+	int i, ret;
 
 	buf[0] = GET_IR_DATA_VENDOR_REQUEST;
 	buf[1] = 0x08;
@@ -632,26 +632,25 @@
 		return 0; /* no key pressed */
 
 	/* decoding */
-	b = buf+1;
 
 #if 0
 	deb_rc("RC: %d ", ret);
-	debug_dump(b, ret, deb_rc);
+	debug_dump(buf + 1, ret, deb_rc);
 #endif
 
 	ev.pulse = 0;
-	while (1) {
-		ev.pulse = !ev.pulse;
-		ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
-		ir_raw_event_store(d->rc_dev, &ev);
-
-		b++;
-		if (*b == 0xff) {
+	for (i = 1; i < ARRAY_SIZE(buf); i++) {
+		if (buf[i] == 0xff) {
 			ev.pulse = 0;
 			ev.duration = 888888*2;
 			ir_raw_event_store(d->rc_dev, &ev);
 			break;
 		}
+
+		ev.pulse = !ev.pulse;
+		ev.duration = (buf[i] * FIRMWARE_CLOCK_DIVISOR *
+			       FIRMWARE_CLOCK_TICK) / 1000;
+		ir_raw_event_store(d->rc_dev, &ev);
 	}
 
 	ir_raw_event_handle(d->rc_dev);
--- linux-4.4.0.orig/drivers/media/usb/dvb-usb/ttusb2.c
+++ linux-4.4.0/drivers/media/usb/dvb-usb/ttusb2.c
@@ -78,6 +78,9 @@
 	u8 *s, *r = NULL;
 	int ret = 0;
 
+	if (4 + rlen > 64)
+		return -EIO;
+
 	s = kzalloc(wlen+4, GFP_KERNEL);
 	if (!s)
 		return -ENOMEM;
@@ -381,6 +384,22 @@
 		write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
 		read = msg[i].flags & I2C_M_RD;
 
+		if (3 + msg[i].len > sizeof(obuf)) {
+			err("i2c wr len=%d too high", msg[i].len);
+			break;
+		}
+		if (write_read) {
+			if (3 + msg[i+1].len > sizeof(ibuf)) {
+				err("i2c rd len=%d too high", msg[i+1].len);
+				break;
+			}
+		} else if (read) {
+			if (3 + msg[i].len > sizeof(ibuf)) {
+				err("i2c rd len=%d too high", msg[i].len);
+				break;
+			}
+		}
+
 		obuf[0] = (msg[i].addr << 1) | (write_read | read);
 		if (read)
 			obuf[1] = 0;
--- linux-4.4.0.orig/drivers/media/usb/em28xx/Kconfig
+++ linux-4.4.0/drivers/media/usb/em28xx/Kconfig
@@ -11,7 +11,7 @@
 	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
-	select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT
+	select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
 
 	---help---
 	  This is a video4linux driver for Empia 28xx based TV cards.
--- linux-4.4.0.orig/drivers/media/usb/em28xx/em28xx-cards.c
+++ linux-4.4.0/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2021,13 +2021,13 @@
 		.input           = { {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = TVP5150_COMPOSITE1,
-			.amux     = EM28XX_AUDIO_SRC_LINE,
+			.amux     = EM28XX_AMUX_LINE_IN,
 			.gpio     = terratec_av350_unmute_gpio,
 
 		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = TVP5150_SVIDEO,
-			.amux     = EM28XX_AUDIO_SRC_LINE,
+			.amux     = EM28XX_AMUX_LINE_IN,
 			.gpio     = terratec_av350_unmute_gpio,
 		} },
 	},
@@ -3415,6 +3415,8 @@
 		goto err_free;
 	}
 
+	kref_init(&dev->ref);
+
 	dev->devno = nr;
 	dev->model = id->driver_info;
 	dev->alt   = -1;
@@ -3491,8 +3493,6 @@
 			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
 	}
 
-	kref_init(&dev->ref);
-
 	request_modules(dev);
 
 	/* Should be the last thing to do, to avoid newer udev's to
--- linux-4.4.0.orig/drivers/media/usb/em28xx/em28xx-dvb.c
+++ linux-4.4.0/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1806,6 +1806,8 @@
 		}
 	}
 
+	em28xx_unregister_dvb(dvb);
+
 	/* remove I2C SEC */
 	client = dvb->i2c_client_sec;
 	if (client) {
@@ -1827,7 +1829,6 @@
 		i2c_unregister_device(client);
 	}
 
-	em28xx_unregister_dvb(dvb);
 	kfree(dvb);
 	dev->dvb = NULL;
 	kref_put(&dev->ref, em28xx_free_device);
--- linux-4.4.0.orig/drivers/media/usb/em28xx/em28xx-i2c.c
+++ linux-4.4.0/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -507,9 +507,8 @@
 	if (dev->disconnected)
 		return -ENODEV;
 
-	rc = rt_mutex_trylock(&dev->i2c_bus_lock);
-	if (rc < 0)
-		return rc;
+	if (!rt_mutex_trylock(&dev->i2c_bus_lock))
+		return -EAGAIN;
 
 	/* Switch I2C bus if needed */
 	if (bus != dev->cur_i2c_bus &&
--- linux-4.4.0.orig/drivers/media/usb/em28xx/em28xx-video.c
+++ linux-4.4.0/drivers/media/usb/em28xx/em28xx-video.c
@@ -930,6 +930,8 @@
 
 	em28xx_videodbg("%s\n", __func__);
 
+	dev->v4l2->field_count = 0;
+
 	/* Make sure streaming is not already in progress for this type
 	   of filehandle (e.g. video, vbi) */
 	rc = res_get(dev, vq->type);
@@ -1288,9 +1290,9 @@
 
 	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 	if (!fmt) {
-		em28xx_videodbg("Fourcc format (%08x) invalid.\n",
-				f->fmt.pix.pixelformat);
-		return -EINVAL;
+		fmt = &format[0];
+		em28xx_videodbg("Fourcc format (%08x) invalid. Using default (%08x).\n",
+				f->fmt.pix.pixelformat, fmt->fourcc);
 	}
 
 	if (dev->board.is_em2800) {
--- linux-4.4.0.orig/drivers/media/usb/em28xx/em28xx.h
+++ linux-4.4.0/drivers/media/usb/em28xx/em28xx.h
@@ -187,7 +187,7 @@
    USB 2.0 spec says bulk packet size is always 512 bytes
  */
 #define EM28XX_BULK_PACKET_MULTIPLIER 384
-#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384
+#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 94
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
--- linux-4.4.0.orig/drivers/media/usb/go7007/Kconfig
+++ linux-4.4.0/drivers/media/usb/go7007/Kconfig
@@ -11,7 +11,7 @@
 	select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT
-	select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT
+	select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
 	select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT
 	---help---
 	  This is a video4linux driver for the WIS GO7007 MPEG
--- linux-4.4.0.orig/drivers/media/usb/go7007/go7007-driver.c
+++ linux-4.4.0/drivers/media/usb/go7007/go7007-driver.c
@@ -88,7 +88,7 @@
 	const struct firmware *fw_entry;
 	char fw_name[] = "go7007/go7007fw.bin";
 	void *bounce;
-	int fw_len, rv = 0;
+	int fw_len;
 	u16 intr_val, intr_data;
 
 	if (go->boot_fw == NULL) {
@@ -117,9 +117,11 @@
 	    go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
 			(intr_val & ~0x1) != 0x5a5a) {
 		v4l2_err(go, "error transferring firmware\n");
-		rv = -1;
+		kfree(go->boot_fw);
+		go->boot_fw = NULL;
+		return -1;
 	}
-	return rv;
+	return 0;
 }
 
 MODULE_FIRMWARE("go7007/go7007fw.bin");
--- linux-4.4.0.orig/drivers/media/usb/go7007/go7007-fw.c
+++ linux-4.4.0/drivers/media/usb/go7007/go7007-fw.c
@@ -1499,8 +1499,8 @@
 	return cnt;
 }
 
-static int do_special(struct go7007 *go, u16 type, __le16 *code, int space,
-			int *framelen)
+static noinline_for_stack int do_special(struct go7007 *go, u16 type,
+					 __le16 *code, int space, int *framelen)
 {
 	switch (type) {
 	case SPECIAL_FRM_HEAD:
--- linux-4.4.0.orig/drivers/media/usb/go7007/go7007-usb.c
+++ linux-4.4.0/drivers/media/usb/go7007/go7007-usb.c
@@ -1052,6 +1052,7 @@
 	struct go7007_usb *usb;
 	const struct go7007_usb_board *board;
 	struct usb_device *usbdev = interface_to_usbdev(intf);
+	struct usb_host_endpoint *ep;
 	unsigned num_i2c_devs;
 	char *name;
 	int video_pipe, i, v_urb_len;
@@ -1147,7 +1148,8 @@
 	if (usb->intr_urb->transfer_buffer == NULL)
 		goto allocfail;
 
-	if (go->board_id == GO7007_BOARDID_SENSORAY_2250)
+	ep = usb->usbdev->ep_in[4];
+	if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)
 		usb_fill_bulk_urb(usb->intr_urb, usb->usbdev,
 			usb_rcvbulkpipe(usb->usbdev, 4),
 			usb->intr_urb->transfer_buffer, 2*sizeof(u16),
--- linux-4.4.0.orig/drivers/media/usb/go7007/snd-go7007.c
+++ linux-4.4.0/drivers/media/usb/go7007/snd-go7007.c
@@ -243,22 +243,18 @@
 	gosnd->capturing = 0;
 	ret = snd_card_new(go->dev, index[dev], id[dev], THIS_MODULE, 0,
 			   &gosnd->card);
-	if (ret < 0) {
-		kfree(gosnd);
-		return ret;
-	}
+	if (ret < 0)
+		goto free_snd;
+
 	ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go,
 			&go7007_snd_device_ops);
-	if (ret < 0) {
-		kfree(gosnd);
-		return ret;
-	}
+	if (ret < 0)
+		goto free_card;
+
 	ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm);
-	if (ret < 0) {
-		snd_card_free(gosnd->card);
-		kfree(gosnd);
-		return ret;
-	}
+	if (ret < 0)
+		goto free_card;
+
 	strlcpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
 	strlcpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver));
 	strlcpy(gosnd->card->longname, gosnd->card->shortname,
@@ -269,11 +265,8 @@
 			&go7007_snd_capture_ops);
 
 	ret = snd_card_register(gosnd->card);
-	if (ret < 0) {
-		snd_card_free(gosnd->card);
-		kfree(gosnd);
-		return ret;
-	}
+	if (ret < 0)
+		goto free_card;
 
 	gosnd->substream = NULL;
 	go->snd_context = gosnd;
@@ -281,6 +274,12 @@
 	++dev;
 
 	return 0;
+
+free_card:
+	snd_card_free(gosnd->card);
+free_snd:
+	kfree(gosnd);
+	return ret;
 }
 EXPORT_SYMBOL(go7007_snd_init);
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/cpia1.c
+++ linux-4.4.0/drivers/media/usb/gspca/cpia1.c
@@ -1624,7 +1624,7 @@
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
+	struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
 
 	command_pause(gspca_dev);
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/gspca.c
+++ linux-4.4.0/drivers/media/usb/gspca/gspca.c
@@ -2028,7 +2028,7 @@
 		pr_err("couldn't kzalloc gspca struct\n");
 		return -ENOMEM;
 	}
-	gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
+	gspca_dev->usb_buf = kzalloc(USB_BUF_SZ, GFP_KERNEL);
 	if (!gspca_dev->usb_buf) {
 		pr_err("out of memory\n");
 		ret = -ENOMEM;
@@ -2130,6 +2130,7 @@
 		input_unregister_device(gspca_dev->input_dev);
 #endif
 	v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler);
+	v4l2_device_unregister(&gspca_dev->v4l2_dev);
 	kfree(gspca_dev->usb_buf);
 	kfree(gspca_dev);
 	return ret;
--- linux-4.4.0.orig/drivers/media/usb/gspca/konica.c
+++ linux-4.4.0/drivers/media/usb/gspca/konica.c
@@ -127,6 +127,11 @@
 	if (ret < 0) {
 		pr_err("reg_r err %d\n", ret);
 		gspca_dev->usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, 2);
 	}
 }
 
@@ -188,6 +193,9 @@
 		return -EIO;
 	}
 
+	if (alt->desc.bNumEndpoints < 2)
+		return -ENODEV;
+
 	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 
 	n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
@@ -243,7 +251,7 @@
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
+	struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
 
 	konica_stream_off(gspca_dev);
 #if IS_ENABLED(CONFIG_INPUT)
--- linux-4.4.0.orig/drivers/media/usb/gspca/nw80x.c
+++ linux-4.4.0/drivers/media/usb/gspca/nw80x.c
@@ -1584,6 +1584,11 @@
 	if (ret < 0) {
 		pr_err("reg_r err %d\n", ret);
 		gspca_dev->usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
 		return;
 	}
 	if (len == 1)
--- linux-4.4.0.orig/drivers/media/usb/gspca/ov519.c
+++ linux-4.4.0/drivers/media/usb/gspca/ov519.c
@@ -2116,6 +2116,11 @@
 	} else {
 		PERR("reg_r %02x failed %d\n", index, ret);
 		sd->gspca_dev.usb_err = ret;
+		/*
+		 * Make sure the result is zeroed to avoid uninitialized
+		 * values.
+		 */
+		gspca_dev->usb_buf[0] = 0;
 	}
 
 	return ret;
@@ -2142,6 +2147,11 @@
 	} else {
 		PERR("reg_r8 %02x failed %d\n", index, ret);
 		sd->gspca_dev.usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, 8);
 	}
 
 	return ret;
@@ -3497,6 +3507,16 @@
 		return;
 	}
 
+	if (alt->desc.bNumEndpoints < 1) {
+		sd->gspca_dev.usb_err = -ENODEV;
+		return;
+	}
+
+	if (alt->desc.bNumEndpoints < 1) {
+		sd->gspca_dev.usb_err = -ENODEV;
+		return;
+	}
+
 	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 	reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5);
 
@@ -3622,6 +3642,16 @@
 		return;
 	}
 
+	if (alt->desc.bNumEndpoints < 1) {
+		sd->gspca_dev.usb_err = -ENODEV;
+		return;
+	}
+
+	if (alt->desc.bNumEndpoints < 1) {
+		sd->gspca_dev.usb_err = -ENODEV;
+		return;
+	}
+
 	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 	ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/ov534.c
+++ linux-4.4.0/drivers/media/usb/gspca/ov534.c
@@ -644,6 +644,11 @@
 	if (ret < 0) {
 		pr_err("read failed %d\n", ret);
 		gspca_dev->usb_err = ret;
+		/*
+		 * Make sure the result is zeroed to avoid uninitialized
+		 * values.
+		 */
+		gspca_dev->usb_buf[0] = 0;
 	}
 	return gspca_dev->usb_buf[0];
 }
@@ -1491,8 +1496,13 @@
 	struct v4l2_fract *tpf = &cp->timeperframe;
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	/* Set requested framerate */
-	sd->frame_rate = tpf->denominator / tpf->numerator;
+	if (tpf->numerator == 0 || tpf->denominator == 0)
+		/* Set default framerate */
+		sd->frame_rate = 30;
+	else
+		/* Set requested framerate */
+		sd->frame_rate = tpf->denominator / tpf->numerator;
+
 	if (gspca_dev->streaming)
 		set_frame_rate(gspca_dev);
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/ov534_9.c
+++ linux-4.4.0/drivers/media/usb/gspca/ov534_9.c
@@ -1157,6 +1157,7 @@
 	if (ret < 0) {
 		pr_err("reg_r err %d\n", ret);
 		gspca_dev->usb_err = ret;
+		return 0;
 	}
 	return gspca_dev->usb_buf[0];
 }
--- linux-4.4.0.orig/drivers/media/usb/gspca/se401.c
+++ linux-4.4.0/drivers/media/usb/gspca/se401.c
@@ -115,6 +115,11 @@
 			pr_err("read req failed req %#04x error %d\n",
 			       req, err);
 		gspca_dev->usb_err = err;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, READ_REQ_SIZE);
 	}
 }
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/sn9c20x.c
+++ linux-4.4.0/drivers/media/usb/gspca/sn9c20x.c
@@ -139,6 +139,13 @@
 		}
 	},
 	{
+		.ident = "MSI MS-1039",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MS-1039"),
+		}
+	},
+	{
 		.ident = "MSI MS-1632",
 		.matches = {
 			DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
@@ -924,6 +931,11 @@
 	if (unlikely(result < 0 || result != length)) {
 		pr_err("Read register %02x failed %d\n", reg, result);
 		gspca_dev->usb_err = result;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
 	}
 }
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/sonixb.c
+++ linux-4.4.0/drivers/media/usb/gspca/sonixb.c
@@ -466,6 +466,11 @@
 		dev_err(gspca_dev->v4l2_dev.dev,
 			"Error reading register %02x: %d\n", value, res);
 		gspca_dev->usb_err = res;
+		/*
+		 * Make sure the result is zeroed to avoid uninitialized
+		 * values.
+		 */
+		gspca_dev->usb_buf[0] = 0;
 	}
 }
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/sonixj.c
+++ linux-4.4.0/drivers/media/usb/gspca/sonixj.c
@@ -1175,6 +1175,11 @@
 	if (ret < 0) {
 		pr_err("reg_r err %d\n", ret);
 		gspca_dev->usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
 	}
 }
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/spca1528.c
+++ linux-4.4.0/drivers/media/usb/gspca/spca1528.c
@@ -84,6 +84,11 @@
 	if (ret < 0) {
 		pr_err("reg_r err %d\n", ret);
 		gspca_dev->usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
 	}
 }
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/sq930x.c
+++ linux-4.4.0/drivers/media/usb/gspca/sq930x.c
@@ -438,6 +438,11 @@
 	if (ret < 0) {
 		pr_err("reg_r %04x failed %d\n", value, ret);
 		gspca_dev->usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
 	}
 }
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/stv06xx/stv06xx.c
+++ linux-4.4.0/drivers/media/usb/gspca/stv06xx/stv06xx.c
@@ -293,6 +293,9 @@
 		return -EIO;
 	}
 
+	if (alt->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 	err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size);
 	if (err < 0)
@@ -317,11 +320,21 @@
 
 static int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
 {
+	struct usb_interface_cache *intfc;
 	struct usb_host_interface *alt;
 	struct sd *sd = (struct sd *) gspca_dev;
 
+	intfc = gspca_dev->dev->actconfig->intf_cache[0];
+
+	if (intfc->num_altsetting < 2)
+		return -ENODEV;
+
+	alt = &intfc->altsetting[1];
+
+	if (alt->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	/* Start isoc bandwidth "negotiation" at max isoc bandwidth */
-	alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
 	alt->endpoint[0].desc.wMaxPacketSize =
 		cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
 
@@ -334,6 +347,10 @@
 	struct usb_host_interface *alt;
 	struct sd *sd = (struct sd *) gspca_dev;
 
+	/*
+	 * Existence of altsetting and endpoint was verified in
+	 * stv06xx_isoc_init()
+	 */
 	alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
 	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 	min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
--- linux-4.4.0.orig/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
+++ linux-4.4.0/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
@@ -198,6 +198,10 @@
 	alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
 	if (!alt)
 		return -ENODEV;
+
+	if (alt->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 
 	/* If we don't have enough bandwidth use a lower framerate */
--- linux-4.4.0.orig/drivers/media/usb/gspca/sunplus.c
+++ linux-4.4.0/drivers/media/usb/gspca/sunplus.c
@@ -268,6 +268,11 @@
 	if (ret < 0) {
 		pr_err("reg_r err %d\n", ret);
 		gspca_dev->usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
 	}
 }
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/t613.c
+++ linux-4.4.0/drivers/media/usb/gspca/t613.c
@@ -837,7 +837,7 @@
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
-	struct sd *sd = (struct sd *) gspca_dev;
+	struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
 	int pkt_type;
 
 	if (data[0] == 0x5a) {
--- linux-4.4.0.orig/drivers/media/usb/gspca/topro.c
+++ linux-4.4.0/drivers/media/usb/gspca/topro.c
@@ -4802,7 +4802,11 @@
 	struct v4l2_fract *tpf = &cp->timeperframe;
 	int fr, i;
 
-	sd->framerate = tpf->denominator / tpf->numerator;
+	if (tpf->numerator == 0 || tpf->denominator == 0)
+		sd->framerate = 30;
+	else
+		sd->framerate = tpf->denominator / tpf->numerator;
+
 	if (gspca_dev->streaming)
 		setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
 
--- linux-4.4.0.orig/drivers/media/usb/gspca/vc032x.c
+++ linux-4.4.0/drivers/media/usb/gspca/vc032x.c
@@ -2919,6 +2919,11 @@
 	if (ret < 0) {
 		pr_err("reg_r err %d\n", ret);
 		gspca_dev->usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
 	}
 }
 static void reg_r(struct gspca_dev *gspca_dev,
--- linux-4.4.0.orig/drivers/media/usb/gspca/w996Xcf.c
+++ linux-4.4.0/drivers/media/usb/gspca/w996Xcf.c
@@ -139,6 +139,11 @@
 	} else {
 		pr_err("Read SB reg [01] failed\n");
 		sd->gspca_dev.usb_err = ret;
+		/*
+		 * Make sure the buffer is zeroed to avoid uninitialized
+		 * values.
+		 */
+		memset(sd->gspca_dev.usb_buf, 0, 2);
 	}
 
 	udelay(W9968CF_I2C_BUS_DELAY);
--- linux-4.4.0.orig/drivers/media/usb/gspca/xirlink_cit.c
+++ linux-4.4.0/drivers/media/usb/gspca/xirlink_cit.c
@@ -1455,6 +1455,9 @@
 		return -EIO;
 	}
 
+	if (alt->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 }
 
@@ -2638,6 +2641,7 @@
 
 static int sd_isoc_init(struct gspca_dev *gspca_dev)
 {
+	struct usb_interface_cache *intfc;
 	struct usb_host_interface *alt;
 	int max_packet_size;
 
@@ -2653,8 +2657,17 @@
 		break;
 	}
 
+	intfc = gspca_dev->dev->actconfig->intf_cache[0];
+
+	if (intfc->num_altsetting < 2)
+		return -ENODEV;
+
+	alt = &intfc->altsetting[1];
+
+	if (alt->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	/* Start isoc bandwidth "negotiation" at max isoc bandwidth */
-	alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
 	alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
 
 	return 0;
@@ -2677,6 +2690,9 @@
 		break;
 	}
 
+	/*
+	 * Existence of altsetting and endpoint was verified in sd_isoc_init()
+	 */
 	alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
 	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 	if (packet_size <= min_packet_size)
--- linux-4.4.0.orig/drivers/media/usb/hdpvr/hdpvr-core.c
+++ linux-4.4.0/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -143,6 +143,7 @@
 
 	dev->fw_ver = dev->usbc_buf[1];
 
+	dev->usbc_buf[46] = '\0';
 	v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n",
 			  dev->fw_ver, &dev->usbc_buf[2]);
 
@@ -273,9 +274,12 @@
 	struct hdpvr_device *dev;
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
+#if IS_ENABLED(CONFIG_I2C)
 	struct i2c_client *client;
+#endif
 	size_t buffer_size;
 	int i;
+	int dev_num;
 	int retval = -ENOMEM;
 
 	/* allocate memory for our device state and initialize it */
@@ -293,7 +297,7 @@
 	/* register v4l2_device early so it can be used for printks */
 	if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
 		dev_err(&interface->dev, "v4l2_device_register failed\n");
-		goto error;
+		goto error_free_dev;
 	}
 
 	mutex_init(&dev->io_mutex);
@@ -302,7 +306,7 @@
 	dev->usbc_buf = kmalloc(64, GFP_KERNEL);
 	if (!dev->usbc_buf) {
 		v4l2_err(&dev->v4l2_dev, "Out of memory\n");
-		goto error;
+		goto error_v4l2_unregister;
 	}
 
 	init_waitqueue_head(&dev->wait_buffer);
@@ -310,7 +314,7 @@
 
 	dev->workqueue = create_singlethread_workqueue("hdpvr_buffer");
 	if (!dev->workqueue)
-		goto error;
+		goto err_free_usbc;
 
 	dev->options = hdpvr_default_options;
 
@@ -344,13 +348,13 @@
 	}
 	if (!dev->bulk_in_endpointAddr) {
 		v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
-		goto error;
+		goto error_put_usb;
 	}
 
 	/* init the device */
 	if (hdpvr_device_init(dev)) {
 		v4l2_err(&dev->v4l2_dev, "device init failed\n");
-		goto error;
+		goto error_put_usb;
 	}
 
 	mutex_lock(&dev->io_mutex);
@@ -358,7 +362,7 @@
 		mutex_unlock(&dev->io_mutex);
 		v4l2_err(&dev->v4l2_dev,
 			 "allocating transfer buffers failed\n");
-		goto error;
+		goto error_put_usb;
 	}
 	mutex_unlock(&dev->io_mutex);
 
@@ -366,7 +370,7 @@
 	retval = hdpvr_register_i2c_adapter(dev);
 	if (retval < 0) {
 		v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
-		goto error;
+		goto error_free_buffers;
 	}
 
 	client = hdpvr_register_ir_rx_i2c(dev);
@@ -384,8 +388,17 @@
 	}
 #endif
 
+	dev_num = atomic_inc_return(&dev_nr);
+	if (dev_num >= HDPVR_MAX) {
+		v4l2_err(&dev->v4l2_dev,
+			 "max device number reached, device register failed\n");
+		atomic_dec(&dev_nr);
+		retval = -ENODEV;
+		goto reg_fail;
+	}
+
 	retval = hdpvr_register_videodev(dev, &interface->dev,
-				    video_nr[atomic_inc_return(&dev_nr)]);
+				    video_nr[dev_num]);
 	if (retval < 0) {
 		v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
 		goto reg_fail;
@@ -399,15 +412,20 @@
 reg_fail:
 #if IS_ENABLED(CONFIG_I2C)
 	i2c_del_adapter(&dev->i2c_adapter);
+error_free_buffers:
 #endif
+	hdpvr_free_buffers(dev);
+error_put_usb:
+	usb_put_dev(dev->udev);
+	/* Destroy single thread */
+	destroy_workqueue(dev->workqueue);
+err_free_usbc:
+	kfree(dev->usbc_buf);
+error_v4l2_unregister:
+	v4l2_device_unregister(&dev->v4l2_dev);
+error_free_dev:
+	kfree(dev);
 error:
-	if (dev) {
-		/* Destroy single thread */
-		if (dev->workqueue)
-			destroy_workqueue(dev->workqueue);
-		/* this frees allocated memory */
-		hdpvr_delete(dev);
-	}
 	return retval;
 }
 
--- linux-4.4.0.orig/drivers/media/usb/msi2500/msi2500.c
+++ linux-4.4.0/drivers/media/usb/msi2500/msi2500.c
@@ -1254,7 +1254,7 @@
 	}
 
 	dev->master = master;
-	master->bus_num = 0;
+	master->bus_num = -1;
 	master->num_chipselect = 1;
 	master->transfer_one_message = msi2500_transfer_one_message;
 	spi_master_set_devdata(master, dev);
--- linux-4.4.0.orig/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ linux-4.4.0/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -281,7 +281,8 @@
 {
 	pvr2_hdw_disconnect(mp->hdw);
 	mp->disconnect_flag = !0;
-	pvr2_context_notify(mp);
+	if (!pvr2_context_shutok())
+		pvr2_context_notify(mp);
 }
 
 
--- linux-4.4.0.orig/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
+++ linux-4.4.0/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
@@ -123,15 +123,10 @@
 	memset(&tvdata,0,sizeof(tvdata));
 
 	eeprom = pvr2_eeprom_fetch(hdw);
-	if (!eeprom) return -EINVAL;
+	if (!eeprom)
+		return -EINVAL;
 
-	{
-		struct i2c_client fake_client;
-		/* Newer version expects a useless client interface */
-		fake_client.addr = hdw->eeprom_addr;
-		fake_client.adapter = &hdw->i2c_adap;
-		tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom);
-	}
+	tveeprom_hauppauge_analog(NULL, &tvdata, eeprom);
 
 	trace_eeprom("eeprom assumed v4l tveeprom module");
 	trace_eeprom("eeprom direct call results:");
--- linux-4.4.0.orig/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ linux-4.4.0/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -670,6 +670,8 @@
 
 static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
 {
+	if (v < 0 || v > PVR2_CVAL_INPUT_MAX)
+		return 0;
 	return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
 }
 
--- linux-4.4.0.orig/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
+++ linux-4.4.0/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
@@ -54,6 +54,7 @@
 #define PVR2_CVAL_INPUT_COMPOSITE 2
 #define PVR2_CVAL_INPUT_SVIDEO 3
 #define PVR2_CVAL_INPUT_RADIO 4
+#define PVR2_CVAL_INPUT_MAX PVR2_CVAL_INPUT_RADIO
 
 enum pvr2_config {
 	pvr2_config_empty,    /* No configuration */
--- linux-4.4.0.orig/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ linux-4.4.0/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -886,8 +886,12 @@
 	pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
 	pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
 	if (!list_empty(&vp->dev_video->devbase.fh_list) ||
-	    !list_empty(&vp->dev_radio->devbase.fh_list))
+	    (vp->dev_radio &&
+	     !list_empty(&vp->dev_radio->devbase.fh_list))) {
+		pvr2_trace(PVR2_TRACE_STRUCT,
+			   "pvr2_v4l2 internal_check exit-empty id=%p", vp);
 		return;
+	}
 	pvr2_v4l2_destroy_no_lock(vp);
 }
 
@@ -961,7 +965,8 @@
 	kfree(fhp);
 	if (vp->channel.mc_head->disconnect_flag &&
 	    list_empty(&vp->dev_video->devbase.fh_list) &&
-	    list_empty(&vp->dev_radio->devbase.fh_list)) {
+	    (!vp->dev_radio ||
+	     list_empty(&vp->dev_radio->devbase.fh_list))) {
 		pvr2_v4l2_destroy_no_lock(vp);
 	}
 	return 0;
--- linux-4.4.0.orig/drivers/media/usb/pwc/pwc-if.c
+++ linux-4.4.0/drivers/media/usb/pwc/pwc-if.c
@@ -91,6 +91,7 @@
 	{ USB_DEVICE(0x0471, 0x0312) },
 	{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
 	{ USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
+	{ USB_DEVICE(0x0471, 0x032C) }, /* Philips SPC 880NC PC Camera */
 	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
 	{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
 	{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
@@ -811,6 +812,11 @@
 			name = "Philips SPC 900NC webcam";
 			type_id = 740;
 			break;
+		case 0x032C:
+			PWC_INFO("Philips SPC 880NC USB webcam detected.\n");
+			name = "Philips SPC 880NC webcam";
+			type_id = 740;
+			break;
 		default:
 			return -ENODEV;
 			break;
@@ -1113,8 +1119,10 @@
 
 	return 0;
 
+#ifdef CONFIG_USB_PWC_INPUT_EVDEV
 err_video_unreg:
 	video_unregister_device(&pdev->vdev);
+#endif
 err_unregister_v4l2_dev:
 	v4l2_device_unregister(&pdev->v4l2_dev);
 err_free_controls:
--- linux-4.4.0.orig/drivers/media/usb/siano/smsusb.c
+++ linux-4.4.0/drivers/media/usb/siano/smsusb.c
@@ -200,22 +200,30 @@
 static int smsusb_sendrequest(void *context, void *buffer, size_t size)
 {
 	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
-	struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
-	int dummy;
+	struct sms_msg_hdr *phdr;
+	int dummy, ret;
 
 	if (dev->state != SMSUSB_ACTIVE) {
 		pr_debug("Device not active yet\n");
 		return -ENOENT;
 	}
 
+	phdr = kmalloc(size, GFP_KERNEL);
+	if (!phdr)
+		return -ENOMEM;
+	memcpy(phdr, buffer, size);
+
 	pr_debug("sending %s(%d) size: %d\n",
 		  smscore_translate_msg(phdr->msg_type), phdr->msg_type,
 		  phdr->msg_length);
 
 	smsendian_handle_tx_message((struct sms_msg_data *) phdr);
-	smsendian_handle_message_header((struct sms_msg_hdr *)buffer);
-	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
-			    buffer, size, &dummy, 1000);
+	smsendian_handle_message_header((struct sms_msg_hdr *)phdr);
+	ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
+			    phdr, size, &dummy, 1000);
+
+	kfree(phdr);
+	return ret;
 }
 
 static char *smsusb1_fw_lkup[] = {
@@ -383,6 +391,7 @@
 	struct smsusb_device_t *dev;
 	void *mdev;
 	int i, rc;
+	int align = 0;
 
 	/* create device object */
 	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
@@ -394,6 +403,24 @@
 	dev->udev = interface_to_usbdev(intf);
 	dev->state = SMSUSB_DISCONNECTED;
 
+	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+		struct usb_endpoint_descriptor *desc =
+				&intf->cur_altsetting->endpoint[i].desc;
+
+		if (desc->bEndpointAddress & USB_DIR_IN) {
+			dev->in_ep = desc->bEndpointAddress;
+			align = usb_endpoint_maxp(desc) - sizeof(struct sms_msg_hdr);
+		} else {
+			dev->out_ep = desc->bEndpointAddress;
+		}
+	}
+
+	pr_debug("in_ep = %02x, out_ep = %02x\n", dev->in_ep, dev->out_ep);
+	if (!dev->in_ep || !dev->out_ep || align < 0) {  /* Missing endpoints? */
+		smsusb_term_device(intf);
+		return -ENODEV;
+	}
+
 	params.device_type = sms_get_board(board_id)->type;
 
 	switch (params.device_type) {
@@ -408,24 +435,12 @@
 		/* fall-thru */
 	default:
 		dev->buffer_size = USB2_BUFFER_SIZE;
-		dev->response_alignment =
-		    le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
-		    sizeof(struct sms_msg_hdr);
+		dev->response_alignment = align;
 
 		params.flags |= SMS_DEVICE_FAMILY2;
 		break;
 	}
 
-	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
-		if (intf->cur_altsetting->endpoint[i].desc. bEndpointAddress & USB_DIR_IN)
-			dev->in_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
-		else
-			dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
-	}
-
-	pr_debug("in_ep = %02x, out_ep = %02x\n",
-		dev->in_ep, dev->out_ep);
-
 	params.device = &dev->udev->dev;
 	params.buffer_size = dev->buffer_size;
 	params.num_buffers = MAX_BUFFERS;
--- linux-4.4.0.orig/drivers/media/usb/stk1160/stk1160-video.c
+++ linux-4.4.0/drivers/media/usb/stk1160/stk1160-video.c
@@ -110,7 +110,7 @@
 static inline
 void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
 {
-	int linesdone, lineoff, lencopy;
+	int linesdone, lineoff, lencopy, offset;
 	int bytesperline = dev->width * 2;
 	struct stk1160_buffer *buf = dev->isoc_ctl.buf;
 	u8 *dst = buf->mem;
@@ -151,8 +151,13 @@
 	 * Check if we have enough space left in the buffer.
 	 * In that case, we force loop exit after copy.
 	 */
-	if (lencopy > buf->bytesused - buf->length) {
-		lencopy = buf->bytesused - buf->length;
+	offset = dst - (u8 *)buf->mem;
+	if (offset > buf->length) {
+		dev_warn_ratelimited(dev->dev, "out of bounds offset\n");
+		return;
+	}
+	if (lencopy > buf->length - offset) {
+		lencopy = buf->length - offset;
 		remain = lencopy;
 	}
 
@@ -194,8 +199,13 @@
 		 * Check if we have enough space left in the buffer.
 		 * In that case, we force loop exit after copy.
 		 */
-		if (lencopy > buf->bytesused - buf->length) {
-			lencopy = buf->bytesused - buf->length;
+		offset = dst - (u8 *)buf->mem;
+		if (offset > buf->length) {
+			dev_warn_ratelimited(dev->dev, "offset out of bounds\n");
+			return;
+		}
+		if (lencopy > buf->length - offset) {
+			lencopy = buf->length - offset;
 			remain = lencopy;
 		}
 
--- linux-4.4.0.orig/drivers/media/usb/stkwebcam/stk-webcam.c
+++ linux-4.4.0/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -642,8 +642,7 @@
 		dev->owner = NULL;
 	}
 
-	if (is_present(dev))
-		usb_autopm_put_interface(dev->interface);
+	usb_autopm_put_interface(dev->interface);
 	mutex_unlock(&dev->lock);
 	return v4l2_fh_release(fp);
 }
--- linux-4.4.0.orig/drivers/media/usb/tm6000/tm6000-dvb.c
+++ linux-4.4.0/drivers/media/usb/tm6000/tm6000-dvb.c
@@ -111,6 +111,7 @@
 			printk(KERN_ERR "tm6000:  error %s\n", __func__);
 			kfree(urb->transfer_buffer);
 			usb_free_urb(urb);
+			dev->dvb->bulk_urb = NULL;
 		}
 	}
 }
@@ -143,6 +144,7 @@
 	dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
 	if (dvb->bulk_urb->transfer_buffer == NULL) {
 		usb_free_urb(dvb->bulk_urb);
+		dvb->bulk_urb = NULL;
 		printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
 		return -ENOMEM;
 	}
@@ -156,6 +158,10 @@
 	if (ret < 0) {
 		printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
 							ret, __func__);
+
+		kfree(dvb->bulk_urb->transfer_buffer);
+		usb_free_urb(dvb->bulk_urb);
+		dvb->bulk_urb = NULL;
 		return ret;
 	} else
 		printk(KERN_ERR "tm6000: pipe resetted\n");
@@ -170,6 +176,7 @@
 
 		kfree(dvb->bulk_urb->transfer_buffer);
 		usb_free_urb(dvb->bulk_urb);
+		dvb->bulk_urb = NULL;
 		return ret;
 	}
 
@@ -275,6 +282,11 @@
 
 	ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
 					THIS_MODULE, &dev->udev->dev, adapter_nr);
+	if (ret < 0) {
+		pr_err("tm6000: couldn't register the adapter!\n");
+		goto err;
+	}
+
 	dvb->adapter.priv = dev;
 
 	if (dvb->frontend) {
--- linux-4.4.0.orig/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ linux-4.4.0/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -272,7 +272,7 @@
 
 	dprintk("%s\n", __func__);
 
-	b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
+	b = kzalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
 	if (!b)
 		return -ENOMEM;
 
--- linux-4.4.0.orig/drivers/media/usb/usbtv/usbtv-audio.c
+++ linux-4.4.0/drivers/media/usb/usbtv/usbtv-audio.c
@@ -278,6 +278,9 @@
 {
 	struct usbtv *chip = container_of(work, struct usbtv, snd_trigger);
 
+	if (!chip->snd)
+		return;
+
 	if (atomic_read(&chip->snd_stream))
 		usbtv_audio_start(chip);
 	else
@@ -378,8 +381,10 @@
 
 void usbtv_audio_free(struct usbtv *usbtv)
 {
+	cancel_work_sync(&usbtv->snd_trigger);
+
 	if (usbtv->snd && usbtv->udev) {
-		snd_card_free(usbtv->snd);
+		snd_card_free_when_closed(usbtv->snd);
 		usbtv->snd = NULL;
 	}
 }
--- linux-4.4.0.orig/drivers/media/usb/usbtv/usbtv-core.c
+++ linux-4.4.0/drivers/media/usb/usbtv/usbtv-core.c
@@ -42,7 +42,7 @@
 
 		ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			value, index, NULL, 0, 0);
+			value, index, NULL, 0, USB_CTRL_GET_TIMEOUT);
 		if (ret < 0)
 			return ret;
 	}
@@ -95,6 +95,9 @@
 	return 0;
 
 usbtv_audio_fail:
+	/* we must not free at this point */
+	v4l2_device_get(&usbtv->v4l2_dev);
+	/* this will undo the v4l2_device_get() */
 	usbtv_video_free(usbtv);
 
 usbtv_video_fail:
@@ -127,6 +130,7 @@
 
 static struct usb_device_id usbtv_id_table[] = {
 	{ USB_DEVICE(0x1b71, 0x3002) },
+	{ USB_DEVICE(0x1f71, 0x3301) },
 	{}
 };
 MODULE_DEVICE_TABLE(usb, usbtv_id_table);
--- linux-4.4.0.orig/drivers/media/usb/usbvision/usbvision-video.c
+++ linux-4.4.0/drivers/media/usb/usbvision/usbvision-video.c
@@ -1463,9 +1463,23 @@
 
 	if (usbvision_device_data[model].interface >= 0)
 		interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
-	else
+	else if (ifnum < dev->actconfig->desc.bNumInterfaces)
 		interface = &dev->actconfig->interface[ifnum]->altsetting[0];
+	else {
+		dev_err(&intf->dev, "interface %d is invalid, max is %d\n",
+		    ifnum, dev->actconfig->desc.bNumInterfaces - 1);
+		ret = -ENODEV;
+		goto err_usb;
+	}
+
+	if (interface->desc.bNumEndpoints < 2) {
+		dev_err(&intf->dev, "interface %d has %d endpoints, but must"
+		    " have minimum 2\n", ifnum, interface->desc.bNumEndpoints);
+		ret = -ENODEV;
+		goto err_usb;
+	}
 	endpoint = &interface->endpoint[1].desc;
+
 	if (!usb_endpoint_xfer_isoc(endpoint)) {
 		dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
 		    __func__, ifnum);
@@ -1509,7 +1523,14 @@
 	}
 
 	for (i = 0; i < usbvision->num_alt; i++) {
-		u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+		u16 tmp;
+
+		if (uif->altsetting[i].desc.bNumEndpoints < 2) {
+			ret = -ENODEV;
+			goto err_pkt;
+		}
+
+		tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
 				      wMaxPacketSize);
 		usbvision->alt_max_pkt_size[i] =
 			(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
--- linux-4.4.0.orig/drivers/media/usb/uvc/uvc_ctrl.c
+++ linux-4.4.0/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1202,7 +1202,7 @@
 
 	__uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
 
-	memset(ev->reserved, 0, sizeof(ev->reserved));
+	memset(ev, 0, sizeof(*ev));
 	ev->type = V4L2_EVENT_CTRL;
 	ev->id = v4l2_ctrl.id;
 	ev->u.ctrl.value = value;
@@ -2001,6 +2001,13 @@
 		goto done;
 	}
 
+	/* Validate the user-provided bit-size and offset */
+	if (mapping->size > 32 ||
+	    mapping->offset + mapping->size > ctrl->info.size * 8) {
+		ret = -EINVAL;
+		goto done;
+	}
+
 	list_for_each_entry(map, &ctrl->info.mappings, list) {
 		if (mapping->id == map->id) {
 			uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
--- linux-4.4.0.orig/drivers/media/usb/uvc/uvc_driver.c
+++ linux-4.4.0/drivers/media/usb/uvc/uvc_driver.c
@@ -148,6 +148,26 @@
 		.guid		= UVC_GUID_FORMAT_H264,
 		.fcc		= V4L2_PIX_FMT_H264,
 	},
+	{
+		.name		= "Greyscale 8 L/R (Y8I)",
+		.guid		= UVC_GUID_FORMAT_Y8I,
+		.fcc		= V4L2_PIX_FMT_Y8I,
+	},
+	{
+		.name		= "Greyscale 12 L/R (Y12I)",
+		.guid		= UVC_GUID_FORMAT_Y12I,
+		.fcc		= V4L2_PIX_FMT_Y12I,
+	},
+	{
+		.name		= "Depth data 16-bit (Z16)",
+		.guid		= UVC_GUID_FORMAT_Z16,
+		.fcc		= V4L2_PIX_FMT_Z16,
+	},
+	{
+		.name		= "Bayer 10-bit (SRGGB10P)",
+		.guid		= UVC_GUID_FORMAT_RW10,
+		.fcc		= V4L2_PIX_FMT_SRGGB10P,
+	},
 };
 
 /* ------------------------------------------------------------------------
@@ -476,7 +496,7 @@
 	/* Parse the frame descriptors. Only uncompressed, MJPEG and frame
 	 * based formats have frame descriptors.
 	 */
-	while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+	while (ftype && buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
 	       buffer[2] == ftype) {
 		frame = &format->frame[format->nframes];
 		if (ftype != UVC_VS_FRAME_FRAME_BASED)
@@ -848,8 +868,11 @@
 	unsigned int size;
 	unsigned int i;
 
-	extra_size = ALIGN(extra_size, sizeof(*entity->pads));
-	num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
+	extra_size = roundup(extra_size, sizeof(*entity->pads));
+	if (num_pads)
+		num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1;
+	else
+		num_inputs = 0;
 	size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
 	     + num_inputs;
 	entity = kzalloc(size, GFP_KERNEL);
@@ -865,7 +888,7 @@
 
 	for (i = 0; i < num_inputs; ++i)
 		entity->pads[i].flags = MEDIA_PAD_FL_SINK;
-	if (!UVC_ENTITY_IS_OTERM(entity))
+	if (!UVC_ENTITY_IS_OTERM(entity) && num_pads)
 		entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
 
 	entity->bNrInPins = num_inputs;
@@ -999,11 +1022,19 @@
 			return -EINVAL;
 		}
 
-		/* Make sure the terminal type MSB is not null, otherwise it
-		 * could be confused with a unit.
+		/*
+		 * Reject invalid terminal types that would cause issues:
+		 *
+		 * - The high byte must be non-zero, otherwise it would be
+		 *   confused with a unit.
+		 *
+		 * - Bit 15 must be 0, as we use it internally as a terminal
+		 *   direction flag.
+		 *
+		 * Other unknown types are accepted.
 		 */
 		type = get_unaligned_le16(&buffer[4]);
-		if ((type & 0xff00) == 0) {
+		if ((type & 0x7f00) == 0 || (type & 0x8000) != 0) {
 			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
 				"interface %d INPUT_TERMINAL %d has invalid "
 				"type 0x%04x, skipping\n", udev->devnum,
@@ -1383,6 +1414,11 @@
 			break;
 		if (forward == prev)
 			continue;
+		if (forward->chain.next || forward->chain.prev) {
+			uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+				"entity %d already in chain.\n", forward->id);
+			return -EINVAL;
+		}
 
 		switch (UVC_ENTITY_TYPE(forward)) {
 		case UVC_VC_EXTENSION_UNIT:
@@ -1464,6 +1500,13 @@
 				return -1;
 			}
 
+			if (term->chain.next || term->chain.prev) {
+				uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+					"entity %d already in chain.\n",
+					term->id);
+				return -EINVAL;
+			}
+
 			if (uvc_trace_param & UVC_TRACE_PROBE)
 				printk(" %d", term->id);
 
@@ -1575,6 +1618,114 @@
 	return buffer;
 }
 
+static struct uvc_video_chain *uvc_alloc_chain(struct uvc_device *dev)
+{
+	struct uvc_video_chain *chain;
+
+	chain = kzalloc(sizeof(*chain), GFP_KERNEL);
+	if (chain == NULL)
+		return NULL;
+
+	INIT_LIST_HEAD(&chain->entities);
+	mutex_init(&chain->ctrl_mutex);
+	chain->dev = dev;
+	v4l2_prio_init(&chain->prio);
+
+	return chain;
+}
+
+/*
+ * Fallback heuristic for devices that don't connect units and terminals in a
+ * valid chain.
+ *
+ * Some devices have invalid baSourceID references, causing uvc_scan_chain()
+ * to fail, but if we just take the entities we can find and put them together
+ * in the most sensible chain we can think of, turns out they do work anyway.
+ * Note: This heuristic assumes there is a single chain.
+ *
+ * At the time of writing, devices known to have such a broken chain are
+ *  - Acer Integrated Camera (5986:055a)
+ *  - Realtek rtl157a7 (0bda:57a7)
+ */
+static int uvc_scan_fallback(struct uvc_device *dev)
+{
+	struct uvc_video_chain *chain;
+	struct uvc_entity *iterm = NULL;
+	struct uvc_entity *oterm = NULL;
+	struct uvc_entity *entity;
+	struct uvc_entity *prev;
+
+	/*
+	 * Start by locating the input and output terminals. We only support
+	 * devices with exactly one of each for now.
+	 */
+	list_for_each_entry(entity, &dev->entities, list) {
+		if (UVC_ENTITY_IS_ITERM(entity)) {
+			if (iterm)
+				return -EINVAL;
+			iterm = entity;
+		}
+
+		if (UVC_ENTITY_IS_OTERM(entity)) {
+			if (oterm)
+				return -EINVAL;
+			oterm = entity;
+		}
+	}
+
+	if (iterm == NULL || oterm == NULL)
+		return -EINVAL;
+
+	/* Allocate the chain and fill it. */
+	chain = uvc_alloc_chain(dev);
+	if (chain == NULL)
+		return -ENOMEM;
+
+	if (uvc_scan_chain_entity(chain, oterm) < 0)
+		goto error;
+
+	prev = oterm;
+
+	/*
+	 * Add all Processing and Extension Units with two pads. The order
+	 * doesn't matter much, use reverse list traversal to connect units in
+	 * UVC descriptor order as we build the chain from output to input. This
+	 * leads to units appearing in the order meant by the manufacturer for
+	 * the cameras known to require this heuristic.
+	 */
+	list_for_each_entry_reverse(entity, &dev->entities, list) {
+		if (entity->type != UVC_VC_PROCESSING_UNIT &&
+		    entity->type != UVC_VC_EXTENSION_UNIT)
+			continue;
+
+		if (entity->num_pads != 2)
+			continue;
+
+		if (uvc_scan_chain_entity(chain, entity) < 0)
+			goto error;
+
+		prev->baSourceID[0] = entity->id;
+		prev = entity;
+	}
+
+	if (uvc_scan_chain_entity(chain, iterm) < 0)
+		goto error;
+
+	prev->baSourceID[0] = iterm->id;
+
+	list_add_tail(&chain->list, &dev->chains);
+
+	uvc_trace(UVC_TRACE_PROBE,
+		  "Found a video chain by fallback heuristic (%s).\n",
+		  uvc_print_chain(chain));
+
+	return 0;
+
+error:
+	kfree(chain);
+	return -EINVAL;
+}
+
 /*
  * Scan the device for video chains and register video devices.
  *
@@ -1597,15 +1748,10 @@
 		if (term->chain.next || term->chain.prev)
 			continue;
 
-		chain = kzalloc(sizeof(*chain), GFP_KERNEL);
+		chain = uvc_alloc_chain(dev);
 		if (chain == NULL)
 			return -ENOMEM;
 
-		INIT_LIST_HEAD(&chain->entities);
-		mutex_init(&chain->ctrl_mutex);
-		chain->dev = dev;
-		v4l2_prio_init(&chain->prio);
-
 		term->flags |= UVC_ENTITY_FLAG_DEFAULT;
 
 		if (uvc_scan_chain(chain, term) < 0) {
@@ -1619,6 +1765,9 @@
 		list_add_tail(&chain->list, &dev->chains);
 	}
 
+	if (list_empty(&dev->chains))
+		uvc_scan_fallback(dev);
+
 	if (list_empty(&dev->chains)) {
 		uvc_printk(KERN_INFO, "No valid video chain found.\n");
 		return -1;
@@ -1654,7 +1803,7 @@
 	if (dev->vdev.dev)
 		v4l2_device_unregister(&dev->vdev);
 #ifdef CONFIG_MEDIA_CONTROLLER
-	if (media_devnode_is_registered(&dev->mdev.devnode))
+	if (media_devnode_is_registered(dev->mdev.devnode))
 		media_device_unregister(&dev->mdev);
 #endif
 
@@ -2265,6 +2414,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_DEF },
+	/* Alienware X51*/
+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+				  | USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor             = 0x05a9,
+	  .idProduct            = 0x2643,
+	  .bInterfaceClass      = USB_CLASS_VIDEO,
+	  .bInterfaceSubClass   = 1,
+	  .bInterfaceProtocol   = 0,
+	  .driver_info          = UVC_QUIRK_PROBE_DEF },
 	/* Apple Built-In iSight */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2540,7 +2698,8 @@
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_FORCE_Y8 },
 	/* Generic USB Video Class */
-	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
+	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
 	{}
 };
 
--- linux-4.4.0.orig/drivers/media/usb/uvc/uvc_queue.c
+++ linux-4.4.0/drivers/media/usb/uvc/uvc_queue.c
@@ -416,7 +416,7 @@
 		nextbuf = NULL;
 	spin_unlock_irqrestore(&queue->irqlock, flags);
 
-	buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
+	buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
 	vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
 	vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
 
--- linux-4.4.0.orig/drivers/media/usb/uvc/uvc_v4l2.c
+++ linux-4.4.0/drivers/media/usb/uvc/uvc_v4l2.c
@@ -242,11 +242,41 @@
 	if (ret < 0)
 		goto done;
 
+	/* After the probe, update fmt with the values returned from
+	 * negotiation with the device. Some devices return invalid bFormatIndex
+	 * and bFrameIndex values, in which case we can only assume they have
+	 * accepted the requested format as-is.
+	 */
+	for (i = 0; i < stream->nformats; ++i) {
+		if (probe->bFormatIndex == stream->format[i].index) {
+			format = &stream->format[i];
+			break;
+		}
+	}
+
+	if (i == stream->nformats)
+		uvc_trace(UVC_TRACE_FORMAT,
+			  "Unknown bFormatIndex %u, using default\n",
+			  probe->bFormatIndex);
+
+	for (i = 0; i < format->nframes; ++i) {
+		if (probe->bFrameIndex == format->frame[i].bFrameIndex) {
+			frame = &format->frame[i];
+			break;
+		}
+	}
+
+	if (i == format->nframes)
+		uvc_trace(UVC_TRACE_FORMAT,
+			  "Unknown bFrameIndex %u, using default\n",
+			  probe->bFrameIndex);
+
 	fmt->fmt.pix.width = frame->wWidth;
 	fmt->fmt.pix.height = frame->wHeight;
 	fmt->fmt.pix.field = V4L2_FIELD_NONE;
 	fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
 	fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize;
+	fmt->fmt.pix.pixelformat = format->fcc;
 	fmt->fmt.pix.colorspace = format->colorspace;
 	fmt->fmt.pix.priv = 0;
 
@@ -1388,47 +1418,44 @@
 static long uvc_v4l2_compat_ioctl32(struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
+	struct uvc_fh *handle = file->private_data;
 	union {
 		struct uvc_xu_control_mapping xmap;
 		struct uvc_xu_control_query xqry;
 	} karg;
 	void __user *up = compat_ptr(arg);
-	mm_segment_t old_fs;
 	long ret;
 
 	switch (cmd) {
 	case UVCIOC_CTRL_MAP32:
-		cmd = UVCIOC_CTRL_MAP;
 		ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
+		if (ret)
+			return ret;
+		ret = uvc_ioctl_ctrl_map(handle->chain, &karg.xmap);
+		if (ret)
+			return ret;
+		ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
+		if (ret)
+			return ret;
+
 		break;
 
 	case UVCIOC_CTRL_QUERY32:
-		cmd = UVCIOC_CTRL_QUERY;
 		ret = uvc_v4l2_get_xu_query(&karg.xqry, up);
+		if (ret)
+			return ret;
+		ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry);
+		if (ret)
+			return ret;
+		ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
+		if (ret)
+			return ret;
 		break;
 
 	default:
 		return -ENOIOCTLCMD;
 	}
 
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = video_ioctl2(file, cmd, (unsigned long)&karg);
-	set_fs(old_fs);
-
-	if (ret < 0)
-		return ret;
-
-	switch (cmd) {
-	case UVCIOC_CTRL_MAP:
-		ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
-		break;
-
-	case UVCIOC_CTRL_QUERY:
-		ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
-		break;
-	}
-
 	return ret;
 }
 #endif
--- linux-4.4.0.orig/drivers/media/usb/uvc/uvc_video.c
+++ linux-4.4.0/drivers/media/usb/uvc/uvc_video.c
@@ -163,14 +163,27 @@
 	}
 }
 
+static size_t uvc_video_ctrl_size(struct uvc_streaming *stream)
+{
+	/*
+	 * Return the size of the video probe and commit controls, which depends
+	 * on the protocol version.
+	 */
+	if (stream->dev->uvc_version < 0x0110)
+		return 26;
+	else if (stream->dev->uvc_version < 0x0150)
+		return 34;
+	else
+		return 48;
+}
+
 static int uvc_get_video_ctrl(struct uvc_streaming *stream,
 	struct uvc_streaming_control *ctrl, int probe, __u8 query)
 {
+	__u16 size = uvc_video_ctrl_size(stream);
 	__u8 *data;
-	__u16 size;
 	int ret;
 
-	size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
 	if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) &&
 			query == UVC_GET_DEF)
 		return -EIO;
@@ -225,7 +238,7 @@
 	ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]);
 	ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]);
 
-	if (size == 34) {
+	if (size >= 34) {
 		ctrl->dwClockFrequency = get_unaligned_le32(&data[26]);
 		ctrl->bmFramingInfo = data[30];
 		ctrl->bPreferedVersion = data[31];
@@ -254,11 +267,10 @@
 static int uvc_set_video_ctrl(struct uvc_streaming *stream,
 	struct uvc_streaming_control *ctrl, int probe)
 {
+	__u16 size = uvc_video_ctrl_size(stream);
 	__u8 *data;
-	__u16 size;
 	int ret;
 
-	size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
 	data = kzalloc(size, GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
@@ -275,7 +287,7 @@
 	put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
 	put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);
 
-	if (size == 34) {
+	if (size >= 34) {
 		put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
 		data[30] = ctrl->bmFramingInfo;
 		data[31] = ctrl->bPreferedVersion;
@@ -626,6 +638,14 @@
 	if (!uvc_hw_timestamps_param)
 		return;
 
+	/*
+	 * We will get called from __vb2_queue_cancel() if there are buffers
+	 * done but not dequeued by the user, but the sample array has already
+	 * been released at that time. Just bail out in that case.
+	 */
+	if (!clock->samples)
+		return;
+
 	spin_lock_irqsave(&clock->lock, flags);
 
 	if (clock->count < clock->size)
@@ -1088,6 +1108,7 @@
 	/* Complete the current frame if the buffer size was exceeded. */
 	if (len > maxlen) {
 		uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
+		buf->error = 1;
 		buf->state = UVC_BUF_STATE_READY;
 	}
 }
--- linux-4.4.0.orig/drivers/media/usb/uvc/uvcvideo.h
+++ linux-4.4.0/drivers/media/usb/uvc/uvcvideo.h
@@ -119,6 +119,18 @@
 #define UVC_GUID_FORMAT_H264 \
 	{ 'H',  '2',  '6',  '4', 0x00, 0x00, 0x10, 0x00, \
 	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y8I \
+	{ 'Y',  '8',  'I',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y12I \
+	{ 'Y',  '1',  '2',  'I', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Z16 \
+	{ 'Z',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RW10 \
+	{ 'R',  'W',  '1',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 
 /* ------------------------------------------------------------------------
  * Driver specific constants.
--- linux-4.4.0.orig/drivers/media/usb/zr364xx/zr364xx.c
+++ linux-4.4.0/drivers/media/usb/zr364xx/zr364xx.c
@@ -604,6 +604,14 @@
 	ptr = pdest = frm->lpvbits;
 
 	if (frm->ulState == ZR364XX_READ_IDLE) {
+		if (purb->actual_length < 128) {
+			/* header incomplete */
+			dev_info(&cam->udev->dev,
+				 "%s: buffer (%d bytes) too small to hold jpeg header. Discarding.\n",
+				 __func__, purb->actual_length);
+			return -EINVAL;
+		}
+
 		frm->ulState = ZR364XX_READ_FRAME;
 		frm->cur_size = 0;
 
@@ -703,7 +711,8 @@
 	struct zr364xx_camera *cam = video_drvdata(file);
 
 	strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
-	strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
+	if (cam->udev->product)
+		strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
 	strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
 		sizeof(cap->bus_info));
 	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
--- linux-4.4.0.orig/drivers/media/v4l2-core/Kconfig
+++ linux-4.4.0/drivers/media/v4l2-core/Kconfig
@@ -37,7 +37,6 @@
 # Used by drivers that need tuner.ko
 config VIDEO_TUNER
 	tristate
-	depends on MEDIA_TUNER
 
 # Used by drivers that need v4l2-mem2mem.ko
 config V4L2_MEM2MEM_DEV
--- linux-4.4.0.orig/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ linux-4.4.0/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -18,8 +18,18 @@
 #include <linux/videodev2.h>
 #include <linux/v4l2-subdev.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-ioctl.h>
 
+/* Use the same argument order as copy_in_user */
+#define assign_in_user(to, from)					\
+({									\
+	typeof(*from) __assign_tmp;					\
+									\
+	get_user(__assign_tmp, from) || put_user(__assign_tmp, to);	\
+})
+
 static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	long ret = -ENOIOCTLCMD;
@@ -33,131 +43,90 @@
 
 struct v4l2_clip32 {
 	struct v4l2_rect        c;
-	compat_caddr_t 		next;
+	compat_caddr_t		next;
 };
 
 struct v4l2_window32 {
 	struct v4l2_rect        w;
-	__u32		  	field;	/* enum v4l2_field */
+	__u32			field;	/* enum v4l2_field */
 	__u32			chromakey;
 	compat_caddr_t		clips; /* actually struct v4l2_clip32 * */
 	__u32			clipcount;
 	compat_caddr_t		bitmap;
+	__u8                    global_alpha;
 };
 
-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
-{
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
-		copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
-		get_user(kp->field, &up->field) ||
-		get_user(kp->chromakey, &up->chromakey) ||
-		get_user(kp->clipcount, &up->clipcount))
-			return -EFAULT;
-	if (kp->clipcount > 2048)
-		return -EINVAL;
-	if (kp->clipcount) {
-		struct v4l2_clip32 __user *uclips;
-		struct v4l2_clip __user *kclips;
-		int n = kp->clipcount;
-		compat_caddr_t p;
-
-		if (get_user(p, &up->clips))
-			return -EFAULT;
-		uclips = compat_ptr(p);
-		kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
-		kp->clips = kclips;
-		while (--n >= 0) {
-			if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
-				return -EFAULT;
-			if (put_user(n ? kclips + 1 : NULL, &kclips->next))
-				return -EFAULT;
-			uclips += 1;
-			kclips += 1;
-		}
-	} else
-		kp->clips = NULL;
-	return 0;
-}
-
-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+static int get_v4l2_window32(struct v4l2_window __user *kp,
+			     struct v4l2_window32 __user *up,
+			     void __user *aux_buf, u32 aux_space)
 {
-	if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
-		put_user(kp->field, &up->field) ||
-		put_user(kp->chromakey, &up->chromakey) ||
-		put_user(kp->clipcount, &up->clipcount))
-			return -EFAULT;
-	return 0;
-}
+	struct v4l2_clip32 __user *uclips;
+	struct v4l2_clip __user *kclips;
+	compat_caddr_t p;
+	u32 clipcount;
 
-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
-{
-	if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
+	    assign_in_user(&kp->field, &up->field) ||
+	    assign_in_user(&kp->chromakey, &up->chromakey) ||
+	    assign_in_user(&kp->global_alpha, &up->global_alpha) ||
+	    get_user(clipcount, &up->clipcount) ||
+	    put_user(clipcount, &kp->clipcount))
 		return -EFAULT;
-	return 0;
-}
+	if (clipcount > 2048)
+		return -EINVAL;
+	if (!clipcount)
+		return put_user(NULL, &kp->clips);
 
-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
-				struct v4l2_pix_format_mplane __user *up)
-{
-	if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+	if (get_user(p, &up->clips))
 		return -EFAULT;
-	return 0;
-}
-
-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
-{
-	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
+	uclips = compat_ptr(p);
+	if (aux_space < clipcount * sizeof(*kclips))
 		return -EFAULT;
-	return 0;
-}
-
-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
-				struct v4l2_pix_format_mplane __user *up)
-{
-	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+	kclips = aux_buf;
+	if (put_user(kclips, &kp->clips))
 		return -EFAULT;
-	return 0;
-}
 
-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
-{
-	if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
-		return -EFAULT;
+	while (clipcount--) {
+		if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+			return -EFAULT;
+		if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
+			return -EFAULT;
+		uclips++;
+		kclips++;
+	}
 	return 0;
 }
 
-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+static int put_v4l2_window32(struct v4l2_window __user *kp,
+			     struct v4l2_window32 __user *up)
 {
-	if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
-		return -EFAULT;
-	return 0;
-}
+	struct v4l2_clip __user *kclips;
+	struct v4l2_clip32 __user *uclips;
+	compat_caddr_t p;
+	u32 clipcount;
 
-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
-{
-	if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+	if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
+	    assign_in_user(&up->field, &kp->field) ||
+	    assign_in_user(&up->chromakey, &kp->chromakey) ||
+	    assign_in_user(&up->global_alpha, &kp->global_alpha) ||
+	    get_user(clipcount, &kp->clipcount) ||
+	    put_user(clipcount, &up->clipcount))
 		return -EFAULT;
-	return 0;
-}
+	if (!clipcount)
+		return 0;
 
-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
-{
-	if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+	if (get_user(kclips, &kp->clips))
 		return -EFAULT;
-	return 0;
-}
-
-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
-{
-	if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format)))
-		return -EFAULT;
-	return 0;
-}
-
-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
-{
-	if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format)))
+	if (get_user(p, &up->clips))
 		return -EFAULT;
+	uclips = compat_ptr(p);
+	while (clipcount--) {
+		if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
+			return -EFAULT;
+		uclips++;
+		kclips++;
+	}
 	return 0;
 }
 
@@ -191,96 +160,158 @@
 	__u32			reserved[8];
 };
 
-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
+{
+	u32 type;
+
+	if (get_user(type, &up->type))
+		return -EFAULT;
+
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
+		u32 clipcount;
+
+		if (get_user(clipcount, &up->fmt.win.clipcount))
+			return -EFAULT;
+		if (clipcount > 2048)
+			return -EINVAL;
+		*size = clipcount * sizeof(struct v4l2_clip);
+		return 0;
+	}
+	default:
+		*size = 0;
+		return 0;
+	}
+}
+
+static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
 {
-	if (get_user(kp->type, &up->type))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
 		return -EFAULT;
+	return __bufsize_v4l2_format(up, size);
+}
+
+static int __get_v4l2_format32(struct v4l2_format __user *kp,
+			       struct v4l2_format32 __user *up,
+			       void __user *aux_buf, u32 aux_space)
+{
+	u32 type;
 
-	switch (kp->type) {
+	if (get_user(type, &up->type) || put_user(type, &kp->type))
+		return -EFAULT;
+
+	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+		return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
+				    sizeof(kp->fmt.pix)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
-						  &up->fmt.pix_mp);
+		return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
+				    sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
+					 aux_buf, aux_space);
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
 	case V4L2_BUF_TYPE_VBI_OUTPUT:
-		return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+		return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
+				    sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-		return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+		return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
+				    sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_SDR_CAPTURE:
 	case V4L2_BUF_TYPE_SDR_OUTPUT:
-		return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+		return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
+				    sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
 	default:
-		pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
-								kp->type);
 		return -EINVAL;
 	}
 }
 
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int get_v4l2_format32(struct v4l2_format __user *kp,
+			     struct v4l2_format32 __user *up,
+			     void __user *aux_buf, u32 aux_space)
+{
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+		return -EFAULT;
+	return __get_v4l2_format32(kp, up, aux_buf, aux_space);
+}
+
+static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
+			       u32 *size)
 {
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
 		return -EFAULT;
-	return __get_v4l2_format32(kp, up);
+	return __bufsize_v4l2_format(&up->format, size);
 }
 
-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
+			     struct v4l2_create_buffers32 __user *up,
+			     void __user *aux_buf, u32 aux_space)
 {
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
-	    copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    copy_in_user(kp, up,
+			 offsetof(struct v4l2_create_buffers32, format)))
 		return -EFAULT;
-	return __get_v4l2_format32(&kp->format, &up->format);
+	return __get_v4l2_format32(&kp->format, &up->format,
+				   aux_buf, aux_space);
 }
 
-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __put_v4l2_format32(struct v4l2_format __user *kp,
+			       struct v4l2_format32 __user *up)
 {
-	if (put_user(kp->type, &up->type))
+	u32 type;
+
+	if (get_user(type, &kp->type))
 		return -EFAULT;
 
-	switch (kp->type) {
+	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+		return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
+				    sizeof(kp->fmt.pix)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
-						  &up->fmt.pix_mp);
+		return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
+				    sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
 	case V4L2_BUF_TYPE_VBI_OUTPUT:
-		return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+		return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
+				    sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-		return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+		return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
+				    sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_SDR_CAPTURE:
 	case V4L2_BUF_TYPE_SDR_OUTPUT:
-		return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+		return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
+				    sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
 	default:
-		pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
-								kp->type);
 		return -EINVAL;
 	}
 }
 
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int put_v4l2_format32(struct v4l2_format __user *kp,
+			     struct v4l2_format32 __user *up)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
 		return -EFAULT;
 	return __put_v4l2_format32(kp, up);
 }
 
-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
+			     struct v4l2_create_buffers32 __user *up)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
-	    copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)))
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    copy_in_user(up, kp,
+			 offsetof(struct v4l2_create_buffers32, format)) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
 		return -EFAULT;
 	return __put_v4l2_format32(&kp->format, &up->format);
 }
@@ -294,25 +325,28 @@
 	__u32		     reserved[4];
 };
 
-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int get_v4l2_standard32(struct v4l2_standard __user *kp,
+			       struct v4l2_standard32 __user *up)
 {
 	/* other fields are not set by the user, nor used by the driver */
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
-		get_user(kp->index, &up->index))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    assign_in_user(&kp->index, &up->index))
 		return -EFAULT;
 	return 0;
 }
 
-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int put_v4l2_standard32(struct v4l2_standard __user *kp,
+			       struct v4l2_standard32 __user *up)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
-		put_user(kp->index, &up->index) ||
-		put_user(kp->id, &up->id) ||
-		copy_to_user(up->name, kp->name, 24) ||
-		copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
-		put_user(kp->framelines, &up->framelines) ||
-		copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->index, &kp->index) ||
+	    assign_in_user(&up->id, &kp->id) ||
+	    copy_in_user(up->name, kp->name, sizeof(up->name)) ||
+	    copy_in_user(&up->frameperiod, &kp->frameperiod,
+			 sizeof(up->frameperiod)) ||
+	    assign_in_user(&up->framelines, &kp->framelines) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -351,138 +385,186 @@
 	__u32			reserved;
 };
 
-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
-				enum v4l2_memory memory)
+static int get_v4l2_plane32(struct v4l2_plane __user *up,
+			    struct v4l2_plane32 __user *up32,
+			    enum v4l2_memory memory)
 {
-	void __user *up_pln;
-	compat_long_t p;
+	compat_ulong_t p;
 
 	if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
-		copy_in_user(&up->data_offset, &up32->data_offset,
-				sizeof(__u32)))
+	    copy_in_user(&up->data_offset, &up32->data_offset,
+			 sizeof(up->data_offset)))
 		return -EFAULT;
 
-	if (memory == V4L2_MEMORY_USERPTR) {
-		if (get_user(p, &up32->m.userptr))
-			return -EFAULT;
-		up_pln = compat_ptr(p);
-		if (put_user((unsigned long)up_pln, &up->m.userptr))
+	switch (memory) {
+	case V4L2_MEMORY_MMAP:
+	case V4L2_MEMORY_OVERLAY:
+		if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+				 sizeof(up32->m.mem_offset)))
 			return -EFAULT;
-	} else if (memory == V4L2_MEMORY_DMABUF) {
-		if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
+		break;
+	case V4L2_MEMORY_USERPTR:
+		if (get_user(p, &up32->m.userptr) ||
+		    put_user((unsigned long)compat_ptr(p), &up->m.userptr))
 			return -EFAULT;
-	} else {
-		if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
-					sizeof(__u32)))
+		break;
+	case V4L2_MEMORY_DMABUF:
+		if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
 			return -EFAULT;
+		break;
 	}
 
 	return 0;
 }
 
-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
-				enum v4l2_memory memory)
+static int put_v4l2_plane32(struct v4l2_plane __user *up,
+			    struct v4l2_plane32 __user *up32,
+			    enum v4l2_memory memory)
 {
+	unsigned long p;
+
 	if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
-		copy_in_user(&up32->data_offset, &up->data_offset,
-				sizeof(__u32)))
+	    copy_in_user(&up32->data_offset, &up->data_offset,
+			 sizeof(up->data_offset)))
 		return -EFAULT;
 
-	/* For MMAP, driver might've set up the offset, so copy it back.
-	 * USERPTR stays the same (was userspace-provided), so no copying. */
-	if (memory == V4L2_MEMORY_MMAP)
+	switch (memory) {
+	case V4L2_MEMORY_MMAP:
+	case V4L2_MEMORY_OVERLAY:
 		if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
-					sizeof(__u32)))
+				 sizeof(up->m.mem_offset)))
 			return -EFAULT;
-	/* For DMABUF, driver might've set up the fd, so copy it back. */
-	if (memory == V4L2_MEMORY_DMABUF)
-		if (copy_in_user(&up32->m.fd, &up->m.fd,
-					sizeof(int)))
+		break;
+	case V4L2_MEMORY_USERPTR:
+		if (get_user(p, &up->m.userptr) ||
+		    put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
+			     &up32->m.userptr))
 			return -EFAULT;
+		break;
+	case V4L2_MEMORY_DMABUF:
+		if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
+			return -EFAULT;
+		break;
+	}
 
 	return 0;
 }
 
-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
 {
+	u32 type;
+	u32 length;
+
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    get_user(type, &up->type) ||
+	    get_user(length, &up->length))
+		return -EFAULT;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+		if (length > VIDEO_MAX_PLANES)
+			return -EINVAL;
+
+		/*
+		 * We don't really care if userspace decides to kill itself
+		 * by passing a very big length value
+		 */
+		*size = length * sizeof(struct v4l2_plane);
+	} else {
+		*size = 0;
+	}
+	return 0;
+}
+
+static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
+			     struct v4l2_buffer32 __user *up,
+			     void __user *aux_buf, u32 aux_space)
+{
+	u32 type;
+	u32 length;
+	enum v4l2_memory memory;
 	struct v4l2_plane32 __user *uplane32;
 	struct v4l2_plane __user *uplane;
 	compat_caddr_t p;
-	int num_planes;
 	int ret;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
-		get_user(kp->index, &up->index) ||
-		get_user(kp->type, &up->type) ||
-		get_user(kp->flags, &up->flags) ||
-		get_user(kp->memory, &up->memory))
-			return -EFAULT;
-
-	if (V4L2_TYPE_IS_OUTPUT(kp->type))
-		if (get_user(kp->bytesused, &up->bytesused) ||
-			get_user(kp->field, &up->field) ||
-			get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-			get_user(kp->timestamp.tv_usec,
-					&up->timestamp.tv_usec))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    assign_in_user(&kp->index, &up->index) ||
+	    get_user(type, &up->type) ||
+	    put_user(type, &kp->type) ||
+	    assign_in_user(&kp->flags, &up->flags) ||
+	    get_user(memory, &up->memory) ||
+	    put_user(memory, &kp->memory) ||
+	    get_user(length, &up->length) ||
+	    put_user(length, &kp->length))
+		return -EFAULT;
+
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		if (assign_in_user(&kp->bytesused, &up->bytesused) ||
+		    assign_in_user(&kp->field, &up->field) ||
+		    assign_in_user(&kp->timestamp.tv_sec,
+				   &up->timestamp.tv_sec) ||
+		    assign_in_user(&kp->timestamp.tv_usec,
+				   &up->timestamp.tv_usec))
 			return -EFAULT;
 
-	if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-		if (get_user(kp->length, &up->length))
-			return -EFAULT;
+	if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+		u32 num_planes = length;
 
-		num_planes = kp->length;
 		if (num_planes == 0) {
-			kp->m.planes = NULL;
-			/* num_planes == 0 is legal, e.g. when userspace doesn't
-			 * need planes array on DQBUF*/
-			return 0;
+			/*
+			 * num_planes == 0 is legal, e.g. when userspace doesn't
+			 * need planes array on DQBUF
+			 */
+			return put_user(NULL, &kp->m.planes);
 		}
+		if (num_planes > VIDEO_MAX_PLANES)
+			return -EINVAL;
 
 		if (get_user(p, &up->m.planes))
 			return -EFAULT;
 
 		uplane32 = compat_ptr(p);
 		if (!access_ok(VERIFY_READ, uplane32,
-				num_planes * sizeof(struct v4l2_plane32)))
+			       num_planes * sizeof(*uplane32)))
 			return -EFAULT;
 
-		/* We don't really care if userspace decides to kill itself
-		 * by passing a very big num_planes value */
-		uplane = compat_alloc_user_space(num_planes *
-						sizeof(struct v4l2_plane));
-		kp->m.planes = (__force struct v4l2_plane *)uplane;
+		/*
+		 * We don't really care if userspace decides to kill itself
+		 * by passing a very big num_planes value
+		 */
+		if (aux_space < num_planes * sizeof(*uplane))
+			return -EFAULT;
+
+		uplane = aux_buf;
+		if (put_user((__force struct v4l2_plane *)uplane,
+			     &kp->m.planes))
+			return -EFAULT;
 
-		while (--num_planes >= 0) {
-			ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
+		while (num_planes--) {
+			ret = get_v4l2_plane32(uplane, uplane32, memory);
 			if (ret)
 				return ret;
-			++uplane;
-			++uplane32;
+			uplane++;
+			uplane32++;
 		}
 	} else {
-		switch (kp->memory) {
+		switch (memory) {
 		case V4L2_MEMORY_MMAP:
-			if (get_user(kp->length, &up->length) ||
-				get_user(kp->m.offset, &up->m.offset))
+		case V4L2_MEMORY_OVERLAY:
+			if (assign_in_user(&kp->m.offset, &up->m.offset))
 				return -EFAULT;
 			break;
-		case V4L2_MEMORY_USERPTR:
-			{
-			compat_long_t tmp;
-
-			if (get_user(kp->length, &up->length) ||
-			    get_user(tmp, &up->m.userptr))
-				return -EFAULT;
+		case V4L2_MEMORY_USERPTR: {
+			compat_ulong_t userptr;
 
-			kp->m.userptr = (unsigned long)compat_ptr(tmp);
-			}
-			break;
-		case V4L2_MEMORY_OVERLAY:
-			if (get_user(kp->m.offset, &up->m.offset))
+			if (get_user(userptr, &up->m.userptr) ||
+			    put_user((unsigned long)compat_ptr(userptr),
+				     &kp->m.userptr))
 				return -EFAULT;
 			break;
+		}
 		case V4L2_MEMORY_DMABUF:
-			if (get_user(kp->m.fd, &up->m.fd))
+			if (assign_in_user(&kp->m.fd, &up->m.fd))
 				return -EFAULT;
 			break;
 		}
@@ -491,66 +573,70 @@
 	return 0;
 }
 
-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
+			     struct v4l2_buffer32 __user *up)
 {
+	u32 type;
+	u32 length;
+	enum v4l2_memory memory;
 	struct v4l2_plane32 __user *uplane32;
 	struct v4l2_plane __user *uplane;
 	compat_caddr_t p;
-	int num_planes;
 	int ret;
 
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
-		put_user(kp->index, &up->index) ||
-		put_user(kp->type, &up->type) ||
-		put_user(kp->flags, &up->flags) ||
-		put_user(kp->memory, &up->memory))
-			return -EFAULT;
-
-	if (put_user(kp->bytesused, &up->bytesused) ||
-		put_user(kp->field, &up->field) ||
-		put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-		put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
-		copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
-		put_user(kp->sequence, &up->sequence) ||
-		put_user(kp->reserved2, &up->reserved2) ||
-		put_user(kp->reserved, &up->reserved))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->index, &kp->index) ||
+	    get_user(type, &kp->type) ||
+	    put_user(type, &up->type) ||
+	    assign_in_user(&up->flags, &kp->flags) ||
+	    get_user(memory, &kp->memory) ||
+	    put_user(memory, &up->memory))
+		return -EFAULT;
+
+	if (assign_in_user(&up->bytesused, &kp->bytesused) ||
+	    assign_in_user(&up->field, &kp->field) ||
+	    assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+	    assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
+	    copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+	    assign_in_user(&up->sequence, &kp->sequence) ||
+	    assign_in_user(&up->reserved2, &kp->reserved2) ||
+	    assign_in_user(&up->reserved, &kp->reserved) ||
+	    get_user(length, &kp->length) ||
+	    put_user(length, &up->length))
+		return -EFAULT;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+		u32 num_planes = length;
 
-	if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-		num_planes = kp->length;
 		if (num_planes == 0)
 			return 0;
 
-		uplane = (__force struct v4l2_plane __user *)kp->m.planes;
+		if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
+			return -EFAULT;
 		if (get_user(p, &up->m.planes))
 			return -EFAULT;
 		uplane32 = compat_ptr(p);
 
-		while (--num_planes >= 0) {
-			ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
+		while (num_planes--) {
+			ret = put_v4l2_plane32(uplane, uplane32, memory);
 			if (ret)
 				return ret;
 			++uplane;
 			++uplane32;
 		}
 	} else {
-		switch (kp->memory) {
+		switch (memory) {
 		case V4L2_MEMORY_MMAP:
-			if (put_user(kp->length, &up->length) ||
-				put_user(kp->m.offset, &up->m.offset))
+		case V4L2_MEMORY_OVERLAY:
+			if (assign_in_user(&up->m.offset, &kp->m.offset))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_USERPTR:
-			if (put_user(kp->length, &up->length) ||
-				put_user(kp->m.userptr, &up->m.userptr))
-				return -EFAULT;
-			break;
-		case V4L2_MEMORY_OVERLAY:
-			if (put_user(kp->m.offset, &up->m.offset))
+			if (assign_in_user(&up->m.userptr, &kp->m.userptr))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_DMABUF:
-			if (put_user(kp->m.fd, &up->m.fd))
+			if (assign_in_user(&up->m.fd, &kp->m.fd))
 				return -EFAULT;
 			break;
 		}
@@ -562,7 +648,7 @@
 struct v4l2_framebuffer32 {
 	__u32			capability;
 	__u32			flags;
-	compat_caddr_t 		base;
+	compat_caddr_t		base;
 	struct {
 		__u32		width;
 		__u32		height;
@@ -575,30 +661,33 @@
 	} fmt;
 };
 
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+				  struct v4l2_framebuffer32 __user *up)
 {
-	u32 tmp;
+	compat_caddr_t tmp;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
-		get_user(tmp, &up->base) ||
-		get_user(kp->capability, &up->capability) ||
-		get_user(kp->flags, &up->flags) ||
-		copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
-			return -EFAULT;
-	kp->base = (__force void *)compat_ptr(tmp);
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    get_user(tmp, &up->base) ||
+	    put_user((__force void *)compat_ptr(tmp), &kp->base) ||
+	    assign_in_user(&kp->capability, &up->capability) ||
+	    assign_in_user(&kp->flags, &up->flags) ||
+	    copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
+		return -EFAULT;
 	return 0;
 }
 
-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+				  struct v4l2_framebuffer32 __user *up)
 {
-	u32 tmp = (u32)((unsigned long)kp->base);
+	void *base;
 
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
-		put_user(tmp, &up->base) ||
-		put_user(kp->capability, &up->capability) ||
-		put_user(kp->flags, &up->flags) ||
-		copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    get_user(base, &kp->base) ||
+	    put_user(ptr_to_compat(base), &up->base) ||
+	    assign_in_user(&up->capability, &kp->capability) ||
+	    assign_in_user(&up->flags, &kp->flags) ||
+	    copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -610,21 +699,26 @@
 	__u32        tuner;             /*  Associated tuner */
 	compat_u64   std;
 	__u32	     status;
-	__u32	     reserved[4];
+	__u32	     capabilities;
+	__u32	     reserved[3];
 };
 
-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
-   Otherwise it is identical to the 32-bit version. */
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+/*
+ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
+ * Otherwise it is identical to the 32-bit version.
+ */
+static inline int get_v4l2_input32(struct v4l2_input __user *kp,
+				   struct v4l2_input32 __user *up)
 {
-	if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
+	if (copy_in_user(kp, up, sizeof(*up)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+static inline int put_v4l2_input32(struct v4l2_input __user *kp,
+				   struct v4l2_input32 __user *up)
 {
-	if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
+	if (copy_in_user(up, kp, sizeof(*up)))
 		return -EFAULT;
 	return 0;
 }
@@ -648,58 +742,95 @@
 	};
 } __attribute__ ((packed));
 
-/* The following function really belong in v4l2-common, but that causes
-   a circular dependency between modules. We need to think about this, but
-   for now this will do. */
-
-/* Return non-zero if this control is a pointer type. Currently only
-   type STRING is a pointer type. */
-static inline int ctrl_is_pointer(u32 id)
-{
-	switch (id) {
-	case V4L2_CID_RDS_TX_PS_NAME:
-	case V4L2_CID_RDS_TX_RADIO_TEXT:
-		return 1;
-	default:
-		return 0;
+/* Return true if this control is a pointer type. */
+static inline bool ctrl_is_pointer(struct file *file, u32 id)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_fh *fh = NULL;
+	struct v4l2_ctrl_handler *hdl = NULL;
+	struct v4l2_query_ext_ctrl qec = { id };
+	const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
+
+	if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
+		fh = file->private_data;
+
+	if (fh && fh->ctrl_handler)
+		hdl = fh->ctrl_handler;
+	else if (vdev->ctrl_handler)
+		hdl = vdev->ctrl_handler;
+
+	if (hdl) {
+		struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
+
+		return ctrl && ctrl->is_ptr;
 	}
+
+	if (!ops || !ops->vidioc_query_ext_ctrl)
+		return false;
+
+	return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
+		(qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
 }
 
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
+				     u32 *size)
+{
+	u32 count;
+
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    get_user(count, &up->count))
+		return -EFAULT;
+	if (count > V4L2_CID_MAX_CTRLS)
+		return -EINVAL;
+	*size = count * sizeof(struct v4l2_ext_control);
+	return 0;
+}
+
+static int get_v4l2_ext_controls32(struct file *file,
+				   struct v4l2_ext_controls __user *kp,
+				   struct v4l2_ext_controls32 __user *up,
+				   void __user *aux_buf, u32 aux_space)
 {
 	struct v4l2_ext_control32 __user *ucontrols;
 	struct v4l2_ext_control __user *kcontrols;
-	int n;
+	u32 count;
+	u32 n;
 	compat_caddr_t p;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
-		get_user(kp->ctrl_class, &up->ctrl_class) ||
-		get_user(kp->count, &up->count) ||
-		get_user(kp->error_idx, &up->error_idx) ||
-		copy_from_user(kp->reserved, up->reserved,
-			       sizeof(kp->reserved)))
-			return -EFAULT;
-	n = kp->count;
-	if (n == 0) {
-		kp->controls = NULL;
-		return 0;
-	}
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    assign_in_user(&kp->ctrl_class, &up->ctrl_class) ||
+	    get_user(count, &up->count) ||
+	    put_user(count, &kp->count) ||
+	    assign_in_user(&kp->error_idx, &up->error_idx) ||
+	    copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+		return -EFAULT;
+
+	if (count == 0)
+		return put_user(NULL, &kp->controls);
+	if (count > V4L2_CID_MAX_CTRLS)
+		return -EINVAL;
 	if (get_user(p, &up->controls))
 		return -EFAULT;
 	ucontrols = compat_ptr(p);
-	if (!access_ok(VERIFY_READ, ucontrols,
-			n * sizeof(struct v4l2_ext_control32)))
+	if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
+		return -EFAULT;
+	if (aux_space < count * sizeof(*kcontrols))
 		return -EFAULT;
-	kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
-	kp->controls = (__force struct v4l2_ext_control *)kcontrols;
-	while (--n >= 0) {
+	kcontrols = aux_buf;
+	if (put_user((__force struct v4l2_ext_control *)kcontrols,
+		     &kp->controls))
+		return -EFAULT;
+
+	for (n = 0; n < count; n++) {
 		u32 id;
 
 		if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
 			return -EFAULT;
+
 		if (get_user(id, &kcontrols->id))
 			return -EFAULT;
-		if (ctrl_is_pointer(id)) {
+
+		if (ctrl_is_pointer(file, id)) {
 			void __user *s;
 
 			if (get_user(p, &ucontrols->string))
@@ -714,43 +845,55 @@
 	return 0;
 }
 
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int put_v4l2_ext_controls32(struct file *file,
+				   struct v4l2_ext_controls __user *kp,
+				   struct v4l2_ext_controls32 __user *up)
 {
 	struct v4l2_ext_control32 __user *ucontrols;
-	struct v4l2_ext_control __user *kcontrols =
-		(__force struct v4l2_ext_control __user *)kp->controls;
-	int n = kp->count;
+	struct v4l2_ext_control __user *kcontrols;
+	u32 count;
+	u32 n;
 	compat_caddr_t p;
 
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
-		put_user(kp->ctrl_class, &up->ctrl_class) ||
-		put_user(kp->count, &up->count) ||
-		put_user(kp->error_idx, &up->error_idx) ||
-		copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
-			return -EFAULT;
-	if (!kp->count)
-		return 0;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->ctrl_class, &kp->ctrl_class) ||
+	    get_user(count, &kp->count) ||
+	    put_user(count, &up->count) ||
+	    assign_in_user(&up->error_idx, &kp->error_idx) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
+	    get_user(kcontrols, &kp->controls))
+		return -EFAULT;
 
+	if (!count || count > (U32_MAX/sizeof(*ucontrols)))
+		return 0;
 	if (get_user(p, &up->controls))
 		return -EFAULT;
 	ucontrols = compat_ptr(p);
-	if (!access_ok(VERIFY_WRITE, ucontrols,
-			n * sizeof(struct v4l2_ext_control32)))
+	if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
 		return -EFAULT;
 
-	while (--n >= 0) {
-		unsigned size = sizeof(*ucontrols);
+	for (n = 0; n < count; n++) {
+		unsigned int size = sizeof(*ucontrols);
 		u32 id;
 
-		if (get_user(id, &kcontrols->id))
+		if (get_user(id, &kcontrols->id) ||
+		    put_user(id, &ucontrols->id) ||
+		    assign_in_user(&ucontrols->size, &kcontrols->size) ||
+		    copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
+				 sizeof(ucontrols->reserved2)))
 			return -EFAULT;
-		/* Do not modify the pointer when copying a pointer control.
-		   The contents of the pointer was changed, not the pointer
-		   itself. */
-		if (ctrl_is_pointer(id))
+
+		/*
+		 * Do not modify the pointer when copying a pointer control.
+		 * The contents of the pointer was changed, not the pointer
+		 * itself.
+		 */
+		if (ctrl_is_pointer(file, id))
 			size -= sizeof(ucontrols->value64);
+
 		if (copy_in_user(ucontrols, kcontrols, size))
 			return -EFAULT;
+
 		ucontrols++;
 		kcontrols++;
 	}
@@ -770,17 +913,19 @@
 	__u32				reserved[8];
 };
 
-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+static int put_v4l2_event32(struct v4l2_event __user *kp,
+			    struct v4l2_event32 __user *up)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
-		put_user(kp->type, &up->type) ||
-		copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
-		put_user(kp->pending, &up->pending) ||
-		put_user(kp->sequence, &up->sequence) ||
-		compat_put_timespec(&kp->timestamp, &up->timestamp) ||
-		put_user(kp->id, &up->id) ||
-		copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->type, &kp->type) ||
+	    copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
+	    assign_in_user(&up->pending, &kp->pending) ||
+	    assign_in_user(&up->sequence, &kp->sequence) ||
+	    assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+	    assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
+	    assign_in_user(&up->id, &kp->id) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -792,32 +937,35 @@
 	compat_caddr_t edid;
 };
 
-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+static int get_v4l2_edid32(struct v4l2_edid __user *kp,
+			   struct v4l2_edid32 __user *up)
 {
-	u32 tmp;
+	compat_uptr_t tmp;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
-		get_user(kp->pad, &up->pad) ||
-		get_user(kp->start_block, &up->start_block) ||
-		get_user(kp->blocks, &up->blocks) ||
-		get_user(tmp, &up->edid) ||
-		copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
-			return -EFAULT;
-	kp->edid = (__force u8 *)compat_ptr(tmp);
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    assign_in_user(&kp->pad, &up->pad) ||
+	    assign_in_user(&kp->start_block, &up->start_block) ||
+	    assign_in_user(&kp->blocks, &up->blocks) ||
+	    get_user(tmp, &up->edid) ||
+	    put_user(compat_ptr(tmp), &kp->edid) ||
+	    copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+		return -EFAULT;
 	return 0;
 }
 
-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+static int put_v4l2_edid32(struct v4l2_edid __user *kp,
+			   struct v4l2_edid32 __user *up)
 {
-	u32 tmp = (u32)((unsigned long)kp->edid);
+	void *edid;
 
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
-		put_user(kp->pad, &up->pad) ||
-		put_user(kp->start_block, &up->start_block) ||
-		put_user(kp->blocks, &up->blocks) ||
-		put_user(tmp, &up->edid) ||
-		copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->pad, &kp->pad) ||
+	    assign_in_user(&up->start_block, &kp->start_block) ||
+	    assign_in_user(&up->blocks, &kp->blocks) ||
+	    get_user(edid, &kp->edid) ||
+	    put_user(ptr_to_compat(edid), &up->edid) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -833,7 +981,7 @@
 #define VIDIOC_ENUMINPUT32	_IOWR('V', 26, struct v4l2_input32)
 #define VIDIOC_G_EDID32		_IOWR('V', 40, struct v4l2_edid32)
 #define VIDIOC_S_EDID32		_IOWR('V', 41, struct v4l2_edid32)
-#define VIDIOC_TRY_FMT32      	_IOWR('V', 64, struct v4l2_format32)
+#define VIDIOC_TRY_FMT32	_IOWR('V', 64, struct v4l2_format32)
 #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
@@ -849,22 +997,23 @@
 #define VIDIOC_G_OUTPUT32	_IOR ('V', 46, s32)
 #define VIDIOC_S_OUTPUT32	_IOWR('V', 47, s32)
 
+static int alloc_userspace(unsigned int size, u32 aux_space,
+			   void __user **up_native)
+{
+	*up_native = compat_alloc_user_space(size + aux_space);
+	if (!*up_native)
+		return -ENOMEM;
+	if (clear_user(*up_native, size))
+		return -EFAULT;
+	return 0;
+}
+
 static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	union {
-		struct v4l2_format v2f;
-		struct v4l2_buffer v2b;
-		struct v4l2_framebuffer v2fb;
-		struct v4l2_input v2i;
-		struct v4l2_standard v2s;
-		struct v4l2_ext_controls v2ecs;
-		struct v4l2_event v2ev;
-		struct v4l2_create_buffers v2crt;
-		struct v4l2_edid v2edid;
-		unsigned long vx;
-		int vi;
-	} karg;
 	void __user *up = compat_ptr(arg);
+	void __user *up_native = NULL;
+	void __user *aux_buf;
+	u32 aux_space;
 	int compatible_arg = 1;
 	long err = 0;
 
@@ -903,30 +1052,52 @@
 	case VIDIOC_STREAMOFF:
 	case VIDIOC_S_INPUT:
 	case VIDIOC_S_OUTPUT:
-		err = get_user(karg.vi, (s32 __user *)up);
+		err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
+		if (!err && assign_in_user((unsigned int __user *)up_native,
+					   (compat_uint_t __user *)up))
+			err = -EFAULT;
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_INPUT:
 	case VIDIOC_G_OUTPUT:
+		err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_EDID:
 	case VIDIOC_S_EDID:
-		err = get_v4l2_edid32(&karg.v2edid, up);
+		err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
+		if (!err)
+			err = get_v4l2_edid32(up_native, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_FMT:
 	case VIDIOC_S_FMT:
 	case VIDIOC_TRY_FMT:
-		err = get_v4l2_format32(&karg.v2f, up);
+		err = bufsize_v4l2_format(up, &aux_space);
+		if (!err)
+			err = alloc_userspace(sizeof(struct v4l2_format),
+					      aux_space, &up_native);
+		if (!err) {
+			aux_buf = up_native + sizeof(struct v4l2_format);
+			err = get_v4l2_format32(up_native, up,
+						aux_buf, aux_space);
+		}
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_CREATE_BUFS:
-		err = get_v4l2_create32(&karg.v2crt, up);
+		err = bufsize_v4l2_create(up, &aux_space);
+		if (!err)
+			err = alloc_userspace(sizeof(struct v4l2_create_buffers),
+					      aux_space, &up_native);
+		if (!err) {
+			aux_buf = up_native + sizeof(struct v4l2_create_buffers);
+			err = get_v4l2_create32(up_native, up,
+						aux_buf, aux_space);
+		}
 		compatible_arg = 0;
 		break;
 
@@ -934,36 +1105,63 @@
 	case VIDIOC_QUERYBUF:
 	case VIDIOC_QBUF:
 	case VIDIOC_DQBUF:
-		err = get_v4l2_buffer32(&karg.v2b, up);
+		err = bufsize_v4l2_buffer(up, &aux_space);
+		if (!err)
+			err = alloc_userspace(sizeof(struct v4l2_buffer),
+					      aux_space, &up_native);
+		if (!err) {
+			aux_buf = up_native + sizeof(struct v4l2_buffer);
+			err = get_v4l2_buffer32(up_native, up,
+						aux_buf, aux_space);
+		}
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_S_FBUF:
-		err = get_v4l2_framebuffer32(&karg.v2fb, up);
+		err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+				      &up_native);
+		if (!err)
+			err = get_v4l2_framebuffer32(up_native, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_FBUF:
+		err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+				      &up_native);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_ENUMSTD:
-		err = get_v4l2_standard32(&karg.v2s, up);
+		err = alloc_userspace(sizeof(struct v4l2_standard), 0,
+				      &up_native);
+		if (!err)
+			err = get_v4l2_standard32(up_native, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_ENUMINPUT:
-		err = get_v4l2_input32(&karg.v2i, up);
+		err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
+		if (!err)
+			err = get_v4l2_input32(up_native, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_EXT_CTRLS:
 	case VIDIOC_S_EXT_CTRLS:
 	case VIDIOC_TRY_EXT_CTRLS:
-		err = get_v4l2_ext_controls32(&karg.v2ecs, up);
+		err = bufsize_v4l2_ext_controls(up, &aux_space);
+		if (!err)
+			err = alloc_userspace(sizeof(struct v4l2_ext_controls),
+					      aux_space, &up_native);
+		if (!err) {
+			aux_buf = up_native + sizeof(struct v4l2_ext_controls);
+			err = get_v4l2_ext_controls32(file, up_native, up,
+						      aux_buf, aux_space);
+		}
 		compatible_arg = 0;
 		break;
 	case VIDIOC_DQEVENT:
+		err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
 		compatible_arg = 0;
 		break;
 	}
@@ -972,22 +1170,26 @@
 
 	if (compatible_arg)
 		err = native_ioctl(file, cmd, (unsigned long)up);
-	else {
-		mm_segment_t old_fs = get_fs();
+	else
+		err = native_ioctl(file, cmd, (unsigned long)up_native);
 
-		set_fs(KERNEL_DS);
-		err = native_ioctl(file, cmd, (unsigned long)&karg);
-		set_fs(old_fs);
-	}
+	if (err == -ENOTTY)
+		return err;
 
-	/* Special case: even after an error we need to put the
-	   results back for these ioctls since the error_idx will
-	   contain information on which control failed. */
+	/*
+	 * Special case: even after an error we need to put the
+	 * results back for these ioctls since the error_idx will
+	 * contain information on which control failed.
+	 */
 	switch (cmd) {
 	case VIDIOC_G_EXT_CTRLS:
 	case VIDIOC_S_EXT_CTRLS:
 	case VIDIOC_TRY_EXT_CTRLS:
-		if (put_v4l2_ext_controls32(&karg.v2ecs, up))
+		if (put_v4l2_ext_controls32(file, up_native, up))
+			err = -EFAULT;
+		break;
+	case VIDIOC_S_EDID:
+		if (put_v4l2_edid32(up_native, up))
 			err = -EFAULT;
 		break;
 	}
@@ -999,44 +1201,46 @@
 	case VIDIOC_S_OUTPUT:
 	case VIDIOC_G_INPUT:
 	case VIDIOC_G_OUTPUT:
-		err = put_user(((s32)karg.vi), (s32 __user *)up);
+		if (assign_in_user((compat_uint_t __user *)up,
+				   ((unsigned int __user *)up_native)))
+			err = -EFAULT;
 		break;
 
 	case VIDIOC_G_FBUF:
-		err = put_v4l2_framebuffer32(&karg.v2fb, up);
+		err = put_v4l2_framebuffer32(up_native, up);
 		break;
 
 	case VIDIOC_DQEVENT:
-		err = put_v4l2_event32(&karg.v2ev, up);
+		err = put_v4l2_event32(up_native, up);
 		break;
 
 	case VIDIOC_G_EDID:
-	case VIDIOC_S_EDID:
-		err = put_v4l2_edid32(&karg.v2edid, up);
+		err = put_v4l2_edid32(up_native, up);
 		break;
 
 	case VIDIOC_G_FMT:
 	case VIDIOC_S_FMT:
 	case VIDIOC_TRY_FMT:
-		err = put_v4l2_format32(&karg.v2f, up);
+		err = put_v4l2_format32(up_native, up);
 		break;
 
 	case VIDIOC_CREATE_BUFS:
-		err = put_v4l2_create32(&karg.v2crt, up);
+		err = put_v4l2_create32(up_native, up);
 		break;
 
+	case VIDIOC_PREPARE_BUF:
 	case VIDIOC_QUERYBUF:
 	case VIDIOC_QBUF:
 	case VIDIOC_DQBUF:
-		err = put_v4l2_buffer32(&karg.v2b, up);
+		err = put_v4l2_buffer32(up_native, up);
 		break;
 
 	case VIDIOC_ENUMSTD:
-		err = put_v4l2_standard32(&karg.v2s, up);
+		err = put_v4l2_standard32(up_native, up);
 		break;
 
 	case VIDIOC_ENUMINPUT:
-		err = put_v4l2_input32(&karg.v2i, up);
+		err = put_v4l2_input32(up_native, up);
 		break;
 	}
 	return err;
--- linux-4.4.0.orig/drivers/media/v4l2-core/v4l2-ctrls.c
+++ linux-4.4.0/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -991,6 +991,7 @@
 	case V4L2_CID_FLASH_STROBE_STOP:
 	case V4L2_CID_AUTO_FOCUS_START:
 	case V4L2_CID_AUTO_FOCUS_STOP:
+	case V4L2_CID_DO_WHITE_BALANCE:
 		*type = V4L2_CTRL_TYPE_BUTTON;
 		*flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
 			  V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
@@ -1200,14 +1201,24 @@
 }
 EXPORT_SYMBOL(v4l2_ctrl_fill);
 
+static u32 user_flags(const struct v4l2_ctrl *ctrl)
+{
+	u32 flags = ctrl->flags;
+
+	if (ctrl->is_ptr)
+		flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
+
+	return flags;
+}
+
 static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes)
 {
-	memset(ev->reserved, 0, sizeof(ev->reserved));
+	memset(ev, 0, sizeof(*ev));
 	ev->type = V4L2_EVENT_CTRL;
 	ev->id = ctrl->id;
 	ev->u.ctrl.changes = changes;
 	ev->u.ctrl.type = ctrl->type;
-	ev->u.ctrl.flags = ctrl->flags;
+	ev->u.ctrl.flags = user_flags(ctrl);
 	if (ctrl->is_ptr)
 		ev->u.ctrl.value64 = 0;
 	else
@@ -2063,16 +2074,15 @@
 		v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
 								&def, &flags);
 
-	is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
-		   cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
+	is_menu = (type == V4L2_CTRL_TYPE_MENU ||
+		   type == V4L2_CTRL_TYPE_INTEGER_MENU);
 	if (is_menu)
 		WARN_ON(step);
 	else
 		WARN_ON(cfg->menu_skip_mask);
-	if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL)
+	if (type == V4L2_CTRL_TYPE_MENU && !qmenu) {
 		qmenu = v4l2_ctrl_get_menu(cfg->id);
-	else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU &&
-		 qmenu_int == NULL) {
+	} else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) {
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
@@ -2536,10 +2546,8 @@
 	else
 		qc->id = ctrl->id;
 	strlcpy(qc->name, ctrl->name, sizeof(qc->name));
-	qc->flags = ctrl->flags;
+	qc->flags = user_flags(ctrl);
 	qc->type = ctrl->type;
-	if (ctrl->is_ptr)
-		qc->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
 	qc->elem_size = ctrl->elem_size;
 	qc->elems = ctrl->elems;
 	qc->nr_of_dims = ctrl->nr_of_dims;
--- linux-4.4.0.orig/drivers/media/v4l2-core/v4l2-event.c
+++ linux-4.4.0/drivers/media/v4l2-core/v4l2-event.c
@@ -119,14 +119,6 @@
 	if (sev == NULL)
 		return;
 
-	/*
-	 * If the event has been added to the fh->subscribed list, but its
-	 * add op has not completed yet elems will be 0, treat this as
-	 * not being subscribed.
-	 */
-	if (!sev->elems)
-		return;
-
 	/* Increase event sequence number on fh. */
 	fh->sequence++;
 
@@ -205,6 +197,22 @@
 }
 EXPORT_SYMBOL_GPL(v4l2_event_pending);
 
+static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev)
+{
+	struct v4l2_fh *fh = sev->fh;
+	unsigned int i;
+
+	lockdep_assert_held(&fh->subscribe_lock);
+	assert_spin_locked(&fh->vdev->fh_lock);
+
+	/* Remove any pending events for this subscription */
+	for (i = 0; i < sev->in_use; i++) {
+		list_del(&sev->events[sev_pos(sev, i)].list);
+		fh->navailable--;
+	}
+	list_del(&sev->list);
+}
+
 int v4l2_event_subscribe(struct v4l2_fh *fh,
 			 const struct v4l2_event_subscription *sub, unsigned elems,
 			 const struct v4l2_subscribed_event_ops *ops)
@@ -212,6 +220,7 @@
 	struct v4l2_subscribed_event *sev, *found_ev;
 	unsigned long flags;
 	unsigned i;
+	int ret = 0;
 
 	if (sub->type == V4L2_EVENT_ALL)
 		return -EINVAL;
@@ -229,6 +238,9 @@
 	sev->flags = sub->flags;
 	sev->fh = fh;
 	sev->ops = ops;
+	sev->elems = elems;
+
+	mutex_lock(&fh->subscribe_lock);
 
 	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
 	found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
@@ -237,23 +249,21 @@
 	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
 
 	if (found_ev) {
+		/* Already listening */
 		kfree(sev);
-		return 0; /* Already listening */
-	}
-
-	if (sev->ops && sev->ops->add) {
-		int ret = sev->ops->add(sev, elems);
+	} else if (sev->ops && sev->ops->add) {
+		ret = sev->ops->add(sev, elems);
 		if (ret) {
-			sev->ops = NULL;
-			v4l2_event_unsubscribe(fh, sub);
-			return ret;
+			spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+			__v4l2_event_unsubscribe(sev);
+			spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+			kfree(sev);
 		}
 	}
 
-	/* Mark as ready for use */
-	sev->elems = elems;
+	mutex_unlock(&fh->subscribe_lock);
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
 
@@ -285,24 +295,19 @@
 {
 	struct v4l2_subscribed_event *sev;
 	unsigned long flags;
-	int i;
 
 	if (sub->type == V4L2_EVENT_ALL) {
 		v4l2_event_unsubscribe_all(fh);
 		return 0;
 	}
 
+	mutex_lock(&fh->subscribe_lock);
+
 	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
 
 	sev = v4l2_event_subscribed(fh, sub->type, sub->id);
-	if (sev != NULL) {
-		/* Remove any pending events for this subscription */
-		for (i = 0; i < sev->in_use; i++) {
-			list_del(&sev->events[sev_pos(sev, i)].list);
-			fh->navailable--;
-		}
-		list_del(&sev->list);
-	}
+	if (sev != NULL)
+		__v4l2_event_unsubscribe(sev);
 
 	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
 
@@ -310,6 +315,7 @@
 		sev->ops->del(sev);
 
 	kfree(sev);
+	mutex_unlock(&fh->subscribe_lock);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/media/v4l2-core/v4l2-fh.c
+++ linux-4.4.0/drivers/media/v4l2-core/v4l2-fh.c
@@ -49,6 +49,7 @@
 	INIT_LIST_HEAD(&fh->available);
 	INIT_LIST_HEAD(&fh->subscribed);
 	fh->sequence = -1;
+	mutex_init(&fh->subscribe_lock);
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_init);
 
@@ -93,6 +94,7 @@
 	if (fh->vdev == NULL)
 		return;
 	v4l2_event_unsubscribe_all(fh);
+	mutex_destroy(&fh->subscribe_lock);
 	fh->vdev = NULL;
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_exit);
--- linux-4.4.0.orig/drivers/media/v4l2-core/v4l2-ioctl.c
+++ linux-4.4.0/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -2710,7 +2710,7 @@
 	       v4l2_kioctl func)
 {
 	char	sbuf[128];
-	void    *mbuf = NULL;
+	void    *mbuf = NULL, *array_buf = NULL;
 	void	*parg = (void *)arg;
 	long	err  = -EINVAL;
 	bool	has_array_args;
@@ -2765,26 +2765,23 @@
 	has_array_args = err;
 
 	if (has_array_args) {
-		/*
-		 * When adding new types of array args, make sure that the
-		 * parent argument to ioctl (which contains the pointer to the
-		 * array) fits into sbuf (so that mbuf will still remain
-		 * unused up to here).
-		 */
-		mbuf = kmalloc(array_size, GFP_KERNEL);
+		array_buf = kmalloc(array_size, GFP_KERNEL);
 		err = -ENOMEM;
-		if (NULL == mbuf)
+		if (array_buf == NULL)
 			goto out_array_args;
 		err = -EFAULT;
-		if (copy_from_user(mbuf, user_ptr, array_size))
+		if (copy_from_user(array_buf, user_ptr, array_size))
 			goto out_array_args;
-		*kernel_ptr = mbuf;
+		*kernel_ptr = array_buf;
 	}
 
 	/* Handles IOCTL */
 	err = func(file, cmd, parg);
-	if (err == -ENOIOCTLCMD)
+	if (err == -ENOTTY || err == -ENOIOCTLCMD) {
 		err = -ENOTTY;
+		goto out;
+	}
+
 	if (err == 0) {
 		if (cmd == VIDIOC_DQBUF)
 			trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
@@ -2794,7 +2791,7 @@
 
 	if (has_array_args) {
 		*kernel_ptr = (void __force *)user_ptr;
-		if (copy_to_user(user_ptr, mbuf, array_size))
+		if (copy_to_user(user_ptr, array_buf, array_size))
 			err = -EFAULT;
 		goto out_array_args;
 	}
@@ -2814,6 +2811,7 @@
 	}
 
 out:
+	kfree(array_buf);
 	kfree(mbuf);
 	return err;
 }
--- linux-4.4.0.orig/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ linux-4.4.0/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -156,6 +156,7 @@
 {
 	unsigned long first, last;
 	int err, rw = 0;
+	unsigned int flags = FOLL_FORCE;
 
 	dma->direction = direction;
 	switch (dma->direction) {
@@ -178,13 +179,15 @@
 	if (NULL == dma->pages)
 		return -ENOMEM;
 
+	if (rw == READ)
+		flags |= FOLL_WRITE;
+
 	dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
 		data, size, dma->nr_pages);
 
 	err = get_user_pages(current, current->mm,
 			     data & PAGE_MASK, dma->nr_pages,
-			     rw == READ, 1, /* force */
-			     dma->pages, NULL);
+			     flags, dma->pages, NULL);
 
 	if (err != dma->nr_pages) {
 		dma->nr_pages = (err >= 0) ? err : 0;
--- linux-4.4.0.orig/drivers/media/v4l2-core/videobuf2-core.c
+++ linux-4.4.0/drivers/media/v4l2-core/videobuf2-core.c
@@ -205,6 +205,10 @@
 	struct vb2_buffer *vb;
 	int ret;
 
+	/* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */
+	num_buffers = min_t(unsigned int, num_buffers,
+			    VB2_MAX_FRAME - q->num_buffers);
+
 	for (buffer = 0; buffer < num_buffers; ++buffer) {
 		/* Allocate videobuf buffer structures */
 		vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
@@ -793,7 +797,7 @@
  */
 void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
 {
-	if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
+	if (plane_no >= vb->num_planes || !vb->planes[plane_no].mem_priv)
 		return NULL;
 
 	return call_ptr_memop(vb, vaddr, vb->planes[plane_no].mem_priv);
@@ -1359,6 +1363,11 @@
 	struct vb2_buffer *vb;
 	int ret;
 
+	if (q->error) {
+		dprintk(1, "fatal error occurred on queue\n");
+		return -EIO;
+	}
+
 	vb = q->bufs[index];
 
 	switch (vb->state) {
@@ -1502,10 +1511,10 @@
  * Will sleep if required for nonblocking == false.
  */
 static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
-				int nonblocking)
+			     void *pb, int nonblocking)
 {
 	unsigned long flags;
-	int ret;
+	int ret = 0;
 
 	/*
 	 * Wait for at least one buffer to become available on the done_list.
@@ -1521,12 +1530,14 @@
 	spin_lock_irqsave(&q->done_lock, flags);
 	*vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
 	/*
-	 * Only remove the buffer from done_list if v4l2_buffer can handle all
-	 * the planes.
-	 * Verifying planes is NOT necessary since it already has been checked
-	 * before the buffer is queued/prepared. So it can never fail.
+	 * Only remove the buffer from done_list if all planes can be
+	 * handled. Some cases such as V4L2 file I/O and DVB have pb
+	 * == NULL; skip the check then as there's nothing to verify.
 	 */
-	list_del(&(*vb)->done_entry);
+	if (pb)
+		ret = call_bufop(q, verify_planes_array, *vb, pb);
+	if (!ret)
+		list_del(&(*vb)->done_entry);
 	spin_unlock_irqrestore(&q->done_lock, flags);
 
 	return ret;
@@ -1604,7 +1615,7 @@
 	struct vb2_buffer *vb = NULL;
 	int ret;
 
-	ret = __vb2_get_done_vb(q, &vb, nonblocking);
+	ret = __vb2_get_done_vb(q, &vb, pb, nonblocking);
 	if (ret < 0)
 		return ret;
 
@@ -1965,9 +1976,13 @@
 			return -EINVAL;
 		}
 	}
+
+	mutex_lock(&q->mmap_lock);
+
 	if (vb2_fileio_is_active(q)) {
 		dprintk(1, "mmap: file io in progress\n");
-		return -EBUSY;
+		ret = -EBUSY;
+		goto unlock;
 	}
 
 	/*
@@ -1975,7 +1990,7 @@
 	 */
 	ret = __find_plane_by_offset(q, off, &buffer, &plane);
 	if (ret)
-		return ret;
+		goto unlock;
 
 	vb = q->bufs[buffer];
 
@@ -1988,11 +2003,13 @@
 	if (length < (vma->vm_end - vma->vm_start)) {
 		dprintk(1,
 			"MMAP invalid, as it would overflow buffer length\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto unlock;
 	}
 
-	mutex_lock(&q->mmap_lock);
 	ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
+
+unlock:
 	mutex_unlock(&q->mmap_lock);
 	if (ret)
 		return ret;
--- linux-4.4.0.orig/drivers/media/v4l2-core/videobuf2-memops.c
+++ linux-4.4.0/drivers/media/v4l2-core/videobuf2-memops.c
@@ -42,6 +42,10 @@
 	unsigned long first, last;
 	unsigned long nr;
 	struct frame_vector *vec;
+	unsigned int flags = FOLL_FORCE;
+
+	if (write)
+		flags |= FOLL_WRITE;
 
 	first = start >> PAGE_SHIFT;
 	last = (start + length - 1) >> PAGE_SHIFT;
@@ -49,7 +53,7 @@
 	vec = frame_vector_create(nr);
 	if (!vec)
 		return ERR_PTR(-ENOMEM);
-	ret = get_vaddr_frames(start, nr, write, 1, vec);
+	ret = get_vaddr_frames(start & PAGE_MASK, nr, flags, vec);
 	if (ret < 0)
 		goto out_destroy;
 	/* We accept only complete set of PFNs */
--- linux-4.4.0.orig/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ linux-4.4.0/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -67,6 +67,11 @@
 	return 0;
 }
 
+static int __verify_planes_array_core(struct vb2_buffer *vb, const void *pb)
+{
+	return __verify_planes_array(vb, pb);
+}
+
 /**
  * __verify_length() - Verify that the bytesused value for each plane fits in
  * the plane length and that the data offset doesn't exceed the bytesused value.
@@ -136,7 +141,6 @@
 		return;
 
 	check_once = true;
-	WARN_ON(1);
 
 	pr_warn("use of bytesused == 0 is deprecated and will be removed in the future,\n");
 	if (vb->vb2_queue->allow_zero_bytesused)
@@ -432,6 +436,7 @@
 }
 
 static const struct vb2_buf_ops v4l2_buf_ops = {
+	.verify_planes_array	= __verify_planes_array_core,
 	.fill_user_buffer	= __fill_v4l2_buffer,
 	.fill_vb2_buffer	= __fill_vb2_buffer,
 	.set_timestamp		= __set_timestamp,
@@ -587,6 +592,12 @@
 			b->flags & V4L2_BUF_FLAG_LAST)
 		q->last_buffer_dequeued = true;
 
+	/*
+	 *  After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be
+	 *  cleared.
+	 */
+	b->flags &= ~V4L2_BUF_FLAG_DONE;
+
 	return ret;
 }
 
@@ -822,10 +833,10 @@
 		return res | POLLERR;
 
 	/*
-	 * For output streams you can write as long as there are fewer buffers
-	 * queued than there are buffers available.
+	 * For output streams you can call write() as long as there are fewer
+	 * buffers queued than there are buffers available.
 	 */
-	if (q->is_output && q->queued_count < q->num_buffers)
+	if (q->is_output && q->fileio && q->queued_count < q->num_buffers)
 		return res | POLLOUT | POLLWRNORM;
 
 	if (list_empty(&q->done_list)) {
--- linux-4.4.0.orig/drivers/memory/emif.c
+++ linux-4.4.0/drivers/memory/emif.c
@@ -165,35 +165,12 @@
 
 static int __init_or_module emif_debugfs_init(struct emif_data *emif)
 {
-	struct dentry	*dentry;
-	int		ret;
-
-	dentry = debugfs_create_dir(dev_name(emif->dev), NULL);
-	if (!dentry) {
-		ret = -ENOMEM;
-		goto err0;
-	}
-	emif->debugfs_root = dentry;
-
-	dentry = debugfs_create_file("regcache_dump", S_IRUGO,
-			emif->debugfs_root, emif, &emif_regdump_fops);
-	if (!dentry) {
-		ret = -ENOMEM;
-		goto err1;
-	}
-
-	dentry = debugfs_create_file("mr4", S_IRUGO,
-			emif->debugfs_root, emif, &emif_mr4_fops);
-	if (!dentry) {
-		ret = -ENOMEM;
-		goto err1;
-	}
-
+	emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
+	debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
+			    &emif_regdump_fops);
+	debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
+			    &emif_mr4_fops);
 	return 0;
-err1:
-	debugfs_remove_recursive(emif->debugfs_root);
-err0:
-	return ret;
 }
 
 static void __exit emif_debugfs_exit(struct emif_data *emif)
--- linux-4.4.0.orig/drivers/memory/fsl-corenet-cf.c
+++ linux-4.4.0/drivers/memory/fsl-corenet-cf.c
@@ -215,10 +215,8 @@
 	dev_set_drvdata(&pdev->dev, ccf);
 
 	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		dev_err(&pdev->dev, "%s: no irq\n", __func__);
-		return -ENXIO;
-	}
+	if (irq < 0)
+		return irq;
 
 	ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);
 	if (ret) {
--- linux-4.4.0.orig/drivers/memory/omap-gpmc.c
+++ linux-4.4.0/drivers/memory/omap-gpmc.c
@@ -394,7 +394,7 @@
 	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
 			   GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
 	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
-			   GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
+			   GPMC_CONFIG4_WEEXTRADELAY, p->we_extra_delay);
 	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
 			   GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
 			   p->cycle2cyclesamecsen);
@@ -928,7 +928,7 @@
 	int ret;
 	u32 old_base, size;
 
-	if (cs > gpmc_cs_num) {
+	if (cs >= gpmc_cs_num) {
 		pr_err("%s: requested chip-select is disabled\n", __func__);
 		return -ENODEV;
 	}
@@ -963,7 +963,7 @@
 	struct resource *res = &gpmc->mem;
 	int r = -1;
 
-	if (cs > gpmc_cs_num) {
+	if (cs >= gpmc_cs_num) {
 		pr_err("%s: requested chip-select is disabled\n", __func__);
 		return -ENODEV;
 	}
@@ -1890,9 +1890,7 @@
 	if (!of_property_read_u32(child, "dma-channel", &val))
 		gpmc_onenand_data->dma_channel = val;
 
-	gpmc_onenand_init(gpmc_onenand_data);
-
-	return 0;
+	return gpmc_onenand_init(gpmc_onenand_data);
 }
 #else
 static int gpmc_probe_onenand_child(struct platform_device *pdev,
--- linux-4.4.0.orig/drivers/memory/tegra/mc.c
+++ linux-4.4.0/drivers/memory/tegra/mc.c
@@ -20,14 +20,6 @@
 #include "mc.h"
 
 #define MC_INTSTATUS 0x000
-#define  MC_INT_DECERR_MTS (1 << 16)
-#define  MC_INT_SECERR_SEC (1 << 13)
-#define  MC_INT_DECERR_VPR (1 << 12)
-#define  MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
-#define  MC_INT_INVALID_SMMU_PAGE (1 << 10)
-#define  MC_INT_ARBITRATION_EMEM (1 << 9)
-#define  MC_INT_SECURITY_VIOLATION (1 << 8)
-#define  MC_INT_DECERR_EMEM (1 << 6)
 
 #define MC_INTMASK 0x004
 
@@ -80,7 +72,7 @@
 	u32 value;
 
 	/* compute the number of MC clock cycles per tick */
-	tick = mc->tick * clk_get_rate(mc->clk);
+	tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk);
 	do_div(tick, NSEC_PER_SEC);
 
 	value = readl(mc->regs + MC_EMEM_ARB_CFG);
@@ -248,12 +240,13 @@
 static irqreturn_t tegra_mc_irq(int irq, void *data)
 {
 	struct tegra_mc *mc = data;
-	unsigned long status, mask;
+	unsigned long status;
 	unsigned int bit;
 
 	/* mask all interrupts to avoid flooding */
-	status = mc_readl(mc, MC_INTSTATUS);
-	mask = mc_readl(mc, MC_INTMASK);
+	status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
+	if (!status)
+		return IRQ_NONE;
 
 	for_each_set_bit(bit, &status, 32) {
 		const char *error = status_names[bit] ?: "unknown";
@@ -346,7 +339,6 @@
 	const struct of_device_id *match;
 	struct resource *res;
 	struct tegra_mc *mc;
-	u32 value;
 	int err;
 
 	match = of_match_node(tegra_mc_of_match, pdev->dev.of_node);
@@ -414,11 +406,7 @@
 
 	WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n");
 
-	value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
-		MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
-		MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM;
-
-	mc_writel(mc, value, MC_INTMASK);
+	mc_writel(mc, mc->soc->intmask, MC_INTMASK);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/memory/tegra/mc.h
+++ linux-4.4.0/drivers/memory/tegra/mc.h
@@ -14,6 +14,15 @@
 
 #include <soc/tegra/mc.h>
 
+#define MC_INT_DECERR_MTS (1 << 16)
+#define MC_INT_SECERR_SEC (1 << 13)
+#define MC_INT_DECERR_VPR (1 << 12)
+#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
+#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
+#define MC_INT_ARBITRATION_EMEM (1 << 9)
+#define MC_INT_SECURITY_VIOLATION (1 << 8)
+#define MC_INT_DECERR_EMEM (1 << 6)
+
 static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
 {
 	return readl(mc->regs + offset);
--- linux-4.4.0.orig/drivers/memory/tegra/tegra114.c
+++ linux-4.4.0/drivers/memory/tegra/tegra114.c
@@ -930,4 +930,6 @@
 	.atom_size = 32,
 	.client_id_mask = 0x7f,
 	.smmu = &tegra114_smmu_soc,
+	.intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
+		   MC_INT_DECERR_EMEM,
 };
--- linux-4.4.0.orig/drivers/memory/tegra/tegra124.c
+++ linux-4.4.0/drivers/memory/tegra/tegra124.c
@@ -1007,6 +1007,7 @@
 	.num_swgroups = ARRAY_SIZE(tegra124_swgroups),
 	.supports_round_robin_arbitration = true,
 	.supports_request_limit = true,
+	.num_tlb_lines = 32,
 	.num_asids = 128,
 };
 
@@ -1019,6 +1020,9 @@
 	.smmu = &tegra124_smmu_soc,
 	.emem_regs = tegra124_mc_emem_regs,
 	.num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs),
+	.intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+		   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+		   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
 };
 #endif /* CONFIG_ARCH_TEGRA_124_SOC */
 
@@ -1041,5 +1045,8 @@
 	.atom_size = 32,
 	.client_id_mask = 0x7f,
 	.smmu = &tegra132_smmu_soc,
+	.intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+		   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+		   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
 };
 #endif /* CONFIG_ARCH_TEGRA_132_SOC */
--- linux-4.4.0.orig/drivers/memory/tegra/tegra210.c
+++ linux-4.4.0/drivers/memory/tegra/tegra210.c
@@ -1077,4 +1077,7 @@
 	.atom_size = 64,
 	.client_id_mask = 0xff,
 	.smmu = &tegra210_smmu_soc,
+	.intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+		   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+		   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
 };
--- linux-4.4.0.orig/drivers/memory/tegra/tegra30.c
+++ linux-4.4.0/drivers/memory/tegra/tegra30.c
@@ -952,4 +952,6 @@
 	.atom_size = 16,
 	.client_id_mask = 0x7f,
 	.smmu = &tegra30_smmu_soc,
+	.intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
+		   MC_INT_DECERR_EMEM,
 };
--- linux-4.4.0.orig/drivers/memstick/core/memstick.c
+++ linux-4.4.0/drivers/memstick/core/memstick.c
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #define DRIVER_NAME "memstick"
 
@@ -436,6 +437,7 @@
 	struct memstick_dev *card;
 
 	dev_dbg(&host->dev, "memstick_check started\n");
+	pm_runtime_get_noresume(host->dev.parent);
 	mutex_lock(&host->lock);
 	if (!host->card) {
 		if (memstick_power_on(host))
@@ -467,7 +469,6 @@
 			host->card = card;
 			if (device_register(&card->dev)) {
 				put_device(&card->dev);
-				kfree(host->card);
 				host->card = NULL;
 			}
 		} else
@@ -479,6 +480,7 @@
 		host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
 
 	mutex_unlock(&host->lock);
+	pm_runtime_put(host->dev.parent);
 	dev_dbg(&host->dev, "memstick_check finished\n");
 }
 
@@ -626,13 +628,18 @@
 		return -ENOMEM;
 
 	rc = bus_register(&memstick_bus_type);
-	if (!rc)
-		rc = class_register(&memstick_host_class);
+	if (rc)
+		goto error_destroy_workqueue;
 
-	if (!rc)
-		return 0;
+	rc = class_register(&memstick_host_class);
+	if (rc)
+		goto error_bus_unregister;
+
+	return 0;
 
+error_bus_unregister:
 	bus_unregister(&memstick_bus_type);
+error_destroy_workqueue:
 	destroy_workqueue(workqueue);
 
 	return rc;
--- linux-4.4.0.orig/drivers/memstick/host/jmb38x_ms.c
+++ linux-4.4.0/drivers/memstick/host/jmb38x_ms.c
@@ -947,7 +947,7 @@
 	if (!cnt) {
 		rc = -ENODEV;
 		pci_dev_busy = 1;
-		goto err_out;
+		goto err_out_int;
 	}
 
 	jm = kzalloc(sizeof(struct jmb38x_ms)
--- linux-4.4.0.orig/drivers/memstick/host/r592.c
+++ linux-4.4.0/drivers/memstick/host/r592.c
@@ -763,8 +763,10 @@
 		goto error3;
 
 	dev->mmio = pci_ioremap_bar(pdev, 0);
-	if (!dev->mmio)
+	if (!dev->mmio) {
+		error = -ENOMEM;
 		goto error4;
+	}
 
 	dev->irq = pdev->irq;
 	spin_lock_init(&dev->irq_lock);
@@ -791,12 +793,14 @@
 		&dev->dummy_dma_page_physical_address, GFP_KERNEL);
 	r592_stop_dma(dev , 0);
 
-	if (request_irq(dev->irq, &r592_irq, IRQF_SHARED,
-			  DRV_NAME, dev))
+	error = request_irq(dev->irq, &r592_irq, IRQF_SHARED,
+			  DRV_NAME, dev);
+	if (error)
 		goto error6;
 
 	r592_update_card_detect(dev);
-	if (memstick_add_host(host))
+	error = memstick_add_host(host);
+	if (error)
 		goto error7;
 
 	message("driver successfully loaded");
@@ -829,7 +833,7 @@
 	/* Stop the processing thread.
 	That ensures that we won't take any more requests */
 	kthread_stop(dev->io_thread);
-
+	del_timer_sync(&dev->detect_timer);
 	r592_enable_device(dev, false);
 
 	while (!error && dev->req) {
--- linux-4.4.0.orig/drivers/memstick/host/rtsx_usb_ms.c
+++ linux-4.4.0/drivers/memstick/host/rtsx_usb_ms.c
@@ -524,6 +524,7 @@
 	int rc;
 
 	if (!host->req) {
+		pm_runtime_get_sync(ms_dev(host));
 		do {
 			rc = memstick_next_req(msh, &host->req);
 			dev_dbg(ms_dev(host), "next req %d\n", rc);
@@ -544,6 +545,7 @@
 						host->req->error);
 			}
 		} while (!rc);
+		pm_runtime_put(ms_dev(host));
 	}
 
 }
@@ -570,6 +572,7 @@
 	dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
 			__func__, param, value);
 
+	pm_runtime_get_sync(ms_dev(host));
 	mutex_lock(&ucr->dev_mutex);
 
 	err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD);
@@ -635,6 +638,7 @@
 	}
 out:
 	mutex_unlock(&ucr->dev_mutex);
+	pm_runtime_put(ms_dev(host));
 
 	/* power-on delay */
 	if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON)
@@ -681,6 +685,7 @@
 	int err;
 
 	for (;;) {
+		pm_runtime_get_sync(ms_dev(host));
 		mutex_lock(&ucr->dev_mutex);
 
 		/* Check pending MS card changes */
@@ -703,10 +708,12 @@
 		}
 
 poll_again:
+		pm_runtime_put(ms_dev(host));
 		if (host->eject)
 			break;
 
-		msleep(1000);
+		if (msleep_interruptible(1000))
+			flush_signals(current);
 	}
 
 	complete(&host->detect_ms_exit);
--- linux-4.4.0.orig/drivers/message/fusion/mptbase.c
+++ linux-4.4.0/drivers/message/fusion/mptbase.c
@@ -6848,6 +6848,7 @@
 	*size = y;
 }
 
+#ifdef CONFIG_PROC_FS
 static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
 {
 	char expVer[32];
@@ -6879,6 +6880,7 @@
 
 	seq_putc(m, '\n');
 }
+#endif
 
 /**
  *	mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
--- linux-4.4.0.orig/drivers/message/fusion/mptctl.c
+++ linux-4.4.0/drivers/message/fusion/mptctl.c
@@ -100,19 +100,19 @@
  * Function prototypes. Called from OS entry point mptctl_ioctl.
  * arg contents specific to function.
  */
-static int mptctl_fw_download(unsigned long arg);
-static int mptctl_getiocinfo(unsigned long arg, unsigned int cmd);
-static int mptctl_gettargetinfo(unsigned long arg);
-static int mptctl_readtest(unsigned long arg);
-static int mptctl_mpt_command(unsigned long arg);
-static int mptctl_eventquery(unsigned long arg);
-static int mptctl_eventenable(unsigned long arg);
-static int mptctl_eventreport(unsigned long arg);
-static int mptctl_replace_fw(unsigned long arg);
-
-static int mptctl_do_reset(unsigned long arg);
-static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);
-static int mptctl_hp_targetinfo(unsigned long arg);
+static int mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg);
+static int mptctl_getiocinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd);
+static int mptctl_gettargetinfo(MPT_ADAPTER *iocp, unsigned long arg);
+static int mptctl_readtest(MPT_ADAPTER *iocp, unsigned long arg);
+static int mptctl_mpt_command(MPT_ADAPTER *iocp, unsigned long arg);
+static int mptctl_eventquery(MPT_ADAPTER *iocp, unsigned long arg);
+static int mptctl_eventenable(MPT_ADAPTER *iocp, unsigned long arg);
+static int mptctl_eventreport(MPT_ADAPTER *iocp, unsigned long arg);
+static int mptctl_replace_fw(MPT_ADAPTER *iocp, unsigned long arg);
+
+static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg);
+static int mptctl_hp_hostinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd);
+static int mptctl_hp_targetinfo(MPT_ADAPTER *iocp, unsigned long arg);
 
 static int  mptctl_probe(struct pci_dev *, const struct pci_device_id *);
 static void mptctl_remove(struct pci_dev *);
@@ -123,8 +123,8 @@
 /*
  * Private function calls.
  */
-static int mptctl_do_mpt_command(struct mpt_ioctl_command karg, void __user *mfPtr);
-static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen);
+static int mptctl_do_mpt_command(MPT_ADAPTER *iocp, struct mpt_ioctl_command karg, void __user *mfPtr);
+static int mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen);
 static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags,
 		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
 static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
@@ -656,19 +656,19 @@
 	 * by TM and FW reloads.
 	 */
 	if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) {
-		return mptctl_getiocinfo(arg, _IOC_SIZE(cmd));
+		return mptctl_getiocinfo(iocp, arg, _IOC_SIZE(cmd));
 	} else if (cmd == MPTTARGETINFO) {
-		return mptctl_gettargetinfo(arg);
+		return mptctl_gettargetinfo(iocp, arg);
 	} else if (cmd == MPTTEST) {
-		return mptctl_readtest(arg);
+		return mptctl_readtest(iocp, arg);
 	} else if (cmd == MPTEVENTQUERY) {
-		return mptctl_eventquery(arg);
+		return mptctl_eventquery(iocp, arg);
 	} else if (cmd == MPTEVENTENABLE) {
-		return mptctl_eventenable(arg);
+		return mptctl_eventenable(iocp, arg);
 	} else if (cmd == MPTEVENTREPORT) {
-		return mptctl_eventreport(arg);
+		return mptctl_eventreport(iocp, arg);
 	} else if (cmd == MPTFWREPLACE) {
-		return mptctl_replace_fw(arg);
+		return mptctl_replace_fw(iocp, arg);
 	}
 
 	/* All of these commands require an interrupt or
@@ -678,15 +678,15 @@
 		return ret;
 
 	if (cmd == MPTFWDOWNLOAD)
-		ret = mptctl_fw_download(arg);
+		ret = mptctl_fw_download(iocp, arg);
 	else if (cmd == MPTCOMMAND)
-		ret = mptctl_mpt_command(arg);
+		ret = mptctl_mpt_command(iocp, arg);
 	else if (cmd == MPTHARDRESET)
-		ret = mptctl_do_reset(arg);
+		ret = mptctl_do_reset(iocp, arg);
 	else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK))
-		ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd));
+		ret = mptctl_hp_hostinfo(iocp, arg, _IOC_SIZE(cmd));
 	else if (cmd == HP_GETTARGETINFO)
-		ret = mptctl_hp_targetinfo(arg);
+		ret = mptctl_hp_targetinfo(iocp, arg);
 	else
 		ret = -EINVAL;
 
@@ -705,11 +705,10 @@
 	return ret;
 }
 
-static int mptctl_do_reset(unsigned long arg)
+static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg)
 {
 	struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg;
 	struct mpt_ioctl_diag_reset krinfo;
-	MPT_ADAPTER		*iocp;
 
 	if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
 		printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - "
@@ -718,12 +717,6 @@
 		return -EFAULT;
 	}
 
-	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
-		printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
-				__FILE__, __LINE__, krinfo.hdr.iocnum);
-		return -ENODEV; /* (-6) No such device or address */
-	}
-
 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n",
 	    iocp->name));
 
@@ -754,7 +747,7 @@
  *		-ENOMSG if FW upload returned bad status
  */
 static int
-mptctl_fw_download(unsigned long arg)
+mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg)
 {
 	struct mpt_fw_xfer __user *ufwdl = (void __user *) arg;
 	struct mpt_fw_xfer	 kfwdl;
@@ -766,7 +759,7 @@
 		return -EFAULT;
 	}
 
-	return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
+	return mptctl_do_fw_download(iocp, kfwdl.bufp, kfwdl.fwlen);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -784,11 +777,10 @@
  *		-ENOMSG if FW upload returned bad status
  */
 static int
-mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
+mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen)
 {
 	FWDownload_t		*dlmsg;
 	MPT_FRAME_HDR		*mf;
-	MPT_ADAPTER		*iocp;
 	FWDownloadTCSGE_t	*ptsge;
 	MptSge_t		*sgl, *sgIn;
 	char			*sgOut;
@@ -808,17 +800,10 @@
 	pFWDownloadReply_t	 ReplyMsg = NULL;
 	unsigned long		 timeleft;
 
-	if (mpt_verify_adapter(ioc, &iocp) < 0) {
-		printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
-				 ioc);
-		return -ENODEV; /* (-6) No such device or address */
-	} else {
-
-		/*  Valid device. Get a message frame and construct the FW download message.
-	 	*/
-		if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
-			return -EAGAIN;
-	}
+	/*  Valid device. Get a message frame and construct the FW download message.
+	*/
+	if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
+		return -EAGAIN;
 
 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT
 	    "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id));
@@ -826,8 +811,6 @@
 	    iocp->name, ufwbuf));
 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n",
 	    iocp->name, (int)fwlen));
-	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.ioc   = %04xh\n",
-	    iocp->name, ioc));
 
 	dlmsg = (FWDownload_t*) mf;
 	ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
@@ -1238,13 +1221,11 @@
  *		-ENODEV  if no such device/adapter
  */
 static int
-mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
+mptctl_getiocinfo (MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size)
 {
 	struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg;
 	struct mpt_ioctl_iocinfo *karg;
-	MPT_ADAPTER		*ioc;
 	struct pci_dev		*pdev;
-	int			iocnum;
 	unsigned int		port;
 	int			cim_rev;
 	struct scsi_device 	*sdev;
@@ -1272,14 +1253,6 @@
 		return PTR_ERR(karg);
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		kfree(karg);
-		return -ENODEV;
-	}
-
 	/* Verify the data transfer size is correct. */
 	if (karg->hdr.maxDataSize != data_size) {
 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
@@ -1385,15 +1358,13 @@
  *		-ENODEV  if no such device/adapter
  */
 static int
-mptctl_gettargetinfo (unsigned long arg)
+mptctl_gettargetinfo (MPT_ADAPTER *ioc, unsigned long arg)
 {
 	struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
 	struct mpt_ioctl_targetinfo karg;
-	MPT_ADAPTER		*ioc;
 	VirtDevice		*vdevice;
 	char			*pmem;
 	int			*pdata;
-	int			iocnum;
 	int			numDevices = 0;
 	int			lun;
 	int			maxWordsLeft;
@@ -1408,13 +1379,6 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
-
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n",
 	    ioc->name));
 	/* Get the port number and set the maximum number of bytes
@@ -1510,12 +1474,10 @@
  *		-ENODEV  if no such device/adapter
  */
 static int
-mptctl_readtest (unsigned long arg)
+mptctl_readtest (MPT_ADAPTER *ioc, unsigned long arg)
 {
 	struct mpt_ioctl_test __user *uarg = (void __user *) arg;
 	struct mpt_ioctl_test	 karg;
-	MPT_ADAPTER *ioc;
-	int iocnum;
 
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
 		printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - "
@@ -1524,13 +1486,6 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
-
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n",
 	    ioc->name));
 	/* Fill in the data and return the structure to the calling
@@ -1571,12 +1526,10 @@
  *		-ENODEV  if no such device/adapter
  */
 static int
-mptctl_eventquery (unsigned long arg)
+mptctl_eventquery (MPT_ADAPTER *ioc, unsigned long arg)
 {
 	struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg;
 	struct mpt_ioctl_eventquery	 karg;
-	MPT_ADAPTER *ioc;
-	int iocnum;
 
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
 		printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
@@ -1585,13 +1538,6 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
-
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n",
 	    ioc->name));
 	karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
@@ -1610,12 +1556,10 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int
-mptctl_eventenable (unsigned long arg)
+mptctl_eventenable (MPT_ADAPTER *ioc, unsigned long arg)
 {
 	struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg;
 	struct mpt_ioctl_eventenable	 karg;
-	MPT_ADAPTER *ioc;
-	int iocnum;
 
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
 		printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
@@ -1624,13 +1568,6 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
-
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n",
 	    ioc->name));
 	if (ioc->events == NULL) {
@@ -1658,12 +1595,10 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int
-mptctl_eventreport (unsigned long arg)
+mptctl_eventreport (MPT_ADAPTER *ioc, unsigned long arg)
 {
 	struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg;
 	struct mpt_ioctl_eventreport	 karg;
-	MPT_ADAPTER		 *ioc;
-	int			 iocnum;
 	int			 numBytes, maxEvents, max;
 
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
@@ -1673,12 +1608,6 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
 	    ioc->name));
 
@@ -1712,12 +1641,10 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int
-mptctl_replace_fw (unsigned long arg)
+mptctl_replace_fw (MPT_ADAPTER *ioc, unsigned long arg)
 {
 	struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg;
 	struct mpt_ioctl_replace_fw	 karg;
-	MPT_ADAPTER		 *ioc;
-	int			 iocnum;
 	int			 newFwSize;
 
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
@@ -1727,13 +1654,6 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
-
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n",
 	    ioc->name));
 	/* If caching FW, Free the old FW image
@@ -1780,12 +1700,10 @@
  *		-ENOMEM if memory allocation error
  */
 static int
-mptctl_mpt_command (unsigned long arg)
+mptctl_mpt_command (MPT_ADAPTER *ioc, unsigned long arg)
 {
 	struct mpt_ioctl_command __user *uarg = (void __user *) arg;
 	struct mpt_ioctl_command  karg;
-	MPT_ADAPTER	*ioc;
-	int		iocnum;
 	int		rc;
 
 
@@ -1796,14 +1714,7 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
-
-	rc = mptctl_do_mpt_command (karg, &uarg->MF);
+	rc = mptctl_do_mpt_command (ioc, karg, &uarg->MF);
 
 	return rc;
 }
@@ -1821,9 +1732,8 @@
  *		-EPERM if SCSI I/O and target is untagged
  */
 static int
-mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
+mptctl_do_mpt_command (MPT_ADAPTER *ioc, struct mpt_ioctl_command karg, void __user *mfPtr)
 {
-	MPT_ADAPTER	*ioc;
 	MPT_FRAME_HDR	*mf = NULL;
 	MPIHeader_t	*hdr;
 	char		*psge;
@@ -1832,7 +1742,7 @@
 	dma_addr_t	dma_addr_in;
 	dma_addr_t	dma_addr_out;
 	int		sgSize = 0;	/* Num SG elements */
-	int		iocnum, flagsLength;
+	int		flagsLength;
 	int		sz, rc = 0;
 	int		msgContext;
 	u16		req_idx;
@@ -1847,13 +1757,6 @@
 	bufIn.kptr = bufOut.kptr = NULL;
 	bufIn.len = bufOut.len = 0;
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
-
 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
 	if (ioc->ioc_reset_in_progress) {
 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
@@ -2418,17 +2321,15 @@
  *		-ENOMEM if memory allocation error
  */
 static int
-mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
+mptctl_hp_hostinfo(MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size)
 {
 	hp_host_info_t	__user *uarg = (void __user *) arg;
-	MPT_ADAPTER		*ioc;
 	struct pci_dev		*pdev;
 	char                    *pbuf=NULL;
 	dma_addr_t		buf_dma;
 	hp_host_info_t		karg;
 	CONFIGPARMS		cfg;
 	ConfigPageHeader_t	hdr;
-	int			iocnum;
 	int			rc, cim_rev;
 	ToolboxIstwiReadWriteRequest_t	*IstwiRWRequest;
 	MPT_FRAME_HDR		*mf = NULL;
@@ -2452,12 +2353,6 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-	    (ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
 	    ioc->name));
 
@@ -2670,15 +2565,13 @@
  *		-ENOMEM if memory allocation error
  */
 static int
-mptctl_hp_targetinfo(unsigned long arg)
+mptctl_hp_targetinfo(MPT_ADAPTER *ioc, unsigned long arg)
 {
 	hp_target_info_t __user *uarg = (void __user *) arg;
 	SCSIDevicePage0_t	*pg0_alloc;
 	SCSIDevicePage3_t	*pg3_alloc;
-	MPT_ADAPTER		*ioc;
 	MPT_SCSI_HOST 		*hd = NULL;
 	hp_target_info_t	karg;
-	int			iocnum;
 	int			data_sz;
 	dma_addr_t		page_dma;
 	CONFIGPARMS	 	cfg;
@@ -2692,12 +2585,8 @@
 		return -EFAULT;
 	}
 
-	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
-		(ioc == NULL)) {
-		printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
-		return -ENODEV;
-	}
+	if (karg.hdr.id >= MPT_MAX_FC_DEVICES)
+		return -EINVAL;
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
 	    ioc->name));
 
@@ -2863,7 +2752,7 @@
 	kfw.fwlen = kfw32.fwlen;
 	kfw.bufp = compat_ptr(kfw32.bufp);
 
-	ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+	ret = mptctl_do_fw_download(iocp, kfw.bufp, kfw.fwlen);
 
 	mutex_unlock(&iocp->ioctl_cmds.mutex);
 
@@ -2917,7 +2806,7 @@
 
 	/* Pass new structure to do_mpt_command
 	 */
-	ret = mptctl_do_mpt_command (karg, &uarg->MF);
+	ret = mptctl_do_mpt_command (iocp, karg, &uarg->MF);
 
 	mutex_unlock(&iocp->ioctl_cmds.mutex);
 
--- linux-4.4.0.orig/drivers/message/fusion/mptsas.c
+++ linux-4.4.0/drivers/message/fusion/mptsas.c
@@ -1994,6 +1994,7 @@
 	.cmd_per_lun			= 7,
 	.use_clustering			= ENABLE_CLUSTERING,
 	.shost_attrs			= mptscsih_host_attrs,
+	.no_write_same			= 1,
 };
 
 static int mptsas_get_linkerrors(struct sas_phy *phy)
@@ -4351,11 +4352,10 @@
 			return;
 
 		phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
-		/* Only For SATA Device ADD */
-		if (!phy_info && (sas_device.device_info &
-				MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
+		/* Device hot plug */
+		if (!phy_info) {
 			devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-				"%s %d SATA HOT PLUG: "
+				"%s %d HOT PLUG: "
 				"parent handle of device %x\n", ioc->name,
 				__func__, __LINE__, sas_device.handle_parent));
 			port_info = mptsas_find_portinfo_by_handle(ioc,
--- linux-4.4.0.orig/drivers/message/fusion/mptscsih.c
+++ linux-4.4.0/drivers/message/fusion/mptscsih.c
@@ -118,8 +118,6 @@
 int 		mptscsih_resume(struct pci_dev *pdev);
 #endif
 
-#define SNS_LEN(scp)	SCSI_SENSE_BUFFERSIZE
-
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -1178,8 +1176,10 @@
 
 	scsi_remove_host(host);
 
-	if((hd = shost_priv(host)) == NULL)
-		return;
+	if (host == NULL)
+		hd = NULL;
+	else
+		hd = shost_priv(host);
 
 	mptscsih_shutdown(pdev);
 
@@ -1195,14 +1195,15 @@
 	    "Free'd ScsiLookup (%d) memory\n",
 	    ioc->name, sz1));
 
-	kfree(hd->info_kbuf);
+	if (hd)
+		kfree(hd->info_kbuf);
 
 	/* NULL the Scsi_Host pointer
 	 */
 	ioc->sh = NULL;
 
-	scsi_host_put(host);
-
+	if (host)
+		scsi_host_put(host);
 	mpt_detach(pdev);
 
 }
@@ -2427,7 +2428,7 @@
 		/* Copy the sense received into the scsi command block. */
 		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
 		sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
-		memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
+		memcpy(sc->sense_buffer, sense_data, MPT_SENSE_BUFFER_ALLOC);
 
 		/* Log SMART data (asc = 0x5D, non-IM case only) if required.
 		 */
--- linux-4.4.0.orig/drivers/mfd/Kconfig
+++ linux-4.4.0/drivers/mfd/Kconfig
@@ -1460,6 +1460,7 @@
 config MFD_WM8350_I2C
 	bool "Wolfson Microelectronics WM8350 with I2C"
 	select MFD_WM8350
+	select REGMAP_I2C
 	depends on I2C=y
 	help
 	  The WM8350 is an integrated audio and power management
--- linux-4.4.0.orig/drivers/mfd/ab8500-core.c
+++ linux-4.4.0/drivers/mfd/ab8500-core.c
@@ -259,7 +259,7 @@
 	mutex_unlock(&ab8500->lock);
 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
 
-	return ret;
+	return (ret < 0) ? ret : 0;
 }
 
 static int ab8500_get_register(struct device *dev, u8 bank,
--- linux-4.4.0.orig/drivers/mfd/ab8500-sysctrl.c
+++ linux-4.4.0/drivers/mfd/ab8500-sysctrl.c
@@ -99,7 +99,7 @@
 	u8 bank;
 
 	if (sysctrl_dev == NULL)
-		return -EINVAL;
+		return -EPROBE_DEFER;
 
 	bank = (reg >> 8);
 	if (!valid_bank(bank))
@@ -115,11 +115,13 @@
 	u8 bank;
 
 	if (sysctrl_dev == NULL)
-		return -EINVAL;
+		return -EPROBE_DEFER;
 
 	bank = (reg >> 8);
-	if (!valid_bank(bank))
+	if (!valid_bank(bank)) {
+		pr_err("invalid bank\n");
 		return -EINVAL;
+	}
 
 	return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
 		(u8)(reg & 0xFF), mask, value);
@@ -180,9 +182,15 @@
 	return 0;
 }
 
+static const struct of_device_id ab8500_sysctrl_match[] = {
+	{ .compatible = "stericsson,ab8500-sysctrl", },
+	{}
+};
+
 static struct platform_driver ab8500_sysctrl_driver = {
 	.driver = {
 		.name = "ab8500-sysctrl",
+		.of_match_table = ab8500_sysctrl_match,
 	},
 	.probe = ab8500_sysctrl_probe,
 	.remove = ab8500_sysctrl_remove,
--- linux-4.4.0.orig/drivers/mfd/arizona-core.c
+++ linux-4.4.0/drivers/mfd/arizona-core.c
@@ -967,7 +967,7 @@
 	unsigned int reg, val, mask;
 	int (*apply_patch)(struct arizona *) = NULL;
 	const struct mfd_cell *subdevs = NULL;
-	int n_subdevs, ret, i;
+	int n_subdevs = 0, ret, i;
 
 	dev_set_drvdata(arizona->dev, arizona);
 	mutex_init(&arizona->clk_lock);
--- linux-4.4.0.orig/drivers/mfd/as3722.c
+++ linux-4.4.0/drivers/mfd/as3722.c
@@ -405,6 +405,8 @@
 		goto scrub;
 	}
 
+	device_init_wakeup(as3722->dev, true);
+
 	dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n");
 	return 0;
 
@@ -422,6 +424,29 @@
 	return 0;
 }
 
+static int __maybe_unused as3722_i2c_suspend(struct device *dev)
+{
+	struct as3722 *as3722 = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(as3722->chip_irq);
+	disable_irq(as3722->chip_irq);
+
+	return 0;
+}
+
+static int __maybe_unused as3722_i2c_resume(struct device *dev)
+{
+	struct as3722 *as3722 = dev_get_drvdata(dev);
+
+	enable_irq(as3722->chip_irq);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(as3722->chip_irq);
+
+	return 0;
+}
+
 static const struct of_device_id as3722_of_match[] = {
 	{ .compatible = "ams,as3722", },
 	{},
@@ -434,10 +459,15 @@
 };
 MODULE_DEVICE_TABLE(i2c, as3722_i2c_id);
 
+static const struct dev_pm_ops as3722_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(as3722_i2c_suspend, as3722_i2c_resume)
+};
+
 static struct i2c_driver as3722_i2c_driver = {
 	.driver = {
 		.name = "as3722",
 		.of_match_table = as3722_of_match,
+		.pm = &as3722_pm_ops,
 	},
 	.probe = as3722_i2c_probe,
 	.remove = as3722_i2c_remove,
--- linux-4.4.0.orig/drivers/mfd/atmel-hlcdc.c
+++ linux-4.4.0/drivers/mfd/atmel-hlcdc.c
@@ -50,8 +50,9 @@
 	if (reg <= ATMEL_HLCDC_DIS) {
 		u32 status;
 
-		readl_poll_timeout(hregmap->regs + ATMEL_HLCDC_SR, status,
-				   !(status & ATMEL_HLCDC_SIP), 1, 100);
+		readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
+					  status, !(status & ATMEL_HLCDC_SIP),
+					  1, 100);
 	}
 
 	writel(val, hregmap->regs + reg);
--- linux-4.4.0.orig/drivers/mfd/axp20x.c
+++ linux-4.4.0/drivers/mfd/axp20x.c
@@ -164,14 +164,14 @@
 static struct resource axp288_power_button_resources[] = {
 	{
 		.name	= "PEK_DBR",
-		.start	= AXP288_IRQ_POKN,
-		.end	= AXP288_IRQ_POKN,
+		.start	= AXP288_IRQ_POKP,
+		.end	= AXP288_IRQ_POKP,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		.name	= "PEK_DBF",
-		.start	= AXP288_IRQ_POKP,
-		.end	= AXP288_IRQ_POKP,
+		.start	= AXP288_IRQ_POKN,
+		.end	= AXP288_IRQ_POKN,
 		.flags	= IORESOURCE_IRQ,
 	},
 };
--- linux-4.4.0.orig/drivers/mfd/cros_ec.c
+++ linux-4.4.0/drivers/mfd/cros_ec.c
@@ -68,7 +68,11 @@
 
 	mutex_init(&ec_dev->lock);
 
-	cros_ec_query_all(ec_dev);
+	err = cros_ec_query_all(ec_dev);
+	if (err) {
+		dev_err(dev, "Cannot identify the EC: error %d\n", err);
+		return err;
+	}
 
 	err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, 1,
 			      NULL, ec_dev->irq, NULL);
--- linux-4.4.0.orig/drivers/mfd/cros_ec_spi.c
+++ linux-4.4.0/drivers/mfd/cros_ec_spi.c
@@ -660,6 +660,7 @@
 			   sizeof(struct ec_response_get_protocol_info);
 	ec_dev->dout_size = sizeof(struct ec_host_request);
 
+	ec_spi->last_transfer_ns = ktime_get_ns();
 
 	err = cros_ec_register(ec_dev);
 	if (err) {
--- linux-4.4.0.orig/drivers/mfd/da9062-core.c
+++ linux-4.4.0/drivers/mfd/da9062-core.c
@@ -142,7 +142,7 @@
 		.name		= "da9062-watchdog",
 		.num_resources	= ARRAY_SIZE(da9062_wdt_resources),
 		.resources	= da9062_wdt_resources,
-		.of_compatible  = "dlg,da9062-wdt",
+		.of_compatible  = "dlg,da9062-watchdog",
 	},
 	{
 		.name		= "da9062-thermal",
--- linux-4.4.0.orig/drivers/mfd/db8500-prcmu.c
+++ linux-4.4.0/drivers/mfd/db8500-prcmu.c
@@ -2048,6 +2048,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(db8500_prcmu_config_hotmon);
 
 static int config_hot_period(u16 val)
 {
@@ -2074,11 +2075,13 @@
 
 	return config_hot_period(cycles32k);
 }
+EXPORT_SYMBOL_GPL(db8500_prcmu_start_temp_sense);
 
 int db8500_prcmu_stop_temp_sense(void)
 {
 	return config_hot_period(0xFFFF);
 }
+EXPORT_SYMBOL_GPL(db8500_prcmu_stop_temp_sense);
 
 static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
 {
@@ -2607,7 +2610,7 @@
 	.irq_unmask	= prcmu_irq_unmask,
 };
 
-static __init char *fw_project_name(u32 project)
+static char *fw_project_name(u32 project)
 {
 	switch (project) {
 	case PRCMU_FW_PROJECT_U8500:
@@ -2755,7 +2758,7 @@
 	INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
 }
 
-static void __init init_prcm_registers(void)
+static void init_prcm_registers(void)
 {
 	u32 val;
 
--- linux-4.4.0.orig/drivers/mfd/dln2.c
+++ linux-4.4.0/drivers/mfd/dln2.c
@@ -93,6 +93,11 @@
 	spinlock_t lock;
 };
 
+enum dln2_endpoint {
+	DLN2_EP_OUT	= 0,
+	DLN2_EP_IN	= 1,
+};
+
 struct dln2_dev {
 	struct usb_device *usb_dev;
 	struct usb_interface *interface;
@@ -289,7 +294,11 @@
 	len = urb->actual_length - sizeof(struct dln2_header);
 
 	if (handle == DLN2_HANDLE_EVENT) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&dln2->event_cb_lock, flags);
 		dln2_run_event_callbacks(dln2, id, echo, data, len);
+		spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
 	} else {
 		/* URB will be re-submitted in _dln2_transfer (free_rx_slot) */
 		if (dln2_transfer_complete(dln2, urb, handle, echo))
@@ -729,6 +738,8 @@
 		      const struct usb_device_id *usb_id)
 {
 	struct usb_host_interface *hostif = interface->cur_altsetting;
+	struct usb_endpoint_descriptor *epin;
+	struct usb_endpoint_descriptor *epout;
 	struct device *dev = &interface->dev;
 	struct dln2_dev *dln2;
 	int ret;
@@ -738,12 +749,19 @@
 	    hostif->desc.bNumEndpoints < 2)
 		return -ENODEV;
 
+	epout = &hostif->endpoint[DLN2_EP_OUT].desc;
+	if (!usb_endpoint_is_bulk_out(epout))
+		return -ENODEV;
+	epin = &hostif->endpoint[DLN2_EP_IN].desc;
+	if (!usb_endpoint_is_bulk_in(epin))
+		return -ENODEV;
+
 	dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL);
 	if (!dln2)
 		return -ENOMEM;
 
-	dln2->ep_out = hostif->endpoint[0].desc.bEndpointAddress;
-	dln2->ep_in = hostif->endpoint[1].desc.bEndpointAddress;
+	dln2->ep_out = epout->bEndpointAddress;
+	dln2->ep_in = epin->bEndpointAddress;
 	dln2->usb_dev = usb_get_dev(interface_to_usbdev(interface));
 	dln2->interface = interface;
 	usb_set_intfdata(interface, dln2);
--- linux-4.4.0.orig/drivers/mfd/intel-lpss-acpi.c
+++ linux-4.4.0/drivers/mfd/intel-lpss-acpi.c
@@ -18,6 +18,7 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 
 #include "intel-lpss.h"
 
@@ -25,24 +26,66 @@
 	.clk_rate = 120000000,
 };
 
+static struct property_entry spt_i2c_properties[] = {
+	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
+	{ },
+};
+
+static struct property_set spt_i2c_pset = {
+	.properties = spt_i2c_properties,
+};
+
+static const struct intel_lpss_platform_info spt_i2c_info = {
+	.clk_rate = 120000000,
+	.pset = &spt_i2c_pset,
+};
+
 static const struct intel_lpss_platform_info bxt_info = {
 	.clk_rate = 100000000,
 };
 
+static struct property_entry bxt_i2c_properties[] = {
+	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42),
+	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
+	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
+	{ },
+};
+
+static struct property_set bxt_i2c_pset = {
+	.properties = bxt_i2c_properties,
+};
+
 static const struct intel_lpss_platform_info bxt_i2c_info = {
 	.clk_rate = 133000000,
+	.pset = &bxt_i2c_pset,
+};
+
+static struct property_entry apl_i2c_properties[] = {
+	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
+	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
+	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
+	{ },
+};
+
+static struct property_set apl_i2c_pset = {
+	.properties = apl_i2c_properties,
+};
+
+static const struct intel_lpss_platform_info apl_i2c_info = {
+	.clk_rate = 133000000,
+	.pset = &apl_i2c_pset,
 };
 
 static const struct acpi_device_id intel_lpss_acpi_ids[] = {
 	/* SPT */
-	{ "INT3446", (kernel_ulong_t)&spt_info },
-	{ "INT3447", (kernel_ulong_t)&spt_info },
+	{ "INT3446", (kernel_ulong_t)&spt_i2c_info },
+	{ "INT3447", (kernel_ulong_t)&spt_i2c_info },
 	/* BXT */
 	{ "80860AAC", (kernel_ulong_t)&bxt_i2c_info },
 	{ "80860ABC", (kernel_ulong_t)&bxt_info },
 	{ "80860AC2", (kernel_ulong_t)&bxt_info },
 	/* APL */
-	{ "80865AAC", (kernel_ulong_t)&bxt_i2c_info },
+	{ "80865AAC", (kernel_ulong_t)&apl_i2c_info },
 	{ "80865ABC", (kernel_ulong_t)&bxt_info },
 	{ "80865AC2", (kernel_ulong_t)&bxt_info },
 	{ }
--- linux-4.4.0.orig/drivers/mfd/intel-lpss-pci.c
+++ linux-4.4.0/drivers/mfd/intel-lpss-pci.c
@@ -17,6 +17,7 @@
 #include <linux/pci.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/property.h>
 
 #include "intel-lpss.h"
 
@@ -38,6 +39,8 @@
 	info->mem = &pdev->resource[0];
 	info->irq = pdev->irq;
 
+	pdev->d3cold_delay = 0;
+
 	/* Probably it is enough to set this for iDMA capable devices only */
 	pci_set_master(pdev);
 
@@ -65,9 +68,35 @@
 	.clk_rate = 120000000,
 };
 
+static struct property_entry spt_i2c_properties[] = {
+	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
+	{ },
+};
+
+static struct property_set spt_i2c_pset = {
+	.properties = spt_i2c_properties,
+};
+
+static const struct intel_lpss_platform_info spt_i2c_info = {
+	.clk_rate = 120000000,
+	.pset = &spt_i2c_pset,
+};
+
+static struct property_entry uart_properties[] = {
+	PROPERTY_ENTRY_U32("reg-io-width", 4),
+	PROPERTY_ENTRY_U32("reg-shift", 2),
+	PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"),
+	{ },
+};
+
+static struct property_set uart_pset = {
+	.properties = uart_properties,
+};
+
 static const struct intel_lpss_platform_info spt_uart_info = {
 	.clk_rate = 120000000,
 	.clk_con_id = "baudclk",
+	.pset = &uart_pset,
 };
 
 static const struct intel_lpss_platform_info bxt_info = {
@@ -77,12 +106,42 @@
 static const struct intel_lpss_platform_info bxt_uart_info = {
 	.clk_rate = 100000000,
 	.clk_con_id = "baudclk",
+	.pset = &uart_pset,
+};
+
+static struct property_entry bxt_i2c_properties[] = {
+	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42),
+	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
+	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
+	{ },
+};
+
+static struct property_set bxt_i2c_pset = {
+	.properties = bxt_i2c_properties,
 };
 
 static const struct intel_lpss_platform_info bxt_i2c_info = {
 	.clk_rate = 133000000,
+	.pset = &bxt_i2c_pset,
+};
+
+static struct property_entry apl_i2c_properties[] = {
+	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
+	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
+	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
+	{ },
+};
+
+static struct property_set apl_i2c_pset = {
+	.properties = apl_i2c_properties,
+};
+
+static const struct intel_lpss_platform_info apl_i2c_info = {
+	.clk_rate = 133000000,
+	.pset = &apl_i2c_pset,
 };
 
+
 static const struct pci_device_id intel_lpss_pci_ids[] = {
 	/* BXT */
 	{ PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
@@ -101,14 +160,14 @@
 	{ PCI_VDEVICE(INTEL, 0x0ac6), (kernel_ulong_t)&bxt_info },
 	{ PCI_VDEVICE(INTEL, 0x0aee), (kernel_ulong_t)&bxt_uart_info },
 	/* APL */
-	{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x5ab0), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x5ab2), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x5ab4), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x5ab6), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x5ab8), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x5aba), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x5ab0), (kernel_ulong_t)&apl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x5ab2), (kernel_ulong_t)&apl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x5ab4), (kernel_ulong_t)&apl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x5ab6), (kernel_ulong_t)&apl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x5ab8), (kernel_ulong_t)&apl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x5aba), (kernel_ulong_t)&apl_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0x5abc), (kernel_ulong_t)&bxt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0x5abe), (kernel_ulong_t)&bxt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0x5ac0), (kernel_ulong_t)&bxt_uart_info },
@@ -121,21 +180,31 @@
 	{ PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info },
 	{ PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info },
-	{ PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_info },
-	{ PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_info },
-	{ PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_info },
-	{ PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_info },
-	{ PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_info },
-	{ PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_info },
+	{ PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info },
 	/* SPT-H */
 	{ PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info },
 	{ PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info },
-	{ PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_info },
-	{ PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_info },
+	{ PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info },
+	/* KBL-H */
+	{ PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&spt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0xa2a8), (kernel_ulong_t)&spt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&spt_info },
+	{ PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&spt_info },
+	{ PCI_VDEVICE(INTEL, 0xa2e0), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0xa2e1), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0xa2e3), (kernel_ulong_t)&spt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0xa2e6), (kernel_ulong_t)&spt_uart_info },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
--- linux-4.4.0.orig/drivers/mfd/intel-lpss.c
+++ linux-4.4.0/drivers/mfd/intel-lpss.c
@@ -24,6 +24,7 @@
 #include <linux/mfd/core.h>
 #include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
+#include <linux/property.h>
 #include <linux/seq_file.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 
@@ -33,6 +34,7 @@
 #define LPSS_DEV_SIZE		0x200
 #define LPSS_PRIV_OFFSET	0x200
 #define LPSS_PRIV_SIZE		0x100
+#define LPSS_PRIV_REG_COUNT	(LPSS_PRIV_SIZE / 4)
 #define LPSS_IDMA64_OFFSET	0x800
 #define LPSS_IDMA64_SIZE	0x800
 
@@ -72,9 +74,10 @@
 	enum intel_lpss_dev_type type;
 	struct clk *clk;
 	struct clk_lookup *clock;
-	const struct mfd_cell *cell;
+	struct mfd_cell *cell;
 	struct device *dev;
 	void __iomem *priv;
+	u32 priv_ctx[LPSS_PRIV_REG_COUNT];
 	int devid;
 	u32 caps;
 	u32 active_ltr;
@@ -217,6 +220,7 @@
 
 static int intel_lpss_assign_devs(struct intel_lpss *lpss)
 {
+	const struct mfd_cell *cell;
 	unsigned int type;
 
 	type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK;
@@ -224,18 +228,22 @@
 
 	switch (type) {
 	case LPSS_DEV_I2C:
-		lpss->cell = &intel_lpss_i2c_cell;
+		cell = &intel_lpss_i2c_cell;
 		break;
 	case LPSS_DEV_UART:
-		lpss->cell = &intel_lpss_uart_cell;
+		cell = &intel_lpss_uart_cell;
 		break;
 	case LPSS_DEV_SPI:
-		lpss->cell = &intel_lpss_spi_cell;
+		cell = &intel_lpss_spi_cell;
 		break;
 	default:
 		return -ENODEV;
 	}
 
+	lpss->cell = devm_kmemdup(lpss->dev, cell, sizeof(*cell), GFP_KERNEL);
+	if (!lpss->cell)
+		return -ENOMEM;
+
 	lpss->type = type;
 
 	return 0;
@@ -265,13 +273,16 @@
 {
 	u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN;
 
+	/* Set the device in reset state */
+	writel(0, lpss->priv + LPSS_PRIV_RESETS);
+
 	intel_lpss_deassert_reset(lpss);
 
+	intel_lpss_set_remap_addr(lpss);
+
 	if (!intel_lpss_has_idma(lpss))
 		return;
 
-	intel_lpss_set_remap_addr(lpss);
-
 	/* Make sure that SPI multiblock DMA transfers are re-enabled */
 	if (lpss->type == LPSS_DEV_SPI)
 		writel(value, lpss->priv + LPSS_PRIV_SSP_REG);
@@ -401,6 +412,8 @@
 	if (ret)
 		return ret;
 
+	lpss->cell->pset = info->pset;
+
 	intel_lpss_init_dev(lpss);
 
 	lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL);
@@ -445,6 +458,7 @@
 err_remove_ltr:
 	intel_lpss_debugfs_remove(lpss);
 	intel_lpss_ltr_hide(lpss);
+	intel_lpss_unregister_clock(lpss);
 
 err_clk_register:
 	ida_simple_remove(&intel_lpss_devid_ida, lpss->devid);
@@ -484,6 +498,13 @@
 
 int intel_lpss_suspend(struct device *dev)
 {
+	struct intel_lpss *lpss = dev_get_drvdata(dev);
+	unsigned int i;
+
+	/* Save device context */
+	for (i = 0; i < LPSS_PRIV_REG_COUNT; i++)
+		lpss->priv_ctx[i] = readl(lpss->priv + i * 4);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(intel_lpss_suspend);
@@ -491,8 +512,13 @@
 int intel_lpss_resume(struct device *dev)
 {
 	struct intel_lpss *lpss = dev_get_drvdata(dev);
+	unsigned int i;
 
-	intel_lpss_init_dev(lpss);
+	intel_lpss_deassert_reset(lpss);
+
+	/* Restore device context */
+	for (i = 0; i < LPSS_PRIV_REG_COUNT; i++)
+		writel(lpss->priv_ctx[i], lpss->priv + i * 4);
 
 	return 0;
 }
@@ -507,6 +533,7 @@
 
 static void __exit intel_lpss_exit(void)
 {
+	ida_destroy(&intel_lpss_devid_ida);
 	debugfs_remove(intel_lpss_debugfs);
 }
 module_exit(intel_lpss_exit);
--- linux-4.4.0.orig/drivers/mfd/intel-lpss.h
+++ linux-4.4.0/drivers/mfd/intel-lpss.h
@@ -16,12 +16,14 @@
 
 struct device;
 struct resource;
+struct property_set;
 
 struct intel_lpss_platform_info {
 	struct resource *mem;
 	int irq;
 	unsigned long clk_rate;
 	const char *clk_con_id;
+	struct property_set *pset;
 };
 
 int intel_lpss_probe(struct device *dev,
--- linux-4.4.0.orig/drivers/mfd/intel_soc_pmic_core.c
+++ linux-4.4.0/drivers/mfd/intel_soc_pmic_core.c
@@ -35,6 +35,7 @@
 	.table = {
 		/* Panel EN/DISABLE */
 		GPIO_LOOKUP("gpio_crystalcove", 94, "panel", GPIO_ACTIVE_HIGH),
+		{ },
 	},
 };
 
--- linux-4.4.0.orig/drivers/mfd/lp8788-irq.c
+++ linux-4.4.0/drivers/mfd/lp8788-irq.c
@@ -112,7 +112,7 @@
 	struct lp8788_irq_data *irqd = ptr;
 	struct lp8788 *lp = irqd->lp;
 	u8 status[NUM_REGS], addr, mask;
-	bool handled;
+	bool handled = false;
 	int i;
 
 	if (lp8788_read_multi_bytes(lp, LP8788_INT_1, status, NUM_REGS))
--- linux-4.4.0.orig/drivers/mfd/max8997.c
+++ linux-4.4.0/drivers/mfd/max8997.c
@@ -156,12 +156,6 @@
 
 	pd->ono = irq_of_parse_and_map(dev->of_node, 1);
 
-	/*
-	 * ToDo: the 'wakeup' member in the platform data is more of a linux
-	 * specfic information. Hence, there is no binding for that yet and
-	 * not parsed here.
-	 */
-
 	return pd;
 }
 
@@ -249,7 +243,7 @@
 	 */
 
 	/* MAX8997 has a power button input. */
-	device_init_wakeup(max8997->dev, pdata->wakeup);
+	device_init_wakeup(max8997->dev, true);
 
 	return ret;
 
--- linux-4.4.0.orig/drivers/mfd/mc13xxx-core.c
+++ linux-4.4.0/drivers/mfd/mc13xxx-core.c
@@ -274,9 +274,12 @@
 
 	mc13xxx->adcflags |= MC13XXX_ADC_WORKING;
 
-	mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
+	ret = mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
+	if (ret)
+		goto out;
 
-	adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2;
+	adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2 |
+	       MC13XXX_ADC0_CHRGRAWDIV;
 	adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC;
 
 	if (channel > 7)
--- linux-4.4.0.orig/drivers/mfd/mfd-core.c
+++ linux-4.4.0/drivers/mfd/mfd-core.c
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
+#include <linux/property.h>
 #include <linux/mfd/core.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
@@ -31,6 +32,11 @@
 	const struct mfd_cell *cell = mfd_get_cell(pdev);
 	int err = 0;
 
+	if (!cell->enable) {
+		dev_dbg(&pdev->dev, "No .enable() call-back registered\n");
+		return 0;
+	}
+
 	/* only call enable hook if the cell wasn't previously enabled */
 	if (atomic_inc_return(cell->usage_count) == 1)
 		err = cell->enable(pdev);
@@ -48,6 +54,11 @@
 	const struct mfd_cell *cell = mfd_get_cell(pdev);
 	int err = 0;
 
+	if (!cell->disable) {
+		dev_dbg(&pdev->dev, "No .disable() call-back registered\n");
+		return 0;
+	}
+
 	/* only disable if no other clients are using it */
 	if (atomic_dec_return(cell->usage_count) == 0)
 		err = cell->disable(pdev);
@@ -178,6 +189,7 @@
 		for_each_child_of_node(parent->of_node, np) {
 			if (of_device_is_compatible(np, cell->of_compatible)) {
 				pdev->dev.of_node = np;
+				pdev->dev.fwnode = &np->fwnode;
 				break;
 			}
 		}
@@ -192,6 +204,12 @@
 			goto fail_alias;
 	}
 
+	if (cell->pset) {
+		ret = platform_device_add_properties(pdev, cell->pset);
+		if (ret)
+			goto fail_alias;
+	}
+
 	ret = mfd_platform_add_cell(pdev, cell, usage_count);
 	if (ret)
 		goto fail_alias;
@@ -354,6 +372,8 @@
 					clones[i]);
 	}
 
+	put_device(dev);
+
 	return 0;
 }
 EXPORT_SYMBOL(mfd_clone_cell);
--- linux-4.4.0.orig/drivers/mfd/omap-usb-host.c
+++ linux-4.4.0/drivers/mfd/omap-usb-host.c
@@ -548,8 +548,8 @@
 }
 
 static const struct of_device_id usbhs_child_match_table[] = {
-	{ .compatible = "ti,omap-ehci", },
-	{ .compatible = "ti,omap-ohci", },
+	{ .compatible = "ti,ehci-omap", },
+	{ .compatible = "ti,ohci-omap3", },
 	{ }
 };
 
@@ -875,6 +875,7 @@
 		.pm		= &usbhsomap_dev_pm_ops,
 		.of_match_table = usbhs_omap_dt_ids,
 	},
+	.probe		= usbhs_omap_probe,
 	.remove		= usbhs_omap_remove,
 };
 
@@ -884,9 +885,9 @@
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI");
 
-static int __init omap_usbhs_drvinit(void)
+static int omap_usbhs_drvinit(void)
 {
-	return platform_driver_probe(&usbhs_omap_driver, usbhs_omap_probe);
+	return platform_driver_register(&usbhs_omap_driver);
 }
 
 /*
@@ -898,7 +899,7 @@
  */
 fs_initcall_sync(omap_usbhs_drvinit);
 
-static void __exit omap_usbhs_drvexit(void)
+static void omap_usbhs_drvexit(void)
 {
 	platform_driver_unregister(&usbhs_omap_driver);
 }
--- linux-4.4.0.orig/drivers/mfd/omap-usb-tll.c
+++ linux-4.4.0/drivers/mfd/omap-usb-tll.c
@@ -129,12 +129,12 @@
 	return readl_relaxed(base + reg);
 }
 
-static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val)
+static inline void usbtll_writeb(void __iomem *base, u32 reg, u8 val)
 {
 	writeb_relaxed(val, base + reg);
 }
 
-static inline u8 usbtll_readb(void __iomem *base, u8 reg)
+static inline u8 usbtll_readb(void __iomem *base, u32 reg)
 {
 	return readb_relaxed(base + reg);
 }
@@ -269,6 +269,8 @@
 
 		if (IS_ERR(tll->ch_clk[i]))
 			dev_dbg(dev, "can't get clock : %s\n", clkname);
+		else
+			clk_prepare(tll->ch_clk[i]);
 	}
 
 	pm_runtime_put_sync(dev);
@@ -301,9 +303,12 @@
 	tll_dev = NULL;
 	spin_unlock(&tll_lock);
 
-	for (i = 0; i < tll->nch; i++)
-		if (!IS_ERR(tll->ch_clk[i]))
+	for (i = 0; i < tll->nch; i++) {
+		if (!IS_ERR(tll->ch_clk[i])) {
+			clk_unprepare(tll->ch_clk[i]);
 			clk_put(tll->ch_clk[i]);
+		}
+	}
 
 	pm_runtime_disable(&pdev->dev);
 	return 0;
@@ -370,8 +375,8 @@
 				 * and use SDR Mode
 				 */
 				reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
-					| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
 					| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
+				reg |= OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
 			} else if (pdata->port_mode[i] ==
 					OMAP_EHCI_PORT_MODE_HSIC) {
 				/*
@@ -420,7 +425,7 @@
 			if (IS_ERR(tll->ch_clk[i]))
 				continue;
 
-			r = clk_prepare_enable(tll->ch_clk[i]);
+			r = clk_enable(tll->ch_clk[i]);
 			if (r) {
 				dev_err(tll_dev,
 				 "Error enabling ch %d clock: %d\n", i, r);
@@ -448,7 +453,7 @@
 	for (i = 0; i < tll->nch; i++) {
 		if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
 			if (!IS_ERR(tll->ch_clk[i]))
-				clk_disable_unprepare(tll->ch_clk[i]);
+				clk_disable(tll->ch_clk[i]);
 		}
 	}
 
--- linux-4.4.0.orig/drivers/mfd/palmas.c
+++ linux-4.4.0/drivers/mfd/palmas.c
@@ -430,6 +430,20 @@
 {
 	unsigned int addr;
 	int ret, slave;
+	struct device_node *np = palmas_dev->dev->of_node;
+
+	if (of_property_read_bool(np, "ti,palmas-override-powerhold")) {
+		addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+					  PALMAS_PRIMARY_SECONDARY_PAD2);
+		slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
+
+		ret = regmap_update_bits(palmas_dev->regmap[slave], addr,
+				PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK, 0);
+		if (ret)
+			dev_err(palmas_dev->dev,
+				"Unable to write PRIMARY_SECONDARY_PAD2 %d\n",
+				ret);
+	}
 
 	if (!palmas_dev)
 		return;
--- linux-4.4.0.orig/drivers/mfd/qcom_rpm.c
+++ linux-4.4.0/drivers/mfd/qcom_rpm.c
@@ -34,7 +34,13 @@
 struct qcom_rpm_data {
 	u32 version;
 	const struct qcom_rpm_resource *resource_table;
-	unsigned n_resources;
+	unsigned int n_resources;
+	unsigned int req_ctx_off;
+	unsigned int req_sel_off;
+	unsigned int ack_ctx_off;
+	unsigned int ack_sel_off;
+	unsigned int req_sel_size;
+	unsigned int ack_sel_size;
 };
 
 struct qcom_rpm {
@@ -61,11 +67,7 @@
 
 #define RPM_REQUEST_TIMEOUT	(5 * HZ)
 
-#define RPM_REQUEST_CONTEXT	3
-#define RPM_REQ_SELECT		11
-#define RPM_ACK_CONTEXT		15
-#define RPM_ACK_SELECTOR	23
-#define RPM_SELECT_SIZE		7
+#define RPM_MAX_SEL_SIZE	7
 
 #define RPM_NOTIFICATION	BIT(30)
 #define RPM_REJECTED		BIT(31)
@@ -157,6 +159,12 @@
 	.version = 3,
 	.resource_table = apq8064_rpm_resource_table,
 	.n_resources = ARRAY_SIZE(apq8064_rpm_resource_table),
+	.req_ctx_off = 3,
+	.req_sel_off = 11,
+	.ack_ctx_off = 15,
+	.ack_sel_off = 23,
+	.req_sel_size = 4,
+	.ack_sel_size = 7,
 };
 
 static const struct qcom_rpm_resource msm8660_rpm_resource_table[] = {
@@ -240,6 +248,12 @@
 	.version = 2,
 	.resource_table = msm8660_rpm_resource_table,
 	.n_resources = ARRAY_SIZE(msm8660_rpm_resource_table),
+	.req_ctx_off = 3,
+	.req_sel_off = 11,
+	.ack_ctx_off = 19,
+	.ack_sel_off = 27,
+	.req_sel_size = 7,
+	.ack_sel_size = 7,
 };
 
 static const struct qcom_rpm_resource msm8960_rpm_resource_table[] = {
@@ -322,6 +336,12 @@
 	.version = 3,
 	.resource_table = msm8960_rpm_resource_table,
 	.n_resources = ARRAY_SIZE(msm8960_rpm_resource_table),
+	.req_ctx_off = 3,
+	.req_sel_off = 11,
+	.ack_ctx_off = 15,
+	.ack_sel_off = 23,
+	.req_sel_size = 4,
+	.ack_sel_size = 7,
 };
 
 static const struct qcom_rpm_resource ipq806x_rpm_resource_table[] = {
@@ -362,6 +382,12 @@
 	.version = 3,
 	.resource_table = ipq806x_rpm_resource_table,
 	.n_resources = ARRAY_SIZE(ipq806x_rpm_resource_table),
+	.req_ctx_off = 3,
+	.req_sel_off = 11,
+	.ack_ctx_off = 15,
+	.ack_sel_off = 23,
+	.req_sel_size = 4,
+	.ack_sel_size = 7,
 };
 
 static const struct of_device_id qcom_rpm_of_match[] = {
@@ -380,7 +406,7 @@
 {
 	const struct qcom_rpm_resource *res;
 	const struct qcom_rpm_data *data = rpm->data;
-	u32 sel_mask[RPM_SELECT_SIZE] = { 0 };
+	u32 sel_mask[RPM_MAX_SEL_SIZE] = { 0 };
 	int left;
 	int ret = 0;
 	int i;
@@ -398,12 +424,12 @@
 		writel_relaxed(buf[i], RPM_REQ_REG(rpm, res->target_id + i));
 
 	bitmap_set((unsigned long *)sel_mask, res->select_id, 1);
-	for (i = 0; i < ARRAY_SIZE(sel_mask); i++) {
+	for (i = 0; i < rpm->data->req_sel_size; i++) {
 		writel_relaxed(sel_mask[i],
-			       RPM_CTRL_REG(rpm, RPM_REQ_SELECT + i));
+			       RPM_CTRL_REG(rpm, rpm->data->req_sel_off + i));
 	}
 
-	writel_relaxed(BIT(state), RPM_CTRL_REG(rpm, RPM_REQUEST_CONTEXT));
+	writel_relaxed(BIT(state), RPM_CTRL_REG(rpm, rpm->data->req_ctx_off));
 
 	reinit_completion(&rpm->ack);
 	regmap_write(rpm->ipc_regmap, rpm->ipc_offset, BIT(rpm->ipc_bit));
@@ -426,10 +452,11 @@
 	u32 ack;
 	int i;
 
-	ack = readl_relaxed(RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT));
-	for (i = 0; i < RPM_SELECT_SIZE; i++)
-		writel_relaxed(0, RPM_CTRL_REG(rpm, RPM_ACK_SELECTOR + i));
-	writel(0, RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT));
+	ack = readl_relaxed(RPM_CTRL_REG(rpm, rpm->data->ack_ctx_off));
+	for (i = 0; i < rpm->data->ack_sel_size; i++)
+		writel_relaxed(0,
+			RPM_CTRL_REG(rpm, rpm->data->ack_sel_off + i));
+	writel(0, RPM_CTRL_REG(rpm, rpm->data->ack_ctx_off));
 
 	if (ack & RPM_NOTIFICATION) {
 		dev_warn(rpm->dev, "ignoring notification!\n");
@@ -543,6 +570,10 @@
 		return -EFAULT;
 	}
 
+	writel(fw_version[0], RPM_CTRL_REG(rpm, 0));
+	writel(fw_version[1], RPM_CTRL_REG(rpm, 1));
+	writel(fw_version[2], RPM_CTRL_REG(rpm, 2));
+
 	dev_info(&pdev->dev, "RPM firmware %u.%u.%u\n", fw_version[0],
 							fw_version[1],
 							fw_version[2]);
--- linux-4.4.0.orig/drivers/mfd/rn5t618.c
+++ linux-4.4.0/drivers/mfd/rn5t618.c
@@ -28,6 +28,7 @@
 	case RN5T618_WATCHDOGCNT:
 	case RN5T618_DCIRQ:
 	case RN5T618_ILIMDATAH ... RN5T618_AIN0DATAL:
+	case RN5T618_ADCCNT3:
 	case RN5T618_IR_ADC1 ... RN5T618_IR_ADC3:
 	case RN5T618_IR_GPR:
 	case RN5T618_IR_GPF:
--- linux-4.4.0.orig/drivers/mfd/rts5227.c
+++ linux-4.4.0/drivers/mfd/rts5227.c
@@ -369,6 +369,7 @@
 void rts522a_init_params(struct rtsx_pcr *pcr)
 {
 	rts5227_init_params(pcr);
+	pcr->ops = &rts522a_pcr_ops;
 
 	pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3;
 }
--- linux-4.4.0.orig/drivers/mfd/rtsx_pcr.c
+++ linux-4.4.0/drivers/mfd/rtsx_pcr.c
@@ -1255,12 +1255,14 @@
 	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
 			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
 	if (ret < 0)
-		goto disable_irq;
+		goto free_slots;
 
 	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
 
 	return 0;
 
+free_slots:
+	kfree(pcr->slots);
 disable_irq:
 	free_irq(pcr->irq, (void *)pcr);
 disable_msi:
--- linux-4.4.0.orig/drivers/mfd/rtsx_usb.c
+++ linux-4.4.0/drivers/mfd/rtsx_usb.c
@@ -46,9 +46,6 @@
 
 	dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
 	usb_sg_cancel(&ucr->current_sg);
-
-	/* we know the cancellation is caused by time-out */
-	ucr->current_sg.status = -ETIMEDOUT;
 }
 
 static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
@@ -67,12 +64,15 @@
 	ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
 	add_timer(&ucr->sg_timer);
 	usb_sg_wait(&ucr->current_sg);
-	del_timer_sync(&ucr->sg_timer);
+	if (!del_timer_sync(&ucr->sg_timer))
+		ret = -ETIMEDOUT;
+	else
+		ret = ucr->current_sg.status;
 
 	if (act_len)
 		*act_len = ucr->current_sg.bytes;
 
-	return ucr->current_sg.status;
+	return ret;
 }
 
 int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
--- linux-4.4.0.orig/drivers/mfd/sm501.c
+++ linux-4.4.0/drivers/mfd/sm501.c
@@ -714,6 +714,7 @@
 	smdev->pdev.name = name;
 	smdev->pdev.id = sm->pdev_id;
 	smdev->pdev.dev.parent = sm->dev;
+	smdev->pdev.dev.coherent_dma_mask = 0xffffffff;
 
 	if (res_count) {
 		smdev->pdev.resource = (struct resource *)(smdev+1);
@@ -1429,8 +1430,14 @@
 		goto err_claim;
 	}
 
-	return sm501_init_dev(sm);
+	ret = sm501_init_dev(sm);
+	if (ret)
+		goto err_unmap;
+
+	return 0;
 
+ err_unmap:
+	iounmap(sm->regs);
  err_claim:
 	release_resource(sm->regs_claim);
 	kfree(sm->regs_claim);
--- linux-4.4.0.orig/drivers/mfd/ti_am335x_tscadc.c
+++ linux-4.4.0/drivers/mfd/ti_am335x_tscadc.c
@@ -224,14 +224,13 @@
 	 * The TSC_ADC_SS controller design assumes the OCP clock is
 	 * at least 6x faster than the ADC clock.
 	 */
-	clk = clk_get(&pdev->dev, "adc_tsc_fck");
+	clk = devm_clk_get(&pdev->dev, "adc_tsc_fck");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get TSC fck\n");
 		err = PTR_ERR(clk);
 		goto err_disable_clk;
 	}
 	clock_rate = clk_get_rate(clk);
-	clk_put(clk);
 	tscadc->clk_div = clock_rate / ADC_CLK;
 
 	/* TSCADC_CLKDIV needs to be configured to the value minus 1 */
@@ -280,8 +279,9 @@
 		cell->pdata_size = sizeof(tscadc);
 	}
 
-	err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells,
-			tscadc->used_cells, NULL, 0, NULL);
+	err = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
+			      tscadc->cells, tscadc->used_cells, NULL,
+			      0, NULL);
 	if (err < 0)
 		goto err_disable_clk;
 
--- linux-4.4.0.orig/drivers/mfd/tps6586x.c
+++ linux-4.4.0/drivers/mfd/tps6586x.c
@@ -594,6 +594,29 @@
 	return 0;
 }
 
+static int __maybe_unused tps6586x_i2c_suspend(struct device *dev)
+{
+	struct tps6586x *tps6586x = dev_get_drvdata(dev);
+
+	if (tps6586x->client->irq)
+		disable_irq(tps6586x->client->irq);
+
+	return 0;
+}
+
+static int __maybe_unused tps6586x_i2c_resume(struct device *dev)
+{
+	struct tps6586x *tps6586x = dev_get_drvdata(dev);
+
+	if (tps6586x->client->irq)
+		enable_irq(tps6586x->client->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_i2c_suspend,
+			 tps6586x_i2c_resume);
+
 static const struct i2c_device_id tps6586x_id_table[] = {
 	{ "tps6586x", 0 },
 	{ },
@@ -604,6 +627,7 @@
 	.driver	= {
 		.name	= "tps6586x",
 		.of_match_table = of_match_ptr(tps6586x_of_match),
+		.pm	= &tps6586x_pm_ops,
 	},
 	.probe		= tps6586x_i2c_probe,
 	.remove		= tps6586x_i2c_remove,
--- linux-4.4.0.orig/drivers/mfd/twl-core.c
+++ linux-4.4.0/drivers/mfd/twl-core.c
@@ -982,7 +982,7 @@
  * letting it generate the right frequencies for USB, MADC, and
  * other purposes.
  */
-static inline int __init protect_pm_master(void)
+static inline int protect_pm_master(void)
 {
 	int e = 0;
 
@@ -991,7 +991,7 @@
 	return e;
 }
 
-static inline int __init unprotect_pm_master(void)
+static inline int unprotect_pm_master(void)
 {
 	int e = 0;
 
--- linux-4.4.0.orig/drivers/mfd/twl4030-audio.c
+++ linux-4.4.0/drivers/mfd/twl4030-audio.c
@@ -159,13 +159,18 @@
 EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk);
 
 static bool twl4030_audio_has_codec(struct twl4030_audio_data *pdata,
-			      struct device_node *node)
+			      struct device_node *parent)
 {
+	struct device_node *node;
+
 	if (pdata && pdata->codec)
 		return true;
 
-	if (of_find_node_by_name(node, "codec"))
+	node = of_get_child_by_name(parent, "codec");
+	if (node) {
+		of_node_put(node);
 		return true;
+	}
 
 	return false;
 }
--- linux-4.4.0.orig/drivers/mfd/twl6040.c
+++ linux-4.4.0/drivers/mfd/twl6040.c
@@ -97,12 +97,16 @@
 };
 
 
-static bool twl6040_has_vibra(struct device_node *node)
+static bool twl6040_has_vibra(struct device_node *parent)
 {
-#ifdef CONFIG_OF
-	if (of_find_node_by_name(node, "vibra"))
+	struct device_node *node;
+
+	node = of_get_child_by_name(parent, "vibra");
+	if (node) {
+		of_node_put(node);
 		return true;
-#endif
+	}
+
 	return false;
 }
 
@@ -312,8 +316,19 @@
 			}
 		}
 
+		/*
+		 * Register access can produce errors after power-up unless we
+		 * wait at least 8ms based on measurements on duovero.
+		 */
+		usleep_range(10000, 12000);
+
 		/* Sync with the HW */
-		regcache_sync(twl6040->regmap);
+		ret = regcache_sync(twl6040->regmap);
+		if (ret) {
+			dev_err(twl6040->dev, "Failed to sync with the HW: %i\n",
+				ret);
+			goto out;
+		}
 
 		/* Default PLL configuration after power up */
 		twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
--- linux-4.4.0.orig/drivers/mfd/wm5110-tables.c
+++ linux-4.4.0/drivers/mfd/wm5110-tables.c
@@ -1622,6 +1622,7 @@
 	{ 0x00000ECD, 0x0000 },    /* R3789  - HPLPF4_2 */
 	{ 0x00000EE0, 0x0000 },    /* R3808  - ASRC_ENABLE */
 	{ 0x00000EE2, 0x0000 },    /* R3810  - ASRC_RATE1 */
+	{ 0x00000EE3, 0x4000 },    /* R3811  - ASRC_RATE2 */
 	{ 0x00000EF0, 0x0000 },    /* R3824  - ISRC 1 CTRL 1 */
 	{ 0x00000EF1, 0x0000 },    /* R3825  - ISRC 1 CTRL 2 */
 	{ 0x00000EF2, 0x0000 },    /* R3826  - ISRC 1 CTRL 3 */
@@ -2877,6 +2878,7 @@
 	case ARIZONA_ASRC_ENABLE:
 	case ARIZONA_ASRC_STATUS:
 	case ARIZONA_ASRC_RATE1:
+	case ARIZONA_ASRC_RATE2:
 	case ARIZONA_ISRC_1_CTRL_1:
 	case ARIZONA_ISRC_1_CTRL_2:
 	case ARIZONA_ISRC_1_CTRL_3:
--- linux-4.4.0.orig/drivers/mfd/wm831x-auxadc.c
+++ linux-4.4.0/drivers/mfd/wm831x-auxadc.c
@@ -98,11 +98,10 @@
 	wait_for_completion_timeout(&req->done, msecs_to_jiffies(500));
 
 	mutex_lock(&wm831x->auxadc_lock);
-
-	list_del(&req->list);
 	ret = req->val;
 
 out:
+	list_del(&req->list);
 	mutex_unlock(&wm831x->auxadc_lock);
 
 	kfree(req);
--- linux-4.4.0.orig/drivers/mfd/wm8994-core.c
+++ linux-4.4.0/drivers/mfd/wm8994-core.c
@@ -690,3 +690,4 @@
 MODULE_DESCRIPTION("Core support for the WM8994 audio CODEC");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_SOFTDEP("pre: wm8994_regulator");
--- linux-4.4.0.orig/drivers/misc/Kconfig
+++ linux-4.4.0/drivers/misc/Kconfig
@@ -439,7 +439,7 @@
 	  still useful.
 
 config BMP085
-	bool
+	tristate
 	depends on SYSFS
 
 config BMP085_I2C
--- linux-4.4.0.orig/drivers/misc/ad525x_dpot.c
+++ linux-4.4.0/drivers/misc/ad525x_dpot.c
@@ -216,7 +216,7 @@
 			 */
 			value = swab16(value);
 
-			if (dpot->uid == DPOT_UID(AD5271_ID))
+			if (dpot->uid == DPOT_UID(AD5274_ID))
 				value = value >> 2;
 		return value;
 	default:
--- linux-4.4.0.orig/drivers/misc/altera-stapl/altera.c
+++ linux-4.4.0/drivers/misc/altera-stapl/altera.c
@@ -2126,8 +2126,8 @@
 	return status;
 }
 
-static int altera_get_note(u8 *p, s32 program_size,
-			s32 *offset, char *key, char *value, int length)
+static int altera_get_note(u8 *p, s32 program_size, s32 *offset,
+			   char *key, char *value, int keylen, int vallen)
 /*
  * Gets key and value of NOTE fields in the JBC file.
  * Can be called in two modes:  if offset pointer is NULL,
@@ -2176,8 +2176,7 @@
 			key_ptr = &p[note_strings +
 					get_unaligned_be32(
 					&p[note_table + (8 * i)])];
-			if ((strncasecmp(key, key_ptr, strlen(key_ptr)) == 0) &&
-						(key != NULL)) {
+			if (key && !strncasecmp(key, key_ptr, strlen(key_ptr))) {
 				status = 0;
 
 				value_ptr = &p[note_strings +
@@ -2185,7 +2184,7 @@
 						&p[note_table + (8 * i) + 4])];
 
 				if (value != NULL)
-					strlcpy(value, value_ptr, length);
+					strlcpy(value, value_ptr, vallen);
 
 			}
 		}
@@ -2204,13 +2203,13 @@
 				strlcpy(key, &p[note_strings +
 						get_unaligned_be32(
 						&p[note_table + (8 * i)])],
-					length);
+					keylen);
 
 			if (value != NULL)
 				strlcpy(value, &p[note_strings +
 						get_unaligned_be32(
 						&p[note_table + (8 * i) + 4])],
-					length);
+					vallen);
 
 			*offset = i + 1;
 		}
@@ -2464,7 +2463,7 @@
 			__func__, (format_version == 2) ? "Jam STAPL" :
 						"pre-standardized Jam 1.1");
 		while (altera_get_note((u8 *)fw->data, fw->size,
-					&offset, key, value, 256) == 0)
+					&offset, key, value, 32, 256) == 0)
 			printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n",
 					__func__, key, value);
 	}
--- linux-4.4.0.orig/drivers/misc/atmel-ssc.c
+++ linux-4.4.0/drivers/misc/atmel-ssc.c
@@ -13,7 +13,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/atmel-ssc.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -21,7 +21,7 @@
 #include <linux/of.h>
 
 /* Serialize access to ssc_list and user count */
-static DEFINE_SPINLOCK(user_lock);
+static DEFINE_MUTEX(user_lock);
 static LIST_HEAD(ssc_list);
 
 struct ssc_device *ssc_request(unsigned int ssc_num)
@@ -29,7 +29,7 @@
 	int ssc_valid = 0;
 	struct ssc_device *ssc;
 
-	spin_lock(&user_lock);
+	mutex_lock(&user_lock);
 	list_for_each_entry(ssc, &ssc_list, list) {
 		if (ssc->pdev->dev.of_node) {
 			if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc")
@@ -44,18 +44,18 @@
 	}
 
 	if (!ssc_valid) {
-		spin_unlock(&user_lock);
+		mutex_unlock(&user_lock);
 		pr_err("ssc: ssc%d platform device is missing\n", ssc_num);
 		return ERR_PTR(-ENODEV);
 	}
 
 	if (ssc->user) {
-		spin_unlock(&user_lock);
+		mutex_unlock(&user_lock);
 		dev_dbg(&ssc->pdev->dev, "module busy\n");
 		return ERR_PTR(-EBUSY);
 	}
 	ssc->user++;
-	spin_unlock(&user_lock);
+	mutex_unlock(&user_lock);
 
 	clk_prepare(ssc->clk);
 
@@ -67,14 +67,14 @@
 {
 	bool disable_clk = true;
 
-	spin_lock(&user_lock);
+	mutex_lock(&user_lock);
 	if (ssc->user)
 		ssc->user--;
 	else {
 		disable_clk = false;
 		dev_dbg(&ssc->pdev->dev, "device already free\n");
 	}
-	spin_unlock(&user_lock);
+	mutex_unlock(&user_lock);
 
 	if (disable_clk)
 		clk_unprepare(ssc->clk);
@@ -129,7 +129,7 @@
 MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids);
 #endif
 
-static inline const struct atmel_ssc_platform_data * __init
+static inline const struct atmel_ssc_platform_data *
 	atmel_ssc_get_driver_data(struct platform_device *pdev)
 {
 	if (pdev->dev.of_node) {
@@ -194,9 +194,9 @@
 		return -ENXIO;
 	}
 
-	spin_lock(&user_lock);
+	mutex_lock(&user_lock);
 	list_add_tail(&ssc->list, &ssc_list);
-	spin_unlock(&user_lock);
+	mutex_unlock(&user_lock);
 
 	platform_set_drvdata(pdev, ssc);
 
@@ -210,9 +210,9 @@
 {
 	struct ssc_device *ssc = platform_get_drvdata(pdev);
 
-	spin_lock(&user_lock);
+	mutex_lock(&user_lock);
 	list_del(&ssc->list);
-	spin_unlock(&user_lock);
+	mutex_unlock(&user_lock);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/misc/c2port/c2port-duramar2150.c
+++ linux-4.4.0/drivers/misc/c2port/c2port-duramar2150.c
@@ -129,8 +129,8 @@
 
 	duramar2150_c2port_dev = c2port_device_register("uc",
 					&duramar2150_c2port_ops, NULL);
-	if (!duramar2150_c2port_dev) {
-		ret = -ENODEV;
+	if (IS_ERR(duramar2150_c2port_dev)) {
+		ret = PTR_ERR(duramar2150_c2port_dev);
 		goto free_region;
 	}
 
--- linux-4.4.0.orig/drivers/misc/cxl/Makefile
+++ linux-4.4.0/drivers/misc/cxl/Makefile
@@ -1,8 +1,10 @@
-ccflags-y := -Werror -Wno-unused-const-variable
+ccflags-y			:= $(call cc-disable-warning, unused-const-variable)
+ccflags-$(CONFIG_PPC_WERROR)	+= -Werror
 
 cxl-y				+= main.o file.o irq.o fault.o native.o
 cxl-y				+= context.o sysfs.o debugfs.o pci.o trace.o
 cxl-y				+= vphb.o api.o
+cxl-$(CONFIG_PPC_PSERIES)	+= flash.o guest.o of.o hcalls.o
 obj-$(CONFIG_CXL)		+= cxl.o
 obj-$(CONFIG_CXL_BASE)		+= base.o
 
--- linux-4.4.0.orig/drivers/misc/cxl/api.c
+++ linux-4.4.0/drivers/misc/cxl/api.c
@@ -9,23 +9,123 @@
 
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/anon_inodes.h>
 #include <linux/file.h>
 #include <misc/cxl.h>
-#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/mount.h>
 
 #include "cxl.h"
 
+/*
+ * Since we want to track memory mappings to be able to force-unmap
+ * when the AFU is no longer reachable, we need an inode. For devices
+ * opened through the cxl user API, this is not a problem, but a
+ * userland process can also get a cxl fd through the cxl_get_fd()
+ * API, which is used by the cxlflash driver.
+ *
+ * Therefore we implement our own simple pseudo-filesystem and inode
+ * allocator. We don't use the anonymous inode, as we need the
+ * meta-data associated with it (address_space) and it is shared by
+ * other drivers/processes, so it could lead to cxl unmapping VMAs
+ * from random processes.
+ */
+
+#define CXL_PSEUDO_FS_MAGIC	0x1697697f
+
+static int cxl_fs_cnt;
+static struct vfsmount *cxl_vfs_mount;
+
+static const struct dentry_operations cxl_fs_dops = {
+	.d_dname	= simple_dname,
+};
+
+static struct dentry *cxl_fs_mount(struct file_system_type *fs_type, int flags,
+				const char *dev_name, void *data)
+{
+	return mount_pseudo(fs_type, "cxl:", NULL, &cxl_fs_dops,
+			CXL_PSEUDO_FS_MAGIC);
+}
+
+static struct file_system_type cxl_fs_type = {
+	.name		= "cxl",
+	.owner		= THIS_MODULE,
+	.mount		= cxl_fs_mount,
+	.kill_sb	= kill_anon_super,
+};
+
+
+void cxl_release_mapping(struct cxl_context *ctx)
+{
+	if (ctx->kernelapi && ctx->mapping)
+		simple_release_fs(&cxl_vfs_mount, &cxl_fs_cnt);
+}
+
+static struct file *cxl_getfile(const char *name,
+				const struct file_operations *fops,
+				void *priv, int flags)
+{
+	struct qstr this;
+	struct path path;
+	struct file *file;
+	struct inode *inode = NULL;
+	int rc;
+
+	/* strongly inspired by anon_inode_getfile() */
+
+	if (fops->owner && !try_module_get(fops->owner))
+		return ERR_PTR(-ENOENT);
+
+	rc = simple_pin_fs(&cxl_fs_type, &cxl_vfs_mount, &cxl_fs_cnt);
+	if (rc < 0) {
+		pr_err("Cannot mount cxl pseudo filesystem: %d\n", rc);
+		file = ERR_PTR(rc);
+		goto err_module;
+	}
+
+	inode = alloc_anon_inode(cxl_vfs_mount->mnt_sb);
+	if (IS_ERR(inode)) {
+		file = ERR_CAST(inode);
+		goto err_fs;
+	}
+
+	file = ERR_PTR(-ENOMEM);
+	this.name = name;
+	this.len = strlen(name);
+	this.hash = 0;
+	path.dentry = d_alloc_pseudo(cxl_vfs_mount->mnt_sb, &this);
+	if (!path.dentry)
+		goto err_inode;
+
+	path.mnt = mntget(cxl_vfs_mount);
+	d_instantiate(path.dentry, inode);
+
+	file = alloc_file(&path, OPEN_FMODE(flags), fops);
+	if (IS_ERR(file))
+		goto err_dput;
+	file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
+	file->private_data = priv;
+
+	return file;
+
+err_dput:
+	path_put(&path);
+err_inode:
+	iput(inode);
+err_fs:
+	simple_release_fs(&cxl_vfs_mount, &cxl_fs_cnt);
+err_module:
+	module_put(fops->owner);
+	return file;
+}
+
 struct cxl_context *cxl_dev_context_init(struct pci_dev *dev)
 {
-	struct address_space *mapping;
 	struct cxl_afu *afu;
 	struct cxl_context  *ctx;
 	int rc;
 
 	afu = cxl_pci_to_afu(dev);
 
-	get_device(&afu->dev);
 	ctx = cxl_context_alloc();
 	if (IS_ERR(ctx)) {
 		rc = PTR_ERR(ctx);
@@ -34,34 +134,16 @@
 
 	ctx->kernelapi = true;
 
-	/*
-	 * Make our own address space since we won't have one from the
-	 * filesystem like the user api has, and even if we do associate a file
-	 * with this context we don't want to use the global anonymous inode's
-	 * address space as that can invalidate unrelated users:
-	 */
-	mapping = kmalloc(sizeof(struct address_space), GFP_KERNEL);
-	if (!mapping) {
-		rc = -ENOMEM;
-		goto err_ctx;
-	}
-	address_space_init_once(mapping);
-
 	/* Make it a slave context.  We can promote it later? */
-	rc = cxl_context_init(ctx, afu, false, mapping);
+	rc = cxl_context_init(ctx, afu, false);
 	if (rc)
-		goto err_mapping;
-
-	cxl_assign_psn_space(ctx);
+		goto err_ctx;
 
 	return ctx;
 
-err_mapping:
-	kfree(mapping);
 err_ctx:
 	kfree(ctx);
 err_dev:
-	put_device(&afu->dev);
 	return ERR_PTR(rc);
 }
 EXPORT_SYMBOL_GPL(cxl_dev_context_init);
@@ -80,43 +162,23 @@
 
 	return afu->adapter->dev.parent;
 }
-EXPORT_SYMBOL_GPL(cxl_get_phys_dev);
 
 int cxl_release_context(struct cxl_context *ctx)
 {
 	if (ctx->status >= STARTED)
 		return -EBUSY;
 
-	put_device(&ctx->afu->dev);
-
 	cxl_context_free(ctx);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(cxl_release_context);
 
-int cxl_allocate_afu_irqs(struct cxl_context *ctx, int num)
-{
-	if (num == 0)
-		num = ctx->afu->pp_irqs;
-	return afu_allocate_irqs(ctx, num);
-}
-EXPORT_SYMBOL_GPL(cxl_allocate_afu_irqs);
-
-void cxl_free_afu_irqs(struct cxl_context *ctx)
-{
-	afu_irq_name_free(ctx);
-	cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
-}
-EXPORT_SYMBOL_GPL(cxl_free_afu_irqs);
-
 static irq_hw_number_t cxl_find_afu_irq(struct cxl_context *ctx, int num)
 {
 	__u16 range;
 	int r;
 
-	WARN_ON(num == 0);
-
 	for (r = 0; r < CXL_IRQ_RANGES; r++) {
 		range = ctx->irqs.range[r];
 		if (num < range) {
@@ -127,6 +189,44 @@
 	return 0;
 }
 
+int cxl_allocate_afu_irqs(struct cxl_context *ctx, int num)
+{
+	int res;
+	irq_hw_number_t hwirq;
+
+	if (num == 0)
+		num = ctx->afu->pp_irqs;
+	res = afu_allocate_irqs(ctx, num);
+	if (!res && !cpu_has_feature(CPU_FTR_HVMODE)) {
+		/* In a guest, the PSL interrupt is not multiplexed. It was
+		 * allocated above, and we need to set its handler
+		 */
+		hwirq = cxl_find_afu_irq(ctx, 0);
+		if (hwirq)
+			cxl_map_irq(ctx->afu->adapter, hwirq, cxl_ops->psl_interrupt, ctx, "psl");
+	}
+	return res;
+}
+EXPORT_SYMBOL_GPL(cxl_allocate_afu_irqs);
+
+void cxl_free_afu_irqs(struct cxl_context *ctx)
+{
+	irq_hw_number_t hwirq;
+	unsigned int virq;
+
+	if (!cpu_has_feature(CPU_FTR_HVMODE)) {
+		hwirq = cxl_find_afu_irq(ctx, 0);
+		if (hwirq) {
+			virq = irq_find_mapping(NULL, hwirq);
+			if (virq)
+				cxl_unmap_irq(virq, ctx);
+		}
+	}
+	afu_irq_name_free(ctx);
+	cxl_ops->release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
+}
+EXPORT_SYMBOL_GPL(cxl_free_afu_irqs);
+
 int cxl_map_afu_irq(struct cxl_context *ctx, int num,
 		    irq_handler_t handler, void *cookie, char *name)
 {
@@ -176,13 +276,17 @@
 
 	if (task) {
 		ctx->pid = get_task_pid(task, PIDTYPE_PID);
-		get_pid(ctx->pid);
+		ctx->glpid = get_task_pid(task->group_leader, PIDTYPE_PID);
 		kernel = false;
 	}
 
+	/*
+	 * Increment driver use count. Enables global TLBIs for hash
+	 * and callbacks to handle the segment table
+	 */
 	cxl_ctx_get();
 
-	if ((rc = cxl_attach_process(ctx, kernel, wed , 0))) {
+	if ((rc = cxl_ops->attach_process(ctx, kernel, wed, 0))) {
 		put_pid(ctx->pid);
 		cxl_ctx_put();
 		goto out;
@@ -197,7 +301,7 @@
 
 int cxl_process_element(struct cxl_context *ctx)
 {
-	return ctx->pe;
+	return ctx->external_pe;
 }
 EXPORT_SYMBOL_GPL(cxl_process_element);
 
@@ -211,7 +315,6 @@
 void cxl_set_master(struct cxl_context *ctx)
 {
 	ctx->master = true;
-	cxl_assign_psn_space(ctx);
 }
 EXPORT_SYMBOL_GPL(cxl_set_master);
 
@@ -256,6 +359,11 @@
 {
 	struct file *file;
 	int rc, flags, fdtmp;
+	char *name = NULL;
+
+	/* only allow one per context */
+	if (ctx->mapping)
+		return ERR_PTR(-EEXIST);
 
 	flags = O_RDWR | O_CLOEXEC;
 
@@ -279,12 +387,13 @@
 	} else /* use default ops */
 		fops = (struct file_operations *)&afu_fops;
 
-	file = anon_inode_getfile("cxl", fops, ctx, flags);
+	name = kasprintf(GFP_KERNEL, "cxl:%d", ctx->pe);
+	file = cxl_getfile(name, fops, ctx, flags);
+	kfree(name);
 	if (IS_ERR(file))
 		goto err_fd;
 
-	file->f_mapping = ctx->mapping;
-
+	cxl_context_set_mapping(ctx, file->f_mapping);
 	*fd = fdtmp;
 	return file;
 
@@ -329,15 +438,11 @@
 
 void __iomem *cxl_psa_map(struct cxl_context *ctx)
 {
-	struct cxl_afu *afu = ctx->afu;
-	int rc;
-
-	rc = cxl_afu_check_and_enable(afu);
-	if (rc)
+	if (ctx->status != STARTED)
 		return NULL;
 
 	pr_devel("%s: psn_phys%llx size:%llx\n",
-		 __func__, afu->psn_phys, afu->adapter->ps_size);
+		__func__, ctx->psn_phys, ctx->psn_size);
 	return ioremap(ctx->psn_phys, ctx->psn_size);
 }
 EXPORT_SYMBOL_GPL(cxl_psa_map);
@@ -353,11 +458,11 @@
 	struct cxl_afu *afu = ctx->afu;
 	int rc;
 
-	rc = __cxl_afu_reset(afu);
+	rc = cxl_ops->afu_reset(afu);
 	if (rc)
 		return rc;
 
-	return cxl_afu_check_and_enable(afu);
+	return cxl_ops->afu_check_and_enable(afu);
 }
 EXPORT_SYMBOL_GPL(cxl_afu_reset);
 
@@ -367,3 +472,11 @@
 	afu->adapter->perst_same_image = perst_reloads_same_image;
 }
 EXPORT_SYMBOL_GPL(cxl_perst_reloads_same_image);
+
+ssize_t cxl_read_adapter_vpd(struct pci_dev *dev, void *buf, size_t count)
+{
+	struct cxl_afu *afu = cxl_pci_to_afu(dev);
+
+	return cxl_ops->read_adapter_vpd(afu->adapter, buf, count);
+}
+EXPORT_SYMBOL_GPL(cxl_read_adapter_vpd);
--- linux-4.4.0.orig/drivers/misc/cxl/base.c
+++ linux-4.4.0/drivers/misc/cxl/base.c
@@ -11,6 +11,7 @@
 #include <linux/rcupdate.h>
 #include <asm/errno.h>
 #include <misc/cxl-base.h>
+#include <linux/of_platform.h>
 #include "cxl.h"
 
 /* protected by rcu */
@@ -84,3 +85,34 @@
 	synchronize_rcu();
 }
 EXPORT_SYMBOL_GPL(unregister_cxl_calls);
+
+int cxl_update_properties(struct device_node *dn,
+			  struct property *new_prop)
+{
+	return of_update_property(dn, new_prop);
+}
+EXPORT_SYMBOL_GPL(cxl_update_properties);
+
+static int __init cxl_base_init(void)
+{
+	struct device_node *np = NULL;
+	struct platform_device *dev;
+	int count = 0;
+
+	/*
+	 * Scan for compatible devices in guest only
+	 */
+	if (cpu_has_feature(CPU_FTR_HVMODE))
+		return 0;
+
+	while ((np = of_find_compatible_node(np, NULL,
+				     "ibm,coherent-platform-facility"))) {
+		dev = of_platform_device_create(np, NULL, NULL);
+		if (dev)
+			count++;
+	}
+	pr_devel("Found %d cxl device(s)\n", count);
+	return 0;
+}
+
+module_init(cxl_base_init);
--- linux-4.4.0.orig/drivers/misc/cxl/context.c
+++ linux-4.4.0/drivers/misc/cxl/context.c
@@ -34,17 +34,16 @@
 /*
  * Initialises a CXL context.
  */
-int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master,
-		     struct address_space *mapping)
+int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master)
 {
 	int i;
 
 	spin_lock_init(&ctx->sste_lock);
 	ctx->afu = afu;
 	ctx->master = master;
-	ctx->pid = NULL; /* Set in start work ioctl */
+	ctx->pid = ctx->glpid = NULL; /* Set in start work ioctl */
 	mutex_init(&ctx->mapping_lock);
-	ctx->mapping = mapping;
+	ctx->mapping = NULL;
 
 	/*
 	 * Allocate the segment table before we put it in the IDR so that we
@@ -95,11 +94,30 @@
 		return i;
 
 	ctx->pe = i;
-	ctx->elem = &ctx->afu->spa[i];
+	if (cpu_has_feature(CPU_FTR_HVMODE)) {
+		ctx->elem = &ctx->afu->native->spa[i];
+		ctx->external_pe = ctx->pe;
+	} else {
+		ctx->external_pe = -1; /* assigned when attaching */
+	}
 	ctx->pe_inserted = false;
+
+	/*
+	 * take a ref on the afu so that it stays alive at-least till
+	 * this context is reclaimed inside reclaim_ctx.
+	 */
+	cxl_afu_get(afu);
 	return 0;
 }
 
+void cxl_context_set_mapping(struct cxl_context *ctx,
+			struct address_space *mapping)
+{
+	mutex_lock(&ctx->mapping_lock);
+	ctx->mapping = mapping;
+	mutex_unlock(&ctx->mapping_lock);
+}
+
 static int cxl_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	struct cxl_context *ctx = vma->vm_file->private_data;
@@ -208,10 +226,21 @@
 	/* Only warn if we detached while the link was OK.
 	 * If detach fails when hw is down, we don't care.
 	 */
-	WARN_ON(cxl_detach_process(ctx) &&
-		cxl_adapter_link_ok(ctx->afu->adapter));
+	WARN_ON(cxl_ops->detach_process(ctx) &&
+		cxl_ops->link_ok(ctx->afu->adapter, ctx->afu));
 	flush_work(&ctx->fault_work); /* Only needed for dedicated process */
+
+	/*
+	 * Wait until no further interrupts are presented by the PSL
+	 * for this context.
+	 */
+	if (cxl_ops->irq_wait)
+		cxl_ops->irq_wait(ctx);
+
+	/* release the reference to the group leader and mm handling pid */
 	put_pid(ctx->pid);
+	put_pid(ctx->glpid);
+
 	cxl_ctx_put();
 	return 0;
 }
@@ -272,17 +301,20 @@
 	if (ctx->ff_page)
 		__free_page(ctx->ff_page);
 	ctx->sstp = NULL;
-	if (ctx->kernelapi)
-		kfree(ctx->mapping);
 
 	if (ctx->irq_bitmap)
 		kfree(ctx->irq_bitmap);
 
+	/* Drop ref to the afu device taken during cxl_context_init */
+	cxl_afu_put(ctx->afu);
+
 	kfree(ctx);
 }
 
 void cxl_context_free(struct cxl_context *ctx)
 {
+	if (ctx->kernelapi && ctx->mapping)
+		cxl_release_mapping(ctx);
 	mutex_lock(&ctx->afu->contexts_lock);
 	idr_remove(&ctx->afu->contexts_idr, ctx->pe);
 	mutex_unlock(&ctx->afu->contexts_lock);
--- linux-4.4.0.orig/drivers/misc/cxl/cxl.h
+++ linux-4.4.0/drivers/misc/cxl/cxl.h
@@ -155,7 +155,10 @@
 #define CXL_PSL_SPAP_V    0x0000000000000001ULL
 
 /****** CXL_PSL_Control ****************************************************/
-#define CXL_PSL_Control_tb 0x0000000000000001ULL
+#define CXL_PSL_Control_tb              (0x1ull << (63-63))
+#define CXL_PSL_Control_Fr              (0x1ull << (63-31))
+#define CXL_PSL_Control_Fs_MASK         (0x3ull << (63-29))
+#define CXL_PSL_Control_Fs_Complete     (0x3ull << (63-29))
 
 /****** CXL_PSL_DLCNTL *****************************************************/
 #define CXL_PSL_DLCNTL_D (0x1ull << (63-28))
@@ -274,6 +277,7 @@
 #define CXL_PSL_DSISR_An_PE (1ull << (63-4))  /* PSL Error (implementation specific) */
 #define CXL_PSL_DSISR_An_AE (1ull << (63-5))  /* AFU Error */
 #define CXL_PSL_DSISR_An_OC (1ull << (63-6))  /* OS Context Warning */
+#define CXL_PSL_DSISR_PENDING (CXL_PSL_DSISR_TRANS | CXL_PSL_DSISR_An_PE | CXL_PSL_DSISR_An_AE | CXL_PSL_DSISR_An_OC)
 /* NOTE: Bits 32:63 are undefined if DSISR[DS] = 1 */
 #define CXL_PSL_DSISR_An_M  DSISR_NOHPTE      /* PTE not found */
 #define CXL_PSL_DSISR_An_P  DSISR_PROTFAULT   /* Storage protection violation */
@@ -324,6 +328,10 @@
 #define CXL_MODE_TIME_SLICED 0x4
 #define CXL_SUPPORTED_MODES (CXL_MODE_DEDICATED | CXL_MODE_DIRECTED)
 
+#define CXL_DEV_MINORS 13   /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
+#define CXL_CARD_MINOR(adapter) (adapter->adapter_num * CXL_DEV_MINORS)
+#define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS)
+
 enum cxl_context_status {
 	CLOSED,
 	OPENED,
@@ -336,6 +344,12 @@
 	CXL_PREFAULT_ALL,
 };
 
+enum cxl_attrs {
+	CXL_ADAPTER_ATTRS,
+	CXL_AFU_MASTER_ATTRS,
+	CXL_AFU_ATTRS,
+};
+
 struct cxl_sste {
 	__be64 esid_data;
 	__be64 vsid_data;
@@ -344,18 +358,46 @@
 #define to_cxl_adapter(d) container_of(d, struct cxl, dev)
 #define to_cxl_afu(d) container_of(d, struct cxl_afu, dev)
 
-struct cxl_afu {
+struct cxl_afu_native {
+	void __iomem *p1n_mmio;
+	void __iomem *afu_desc_mmio;
 	irq_hw_number_t psl_hwirq;
+	unsigned int psl_virq;
+	struct mutex spa_mutex;
+	/*
+	 * Only the first part of the SPA is used for the process element
+	 * linked list. The only other part that software needs to worry about
+	 * is sw_command_status, which we store a separate pointer to.
+	 * Everything else in the SPA is only used by hardware
+	 */
+	struct cxl_process_element *spa;
+	__be64 *sw_command_status;
+	unsigned int spa_size;
+	int spa_order;
+	int spa_max_procs;
+	u64 pp_offset;
+};
+
+struct cxl_afu_guest {
+	u64 handle;
+	phys_addr_t p2n_phys;
+	u64 p2n_size;
+	int max_ints;
+	struct mutex recovery_lock;
+	int previous_state;
+};
+
+struct cxl_afu {
+	struct cxl_afu_native *native;
+	struct cxl_afu_guest *guest;
 	irq_hw_number_t serr_hwirq;
-	char *err_irq_name;
-	char *psl_irq_name;
 	unsigned int serr_virq;
-	void __iomem *p1n_mmio;
+	char *psl_irq_name;
+	char *err_irq_name;
 	void __iomem *p2n_mmio;
 	phys_addr_t psn_phys;
-	u64 pp_offset;
 	u64 pp_size;
-	void __iomem *afu_desc_mmio;
+
 	struct cxl *adapter;
 	struct device dev;
 	struct cdev afu_cdev_s, afu_cdev_m, afu_cdev_d;
@@ -363,26 +405,12 @@
 	struct idr contexts_idr;
 	struct dentry *debugfs;
 	struct mutex contexts_lock;
-	struct mutex spa_mutex;
 	spinlock_t afu_cntl_lock;
 
 	/* AFU error buffer fields and bin attribute for sysfs */
 	u64 eb_len, eb_offset;
 	struct bin_attribute attr_eb;
 
-	/*
-	 * Only the first part of the SPA is used for the process element
-	 * linked list. The only other part that software needs to worry about
-	 * is sw_command_status, which we store a separate pointer to.
-	 * Everything else in the SPA is only used by hardware
-	 */
-	struct cxl_process_element *spa;
-	__be64 *sw_command_status;
-	unsigned int spa_size;
-	int spa_order;
-	int spa_max_procs;
-	unsigned int psl_virq;
-
 	/* pointer to the vphb */
 	struct pci_controller *phb;
 
@@ -403,12 +431,30 @@
 	bool enabled;
 };
 
+/* AFU refcount management */
+static inline struct cxl_afu *cxl_afu_get(struct cxl_afu *afu)
+{
+
+	return (get_device(&afu->dev) == NULL) ? NULL : afu;
+}
+
+static inline void  cxl_afu_put(struct cxl_afu *afu)
+{
+	put_device(&afu->dev);
+}
+
 
 struct cxl_irq_name {
 	struct list_head list;
 	char *name;
 };
 
+struct irq_avail {
+	irq_hw_number_t offset;
+	irq_hw_number_t range;
+	unsigned long   *bitmap;
+};
+
 /*
  * This is a cxl context.  If the PSL is in dedicated mode, there will be one
  * of these per AFU.  If in AFU directed there can be lots of these.
@@ -433,6 +479,9 @@
 	unsigned int sst_size, sst_lru;
 
 	wait_queue_head_t wq;
+	/* pid of the group leader associated with the pid */
+	struct pid *glpid;
+	/* use mm context associated with this pid for ds faults */
 	struct pid *pid;
 	spinlock_t lock; /* Protects pending_irq_mask, pending_fault and fault_addr */
 	/* Only used in PR mode */
@@ -461,7 +510,19 @@
 
 	struct cxl_process_element *elem;
 
-	int pe; /* process element handle */
+	/*
+	 * pe is the process element handle, assigned by this driver when the
+	 * context is initialized.
+	 *
+	 * external_pe is the PE shown outside of cxl.
+	 * On bare-metal, pe=external_pe, because we decide what the handle is.
+	 * In a guest, we only find out about the pe used by pHyp when the
+	 * context is attached, and that's the value we want to report outside
+	 * of cxl.
+	 */
+	int pe;
+	int external_pe;
+
 	u32 irq_count;
 	bool pe_inserted;
 	bool master;
@@ -473,11 +534,34 @@
 	struct rcu_head rcu;
 };
 
-struct cxl {
+struct cxl_native {
+	u64 afu_desc_off;
+	u64 afu_desc_size;
 	void __iomem *p1_mmio;
 	void __iomem *p2_mmio;
 	irq_hw_number_t err_hwirq;
 	unsigned int err_virq;
+	u64 ps_off;
+};
+
+struct cxl_guest {
+	struct platform_device *pdev;
+	int irq_nranges;
+	struct cdev cdev;
+	irq_hw_number_t irq_base_offset;
+	struct irq_avail *irq_avail;
+	spinlock_t irq_alloc_lock;
+	u64 handle;
+	char *status;
+	u16 vendor;
+	u16 device;
+	u16 subsystem_vendor;
+	u16 subsystem;
+};
+
+struct cxl {
+	struct cxl_native *native;
+	struct cxl_guest *guest;
 	spinlock_t afu_list_lock;
 	struct cxl_afu *afu[CXL_MAX_SLICES];
 	struct device dev;
@@ -488,9 +572,6 @@
 	struct bin_attribute cxl_attr;
 	int adapter_num;
 	int user_irqs;
-	u64 afu_desc_off;
-	u64 afu_desc_size;
-	u64 ps_off;
 	u64 ps_size;
 	u16 psl_rev;
 	u16 base_image;
@@ -502,15 +583,18 @@
 	bool perst_loads_image;
 	bool perst_select_user;
 	bool perst_same_image;
+	bool psl_timebase_synced;
 };
 
-int cxl_alloc_one_irq(struct cxl *adapter);
-void cxl_release_one_irq(struct cxl *adapter, int hwirq);
-int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num);
-void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter);
-int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq);
+int cxl_pci_alloc_one_irq(struct cxl *adapter);
+void cxl_pci_release_one_irq(struct cxl *adapter, int hwirq);
+int cxl_pci_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num);
+void cxl_pci_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter);
+int cxl_pci_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq);
 int cxl_update_image_control(struct cxl *adapter);
-int cxl_reset(struct cxl *adapter);
+int cxl_pci_reset(struct cxl *adapter);
+void cxl_pci_release_afu(struct device *dev);
+ssize_t cxl_pci_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len);
 
 /* common == phyp + powernv */
 struct cxl_process_element_common {
@@ -540,29 +624,32 @@
 	__be32 software_state;
 } __packed;
 
-static inline bool cxl_adapter_link_ok(struct cxl *cxl)
+static inline bool cxl_adapter_link_ok(struct cxl *cxl, struct cxl_afu *afu)
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(cxl->dev.parent);
-	return !pci_channel_offline(pdev);
+	if (cpu_has_feature(CPU_FTR_HVMODE)) {
+		pdev = to_pci_dev(cxl->dev.parent);
+		return !pci_channel_offline(pdev);
+	}
+	return true;
 }
 
 static inline void __iomem *_cxl_p1_addr(struct cxl *cxl, cxl_p1_reg_t reg)
 {
 	WARN_ON(!cpu_has_feature(CPU_FTR_HVMODE));
-	return cxl->p1_mmio + cxl_reg_off(reg);
+	return cxl->native->p1_mmio + cxl_reg_off(reg);
 }
 
 static inline void cxl_p1_write(struct cxl *cxl, cxl_p1_reg_t reg, u64 val)
 {
-	if (likely(cxl_adapter_link_ok(cxl)))
+	if (likely(cxl_adapter_link_ok(cxl, NULL)))
 		out_be64(_cxl_p1_addr(cxl, reg), val);
 }
 
 static inline u64 cxl_p1_read(struct cxl *cxl, cxl_p1_reg_t reg)
 {
-	if (likely(cxl_adapter_link_ok(cxl)))
+	if (likely(cxl_adapter_link_ok(cxl, NULL)))
 		return in_be64(_cxl_p1_addr(cxl, reg));
 	else
 		return ~0ULL;
@@ -571,18 +658,18 @@
 static inline void __iomem *_cxl_p1n_addr(struct cxl_afu *afu, cxl_p1n_reg_t reg)
 {
 	WARN_ON(!cpu_has_feature(CPU_FTR_HVMODE));
-	return afu->p1n_mmio + cxl_reg_off(reg);
+	return afu->native->p1n_mmio + cxl_reg_off(reg);
 }
 
 static inline void cxl_p1n_write(struct cxl_afu *afu, cxl_p1n_reg_t reg, u64 val)
 {
-	if (likely(cxl_adapter_link_ok(afu->adapter)))
+	if (likely(cxl_adapter_link_ok(afu->adapter, afu)))
 		out_be64(_cxl_p1n_addr(afu, reg), val);
 }
 
 static inline u64 cxl_p1n_read(struct cxl_afu *afu, cxl_p1n_reg_t reg)
 {
-	if (likely(cxl_adapter_link_ok(afu->adapter)))
+	if (likely(cxl_adapter_link_ok(afu->adapter, afu)))
 		return in_be64(_cxl_p1n_addr(afu, reg));
 	else
 		return ~0ULL;
@@ -595,39 +682,19 @@
 
 static inline void cxl_p2n_write(struct cxl_afu *afu, cxl_p2n_reg_t reg, u64 val)
 {
-	if (likely(cxl_adapter_link_ok(afu->adapter)))
+	if (likely(cxl_adapter_link_ok(afu->adapter, afu)))
 		out_be64(_cxl_p2n_addr(afu, reg), val);
 }
 
 static inline u64 cxl_p2n_read(struct cxl_afu *afu, cxl_p2n_reg_t reg)
 {
-	if (likely(cxl_adapter_link_ok(afu->adapter)))
+	if (likely(cxl_adapter_link_ok(afu->adapter, afu)))
 		return in_be64(_cxl_p2n_addr(afu, reg));
 	else
 		return ~0ULL;
 }
 
-static inline u64 cxl_afu_cr_read64(struct cxl_afu *afu, int cr, u64 off)
-{
-	if (likely(cxl_adapter_link_ok(afu->adapter)))
-		return in_le64((afu)->afu_desc_mmio + (afu)->crs_offset +
-			       ((cr) * (afu)->crs_len) + (off));
-	else
-		return ~0ULL;
-}
-
-static inline u32 cxl_afu_cr_read32(struct cxl_afu *afu, int cr, u64 off)
-{
-	if (likely(cxl_adapter_link_ok(afu->adapter)))
-		return in_le32((afu)->afu_desc_mmio + (afu)->crs_offset +
-			       ((cr) * (afu)->crs_len) + (off));
-	else
-		return 0xffffffff;
-}
-u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off);
-u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off);
-
-ssize_t cxl_afu_read_err_buffer(struct cxl_afu *afu, char *buf,
+ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf,
 				loff_t off, size_t count);
 
 
@@ -637,13 +704,14 @@
 };
 int register_cxl_calls(struct cxl_calls *calls);
 void unregister_cxl_calls(struct cxl_calls *calls);
+int cxl_update_properties(struct device_node *dn, struct property *new_prop);
 
-int cxl_alloc_adapter_nr(struct cxl *adapter);
 void cxl_remove_adapter_nr(struct cxl *adapter);
 
 int cxl_alloc_spa(struct cxl_afu *afu);
 void cxl_release_spa(struct cxl_afu *afu);
 
+dev_t cxl_get_dev(void);
 int cxl_file_init(void);
 void cxl_file_exit(void);
 int cxl_register_adapter(struct cxl *adapter);
@@ -664,21 +732,19 @@
 int cxl_sysfs_afu_m_add(struct cxl_afu *afu);
 void cxl_sysfs_afu_m_remove(struct cxl_afu *afu);
 
-int cxl_afu_activate_mode(struct cxl_afu *afu, int mode);
-int _cxl_afu_deactivate_mode(struct cxl_afu *afu, int mode);
-int cxl_afu_deactivate_mode(struct cxl_afu *afu);
+struct cxl *cxl_alloc_adapter(void);
+struct cxl_afu *cxl_alloc_afu(struct cxl *adapter, int slice);
 int cxl_afu_select_best_mode(struct cxl_afu *afu);
 
-int cxl_register_psl_irq(struct cxl_afu *afu);
-void cxl_release_psl_irq(struct cxl_afu *afu);
-int cxl_register_psl_err_irq(struct cxl *adapter);
-void cxl_release_psl_err_irq(struct cxl *adapter);
-int cxl_register_serr_irq(struct cxl_afu *afu);
-void cxl_release_serr_irq(struct cxl_afu *afu);
+int cxl_native_register_psl_irq(struct cxl_afu *afu);
+void cxl_native_release_psl_irq(struct cxl_afu *afu);
+int cxl_native_register_psl_err_irq(struct cxl *adapter);
+void cxl_native_release_psl_err_irq(struct cxl *adapter);
+int cxl_native_register_serr_irq(struct cxl_afu *afu);
+void cxl_native_release_serr_irq(struct cxl_afu *afu);
 int afu_register_irqs(struct cxl_context *ctx, u32 count);
 void afu_release_irqs(struct cxl_context *ctx, void *cookie);
 void afu_irq_name_free(struct cxl_context *ctx);
-irqreturn_t cxl_slice_irq_err(int irq, void *data);
 
 int cxl_debugfs_init(void);
 void cxl_debugfs_exit(void);
@@ -692,12 +758,14 @@
 
 struct cxl *get_cxl_adapter(int num);
 int cxl_alloc_sst(struct cxl_context *ctx);
+void cxl_dump_debug_buffer(void *addr, size_t size);
 
 void init_cxl_native(void);
 
 struct cxl_context *cxl_context_alloc(void);
-int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master,
-		     struct address_space *mapping);
+int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master);
+void cxl_context_set_mapping(struct cxl_context *ctx,
+			struct address_space *mapping);
 void cxl_context_free(struct cxl_context *ctx);
 int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma);
 unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
@@ -705,40 +773,56 @@
 void cxl_unmap_irq(unsigned int virq, void *cookie);
 int __detach_context(struct cxl_context *ctx);
 
-/* This matches the layout of the H_COLLECT_CA_INT_INFO retbuf */
+/*
+ * This must match the layout of the H_COLLECT_CA_INT_INFO retbuf defined
+ * in PAPR.
+ * A word about endianness: a pointer to this structure is passed when
+ * calling the hcall. However, it is not a block of memory filled up by
+ * the hypervisor. The return values are found in registers, and copied
+ * one by one when returning from the hcall. See the end of the call to
+ * plpar_hcall9() in hvCall.S
+ * As a consequence:
+ * - we don't need to do any endianness conversion
+ * - the pid and tid are an exception. They are 32-bit values returned in
+ *   the same 64-bit register. So we do need to worry about byte ordering.
+ */
 struct cxl_irq_info {
 	u64 dsisr;
 	u64 dar;
 	u64 dsr;
+#ifndef CONFIG_CPU_LITTLE_ENDIAN
 	u32 pid;
 	u32 tid;
+#else
+	u32 tid;
+	u32 pid;
+#endif
 	u64 afu_err;
 	u64 errstat;
-	u64 padding[3]; /* to match the expected retbuf size for plpar_hcall9 */
+	u64 proc_handle;
+	u64 padding[2]; /* to match the expected retbuf size for plpar_hcall9 */
 };
 
 void cxl_assign_psn_space(struct cxl_context *ctx);
-int cxl_attach_process(struct cxl_context *ctx, bool kernel, u64 wed,
-			    u64 amr);
-int cxl_detach_process(struct cxl_context *ctx);
-
-int cxl_get_irq(struct cxl_afu *afu, struct cxl_irq_info *info);
-int cxl_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask);
+irqreturn_t cxl_irq(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info);
+int cxl_register_one_irq(struct cxl *adapter, irq_handler_t handler,
+			void *cookie, irq_hw_number_t *dest_hwirq,
+			unsigned int *dest_virq, const char *name);
 
 int cxl_check_error(struct cxl_afu *afu);
 int cxl_afu_slbia(struct cxl_afu *afu);
 int cxl_tlb_slb_invalidate(struct cxl *adapter);
+int cxl_data_cache_flush(struct cxl *adapter);
 int cxl_afu_disable(struct cxl_afu *afu);
-int __cxl_afu_reset(struct cxl_afu *afu);
-int cxl_afu_check_and_enable(struct cxl_afu *afu);
 int cxl_psl_purge(struct cxl_afu *afu);
 
 void cxl_stop_trace(struct cxl *cxl);
 int cxl_pci_vphb_add(struct cxl_afu *afu);
-void cxl_pci_vphb_reconfigure(struct cxl_afu *afu);
 void cxl_pci_vphb_remove(struct cxl_afu *afu);
+void cxl_release_mapping(struct cxl_context *ctx);
 
 extern struct pci_driver cxl_pci_driver;
+extern struct platform_driver cxl_of_driver;
 int afu_allocate_irqs(struct cxl_context *ctx, u32 count);
 
 int afu_open(struct inode *inode, struct file *file);
@@ -749,4 +833,62 @@
 ssize_t afu_read(struct file *file, char __user *buf, size_t count, loff_t *off);
 extern const struct file_operations afu_fops;
 
+struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_device *dev);
+void cxl_guest_remove_adapter(struct cxl *adapter);
+int cxl_of_read_adapter_handle(struct cxl *adapter, struct device_node *np);
+int cxl_of_read_adapter_properties(struct cxl *adapter, struct device_node *np);
+ssize_t cxl_guest_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len);
+ssize_t cxl_guest_read_afu_vpd(struct cxl_afu *afu, void *buf, size_t len);
+int cxl_guest_init_afu(struct cxl *adapter, int slice, struct device_node *afu_np);
+void cxl_guest_remove_afu(struct cxl_afu *afu);
+int cxl_of_read_afu_handle(struct cxl_afu *afu, struct device_node *afu_np);
+int cxl_of_read_afu_properties(struct cxl_afu *afu, struct device_node *afu_np);
+int cxl_guest_add_chardev(struct cxl *adapter);
+void cxl_guest_remove_chardev(struct cxl *adapter);
+void cxl_guest_reload_module(struct cxl *adapter);
+int cxl_of_probe(struct platform_device *pdev);
+
+struct cxl_backend_ops {
+	struct module *module;
+	int (*adapter_reset)(struct cxl *adapter);
+	int (*alloc_one_irq)(struct cxl *adapter);
+	void (*release_one_irq)(struct cxl *adapter, int hwirq);
+	int (*alloc_irq_ranges)(struct cxl_irq_ranges *irqs,
+				struct cxl *adapter, unsigned int num);
+	void (*release_irq_ranges)(struct cxl_irq_ranges *irqs,
+				struct cxl *adapter);
+	int (*setup_irq)(struct cxl *adapter, unsigned int hwirq,
+			unsigned int virq);
+	irqreturn_t (*handle_psl_slice_error)(struct cxl_context *ctx,
+					u64 dsisr, u64 errstat);
+	irqreturn_t (*psl_interrupt)(int irq, void *data);
+	int (*ack_irq)(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask);
+	void (*irq_wait)(struct cxl_context *ctx);
+	int (*attach_process)(struct cxl_context *ctx, bool kernel,
+			u64 wed, u64 amr);
+	int (*detach_process)(struct cxl_context *ctx);
+	bool (*support_attributes)(const char *attr_name, enum cxl_attrs type);
+	bool (*link_ok)(struct cxl *cxl, struct cxl_afu *afu);
+	void (*release_afu)(struct device *dev);
+	ssize_t (*afu_read_err_buffer)(struct cxl_afu *afu, char *buf,
+				loff_t off, size_t count);
+	int (*afu_check_and_enable)(struct cxl_afu *afu);
+	int (*afu_activate_mode)(struct cxl_afu *afu, int mode);
+	int (*afu_deactivate_mode)(struct cxl_afu *afu, int mode);
+	int (*afu_reset)(struct cxl_afu *afu);
+	int (*afu_cr_read8)(struct cxl_afu *afu, int cr_idx, u64 offset, u8 *val);
+	int (*afu_cr_read16)(struct cxl_afu *afu, int cr_idx, u64 offset, u16 *val);
+	int (*afu_cr_read32)(struct cxl_afu *afu, int cr_idx, u64 offset, u32 *val);
+	int (*afu_cr_read64)(struct cxl_afu *afu, int cr_idx, u64 offset, u64 *val);
+	int (*afu_cr_write8)(struct cxl_afu *afu, int cr_idx, u64 offset, u8 val);
+	int (*afu_cr_write16)(struct cxl_afu *afu, int cr_idx, u64 offset, u16 val);
+	int (*afu_cr_write32)(struct cxl_afu *afu, int cr_idx, u64 offset, u32 val);
+	ssize_t (*read_adapter_vpd)(struct cxl *adapter, void *buf, size_t count);
+};
+extern const struct cxl_backend_ops cxl_native_ops;
+extern const struct cxl_backend_ops cxl_guest_ops;
+extern const struct cxl_backend_ops *cxl_ops;
+
+/* check if the given pci_dev is on the the cxl vphb bus */
+bool cxl_pci_is_vphb_device(struct pci_dev *dev);
 #endif
--- linux-4.4.0.orig/drivers/misc/cxl/debugfs.c
+++ linux-4.4.0/drivers/misc/cxl/debugfs.c
@@ -118,6 +118,10 @@
 int __init cxl_debugfs_init(void)
 {
 	struct dentry *ent;
+
+	if (!cpu_has_feature(CPU_FTR_HVMODE))
+		return 0;
+
 	ent = debugfs_create_dir("cxl", NULL);
 	if (IS_ERR(ent))
 		return PTR_ERR(ent);
--- linux-4.4.0.orig/drivers/misc/cxl/fault.c
+++ linux-4.4.0/drivers/misc/cxl/fault.c
@@ -101,7 +101,7 @@
 {
 	unsigned long flags;
 
-	cxl_ack_irq(ctx, CXL_PSL_TFC_An_AE, 0);
+	cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_AE, 0);
 
 	spin_lock_irqsave(&ctx->lock, flags);
 	ctx->pending_fault = true;
@@ -125,7 +125,7 @@
 	else {
 
 		mb(); /* Order seg table write to TFC MMIO write */
-		cxl_ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
+		cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
 	}
 
 	return IRQ_HANDLED;
@@ -152,7 +152,7 @@
 	access = _PAGE_PRESENT;
 	if (dsisr & CXL_PSL_DSISR_An_S)
 		access |= _PAGE_RW;
-	if ((!ctx->kernel) || ~(dar & (1ULL << 63)))
+	if ((!ctx->kernel) || (REGION_ID(dar) == USER_REGION_ID))
 		access |= _PAGE_USER;
 
 	if (dsisr & DSISR_NOHPTE)
@@ -163,26 +163,108 @@
 	local_irq_restore(flags);
 
 	pr_devel("Page fault successfully handled for pe: %i!\n", ctx->pe);
-	cxl_ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
+	cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
 }
 
+/*
+ * Returns the mm_struct corresponding to the context ctx via ctx->pid
+ * In case the task has exited we use the task group leader accessible
+ * via ctx->glpid to find the next task in the thread group that has a
+ * valid  mm_struct associated with it. If a task with valid mm_struct
+ * is found the ctx->pid is updated to use the task struct for subsequent
+ * translations. In case no valid mm_struct is found in the task group to
+ * service the fault a NULL is returned.
+ */
+static struct mm_struct *get_mem_context(struct cxl_context *ctx)
+{
+	struct task_struct *task = NULL;
+	struct mm_struct *mm = NULL;
+	struct pid *old_pid = ctx->pid;
+
+	if (old_pid == NULL) {
+		pr_warn("%s: Invalid context for pe=%d\n",
+			 __func__, ctx->pe);
+		return NULL;
+	}
+
+	task = get_pid_task(old_pid, PIDTYPE_PID);
+
+	/*
+	 * pid_alive may look racy but this saves us from costly
+	 * get_task_mm when the task is a zombie. In worst case
+	 * we may think a task is alive, which is about to die
+	 * but get_task_mm will return NULL.
+	 */
+	if (task != NULL && pid_alive(task))
+		mm = get_task_mm(task);
+
+	/* release the task struct that was taken earlier */
+	if (task)
+		put_task_struct(task);
+	else
+		pr_devel("%s: Context owning pid=%i for pe=%i dead\n",
+			__func__, pid_nr(old_pid), ctx->pe);
+
+	/*
+	 * If we couldn't find the mm context then use the group
+	 * leader to iterate over the task group and find a task
+	 * that gives us mm_struct.
+	 */
+	if (unlikely(mm == NULL && ctx->glpid != NULL)) {
+
+		rcu_read_lock();
+		task = pid_task(ctx->glpid, PIDTYPE_PID);
+		if (task)
+			do {
+				mm = get_task_mm(task);
+				if (mm) {
+					ctx->pid = get_task_pid(task,
+								PIDTYPE_PID);
+					break;
+				}
+				task = next_thread(task);
+			} while (task && !thread_group_leader(task));
+		rcu_read_unlock();
+
+		/* check if we switched pid */
+		if (ctx->pid != old_pid) {
+			if (mm)
+				pr_devel("%s:pe=%i switch pid %i->%i\n",
+					 __func__, ctx->pe, pid_nr(old_pid),
+					 pid_nr(ctx->pid));
+			else
+				pr_devel("%s:Cannot find mm for pid=%i\n",
+					 __func__, pid_nr(old_pid));
+
+			/* drop the reference to older pid */
+			put_pid(old_pid);
+		}
+	}
+
+	return mm;
+}
+
+
+
 void cxl_handle_fault(struct work_struct *fault_work)
 {
 	struct cxl_context *ctx =
 		container_of(fault_work, struct cxl_context, fault_work);
 	u64 dsisr = ctx->dsisr;
 	u64 dar = ctx->dar;
-	struct task_struct *task = NULL;
 	struct mm_struct *mm = NULL;
 
-	if (cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An) != dsisr ||
-	    cxl_p2n_read(ctx->afu, CXL_PSL_DAR_An) != dar ||
-	    cxl_p2n_read(ctx->afu, CXL_PSL_PEHandle_An) != ctx->pe) {
-		/* Most likely explanation is harmless - a dedicated process
-		 * has detached and these were cleared by the PSL purge, but
-		 * warn about it just in case */
-		dev_notice(&ctx->afu->dev, "cxl_handle_fault: Translation fault regs changed\n");
-		return;
+	if (cpu_has_feature(CPU_FTR_HVMODE)) {
+		if (cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An) != dsisr ||
+		    cxl_p2n_read(ctx->afu, CXL_PSL_DAR_An) != dar ||
+		    cxl_p2n_read(ctx->afu, CXL_PSL_PEHandle_An) != ctx->pe) {
+			/* Most likely explanation is harmless - a dedicated
+			 * process has detached and these were cleared by the
+			 * PSL purge, but warn about it just in case
+			 */
+			dev_notice(&ctx->afu->dev, "cxl_handle_fault: Translation fault regs changed\n");
+			return;
+		}
 	}
 
 	/* Early return if the context is being / has been detached */
@@ -195,17 +277,17 @@
 		"DSISR: %#llx DAR: %#llx\n", ctx->pe, dsisr, dar);
 
 	if (!ctx->kernel) {
-		if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
-			pr_devel("cxl_handle_fault unable to get task %i\n",
-				 pid_nr(ctx->pid));
+
+		mm = get_mem_context(ctx);
+		/* indicates all the thread in task group have exited */
+		if (mm == NULL) {
+			pr_devel("%s: unable to get mm for pe=%d pid=%i\n",
+				 __func__, ctx->pe, pid_nr(ctx->pid));
 			cxl_ack_ae(ctx);
 			return;
-		}
-		if (!(mm = get_task_mm(task))) {
-			pr_devel("cxl_handle_fault unable to get mm %i\n",
-				 pid_nr(ctx->pid));
-			cxl_ack_ae(ctx);
-			goto out;
+		} else {
+			pr_devel("Handling page fault for pe=%d pid=%i\n",
+				 ctx->pe, pid_nr(ctx->pid));
 		}
 	}
 
@@ -218,33 +300,22 @@
 
 	if (mm)
 		mmput(mm);
-out:
-	if (task)
-		put_task_struct(task);
 }
 
 static void cxl_prefault_one(struct cxl_context *ctx, u64 ea)
 {
-	int rc;
-	struct task_struct *task;
 	struct mm_struct *mm;
 
-	if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
-		pr_devel("cxl_prefault_one unable to get task %i\n",
-			 pid_nr(ctx->pid));
-		return;
-	}
-	if (!(mm = get_task_mm(task))) {
+	mm = get_mem_context(ctx);
+	if (mm == NULL) {
 		pr_devel("cxl_prefault_one unable to get mm %i\n",
 			 pid_nr(ctx->pid));
-		put_task_struct(task);
 		return;
 	}
 
-	rc = cxl_fault_segment(ctx, mm, ea);
+	cxl_fault_segment(ctx, mm, ea);
 
 	mmput(mm);
-	put_task_struct(task);
 }
 
 static u64 next_segment(u64 ea, u64 vsid)
@@ -263,18 +334,13 @@
 	struct copro_slb slb;
 	struct vm_area_struct *vma;
 	int rc;
-	struct task_struct *task;
 	struct mm_struct *mm;
 
-	if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
-		pr_devel("cxl_prefault_vma unable to get task %i\n",
-			 pid_nr(ctx->pid));
-		return;
-	}
-	if (!(mm = get_task_mm(task))) {
+	mm = get_mem_context(ctx);
+	if (mm == NULL) {
 		pr_devel("cxl_prefault_vm unable to get mm %i\n",
 			 pid_nr(ctx->pid));
-		goto out1;
+		return;
 	}
 
 	down_read(&mm->mmap_sem);
@@ -295,8 +361,6 @@
 	up_read(&mm->mmap_sem);
 
 	mmput(mm);
-out1:
-	put_task_struct(task);
 }
 
 void cxl_prefault(struct cxl_context *ctx, u64 wed)
--- linux-4.4.0.orig/drivers/misc/cxl/file.c
+++ linux-4.4.0/drivers/misc/cxl/file.c
@@ -26,9 +26,7 @@
 #include "trace.h"
 
 #define CXL_NUM_MINORS 256 /* Total to reserve */
-#define CXL_DEV_MINORS 13   /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
 
-#define CXL_CARD_MINOR(adapter) (adapter->adapter_num * CXL_DEV_MINORS)
 #define CXL_AFU_MINOR_D(afu) (CXL_CARD_MINOR(afu->adapter) + 1 + (3 * afu->slice))
 #define CXL_AFU_MINOR_M(afu) (CXL_AFU_MINOR_D(afu) + 1)
 #define CXL_AFU_MINOR_S(afu) (CXL_AFU_MINOR_D(afu) + 2)
@@ -36,7 +34,6 @@
 #define CXL_AFU_MKDEV_M(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_M(afu))
 #define CXL_AFU_MKDEV_S(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_S(afu))
 
-#define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS)
 #define CXL_DEVT_AFU(dev) ((MINOR(dev) % CXL_DEV_MINORS - 1) / 3)
 
 #define CXL_DEVT_IS_CARD(dev) (MINOR(dev) % CXL_DEV_MINORS == 0)
@@ -67,13 +64,19 @@
 		spin_unlock(&adapter->afu_list_lock);
 		goto err_put_adapter;
 	}
-	get_device(&afu->dev);
+
+	/*
+	 * taking a ref to the afu so that it doesn't go away
+	 * for rest of the function. This ref is released before
+	 * we return.
+	 */
+	cxl_afu_get(afu);
 	spin_unlock(&adapter->afu_list_lock);
 
 	if (!afu->current_mode)
 		goto err_put_afu;
 
-	if (!cxl_adapter_link_ok(adapter)) {
+	if (!cxl_ops->link_ok(adapter, afu)) {
 		rc = -EIO;
 		goto err_put_afu;
 	}
@@ -83,20 +86,21 @@
 		goto err_put_afu;
 	}
 
-	if ((rc = cxl_context_init(ctx, afu, master, inode->i_mapping)))
+	rc = cxl_context_init(ctx, afu, master);
+	if (rc)
 		goto err_put_afu;
 
+	cxl_context_set_mapping(ctx, inode->i_mapping);
+
 	pr_devel("afu_open pe: %i\n", ctx->pe);
 	file->private_data = ctx;
-	cxl_ctx_get();
 
-	/* Our ref on the AFU will now hold the adapter */
-	put_device(&adapter->dev);
-
-	return 0;
+	/* indicate success */
+	rc = 0;
 
 err_put_afu:
-	put_device(&afu->dev);
+	/* release the ref taken earlier */
+	cxl_afu_put(afu);
 err_put_adapter:
 	put_device(&adapter->dev);
 	return rc;
@@ -131,8 +135,6 @@
 		mutex_unlock(&ctx->mapping_lock);
 	}
 
-	put_device(&ctx->afu->dev);
-
 	/*
 	 * At this this point all bottom halfs have finished and we should be
 	 * getting no more IRQs from the hardware for this context.  Once it's
@@ -155,11 +157,8 @@
 
 	/* Do this outside the status_mutex to avoid a circular dependency with
 	 * the locking in cxl_mmap_fault() */
-	if (copy_from_user(&work, uwork,
-			   sizeof(struct cxl_ioctl_start_work))) {
-		rc = -EFAULT;
-		goto out;
-	}
+	if (copy_from_user(&work, uwork, sizeof(work)))
+		return -EFAULT;
 
 	mutex_lock(&ctx->status_mutex);
 	if (ctx->status != OPENED) {
@@ -198,14 +197,25 @@
 	 * where a process (master, some daemon, etc) has opened the chardev on
 	 * behalf of another process, so the AFU's mm gets bound to the process
 	 * that performs this ioctl and not the process that opened the file.
+	 * Also we grab the PID of the group leader so that if the task that
+	 * has performed the attach operation exits the mm context of the
+	 * process is still accessible.
+	 */
+	ctx->pid = get_task_pid(current, PIDTYPE_PID);
+	ctx->glpid = get_task_pid(current->group_leader, PIDTYPE_PID);
+
+	/*
+	 * Increment driver use count. Enables global TLBIs for hash
+	 * and callbacks to handle the segment table
 	 */
-	ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID));
+	cxl_ctx_get();
 
 	trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr);
 
-	if ((rc = cxl_attach_process(ctx, false, work.work_element_descriptor,
-				     amr))) {
+	if ((rc = cxl_ops->attach_process(ctx, false, work.work_element_descriptor,
+							amr))) {
 		afu_release_irqs(ctx, ctx);
+		cxl_ctx_put();
 		goto out;
 	}
 
@@ -215,12 +225,13 @@
 	mutex_unlock(&ctx->status_mutex);
 	return rc;
 }
+
 static long afu_ioctl_process_element(struct cxl_context *ctx,
 				      int __user *upe)
 {
 	pr_devel("%s: pe: %i\n", __func__, ctx->pe);
 
-	if (copy_to_user(upe, &ctx->pe, sizeof(__u32)))
+	if (copy_to_user(upe, &ctx->external_pe, sizeof(__u32)))
 		return -EFAULT;
 
 	return 0;
@@ -252,7 +263,7 @@
 	if (ctx->status == CLOSED)
 		return -EIO;
 
-	if (!cxl_adapter_link_ok(ctx->afu->adapter))
+	if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu))
 		return -EIO;
 
 	pr_devel("afu_ioctl\n");
@@ -282,7 +293,7 @@
 	if (ctx->status != STARTED)
 		return -EIO;
 
-	if (!cxl_adapter_link_ok(ctx->afu->adapter))
+	if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu))
 		return -EIO;
 
 	return cxl_context_iomap(ctx, vm);
@@ -329,7 +340,7 @@
 	int rc;
 	DEFINE_WAIT(wait);
 
-	if (!cxl_adapter_link_ok(ctx->afu->adapter))
+	if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu))
 		return -EIO;
 
 	if (count < CXL_READ_MIN_SIZE)
@@ -342,7 +353,7 @@
 		if (ctx_event_pending(ctx))
 			break;
 
-		if (!cxl_adapter_link_ok(ctx->afu->adapter)) {
+		if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)) {
 			rc = -EIO;
 			goto out;
 		}
@@ -438,7 +449,8 @@
 
 static char *cxl_devnode(struct device *dev, umode_t *mode)
 {
-	if (CXL_DEVT_IS_CARD(dev->devt)) {
+	if (cpu_has_feature(CPU_FTR_HVMODE) &&
+	    CXL_DEVT_IS_CARD(dev->devt)) {
 		/*
 		 * These minor numbers will eventually be used to program the
 		 * PSL and AFUs once we have dynamic reprogramming support
@@ -539,6 +551,11 @@
 	return device_register(&adapter->dev);
 }
 
+dev_t cxl_get_dev(void)
+{
+	return cxl_dev;
+}
+
 int __init cxl_file_init(void)
 {
 	int rc;
--- linux-4.4.0.orig/drivers/misc/cxl/flash.c
+++ linux-4.4.0/drivers/misc/cxl/flash.c
@@ -0,0 +1,538 @@
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <asm/rtas.h>
+
+#include "cxl.h"
+#include "hcalls.h"
+
+#define DOWNLOAD_IMAGE 1
+#define VALIDATE_IMAGE 2
+
+struct ai_header {
+	u16 version;
+	u8  reserved0[6];
+	u16 vendor;
+	u16 device;
+	u16 subsystem_vendor;
+	u16 subsystem;
+	u64 image_offset;
+	u64 image_length;
+	u8  reserved1[96];
+};
+
+static struct semaphore sem;
+unsigned long *buffer[CXL_AI_MAX_ENTRIES];
+struct sg_list *le;
+static u64 continue_token;
+static unsigned int transfer;
+
+struct update_props_workarea {
+	__be32 phandle;
+	__be32 state;
+	__be64 reserved;
+	__be32 nprops;
+} __packed;
+
+struct update_nodes_workarea {
+	__be32 state;
+	__be64 unit_address;
+	__be32 reserved;
+} __packed;
+
+#define DEVICE_SCOPE 3
+#define NODE_ACTION_MASK	0xff000000
+#define NODE_COUNT_MASK		0x00ffffff
+#define OPCODE_DELETE	0x01000000
+#define OPCODE_UPDATE	0x02000000
+#define OPCODE_ADD	0x03000000
+
+static int rcall(int token, char *buf, s32 scope)
+{
+	int rc;
+
+	spin_lock(&rtas_data_buf_lock);
+
+	memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
+	rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope);
+	memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
+
+	spin_unlock(&rtas_data_buf_lock);
+	return rc;
+}
+
+static int update_property(struct device_node *dn, const char *name,
+			   u32 vd, char *value)
+{
+	struct property *new_prop;
+	u32 *val;
+	int rc;
+
+	new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
+	if (!new_prop)
+		return -ENOMEM;
+
+	new_prop->name = kstrdup(name, GFP_KERNEL);
+	if (!new_prop->name) {
+		kfree(new_prop);
+		return -ENOMEM;
+	}
+
+	new_prop->length = vd;
+	new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
+	if (!new_prop->value) {
+		kfree(new_prop->name);
+		kfree(new_prop);
+		return -ENOMEM;
+	}
+	memcpy(new_prop->value, value, vd);
+
+	val = (u32 *)new_prop->value;
+	rc = cxl_update_properties(dn, new_prop);
+	pr_devel("%s: update property (%s, length: %i, value: %#x)\n",
+		  dn->name, name, vd, be32_to_cpu(*val));
+
+	if (rc) {
+		kfree(new_prop->name);
+		kfree(new_prop->value);
+		kfree(new_prop);
+	}
+	return rc;
+}
+
+static int update_node(__be32 phandle, s32 scope)
+{
+	struct update_props_workarea *upwa;
+	struct device_node *dn;
+	int i, rc, ret;
+	char *prop_data;
+	char *buf;
+	int token;
+	u32 nprops;
+	u32 vd;
+
+	token = rtas_token("ibm,update-properties");
+	if (token == RTAS_UNKNOWN_SERVICE)
+		return -EINVAL;
+
+	buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	dn = of_find_node_by_phandle(be32_to_cpu(phandle));
+	if (!dn) {
+		kfree(buf);
+		return -ENOENT;
+	}
+
+	upwa = (struct update_props_workarea *)&buf[0];
+	upwa->phandle = phandle;
+	do {
+		rc = rcall(token, buf, scope);
+		if (rc < 0)
+			break;
+
+		prop_data = buf + sizeof(*upwa);
+		nprops = be32_to_cpu(upwa->nprops);
+
+		if (*prop_data == 0) {
+			prop_data++;
+			vd = be32_to_cpu(*(__be32 *)prop_data);
+			prop_data += vd + sizeof(vd);
+			nprops--;
+		}
+
+		for (i = 0; i < nprops; i++) {
+			char *prop_name;
+
+			prop_name = prop_data;
+			prop_data += strlen(prop_name) + 1;
+			vd = be32_to_cpu(*(__be32 *)prop_data);
+			prop_data += sizeof(vd);
+
+			if ((vd != 0x00000000) && (vd != 0x80000000)) {
+				ret = update_property(dn, prop_name, vd,
+						prop_data);
+				if (ret)
+					pr_err("cxl: Could not update property %s - %i\n",
+					       prop_name, ret);
+
+				prop_data += vd;
+			}
+		}
+	} while (rc == 1);
+
+	of_node_put(dn);
+	kfree(buf);
+	return rc;
+}
+
+static int update_devicetree(struct cxl *adapter, s32 scope)
+{
+	struct update_nodes_workarea *unwa;
+	u32 action, node_count;
+	int token, rc, i;
+	__be32 *data, drc_index, phandle;
+	char *buf;
+
+	token = rtas_token("ibm,update-nodes");
+	if (token == RTAS_UNKNOWN_SERVICE)
+		return -EINVAL;
+
+	buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	unwa = (struct update_nodes_workarea *)&buf[0];
+	unwa->unit_address = cpu_to_be64(adapter->guest->handle);
+	do {
+		rc = rcall(token, buf, scope);
+		if (rc && rc != 1)
+			break;
+
+		data = (__be32 *)buf + 4;
+		while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
+			action = be32_to_cpu(*data) & NODE_ACTION_MASK;
+			node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
+			pr_devel("device reconfiguration - action: %#x, nodes: %#x\n",
+				 action, node_count);
+			data++;
+
+			for (i = 0; i < node_count; i++) {
+				phandle = *data++;
+
+				switch (action) {
+				case OPCODE_DELETE:
+					/* nothing to do */
+					break;
+				case OPCODE_UPDATE:
+					update_node(phandle, scope);
+					break;
+				case OPCODE_ADD:
+					/* nothing to do, just move pointer */
+					drc_index = *data++;
+					break;
+				}
+			}
+		}
+	} while (rc == 1);
+
+	kfree(buf);
+	return 0;
+}
+
+static int handle_image(struct cxl *adapter, int operation,
+			long (*fct)(u64, u64, u64, u64 *),
+			struct cxl_adapter_image *ai)
+{
+	size_t mod, s_copy, len_chunk = 0;
+	struct ai_header *header = NULL;
+	unsigned int entries = 0, i;
+	void *dest, *from;
+	int rc = 0, need_header;
+
+	/* base adapter image header */
+	need_header = (ai->flags & CXL_AI_NEED_HEADER);
+	if (need_header) {
+		header = kzalloc(sizeof(struct ai_header), GFP_KERNEL);
+		if (!header)
+			return -ENOMEM;
+		header->version = cpu_to_be16(1);
+		header->vendor = cpu_to_be16(adapter->guest->vendor);
+		header->device = cpu_to_be16(adapter->guest->device);
+		header->subsystem_vendor = cpu_to_be16(adapter->guest->subsystem_vendor);
+		header->subsystem = cpu_to_be16(adapter->guest->subsystem);
+		header->image_offset = cpu_to_be64(CXL_AI_HEADER_SIZE);
+		header->image_length = cpu_to_be64(ai->len_image);
+	}
+
+	/* number of entries in the list */
+	len_chunk = ai->len_data;
+	if (need_header)
+		len_chunk += CXL_AI_HEADER_SIZE;
+
+	entries = len_chunk / CXL_AI_BUFFER_SIZE;
+	mod = len_chunk % CXL_AI_BUFFER_SIZE;
+	if (mod)
+		entries++;
+
+	if (entries > CXL_AI_MAX_ENTRIES) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	/*          < -- MAX_CHUNK_SIZE = 4096 * 256 = 1048576 bytes -->
+	 * chunk 0  ----------------------------------------------------
+	 *          | header   |  data                                 |
+	 *          ----------------------------------------------------
+	 * chunk 1  ----------------------------------------------------
+	 *          | data                                             |
+	 *          ----------------------------------------------------
+	 * ....
+	 * chunk n  ----------------------------------------------------
+	 *          | data                                             |
+	 *          ----------------------------------------------------
+	 */
+	from = (void *) ai->data;
+	for (i = 0; i < entries; i++) {
+		dest = buffer[i];
+		s_copy = CXL_AI_BUFFER_SIZE;
+
+		if ((need_header) && (i == 0)) {
+			/* add adapter image header */
+			memcpy(buffer[i], header, sizeof(struct ai_header));
+			s_copy = CXL_AI_BUFFER_SIZE - CXL_AI_HEADER_SIZE;
+			dest += CXL_AI_HEADER_SIZE; /* image offset */
+		}
+		if ((i == (entries - 1)) && mod)
+			s_copy = mod;
+
+		/* copy data */
+		if (copy_from_user(dest, from, s_copy))
+			goto err;
+
+		/* fill in the list */
+		le[i].phys_addr = cpu_to_be64(virt_to_phys(buffer[i]));
+		le[i].len = cpu_to_be64(CXL_AI_BUFFER_SIZE);
+		if ((i == (entries - 1)) && mod)
+			le[i].len = cpu_to_be64(mod);
+		from += s_copy;
+	}
+	pr_devel("%s (op: %i, need header: %i, entries: %i, token: %#llx)\n",
+		 __func__, operation, need_header, entries, continue_token);
+
+	/*
+	 * download/validate the adapter image to the coherent
+	 * platform facility
+	 */
+	rc = fct(adapter->guest->handle, virt_to_phys(le), entries,
+		&continue_token);
+	if (rc == 0) /* success of download/validation operation */
+		continue_token = 0;
+
+err:
+	kfree(header);
+
+	return rc;
+}
+
+static int transfer_image(struct cxl *adapter, int operation,
+			struct cxl_adapter_image *ai)
+{
+	int rc = 0;
+	int afu;
+
+	switch (operation) {
+	case DOWNLOAD_IMAGE:
+		rc = handle_image(adapter, operation,
+				&cxl_h_download_adapter_image, ai);
+		if (rc < 0) {
+			pr_devel("resetting adapter\n");
+			cxl_h_reset_adapter(adapter->guest->handle);
+		}
+		return rc;
+
+	case VALIDATE_IMAGE:
+		rc = handle_image(adapter, operation,
+				&cxl_h_validate_adapter_image, ai);
+		if (rc < 0) {
+			pr_devel("resetting adapter\n");
+			cxl_h_reset_adapter(adapter->guest->handle);
+			return rc;
+		}
+		if (rc == 0) {
+			pr_devel("remove curent afu\n");
+			for (afu = 0; afu < adapter->slices; afu++)
+				cxl_guest_remove_afu(adapter->afu[afu]);
+
+			pr_devel("resetting adapter\n");
+			cxl_h_reset_adapter(adapter->guest->handle);
+
+			/* The entire image has now been
+			 * downloaded and the validation has
+			 * been successfully performed.
+			 * After that, the partition should call
+			 * ibm,update-nodes and
+			 * ibm,update-properties to receive the
+			 * current configuration
+			 */
+			rc = update_devicetree(adapter, DEVICE_SCOPE);
+			transfer = 1;
+		}
+		return rc;
+	}
+
+	return -EINVAL;
+}
+
+static long ioctl_transfer_image(struct cxl *adapter, int operation,
+				struct cxl_adapter_image __user *uai)
+{
+	struct cxl_adapter_image ai;
+
+	pr_devel("%s\n", __func__);
+
+	if (copy_from_user(&ai, uai, sizeof(struct cxl_adapter_image)))
+		return -EFAULT;
+
+	/*
+	 * Make sure reserved fields and bits are set to 0
+	 */
+	if (ai.reserved1 || ai.reserved2 || ai.reserved3 || ai.reserved4 ||
+		(ai.flags & ~CXL_AI_ALL))
+		return -EINVAL;
+
+	return transfer_image(adapter, operation, &ai);
+}
+
+static int device_open(struct inode *inode, struct file *file)
+{
+	int adapter_num = CXL_DEVT_ADAPTER(inode->i_rdev);
+	struct cxl *adapter;
+	int rc = 0, i;
+
+	pr_devel("in %s\n", __func__);
+
+	BUG_ON(sizeof(struct ai_header) != CXL_AI_HEADER_SIZE);
+
+	/* Allows one process to open the device by using a semaphore */
+	if (down_interruptible(&sem) != 0)
+		return -EPERM;
+
+	if (!(adapter = get_cxl_adapter(adapter_num)))
+		return -ENODEV;
+
+	file->private_data = adapter;
+	continue_token = 0;
+	transfer = 0;
+
+	for (i = 0; i < CXL_AI_MAX_ENTRIES; i++)
+		buffer[i] = NULL;
+
+	/* aligned buffer containing list entries which describes up to
+	 * 1 megabyte of data (256 entries of 4096 bytes each)
+	 *  Logical real address of buffer 0  -  Buffer 0 length in bytes
+	 *  Logical real address of buffer 1  -  Buffer 1 length in bytes
+	 *  Logical real address of buffer 2  -  Buffer 2 length in bytes
+	 *  ....
+	 *  ....
+	 *  Logical real address of buffer N  -  Buffer N length in bytes
+	 */
+	le = (struct sg_list *)get_zeroed_page(GFP_KERNEL);
+	if (!le) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
+		buffer[i] = (unsigned long *)get_zeroed_page(GFP_KERNEL);
+		if (!buffer[i]) {
+			rc = -ENOMEM;
+			goto err1;
+		}
+	}
+
+	return 0;
+
+err1:
+	for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
+		if (buffer[i])
+			free_page((unsigned long) buffer[i]);
+	}
+
+	if (le)
+		free_page((unsigned long) le);
+err:
+	put_device(&adapter->dev);
+
+	return rc;
+}
+
+static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct cxl *adapter = file->private_data;
+
+	pr_devel("in %s\n", __func__);
+
+	if (cmd == CXL_IOCTL_DOWNLOAD_IMAGE)
+		return ioctl_transfer_image(adapter,
+					DOWNLOAD_IMAGE,
+					(struct cxl_adapter_image __user *)arg);
+	else if (cmd == CXL_IOCTL_VALIDATE_IMAGE)
+		return ioctl_transfer_image(adapter,
+					VALIDATE_IMAGE,
+					(struct cxl_adapter_image __user *)arg);
+	else
+		return -EINVAL;
+}
+
+static long device_compat_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	return device_ioctl(file, cmd, arg);
+}
+
+static int device_close(struct inode *inode, struct file *file)
+{
+	struct cxl *adapter = file->private_data;
+	int i;
+
+	pr_devel("in %s\n", __func__);
+
+	for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
+		if (buffer[i])
+			free_page((unsigned long) buffer[i]);
+	}
+
+	if (le)
+		free_page((unsigned long) le);
+
+	up(&sem);
+	put_device(&adapter->dev);
+	continue_token = 0;
+
+	/* reload the module */
+	if (transfer)
+		cxl_guest_reload_module(adapter);
+	else {
+		pr_devel("resetting adapter\n");
+		cxl_h_reset_adapter(adapter->guest->handle);
+	}
+
+	transfer = 0;
+	return 0;
+}
+
+static const struct file_operations fops = {
+	.owner		= THIS_MODULE,
+	.open		= device_open,
+	.unlocked_ioctl	= device_ioctl,
+	.compat_ioctl	= device_compat_ioctl,
+	.release	= device_close,
+};
+
+void cxl_guest_remove_chardev(struct cxl *adapter)
+{
+	cdev_del(&adapter->guest->cdev);
+}
+
+int cxl_guest_add_chardev(struct cxl *adapter)
+{
+	dev_t devt;
+	int rc;
+
+	devt = MKDEV(MAJOR(cxl_get_dev()), CXL_CARD_MINOR(adapter));
+	cdev_init(&adapter->guest->cdev, &fops);
+	if ((rc = cdev_add(&adapter->guest->cdev, devt, 1))) {
+		dev_err(&adapter->dev,
+			"Unable to add chardev on adapter (card%i): %i\n",
+			adapter->adapter_num, rc);
+		goto err;
+	}
+	adapter->dev.devt = devt;
+	sema_init(&sem, 1);
+err:
+	return rc;
+}
--- linux-4.4.0.orig/drivers/misc/cxl/guest.c
+++ linux-4.4.0/drivers/misc/cxl/guest.c
@@ -0,0 +1,1177 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+
+#include "cxl.h"
+#include "hcalls.h"
+#include "trace.h"
+
+#define CXL_ERROR_DETECTED_EVENT	1
+#define CXL_SLOT_RESET_EVENT		2
+#define CXL_RESUME_EVENT		3
+
+static void pci_error_handlers(struct cxl_afu *afu,
+				int bus_error_event,
+				pci_channel_state_t state)
+{
+	struct pci_dev *afu_dev;
+
+	if (afu->phb == NULL)
+		return;
+
+	list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
+		if (!afu_dev->driver)
+			continue;
+
+		switch (bus_error_event) {
+		case CXL_ERROR_DETECTED_EVENT:
+			afu_dev->error_state = state;
+
+			if (afu_dev->driver->err_handler &&
+			    afu_dev->driver->err_handler->error_detected)
+				afu_dev->driver->err_handler->error_detected(afu_dev, state);
+		break;
+		case CXL_SLOT_RESET_EVENT:
+			afu_dev->error_state = state;
+
+			if (afu_dev->driver->err_handler &&
+			    afu_dev->driver->err_handler->slot_reset)
+				afu_dev->driver->err_handler->slot_reset(afu_dev);
+		break;
+		case CXL_RESUME_EVENT:
+			if (afu_dev->driver->err_handler &&
+			    afu_dev->driver->err_handler->resume)
+				afu_dev->driver->err_handler->resume(afu_dev);
+		break;
+		}
+	}
+}
+
+static irqreturn_t guest_handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr,
+					u64 errstat)
+{
+	pr_devel("in %s\n", __func__);
+	dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%.16llx\n", errstat);
+
+	return cxl_ops->ack_irq(ctx, 0, errstat);
+}
+
+static ssize_t guest_collect_vpd(struct cxl *adapter, struct cxl_afu *afu,
+			void *buf, size_t len)
+{
+	unsigned int entries, mod;
+	unsigned long **vpd_buf = NULL;
+	struct sg_list *le;
+	int rc = 0, i, tocopy;
+	u64 out = 0;
+
+	if (buf == NULL)
+		return -EINVAL;
+
+	/* number of entries in the list */
+	entries = len / SG_BUFFER_SIZE;
+	mod = len % SG_BUFFER_SIZE;
+	if (mod)
+		entries++;
+
+	if (entries > SG_MAX_ENTRIES) {
+		entries = SG_MAX_ENTRIES;
+		len = SG_MAX_ENTRIES * SG_BUFFER_SIZE;
+		mod = 0;
+	}
+
+	vpd_buf = kzalloc(entries * sizeof(unsigned long *), GFP_KERNEL);
+	if (!vpd_buf)
+		return -ENOMEM;
+
+	le = (struct sg_list *)get_zeroed_page(GFP_KERNEL);
+	if (!le) {
+		rc = -ENOMEM;
+		goto err1;
+	}
+
+	for (i = 0; i < entries; i++) {
+		vpd_buf[i] = (unsigned long *)get_zeroed_page(GFP_KERNEL);
+		if (!vpd_buf[i]) {
+			rc = -ENOMEM;
+			goto err2;
+		}
+		le[i].phys_addr = cpu_to_be64(virt_to_phys(vpd_buf[i]));
+		le[i].len = cpu_to_be64(SG_BUFFER_SIZE);
+		if ((i == (entries - 1)) && mod)
+			le[i].len = cpu_to_be64(mod);
+	}
+
+	if (adapter)
+		rc = cxl_h_collect_vpd_adapter(adapter->guest->handle,
+					virt_to_phys(le), entries, &out);
+	else
+		rc = cxl_h_collect_vpd(afu->guest->handle, 0,
+				virt_to_phys(le), entries, &out);
+	pr_devel("length of available (entries: %i), vpd: %#llx\n",
+		entries, out);
+
+	if (!rc) {
+		/*
+		 * hcall returns in 'out' the size of available VPDs.
+		 * It fills the buffer with as much data as possible.
+		 */
+		if (out < len)
+			len = out;
+		rc = len;
+		if (out) {
+			for (i = 0; i < entries; i++) {
+				if (len < SG_BUFFER_SIZE)
+					tocopy = len;
+				else
+					tocopy = SG_BUFFER_SIZE;
+				memcpy(buf, vpd_buf[i], tocopy);
+				buf += tocopy;
+				len -= tocopy;
+			}
+		}
+	}
+err2:
+	for (i = 0; i < entries; i++) {
+		if (vpd_buf[i])
+			free_page((unsigned long) vpd_buf[i]);
+	}
+	free_page((unsigned long) le);
+err1:
+	kfree(vpd_buf);
+	return rc;
+}
+
+static int guest_get_irq_info(struct cxl_context *ctx, struct cxl_irq_info *info)
+{
+	return cxl_h_collect_int_info(ctx->afu->guest->handle, ctx->process_token, info);
+}
+
+static irqreturn_t guest_psl_irq(int irq, void *data)
+{
+	struct cxl_context *ctx = data;
+	struct cxl_irq_info irq_info;
+	int rc;
+
+	pr_devel("%d: received PSL interrupt %i\n", ctx->pe, irq);
+	rc = guest_get_irq_info(ctx, &irq_info);
+	if (rc) {
+		WARN(1, "Unable to get IRQ info: %i\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	rc = cxl_irq(irq, ctx, &irq_info);
+	return rc;
+}
+
+static int afu_read_error_state(struct cxl_afu *afu, int *state_out)
+{
+	u64 state;
+	int rc = 0;
+
+	rc = cxl_h_read_error_state(afu->guest->handle, &state);
+	if (!rc) {
+		WARN_ON(state != H_STATE_NORMAL &&
+			state != H_STATE_DISABLE &&
+			state != H_STATE_TEMP_UNAVAILABLE &&
+			state != H_STATE_PERM_UNAVAILABLE);
+		*state_out = state & 0xffffffff;
+	}
+	return rc;
+}
+
+static irqreturn_t guest_slice_irq_err(int irq, void *data)
+{
+	struct cxl_afu *afu = data;
+	int rc;
+	u64 serr;
+
+	WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq);
+	rc = cxl_h_get_fn_error_interrupt(afu->guest->handle, &serr);
+	if (rc) {
+		dev_crit(&afu->dev, "Couldn't read PSL_SERR_An: %d\n", rc);
+		return IRQ_HANDLED;
+	}
+	dev_crit(&afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr);
+
+	rc = cxl_h_ack_fn_error_interrupt(afu->guest->handle, serr);
+	if (rc)
+		dev_crit(&afu->dev, "Couldn't ack slice error interrupt: %d\n",
+			rc);
+
+	return IRQ_HANDLED;
+}
+
+
+static int irq_alloc_range(struct cxl *adapter, int len, int *irq)
+{
+	int i, n;
+	struct irq_avail *cur;
+
+	for (i = 0; i < adapter->guest->irq_nranges; i++) {
+		cur = &adapter->guest->irq_avail[i];
+		n = bitmap_find_next_zero_area(cur->bitmap, cur->range,
+					0, len, 0);
+		if (n < cur->range) {
+			bitmap_set(cur->bitmap, n, len);
+			*irq = cur->offset + n;
+			pr_devel("guest: allocate IRQs %#x->%#x\n",
+				*irq, *irq + len - 1);
+
+			return 0;
+		}
+	}
+	return -ENOSPC;
+}
+
+static int irq_free_range(struct cxl *adapter, int irq, int len)
+{
+	int i, n;
+	struct irq_avail *cur;
+
+	if (len == 0)
+		return -ENOENT;
+
+	for (i = 0; i < adapter->guest->irq_nranges; i++) {
+		cur = &adapter->guest->irq_avail[i];
+		if (irq >= cur->offset &&
+			(irq + len) <= (cur->offset + cur->range)) {
+			n = irq - cur->offset;
+			bitmap_clear(cur->bitmap, n, len);
+			pr_devel("guest: release IRQs %#x->%#x\n",
+				irq, irq + len - 1);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+static int guest_reset(struct cxl *adapter)
+{
+	struct cxl_afu *afu = NULL;
+	int i, rc;
+
+	pr_devel("Adapter reset request\n");
+	for (i = 0; i < adapter->slices; i++) {
+		if ((afu = adapter->afu[i])) {
+			pci_error_handlers(afu, CXL_ERROR_DETECTED_EVENT,
+					pci_channel_io_frozen);
+			cxl_context_detach_all(afu);
+		}
+	}
+
+	rc = cxl_h_reset_adapter(adapter->guest->handle);
+	for (i = 0; i < adapter->slices; i++) {
+		if (!rc && (afu = adapter->afu[i])) {
+			pci_error_handlers(afu, CXL_SLOT_RESET_EVENT,
+					pci_channel_io_normal);
+			pci_error_handlers(afu, CXL_RESUME_EVENT, 0);
+		}
+	}
+	return rc;
+}
+
+static int guest_alloc_one_irq(struct cxl *adapter)
+{
+	int irq;
+
+	spin_lock(&adapter->guest->irq_alloc_lock);
+	if (irq_alloc_range(adapter, 1, &irq))
+		irq = -ENOSPC;
+	spin_unlock(&adapter->guest->irq_alloc_lock);
+	return irq;
+}
+
+static void guest_release_one_irq(struct cxl *adapter, int irq)
+{
+	spin_lock(&adapter->guest->irq_alloc_lock);
+	irq_free_range(adapter, irq, 1);
+	spin_unlock(&adapter->guest->irq_alloc_lock);
+}
+
+static int guest_alloc_irq_ranges(struct cxl_irq_ranges *irqs,
+				struct cxl *adapter, unsigned int num)
+{
+	int i, try, irq;
+
+	memset(irqs, 0, sizeof(struct cxl_irq_ranges));
+
+	spin_lock(&adapter->guest->irq_alloc_lock);
+	for (i = 0; i < CXL_IRQ_RANGES && num; i++) {
+		try = num;
+		while (try) {
+			if (irq_alloc_range(adapter, try, &irq) == 0)
+				break;
+			try /= 2;
+		}
+		if (!try)
+			goto error;
+		irqs->offset[i] = irq;
+		irqs->range[i] = try;
+		num -= try;
+	}
+	if (num)
+		goto error;
+	spin_unlock(&adapter->guest->irq_alloc_lock);
+	return 0;
+
+error:
+	for (i = 0; i < CXL_IRQ_RANGES; i++)
+		irq_free_range(adapter, irqs->offset[i], irqs->range[i]);
+	spin_unlock(&adapter->guest->irq_alloc_lock);
+	return -ENOSPC;
+}
+
+static void guest_release_irq_ranges(struct cxl_irq_ranges *irqs,
+				struct cxl *adapter)
+{
+	int i;
+
+	spin_lock(&adapter->guest->irq_alloc_lock);
+	for (i = 0; i < CXL_IRQ_RANGES; i++)
+		irq_free_range(adapter, irqs->offset[i], irqs->range[i]);
+	spin_unlock(&adapter->guest->irq_alloc_lock);
+}
+
+static int guest_register_serr_irq(struct cxl_afu *afu)
+{
+	afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
+				      dev_name(&afu->dev));
+	if (!afu->err_irq_name)
+		return -ENOMEM;
+
+	if (!(afu->serr_virq = cxl_map_irq(afu->adapter, afu->serr_hwirq,
+				 guest_slice_irq_err, afu, afu->err_irq_name))) {
+		kfree(afu->err_irq_name);
+		afu->err_irq_name = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void guest_release_serr_irq(struct cxl_afu *afu)
+{
+	cxl_unmap_irq(afu->serr_virq, afu);
+	cxl_ops->release_one_irq(afu->adapter, afu->serr_hwirq);
+	kfree(afu->err_irq_name);
+}
+
+static int guest_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
+{
+	return cxl_h_control_faults(ctx->afu->guest->handle, ctx->process_token,
+				tfc >> 32, (psl_reset_mask != 0));
+}
+
+static void disable_afu_irqs(struct cxl_context *ctx)
+{
+	irq_hw_number_t hwirq;
+	unsigned int virq;
+	int r, i;
+
+	pr_devel("Disabling AFU(%d) interrupts\n", ctx->afu->slice);
+	for (r = 0; r < CXL_IRQ_RANGES; r++) {
+		hwirq = ctx->irqs.offset[r];
+		for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
+			virq = irq_find_mapping(NULL, hwirq);
+			disable_irq(virq);
+		}
+	}
+}
+
+static void enable_afu_irqs(struct cxl_context *ctx)
+{
+	irq_hw_number_t hwirq;
+	unsigned int virq;
+	int r, i;
+
+	pr_devel("Enabling AFU(%d) interrupts\n", ctx->afu->slice);
+	for (r = 0; r < CXL_IRQ_RANGES; r++) {
+		hwirq = ctx->irqs.offset[r];
+		for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
+			virq = irq_find_mapping(NULL, hwirq);
+			enable_irq(virq);
+		}
+	}
+}
+
+static int _guest_afu_cr_readXX(int sz, struct cxl_afu *afu, int cr_idx,
+			u64 offset, u64 *val)
+{
+	unsigned long cr;
+	char c;
+	int rc = 0;
+
+	if (afu->crs_len < sz)
+		return -ENOENT;
+
+	if (unlikely(offset >= afu->crs_len))
+		return -ERANGE;
+
+	cr = get_zeroed_page(GFP_KERNEL);
+	if (!cr)
+		return -ENOMEM;
+
+	rc = cxl_h_get_config(afu->guest->handle, cr_idx, offset,
+			virt_to_phys((void *)cr), sz);
+	if (rc)
+		goto err;
+
+	switch (sz) {
+	case 1:
+		c = *((char *) cr);
+		*val = c;
+		break;
+	case 2:
+		*val = in_le16((u16 *)cr);
+		break;
+	case 4:
+		*val = in_le32((unsigned *)cr);
+		break;
+	case 8:
+		*val = in_le64((u64 *)cr);
+		break;
+	default:
+		WARN_ON(1);
+	}
+err:
+	free_page(cr);
+	return rc;
+}
+
+static int guest_afu_cr_read32(struct cxl_afu *afu, int cr_idx, u64 offset,
+			u32 *out)
+{
+	int rc;
+	u64 val;
+
+	rc = _guest_afu_cr_readXX(4, afu, cr_idx, offset, &val);
+	if (!rc)
+		*out = (u32) val;
+	return rc;
+}
+
+static int guest_afu_cr_read16(struct cxl_afu *afu, int cr_idx, u64 offset,
+			u16 *out)
+{
+	int rc;
+	u64 val;
+
+	rc = _guest_afu_cr_readXX(2, afu, cr_idx, offset, &val);
+	if (!rc)
+		*out = (u16) val;
+	return rc;
+}
+
+static int guest_afu_cr_read8(struct cxl_afu *afu, int cr_idx, u64 offset,
+			u8 *out)
+{
+	int rc;
+	u64 val;
+
+	rc = _guest_afu_cr_readXX(1, afu, cr_idx, offset, &val);
+	if (!rc)
+		*out = (u8) val;
+	return rc;
+}
+
+static int guest_afu_cr_read64(struct cxl_afu *afu, int cr_idx, u64 offset,
+			u64 *out)
+{
+	return _guest_afu_cr_readXX(8, afu, cr_idx, offset, out);
+}
+
+static int guest_afu_cr_write32(struct cxl_afu *afu, int cr, u64 off, u32 in)
+{
+	/* config record is not writable from guest */
+	return -EPERM;
+}
+
+static int guest_afu_cr_write16(struct cxl_afu *afu, int cr, u64 off, u16 in)
+{
+	/* config record is not writable from guest */
+	return -EPERM;
+}
+
+static int guest_afu_cr_write8(struct cxl_afu *afu, int cr, u64 off, u8 in)
+{
+	/* config record is not writable from guest */
+	return -EPERM;
+}
+
+static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr)
+{
+	struct cxl_process_element_hcall *elem;
+	struct cxl *adapter = ctx->afu->adapter;
+	const struct cred *cred;
+	u32 pid, idx;
+	int rc, r, i;
+	u64 mmio_addr, mmio_size;
+	__be64 flags = 0;
+
+	/* Must be 8 byte aligned and cannot cross a 4096 byte boundary */
+	if (!(elem = (struct cxl_process_element_hcall *)
+			get_zeroed_page(GFP_KERNEL)))
+		return -ENOMEM;
+
+	elem->version = cpu_to_be64(CXL_PROCESS_ELEMENT_VERSION);
+	if (ctx->kernel) {
+		pid = 0;
+		flags |= CXL_PE_TRANSLATION_ENABLED;
+		flags |= CXL_PE_PRIVILEGED_PROCESS;
+		if (mfmsr() & MSR_SF)
+			flags |= CXL_PE_64_BIT;
+	} else {
+		pid = current->pid;
+		flags |= CXL_PE_PROBLEM_STATE;
+		flags |= CXL_PE_TRANSLATION_ENABLED;
+		if (!test_tsk_thread_flag(current, TIF_32BIT))
+			flags |= CXL_PE_64_BIT;
+		cred = get_current_cred();
+		if (uid_eq(cred->euid, GLOBAL_ROOT_UID))
+			flags |= CXL_PE_PRIVILEGED_PROCESS;
+		put_cred(cred);
+	}
+	elem->flags         = cpu_to_be64(flags);
+	elem->common.tid    = cpu_to_be32(0); /* Unused */
+	elem->common.pid    = cpu_to_be32(pid);
+	elem->common.csrp   = cpu_to_be64(0); /* disable */
+	elem->common.aurp0  = cpu_to_be64(0); /* disable */
+	elem->common.aurp1  = cpu_to_be64(0); /* disable */
+
+	cxl_prefault(ctx, wed);
+
+	elem->common.sstp0  = cpu_to_be64(ctx->sstp0);
+	elem->common.sstp1  = cpu_to_be64(ctx->sstp1);
+	for (r = 0; r < CXL_IRQ_RANGES; r++) {
+		for (i = 0; i < ctx->irqs.range[r]; i++) {
+			if (r == 0 && i == 0) {
+				elem->pslVirtualIsn = cpu_to_be32(ctx->irqs.offset[0]);
+			} else {
+				idx = ctx->irqs.offset[r] + i - adapter->guest->irq_base_offset;
+				elem->applicationVirtualIsnBitmap[idx / 8] |= 0x80 >> (idx % 8);
+			}
+		}
+	}
+	elem->common.amr = cpu_to_be64(amr);
+	elem->common.wed = cpu_to_be64(wed);
+
+	disable_afu_irqs(ctx);
+
+	rc = cxl_h_attach_process(ctx->afu->guest->handle, elem,
+				&ctx->process_token, &mmio_addr, &mmio_size);
+	if (rc == H_SUCCESS) {
+		if (ctx->master || !ctx->afu->pp_psa) {
+			ctx->psn_phys = ctx->afu->psn_phys;
+			ctx->psn_size = ctx->afu->adapter->ps_size;
+		} else {
+			ctx->psn_phys = mmio_addr;
+			ctx->psn_size = mmio_size;
+		}
+		if (ctx->afu->pp_psa && mmio_size &&
+			ctx->afu->pp_size == 0) {
+			/*
+			 * There's no property in the device tree to read the
+			 * pp_size. We only find out at the 1st attach.
+			 * Compared to bare-metal, it is too late and we
+			 * should really lock here. However, on powerVM,
+			 * pp_size is really only used to display in /sys.
+			 * Being discussed with pHyp for their next release.
+			 */
+			ctx->afu->pp_size = mmio_size;
+		}
+		/* from PAPR: process element is bytes 4-7 of process token */
+		ctx->external_pe = ctx->process_token & 0xFFFFFFFF;
+		pr_devel("CXL pe=%i is known as %i for pHyp, mmio_size=%#llx",
+			ctx->pe, ctx->external_pe, ctx->psn_size);
+		ctx->pe_inserted = true;
+		enable_afu_irqs(ctx);
+	}
+
+	free_page((u64)elem);
+	return rc;
+}
+
+static int guest_attach_process(struct cxl_context *ctx, bool kernel, u64 wed, u64 amr)
+{
+	pr_devel("in %s\n", __func__);
+
+	ctx->kernel = kernel;
+	if (ctx->afu->current_mode == CXL_MODE_DIRECTED)
+		return attach_afu_directed(ctx, wed, amr);
+
+	/* dedicated mode not supported on FW840 */
+
+	return -EINVAL;
+}
+
+static int detach_afu_directed(struct cxl_context *ctx)
+{
+	if (!ctx->pe_inserted)
+		return 0;
+	if (cxl_h_detach_process(ctx->afu->guest->handle, ctx->process_token))
+		return -1;
+	return 0;
+}
+
+static int guest_detach_process(struct cxl_context *ctx)
+{
+	pr_devel("in %s\n", __func__);
+	trace_cxl_detach(ctx);
+
+	if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu))
+		return -EIO;
+
+	if (ctx->afu->current_mode == CXL_MODE_DIRECTED)
+		return detach_afu_directed(ctx);
+
+	return -EINVAL;
+}
+
+static void guest_release_afu(struct device *dev)
+{
+	struct cxl_afu *afu = to_cxl_afu(dev);
+
+	pr_devel("%s\n", __func__);
+
+	idr_destroy(&afu->contexts_idr);
+
+	kfree(afu->guest);
+	kfree(afu);
+}
+
+ssize_t cxl_guest_read_afu_vpd(struct cxl_afu *afu, void *buf, size_t len)
+{
+	return guest_collect_vpd(NULL, afu, buf, len);
+}
+
+#define ERR_BUFF_MAX_COPY_SIZE PAGE_SIZE
+static ssize_t guest_afu_read_err_buffer(struct cxl_afu *afu, char *buf,
+					loff_t off, size_t count)
+{
+	void *tbuf = NULL;
+	int rc = 0;
+
+	tbuf = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!tbuf)
+		return -ENOMEM;
+
+	rc = cxl_h_get_afu_err(afu->guest->handle,
+			       off & 0x7,
+			       virt_to_phys(tbuf),
+			       count);
+	if (rc)
+		goto err;
+
+	if (count > ERR_BUFF_MAX_COPY_SIZE)
+		count = ERR_BUFF_MAX_COPY_SIZE - (off & 0x7);
+	memcpy(buf, tbuf, count);
+err:
+	free_page((u64)tbuf);
+
+	return rc;
+}
+
+static int guest_afu_check_and_enable(struct cxl_afu *afu)
+{
+	return 0;
+}
+
+static bool guest_support_attributes(const char *attr_name,
+				     enum cxl_attrs type)
+{
+	switch (type) {
+	case CXL_ADAPTER_ATTRS:
+		if ((strcmp(attr_name, "base_image") == 0) ||
+			(strcmp(attr_name, "load_image_on_perst") == 0) ||
+			(strcmp(attr_name, "perst_reloads_same_image") == 0) ||
+			(strcmp(attr_name, "image_loaded") == 0))
+			return false;
+		break;
+	case CXL_AFU_MASTER_ATTRS:
+		if ((strcmp(attr_name, "pp_mmio_off") == 0))
+			return false;
+		break;
+	case CXL_AFU_ATTRS:
+		break;
+	default:
+		break;
+	}
+
+	return true;
+}
+
+static int activate_afu_directed(struct cxl_afu *afu)
+{
+	int rc;
+
+	dev_info(&afu->dev, "Activating AFU(%d) directed mode\n", afu->slice);
+
+	afu->current_mode = CXL_MODE_DIRECTED;
+
+	afu->num_procs = afu->max_procs_virtualised;
+
+	if ((rc = cxl_chardev_m_afu_add(afu)))
+		return rc;
+
+	if ((rc = cxl_sysfs_afu_m_add(afu)))
+		goto err;
+
+	if ((rc = cxl_chardev_s_afu_add(afu)))
+		goto err1;
+
+	return 0;
+err1:
+	cxl_sysfs_afu_m_remove(afu);
+err:
+	cxl_chardev_afu_remove(afu);
+	return rc;
+}
+
+static int guest_afu_activate_mode(struct cxl_afu *afu, int mode)
+{
+	if (!mode)
+		return 0;
+	if (!(mode & afu->modes_supported))
+		return -EINVAL;
+
+	if (mode == CXL_MODE_DIRECTED)
+		return activate_afu_directed(afu);
+
+	if (mode == CXL_MODE_DEDICATED)
+		dev_err(&afu->dev, "Dedicated mode not supported\n");
+
+	return -EINVAL;
+}
+
+static int deactivate_afu_directed(struct cxl_afu *afu)
+{
+	dev_info(&afu->dev, "Deactivating AFU(%d) directed mode\n", afu->slice);
+
+	afu->current_mode = 0;
+	afu->num_procs = 0;
+
+	cxl_sysfs_afu_m_remove(afu);
+	cxl_chardev_afu_remove(afu);
+
+	cxl_ops->afu_reset(afu);
+
+	return 0;
+}
+
+static int guest_afu_deactivate_mode(struct cxl_afu *afu, int mode)
+{
+	if (!mode)
+		return 0;
+	if (!(mode & afu->modes_supported))
+		return -EINVAL;
+
+	if (mode == CXL_MODE_DIRECTED)
+		return deactivate_afu_directed(afu);
+	return 0;
+}
+
+static int guest_afu_reset(struct cxl_afu *afu)
+{
+	pr_devel("AFU(%d) reset request\n", afu->slice);
+	return cxl_h_reset_afu(afu->guest->handle);
+}
+
+static int guest_map_slice_regs(struct cxl_afu *afu)
+{
+	if (!(afu->p2n_mmio = ioremap(afu->guest->p2n_phys, afu->guest->p2n_size))) {
+		dev_err(&afu->dev, "Error mapping AFU(%d) MMIO regions\n",
+			afu->slice);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void guest_unmap_slice_regs(struct cxl_afu *afu)
+{
+	if (afu->p2n_mmio)
+		iounmap(afu->p2n_mmio);
+}
+
+static int afu_update_state(struct cxl_afu *afu)
+{
+	int rc, cur_state;
+
+	rc = afu_read_error_state(afu, &cur_state);
+	if (rc)
+		return rc;
+
+	if (afu->guest->previous_state == cur_state)
+		return 0;
+
+	pr_devel("AFU(%d) update state to %#x\n", afu->slice, cur_state);
+
+	switch (cur_state) {
+	case H_STATE_NORMAL:
+		afu->guest->previous_state = cur_state;
+		rc = 1;
+		break;
+
+	case H_STATE_DISABLE:
+		pci_error_handlers(afu, CXL_ERROR_DETECTED_EVENT,
+				pci_channel_io_frozen);
+
+		cxl_context_detach_all(afu);
+		if ((rc = cxl_ops->afu_reset(afu)))
+			pr_devel("reset hcall failed %d\n", rc);
+
+		rc = afu_read_error_state(afu, &cur_state);
+		if (!rc && cur_state == H_STATE_NORMAL) {
+			pci_error_handlers(afu, CXL_SLOT_RESET_EVENT,
+					pci_channel_io_normal);
+			pci_error_handlers(afu, CXL_RESUME_EVENT, 0);
+			rc = 1;
+		}
+		afu->guest->previous_state = 0;
+		break;
+
+	case H_STATE_TEMP_UNAVAILABLE:
+		afu->guest->previous_state = cur_state;
+		break;
+
+	case H_STATE_PERM_UNAVAILABLE:
+		dev_err(&afu->dev, "AFU is in permanent error state\n");
+		pci_error_handlers(afu, CXL_ERROR_DETECTED_EVENT,
+				pci_channel_io_perm_failure);
+		afu->guest->previous_state = cur_state;
+		break;
+
+	default:
+		pr_err("Unexpected AFU(%d) error state: %#x\n",
+		       afu->slice, cur_state);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int afu_do_recovery(struct cxl_afu *afu)
+{
+	int rc;
+
+	/* many threads can arrive here, in case of detach_all for example.
+	 * Only one needs to drive the recovery
+	 */
+	if (mutex_trylock(&afu->guest->recovery_lock)) {
+		rc = afu_update_state(afu);
+		mutex_unlock(&afu->guest->recovery_lock);
+		return rc;
+	}
+	return 0;
+}
+
+static bool guest_link_ok(struct cxl *cxl, struct cxl_afu *afu)
+{
+	int state;
+
+	if (afu) {
+		if (afu_read_error_state(afu, &state) ||
+			state != H_STATE_NORMAL) {
+			if (afu_do_recovery(afu) > 0) {
+				/* check again in case we've just fixed it */
+				if (!afu_read_error_state(afu, &state) &&
+					state == H_STATE_NORMAL)
+					return true;
+			}
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static int afu_properties_look_ok(struct cxl_afu *afu)
+{
+	if (afu->pp_irqs < 0) {
+		dev_err(&afu->dev, "Unexpected per-process minimum interrupt value\n");
+		return -EINVAL;
+	}
+
+	if (afu->max_procs_virtualised < 1) {
+		dev_err(&afu->dev, "Unexpected max number of processes virtualised value\n");
+		return -EINVAL;
+	}
+
+	if (afu->crs_len < 0) {
+		dev_err(&afu->dev, "Unexpected configuration record size value\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int cxl_guest_init_afu(struct cxl *adapter, int slice, struct device_node *afu_np)
+{
+	struct cxl_afu *afu;
+	bool free = true;
+	int rc;
+
+	pr_devel("in %s - AFU(%d)\n", __func__, slice);
+	if (!(afu = cxl_alloc_afu(adapter, slice)))
+		return -ENOMEM;
+
+	if (!(afu->guest = kzalloc(sizeof(struct cxl_afu_guest), GFP_KERNEL))) {
+		kfree(afu);
+		return -ENOMEM;
+	}
+
+	mutex_init(&afu->guest->recovery_lock);
+
+	if ((rc = dev_set_name(&afu->dev, "afu%i.%i",
+					  adapter->adapter_num,
+					  slice)))
+		goto err1;
+
+	adapter->slices++;
+
+	if ((rc = cxl_of_read_afu_handle(afu, afu_np)))
+		goto err1;
+
+	if ((rc = cxl_ops->afu_reset(afu)))
+		goto err1;
+
+	if ((rc = cxl_of_read_afu_properties(afu, afu_np)))
+		goto err1;
+
+	if ((rc = afu_properties_look_ok(afu)))
+		goto err1;
+
+	if ((rc = guest_map_slice_regs(afu)))
+		goto err1;
+
+	if ((rc = guest_register_serr_irq(afu)))
+		goto err2;
+
+	/*
+	 * After we call this function we must not free the afu directly, even
+	 * if it returns an error!
+	 */
+	if ((rc = cxl_register_afu(afu)))
+		goto err_put1;
+
+	if ((rc = cxl_sysfs_afu_add(afu)))
+		goto err_put1;
+
+	/*
+	 * pHyp doesn't expose the programming models supported by the
+	 * AFU. pHyp currently only supports directed mode. If it adds
+	 * dedicated mode later, this version of cxl has no way to
+	 * detect it. So we'll initialize the driver, but the first
+	 * attach will fail.
+	 * Being discussed with pHyp to do better (likely new property)
+	 */
+	if (afu->max_procs_virtualised == 1)
+		afu->modes_supported = CXL_MODE_DEDICATED;
+	else
+		afu->modes_supported = CXL_MODE_DIRECTED;
+
+	if ((rc = cxl_afu_select_best_mode(afu)))
+		goto err_put2;
+
+	adapter->afu[afu->slice] = afu;
+
+	afu->enabled = true;
+
+	if ((rc = cxl_pci_vphb_add(afu)))
+		dev_info(&afu->dev, "Can't register vPHB\n");
+
+	return 0;
+
+err_put2:
+	cxl_sysfs_afu_remove(afu);
+err_put1:
+	device_unregister(&afu->dev);
+	free = false;
+	guest_release_serr_irq(afu);
+err2:
+	guest_unmap_slice_regs(afu);
+err1:
+	if (free) {
+		kfree(afu->guest);
+		kfree(afu);
+	}
+	return rc;
+}
+
+void cxl_guest_remove_afu(struct cxl_afu *afu)
+{
+	pr_devel("in %s - AFU(%d)\n", __func__, afu->slice);
+
+	if (!afu)
+		return;
+
+	cxl_pci_vphb_remove(afu);
+	cxl_sysfs_afu_remove(afu);
+
+	spin_lock(&afu->adapter->afu_list_lock);
+	afu->adapter->afu[afu->slice] = NULL;
+	spin_unlock(&afu->adapter->afu_list_lock);
+
+	cxl_context_detach_all(afu);
+	cxl_ops->afu_deactivate_mode(afu, afu->current_mode);
+	guest_release_serr_irq(afu);
+	guest_unmap_slice_regs(afu);
+
+	device_unregister(&afu->dev);
+}
+
+static void free_adapter(struct cxl *adapter)
+{
+	struct irq_avail *cur;
+	int i;
+
+	if (adapter->guest->irq_avail) {
+		for (i = 0; i < adapter->guest->irq_nranges; i++) {
+			cur = &adapter->guest->irq_avail[i];
+			kfree(cur->bitmap);
+		}
+		kfree(adapter->guest->irq_avail);
+	}
+	kfree(adapter->guest->status);
+	cxl_remove_adapter_nr(adapter);
+	kfree(adapter->guest);
+	kfree(adapter);
+}
+
+static int properties_look_ok(struct cxl *adapter)
+{
+	/* The absence of this property means that the operational
+	 * status is unknown or okay
+	 */
+	if (strlen(adapter->guest->status) &&
+	    strcmp(adapter->guest->status, "okay")) {
+		pr_err("ABORTING:Bad operational status of the device\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+ssize_t cxl_guest_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len)
+{
+	return guest_collect_vpd(adapter, NULL, buf, len);
+}
+
+void cxl_guest_remove_adapter(struct cxl *adapter)
+{
+	pr_devel("in %s\n", __func__);
+
+	cxl_sysfs_adapter_remove(adapter);
+
+	cxl_guest_remove_chardev(adapter);
+	device_unregister(&adapter->dev);
+}
+
+static void release_adapter(struct device *dev)
+{
+	free_adapter(to_cxl_adapter(dev));
+}
+
+struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_device *pdev)
+{
+	struct cxl *adapter;
+	bool free = true;
+	int rc;
+
+	if (!(adapter = cxl_alloc_adapter()))
+		return ERR_PTR(-ENOMEM);
+
+	if (!(adapter->guest = kzalloc(sizeof(struct cxl_guest), GFP_KERNEL))) {
+		free_adapter(adapter);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	adapter->slices = 0;
+	adapter->guest->pdev = pdev;
+	adapter->dev.parent = &pdev->dev;
+	adapter->dev.release = release_adapter;
+	dev_set_drvdata(&pdev->dev, adapter);
+
+	if ((rc = cxl_of_read_adapter_handle(adapter, np)))
+		goto err1;
+
+	if ((rc = cxl_of_read_adapter_properties(adapter, np)))
+		goto err1;
+
+	if ((rc = properties_look_ok(adapter)))
+		goto err1;
+
+	if ((rc = cxl_guest_add_chardev(adapter)))
+		goto err1;
+
+	/*
+	 * After we call this function we must not free the adapter directly,
+	 * even if it returns an error!
+	 */
+	if ((rc = cxl_register_adapter(adapter)))
+		goto err_put1;
+
+	if ((rc = cxl_sysfs_adapter_add(adapter)))
+		goto err_put1;
+
+	return adapter;
+
+err_put1:
+	device_unregister(&adapter->dev);
+	free = false;
+	cxl_guest_remove_chardev(adapter);
+err1:
+	if (free)
+		free_adapter(adapter);
+	return ERR_PTR(rc);
+}
+
+void cxl_guest_reload_module(struct cxl *adapter)
+{
+	struct platform_device *pdev;
+
+	pdev = adapter->guest->pdev;
+	cxl_guest_remove_adapter(adapter);
+
+	cxl_of_probe(pdev);
+}
+
+const struct cxl_backend_ops cxl_guest_ops = {
+	.module = THIS_MODULE,
+	.adapter_reset = guest_reset,
+	.alloc_one_irq = guest_alloc_one_irq,
+	.release_one_irq = guest_release_one_irq,
+	.alloc_irq_ranges = guest_alloc_irq_ranges,
+	.release_irq_ranges = guest_release_irq_ranges,
+	.setup_irq = NULL,
+	.handle_psl_slice_error = guest_handle_psl_slice_error,
+	.psl_interrupt = guest_psl_irq,
+	.ack_irq = guest_ack_irq,
+	.attach_process = guest_attach_process,
+	.detach_process = guest_detach_process,
+	.support_attributes = guest_support_attributes,
+	.link_ok = guest_link_ok,
+	.release_afu = guest_release_afu,
+	.afu_read_err_buffer = guest_afu_read_err_buffer,
+	.afu_check_and_enable = guest_afu_check_and_enable,
+	.afu_activate_mode = guest_afu_activate_mode,
+	.afu_deactivate_mode = guest_afu_deactivate_mode,
+	.afu_reset = guest_afu_reset,
+	.afu_cr_read8 = guest_afu_cr_read8,
+	.afu_cr_read16 = guest_afu_cr_read16,
+	.afu_cr_read32 = guest_afu_cr_read32,
+	.afu_cr_read64 = guest_afu_cr_read64,
+	.afu_cr_write8 = guest_afu_cr_write8,
+	.afu_cr_write16 = guest_afu_cr_write16,
+	.afu_cr_write32 = guest_afu_cr_write32,
+	.read_adapter_vpd = cxl_guest_read_adapter_vpd,
+};
--- linux-4.4.0.orig/drivers/misc/cxl/hcalls.c
+++ linux-4.4.0/drivers/misc/cxl/hcalls.c
@@ -0,0 +1,647 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include "hcalls.h"
+#include "trace.h"
+
+#define CXL_HCALL_TIMEOUT 60000
+#define CXL_HCALL_TIMEOUT_DOWNLOAD 120000
+
+#define H_ATTACH_CA_PROCESS    0x344
+#define H_CONTROL_CA_FUNCTION  0x348
+#define H_DETACH_CA_PROCESS    0x34C
+#define H_COLLECT_CA_INT_INFO  0x350
+#define H_CONTROL_CA_FAULTS    0x354
+#define H_DOWNLOAD_CA_FUNCTION 0x35C
+#define H_DOWNLOAD_CA_FACILITY 0x364
+#define H_CONTROL_CA_FACILITY  0x368
+
+#define H_CONTROL_CA_FUNCTION_RESET                   1 /* perform a reset */
+#define H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS         2 /* suspend a process from being executed */
+#define H_CONTROL_CA_FUNCTION_RESUME_PROCESS          3 /* resume a process to be executed */
+#define H_CONTROL_CA_FUNCTION_READ_ERR_STATE          4 /* read the error state */
+#define H_CONTROL_CA_FUNCTION_GET_AFU_ERR             5 /* collect the AFU error buffer */
+#define H_CONTROL_CA_FUNCTION_GET_CONFIG              6 /* collect configuration record */
+#define H_CONTROL_CA_FUNCTION_GET_DOWNLOAD_STATE      7 /* query to return download status */
+#define H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS       8 /* terminate the process before completion */
+#define H_CONTROL_CA_FUNCTION_COLLECT_VPD             9 /* collect VPD */
+#define H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT   11 /* read the function-wide error data based on an interrupt */
+#define H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT   12 /* acknowledge function-wide error data based on an interrupt */
+#define H_CONTROL_CA_FUNCTION_GET_ERROR_LOG          13 /* retrieve the Platform Log ID (PLID) of an error log */
+
+#define H_CONTROL_CA_FAULTS_RESPOND_PSL         1
+#define H_CONTROL_CA_FAULTS_RESPOND_AFU         2
+
+#define H_CONTROL_CA_FACILITY_RESET             1 /* perform a reset */
+#define H_CONTROL_CA_FACILITY_COLLECT_VPD       2 /* collect VPD */
+
+#define H_DOWNLOAD_CA_FACILITY_DOWNLOAD         1 /* download adapter image */
+#define H_DOWNLOAD_CA_FACILITY_VALIDATE         2 /* validate adapter image */
+
+
+#define _CXL_LOOP_HCALL(call, rc, retbuf, fn, ...)			\
+	{								\
+		unsigned int delay, total_delay = 0;			\
+		u64 token = 0;						\
+									\
+		memset(retbuf, 0, sizeof(retbuf));			\
+		while (1) {						\
+			rc = call(fn, retbuf, __VA_ARGS__, token);	\
+			token = retbuf[0];				\
+			if (rc != H_BUSY && !H_IS_LONG_BUSY(rc))	\
+				break;					\
+									\
+			if (rc == H_BUSY)				\
+				delay = 10;				\
+			else						\
+				delay = get_longbusy_msecs(rc);		\
+									\
+			total_delay += delay;				\
+			if (total_delay > CXL_HCALL_TIMEOUT) {		\
+				WARN(1, "Warning: Giving up waiting for CXL hcall " \
+					"%#x after %u msec\n", fn, total_delay); \
+				rc = H_BUSY;				\
+				break;					\
+			}						\
+			msleep(delay);					\
+		}							\
+	}
+#define CXL_H_WAIT_UNTIL_DONE(...)  _CXL_LOOP_HCALL(plpar_hcall, __VA_ARGS__)
+#define CXL_H9_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall9, __VA_ARGS__)
+
+#define _PRINT_MSG(rc, format, ...)					\
+	{								\
+		if ((rc != H_SUCCESS) && (rc != H_CONTINUE))		\
+			pr_err(format, __VA_ARGS__);			\
+		else							\
+			pr_devel(format, __VA_ARGS__);			\
+	}								\
+
+
+static char *afu_op_names[] = {
+	"UNKNOWN_OP",		/* 0 undefined */
+	"RESET",		/* 1 */
+	"SUSPEND_PROCESS",	/* 2 */
+	"RESUME_PROCESS",	/* 3 */
+	"READ_ERR_STATE",	/* 4 */
+	"GET_AFU_ERR",		/* 5 */
+	"GET_CONFIG",		/* 6 */
+	"GET_DOWNLOAD_STATE",	/* 7 */
+	"TERMINATE_PROCESS",	/* 8 */
+	"COLLECT_VPD",		/* 9 */
+	"UNKNOWN_OP",		/* 10 undefined */
+	"GET_FUNCTION_ERR_INT",	/* 11 */
+	"ACK_FUNCTION_ERR_INT",	/* 12 */
+	"GET_ERROR_LOG",	/* 13 */
+};
+
+static char *control_adapter_op_names[] = {
+	"UNKNOWN_OP",		/* 0 undefined */
+	"RESET",		/* 1 */
+	"COLLECT_VPD",		/* 2 */
+};
+
+static char *download_op_names[] = {
+	"UNKNOWN_OP",		/* 0 undefined */
+	"DOWNLOAD",		/* 1 */
+	"VALIDATE",		/* 2 */
+};
+
+static char *op_str(unsigned int op, char *name_array[], int array_len)
+{
+	if (op >= array_len)
+		return "UNKNOWN_OP";
+	return name_array[op];
+}
+
+#define OP_STR(op, name_array)      op_str(op, name_array, ARRAY_SIZE(name_array))
+
+#define OP_STR_AFU(op)              OP_STR(op, afu_op_names)
+#define OP_STR_CONTROL_ADAPTER(op)  OP_STR(op, control_adapter_op_names)
+#define OP_STR_DOWNLOAD_ADAPTER(op) OP_STR(op, download_op_names)
+
+
+long cxl_h_attach_process(u64 unit_address,
+			struct cxl_process_element_hcall *element,
+			u64 *process_token, u64 *mmio_addr, u64 *mmio_size)
+{
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+	long rc;
+
+	CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_ATTACH_CA_PROCESS, unit_address, virt_to_phys(element));
+	_PRINT_MSG(rc, "cxl_h_attach_process(%#.16llx, %#.16lx): %li\n",
+		unit_address, virt_to_phys(element), rc);
+	trace_cxl_hcall_attach(unit_address, virt_to_phys(element), retbuf[0], retbuf[1], retbuf[2], rc);
+
+	pr_devel("token: 0x%.8lx mmio_addr: 0x%lx mmio_size: 0x%lx\nProcess Element Structure:\n",
+		retbuf[0], retbuf[1], retbuf[2]);
+	cxl_dump_debug_buffer(element, sizeof(*element));
+
+	switch (rc) {
+	case H_SUCCESS:       /* The process info is attached to the coherent platform function */
+		*process_token = retbuf[0];
+		if (mmio_addr)
+			*mmio_addr = retbuf[1];
+		if (mmio_size)
+			*mmio_size = retbuf[2];
+		return 0;
+	case H_PARAMETER:     /* An incorrect parameter was supplied. */
+	case H_FUNCTION:      /* The function is not supported. */
+		return -EINVAL;
+	case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
+	case H_RESOURCE:      /* The coherent platform function does not have enough additional resource to attach the process */
+	case H_HARDWARE:      /* A hardware event prevented the attach operation */
+	case H_STATE:         /* The coherent platform function is not in a valid state */
+	case H_BUSY:
+		return -EBUSY;
+	default:
+		WARN(1, "Unexpected return code: %lx", rc);
+		return -EINVAL;
+	}
+}
+
+/**
+ * cxl_h_detach_process - Detach a process element from a coherent
+ *                        platform function.
+ */
+long cxl_h_detach_process(u64 unit_address, u64 process_token)
+{
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+	long rc;
+
+	CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_DETACH_CA_PROCESS, unit_address, process_token);
+	_PRINT_MSG(rc, "cxl_h_detach_process(%#.16llx, 0x%.8llx): %li\n", unit_address, process_token, rc);
+	trace_cxl_hcall_detach(unit_address, process_token, rc);
+
+	switch (rc) {
+	case H_SUCCESS:       /* The process was detached from the coherent platform function */
+		return 0;
+	case H_PARAMETER:     /* An incorrect parameter was supplied. */
+		return -EINVAL;
+	case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
+	case H_RESOURCE:      /* The function has page table mappings for MMIO */
+	case H_HARDWARE:      /* A hardware event prevented the detach operation */
+	case H_STATE:         /* The coherent platform function is not in a valid state */
+	case H_BUSY:
+		return -EBUSY;
+	default:
+		WARN(1, "Unexpected return code: %lx", rc);
+		return -EINVAL;
+	}
+}
+
+/**
+ * cxl_h_control_function - This H_CONTROL_CA_FUNCTION hypervisor call allows
+ *                          the partition to manipulate or query
+ *                          certain coherent platform function behaviors.
+ */
+static long cxl_h_control_function(u64 unit_address, u64 op,
+				   u64 p1, u64 p2, u64 p3, u64 p4, u64 *out)
+{
+	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+	long rc;
+
+	CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FUNCTION, unit_address, op, p1, p2, p3, p4);
+	_PRINT_MSG(rc, "cxl_h_control_function(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n",
+		unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc);
+	trace_cxl_hcall_control_function(unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc);
+
+	switch (rc) {
+	case H_SUCCESS:       /* The operation is completed for the coherent platform function */
+		if ((op == H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT ||
+		     op == H_CONTROL_CA_FUNCTION_READ_ERR_STATE ||
+		     op == H_CONTROL_CA_FUNCTION_COLLECT_VPD))
+			*out = retbuf[0];
+		return 0;
+	case H_PARAMETER:     /* An incorrect parameter was supplied. */
+	case H_FUNCTION:      /* The function is not supported. */
+	case H_NOT_FOUND:     /* The operation supplied was not valid */
+	case H_NOT_AVAILABLE: /* The operation cannot be performed because the AFU has not been downloaded */
+	case H_SG_LIST:       /* An block list entry was invalid */
+		return -EINVAL;
+	case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
+	case H_RESOURCE:      /* The function has page table mappings for MMIO */
+	case H_HARDWARE:      /* A hardware event prevented the attach operation */
+	case H_STATE:         /* The coherent platform function is not in a valid state */
+	case H_BUSY:
+		return -EBUSY;
+	default:
+		WARN(1, "Unexpected return code: %lx", rc);
+		return -EINVAL;
+	}
+}
+
+/**
+ * cxl_h_reset_afu - Perform a reset to the coherent platform function.
+ */
+long cxl_h_reset_afu(u64 unit_address)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_RESET,
+				0, 0, 0, 0,
+				NULL);
+}
+
+/**
+ * cxl_h_suspend_process - Suspend a process from being executed
+ * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
+ *              process was attached.
+ */
+long cxl_h_suspend_process(u64 unit_address, u64 process_token)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS,
+				process_token, 0, 0, 0,
+				NULL);
+}
+
+/**
+ * cxl_h_resume_process - Resume a process to be executed
+ * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
+ *              process was attached.
+ */
+long cxl_h_resume_process(u64 unit_address, u64 process_token)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_RESUME_PROCESS,
+				process_token, 0, 0, 0,
+				NULL);
+}
+
+/**
+ * cxl_h_read_error_state - Checks the error state of the coherent
+ *                          platform function.
+ * R4 contains the error state
+ */
+long cxl_h_read_error_state(u64 unit_address, u64 *state)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_READ_ERR_STATE,
+				0, 0, 0, 0,
+				state);
+}
+
+/**
+ * cxl_h_get_afu_err - collect the AFU error buffer
+ * Parameter1 = byte offset into error buffer to retrieve, valid values
+ *              are between 0 and (ibm,error-buffer-size - 1)
+ * Parameter2 = 4K aligned real address of error buffer, to be filled in
+ * Parameter3 = length of error buffer, valid values are 4K or less
+ */
+long cxl_h_get_afu_err(u64 unit_address, u64 offset,
+		u64 buf_address, u64 len)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_GET_AFU_ERR,
+				offset, buf_address, len, 0,
+				NULL);
+}
+
+/**
+ * cxl_h_get_config - collect configuration record for the
+ *                    coherent platform function
+ * Parameter1 = # of configuration record to retrieve, valid values are
+ *              between 0 and (ibm,#config-records - 1)
+ * Parameter2 = byte offset into configuration record to retrieve,
+ *              valid values are between 0 and (ibm,config-record-size - 1)
+ * Parameter3 = 4K aligned real address of configuration record buffer,
+ *              to be filled in
+ * Parameter4 = length of configuration buffer, valid values are 4K or less
+ */
+long cxl_h_get_config(u64 unit_address, u64 cr_num, u64 offset,
+		u64 buf_address, u64 len)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_GET_CONFIG,
+				cr_num, offset, buf_address, len,
+				NULL);
+}
+
+/**
+ * cxl_h_terminate_process - Terminate the process before completion
+ * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
+ *              process was attached.
+ */
+long cxl_h_terminate_process(u64 unit_address, u64 process_token)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS,
+				process_token, 0, 0, 0,
+				NULL);
+}
+
+/**
+ * cxl_h_collect_vpd - Collect VPD for the coherent platform function.
+ * Parameter1 = # of VPD record to retrieve, valid values are between 0
+ *              and (ibm,#config-records - 1).
+ * Parameter2 = 4K naturally aligned real buffer containing block
+ *              list entries
+ * Parameter3 = number of block list entries in the block list, valid
+ *              values are between 0 and 256
+ */
+long cxl_h_collect_vpd(u64 unit_address, u64 record, u64 list_address,
+		       u64 num, u64 *out)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_COLLECT_VPD,
+				record, list_address, num, 0,
+				out);
+}
+
+/**
+ * cxl_h_get_fn_error_interrupt - Read the function-wide error data based on an interrupt
+ */
+long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT,
+				0, 0, 0, 0, reg);
+}
+
+/**
+ * cxl_h_ack_fn_error_interrupt - Acknowledge function-wide error data
+ *                                based on an interrupt
+ * Parameter1 = value to write to the function-wide error interrupt register
+ */
+long cxl_h_ack_fn_error_interrupt(u64 unit_address, u64 value)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT,
+				value, 0, 0, 0,
+				NULL);
+}
+
+/**
+ * cxl_h_get_error_log - Retrieve the Platform Log ID (PLID) of
+ *                       an error log
+ */
+long cxl_h_get_error_log(u64 unit_address, u64 value)
+{
+	return cxl_h_control_function(unit_address,
+				H_CONTROL_CA_FUNCTION_GET_ERROR_LOG,
+				0, 0, 0, 0,
+				NULL);
+}
+
+/**
+ * cxl_h_collect_int_info - Collect interrupt info about a coherent
+ *                          platform function after an interrupt occurred.
+ */
+long cxl_h_collect_int_info(u64 unit_address, u64 process_token,
+			    struct cxl_irq_info *info)
+{
+	long rc;
+
+	BUG_ON(sizeof(*info) != sizeof(unsigned long[PLPAR_HCALL9_BUFSIZE]));
+
+	rc = plpar_hcall9(H_COLLECT_CA_INT_INFO, (unsigned long *) info,
+			unit_address, process_token);
+	_PRINT_MSG(rc, "cxl_h_collect_int_info(%#.16llx, 0x%llx): %li\n",
+		unit_address, process_token, rc);
+	trace_cxl_hcall_collect_int_info(unit_address, process_token, rc);
+
+	switch (rc) {
+	case H_SUCCESS:     /* The interrupt info is returned in return registers. */
+		pr_devel("dsisr:%#llx, dar:%#llx, dsr:%#llx, pid:%u, tid:%u, afu_err:%#llx, errstat:%#llx\n",
+			info->dsisr, info->dar, info->dsr, info->pid,
+			info->tid, info->afu_err, info->errstat);
+		return 0;
+	case H_PARAMETER:   /* An incorrect parameter was supplied. */
+		return -EINVAL;
+	case H_AUTHORITY:   /* The partition does not have authority to perform this hcall. */
+	case H_HARDWARE:    /* A hardware event prevented the collection of the interrupt info.*/
+	case H_STATE:       /* The coherent platform function is not in a valid state to collect interrupt info. */
+		return -EBUSY;
+	default:
+		WARN(1, "Unexpected return code: %lx", rc);
+		return -EINVAL;
+	}
+}
+
+/**
+ * cxl_h_control_faults - Control the operation of a coherent platform
+ *                        function after a fault occurs.
+ *
+ * Parameters
+ *    control-mask: value to control the faults
+ *                  looks like PSL_TFC_An shifted >> 32
+ *    reset-mask: mask to control reset of function faults
+ *                Set reset_mask = 1 to reset PSL errors
+ */
+long cxl_h_control_faults(u64 unit_address, u64 process_token,
+			  u64 control_mask, u64 reset_mask)
+{
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+	long rc;
+
+	memset(retbuf, 0, sizeof(retbuf));
+
+	rc = plpar_hcall(H_CONTROL_CA_FAULTS, retbuf, unit_address,
+			H_CONTROL_CA_FAULTS_RESPOND_PSL, process_token,
+			control_mask, reset_mask);
+	_PRINT_MSG(rc, "cxl_h_control_faults(%#.16llx, 0x%llx, %#llx, %#llx): %li (%#lx)\n",
+		unit_address, process_token, control_mask, reset_mask,
+		rc, retbuf[0]);
+	trace_cxl_hcall_control_faults(unit_address, process_token,
+				control_mask, reset_mask, retbuf[0], rc);
+
+	switch (rc) {
+	case H_SUCCESS:    /* Faults were successfully controlled for the function. */
+		return 0;
+	case H_PARAMETER:  /* An incorrect parameter was supplied. */
+		return -EINVAL;
+	case H_HARDWARE:   /* A hardware event prevented the control of faults. */
+	case H_STATE:      /* The function was in an invalid state. */
+	case H_AUTHORITY:  /* The partition does not have authority to perform this hcall; the coherent platform facilities may need to be licensed. */
+		return -EBUSY;
+	case H_FUNCTION:   /* The function is not supported */
+	case H_NOT_FOUND:  /* The operation supplied was not valid */
+		return -EINVAL;
+	default:
+		WARN(1, "Unexpected return code: %lx", rc);
+		return -EINVAL;
+	}
+}
+
+/**
+ * cxl_h_control_facility - This H_CONTROL_CA_FACILITY hypervisor call
+ *                          allows the partition to manipulate or query
+ *                          certain coherent platform facility behaviors.
+ */
+static long cxl_h_control_facility(u64 unit_address, u64 op,
+				   u64 p1, u64 p2, u64 p3, u64 p4, u64 *out)
+{
+	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+	long rc;
+
+	CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FACILITY, unit_address, op, p1, p2, p3, p4);
+	_PRINT_MSG(rc, "cxl_h_control_facility(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n",
+		unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc);
+	trace_cxl_hcall_control_facility(unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc);
+
+	switch (rc) {
+	case H_SUCCESS:       /* The operation is completed for the coherent platform facility */
+		if (op == H_CONTROL_CA_FACILITY_COLLECT_VPD)
+			*out = retbuf[0];
+		return 0;
+	case H_PARAMETER:     /* An incorrect parameter was supplied. */
+	case H_FUNCTION:      /* The function is not supported. */
+	case H_NOT_FOUND:     /* The operation supplied was not valid */
+	case H_NOT_AVAILABLE: /* The operation cannot be performed because the AFU has not been downloaded */
+	case H_SG_LIST:       /* An block list entry was invalid */
+		return -EINVAL;
+	case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
+	case H_RESOURCE:      /* The function has page table mappings for MMIO */
+	case H_HARDWARE:      /* A hardware event prevented the attach operation */
+	case H_STATE:         /* The coherent platform facility is not in a valid state */
+	case H_BUSY:
+		return -EBUSY;
+	default:
+		WARN(1, "Unexpected return code: %lx", rc);
+		return -EINVAL;
+	}
+}
+
+/**
+ * cxl_h_reset_adapter - Perform a reset to the coherent platform facility.
+ */
+long cxl_h_reset_adapter(u64 unit_address)
+{
+	return cxl_h_control_facility(unit_address,
+				H_CONTROL_CA_FACILITY_RESET,
+				0, 0, 0, 0,
+				NULL);
+}
+
+/**
+ * cxl_h_collect_vpd - Collect VPD for the coherent platform function.
+ * Parameter1 = 4K naturally aligned real buffer containing block
+ *              list entries
+ * Parameter2 = number of block list entries in the block list, valid
+ *              values are between 0 and 256
+ */
+long cxl_h_collect_vpd_adapter(u64 unit_address, u64 list_address,
+			       u64 num, u64 *out)
+{
+	return cxl_h_control_facility(unit_address,
+				H_CONTROL_CA_FACILITY_COLLECT_VPD,
+				list_address, num, 0, 0,
+				out);
+}
+
+/**
+ * cxl_h_download_facility - This H_DOWNLOAD_CA_FACILITY
+ *                    hypervisor call provide platform support for
+ *                    downloading a base adapter image to the coherent
+ *                    platform facility, and for validating the entire
+ *                    image after the download.
+ * Parameters
+ *    op: operation to perform to the coherent platform function
+ *      Download: operation = 1, the base image in the coherent platform
+ *                               facility is first erased, and then
+ *                               programmed using the image supplied
+ *                               in the scatter/gather list.
+ *      Validate: operation = 2, the base image in the coherent platform
+ *                               facility is compared with the image
+ *                               supplied in the scatter/gather list.
+ *    list_address: 4K naturally aligned real buffer containing
+ *                  scatter/gather list entries.
+ *    num: number of block list entries in the scatter/gather list.
+ */
+static long cxl_h_download_facility(u64 unit_address, u64 op,
+				    u64 list_address, u64 num,
+				    u64 *out)
+{
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+	unsigned int delay, total_delay = 0;
+	u64 token = 0;
+	long rc;
+
+	if (*out != 0)
+		token = *out;
+
+	memset(retbuf, 0, sizeof(retbuf));
+	while (1) {
+		rc = plpar_hcall(H_DOWNLOAD_CA_FACILITY, retbuf,
+				 unit_address, op, list_address, num,
+				 token);
+		token = retbuf[0];
+		if (rc != H_BUSY && !H_IS_LONG_BUSY(rc))
+			break;
+
+		if (rc != H_BUSY) {
+			delay = get_longbusy_msecs(rc);
+			total_delay += delay;
+			if (total_delay > CXL_HCALL_TIMEOUT_DOWNLOAD) {
+				WARN(1, "Warning: Giving up waiting for CXL hcall "
+					"%#x after %u msec\n",
+					H_DOWNLOAD_CA_FACILITY, total_delay);
+				rc = H_BUSY;
+				break;
+			}
+			msleep(delay);
+		}
+	}
+	_PRINT_MSG(rc, "cxl_h_download_facility(%#.16llx, %s(%#llx, %#llx), %#lx): %li\n",
+		 unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc);
+	trace_cxl_hcall_download_facility(unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc);
+
+	switch (rc) {
+	case H_SUCCESS:       /* The operation is completed for the coherent platform facility */
+		return 0;
+	case H_PARAMETER:     /* An incorrect parameter was supplied */
+	case H_FUNCTION:      /* The function is not supported. */
+	case H_SG_LIST:       /* An block list entry was invalid */
+	case H_BAD_DATA:      /* Image verification failed */
+		return -EINVAL;
+	case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
+	case H_RESOURCE:      /* The function has page table mappings for MMIO */
+	case H_HARDWARE:      /* A hardware event prevented the attach operation */
+	case H_STATE:         /* The coherent platform facility is not in a valid state */
+	case H_BUSY:
+		return -EBUSY;
+	case H_CONTINUE:
+		*out = retbuf[0];
+		return 1;  /* More data is needed for the complete image */
+	default:
+		WARN(1, "Unexpected return code: %lx", rc);
+		return -EINVAL;
+	}
+}
+
+/**
+ * cxl_h_download_adapter_image - Download the base image to the coherent
+ *                                platform facility.
+ */
+long cxl_h_download_adapter_image(u64 unit_address,
+				  u64 list_address, u64 num,
+				  u64 *out)
+{
+	return cxl_h_download_facility(unit_address,
+				       H_DOWNLOAD_CA_FACILITY_DOWNLOAD,
+				       list_address, num, out);
+}
+
+/**
+ * cxl_h_validate_adapter_image - Validate the base image in the coherent
+ *                                platform facility.
+ */
+long cxl_h_validate_adapter_image(u64 unit_address,
+				  u64 list_address, u64 num,
+				  u64 *out)
+{
+	return cxl_h_download_facility(unit_address,
+				       H_DOWNLOAD_CA_FACILITY_VALIDATE,
+				       list_address, num, out);
+}
--- linux-4.4.0.orig/drivers/misc/cxl/hcalls.h
+++ linux-4.4.0/drivers/misc/cxl/hcalls.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _HCALLS_H
+#define _HCALLS_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/hvcall.h>
+#include "cxl.h"
+
+#define SG_BUFFER_SIZE 4096
+#define SG_MAX_ENTRIES 256
+
+struct sg_list {
+	u64 phys_addr;
+	u64 len;
+};
+
+/*
+ * This is straight out of PAPR, but replacing some of the compound fields with
+ * a single field, where they were identical to the register layout.
+ *
+ * The 'flags' parameter regroups the various bit-fields
+ */
+#define CXL_PE_CSRP_VALID			(1ULL << 63)
+#define CXL_PE_PROBLEM_STATE			(1ULL << 62)
+#define CXL_PE_SECONDARY_SEGMENT_TBL_SRCH	(1ULL << 61)
+#define CXL_PE_TAGS_ACTIVE			(1ULL << 60)
+#define CXL_PE_USER_STATE			(1ULL << 59)
+#define CXL_PE_TRANSLATION_ENABLED		(1ULL << 58)
+#define CXL_PE_64_BIT				(1ULL << 57)
+#define CXL_PE_PRIVILEGED_PROCESS		(1ULL << 56)
+
+#define CXL_PROCESS_ELEMENT_VERSION 1
+struct cxl_process_element_hcall {
+	__be64 version;
+	__be64 flags;
+	u8     reserved0[12];
+	__be32 pslVirtualIsn;
+	u8     applicationVirtualIsnBitmap[256];
+	u8     reserved1[144];
+	struct cxl_process_element_common common;
+	u8     reserved4[12];
+} __packed;
+
+#define H_STATE_NORMAL              1
+#define H_STATE_DISABLE             2
+#define H_STATE_TEMP_UNAVAILABLE    3
+#define H_STATE_PERM_UNAVAILABLE    4
+
+/* NOTE: element must be a logical real address, and must be pinned */
+long cxl_h_attach_process(u64 unit_address, struct cxl_process_element_hcall *element,
+			u64 *process_token, u64 *mmio_addr, u64 *mmio_size);
+
+/**
+ * cxl_h_detach_process - Detach a process element from a coherent
+ *                        platform function.
+ */
+long cxl_h_detach_process(u64 unit_address, u64 process_token);
+
+/**
+ * cxl_h_reset_afu - Perform a reset to the coherent platform function.
+ */
+long cxl_h_reset_afu(u64 unit_address);
+
+/**
+ * cxl_h_suspend_process - Suspend a process from being executed
+ * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
+ *              process was attached.
+ */
+long cxl_h_suspend_process(u64 unit_address, u64 process_token);
+
+/**
+ * cxl_h_resume_process - Resume a process to be executed
+ * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
+ *              process was attached.
+ */
+long cxl_h_resume_process(u64 unit_address, u64 process_token);
+
+/**
+ * cxl_h_read_error_state - Reads the error state of the coherent
+ *                          platform function.
+ * R4 contains the error state
+ */
+long cxl_h_read_error_state(u64 unit_address, u64 *state);
+
+/**
+ * cxl_h_get_afu_err - collect the AFU error buffer
+ * Parameter1 = byte offset into error buffer to retrieve, valid values
+ *              are between 0 and (ibm,error-buffer-size - 1)
+ * Parameter2 = 4K aligned real address of error buffer, to be filled in
+ * Parameter3 = length of error buffer, valid values are 4K or less
+ */
+long cxl_h_get_afu_err(u64 unit_address, u64 offset, u64 buf_address, u64 len);
+
+/**
+ * cxl_h_get_config - collect configuration record for the
+ *                    coherent platform function
+ * Parameter1 = # of configuration record to retrieve, valid values are
+ *              between 0 and (ibm,#config-records - 1)
+ * Parameter2 = byte offset into configuration record to retrieve,
+ *              valid values are between 0 and (ibm,config-record-size - 1)
+ * Parameter3 = 4K aligned real address of configuration record buffer,
+ *              to be filled in
+ * Parameter4 = length of configuration buffer, valid values are 4K or less
+ */
+long cxl_h_get_config(u64 unit_address, u64 cr_num, u64 offset,
+		u64 buf_address, u64 len);
+
+/**
+ * cxl_h_terminate_process - Terminate the process before completion
+ * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
+ *              process was attached.
+ */
+long cxl_h_terminate_process(u64 unit_address, u64 process_token);
+
+/**
+ * cxl_h_collect_vpd - Collect VPD for the coherent platform function.
+ * Parameter1 = # of VPD record to retrieve, valid values are between 0
+ *              and (ibm,#config-records - 1).
+ * Parameter2 = 4K naturally aligned real buffer containing block
+ *              list entries
+ * Parameter3 = number of block list entries in the block list, valid
+ *              values are between 0 and 256
+ */
+long cxl_h_collect_vpd(u64 unit_address, u64 record, u64 list_address,
+		       u64 num, u64 *out);
+
+/**
+ * cxl_h_get_fn_error_interrupt - Read the function-wide error data based on an interrupt
+ */
+long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg);
+
+/**
+ * cxl_h_ack_fn_error_interrupt - Acknowledge function-wide error data
+ *                                based on an interrupt
+ * Parameter1 = value to write to the function-wide error interrupt register
+ */
+long cxl_h_ack_fn_error_interrupt(u64 unit_address, u64 value);
+
+/**
+ * cxl_h_get_error_log - Retrieve the Platform Log ID (PLID) of
+ *                       an error log
+ */
+long cxl_h_get_error_log(u64 unit_address, u64 value);
+
+/**
+ * cxl_h_collect_int_info - Collect interrupt info about a coherent
+ *                          platform function after an interrupt occurred.
+ */
+long cxl_h_collect_int_info(u64 unit_address, u64 process_token,
+			struct cxl_irq_info *info);
+
+/**
+ * cxl_h_control_faults - Control the operation of a coherent platform
+ *                        function after a fault occurs.
+ *
+ * Parameters
+ *    control-mask: value to control the faults
+ *                  looks like PSL_TFC_An shifted >> 32
+ *    reset-mask: mask to control reset of function faults
+ *                Set reset_mask = 1 to reset PSL errors
+ */
+long cxl_h_control_faults(u64 unit_address, u64 process_token,
+			u64 control_mask, u64 reset_mask);
+
+/**
+ * cxl_h_reset_adapter - Perform a reset to the coherent platform facility.
+ */
+long cxl_h_reset_adapter(u64 unit_address);
+
+/**
+ * cxl_h_collect_vpd - Collect VPD for the coherent platform function.
+ * Parameter1 = 4K naturally aligned real buffer containing block
+ *              list entries
+ * Parameter2 = number of block list entries in the block list, valid
+ *              values are between 0 and 256
+ */
+long cxl_h_collect_vpd_adapter(u64 unit_address, u64 list_address,
+			       u64 num, u64 *out);
+
+/**
+ * cxl_h_download_adapter_image - Download the base image to the coherent
+ *                                platform facility.
+ */
+long cxl_h_download_adapter_image(u64 unit_address,
+				  u64 list_address, u64 num,
+				  u64 *out);
+
+/**
+ * cxl_h_validate_adapter_image - Validate the base image in the coherent
+ *                                platform facility.
+ */
+long cxl_h_validate_adapter_image(u64 unit_address,
+				  u64 list_address, u64 num,
+				  u64 *out);
+#endif /* _HCALLS_H */
--- linux-4.4.0.orig/drivers/misc/cxl/irq.c
+++ linux-4.4.0/drivers/misc/cxl/irq.c
@@ -19,70 +19,11 @@
 #include "cxl.h"
 #include "trace.h"
 
-/* XXX: This is implementation specific */
-static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u64 errstat)
+static int afu_irq_range_start(void)
 {
-	u64 fir1, fir2, fir_slice, serr, afu_debug;
-
-	fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR1);
-	fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR2);
-	fir_slice = cxl_p1n_read(ctx->afu, CXL_PSL_FIR_SLICE_An);
-	serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An);
-	afu_debug = cxl_p1n_read(ctx->afu, CXL_AFU_DEBUG_An);
-
-	dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%016llx\n", errstat);
-	dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1);
-	dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2);
-	dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%016llx\n", serr);
-	dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice);
-	dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug);
-
-	dev_crit(&ctx->afu->dev, "STOPPING CXL TRACE\n");
-	cxl_stop_trace(ctx->afu->adapter);
-
-	return cxl_ack_irq(ctx, 0, errstat);
-}
-
-irqreturn_t cxl_slice_irq_err(int irq, void *data)
-{
-	struct cxl_afu *afu = data;
-	u64 fir_slice, errstat, serr, afu_debug;
-
-	WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq);
-
-	serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
-	fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An);
-	errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
-	afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An);
-	dev_crit(&afu->dev, "PSL_SERR_An: 0x%016llx\n", serr);
-	dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice);
-	dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%016llx\n", errstat);
-	dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug);
-
-	cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t cxl_irq_err(int irq, void *data)
-{
-	struct cxl *adapter = data;
-	u64 fir1, fir2, err_ivte;
-
-	WARN(1, "CXL ERROR interrupt %i\n", irq);
-
-	err_ivte = cxl_p1_read(adapter, CXL_PSL_ErrIVTE);
-	dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%016llx\n", err_ivte);
-
-	dev_crit(&adapter->dev, "STOPPING CXL TRACE\n");
-	cxl_stop_trace(adapter);
-
-	fir1 = cxl_p1_read(adapter, CXL_PSL_FIR1);
-	fir2 = cxl_p1_read(adapter, CXL_PSL_FIR2);
-
-	dev_crit(&adapter->dev, "PSL_FIR1: 0x%016llx\nPSL_FIR2: 0x%016llx\n", fir1, fir2);
-
-	return IRQ_HANDLED;
+	if (cpu_has_feature(CPU_FTR_HVMODE))
+		return 1;
+	return 0;
 }
 
 static irqreturn_t schedule_cxl_fault(struct cxl_context *ctx, u64 dsisr, u64 dar)
@@ -93,9 +34,8 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info)
+irqreturn_t cxl_irq(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info)
 {
-	struct cxl_context *ctx = data;
 	u64 dsisr, dar;
 
 	dsisr = irq_info->dsisr;
@@ -145,7 +85,8 @@
 	if (dsisr & CXL_PSL_DSISR_An_UR)
 		pr_devel("CXL interrupt: AURP PTE not found\n");
 	if (dsisr & CXL_PSL_DSISR_An_PE)
-		return handle_psl_slice_error(ctx, dsisr, irq_info->errstat);
+		return cxl_ops->handle_psl_slice_error(ctx, dsisr,
+						irq_info->errstat);
 	if (dsisr & CXL_PSL_DSISR_An_AE) {
 		pr_devel("CXL interrupt: AFU Error 0x%016llx\n", irq_info->afu_err);
 
@@ -169,7 +110,7 @@
 			wake_up_all(&ctx->wq);
 		}
 
-		cxl_ack_irq(ctx, CXL_PSL_TFC_An_A, 0);
+		cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_A, 0);
 		return IRQ_HANDLED;
 	}
 	if (dsisr & CXL_PSL_DSISR_An_OC)
@@ -179,54 +120,27 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t fail_psl_irq(struct cxl_afu *afu, struct cxl_irq_info *irq_info)
-{
-	if (irq_info->dsisr & CXL_PSL_DSISR_TRANS)
-		cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
-	else
-		cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t cxl_irq_multiplexed(int irq, void *data)
-{
-	struct cxl_afu *afu = data;
-	struct cxl_context *ctx;
-	struct cxl_irq_info irq_info;
-	int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff;
-	int ret;
-
-	if ((ret = cxl_get_irq(afu, &irq_info))) {
-		WARN(1, "Unable to get CXL IRQ Info: %i\n", ret);
-		return fail_psl_irq(afu, &irq_info);
-	}
-
-	rcu_read_lock();
-	ctx = idr_find(&afu->contexts_idr, ph);
-	if (ctx) {
-		ret = cxl_irq(irq, ctx, &irq_info);
-		rcu_read_unlock();
-		return ret;
-	}
-	rcu_read_unlock();
-
-	WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %016llx DAR"
-		" %016llx\n(Possible AFU HW issue - was a term/remove acked"
-		" with outstanding transactions?)\n", ph, irq_info.dsisr,
-		irq_info.dar);
-	return fail_psl_irq(afu, &irq_info);
-}
-
 static irqreturn_t cxl_irq_afu(int irq, void *data)
 {
 	struct cxl_context *ctx = data;
 	irq_hw_number_t hwirq = irqd_to_hwirq(irq_get_irq_data(irq));
-	int irq_off, afu_irq = 1;
+	int irq_off, afu_irq = 0;
 	__u16 range;
 	int r;
 
-	for (r = 1; r < CXL_IRQ_RANGES; r++) {
+	/*
+	 * Look for the interrupt number.
+	 * On bare-metal, we know range 0 only contains the PSL
+	 * interrupt so we could start counting at range 1 and initialize
+	 * afu_irq at 1.
+	 * In a guest, range 0 also contains AFU interrupts, so it must
+	 * be counted for. Therefore we initialize afu_irq at 0 to take into
+	 * account the PSL interrupt.
+	 *
+	 * For code-readability, it just seems easier to go over all
+	 * the ranges on bare-metal and guest. The end result is the same.
+	 */
+	for (r = 0; r < CXL_IRQ_RANGES; r++) {
 		irq_off = hwirq - ctx->irqs.offset[r];
 		range = ctx->irqs.range[r];
 		if (irq_off >= 0 && irq_off < range) {
@@ -236,7 +150,7 @@
 		afu_irq += range;
 	}
 	if (unlikely(r >= CXL_IRQ_RANGES)) {
-		WARN(1, "Recieved AFU IRQ out of range for pe %i (virq %i hwirq %lx)\n",
+		WARN(1, "Received AFU IRQ out of range for pe %i (virq %i hwirq %lx)\n",
 		     ctx->pe, irq, hwirq);
 		return IRQ_HANDLED;
 	}
@@ -246,7 +160,7 @@
 	       afu_irq, ctx->pe, irq, hwirq);
 
 	if (unlikely(!ctx->irq_bitmap)) {
-		WARN(1, "Recieved AFU IRQ for context with no IRQ bitmap\n");
+		WARN(1, "Received AFU IRQ for context with no IRQ bitmap\n");
 		return IRQ_HANDLED;
 	}
 	spin_lock(&ctx->lock);
@@ -272,7 +186,8 @@
 		return 0;
 	}
 
-	cxl_setup_irq(adapter, hwirq, virq);
+	if (cxl_ops->setup_irq)
+		cxl_ops->setup_irq(adapter, hwirq, virq);
 
 	pr_devel("hwirq %#lx mapped to virq %u\n", hwirq, virq);
 
@@ -288,19 +203,18 @@
 void cxl_unmap_irq(unsigned int virq, void *cookie)
 {
 	free_irq(virq, cookie);
-	irq_dispose_mapping(virq);
 }
 
-static int cxl_register_one_irq(struct cxl *adapter,
-				irq_handler_t handler,
-				void *cookie,
-				irq_hw_number_t *dest_hwirq,
-				unsigned int *dest_virq,
-				const char *name)
+int cxl_register_one_irq(struct cxl *adapter,
+			irq_handler_t handler,
+			void *cookie,
+			irq_hw_number_t *dest_hwirq,
+			unsigned int *dest_virq,
+			const char *name)
 {
 	int hwirq, virq;
 
-	if ((hwirq = cxl_alloc_one_irq(adapter)) < 0)
+	if ((hwirq = cxl_ops->alloc_one_irq(adapter)) < 0)
 		return hwirq;
 
 	if (!(virq = cxl_map_irq(adapter, hwirq, handler, cookie, name)))
@@ -312,108 +226,10 @@
 	return 0;
 
 err:
-	cxl_release_one_irq(adapter, hwirq);
+	cxl_ops->release_one_irq(adapter, hwirq);
 	return -ENOMEM;
 }
 
-int cxl_register_psl_err_irq(struct cxl *adapter)
-{
-	int rc;
-
-	adapter->irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
-				      dev_name(&adapter->dev));
-	if (!adapter->irq_name)
-		return -ENOMEM;
-
-	if ((rc = cxl_register_one_irq(adapter, cxl_irq_err, adapter,
-				       &adapter->err_hwirq,
-				       &adapter->err_virq,
-				       adapter->irq_name))) {
-		kfree(adapter->irq_name);
-		adapter->irq_name = NULL;
-		return rc;
-	}
-
-	cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->err_hwirq & 0xffff);
-
-	return 0;
-}
-
-void cxl_release_psl_err_irq(struct cxl *adapter)
-{
-	if (adapter->err_virq != irq_find_mapping(NULL, adapter->err_hwirq))
-		return;
-
-	cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000);
-	cxl_unmap_irq(adapter->err_virq, adapter);
-	cxl_release_one_irq(adapter, adapter->err_hwirq);
-	kfree(adapter->irq_name);
-}
-
-int cxl_register_serr_irq(struct cxl_afu *afu)
-{
-	u64 serr;
-	int rc;
-
-	afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
-				      dev_name(&afu->dev));
-	if (!afu->err_irq_name)
-		return -ENOMEM;
-
-	if ((rc = cxl_register_one_irq(afu->adapter, cxl_slice_irq_err, afu,
-				       &afu->serr_hwirq,
-				       &afu->serr_virq, afu->err_irq_name))) {
-		kfree(afu->err_irq_name);
-		afu->err_irq_name = NULL;
-		return rc;
-	}
-
-	serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
-	serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff);
-	cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
-
-	return 0;
-}
-
-void cxl_release_serr_irq(struct cxl_afu *afu)
-{
-	if (afu->serr_virq != irq_find_mapping(NULL, afu->serr_hwirq))
-		return;
-
-	cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000);
-	cxl_unmap_irq(afu->serr_virq, afu);
-	cxl_release_one_irq(afu->adapter, afu->serr_hwirq);
-	kfree(afu->err_irq_name);
-}
-
-int cxl_register_psl_irq(struct cxl_afu *afu)
-{
-	int rc;
-
-	afu->psl_irq_name = kasprintf(GFP_KERNEL, "cxl-%s",
-				      dev_name(&afu->dev));
-	if (!afu->psl_irq_name)
-		return -ENOMEM;
-
-	if ((rc = cxl_register_one_irq(afu->adapter, cxl_irq_multiplexed, afu,
-				    &afu->psl_hwirq, &afu->psl_virq,
-				    afu->psl_irq_name))) {
-		kfree(afu->psl_irq_name);
-		afu->psl_irq_name = NULL;
-	}
-	return rc;
-}
-
-void cxl_release_psl_irq(struct cxl_afu *afu)
-{
-	if (afu->psl_virq != irq_find_mapping(NULL, afu->psl_hwirq))
-		return;
-
-	cxl_unmap_irq(afu->psl_virq, afu);
-	cxl_release_one_irq(afu->adapter, afu->psl_hwirq);
-	kfree(afu->psl_irq_name);
-}
-
 void afu_irq_name_free(struct cxl_context *ctx)
 {
 	struct cxl_irq_name *irq_name, *tmp;
@@ -429,16 +245,33 @@
 {
 	int rc, r, i, j = 1;
 	struct cxl_irq_name *irq_name;
+	int alloc_count;
+
+	/*
+	 * In native mode, range 0 is reserved for the multiplexed
+	 * PSL interrupt. It has been allocated when the AFU was initialized.
+	 *
+	 * In a guest, the PSL interrupt is not mutliplexed, but per-context,
+	 * and is the first interrupt from range 0. It still needs to be
+	 * allocated, so bump the count by one.
+	 */
+	if (cpu_has_feature(CPU_FTR_HVMODE))
+		alloc_count = count;
+	else
+		alloc_count = count + 1;
 
 	/* Initialize the list head to hold irq names */
 	INIT_LIST_HEAD(&ctx->irq_names);
 
-	if ((rc = cxl_alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter, count)))
+	if ((rc = cxl_ops->alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter,
+							alloc_count)))
 		return rc;
 
-	/* Multiplexed PSL Interrupt */
-	ctx->irqs.offset[0] = ctx->afu->psl_hwirq;
-	ctx->irqs.range[0] = 1;
+	if (cpu_has_feature(CPU_FTR_HVMODE)) {
+		/* Multiplexed PSL Interrupt */
+		ctx->irqs.offset[0] = ctx->afu->native->psl_hwirq;
+		ctx->irqs.range[0] = 1;
+	}
 
 	ctx->irq_count = count;
 	ctx->irq_bitmap = kcalloc(BITS_TO_LONGS(count),
@@ -450,7 +283,7 @@
 	 * Allocate names first.  If any fail, bail out before allocating
 	 * actual hardware IRQs.
 	 */
-	for (r = 1; r < CXL_IRQ_RANGES; r++) {
+	for (r = afu_irq_range_start(); r < CXL_IRQ_RANGES; r++) {
 		for (i = 0; i < ctx->irqs.range[r]; i++) {
 			irq_name = kmalloc(sizeof(struct cxl_irq_name),
 					   GFP_KERNEL);
@@ -471,7 +304,7 @@
 	return 0;
 
 out:
-	cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
+	cxl_ops->release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
 	afu_irq_name_free(ctx);
 	return -ENOMEM;
 }
@@ -480,15 +313,30 @@
 {
 	irq_hw_number_t hwirq;
 	struct cxl_irq_name *irq_name;
-	int r,i;
+	int r, i;
+	irqreturn_t (*handler)(int irq, void *data);
 
 	/* We've allocated all memory now, so let's do the irq allocations */
 	irq_name = list_first_entry(&ctx->irq_names, struct cxl_irq_name, list);
-	for (r = 1; r < CXL_IRQ_RANGES; r++) {
+	for (r = afu_irq_range_start(); r < CXL_IRQ_RANGES; r++) {
 		hwirq = ctx->irqs.offset[r];
 		for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
-			cxl_map_irq(ctx->afu->adapter, hwirq,
-				    cxl_irq_afu, ctx, irq_name->name);
+			if (r == 0 && i == 0)
+				/*
+				 * The very first interrupt of range 0 is
+				 * always the PSL interrupt, but we only
+				 * need to connect a handler for guests,
+				 * because there's one PSL interrupt per
+				 * context.
+				 * On bare-metal, the PSL interrupt is
+				 * multiplexed and was setup when the AFU
+				 * was configured.
+				 */
+				handler = cxl_ops->psl_interrupt;
+			else
+				handler = cxl_irq_afu;
+			cxl_map_irq(ctx->afu->adapter, hwirq, handler, ctx,
+				irq_name->name);
 			irq_name = list_next_entry(irq_name, list);
 		}
 	}
@@ -504,7 +352,7 @@
 
 	afu_register_hwirqs(ctx);
 	return 0;
- }
+}
 
 void afu_release_irqs(struct cxl_context *ctx, void *cookie)
 {
@@ -512,7 +360,7 @@
 	unsigned int virq;
 	int r, i;
 
-	for (r = 1; r < CXL_IRQ_RANGES; r++) {
+	for (r = afu_irq_range_start(); r < CXL_IRQ_RANGES; r++) {
 		hwirq = ctx->irqs.offset[r];
 		for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
 			virq = irq_find_mapping(NULL, hwirq);
@@ -522,7 +370,7 @@
 	}
 
 	afu_irq_name_free(ctx);
-	cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
+	cxl_ops->release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
 
 	ctx->irq_count = 0;
 }
--- linux-4.4.0.orig/drivers/misc/cxl/main.c
+++ linux-4.4.0/drivers/misc/cxl/main.c
@@ -32,6 +32,29 @@
 module_param_named(verbose, cxl_verbose, uint, 0600);
 MODULE_PARM_DESC(verbose, "Enable verbose dmesg output");
 
+const struct cxl_backend_ops *cxl_ops;
+
+int cxl_afu_slbia(struct cxl_afu *afu)
+{
+	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+
+	pr_devel("cxl_afu_slbia issuing SLBIA command\n");
+	cxl_p2n_write(afu, CXL_SLBIA_An, CXL_TLB_SLB_IQ_ALL);
+	while (cxl_p2n_read(afu, CXL_SLBIA_An) & CXL_TLB_SLB_P) {
+		if (time_after_eq(jiffies, timeout)) {
+			dev_warn(&afu->dev, "WARNING: CXL AFU SLBIA timed out!\n");
+			return -EBUSY;
+		}
+		/* If the adapter has gone down, we can assume that we
+		 * will PERST it and that will invalidate everything.
+		 */
+		if (!cxl_ops->link_ok(afu->adapter, afu))
+			return -EIO;
+		cpu_relax();
+	}
+	return 0;
+}
+
 static inline void _cxl_slbia(struct cxl_context *ctx, struct mm_struct *mm)
 {
 	struct task_struct *task;
@@ -139,6 +162,32 @@
 	return 0;
 }
 
+/* print buffer content as integers when debugging */
+void cxl_dump_debug_buffer(void *buf, size_t buf_len)
+{
+#ifdef DEBUG
+	int i, *ptr;
+
+	/*
+	 * We want to regroup up to 4 integers per line, which means they
+	 * need to be in the same pr_devel() statement
+	 */
+	ptr = (int *) buf;
+	for (i = 0; i * 4 < buf_len; i += 4) {
+		if ((i + 3) * 4 < buf_len)
+			pr_devel("%.8x %.8x %.8x %.8x\n", ptr[i], ptr[i + 1],
+				ptr[i + 2], ptr[i + 3]);
+		else if ((i + 2) * 4 < buf_len)
+			pr_devel("%.8x %.8x %.8x\n", ptr[i], ptr[i + 1],
+				ptr[i + 2]);
+		else if ((i + 1) * 4 < buf_len)
+			pr_devel("%.8x %.8x\n", ptr[i], ptr[i + 1]);
+		else
+			pr_devel("%.8x\n", ptr[i]);
+	}
+#endif /* DEBUG */
+}
+
 /* Find a CXL adapter by it's number and increase it's refcount */
 struct cxl *get_cxl_adapter(int num)
 {
@@ -152,7 +201,7 @@
 	return adapter;
 }
 
-int cxl_alloc_adapter_nr(struct cxl *adapter)
+static int cxl_alloc_adapter_nr(struct cxl *adapter)
 {
 	int i;
 
@@ -174,13 +223,58 @@
 	idr_remove(&cxl_adapter_idr, adapter->adapter_num);
 }
 
+struct cxl *cxl_alloc_adapter(void)
+{
+	struct cxl *adapter;
+
+	if (!(adapter = kzalloc(sizeof(struct cxl), GFP_KERNEL)))
+		return NULL;
+
+	spin_lock_init(&adapter->afu_list_lock);
+
+	if (cxl_alloc_adapter_nr(adapter))
+		goto err1;
+
+	if (dev_set_name(&adapter->dev, "card%i", adapter->adapter_num))
+		goto err2;
+
+	return adapter;
+
+err2:
+	cxl_remove_adapter_nr(adapter);
+err1:
+	kfree(adapter);
+	return NULL;
+}
+
+struct cxl_afu *cxl_alloc_afu(struct cxl *adapter, int slice)
+{
+	struct cxl_afu *afu;
+
+	if (!(afu = kzalloc(sizeof(struct cxl_afu), GFP_KERNEL)))
+		return NULL;
+
+	afu->adapter = adapter;
+	afu->dev.parent = &adapter->dev;
+	afu->dev.release = cxl_ops->release_afu;
+	afu->slice = slice;
+	idr_init(&afu->contexts_idr);
+	mutex_init(&afu->contexts_lock);
+	spin_lock_init(&afu->afu_cntl_lock);
+
+	afu->prefault_mode = CXL_PREFAULT_NONE;
+	afu->irqs_max = afu->adapter->user_irqs;
+
+	return afu;
+}
+
 int cxl_afu_select_best_mode(struct cxl_afu *afu)
 {
 	if (afu->modes_supported & CXL_MODE_DIRECTED)
-		return cxl_afu_activate_mode(afu, CXL_MODE_DIRECTED);
+		return cxl_ops->afu_activate_mode(afu, CXL_MODE_DIRECTED);
 
 	if (afu->modes_supported & CXL_MODE_DEDICATED)
-		return cxl_afu_activate_mode(afu, CXL_MODE_DEDICATED);
+		return cxl_ops->afu_activate_mode(afu, CXL_MODE_DEDICATED);
 
 	dev_warn(&afu->dev, "No supported programming modes available\n");
 	/* We don't fail this so the user can inspect sysfs */
@@ -191,9 +285,6 @@
 {
 	int rc = 0;
 
-	if (!cpu_has_feature(CPU_FTR_HVMODE))
-		return -EPERM;
-
 	if ((rc = cxl_file_init()))
 		return rc;
 
@@ -202,7 +293,17 @@
 	if ((rc = register_cxl_calls(&cxl_calls)))
 		goto err;
 
-	if ((rc = pci_register_driver(&cxl_pci_driver)))
+	if (cpu_has_feature(CPU_FTR_HVMODE)) {
+		cxl_ops = &cxl_native_ops;
+		rc = pci_register_driver(&cxl_pci_driver);
+	}
+#ifdef CONFIG_PPC_PSERIES
+	else {
+		cxl_ops = &cxl_guest_ops;
+		rc = platform_driver_register(&cxl_of_driver);
+	}
+#endif
+	if (rc)
 		goto err1;
 
 	return 0;
@@ -217,7 +318,12 @@
 
 static void exit_cxl(void)
 {
-	pci_unregister_driver(&cxl_pci_driver);
+	if (cpu_has_feature(CPU_FTR_HVMODE))
+		pci_unregister_driver(&cxl_pci_driver);
+#ifdef CONFIG_PPC_PSERIES
+	else
+		platform_driver_unregister(&cxl_of_driver);
+#endif
 
 	cxl_debugfs_exit();
 	cxl_file_exit();
--- linux-4.4.0.orig/drivers/misc/cxl/native.c
+++ linux-4.4.0/drivers/misc/cxl/native.c
@@ -14,6 +14,7 @@
 #include <linux/mutex.h>
 #include <linux/mm.h>
 #include <linux/uaccess.h>
+#include <linux/delay.h>
 #include <asm/synch.h>
 #include <misc/cxl-base.h>
 
@@ -42,7 +43,7 @@
 			goto out;
 		}
 
-		if (!cxl_adapter_link_ok(afu->adapter)) {
+		if (!cxl_ops->link_ok(afu->adapter, afu)) {
 			afu->enabled = enabled;
 			rc = -EIO;
 			goto out;
@@ -80,7 +81,7 @@
 }
 
 /* This will disable as well as reset */
-int __cxl_afu_reset(struct cxl_afu *afu)
+static int native_afu_reset(struct cxl_afu *afu)
 {
 	pr_devel("AFU reset request\n");
 
@@ -90,9 +91,9 @@
 			   false);
 }
 
-int cxl_afu_check_and_enable(struct cxl_afu *afu)
+static int native_afu_check_and_enable(struct cxl_afu *afu)
 {
-	if (!cxl_adapter_link_ok(afu->adapter)) {
+	if (!cxl_ops->link_ok(afu->adapter, afu)) {
 		WARN(1, "Refusing to enable afu while link down!\n");
 		return -EIO;
 	}
@@ -114,7 +115,7 @@
 
 	pr_devel("PSL purge request\n");
 
-	if (!cxl_adapter_link_ok(afu->adapter)) {
+	if (!cxl_ops->link_ok(afu->adapter, afu)) {
 		dev_warn(&afu->dev, "PSL Purge called with link down, ignoring\n");
 		rc = -EIO;
 		goto out;
@@ -136,7 +137,7 @@
 			rc = -EBUSY;
 			goto out;
 		}
-		if (!cxl_adapter_link_ok(afu->adapter)) {
+		if (!cxl_ops->link_ok(afu->adapter, afu)) {
 			rc = -EIO;
 			goto out;
 		}
@@ -186,22 +187,22 @@
 int cxl_alloc_spa(struct cxl_afu *afu)
 {
 	/* Work out how many pages to allocate */
-	afu->spa_order = 0;
+	afu->native->spa_order = 0;
 	do {
-		afu->spa_order++;
-		afu->spa_size = (1 << afu->spa_order) * PAGE_SIZE;
-		afu->spa_max_procs = spa_max_procs(afu->spa_size);
-	} while (afu->spa_max_procs < afu->num_procs);
+		afu->native->spa_order++;
+		afu->native->spa_size = (1 << afu->native->spa_order) * PAGE_SIZE;
+		afu->native->spa_max_procs = spa_max_procs(afu->native->spa_size);
+	} while (afu->native->spa_max_procs < afu->num_procs);
 
-	WARN_ON(afu->spa_size > 0x100000); /* Max size supported by the hardware */
+	WARN_ON(afu->native->spa_size > 0x100000); /* Max size supported by the hardware */
 
-	if (!(afu->spa = (struct cxl_process_element *)
-	      __get_free_pages(GFP_KERNEL | __GFP_ZERO, afu->spa_order))) {
+	if (!(afu->native->spa = (struct cxl_process_element *)
+	      __get_free_pages(GFP_KERNEL | __GFP_ZERO, afu->native->spa_order))) {
 		pr_err("cxl_alloc_spa: Unable to allocate scheduled process area\n");
 		return -ENOMEM;
 	}
 	pr_devel("spa pages: %i afu->spa_max_procs: %i   afu->num_procs: %i\n",
-		 1<<afu->spa_order, afu->spa_max_procs, afu->num_procs);
+		 1<<afu->native->spa_order, afu->native->spa_max_procs, afu->num_procs);
 
 	return 0;
 }
@@ -210,13 +211,15 @@
 {
 	u64 spap;
 
-	afu->sw_command_status = (__be64 *)((char *)afu->spa +
-					    ((afu->spa_max_procs + 3) * 128));
+	afu->native->sw_command_status = (__be64 *)((char *)afu->native->spa +
+					    ((afu->native->spa_max_procs + 3) * 128));
 
-	spap = virt_to_phys(afu->spa) & CXL_PSL_SPAP_Addr;
-	spap |= ((afu->spa_size >> (12 - CXL_PSL_SPAP_Size_Shift)) - 1) & CXL_PSL_SPAP_Size;
+	spap = virt_to_phys(afu->native->spa) & CXL_PSL_SPAP_Addr;
+	spap |= ((afu->native->spa_size >> (12 - CXL_PSL_SPAP_Size_Shift)) - 1) & CXL_PSL_SPAP_Size;
 	spap |= CXL_PSL_SPAP_V;
-	pr_devel("cxl: SPA allocated at 0x%p. Max processes: %i, sw_command_status: 0x%p CXL_PSL_SPAP_An=0x%016llx\n", afu->spa, afu->spa_max_procs, afu->sw_command_status, spap);
+	pr_devel("cxl: SPA allocated at 0x%p. Max processes: %i, sw_command_status: 0x%p CXL_PSL_SPAP_An=0x%016llx\n",
+		afu->native->spa, afu->native->spa_max_procs,
+		afu->native->sw_command_status, spap);
 	cxl_p1n_write(afu, CXL_PSL_SPAP_An, spap);
 }
 
@@ -227,9 +230,10 @@
 
 void cxl_release_spa(struct cxl_afu *afu)
 {
-	if (afu->spa) {
-		free_pages((unsigned long) afu->spa, afu->spa_order);
-		afu->spa = NULL;
+	if (afu->native->spa) {
+		free_pages((unsigned long) afu->native->spa,
+			afu->native->spa_order);
+		afu->native->spa = NULL;
 	}
 }
 
@@ -247,7 +251,7 @@
 			dev_warn(&adapter->dev, "WARNING: CXL adapter wide TLBIA timed out!\n");
 			return -EBUSY;
 		}
-		if (!cxl_adapter_link_ok(adapter))
+		if (!cxl_ops->link_ok(adapter, NULL))
 			return -EIO;
 		cpu_relax();
 	}
@@ -258,31 +262,41 @@
 			dev_warn(&adapter->dev, "WARNING: CXL adapter wide SLBIA timed out!\n");
 			return -EBUSY;
 		}
-		if (!cxl_adapter_link_ok(adapter))
+		if (!cxl_ops->link_ok(adapter, NULL))
 			return -EIO;
 		cpu_relax();
 	}
 	return 0;
 }
 
-int cxl_afu_slbia(struct cxl_afu *afu)
+int cxl_data_cache_flush(struct cxl *adapter)
 {
+	u64 reg;
 	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
 
-	pr_devel("cxl_afu_slbia issuing SLBIA command\n");
-	cxl_p2n_write(afu, CXL_SLBIA_An, CXL_TLB_SLB_IQ_ALL);
-	while (cxl_p2n_read(afu, CXL_SLBIA_An) & CXL_TLB_SLB_P) {
+	pr_devel("Flushing data cache\n");
+
+	reg = cxl_p1_read(adapter, CXL_PSL_Control);
+	reg |= CXL_PSL_Control_Fr;
+	cxl_p1_write(adapter, CXL_PSL_Control, reg);
+
+	reg = cxl_p1_read(adapter, CXL_PSL_Control);
+	while ((reg & CXL_PSL_Control_Fs_MASK) != CXL_PSL_Control_Fs_Complete) {
 		if (time_after_eq(jiffies, timeout)) {
-			dev_warn(&afu->dev, "WARNING: CXL AFU SLBIA timed out!\n");
+			dev_warn(&adapter->dev, "WARNING: cache flush timed out!\n");
 			return -EBUSY;
 		}
-		/* If the adapter has gone down, we can assume that we
-		 * will PERST it and that will invalidate everything.
-		 */
-		if (!cxl_adapter_link_ok(afu->adapter))
+
+		if (!cxl_ops->link_ok(adapter, NULL)) {
+			dev_warn(&adapter->dev, "WARNING: link down when flushing cache\n");
 			return -EIO;
+		}
 		cpu_relax();
+		reg = cxl_p1_read(adapter, CXL_PSL_Control);
 	}
+
+	reg &= ~CXL_PSL_Control_Fr;
+	cxl_p1_write(adapter, CXL_PSL_Control, reg);
 	return 0;
 }
 
@@ -312,7 +326,7 @@
 	struct cxl *adapter = ctx->afu->adapter;
 	u64 slbia;
 
-	WARN_ON(!mutex_is_locked(&ctx->afu->spa_mutex));
+	WARN_ON(!mutex_is_locked(&ctx->afu->native->spa_mutex));
 
 	cxl_p1_write(adapter, CXL_PSL_LBISEL,
 			((u64)be32_to_cpu(ctx->elem->common.pid) << 32) |
@@ -320,7 +334,7 @@
 	cxl_p1_write(adapter, CXL_PSL_SLBIA, CXL_TLB_SLB_IQ_LPIDPID);
 
 	while (1) {
-		if (!cxl_adapter_link_ok(adapter))
+		if (!cxl_ops->link_ok(adapter, NULL))
 			break;
 		slbia = cxl_p1_read(adapter, CXL_PSL_SLBIA);
 		if (!(slbia & CXL_TLB_SLB_P))
@@ -342,7 +356,7 @@
 
 	ctx->elem->software_state = cpu_to_be32(pe_state);
 	smp_wmb();
-	*(ctx->afu->sw_command_status) = cpu_to_be64(cmd | 0 | ctx->pe);
+	*(ctx->afu->native->sw_command_status) = cpu_to_be64(cmd | 0 | ctx->pe);
 	smp_mb();
 	cxl_p1n_write(ctx->afu, CXL_PSL_LLCMD_An, cmd | ctx->pe);
 	while (1) {
@@ -351,12 +365,12 @@
 			rc = -EBUSY;
 			goto out;
 		}
-		if (!cxl_adapter_link_ok(ctx->afu->adapter)) {
+		if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)) {
 			dev_warn(&ctx->afu->dev, "WARNING: Device link down, aborting Process Element Command!\n");
 			rc = -EIO;
 			goto out;
 		}
-		state = be64_to_cpup(ctx->afu->sw_command_status);
+		state = be64_to_cpup(ctx->afu->native->sw_command_status);
 		if (state == ~0ULL) {
 			pr_err("cxl: Error adding process element to AFU\n");
 			rc = -1;
@@ -384,12 +398,12 @@
 {
 	int rc = 0;
 
-	mutex_lock(&ctx->afu->spa_mutex);
+	mutex_lock(&ctx->afu->native->spa_mutex);
 	pr_devel("%s Adding pe: %i started\n", __func__, ctx->pe);
 	if (!(rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_ADD, CXL_PE_SOFTWARE_STATE_V)))
 		ctx->pe_inserted = true;
 	pr_devel("%s Adding pe: %i finished\n", __func__, ctx->pe);
-	mutex_unlock(&ctx->afu->spa_mutex);
+	mutex_unlock(&ctx->afu->native->spa_mutex);
 	return rc;
 }
 
@@ -401,18 +415,18 @@
 	if (!(ctx->elem->software_state & cpu_to_be32(CXL_PE_SOFTWARE_STATE_V)))
 		return rc;
 
-	mutex_lock(&ctx->afu->spa_mutex);
+	mutex_lock(&ctx->afu->native->spa_mutex);
 	pr_devel("%s Terminate pe: %i started\n", __func__, ctx->pe);
 	/* We could be asked to terminate when the hw is down. That
 	 * should always succeed: it's not running if the hw has gone
 	 * away and is being reset.
 	 */
-	if (cxl_adapter_link_ok(ctx->afu->adapter))
+	if (cxl_ops->link_ok(ctx->afu->adapter, ctx->afu))
 		rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_TERMINATE,
 					    CXL_PE_SOFTWARE_STATE_V | CXL_PE_SOFTWARE_STATE_T);
 	ctx->elem->software_state = 0;	/* Remove Valid bit */
 	pr_devel("%s Terminate pe: %i finished\n", __func__, ctx->pe);
-	mutex_unlock(&ctx->afu->spa_mutex);
+	mutex_unlock(&ctx->afu->native->spa_mutex);
 	return rc;
 }
 
@@ -420,20 +434,20 @@
 {
 	int rc = 0;
 
-	mutex_lock(&ctx->afu->spa_mutex);
+	mutex_lock(&ctx->afu->native->spa_mutex);
 	pr_devel("%s Remove pe: %i started\n", __func__, ctx->pe);
 
 	/* We could be asked to remove when the hw is down. Again, if
 	 * the hw is down, the PE is gone, so we succeed.
 	 */
-	if (cxl_adapter_link_ok(ctx->afu->adapter))
+	if (cxl_ops->link_ok(ctx->afu->adapter, ctx->afu))
 		rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_REMOVE, 0);
 
 	if (!rc)
 		ctx->pe_inserted = false;
 	slb_invalid(ctx);
 	pr_devel("%s Remove pe: %i finished\n", __func__, ctx->pe);
-	mutex_unlock(&ctx->afu->spa_mutex);
+	mutex_unlock(&ctx->afu->native->spa_mutex);
 
 	return rc;
 }
@@ -446,7 +460,7 @@
 		ctx->psn_size = ctx->afu->adapter->ps_size;
 	} else {
 		ctx->psn_phys = ctx->afu->psn_phys +
-			(ctx->afu->pp_offset + ctx->afu->pp_size * ctx->pe);
+			(ctx->afu->native->pp_offset + ctx->afu->pp_size * ctx->pe);
 		ctx->psn_size = ctx->afu->pp_size;
 	}
 }
@@ -458,7 +472,7 @@
 	dev_info(&afu->dev, "Activating AFU directed mode\n");
 
 	afu->num_procs = afu->max_procs_virtualised;
-	if (afu->spa == NULL) {
+	if (afu->native->spa == NULL) {
 		if (cxl_alloc_spa(afu))
 			return -ENOMEM;
 	}
@@ -552,7 +566,7 @@
 	ctx->elem->common.wed = cpu_to_be64(wed);
 
 	/* first guy needs to enable */
-	if ((result = cxl_afu_check_and_enable(ctx->afu)))
+	if ((result = cxl_ops->afu_check_and_enable(ctx->afu)))
 		return result;
 
 	return add_process_element(ctx);
@@ -568,7 +582,7 @@
 	cxl_sysfs_afu_m_remove(afu);
 	cxl_chardev_afu_remove(afu);
 
-	__cxl_afu_reset(afu);
+	cxl_ops->afu_reset(afu);
 	cxl_afu_disable(afu);
 	cxl_psl_purge(afu);
 
@@ -632,7 +646,7 @@
 	/* master only context for dedicated */
 	cxl_assign_psn_space(ctx);
 
-	if ((rc = __cxl_afu_reset(afu)))
+	if ((rc = cxl_ops->afu_reset(afu)))
 		return rc;
 
 	cxl_p2n_write(afu, CXL_PSL_WED_An, wed);
@@ -652,7 +666,7 @@
 	return 0;
 }
 
-int _cxl_afu_deactivate_mode(struct cxl_afu *afu, int mode)
+static int native_afu_deactivate_mode(struct cxl_afu *afu, int mode)
 {
 	if (mode == CXL_MODE_DIRECTED)
 		return deactivate_afu_directed(afu);
@@ -661,19 +675,14 @@
 	return 0;
 }
 
-int cxl_afu_deactivate_mode(struct cxl_afu *afu)
-{
-	return _cxl_afu_deactivate_mode(afu, afu->current_mode);
-}
-
-int cxl_afu_activate_mode(struct cxl_afu *afu, int mode)
+static int native_afu_activate_mode(struct cxl_afu *afu, int mode)
 {
 	if (!mode)
 		return 0;
 	if (!(mode & afu->modes_supported))
 		return -EINVAL;
 
-	if (!cxl_adapter_link_ok(afu->adapter)) {
+	if (!cxl_ops->link_ok(afu->adapter, afu)) {
 		WARN(1, "Device link is down, refusing to activate!\n");
 		return -EIO;
 	}
@@ -686,9 +695,10 @@
 	return -EINVAL;
 }
 
-int cxl_attach_process(struct cxl_context *ctx, bool kernel, u64 wed, u64 amr)
+static int native_attach_process(struct cxl_context *ctx, bool kernel,
+				u64 wed, u64 amr)
 {
-	if (!cxl_adapter_link_ok(ctx->afu->adapter)) {
+	if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)) {
 		WARN(1, "Device link is down, refusing to attach process!\n");
 		return -EIO;
 	}
@@ -705,7 +715,7 @@
 
 static inline int detach_process_native_dedicated(struct cxl_context *ctx)
 {
-	__cxl_afu_reset(ctx->afu);
+	cxl_ops->afu_reset(ctx->afu);
 	cxl_afu_disable(ctx->afu);
 	cxl_psl_purge(ctx->afu);
 	return 0;
@@ -723,7 +733,7 @@
 	return 0;
 }
 
-int cxl_detach_process(struct cxl_context *ctx)
+static int native_detach_process(struct cxl_context *ctx)
 {
 	trace_cxl_detach(ctx);
 
@@ -733,14 +743,14 @@
 	return detach_process_native_afu_directed(ctx);
 }
 
-int cxl_get_irq(struct cxl_afu *afu, struct cxl_irq_info *info)
+static int native_get_irq_info(struct cxl_afu *afu, struct cxl_irq_info *info)
 {
 	u64 pidtid;
 
 	/* If the adapter has gone away, we can't get any meaningful
 	 * information.
 	 */
-	if (!cxl_adapter_link_ok(afu->adapter))
+	if (!cxl_ops->link_ok(afu->adapter, afu))
 		return -EIO;
 
 	info->dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
@@ -751,10 +761,243 @@
 	info->tid = pidtid & 0xffffffff;
 	info->afu_err = cxl_p2n_read(afu, CXL_AFU_ERR_An);
 	info->errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
+	info->proc_handle = 0;
 
 	return 0;
 }
 
+static irqreturn_t native_handle_psl_slice_error(struct cxl_context *ctx,
+						u64 dsisr, u64 errstat)
+{
+	u64 fir1, fir2, fir_slice, serr, afu_debug;
+
+	fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR1);
+	fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR2);
+	fir_slice = cxl_p1n_read(ctx->afu, CXL_PSL_FIR_SLICE_An);
+	serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An);
+	afu_debug = cxl_p1n_read(ctx->afu, CXL_AFU_DEBUG_An);
+
+	dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%016llx\n", errstat);
+	dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1);
+	dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2);
+	dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%016llx\n", serr);
+	dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice);
+	dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug);
+
+	dev_crit(&ctx->afu->dev, "STOPPING CXL TRACE\n");
+	cxl_stop_trace(ctx->afu->adapter);
+
+	return cxl_ops->ack_irq(ctx, 0, errstat);
+}
+
+static irqreturn_t fail_psl_irq(struct cxl_afu *afu, struct cxl_irq_info *irq_info)
+{
+	if (irq_info->dsisr & CXL_PSL_DSISR_TRANS)
+		cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
+	else
+		cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t native_irq_multiplexed(int irq, void *data)
+{
+	struct cxl_afu *afu = data;
+	struct cxl_context *ctx;
+	struct cxl_irq_info irq_info;
+	int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff;
+	int ret;
+
+	if ((ret = native_get_irq_info(afu, &irq_info))) {
+		WARN(1, "Unable to get CXL IRQ Info: %i\n", ret);
+		return fail_psl_irq(afu, &irq_info);
+	}
+
+	rcu_read_lock();
+	ctx = idr_find(&afu->contexts_idr, ph);
+	if (ctx) {
+		ret = cxl_irq(irq, ctx, &irq_info);
+		rcu_read_unlock();
+		return ret;
+	}
+	rcu_read_unlock();
+
+	WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %016llx DAR"
+		" %016llx\n(Possible AFU HW issue - was a term/remove acked"
+		" with outstanding transactions?)\n", ph, irq_info.dsisr,
+		irq_info.dar);
+	return fail_psl_irq(afu, &irq_info);
+}
+
+void native_irq_wait(struct cxl_context *ctx)
+{
+	u64 dsisr;
+	int timeout = 1000;
+	int ph;
+
+	/*
+	 * Wait until no further interrupts are presented by the PSL
+	 * for this context.
+	 */
+	while (timeout--) {
+		ph = cxl_p2n_read(ctx->afu, CXL_PSL_PEHandle_An) & 0xffff;
+		if (ph != ctx->pe)
+			return;
+		dsisr = cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An);
+		if ((dsisr & CXL_PSL_DSISR_PENDING) == 0)
+			return;
+		/*
+		 * We are waiting for the workqueue to process our
+		 * irq, so need to let that run here.
+		 */
+		msleep(1);
+	}
+
+	dev_warn(&ctx->afu->dev, "WARNING: waiting on DSI for PE %i"
+		 " DSISR %016llx!\n", ph, dsisr);
+	return;
+}
+
+static irqreturn_t native_slice_irq_err(int irq, void *data)
+{
+	struct cxl_afu *afu = data;
+	u64 fir_slice, errstat, serr, afu_debug;
+
+	WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq);
+
+	serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
+	fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An);
+	errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
+	afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An);
+	dev_crit(&afu->dev, "PSL_SERR_An: 0x%016llx\n", serr);
+	dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice);
+	dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%016llx\n", errstat);
+	dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug);
+
+	cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t native_irq_err(int irq, void *data)
+{
+	struct cxl *adapter = data;
+	u64 fir1, fir2, err_ivte;
+
+	WARN(1, "CXL ERROR interrupt %i\n", irq);
+
+	err_ivte = cxl_p1_read(adapter, CXL_PSL_ErrIVTE);
+	dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%016llx\n", err_ivte);
+
+	dev_crit(&adapter->dev, "STOPPING CXL TRACE\n");
+	cxl_stop_trace(adapter);
+
+	fir1 = cxl_p1_read(adapter, CXL_PSL_FIR1);
+	fir2 = cxl_p1_read(adapter, CXL_PSL_FIR2);
+
+	dev_crit(&adapter->dev, "PSL_FIR1: 0x%016llx\nPSL_FIR2: 0x%016llx\n", fir1, fir2);
+
+	return IRQ_HANDLED;
+}
+
+int cxl_native_register_psl_err_irq(struct cxl *adapter)
+{
+	int rc;
+
+	adapter->irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
+				      dev_name(&adapter->dev));
+	if (!adapter->irq_name)
+		return -ENOMEM;
+
+	if ((rc = cxl_register_one_irq(adapter, native_irq_err, adapter,
+				       &adapter->native->err_hwirq,
+				       &adapter->native->err_virq,
+				       adapter->irq_name))) {
+		kfree(adapter->irq_name);
+		adapter->irq_name = NULL;
+		return rc;
+	}
+
+	cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->native->err_hwirq & 0xffff);
+
+	return 0;
+}
+
+void cxl_native_release_psl_err_irq(struct cxl *adapter)
+{
+	if (adapter->native->err_virq != irq_find_mapping(NULL, adapter->native->err_hwirq))
+		return;
+
+	cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000);
+	cxl_unmap_irq(adapter->native->err_virq, adapter);
+	cxl_ops->release_one_irq(adapter, adapter->native->err_hwirq);
+	kfree(adapter->irq_name);
+}
+
+int cxl_native_register_serr_irq(struct cxl_afu *afu)
+{
+	u64 serr;
+	int rc;
+
+	afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
+				      dev_name(&afu->dev));
+	if (!afu->err_irq_name)
+		return -ENOMEM;
+
+	if ((rc = cxl_register_one_irq(afu->adapter, native_slice_irq_err, afu,
+				       &afu->serr_hwirq,
+				       &afu->serr_virq, afu->err_irq_name))) {
+		kfree(afu->err_irq_name);
+		afu->err_irq_name = NULL;
+		return rc;
+	}
+
+	serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
+	serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff);
+	cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
+
+	return 0;
+}
+
+void cxl_native_release_serr_irq(struct cxl_afu *afu)
+{
+	if (afu->serr_virq != irq_find_mapping(NULL, afu->serr_hwirq))
+		return;
+
+	cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000);
+	cxl_unmap_irq(afu->serr_virq, afu);
+	cxl_ops->release_one_irq(afu->adapter, afu->serr_hwirq);
+	kfree(afu->err_irq_name);
+}
+
+int cxl_native_register_psl_irq(struct cxl_afu *afu)
+{
+	int rc;
+
+	afu->psl_irq_name = kasprintf(GFP_KERNEL, "cxl-%s",
+				      dev_name(&afu->dev));
+	if (!afu->psl_irq_name)
+		return -ENOMEM;
+
+	if ((rc = cxl_register_one_irq(afu->adapter, native_irq_multiplexed,
+				    afu, &afu->native->psl_hwirq, &afu->native->psl_virq,
+				    afu->psl_irq_name))) {
+		kfree(afu->psl_irq_name);
+		afu->psl_irq_name = NULL;
+	}
+	return rc;
+}
+
+void cxl_native_release_psl_irq(struct cxl_afu *afu)
+{
+	if (afu->native->psl_virq != irq_find_mapping(NULL, afu->native->psl_hwirq))
+		return;
+
+	cxl_unmap_irq(afu->native->psl_virq, afu);
+	cxl_ops->release_one_irq(afu->adapter, afu->native->psl_hwirq);
+	kfree(afu->psl_irq_name);
+}
+
 static void recover_psl_err(struct cxl_afu *afu, u64 errstat)
 {
 	u64 dsisr;
@@ -769,7 +1012,7 @@
 	cxl_p2n_write(afu, CXL_PSL_ErrStat_An, errstat);
 }
 
-int cxl_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
+static int native_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
 {
 	trace_cxl_psl_irq_ack(ctx, tfc);
 	if (tfc)
@@ -784,3 +1027,133 @@
 {
 	return (cxl_p1n_read(afu, CXL_PSL_SCNTL_An) == ~0ULL);
 }
+
+static bool native_support_attributes(const char *attr_name,
+				      enum cxl_attrs type)
+{
+	return true;
+}
+
+static int native_afu_cr_read64(struct cxl_afu *afu, int cr, u64 off, u64 *out)
+{
+	if (unlikely(!cxl_ops->link_ok(afu->adapter, afu)))
+		return -EIO;
+	if (unlikely(off >= afu->crs_len))
+		return -ERANGE;
+	*out = in_le64(afu->native->afu_desc_mmio + afu->crs_offset +
+		(cr * afu->crs_len) + off);
+	return 0;
+}
+
+static int native_afu_cr_read32(struct cxl_afu *afu, int cr, u64 off, u32 *out)
+{
+	if (unlikely(!cxl_ops->link_ok(afu->adapter, afu)))
+		return -EIO;
+	if (unlikely(off >= afu->crs_len))
+		return -ERANGE;
+	*out = in_le32(afu->native->afu_desc_mmio + afu->crs_offset +
+		(cr * afu->crs_len) + off);
+	return 0;
+}
+
+static int native_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off, u16 *out)
+{
+	u64 aligned_off = off & ~0x3L;
+	u32 val;
+	int rc;
+
+	rc = native_afu_cr_read32(afu, cr, aligned_off, &val);
+	if (!rc)
+		*out = (val >> ((off & 0x3) * 8)) & 0xffff;
+	return rc;
+}
+
+static int native_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off, u8 *out)
+{
+	u64 aligned_off = off & ~0x3L;
+	u32 val;
+	int rc;
+
+	rc = native_afu_cr_read32(afu, cr, aligned_off, &val);
+	if (!rc)
+		*out = (val >> ((off & 0x3) * 8)) & 0xff;
+	return rc;
+}
+
+static int native_afu_cr_write32(struct cxl_afu *afu, int cr, u64 off, u32 in)
+{
+	if (unlikely(!cxl_ops->link_ok(afu->adapter, afu)))
+		return -EIO;
+	if (unlikely(off >= afu->crs_len))
+		return -ERANGE;
+	out_le32(afu->native->afu_desc_mmio + afu->crs_offset +
+		(cr * afu->crs_len) + off, in);
+	return 0;
+}
+
+static int native_afu_cr_write16(struct cxl_afu *afu, int cr, u64 off, u16 in)
+{
+	u64 aligned_off = off & ~0x3L;
+	u32 val32, mask, shift;
+	int rc;
+
+	rc = native_afu_cr_read32(afu, cr, aligned_off, &val32);
+	if (rc)
+		return rc;
+	shift = (off & 0x3) * 8;
+	WARN_ON(shift == 24);
+	mask = 0xffff << shift;
+	val32 = (val32 & ~mask) | (in << shift);
+
+	rc = native_afu_cr_write32(afu, cr, aligned_off, val32);
+	return rc;
+}
+
+static int native_afu_cr_write8(struct cxl_afu *afu, int cr, u64 off, u8 in)
+{
+	u64 aligned_off = off & ~0x3L;
+	u32 val32, mask, shift;
+	int rc;
+
+	rc = native_afu_cr_read32(afu, cr, aligned_off, &val32);
+	if (rc)
+		return rc;
+	shift = (off & 0x3) * 8;
+	mask = 0xff << shift;
+	val32 = (val32 & ~mask) | (in << shift);
+
+	rc = native_afu_cr_write32(afu, cr, aligned_off, val32);
+	return rc;
+}
+
+const struct cxl_backend_ops cxl_native_ops = {
+	.module = THIS_MODULE,
+	.adapter_reset = cxl_pci_reset,
+	.alloc_one_irq = cxl_pci_alloc_one_irq,
+	.release_one_irq = cxl_pci_release_one_irq,
+	.alloc_irq_ranges = cxl_pci_alloc_irq_ranges,
+	.release_irq_ranges = cxl_pci_release_irq_ranges,
+	.setup_irq = cxl_pci_setup_irq,
+	.handle_psl_slice_error = native_handle_psl_slice_error,
+	.psl_interrupt = NULL,
+	.ack_irq = native_ack_irq,
+	.irq_wait = native_irq_wait,
+	.attach_process = native_attach_process,
+	.detach_process = native_detach_process,
+	.support_attributes = native_support_attributes,
+	.link_ok = cxl_adapter_link_ok,
+	.release_afu = cxl_pci_release_afu,
+	.afu_read_err_buffer = cxl_pci_afu_read_err_buffer,
+	.afu_check_and_enable = native_afu_check_and_enable,
+	.afu_activate_mode = native_afu_activate_mode,
+	.afu_deactivate_mode = native_afu_deactivate_mode,
+	.afu_reset = native_afu_reset,
+	.afu_cr_read8 = native_afu_cr_read8,
+	.afu_cr_read16 = native_afu_cr_read16,
+	.afu_cr_read32 = native_afu_cr_read32,
+	.afu_cr_read64 = native_afu_cr_read64,
+	.afu_cr_write8 = native_afu_cr_write8,
+	.afu_cr_write16 = native_afu_cr_write16,
+	.afu_cr_write32 = native_afu_cr_write32,
+	.read_adapter_vpd = cxl_pci_read_adapter_vpd,
+};
--- linux-4.4.0.orig/drivers/misc/cxl/of.c
+++ linux-4.4.0/drivers/misc/cxl/of.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#include "cxl.h"
+
+
+static const __be32 *read_prop_string(const struct device_node *np,
+				const char *prop_name)
+{
+	const __be32 *prop;
+
+	prop = of_get_property(np, prop_name, NULL);
+	if (cxl_verbose && prop)
+		pr_info("%s: %s\n", prop_name, (char *) prop);
+	return prop;
+}
+
+static const __be32 *read_prop_dword(const struct device_node *np,
+				const char *prop_name, u32 *val)
+{
+	const __be32 *prop;
+
+	prop = of_get_property(np, prop_name, NULL);
+	if (prop)
+		*val = be32_to_cpu(prop[0]);
+	if (cxl_verbose && prop)
+		pr_info("%s: %#x (%u)\n", prop_name, *val, *val);
+	return prop;
+}
+
+static const __be64 *read_prop64_dword(const struct device_node *np,
+				const char *prop_name, u64 *val)
+{
+	const __be64 *prop;
+
+	prop = of_get_property(np, prop_name, NULL);
+	if (prop)
+		*val = be64_to_cpu(prop[0]);
+	if (cxl_verbose && prop)
+		pr_info("%s: %#llx (%llu)\n", prop_name, *val, *val);
+	return prop;
+}
+
+
+static int read_handle(struct device_node *np, u64 *handle)
+{
+	const __be32 *prop;
+	u64 size;
+
+	/* Get address and size of the node */
+	prop = of_get_address(np, 0, &size, NULL);
+	if (size)
+		return -EINVAL;
+
+	/* Helper to read a big number; size is in cells (not bytes) */
+	*handle = of_read_number(prop, of_n_addr_cells(np));
+	return 0;
+}
+
+static int read_phys_addr(struct device_node *np, char *prop_name,
+			struct cxl_afu *afu)
+{
+	int i, len, entry_size, naddr, nsize, type;
+	u64 addr, size;
+	const __be32 *prop;
+
+	naddr = of_n_addr_cells(np);
+	nsize = of_n_size_cells(np);
+
+	prop = of_get_property(np, prop_name, &len);
+	if (prop) {
+		entry_size = naddr + nsize;
+		for (i = 0; i < (len / 4); i += entry_size, prop += entry_size) {
+			type = be32_to_cpu(prop[0]);
+			addr = of_read_number(prop, naddr);
+			size = of_read_number(&prop[naddr], nsize);
+			switch (type) {
+			case 0: /* unit address */
+				afu->guest->handle = addr;
+				break;
+			case 1: /* p2 area */
+				afu->guest->p2n_phys += addr;
+				afu->guest->p2n_size = size;
+				break;
+			case 2: /* problem state area */
+				afu->psn_phys += addr;
+				afu->adapter->ps_size = size;
+				break;
+			default:
+				pr_err("Invalid address type %d found in %s property of AFU\n",
+					type, prop_name);
+				return -EINVAL;
+			}
+			if (cxl_verbose)
+				pr_info("%s: %#x %#llx (size %#llx)\n",
+					prop_name, type, addr, size);
+		}
+	}
+	return 0;
+}
+
+static int read_vpd(struct cxl *adapter, struct cxl_afu *afu)
+{
+	char vpd[256];
+	int rc;
+	size_t len = sizeof(vpd);
+
+	memset(vpd, 0, len);
+
+	if (adapter)
+		rc = cxl_guest_read_adapter_vpd(adapter, vpd, len);
+	else
+		rc = cxl_guest_read_afu_vpd(afu, vpd, len);
+
+	if (rc > 0) {
+		cxl_dump_debug_buffer(vpd, rc);
+		rc = 0;
+	}
+	return rc;
+}
+
+int cxl_of_read_afu_handle(struct cxl_afu *afu, struct device_node *afu_np)
+{
+	if (read_handle(afu_np, &afu->guest->handle))
+		return -EINVAL;
+	pr_devel("AFU handle: 0x%.16llx\n", afu->guest->handle);
+
+	return 0;
+}
+
+int cxl_of_read_afu_properties(struct cxl_afu *afu, struct device_node *np)
+{
+	int i, len, rc;
+	char *p;
+	const __be32 *prop;
+	u16 device_id, vendor_id;
+	u32 val = 0, class_code;
+
+	/* Properties are read in the same order as listed in PAPR */
+
+	if (cxl_verbose) {
+		pr_info("Dump of the 'ibm,coherent-platform-function' node properties:\n");
+
+		prop = of_get_property(np, "compatible", &len);
+		i = 0;
+		while (i < len) {
+			p = (char *) prop + i;
+			pr_info("compatible: %s\n", p);
+			i += strlen(p) + 1;
+		}
+		read_prop_string(np, "name");
+	}
+
+	rc = read_phys_addr(np, "reg", afu);
+	if (rc)
+		return rc;
+
+	rc = read_phys_addr(np, "assigned-addresses", afu);
+	if (rc)
+		return rc;
+
+	if (afu->psn_phys == 0)
+		afu->psa = false;
+	else
+		afu->psa = true;
+
+	if (cxl_verbose) {
+		read_prop_string(np, "ibm,loc-code");
+		read_prop_string(np, "device_type");
+	}
+
+	read_prop_dword(np, "ibm,#processes", &afu->max_procs_virtualised);
+
+	if (cxl_verbose) {
+		read_prop_dword(np, "ibm,scratchpad-size", &val);
+		read_prop_dword(np, "ibm,programmable", &val);
+		read_prop_string(np, "ibm,phandle");
+		read_vpd(NULL, afu);
+	}
+
+	read_prop_dword(np, "ibm,max-ints-per-process", &afu->guest->max_ints);
+	afu->irqs_max = afu->guest->max_ints;
+
+	prop = read_prop_dword(np, "ibm,min-ints-per-process", &afu->pp_irqs);
+	if (prop) {
+		/* One extra interrupt for the PSL interrupt is already
+		 * included. Remove it now to keep only AFU interrupts and
+		 * match the native case.
+		 */
+		afu->pp_irqs--;
+	}
+
+	if (cxl_verbose) {
+		read_prop_dword(np, "ibm,max-ints", &val);
+		read_prop_dword(np, "ibm,vpd-size", &val);
+	}
+
+	read_prop64_dword(np, "ibm,error-buffer-size", &afu->eb_len);
+	afu->eb_offset = 0;
+
+	if (cxl_verbose)
+		read_prop_dword(np, "ibm,config-record-type", &val);
+
+	read_prop64_dword(np, "ibm,config-record-size", &afu->crs_len);
+	afu->crs_offset = 0;
+
+	read_prop_dword(np, "ibm,#config-records", &afu->crs_num);
+
+	if (cxl_verbose) {
+		for (i = 0; i < afu->crs_num; i++) {
+			rc = cxl_ops->afu_cr_read16(afu, i, PCI_DEVICE_ID,
+						&device_id);
+			if (!rc)
+				pr_info("record %d - device-id: %#x\n",
+					i, device_id);
+			rc = cxl_ops->afu_cr_read16(afu, i, PCI_VENDOR_ID,
+						&vendor_id);
+			if (!rc)
+				pr_info("record %d - vendor-id: %#x\n",
+					i, vendor_id);
+			rc = cxl_ops->afu_cr_read32(afu, i, PCI_CLASS_REVISION,
+						&class_code);
+			if (!rc) {
+				class_code >>= 8;
+				pr_info("record %d - class-code: %#x\n",
+					i, class_code);
+			}
+		}
+
+		read_prop_dword(np, "ibm,function-number", &val);
+		read_prop_dword(np, "ibm,privileged-function", &val);
+		read_prop_dword(np, "vendor-id", &val);
+		read_prop_dword(np, "device-id", &val);
+		read_prop_dword(np, "revision-id", &val);
+		read_prop_dword(np, "class-code", &val);
+		read_prop_dword(np, "subsystem-vendor-id", &val);
+		read_prop_dword(np, "subsystem-id", &val);
+	}
+	/*
+	 * if "ibm,process-mmio" doesn't exist then per-process mmio is
+	 * not supported
+	 */
+	val = 0;
+	prop = read_prop_dword(np, "ibm,process-mmio", &val);
+	if (prop && val == 1)
+		afu->pp_psa = true;
+	else
+		afu->pp_psa = false;
+
+	if (cxl_verbose) {
+		read_prop_dword(np, "ibm,supports-aur", &val);
+		read_prop_dword(np, "ibm,supports-csrp", &val);
+		read_prop_dword(np, "ibm,supports-prr", &val);
+	}
+
+	prop = read_prop_dword(np, "ibm,function-error-interrupt", &val);
+	if (prop)
+		afu->serr_hwirq = val;
+
+	pr_devel("AFU handle: %#llx\n", afu->guest->handle);
+	pr_devel("p2n_phys: %#llx (size %#llx)\n",
+		afu->guest->p2n_phys, afu->guest->p2n_size);
+	pr_devel("psn_phys: %#llx (size %#llx)\n",
+		afu->psn_phys, afu->adapter->ps_size);
+	pr_devel("Max number of processes virtualised=%i\n",
+		afu->max_procs_virtualised);
+	pr_devel("Per-process irqs min=%i, max=%i\n", afu->pp_irqs,
+		 afu->irqs_max);
+	pr_devel("Slice error interrupt=%#lx\n", afu->serr_hwirq);
+
+	return 0;
+}
+
+static int read_adapter_irq_config(struct cxl *adapter, struct device_node *np)
+{
+	const __be32 *ranges;
+	int len, nranges, i;
+	struct irq_avail *cur;
+
+	ranges = of_get_property(np, "interrupt-ranges", &len);
+	if (ranges == NULL || len < (2 * sizeof(int)))
+		return -EINVAL;
+
+	/*
+	 * encoded array of two cells per entry, each cell encoded as
+	 * with encode-int
+	 */
+	nranges = len / (2 * sizeof(int));
+	if (nranges == 0 || (nranges * 2 * sizeof(int)) != len)
+		return -EINVAL;
+
+	adapter->guest->irq_avail = kzalloc(nranges * sizeof(struct irq_avail),
+					    GFP_KERNEL);
+	if (adapter->guest->irq_avail == NULL)
+		return -ENOMEM;
+
+	adapter->guest->irq_base_offset = be32_to_cpu(ranges[0]);
+	for (i = 0; i < nranges; i++) {
+		cur = &adapter->guest->irq_avail[i];
+		cur->offset = be32_to_cpu(ranges[i * 2]);
+		cur->range  = be32_to_cpu(ranges[i * 2 + 1]);
+		cur->bitmap = kcalloc(BITS_TO_LONGS(cur->range),
+				sizeof(*cur->bitmap), GFP_KERNEL);
+		if (cur->bitmap == NULL)
+			goto err;
+		if (cur->offset < adapter->guest->irq_base_offset)
+			adapter->guest->irq_base_offset = cur->offset;
+		if (cxl_verbose)
+			pr_info("available IRQ range: %#lx-%#lx (%lu)\n",
+				cur->offset, cur->offset + cur->range - 1,
+				cur->range);
+	}
+	adapter->guest->irq_nranges = nranges;
+	spin_lock_init(&adapter->guest->irq_alloc_lock);
+
+	return 0;
+err:
+	for (i--; i >= 0; i--) {
+		cur = &adapter->guest->irq_avail[i];
+		kfree(cur->bitmap);
+	}
+	kfree(adapter->guest->irq_avail);
+	adapter->guest->irq_avail = NULL;
+	return -ENOMEM;
+}
+
+int cxl_of_read_adapter_handle(struct cxl *adapter, struct device_node *np)
+{
+	if (read_handle(np, &adapter->guest->handle))
+		return -EINVAL;
+	pr_devel("Adapter handle: 0x%.16llx\n", adapter->guest->handle);
+
+	return 0;
+}
+
+int cxl_of_read_adapter_properties(struct cxl *adapter, struct device_node *np)
+{
+	int rc, len, naddr, i;
+	char *p;
+	const __be32 *prop;
+	u32 val = 0;
+
+	/* Properties are read in the same order as listed in PAPR */
+
+	naddr = of_n_addr_cells(np);
+
+	if (cxl_verbose) {
+		pr_info("Dump of the 'ibm,coherent-platform-facility' node properties:\n");
+
+		read_prop_dword(np, "#address-cells", &val);
+		read_prop_dword(np, "#size-cells", &val);
+
+		prop = of_get_property(np, "compatible", &len);
+		i = 0;
+		while (i < len) {
+			p = (char *) prop + i;
+			pr_info("compatible: %s\n", p);
+			i += strlen(p) + 1;
+		}
+		read_prop_string(np, "name");
+		read_prop_string(np, "model");
+
+		prop = of_get_property(np, "reg", NULL);
+		if (prop) {
+			pr_info("reg: addr:%#llx size:%#x\n",
+				of_read_number(prop, naddr),
+				be32_to_cpu(prop[naddr]));
+		}
+
+		read_prop_string(np, "ibm,loc-code");
+	}
+
+	if ((rc = read_adapter_irq_config(adapter, np)))
+		return rc;
+
+	if (cxl_verbose) {
+		read_prop_string(np, "device_type");
+		read_prop_string(np, "ibm,phandle");
+	}
+
+	prop = read_prop_dword(np, "ibm,caia-version", &val);
+	if (prop) {
+		adapter->caia_major = (val & 0xFF00) >> 8;
+		adapter->caia_minor = val & 0xFF;
+	}
+
+	prop = read_prop_dword(np, "ibm,psl-revision", &val);
+	if (prop)
+		adapter->psl_rev = val;
+
+	prop = read_prop_string(np, "status");
+	if (prop) {
+		adapter->guest->status = kasprintf(GFP_KERNEL, "%s", (char *) prop);
+		if (adapter->guest->status == NULL)
+			return -ENOMEM;
+	}
+
+	prop = read_prop_dword(np, "vendor-id", &val);
+	if (prop)
+		adapter->guest->vendor = val;
+
+	prop = read_prop_dword(np, "device-id", &val);
+	if (prop)
+		adapter->guest->device = val;
+
+	if (cxl_verbose) {
+		read_prop_dword(np, "ibm,privileged-facility", &val);
+		read_prop_dword(np, "revision-id", &val);
+		read_prop_dword(np, "class-code", &val);
+	}
+
+	prop = read_prop_dword(np, "subsystem-vendor-id", &val);
+	if (prop)
+		adapter->guest->subsystem_vendor = val;
+
+	prop = read_prop_dword(np, "subsystem-id", &val);
+	if (prop)
+		adapter->guest->subsystem = val;
+
+	if (cxl_verbose)
+		read_vpd(adapter, NULL);
+
+	return 0;
+}
+
+static int cxl_of_remove(struct platform_device *pdev)
+{
+	struct cxl *adapter;
+	int afu;
+
+	adapter = dev_get_drvdata(&pdev->dev);
+	for (afu = 0; afu < adapter->slices; afu++)
+		cxl_guest_remove_afu(adapter->afu[afu]);
+
+	cxl_guest_remove_adapter(adapter);
+	return 0;
+}
+
+static void cxl_of_shutdown(struct platform_device *pdev)
+{
+	cxl_of_remove(pdev);
+}
+
+int cxl_of_probe(struct platform_device *pdev)
+{
+	struct device_node *np = NULL;
+	struct device_node *afu_np = NULL;
+	struct cxl *adapter = NULL;
+	int ret;
+	int slice, slice_ok;
+
+	pr_devel("in %s\n", __func__);
+
+	np = pdev->dev.of_node;
+	if (np == NULL)
+		return -ENODEV;
+
+	/* init adapter */
+	adapter = cxl_guest_init_adapter(np, pdev);
+	if (IS_ERR(adapter)) {
+		dev_err(&pdev->dev, "guest_init_adapter failed: %li\n", PTR_ERR(adapter));
+		return PTR_ERR(adapter);
+	}
+
+	/* init afu */
+	slice_ok = 0;
+	for (afu_np = NULL, slice = 0; (afu_np = of_get_next_child(np, afu_np)); slice++) {
+		if ((ret = cxl_guest_init_afu(adapter, slice, afu_np)))
+			dev_err(&pdev->dev, "AFU %i failed to initialise: %i\n",
+				slice, ret);
+		else
+			slice_ok++;
+	}
+
+	if (slice_ok == 0) {
+		dev_info(&pdev->dev, "No active AFU");
+		adapter->slices = 0;
+	}
+
+	if (afu_np)
+		of_node_put(afu_np);
+	return 0;
+}
+
+static const struct of_device_id cxl_of_match[] = {
+	{ .compatible = "ibm,coherent-platform-facility",},
+	{},
+};
+MODULE_DEVICE_TABLE(of, cxl_of_match);
+
+struct platform_driver cxl_of_driver = {
+	.driver = {
+		.name = "cxl_of",
+		.of_match_table = cxl_of_match,
+		.owner = THIS_MODULE
+	},
+	.probe = cxl_of_probe,
+	.remove = cxl_of_remove,
+	.shutdown = cxl_of_shutdown,
+};
--- linux-4.4.0.orig/drivers/misc/cxl/pci.c
+++ linux-4.4.0/drivers/misc/cxl/pci.c
@@ -22,6 +22,7 @@
 #include <asm/pci-bridge.h> /* for struct pci_controller */
 #include <asm/pnv-pci.h>
 #include <asm/io.h>
+#include <asm/reg.h>
 
 #include "cxl.h"
 #include <misc/cxl.h>
@@ -90,8 +91,8 @@
 
 /* This works a little different than the p1/p2 register accesses to make it
  * easier to pull out individual fields */
-#define AFUD_READ(afu, off)		in_be64(afu->afu_desc_mmio + off)
-#define AFUD_READ_LE(afu, off)		in_le64(afu->afu_desc_mmio + off)
+#define AFUD_READ(afu, off)		in_be64(afu->native->afu_desc_mmio + off)
+#define AFUD_READ_LE(afu, off)		in_le64(afu->native->afu_desc_mmio + off)
 #define EXTRACT_PPC_BIT(val, bit)	(!!(val & PPC_BIT(bit)))
 #define EXTRACT_PPC_BITS(val, bs, be)	((val & PPC_BITMASK(bs, be)) >> PPC_BITLSHIFT(be))
 
@@ -116,28 +117,11 @@
 #define   AFUD_EB_LEN(val)		EXTRACT_PPC_BITS(val, 8, 63)
 #define AFUD_READ_EB_OFF(afu)		AFUD_READ(afu, 0x48)
 
-u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off)
-{
-	u64 aligned_off = off & ~0x3L;
-	u32 val;
-
-	val = cxl_afu_cr_read32(afu, cr, aligned_off);
-	return (val >> ((off & 0x2) * 8)) & 0xffff;
-}
-
-u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off)
-{
-	u64 aligned_off = off & ~0x3L;
-	u32 val;
-
-	val = cxl_afu_cr_read32(afu, cr, aligned_off);
-	return (val >> ((off & 0x3) * 8)) & 0xff;
-}
-
 static const struct pci_device_id cxl_pci_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0477), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x044b), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x04cf), },
+	{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0601), },
 	{ PCI_DEVICE_CLASS(0x120000, ~0), },
 
 	{ }
@@ -339,12 +323,43 @@
 #undef show_reg
 }
 
+#define CAPP_UNIT0_ID 0xBA
+#define CAPP_UNIT1_ID 0XBE
+
+static u64 get_capp_unit_id(struct device_node *np)
+{
+	u32 phb_index;
+
+	/*
+	 * For chips other than POWER8NVL, we only have CAPP 0,
+	 * irrespective of which PHB is used.
+	 */
+	if (!pvr_version_is(PVR_POWER8NVL))
+		return CAPP_UNIT0_ID;
+
+	/*
+	 * For POWER8NVL, assume CAPP 0 is attached to PHB0 and
+	 * CAPP 1 is attached to PHB1.
+	 */
+	if (of_property_read_u32(np, "ibm,phb-index", &phb_index))
+		return 0;
+
+	if (phb_index == 0)
+		return CAPP_UNIT0_ID;
+
+	if (phb_index == 1)
+		return CAPP_UNIT1_ID;
+
+	return 0;
+}
+
 static int init_implementation_adapter_regs(struct cxl *adapter, struct pci_dev *dev)
 {
 	struct device_node *np;
 	const __be32 *prop;
-	u64 psl_dsnctl;
+	u64 psl_dsnctl, psl_fircntl;
 	u64 chipid;
+	u64 capp_unit_id;
 
 	if (!(np = pnv_pci_get_phb_node(dev)))
 		return -ENODEV;
@@ -354,16 +369,28 @@
 	if (!np)
 		return -ENODEV;
 	chipid = be32_to_cpup(prop);
+	capp_unit_id = get_capp_unit_id(np);
 	of_node_put(np);
+	if (!capp_unit_id) {
+		pr_err("cxl: invalid capp unit id\n");
+		return -ENODEV;
+	}
 
+	psl_dsnctl = 0x0000900000000000ULL; /* pteupd ttype, scdone */
+	psl_dsnctl |= (0x2ULL << (63-38)); /* MMIO hang pulse: 256 us */
 	/* Tell PSL where to route data to */
-	psl_dsnctl = 0x02E8900002000000ULL | (chipid << (63-5));
+	psl_dsnctl |= (chipid << (63-5));
+	psl_dsnctl |= (capp_unit_id << (63-13));
+
 	cxl_p1_write(adapter, CXL_PSL_DSNDCTL, psl_dsnctl);
 	cxl_p1_write(adapter, CXL_PSL_RESLCKTO, 0x20000000200ULL);
 	/* snoop write mask */
 	cxl_p1_write(adapter, CXL_PSL_SNWRALLOC, 0x00000000FFFFFFFFULL);
-	/* set fir_accum */
-	cxl_p1_write(adapter, CXL_PSL_FIR_CNTL, 0x0800000000000000ULL);
+	/* set fir_cntl to recommended value for production env */
+	psl_fircntl = (0x2ULL << (63-3)); /* ce_report */
+	psl_fircntl |= (0x1ULL << (63-6)); /* FIR_report */
+	psl_fircntl |= 0x1ULL; /* ce_thresh */
+	cxl_p1_write(adapter, CXL_PSL_FIR_CNTL, psl_fircntl);
 	/* for debugging with trace arrays */
 	cxl_p1_write(adapter, CXL_PSL_TRACE, 0x0000FF7C00000000ULL);
 
@@ -373,22 +400,24 @@
 #define TBSYNC_CNT(n) (((u64)n & 0x7) << (63-6))
 #define _2048_250MHZ_CYCLES 1
 
-static int cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
+static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
 {
 	u64 psl_tb;
 	int delta;
 	unsigned int retry = 0;
 	struct device_node *np;
 
+	adapter->psl_timebase_synced = false;
+
 	if (!(np = pnv_pci_get_phb_node(dev)))
-		return -ENODEV;
+		return;
 
 	/* Do not fail when CAPP timebase sync is not supported by OPAL */
 	of_node_get(np);
 	if (! of_get_property(np, "ibm,capp-timebase-sync", NULL)) {
 		of_node_put(np);
-		pr_err("PSL: Timebase sync: OPAL support missing\n");
-		return 0;
+		dev_info(&dev->dev, "PSL timebase inactive: OPAL support missing\n");
+		return;
 	}
 	of_node_put(np);
 
@@ -407,16 +436,17 @@
 	do {
 		msleep(1);
 		if (retry++ > 5) {
-			pr_err("PSL: Timebase sync: giving up!\n");
-			return -EIO;
+			dev_info(&dev->dev, "PSL timebase can't synchronize\n");
+			return;
 		}
 		psl_tb = cxl_p1_read(adapter, CXL_PSL_Timebase);
 		delta = mftb() - psl_tb;
 		if (delta < 0)
 			delta = -delta;
-	} while (cputime_to_usecs(delta) > 16);
+	} while (tb_to_ns(delta) > 16000);
 
-	return 0;
+	adapter->psl_timebase_synced = true;
+	return;
 }
 
 static int init_implementation_afu_regs(struct cxl_afu *afu)
@@ -432,8 +462,8 @@
 	return 0;
 }
 
-int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq,
-			 unsigned int virq)
+int cxl_pci_setup_irq(struct cxl *adapter, unsigned int hwirq,
+		unsigned int virq)
 {
 	struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
 
@@ -475,28 +505,30 @@
 	return 0;
 }
 
-int cxl_alloc_one_irq(struct cxl *adapter)
+int cxl_pci_alloc_one_irq(struct cxl *adapter)
 {
 	struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
 
 	return pnv_cxl_alloc_hwirqs(dev, 1);
 }
 
-void cxl_release_one_irq(struct cxl *adapter, int hwirq)
+void cxl_pci_release_one_irq(struct cxl *adapter, int hwirq)
 {
 	struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
 
 	return pnv_cxl_release_hwirqs(dev, hwirq, 1);
 }
 
-int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num)
+int cxl_pci_alloc_irq_ranges(struct cxl_irq_ranges *irqs,
+			struct cxl *adapter, unsigned int num)
 {
 	struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
 
 	return pnv_cxl_alloc_hwirq_ranges(irqs, dev, num);
 }
 
-void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter)
+void cxl_pci_release_irq_ranges(struct cxl_irq_ranges *irqs,
+				struct cxl *adapter)
 {
 	struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
 
@@ -557,7 +589,7 @@
 	return 0;
 }
 
-static int cxl_map_slice_regs(struct cxl_afu *afu, struct cxl *adapter, struct pci_dev *dev)
+static int pci_map_slice_regs(struct cxl_afu *afu, struct cxl *adapter, struct pci_dev *dev)
 {
 	u64 p1n_base, p2n_base, afu_desc;
 	const u64 p1n_size = 0x100;
@@ -565,15 +597,15 @@
 
 	p1n_base = p1_base(dev) + 0x10000 + (afu->slice * p1n_size);
 	p2n_base = p2_base(dev) + (afu->slice * p2n_size);
-	afu->psn_phys = p2_base(dev) + (adapter->ps_off + (afu->slice * adapter->ps_size));
-	afu_desc = p2_base(dev) + adapter->afu_desc_off + (afu->slice * adapter->afu_desc_size);
+	afu->psn_phys = p2_base(dev) + (adapter->native->ps_off + (afu->slice * adapter->ps_size));
+	afu_desc = p2_base(dev) + adapter->native->afu_desc_off + (afu->slice * adapter->native->afu_desc_size);
 
-	if (!(afu->p1n_mmio = ioremap(p1n_base, p1n_size)))
+	if (!(afu->native->p1n_mmio = ioremap(p1n_base, p1n_size)))
 		goto err;
 	if (!(afu->p2n_mmio = ioremap(p2n_base, p2n_size)))
 		goto err1;
 	if (afu_desc) {
-		if (!(afu->afu_desc_mmio = ioremap(afu_desc, adapter->afu_desc_size)))
+		if (!(afu->native->afu_desc_mmio = ioremap(afu_desc, adapter->native->afu_desc_size)))
 			goto err2;
 	}
 
@@ -581,62 +613,41 @@
 err2:
 	iounmap(afu->p2n_mmio);
 err1:
-	iounmap(afu->p1n_mmio);
+	iounmap(afu->native->p1n_mmio);
 err:
 	dev_err(&afu->dev, "Error mapping AFU MMIO regions\n");
 	return -ENOMEM;
 }
 
-static void cxl_unmap_slice_regs(struct cxl_afu *afu)
+static void pci_unmap_slice_regs(struct cxl_afu *afu)
 {
 	if (afu->p2n_mmio) {
 		iounmap(afu->p2n_mmio);
 		afu->p2n_mmio = NULL;
 	}
-	if (afu->p1n_mmio) {
-		iounmap(afu->p1n_mmio);
-		afu->p1n_mmio = NULL;
+	if (afu->native->p1n_mmio) {
+		iounmap(afu->native->p1n_mmio);
+		afu->native->p1n_mmio = NULL;
 	}
-	if (afu->afu_desc_mmio) {
-		iounmap(afu->afu_desc_mmio);
-		afu->afu_desc_mmio = NULL;
+	if (afu->native->afu_desc_mmio) {
+		iounmap(afu->native->afu_desc_mmio);
+		afu->native->afu_desc_mmio = NULL;
 	}
 }
 
-static void cxl_release_afu(struct device *dev)
+void cxl_pci_release_afu(struct device *dev)
 {
 	struct cxl_afu *afu = to_cxl_afu(dev);
 
-	pr_devel("cxl_release_afu\n");
+	pr_devel("%s\n", __func__);
 
 	idr_destroy(&afu->contexts_idr);
 	cxl_release_spa(afu);
 
+	kfree(afu->native);
 	kfree(afu);
 }
 
-static struct cxl_afu *cxl_alloc_afu(struct cxl *adapter, int slice)
-{
-	struct cxl_afu *afu;
-
-	if (!(afu = kzalloc(sizeof(struct cxl_afu), GFP_KERNEL)))
-		return NULL;
-
-	afu->adapter = adapter;
-	afu->dev.parent = &adapter->dev;
-	afu->dev.release = cxl_release_afu;
-	afu->slice = slice;
-	idr_init(&afu->contexts_idr);
-	mutex_init(&afu->contexts_lock);
-	spin_lock_init(&afu->afu_cntl_lock);
-	mutex_init(&afu->spa_mutex);
-
-	afu->prefault_mode = CXL_PREFAULT_NONE;
-	afu->irqs_max = afu->adapter->user_irqs;
-
-	return afu;
-}
-
 /* Expects AFU struct to have recently been zeroed out */
 static int cxl_read_afu_descriptor(struct cxl_afu *afu)
 {
@@ -658,7 +669,7 @@
 	afu->pp_size = AFUD_PPPSA_LEN(val) * 4096;
 	afu->psa = AFUD_PPPSA_PSA(val);
 	if ((afu->pp_psa = AFUD_PPPSA_PP(val)))
-		afu->pp_offset = AFUD_READ_PPPSA_OFF(afu);
+		afu->native->pp_offset = AFUD_READ_PPPSA_OFF(afu);
 
 	val = AFUD_READ_CR(afu);
 	afu->crs_len = AFUD_CR_LEN(val) * 256;
@@ -685,10 +696,11 @@
 
 static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu)
 {
-	int i;
+	int i, rc;
+	u32 val;
 
 	if (afu->psa && afu->adapter->ps_size <
-			(afu->pp_offset + afu->pp_size*afu->max_procs_virtualised)) {
+			(afu->native->pp_offset + afu->pp_size*afu->max_procs_virtualised)) {
 		dev_err(&afu->dev, "per-process PSA can't fit inside the PSA!\n");
 		return -ENODEV;
 	}
@@ -697,7 +709,8 @@
 		dev_warn(&afu->dev, "AFU uses < PAGE_SIZE per-process PSA!");
 
 	for (i = 0; i < afu->crs_num; i++) {
-		if ((cxl_afu_cr_read32(afu, i, 0) == 0)) {
+		rc = cxl_ops->afu_cr_read32(afu, i, 0, &val);
+		if (rc || val == 0) {
 			dev_err(&afu->dev, "ABORTING: AFU configuration record %i is invalid\n", i);
 			return -EINVAL;
 		}
@@ -718,7 +731,7 @@
 	reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
 	if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) {
 		dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#016llx\n", reg);
-		if (__cxl_afu_reset(afu))
+		if (cxl_ops->afu_reset(afu))
 			return -EIO;
 		if (cxl_afu_disable(afu))
 			return -EIO;
@@ -766,13 +779,13 @@
  * 4/8 bytes aligned access. So in case the requested offset/count arent 8 byte
  * aligned the function uses a bounce buffer which can be max PAGE_SIZE.
  */
-ssize_t cxl_afu_read_err_buffer(struct cxl_afu *afu, char *buf,
+ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf,
 				loff_t off, size_t count)
 {
 	loff_t aligned_start, aligned_end;
 	size_t aligned_length;
 	void *tbuf;
-	const void __iomem *ebuf = afu->afu_desc_mmio + afu->eb_offset;
+	const void __iomem *ebuf = afu->native->afu_desc_mmio + afu->eb_offset;
 
 	if (count == 0 || off < 0 || (size_t)off >= afu->eb_len)
 		return 0;
@@ -803,18 +816,18 @@
 	return count;
 }
 
-static int cxl_configure_afu(struct cxl_afu *afu, struct cxl *adapter, struct pci_dev *dev)
+static int pci_configure_afu(struct cxl_afu *afu, struct cxl *adapter, struct pci_dev *dev)
 {
 	int rc;
 
-	if ((rc = cxl_map_slice_regs(afu, adapter, dev)))
+	if ((rc = pci_map_slice_regs(afu, adapter, dev)))
 		return rc;
 
 	if ((rc = sanitise_afu_regs(afu)))
 		goto err1;
 
 	/* We need to reset the AFU before we can read the AFU descriptor */
-	if ((rc = __cxl_afu_reset(afu)))
+	if ((rc = cxl_ops->afu_reset(afu)))
 		goto err1;
 
 	if (cxl_verbose)
@@ -829,44 +842,50 @@
 	if ((rc = init_implementation_afu_regs(afu)))
 		goto err1;
 
-	if ((rc = cxl_register_serr_irq(afu)))
+	if ((rc = cxl_native_register_serr_irq(afu)))
 		goto err1;
 
-	if ((rc = cxl_register_psl_irq(afu)))
+	if ((rc = cxl_native_register_psl_irq(afu)))
 		goto err2;
 
 	return 0;
 
 err2:
-	cxl_release_serr_irq(afu);
+	cxl_native_release_serr_irq(afu);
 err1:
-	cxl_unmap_slice_regs(afu);
+	pci_unmap_slice_regs(afu);
 	return rc;
 }
 
-static void cxl_deconfigure_afu(struct cxl_afu *afu)
+static void pci_deconfigure_afu(struct cxl_afu *afu)
 {
-	cxl_release_psl_irq(afu);
-	cxl_release_serr_irq(afu);
-	cxl_unmap_slice_regs(afu);
+	cxl_native_release_psl_irq(afu);
+	cxl_native_release_serr_irq(afu);
+	pci_unmap_slice_regs(afu);
 }
 
-static int cxl_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev)
+static int pci_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev)
 {
 	struct cxl_afu *afu;
-	int rc;
+	int rc = -ENOMEM;
 
 	afu = cxl_alloc_afu(adapter, slice);
 	if (!afu)
 		return -ENOMEM;
 
+	afu->native = kzalloc(sizeof(struct cxl_afu_native), GFP_KERNEL);
+	if (!afu->native)
+		goto err_free_afu;
+
+	mutex_init(&afu->native->spa_mutex);
+
 	rc = dev_set_name(&afu->dev, "afu%i.%i", adapter->adapter_num, slice);
 	if (rc)
-		goto err_free;
+		goto err_free_native;
 
-	rc = cxl_configure_afu(afu, adapter, dev);
+	rc = pci_configure_afu(afu, adapter, dev);
 	if (rc)
-		goto err_free;
+		goto err_free_native;
 
 	/* Don't care if this fails */
 	cxl_debugfs_afu_add(afu);
@@ -889,24 +908,27 @@
 	return 0;
 
 err_put1:
-	cxl_deconfigure_afu(afu);
+	pci_deconfigure_afu(afu);
 	cxl_debugfs_afu_remove(afu);
 	device_unregister(&afu->dev);
 	return rc;
 
-err_free:
+err_free_native:
+	kfree(afu->native);
+err_free_afu:
 	kfree(afu);
 	return rc;
 
 }
 
-static void cxl_remove_afu(struct cxl_afu *afu)
+static void cxl_pci_remove_afu(struct cxl_afu *afu)
 {
-	pr_devel("cxl_remove_afu\n");
+	pr_devel("%s\n", __func__);
 
 	if (!afu)
 		return;
 
+	cxl_pci_vphb_remove(afu);
 	cxl_sysfs_afu_remove(afu);
 	cxl_debugfs_afu_remove(afu);
 
@@ -915,13 +937,13 @@
 	spin_unlock(&afu->adapter->afu_list_lock);
 
 	cxl_context_detach_all(afu);
-	cxl_afu_deactivate_mode(afu);
+	cxl_ops->afu_deactivate_mode(afu, afu->current_mode);
 
-	cxl_deconfigure_afu(afu);
+	pci_deconfigure_afu(afu);
 	device_unregister(&afu->dev);
 }
 
-int cxl_reset(struct cxl *adapter)
+int cxl_pci_reset(struct cxl *adapter)
 {
 	struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
 	int rc;
@@ -934,6 +956,9 @@
 
 	dev_info(&dev->dev, "CXL reset\n");
 
+	/* the adapter is about to be reset, so ignore errors */
+	cxl_data_cache_flush(adapter);
+
 	/* pcie_warm_reset requests a fundamental pci reset which includes a
 	 * PERST assert/deassert.  PERST triggers a loading of the image
 	 * if "user" or "factory" is selected in sysfs */
@@ -955,17 +980,17 @@
 	pr_devel("cxl_map_adapter_regs: p1: %#016llx %#llx, p2: %#016llx %#llx",
 			p1_base(dev), p1_size(dev), p2_base(dev), p2_size(dev));
 
-	if (!(adapter->p1_mmio = ioremap(p1_base(dev), p1_size(dev))))
+	if (!(adapter->native->p1_mmio = ioremap(p1_base(dev), p1_size(dev))))
 		goto err3;
 
-	if (!(adapter->p2_mmio = ioremap(p2_base(dev), p2_size(dev))))
+	if (!(adapter->native->p2_mmio = ioremap(p2_base(dev), p2_size(dev))))
 		goto err4;
 
 	return 0;
 
 err4:
-	iounmap(adapter->p1_mmio);
-	adapter->p1_mmio = NULL;
+	iounmap(adapter->native->p1_mmio);
+	adapter->native->p1_mmio = NULL;
 err3:
 	pci_release_region(dev, 0);
 err2:
@@ -976,14 +1001,14 @@
 
 static void cxl_unmap_adapter_regs(struct cxl *adapter)
 {
-	if (adapter->p1_mmio) {
-		iounmap(adapter->p1_mmio);
-		adapter->p1_mmio = NULL;
+	if (adapter->native->p1_mmio) {
+		iounmap(adapter->native->p1_mmio);
+		adapter->native->p1_mmio = NULL;
 		pci_release_region(to_pci_dev(adapter->dev.parent), 2);
 	}
-	if (adapter->p2_mmio) {
-		iounmap(adapter->p2_mmio);
-		adapter->p2_mmio = NULL;
+	if (adapter->native->p2_mmio) {
+		iounmap(adapter->native->p2_mmio);
+		adapter->native->p2_mmio = NULL;
 		pci_release_region(to_pci_dev(adapter->dev.parent), 0);
 	}
 }
@@ -1024,10 +1049,10 @@
 
 	/* Convert everything to bytes, because there is NO WAY I'd look at the
 	 * code a month later and forget what units these are in ;-) */
-	adapter->ps_off = ps_off * 64 * 1024;
+	adapter->native->ps_off = ps_off * 64 * 1024;
 	adapter->ps_size = ps_size * 64 * 1024;
-	adapter->afu_desc_off = afu_desc_off * 64 * 1024;
-	adapter->afu_desc_size = afu_desc_size *64 * 1024;
+	adapter->native->afu_desc_off = afu_desc_off * 64 * 1024;
+	adapter->native->afu_desc_size = afu_desc_size * 64 * 1024;
 
 	/* Total IRQs - 1 PSL ERROR - #AFU*(1 slice error + 1 DSI) */
 	adapter->user_irqs = pnv_cxl_get_irq_count(dev) - 1 - 2*adapter->slices;
@@ -1078,21 +1103,26 @@
 		return -EINVAL;
 	}
 
-	if (!adapter->afu_desc_off || !adapter->afu_desc_size) {
+	if (!adapter->native->afu_desc_off || !adapter->native->afu_desc_size) {
 		dev_err(&dev->dev, "ABORTING: VSEC shows no AFU descriptors\n");
 		return -EINVAL;
 	}
 
-	if (adapter->ps_size > p2_size(dev) - adapter->ps_off) {
+	if (adapter->ps_size > p2_size(dev) - adapter->native->ps_off) {
 		dev_err(&dev->dev, "ABORTING: Problem state size larger than "
 				   "available in BAR2: 0x%llx > 0x%llx\n",
-			 adapter->ps_size, p2_size(dev) - adapter->ps_off);
+			 adapter->ps_size, p2_size(dev) - adapter->native->ps_off);
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
+ssize_t cxl_pci_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len)
+{
+	return pci_read_vpd(to_pci_dev(adapter->dev.parent), 0, len, buf);
+}
+
 static void cxl_release_adapter(struct device *dev)
 {
 	struct cxl *adapter = to_cxl_adapter(dev);
@@ -1101,33 +1131,10 @@
 
 	cxl_remove_adapter_nr(adapter);
 
+	kfree(adapter->native);
 	kfree(adapter);
 }
 
-static struct cxl *cxl_alloc_adapter(void)
-{
-	struct cxl *adapter;
-
-	if (!(adapter = kzalloc(sizeof(struct cxl), GFP_KERNEL)))
-		return NULL;
-
-	spin_lock_init(&adapter->afu_list_lock);
-
-	if (cxl_alloc_adapter_nr(adapter))
-		goto err1;
-
-	if (dev_set_name(&adapter->dev, "card%i", adapter->adapter_num))
-		goto err2;
-
-	return adapter;
-
-err2:
-	cxl_remove_adapter_nr(adapter);
-err1:
-	kfree(adapter);
-	return NULL;
-}
-
 #define CXL_PSL_ErrIVTE_tberror (0x1ull << (63-31))
 
 static int sanitise_adapter_regs(struct cxl *adapter)
@@ -1188,10 +1195,10 @@
 	if ((rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_ON)))
 		goto err;
 
-	if ((rc = cxl_setup_psl_timebase(adapter, dev)))
-		goto err;
+	/* Ignore error, adapter init is not dependant on timebase sync */
+	cxl_setup_psl_timebase(adapter, dev);
 
-	if ((rc = cxl_register_psl_err_irq(adapter)))
+	if ((rc = cxl_native_register_psl_err_irq(adapter)))
 		goto err;
 
 	return 0;
@@ -1206,13 +1213,13 @@
 {
 	struct pci_dev *pdev = to_pci_dev(adapter->dev.parent);
 
-	cxl_release_psl_err_irq(adapter);
+	cxl_native_release_psl_err_irq(adapter);
 	cxl_unmap_adapter_regs(adapter);
 
 	pci_disable_device(pdev);
 }
 
-static struct cxl *cxl_init_adapter(struct pci_dev *dev)
+static struct cxl *cxl_pci_init_adapter(struct pci_dev *dev)
 {
 	struct cxl *adapter;
 	int rc;
@@ -1221,6 +1228,12 @@
 	if (!adapter)
 		return ERR_PTR(-ENOMEM);
 
+	adapter->native = kzalloc(sizeof(struct cxl_native), GFP_KERNEL);
+	if (!adapter->native) {
+		rc = -ENOMEM;
+		goto err_release;
+	}
+
 	/* Set defaults for parameters which need to persist over
 	 * configure/reconfigure
 	 */
@@ -1230,8 +1243,7 @@
 	rc = cxl_configure_adapter(adapter, dev);
 	if (rc) {
 		pci_disable_device(dev);
-		cxl_release_adapter(&adapter->dev);
-		return ERR_PTR(rc);
+		goto err_release;
 	}
 
 	/* Don't care if this one fails: */
@@ -1257,9 +1269,13 @@
 	cxl_deconfigure_adapter(adapter);
 	device_unregister(&adapter->dev);
 	return ERR_PTR(rc);
+
+err_release:
+	cxl_release_adapter(&adapter->dev);
+	return ERR_PTR(rc);
 }
 
-static void cxl_remove_adapter(struct cxl *adapter)
+static void cxl_pci_remove_adapter(struct cxl *adapter)
 {
 	pr_devel("cxl_remove_adapter\n");
 
@@ -1271,23 +1287,57 @@
 	device_unregister(&adapter->dev);
 }
 
+#define CXL_MAX_PCIEX_PARENT 2
+
+static int cxl_slot_is_switched(struct pci_dev *dev)
+{
+	struct device_node *np;
+	int depth = 0;
+	const __be32 *prop;
+
+	if (!(np = pci_device_to_OF_node(dev))) {
+		pr_err("cxl: np = NULL\n");
+		return -ENODEV;
+	}
+	of_node_get(np);
+	while (np) {
+		np = of_get_next_parent(np);
+		prop = of_get_property(np, "device_type", NULL);
+		if (!prop || strcmp((char *)prop, "pciex"))
+			break;
+		depth++;
+	}
+	of_node_put(np);
+	return (depth > CXL_MAX_PCIEX_PARENT);
+}
+
 static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	struct cxl *adapter;
 	int slice;
 	int rc;
 
+	if (cxl_pci_is_vphb_device(dev)) {
+		dev_dbg(&dev->dev, "cxl_init_adapter: Ignoring cxl vphb device\n");
+		return -ENODEV;
+	}
+
+	if (cxl_slot_is_switched(dev)) {
+		dev_info(&dev->dev, "Ignoring card on incompatible PCI slot\n");
+		return -ENODEV;
+	}
+
 	if (cxl_verbose)
 		dump_cxl_config_space(dev);
 
-	adapter = cxl_init_adapter(dev);
+	adapter = cxl_pci_init_adapter(dev);
 	if (IS_ERR(adapter)) {
 		dev_err(&dev->dev, "cxl_init_adapter failed: %li\n", PTR_ERR(adapter));
 		return PTR_ERR(adapter);
 	}
 
 	for (slice = 0; slice < adapter->slices; slice++) {
-		if ((rc = cxl_init_afu(adapter, slice, dev))) {
+		if ((rc = pci_init_afu(adapter, slice, dev))) {
 			dev_err(&dev->dev, "AFU %i failed to initialise: %i\n", slice, rc);
 			continue;
 		}
@@ -1312,10 +1362,9 @@
 	 */
 	for (i = 0; i < adapter->slices; i++) {
 		afu = adapter->afu[i];
-		cxl_pci_vphb_remove(afu);
-		cxl_remove_afu(afu);
+		cxl_pci_remove_afu(afu);
 	}
-	cxl_remove_adapter(adapter);
+	cxl_pci_remove_adapter(adapter);
 }
 
 static pci_ers_result_t cxl_vphb_error_detected(struct cxl_afu *afu,
@@ -1328,6 +1377,9 @@
 	/* There should only be one entry, but go through the list
 	 * anyway
 	 */
+	if (afu->phb == NULL)
+		return result;
+
 	list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
 		if (!afu_dev->driver)
 			continue;
@@ -1368,6 +1420,10 @@
 		 */
 		for (i = 0; i < adapter->slices; i++) {
 			afu = adapter->afu[i];
+			/*
+			 * Tell the AFU drivers; but we don't care what they
+			 * say, we're going away.
+			 */
 			cxl_vphb_error_detected(afu, state);
 		}
 		return PCI_ERS_RESULT_DISCONNECT;
@@ -1461,8 +1517,8 @@
 			return result;
 
 		cxl_context_detach_all(afu);
-		cxl_afu_deactivate_mode(afu);
-		cxl_deconfigure_afu(afu);
+		cxl_ops->afu_deactivate_mode(afu, afu->current_mode);
+		pci_deconfigure_afu(afu);
 	}
 	cxl_deconfigure_adapter(adapter);
 
@@ -1485,13 +1541,14 @@
 	for (i = 0; i < adapter->slices; i++) {
 		afu = adapter->afu[i];
 
-		if (cxl_configure_afu(afu, adapter, pdev))
+		if (pci_configure_afu(afu, adapter, pdev))
 			goto err;
 
 		if (cxl_afu_select_best_mode(afu))
 			goto err;
 
-		cxl_pci_vphb_reconfigure(afu);
+		if (afu->phb == NULL)
+			continue;
 
 		list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
 			/* Reset the device context.
@@ -1508,7 +1565,7 @@
 
 			afu_dev->dev.archdata.cxl_ctx = ctx;
 
-			if (cxl_afu_check_and_enable(afu))
+			if (cxl_ops->afu_check_and_enable(afu))
 				goto err;
 
 			afu_dev->error_state = pci_channel_io_normal;
@@ -1555,6 +1612,9 @@
 	for (i = 0; i < adapter->slices; i++) {
 		afu = adapter->afu[i];
 
+		if (afu->phb == NULL)
+			continue;
+
 		list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
 			if (afu_dev->driver && afu_dev->driver->err_handler &&
 			    afu_dev->driver->err_handler->resume)
--- linux-4.4.0.orig/drivers/misc/cxl/sysfs.c
+++ linux-4.4.0/drivers/misc/cxl/sysfs.c
@@ -57,6 +57,15 @@
 	return scnprintf(buf, PAGE_SIZE, "factory\n");
 }
 
+static ssize_t psl_timebase_synced_show(struct device *device,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct cxl *adapter = to_cxl_adapter(device);
+
+	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced);
+}
+
 static ssize_t reset_adapter_store(struct device *device,
 				   struct device_attribute *attr,
 				   const char *buf, size_t count)
@@ -69,7 +78,7 @@
 	if ((rc != 1) || (val != 1))
 		return -EINVAL;
 
-	if ((rc = cxl_reset(adapter)))
+	if ((rc = cxl_ops->adapter_reset(adapter)))
 		return rc;
 	return count;
 }
@@ -142,6 +151,7 @@
 	__ATTR_RO(psl_revision),
 	__ATTR_RO(base_image),
 	__ATTR_RO(image_loaded),
+	__ATTR_RO(psl_timebase_synced),
 	__ATTR_RW(load_image_on_perst),
 	__ATTR_RW(perst_reloads_same_image),
 	__ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
@@ -165,7 +175,7 @@
 {
 	struct cxl_afu *afu = to_afu_chardev_m(device);
 
-	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_offset);
+	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset);
 }
 
 static ssize_t pp_mmio_len_show(struct device *device,
@@ -211,7 +221,7 @@
 		goto err;
 	}
 
-	if ((rc = __cxl_afu_reset(afu)))
+	if ((rc = cxl_ops->afu_reset(afu)))
 		goto err;
 
 	rc = count;
@@ -253,8 +263,14 @@
 	if (irqs_max < afu->pp_irqs)
 		return -EINVAL;
 
-	if (irqs_max > afu->adapter->user_irqs)
-		return -EINVAL;
+	if (cpu_has_feature(CPU_FTR_HVMODE)) {
+		if (irqs_max > afu->adapter->user_irqs)
+			return -EINVAL;
+	} else {
+		/* pHyp sets a per-AFU limit */
+		if (irqs_max > afu->guest->max_ints)
+			return -EINVAL;
+	}
 
 	afu->irqs_max = irqs_max;
 	return count;
@@ -348,7 +364,7 @@
 	}
 
 	/*
-	 * cxl_afu_deactivate_mode needs to be done outside the lock, prevent
+	 * afu_deactivate_mode needs to be done outside the lock, prevent
 	 * other contexts coming in before we are ready:
 	 */
 	old_mode = afu->current_mode;
@@ -357,9 +373,9 @@
 
 	mutex_unlock(&afu->contexts_lock);
 
-	if ((rc = _cxl_afu_deactivate_mode(afu, old_mode)))
+	if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode)))
 		return rc;
-	if ((rc = cxl_afu_activate_mode(afu, mode)))
+	if ((rc = cxl_ops->afu_activate_mode(afu, mode)))
 		return rc;
 
 	return count;
@@ -386,10 +402,9 @@
 			       struct bin_attribute *bin_attr, char *buf,
 			       loff_t off, size_t count)
 {
-	struct cxl_afu *afu = to_cxl_afu(container_of(kobj,
-						      struct device, kobj));
+	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj));
 
-	return cxl_afu_read_err_buffer(afu, buf, off, count);
+	return cxl_ops->afu_read_err_buffer(afu, buf, off, count);
 }
 
 static struct device_attribute afu_attrs[] = {
@@ -406,24 +421,39 @@
 
 int cxl_sysfs_adapter_add(struct cxl *adapter)
 {
+	struct device_attribute *dev_attr;
 	int i, rc;
 
 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
-		if ((rc = device_create_file(&adapter->dev, &adapter_attrs[i])))
-			goto err;
+		dev_attr = &adapter_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_ADAPTER_ATTRS)) {
+			if ((rc = device_create_file(&adapter->dev, dev_attr)))
+				goto err;
+		}
 	}
 	return 0;
 err:
-	for (i--; i >= 0; i--)
-		device_remove_file(&adapter->dev, &adapter_attrs[i]);
+	for (i--; i >= 0; i--) {
+		dev_attr = &adapter_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_ADAPTER_ATTRS))
+			device_remove_file(&adapter->dev, dev_attr);
+	}
 	return rc;
 }
+
 void cxl_sysfs_adapter_remove(struct cxl *adapter)
 {
+	struct device_attribute *dev_attr;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++)
-		device_remove_file(&adapter->dev, &adapter_attrs[i]);
+	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
+		dev_attr = &adapter_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_ADAPTER_ATTRS))
+			device_remove_file(&adapter->dev, dev_attr);
+	}
 }
 
 struct afu_config_record {
@@ -467,12 +497,14 @@
 			       loff_t off, size_t count)
 {
 	struct afu_config_record *cr = to_cr(kobj);
-	struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj));
+	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent));
 
-	u64 i, j, val;
+	u64 i, j, val, rc;
 
 	for (i = 0; i < count;) {
-		val = cxl_afu_cr_read64(afu, cr->cr, off & ~0x7);
+		rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val);
+		if (rc)
+			val = ~0ULL;
 		for (j = off & 0x7; j < 8 && i < count; i++, j++, off++)
 			buf[i] = (val >> (j * 8)) & 0xff;
 	}
@@ -517,14 +549,22 @@
 		return ERR_PTR(-ENOMEM);
 
 	cr->cr = cr_idx;
-	cr->device = cxl_afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID);
-	cr->vendor = cxl_afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID);
-	cr->class = cxl_afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION) >> 8;
+
+	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device);
+	if (rc)
+		goto err;
+	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor);
+	if (rc)
+		goto err;
+	rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class);
+	if (rc)
+		goto err;
+	cr->class >>= 8;
 
 	/*
 	 * Export raw AFU PCIe like config record. For now this is read only by
 	 * root - we can expand that later to be readable by non-root and maybe
-	 * even writable provided we have a good use-case. Once we suport
+	 * even writable provided we have a good use-case. Once we support
 	 * exposing AFUs through a virtual PHB they will get that for free from
 	 * Linux' PCI infrastructure, but until then it's not clear that we
 	 * need it for anything since the main use case is just identifying
@@ -539,7 +579,7 @@
 	rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
 				  &afu->dev.kobj, "cr%i", cr->cr);
 	if (rc)
-		goto err;
+		goto err1;
 
 	rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
 	if (rc)
@@ -562,6 +602,7 @@
 
 void cxl_sysfs_afu_remove(struct cxl_afu *afu)
 {
+	struct device_attribute *dev_attr;
 	struct afu_config_record *cr, *tmp;
 	int i;
 
@@ -569,8 +610,12 @@
 	if (afu->eb_len)
 		device_remove_bin_file(&afu->dev, &afu->attr_eb);
 
-	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
-		device_remove_file(&afu->dev, &afu_attrs[i]);
+	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
+		dev_attr = &afu_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_AFU_ATTRS))
+			device_remove_file(&afu->dev, &afu_attrs[i]);
+	}
 
 	list_for_each_entry_safe(cr, tmp, &afu->crs, list) {
 		sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
@@ -580,14 +625,19 @@
 
 int cxl_sysfs_afu_add(struct cxl_afu *afu)
 {
+	struct device_attribute *dev_attr;
 	struct afu_config_record *cr;
 	int i, rc;
 
 	INIT_LIST_HEAD(&afu->crs);
 
 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
-		if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
-			goto err;
+		dev_attr = &afu_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_AFU_ATTRS)) {
+			if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
+				goto err;
+		}
 	}
 
 	/* conditionally create the add the binary file for error info buffer */
@@ -626,32 +676,50 @@
 	/* reset the eb_len as we havent created the bin attr */
 	afu->eb_len = 0;
 
-	for (i--; i >= 0; i--)
+	for (i--; i >= 0; i--) {
+		dev_attr = &afu_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_AFU_ATTRS))
 		device_remove_file(&afu->dev, &afu_attrs[i]);
+	}
 	return rc;
 }
 
 int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
 {
+	struct device_attribute *dev_attr;
 	int i, rc;
 
 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
-		if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
-			goto err;
+		dev_attr = &afu_master_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_AFU_MASTER_ATTRS)) {
+			if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
+				goto err;
+		}
 	}
 
 	return 0;
 
 err:
-	for (i--; i >= 0; i--)
-		device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
+	for (i--; i >= 0; i--) {
+		dev_attr = &afu_master_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_AFU_MASTER_ATTRS))
+			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
+	}
 	return rc;
 }
 
 void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)
 {
+	struct device_attribute *dev_attr;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++)
-		device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
+	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
+		dev_attr = &afu_master_attrs[i];
+		if (cxl_ops->support_attributes(dev_attr->attr.name,
+						CXL_AFU_MASTER_ATTRS))
+			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
+	}
 }
--- linux-4.4.0.orig/drivers/misc/cxl/trace.h
+++ linux-4.4.0/drivers/misc/cxl/trace.h
@@ -450,6 +450,199 @@
 	TP_ARGS(ctx)
 );
 
+TRACE_EVENT(cxl_hcall,
+	TP_PROTO(u64 unit_address, u64 process_token, long rc),
+
+	TP_ARGS(unit_address, process_token, rc),
+
+	TP_STRUCT__entry(
+		__field(u64, unit_address)
+		__field(u64, process_token)
+		__field(long, rc)
+	),
+
+	TP_fast_assign(
+		__entry->unit_address = unit_address;
+		__entry->process_token = process_token;
+		__entry->rc = rc;
+	),
+
+	TP_printk("unit_address=0x%016llx process_token=0x%016llx rc=%li",
+		__entry->unit_address,
+		__entry->process_token,
+		__entry->rc
+	)
+);
+
+TRACE_EVENT(cxl_hcall_control,
+	TP_PROTO(u64 unit_address, char *fct, u64 p1, u64 p2, u64 p3,
+	u64 p4, unsigned long r4, long rc),
+
+	TP_ARGS(unit_address, fct, p1, p2, p3, p4, r4, rc),
+
+	TP_STRUCT__entry(
+		__field(u64, unit_address)
+		__field(char *, fct)
+		__field(u64, p1)
+		__field(u64, p2)
+		__field(u64, p3)
+		__field(u64, p4)
+		__field(unsigned long, r4)
+		__field(long, rc)
+	),
+
+	TP_fast_assign(
+		__entry->unit_address = unit_address;
+		__entry->fct = fct;
+		__entry->p1 = p1;
+		__entry->p2 = p2;
+		__entry->p3 = p3;
+		__entry->p4 = p4;
+		__entry->r4 = r4;
+		__entry->rc = rc;
+	),
+
+	TP_printk("unit_address=%#.16llx %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li",
+		__entry->unit_address,
+		__entry->fct,
+		__entry->p1,
+		__entry->p2,
+		__entry->p3,
+		__entry->p4,
+		__entry->r4,
+		__entry->rc
+	)
+);
+
+TRACE_EVENT(cxl_hcall_attach,
+	TP_PROTO(u64 unit_address, u64 phys_addr, unsigned long process_token,
+		unsigned long mmio_addr, unsigned long mmio_size, long rc),
+
+	TP_ARGS(unit_address, phys_addr, process_token,
+		mmio_addr, mmio_size, rc),
+
+	TP_STRUCT__entry(
+		__field(u64, unit_address)
+		__field(u64, phys_addr)
+		__field(unsigned long, process_token)
+		__field(unsigned long, mmio_addr)
+		__field(unsigned long, mmio_size)
+		__field(long, rc)
+	),
+
+	TP_fast_assign(
+		__entry->unit_address = unit_address;
+		__entry->phys_addr = phys_addr;
+		__entry->process_token = process_token;
+		__entry->mmio_addr = mmio_addr;
+		__entry->mmio_size = mmio_size;
+		__entry->rc = rc;
+	),
+
+	TP_printk("unit_address=0x%016llx phys_addr=0x%016llx "
+		"token=0x%.8lx mmio_addr=0x%lx mmio_size=0x%lx rc=%li",
+		__entry->unit_address,
+		__entry->phys_addr,
+		__entry->process_token,
+		__entry->mmio_addr,
+		__entry->mmio_size,
+		__entry->rc
+	)
+);
+
+DEFINE_EVENT(cxl_hcall, cxl_hcall_detach,
+	TP_PROTO(u64 unit_address, u64 process_token, long rc),
+	TP_ARGS(unit_address, process_token, rc)
+);
+
+DEFINE_EVENT(cxl_hcall_control, cxl_hcall_control_function,
+	TP_PROTO(u64 unit_address, char *fct, u64 p1, u64 p2, u64 p3,
+	u64 p4, unsigned long r4, long rc),
+	TP_ARGS(unit_address, fct, p1, p2, p3, p4, r4, rc)
+);
+
+DEFINE_EVENT(cxl_hcall, cxl_hcall_collect_int_info,
+	TP_PROTO(u64 unit_address, u64 process_token, long rc),
+	TP_ARGS(unit_address, process_token, rc)
+);
+
+TRACE_EVENT(cxl_hcall_control_faults,
+	TP_PROTO(u64 unit_address, u64 process_token,
+		u64 control_mask, u64 reset_mask, unsigned long r4,
+		long rc),
+
+	TP_ARGS(unit_address, process_token,
+		control_mask, reset_mask, r4, rc),
+
+	TP_STRUCT__entry(
+		__field(u64, unit_address)
+		__field(u64, process_token)
+		__field(u64, control_mask)
+		__field(u64, reset_mask)
+		__field(unsigned long, r4)
+		__field(long, rc)
+	),
+
+	TP_fast_assign(
+		__entry->unit_address = unit_address;
+		__entry->process_token = process_token;
+		__entry->control_mask = control_mask;
+		__entry->reset_mask = reset_mask;
+		__entry->r4 = r4;
+		__entry->rc = rc;
+	),
+
+	TP_printk("unit_address=0x%016llx process_token=0x%llx "
+		"control_mask=%#llx reset_mask=%#llx r4=%#lx rc=%li",
+		__entry->unit_address,
+		__entry->process_token,
+		__entry->control_mask,
+		__entry->reset_mask,
+		__entry->r4,
+		__entry->rc
+	)
+);
+
+DEFINE_EVENT(cxl_hcall_control, cxl_hcall_control_facility,
+	TP_PROTO(u64 unit_address, char *fct, u64 p1, u64 p2, u64 p3,
+	u64 p4, unsigned long r4, long rc),
+	TP_ARGS(unit_address, fct, p1, p2, p3, p4, r4, rc)
+);
+
+TRACE_EVENT(cxl_hcall_download_facility,
+	TP_PROTO(u64 unit_address, char *fct, u64 list_address, u64 num,
+	unsigned long r4, long rc),
+
+	TP_ARGS(unit_address, fct, list_address, num, r4, rc),
+
+	TP_STRUCT__entry(
+		__field(u64, unit_address)
+		__field(char *, fct)
+		__field(u64, list_address)
+		__field(u64, num)
+		__field(unsigned long, r4)
+		__field(long, rc)
+	),
+
+	TP_fast_assign(
+		__entry->unit_address = unit_address;
+		__entry->fct = fct;
+		__entry->list_address = list_address;
+		__entry->num = num;
+		__entry->r4 = r4;
+		__entry->rc = rc;
+	),
+
+	TP_printk("%#.16llx, %s(%#llx, %#llx), %#lx): %li",
+		__entry->unit_address,
+		__entry->fct,
+		__entry->list_address,
+		__entry->num,
+		__entry->r4,
+		__entry->rc
+	)
+);
+
 #endif /* _CXL_TRACE_H */
 
 /* This part must be outside protection */
--- linux-4.4.0.orig/drivers/misc/cxl/vphb.c
+++ linux-4.4.0/drivers/misc/cxl/vphb.c
@@ -49,7 +49,7 @@
 	phb = pci_bus_to_host(dev->bus);
 	afu = (struct cxl_afu *)phb->private_data;
 
-	if (!cxl_adapter_link_ok(afu->adapter)) {
+	if (!cxl_ops->link_ok(afu->adapter, afu)) {
 		dev_warn(&dev->dev, "%s: Device link is down, refusing to enable AFU\n", __func__);
 		return false;
 	}
@@ -66,7 +66,7 @@
 		return false;
 	dev->dev.archdata.cxl_ctx = ctx;
 
-	return (cxl_afu_check_and_enable(afu) == 0);
+	return (cxl_ops->afu_check_and_enable(afu) == 0);
 }
 
 static void cxl_pci_disable_device(struct pci_dev *dev)
@@ -99,113 +99,90 @@
 	return (bus << 8) + devfn;
 }
 
-static unsigned long cxl_pcie_cfg_addr(struct pci_controller* phb,
-				       u8 bus, u8 devfn, int offset)
-{
-	int record = cxl_pcie_cfg_record(bus, devfn);
-
-	return (unsigned long)phb->cfg_addr + ((unsigned long)phb->cfg_data * record) + offset;
-}
-
-
 static int cxl_pcie_config_info(struct pci_bus *bus, unsigned int devfn,
-				int offset, int len,
-				volatile void __iomem **ioaddr,
-				u32 *mask, int *shift)
+				struct cxl_afu **_afu, int *_record)
 {
 	struct pci_controller *phb;
 	struct cxl_afu *afu;
-	unsigned long addr;
+	int record;
 
 	phb = pci_bus_to_host(bus);
 	if (phb == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	afu = (struct cxl_afu *)phb->private_data;
 
-	if (cxl_pcie_cfg_record(bus->number, devfn) > afu->crs_num)
+	afu = (struct cxl_afu *)phb->private_data;
+	record = cxl_pcie_cfg_record(bus->number, devfn);
+	if (record > afu->crs_num)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (offset >= (unsigned long)phb->cfg_data)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	addr = cxl_pcie_cfg_addr(phb, bus->number, devfn, offset);
 
-	*ioaddr = (void *)(addr & ~0x3ULL);
-	*shift = ((addr & 0x3) * 8);
-	switch (len) {
-	case 1:
-		*mask = 0xff;
-		break;
-	case 2:
-		*mask = 0xffff;
-		break;
-	default:
-		*mask = 0xffffffff;
-		break;
-	}
+	*_afu = afu;
+	*_record = record;
 	return 0;
 }
 
-
-static inline bool cxl_config_link_ok(struct pci_bus *bus)
-{
-	struct pci_controller *phb;
-	struct cxl_afu *afu;
-
-	/* Config space IO is based on phb->cfg_addr, which is based on
-	 * afu_desc_mmio. This isn't safe to read/write when the link
-	 * goes down, as EEH tears down MMIO space.
-	 *
-	 * Check if the link is OK before proceeding.
-	 */
-
-	phb = pci_bus_to_host(bus);
-	if (phb == NULL)
-		return false;
-	afu = (struct cxl_afu *)phb->private_data;
-	return cxl_adapter_link_ok(afu->adapter);
-}
-
 static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
 				int offset, int len, u32 *val)
 {
-	volatile void __iomem *ioaddr;
-	int shift, rc;
-	u32 mask;
+	int rc, record;
+	struct cxl_afu *afu;
+	u8 val8;
+	u16 val16;
+	u32 val32;
 
-	rc = cxl_pcie_config_info(bus, devfn, offset, len, &ioaddr,
-				  &mask, &shift);
+	rc = cxl_pcie_config_info(bus, devfn, &afu, &record);
 	if (rc)
 		return rc;
 
-	if (!cxl_config_link_ok(bus))
+	switch (len) {
+	case 1:
+		rc = cxl_ops->afu_cr_read8(afu, record, offset,	&val8);
+		*val = val8;
+		break;
+	case 2:
+		rc = cxl_ops->afu_cr_read16(afu, record, offset, &val16);
+		*val = val16;
+		break;
+	case 4:
+		rc = cxl_ops->afu_cr_read32(afu, record, offset, &val32);
+		*val = val32;
+		break;
+	default:
+		WARN_ON(1);
+	}
+
+	if (rc)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	/* Can only read 32 bits */
-	*val = (in_le32(ioaddr) >> shift) & mask;
 	return PCIBIOS_SUCCESSFUL;
 }
 
 static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
 				 int offset, int len, u32 val)
 {
-	volatile void __iomem *ioaddr;
-	u32 v, mask;
-	int shift, rc;
+	int rc, record;
+	struct cxl_afu *afu;
 
-	rc = cxl_pcie_config_info(bus, devfn, offset, len, &ioaddr,
-				  &mask, &shift);
+	rc = cxl_pcie_config_info(bus, devfn, &afu, &record);
 	if (rc)
 		return rc;
 
-	if (!cxl_config_link_ok(bus))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	/* Can only write 32 bits so do read-modify-write */
-	mask <<= shift;
-	val <<= shift;
+	switch (len) {
+	case 1:
+		rc = cxl_ops->afu_cr_write8(afu, record, offset, val & 0xff);
+		break;
+	case 2:
+		rc = cxl_ops->afu_cr_write16(afu, record, offset, val & 0xffff);
+		break;
+	case 4:
+		rc = cxl_ops->afu_cr_write32(afu, record, offset, val);
+		break;
+	default:
+		WARN_ON(1);
+	}
 
-	v = (in_le32(ioaddr) & ~mask) || (val & mask);
+	if (rc)
+		return PCIBIOS_SET_FAILED;
 
-	out_le32(ioaddr, v);
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -231,25 +208,32 @@
 
 int cxl_pci_vphb_add(struct cxl_afu *afu)
 {
-	struct pci_dev *phys_dev;
-	struct pci_controller *phb, *phys_phb;
+	struct pci_controller *phb;
+	struct device_node *vphb_dn;
+	struct device *parent;
 
-	phys_dev = to_pci_dev(afu->adapter->dev.parent);
-	phys_phb = pci_bus_to_host(phys_dev->bus);
+	/* The parent device is the adapter. Reuse the device node of
+	 * the adapter.
+	 * We don't seem to care what device node is used for the vPHB,
+	 * but tools such as lsvpd walk up the device parents looking
+	 * for a valid location code, so we might as well show devices
+	 * attached to the adapter as being located on that adapter.
+	 */
+	parent = afu->adapter->dev.parent;
+	vphb_dn = parent->of_node;
 
 	/* Alloc and setup PHB data structure */
-	phb = pcibios_alloc_controller(phys_phb->dn);
-
+	phb = pcibios_alloc_controller(vphb_dn);
 	if (!phb)
 		return -ENODEV;
 
 	/* Setup parent in sysfs */
-	phb->parent = &phys_dev->dev;
+	phb->parent = parent;
 
 	/* Setup the PHB using arch provided callback */
 	phb->ops = &cxl_pcie_pci_ops;
-	phb->cfg_addr = afu->afu_desc_mmio + afu->crs_offset;
-	phb->cfg_data = (void *)(u64)afu->crs_len;
+	phb->cfg_addr = NULL;
+	phb->cfg_data = 0;
 	phb->private_data = afu;
 	phb->controller_ops = cxl_pci_controller_ops;
 
@@ -272,15 +256,6 @@
 	return 0;
 }
 
-void cxl_pci_vphb_reconfigure(struct cxl_afu *afu)
-{
-	/* When we are reconfigured, the AFU's MMIO space is unmapped
-	 * and remapped. We need to reflect this in the PHB's view of
-	 * the world.
-	 */
-	afu->phb->cfg_addr = afu->afu_desc_mmio + afu->crs_offset;
-}
-
 void cxl_pci_vphb_remove(struct cxl_afu *afu)
 {
 	struct pci_controller *phb;
@@ -296,6 +271,15 @@
 	pcibios_free_controller(phb);
 }
 
+bool cxl_pci_is_vphb_device(struct pci_dev *dev)
+{
+	struct pci_controller *phb;
+
+	phb = pci_bus_to_host(dev->bus);
+
+	return (phb->ops == &cxl_pcie_pci_ops);
+}
+
 struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev)
 {
 	struct pci_controller *phb;
--- linux-4.4.0.orig/drivers/misc/dummy-irq.c
+++ linux-4.4.0/drivers/misc/dummy-irq.c
@@ -59,6 +59,6 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jiri Kosina");
-module_param(irq, uint, 0444);
+module_param_hw(irq, uint, irq, 0444);
 MODULE_PARM_DESC(irq, "The IRQ to register for");
 MODULE_DESCRIPTION("Dummy IRQ handler driver");
--- linux-4.4.0.orig/drivers/misc/echo/echo.c
+++ linux-4.4.0/drivers/misc/echo/echo.c
@@ -454,7 +454,7 @@
 	 */
 	ec->factor = 0;
 	ec->shift = 0;
-	if ((ec->nonupdate_dwell == 0)) {
+	if (!ec->nonupdate_dwell) {
 		int p, logp, shift;
 
 		/* Determine:
--- linux-4.4.0.orig/drivers/misc/eeprom/at24.c
+++ linux-4.4.0/drivers/misc/eeprom/at24.c
@@ -257,6 +257,9 @@
 	if (unlikely(!count))
 		return count;
 
+	if (off + count > at24->chip.byte_len)
+		return -EINVAL;
+
 	/*
 	 * Read data from chip, protecting against concurrent updates
 	 * from this host, but not from other I2C masters.
@@ -311,6 +314,9 @@
 	unsigned long timeout, write_time;
 	unsigned next_page;
 
+	if (offset + count > at24->chip.byte_len)
+		return -EINVAL;
+
 	/* Get corresponding I2C address and adjust offset */
 	client = at24_translate_offset(at24, &offset);
 
--- linux-4.4.0.orig/drivers/misc/eeprom/eeprom_93xx46.c
+++ linux-4.4.0/drivers/misc/eeprom/eeprom_93xx46.c
@@ -381,3 +381,4 @@
 MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs");
 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
 MODULE_ALIAS("spi:93xx46");
+MODULE_ALIAS("spi:eeprom-93xx46");
--- linux-4.4.0.orig/drivers/misc/enclosure.c
+++ linux-4.4.0/drivers/misc/enclosure.c
@@ -148,7 +148,7 @@
 	for (i = 0; i < components; i++) {
 		edev->component[i].number = -1;
 		edev->component[i].slot = -1;
-		edev->component[i].power_status = 1;
+		edev->component[i].power_status = -1;
 	}
 
 	mutex_lock(&container_list_lock);
@@ -375,6 +375,7 @@
 			 struct device *dev)
 {
 	struct enclosure_component *cdev;
+	int err;
 
 	if (!edev || component >= edev->components)
 		return -EINVAL;
@@ -384,12 +385,17 @@
 	if (cdev->dev == dev)
 		return -EEXIST;
 
-	if (cdev->dev)
+	if (cdev->dev) {
 		enclosure_remove_links(cdev);
-
-	put_device(cdev->dev);
+		put_device(cdev->dev);
+	}
 	cdev->dev = get_device(dev);
-	return enclosure_add_links(cdev);
+	err = enclosure_add_links(cdev);
+	if (err) {
+		put_device(cdev->dev);
+		cdev->dev = NULL;
+	}
+	return err;
 }
 EXPORT_SYMBOL_GPL(enclosure_add_device);
 
@@ -413,10 +419,9 @@
 		cdev = &edev->component[i];
 		if (cdev->dev == dev) {
 			enclosure_remove_links(cdev);
-			device_del(&cdev->cdev);
 			put_device(dev);
 			cdev->dev = NULL;
-			return device_add(&cdev->cdev);
+			return 0;
 		}
 	}
 	return -ENODEV;
@@ -594,6 +599,11 @@
 
 	if (edev->cb->get_power_status)
 		edev->cb->get_power_status(edev, ecomp);
+
+	/* If still uninitialized, the callback failed or does not exist. */
+	if (ecomp->power_status == -1)
+		return (edev->cb->get_power_status) ? -EIO : -ENOTTY;
+
 	return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off");
 }
 
--- linux-4.4.0.orig/drivers/misc/genwqe/card_base.h
+++ linux-4.4.0/drivers/misc/genwqe/card_base.h
@@ -404,7 +404,7 @@
 	struct file *filp;
 
 	struct fasync_struct *async_queue;
-	struct task_struct *owner;
+	struct pid *opener;
 	struct list_head list;		/* entry in list of open files */
 
 	spinlock_t map_lock;		/* lock for dma_mappings */
--- linux-4.4.0.orig/drivers/misc/genwqe/card_dev.c
+++ linux-4.4.0/drivers/misc/genwqe/card_dev.c
@@ -52,7 +52,7 @@
 {
 	unsigned long flags;
 
-	cfile->owner = current;
+	cfile->opener = get_pid(task_tgid(current));
 	spin_lock_irqsave(&cd->file_lock, flags);
 	list_add(&cfile->list, &cd->file_list);
 	spin_unlock_irqrestore(&cd->file_lock, flags);
@@ -65,6 +65,7 @@
 	spin_lock_irqsave(&cd->file_lock, flags);
 	list_del(&cfile->list);
 	spin_unlock_irqrestore(&cd->file_lock, flags);
+	put_pid(cfile->opener);
 
 	return 0;
 }
@@ -275,7 +276,7 @@
 	return files;
 }
 
-static int genwqe_force_sig(struct genwqe_dev *cd, int sig)
+static int genwqe_terminate(struct genwqe_dev *cd)
 {
 	unsigned int files = 0;
 	unsigned long flags;
@@ -283,7 +284,7 @@
 
 	spin_lock_irqsave(&cd->file_lock, flags);
 	list_for_each_entry(cfile, &cd->file_list, list) {
-		force_sig(sig, cfile->owner);
+		kill_pid(cfile->opener, SIGKILL, 1);
 		files++;
 	}
 	spin_unlock_irqrestore(&cd->file_lock, flags);
@@ -781,6 +782,8 @@
 
 	if ((m->addr == 0x0) || (m->size == 0))
 		return -EINVAL;
+	if (m->size > ULONG_MAX - PAGE_SIZE - (m->addr & ~PAGE_MASK))
+		return -EINVAL;
 
 	map_addr = (m->addr & PAGE_MASK);
 	map_size = round_up(m->size + (m->addr & ~PAGE_MASK), PAGE_SIZE);
@@ -1356,7 +1359,7 @@
 		dev_warn(&pci_dev->dev,
 			 "[%s] send SIGKILL and wait ...\n", __func__);
 
-		rc = genwqe_force_sig(cd, SIGKILL); /* force terminate */
+		rc = genwqe_terminate(cd);
 		if (rc) {
 			/* Give kill_timout more seconds to end processes */
 			for (i = 0; (i < genwqe_kill_timeout) &&
--- linux-4.4.0.orig/drivers/misc/genwqe/card_utils.c
+++ linux-4.4.0/drivers/misc/genwqe/card_utils.c
@@ -217,7 +217,7 @@
 void *__genwqe_alloc_consistent(struct genwqe_dev *cd, size_t size,
 			       dma_addr_t *dma_handle)
 {
-	if (get_order(size) > MAX_ORDER)
+	if (get_order(size) >= MAX_ORDER)
 		return NULL;
 
 	return dma_alloc_coherent(&cd->pci_dev->dev, size, dma_handle,
@@ -298,7 +298,7 @@
 int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
 			  void __user *user_addr, size_t user_size)
 {
-	int rc;
+	int ret = -ENOMEM;
 	struct pci_dev *pci_dev = cd->pci_dev;
 
 	sgl->fpage_offs = offset_in_page((unsigned long)user_addr);
@@ -317,7 +317,7 @@
 	if (get_order(sgl->sgl_size) > MAX_ORDER) {
 		dev_err(&pci_dev->dev,
 			"[%s] err: too much memory requested!\n", __func__);
-		return -ENOMEM;
+		return ret;
 	}
 
 	sgl->sgl = __genwqe_alloc_consistent(cd, sgl->sgl_size,
@@ -325,7 +325,7 @@
 	if (sgl->sgl == NULL) {
 		dev_err(&pci_dev->dev,
 			"[%s] err: no memory available!\n", __func__);
-		return -ENOMEM;
+		return ret;
 	}
 
 	/* Only use buffering on incomplete pages */
@@ -338,7 +338,7 @@
 		/* Sync with user memory */
 		if (copy_from_user(sgl->fpage + sgl->fpage_offs,
 				   user_addr, sgl->fpage_size)) {
-			rc = -EFAULT;
+			ret = -EFAULT;
 			goto err_out;
 		}
 	}
@@ -351,19 +351,30 @@
 		/* Sync with user memory */
 		if (copy_from_user(sgl->lpage, user_addr + user_size -
 				   sgl->lpage_size, sgl->lpage_size)) {
-			rc = -EFAULT;
-			goto err_out1;
+			ret = -EFAULT;
+			goto err_out2;
 		}
 	}
 	return 0;
 
+ err_out2:
+	__genwqe_free_consistent(cd, PAGE_SIZE, sgl->lpage,
+				 sgl->lpage_dma_addr);
+	sgl->lpage = NULL;
+	sgl->lpage_dma_addr = 0;
  err_out1:
 	__genwqe_free_consistent(cd, PAGE_SIZE, sgl->fpage,
 				 sgl->fpage_dma_addr);
+	sgl->fpage = NULL;
+	sgl->fpage_dma_addr = 0;
  err_out:
 	__genwqe_free_consistent(cd, sgl->sgl_size, sgl->sgl,
 				 sgl->sgl_dma_addr);
-	return -ENOMEM;
+	sgl->sgl = NULL;
+	sgl->sgl_dma_addr = 0;
+	sgl->sgl_size = 0;
+
+	return ret;
 }
 
 int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
@@ -572,6 +583,10 @@
 	/* determine space needed for page_list. */
 	data = (unsigned long)uaddr;
 	offs = offset_in_page(data);
+	if (size > ULONG_MAX - PAGE_SIZE - offs) {
+		m->size = 0;	/* mark unused and not added */
+		return -EINVAL;
+	}
 	m->nr_pages = DIV_ROUND_UP(offs + size, PAGE_SIZE);
 
 	m->page_list = kcalloc(m->nr_pages,
--- linux-4.4.0.orig/drivers/misc/hmc6352.c
+++ linux-4.4.0/drivers/misc/hmc6352.c
@@ -27,6 +27,7 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/sysfs.h>
+#include <linux/nospec.h>
 
 static DEFINE_MUTEX(compass_mutex);
 
@@ -50,6 +51,7 @@
 		return ret;
 	if (val >= strlen(map))
 		return -EINVAL;
+	val = array_index_nospec(val, strlen(map));
 	mutex_lock(&compass_mutex);
 	ret = compass_command(c, map[val]);
 	mutex_unlock(&compass_mutex);
--- linux-4.4.0.orig/drivers/misc/ibmasm/ibmasmfs.c
+++ linux-4.4.0/drivers/misc/ibmasm/ibmasmfs.c
@@ -507,35 +507,14 @@
 static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
 {
 	void __iomem *address = (void __iomem *)file->private_data;
-	unsigned char *page;
-	int retval;
 	int len = 0;
 	unsigned int value;
-
-	if (*offset < 0)
-		return -EINVAL;
-	if (count == 0 || count > 1024)
-		return 0;
-	if (*offset != 0)
-		return 0;
-
-	page = (unsigned char *)__get_free_page(GFP_KERNEL);
-	if (!page)
-		return -ENOMEM;
+	char lbuf[20];
 
 	value = readl(address);
-	len = sprintf(page, "%d\n", value);
-
-	if (copy_to_user(buf, page, len)) {
-		retval = -EFAULT;
-		goto exit;
-	}
-	*offset += len;
-	retval = len;
+	len = snprintf(lbuf, sizeof(lbuf), "%d\n", value);
 
-exit:
-	free_page((unsigned long)page);
-	return retval;
+	return simple_read_from_buffer(buf, count, offset, lbuf, len);
 }
 
 static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
--- linux-4.4.0.orig/drivers/misc/kgdbts.c
+++ linux-4.4.0/drivers/misc/kgdbts.c
@@ -979,6 +979,12 @@
 	int nmi_sleep = 0;
 	int i;
 
+	verbose = 0;
+	if (strstr(config, "V1"))
+		verbose = 1;
+	if (strstr(config, "V2"))
+		verbose = 2;
+
 	ptr = strchr(config, 'F');
 	if (ptr)
 		fork_test = simple_strtol(ptr + 1, NULL, 10);
@@ -1062,13 +1068,6 @@
 		return -ENOSPC;
 	}
 	strcpy(config, opt);
-
-	verbose = 0;
-	if (strstr(config, "V1"))
-		verbose = 1;
-	if (strstr(config, "V2"))
-		verbose = 2;
-
 	return 0;
 }
 
@@ -1080,9 +1079,6 @@
 
 	if (!strlen(config) || isspace(config[0]))
 		goto noconfig;
-	err = kgdbts_option_setup(config);
-	if (err)
-		goto noconfig;
 
 	final_ack = 0;
 	run_plant_and_detach_test(1);
@@ -1132,7 +1128,7 @@
 
 static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp)
 {
-	int len = strlen(kmessage);
+	size_t len = strlen(kmessage);
 
 	if (len >= MAX_CONFIG_LEN) {
 		printk(KERN_ERR "kgdbts: config string too long\n");
@@ -1152,7 +1148,7 @@
 
 	strcpy(config, kmessage);
 	/* Chop out \n char as a result of echo */
-	if (config[len - 1] == '\n')
+	if (len && config[len - 1] == '\n')
 		config[len - 1] = '\0';
 
 	/* Go and configure with the new params. */
--- linux-4.4.0.orig/drivers/misc/mei/amthif.c
+++ linux-4.4.0/drivers/misc/mei/amthif.c
@@ -417,8 +417,10 @@
 
 	dev = cl->dev;
 
-	if (dev->iamthif_state != MEI_IAMTHIF_READING)
+	if (dev->iamthif_state != MEI_IAMTHIF_READING) {
+		mei_irq_discard_msg(dev, mei_hdr);
 		return 0;
+	}
 
 	ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
 	if (ret)
--- linux-4.4.0.orig/drivers/misc/mei/bus-fixup.c
+++ linux-4.4.0/drivers/misc/mei/bus-fixup.c
@@ -151,7 +151,7 @@
 
 	ret = 0;
 	bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
-	if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+	if (bytes_recv < 0 || bytes_recv < if_version_length) {
 		dev_err(bus->dev, "Could not read IF version\n");
 		ret = -EIO;
 		goto err;
--- linux-4.4.0.orig/drivers/misc/mei/bus.c
+++ linux-4.4.0/drivers/misc/mei/bus.c
@@ -53,6 +53,11 @@
 	bus = cl->dev;
 
 	mutex_lock(&bus->device_lock);
+	if (bus->dev_state != MEI_DEV_ENABLED) {
+		rets = -ENODEV;
+		goto out;
+	}
+
 	if (!mei_cl_is_connected(cl)) {
 		rets = -ENODEV;
 		goto out;
@@ -109,6 +114,10 @@
 	bus = cl->dev;
 
 	mutex_lock(&bus->device_lock);
+	if (bus->dev_state != MEI_DEV_ENABLED) {
+		rets = -ENODEV;
+		goto out;
+	}
 
 	cb = mei_cl_read_cb(cl, NULL);
 	if (cb)
@@ -135,7 +144,7 @@
 		mutex_lock(&bus->device_lock);
 
 		if (!mei_cl_is_connected(cl)) {
-			rets = -EBUSY;
+			rets = -ENODEV;
 			goto out;
 		}
 	}
@@ -213,17 +222,23 @@
 static void mei_cl_bus_event_work(struct work_struct *work)
 {
 	struct mei_cl_device *cldev;
+	struct mei_device *bus;
 
 	cldev = container_of(work, struct mei_cl_device, event_work);
 
+	bus = cldev->bus;
+
 	if (cldev->event_cb)
 		cldev->event_cb(cldev, cldev->events, cldev->event_context);
 
 	cldev->events = 0;
 
 	/* Prepare for the next read */
-	if (cldev->events_mask & BIT(MEI_CL_EVENT_RX))
+	if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
+		mutex_lock(&bus->device_lock);
 		mei_cl_read_start(cldev->cl, 0, NULL);
+		mutex_unlock(&bus->device_lock);
+	}
 }
 
 /**
@@ -287,6 +302,7 @@
 				unsigned long events_mask,
 				mei_cldev_event_cb_t event_cb, void *context)
 {
+	struct mei_device *bus = cldev->bus;
 	int ret;
 
 	if (cldev->event_cb)
@@ -299,15 +315,17 @@
 	INIT_WORK(&cldev->event_work, mei_cl_bus_event_work);
 
 	if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
+		mutex_lock(&bus->device_lock);
 		ret = mei_cl_read_start(cldev->cl, 0, NULL);
+		mutex_unlock(&bus->device_lock);
 		if (ret && ret != -EBUSY)
 			return ret;
 	}
 
 	if (cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)) {
-		mutex_lock(&cldev->cl->dev->device_lock);
+		mutex_lock(&bus->device_lock);
 		ret = mei_cl_notify_request(cldev->cl, NULL, event_cb ? 1 : 0);
-		mutex_unlock(&cldev->cl->dev->device_lock);
+		mutex_unlock(&bus->device_lock);
 		if (ret)
 			return ret;
 	}
@@ -381,7 +399,7 @@
 EXPORT_SYMBOL_GPL(mei_cldev_enabled);
 
 /**
- * mei_cldev_enable_device - enable me client device
+ * mei_cldev_enable - enable me client device
  *     create connection with me client
  *
  * @cldev: me client device
@@ -608,9 +626,8 @@
 		ret = cldrv->remove(cldev);
 
 	module_put(THIS_MODULE);
-	dev->driver = NULL;
-	return ret;
 
+	return ret;
 }
 
 static ssize_t name_show(struct device *dev, struct device_attribute *a,
@@ -743,15 +760,16 @@
 
 /**
  * mei_cl_bus_set_name - set device name for me client device
+ *  <controller>-<client device>
+ *  Example: 0000:00:16.0-55213584-9a29-4916-badf-0fb7ed682aeb
  *
  * @cldev: me client device
  */
 static inline void mei_cl_bus_set_name(struct mei_cl_device *cldev)
 {
-	dev_set_name(&cldev->dev, "mei:%s:%pUl:%02X",
-		     cldev->name,
-		     mei_me_cl_uuid(cldev->me_cl),
-		     mei_me_cl_ver(cldev->me_cl));
+	dev_set_name(&cldev->dev, "%s-%pUl",
+		     dev_name(cldev->bus->dev),
+		     mei_me_cl_uuid(cldev->me_cl));
 }
 
 /**
--- linux-4.4.0.orig/drivers/misc/mei/client.c
+++ linux-4.4.0/drivers/misc/mei/client.c
@@ -276,6 +276,7 @@
 	down_write(&dev->me_clients_rwsem);
 	me_cl = __mei_me_cl_by_uuid(dev, uuid);
 	__mei_me_cl_del(dev, me_cl);
+	mei_me_cl_put(me_cl);
 	up_write(&dev->me_clients_rwsem);
 }
 
@@ -297,6 +298,7 @@
 	down_write(&dev->me_clients_rwsem);
 	me_cl = __mei_me_cl_by_uuid_id(dev, uuid, id);
 	__mei_me_cl_del(dev, me_cl);
+	mei_me_cl_put(me_cl);
 	up_write(&dev->me_clients_rwsem);
 }
 
@@ -698,7 +700,7 @@
 
 	pm_runtime_mark_last_busy(dev->dev);
 	dev_dbg(dev->dev, "rpm: autosuspend\n");
-	pm_runtime_autosuspend(dev->dev);
+	pm_request_autosuspend(dev->dev);
 }
 
 /**
@@ -1300,6 +1302,9 @@
 		return -EOPNOTSUPP;
 	}
 
+	if (!mei_cl_is_connected(cl))
+		return -ENODEV;
+
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
 		pm_runtime_put_noidle(dev->dev);
@@ -1735,6 +1740,10 @@
 			wake_up(&cl->wait);
 
 		break;
+	case MEI_FOP_DISCONNECT_RSP:
+		mei_io_cb_free(cb);
+		mei_cl_set_disconnected(cl);
+		break;
 	default:
 		BUG_ON(0);
 	}
--- linux-4.4.0.orig/drivers/misc/mei/client.h
+++ linux-4.4.0/drivers/misc/mei/client.h
@@ -156,11 +156,11 @@
  *
  * @cl: host client
  *
- * Return: mtu
+ * Return: mtu or 0 if client is not connected
  */
 static inline size_t mei_cl_mtu(const struct mei_cl *cl)
 {
-	return cl->me_cl->props.max_msg_length;
+	return cl->me_cl ? cl->me_cl->props.max_msg_length : 0;
 }
 
 /**
--- linux-4.4.0.orig/drivers/misc/mei/hbm.c
+++ linux-4.4.0/drivers/misc/mei/hbm.c
@@ -873,8 +873,7 @@
 		cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT_RSP, NULL);
 		if (!cb)
 			return -ENOMEM;
-		cl_dbg(dev, cl, "add disconnect response as first\n");
-		list_add(&cb->list, &dev->ctrl_wr_list.list);
+		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 	}
 	return 0;
 }
--- linux-4.4.0.orig/drivers/misc/mei/hw-me-regs.h
+++ linux-4.4.0/drivers/misc/mei/hw-me-regs.h
@@ -121,6 +121,15 @@
 #define MEI_DEV_ID_SPT_2      0x9D3B  /* Sunrise Point 2 */
 #define MEI_DEV_ID_SPT_H      0xA13A  /* Sunrise Point H */
 #define MEI_DEV_ID_SPT_H_2    0xA13B  /* Sunrise Point H 2 */
+
+#define MEI_DEV_ID_KBP        0xA2BA  /* Kaby Point */
+#define MEI_DEV_ID_KBP_2      0xA2BB  /* Kaby Point 2 */
+
+#define MEI_DEV_ID_LBG        0xA1BA  /* Lewisburg (SPT) */
+
+#define MEI_DEV_ID_BXT_M      0x1A9A  /* Broxton M */
+#define MEI_DEV_ID_APL_I      0x5A9A  /* Apollo Lake I */
+
 /*
  * MEI HW Section
  */
--- linux-4.4.0.orig/drivers/misc/mei/hw-me.c
+++ linux-4.4.0/drivers/misc/mei/hw-me.c
@@ -1258,8 +1258,14 @@
 static bool mei_me_fw_type_sps(struct pci_dev *pdev)
 {
 	u32 reg;
-	/* Read ME FW Status check for SPS Firmware */
-	pci_read_config_dword(pdev, PCI_CFG_HFS_1, &reg);
+	unsigned int devfn;
+
+	/*
+	 * Read ME FW Status register to check for SPS Firmware
+	 * The SPS FW is only signaled in pci function 0
+	 */
+	devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
+	pci_bus_read_config_dword(pdev->bus, devfn, PCI_CFG_HFS_1, &reg);
 	/* if bits [19:16] = 15, running SPS Firmware */
 	return (reg & 0xf0000) == 0xf0000;
 }
--- linux-4.4.0.orig/drivers/misc/mei/hw-txe.c
+++ linux-4.4.0/drivers/misc/mei/hw-txe.c
@@ -972,11 +972,13 @@
 	hisr = mei_txe_br_reg_read(hw, HISR_REG);
 
 	aliveness = mei_txe_aliveness_get(dev);
-	if (hhisr & IPC_HHIER_SEC && aliveness)
+	if (hhisr & IPC_HHIER_SEC && aliveness) {
 		ipc_isr = mei_txe_sec_reg_read_silent(hw,
 				SEC_IPC_HOST_INT_STATUS_REG);
-	else
+	} else {
 		ipc_isr = 0;
+		hhisr &= ~IPC_HHIER_SEC;
+	}
 
 	generated = generated ||
 		(hisr & HISR_INT_STS_MSK) ||
--- linux-4.4.0.orig/drivers/misc/mei/interrupt.c
+++ linux-4.4.0/drivers/misc/mei/interrupt.c
@@ -76,7 +76,6 @@
  * @dev: mei device
  * @hdr: message header
  */
-static inline
 void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
 {
 	/*
@@ -184,10 +183,7 @@
 		return -EMSGSIZE;
 
 	ret = mei_hbm_cl_disconnect_rsp(dev, cl);
-	mei_cl_set_disconnected(cl);
-	mei_io_cb_free(cb);
-	mei_me_cl_put(cl->me_cl);
-	cl->me_cl = NULL;
+	list_move_tail(&cb->list, &cmpl_list->list);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/misc/mei/main.c
+++ linux-4.4.0/drivers/misc/mei/main.c
@@ -207,7 +207,7 @@
 
 		mutex_lock(&dev->device_lock);
 		if (!mei_cl_is_connected(cl)) {
-			rets = -EBUSY;
+			rets = -ENODEV;
 			goto out;
 		}
 	}
@@ -458,7 +458,11 @@
 {
 	struct mei_cl *cl = file->private_data;
 
-	return mei_cl_notify_request(cl, file, request);
+	if (request != MEI_HBM_NOTIFICATION_START &&
+	    request != MEI_HBM_NOTIFICATION_STOP)
+		return -EINVAL;
+
+	return mei_cl_notify_request(cl, file, (u8)request);
 }
 
 /**
@@ -567,7 +571,6 @@
 		break;
 
 	default:
-		dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
 		rets = -ENOIOCTLCMD;
 	}
 
@@ -657,7 +660,9 @@
  * @file: pointer to file structure
  * @band: band bitmap
  *
- * Return: poll mask
+ * Return: negative on error,
+ *         0 if it did no changes,
+ *         and positive a process was added or deleted
  */
 static int mei_fasync(int fd, struct file *file, int band)
 {
@@ -665,7 +670,7 @@
 	struct mei_cl *cl = file->private_data;
 
 	if (!mei_cl_is_connected(cl))
-		return POLLERR;
+		return -ENODEV;
 
 	return fasync_helper(fd, file, band, &cl->ev_async);
 }
--- linux-4.4.0.orig/drivers/misc/mei/mei_dev.h
+++ linux-4.4.0/drivers/misc/mei/mei_dev.h
@@ -782,6 +782,8 @@
 
 bool mei_write_is_idle(struct mei_device *dev);
 
+void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr);
+
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 int mei_dbgfs_register(struct mei_device *dev, const char *name);
 void mei_dbgfs_deregister(struct mei_device *dev);
--- linux-4.4.0.orig/drivers/misc/mei/pci-me.c
+++ linux-4.4.0/drivers/misc/mei/pci-me.c
@@ -40,6 +40,9 @@
 #include "hw-me-regs.h"
 #include "hw-me.h"
 
+static bool disable_msi;
+module_param(disable_msi, bool, 0);
+
 /* mei_pci_tbl - PCI Device ID Table */
 static const struct pci_device_id mei_me_pci_tbl[] = {
 	{MEI_PCI_DEVICE(MEI_DEV_ID_82946GZ, mei_me_legacy_cfg)},
@@ -84,8 +87,15 @@
 
 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT, mei_me_pch8_cfg)},
 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, mei_me_pch8_cfg)},
-	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, mei_me_pch8_cfg)},
-	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, mei_me_pch8_cfg)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, mei_me_pch8_sps_cfg)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, mei_me_pch8_sps_cfg)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_LBG, mei_me_pch8_cfg)},
+
+	{MEI_PCI_DEVICE(MEI_DEV_ID_KBP, mei_me_pch8_cfg)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, mei_me_pch8_cfg)},
+
+	{MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, mei_me_pch8_cfg)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, mei_me_pch8_cfg)},
 
 	/* required last entry */
 	{0, }
@@ -183,7 +193,8 @@
 		err = -ENOMEM;
 		goto free_device;
 	}
-	pci_enable_msi(pdev);
+	if (!disable_msi)
+		pci_enable_msi(pdev);
 
 	 /* request and enable interrupt */
 	irqflags = pci_dev_msi_enabled(pdev) ? IRQF_ONESHOT : IRQF_SHARED;
@@ -223,8 +234,11 @@
 	if (!pci_dev_run_wake(pdev))
 		mei_me_set_pm_domain(dev);
 
-	if (mei_pg_is_enabled(dev))
+	if (mei_pg_is_enabled(dev)) {
 		pm_runtime_put_noidle(&pdev->dev);
+		if (hw->d0i3_supported)
+			pm_runtime_allow(&pdev->dev);
+	}
 
 	dev_dbg(&pdev->dev, "initialization successful.\n");
 
--- linux-4.4.0.orig/drivers/misc/mic/card/mic_x100.c
+++ linux-4.4.0/drivers/misc/mic/card/mic_x100.c
@@ -249,6 +249,9 @@
 	mdrv->dev = &pdev->dev;
 	snprintf(mdrv->name, sizeof(mic_driver_name), mic_driver_name);
 
+	/* FIXME: use dma_set_mask_and_coherent() and check result */
+	dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+
 	mdev->mmio.pa = MIC_X100_MMIO_BASE;
 	mdev->mmio.len = MIC_X100_MMIO_LEN;
 	mdev->mmio.va = devm_ioremap(&pdev->dev, MIC_X100_MMIO_BASE,
@@ -294,18 +297,6 @@
 	mic_remove(pdev);
 }
 
-static u64 mic_dma_mask = DMA_BIT_MASK(64);
-
-static struct platform_device mic_platform_dev = {
-	.name = mic_driver_name,
-	.id   = 0,
-	.num_resources = 0,
-	.dev = {
-		.dma_mask = &mic_dma_mask,
-		.coherent_dma_mask = DMA_BIT_MASK(64),
-	},
-};
-
 static struct platform_driver __refdata mic_platform_driver = {
 	.probe = mic_probe,
 	.remove = mic_remove,
@@ -315,6 +306,8 @@
 	},
 };
 
+static struct platform_device *mic_platform_dev;
+
 static int __init mic_init(void)
 {
 	int ret;
@@ -327,9 +320,12 @@
 	}
 
 	mic_init_card_debugfs();
-	ret = platform_device_register(&mic_platform_dev);
+
+	mic_platform_dev = platform_device_register_simple(mic_driver_name,
+							   0, NULL, 0);
+	ret = PTR_ERR_OR_ZERO(mic_platform_dev);
 	if (ret) {
-		pr_err("platform_device_register ret %d\n", ret);
+		pr_err("platform_device_register_full ret %d\n", ret);
 		goto cleanup_debugfs;
 	}
 	ret = platform_driver_register(&mic_platform_driver);
@@ -340,7 +336,7 @@
 	return ret;
 
 device_unregister:
-	platform_device_unregister(&mic_platform_dev);
+	platform_device_unregister(mic_platform_dev);
 cleanup_debugfs:
 	mic_exit_card_debugfs();
 done:
@@ -350,7 +346,7 @@
 static void __exit mic_exit(void)
 {
 	platform_driver_unregister(&mic_platform_driver);
-	platform_device_unregister(&mic_platform_dev);
+	platform_device_unregister(mic_platform_dev);
 	mic_exit_card_debugfs();
 }
 
--- linux-4.4.0.orig/drivers/misc/mic/host/mic_virtio.c
+++ linux-4.4.0/drivers/misc/mic/host/mic_virtio.c
@@ -556,6 +556,12 @@
 		goto exit;
 	}
 
+	/* Ensure desc has not changed between the two reads */
+	if (memcmp(&dd, dd_config, sizeof(dd))) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
 	vqconfig = mic_vq_config(dd_config);
 	for (i = 0; i < dd.num_vq; i++) {
 		if (le16_to_cpu(vqconfig[i].num) > MIC_MAX_VRING_ENTRIES) {
--- linux-4.4.0.orig/drivers/misc/mic/scif/scif_api.c
+++ linux-4.4.0/drivers/misc/mic/scif/scif_api.c
@@ -370,11 +370,10 @@
 			goto scif_bind_exit;
 		}
 	} else {
-		pn = scif_get_new_port();
-		if (!pn) {
-			ret = -ENOSPC;
+		ret = scif_get_new_port();
+		if (ret < 0)
 			goto scif_bind_exit;
-		}
+		pn = ret;
 	}
 
 	ep->state = SCIFEP_BOUND;
@@ -648,13 +647,12 @@
 			err = -EISCONN;
 		break;
 	case SCIFEP_UNBOUND:
-		ep->port.port = scif_get_new_port();
-		if (!ep->port.port) {
-			err = -ENOSPC;
-		} else {
-			ep->port.node = scif_info.nodeid;
-			ep->conn_async_state = ASYNC_CONN_IDLE;
-		}
+		err = scif_get_new_port();
+		if (err < 0)
+			break;
+		ep->port.port = err;
+		ep->port.node = scif_info.nodeid;
+		ep->conn_async_state = ASYNC_CONN_IDLE;
 		/* Fall through */
 	case SCIFEP_BOUND:
 		/*
--- linux-4.4.0.orig/drivers/misc/mic/scif/scif_fence.c
+++ linux-4.4.0/drivers/misc/mic/scif/scif_fence.c
@@ -271,7 +271,7 @@
 dma_fail:
 	if (!x100)
 		dma_pool_free(ep->remote_dev->signal_pool, status,
-			      status->src_dma_addr);
+			      src - offsetof(struct scif_status, val));
 alloc_fail:
 	return err;
 }
--- linux-4.4.0.orig/drivers/misc/mic/scif/scif_rma.c
+++ linux-4.4.0/drivers/misc/mic/scif/scif_rma.c
@@ -414,7 +414,7 @@
 		if (err)
 			goto error_window;
 		err = scif_map_page(&window->num_pages_lookup.lookup[j],
-				    vmalloc_dma_phys ?
+				    vmalloc_num_pages ?
 				    vmalloc_to_page(&window->num_pages[i]) :
 				    virt_to_page(&window->num_pages[i]),
 				    remote_dev);
@@ -1398,12 +1398,13 @@
 				mm,
 				(u64)addr,
 				nr_pages,
-				!!(prot & SCIF_PROT_WRITE),
-				0,
+				(prot & SCIF_PROT_WRITE) ? FOLL_WRITE : 0,
 				pinned_pages->pages,
 				NULL);
 		up_write(&mm->mmap_sem);
 		if (nr_pages != pinned_pages->nr_pages) {
+			if (pinned_pages->nr_pages < 0)
+				pinned_pages->nr_pages = 0;
 			if (try_upgrade) {
 				if (ulimit)
 					__scif_dec_pinned_vm_lock(mm,
@@ -1424,7 +1425,6 @@
 
 	if (pinned_pages->nr_pages < nr_pages) {
 		err = -EFAULT;
-		pinned_pages->nr_pages = nr_pages;
 		goto dec_pinned;
 	}
 
@@ -1437,7 +1437,6 @@
 		__scif_dec_pinned_vm_lock(mm, nr_pages, 0);
 	/* Something went wrong! Rollback */
 error_unmap:
-	pinned_pages->nr_pages = nr_pages;
 	scif_destroy_pinned_pages(pinned_pages);
 	*pages = NULL;
 	dev_dbg(scif_info.mdev.this_device,
@@ -1511,7 +1510,7 @@
 	if ((map_flags & SCIF_MAP_FIXED) &&
 	    ((ALIGN(offset, PAGE_SIZE) != offset) ||
 	    (offset < 0) ||
-	    (offset + (off_t)len < offset)))
+	    (len > LONG_MAX - offset)))
 		return -EINVAL;
 
 	might_sleep();
@@ -1614,7 +1613,7 @@
 	if ((map_flags & SCIF_MAP_FIXED) &&
 	    ((ALIGN(offset, PAGE_SIZE) != offset) ||
 	    (offset < 0) ||
-	    (offset + (off_t)len < offset)))
+	    (len > LONG_MAX - offset)))
 		return -EINVAL;
 
 	/* Unsupported protection requested */
@@ -1732,7 +1731,8 @@
 
 	/* Offset is not page aligned or offset+len wraps around */
 	if ((ALIGN(offset, PAGE_SIZE) != offset) ||
-	    (offset + (off_t)len < offset))
+	    (offset < 0) ||
+	    (len > LONG_MAX - offset))
 		return -EINVAL;
 
 	err = scif_verify_epd(ep);
--- linux-4.4.0.orig/drivers/misc/sgi-gru/grufault.c
+++ linux-4.4.0/drivers/misc/sgi-gru/grufault.c
@@ -199,7 +199,7 @@
 	*pageshift = PAGE_SHIFT;
 #endif
 	if (get_user_pages
-	    (current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0)
+	    (current, current->mm, vaddr, 1, write ? FOLL_WRITE : 0, &page, NULL) <= 0)
 		return -EFAULT;
 	*paddr = page_to_phys(page);
 	put_page(page);
--- linux-4.4.0.orig/drivers/misc/sgi-gru/grukdump.c
+++ linux-4.4.0/drivers/misc/sgi-gru/grukdump.c
@@ -27,6 +27,9 @@
 #include <linux/delay.h>
 #include <linux/bitops.h>
 #include <asm/uv/uv_hub.h>
+
+#include <linux/nospec.h>
+
 #include "gru.h"
 #include "grutables.h"
 #include "gruhandles.h"
@@ -196,6 +199,7 @@
 	/* Currently, only dump by gid is implemented */
 	if (req.gid >= gru_max_gids)
 		return -EINVAL;
+	req.gid = array_index_nospec(req.gid, gru_max_gids);
 
 	gru = GID_TO_GRU(req.gid);
 	ubuf = req.buf;
--- linux-4.4.0.orig/drivers/misc/sgi-xp/xpc_partition.c
+++ linux-4.4.0/drivers/misc/sgi-xp/xpc_partition.c
@@ -70,7 +70,7 @@
 	unsigned long rp_pa = nasid;	/* seed with nasid */
 	size_t len = 0;
 	size_t buf_len = 0;
-	void *buf = buf;
+	void *buf = NULL;
 	void *buf_base = NULL;
 	enum xp_retval (*get_partition_rsvd_page_pa)
 		(void *, u64 *, unsigned long *, size_t *) =
--- linux-4.4.0.orig/drivers/misc/ti-st/st_kim.c
+++ linux-4.4.0/drivers/misc/ti-st/st_kim.c
@@ -757,14 +757,14 @@
 	err = gpio_request(kim_gdata->nshutdown, "kim");
 	if (unlikely(err)) {
 		pr_err(" gpio %d request failed ", kim_gdata->nshutdown);
-		return err;
+		goto err_sysfs_group;
 	}
 
 	/* Configure nShutdown GPIO as output=0 */
 	err = gpio_direction_output(kim_gdata->nshutdown, 0);
 	if (unlikely(err)) {
 		pr_err(" unable to configure gpio %d", kim_gdata->nshutdown);
-		return err;
+		goto err_sysfs_group;
 	}
 	/* get reference of pdev for request_firmware
 	 */
--- linux-4.4.0.orig/drivers/misc/tsl2550.c
+++ linux-4.4.0/drivers/misc/tsl2550.c
@@ -177,7 +177,7 @@
 		} else
 			lux = 0;
 	else
-		return -EAGAIN;
+		return 0;
 
 	/* LUX range check */
 	return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
--- linux-4.4.0.orig/drivers/misc/vexpress-syscfg.c
+++ linux-4.4.0/drivers/misc/vexpress-syscfg.c
@@ -61,7 +61,7 @@
 	int tries;
 	long timeout;
 
-	if (WARN_ON(index > func->num_templates))
+	if (WARN_ON(index >= func->num_templates))
 		return -EINVAL;
 
 	command = readl(syscfg->base + SYS_CFGCTRL);
--- linux-4.4.0.orig/drivers/misc/vmw_balloon.c
+++ linux-4.4.0/drivers/misc/vmw_balloon.c
@@ -45,6 +45,7 @@
 #include <linux/seq_file.h>
 #include <linux/vmw_vmci_defs.h>
 #include <linux/vmw_vmci_api.h>
+#include <linux/io.h>
 #include <asm/hypervisor.h>
 
 MODULE_AUTHOR("VMware, Inc.");
@@ -341,7 +342,13 @@
 		success = false;
 	}
 
-	if (b->capabilities & VMW_BALLOON_BATCHED_2M_CMDS)
+	/*
+	 * 2MB pages are only supported with batching. If batching is for some
+	 * reason disabled, do not use 2MB pages, since otherwise the legacy
+	 * mechanism is used with 2MB pages, causing a failure.
+	 */
+	if ((b->capabilities & VMW_BALLOON_BATCHED_2M_CMDS) &&
+	    (b->capabilities & VMW_BALLOON_BATCHED_CMDS))
 		b->supported_page_sizes = 2;
 	else
 		b->supported_page_sizes = 1;
@@ -450,7 +457,7 @@
 
 	pfn32 = (u32)pfn;
 	if (pfn32 != pfn)
-		return -1;
+		return -EINVAL;
 
 	STATS_INC(b->stats.lock[false]);
 
@@ -460,14 +467,14 @@
 
 	pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status);
 	STATS_INC(b->stats.lock_fail[false]);
-	return 1;
+	return -EIO;
 }
 
 static int vmballoon_send_batched_lock(struct vmballoon *b,
 		unsigned int num_pages, bool is_2m_pages, unsigned int *target)
 {
 	unsigned long status;
-	unsigned long pfn = page_to_pfn(b->page);
+	unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page));
 
 	STATS_INC(b->stats.lock[is_2m_pages]);
 
@@ -515,7 +522,7 @@
 		unsigned int num_pages, bool is_2m_pages, unsigned int *target)
 {
 	unsigned long status;
-	unsigned long pfn = page_to_pfn(b->page);
+	unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page));
 
 	STATS_INC(b->stats.unlock[is_2m_pages]);
 
@@ -576,15 +583,9 @@
 		}
 	}
 
-	if (b->batch_page) {
-		vunmap(b->batch_page);
-		b->batch_page = NULL;
-	}
-
-	if (b->page) {
-		__free_page(b->page);
-		b->page = NULL;
-	}
+	/* Clearing the batch_page unconditionally has no adverse effect */
+	free_page((unsigned long)b->batch_page);
+	b->batch_page = NULL;
 }
 
 /*
@@ -603,11 +604,12 @@
 
 	locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status,
 								target);
-	if (locked > 0) {
+	if (locked) {
 		STATS_INC(b->stats.refused_alloc[false]);
 
-		if (hv_status == VMW_BALLOON_ERROR_RESET ||
-				hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED) {
+		if (locked == -EIO &&
+		    (hv_status == VMW_BALLOON_ERROR_RESET ||
+		     hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED)) {
 			vmballoon_free_page(page, false);
 			return -EIO;
 		}
@@ -623,7 +625,7 @@
 		} else {
 			vmballoon_free_page(page, false);
 		}
-		return -EIO;
+		return locked;
 	}
 
 	/* track allocated page */
@@ -991,16 +993,13 @@
 
 static bool vmballoon_init_batching(struct vmballoon *b)
 {
-	b->page = alloc_page(VMW_PAGE_ALLOC_NOSLEEP);
-	if (!b->page)
-		return false;
+	struct page *page;
 
-	b->batch_page = vmap(&b->page, 1, VM_MAP, PAGE_KERNEL);
-	if (!b->batch_page) {
-		__free_page(b->page);
+	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	if (!page)
 		return false;
-	}
 
+	b->batch_page = page_address(page);
 	return true;
 }
 
@@ -1038,29 +1037,30 @@
  */
 static int vmballoon_vmci_init(struct vmballoon *b)
 {
-	int error = 0;
+	unsigned long error, dummy;
 
-	if ((b->capabilities & VMW_BALLOON_SIGNALLED_WAKEUP_CMD) != 0) {
-		error = vmci_doorbell_create(&b->vmci_doorbell,
-				VMCI_FLAG_DELAYED_CB,
-				VMCI_PRIVILEGE_FLAG_RESTRICTED,
-				vmballoon_doorbell, b);
-
-		if (error == VMCI_SUCCESS) {
-			VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET,
-					b->vmci_doorbell.context,
-					b->vmci_doorbell.resource, error);
-			STATS_INC(b->stats.doorbell_set);
-		}
-	}
+	if ((b->capabilities & VMW_BALLOON_SIGNALLED_WAKEUP_CMD) == 0)
+		return 0;
 
-	if (error != 0) {
-		vmballoon_vmci_cleanup(b);
+	error = vmci_doorbell_create(&b->vmci_doorbell, VMCI_FLAG_DELAYED_CB,
+				     VMCI_PRIVILEGE_FLAG_RESTRICTED,
+				     vmballoon_doorbell, b);
 
-		return -EIO;
-	}
+	if (error != VMCI_SUCCESS)
+		goto fail;
+
+	error = VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, b->vmci_doorbell.context,
+				   b->vmci_doorbell.resource, dummy);
+
+	STATS_INC(b->stats.doorbell_set);
+
+	if (error != VMW_BALLOON_SUCCESS)
+		goto fail;
 
 	return 0;
+fail:
+	vmballoon_vmci_cleanup(b);
+	return -EIO;
 }
 
 /*
@@ -1298,7 +1298,14 @@
 
 	return 0;
 }
-module_init(vmballoon_init);
+
+/*
+ * Using late_initcall() instead of module_init() allows the balloon to use the
+ * VMCI doorbell even when the balloon is built into the kernel. Otherwise the
+ * VMCI is probed only after the balloon is initialized. If the balloon is used
+ * as a module, late_initcall() is equivalent to module_init().
+ */
+late_initcall(vmballoon_init);
 
 static void __exit vmballoon_exit(void)
 {
--- linux-4.4.0.orig/drivers/misc/vmw_vmci/vmci_context.c
+++ linux-4.4.0/drivers/misc/vmw_vmci/vmci_context.c
@@ -28,6 +28,9 @@
 #include "vmci_driver.h"
 #include "vmci_event.h"
 
+/* Use a wide upper bound for the maximum contexts. */
+#define VMCI_MAX_CONTEXTS 2000
+
 /*
  * List of current VMCI contexts.  Contexts can be added by
  * vmci_ctx_create() and removed via vmci_ctx_destroy().
@@ -124,19 +127,22 @@
 	/* Initialize host-specific VMCI context. */
 	init_waitqueue_head(&context->host_context.wait_queue);
 
-	context->queue_pair_array = vmci_handle_arr_create(0);
+	context->queue_pair_array =
+		vmci_handle_arr_create(0, VMCI_MAX_GUEST_QP_COUNT);
 	if (!context->queue_pair_array) {
 		error = -ENOMEM;
 		goto err_free_ctx;
 	}
 
-	context->doorbell_array = vmci_handle_arr_create(0);
+	context->doorbell_array =
+		vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
 	if (!context->doorbell_array) {
 		error = -ENOMEM;
 		goto err_free_qp_array;
 	}
 
-	context->pending_doorbell_array = vmci_handle_arr_create(0);
+	context->pending_doorbell_array =
+		vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
 	if (!context->pending_doorbell_array) {
 		error = -ENOMEM;
 		goto err_free_db_array;
@@ -211,7 +217,7 @@
 	 * We create an array to hold the subscribers we find when
 	 * scanning through all contexts.
 	 */
-	subscriber_array = vmci_handle_arr_create(0);
+	subscriber_array = vmci_handle_arr_create(0, VMCI_MAX_CONTEXTS);
 	if (subscriber_array == NULL)
 		return VMCI_ERROR_NO_MEM;
 
@@ -630,20 +636,26 @@
 
 	spin_lock(&context->lock);
 
-	list_for_each_entry(n, &context->notifier_list, node) {
-		if (vmci_handle_is_equal(n->handle, notifier->handle)) {
-			exists = true;
-			break;
+	if (context->n_notifiers < VMCI_MAX_CONTEXTS) {
+		list_for_each_entry(n, &context->notifier_list, node) {
+			if (vmci_handle_is_equal(n->handle, notifier->handle)) {
+				exists = true;
+				break;
+			}
 		}
-	}
 
-	if (exists) {
-		kfree(notifier);
-		result = VMCI_ERROR_ALREADY_EXISTS;
+		if (exists) {
+			kfree(notifier);
+			result = VMCI_ERROR_ALREADY_EXISTS;
+		} else {
+			list_add_tail_rcu(&notifier->node,
+					  &context->notifier_list);
+			context->n_notifiers++;
+			result = VMCI_SUCCESS;
+		}
 	} else {
-		list_add_tail_rcu(&notifier->node, &context->notifier_list);
-		context->n_notifiers++;
-		result = VMCI_SUCCESS;
+		kfree(notifier);
+		result = VMCI_ERROR_NO_MEM;
 	}
 
 	spin_unlock(&context->lock);
@@ -728,8 +740,7 @@
 					u32 *buf_size, void **pbuf)
 {
 	struct dbell_cpt_state *dbells;
-	size_t n_doorbells;
-	int i;
+	u32 i, n_doorbells;
 
 	n_doorbells = vmci_handle_arr_get_size(context->doorbell_array);
 	if (n_doorbells > 0) {
@@ -739,7 +750,7 @@
 			return VMCI_ERROR_MORE_DATA;
 		}
 
-		dbells = kmalloc(data_size, GFP_ATOMIC);
+		dbells = kzalloc(data_size, GFP_ATOMIC);
 		if (!dbells)
 			return VMCI_ERROR_NO_MEM;
 
@@ -867,7 +878,8 @@
 	spin_lock(&context->lock);
 
 	*db_handle_array = context->pending_doorbell_array;
-	context->pending_doorbell_array = vmci_handle_arr_create(0);
+	context->pending_doorbell_array =
+		vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
 	if (!context->pending_doorbell_array) {
 		context->pending_doorbell_array = *db_handle_array;
 		*db_handle_array = NULL;
@@ -949,12 +961,11 @@
 		return VMCI_ERROR_NOT_FOUND;
 
 	spin_lock(&context->lock);
-	if (!vmci_handle_arr_has_entry(context->doorbell_array, handle)) {
-		vmci_handle_arr_append_entry(&context->doorbell_array, handle);
-		result = VMCI_SUCCESS;
-	} else {
+	if (!vmci_handle_arr_has_entry(context->doorbell_array, handle))
+		result = vmci_handle_arr_append_entry(&context->doorbell_array,
+						      handle);
+	else
 		result = VMCI_ERROR_DUPLICATE_ENTRY;
-	}
 
 	spin_unlock(&context->lock);
 	vmci_ctx_put(context);
@@ -1090,15 +1101,16 @@
 			if (!vmci_handle_arr_has_entry(
 					dst_context->pending_doorbell_array,
 					handle)) {
-				vmci_handle_arr_append_entry(
+				result = vmci_handle_arr_append_entry(
 					&dst_context->pending_doorbell_array,
 					handle);
-
-				ctx_signal_notify(dst_context);
-				wake_up(&dst_context->host_context.wait_queue);
-
+				if (result == VMCI_SUCCESS) {
+					ctx_signal_notify(dst_context);
+					wake_up(&dst_context->host_context.wait_queue);
+				}
+			} else {
+				result = VMCI_SUCCESS;
 			}
-			result = VMCI_SUCCESS;
 		}
 		spin_unlock(&dst_context->lock);
 	}
@@ -1125,13 +1137,11 @@
 	if (context == NULL || vmci_handle_is_invalid(handle))
 		return VMCI_ERROR_INVALID_ARGS;
 
-	if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle)) {
-		vmci_handle_arr_append_entry(&context->queue_pair_array,
-					     handle);
-		result = VMCI_SUCCESS;
-	} else {
+	if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle))
+		result = vmci_handle_arr_append_entry(
+			&context->queue_pair_array, handle);
+	else
 		result = VMCI_ERROR_DUPLICATE_ENTRY;
-	}
 
 	return result;
 }
--- linux-4.4.0.orig/drivers/misc/vmw_vmci/vmci_doorbell.c
+++ linux-4.4.0/drivers/misc/vmw_vmci/vmci_doorbell.c
@@ -318,7 +318,8 @@
 
 	entry = container_of(resource, struct dbell_entry, resource);
 	if (entry->run_delayed) {
-		schedule_work(&entry->work);
+		if (!schedule_work(&entry->work))
+			vmci_resource_put(resource);
 	} else {
 		entry->notify_cb(entry->client_data);
 		vmci_resource_put(resource);
@@ -366,7 +367,8 @@
 		    atomic_read(&dbell->active) == 1) {
 			if (dbell->run_delayed) {
 				vmci_resource_get(&dbell->resource);
-				schedule_work(&dbell->work);
+				if (!schedule_work(&dbell->work))
+					vmci_resource_put(&dbell->resource);
 			} else {
 				dbell->notify_cb(dbell->client_data);
 			}
--- linux-4.4.0.orig/drivers/misc/vmw_vmci/vmci_handle_array.c
+++ linux-4.4.0/drivers/misc/vmw_vmci/vmci_handle_array.c
@@ -16,24 +16,29 @@
 #include <linux/slab.h>
 #include "vmci_handle_array.h"
 
-static size_t handle_arr_calc_size(size_t capacity)
+static size_t handle_arr_calc_size(u32 capacity)
 {
-	return sizeof(struct vmci_handle_arr) +
+	return VMCI_HANDLE_ARRAY_HEADER_SIZE +
 	    capacity * sizeof(struct vmci_handle);
 }
 
-struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity)
+struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity)
 {
 	struct vmci_handle_arr *array;
 
+	if (max_capacity == 0 || capacity > max_capacity)
+		return NULL;
+
 	if (capacity == 0)
-		capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE;
+		capacity = min((u32)VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY,
+			       max_capacity);
 
 	array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC);
 	if (!array)
 		return NULL;
 
 	array->capacity = capacity;
+	array->max_capacity = max_capacity;
 	array->size = 0;
 
 	return array;
@@ -44,27 +49,34 @@
 	kfree(array);
 }
 
-void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
-				  struct vmci_handle handle)
+int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+				 struct vmci_handle handle)
 {
 	struct vmci_handle_arr *array = *array_ptr;
 
 	if (unlikely(array->size >= array->capacity)) {
 		/* reallocate. */
 		struct vmci_handle_arr *new_array;
-		size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT;
-		size_t new_size = handle_arr_calc_size(new_capacity);
+		u32 capacity_bump = min(array->max_capacity - array->capacity,
+					array->capacity);
+		size_t new_size = handle_arr_calc_size(array->capacity +
+						       capacity_bump);
+
+		if (array->size >= array->max_capacity)
+			return VMCI_ERROR_NO_MEM;
 
 		new_array = krealloc(array, new_size, GFP_ATOMIC);
 		if (!new_array)
-			return;
+			return VMCI_ERROR_NO_MEM;
 
-		new_array->capacity = new_capacity;
+		new_array->capacity += capacity_bump;
 		*array_ptr = array = new_array;
 	}
 
 	array->entries[array->size] = handle;
 	array->size++;
+
+	return VMCI_SUCCESS;
 }
 
 /*
@@ -74,7 +86,7 @@
 						struct vmci_handle entry_handle)
 {
 	struct vmci_handle handle = VMCI_INVALID_HANDLE;
-	size_t i;
+	u32 i;
 
 	for (i = 0; i < array->size; i++) {
 		if (vmci_handle_is_equal(array->entries[i], entry_handle)) {
@@ -109,7 +121,7 @@
  * Handle at given index, VMCI_INVALID_HANDLE if invalid index.
  */
 struct vmci_handle
-vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index)
 {
 	if (unlikely(index >= array->size))
 		return VMCI_INVALID_HANDLE;
@@ -120,7 +132,7 @@
 bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
 			       struct vmci_handle entry_handle)
 {
-	size_t i;
+	u32 i;
 
 	for (i = 0; i < array->size; i++)
 		if (vmci_handle_is_equal(array->entries[i], entry_handle))
--- linux-4.4.0.orig/drivers/misc/vmw_vmci/vmci_handle_array.h
+++ linux-4.4.0/drivers/misc/vmw_vmci/vmci_handle_array.h
@@ -17,32 +17,41 @@
 #define _VMCI_HANDLE_ARRAY_H_
 
 #include <linux/vmw_vmci_defs.h>
+#include <linux/limits.h>
 #include <linux/types.h>
 
-#define VMCI_HANDLE_ARRAY_DEFAULT_SIZE 4
-#define VMCI_ARR_CAP_MULT 2	/* Array capacity multiplier */
-
 struct vmci_handle_arr {
-	size_t capacity;
-	size_t size;
+	u32 capacity;
+	u32 max_capacity;
+	u32 size;
+	u32 pad;
 	struct vmci_handle entries[];
 };
 
-struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity);
+#define VMCI_HANDLE_ARRAY_HEADER_SIZE				\
+	offsetof(struct vmci_handle_arr, entries)
+/* Select a default capacity that results in a 64 byte sized array */
+#define VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY			6
+/* Make sure that the max array size can be expressed by a u32 */
+#define VMCI_HANDLE_ARRAY_MAX_CAPACITY				\
+	((U32_MAX - VMCI_HANDLE_ARRAY_HEADER_SIZE - 1) /	\
+	sizeof(struct vmci_handle))
+
+struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity);
 void vmci_handle_arr_destroy(struct vmci_handle_arr *array);
-void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
-				  struct vmci_handle handle);
+int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+				 struct vmci_handle handle);
 struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
 						struct vmci_handle
 						entry_handle);
 struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array);
 struct vmci_handle
-vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index);
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index);
 bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
 			       struct vmci_handle entry_handle);
 struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array);
 
-static inline size_t vmci_handle_arr_get_size(
+static inline u32 vmci_handle_arr_get_size(
 	const struct vmci_handle_arr *array)
 {
 	return array->size;
--- linux-4.4.0.orig/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ linux-4.4.0/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -298,8 +298,11 @@
 	size_t pas_size;
 	size_t vas_size;
 	size_t queue_size = sizeof(*queue) + sizeof(*queue->kernel_if);
-	const u64 num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+	u64 num_pages;
 
+	if (size > SIZE_MAX - PAGE_SIZE)
+		return NULL;
+	num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
 	if (num_pages >
 		 (SIZE_MAX - queue_size) /
 		 (sizeof(*queue->kernel_if->u.g.pas) +
@@ -624,15 +627,21 @@
 {
 	struct vmci_queue *queue;
 	size_t queue_page_size;
-	const u64 num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+	u64 num_pages;
 	const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));
 
+	if (size > SIZE_MAX - PAGE_SIZE)
+		return NULL;
+	num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
 	if (num_pages > (SIZE_MAX - queue_size) /
 		 sizeof(*queue->kernel_if->u.h.page))
 		return NULL;
 
 	queue_page_size = num_pages * sizeof(*queue->kernel_if->u.h.page);
 
+	if (queue_size + queue_page_size > KMALLOC_MAX_SIZE)
+		return NULL;
+
 	queue = kzalloc(queue_size + queue_page_size, GFP_KERNEL);
 	if (queue) {
 		queue->q_header = NULL;
@@ -726,7 +735,7 @@
 
 	for (i = 0; i < num_pages; i++) {
 		if (dirty)
-			set_page_dirty(pages[i]);
+			set_page_dirty_lock(pages[i]);
 
 		page_cache_release(pages[i]);
 		pages[i] = NULL;
@@ -749,11 +758,12 @@
 	retval = get_user_pages_fast((uintptr_t) produce_uva,
 				     produce_q->kernel_if->num_pages, 1,
 				     produce_q->kernel_if->u.h.header_page);
-	if (retval < produce_q->kernel_if->num_pages) {
+	if (retval < (int)produce_q->kernel_if->num_pages) {
 		pr_debug("get_user_pages_fast(produce) failed (retval=%d)",
 			retval);
-		qp_release_pages(produce_q->kernel_if->u.h.header_page,
-				 retval, false);
+		if (retval > 0)
+			qp_release_pages(produce_q->kernel_if->u.h.header_page,
+					retval, false);
 		err = VMCI_ERROR_NO_MEM;
 		goto out;
 	}
@@ -761,11 +771,12 @@
 	retval = get_user_pages_fast((uintptr_t) consume_uva,
 				     consume_q->kernel_if->num_pages, 1,
 				     consume_q->kernel_if->u.h.header_page);
-	if (retval < consume_q->kernel_if->num_pages) {
+	if (retval < (int)consume_q->kernel_if->num_pages) {
 		pr_debug("get_user_pages_fast(consume) failed (retval=%d)",
 			retval);
-		qp_release_pages(consume_q->kernel_if->u.h.header_page,
-				 retval, false);
+		if (retval > 0)
+			qp_release_pages(consume_q->kernel_if->u.h.header_page,
+					retval, false);
 		qp_release_pages(produce_q->kernel_if->u.h.header_page,
 				 produce_q->kernel_if->num_pages, false);
 		err = VMCI_ERROR_NO_MEM;
--- linux-4.4.0.orig/drivers/misc/vmw_vmci/vmci_resource.c
+++ linux-4.4.0/drivers/misc/vmw_vmci/vmci_resource.c
@@ -150,7 +150,8 @@
 	spin_lock(&vmci_resource_table.lock);
 
 	hlist_for_each_entry(r, &vmci_resource_table.entries[idx], node) {
-		if (vmci_handle_is_equal(r->handle, resource->handle)) {
+		if (vmci_handle_is_equal(r->handle, resource->handle) &&
+		    resource->type == r->type) {
 			hlist_del_init_rcu(&r->node);
 			break;
 		}
--- linux-4.4.0.orig/drivers/mmc/card/block.c
+++ linux-4.4.0/drivers/mmc/card/block.c
@@ -47,13 +47,10 @@
 #include "queue.h"
 
 MODULE_ALIAS("mmc:block");
-
-#ifdef KERNEL
 #ifdef MODULE_PARAM_PREFIX
 #undef MODULE_PARAM_PREFIX
 #endif
 #define MODULE_PARAM_PREFIX "mmcblk."
-#endif
 
 #define INAND_CMD38_ARG_EXT_CSD  113
 #define INAND_CMD38_ARG_ERASE    0x00
@@ -171,11 +168,7 @@
 
 static inline int mmc_get_devidx(struct gendisk *disk)
 {
-	int devmaj = MAJOR(disk_devt(disk));
-	int devidx = MINOR(disk_devt(disk)) / perdev_minors;
-
-	if (!devmaj)
-		devidx = disk->first_minor / perdev_minors;
+	int devidx = disk->first_minor / perdev_minors;
 	return devidx;
 }
 
@@ -596,6 +589,14 @@
 	struct mmc_card *card;
 	int err = 0, ioc_err = 0;
 
+	/*
+	 * The caller must have CAP_SYS_RAWIO, and must be calling this on the
+	 * whole block device, not on a partition.  This prevents overspray
+	 * between sibling partitions.
+	 */
+	if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
+		return -EPERM;
+
 	idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
 	if (IS_ERR(idata))
 		return PTR_ERR(idata);
@@ -638,6 +639,14 @@
 	int i, err = 0, ioc_err = 0;
 	__u64 num_of_cmds;
 
+	/*
+	 * The caller must have CAP_SYS_RAWIO, and must be calling this on the
+	 * whole block device, not on a partition.  This prevents overspray
+	 * between sibling partitions.
+	 */
+	if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
+		return -EPERM;
+
 	if (copy_from_user(&num_of_cmds, &user->num_of_cmds,
 			   sizeof(num_of_cmds)))
 		return -EFAULT;
@@ -659,8 +668,10 @@
 	}
 
 	md = mmc_blk_get(bdev->bd_disk);
-	if (!md)
+	if (!md) {
+		err = -EINVAL;
 		goto cmd_err;
+	}
 
 	card = md->queue.card;
 	if (IS_ERR(card)) {
@@ -693,14 +704,6 @@
 static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
 	unsigned int cmd, unsigned long arg)
 {
-	/*
-	 * The caller must have CAP_SYS_RAWIO, and must be calling this on the
-	 * whole block device, not on a partition.  This prevents overspray
-	 * between sibling partitions.
-	 */
-	if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
-		return -EPERM;
-
 	switch (cmd) {
 	case MMC_IOC_CMD:
 		return mmc_blk_ioctl_cmd(bdev,
@@ -1747,7 +1750,7 @@
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_packed *packed = mqrq->packed;
 	bool do_rel_wr, do_data_tag;
-	u32 *packed_cmd_hdr;
+	__le32 *packed_cmd_hdr;
 	u8 hdr_blocks;
 	u8 i = 1;
 
@@ -1759,8 +1762,8 @@
 
 	packed_cmd_hdr = packed->cmd_hdr;
 	memset(packed_cmd_hdr, 0, sizeof(packed->cmd_hdr));
-	packed_cmd_hdr[0] = (packed->nr_entries << 16) |
-		(PACKED_CMD_WR << 8) | PACKED_CMD_VER;
+	packed_cmd_hdr[0] = cpu_to_le32((packed->nr_entries << 16) |
+		(PACKED_CMD_WR << 8) | PACKED_CMD_VER);
 	hdr_blocks = mmc_large_sector(card) ? 8 : 1;
 
 	/*
@@ -1771,17 +1774,16 @@
 		do_data_tag = (card->ext_csd.data_tag_unit_size) &&
 			(prq->cmd_flags & REQ_META) &&
 			(rq_data_dir(prq) == WRITE) &&
-			((brq->data.blocks * brq->data.blksz) >=
-			 card->ext_csd.data_tag_unit_size);
+			blk_rq_bytes(prq) >= card->ext_csd.data_tag_unit_size;
 		/* Argument of CMD23 */
-		packed_cmd_hdr[(i * 2)] =
+		packed_cmd_hdr[(i * 2)] = cpu_to_le32(
 			(do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
 			(do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) |
-			blk_rq_sectors(prq);
+			blk_rq_sectors(prq));
 		/* Argument of CMD18 or CMD25 */
-		packed_cmd_hdr[((i * 2)) + 1] =
+		packed_cmd_hdr[((i * 2)) + 1] = cpu_to_le32(
 			mmc_card_blockaddr(card) ?
-			blk_rq_pos(prq) : blk_rq_pos(prq) << 9;
+			blk_rq_pos(prq) : blk_rq_pos(prq) << 9);
 		packed->blocks += blk_rq_sectors(prq);
 		i++;
 	}
@@ -2244,6 +2246,7 @@
 	md->disk->queue = md->queue.queue;
 	md->disk->driverfs_dev = parent;
 	set_disk_ro(md->disk, md->read_only || default_ro);
+	md->disk->flags = GENHD_FL_EXT_DEVT;
 	if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
 		md->disk->flags |= GENHD_FL_NO_PART_SCAN;
 
@@ -2271,7 +2274,8 @@
 	set_capacity(md->disk, size);
 
 	if (mmc_host_cmd23(card->host)) {
-		if (mmc_card_mmc(card) ||
+		if ((mmc_card_mmc(card) &&
+		     card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
 		    (mmc_card_sd(card) &&
 		     card->scr.cmds & SD_SCR_CMD23_SUPPORT))
 			md->flags |= MMC_BLK_CMD23;
@@ -2506,11 +2510,12 @@
 		  MMC_QUIRK_BLK_NO_CMD23),
 
 	/*
-	 * Some Micron MMC cards needs longer data read timeout than
-	 * indicated in CSD.
+	 * Some MMC cards need longer data read timeout than indicated in CSD.
 	 */
 	MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
 		  MMC_QUIRK_LONG_READ_TIME),
+	MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_LONG_READ_TIME),
 
 	/*
 	 * On these Samsung MoviNAND parts, performing secure erase or
--- linux-4.4.0.orig/drivers/mmc/card/mmc_test.c
+++ linux-4.4.0/drivers/mmc/card/mmc_test.c
@@ -791,7 +791,7 @@
 	struct mmc_async_req *cur_areq = &test_areq[0].areq;
 	struct mmc_async_req *other_areq = &test_areq[1].areq;
 	int i;
-	int ret;
+	int ret = RESULT_OK;
 
 	test_areq[0].test = test;
 	test_areq[1].test = test;
--- linux-4.4.0.orig/drivers/mmc/card/queue.h
+++ linux-4.4.0/drivers/mmc/card/queue.h
@@ -25,7 +25,7 @@
 
 struct mmc_packed {
 	struct list_head	list;
-	u32			cmd_hdr[1024];
+	__le32			cmd_hdr[1024];
 	unsigned int		blocks;
 	u8			nr_entries;
 	u8			retries;
--- linux-4.4.0.orig/drivers/mmc/core/bus.c
+++ linux-4.4.0/drivers/mmc/core/bus.c
@@ -18,6 +18,7 @@
 #include <linux/stat.h>
 #include <linux/of.h>
 #include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -35,13 +36,13 @@
 
 	switch (card->type) {
 	case MMC_TYPE_MMC:
-		return sprintf(buf, "MMC\n");
+		return sysfs_emit(buf, "MMC\n");
 	case MMC_TYPE_SD:
-		return sprintf(buf, "SD\n");
+		return sysfs_emit(buf, "SD\n");
 	case MMC_TYPE_SDIO:
-		return sprintf(buf, "SDIO\n");
+		return sysfs_emit(buf, "SDIO\n");
 	case MMC_TYPE_SD_COMBO:
-		return sprintf(buf, "SDcombo\n");
+		return sysfs_emit(buf, "SDcombo\n");
 	default:
 		return -EFAULT;
 	}
@@ -155,6 +156,9 @@
 		return ret;
 
 	ret = host->bus_ops->suspend(host);
+	if (ret)
+		pm_generic_resume(dev);
+
 	return ret;
 }
 
@@ -349,6 +353,8 @@
 
 	card->dev.of_node = mmc_of_find_child_device(card->host, 0);
 
+	device_enable_async_suspend(&card->dev);
+
 	ret = device_add(&card->dev);
 	if (ret)
 		return ret;
--- linux-4.4.0.orig/drivers/mmc/core/bus.h
+++ linux-4.4.0/drivers/mmc/core/bus.h
@@ -11,11 +11,13 @@
 #ifndef _MMC_CORE_BUS_H
 #define _MMC_CORE_BUS_H
 
+#include <linux/sysfs.h>
+
 #define MMC_DEV_ATTR(name, fmt, args...)					\
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)	\
 {										\
 	struct mmc_card *card = mmc_dev_to_card(dev);				\
-	return sprintf(buf, fmt, args);						\
+	return sysfs_emit(buf, fmt, args);					\
 }										\
 static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
 
--- linux-4.4.0.orig/drivers/mmc/core/core.c
+++ linux-4.4.0/drivers/mmc/core/core.c
@@ -874,11 +874,11 @@
 	/*
 	 * Some cards require longer data read timeout than indicated in CSD.
 	 * Address this by setting the read timeout to a "reasonably high"
-	 * value. For the cards tested, 300ms has proven enough. If necessary,
+	 * value. For the cards tested, 600ms has proven enough. If necessary,
 	 * this value can be increased if other problematic cards require this.
 	 */
 	if (mmc_card_long_read_time(card) && data->flags & MMC_DATA_READ) {
-		data->timeout_ns = 300000000;
+		data->timeout_ns = 600000000;
 		data->timeout_clks = 0;
 	}
 
@@ -1039,7 +1039,7 @@
 		"width %u timing %u\n",
 		 mmc_hostname(host), ios->clock, ios->bus_mode,
 		 ios->power_mode, ios->chip_select, ios->vdd,
-		 ios->bus_width, ios->timing);
+		 1 << ios->bus_width, ios->timing);
 
 	host->ops->set_ios(host, ios);
 }
@@ -1220,8 +1220,12 @@
 
 	voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
 	num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
-	if (!voltage_ranges || !num_ranges) {
-		pr_info("%s: voltage-ranges unspecified\n", np->full_name);
+	if (!voltage_ranges) {
+		pr_debug("%s: voltage-ranges unspecified\n", np->full_name);
+		return -EINVAL;
+	}
+	if (!num_ranges) {
+		pr_err("%s: voltage-ranges empty\n", np->full_name);
 		return -EINVAL;
 	}
 
@@ -2791,6 +2795,14 @@
 		if (!err)
 			break;
 
+		if (!mmc_card_is_removable(host)) {
+			dev_warn(mmc_dev(host),
+				 "pre_suspend failed for non-removable host: "
+				 "%d\n", err);
+			/* Avoid removing non-removable hosts */
+			break;
+		}
+
 		/* Calling bus_ops->remove() with a claimed host can deadlock */
 		host->bus_ops->remove(host);
 		mmc_claim_host(host);
--- linux-4.4.0.orig/drivers/mmc/core/debugfs.c
+++ linux-4.4.0/drivers/mmc/core/debugfs.c
@@ -170,7 +170,7 @@
 		str = "invalid";
 		break;
 	}
-	seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str);
+	seq_printf(s, "signal voltage:\t%u (%s)\n", ios->signal_voltage, str);
 
 	switch (ios->drv_type) {
 	case MMC_SET_DRIVER_TYPE_A:
@@ -220,7 +220,7 @@
 	struct mmc_host *host = data;
 
 	/* We need this check due to input value is u64 */
-	if (val > host->f_max)
+	if (val != 0 && (val > host->f_max || val < host->f_min))
 		return -EINVAL;
 
 	mmc_claim_host(host);
--- linux-4.4.0.orig/drivers/mmc/core/mmc.c
+++ linux-4.4.0/drivers/mmc/core/mmc.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -333,6 +334,9 @@
 	}
 }
 
+/* Minimum partition switch timeout in milliseconds */
+#define MMC_MIN_PART_SWITCH_TIME	300
+
 /*
  * Decode extended CSD.
  */
@@ -501,7 +505,7 @@
 			card->ext_csd.raw_bkops_status =
 				ext_csd[EXT_CSD_BKOPS_STATUS];
 			if (!card->ext_csd.man_bkops_en)
-				pr_info("%s: MAN_BKOPS_EN bit is not set\n",
+				pr_debug("%s: MAN_BKOPS_EN bit is not set\n",
 					mmc_hostname(card->host));
 		}
 
@@ -578,6 +582,17 @@
 		card->ext_csd.data_sector_size = 512;
 	}
 
+	/*
+	 * GENERIC_CMD6_TIME is to be used "unless a specific timeout is defined
+	 * when accessing a specific field", so use it here if there is no
+	 * PARTITION_SWITCH_TIME.
+	 */
+	if (!card->ext_csd.part_time)
+		card->ext_csd.part_time = card->ext_csd.generic_cmd6_time;
+	/* Some eMMC set the value too low so set a minimum */
+	if (card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME)
+		card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME;
+
 	/* eMMC v5 or later */
 	if (card->ext_csd.rev >= 7) {
 		memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION],
@@ -727,12 +742,11 @@
 {
 	struct mmc_card *card = mmc_dev_to_card(dev);
 
-	if (card->ext_csd.rev < 7) {
-		return sprintf(buf, "0x%x\n", card->cid.fwrev);
-	} else {
-		return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN,
-			       card->ext_csd.fwrev);
-	}
+	if (card->ext_csd.rev < 7)
+		return sysfs_emit(buf, "0x%x\n", card->cid.fwrev);
+	else
+		return sysfs_emit(buf, "0x%*phN\n", MMC_FIRMWARE_LEN,
+				  card->ext_csd.fwrev);
 }
 
 static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL);
@@ -945,7 +959,7 @@
 			break;
 		} else {
 			pr_warn("%s: switch to bus width %d failed\n",
-				mmc_hostname(host), ext_csd_bits[idx]);
+				mmc_hostname(host), 1 << bus_width);
 		}
 	}
 
@@ -1076,8 +1090,7 @@
 	mmc_set_clock(host, max_dtr);
 
 	/* Switch card to HS mode */
-	val = EXT_CSD_TIMING_HS |
-	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+	val = EXT_CSD_TIMING_HS;
 	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 			   EXT_CSD_HS_TIMING, val,
 			   card->ext_csd.generic_cmd6_time,
@@ -1160,8 +1173,7 @@
 	mmc_set_clock(host, max_dtr);
 
 	/* Switch HS400 to HS DDR */
-	val = EXT_CSD_TIMING_HS |
-	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+	val = EXT_CSD_TIMING_HS;
 	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
 			   val, card->ext_csd.generic_cmd6_time,
 			   true, send_status, true);
@@ -1246,10 +1258,11 @@
 {
 	struct mmc_host *host = card->host;
 	bool send_status = true;
-	unsigned int old_timing;
+	unsigned int old_timing, old_signal_voltage;
 	int err = -EINVAL;
 	u8 val;
 
+	old_signal_voltage = host->ios.signal_voltage;
 	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
@@ -1258,7 +1271,7 @@
 
 	/* If fails try again during next card power cycle */
 	if (err)
-		goto err;
+		return err;
 
 	mmc_select_driver_type(card);
 
@@ -1292,9 +1305,14 @@
 		}
 	}
 err:
-	if (err)
+	if (err) {
+		/* fall back to the old signal voltage, if fails report error */
+		if (__mmc_set_signal_voltage(host, old_signal_voltage))
+			err = -EIO;
+
 		pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
 		       __func__, err);
+	}
 	return err;
 }
 
@@ -1576,10 +1594,10 @@
 		err = mmc_select_hs400(card);
 		if (err)
 			goto free_card;
-	} else if (mmc_card_hs(card)) {
+	} else {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
-		if (!IS_ERR_VALUE(err)) {
+		if (!IS_ERR_VALUE(err) && mmc_card_hs(card)) {
 			err = mmc_select_hs_ddr(card);
 			if (err)
 				goto free_card;
@@ -1603,9 +1621,11 @@
 		if (err) {
 			pr_warn("%s: Enabling HPI failed\n",
 				mmc_hostname(card->host));
+			card->ext_csd.hpi_en = 0;
 			err = 0;
-		} else
+		} else {
 			card->ext_csd.hpi_en = 1;
+		}
 	}
 
 	/*
@@ -1948,8 +1968,8 @@
 		return 0;
 
 	err = _mmc_resume(host);
-	if (err)
-		pr_err("%s: error %d doing aggressive resume\n",
+	if (err && err != -ENOMEDIUM)
+		pr_err("%s: error %d doing runtime resume\n",
 			mmc_hostname(host), err);
 
 	return 0;
--- linux-4.4.0.orig/drivers/mmc/core/mmc_ops.c
+++ linux-4.4.0/drivers/mmc/core/mmc_ops.c
@@ -542,7 +542,7 @@
 		timeout_ms = MMC_OPS_TIMEOUT_MS;
 
 	/* Must check status to be sure of no errors. */
-	timeout = jiffies + msecs_to_jiffies(timeout_ms);
+	timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
 	do {
 		if (send_status) {
 			err = __mmc_send_status(card, &status, ignore_crc);
--- linux-4.4.0.orig/drivers/mmc/core/pwrseq_simple.c
+++ linux-4.4.0/drivers/mmc/core/pwrseq_simple.c
@@ -29,15 +29,18 @@
 static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
 					      int value)
 {
-	int i;
 	struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
-	int values[reset_gpios->ndescs];
 
-	for (i = 0; i < reset_gpios->ndescs; i++)
-		values[i] = value;
+	if (!IS_ERR(reset_gpios)) {
+		int i;
+		int values[reset_gpios->ndescs];
 
-	gpiod_set_array_value_cansleep(reset_gpios->ndescs, reset_gpios->desc,
-				       values);
+		for (i = 0; i < reset_gpios->ndescs; i++)
+			values[i] = value;
+
+		gpiod_set_array_value_cansleep(
+			reset_gpios->ndescs, reset_gpios->desc, values);
+	}
 }
 
 static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
@@ -79,7 +82,8 @@
 	struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
 					struct mmc_pwrseq_simple, pwrseq);
 
-	gpiod_put_array(pwrseq->reset_gpios);
+	if (!IS_ERR(pwrseq->reset_gpios))
+		gpiod_put_array(pwrseq->reset_gpios);
 
 	if (!IS_ERR(pwrseq->ext_clk))
 		clk_put(pwrseq->ext_clk);
@@ -112,7 +116,9 @@
 	}
 
 	pwrseq->reset_gpios = gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
-	if (IS_ERR(pwrseq->reset_gpios)) {
+	if (IS_ERR(pwrseq->reset_gpios) &&
+	    PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
+	    PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
 		ret = PTR_ERR(pwrseq->reset_gpios);
 		goto clk_put;
 	}
--- linux-4.4.0.orig/drivers/mmc/core/sd.c
+++ linux-4.4.0/drivers/mmc/core/sd.c
@@ -216,6 +216,14 @@
 
 	if (scr->sda_spec3)
 		scr->cmds = UNSTUFF_BITS(resp, 32, 2);
+
+	/* SD Spec says: any SD Card shall set at least bits 0 and 2 */
+	if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) ||
+	    !(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) {
+		pr_err("%s: invalid bus width\n", mmc_hostname(card->host));
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -329,6 +337,7 @@
 		card->sw_caps.sd3_bus_mode = status[13];
 		/* Driver Strengths supported by the card */
 		card->sw_caps.sd3_drv_type = status[9];
+		card->sw_caps.sd3_curr_limit = status[7] | status[6] << 8;
 	}
 
 out:
@@ -545,14 +554,25 @@
 	 * when we set current limit to 200ma, the card will draw 200ma, and
 	 * when we set current limit to 400/600/800ma, the card will draw its
 	 * maximum 300ma from the host.
+	 *
+	 * The above is incorrect: if we try to set a current limit that is
+	 * not supported by the card, the card can rightfully error out the
+	 * attempt, and remain at the default current limit.  This results
+	 * in a 300mA card being limited to 200mA even though the host
+	 * supports 800mA. Failures seen with SanDisk 8GB UHS cards with
+	 * an iMX6 host. --rmk
 	 */
-	if (max_current >= 800)
+	if (max_current >= 800 &&
+	    card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
 		current_limit = SD_SET_CURRENT_LIMIT_800;
-	else if (max_current >= 600)
+	else if (max_current >= 600 &&
+		 card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
 		current_limit = SD_SET_CURRENT_LIMIT_600;
-	else if (max_current >= 400)
+	else if (max_current >= 400 &&
+		 card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
 		current_limit = SD_SET_CURRENT_LIMIT_400;
-	else if (max_current >= 200)
+	else if (max_current >= 200 &&
+		 card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
 		current_limit = SD_SET_CURRENT_LIMIT_200;
 
 	if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
@@ -626,9 +646,9 @@
 	 * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
 	 */
 	if (!mmc_host_is_spi(card->host) &&
-		(card->sd_bus_speed == UHS_SDR50_BUS_SPEED ||
-		 card->sd_bus_speed == UHS_DDR50_BUS_SPEED ||
-		 card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) {
+		(card->host->ios.timing == MMC_TIMING_UHS_SDR50 ||
+		 card->host->ios.timing == MMC_TIMING_UHS_DDR50 ||
+		 card->host->ios.timing == MMC_TIMING_UHS_SDR104)) {
 		err = mmc_execute_tuning(card);
 
 		/*
@@ -638,7 +658,7 @@
 		 * difference between v3.00 and 3.01 spec means that CMD19
 		 * tuning is also available for DDR50 mode.
 		 */
-		if (err && card->sd_bus_speed == UHS_DDR50_BUS_SPEED) {
+		if (err && card->host->ios.timing == MMC_TIMING_UHS_DDR50) {
 			pr_warn("%s: ddr50 tuning failed\n",
 				mmc_hostname(card->host));
 			err = 0;
@@ -1169,8 +1189,8 @@
 		return 0;
 
 	err = _mmc_sd_resume(host);
-	if (err)
-		pr_err("%s: error %d doing aggressive resume\n",
+	if (err && err != -ENOMEDIUM)
+		pr_err("%s: error %d doing runtime resume\n",
 			mmc_hostname(host), err);
 
 	return 0;
@@ -1224,6 +1244,12 @@
 			goto err;
 	}
 
+	/*
+	 * Some SD cards claims an out of spec VDD voltage range. Let's treat
+	 * these bits as being in-valid and especially also bit7.
+	 */
+	ocr &= ~0x7FFF;
+
 	rocr = mmc_select_voltage(host, ocr);
 
 	/*
--- linux-4.4.0.orig/drivers/mmc/core/sdio.c
+++ linux-4.4.0/drivers/mmc/core/sdio.c
@@ -535,8 +535,8 @@
 	 * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
 	 */
 	if (!mmc_host_is_spi(card->host) &&
-	    ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) ||
-	     (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)))
+	    ((card->host->ios.timing == MMC_TIMING_UHS_SDR50) ||
+	      (card->host->ios.timing == MMC_TIMING_UHS_SDR104)))
 		err = mmc_execute_tuning(card);
 out:
 	return err;
@@ -630,7 +630,7 @@
 	 */
 	if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
 		err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
-					ocr);
+					ocr_card);
 		if (err == -EAGAIN) {
 			sdio_reset(host);
 			mmc_go_idle(host);
--- linux-4.4.0.orig/drivers/mmc/core/sdio_bus.c
+++ linux-4.4.0/drivers/mmc/core/sdio_bus.c
@@ -18,6 +18,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pm_domain.h>
 #include <linux/acpi.h>
+#include <linux/sysfs.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -38,7 +39,7 @@
 	struct sdio_func *func;						\
 									\
 	func = dev_to_sdio_func (dev);					\
-	return sprintf (buf, format_string, func->field);		\
+	return sysfs_emit(buf, format_string, func->field);		\
 }									\
 static DEVICE_ATTR_RO(field)
 
@@ -50,7 +51,7 @@
 {
 	struct sdio_func *func = dev_to_sdio_func (dev);
 
-	return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
+	return sysfs_emit(buf, "sdio:c%02Xv%04Xd%04X\n",
 			func->class, func->vendor, func->device);
 }
 static DEVICE_ATTR_RO(modalias);
@@ -266,7 +267,7 @@
 	sdio_free_func_cis(func);
 
 	kfree(func->info);
-
+	kfree(func->tmpbuf);
 	kfree(func);
 }
 
@@ -281,6 +282,16 @@
 	if (!func)
 		return ERR_PTR(-ENOMEM);
 
+	/*
+	 * allocate buffer separately to make sure it's properly aligned for
+	 * DMA usage (incl. 64 bit DMA)
+	 */
+	func->tmpbuf = kmalloc(4, GFP_KERNEL);
+	if (!func->tmpbuf) {
+		kfree(func);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	func->card = card;
 
 	device_initialize(&func->dev);
@@ -322,6 +333,7 @@
 
 	sdio_set_of_node(func);
 	sdio_acpi_set_handle(func);
+	device_enable_async_suspend(&func->dev);
 	ret = device_add(&func->dev);
 	if (ret == 0)
 		sdio_func_set_present(func);
--- linux-4.4.0.orig/drivers/mmc/core/sdio_cis.c
+++ linux-4.4.0/drivers/mmc/core/sdio_cis.c
@@ -24,12 +24,17 @@
 #include "sdio_cis.h"
 #include "sdio_ops.h"
 
+#define SDIO_READ_CIS_TIMEOUT_MS  (10 * 1000) /* 10s */
+
 static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
 			 const unsigned char *buf, unsigned size)
 {
 	unsigned i, nr_strings;
 	char **buffer, *string;
 
+	if (size < 2)
+		return 0;
+
 	/* Find all null-terminated (including zero length) strings in
 	   the TPLLV1_INFO field. Trailing garbage is ignored. */
 	buf += 2;
@@ -260,6 +265,8 @@
 
 	do {
 		unsigned char tpl_code, tpl_link;
+		unsigned long timeout = jiffies +
+			msecs_to_jiffies(SDIO_READ_CIS_TIMEOUT_MS);
 
 		ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
 		if (ret)
@@ -312,6 +319,8 @@
 			prev = &this->next;
 
 			if (ret == -ENOENT) {
+				if (time_after(jiffies, timeout))
+					break;
 				/* warn about unknown tuples */
 				pr_warn_ratelimited("%s: queuing unknown"
 				       " CIS tuple 0x%02x (%u bytes)\n",
--- linux-4.4.0.orig/drivers/mmc/host/Kconfig
+++ linux-4.4.0/drivers/mmc/host/Kconfig
@@ -97,6 +97,7 @@
 config MMC_SDHCI_ACPI
 	tristate "SDHCI support for ACPI enumerated SDHCI controllers"
 	depends on MMC_SDHCI && ACPI
+	select IOSF_MBI if X86
 	help
 	  This selects support for ACPI enumerated SDHCI controllers,
 	  identified by ACPI Compatibility ID PNP0D40 or specific
--- linux-4.4.0.orig/drivers/mmc/host/atmel-mci.c
+++ linux-4.4.0/drivers/mmc/host/atmel-mci.c
@@ -1840,13 +1840,14 @@
 			}
 
 			atmci_request_end(host, host->mrq);
-			state = STATE_IDLE;
+			goto unlock; /* atmci_request_end() sets host->state */
 			break;
 		}
 	} while (state != prev_state);
 
 	host->state = state;
 
+unlock:
 	spin_unlock(&host->lock);
 }
 
--- linux-4.4.0.orig/drivers/mmc/host/davinci_mmc.c
+++ linux-4.4.0/drivers/mmc/host/davinci_mmc.c
@@ -1147,7 +1147,7 @@
 {
 }
 #endif
-static void __init init_mmcsd_host(struct mmc_davinci_host *host)
+static void init_mmcsd_host(struct mmc_davinci_host *host)
 {
 
 	mmc_davinci_reset_ctrl(host, 1);
@@ -1402,7 +1402,7 @@
 	return ret;
 }
 
-static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
+static int davinci_mmcsd_remove(struct platform_device *pdev)
 {
 	struct mmc_davinci_host *host = platform_get_drvdata(pdev);
 
@@ -1469,7 +1469,7 @@
 		.pm	= davinci_mmcsd_pm_ops,
 		.of_match_table = davinci_mmc_dt_ids,
 	},
-	.remove		= __exit_p(davinci_mmcsd_remove),
+	.remove		= davinci_mmcsd_remove,
 	.id_table	= davinci_mmc_devtype,
 };
 
--- linux-4.4.0.orig/drivers/mmc/host/dw_mmc-pltfm.c
+++ linux-4.4.0/drivers/mmc/host/dw_mmc-pltfm.c
@@ -59,12 +59,13 @@
 	host->pdata = pdev->dev.platform_data;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	/* Get registers' physical base address */
-	host->phy_regs = (void *)(regs->start);
 	host->regs = devm_ioremap_resource(&pdev->dev, regs);
 	if (IS_ERR(host->regs))
 		return PTR_ERR(host->regs);
 
+	/* Get registers' physical base address */
+	host->phy_regs = regs->start;
+
 	platform_set_drvdata(pdev, host);
 	return dw_mci_probe(host);
 }
--- linux-4.4.0.orig/drivers/mmc/host/dw_mmc-rockchip.c
+++ linux-4.4.0/drivers/mmc/host/dw_mmc-rockchip.c
@@ -78,6 +78,70 @@
 	/* Make sure we use phases which we can enumerate with */
 	if (!IS_ERR(priv->sample_clk))
 		clk_set_phase(priv->sample_clk, priv->default_sample_phase);
+
+	/*
+	 * Set the drive phase offset based on speed mode to achieve hold times.
+	 *
+	 * NOTE: this is _not_ a value that is dynamically tuned and is also
+	 * _not_ a value that will vary from board to board.  It is a value
+	 * that could vary between different SoC models if they had massively
+	 * different output clock delays inside their dw_mmc IP block (delay_o),
+	 * but since it's OK to overshoot a little we don't need to do complex
+	 * calculations and can pick values that will just work for everyone.
+	 *
+	 * When picking values we'll stick with picking 0/90/180/270 since
+	 * those can be made very accurately on all known Rockchip SoCs.
+	 *
+	 * Note that these values match values from the DesignWare Databook
+	 * tables for the most part except for SDR12 and "ID mode".  For those
+	 * two modes the databook calculations assume a clock in of 50MHz.  As
+	 * seen above, we always use a clock in rate that is exactly the
+	 * card's input clock (times RK3288_CLKGEN_DIV, but that gets divided
+	 * back out before the controller sees it).
+	 *
+	 * From measurement of a single device, it appears that delay_o is
+	 * about .5 ns.  Since we try to leave a bit of margin, it's expected
+	 * that numbers here will be fine even with much larger delay_o
+	 * (the 1.4 ns assumed by the DesignWare Databook would result in the
+	 * same results, for instance).
+	 */
+	if (!IS_ERR(priv->drv_clk)) {
+		int phase;
+
+		/*
+		 * In almost all cases a 90 degree phase offset will provide
+		 * sufficient hold times across all valid input clock rates
+		 * assuming delay_o is not absurd for a given SoC.  We'll use
+		 * that as a default.
+		 */
+		phase = 90;
+
+		switch (ios->timing) {
+		case MMC_TIMING_MMC_DDR52:
+			/*
+			 * Since clock in rate with MMC_DDR52 is doubled when
+			 * bus width is 8 we need to double the phase offset
+			 * to get the same timings.
+			 */
+			if (ios->bus_width == MMC_BUS_WIDTH_8)
+				phase = 180;
+			break;
+		case MMC_TIMING_UHS_SDR104:
+		case MMC_TIMING_MMC_HS200:
+			/*
+			 * In the case of 150 MHz clock (typical max for
+			 * Rockchip SoCs), 90 degree offset will add a delay
+			 * of 1.67 ns.  That will meet min hold time of .8 ns
+			 * as long as clock output delay is < .87 ns.  On
+			 * SoCs measured this seems to be OK, but it doesn't
+			 * hurt to give margin here, so we use 180.
+			 */
+			phase = 180;
+			break;
+		}
+
+		clk_set_phase(priv->drv_clk, phase);
+	}
 }
 
 #define NUM_PHASES			360
--- linux-4.4.0.orig/drivers/mmc/host/dw_mmc.c
+++ linux-4.4.0/drivers/mmc/host/dw_mmc.c
@@ -619,6 +619,7 @@
 					(sizeof(struct idmac_desc_64addr) *
 							(i + 1))) >> 32;
 			/* Initialize reserved and buffer size fields to "0" */
+			p->des0 = 0;
 			p->des1 = 0;
 			p->des2 = 0;
 			p->des3 = 0;
@@ -640,6 +641,7 @@
 		     i++, p++) {
 			p->des3 = cpu_to_le32(host->sg_dma +
 					(sizeof(struct idmac_desc) * (i + 1)));
+			p->des0 = 0;
 			p->des1 = 0;
 		}
 
@@ -699,7 +701,7 @@
 	int ret = 0;
 
 	/* Set external dma config: burst size, burst width */
-	cfg.dst_addr = (dma_addr_t)(host->phy_regs + fifo_offset);
+	cfg.dst_addr = host->phy_regs + fifo_offset;
 	cfg.src_addr = cfg.dst_addr;
 	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -2807,8 +2809,8 @@
 	}
 
 	if (host->use_dma == TRANS_MODE_IDMAC)
-		/* It is also recommended that we reset and reprogram idmac */
-		dw_mci_idmac_reset(host);
+		/* It is also required that we reinit idmac */
+		dw_mci_idmac_init(host);
 
 	ret = true;
 
--- linux-4.4.0.orig/drivers/mmc/host/jz4740_mmc.c
+++ linux-4.4.0/drivers/mmc/host/jz4740_mmc.c
@@ -368,9 +368,9 @@
 		host->irq_mask &= ~irq;
 	else
 		host->irq_mask |= irq;
-	spin_unlock_irqrestore(&host->lock, flags);
 
 	writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
+	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host,
--- linux-4.4.0.orig/drivers/mmc/host/mmc_spi.c
+++ linux-4.4.0/drivers/mmc/host/mmc_spi.c
@@ -819,6 +819,10 @@
 	}
 
 	status = spi_sync_locked(spi, &host->m);
+	if (status < 0) {
+		dev_dbg(&spi->dev, "read error %d\n", status);
+		return status;
+	}
 
 	if (host->dma_dev) {
 		dma_sync_single_for_cpu(host->dma_dev,
@@ -1149,17 +1153,22 @@
 	 * SPI protocol.  Another is that when chipselect is released while
 	 * the card returns BUSY status, the clock must issue several cycles
 	 * with chipselect high before the card will stop driving its output.
+	 *
+	 * SPI_CS_HIGH means "asserted" here. In some cases like when using
+	 * GPIOs for chip select, SPI_CS_HIGH is set but this will be logically
+	 * inverted by gpiolib, so if we want to ascertain to drive it high
+	 * we should toggle the default with an XOR as we do here.
 	 */
-	host->spi->mode |= SPI_CS_HIGH;
+	host->spi->mode ^= SPI_CS_HIGH;
 	if (spi_setup(host->spi) != 0) {
 		/* Just warn; most cards work without it. */
 		dev_warn(&host->spi->dev,
 				"can't change chip-select polarity\n");
-		host->spi->mode &= ~SPI_CS_HIGH;
+		host->spi->mode ^= SPI_CS_HIGH;
 	} else {
 		mmc_spi_readbytes(host, 18);
 
-		host->spi->mode &= ~SPI_CS_HIGH;
+		host->spi->mode ^= SPI_CS_HIGH;
 		if (spi_setup(host->spi) != 0) {
 			/* Wot, we can't get the same setup we had before? */
 			dev_err(&host->spi->dev,
@@ -1436,6 +1445,12 @@
 					     host->pdata->cd_debounce);
 		if (status != 0)
 			goto fail_add_host;
+
+		/* The platform has a CD GPIO signal that may support
+		 * interrupts, so let mmc_gpiod_request_cd_irq() decide
+		 * if polling is needed or not.
+		 */
+		mmc->caps &= ~MMC_CAP_NEEDS_POLL;
 		mmc_gpiod_request_cd_irq(mmc);
 	}
 
@@ -1445,6 +1460,7 @@
 		if (status != 0)
 			goto fail_add_host;
 	}
+	mmc_detect_change(mmc, 0);
 
 	dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n",
 			dev_name(&mmc->class_dev),
--- linux-4.4.0.orig/drivers/mmc/host/mmci.c
+++ linux-4.4.0/drivers/mmc/host/mmci.c
@@ -1886,7 +1886,7 @@
 	{
 		.id     = 0x00280180,
 		.mask   = 0x00ffffff,
-		.data	= &variant_u300,
+		.data	= &variant_nomadik,
 	},
 	{
 		.id     = 0x00480180,
--- linux-4.4.0.orig/drivers/mmc/host/moxart-mmc.c
+++ linux-4.4.0/drivers/mmc/host/moxart-mmc.c
@@ -257,7 +257,7 @@
 static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
 {
 	u32 len, dir_data, dir_slave;
-	unsigned long dma_time;
+	long dma_time;
 	struct dma_async_tx_descriptor *desc = NULL;
 	struct dma_chan *dma_chan;
 
@@ -397,7 +397,8 @@
 static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 	struct moxart_host *host = mmc_priv(mmc);
-	unsigned long pio_time, flags;
+	long pio_time;
+	unsigned long flags;
 	u32 status;
 
 	spin_lock_irqsave(&host->lock, flags);
@@ -690,19 +691,18 @@
 
 	dev_set_drvdata(&pdev->dev, NULL);
 
-	if (mmc) {
-		if (!IS_ERR(host->dma_chan_tx))
-			dma_release_channel(host->dma_chan_tx);
-		if (!IS_ERR(host->dma_chan_rx))
-			dma_release_channel(host->dma_chan_rx);
-		mmc_remove_host(mmc);
-		mmc_free_host(mmc);
+	if (!IS_ERR(host->dma_chan_tx))
+		dma_release_channel(host->dma_chan_tx);
+	if (!IS_ERR(host->dma_chan_rx))
+		dma_release_channel(host->dma_chan_rx);
+	mmc_remove_host(mmc);
+
+	writel(0, host->base + REG_INTERRUPT_MASK);
+	writel(0, host->base + REG_POWER_CONTROL);
+	writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
+	       host->base + REG_CLOCK_CONTROL);
+	mmc_free_host(mmc);
 
-		writel(0, host->base + REG_INTERRUPT_MASK);
-		writel(0, host->base + REG_POWER_CONTROL);
-		writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
-		       host->base + REG_CLOCK_CONTROL);
-	}
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/mmc/host/mtk-sd.c
+++ linux-4.4.0/drivers/mmc/host/mtk-sd.c
@@ -570,7 +570,7 @@
 		}
 	}
 	sdr_set_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD | MSDC_CFG_CKDIV,
-			(mode << 8) | (div % 0xff));
+		      (mode << 8) | div);
 	sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
 	while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
 		cpu_relax();
@@ -720,13 +720,13 @@
 static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
 {
 	unsigned long flags;
-	bool ret;
 
-	ret = cancel_delayed_work(&host->req_timeout);
-	if (!ret) {
-		/* delay work already running */
-		return;
-	}
+	/*
+	 * No need check the return value of cancel_delayed_work, as only ONE
+	 * path will go here!
+	 */
+	cancel_delayed_work(&host->req_timeout);
+
 	spin_lock_irqsave(&host->lock, flags);
 	host->mrq = NULL;
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -747,7 +747,7 @@
 	bool done = false;
 	bool sbc_error;
 	unsigned long flags;
-	u32 *rsp = cmd->resp;
+	u32 *rsp;
 
 	if (mrq->sbc && cmd == mrq->cmd &&
 	    (events & (MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR
@@ -768,6 +768,7 @@
 
 	if (done)
 		return true;
+	rsp = cmd->resp;
 
 	sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
 
@@ -846,6 +847,7 @@
 	WARN_ON(host->cmd);
 	host->cmd = cmd;
 
+	mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
 	if (!msdc_cmd_is_ready(host, mrq, cmd))
 		return;
 
@@ -857,7 +859,6 @@
 
 	cmd->error = 0;
 	rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
-	mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
 
 	sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
 	writel(cmd->arg, host->base + SDC_ARG);
@@ -942,7 +943,7 @@
 static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
 				struct mmc_request *mrq, struct mmc_data *data)
 {
-	struct mmc_command *stop = data->stop;
+	struct mmc_command *stop;
 	unsigned long flags;
 	bool done;
 	unsigned int check_data = events &
@@ -958,6 +959,7 @@
 
 	if (done)
 		return true;
+	stop = data->stop;
 
 	if (check_data || (stop && stop->error)) {
 		dev_dbg(host->dev, "DMA status: 0x%8X\n",
@@ -1540,7 +1542,7 @@
 	host->src_clk_freq = clk_get_rate(host->src_clk);
 	/* Set host parameters to mmc */
 	mmc->ops = &mt_msdc_ops;
-	mmc->f_min = host->src_clk_freq / (4 * 255);
+	mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 255);
 
 	mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
 	mmc->caps |= MMC_CAP_RUNTIME_RESUME;
--- linux-4.4.0.orig/drivers/mmc/host/mxs-mmc.c
+++ linux-4.4.0/drivers/mmc/host/mxs-mmc.c
@@ -309,6 +309,9 @@
 	cmd0 = BF_SSP(cmd->opcode, CMD0_CMD);
 	cmd1 = cmd->arg;
 
+	if (cmd->opcode == MMC_STOP_TRANSMISSION)
+		cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
+
 	if (host->sdio_irq_en) {
 		ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
 		cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
@@ -417,8 +420,7 @@
 		       ssp->base + HW_SSP_BLOCK_SIZE);
 	}
 
-	if ((cmd->opcode == MMC_STOP_TRANSMISSION) ||
-	    (cmd->opcode == SD_IO_RW_EXTENDED))
+	if (cmd->opcode == SD_IO_RW_EXTENDED)
 		cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
 
 	cmd1 = cmd->arg;
@@ -649,7 +651,7 @@
 
 	ret = mmc_of_parse(mmc);
 	if (ret)
-		goto out_clk_disable;
+		goto out_free_dma;
 
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
@@ -661,13 +663,13 @@
 
 	platform_set_drvdata(pdev, mmc);
 
+	spin_lock_init(&host->lock);
+
 	ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0,
 			       dev_name(&pdev->dev), host);
 	if (ret)
 		goto out_free_dma;
 
-	spin_lock_init(&host->lock);
-
 	ret = mmc_add_host(mmc);
 	if (ret)
 		goto out_free_dma;
--- linux-4.4.0.orig/drivers/mmc/host/omap.c
+++ linux-4.4.0/drivers/mmc/host/omap.c
@@ -105,6 +105,7 @@
 	unsigned int		vdd;
 	u16			saved_con;
 	u16			bus_mode;
+	u16			power_mode;
 	unsigned int		fclk_freq;
 
 	struct tasklet_struct	cover_tasklet;
@@ -920,7 +921,7 @@
 	reg &= ~(1 << 5);
 	OMAP_MMC_WRITE(host, SDIO, reg);
 	/* Set maximum timeout */
-	OMAP_MMC_WRITE(host, CTO, 0xff);
+	OMAP_MMC_WRITE(host, CTO, 0xfd);
 }
 
 static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req)
@@ -1156,7 +1157,7 @@
 	struct mmc_omap_slot *slot = mmc_priv(mmc);
 	struct mmc_omap_host *host = slot->host;
 	int i, dsor;
-	int clk_enabled;
+	int clk_enabled, init_stream;
 
 	mmc_omap_select_slot(slot, 0);
 
@@ -1166,6 +1167,7 @@
 		slot->vdd = ios->vdd;
 
 	clk_enabled = 0;
+	init_stream = 0;
 	switch (ios->power_mode) {
 	case MMC_POWER_OFF:
 		mmc_omap_set_power(slot, 0, ios->vdd);
@@ -1173,13 +1175,17 @@
 	case MMC_POWER_UP:
 		/* Cannot touch dsor yet, just power up MMC */
 		mmc_omap_set_power(slot, 1, ios->vdd);
+		slot->power_mode = ios->power_mode;
 		goto exit;
 	case MMC_POWER_ON:
 		mmc_omap_fclk_enable(host, 1);
 		clk_enabled = 1;
 		dsor |= 1 << 11;
+		if (slot->power_mode != MMC_POWER_ON)
+			init_stream = 1;
 		break;
 	}
+	slot->power_mode = ios->power_mode;
 
 	if (slot->bus_mode != ios->bus_mode) {
 		if (slot->pdata->set_bus_mode != NULL)
@@ -1195,7 +1201,7 @@
 	for (i = 0; i < 2; i++)
 		OMAP_MMC_WRITE(host, CON, dsor);
 	slot->saved_con = dsor;
-	if (ios->power_mode == MMC_POWER_ON) {
+	if (init_stream) {
 		/* worst case at 400kHz, 80 cycles makes 200 microsecs */
 		int usecs = 250;
 
@@ -1233,6 +1239,7 @@
 	slot->host = host;
 	slot->mmc = mmc;
 	slot->id = id;
+	slot->power_mode = MMC_POWER_UNDEFINED;
 	slot->pdata = &host->pdata->slots[id];
 
 	host->slots[id] = slot;
--- linux-4.4.0.orig/drivers/mmc/host/omap_hsmmc.c
+++ linux-4.4.0/drivers/mmc/host/omap_hsmmc.c
@@ -1776,8 +1776,8 @@
 	 */
 	if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) {
 		struct pinctrl *p = devm_pinctrl_get(host->dev);
-		if (!p) {
-			ret = -ENODEV;
+		if (IS_ERR(p)) {
+			ret = PTR_ERR(p);
 			goto err_free_irq;
 		}
 		if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT))) {
@@ -2117,7 +2117,6 @@
 	mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
 	mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-	mmc->max_seg_size = mmc->max_req_size;
 
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
 		     MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
@@ -2174,6 +2173,17 @@
 		goto err_irq;
 	}
 
+	/*
+	 * Limit the maximum segment size to the lower of the request size
+	 * and the DMA engine device segment size limits.  In reality, with
+	 * 32-bit transfers, the DMA engine can do longer segments than this
+	 * but there is no way to represent that in the DMA model - if we
+	 * increase this figure here, we get warnings from the DMA API debug.
+	 */
+	mmc->max_seg_size = min3(mmc->max_req_size,
+			dma_get_max_seg_size(host->rx_chan->device->dev),
+			dma_get_max_seg_size(host->tx_chan->device->dev));
+
 	/* Request IRQ for MMC operations */
 	ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0,
 			mmc_hostname(mmc), host);
--- linux-4.4.0.orig/drivers/mmc/host/pxamci.c
+++ linux-4.4.0/drivers/mmc/host/pxamci.c
@@ -181,7 +181,7 @@
 static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 {
 	struct dma_async_tx_descriptor *tx;
-	enum dma_data_direction direction;
+	enum dma_transfer_direction direction;
 	struct dma_slave_config	config;
 	struct dma_chan *chan;
 	unsigned int nob = data->blocks;
@@ -798,14 +798,16 @@
 		gpio_direction_output(gpio_power,
 				      host->pdata->gpio_power_invert);
 	}
-	if (gpio_is_valid(gpio_ro))
+	if (gpio_is_valid(gpio_ro)) {
 		ret = mmc_gpio_request_ro(mmc, gpio_ro);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro);
-		goto out;
-	} else {
-		mmc->caps |= host->pdata->gpio_card_ro_invert ?
-			0 : MMC_CAP2_RO_ACTIVE_HIGH;
+		if (ret) {
+			dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n",
+				gpio_ro);
+			goto out;
+		} else {
+			mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
+				0 : MMC_CAP2_RO_ACTIVE_HIGH;
+		}
 	}
 
 	if (gpio_is_valid(gpio_cd))
--- linux-4.4.0.orig/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ linux-4.4.0/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -1138,11 +1138,6 @@
 	dev_dbg(sdmmc_dev(host), "%s\n", __func__);
 	mutex_lock(&ucr->dev_mutex);
 
-	if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) {
-		mutex_unlock(&ucr->dev_mutex);
-		return;
-	}
-
 	sd_set_power_mode(host, ios->power_mode);
 	sd_set_bus_width(host, ios->bus_width);
 	sd_set_timing(host, ios->timing, &host->ddr_mode);
@@ -1314,6 +1309,7 @@
 		container_of(work, struct rtsx_usb_sdmmc, led_work);
 	struct rtsx_ucr *ucr = host->ucr;
 
+	pm_runtime_get_sync(sdmmc_dev(host));
 	mutex_lock(&ucr->dev_mutex);
 
 	if (host->led.brightness == LED_OFF)
@@ -1322,6 +1318,7 @@
 		rtsx_usb_turn_on_led(ucr);
 
 	mutex_unlock(&ucr->dev_mutex);
+	pm_runtime_put(sdmmc_dev(host));
 }
 #endif
 
--- linux-4.4.0.orig/drivers/mmc/host/s3cmci.c
+++ linux-4.4.0/drivers/mmc/host/s3cmci.c
@@ -21,6 +21,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-acpi.c
+++ linux-4.4.0/drivers/mmc/host/sdhci-acpi.c
@@ -41,6 +41,11 @@
 #include <linux/mmc/pm.h>
 #include <linux/mmc/slot-gpio.h>
 
+#ifdef CONFIG_X86
+#include <asm/cpu_device_id.h>
+#include <asm/iosf_mbi.h>
+#endif
+
 #include "sdhci.h"
 
 enum {
@@ -146,6 +151,102 @@
 	.ops = &sdhci_acpi_ops_int,
 };
 
+#ifdef CONFIG_X86
+
+static bool sdhci_acpi_byt(void)
+{
+	static const struct x86_cpu_id byt[] = {
+		{ X86_VENDOR_INTEL, 6, 0x37 },
+		{}
+	};
+
+	return x86_match_cpu(byt);
+}
+
+#define BYT_IOSF_SCCEP			0x63
+#define BYT_IOSF_OCP_NETCTRL0		0x1078
+#define BYT_IOSF_OCP_TIMEOUT_BASE	GENMASK(10, 8)
+
+static void sdhci_acpi_byt_setting(struct device *dev)
+{
+	u32 val = 0;
+
+	if (!sdhci_acpi_byt())
+		return;
+
+	if (iosf_mbi_read(BYT_IOSF_SCCEP, 0x06, BYT_IOSF_OCP_NETCTRL0,
+			  &val)) {
+		dev_err(dev, "%s read error\n", __func__);
+		return;
+	}
+
+	if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE))
+		return;
+
+	val &= ~BYT_IOSF_OCP_TIMEOUT_BASE;
+
+	if (iosf_mbi_write(BYT_IOSF_SCCEP, 0x07, BYT_IOSF_OCP_NETCTRL0,
+			   val)) {
+		dev_err(dev, "%s write error\n", __func__);
+		return;
+	}
+
+	dev_dbg(dev, "%s completed\n", __func__);
+}
+
+static bool sdhci_acpi_byt_defer(struct device *dev)
+{
+	if (!sdhci_acpi_byt())
+		return false;
+
+	if (!iosf_mbi_available())
+		return true;
+
+	sdhci_acpi_byt_setting(dev);
+
+	return false;
+}
+
+#else
+
+static inline void sdhci_acpi_byt_setting(struct device *dev)
+{
+}
+
+static inline bool sdhci_acpi_byt_defer(struct device *dev)
+{
+	return false;
+}
+
+#endif
+
+static int bxt_get_cd(struct mmc_host *mmc)
+{
+	int gpio_cd = mmc_gpio_get_cd(mmc);
+	struct sdhci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	int ret = 0;
+
+	if (!gpio_cd)
+		return 0;
+
+	pm_runtime_get_sync(mmc->parent);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (host->flags & SDHCI_DEVICE_DEAD)
+		goto out;
+
+	ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+out:
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	pm_runtime_mark_last_busy(mmc->parent);
+	pm_runtime_put_autosuspend(mmc->parent);
+
+	return ret;
+}
+
 static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev,
 				      const char *hid, const char *uid)
 {
@@ -196,6 +297,9 @@
 
 	/* Platform specific code during sd probe slot goes here */
 
+	if (hid && !strcmp(hid, "80865ACA"))
+		host->mmc_host_ops.get_cd = bxt_get_cd;
+
 	return 0;
 }
 
@@ -203,7 +307,7 @@
 	.chip    = &sdhci_acpi_chip_int,
 	.caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
 		   MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
-		   MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
+		   MMC_CAP_WAIT_WHILE_BUSY,
 	.caps2   = MMC_CAP2_HC_ERASE_SZ,
 	.flags   = SDHCI_ACPI_RUNTIME_PM,
 	.quirks  = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
@@ -218,7 +322,7 @@
 		   SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
 	.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
 	.caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD |
-		   MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
+		   MMC_CAP_WAIT_WHILE_BUSY,
 	.flags   = SDHCI_ACPI_RUNTIME_PM,
 	.pm_caps = MMC_PM_KEEP_POWER,
 	.probe_slot	= sdhci_acpi_sdio_probe_slot,
@@ -230,7 +334,7 @@
 	.quirks  = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
 	.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
 		   SDHCI_QUIRK2_STOP_WITH_TC,
-	.caps    = MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
+	.caps    = MMC_CAP_WAIT_WHILE_BUSY,
 	.probe_slot	= sdhci_acpi_sd_probe_slot,
 };
 
@@ -307,6 +411,9 @@
 	if (acpi_bus_get_status(device) || !device->status.present)
 		return -ENODEV;
 
+	if (sdhci_acpi_byt_defer(dev))
+		return -EPROBE_DEFER;
+
 	hid = acpi_device_hid(device);
 	uid = device->pnp.unique_id;
 
@@ -430,6 +537,8 @@
 {
 	struct sdhci_acpi_host *c = dev_get_drvdata(dev);
 
+	sdhci_acpi_byt_setting(&c->pdev->dev);
+
 	return sdhci_resume_host(c->host);
 }
 
@@ -453,6 +562,8 @@
 {
 	struct sdhci_acpi_host *c = dev_get_drvdata(dev);
 
+	sdhci_acpi_byt_setting(&c->pdev->dev);
+
 	return sdhci_runtime_resume_host(c->host);
 }
 
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-esdhc-imx.c
+++ linux-4.4.0/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -804,6 +804,7 @@
 
 	switch (uhs) {
 	case MMC_TIMING_UHS_SDR50:
+	case MMC_TIMING_UHS_DDR50:
 		pinctrl = imx_data->pins_100mhz;
 		break;
 	case MMC_TIMING_UHS_SDR104:
@@ -1239,9 +1240,10 @@
 	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+	int dead;
 
 	pm_runtime_get_sync(&pdev->dev);
+	dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_put_noidle(&pdev->dev);
 
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-iproc.c
+++ linux-4.4.0/drivers/mmc/host/sdhci-iproc.c
@@ -32,6 +32,8 @@
 	const struct sdhci_iproc_data *data;
 	u32 shadow_cmd;
 	u32 shadow_blk;
+	bool is_cmd_shadowed;
+	bool is_blk_shadowed;
 };
 
 #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18)
@@ -47,8 +49,22 @@
 
 static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg)
 {
-	u32 val = sdhci_iproc_readl(host, (reg & ~3));
-	u16 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host);
+	u32 val;
+	u16 word;
+
+	if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed) {
+		/* Get the saved transfer mode */
+		val = iproc_host->shadow_cmd;
+	} else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
+		   iproc_host->is_blk_shadowed) {
+		/* Get the saved block info */
+		val = iproc_host->shadow_blk;
+	} else {
+		val = sdhci_iproc_readl(host, (reg & ~3));
+	}
+	word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff;
 	return word;
 }
 
@@ -104,13 +120,15 @@
 
 	if (reg == SDHCI_COMMAND) {
 		/* Write the block now as we are issuing a command */
-		if (iproc_host->shadow_blk != 0) {
+		if (iproc_host->is_blk_shadowed) {
 			sdhci_iproc_writel(host, iproc_host->shadow_blk,
 				SDHCI_BLOCK_SIZE);
-			iproc_host->shadow_blk = 0;
+			iproc_host->is_blk_shadowed = false;
 		}
 		oldval = iproc_host->shadow_cmd;
-	} else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) {
+		iproc_host->is_cmd_shadowed = false;
+	} else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
+		   iproc_host->is_blk_shadowed) {
 		/* Block size and count are stored in shadow reg */
 		oldval = iproc_host->shadow_blk;
 	} else {
@@ -122,9 +140,11 @@
 	if (reg == SDHCI_TRANSFER_MODE) {
 		/* Save the transfer mode until the command is issued */
 		iproc_host->shadow_cmd = newval;
+		iproc_host->is_cmd_shadowed = true;
 	} else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) {
 		/* Save the block info until the command is issued */
 		iproc_host->shadow_blk = newval;
+		iproc_host->is_blk_shadowed = true;
 	} else {
 		/* Command or other regular 32-bit write */
 		sdhci_iproc_writel(host, newval, reg & ~3);
@@ -156,7 +176,8 @@
 };
 
 static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
-	.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
+	.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
 	.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN,
 	.ops = &sdhci_iproc_ops,
 };
@@ -196,7 +217,10 @@
 
 	iproc_host->data = iproc_data;
 
-	mmc_of_parse(host->mmc);
+	ret = mmc_of_parse(host->mmc);
+	if (ret)
+		goto err;
+
 	sdhci_get_of_property(pdev);
 
 	/* Enable EMMC 1/8V DDR capable */
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-of-at91.c
+++ linux-4.4.0/drivers/mmc/host/sdhci-of-at91.c
@@ -144,6 +144,9 @@
 
 	sdhci_get_of_property(pdev);
 
+	/* HS200 is broken at this moment */
+	host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
+
 	ret = sdhci_add_host(host);
 	if (ret)
 		goto clocks_disable_unprepare;
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-of-esdhc.c
+++ linux-4.4.0/drivers/mmc/host/sdhci-of-esdhc.c
@@ -418,6 +418,20 @@
 	if (esdhc->vendor_ver < VENDOR_V_23)
 		pre_div = 2;
 
+	/*
+	 * Limit SD clock to 167MHz for ls1046a according to its datasheet
+	 */
+	if (clock > 167000000 &&
+	    of_find_compatible_node(NULL, NULL, "fsl,ls1046a-esdhc"))
+		clock = 167000000;
+
+	/*
+	 * Limit SD clock to 125MHz for ls1012a according to its datasheet
+	 */
+	if (clock > 125000000 &&
+	    of_find_compatible_node(NULL, NULL, "fsl,ls1012a-esdhc"))
+		clock = 125000000;
+
 	/* Workaround to reduce the clock frequency for p1010 esdhc */
 	if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
 		if (clock > 20000000)
@@ -584,6 +598,8 @@
 {
 	struct sdhci_host *host;
 	struct device_node *np;
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_esdhc *esdhc;
 	int ret;
 
 	np = pdev->dev.of_node;
@@ -600,6 +616,19 @@
 
 	sdhci_get_of_property(pdev);
 
+	pltfm_host = sdhci_priv(host);
+	esdhc = pltfm_host->priv;
+	if (esdhc->vendor_ver == VENDOR_V_22)
+		host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
+
+	if (esdhc->vendor_ver > VENDOR_V_22)
+		host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
+
+	if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) {
+		host->quirks |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
+		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+	}
+
 	if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
 	    of_device_is_compatible(np, "fsl,p5020-esdhc") ||
 	    of_device_is_compatible(np, "fsl,p4080-esdhc") ||
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-pci-core.c
+++ linux-4.4.0/drivers/mmc/host/sdhci-pci-core.c
@@ -277,7 +277,7 @@
 	if (sdhci_pci_spt_drive_strength > 0)
 		drive_strength = sdhci_pci_spt_drive_strength & 0xf;
 	else
-		drive_strength = 1; /* 33-ohm */
+		drive_strength = 0; /* Default 50-ohm */
 
 	if ((mmc_driver_type_mask(drive_strength) & card_drv) == 0)
 		drive_strength = 0; /* Default 50-ohm */
@@ -330,11 +330,37 @@
 	sdhci_pci_spt_drive_strength = 0x10 | ((val >> 12) & 0xf);
 }
 
+static int bxt_get_cd(struct mmc_host *mmc)
+{
+	int gpio_cd = mmc_gpio_get_cd(mmc);
+	struct sdhci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	int ret = 0;
+
+	if (!gpio_cd)
+		return 0;
+
+	pm_runtime_get_sync(mmc->parent);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (host->flags & SDHCI_DEVICE_DEAD)
+		goto out;
+
+	ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+out:
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	pm_runtime_mark_last_busy(mmc->parent);
+	pm_runtime_put_autosuspend(mmc->parent);
+
+	return ret;
+}
+
 static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
 	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
 				 MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
-				 MMC_CAP_BUS_WIDTH_TEST |
 				 MMC_CAP_WAIT_WHILE_BUSY;
 	slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
 	slot->hw_reset = sdhci_pci_int_hw_reset;
@@ -350,18 +376,21 @@
 static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 {
 	slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE |
-				 MMC_CAP_BUS_WIDTH_TEST |
 				 MMC_CAP_WAIT_WHILE_BUSY;
 	return 0;
 }
 
 static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
 {
-	slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST |
-				 MMC_CAP_WAIT_WHILE_BUSY;
+	slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
 	slot->cd_con_id = NULL;
 	slot->cd_idx = 0;
 	slot->cd_override_level = true;
+	if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD ||
+	    slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXTM_SD ||
+	    slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD)
+		slot->host->mmc_host_ops.get_cd = bxt_get_cd;
+
 	return 0;
 }
 
@@ -1138,6 +1167,30 @@
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
 		.driver_data	= (kernel_ulong_t)&sdhci_intel_byt_sd,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_BXTM_EMMC,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_byt_emmc,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_BXTM_SDIO,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_byt_sdio,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_BXTM_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_byt_sd,
 	},
 
 	{
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-pci-o2micro.c
+++ linux-4.4.0/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -334,6 +334,9 @@
 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
 		break;
 	case PCI_DEVICE_ID_O2_SEABIRD0:
+		if (chip->pdev->revision == 0x01)
+			chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER;
+		/* fall through */
 	case PCI_DEVICE_ID_O2_SEABIRD1:
 		/* UnLock WP */
 		ret = pci_read_config_byte(chip->pdev,
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-pci.h
+++ linux-4.4.0/drivers/mmc/host/sdhci-pci.h
@@ -28,6 +28,9 @@
 #define PCI_DEVICE_ID_INTEL_BXT_SD	0x0aca
 #define PCI_DEVICE_ID_INTEL_BXT_EMMC	0x0acc
 #define PCI_DEVICE_ID_INTEL_BXT_SDIO	0x0ad0
+#define PCI_DEVICE_ID_INTEL_BXTM_SD	0x1aca
+#define PCI_DEVICE_ID_INTEL_BXTM_EMMC	0x1acc
+#define PCI_DEVICE_ID_INTEL_BXTM_SDIO	0x1ad0
 #define PCI_DEVICE_ID_INTEL_APL_SD	0x5aca
 #define PCI_DEVICE_ID_INTEL_APL_EMMC	0x5acc
 #define PCI_DEVICE_ID_INTEL_APL_SDIO	0x5ad0
--- linux-4.4.0.orig/drivers/mmc/host/sdhci-pxav3.c
+++ linux-4.4.0/drivers/mmc/host/sdhci-pxav3.c
@@ -307,8 +307,30 @@
 		__func__, uhs, ctrl_2);
 }
 
+static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
+			    unsigned short vdd)
+{
+	struct mmc_host *mmc = host->mmc;
+	u8 pwr = host->pwr;
+
+	sdhci_set_power(host, mode, vdd);
+
+	if (host->pwr == pwr)
+		return;
+
+	if (host->pwr == 0)
+		vdd = 0;
+
+	if (!IS_ERR(mmc->supply.vmmc)) {
+		spin_unlock_irq(&host->lock);
+		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+		spin_lock_irq(&host->lock);
+	}
+}
+
 static const struct sdhci_ops pxav3_sdhci_ops = {
 	.set_clock = sdhci_set_clock,
+	.set_power = pxav3_set_power,
 	.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.set_bus_width = sdhci_set_bus_width,
--- linux-4.4.0.orig/drivers/mmc/host/sdhci.c
+++ linux-4.4.0/drivers/mmc/host/sdhci.c
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include <linux/regulator/consumer.h>
@@ -492,7 +493,7 @@
 		host->align_buffer, host->align_buffer_sz, direction);
 	if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
 		goto fail;
-	BUG_ON(host->align_addr & host->align_mask);
+	BUG_ON(host->align_addr & SDHCI_ADMA2_MASK);
 
 	host->sg_count = sdhci_pre_dma_transfer(host, data);
 	if (host->sg_count < 0)
@@ -514,8 +515,8 @@
 		 * the (up to three) bytes that screw up the
 		 * alignment.
 		 */
-		offset = (host->align_sz - (addr & host->align_mask)) &
-			 host->align_mask;
+		offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
+			 SDHCI_ADMA2_MASK;
 		if (offset) {
 			if (data->flags & MMC_DATA_WRITE) {
 				buffer = sdhci_kmap_atomic(sg, &flags);
@@ -529,8 +530,8 @@
 
 			BUG_ON(offset > 65536);
 
-			align += host->align_sz;
-			align_addr += host->align_sz;
+			align += SDHCI_ADMA2_ALIGN;
+			align_addr += SDHCI_ADMA2_ALIGN;
 
 			desc += host->desc_sz;
 
@@ -540,9 +541,12 @@
 
 		BUG_ON(len > 65536);
 
-		/* tran, valid */
-		sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID);
-		desc += host->desc_sz;
+		if (len) {
+			/* tran, valid */
+			sdhci_adma_write_desc(host, desc, addr, len,
+					      ADMA2_TRAN_VALID);
+			desc += host->desc_sz;
+		}
 
 		/*
 		 * If this triggers then we have a calculation bug
@@ -608,7 +612,7 @@
 	/* Do a quick scan of the SG list for any unaligned mappings */
 	has_unaligned = false;
 	for_each_sg(data->sg, sg, host->sg_count, i)
-		if (sg_dma_address(sg) & host->align_mask) {
+		if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
 			has_unaligned = true;
 			break;
 		}
@@ -620,15 +624,15 @@
 		align = host->align_buffer;
 
 		for_each_sg(data->sg, sg, host->sg_count, i) {
-			if (sg_dma_address(sg) & host->align_mask) {
-				size = host->align_sz -
-				       (sg_dma_address(sg) & host->align_mask);
+			if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
+				size = SDHCI_ADMA2_ALIGN -
+				       (sg_dma_address(sg) & SDHCI_ADMA2_MASK);
 
 				buffer = sdhci_kmap_atomic(sg, &flags);
 				memcpy(buffer, align, size);
 				sdhci_kunmap_atomic(buffer, &flags);
 
-				align += host->align_sz;
+				align += SDHCI_ADMA2_ALIGN;
 			}
 		}
 	}
@@ -663,9 +667,20 @@
 	if (!data)
 		target_timeout = cmd->busy_timeout * 1000;
 	else {
-		target_timeout = data->timeout_ns / 1000;
-		if (host->clock)
-			target_timeout += data->timeout_clks / host->clock;
+		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
+		if (host->clock && data->timeout_clks) {
+			unsigned long long val;
+
+			/*
+			 * data->timeout_clks is in units of clock cycles.
+			 * host->clock is in Hz.  target_timeout is in us.
+			 * Hence, us = 1000000 * cycles / Hz.  Round up.
+			 */
+			val = 1000000ULL * data->timeout_clks;
+			if (do_div(val, host->clock))
+				target_timeout++;
+			target_timeout += val;
+		}
 	}
 
 	/*
@@ -1260,7 +1275,9 @@
 			return;
 		}
 		timeout--;
-		mdelay(1);
+		spin_unlock_irq(&host->lock);
+		usleep_range(900, 1100);
+		spin_lock_irq(&host->lock);
 	}
 
 	clk |= SDHCI_CLOCK_CARD_EN;
@@ -1268,24 +1285,25 @@
 }
 EXPORT_SYMBOL_GPL(sdhci_set_clock);
 
-static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
-			    unsigned short vdd)
+static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
+				unsigned short vdd)
 {
 	struct mmc_host *mmc = host->mmc;
-	u8 pwr = 0;
 
-	if (!IS_ERR(mmc->supply.vmmc)) {
-		spin_unlock_irq(&host->lock);
-		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
-		spin_lock_irq(&host->lock);
+	spin_unlock_irq(&host->lock);
+	mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+	spin_lock_irq(&host->lock);
 
-		if (mode != MMC_POWER_OFF)
-			sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
-		else
-			sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+	if (mode != MMC_POWER_OFF)
+		sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
+	else
+		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+}
 
-		return;
-	}
+void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+		     unsigned short vdd)
+{
+	u8 pwr = 0;
 
 	if (mode != MMC_POWER_OFF) {
 		switch (1 << vdd) {
@@ -1301,7 +1319,9 @@
 			pwr = SDHCI_POWER_330;
 			break;
 		default:
-			BUG();
+			WARN(1, "%s: Invalid vdd %#x\n",
+			     mmc_hostname(host->mmc), vdd);
+			break;
 		}
 	}
 
@@ -1314,7 +1334,6 @@
 		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
 			sdhci_runtime_pm_bus_off(host);
-		vdd = 0;
 	} else {
 		/*
 		 * Spec says that we should clear the power reg before setting
@@ -1346,6 +1365,20 @@
 			mdelay(10);
 	}
 }
+EXPORT_SYMBOL_GPL(sdhci_set_power);
+
+static void __sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+			      unsigned short vdd)
+{
+	struct mmc_host *mmc = host->mmc;
+
+	if (host->ops->set_power)
+		host->ops->set_power(host, mode, vdd);
+	else if (!IS_ERR(mmc->supply.vmmc))
+		sdhci_set_power_reg(host, mode, vdd);
+	else
+		sdhci_set_power(host, mode, vdd);
+}
 
 /*****************************************************************************\
  *                                                                           *
@@ -1364,7 +1397,7 @@
 	sdhci_runtime_pm_get(host);
 
 	/* Firstly check card presence */
-	present = sdhci_do_get_cd(host);
+	present = mmc->ops->get_cd(mmc);
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -1494,7 +1527,7 @@
 		}
 	}
 
-	sdhci_set_power(host, ios->power_mode, ios->vdd);
+	__sdhci_set_power(host, ios->power_mode, ios->vdd);
 
 	if (host->ops->platform_send_init_74_clocks)
 		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -1729,9 +1762,18 @@
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
+	struct pci_dev *pci_host;
 	unsigned long flags;
 
-	sdhci_runtime_pm_get(host);
+	pci_host = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID,
+			0x1028, 0x07b9, NULL);
+
+	if (!pci_host)
+		sdhci_runtime_pm_get(host);
+	else {
+		if (enable)
+			sdhci_runtime_pm_get(host);
+	}
 
 	spin_lock_irqsave(&host->lock, flags);
 	if (enable)
@@ -1742,7 +1784,12 @@
 	sdhci_enable_sdio_irq_nolock(host, enable);
 	spin_unlock_irqrestore(&host->lock, flags);
 
-	sdhci_runtime_pm_put(host);
+	if (!pci_host)
+		sdhci_runtime_pm_put(host);
+	else {
+		if (!enable)
+			sdhci_runtime_pm_put(host);
+	}
 }
 
 static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
@@ -2015,7 +2062,7 @@
 		spin_lock_irqsave(&host->lock, flags);
 
 		if (!host->tuning_done) {
-			pr_info(DRIVER_NAME ": Timeout waiting for "
+			pr_debug(DRIVER_NAME ": Timeout waiting for "
 				"Buffer Read Ready interrupt during tuning "
 				"procedure, falling back to fixed sampling "
 				"clock\n");
@@ -2024,7 +2071,27 @@
 			ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
 			sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
+			sdhci_do_reset(host, SDHCI_RESET_CMD);
+			sdhci_do_reset(host, SDHCI_RESET_DATA);
+
 			err = -EIO;
+
+			if (cmd.opcode != MMC_SEND_TUNING_BLOCK_HS200)
+				goto out;
+
+			sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+			sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+			spin_unlock_irqrestore(&host->lock, flags);
+
+			memset(&cmd, 0, sizeof(cmd));
+			cmd.opcode = MMC_STOP_TRANSMISSION;
+			cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+			cmd.busy_timeout = 50;
+			mmc_wait_for_cmd(mmc, &cmd, 0);
+
+			spin_lock_irqsave(&host->lock, flags);
+
 			goto out;
 		}
 
@@ -2593,7 +2660,8 @@
 			pr_err("%s: Card is consuming too much power!\n",
 				mmc_hostname(host->mmc));
 
-		if (intmask & SDHCI_INT_CARD_INT) {
+		if ((intmask & SDHCI_INT_CARD_INT) &&
+		    (host->ier & SDHCI_INT_CARD_INT)) {
 			sdhci_enable_sdio_irq_nolock(host, false);
 			host->thread_isr |= SDHCI_INT_CARD_INT;
 			result = IRQ_WAKE_THREAD;
@@ -2760,7 +2828,7 @@
 
 static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
 {
-	if (host->runtime_suspended || host->bus_on)
+	if (host->bus_on)
 		return;
 	host->bus_on = true;
 	pm_runtime_get_noresume(host->mmc->parent);
@@ -2768,7 +2836,7 @@
 
 static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
 {
-	if (host->runtime_suspended || !host->bus_on)
+	if (!host->bus_on)
 		return;
 	host->bus_on = false;
 	pm_runtime_put_noidle(host->mmc->parent);
@@ -2861,6 +2929,8 @@
 
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
+	host->mmc_host_ops = sdhci_ops;
+	mmc->ops = &host->mmc_host_ops;
 
 	return host;
 }
@@ -2967,24 +3037,17 @@
 		if (host->flags & SDHCI_USE_64_BIT_DMA) {
 			host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
 					      SDHCI_ADMA2_64_DESC_SZ;
-			host->align_buffer_sz = SDHCI_MAX_SEGS *
-						SDHCI_ADMA2_64_ALIGN;
 			host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
-			host->align_sz = SDHCI_ADMA2_64_ALIGN;
-			host->align_mask = SDHCI_ADMA2_64_ALIGN - 1;
 		} else {
 			host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
 					      SDHCI_ADMA2_32_DESC_SZ;
-			host->align_buffer_sz = SDHCI_MAX_SEGS *
-						SDHCI_ADMA2_32_ALIGN;
 			host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
-			host->align_sz = SDHCI_ADMA2_32_ALIGN;
-			host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
 		}
 		host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
 						      host->adma_table_sz,
 						      &host->adma_addr,
 						      GFP_KERNEL);
+		host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
 		host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
 		if (!host->adma_table || !host->align_buffer) {
 			if (host->adma_table)
@@ -2998,7 +3061,7 @@
 			host->flags &= ~SDHCI_USE_ADMA;
 			host->adma_table = NULL;
 			host->align_buffer = NULL;
-		} else if (host->adma_addr & host->align_mask) {
+		} else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) {
 			pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
 				mmc_hostname(mmc));
 			host->flags &= ~SDHCI_USE_ADMA;
@@ -3057,17 +3120,18 @@
 	/*
 	 * Set host parameters.
 	 */
-	mmc->ops = &sdhci_ops;
 	max_clk = host->max_clk;
 
 	if (host->ops->get_min_clock)
 		mmc->f_min = host->ops->get_min_clock(host);
 	else if (host->version >= SDHCI_SPEC_300) {
-		if (host->clk_mul) {
-			mmc->f_min = (host->max_clk * host->clk_mul) / 1024;
+		if (host->clk_mul)
 			max_clk = host->max_clk * host->clk_mul;
-		} else
-			mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
+		/*
+		 * Divided Clock Mode minimum clock rate is always less than
+		 * Programmable Clock Mode minimum clock rate.
+		 */
+		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
 	} else
 		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
@@ -3091,14 +3155,14 @@
 		if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
 			host->timeout_clk *= 1000;
 
+		if (override_timeout_clk)
+			host->timeout_clk = override_timeout_clk;
+
 		mmc->max_busy_timeout = host->ops->get_max_timeout_count ?
 			host->ops->get_max_timeout_count(host) : 1 << 27;
 		mmc->max_busy_timeout /= host->timeout_clk;
 	}
 
-	if (override_timeout_clk)
-		host->timeout_clk = override_timeout_clk;
-
 	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 	mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
--- linux-4.4.0.orig/drivers/mmc/host/sdhci.h
+++ linux-4.4.0/drivers/mmc/host/sdhci.h
@@ -272,22 +272,27 @@
 /* ADMA2 32-bit DMA descriptor size */
 #define SDHCI_ADMA2_32_DESC_SZ	8
 
-/* ADMA2 32-bit DMA alignment */
-#define SDHCI_ADMA2_32_ALIGN	4
-
 /* ADMA2 32-bit descriptor */
 struct sdhci_adma2_32_desc {
 	__le16	cmd;
 	__le16	len;
 	__le32	addr;
-}  __packed __aligned(SDHCI_ADMA2_32_ALIGN);
+}  __packed __aligned(4);
+
+/* ADMA2 data alignment */
+#define SDHCI_ADMA2_ALIGN	4
+#define SDHCI_ADMA2_MASK	(SDHCI_ADMA2_ALIGN - 1)
+
+/*
+ * ADMA2 descriptor alignment.  Some controllers (e.g. Intel) require 8 byte
+ * alignment for the descriptor table even in 32-bit DMA mode.  Memory
+ * allocation is at least 8 byte aligned anyway, so just stipulate 8 always.
+ */
+#define SDHCI_ADMA2_DESC_ALIGN	8
 
 /* ADMA2 64-bit DMA descriptor size */
 #define SDHCI_ADMA2_64_DESC_SZ	12
 
-/* ADMA2 64-bit DMA alignment */
-#define SDHCI_ADMA2_64_ALIGN	8
-
 /*
  * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
  * aligned.
@@ -425,6 +430,7 @@
 
 	/* Internal data */
 	struct mmc_host *mmc;	/* MMC structure */
+	struct mmc_host_ops mmc_host_ops;	/* MMC host ops */
 	u64 dma_mask;		/* custom DMA mask */
 
 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
@@ -482,8 +488,6 @@
 	dma_addr_t align_addr;	/* Mapped bounce buffer */
 
 	unsigned int desc_sz;	/* ADMA descriptor size */
-	unsigned int align_sz;	/* ADMA alignment */
-	unsigned int align_mask;	/* ADMA alignment mask */
 
 	struct tasklet_struct finish_tasklet;	/* Tasklet structures */
 
@@ -525,6 +529,8 @@
 #endif
 
 	void	(*set_clock)(struct sdhci_host *host, unsigned int clock);
+	void	(*set_power)(struct sdhci_host *host, unsigned char mode,
+			     unsigned short vdd);
 
 	int		(*enable_dma)(struct sdhci_host *host);
 	unsigned int	(*get_max_clock)(struct sdhci_host *host);
@@ -656,6 +662,8 @@
 }
 
 void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
+void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+		     unsigned short vdd);
 void sdhci_set_bus_width(struct sdhci_host *host, int width);
 void sdhci_reset(struct sdhci_host *host, u8 mask);
 void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
--- linux-4.4.0.orig/drivers/mmc/host/sh_mmcif.c
+++ linux-4.4.0/drivers/mmc/host/sh_mmcif.c
@@ -397,38 +397,26 @@
 }
 
 static struct dma_chan *
-sh_mmcif_request_dma_one(struct sh_mmcif_host *host,
-			 struct sh_mmcif_plat_data *pdata,
-			 enum dma_transfer_direction direction)
+sh_mmcif_request_dma_pdata(struct sh_mmcif_host *host, uintptr_t slave_id)
 {
-	struct dma_slave_config cfg = { 0, };
-	struct dma_chan *chan;
-	void *slave_data = NULL;
-	struct resource *res;
-	struct device *dev = sh_mmcif_host_to_dev(host);
 	dma_cap_mask_t mask;
-	int ret;
 
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
+	if (slave_id <= 0)
+		return NULL;
 
-	if (pdata)
-		slave_data = direction == DMA_MEM_TO_DEV ?
-			(void *)pdata->slave_id_tx :
-			(void *)pdata->slave_id_rx;
-
-	chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
-				slave_data, dev,
-				direction == DMA_MEM_TO_DEV ? "tx" : "rx");
-
-	dev_dbg(dev, "%s: %s: got channel %p\n", __func__,
-		direction == DMA_MEM_TO_DEV ? "TX" : "RX", chan);
+	return dma_request_channel(mask, shdma_chan_filter, (void *)slave_id);
+}
 
-	if (!chan)
-		return NULL;
+static int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host,
+				     struct dma_chan *chan,
+				     enum dma_transfer_direction direction)
+{
+	struct resource *res;
+	struct dma_slave_config cfg = { 0, };
 
 	res = platform_get_resource(host->pd, IORESOURCE_MEM, 0);
-
 	cfg.direction = direction;
 
 	if (direction == DMA_DEV_TO_MEM) {
@@ -439,38 +427,42 @@
 		cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	}
 
-	ret = dmaengine_slave_config(chan, &cfg);
-	if (ret < 0) {
-		dma_release_channel(chan);
-		return NULL;
-	}
-
-	return chan;
+	return dmaengine_slave_config(chan, &cfg);
 }
 
-static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
-				 struct sh_mmcif_plat_data *pdata)
+static void sh_mmcif_request_dma(struct sh_mmcif_host *host)
 {
 	struct device *dev = sh_mmcif_host_to_dev(host);
 	host->dma_active = false;
 
-	if (pdata) {
-		if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0)
-			return;
-	} else if (!dev->of_node) {
-		return;
+	/* We can only either use DMA for both Tx and Rx or not use it at all */
+	if (IS_ENABLED(CONFIG_SUPERH) && dev->platform_data) {
+		struct sh_mmcif_plat_data *pdata = dev->platform_data;
+
+		host->chan_tx = sh_mmcif_request_dma_pdata(host,
+							pdata->slave_id_tx);
+		host->chan_rx = sh_mmcif_request_dma_pdata(host,
+							pdata->slave_id_rx);
+	} else {
+		host->chan_tx = dma_request_slave_channel(dev, "tx");
+		host->chan_rx = dma_request_slave_channel(dev, "rx");
 	}
+	dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx,
+		host->chan_rx);
 
-	/* We can only either use DMA for both Tx and Rx or not use it at all */
-	host->chan_tx = sh_mmcif_request_dma_one(host, pdata, DMA_MEM_TO_DEV);
-	if (!host->chan_tx)
-		return;
+	if (!host->chan_tx || !host->chan_rx ||
+	    sh_mmcif_dma_slave_config(host, host->chan_tx, DMA_MEM_TO_DEV) ||
+	    sh_mmcif_dma_slave_config(host, host->chan_rx, DMA_DEV_TO_MEM))
+		goto error;
 
-	host->chan_rx = sh_mmcif_request_dma_one(host, pdata, DMA_DEV_TO_MEM);
-	if (!host->chan_rx) {
+	return;
+
+error:
+	if (host->chan_tx)
 		dma_release_channel(host->chan_tx);
-		host->chan_tx = NULL;
-	}
+	if (host->chan_rx)
+		dma_release_channel(host->chan_rx);
+	host->chan_tx = host->chan_rx = NULL;
 }
 
 static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
@@ -1102,7 +1094,7 @@
 	if (ios->power_mode == MMC_POWER_UP) {
 		if (!host->card_present) {
 			/* See if we also get DMA */
-			sh_mmcif_request_dma(host, dev->platform_data);
+			sh_mmcif_request_dma(host);
 			host->card_present = true;
 		}
 		sh_mmcif_set_power(host, ios);
--- linux-4.4.0.orig/drivers/mmc/host/tmio_mmc_pio.c
+++ linux-4.4.0/drivers/mmc/host/tmio_mmc_pio.c
@@ -716,7 +716,7 @@
 	unsigned int sdio_status;
 
 	if (!(pdata->flags & TMIO_MMC_SDIO_IRQ))
-		return IRQ_HANDLED;
+		return IRQ_NONE;
 
 	status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
 	ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
@@ -730,7 +730,7 @@
 	if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ)
 		mmc_signal_sdio_irq(mmc);
 
-	return IRQ_HANDLED;
+	return IRQ_RETVAL(ireg);
 }
 EXPORT_SYMBOL(tmio_mmc_sdio_irq);
 
@@ -747,9 +747,7 @@
 	if (__tmio_mmc_sdcard_irq(host, ireg, status))
 		return IRQ_HANDLED;
 
-	tmio_mmc_sdio_irq(irq, devid);
-
-	return IRQ_HANDLED;
+	return tmio_mmc_sdio_irq(irq, devid);
 }
 EXPORT_SYMBOL(tmio_mmc_irq);
 
--- linux-4.4.0.orig/drivers/mmc/host/usdhi6rol0.c
+++ linux-4.4.0/drivers/mmc/host/usdhi6rol0.c
@@ -1634,7 +1634,7 @@
 	struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work);
 	struct mmc_request *mrq = host->mrq;
 	struct mmc_data *data = mrq ? mrq->data : NULL;
-	struct scatterlist *sg = host->sg ?: data->sg;
+	struct scatterlist *sg;
 
 	dev_warn(mmc_dev(host->mmc),
 		 "%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n",
@@ -1666,6 +1666,7 @@
 	case USDHI6_WAIT_FOR_MWRITE:
 	case USDHI6_WAIT_FOR_READ:
 	case USDHI6_WAIT_FOR_WRITE:
+		sg = host->sg ?: data->sg;
 		dev_dbg(mmc_dev(host->mmc),
 			"%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n",
 			data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx,
@@ -1807,10 +1808,12 @@
 
 	ret = mmc_add_host(mmc);
 	if (ret < 0)
-		goto e_clk_off;
+		goto e_release_dma;
 
 	return 0;
 
+e_release_dma:
+	usdhi6_dma_release(host);
 e_clk_off:
 	clk_disable_unprepare(host->clk);
 e_free_mmc:
--- linux-4.4.0.orig/drivers/mmc/host/ushc.c
+++ linux-4.4.0/drivers/mmc/host/ushc.c
@@ -426,6 +426,9 @@
 	struct ushc_data *ushc;
 	int ret;
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
 	if (mmc == NULL)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/mmc/host/via-sdmmc.c
+++ linux-4.4.0/drivers/mmc/host/via-sdmmc.c
@@ -1269,11 +1269,14 @@
 static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state)
 {
 	struct via_crdr_mmc_host *host;
+	unsigned long flags;
 
 	host = pci_get_drvdata(pcidev);
 
+	spin_lock_irqsave(&host->lock, flags);
 	via_save_pcictrlreg(host);
 	via_save_sdcreg(host);
+	spin_unlock_irqrestore(&host->lock, flags);
 
 	pci_save_state(pcidev);
 	pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
--- linux-4.4.0.orig/drivers/mmc/host/wbsd.c
+++ linux-4.4.0/drivers/mmc/host/wbsd.c
@@ -1995,11 +1995,11 @@
 module_init(wbsd_drv_init);
 module_exit(wbsd_drv_exit);
 #ifdef CONFIG_PNP
-module_param_named(nopnp, param_nopnp, uint, 0444);
+module_param_hw_named(nopnp, param_nopnp, uint, other, 0444);
 #endif
-module_param_named(io, param_io, uint, 0444);
-module_param_named(irq, param_irq, uint, 0444);
-module_param_named(dma, param_dma, int, 0444);
+module_param_hw_named(io, param_io, uint, ioport, 0444);
+module_param_hw_named(irq, param_irq, uint, irq, 0444);
+module_param_hw_named(dma, param_dma, int, dma, 0444);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
--- linux-4.4.0.orig/drivers/mtd/bcm47xxpart.c
+++ linux-4.4.0/drivers/mtd/bcm47xxpart.c
@@ -66,11 +66,13 @@
 {
 	uint32_t buf;
 	size_t bytes_read;
+	int err;
 
-	if (mtd_read(master, offset, sizeof(buf), &bytes_read,
-		     (uint8_t *)&buf) < 0) {
-		pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-			offset);
+	err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
+			(uint8_t *)&buf);
+	if (err && !mtd_is_bitflip(err)) {
+		pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+			offset, err);
 		goto out_default;
 	}
 
@@ -95,6 +97,7 @@
 	int trx_part = -1;
 	int last_trx_part = -1;
 	int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
+	int err;
 
 	/*
 	 * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
@@ -118,8 +121,8 @@
 	/* Parse block by block looking for magics */
 	for (offset = 0; offset <= master->size - blocksize;
 	     offset += blocksize) {
-		/* Nothing more in higher memory */
-		if (offset >= 0x2000000)
+		/* Nothing more in higher memory on BCM47XX (MIPS) */
+		if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
 			break;
 
 		if (curr_part >= BCM47XXPART_MAX_PARTS) {
@@ -128,10 +131,11 @@
 		}
 
 		/* Read beginning of the block */
-		if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
-			     &bytes_read, (uint8_t *)buf) < 0) {
-			pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-			       offset);
+		err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+			       &bytes_read, (uint8_t *)buf);
+		if (err && !mtd_is_bitflip(err)) {
+			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+			       offset, err);
 			continue;
 		}
 
@@ -225,12 +229,10 @@
 
 			last_trx_part = curr_part - 1;
 
-			/*
-			 * We have whole TRX scanned, skip to the next part. Use
-			 * roundown (not roundup), as the loop will increase
-			 * offset in next step.
-			 */
-			offset = rounddown(offset + trx->length, blocksize);
+			/* Jump to the end of TRX */
+			offset = roundup(offset + trx->length, blocksize);
+			/* Next loop iteration will increase the offset */
+			offset -= blocksize;
 			continue;
 		}
 
@@ -254,10 +256,11 @@
 		}
 
 		/* Read middle of the block */
-		if (mtd_read(master, offset + 0x8000, 0x4,
-			     &bytes_read, (uint8_t *)buf) < 0) {
-			pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-			       offset);
+		err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
+			       (uint8_t *)buf);
+		if (err && !mtd_is_bitflip(err)) {
+			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+			       offset, err);
 			continue;
 		}
 
@@ -277,10 +280,11 @@
 		}
 
 		offset = master->size - possible_nvram_sizes[i];
-		if (mtd_read(master, offset, 0x4, &bytes_read,
-			     (uint8_t *)buf) < 0) {
-			pr_err("mtd_read error while reading at offset 0x%X!\n",
-			       offset);
+		err = mtd_read(master, offset, 0x4, &bytes_read,
+			       (uint8_t *)buf);
+		if (err && !mtd_is_bitflip(err)) {
+			pr_err("mtd_read error while reading (offset 0x%X): %d\n",
+			       offset, err);
 			continue;
 		}
 
--- linux-4.4.0.orig/drivers/mtd/chips/Kconfig
+++ linux-4.4.0/drivers/mtd/chips/Kconfig
@@ -67,6 +67,10 @@
 config MTD_CFI_GEOMETRY
 	bool "Specific CFI Flash geometry selection"
 	depends on MTD_CFI_ADV_OPTIONS
+	select MTD_MAP_BANK_WIDTH_1 if  !(MTD_MAP_BANK_WIDTH_2 || \
+		 MTD_MAP_BANK_WIDTH_4  || MTD_MAP_BANK_WIDTH_8 || \
+		 MTD_MAP_BANK_WIDTH_16 || MTD_MAP_BANK_WIDTH_32)
+	select MTD_CFI_I1 if !(MTD_CFI_I2 || MTD_CFI_I4 || MTD_CFI_I8)
 	help
 	  This option does not affect the code directly, but will enable
 	  some other configuration options which would allow you to reduce
@@ -111,6 +115,7 @@
 
 config MTD_MAP_BANK_WIDTH_32
 	bool "Support 256-bit buswidth" if MTD_CFI_GEOMETRY
+	select MTD_COMPLEX_MAPPINGS if HAS_IOMEM
 	default n
 	help
 	  If you wish to support CFI devices on a physical bus which is
--- linux-4.4.0.orig/drivers/mtd/chips/cfi_cmdset_0001.c
+++ linux-4.4.0/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -45,6 +45,7 @@
 #define I82802AB	0x00ad
 #define I82802AC	0x00ac
 #define PF38F4476	0x881c
+#define M28F00AP30	0x8963
 /* STMicroelectronics chips */
 #define M50LPW080       0x002F
 #define M50FLW080A	0x0080
@@ -375,6 +376,17 @@
 		extp->MinorVersion = '1';
 }
 
+static int cfi_is_micron_28F00AP30(struct cfi_private *cfi, struct flchip *chip)
+{
+	/*
+	 * Micron(was Numonyx) 1Gbit bottom boot are buggy w.r.t
+	 * Erase Supend for their small Erase Blocks(0x8000)
+	 */
+	if (cfi->mfr == CFI_MFR_INTEL && cfi->id == M28F00AP30)
+		return 1;
+	return 0;
+}
+
 static inline struct cfi_pri_intelext *
 read_pri_intelext(struct map_info *map, __u16 adr)
 {
@@ -825,21 +837,30 @@
 		     (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
 			goto sleep;
 
+		/* Do not allow suspend iff read/write to EB address */
+		if ((adr & chip->in_progress_block_mask) ==
+		    chip->in_progress_block_addr)
+			goto sleep;
+
+		/* do not suspend small EBs, buggy Micron Chips */
+		if (cfi_is_micron_28F00AP30(cfi, chip) &&
+		    (chip->in_progress_block_mask == ~(0x8000-1)))
+			goto sleep;
 
 		/* Erase suspend */
-		map_write(map, CMD(0xB0), adr);
+		map_write(map, CMD(0xB0), chip->in_progress_block_addr);
 
 		/* If the flash has finished erasing, then 'erase suspend'
 		 * appears to make some (28F320) flash devices switch to
 		 * 'read' mode.  Make sure that we switch to 'read status'
 		 * mode so we get the right data. --rmk
 		 */
-		map_write(map, CMD(0x70), adr);
+		map_write(map, CMD(0x70), chip->in_progress_block_addr);
 		chip->oldstate = FL_ERASING;
 		chip->state = FL_ERASE_SUSPENDING;
 		chip->erase_suspended = 1;
 		for (;;) {
-			status = map_read(map, adr);
+			status = map_read(map, chip->in_progress_block_addr);
 			if (map_word_andequal(map, status, status_OK, status_OK))
 			        break;
 
@@ -1035,8 +1056,8 @@
 		   sending the 0x70 (Read Status) command to an erasing
 		   chip and expecting it to be ignored, that's what we
 		   do. */
-		map_write(map, CMD(0xd0), adr);
-		map_write(map, CMD(0x70), adr);
+		map_write(map, CMD(0xd0), chip->in_progress_block_addr);
+		map_write(map, CMD(0x70), chip->in_progress_block_addr);
 		chip->oldstate = FL_READY;
 		chip->state = FL_ERASING;
 		break;
@@ -1927,6 +1948,8 @@
 	map_write(map, CMD(0xD0), adr);
 	chip->state = FL_ERASING;
 	chip->erase_suspended = 0;
+	chip->in_progress_block_addr = adr;
+	chip->in_progress_block_mask = ~(len - 1);
 
 	ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
 				   adr, len,
--- linux-4.4.0.orig/drivers/mtd/chips/cfi_cmdset_0002.c
+++ linux-4.4.0/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -42,7 +42,7 @@
 #define AMD_BOOTLOC_BUG
 #define FORCE_WORD_WRITE 0
 
-#define MAX_WORD_RETRIES 3
+#define MAX_RETRIES 3
 
 #define SST49LF004B	        0x0060
 #define SST49LF040B	        0x0050
@@ -724,7 +724,6 @@
 	kfree(mtd->eraseregions);
 	kfree(mtd);
 	kfree(cfi->cmdset_priv);
-	kfree(cfi->cfiq);
 	return NULL;
 }
 
@@ -814,9 +813,10 @@
 		    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
 			goto sleep;
 
-		/* We could check to see if we're trying to access the sector
-		 * that is currently being erased. However, no user will try
-		 * anything like that so we just wait for the timeout. */
+		/* Do not allow suspend iff read/write to EB address */
+		if ((adr & chip->in_progress_block_mask) ==
+		    chip->in_progress_block_addr)
+			goto sleep;
 
 		/* Erase suspend */
 		/* It's harmless to issue the Erase-Suspend and Erase-Resume
@@ -1625,29 +1625,35 @@
 			continue;
 		}
 
-		if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
+		/*
+		 * We check "time_after" and "!chip_good" before checking
+		 * "chip_good" to avoid the failure due to scheduling.
+		 */
+		if (time_after(jiffies, timeo) && !chip_good(map, adr, datum)) {
 			xip_enable(map, chip, adr);
 			printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
 			xip_disable(map, chip, adr);
+			ret = -EIO;
 			break;
 		}
 
-		if (chip_ready(map, adr))
+		if (chip_good(map, adr, datum))
 			break;
 
 		/* Latency issues. Drop the lock, wait a while and retry */
 		UDELAY(map, chip, adr, 1);
 	}
+
 	/* Did we succeed? */
-	if (!chip_good(map, adr, datum)) {
+	if (ret) {
 		/* reset on all failures. */
 		map_write( map, CMD(0xF0), chip->start );
 		/* FIXME - should have reset delay before continuing */
 
-		if (++retry_cnt <= MAX_WORD_RETRIES)
+		if (++retry_cnt <= MAX_RETRIES) {
+			ret = 0;
 			goto retry;
-
-		ret = -EIO;
+		}
 	}
 	xip_enable(map, chip, adr);
  op_done:
@@ -1874,10 +1880,14 @@
 			continue;
 		}
 
-		if (time_after(jiffies, timeo) && !chip_ready(map, adr))
+		/*
+		 * We check "time_after" and "!chip_good" before checking "chip_good" to avoid
+		 * the failure due to scheduling.
+		 */
+		if (time_after(jiffies, timeo) && !chip_good(map, adr, datum))
 			break;
 
-		if (chip_ready(map, adr)) {
+		if (chip_good(map, adr, datum)) {
 			xip_enable(map, chip, adr);
 			goto op_done;
 		}
@@ -2103,7 +2113,7 @@
 		map_write(map, CMD(0xF0), chip->start);
 		/* FIXME - should have reset delay before continuing */
 
-		if (++retry_cnt <= MAX_WORD_RETRIES)
+		if (++retry_cnt <= MAX_RETRIES)
 			goto retry;
 
 		ret = -EIO;
@@ -2238,6 +2248,7 @@
 	unsigned long int adr;
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
+	int retry_cnt = 0;
 
 	adr = cfi->addr_unlock1;
 
@@ -2255,6 +2266,7 @@
 	ENABLE_VPP(map);
 	xip_disable(map, chip, adr);
 
+ retry:
 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -2265,6 +2277,7 @@
 	chip->state = FL_ERASING;
 	chip->erase_suspended = 0;
 	chip->in_progress_block_addr = adr;
+	chip->in_progress_block_mask = ~(map->size - 1);
 
 	INVALIDATE_CACHE_UDELAY(map, chip,
 				adr, map->size,
@@ -2290,12 +2303,13 @@
 			chip->erase_suspended = 0;
 		}
 
-		if (chip_ready(map, adr))
+		if (chip_good(map, adr, map_word_ff(map)))
 			break;
 
 		if (time_after(jiffies, timeo)) {
 			printk(KERN_WARNING "MTD %s(): software timeout\n",
 				__func__ );
+			ret = -EIO;
 			break;
 		}
 
@@ -2303,12 +2317,15 @@
 		UDELAY(map, chip, adr, 1000000/HZ);
 	}
 	/* Did we succeed? */
-	if (!chip_good(map, adr, map_word_ff(map))) {
+	if (ret) {
 		/* reset on all failures. */
 		map_write( map, CMD(0xF0), chip->start );
 		/* FIXME - should have reset delay before continuing */
 
-		ret = -EIO;
+		if (++retry_cnt <= MAX_RETRIES) {
+			ret = 0;
+			goto retry;
+		}
 	}
 
 	chip->state = FL_READY;
@@ -2327,6 +2344,7 @@
 	unsigned long timeo = jiffies + HZ;
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
+	int retry_cnt = 0;
 
 	adr += chip->start;
 
@@ -2344,6 +2362,7 @@
 	ENABLE_VPP(map);
 	xip_disable(map, chip, adr);
 
+ retry:
 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -2354,6 +2373,7 @@
 	chip->state = FL_ERASING;
 	chip->erase_suspended = 0;
 	chip->in_progress_block_addr = adr;
+	chip->in_progress_block_mask = ~(len - 1);
 
 	INVALIDATE_CACHE_UDELAY(map, chip,
 				adr, len,
@@ -2379,7 +2399,7 @@
 			chip->erase_suspended = 0;
 		}
 
-		if (chip_ready(map, adr)) {
+		if (chip_good(map, adr, map_word_ff(map))) {
 			xip_enable(map, chip, adr);
 			break;
 		}
@@ -2388,6 +2408,7 @@
 			xip_enable(map, chip, adr);
 			printk(KERN_WARNING "MTD %s(): software timeout\n",
 				__func__ );
+			ret = -EIO;
 			break;
 		}
 
@@ -2395,12 +2416,15 @@
 		UDELAY(map, chip, adr, 1000000/HZ);
 	}
 	/* Did we succeed? */
-	if (!chip_good(map, adr, map_word_ff(map))) {
+	if (ret) {
 		/* reset on all failures. */
 		map_write( map, CMD(0xF0), chip->start );
 		/* FIXME - should have reset delay before continuing */
 
-		ret = -EIO;
+		if (++retry_cnt <= MAX_RETRIES) {
+			ret = 0;
+			goto retry;
+		}
 	}
 
 	chip->state = FL_READY;
@@ -2530,7 +2554,7 @@
 
 struct ppb_lock {
 	struct flchip *chip;
-	loff_t offset;
+	unsigned long adr;
 	int locked;
 };
 
@@ -2548,8 +2572,9 @@
 	unsigned long timeo;
 	int ret;
 
+	adr += chip->start;
 	mutex_lock(&chip->mutex);
-	ret = get_chip(map, chip, adr + chip->start, FL_LOCKING);
+	ret = get_chip(map, chip, adr, FL_LOCKING);
 	if (ret) {
 		mutex_unlock(&chip->mutex);
 		return ret;
@@ -2567,8 +2592,8 @@
 
 	if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
 		chip->state = FL_LOCKING;
-		map_write(map, CMD(0xA0), chip->start + adr);
-		map_write(map, CMD(0x00), chip->start + adr);
+		map_write(map, CMD(0xA0), adr);
+		map_write(map, CMD(0x00), adr);
 	} else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
 		/*
 		 * Unlocking of one specific sector is not supported, so we
@@ -2606,7 +2631,7 @@
 	map_write(map, CMD(0x00), chip->start);
 
 	chip->state = FL_READY;
-	put_chip(map, chip, adr + chip->start);
+	put_chip(map, chip, adr);
 	mutex_unlock(&chip->mutex);
 
 	return ret;
@@ -2663,9 +2688,9 @@
 		 * sectors shall be unlocked, so lets keep their locking
 		 * status at "unlocked" (locked=0) for the final re-locking.
 		 */
-		if ((adr < ofs) || (adr >= (ofs + len))) {
+		if ((offset < ofs) || (offset >= (ofs + len))) {
 			sect[sectors].chip = &cfi->chips[chipnum];
-			sect[sectors].offset = offset;
+			sect[sectors].adr = adr;
 			sect[sectors].locked = do_ppb_xxlock(
 				map, &cfi->chips[chipnum], adr, 0,
 				DO_XXLOCK_ONEBLOCK_GETLOCK);
@@ -2679,6 +2704,8 @@
 			i++;
 
 		if (adr >> cfi->chipshift) {
+			if (offset >= (ofs + len))
+				break;
 			adr = 0;
 			chipnum++;
 
@@ -2709,7 +2736,7 @@
 	 */
 	for (i = 0; i < sectors; i++) {
 		if (sect[i].locked)
-			do_ppb_xxlock(map, sect[i].chip, sect[i].offset, 0,
+			do_ppb_xxlock(map, sect[i].chip, sect[i].adr, 0,
 				      DO_XXLOCK_ONEBLOCK_LOCK);
 	}
 
--- linux-4.4.0.orig/drivers/mtd/chips/jedec_probe.c
+++ linux-4.4.0/drivers/mtd/chips/jedec_probe.c
@@ -1889,6 +1889,8 @@
 	do {
 		uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi);
 		mask = (1 << (cfi->device_type * 8)) - 1;
+		if (ofs >= map->size)
+			return 0;
 		result = map_read(map, base + ofs);
 		bank++;
 	} while ((result.x[0] & mask) == CFI_MFR_CONTINUATION);
--- linux-4.4.0.orig/drivers/mtd/cmdlinepart.c
+++ linux-4.4.0/drivers/mtd/cmdlinepart.c
@@ -228,12 +228,41 @@
 		struct cmdline_mtd_partition *this_mtd;
 		struct mtd_partition *parts;
 		int mtd_id_len, num_parts;
-		char *p, *mtd_id;
+		char *p, *mtd_id, *semicol, *open_parenth;
+
+		/*
+		 * Replace the first ';' by a NULL char so strrchr can work
+		 * properly.
+		 */
+		semicol = strchr(s, ';');
+		if (semicol)
+			*semicol = '\0';
+
+		/*
+		 * make sure that part-names with ":" will not be handled as
+		 * part of the mtd-id with an ":"
+		 */
+		open_parenth = strchr(s, '(');
+		if (open_parenth)
+			*open_parenth = '\0';
 
 		mtd_id = s;
 
-		/* fetch <mtd-id> */
-		p = strchr(s, ':');
+		/*
+		 * fetch <mtd-id>. We use strrchr to ignore all ':' that could
+		 * be present in the MTD name, only the last one is interpreted
+		 * as an <mtd-id>/<part-definition> separator.
+		 */
+		p = strrchr(s, ':');
+
+		/* Restore the '(' now. */
+		if (open_parenth)
+			*open_parenth = '(';
+
+		/* Restore the ';' now. */
+		if (semicol)
+			*semicol = ';';
+
 		if (!p) {
 			pr_err("no mtd-id\n");
 			return -EINVAL;
--- linux-4.4.0.orig/drivers/mtd/devices/Kconfig
+++ linux-4.4.0/drivers/mtd/devices/Kconfig
@@ -208,7 +208,7 @@
 config MTD_DOCG3
 	tristate "M-Systems Disk-On-Chip G3"
 	select BCH
-	select BCH_CONST_PARAMS
+	select BCH_CONST_PARAMS if !MTD_NAND_BCH
 	select BITREVERSE
 	---help---
 	  This provides an MTD device driver for the M-Systems DiskOnChip
--- linux-4.4.0.orig/drivers/mtd/devices/phram.c
+++ linux-4.4.0/drivers/mtd/devices/phram.c
@@ -247,22 +247,25 @@
 
 	ret = parse_num64(&start, token[1]);
 	if (ret) {
-		kfree(name);
 		parse_err("illegal start address\n");
+		goto error;
 	}
 
 	ret = parse_num64(&len, token[2]);
 	if (ret) {
-		kfree(name);
 		parse_err("illegal device length\n");
+		goto error;
 	}
 
 	ret = register_device(name, start, len);
-	if (!ret)
-		pr_info("%s device: %#llx at %#llx\n", name, len, start);
-	else
-		kfree(name);
+	if (ret)
+		goto error;
 
+	pr_info("%s device: %#llx at %#llx\n", name, len, start);
+	return 0;
+
+error:
+	kfree(name);
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/mtd/devices/spear_smi.c
+++ linux-4.4.0/drivers/mtd/devices/spear_smi.c
@@ -595,6 +595,26 @@
 	return 0;
 }
 
+/*
+ * The purpose of this function is to ensure a memcpy_toio() with byte writes
+ * only. Its structure is inspired from the ARM implementation of _memcpy_toio()
+ * which also does single byte writes but cannot be used here as this is just an
+ * implementation detail and not part of the API. Not mentioning the comment
+ * stating that _memcpy_toio() should be optimized.
+ */
+static void spear_smi_memcpy_toio_b(volatile void __iomem *dest,
+				    const void *src, size_t len)
+{
+	const unsigned char *from = src;
+
+	while (len) {
+		len--;
+		writeb(*from, dest);
+		from++;
+		dest++;
+	}
+}
+
 static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
 		void __iomem *dest, const void *src, size_t len)
 {
@@ -617,7 +637,23 @@
 	ctrlreg1 = readl(dev->io_base + SMI_CR1);
 	writel((ctrlreg1 | WB_MODE) & ~SW_MODE, dev->io_base + SMI_CR1);
 
-	memcpy_toio(dest, src, len);
+	/*
+	 * In Write Burst mode (WB_MODE), the specs states that writes must be:
+	 * - incremental
+	 * - of the same size
+	 * The ARM implementation of memcpy_toio() will optimize the number of
+	 * I/O by using as much 4-byte writes as possible, surrounded by
+	 * 2-byte/1-byte access if:
+	 * - the destination is not 4-byte aligned
+	 * - the length is not a multiple of 4-byte.
+	 * Avoid this alternance of write access size by using our own 'byte
+	 * access' helper if at least one of the two conditions above is true.
+	 */
+	if (IS_ALIGNED(len, sizeof(u32)) &&
+	    IS_ALIGNED((uintptr_t)dest, sizeof(u32)))
+		memcpy_toio(dest, src, len);
+	else
+		spear_smi_memcpy_toio_b(dest, src, len);
 
 	writel(ctrlreg1, dev->io_base + SMI_CR1);
 
--- linux-4.4.0.orig/drivers/mtd/lpddr/lpddr2_nvm.c
+++ linux-4.4.0/drivers/mtd/lpddr/lpddr2_nvm.c
@@ -408,6 +408,17 @@
 	return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_LOCK);
 }
 
+static const struct mtd_info lpddr2_nvm_mtd_info = {
+	.type		= MTD_RAM,
+	.writesize	= 1,
+	.flags		= (MTD_CAP_NVRAM | MTD_POWERUP_LOCK),
+	._read		= lpddr2_nvm_read,
+	._write		= lpddr2_nvm_write,
+	._erase		= lpddr2_nvm_erase,
+	._unlock	= lpddr2_nvm_unlock,
+	._lock		= lpddr2_nvm_lock,
+};
+
 /*
  * lpddr2_nvm driver probe method
  */
@@ -448,6 +459,7 @@
 		.pfow_base	= OW_BASE_ADDRESS,
 		.fldrv_priv	= pcm_data,
 	};
+
 	if (IS_ERR(map->virt))
 		return PTR_ERR(map->virt);
 
@@ -459,22 +471,13 @@
 		return PTR_ERR(pcm_data->ctl_regs);
 
 	/* Populate mtd_info data structure */
-	*mtd = (struct mtd_info) {
-		.dev		= { .parent = &pdev->dev },
-		.name		= pdev->dev.init_name,
-		.type		= MTD_RAM,
-		.priv		= map,
-		.size		= resource_size(add_range),
-		.erasesize	= ERASE_BLOCKSIZE * pcm_data->bus_width,
-		.writesize	= 1,
-		.writebufsize	= WRITE_BUFFSIZE * pcm_data->bus_width,
-		.flags		= (MTD_CAP_NVRAM | MTD_POWERUP_LOCK),
-		._read		= lpddr2_nvm_read,
-		._write		= lpddr2_nvm_write,
-		._erase		= lpddr2_nvm_erase,
-		._unlock	= lpddr2_nvm_unlock,
-		._lock		= lpddr2_nvm_lock,
-	};
+	*mtd = lpddr2_nvm_mtd_info;
+	mtd->dev.parent		= &pdev->dev;
+	mtd->name		= pdev->dev.init_name;
+	mtd->priv		= map;
+	mtd->size		= resource_size(add_range);
+	mtd->erasesize		= ERASE_BLOCKSIZE * pcm_data->bus_width;
+	mtd->writebufsize	= WRITE_BUFFSIZE * pcm_data->bus_width;
 
 	/* Verify the presence of the device looking for PFOW string */
 	if (!lpddr2_nvm_pfow_present(map)) {
--- linux-4.4.0.orig/drivers/mtd/lpddr/lpddr_cmds.c
+++ linux-4.4.0/drivers/mtd/lpddr/lpddr_cmds.c
@@ -81,7 +81,6 @@
 	shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips,
 						GFP_KERNEL);
 	if (!shared) {
-		kfree(lpddr);
 		kfree(mtd);
 		return NULL;
 	}
--- linux-4.4.0.orig/drivers/mtd/maps/ck804xrom.c
+++ linux-4.4.0/drivers/mtd/maps/ck804xrom.c
@@ -112,8 +112,8 @@
 }
 
 
-static int ck804xrom_init_one(struct pci_dev *pdev,
-			      const struct pci_device_id *ent)
+static int __init ck804xrom_init_one(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
 {
 	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
 	u8 byte;
--- linux-4.4.0.orig/drivers/mtd/maps/esb2rom.c
+++ linux-4.4.0/drivers/mtd/maps/esb2rom.c
@@ -144,8 +144,8 @@
 	pci_dev_put(window->pdev);
 }
 
-static int esb2rom_init_one(struct pci_dev *pdev,
-			    const struct pci_device_id *ent)
+static int __init esb2rom_init_one(struct pci_dev *pdev,
+				   const struct pci_device_id *ent)
 {
 	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
 	struct esb2rom_window *window = &esb2rom_window;
--- linux-4.4.0.orig/drivers/mtd/maps/ichxrom.c
+++ linux-4.4.0/drivers/mtd/maps/ichxrom.c
@@ -57,10 +57,12 @@
 {
 	struct ichxrom_map_info *map, *scratch;
 	u16 word;
+	int ret;
 
 	/* Disable writes through the rom window */
-	pci_read_config_word(window->pdev, BIOS_CNTL, &word);
-	pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
+	ret = pci_read_config_word(window->pdev, BIOS_CNTL, &word);
+	if (!ret)
+		pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
 	pci_dev_put(window->pdev);
 
 	/* Free all of the mtd devices */
@@ -84,8 +86,8 @@
 }
 
 
-static int ichxrom_init_one(struct pci_dev *pdev,
-			    const struct pci_device_id *ent)
+static int __init ichxrom_init_one(struct pci_dev *pdev,
+				   const struct pci_device_id *ent)
 {
 	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
 	struct ichxrom_window *window = &ichxrom_window;
--- linux-4.4.0.orig/drivers/mtd/maps/physmap_of.c
+++ linux-4.4.0/drivers/mtd/maps/physmap_of.c
@@ -28,7 +28,6 @@
 struct of_flash_list {
 	struct mtd_info *mtd;
 	struct map_info map;
-	struct resource *res;
 };
 
 struct of_flash {
@@ -53,18 +52,10 @@
 			mtd_concat_destroy(info->cmtd);
 	}
 
-	for (i = 0; i < info->list_size; i++) {
+	for (i = 0; i < info->list_size; i++)
 		if (info->list[i].mtd)
 			map_destroy(info->list[i].mtd);
 
-		if (info->list[i].map.virt)
-			iounmap(info->list[i].map.virt);
-
-		if (info->list[i].res) {
-			release_resource(info->list[i].res);
-			kfree(info->list[i].res);
-		}
-	}
 	return 0;
 }
 
@@ -223,10 +214,11 @@
 
 		err = -EBUSY;
 		res_size = resource_size(&res);
-		info->list[i].res = request_mem_region(res.start, res_size,
-						       dev_name(&dev->dev));
-		if (!info->list[i].res)
+		info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res);
+		if (IS_ERR(info->list[i].map.virt)) {
+			err = PTR_ERR(info->list[i].map.virt);
 			goto err_out;
+		}
 
 		err = -ENXIO;
 		width = of_get_property(dp, "bank-width", NULL);
@@ -242,15 +234,6 @@
 		info->list[i].map.bankwidth = be32_to_cpup(width);
 		info->list[i].map.device_node = dp;
 
-		err = -ENOMEM;
-		info->list[i].map.virt = ioremap(info->list[i].map.phys,
-						 info->list[i].map.size);
-		if (!info->list[i].map.virt) {
-			dev_err(&dev->dev, "Failed to ioremap() flash"
-				" region\n");
-			goto err_out;
-		}
-
 		simple_map_init(&info->list[i].map);
 
 		/*
--- linux-4.4.0.orig/drivers/mtd/maps/pmcmsp-flash.c
+++ linux-4.4.0/drivers/mtd/maps/pmcmsp-flash.c
@@ -75,15 +75,15 @@
 
 	printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
 
-	msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL);
+	msp_flash = kcalloc(fcnt, sizeof(*msp_flash), GFP_KERNEL);
 	if (!msp_flash)
 		return -ENOMEM;
 
-	msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+	msp_parts = kcalloc(fcnt, sizeof(*msp_parts), GFP_KERNEL);
 	if (!msp_parts)
 		goto free_msp_flash;
 
-	msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL);
+	msp_maps = kcalloc(fcnt, sizeof(*msp_maps), GFP_KERNEL);
 	if (!msp_maps)
 		goto free_msp_parts;
 
@@ -139,15 +139,13 @@
 		}
 
 		msp_maps[i].bankwidth = 1;
-		msp_maps[i].name = kmalloc(7, GFP_KERNEL);
+		msp_maps[i].name = kstrndup(flash_name, 7, GFP_KERNEL);
 		if (!msp_maps[i].name) {
 			iounmap(msp_maps[i].virt);
 			kfree(msp_parts[i]);
 			goto cleanup_loop;
 		}
 
-		msp_maps[i].name = strncpy(msp_maps[i].name, flash_name, 7);
-
 		for (j = 0; j < pcnt; j++) {
 			part_name[5] = '0' + i;
 			part_name[7] = '0' + j;
--- linux-4.4.0.orig/drivers/mtd/maps/sa1100-flash.c
+++ linux-4.4.0/drivers/mtd/maps/sa1100-flash.c
@@ -230,8 +230,10 @@
 
 		info->mtd = mtd_concat_create(cdev, info->num_subdev,
 					      plat->name);
-		if (info->mtd == NULL)
+		if (info->mtd == NULL) {
 			ret = -ENXIO;
+			goto err;
+		}
 	}
 	info->mtd->dev.parent = &pdev->dev;
 
--- linux-4.4.0.orig/drivers/mtd/maps/solutionengine.c
+++ linux-4.4.0/drivers/mtd/maps/solutionengine.c
@@ -59,9 +59,9 @@
 			return -ENXIO;
 		}
 	}
-	printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n",
-	       soleng_flash_map.phys & 0x1fffffff,
-	       soleng_eprom_map.phys & 0x1fffffff);
+	printk(KERN_NOTICE "Solution Engine: Flash at 0x%pap, EPROM at 0x%pap\n",
+	       &soleng_flash_map.phys,
+	       &soleng_eprom_map.phys);
 	flash_mtd->owner = THIS_MODULE;
 
 	eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map);
--- linux-4.4.0.orig/drivers/mtd/mtd_blkdevs.c
+++ linux-4.4.0/drivers/mtd/mtd_blkdevs.c
@@ -510,7 +510,7 @@
 {
 	struct mtd_blktrans_ops *tr;
 
-	if (mtd->type == MTD_ABSENT)
+	if (mtd->type == MTD_ABSENT || mtd->type == MTD_UBIVOLUME)
 		return;
 
 	list_for_each_entry(tr, &blktrans_majors, list)
@@ -553,7 +553,7 @@
 	list_add(&tr->list, &blktrans_majors);
 
 	mtd_for_each_device(mtd)
-		if (mtd->type != MTD_ABSENT)
+		if (mtd->type != MTD_ABSENT && mtd->type != MTD_UBIVOLUME)
 			tr->add_mtd(tr, mtd);
 
 	mutex_unlock(&mtd_table_mutex);
--- linux-4.4.0.orig/drivers/mtd/mtdchar.c
+++ linux-4.4.0/drivers/mtd/mtdchar.c
@@ -160,8 +160,12 @@
 
 	pr_debug("MTD_read\n");
 
-	if (*ppos + count > mtd->size)
-		count = mtd->size - *ppos;
+	if (*ppos + count > mtd->size) {
+		if (*ppos < mtd->size)
+			count = mtd->size - *ppos;
+		else
+			count = 0;
+	}
 
 	if (!count)
 		return 0;
@@ -246,7 +250,7 @@
 
 	pr_debug("MTD_write\n");
 
-	if (*ppos == mtd->size)
+	if (*ppos >= mtd->size)
 		return -ENOSPC;
 
 	if (*ppos + count > mtd->size)
@@ -368,9 +372,6 @@
 	uint32_t retlen;
 	int ret = 0;
 
-	if (!(file->f_mode & FMODE_WRITE))
-		return -EPERM;
-
 	if (length > 4096)
 		return -EINVAL;
 
@@ -604,6 +605,48 @@
 			return -EFAULT;
 	}
 
+	/*
+	 * Check the file mode to require "dangerous" commands to have write
+	 * permissions.
+	 */
+	switch (cmd) {
+	/* "safe" commands */
+	case MEMGETREGIONCOUNT:
+	case MEMGETREGIONINFO:
+	case MEMGETINFO:
+	case MEMREADOOB:
+	case MEMREADOOB64:
+	case MEMISLOCKED:
+	case MEMGETOOBSEL:
+	case MEMGETBADBLOCK:
+	case OTPSELECT:
+	case OTPGETREGIONCOUNT:
+	case OTPGETREGIONINFO:
+	case ECCGETLAYOUT:
+	case ECCGETSTATS:
+	case MTDFILEMODE:
+	case BLKPG:
+	case BLKRRPART:
+		break;
+
+	/* "dangerous" commands */
+	case MEMERASE:
+	case MEMERASE64:
+	case MEMLOCK:
+	case MEMUNLOCK:
+	case MEMSETBADBLOCK:
+	case MEMWRITEOOB:
+	case MEMWRITEOOB64:
+	case MEMWRITE:
+	case OTPLOCK:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EPERM;
+		break;
+
+	default:
+		return -ENOTTY;
+	}
+
 	switch (cmd) {
 	case MEMGETREGIONCOUNT:
 		if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
@@ -651,9 +694,6 @@
 	{
 		struct erase_info *erase;
 
-		if(!(file->f_mode & FMODE_WRITE))
-			return -EPERM;
-
 		erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);
 		if (!erase)
 			ret = -ENOMEM;
@@ -978,9 +1018,6 @@
 		ret = 0;
 		break;
 	}
-
-	default:
-		ret = -ENOTTY;
 	}
 
 	return ret;
@@ -1024,6 +1061,11 @@
 		struct mtd_oob_buf32 buf;
 		struct mtd_oob_buf32 __user *buf_user = argp;
 
+		if (!(file->f_mode & FMODE_WRITE)) {
+			ret = -EPERM;
+			break;
+		}
+
 		if (copy_from_user(&buf, argp, sizeof(buf)))
 			ret = -EFAULT;
 		else
--- linux-4.4.0.orig/drivers/mtd/mtdcore.h
+++ linux-4.4.0/drivers/mtd/mtdcore.h
@@ -6,7 +6,7 @@
 extern struct mutex mtd_table_mutex;
 
 struct mtd_info *__mtd_next_device(int i);
-int add_mtd_device(struct mtd_info *mtd);
+int __must_check add_mtd_device(struct mtd_info *mtd);
 int del_mtd_device(struct mtd_info *mtd);
 int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
 int del_mtd_partitions(struct mtd_info *);
--- linux-4.4.0.orig/drivers/mtd/mtdoops.c
+++ linux-4.4.0/drivers/mtd/mtdoops.c
@@ -313,12 +313,13 @@
 	kmsg_dump_get_buffer(dumper, true, cxt->oops_buf + MTDOOPS_HEADER_SIZE,
 			     record_size - MTDOOPS_HEADER_SIZE, NULL);
 
-	/* Panics must be written immediately */
-	if (reason != KMSG_DUMP_OOPS)
+	if (reason != KMSG_DUMP_OOPS) {
+		/* Panics must be written immediately */
 		mtdoops_write(cxt, 1);
-
-	/* For other cases, schedule work to write it "nicely" */
-	schedule_work(&cxt->work_write);
+	} else {
+		/* For other cases, schedule work to write it "nicely" */
+		schedule_work(&cxt->work_write);
+	}
 }
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
--- linux-4.4.0.orig/drivers/mtd/mtdpart.c
+++ linux-4.4.0/drivers/mtd/mtdpart.c
@@ -610,10 +610,21 @@
 	list_add(&new->list, &mtd_partitions);
 	mutex_unlock(&mtd_partitions_mutex);
 
-	add_mtd_device(&new->mtd);
+	ret = add_mtd_device(&new->mtd);
+	if (ret)
+		goto err_remove_part;
 
 	mtd_add_partition_attrs(new);
 
+	return 0;
+
+err_remove_part:
+	mutex_lock(&mtd_partitions_mutex);
+	list_del(&new->list);
+	mutex_unlock(&mtd_partitions_mutex);
+
+	free_partition(new);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(mtd_add_partition);
@@ -658,28 +669,42 @@
 {
 	struct mtd_part *slave;
 	uint64_t cur_offset = 0;
-	int i;
+	int i, ret;
 
 	printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
 
 	for (i = 0; i < nbparts; i++) {
 		slave = allocate_partition(master, parts + i, i, cur_offset);
 		if (IS_ERR(slave)) {
-			del_mtd_partitions(master);
-			return PTR_ERR(slave);
+			ret = PTR_ERR(slave);
+			goto err_del_partitions;
 		}
 
 		mutex_lock(&mtd_partitions_mutex);
 		list_add(&slave->list, &mtd_partitions);
 		mutex_unlock(&mtd_partitions_mutex);
 
-		add_mtd_device(&slave->mtd);
+		ret = add_mtd_device(&slave->mtd);
+		if (ret) {
+			mutex_lock(&mtd_partitions_mutex);
+			list_del(&slave->list);
+			mutex_unlock(&mtd_partitions_mutex);
+
+			free_partition(slave);
+			goto err_del_partitions;
+		}
+
 		mtd_add_partition_attrs(slave);
 
 		cur_offset = slave->offset + slave->mtd.size;
 	}
 
 	return 0;
+
+err_del_partitions:
+	del_mtd_partitions(master);
+
+	return ret;
 }
 
 static DEFINE_SPINLOCK(part_parser_lock);
--- linux-4.4.0.orig/drivers/mtd/mtdsuper.c
+++ linux-4.4.0/drivers/mtd/mtdsuper.c
@@ -125,6 +125,7 @@
 #ifdef CONFIG_BLOCK
 	struct block_device *bdev;
 	int ret, major;
+	int perm;
 #endif
 	int mtdnr;
 
@@ -176,7 +177,10 @@
 	/* try the old way - the hack where we allowed users to mount
 	 * /dev/mtdblock$(n) but didn't actually _use_ the blockdev
 	 */
-	bdev = lookup_bdev(dev_name);
+	perm = MAY_READ;
+	if (!(flags & MS_RDONLY))
+		perm |= MAY_WRITE;
+	bdev = lookup_bdev(dev_name, perm);
 	if (IS_ERR(bdev)) {
 		ret = PTR_ERR(bdev);
 		pr_debug("MTDSB: lookup_bdev() returned %d\n", ret);
--- linux-4.4.0.orig/drivers/mtd/nand/Kconfig
+++ linux-4.4.0/drivers/mtd/nand/Kconfig
@@ -527,7 +527,7 @@
 	  Flexible Static Memory Controller (FSMC)
 
 config MTD_NAND_XWAY
-	tristate "Support for NAND on Lantiq XWAY SoC"
+	bool "Support for NAND on Lantiq XWAY SoC"
 	depends on LANTIQ && SOC_TYPE_XWAY
 	select MTD_NAND_PLATFORM
 	help
--- linux-4.4.0.orig/drivers/mtd/nand/brcmnand/brcmnand.c
+++ linux-4.4.0/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -309,6 +309,36 @@
 	[BRCMNAND_FC_BASE]		= 0x400,
 };
 
+/* BRCMNAND v7.1 */
+static const u16 brcmnand_regs_v71[] = {
+	[BRCMNAND_CMD_START]		=  0x04,
+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+	[BRCMNAND_INTFC_STATUS]		=  0x14,
+	[BRCMNAND_CS_SELECT]		=  0x18,
+	[BRCMNAND_CS_XOR]		=  0x1c,
+	[BRCMNAND_LL_OP]		=  0x20,
+	[BRCMNAND_CS0_BASE]		=  0x50,
+	[BRCMNAND_CS1_BASE]		=     0,
+	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
+	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
+	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
+	[BRCMNAND_CORR_COUNT]		= 0x100,
+	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
+	[BRCMNAND_CORR_ADDR]		= 0x110,
+	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
+	[BRCMNAND_UNCORR_ADDR]		= 0x118,
+	[BRCMNAND_SEMAPHORE]		= 0x150,
+	[BRCMNAND_ID]			= 0x194,
+	[BRCMNAND_ID_EXT]		= 0x198,
+	[BRCMNAND_LL_RDATA]		= 0x19c,
+	[BRCMNAND_OOB_READ_BASE]	= 0x200,
+	[BRCMNAND_OOB_READ_10_BASE]	=     0,
+	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+	[BRCMNAND_FC_BASE]		= 0x400,
+};
+
 enum brcmnand_cs_reg {
 	BRCMNAND_CS_CFG_EXT = 0,
 	BRCMNAND_CS_CFG,
@@ -404,7 +434,9 @@
 	}
 
 	/* Register offsets */
-	if (ctrl->nand_version >= 0x0600)
+	if (ctrl->nand_version >= 0x0701)
+		ctrl->reg_offsets = brcmnand_regs_v71;
+	else if (ctrl->nand_version >= 0x0600)
 		ctrl->reg_offsets = brcmnand_regs_v60;
 	else if (ctrl->nand_version >= 0x0500)
 		ctrl->reg_offsets = brcmnand_regs_v50;
@@ -423,8 +455,9 @@
 	} else {
 		ctrl->cs_offsets = brcmnand_cs_offsets;
 
-		/* v5.0 and earlier has a different CS0 offset layout */
-		if (ctrl->nand_version <= 0x0500)
+		/* v3.3-5.0 have a different CS0 offset layout */
+		if (ctrl->nand_version >= 0x0303 &&
+		    ctrl->nand_version <= 0x0500)
 			ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
 	}
 
@@ -1890,16 +1923,9 @@
 	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
 	tmp &= ~ACC_CONTROL_RD_ERASED;
 	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
-	if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
-		/*
-		 * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
-		 * errors
-		 */
-		if (has_flash_dma(ctrl))
-			tmp &= ~ACC_CONTROL_PREFETCH;
-		else
-			tmp |= ACC_CONTROL_PREFETCH;
-	}
+	if (ctrl->features & BRCMNAND_HAS_PREFETCH)
+		tmp &= ~ACC_CONTROL_PREFETCH;
+
 	nand_writereg(ctrl, offs, tmp);
 
 	return 0;
--- linux-4.4.0.orig/drivers/mtd/nand/davinci_nand.c
+++ linux-4.4.0/drivers/mtd/nand/davinci_nand.c
@@ -241,6 +241,9 @@
 	unsigned long flags;
 	u32 val;
 
+	/* Reset ECC hardware */
+	davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
+
 	spin_lock_irqsave(&davinci_nand_lock, flags);
 
 	/* Start 4-bit ECC calculation for read/write */
--- linux-4.4.0.orig/drivers/mtd/nand/denali.c
+++ linux-4.4.0/drivers/mtd/nand/denali.c
@@ -1622,9 +1622,16 @@
 /* driver exit point */
 void denali_remove(struct denali_nand_info *denali)
 {
+	/*
+	 * Pre-compute DMA buffer size to avoid any problems in case
+	 * nand_release() ever changes in a way that mtd->writesize and
+	 * mtd->oobsize are not reliable after this call.
+	 */
+	int bufsize = denali->mtd.writesize + denali->mtd.oobsize;
+
+	nand_release(&denali->mtd);
 	denali_irq_cleanup(denali->irq, denali);
-	dma_unmap_single(denali->dev, denali->buf.dma_buf,
-			 denali->mtd.writesize + denali->mtd.oobsize,
+	dma_unmap_single(denali->dev, denali->buf.dma_buf, bufsize,
 			 DMA_BIDIRECTIONAL);
 }
 EXPORT_SYMBOL(denali_remove);
--- linux-4.4.0.orig/drivers/mtd/nand/denali_pci.c
+++ linux-4.4.0/drivers/mtd/nand/denali_pci.c
@@ -119,3 +119,7 @@
 };
 
 module_pci_driver(denali_pci_driver);
+
+MODULE_DESCRIPTION("PCI driver for Denali NAND controller");
+MODULE_AUTHOR("Intel Corporation and its suppliers");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/mtd/nand/fsl_ifc_nand.c
+++ linux-4.4.0/drivers/mtd/nand/fsl_ifc_nand.c
@@ -449,9 +449,16 @@
 
 	case NAND_CMD_READID:
 	case NAND_CMD_PARAM: {
+		/*
+		 * For READID, read 8 bytes that are currently used.
+		 * For PARAM, read all 3 copies of 256-bytes pages.
+		 */
+		int len = 8;
 		int timing = IFC_FIR_OP_RB;
-		if (command == NAND_CMD_PARAM)
+		if (command == NAND_CMD_PARAM) {
 			timing = IFC_FIR_OP_RBCD;
+			len = 256 * 3;
+		}
 
 		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
 			  (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
@@ -461,12 +468,8 @@
 			  &ifc->ifc_nand.nand_fcr0);
 		ifc_out32(column, &ifc->ifc_nand.row3);
 
-		/*
-		 * although currently it's 8 bytes for READID, we always read
-		 * the maximum 256 bytes(for PARAM)
-		 */
-		ifc_out32(256, &ifc->ifc_nand.nand_fbcr);
-		ifc_nand_ctrl->read_bytes = 256;
+		ifc_out32(len, &ifc->ifc_nand.nand_fbcr);
+		ifc_nand_ctrl->read_bytes = len;
 
 		set_addr(mtd, 0, 0, 0);
 		fsl_ifc_run_command(mtd);
@@ -726,6 +729,7 @@
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
 	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
 	u32 nand_fsr;
+	int status;
 
 	/* Use READ_STATUS command, but wait for the device to be ready */
 	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
@@ -740,12 +744,12 @@
 	fsl_ifc_run_command(mtd);
 
 	nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr);
-
+	status = nand_fsr >> 24;
 	/*
 	 * The chip always seems to report that it is
 	 * write-protected, even when it is not.
 	 */
-	return nand_fsr | NAND_STATUS_WP;
+	return status | NAND_STATUS_WP;
 }
 
 static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
--- linux-4.4.0.orig/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ linux-4.4.0/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -168,9 +168,10 @@
 
 	/*
 	 * Reset BCH here, too. We got failures otherwise :(
-	 * See later BCH reset for explanation of MX23 handling
+	 * See later BCH reset for explanation of MX23 and MX28 handling
 	 */
-	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+	ret = gpmi_reset_block(r->bch_regs,
+			       GPMI_IS_MX23(this) || GPMI_IS_MX28(this));
 	if (ret)
 		goto err_out;
 
@@ -274,13 +275,11 @@
 
 	/*
 	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
-	* chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
-	* On the other hand, the MX28 needs the reset, because one case has been
-	* seen where the BCH produced ECC errors constantly after 10000
-	* consecutive reboots. The latter case has not been seen on the MX23
-	* yet, still we don't know if it could happen there as well.
+	* chip, otherwise it will lock up. So we skip resetting BCH on the MX23
+	* and MX28.
 	*/
-	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+	ret = gpmi_reset_block(r->bch_regs,
+			       GPMI_IS_MX23(this) || GPMI_IS_MX28(this));
 	if (ret)
 		goto err_out;
 
--- linux-4.4.0.orig/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ linux-4.4.0/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1029,24 +1029,97 @@
 		return ret;
 	}
 
-	/* handle the block mark swapping */
-	block_mark_swapping(this, payload_virt, auxiliary_virt);
-
 	/* Loop over status bytes, accumulating ECC status. */
 	status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
 
+	read_page_swap_end(this, buf, nfc_geo->payload_size,
+			   this->payload_virt, this->payload_phys,
+			   nfc_geo->payload_size,
+			   payload_virt, payload_phys);
+
 	for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
 		if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
 			continue;
 
 		if (*status == STATUS_UNCORRECTABLE) {
+			int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+			u8 *eccbuf = this->raw_buffer;
+			int offset, bitoffset;
+			int eccbytes;
+			int flips;
+
+			/* Read ECC bytes into our internal raw_buffer */
+			offset = nfc_geo->metadata_size * 8;
+			offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
+			offset -= eccbits;
+			bitoffset = offset % 8;
+			eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
+			offset /= 8;
+			eccbytes -= offset;
+			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+			chip->read_buf(mtd, eccbuf, eccbytes);
+
+			/*
+			 * ECC data are not byte aligned and we may have
+			 * in-band data in the first and last byte of
+			 * eccbuf. Set non-eccbits to one so that
+			 * nand_check_erased_ecc_chunk() does not count them
+			 * as bitflips.
+			 */
+			if (bitoffset)
+				eccbuf[0] |= GENMASK(bitoffset - 1, 0);
+
+			bitoffset = (bitoffset + eccbits) % 8;
+			if (bitoffset)
+				eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
+
+			/*
+			 * The ECC hardware has an uncorrectable ECC status
+			 * code in case we have bitflips in an erased page. As
+			 * nothing was written into this subpage the ECC is
+			 * obviously wrong and we can not trust it. We assume
+			 * at this point that we are reading an erased page and
+			 * try to correct the bitflips in buffer up to
+			 * ecc_strength bitflips. If this is a page with random
+			 * data, we exceed this number of bitflips and have a
+			 * ECC failure. Otherwise we use the corrected buffer.
+			 */
+			if (i == 0) {
+				/* The first block includes metadata */
+				flips = nand_check_erased_ecc_chunk(
+						buf + i * nfc_geo->ecc_chunk_size,
+						nfc_geo->ecc_chunk_size,
+						eccbuf, eccbytes,
+						auxiliary_virt,
+						nfc_geo->metadata_size,
+						nfc_geo->ecc_strength);
+			} else {
+				flips = nand_check_erased_ecc_chunk(
+						buf + i * nfc_geo->ecc_chunk_size,
+						nfc_geo->ecc_chunk_size,
+						eccbuf, eccbytes,
+						NULL, 0,
+						nfc_geo->ecc_strength);
+			}
+
+			if (flips > 0) {
+				max_bitflips = max_t(unsigned int, max_bitflips,
+						     flips);
+				mtd->ecc_stats.corrected += flips;
+				continue;
+			}
+
 			mtd->ecc_stats.failed++;
 			continue;
 		}
+
 		mtd->ecc_stats.corrected += *status;
 		max_bitflips = max_t(unsigned int, max_bitflips, *status);
 	}
 
+	/* handle the block mark swapping */
+	block_mark_swapping(this, buf, auxiliary_virt);
+
 	if (oob_required) {
 		/*
 		 * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob()
@@ -1062,11 +1135,6 @@
 		chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
 	}
 
-	read_page_swap_end(this, buf, nfc_geo->payload_size,
-			this->payload_virt, this->payload_phys,
-			nfc_geo->payload_size,
-			payload_virt, payload_phys);
-
 	return max_bitflips;
 }
 
--- linux-4.4.0.orig/drivers/mtd/nand/mxc_nand.c
+++ linux-4.4.0/drivers/mtd/nand/mxc_nand.c
@@ -49,7 +49,7 @@
 #define NFC_V1_V2_CONFIG		(host->regs + 0x0a)
 #define NFC_V1_V2_ECC_STATUS_RESULT	(host->regs + 0x0c)
 #define NFC_V1_V2_RSLTMAIN_AREA		(host->regs + 0x0e)
-#define NFC_V1_V2_RSLTSPARE_AREA	(host->regs + 0x10)
+#define NFC_V21_RSLTSPARE_AREA		(host->regs + 0x10)
 #define NFC_V1_V2_WRPROT		(host->regs + 0x12)
 #define NFC_V1_UNLOCKSTART_BLKADDR	(host->regs + 0x14)
 #define NFC_V1_UNLOCKEND_BLKADDR	(host->regs + 0x16)
@@ -1034,6 +1034,9 @@
 	writew(config1, NFC_V1_V2_CONFIG1);
 	/* preset operation */
 
+	/* spare area size in 16-bit half-words */
+	writew(mtd->oobsize / 2, NFC_V21_RSLTSPARE_AREA);
+
 	/* Unlock the internal RAM Buffer */
 	writew(0x2, NFC_V1_V2_CONFIG);
 
--- linux-4.4.0.orig/drivers/mtd/nand/nand_base.c
+++ linux-4.4.0/drivers/mtd/nand/nand_base.c
@@ -626,7 +626,8 @@
 		chip->cmd_ctrl(mtd, readcmd, ctrl);
 		ctrl &= ~NAND_CTRL_CHANGE;
 	}
-	chip->cmd_ctrl(mtd, command, ctrl);
+	if (command != NAND_CMD_NONE)
+		chip->cmd_ctrl(mtd, command, ctrl);
 
 	/* Address cycle, when necessary */
 	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
@@ -655,6 +656,7 @@
 	 */
 	switch (command) {
 
+	case NAND_CMD_NONE:
 	case NAND_CMD_PAGEPROG:
 	case NAND_CMD_ERASE1:
 	case NAND_CMD_ERASE2:
@@ -717,7 +719,9 @@
 	}
 
 	/* Command latch cycle */
-	chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+	if (command != NAND_CMD_NONE)
+		chip->cmd_ctrl(mtd, command,
+			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
 
 	if (column != -1 || page_addr != -1) {
 		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
@@ -750,6 +754,7 @@
 	 */
 	switch (command) {
 
+	case NAND_CMD_NONE:
 	case NAND_CMD_CACHEDPROG:
 	case NAND_CMD_PAGEPROG:
 	case NAND_CMD_ERASE1:
@@ -2023,6 +2028,7 @@
 static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 			    struct mtd_oob_ops *ops)
 {
+	unsigned int max_bitflips = 0;
 	int page, realpage, chipnr;
 	struct nand_chip *chip = mtd->priv;
 	struct mtd_ecc_stats stats;
@@ -2083,6 +2089,8 @@
 				nand_wait_ready(mtd);
 		}
 
+		max_bitflips = max_t(unsigned int, max_bitflips, ret);
+
 		readlen -= len;
 		if (!readlen)
 			break;
@@ -2108,7 +2116,7 @@
 	if (mtd->ecc_stats.failed - stats.failed)
 		return -EBADMSG;
 
-	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+	return max_bitflips;
 }
 
 /**
@@ -2586,7 +2594,7 @@
 		int cached = writelen > bytes && page != blockmask;
 		uint8_t *wbuf = buf;
 		int use_bufpoi;
-		int part_pagewr = (column || writelen < (mtd->writesize - 1));
+		int part_pagewr = (column || writelen < mtd->writesize);
 
 		if (part_pagewr)
 			use_bufpoi = 1;
@@ -2663,15 +2671,18 @@
 			    size_t *retlen, const uint8_t *buf)
 {
 	struct nand_chip *chip = mtd->priv;
+	int chipnr = (int)(to >> chip->chip_shift);
 	struct mtd_oob_ops ops;
 	int ret;
 
-	/* Wait for the device to get ready */
-	panic_nand_wait(mtd, chip, 400);
-
 	/* Grab the device */
 	panic_nand_get_device(chip, mtd, FL_WRITING);
 
+	chip->select_chip(mtd, chipnr);
+
+	/* Wait for the device to get ready */
+	panic_nand_wait(mtd, chip, 400);
+
 	memset(&ops, 0, sizeof(ops));
 	ops.len = len;
 	ops.datbuf = (uint8_t *)buf;
@@ -3979,7 +3990,6 @@
  * This is the first phase of the normal nand_scan() function. It reads the
  * flash ID and sets up MTD fields accordingly.
  *
- * The mtd->owner field must be set to the module of the caller.
  */
 int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 		    struct nand_flash_dev *table)
@@ -3995,6 +4005,9 @@
 			return ret;
 	}
 
+	if (!mtd->name && mtd->dev.parent)
+		mtd->name = dev_name(mtd->dev.parent);
+
 	/* Set the default functions */
 	nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
 
@@ -4400,19 +4413,12 @@
  *
  * This fills out all the uninitialized function pointers with the defaults.
  * The flash ID is read and the mtd/chip structures are filled with the
- * appropriate values. The mtd->owner field must be set to the module of the
- * caller.
+ * appropriate values.
  */
 int nand_scan(struct mtd_info *mtd, int maxchips)
 {
 	int ret;
 
-	/* Many callers got this wrong, so check for it for a while... */
-	if (!mtd->owner && caller_is_module()) {
-		pr_crit("%s called with NULL mtd->owner!\n", __func__);
-		BUG();
-	}
-
 	ret = nand_scan_ident(mtd, maxchips, NULL);
 	if (!ret)
 		ret = nand_scan_tail(mtd);
@@ -4421,18 +4427,14 @@
 EXPORT_SYMBOL(nand_scan);
 
 /**
- * nand_release - [NAND Interface] Free resources held by the NAND device
- * @mtd: MTD device structure
+ * nand_cleanup - [NAND Interface] Free resources held by the NAND device
+ * @chip: NAND chip object
  */
-void nand_release(struct mtd_info *mtd)
+void nand_cleanup(struct nand_chip *chip)
 {
-	struct nand_chip *chip = mtd->priv;
-
 	if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
 		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
 
-	mtd_device_unregister(mtd);
-
 	/* Free bad block table memory */
 	kfree(chip->bbt);
 	if (!(chip->options & NAND_OWN_BUFFERS))
@@ -4443,6 +4445,18 @@
 			& NAND_BBT_DYNAMICSTRUCT)
 		kfree(chip->badblock_pattern);
 }
+EXPORT_SYMBOL_GPL(nand_cleanup);
+
+/**
+ * nand_release - [NAND Interface] Unregister the MTD device and free resources
+ *		  held by the NAND device
+ * @mtd: MTD device structure
+ */
+void nand_release(struct mtd_info *mtd)
+{
+	mtd_device_unregister(mtd);
+	nand_cleanup(mtd->priv);
+}
 EXPORT_SYMBOL_GPL(nand_release);
 
 static int __init nand_base_init(void)
--- linux-4.4.0.orig/drivers/mtd/nand/omap_elm.c
+++ linux-4.4.0/drivers/mtd/nand/omap_elm.c
@@ -421,6 +421,7 @@
 	pm_runtime_enable(&pdev->dev);
 	if (pm_runtime_get_sync(&pdev->dev) < 0) {
 		ret = -EINVAL;
+		pm_runtime_put_sync(&pdev->dev);
 		pm_runtime_disable(&pdev->dev);
 		dev_err(&pdev->dev, "can't enable clock\n");
 		return ret;
--- linux-4.4.0.orig/drivers/mtd/nand/sh_flctl.c
+++ linux-4.4.0/drivers/mtd/nand/sh_flctl.c
@@ -160,7 +160,7 @@
 
 	memset(&cfg, 0, sizeof(cfg));
 	cfg.direction = DMA_MEM_TO_DEV;
-	cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl);
+	cfg.dst_addr = flctl->fifo;
 	cfg.src_addr = 0;
 	ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
 	if (ret < 0)
@@ -176,7 +176,7 @@
 
 	cfg.direction = DMA_DEV_TO_MEM;
 	cfg.dst_addr = 0;
-	cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl);
+	cfg.src_addr = flctl->fifo;
 	ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
 	if (ret < 0)
 		goto err;
@@ -428,7 +428,7 @@
 
 	/* initiate DMA transfer */
 	if (flctl->chan_fifo0_rx && rlen >= 32 &&
-		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0)
 			goto convert;	/* DMA success */
 
 	/* do polling transfer */
@@ -487,7 +487,7 @@
 
 	/* initiate DMA transfer */
 	if (flctl->chan_fifo0_tx && rlen >= 32 &&
-		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0)
 			return;	/* DMA success */
 
 	/* do polling transfer */
@@ -1096,6 +1096,7 @@
 	flctl->reg = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(flctl->reg))
 		return PTR_ERR(flctl->reg);
+	flctl->fifo = res->start + 0x24; /* FLDTFIFO */
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
--- linux-4.4.0.orig/drivers/mtd/nand/sunxi_nand.c
+++ linux-4.4.0/drivers/mtd/nand/sunxi_nand.c
@@ -1046,8 +1046,14 @@
 
 	/* Add ECC info retrieval from DT */
 	for (i = 0; i < ARRAY_SIZE(strengths); i++) {
-		if (ecc->strength <= strengths[i])
+		if (ecc->strength <= strengths[i]) {
+			/*
+			 * Update ecc->strength value with the actual strength
+			 * that will be used by the ECC engine.
+			 */
+			ecc->strength = strengths[i];
 			break;
+		}
 	}
 
 	if (i >= ARRAY_SIZE(strengths)) {
--- linux-4.4.0.orig/drivers/mtd/onenand/onenand_base.c
+++ linux-4.4.0/drivers/mtd/onenand/onenand_base.c
@@ -2599,6 +2599,7 @@
  */
 static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
+	struct onenand_chip *this = mtd->priv;
 	int ret;
 
 	ret = onenand_block_isbad(mtd, ofs);
@@ -2610,7 +2611,7 @@
 	}
 
 	onenand_get_device(mtd, FL_WRITING);
-	ret = mtd_block_markbad(mtd, ofs);
+	ret = this->block_markbad(mtd, ofs);
 	onenand_release_device(mtd);
 	return ret;
 }
--- linux-4.4.0.orig/drivers/mtd/spi-nor/spi-nor.c
+++ linux-4.4.0/drivers/mtd/spi-nor/spi-nor.c
@@ -708,6 +708,12 @@
 
 	/* ISSI */
 	{ "is25cd512", INFO(0x7f9d20, 0, 32 * 1024,   2, SECT_4K) },
+	{ "is25wp032", INFO(0x9d7016, 0, 64 * 1024,  64,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 
 	/* Macronix */
 	{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
@@ -1057,6 +1063,13 @@
 		return -EINVAL;
 	}
 
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret) {
+		dev_err(nor->dev,
+			"timeout while writing configuration register\n");
+		return ret;
+	}
+
 	/* read back and check it */
 	ret = read_cr(nor);
 	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
@@ -1067,45 +1080,6 @@
 	return 0;
 }
 
-static int micron_quad_enable(struct spi_nor *nor)
-{
-	int ret;
-	u8 val;
-
-	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
-	if (ret < 0) {
-		dev_err(nor->dev, "error %d reading EVCR\n", ret);
-		return ret;
-	}
-
-	write_enable(nor);
-
-	/* set EVCR, enable quad I/O */
-	nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
-	ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
-	if (ret < 0) {
-		dev_err(nor->dev, "error while writing EVCR register\n");
-		return ret;
-	}
-
-	ret = spi_nor_wait_till_ready(nor);
-	if (ret)
-		return ret;
-
-	/* read EVCR and check it */
-	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
-	if (ret < 0) {
-		dev_err(nor->dev, "error %d reading EVCR\n", ret);
-		return ret;
-	}
-	if (val & EVCR_QUAD_EN_MICRON) {
-		dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 {
 	int status;
@@ -1119,12 +1093,7 @@
 		}
 		return status;
 	case SNOR_MFR_MICRON:
-		status = micron_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Micron quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
+		return 0;
 	default:
 		status = spansion_quad_enable(nor);
 		if (status) {
--- linux-4.4.0.orig/drivers/mtd/ubi/attach.c
+++ linux-4.4.0/drivers/mtd/ubi/attach.c
@@ -175,6 +175,40 @@
 }
 
 /**
+ * add_fastmap - add a Fastmap related physical eraseblock.
+ * @ai: attaching information
+ * @pnum: physical eraseblock number the VID header came from
+ * @vid_hdr: the volume identifier header
+ * @ec: erase counter of the physical eraseblock
+ *
+ * This function allocates a 'struct ubi_ainf_peb' object for a Fastamp
+ * physical eraseblock @pnum and adds it to the 'fastmap' list.
+ * Such blocks can be Fastmap super and data blocks from both the most
+ * recent Fastmap we're attaching from or from old Fastmaps which will
+ * be erased.
+ */
+static int add_fastmap(struct ubi_attach_info *ai, int pnum,
+		       struct ubi_vid_hdr *vid_hdr, int ec)
+{
+	struct ubi_ainf_peb *aeb;
+
+	aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+	if (!aeb)
+		return -ENOMEM;
+
+	aeb->pnum = pnum;
+	aeb->vol_id = be32_to_cpu(vidh->vol_id);
+	aeb->sqnum = be64_to_cpu(vidh->sqnum);
+	aeb->ec = ec;
+	list_add(&aeb->u.list, &ai->fastmap);
+
+	dbg_bld("add to fastmap list: PEB %d, vol_id %d, sqnum: %llu", pnum,
+		aeb->vol_id, aeb->sqnum);
+
+	return 0;
+}
+
+/**
  * validate_vid_hdr - check volume identifier header.
  * @ubi: UBI device description object
  * @vid_hdr: the volume identifier header to check
@@ -803,13 +837,26 @@
 	return err;
 }
 
+static bool vol_ignored(int vol_id)
+{
+	switch (vol_id) {
+		case UBI_LAYOUT_VOLUME_ID:
+		return true;
+	}
+
+#ifdef CONFIG_MTD_UBI_FASTMAP
+	return ubi_is_fm_vol(vol_id);
+#else
+	return false;
+#endif
+}
+
 /**
  * scan_peb - scan and process UBI headers of a PEB.
  * @ubi: UBI device description object
  * @ai: attaching information
  * @pnum: the physical eraseblock number
- * @vid: The volume ID of the found volume will be stored in this pointer
- * @sqnum: The sqnum of the found volume will be stored in this pointer
+ * @fast: true if we're scanning for a Fastmap
  *
  * This function reads UBI headers of PEB @pnum, checks them, and adds
  * information about this PEB to the corresponding list or RB-tree in the
@@ -817,9 +864,9 @@
  * successfully handled and a negative error code in case of failure.
  */
 static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
-		    int pnum, int *vid, unsigned long long *sqnum)
+		    int pnum, bool fast)
 {
-	long long uninitialized_var(ec);
+	long long ec;
 	int err, bitflips = 0, vol_id = -1, ec_err = 0;
 
 	dbg_bld("scan PEB %d", pnum);
@@ -935,6 +982,20 @@
 			 */
 			ai->maybe_bad_peb_count += 1;
 	case UBI_IO_BAD_HDR:
+			/*
+			 * If we're facing a bad VID header we have to drop *all*
+			 * Fastmap data structures we find. The most recent Fastmap
+			 * could be bad and therefore there is a chance that we attach
+			 * from an old one. On a fine MTD stack a PEB must not render
+			 * bad all of a sudden, but the reality is different.
+			 * So, let's be paranoid and help finding the root cause by
+			 * falling back to scanning mode instead of attaching with a
+			 * bad EBA table and cause data corruption which is hard to
+			 * analyze.
+			 */
+			if (fast)
+				ai->force_full_scan = 1;
+
 		if (ec_err)
 			/*
 			 * Both headers are corrupted. There is a possibility
@@ -991,21 +1052,15 @@
 	}
 
 	vol_id = be32_to_cpu(vidh->vol_id);
-	if (vid)
-		*vid = vol_id;
-	if (sqnum)
-		*sqnum = be64_to_cpu(vidh->sqnum);
-	if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
+	if (vol_id > UBI_MAX_VOLUMES && !vol_ignored(vol_id)) {
 		int lnum = be32_to_cpu(vidh->lnum);
 
 		/* Unsupported internal volume */
 		switch (vidh->compat) {
 		case UBI_COMPAT_DELETE:
-			if (vol_id != UBI_FM_SB_VOLUME_ID
-			    && vol_id != UBI_FM_DATA_VOLUME_ID) {
-				ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
-					vol_id, lnum);
-			}
+			ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
+				vol_id, lnum);
+
 			err = add_to_list(ai, pnum, vol_id, lnum,
 					  ec, 1, &ai->erase);
 			if (err)
@@ -1037,7 +1092,12 @@
 	if (ec_err)
 		ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d",
 			 pnum);
-	err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
+
+	if (ubi_is_fm_vol(vol_id))
+		err = add_fastmap(ai, pnum, vidh, ec);
+	else
+		err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
+
 	if (err)
 		return err;
 
@@ -1186,6 +1246,10 @@
 		list_del(&aeb->u.list);
 		kmem_cache_free(ai->aeb_slab_cache, aeb);
 	}
+	list_for_each_entry_safe(aeb, aeb_tmp, &ai->fastmap, u.list) {
+		list_del(&aeb->u.list);
+		kmem_cache_free(ai->aeb_slab_cache, aeb);
+	}
 
 	/* Destroy the volume RB-tree */
 	rb = ai->volumes.rb_node;
@@ -1245,7 +1309,7 @@
 		cond_resched();
 
 		dbg_gen("process PEB %d", pnum);
-		err = scan_peb(ubi, ai, pnum, NULL, NULL);
+		err = scan_peb(ubi, ai, pnum, false);
 		if (err < 0)
 			goto out_vidh;
 	}
@@ -1311,6 +1375,7 @@
 	INIT_LIST_HEAD(&ai->free);
 	INIT_LIST_HEAD(&ai->erase);
 	INIT_LIST_HEAD(&ai->alien);
+	INIT_LIST_HEAD(&ai->fastmap);
 	ai->volumes = RB_ROOT;
 	ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
 					       sizeof(struct ubi_ainf_peb),
@@ -1337,52 +1402,58 @@
  */
 static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info **ai)
 {
-	int err, pnum, fm_anchor = -1;
-	unsigned long long max_sqnum = 0;
+	int err, pnum;
+	struct ubi_attach_info *scan_ai;
 
 	err = -ENOMEM;
 
+	scan_ai = alloc_ai();
+	if (!scan_ai)
+		goto out;
+
 	ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
 	if (!ech)
-		goto out;
+		goto out_ai;
 
 	vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
 	if (!vidh)
 		goto out_ech;
 
 	for (pnum = 0; pnum < UBI_FM_MAX_START; pnum++) {
-		int vol_id = -1;
-		unsigned long long sqnum = -1;
 		cond_resched();
 
 		dbg_gen("process PEB %d", pnum);
-		err = scan_peb(ubi, *ai, pnum, &vol_id, &sqnum);
+		err = scan_peb(ubi, scan_ai, pnum, true);
 		if (err < 0)
 			goto out_vidh;
-
-		if (vol_id == UBI_FM_SB_VOLUME_ID && sqnum > max_sqnum) {
-			max_sqnum = sqnum;
-			fm_anchor = pnum;
-		}
 	}
 
 	ubi_free_vid_hdr(ubi, vidh);
 	kfree(ech);
 
-	if (fm_anchor < 0)
-		return UBI_NO_FASTMAP;
+	if (scan_ai->force_full_scan)
+		err = UBI_NO_FASTMAP;
+	else
+		err = ubi_scan_fastmap(ubi, *ai, scan_ai);
 
-	destroy_ai(*ai);
-	*ai = alloc_ai();
-	if (!*ai)
-		return -ENOMEM;
+	if (err) {
+		/*
+		 * Didn't attach via fastmap, do a full scan but reuse what
+		 * we've aready scanned.
+		 */
+		destroy_ai(*ai);
+		*ai = scan_ai;
+	} else
+		destroy_ai(scan_ai);
 
-	return ubi_scan_fastmap(ubi, *ai, fm_anchor);
+	return err;
 
 out_vidh:
 	ubi_free_vid_hdr(ubi, vidh);
 out_ech:
 	kfree(ech);
+out_ai:
+	destroy_ai(scan_ai);
 out:
 	return err;
 }
--- linux-4.4.0.orig/drivers/mtd/ubi/block.c
+++ linux-4.4.0/drivers/mtd/ubi/block.c
@@ -99,6 +99,8 @@
 
 /* Linked list of all ubiblock instances */
 static LIST_HEAD(ubiblock_devices);
+static DEFINE_IDR(ubiblock_minor_idr);
+/* Protects ubiblock_devices and ubiblock_minor_idr */
 static DEFINE_MUTEX(devices_mutex);
 static int ubiblock_major;
 
@@ -242,7 +244,7 @@
 	 * in any case.
 	 */
 	if (mode & FMODE_WRITE) {
-		ret = -EPERM;
+		ret = -EROFS;
 		goto out_unlock;
 	}
 
@@ -354,8 +356,6 @@
 	.map_queue      = blk_mq_map_queue,
 };
 
-static DEFINE_IDR(ubiblock_minor_idr);
-
 int ubiblock_create(struct ubi_volume_info *vi)
 {
 	struct ubiblock *dev;
@@ -368,14 +368,15 @@
 	/* Check that the volume isn't already handled */
 	mutex_lock(&devices_mutex);
 	if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
-		mutex_unlock(&devices_mutex);
-		return -EEXIST;
+		ret = -EEXIST;
+		goto out_unlock;
 	}
-	mutex_unlock(&devices_mutex);
 
 	dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
-	if (!dev)
-		return -ENOMEM;
+	if (!dev) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
 
 	mutex_init(&dev->dev_mutex);
 
@@ -440,14 +441,13 @@
 		goto out_free_queue;
 	}
 
-	mutex_lock(&devices_mutex);
 	list_add_tail(&dev->list, &ubiblock_devices);
-	mutex_unlock(&devices_mutex);
 
 	/* Must be the last step: anyone can call file ops from now on */
 	add_disk(dev->gd);
 	dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
 		 dev->ubi_num, dev->vol_id, vi->name);
+	mutex_unlock(&devices_mutex);
 	return 0;
 
 out_free_queue:
@@ -460,6 +460,8 @@
 	put_disk(dev->gd);
 out_free_dev:
 	kfree(dev);
+out_unlock:
+	mutex_unlock(&devices_mutex);
 
 	return ret;
 }
@@ -481,30 +483,36 @@
 int ubiblock_remove(struct ubi_volume_info *vi)
 {
 	struct ubiblock *dev;
+	int ret;
 
 	mutex_lock(&devices_mutex);
 	dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
 	if (!dev) {
-		mutex_unlock(&devices_mutex);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto out_unlock;
 	}
 
 	/* Found a device, let's lock it so we can check if it's busy */
 	mutex_lock(&dev->dev_mutex);
 	if (dev->refcnt > 0) {
-		mutex_unlock(&dev->dev_mutex);
-		mutex_unlock(&devices_mutex);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto out_unlock_dev;
 	}
 
 	/* Remove from device list */
 	list_del(&dev->list);
-	mutex_unlock(&devices_mutex);
-
 	ubiblock_cleanup(dev);
 	mutex_unlock(&dev->dev_mutex);
+	mutex_unlock(&devices_mutex);
+
 	kfree(dev);
 	return 0;
+
+out_unlock_dev:
+	mutex_unlock(&dev->dev_mutex);
+out_unlock:
+	mutex_unlock(&devices_mutex);
+	return ret;
 }
 
 static int ubiblock_resize(struct ubi_volume_info *vi)
@@ -633,6 +641,7 @@
 	struct ubiblock *next;
 	struct ubiblock *dev;
 
+	mutex_lock(&devices_mutex);
 	list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
 		/* The module is being forcefully removed */
 		WARN_ON(dev->desc);
@@ -641,6 +650,7 @@
 		ubiblock_cleanup(dev);
 		kfree(dev);
 	}
+	mutex_unlock(&devices_mutex);
 }
 
 int __init ubiblock_init(void)
--- linux-4.4.0.orig/drivers/mtd/ubi/build.c
+++ linux-4.4.0/drivers/mtd/ubi/build.c
@@ -359,9 +359,6 @@
 	 * we still can use 'ubi->ubi_num'.
 	 */
 	ubi = container_of(dev, struct ubi_device, dev);
-	ubi = ubi_get_device(ubi->ubi_num);
-	if (!ubi)
-		return -ENODEV;
 
 	if (attr == &dev_eraseblock_size)
 		ret = sprintf(buf, "%d\n", ubi->leb_size);
@@ -388,7 +385,6 @@
 	else
 		ret = -EINVAL;
 
-	ubi_put_device(ubi);
 	return ret;
 }
 
@@ -869,7 +865,7 @@
 	for (i = 0; i < UBI_MAX_DEVICES; i++) {
 		ubi = ubi_devices[i];
 		if (ubi && mtd->index == ubi->mtd->index) {
-			ubi_err(ubi, "mtd%d is already attached to ubi%d",
+			pr_err("ubi: mtd%d is already attached to ubi%d",
 				mtd->index, i);
 			return -EEXIST;
 		}
@@ -884,7 +880,25 @@
 	 * no sense to attach emulated MTD devices, so we prohibit this.
 	 */
 	if (mtd->type == MTD_UBIVOLUME) {
-		ubi_err(ubi, "refuse attaching mtd%d - it is already emulated on top of UBI",
+		pr_err("ubi: refuse attaching mtd%d - it is already emulated on top of UBI",
+			mtd->index);
+		return -EINVAL;
+	}
+
+	/*
+	 * Both UBI and UBIFS have been designed for SLC NAND and NOR flashes.
+	 * MLC NAND is different and needs special care, otherwise UBI or UBIFS
+	 * will die soon and you will lose all your data.
+	 */
+	if (mtd->type == MTD_MLCNANDFLASH) {
+		pr_err("ubi: refuse attaching mtd%d - MLC NAND is not supported\n",
+			mtd->index);
+		return -EINVAL;
+	}
+
+	/* UBI cannot work on flashes with zero erasesize. */
+	if (!mtd->erasesize) {
+		pr_err("ubi: refuse attaching mtd%d - zero erasesize flash is not supported\n",
 			mtd->index);
 		return -EINVAL;
 	}
@@ -895,7 +909,7 @@
 			if (!ubi_devices[ubi_num])
 				break;
 		if (ubi_num == UBI_MAX_DEVICES) {
-			ubi_err(ubi, "only %d UBI devices may be created",
+			pr_err("ubi: only %d UBI devices may be created",
 				UBI_MAX_DEVICES);
 			return -ENFILE;
 		}
@@ -905,7 +919,7 @@
 
 		/* Make sure ubi_num is not busy */
 		if (ubi_devices[ubi_num]) {
-			ubi_err(ubi, "already exists");
+			pr_err("ubi: ubi%i already exists", ubi_num);
 			return -EEXIST;
 		}
 	}
@@ -1118,16 +1132,19 @@
 	 */
 	get_device(&ubi->dev);
 
+#ifdef CONFIG_MTD_UBI_FASTMAP
+	cancel_work_sync(&ubi->fm_work);
+#endif
 	ubi_debugfs_exit_dev(ubi);
 	uif_close(ubi);
 
 	ubi_wl_close(ubi);
 	ubi_free_internal_volumes(ubi);
 	vfree(ubi->vtbl);
-	put_mtd_device(ubi->mtd);
 	vfree(ubi->peb_buf);
 	vfree(ubi->fm_buf);
 	ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index);
+	put_mtd_device(ubi->mtd);
 	put_device(&ubi->dev);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/mtd/ubi/eba.c
+++ linux-4.4.0/drivers/mtd/ubi/eba.c
@@ -350,6 +350,82 @@
 	return err;
 }
 
+#ifdef CONFIG_MTD_UBI_FASTMAP
+/**
+ * check_mapping - check and fixup a mapping
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @pnum: physical eraseblock number
+ *
+ * Checks whether a given mapping is valid. Fastmap cannot track LEB unmap
+ * operations, if such an operation is interrupted the mapping still looks
+ * good, but upon first read an ECC is reported to the upper layer.
+ * Normaly during the full-scan at attach time this is fixed, for Fastmap
+ * we have to deal with it while reading.
+ * If the PEB behind a LEB shows this symthom we change the mapping to
+ * %UBI_LEB_UNMAPPED and schedule the PEB for erasure.
+ *
+ * Returns 0 on success, negative error code in case of failure.
+ */
+static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+			 int *pnum)
+{
+	int err;
+	struct ubi_vid_hdr *vid_hdr;
+
+	if (!ubi->fast_attach)
+		return 0;
+
+	vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+	if (!vid_hdr)
+		return -ENOMEM;
+
+	err = ubi_io_read_vid_hdr(ubi, *pnum, vid_hdr, 0);
+	if (err > 0 && err != UBI_IO_BITFLIPS) {
+		int torture = 0;
+
+		switch (err) {
+			case UBI_IO_FF:
+			case UBI_IO_FF_BITFLIPS:
+			case UBI_IO_BAD_HDR:
+			case UBI_IO_BAD_HDR_EBADMSG:
+				break;
+			default:
+				ubi_assert(0);
+		}
+
+		if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_FF_BITFLIPS)
+			torture = 1;
+
+		down_read(&ubi->fm_eba_sem);
+		vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
+		up_read(&ubi->fm_eba_sem);
+		ubi_wl_put_peb(ubi, vol->vol_id, lnum, *pnum, torture);
+
+		*pnum = UBI_LEB_UNMAPPED;
+	} else if (err < 0) {
+		ubi_err(ubi, "unable to read VID header back from PEB %i: %i",
+			*pnum, err);
+
+		goto out_free;
+	}
+
+	err = 0;
+
+out_free:
+	ubi_free_vid_hdr(ubi, vid_hdr);
+
+	return err;
+}
+#else
+static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+		  int *pnum)
+{
+	return 0;
+}
+#endif
+
 /**
  * ubi_eba_read_leb - read data.
  * @ubi: UBI device description object
@@ -381,7 +457,13 @@
 		return err;
 
 	pnum = vol->eba_tbl[lnum];
-	if (pnum < 0) {
+	if (pnum >= 0) {
+		err = check_mapping(ubi, vol, lnum, &pnum);
+		if (err < 0)
+			goto out_unlock;
+	}
+
+	if (pnum == UBI_LEB_UNMAPPED) {
 		/*
 		 * The logical eraseblock is not mapped, fill the whole buffer
 		 * with 0xFF bytes. The exception is static volumes for which
@@ -426,8 +508,25 @@
 						 pnum, vol_id, lnum);
 					err = -EBADMSG;
 				} else {
-					err = -EINVAL;
-					ubi_ro_mode(ubi);
+					/*
+					 * Ending up here in the non-Fastmap case
+					 * is a clear bug as the VID header had to
+					 * be present at scan time to have it referenced.
+					 * With fastmap the story is more complicated.
+					 * Fastmap has the mapping info without the need
+					 * of a full scan. So the LEB could have been
+					 * unmapped, Fastmap cannot know this and keeps
+					 * the LEB referenced.
+					 * This is valid and works as the layer above UBI
+					 * has to do bookkeeping about used/referenced
+					 * LEBs in any case.
+					 */
+					if (ubi->fast_attach) {
+						err = -EBADMSG;
+					} else {
+						err = -EINVAL;
+						ubi_ro_mode(ubi);
+					}
 				}
 			}
 			goto out_free;
@@ -558,6 +657,7 @@
 	int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
 	struct ubi_volume *vol = ubi->volumes[idx];
 	struct ubi_vid_hdr *vid_hdr;
+	uint32_t crc;
 
 	vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
 	if (!vid_hdr)
@@ -582,14 +682,8 @@
 		goto out_put;
 	}
 
-	vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-	err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
-	if (err) {
-		up_read(&ubi->fm_eba_sem);
-		goto write_error;
-	}
+	ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC);
 
-	data_size = offset + len;
 	mutex_lock(&ubi->buf_mutex);
 	memset(ubi->peb_buf + offset, 0xFF, len);
 
@@ -604,6 +698,19 @@
 
 	memcpy(ubi->peb_buf + offset, buf, len);
 
+	data_size = offset + len;
+	crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size);
+	vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
+	vid_hdr->copy_flag = 1;
+	vid_hdr->data_size = cpu_to_be32(data_size);
+	vid_hdr->data_crc = cpu_to_be32(crc);
+	err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
+	if (err) {
+		mutex_unlock(&ubi->buf_mutex);
+		up_read(&ubi->fm_eba_sem);
+		goto write_error;
+	}
+
 	err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
 	if (err) {
 		mutex_unlock(&ubi->buf_mutex);
@@ -672,6 +779,14 @@
 
 	pnum = vol->eba_tbl[lnum];
 	if (pnum >= 0) {
+		err = check_mapping(ubi, vol, lnum, &pnum);
+		if (err < 0) {
+			leb_write_unlock(ubi, vol_id, lnum);
+			return err;
+		}
+	}
+
+	if (pnum >= 0) {
 		dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d",
 			len, offset, vol_id, lnum, pnum);
 
@@ -1063,6 +1178,8 @@
 	struct ubi_volume *vol;
 	uint32_t crc;
 
+	ubi_assert(rwsem_is_locked(&ubi->fm_eba_sem));
+
 	vol_id = be32_to_cpu(vid_hdr->vol_id);
 	lnum = be32_to_cpu(vid_hdr->lnum);
 
@@ -1231,9 +1348,7 @@
 	}
 
 	ubi_assert(vol->eba_tbl[lnum] == from);
-	down_read(&ubi->fm_eba_sem);
 	vol->eba_tbl[lnum] = to;
-	up_read(&ubi->fm_eba_sem);
 
 out_unlock_buf:
 	mutex_unlock(&ubi->buf_mutex);
--- linux-4.4.0.orig/drivers/mtd/ubi/fastmap-wl.c
+++ linux-4.4.0/drivers/mtd/ubi/fastmap-wl.c
@@ -262,6 +262,8 @@
 	struct ubi_fm_pool *pool = &ubi->fm_wl_pool;
 	int pnum;
 
+	ubi_assert(rwsem_is_locked(&ubi->fm_eba_sem));
+
 	if (pool->used == pool->size) {
 		/* We cannot update the fastmap here because this
 		 * function is called in atomic context.
@@ -303,7 +305,7 @@
 
 	wrk->anchor = 1;
 	wrk->func = &wear_leveling_worker;
-	schedule_ubi_work(ubi, wrk);
+	__schedule_ubi_work(ubi, wrk);
 	return 0;
 }
 
@@ -344,7 +346,7 @@
 	spin_unlock(&ubi->wl_lock);
 
 	vol_id = lnum ? UBI_FM_DATA_VOLUME_ID : UBI_FM_SB_VOLUME_ID;
-	return schedule_erase(ubi, e, vol_id, lnum, torture);
+	return schedule_erase(ubi, e, vol_id, lnum, torture, true);
 }
 
 /**
@@ -360,7 +362,6 @@
 {
 	int i;
 
-	flush_work(&ubi->fm_work);
 	return_unused_pool_pebs(ubi, &ubi->fm_pool);
 	return_unused_pool_pebs(ubi, &ubi->fm_wl_pool);
 
--- linux-4.4.0.orig/drivers/mtd/ubi/fastmap.c
+++ linux-4.4.0/drivers/mtd/ubi/fastmap.c
@@ -326,6 +326,7 @@
 			aeb->pnum = new_aeb->pnum;
 			aeb->copy_flag = new_vh->copy_flag;
 			aeb->scrub = new_aeb->scrub;
+			aeb->sqnum = new_aeb->sqnum;
 			kmem_cache_free(ai->aeb_slab_cache, new_aeb);
 
 		/* new_aeb is older */
@@ -513,10 +514,11 @@
 			unsigned long long ec = be64_to_cpu(ech->ec);
 			unmap_peb(ai, pnum);
 			dbg_bld("Adding PEB to free: %i", pnum);
+
 			if (err == UBI_IO_FF_BITFLIPS)
-				add_aeb(ai, free, pnum, ec, 1);
-			else
-				add_aeb(ai, free, pnum, ec, 0);
+				scrub = 1;
+
+			add_aeb(ai, free, pnum, ec, scrub);
 			continue;
 		} else if (err == 0 || err == UBI_IO_BITFLIPS) {
 			dbg_bld("Found non empty PEB:%i in pool", pnum);
@@ -748,11 +750,11 @@
 			     fmvhdr->vol_type,
 			     be32_to_cpu(fmvhdr->last_eb_bytes));
 
-		if (!av)
-			goto fail_bad;
-		if (PTR_ERR(av) == -EINVAL) {
-			ubi_err(ubi, "volume (ID %i) already exists",
-				fmvhdr->vol_id);
+		if (IS_ERR(av)) {
+			if (PTR_ERR(av) == -EEXIST)
+				ubi_err(ubi, "volume (ID %i) already exists",
+					fmvhdr->vol_id);
+
 			goto fail_bad;
 		}
 
@@ -850,27 +852,57 @@
 }
 
 /**
+ * find_fm_anchor - find the most recent Fastmap superblock (anchor)
+ * @ai: UBI attach info to be filled
+ */
+static int find_fm_anchor(struct ubi_attach_info *ai)
+{
+	int ret = -1;
+	struct ubi_ainf_peb *aeb;
+	unsigned long long max_sqnum = 0;
+
+	list_for_each_entry(aeb, &ai->fastmap, u.list) {
+		if (aeb->vol_id == UBI_FM_SB_VOLUME_ID && aeb->sqnum > max_sqnum) {
+			max_sqnum = aeb->sqnum;
+			ret = aeb->pnum;
+		}
+	}
+
+	return ret;
+}
+
+/**
  * ubi_scan_fastmap - scan the fastmap.
  * @ubi: UBI device object
  * @ai: UBI attach info to be filled
- * @fm_anchor: The fastmap starts at this PEB
+ * @scan_ai: UBI attach info from the first 64 PEBs,
+ *           used to find the most recent Fastmap data structure
  *
  * Returns 0 on success, UBI_NO_FASTMAP if no fastmap was found,
  * UBI_BAD_FASTMAP if one was found but is not usable.
  * < 0 indicates an internal error.
  */
 int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
-		     int fm_anchor)
+		     struct ubi_attach_info *scan_ai)
 {
 	struct ubi_fm_sb *fmsb, *fmsb2;
 	struct ubi_vid_hdr *vh;
 	struct ubi_ec_hdr *ech;
 	struct ubi_fastmap_layout *fm;
-	int i, used_blocks, pnum, ret = 0;
+	struct ubi_ainf_peb *tmp_aeb, *aeb;
+	int i, used_blocks, pnum, fm_anchor, ret = 0;
 	size_t fm_size;
 	__be32 crc, tmp_crc;
 	unsigned long long sqnum = 0;
 
+	fm_anchor = find_fm_anchor(scan_ai);
+	if (fm_anchor < 0)
+		return UBI_NO_FASTMAP;
+
+	/* Move all (possible) fastmap blocks into our new attach structure. */
+	list_for_each_entry_safe(aeb, tmp_aeb, &scan_ai->fastmap, u.list)
+		list_move_tail(&aeb->u.list, &ai->fastmap);
+
 	down_write(&ubi->fm_protect);
 	memset(ubi->fm_buf, 0, ubi->fm_size);
 
@@ -1058,6 +1090,7 @@
 	ubi_msg(ubi, "fastmap WL pool size: %d",
 		ubi->fm_wl_pool.max_size);
 	ubi->fm_disabled = 0;
+	ubi->fast_attach = 1;
 
 	ubi_free_vid_hdr(ubi, vh);
 	kfree(ech);
@@ -1482,22 +1515,30 @@
 	struct ubi_wl_entry *tmp_e;
 
 	down_write(&ubi->fm_protect);
+	down_write(&ubi->work_sem);
+	down_write(&ubi->fm_eba_sem);
 
 	ubi_refill_pools(ubi);
 
 	if (ubi->ro_mode || ubi->fm_disabled) {
+		up_write(&ubi->fm_eba_sem);
+		up_write(&ubi->work_sem);
 		up_write(&ubi->fm_protect);
 		return 0;
 	}
 
 	ret = ubi_ensure_anchor_pebs(ubi);
 	if (ret) {
+		up_write(&ubi->fm_eba_sem);
+		up_write(&ubi->work_sem);
 		up_write(&ubi->fm_protect);
 		return ret;
 	}
 
 	new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL);
 	if (!new_fm) {
+		up_write(&ubi->fm_eba_sem);
+		up_write(&ubi->work_sem);
 		up_write(&ubi->fm_protect);
 		return -ENOMEM;
 	}
@@ -1606,16 +1647,14 @@
 		new_fm->e[0] = tmp_e;
 	}
 
-	down_write(&ubi->work_sem);
-	down_write(&ubi->fm_eba_sem);
 	ret = ubi_write_fastmap(ubi, new_fm);
-	up_write(&ubi->fm_eba_sem);
-	up_write(&ubi->work_sem);
 
 	if (ret)
 		goto err;
 
 out_unlock:
+	up_write(&ubi->fm_eba_sem);
+	up_write(&ubi->work_sem);
 	up_write(&ubi->fm_protect);
 	kfree(old_fm);
 	return ret;
--- linux-4.4.0.orig/drivers/mtd/ubi/kapi.c
+++ linux-4.4.0/drivers/mtd/ubi/kapi.c
@@ -227,9 +227,9 @@
 out_free:
 	kfree(desc);
 out_put_ubi:
-	ubi_put_device(ubi);
 	ubi_err(ubi, "cannot open device %d, volume %d, error %d",
 		ubi_num, vol_id, err);
+	ubi_put_device(ubi);
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume);
--- linux-4.4.0.orig/drivers/mtd/ubi/ubi.h
+++ linux-4.4.0/drivers/mtd/ubi/ubi.h
@@ -462,6 +462,7 @@
  * @fm_eba_sem: allows ubi_update_fastmap() to block EBA table changes
  * @fm_work: fastmap work queue
  * @fm_work_scheduled: non-zero if fastmap work was scheduled
+ * @fast_attach: non-zero if UBI was attached by fastmap
  *
  * @used: RB-tree of used physical eraseblocks
  * @erroneous: RB-tree of erroneous used physical eraseblocks
@@ -570,6 +571,7 @@
 	size_t fm_size;
 	struct work_struct fm_work;
 	int fm_work_scheduled;
+	int fast_attach;
 
 	/* Wear-leveling sub-system's stuff */
 	struct rb_root used;
@@ -697,6 +699,8 @@
  * @erase: list of physical eraseblocks which have to be erased
  * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
  *         those belonging to "preserve"-compatible internal volumes)
+ * @fastmap: list of physical eraseblocks which relate to fastmap (e.g.,
+ *           eraseblocks of the current and not yet erased old fastmap blocks)
  * @corr_peb_count: count of PEBs in the @corr list
  * @empty_peb_count: count of PEBs which are presumably empty (contain only
  *                   0xFF bytes)
@@ -707,6 +711,8 @@
  * @vols_found: number of volumes found
  * @highest_vol_id: highest volume ID
  * @is_empty: flag indicating whether the MTD device is empty or not
+ * @force_full_scan: flag indicating whether we need to do a full scan and drop
+		     all existing Fastmap data structures
  * @min_ec: lowest erase counter value
  * @max_ec: highest erase counter value
  * @max_sqnum: highest sequence number value
@@ -725,6 +731,7 @@
 	struct list_head free;
 	struct list_head erase;
 	struct list_head alien;
+	struct list_head fastmap;
 	int corr_peb_count;
 	int empty_peb_count;
 	int alien_peb_count;
@@ -733,6 +740,7 @@
 	int vols_found;
 	int highest_vol_id;
 	int is_empty;
+	int force_full_scan;
 	int min_ec;
 	int max_ec;
 	unsigned long long max_sqnum;
@@ -905,7 +913,7 @@
 size_t ubi_calc_fm_size(struct ubi_device *ubi);
 int ubi_update_fastmap(struct ubi_device *ubi);
 int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
-		     int fm_anchor);
+		     struct ubi_attach_info *scan_ai);
 #else
 static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
 #endif
@@ -1099,4 +1107,42 @@
 		return idx;
 }
 
+/**
+ * ubi_is_fm_vol - check whether a volume ID is a Fastmap volume.
+ * @vol_id: volume ID
+ */
+static inline bool ubi_is_fm_vol(int vol_id)
+{
+	switch (vol_id) {
+		case UBI_FM_SB_VOLUME_ID:
+		case UBI_FM_DATA_VOLUME_ID:
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * ubi_find_fm_block - check whether a PEB is part of the current Fastmap.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to look for
+ *
+ * This function returns a wear leveling object if @pnum relates to the current
+ * fastmap, @NULL otherwise.
+ */
+static inline struct ubi_wl_entry *ubi_find_fm_block(const struct ubi_device *ubi,
+						     int pnum)
+{
+	int i;
+
+	if (ubi->fm) {
+		for (i = 0; i < ubi->fm->used_blocks; i++) {
+			if (ubi->fm->e[i]->pnum == pnum)
+				return ubi->fm->e[i];
+		}
+	}
+
+	return NULL;
+}
+
 #endif /* !__UBI_UBI_H__ */
--- linux-4.4.0.orig/drivers/mtd/ubi/upd.c
+++ linux-4.4.0/drivers/mtd/ubi/upd.c
@@ -148,11 +148,11 @@
 			return err;
 	}
 
-	if (bytes == 0) {
-		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
-		if (err)
-			return err;
+	err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
+	if (err)
+		return err;
 
+	if (bytes == 0) {
 		err = clear_update_marker(ubi, vol, 0);
 		if (err)
 			return err;
@@ -193,7 +193,7 @@
 	vol->changing_leb = 1;
 	vol->ch_lnum = req->lnum;
 
-	vol->upd_buf = vmalloc(req->bytes);
+	vol->upd_buf = vmalloc(ALIGN((int)req->bytes, ubi->min_io_size));
 	if (!vol->upd_buf)
 		return -ENOMEM;
 
--- linux-4.4.0.orig/drivers/mtd/ubi/vmt.c
+++ linux-4.4.0/drivers/mtd/ubi/vmt.c
@@ -69,16 +69,11 @@
 {
 	int ret;
 	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
-	struct ubi_device *ubi;
-
-	ubi = ubi_get_device(vol->ubi->ubi_num);
-	if (!ubi)
-		return -ENODEV;
+	struct ubi_device *ubi = vol->ubi;
 
 	spin_lock(&ubi->volumes_lock);
 	if (!ubi->volumes[vol->vol_id]) {
 		spin_unlock(&ubi->volumes_lock);
-		ubi_put_device(ubi);
 		return -ENODEV;
 	}
 	/* Take a reference to prevent volume removal */
@@ -116,7 +111,6 @@
 	vol->ref_count -= 1;
 	ubi_assert(vol->ref_count >= 0);
 	spin_unlock(&ubi->volumes_lock);
-	ubi_put_device(ubi);
 	return ret;
 }
 
@@ -265,6 +259,12 @@
 			vol->last_eb_bytes = vol->usable_leb_size;
 	}
 
+	/* Make volume "available" before it becomes accessible via sysfs */
+	spin_lock(&ubi->volumes_lock);
+	ubi->volumes[vol_id] = vol;
+	ubi->vol_count += 1;
+	spin_unlock(&ubi->volumes_lock);
+
 	/* Register character device for the volume */
 	cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
 	vol->cdev.owner = THIS_MODULE;
@@ -304,11 +304,6 @@
 	if (err)
 		goto out_sysfs;
 
-	spin_lock(&ubi->volumes_lock);
-	ubi->volumes[vol_id] = vol;
-	ubi->vol_count += 1;
-	spin_unlock(&ubi->volumes_lock);
-
 	ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
 	self_check_volumes(ubi);
 	return err;
@@ -328,6 +323,10 @@
 out_cdev:
 	cdev_del(&vol->cdev);
 out_mapping:
+	spin_lock(&ubi->volumes_lock);
+	ubi->volumes[vol_id] = NULL;
+	ubi->vol_count -= 1;
+	spin_unlock(&ubi->volumes_lock);
 	if (do_free)
 		kfree(vol->eba_tbl);
 out_acc:
@@ -488,13 +487,6 @@
 		spin_unlock(&ubi->volumes_lock);
 	}
 
-	/* Change volume table record */
-	vtbl_rec = ubi->vtbl[vol_id];
-	vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
-	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
-	if (err)
-		goto out_acc;
-
 	if (pebs < 0) {
 		for (i = 0; i < -pebs; i++) {
 			err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
@@ -512,6 +504,24 @@
 		spin_unlock(&ubi->volumes_lock);
 	}
 
+	/*
+	 * When we shrink a volume we have to flush all pending (erase) work.
+	 * Otherwise it can happen that upon next attach UBI finds a LEB with
+	 * lnum > highest_lnum and refuses to attach.
+	 */
+	if (pebs < 0) {
+		err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
+		if (err)
+			goto out_acc;
+	}
+
+	/* Change volume table record */
+	vtbl_rec = ubi->vtbl[vol_id];
+	vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
+	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+	if (err)
+		goto out_acc;
+
 	vol->reserved_pebs = reserved_pebs;
 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
 		vol->used_ebs = reserved_pebs;
--- linux-4.4.0.orig/drivers/mtd/ubi/vtbl.c
+++ linux-4.4.0/drivers/mtd/ubi/vtbl.c
@@ -785,6 +785,12 @@
 	 * The number of supported volumes is limited by the eraseblock size
 	 * and by the UBI_MAX_VOLUMES constant.
 	 */
+
+	if (ubi->leb_size < UBI_VTBL_RECORD_SIZE) {
+		ubi_err(ubi, "LEB size too small for a volume record");
+		return -EINVAL;
+	}
+
 	ubi->vtbl_slots = ubi->leb_size / UBI_VTBL_RECORD_SIZE;
 	if (ubi->vtbl_slots > UBI_MAX_VOLUMES)
 		ubi->vtbl_slots = UBI_MAX_VOLUMES;
--- linux-4.4.0.orig/drivers/mtd/ubi/wl.c
+++ linux-4.4.0/drivers/mtd/ubi/wl.c
@@ -580,7 +580,7 @@
  * failure.
  */
 static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
-			  int vol_id, int lnum, int torture)
+			  int vol_id, int lnum, int torture, bool nested)
 {
 	struct ubi_work *wl_wrk;
 
@@ -599,7 +599,10 @@
 	wl_wrk->lnum = lnum;
 	wl_wrk->torture = torture;
 
-	schedule_ubi_work(ubi, wl_wrk);
+	if (nested)
+		__schedule_ubi_work(ubi, wl_wrk);
+	else
+		schedule_ubi_work(ubi, wl_wrk);
 	return 0;
 }
 
@@ -643,7 +646,7 @@
 				int shutdown)
 {
 	int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
-	int vol_id = -1, lnum = -1;
+	int erase = 0, keep = 0, vol_id = -1, lnum = -1;
 #ifdef CONFIG_MTD_UBI_FASTMAP
 	int anchor = wrk->anchor;
 #endif
@@ -658,6 +661,7 @@
 	if (!vid_hdr)
 		return -ENOMEM;
 
+	down_read(&ubi->fm_eba_sem);
 	mutex_lock(&ubi->move_mutex);
 	spin_lock(&ubi->wl_lock);
 	ubi_assert(!ubi->move_from && !ubi->move_to);
@@ -777,6 +781,16 @@
 			       e1->pnum);
 			scrubbing = 1;
 			goto out_not_moved;
+		} else if (ubi->fast_attach && err == UBI_IO_BAD_HDR_EBADMSG) {
+			/*
+			 * While a full scan would detect interrupted erasures
+			 * at attach time we can face them here when attached from
+			 * Fastmap.
+			 */
+			dbg_wl("PEB %d has ECC errors, maybe from an interrupted erasure",
+			       e1->pnum);
+			erase = 1;
+			goto out_not_moved;
 		}
 
 		ubi_err(ubi, "error %d while reading VID header from PEB %d",
@@ -810,6 +824,7 @@
 			 * Target PEB had bit-flips or write error - torture it.
 			 */
 			torture = 1;
+			keep = 1;
 			goto out_not_moved;
 		}
 
@@ -873,6 +888,7 @@
 
 	dbg_wl("done");
 	mutex_unlock(&ubi->move_mutex);
+	up_read(&ubi->fm_eba_sem);
 	return 0;
 
 	/*
@@ -895,7 +911,7 @@
 		ubi->erroneous_peb_count += 1;
 	} else if (scrubbing)
 		wl_tree_add(e1, &ubi->scrub);
-	else
+	else if (keep)
 		wl_tree_add(e1, &ubi->used);
 	ubi_assert(!ubi->move_to_put);
 	ubi->move_from = ubi->move_to = NULL;
@@ -907,7 +923,14 @@
 	if (err)
 		goto out_ro;
 
+	if (erase) {
+		err = do_sync_erase(ubi, e1, vol_id, lnum, 1);
+		if (err)
+			goto out_ro;
+	}
+
 	mutex_unlock(&ubi->move_mutex);
+	up_read(&ubi->fm_eba_sem);
 	return 0;
 
 out_error:
@@ -929,6 +952,7 @@
 out_ro:
 	ubi_ro_mode(ubi);
 	mutex_unlock(&ubi->move_mutex);
+	up_read(&ubi->fm_eba_sem);
 	ubi_assert(err != 0);
 	return err < 0 ? err : -EIO;
 
@@ -936,6 +960,7 @@
 	ubi->wl_scheduled = 0;
 	spin_unlock(&ubi->wl_lock);
 	mutex_unlock(&ubi->move_mutex);
+	up_read(&ubi->fm_eba_sem);
 	ubi_free_vid_hdr(ubi, vid_hdr);
 	return 0;
 }
@@ -1058,7 +1083,7 @@
 		int err1;
 
 		/* Re-schedule the LEB for erasure */
-		err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
+		err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false);
 		if (err1) {
 			wl_entry_destroy(ubi, e);
 			err = err1;
@@ -1239,7 +1264,7 @@
 	}
 	spin_unlock(&ubi->wl_lock);
 
-	err = schedule_erase(ubi, e, vol_id, lnum, torture);
+	err = schedule_erase(ubi, e, vol_id, lnum, torture, false);
 	if (err) {
 		spin_lock(&ubi->wl_lock);
 		wl_tree_add(e, &ubi->used);
@@ -1435,6 +1460,19 @@
 		    !ubi->thread_enabled || ubi_dbg_is_bgt_disabled(ubi)) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			spin_unlock(&ubi->wl_lock);
+
+			/*
+			 * Check kthread_should_stop() after we set the task
+			 * state to guarantee that we either see the stop bit
+			 * and exit or the task state is reset to runnable such
+			 * that it's not scheduled out indefinitely and detects
+			 * the stop bit at kthread_should_stop().
+			 */
+			if (kthread_should_stop()) {
+				set_current_state(TASK_RUNNING);
+				break;
+			}
+
 			schedule();
 			continue;
 		}
@@ -1462,6 +1500,7 @@
 	}
 
 	dbg_wl("background thread \"%s\" is killed", ubi->bgt_name);
+	ubi->thread_enabled = 0;
 	return 0;
 }
 
@@ -1471,9 +1510,6 @@
  */
 static void shutdown_work(struct ubi_device *ubi)
 {
-#ifdef CONFIG_MTD_UBI_FASTMAP
-	flush_work(&ubi->fm_work);
-#endif
 	while (!list_empty(&ubi->works)) {
 		struct ubi_work *wrk;
 
@@ -1486,6 +1522,46 @@
 }
 
 /**
+ * erase_aeb - erase a PEB given in UBI attach info PEB
+ * @ubi: UBI device description object
+ * @aeb: UBI attach info PEB
+ * @sync: If true, erase synchronously. Otherwise schedule for erasure
+ */
+static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync)
+{
+	struct ubi_wl_entry *e;
+	int err;
+
+	e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+	if (!e)
+		return -ENOMEM;
+
+	e->pnum = aeb->pnum;
+	e->ec = aeb->ec;
+	ubi->lookuptbl[e->pnum] = e;
+
+	if (sync) {
+		err = sync_erase(ubi, e, false);
+		if (err)
+			goto out_free;
+
+		wl_tree_add(e, &ubi->free);
+		ubi->free_count++;
+	} else {
+		err = schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false);
+		if (err)
+			goto out_free;
+	}
+
+	return 0;
+
+out_free:
+	wl_entry_destroy(ubi, e);
+
+	return err;
+}
+
+/**
  * ubi_wl_init - initialize the WL sub-system using attaching information.
  * @ubi: UBI device description object
  * @ai: attaching information
@@ -1522,17 +1598,9 @@
 	list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) {
 		cond_resched();
 
-		e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
-		if (!e)
-			goto out_free;
-
-		e->pnum = aeb->pnum;
-		e->ec = aeb->ec;
-		ubi->lookuptbl[e->pnum] = e;
-		if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
-			wl_entry_destroy(ubi, e);
+		err = erase_aeb(ubi, aeb, false);
+		if (err)
 			goto out_free;
-		}
 
 		found_pebs++;
 	}
@@ -1542,8 +1610,10 @@
 		cond_resched();
 
 		e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
-		if (!e)
+		if (!e) {
+			err = -ENOMEM;
 			goto out_free;
+		}
 
 		e->pnum = aeb->pnum;
 		e->ec = aeb->ec;
@@ -1562,8 +1632,10 @@
 			cond_resched();
 
 			e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
-			if (!e)
+			if (!e) {
+				err = -ENOMEM;
 				goto out_free;
+			}
 
 			e->pnum = aeb->pnum;
 			e->ec = aeb->ec;
@@ -1583,19 +1655,49 @@
 		}
 	}
 
-	dbg_wl("found %i PEBs", found_pebs);
+	list_for_each_entry(aeb, &ai->fastmap, u.list) {
+		cond_resched();
 
-	if (ubi->fm) {
-		ubi_assert(ubi->good_peb_count ==
-			   found_pebs + ubi->fm->used_blocks);
+		e = ubi_find_fm_block(ubi, aeb->pnum);
 
-		for (i = 0; i < ubi->fm->used_blocks; i++) {
-			e = ubi->fm->e[i];
+		if (e) {
+			ubi_assert(!ubi->lookuptbl[e->pnum]);
 			ubi->lookuptbl[e->pnum] = e;
+		} else {
+			bool sync = false;
+
+			/*
+			 * Usually old Fastmap PEBs are scheduled for erasure
+			 * and we don't have to care about them but if we face
+			 * an power cut before scheduling them we need to
+			 * take care of them here.
+			 */
+			if (ubi->lookuptbl[aeb->pnum])
+				continue;
+
+			/*
+			 * The fastmap update code might not find a free PEB for
+			 * writing the fastmap anchor to and then reuses the
+			 * current fastmap anchor PEB. When this PEB gets erased
+			 * and a power cut happens before it is written again we
+			 * must make sure that the fastmap attach code doesn't
+			 * find any outdated fastmap anchors, hence we erase the
+			 * outdated fastmap anchor PEBs synchronously here.
+			 */
+			if (aeb->vol_id == UBI_FM_SB_VOLUME_ID)
+				sync = true;
+
+			err = erase_aeb(ubi, aeb, sync);
+			if (err)
+				goto out_free;
 		}
+
+		found_pebs++;
 	}
-	else
-		ubi_assert(ubi->good_peb_count == found_pebs);
+
+	dbg_wl("found %i PEBs", found_pebs);
+
+	ubi_assert(ubi->good_peb_count == found_pebs);
 
 	reserved_pebs = WL_RESERVED_PEBS;
 	ubi_fastmap_init(ubi, &reserved_pebs);
--- linux-4.4.0.orig/drivers/net/Kconfig
+++ linux-4.4.0/drivers/net/Kconfig
@@ -411,6 +411,9 @@
 config VMXNET3
 	tristate "VMware VMXNET3 ethernet driver"
 	depends on PCI && INET
+	depends on !(PAGE_SIZE_64KB || ARM64_64K_PAGES || \
+		     IA64_PAGE_SIZE_64KB || MICROBLAZE_64K_PAGES || \
+		     PARISC_PAGE_SIZE_64KB || PPC_64K_PAGES)
 	help
 	  This driver supports VMware's vmxnet3 virtual ethernet NIC.
 	  To compile this driver as a module, choose M here: the
--- linux-4.4.0.orig/drivers/net/appletalk/cops.c
+++ linux-4.4.0/drivers/net/appletalk/cops.c
@@ -986,9 +986,9 @@
 static struct net_device *cops_dev;
 
 MODULE_LICENSE("GPL");
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(board_type, int, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
+module_param_hw(board_type, int, other, 0);
 
 static int __init cops_module_init(void)
 {
--- linux-4.4.0.orig/drivers/net/appletalk/ipddp.c
+++ linux-4.4.0/drivers/net/appletalk/ipddp.c
@@ -191,7 +191,7 @@
  */
 static int ipddp_create(struct ipddp_route *new_rt)
 {
-        struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL);
+        struct ipddp_route *rt = kzalloc(sizeof(*rt), GFP_KERNEL);
 
         if (rt == NULL)
                 return -ENOMEM;
@@ -284,8 +284,12 @@
                 case SIOCFINDIPDDPRT:
 			spin_lock_bh(&ipddp_route_lock);
 			rp = __ipddp_find_route(&rcp);
-			if (rp)
-				memcpy(&rcp2, rp, sizeof(rcp2));
+			if (rp) {
+				memset(&rcp2, 0, sizeof(rcp2));
+				rcp2.ip    = rp->ip;
+				rcp2.at    = rp->at;
+				rcp2.flags = rp->flags;
+			}
 			spin_unlock_bh(&ipddp_route_lock);
 
 			if (rp) {
--- linux-4.4.0.orig/drivers/net/appletalk/ltpc.c
+++ linux-4.4.0/drivers/net/appletalk/ltpc.c
@@ -1231,9 +1231,9 @@
 
 MODULE_LICENSE("GPL");
 module_param(debug, int, 0);
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
+module_param_hw(dma, int, dma, 0);
 
 
 static int __init ltpc_module_init(void)
--- linux-4.4.0.orig/drivers/net/arcnet/arcnet.c
+++ linux-4.4.0/drivers/net/arcnet/arcnet.c
@@ -1009,31 +1009,34 @@
 static void arcnet_rx(struct net_device *dev, int bufnum)
 {
 	struct arcnet_local *lp = netdev_priv(dev);
-	struct archdr pkt;
+	union {
+		struct archdr pkt;
+		char buf[512];
+	} rxdata;
 	struct arc_rfc1201 *soft;
 	int length, ofs;
 
-	soft = &pkt.soft.rfc1201;
+	soft = &rxdata.pkt.soft.rfc1201;
 
-	lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE);
-	if (pkt.hard.offset[0]) {
-		ofs = pkt.hard.offset[0];
+	lp->hw.copy_from_card(dev, bufnum, 0, &rxdata.pkt, ARC_HDR_SIZE);
+	if (rxdata.pkt.hard.offset[0]) {
+		ofs = rxdata.pkt.hard.offset[0];
 		length = 256 - ofs;
 	} else {
-		ofs = pkt.hard.offset[1];
+		ofs = rxdata.pkt.hard.offset[1];
 		length = 512 - ofs;
 	}
 
 	/* get the full header, if possible */
-	if (sizeof(pkt.soft) <= length) {
-		lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft));
+	if (sizeof(rxdata.pkt.soft) <= length) {
+		lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(rxdata.pkt.soft));
 	} else {
-		memset(&pkt.soft, 0, sizeof(pkt.soft));
+		memset(&rxdata.pkt.soft, 0, sizeof(rxdata.pkt.soft));
 		lp->hw.copy_from_card(dev, bufnum, ofs, soft, length);
 	}
 
 	arc_printk(D_DURING, dev, "Buffer #%d: received packet from %02Xh to %02Xh (%d+4 bytes)\n",
-		   bufnum, pkt.hard.source, pkt.hard.dest, length);
+		   bufnum, rxdata.pkt.hard.source, rxdata.pkt.hard.dest, length);
 
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += length + ARC_HDR_SIZE;
@@ -1042,13 +1045,13 @@
 	if (arc_proto_map[soft->proto]->is_ip) {
 		if (BUGLVL(D_PROTO)) {
 			struct ArcProto
-			*oldp = arc_proto_map[lp->default_proto[pkt.hard.source]],
+			*oldp = arc_proto_map[lp->default_proto[rxdata.pkt.hard.source]],
 			*newp = arc_proto_map[soft->proto];
 
 			if (oldp != newp) {
 				arc_printk(D_PROTO, dev,
 					   "got protocol %02Xh; encap for host %02Xh is now '%c' (was '%c')\n",
-					   soft->proto, pkt.hard.source,
+					   soft->proto, rxdata.pkt.hard.source,
 					   newp->suffix, oldp->suffix);
 			}
 		}
@@ -1057,10 +1060,10 @@
 		lp->default_proto[0] = soft->proto;
 
 		/* in striking contrast, the following isn't a hack. */
-		lp->default_proto[pkt.hard.source] = soft->proto;
+		lp->default_proto[rxdata.pkt.hard.source] = soft->proto;
 	}
 	/* call the protocol-specific receiver. */
-	arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length);
+	arc_proto_map[soft->proto]->rx(dev, bufnum, &rxdata.pkt, length);
 }
 
 static void null_rx(struct net_device *dev, int bufnum,
--- linux-4.4.0.orig/drivers/net/arcnet/com20020-isa.c
+++ linux-4.4.0/drivers/net/arcnet/com20020-isa.c
@@ -129,8 +129,8 @@
 static int clockm = 0;
 
 module_param(node, int, 0);
-module_param(io, int, 0);
-module_param(irq, int, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
 module_param_string(device, device, sizeof(device), 0);
 module_param(timeout, int, 0);
 module_param(backplane, int, 0);
--- linux-4.4.0.orig/drivers/net/arcnet/com90io.c
+++ linux-4.4.0/drivers/net/arcnet/com90io.c
@@ -347,8 +347,8 @@
 static int irq;
 static char device[9];		/* use eg. device=arc1 to change name */
 
-module_param(io, int, 0);
-module_param(irq, int, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
 module_param_string(device, device, sizeof(device), 0);
 MODULE_LICENSE("GPL");
 
--- linux-4.4.0.orig/drivers/net/arcnet/com90xx.c
+++ linux-4.4.0/drivers/net/arcnet/com90xx.c
@@ -88,8 +88,8 @@
 static int shmem;
 static char device[9];		/* use eg. device=arc1 to change name */
 
-module_param(io, int, 0);
-module_param(irq, int, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
 module_param(shmem, int, 0);
 module_param_string(device, device, sizeof(device), 0);
 
--- linux-4.4.0.orig/drivers/net/bonding/bond_3ad.c
+++ linux-4.4.0/drivers/net/bonding/bond_3ad.c
@@ -90,21 +90,28 @@
 	AD_LINK_SPEED_100MBPS,
 	AD_LINK_SPEED_1000MBPS,
 	AD_LINK_SPEED_2500MBPS,
+	AD_LINK_SPEED_5000MBPS,
 	AD_LINK_SPEED_10000MBPS,
 	AD_LINK_SPEED_20000MBPS,
+	AD_LINK_SPEED_25000MBPS,
 	AD_LINK_SPEED_40000MBPS,
-	AD_LINK_SPEED_56000MBPS
+	AD_LINK_SPEED_50000MBPS,
+	AD_LINK_SPEED_56000MBPS,
+	AD_LINK_SPEED_100000MBPS,
 };
 
 /* compare MAC addresses */
 #define MAC_ADDRESS_EQUAL(A, B)	\
 	ether_addr_equal_64bits((const u8 *)A, (const u8 *)B)
 
-static struct mac_addr null_mac_addr = { { 0, 0, 0, 0, 0, 0 } };
+static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = {
+	0, 0, 0, 0, 0, 0
+};
 static u16 ad_ticks_per_sec;
 static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;
 
-static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
+static const u8 lacpdu_mcast_addr[ETH_ALEN + 2] __long_aligned =
+	MULTICAST_LACPDU_ADDR;
 
 /* ================= main 802.3ad protocol functions ================== */
 static int ad_lacpdu_send(struct port *port);
@@ -254,10 +261,14 @@
  *     %AD_LINK_SPEED_100MBPS,
  *     %AD_LINK_SPEED_1000MBPS,
  *     %AD_LINK_SPEED_2500MBPS,
+ *     %AD_LINK_SPEED_5000MBPS,
  *     %AD_LINK_SPEED_10000MBPS
  *     %AD_LINK_SPEED_20000MBPS
+ *     %AD_LINK_SPEED_25000MBPS
  *     %AD_LINK_SPEED_40000MBPS
+ *     %AD_LINK_SPEED_50000MBPS
  *     %AD_LINK_SPEED_56000MBPS
+ *     %AD_LINK_SPEED_100000MBPS
  */
 static u16 __get_link_speed(struct port *port)
 {
@@ -289,6 +300,10 @@
 			speed = AD_LINK_SPEED_2500MBPS;
 			break;
 
+		case SPEED_5000:
+			speed = AD_LINK_SPEED_5000MBPS;
+			break;
+
 		case SPEED_10000:
 			speed = AD_LINK_SPEED_10000MBPS;
 			break;
@@ -297,14 +312,26 @@
 			speed = AD_LINK_SPEED_20000MBPS;
 			break;
 
+		case SPEED_25000:
+			speed = AD_LINK_SPEED_25000MBPS;
+			break;
+
 		case SPEED_40000:
 			speed = AD_LINK_SPEED_40000MBPS;
 			break;
 
+		case SPEED_50000:
+			speed = AD_LINK_SPEED_50000MBPS;
+			break;
+
 		case SPEED_56000:
 			speed = AD_LINK_SPEED_56000MBPS;
 			break;
 
+		case SPEED_100000:
+			speed = AD_LINK_SPEED_100000MBPS;
+			break;
+
 		default:
 			/* unknown speed value from ethtool. shouldn't happen */
 			speed = 0;
@@ -643,6 +670,20 @@
 	}
 }
 
+static int __agg_active_ports(struct aggregator *agg)
+{
+	struct port *port;
+	int active = 0;
+
+	for (port = agg->lag_ports; port;
+	     port = port->next_port_in_aggregator) {
+		if (port->is_enabled)
+			active++;
+	}
+
+	return active;
+}
+
 /**
  * __get_agg_bandwidth - get the total bandwidth of an aggregator
  * @aggregator: the aggregator we're looking at
@@ -650,36 +691,49 @@
  */
 static u32 __get_agg_bandwidth(struct aggregator *aggregator)
 {
+	int nports = __agg_active_ports(aggregator);
 	u32 bandwidth = 0;
 
-	if (aggregator->num_of_ports) {
+	if (nports) {
 		switch (__get_link_speed(aggregator->lag_ports)) {
 		case AD_LINK_SPEED_1MBPS:
-			bandwidth = aggregator->num_of_ports;
+			bandwidth = nports;
 			break;
 		case AD_LINK_SPEED_10MBPS:
-			bandwidth = aggregator->num_of_ports * 10;
+			bandwidth = nports * 10;
 			break;
 		case AD_LINK_SPEED_100MBPS:
-			bandwidth = aggregator->num_of_ports * 100;
+			bandwidth = nports * 100;
 			break;
 		case AD_LINK_SPEED_1000MBPS:
-			bandwidth = aggregator->num_of_ports * 1000;
+			bandwidth = nports * 1000;
 			break;
 		case AD_LINK_SPEED_2500MBPS:
-			bandwidth = aggregator->num_of_ports * 2500;
+			bandwidth = nports * 2500;
+			break;
+		case AD_LINK_SPEED_5000MBPS:
+			bandwidth = nports * 5000;
 			break;
 		case AD_LINK_SPEED_10000MBPS:
-			bandwidth = aggregator->num_of_ports * 10000;
+			bandwidth = nports * 10000;
 			break;
 		case AD_LINK_SPEED_20000MBPS:
-			bandwidth = aggregator->num_of_ports * 20000;
+			bandwidth = nports * 20000;
+			break;
+		case AD_LINK_SPEED_25000MBPS:
+			bandwidth = nports * 25000;
 			break;
 		case AD_LINK_SPEED_40000MBPS:
-			bandwidth = aggregator->num_of_ports * 40000;
+			bandwidth = nports * 40000;
+			break;
+		case AD_LINK_SPEED_50000MBPS:
+			bandwidth = nports * 50000;
 			break;
 		case AD_LINK_SPEED_56000MBPS:
-			bandwidth = aggregator->num_of_ports * 56000;
+			bandwidth = nports * 56000;
+			break;
+		case AD_LINK_SPEED_100000MBPS:
+			bandwidth = nports * 100000;
 			break;
 		default:
 			bandwidth = 0; /* to silence the compiler */
@@ -1513,10 +1567,10 @@
 
 	switch (__get_agg_selection_mode(curr->lag_ports)) {
 	case BOND_AD_COUNT:
-		if (curr->num_of_ports > best->num_of_ports)
+		if (__agg_active_ports(curr) > __agg_active_ports(best))
 			return curr;
 
-		if (curr->num_of_ports < best->num_of_ports)
+		if (__agg_active_ports(curr) < __agg_active_ports(best))
 			return best;
 
 		/*FALLTHROUGH*/
@@ -1544,8 +1598,14 @@
 	if (!port)
 		return 0;
 
-	return netif_running(port->slave->dev) &&
-	       netif_carrier_ok(port->slave->dev);
+	for (port = agg->lag_ports; port;
+	     port = port->next_port_in_aggregator) {
+		if (netif_running(port->slave->dev) &&
+		    netif_carrier_ok(port->slave->dev))
+			return 1;
+	}
+
+	return 0;
 }
 
 /**
@@ -1593,7 +1653,7 @@
 
 		agg->is_active = 0;
 
-		if (agg->num_of_ports && agg_device_up(agg))
+		if (__agg_active_ports(agg) && agg_device_up(agg))
 			best = ad_agg_selection_test(best, agg);
 	}
 
@@ -1605,7 +1665,7 @@
 		 * answering partner.
 		 */
 		if (active && active->lag_ports &&
-		    active->lag_ports->is_enabled &&
+		    __agg_active_ports(active) &&
 		    (__agg_has_partner(active) ||
 		     (!__agg_has_partner(active) &&
 		     !__agg_has_partner(best)))) {
@@ -1701,7 +1761,7 @@
 		aggregator->is_individual = false;
 		aggregator->actor_admin_aggregator_key = 0;
 		aggregator->actor_oper_aggregator_key = 0;
-		aggregator->partner_system = null_mac_addr;
+		eth_zero_addr(aggregator->partner_system.mac_addr_value);
 		aggregator->partner_system_priority = 0;
 		aggregator->partner_oper_aggregator_key = 0;
 		aggregator->receive_state = 0;
@@ -1723,7 +1783,7 @@
 	if (aggregator) {
 		ad_clear_agg(aggregator);
 
-		aggregator->aggregator_mac_address = null_mac_addr;
+		eth_zero_addr(aggregator->aggregator_mac_address.mac_addr_value);
 		aggregator->aggregator_identifier = 0;
 		aggregator->slave = NULL;
 	}
@@ -2011,6 +2071,9 @@
 		   aggregator->aggregator_identifier);
 
 	/* Tell the partner that this port is not suitable for aggregation */
+	port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
+	port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
+	port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
 	port->actor_oper_port_state &= ~AD_STATE_AGGREGATION;
 	__update_lacpdu_from_port(port);
 	ad_lacpdu_send(port);
@@ -2118,7 +2181,7 @@
 				else
 					temp_aggregator->lag_ports = temp_port->next_port_in_aggregator;
 				temp_aggregator->num_of_ports--;
-				if (temp_aggregator->num_of_ports == 0) {
+				if (__agg_active_ports(temp_aggregator) == 0) {
 					select_new_active_agg = temp_aggregator->is_active;
 					ad_clear_agg(temp_aggregator);
 					if (select_new_active_agg) {
@@ -2385,7 +2448,9 @@
  */
 void bond_3ad_handle_link_change(struct slave *slave, char link)
 {
+	struct aggregator *agg;
 	struct port *port;
+	bool dummy;
 
 	port = &(SLAVE_AD_INFO(slave)->port);
 
@@ -2412,6 +2477,9 @@
 		port->is_enabled = false;
 		ad_update_actor_keys(port, true);
 	}
+	agg = __get_first_agg(port);
+	ad_agg_selection_logic(agg, &dummy);
+
 	netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n",
 		   port->actor_port_number,
 		   link == BOND_LINK_UP ? "UP" : "DOWN");
@@ -2452,7 +2520,7 @@
 	active = __get_active_agg(&(SLAVE_AD_INFO(first_slave)->aggregator));
 	if (active) {
 		/* are enough slaves available to consider link up? */
-		if (active->num_of_ports < bond->params.min_links) {
+		if (__agg_active_ports(active) < bond->params.min_links) {
 			if (netif_carrier_ok(bond->dev)) {
 				netif_carrier_off(bond->dev);
 				goto out;
--- linux-4.4.0.orig/drivers/net/bonding/bond_alb.c
+++ linux-4.4.0/drivers/net/bonding/bond_alb.c
@@ -42,13 +42,10 @@
 
 
 
-#ifndef __long_aligned
-#define __long_aligned __attribute__((aligned((sizeof(long)))))
-#endif
-static const u8 mac_bcast[ETH_ALEN] __long_aligned = {
+static const u8 mac_bcast[ETH_ALEN + 2] __long_aligned = {
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 };
-static const u8 mac_v6_allmcast[ETH_ALEN] __long_aligned = {
+static const u8 mac_v6_allmcast[ETH_ALEN + 2] __long_aligned = {
 	0x33, 0x33, 0x00, 0x00, 0x00, 0x01
 };
 static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC;
@@ -74,11 +71,6 @@
 };
 #pragma pack()
 
-static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb)
-{
-	return (struct arp_pkt *)skb_network_header(skb);
-}
-
 /* Forward declaration */
 static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
 				      bool strict_match);
@@ -453,7 +445,7 @@
 {
 	int i;
 
-	if (!client_info->slave)
+	if (!client_info->slave || !is_valid_ether_addr(client_info->mac_dst))
 		return;
 
 	for (i = 0; i < RLB_ARP_BURST_SIZE; i++) {
@@ -577,10 +569,11 @@
 	spin_unlock(&bond->mode_lock);
 }
 
-static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond)
+static struct slave *rlb_choose_channel(struct sk_buff *skb,
+					struct bonding *bond,
+					const struct arp_pkt *arp)
 {
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
-	struct arp_pkt *arp = arp_pkt(skb);
 	struct slave *assigned_slave, *curr_active_slave;
 	struct rlb_client_info *client_info;
 	u32 hash_index = 0;
@@ -677,8 +670,12 @@
  */
 static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
 {
-	struct arp_pkt *arp = arp_pkt(skb);
 	struct slave *tx_slave = NULL;
+	struct arp_pkt *arp;
+
+	if (!pskb_network_may_pull(skb, sizeof(*arp)))
+		return NULL;
+	arp = (struct arp_pkt *)skb_network_header(skb);
 
 	/* Don't modify or load balance ARPs that do not originate locally
 	 * (e.g.,arrive via a bridge).
@@ -688,7 +685,7 @@
 
 	if (arp->op_code == htons(ARPOP_REPLY)) {
 		/* the arp must be sent on the selected rx channel */
-		tx_slave = rlb_choose_channel(skb, bond);
+		tx_slave = rlb_choose_channel(skb, bond, arp);
 		if (tx_slave)
 			ether_addr_copy(arp->mac_src, tx_slave->dev->dev_addr);
 		netdev_dbg(bond->dev, "Server sent ARP Reply packet\n");
@@ -698,7 +695,7 @@
 		 * When the arp reply is received the entry will be updated
 		 * with the correct unicast address of the client.
 		 */
-		rlb_choose_channel(skb, bond);
+		rlb_choose_channel(skb, bond, arp);
 
 		/* The ARP reply packets must be delayed so that
 		 * they can cancel out the influence of the ARP request.
@@ -1371,26 +1368,31 @@
 	bool do_tx_balance = true;
 	u32 hash_index = 0;
 	const u8 *hash_start = NULL;
-	struct ipv6hdr *ip6hdr;
 
 	skb_reset_mac_header(skb);
 	eth_data = eth_hdr(skb);
 
 	switch (ntohs(skb->protocol)) {
 	case ETH_P_IP: {
-		const struct iphdr *iph = ip_hdr(skb);
+		const struct iphdr *iph;
 
 		if (ether_addr_equal_64bits(eth_data->h_dest, mac_bcast) ||
-		    (iph->daddr == ip_bcast) ||
-		    (iph->protocol == IPPROTO_IGMP)) {
+		    (!pskb_network_may_pull(skb, sizeof(*iph)))) {
+			do_tx_balance = false;
+			break;
+		}
+		iph = ip_hdr(skb);
+		if (iph->daddr == ip_bcast || iph->protocol == IPPROTO_IGMP) {
 			do_tx_balance = false;
 			break;
 		}
 		hash_start = (char *)&(iph->daddr);
 		hash_size = sizeof(iph->daddr);
-	}
 		break;
-	case ETH_P_IPV6:
+	}
+	case ETH_P_IPV6: {
+		const struct ipv6hdr *ip6hdr;
+
 		/* IPv6 doesn't really use broadcast mac address, but leave
 		 * that here just in case.
 		 */
@@ -1407,7 +1409,11 @@
 			break;
 		}
 
-		/* Additianally, DAD probes should not be tx-balanced as that
+		if (!pskb_network_may_pull(skb, sizeof(*ip6hdr))) {
+			do_tx_balance = false;
+			break;
+		}
+		/* Additionally, DAD probes should not be tx-balanced as that
 		 * will lead to false positives for duplicate addresses and
 		 * prevent address configuration from working.
 		 */
@@ -1417,17 +1423,26 @@
 			break;
 		}
 
-		hash_start = (char *)&(ipv6_hdr(skb)->daddr);
-		hash_size = sizeof(ipv6_hdr(skb)->daddr);
+		hash_start = (char *)&ip6hdr->daddr;
+		hash_size = sizeof(ip6hdr->daddr);
 		break;
-	case ETH_P_IPX:
-		if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) {
+	}
+	case ETH_P_IPX: {
+		const struct ipxhdr *ipxhdr;
+
+		if (pskb_network_may_pull(skb, sizeof(*ipxhdr))) {
+			do_tx_balance = false;
+			break;
+		}
+		ipxhdr = (struct ipxhdr *)skb_network_header(skb);
+
+		if (ipxhdr->ipx_checksum != IPX_NO_CHECKSUM) {
 			/* something is wrong with this packet */
 			do_tx_balance = false;
 			break;
 		}
 
-		if (ipx_hdr(skb)->ipx_type != IPX_TYPE_NCP) {
+		if (ipxhdr->ipx_type != IPX_TYPE_NCP) {
 			/* The only protocol worth balancing in
 			 * this family since it has an "ARP" like
 			 * mechanism
@@ -1436,9 +1451,11 @@
 			break;
 		}
 
+		eth_data = eth_hdr(skb);
 		hash_start = (char *)eth_data->h_dest;
 		hash_size = ETH_ALEN;
 		break;
+	}
 	case ETH_P_ARP:
 		do_tx_balance = false;
 		if (bond_info->rlb_enabled)
--- linux-4.4.0.orig/drivers/net/bonding/bond_main.c
+++ linux-4.4.0/drivers/net/bonding/bond_main.c
@@ -214,6 +214,9 @@
 static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
 						struct rtnl_link_stats64 *stats);
 static void bond_slave_arr_handler(struct work_struct *work);
+static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act,
+				  int mod);
+static void bond_netdev_notify_work(struct work_struct *work);
 
 /*---------------------------- General routines -----------------------------*/
 
@@ -830,7 +833,8 @@
 			}
 
 			new_active->delay = 0;
-			bond_set_slave_link_state(new_active, BOND_LINK_UP);
+			bond_set_slave_link_state(new_active, BOND_LINK_UP,
+						  BOND_SLAVE_NOTIFY_NOW);
 
 			if (BOND_MODE(bond) == BOND_MODE_8023AD)
 				bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
@@ -972,16 +976,13 @@
 	struct slave *slave = NULL;
 	struct list_head *iter;
 	struct ad_info ad_info;
-	struct netpoll_info *ni;
-	const struct net_device_ops *ops;
 
 	if (BOND_MODE(bond) == BOND_MODE_8023AD)
 		if (bond_3ad_get_active_agg_info(bond, &ad_info))
 			return;
 
 	bond_for_each_slave_rcu(bond, slave, iter) {
-		ops = slave->dev->netdev_ops;
-		if (!bond_slave_is_up(slave) || !ops->ndo_poll_controller)
+		if (!bond_slave_is_up(slave))
 			continue;
 
 		if (BOND_MODE(bond) == BOND_MODE_8023AD) {
@@ -993,11 +994,7 @@
 				continue;
 		}
 
-		ni = rcu_dereference_bh(slave->dev->npinfo);
-		if (down_trylock(&ni->dev_lock))
-			continue;
-		ops->ndo_poll_controller(slave->dev);
-		up(&ni->dev_lock);
+		netpoll_poll_dev(slave->dev);
 	}
 }
 
@@ -1104,11 +1101,13 @@
 		gso_max_size = min(gso_max_size, slave->dev->gso_max_size);
 		gso_max_segs = min(gso_max_segs, slave->dev->gso_max_segs);
 	}
+	bond_dev->hard_header_len = max_hard_header_len;
 
 done:
 	bond_dev->vlan_features = vlan_features;
-	bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL;
-	bond_dev->hard_header_len = max_hard_header_len;
+	bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
+				    NETIF_F_HW_VLAN_CTAG_TX |
+				    NETIF_F_HW_VLAN_STAG_TX;
 	bond_dev->gso_max_segs = gso_max_segs;
 	netif_set_gso_max_size(bond_dev, gso_max_size);
 
@@ -1127,6 +1126,7 @@
 
 	bond_dev->type		    = slave_dev->type;
 	bond_dev->hard_header_len   = slave_dev->hard_header_len;
+	bond_dev->needed_headroom   = slave_dev->needed_headroom;
 	bond_dev->addr_len	    = slave_dev->addr_len;
 
 	memcpy(bond_dev->broadcast, slave_dev->broadcast,
@@ -1207,7 +1207,6 @@
 	err = netdev_master_upper_dev_link_private(slave_dev, bond_dev, slave);
 	if (err)
 		return err;
-	slave_dev->flags |= IFF_SLAVE;
 	rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE, GFP_KERNEL);
 	return 0;
 }
@@ -1220,7 +1219,39 @@
 	rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE, GFP_KERNEL);
 }
 
-static struct slave *bond_alloc_slave(struct bonding *bond)
+static void slave_kobj_release(struct kobject *kobj)
+{
+	struct slave *slave = to_slave(kobj);
+	struct bonding *bond = bond_get_bond_by_slave(slave);
+
+	cancel_delayed_work_sync(&slave->notify_work);
+	if (BOND_MODE(bond) == BOND_MODE_8023AD)
+		kfree(SLAVE_AD_INFO(slave));
+
+	kfree(slave);
+}
+
+static struct kobj_type slave_ktype = {
+	.release = slave_kobj_release,
+#ifdef CONFIG_SYSFS
+	.sysfs_ops = &slave_sysfs_ops,
+#endif
+};
+
+static int bond_kobj_init(struct slave *slave)
+{
+	int err;
+
+	err = kobject_init_and_add(&slave->kobj, &slave_ktype,
+				   &(slave->dev->dev.kobj), "bonding_slave");
+	if (err)
+		kobject_put(&slave->kobj);
+
+	return err;
+}
+
+static struct slave *bond_alloc_slave(struct bonding *bond,
+				      struct net_device *slave_dev)
 {
 	struct slave *slave = NULL;
 
@@ -1228,25 +1259,23 @@
 	if (!slave)
 		return NULL;
 
+	slave->bond = bond;
+	slave->dev = slave_dev;
+
+	if (bond_kobj_init(slave))
+		return NULL;
+
 	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
 		SLAVE_AD_INFO(slave) = kzalloc(sizeof(struct ad_slave_info),
 					       GFP_KERNEL);
 		if (!SLAVE_AD_INFO(slave)) {
-			kfree(slave);
+			kobject_put(&slave->kobj);
 			return NULL;
 		}
 	}
-	return slave;
-}
+	INIT_DELAYED_WORK(&slave->notify_work, bond_netdev_notify_work);
 
-static void bond_free_slave(struct slave *slave)
-{
-	struct bonding *bond = bond_get_bond_by_slave(slave);
-
-	if (BOND_MODE(bond) == BOND_MODE_8023AD)
-		kfree(SLAVE_AD_INFO(slave));
-
-	kfree(slave);
+	return slave;
 }
 
 static void bond_fill_ifbond(struct bonding *bond, struct ifbond *info)
@@ -1264,39 +1293,26 @@
 	info->link_failure_count = slave->link_failure_count;
 }
 
-static void bond_netdev_notify(struct net_device *dev,
-			       struct netdev_bonding_info *info)
-{
-	rtnl_lock();
-	netdev_bonding_info_change(dev, info);
-	rtnl_unlock();
-}
-
 static void bond_netdev_notify_work(struct work_struct *_work)
 {
-	struct netdev_notify_work *w =
-		container_of(_work, struct netdev_notify_work, work.work);
+	struct slave *slave = container_of(_work, struct slave,
+					   notify_work.work);
 
-	bond_netdev_notify(w->dev, &w->bonding_info);
-	dev_put(w->dev);
-	kfree(w);
+	if (rtnl_trylock()) {
+		struct netdev_bonding_info binfo;
+
+		bond_fill_ifslave(slave, &binfo.slave);
+		bond_fill_ifbond(slave->bond, &binfo.master);
+		netdev_bonding_info_change(slave->dev, &binfo);
+		rtnl_unlock();
+	} else {
+		queue_delayed_work(slave->bond->wq, &slave->notify_work, 1);
+	}
 }
 
 void bond_queue_slave_event(struct slave *slave)
 {
-	struct bonding *bond = slave->bond;
-	struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC);
-
-	if (!nnw)
-		return;
-
-	dev_hold(slave->dev);
-	nnw->dev = slave->dev;
-	bond_fill_ifslave(slave, &nnw->bonding_info.slave);
-	bond_fill_ifbond(bond, &nnw->bonding_info.master);
-	INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work);
-
-	queue_delayed_work(slave->bond->wq, &nnw->work, 0);
+	queue_delayed_work(slave->bond->wq, &slave->notify_work, 0);
 }
 
 /* enslave device <slave> to bond device <master> */
@@ -1316,9 +1332,10 @@
 			    slave_dev->name);
 	}
 
-	/* already enslaved */
-	if (slave_dev->flags & IFF_SLAVE) {
-		netdev_dbg(bond_dev, "Error: Device was already enslaved\n");
+	/* already in-use? */
+	if (netdev_is_rx_handler_busy(slave_dev)) {
+		netdev_err(bond_dev,
+			   "Error: Device is in use and cannot be enslaved\n");
 		return -EBUSY;
 	}
 
@@ -1400,7 +1417,16 @@
 		goto err_undo_flags;
 	}
 
-	if (slave_ops->ndo_set_mac_address == NULL) {
+	if (slave_dev->type == ARPHRD_INFINIBAND &&
+	    BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
+		netdev_warn(bond_dev, "Type (%d) supports only active-backup mode\n",
+			    slave_dev->type);
+		res = -EOPNOTSUPP;
+		goto err_undo_flags;
+	}
+
+	if (!slave_ops->ndo_set_mac_address ||
+	    slave_dev->type == ARPHRD_INFINIBAND) {
 		netdev_warn(bond_dev, "The slave device specified does not support setting the MAC address\n");
 		if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
 		    bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
@@ -1424,14 +1450,12 @@
 	    bond->dev->addr_assign_type == NET_ADDR_RANDOM)
 		bond_set_dev_addr(bond->dev, slave_dev);
 
-	new_slave = bond_alloc_slave(bond);
+	new_slave = bond_alloc_slave(bond, slave_dev);
 	if (!new_slave) {
 		res = -ENOMEM;
 		goto err_undo_flags;
 	}
 
-	new_slave->bond = bond;
-	new_slave->dev = slave_dev;
 	/* Set the new_slave's queue_id to be zero.  Queue ID mapping
 	 * is set via sysfs or module option if desired.
 	 */
@@ -1465,6 +1489,9 @@
 		}
 	}
 
+	/* set slave flag before open to prevent IPv6 addrconf */
+	slave_dev->flags |= IFF_SLAVE;
+
 	/* open the slave since the application closed it */
 	res = dev_open(slave_dev);
 	if (res) {
@@ -1485,39 +1512,6 @@
 			goto err_close;
 	}
 
-	/* If the mode uses primary, then the following is handled by
-	 * bond_change_active_slave().
-	 */
-	if (!bond_uses_primary(bond)) {
-		/* set promiscuity level to new slave */
-		if (bond_dev->flags & IFF_PROMISC) {
-			res = dev_set_promiscuity(slave_dev, 1);
-			if (res)
-				goto err_close;
-		}
-
-		/* set allmulti level to new slave */
-		if (bond_dev->flags & IFF_ALLMULTI) {
-			res = dev_set_allmulti(slave_dev, 1);
-			if (res)
-				goto err_close;
-		}
-
-		netif_addr_lock_bh(bond_dev);
-
-		dev_mc_sync_multiple(slave_dev, bond_dev);
-		dev_uc_sync_multiple(slave_dev, bond_dev);
-
-		netif_addr_unlock_bh(bond_dev);
-	}
-
-	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
-		/* add lacpdu mc addr to mc list */
-		u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
-
-		dev_mc_add(slave_dev, lacpdu_multicast);
-	}
-
 	res = vlan_vids_add_by_dev(slave_dev, bond_dev);
 	if (res) {
 		netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n",
@@ -1563,21 +1557,26 @@
 		if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) {
 			if (bond->params.updelay) {
 				bond_set_slave_link_state(new_slave,
-							  BOND_LINK_BACK);
+							  BOND_LINK_BACK,
+							  BOND_SLAVE_NOTIFY_NOW);
 				new_slave->delay = bond->params.updelay;
 			} else {
 				bond_set_slave_link_state(new_slave,
-							  BOND_LINK_UP);
+							  BOND_LINK_UP,
+							  BOND_SLAVE_NOTIFY_NOW);
 			}
 		} else {
-			bond_set_slave_link_state(new_slave, BOND_LINK_DOWN);
+			bond_set_slave_link_state(new_slave, BOND_LINK_DOWN,
+						  BOND_SLAVE_NOTIFY_NOW);
 		}
 	} else if (bond->params.arp_interval) {
 		bond_set_slave_link_state(new_slave,
 					  (netif_carrier_ok(slave_dev) ?
-					  BOND_LINK_UP : BOND_LINK_DOWN));
+					  BOND_LINK_UP : BOND_LINK_DOWN),
+					  BOND_SLAVE_NOTIFY_NOW);
 	} else {
-		bond_set_slave_link_state(new_slave, BOND_LINK_UP);
+		bond_set_slave_link_state(new_slave, BOND_LINK_UP,
+					  BOND_SLAVE_NOTIFY_NOW);
 	}
 
 	if (new_slave->link != BOND_LINK_DOWN)
@@ -1642,8 +1641,7 @@
 	} /* switch(bond_mode) */
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-	slave_dev->npinfo = bond->dev->npinfo;
-	if (slave_dev->npinfo) {
+	if (bond->dev->npinfo) {
 		if (slave_enable_netpoll(new_slave)) {
 			netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n");
 			res = -EBUSY;
@@ -1674,6 +1672,40 @@
 		goto err_upper_unlink;
 	}
 
+	/* If the mode uses primary, then the following is handled by
+	 * bond_change_active_slave().
+	 */
+	if (!bond_uses_primary(bond)) {
+		/* set promiscuity level to new slave */
+		if (bond_dev->flags & IFF_PROMISC) {
+			res = dev_set_promiscuity(slave_dev, 1);
+			if (res)
+				goto err_sysfs_del;
+		}
+
+		/* set allmulti level to new slave */
+		if (bond_dev->flags & IFF_ALLMULTI) {
+			res = dev_set_allmulti(slave_dev, 1);
+			if (res) {
+				if (bond_dev->flags & IFF_PROMISC)
+					dev_set_promiscuity(slave_dev, -1);
+				goto err_sysfs_del;
+			}
+		}
+
+		netif_addr_lock_bh(bond_dev);
+		dev_mc_sync_multiple(slave_dev, bond_dev);
+		dev_uc_sync_multiple(slave_dev, bond_dev);
+		netif_addr_unlock_bh(bond_dev);
+
+		if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+			/* add lacpdu mc addr to mc list */
+			u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
+
+			dev_mc_add(slave_dev, lacpdu_multicast);
+		}
+	}
+
 	bond->slave_cnt++;
 	bond_compute_features(bond);
 	bond_set_carrier(bond);
@@ -1697,6 +1729,9 @@
 	return 0;
 
 /* Undo stages on error */
+err_sysfs_del:
+	bond_sysfs_slave_del(new_slave);
+
 err_upper_unlink:
 	bond_upper_dev_unlink(bond_dev, slave_dev);
 
@@ -1704,9 +1739,6 @@
 	netdev_rx_handler_unregister(slave_dev);
 
 err_detach:
-	if (!bond_uses_primary(bond))
-		bond_hw_addr_flush(bond_dev, slave_dev);
-
 	vlan_vids_del_by_dev(slave_dev, bond_dev);
 	if (rcu_access_pointer(bond->primary_slave) == new_slave)
 		RCU_INIT_POINTER(bond->primary_slave, NULL);
@@ -1721,10 +1753,12 @@
 	slave_disable_netpoll(new_slave);
 
 err_close:
-	slave_dev->priv_flags &= ~IFF_BONDING;
+	if (!netif_is_bond_master(slave_dev))
+		slave_dev->priv_flags &= ~IFF_BONDING;
 	dev_close(slave_dev);
 
 err_restore_mac:
+	slave_dev->flags &= ~IFF_SLAVE;
 	if (!bond->params.fail_over_mac ||
 	    BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
 		/* XXX TODO - fom follow mode needs to change master's
@@ -1740,7 +1774,7 @@
 	dev_set_mtu(slave_dev, new_slave->original_mtu);
 
 err_free:
-	bond_free_slave(new_slave);
+	kobject_put(&new_slave->kobj);
 
 err_undo_flags:
 	/* Enslave of first slave has failed and we need to fix master's mac */
@@ -1772,7 +1806,7 @@
  */
 static int __bond_release_one(struct net_device *bond_dev,
 			      struct net_device *slave_dev,
-			      bool all)
+			      bool all, bool unregister)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *oldcurrent;
@@ -1914,11 +1948,15 @@
 		dev_set_mac_address(slave_dev, &addr);
 	}
 
-	dev_set_mtu(slave_dev, slave->original_mtu);
+	if (unregister)
+		__dev_set_mtu(slave_dev, slave->original_mtu);
+	else
+		dev_set_mtu(slave_dev, slave->original_mtu);
 
-	slave_dev->priv_flags &= ~IFF_BONDING;
+	if (!netif_is_bond_master(slave_dev))
+		slave_dev->priv_flags &= ~IFF_BONDING;
 
-	bond_free_slave(slave);
+	kobject_put(&slave->kobj);
 
 	return 0;
 }
@@ -1926,7 +1964,7 @@
 /* A wrapper used because of ndo_del_link */
 int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 {
-	return __bond_release_one(bond_dev, slave_dev, false);
+	return __bond_release_one(bond_dev, slave_dev, false, false);
 }
 
 /* First release a slave and then destroy the bond if no more slaves are left.
@@ -1938,8 +1976,9 @@
 	struct bonding *bond = netdev_priv(bond_dev);
 	int ret;
 
-	ret = bond_release(bond_dev, slave_dev);
-	if (ret == 0 && !bond_has_slaves(bond)) {
+	ret = __bond_release_one(bond_dev, slave_dev, false, true);
+	if (ret == 0 && !bond_has_slaves(bond) &&
+	    bond_dev->reg_state != NETREG_UNREGISTERING) {
 		bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
 		netdev_info(bond_dev, "Destroying bond %s\n",
 			    bond_dev->name);
@@ -1996,7 +2035,8 @@
 			if (link_state)
 				continue;
 
-			bond_set_slave_link_state(slave, BOND_LINK_FAIL);
+			bond_set_slave_link_state(slave, BOND_LINK_FAIL,
+						  BOND_SLAVE_NOTIFY_LATER);
 			slave->delay = bond->params.downdelay;
 			if (slave->delay) {
 				netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n",
@@ -2011,7 +2051,8 @@
 		case BOND_LINK_FAIL:
 			if (link_state) {
 				/* recovered before downdelay expired */
-				bond_set_slave_link_state(slave, BOND_LINK_UP);
+				bond_set_slave_link_state(slave, BOND_LINK_UP,
+							  BOND_SLAVE_NOTIFY_LATER);
 				slave->last_link_up = jiffies;
 				netdev_info(bond->dev, "link status up again after %d ms for interface %s\n",
 					    (bond->params.downdelay - slave->delay) *
@@ -2033,7 +2074,8 @@
 			if (!link_state)
 				continue;
 
-			bond_set_slave_link_state(slave, BOND_LINK_BACK);
+			bond_set_slave_link_state(slave, BOND_LINK_BACK,
+						  BOND_SLAVE_NOTIFY_LATER);
 			slave->delay = bond->params.updelay;
 
 			if (slave->delay) {
@@ -2047,7 +2089,8 @@
 		case BOND_LINK_BACK:
 			if (!link_state) {
 				bond_set_slave_link_state(slave,
-							  BOND_LINK_DOWN);
+							  BOND_LINK_DOWN,
+							  BOND_SLAVE_NOTIFY_LATER);
 				netdev_info(bond->dev, "link status down again after %d ms for interface %s\n",
 					    (bond->params.updelay - slave->delay) *
 					    bond->params.miimon,
@@ -2082,10 +2125,20 @@
 	bond_for_each_slave(bond, slave, iter) {
 		switch (slave->new_link) {
 		case BOND_LINK_NOCHANGE:
+			/* For 802.3ad mode, check current slave speed and
+			 * duplex again in case its port was disabled after
+			 * invalid speed/duplex reporting but recovered before
+			 * link monitoring could make a decision on the actual
+			 * link status
+			 */
+			if (BOND_MODE(bond) == BOND_MODE_8023AD &&
+			    slave->link == BOND_LINK_UP)
+				bond_3ad_adapter_speed_duplex_changed(slave);
 			continue;
 
 		case BOND_LINK_UP:
-			bond_set_slave_link_state(slave, BOND_LINK_UP);
+			bond_set_slave_link_state(slave, BOND_LINK_UP,
+						  BOND_SLAVE_NOTIFY_NOW);
 			slave->last_link_up = jiffies;
 
 			primary = rtnl_dereference(bond->primary_slave);
@@ -2125,7 +2178,8 @@
 			if (slave->link_failure_count < UINT_MAX)
 				slave->link_failure_count++;
 
-			bond_set_slave_link_state(slave, BOND_LINK_DOWN);
+			bond_set_slave_link_state(slave, BOND_LINK_DOWN,
+						  BOND_SLAVE_NOTIFY_NOW);
 
 			if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
 			    BOND_MODE(bond) == BOND_MODE_8023AD)
@@ -2415,7 +2469,7 @@
 		 struct slave *slave)
 {
 	struct arphdr *arp = (struct arphdr *)skb->data;
-	struct slave *curr_active_slave;
+	struct slave *curr_active_slave, *curr_arp_slave;
 	unsigned char *arp_ptr;
 	__be32 sip, tip;
 	int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP);
@@ -2462,26 +2516,41 @@
 		     &sip, &tip);
 
 	curr_active_slave = rcu_dereference(bond->curr_active_slave);
+	curr_arp_slave = rcu_dereference(bond->current_arp_slave);
 
-	/* Backup slaves won't see the ARP reply, but do come through
-	 * here for each ARP probe (so we swap the sip/tip to validate
-	 * the probe).  In a "redundant switch, common router" type of
-	 * configuration, the ARP probe will (hopefully) travel from
-	 * the active, through one switch, the router, then the other
-	 * switch before reaching the backup.
+	/* We 'trust' the received ARP enough to validate it if:
+	 *
+	 * (a) the slave receiving the ARP is active (which includes the
+	 * current ARP slave, if any), or
+	 *
+	 * (b) the receiving slave isn't active, but there is a currently
+	 * active slave and it received valid arp reply(s) after it became
+	 * the currently active slave, or
 	 *
-	 * We 'trust' the arp requests if there is an active slave and
-	 * it received valid arp reply(s) after it became active. This
-	 * is done to avoid endless looping when we can't reach the
+	 * (c) there is an ARP slave that sent an ARP during the prior ARP
+	 * interval, and we receive an ARP reply on any slave.  We accept
+	 * these because switch FDB update delays may deliver the ARP
+	 * reply to a slave other than the sender of the ARP request.
+	 *
+	 * Note: for (b), backup slaves are receiving the broadcast ARP
+	 * request, not a reply.  This request passes from the sending
+	 * slave through the L2 switch(es) to the receiving slave.  Since
+	 * this is checking the request, sip/tip are swapped for
+	 * validation.
+	 *
+	 * This is done to avoid endless looping when we can't reach the
 	 * arp_ip_target and fool ourselves with our own arp requests.
 	 */
-
 	if (bond_is_active_slave(slave))
 		bond_validate_arp(bond, slave, sip, tip);
 	else if (curr_active_slave &&
 		 time_after(slave_last_rx(bond, curr_active_slave),
 			    curr_active_slave->last_link_up))
 		bond_validate_arp(bond, slave, tip, sip);
+	else if (curr_arp_slave && (arp->ar_op == htons(ARPOP_REPLY)) &&
+		 bond_time_in_interval(bond,
+				       dev_trans_start(curr_arp_slave->dev), 1))
+		bond_validate_arp(bond, slave, sip, tip);
 
 out_unlock:
 	if (arp != (struct arphdr *)skb->data)
@@ -2534,11 +2603,13 @@
 	bond_for_each_slave_rcu(bond, slave, iter) {
 		unsigned long trans_start = dev_trans_start(slave->dev);
 
+		slave->new_link = BOND_LINK_NOCHANGE;
+
 		if (slave->link != BOND_LINK_UP) {
 			if (bond_time_in_interval(bond, trans_start, 1) &&
 			    bond_time_in_interval(bond, slave->last_rx, 1)) {
 
-				slave->link  = BOND_LINK_UP;
+				slave->new_link = BOND_LINK_UP;
 				slave_state_changed = 1;
 
 				/* primary_slave has no meaning in round-robin
@@ -2565,7 +2636,7 @@
 			if (!bond_time_in_interval(bond, trans_start, 2) ||
 			    !bond_time_in_interval(bond, slave->last_rx, 2)) {
 
-				slave->link  = BOND_LINK_DOWN;
+				slave->new_link = BOND_LINK_DOWN;
 				slave_state_changed = 1;
 
 				if (slave->link_failure_count < UINT_MAX)
@@ -2596,6 +2667,11 @@
 		if (!rtnl_trylock())
 			goto re_arm;
 
+		bond_for_each_slave(bond, slave, iter) {
+			if (slave->new_link != BOND_LINK_NOCHANGE)
+				slave->link = slave->new_link;
+		}
+
 		if (slave_state_changed) {
 			bond_slave_state_change(bond);
 			if (BOND_MODE(bond) == BOND_MODE_XOR)
@@ -2708,7 +2784,8 @@
 				struct slave *current_arp_slave;
 
 				current_arp_slave = rtnl_dereference(bond->current_arp_slave);
-				bond_set_slave_link_state(slave, BOND_LINK_UP);
+				bond_set_slave_link_state(slave, BOND_LINK_UP,
+							  BOND_SLAVE_NOTIFY_NOW);
 				if (current_arp_slave) {
 					bond_set_slave_inactive_flags(
 						current_arp_slave,
@@ -2731,7 +2808,8 @@
 			if (slave->link_failure_count < UINT_MAX)
 				slave->link_failure_count++;
 
-			bond_set_slave_link_state(slave, BOND_LINK_DOWN);
+			bond_set_slave_link_state(slave, BOND_LINK_DOWN,
+						  BOND_SLAVE_NOTIFY_NOW);
 			bond_set_slave_inactive_flags(slave,
 						      BOND_SLAVE_NOTIFY_NOW);
 
@@ -2810,7 +2888,8 @@
 		 * up when it is actually down
 		 */
 		if (!bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) {
-			bond_set_slave_link_state(slave, BOND_LINK_DOWN);
+			bond_set_slave_link_state(slave, BOND_LINK_DOWN,
+						  BOND_SLAVE_NOTIFY_LATER);
 			if (slave->link_failure_count < UINT_MAX)
 				slave->link_failure_count++;
 
@@ -2830,7 +2909,8 @@
 	if (!new_slave)
 		goto check_state;
 
-	bond_set_slave_link_state(new_slave, BOND_LINK_BACK);
+	bond_set_slave_link_state(new_slave, BOND_LINK_BACK,
+				  BOND_SLAVE_NOTIFY_LATER);
 	bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER);
 	bond_arp_send_all(bond, new_slave);
 	new_slave->last_link_up = jiffies;
@@ -2838,7 +2918,7 @@
 
 check_state:
 	bond_for_each_slave_rcu(bond, slave, iter) {
-		if (slave->should_notify) {
+		if (slave->should_notify || slave->should_notify_link) {
 			should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
 			break;
 		}
@@ -2893,8 +2973,10 @@
 		if (should_notify_peers)
 			call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
 						 bond->dev);
-		if (should_notify_rtnl)
+		if (should_notify_rtnl) {
 			bond_slave_state_notify(bond);
+			bond_slave_link_notify(bond);
+		}
 
 		rtnl_unlock();
 	}
@@ -2960,7 +3042,7 @@
 		if (bond_dev->type != ARPHRD_ETHER)
 			bond_release_and_destroy(bond_dev, slave_dev);
 		else
-			bond_release(bond_dev, slave_dev);
+			__bond_release_one(bond_dev, slave_dev, false, true);
 		break;
 	case NETDEV_UP:
 	case NETDEV_CHANGE:
@@ -3048,8 +3130,12 @@
 		return NOTIFY_DONE;
 
 	if (event_dev->flags & IFF_MASTER) {
+		int ret;
+
 		netdev_dbg(event_dev, "IFF_MASTER\n");
-		return bond_master_netdev_event(event, event_dev);
+		ret = bond_master_netdev_event(event, event_dev);
+		if (ret != NOTIFY_DONE)
+			return ret;
 	}
 
 	if (event_dev->flags & IFF_SLAVE) {
@@ -3145,7 +3231,7 @@
 	hash ^= (hash >> 16);
 	hash ^= (hash >> 8);
 
-	return hash;
+	return hash >> 1;
 }
 
 /*-------------------------- Device entry points ----------------------------*/
@@ -3240,6 +3326,35 @@
 	return 0;
 }
 
+/* fold stats, assuming all rtnl_link_stats64 fields are u64, but
+ * that some drivers can provide 32bit values only.
+ */
+static void bond_fold_stats(struct rtnl_link_stats64 *_res,
+			    const struct rtnl_link_stats64 *_new,
+			    const struct rtnl_link_stats64 *_old)
+{
+	const u64 *new = (const u64 *)_new;
+	const u64 *old = (const u64 *)_old;
+	u64 *res = (u64 *)_res;
+	int i;
+
+	for (i = 0; i < sizeof(*_res) / sizeof(u64); i++) {
+		u64 nv = new[i];
+		u64 ov = old[i];
+		s64 delta = nv - ov;
+
+		/* detects if this particular field is 32bit only */
+		if (((nv | ov) >> 32) == 0)
+			delta = (s64)(s32)((u32)nv - (u32)ov);
+
+		/* filter anomalies, some drivers reset their stats
+		 * at down/up events.
+		 */
+		if (delta > 0)
+			res[i] += delta;
+	}
+}
+
 static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
 						struct rtnl_link_stats64 *stats)
 {
@@ -3248,43 +3363,23 @@
 	struct list_head *iter;
 	struct slave *slave;
 
+	spin_lock(&bond->stats_lock);
 	memcpy(stats, &bond->bond_stats, sizeof(*stats));
 
-	bond_for_each_slave(bond, slave, iter) {
-		const struct rtnl_link_stats64 *sstats =
+	rcu_read_lock();
+	bond_for_each_slave_rcu(bond, slave, iter) {
+		const struct rtnl_link_stats64 *new =
 			dev_get_stats(slave->dev, &temp);
-		struct rtnl_link_stats64 *pstats = &slave->slave_stats;
 
-		stats->rx_packets +=  sstats->rx_packets - pstats->rx_packets;
-		stats->rx_bytes += sstats->rx_bytes - pstats->rx_bytes;
-		stats->rx_errors += sstats->rx_errors - pstats->rx_errors;
-		stats->rx_dropped += sstats->rx_dropped - pstats->rx_dropped;
-
-		stats->tx_packets += sstats->tx_packets - pstats->tx_packets;;
-		stats->tx_bytes += sstats->tx_bytes - pstats->tx_bytes;
-		stats->tx_errors += sstats->tx_errors - pstats->tx_errors;
-		stats->tx_dropped += sstats->tx_dropped - pstats->tx_dropped;
-
-		stats->multicast += sstats->multicast - pstats->multicast;
-		stats->collisions += sstats->collisions - pstats->collisions;
-
-		stats->rx_length_errors += sstats->rx_length_errors - pstats->rx_length_errors;
-		stats->rx_over_errors += sstats->rx_over_errors - pstats->rx_over_errors;
-		stats->rx_crc_errors += sstats->rx_crc_errors - pstats->rx_crc_errors;
-		stats->rx_frame_errors += sstats->rx_frame_errors - pstats->rx_frame_errors;
-		stats->rx_fifo_errors += sstats->rx_fifo_errors - pstats->rx_fifo_errors;
-		stats->rx_missed_errors += sstats->rx_missed_errors - pstats->rx_missed_errors;
-
-		stats->tx_aborted_errors += sstats->tx_aborted_errors - pstats->tx_aborted_errors;
-		stats->tx_carrier_errors += sstats->tx_carrier_errors - pstats->tx_carrier_errors;
-		stats->tx_fifo_errors += sstats->tx_fifo_errors - pstats->tx_fifo_errors;
-		stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors - pstats->tx_heartbeat_errors;
-		stats->tx_window_errors += sstats->tx_window_errors - pstats->tx_window_errors;
+		bond_fold_stats(stats, new, &slave->slave_stats);
 
 		/* save off the slave stats for the next run */
-		memcpy(pstats, sstats, sizeof(*sstats));
+		memcpy(&slave->slave_stats, new, sizeof(*new));
 	}
+	rcu_read_unlock();
+
 	memcpy(&bond->bond_stats, stats, sizeof(*stats));
+	spin_unlock(&bond->stats_lock);
 
 	return stats;
 }
@@ -3682,8 +3777,8 @@
 static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	struct iphdr *iph = ip_hdr(skb);
 	struct slave *slave;
+	int slave_cnt;
 	u32 slave_id;
 
 	/* Start with the curr_active_slave that joined the bond as the
@@ -3692,23 +3787,32 @@
 	 * send the join/membership reports.  The curr_active_slave found
 	 * will send all of this type of traffic.
 	 */
-	if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
-		slave = rcu_dereference(bond->curr_active_slave);
-		if (slave)
-			bond_dev_queue_xmit(bond, skb, slave->dev);
-		else
-			bond_xmit_slave_id(bond, skb, 0);
-	} else {
-		int slave_cnt = ACCESS_ONCE(bond->slave_cnt);
+	if (skb->protocol == htons(ETH_P_IP)) {
+		int noff = skb_network_offset(skb);
+		struct iphdr *iph;
 
-		if (likely(slave_cnt)) {
-			slave_id = bond_rr_gen_slave_id(bond);
-			bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
-		} else {
-			bond_tx_drop(bond_dev, skb);
+		if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
+			goto non_igmp;
+
+		iph = ip_hdr(skb);
+		if (iph->protocol == IPPROTO_IGMP) {
+			slave = rcu_dereference(bond->curr_active_slave);
+			if (slave)
+				bond_dev_queue_xmit(bond, skb, slave->dev);
+			else
+				bond_xmit_slave_id(bond, skb, 0);
+			return NETDEV_TX_OK;
 		}
 	}
 
+non_igmp:
+	slave_cnt = ACCESS_ONCE(bond->slave_cnt);
+	if (likely(slave_cnt)) {
+		slave_id = bond_rr_gen_slave_id(bond);
+		bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
+	} else {
+		bond_tx_drop(bond_dev, skb);
+	}
 	return NETDEV_TX_OK;
 }
 
@@ -3837,7 +3941,7 @@
 		 * this to-be-skipped slave to send a packet out.
 		 */
 		old_arr = rtnl_dereference(bond->slave_arr);
-		for (idx = 0; idx < old_arr->count; idx++) {
+		for (idx = 0; old_arr != NULL && idx < old_arr->count; idx++) {
 			if (skipslave == old_arr->arr[idx]) {
 				old_arr->arr[idx] =
 				    old_arr->arr[old_arr->count-1];
@@ -4003,13 +4107,23 @@
 	return ret;
 }
 
+static u32 bond_mode_bcast_speed(struct slave *slave, u32 speed)
+{
+	if (speed == 0 || speed == SPEED_UNKNOWN)
+		speed = slave->speed;
+	else
+		speed = min(speed, slave->speed);
+
+	return speed;
+}
+
 static int bond_ethtool_get_settings(struct net_device *bond_dev,
 				     struct ethtool_cmd *ecmd)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	unsigned long speed = 0;
 	struct list_head *iter;
 	struct slave *slave;
+	u32 speed = 0;
 
 	ecmd->duplex = DUPLEX_UNKNOWN;
 	ecmd->port = PORT_OTHER;
@@ -4021,8 +4135,13 @@
 	 */
 	bond_for_each_slave(bond, slave, iter) {
 		if (bond_slave_can_tx(slave)) {
-			if (slave->speed != SPEED_UNKNOWN)
-				speed += slave->speed;
+			if (slave->speed != SPEED_UNKNOWN) {
+				if (BOND_MODE(bond) == BOND_MODE_BROADCAST)
+					speed = bond_mode_bcast_speed(slave,
+								      speed);
+				else
+					speed += slave->speed;
+			}
 			if (ecmd->duplex == DUPLEX_UNKNOWN &&
 			    slave->duplex != DUPLEX_UNKNOWN)
 				ecmd->duplex = slave->duplex;
@@ -4098,6 +4217,7 @@
 	struct bonding *bond = netdev_priv(bond_dev);
 
 	spin_lock_init(&bond->mode_lock);
+	spin_lock_init(&bond->stats_lock);
 	bond->params = bonding_defaults;
 
 	/* Initialize pointers */
@@ -4131,13 +4251,13 @@
 	bond_dev->features |= NETIF_F_NETNS_LOCAL;
 
 	bond_dev->hw_features = BOND_VLAN_FEATURES |
-				NETIF_F_HW_VLAN_CTAG_TX |
 				NETIF_F_HW_VLAN_CTAG_RX |
 				NETIF_F_HW_VLAN_CTAG_FILTER;
 
 	bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
 	bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL;
 	bond_dev->features |= bond_dev->hw_features;
+	bond_dev->features |= NETIF_F_HW_VLAN_CTAG_TX;
 }
 
 /* Destroy a bonding device.
@@ -4154,7 +4274,7 @@
 
 	/* Release the bonded slaves */
 	bond_for_each_slave(bond, slave, iter)
-		__bond_release_one(bond_dev, slave->dev, true);
+		__bond_release_one(bond_dev, slave->dev, true, true);
 	netdev_info(bond_dev, "Released all slaves\n");
 
 	arr = rtnl_dereference(bond->slave_arr);
--- linux-4.4.0.orig/drivers/net/bonding/bond_netlink.c
+++ linux-4.4.0/drivers/net/bonding/bond_netlink.c
@@ -446,7 +446,11 @@
 	if (err < 0)
 		return err;
 
-	return register_netdevice(bond_dev);
+	err = register_netdevice(bond_dev);
+
+	netif_carrier_off(bond_dev);
+
+	return err;
 }
 
 static size_t bond_get_size(const struct net_device *bond_dev)
@@ -624,8 +628,7 @@
 				goto nla_put_failure;
 
 			if (nla_put(skb, IFLA_BOND_AD_ACTOR_SYSTEM,
-				    sizeof(bond->params.ad_actor_system),
-				    &bond->params.ad_actor_system))
+				    ETH_ALEN, &bond->params.ad_actor_system))
 				goto nla_put_failure;
 		}
 		if (!bond_3ad_get_active_agg_info(bond, &info)) {
--- linux-4.4.0.orig/drivers/net/bonding/bond_options.c
+++ linux-4.4.0/drivers/net/bonding/bond_options.c
@@ -1042,9 +1042,9 @@
 	__be32 target;
 
 	if (newval->string) {
-		if (!in4_pton(newval->string+1, -1, (u8 *)&target, -1, NULL)) {
-			netdev_err(bond->dev, "invalid ARP target %pI4 specified\n",
-				   &target);
+		if (strlen(newval->string) < 1 ||
+		    !in4_pton(newval->string + 1, -1, (u8 *)&target, -1, NULL)) {
+			netdev_err(bond->dev, "invalid ARP target specified\n");
 			return ret;
 		}
 		if (newval->string[0] == '+')
@@ -1066,13 +1066,6 @@
 {
 	netdev_info(bond->dev, "Setting arp_validate to %s (%llu)\n",
 		    newval->string, newval->value);
-
-	if (bond->dev->flags & IFF_UP) {
-		if (!newval->value)
-			bond->recv_probe = NULL;
-		else if (bond->params.arp_interval)
-			bond->recv_probe = bond_arp_rcv;
-	}
 	bond->params.arp_validate = newval->value;
 
 	return 0;
@@ -1115,6 +1108,7 @@
 				    slave->dev->name);
 			rcu_assign_pointer(bond->primary_slave, slave);
 			strcpy(bond->params.primary, slave->dev->name);
+			bond->force_primary = true;
 			bond_select_active_slave(bond);
 			goto out;
 		}
--- linux-4.4.0.orig/drivers/net/bonding/bond_sysfs_slave.c
+++ linux-4.4.0/drivers/net/bonding/bond_sysfs_slave.c
@@ -55,7 +55,9 @@
 
 static ssize_t perm_hwaddr_show(struct slave *slave, char *buf)
 {
-	return sprintf(buf, "%pM\n", slave->perm_hwaddr);
+	return sprintf(buf, "%*phC\n",
+		       slave->dev->addr_len,
+		       slave->perm_hwaddr);
 }
 static SLAVE_ATTR_RO(perm_hwaddr);
 
@@ -123,7 +125,6 @@
 };
 
 #define to_slave_attr(_at) container_of(_at, struct slave_attribute, attr)
-#define to_slave(obj)	container_of(obj, struct slave, kobj)
 
 static ssize_t slave_show(struct kobject *kobj,
 			  struct attribute *attr, char *buf)
@@ -134,26 +135,15 @@
 	return slave_attr->show(slave, buf);
 }
 
-static const struct sysfs_ops slave_sysfs_ops = {
+const struct sysfs_ops slave_sysfs_ops = {
 	.show = slave_show,
 };
 
-static struct kobj_type slave_ktype = {
-#ifdef CONFIG_SYSFS
-	.sysfs_ops = &slave_sysfs_ops,
-#endif
-};
-
 int bond_sysfs_slave_add(struct slave *slave)
 {
 	const struct slave_attribute **a;
 	int err;
 
-	err = kobject_init_and_add(&slave->kobj, &slave_ktype,
-				   &(slave->dev->dev.kobj), "bonding_slave");
-	if (err)
-		return err;
-
 	for (a = slave_attrs; *a; ++a) {
 		err = sysfs_create_file(&slave->kobj, &((*a)->attr));
 		if (err) {
@@ -171,6 +161,4 @@
 
 	for (a = slave_attrs; *a; ++a)
 		sysfs_remove_file(&slave->kobj, &((*a)->attr));
-
-	kobject_put(&slave->kobj);
 }
--- linux-4.4.0.orig/drivers/net/caif/caif_hsi.c
+++ linux-4.4.0/drivers/net/caif/caif_hsi.c
@@ -1467,7 +1467,7 @@
 	rtnl_lock();
 	list_for_each_safe(list_node, n, &cfhsi_list) {
 		cfhsi = list_entry(list_node, struct cfhsi, list);
-		unregister_netdev(cfhsi->ndev);
+		unregister_netdevice(cfhsi->ndev);
 	}
 	rtnl_unlock();
 }
--- linux-4.4.0.orig/drivers/net/can/at91_can.c
+++ linux-4.4.0/drivers/net/can/at91_can.c
@@ -712,9 +712,10 @@
 
 	/* upper group completed, look again in lower */
 	if (priv->rx_next > get_mb_rx_low_last(priv) &&
-	    quota > 0 && mb > get_mb_rx_last(priv)) {
+	    mb > get_mb_rx_last(priv)) {
 		priv->rx_next = get_mb_rx_first(priv);
-		goto again;
+		if (quota > 0)
+			goto again;
 	}
 
 	return received;
--- linux-4.4.0.orig/drivers/net/can/c_can/c_can.c
+++ linux-4.4.0/drivers/net/can/c_can/c_can.c
@@ -52,6 +52,7 @@
 #define CONTROL_EX_PDR		BIT(8)
 
 /* control register */
+#define CONTROL_SWR		BIT(15)
 #define CONTROL_TEST		BIT(7)
 #define CONTROL_CCE		BIT(6)
 #define CONTROL_DISABLE_AR	BIT(5)
@@ -97,6 +98,9 @@
 #define BTR_TSEG2_SHIFT		12
 #define BTR_TSEG2_MASK		(0x7 << BTR_TSEG2_SHIFT)
 
+/* interrupt register */
+#define INT_STS_PENDING		0x8000
+
 /* brp extension register */
 #define BRP_EXT_BRPE_MASK	0x0f
 #define BRP_EXT_BRPE_SHIFT	0
@@ -332,9 +336,23 @@
 
 	priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
 
-	for (i = 0; i < frame->can_dlc; i += 2) {
-		priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
-				frame->data[i] | (frame->data[i + 1] << 8));
+	if (priv->type == BOSCH_D_CAN) {
+		u32 data = 0, dreg = C_CAN_IFACE(DATA1_REG, iface);
+
+		for (i = 0; i < frame->can_dlc; i += 4, dreg += 2) {
+			data = (u32)frame->data[i];
+			data |= (u32)frame->data[i + 1] << 8;
+			data |= (u32)frame->data[i + 2] << 16;
+			data |= (u32)frame->data[i + 3] << 24;
+			priv->write_reg32(priv, dreg, data);
+		}
+	} else {
+		for (i = 0; i < frame->can_dlc; i += 2) {
+			priv->write_reg(priv,
+					C_CAN_IFACE(DATA1_REG, iface) + i / 2,
+					frame->data[i] |
+					(frame->data[i + 1] << 8));
+		}
 	}
 }
 
@@ -402,10 +420,20 @@
 	} else {
 		int i, dreg = C_CAN_IFACE(DATA1_REG, iface);
 
-		for (i = 0; i < frame->can_dlc; i += 2, dreg ++) {
-			data = priv->read_reg(priv, dreg);
-			frame->data[i] = data;
-			frame->data[i + 1] = data >> 8;
+		if (priv->type == BOSCH_D_CAN) {
+			for (i = 0; i < frame->can_dlc; i += 4, dreg += 2) {
+				data = priv->read_reg32(priv, dreg);
+				frame->data[i] = data;
+				frame->data[i + 1] = data >> 8;
+				frame->data[i + 2] = data >> 16;
+				frame->data[i + 3] = data >> 24;
+			}
+		} else {
+			for (i = 0; i < frame->can_dlc; i += 2, dreg++) {
+				data = priv->read_reg(priv, dreg);
+				frame->data[i] = data;
+				frame->data[i + 1] = data >> 8;
+			}
 		}
 	}
 
@@ -545,6 +573,26 @@
 				   IF_MCONT_RCV_EOB);
 }
 
+static int c_can_software_reset(struct net_device *dev)
+{
+	struct c_can_priv *priv = netdev_priv(dev);
+	int retry = 0;
+
+	if (priv->type != BOSCH_D_CAN)
+		return 0;
+
+	priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_SWR | CONTROL_INIT);
+	while (priv->read_reg(priv, C_CAN_CTRL_REG) & CONTROL_SWR) {
+		msleep(20);
+		if (retry++ > 100) {
+			netdev_err(dev, "CCTRL: software reset failed\n");
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * Configure C_CAN chip:
  * - enable/disable auto-retransmission
@@ -554,6 +602,11 @@
 static int c_can_chip_config(struct net_device *dev)
 {
 	struct c_can_priv *priv = netdev_priv(dev);
+	int err;
+
+	err = c_can_software_reset(dev);
+	if (err)
+		return err;
 
 	/* enable automatic retransmission */
 	priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR);
@@ -1005,10 +1058,16 @@
 	u16 curr, last = priv->last_status;
 	int work_done = 0;
 
-	priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
-	/* Ack status on C_CAN. D_CAN is self clearing */
-	if (priv->type != BOSCH_D_CAN)
-		priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
+	/* Only read the status register if a status interrupt was pending */
+	if (atomic_xchg(&priv->sie_pending, 0)) {
+		priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
+		/* Ack status on C_CAN. D_CAN is self clearing */
+		if (priv->type != BOSCH_D_CAN)
+			priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
+	} else {
+		/* no change detected ... */
+		curr = last;
+	}
 
 	/* handle state changes */
 	if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) {
@@ -1059,10 +1118,16 @@
 {
 	struct net_device *dev = (struct net_device *)dev_id;
 	struct c_can_priv *priv = netdev_priv(dev);
+	int reg_int;
 
-	if (!priv->read_reg(priv, C_CAN_INT_REG))
+	reg_int = priv->read_reg(priv, C_CAN_INT_REG);
+	if (!reg_int)
 		return IRQ_NONE;
 
+	/* save for later use */
+	if (reg_int & INT_STS_PENDING)
+		atomic_set(&priv->sie_pending, 1);
+
 	/* disable all interrupts and schedule the NAPI */
 	c_can_irq_control(priv, false);
 	napi_schedule(&priv->napi);
--- linux-4.4.0.orig/drivers/net/can/c_can/c_can.h
+++ linux-4.4.0/drivers/net/can/c_can/c_can.h
@@ -198,6 +198,7 @@
 	struct net_device *dev;
 	struct device *device;
 	atomic_t tx_active;
+	atomic_t sie_pending;
 	unsigned long tx_dir;
 	int last_status;
 	u16 (*read_reg) (const struct c_can_priv *priv, enum reg index);
--- linux-4.4.0.orig/drivers/net/can/c_can/c_can_pci.c
+++ linux-4.4.0/drivers/net/can/c_can/c_can_pci.c
@@ -161,6 +161,7 @@
 
 	dev->irq = pdev->irq;
 	priv->base = addr;
+	priv->device = &pdev->dev;
 
 	if (!c_can_pci_data->freq) {
 		dev_err(&pdev->dev, "no clock frequency defined\n");
@@ -177,7 +178,6 @@
 		break;
 	case BOSCH_D_CAN:
 		priv->regs = reg_map_d_can;
-		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
 		break;
 	default:
 		ret = -EINVAL;
--- linux-4.4.0.orig/drivers/net/can/c_can/c_can_platform.c
+++ linux-4.4.0/drivers/net/can/c_can/c_can_platform.c
@@ -320,7 +320,6 @@
 		break;
 	case BOSCH_D_CAN:
 		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;
 		priv->read_reg32 = d_can_plat_read_reg32;
--- linux-4.4.0.orig/drivers/net/can/cc770/cc770.c
+++ linux-4.4.0/drivers/net/can/cc770/cc770.c
@@ -390,37 +390,23 @@
 	return 0;
 }
 
-static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void cc770_tx(struct net_device *dev, int mo)
 {
 	struct cc770_priv *priv = netdev_priv(dev);
-	struct net_device_stats *stats = &dev->stats;
-	struct can_frame *cf = (struct can_frame *)skb->data;
-	unsigned int mo = obj2msgobj(CC770_OBJ_TX);
+	struct can_frame *cf = (struct can_frame *)priv->tx_skb->data;
 	u8 dlc, rtr;
 	u32 id;
 	int i;
 
-	if (can_dropped_invalid_skb(dev, skb))
-		return NETDEV_TX_OK;
-
-	if ((cc770_read_reg(priv,
-			    msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) {
-		netdev_err(dev, "TX register is still occupied!\n");
-		return NETDEV_TX_BUSY;
-	}
-
-	netif_stop_queue(dev);
-
 	dlc = cf->can_dlc;
 	id = cf->can_id;
-	if (cf->can_id & CAN_RTR_FLAG)
-		rtr = 0;
-	else
-		rtr = MSGCFG_DIR;
+	rtr = cf->can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR;
+
+	cc770_write_reg(priv, msgobj[mo].ctrl0,
+			MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES);
 	cc770_write_reg(priv, msgobj[mo].ctrl1,
 			RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES);
-	cc770_write_reg(priv, msgobj[mo].ctrl0,
-			MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES);
+
 	if (id & CAN_EFF_FLAG) {
 		id &= CAN_EFF_MASK;
 		cc770_write_reg(priv, msgobj[mo].config,
@@ -439,22 +425,30 @@
 	for (i = 0; i < dlc; i++)
 		cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]);
 
-	/* Store echo skb before starting the transfer */
-	can_put_echo_skb(skb, dev, 0);
-
 	cc770_write_reg(priv, msgobj[mo].ctrl1,
-			RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC);
+			RMTPND_UNC | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC);
+	cc770_write_reg(priv, msgobj[mo].ctrl0,
+			MSGVAL_SET | TXIE_SET | RXIE_SET | INTPND_UNC);
+}
+
+static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct cc770_priv *priv = netdev_priv(dev);
+	unsigned int mo = obj2msgobj(CC770_OBJ_TX);
 
-	stats->tx_bytes += dlc;
+	if (can_dropped_invalid_skb(dev, skb))
+		return NETDEV_TX_OK;
 
+	netif_stop_queue(dev);
 
-	/*
-	 * HM: We had some cases of repeated IRQs so make sure the
-	 * INT is acknowledged I know it's already further up, but
-	 * doing again fixed the issue
-	 */
-	cc770_write_reg(priv, msgobj[mo].ctrl0,
-			MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES);
+	if ((cc770_read_reg(priv,
+			    msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) {
+		netdev_err(dev, "TX register is still occupied!\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	priv->tx_skb = skb;
+	cc770_tx(dev, mo);
 
 	return NETDEV_TX_OK;
 }
@@ -680,19 +674,46 @@
 	struct cc770_priv *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &dev->stats;
 	unsigned int mo = obj2msgobj(o);
+	struct can_frame *cf;
+	u8 ctrl1;
+
+	ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1);
 
-	/* Nothing more to send, switch off interrupts */
 	cc770_write_reg(priv, msgobj[mo].ctrl0,
 			MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES);
-	/*
-	 * We had some cases of repeated IRQ so make sure the
-	 * INT is acknowledged
+	cc770_write_reg(priv, msgobj[mo].ctrl1,
+			RMTPND_RES | TXRQST_RES | MSGLST_RES | NEWDAT_RES);
+
+	if (unlikely(!priv->tx_skb)) {
+		netdev_err(dev, "missing tx skb in tx interrupt\n");
+		return;
+	}
+
+	if (unlikely(ctrl1 & MSGLST_SET)) {
+		stats->rx_over_errors++;
+		stats->rx_errors++;
+	}
+
+	/* When the CC770 is sending an RTR message and it receives a regular
+	 * message that matches the id of the RTR message, it will overwrite the
+	 * outgoing message in the TX register. When this happens we must
+	 * process the received message and try to transmit the outgoing skb
+	 * again.
 	 */
-	cc770_write_reg(priv, msgobj[mo].ctrl0,
-			MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES);
+	if (unlikely(ctrl1 & NEWDAT_SET)) {
+		cc770_rx(dev, mo, ctrl1);
+		cc770_tx(dev, mo);
+		return;
+	}
 
+	cf = (struct can_frame *)priv->tx_skb->data;
+	stats->tx_bytes += cf->can_dlc;
 	stats->tx_packets++;
+
+	can_put_echo_skb(priv->tx_skb, dev, 0);
 	can_get_echo_skb(dev, 0);
+	priv->tx_skb = NULL;
+
 	netif_wake_queue(dev);
 }
 
@@ -804,6 +825,7 @@
 	priv->can.do_set_bittiming = cc770_set_bittiming;
 	priv->can.do_set_mode = cc770_set_mode;
 	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+	priv->tx_skb = NULL;
 
 	memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags));
 
--- linux-4.4.0.orig/drivers/net/can/cc770/cc770.h
+++ linux-4.4.0/drivers/net/can/cc770/cc770.h
@@ -193,6 +193,8 @@
 	u8 cpu_interface;	/* CPU interface register */
 	u8 clkout;		/* Clock out register */
 	u8 bus_config;		/* Bus conffiguration register */
+
+	struct sk_buff *tx_skb;
 };
 
 struct net_device *alloc_cc770dev(int sizeof_priv);
--- linux-4.4.0.orig/drivers/net/can/cc770/cc770_isa.c
+++ linux-4.4.0/drivers/net/can/cc770/cc770_isa.c
@@ -82,16 +82,16 @@
 static u8 bcr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
 static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
 
-module_param_array(port, ulong, NULL, S_IRUGO);
+module_param_hw_array(port, ulong, ioport, NULL, S_IRUGO);
 MODULE_PARM_DESC(port, "I/O port number");
 
-module_param_array(mem, ulong, NULL, S_IRUGO);
+module_param_hw_array(mem, ulong, iomem, NULL, S_IRUGO);
 MODULE_PARM_DESC(mem, "I/O memory address");
 
-module_param_array(indirect, int, NULL, S_IRUGO);
+module_param_hw_array(indirect, int, ioport, NULL, S_IRUGO);
 MODULE_PARM_DESC(indirect, "Indirect access via address and data port");
 
-module_param_array(irq, int, NULL, S_IRUGO);
+module_param_hw_array(irq, int, irq, NULL, S_IRUGO);
 MODULE_PARM_DESC(irq, "IRQ number");
 
 module_param_array(clk, int, NULL, S_IRUGO);
--- linux-4.4.0.orig/drivers/net/can/dev.c
+++ linux-4.4.0/drivers/net/can/dev.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
+#include <linux/workqueue.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/skb.h>
@@ -422,6 +423,37 @@
 }
 EXPORT_SYMBOL_GPL(can_put_echo_skb);
 
+struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	if (idx >= priv->echo_skb_max) {
+		netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
+			   __func__, idx, priv->echo_skb_max);
+		return NULL;
+	}
+
+	if (priv->echo_skb[idx]) {
+		/* Using "struct canfd_frame::len" for the frame
+		 * length is supported on both CAN and CANFD frames.
+		 */
+		struct sk_buff *skb = priv->echo_skb[idx];
+		struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+
+		/* get the real payload length for netdev statistics */
+		if (cf->can_id & CAN_RTR_FLAG)
+			*len_ptr = 0;
+		else
+			*len_ptr = cf->len;
+
+		priv->echo_skb[idx] = NULL;
+
+		return skb;
+	}
+
+	return NULL;
+}
+
 /*
  * Get the skb from the stack and loop it back locally
  *
@@ -431,22 +463,20 @@
  */
 unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
 {
-	struct can_priv *priv = netdev_priv(dev);
-
-	BUG_ON(idx >= priv->echo_skb_max);
-
-	if (priv->echo_skb[idx]) {
-		struct sk_buff *skb = priv->echo_skb[idx];
-		struct can_frame *cf = (struct can_frame *)skb->data;
-		u8 dlc = cf->can_dlc;
+	struct sk_buff *skb;
+	u8 len;
 
-		netif_rx(priv->echo_skb[idx]);
-		priv->echo_skb[idx] = NULL;
+	skb = __can_get_echo_skb(dev, idx, &len);
+	if (!skb)
+		return 0;
 
-		return dlc;
-	}
+	skb_get(skb);
+	if (netif_rx(skb) == NET_RX_SUCCESS)
+		dev_consume_skb_any(skb);
+	else
+		dev_kfree_skb_any(skb);
 
-	return 0;
+	return len;
 }
 EXPORT_SYMBOL_GPL(can_get_echo_skb);
 
@@ -471,9 +501,8 @@
 /*
  * CAN device restart for bus-off recovery
  */
-static void can_restart(unsigned long data)
+static void can_restart(struct net_device *dev)
 {
-	struct net_device *dev = (struct net_device *)data;
 	struct can_priv *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &dev->stats;
 	struct sk_buff *skb;
@@ -496,11 +525,11 @@
 	}
 	cf->can_id |= CAN_ERR_RESTARTED;
 
-	netif_rx(skb);
-
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
 
+	netif_rx_ni(skb);
+
 restart:
 	netdev_dbg(dev, "restarted\n");
 	priv->can_stats.restarts++;
@@ -513,6 +542,14 @@
 		netdev_err(dev, "Error %d during restart", err);
 }
 
+static void can_restart_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct can_priv *priv = container_of(dwork, struct can_priv, restart_work);
+
+	can_restart(priv->dev);
+}
+
 int can_restart_now(struct net_device *dev)
 {
 	struct can_priv *priv = netdev_priv(dev);
@@ -526,8 +563,8 @@
 	if (priv->state != CAN_STATE_BUS_OFF)
 		return -EBUSY;
 
-	/* Runs as soon as possible in the timer context */
-	mod_timer(&priv->restart_timer, jiffies);
+	cancel_delayed_work_sync(&priv->restart_work);
+	can_restart(dev);
 
 	return 0;
 }
@@ -548,8 +585,8 @@
 	netif_carrier_off(dev);
 
 	if (priv->restart_ms)
-		mod_timer(&priv->restart_timer,
-			  jiffies + (priv->restart_ms * HZ) / 1000);
+		schedule_delayed_work(&priv->restart_work,
+				      msecs_to_jiffies(priv->restart_ms));
 }
 EXPORT_SYMBOL_GPL(can_bus_off);
 
@@ -658,6 +695,7 @@
 		return NULL;
 
 	priv = netdev_priv(dev);
+	priv->dev = dev;
 
 	if (echo_skb_max) {
 		priv->echo_skb_max = echo_skb_max;
@@ -667,7 +705,7 @@
 
 	priv->state = CAN_STATE_STOPPED;
 
-	init_timer(&priv->restart_timer);
+	INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);
 
 	return dev;
 }
@@ -696,11 +734,17 @@
 	/* allow change of MTU according to the CANFD ability of the device */
 	switch (new_mtu) {
 	case CAN_MTU:
+		/* 'CANFD-only' controllers can not switch to CAN_MTU */
+		if (priv->ctrlmode_static & CAN_CTRLMODE_FD)
+			return -EINVAL;
+
 		priv->ctrlmode &= ~CAN_CTRLMODE_FD;
 		break;
 
 	case CANFD_MTU:
-		if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD))
+		/* check for potential CANFD ability */
+		if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) &&
+		    !(priv->ctrlmode_static & CAN_CTRLMODE_FD))
 			return -EINVAL;
 
 		priv->ctrlmode |= CAN_CTRLMODE_FD;
@@ -742,8 +786,6 @@
 	if (!netif_carrier_ok(dev))
 		netif_carrier_on(dev);
 
-	setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(open_candev);
@@ -758,7 +800,7 @@
 {
 	struct can_priv *priv = netdev_priv(dev);
 
-	del_timer_sync(&priv->restart_timer);
+	cancel_delayed_work_sync(&priv->restart_work);
 	can_flush_echo_skb(dev);
 }
 EXPORT_SYMBOL_GPL(close_candev);
@@ -782,6 +824,38 @@
 				= { .len = sizeof(struct can_bittiming_const) },
 };
 
+static int can_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	bool is_can_fd = false;
+
+	/* Make sure that valid CAN FD configurations always consist of
+	 * - nominal/arbitration bittiming
+	 * - data bittiming
+	 * - control mode with CAN_CTRLMODE_FD set
+	 */
+
+	if (!data)
+		return 0;
+
+	if (data[IFLA_CAN_CTRLMODE]) {
+		struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
+
+		is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
+	}
+
+	if (is_can_fd) {
+		if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
+			return -EOPNOTSUPP;
+	}
+
+	if (data[IFLA_CAN_DATA_BITTIMING]) {
+		if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
+			return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 static int can_changelink(struct net_device *dev,
 			  struct nlattr *tb[], struct nlattr *data[])
 {
@@ -813,19 +887,31 @@
 
 	if (data[IFLA_CAN_CTRLMODE]) {
 		struct can_ctrlmode *cm;
+		u32 ctrlstatic;
+		u32 maskedflags;
 
 		/* Do not allow changing controller mode while running */
 		if (dev->flags & IFF_UP)
 			return -EBUSY;
 		cm = nla_data(data[IFLA_CAN_CTRLMODE]);
+		ctrlstatic = priv->ctrlmode_static;
+		maskedflags = cm->flags & cm->mask;
 
-		/* check whether changed bits are allowed to be modified */
-		if (cm->mask & ~priv->ctrlmode_supported)
+		/* check whether provided bits are allowed to be passed */
+		if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic))
+			return -EOPNOTSUPP;
+
+		/* do not check for static fd-non-iso if 'fd' is disabled */
+		if (!(maskedflags & CAN_CTRLMODE_FD))
+			ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
+
+		/* make sure static options are provided by configuration */
+		if ((maskedflags & ctrlstatic) != ctrlstatic)
 			return -EOPNOTSUPP;
 
 		/* clear bits to be modified and copy the flag values */
 		priv->ctrlmode &= ~cm->mask;
-		priv->ctrlmode |= (cm->flags & cm->mask);
+		priv->ctrlmode |= maskedflags;
 
 		/* CAN_CTRLMODE_FD can only be set when driver supports FD */
 		if (priv->ctrlmode & CAN_CTRLMODE_FD)
@@ -901,7 +987,7 @@
 {
 	struct can_priv *priv = netdev_priv(dev);
 	struct can_ctrlmode cm = {.flags = priv->ctrlmode};
-	struct can_berr_counter bec;
+	struct can_berr_counter bec = { };
 	enum can_state state = priv->state;
 
 	if (priv->do_get_state)
@@ -961,13 +1047,20 @@
 	return -EOPNOTSUPP;
 }
 
+static void can_dellink(struct net_device *dev, struct list_head *head)
+{
+	return;
+}
+
 static struct rtnl_link_ops can_link_ops __read_mostly = {
 	.kind		= "can",
 	.maxtype	= IFLA_CAN_MAX,
 	.policy		= can_policy,
 	.setup		= can_setup,
+	.validate	= can_validate,
 	.newlink	= can_newlink,
 	.changelink	= can_changelink,
+	.dellink	= can_dellink,
 	.get_size	= can_get_size,
 	.fill_info	= can_fill_info,
 	.get_xstats_size = can_get_xstats_size,
@@ -980,6 +1073,8 @@
 int register_candev(struct net_device *dev)
 {
 	dev->rtnl_link_ops = &can_link_ops;
+	netif_carrier_off(dev);
+
 	return register_netdev(dev);
 }
 EXPORT_SYMBOL_GPL(register_candev);
--- linux-4.4.0.orig/drivers/net/can/flexcan.c
+++ linux-4.4.0/drivers/net/can/flexcan.c
@@ -171,7 +171,7 @@
 #define FLEXCAN_MB_CNT_LENGTH(x)	(((x) & 0xf) << 16)
 #define FLEXCAN_MB_CNT_TIMESTAMP(x)	((x) & 0xffff)
 
-#define FLEXCAN_TIMEOUT_US		(50)
+#define FLEXCAN_TIMEOUT_US		(250)
 
 /* FLEXCAN hardware feature flags
  *
@@ -383,7 +383,7 @@
 	u32 reg;
 
 	reg = flexcan_read(&regs->mcr);
-	reg |= FLEXCAN_MCR_HALT;
+	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT;
 	flexcan_write(reg, &regs->mcr);
 
 	while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
@@ -493,7 +493,7 @@
 		data = be32_to_cpup((__be32 *)&cf->data[0]);
 		flexcan_write(data, &regs->mb[FLEXCAN_TX_BUF_ID].data[0]);
 	}
-	if (cf->can_dlc > 3) {
+	if (cf->can_dlc > 4) {
 		data = be32_to_cpup((__be32 *)&cf->data[4]);
 		flexcan_write(data, &regs->mb[FLEXCAN_TX_BUF_ID].data[1]);
 	}
@@ -923,6 +923,7 @@
 		reg_mecr = flexcan_read(&regs->mecr);
 		reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
 		flexcan_write(reg_mecr, &regs->mecr);
+		reg_mecr |= FLEXCAN_MECR_ECCDIS;
 		reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
 			      FLEXCAN_MECR_FANCEI_MSK);
 		flexcan_write(reg_mecr, &regs->mecr);
@@ -1097,10 +1098,14 @@
 	if (err)
 		goto out_chip_disable;
 
-	/* set freeze, halt and activate FIFO, restrict register access */
+	/* set freeze, halt */
+	err = flexcan_chip_freeze(priv);
+	if (err)
+		goto out_chip_disable;
+
+	/* activate FIFO, restrict register access */
 	reg = flexcan_read(&regs->mcr);
-	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
-		FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
+	reg |=  FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
 	flexcan_write(reg, &regs->mcr);
 
 	/* Currently we only support newer versions of this core
@@ -1268,11 +1273,10 @@
 	struct flexcan_priv *priv = netdev_priv(dev);
 	int err;
 
-	err = flexcan_chip_disable(priv);
-	if (err)
-		return err;
-
 	if (netif_running(dev)) {
+		err = flexcan_chip_disable(priv);
+		if (err)
+			return err;
 		netif_stop_queue(dev);
 		netif_device_detach(dev);
 	}
@@ -1285,13 +1289,17 @@
 {
 	struct net_device *dev = dev_get_drvdata(device);
 	struct flexcan_priv *priv = netdev_priv(dev);
+	int err;
 
 	priv->can.state = CAN_STATE_ERROR_ACTIVE;
 	if (netif_running(dev)) {
 		netif_device_attach(dev);
 		netif_start_queue(dev);
+		err = flexcan_chip_enable(priv);
+		if (err)
+			return err;
 	}
-	return flexcan_chip_enable(priv);
+	return 0;
 }
 
 static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
--- linux-4.4.0.orig/drivers/net/can/m_can/m_can.c
+++ linux-4.4.0/drivers/net/can/m_can/m_can.c
@@ -572,7 +572,7 @@
 	unsigned int ecr;
 
 	switch (new_state) {
-	case CAN_STATE_ERROR_ACTIVE:
+	case CAN_STATE_ERROR_WARNING:
 		/* error warning state */
 		priv->can.can_stats.error_warning++;
 		priv->can.state = CAN_STATE_ERROR_WARNING;
@@ -601,7 +601,7 @@
 	__m_can_get_berr_counter(dev, &bec);
 
 	switch (new_state) {
-	case CAN_STATE_ERROR_ACTIVE:
+	case CAN_STATE_ERROR_WARNING:
 		/* error warning state */
 		cf->can_id |= CAN_ERR_CRTL;
 		cf->data[1] = (bec.txerr > bec.rxerr) ?
@@ -955,7 +955,7 @@
 	priv->can.do_get_berr_counter = m_can_get_berr_counter;
 
 	/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */
-	priv->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO;
+	can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
 
 	/* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */
 	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
--- linux-4.4.0.orig/drivers/net/can/mscan/mpc5xxx_can.c
+++ linux-4.4.0/drivers/net/can/mscan/mpc5xxx_can.c
@@ -86,6 +86,11 @@
 		return 0;
 	}
 	cdm = of_iomap(np_cdm, 0);
+	if (!cdm) {
+		of_node_put(np_cdm);
+		dev_err(&ofdev->dev, "can't map clock node!\n");
+		return 0;
+	}
 
 	if (in_8(&cdm->ipb_clk_sel) & 0x1)
 		freq *= 2;
--- linux-4.4.0.orig/drivers/net/can/mscan/mscan.c
+++ linux-4.4.0/drivers/net/can/mscan/mscan.c
@@ -392,13 +392,12 @@
 	struct net_device *dev = napi->dev;
 	struct mscan_regs __iomem *regs = priv->reg_base;
 	struct net_device_stats *stats = &dev->stats;
-	int npackets = 0;
-	int ret = 1;
+	int work_done = 0;
 	struct sk_buff *skb;
 	struct can_frame *frame;
 	u8 canrflg;
 
-	while (npackets < quota) {
+	while (work_done < quota) {
 		canrflg = in_8(&regs->canrflg);
 		if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF)))
 			break;
@@ -419,18 +418,18 @@
 
 		stats->rx_packets++;
 		stats->rx_bytes += frame->can_dlc;
-		npackets++;
+		work_done++;
 		netif_receive_skb(skb);
 	}
 
-	if (!(in_8(&regs->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) {
-		napi_complete(&priv->napi);
-		clear_bit(F_RX_PROGRESS, &priv->flags);
-		if (priv->can.state < CAN_STATE_BUS_OFF)
-			out_8(&regs->canrier, priv->shadow_canrier);
-		ret = 0;
+	if (work_done < quota) {
+		if (likely(napi_complete_done(&priv->napi, work_done))) {
+			clear_bit(F_RX_PROGRESS, &priv->flags);
+			if (priv->can.state < CAN_STATE_BUS_OFF)
+				out_8(&regs->canrier, priv->shadow_canrier);
+		}
 	}
-	return ret;
+	return work_done;
 }
 
 static irqreturn_t mscan_isr(int irq, void *dev_id)
--- linux-4.4.0.orig/drivers/net/can/rcar_can.c
+++ linux-4.4.0/drivers/net/can/rcar_can.c
@@ -24,6 +24,9 @@
 
 #define RCAR_CAN_DRV_NAME	"rcar_can"
 
+#define RCAR_SUPPORTED_CLOCKS	(BIT(CLKR_CLKP1) | BIT(CLKR_CLKP2) | \
+				 BIT(CLKR_CLKEXT))
+
 /* Mailbox configuration:
  * mailbox 60 - 63 - Rx FIFO mailboxes
  * mailbox 56 - 59 - Tx FIFO mailboxes
@@ -789,7 +792,7 @@
 		goto fail_clk;
 	}
 
-	if (clock_select >= ARRAY_SIZE(clock_names)) {
+	if (!(BIT(clock_select) & RCAR_SUPPORTED_CLOCKS)) {
 		err = -EINVAL;
 		dev_err(&pdev->dev, "invalid CAN clock selected\n");
 		goto fail_clk;
--- linux-4.4.0.orig/drivers/net/can/sja1000/ems_pcmcia.c
+++ linux-4.4.0/drivers/net/can/sja1000/ems_pcmcia.c
@@ -243,7 +243,12 @@
 			free_sja1000dev(dev);
 	}
 
-	err = request_irq(dev->irq, &ems_pcmcia_interrupt, IRQF_SHARED,
+	if (!card->channels) {
+		err = -ENODEV;
+		goto failure_cleanup;
+	}
+
+	err = request_irq(pdev->irq, &ems_pcmcia_interrupt, IRQF_SHARED,
 			  DRV_NAME, card);
 	if (!err)
 		return 0;
--- linux-4.4.0.orig/drivers/net/can/sja1000/peak_pcmcia.c
+++ linux-4.4.0/drivers/net/can/sja1000/peak_pcmcia.c
@@ -487,7 +487,7 @@
 		if (!netdev)
 			continue;
 
-		strncpy(name, netdev->name, IFNAMSIZ);
+		strlcpy(name, netdev->name, IFNAMSIZ);
 
 		unregister_sja1000dev(netdev);
 
--- linux-4.4.0.orig/drivers/net/can/sja1000/sja1000_isa.c
+++ linux-4.4.0/drivers/net/can/sja1000/sja1000_isa.c
@@ -48,16 +48,16 @@
 static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
 static spinlock_t indirect_lock[MAXDEV];  /* lock for indirect access mode */
 
-module_param_array(port, ulong, NULL, S_IRUGO);
+module_param_hw_array(port, ulong, ioport, NULL, S_IRUGO);
 MODULE_PARM_DESC(port, "I/O port number");
 
-module_param_array(mem, ulong, NULL, S_IRUGO);
+module_param_hw_array(mem, ulong, iomem, NULL, S_IRUGO);
 MODULE_PARM_DESC(mem, "I/O memory address");
 
-module_param_array(indirect, int, NULL, S_IRUGO);
+module_param_hw_array(indirect, int, ioport, NULL, S_IRUGO);
 MODULE_PARM_DESC(indirect, "Indirect access via address and data port");
 
-module_param_array(irq, int, NULL, S_IRUGO);
+module_param_hw_array(irq, int, irq, NULL, S_IRUGO);
 MODULE_PARM_DESC(irq, "IRQ number");
 
 module_param_array(clk, int, NULL, S_IRUGO);
--- linux-4.4.0.orig/drivers/net/can/slcan.c
+++ linux-4.4.0/drivers/net/can/slcan.c
@@ -147,7 +147,7 @@
 	u32 tmpid;
 	char *cmd = sl->rbuff;
 
-	cf.can_id = 0;
+	memset(&cf, 0, sizeof(cf));
 
 	switch (*cmd) {
 	case 'r':
@@ -186,8 +186,6 @@
 	else
 		return;
 
-	*(u64 *) (&cf.data) = 0; /* clear payload */
-
 	/* RTR frames may have a dlc > 0 but they never have any data bytes */
 	if (!(cf.can_id & CAN_RTR_FLAG)) {
 		for (i = 0; i < cf.can_dlc; i++) {
@@ -344,9 +342,16 @@
  */
 static void slcan_write_wakeup(struct tty_struct *tty)
 {
-	struct slcan *sl = tty->disc_data;
+	struct slcan *sl;
+
+	rcu_read_lock();
+	sl = rcu_dereference(tty->disc_data);
+	if (!sl)
+		goto out;
 
 	schedule_work(&sl->tx_work);
+out:
+	rcu_read_unlock();
 }
 
 /* Send a can_frame to a TTY queue. */
@@ -613,6 +618,10 @@
 	sl->tty = NULL;
 	tty->disc_data = NULL;
 	clear_bit(SLF_INUSE, &sl->flags);
+	/* do not call free_netdev before rtnl_unlock */
+	rtnl_unlock();
+	slc_free_netdev(sl->dev);
+	return err;
 
 err_exit:
 	rtnl_unlock();
@@ -638,10 +647,11 @@
 		return;
 
 	spin_lock_bh(&sl->lock);
-	tty->disc_data = NULL;
+	rcu_assign_pointer(tty->disc_data, NULL);
 	sl->tty = NULL;
 	spin_unlock_bh(&sl->lock);
 
+	synchronize_rcu();
 	flush_work(&sl->tx_work);
 
 	/* Flush network side */
--- linux-4.4.0.orig/drivers/net/can/softing/softing_main.c
+++ linux-4.4.0/drivers/net/can/softing/softing_main.c
@@ -393,8 +393,13 @@
 
 	/* check or determine and set bittime */
 	ret = open_candev(ndev);
-	if (!ret)
-		ret = softing_startstop(ndev, 1);
+	if (ret)
+		return ret;
+
+	ret = softing_startstop(ndev, 1);
+	if (ret < 0)
+		close_candev(ndev);
+
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/net/can/spi/Kconfig
+++ linux-4.4.0/drivers/net/can/spi/Kconfig
@@ -2,9 +2,10 @@
 	depends on SPI
 
 config CAN_MCP251X
-	tristate "Microchip MCP251x SPI CAN controllers"
+	tristate "Microchip MCP251x and MCP25625 SPI CAN controllers"
 	depends on HAS_DMA
 	---help---
-	  Driver for the Microchip MCP251x SPI CAN controllers.
+	  Driver for the Microchip MCP251x and MCP25625 SPI CAN
+	  controllers.
 
 endmenu
--- linux-4.4.0.orig/drivers/net/can/spi/mcp251x.c
+++ linux-4.4.0/drivers/net/can/spi/mcp251x.c
@@ -1,5 +1,5 @@
 /*
- * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
+ * CAN bus driver for Microchip 251x/25625 CAN Controller with SPI Interface
  *
  * MCP2510 support and bug fixes by Christian Pellegrin
  * <chripell@evolware.org>
@@ -41,7 +41,7 @@
  * static struct spi_board_info spi_board_info[] = {
  *         {
  *                 .modalias = "mcp2510",
- *			// or "mcp2515" depending on your controller
+ *			// "mcp2515" or "mcp25625" depending on your controller
  *                 .platform_data = &mcp251x_info,
  *                 .irq = IRQ_EINT13,
  *                 .max_speed_hz = 2*1000*1000,
@@ -238,6 +238,7 @@
 enum mcp251x_model {
 	CAN_MCP251X_MCP2510	= 0x2510,
 	CAN_MCP251X_MCP2515	= 0x2515,
+	CAN_MCP251X_MCP25625	= 0x25625,
 };
 
 struct mcp251x_priv {
@@ -280,7 +281,6 @@
 }
 
 MCP251X_IS(2510);
-MCP251X_IS(2515);
 
 static void mcp251x_clean(struct net_device *net)
 {
@@ -627,7 +627,7 @@
 static int mcp251x_hw_reset(struct spi_device *spi)
 {
 	struct mcp251x_priv *priv = spi_get_drvdata(spi);
-	u8 reg;
+	unsigned long timeout;
 	int ret;
 
 	/* Wait for oscillator startup timer after power up */
@@ -640,11 +640,20 @@
 
 	/* Wait for oscillator startup timer after reset */
 	mdelay(MCP251X_OST_DELAY_MS);
-	
-	reg = mcp251x_read_reg(spi, CANSTAT);
-	if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
-		return -ENODEV;
 
+	/* Wait for reset to finish */
+	timeout = jiffies + HZ;
+	while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) !=
+	       CANCTRL_REQOP_CONF) {
+		usleep_range(MCP251X_OST_DELAY_MS * 1000,
+			     MCP251X_OST_DELAY_MS * 1000 * 2);
+
+		if (time_after(jiffies, timeout)) {
+			dev_err(&spi->dev,
+				"MCP251x didn't enter in conf mode after reset\n");
+			return -EBUSY;
+		}
+	}
 	return 0;
 }
 
@@ -821,9 +830,8 @@
 		/* receive buffer 0 */
 		if (intf & CANINTF_RX0IF) {
 			mcp251x_hw_rx(spi, 0);
-			/*
-			 * Free one buffer ASAP
-			 * (The MCP2515 does this automatically.)
+			/* Free one buffer ASAP
+			 * (The MCP2515/25625 does this automatically.)
 			 */
 			if (mcp251x_is_2510(spi))
 				mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);
@@ -832,7 +840,7 @@
 		/* receive buffer 1 */
 		if (intf & CANINTF_RX1IF) {
 			mcp251x_hw_rx(spi, 1);
-			/* the MCP2515 does this automatically */
+			/* The MCP2515/25625 does this automatically. */
 			if (mcp251x_is_2510(spi))
 				clear_intf |= CANINTF_RX1IF;
 		}
@@ -1006,6 +1014,10 @@
 		.compatible	= "microchip,mcp2515",
 		.data		= (void *)CAN_MCP251X_MCP2515,
 	},
+	{
+		.compatible	= "microchip,mcp25625",
+		.data		= (void *)CAN_MCP251X_MCP25625,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, mcp251x_of_match);
@@ -1019,6 +1031,10 @@
 		.name		= "mcp2515",
 		.driver_data	= (kernel_ulong_t)CAN_MCP251X_MCP2515,
 	},
+	{
+		.name		= "mcp25625",
+		.driver_data	= (kernel_ulong_t)CAN_MCP251X_MCP25625,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
@@ -1254,5 +1270,5 @@
 
 MODULE_AUTHOR("Chris Elston <celston@katalix.com>, "
 	      "Christian Pellegrin <chripell@evolware.org>");
-MODULE_DESCRIPTION("Microchip 251x CAN driver");
+MODULE_DESCRIPTION("Microchip 251x/25625 CAN driver");
 MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/net/can/sun4i_can.c
+++ linux-4.4.0/drivers/net/can/sun4i_can.c
@@ -342,7 +342,7 @@
 
 	/* enter the selected mode */
 	mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR);
-	if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK)
+	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
 		mod_reg_val |= SUN4I_MSEL_LOOPBACK_MODE;
 	else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
 		mod_reg_val |= SUN4I_MSEL_LISTEN_ONLY_MODE;
@@ -539,6 +539,13 @@
 		}
 		stats->rx_over_errors++;
 		stats->rx_errors++;
+
+		/* reset the CAN IP by entering reset mode
+		 * ignoring timeout error
+		 */
+		set_reset_mode(dev);
+		set_normal_mode(dev);
+
 		/* clear bit */
 		sun4i_can_write_cmdreg(priv, SUN4I_CMD_CLEAR_OR_FLAG);
 	}
@@ -653,8 +660,9 @@
 			netif_wake_queue(dev);
 			can_led_event(dev, CAN_LED_EVENT_TX);
 		}
-		if (isrc & SUN4I_INT_RBUF_VLD) {
-			/* receive interrupt */
+		if ((isrc & SUN4I_INT_RBUF_VLD) &&
+		    !(isrc & SUN4I_INT_DATA_OR)) {
+			/* receive interrupt - don't read if overrun occurred */
 			while (status & SUN4I_STA_RBUF_RDY) {
 				/* RX buffer is not empty */
 				sun4i_can_rx(dev);
@@ -811,7 +819,6 @@
 	priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING |
 				       CAN_CTRLMODE_LISTENONLY |
 				       CAN_CTRLMODE_LOOPBACK |
-				       CAN_CTRLMODE_PRESUME_ACK |
 				       CAN_CTRLMODE_3_SAMPLES;
 	priv->base = addr;
 	priv->clk = clk;
--- linux-4.4.0.orig/drivers/net/can/ti_hecc.c
+++ linux-4.4.0/drivers/net/can/ti_hecc.c
@@ -652,6 +652,9 @@
 		mbx_mask = hecc_read(priv, HECC_CANMIM);
 		mbx_mask |= HECC_TX_MBOX_MASK;
 		hecc_write(priv, HECC_CANMIM, mbx_mask);
+	} else {
+		/* repoll is done only if whole budget is used */
+		num_pkts = quota;
 	}
 
 	return num_pkts;
@@ -948,7 +951,12 @@
 	netif_napi_add(ndev, &priv->napi, ti_hecc_rx_poll,
 		HECC_DEF_NAPI_WEIGHT);
 
-	clk_enable(priv->clk);
+	err = clk_prepare_enable(priv->clk);
+	if (err) {
+		dev_err(&pdev->dev, "clk_prepare_enable() failed\n");
+		goto probe_exit_clk;
+	}
+
 	err = register_candev(ndev);
 	if (err) {
 		dev_err(&pdev->dev, "register_candev() failed\n");
@@ -981,7 +989,7 @@
 	struct ti_hecc_priv *priv = netdev_priv(ndev);
 
 	unregister_candev(ndev);
-	clk_disable(priv->clk);
+	clk_disable_unprepare(priv->clk);
 	clk_put(priv->clk);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	iounmap(priv->base);
@@ -1006,7 +1014,7 @@
 	hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
 	priv->can.state = CAN_STATE_SLEEPING;
 
-	clk_disable(priv->clk);
+	clk_disable_unprepare(priv->clk);
 
 	return 0;
 }
@@ -1015,8 +1023,11 @@
 {
 	struct net_device *dev = platform_get_drvdata(pdev);
 	struct ti_hecc_priv *priv = netdev_priv(dev);
+	int err;
 
-	clk_enable(priv->clk);
+	err = clk_prepare_enable(priv->clk);
+	if (err)
+		return err;
 
 	hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
 	priv->can.state = CAN_STATE_ERROR_ACTIVE;
--- linux-4.4.0.orig/drivers/net/can/usb/ems_usb.c
+++ linux-4.4.0/drivers/net/can/usb/ems_usb.c
@@ -117,6 +117,9 @@
  */
 #define EMS_USB_ARM7_CLOCK 8000000
 
+#define CPC_TX_QUEUE_TRIGGER_LOW	25
+#define CPC_TX_QUEUE_TRIGGER_HIGH	35
+
 /*
  * CAN-Message representation in a CPC_MSG. Message object type is
  * CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or
@@ -278,10 +281,17 @@
 	switch (urb->status) {
 	case 0:
 		dev->free_slots = dev->intr_in_buffer[1];
+		if(dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH){
+			if (netif_queue_stopped(netdev)){
+				netif_wake_queue(netdev);
+			}
+		}
 		break;
 
 	case -ECONNRESET: /* unlink */
 	case -ENOENT:
+	case -EPIPE:
+	case -EPROTO:
 	case -ESHUTDOWN:
 		return;
 
@@ -526,8 +536,6 @@
 	/* Release context */
 	context->echo_index = MAX_TX_URBS;
 
-	if (netif_queue_stopped(netdev))
-		netif_wake_queue(netdev);
 }
 
 /*
@@ -587,7 +595,7 @@
 	int err, i;
 
 	dev->intr_in_buffer[0] = 0;
-	dev->free_slots = 15; /* initial size */
+	dev->free_slots = 50; /* initial size */
 
 	for (i = 0; i < MAX_RX_URBS; i++) {
 		struct urb *urb = NULL;
@@ -819,7 +827,6 @@
 
 		usb_unanchor_urb(urb);
 		usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
-		dev_kfree_skb(skb);
 
 		atomic_dec(&dev->active_tx_urbs);
 
@@ -835,7 +842,7 @@
 
 		/* Slow down tx path */
 		if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS ||
-		    dev->free_slots < 5) {
+		    dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) {
 			netif_stop_queue(netdev);
 		}
 	}
@@ -1070,6 +1077,7 @@
 		usb_free_urb(dev->intr_urb);
 
 		kfree(dev->intr_in_buffer);
+		kfree(dev->tx_msg_buffer);
 	}
 }
 
--- linux-4.4.0.orig/drivers/net/can/usb/esd_usb2.c
+++ linux-4.4.0/drivers/net/can/usb/esd_usb2.c
@@ -333,7 +333,7 @@
 		}
 
 		cf->can_id = id & ESD_IDMASK;
-		cf->can_dlc = get_can_dlc(msg->msg.rx.dlc);
+		cf->can_dlc = get_can_dlc(msg->msg.rx.dlc & ~ESD_RTR);
 
 		if (id & ESD_EXTID)
 			cf->can_id |= CAN_EFF_FLAG;
@@ -393,6 +393,8 @@
 		break;
 
 	case -ENOENT:
+	case -EPIPE:
+	case -EPROTO:
 	case -ESHUTDOWN:
 		return;
 
--- linux-4.4.0.orig/drivers/net/can/usb/gs_usb.c
+++ linux-4.4.0/drivers/net/can/usb/gs_usb.c
@@ -246,6 +246,8 @@
 			     sizeof(*dm),
 			     1000);
 
+	kfree(dm);
+
 	return rc;
 }
 
@@ -354,6 +356,8 @@
 
 		gs_free_tx_context(txc);
 
+		atomic_dec(&dev->active_tx_urbs);
+
 		netif_wake_queue(netdev);
 	}
 
@@ -426,7 +430,7 @@
 		dev_err(netdev->dev.parent, "Couldn't set bittimings (err=%d)",
 			rc);
 
-	return rc;
+	return (rc > 0) ? 0 : rc;
 }
 
 static void gs_usb_xmit_callback(struct urb *urb)
@@ -442,14 +446,6 @@
 			  urb->transfer_buffer_length,
 			  urb->transfer_buffer,
 			  urb->transfer_dma);
-
-	atomic_dec(&dev->active_tx_urbs);
-
-	if (!netif_device_present(netdev))
-		return;
-
-	if (netif_queue_stopped(netdev))
-		netif_wake_queue(netdev);
 }
 
 static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, struct net_device *netdev)
@@ -621,6 +617,7 @@
 					   rc);
 
 				usb_unanchor_urb(urb);
+				usb_free_urb(urb);
 				break;
 			}
 
@@ -826,9 +823,8 @@
 static void gs_destroy_candev(struct gs_can *dev)
 {
 	unregister_candev(dev->netdev);
-	free_candev(dev->netdev);
 	usb_kill_anchored_urbs(&dev->tx_submitted);
-	kfree(dev);
+	free_candev(dev->netdev);
 }
 
 static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -851,7 +847,7 @@
 			     GS_USB_BREQ_HOST_FORMAT,
 			     USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
 			     1,
-			     intf->altsetting[0].desc.bInterfaceNumber,
+			     intf->cur_altsetting->desc.bInterfaceNumber,
 			     hconf,
 			     sizeof(*hconf),
 			     1000);
@@ -874,7 +870,7 @@
 			     GS_USB_BREQ_DEVICE_CONFIG,
 			     USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
 			     1,
-			     intf->altsetting[0].desc.bInterfaceNumber,
+			     intf->cur_altsetting->desc.bInterfaceNumber,
 			     dconf,
 			     sizeof(*dconf),
 			     1000);
@@ -913,12 +909,15 @@
 	for (i = 0; i < icount; i++) {
 		dev->canch[i] = gs_make_candev(i, intf);
 		if (IS_ERR_OR_NULL(dev->canch[i])) {
+			/* save error code to return later */
+			rc = PTR_ERR(dev->canch[i]);
+
 			/* on failure destroy previously created candevs */
 			icount = i;
-			for (i = 0; i < icount; i++) {
+			for (i = 0; i < icount; i++)
 				gs_destroy_candev(dev->canch[i]);
-				dev->canch[i] = NULL;
-			}
+
+			usb_kill_anchored_urbs(&dev->rx_submitted);
 			kfree(dev);
 			return rc;
 		}
@@ -939,16 +938,12 @@
 		return;
 	}
 
-	for (i = 0; i < GS_MAX_INTF; i++) {
-		struct gs_can *can = dev->canch[i];
-
-		if (!can)
-			continue;
-
-		gs_destroy_candev(can);
-	}
+	for (i = 0; i < GS_MAX_INTF; i++)
+		if (dev->canch[i])
+			gs_destroy_candev(dev->canch[i]);
 
 	usb_kill_anchored_urbs(&dev->rx_submitted);
+	kfree(dev);
 }
 
 static const struct usb_device_id gs_usb_table[] = {
--- linux-4.4.0.orig/drivers/net/can/usb/kvaser_usb.c
+++ linux-4.4.0/drivers/net/can/usb/kvaser_usb.c
@@ -134,6 +134,7 @@
 #define CMD_RESET_ERROR_COUNTER		49
 #define CMD_TX_ACKNOWLEDGE		50
 #define CMD_CAN_ERROR_EVENT		51
+#define CMD_FLUSH_QUEUE_REPLY		68
 
 #define CMD_LEAF_USB_THROTTLE		77
 #define CMD_LEAF_LOG_MESSAGE		106
@@ -602,8 +603,8 @@
 			}
 
 			if (pos + tmp->len > actual_len) {
-				dev_err(dev->udev->dev.parent,
-					"Format error\n");
+				dev_err_ratelimited(dev->udev->dev.parent,
+						    "Format error\n");
 				break;
 			}
 
@@ -786,7 +787,7 @@
 		return -ENOMEM;
 	}
 
-	buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
+	buf = kzalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
 	if (!buf) {
 		usb_free_urb(urb);
 		return -ENOMEM;
@@ -808,6 +809,7 @@
 	if (err) {
 		netdev_err(netdev, "Error transmitting URB\n");
 		usb_unanchor_urb(urb);
+		kfree(buf);
 		usb_free_urb(urb);
 		return err;
 	}
@@ -1173,7 +1175,7 @@
 
 	skb = alloc_can_skb(priv->netdev, &cf);
 	if (!skb) {
-		stats->tx_dropped++;
+		stats->rx_dropped++;
 		return;
 	}
 
@@ -1297,6 +1299,11 @@
 			goto warn;
 		break;
 
+	case CMD_FLUSH_QUEUE_REPLY:
+		if (dev->family != KVASER_LEAF)
+			goto warn;
+		break;
+
 	default:
 warn:		dev_warn(dev->udev->dev.parent,
 			 "Unhandled message (%d)\n", msg->id);
@@ -1315,6 +1322,8 @@
 	case 0:
 		break;
 	case -ENOENT:
+	case -EPIPE:
+	case -EPROTO:
 	case -ESHUTDOWN:
 		return;
 	default:
@@ -1323,7 +1332,7 @@
 		goto resubmit_urb;
 	}
 
-	while (pos <= urb->actual_length - MSG_HEADER_LEN) {
+	while (pos <= (int)(urb->actual_length - MSG_HEADER_LEN)) {
 		msg = urb->transfer_buffer + pos;
 
 		/* The Kvaser firmware can only read and write messages that
@@ -1342,7 +1351,8 @@
 		}
 
 		if (pos + msg->len > urb->actual_length) {
-			dev_err(dev->udev->dev.parent, "Format error\n");
+			dev_err_ratelimited(dev->udev->dev.parent,
+					    "Format error\n");
 			break;
 		}
 
@@ -1447,7 +1457,7 @@
 	struct kvaser_msg *msg;
 	int rc;
 
-	msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+	msg = kzalloc(sizeof(*msg), GFP_KERNEL);
 	if (!msg)
 		return -ENOMEM;
 
@@ -1580,7 +1590,7 @@
 	struct kvaser_msg *msg;
 	int rc;
 
-	msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+	msg = kzalloc(sizeof(*msg), GFP_KERNEL);
 	if (!msg)
 		return -ENOMEM;
 
@@ -1607,7 +1617,8 @@
 	if (err)
 		netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
 
-	if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel))
+	err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel);
+	if (err)
 		netdev_warn(netdev, "Cannot reset card, error %d\n", err);
 
 	err = kvaser_usb_stop_chip(priv);
@@ -1760,6 +1771,7 @@
 		spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 
 		usb_unanchor_urb(urb);
+		kfree(buf);
 
 		stats->tx_dropped++;
 
--- linux-4.4.0.orig/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ linux-4.4.0/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -108,7 +108,7 @@
 	u8 *end;
 	u8 rec_cnt;
 	u8 rec_idx;
-	u8 rec_data_idx;
+	u8 rec_ts_idx;
 	struct net_device *netdev;
 	struct pcan_usb *pdev;
 };
@@ -441,8 +441,8 @@
 		}
 		if ((n & PCAN_USB_ERROR_BUS_LIGHT) == 0) {
 			/* no error (back to active state) */
-			mc->pdev->dev.can.state = CAN_STATE_ERROR_ACTIVE;
-			return 0;
+			new_state = CAN_STATE_ERROR_ACTIVE;
+			break;
 		}
 		break;
 
@@ -465,9 +465,9 @@
 		}
 
 		if ((n & PCAN_USB_ERROR_BUS_HEAVY) == 0) {
-			/* no error (back to active state) */
-			mc->pdev->dev.can.state = CAN_STATE_ERROR_ACTIVE;
-			return 0;
+			/* no error (back to warning state) */
+			new_state = CAN_STATE_ERROR_WARNING;
+			break;
 		}
 		break;
 
@@ -506,6 +506,11 @@
 		mc->pdev->dev.can.can_stats.error_warning++;
 		break;
 
+	case CAN_STATE_ERROR_ACTIVE:
+		cf->can_id |= CAN_ERR_CRTL;
+		cf->data[1] = CAN_ERR_CRTL_ACTIVE;
+		break;
+
 	default:
 		/* CAN_STATE_MAX (trick to handle other errors) */
 		cf->can_id |= CAN_ERR_CRTL;
@@ -552,10 +557,15 @@
 	mc->ptr += PCAN_USB_CMD_ARGS;
 
 	if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
-		int err = pcan_usb_decode_ts(mc, !mc->rec_idx);
+		int err = pcan_usb_decode_ts(mc, !mc->rec_ts_idx);
 
 		if (err)
 			return err;
+
+		/* Next packet in the buffer will have a timestamp on a single
+		 * byte
+		 */
+		mc->rec_ts_idx++;
 	}
 
 	switch (f) {
@@ -638,10 +648,13 @@
 
 	cf->can_dlc = get_can_dlc(rec_len);
 
-	/* first data packet timestamp is a word */
-	if (pcan_usb_decode_ts(mc, !mc->rec_data_idx))
+	/* Only first packet timestamp is a word */
+	if (pcan_usb_decode_ts(mc, !mc->rec_ts_idx))
 		goto decode_failed;
 
+	/* Next packet in the buffer will have a timestamp on a single byte */
+	mc->rec_ts_idx++;
+
 	/* read data */
 	memset(cf->data, 0x0, sizeof(cf->data));
 	if (status_len & PCAN_USB_STATUSLEN_RTR) {
@@ -695,7 +708,6 @@
 		/* handle normal can frames here */
 		} else {
 			err = pcan_usb_decode_data(&mc, sl);
-			mc.rec_data_idx++;
 		}
 	}
 
--- linux-4.4.0.orig/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ linux-4.4.0/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -150,14 +150,55 @@
 	/* protect from getting timeval before setting now */
 	if (time_ref->tv_host.tv_sec > 0) {
 		u64 delta_us;
+		s64 delta_ts = 0;
 
-		delta_us = ts - time_ref->ts_dev_2;
-		if (ts < time_ref->ts_dev_2)
-			delta_us &= (1 << time_ref->adapter->ts_used_bits) - 1;
+		/* General case: dev_ts_1 < dev_ts_2 < ts, with:
+		 *
+		 * - dev_ts_1 = previous sync timestamp
+		 * - dev_ts_2 = last sync timestamp
+		 * - ts = event timestamp
+		 * - ts_period = known sync period (theoretical)
+		 *             ~ dev_ts2 - dev_ts1
+		 * *but*:
+		 *
+		 * - time counters wrap (see adapter->ts_used_bits)
+		 * - sometimes, dev_ts_1 < ts < dev_ts2
+		 *
+		 * "normal" case (sync time counters increase):
+		 * must take into account case when ts wraps (tsw)
+		 *
+		 *      < ts_period > <          >
+		 *     |             |            |
+		 *  ---+--------+----+-------0-+--+-->
+		 *     ts_dev_1 |    ts_dev_2  |
+		 *              ts             tsw
+		 */
+		if (time_ref->ts_dev_1 < time_ref->ts_dev_2) {
+			/* case when event time (tsw) wraps */
+			if (ts < time_ref->ts_dev_1)
+				delta_ts = BIT_ULL(time_ref->adapter->ts_used_bits);
+
+		/* Otherwise, sync time counter (ts_dev_2) has wrapped:
+		 * handle case when event time (tsn) hasn't.
+		 *
+		 *      < ts_period > <          >
+		 *     |             |            |
+		 *  ---+--------+--0-+---------+--+-->
+		 *     ts_dev_1 |    ts_dev_2  |
+		 *              tsn            ts
+		 */
+		} else if (time_ref->ts_dev_1 < ts) {
+			delta_ts = -BIT_ULL(time_ref->adapter->ts_used_bits);
+		}
+
+		/* add delay between last sync and event timestamps */
+		delta_ts += (signed int)(ts - time_ref->ts_dev_2);
 
-		delta_us += time_ref->ts_total;
+		/* add time from beginning to last sync */
+		delta_ts += time_ref->ts_total;
 
-		delta_us *= time_ref->adapter->us_per_ts_scale;
+		/* convert ticks number into microseconds */
+		delta_us = delta_ts * time_ref->adapter->us_per_ts_scale;
 		delta_us >>= time_ref->adapter->us_per_ts_shift;
 
 		*tv = time_ref->tv_host_0;
@@ -592,16 +633,16 @@
 	dev->state &= ~PCAN_USB_STATE_STARTED;
 	netif_stop_queue(netdev);
 
+	close_candev(netdev);
+
+	dev->can.state = CAN_STATE_STOPPED;
+
 	/* unlink all pending urbs and free used memory */
 	peak_usb_unlink_all_urbs(dev);
 
 	if (dev->adapter->dev_stop)
 		dev->adapter->dev_stop(dev);
 
-	close_candev(netdev);
-
-	dev->can.state = CAN_STATE_STOPPED;
-
 	/* can set bus off now */
 	if (dev->adapter->dev_set_bus) {
 		int err = dev->adapter->dev_set_bus(dev, 0);
@@ -776,7 +817,7 @@
 	dev = netdev_priv(netdev);
 
 	/* allocate a buffer large enough to send commands */
-	dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL);
+	dev->cmd_buf = kzalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL);
 	if (!dev->cmd_buf) {
 		err = -ENOMEM;
 		goto lbl_free_candev;
@@ -872,23 +913,25 @@
 static void peak_usb_disconnect(struct usb_interface *intf)
 {
 	struct peak_usb_device *dev;
+	struct peak_usb_device *dev_prev_siblings;
 
 	/* unregister as many netdev devices as siblings */
-	for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) {
+	for (dev = usb_get_intfdata(intf); dev; dev = dev_prev_siblings) {
 		struct net_device *netdev = dev->netdev;
 		char name[IFNAMSIZ];
 
+		dev_prev_siblings = dev->prev_siblings;
 		dev->state &= ~PCAN_USB_STATE_CONNECTED;
-		strncpy(name, netdev->name, IFNAMSIZ);
+		strlcpy(name, netdev->name, IFNAMSIZ);
 
 		unregister_netdev(netdev);
-		free_candev(netdev);
 
 		kfree(dev->cmd_buf);
 		dev->next_siblings = NULL;
 		if (dev->adapter->dev_free)
 			dev->adapter->dev_free(dev);
 
+		free_candev(netdev);
 		dev_info(&intf->dev, "%s removed\n", name);
 	}
 
--- linux-4.4.0.orig/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ linux-4.4.0/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -184,7 +184,7 @@
 	void *cmd_head = pcan_usb_fd_cmd_buffer(dev);
 	int err = 0;
 	u8 *packet_ptr;
-	int i, n = 1, packet_len;
+	int packet_len;
 	ptrdiff_t cmd_len;
 
 	/* usb device unregistered? */
@@ -201,17 +201,13 @@
 	}
 
 	packet_ptr = cmd_head;
+	packet_len = cmd_len;
 
 	/* firmware is not able to re-assemble 512 bytes buffer in full-speed */
-	if ((dev->udev->speed != USB_SPEED_HIGH) &&
-	    (cmd_len > PCAN_UFD_LOSPD_PKT_SIZE)) {
-		packet_len = PCAN_UFD_LOSPD_PKT_SIZE;
-		n += cmd_len / packet_len;
-	} else {
-		packet_len = cmd_len;
-	}
+	if (unlikely(dev->udev->speed != USB_SPEED_HIGH))
+		packet_len = min(packet_len, PCAN_UFD_LOSPD_PKT_SIZE);
 
-	for (i = 0; i < n; i++) {
+	do {
 		err = usb_bulk_msg(dev->udev,
 				   usb_sndbulkpipe(dev->udev,
 						   PCAN_USBPRO_EP_CMDOUT),
@@ -224,7 +220,12 @@
 		}
 
 		packet_ptr += packet_len;
-	}
+		cmd_len -= packet_len;
+
+		if (cmd_len < PCAN_UFD_LOSPD_PKT_SIZE)
+			packet_len = cmd_len;
+
+	} while (packet_len > 0);
 
 	return err;
 }
@@ -474,12 +475,18 @@
 				     struct pucan_msg *rx_msg)
 {
 	struct pucan_rx_msg *rm = (struct pucan_rx_msg *)rx_msg;
-	struct peak_usb_device *dev = usb_if->dev[pucan_msg_get_channel(rm)];
-	struct net_device *netdev = dev->netdev;
+	struct peak_usb_device *dev;
+	struct net_device *netdev;
 	struct canfd_frame *cfd;
 	struct sk_buff *skb;
 	const u16 rx_msg_flags = le16_to_cpu(rm->flags);
 
+	if (pucan_msg_get_channel(rm) >= ARRAY_SIZE(usb_if->dev))
+		return -ENOMEM;
+
+	dev = usb_if->dev[pucan_msg_get_channel(rm)];
+	netdev = dev->netdev;
+
 	if (rx_msg_flags & PUCAN_MSG_EXT_DATA_LEN) {
 		/* CANFD frame case */
 		skb = alloc_canfd_skb(netdev, &cfd);
@@ -526,15 +533,21 @@
 				     struct pucan_msg *rx_msg)
 {
 	struct pucan_status_msg *sm = (struct pucan_status_msg *)rx_msg;
-	struct peak_usb_device *dev = usb_if->dev[pucan_stmsg_get_channel(sm)];
-	struct pcan_usb_fd_device *pdev =
-			container_of(dev, struct pcan_usb_fd_device, dev);
+	struct pcan_usb_fd_device *pdev;
 	enum can_state new_state = CAN_STATE_ERROR_ACTIVE;
 	enum can_state rx_state, tx_state;
-	struct net_device *netdev = dev->netdev;
+	struct peak_usb_device *dev;
+	struct net_device *netdev;
 	struct can_frame *cf;
 	struct sk_buff *skb;
 
+	if (pucan_stmsg_get_channel(sm) >= ARRAY_SIZE(usb_if->dev))
+		return -ENOMEM;
+
+	dev = usb_if->dev[pucan_stmsg_get_channel(sm)];
+	pdev = container_of(dev, struct pcan_usb_fd_device, dev);
+	netdev = dev->netdev;
+
 	/* nothing should be sent while in BUS_OFF state */
 	if (dev->can.state == CAN_STATE_BUS_OFF)
 		return 0;
@@ -587,9 +600,14 @@
 				    struct pucan_msg *rx_msg)
 {
 	struct pucan_error_msg *er = (struct pucan_error_msg *)rx_msg;
-	struct peak_usb_device *dev = usb_if->dev[pucan_ermsg_get_channel(er)];
-	struct pcan_usb_fd_device *pdev =
-			container_of(dev, struct pcan_usb_fd_device, dev);
+	struct pcan_usb_fd_device *pdev;
+	struct peak_usb_device *dev;
+
+	if (pucan_ermsg_get_channel(er) >= ARRAY_SIZE(usb_if->dev))
+		return -EINVAL;
+
+	dev = usb_if->dev[pucan_ermsg_get_channel(er)];
+	pdev = container_of(dev, struct pcan_usb_fd_device, dev);
 
 	/* keep a trace of tx and rx error counters for later use */
 	pdev->bec.txerr = er->tx_err_cnt;
@@ -603,11 +621,17 @@
 				      struct pucan_msg *rx_msg)
 {
 	struct pcan_ufd_ovr_msg *ov = (struct pcan_ufd_ovr_msg *)rx_msg;
-	struct peak_usb_device *dev = usb_if->dev[pufd_omsg_get_channel(ov)];
-	struct net_device *netdev = dev->netdev;
+	struct peak_usb_device *dev;
+	struct net_device *netdev;
 	struct can_frame *cf;
 	struct sk_buff *skb;
 
+	if (pufd_omsg_get_channel(ov) >= ARRAY_SIZE(usb_if->dev))
+		return -EINVAL;
+
+	dev = usb_if->dev[pufd_omsg_get_channel(ov)];
+	netdev = dev->netdev;
+
 	/* allocate an skb to store the error frame */
 	skb = alloc_can_err_skb(netdev, &cf);
 	if (!skb)
@@ -725,6 +749,9 @@
 	u16 tx_msg_size, tx_msg_flags;
 	u8 can_dlc;
 
+	if (cfd->len > CANFD_MAX_DLEN)
+		return -EINVAL;
+
 	tx_msg_size = ALIGN(sizeof(struct pucan_tx_msg) + cfd->len, 4);
 	tx_msg->size = cpu_to_le16(tx_msg_size);
 	tx_msg->type = cpu_to_le16(PUCAN_MSG_CAN_TX);
@@ -850,7 +877,7 @@
 			goto err_out;
 
 		/* allocate command buffer once for all for the interface */
-		pdev->cmd_buffer_addr = kmalloc(PCAN_UFD_CMD_BUFFER_SIZE,
+		pdev->cmd_buffer_addr = kzalloc(PCAN_UFD_CMD_BUFFER_SIZE,
 						GFP_KERNEL);
 		if (!pdev->cmd_buffer_addr)
 			goto err_out_1;
--- linux-4.4.0.orig/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ linux-4.4.0/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -500,7 +500,7 @@
 	u8 *buffer;
 	int err;
 
-	buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL);
+	buffer = kzalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
 
--- linux-4.4.0.orig/drivers/net/can/usb/usb_8dev.c
+++ linux-4.4.0/drivers/net/can/usb/usb_8dev.c
@@ -524,6 +524,8 @@
 		break;
 
 	case -ENOENT:
+	case -EPIPE:
+	case -EPROTO:
 	case -ESHUTDOWN:
 		return;
 
@@ -680,9 +682,20 @@
 	atomic_inc(&priv->active_tx_urbs);
 
 	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (unlikely(err))
-		goto failed;
-	else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
+	if (unlikely(err)) {
+		can_free_echo_skb(netdev, context->echo_index);
+
+		usb_unanchor_urb(urb);
+		usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+
+		atomic_dec(&priv->active_tx_urbs);
+
+		if (err == -ENODEV)
+			netif_device_detach(netdev);
+		else
+			netdev_warn(netdev, "failed tx_urb %d\n", err);
+		stats->tx_dropped++;
+	} else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
 		/* Slow down tx path */
 		netif_stop_queue(netdev);
 
@@ -701,19 +714,6 @@
 
 	return NETDEV_TX_BUSY;
 
-failed:
-	can_free_echo_skb(netdev, context->echo_index);
-
-	usb_unanchor_urb(urb);
-	usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
-
-	atomic_dec(&priv->active_tx_urbs);
-
-	if (err == -ENODEV)
-		netif_device_detach(netdev);
-	else
-		netdev_warn(netdev, "failed tx_urb %d\n", err);
-
 nomembuf:
 	usb_free_urb(urb);
 
@@ -954,8 +954,8 @@
 	for (i = 0; i < MAX_TX_URBS; i++)
 		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
 
-	priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg),
-				      GFP_KERNEL);
+	priv->cmd_msg_buffer = devm_kzalloc(&intf->dev, sizeof(struct usb_8dev_cmd_msg),
+					    GFP_KERNEL);
 	if (!priv->cmd_msg_buffer)
 		goto cleanup_candev;
 
@@ -969,7 +969,7 @@
 	if (err) {
 		netdev_err(netdev,
 			"couldn't register CAN device: %d\n", err);
-		goto cleanup_cmd_msg_buffer;
+		goto cleanup_candev;
 	}
 
 	err = usb_8dev_cmd_version(priv, &version);
@@ -990,9 +990,6 @@
 cleanup_unregister_candev:
 	unregister_netdev(priv->netdev);
 
-cleanup_cmd_msg_buffer:
-	kfree(priv->cmd_msg_buffer);
-
 cleanup_candev:
 	free_candev(netdev);
 
@@ -1011,9 +1008,8 @@
 		netdev_info(priv->netdev, "device disconnected\n");
 
 		unregister_netdev(priv->netdev);
-		free_candev(priv->netdev);
-
 		unlink_all_urbs(priv);
+		free_candev(priv->netdev);
 	}
 
 }
--- linux-4.4.0.orig/drivers/net/can/xilinx_can.c
+++ linux-4.4.0/drivers/net/can/xilinx_can.c
@@ -2,6 +2,7 @@
  *
  * Copyright (C) 2012 - 2014 Xilinx, Inc.
  * Copyright (C) 2009 PetaLogix. All rights reserved.
+ * Copyright (C) 2017 Sandvik Mining and Construction Oy
  *
  * Description:
  * This driver is developed for Axi CAN IP and for Zynq CANPS Controller.
@@ -25,8 +26,10 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/skbuff.h>
+#include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/can/dev.h>
@@ -100,7 +103,7 @@
 #define XCAN_INTR_ALL		(XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\
 				 XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \
 				 XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \
-				 XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK)
+				 XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK)
 
 /* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */
 #define XCAN_BTR_SJW_SHIFT		7  /* Synchronous jump width */
@@ -117,6 +120,7 @@
 /**
  * struct xcan_priv - This definition define CAN driver instance
  * @can:			CAN private data structure.
+ * @tx_lock:			Lock for synchronizing TX interrupt handling
  * @tx_head:			Tx CAN packets ready to send on the queue
  * @tx_tail:			Tx CAN packets successfully sended on the queue
  * @tx_max:			Maximum number packets the driver can send
@@ -131,6 +135,7 @@
  */
 struct xcan_priv {
 	struct can_priv can;
+	spinlock_t tx_lock;
 	unsigned int tx_head;
 	unsigned int tx_tail;
 	unsigned int tx_max;
@@ -158,6 +163,11 @@
 	.brp_inc = 1,
 };
 
+#define XCAN_CAP_WATERMARK	0x0001
+struct xcan_devtype_data {
+	unsigned int caps;
+};
+
 /**
  * xcan_write_reg_le - Write a value to the device register little endian
  * @priv:	Driver private data structure
@@ -237,6 +247,10 @@
 		usleep_range(500, 10000);
 	}
 
+	/* reset clears FIFOs */
+	priv->tx_head = 0;
+	priv->tx_tail = 0;
+
 	return 0;
 }
 
@@ -391,6 +405,7 @@
 	struct net_device_stats *stats = &ndev->stats;
 	struct can_frame *cf = (struct can_frame *)skb->data;
 	u32 id, dlc, data[2] = {0, 0};
+	unsigned long flags;
 
 	if (can_dropped_invalid_skb(ndev, skb))
 		return NETDEV_TX_OK;
@@ -438,6 +453,9 @@
 		data[1] = be32_to_cpup((__be32 *)(cf->data + 4));
 
 	can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max);
+
+	spin_lock_irqsave(&priv->tx_lock, flags);
+
 	priv->tx_head++;
 
 	/* Write the Frame to Xilinx CAN TX FIFO */
@@ -453,10 +471,16 @@
 		stats->tx_bytes += cf->can_dlc;
 	}
 
+	/* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */
+	if (priv->tx_max > 1)
+		priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK);
+
 	/* Check if the TX buffer is full */
 	if ((priv->tx_head - priv->tx_tail) == priv->tx_max)
 		netif_stop_queue(ndev);
 
+	spin_unlock_irqrestore(&priv->tx_lock, flags);
+
 	return NETDEV_TX_OK;
 }
 
@@ -529,6 +553,123 @@
 }
 
 /**
+ * xcan_current_error_state - Get current error state from HW
+ * @ndev:	Pointer to net_device structure
+ *
+ * Checks the current CAN error state from the HW. Note that this
+ * only checks for ERROR_PASSIVE and ERROR_WARNING.
+ *
+ * Return:
+ * ERROR_PASSIVE or ERROR_WARNING if either is active, ERROR_ACTIVE
+ * otherwise.
+ */
+static enum can_state xcan_current_error_state(struct net_device *ndev)
+{
+	struct xcan_priv *priv = netdev_priv(ndev);
+	u32 status = priv->read_reg(priv, XCAN_SR_OFFSET);
+
+	if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK)
+		return CAN_STATE_ERROR_PASSIVE;
+	else if (status & XCAN_SR_ERRWRN_MASK)
+		return CAN_STATE_ERROR_WARNING;
+	else
+		return CAN_STATE_ERROR_ACTIVE;
+}
+
+/**
+ * xcan_set_error_state - Set new CAN error state
+ * @ndev:	Pointer to net_device structure
+ * @new_state:	The new CAN state to be set
+ * @cf:		Error frame to be populated or NULL
+ *
+ * Set new CAN error state for the device, updating statistics and
+ * populating the error frame if given.
+ */
+static void xcan_set_error_state(struct net_device *ndev,
+				 enum can_state new_state,
+				 struct can_frame *cf)
+{
+	struct xcan_priv *priv = netdev_priv(ndev);
+	u32 ecr = priv->read_reg(priv, XCAN_ECR_OFFSET);
+	u32 txerr = ecr & XCAN_ECR_TEC_MASK;
+	u32 rxerr = (ecr & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT;
+
+	priv->can.state = new_state;
+
+	if (cf) {
+		cf->can_id |= CAN_ERR_CRTL;
+		cf->data[6] = txerr;
+		cf->data[7] = rxerr;
+	}
+
+	switch (new_state) {
+	case CAN_STATE_ERROR_PASSIVE:
+		priv->can.can_stats.error_passive++;
+		if (cf)
+			cf->data[1] = (rxerr > 127) ?
+					CAN_ERR_CRTL_RX_PASSIVE :
+					CAN_ERR_CRTL_TX_PASSIVE;
+		break;
+	case CAN_STATE_ERROR_WARNING:
+		priv->can.can_stats.error_warning++;
+		if (cf)
+			cf->data[1] |= (txerr > rxerr) ?
+					CAN_ERR_CRTL_TX_WARNING :
+					CAN_ERR_CRTL_RX_WARNING;
+		break;
+	case CAN_STATE_ERROR_ACTIVE:
+		if (cf)
+			cf->data[1] |= CAN_ERR_CRTL_ACTIVE;
+		break;
+	default:
+		/* non-ERROR states are handled elsewhere */
+		WARN_ON(1);
+		break;
+	}
+}
+
+/**
+ * xcan_update_error_state_after_rxtx - Update CAN error state after RX/TX
+ * @ndev:	Pointer to net_device structure
+ *
+ * If the device is in a ERROR-WARNING or ERROR-PASSIVE state, check if
+ * the performed RX/TX has caused it to drop to a lesser state and set
+ * the interface state accordingly.
+ */
+static void xcan_update_error_state_after_rxtx(struct net_device *ndev)
+{
+	struct xcan_priv *priv = netdev_priv(ndev);
+	enum can_state old_state = priv->can.state;
+	enum can_state new_state;
+
+	/* changing error state due to successful frame RX/TX can only
+	 * occur from these states
+	 */
+	if (old_state != CAN_STATE_ERROR_WARNING &&
+	    old_state != CAN_STATE_ERROR_PASSIVE)
+		return;
+
+	new_state = xcan_current_error_state(ndev);
+
+	if (new_state != old_state) {
+		struct sk_buff *skb;
+		struct can_frame *cf;
+
+		skb = alloc_can_err_skb(ndev, &cf);
+
+		xcan_set_error_state(ndev, new_state, skb ? cf : NULL);
+
+		if (skb) {
+			struct net_device_stats *stats = &ndev->stats;
+
+			stats->rx_packets++;
+			stats->rx_bytes += cf->can_dlc;
+			netif_rx(skb);
+		}
+	}
+}
+
+/**
  * xcan_err_interrupt - error frame Isr
  * @ndev:	net_device pointer
  * @isr:	interrupt status register value
@@ -543,16 +684,12 @@
 	struct net_device_stats *stats = &ndev->stats;
 	struct can_frame *cf;
 	struct sk_buff *skb;
-	u32 err_status, status, txerr = 0, rxerr = 0;
+	u32 err_status;
 
 	skb = alloc_can_err_skb(ndev, &cf);
 
 	err_status = priv->read_reg(priv, XCAN_ESR_OFFSET);
 	priv->write_reg(priv, XCAN_ESR_OFFSET, err_status);
-	txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK;
-	rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) &
-			XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT);
-	status = priv->read_reg(priv, XCAN_SR_OFFSET);
 
 	if (isr & XCAN_IXR_BSOFF_MASK) {
 		priv->can.state = CAN_STATE_BUS_OFF;
@@ -562,28 +699,10 @@
 		can_bus_off(ndev);
 		if (skb)
 			cf->can_id |= CAN_ERR_BUSOFF;
-	} else if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) {
-		priv->can.state = CAN_STATE_ERROR_PASSIVE;
-		priv->can.can_stats.error_passive++;
-		if (skb) {
-			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (rxerr > 127) ?
-					CAN_ERR_CRTL_RX_PASSIVE :
-					CAN_ERR_CRTL_TX_PASSIVE;
-			cf->data[6] = txerr;
-			cf->data[7] = rxerr;
-		}
-	} else if (status & XCAN_SR_ERRWRN_MASK) {
-		priv->can.state = CAN_STATE_ERROR_WARNING;
-		priv->can.can_stats.error_warning++;
-		if (skb) {
-			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] |= (txerr > rxerr) ?
-					CAN_ERR_CRTL_TX_WARNING :
-					CAN_ERR_CRTL_RX_WARNING;
-			cf->data[6] = txerr;
-			cf->data[7] = rxerr;
-		}
+	} else {
+		enum can_state new_state = xcan_current_error_state(ndev);
+
+		xcan_set_error_state(ndev, new_state, skb ? cf : NULL);
 	}
 
 	/* Check for Arbitration lost interrupt */
@@ -599,7 +718,6 @@
 	if (isr & XCAN_IXR_RXOFLW_MASK) {
 		stats->rx_over_errors++;
 		stats->rx_errors++;
-		priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
 		if (skb) {
 			cf->can_id |= CAN_ERR_CRTL;
 			cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
@@ -708,26 +826,20 @@
 
 	isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
 	while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) {
-		if (isr & XCAN_IXR_RXOK_MASK) {
-			priv->write_reg(priv, XCAN_ICR_OFFSET,
-				XCAN_IXR_RXOK_MASK);
-			work_done += xcan_rx(ndev);
-		} else {
-			priv->write_reg(priv, XCAN_ICR_OFFSET,
-				XCAN_IXR_RXNEMP_MASK);
-			break;
-		}
+		work_done += xcan_rx(ndev);
 		priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK);
 		isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
 	}
 
-	if (work_done)
+	if (work_done) {
 		can_led_event(ndev, CAN_LED_EVENT_RX);
+		xcan_update_error_state_after_rxtx(ndev);
+	}
 
 	if (work_done < quota) {
 		napi_complete(napi);
 		ier = priv->read_reg(priv, XCAN_IER_OFFSET);
-		ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK);
+		ier |= XCAN_IXR_RXNEMP_MASK;
 		priv->write_reg(priv, XCAN_IER_OFFSET, ier);
 	}
 	return work_done;
@@ -742,18 +854,71 @@
 {
 	struct xcan_priv *priv = netdev_priv(ndev);
 	struct net_device_stats *stats = &ndev->stats;
+	unsigned int frames_in_fifo;
+	int frames_sent = 1; /* TXOK => at least 1 frame was sent */
+	unsigned long flags;
+	int retries = 0;
+
+	/* Synchronize with xmit as we need to know the exact number
+	 * of frames in the FIFO to stay in sync due to the TXFEMP
+	 * handling.
+	 * This also prevents a race between netif_wake_queue() and
+	 * netif_stop_queue().
+	 */
+	spin_lock_irqsave(&priv->tx_lock, flags);
+
+	frames_in_fifo = priv->tx_head - priv->tx_tail;
+
+	if (WARN_ON_ONCE(frames_in_fifo == 0)) {
+		/* clear TXOK anyway to avoid getting back here */
+		priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
+		spin_unlock_irqrestore(&priv->tx_lock, flags);
+		return;
+	}
+
+	/* Check if 2 frames were sent (TXOK only means that at least 1
+	 * frame was sent).
+	 */
+	if (frames_in_fifo > 1) {
+		WARN_ON(frames_in_fifo > priv->tx_max);
+
+		/* Synchronize TXOK and isr so that after the loop:
+		 * (1) isr variable is up-to-date at least up to TXOK clear
+		 *     time. This avoids us clearing a TXOK of a second frame
+		 *     but not noticing that the FIFO is now empty and thus
+		 *     marking only a single frame as sent.
+		 * (2) No TXOK is left. Having one could mean leaving a
+		 *     stray TXOK as we might process the associated frame
+		 *     via TXFEMP handling as we read TXFEMP *after* TXOK
+		 *     clear to satisfy (1).
+		 */
+		while ((isr & XCAN_IXR_TXOK_MASK) && !WARN_ON(++retries == 100)) {
+			priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
+			isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
+		}
 
-	while ((priv->tx_head - priv->tx_tail > 0) &&
-			(isr & XCAN_IXR_TXOK_MASK)) {
+		if (isr & XCAN_IXR_TXFEMP_MASK) {
+			/* nothing in FIFO anymore */
+			frames_sent = frames_in_fifo;
+		}
+	} else {
+		/* single frame in fifo, just clear TXOK */
 		priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
+	}
+
+	while (frames_sent--) {
 		can_get_echo_skb(ndev, priv->tx_tail %
 					priv->tx_max);
 		priv->tx_tail++;
 		stats->tx_packets++;
-		isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
 	}
-	can_led_event(ndev, CAN_LED_EVENT_TX);
+
 	netif_wake_queue(ndev);
+
+	spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+	can_led_event(ndev, CAN_LED_EVENT_TX);
+	xcan_update_error_state_after_rxtx(ndev);
 }
 
 /**
@@ -772,6 +937,7 @@
 	struct net_device *ndev = (struct net_device *)dev_id;
 	struct xcan_priv *priv = netdev_priv(ndev);
 	u32 isr, ier;
+	u32 isr_errors;
 
 	/* Get the interrupt status from Xilinx CAN */
 	isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
@@ -790,18 +956,17 @@
 		xcan_tx_interrupt(ndev, isr);
 
 	/* Check for the type of error interrupt and Processing it */
-	if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
-			XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) {
-		priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_ERROR_MASK |
-				XCAN_IXR_RXOFLW_MASK | XCAN_IXR_BSOFF_MASK |
-				XCAN_IXR_ARBLST_MASK));
+	isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
+			    XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK);
+	if (isr_errors) {
+		priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors);
 		xcan_err_interrupt(ndev, isr);
 	}
 
 	/* Check for the type of receive interrupt and Processing it */
-	if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) {
+	if (isr & XCAN_IXR_RXNEMP_MASK) {
 		ier = priv->read_reg(priv, XCAN_IER_OFFSET);
-		ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK);
+		ier &= ~XCAN_IXR_RXNEMP_MASK;
 		priv->write_reg(priv, XCAN_IER_OFFSET, ier);
 		napi_schedule(&priv->napi);
 	}
@@ -1030,6 +1195,18 @@
 
 static SIMPLE_DEV_PM_OPS(xcan_dev_pm_ops, xcan_suspend, xcan_resume);
 
+static const struct xcan_devtype_data xcan_zynq_data = {
+	.caps = XCAN_CAP_WATERMARK,
+};
+
+/* Match table for OF platform binding */
+static const struct of_device_id xcan_of_match[] = {
+	{ .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data },
+	{ .compatible = "xlnx,axi-can-1.00.a", },
+	{ /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, xcan_of_match);
+
 /**
  * xcan_probe - Platform registration call
  * @pdev:	Handle to the platform device structure
@@ -1044,8 +1221,10 @@
 	struct resource *res; /* IO mem resources */
 	struct net_device *ndev;
 	struct xcan_priv *priv;
+	const struct of_device_id *of_id;
+	int caps = 0;
 	void __iomem *addr;
-	int ret, rx_max, tx_max;
+	int ret, rx_max, tx_max, tx_fifo_depth;
 
 	/* Get the virtual base address for the device */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1055,7 +1234,8 @@
 		goto err;
 	}
 
-	ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", &tx_max);
+	ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
+				   &tx_fifo_depth);
 	if (ret < 0)
 		goto err;
 
@@ -1063,6 +1243,30 @@
 	if (ret < 0)
 		goto err;
 
+	of_id = of_match_device(xcan_of_match, &pdev->dev);
+	if (of_id) {
+		const struct xcan_devtype_data *devtype_data = of_id->data;
+
+		if (devtype_data)
+			caps = devtype_data->caps;
+	}
+
+	/* There is no way to directly figure out how many frames have been
+	 * sent when the TXOK interrupt is processed. If watermark programming
+	 * is supported, we can have 2 frames in the FIFO and use TXFEMP
+	 * to determine if 1 or 2 frames have been sent.
+	 * Theoretically we should be able to use TXFWMEMP to determine up
+	 * to 3 frames, but it seems that after putting a second frame in the
+	 * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less
+	 * than 2 frames in FIFO) is set anyway with no TXOK (a frame was
+	 * sent), which is not a sensible state - possibly TXFWMEMP is not
+	 * completely synchronized with the rest of the bits?
+	 */
+	if (caps & XCAN_CAP_WATERMARK)
+		tx_max = min(tx_fifo_depth, 2);
+	else
+		tx_max = 1;
+
 	/* Create a CAN device instance */
 	ndev = alloc_candev(sizeof(struct xcan_priv), tx_max);
 	if (!ndev)
@@ -1077,6 +1281,7 @@
 					CAN_CTRLMODE_BERR_REPORTING;
 	priv->reg_base = addr;
 	priv->tx_max = tx_max;
+	spin_lock_init(&priv->tx_lock);
 
 	/* Get IRQ for the device */
 	ndev->irq = platform_get_irq(pdev, 0);
@@ -1144,9 +1349,9 @@
 	devm_can_led_init(ndev);
 	clk_disable_unprepare(priv->bus_clk);
 	clk_disable_unprepare(priv->can_clk);
-	netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n",
+	netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth: actual %d, using %d\n",
 			priv->reg_base, ndev->irq, priv->can.clock.freq,
-			priv->tx_max);
+			tx_fifo_depth, priv->tx_max);
 
 	return 0;
 
@@ -1182,14 +1387,6 @@
 	return 0;
 }
 
-/* Match table for OF platform binding */
-static const struct of_device_id xcan_of_match[] = {
-	{ .compatible = "xlnx,zynq-can-1.0", },
-	{ .compatible = "xlnx,axi-can-1.00.a", },
-	{ /* end of list */ },
-};
-MODULE_DEVICE_TABLE(of, xcan_of_match);
-
 static struct platform_driver xcan_driver = {
 	.probe = xcan_probe,
 	.remove	= xcan_remove,
--- linux-4.4.0.orig/drivers/net/dsa/bcm_sf2.c
+++ linux-4.4.0/drivers/net/dsa/bcm_sf2.c
@@ -1137,6 +1137,7 @@
 				   struct phy_device *phydev)
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	struct ethtool_eee *p = &priv->port_sts[port].eee;
 	u32 id_mode_dis = 0, port_mode;
 	const char *str = NULL;
 	u32 reg;
@@ -1211,6 +1212,9 @@
 		reg |= DUPLX_MODE;
 
 	core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
+
+	if (!phydev->is_pseudo_fixed_link)
+		p->eee_enabled = bcm_sf2_eee_init(ds, port, phydev);
 }
 
 static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
--- linux-4.4.0.orig/drivers/net/dsa/bcm_sf2.h
+++ linux-4.4.0/drivers/net/dsa/bcm_sf2.h
@@ -187,8 +187,8 @@
 static inline void intrl2_##which##_mask_clear(struct bcm_sf2_priv *priv, \
 						u32 mask)		\
 {									\
-	intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);	\
 	priv->irq##which##_mask &= ~(mask);				\
+	intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);	\
 }									\
 static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \
 						u32 mask)		\
--- linux-4.4.0.orig/drivers/net/dsa/mv88e6060.c
+++ linux-4.4.0/drivers/net/dsa/mv88e6060.c
@@ -98,8 +98,7 @@
 	/* Reset the switch. */
 	REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
 		  GLOBAL_ATU_CONTROL_SWRESET |
-		  GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
-		  GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
+		  GLOBAL_ATU_CONTROL_LEARNDIS);
 
 	/* Wait up to one second for reset to complete. */
 	timeout = jiffies + 1 * HZ;
@@ -124,13 +123,10 @@
 	 */
 	REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536);
 
-	/* Enable automatic address learning, set the address
-	 * database size to 1024 entries, and set the default aging
-	 * time to 5 minutes.
+	/* Disable automatic address learning.
 	 */
 	REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
-		  GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
-		  GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
+		  GLOBAL_ATU_CONTROL_LEARNDIS);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/dsa/mv88e6xxx.c
+++ linux-4.4.0/drivers/net/dsa/mv88e6xxx.c
@@ -712,7 +712,7 @@
 		if (s->sizeof_stat == 8)
 			_mv88e6xxx_stats_read(ds, s->reg + 1, &high);
 	}
-	value = (((u64)high) << 16) | low;
+	value = (((u64)high) << 32) | low;
 	return value;
 }
 
@@ -1519,7 +1519,7 @@
 
 	/* no PVID with ranges, otherwise it's a bug */
 	if (pvid)
-		err = _mv88e6xxx_port_pvid_set(ds, port, vid);
+		err = _mv88e6xxx_port_pvid_set(ds, port, vlan->vid_end);
 unlock:
 	mutex_unlock(&ps->smi_mutex);
 
@@ -2064,9 +2064,9 @@
 	 * the other bits clear.
 	 */
 	reg = 1 << port;
-	/* Disable learning for DSA and CPU ports */
-	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
-		reg = PORT_ASSOC_VECTOR_LOCKED_PORT;
+	/* Disable learning for CPU port */
+	if (dsa_is_cpu_port(ds, port))
+		reg = 0;
 
 	ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR, reg);
 	if (ret)
@@ -2150,7 +2150,8 @@
 	 * database, and allow every port to egress frames on all other ports.
 	 */
 	reg = BIT(ps->num_ports) - 1; /* all ports */
-	ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg & ~port);
+	reg &= ~BIT(port); /* except itself */
+	ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg);
 	if (ret)
 		goto abort;
 
--- linux-4.4.0.orig/drivers/net/ethernet/3com/3c509.c
+++ linux-4.4.0/drivers/net/ethernet/3com/3c509.c
@@ -562,7 +562,7 @@
 }
 
 #ifdef CONFIG_EISA
-static int __init el3_eisa_probe (struct device *device)
+static int el3_eisa_probe(struct device *device)
 {
 	short i;
 	int ioaddr, irq, if_port;
@@ -1369,7 +1369,7 @@
 #endif /* CONFIG_PM */
 
 module_param(debug,int, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param(max_interrupt_work, int, 0);
 MODULE_PARM_DESC(debug, "debug level (0-6)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
--- linux-4.4.0.orig/drivers/net/ethernet/3com/3c59x.c
+++ linux-4.4.0/drivers/net/ethernet/3com/3c59x.c
@@ -813,8 +813,8 @@
 module_param_array(enable_wol, int, NULL, 0);
 module_param(rx_copybreak, int, 0);
 module_param(max_interrupt_work, int, 0);
-module_param(compaq_ioaddr, int, 0);
-module_param(compaq_irq, int, 0);
+module_param_hw(compaq_ioaddr, int, ioport, 0);
+module_param_hw(compaq_irq, int, irq, 0);
 module_param(compaq_device_id, int, 0);
 module_param(watchdog, int, 0);
 module_param(global_use_mmio, int, 0);
@@ -907,7 +907,7 @@
 };
 MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
 
-static int __init vortex_eisa_probe(struct device *device)
+static int vortex_eisa_probe(struct device *device)
 {
 	void __iomem *ioaddr;
 	struct eisa_device *edev;
--- linux-4.4.0.orig/drivers/net/ethernet/3com/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/3com/Kconfig
@@ -32,7 +32,7 @@
 
 config 3C515
 	tristate "3c515 ISA \"Fast EtherLink\""
-	depends on ISA && ISA_DMA_API
+	depends on ISA && ISA_DMA_API && !PPC32
 	---help---
 	  If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
 	  network card, say Y here.
--- linux-4.4.0.orig/drivers/net/ethernet/3com/typhoon.c
+++ linux-4.4.0/drivers/net/ethernet/3com/typhoon.c
@@ -2366,9 +2366,9 @@
 	 * 4) Get the hardware address.
 	 * 5) Put the card to sleep.
 	 */
-	if (typhoon_reset(ioaddr, WaitSleep) < 0) {
+	err = typhoon_reset(ioaddr, WaitSleep);
+	if (err < 0) {
 		err_msg = "could not reset 3XP";
-		err = -EIO;
 		goto error_out_dma;
 	}
 
@@ -2382,24 +2382,25 @@
 	typhoon_init_interface(tp);
 	typhoon_init_rings(tp);
 
-	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
+	err = typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST);
+	if (err < 0) {
 		err_msg = "cannot boot 3XP sleep image";
-		err = -EIO;
 		goto error_out_reset;
 	}
 
 	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS);
-	if(typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp) < 0) {
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp);
+	if (err < 0) {
 		err_msg = "cannot read MAC address";
-		err = -EIO;
 		goto error_out_reset;
 	}
 
 	*(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
 	*(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
 
-	if(!is_valid_ether_addr(dev->dev_addr)) {
+	if (!is_valid_ether_addr(dev->dev_addr)) {
 		err_msg = "Could not obtain valid ethernet address, aborting";
+		err = -EIO;
 		goto error_out_reset;
 	}
 
@@ -2407,7 +2408,8 @@
 	 * later when we print out the version reported.
 	 */
 	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
-	if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp);
+	if (err < 0) {
 		err_msg = "Could not get Sleep Image version";
 		goto error_out_reset;
 	}
@@ -2424,9 +2426,9 @@
 	if(xp_resp[0].numDesc != 0)
 		tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET;
 
-	if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) {
+	err = typhoon_sleep(tp, PCI_D3hot, 0);
+	if (err < 0) {
 		err_msg = "cannot put adapter to sleep";
-		err = -EIO;
 		goto error_out_reset;
 	}
 
@@ -2449,7 +2451,8 @@
 	dev->features = dev->hw_features |
 		NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXCSUM;
 
-	if(register_netdev(dev) < 0) {
+	err = register_netdev(dev);
+	if (err < 0) {
 		err_msg = "unable to register netdev";
 		goto error_out_reset;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/8390/mac8390.c
+++ linux-4.4.0/drivers/net/ethernet/8390/mac8390.c
@@ -156,8 +156,6 @@
 #define memcpy_fromio(a, b, c)	memcpy((a), (void *)(b), (c))
 #define memcpy_toio(a, b, c)	memcpy((void *)(a), (b), (c))
 
-#define memcmp_withio(a, b, c)	memcmp((a), (void *)(b), (c))
-
 /* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
 static void slow_sane_get_8390_hdr(struct net_device *dev,
 				   struct e8390_pkt_hdr *hdr, int ring_page);
@@ -237,19 +235,26 @@
 
 static enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
 {
-	unsigned long outdata = 0xA5A0B5B0;
-	unsigned long indata =  0x00000000;
+	u32 outdata = 0xA5A0B5B0;
+	u32 indata = 0;
+
 	/* Try writing 32 bits */
-	memcpy_toio(membase, &outdata, 4);
-	/* Now compare them */
-	if (memcmp_withio(&outdata, membase, 4) == 0)
+	nubus_writel(outdata, membase);
+	/* Now read it back */
+	indata = nubus_readl(membase);
+	if (outdata == indata)
 		return ACCESS_32;
+
+	outdata = 0xC5C0D5D0;
+	indata = 0;
+
 	/* Write 16 bit output */
 	word_memcpy_tocard(membase, &outdata, 4);
 	/* Now read it back */
 	word_memcpy_fromcard(&indata, membase, 4);
 	if (outdata == indata)
 		return ACCESS_16;
+
 	return ACCESS_UNKNOWN;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/8390/ne.c
+++ linux-4.4.0/drivers/net/ethernet/8390/ne.c
@@ -74,8 +74,8 @@
 static u32 ne_msg_enable;
 
 #ifdef MODULE
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param_array(bad, int, NULL, 0);
 module_param_named(msg_enable, ne_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH));
 MODULE_PARM_DESC(io, "I/O base address(es),required");
--- linux-4.4.0.orig/drivers/net/ethernet/8390/smc-ultra.c
+++ linux-4.4.0/drivers/net/ethernet/8390/smc-ultra.c
@@ -562,8 +562,8 @@
 static int io[MAX_ULTRA_CARDS];
 static int irq[MAX_ULTRA_CARDS];
 
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param_named(msg_enable, ultra_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH));
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
--- linux-4.4.0.orig/drivers/net/ethernet/8390/wd.c
+++ linux-4.4.0/drivers/net/ethernet/8390/wd.c
@@ -504,10 +504,10 @@
 static int mem[MAX_WD_CARDS];
 static int mem_end[MAX_WD_CARDS];	/* for non std. mem size */
 
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param_array(mem_end, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
+module_param_hw_array(mem, int, iomem, NULL, 0);
+module_param_hw_array(mem_end, int, iomem, NULL, 0);
 module_param_named(msg_enable, wd_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH));
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)");
--- linux-4.4.0.orig/drivers/net/ethernet/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/Kconfig
@@ -24,6 +24,7 @@
 source "drivers/net/ethernet/allwinner/Kconfig"
 source "drivers/net/ethernet/alteon/Kconfig"
 source "drivers/net/ethernet/altera/Kconfig"
+source "drivers/net/ethernet/amazon/Kconfig"
 source "drivers/net/ethernet/amd/Kconfig"
 source "drivers/net/ethernet/apm/Kconfig"
 source "drivers/net/ethernet/apple/Kconfig"
--- linux-4.4.0.orig/drivers/net/ethernet/Makefile
+++ linux-4.4.0/drivers/net/ethernet/Makefile
@@ -10,6 +10,7 @@
 obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/
 obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
 obj-$(CONFIG_ALTERA_TSE) += altera/
+obj-$(CONFIG_NET_VENDOR_AMAZON) += amazon/
 obj-$(CONFIG_NET_VENDOR_AMD) += amd/
 obj-$(CONFIG_NET_XGENE) += apm/
 obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
--- linux-4.4.0.orig/drivers/net/ethernet/adaptec/starfire.c
+++ linux-4.4.0/drivers/net/ethernet/adaptec/starfire.c
@@ -1153,6 +1153,12 @@
 		if (skb == NULL)
 			break;
 		np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(np->pci_dev,
+					  np->rx_info[i].mapping)) {
+			dev_kfree_skb(skb);
+			np->rx_info[i].skb = NULL;
+			break;
+		}
 		/* Grrr, we cannot offset to correctly align the IP header. */
 		np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid);
 	}
@@ -1183,8 +1189,9 @@
 {
 	struct netdev_private *np = netdev_priv(dev);
 	unsigned int entry;
+	unsigned int prev_tx;
 	u32 status;
-	int i;
+	int i, j;
 
 	/*
 	 * be cautious here, wrapping the queue has weird semantics
@@ -1202,6 +1209,7 @@
 	}
 #endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
 
+	prev_tx = np->cur_tx;
 	entry = np->cur_tx % TX_RING_SIZE;
 	for (i = 0; i < skb_num_frags(skb); i++) {
 		int wrap_ring = 0;
@@ -1235,6 +1243,11 @@
 					       skb_frag_size(this_frag),
 					       PCI_DMA_TODEVICE);
 		}
+		if (pci_dma_mapping_error(np->pci_dev,
+					  np->tx_info[entry].mapping)) {
+			dev->stats.tx_dropped++;
+			goto err_out;
+		}
 
 		np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping);
 		np->tx_ring[entry].status = cpu_to_le32(status);
@@ -1269,8 +1282,30 @@
 		netif_stop_queue(dev);
 
 	return NETDEV_TX_OK;
-}
 
+err_out:
+	entry = prev_tx % TX_RING_SIZE;
+	np->tx_info[entry].skb = NULL;
+	if (i > 0) {
+		pci_unmap_single(np->pci_dev,
+				 np->tx_info[entry].mapping,
+				 skb_first_frag_len(skb),
+				 PCI_DMA_TODEVICE);
+		np->tx_info[entry].mapping = 0;
+		entry = (entry + np->tx_info[entry].used_slots) % TX_RING_SIZE;
+		for (j = 1; j < i; j++) {
+			pci_unmap_single(np->pci_dev,
+					 np->tx_info[entry].mapping,
+					 skb_frag_size(
+						&skb_shinfo(skb)->frags[j-1]),
+					 PCI_DMA_TODEVICE);
+			entry++;
+		}
+	}
+	dev_kfree_skb_any(skb);
+	np->cur_tx = prev_tx;
+	return NETDEV_TX_OK;
+}
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
@@ -1570,6 +1605,12 @@
 				break;	/* Better luck next round. */
 			np->rx_info[entry].mapping =
 				pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			if (pci_dma_mapping_error(np->pci_dev,
+						np->rx_info[entry].mapping)) {
+				dev_kfree_skb(skb);
+				np->rx_info[entry].skb = NULL;
+				break;
+			}
 			np->rx_ring[entry].rxaddr =
 				cpu_to_dma(np->rx_info[entry].mapping | RxDescValid);
 		}
--- linux-4.4.0.orig/drivers/net/ethernet/agere/et131x.c
+++ linux-4.4.0/drivers/net/ethernet/agere/et131x.c
@@ -3854,7 +3854,7 @@
 	unsigned long flags;
 
 	/* If the device is closed, ignore the timeout */
-	if (~(adapter->flags & FMP_ADAPTER_INTERRUPT_IN_USE))
+	if (!(adapter->flags & FMP_ADAPTER_INTERRUPT_IN_USE))
 		return;
 
 	/* Any nonrecoverable hardware error?
--- linux-4.4.0.orig/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ linux-4.4.0/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -438,7 +438,7 @@
 /* Hardware start transmission.
  * Send a packet to media from the upper layer.
  */
-static int emac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct emac_board_info *db = netdev_priv(dev);
 	unsigned long channel;
@@ -446,7 +446,7 @@
 
 	channel = db->tx_fifo_stat & 3;
 	if (channel == 3)
-		return 1;
+		return NETDEV_TX_BUSY;
 
 	channel = (channel == 1 ? 1 : 0);
 
@@ -853,13 +853,13 @@
 	db->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(db->clk)) {
 		ret = PTR_ERR(db->clk);
-		goto out_iounmap;
+		goto out_dispose_mapping;
 	}
 
 	ret = clk_prepare_enable(db->clk);
 	if (ret) {
 		dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", ret);
-		goto out_iounmap;
+		goto out_dispose_mapping;
 	}
 
 	ret = sunxi_sram_claim(&pdev->dev);
@@ -916,6 +916,8 @@
 	sunxi_sram_release(&pdev->dev);
 out_clk_disable_unprepare:
 	clk_disable_unprepare(db->clk);
+out_dispose_mapping:
+	irq_dispose_mapping(ndev->irq);
 out_iounmap:
 	iounmap(db->membase);
 out:
@@ -934,6 +936,7 @@
 	unregister_netdev(ndev);
 	sunxi_sram_release(&pdev->dev);
 	clk_disable_unprepare(db->clk);
+	irq_dispose_mapping(ndev->irq);
 	iounmap(db->membase);
 	free_netdev(ndev);
 
--- linux-4.4.0.orig/drivers/net/ethernet/altera/altera_msgdma.c
+++ linux-4.4.0/drivers/net/ethernet/altera/altera_msgdma.c
@@ -145,7 +145,8 @@
 			& 0xffff;
 
 	if (inuse) { /* Tx FIFO is not empty */
-		ready = priv->tx_prod - priv->tx_cons - inuse - 1;
+		ready = max_t(int,
+			      priv->tx_prod - priv->tx_cons - inuse - 1, 0);
 	} else {
 		/* Check for buffered last packet */
 		status = csrrd32(priv->tx_dma_csr, msgdma_csroffs(status));
--- linux-4.4.0.orig/drivers/net/ethernet/altera/altera_tse_main.c
+++ linux-4.4.0/drivers/net/ethernet/altera/altera_tse_main.c
@@ -716,8 +716,10 @@
 
 		phydev = phy_connect(dev, phy_id_fmt, &altera_tse_adjust_link,
 				     priv->phy_iface);
-		if (IS_ERR(phydev))
+		if (IS_ERR(phydev)) {
 			netdev_err(dev, "Could not attach to PHY\n");
+			phydev = NULL;
+		}
 
 	} else {
 		int ret;
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/amazon/Kconfig
@@ -0,0 +1,28 @@
+#
+# Amazon network device configuration
+#
+
+config NET_VENDOR_AMAZON
+	bool "Amazon Devices"
+	default y
+	---help---
+	  If you have a network (Ethernet) device belonging to this class, say Y.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about Amazon devices. If you say Y, you will be asked
+	  for your specific device in the following questions.
+
+if NET_VENDOR_AMAZON
+
+config ENA_ETHERNET
+	tristate "Elastic Network Adapter (ENA) support"
+	depends on PCI_MSI && !CPU_BIG_ENDIAN
+	select DIMLIB
+	---help---
+	  This driver supports Elastic Network Adapter (ENA)"
+
+	  To compile this driver as a module, choose M here.
+	  The module will be called ena.
+
+endif #NET_VENDOR_AMAZON
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/Makefile
+++ linux-4.4.0/drivers/net/ethernet/amazon/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Amazon network device drivers.
+#
+
+obj-$(CONFIG_ENA_ETHERNET) += ena/
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/Makefile
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Elastic Network Adapter (ENA) device drivers.
+#
+
+obj-$(CONFIG_ENA_ETHERNET) += ena.o
+
+ena-y := ena_netdev.o ena_com.o ena_eth_com.o ena_ethtool.o
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
@@ -0,0 +1,1128 @@
+/*
+ * Copyright 2015 - 2016 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _ENA_ADMIN_H_
+#define _ENA_ADMIN_H_
+
+
+enum ena_admin_aq_opcode {
+	ENA_ADMIN_CREATE_SQ                         = 1,
+	ENA_ADMIN_DESTROY_SQ                        = 2,
+	ENA_ADMIN_CREATE_CQ                         = 3,
+	ENA_ADMIN_DESTROY_CQ                        = 4,
+	ENA_ADMIN_GET_FEATURE                       = 8,
+	ENA_ADMIN_SET_FEATURE                       = 9,
+	ENA_ADMIN_GET_STATS                         = 11,
+};
+
+enum ena_admin_aq_completion_status {
+	ENA_ADMIN_SUCCESS                           = 0,
+	ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE       = 1,
+	ENA_ADMIN_BAD_OPCODE                        = 2,
+	ENA_ADMIN_UNSUPPORTED_OPCODE                = 3,
+	ENA_ADMIN_MALFORMED_REQUEST                 = 4,
+	/* Additional status is provided in ACQ entry extended_status */
+	ENA_ADMIN_ILLEGAL_PARAMETER                 = 5,
+	ENA_ADMIN_UNKNOWN_ERROR                     = 6,
+	ENA_ADMIN_RESOURCE_BUSY                     = 7,
+};
+
+enum ena_admin_aq_feature_id {
+	ENA_ADMIN_DEVICE_ATTRIBUTES                 = 1,
+	ENA_ADMIN_MAX_QUEUES_NUM                    = 2,
+	ENA_ADMIN_HW_HINTS                          = 3,
+	ENA_ADMIN_LLQ                               = 4,
+	ENA_ADMIN_MAX_QUEUES_EXT                    = 7,
+	ENA_ADMIN_RSS_HASH_FUNCTION                 = 10,
+	ENA_ADMIN_STATELESS_OFFLOAD_CONFIG          = 11,
+	ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG      = 12,
+	ENA_ADMIN_MTU                               = 14,
+	ENA_ADMIN_RSS_HASH_INPUT                    = 18,
+	ENA_ADMIN_INTERRUPT_MODERATION              = 20,
+	ENA_ADMIN_AENQ_CONFIG                       = 26,
+	ENA_ADMIN_LINK_CONFIG                       = 27,
+	ENA_ADMIN_HOST_ATTR_CONFIG                  = 28,
+	ENA_ADMIN_FEATURES_OPCODE_NUM               = 32,
+};
+
+enum ena_admin_placement_policy_type {
+	/* descriptors and headers are in host memory */
+	ENA_ADMIN_PLACEMENT_POLICY_HOST             = 1,
+	/* descriptors and headers are in device memory (a.k.a Low Latency
+	 * Queue)
+	 */
+	ENA_ADMIN_PLACEMENT_POLICY_DEV              = 3,
+};
+
+enum ena_admin_link_types {
+	ENA_ADMIN_LINK_SPEED_1G                     = 0x1,
+	ENA_ADMIN_LINK_SPEED_2_HALF_G               = 0x2,
+	ENA_ADMIN_LINK_SPEED_5G                     = 0x4,
+	ENA_ADMIN_LINK_SPEED_10G                    = 0x8,
+	ENA_ADMIN_LINK_SPEED_25G                    = 0x10,
+	ENA_ADMIN_LINK_SPEED_40G                    = 0x20,
+	ENA_ADMIN_LINK_SPEED_50G                    = 0x40,
+	ENA_ADMIN_LINK_SPEED_100G                   = 0x80,
+	ENA_ADMIN_LINK_SPEED_200G                   = 0x100,
+	ENA_ADMIN_LINK_SPEED_400G                   = 0x200,
+};
+
+enum ena_admin_completion_policy_type {
+	/* completion queue entry for each sq descriptor */
+	ENA_ADMIN_COMPLETION_POLICY_DESC            = 0,
+	/* completion queue entry upon request in sq descriptor */
+	ENA_ADMIN_COMPLETION_POLICY_DESC_ON_DEMAND  = 1,
+	/* current queue head pointer is updated in OS memory upon sq
+	 * descriptor request
+	 */
+	ENA_ADMIN_COMPLETION_POLICY_HEAD_ON_DEMAND  = 2,
+	/* current queue head pointer is updated in OS memory for each sq
+	 * descriptor
+	 */
+	ENA_ADMIN_COMPLETION_POLICY_HEAD            = 3,
+};
+
+/* basic stats return ena_admin_basic_stats while extanded stats return a
+ * buffer (string format) with additional statistics per queue and per
+ * device id
+ */
+enum ena_admin_get_stats_type {
+	ENA_ADMIN_GET_STATS_TYPE_BASIC              = 0,
+	ENA_ADMIN_GET_STATS_TYPE_EXTENDED           = 1,
+};
+
+enum ena_admin_get_stats_scope {
+	ENA_ADMIN_SPECIFIC_QUEUE                    = 0,
+	ENA_ADMIN_ETH_TRAFFIC                       = 1,
+};
+
+struct ena_admin_aq_common_desc {
+	/* 11:0 : command_id
+	 * 15:12 : reserved12
+	 */
+	u16 command_id;
+
+	/* as appears in ena_admin_aq_opcode */
+	u8 opcode;
+
+	/* 0 : phase
+	 * 1 : ctrl_data - control buffer address valid
+	 * 2 : ctrl_data_indirect - control buffer address
+	 *    points to list of pages with addresses of control
+	 *    buffers
+	 * 7:3 : reserved3
+	 */
+	u8 flags;
+};
+
+/* used in ena_admin_aq_entry. Can point directly to control data, or to a
+ * page list chunk. Used also at the end of indirect mode page list chunks,
+ * for chaining.
+ */
+struct ena_admin_ctrl_buff_info {
+	u32 length;
+
+	struct ena_common_mem_addr address;
+};
+
+struct ena_admin_sq {
+	u16 sq_idx;
+
+	/* 4:0 : reserved
+	 * 7:5 : sq_direction - 0x1 - Tx; 0x2 - Rx
+	 */
+	u8 sq_identity;
+
+	u8 reserved1;
+};
+
+struct ena_admin_aq_entry {
+	struct ena_admin_aq_common_desc aq_common_descriptor;
+
+	union {
+		u32 inline_data_w1[3];
+
+		struct ena_admin_ctrl_buff_info control_buffer;
+	} u;
+
+	u32 inline_data_w4[12];
+};
+
+struct ena_admin_acq_common_desc {
+	/* command identifier to associate it with the aq descriptor
+	 * 11:0 : command_id
+	 * 15:12 : reserved12
+	 */
+	u16 command;
+
+	u8 status;
+
+	/* 0 : phase
+	 * 7:1 : reserved1
+	 */
+	u8 flags;
+
+	u16 extended_status;
+
+	/* indicates to the driver which AQ entry has been consumed by the
+	 *    device and could be reused
+	 */
+	u16 sq_head_indx;
+};
+
+struct ena_admin_acq_entry {
+	struct ena_admin_acq_common_desc acq_common_descriptor;
+
+	u32 response_specific_data[14];
+};
+
+struct ena_admin_aq_create_sq_cmd {
+	struct ena_admin_aq_common_desc aq_common_descriptor;
+
+	/* 4:0 : reserved0_w1
+	 * 7:5 : sq_direction - 0x1 - Tx, 0x2 - Rx
+	 */
+	u8 sq_identity;
+
+	u8 reserved8_w1;
+
+	/* 3:0 : placement_policy - Describing where the SQ
+	 *    descriptor ring and the SQ packet headers reside:
+	 *    0x1 - descriptors and headers are in OS memory,
+	 *    0x3 - descriptors and headers in device memory
+	 *    (a.k.a Low Latency Queue)
+	 * 6:4 : completion_policy - Describing what policy
+	 *    to use for generation completion entry (cqe) in
+	 *    the CQ associated with this SQ: 0x0 - cqe for each
+	 *    sq descriptor, 0x1 - cqe upon request in sq
+	 *    descriptor, 0x2 - current queue head pointer is
+	 *    updated in OS memory upon sq descriptor request
+	 *    0x3 - current queue head pointer is updated in OS
+	 *    memory for each sq descriptor
+	 * 7 : reserved15_w1
+	 */
+	u8 sq_caps_2;
+
+	/* 0 : is_physically_contiguous - Described if the
+	 *    queue ring memory is allocated in physical
+	 *    contiguous pages or split.
+	 * 7:1 : reserved17_w1
+	 */
+	u8 sq_caps_3;
+
+	/* associated completion queue id. This CQ must be created prior to
+	 *    SQ creation
+	 */
+	u16 cq_idx;
+
+	/* submission queue depth in entries */
+	u16 sq_depth;
+
+	/* SQ physical base address in OS memory. This field should not be
+	 * used for Low Latency queues. Has to be page aligned.
+	 */
+	struct ena_common_mem_addr sq_ba;
+
+	/* specifies queue head writeback location in OS memory. Valid if
+	 * completion_policy is set to completion_policy_head_on_demand or
+	 * completion_policy_head. Has to be cache aligned
+	 */
+	struct ena_common_mem_addr sq_head_writeback;
+
+	u32 reserved0_w7;
+
+	u32 reserved0_w8;
+};
+
+enum ena_admin_sq_direction {
+	ENA_ADMIN_SQ_DIRECTION_TX                   = 1,
+	ENA_ADMIN_SQ_DIRECTION_RX                   = 2,
+};
+
+struct ena_admin_acq_create_sq_resp_desc {
+	struct ena_admin_acq_common_desc acq_common_desc;
+
+	u16 sq_idx;
+
+	u16 reserved;
+
+	/* queue doorbell address as an offset to PCIe MMIO REG BAR */
+	u32 sq_doorbell_offset;
+
+	/* low latency queue ring base address as an offset to PCIe MMIO
+	 * LLQ_MEM BAR
+	 */
+	u32 llq_descriptors_offset;
+
+	/* low latency queue headers' memory as an offset to PCIe MMIO
+	 * LLQ_MEM BAR
+	 */
+	u32 llq_headers_offset;
+};
+
+struct ena_admin_aq_destroy_sq_cmd {
+	struct ena_admin_aq_common_desc aq_common_descriptor;
+
+	struct ena_admin_sq sq;
+};
+
+struct ena_admin_acq_destroy_sq_resp_desc {
+	struct ena_admin_acq_common_desc acq_common_desc;
+};
+
+struct ena_admin_aq_create_cq_cmd {
+	struct ena_admin_aq_common_desc aq_common_descriptor;
+
+	/* 4:0 : reserved5
+	 * 5 : interrupt_mode_enabled - if set, cq operates
+	 *    in interrupt mode, otherwise - polling
+	 * 7:6 : reserved6
+	 */
+	u8 cq_caps_1;
+
+	/* 4:0 : cq_entry_size_words - size of CQ entry in
+	 *    32-bit words, valid values: 4, 8.
+	 * 7:5 : reserved7
+	 */
+	u8 cq_caps_2;
+
+	/* completion queue depth in # of entries. must be power of 2 */
+	u16 cq_depth;
+
+	/* msix vector assigned to this cq */
+	u32 msix_vector;
+
+	/* cq physical base address in OS memory. CQ must be physically
+	 * contiguous
+	 */
+	struct ena_common_mem_addr cq_ba;
+};
+
+struct ena_admin_acq_create_cq_resp_desc {
+	struct ena_admin_acq_common_desc acq_common_desc;
+
+	u16 cq_idx;
+
+	/* actual cq depth in number of entries */
+	u16 cq_actual_depth;
+
+	u32 numa_node_register_offset;
+
+	u32 cq_head_db_register_offset;
+
+	u32 cq_interrupt_unmask_register_offset;
+};
+
+struct ena_admin_aq_destroy_cq_cmd {
+	struct ena_admin_aq_common_desc aq_common_descriptor;
+
+	u16 cq_idx;
+
+	u16 reserved1;
+};
+
+struct ena_admin_acq_destroy_cq_resp_desc {
+	struct ena_admin_acq_common_desc acq_common_desc;
+};
+
+/* ENA AQ Get Statistics command. Extended statistics are placed in control
+ * buffer pointed by AQ entry
+ */
+struct ena_admin_aq_get_stats_cmd {
+	struct ena_admin_aq_common_desc aq_common_descriptor;
+
+	union {
+		/* command specific inline data */
+		u32 inline_data_w1[3];
+
+		struct ena_admin_ctrl_buff_info control_buffer;
+	} u;
+
+	/* stats type as defined in enum ena_admin_get_stats_type */
+	u8 type;
+
+	/* stats scope defined in enum ena_admin_get_stats_scope */
+	u8 scope;
+
+	u16 reserved3;
+
+	/* queue id. used when scope is specific_queue */
+	u16 queue_idx;
+
+	/* device id, value 0xFFFF means mine. only privileged device can get
+	 *    stats of other device
+	 */
+	u16 device_id;
+};
+
+/* Basic Statistics Command. */
+struct ena_admin_basic_stats {
+	u32 tx_bytes_low;
+
+	u32 tx_bytes_high;
+
+	u32 tx_pkts_low;
+
+	u32 tx_pkts_high;
+
+	u32 rx_bytes_low;
+
+	u32 rx_bytes_high;
+
+	u32 rx_pkts_low;
+
+	u32 rx_pkts_high;
+
+	u32 rx_drops_low;
+
+	u32 rx_drops_high;
+};
+
+struct ena_admin_acq_get_stats_resp {
+	struct ena_admin_acq_common_desc acq_common_desc;
+
+	struct ena_admin_basic_stats basic_stats;
+};
+
+struct ena_admin_get_set_feature_common_desc {
+	/* 1:0 : select - 0x1 - current value; 0x3 - default
+	 *    value
+	 * 7:3 : reserved3
+	 */
+	u8 flags;
+
+	/* as appears in ena_admin_aq_feature_id */
+	u8 feature_id;
+
+	/* The driver specifies the max feature version it supports and the
+	 * device responds with the currently supported feature version. The
+	 * field is zero based
+	 */
+	u8 feature_version;
+
+	u8 reserved8;
+};
+
+struct ena_admin_device_attr_feature_desc {
+	u32 impl_id;
+
+	u32 device_version;
+
+	/* bitmap of ena_admin_aq_feature_id */
+	u32 supported_features;
+
+	u32 reserved3;
+
+	/* Indicates how many bits are used physical address access. */
+	u32 phys_addr_width;
+
+	/* Indicates how many bits are used virtual address access. */
+	u32 virt_addr_width;
+
+	/* unicast MAC address (in Network byte order) */
+	u8 mac_addr[6];
+
+	u8 reserved7[2];
+
+	u32 max_mtu;
+};
+
+enum ena_admin_llq_header_location {
+	/* header is in descriptor list */
+	ENA_ADMIN_INLINE_HEADER                     = 1,
+	/* header in a separate ring, implies 16B descriptor list entry */
+	ENA_ADMIN_HEADER_RING                       = 2,
+};
+
+enum ena_admin_llq_ring_entry_size {
+	ENA_ADMIN_LIST_ENTRY_SIZE_128B              = 1,
+	ENA_ADMIN_LIST_ENTRY_SIZE_192B              = 2,
+	ENA_ADMIN_LIST_ENTRY_SIZE_256B              = 4,
+};
+
+enum ena_admin_llq_num_descs_before_header {
+	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_0     = 0,
+	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1     = 1,
+	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2     = 2,
+	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4     = 4,
+	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8     = 8,
+};
+
+/* packet descriptor list entry always starts with one or more descriptors,
+ * followed by a header. The rest of the descriptors are located in the
+ * beginning of the subsequent entry. Stride refers to how the rest of the
+ * descriptors are placed. This field is relevant only for inline header
+ * mode
+ */
+enum ena_admin_llq_stride_ctrl {
+	ENA_ADMIN_SINGLE_DESC_PER_ENTRY             = 1,
+	ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY          = 2,
+};
+
+struct ena_admin_feature_llq_desc {
+	u32 max_llq_num;
+
+	u32 max_llq_depth;
+
+	/*  specify the header locations the device supports. bitfield of
+	 *    enum ena_admin_llq_header_location.
+	 */
+	u16 header_location_ctrl_supported;
+
+	/* the header location the driver selected to use. */
+	u16 header_location_ctrl_enabled;
+
+	/* if inline header is specified - this is the size of descriptor
+	 *    list entry. If header in a separate ring is specified - this is
+	 *    the size of header ring entry. bitfield of enum
+	 *    ena_admin_llq_ring_entry_size. specify the entry sizes the device
+	 *    supports
+	 */
+	u16 entry_size_ctrl_supported;
+
+	/* the entry size the driver selected to use. */
+	u16 entry_size_ctrl_enabled;
+
+	/* valid only if inline header is specified. First entry associated
+	 *    with the packet includes descriptors and header. Rest of the
+	 *    entries occupied by descriptors. This parameter defines the max
+	 *    number of descriptors precedding the header in the first entry.
+	 *    The field is bitfield of enum
+	 *    ena_admin_llq_num_descs_before_header and specify the values the
+	 *    device supports
+	 */
+	u16 desc_num_before_header_supported;
+
+	/* the desire field the driver selected to use */
+	u16 desc_num_before_header_enabled;
+
+	/* valid only if inline was chosen. bitfield of enum
+	 *    ena_admin_llq_stride_ctrl
+	 */
+	u16 descriptors_stride_ctrl_supported;
+
+	/* the stride control the driver selected to use */
+	u16 descriptors_stride_ctrl_enabled;
+
+	/* Maximum size in bytes taken by llq entries in a single tx burst.
+	 * Set to 0 when there is no such limit.
+	 */
+	u32 max_tx_burst_size;
+};
+
+struct ena_admin_queue_ext_feature_fields {
+	u32 max_tx_sq_num;
+
+	u32 max_tx_cq_num;
+
+	u32 max_rx_sq_num;
+
+	u32 max_rx_cq_num;
+
+	u32 max_tx_sq_depth;
+
+	u32 max_tx_cq_depth;
+
+	u32 max_rx_sq_depth;
+
+	u32 max_rx_cq_depth;
+
+	u32 max_tx_header_size;
+
+	/* Maximum Descriptors number, including meta descriptor, allowed for
+	 * a single Tx packet
+	 */
+	u16 max_per_packet_tx_descs;
+
+	/* Maximum Descriptors number allowed for a single Rx packet */
+	u16 max_per_packet_rx_descs;
+};
+
+struct ena_admin_queue_feature_desc {
+	u32 max_sq_num;
+
+	u32 max_sq_depth;
+
+	u32 max_cq_num;
+
+	u32 max_cq_depth;
+
+	u32 max_legacy_llq_num;
+
+	u32 max_legacy_llq_depth;
+
+	u32 max_header_size;
+
+	/* Maximum Descriptors number, including meta descriptor, allowed for
+	 *    a single Tx packet
+	 */
+	u16 max_packet_tx_descs;
+
+	/* Maximum Descriptors number allowed for a single Rx packet */
+	u16 max_packet_rx_descs;
+};
+
+struct ena_admin_set_feature_mtu_desc {
+	/* exclude L2 */
+	u32 mtu;
+};
+
+struct ena_admin_set_feature_host_attr_desc {
+	/* host OS info base address in OS memory. host info is 4KB of
+	 * physically contiguous
+	 */
+	struct ena_common_mem_addr os_info_ba;
+
+	/* host debug area base address in OS memory. debug area must be
+	 * physically contiguous
+	 */
+	struct ena_common_mem_addr debug_ba;
+
+	/* debug area size */
+	u32 debug_area_size;
+};
+
+struct ena_admin_feature_intr_moder_desc {
+	/* interrupt delay granularity in usec */
+	u16 intr_delay_resolution;
+
+	u16 reserved;
+};
+
+struct ena_admin_get_feature_link_desc {
+	/* Link speed in Mb */
+	u32 speed;
+
+	/* bit field of enum ena_admin_link types */
+	u32 supported;
+
+	/* 0 : autoneg
+	 * 1 : duplex - Full Duplex
+	 * 31:2 : reserved2
+	 */
+	u32 flags;
+};
+
+struct ena_admin_feature_aenq_desc {
+	/* bitmask for AENQ groups the device can report */
+	u32 supported_groups;
+
+	/* bitmask for AENQ groups to report */
+	u32 enabled_groups;
+};
+
+struct ena_admin_feature_offload_desc {
+	/* 0 : TX_L3_csum_ipv4
+	 * 1 : TX_L4_ipv4_csum_part - The checksum field
+	 *    should be initialized with pseudo header checksum
+	 * 2 : TX_L4_ipv4_csum_full
+	 * 3 : TX_L4_ipv6_csum_part - The checksum field
+	 *    should be initialized with pseudo header checksum
+	 * 4 : TX_L4_ipv6_csum_full
+	 * 5 : tso_ipv4
+	 * 6 : tso_ipv6
+	 * 7 : tso_ecn
+	 */
+	u32 tx;
+
+	/* Receive side supported stateless offload
+	 * 0 : RX_L3_csum_ipv4 - IPv4 checksum
+	 * 1 : RX_L4_ipv4_csum - TCP/UDP/IPv4 checksum
+	 * 2 : RX_L4_ipv6_csum - TCP/UDP/IPv6 checksum
+	 * 3 : RX_hash - Hash calculation
+	 */
+	u32 rx_supported;
+
+	u32 rx_enabled;
+};
+
+enum ena_admin_hash_functions {
+	ENA_ADMIN_TOEPLITZ                          = 1,
+	ENA_ADMIN_CRC32                             = 2,
+};
+
+struct ena_admin_feature_rss_flow_hash_control {
+	u32 keys_num;
+
+	u32 reserved;
+
+	u32 key[10];
+};
+
+struct ena_admin_feature_rss_flow_hash_function {
+	/* 7:0 : funcs - bitmask of ena_admin_hash_functions */
+	u32 supported_func;
+
+	/* 7:0 : selected_func - bitmask of
+	 *    ena_admin_hash_functions
+	 */
+	u32 selected_func;
+
+	/* initial value */
+	u32 init_val;
+};
+
+/* RSS flow hash protocols */
+enum ena_admin_flow_hash_proto {
+	ENA_ADMIN_RSS_TCP4                          = 0,
+	ENA_ADMIN_RSS_UDP4                          = 1,
+	ENA_ADMIN_RSS_TCP6                          = 2,
+	ENA_ADMIN_RSS_UDP6                          = 3,
+	ENA_ADMIN_RSS_IP4                           = 4,
+	ENA_ADMIN_RSS_IP6                           = 5,
+	ENA_ADMIN_RSS_IP4_FRAG                      = 6,
+	ENA_ADMIN_RSS_NOT_IP                        = 7,
+	/* TCPv6 with extension header */
+	ENA_ADMIN_RSS_TCP6_EX                       = 8,
+	/* IPv6 with extension header */
+	ENA_ADMIN_RSS_IP6_EX                        = 9,
+	ENA_ADMIN_RSS_PROTO_NUM                     = 16,
+};
+
+/* RSS flow hash fields */
+enum ena_admin_flow_hash_fields {
+	/* Ethernet Dest Addr */
+	ENA_ADMIN_RSS_L2_DA                         = BIT(0),
+	/* Ethernet Src Addr */
+	ENA_ADMIN_RSS_L2_SA                         = BIT(1),
+	/* ipv4/6 Dest Addr */
+	ENA_ADMIN_RSS_L3_DA                         = BIT(2),
+	/* ipv4/6 Src Addr */
+	ENA_ADMIN_RSS_L3_SA                         = BIT(3),
+	/* tcp/udp Dest Port */
+	ENA_ADMIN_RSS_L4_DP                         = BIT(4),
+	/* tcp/udp Src Port */
+	ENA_ADMIN_RSS_L4_SP                         = BIT(5),
+};
+
+struct ena_admin_proto_input {
+	/* flow hash fields (bitwise according to ena_admin_flow_hash_fields) */
+	u16 fields;
+
+	u16 reserved2;
+};
+
+struct ena_admin_feature_rss_hash_control {
+	struct ena_admin_proto_input supported_fields[ENA_ADMIN_RSS_PROTO_NUM];
+
+	struct ena_admin_proto_input selected_fields[ENA_ADMIN_RSS_PROTO_NUM];
+
+	struct ena_admin_proto_input reserved2[ENA_ADMIN_RSS_PROTO_NUM];
+
+	struct ena_admin_proto_input reserved3[ENA_ADMIN_RSS_PROTO_NUM];
+};
+
+struct ena_admin_feature_rss_flow_hash_input {
+	/* supported hash input sorting
+	 * 1 : L3_sort - support swap L3 addresses if DA is
+	 *    smaller than SA
+	 * 2 : L4_sort - support swap L4 ports if DP smaller
+	 *    SP
+	 */
+	u16 supported_input_sort;
+
+	/* enabled hash input sorting
+	 * 1 : enable_L3_sort - enable swap L3 addresses if
+	 *    DA smaller than SA
+	 * 2 : enable_L4_sort - enable swap L4 ports if DP
+	 *    smaller than SP
+	 */
+	u16 enabled_input_sort;
+};
+
+enum ena_admin_os_type {
+	ENA_ADMIN_OS_LINUX                          = 1,
+	ENA_ADMIN_OS_WIN                            = 2,
+	ENA_ADMIN_OS_DPDK                           = 3,
+	ENA_ADMIN_OS_FREEBSD                        = 4,
+	ENA_ADMIN_OS_IPXE                           = 5,
+	ENA_ADMIN_OS_ESXI			    = 6,
+	ENA_ADMIN_OS_GROUPS_NUM			    = 6,
+};
+
+struct ena_admin_host_info {
+	/* defined in enum ena_admin_os_type */
+	u32 os_type;
+
+	/* os distribution string format */
+	u8 os_dist_str[128];
+
+	/* OS distribution numeric format */
+	u32 os_dist;
+
+	/* kernel version string format */
+	u8 kernel_ver_str[32];
+
+	/* Kernel version numeric format */
+	u32 kernel_ver;
+
+	/* 7:0 : major
+	 * 15:8 : minor
+	 * 23:16 : sub_minor
+	 * 31:24 : module_type
+	 */
+	u32 driver_version;
+
+	/* features bitmap */
+	u32 supported_network_features[2];
+
+	/* ENA spec version of driver */
+	u16 ena_spec_version;
+
+	/* ENA device's Bus, Device and Function
+	 * 2:0 : function
+	 * 7:3 : device
+	 * 15:8 : bus
+	 */
+	u16 bdf;
+
+	/* Number of CPUs */
+	u16 num_cpus;
+
+	u16 reserved;
+
+	/* 1 :0 : reserved
+	 * 2 : interrupt_moderation
+	 * 31:3 : reserved
+	 */
+	u32 driver_supported_features;
+};
+
+struct ena_admin_rss_ind_table_entry {
+	u16 cq_idx;
+
+	u16 reserved;
+};
+
+struct ena_admin_feature_rss_ind_table {
+	/* min supported table size (2^min_size) */
+	u16 min_size;
+
+	/* max supported table size (2^max_size) */
+	u16 max_size;
+
+	/* table size (2^size) */
+	u16 size;
+
+	u16 reserved;
+
+	/* index of the inline entry. 0xFFFFFFFF means invalid */
+	u32 inline_index;
+
+	/* used for updating single entry, ignored when setting the entire
+	 * table through the control buffer.
+	 */
+	struct ena_admin_rss_ind_table_entry inline_entry;
+};
+
+/* When hint value is 0, driver should use it's own predefined value */
+struct ena_admin_ena_hw_hints {
+	/* value in ms */
+	u16 mmio_read_timeout;
+
+	/* value in ms */
+	u16 driver_watchdog_timeout;
+
+	/* Per packet tx completion timeout. value in ms */
+	u16 missing_tx_completion_timeout;
+
+	u16 missed_tx_completion_count_threshold_to_reset;
+
+	/* value in ms */
+	u16 admin_completion_tx_timeout;
+
+	u16 netdev_wd_timeout;
+
+	u16 max_tx_sgl_size;
+
+	u16 max_rx_sgl_size;
+
+	u16 reserved[8];
+};
+
+struct ena_admin_get_feat_cmd {
+	struct ena_admin_aq_common_desc aq_common_descriptor;
+
+	struct ena_admin_ctrl_buff_info control_buffer;
+
+	struct ena_admin_get_set_feature_common_desc feat_common;
+
+	u32 raw[11];
+};
+
+struct ena_admin_queue_ext_feature_desc {
+	/* version */
+	u8 version;
+
+	u8 reserved1[3];
+
+	union {
+		struct ena_admin_queue_ext_feature_fields max_queue_ext;
+
+		u32 raw[10];
+	};
+};
+
+struct ena_admin_get_feat_resp {
+	struct ena_admin_acq_common_desc acq_common_desc;
+
+	union {
+		u32 raw[14];
+
+		struct ena_admin_device_attr_feature_desc dev_attr;
+
+		struct ena_admin_feature_llq_desc llq;
+
+		struct ena_admin_queue_feature_desc max_queue;
+
+		struct ena_admin_queue_ext_feature_desc max_queue_ext;
+
+		struct ena_admin_feature_aenq_desc aenq;
+
+		struct ena_admin_get_feature_link_desc link;
+
+		struct ena_admin_feature_offload_desc offload;
+
+		struct ena_admin_feature_rss_flow_hash_function flow_hash_func;
+
+		struct ena_admin_feature_rss_flow_hash_input flow_hash_input;
+
+		struct ena_admin_feature_rss_ind_table ind_table;
+
+		struct ena_admin_feature_intr_moder_desc intr_moderation;
+
+		struct ena_admin_ena_hw_hints hw_hints;
+	} u;
+};
+
+struct ena_admin_set_feat_cmd {
+	struct ena_admin_aq_common_desc aq_common_descriptor;
+
+	struct ena_admin_ctrl_buff_info control_buffer;
+
+	struct ena_admin_get_set_feature_common_desc feat_common;
+
+	union {
+		u32 raw[11];
+
+		/* mtu size */
+		struct ena_admin_set_feature_mtu_desc mtu;
+
+		/* host attributes */
+		struct ena_admin_set_feature_host_attr_desc host_attr;
+
+		/* AENQ configuration */
+		struct ena_admin_feature_aenq_desc aenq;
+
+		/* rss flow hash function */
+		struct ena_admin_feature_rss_flow_hash_function flow_hash_func;
+
+		/* rss flow hash input */
+		struct ena_admin_feature_rss_flow_hash_input flow_hash_input;
+
+		/* rss indirection table */
+		struct ena_admin_feature_rss_ind_table ind_table;
+
+		/* LLQ configuration */
+		struct ena_admin_feature_llq_desc llq;
+	} u;
+};
+
+struct ena_admin_set_feat_resp {
+	struct ena_admin_acq_common_desc acq_common_desc;
+
+	union {
+		u32 raw[14];
+	} u;
+};
+
+struct ena_admin_aenq_common_desc {
+	u16 group;
+
+	u16 syndrom;
+
+	/* 0 : phase
+	 * 7:1 : reserved - MBZ
+	 */
+	u8 flags;
+
+	u8 reserved1[3];
+
+	u32 timestamp_low;
+
+	u32 timestamp_high;
+};
+
+/* asynchronous event notification groups */
+enum ena_admin_aenq_group {
+	ENA_ADMIN_LINK_CHANGE                       = 0,
+	ENA_ADMIN_FATAL_ERROR                       = 1,
+	ENA_ADMIN_WARNING                           = 2,
+	ENA_ADMIN_NOTIFICATION                      = 3,
+	ENA_ADMIN_KEEP_ALIVE                        = 4,
+	ENA_ADMIN_AENQ_GROUPS_NUM                   = 5,
+};
+
+enum ena_admin_aenq_notification_syndrom {
+	ENA_ADMIN_SUSPEND                           = 0,
+	ENA_ADMIN_RESUME                            = 1,
+	ENA_ADMIN_UPDATE_HINTS                      = 2,
+};
+
+struct ena_admin_aenq_entry {
+	struct ena_admin_aenq_common_desc aenq_common_desc;
+
+	/* command specific inline data */
+	u32 inline_data_w4[12];
+};
+
+struct ena_admin_aenq_link_change_desc {
+	struct ena_admin_aenq_common_desc aenq_common_desc;
+
+	/* 0 : link_status */
+	u32 flags;
+};
+
+struct ena_admin_aenq_keep_alive_desc {
+	struct ena_admin_aenq_common_desc aenq_common_desc;
+
+	u32 rx_drops_low;
+
+	u32 rx_drops_high;
+};
+
+struct ena_admin_ena_mmio_req_read_less_resp {
+	u16 req_id;
+
+	u16 reg_off;
+
+	/* value is valid when poll is cleared */
+	u32 reg_val;
+};
+
+/* aq_common_desc */
+#define ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK            GENMASK(11, 0)
+#define ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK                 BIT(0)
+#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_SHIFT            1
+#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_MASK             BIT(1)
+#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_SHIFT   2
+#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK    BIT(2)
+
+/* sq */
+#define ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT                     5
+#define ENA_ADMIN_SQ_SQ_DIRECTION_MASK                      GENMASK(7, 5)
+
+/* acq_common_desc */
+#define ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK           GENMASK(11, 0)
+#define ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK                BIT(0)
+
+/* aq_create_sq_cmd */
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT       5
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK        GENMASK(7, 5)
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK    GENMASK(3, 0)
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT  4
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK   GENMASK(6, 4)
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK BIT(0)
+
+/* aq_create_cq_cmd */
+#define ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_SHIFT 5
+#define ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK BIT(5)
+#define ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK GENMASK(4, 0)
+
+/* get_set_feature_common_desc */
+#define ENA_ADMIN_GET_SET_FEATURE_COMMON_DESC_SELECT_MASK   GENMASK(1, 0)
+
+/* get_feature_link_desc */
+#define ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK        BIT(0)
+#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_SHIFT        1
+#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_MASK         BIT(1)
+
+/* feature_offload_desc */
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK BIT(0)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_SHIFT 1
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK BIT(1)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_SHIFT 2
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_MASK BIT(2)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_SHIFT 3
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK BIT(3)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_SHIFT 4
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_MASK BIT(4)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_SHIFT       5
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK        BIT(5)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_SHIFT       6
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK        BIT(6)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_SHIFT        7
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK         BIT(7)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L3_CSUM_IPV4_MASK BIT(0)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_SHIFT 1
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK BIT(1)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_SHIFT 2
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK BIT(2)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_SHIFT        3
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_MASK         BIT(3)
+
+/* feature_rss_flow_hash_function */
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_FUNCS_MASK GENMASK(7, 0)
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_SELECTED_FUNC_MASK GENMASK(7, 0)
+
+/* feature_rss_flow_hash_input */
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_SHIFT 1
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK  BIT(1)
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_SHIFT 2
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK  BIT(2)
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_SHIFT 1
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_MASK BIT(1)
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_SHIFT 2
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_MASK BIT(2)
+
+/* host_info */
+#define ENA_ADMIN_HOST_INFO_MAJOR_MASK                      GENMASK(7, 0)
+#define ENA_ADMIN_HOST_INFO_MINOR_SHIFT                     8
+#define ENA_ADMIN_HOST_INFO_MINOR_MASK                      GENMASK(15, 8)
+#define ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT                 16
+#define ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK                  GENMASK(23, 16)
+#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT               24
+#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_MASK                GENMASK(31, 24)
+#define ENA_ADMIN_HOST_INFO_FUNCTION_MASK                   GENMASK(2, 0)
+#define ENA_ADMIN_HOST_INFO_DEVICE_SHIFT                    3
+#define ENA_ADMIN_HOST_INFO_DEVICE_MASK                     GENMASK(7, 3)
+#define ENA_ADMIN_HOST_INFO_BUS_SHIFT                       8
+#define ENA_ADMIN_HOST_INFO_BUS_MASK                        GENMASK(15, 8)
+#define ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_SHIFT      2
+#define ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_MASK       BIT(2)
+
+/* aenq_common_desc */
+#define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK               BIT(0)
+
+/* aenq_link_change_desc */
+#define ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK    BIT(0)
+
+#endif /*_ENA_ADMIN_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_com.c
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -0,0 +1,2873 @@
+/*
+ * Copyright 2015 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "ena_com.h"
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+/* Timeout in micro-sec */
+#define ADMIN_CMD_TIMEOUT_US (3000000)
+
+#define ENA_ASYNC_QUEUE_DEPTH 16
+#define ENA_ADMIN_QUEUE_DEPTH 32
+
+
+#define ENA_CTRL_MAJOR		0
+#define ENA_CTRL_MINOR		0
+#define ENA_CTRL_SUB_MINOR	1
+
+#define MIN_ENA_CTRL_VER \
+	(((ENA_CTRL_MAJOR) << \
+	(ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT)) | \
+	((ENA_CTRL_MINOR) << \
+	(ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT)) | \
+	(ENA_CTRL_SUB_MINOR))
+
+#define ENA_DMA_ADDR_TO_UINT32_LOW(x)	((u32)((u64)(x)))
+#define ENA_DMA_ADDR_TO_UINT32_HIGH(x)	((u32)(((u64)(x)) >> 32))
+
+#define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF
+
+#define ENA_COM_BOUNCE_BUFFER_CNTRL_CNT	4
+
+#define ENA_REGS_ADMIN_INTR_MASK 1
+
+#define ENA_POLL_MS	5
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+enum ena_cmd_status {
+	ENA_CMD_SUBMITTED,
+	ENA_CMD_COMPLETED,
+	/* Abort - canceled by the driver */
+	ENA_CMD_ABORTED,
+};
+
+struct ena_comp_ctx {
+	struct completion wait_event;
+	struct ena_admin_acq_entry *user_cqe;
+	u32 comp_size;
+	enum ena_cmd_status status;
+	/* status from the device */
+	u8 comp_status;
+	u8 cmd_opcode;
+	bool occupied;
+};
+
+struct ena_com_stats_ctx {
+	struct ena_admin_aq_get_stats_cmd get_cmd;
+	struct ena_admin_acq_get_stats_resp get_resp;
+};
+
+static int ena_com_mem_addr_set(struct ena_com_dev *ena_dev,
+				       struct ena_common_mem_addr *ena_addr,
+				       dma_addr_t addr)
+{
+	if ((addr & GENMASK_ULL(ena_dev->dma_addr_bits - 1, 0)) != addr) {
+		pr_err("dma address has more bits that the device supports\n");
+		return -EINVAL;
+	}
+
+	ena_addr->mem_addr_low = lower_32_bits(addr);
+	ena_addr->mem_addr_high = (u16)upper_32_bits(addr);
+
+	return 0;
+}
+
+static int ena_com_admin_init_sq(struct ena_com_admin_queue *queue)
+{
+	struct ena_com_admin_sq *sq = &queue->sq;
+	u16 size = ADMIN_SQ_SIZE(queue->q_depth);
+
+	sq->entries = dma_zalloc_coherent(queue->q_dmadev, size, &sq->dma_addr,
+					  GFP_KERNEL);
+
+	if (!sq->entries) {
+		pr_err("memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	sq->head = 0;
+	sq->tail = 0;
+	sq->phase = 1;
+
+	sq->db_addr = NULL;
+
+	return 0;
+}
+
+static int ena_com_admin_init_cq(struct ena_com_admin_queue *queue)
+{
+	struct ena_com_admin_cq *cq = &queue->cq;
+	u16 size = ADMIN_CQ_SIZE(queue->q_depth);
+
+	cq->entries = dma_zalloc_coherent(queue->q_dmadev, size, &cq->dma_addr,
+					  GFP_KERNEL);
+
+	if (!cq->entries) {
+		pr_err("memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	cq->head = 0;
+	cq->phase = 1;
+
+	return 0;
+}
+
+static int ena_com_admin_init_aenq(struct ena_com_dev *dev,
+				   struct ena_aenq_handlers *aenq_handlers)
+{
+	struct ena_com_aenq *aenq = &dev->aenq;
+	u32 addr_low, addr_high, aenq_caps;
+	u16 size;
+
+	dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH;
+	size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH);
+	aenq->entries = dma_zalloc_coherent(dev->dmadev, size, &aenq->dma_addr,
+					    GFP_KERNEL);
+
+	if (!aenq->entries) {
+		pr_err("memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	aenq->head = aenq->q_depth;
+	aenq->phase = 1;
+
+	addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(aenq->dma_addr);
+	addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(aenq->dma_addr);
+
+	writel(addr_low, dev->reg_bar + ENA_REGS_AENQ_BASE_LO_OFF);
+	writel(addr_high, dev->reg_bar + ENA_REGS_AENQ_BASE_HI_OFF);
+
+	aenq_caps = 0;
+	aenq_caps |= dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK;
+	aenq_caps |= (sizeof(struct ena_admin_aenq_entry)
+		      << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) &
+		     ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK;
+	writel(aenq_caps, dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF);
+
+	if (unlikely(!aenq_handlers)) {
+		pr_err("aenq handlers pointer is NULL\n");
+		return -EINVAL;
+	}
+
+	aenq->aenq_handlers = aenq_handlers;
+
+	return 0;
+}
+
+static void comp_ctxt_release(struct ena_com_admin_queue *queue,
+				     struct ena_comp_ctx *comp_ctx)
+{
+	comp_ctx->occupied = false;
+	atomic_dec(&queue->outstanding_cmds);
+}
+
+static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *queue,
+					  u16 command_id, bool capture)
+{
+	if (unlikely(command_id >= queue->q_depth)) {
+		pr_err("command id is larger than the queue size. cmd_id: %u queue size %d\n",
+		       command_id, queue->q_depth);
+		return NULL;
+	}
+
+	if (unlikely(queue->comp_ctx[command_id].occupied && capture)) {
+		pr_err("Completion context is occupied\n");
+		return NULL;
+	}
+
+	if (capture) {
+		atomic_inc(&queue->outstanding_cmds);
+		queue->comp_ctx[command_id].occupied = true;
+	}
+
+	return &queue->comp_ctx[command_id];
+}
+
+static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue,
+						       struct ena_admin_aq_entry *cmd,
+						       size_t cmd_size_in_bytes,
+						       struct ena_admin_acq_entry *comp,
+						       size_t comp_size_in_bytes)
+{
+	struct ena_comp_ctx *comp_ctx;
+	u16 tail_masked, cmd_id;
+	u16 queue_size_mask;
+	u16 cnt;
+
+	queue_size_mask = admin_queue->q_depth - 1;
+
+	tail_masked = admin_queue->sq.tail & queue_size_mask;
+
+	/* In case of queue FULL */
+	cnt = (u16)atomic_read(&admin_queue->outstanding_cmds);
+	if (cnt >= admin_queue->q_depth) {
+		pr_debug("admin queue is full.\n");
+		admin_queue->stats.out_of_space++;
+		return ERR_PTR(-ENOSPC);
+	}
+
+	cmd_id = admin_queue->curr_cmd_id;
+
+	cmd->aq_common_descriptor.flags |= admin_queue->sq.phase &
+		ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK;
+
+	cmd->aq_common_descriptor.command_id |= cmd_id &
+		ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK;
+
+	comp_ctx = get_comp_ctxt(admin_queue, cmd_id, true);
+	if (unlikely(!comp_ctx))
+		return ERR_PTR(-EINVAL);
+
+	comp_ctx->status = ENA_CMD_SUBMITTED;
+	comp_ctx->comp_size = (u32)comp_size_in_bytes;
+	comp_ctx->user_cqe = comp;
+	comp_ctx->cmd_opcode = cmd->aq_common_descriptor.opcode;
+
+	reinit_completion(&comp_ctx->wait_event);
+
+	memcpy(&admin_queue->sq.entries[tail_masked], cmd, cmd_size_in_bytes);
+
+	admin_queue->curr_cmd_id = (admin_queue->curr_cmd_id + 1) &
+		queue_size_mask;
+
+	admin_queue->sq.tail++;
+	admin_queue->stats.submitted_cmd++;
+
+	if (unlikely((admin_queue->sq.tail & queue_size_mask) == 0))
+		admin_queue->sq.phase = !admin_queue->sq.phase;
+
+	writel(admin_queue->sq.tail, admin_queue->sq.db_addr);
+
+	return comp_ctx;
+}
+
+static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *queue)
+{
+	size_t size = queue->q_depth * sizeof(struct ena_comp_ctx);
+	struct ena_comp_ctx *comp_ctx;
+	u16 i;
+
+	queue->comp_ctx = devm_kzalloc(queue->q_dmadev, size, GFP_KERNEL);
+	if (unlikely(!queue->comp_ctx)) {
+		pr_err("memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < queue->q_depth; i++) {
+		comp_ctx = get_comp_ctxt(queue, i, false);
+		if (comp_ctx)
+			init_completion(&comp_ctx->wait_event);
+	}
+
+	return 0;
+}
+
+static struct ena_comp_ctx *ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue,
+						     struct ena_admin_aq_entry *cmd,
+						     size_t cmd_size_in_bytes,
+						     struct ena_admin_acq_entry *comp,
+						     size_t comp_size_in_bytes)
+{
+	unsigned long flags = 0;
+	struct ena_comp_ctx *comp_ctx;
+
+	spin_lock_irqsave(&admin_queue->q_lock, flags);
+	if (unlikely(!admin_queue->running_state)) {
+		spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+		return ERR_PTR(-ENODEV);
+	}
+	comp_ctx = __ena_com_submit_admin_cmd(admin_queue, cmd,
+					      cmd_size_in_bytes,
+					      comp,
+					      comp_size_in_bytes);
+	if (IS_ERR(comp_ctx))
+		admin_queue->running_state = false;
+	spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+
+	return comp_ctx;
+}
+
+static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
+			      struct ena_com_create_io_ctx *ctx,
+			      struct ena_com_io_sq *io_sq)
+{
+	size_t size;
+	int dev_node = 0;
+
+	memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr));
+
+	io_sq->dma_addr_bits = (u8)ena_dev->dma_addr_bits;
+	io_sq->desc_entry_size =
+		(io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ?
+		sizeof(struct ena_eth_io_tx_desc) :
+		sizeof(struct ena_eth_io_rx_desc);
+
+	size = io_sq->desc_entry_size * io_sq->q_depth;
+
+	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) {
+		dev_node = dev_to_node(ena_dev->dmadev);
+		set_dev_node(ena_dev->dmadev, ctx->numa_node);
+		io_sq->desc_addr.virt_addr =
+			dma_zalloc_coherent(ena_dev->dmadev, size,
+					    &io_sq->desc_addr.phys_addr,
+					    GFP_KERNEL);
+		set_dev_node(ena_dev->dmadev, dev_node);
+		if (!io_sq->desc_addr.virt_addr) {
+			io_sq->desc_addr.virt_addr =
+				dma_zalloc_coherent(ena_dev->dmadev, size,
+						    &io_sq->desc_addr.phys_addr,
+						    GFP_KERNEL);
+		}
+
+		if (!io_sq->desc_addr.virt_addr) {
+			pr_err("memory allocation failed\n");
+			return -ENOMEM;
+		}
+	}
+
+	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
+		/* Allocate bounce buffers */
+		io_sq->bounce_buf_ctrl.buffer_size =
+			ena_dev->llq_info.desc_list_entry_size;
+		io_sq->bounce_buf_ctrl.buffers_num =
+			ENA_COM_BOUNCE_BUFFER_CNTRL_CNT;
+		io_sq->bounce_buf_ctrl.next_to_use = 0;
+
+		size = io_sq->bounce_buf_ctrl.buffer_size *
+			 io_sq->bounce_buf_ctrl.buffers_num;
+
+		dev_node = dev_to_node(ena_dev->dmadev);
+		set_dev_node(ena_dev->dmadev, ctx->numa_node);
+		io_sq->bounce_buf_ctrl.base_buffer =
+			devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL);
+		set_dev_node(ena_dev->dmadev, dev_node);
+		if (!io_sq->bounce_buf_ctrl.base_buffer)
+			io_sq->bounce_buf_ctrl.base_buffer =
+				devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL);
+
+		if (!io_sq->bounce_buf_ctrl.base_buffer) {
+			pr_err("bounce buffer memory allocation failed\n");
+			return -ENOMEM;
+		}
+
+		memcpy(&io_sq->llq_info, &ena_dev->llq_info,
+		       sizeof(io_sq->llq_info));
+
+		/* Initiate the first bounce buffer */
+		io_sq->llq_buf_ctrl.curr_bounce_buf =
+			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
+		memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
+		       0x0, io_sq->llq_info.desc_list_entry_size);
+		io_sq->llq_buf_ctrl.descs_left_in_line =
+			io_sq->llq_info.descs_num_before_header;
+
+		if (io_sq->llq_info.max_entries_in_tx_burst > 0)
+			io_sq->entries_in_tx_burst_left =
+				io_sq->llq_info.max_entries_in_tx_burst;
+	}
+
+	io_sq->tail = 0;
+	io_sq->next_to_comp = 0;
+	io_sq->phase = 1;
+
+	return 0;
+}
+
+static int ena_com_init_io_cq(struct ena_com_dev *ena_dev,
+			      struct ena_com_create_io_ctx *ctx,
+			      struct ena_com_io_cq *io_cq)
+{
+	size_t size;
+	int prev_node = 0;
+
+	memset(&io_cq->cdesc_addr, 0x0, sizeof(io_cq->cdesc_addr));
+
+	/* Use the basic completion descriptor for Rx */
+	io_cq->cdesc_entry_size_in_bytes =
+		(io_cq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ?
+		sizeof(struct ena_eth_io_tx_cdesc) :
+		sizeof(struct ena_eth_io_rx_cdesc_base);
+
+	size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth;
+
+	prev_node = dev_to_node(ena_dev->dmadev);
+	set_dev_node(ena_dev->dmadev, ctx->numa_node);
+	io_cq->cdesc_addr.virt_addr =
+		dma_zalloc_coherent(ena_dev->dmadev, size,
+				    &io_cq->cdesc_addr.phys_addr, GFP_KERNEL);
+	set_dev_node(ena_dev->dmadev, prev_node);
+	if (!io_cq->cdesc_addr.virt_addr) {
+		io_cq->cdesc_addr.virt_addr =
+			dma_zalloc_coherent(ena_dev->dmadev, size,
+					    &io_cq->cdesc_addr.phys_addr,
+					    GFP_KERNEL);
+	}
+
+	if (!io_cq->cdesc_addr.virt_addr) {
+		pr_err("memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	io_cq->phase = 1;
+	io_cq->head = 0;
+
+	return 0;
+}
+
+static void ena_com_handle_single_admin_completion(struct ena_com_admin_queue *admin_queue,
+						   struct ena_admin_acq_entry *cqe)
+{
+	struct ena_comp_ctx *comp_ctx;
+	u16 cmd_id;
+
+	cmd_id = cqe->acq_common_descriptor.command &
+		ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK;
+
+	comp_ctx = get_comp_ctxt(admin_queue, cmd_id, false);
+	if (unlikely(!comp_ctx)) {
+		pr_err("comp_ctx is NULL. Changing the admin queue running state\n");
+		admin_queue->running_state = false;
+		return;
+	}
+
+	comp_ctx->status = ENA_CMD_COMPLETED;
+	comp_ctx->comp_status = cqe->acq_common_descriptor.status;
+
+	if (comp_ctx->user_cqe)
+		memcpy(comp_ctx->user_cqe, (void *)cqe, comp_ctx->comp_size);
+
+	if (!admin_queue->polling)
+		complete(&comp_ctx->wait_event);
+}
+
+static void ena_com_handle_admin_completion(struct ena_com_admin_queue *admin_queue)
+{
+	struct ena_admin_acq_entry *cqe = NULL;
+	u16 comp_num = 0;
+	u16 head_masked;
+	u8 phase;
+
+	head_masked = admin_queue->cq.head & (admin_queue->q_depth - 1);
+	phase = admin_queue->cq.phase;
+
+	cqe = &admin_queue->cq.entries[head_masked];
+
+	/* Go over all the completions */
+	while ((READ_ONCE(cqe->acq_common_descriptor.flags) &
+		ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) {
+		/* Do not read the rest of the completion entry before the
+		 * phase bit was validated
+		 */
+		dma_rmb();
+		ena_com_handle_single_admin_completion(admin_queue, cqe);
+
+		head_masked++;
+		comp_num++;
+		if (unlikely(head_masked == admin_queue->q_depth)) {
+			head_masked = 0;
+			phase = !phase;
+		}
+
+		cqe = &admin_queue->cq.entries[head_masked];
+	}
+
+	admin_queue->cq.head += comp_num;
+	admin_queue->cq.phase = phase;
+	admin_queue->sq.head += comp_num;
+	admin_queue->stats.completed_cmd += comp_num;
+}
+
+static int ena_com_comp_status_to_errno(u8 comp_status)
+{
+	if (unlikely(comp_status != 0))
+		pr_err("admin command failed[%u]\n", comp_status);
+
+	if (unlikely(comp_status > ENA_ADMIN_UNKNOWN_ERROR))
+		return -EINVAL;
+
+	switch (comp_status) {
+	case ENA_ADMIN_SUCCESS:
+		return 0;
+	case ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE:
+		return -ENOMEM;
+	case ENA_ADMIN_UNSUPPORTED_OPCODE:
+		return -EOPNOTSUPP;
+	case ENA_ADMIN_BAD_OPCODE:
+	case ENA_ADMIN_MALFORMED_REQUEST:
+	case ENA_ADMIN_ILLEGAL_PARAMETER:
+	case ENA_ADMIN_UNKNOWN_ERROR:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx,
+						     struct ena_com_admin_queue *admin_queue)
+{
+	unsigned long flags = 0;
+	unsigned long timeout;
+	int ret;
+
+	timeout = jiffies + usecs_to_jiffies(admin_queue->completion_timeout);
+
+	while (1) {
+		spin_lock_irqsave(&admin_queue->q_lock, flags);
+		ena_com_handle_admin_completion(admin_queue);
+		spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+
+		if (comp_ctx->status != ENA_CMD_SUBMITTED)
+			break;
+
+		if (time_is_before_jiffies(timeout)) {
+			pr_err("Wait for completion (polling) timeout\n");
+			/* ENA didn't have any completion */
+			spin_lock_irqsave(&admin_queue->q_lock, flags);
+			admin_queue->stats.no_completion++;
+			admin_queue->running_state = false;
+			spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+
+			ret = -ETIME;
+			goto err;
+		}
+
+		msleep(ENA_POLL_MS);
+	}
+
+	if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) {
+		pr_err("Command was aborted\n");
+		spin_lock_irqsave(&admin_queue->q_lock, flags);
+		admin_queue->stats.aborted_cmd++;
+		spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n",
+	     comp_ctx->status);
+
+	ret = ena_com_comp_status_to_errno(comp_ctx->comp_status);
+err:
+	comp_ctxt_release(admin_queue, comp_ctx);
+	return ret;
+}
+
+/**
+ * Set the LLQ configurations of the firmware
+ *
+ * The driver provides only the enabled feature values to the device,
+ * which in turn, checks if they are supported.
+ */
+static int ena_com_set_llq(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_admin_queue *admin_queue;
+	struct ena_admin_set_feat_cmd cmd;
+	struct ena_admin_set_feat_resp resp;
+	struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
+	int ret;
+
+	memset(&cmd, 0x0, sizeof(cmd));
+	admin_queue = &ena_dev->admin_queue;
+
+	cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+	cmd.feat_common.feature_id = ENA_ADMIN_LLQ;
+
+	cmd.u.llq.header_location_ctrl_enabled = llq_info->header_location_ctrl;
+	cmd.u.llq.entry_size_ctrl_enabled = llq_info->desc_list_entry_size_ctrl;
+	cmd.u.llq.desc_num_before_header_enabled = llq_info->descs_num_before_header;
+	cmd.u.llq.descriptors_stride_ctrl_enabled = llq_info->desc_stride_ctrl;
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&cmd,
+					    sizeof(cmd),
+					    (struct ena_admin_acq_entry *)&resp,
+					    sizeof(resp));
+
+	if (unlikely(ret))
+		pr_err("Failed to set LLQ configurations: %d\n", ret);
+
+	return ret;
+}
+
+static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
+				   struct ena_admin_feature_llq_desc *llq_features,
+				   struct ena_llq_configurations *llq_default_cfg)
+{
+	struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
+	u16 supported_feat;
+	int rc;
+
+	memset(llq_info, 0, sizeof(*llq_info));
+
+	supported_feat = llq_features->header_location_ctrl_supported;
+
+	if (likely(supported_feat & llq_default_cfg->llq_header_location)) {
+		llq_info->header_location_ctrl =
+			llq_default_cfg->llq_header_location;
+	} else {
+		pr_err("Invalid header location control, supported: 0x%x\n",
+		       supported_feat);
+		return -EINVAL;
+	}
+
+	if (likely(llq_info->header_location_ctrl == ENA_ADMIN_INLINE_HEADER)) {
+		supported_feat = llq_features->descriptors_stride_ctrl_supported;
+		if (likely(supported_feat & llq_default_cfg->llq_stride_ctrl)) {
+			llq_info->desc_stride_ctrl = llq_default_cfg->llq_stride_ctrl;
+		} else	{
+			if (supported_feat & ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY) {
+				llq_info->desc_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
+			} else if (supported_feat & ENA_ADMIN_SINGLE_DESC_PER_ENTRY) {
+				llq_info->desc_stride_ctrl = ENA_ADMIN_SINGLE_DESC_PER_ENTRY;
+			} else {
+				pr_err("Invalid desc_stride_ctrl, supported: 0x%x\n",
+				       supported_feat);
+				return -EINVAL;
+			}
+
+			pr_err("Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+			       llq_default_cfg->llq_stride_ctrl, supported_feat,
+			       llq_info->desc_stride_ctrl);
+		}
+	} else {
+		llq_info->desc_stride_ctrl = 0;
+	}
+
+	supported_feat = llq_features->entry_size_ctrl_supported;
+	if (likely(supported_feat & llq_default_cfg->llq_ring_entry_size)) {
+		llq_info->desc_list_entry_size_ctrl = llq_default_cfg->llq_ring_entry_size;
+		llq_info->desc_list_entry_size = llq_default_cfg->llq_ring_entry_size_value;
+	} else {
+		if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_128B) {
+			llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
+			llq_info->desc_list_entry_size = 128;
+		} else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_192B) {
+			llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_192B;
+			llq_info->desc_list_entry_size = 192;
+		} else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_256B) {
+			llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
+			llq_info->desc_list_entry_size = 256;
+		} else {
+			pr_err("Invalid entry_size_ctrl, supported: 0x%x\n",
+			       supported_feat);
+			return -EINVAL;
+		}
+
+		pr_err("Default llq ring entry size is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+		       llq_default_cfg->llq_ring_entry_size, supported_feat,
+		       llq_info->desc_list_entry_size);
+	}
+	if (unlikely(llq_info->desc_list_entry_size & 0x7)) {
+		/* The desc list entry size should be whole multiply of 8
+		 * This requirement comes from __iowrite64_copy()
+		 */
+		pr_err("illegal entry size %d\n",
+		       llq_info->desc_list_entry_size);
+		return -EINVAL;
+	}
+
+	if (llq_info->desc_stride_ctrl == ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY)
+		llq_info->descs_per_entry = llq_info->desc_list_entry_size /
+			sizeof(struct ena_eth_io_tx_desc);
+	else
+		llq_info->descs_per_entry = 1;
+
+	supported_feat = llq_features->desc_num_before_header_supported;
+	if (likely(supported_feat & llq_default_cfg->llq_num_decs_before_header)) {
+		llq_info->descs_num_before_header = llq_default_cfg->llq_num_decs_before_header;
+	} else {
+		if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2) {
+			llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
+		} else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1) {
+			llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1;
+		} else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4) {
+			llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4;
+		} else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8) {
+			llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8;
+		} else {
+			pr_err("Invalid descs_num_before_header, supported: 0x%x\n",
+			       supported_feat);
+			return -EINVAL;
+		}
+
+		pr_err("Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+		       llq_default_cfg->llq_num_decs_before_header,
+		       supported_feat, llq_info->descs_num_before_header);
+	}
+
+	llq_info->max_entries_in_tx_burst =
+		(u16)(llq_features->max_tx_burst_size /	llq_default_cfg->llq_ring_entry_size_value);
+
+	rc = ena_com_set_llq(ena_dev);
+	if (rc)
+		pr_err("Cannot set LLQ configuration: %d\n", rc);
+
+	return rc;
+}
+
+static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx,
+							struct ena_com_admin_queue *admin_queue)
+{
+	unsigned long flags = 0;
+	int ret;
+
+	wait_for_completion_timeout(&comp_ctx->wait_event,
+				    usecs_to_jiffies(
+					    admin_queue->completion_timeout));
+
+	/* In case the command wasn't completed find out the root cause.
+	 * There might be 2 kinds of errors
+	 * 1) No completion (timeout reached)
+	 * 2) There is completion but the device didn't get any msi-x interrupt.
+	 */
+	if (unlikely(comp_ctx->status == ENA_CMD_SUBMITTED)) {
+		spin_lock_irqsave(&admin_queue->q_lock, flags);
+		ena_com_handle_admin_completion(admin_queue);
+		admin_queue->stats.no_completion++;
+		spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+
+		if (comp_ctx->status == ENA_CMD_COMPLETED) {
+			pr_err("The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n",
+			       comp_ctx->cmd_opcode,
+			       admin_queue->auto_polling ? "ON" : "OFF");
+			/* Check if fallback to polling is enabled */
+			if (admin_queue->auto_polling)
+				admin_queue->polling = true;
+		} else {
+			pr_err("The ena device doesn't send a completion for the admin cmd %d status %d\n",
+			       comp_ctx->cmd_opcode, comp_ctx->status);
+		}
+		/* Check if shifted to polling mode.
+		 * This will happen if there is a completion without an interrupt
+		 * and autopolling mode is enabled. Continuing normal execution in such case
+		 */
+		if (!admin_queue->polling) {
+			admin_queue->running_state = false;
+			ret = -ETIME;
+			goto err;
+		}
+	}
+
+	ret = ena_com_comp_status_to_errno(comp_ctx->comp_status);
+err:
+	comp_ctxt_release(admin_queue, comp_ctx);
+	return ret;
+}
+
+/* This method read the hardware device register through posting writes
+ * and waiting for response
+ * On timeout the function will return ENA_MMIO_READ_TIMEOUT
+ */
+static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
+{
+	struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
+	volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp =
+		mmio_read->read_resp;
+	u32 mmio_read_reg, ret, i;
+	unsigned long flags = 0;
+	u32 timeout = mmio_read->reg_read_to;
+
+	might_sleep();
+
+	if (timeout == 0)
+		timeout = ENA_REG_READ_TIMEOUT;
+
+	/* If readless is disabled, perform regular read */
+	if (!mmio_read->readless_supported)
+		return readl(ena_dev->reg_bar + offset);
+
+	spin_lock_irqsave(&mmio_read->lock, flags);
+	mmio_read->seq_num++;
+
+	read_resp->req_id = mmio_read->seq_num + 0xDEAD;
+	mmio_read_reg = (offset << ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT) &
+			ENA_REGS_MMIO_REG_READ_REG_OFF_MASK;
+	mmio_read_reg |= mmio_read->seq_num &
+			ENA_REGS_MMIO_REG_READ_REQ_ID_MASK;
+
+	writel(mmio_read_reg, ena_dev->reg_bar + ENA_REGS_MMIO_REG_READ_OFF);
+
+	for (i = 0; i < timeout; i++) {
+		if (READ_ONCE(read_resp->req_id) == mmio_read->seq_num)
+			break;
+
+		udelay(1);
+	}
+
+	if (unlikely(i == timeout)) {
+		pr_err("reading reg failed for timeout. expected: req id[%hu] offset[%hu] actual: req id[%hu] offset[%hu]\n",
+		       mmio_read->seq_num, offset, read_resp->req_id,
+		       read_resp->reg_off);
+		ret = ENA_MMIO_READ_TIMEOUT;
+		goto err;
+	}
+
+	if (read_resp->reg_off != offset) {
+		pr_err("Read failure: wrong offset provided\n");
+		ret = ENA_MMIO_READ_TIMEOUT;
+	} else {
+		ret = read_resp->reg_val;
+	}
+err:
+	spin_unlock_irqrestore(&mmio_read->lock, flags);
+
+	return ret;
+}
+
+/* There are two types to wait for completion.
+ * Polling mode - wait until the completion is available.
+ * Async mode - wait on wait queue until the completion is ready
+ * (or the timeout expired).
+ * It is expected that the IRQ called ena_com_handle_admin_completion
+ * to mark the completions.
+ */
+static int ena_com_wait_and_process_admin_cq(struct ena_comp_ctx *comp_ctx,
+					     struct ena_com_admin_queue *admin_queue)
+{
+	if (admin_queue->polling)
+		return ena_com_wait_and_process_admin_cq_polling(comp_ctx,
+								 admin_queue);
+
+	return ena_com_wait_and_process_admin_cq_interrupts(comp_ctx,
+							    admin_queue);
+}
+
+static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev,
+				 struct ena_com_io_sq *io_sq)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_admin_aq_destroy_sq_cmd destroy_cmd;
+	struct ena_admin_acq_destroy_sq_resp_desc destroy_resp;
+	u8 direction;
+	int ret;
+
+	memset(&destroy_cmd, 0x0, sizeof(destroy_cmd));
+
+	if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX)
+		direction = ENA_ADMIN_SQ_DIRECTION_TX;
+	else
+		direction = ENA_ADMIN_SQ_DIRECTION_RX;
+
+	destroy_cmd.sq.sq_identity |= (direction <<
+		ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT) &
+		ENA_ADMIN_SQ_SQ_DIRECTION_MASK;
+
+	destroy_cmd.sq.sq_idx = io_sq->idx;
+	destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_SQ;
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&destroy_cmd,
+					    sizeof(destroy_cmd),
+					    (struct ena_admin_acq_entry *)&destroy_resp,
+					    sizeof(destroy_resp));
+
+	if (unlikely(ret && (ret != -ENODEV)))
+		pr_err("failed to destroy io sq error: %d\n", ret);
+
+	return ret;
+}
+
+static void ena_com_io_queue_free(struct ena_com_dev *ena_dev,
+				  struct ena_com_io_sq *io_sq,
+				  struct ena_com_io_cq *io_cq)
+{
+	size_t size;
+
+	if (io_cq->cdesc_addr.virt_addr) {
+		size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth;
+
+		dma_free_coherent(ena_dev->dmadev, size,
+				  io_cq->cdesc_addr.virt_addr,
+				  io_cq->cdesc_addr.phys_addr);
+
+		io_cq->cdesc_addr.virt_addr = NULL;
+	}
+
+	if (io_sq->desc_addr.virt_addr) {
+		size = io_sq->desc_entry_size * io_sq->q_depth;
+
+		dma_free_coherent(ena_dev->dmadev, size,
+				  io_sq->desc_addr.virt_addr,
+				  io_sq->desc_addr.phys_addr);
+
+		io_sq->desc_addr.virt_addr = NULL;
+	}
+
+	if (io_sq->bounce_buf_ctrl.base_buffer) {
+		devm_kfree(ena_dev->dmadev, io_sq->bounce_buf_ctrl.base_buffer);
+		io_sq->bounce_buf_ctrl.base_buffer = NULL;
+	}
+}
+
+static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout,
+				u16 exp_state)
+{
+	u32 val, i;
+
+	/* Convert timeout from resolution of 100ms to ENA_POLL_MS */
+	timeout = (timeout * 100) / ENA_POLL_MS;
+
+	for (i = 0; i < timeout; i++) {
+		val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
+
+		if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) {
+			pr_err("Reg read timeout occurred\n");
+			return -ETIME;
+		}
+
+		if ((val & ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK) ==
+			exp_state)
+			return 0;
+
+		msleep(ENA_POLL_MS);
+	}
+
+	return -ETIME;
+}
+
+static bool ena_com_check_supported_feature_id(struct ena_com_dev *ena_dev,
+					       enum ena_admin_aq_feature_id feature_id)
+{
+	u32 feature_mask = 1 << feature_id;
+
+	/* Device attributes is always supported */
+	if ((feature_id != ENA_ADMIN_DEVICE_ATTRIBUTES) &&
+	    !(ena_dev->supported_features & feature_mask))
+		return false;
+
+	return true;
+}
+
+static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev,
+				  struct ena_admin_get_feat_resp *get_resp,
+				  enum ena_admin_aq_feature_id feature_id,
+				  dma_addr_t control_buf_dma_addr,
+				  u32 control_buff_size,
+				  u8 feature_ver)
+{
+	struct ena_com_admin_queue *admin_queue;
+	struct ena_admin_get_feat_cmd get_cmd;
+	int ret;
+
+	if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) {
+		pr_debug("Feature %d isn't supported\n", feature_id);
+		return -EOPNOTSUPP;
+	}
+
+	memset(&get_cmd, 0x0, sizeof(get_cmd));
+	admin_queue = &ena_dev->admin_queue;
+
+	get_cmd.aq_common_descriptor.opcode = ENA_ADMIN_GET_FEATURE;
+
+	if (control_buff_size)
+		get_cmd.aq_common_descriptor.flags =
+			ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK;
+	else
+		get_cmd.aq_common_descriptor.flags = 0;
+
+	ret = ena_com_mem_addr_set(ena_dev,
+				   &get_cmd.control_buffer.address,
+				   control_buf_dma_addr);
+	if (unlikely(ret)) {
+		pr_err("memory address set failed\n");
+		return ret;
+	}
+
+	get_cmd.control_buffer.length = control_buff_size;
+	get_cmd.feat_common.feature_version = feature_ver;
+	get_cmd.feat_common.feature_id = feature_id;
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)
+					    &get_cmd,
+					    sizeof(get_cmd),
+					    (struct ena_admin_acq_entry *)
+					    get_resp,
+					    sizeof(*get_resp));
+
+	if (unlikely(ret))
+		pr_err("Failed to submit get_feature command %d error: %d\n",
+		       feature_id, ret);
+
+	return ret;
+}
+
+static int ena_com_get_feature(struct ena_com_dev *ena_dev,
+			       struct ena_admin_get_feat_resp *get_resp,
+			       enum ena_admin_aq_feature_id feature_id,
+			       u8 feature_ver)
+{
+	return ena_com_get_feature_ex(ena_dev,
+				      get_resp,
+				      feature_id,
+				      0,
+				      0,
+				      feature_ver);
+}
+
+static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+
+	rss->hash_key =
+		dma_zalloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key),
+				    &rss->hash_key_dma_addr, GFP_KERNEL);
+
+	if (unlikely(!rss->hash_key))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void ena_com_hash_key_destroy(struct ena_com_dev *ena_dev)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+
+	if (rss->hash_key)
+		dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key),
+				  rss->hash_key, rss->hash_key_dma_addr);
+	rss->hash_key = NULL;
+}
+
+static int ena_com_hash_ctrl_init(struct ena_com_dev *ena_dev)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+
+	rss->hash_ctrl =
+		dma_zalloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl),
+				    &rss->hash_ctrl_dma_addr, GFP_KERNEL);
+
+	if (unlikely(!rss->hash_ctrl))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void ena_com_hash_ctrl_destroy(struct ena_com_dev *ena_dev)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+
+	if (rss->hash_ctrl)
+		dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl),
+				  rss->hash_ctrl, rss->hash_ctrl_dma_addr);
+	rss->hash_ctrl = NULL;
+}
+
+static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev,
+					   u16 log_size)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_get_feat_resp get_resp;
+	size_t tbl_size;
+	int ret;
+
+	ret = ena_com_get_feature(ena_dev, &get_resp,
+				  ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG, 0);
+	if (unlikely(ret))
+		return ret;
+
+	if ((get_resp.u.ind_table.min_size > log_size) ||
+	    (get_resp.u.ind_table.max_size < log_size)) {
+		pr_err("indirect table size doesn't fit. requested size: %d while min is:%d and max %d\n",
+		       1 << log_size, 1 << get_resp.u.ind_table.min_size,
+		       1 << get_resp.u.ind_table.max_size);
+		return -EINVAL;
+	}
+
+	tbl_size = (1ULL << log_size) *
+		sizeof(struct ena_admin_rss_ind_table_entry);
+
+	rss->rss_ind_tbl =
+		dma_zalloc_coherent(ena_dev->dmadev, tbl_size,
+				    &rss->rss_ind_tbl_dma_addr, GFP_KERNEL);
+	if (unlikely(!rss->rss_ind_tbl))
+		goto mem_err1;
+
+	tbl_size = (1ULL << log_size) * sizeof(u16);
+	rss->host_rss_ind_tbl =
+		devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL);
+	if (unlikely(!rss->host_rss_ind_tbl))
+		goto mem_err2;
+
+	rss->tbl_log_size = log_size;
+
+	return 0;
+
+mem_err2:
+	tbl_size = (1ULL << log_size) *
+		sizeof(struct ena_admin_rss_ind_table_entry);
+
+	dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl,
+			  rss->rss_ind_tbl_dma_addr);
+	rss->rss_ind_tbl = NULL;
+mem_err1:
+	rss->tbl_log_size = 0;
+	return -ENOMEM;
+}
+
+static void ena_com_indirect_table_destroy(struct ena_com_dev *ena_dev)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	size_t tbl_size = (1ULL << rss->tbl_log_size) *
+		sizeof(struct ena_admin_rss_ind_table_entry);
+
+	if (rss->rss_ind_tbl)
+		dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl,
+				  rss->rss_ind_tbl_dma_addr);
+	rss->rss_ind_tbl = NULL;
+
+	if (rss->host_rss_ind_tbl)
+		devm_kfree(ena_dev->dmadev, rss->host_rss_ind_tbl);
+	rss->host_rss_ind_tbl = NULL;
+}
+
+static int ena_com_create_io_sq(struct ena_com_dev *ena_dev,
+				struct ena_com_io_sq *io_sq, u16 cq_idx)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_admin_aq_create_sq_cmd create_cmd;
+	struct ena_admin_acq_create_sq_resp_desc cmd_completion;
+	u8 direction;
+	int ret;
+
+	memset(&create_cmd, 0x0, sizeof(create_cmd));
+
+	create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_SQ;
+
+	if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX)
+		direction = ENA_ADMIN_SQ_DIRECTION_TX;
+	else
+		direction = ENA_ADMIN_SQ_DIRECTION_RX;
+
+	create_cmd.sq_identity |= (direction <<
+		ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT) &
+		ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK;
+
+	create_cmd.sq_caps_2 |= io_sq->mem_queue_type &
+		ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK;
+
+	create_cmd.sq_caps_2 |= (ENA_ADMIN_COMPLETION_POLICY_DESC <<
+		ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT) &
+		ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK;
+
+	create_cmd.sq_caps_3 |=
+		ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK;
+
+	create_cmd.cq_idx = cq_idx;
+	create_cmd.sq_depth = io_sq->q_depth;
+
+	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) {
+		ret = ena_com_mem_addr_set(ena_dev,
+					   &create_cmd.sq_ba,
+					   io_sq->desc_addr.phys_addr);
+		if (unlikely(ret)) {
+			pr_err("memory address set failed\n");
+			return ret;
+		}
+	}
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&create_cmd,
+					    sizeof(create_cmd),
+					    (struct ena_admin_acq_entry *)&cmd_completion,
+					    sizeof(cmd_completion));
+	if (unlikely(ret)) {
+		pr_err("Failed to create IO SQ. error: %d\n", ret);
+		return ret;
+	}
+
+	io_sq->idx = cmd_completion.sq_idx;
+
+	io_sq->db_addr = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
+		(uintptr_t)cmd_completion.sq_doorbell_offset);
+
+	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
+		io_sq->header_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar
+				+ cmd_completion.llq_headers_offset);
+
+		io_sq->desc_addr.pbuf_dev_addr =
+			(u8 __iomem *)((uintptr_t)ena_dev->mem_bar +
+			cmd_completion.llq_descriptors_offset);
+	}
+
+	pr_debug("created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth);
+
+	return ret;
+}
+
+static int ena_com_ind_tbl_convert_to_device(struct ena_com_dev *ena_dev)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_com_io_sq *io_sq;
+	u16 qid;
+	int i;
+
+	for (i = 0; i < 1 << rss->tbl_log_size; i++) {
+		qid = rss->host_rss_ind_tbl[i];
+		if (qid >= ENA_TOTAL_NUM_QUEUES)
+			return -EINVAL;
+
+		io_sq = &ena_dev->io_sq_queues[qid];
+
+		if (io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX)
+			return -EINVAL;
+
+		rss->rss_ind_tbl[i].cq_idx = io_sq->idx;
+	}
+
+	return 0;
+}
+
+static int ena_com_ind_tbl_convert_from_device(struct ena_com_dev *ena_dev)
+{
+	u16 dev_idx_to_host_tbl[ENA_TOTAL_NUM_QUEUES] = { (u16)-1 };
+	struct ena_rss *rss = &ena_dev->rss;
+	u8 idx;
+	u16 i;
+
+	for (i = 0; i < ENA_TOTAL_NUM_QUEUES; i++)
+		dev_idx_to_host_tbl[ena_dev->io_sq_queues[i].idx] = i;
+
+	for (i = 0; i < 1 << rss->tbl_log_size; i++) {
+		if (rss->rss_ind_tbl[i].cq_idx > ENA_TOTAL_NUM_QUEUES)
+			return -EINVAL;
+		idx = (u8)rss->rss_ind_tbl[i].cq_idx;
+
+		if (dev_idx_to_host_tbl[idx] > ENA_TOTAL_NUM_QUEUES)
+			return -EINVAL;
+
+		rss->host_rss_ind_tbl[i] = dev_idx_to_host_tbl[idx];
+	}
+
+	return 0;
+}
+
+static void ena_com_update_intr_delay_resolution(struct ena_com_dev *ena_dev,
+						 u16 intr_delay_resolution)
+{
+	/* Initial value of intr_delay_resolution might be 0 */
+	u16 prev_intr_delay_resolution =
+		ena_dev->intr_delay_resolution ?
+		ena_dev->intr_delay_resolution :
+		ENA_DEFAULT_INTR_DELAY_RESOLUTION;
+
+	if (!intr_delay_resolution) {
+		pr_err("Illegal intr_delay_resolution provided. Going to use default 1 usec resolution\n");
+		intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION;
+	}
+
+	/* update Rx */
+	ena_dev->intr_moder_rx_interval =
+		ena_dev->intr_moder_rx_interval *
+		prev_intr_delay_resolution /
+		intr_delay_resolution;
+
+	/* update Tx */
+	ena_dev->intr_moder_tx_interval =
+		ena_dev->intr_moder_tx_interval *
+		prev_intr_delay_resolution /
+		intr_delay_resolution;
+
+	ena_dev->intr_delay_resolution = intr_delay_resolution;
+}
+
+/*****************************************************************************/
+/*******************************      API       ******************************/
+/*****************************************************************************/
+
+int ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue,
+				  struct ena_admin_aq_entry *cmd,
+				  size_t cmd_size,
+				  struct ena_admin_acq_entry *comp,
+				  size_t comp_size)
+{
+	struct ena_comp_ctx *comp_ctx;
+	int ret;
+
+	comp_ctx = ena_com_submit_admin_cmd(admin_queue, cmd, cmd_size,
+					    comp, comp_size);
+	if (IS_ERR(comp_ctx)) {
+		if (comp_ctx == ERR_PTR(-ENODEV))
+			pr_debug("Failed to submit command [%ld]\n",
+				 PTR_ERR(comp_ctx));
+		else
+			pr_err("Failed to submit command [%ld]\n",
+			       PTR_ERR(comp_ctx));
+
+		return PTR_ERR(comp_ctx);
+	}
+
+	ret = ena_com_wait_and_process_admin_cq(comp_ctx, admin_queue);
+	if (unlikely(ret)) {
+		if (admin_queue->running_state)
+			pr_err("Failed to process command. ret = %d\n", ret);
+		else
+			pr_debug("Failed to process command. ret = %d\n", ret);
+	}
+	return ret;
+}
+
+int ena_com_create_io_cq(struct ena_com_dev *ena_dev,
+			 struct ena_com_io_cq *io_cq)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_admin_aq_create_cq_cmd create_cmd;
+	struct ena_admin_acq_create_cq_resp_desc cmd_completion;
+	int ret;
+
+	memset(&create_cmd, 0x0, sizeof(create_cmd));
+
+	create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_CQ;
+
+	create_cmd.cq_caps_2 |= (io_cq->cdesc_entry_size_in_bytes / 4) &
+		ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK;
+	create_cmd.cq_caps_1 |=
+		ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK;
+
+	create_cmd.msix_vector = io_cq->msix_vector;
+	create_cmd.cq_depth = io_cq->q_depth;
+
+	ret = ena_com_mem_addr_set(ena_dev,
+				   &create_cmd.cq_ba,
+				   io_cq->cdesc_addr.phys_addr);
+	if (unlikely(ret)) {
+		pr_err("memory address set failed\n");
+		return ret;
+	}
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&create_cmd,
+					    sizeof(create_cmd),
+					    (struct ena_admin_acq_entry *)&cmd_completion,
+					    sizeof(cmd_completion));
+	if (unlikely(ret)) {
+		pr_err("Failed to create IO CQ. error: %d\n", ret);
+		return ret;
+	}
+
+	io_cq->idx = cmd_completion.cq_idx;
+
+	io_cq->unmask_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
+		cmd_completion.cq_interrupt_unmask_register_offset);
+
+	if (cmd_completion.cq_head_db_register_offset)
+		io_cq->cq_head_db_reg =
+			(u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
+			cmd_completion.cq_head_db_register_offset);
+
+	if (cmd_completion.numa_node_register_offset)
+		io_cq->numa_node_cfg_reg =
+			(u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
+			cmd_completion.numa_node_register_offset);
+
+	pr_debug("created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth);
+
+	return ret;
+}
+
+int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid,
+			    struct ena_com_io_sq **io_sq,
+			    struct ena_com_io_cq **io_cq)
+{
+	if (qid >= ENA_TOTAL_NUM_QUEUES) {
+		pr_err("Invalid queue number %d but the max is %d\n", qid,
+		       ENA_TOTAL_NUM_QUEUES);
+		return -EINVAL;
+	}
+
+	*io_sq = &ena_dev->io_sq_queues[qid];
+	*io_cq = &ena_dev->io_cq_queues[qid];
+
+	return 0;
+}
+
+void ena_com_abort_admin_commands(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_comp_ctx *comp_ctx;
+	u16 i;
+
+	if (!admin_queue->comp_ctx)
+		return;
+
+	for (i = 0; i < admin_queue->q_depth; i++) {
+		comp_ctx = get_comp_ctxt(admin_queue, i, false);
+		if (unlikely(!comp_ctx))
+			break;
+
+		comp_ctx->status = ENA_CMD_ABORTED;
+
+		complete(&comp_ctx->wait_event);
+	}
+}
+
+void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&admin_queue->q_lock, flags);
+	while (atomic_read(&admin_queue->outstanding_cmds) != 0) {
+		spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+		msleep(ENA_POLL_MS);
+		spin_lock_irqsave(&admin_queue->q_lock, flags);
+	}
+	spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+}
+
+int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev,
+			  struct ena_com_io_cq *io_cq)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_admin_aq_destroy_cq_cmd destroy_cmd;
+	struct ena_admin_acq_destroy_cq_resp_desc destroy_resp;
+	int ret;
+
+	memset(&destroy_cmd, 0x0, sizeof(destroy_cmd));
+
+	destroy_cmd.cq_idx = io_cq->idx;
+	destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_CQ;
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&destroy_cmd,
+					    sizeof(destroy_cmd),
+					    (struct ena_admin_acq_entry *)&destroy_resp,
+					    sizeof(destroy_resp));
+
+	if (unlikely(ret && (ret != -ENODEV)))
+		pr_err("Failed to destroy IO CQ. error: %d\n", ret);
+
+	return ret;
+}
+
+bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev)
+{
+	return ena_dev->admin_queue.running_state;
+}
+
+void ena_com_set_admin_running_state(struct ena_com_dev *ena_dev, bool state)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&admin_queue->q_lock, flags);
+	ena_dev->admin_queue.running_state = state;
+	spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+}
+
+void ena_com_admin_aenq_enable(struct ena_com_dev *ena_dev)
+{
+	u16 depth = ena_dev->aenq.q_depth;
+
+	WARN(ena_dev->aenq.head != depth, "Invalid AENQ state\n");
+
+	/* Init head_db to mark that all entries in the queue
+	 * are initially available
+	 */
+	writel(depth, ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF);
+}
+
+int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag)
+{
+	struct ena_com_admin_queue *admin_queue;
+	struct ena_admin_set_feat_cmd cmd;
+	struct ena_admin_set_feat_resp resp;
+	struct ena_admin_get_feat_resp get_resp;
+	int ret;
+
+	ret = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_AENQ_CONFIG, 0);
+	if (ret) {
+		pr_info("Can't get aenq configuration\n");
+		return ret;
+	}
+
+	if ((get_resp.u.aenq.supported_groups & groups_flag) != groups_flag) {
+		pr_warn("Trying to set unsupported aenq events. supported flag: 0x%x asked flag: 0x%x\n",
+			get_resp.u.aenq.supported_groups, groups_flag);
+		return -EOPNOTSUPP;
+	}
+
+	memset(&cmd, 0x0, sizeof(cmd));
+	admin_queue = &ena_dev->admin_queue;
+
+	cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+	cmd.aq_common_descriptor.flags = 0;
+	cmd.feat_common.feature_id = ENA_ADMIN_AENQ_CONFIG;
+	cmd.u.aenq.enabled_groups = groups_flag;
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&cmd,
+					    sizeof(cmd),
+					    (struct ena_admin_acq_entry *)&resp,
+					    sizeof(resp));
+
+	if (unlikely(ret))
+		pr_err("Failed to config AENQ ret: %d\n", ret);
+
+	return ret;
+}
+
+int ena_com_get_dma_width(struct ena_com_dev *ena_dev)
+{
+	u32 caps = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF);
+	int width;
+
+	if (unlikely(caps == ENA_MMIO_READ_TIMEOUT)) {
+		pr_err("Reg read timeout occurred\n");
+		return -ETIME;
+	}
+
+	width = (caps & ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK) >>
+		ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT;
+
+	pr_debug("ENA dma width: %d\n", width);
+
+	if ((width < 32) || width > ENA_MAX_PHYS_ADDR_SIZE_BITS) {
+		pr_err("DMA width illegal value: %d\n", width);
+		return -EINVAL;
+	}
+
+	ena_dev->dma_addr_bits = width;
+
+	return width;
+}
+
+int ena_com_validate_version(struct ena_com_dev *ena_dev)
+{
+	u32 ver;
+	u32 ctrl_ver;
+	u32 ctrl_ver_masked;
+
+	/* Make sure the ENA version and the controller version are at least
+	 * as the driver expects
+	 */
+	ver = ena_com_reg_bar_read32(ena_dev, ENA_REGS_VERSION_OFF);
+	ctrl_ver = ena_com_reg_bar_read32(ena_dev,
+					  ENA_REGS_CONTROLLER_VERSION_OFF);
+
+	if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) ||
+		     (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) {
+		pr_err("Reg read timeout occurred\n");
+		return -ETIME;
+	}
+
+	pr_info("ena device version: %d.%d\n",
+		(ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >>
+			ENA_REGS_VERSION_MAJOR_VERSION_SHIFT,
+		ver & ENA_REGS_VERSION_MINOR_VERSION_MASK);
+
+	pr_info("ena controller version: %d.%d.%d implementation version %d\n",
+		(ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) >>
+			ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT,
+		(ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) >>
+			ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT,
+		(ctrl_ver & ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK),
+		(ctrl_ver & ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK) >>
+			ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT);
+
+	ctrl_ver_masked =
+		(ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) |
+		(ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) |
+		(ctrl_ver & ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK);
+
+	/* Validate the ctrl version without the implementation ID */
+	if (ctrl_ver_masked < MIN_ENA_CTRL_VER) {
+		pr_err("ENA ctrl version is lower than the minimal ctrl version the driver supports\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void ena_com_admin_destroy(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_com_admin_cq *cq = &admin_queue->cq;
+	struct ena_com_admin_sq *sq = &admin_queue->sq;
+	struct ena_com_aenq *aenq = &ena_dev->aenq;
+	u16 size;
+
+	if (admin_queue->comp_ctx)
+		devm_kfree(ena_dev->dmadev, admin_queue->comp_ctx);
+	admin_queue->comp_ctx = NULL;
+	size = ADMIN_SQ_SIZE(admin_queue->q_depth);
+	if (sq->entries)
+		dma_free_coherent(ena_dev->dmadev, size, sq->entries,
+				  sq->dma_addr);
+	sq->entries = NULL;
+
+	size = ADMIN_CQ_SIZE(admin_queue->q_depth);
+	if (cq->entries)
+		dma_free_coherent(ena_dev->dmadev, size, cq->entries,
+				  cq->dma_addr);
+	cq->entries = NULL;
+
+	size = ADMIN_AENQ_SIZE(aenq->q_depth);
+	if (ena_dev->aenq.entries)
+		dma_free_coherent(ena_dev->dmadev, size, aenq->entries,
+				  aenq->dma_addr);
+	aenq->entries = NULL;
+}
+
+void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling)
+{
+	u32 mask_value = 0;
+
+	if (polling)
+		mask_value = ENA_REGS_ADMIN_INTR_MASK;
+
+	writel(mask_value, ena_dev->reg_bar + ENA_REGS_INTR_MASK_OFF);
+	ena_dev->admin_queue.polling = polling;
+}
+
+void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev,
+					 bool polling)
+{
+	ena_dev->admin_queue.auto_polling = polling;
+}
+
+int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
+
+	spin_lock_init(&mmio_read->lock);
+	mmio_read->read_resp =
+		dma_zalloc_coherent(ena_dev->dmadev,
+				    sizeof(*mmio_read->read_resp),
+				    &mmio_read->read_resp_dma_addr, GFP_KERNEL);
+	if (unlikely(!mmio_read->read_resp))
+		goto err;
+
+	ena_com_mmio_reg_read_request_write_dev_addr(ena_dev);
+
+	mmio_read->read_resp->req_id = 0x0;
+	mmio_read->seq_num = 0x0;
+	mmio_read->readless_supported = true;
+
+	return 0;
+
+err:
+
+	return -ENOMEM;
+}
+
+void ena_com_set_mmio_read_mode(struct ena_com_dev *ena_dev, bool readless_supported)
+{
+	struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
+
+	mmio_read->readless_supported = readless_supported;
+}
+
+void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
+
+	writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF);
+	writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF);
+
+	dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp),
+			  mmio_read->read_resp, mmio_read->read_resp_dma_addr);
+
+	mmio_read->read_resp = NULL;
+}
+
+void ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
+	u32 addr_low, addr_high;
+
+	addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(mmio_read->read_resp_dma_addr);
+	addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(mmio_read->read_resp_dma_addr);
+
+	writel(addr_low, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF);
+	writel(addr_high, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF);
+}
+
+int ena_com_admin_init(struct ena_com_dev *ena_dev,
+		       struct ena_aenq_handlers *aenq_handlers)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	u32 aq_caps, acq_caps, dev_sts, addr_low, addr_high;
+	int ret;
+
+	dev_sts = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
+
+	if (unlikely(dev_sts == ENA_MMIO_READ_TIMEOUT)) {
+		pr_err("Reg read timeout occurred\n");
+		return -ETIME;
+	}
+
+	if (!(dev_sts & ENA_REGS_DEV_STS_READY_MASK)) {
+		pr_err("Device isn't ready, abort com init\n");
+		return -ENODEV;
+	}
+
+	admin_queue->q_depth = ENA_ADMIN_QUEUE_DEPTH;
+
+	admin_queue->q_dmadev = ena_dev->dmadev;
+	admin_queue->polling = false;
+	admin_queue->curr_cmd_id = 0;
+
+	atomic_set(&admin_queue->outstanding_cmds, 0);
+
+	spin_lock_init(&admin_queue->q_lock);
+
+	ret = ena_com_init_comp_ctxt(admin_queue);
+	if (ret)
+		goto error;
+
+	ret = ena_com_admin_init_sq(admin_queue);
+	if (ret)
+		goto error;
+
+	ret = ena_com_admin_init_cq(admin_queue);
+	if (ret)
+		goto error;
+
+	admin_queue->sq.db_addr = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
+		ENA_REGS_AQ_DB_OFF);
+
+	addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(admin_queue->sq.dma_addr);
+	addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(admin_queue->sq.dma_addr);
+
+	writel(addr_low, ena_dev->reg_bar + ENA_REGS_AQ_BASE_LO_OFF);
+	writel(addr_high, ena_dev->reg_bar + ENA_REGS_AQ_BASE_HI_OFF);
+
+	addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(admin_queue->cq.dma_addr);
+	addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(admin_queue->cq.dma_addr);
+
+	writel(addr_low, ena_dev->reg_bar + ENA_REGS_ACQ_BASE_LO_OFF);
+	writel(addr_high, ena_dev->reg_bar + ENA_REGS_ACQ_BASE_HI_OFF);
+
+	aq_caps = 0;
+	aq_caps |= admin_queue->q_depth & ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK;
+	aq_caps |= (sizeof(struct ena_admin_aq_entry) <<
+			ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT) &
+			ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK;
+
+	acq_caps = 0;
+	acq_caps |= admin_queue->q_depth & ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK;
+	acq_caps |= (sizeof(struct ena_admin_acq_entry) <<
+		ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT) &
+		ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK;
+
+	writel(aq_caps, ena_dev->reg_bar + ENA_REGS_AQ_CAPS_OFF);
+	writel(acq_caps, ena_dev->reg_bar + ENA_REGS_ACQ_CAPS_OFF);
+	ret = ena_com_admin_init_aenq(ena_dev, aenq_handlers);
+	if (ret)
+		goto error;
+
+	admin_queue->running_state = true;
+
+	return 0;
+error:
+	ena_com_admin_destroy(ena_dev);
+
+	return ret;
+}
+
+int ena_com_create_io_queue(struct ena_com_dev *ena_dev,
+			    struct ena_com_create_io_ctx *ctx)
+{
+	struct ena_com_io_sq *io_sq;
+	struct ena_com_io_cq *io_cq;
+	int ret;
+
+	if (ctx->qid >= ENA_TOTAL_NUM_QUEUES) {
+		pr_err("Qid (%d) is bigger than max num of queues (%d)\n",
+		       ctx->qid, ENA_TOTAL_NUM_QUEUES);
+		return -EINVAL;
+	}
+
+	io_sq = &ena_dev->io_sq_queues[ctx->qid];
+	io_cq = &ena_dev->io_cq_queues[ctx->qid];
+
+	memset(io_sq, 0x0, sizeof(*io_sq));
+	memset(io_cq, 0x0, sizeof(*io_cq));
+
+	/* Init CQ */
+	io_cq->q_depth = ctx->queue_size;
+	io_cq->direction = ctx->direction;
+	io_cq->qid = ctx->qid;
+
+	io_cq->msix_vector = ctx->msix_vector;
+
+	io_sq->q_depth = ctx->queue_size;
+	io_sq->direction = ctx->direction;
+	io_sq->qid = ctx->qid;
+
+	io_sq->mem_queue_type = ctx->mem_queue_type;
+
+	if (ctx->direction == ENA_COM_IO_QUEUE_DIRECTION_TX)
+		/* header length is limited to 8 bits */
+		io_sq->tx_max_header_size =
+			min_t(u32, ena_dev->tx_max_header_size, SZ_256);
+
+	ret = ena_com_init_io_sq(ena_dev, ctx, io_sq);
+	if (ret)
+		goto error;
+	ret = ena_com_init_io_cq(ena_dev, ctx, io_cq);
+	if (ret)
+		goto error;
+
+	ret = ena_com_create_io_cq(ena_dev, io_cq);
+	if (ret)
+		goto error;
+
+	ret = ena_com_create_io_sq(ena_dev, io_sq, io_cq->idx);
+	if (ret)
+		goto destroy_io_cq;
+
+	return 0;
+
+destroy_io_cq:
+	ena_com_destroy_io_cq(ena_dev, io_cq);
+error:
+	ena_com_io_queue_free(ena_dev, io_sq, io_cq);
+	return ret;
+}
+
+void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid)
+{
+	struct ena_com_io_sq *io_sq;
+	struct ena_com_io_cq *io_cq;
+
+	if (qid >= ENA_TOTAL_NUM_QUEUES) {
+		pr_err("Qid (%d) is bigger than max num of queues (%d)\n", qid,
+		       ENA_TOTAL_NUM_QUEUES);
+		return;
+	}
+
+	io_sq = &ena_dev->io_sq_queues[qid];
+	io_cq = &ena_dev->io_cq_queues[qid];
+
+	ena_com_destroy_io_sq(ena_dev, io_sq);
+	ena_com_destroy_io_cq(ena_dev, io_cq);
+
+	ena_com_io_queue_free(ena_dev, io_sq, io_cq);
+}
+
+int ena_com_get_link_params(struct ena_com_dev *ena_dev,
+			    struct ena_admin_get_feat_resp *resp)
+{
+	return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG, 0);
+}
+
+int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
+			      struct ena_com_dev_get_features_ctx *get_feat_ctx)
+{
+	struct ena_admin_get_feat_resp get_resp;
+	int rc;
+
+	rc = ena_com_get_feature(ena_dev, &get_resp,
+				 ENA_ADMIN_DEVICE_ATTRIBUTES, 0);
+	if (rc)
+		return rc;
+
+	memcpy(&get_feat_ctx->dev_attr, &get_resp.u.dev_attr,
+	       sizeof(get_resp.u.dev_attr));
+	ena_dev->supported_features = get_resp.u.dev_attr.supported_features;
+
+	if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
+		rc = ena_com_get_feature(ena_dev, &get_resp,
+					 ENA_ADMIN_MAX_QUEUES_EXT,
+					 ENA_FEATURE_MAX_QUEUE_EXT_VER);
+		if (rc)
+			return rc;
+
+		if (get_resp.u.max_queue_ext.version != ENA_FEATURE_MAX_QUEUE_EXT_VER)
+			return -EINVAL;
+
+		memcpy(&get_feat_ctx->max_queue_ext, &get_resp.u.max_queue_ext,
+		       sizeof(get_resp.u.max_queue_ext));
+		ena_dev->tx_max_header_size =
+			get_resp.u.max_queue_ext.max_queue_ext.max_tx_header_size;
+	} else {
+		rc = ena_com_get_feature(ena_dev, &get_resp,
+					 ENA_ADMIN_MAX_QUEUES_NUM, 0);
+		memcpy(&get_feat_ctx->max_queues, &get_resp.u.max_queue,
+		       sizeof(get_resp.u.max_queue));
+		ena_dev->tx_max_header_size =
+			get_resp.u.max_queue.max_header_size;
+
+		if (rc)
+			return rc;
+	}
+
+	rc = ena_com_get_feature(ena_dev, &get_resp,
+				 ENA_ADMIN_AENQ_CONFIG, 0);
+	if (rc)
+		return rc;
+
+	memcpy(&get_feat_ctx->aenq, &get_resp.u.aenq,
+	       sizeof(get_resp.u.aenq));
+
+	rc = ena_com_get_feature(ena_dev, &get_resp,
+				 ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0);
+	if (rc)
+		return rc;
+
+	memcpy(&get_feat_ctx->offload, &get_resp.u.offload,
+	       sizeof(get_resp.u.offload));
+
+	/* Driver hints isn't mandatory admin command. So in case the
+	 * command isn't supported set driver hints to 0
+	 */
+	rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS, 0);
+
+	if (!rc)
+		memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints,
+		       sizeof(get_resp.u.hw_hints));
+	else if (rc == -EOPNOTSUPP)
+		memset(&get_feat_ctx->hw_hints, 0x0,
+		       sizeof(get_feat_ctx->hw_hints));
+	else
+		return rc;
+
+	rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ, 0);
+	if (!rc)
+		memcpy(&get_feat_ctx->llq, &get_resp.u.llq,
+		       sizeof(get_resp.u.llq));
+	else if (rc == -EOPNOTSUPP)
+		memset(&get_feat_ctx->llq, 0x0, sizeof(get_feat_ctx->llq));
+	else
+		return rc;
+
+	return 0;
+}
+
+void ena_com_admin_q_comp_intr_handler(struct ena_com_dev *ena_dev)
+{
+	ena_com_handle_admin_completion(&ena_dev->admin_queue);
+}
+
+/* ena_handle_specific_aenq_event:
+ * return the handler that is relevant to the specific event group
+ */
+static ena_aenq_handler ena_com_get_specific_aenq_cb(struct ena_com_dev *dev,
+						     u16 group)
+{
+	struct ena_aenq_handlers *aenq_handlers = dev->aenq.aenq_handlers;
+
+	if ((group < ENA_MAX_HANDLERS) && aenq_handlers->handlers[group])
+		return aenq_handlers->handlers[group];
+
+	return aenq_handlers->unimplemented_handler;
+}
+
+/* ena_aenq_intr_handler:
+ * handles the aenq incoming events.
+ * pop events from the queue and apply the specific handler
+ */
+void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data)
+{
+	struct ena_admin_aenq_entry *aenq_e;
+	struct ena_admin_aenq_common_desc *aenq_common;
+	struct ena_com_aenq *aenq  = &dev->aenq;
+	unsigned long long timestamp;
+	ena_aenq_handler handler_cb;
+	u16 masked_head, processed = 0;
+	u8 phase;
+
+	masked_head = aenq->head & (aenq->q_depth - 1);
+	phase = aenq->phase;
+	aenq_e = &aenq->entries[masked_head]; /* Get first entry */
+	aenq_common = &aenq_e->aenq_common_desc;
+
+	/* Go over all the events */
+	while ((READ_ONCE(aenq_common->flags) &
+		ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) {
+		/* Make sure the phase bit (ownership) is as expected before
+		 * reading the rest of the descriptor.
+		 */
+		dma_rmb();
+
+		timestamp =
+			(unsigned long long)aenq_common->timestamp_low |
+			((unsigned long long)aenq_common->timestamp_high << 32);
+		pr_debug("AENQ! Group[%x] Syndrom[%x] timestamp: [%llus]\n",
+			 aenq_common->group, aenq_common->syndrom, timestamp);
+
+		/* Handle specific event*/
+		handler_cb = ena_com_get_specific_aenq_cb(dev,
+							  aenq_common->group);
+		handler_cb(data, aenq_e); /* call the actual event handler*/
+
+		/* Get next event entry */
+		masked_head++;
+		processed++;
+
+		if (unlikely(masked_head == aenq->q_depth)) {
+			masked_head = 0;
+			phase = !phase;
+		}
+		aenq_e = &aenq->entries[masked_head];
+		aenq_common = &aenq_e->aenq_common_desc;
+	}
+
+	aenq->head += processed;
+	aenq->phase = phase;
+
+	/* Don't update aenq doorbell if there weren't any processed events */
+	if (!processed)
+		return;
+
+	/* write the aenq doorbell after all AENQ descriptors were read */
+	mb();
+	writel_relaxed((u32)aenq->head,
+		       dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF);
+	mmiowb();
+}
+
+int ena_com_dev_reset(struct ena_com_dev *ena_dev,
+		      enum ena_regs_reset_reason_types reset_reason)
+{
+	u32 stat, timeout, cap, reset_val;
+	int rc;
+
+	stat = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
+	cap = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF);
+
+	if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) ||
+		     (cap == ENA_MMIO_READ_TIMEOUT))) {
+		pr_err("Reg read32 timeout occurred\n");
+		return -ETIME;
+	}
+
+	if ((stat & ENA_REGS_DEV_STS_READY_MASK) == 0) {
+		pr_err("Device isn't ready, can't reset device\n");
+		return -EINVAL;
+	}
+
+	timeout = (cap & ENA_REGS_CAPS_RESET_TIMEOUT_MASK) >>
+			ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT;
+	if (timeout == 0) {
+		pr_err("Invalid timeout value\n");
+		return -EINVAL;
+	}
+
+	/* start reset */
+	reset_val = ENA_REGS_DEV_CTL_DEV_RESET_MASK;
+	reset_val |= (reset_reason << ENA_REGS_DEV_CTL_RESET_REASON_SHIFT) &
+		     ENA_REGS_DEV_CTL_RESET_REASON_MASK;
+	writel(reset_val, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF);
+
+	/* Write again the MMIO read request address */
+	ena_com_mmio_reg_read_request_write_dev_addr(ena_dev);
+
+	rc = wait_for_reset_state(ena_dev, timeout,
+				  ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK);
+	if (rc != 0) {
+		pr_err("Reset indication didn't turn on\n");
+		return rc;
+	}
+
+	/* reset done */
+	writel(0, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF);
+	rc = wait_for_reset_state(ena_dev, timeout, 0);
+	if (rc != 0) {
+		pr_err("Reset indication didn't turn off\n");
+		return rc;
+	}
+
+	timeout = (cap & ENA_REGS_CAPS_ADMIN_CMD_TO_MASK) >>
+		ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT;
+	if (timeout)
+		/* the resolution of timeout reg is 100ms */
+		ena_dev->admin_queue.completion_timeout = timeout * 100000;
+	else
+		ena_dev->admin_queue.completion_timeout = ADMIN_CMD_TIMEOUT_US;
+
+	return 0;
+}
+
+static int ena_get_dev_stats(struct ena_com_dev *ena_dev,
+			     struct ena_com_stats_ctx *ctx,
+			     enum ena_admin_get_stats_type type)
+{
+	struct ena_admin_aq_get_stats_cmd *get_cmd = &ctx->get_cmd;
+	struct ena_admin_acq_get_stats_resp *get_resp = &ctx->get_resp;
+	struct ena_com_admin_queue *admin_queue;
+	int ret;
+
+	admin_queue = &ena_dev->admin_queue;
+
+	get_cmd->aq_common_descriptor.opcode = ENA_ADMIN_GET_STATS;
+	get_cmd->aq_common_descriptor.flags = 0;
+	get_cmd->type = type;
+
+	ret =  ena_com_execute_admin_command(admin_queue,
+					     (struct ena_admin_aq_entry *)get_cmd,
+					     sizeof(*get_cmd),
+					     (struct ena_admin_acq_entry *)get_resp,
+					     sizeof(*get_resp));
+
+	if (unlikely(ret))
+		pr_err("Failed to get stats. error: %d\n", ret);
+
+	return ret;
+}
+
+int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
+				struct ena_admin_basic_stats *stats)
+{
+	struct ena_com_stats_ctx ctx;
+	int ret;
+
+	memset(&ctx, 0x0, sizeof(ctx));
+	ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_BASIC);
+	if (likely(ret == 0))
+		memcpy(stats, &ctx.get_resp.basic_stats,
+		       sizeof(ctx.get_resp.basic_stats));
+
+	return ret;
+}
+
+int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu)
+{
+	struct ena_com_admin_queue *admin_queue;
+	struct ena_admin_set_feat_cmd cmd;
+	struct ena_admin_set_feat_resp resp;
+	int ret;
+
+	if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) {
+		pr_debug("Feature %d isn't supported\n", ENA_ADMIN_MTU);
+		return -EOPNOTSUPP;
+	}
+
+	memset(&cmd, 0x0, sizeof(cmd));
+	admin_queue = &ena_dev->admin_queue;
+
+	cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+	cmd.aq_common_descriptor.flags = 0;
+	cmd.feat_common.feature_id = ENA_ADMIN_MTU;
+	cmd.u.mtu.mtu = mtu;
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&cmd,
+					    sizeof(cmd),
+					    (struct ena_admin_acq_entry *)&resp,
+					    sizeof(resp));
+
+	if (unlikely(ret))
+		pr_err("Failed to set mtu %d. error: %d\n", mtu, ret);
+
+	return ret;
+}
+
+int ena_com_get_offload_settings(struct ena_com_dev *ena_dev,
+				 struct ena_admin_feature_offload_desc *offload)
+{
+	int ret;
+	struct ena_admin_get_feat_resp resp;
+
+	ret = ena_com_get_feature(ena_dev, &resp,
+				  ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0);
+	if (unlikely(ret)) {
+		pr_err("Failed to get offload capabilities %d\n", ret);
+		return ret;
+	}
+
+	memcpy(offload, &resp.u.offload, sizeof(resp.u.offload));
+
+	return 0;
+}
+
+int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_set_feat_cmd cmd;
+	struct ena_admin_set_feat_resp resp;
+	struct ena_admin_get_feat_resp get_resp;
+	int ret;
+
+	if (!ena_com_check_supported_feature_id(ena_dev,
+						ENA_ADMIN_RSS_HASH_FUNCTION)) {
+		pr_debug("Feature %d isn't supported\n",
+			 ENA_ADMIN_RSS_HASH_FUNCTION);
+		return -EOPNOTSUPP;
+	}
+
+	/* Validate hash function is supported */
+	ret = ena_com_get_feature(ena_dev, &get_resp,
+				  ENA_ADMIN_RSS_HASH_FUNCTION, 0);
+	if (unlikely(ret))
+		return ret;
+
+	if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) {
+		pr_err("Func hash %d isn't supported by device, abort\n",
+		       rss->hash_func);
+		return -EOPNOTSUPP;
+	}
+
+	memset(&cmd, 0x0, sizeof(cmd));
+
+	cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+	cmd.aq_common_descriptor.flags =
+		ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK;
+	cmd.feat_common.feature_id = ENA_ADMIN_RSS_HASH_FUNCTION;
+	cmd.u.flow_hash_func.init_val = rss->hash_init_val;
+	cmd.u.flow_hash_func.selected_func = 1 << rss->hash_func;
+
+	ret = ena_com_mem_addr_set(ena_dev,
+				   &cmd.control_buffer.address,
+				   rss->hash_key_dma_addr);
+	if (unlikely(ret)) {
+		pr_err("memory address set failed\n");
+		return ret;
+	}
+
+	cmd.control_buffer.length = sizeof(*rss->hash_key);
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&cmd,
+					    sizeof(cmd),
+					    (struct ena_admin_acq_entry *)&resp,
+					    sizeof(resp));
+	if (unlikely(ret)) {
+		pr_err("Failed to set hash function %d. error: %d\n",
+		       rss->hash_func, ret);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int ena_com_fill_hash_function(struct ena_com_dev *ena_dev,
+			       enum ena_admin_hash_functions func,
+			       const u8 *key, u16 key_len, u32 init_val)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_get_feat_resp get_resp;
+	struct ena_admin_feature_rss_flow_hash_control *hash_key =
+		rss->hash_key;
+	int rc;
+
+	/* Make sure size is a mult of DWs */
+	if (unlikely(key_len & 0x3))
+		return -EINVAL;
+
+	rc = ena_com_get_feature_ex(ena_dev, &get_resp,
+				    ENA_ADMIN_RSS_HASH_FUNCTION,
+				    rss->hash_key_dma_addr,
+				    sizeof(*rss->hash_key), 0);
+	if (unlikely(rc))
+		return rc;
+
+	if (!((1 << func) & get_resp.u.flow_hash_func.supported_func)) {
+		pr_err("Flow hash function %d isn't supported\n", func);
+		return -EOPNOTSUPP;
+	}
+
+	switch (func) {
+	case ENA_ADMIN_TOEPLITZ:
+		if (key_len > sizeof(hash_key->key)) {
+			pr_err("key len (%hu) is bigger than the max supported (%zu)\n",
+			       key_len, sizeof(hash_key->key));
+			return -EINVAL;
+		}
+
+		memcpy(hash_key->key, key, key_len);
+		rss->hash_init_val = init_val;
+		hash_key->keys_num = key_len >> 2;
+		break;
+	case ENA_ADMIN_CRC32:
+		rss->hash_init_val = init_val;
+		break;
+	default:
+		pr_err("Invalid hash function (%d)\n", func);
+		return -EINVAL;
+	}
+
+	rss->hash_func = func;
+	rc = ena_com_set_hash_function(ena_dev);
+
+	/* Restore the old function */
+	if (unlikely(rc))
+		ena_com_get_hash_function(ena_dev, NULL, NULL);
+
+	return rc;
+}
+
+int ena_com_get_hash_function(struct ena_com_dev *ena_dev,
+			      enum ena_admin_hash_functions *func,
+			      u8 *key)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_get_feat_resp get_resp;
+	struct ena_admin_feature_rss_flow_hash_control *hash_key =
+		rss->hash_key;
+	int rc;
+
+	rc = ena_com_get_feature_ex(ena_dev, &get_resp,
+				    ENA_ADMIN_RSS_HASH_FUNCTION,
+				    rss->hash_key_dma_addr,
+				    sizeof(*rss->hash_key), 0);
+	if (unlikely(rc))
+		return rc;
+
+	rss->hash_func = get_resp.u.flow_hash_func.selected_func;
+	if (func)
+		*func = rss->hash_func;
+
+	if (key)
+		memcpy(key, hash_key->key, (size_t)(hash_key->keys_num) << 2);
+
+	return 0;
+}
+
+int ena_com_get_hash_ctrl(struct ena_com_dev *ena_dev,
+			  enum ena_admin_flow_hash_proto proto,
+			  u16 *fields)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_get_feat_resp get_resp;
+	int rc;
+
+	rc = ena_com_get_feature_ex(ena_dev, &get_resp,
+				    ENA_ADMIN_RSS_HASH_INPUT,
+				    rss->hash_ctrl_dma_addr,
+				    sizeof(*rss->hash_ctrl), 0);
+	if (unlikely(rc))
+		return rc;
+
+	if (fields)
+		*fields = rss->hash_ctrl->selected_fields[proto].fields;
+
+	return 0;
+}
+
+int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_feature_rss_hash_control *hash_ctrl = rss->hash_ctrl;
+	struct ena_admin_set_feat_cmd cmd;
+	struct ena_admin_set_feat_resp resp;
+	int ret;
+
+	if (!ena_com_check_supported_feature_id(ena_dev,
+						ENA_ADMIN_RSS_HASH_INPUT)) {
+		pr_debug("Feature %d isn't supported\n",
+			 ENA_ADMIN_RSS_HASH_INPUT);
+		return -EOPNOTSUPP;
+	}
+
+	memset(&cmd, 0x0, sizeof(cmd));
+
+	cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+	cmd.aq_common_descriptor.flags =
+		ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK;
+	cmd.feat_common.feature_id = ENA_ADMIN_RSS_HASH_INPUT;
+	cmd.u.flow_hash_input.enabled_input_sort =
+		ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK |
+		ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK;
+
+	ret = ena_com_mem_addr_set(ena_dev,
+				   &cmd.control_buffer.address,
+				   rss->hash_ctrl_dma_addr);
+	if (unlikely(ret)) {
+		pr_err("memory address set failed\n");
+		return ret;
+	}
+	cmd.control_buffer.length = sizeof(*hash_ctrl);
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&cmd,
+					    sizeof(cmd),
+					    (struct ena_admin_acq_entry *)&resp,
+					    sizeof(resp));
+	if (unlikely(ret))
+		pr_err("Failed to set hash input. error: %d\n", ret);
+
+	return ret;
+}
+
+int ena_com_set_default_hash_ctrl(struct ena_com_dev *ena_dev)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_feature_rss_hash_control *hash_ctrl =
+		rss->hash_ctrl;
+	u16 available_fields = 0;
+	int rc, i;
+
+	/* Get the supported hash input */
+	rc = ena_com_get_hash_ctrl(ena_dev, 0, NULL);
+	if (unlikely(rc))
+		return rc;
+
+	hash_ctrl->selected_fields[ENA_ADMIN_RSS_TCP4].fields =
+		ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA |
+		ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP;
+
+	hash_ctrl->selected_fields[ENA_ADMIN_RSS_UDP4].fields =
+		ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA |
+		ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP;
+
+	hash_ctrl->selected_fields[ENA_ADMIN_RSS_TCP6].fields =
+		ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA |
+		ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP;
+
+	hash_ctrl->selected_fields[ENA_ADMIN_RSS_UDP6].fields =
+		ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA |
+		ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP;
+
+	hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP4].fields =
+		ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA;
+
+	hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP6].fields =
+		ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA;
+
+	hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP4_FRAG].fields =
+		ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA;
+
+	hash_ctrl->selected_fields[ENA_ADMIN_RSS_NOT_IP].fields =
+		ENA_ADMIN_RSS_L2_DA | ENA_ADMIN_RSS_L2_SA;
+
+	for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; i++) {
+		available_fields = hash_ctrl->selected_fields[i].fields &
+				hash_ctrl->supported_fields[i].fields;
+		if (available_fields != hash_ctrl->selected_fields[i].fields) {
+			pr_err("hash control doesn't support all the desire configuration. proto %x supported %x selected %x\n",
+			       i, hash_ctrl->supported_fields[i].fields,
+			       hash_ctrl->selected_fields[i].fields);
+			return -EOPNOTSUPP;
+		}
+	}
+
+	rc = ena_com_set_hash_ctrl(ena_dev);
+
+	/* In case of failure, restore the old hash ctrl */
+	if (unlikely(rc))
+		ena_com_get_hash_ctrl(ena_dev, 0, NULL);
+
+	return rc;
+}
+
+int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev,
+			   enum ena_admin_flow_hash_proto proto,
+			   u16 hash_fields)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_feature_rss_hash_control *hash_ctrl = rss->hash_ctrl;
+	u16 supported_fields;
+	int rc;
+
+	if (proto >= ENA_ADMIN_RSS_PROTO_NUM) {
+		pr_err("Invalid proto num (%u)\n", proto);
+		return -EINVAL;
+	}
+
+	/* Get the ctrl table */
+	rc = ena_com_get_hash_ctrl(ena_dev, proto, NULL);
+	if (unlikely(rc))
+		return rc;
+
+	/* Make sure all the fields are supported */
+	supported_fields = hash_ctrl->supported_fields[proto].fields;
+	if ((hash_fields & supported_fields) != hash_fields) {
+		pr_err("proto %d doesn't support the required fields %x. supports only: %x\n",
+		       proto, hash_fields, supported_fields);
+	}
+
+	hash_ctrl->selected_fields[proto].fields = hash_fields;
+
+	rc = ena_com_set_hash_ctrl(ena_dev);
+
+	/* In case of failure, restore the old hash ctrl */
+	if (unlikely(rc))
+		ena_com_get_hash_ctrl(ena_dev, 0, NULL);
+
+	return 0;
+}
+
+int ena_com_indirect_table_fill_entry(struct ena_com_dev *ena_dev,
+				      u16 entry_idx, u16 entry_value)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+
+	if (unlikely(entry_idx >= (1 << rss->tbl_log_size)))
+		return -EINVAL;
+
+	if (unlikely((entry_value > ENA_TOTAL_NUM_QUEUES)))
+		return -EINVAL;
+
+	rss->host_rss_ind_tbl[entry_idx] = entry_value;
+
+	return 0;
+}
+
+int ena_com_indirect_table_set(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_set_feat_cmd cmd;
+	struct ena_admin_set_feat_resp resp;
+	int ret;
+
+	if (!ena_com_check_supported_feature_id(
+		    ena_dev, ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG)) {
+		pr_debug("Feature %d isn't supported\n",
+			 ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG);
+		return -EOPNOTSUPP;
+	}
+
+	ret = ena_com_ind_tbl_convert_to_device(ena_dev);
+	if (ret) {
+		pr_err("Failed to convert host indirection table to device table\n");
+		return ret;
+	}
+
+	memset(&cmd, 0x0, sizeof(cmd));
+
+	cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+	cmd.aq_common_descriptor.flags =
+		ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK;
+	cmd.feat_common.feature_id = ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG;
+	cmd.u.ind_table.size = rss->tbl_log_size;
+	cmd.u.ind_table.inline_index = 0xFFFFFFFF;
+
+	ret = ena_com_mem_addr_set(ena_dev,
+				   &cmd.control_buffer.address,
+				   rss->rss_ind_tbl_dma_addr);
+	if (unlikely(ret)) {
+		pr_err("memory address set failed\n");
+		return ret;
+	}
+
+	cmd.control_buffer.length = (1ULL << rss->tbl_log_size) *
+		sizeof(struct ena_admin_rss_ind_table_entry);
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&cmd,
+					    sizeof(cmd),
+					    (struct ena_admin_acq_entry *)&resp,
+					    sizeof(resp));
+
+	if (unlikely(ret))
+		pr_err("Failed to set indirect table. error: %d\n", ret);
+
+	return ret;
+}
+
+int ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl)
+{
+	struct ena_rss *rss = &ena_dev->rss;
+	struct ena_admin_get_feat_resp get_resp;
+	u32 tbl_size;
+	int i, rc;
+
+	tbl_size = (1ULL << rss->tbl_log_size) *
+		sizeof(struct ena_admin_rss_ind_table_entry);
+
+	rc = ena_com_get_feature_ex(ena_dev, &get_resp,
+				    ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG,
+				    rss->rss_ind_tbl_dma_addr,
+				    tbl_size, 0);
+	if (unlikely(rc))
+		return rc;
+
+	if (!ind_tbl)
+		return 0;
+
+	rc = ena_com_ind_tbl_convert_from_device(ena_dev);
+	if (unlikely(rc))
+		return rc;
+
+	for (i = 0; i < (1 << rss->tbl_log_size); i++)
+		ind_tbl[i] = rss->host_rss_ind_tbl[i];
+
+	return 0;
+}
+
+int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 indr_tbl_log_size)
+{
+	int rc;
+
+	memset(&ena_dev->rss, 0x0, sizeof(ena_dev->rss));
+
+	rc = ena_com_indirect_table_allocate(ena_dev, indr_tbl_log_size);
+	if (unlikely(rc))
+		goto err_indr_tbl;
+
+	rc = ena_com_hash_key_allocate(ena_dev);
+	if (unlikely(rc))
+		goto err_hash_key;
+
+	rc = ena_com_hash_ctrl_init(ena_dev);
+	if (unlikely(rc))
+		goto err_hash_ctrl;
+
+	return 0;
+
+err_hash_ctrl:
+	ena_com_hash_key_destroy(ena_dev);
+err_hash_key:
+	ena_com_indirect_table_destroy(ena_dev);
+err_indr_tbl:
+
+	return rc;
+}
+
+void ena_com_rss_destroy(struct ena_com_dev *ena_dev)
+{
+	ena_com_indirect_table_destroy(ena_dev);
+	ena_com_hash_key_destroy(ena_dev);
+	ena_com_hash_ctrl_destroy(ena_dev);
+
+	memset(&ena_dev->rss, 0x0, sizeof(ena_dev->rss));
+}
+
+int ena_com_allocate_host_info(struct ena_com_dev *ena_dev)
+{
+	struct ena_host_attribute *host_attr = &ena_dev->host_attr;
+
+	host_attr->host_info =
+		dma_zalloc_coherent(ena_dev->dmadev, SZ_4K,
+				    &host_attr->host_info_dma_addr, GFP_KERNEL);
+	if (unlikely(!host_attr->host_info))
+		return -ENOMEM;
+
+	host_attr->host_info->ena_spec_version = ((ENA_COMMON_SPEC_VERSION_MAJOR <<
+		ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) |
+		(ENA_COMMON_SPEC_VERSION_MINOR));
+
+	return 0;
+}
+
+int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev,
+				u32 debug_area_size)
+{
+	struct ena_host_attribute *host_attr = &ena_dev->host_attr;
+
+	host_attr->debug_area_virt_addr =
+		dma_zalloc_coherent(ena_dev->dmadev, debug_area_size,
+				    &host_attr->debug_area_dma_addr, GFP_KERNEL);
+	if (unlikely(!host_attr->debug_area_virt_addr)) {
+		host_attr->debug_area_size = 0;
+		return -ENOMEM;
+	}
+
+	host_attr->debug_area_size = debug_area_size;
+
+	return 0;
+}
+
+void ena_com_delete_host_info(struct ena_com_dev *ena_dev)
+{
+	struct ena_host_attribute *host_attr = &ena_dev->host_attr;
+
+	if (host_attr->host_info) {
+		dma_free_coherent(ena_dev->dmadev, SZ_4K, host_attr->host_info,
+				  host_attr->host_info_dma_addr);
+		host_attr->host_info = NULL;
+	}
+}
+
+void ena_com_delete_debug_area(struct ena_com_dev *ena_dev)
+{
+	struct ena_host_attribute *host_attr = &ena_dev->host_attr;
+
+	if (host_attr->debug_area_virt_addr) {
+		dma_free_coherent(ena_dev->dmadev, host_attr->debug_area_size,
+				  host_attr->debug_area_virt_addr,
+				  host_attr->debug_area_dma_addr);
+		host_attr->debug_area_virt_addr = NULL;
+	}
+}
+
+int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
+{
+	struct ena_host_attribute *host_attr = &ena_dev->host_attr;
+	struct ena_com_admin_queue *admin_queue;
+	struct ena_admin_set_feat_cmd cmd;
+	struct ena_admin_set_feat_resp resp;
+
+	int ret;
+
+	/* Host attribute config is called before ena_com_get_dev_attr_feat
+	 * so ena_com can't check if the feature is supported.
+	 */
+
+	memset(&cmd, 0x0, sizeof(cmd));
+	admin_queue = &ena_dev->admin_queue;
+
+	cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+	cmd.feat_common.feature_id = ENA_ADMIN_HOST_ATTR_CONFIG;
+
+	ret = ena_com_mem_addr_set(ena_dev,
+				   &cmd.u.host_attr.debug_ba,
+				   host_attr->debug_area_dma_addr);
+	if (unlikely(ret)) {
+		pr_err("memory address set failed\n");
+		return ret;
+	}
+
+	ret = ena_com_mem_addr_set(ena_dev,
+				   &cmd.u.host_attr.os_info_ba,
+				   host_attr->host_info_dma_addr);
+	if (unlikely(ret)) {
+		pr_err("memory address set failed\n");
+		return ret;
+	}
+
+	cmd.u.host_attr.debug_area_size = host_attr->debug_area_size;
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)&cmd,
+					    sizeof(cmd),
+					    (struct ena_admin_acq_entry *)&resp,
+					    sizeof(resp));
+
+	if (unlikely(ret))
+		pr_err("Failed to set host attributes: %d\n", ret);
+
+	return ret;
+}
+
+/* Interrupt moderation */
+bool ena_com_interrupt_moderation_supported(struct ena_com_dev *ena_dev)
+{
+	return ena_com_check_supported_feature_id(ena_dev,
+						  ENA_ADMIN_INTERRUPT_MODERATION);
+}
+
+static int ena_com_update_nonadaptive_moderation_interval(u32 coalesce_usecs,
+							  u32 intr_delay_resolution,
+							  u32 *intr_moder_interval)
+{
+	if (!intr_delay_resolution) {
+		pr_err("Illegal interrupt delay granularity value\n");
+		return -EFAULT;
+	}
+
+	*intr_moder_interval = coalesce_usecs / intr_delay_resolution;
+
+	return 0;
+}
+
+int ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev,
+						      u32 tx_coalesce_usecs)
+{
+	return ena_com_update_nonadaptive_moderation_interval(tx_coalesce_usecs,
+							      ena_dev->intr_delay_resolution,
+							      &ena_dev->intr_moder_tx_interval);
+}
+
+int ena_com_update_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev,
+						      u32 rx_coalesce_usecs)
+{
+	return ena_com_update_nonadaptive_moderation_interval(rx_coalesce_usecs,
+							      ena_dev->intr_delay_resolution,
+							      &ena_dev->intr_moder_rx_interval);
+}
+
+int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev)
+{
+	struct ena_admin_get_feat_resp get_resp;
+	u16 delay_resolution;
+	int rc;
+
+	rc = ena_com_get_feature(ena_dev, &get_resp,
+				 ENA_ADMIN_INTERRUPT_MODERATION, 0);
+
+	if (rc) {
+		if (rc == -EOPNOTSUPP) {
+			pr_debug("Feature %d isn't supported\n",
+				 ENA_ADMIN_INTERRUPT_MODERATION);
+			rc = 0;
+		} else {
+			pr_err("Failed to get interrupt moderation admin cmd. rc: %d\n",
+			       rc);
+		}
+
+		/* no moderation supported, disable adaptive support */
+		ena_com_disable_adaptive_moderation(ena_dev);
+		return rc;
+	}
+
+	/* if moderation is supported by device we set adaptive moderation */
+	delay_resolution = get_resp.u.intr_moderation.intr_delay_resolution;
+	ena_com_update_intr_delay_resolution(ena_dev, delay_resolution);
+
+	/* Disable adaptive moderation by default - can be enabled later */
+	ena_com_disable_adaptive_moderation(ena_dev);
+
+	return 0;
+}
+
+unsigned int ena_com_get_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev)
+{
+	return ena_dev->intr_moder_tx_interval;
+}
+
+unsigned int ena_com_get_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev)
+{
+	return ena_dev->intr_moder_rx_interval;
+}
+
+int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
+			    struct ena_admin_feature_llq_desc *llq_features,
+			    struct ena_llq_configurations *llq_default_cfg)
+{
+	struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
+	int rc;
+
+	if (!llq_features->max_llq_num) {
+		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+		return 0;
+	}
+
+	rc = ena_com_config_llq_info(ena_dev, llq_features, llq_default_cfg);
+	if (rc)
+		return rc;
+
+	ena_dev->tx_max_header_size = llq_info->desc_list_entry_size -
+		(llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc));
+
+	if (unlikely(ena_dev->tx_max_header_size == 0)) {
+		pr_err("the size of the LLQ entry is smaller than needed\n");
+		return -EINVAL;
+	}
+
+	ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV;
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_com.h
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_com.h
@@ -0,0 +1,995 @@
+/*
+ * Copyright 2015 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef ENA_COM
+#define ENA_COM
+
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/prefetch.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include "ena_common_defs.h"
+#include "ena_admin_defs.h"
+#include "ena_eth_io_defs.h"
+#include "ena_regs_defs.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define ENA_MAX_NUM_IO_QUEUES		128U
+/* We need to queues for each IO (on for Tx and one for Rx) */
+#define ENA_TOTAL_NUM_QUEUES		(2 * (ENA_MAX_NUM_IO_QUEUES))
+
+#define ENA_MAX_HANDLERS 256
+
+#define ENA_MAX_PHYS_ADDR_SIZE_BITS 48
+
+/* Unit in usec */
+#define ENA_REG_READ_TIMEOUT 200000
+
+#define ADMIN_SQ_SIZE(depth)	((depth) * sizeof(struct ena_admin_aq_entry))
+#define ADMIN_CQ_SIZE(depth)	((depth) * sizeof(struct ena_admin_acq_entry))
+#define ADMIN_AENQ_SIZE(depth)	((depth) * sizeof(struct ena_admin_aenq_entry))
+
+/*****************************************************************************/
+/*****************************************************************************/
+/* ENA adaptive interrupt moderation settings */
+
+#define ENA_INTR_INITIAL_TX_INTERVAL_USECS		0
+#define ENA_INTR_INITIAL_RX_INTERVAL_USECS		0
+#define ENA_DEFAULT_INTR_DELAY_RESOLUTION		1
+
+#define ENA_HW_HINTS_NO_TIMEOUT				0xFFFF
+
+#define ENA_FEATURE_MAX_QUEUE_EXT_VER	1
+
+struct ena_llq_configurations {
+	enum ena_admin_llq_header_location llq_header_location;
+	enum ena_admin_llq_ring_entry_size llq_ring_entry_size;
+	enum ena_admin_llq_stride_ctrl  llq_stride_ctrl;
+	enum ena_admin_llq_num_descs_before_header llq_num_decs_before_header;
+	u16 llq_ring_entry_size_value;
+};
+
+enum queue_direction {
+	ENA_COM_IO_QUEUE_DIRECTION_TX,
+	ENA_COM_IO_QUEUE_DIRECTION_RX
+};
+
+struct ena_com_buf {
+	dma_addr_t paddr; /**< Buffer physical address */
+	u16 len; /**< Buffer length in bytes */
+};
+
+struct ena_com_rx_buf_info {
+	u16 len;
+	u16 req_id;
+};
+
+struct ena_com_io_desc_addr {
+	u8 __iomem *pbuf_dev_addr; /* LLQ address */
+	u8 *virt_addr;
+	dma_addr_t phys_addr;
+};
+
+struct ena_com_tx_meta {
+	u16 mss;
+	u16 l3_hdr_len;
+	u16 l3_hdr_offset;
+	u16 l4_hdr_len; /* In words */
+};
+
+struct ena_com_llq_info {
+	u16 header_location_ctrl;
+	u16 desc_stride_ctrl;
+	u16 desc_list_entry_size_ctrl;
+	u16 desc_list_entry_size;
+	u16 descs_num_before_header;
+	u16 descs_per_entry;
+	u16 max_entries_in_tx_burst;
+};
+
+struct ena_com_io_cq {
+	struct ena_com_io_desc_addr cdesc_addr;
+
+	/* Interrupt unmask register */
+	u32 __iomem *unmask_reg;
+
+	/* The completion queue head doorbell register */
+	u32 __iomem *cq_head_db_reg;
+
+	/* numa configuration register (for TPH) */
+	u32 __iomem *numa_node_cfg_reg;
+
+	/* The value to write to the above register to unmask
+	 * the interrupt of this queue
+	 */
+	u32 msix_vector;
+
+	enum queue_direction direction;
+
+	/* holds the number of cdesc of the current packet */
+	u16 cur_rx_pkt_cdesc_count;
+	/* save the firt cdesc idx of the current packet */
+	u16 cur_rx_pkt_cdesc_start_idx;
+
+	u16 q_depth;
+	/* Caller qid */
+	u16 qid;
+
+	/* Device queue index */
+	u16 idx;
+	u16 head;
+	u16 last_head_update;
+	u8 phase;
+	u8 cdesc_entry_size_in_bytes;
+
+} ____cacheline_aligned;
+
+struct ena_com_io_bounce_buffer_control {
+	u8 *base_buffer;
+	u16 next_to_use;
+	u16 buffer_size;
+	u16 buffers_num;  /* Must be a power of 2 */
+};
+
+/* This struct is to keep tracking the current location of the next llq entry */
+struct ena_com_llq_pkt_ctrl {
+	u8 *curr_bounce_buf;
+	u16 idx;
+	u16 descs_left_in_line;
+};
+
+struct ena_com_io_sq {
+	struct ena_com_io_desc_addr desc_addr;
+
+	u32 __iomem *db_addr;
+	u8 __iomem *header_addr;
+
+	enum queue_direction direction;
+	enum ena_admin_placement_policy_type mem_queue_type;
+
+	u32 msix_vector;
+	struct ena_com_tx_meta cached_tx_meta;
+	struct ena_com_llq_info llq_info;
+	struct ena_com_llq_pkt_ctrl llq_buf_ctrl;
+	struct ena_com_io_bounce_buffer_control bounce_buf_ctrl;
+
+	u16 q_depth;
+	u16 qid;
+
+	u16 idx;
+	u16 tail;
+	u16 next_to_comp;
+	u16 llq_last_copy_tail;
+	u32 tx_max_header_size;
+	u8 phase;
+	u8 desc_entry_size;
+	u8 dma_addr_bits;
+	u16 entries_in_tx_burst_left;
+} ____cacheline_aligned;
+
+struct ena_com_admin_cq {
+	struct ena_admin_acq_entry *entries;
+	dma_addr_t dma_addr;
+
+	u16 head;
+	u8 phase;
+};
+
+struct ena_com_admin_sq {
+	struct ena_admin_aq_entry *entries;
+	dma_addr_t dma_addr;
+
+	u32 __iomem *db_addr;
+
+	u16 head;
+	u16 tail;
+	u8 phase;
+
+};
+
+struct ena_com_stats_admin {
+	u32 aborted_cmd;
+	u32 submitted_cmd;
+	u32 completed_cmd;
+	u32 out_of_space;
+	u32 no_completion;
+};
+
+struct ena_com_admin_queue {
+	void *q_dmadev;
+	spinlock_t q_lock; /* spinlock for the admin queue */
+
+	struct ena_comp_ctx *comp_ctx;
+	u32 completion_timeout;
+	u16 q_depth;
+	struct ena_com_admin_cq cq;
+	struct ena_com_admin_sq sq;
+
+	/* Indicate if the admin queue should poll for completion */
+	bool polling;
+
+	/* Define if fallback to polling mode should occur */
+	bool auto_polling;
+
+	u16 curr_cmd_id;
+
+	/* Indicate that the ena was initialized and can
+	 * process new admin commands
+	 */
+	bool running_state;
+
+	/* Count the number of outstanding admin commands */
+	atomic_t outstanding_cmds;
+
+	struct ena_com_stats_admin stats;
+};
+
+struct ena_aenq_handlers;
+
+struct ena_com_aenq {
+	u16 head;
+	u8 phase;
+	struct ena_admin_aenq_entry *entries;
+	dma_addr_t dma_addr;
+	u16 q_depth;
+	struct ena_aenq_handlers *aenq_handlers;
+};
+
+struct ena_com_mmio_read {
+	struct ena_admin_ena_mmio_req_read_less_resp *read_resp;
+	dma_addr_t read_resp_dma_addr;
+	u32 reg_read_to; /* in us */
+	u16 seq_num;
+	bool readless_supported;
+	/* spin lock to ensure a single outstanding read */
+	spinlock_t lock;
+};
+
+struct ena_rss {
+	/* Indirect table */
+	u16 *host_rss_ind_tbl;
+	struct ena_admin_rss_ind_table_entry *rss_ind_tbl;
+	dma_addr_t rss_ind_tbl_dma_addr;
+	u16 tbl_log_size;
+
+	/* Hash key */
+	enum ena_admin_hash_functions hash_func;
+	struct ena_admin_feature_rss_flow_hash_control *hash_key;
+	dma_addr_t hash_key_dma_addr;
+	u32 hash_init_val;
+
+	/* Flow Control */
+	struct ena_admin_feature_rss_hash_control *hash_ctrl;
+	dma_addr_t hash_ctrl_dma_addr;
+
+};
+
+struct ena_host_attribute {
+	/* Debug area */
+	u8 *debug_area_virt_addr;
+	dma_addr_t debug_area_dma_addr;
+	u32 debug_area_size;
+
+	/* Host information */
+	struct ena_admin_host_info *host_info;
+	dma_addr_t host_info_dma_addr;
+};
+
+/* Each ena_dev is a PCI function. */
+struct ena_com_dev {
+	struct ena_com_admin_queue admin_queue;
+	struct ena_com_aenq aenq;
+	struct ena_com_io_cq io_cq_queues[ENA_TOTAL_NUM_QUEUES];
+	struct ena_com_io_sq io_sq_queues[ENA_TOTAL_NUM_QUEUES];
+	u8 __iomem *reg_bar;
+	void __iomem *mem_bar;
+	void *dmadev;
+
+	enum ena_admin_placement_policy_type tx_mem_queue_type;
+	u32 tx_max_header_size;
+	u16 stats_func; /* Selected function for extended statistic dump */
+	u16 stats_queue; /* Selected queue for extended statistic dump */
+
+	struct ena_com_mmio_read mmio_read;
+
+	struct ena_rss rss;
+	u32 supported_features;
+	u32 dma_addr_bits;
+
+	struct ena_host_attribute host_attr;
+	bool adaptive_coalescing;
+	u16 intr_delay_resolution;
+
+	/* interrupt moderation intervals are in usec divided by
+	 * intr_delay_resolution, which is supplied by the device.
+	 */
+	u32 intr_moder_tx_interval;
+	u32 intr_moder_rx_interval;
+
+	struct ena_intr_moder_entry *intr_moder_tbl;
+
+	struct ena_com_llq_info llq_info;
+};
+
+struct ena_com_dev_get_features_ctx {
+	struct ena_admin_queue_feature_desc max_queues;
+	struct ena_admin_queue_ext_feature_desc max_queue_ext;
+	struct ena_admin_device_attr_feature_desc dev_attr;
+	struct ena_admin_feature_aenq_desc aenq;
+	struct ena_admin_feature_offload_desc offload;
+	struct ena_admin_ena_hw_hints hw_hints;
+	struct ena_admin_feature_llq_desc llq;
+};
+
+struct ena_com_create_io_ctx {
+	enum ena_admin_placement_policy_type mem_queue_type;
+	enum queue_direction direction;
+	int numa_node;
+	u32 msix_vector;
+	u16 queue_size;
+	u16 qid;
+};
+
+typedef void (*ena_aenq_handler)(void *data,
+	struct ena_admin_aenq_entry *aenq_e);
+
+/* Holds aenq handlers. Indexed by AENQ event group */
+struct ena_aenq_handlers {
+	ena_aenq_handler handlers[ENA_MAX_HANDLERS];
+	ena_aenq_handler unimplemented_handler;
+};
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+/* ena_com_mmio_reg_read_request_init - Init the mmio reg read mechanism
+ * @ena_dev: ENA communication layer struct
+ *
+ * Initialize the register read mechanism.
+ *
+ * @note: This method must be the first stage in the initialization sequence.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev);
+
+/* ena_com_set_mmio_read_mode - Enable/disable the mmio reg read mechanism
+ * @ena_dev: ENA communication layer struct
+ * @readless_supported: readless mode (enable/disable)
+ */
+void ena_com_set_mmio_read_mode(struct ena_com_dev *ena_dev,
+				bool readless_supported);
+
+/* ena_com_mmio_reg_read_request_write_dev_addr - Write the mmio reg read return
+ * value physical address.
+ * @ena_dev: ENA communication layer struct
+ */
+void ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev *ena_dev);
+
+/* ena_com_mmio_reg_read_request_destroy - Destroy the mmio reg read mechanism
+ * @ena_dev: ENA communication layer struct
+ */
+void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev);
+
+/* ena_com_admin_init - Init the admin and the async queues
+ * @ena_dev: ENA communication layer struct
+ * @aenq_handlers: Those handlers to be called upon event.
+ *
+ * Initialize the admin submission and completion queues.
+ * Initialize the asynchronous events notification queues.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_admin_init(struct ena_com_dev *ena_dev,
+		       struct ena_aenq_handlers *aenq_handlers);
+
+/* ena_com_admin_destroy - Destroy the admin and the async events queues.
+ * @ena_dev: ENA communication layer struct
+ *
+ * @note: Before calling this method, the caller must validate that the device
+ * won't send any additional admin completions/aenq.
+ * To achieve that, a FLR is recommended.
+ */
+void ena_com_admin_destroy(struct ena_com_dev *ena_dev);
+
+/* ena_com_dev_reset - Perform device FLR to the device.
+ * @ena_dev: ENA communication layer struct
+ * @reset_reason: Specify what is the trigger for the reset in case of an error.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_dev_reset(struct ena_com_dev *ena_dev,
+		      enum ena_regs_reset_reason_types reset_reason);
+
+/* ena_com_create_io_queue - Create io queue.
+ * @ena_dev: ENA communication layer struct
+ * @ctx - create context structure
+ *
+ * Create the submission and the completion queues.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_create_io_queue(struct ena_com_dev *ena_dev,
+			    struct ena_com_create_io_ctx *ctx);
+
+/* ena_com_destroy_io_queue - Destroy IO queue with the queue id - qid.
+ * @ena_dev: ENA communication layer struct
+ * @qid - the caller virtual queue id.
+ */
+void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid);
+
+/* ena_com_get_io_handlers - Return the io queue handlers
+ * @ena_dev: ENA communication layer struct
+ * @qid - the caller virtual queue id.
+ * @io_sq - IO submission queue handler
+ * @io_cq - IO completion queue handler.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid,
+			    struct ena_com_io_sq **io_sq,
+			    struct ena_com_io_cq **io_cq);
+
+/* ena_com_admin_aenq_enable - ENAble asynchronous event notifications
+ * @ena_dev: ENA communication layer struct
+ *
+ * After this method, aenq event can be received via AENQ.
+ */
+void ena_com_admin_aenq_enable(struct ena_com_dev *ena_dev);
+
+/* ena_com_set_admin_running_state - Set the state of the admin queue
+ * @ena_dev: ENA communication layer struct
+ *
+ * Change the state of the admin queue (enable/disable)
+ */
+void ena_com_set_admin_running_state(struct ena_com_dev *ena_dev, bool state);
+
+/* ena_com_get_admin_running_state - Get the admin queue state
+ * @ena_dev: ENA communication layer struct
+ *
+ * Retrieve the state of the admin queue (enable/disable)
+ *
+ * @return - current polling mode (enable/disable)
+ */
+bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev);
+
+/* ena_com_set_admin_polling_mode - Set the admin completion queue polling mode
+ * @ena_dev: ENA communication layer struct
+ * @polling: ENAble/Disable polling mode
+ *
+ * Set the admin completion mode.
+ */
+void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling);
+
+/* ena_com_set_admin_polling_mode - Get the admin completion queue polling mode
+ * @ena_dev: ENA communication layer struct
+ *
+ * Get the admin completion mode.
+ * If polling mode is on, ena_com_execute_admin_command will perform a
+ * polling on the admin completion queue for the commands completion,
+ * otherwise it will wait on wait event.
+ *
+ * @return state
+ */
+bool ena_com_get_ena_admin_polling_mode(struct ena_com_dev *ena_dev);
+
+/* ena_com_set_admin_auto_polling_mode - Enable autoswitch to polling mode
+ * @ena_dev: ENA communication layer struct
+ * @polling: Enable/Disable polling mode
+ *
+ * Set the autopolling mode.
+ * If autopolling is on:
+ * In case of missing interrupt when data is available switch to polling.
+ */
+void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev,
+					 bool polling);
+
+/* ena_com_admin_q_comp_intr_handler - admin queue interrupt handler
+ * @ena_dev: ENA communication layer struct
+ *
+ * This method go over the admin completion queue and wake up all the pending
+ * threads that wait on the commands wait event.
+ *
+ * @note: Should be called after MSI-X interrupt.
+ */
+void ena_com_admin_q_comp_intr_handler(struct ena_com_dev *ena_dev);
+
+/* ena_com_aenq_intr_handler - AENQ interrupt handler
+ * @ena_dev: ENA communication layer struct
+ *
+ * This method go over the async event notification queue and call the proper
+ * aenq handler.
+ */
+void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data);
+
+/* ena_com_abort_admin_commands - Abort all the outstanding admin commands.
+ * @ena_dev: ENA communication layer struct
+ *
+ * This method aborts all the outstanding admin commands.
+ * The caller should then call ena_com_wait_for_abort_completion to make sure
+ * all the commands were completed.
+ */
+void ena_com_abort_admin_commands(struct ena_com_dev *ena_dev);
+
+/* ena_com_wait_for_abort_completion - Wait for admin commands abort.
+ * @ena_dev: ENA communication layer struct
+ *
+ * This method wait until all the outstanding admin commands will be completed.
+ */
+void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev);
+
+/* ena_com_validate_version - Validate the device parameters
+ * @ena_dev: ENA communication layer struct
+ *
+ * This method validate the device parameters are the same as the saved
+ * parameters in ena_dev.
+ * This method is useful after device reset, to validate the device mac address
+ * and the device offloads are the same as before the reset.
+ *
+ * @return - 0 on success negative value otherwise.
+ */
+int ena_com_validate_version(struct ena_com_dev *ena_dev);
+
+/* ena_com_get_link_params - Retrieve physical link parameters.
+ * @ena_dev: ENA communication layer struct
+ * @resp: Link parameters
+ *
+ * Retrieve the physical link parameters,
+ * like speed, auto-negotiation and full duplex support.
+ *
+ * @return - 0 on Success negative value otherwise.
+ */
+int ena_com_get_link_params(struct ena_com_dev *ena_dev,
+			    struct ena_admin_get_feat_resp *resp);
+
+/* ena_com_get_dma_width - Retrieve physical dma address width the device
+ * supports.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Retrieve the maximum physical address bits the device can handle.
+ *
+ * @return: > 0 on Success and negative value otherwise.
+ */
+int ena_com_get_dma_width(struct ena_com_dev *ena_dev);
+
+/* ena_com_set_aenq_config - Set aenq groups configurations
+ * @ena_dev: ENA communication layer struct
+ * @groups flag: bit fields flags of enum ena_admin_aenq_group.
+ *
+ * Configure which aenq event group the driver would like to receive.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag);
+
+/* ena_com_get_dev_attr_feat - Get device features
+ * @ena_dev: ENA communication layer struct
+ * @get_feat_ctx: returned context that contain the get features.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
+			      struct ena_com_dev_get_features_ctx *get_feat_ctx);
+
+/* ena_com_get_dev_basic_stats - Get device basic statistics
+ * @ena_dev: ENA communication layer struct
+ * @stats: stats return value
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
+				struct ena_admin_basic_stats *stats);
+
+/* ena_com_set_dev_mtu - Configure the device mtu.
+ * @ena_dev: ENA communication layer struct
+ * @mtu: mtu value
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu);
+
+/* ena_com_get_offload_settings - Retrieve the device offloads capabilities
+ * @ena_dev: ENA communication layer struct
+ * @offlad: offload return value
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_offload_settings(struct ena_com_dev *ena_dev,
+				 struct ena_admin_feature_offload_desc *offload);
+
+/* ena_com_rss_init - Init RSS
+ * @ena_dev: ENA communication layer struct
+ * @log_size: indirection log size
+ *
+ * Allocate RSS/RFS resources.
+ * The caller then can configure rss using ena_com_set_hash_function,
+ * ena_com_set_hash_ctrl and ena_com_indirect_table_set.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 log_size);
+
+/* ena_com_rss_destroy - Destroy rss
+ * @ena_dev: ENA communication layer struct
+ *
+ * Free all the RSS/RFS resources.
+ */
+void ena_com_rss_destroy(struct ena_com_dev *ena_dev);
+
+/* ena_com_fill_hash_function - Fill RSS hash function
+ * @ena_dev: ENA communication layer struct
+ * @func: The hash function (Toeplitz or crc)
+ * @key: Hash key (for toeplitz hash)
+ * @key_len: key length (max length 10 DW)
+ * @init_val: initial value for the hash function
+ *
+ * Fill the ena_dev resources with the desire hash function, hash key, key_len
+ * and key initial value (if needed by the hash function).
+ * To flush the key into the device the caller should call
+ * ena_com_set_hash_function.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_fill_hash_function(struct ena_com_dev *ena_dev,
+			       enum ena_admin_hash_functions func,
+			       const u8 *key, u16 key_len, u32 init_val);
+
+/* ena_com_set_hash_function - Flush the hash function and it dependencies to
+ * the device.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Flush the hash function and it dependencies (key, key length and
+ * initial value) if needed.
+ *
+ * @note: Prior to this method the caller should call ena_com_fill_hash_function
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_set_hash_function(struct ena_com_dev *ena_dev);
+
+/* ena_com_get_hash_function - Retrieve the hash function and the hash key
+ * from the device.
+ * @ena_dev: ENA communication layer struct
+ * @func: hash function
+ * @key: hash key
+ *
+ * Retrieve the hash function and the hash key from the device.
+ *
+ * @note: If the caller called ena_com_fill_hash_function but didn't flash
+ * it to the device, the new configuration will be lost.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_hash_function(struct ena_com_dev *ena_dev,
+			      enum ena_admin_hash_functions *func,
+			      u8 *key);
+
+/* ena_com_fill_hash_ctrl - Fill RSS hash control
+ * @ena_dev: ENA communication layer struct.
+ * @proto: The protocol to configure.
+ * @hash_fields: bit mask of ena_admin_flow_hash_fields
+ *
+ * Fill the ena_dev resources with the desire hash control (the ethernet
+ * fields that take part of the hash) for a specific protocol.
+ * To flush the hash control to the device, the caller should call
+ * ena_com_set_hash_ctrl.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev,
+			   enum ena_admin_flow_hash_proto proto,
+			   u16 hash_fields);
+
+/* ena_com_set_hash_ctrl - Flush the hash control resources to the device.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Flush the hash control (the ethernet fields that take part of the hash)
+ *
+ * @note: Prior to this method the caller should call ena_com_fill_hash_ctrl.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev);
+
+/* ena_com_get_hash_ctrl - Retrieve the hash control from the device.
+ * @ena_dev: ENA communication layer struct
+ * @proto: The protocol to retrieve.
+ * @fields: bit mask of ena_admin_flow_hash_fields.
+ *
+ * Retrieve the hash control from the device.
+ *
+ * @note, If the caller called ena_com_fill_hash_ctrl but didn't flash
+ * it to the device, the new configuration will be lost.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_hash_ctrl(struct ena_com_dev *ena_dev,
+			  enum ena_admin_flow_hash_proto proto,
+			  u16 *fields);
+
+/* ena_com_set_default_hash_ctrl - Set the hash control to a default
+ * configuration.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Fill the ena_dev resources with the default hash control configuration.
+ * To flush the hash control to the device, the caller should call
+ * ena_com_set_hash_ctrl.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_set_default_hash_ctrl(struct ena_com_dev *ena_dev);
+
+/* ena_com_indirect_table_fill_entry - Fill a single entry in the RSS
+ * indirection table
+ * @ena_dev: ENA communication layer struct.
+ * @entry_idx - indirection table entry.
+ * @entry_value - redirection value
+ *
+ * Fill a single entry of the RSS indirection table in the ena_dev resources.
+ * To flush the indirection table to the device, the called should call
+ * ena_com_indirect_table_set.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_indirect_table_fill_entry(struct ena_com_dev *ena_dev,
+				      u16 entry_idx, u16 entry_value);
+
+/* ena_com_indirect_table_set - Flush the indirection table to the device.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Flush the indirection hash control to the device.
+ * Prior to this method the caller should call ena_com_indirect_table_fill_entry
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_indirect_table_set(struct ena_com_dev *ena_dev);
+
+/* ena_com_indirect_table_get - Retrieve the indirection table from the device.
+ * @ena_dev: ENA communication layer struct
+ * @ind_tbl: indirection table
+ *
+ * Retrieve the RSS indirection table from the device.
+ *
+ * @note: If the caller called ena_com_indirect_table_fill_entry but didn't flash
+ * it to the device, the new configuration will be lost.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl);
+
+/* ena_com_allocate_host_info - Allocate host info resources.
+ * @ena_dev: ENA communication layer struct
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_allocate_host_info(struct ena_com_dev *ena_dev);
+
+/* ena_com_allocate_debug_area - Allocate debug area.
+ * @ena_dev: ENA communication layer struct
+ * @debug_area_size - debug area size.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev,
+				u32 debug_area_size);
+
+/* ena_com_delete_debug_area - Free the debug area resources.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Free the allocate debug area.
+ */
+void ena_com_delete_debug_area(struct ena_com_dev *ena_dev);
+
+/* ena_com_delete_host_info - Free the host info resources.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Free the allocate host info.
+ */
+void ena_com_delete_host_info(struct ena_com_dev *ena_dev);
+
+/* ena_com_set_host_attributes - Update the device with the host
+ * attributes (debug area and host info) base address.
+ * @ena_dev: ENA communication layer struct
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_set_host_attributes(struct ena_com_dev *ena_dev);
+
+/* ena_com_create_io_cq - Create io completion queue.
+ * @ena_dev: ENA communication layer struct
+ * @io_cq - io completion queue handler
+
+ * Create IO completion queue.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_create_io_cq(struct ena_com_dev *ena_dev,
+			 struct ena_com_io_cq *io_cq);
+
+/* ena_com_destroy_io_cq - Destroy io completion queue.
+ * @ena_dev: ENA communication layer struct
+ * @io_cq - io completion queue handler
+
+ * Destroy IO completion queue.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev,
+			  struct ena_com_io_cq *io_cq);
+
+/* ena_com_execute_admin_command - Execute admin command
+ * @admin_queue: admin queue.
+ * @cmd: the admin command to execute.
+ * @cmd_size: the command size.
+ * @cmd_completion: command completion return value.
+ * @cmd_comp_size: command completion size.
+
+ * Submit an admin command and then wait until the device will return a
+ * completion.
+ * The completion will be copyed into cmd_comp.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue,
+				  struct ena_admin_aq_entry *cmd,
+				  size_t cmd_size,
+				  struct ena_admin_acq_entry *cmd_comp,
+				  size_t cmd_comp_size);
+
+/* ena_com_init_interrupt_moderation - Init interrupt moderation
+ * @ena_dev: ENA communication layer struct
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev);
+
+/* ena_com_interrupt_moderation_supported - Return if interrupt moderation
+ * capability is supported by the device.
+ *
+ * @return - supported or not.
+ */
+bool ena_com_interrupt_moderation_supported(struct ena_com_dev *ena_dev);
+
+/* ena_com_update_nonadaptive_moderation_interval_tx - Update the
+ * non-adaptive interval in Tx direction.
+ * @ena_dev: ENA communication layer struct
+ * @tx_coalesce_usecs: Interval in usec.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev,
+						      u32 tx_coalesce_usecs);
+
+/* ena_com_update_nonadaptive_moderation_interval_rx - Update the
+ * non-adaptive interval in Rx direction.
+ * @ena_dev: ENA communication layer struct
+ * @rx_coalesce_usecs: Interval in usec.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_update_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev,
+						      u32 rx_coalesce_usecs);
+
+/* ena_com_get_nonadaptive_moderation_interval_tx - Retrieve the
+ * non-adaptive interval in Tx direction.
+ * @ena_dev: ENA communication layer struct
+ *
+ * @return - interval in usec
+ */
+unsigned int ena_com_get_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev);
+
+/* ena_com_get_nonadaptive_moderation_interval_rx - Retrieve the
+ * non-adaptive interval in Rx direction.
+ * @ena_dev: ENA communication layer struct
+ *
+ * @return - interval in usec
+ */
+unsigned int ena_com_get_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev);
+
+/* ena_com_config_dev_mode - Configure the placement policy of the device.
+ * @ena_dev: ENA communication layer struct
+ * @llq_features: LLQ feature descriptor, retrieve via
+ *                ena_com_get_dev_attr_feat.
+ * @ena_llq_config: The default driver LLQ parameters configurations
+ */
+int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
+			    struct ena_admin_feature_llq_desc *llq_features,
+			    struct ena_llq_configurations *llq_default_config);
+
+static inline bool ena_com_get_adaptive_moderation_enabled(struct ena_com_dev *ena_dev)
+{
+	return ena_dev->adaptive_coalescing;
+}
+
+static inline void ena_com_enable_adaptive_moderation(struct ena_com_dev *ena_dev)
+{
+	ena_dev->adaptive_coalescing = true;
+}
+
+static inline void ena_com_disable_adaptive_moderation(struct ena_com_dev *ena_dev)
+{
+	ena_dev->adaptive_coalescing = false;
+}
+
+/* ena_com_update_intr_reg - Prepare interrupt register
+ * @intr_reg: interrupt register to update.
+ * @rx_delay_interval: Rx interval in usecs
+ * @tx_delay_interval: Tx interval in usecs
+ * @unmask: unask enable/disable
+ *
+ * Prepare interrupt update register with the supplied parameters.
+ */
+static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg,
+					   u32 rx_delay_interval,
+					   u32 tx_delay_interval,
+					   bool unmask)
+{
+	intr_reg->intr_control = 0;
+	intr_reg->intr_control |= rx_delay_interval &
+		ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK;
+
+	intr_reg->intr_control |=
+		(tx_delay_interval << ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT)
+		& ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK;
+
+	if (unmask)
+		intr_reg->intr_control |= ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK;
+}
+
+static inline u8 *ena_com_get_next_bounce_buffer(struct ena_com_io_bounce_buffer_control *bounce_buf_ctrl)
+{
+	u16 size, buffers_num;
+	u8 *buf;
+
+	size = bounce_buf_ctrl->buffer_size;
+	buffers_num = bounce_buf_ctrl->buffers_num;
+
+	buf = bounce_buf_ctrl->base_buffer +
+		(bounce_buf_ctrl->next_to_use++ & (buffers_num - 1)) * size;
+
+	prefetchw(bounce_buf_ctrl->base_buffer +
+		(bounce_buf_ctrl->next_to_use & (buffers_num - 1)) * size);
+
+	return buf;
+}
+
+#endif /* !(ENA_COM) */
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_common_defs.h
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_common_defs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 - 2016 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _ENA_COMMON_H_
+#define _ENA_COMMON_H_
+
+#define ENA_COMMON_SPEC_VERSION_MAJOR        2
+#define ENA_COMMON_SPEC_VERSION_MINOR        0
+
+/* ENA operates with 48-bit memory addresses. ena_mem_addr_t */
+struct ena_common_mem_addr {
+	u32 mem_addr_low;
+
+	u16 mem_addr_high;
+
+	/* MBZ */
+	u16 reserved16;
+};
+
+#endif /*_ENA_COMMON_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_eth_com.c
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_eth_com.c
@@ -0,0 +1,604 @@
+/*
+ * Copyright 2015 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "ena_eth_com.h"
+
+static struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc(
+	struct ena_com_io_cq *io_cq)
+{
+	struct ena_eth_io_rx_cdesc_base *cdesc;
+	u16 expected_phase, head_masked;
+	u16 desc_phase;
+
+	head_masked = io_cq->head & (io_cq->q_depth - 1);
+	expected_phase = io_cq->phase;
+
+	cdesc = (struct ena_eth_io_rx_cdesc_base *)(io_cq->cdesc_addr.virt_addr
+			+ (head_masked * io_cq->cdesc_entry_size_in_bytes));
+
+	desc_phase = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >>
+			ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT;
+
+	if (desc_phase != expected_phase)
+		return NULL;
+
+	/* Make sure we read the rest of the descriptor after the phase bit
+	 * has been read
+	 */
+	dma_rmb();
+
+	return cdesc;
+}
+
+static void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq)
+{
+	u16 tail_masked;
+	u32 offset;
+
+	tail_masked = io_sq->tail & (io_sq->q_depth - 1);
+
+	offset = tail_masked * io_sq->desc_entry_size;
+
+	return (void *)((uintptr_t)io_sq->desc_addr.virt_addr + offset);
+}
+
+static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
+						     u8 *bounce_buffer)
+{
+	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+
+	u16 dst_tail_mask;
+	u32 dst_offset;
+
+	dst_tail_mask = io_sq->tail & (io_sq->q_depth - 1);
+	dst_offset = dst_tail_mask * llq_info->desc_list_entry_size;
+
+	if (is_llq_max_tx_burst_exists(io_sq)) {
+		if (unlikely(!io_sq->entries_in_tx_burst_left)) {
+			pr_err("Error: trying to send more packets than tx burst allows\n");
+			return -ENOSPC;
+		}
+
+		io_sq->entries_in_tx_burst_left--;
+		pr_debug("decreasing entries_in_tx_burst_left of queue %d to %d\n",
+			 io_sq->qid, io_sq->entries_in_tx_burst_left);
+	}
+
+	/* Make sure everything was written into the bounce buffer before
+	 * writing the bounce buffer to the device
+	 */
+	wmb();
+
+	/* The line is completed. Copy it to dev */
+	__iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset,
+			 bounce_buffer, (llq_info->desc_list_entry_size) / 8);
+
+	io_sq->tail++;
+
+	/* Switch phase bit in case of wrap around */
+	if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0))
+		io_sq->phase ^= 1;
+
+	return 0;
+}
+
+static int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq,
+						 u8 *header_src,
+						 u16 header_len)
+{
+	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	u8 *bounce_buffer = pkt_ctrl->curr_bounce_buf;
+	u16 header_offset;
+
+	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
+		return 0;
+
+	header_offset =
+		llq_info->descs_num_before_header * io_sq->desc_entry_size;
+
+	if (unlikely((header_offset + header_len) >
+		     llq_info->desc_list_entry_size)) {
+		pr_err("trying to write header larger than llq entry can accommodate\n");
+		return -EFAULT;
+	}
+
+	if (unlikely(!bounce_buffer)) {
+		pr_err("bounce buffer is NULL\n");
+		return -EFAULT;
+	}
+
+	memcpy(bounce_buffer + header_offset, header_src, header_len);
+
+	return 0;
+}
+
+static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
+{
+	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+	u8 *bounce_buffer;
+	void *sq_desc;
+
+	bounce_buffer = pkt_ctrl->curr_bounce_buf;
+
+	if (unlikely(!bounce_buffer)) {
+		pr_err("bounce buffer is NULL\n");
+		return NULL;
+	}
+
+	sq_desc = bounce_buffer + pkt_ctrl->idx * io_sq->desc_entry_size;
+	pkt_ctrl->idx++;
+	pkt_ctrl->descs_left_in_line--;
+
+	return sq_desc;
+}
+
+static int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
+{
+	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	int rc;
+
+	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
+		return 0;
+
+	/* bounce buffer was used, so write it and get a new one */
+	if (pkt_ctrl->idx) {
+		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
+							pkt_ctrl->curr_bounce_buf);
+		if (unlikely(rc))
+			return rc;
+
+		pkt_ctrl->curr_bounce_buf =
+			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
+		memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
+		       0x0, llq_info->desc_list_entry_size);
+	}
+
+	pkt_ctrl->idx = 0;
+	pkt_ctrl->descs_left_in_line = llq_info->descs_num_before_header;
+	return 0;
+}
+
+static void *get_sq_desc(struct ena_com_io_sq *io_sq)
+{
+	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+		return get_sq_desc_llq(io_sq);
+
+	return get_sq_desc_regular_queue(io_sq);
+}
+
+static int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
+{
+	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	int rc;
+
+	if (!pkt_ctrl->descs_left_in_line) {
+		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
+							pkt_ctrl->curr_bounce_buf);
+		if (unlikely(rc))
+			return rc;
+
+		pkt_ctrl->curr_bounce_buf =
+			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
+		memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
+		       0x0, llq_info->desc_list_entry_size);
+
+		pkt_ctrl->idx = 0;
+		if (unlikely(llq_info->desc_stride_ctrl == ENA_ADMIN_SINGLE_DESC_PER_ENTRY))
+			pkt_ctrl->descs_left_in_line = 1;
+		else
+			pkt_ctrl->descs_left_in_line =
+			llq_info->desc_list_entry_size / io_sq->desc_entry_size;
+	}
+
+	return 0;
+}
+
+static int ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
+{
+	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+		return ena_com_sq_update_llq_tail(io_sq);
+
+	io_sq->tail++;
+
+	/* Switch phase bit in case of wrap around */
+	if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0))
+		io_sq->phase ^= 1;
+
+	return 0;
+}
+
+static struct ena_eth_io_rx_cdesc_base *
+	ena_com_rx_cdesc_idx_to_ptr(struct ena_com_io_cq *io_cq, u16 idx)
+{
+	idx &= (io_cq->q_depth - 1);
+	return (struct ena_eth_io_rx_cdesc_base *)
+		((uintptr_t)io_cq->cdesc_addr.virt_addr +
+		idx * io_cq->cdesc_entry_size_in_bytes);
+}
+
+static u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
+					   u16 *first_cdesc_idx)
+{
+	struct ena_eth_io_rx_cdesc_base *cdesc;
+	u16 count = 0, head_masked;
+	u32 last = 0;
+
+	do {
+		cdesc = ena_com_get_next_rx_cdesc(io_cq);
+		if (!cdesc)
+			break;
+
+		ena_com_cq_inc_head(io_cq);
+		count++;
+		last = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >>
+			ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT;
+	} while (!last);
+
+	if (last) {
+		*first_cdesc_idx = io_cq->cur_rx_pkt_cdesc_start_idx;
+		count += io_cq->cur_rx_pkt_cdesc_count;
+
+		head_masked = io_cq->head & (io_cq->q_depth - 1);
+
+		io_cq->cur_rx_pkt_cdesc_count = 0;
+		io_cq->cur_rx_pkt_cdesc_start_idx = head_masked;
+
+		pr_debug("ena q_id: %d packets were completed. first desc idx %u descs# %d\n",
+			 io_cq->qid, *first_cdesc_idx, count);
+	} else {
+		io_cq->cur_rx_pkt_cdesc_count += count;
+		count = 0;
+	}
+
+	return count;
+}
+
+static int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
+							struct ena_com_tx_ctx *ena_tx_ctx)
+{
+	struct ena_eth_io_tx_meta_desc *meta_desc = NULL;
+	struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
+
+	meta_desc = get_sq_desc(io_sq);
+	memset(meta_desc, 0x0, sizeof(struct ena_eth_io_tx_meta_desc));
+
+	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_DESC_MASK;
+
+	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK;
+
+	/* bits 0-9 of the mss */
+	meta_desc->word2 |= (ena_meta->mss <<
+		ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT) &
+		ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK;
+	/* bits 10-13 of the mss */
+	meta_desc->len_ctrl |= ((ena_meta->mss >> 10) <<
+		ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT) &
+		ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK;
+
+	/* Extended meta desc */
+	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK;
+	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_STORE_MASK;
+	meta_desc->len_ctrl |= (io_sq->phase <<
+		ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT) &
+		ENA_ETH_IO_TX_META_DESC_PHASE_MASK;
+
+	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_FIRST_MASK;
+	meta_desc->word2 |= ena_meta->l3_hdr_len &
+		ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK;
+	meta_desc->word2 |= (ena_meta->l3_hdr_offset <<
+		ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT) &
+		ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK;
+
+	meta_desc->word2 |= (ena_meta->l4_hdr_len <<
+		ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT) &
+		ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK;
+
+	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_STORE_MASK;
+
+	/* Cached the meta desc */
+	memcpy(&io_sq->cached_tx_meta, ena_meta,
+	       sizeof(struct ena_com_tx_meta));
+
+	return ena_com_sq_update_tail(io_sq);
+}
+
+static void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
+					struct ena_eth_io_rx_cdesc_base *cdesc)
+{
+	ena_rx_ctx->l3_proto = cdesc->status &
+		ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK;
+	ena_rx_ctx->l4_proto =
+		(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK) >>
+		ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT;
+	ena_rx_ctx->l3_csum_err =
+		!!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK) >>
+		ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT);
+	ena_rx_ctx->l4_csum_err =
+		!!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK) >>
+		ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT);
+	ena_rx_ctx->l4_csum_checked =
+		!!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK) >>
+		ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT);
+	ena_rx_ctx->hash = cdesc->hash;
+	ena_rx_ctx->frag =
+		(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK) >>
+		ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT;
+
+	pr_debug("ena_rx_ctx->l3_proto %d ena_rx_ctx->l4_proto %d\nena_rx_ctx->l3_csum_err %d ena_rx_ctx->l4_csum_err %d\nhash frag %d frag: %d cdesc_status: %x\n",
+		 ena_rx_ctx->l3_proto, ena_rx_ctx->l4_proto,
+		 ena_rx_ctx->l3_csum_err, ena_rx_ctx->l4_csum_err,
+		 ena_rx_ctx->hash, ena_rx_ctx->frag, cdesc->status);
+}
+
+/*****************************************************************************/
+/*****************************     API      **********************************/
+/*****************************************************************************/
+
+int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
+		       struct ena_com_tx_ctx *ena_tx_ctx,
+		       int *nb_hw_desc)
+{
+	struct ena_eth_io_tx_desc *desc = NULL;
+	struct ena_com_buf *ena_bufs = ena_tx_ctx->ena_bufs;
+	void *buffer_to_push = ena_tx_ctx->push_header;
+	u16 header_len = ena_tx_ctx->header_len;
+	u16 num_bufs = ena_tx_ctx->num_bufs;
+	u16 start_tail = io_sq->tail;
+	int i, rc;
+	bool have_meta;
+	u64 addr_hi;
+
+	WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_TX, "wrong Q type");
+
+	/* num_bufs +1 for potential meta desc */
+	if (unlikely(!ena_com_sq_have_enough_space(io_sq, num_bufs + 1))) {
+		pr_debug("Not enough space in the tx queue\n");
+		return -ENOMEM;
+	}
+
+	if (unlikely(header_len > io_sq->tx_max_header_size)) {
+		pr_err("header size is too large %d max header: %d\n",
+		       header_len, io_sq->tx_max_header_size);
+		return -EINVAL;
+	}
+
+	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV &&
+		     !buffer_to_push))
+		return -EINVAL;
+
+	rc = ena_com_write_header_to_bounce(io_sq, buffer_to_push, header_len);
+	if (unlikely(rc))
+		return rc;
+
+	have_meta = ena_tx_ctx->meta_valid && ena_com_meta_desc_changed(io_sq,
+			ena_tx_ctx);
+	if (have_meta) {
+		rc = ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx);
+		if (unlikely(rc))
+			return rc;
+	}
+
+	/* If the caller doesn't want to send packets */
+	if (unlikely(!num_bufs && !header_len)) {
+		rc = ena_com_close_bounce_buffer(io_sq);
+		*nb_hw_desc = io_sq->tail - start_tail;
+		return rc;
+	}
+
+	desc = get_sq_desc(io_sq);
+	if (unlikely(!desc))
+		return -EFAULT;
+	memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));
+
+	/* Set first desc when we don't have meta descriptor */
+	if (!have_meta)
+		desc->len_ctrl |= ENA_ETH_IO_TX_DESC_FIRST_MASK;
+
+	desc->buff_addr_hi_hdr_sz |= (header_len <<
+		ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT) &
+		ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK;
+	desc->len_ctrl |= (io_sq->phase << ENA_ETH_IO_TX_DESC_PHASE_SHIFT) &
+		ENA_ETH_IO_TX_DESC_PHASE_MASK;
+
+	desc->len_ctrl |= ENA_ETH_IO_TX_DESC_COMP_REQ_MASK;
+
+	/* Bits 0-9 */
+	desc->meta_ctrl |= (ena_tx_ctx->req_id <<
+		ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT) &
+		ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK;
+
+	desc->meta_ctrl |= (ena_tx_ctx->df <<
+		ENA_ETH_IO_TX_DESC_DF_SHIFT) &
+		ENA_ETH_IO_TX_DESC_DF_MASK;
+
+	/* Bits 10-15 */
+	desc->len_ctrl |= ((ena_tx_ctx->req_id >> 10) <<
+		ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT) &
+		ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK;
+
+	if (ena_tx_ctx->meta_valid) {
+		desc->meta_ctrl |= (ena_tx_ctx->tso_enable <<
+			ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT) &
+			ENA_ETH_IO_TX_DESC_TSO_EN_MASK;
+		desc->meta_ctrl |= ena_tx_ctx->l3_proto &
+			ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK;
+		desc->meta_ctrl |= (ena_tx_ctx->l4_proto <<
+			ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT) &
+			ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK;
+		desc->meta_ctrl |= (ena_tx_ctx->l3_csum_enable <<
+			ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT) &
+			ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK;
+		desc->meta_ctrl |= (ena_tx_ctx->l4_csum_enable <<
+			ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT) &
+			ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK;
+		desc->meta_ctrl |= (ena_tx_ctx->l4_csum_partial <<
+			ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT) &
+			ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK;
+	}
+
+	for (i = 0; i < num_bufs; i++) {
+		/* The first desc share the same desc as the header */
+		if (likely(i != 0)) {
+			rc = ena_com_sq_update_tail(io_sq);
+			if (unlikely(rc))
+				return rc;
+
+			desc = get_sq_desc(io_sq);
+			if (unlikely(!desc))
+				return -EFAULT;
+
+			memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));
+
+			desc->len_ctrl |= (io_sq->phase <<
+				ENA_ETH_IO_TX_DESC_PHASE_SHIFT) &
+				ENA_ETH_IO_TX_DESC_PHASE_MASK;
+		}
+
+		desc->len_ctrl |= ena_bufs->len &
+			ENA_ETH_IO_TX_DESC_LENGTH_MASK;
+
+		addr_hi = ((ena_bufs->paddr &
+			GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32);
+
+		desc->buff_addr_lo = (u32)ena_bufs->paddr;
+		desc->buff_addr_hi_hdr_sz |= addr_hi &
+			ENA_ETH_IO_TX_DESC_ADDR_HI_MASK;
+		ena_bufs++;
+	}
+
+	/* set the last desc indicator */
+	desc->len_ctrl |= ENA_ETH_IO_TX_DESC_LAST_MASK;
+
+	rc = ena_com_sq_update_tail(io_sq);
+	if (unlikely(rc))
+		return rc;
+
+	rc = ena_com_close_bounce_buffer(io_sq);
+
+	*nb_hw_desc = io_sq->tail - start_tail;
+	return rc;
+}
+
+int ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
+		   struct ena_com_io_sq *io_sq,
+		   struct ena_com_rx_ctx *ena_rx_ctx)
+{
+	struct ena_com_rx_buf_info *ena_buf = &ena_rx_ctx->ena_bufs[0];
+	struct ena_eth_io_rx_cdesc_base *cdesc = NULL;
+	u16 cdesc_idx = 0;
+	u16 nb_hw_desc;
+	u16 i;
+
+	WARN(io_cq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type");
+
+	nb_hw_desc = ena_com_cdesc_rx_pkt_get(io_cq, &cdesc_idx);
+	if (nb_hw_desc == 0) {
+		ena_rx_ctx->descs = nb_hw_desc;
+		return 0;
+	}
+
+	pr_debug("fetch rx packet: queue %d completed desc: %d\n", io_cq->qid,
+		 nb_hw_desc);
+
+	if (unlikely(nb_hw_desc > ena_rx_ctx->max_bufs)) {
+		pr_err("Too many RX cdescs (%d) > MAX(%d)\n", nb_hw_desc,
+		       ena_rx_ctx->max_bufs);
+		return -ENOSPC;
+	}
+
+	for (i = 0; i < nb_hw_desc; i++) {
+		cdesc = ena_com_rx_cdesc_idx_to_ptr(io_cq, cdesc_idx + i);
+
+		ena_buf->len = cdesc->length;
+		ena_buf->req_id = cdesc->req_id;
+		ena_buf++;
+	}
+
+	/* Update SQ head ptr */
+	io_sq->next_to_comp += nb_hw_desc;
+
+	pr_debug("[%s][QID#%d] Updating SQ head to: %d\n", __func__, io_sq->qid,
+		 io_sq->next_to_comp);
+
+	/* Get rx flags from the last pkt */
+	ena_com_rx_set_flags(ena_rx_ctx, cdesc);
+
+	ena_rx_ctx->descs = nb_hw_desc;
+	return 0;
+}
+
+int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
+			       struct ena_com_buf *ena_buf,
+			       u16 req_id)
+{
+	struct ena_eth_io_rx_desc *desc;
+
+	WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type");
+
+	if (unlikely(!ena_com_sq_have_enough_space(io_sq, 1)))
+		return -ENOSPC;
+
+	desc = get_sq_desc(io_sq);
+	if (unlikely(!desc))
+		return -EFAULT;
+
+	memset(desc, 0x0, sizeof(struct ena_eth_io_rx_desc));
+
+	desc->length = ena_buf->len;
+
+	desc->ctrl = ENA_ETH_IO_RX_DESC_FIRST_MASK;
+	desc->ctrl |= ENA_ETH_IO_RX_DESC_LAST_MASK;
+	desc->ctrl |= io_sq->phase & ENA_ETH_IO_RX_DESC_PHASE_MASK;
+	desc->ctrl |= ENA_ETH_IO_RX_DESC_COMP_REQ_MASK;
+
+	desc->req_id = req_id;
+
+	desc->buff_addr_lo = (u32)ena_buf->paddr;
+	desc->buff_addr_hi =
+		((ena_buf->paddr & GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32);
+
+	return ena_com_sq_update_tail(io_sq);
+}
+
+bool ena_com_cq_empty(struct ena_com_io_cq *io_cq)
+{
+	struct ena_eth_io_rx_cdesc_base *cdesc;
+
+	cdesc = ena_com_get_next_rx_cdesc(io_cq);
+	if (cdesc)
+		return false;
+	else
+		return true;
+}
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_eth_com.h
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_eth_com.h
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2015 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef ENA_ETH_COM_H_
+#define ENA_ETH_COM_H_
+
+#include "ena_com.h"
+
+/* head update threshold in units of (queue size / ENA_COMP_HEAD_THRESH) */
+#define ENA_COMP_HEAD_THRESH 4
+
+struct ena_com_tx_ctx {
+	struct ena_com_tx_meta ena_meta;
+	struct ena_com_buf *ena_bufs;
+	/* For LLQ, header buffer - pushed to the device mem space */
+	void *push_header;
+
+	enum ena_eth_io_l3_proto_index l3_proto;
+	enum ena_eth_io_l4_proto_index l4_proto;
+	u16 num_bufs;
+	u16 req_id;
+	/* For regular queue, indicate the size of the header
+	 * For LLQ, indicate the size of the pushed buffer
+	 */
+	u16 header_len;
+
+	u8 meta_valid;
+	u8 tso_enable;
+	u8 l3_csum_enable;
+	u8 l4_csum_enable;
+	u8 l4_csum_partial;
+	u8 df; /* Don't fragment */
+};
+
+struct ena_com_rx_ctx {
+	struct ena_com_rx_buf_info *ena_bufs;
+	enum ena_eth_io_l3_proto_index l3_proto;
+	enum ena_eth_io_l4_proto_index l4_proto;
+	bool l3_csum_err;
+	bool l4_csum_err;
+	u8 l4_csum_checked;
+	/* fragmented packet */
+	bool frag;
+	u32 hash;
+	u16 descs;
+	int max_bufs;
+};
+
+int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
+		       struct ena_com_tx_ctx *ena_tx_ctx,
+		       int *nb_hw_desc);
+
+int ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
+		   struct ena_com_io_sq *io_sq,
+		   struct ena_com_rx_ctx *ena_rx_ctx);
+
+int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
+			       struct ena_com_buf *ena_buf,
+			       u16 req_id);
+
+bool ena_com_cq_empty(struct ena_com_io_cq *io_cq);
+
+static inline void ena_com_unmask_intr(struct ena_com_io_cq *io_cq,
+				       struct ena_eth_io_intr_reg *intr_reg)
+{
+	writel(intr_reg->intr_control, io_cq->unmask_reg);
+}
+
+static inline int ena_com_free_desc(struct ena_com_io_sq *io_sq)
+{
+	u16 tail, next_to_comp, cnt;
+
+	next_to_comp = io_sq->next_to_comp;
+	tail = io_sq->tail;
+	cnt = tail - next_to_comp;
+
+	return io_sq->q_depth - 1 - cnt;
+}
+
+/* Check if the submission queue has enough space to hold required_buffers */
+static inline bool ena_com_sq_have_enough_space(struct ena_com_io_sq *io_sq,
+						u16 required_buffers)
+{
+	int temp;
+
+	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
+		return ena_com_free_desc(io_sq) >= required_buffers;
+
+	/* This calculation doesn't need to be 100% accurate. So to reduce
+	 * the calculation overhead just Subtract 2 lines from the free descs
+	 * (one for the header line and one to compensate the devision
+	 * down calculation.
+	 */
+	temp = required_buffers / io_sq->llq_info.descs_per_entry + 2;
+
+	return ena_com_free_desc(io_sq) > temp;
+}
+
+static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
+					     struct ena_com_tx_ctx *ena_tx_ctx)
+{
+	if (!ena_tx_ctx->meta_valid)
+		return false;
+
+	return !!memcmp(&io_sq->cached_tx_meta,
+			&ena_tx_ctx->ena_meta,
+			sizeof(struct ena_com_tx_meta));
+}
+
+static inline bool is_llq_max_tx_burst_exists(struct ena_com_io_sq *io_sq)
+{
+	return (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) &&
+	       io_sq->llq_info.max_entries_in_tx_burst > 0;
+}
+
+static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq,
+					      struct ena_com_tx_ctx *ena_tx_ctx)
+{
+	struct ena_com_llq_info *llq_info;
+	int descs_after_first_entry;
+	int num_entries_needed = 1;
+	u16 num_descs;
+
+	if (!is_llq_max_tx_burst_exists(io_sq))
+		return false;
+
+	llq_info = &io_sq->llq_info;
+	num_descs = ena_tx_ctx->num_bufs;
+
+	if (unlikely(ena_com_meta_desc_changed(io_sq, ena_tx_ctx)))
+		++num_descs;
+
+	if (num_descs > llq_info->descs_num_before_header) {
+		descs_after_first_entry = num_descs - llq_info->descs_num_before_header;
+		num_entries_needed += DIV_ROUND_UP(descs_after_first_entry,
+						   llq_info->descs_per_entry);
+	}
+
+	pr_debug("queue: %d num_descs: %d num_entries_needed: %d\n", io_sq->qid,
+		 num_descs, num_entries_needed);
+
+	return num_entries_needed > io_sq->entries_in_tx_burst_left;
+}
+
+static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq)
+{
+	u16 max_entries_in_tx_burst = io_sq->llq_info.max_entries_in_tx_burst;
+	u16 tail = io_sq->tail;
+
+	pr_debug("write submission queue doorbell for queue: %d tail: %d\n",
+		 io_sq->qid, tail);
+
+	writel(tail, io_sq->db_addr);
+
+	if (is_llq_max_tx_burst_exists(io_sq)) {
+		pr_debug("reset available entries in tx burst for queue %d to %d\n",
+			 io_sq->qid, max_entries_in_tx_burst);
+		io_sq->entries_in_tx_burst_left = max_entries_in_tx_burst;
+	}
+
+	return 0;
+}
+
+static inline int ena_com_update_dev_comp_head(struct ena_com_io_cq *io_cq)
+{
+	u16 unreported_comp, head;
+	bool need_update;
+
+	if (unlikely(io_cq->cq_head_db_reg)) {
+		head = io_cq->head;
+		unreported_comp = head - io_cq->last_head_update;
+		need_update = unreported_comp > (io_cq->q_depth / ENA_COMP_HEAD_THRESH);
+
+		if (unlikely(need_update)) {
+			pr_debug("Write completion queue doorbell for queue %d: head: %d\n",
+				 io_cq->qid, head);
+			writel(head, io_cq->cq_head_db_reg);
+			io_cq->last_head_update = head;
+		}
+	}
+
+	return 0;
+}
+
+static inline void ena_com_update_numa_node(struct ena_com_io_cq *io_cq,
+					    u8 numa_node)
+{
+	struct ena_eth_io_numa_node_cfg_reg numa_cfg;
+
+	if (!io_cq->numa_node_cfg_reg)
+		return;
+
+	numa_cfg.numa_cfg = (numa_node & ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK)
+		| ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK;
+
+	writel(numa_cfg.numa_cfg, io_cq->numa_node_cfg_reg);
+}
+
+static inline void ena_com_comp_ack(struct ena_com_io_sq *io_sq, u16 elem)
+{
+	io_sq->next_to_comp += elem;
+}
+
+static inline void ena_com_cq_inc_head(struct ena_com_io_cq *io_cq)
+{
+	io_cq->head++;
+
+	/* Switch phase bit in case of wrap around */
+	if (unlikely((io_cq->head & (io_cq->q_depth - 1)) == 0))
+		io_cq->phase ^= 1;
+}
+
+static inline int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq,
+					     u16 *req_id)
+{
+	u8 expected_phase, cdesc_phase;
+	struct ena_eth_io_tx_cdesc *cdesc;
+	u16 masked_head;
+
+	masked_head = io_cq->head & (io_cq->q_depth - 1);
+	expected_phase = io_cq->phase;
+
+	cdesc = (struct ena_eth_io_tx_cdesc *)
+		((uintptr_t)io_cq->cdesc_addr.virt_addr +
+		(masked_head * io_cq->cdesc_entry_size_in_bytes));
+
+	/* When the current completion descriptor phase isn't the same as the
+	 * expected, it mean that the device still didn't update
+	 * this completion.
+	 */
+	cdesc_phase = READ_ONCE(cdesc->flags) & ENA_ETH_IO_TX_CDESC_PHASE_MASK;
+	if (cdesc_phase != expected_phase)
+		return -EAGAIN;
+
+	dma_rmb();
+
+	*req_id = READ_ONCE(cdesc->req_id);
+	if (unlikely(*req_id >= io_cq->q_depth)) {
+		pr_err("Invalid req id %d\n", cdesc->req_id);
+		return -EINVAL;
+	}
+
+	ena_com_cq_inc_head(io_cq);
+
+	return 0;
+}
+
+#endif /* ENA_ETH_COM_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2015 - 2016 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _ENA_ETH_IO_H_
+#define _ENA_ETH_IO_H_
+
+enum ena_eth_io_l3_proto_index {
+	ENA_ETH_IO_L3_PROTO_UNKNOWN                 = 0,
+	ENA_ETH_IO_L3_PROTO_IPV4                    = 8,
+	ENA_ETH_IO_L3_PROTO_IPV6                    = 11,
+	ENA_ETH_IO_L3_PROTO_FCOE                    = 21,
+	ENA_ETH_IO_L3_PROTO_ROCE                    = 22,
+};
+
+enum ena_eth_io_l4_proto_index {
+	ENA_ETH_IO_L4_PROTO_UNKNOWN                 = 0,
+	ENA_ETH_IO_L4_PROTO_TCP                     = 12,
+	ENA_ETH_IO_L4_PROTO_UDP                     = 13,
+	ENA_ETH_IO_L4_PROTO_ROUTEABLE_ROCE          = 23,
+};
+
+struct ena_eth_io_tx_desc {
+	/* 15:0 : length - Buffer length in bytes, must
+	 *    include any packet trailers that the ENA supposed
+	 *    to update like End-to-End CRC, Authentication GMAC
+	 *    etc. This length must not include the
+	 *    'Push_Buffer' length. This length must not include
+	 *    the 4-byte added in the end for 802.3 Ethernet FCS
+	 * 21:16 : req_id_hi - Request ID[15:10]
+	 * 22 : reserved22 - MBZ
+	 * 23 : meta_desc - MBZ
+	 * 24 : phase
+	 * 25 : reserved1 - MBZ
+	 * 26 : first - Indicates first descriptor in
+	 *    transaction
+	 * 27 : last - Indicates last descriptor in
+	 *    transaction
+	 * 28 : comp_req - Indicates whether completion
+	 *    should be posted, after packet is transmitted.
+	 *    Valid only for first descriptor
+	 * 30:29 : reserved29 - MBZ
+	 * 31 : reserved31 - MBZ
+	 */
+	u32 len_ctrl;
+
+	/* 3:0 : l3_proto_idx - L3 protocol. This field
+	 *    required when l3_csum_en,l3_csum or tso_en are set.
+	 * 4 : DF - IPv4 DF, must be 0 if packet is IPv4 and
+	 *    DF flags of the IPv4 header is 0. Otherwise must
+	 *    be set to 1
+	 * 6:5 : reserved5
+	 * 7 : tso_en - Enable TSO, For TCP only.
+	 * 12:8 : l4_proto_idx - L4 protocol. This field need
+	 *    to be set when l4_csum_en or tso_en are set.
+	 * 13 : l3_csum_en - enable IPv4 header checksum.
+	 * 14 : l4_csum_en - enable TCP/UDP checksum.
+	 * 15 : ethernet_fcs_dis - when set, the controller
+	 *    will not append the 802.3 Ethernet Frame Check
+	 *    Sequence to the packet
+	 * 16 : reserved16
+	 * 17 : l4_csum_partial - L4 partial checksum. when
+	 *    set to 0, the ENA calculates the L4 checksum,
+	 *    where the Destination Address required for the
+	 *    TCP/UDP pseudo-header is taken from the actual
+	 *    packet L3 header. when set to 1, the ENA doesn't
+	 *    calculate the sum of the pseudo-header, instead,
+	 *    the checksum field of the L4 is used instead. When
+	 *    TSO enabled, the checksum of the pseudo-header
+	 *    must not include the tcp length field. L4 partial
+	 *    checksum should be used for IPv6 packet that
+	 *    contains Routing Headers.
+	 * 20:18 : reserved18 - MBZ
+	 * 21 : reserved21 - MBZ
+	 * 31:22 : req_id_lo - Request ID[9:0]
+	 */
+	u32 meta_ctrl;
+
+	u32 buff_addr_lo;
+
+	/* address high and header size
+	 * 15:0 : addr_hi - Buffer Pointer[47:32]
+	 * 23:16 : reserved16_w2
+	 * 31:24 : header_length - Header length. For Low
+	 *    Latency Queues, this fields indicates the number
+	 *    of bytes written to the headers' memory. For
+	 *    normal queues, if packet is TCP or UDP, and longer
+	 *    than max_header_size, then this field should be
+	 *    set to the sum of L4 header offset and L4 header
+	 *    size(without options), otherwise, this field
+	 *    should be set to 0. For both modes, this field
+	 *    must not exceed the max_header_size.
+	 *    max_header_size value is reported by the Max
+	 *    Queues Feature descriptor
+	 */
+	u32 buff_addr_hi_hdr_sz;
+};
+
+struct ena_eth_io_tx_meta_desc {
+	/* 9:0 : req_id_lo - Request ID[9:0]
+	 * 11:10 : reserved10 - MBZ
+	 * 12 : reserved12 - MBZ
+	 * 13 : reserved13 - MBZ
+	 * 14 : ext_valid - if set, offset fields in Word2
+	 *    are valid Also MSS High in Word 0 and bits [31:24]
+	 *    in Word 3
+	 * 15 : reserved15
+	 * 19:16 : mss_hi
+	 * 20 : eth_meta_type - 0: Tx Metadata Descriptor, 1:
+	 *    Extended Metadata Descriptor
+	 * 21 : meta_store - Store extended metadata in queue
+	 *    cache
+	 * 22 : reserved22 - MBZ
+	 * 23 : meta_desc - MBO
+	 * 24 : phase
+	 * 25 : reserved25 - MBZ
+	 * 26 : first - Indicates first descriptor in
+	 *    transaction
+	 * 27 : last - Indicates last descriptor in
+	 *    transaction
+	 * 28 : comp_req - Indicates whether completion
+	 *    should be posted, after packet is transmitted.
+	 *    Valid only for first descriptor
+	 * 30:29 : reserved29 - MBZ
+	 * 31 : reserved31 - MBZ
+	 */
+	u32 len_ctrl;
+
+	/* 5:0 : req_id_hi
+	 * 31:6 : reserved6 - MBZ
+	 */
+	u32 word1;
+
+	/* 7:0 : l3_hdr_len
+	 * 15:8 : l3_hdr_off
+	 * 21:16 : l4_hdr_len_in_words - counts the L4 header
+	 *    length in words. there is an explicit assumption
+	 *    that L4 header appears right after L3 header and
+	 *    L4 offset is based on l3_hdr_off+l3_hdr_len
+	 * 31:22 : mss_lo
+	 */
+	u32 word2;
+
+	u32 reserved;
+};
+
+struct ena_eth_io_tx_cdesc {
+	/* Request ID[15:0] */
+	u16 req_id;
+
+	u8 status;
+
+	/* flags
+	 * 0 : phase
+	 * 7:1 : reserved1
+	 */
+	u8 flags;
+
+	u16 sub_qid;
+
+	u16 sq_head_idx;
+};
+
+struct ena_eth_io_rx_desc {
+	/* In bytes. 0 means 64KB */
+	u16 length;
+
+	/* MBZ */
+	u8 reserved2;
+
+	/* 0 : phase
+	 * 1 : reserved1 - MBZ
+	 * 2 : first - Indicates first descriptor in
+	 *    transaction
+	 * 3 : last - Indicates last descriptor in transaction
+	 * 4 : comp_req
+	 * 5 : reserved5 - MBO
+	 * 7:6 : reserved6 - MBZ
+	 */
+	u8 ctrl;
+
+	u16 req_id;
+
+	/* MBZ */
+	u16 reserved6;
+
+	u32 buff_addr_lo;
+
+	u16 buff_addr_hi;
+
+	/* MBZ */
+	u16 reserved16_w3;
+};
+
+/* 4-word format Note: all ethernet parsing information are valid only when
+ * last=1
+ */
+struct ena_eth_io_rx_cdesc_base {
+	/* 4:0 : l3_proto_idx
+	 * 6:5 : src_vlan_cnt
+	 * 7 : reserved7 - MBZ
+	 * 12:8 : l4_proto_idx
+	 * 13 : l3_csum_err - when set, either the L3
+	 *    checksum error detected, or, the controller didn't
+	 *    validate the checksum. This bit is valid only when
+	 *    l3_proto_idx indicates IPv4 packet
+	 * 14 : l4_csum_err - when set, either the L4
+	 *    checksum error detected, or, the controller didn't
+	 *    validate the checksum. This bit is valid only when
+	 *    l4_proto_idx indicates TCP/UDP packet, and,
+	 *    ipv4_frag is not set. This bit is valid only when
+	 *    l4_csum_checked below is set.
+	 * 15 : ipv4_frag - Indicates IPv4 fragmented packet
+	 * 16 : l4_csum_checked - L4 checksum was verified
+	 *    (could be OK or error), when cleared the status of
+	 *    checksum is unknown
+	 * 23:17 : reserved17 - MBZ
+	 * 24 : phase
+	 * 25 : l3_csum2 - second checksum engine result
+	 * 26 : first - Indicates first descriptor in
+	 *    transaction
+	 * 27 : last - Indicates last descriptor in
+	 *    transaction
+	 * 29:28 : reserved28
+	 * 30 : buffer - 0: Metadata descriptor. 1: Buffer
+	 *    Descriptor was used
+	 * 31 : reserved31
+	 */
+	u32 status;
+
+	u16 length;
+
+	u16 req_id;
+
+	/* 32-bit hash result */
+	u32 hash;
+
+	u16 sub_qid;
+
+	u16 reserved;
+};
+
+/* 8-word format */
+struct ena_eth_io_rx_cdesc_ext {
+	struct ena_eth_io_rx_cdesc_base base;
+
+	u32 buff_addr_lo;
+
+	u16 buff_addr_hi;
+
+	u16 reserved16;
+
+	u32 reserved_w6;
+
+	u32 reserved_w7;
+};
+
+struct ena_eth_io_intr_reg {
+	/* 14:0 : rx_intr_delay
+	 * 29:15 : tx_intr_delay
+	 * 30 : intr_unmask
+	 * 31 : reserved
+	 */
+	u32 intr_control;
+};
+
+struct ena_eth_io_numa_node_cfg_reg {
+	/* 7:0 : numa
+	 * 30:8 : reserved
+	 * 31 : enabled
+	 */
+	u32 numa_cfg;
+};
+
+/* tx_desc */
+#define ENA_ETH_IO_TX_DESC_LENGTH_MASK                      GENMASK(15, 0)
+#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT                  16
+#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK                   GENMASK(21, 16)
+#define ENA_ETH_IO_TX_DESC_META_DESC_SHIFT                  23
+#define ENA_ETH_IO_TX_DESC_META_DESC_MASK                   BIT(23)
+#define ENA_ETH_IO_TX_DESC_PHASE_SHIFT                      24
+#define ENA_ETH_IO_TX_DESC_PHASE_MASK                       BIT(24)
+#define ENA_ETH_IO_TX_DESC_FIRST_SHIFT                      26
+#define ENA_ETH_IO_TX_DESC_FIRST_MASK                       BIT(26)
+#define ENA_ETH_IO_TX_DESC_LAST_SHIFT                       27
+#define ENA_ETH_IO_TX_DESC_LAST_MASK                        BIT(27)
+#define ENA_ETH_IO_TX_DESC_COMP_REQ_SHIFT                   28
+#define ENA_ETH_IO_TX_DESC_COMP_REQ_MASK                    BIT(28)
+#define ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK                GENMASK(3, 0)
+#define ENA_ETH_IO_TX_DESC_DF_SHIFT                         4
+#define ENA_ETH_IO_TX_DESC_DF_MASK                          BIT(4)
+#define ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT                     7
+#define ENA_ETH_IO_TX_DESC_TSO_EN_MASK                      BIT(7)
+#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT               8
+#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK                GENMASK(12, 8)
+#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT                 13
+#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK                  BIT(13)
+#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT                 14
+#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK                  BIT(14)
+#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_SHIFT           15
+#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_MASK            BIT(15)
+#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT            17
+#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK             BIT(17)
+#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT                  22
+#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK                   GENMASK(31, 22)
+#define ENA_ETH_IO_TX_DESC_ADDR_HI_MASK                     GENMASK(15, 0)
+#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT              24
+#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK               GENMASK(31, 24)
+
+/* tx_meta_desc */
+#define ENA_ETH_IO_TX_META_DESC_REQ_ID_LO_MASK              GENMASK(9, 0)
+#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_SHIFT             14
+#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK              BIT(14)
+#define ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT                16
+#define ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK                 GENMASK(19, 16)
+#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_SHIFT         20
+#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK          BIT(20)
+#define ENA_ETH_IO_TX_META_DESC_META_STORE_SHIFT            21
+#define ENA_ETH_IO_TX_META_DESC_META_STORE_MASK             BIT(21)
+#define ENA_ETH_IO_TX_META_DESC_META_DESC_SHIFT             23
+#define ENA_ETH_IO_TX_META_DESC_META_DESC_MASK              BIT(23)
+#define ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT                 24
+#define ENA_ETH_IO_TX_META_DESC_PHASE_MASK                  BIT(24)
+#define ENA_ETH_IO_TX_META_DESC_FIRST_SHIFT                 26
+#define ENA_ETH_IO_TX_META_DESC_FIRST_MASK                  BIT(26)
+#define ENA_ETH_IO_TX_META_DESC_LAST_SHIFT                  27
+#define ENA_ETH_IO_TX_META_DESC_LAST_MASK                   BIT(27)
+#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_SHIFT              28
+#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_MASK               BIT(28)
+#define ENA_ETH_IO_TX_META_DESC_REQ_ID_HI_MASK              GENMASK(5, 0)
+#define ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK             GENMASK(7, 0)
+#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT            8
+#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK             GENMASK(15, 8)
+#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT   16
+#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK    GENMASK(21, 16)
+#define ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT                22
+#define ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK                 GENMASK(31, 22)
+
+/* tx_cdesc */
+#define ENA_ETH_IO_TX_CDESC_PHASE_MASK                      BIT(0)
+
+/* rx_desc */
+#define ENA_ETH_IO_RX_DESC_PHASE_MASK                       BIT(0)
+#define ENA_ETH_IO_RX_DESC_FIRST_SHIFT                      2
+#define ENA_ETH_IO_RX_DESC_FIRST_MASK                       BIT(2)
+#define ENA_ETH_IO_RX_DESC_LAST_SHIFT                       3
+#define ENA_ETH_IO_RX_DESC_LAST_MASK                        BIT(3)
+#define ENA_ETH_IO_RX_DESC_COMP_REQ_SHIFT                   4
+#define ENA_ETH_IO_RX_DESC_COMP_REQ_MASK                    BIT(4)
+
+/* rx_cdesc_base */
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK          GENMASK(4, 0)
+#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_SHIFT         5
+#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_MASK          GENMASK(6, 5)
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT         8
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK          GENMASK(12, 8)
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT          13
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK           BIT(13)
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT          14
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK           BIT(14)
+#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT            15
+#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK             BIT(15)
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT      16
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK       BIT(16)
+#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT                24
+#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK                 BIT(24)
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT             25
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_MASK              BIT(25)
+#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT                26
+#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK                 BIT(26)
+#define ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT                 27
+#define ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK                  BIT(27)
+#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_SHIFT               30
+#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_MASK                BIT(30)
+
+/* intr_reg */
+#define ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK              GENMASK(14, 0)
+#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT             15
+#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK              GENMASK(29, 15)
+#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT               30
+#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK                BIT(30)
+
+/* numa_node_cfg_reg */
+#define ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK              GENMASK(7, 0)
+#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_SHIFT          31
+#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK           BIT(31)
+
+#endif /*_ENA_ETH_IO_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_ethtool.c
@@ -0,0 +1,877 @@
+/*
+ * Copyright 2015 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/pci.h>
+
+#include "ena_netdev.h"
+
+struct ena_stats {
+	char name[ETH_GSTRING_LEN];
+	int stat_offset;
+};
+
+#define ENA_STAT_ENA_COM_ENTRY(stat) { \
+	.name = #stat, \
+	.stat_offset = offsetof(struct ena_com_stats_admin, stat) \
+}
+
+#define ENA_STAT_ENTRY(stat, stat_type) { \
+	.name = #stat, \
+	.stat_offset = offsetof(struct ena_stats_##stat_type, stat) \
+}
+
+#define ENA_STAT_RX_ENTRY(stat) \
+	ENA_STAT_ENTRY(stat, rx)
+
+#define ENA_STAT_TX_ENTRY(stat) \
+	ENA_STAT_ENTRY(stat, tx)
+
+#define ENA_STAT_GLOBAL_ENTRY(stat) \
+	ENA_STAT_ENTRY(stat, dev)
+
+static const struct ena_stats ena_stats_global_strings[] = {
+	ENA_STAT_GLOBAL_ENTRY(tx_timeout),
+	ENA_STAT_GLOBAL_ENTRY(suspend),
+	ENA_STAT_GLOBAL_ENTRY(resume),
+	ENA_STAT_GLOBAL_ENTRY(wd_expired),
+	ENA_STAT_GLOBAL_ENTRY(interface_up),
+	ENA_STAT_GLOBAL_ENTRY(interface_down),
+	ENA_STAT_GLOBAL_ENTRY(admin_q_pause),
+};
+
+static const struct ena_stats ena_stats_tx_strings[] = {
+	ENA_STAT_TX_ENTRY(cnt),
+	ENA_STAT_TX_ENTRY(bytes),
+	ENA_STAT_TX_ENTRY(queue_stop),
+	ENA_STAT_TX_ENTRY(queue_wakeup),
+	ENA_STAT_TX_ENTRY(dma_mapping_err),
+	ENA_STAT_TX_ENTRY(linearize),
+	ENA_STAT_TX_ENTRY(linearize_failed),
+	ENA_STAT_TX_ENTRY(napi_comp),
+	ENA_STAT_TX_ENTRY(tx_poll),
+	ENA_STAT_TX_ENTRY(doorbells),
+	ENA_STAT_TX_ENTRY(prepare_ctx_err),
+	ENA_STAT_TX_ENTRY(bad_req_id),
+	ENA_STAT_TX_ENTRY(llq_buffer_copy),
+	ENA_STAT_TX_ENTRY(missed_tx),
+};
+
+static const struct ena_stats ena_stats_rx_strings[] = {
+	ENA_STAT_RX_ENTRY(cnt),
+	ENA_STAT_RX_ENTRY(bytes),
+	ENA_STAT_RX_ENTRY(rx_copybreak_pkt),
+	ENA_STAT_RX_ENTRY(csum_good),
+	ENA_STAT_RX_ENTRY(refil_partial),
+	ENA_STAT_RX_ENTRY(bad_csum),
+	ENA_STAT_RX_ENTRY(page_alloc_fail),
+	ENA_STAT_RX_ENTRY(skb_alloc_fail),
+	ENA_STAT_RX_ENTRY(dma_mapping_err),
+	ENA_STAT_RX_ENTRY(bad_desc_num),
+	ENA_STAT_RX_ENTRY(bad_req_id),
+	ENA_STAT_RX_ENTRY(empty_rx_ring),
+	ENA_STAT_RX_ENTRY(csum_unchecked),
+};
+
+static const struct ena_stats ena_stats_ena_com_strings[] = {
+	ENA_STAT_ENA_COM_ENTRY(aborted_cmd),
+	ENA_STAT_ENA_COM_ENTRY(submitted_cmd),
+	ENA_STAT_ENA_COM_ENTRY(completed_cmd),
+	ENA_STAT_ENA_COM_ENTRY(out_of_space),
+	ENA_STAT_ENA_COM_ENTRY(no_completion),
+};
+
+#define ENA_STATS_ARRAY_GLOBAL	ARRAY_SIZE(ena_stats_global_strings)
+#define ENA_STATS_ARRAY_TX	ARRAY_SIZE(ena_stats_tx_strings)
+#define ENA_STATS_ARRAY_RX	ARRAY_SIZE(ena_stats_rx_strings)
+#define ENA_STATS_ARRAY_ENA_COM	ARRAY_SIZE(ena_stats_ena_com_strings)
+
+static void ena_safe_update_stat(u64 *src, u64 *dst,
+				 struct u64_stats_sync *syncp)
+{
+	unsigned int start;
+
+	do {
+		start = u64_stats_fetch_begin_irq(syncp);
+		*(dst) = *src;
+	} while (u64_stats_fetch_retry_irq(syncp, start));
+}
+
+static void ena_queue_stats(struct ena_adapter *adapter, u64 **data)
+{
+	const struct ena_stats *ena_stats;
+	struct ena_ring *ring;
+
+	u64 *ptr;
+	int i, j;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		/* Tx stats */
+		ring = &adapter->tx_ring[i];
+
+		for (j = 0; j < ENA_STATS_ARRAY_TX; j++) {
+			ena_stats = &ena_stats_tx_strings[j];
+
+			ptr = (u64 *)((uintptr_t)&ring->tx_stats +
+				(uintptr_t)ena_stats->stat_offset);
+
+			ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
+		}
+
+		/* Rx stats */
+		ring = &adapter->rx_ring[i];
+
+		for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
+			ena_stats = &ena_stats_rx_strings[j];
+
+			ptr = (u64 *)((uintptr_t)&ring->rx_stats +
+				(uintptr_t)ena_stats->stat_offset);
+
+			ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
+		}
+	}
+}
+
+static void ena_dev_admin_queue_stats(struct ena_adapter *adapter, u64 **data)
+{
+	const struct ena_stats *ena_stats;
+	u32 *ptr;
+	int i;
+
+	for (i = 0; i < ENA_STATS_ARRAY_ENA_COM; i++) {
+		ena_stats = &ena_stats_ena_com_strings[i];
+
+		ptr = (u32 *)((uintptr_t)&adapter->ena_dev->admin_queue.stats +
+			(uintptr_t)ena_stats->stat_offset);
+
+		*(*data)++ = *ptr;
+	}
+}
+
+static void ena_get_ethtool_stats(struct net_device *netdev,
+				  struct ethtool_stats *stats,
+				  u64 *data)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	const struct ena_stats *ena_stats;
+	u64 *ptr;
+	int i;
+
+	for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) {
+		ena_stats = &ena_stats_global_strings[i];
+
+		ptr = (u64 *)((uintptr_t)&adapter->dev_stats +
+			(uintptr_t)ena_stats->stat_offset);
+
+		ena_safe_update_stat(ptr, data++, &adapter->syncp);
+	}
+
+	ena_queue_stats(adapter, &data);
+	ena_dev_admin_queue_stats(adapter, &data);
+}
+
+int ena_get_sset_count(struct net_device *netdev, int sset)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	if (sset != ETH_SS_STATS)
+		return -EOPNOTSUPP;
+
+	return  adapter->num_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX)
+		+ ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENA_COM;
+}
+
+static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
+{
+	const struct ena_stats *ena_stats;
+	int i, j;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		/* Tx stats */
+		for (j = 0; j < ENA_STATS_ARRAY_TX; j++) {
+			ena_stats = &ena_stats_tx_strings[j];
+
+			snprintf(*data, ETH_GSTRING_LEN,
+				 "queue_%u_tx_%s", i, ena_stats->name);
+			 (*data) += ETH_GSTRING_LEN;
+		}
+		/* Rx stats */
+		for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
+			ena_stats = &ena_stats_rx_strings[j];
+
+			snprintf(*data, ETH_GSTRING_LEN,
+				 "queue_%u_rx_%s", i, ena_stats->name);
+			(*data) += ETH_GSTRING_LEN;
+		}
+	}
+}
+
+static void ena_com_dev_strings(u8 **data)
+{
+	const struct ena_stats *ena_stats;
+	int i;
+
+	for (i = 0; i < ENA_STATS_ARRAY_ENA_COM; i++) {
+		ena_stats = &ena_stats_ena_com_strings[i];
+
+		snprintf(*data, ETH_GSTRING_LEN,
+			 "ena_admin_q_%s", ena_stats->name);
+		(*data) += ETH_GSTRING_LEN;
+	}
+}
+
+static void ena_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	const struct ena_stats *ena_stats;
+	int i;
+
+	if (sset != ETH_SS_STATS)
+		return;
+
+	for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) {
+		ena_stats = &ena_stats_global_strings[i];
+
+		memcpy(data, ena_stats->name, ETH_GSTRING_LEN);
+		data += ETH_GSTRING_LEN;
+	}
+
+	ena_queue_strings(adapter, &data);
+	ena_com_dev_strings(&data);
+}
+
+static int ena_get_link_ksettings(struct net_device *netdev,
+				  struct ethtool_link_ksettings *link_ksettings)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	struct ena_admin_get_feature_link_desc *link;
+	struct ena_admin_get_feat_resp feat_resp;
+	int rc;
+
+	rc = ena_com_get_link_params(ena_dev, &feat_resp);
+	if (rc)
+		return rc;
+
+	link = &feat_resp.u.link;
+	link_ksettings->base.speed = link->speed;
+
+	if (link->flags & ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK) {
+		ethtool_link_ksettings_add_link_mode(link_ksettings,
+						     supported, Autoneg);
+		ethtool_link_ksettings_add_link_mode(link_ksettings,
+						     supported, Autoneg);
+	}
+
+	link_ksettings->base.autoneg =
+		(link->flags & ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK) ?
+		AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+	link_ksettings->base.duplex = DUPLEX_FULL;
+
+	return 0;
+}
+
+static int ena_get_coalesce(struct net_device *net_dev,
+			    struct ethtool_coalesce *coalesce)
+{
+	struct ena_adapter *adapter = netdev_priv(net_dev);
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+
+	if (!ena_com_interrupt_moderation_supported(ena_dev))
+		return -EOPNOTSUPP;
+
+	coalesce->tx_coalesce_usecs =
+		ena_com_get_nonadaptive_moderation_interval_tx(ena_dev) *
+			ena_dev->intr_delay_resolution;
+
+	coalesce->rx_coalesce_usecs =
+		ena_com_get_nonadaptive_moderation_interval_rx(ena_dev)
+		* ena_dev->intr_delay_resolution;
+
+	coalesce->use_adaptive_rx_coalesce =
+		ena_com_get_adaptive_moderation_enabled(ena_dev);
+
+	return 0;
+}
+
+static void ena_update_tx_rings_nonadaptive_intr_moderation(struct ena_adapter *adapter)
+{
+	unsigned int val;
+	int i;
+
+	val = ena_com_get_nonadaptive_moderation_interval_tx(adapter->ena_dev);
+
+	for (i = 0; i < adapter->num_queues; i++)
+		adapter->tx_ring[i].smoothed_interval = val;
+}
+
+static void ena_update_rx_rings_nonadaptive_intr_moderation(struct ena_adapter *adapter)
+{
+	unsigned int val;
+	int i;
+
+	val = ena_com_get_nonadaptive_moderation_interval_rx(adapter->ena_dev);
+
+	for (i = 0; i < adapter->num_queues; i++)
+		adapter->rx_ring[i].smoothed_interval = val;
+}
+
+static int ena_set_coalesce(struct net_device *net_dev,
+			    struct ethtool_coalesce *coalesce)
+{
+	struct ena_adapter *adapter = netdev_priv(net_dev);
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	int rc;
+
+	if (!ena_com_interrupt_moderation_supported(ena_dev))
+		return -EOPNOTSUPP;
+
+	rc = ena_com_update_nonadaptive_moderation_interval_tx(ena_dev,
+							       coalesce->tx_coalesce_usecs);
+	if (rc)
+		return rc;
+
+	ena_update_tx_rings_nonadaptive_intr_moderation(adapter);
+
+	rc = ena_com_update_nonadaptive_moderation_interval_rx(ena_dev,
+							       coalesce->rx_coalesce_usecs);
+	if (rc)
+		return rc;
+
+	ena_update_rx_rings_nonadaptive_intr_moderation(adapter);
+
+	if ((coalesce->use_adaptive_rx_coalesce) &&
+	    (!ena_com_get_adaptive_moderation_enabled(ena_dev)))
+		ena_com_enable_adaptive_moderation(ena_dev);
+
+	if ((!coalesce->use_adaptive_rx_coalesce) &&
+	    (ena_com_get_adaptive_moderation_enabled(ena_dev)))
+		ena_com_disable_adaptive_moderation(ena_dev);
+
+	return 0;
+}
+
+static u32 ena_get_msglevel(struct net_device *netdev)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	return adapter->msg_enable;
+}
+
+static void ena_set_msglevel(struct net_device *netdev, u32 value)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	adapter->msg_enable = value;
+}
+
+static void ena_get_drvinfo(struct net_device *dev,
+			    struct ethtool_drvinfo *info)
+{
+	struct ena_adapter *adapter = netdev_priv(dev);
+
+	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(adapter->pdev),
+		sizeof(info->bus_info));
+}
+
+static void ena_get_ringparam(struct net_device *netdev,
+			      struct ethtool_ringparam *ring)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	ring->tx_max_pending = adapter->max_tx_ring_size;
+	ring->rx_max_pending = adapter->max_rx_ring_size;
+	ring->tx_pending = adapter->tx_ring[0].ring_size;
+	ring->rx_pending = adapter->rx_ring[0].ring_size;
+}
+
+static int ena_set_ringparam(struct net_device *netdev,
+			     struct ethtool_ringparam *ring)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	u32 new_tx_size, new_rx_size;
+
+	new_tx_size = ring->tx_pending < ENA_MIN_RING_SIZE ?
+			ENA_MIN_RING_SIZE : ring->tx_pending;
+	new_tx_size = rounddown_pow_of_two(new_tx_size);
+
+	new_rx_size = ring->rx_pending < ENA_MIN_RING_SIZE ?
+			ENA_MIN_RING_SIZE : ring->rx_pending;
+	new_rx_size = rounddown_pow_of_two(new_rx_size);
+
+	if (new_tx_size == adapter->requested_tx_ring_size &&
+	    new_rx_size == adapter->requested_rx_ring_size)
+		return 0;
+
+	return ena_update_queue_sizes(adapter, new_tx_size, new_rx_size);
+}
+
+static u32 ena_flow_hash_to_flow_type(u16 hash_fields)
+{
+	u32 data = 0;
+
+	if (hash_fields & ENA_ADMIN_RSS_L2_DA)
+		data |= RXH_L2DA;
+
+	if (hash_fields & ENA_ADMIN_RSS_L3_DA)
+		data |= RXH_IP_DST;
+
+	if (hash_fields & ENA_ADMIN_RSS_L3_SA)
+		data |= RXH_IP_SRC;
+
+	if (hash_fields & ENA_ADMIN_RSS_L4_DP)
+		data |= RXH_L4_B_2_3;
+
+	if (hash_fields & ENA_ADMIN_RSS_L4_SP)
+		data |= RXH_L4_B_0_1;
+
+	return data;
+}
+
+static u16 ena_flow_data_to_flow_hash(u32 hash_fields)
+{
+	u16 data = 0;
+
+	if (hash_fields & RXH_L2DA)
+		data |= ENA_ADMIN_RSS_L2_DA;
+
+	if (hash_fields & RXH_IP_DST)
+		data |= ENA_ADMIN_RSS_L3_DA;
+
+	if (hash_fields & RXH_IP_SRC)
+		data |= ENA_ADMIN_RSS_L3_SA;
+
+	if (hash_fields & RXH_L4_B_2_3)
+		data |= ENA_ADMIN_RSS_L4_DP;
+
+	if (hash_fields & RXH_L4_B_0_1)
+		data |= ENA_ADMIN_RSS_L4_SP;
+
+	return data;
+}
+
+static int ena_get_rss_hash(struct ena_com_dev *ena_dev,
+			    struct ethtool_rxnfc *cmd)
+{
+	enum ena_admin_flow_hash_proto proto;
+	u16 hash_fields;
+	int rc;
+
+	cmd->data = 0;
+
+	switch (cmd->flow_type) {
+	case TCP_V4_FLOW:
+		proto = ENA_ADMIN_RSS_TCP4;
+		break;
+	case UDP_V4_FLOW:
+		proto = ENA_ADMIN_RSS_UDP4;
+		break;
+	case TCP_V6_FLOW:
+		proto = ENA_ADMIN_RSS_TCP6;
+		break;
+	case UDP_V6_FLOW:
+		proto = ENA_ADMIN_RSS_UDP6;
+		break;
+	case IPV4_FLOW:
+		proto = ENA_ADMIN_RSS_IP4;
+		break;
+	case IPV6_FLOW:
+		proto = ENA_ADMIN_RSS_IP6;
+		break;
+	case ETHER_FLOW:
+		proto = ENA_ADMIN_RSS_NOT_IP;
+		break;
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+	case SCTP_V4_FLOW:
+	case AH_ESP_V4_FLOW:
+		return -EOPNOTSUPP;
+	default:
+		return -EINVAL;
+	}
+
+	rc = ena_com_get_hash_ctrl(ena_dev, proto, &hash_fields);
+	if (rc)
+		return rc;
+
+	cmd->data = ena_flow_hash_to_flow_type(hash_fields);
+
+	return 0;
+}
+
+static int ena_set_rss_hash(struct ena_com_dev *ena_dev,
+			    struct ethtool_rxnfc *cmd)
+{
+	enum ena_admin_flow_hash_proto proto;
+	u16 hash_fields;
+
+	switch (cmd->flow_type) {
+	case TCP_V4_FLOW:
+		proto = ENA_ADMIN_RSS_TCP4;
+		break;
+	case UDP_V4_FLOW:
+		proto = ENA_ADMIN_RSS_UDP4;
+		break;
+	case TCP_V6_FLOW:
+		proto = ENA_ADMIN_RSS_TCP6;
+		break;
+	case UDP_V6_FLOW:
+		proto = ENA_ADMIN_RSS_UDP6;
+		break;
+	case IPV4_FLOW:
+		proto = ENA_ADMIN_RSS_IP4;
+		break;
+	case IPV6_FLOW:
+		proto = ENA_ADMIN_RSS_IP6;
+		break;
+	case ETHER_FLOW:
+		proto = ENA_ADMIN_RSS_NOT_IP;
+		break;
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+	case SCTP_V4_FLOW:
+	case AH_ESP_V4_FLOW:
+		return -EOPNOTSUPP;
+	default:
+		return -EINVAL;
+	}
+
+	hash_fields = ena_flow_data_to_flow_hash(cmd->data);
+
+	return ena_com_fill_hash_ctrl(ena_dev, proto, hash_fields);
+}
+
+static int ena_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	int rc = 0;
+
+	switch (info->cmd) {
+	case ETHTOOL_SRXFH:
+		rc = ena_set_rss_hash(adapter->ena_dev, info);
+		break;
+	case ETHTOOL_SRXCLSRLDEL:
+	case ETHTOOL_SRXCLSRLINS:
+	default:
+		netif_err(adapter, drv, netdev,
+			  "Command parameter %d is not supported\n", info->cmd);
+		rc = -EOPNOTSUPP;
+	}
+
+	return rc;
+}
+
+static int ena_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info,
+			 u32 *rules)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	int rc = 0;
+
+	switch (info->cmd) {
+	case ETHTOOL_GRXRINGS:
+		info->data = adapter->num_queues;
+		rc = 0;
+		break;
+	case ETHTOOL_GRXFH:
+		rc = ena_get_rss_hash(adapter->ena_dev, info);
+		break;
+	case ETHTOOL_GRXCLSRLCNT:
+	case ETHTOOL_GRXCLSRULE:
+	case ETHTOOL_GRXCLSRLALL:
+	default:
+		netif_err(adapter, drv, netdev,
+			  "Command parameter %d is not supported\n", info->cmd);
+		rc = -EOPNOTSUPP;
+	}
+
+	return rc;
+}
+
+static u32 ena_get_rxfh_indir_size(struct net_device *netdev)
+{
+	return ENA_RX_RSS_TABLE_SIZE;
+}
+
+static u32 ena_get_rxfh_key_size(struct net_device *netdev)
+{
+	return ENA_HASH_KEY_SIZE;
+}
+
+static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
+			u8 *hfunc)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	enum ena_admin_hash_functions ena_func;
+	u8 func;
+	int rc;
+
+	rc = ena_com_indirect_table_get(adapter->ena_dev, indir);
+	if (rc)
+		return rc;
+
+	rc = ena_com_get_hash_function(adapter->ena_dev, &ena_func, key);
+	if (rc)
+		return rc;
+
+	switch (ena_func) {
+	case ENA_ADMIN_TOEPLITZ:
+		func = ETH_RSS_HASH_TOP;
+		break;
+	case ENA_ADMIN_CRC32:
+		func = ETH_RSS_HASH_XOR;
+		break;
+	default:
+		netif_err(adapter, drv, netdev,
+			  "Command parameter is not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (hfunc)
+		*hfunc = func;
+
+	return rc;
+}
+
+static int ena_set_rxfh(struct net_device *netdev, const u32 *indir,
+			const u8 *key, const u8 hfunc)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	enum ena_admin_hash_functions func;
+	int rc, i;
+
+	if (indir) {
+		for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
+			rc = ena_com_indirect_table_fill_entry(ena_dev,
+							       i,
+							       ENA_IO_RXQ_IDX(indir[i]));
+			if (unlikely(rc)) {
+				netif_err(adapter, drv, netdev,
+					  "Cannot fill indirect table (index is too large)\n");
+				return rc;
+			}
+		}
+
+		rc = ena_com_indirect_table_set(ena_dev);
+		if (rc) {
+			netif_err(adapter, drv, netdev,
+				  "Cannot set indirect table\n");
+			return rc == -EPERM ? -EOPNOTSUPP : rc;
+		}
+	}
+
+	switch (hfunc) {
+	case ETH_RSS_HASH_TOP:
+		func = ENA_ADMIN_TOEPLITZ;
+		break;
+	case ETH_RSS_HASH_XOR:
+		func = ENA_ADMIN_CRC32;
+		break;
+	default:
+		netif_err(adapter, drv, netdev, "Unsupported hfunc %d\n",
+			  hfunc);
+		return -EOPNOTSUPP;
+	}
+
+	if (key) {
+		rc = ena_com_fill_hash_function(ena_dev, func, key,
+						ENA_HASH_KEY_SIZE,
+						0xFFFFFFFF);
+		if (unlikely(rc)) {
+			netif_err(adapter, drv, netdev, "Cannot fill key\n");
+			return rc == -EPERM ? -EOPNOTSUPP : rc;
+		}
+	}
+
+	return 0;
+}
+
+static void ena_get_channels(struct net_device *netdev,
+			     struct ethtool_channels *channels)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	channels->max_rx = adapter->num_queues;
+	channels->max_tx = adapter->num_queues;
+	channels->max_other = 0;
+	channels->max_combined = 0;
+	channels->rx_count = adapter->num_queues;
+	channels->tx_count = adapter->num_queues;
+	channels->other_count = 0;
+	channels->combined_count = 0;
+}
+
+static int ena_get_tunable(struct net_device *netdev,
+			   const struct ethtool_tunable *tuna, void *data)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	int ret = 0;
+
+	switch (tuna->id) {
+	case ETHTOOL_RX_COPYBREAK:
+		*(u32 *)data = adapter->rx_copybreak;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int ena_set_tunable(struct net_device *netdev,
+			   const struct ethtool_tunable *tuna,
+			   const void *data)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	int ret = 0;
+	u32 len;
+
+	switch (tuna->id) {
+	case ETHTOOL_RX_COPYBREAK:
+		len = *(u32 *)data;
+		if (len > adapter->netdev->mtu) {
+			ret = -EINVAL;
+			break;
+		}
+		adapter->rx_copybreak = len;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static const struct ethtool_ops ena_ethtool_ops = {
+	.get_link_ksettings	= ena_get_link_ksettings,
+	.get_drvinfo		= ena_get_drvinfo,
+	.get_msglevel		= ena_get_msglevel,
+	.set_msglevel		= ena_set_msglevel,
+	.get_link		= ethtool_op_get_link,
+	.get_coalesce		= ena_get_coalesce,
+	.set_coalesce		= ena_set_coalesce,
+	.get_ringparam		= ena_get_ringparam,
+	.set_ringparam		= ena_set_ringparam,
+	.get_sset_count         = ena_get_sset_count,
+	.get_strings		= ena_get_strings,
+	.get_ethtool_stats      = ena_get_ethtool_stats,
+	.get_rxnfc		= ena_get_rxnfc,
+	.set_rxnfc		= ena_set_rxnfc,
+	.get_rxfh_indir_size    = ena_get_rxfh_indir_size,
+	.get_rxfh_key_size	= ena_get_rxfh_key_size,
+	.get_rxfh		= ena_get_rxfh,
+	.set_rxfh		= ena_set_rxfh,
+	.get_channels		= ena_get_channels,
+	.get_tunable		= ena_get_tunable,
+	.set_tunable		= ena_set_tunable,
+};
+
+void ena_set_ethtool_ops(struct net_device *netdev)
+{
+	netdev->ethtool_ops = &ena_ethtool_ops;
+}
+
+static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf)
+{
+	struct net_device *netdev = adapter->netdev;
+	u8 *strings_buf;
+	u64 *data_buf;
+	int strings_num;
+	int i, rc;
+
+	strings_num = ena_get_sset_count(netdev, ETH_SS_STATS);
+	if (strings_num <= 0) {
+		netif_err(adapter, drv, netdev, "Can't get stats num\n");
+		return;
+	}
+
+	strings_buf = devm_kcalloc(&adapter->pdev->dev,
+				   ETH_GSTRING_LEN, strings_num,
+				   GFP_ATOMIC);
+	if (!strings_buf) {
+		netif_err(adapter, drv, netdev,
+			  "failed to alloc strings_buf\n");
+		return;
+	}
+
+	data_buf = devm_kcalloc(&adapter->pdev->dev,
+				strings_num, sizeof(u64),
+				GFP_ATOMIC);
+	if (!data_buf) {
+		netif_err(adapter, drv, netdev,
+			  "failed to allocate data buf\n");
+		devm_kfree(&adapter->pdev->dev, strings_buf);
+		return;
+	}
+
+	ena_get_strings(netdev, ETH_SS_STATS, strings_buf);
+	ena_get_ethtool_stats(netdev, NULL, data_buf);
+
+	/* If there is a buffer, dump stats, otherwise print them to dmesg */
+	if (buf)
+		for (i = 0; i < strings_num; i++) {
+			rc = snprintf(buf, ETH_GSTRING_LEN + sizeof(u64),
+				      "%s %llu\n",
+				      strings_buf + i * ETH_GSTRING_LEN,
+				      data_buf[i]);
+			buf += rc;
+		}
+	else
+		for (i = 0; i < strings_num; i++)
+			netif_err(adapter, drv, netdev, "%s: %llu\n",
+				  strings_buf + i * ETH_GSTRING_LEN,
+				  data_buf[i]);
+
+	devm_kfree(&adapter->pdev->dev, strings_buf);
+	devm_kfree(&adapter->pdev->dev, data_buf);
+}
+
+void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf)
+{
+	if (!buf)
+		return;
+
+	ena_dump_stats_ex(adapter, buf);
+}
+
+void ena_dump_stats_to_dmesg(struct ena_adapter *adapter)
+{
+	ena_dump_stats_ex(adapter, NULL);
+}
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -0,0 +1,3921 @@
+/*
+ * Copyright 2015 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#ifdef CONFIG_RFS_ACCEL
+#include <linux/cpu_rmap.h>
+#endif /* CONFIG_RFS_ACCEL */
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/numa.h>
+#include <linux/pci.h>
+#include <linux/utsname.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <net/ip.h>
+
+#include "ena_netdev.h"
+#include "ena_pci_id_tbl.h"
+
+static char version[] = DEVICE_NAME " v" DRV_MODULE_VERSION "\n";
+
+MODULE_AUTHOR("Amazon.com, Inc. or its affiliates");
+MODULE_DESCRIPTION(DEVICE_NAME);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (5 * HZ)
+
+#define ENA_NAPI_BUDGET 64
+
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | \
+		NETIF_MSG_TX_DONE | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR)
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+static struct ena_aenq_handlers aenq_handlers;
+
+static struct workqueue_struct *ena_wq;
+
+MODULE_DEVICE_TABLE(pci, ena_pci_tbl);
+
+static int ena_rss_init_default(struct ena_adapter *adapter);
+static void check_for_admin_com_state(struct ena_adapter *adapter);
+static void ena_destroy_device(struct ena_adapter *adapter, bool graceful);
+static int ena_restore_device(struct ena_adapter *adapter);
+
+static void ena_tx_timeout(struct net_device *dev)
+{
+	struct ena_adapter *adapter = netdev_priv(dev);
+
+	/* Change the state of the device to trigger reset
+	 * Check that we are not in the middle or a trigger already
+	 */
+
+	if (test_and_set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
+		return;
+
+	adapter->reset_reason = ENA_REGS_RESET_OS_NETDEV_WD;
+	u64_stats_update_begin(&adapter->syncp);
+	adapter->dev_stats.tx_timeout++;
+	u64_stats_update_end(&adapter->syncp);
+
+	netif_err(adapter, tx_err, dev, "Transmit time out\n");
+}
+
+static void update_rx_ring_mtu(struct ena_adapter *adapter, int mtu)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++)
+		adapter->rx_ring[i].mtu = mtu;
+}
+
+static int ena_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct ena_adapter *adapter = netdev_priv(dev);
+	int ret;
+
+	if ((new_mtu > adapter->max_mtu) || (new_mtu < ENA_MIN_MTU)) {
+		netif_err(adapter, drv, dev,
+			  "Invalid MTU setting. new_mtu: %d\n", new_mtu);
+
+		return -EINVAL;
+	}
+
+	ret = ena_com_set_dev_mtu(adapter->ena_dev, new_mtu);
+	if (!ret) {
+		netif_dbg(adapter, drv, dev, "set MTU to %d\n", new_mtu);
+		update_rx_ring_mtu(adapter, new_mtu);
+		dev->mtu = new_mtu;
+	} else {
+		netif_err(adapter, drv, dev, "Failed to set MTU to %d\n",
+			  new_mtu);
+	}
+
+	return ret;
+}
+
+static int ena_init_rx_cpu_rmap(struct ena_adapter *adapter)
+{
+#ifdef CONFIG_RFS_ACCEL
+	u32 i;
+	int rc;
+
+	adapter->netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(adapter->num_queues);
+	if (!adapter->netdev->rx_cpu_rmap)
+		return -ENOMEM;
+	for (i = 0; i < adapter->num_queues; i++) {
+		int irq_idx = ENA_IO_IRQ_IDX(i);
+
+		rc = irq_cpu_rmap_add(adapter->netdev->rx_cpu_rmap,
+				      adapter->msix_entries[irq_idx].vector);
+		if (rc) {
+			free_irq_cpu_rmap(adapter->netdev->rx_cpu_rmap);
+			adapter->netdev->rx_cpu_rmap = NULL;
+			return rc;
+		}
+	}
+#endif /* CONFIG_RFS_ACCEL */
+	return 0;
+}
+
+static void ena_init_io_rings_common(struct ena_adapter *adapter,
+				     struct ena_ring *ring, u16 qid)
+{
+	ring->qid = qid;
+	ring->pdev = adapter->pdev;
+	ring->dev = &adapter->pdev->dev;
+	ring->netdev = adapter->netdev;
+	ring->napi = &adapter->ena_napi[qid].napi;
+	ring->adapter = adapter;
+	ring->ena_dev = adapter->ena_dev;
+	ring->per_napi_packets = 0;
+	ring->cpu = 0;
+	ring->first_interrupt = false;
+	ring->no_interrupt_event_cnt = 0;
+	u64_stats_init(&ring->syncp);
+}
+
+static void ena_init_io_rings(struct ena_adapter *adapter)
+{
+	struct ena_com_dev *ena_dev;
+	struct ena_ring *txr, *rxr;
+	int i;
+
+	ena_dev = adapter->ena_dev;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		txr = &adapter->tx_ring[i];
+		rxr = &adapter->rx_ring[i];
+
+		/* TX/RX common ring state */
+		ena_init_io_rings_common(adapter, txr, i);
+		ena_init_io_rings_common(adapter, rxr, i);
+
+		/* TX specific ring state */
+		txr->ring_size = adapter->requested_tx_ring_size;
+		txr->tx_max_header_size = ena_dev->tx_max_header_size;
+		txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
+		txr->sgl_size = adapter->max_tx_sgl_size;
+		txr->smoothed_interval =
+			ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
+
+		/* RX specific ring state */
+		rxr->ring_size = adapter->requested_rx_ring_size;
+		rxr->rx_copybreak = adapter->rx_copybreak;
+		rxr->sgl_size = adapter->max_rx_sgl_size;
+		rxr->smoothed_interval =
+			ena_com_get_nonadaptive_moderation_interval_rx(ena_dev);
+		rxr->empty_rx_queue = 0;
+		adapter->ena_napi[i].dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+	}
+}
+
+/* ena_setup_tx_resources - allocate I/O Tx resources (Descriptors)
+ * @adapter: network interface device structure
+ * @qid: queue index
+ *
+ * Return 0 on success, negative on failure
+ */
+static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
+{
+	struct ena_ring *tx_ring = &adapter->tx_ring[qid];
+	struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)];
+	int size, i, node;
+
+	if (tx_ring->tx_buffer_info) {
+		netif_err(adapter, ifup,
+			  adapter->netdev, "tx_buffer_info info is not NULL");
+		return -EEXIST;
+	}
+
+	size = sizeof(struct ena_tx_buffer) * tx_ring->ring_size;
+	node = cpu_to_node(ena_irq->cpu);
+
+	tx_ring->tx_buffer_info = vzalloc_node(size, node);
+	if (!tx_ring->tx_buffer_info) {
+		tx_ring->tx_buffer_info = vzalloc(size);
+		if (!tx_ring->tx_buffer_info)
+			goto err_tx_buffer_info;
+	}
+
+	size = sizeof(u16) * tx_ring->ring_size;
+	tx_ring->free_ids = vzalloc_node(size, node);
+	if (!tx_ring->free_ids) {
+		tx_ring->free_ids = vzalloc(size);
+		if (!tx_ring->free_ids)
+			goto err_tx_free_ids;
+	}
+
+	size = tx_ring->tx_max_header_size;
+	tx_ring->push_buf_intermediate_buf = vzalloc_node(size, node);
+	if (!tx_ring->push_buf_intermediate_buf) {
+		tx_ring->push_buf_intermediate_buf = vzalloc(size);
+		if (!tx_ring->push_buf_intermediate_buf)
+			goto err_push_buf_intermediate_buf;
+	}
+
+	/* Req id ring for TX out of order completions */
+	for (i = 0; i < tx_ring->ring_size; i++)
+		tx_ring->free_ids[i] = i;
+
+	/* Reset tx statistics */
+	memset(&tx_ring->tx_stats, 0x0, sizeof(tx_ring->tx_stats));
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+	tx_ring->cpu = ena_irq->cpu;
+	return 0;
+
+err_push_buf_intermediate_buf:
+	vfree(tx_ring->free_ids);
+	tx_ring->free_ids = NULL;
+err_tx_free_ids:
+	vfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+err_tx_buffer_info:
+	return -ENOMEM;
+}
+
+/* ena_free_tx_resources - Free I/O Tx Resources per Queue
+ * @adapter: network interface device structure
+ * @qid: queue index
+ *
+ * Free all transmit software resources
+ */
+static void ena_free_tx_resources(struct ena_adapter *adapter, int qid)
+{
+	struct ena_ring *tx_ring = &adapter->tx_ring[qid];
+
+	vfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+
+	vfree(tx_ring->free_ids);
+	tx_ring->free_ids = NULL;
+
+	vfree(tx_ring->push_buf_intermediate_buf);
+	tx_ring->push_buf_intermediate_buf = NULL;
+}
+
+/* ena_setup_all_tx_resources - allocate I/O Tx queues resources for All queues
+ * @adapter: private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static int ena_setup_all_tx_resources(struct ena_adapter *adapter)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		rc = ena_setup_tx_resources(adapter, i);
+		if (rc)
+			goto err_setup_tx;
+	}
+
+	return 0;
+
+err_setup_tx:
+
+	netif_err(adapter, ifup, adapter->netdev,
+		  "Tx queue %d: allocation failed\n", i);
+
+	/* rewind the index freeing the rings as we go */
+	while (i--)
+		ena_free_tx_resources(adapter, i);
+	return rc;
+}
+
+/* ena_free_all_io_tx_resources - Free I/O Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+static void ena_free_all_io_tx_resources(struct ena_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++)
+		ena_free_tx_resources(adapter, i);
+}
+
+static int validate_rx_req_id(struct ena_ring *rx_ring, u16 req_id)
+{
+	if (likely(req_id < rx_ring->ring_size))
+		return 0;
+
+	netif_err(rx_ring->adapter, rx_err, rx_ring->netdev,
+		  "Invalid rx req_id: %hu\n", req_id);
+
+	u64_stats_update_begin(&rx_ring->syncp);
+	rx_ring->rx_stats.bad_req_id++;
+	u64_stats_update_end(&rx_ring->syncp);
+
+	/* Trigger device reset */
+	rx_ring->adapter->reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID;
+	set_bit(ENA_FLAG_TRIGGER_RESET, &rx_ring->adapter->flags);
+	return -EFAULT;
+}
+
+/* ena_setup_rx_resources - allocate I/O Rx resources (Descriptors)
+ * @adapter: network interface device structure
+ * @qid: queue index
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int ena_setup_rx_resources(struct ena_adapter *adapter,
+				  u32 qid)
+{
+	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
+	struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)];
+	int size, node, i;
+
+	if (rx_ring->rx_buffer_info) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "rx_buffer_info is not NULL");
+		return -EEXIST;
+	}
+
+	/* alloc extra element so in rx path
+	 * we can always prefetch rx_info + 1
+	 */
+	size = sizeof(struct ena_rx_buffer) * (rx_ring->ring_size + 1);
+	node = cpu_to_node(ena_irq->cpu);
+
+	rx_ring->rx_buffer_info = vzalloc_node(size, node);
+	if (!rx_ring->rx_buffer_info) {
+		rx_ring->rx_buffer_info = vzalloc(size);
+		if (!rx_ring->rx_buffer_info)
+			return -ENOMEM;
+	}
+
+	size = sizeof(u16) * rx_ring->ring_size;
+	rx_ring->free_ids = vzalloc_node(size, node);
+	if (!rx_ring->free_ids) {
+		rx_ring->free_ids = vzalloc(size);
+		if (!rx_ring->free_ids) {
+			vfree(rx_ring->rx_buffer_info);
+			rx_ring->rx_buffer_info = NULL;
+			return -ENOMEM;
+		}
+	}
+
+	/* Req id ring for receiving RX pkts out of order */
+	for (i = 0; i < rx_ring->ring_size; i++)
+		rx_ring->free_ids[i] = i;
+
+	/* Reset rx statistics */
+	memset(&rx_ring->rx_stats, 0x0, sizeof(rx_ring->rx_stats));
+
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+	rx_ring->cpu = ena_irq->cpu;
+
+	return 0;
+}
+
+/* ena_free_rx_resources - Free I/O Rx Resources
+ * @adapter: network interface device structure
+ * @qid: queue index
+ *
+ * Free all receive software resources
+ */
+static void ena_free_rx_resources(struct ena_adapter *adapter,
+				  u32 qid)
+{
+	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
+
+	vfree(rx_ring->rx_buffer_info);
+	rx_ring->rx_buffer_info = NULL;
+
+	vfree(rx_ring->free_ids);
+	rx_ring->free_ids = NULL;
+}
+
+/* ena_setup_all_rx_resources - allocate I/O Rx queues resources for all queues
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static int ena_setup_all_rx_resources(struct ena_adapter *adapter)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		rc = ena_setup_rx_resources(adapter, i);
+		if (rc)
+			goto err_setup_rx;
+	}
+
+	return 0;
+
+err_setup_rx:
+
+	netif_err(adapter, ifup, adapter->netdev,
+		  "Rx queue %d: allocation failed\n", i);
+
+	/* rewind the index freeing the rings as we go */
+	while (i--)
+		ena_free_rx_resources(adapter, i);
+	return rc;
+}
+
+/* ena_free_all_io_rx_resources - Free I/O Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ */
+static void ena_free_all_io_rx_resources(struct ena_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++)
+		ena_free_rx_resources(adapter, i);
+}
+
+static int ena_alloc_rx_page(struct ena_ring *rx_ring,
+				    struct ena_rx_buffer *rx_info, gfp_t gfp)
+{
+	struct ena_com_buf *ena_buf;
+	struct page *page;
+	dma_addr_t dma;
+
+	/* if previous allocated page is not used */
+	if (unlikely(rx_info->page))
+		return 0;
+
+	page = alloc_page(gfp);
+	if (unlikely(!page)) {
+		u64_stats_update_begin(&rx_ring->syncp);
+		rx_ring->rx_stats.page_alloc_fail++;
+		u64_stats_update_end(&rx_ring->syncp);
+		return -ENOMEM;
+	}
+
+	dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE,
+			   DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(rx_ring->dev, dma))) {
+		u64_stats_update_begin(&rx_ring->syncp);
+		rx_ring->rx_stats.dma_mapping_err++;
+		u64_stats_update_end(&rx_ring->syncp);
+
+		__free_page(page);
+		return -EIO;
+	}
+	netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
+		  "alloc page %p, rx_info %p\n", page, rx_info);
+
+	rx_info->page = page;
+	rx_info->page_offset = 0;
+	ena_buf = &rx_info->ena_buf;
+	ena_buf->paddr = dma;
+	ena_buf->len = ENA_PAGE_SIZE;
+
+	return 0;
+}
+
+static void ena_free_rx_page(struct ena_ring *rx_ring,
+			     struct ena_rx_buffer *rx_info)
+{
+	struct page *page = rx_info->page;
+	struct ena_com_buf *ena_buf = &rx_info->ena_buf;
+
+	if (unlikely(!page)) {
+		netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
+			   "Trying to free unallocated buffer\n");
+		return;
+	}
+
+	dma_unmap_page(rx_ring->dev, ena_buf->paddr, ENA_PAGE_SIZE,
+		       DMA_FROM_DEVICE);
+
+	__free_page(page);
+	rx_info->page = NULL;
+}
+
+static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num)
+{
+	u16 next_to_use, req_id;
+	u32 i;
+	int rc;
+
+	next_to_use = rx_ring->next_to_use;
+
+	for (i = 0; i < num; i++) {
+		struct ena_rx_buffer *rx_info;
+
+		req_id = rx_ring->free_ids[next_to_use];
+		rc = validate_rx_req_id(rx_ring, req_id);
+		if (unlikely(rc < 0))
+			break;
+
+		rx_info = &rx_ring->rx_buffer_info[req_id];
+
+
+		rc = ena_alloc_rx_page(rx_ring, rx_info,
+				       __GFP_COLD | GFP_ATOMIC | __GFP_COMP);
+		if (unlikely(rc < 0)) {
+			netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
+				   "failed to alloc buffer for rx queue %d\n",
+				   rx_ring->qid);
+			break;
+		}
+		rc = ena_com_add_single_rx_desc(rx_ring->ena_com_io_sq,
+						&rx_info->ena_buf,
+						req_id);
+		if (unlikely(rc)) {
+			netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
+				   "failed to add buffer for rx queue %d\n",
+				   rx_ring->qid);
+			break;
+		}
+		next_to_use = ENA_RX_RING_IDX_NEXT(next_to_use,
+						   rx_ring->ring_size);
+	}
+
+	if (unlikely(i < num)) {
+		u64_stats_update_begin(&rx_ring->syncp);
+		rx_ring->rx_stats.refil_partial++;
+		u64_stats_update_end(&rx_ring->syncp);
+		netdev_warn(rx_ring->netdev,
+			    "refilled rx qid %d with only %d buffers (from %d)\n",
+			    rx_ring->qid, i, num);
+	}
+
+	/* ena_com_write_sq_doorbell issues a wmb() */
+	if (likely(i))
+		ena_com_write_sq_doorbell(rx_ring->ena_com_io_sq);
+
+	rx_ring->next_to_use = next_to_use;
+
+	return i;
+}
+
+static void ena_free_rx_bufs(struct ena_adapter *adapter,
+			     u32 qid)
+{
+	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
+	u32 i;
+
+	for (i = 0; i < rx_ring->ring_size; i++) {
+		struct ena_rx_buffer *rx_info = &rx_ring->rx_buffer_info[i];
+
+		if (rx_info->page)
+			ena_free_rx_page(rx_ring, rx_info);
+	}
+}
+
+/* ena_refill_all_rx_bufs - allocate all queues Rx buffers
+ * @adapter: board private structure
+ */
+static void ena_refill_all_rx_bufs(struct ena_adapter *adapter)
+{
+	struct ena_ring *rx_ring;
+	int i, rc, bufs_num;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		rx_ring = &adapter->rx_ring[i];
+		bufs_num = rx_ring->ring_size - 1;
+		rc = ena_refill_rx_bufs(rx_ring, bufs_num);
+
+		if (unlikely(rc != bufs_num))
+			netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
+				   "refilling Queue %d failed. allocated %d buffers from: %d\n",
+				   i, rc, bufs_num);
+	}
+}
+
+static void ena_free_all_rx_bufs(struct ena_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++)
+		ena_free_rx_bufs(adapter, i);
+}
+
+static void ena_unmap_tx_skb(struct ena_ring *tx_ring,
+				    struct ena_tx_buffer *tx_info)
+{
+	struct ena_com_buf *ena_buf;
+	u32 cnt;
+	int i;
+
+	ena_buf = tx_info->bufs;
+	cnt = tx_info->num_of_bufs;
+
+	if (unlikely(!cnt))
+		return;
+
+	if (tx_info->map_linear_data) {
+		dma_unmap_single(tx_ring->dev,
+				 dma_unmap_addr(ena_buf, paddr),
+				 dma_unmap_len(ena_buf, len),
+				 DMA_TO_DEVICE);
+		ena_buf++;
+		cnt--;
+	}
+
+	/* unmap remaining mapped pages */
+	for (i = 0; i < cnt; i++) {
+		dma_unmap_page(tx_ring->dev, dma_unmap_addr(ena_buf, paddr),
+			       dma_unmap_len(ena_buf, len), DMA_TO_DEVICE);
+		ena_buf++;
+	}
+}
+
+/* ena_free_tx_bufs - Free Tx Buffers per Queue
+ * @tx_ring: TX ring for which buffers be freed
+ */
+static void ena_free_tx_bufs(struct ena_ring *tx_ring)
+{
+	bool print_once = true;
+	u32 i;
+
+	for (i = 0; i < tx_ring->ring_size; i++) {
+		struct ena_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i];
+
+		if (!tx_info->skb)
+			continue;
+
+		if (print_once) {
+			netdev_notice(tx_ring->netdev,
+				      "free uncompleted tx skb qid %d idx 0x%x\n",
+				      tx_ring->qid, i);
+			print_once = false;
+		} else {
+			netdev_dbg(tx_ring->netdev,
+				   "free uncompleted tx skb qid %d idx 0x%x\n",
+				   tx_ring->qid, i);
+		}
+
+		ena_unmap_tx_skb(tx_ring, tx_info);
+
+		dev_kfree_skb_any(tx_info->skb);
+	}
+	netdev_tx_reset_queue(netdev_get_tx_queue(tx_ring->netdev,
+						  tx_ring->qid));
+}
+
+static void ena_free_all_tx_bufs(struct ena_adapter *adapter)
+{
+	struct ena_ring *tx_ring;
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		tx_ring = &adapter->tx_ring[i];
+		ena_free_tx_bufs(tx_ring);
+	}
+}
+
+static void ena_destroy_all_tx_queues(struct ena_adapter *adapter)
+{
+	u16 ena_qid;
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		ena_qid = ENA_IO_TXQ_IDX(i);
+		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
+	}
+}
+
+static void ena_destroy_all_rx_queues(struct ena_adapter *adapter)
+{
+	u16 ena_qid;
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		ena_qid = ENA_IO_RXQ_IDX(i);
+		cancel_work_sync(&adapter->ena_napi[i].dim.work);
+		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
+	}
+}
+
+static void ena_destroy_all_io_queues(struct ena_adapter *adapter)
+{
+	ena_destroy_all_tx_queues(adapter);
+	ena_destroy_all_rx_queues(adapter);
+}
+
+static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id)
+{
+	struct ena_tx_buffer *tx_info = NULL;
+
+	if (likely(req_id < tx_ring->ring_size)) {
+		tx_info = &tx_ring->tx_buffer_info[req_id];
+		if (likely(tx_info->skb))
+			return 0;
+	}
+
+	if (tx_info)
+		netif_err(tx_ring->adapter, tx_done, tx_ring->netdev,
+			  "tx_info doesn't have valid skb\n");
+	else
+		netif_err(tx_ring->adapter, tx_done, tx_ring->netdev,
+			  "Invalid req_id: %hu\n", req_id);
+
+	u64_stats_update_begin(&tx_ring->syncp);
+	tx_ring->tx_stats.bad_req_id++;
+	u64_stats_update_end(&tx_ring->syncp);
+
+	/* Trigger device reset */
+	tx_ring->adapter->reset_reason = ENA_REGS_RESET_INV_TX_REQ_ID;
+	set_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags);
+	return -EFAULT;
+}
+
+static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
+{
+	struct netdev_queue *txq;
+	bool above_thresh;
+	u32 tx_bytes = 0;
+	u32 total_done = 0;
+	u16 next_to_clean;
+	u16 req_id;
+	int tx_pkts = 0;
+	int rc;
+
+	next_to_clean = tx_ring->next_to_clean;
+	txq = netdev_get_tx_queue(tx_ring->netdev, tx_ring->qid);
+
+	while (tx_pkts < budget) {
+		struct ena_tx_buffer *tx_info;
+		struct sk_buff *skb;
+
+		rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq,
+						&req_id);
+		if (rc)
+			break;
+
+		rc = validate_tx_req_id(tx_ring, req_id);
+		if (rc)
+			break;
+
+		tx_info = &tx_ring->tx_buffer_info[req_id];
+		skb = tx_info->skb;
+
+		/* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
+		prefetch(&skb->end);
+
+		tx_info->skb = NULL;
+		tx_info->last_jiffies = 0;
+
+		ena_unmap_tx_skb(tx_ring, tx_info);
+
+		netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
+			  "tx_poll: q %d skb %p completed\n", tx_ring->qid,
+			  skb);
+
+		tx_bytes += skb->len;
+		dev_kfree_skb(skb);
+		tx_pkts++;
+		total_done += tx_info->tx_descs;
+
+		tx_ring->free_ids[next_to_clean] = req_id;
+		next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
+						     tx_ring->ring_size);
+	}
+
+	tx_ring->next_to_clean = next_to_clean;
+	ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done);
+	ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq);
+
+	netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);
+
+	netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
+		  "tx_poll: q %d done. total pkts: %d\n",
+		  tx_ring->qid, tx_pkts);
+
+	/* need to make the rings circular update visible to
+	 * ena_start_xmit() before checking for netif_queue_stopped().
+	 */
+	smp_mb();
+
+	above_thresh = ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+						    ENA_TX_WAKEUP_THRESH);
+	if (unlikely(netif_tx_queue_stopped(txq) && above_thresh)) {
+		__netif_tx_lock(txq, smp_processor_id());
+		above_thresh =
+			ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+						     ENA_TX_WAKEUP_THRESH);
+		if (netif_tx_queue_stopped(txq) && above_thresh &&
+		    test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags)) {
+			netif_tx_wake_queue(txq);
+			u64_stats_update_begin(&tx_ring->syncp);
+			tx_ring->tx_stats.queue_wakeup++;
+			u64_stats_update_end(&tx_ring->syncp);
+		}
+		__netif_tx_unlock(txq);
+	}
+
+	return tx_pkts;
+}
+
+static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, bool frags)
+{
+	struct sk_buff *skb;
+
+	if (frags)
+		skb = napi_get_frags(rx_ring->napi);
+	else
+		skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
+						rx_ring->rx_copybreak);
+
+	if (unlikely(!skb)) {
+		u64_stats_update_begin(&rx_ring->syncp);
+		rx_ring->rx_stats.skb_alloc_fail++;
+		u64_stats_update_end(&rx_ring->syncp);
+		netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
+			  "Failed to allocate skb. frags: %d\n", frags);
+		return NULL;
+	}
+
+	return skb;
+}
+
+static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
+				  struct ena_com_rx_buf_info *ena_bufs,
+				  u32 descs,
+				  u16 *next_to_clean)
+{
+	struct sk_buff *skb;
+	struct ena_rx_buffer *rx_info;
+	u16 len, req_id, buf = 0;
+	void *va;
+
+	len = ena_bufs[buf].len;
+	req_id = ena_bufs[buf].req_id;
+	rx_info = &rx_ring->rx_buffer_info[req_id];
+
+	if (unlikely(!rx_info->page)) {
+		netif_err(rx_ring->adapter, rx_err, rx_ring->netdev,
+			  "Page is NULL\n");
+		return NULL;
+	}
+
+	netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
+		  "rx_info %p page %p\n",
+		  rx_info, rx_info->page);
+
+	/* save virt address of first buffer */
+	va = page_address(rx_info->page) + rx_info->page_offset;
+	prefetch(va + NET_IP_ALIGN);
+
+	if (len <= rx_ring->rx_copybreak) {
+		skb = ena_alloc_skb(rx_ring, false);
+		if (unlikely(!skb))
+			return NULL;
+
+		netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
+			  "rx allocated small packet. len %d. data_len %d\n",
+			  skb->len, skb->data_len);
+
+		/* sync this buffer for CPU use */
+		dma_sync_single_for_cpu(rx_ring->dev,
+					dma_unmap_addr(&rx_info->ena_buf, paddr),
+					len,
+					DMA_FROM_DEVICE);
+		skb_copy_to_linear_data(skb, va, len);
+		dma_sync_single_for_device(rx_ring->dev,
+					   dma_unmap_addr(&rx_info->ena_buf, paddr),
+					   len,
+					   DMA_FROM_DEVICE);
+
+		skb_put(skb, len);
+		skb->protocol = eth_type_trans(skb, rx_ring->netdev);
+		rx_ring->free_ids[*next_to_clean] = req_id;
+		*next_to_clean = ENA_RX_RING_IDX_ADD(*next_to_clean, descs,
+						     rx_ring->ring_size);
+		return skb;
+	}
+
+	skb = ena_alloc_skb(rx_ring, true);
+	if (unlikely(!skb))
+		return NULL;
+
+	do {
+		dma_unmap_page(rx_ring->dev,
+			       dma_unmap_addr(&rx_info->ena_buf, paddr),
+			       ENA_PAGE_SIZE, DMA_FROM_DEVICE);
+
+		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page,
+				rx_info->page_offset, len, ENA_PAGE_SIZE);
+
+		netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
+			  "rx skb updated. len %d. data_len %d\n",
+			  skb->len, skb->data_len);
+
+		rx_info->page = NULL;
+
+		rx_ring->free_ids[*next_to_clean] = req_id;
+		*next_to_clean =
+			ENA_RX_RING_IDX_NEXT(*next_to_clean,
+					     rx_ring->ring_size);
+		if (likely(--descs == 0))
+			break;
+
+		buf++;
+		len = ena_bufs[buf].len;
+		req_id = ena_bufs[buf].req_id;
+		rx_info = &rx_ring->rx_buffer_info[req_id];
+	} while (1);
+
+	return skb;
+}
+
+/* ena_rx_checksum - indicate in skb if hw indicated a good cksum
+ * @adapter: structure containing adapter specific data
+ * @ena_rx_ctx: received packet context/metadata
+ * @skb: skb currently being received and modified
+ */
+static void ena_rx_checksum(struct ena_ring *rx_ring,
+				   struct ena_com_rx_ctx *ena_rx_ctx,
+				   struct sk_buff *skb)
+{
+	/* Rx csum disabled */
+	if (unlikely(!(rx_ring->netdev->features & NETIF_F_RXCSUM))) {
+		skb->ip_summed = CHECKSUM_NONE;
+		return;
+	}
+
+	/* For fragmented packets the checksum isn't valid */
+	if (ena_rx_ctx->frag) {
+		skb->ip_summed = CHECKSUM_NONE;
+		return;
+	}
+
+	/* if IP and error */
+	if (unlikely((ena_rx_ctx->l3_proto == ENA_ETH_IO_L3_PROTO_IPV4) &&
+		     (ena_rx_ctx->l3_csum_err))) {
+		/* ipv4 checksum error */
+		skb->ip_summed = CHECKSUM_NONE;
+		u64_stats_update_begin(&rx_ring->syncp);
+		rx_ring->rx_stats.bad_csum++;
+		u64_stats_update_end(&rx_ring->syncp);
+		netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
+			  "RX IPv4 header checksum error\n");
+		return;
+	}
+
+	/* if TCP/UDP */
+	if (likely((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
+		   (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP))) {
+		if (unlikely(ena_rx_ctx->l4_csum_err)) {
+			/* TCP/UDP checksum error */
+			u64_stats_update_begin(&rx_ring->syncp);
+			rx_ring->rx_stats.bad_csum++;
+			u64_stats_update_end(&rx_ring->syncp);
+			netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
+				  "RX L4 checksum error\n");
+			skb->ip_summed = CHECKSUM_NONE;
+			return;
+		}
+
+		if (likely(ena_rx_ctx->l4_csum_checked)) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			u64_stats_update_begin(&rx_ring->syncp);
+			rx_ring->rx_stats.csum_good++;
+			u64_stats_update_end(&rx_ring->syncp);
+		} else {
+			u64_stats_update_begin(&rx_ring->syncp);
+			rx_ring->rx_stats.csum_unchecked++;
+			u64_stats_update_end(&rx_ring->syncp);
+			skb->ip_summed = CHECKSUM_NONE;
+		}
+	} else {
+		skb->ip_summed = CHECKSUM_NONE;
+		return;
+	}
+
+}
+
+static void ena_set_rx_hash(struct ena_ring *rx_ring,
+			    struct ena_com_rx_ctx *ena_rx_ctx,
+			    struct sk_buff *skb)
+{
+	enum pkt_hash_types hash_type;
+
+	if (likely(rx_ring->netdev->features & NETIF_F_RXHASH)) {
+		if (likely((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
+			   (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP)))
+
+			hash_type = PKT_HASH_TYPE_L4;
+		else
+			hash_type = PKT_HASH_TYPE_NONE;
+
+		/* Override hash type if the packet is fragmented */
+		if (ena_rx_ctx->frag)
+			hash_type = PKT_HASH_TYPE_NONE;
+
+		skb_set_hash(skb, ena_rx_ctx->hash, hash_type);
+	}
+}
+
+/* ena_clean_rx_irq - Cleanup RX irq
+ * @rx_ring: RX ring to clean
+ * @napi: napi handler
+ * @budget: how many packets driver is allowed to clean
+ *
+ * Returns the number of cleaned buffers.
+ */
+static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
+			    u32 budget)
+{
+	u16 next_to_clean = rx_ring->next_to_clean;
+	u32 res_budget, work_done;
+
+	struct ena_com_rx_ctx ena_rx_ctx;
+	struct ena_adapter *adapter;
+	struct sk_buff *skb;
+	int refill_required;
+	int refill_threshold;
+	int rc = 0;
+	int total_len = 0;
+	int rx_copybreak_pkt = 0;
+	int i;
+
+	netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
+		  "%s qid %d\n", __func__, rx_ring->qid);
+	res_budget = budget;
+
+	do {
+		ena_rx_ctx.ena_bufs = rx_ring->ena_bufs;
+		ena_rx_ctx.max_bufs = rx_ring->sgl_size;
+		ena_rx_ctx.descs = 0;
+		rc = ena_com_rx_pkt(rx_ring->ena_com_io_cq,
+				    rx_ring->ena_com_io_sq,
+				    &ena_rx_ctx);
+		if (unlikely(rc))
+			goto error;
+
+		if (unlikely(ena_rx_ctx.descs == 0))
+			break;
+
+		netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
+			  "rx_poll: q %d got packet from ena. descs #: %d l3 proto %d l4 proto %d hash: %x\n",
+			  rx_ring->qid, ena_rx_ctx.descs, ena_rx_ctx.l3_proto,
+			  ena_rx_ctx.l4_proto, ena_rx_ctx.hash);
+
+		/* allocate skb and fill it */
+		skb = ena_rx_skb(rx_ring, rx_ring->ena_bufs, ena_rx_ctx.descs,
+				 &next_to_clean);
+
+		/* exit if we failed to retrieve a buffer */
+		if (unlikely(!skb)) {
+			for (i = 0; i < ena_rx_ctx.descs; i++) {
+				rx_ring->free_ids[next_to_clean] =
+					rx_ring->ena_bufs[i].req_id;
+				next_to_clean =
+					ENA_RX_RING_IDX_NEXT(next_to_clean,
+							     rx_ring->ring_size);
+			}
+			break;
+		}
+
+		ena_rx_checksum(rx_ring, &ena_rx_ctx, skb);
+
+		ena_set_rx_hash(rx_ring, &ena_rx_ctx, skb);
+
+		skb_record_rx_queue(skb, rx_ring->qid);
+
+		if (rx_ring->ena_bufs[0].len <= rx_ring->rx_copybreak) {
+			total_len += rx_ring->ena_bufs[0].len;
+			rx_copybreak_pkt++;
+			napi_gro_receive(napi, skb);
+		} else {
+			total_len += skb->len;
+			napi_gro_frags(napi);
+		}
+
+		res_budget--;
+	} while (likely(res_budget));
+
+	work_done = budget - res_budget;
+	rx_ring->per_napi_packets += work_done;
+	u64_stats_update_begin(&rx_ring->syncp);
+	rx_ring->rx_stats.bytes += total_len;
+	rx_ring->rx_stats.cnt += work_done;
+	rx_ring->rx_stats.rx_copybreak_pkt += rx_copybreak_pkt;
+	u64_stats_update_end(&rx_ring->syncp);
+
+	rx_ring->next_to_clean = next_to_clean;
+
+	refill_required = ena_com_free_desc(rx_ring->ena_com_io_sq);
+	refill_threshold =
+		min_t(int, rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER,
+		      ENA_RX_REFILL_THRESH_PACKET);
+
+	/* Optimization, try to batch new rx buffers */
+	if (refill_required > refill_threshold) {
+		ena_com_update_dev_comp_head(rx_ring->ena_com_io_cq);
+		ena_refill_rx_bufs(rx_ring, refill_required);
+	}
+
+	return work_done;
+
+error:
+	adapter = netdev_priv(rx_ring->netdev);
+
+	u64_stats_update_begin(&rx_ring->syncp);
+	rx_ring->rx_stats.bad_desc_num++;
+	u64_stats_update_end(&rx_ring->syncp);
+
+	/* Too many desc from the device. Trigger reset */
+	adapter->reset_reason = ENA_REGS_RESET_TOO_MANY_RX_DESCS;
+	set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+
+	return 0;
+}
+
+static void ena_dim_work(struct work_struct *w)
+{
+	struct dim *dim = container_of(w, struct dim, work);
+	struct dim_cq_moder cur_moder =
+		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
+	struct ena_napi *ena_napi = container_of(dim, struct ena_napi, dim);
+
+	ena_napi->rx_ring->smoothed_interval = cur_moder.usec;
+	dim->state = DIM_START_MEASURE;
+}
+
+static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi)
+{
+	struct dim_sample dim_sample;
+	struct ena_ring *rx_ring = ena_napi->rx_ring;
+
+	if (!rx_ring->per_napi_packets)
+		return;
+
+	rx_ring->non_empty_napi_events++;
+
+	dim_update_sample(rx_ring->non_empty_napi_events,
+			  rx_ring->rx_stats.cnt,
+			  rx_ring->rx_stats.bytes,
+			  &dim_sample);
+
+	net_dim(&ena_napi->dim, dim_sample);
+
+	rx_ring->per_napi_packets = 0;
+}
+
+static void ena_unmask_interrupt(struct ena_ring *tx_ring,
+					struct ena_ring *rx_ring)
+{
+	struct ena_eth_io_intr_reg intr_reg;
+	u32 rx_interval = ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev) ?
+		rx_ring->smoothed_interval :
+		ena_com_get_nonadaptive_moderation_interval_rx(rx_ring->ena_dev);
+
+	/* Update intr register: rx intr delay,
+	 * tx intr delay and interrupt unmask
+	 */
+	ena_com_update_intr_reg(&intr_reg,
+				rx_interval,
+				tx_ring->smoothed_interval,
+				true);
+
+	/* It is a shared MSI-X.
+	 * Tx and Rx CQ have pointer to it.
+	 * So we use one of them to reach the intr reg
+	 */
+	ena_com_unmask_intr(rx_ring->ena_com_io_cq, &intr_reg);
+}
+
+static void ena_update_ring_numa_node(struct ena_ring *tx_ring,
+					     struct ena_ring *rx_ring)
+{
+	int cpu = get_cpu();
+	int numa_node;
+
+	/* Check only one ring since the 2 rings are running on the same cpu */
+	if (likely(tx_ring->cpu == cpu))
+		goto out;
+
+	numa_node = cpu_to_node(cpu);
+	put_cpu();
+
+	if (numa_node != NUMA_NO_NODE) {
+		ena_com_update_numa_node(tx_ring->ena_com_io_cq, numa_node);
+		ena_com_update_numa_node(rx_ring->ena_com_io_cq, numa_node);
+	}
+
+	tx_ring->cpu = cpu;
+	rx_ring->cpu = cpu;
+
+	return;
+out:
+	put_cpu();
+}
+
+static int ena_io_poll(struct napi_struct *napi, int budget)
+{
+	struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
+	struct ena_ring *tx_ring, *rx_ring;
+
+	u32 tx_work_done;
+	u32 rx_work_done;
+	int tx_budget;
+	int napi_comp_call = 0;
+	int ret;
+
+	tx_ring = ena_napi->tx_ring;
+	rx_ring = ena_napi->rx_ring;
+
+	tx_budget = tx_ring->ring_size / ENA_TX_POLL_BUDGET_DIVIDER;
+
+	if (!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
+	    test_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags)) {
+		napi_complete_done(napi, 0);
+		return 0;
+	}
+
+	tx_work_done = ena_clean_tx_irq(tx_ring, tx_budget);
+	rx_work_done = ena_clean_rx_irq(rx_ring, napi, budget);
+
+	if ((budget > rx_work_done) && (tx_budget > tx_work_done)) {
+		napi_complete_done(napi, rx_work_done);
+
+		napi_comp_call = 1;
+		/* We apply adaptive moderation on Rx path only.
+		 * Tx uses static interrupt moderation.
+		 */
+		if (ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev))
+			ena_adjust_adaptive_rx_intr_moderation(ena_napi);
+
+		ena_unmask_interrupt(tx_ring, rx_ring);
+
+		ena_update_ring_numa_node(tx_ring, rx_ring);
+
+		ret = rx_work_done;
+	} else {
+		ret = budget;
+	}
+
+	u64_stats_update_begin(&tx_ring->syncp);
+	tx_ring->tx_stats.napi_comp += napi_comp_call;
+	tx_ring->tx_stats.tx_poll++;
+	u64_stats_update_end(&tx_ring->syncp);
+
+	return ret;
+}
+
+static irqreturn_t ena_intr_msix_mgmnt(int irq, void *data)
+{
+	struct ena_adapter *adapter = (struct ena_adapter *)data;
+
+	ena_com_admin_q_comp_intr_handler(adapter->ena_dev);
+
+	/* Don't call the aenq handler before probe is done */
+	if (likely(test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)))
+		ena_com_aenq_intr_handler(adapter->ena_dev, data);
+
+	return IRQ_HANDLED;
+}
+
+/* ena_intr_msix_io - MSI-X Interrupt Handler for Tx/Rx
+ * @irq: interrupt number
+ * @data: pointer to a network interface private napi device structure
+ */
+static irqreturn_t ena_intr_msix_io(int irq, void *data)
+{
+	struct ena_napi *ena_napi = data;
+
+	ena_napi->tx_ring->first_interrupt = true;
+	ena_napi->rx_ring->first_interrupt = true;
+
+	napi_schedule_irqoff(&ena_napi->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int ena_enable_msix(struct ena_adapter *adapter, int num_queues)
+{
+	int i, msix_vecs, rc;
+
+	if (test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) {
+		netif_err(adapter, probe, adapter->netdev,
+			  "Error, MSI-X is already enabled\n");
+		return -EPERM;
+	}
+
+	/* Reserved the max msix vectors we might need */
+	msix_vecs = ENA_MAX_MSIX_VEC(num_queues);
+	netif_dbg(adapter, probe, adapter->netdev,
+		  "trying to enable MSI-X, vectors %d\n", msix_vecs);
+
+	adapter->msix_entries = vzalloc(msix_vecs * sizeof(struct msix_entry));
+
+	if (!adapter->msix_entries)
+		return -ENOMEM;
+
+	for (i = 0; i < msix_vecs; i++)
+		adapter->msix_entries[i].entry = i;
+
+	rc = pci_enable_msix(adapter->pdev, adapter->msix_entries, msix_vecs);
+	if (rc != 0) {
+		netif_err(adapter, probe, adapter->netdev,
+			  "Failed to enable MSI-X, vectors %d rc %d\n",
+			  msix_vecs, rc);
+		return -ENOSPC;
+	}
+
+	netif_dbg(adapter, probe, adapter->netdev, "enable MSI-X, vectors %d\n",
+		  msix_vecs);
+
+	if (msix_vecs >= 1) {
+		if (ena_init_rx_cpu_rmap(adapter))
+			netif_warn(adapter, probe, adapter->netdev,
+				   "Failed to map IRQs to CPUs\n");
+	}
+
+	adapter->msix_vecs = msix_vecs;
+	set_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags);
+
+	return 0;
+}
+
+static void ena_setup_mgmnt_intr(struct ena_adapter *adapter)
+{
+	u32 cpu;
+
+	snprintf(adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].name,
+		 ENA_IRQNAME_SIZE, "ena-mgmnt@pci:%s",
+		 pci_name(adapter->pdev));
+	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].handler =
+		ena_intr_msix_mgmnt;
+	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].data = adapter;
+	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].vector =
+		adapter->msix_entries[ENA_MGMNT_IRQ_IDX].vector;
+	cpu = cpumask_first(cpu_online_mask);
+	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].cpu = cpu;
+	cpumask_set_cpu(cpu,
+			&adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].affinity_hint_mask);
+}
+
+static void ena_setup_io_intr(struct ena_adapter *adapter)
+{
+	struct net_device *netdev;
+	int irq_idx, i, cpu;
+
+	netdev = adapter->netdev;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		irq_idx = ENA_IO_IRQ_IDX(i);
+		cpu = i % num_online_cpus();
+
+		snprintf(adapter->irq_tbl[irq_idx].name, ENA_IRQNAME_SIZE,
+			 "%s-Tx-Rx-%d", netdev->name, i);
+		adapter->irq_tbl[irq_idx].handler = ena_intr_msix_io;
+		adapter->irq_tbl[irq_idx].data = &adapter->ena_napi[i];
+		adapter->irq_tbl[irq_idx].vector =
+			adapter->msix_entries[irq_idx].vector;
+		adapter->irq_tbl[irq_idx].cpu = cpu;
+
+		cpumask_set_cpu(cpu,
+				&adapter->irq_tbl[irq_idx].affinity_hint_mask);
+	}
+}
+
+static int ena_request_mgmnt_irq(struct ena_adapter *adapter)
+{
+	unsigned long flags = 0;
+	struct ena_irq *irq;
+	int rc;
+
+	irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
+	rc = request_irq(irq->vector, irq->handler, flags, irq->name,
+			 irq->data);
+	if (rc) {
+		netif_err(adapter, probe, adapter->netdev,
+			  "failed to request admin irq\n");
+		return rc;
+	}
+
+	netif_dbg(adapter, probe, adapter->netdev,
+		  "set affinity hint of mgmnt irq.to 0x%lx (irq vector: %d)\n",
+		  irq->affinity_hint_mask.bits[0], irq->vector);
+
+	irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
+
+	return rc;
+}
+
+static int ena_request_io_irq(struct ena_adapter *adapter)
+{
+	unsigned long flags = 0;
+	struct ena_irq *irq;
+	int rc = 0, i, k;
+
+	if (!test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "Failed to request I/O IRQ: MSI-X is not enabled\n");
+		return -EINVAL;
+	}
+
+	for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
+		irq = &adapter->irq_tbl[i];
+		rc = request_irq(irq->vector, irq->handler, flags, irq->name,
+				 irq->data);
+		if (rc) {
+			netif_err(adapter, ifup, adapter->netdev,
+				  "Failed to request I/O IRQ. index %d rc %d\n",
+				   i, rc);
+			goto err;
+		}
+
+		netif_dbg(adapter, ifup, adapter->netdev,
+			  "set affinity hint of irq. index %d to 0x%lx (irq vector: %d)\n",
+			  i, irq->affinity_hint_mask.bits[0], irq->vector);
+
+		irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
+	}
+
+	return rc;
+
+err:
+	for (k = ENA_IO_IRQ_FIRST_IDX; k < i; k++) {
+		irq = &adapter->irq_tbl[k];
+		free_irq(irq->vector, irq->data);
+	}
+
+	return rc;
+}
+
+static void ena_free_mgmnt_irq(struct ena_adapter *adapter)
+{
+	struct ena_irq *irq;
+
+	irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
+	synchronize_irq(irq->vector);
+	irq_set_affinity_hint(irq->vector, NULL);
+	free_irq(irq->vector, irq->data);
+}
+
+static void ena_free_io_irq(struct ena_adapter *adapter)
+{
+	struct ena_irq *irq;
+	int i;
+
+#ifdef CONFIG_RFS_ACCEL
+	if (adapter->msix_vecs >= 1) {
+		free_irq_cpu_rmap(adapter->netdev->rx_cpu_rmap);
+		adapter->netdev->rx_cpu_rmap = NULL;
+	}
+#endif /* CONFIG_RFS_ACCEL */
+
+	for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
+		irq = &adapter->irq_tbl[i];
+		irq_set_affinity_hint(irq->vector, NULL);
+		free_irq(irq->vector, irq->data);
+	}
+}
+
+static void ena_disable_msix(struct ena_adapter *adapter)
+{
+	if (test_and_clear_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags))
+		pci_disable_msix(adapter->pdev);
+
+	if (adapter->msix_entries)
+		vfree(adapter->msix_entries);
+	adapter->msix_entries = NULL;
+}
+
+static void ena_disable_io_intr_sync(struct ena_adapter *adapter)
+{
+	int i;
+
+	if (!netif_running(adapter->netdev))
+		return;
+
+	for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++)
+		synchronize_irq(adapter->irq_tbl[i].vector);
+}
+
+static void ena_del_napi(struct ena_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++)
+		netif_napi_del(&adapter->ena_napi[i].napi);
+}
+
+static void ena_init_napi(struct ena_adapter *adapter)
+{
+	struct ena_napi *napi;
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		napi = &adapter->ena_napi[i];
+
+		netif_napi_add(adapter->netdev,
+			       &adapter->ena_napi[i].napi,
+			       ena_io_poll,
+			       ENA_NAPI_BUDGET);
+		napi->rx_ring = &adapter->rx_ring[i];
+		napi->tx_ring = &adapter->tx_ring[i];
+		napi->qid = i;
+	}
+}
+
+static void ena_napi_disable_all(struct ena_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++)
+		napi_disable(&adapter->ena_napi[i].napi);
+}
+
+static void ena_napi_enable_all(struct ena_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++)
+		napi_enable(&adapter->ena_napi[i].napi);
+}
+
+/* Configure the Rx forwarding */
+static int ena_rss_configure(struct ena_adapter *adapter)
+{
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	int rc;
+
+	/* In case the RSS table wasn't initialized by probe */
+	if (!ena_dev->rss.tbl_log_size) {
+		rc = ena_rss_init_default(adapter);
+		if (rc && (rc != -EOPNOTSUPP)) {
+			netif_err(adapter, ifup, adapter->netdev,
+				  "Failed to init RSS rc: %d\n", rc);
+			return rc;
+		}
+	}
+
+	/* Set indirect table */
+	rc = ena_com_indirect_table_set(ena_dev);
+	if (unlikely(rc && rc != -EOPNOTSUPP))
+		return rc;
+
+	/* Configure hash function (if supported) */
+	rc = ena_com_set_hash_function(ena_dev);
+	if (unlikely(rc && (rc != -EOPNOTSUPP)))
+		return rc;
+
+	/* Configure hash inputs (if supported) */
+	rc = ena_com_set_hash_ctrl(ena_dev);
+	if (unlikely(rc && (rc != -EOPNOTSUPP)))
+		return rc;
+
+	return 0;
+}
+
+static int ena_up_complete(struct ena_adapter *adapter)
+{
+	int rc, i;
+
+	rc = ena_rss_configure(adapter);
+	if (rc)
+		return rc;
+
+	ena_change_mtu(adapter->netdev, adapter->netdev->mtu);
+
+	ena_refill_all_rx_bufs(adapter);
+
+	/* enable transmits */
+	netif_tx_start_all_queues(adapter->netdev);
+
+	ena_napi_enable_all(adapter);
+
+	/* Enable completion queues interrupt */
+	for (i = 0; i < adapter->num_queues; i++)
+		ena_unmask_interrupt(&adapter->tx_ring[i],
+				     &adapter->rx_ring[i]);
+
+	/* schedule napi in case we had pending packets
+	 * from the last time we disable napi
+	 */
+	for (i = 0; i < adapter->num_queues; i++)
+		napi_schedule(&adapter->ena_napi[i].napi);
+
+	return 0;
+}
+
+static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid)
+{
+	struct ena_com_create_io_ctx ctx;
+	struct ena_com_dev *ena_dev;
+	struct ena_ring *tx_ring;
+	u32 msix_vector;
+	u16 ena_qid;
+	int rc;
+
+	ena_dev = adapter->ena_dev;
+
+	tx_ring = &adapter->tx_ring[qid];
+	msix_vector = ENA_IO_IRQ_IDX(qid);
+	ena_qid = ENA_IO_TXQ_IDX(qid);
+
+	memset(&ctx, 0x0, sizeof(ctx));
+
+	ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX;
+	ctx.qid = ena_qid;
+	ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
+	ctx.msix_vector = msix_vector;
+	ctx.queue_size = tx_ring->ring_size;
+	ctx.numa_node = cpu_to_node(tx_ring->cpu);
+
+	rc = ena_com_create_io_queue(ena_dev, &ctx);
+	if (rc) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "Failed to create I/O TX queue num %d rc: %d\n",
+			  qid, rc);
+		return rc;
+	}
+
+	rc = ena_com_get_io_handlers(ena_dev, ena_qid,
+				     &tx_ring->ena_com_io_sq,
+				     &tx_ring->ena_com_io_cq);
+	if (rc) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "Failed to get TX queue handlers. TX queue num %d rc: %d\n",
+			  qid, rc);
+		ena_com_destroy_io_queue(ena_dev, ena_qid);
+		return rc;
+	}
+
+	ena_com_update_numa_node(tx_ring->ena_com_io_cq, ctx.numa_node);
+	return rc;
+}
+
+static int ena_create_all_io_tx_queues(struct ena_adapter *adapter)
+{
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	int rc, i;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		rc = ena_create_io_tx_queue(adapter, i);
+		if (rc)
+			goto create_err;
+	}
+
+	return 0;
+
+create_err:
+	while (i--)
+		ena_com_destroy_io_queue(ena_dev, ENA_IO_TXQ_IDX(i));
+
+	return rc;
+}
+
+static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid)
+{
+	struct ena_com_dev *ena_dev;
+	struct ena_com_create_io_ctx ctx;
+	struct ena_ring *rx_ring;
+	u32 msix_vector;
+	u16 ena_qid;
+	int rc;
+
+	ena_dev = adapter->ena_dev;
+
+	rx_ring = &adapter->rx_ring[qid];
+	msix_vector = ENA_IO_IRQ_IDX(qid);
+	ena_qid = ENA_IO_RXQ_IDX(qid);
+
+	memset(&ctx, 0x0, sizeof(ctx));
+
+	ctx.qid = ena_qid;
+	ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
+	ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+	ctx.msix_vector = msix_vector;
+	ctx.queue_size = rx_ring->ring_size;
+	ctx.numa_node = cpu_to_node(rx_ring->cpu);
+
+	rc = ena_com_create_io_queue(ena_dev, &ctx);
+	if (rc) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "Failed to create I/O RX queue num %d rc: %d\n",
+			  qid, rc);
+		return rc;
+	}
+
+	rc = ena_com_get_io_handlers(ena_dev, ena_qid,
+				     &rx_ring->ena_com_io_sq,
+				     &rx_ring->ena_com_io_cq);
+	if (rc) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "Failed to get RX queue handlers. RX queue num %d rc: %d\n",
+			  qid, rc);
+		ena_com_destroy_io_queue(ena_dev, ena_qid);
+		return rc;
+	}
+
+	ena_com_update_numa_node(rx_ring->ena_com_io_cq, ctx.numa_node);
+
+	return rc;
+}
+
+static int ena_create_all_io_rx_queues(struct ena_adapter *adapter)
+{
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	int rc, i;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		rc = ena_create_io_rx_queue(adapter, i);
+		if (rc)
+			goto create_err;
+		INIT_WORK(&adapter->ena_napi[i].dim.work, ena_dim_work);
+	}
+
+	return 0;
+
+create_err:
+	while (i--) {
+		cancel_work_sync(&adapter->ena_napi[i].dim.work);
+		ena_com_destroy_io_queue(ena_dev, ENA_IO_RXQ_IDX(i));
+	}
+
+	return rc;
+}
+
+static void set_io_rings_size(struct ena_adapter *adapter,
+				     int new_tx_size, int new_rx_size)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		adapter->tx_ring[i].ring_size = new_tx_size;
+		adapter->rx_ring[i].ring_size = new_rx_size;
+	}
+}
+
+/* This function allows queue allocation to backoff when the system is
+ * low on memory. If there is not enough memory to allocate io queues
+ * the driver will try to allocate smaller queues.
+ *
+ * The backoff algorithm is as follows:
+ *  1. Try to allocate TX and RX and if successful.
+ *  1.1. return success
+ *
+ *  2. Divide by 2 the size of the larger of RX and TX queues (or both if their size is the same).
+ *
+ *  3. If TX or RX is smaller than 256
+ *  3.1. return failure.
+ *  4. else
+ *  4.1. go back to 1.
+ */
+static int create_queues_with_size_backoff(struct ena_adapter *adapter)
+{
+	int rc, cur_rx_ring_size, cur_tx_ring_size;
+	int new_rx_ring_size, new_tx_ring_size;
+
+	/* current queue sizes might be set to smaller than the requested
+	 * ones due to past queue allocation failures.
+	 */
+	set_io_rings_size(adapter, adapter->requested_tx_ring_size,
+			  adapter->requested_rx_ring_size);
+
+	while (1) {
+		rc = ena_setup_all_tx_resources(adapter);
+		if (rc)
+			goto err_setup_tx;
+
+		rc = ena_create_all_io_tx_queues(adapter);
+		if (rc)
+			goto err_create_tx_queues;
+
+		rc = ena_setup_all_rx_resources(adapter);
+		if (rc)
+			goto err_setup_rx;
+
+		rc = ena_create_all_io_rx_queues(adapter);
+		if (rc)
+			goto err_create_rx_queues;
+
+		return 0;
+
+err_create_rx_queues:
+		ena_free_all_io_rx_resources(adapter);
+err_setup_rx:
+		ena_destroy_all_tx_queues(adapter);
+err_create_tx_queues:
+		ena_free_all_io_tx_resources(adapter);
+err_setup_tx:
+		if (rc != -ENOMEM) {
+			netif_err(adapter, ifup, adapter->netdev,
+				  "Queue creation failed with error code %d\n",
+				  rc);
+			return rc;
+		}
+
+		cur_tx_ring_size = adapter->tx_ring[0].ring_size;
+		cur_rx_ring_size = adapter->rx_ring[0].ring_size;
+
+		netif_err(adapter, ifup, adapter->netdev,
+			  "Not enough memory to create queues with sizes TX=%d, RX=%d\n",
+			  cur_tx_ring_size, cur_rx_ring_size);
+
+		new_tx_ring_size = cur_tx_ring_size;
+		new_rx_ring_size = cur_rx_ring_size;
+
+		/* Decrease the size of the larger queue, or
+		 * decrease both if they are the same size.
+		 */
+		if (cur_rx_ring_size <= cur_tx_ring_size)
+			new_tx_ring_size = cur_tx_ring_size / 2;
+		if (cur_rx_ring_size >= cur_tx_ring_size)
+			new_rx_ring_size = cur_rx_ring_size / 2;
+
+		if (new_tx_ring_size < ENA_MIN_RING_SIZE ||
+		    new_rx_ring_size < ENA_MIN_RING_SIZE) {
+			netif_err(adapter, ifup, adapter->netdev,
+				  "Queue creation failed with the smallest possible queue size of %d for both queues. Not retrying with smaller queues\n",
+				  ENA_MIN_RING_SIZE);
+			return rc;
+		}
+
+		netif_err(adapter, ifup, adapter->netdev,
+			  "Retrying queue creation with sizes TX=%d, RX=%d\n",
+			  new_tx_ring_size,
+			  new_rx_ring_size);
+
+		set_io_rings_size(adapter, new_tx_ring_size,
+				  new_rx_ring_size);
+	}
+}
+
+static int ena_up(struct ena_adapter *adapter)
+{
+	int rc;
+
+	netdev_dbg(adapter->netdev, "%s\n", __func__);
+
+	ena_setup_io_intr(adapter);
+
+	/* napi poll functions should be initialized before running
+	 * request_irq(), to handle a rare condition where there is a pending
+	 * interrupt, causing the ISR to fire immediately while the poll
+	 * function wasn't set yet, causing a null dereference
+	 */
+	ena_init_napi(adapter);
+
+	rc = ena_request_io_irq(adapter);
+	if (rc)
+		goto err_req_irq;
+
+	rc = create_queues_with_size_backoff(adapter);
+	if (rc)
+		goto err_create_queues_with_backoff;
+
+	rc = ena_up_complete(adapter);
+	if (rc)
+		goto err_up;
+
+	if (test_bit(ENA_FLAG_LINK_UP, &adapter->flags))
+		netif_carrier_on(adapter->netdev);
+
+	u64_stats_update_begin(&adapter->syncp);
+	adapter->dev_stats.interface_up++;
+	u64_stats_update_end(&adapter->syncp);
+
+	set_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+
+	return rc;
+
+err_up:
+	ena_destroy_all_tx_queues(adapter);
+	ena_free_all_io_tx_resources(adapter);
+	ena_destroy_all_rx_queues(adapter);
+	ena_free_all_io_rx_resources(adapter);
+err_create_queues_with_backoff:
+	ena_free_io_irq(adapter);
+err_req_irq:
+	ena_del_napi(adapter);
+
+	return rc;
+}
+
+static void ena_down(struct ena_adapter *adapter)
+{
+	netif_info(adapter, ifdown, adapter->netdev, "%s\n", __func__);
+
+	clear_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+
+	u64_stats_update_begin(&adapter->syncp);
+	adapter->dev_stats.interface_down++;
+	u64_stats_update_end(&adapter->syncp);
+
+	netif_carrier_off(adapter->netdev);
+	netif_tx_disable(adapter->netdev);
+
+	/* After this point the napi handler won't enable the tx queue */
+	ena_napi_disable_all(adapter);
+
+	/* After destroy the queue there won't be any new interrupts */
+
+	if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) {
+		int rc;
+
+		rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
+		if (rc)
+			dev_err(&adapter->pdev->dev, "Device reset failed\n");
+		/* stop submitting admin commands on a device that was reset */
+		ena_com_set_admin_running_state(adapter->ena_dev, false);
+	}
+
+	ena_destroy_all_io_queues(adapter);
+
+	ena_disable_io_intr_sync(adapter);
+	ena_free_io_irq(adapter);
+	ena_del_napi(adapter);
+
+	ena_free_all_tx_bufs(adapter);
+	ena_free_all_rx_bufs(adapter);
+	ena_free_all_io_tx_resources(adapter);
+	ena_free_all_io_rx_resources(adapter);
+}
+
+/* ena_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int ena_open(struct net_device *netdev)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	int rc;
+
+	/* Notify the stack of the actual queue counts. */
+	rc = netif_set_real_num_tx_queues(netdev, adapter->num_queues);
+	if (rc) {
+		netif_err(adapter, ifup, netdev, "Can't set num tx queues\n");
+		return rc;
+	}
+
+	rc = netif_set_real_num_rx_queues(netdev, adapter->num_queues);
+	if (rc) {
+		netif_err(adapter, ifup, netdev, "Can't set num rx queues\n");
+		return rc;
+	}
+
+	rc = ena_up(adapter);
+	if (rc)
+		return rc;
+
+	return rc;
+}
+
+/* ena_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int ena_close(struct net_device *netdev)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	netif_dbg(adapter, ifdown, netdev, "%s\n", __func__);
+
+	if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
+		return 0;
+
+	if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
+		ena_down(adapter);
+
+	/* Check for device status and issue reset if needed*/
+	check_for_admin_com_state(adapter);
+	if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
+		netif_err(adapter, ifdown, adapter->netdev,
+			  "Destroy failure, restarting device\n");
+		ena_dump_stats_to_dmesg(adapter);
+		/* rtnl lock already obtained in dev_ioctl() layer */
+		ena_destroy_device(adapter, false);
+		ena_restore_device(adapter);
+	}
+
+	return 0;
+}
+
+int ena_update_queue_sizes(struct ena_adapter *adapter,
+			   u32 new_tx_size,
+			   u32 new_rx_size)
+{
+	bool dev_up;
+
+	dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+	ena_close(adapter->netdev);
+	adapter->requested_tx_ring_size = new_tx_size;
+	adapter->requested_rx_ring_size = new_rx_size;
+	ena_init_io_rings(adapter);
+	return dev_up ? ena_up(adapter) : 0;
+}
+
+static void ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx, struct sk_buff *skb)
+{
+	u32 mss = skb_shinfo(skb)->gso_size;
+	struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
+	u8 l4_protocol = 0;
+
+	if ((skb->ip_summed == CHECKSUM_PARTIAL) || mss) {
+		ena_tx_ctx->l4_csum_enable = 1;
+		if (mss) {
+			ena_tx_ctx->tso_enable = 1;
+			ena_meta->l4_hdr_len = tcp_hdr(skb)->doff;
+			ena_tx_ctx->l4_csum_partial = 0;
+		} else {
+			ena_tx_ctx->tso_enable = 0;
+			ena_meta->l4_hdr_len = 0;
+			ena_tx_ctx->l4_csum_partial = 1;
+		}
+
+		switch (ip_hdr(skb)->version) {
+		case IPVERSION:
+			ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV4;
+			if (ip_hdr(skb)->frag_off & htons(IP_DF))
+				ena_tx_ctx->df = 1;
+			if (mss)
+				ena_tx_ctx->l3_csum_enable = 1;
+			l4_protocol = ip_hdr(skb)->protocol;
+			break;
+		case 6:
+			ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV6;
+			l4_protocol = ipv6_hdr(skb)->nexthdr;
+			break;
+		default:
+			break;
+		}
+
+		if (l4_protocol == IPPROTO_TCP)
+			ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_TCP;
+		else
+			ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_UDP;
+
+		ena_meta->mss = mss;
+		ena_meta->l3_hdr_len = skb_network_header_len(skb);
+		ena_meta->l3_hdr_offset = skb_network_offset(skb);
+		ena_tx_ctx->meta_valid = 1;
+
+	} else {
+		ena_tx_ctx->meta_valid = 0;
+	}
+}
+
+static int ena_check_and_linearize_skb(struct ena_ring *tx_ring,
+				       struct sk_buff *skb)
+{
+	int num_frags, header_len, rc;
+
+	num_frags = skb_shinfo(skb)->nr_frags;
+	header_len = skb_headlen(skb);
+
+	if (num_frags < tx_ring->sgl_size)
+		return 0;
+
+	if ((num_frags == tx_ring->sgl_size) &&
+	    (header_len < tx_ring->tx_max_header_size))
+		return 0;
+
+	u64_stats_update_begin(&tx_ring->syncp);
+	tx_ring->tx_stats.linearize++;
+	u64_stats_update_end(&tx_ring->syncp);
+
+	rc = skb_linearize(skb);
+	if (unlikely(rc)) {
+		u64_stats_update_begin(&tx_ring->syncp);
+		tx_ring->tx_stats.linearize_failed++;
+		u64_stats_update_end(&tx_ring->syncp);
+	}
+
+	return rc;
+}
+
+static int ena_tx_map_skb(struct ena_ring *tx_ring,
+			  struct ena_tx_buffer *tx_info,
+			  struct sk_buff *skb,
+			  void **push_hdr,
+			  u16 *header_len)
+{
+	struct ena_adapter *adapter = tx_ring->adapter;
+	struct ena_com_buf *ena_buf;
+	dma_addr_t dma;
+	u32 skb_head_len, frag_len, last_frag;
+	u16 push_len = 0;
+	u16 delta = 0;
+	int i = 0;
+
+	skb_head_len = skb_headlen(skb);
+	tx_info->skb = skb;
+	ena_buf = tx_info->bufs;
+
+	if (tx_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
+		/* When the device is LLQ mode, the driver will copy
+		 * the header into the device memory space.
+		 * the ena_com layer assume the header is in a linear
+		 * memory space.
+		 * This assumption might be wrong since part of the header
+		 * can be in the fragmented buffers.
+		 * Use skb_header_pointer to make sure the header is in a
+		 * linear memory space.
+		 */
+
+		push_len = min_t(u32, skb->len, tx_ring->tx_max_header_size);
+		*push_hdr = skb_header_pointer(skb, 0, push_len,
+					       tx_ring->push_buf_intermediate_buf);
+		*header_len = push_len;
+		if (unlikely(skb->data != *push_hdr)) {
+			u64_stats_update_begin(&tx_ring->syncp);
+			tx_ring->tx_stats.llq_buffer_copy++;
+			u64_stats_update_end(&tx_ring->syncp);
+
+			delta = push_len - skb_head_len;
+		}
+	} else {
+		*push_hdr = NULL;
+		*header_len = min_t(u32, skb_head_len,
+				    tx_ring->tx_max_header_size);
+	}
+
+	netif_dbg(adapter, tx_queued, adapter->netdev,
+		  "skb: %p header_buf->vaddr: %p push_len: %d\n", skb,
+		  *push_hdr, push_len);
+
+	if (skb_head_len > push_len) {
+		dma = dma_map_single(tx_ring->dev, skb->data + push_len,
+				     skb_head_len - push_len, DMA_TO_DEVICE);
+		if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
+			goto error_report_dma_error;
+
+		ena_buf->paddr = dma;
+		ena_buf->len = skb_head_len - push_len;
+
+		ena_buf++;
+		tx_info->num_of_bufs++;
+		tx_info->map_linear_data = 1;
+	} else {
+		tx_info->map_linear_data = 0;
+	}
+
+	last_frag = skb_shinfo(skb)->nr_frags;
+
+	for (i = 0; i < last_frag; i++) {
+		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		frag_len = skb_frag_size(frag);
+
+		if (unlikely(delta >= frag_len)) {
+			delta -= frag_len;
+			continue;
+		}
+
+		dma = skb_frag_dma_map(tx_ring->dev, frag, delta,
+				       frag_len - delta, DMA_TO_DEVICE);
+		if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
+			goto error_report_dma_error;
+
+		ena_buf->paddr = dma;
+		ena_buf->len = frag_len - delta;
+		ena_buf++;
+		tx_info->num_of_bufs++;
+		delta = 0;
+	}
+
+	return 0;
+
+error_report_dma_error:
+	u64_stats_update_begin(&tx_ring->syncp);
+	tx_ring->tx_stats.dma_mapping_err++;
+	u64_stats_update_end(&tx_ring->syncp);
+	netdev_warn(adapter->netdev, "failed to map skb\n");
+
+	tx_info->skb = NULL;
+
+	tx_info->num_of_bufs += i;
+	ena_unmap_tx_skb(tx_ring, tx_info);
+
+	return -EINVAL;
+}
+
+/* Called with netif_tx_lock. */
+static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ena_adapter *adapter = netdev_priv(dev);
+	struct ena_tx_buffer *tx_info;
+	struct ena_com_tx_ctx ena_tx_ctx;
+	struct ena_ring *tx_ring;
+	struct netdev_queue *txq;
+	void *push_hdr;
+	u16 next_to_use, req_id, header_len;
+	int qid, rc, nb_hw_desc;
+
+	netif_dbg(adapter, tx_queued, dev, "%s skb %p\n", __func__, skb);
+	/*  Determine which tx ring we will be placed on */
+	qid = skb_get_queue_mapping(skb);
+	tx_ring = &adapter->tx_ring[qid];
+	txq = netdev_get_tx_queue(dev, qid);
+
+	rc = ena_check_and_linearize_skb(tx_ring, skb);
+	if (unlikely(rc))
+		goto error_drop_packet;
+
+	skb_tx_timestamp(skb);
+
+	next_to_use = tx_ring->next_to_use;
+	req_id = tx_ring->free_ids[next_to_use];
+	tx_info = &tx_ring->tx_buffer_info[req_id];
+	tx_info->num_of_bufs = 0;
+
+	WARN(tx_info->skb, "SKB isn't NULL req_id %d\n", req_id);
+
+	rc = ena_tx_map_skb(tx_ring, tx_info, skb, &push_hdr, &header_len);
+	if (unlikely(rc))
+		goto error_drop_packet;
+
+	memset(&ena_tx_ctx, 0x0, sizeof(struct ena_com_tx_ctx));
+	ena_tx_ctx.ena_bufs = tx_info->bufs;
+	ena_tx_ctx.push_header = push_hdr;
+	ena_tx_ctx.num_bufs = tx_info->num_of_bufs;
+	ena_tx_ctx.req_id = req_id;
+	ena_tx_ctx.header_len = header_len;
+
+	/* set flags and meta data */
+	ena_tx_csum(&ena_tx_ctx, skb);
+
+	if (unlikely(ena_com_is_doorbell_needed(tx_ring->ena_com_io_sq, &ena_tx_ctx))) {
+		netif_dbg(adapter, tx_queued, dev,
+			  "llq tx max burst size of queue %d achieved, writing doorbell to send burst\n",
+			  qid);
+		ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
+	}
+
+	/* prepare the packet's descriptors to dma engine */
+	rc = ena_com_prepare_tx(tx_ring->ena_com_io_sq, &ena_tx_ctx,
+				&nb_hw_desc);
+
+	/* ena_com_prepare_tx() can't fail due to overflow of tx queue,
+	 * since the number of free descriptors in the queue is checked
+	 * after sending the previous packet. In case there isn't enough
+	 * space in the queue for the next packet, it is stopped
+	 * until there is again enough available space in the queue.
+	 * All other failure reasons of ena_com_prepare_tx() are fatal
+	 * and therefore require a device reset.
+	 */
+	if (unlikely(rc)) {
+		netif_err(adapter, tx_queued, dev,
+			  "failed to prepare tx bufs\n");
+		u64_stats_update_begin(&tx_ring->syncp);
+		tx_ring->tx_stats.prepare_ctx_err++;
+		u64_stats_update_end(&tx_ring->syncp);
+		adapter->reset_reason = ENA_REGS_RESET_DRIVER_INVALID_STATE;
+		set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+		goto error_unmap_dma;
+	}
+
+	netdev_tx_sent_queue(txq, skb->len);
+
+	u64_stats_update_begin(&tx_ring->syncp);
+	tx_ring->tx_stats.cnt++;
+	tx_ring->tx_stats.bytes += skb->len;
+	u64_stats_update_end(&tx_ring->syncp);
+
+	tx_info->tx_descs = nb_hw_desc;
+	tx_info->last_jiffies = jiffies;
+	tx_info->print_once = 0;
+
+	tx_ring->next_to_use = ENA_TX_RING_IDX_NEXT(next_to_use,
+		tx_ring->ring_size);
+
+	/* stop the queue when no more space available, the packet can have up
+	 * to sgl_size + 2. one for the meta descriptor and one for header
+	 * (if the header is larger than tx_max_header_size).
+	 */
+	if (unlikely(!ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+						   tx_ring->sgl_size + 2))) {
+		netif_dbg(adapter, tx_queued, dev, "%s stop queue %d\n",
+			  __func__, qid);
+
+		netif_tx_stop_queue(txq);
+		u64_stats_update_begin(&tx_ring->syncp);
+		tx_ring->tx_stats.queue_stop++;
+		u64_stats_update_end(&tx_ring->syncp);
+
+		/* There is a rare condition where this function decide to
+		 * stop the queue but meanwhile clean_tx_irq updates
+		 * next_to_completion and terminates.
+		 * The queue will remain stopped forever.
+		 * To solve this issue add a mb() to make sure that
+		 * netif_tx_stop_queue() write is vissible before checking if
+		 * there is additional space in the queue.
+		 */
+		smp_mb();
+
+		if (ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+						 ENA_TX_WAKEUP_THRESH)) {
+			netif_tx_wake_queue(txq);
+			u64_stats_update_begin(&tx_ring->syncp);
+			tx_ring->tx_stats.queue_wakeup++;
+			u64_stats_update_end(&tx_ring->syncp);
+		}
+	}
+
+	if (netif_xmit_stopped(txq) || !skb->xmit_more) {
+		/* trigger the dma engine. ena_com_write_sq_doorbell()
+		 * has a mb
+		 */
+		ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
+		u64_stats_update_begin(&tx_ring->syncp);
+		tx_ring->tx_stats.doorbells++;
+		u64_stats_update_end(&tx_ring->syncp);
+	}
+
+	return NETDEV_TX_OK;
+
+error_unmap_dma:
+	ena_unmap_tx_skb(tx_ring, tx_info);
+	tx_info->skb = NULL;
+
+error_drop_packet:
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static u16 ena_select_queue(struct net_device *dev, struct sk_buff *skb,
+			    void *accel_priv, select_queue_fallback_t fallback)
+{
+	u16 qid;
+	/* we suspect that this is good for in--kernel network services that
+	 * want to loop incoming skb rx to tx in normal user generated traffic,
+	 * most probably we will not get to this
+	 */
+	if (skb_rx_queue_recorded(skb))
+		qid = skb_get_rx_queue(skb);
+	else
+		qid = fallback(dev, skb);
+
+	return qid;
+}
+
+static void ena_config_host_info(struct ena_com_dev *ena_dev,
+				 struct pci_dev *pdev)
+{
+	struct ena_admin_host_info *host_info;
+	int rc;
+
+	/* Allocate only the host info */
+	rc = ena_com_allocate_host_info(ena_dev);
+	if (rc) {
+		pr_err("Cannot allocate host info\n");
+		return;
+	}
+
+	host_info = ena_dev->host_attr.host_info;
+
+	host_info->bdf = (pdev->bus->number << 8) | pdev->devfn;
+	host_info->os_type = ENA_ADMIN_OS_LINUX;
+	host_info->kernel_ver = LINUX_VERSION_CODE;
+	strlcpy(host_info->kernel_ver_str, utsname()->version,
+		sizeof(host_info->kernel_ver_str) - 1);
+	host_info->os_dist = 0;
+	strncpy(host_info->os_dist_str, utsname()->release,
+		sizeof(host_info->os_dist_str) - 1);
+	host_info->driver_version =
+		(DRV_MODULE_VER_MAJOR) |
+		(DRV_MODULE_VER_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) |
+		(DRV_MODULE_VER_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT) |
+		("K"[0] << ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT);
+	host_info->num_cpus = num_online_cpus();
+
+	host_info->driver_supported_features =
+		ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_MASK;
+
+	rc = ena_com_set_host_attributes(ena_dev);
+	if (rc) {
+		if (rc == -EOPNOTSUPP)
+			pr_warn("Cannot set host attributes\n");
+		else
+			pr_err("Cannot set host attributes\n");
+
+		goto err;
+	}
+
+	return;
+
+err:
+	ena_com_delete_host_info(ena_dev);
+}
+
+static void ena_config_debug_area(struct ena_adapter *adapter)
+{
+	u32 debug_area_size;
+	int rc, ss_count;
+
+	ss_count = ena_get_sset_count(adapter->netdev, ETH_SS_STATS);
+	if (ss_count <= 0) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "SS count is negative\n");
+		return;
+	}
+
+	/* allocate 32 bytes for each string and 64bit for the value */
+	debug_area_size = ss_count * ETH_GSTRING_LEN + sizeof(u64) * ss_count;
+
+	rc = ena_com_allocate_debug_area(adapter->ena_dev, debug_area_size);
+	if (rc) {
+		pr_err("Cannot allocate debug area\n");
+		return;
+	}
+
+	rc = ena_com_set_host_attributes(adapter->ena_dev);
+	if (rc) {
+		if (rc == -EOPNOTSUPP)
+			netif_warn(adapter, drv, adapter->netdev,
+				   "Cannot set host attributes\n");
+		else
+			netif_err(adapter, drv, adapter->netdev,
+				  "Cannot set host attributes\n");
+		goto err;
+	}
+
+	return;
+err:
+	ena_com_delete_debug_area(adapter->ena_dev);
+}
+
+static struct rtnl_link_stats64 *ena_get_stats64(struct net_device *netdev,
+						 struct rtnl_link_stats64 *stats)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	struct ena_ring *rx_ring, *tx_ring;
+	unsigned int start;
+	u64 rx_drops;
+	int i;
+
+	if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
+		return NULL;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		u64 bytes, packets;
+
+		tx_ring = &adapter->tx_ring[i];
+
+		do {
+			start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
+			packets = tx_ring->tx_stats.cnt;
+			bytes = tx_ring->tx_stats.bytes;
+		} while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
+
+		stats->tx_packets += packets;
+		stats->tx_bytes += bytes;
+
+		rx_ring = &adapter->rx_ring[i];
+
+		do {
+			start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
+			packets = rx_ring->rx_stats.cnt;
+			bytes = rx_ring->rx_stats.bytes;
+		} while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
+
+		stats->rx_packets += packets;
+		stats->rx_bytes += bytes;
+	}
+
+	do {
+		start = u64_stats_fetch_begin_irq(&adapter->syncp);
+		rx_drops = adapter->dev_stats.rx_drops;
+	} while (u64_stats_fetch_retry_irq(&adapter->syncp, start));
+
+	stats->rx_dropped = rx_drops;
+
+	stats->multicast = 0;
+	stats->collisions = 0;
+
+	stats->rx_length_errors = 0;
+	stats->rx_crc_errors = 0;
+	stats->rx_frame_errors = 0;
+	stats->rx_fifo_errors = 0;
+	stats->rx_missed_errors = 0;
+	stats->tx_window_errors = 0;
+
+	stats->rx_errors = 0;
+	stats->tx_errors = 0;
+
+	return stats;
+}
+
+static const struct net_device_ops ena_netdev_ops = {
+	.ndo_open		= ena_open,
+	.ndo_stop		= ena_close,
+	.ndo_start_xmit		= ena_start_xmit,
+	.ndo_select_queue	= ena_select_queue,
+	.ndo_get_stats64	= ena_get_stats64,
+	.ndo_tx_timeout		= ena_tx_timeout,
+	.ndo_change_mtu		= ena_change_mtu,
+	.ndo_set_mac_address	= NULL,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
+static int ena_device_validate_params(struct ena_adapter *adapter,
+				      struct ena_com_dev_get_features_ctx *get_feat_ctx)
+{
+	struct net_device *netdev = adapter->netdev;
+	int rc;
+
+	rc = ether_addr_equal(get_feat_ctx->dev_attr.mac_addr,
+			      adapter->mac_addr);
+	if (!rc) {
+		netif_err(adapter, drv, netdev,
+			  "Error, mac address are different\n");
+		return -EINVAL;
+	}
+
+	if (get_feat_ctx->dev_attr.max_mtu < netdev->mtu) {
+		netif_err(adapter, drv, netdev,
+			  "Error, device max mtu is smaller than netdev MTU\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ena_device_init(struct ena_com_dev *ena_dev, struct pci_dev *pdev,
+			   struct ena_com_dev_get_features_ctx *get_feat_ctx,
+			   bool *wd_state)
+{
+	struct device *dev = &pdev->dev;
+	bool readless_supported;
+	u32 aenq_groups;
+	int dma_width;
+	int rc;
+
+	rc = ena_com_mmio_reg_read_request_init(ena_dev);
+	if (rc) {
+		dev_err(dev, "failed to init mmio read less\n");
+		return rc;
+	}
+
+	/* The PCIe configuration space revision id indicate if mmio reg
+	 * read is disabled
+	 */
+	readless_supported = !(pdev->revision & ENA_MMIO_DISABLE_REG_READ);
+	ena_com_set_mmio_read_mode(ena_dev, readless_supported);
+
+	rc = ena_com_dev_reset(ena_dev, ENA_REGS_RESET_NORMAL);
+	if (rc) {
+		dev_err(dev, "Can not reset device\n");
+		goto err_mmio_read_less;
+	}
+
+	rc = ena_com_validate_version(ena_dev);
+	if (rc) {
+		dev_err(dev, "device version is too low\n");
+		goto err_mmio_read_less;
+	}
+
+	dma_width = ena_com_get_dma_width(ena_dev);
+	if (dma_width < 0) {
+		dev_err(dev, "Invalid dma width value %d", dma_width);
+		rc = dma_width;
+		goto err_mmio_read_less;
+	}
+
+	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_width));
+	if (rc) {
+		dev_err(dev, "pci_set_dma_mask failed 0x%x\n", rc);
+		goto err_mmio_read_less;
+	}
+
+	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(dma_width));
+	if (rc) {
+		dev_err(dev, "err_pci_set_consistent_dma_mask failed 0x%x\n",
+			rc);
+		goto err_mmio_read_less;
+	}
+
+	/* ENA admin level init */
+	rc = ena_com_admin_init(ena_dev, &aenq_handlers);
+	if (rc) {
+		dev_err(dev,
+			"Can not initialize ena admin queue with device\n");
+		goto err_mmio_read_less;
+	}
+
+	/* To enable the msix interrupts the driver needs to know the number
+	 * of queues. So the driver uses polling mode to retrieve this
+	 * information
+	 */
+	ena_com_set_admin_polling_mode(ena_dev, true);
+
+	ena_config_host_info(ena_dev, pdev);
+
+	/* Get Device Attributes*/
+	rc = ena_com_get_dev_attr_feat(ena_dev, get_feat_ctx);
+	if (rc) {
+		dev_err(dev, "Cannot get attribute for ena device rc=%d\n", rc);
+		goto err_admin_init;
+	}
+
+	/* Try to turn all the available aenq groups */
+	aenq_groups = BIT(ENA_ADMIN_LINK_CHANGE) |
+		BIT(ENA_ADMIN_FATAL_ERROR) |
+		BIT(ENA_ADMIN_WARNING) |
+		BIT(ENA_ADMIN_NOTIFICATION) |
+		BIT(ENA_ADMIN_KEEP_ALIVE);
+
+	aenq_groups &= get_feat_ctx->aenq.supported_groups;
+
+	rc = ena_com_set_aenq_config(ena_dev, aenq_groups);
+	if (rc) {
+		dev_err(dev, "Cannot configure aenq groups rc= %d\n", rc);
+		goto err_admin_init;
+	}
+
+	*wd_state = !!(aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE));
+
+	return 0;
+
+err_admin_init:
+	ena_com_delete_host_info(ena_dev);
+	ena_com_admin_destroy(ena_dev);
+err_mmio_read_less:
+	ena_com_mmio_reg_read_request_destroy(ena_dev);
+
+	return rc;
+}
+
+static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter,
+						    int io_vectors)
+{
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	struct device *dev = &adapter->pdev->dev;
+	int rc;
+
+	rc = ena_enable_msix(adapter, io_vectors);
+	if (rc) {
+		dev_err(dev, "Can not reserve msix vectors\n");
+		return rc;
+	}
+
+	ena_setup_mgmnt_intr(adapter);
+
+	rc = ena_request_mgmnt_irq(adapter);
+	if (rc) {
+		dev_err(dev, "Can not setup management interrupts\n");
+		goto err_disable_msix;
+	}
+
+	ena_com_set_admin_polling_mode(ena_dev, false);
+
+	ena_com_admin_aenq_enable(ena_dev);
+
+	return 0;
+
+err_disable_msix:
+	ena_disable_msix(adapter);
+
+	return rc;
+}
+
+static void ena_destroy_device(struct ena_adapter *adapter, bool graceful)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	bool dev_up;
+
+	if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
+		return;
+
+	netif_carrier_off(netdev);
+
+	del_timer_sync(&adapter->timer_service);
+
+	dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+	adapter->dev_up_before_reset = dev_up;
+	if (!graceful)
+		ena_com_set_admin_running_state(ena_dev, false);
+
+	if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
+		ena_down(adapter);
+
+	/* Stop the device from sending AENQ events (in case reset flag is set
+	 *  and device is up, ena_down() already reset the device.
+	 */
+	if (!(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags) && dev_up))
+		ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
+
+	ena_free_mgmnt_irq(adapter);
+
+	ena_disable_msix(adapter);
+
+	ena_com_abort_admin_commands(ena_dev);
+
+	ena_com_wait_for_abort_completion(ena_dev);
+
+	ena_com_admin_destroy(ena_dev);
+
+	ena_com_mmio_reg_read_request_destroy(ena_dev);
+
+	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
+
+	clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+	clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
+}
+
+static int ena_restore_device(struct ena_adapter *adapter)
+{
+	struct ena_com_dev_get_features_ctx get_feat_ctx;
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	struct pci_dev *pdev = adapter->pdev;
+	bool wd_state;
+	int rc;
+
+	set_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
+	rc = ena_device_init(ena_dev, adapter->pdev, &get_feat_ctx, &wd_state);
+	if (rc) {
+		dev_err(&pdev->dev, "Can not initialize device\n");
+		goto err;
+	}
+	adapter->wd_state = wd_state;
+
+	rc = ena_device_validate_params(adapter, &get_feat_ctx);
+	if (rc) {
+		dev_err(&pdev->dev, "Validation of device parameters failed\n");
+		goto err_device_destroy;
+	}
+
+	rc = ena_enable_msix_and_set_admin_interrupts(adapter,
+						      adapter->num_queues);
+	if (rc) {
+		dev_err(&pdev->dev, "Enable MSI-X failed\n");
+		goto err_device_destroy;
+	}
+	/* If the interface was up before the reset bring it up */
+	if (adapter->dev_up_before_reset) {
+		rc = ena_up(adapter);
+		if (rc) {
+			dev_err(&pdev->dev, "Failed to create I/O queues\n");
+			goto err_disable_msix;
+		}
+	}
+
+	set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
+
+	clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
+	if (test_bit(ENA_FLAG_LINK_UP, &adapter->flags))
+		netif_carrier_on(adapter->netdev);
+
+	mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
+	dev_err(&pdev->dev,
+		"Device reset completed successfully, Driver info: %s\n",
+		version);
+
+	return rc;
+err_disable_msix:
+	ena_free_mgmnt_irq(adapter);
+	ena_disable_msix(adapter);
+err_device_destroy:
+	ena_com_abort_admin_commands(ena_dev);
+	ena_com_wait_for_abort_completion(ena_dev);
+	ena_com_admin_destroy(ena_dev);
+	ena_com_dev_reset(ena_dev, ENA_REGS_RESET_DRIVER_INVALID_STATE);
+	ena_com_mmio_reg_read_request_destroy(ena_dev);
+err:
+	clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
+	clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
+	dev_err(&pdev->dev,
+		"Reset attempt failed. Can not reset the device\n");
+
+	return rc;
+}
+
+static void ena_fw_reset_device(struct work_struct *work)
+{
+	struct ena_adapter *adapter =
+		container_of(work, struct ena_adapter, reset_task);
+	struct pci_dev *pdev = adapter->pdev;
+
+	if (unlikely(!test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
+		dev_err(&pdev->dev,
+			"device reset schedule while reset bit is off\n");
+		return;
+	}
+	rtnl_lock();
+	ena_destroy_device(adapter, false);
+	ena_restore_device(adapter);
+	rtnl_unlock();
+}
+
+static int check_for_rx_interrupt_queue(struct ena_adapter *adapter,
+					struct ena_ring *rx_ring)
+{
+	if (likely(rx_ring->first_interrupt))
+		return 0;
+
+	if (ena_com_cq_empty(rx_ring->ena_com_io_cq))
+		return 0;
+
+	rx_ring->no_interrupt_event_cnt++;
+
+	if (rx_ring->no_interrupt_event_cnt == ENA_MAX_NO_INTERRUPT_ITERATIONS) {
+		netif_err(adapter, rx_err, adapter->netdev,
+			  "Potential MSIX issue on Rx side Queue = %d. Reset the device\n",
+			  rx_ring->qid);
+		adapter->reset_reason = ENA_REGS_RESET_MISS_INTERRUPT;
+		smp_mb__before_atomic();
+		set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
+					  struct ena_ring *tx_ring)
+{
+	struct ena_tx_buffer *tx_buf;
+	unsigned long last_jiffies;
+	u32 missed_tx = 0;
+	int i, rc = 0;
+
+	for (i = 0; i < tx_ring->ring_size; i++) {
+		tx_buf = &tx_ring->tx_buffer_info[i];
+		last_jiffies = tx_buf->last_jiffies;
+
+		if (last_jiffies == 0)
+			/* no pending Tx at this location */
+			continue;
+
+		if (unlikely(!tx_ring->first_interrupt && time_is_before_jiffies(last_jiffies +
+			     2 * adapter->missing_tx_completion_to))) {
+			/* If after graceful period interrupt is still not
+			 * received, we schedule a reset
+			 */
+			netif_err(adapter, tx_err, adapter->netdev,
+				  "Potential MSIX issue on Tx side Queue = %d. Reset the device\n",
+				  tx_ring->qid);
+			adapter->reset_reason = ENA_REGS_RESET_MISS_INTERRUPT;
+			smp_mb__before_atomic();
+			set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+			return -EIO;
+		}
+
+		if (unlikely(time_is_before_jiffies(last_jiffies +
+				adapter->missing_tx_completion_to))) {
+			if (!tx_buf->print_once)
+				netif_notice(adapter, tx_err, adapter->netdev,
+					     "Found a Tx that wasn't completed on time, qid %d, index %d.\n",
+					     tx_ring->qid, i);
+
+			tx_buf->print_once = 1;
+			missed_tx++;
+		}
+	}
+
+	if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) {
+		netif_err(adapter, tx_err, adapter->netdev,
+			  "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n",
+			  missed_tx,
+			  adapter->missing_tx_completion_threshold);
+		adapter->reset_reason =
+			ENA_REGS_RESET_MISS_TX_CMPL;
+		set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+		rc = -EIO;
+	}
+
+	u64_stats_update_begin(&tx_ring->syncp);
+	tx_ring->tx_stats.missed_tx = missed_tx;
+	u64_stats_update_end(&tx_ring->syncp);
+
+	return rc;
+}
+
+static void check_for_missing_completions(struct ena_adapter *adapter)
+{
+	struct ena_ring *tx_ring;
+	struct ena_ring *rx_ring;
+	int i, budget, rc;
+
+	/* Make sure the driver doesn't turn the device in other process */
+	smp_rmb();
+
+	if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
+		return;
+
+	if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
+		return;
+
+	if (adapter->missing_tx_completion_to == ENA_HW_HINTS_NO_TIMEOUT)
+		return;
+
+	budget = ENA_MONITORED_TX_QUEUES;
+
+	for (i = adapter->last_monitored_tx_qid; i < adapter->num_queues; i++) {
+		tx_ring = &adapter->tx_ring[i];
+		rx_ring = &adapter->rx_ring[i];
+
+		rc = check_missing_comp_in_tx_queue(adapter, tx_ring);
+		if (unlikely(rc))
+			return;
+
+		rc = check_for_rx_interrupt_queue(adapter, rx_ring);
+		if (unlikely(rc))
+			return;
+
+		budget--;
+		if (!budget)
+			break;
+	}
+
+	adapter->last_monitored_tx_qid = i % adapter->num_queues;
+}
+
+/* trigger napi schedule after 2 consecutive detections */
+#define EMPTY_RX_REFILL 2
+/* For the rare case where the device runs out of Rx descriptors and the
+ * napi handler failed to refill new Rx descriptors (due to a lack of memory
+ * for example).
+ * This case will lead to a deadlock:
+ * The device won't send interrupts since all the new Rx packets will be dropped
+ * The napi handler won't allocate new Rx descriptors so the device will be
+ * able to send new packets.
+ *
+ * This scenario can happen when the kernel's vm.min_free_kbytes is too small.
+ * It is recommended to have at least 512MB, with a minimum of 128MB for
+ * constrained environment).
+ *
+ * When such a situation is detected - Reschedule napi
+ */
+static void check_for_empty_rx_ring(struct ena_adapter *adapter)
+{
+	struct ena_ring *rx_ring;
+	int i, refill_required;
+
+	if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
+		return;
+
+	if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
+		return;
+
+	for (i = 0; i < adapter->num_queues; i++) {
+		rx_ring = &adapter->rx_ring[i];
+
+		refill_required =
+			ena_com_free_desc(rx_ring->ena_com_io_sq);
+		if (unlikely(refill_required == (rx_ring->ring_size - 1))) {
+			rx_ring->empty_rx_queue++;
+
+			if (rx_ring->empty_rx_queue >= EMPTY_RX_REFILL) {
+				u64_stats_update_begin(&rx_ring->syncp);
+				rx_ring->rx_stats.empty_rx_ring++;
+				u64_stats_update_end(&rx_ring->syncp);
+
+				netif_err(adapter, drv, adapter->netdev,
+					  "trigger refill for ring %d\n", i);
+
+				napi_schedule(rx_ring->napi);
+				rx_ring->empty_rx_queue = 0;
+			}
+		} else {
+			rx_ring->empty_rx_queue = 0;
+		}
+	}
+}
+
+/* Check for keep alive expiration */
+static void check_for_missing_keep_alive(struct ena_adapter *adapter)
+{
+	unsigned long keep_alive_expired;
+
+	if (!adapter->wd_state)
+		return;
+
+	if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT)
+		return;
+
+	keep_alive_expired = round_jiffies(adapter->last_keep_alive_jiffies +
+					   adapter->keep_alive_timeout);
+	if (unlikely(time_is_before_jiffies(keep_alive_expired))) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Keep alive watchdog timeout.\n");
+		u64_stats_update_begin(&adapter->syncp);
+		adapter->dev_stats.wd_expired++;
+		u64_stats_update_end(&adapter->syncp);
+		adapter->reset_reason = ENA_REGS_RESET_KEEP_ALIVE_TO;
+		set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+	}
+}
+
+static void check_for_admin_com_state(struct ena_adapter *adapter)
+{
+	if (unlikely(!ena_com_get_admin_running_state(adapter->ena_dev))) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "ENA admin queue is not in running state!\n");
+		u64_stats_update_begin(&adapter->syncp);
+		adapter->dev_stats.admin_q_pause++;
+		u64_stats_update_end(&adapter->syncp);
+		adapter->reset_reason = ENA_REGS_RESET_ADMIN_TO;
+		set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+	}
+}
+
+static void ena_update_hints(struct ena_adapter *adapter,
+			     struct ena_admin_ena_hw_hints *hints)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	if (hints->admin_completion_tx_timeout)
+		adapter->ena_dev->admin_queue.completion_timeout =
+			hints->admin_completion_tx_timeout * 1000;
+
+	if (hints->mmio_read_timeout)
+		/* convert to usec */
+		adapter->ena_dev->mmio_read.reg_read_to =
+			hints->mmio_read_timeout * 1000;
+
+	if (hints->missed_tx_completion_count_threshold_to_reset)
+		adapter->missing_tx_completion_threshold =
+			hints->missed_tx_completion_count_threshold_to_reset;
+
+	if (hints->missing_tx_completion_timeout) {
+		if (hints->missing_tx_completion_timeout == ENA_HW_HINTS_NO_TIMEOUT)
+			adapter->missing_tx_completion_to = ENA_HW_HINTS_NO_TIMEOUT;
+		else
+			adapter->missing_tx_completion_to =
+				msecs_to_jiffies(hints->missing_tx_completion_timeout);
+	}
+
+	if (hints->netdev_wd_timeout)
+		netdev->watchdog_timeo = msecs_to_jiffies(hints->netdev_wd_timeout);
+
+	if (hints->driver_watchdog_timeout) {
+		if (hints->driver_watchdog_timeout == ENA_HW_HINTS_NO_TIMEOUT)
+			adapter->keep_alive_timeout = ENA_HW_HINTS_NO_TIMEOUT;
+		else
+			adapter->keep_alive_timeout =
+				msecs_to_jiffies(hints->driver_watchdog_timeout);
+	}
+}
+
+static void ena_update_host_info(struct ena_admin_host_info *host_info,
+				 struct net_device *netdev)
+{
+	host_info->supported_network_features[0] =
+		netdev->features & GENMASK_ULL(31, 0);
+	host_info->supported_network_features[1] =
+		(netdev->features & GENMASK_ULL(63, 32)) >> 32;
+}
+
+static void ena_timer_service(unsigned long data)
+{
+	struct ena_adapter *adapter = (struct ena_adapter *)data;
+	u8 *debug_area = adapter->ena_dev->host_attr.debug_area_virt_addr;
+	struct ena_admin_host_info *host_info =
+		adapter->ena_dev->host_attr.host_info;
+
+	check_for_missing_keep_alive(adapter);
+
+	check_for_admin_com_state(adapter);
+
+	check_for_missing_completions(adapter);
+
+	check_for_empty_rx_ring(adapter);
+
+	if (debug_area)
+		ena_dump_stats_to_buf(adapter, debug_area);
+
+	if (host_info)
+		ena_update_host_info(host_info, adapter->netdev);
+
+	if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Trigger reset is on\n");
+		ena_dump_stats_to_dmesg(adapter);
+		queue_work(ena_wq, &adapter->reset_task);
+		return;
+	}
+
+	/* Reset the timer */
+	mod_timer(&adapter->timer_service, jiffies + HZ);
+}
+
+static int ena_calc_io_queue_num(struct pci_dev *pdev,
+				 struct ena_com_dev *ena_dev,
+				 struct ena_com_dev_get_features_ctx *get_feat_ctx)
+{
+	int io_tx_sq_num, io_tx_cq_num, io_rx_num, io_queue_num;
+
+	if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
+		struct ena_admin_queue_ext_feature_fields *max_queue_ext =
+			&get_feat_ctx->max_queue_ext.max_queue_ext;
+		io_rx_num = min_t(int, max_queue_ext->max_rx_sq_num,
+				  max_queue_ext->max_rx_cq_num);
+
+		io_tx_sq_num = max_queue_ext->max_tx_sq_num;
+		io_tx_cq_num = max_queue_ext->max_tx_cq_num;
+	} else {
+		struct ena_admin_queue_feature_desc *max_queues =
+			&get_feat_ctx->max_queues;
+		io_tx_sq_num = max_queues->max_sq_num;
+		io_tx_cq_num = max_queues->max_cq_num;
+		io_rx_num = min_t(int, io_tx_sq_num, io_tx_cq_num);
+	}
+
+	/* In case of LLQ use the llq fields for the tx SQ/CQ */
+	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+		io_tx_sq_num = get_feat_ctx->llq.max_llq_num;
+
+	io_queue_num = min_t(int, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES);
+	io_queue_num = min_t(int, io_queue_num, io_rx_num);
+	io_queue_num = min_t(int, io_queue_num, io_tx_sq_num);
+	io_queue_num = min_t(int, io_queue_num, io_tx_cq_num);
+	/* 1 IRQ for for mgmnt and 1 IRQs for each IO direction */
+	io_queue_num = min_t(int, io_queue_num, pci_msix_vec_count(pdev) - 1);
+	if (unlikely(!io_queue_num)) {
+		dev_err(&pdev->dev, "The device doesn't have io queues\n");
+		return -EFAULT;
+	}
+
+	return io_queue_num;
+}
+
+static int ena_set_queues_placement_policy(struct pci_dev *pdev,
+					   struct ena_com_dev *ena_dev,
+					   struct ena_admin_feature_llq_desc *llq,
+					   struct ena_llq_configurations *llq_default_configurations)
+{
+	bool has_mem_bar;
+	int rc;
+	u32 llq_feature_mask;
+
+	llq_feature_mask = 1 << ENA_ADMIN_LLQ;
+	if (!(ena_dev->supported_features & llq_feature_mask)) {
+		dev_err(&pdev->dev,
+			"LLQ is not supported Fallback to host mode policy.\n");
+		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+		return 0;
+	}
+
+	has_mem_bar = pci_select_bars(pdev, IORESOURCE_MEM) & BIT(ENA_MEM_BAR);
+
+	rc = ena_com_config_dev_mode(ena_dev, llq, llq_default_configurations);
+	if (unlikely(rc)) {
+		dev_err(&pdev->dev,
+			"Failed to configure the device mode.  Fallback to host mode policy.\n");
+		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+		return 0;
+	}
+
+	/* Nothing to config, exit */
+	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
+		return 0;
+
+	if (!has_mem_bar) {
+		dev_err(&pdev->dev,
+			"ENA device does not expose LLQ bar. Fallback to host mode policy.\n");
+		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+		return 0;
+	}
+
+	ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev,
+					   pci_resource_start(pdev, ENA_MEM_BAR),
+					   pci_resource_len(pdev, ENA_MEM_BAR));
+
+	if (!ena_dev->mem_bar)
+		return -EFAULT;
+
+	return 0;
+}
+
+static void ena_set_dev_offloads(struct ena_com_dev_get_features_ctx *feat,
+				 struct net_device *netdev)
+{
+	netdev_features_t dev_features = 0;
+
+	/* Set offload features */
+	if (feat->offload.tx &
+		ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK)
+		dev_features |= NETIF_F_IP_CSUM;
+
+	if (feat->offload.tx &
+		ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK)
+		dev_features |= NETIF_F_IPV6_CSUM;
+
+	if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK)
+		dev_features |= NETIF_F_TSO;
+
+	if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK)
+		dev_features |= NETIF_F_TSO6;
+
+	if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK)
+		dev_features |= NETIF_F_TSO_ECN;
+
+	if (feat->offload.rx_supported &
+		ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK)
+		dev_features |= NETIF_F_RXCSUM;
+
+	if (feat->offload.rx_supported &
+		ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK)
+		dev_features |= NETIF_F_RXCSUM;
+
+	netdev->features =
+		dev_features |
+		NETIF_F_SG |
+		NETIF_F_RXHASH |
+		NETIF_F_HIGHDMA;
+
+	netdev->hw_features |= netdev->features;
+	netdev->vlan_features |= netdev->features;
+}
+
+static void ena_set_conf_feat_params(struct ena_adapter *adapter,
+				     struct ena_com_dev_get_features_ctx *feat)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	/* Copy mac address */
+	if (!is_valid_ether_addr(feat->dev_attr.mac_addr)) {
+		eth_hw_addr_random(netdev);
+		ether_addr_copy(adapter->mac_addr, netdev->dev_addr);
+	} else {
+		ether_addr_copy(adapter->mac_addr, feat->dev_attr.mac_addr);
+		ether_addr_copy(netdev->dev_addr, adapter->mac_addr);
+	}
+
+	/* Set offload features */
+	ena_set_dev_offloads(feat, netdev);
+
+	adapter->max_mtu = feat->dev_attr.max_mtu;
+}
+
+static int ena_rss_init_default(struct ena_adapter *adapter)
+{
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	struct device *dev = &adapter->pdev->dev;
+	int rc, i;
+	u32 val;
+
+	rc = ena_com_rss_init(ena_dev, ENA_RX_RSS_TABLE_LOG_SIZE);
+	if (unlikely(rc)) {
+		dev_err(dev, "Cannot init indirect table\n");
+		goto err_rss_init;
+	}
+
+	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
+		val = ethtool_rxfh_indir_default(i, adapter->num_queues);
+		rc = ena_com_indirect_table_fill_entry(ena_dev, i,
+						       ENA_IO_RXQ_IDX(val));
+		if (unlikely(rc && (rc != -EOPNOTSUPP))) {
+			dev_err(dev, "Cannot fill indirect table\n");
+			goto err_fill_indir;
+		}
+	}
+
+	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_CRC32, NULL,
+					ENA_HASH_KEY_SIZE, 0xFFFFFFFF);
+	if (unlikely(rc && (rc != -EOPNOTSUPP))) {
+		dev_err(dev, "Cannot fill hash function\n");
+		goto err_fill_indir;
+	}
+
+	rc = ena_com_set_default_hash_ctrl(ena_dev);
+	if (unlikely(rc && (rc != -EOPNOTSUPP))) {
+		dev_err(dev, "Cannot fill hash control\n");
+		goto err_fill_indir;
+	}
+
+	return 0;
+
+err_fill_indir:
+	ena_com_rss_destroy(ena_dev);
+err_rss_init:
+
+	return rc;
+}
+
+static void ena_release_bars(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
+{
+	int release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
+
+	pci_release_selected_regions(pdev, release_bars);
+}
+
+static void set_default_llq_configurations(struct ena_llq_configurations *llq_config)
+{
+	llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
+	llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
+	llq_config->llq_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
+	llq_config->llq_num_decs_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
+	llq_config->llq_ring_entry_size_value = 128;
+}
+
+static int ena_calc_queue_size(struct ena_calc_queue_size_ctx *ctx)
+{
+	struct ena_admin_feature_llq_desc *llq = &ctx->get_feat_ctx->llq;
+	struct ena_com_dev *ena_dev = ctx->ena_dev;
+	u32 tx_queue_size = ENA_DEFAULT_RING_SIZE;
+	u32 rx_queue_size = ENA_DEFAULT_RING_SIZE;
+	u32 max_tx_queue_size;
+	u32 max_rx_queue_size;
+
+	if (ctx->ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
+		struct ena_admin_queue_ext_feature_fields *max_queue_ext =
+			&ctx->get_feat_ctx->max_queue_ext.max_queue_ext;
+		max_rx_queue_size = min_t(u32, max_queue_ext->max_rx_cq_depth,
+					  max_queue_ext->max_rx_sq_depth);
+		max_tx_queue_size = max_queue_ext->max_tx_cq_depth;
+
+		if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+			max_tx_queue_size = min_t(u32, max_tx_queue_size,
+						  llq->max_llq_depth);
+		else
+			max_tx_queue_size = min_t(u32, max_tx_queue_size,
+						  max_queue_ext->max_tx_sq_depth);
+
+		ctx->max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
+					     max_queue_ext->max_per_packet_tx_descs);
+		ctx->max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
+					     max_queue_ext->max_per_packet_rx_descs);
+	} else {
+		struct ena_admin_queue_feature_desc *max_queues =
+			&ctx->get_feat_ctx->max_queues;
+		max_rx_queue_size = min_t(u32, max_queues->max_cq_depth,
+					  max_queues->max_sq_depth);
+		max_tx_queue_size = max_queues->max_cq_depth;
+
+		if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+			max_tx_queue_size = min_t(u32, max_tx_queue_size,
+						  llq->max_llq_depth);
+		else
+			max_tx_queue_size = min_t(u32, max_tx_queue_size,
+						  max_queues->max_sq_depth);
+
+		ctx->max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
+					     max_queues->max_packet_tx_descs);
+		ctx->max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
+					     max_queues->max_packet_rx_descs);
+	}
+
+	max_tx_queue_size = rounddown_pow_of_two(max_tx_queue_size);
+	max_rx_queue_size = rounddown_pow_of_two(max_rx_queue_size);
+
+	tx_queue_size = clamp_val(tx_queue_size, ENA_MIN_RING_SIZE,
+				  max_tx_queue_size);
+	rx_queue_size = clamp_val(rx_queue_size, ENA_MIN_RING_SIZE,
+				  max_rx_queue_size);
+
+	tx_queue_size = rounddown_pow_of_two(tx_queue_size);
+	rx_queue_size = rounddown_pow_of_two(rx_queue_size);
+
+	ctx->max_tx_queue_size = max_tx_queue_size;
+	ctx->max_rx_queue_size = max_rx_queue_size;
+	ctx->tx_queue_size = tx_queue_size;
+	ctx->rx_queue_size = rx_queue_size;
+
+	return 0;
+}
+
+/* ena_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in ena_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * ena_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct ena_com_dev_get_features_ctx get_feat_ctx;
+	struct ena_calc_queue_size_ctx calc_queue_ctx = { 0 };
+	struct ena_llq_configurations llq_config;
+	struct ena_com_dev *ena_dev = NULL;
+	struct ena_adapter *adapter;
+	int io_queue_num, bars, rc;
+	struct net_device *netdev;
+	static int adapters_found;
+	char *queue_type_str;
+	bool wd_state;
+
+	dev_dbg(&pdev->dev, "%s\n", __func__);
+
+	dev_info_once(&pdev->dev, "%s", version);
+
+	rc = pci_enable_device_mem(pdev);
+	if (rc) {
+		dev_err(&pdev->dev, "pci_enable_device_mem() failed!\n");
+		return rc;
+	}
+
+	pci_set_master(pdev);
+
+	ena_dev = vzalloc(sizeof(*ena_dev));
+	if (!ena_dev) {
+		rc = -ENOMEM;
+		goto err_disable_device;
+	}
+
+	bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
+	rc = pci_request_selected_regions(pdev, bars, DRV_MODULE_NAME);
+	if (rc) {
+		dev_err(&pdev->dev, "pci_request_selected_regions failed %d\n",
+			rc);
+		goto err_free_ena_dev;
+	}
+
+	ena_dev->reg_bar = devm_ioremap(&pdev->dev,
+					pci_resource_start(pdev, ENA_REG_BAR),
+					pci_resource_len(pdev, ENA_REG_BAR));
+	if (!ena_dev->reg_bar) {
+		dev_err(&pdev->dev, "failed to remap regs bar\n");
+		rc = -EFAULT;
+		goto err_free_region;
+	}
+
+	ena_dev->dmadev = &pdev->dev;
+
+	rc = ena_device_init(ena_dev, pdev, &get_feat_ctx, &wd_state);
+	if (rc) {
+		dev_err(&pdev->dev, "ena device init failed\n");
+		if (rc == -ETIME)
+			rc = -EPROBE_DEFER;
+		goto err_free_region;
+	}
+
+	set_default_llq_configurations(&llq_config);
+
+	rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx.llq,
+					     &llq_config);
+	if (rc) {
+		dev_err(&pdev->dev, "ena device init failed\n");
+		goto err_device_destroy;
+	}
+
+	calc_queue_ctx.ena_dev = ena_dev;
+	calc_queue_ctx.get_feat_ctx = &get_feat_ctx;
+	calc_queue_ctx.pdev = pdev;
+
+	/* Initial Tx and RX interrupt delay. Assumes 1 usec granularity.
+	* Updated during device initialization with the real granularity
+	*/
+	ena_dev->intr_moder_tx_interval = ENA_INTR_INITIAL_TX_INTERVAL_USECS;
+	ena_dev->intr_moder_rx_interval = ENA_INTR_INITIAL_RX_INTERVAL_USECS;
+	ena_dev->intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION;
+	io_queue_num = ena_calc_io_queue_num(pdev, ena_dev, &get_feat_ctx);
+	rc = ena_calc_queue_size(&calc_queue_ctx);
+	if (rc || io_queue_num <= 0) {
+		rc = -EFAULT;
+		goto err_device_destroy;
+	}
+
+	dev_info(&pdev->dev, "creating %d io queues. rx queue size: %d tx queue size. %d LLQ is %s\n",
+		 io_queue_num,
+		 calc_queue_ctx.rx_queue_size,
+		 calc_queue_ctx.tx_queue_size,
+		 (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) ?
+		 "ENABLED" : "DISABLED");
+
+	/* dev zeroed in init_etherdev */
+	netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), io_queue_num);
+	if (!netdev) {
+		dev_err(&pdev->dev, "alloc_etherdev_mq failed\n");
+		rc = -ENOMEM;
+		goto err_device_destroy;
+	}
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	adapter = netdev_priv(netdev);
+	pci_set_drvdata(pdev, adapter);
+
+	adapter->ena_dev = ena_dev;
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+
+	ena_set_conf_feat_params(adapter, &get_feat_ctx);
+
+	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
+	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
+
+	adapter->requested_tx_ring_size = calc_queue_ctx.tx_queue_size;
+	adapter->requested_rx_ring_size = calc_queue_ctx.rx_queue_size;
+	adapter->max_tx_ring_size = calc_queue_ctx.max_tx_queue_size;
+	adapter->max_rx_ring_size = calc_queue_ctx.max_rx_queue_size;
+	adapter->max_tx_sgl_size = calc_queue_ctx.max_tx_sgl_size;
+	adapter->max_rx_sgl_size = calc_queue_ctx.max_rx_sgl_size;
+
+	adapter->num_queues = io_queue_num;
+	adapter->last_monitored_tx_qid = 0;
+
+	adapter->rx_copybreak = ENA_DEFAULT_RX_COPYBREAK;
+	adapter->wd_state = wd_state;
+
+	snprintf(adapter->name, ENA_NAME_MAX_LEN, "ena_%d", adapters_found);
+
+	rc = ena_com_init_interrupt_moderation(adapter->ena_dev);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"Failed to query interrupt moderation feature\n");
+		goto err_netdev_destroy;
+	}
+	ena_init_io_rings(adapter);
+
+	netdev->netdev_ops = &ena_netdev_ops;
+	netdev->watchdog_timeo = TX_TIMEOUT;
+	ena_set_ethtool_ops(netdev);
+
+	netdev->priv_flags |= IFF_UNICAST_FLT;
+
+	u64_stats_init(&adapter->syncp);
+
+	rc = ena_enable_msix_and_set_admin_interrupts(adapter, io_queue_num);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"Failed to enable and set the admin interrupts\n");
+		goto err_worker_destroy;
+	}
+	rc = ena_rss_init_default(adapter);
+	if (rc && (rc != -EOPNOTSUPP)) {
+		dev_err(&pdev->dev, "Cannot init RSS rc: %d\n", rc);
+		goto err_free_msix;
+	}
+
+	ena_config_debug_area(adapter);
+
+	memcpy(adapter->netdev->perm_addr, adapter->mac_addr, netdev->addr_len);
+
+	netif_carrier_off(netdev);
+
+	rc = register_netdev(netdev);
+	if (rc) {
+		dev_err(&pdev->dev, "Cannot register net device\n");
+		goto err_rss;
+	}
+
+	INIT_WORK(&adapter->reset_task, ena_fw_reset_device);
+
+	adapter->last_keep_alive_jiffies = jiffies;
+	adapter->keep_alive_timeout = ENA_DEVICE_KALIVE_TIMEOUT;
+	adapter->missing_tx_completion_to = TX_TIMEOUT;
+	adapter->missing_tx_completion_threshold = MAX_NUM_OF_TIMEOUTED_PACKETS;
+
+	ena_update_hints(adapter, &get_feat_ctx.hw_hints);
+
+	setup_timer(&adapter->timer_service, ena_timer_service,
+		    (unsigned long)adapter);
+	mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
+
+	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
+		queue_type_str = "Regular";
+	else
+		queue_type_str = "Low Latency";
+
+	dev_info(&pdev->dev,
+		 "%s found at mem %lx, mac addr %pM Queues %d, Placement policy: %s\n",
+		 DEVICE_NAME, (long)pci_resource_start(pdev, 0),
+		 netdev->dev_addr, io_queue_num, queue_type_str);
+
+	set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
+
+	adapters_found++;
+
+	return 0;
+
+err_rss:
+	ena_com_delete_debug_area(ena_dev);
+	ena_com_rss_destroy(ena_dev);
+err_free_msix:
+	ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR);
+	/* stop submitting admin commands on a device that was reset */
+	ena_com_set_admin_running_state(ena_dev, false);
+	ena_free_mgmnt_irq(adapter);
+	ena_disable_msix(adapter);
+err_worker_destroy:
+	del_timer(&adapter->timer_service);
+err_netdev_destroy:
+	free_netdev(netdev);
+err_device_destroy:
+	ena_com_delete_host_info(ena_dev);
+	ena_com_admin_destroy(ena_dev);
+err_free_region:
+	ena_release_bars(ena_dev, pdev);
+err_free_ena_dev:
+	vfree(ena_dev);
+err_disable_device:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+/*****************************************************************************/
+static int ena_sriov_configure(struct pci_dev *dev, int numvfs)
+{
+	int rc;
+
+	if (numvfs > 0) {
+		rc = pci_enable_sriov(dev, numvfs);
+		if (rc != 0) {
+			dev_err(&dev->dev,
+				"pci_enable_sriov failed to enable: %d vfs with the error: %d\n",
+				numvfs, rc);
+			return rc;
+		}
+
+		return numvfs;
+	}
+
+	if (numvfs == 0) {
+		pci_disable_sriov(dev);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+/* __ena_shutoff - Helper used in both PCI remove/shutdown routines
+ * @pdev: PCI device information struct
+ * @shutdown: Is it a shutdown operation? If false, means it is a removal
+ *
+ * __ena_shutoff is a helper routine that does the real work on shutdown and
+ * removal paths; the difference between those paths is with regards to whether
+ * dettach or unregister the netdevice.
+ */
+static void __ena_shutoff(struct pci_dev *pdev, bool shutdown)
+{
+	struct ena_adapter *adapter = pci_get_drvdata(pdev);
+	struct ena_com_dev *ena_dev;
+	struct net_device *netdev;
+
+	ena_dev = adapter->ena_dev;
+	netdev = adapter->netdev;
+
+#ifdef CONFIG_RFS_ACCEL
+	if ((adapter->msix_vecs >= 1) && (netdev->rx_cpu_rmap)) {
+		free_irq_cpu_rmap(netdev->rx_cpu_rmap);
+		netdev->rx_cpu_rmap = NULL;
+	}
+#endif /* CONFIG_RFS_ACCEL */
+	del_timer_sync(&adapter->timer_service);
+
+	cancel_work_sync(&adapter->reset_task);
+
+	rtnl_lock(); /* lock released inside the below if-else block */
+	ena_destroy_device(adapter, true);
+	if (shutdown) {
+		netif_device_detach(netdev);
+		dev_close(netdev);
+		rtnl_unlock();
+	} else {
+		rtnl_unlock();
+		unregister_netdev(netdev);
+		free_netdev(netdev);
+	}
+
+	ena_com_rss_destroy(ena_dev);
+
+	ena_com_delete_debug_area(ena_dev);
+
+	ena_com_delete_host_info(ena_dev);
+
+	ena_release_bars(ena_dev, pdev);
+
+	pci_disable_device(pdev);
+
+	vfree(ena_dev);
+}
+
+/* ena_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * ena_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+
+static void ena_remove(struct pci_dev *pdev)
+{
+	__ena_shutoff(pdev, false);
+}
+
+/* ena_shutdown - Device Shutdown Routine
+ * @pdev: PCI device information struct
+ *
+ * ena_shutdown is called by the PCI subsystem to alert the driver that
+ * a shutdown/reboot (or kexec) is happening and device must be disabled.
+ */
+
+static void ena_shutdown(struct pci_dev *pdev)
+{
+	__ena_shutoff(pdev, true);
+}
+
+#ifdef CONFIG_PM
+/* ena_suspend - PM suspend callback
+ * @pdev: PCI device information struct
+ * @state:power state
+ */
+static int ena_suspend(struct pci_dev *pdev,  pm_message_t state)
+{
+	struct ena_adapter *adapter = pci_get_drvdata(pdev);
+
+	u64_stats_update_begin(&adapter->syncp);
+	adapter->dev_stats.suspend++;
+	u64_stats_update_end(&adapter->syncp);
+
+	rtnl_lock();
+	if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
+		dev_err(&pdev->dev,
+			"ignoring device reset request as the device is being suspended\n");
+		clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+	}
+	ena_destroy_device(adapter, true);
+	rtnl_unlock();
+	return 0;
+}
+
+/* ena_resume - PM resume callback
+ * @pdev: PCI device information struct
+ *
+ */
+static int ena_resume(struct pci_dev *pdev)
+{
+	struct ena_adapter *adapter = pci_get_drvdata(pdev);
+	int rc;
+
+	u64_stats_update_begin(&adapter->syncp);
+	adapter->dev_stats.resume++;
+	u64_stats_update_end(&adapter->syncp);
+
+	rtnl_lock();
+	rc = ena_restore_device(adapter);
+	rtnl_unlock();
+	return rc;
+}
+#endif
+
+static struct pci_driver ena_pci_driver = {
+	.name		= DRV_MODULE_NAME,
+	.id_table	= ena_pci_tbl,
+	.probe		= ena_probe,
+	.remove		= ena_remove,
+	.shutdown	= ena_shutdown,
+#ifdef CONFIG_PM
+	.suspend    = ena_suspend,
+	.resume     = ena_resume,
+#endif
+	.sriov_configure = ena_sriov_configure,
+};
+
+static int __init ena_init(void)
+{
+	pr_info("%s", version);
+
+	ena_wq = create_singlethread_workqueue(DRV_MODULE_NAME);
+	if (!ena_wq) {
+		pr_err("Failed to create workqueue\n");
+		return -ENOMEM;
+	}
+
+	return pci_register_driver(&ena_pci_driver);
+}
+
+static void __exit ena_cleanup(void)
+{
+	pci_unregister_driver(&ena_pci_driver);
+
+	if (ena_wq) {
+		destroy_workqueue(ena_wq);
+		ena_wq = NULL;
+	}
+}
+
+/******************************************************************************
+ ******************************** AENQ Handlers *******************************
+ *****************************************************************************/
+/* ena_update_on_link_change:
+ * Notify the network interface about the change in link status
+ */
+static void ena_update_on_link_change(void *adapter_data,
+				      struct ena_admin_aenq_entry *aenq_e)
+{
+	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
+	struct ena_admin_aenq_link_change_desc *aenq_desc =
+		(struct ena_admin_aenq_link_change_desc *)aenq_e;
+	int status = aenq_desc->flags &
+		ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK;
+
+	if (status) {
+		netdev_dbg(adapter->netdev, "%s\n", __func__);
+		set_bit(ENA_FLAG_LINK_UP, &adapter->flags);
+		if (!test_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags))
+			netif_carrier_on(adapter->netdev);
+	} else {
+		clear_bit(ENA_FLAG_LINK_UP, &adapter->flags);
+		netif_carrier_off(adapter->netdev);
+	}
+}
+
+static void ena_keep_alive_wd(void *adapter_data,
+			      struct ena_admin_aenq_entry *aenq_e)
+{
+	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
+	struct ena_admin_aenq_keep_alive_desc *desc;
+	u64 rx_drops;
+
+	desc = (struct ena_admin_aenq_keep_alive_desc *)aenq_e;
+	adapter->last_keep_alive_jiffies = jiffies;
+
+	rx_drops = ((u64)desc->rx_drops_high << 32) | desc->rx_drops_low;
+
+	u64_stats_update_begin(&adapter->syncp);
+	adapter->dev_stats.rx_drops = rx_drops;
+	u64_stats_update_end(&adapter->syncp);
+}
+
+static void ena_notification(void *adapter_data,
+			     struct ena_admin_aenq_entry *aenq_e)
+{
+	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
+	struct ena_admin_ena_hw_hints *hints;
+
+	WARN(aenq_e->aenq_common_desc.group != ENA_ADMIN_NOTIFICATION,
+	     "Invalid group(%x) expected %x\n",
+	     aenq_e->aenq_common_desc.group,
+	     ENA_ADMIN_NOTIFICATION);
+
+	switch (aenq_e->aenq_common_desc.syndrom) {
+	case ENA_ADMIN_UPDATE_HINTS:
+		hints = (struct ena_admin_ena_hw_hints *)
+			(&aenq_e->inline_data_w4);
+		ena_update_hints(adapter, hints);
+		break;
+	default:
+		netif_err(adapter, drv, adapter->netdev,
+			  "Invalid aenq notification link state %d\n",
+			  aenq_e->aenq_common_desc.syndrom);
+	}
+}
+
+/* This handler will called for unknown event group or unimplemented handlers*/
+static void unimplemented_aenq_handler(void *data,
+				       struct ena_admin_aenq_entry *aenq_e)
+{
+	struct ena_adapter *adapter = (struct ena_adapter *)data;
+
+	netif_err(adapter, drv, adapter->netdev,
+		  "Unknown event was received or event with unimplemented handler\n");
+}
+
+static struct ena_aenq_handlers aenq_handlers = {
+	.handlers = {
+		[ENA_ADMIN_LINK_CHANGE] = ena_update_on_link_change,
+		[ENA_ADMIN_NOTIFICATION] = ena_notification,
+		[ENA_ADMIN_KEEP_ALIVE] = ena_keep_alive_wd,
+	},
+	.unimplemented_handler = unimplemented_aenq_handler
+};
+
+module_init(ena_init);
+module_exit(ena_cleanup);
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_netdev.h
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_netdev.h
@@ -0,0 +1,391 @@
+/*
+ * Copyright 2015 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef ENA_H
+#define ENA_H
+
+#include <linux/bitops.h>
+#include <linux/dim.h>
+#include <linux/etherdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include "ena_com.h"
+#include "ena_eth_com.h"
+
+#define DRV_MODULE_VER_MAJOR	2
+#define DRV_MODULE_VER_MINOR	1
+#define DRV_MODULE_VER_SUBMINOR 0
+
+#define DRV_MODULE_NAME		"ena"
+#ifndef DRV_MODULE_VERSION
+#define DRV_MODULE_VERSION \
+	__stringify(DRV_MODULE_VER_MAJOR) "."	\
+	__stringify(DRV_MODULE_VER_MINOR) "."	\
+	__stringify(DRV_MODULE_VER_SUBMINOR) "K"
+#endif
+
+#define DEVICE_NAME	"Elastic Network Adapter (ENA)"
+
+/* 1 for AENQ + ADMIN */
+#define ENA_MAX_MSIX_VEC(io_queues)	(1 + (io_queues))
+
+/* The ENA buffer length fields is 16 bit long. So when PAGE_SIZE == 64kB the
+ * driver passes 0.
+ * Since the max packet size the ENA handles is ~9kB limit the buffer length to
+ * 16kB.
+ */
+#if PAGE_SIZE > SZ_16K
+#define ENA_PAGE_SIZE SZ_16K
+#else
+#define ENA_PAGE_SIZE PAGE_SIZE
+#endif
+
+#define ENA_REG_BAR			0
+#define ENA_MEM_BAR			2
+#define ENA_BAR_MASK (BIT(ENA_REG_BAR) | BIT(ENA_MEM_BAR))
+
+#define ENA_DEFAULT_RING_SIZE	(1024)
+#define ENA_MIN_RING_SIZE	(256)
+
+#define ENA_TX_WAKEUP_THRESH		(MAX_SKB_FRAGS + 2)
+#define ENA_DEFAULT_RX_COPYBREAK	(256 - NET_IP_ALIGN)
+
+/* limit the buffer size to 600 bytes to handle MTU changes from very
+ * small to very large, in which case the number of buffers per packet
+ * could exceed ENA_PKT_MAX_BUFS
+ */
+#define ENA_DEFAULT_MIN_RX_BUFF_ALLOC_SIZE 600
+
+#define ENA_MIN_MTU		128
+
+#define ENA_NAME_MAX_LEN	20
+#define ENA_IRQNAME_SIZE	40
+
+#define ENA_PKT_MAX_BUFS	19
+
+#define ENA_RX_RSS_TABLE_LOG_SIZE  7
+#define ENA_RX_RSS_TABLE_SIZE	(1 << ENA_RX_RSS_TABLE_LOG_SIZE)
+
+#define ENA_HASH_KEY_SIZE	40
+
+/* The number of tx packet completions that will be handled each NAPI poll
+ * cycle is ring_size / ENA_TX_POLL_BUDGET_DIVIDER.
+ */
+#define ENA_TX_POLL_BUDGET_DIVIDER	4
+
+/* Refill Rx queue when number of required descriptors is above
+ * QUEUE_SIZE / ENA_RX_REFILL_THRESH_DIVIDER or ENA_RX_REFILL_THRESH_PACKET
+ */
+#define ENA_RX_REFILL_THRESH_DIVIDER	8
+#define ENA_RX_REFILL_THRESH_PACKET	256
+
+/* Number of queues to check for missing queues per timer service */
+#define ENA_MONITORED_TX_QUEUES	4
+/* Max timeout packets before device reset */
+#define MAX_NUM_OF_TIMEOUTED_PACKETS 128
+
+#define ENA_TX_RING_IDX_NEXT(idx, ring_size) (((idx) + 1) & ((ring_size) - 1))
+
+#define ENA_RX_RING_IDX_NEXT(idx, ring_size) (((idx) + 1) & ((ring_size) - 1))
+#define ENA_RX_RING_IDX_ADD(idx, n, ring_size) \
+	(((idx) + (n)) & ((ring_size) - 1))
+
+#define ENA_IO_TXQ_IDX(q)	(2 * (q))
+#define ENA_IO_RXQ_IDX(q)	(2 * (q) + 1)
+
+#define ENA_MGMNT_IRQ_IDX		0
+#define ENA_IO_IRQ_FIRST_IDX		1
+#define ENA_IO_IRQ_IDX(q)		(ENA_IO_IRQ_FIRST_IDX + (q))
+
+/* ENA device should send keep alive msg every 1 sec.
+ * We wait for 6 sec just to be on the safe side.
+ */
+#define ENA_DEVICE_KALIVE_TIMEOUT	(6 * HZ)
+#define ENA_MAX_NO_INTERRUPT_ITERATIONS 3
+
+#define ENA_MMIO_DISABLE_REG_READ	BIT(0)
+
+struct ena_irq {
+	irq_handler_t handler;
+	void *data;
+	int cpu;
+	u32 vector;
+	cpumask_t affinity_hint_mask;
+	char name[ENA_IRQNAME_SIZE];
+};
+
+struct ena_napi {
+	struct napi_struct napi ____cacheline_aligned;
+	struct ena_ring *tx_ring;
+	struct ena_ring *rx_ring;
+	u32 qid;
+	struct dim dim;
+};
+
+struct ena_calc_queue_size_ctx {
+	struct ena_com_dev_get_features_ctx *get_feat_ctx;
+	struct ena_com_dev *ena_dev;
+	struct pci_dev *pdev;
+	u16 tx_queue_size;
+	u16 rx_queue_size;
+	u16 max_tx_queue_size;
+	u16 max_rx_queue_size;
+	u16 max_tx_sgl_size;
+	u16 max_rx_sgl_size;
+};
+
+struct ena_tx_buffer {
+	struct sk_buff *skb;
+	/* num of ena desc for this specific skb
+	 * (includes data desc and metadata desc)
+	 */
+	u32 tx_descs;
+	/* num of buffers used by this skb */
+	u32 num_of_bufs;
+
+	/* Indicate if bufs[0] map the linear data of the skb. */
+	u8 map_linear_data;
+
+	/* Used for detect missing tx packets to limit the number of prints */
+	u32 print_once;
+	/* Save the last jiffies to detect missing tx packets
+	 *
+	 * sets to non zero value on ena_start_xmit and set to zero on
+	 * napi and timer_Service_routine.
+	 *
+	 * while this value is not protected by lock,
+	 * a given packet is not expected to be handled by ena_start_xmit
+	 * and by napi/timer_service at the same time.
+	 */
+	unsigned long last_jiffies;
+	struct ena_com_buf bufs[ENA_PKT_MAX_BUFS];
+} ____cacheline_aligned;
+
+struct ena_rx_buffer {
+	struct sk_buff *skb;
+	struct page *page;
+	u32 page_offset;
+	struct ena_com_buf ena_buf;
+} ____cacheline_aligned;
+
+struct ena_stats_tx {
+	u64 cnt;
+	u64 bytes;
+	u64 queue_stop;
+	u64 prepare_ctx_err;
+	u64 queue_wakeup;
+	u64 dma_mapping_err;
+	u64 linearize;
+	u64 linearize_failed;
+	u64 napi_comp;
+	u64 tx_poll;
+	u64 doorbells;
+	u64 bad_req_id;
+	u64 llq_buffer_copy;
+	u64 missed_tx;
+};
+
+struct ena_stats_rx {
+	u64 cnt;
+	u64 bytes;
+	u64 rx_copybreak_pkt;
+	u64 csum_good;
+	u64 refil_partial;
+	u64 bad_csum;
+	u64 page_alloc_fail;
+	u64 skb_alloc_fail;
+	u64 dma_mapping_err;
+	u64 bad_desc_num;
+	u64 bad_req_id;
+	u64 empty_rx_ring;
+	u64 csum_unchecked;
+};
+
+struct ena_ring {
+	/* Holds the empty requests for TX/RX
+	 * out of order completions
+	 */
+	u16 *free_ids;
+
+	union {
+		struct ena_tx_buffer *tx_buffer_info;
+		struct ena_rx_buffer *rx_buffer_info;
+	};
+
+	/* cache ptr to avoid using the adapter */
+	struct device *dev;
+	struct pci_dev *pdev;
+	struct napi_struct *napi;
+	struct net_device *netdev;
+	struct ena_com_dev *ena_dev;
+	struct ena_adapter *adapter;
+	struct ena_com_io_cq *ena_com_io_cq;
+	struct ena_com_io_sq *ena_com_io_sq;
+
+	u16 next_to_use;
+	u16 next_to_clean;
+	u16 rx_copybreak;
+	u16 qid;
+	u16 mtu;
+	u16 sgl_size;
+
+	/* The maximum header length the device can handle */
+	u8 tx_max_header_size;
+
+	bool first_interrupt;
+	u16 no_interrupt_event_cnt;
+
+	/* cpu for TPH */
+	int cpu;
+	 /* number of tx/rx_buffer_info's entries */
+	int ring_size;
+
+	enum ena_admin_placement_policy_type tx_mem_queue_type;
+
+	struct ena_com_rx_buf_info ena_bufs[ENA_PKT_MAX_BUFS];
+	u32  smoothed_interval;
+	u32  per_napi_packets;
+	u16 non_empty_napi_events;
+	struct u64_stats_sync syncp;
+	union {
+		struct ena_stats_tx tx_stats;
+		struct ena_stats_rx rx_stats;
+	};
+
+	u8 *push_buf_intermediate_buf;
+	int empty_rx_queue;
+} ____cacheline_aligned;
+
+struct ena_stats_dev {
+	u64 tx_timeout;
+	u64 suspend;
+	u64 resume;
+	u64 wd_expired;
+	u64 interface_up;
+	u64 interface_down;
+	u64 admin_q_pause;
+	u64 rx_drops;
+};
+
+enum ena_flags_t {
+	ENA_FLAG_DEVICE_RUNNING,
+	ENA_FLAG_DEV_UP,
+	ENA_FLAG_LINK_UP,
+	ENA_FLAG_MSIX_ENABLED,
+	ENA_FLAG_TRIGGER_RESET,
+	ENA_FLAG_ONGOING_RESET
+};
+
+/* adapter specific private data structure */
+struct ena_adapter {
+	struct ena_com_dev *ena_dev;
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+
+	/* rx packets that shorter that this len will be copied to the skb
+	 * header
+	 */
+	u32 rx_copybreak;
+	u32 max_mtu;
+
+	int num_queues;
+
+	struct msix_entry *msix_entries;
+	int msix_vecs;
+
+	u32 missing_tx_completion_threshold;
+
+	u32 requested_tx_ring_size;
+	u32 requested_rx_ring_size;
+
+	u32 max_tx_ring_size;
+	u32 max_rx_ring_size;
+
+	u32 msg_enable;
+
+	u16 max_tx_sgl_size;
+	u16 max_rx_sgl_size;
+
+	u8 mac_addr[ETH_ALEN];
+
+	unsigned long keep_alive_timeout;
+	unsigned long missing_tx_completion_to;
+
+	char name[ENA_NAME_MAX_LEN];
+
+	unsigned long flags;
+	/* TX */
+	struct ena_ring tx_ring[ENA_MAX_NUM_IO_QUEUES]
+		____cacheline_aligned_in_smp;
+
+	/* RX */
+	struct ena_ring rx_ring[ENA_MAX_NUM_IO_QUEUES]
+		____cacheline_aligned_in_smp;
+
+	struct ena_napi ena_napi[ENA_MAX_NUM_IO_QUEUES];
+
+	struct ena_irq irq_tbl[ENA_MAX_MSIX_VEC(ENA_MAX_NUM_IO_QUEUES)];
+
+	/* timer service */
+	struct work_struct reset_task;
+	struct timer_list timer_service;
+
+	bool wd_state;
+	bool dev_up_before_reset;
+	unsigned long last_keep_alive_jiffies;
+
+	struct u64_stats_sync syncp;
+	struct ena_stats_dev dev_stats;
+
+	/* last queue index that was checked for uncompleted tx packets */
+	u32 last_monitored_tx_qid;
+
+	enum ena_regs_reset_reason_types reset_reason;
+};
+
+void ena_set_ethtool_ops(struct net_device *netdev);
+
+void ena_dump_stats_to_dmesg(struct ena_adapter *adapter);
+
+void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf);
+
+int ena_update_queue_sizes(struct ena_adapter *adapter,
+			   u32 new_tx_size,
+			   u32 new_rx_size);
+
+int ena_get_sset_count(struct net_device *netdev, int sset);
+
+#endif /* !(ENA_H) */
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_pci_id_tbl.h
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_pci_id_tbl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef ENA_PCI_ID_TBL_H_
+#define ENA_PCI_ID_TBL_H_
+
+#ifndef PCI_VENDOR_ID_AMAZON
+#define PCI_VENDOR_ID_AMAZON 0x1d0f
+#endif
+
+#ifndef PCI_DEV_ID_ENA_PF
+#define PCI_DEV_ID_ENA_PF	0x0ec2
+#endif
+
+#ifndef PCI_DEV_ID_ENA_LLQ_PF
+#define PCI_DEV_ID_ENA_LLQ_PF	0x1ec2
+#endif
+
+#ifndef PCI_DEV_ID_ENA_VF
+#define PCI_DEV_ID_ENA_VF	0xec20
+#endif
+
+#ifndef PCI_DEV_ID_ENA_LLQ_VF
+#define PCI_DEV_ID_ENA_LLQ_VF	0xec21
+#endif
+
+#define ENA_PCI_ID_TABLE_ENTRY(devid) \
+	{PCI_DEVICE(PCI_VENDOR_ID_AMAZON, devid)},
+
+static const struct pci_device_id ena_pci_tbl[] = {
+	ENA_PCI_ID_TABLE_ENTRY(PCI_DEV_ID_ENA_PF)
+	ENA_PCI_ID_TABLE_ENTRY(PCI_DEV_ID_ENA_LLQ_PF)
+	ENA_PCI_ID_TABLE_ENTRY(PCI_DEV_ID_ENA_VF)
+	ENA_PCI_ID_TABLE_ENTRY(PCI_DEV_ID_ENA_LLQ_VF)
+	{ }
+};
+
+#endif /* ENA_PCI_ID_TBL_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/amazon/ena/ena_regs_defs.h
+++ linux-4.4.0/drivers/net/ethernet/amazon/ena/ena_regs_defs.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2015 - 2016 Amazon.com, Inc. or its affiliates.
+ *
+ * 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
+ * BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _ENA_REGS_H_
+#define _ENA_REGS_H_
+
+enum ena_regs_reset_reason_types {
+	ENA_REGS_RESET_NORMAL                       = 0,
+	ENA_REGS_RESET_KEEP_ALIVE_TO                = 1,
+	ENA_REGS_RESET_ADMIN_TO                     = 2,
+	ENA_REGS_RESET_MISS_TX_CMPL                 = 3,
+	ENA_REGS_RESET_INV_RX_REQ_ID                = 4,
+	ENA_REGS_RESET_INV_TX_REQ_ID                = 5,
+	ENA_REGS_RESET_TOO_MANY_RX_DESCS            = 6,
+	ENA_REGS_RESET_INIT_ERR                     = 7,
+	ENA_REGS_RESET_DRIVER_INVALID_STATE         = 8,
+	ENA_REGS_RESET_OS_TRIGGER                   = 9,
+	ENA_REGS_RESET_OS_NETDEV_WD                 = 10,
+	ENA_REGS_RESET_SHUTDOWN                     = 11,
+	ENA_REGS_RESET_USER_TRIGGER                 = 12,
+	ENA_REGS_RESET_GENERIC                      = 13,
+	ENA_REGS_RESET_MISS_INTERRUPT               = 14,
+};
+
+/* ena_registers offsets */
+
+/* 0 base */
+#define ENA_REGS_VERSION_OFF                                0x0
+#define ENA_REGS_CONTROLLER_VERSION_OFF                     0x4
+#define ENA_REGS_CAPS_OFF                                   0x8
+#define ENA_REGS_CAPS_EXT_OFF                               0xc
+#define ENA_REGS_AQ_BASE_LO_OFF                             0x10
+#define ENA_REGS_AQ_BASE_HI_OFF                             0x14
+#define ENA_REGS_AQ_CAPS_OFF                                0x18
+#define ENA_REGS_ACQ_BASE_LO_OFF                            0x20
+#define ENA_REGS_ACQ_BASE_HI_OFF                            0x24
+#define ENA_REGS_ACQ_CAPS_OFF                               0x28
+#define ENA_REGS_AQ_DB_OFF                                  0x2c
+#define ENA_REGS_ACQ_TAIL_OFF                               0x30
+#define ENA_REGS_AENQ_CAPS_OFF                              0x34
+#define ENA_REGS_AENQ_BASE_LO_OFF                           0x38
+#define ENA_REGS_AENQ_BASE_HI_OFF                           0x3c
+#define ENA_REGS_AENQ_HEAD_DB_OFF                           0x40
+#define ENA_REGS_AENQ_TAIL_OFF                              0x44
+#define ENA_REGS_INTR_MASK_OFF                              0x4c
+#define ENA_REGS_DEV_CTL_OFF                                0x54
+#define ENA_REGS_DEV_STS_OFF                                0x58
+#define ENA_REGS_MMIO_REG_READ_OFF                          0x5c
+#define ENA_REGS_MMIO_RESP_LO_OFF                           0x60
+#define ENA_REGS_MMIO_RESP_HI_OFF                           0x64
+#define ENA_REGS_RSS_IND_ENTRY_UPDATE_OFF                   0x68
+
+/* version register */
+#define ENA_REGS_VERSION_MINOR_VERSION_MASK                 0xff
+#define ENA_REGS_VERSION_MAJOR_VERSION_SHIFT                8
+#define ENA_REGS_VERSION_MAJOR_VERSION_MASK                 0xff00
+
+/* controller_version register */
+#define ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK   0xff
+#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT     8
+#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK      0xff00
+#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT     16
+#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK      0xff0000
+#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT           24
+#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK            0xff000000
+
+/* caps register */
+#define ENA_REGS_CAPS_CONTIGUOUS_QUEUE_REQUIRED_MASK        0x1
+#define ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT                   1
+#define ENA_REGS_CAPS_RESET_TIMEOUT_MASK                    0x3e
+#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT                  8
+#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK                   0xff00
+#define ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT                    16
+#define ENA_REGS_CAPS_ADMIN_CMD_TO_MASK                     0xf0000
+
+/* aq_caps register */
+#define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK                      0xffff
+#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT                16
+#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK                 0xffff0000
+
+/* acq_caps register */
+#define ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK                    0xffff
+#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT              16
+#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK               0xffff0000
+
+/* aenq_caps register */
+#define ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK                  0xffff
+#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT            16
+#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK             0xffff0000
+
+/* dev_ctl register */
+#define ENA_REGS_DEV_CTL_DEV_RESET_MASK                     0x1
+#define ENA_REGS_DEV_CTL_AQ_RESTART_SHIFT                   1
+#define ENA_REGS_DEV_CTL_AQ_RESTART_MASK                    0x2
+#define ENA_REGS_DEV_CTL_QUIESCENT_SHIFT                    2
+#define ENA_REGS_DEV_CTL_QUIESCENT_MASK                     0x4
+#define ENA_REGS_DEV_CTL_IO_RESUME_SHIFT                    3
+#define ENA_REGS_DEV_CTL_IO_RESUME_MASK                     0x8
+#define ENA_REGS_DEV_CTL_RESET_REASON_SHIFT                 28
+#define ENA_REGS_DEV_CTL_RESET_REASON_MASK                  0xf0000000
+
+/* dev_sts register */
+#define ENA_REGS_DEV_STS_READY_MASK                         0x1
+#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_SHIFT       1
+#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_MASK        0x2
+#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_SHIFT          2
+#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_MASK           0x4
+#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_SHIFT            3
+#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK             0x8
+#define ENA_REGS_DEV_STS_RESET_FINISHED_SHIFT               4
+#define ENA_REGS_DEV_STS_RESET_FINISHED_MASK                0x10
+#define ENA_REGS_DEV_STS_FATAL_ERROR_SHIFT                  5
+#define ENA_REGS_DEV_STS_FATAL_ERROR_MASK                   0x20
+#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_SHIFT  6
+#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_MASK   0x40
+#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_SHIFT     7
+#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_MASK      0x80
+
+/* mmio_reg_read register */
+#define ENA_REGS_MMIO_REG_READ_REQ_ID_MASK                  0xffff
+#define ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT                16
+#define ENA_REGS_MMIO_REG_READ_REG_OFF_MASK                 0xffff0000
+
+/* rss_ind_entry_update register */
+#define ENA_REGS_RSS_IND_ENTRY_UPDATE_INDEX_MASK            0xffff
+#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_SHIFT          16
+#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_MASK           0xffff0000
+
+#endif /*_ENA_REGS_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/amd/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/amd/Kconfig
@@ -44,7 +44,7 @@
 
 config LANCE
 	tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
-	depends on ISA && ISA_DMA_API && !ARM
+	depends on ISA && ISA_DMA_API && !ARM && !PPC32
 	---help---
 	  If you have a network (Ethernet) card of this type, say Y here.
 	  Some LinkSys cards are of this type.
@@ -138,7 +138,7 @@
 
 config NI65
 	tristate "NI6510 support"
-	depends on ISA && ISA_DMA_API && !ARM
+	depends on ISA && ISA_DMA_API && !ARM && !PPC32
 	---help---
 	  If you have a network (Ethernet) card of this type, say Y here.
 
--- linux-4.4.0.orig/drivers/net/ethernet/amd/am79c961a.c
+++ linux-4.4.0/drivers/net/ethernet/amd/am79c961a.c
@@ -440,7 +440,7 @@
 /*
  * Transmit a packet
  */
-static int
+static netdev_tx_t
 am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dev_priv *priv = netdev_priv(dev);
--- linux-4.4.0.orig/drivers/net/ethernet/amd/atarilance.c
+++ linux-4.4.0/drivers/net/ethernet/amd/atarilance.c
@@ -339,7 +339,8 @@
                                    *init_rec );
 static int lance_open( struct net_device *dev );
 static void lance_init_ring( struct net_device *dev );
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
+static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
+				    struct net_device *dev);
 static irqreturn_t lance_interrupt( int irq, void *dev_id );
 static int lance_rx( struct net_device *dev );
 static int lance_close( struct net_device *dev );
@@ -770,7 +771,8 @@
 
 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
 
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
+static netdev_tx_t
+lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
--- linux-4.4.0.orig/drivers/net/ethernet/amd/declance.c
+++ linux-4.4.0/drivers/net/ethernet/amd/declance.c
@@ -893,7 +893,7 @@
 	netif_wake_queue(dev);
 }
 
-static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
--- linux-4.4.0.orig/drivers/net/ethernet/amd/lance.c
+++ linux-4.4.0/drivers/net/ethernet/amd/lance.c
@@ -318,9 +318,9 @@
 static int dma[MAX_CARDS];
 static int irq[MAX_CARDS];
 
-module_param_array(io, int, NULL, 0);
-module_param_array(dma, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(dma, int, dma, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param(lance_debug, int, 0);
 MODULE_PARM_DESC(io, "LANCE/PCnet I/O base address(es),required");
 MODULE_PARM_DESC(dma, "LANCE/PCnet ISA DMA channel (ignored for some devices)");
--- linux-4.4.0.orig/drivers/net/ethernet/amd/ni65.c
+++ linux-4.4.0/drivers/net/ethernet/amd/ni65.c
@@ -1228,9 +1228,9 @@
 #ifdef MODULE
 static struct net_device *dev_ni65;
 
-module_param(irq, int, 0);
-module_param(io, int, 0);
-module_param(dma, int, 0);
+module_param_hw(irq, int, irq, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(dma, int, dma, 0);
 MODULE_PARM_DESC(irq, "ni6510 IRQ number (ignored for some cards)");
 MODULE_PARM_DESC(io, "ni6510 I/O base address");
 MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)");
--- linux-4.4.0.orig/drivers/net/ethernet/amd/sun3lance.c
+++ linux-4.4.0/drivers/net/ethernet/amd/sun3lance.c
@@ -235,7 +235,8 @@
 static int lance_probe( struct net_device *dev);
 static int lance_open( struct net_device *dev );
 static void lance_init_ring( struct net_device *dev );
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
+static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
+				    struct net_device *dev);
 static irqreturn_t lance_interrupt( int irq, void *dev_id);
 static int lance_rx( struct net_device *dev );
 static int lance_close( struct net_device *dev );
@@ -511,7 +512,8 @@
 }
 
 
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
+static netdev_tx_t
+lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct lance_private *lp = netdev_priv(dev);
 	int entry, len;
--- linux-4.4.0.orig/drivers/net/ethernet/amd/sunlance.c
+++ linux-4.4.0/drivers/net/ethernet/amd/sunlance.c
@@ -1106,7 +1106,7 @@
 	netif_wake_queue(dev);
 }
 
-static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct lance_private *lp = netdev_priv(dev);
 	int entry, skblen, len;
@@ -1419,7 +1419,7 @@
 
 			prop = of_get_property(nd, "tpe-link-test?", NULL);
 			if (!prop)
-				goto no_link_test;
+				goto node_put;
 
 			if (strcmp(prop, "true")) {
 				printk(KERN_NOTICE "SunLance: warning: overriding option "
@@ -1428,6 +1428,8 @@
 				       "to ecd@skynet.be\n");
 				auxio_set_lte(AUXIO_LTE_ON);
 			}
+node_put:
+			of_node_put(nd);
 no_link_test:
 			lp->auto_select = 1;
 			lp->tpe = 0;
--- linux-4.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ linux-4.4.0/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -913,8 +913,8 @@
 #define RX_PACKET_ATTRIBUTES_CSUM_DONE_WIDTH	1
 #define RX_PACKET_ATTRIBUTES_VLAN_CTAG_INDEX	1
 #define RX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH	1
-#define RX_PACKET_ATTRIBUTES_INCOMPLETE_INDEX	2
-#define RX_PACKET_ATTRIBUTES_INCOMPLETE_WIDTH	1
+#define RX_PACKET_ATTRIBUTES_LAST_INDEX		2
+#define RX_PACKET_ATTRIBUTES_LAST_WIDTH		1
 #define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_INDEX	3
 #define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_WIDTH	1
 #define RX_PACKET_ATTRIBUTES_CONTEXT_INDEX	4
@@ -923,6 +923,8 @@
 #define RX_PACKET_ATTRIBUTES_RX_TSTAMP_WIDTH	1
 #define RX_PACKET_ATTRIBUTES_RSS_HASH_INDEX	6
 #define RX_PACKET_ATTRIBUTES_RSS_HASH_WIDTH	1
+#define RX_PACKET_ATTRIBUTES_FIRST_INDEX	7
+#define RX_PACKET_ATTRIBUTES_FIRST_WIDTH	1
 
 #define RX_NORMAL_DESC0_OVT_INDEX		0
 #define RX_NORMAL_DESC0_OVT_WIDTH		16
--- linux-4.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ linux-4.4.0/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1658,10 +1658,15 @@
 
 	/* Get the header length */
 	if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD)) {
+		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+			       FIRST, 1);
 		rdata->rx.hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
 						      RX_NORMAL_DESC2, HL);
 		if (rdata->rx.hdr_len)
 			pdata->ext_stats.rx_split_header_packets++;
+	} else {
+		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+			       FIRST, 0);
 	}
 
 	/* Get the RSS hash */
@@ -1684,19 +1689,16 @@
 		}
 	}
 
-	/* Get the packet length */
-	rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
-
-	if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD)) {
-		/* Not all the data has been transferred for this packet */
-		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
-			       INCOMPLETE, 1);
+	/* Not all the data has been transferred for this packet */
+	if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD))
 		return 0;
-	}
 
 	/* This is the last of the data for this packet */
 	XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
-		       INCOMPLETE, 0);
+		       LAST, 1);
+
+	/* Get the packet length */
+	rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
 
 	/* Set checksum done indicator as appropriate */
 	if (netdev->features & NETIF_F_RXCSUM)
@@ -2730,8 +2732,10 @@
 
 	/* Flush Tx queues */
 	ret = xgbe_flush_tx_queues(pdata);
-	if (ret)
+	if (ret) {
+		netdev_err(pdata->netdev, "error flushing TX queues\n");
 		return ret;
+	}
 
 	/*
 	 * Initialize DMA related features
--- linux-4.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ linux-4.4.0/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -877,7 +877,9 @@
 
 	DBGPR("-->xgbe_start\n");
 
-	hw_if->init(pdata);
+	ret = hw_if->init(pdata);
+	if (ret)
+		return ret;
 
 	ret = phy_if->phy_start(pdata);
 	if (ret)
@@ -1388,7 +1390,7 @@
 	return 0;
 }
 
-static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct xgbe_prv_data *pdata = netdev_priv(netdev);
 	struct xgbe_hw_if *hw_if = &pdata->hw_if;
@@ -1397,7 +1399,7 @@
 	struct xgbe_ring *ring;
 	struct xgbe_packet_data *packet;
 	struct netdev_queue *txq;
-	int ret;
+	netdev_tx_t ret;
 
 	DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len);
 
@@ -1626,11 +1628,17 @@
 }
 #endif /* End CONFIG_NET_POLL_CONTROLLER */
 
-static int xgbe_setup_tc(struct net_device *netdev, u8 tc)
+static int xgbe_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+			 struct tc_to_netdev *tc_to_netdev)
 {
 	struct xgbe_prv_data *pdata = netdev_priv(netdev);
 	unsigned int offset, queue;
-	u8 i;
+	u8 i, tc;
+
+	if (handle != TC_H_ROOT || tc_to_netdev->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+
+	tc = tc_to_netdev->tc;
 
 	if (tc && (tc != pdata->hw_feat.tc_cnt))
 		return -EINVAL;
@@ -1760,13 +1768,12 @@
 {
 	struct sk_buff *skb;
 	u8 *packet;
-	unsigned int copy_len;
 
 	skb = napi_alloc_skb(napi, rdata->rx.hdr.dma_len);
 	if (!skb)
 		return NULL;
 
-	/* Start with the header buffer which may contain just the header
+	/* Pull in the header buffer which may contain just the header
 	 * or the header plus data
 	 */
 	dma_sync_single_range_for_cpu(pdata->dev, rdata->rx.hdr.dma_base,
@@ -1775,30 +1782,49 @@
 
 	packet = page_address(rdata->rx.hdr.pa.pages) +
 		 rdata->rx.hdr.pa.pages_offset;
-	copy_len = (rdata->rx.hdr_len) ? rdata->rx.hdr_len : len;
-	copy_len = min(rdata->rx.hdr.dma_len, copy_len);
-	skb_copy_to_linear_data(skb, packet, copy_len);
-	skb_put(skb, copy_len);
-
-	len -= copy_len;
-	if (len) {
-		/* Add the remaining data as a frag */
-		dma_sync_single_range_for_cpu(pdata->dev,
-					      rdata->rx.buf.dma_base,
-					      rdata->rx.buf.dma_off,
-					      rdata->rx.buf.dma_len,
-					      DMA_FROM_DEVICE);
-
-		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-				rdata->rx.buf.pa.pages,
-				rdata->rx.buf.pa.pages_offset,
-				len, rdata->rx.buf.dma_len);
-		rdata->rx.buf.pa.pages = NULL;
-	}
+	skb_copy_to_linear_data(skb, packet, len);
+	skb_put(skb, len);
 
 	return skb;
 }
 
+static unsigned int xgbe_rx_buf1_len(struct xgbe_ring_data *rdata,
+				     struct xgbe_packet_data *packet)
+{
+	/* Always zero if not the first descriptor */
+	if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, FIRST))
+		return 0;
+
+	/* First descriptor with split header, return header length */
+	if (rdata->rx.hdr_len)
+		return rdata->rx.hdr_len;
+
+	/* First descriptor but not the last descriptor and no split header,
+	 * so the full buffer was used
+	 */
+	if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, LAST))
+		return rdata->rx.hdr.dma_len;
+
+	/* First descriptor and last descriptor and no split header, so
+	 * calculate how much of the buffer was used
+	 */
+	return min_t(unsigned int, rdata->rx.hdr.dma_len, rdata->rx.len);
+}
+
+static unsigned int xgbe_rx_buf2_len(struct xgbe_ring_data *rdata,
+				     struct xgbe_packet_data *packet,
+				     unsigned int len)
+{
+	/* Always the full buffer if not the last descriptor */
+	if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, LAST))
+		return rdata->rx.buf.dma_len;
+
+	/* Last descriptor so calculate how much of the buffer was used
+	 * for the last bit of data
+	 */
+	return rdata->rx.len - len;
+}
+
 static int xgbe_tx_poll(struct xgbe_channel *channel)
 {
 	struct xgbe_prv_data *pdata = channel->pdata;
@@ -1881,8 +1907,8 @@
 	struct napi_struct *napi;
 	struct sk_buff *skb;
 	struct skb_shared_hwtstamps *hwtstamps;
-	unsigned int incomplete, error, context_next, context;
-	unsigned int len, rdesc_len, max_len;
+	unsigned int last, error, context_next, context;
+	unsigned int len, buf1_len, buf2_len, max_len;
 	unsigned int received = 0;
 	int packet_count = 0;
 
@@ -1892,7 +1918,7 @@
 	if (!ring)
 		return 0;
 
-	incomplete = 0;
+	last = 0;
 	context_next = 0;
 
 	napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi;
@@ -1926,9 +1952,8 @@
 		received++;
 		ring->cur++;
 
-		incomplete = XGMAC_GET_BITS(packet->attributes,
-					    RX_PACKET_ATTRIBUTES,
-					    INCOMPLETE);
+		last = XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+				      LAST);
 		context_next = XGMAC_GET_BITS(packet->attributes,
 					      RX_PACKET_ATTRIBUTES,
 					      CONTEXT_NEXT);
@@ -1937,7 +1962,7 @@
 					 CONTEXT);
 
 		/* Earlier error, just drain the remaining data */
-		if ((incomplete || context_next) && error)
+		if ((!last || context_next) && error)
 			goto read_again;
 
 		if (error || packet->errors) {
@@ -1949,16 +1974,22 @@
 		}
 
 		if (!context) {
-			/* Length is cumulative, get this descriptor's length */
-			rdesc_len = rdata->rx.len - len;
-			len += rdesc_len;
+			/* Get the data length in the descriptor buffers */
+			buf1_len = xgbe_rx_buf1_len(rdata, packet);
+			len += buf1_len;
+			buf2_len = xgbe_rx_buf2_len(rdata, packet, len);
+			len += buf2_len;
 
-			if (rdesc_len && !skb) {
+			if (!skb) {
 				skb = xgbe_create_skb(pdata, napi, rdata,
-						      rdesc_len);
-				if (!skb)
+						      buf1_len);
+				if (!skb) {
 					error = 1;
-			} else if (rdesc_len) {
+					goto skip_data;
+				}
+			}
+
+			if (buf2_len) {
 				dma_sync_single_range_for_cpu(pdata->dev,
 							rdata->rx.buf.dma_base,
 							rdata->rx.buf.dma_off,
@@ -1968,13 +1999,14 @@
 				skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
 						rdata->rx.buf.pa.pages,
 						rdata->rx.buf.pa.pages_offset,
-						rdesc_len,
+						buf2_len,
 						rdata->rx.buf.dma_len);
 				rdata->rx.buf.pa.pages = NULL;
 			}
 		}
 
-		if (incomplete || context_next)
+skip_data:
+		if (!last || context_next)
 			goto read_again;
 
 		if (!skb)
@@ -2033,7 +2065,7 @@
 	}
 
 	/* Check if we need to save state before leaving */
-	if (received && (incomplete || context_next)) {
+	if (received && (!last || context_next)) {
 		rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
 		rdata->state_saved = 1;
 		rdata->state.skb = skb;
--- linux-4.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ linux-4.4.0/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -829,7 +829,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int xgbe_suspend(struct device *dev)
 {
 	struct net_device *netdev = dev_get_drvdata(dev);
@@ -868,7 +868,7 @@
 
 	return ret;
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xgbe_acpi_match[] = {
--- linux-4.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ linux-4.4.0/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -872,14 +872,14 @@
 
 		if (pdata->tx_pause != pdata->phy.tx_pause) {
 			new_state = 1;
-			pdata->hw_if.config_tx_flow_control(pdata);
 			pdata->tx_pause = pdata->phy.tx_pause;
+			pdata->hw_if.config_tx_flow_control(pdata);
 		}
 
 		if (pdata->rx_pause != pdata->phy.rx_pause) {
 			new_state = 1;
-			pdata->hw_if.config_rx_flow_control(pdata);
 			pdata->rx_pause = pdata->phy.rx_pause;
+			pdata->hw_if.config_rx_flow_control(pdata);
 		}
 
 		/* Speed support */
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/Kconfig
@@ -3,6 +3,7 @@
 	depends on HAS_DMA
 	depends on ARCH_XGENE || COMPILE_TEST
 	select PHYLIB
+	select MDIO_XGENE
 	help
 	  This is the Ethernet driver for the on-chip ethernet interface on the
 	  APM X-Gene SoC.
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/Makefile
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/Makefile
@@ -3,5 +3,6 @@
 #
 
 xgene-enet-objs := xgene_enet_hw.o xgene_enet_sgmac.o xgene_enet_xgmac.o \
-		   xgene_enet_main.o xgene_enet_ring2.o xgene_enet_ethtool.o
+		   xgene_enet_main.o xgene_enet_ring2.o xgene_enet_ethtool.o \
+		   xgene_enet_cle.o
 obj-$(CONFIG_NET_XGENE) += xgene-enet.o
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_cle.c
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_cle.c
@@ -0,0 +1,735 @@
+/* Applied Micro X-Gene SoC Ethernet Classifier structures
+ *
+ * Copyright (c) 2016, Applied Micro Circuits Corporation
+ * Authors: Khuong Dinh <kdinh@apm.com>
+ *          Tanmay Inamdar <tinamdar@apm.com>
+ *          Iyappan Subramanian <isubramanian@apm.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "xgene_enet_main.h"
+
+/* interfaces to convert structures to HW recognized bit formats */
+static void xgene_cle_sband_to_hw(u8 frag, enum xgene_cle_prot_version ver,
+				  enum xgene_cle_prot_type type, u32 len,
+				  u32 *reg)
+{
+	*reg =  SET_VAL(SB_IPFRAG, frag) |
+		SET_VAL(SB_IPPROT, type) |
+		SET_VAL(SB_IPVER, ver) |
+		SET_VAL(SB_HDRLEN, len);
+}
+
+static void xgene_cle_idt_to_hw(u32 dstqid, u32 fpsel,
+				u32 nfpsel, u32 *idt_reg)
+{
+	*idt_reg =  SET_VAL(IDT_DSTQID, dstqid) |
+		    SET_VAL(IDT_FPSEL, fpsel) |
+		    SET_VAL(IDT_NFPSEL, nfpsel);
+}
+
+static void xgene_cle_dbptr_to_hw(struct xgene_enet_pdata *pdata,
+				  struct xgene_cle_dbptr *dbptr, u32 *buf)
+{
+	buf[0] = SET_VAL(CLE_DROP, dbptr->drop);
+	buf[4] = SET_VAL(CLE_FPSEL, dbptr->fpsel) |
+		 SET_VAL(CLE_DSTQIDL, dbptr->dstqid);
+
+	buf[5] = SET_VAL(CLE_DSTQIDH, (u32)dbptr->dstqid >> CLE_DSTQIDL_LEN) |
+		 SET_VAL(CLE_PRIORITY, dbptr->cle_priority);
+}
+
+static void xgene_cle_kn_to_hw(struct xgene_cle_ptree_kn *kn, u32 *buf)
+{
+	u32 i, j = 0;
+	u32 data;
+
+	buf[j++] = SET_VAL(CLE_TYPE, kn->node_type);
+	for (i = 0; i < kn->num_keys; i++) {
+		struct xgene_cle_ptree_key *key = &kn->key[i];
+
+		if (!(i % 2)) {
+			buf[j] = SET_VAL(CLE_KN_PRIO, key->priority) |
+				 SET_VAL(CLE_KN_RPTR, key->result_pointer);
+		} else {
+			data = SET_VAL(CLE_KN_PRIO, key->priority) |
+			       SET_VAL(CLE_KN_RPTR, key->result_pointer);
+			buf[j++] |= (data << 16);
+		}
+	}
+}
+
+static void xgene_cle_dn_to_hw(struct xgene_cle_ptree_ewdn *dn,
+			       u32 *buf, u32 jb)
+{
+	struct xgene_cle_ptree_branch *br;
+	u32 i, j = 0;
+	u32 npp;
+
+	buf[j++] = SET_VAL(CLE_DN_TYPE, dn->node_type) |
+		   SET_VAL(CLE_DN_LASTN, dn->last_node) |
+		   SET_VAL(CLE_DN_HLS, dn->hdr_len_store) |
+		   SET_VAL(CLE_DN_EXT, dn->hdr_extn) |
+		   SET_VAL(CLE_DN_BSTOR, dn->byte_store) |
+		   SET_VAL(CLE_DN_SBSTOR, dn->search_byte_store) |
+		   SET_VAL(CLE_DN_RPTR, dn->result_pointer);
+
+	for (i = 0; i < dn->num_branches; i++) {
+		br = &dn->branch[i];
+		npp = br->next_packet_pointer;
+
+		if ((br->jump_rel == JMP_ABS) && (npp < CLE_PKTRAM_SIZE))
+			npp += jb;
+
+		buf[j++] = SET_VAL(CLE_BR_VALID, br->valid) |
+			   SET_VAL(CLE_BR_NPPTR, npp) |
+			   SET_VAL(CLE_BR_JB, br->jump_bw) |
+			   SET_VAL(CLE_BR_JR, br->jump_rel) |
+			   SET_VAL(CLE_BR_OP, br->operation) |
+			   SET_VAL(CLE_BR_NNODE, br->next_node) |
+			   SET_VAL(CLE_BR_NBR, br->next_branch);
+
+		buf[j++] = SET_VAL(CLE_BR_DATA, br->data) |
+			   SET_VAL(CLE_BR_MASK, br->mask);
+	}
+}
+
+static int xgene_cle_poll_cmd_done(void __iomem *base,
+				   enum xgene_cle_cmd_type cmd)
+{
+	u32 status, loop = 10;
+	int ret = -EBUSY;
+
+	while (loop--) {
+		status = ioread32(base + INDCMD_STATUS);
+		if (status & cmd) {
+			ret = 0;
+			break;
+		}
+		usleep_range(1000, 2000);
+	}
+
+	return ret;
+}
+
+static int xgene_cle_dram_wr(struct xgene_enet_cle *cle, u32 *data, u8 nregs,
+			     u32 index, enum xgene_cle_dram_type type,
+			     enum xgene_cle_cmd_type cmd)
+{
+	enum xgene_cle_parser parser = cle->active_parser;
+	void __iomem *base = cle->base;
+	u32 i, j, ind_addr;
+	u8 port, nparsers;
+	int ret = 0;
+
+	/* PTREE_RAM onwards, DRAM regions are common for all parsers */
+	nparsers = (type >= PTREE_RAM) ? 1 : cle->parsers;
+
+	for (i = 0; i < nparsers; i++) {
+		port = i;
+		if ((type < PTREE_RAM) && (parser != PARSER_ALL))
+			port = parser;
+
+		ind_addr = XGENE_CLE_DRAM(type + (port * 4)) | index;
+		iowrite32(ind_addr, base + INDADDR);
+		for (j = 0; j < nregs; j++)
+			iowrite32(data[j], base + DATA_RAM0 + (j * 4));
+		iowrite32(cmd, base + INDCMD);
+
+		ret = xgene_cle_poll_cmd_done(base, cmd);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static void xgene_cle_enable_ptree(struct xgene_enet_pdata *pdata,
+				   struct xgene_enet_cle *cle)
+{
+	struct xgene_cle_ptree *ptree = &cle->ptree;
+	void __iomem *addr, *base = cle->base;
+	u32 offset = CLE_PORT_OFFSET;
+	u32 i;
+
+	/* 1G port has to advance 4 bytes and 10G has to advance 8 bytes */
+	ptree->start_pkt += cle->jump_bytes;
+	for (i = 0; i < cle->parsers; i++) {
+		if (cle->active_parser != PARSER_ALL)
+			addr = base + cle->active_parser * offset;
+		else
+			addr = base + (i * offset);
+
+		iowrite32(ptree->start_node & 0x3fff, addr + SNPTR0);
+		iowrite32(ptree->start_pkt & 0x1ff, addr + SPPTR0);
+	}
+}
+
+static int xgene_cle_setup_dbptr(struct xgene_enet_pdata *pdata,
+				 struct xgene_enet_cle *cle)
+{
+	struct xgene_cle_ptree *ptree = &cle->ptree;
+	u32 buf[CLE_DRAM_REGS];
+	u32 i;
+	int ret;
+
+	memset(buf, 0, sizeof(buf));
+	for (i = 0; i < ptree->num_dbptr; i++) {
+		xgene_cle_dbptr_to_hw(pdata, &ptree->dbptr[i], buf);
+		ret = xgene_cle_dram_wr(cle, buf, 6, i + ptree->start_dbptr,
+					DB_RAM,	CLE_CMD_WR);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int xgene_cle_setup_node(struct xgene_enet_pdata *pdata,
+				struct xgene_enet_cle *cle)
+{
+	struct xgene_cle_ptree *ptree = &cle->ptree;
+	struct xgene_cle_ptree_ewdn *dn = ptree->dn;
+	struct xgene_cle_ptree_kn *kn = ptree->kn;
+	u32 buf[CLE_DRAM_REGS];
+	int i, j, ret;
+
+	memset(buf, 0, sizeof(buf));
+	for (i = 0; i < ptree->num_dn; i++) {
+		xgene_cle_dn_to_hw(&dn[i], buf, cle->jump_bytes);
+		ret = xgene_cle_dram_wr(cle, buf, 17, i + ptree->start_node,
+					PTREE_RAM, CLE_CMD_WR);
+		if (ret)
+			return ret;
+	}
+
+	/* continue node index for key node */
+	memset(buf, 0, sizeof(buf));
+	for (j = i; j < (ptree->num_kn + ptree->num_dn); j++) {
+		xgene_cle_kn_to_hw(&kn[j - ptree->num_dn], buf);
+		ret = xgene_cle_dram_wr(cle, buf, 17, j + ptree->start_node,
+					PTREE_RAM, CLE_CMD_WR);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int xgene_cle_setup_ptree(struct xgene_enet_pdata *pdata,
+				 struct xgene_enet_cle *cle)
+{
+	int ret;
+
+	ret = xgene_cle_setup_node(pdata, cle);
+	if (ret)
+		return ret;
+
+	ret = xgene_cle_setup_dbptr(pdata, cle);
+	if (ret)
+		return ret;
+
+	xgene_cle_enable_ptree(pdata, cle);
+
+	return 0;
+}
+
+static void xgene_cle_setup_def_dbptr(struct xgene_enet_pdata *pdata,
+				      struct xgene_enet_cle *enet_cle,
+				      struct xgene_cle_dbptr *dbptr,
+				      u32 index, u8 priority)
+{
+	void __iomem *base = enet_cle->base;
+	void __iomem *base_addr;
+	u32 buf[CLE_DRAM_REGS];
+	u32 def_cls, offset;
+	u32 i, j;
+
+	memset(buf, 0, sizeof(buf));
+	xgene_cle_dbptr_to_hw(pdata, dbptr, buf);
+
+	for (i = 0; i < enet_cle->parsers; i++) {
+		if (enet_cle->active_parser != PARSER_ALL) {
+			offset = enet_cle->active_parser *
+				CLE_PORT_OFFSET;
+		} else {
+			offset = i * CLE_PORT_OFFSET;
+		}
+
+		base_addr = base + DFCLSRESDB00 + offset;
+		for (j = 0; j < 6; j++)
+			iowrite32(buf[j], base_addr + (j * 4));
+
+		def_cls = ((priority & 0x7) << 10) | (index & 0x3ff);
+		iowrite32(def_cls, base + DFCLSRESDBPTR0 + offset);
+	}
+}
+
+static int xgene_cle_set_rss_sband(struct xgene_enet_cle *cle)
+{
+	u32 idx = CLE_PKTRAM_SIZE / sizeof(u32);
+	u32 mac_hdr_len = ETH_HLEN;
+	u32 sband, reg = 0;
+	u32 ipv4_ihl = 5;
+	u32 hdr_len;
+	int ret;
+
+	/* Sideband: IPV4/TCP packets */
+	hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
+	xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_TCP, hdr_len, &reg);
+	sband = reg;
+
+	/* Sideband: IPv4/UDP packets */
+	hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
+	xgene_cle_sband_to_hw(1, XGENE_CLE_IPV4, XGENE_CLE_UDP, hdr_len, &reg);
+	sband |= (reg << 16);
+
+	ret = xgene_cle_dram_wr(cle, &sband, 1, idx, PKT_RAM, CLE_CMD_WR);
+	if (ret)
+		return ret;
+
+	/* Sideband: IPv4/RAW packets */
+	hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
+	xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_OTHER,
+			      hdr_len, &reg);
+	sband = reg;
+
+	/* Sideband: Ethernet II/RAW packets */
+	hdr_len = (mac_hdr_len << 5);
+	xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_OTHER,
+			      hdr_len, &reg);
+	sband |= (reg << 16);
+
+	ret = xgene_cle_dram_wr(cle, &sband, 1, idx + 1, PKT_RAM, CLE_CMD_WR);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int xgene_cle_set_rss_skeys(struct xgene_enet_cle *cle)
+{
+	u32 secret_key_ipv4[4];  /* 16 Bytes*/
+	int ret = 0;
+
+	get_random_bytes(secret_key_ipv4, 16);
+	ret = xgene_cle_dram_wr(cle, secret_key_ipv4, 4, 0,
+				RSS_IPV4_HASH_SKEY, CLE_CMD_WR);
+	return ret;
+}
+
+static int xgene_cle_set_rss_idt(struct xgene_enet_pdata *pdata)
+{
+	u32 fpsel, dstqid, nfpsel, idt_reg, idx;
+	int i, ret = 0;
+	u16 pool_id;
+
+	for (i = 0; i < XGENE_CLE_IDT_ENTRIES; i++) {
+		idx = i % pdata->rxq_cnt;
+		pool_id = pdata->rx_ring[idx]->buf_pool->id;
+		fpsel = xgene_enet_ring_bufnum(pool_id) - 0x20;
+		dstqid = xgene_enet_dst_ring_num(pdata->rx_ring[idx]);
+		nfpsel = 0;
+		idt_reg = 0;
+
+		xgene_cle_idt_to_hw(dstqid, fpsel, nfpsel, &idt_reg);
+		ret = xgene_cle_dram_wr(&pdata->cle, &idt_reg, 1, i,
+					RSS_IDT, CLE_CMD_WR);
+		if (ret)
+			return ret;
+	}
+
+	ret = xgene_cle_set_rss_skeys(&pdata->cle);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int xgene_cle_setup_rss(struct xgene_enet_pdata *pdata)
+{
+	struct xgene_enet_cle *cle = &pdata->cle;
+	void __iomem *base = cle->base;
+	u32 offset, val = 0;
+	int i, ret = 0;
+
+	offset = CLE_PORT_OFFSET;
+	for (i = 0; i < cle->parsers; i++) {
+		if (cle->active_parser != PARSER_ALL)
+			offset = cle->active_parser * CLE_PORT_OFFSET;
+		else
+			offset = i * CLE_PORT_OFFSET;
+
+		/* enable RSS */
+		val = (RSS_IPV4_12B << 1) | 0x1;
+		writel(val, base + RSS_CTRL0 + offset);
+	}
+
+	/* setup sideband data */
+	ret = xgene_cle_set_rss_sband(cle);
+	if (ret)
+		return ret;
+
+	/* setup indirection table */
+	ret = xgene_cle_set_rss_idt(pdata);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata)
+{
+	struct xgene_enet_cle *enet_cle = &pdata->cle;
+	struct xgene_cle_dbptr dbptr[DB_MAX_PTRS];
+	struct xgene_cle_ptree_branch *br;
+	u32 def_qid, def_fpsel, pool_id;
+	struct xgene_cle_ptree *ptree;
+	struct xgene_cle_ptree_kn kn;
+	int ret;
+	struct xgene_cle_ptree_ewdn ptree_dn[] = {
+		{
+			/* PKT_TYPE_NODE */
+			.node_type = EWDN,
+			.last_node = 0,
+			.hdr_len_store = 1,
+			.hdr_extn = NO_BYTE,
+			.byte_store = NO_BYTE,
+			.search_byte_store = NO_BYTE,
+			.result_pointer = DB_RES_DROP,
+			.num_branches = 2,
+			.branch = {
+				{
+					/* IPV4 */
+					.valid = 1,
+					.next_packet_pointer = 22,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = PKT_PROT_NODE,
+					.next_branch = 0,
+					.data = 0x8,
+					.mask = 0x0
+				},
+				{
+					.valid = 0,
+					.next_packet_pointer = 262,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = LAST_NODE,
+					.next_branch = 0,
+					.data = 0x0,
+					.mask = 0xffff
+				}
+			},
+		},
+		{
+			/* PKT_PROT_NODE */
+			.node_type = EWDN,
+			.last_node = 0,
+			.hdr_len_store = 1,
+			.hdr_extn = NO_BYTE,
+			.byte_store = NO_BYTE,
+			.search_byte_store = NO_BYTE,
+			.result_pointer = DB_RES_DROP,
+			.num_branches = 3,
+			.branch = {
+				{
+					/* TCP */
+					.valid = 1,
+					.next_packet_pointer = 26,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_TCP_NODE,
+					.next_branch = 0,
+					.data = 0x0600,
+					.mask = 0x00ff
+				},
+				{
+					/* UDP */
+					.valid = 1,
+					.next_packet_pointer = 26,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_UDP_NODE,
+					.next_branch = 0,
+					.data = 0x1100,
+					.mask = 0x00ff
+				},
+				{
+					.valid = 0,
+					.next_packet_pointer = 260,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = LAST_NODE,
+					.next_branch = 0,
+					.data = 0x0,
+					.mask = 0xffff
+				}
+			}
+		},
+		{
+			/* RSS_IPV4_TCP_NODE */
+			.node_type = EWDN,
+			.last_node = 0,
+			.hdr_len_store = 1,
+			.hdr_extn = NO_BYTE,
+			.byte_store = NO_BYTE,
+			.search_byte_store = BOTH_BYTES,
+			.result_pointer = DB_RES_DROP,
+			.num_branches = 6,
+			.branch = {
+				{
+					/* SRC IPV4 B01 */
+					.valid = 0,
+					.next_packet_pointer = 28,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_TCP_NODE,
+					.next_branch = 1,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* SRC IPV4 B23 */
+					.valid = 0,
+					.next_packet_pointer = 30,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_TCP_NODE,
+					.next_branch = 2,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* DST IPV4 B01 */
+					.valid = 0,
+					.next_packet_pointer = 32,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_TCP_NODE,
+					.next_branch = 3,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* DST IPV4 B23 */
+					.valid = 0,
+					.next_packet_pointer = 34,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_TCP_NODE,
+					.next_branch = 4,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* TCP SRC Port */
+					.valid = 0,
+					.next_packet_pointer = 36,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_TCP_NODE,
+					.next_branch = 5,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* TCP DST Port */
+					.valid = 0,
+					.next_packet_pointer = 256,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = LAST_NODE,
+					.next_branch = 0,
+					.data = 0x0,
+					.mask = 0xffff
+				}
+			}
+		},
+		{
+			/* RSS_IPV4_UDP_NODE */
+			.node_type = EWDN,
+			.last_node = 0,
+			.hdr_len_store = 1,
+			.hdr_extn = NO_BYTE,
+			.byte_store = NO_BYTE,
+			.search_byte_store = BOTH_BYTES,
+			.result_pointer = DB_RES_DROP,
+			.num_branches = 6,
+			.branch = {
+				{
+					/* SRC IPV4 B01 */
+					.valid = 0,
+					.next_packet_pointer = 28,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_UDP_NODE,
+					.next_branch = 1,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* SRC IPV4 B23 */
+					.valid = 0,
+					.next_packet_pointer = 30,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_UDP_NODE,
+					.next_branch = 2,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* DST IPV4 B01 */
+					.valid = 0,
+					.next_packet_pointer = 32,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_UDP_NODE,
+					.next_branch = 3,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* DST IPV4 B23 */
+					.valid = 0,
+					.next_packet_pointer = 34,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_UDP_NODE,
+					.next_branch = 4,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* TCP SRC Port */
+					.valid = 0,
+					.next_packet_pointer = 36,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = RSS_IPV4_UDP_NODE,
+					.next_branch = 5,
+					.data = 0x0,
+					.mask = 0xffff
+				},
+				{
+					/* TCP DST Port */
+					.valid = 0,
+					.next_packet_pointer = 258,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = LAST_NODE,
+					.next_branch = 0,
+					.data = 0x0,
+					.mask = 0xffff
+				}
+			}
+		},
+		{
+			/* LAST NODE */
+			.node_type = EWDN,
+			.last_node = 1,
+			.hdr_len_store = 1,
+			.hdr_extn = NO_BYTE,
+			.byte_store = NO_BYTE,
+			.search_byte_store = NO_BYTE,
+			.result_pointer = DB_RES_DROP,
+			.num_branches = 1,
+			.branch = {
+				{
+					.valid = 0,
+					.next_packet_pointer = 0,
+					.jump_bw = JMP_FW,
+					.jump_rel = JMP_ABS,
+					.operation = EQT,
+					.next_node = MAX_NODES,
+					.next_branch = 0,
+					.data = 0,
+					.mask = 0xffff
+				}
+			}
+		}
+	};
+
+	ptree = &enet_cle->ptree;
+	ptree->start_pkt = 12; /* Ethertype */
+	if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+		ret = xgene_cle_setup_rss(pdata);
+		if (ret) {
+			netdev_err(pdata->ndev, "RSS initialization failed\n");
+			return ret;
+		}
+	} else {
+		br = &ptree_dn[PKT_PROT_NODE].branch[0];
+		br->valid = 0;
+		br->next_packet_pointer = 260;
+		br->next_node = LAST_NODE;
+		br->data = 0x0000;
+		br->mask = 0xffff;
+	}
+
+	def_qid = xgene_enet_dst_ring_num(pdata->rx_ring[0]);
+	pool_id = pdata->rx_ring[0]->buf_pool->id;
+	def_fpsel = xgene_enet_ring_bufnum(pool_id) - 0x20;
+
+	memset(dbptr, 0, sizeof(struct xgene_cle_dbptr) * DB_MAX_PTRS);
+	dbptr[DB_RES_ACCEPT].fpsel =  def_fpsel;
+	dbptr[DB_RES_ACCEPT].dstqid = def_qid;
+	dbptr[DB_RES_ACCEPT].cle_priority = 1;
+
+	dbptr[DB_RES_DEF].fpsel = def_fpsel;
+	dbptr[DB_RES_DEF].dstqid = def_qid;
+	dbptr[DB_RES_DEF].cle_priority = 7;
+	xgene_cle_setup_def_dbptr(pdata, enet_cle, &dbptr[DB_RES_DEF],
+				  DB_RES_ACCEPT, 7);
+
+	dbptr[DB_RES_DROP].drop = 1;
+
+	memset(&kn, 0, sizeof(kn));
+	kn.node_type = KN;
+	kn.num_keys = 1;
+	kn.key[0].priority = 0;
+	kn.key[0].result_pointer = DB_RES_ACCEPT;
+
+	ptree->dn = ptree_dn;
+	ptree->kn = &kn;
+	ptree->dbptr = dbptr;
+	ptree->num_dn = MAX_NODES;
+	ptree->num_kn = 1;
+	ptree->num_dbptr = DB_MAX_PTRS;
+
+	return xgene_cle_setup_ptree(pdata, enet_cle);
+}
+
+const struct xgene_cle_ops xgene_cle3in_ops = {
+	.cle_init = xgene_enet_cle_init,
+};
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_cle.h
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_cle.h
@@ -0,0 +1,297 @@
+/* Applied Micro X-Gene SoC Ethernet Classifier structures
+ *
+ * Copyright (c) 2016, Applied Micro Circuits Corporation
+ * Authors: Khuong Dinh <kdinh@apm.com>
+ *          Tanmay Inamdar <tinamdar@apm.com>
+ *          Iyappan Subramanian <isubramanian@apm.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __XGENE_ENET_CLE_H__
+#define __XGENE_ENET_CLE_H__
+
+#include <linux/io.h>
+#include <linux/random.h>
+
+/* Register offsets */
+#define INDADDR			0x04
+#define INDCMD			0x08
+#define INDCMD_STATUS		0x0c
+#define DATA_RAM0		0x10
+#define SNPTR0			0x0100
+#define SPPTR0			0x0104
+#define DFCLSRESDBPTR0		0x0108
+#define DFCLSRESDB00		0x010c
+#define RSS_CTRL0		0x0000013c
+
+#define CLE_CMD_TO		10	/* ms */
+#define CLE_PKTRAM_SIZE		256	/* bytes */
+#define CLE_PORT_OFFSET		0x200
+#define CLE_DRAM_REGS		17
+
+#define CLE_DN_TYPE_LEN		2
+#define CLE_DN_TYPE_POS		0
+#define CLE_DN_LASTN_LEN	1
+#define CLE_DN_LASTN_POS	2
+#define CLE_DN_HLS_LEN		1
+#define CLE_DN_HLS_POS		3
+#define CLE_DN_EXT_LEN		2
+#define	CLE_DN_EXT_POS		4
+#define CLE_DN_BSTOR_LEN	2
+#define CLE_DN_BSTOR_POS	6
+#define CLE_DN_SBSTOR_LEN	2
+#define CLE_DN_SBSTOR_POS	8
+#define CLE_DN_RPTR_LEN		12
+#define CLE_DN_RPTR_POS		12
+
+#define CLE_BR_VALID_LEN	1
+#define CLE_BR_VALID_POS	0
+#define CLE_BR_NPPTR_LEN	9
+#define CLE_BR_NPPTR_POS	1
+#define CLE_BR_JB_LEN		1
+#define CLE_BR_JB_POS		10
+#define CLE_BR_JR_LEN		1
+#define CLE_BR_JR_POS		11
+#define CLE_BR_OP_LEN		3
+#define CLE_BR_OP_POS		12
+#define CLE_BR_NNODE_LEN	9
+#define CLE_BR_NNODE_POS	15
+#define CLE_BR_NBR_LEN		5
+#define CLE_BR_NBR_POS		24
+
+#define CLE_BR_DATA_LEN		16
+#define CLE_BR_DATA_POS		0
+#define CLE_BR_MASK_LEN		16
+#define CLE_BR_MASK_POS		16
+
+#define CLE_KN_PRIO_POS		0
+#define CLE_KN_PRIO_LEN		3
+#define CLE_KN_RPTR_POS		3
+#define CLE_KN_RPTR_LEN		10
+#define CLE_TYPE_POS		0
+#define CLE_TYPE_LEN		2
+
+#define CLE_DROP_POS		28
+#define CLE_DROP_LEN		1
+#define CLE_DSTQIDL_POS		25
+#define CLE_DSTQIDL_LEN		7
+#define CLE_DSTQIDH_POS		0
+#define CLE_DSTQIDH_LEN		5
+#define CLE_FPSEL_POS		21
+#define CLE_FPSEL_LEN		4
+#define CLE_PRIORITY_POS	5
+#define CLE_PRIORITY_LEN	3
+
+#define JMP_ABS			0
+#define JMP_REL			1
+#define JMP_FW			0
+#define JMP_BW			1
+
+enum xgene_cle_ptree_nodes {
+	PKT_TYPE_NODE,
+	PKT_PROT_NODE,
+	RSS_IPV4_TCP_NODE,
+	RSS_IPV4_UDP_NODE,
+	LAST_NODE,
+	MAX_NODES
+};
+
+enum xgene_cle_byte_store {
+	NO_BYTE,
+	FIRST_BYTE,
+	SECOND_BYTE,
+	BOTH_BYTES
+};
+
+/* Preclassification operation types */
+enum xgene_cle_node_type {
+	INV,
+	KN,
+	EWDN,
+	RES_NODE
+};
+
+/* Preclassification operation types */
+enum xgene_cle_op_type {
+	EQT,
+	NEQT,
+	LTEQT,
+	GTEQT,
+	AND,
+	NAND
+};
+
+enum xgene_cle_parser {
+	PARSER0,
+	PARSER1,
+	PARSER2,
+	PARSER_ALL
+};
+
+#define XGENE_CLE_DRAM(type)	(((type) & 0xf) << 28)
+enum xgene_cle_dram_type {
+	PKT_RAM,
+	RSS_IDT,
+	RSS_IPV4_HASH_SKEY,
+	PTREE_RAM = 0xc,
+	AVL_RAM,
+	DB_RAM
+};
+
+enum xgene_cle_cmd_type {
+	CLE_CMD_WR = 1,
+	CLE_CMD_RD = 2,
+	CLE_CMD_AVL_ADD = 8,
+	CLE_CMD_AVL_DEL = 16,
+	CLE_CMD_AVL_SRCH = 32
+};
+
+enum xgene_cle_ipv4_rss_hashtype {
+	RSS_IPV4_8B,
+	RSS_IPV4_12B,
+};
+
+enum xgene_cle_prot_type {
+	XGENE_CLE_TCP,
+	XGENE_CLE_UDP,
+	XGENE_CLE_ESP,
+	XGENE_CLE_OTHER
+};
+
+enum xgene_cle_prot_version {
+	XGENE_CLE_IPV4,
+};
+
+enum xgene_cle_ptree_dbptrs {
+	DB_RES_DROP,
+	DB_RES_DEF,
+	DB_RES_ACCEPT,
+	DB_MAX_PTRS
+};
+
+/* RSS sideband signal info */
+#define SB_IPFRAG_POS	0
+#define SB_IPFRAG_LEN	1
+#define SB_IPPROT_POS	1
+#define SB_IPPROT_LEN	2
+#define SB_IPVER_POS	3
+#define SB_IPVER_LEN	1
+#define SB_HDRLEN_POS	4
+#define SB_HDRLEN_LEN	12
+
+/* RSS indirection table */
+#define XGENE_CLE_IDT_ENTRIES	128
+#define IDT_DSTQID_POS		0
+#define IDT_DSTQID_LEN		12
+#define IDT_FPSEL_POS		12
+#define IDT_FPSEL_LEN		4
+#define IDT_NFPSEL_POS		16
+#define IDT_NFPSEL_LEN		4
+
+struct xgene_cle_ptree_branch {
+	bool valid;
+	u16 next_packet_pointer;
+	bool jump_bw;
+	bool jump_rel;
+	u8 operation;
+	u16 next_node;
+	u8 next_branch;
+	u16 data;
+	u16 mask;
+};
+
+struct xgene_cle_ptree_ewdn {
+	u8 node_type;
+	bool last_node;
+	bool hdr_len_store;
+	u8 hdr_extn;
+	u8 byte_store;
+	u8 search_byte_store;
+	u16 result_pointer;
+	u8 num_branches;
+	struct xgene_cle_ptree_branch branch[6];
+};
+
+struct xgene_cle_ptree_key {
+	u8 priority;
+	u16 result_pointer;
+};
+
+struct xgene_cle_ptree_kn {
+	u8 node_type;
+	u8 num_keys;
+	struct xgene_cle_ptree_key key[32];
+};
+
+struct xgene_cle_dbptr {
+	u8 split_boundary;
+	u8 mirror_nxtfpsel;
+	u8 mirror_fpsel;
+	u16 mirror_dstqid;
+	u8 drop;
+	u8 mirror;
+	u8 hdr_data_split;
+	u64 hopinfomsbs;
+	u8 DR;
+	u8 HR;
+	u64 hopinfomlsbs;
+	u16 h0enq_num;
+	u8 h0fpsel;
+	u8 nxtfpsel;
+	u8 fpsel;
+	u16 dstqid;
+	u8 cle_priority;
+	u8 cle_flowgroup;
+	u8 cle_perflow;
+	u8 cle_insert_timestamp;
+	u8 stash;
+	u8 in;
+	u8 perprioen;
+	u8 perflowgroupen;
+	u8 perflowen;
+	u8 selhash;
+	u8 selhdrext;
+	u8 mirror_nxtfpsel_msb;
+	u8 mirror_fpsel_msb;
+	u8 hfpsel_msb;
+	u8 nxtfpsel_msb;
+	u8 fpsel_msb;
+};
+
+struct xgene_cle_ptree {
+	struct xgene_cle_ptree_ewdn *dn;
+	struct xgene_cle_ptree_kn *kn;
+	struct xgene_cle_dbptr *dbptr;
+	u32 num_dn;
+	u32 num_kn;
+	u32 num_dbptr;
+	u32 start_node;
+	u32 start_pkt;
+	u32 start_dbptr;
+};
+
+struct xgene_enet_cle {
+	void __iomem *base;
+	struct xgene_cle_ptree ptree;
+	enum xgene_cle_parser active_parser;
+	u32 parsers;
+	u32 max_nodes;
+	u32 max_dbptrs;
+	u32 jump_bytes;
+};
+
+extern const struct xgene_cle_ops xgene_cle3in_ops;
+
+#endif /* __XGENE_ENET_CLE_H__ */
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
@@ -65,8 +65,15 @@
 
 		return phy_ethtool_gset(phydev, cmd);
 	} else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
-		cmd->supported = SUPPORTED_1000baseT_Full |
-				 SUPPORTED_Autoneg | SUPPORTED_MII;
+		if (pdata->mdio_driver) {
+			if (!phydev)
+				return -ENODEV;
+
+			return phy_ethtool_gset(phydev, cmd);
+		}
+
+		cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+				 SUPPORTED_MII;
 		cmd->advertising = cmd->supported;
 		ethtool_cmd_speed_set(cmd, SPEED_1000);
 		cmd->duplex = DUPLEX_FULL;
@@ -92,12 +99,21 @@
 	struct phy_device *phydev = pdata->phy_dev;
 
 	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
-		if (phydev == NULL)
+		if (!phydev)
 			return -ENODEV;
 
 		return phy_ethtool_sset(phydev, cmd);
 	}
 
+	if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
+		if (pdata->mdio_driver) {
+			if (!phydev)
+				return -ENODEV;
+
+			return phy_ethtool_sset(phydev, cmd);
+		}
+	}
+
 	return -EINVAL;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
@@ -204,31 +204,45 @@
 	return num_msgs;
 }
 
+static void xgene_enet_setup_coalescing(struct xgene_enet_desc_ring *ring)
+{
+	u32 data = 0x7777;
+
+	xgene_enet_ring_wr32(ring, CSR_PBM_COAL, 0x8e);
+	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK1, data);
+	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data << 16);
+	xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x40);
+	xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x80);
+}
+
 void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
 			    struct xgene_enet_pdata *pdata,
 			    enum xgene_enet_err_code status)
 {
-	struct rtnl_link_stats64 *stats = &pdata->stats;
-
 	switch (status) {
 	case INGRESS_CRC:
-		stats->rx_crc_errors++;
+		ring->rx_crc_errors++;
+		ring->rx_dropped++;
 		break;
 	case INGRESS_CHECKSUM:
 	case INGRESS_CHECKSUM_COMPUTE:
-		stats->rx_errors++;
+		ring->rx_errors++;
+		ring->rx_dropped++;
 		break;
 	case INGRESS_TRUNC_FRAME:
-		stats->rx_frame_errors++;
+		ring->rx_frame_errors++;
+		ring->rx_dropped++;
 		break;
 	case INGRESS_PKT_LEN:
-		stats->rx_length_errors++;
+		ring->rx_length_errors++;
+		ring->rx_dropped++;
 		break;
 	case INGRESS_PKT_UNDER:
-		stats->rx_frame_errors++;
+		ring->rx_frame_errors++;
+		ring->rx_dropped++;
 		break;
 	case INGRESS_FIFO_OVERRUN:
-		stats->rx_fifo_errors++;
+		ring->rx_fifo_errors++;
 		break;
 	default:
 		break;
@@ -367,59 +381,6 @@
 			   rd_addr);
 }
 
-static int xgene_mii_phy_write(struct xgene_enet_pdata *pdata, int phy_id,
-			       u32 reg, u16 data)
-{
-	u32 addr = 0, wr_data = 0;
-	u32 done;
-	u8 wait = 10;
-
-	PHY_ADDR_SET(&addr, phy_id);
-	REG_ADDR_SET(&addr, reg);
-	xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr);
-
-	PHY_CONTROL_SET(&wr_data, data);
-	xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONTROL_ADDR, wr_data);
-	do {
-		usleep_range(5, 10);
-		xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done);
-	} while ((done & BUSY_MASK) && wait--);
-
-	if (done & BUSY_MASK) {
-		netdev_err(pdata->ndev, "MII_MGMT write failed\n");
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata,
-			      u8 phy_id, u32 reg)
-{
-	u32 addr = 0;
-	u32 data, done;
-	u8 wait = 10;
-
-	PHY_ADDR_SET(&addr, phy_id);
-	REG_ADDR_SET(&addr, reg);
-	xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr);
-	xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK);
-	do {
-		usleep_range(5, 10);
-		xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done);
-	} while ((done & BUSY_MASK) && wait--);
-
-	if (done & BUSY_MASK) {
-		netdev_err(pdata->ndev, "MII_MGMT read failed\n");
-		return -EBUSY;
-	}
-
-	xgene_enet_rd_mcx_mac(pdata, MII_MGMT_STATUS_ADDR, &data);
-	xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, 0);
-
-	return data;
-}
-
 static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata)
 {
 	u32 addr0, addr1;
@@ -498,14 +459,11 @@
 #endif
 }
 
-static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
+static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata)
 {
 	struct device *dev = &pdata->pdev->dev;
-	u32 value, mc2;
-	u32 intf_ctl, rgmii;
-	u32 icm0, icm2;
-
-	xgene_gmac_reset(pdata);
+	u32 icm0, icm2, mc2;
+	u32 intf_ctl, rgmii, value;
 
 	xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0);
 	xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2);
@@ -550,7 +508,21 @@
 	mc2 |= FULL_DUPLEX2 | PAD_CRC;
 	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2);
 	xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl);
+	xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii);
+	xgene_enet_configure_clock(pdata);
 
+	xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0);
+	xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2);
+}
+
+static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
+{
+	u32 value;
+
+	if (!pdata->mdio_driver)
+		xgene_gmac_reset(pdata);
+
+	xgene_gmac_set_speed(pdata);
 	xgene_gmac_set_mac_addr(pdata);
 
 	/* Adjust MDC clock frequency */
@@ -565,15 +537,10 @@
 
 	/* Rtype should be copied from FP */
 	xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0);
-	xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii);
-	xgene_enet_configure_clock(pdata);
 
 	/* Rx-Tx traffic resume */
 	xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0);
 
-	xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0);
-	xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2);
-
 	xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value);
 	value &= ~TX_DV_GATE_EN0;
 	value &= ~RX_DV_GATE_EN0;
@@ -604,6 +571,7 @@
 	xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb);
 	cb |= CFG_CLE_BYPASS_EN0;
 	CFG_CLE_IP_PROTOCOL0_SET(&cb, 3);
+	CFG_CLE_IP_HDR_LEN_SET(&cb, 0);
 	xgene_enet_wr_csr(pdata, CLE_BYPASS_REG0_0_ADDR, cb);
 
 	xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb);
@@ -657,92 +625,133 @@
 
 static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
 {
-	u32 val;
+	struct device *dev = &pdata->pdev->dev;
 
 	if (!xgene_ring_mgr_init(pdata))
 		return -ENODEV;
 
-	if (!IS_ERR(pdata->clk)) {
+	if (pdata->mdio_driver) {
+		xgene_enet_config_ring_if_assoc(pdata);
+		return 0;
+	}
+
+	if (dev->of_node) {
 		clk_prepare_enable(pdata->clk);
+		udelay(5);
 		clk_disable_unprepare(pdata->clk);
+		udelay(5);
 		clk_prepare_enable(pdata->clk);
-		xgene_enet_ecc_init(pdata);
+		udelay(5);
+	} else {
+#ifdef CONFIG_ACPI
+		if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), "_RST")) {
+			acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
+					     "_RST", NULL, NULL);
+		} else if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev),
+					 "_INI")) {
+			acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
+					     "_INI", NULL, NULL);
+		}
+#endif
 	}
-	xgene_enet_config_ring_if_assoc(pdata);
 
-	/* Enable auto-incr for scanning */
-	xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val);
-	val |= SCAN_AUTO_INCR;
-	MGMT_CLOCK_SEL_SET(&val, 1);
-	xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val);
+	xgene_enet_ecc_init(pdata);
+	xgene_enet_config_ring_if_assoc(pdata);
 
 	return 0;
 }
 
-static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
+static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
+			     struct xgene_enet_desc_ring *ring)
 {
-	if (!IS_ERR(pdata->clk))
-		clk_disable_unprepare(pdata->clk);
-}
+	u32 addr, val, data;
 
-static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-	struct xgene_enet_pdata *pdata = bus->priv;
-	u32 val;
+	val = xgene_enet_ring_bufnum(ring->id);
 
-	val = xgene_mii_phy_read(pdata, mii_id, regnum);
-	netdev_dbg(pdata->ndev, "mdio_rd: bus=%d reg=%d val=%x\n",
-		   mii_id, regnum, val);
+	if (xgene_enet_is_bufpool(ring->id)) {
+		addr = ENET_CFGSSQMIFPRESET_ADDR;
+		data = BIT(val - 0x20);
+	} else {
+		addr = ENET_CFGSSQMIWQRESET_ADDR;
+		data = BIT(val);
+	}
 
-	return val;
+	xgene_enet_wr_ring_if(pdata, addr, data);
 }
 
-static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
-				 u16 val)
+static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
 {
-	struct xgene_enet_pdata *pdata = bus->priv;
+	struct device *dev = &pdata->pdev->dev;
 
-	netdev_dbg(pdata->ndev, "mdio_wr: bus=%d reg=%d val=%x\n",
-		   mii_id, regnum, val);
-	return xgene_mii_phy_write(pdata, mii_id, regnum, val);
+	if (dev->of_node) {
+		if (!IS_ERR(pdata->clk))
+			clk_disable_unprepare(pdata->clk);
+	}
 }
 
 static void xgene_enet_adjust_link(struct net_device *ndev)
 {
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+	const struct xgene_mac_ops *mac_ops = pdata->mac_ops;
 	struct phy_device *phydev = pdata->phy_dev;
 
 	if (phydev->link) {
 		if (pdata->phy_speed != phydev->speed) {
 			pdata->phy_speed = phydev->speed;
-			xgene_gmac_init(pdata);
-			xgene_gmac_rx_enable(pdata);
-			xgene_gmac_tx_enable(pdata);
+			mac_ops->set_speed(pdata);
+			mac_ops->rx_enable(pdata);
+			mac_ops->tx_enable(pdata);
 			phy_print_status(phydev);
 		}
 	} else {
-		xgene_gmac_rx_disable(pdata);
-		xgene_gmac_tx_disable(pdata);
+		mac_ops->rx_disable(pdata);
+		mac_ops->tx_disable(pdata);
 		pdata->phy_speed = SPEED_UNKNOWN;
 		phy_print_status(phydev);
 	}
 }
 
-static int xgene_enet_phy_connect(struct net_device *ndev)
+#ifdef CONFIG_ACPI
+static struct acpi_device *acpi_phy_find_device(struct device *dev)
+{
+	struct acpi_reference_args args;
+	struct fwnode_handle *fw_node;
+	int status;
+
+	fw_node = acpi_fwnode_handle(ACPI_COMPANION(dev));
+	status = acpi_node_get_property_reference(fw_node, "phy-handle", 0,
+						  &args);
+	if (ACPI_FAILURE(status)) {
+		dev_dbg(dev, "No matching phy in ACPI table\n");
+		return NULL;
+	}
+
+	return args.adev;
+}
+#endif
+
+int xgene_enet_phy_connect(struct net_device *ndev)
 {
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-	struct device_node *phy_np;
+	struct device_node *np;
 	struct phy_device *phy_dev;
 	struct device *dev = &pdata->pdev->dev;
+	struct acpi_device *adev;
+	int i;
 
 	if (dev->of_node) {
-		phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0);
-		if (!phy_np) {
+		for (i = 0 ; i < 2; i++) {
+			np = of_parse_phandle(dev->of_node, "phy-handle", i);
+			if (np)
+				break;
+		}
+
+		if (!np) {
 			netdev_dbg(ndev, "No phy-handle found in DT\n");
 			return -ENODEV;
 		}
 
-		phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link,
+		phy_dev = of_phy_connect(ndev, np, &xgene_enet_adjust_link,
 					 0, pdata->phy_mode);
 		if (!phy_dev) {
 			netdev_err(ndev, "Could not connect to PHY\n");
@@ -751,6 +760,11 @@
 
 		pdata->phy_dev = phy_dev;
 	} else {
+#ifdef CONFIG_ACPI
+		adev = acpi_phy_find_device(dev);
+		if (adev)
+			pdata->phy_dev =  adev->driver_data;
+
 		phy_dev = pdata->phy_dev;
 
 		if (!phy_dev ||
@@ -759,6 +773,7 @@
 			netdev_err(ndev, "Could not connect to PHY\n");
 			return  -ENODEV;
 		}
+#endif
 	}
 
 	pdata->phy_speed = SPEED_UNKNOWN;
@@ -778,8 +793,8 @@
 	struct phy_device *phy;
 	struct device_node *child_np;
 	struct device_node *mdio_np = NULL;
+	u32 phy_addr;
 	int ret;
-	u32 phy_id;
 
 	if (dev->of_node) {
 		for_each_child_of_node(dev->of_node, child_np) {
@@ -806,21 +821,17 @@
 	if (ret)
 		return ret;
 
-	ret = device_property_read_u32(dev, "phy-channel", &phy_id);
+	ret = device_property_read_u32(dev, "phy-channel", &phy_addr);
 	if (ret)
-		ret = device_property_read_u32(dev, "phy-addr", &phy_id);
+		ret = device_property_read_u32(dev, "phy-addr", &phy_addr);
 	if (ret)
 		return -EINVAL;
 
-	phy = get_phy_device(mdio, phy_id, false);
-	if (!phy || IS_ERR(phy))
+	phy = xgene_enet_phy_register(mdio, phy_addr);
+	if (!phy)
 		return -EIO;
 
-	ret = phy_device_register(phy);
-	if (ret)
-		phy_device_free(phy);
-	else
-		pdata->phy_dev = phy;
+	pdata->phy_dev = phy;
 
 	return ret;
 }
@@ -836,13 +847,13 @@
 		return -ENOMEM;
 
 	mdio_bus->name = "APM X-Gene MDIO bus";
-	mdio_bus->read = xgene_enet_mdio_read;
-	mdio_bus->write = xgene_enet_mdio_write;
+	mdio_bus->read = xgene_mdio_rgmii_read;
+	mdio_bus->write = xgene_mdio_rgmii_write;
 	snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "xgene-mii",
 		 ndev->name);
 
-	mdio_bus->priv = pdata;
-	mdio_bus->parent = &ndev->dev;
+	mdio_bus->priv = (void __force *)pdata->mcx_mac_addr;
+	mdio_bus->parent = &pdata->pdev->dev;
 
 	ret = xgene_mdiobus_register(pdata, mdio_bus);
 	if (ret) {
@@ -859,6 +870,12 @@
 	return ret;
 }
 
+void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata)
+{
+	if (pdata->phy_dev)
+		phy_disconnect(pdata->phy_dev);
+}
+
 void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata)
 {
 	if (pdata->phy_dev)
@@ -876,11 +893,13 @@
 	.tx_enable = xgene_gmac_tx_enable,
 	.rx_disable = xgene_gmac_rx_disable,
 	.tx_disable = xgene_gmac_tx_disable,
+	.set_speed = xgene_gmac_set_speed,
 	.set_mac_addr = xgene_gmac_set_mac_addr,
 };
 
 struct xgene_port_ops xgene_gport_ops = {
 	.reset = xgene_enet_reset,
+	.clear = xgene_enet_clear,
 	.cle_bypass = xgene_enet_cle_bypass,
 	.shutdown = xgene_gport_shutdown,
 };
@@ -892,4 +911,5 @@
 	.clear = xgene_enet_clear_ring,
 	.wr_cmd = xgene_enet_wr_cmd,
 	.len = xgene_enet_ring_len,
+	.coalesce = xgene_enet_setup_coalescing,
 };
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
@@ -54,6 +54,11 @@
 #define IS_BUFFER_POOL		BIT(20)
 #define PREFETCH_BUF_EN		BIT(21)
 #define CSR_RING_ID_BUF		0x000c
+#define CSR_PBM_COAL		0x0014
+#define CSR_PBM_CTICK1		0x001c
+#define CSR_PBM_CTICK2		0x0020
+#define CSR_THRESHOLD0_SET1	0x0030
+#define CSR_THRESHOLD1_SET1	0x0034
 #define CSR_RING_NE_INT_MODE	0x017c
 #define CSR_RING_CONFIG		0x006c
 #define CSR_RING_WR_BASE	0x0070
@@ -81,7 +86,7 @@
 #define RINGADDRL_POS		5
 #define RINGADDRL_LEN		27
 #define RINGADDRH_POS		0
-#define RINGADDRH_LEN		6
+#define RINGADDRH_LEN		7
 #define RINGSIZE_POS		23
 #define RINGSIZE_LEN		3
 #define RINGTYPE_POS		19
@@ -89,9 +94,9 @@
 #define RINGMODE_POS		20
 #define RINGMODE_LEN		3
 #define RECOMTIMEOUTL_POS	28
-#define RECOMTIMEOUTL_LEN	3
+#define RECOMTIMEOUTL_LEN	4
 #define RECOMTIMEOUTH_POS	0
-#define RECOMTIMEOUTH_LEN	2
+#define RECOMTIMEOUTH_LEN	3
 #define NUMMSGSINQ_POS		1
 #define NUMMSGSINQ_LEN		16
 #define ACCEPTLERR		BIT(19)
@@ -99,8 +104,11 @@
 #define RECOMBBUF		BIT(27)
 
 #define MAC_OFFSET			0x30
+#define OFFSET_4			0x04
+#define OFFSET_8			0x08
 
 #define BLOCK_ETH_CSR_OFFSET		0x2000
+#define BLOCK_ETH_CLE_CSR_OFFSET	0x6000
 #define BLOCK_ETH_RING_IF_OFFSET	0x9000
 #define BLOCK_ETH_CLKRST_CSR_OFFSET	0xc000
 #define BLOCK_ETH_DIAG_CSR_OFFSET	0xD000
@@ -147,6 +155,7 @@
 #define CFG_RXCLK_MUXSEL0_SET(dst, val)	xgene_set_bits(dst, val, 26, 3)
 
 #define CFG_CLE_IP_PROTOCOL0_SET(dst, val)	xgene_set_bits(dst, val, 16, 2)
+#define CFG_CLE_IP_HDR_LEN_SET(dst, val)	xgene_set_bits(dst, val, 8, 5)
 #define CFG_CLE_DSTQID0_SET(dst, val)		xgene_set_bits(dst, val, 0, 12)
 #define CFG_CLE_FPSEL0_SET(dst, val)		xgene_set_bits(dst, val, 16, 4)
 #define CFG_MACMODE_SET(dst, val)		xgene_set_bits(dst, val, 18, 2)
@@ -159,6 +168,8 @@
 #define TX_DV_GATE_EN0			BIT(2)
 #define RX_DV_GATE_EN0			BIT(1)
 #define RESUME_RX0			BIT(0)
+#define ENET_CFGSSQMIFPRESET_ADDR		0x14
+#define ENET_CFGSSQMIWQRESET_ADDR		0x1c
 #define ENET_CFGSSQMIWQASSOC_ADDR		0xe0
 #define ENET_CFGSSQMIFPQASSOC_ADDR		0xdc
 #define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR	0xf0
@@ -195,6 +206,8 @@
 #define USERINFO_LEN			32
 #define FPQNUM_POS			32
 #define FPQNUM_LEN			12
+#define ELERR_POS                       46
+#define ELERR_LEN                       2
 #define NV_POS				50
 #define NV_LEN				1
 #define LL_POS				51
@@ -289,11 +302,6 @@
 	RING_BUFNUM_INVALID
 };
 
-enum xgene_enet_cmd {
-	XGENE_ENET_WR_CMD = BIT(31),
-	XGENE_ENET_RD_CMD = BIT(30)
-};
-
 enum xgene_enet_err_code {
 	HBF_READ_DATA = 3,
 	HBF_LL_READ = 4,
@@ -339,6 +347,8 @@
 int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata);
 void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata);
 bool xgene_ring_mgr_init(struct xgene_enet_pdata *p);
+int xgene_enet_phy_connect(struct net_device *ndev);
+void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata);
 
 extern struct xgene_mac_ops xgene_gmac_ops;
 extern struct xgene_port_ops xgene_gport_ops;
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -93,13 +93,6 @@
 	return 0;
 }
 
-static u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring)
-{
-	struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
-
-	return ((u16)pdata->rm << 10) | ring->num;
-}
-
 static u8 xgene_enet_hdr_len(const void *data)
 {
 	const struct ethhdr *eth = data;
@@ -109,25 +102,13 @@
 
 static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool)
 {
-	struct xgene_enet_pdata *pdata = netdev_priv(buf_pool->ndev);
-	struct xgene_enet_raw_desc16 *raw_desc;
-	u32 slots = buf_pool->slots - 1;
-	u32 tail = buf_pool->tail;
-	u32 userinfo;
-	int i, len;
-
-	len = pdata->ring_ops->len(buf_pool);
-	for (i = 0; i < len; i++) {
-		tail = (tail - 1) & slots;
-		raw_desc = &buf_pool->raw_desc16[tail];
-
-		/* Hardware stores descriptor in little endian format */
-		userinfo = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
-		dev_kfree_skb_any(buf_pool->rx_skb[userinfo]);
-	}
+	int i;
 
-	pdata->ring_ops->wr_cmd(buf_pool, -len);
-	buf_pool->tail = tail;
+	/* Free up the buffers held by hardware */
+	for (i = 0; i < buf_pool->slots; i++) {
+		if (buf_pool->rx_skb[i])
+			dev_kfree_skb_any(buf_pool->rx_skb[i]);
+	}
 }
 
 static irqreturn_t xgene_enet_rx_irq(const int irq, void *data)
@@ -189,7 +170,6 @@
 static u64 xgene_enet_work_msg(struct sk_buff *skb)
 {
 	struct net_device *ndev = skb->dev;
-	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
 	struct iphdr *iph;
 	u8 l3hlen = 0, l4hlen = 0;
 	u8 ethhdr, proto = 0, csum_enable = 0;
@@ -235,10 +215,6 @@
 			if (!mss || ((skb->len - hdr_len) <= mss))
 				goto out;
 
-			if (mss != pdata->mss) {
-				pdata->mss = mss;
-				pdata->mac_ops->set_mss(pdata);
-			}
 			hopinfo |= SET_BIT(ET);
 		}
 	} else if (iph->protocol == IPPROTO_UDP) {
@@ -420,7 +396,7 @@
 	raw_desc->m0 = cpu_to_le64(SET_VAL(LL, ll) | SET_VAL(NV, nv) |
 				   SET_VAL(USERINFO, tx_ring->tail));
 	tx_ring->cp_ring->cp_skb[tx_ring->tail] = skb;
-	pdata->tx_level += count;
+	pdata->tx_level[tx_ring->cp_ring->index] += count;
 	tx_ring->tail = tail;
 
 	return count;
@@ -430,15 +406,17 @@
 					 struct net_device *ndev)
 {
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-	struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring;
-	u32 tx_level = pdata->tx_level;
+	struct xgene_enet_desc_ring *tx_ring;
+	int index = skb->queue_mapping;
+	u32 tx_level = pdata->tx_level[index];
 	int count;
 
-	if (tx_level < pdata->txc_level)
-		tx_level += ((typeof(pdata->tx_level))~0U);
+	tx_ring = pdata->tx_ring[index];
+	if (tx_level < pdata->txc_level[index])
+		tx_level += ((typeof(pdata->tx_level[index]))~0U);
 
-	if ((tx_level - pdata->txc_level) > pdata->tx_qcnt_hi) {
-		netif_stop_queue(ndev);
+	if ((tx_level - pdata->txc_level[index]) > pdata->tx_qcnt_hi) {
+		netif_stop_subqueue(ndev, index);
 		return NETDEV_TX_BUSY;
 	}
 
@@ -453,8 +431,8 @@
 
 	skb_tx_timestamp(skb);
 
-	pdata->stats.tx_packets++;
-	pdata->stats.tx_bytes += skb->len;
+	tx_ring->tx_packets++;
+	tx_ring->tx_bytes += skb->len;
 
 	pdata->ring_ops->wr_cmd(tx_ring, count);
 	return NETDEV_TX_OK;
@@ -491,14 +469,15 @@
 			 XGENE_ENET_MAX_MTU, DMA_FROM_DEVICE);
 	skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
 	skb = buf_pool->rx_skb[skb_index];
+	buf_pool->rx_skb[skb_index] = NULL;
 
 	/* checking for error */
-	status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
+	status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) ||
+		  GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
 	if (unlikely(status > 2)) {
 		dev_kfree_skb_any(skb);
 		xgene_enet_parse_error(rx_ring, netdev_priv(rx_ring->ndev),
 				       status);
-		pdata->stats.rx_dropped++;
 		ret = -EIO;
 		goto out;
 	}
@@ -516,8 +495,8 @@
 		xgene_enet_skip_csum(skb);
 	}
 
-	pdata->stats.rx_packets++;
-	pdata->stats.rx_bytes += datalen;
+	rx_ring->rx_packets++;
+	rx_ring->rx_bytes += datalen;
 	napi_gro_receive(&rx_ring->napi, skb);
 out:
 	if (--rx_ring->nbufpool == 0) {
@@ -536,7 +515,8 @@
 static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
 				   int budget)
 {
-	struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
+	struct net_device *ndev = ring->ndev;
+	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
 	struct xgene_enet_raw_desc *raw_desc, *exp_desc;
 	u16 head = ring->head;
 	u16 slots = ring->slots - 1;
@@ -580,7 +560,7 @@
 		desc_count++;
 		processed++;
 		if (is_completion)
-			pdata->txc_level += desc_count;
+			pdata->txc_level[ring->index] += desc_count;
 
 		if (ret)
 			break;
@@ -590,8 +570,8 @@
 		pdata->ring_ops->wr_cmd(ring, -count);
 		ring->head = head;
 
-		if (netif_queue_stopped(ring->ndev))
-			netif_start_queue(ring->ndev);
+		if (__netif_subqueue_stopped(ndev, ring->index))
+			netif_start_subqueue(ndev, ring->index);
 	}
 
 	return processed;
@@ -616,8 +596,40 @@
 static void xgene_enet_timeout(struct net_device *ndev)
 {
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+	struct netdev_queue *txq;
+	int i;
 
 	pdata->mac_ops->reset(pdata);
+
+	for (i = 0; i < pdata->txq_cnt; i++) {
+		txq = netdev_get_tx_queue(ndev, i);
+		txq->trans_start = jiffies;
+		netif_tx_start_queue(txq);
+	}
+}
+
+static void xgene_enet_set_irq_name(struct net_device *ndev)
+{
+	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+	struct xgene_enet_desc_ring *ring;
+	int i;
+
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		ring = pdata->rx_ring[i];
+		if (!pdata->cq_cnt) {
+			snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-rx-txc",
+				 ndev->name);
+		} else {
+			snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-rx-%d",
+				 ndev->name, i);
+		}
+	}
+
+	for (i = 0; i < pdata->cq_cnt; i++) {
+		ring = pdata->tx_ring[i]->cp_ring;
+		snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-txc-%d",
+			 ndev->name, i);
+	}
 }
 
 static int xgene_enet_register_irq(struct net_device *ndev)
@@ -625,18 +637,25 @@
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
 	struct device *dev = ndev_to_dev(ndev);
 	struct xgene_enet_desc_ring *ring;
-	int ret;
+	int ret = 0, i;
 
-	ring = pdata->rx_ring;
-	ret = devm_request_irq(dev, ring->irq, xgene_enet_rx_irq,
-			       IRQF_SHARED, ring->irq_name, ring);
-	if (ret)
-		netdev_err(ndev, "Failed to request irq %s\n", ring->irq_name);
+	xgene_enet_set_irq_name(ndev);
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		ring = pdata->rx_ring[i];
+		irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
+		ret = devm_request_irq(dev, ring->irq, xgene_enet_rx_irq,
+				       0, ring->irq_name, ring);
+		if (ret) {
+			netdev_err(ndev, "Failed to request irq %s\n",
+				   ring->irq_name);
+		}
+	}
 
-	if (pdata->cq_cnt) {
-		ring = pdata->tx_ring->cp_ring;
+	for (i = 0; i < pdata->cq_cnt; i++) {
+		ring = pdata->tx_ring[i]->cp_ring;
+		irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
 		ret = devm_request_irq(dev, ring->irq, xgene_enet_rx_irq,
-				       IRQF_SHARED, ring->irq_name, ring);
+				       0, ring->irq_name, ring);
 		if (ret) {
 			netdev_err(ndev, "Failed to request irq %s\n",
 				   ring->irq_name);
@@ -649,27 +668,38 @@
 static void xgene_enet_free_irq(struct net_device *ndev)
 {
 	struct xgene_enet_pdata *pdata;
+	struct xgene_enet_desc_ring *ring;
 	struct device *dev;
+	int i;
 
 	pdata = netdev_priv(ndev);
 	dev = ndev_to_dev(ndev);
-	devm_free_irq(dev, pdata->rx_ring->irq, pdata->rx_ring);
 
-	if (pdata->cq_cnt) {
-		devm_free_irq(dev, pdata->tx_ring->cp_ring->irq,
-			      pdata->tx_ring->cp_ring);
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		ring = pdata->rx_ring[i];
+		irq_clear_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
+		devm_free_irq(dev, ring->irq, ring);
+	}
+
+	for (i = 0; i < pdata->cq_cnt; i++) {
+		ring = pdata->tx_ring[i]->cp_ring;
+		irq_clear_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
+		devm_free_irq(dev, ring->irq, ring);
 	}
 }
 
 static void xgene_enet_napi_enable(struct xgene_enet_pdata *pdata)
 {
 	struct napi_struct *napi;
+	int i;
 
-	napi = &pdata->rx_ring->napi;
-	napi_enable(napi);
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		napi = &pdata->rx_ring[i]->napi;
+		napi_enable(napi);
+	}
 
-	if (pdata->cq_cnt) {
-		napi = &pdata->tx_ring->cp_ring->napi;
+	for (i = 0; i < pdata->cq_cnt; i++) {
+		napi = &pdata->tx_ring[i]->cp_ring->napi;
 		napi_enable(napi);
 	}
 }
@@ -677,12 +707,15 @@
 static void xgene_enet_napi_disable(struct xgene_enet_pdata *pdata)
 {
 	struct napi_struct *napi;
+	int i;
 
-	napi = &pdata->rx_ring->napi;
-	napi_disable(napi);
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		napi = &pdata->rx_ring[i]->napi;
+		napi_disable(napi);
+	}
 
-	if (pdata->cq_cnt) {
-		napi = &pdata->tx_ring->cp_ring->napi;
+	for (i = 0; i < pdata->cq_cnt; i++) {
+		napi = &pdata->tx_ring[i]->cp_ring->napi;
 		napi_disable(napi);
 	}
 }
@@ -693,20 +726,29 @@
 	struct xgene_mac_ops *mac_ops = pdata->mac_ops;
 	int ret;
 
-	mac_ops->tx_enable(pdata);
-	mac_ops->rx_enable(pdata);
+	ret = netif_set_real_num_tx_queues(ndev, pdata->txq_cnt);
+	if (ret)
+		return ret;
+
+	ret = netif_set_real_num_rx_queues(ndev, pdata->rxq_cnt);
+	if (ret)
+		return ret;
 
 	xgene_enet_napi_enable(pdata);
 	ret = xgene_enet_register_irq(ndev);
 	if (ret)
 		return ret;
 
-	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+	if (pdata->phy_dev) {
 		phy_start(pdata->phy_dev);
-	else
+	} else {
 		schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF);
+		netif_carrier_off(ndev);
+	}
 
-	netif_start_queue(ndev);
+	mac_ops->tx_enable(pdata);
+	mac_ops->rx_enable(pdata);
+	netif_tx_start_all_queues(ndev);
 
 	return ret;
 }
@@ -715,24 +757,24 @@
 {
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
 	struct xgene_mac_ops *mac_ops = pdata->mac_ops;
+	int i;
 
-	netif_stop_queue(ndev);
+	netif_tx_stop_all_queues(ndev);
+	mac_ops->tx_disable(pdata);
+	mac_ops->rx_disable(pdata);
 
-	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+	if (pdata->phy_dev)
 		phy_stop(pdata->phy_dev);
 	else
 		cancel_delayed_work_sync(&pdata->link_work);
 
-	mac_ops->tx_disable(pdata);
-	mac_ops->rx_disable(pdata);
-
 	xgene_enet_free_irq(ndev);
 	xgene_enet_napi_disable(pdata);
-	xgene_enet_process_ring(pdata->rx_ring, -1);
+	for (i = 0; i < pdata->rxq_cnt; i++)
+		xgene_enet_process_ring(pdata->rx_ring[i], -1);
 
 	return 0;
 }
-
 static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring)
 {
 	struct xgene_enet_pdata *pdata;
@@ -742,24 +784,36 @@
 	dev = ndev_to_dev(ring->ndev);
 
 	pdata->ring_ops->clear(ring);
-	dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
+	dmam_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
 }
 
 static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata)
 {
 	struct xgene_enet_desc_ring *buf_pool;
+	struct xgene_enet_desc_ring *ring;
+	int i;
 
-	if (pdata->tx_ring) {
-		xgene_enet_delete_ring(pdata->tx_ring);
-		pdata->tx_ring = NULL;
+	for (i = 0; i < pdata->txq_cnt; i++) {
+		ring = pdata->tx_ring[i];
+		if (ring) {
+			xgene_enet_delete_ring(ring);
+			pdata->port_ops->clear(pdata, ring);
+			if (pdata->cq_cnt)
+				xgene_enet_delete_ring(ring->cp_ring);
+			pdata->tx_ring[i] = NULL;
+		}
 	}
 
-	if (pdata->rx_ring) {
-		buf_pool = pdata->rx_ring->buf_pool;
-		xgene_enet_delete_bufpool(buf_pool);
-		xgene_enet_delete_ring(buf_pool);
-		xgene_enet_delete_ring(pdata->rx_ring);
-		pdata->rx_ring = NULL;
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		ring = pdata->rx_ring[i];
+		if (ring) {
+			buf_pool = ring->buf_pool;
+			xgene_enet_delete_bufpool(buf_pool);
+			xgene_enet_delete_ring(buf_pool);
+			pdata->port_ops->clear(pdata, buf_pool);
+			xgene_enet_delete_ring(ring);
+			pdata->rx_ring[i] = NULL;
+		}
 	}
 }
 
@@ -805,7 +859,7 @@
 
 	if (ring->desc_addr) {
 		pdata->ring_ops->clear(ring);
-		dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
+		dmam_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
 	}
 	devm_kfree(dev, ring);
 }
@@ -814,24 +868,29 @@
 {
 	struct device *dev = &pdata->pdev->dev;
 	struct xgene_enet_desc_ring *ring;
+	int i;
+
+	for (i = 0; i < pdata->txq_cnt; i++) {
+		ring = pdata->tx_ring[i];
+		if (ring) {
+			if (ring->cp_ring && ring->cp_ring->cp_skb)
+				devm_kfree(dev, ring->cp_ring->cp_skb);
+			if (ring->cp_ring && pdata->cq_cnt)
+				xgene_enet_free_desc_ring(ring->cp_ring);
+			xgene_enet_free_desc_ring(ring);
+		}
+	}
 
-	ring = pdata->tx_ring;
-	if (ring) {
-		if (ring->cp_ring && ring->cp_ring->cp_skb)
-			devm_kfree(dev, ring->cp_ring->cp_skb);
-		if (ring->cp_ring && pdata->cq_cnt)
-			xgene_enet_free_desc_ring(ring->cp_ring);
-		xgene_enet_free_desc_ring(ring);
-	}
-
-	ring = pdata->rx_ring;
-	if (ring) {
-		if (ring->buf_pool) {
-			if (ring->buf_pool->rx_skb)
-				devm_kfree(dev, ring->buf_pool->rx_skb);
-			xgene_enet_free_desc_ring(ring->buf_pool);
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		ring = pdata->rx_ring[i];
+		if (ring) {
+			if (ring->buf_pool) {
+				if (ring->buf_pool->rx_skb)
+					devm_kfree(dev, ring->buf_pool->rx_skb);
+				xgene_enet_free_desc_ring(ring->buf_pool);
+			}
+			xgene_enet_free_desc_ring(ring);
 		}
-		xgene_enet_free_desc_ring(ring);
 	}
 }
 
@@ -858,9 +917,10 @@
 			struct net_device *ndev, u32 ring_num,
 			enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id)
 {
-	struct xgene_enet_desc_ring *ring;
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
 	struct device *dev = ndev_to_dev(ndev);
+	struct xgene_enet_desc_ring *ring;
+	void *irq_mbox_addr;
 	int size;
 
 	size = xgene_enet_get_ring_size(dev, cfgsize);
@@ -877,8 +937,8 @@
 	ring->cfgsize = cfgsize;
 	ring->id = ring_id;
 
-	ring->desc_addr = dma_zalloc_coherent(dev, size, &ring->dma,
-					      GFP_KERNEL);
+	ring->desc_addr = dmam_alloc_coherent(dev, size, &ring->dma,
+					      GFP_KERNEL | __GFP_ZERO);
 	if (!ring->desc_addr) {
 		devm_kfree(dev, ring);
 		return NULL;
@@ -886,14 +946,16 @@
 	ring->size = size;
 
 	if (is_irq_mbox_required(pdata, ring)) {
-		ring->irq_mbox_addr = dma_zalloc_coherent(dev, INTR_MBOX_SIZE,
-				&ring->irq_mbox_dma, GFP_KERNEL);
-		if (!ring->irq_mbox_addr) {
-			dma_free_coherent(dev, size, ring->desc_addr,
-					  ring->dma);
+		irq_mbox_addr = dmam_alloc_coherent(dev, INTR_MBOX_SIZE,
+						    &ring->irq_mbox_dma,
+						    GFP_KERNEL | __GFP_ZERO);
+		if (!irq_mbox_addr) {
+			dmam_free_coherent(dev, size, ring->desc_addr,
+					   ring->dma);
 			devm_kfree(dev, ring);
 			return NULL;
 		}
+		ring->irq_mbox_addr = irq_mbox_addr;
 	}
 
 	ring->cmd_base = xgene_enet_ring_cmd_base(pdata, ring);
@@ -931,6 +993,17 @@
 	return owner;
 }
 
+static u8 xgene_start_cpu_bufnum(struct xgene_enet_pdata *pdata)
+{
+	struct device *dev = &pdata->pdev->dev;
+	u32 cpu_bufnum;
+	int ret;
+
+	ret = device_property_read_u32(dev, "channel", &cpu_bufnum);
+
+	return (!ret) ? cpu_bufnum : pdata->cpu_bufnum;
+}
+
 static int xgene_enet_create_desc_rings(struct net_device *ndev)
 {
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
@@ -939,109 +1012,119 @@
 	struct xgene_enet_desc_ring *buf_pool = NULL;
 	enum xgene_ring_owner owner;
 	dma_addr_t dma_exp_bufs;
-	u8 cpu_bufnum = pdata->cpu_bufnum;
+	u8 cpu_bufnum;
 	u8 eth_bufnum = pdata->eth_bufnum;
 	u8 bp_bufnum = pdata->bp_bufnum;
 	u16 ring_num = pdata->ring_num;
+	__le64 *exp_bufs;
 	u16 ring_id;
-	int ret, size;
+	int i, ret, size;
 
-	/* allocate rx descriptor ring */
-	owner = xgene_derive_ring_owner(pdata);
-	ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
-	rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
-					      RING_CFGSIZE_16KB, ring_id);
-	if (!rx_ring) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	/* allocate buffer pool for receiving packets */
-	owner = xgene_derive_ring_owner(pdata);
-	ring_id = xgene_enet_get_ring_id(owner, bp_bufnum++);
-	buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++,
-					       RING_CFGSIZE_2KB, ring_id);
-	if (!buf_pool) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	cpu_bufnum = xgene_start_cpu_bufnum(pdata);
 
-	rx_ring->nbufpool = NUM_BUFPOOL;
-	rx_ring->buf_pool = buf_pool;
-	rx_ring->irq = pdata->rx_irq;
-	if (!pdata->cq_cnt) {
-		snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx-txc",
-			 ndev->name);
-	} else {
-		snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx", ndev->name);
-	}
-	buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots,
-					sizeof(struct sk_buff *), GFP_KERNEL);
-	if (!buf_pool->rx_skb) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		/* allocate rx descriptor ring */
+		owner = xgene_derive_ring_owner(pdata);
+		ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
+		rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
+						      RING_CFGSIZE_16KB,
+						      ring_id);
+		if (!rx_ring) {
+			ret = -ENOMEM;
+			goto err;
+		}
 
-	buf_pool->dst_ring_num = xgene_enet_dst_ring_num(buf_pool);
-	rx_ring->buf_pool = buf_pool;
-	pdata->rx_ring = rx_ring;
-
-	/* allocate tx descriptor ring */
-	owner = xgene_derive_ring_owner(pdata);
-	ring_id = xgene_enet_get_ring_id(owner, eth_bufnum++);
-	tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
-					      RING_CFGSIZE_16KB, ring_id);
-	if (!tx_ring) {
-		ret = -ENOMEM;
-		goto err;
-	}
+		/* allocate buffer pool for receiving packets */
+		owner = xgene_derive_ring_owner(pdata);
+		ring_id = xgene_enet_get_ring_id(owner, bp_bufnum++);
+		buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++,
+						       RING_CFGSIZE_2KB,
+						       ring_id);
+		if (!buf_pool) {
+			ret = -ENOMEM;
+			goto err;
+		}
 
-	size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS;
-	tx_ring->exp_bufs = dma_zalloc_coherent(dev, size, &dma_exp_bufs,
+		rx_ring->nbufpool = NUM_BUFPOOL;
+		rx_ring->buf_pool = buf_pool;
+		rx_ring->irq = pdata->irqs[i];
+		buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots,
+						sizeof(struct sk_buff *),
 						GFP_KERNEL);
-	if (!tx_ring->exp_bufs) {
-		ret = -ENOMEM;
-		goto err;
-	}
+		if (!buf_pool->rx_skb) {
+			ret = -ENOMEM;
+			goto err;
+		}
 
-	pdata->tx_ring = tx_ring;
+		buf_pool->dst_ring_num = xgene_enet_dst_ring_num(buf_pool);
+		rx_ring->buf_pool = buf_pool;
+		pdata->rx_ring[i] = rx_ring;
+	}
 
-	if (!pdata->cq_cnt) {
-		cp_ring = pdata->rx_ring;
-	} else {
-		/* allocate tx completion descriptor ring */
-		ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
-		cp_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
+	for (i = 0; i < pdata->txq_cnt; i++) {
+		/* allocate tx descriptor ring */
+		owner = xgene_derive_ring_owner(pdata);
+		ring_id = xgene_enet_get_ring_id(owner, eth_bufnum++);
+		tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
 						      RING_CFGSIZE_16KB,
 						      ring_id);
-		if (!cp_ring) {
+		if (!tx_ring) {
 			ret = -ENOMEM;
 			goto err;
 		}
-		cp_ring->irq = pdata->txc_irq;
-		snprintf(cp_ring->irq_name, IRQ_ID_SIZE, "%s-txc", ndev->name);
-	}
 
-	cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots,
-				       sizeof(struct sk_buff *), GFP_KERNEL);
-	if (!cp_ring->cp_skb) {
-		ret = -ENOMEM;
-		goto err;
-	}
+		size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS;
+		exp_bufs = dmam_alloc_coherent(dev, size, &dma_exp_bufs,
+					       GFP_KERNEL | __GFP_ZERO);
+		if (!exp_bufs) {
+			ret = -ENOMEM;
+			goto err;
+		}
+		tx_ring->exp_bufs = exp_bufs;
 
-	size = sizeof(dma_addr_t) * MAX_SKB_FRAGS;
-	cp_ring->frag_dma_addr = devm_kcalloc(dev, tx_ring->slots,
-					      size, GFP_KERNEL);
-	if (!cp_ring->frag_dma_addr) {
-		devm_kfree(dev, cp_ring->cp_skb);
-		ret = -ENOMEM;
-		goto err;
-	}
+		pdata->tx_ring[i] = tx_ring;
 
-	pdata->tx_ring->cp_ring = cp_ring;
-	pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
+		if (!pdata->cq_cnt) {
+			cp_ring = pdata->rx_ring[i];
+		} else {
+			/* allocate tx completion descriptor ring */
+			ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU,
+							 cpu_bufnum++);
+			cp_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
+							      RING_CFGSIZE_16KB,
+							      ring_id);
+			if (!cp_ring) {
+				ret = -ENOMEM;
+				goto err;
+			}
 
-	pdata->tx_qcnt_hi = pdata->tx_ring->slots - 128;
+			cp_ring->irq = pdata->irqs[pdata->rxq_cnt + i];
+			cp_ring->index = i;
+		}
+
+		cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots,
+					       sizeof(struct sk_buff *),
+					       GFP_KERNEL);
+		if (!cp_ring->cp_skb) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		size = sizeof(dma_addr_t) * MAX_SKB_FRAGS;
+		cp_ring->frag_dma_addr = devm_kcalloc(dev, tx_ring->slots,
+						      size, GFP_KERNEL);
+		if (!cp_ring->frag_dma_addr) {
+			devm_kfree(dev, cp_ring->cp_skb);
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		tx_ring->cp_ring = cp_ring;
+		tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
+	}
+
+	pdata->ring_ops->coalesce(pdata->tx_ring[0]);
+	pdata->tx_qcnt_hi = pdata->tx_ring[0]->slots - 128;
 
 	return 0;
 
@@ -1056,12 +1139,31 @@
 {
 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
 	struct rtnl_link_stats64 *stats = &pdata->stats;
+	struct xgene_enet_desc_ring *ring;
+	int i;
 
-	stats->rx_errors += stats->rx_length_errors +
-			    stats->rx_crc_errors +
-			    stats->rx_frame_errors +
-			    stats->rx_fifo_errors;
-	memcpy(storage, &pdata->stats, sizeof(struct rtnl_link_stats64));
+	memset(stats, 0, sizeof(struct rtnl_link_stats64));
+	for (i = 0; i < pdata->txq_cnt; i++) {
+		ring = pdata->tx_ring[i];
+		if (ring) {
+			stats->tx_packets += ring->tx_packets;
+			stats->tx_bytes += ring->tx_bytes;
+		}
+	}
+
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		ring = pdata->rx_ring[i];
+		if (ring) {
+			stats->rx_packets += ring->rx_packets;
+			stats->rx_bytes += ring->rx_bytes;
+			stats->rx_errors += ring->rx_length_errors +
+				ring->rx_crc_errors +
+				ring->rx_frame_errors +
+				ring->rx_fifo_errors;
+			stats->rx_dropped += ring->rx_dropped;
+		}
+	}
+	memcpy(storage, stats, sizeof(struct rtnl_link_stats64));
 
 	return storage;
 }
@@ -1090,7 +1192,7 @@
 };
 
 #ifdef CONFIG_ACPI
-static int xgene_get_port_id_acpi(struct device *dev,
+static void xgene_get_port_id_acpi(struct device *dev,
 				  struct xgene_enet_pdata *pdata)
 {
 	acpi_status status;
@@ -1103,24 +1205,19 @@
 		pdata->port_id = temp;
 	}
 
-	return 0;
+	return;
 }
 #endif
 
-static int xgene_get_port_id_dt(struct device *dev, struct xgene_enet_pdata *pdata)
+static void xgene_get_port_id_dt(struct device *dev, struct xgene_enet_pdata *pdata)
 {
 	u32 id = 0;
-	int ret;
 
-	ret = of_property_read_u32(dev->of_node, "port-id", &id);
-	if (ret) {
-		pdata->port_id = 0;
-		ret = 0;
-	} else {
-		pdata->port_id = id & BIT(0);
-	}
+	of_property_read_u32(dev->of_node, "port-id", &id);
 
-	return ret;
+	pdata->port_id = id & BIT(0);
+
+	return;
 }
 
 static int xgene_get_tx_delay(struct xgene_enet_pdata *pdata)
@@ -1165,6 +1262,56 @@
 	return 0;
 }
 
+static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata)
+{
+	struct platform_device *pdev = pdata->pdev;
+	struct device *dev = &pdev->dev;
+	int i, ret, max_irqs;
+
+	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+		max_irqs = 1;
+	else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII)
+		max_irqs = 2;
+	else
+		max_irqs = XGENE_MAX_ENET_IRQ;
+
+	for (i = 0; i < max_irqs; i++) {
+		ret = platform_get_irq(pdev, i);
+		if (ret <= 0) {
+			if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+				max_irqs = i;
+				pdata->rxq_cnt = max_irqs / 2;
+				pdata->txq_cnt = max_irqs / 2;
+				pdata->cq_cnt = max_irqs / 2;
+				break;
+			}
+			dev_err(dev, "Unable to get ENET IRQ\n");
+			ret = ret ? : -ENXIO;
+			return ret;
+		}
+		pdata->irqs[i] = ret;
+	}
+
+	return 0;
+}
+
+static int xgene_enet_check_phy_handle(struct xgene_enet_pdata *pdata)
+{
+	int ret;
+
+	if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII)
+		return 0;
+
+	if (!IS_ENABLED(CONFIG_MDIO_XGENE))
+		return 0;
+
+	ret = xgene_enet_phy_connect(pdata->ndev);
+	if (!ret)
+		pdata->mdio_driver = true;
+
+	return 0;
+}
+
 static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
 {
 	struct platform_device *pdev;
@@ -1215,13 +1362,11 @@
 	}
 
 	if (dev->of_node)
-		ret = xgene_get_port_id_dt(dev, pdata);
+		xgene_get_port_id_dt(dev, pdata);
 #ifdef CONFIG_ACPI
 	else
-		ret = xgene_get_port_id_acpi(dev, pdata);
+		xgene_get_port_id_acpi(dev, pdata);
 #endif
-	if (ret)
-		return ret;
 
 	if (!device_get_mac_address(dev, ndev->dev_addr, ETH_ALEN))
 		eth_hw_addr_random(ndev);
@@ -1248,25 +1393,13 @@
 	if (ret)
 		return ret;
 
-	ret = platform_get_irq(pdev, 0);
-	if (ret <= 0) {
-		dev_err(dev, "Unable to get ENET Rx IRQ\n");
-		ret = ret ? : -ENXIO;
+	ret = xgene_enet_get_irqs(pdata);
+	if (ret)
 		return ret;
-	}
-	pdata->rx_irq = ret;
 
-	if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII) {
-		ret = platform_get_irq(pdev, 1);
-		if (ret <= 0) {
-			pdata->cq_cnt = 0;
-			dev_info(dev, "Unable to get Tx completion IRQ,"
-				 "using Rx IRQ instead\n");
-		} else {
-			pdata->cq_cnt = XGENE_MAX_TXC_RINGS;
-			pdata->txc_irq = ret;
-		}
-	}
+	ret = xgene_enet_check_phy_handle(pdata);
+	if (ret)
+		return ret;
 
 	pdata->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(pdata->clk)) {
@@ -1279,6 +1412,7 @@
 	else
 		base_addr = pdata->base_addr;
 	pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET;
+	pdata->cle.base = base_addr + BLOCK_ETH_CLE_CSR_OFFSET;
 	pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET;
 	pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET;
 	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII ||
@@ -1299,10 +1433,11 @@
 
 static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata)
 {
+	struct xgene_enet_cle *enet_cle = &pdata->cle;
 	struct net_device *ndev = pdata->ndev;
 	struct xgene_enet_desc_ring *buf_pool;
 	u16 dst_ring_num;
-	int ret;
+	int i, ret;
 
 	ret = pdata->port_ops->reset(pdata);
 	if (ret)
@@ -1315,16 +1450,37 @@
 	}
 
 	/* setup buffer pool */
-	buf_pool = pdata->rx_ring->buf_pool;
-	xgene_enet_init_bufpool(buf_pool);
-	ret = xgene_enet_refill_bufpool(buf_pool, pdata->rx_buff_cnt);
-	if (ret) {
-		xgene_enet_delete_desc_rings(pdata);
-		return ret;
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		buf_pool = pdata->rx_ring[i]->buf_pool;
+		xgene_enet_init_bufpool(buf_pool);
+		ret = xgene_enet_refill_bufpool(buf_pool, pdata->rx_buff_cnt);
+		if (ret) {
+			xgene_enet_delete_desc_rings(pdata);
+			return ret;
+		}
+	}
+
+	dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring[0]);
+	buf_pool = pdata->rx_ring[0]->buf_pool;
+	if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+		/* Initialize and Enable  PreClassifier Tree */
+		enet_cle->max_nodes = 512;
+		enet_cle->max_dbptrs = 1024;
+		enet_cle->parsers = 3;
+		enet_cle->active_parser = PARSER_ALL;
+		enet_cle->ptree.start_node = 0;
+		enet_cle->ptree.start_dbptr = 0;
+		enet_cle->jump_bytes = 8;
+		ret = pdata->cle_ops->cle_init(pdata);
+		if (ret) {
+			netdev_err(ndev, "Preclass Tree init error\n");
+			return ret;
+		}
+	} else {
+		pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id);
 	}
 
-	dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring);
-	pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id);
+	pdata->phy_speed = SPEED_UNKNOWN;
 	pdata->mac_ops->init(pdata);
 
 	return ret;
@@ -1337,26 +1493,45 @@
 		pdata->mac_ops = &xgene_gmac_ops;
 		pdata->port_ops = &xgene_gport_ops;
 		pdata->rm = RM3;
+		pdata->rxq_cnt = 1;
+		pdata->txq_cnt = 1;
+		pdata->cq_cnt = 0;
 		break;
 	case PHY_INTERFACE_MODE_SGMII:
 		pdata->mac_ops = &xgene_sgmac_ops;
 		pdata->port_ops = &xgene_sgport_ops;
 		pdata->rm = RM1;
+		pdata->rxq_cnt = 1;
+		pdata->txq_cnt = 1;
+		pdata->cq_cnt = 1;
 		break;
 	default:
 		pdata->mac_ops = &xgene_xgmac_ops;
 		pdata->port_ops = &xgene_xgport_ops;
+		pdata->cle_ops = &xgene_cle3in_ops;
 		pdata->rm = RM0;
+		if (!pdata->rxq_cnt) {
+			pdata->rxq_cnt = XGENE_NUM_RX_RING;
+			pdata->txq_cnt = XGENE_NUM_TX_RING;
+			pdata->cq_cnt = XGENE_NUM_TXC_RING;
+		}
 		break;
 	}
 
 	if (pdata->enet_id == XGENE_ENET1) {
 		switch (pdata->port_id) {
 		case 0:
-			pdata->cpu_bufnum = START_CPU_BUFNUM_0;
-			pdata->eth_bufnum = START_ETH_BUFNUM_0;
-			pdata->bp_bufnum = START_BP_BUFNUM_0;
-			pdata->ring_num = START_RING_NUM_0;
+			if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+				pdata->cpu_bufnum = X2_START_CPU_BUFNUM_0;
+				pdata->eth_bufnum = X2_START_ETH_BUFNUM_0;
+				pdata->bp_bufnum = X2_START_BP_BUFNUM_0;
+				pdata->ring_num = START_RING_NUM_0;
+			} else {
+				pdata->cpu_bufnum = START_CPU_BUFNUM_0;
+				pdata->eth_bufnum = START_ETH_BUFNUM_0;
+				pdata->bp_bufnum = START_BP_BUFNUM_0;
+				pdata->ring_num = START_RING_NUM_0;
+			}
 			break;
 		case 1:
 			if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
@@ -1400,27 +1575,18 @@
 static void xgene_enet_napi_add(struct xgene_enet_pdata *pdata)
 {
 	struct napi_struct *napi;
+	int i;
 
-	napi = &pdata->rx_ring->napi;
-	netif_napi_add(pdata->ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT);
-
-	if (pdata->cq_cnt) {
-		napi = &pdata->tx_ring->cp_ring->napi;
+	for (i = 0; i < pdata->rxq_cnt; i++) {
+		napi = &pdata->rx_ring[i]->napi;
 		netif_napi_add(pdata->ndev, napi, xgene_enet_napi,
 			       NAPI_POLL_WEIGHT);
 	}
-}
-
-static void xgene_enet_napi_del(struct xgene_enet_pdata *pdata)
-{
-	struct napi_struct *napi;
 
-	napi = &pdata->rx_ring->napi;
-	netif_napi_del(napi);
-
-	if (pdata->cq_cnt) {
-		napi = &pdata->tx_ring->cp_ring->napi;
-		netif_napi_del(napi);
+	for (i = 0; i < pdata->cq_cnt; i++) {
+		napi = &pdata->tx_ring[i]->cp_ring->napi;
+		netif_napi_add(pdata->ndev, napi, xgene_enet_napi,
+			       NAPI_POLL_WEIGHT);
 	}
 }
 
@@ -1429,11 +1595,12 @@
 	struct net_device *ndev;
 	struct xgene_enet_pdata *pdata;
 	struct device *dev = &pdev->dev;
-	struct xgene_mac_ops *mac_ops;
+	void (*link_state)(struct work_struct *);
 	const struct of_device_id *of_id;
 	int ret;
 
-	ndev = alloc_etherdev(sizeof(struct xgene_enet_pdata));
+	ndev = alloc_etherdev_mqs(sizeof(struct xgene_enet_pdata),
+				  XGENE_NUM_RX_RING, XGENE_NUM_TX_RING);
 	if (!ndev)
 		return -ENOMEM;
 
@@ -1486,29 +1653,34 @@
 		goto err;
 	}
 
-	ret = register_netdev(ndev);
-	if (ret) {
-		netdev_err(ndev, "Failed to register netdev\n");
-		goto err;
-	}
-
 	ret = xgene_enet_init_hw(pdata);
 	if (ret)
-		goto err;
+		goto err_netdev;
 
-	mac_ops = pdata->mac_ops;
-	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
-		ret = xgene_enet_mdio_config(pdata);
-		if (ret)
-			goto err;
-	} else {
-		INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state);
+	link_state = pdata->mac_ops->link_state;
+	if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+		INIT_DELAYED_WORK(&pdata->link_work, link_state);
+	} else if (!pdata->mdio_driver) {
+		if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+			ret = xgene_enet_mdio_config(pdata);
+		else
+			INIT_DELAYED_WORK(&pdata->link_work, link_state);
 	}
+	if (ret)
+		goto err;
 
 	xgene_enet_napi_add(pdata);
+	ret = register_netdev(ndev);
+	if (ret) {
+		netdev_err(ndev, "Failed to register netdev\n");
+		goto err;
+	}
+
 	return 0;
-err:
+
+err_netdev:
 	unregister_netdev(ndev);
+err:
 	free_netdev(ndev);
 	return ret;
 }
@@ -1523,12 +1695,16 @@
 	mac_ops = pdata->mac_ops;
 	ndev = pdata->ndev;
 
-	mac_ops->rx_disable(pdata);
-	mac_ops->tx_disable(pdata);
-
-	xgene_enet_napi_del(pdata);
-	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+	rtnl_lock();
+	if (netif_running(ndev))
+		dev_close(ndev);
+	rtnl_unlock();
+
+	if (pdata->mdio_driver)
+		xgene_enet_phy_disconnect(pdata);
+	else if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
 		xgene_enet_mdio_remove(pdata);
+
 	unregister_netdev(ndev);
 	xgene_enet_delete_desc_rings(pdata);
 	pdata->port_ops->shutdown(pdata);
@@ -1537,6 +1713,20 @@
 	return 0;
 }
 
+static void xgene_enet_shutdown(struct platform_device *pdev)
+{
+	struct xgene_enet_pdata *pdata;
+
+	pdata = platform_get_drvdata(pdev);
+	if (!pdata)
+		return;
+
+	if (!pdata->ndev)
+		return;
+
+	xgene_enet_remove(pdev);
+}
+
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xgene_enet_acpi_match[] = {
 	{ "APMC0D05", XGENE_ENET1},
@@ -1571,6 +1761,7 @@
 	},
 	.probe = xgene_enet_probe,
 	.remove = xgene_enet_remove,
+	.shutdown = xgene_enet_shutdown,
 };
 
 module_platform_driver(xgene_enet_driver);
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
@@ -25,6 +25,7 @@
 #include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/efi.h>
+#include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/of_net.h>
@@ -35,7 +36,9 @@
 #include <linux/if_vlan.h>
 #include <linux/phy.h>
 #include "xgene_enet_hw.h"
+#include "xgene_enet_cle.h"
 #include "xgene_enet_ring2.h"
+#include "../../../phy/mdio-xgene.h"
 
 #define XGENE_DRV_VERSION	"v1.0"
 #define XGENE_ENET_MAX_MTU	1536
@@ -47,6 +50,11 @@
 #define XGENE_ENET_MSS	1448
 #define XGENE_MIN_ENET_FRAME_SIZE	60
 
+#define XGENE_MAX_ENET_IRQ	16
+#define XGENE_NUM_RX_RING	8
+#define XGENE_NUM_TX_RING	8
+#define XGENE_NUM_TXC_RING	8
+
 #define START_CPU_BUFNUM_0	0
 #define START_ETH_BUFNUM_0	2
 #define START_BP_BUFNUM_0	0x22
@@ -71,7 +79,6 @@
 #define X2_START_RING_NUM_1	256
 
 #define IRQ_ID_SIZE		16
-#define XGENE_MAX_TXC_RINGS	1
 
 #define PHY_POLL_LINK_ON	(10 * HZ)
 #define PHY_POLL_LINK_OFF	(PHY_POLL_LINK_ON / 5)
@@ -101,6 +108,7 @@
 	void *irq_mbox_addr;
 	u16 dst_ring_num;
 	u8 nbufpool;
+	u8 index;
 	struct sk_buff *(*rx_skb);
 	struct sk_buff *(*cp_skb);
 	dma_addr_t *frag_dma_addr;
@@ -114,6 +122,16 @@
 		struct xgene_enet_raw_desc16 *raw_desc16;
 	};
 	__le64 *exp_bufs;
+	u64 tx_packets;
+	u64 tx_bytes;
+	u64 rx_packets;
+	u64 rx_bytes;
+	u64 rx_dropped;
+	u64 rx_errors;
+	u64 rx_length_errors;
+	u64 rx_crc_errors;
+	u64 rx_frame_errors;
+	u64 rx_fifo_errors;
 };
 
 struct xgene_mac_ops {
@@ -123,6 +141,7 @@
 	void (*rx_enable)(struct xgene_enet_pdata *pdata);
 	void (*tx_disable)(struct xgene_enet_pdata *pdata);
 	void (*rx_disable)(struct xgene_enet_pdata *pdata);
+	void (*set_speed)(struct xgene_enet_pdata *pdata);
 	void (*set_mac_addr)(struct xgene_enet_pdata *pdata);
 	void (*set_mss)(struct xgene_enet_pdata *pdata);
 	void (*link_state)(struct work_struct *work);
@@ -130,6 +149,8 @@
 
 struct xgene_port_ops {
 	int (*reset)(struct xgene_enet_pdata *pdata);
+	void (*clear)(struct xgene_enet_pdata *pdata,
+		      struct xgene_enet_desc_ring *ring);
 	void (*cle_bypass)(struct xgene_enet_pdata *pdata,
 			   u32 dst_ring_num, u16 bufpool_id);
 	void (*shutdown)(struct xgene_enet_pdata *pdata);
@@ -142,6 +163,11 @@
 	void (*clear)(struct xgene_enet_desc_ring *);
 	void (*wr_cmd)(struct xgene_enet_desc_ring *, int);
 	u32 (*len)(struct xgene_enet_desc_ring *);
+	void (*coalesce)(struct xgene_enet_desc_ring *);
+};
+
+struct xgene_cle_ops {
+	int (*cle_init)(struct xgene_enet_pdata *pdata);
 };
 
 /* ethernet private data */
@@ -153,15 +179,16 @@
 	struct clk *clk;
 	struct platform_device *pdev;
 	enum xgene_enet_id enet_id;
-	struct xgene_enet_desc_ring *tx_ring;
-	struct xgene_enet_desc_ring *rx_ring;
-	u16 tx_level;
-	u16 txc_level;
+	struct xgene_enet_desc_ring *tx_ring[XGENE_NUM_TX_RING];
+	struct xgene_enet_desc_ring *rx_ring[XGENE_NUM_RX_RING];
+	u16 tx_level[XGENE_NUM_TX_RING];
+	u16 txc_level[XGENE_NUM_TX_RING];
 	char *dev_name;
 	u32 rx_buff_cnt;
 	u32 tx_qcnt_hi;
-	u32 rx_irq;
-	u32 txc_irq;
+	u32 irqs[XGENE_MAX_ENET_IRQ];
+	u8 rxq_cnt;
+	u8 txq_cnt;
 	u8 cq_cnt;
 	void __iomem *eth_csr_addr;
 	void __iomem *eth_ring_if_addr;
@@ -173,10 +200,12 @@
 	void __iomem *ring_cmd_addr;
 	int phy_mode;
 	enum xgene_enet_rm rm;
+	struct xgene_enet_cle cle;
 	struct rtnl_link_stats64 stats;
 	struct xgene_mac_ops *mac_ops;
 	struct xgene_port_ops *port_ops;
 	struct xgene_ring_ops *ring_ops;
+	const struct xgene_cle_ops *cle_ops;
 	struct delayed_work link_work;
 	u32 port_id;
 	u8 cpu_bufnum;
@@ -186,6 +215,7 @@
 	u32 mss;
 	u8 tx_delay;
 	u8 rx_delay;
+	bool mdio_driver;
 };
 
 struct xgene_indirect_ctl {
@@ -195,37 +225,16 @@
 	void __iomem *cmd_done;
 };
 
-/* Set the specified value into a bit-field defined by its starting position
- * and length within a single u64.
- */
-static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val)
+static inline struct device *ndev_to_dev(struct net_device *ndev)
 {
-	return (val & ((1ULL << len) - 1)) << pos;
+	return ndev->dev.parent;
 }
 
-#define SET_VAL(field, val) \
-		xgene_enet_set_field_value(field ## _POS, field ## _LEN, val)
-
-#define SET_BIT(field) \
-		xgene_enet_set_field_value(field ## _POS, 1, 1)
-
-/* Get the value from a bit-field defined by its starting position
- * and length within the specified u64.
- */
-static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src)
+static inline u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring)
 {
-	return (src >> pos) & ((1ULL << len) - 1);
-}
-
-#define GET_VAL(field, src) \
-		xgene_enet_get_field_value(field ## _POS, field ## _LEN, src)
-
-#define GET_BIT(field, src) \
-		xgene_enet_get_field_value(field ## _POS, 1, src)
+	struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
 
-static inline struct device *ndev_to_dev(struct net_device *ndev)
-{
-	return ndev->dev.parent;
+	return ((u16)pdata->rm << 10) | ring->num;
 }
 
 void xgene_enet_set_ethtool_ops(struct net_device *netdev);
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
@@ -190,6 +190,17 @@
 	return num_msgs;
 }
 
+static void xgene_enet_setup_coalescing(struct xgene_enet_desc_ring *ring)
+{
+	u32 data = 0x7777;
+
+	xgene_enet_ring_wr32(ring, CSR_PBM_COAL, 0x8e);
+	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK1, data);
+	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data << 16);
+	xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x40);
+	xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x80);
+}
+
 struct xgene_ring_ops xgene_ring2_ops = {
 	.num_ring_config = X2_NUM_RING_CONFIG,
 	.num_ring_id_shift = 13,
@@ -197,4 +208,5 @@
 	.clear = xgene_enet_clear_ring,
 	.wr_cmd = xgene_enet_wr_cmd,
 	.len = xgene_enet_ring_len,
+	.coalesce = xgene_enet_setup_coalescing,
 };
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
@@ -28,6 +28,12 @@
 	iowrite32(val, p->eth_csr_addr + offset);
 }
 
+static void xgene_enet_wr_clkrst_csr(struct xgene_enet_pdata *p, u32 offset,
+				     u32 val)
+{
+	iowrite32(val, p->base_addr + offset);
+}
+
 static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p,
 				  u32 offset, u32 val)
 {
@@ -93,6 +99,11 @@
 	return ioread32(p->eth_diag_csr_addr + offset);
 }
 
+static u32 xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *p, u32 offset)
+{
+	return ioread32(p->mcx_mac_csr_addr + offset);
+}
+
 static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr)
 {
 	u32 rd_data;
@@ -132,9 +143,17 @@
 static int xgene_enet_ecc_init(struct xgene_enet_pdata *p)
 {
 	struct net_device *ndev = p->ndev;
-	u32 data;
+	u32 data, shutdown;
 	int i = 0;
 
+	shutdown = xgene_enet_rd_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR);
+	data = xgene_enet_rd_diag_csr(p, ENET_BLOCK_MEM_RDY_ADDR);
+
+	if (!shutdown && data == ~0U) {
+		netdev_dbg(ndev, "+ ecc_init done, skipping\n");
+		return 0;
+	}
+
 	xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0);
 	do {
 		usleep_range(100, 110);
@@ -230,21 +249,105 @@
 	data = xgene_mii_phy_read(p, INT_PHY_ADDR,
 				  SGMII_BASE_PAGE_ABILITY_ADDR >> 2);
 
+	if (LINK_SPEED(data) == PHY_SPEED_1000)
+		p->phy_speed = SPEED_1000;
+	else if (LINK_SPEED(data) == PHY_SPEED_100)
+		p->phy_speed = SPEED_100;
+	else
+		p->phy_speed = SPEED_10;
+
 	return data & LINK_UP;
 }
 
-static void xgene_sgmac_init(struct xgene_enet_pdata *p)
+static void xgene_sgmii_configure(struct xgene_enet_pdata *p)
 {
-	u32 data, loop = 10;
-	u32 offset = p->port_id * 4;
-	u32 enet_spare_cfg_reg, rsif_config_reg;
-	u32 cfg_bypass_reg, rx_dv_gate_reg;
-
-	xgene_sgmac_reset(p);
+	xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2,
+			    0x8000);
+	xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x9000);
+	xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0);
+}
 
-	/* Enable auto-negotiation */
-	xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x1000);
+static void xgene_sgmii_tbi_control_reset(struct xgene_enet_pdata *p)
+{
+	xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2,
+			    0x8000);
 	xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0);
+}
+
+static void xgene_sgmii_reset(struct xgene_enet_pdata *p)
+{
+	u32 value;
+
+	if (p->phy_speed == SPEED_UNKNOWN)
+		return;
+
+	value = xgene_mii_phy_read(p, INT_PHY_ADDR,
+				   SGMII_BASE_PAGE_ABILITY_ADDR >> 2);
+	if (!(value & LINK_UP))
+		xgene_sgmii_tbi_control_reset(p);
+}
+
+static void xgene_sgmac_set_speed(struct xgene_enet_pdata *p)
+{
+	u32 icm0_addr, icm2_addr, debug_addr;
+	u32 icm0, icm2, intf_ctl;
+	u32 mc2, value;
+
+	xgene_sgmii_reset(p);
+
+	if (p->enet_id == XGENE_ENET1) {
+		icm0_addr = ICM_CONFIG0_REG_0_ADDR + p->port_id * OFFSET_8;
+		icm2_addr = ICM_CONFIG2_REG_0_ADDR + p->port_id * OFFSET_4;
+		debug_addr = DEBUG_REG_ADDR;
+	} else {
+		icm0_addr = XG_MCX_ICM_CONFIG0_REG_0_ADDR;
+		icm2_addr = XG_MCX_ICM_CONFIG2_REG_0_ADDR;
+		debug_addr = XG_DEBUG_REG_ADDR;
+	}
+
+	icm0 = xgene_enet_rd_mcx_csr(p, icm0_addr);
+	icm2 = xgene_enet_rd_mcx_csr(p, icm2_addr);
+	mc2 = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR);
+	intf_ctl = xgene_enet_rd_mac(p, INTERFACE_CONTROL_ADDR);
+
+	switch (p->phy_speed) {
+	case SPEED_10:
+		ENET_INTERFACE_MODE2_SET(&mc2, 1);
+		intf_ctl &= ~(ENET_LHD_MODE | ENET_GHD_MODE);
+		CFG_MACMODE_SET(&icm0, 0);
+		CFG_WAITASYNCRD_SET(&icm2, 500);
+		break;
+	case SPEED_100:
+		ENET_INTERFACE_MODE2_SET(&mc2, 1);
+		intf_ctl &= ~ENET_GHD_MODE;
+		intf_ctl |= ENET_LHD_MODE;
+		CFG_MACMODE_SET(&icm0, 1);
+		CFG_WAITASYNCRD_SET(&icm2, 80);
+		break;
+	default:
+		ENET_INTERFACE_MODE2_SET(&mc2, 2);
+		intf_ctl &= ~ENET_LHD_MODE;
+		intf_ctl |= ENET_GHD_MODE;
+		CFG_MACMODE_SET(&icm0, 2);
+		CFG_WAITASYNCRD_SET(&icm2, 16);
+		value = xgene_enet_rd_csr(p, debug_addr);
+		value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX;
+		xgene_enet_wr_csr(p, debug_addr, value);
+		break;
+	}
+
+	mc2 |= FULL_DUPLEX2 | PAD_CRC;
+	xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, mc2);
+	xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, intf_ctl);
+	xgene_enet_wr_mcx_csr(p, icm0_addr, icm0);
+	xgene_enet_wr_mcx_csr(p, icm2_addr, icm2);
+}
+
+static void xgene_sgmii_enable_autoneg(struct xgene_enet_pdata *p)
+{
+	u32 data, loop = 10;
+
+	xgene_sgmii_configure(p);
 
 	while (loop--) {
 		data = xgene_mii_phy_read(p, INT_PHY_ADDR,
@@ -255,17 +358,27 @@
 	}
 	if (!(data & AUTO_NEG_COMPLETE) || !(data & LINK_STATUS))
 		netdev_err(p->ndev, "Auto-negotiation failed\n");
+}
 
-	data = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR);
-	ENET_INTERFACE_MODE2_SET(&data, 2);
-	xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, data | FULL_DUPLEX2);
-	xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, ENET_GHD_MODE);
+static void xgene_sgmac_init(struct xgene_enet_pdata *p)
+{
+	u32 enet_spare_cfg_reg, rsif_config_reg;
+	u32 cfg_bypass_reg, rx_dv_gate_reg;
+	u32 data, offset;
+
+	if (!(p->enet_id == XGENE_ENET2 && p->mdio_driver))
+		xgene_sgmac_reset(p);
+
+	xgene_sgmii_enable_autoneg(p);
+	xgene_sgmac_set_speed(p);
+	xgene_sgmac_set_mac_addr(p);
 
 	if (p->enet_id == XGENE_ENET1) {
 		enet_spare_cfg_reg = ENET_SPARE_CFG_REG_ADDR;
 		rsif_config_reg = RSIF_CONFIG_REG_ADDR;
 		cfg_bypass_reg = CFG_BYPASS_ADDR;
-		rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR;
+		offset = p->port_id * OFFSET_4;
+		rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR + offset;
 	} else {
 		enet_spare_cfg_reg = XG_ENET_SPARE_CFG_REG_ADDR;
 		rsif_config_reg = XG_RSIF_CONFIG_REG_ADDR;
@@ -277,8 +390,6 @@
 	data |= MPA_IDLE_WITH_QMI_EMPTY;
 	xgene_enet_wr_csr(p, enet_spare_cfg_reg, data);
 
-	xgene_sgmac_set_mac_addr(p);
-
 	/* Adjust MDC clock frequency */
 	data = xgene_enet_rd_mac(p, MII_MGMT_CONFIG_ADDR);
 	MGMT_CLOCK_SEL_SET(&data, 7);
@@ -292,7 +403,7 @@
 	/* Bypass traffic gating */
 	xgene_enet_wr_csr(p, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x84);
 	xgene_enet_wr_csr(p, cfg_bypass_reg, RESUME_TX);
-	xgene_enet_wr_mcx_csr(p, rx_dv_gate_reg + offset, RESUME_RX0);
+	xgene_enet_wr_mcx_csr(p, rx_dv_gate_reg, RESUME_RX0);
 }
 
 static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set)
@@ -331,17 +442,43 @@
 
 static int xgene_enet_reset(struct xgene_enet_pdata *p)
 {
+	struct device *dev = &p->pdev->dev;
+
 	if (!xgene_ring_mgr_init(p))
 		return -ENODEV;
 
-	if (!IS_ERR(p->clk)) {
-		clk_prepare_enable(p->clk);
-		clk_disable_unprepare(p->clk);
-		clk_prepare_enable(p->clk);
+	if (p->mdio_driver && p->enet_id == XGENE_ENET2) {
+		xgene_enet_config_ring_if_assoc(p);
+		return 0;
 	}
 
-	xgene_enet_ecc_init(p);
-	xgene_enet_config_ring_if_assoc(p);
+	if (p->enet_id == XGENE_ENET2)
+		xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN);
+
+	if (dev->of_node) {
+		if (!IS_ERR(p->clk)) {
+			clk_prepare_enable(p->clk);
+			udelay(5);
+			clk_disable_unprepare(p->clk);
+			udelay(5);
+			clk_prepare_enable(p->clk);
+			udelay(5);
+		}
+	} else {
+#ifdef CONFIG_ACPI
+		if (acpi_has_method(ACPI_HANDLE(&p->pdev->dev), "_RST"))
+			acpi_evaluate_object(ACPI_HANDLE(&p->pdev->dev),
+					     "_RST", NULL, NULL);
+		else if (acpi_has_method(ACPI_HANDLE(&p->pdev->dev), "_INI"))
+			acpi_evaluate_object(ACPI_HANDLE(&p->pdev->dev),
+					     "_INI", NULL, NULL);
+#endif
+	}
+
+	if (!p->port_id) {
+		xgene_enet_ecc_init(p);
+		xgene_enet_config_ring_if_assoc(p);
+	}
 
 	return 0;
 }
@@ -369,10 +506,32 @@
 	xgene_enet_wr_csr(p, cle_bypass_reg1 + offset, data);
 }
 
+static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
+			     struct xgene_enet_desc_ring *ring)
+{
+	u32 addr, val, data;
+
+	val = xgene_enet_ring_bufnum(ring->id);
+
+	if (xgene_enet_is_bufpool(ring->id)) {
+		addr = ENET_CFGSSQMIFPRESET_ADDR;
+		data = BIT(val - 0x20);
+	} else {
+		addr = ENET_CFGSSQMIWQRESET_ADDR;
+		data = BIT(val);
+	}
+
+	xgene_enet_wr_ring_if(pdata, addr, data);
+}
+
 static void xgene_enet_shutdown(struct xgene_enet_pdata *p)
 {
-	if (!IS_ERR(p->clk))
-		clk_disable_unprepare(p->clk);
+	struct device *dev = &p->pdev->dev;
+
+	if (dev->of_node) {
+		if (!IS_ERR(p->clk))
+			clk_disable_unprepare(p->clk);
+	}
 }
 
 static void xgene_enet_link_state(struct work_struct *work)
@@ -386,10 +545,11 @@
 	if (link) {
 		if (!netif_carrier_ok(ndev)) {
 			netif_carrier_on(ndev);
-			xgene_sgmac_init(p);
+			xgene_sgmac_set_speed(p);
 			xgene_sgmac_rx_enable(p);
 			xgene_sgmac_tx_enable(p);
-			netdev_info(ndev, "Link is Up - 1Gbps\n");
+			netdev_info(ndev, "Link is Up - %dMbps\n",
+				    p->phy_speed);
 		}
 		poll_interval = PHY_POLL_LINK_ON;
 	} else {
@@ -412,12 +572,14 @@
 	.tx_enable	= xgene_sgmac_tx_enable,
 	.rx_disable	= xgene_sgmac_rx_disable,
 	.tx_disable	= xgene_sgmac_tx_disable,
+	.set_speed	= xgene_sgmac_set_speed,
 	.set_mac_addr	= xgene_sgmac_set_mac_addr,
 	.link_state	= xgene_enet_link_state
 };
 
 struct xgene_port_ops xgene_sgport_ops = {
 	.reset		= xgene_enet_reset,
+	.clear		= xgene_enet_clear,
 	.cle_bypass	= xgene_enet_cle_bypass,
 	.shutdown	= xgene_enet_shutdown
 };
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h
@@ -24,6 +24,7 @@
 #define PHY_ADDR(src)		(((src)<<8) & GENMASK(12, 8))
 #define REG_ADDR(src)		((src) & GENMASK(4, 0))
 #define PHY_CONTROL(src)	((src) & GENMASK(15, 0))
+#define LINK_SPEED(src)		(((src) & GENMASK(11, 10)) >> 10)
 #define INT_PHY_ADDR			0x1e
 #define SGMII_TBI_CONTROL_ADDR		0x44
 #define SGMII_CONTROL_ADDR		0x00
@@ -33,9 +34,17 @@
 #define LINK_STATUS			BIT(2)
 #define LINK_UP				BIT(15)
 #define MPA_IDLE_WITH_QMI_EMPTY		BIT(12)
-#define SG_RX_DV_GATE_REG_0_ADDR	0x0dfc
+#define SG_RX_DV_GATE_REG_0_ADDR	0x05fc
+#define SGMII_EN			0x1
+
 
 extern struct xgene_mac_ops xgene_sgmac_ops;
 extern struct xgene_port_ops xgene_sgport_ops;
 
+enum xgene_phy_speed {
+	PHY_SPEED_10,
+	PHY_SPEED_100,
+	PHY_SPEED_1000
+};
+
 #endif  /* __XGENE_ENET_SGMAC_H__ */
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
@@ -258,13 +258,29 @@
 
 static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
 {
+	struct device *dev = &pdata->pdev->dev;
+
 	if (!xgene_ring_mgr_init(pdata))
 		return -ENODEV;
 
-	if (!IS_ERR(pdata->clk)) {
+	if (dev->of_node) {
 		clk_prepare_enable(pdata->clk);
+		udelay(5);
 		clk_disable_unprepare(pdata->clk);
+		udelay(5);
 		clk_prepare_enable(pdata->clk);
+		udelay(5);
+	} else {
+#ifdef CONFIG_ACPI
+		if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), "_RST")) {
+			acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
+					     "_RST", NULL, NULL);
+		} else if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev),
+					   "_INI")) {
+			acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
+					     "_INI", NULL, NULL);
+		}
+#endif
 	}
 
 	xgene_enet_ecc_init(pdata);
@@ -292,8 +308,30 @@
 
 static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
 {
-	if (!IS_ERR(pdata->clk))
-		clk_disable_unprepare(pdata->clk);
+	struct device *dev = &pdata->pdev->dev;
+
+	if (dev->of_node) {
+		if (!IS_ERR(pdata->clk))
+			clk_disable_unprepare(pdata->clk);
+	}
+}
+
+static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
+			     struct xgene_enet_desc_ring *ring)
+{
+	u32 addr, val, data;
+
+	val = xgene_enet_ring_bufnum(ring->id);
+
+	if (xgene_enet_is_bufpool(ring->id)) {
+		addr = ENET_CFGSSQMIFPRESET_ADDR;
+		data = BIT(val - 0x20);
+	} else {
+		addr = ENET_CFGSSQMIWQRESET_ADDR;
+		data = BIT(val);
+	}
+
+	xgene_enet_wr_ring_if(pdata, addr, data);
 }
 
 static void xgene_enet_link_state(struct work_struct *work)
@@ -340,6 +378,7 @@
 
 struct xgene_port_ops xgene_xgport_ops = {
 	.reset = xgene_enet_reset,
+	.clear = xgene_enet_clear,
 	.cle_bypass = xgene_enet_xgcle_bypass,
 	.shutdown = xgene_enet_shutdown,
 };
--- linux-4.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h
+++ linux-4.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h
@@ -65,9 +65,12 @@
 #define XG_CFG_LINK_AGGR_RESUME_0_ADDR	0x0214
 #define XG_LINK_STATUS_ADDR		0x0228
 #define XG_TSIF_MSS_REG0_ADDR		0x02a4
+#define XG_DEBUG_REG_ADDR		0x0400
 #define XG_ENET_SPARE_CFG_REG_ADDR	0x040c
 #define XG_ENET_SPARE_CFG_REG_1_ADDR	0x0410
 #define XGENET_RX_DV_GATE_REG_0_ADDR	0x0804
+#define XG_MCX_ICM_CONFIG0_REG_0_ADDR	0x00e0
+#define XG_MCX_ICM_CONFIG2_REG_0_ADDR	0x00e8
 
 extern struct xgene_mac_ops xgene_xgmac_ops;
 extern struct xgene_port_ops xgene_xgport_ops;
--- linux-4.4.0.orig/drivers/net/ethernet/apple/bmac.c
+++ linux-4.4.0/drivers/net/ethernet/apple/bmac.c
@@ -1187,7 +1187,7 @@
 	int i;
 	unsigned short data;
 
-	for (i = 0; i < 6; i++)
+	for (i = 0; i < 3; i++)
 		{
 			reset_and_select_srom(dev);
 			data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
--- linux-4.4.0.orig/drivers/net/ethernet/arc/emac_main.c
+++ linux-4.4.0/drivers/net/ethernet/arc/emac_main.c
@@ -163,7 +163,7 @@
 		struct sk_buff *skb = tx_buff->skb;
 		unsigned int info = le32_to_cpu(txbd->info);
 
-		if ((info & FOR_EMAC) || !txbd->data)
+		if ((info & FOR_EMAC) || !txbd->data || !skb)
 			break;
 
 		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
@@ -191,6 +191,7 @@
 
 		txbd->data = 0;
 		txbd->info = 0;
+		tx_buff->skb = NULL;
 
 		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
 	}
@@ -250,39 +251,48 @@
 			continue;
 		}
 
-		pktlen = info & LEN_MASK;
-		stats->rx_packets++;
-		stats->rx_bytes += pktlen;
-		skb = rx_buff->skb;
-		skb_put(skb, pktlen);
-		skb->dev = ndev;
-		skb->protocol = eth_type_trans(skb, ndev);
-
-		dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr),
-				 dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE);
-
-		/* Prepare the BD for next cycle */
-		rx_buff->skb = netdev_alloc_skb_ip_align(ndev,
-							 EMAC_BUFFER_SIZE);
-		if (unlikely(!rx_buff->skb)) {
+		/* Prepare the BD for next cycle. netif_receive_skb()
+		 * only if new skb was allocated and mapped to avoid holes
+		 * in the RX fifo.
+		 */
+		skb = netdev_alloc_skb_ip_align(ndev, EMAC_BUFFER_SIZE);
+		if (unlikely(!skb)) {
+			if (net_ratelimit())
+				netdev_err(ndev, "cannot allocate skb\n");
+			/* Return ownership to EMAC */
+			rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
 			stats->rx_errors++;
-			/* Because receive_skb is below, increment rx_dropped */
 			stats->rx_dropped++;
 			continue;
 		}
 
-		/* receive_skb only if new skb was allocated to avoid holes */
-		netif_receive_skb(skb);
-
-		addr = dma_map_single(&ndev->dev, (void *)rx_buff->skb->data,
+		addr = dma_map_single(&ndev->dev, (void *)skb->data,
 				      EMAC_BUFFER_SIZE, DMA_FROM_DEVICE);
 		if (dma_mapping_error(&ndev->dev, addr)) {
 			if (net_ratelimit())
-				netdev_err(ndev, "cannot dma map\n");
-			dev_kfree_skb(rx_buff->skb);
+				netdev_err(ndev, "cannot map dma buffer\n");
+			dev_kfree_skb(skb);
+			/* Return ownership to EMAC */
+			rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
 			stats->rx_errors++;
+			stats->rx_dropped++;
 			continue;
 		}
+
+		/* unmap previosly mapped skb */
+		dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr),
+				 dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE);
+
+		pktlen = info & LEN_MASK;
+		stats->rx_packets++;
+		stats->rx_bytes += pktlen;
+		skb_put(rx_buff->skb, pktlen);
+		rx_buff->skb->dev = ndev;
+		rx_buff->skb->protocol = eth_type_trans(rx_buff->skb, ndev);
+
+		netif_receive_skb(rx_buff->skb);
+
+		rx_buff->skb = skb;
 		dma_unmap_addr_set(rx_buff, addr, addr);
 		dma_unmap_len_set(rx_buff, len, EMAC_BUFFER_SIZE);
 
@@ -610,7 +620,6 @@
 	dma_unmap_addr_set(&priv->tx_buff[*txbd_curr], addr, addr);
 	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
 
-	priv->tx_buff[*txbd_curr].skb = skb;
 	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
 
 	/* Make sure pointer to data buffer is set */
@@ -620,6 +629,11 @@
 
 	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
+	/* Make sure info word is set */
+	wmb();
+
+	priv->tx_buff[*txbd_curr].skb = skb;
+
 	/* Increment index to point to the next BD */
 	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
 
--- linux-4.4.0.orig/drivers/net/ethernet/arc/emac_rockchip.c
+++ linux-4.4.0/drivers/net/ethernet/arc/emac_rockchip.c
@@ -150,8 +150,10 @@
 	/* Optional regulator for PHY */
 	priv->regulator = devm_regulator_get_optional(dev, "phy");
 	if (IS_ERR(priv->regulator)) {
-		if (PTR_ERR(priv->regulator) == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
+		if (PTR_ERR(priv->regulator) == -EPROBE_DEFER) {
+			err = -EPROBE_DEFER;
+			goto out_clk_disable;
+		}
 		dev_err(dev, "no regulator found\n");
 		priv->regulator = NULL;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/atheros/alx/main.c
+++ linux-4.4.0/drivers/net/ethernet/atheros/alx/main.c
@@ -86,9 +86,14 @@
 	while (!cur_buf->skb && next != rxq->read_idx) {
 		struct alx_rfd *rfd = &rxq->rfd[cur];
 
-		skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp);
+		skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size + 64, gfp);
 		if (!skb)
 			break;
+
+		/* Workround for the HW RX DMA overflow issue */
+		if (((unsigned long)skb->data & 0xfff) == 0xfc0)
+			skb_reserve(skb, 64);
+
 		dma = dma_map_single(&alx->hw.pdev->dev,
 				     skb->data, alx->rxbuf_size,
 				     DMA_FROM_DEVICE);
@@ -867,8 +872,12 @@
 
 static void __alx_stop(struct alx_priv *alx)
 {
-	alx_halt(alx);
 	alx_free_irq(alx);
+
+	cancel_work_sync(&alx->link_check_wk);
+	cancel_work_sync(&alx->reset_wk);
+
+	alx_halt(alx);
 	alx_free_rings(alx);
 }
 
@@ -1401,9 +1410,6 @@
 	struct alx_priv *alx = pci_get_drvdata(pdev);
 	struct alx_hw *hw = &alx->hw;
 
-	cancel_work_sync(&alx->link_check_wk);
-	cancel_work_sync(&alx->reset_wk);
-
 	/* restore permanent mac address */
 	alx_set_macaddr(hw, hw->perm_addr);
 
--- linux-4.4.0.orig/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ linux-4.4.0/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -1683,6 +1683,7 @@
 	skb = build_skb(page_address(page) + adapter->rx_page_offset,
 			adapter->rx_frag_size);
 	if (likely(skb)) {
+		skb_reserve(skb, NET_SKB_PAD);
 		adapter->rx_page_offset += adapter->rx_frag_size;
 		if (adapter->rx_page_offset >= PAGE_SIZE)
 			adapter->rx_page = NULL;
--- linux-4.4.0.orig/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ linux-4.4.0/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -478,7 +478,9 @@
 {
 	struct atl1e_adapter *adapter = netdev_priv(netdev);
 
-	atl1e_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val);
+	if (atl1e_write_phy_reg(&adapter->hw,
+				reg_num & MDIO_REG_ADDR_MASK, val))
+		netdev_err(netdev, "write phy register failed\n");
 }
 
 static int atl1e_mii_ioctl(struct net_device *netdev,
--- linux-4.4.0.orig/drivers/net/ethernet/atheros/atlx/atl2.c
+++ linux-4.4.0/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -1338,13 +1338,11 @@
 {
 	struct net_device *netdev;
 	struct atl2_adapter *adapter;
-	static int cards_found;
+	static int cards_found = 0;
 	unsigned long mmio_start;
 	int mmio_len;
 	int err;
 
-	cards_found = 0;
-
 	err = pci_enable_device(pdev);
 	if (err)
 		return err;
@@ -1412,7 +1410,7 @@
 
 	err = -EIO;
 
-	netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_RX;
+	netdev->hw_features = NETIF_F_HW_VLAN_CTAG_RX;
 	netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
 
 	/* Init PHY as early as possible due to power saving issue  */
--- linux-4.4.0.orig/drivers/net/ethernet/aurora/nb8800.c
+++ linux-4.4.0/drivers/net/ethernet/aurora/nb8800.c
@@ -608,7 +608,7 @@
 		mac_mode |= HALF_DUPLEX;
 
 	if (gigabit) {
-		if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII)
+		if (phy_interface_is_rgmii(dev->phydev))
 			mac_mode |= RGMII_MODE;
 
 		mac_mode |= GMAC_MODE;
@@ -1295,11 +1295,10 @@
 		break;
 
 	case PHY_INTERFACE_MODE_RGMII:
-		pad_mode = PAD_MODE_RGMII;
-		break;
-
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
 	case PHY_INTERFACE_MODE_RGMII_TXID:
-		pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY;
+		pad_mode = PAD_MODE_RGMII;
 		break;
 
 	default:
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/b44.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/b44.c
@@ -1524,8 +1524,10 @@
 	int ethaddr_bytes = ETH_ALEN;
 
 	memset(ppattern + offset, 0xff, magicsync);
-	for (j = 0; j < magicsync; j++)
-		set_bit(len++, (unsigned long *) pmask);
+	for (j = 0; j < magicsync; j++) {
+		pmask[len >> 3] |= BIT(len & 7);
+		len++;
+	}
 
 	for (j = 0; j < B44_MAX_PATTERNS; j++) {
 		if ((B44_PATTERN_SIZE - len) >= ETH_ALEN)
@@ -1537,7 +1539,8 @@
 		for (k = 0; k< ethaddr_bytes; k++) {
 			ppattern[offset + magicsync +
 				(j * ETH_ALEN) + k] = macaddr[k];
-			set_bit(len++, (unsigned long *) pmask);
+			pmask[len >> 3] |= BIT(len & 7);
+			len++;
 		}
 	}
 	return len - 1;
@@ -2390,7 +2393,8 @@
 		goto err_out_free_dev;
 	}
 
-	if (dma_set_mask_and_coherent(sdev->dma_dev, DMA_BIT_MASK(30))) {
+	err = dma_set_mask_and_coherent(sdev->dma_dev, DMA_BIT_MASK(30));
+	if (err) {
 		dev_err(sdev->dev,
 			"Required 30BIT DMA mask unsupported by the system\n");
 		goto err_out_powerdown;
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -571,12 +571,13 @@
 /*
  * tx request callback
  */
-static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct bcm_enet_priv *priv;
 	struct bcm_enet_desc *desc;
 	u32 len_stat;
-	int ret;
+	netdev_tx_t ret;
 
 	priv = netdev_priv(dev);
 
@@ -1063,7 +1064,8 @@
 	val = enet_readl(priv, ENET_CTL_REG);
 	val |= ENET_CTL_ENABLE_MASK;
 	enet_writel(priv, val, ENET_CTL_REG);
-	enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
+	if (priv->dma_has_sram)
+		enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
 	enet_dmac_writel(priv, priv->dma_chan_en_mask,
 			 ENETDMAC_CHANCFG, priv->rx_chan);
 
@@ -1787,7 +1789,9 @@
 		ret = PTR_ERR(priv->mac_clk);
 		goto out;
 	}
-	clk_prepare_enable(priv->mac_clk);
+	ret = clk_prepare_enable(priv->mac_clk);
+	if (ret)
+		goto out_put_clk_mac;
 
 	/* initialize default and fetch platform data */
 	priv->rx_ring_size = BCMENET_DEF_RX_DESC;
@@ -1819,9 +1823,11 @@
 		if (IS_ERR(priv->phy_clk)) {
 			ret = PTR_ERR(priv->phy_clk);
 			priv->phy_clk = NULL;
-			goto out_put_clk_mac;
+			goto out_disable_clk_mac;
 		}
-		clk_prepare_enable(priv->phy_clk);
+		ret = clk_prepare_enable(priv->phy_clk);
+		if (ret)
+			goto out_put_clk_phy;
 	}
 
 	/* do minimal hardware init to be able to probe mii bus */
@@ -1921,13 +1927,16 @@
 out_uninit_hw:
 	/* turn off mdc clock */
 	enet_writel(priv, 0, ENET_MIISC_REG);
-	if (priv->phy_clk) {
+	if (priv->phy_clk)
 		clk_disable_unprepare(priv->phy_clk);
+
+out_put_clk_phy:
+	if (priv->phy_clk)
 		clk_put(priv->phy_clk);
-	}
 
-out_put_clk_mac:
+out_disable_clk_mac:
 	clk_disable_unprepare(priv->mac_clk);
+out_put_clk_mac:
 	clk_put(priv->mac_clk);
 out:
 	free_netdev(dev);
@@ -2772,7 +2781,9 @@
 		ret = PTR_ERR(priv->mac_clk);
 		goto out_unmap;
 	}
-	clk_enable(priv->mac_clk);
+	ret = clk_prepare_enable(priv->mac_clk);
+	if (ret)
+		goto out_put_clk;
 
 	priv->rx_chan = 0;
 	priv->tx_chan = 1;
@@ -2793,7 +2804,7 @@
 
 	ret = register_netdev(dev);
 	if (ret)
-		goto out_put_clk;
+		goto out_disable_clk;
 
 	netif_carrier_off(dev);
 	platform_set_drvdata(pdev, dev);
@@ -2802,6 +2813,9 @@
 
 	return 0;
 
+out_disable_clk:
+	clk_disable_unprepare(priv->mac_clk);
+
 out_put_clk:
 	clk_put(priv->mac_clk);
 
@@ -2833,6 +2847,9 @@
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(res->start, resource_size(res));
 
+	clk_disable_unprepare(priv->mac_clk);
+	clk_put(priv->mac_clk);
+
 	free_netdev(dev);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bcmsysport.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -90,9 +90,13 @@
 					     struct dma_desc *desc,
 					     unsigned int port)
 {
+	unsigned long desc_flags;
+
 	/* Ports are latched, so write upper address first */
+	spin_lock_irqsave(&priv->desc_lock, desc_flags);
 	tdma_writel(priv, desc->addr_status_len, TDMA_WRITE_PORT_HI(port));
 	tdma_writel(priv, desc->addr_lo, TDMA_WRITE_PORT_LO(port));
+	spin_unlock_irqrestore(&priv->desc_lock, desc_flags);
 }
 
 /* Ethtool operations */
@@ -126,6 +130,10 @@
 
 	priv->rx_chk_en = !!(wanted & NETIF_F_RXCSUM);
 	reg = rxchk_readl(priv, RXCHK_CONTROL);
+	/* Clear L2 header checks, which would prevent BPDUs
+	 * from being received.
+	 */
+	reg &= ~RXCHK_L2_HDR_DIS;
 	if (priv->rx_chk_en)
 		reg |= RXCHK_EN;
 	else
@@ -392,7 +400,7 @@
 		else
 			p = (char *)priv;
 		p += s->stat_offset;
-		data[i] = *(u32 *)p;
+		data[i] = *(unsigned long *)p;
 	}
 }
 
@@ -400,7 +408,6 @@
 				struct ethtool_wolinfo *wol)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
-	u32 reg;
 
 	wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
 	wol->wolopts = priv->wolopts;
@@ -408,11 +415,7 @@
 	if (!(priv->wolopts & WAKE_MAGICSECURE))
 		return;
 
-	/* Return the programmed SecureOn password */
-	reg = umac_readl(priv, UMAC_PSW_MS);
-	put_unaligned_be16(reg, &wol->sopass[0]);
-	reg = umac_readl(priv, UMAC_PSW_LS);
-	put_unaligned_be32(reg, &wol->sopass[2]);
+	memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
 }
 
 static int bcm_sysport_set_wol(struct net_device *dev,
@@ -428,13 +431,8 @@
 	if (wol->wolopts & ~supported)
 		return -EINVAL;
 
-	/* Program the SecureOn password */
-	if (wol->wolopts & WAKE_MAGICSECURE) {
-		umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
-			    UMAC_PSW_MS);
-		umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
-			    UMAC_PSW_LS);
-	}
+	if (wol->wolopts & WAKE_MAGICSECURE)
+		memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
 
 	/* Flag the device and relevant IRQ as wakeup capable */
 	if (wol->wolopts) {
@@ -532,7 +530,8 @@
 	dma_addr_t mapping;
 
 	/* Allocate a new SKB for a new packet */
-	skb = netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH);
+	skb = __netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH,
+				 GFP_ATOMIC | __GFP_NOWARN);
 	if (!skb) {
 		priv->mib.alloc_rx_buff_failed++;
 		netif_err(priv, rx_err, ndev, "SKB alloc failed\n");
@@ -729,47 +728,37 @@
 					     struct bcm_sysport_tx_ring *ring)
 {
 	struct net_device *ndev = priv->netdev;
-	unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs;
 	unsigned int pkts_compl = 0, bytes_compl = 0;
+	unsigned int txbds_processed = 0;
 	struct bcm_sysport_cb *cb;
-	struct netdev_queue *txq;
+	unsigned int txbds_ready;
+	unsigned int c_index;
 	u32 hw_ind;
 
-	txq = netdev_get_tx_queue(ndev, ring->index);
-
 	/* Compute how many descriptors have been processed since last call */
 	hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index));
 	c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK;
-	ring->p_index = (hw_ind & RING_PROD_INDEX_MASK);
-
-	last_c_index = ring->c_index;
-	num_tx_cbs = ring->size;
-
-	c_index &= (num_tx_cbs - 1);
-
-	if (c_index >= last_c_index)
-		last_tx_cn = c_index - last_c_index;
-	else
-		last_tx_cn = num_tx_cbs - last_c_index + c_index;
+	txbds_ready = (c_index - ring->c_index) & RING_CONS_INDEX_MASK;
 
 	netif_dbg(priv, tx_done, ndev,
-		  "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n",
-		  ring->index, c_index, last_tx_cn, last_c_index);
+		  "ring=%d old_c_index=%u c_index=%u txbds_ready=%u\n",
+		  ring->index, ring->c_index, c_index, txbds_ready);
 
-	while (last_tx_cn-- > 0) {
-		cb = ring->cbs + last_c_index;
+	while (txbds_processed < txbds_ready) {
+		cb = &ring->cbs[ring->clean_index];
 		bcm_sysport_tx_reclaim_one(priv, cb, &bytes_compl, &pkts_compl);
 
 		ring->desc_count++;
-		last_c_index++;
-		last_c_index &= (num_tx_cbs - 1);
+		txbds_processed++;
+
+		if (likely(ring->clean_index < ring->size - 1))
+			ring->clean_index++;
+		else
+			ring->clean_index = 0;
 	}
 
 	ring->c_index = c_index;
 
-	if (netif_tx_queue_stopped(txq) && pkts_compl)
-		netif_tx_wake_queue(txq);
-
 	netif_dbg(priv, tx_done, ndev,
 		  "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n",
 		  ring->index, ring->c_index, pkts_compl, bytes_compl);
@@ -781,16 +770,33 @@
 static unsigned int bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
 					   struct bcm_sysport_tx_ring *ring)
 {
+	struct netdev_queue *txq;
 	unsigned int released;
 	unsigned long flags;
 
+	txq = netdev_get_tx_queue(priv->netdev, ring->index);
+
 	spin_lock_irqsave(&ring->lock, flags);
 	released = __bcm_sysport_tx_reclaim(priv, ring);
+	if (released)
+		netif_tx_wake_queue(txq);
+
 	spin_unlock_irqrestore(&ring->lock, flags);
 
 	return released;
 }
 
+/* Locked version of the per-ring TX reclaim, but does not wake the queue */
+static void bcm_sysport_tx_clean(struct bcm_sysport_priv *priv,
+				 struct bcm_sysport_tx_ring *ring)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ring->lock, flags);
+	__bcm_sysport_tx_reclaim(priv, ring);
+	spin_unlock_irqrestore(&ring->lock, flags);
+}
+
 static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
 {
 	struct bcm_sysport_tx_ring *ring =
@@ -843,14 +849,22 @@
 {
 	u32 reg;
 
-	/* Stop monitoring MPD interrupt */
-	intrl2_0_mask_set(priv, INTRL2_0_MPD);
-
 	/* Clear the MagicPacket detection logic */
 	reg = umac_readl(priv, UMAC_MPD_CTRL);
 	reg &= ~MPD_EN;
 	umac_writel(priv, reg, UMAC_MPD_CTRL);
 
+	reg = intrl2_0_readl(priv, INTRL2_CPU_STATUS);
+	if (reg & INTRL2_0_MPD)
+		netdev_info(priv->netdev, "Wake-on-LAN (MPD) interrupt!\n");
+
+	if (reg & INTRL2_0_BRCM_MATCH_TAG) {
+		reg = rxchk_readl(priv, RXCHK_BRCM_TAG_MATCH_STATUS) &
+				  RXCHK_BRCM_TAG_MATCH_MASK;
+		netdev_info(priv->netdev,
+			    "Wake-on-LAN (filters 0x%02x) interrupt!\n", reg);
+	}
+
 	netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n");
 }
 
@@ -883,11 +897,6 @@
 	if (priv->irq0_stat & INTRL2_0_TX_RING_FULL)
 		bcm_sysport_tx_reclaim_all(priv);
 
-	if (priv->irq0_stat & INTRL2_0_MPD) {
-		netdev_info(priv->netdev, "Wake-on-LAN interrupt!\n");
-		bcm_sysport_resume_from_wol(priv);
-	}
-
 	return IRQ_HANDLED;
 }
 
@@ -1034,15 +1043,6 @@
 		goto out;
 	}
 
-	/* Insert TSB and checksum infos */
-	if (priv->tsb_en) {
-		skb = bcm_sysport_insert_tsb(skb, dev);
-		if (!skb) {
-			ret = NETDEV_TX_OK;
-			goto out;
-		}
-	}
-
 	/* The Ethernet switch we are interfaced with needs packets to be at
 	 * least 64 bytes (including FCS) otherwise they will be discarded when
 	 * they enter the switch port logic. When Broadcom tags are enabled, we
@@ -1050,13 +1050,21 @@
 	 * (including FCS and tag) because the length verification is done after
 	 * the Broadcom tag is stripped off the ingress packet.
 	 */
-	if (skb_padto(skb, ETH_ZLEN + ENET_BRCM_TAG_LEN)) {
+	if (skb_put_padto(skb, ETH_ZLEN + ENET_BRCM_TAG_LEN)) {
 		ret = NETDEV_TX_OK;
 		goto out;
 	}
 
-	skb_len = skb->len < ETH_ZLEN + ENET_BRCM_TAG_LEN ?
-			ETH_ZLEN + ENET_BRCM_TAG_LEN : skb->len;
+	/* Insert TSB and checksum infos */
+	if (priv->tsb_en) {
+		skb = bcm_sysport_insert_tsb(skb, dev);
+		if (!skb) {
+			ret = NETDEV_TX_OK;
+			goto out;
+		}
+	}
+
+	skb_len = skb->len;
 
 	mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE);
 	if (dma_mapping_error(kdev, mapping)) {
@@ -1064,6 +1072,7 @@
 		netif_err(priv, tx_err, dev, "DMA map failed at %p (len=%d)\n",
 			  skb->data, skb_len);
 		ret = NETDEV_TX_OK;
+		dev_kfree_skb_any(skb);
 		goto out;
 	}
 
@@ -1219,6 +1228,7 @@
 	netif_napi_add(priv->netdev, &ring->napi, bcm_sysport_tx_poll, 64);
 	ring->index = index;
 	ring->size = size;
+	ring->clean_index = 0;
 	ring->alloc_size = ring->size;
 	ring->desc_cpu = p;
 	ring->desc_count = ring->size;
@@ -1275,7 +1285,7 @@
 	napi_disable(&ring->napi);
 	netif_napi_del(&ring->napi);
 
-	bcm_sysport_tx_reclaim(priv, ring);
+	bcm_sysport_tx_clean(priv, ring);
 
 	kfree(ring->cbs);
 	ring->cbs = NULL;
@@ -1603,6 +1613,7 @@
 	}
 
 	/* Initialize both hardware and software ring */
+	spin_lock_init(&priv->desc_lock);
 	for (i = 0; i < dev->num_tx_queues; i++) {
 		ret = bcm_sysport_init_tx_ring(priv, i);
 		if (ret) {
@@ -1790,7 +1801,7 @@
 
 	priv->phy_interface = of_get_phy_mode(dn);
 	/* Default to GMII interface mode */
-	if (priv->phy_interface < 0)
+	if ((int)priv->phy_interface < 0)
 		priv->phy_interface = PHY_INTERFACE_MODE_GMII;
 
 	/* In the case of a fixed PHY, the DT node associated
@@ -1879,12 +1890,17 @@
 	unsigned int timeout = 1000;
 	u32 reg;
 
-	/* Password has already been programmed */
 	reg = umac_readl(priv, UMAC_MPD_CTRL);
 	reg |= MPD_EN;
 	reg &= ~PSW_EN;
-	if (priv->wolopts & WAKE_MAGICSECURE)
+	if (priv->wolopts & WAKE_MAGICSECURE) {
+		/* Program the SecureOn password */
+		umac_writel(priv, get_unaligned_be16(&priv->sopass[0]),
+			    UMAC_PSW_MS);
+		umac_writel(priv, get_unaligned_be32(&priv->sopass[2]),
+			    UMAC_PSW_LS);
 		reg |= PSW_EN;
+	}
 	umac_writel(priv, reg, UMAC_MPD_CTRL);
 
 	/* Make sure RBUF entered WoL mode as result */
@@ -1908,9 +1924,6 @@
 	/* UniMAC receive needs to be turned on */
 	umac_enable_set(priv, CMD_RX_EN, 1);
 
-	/* Enable the interrupt wake-up source */
-	intrl2_0_mask_clear(priv, INTRL2_0_MPD);
-
 	netif_dbg(priv, wol, ndev, "entered WOL mode\n");
 
 	return 0;
@@ -1991,6 +2004,9 @@
 
 	umac_reset(priv);
 
+	/* Disable the UniMAC RX/TX */
+	umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0);
+
 	/* We may have been suspended and never received a WOL event that
 	 * would turn off MPD detection, take care of that now
 	 */
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bcmsysport.h
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -11,6 +11,7 @@
 #ifndef __BCM_SYSPORT_H
 #define __BCM_SYSPORT_H
 
+#include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 
 /* Receive/transmit descriptor format */
@@ -638,7 +639,7 @@
 	unsigned int	desc_count;	/* Number of descriptors */
 	unsigned int	curr_desc;	/* Current descriptor */
 	unsigned int	c_index;	/* Last consumer index */
-	unsigned int	p_index;	/* Current producer index */
+	unsigned int	clean_index;	/* Current clean index */
 	struct bcm_sysport_cb *cbs;	/* Transmit control blocks */
 	struct dma_desc	*desc_cpu;	/* CPU view of the descriptor */
 	struct bcm_sysport_priv *priv;	/* private context backpointer */
@@ -659,6 +660,7 @@
 	int			wol_irq;
 
 	/* Transmit rings */
+	spinlock_t		desc_lock;
 	struct bcm_sysport_tx_ring tx_rings[TDMA_NUM_RINGS];
 
 	/* Receive queue */
@@ -682,6 +684,7 @@
 	unsigned int		crc_fwd:1;
 	u16			rev;
 	u32			wolopts;
+	u8			sopass[SOPASS_MAX];
 	unsigned int		wol_irq_disabled:1;
 
 	/* MIB related fields */
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bgmac.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bgmac.c
@@ -219,7 +219,7 @@
 	dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb),
 			 DMA_TO_DEVICE);
 
-	while (i > 0) {
+	while (i-- > 0) {
 		int index = (ring->end + i) % BGMAC_TX_RING_SLOTS;
 		struct bgmac_slot_info *slot = &ring->slots[index];
 		u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1);
@@ -255,15 +255,16 @@
 	while (ring->start != ring->end) {
 		int slot_idx = ring->start % BGMAC_TX_RING_SLOTS;
 		struct bgmac_slot_info *slot = &ring->slots[slot_idx];
-		u32 ctl1;
+		u32 ctl0, ctl1;
 		int len;
 
 		if (slot_idx == empty_slot)
 			break;
 
+		ctl0 = le32_to_cpu(ring->cpu_base[slot_idx].ctl0);
 		ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1);
 		len = ctl1 & BGMAC_DESC_CTL1_LEN;
-		if (ctl1 & BGMAC_DESC_CTL0_SOF)
+		if (ctl0 & BGMAC_DESC_CTL0_SOF)
 			/* Unmap no longer used buffer */
 			dma_unmap_single(dma_dev, slot->dma_addr, len,
 					 DMA_TO_DEVICE);
@@ -314,6 +315,10 @@
 	u32 ctl;
 
 	ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL);
+
+	/* preserve ONLY bits 16-17 from current hardware value */
+	ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
+
 	if (bgmac->core->id.rev >= 4) {
 		ctl &= ~BGMAC_DMA_RX_BL_MASK;
 		ctl |= BGMAC_DMA_RX_BL_128 << BGMAC_DMA_RX_BL_SHIFT;
@@ -324,7 +329,6 @@
 		ctl &= ~BGMAC_DMA_RX_PT_MASK;
 		ctl |= BGMAC_DMA_RX_PT_1 << BGMAC_DMA_RX_PT_SHIFT;
 	}
-	ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
 	ctl |= BGMAC_DMA_RX_ENABLE;
 	ctl |= BGMAC_DMA_RX_PARITY_DISABLE;
 	ctl |= BGMAC_DMA_RX_OVERFLOW_CONT;
@@ -466,6 +470,11 @@
 			len -= ETH_FCS_LEN;
 
 			skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
+			if (unlikely(!skb)) {
+				bgmac_err(bgmac, "build_skb failed\n");
+				put_page(virt_to_head_page(buf));
+				break;
+			}
 			skb_put(skb, BGMAC_RX_FRAME_OFFSET +
 				BGMAC_RX_BUF_OFFSET + len);
 			skb_pull(skb, BGMAC_RX_FRAME_OFFSET +
@@ -522,7 +531,8 @@
 	int i;
 
 	for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) {
-		int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN;
+		u32 ctl1 = le32_to_cpu(dma_desc[i].ctl1);
+		unsigned int len = ctl1 & BGMAC_DESC_CTL1_LEN;
 
 		slot = &ring->slots[i];
 		dev_kfree_skb(slot->skb);
@@ -1299,7 +1309,8 @@
 
 	phy_start(bgmac->phy_dev);
 
-	netif_carrier_on(net_dev);
+	netif_start_queue(net_dev);
+
 	return 0;
 }
 
@@ -1573,6 +1584,11 @@
 		dev_warn(&core->dev, "Using random MAC: %pM\n", mac);
 	}
 
+	/* This (reset &) enable is not preset in specs or reference driver but
+	 * Broadcom does it in arch PCI code when enabling fake PCI device.
+	 */
+	bcma_core_enable(core, 0);
+
 	/* Allocation and references */
 	net_dev = alloc_etherdev(sizeof(*bgmac));
 	if (!net_dev)
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1634,6 +1634,7 @@
 	struct link_vars	link_vars;
 	u32			link_cnt;
 	struct bnx2x_link_report_data last_reported_link;
+	bool			force_link_down;
 
 	struct mdio_if_info	mdio;
 
@@ -2290,6 +2291,13 @@
 #define PMF_DMAE_C(bp)			(BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
 					 E1HVN_MAX)
 
+/* Following is the DMAE channel number allocation for the clients.
+ *   MFW: OCBB/OCSD implementations use DMAE channels 14/15 respectively.
+ *   Driver: 0-3 and 8-11 (for PF dmae operations)
+ *           4 and 12 (for stats requests)
+ */
+#define BNX2X_FW_DMAE_C                 13 /* Channel for FW DMAE operations */
+
 /* PCIE link and speed */
 #define PCICFG_LINK_WIDTH		0x1f00000
 #define PCICFG_LINK_WIDTH_SHIFT		20
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -288,6 +288,9 @@
 	hw_cons = le16_to_cpu(*txdata->tx_cons_sb);
 	sw_cons = txdata->tx_pkt_cons;
 
+	/* Ensure subsequent loads occur after hw_cons */
+	smp_rmb();
+
 	while (sw_cons != hw_cons) {
 		u16 pkt_cons;
 
@@ -1277,6 +1280,11 @@
 {
 	struct bnx2x_link_report_data cur_data;
 
+	if (bp->force_link_down) {
+		bp->link_vars.link_up = 0;
+		return;
+	}
+
 	/* reread mf_cfg */
 	if (IS_PF(bp) && !CHIP_IS_E1(bp))
 		bnx2x_read_mf_cfg(bp);
@@ -1949,7 +1957,7 @@
 	}
 
 	/* select a non-FCoE queue */
-	return fallback(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
+	return fallback(dev, skb) % (BNX2X_NUM_ETH_QUEUES(bp));
 }
 
 void bnx2x_set_num_queues(struct bnx2x *bp)
@@ -2044,6 +2052,7 @@
 				  ETH_OVREHEAD +
 				  mtu +
 				  BNX2X_FW_RX_ALIGN_END;
+		fp->rx_buf_size = SKB_DATA_ALIGN(fp->rx_buf_size);
 		/* Note : rx_buf_size doesn't take into account NET_SKB_PAD */
 		if (fp->rx_buf_size + NET_SKB_PAD <= PAGE_SIZE)
 			fp->rx_frag_size = fp->rx_buf_size + NET_SKB_PAD;
@@ -2839,6 +2848,7 @@
 		bp->pending_max = 0;
 	}
 
+	bp->force_link_down = false;
 	if (bp->port.pmf) {
 		rc = bnx2x_initial_phy_init(bp, load_mode);
 		if (rc)
@@ -3052,7 +3062,7 @@
 
 	del_timer_sync(&bp->timer);
 
-	if (IS_PF(bp)) {
+	if (IS_PF(bp) && !BP_NOMCP(bp)) {
 		/* Set ALWAYS_ALIVE bit in shmem */
 		bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
 		bnx2x_drv_pulse(bp);
@@ -3134,7 +3144,7 @@
 	bp->cnic_loaded = false;
 
 	/* Clear driver version indication in shmem */
-	if (IS_PF(bp))
+	if (IS_PF(bp) && !BP_NOMCP(bp))
 		bnx2x_update_mng_version(bp);
 
 	/* Check if there are pending parity attentions. If there are - set
@@ -3909,9 +3919,11 @@
 
 	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
 		if (!(bp->flags & TX_TIMESTAMPING_EN)) {
+			bp->eth_stats.ptp_skip_tx_ts++;
 			BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n");
 		} else if (bp->ptp_tx_skb) {
-			BNX2X_ERR("The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+			bp->eth_stats.ptp_skip_tx_ts++;
+			pr_err_once("[%s] Device supports only a single outstanding packet to timestamp, this packet won't be timestamped\n", netdev_name(bp->dev));
 		} else {
 			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 			/* schedule check for Tx timestamp */
@@ -3942,15 +3954,26 @@
 		/* when transmitting in a vf, start bd must hold the ethertype
 		 * for fw to enforce it
 		 */
+		u16 vlan_tci = 0;
 #ifndef BNX2X_STOP_ON_ERROR
-		if (IS_VF(bp))
+		if (IS_VF(bp)) {
 #endif
-			tx_start_bd->vlan_or_ethertype =
-				cpu_to_le16(ntohs(eth->h_proto));
+			/* Still need to consider inband vlan for enforced */
+			if (__vlan_get_tag(skb, &vlan_tci)) {
+				tx_start_bd->vlan_or_ethertype =
+					cpu_to_le16(ntohs(eth->h_proto));
+			} else {
+				tx_start_bd->bd_flags.as_bitfield |=
+					(X_ETH_INBAND_VLAN <<
+					 ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
+				tx_start_bd->vlan_or_ethertype =
+					cpu_to_le16(vlan_tci);
+			}
 #ifndef BNX2X_STOP_ON_ERROR
-		else
+		} else {
 			/* used by FW for packet accounting */
 			tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+		}
 #endif
 	}
 
@@ -4332,6 +4355,14 @@
 	return 0;
 }
 
+int __bnx2x_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+		     struct tc_to_netdev *tc)
+{
+	if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+	return bnx2x_setup_tc(dev, tc->tc);
+}
+
 /* called with rtnl_lock */
 int bnx2x_change_mac_addr(struct net_device *dev, void *p)
 {
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -486,6 +486,8 @@
 
 /* setup_tc callback */
 int bnx2x_setup_tc(struct net_device *dev, u8 num_tc);
+int __bnx2x_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+		     struct tc_to_netdev *tc);
 
 int bnx2x_get_vf_config(struct net_device *dev, int vf,
 			struct ifla_vf_info *ivi);
@@ -1107,7 +1109,7 @@
 		for (i = 0; i < E1H_FUNC_MAX / 2; i++) {
 			u32 func_config =
 				MF_CFG_RD(bp,
-					  func_mf_config[BP_PORT(bp) + 2 * i].
+					  func_mf_config[BP_PATH(bp) + 2 * i].
 					  config);
 			func_num +=
 				((func_config & FUNC_MF_CFG_FUNC_HIDE) ? 0 : 1);
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -184,7 +184,9 @@
 	{ STATS_OFFSET32(driver_filtered_tx_pkt),
 			4, STATS_FLAGS_FUNC, "driver_filtered_tx_pkt" },
 	{ STATS_OFFSET32(eee_tx_lpi),
-			4, STATS_FLAGS_PORT, "Tx LPI entry count"}
+			4, STATS_FLAGS_PORT, "Tx LPI entry count"},
+	{ STATS_OFFSET32(ptp_skip_tx_ts),
+			4, STATS_FLAGS_FUNC, "ptp_skipped_tx_tstamp" },
 };
 
 #define BNX2X_NUM_STATS		ARRAY_SIZE(bnx2x_stats_arr)
@@ -1559,7 +1561,8 @@
 	}
 
 	if (!sff8472_comp ||
-	    (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ)) {
+	    (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ) ||
+	    !(diag_type & SFP_EEPROM_DDM_IMPLEMENTED)) {
 		modinfo->type = ETH_MODULE_SFF_8079;
 		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
 	} else {
@@ -3360,14 +3363,18 @@
 			DP(BNX2X_MSG_ETHTOOL,
 			   "rss re-configured, UDP 4-tupple %s\n",
 			   udp_rss_requested ? "enabled" : "disabled");
-			return bnx2x_rss(bp, &bp->rss_conf_obj, false, true);
+			if (bp->state == BNX2X_STATE_OPEN)
+				return bnx2x_rss(bp, &bp->rss_conf_obj, false,
+						 true);
 		} 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;
 			DP(BNX2X_MSG_ETHTOOL,
 			   "rss re-configured, UDP 4-tupple %s\n",
 			   udp_rss_requested ? "enabled" : "disabled");
-			return bnx2x_rss(bp, &bp->rss_conf_obj, false, true);
+			if (bp->state == BNX2X_STATE_OPEN)
+				return bnx2x_rss(bp, &bp->rss_conf_obj, false,
+						 true);
 		}
 		return 0;
 
@@ -3481,7 +3488,10 @@
 		bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id;
 	}
 
-	return bnx2x_config_rss_eth(bp, false);
+	if (bp->state == BNX2X_STATE_OPEN)
+		return bnx2x_config_rss_eth(bp, false);
+
+	return 0;
 }
 
 /**
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -594,7 +594,7 @@
 	 * slots for the highest priority.
 	 */
 	REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS :
-		   NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
+		   NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
 	/* Mapping between the CREDIT_WEIGHT registers and actual client
 	 * numbers
 	 */
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -62,6 +62,7 @@
 #define SFP_EEPROM_DIAG_TYPE_ADDR		0x5c
 #define SFP_EEPROM_DIAG_TYPE_SIZE		1
 #define SFP_EEPROM_DIAG_ADDR_CHANGE_REQ		(1<<2)
+#define SFP_EEPROM_DDM_IMPLEMENTED		(1<<6)
 #define SFP_EEPROM_SFF_8472_COMP_ADDR		0x5e
 #define SFP_EEPROM_SFF_8472_COMP_SIZE		1
 
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -3532,6 +3532,16 @@
  */
 static void bnx2x_config_mf_bw(struct bnx2x *bp)
 {
+	/* Workaround for MFW bug.
+	 * MFW is not supposed to generate BW attention in
+	 * single function mode.
+	 */
+	if (!IS_MF(bp)) {
+		DP(BNX2X_MSG_MCP,
+		   "Ignoring MF BW config in single function mode\n");
+		return;
+	}
+
 	if (bp->link_vars.link_up) {
 		bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX);
 		bnx2x_link_sync_notify(bp);
@@ -9570,6 +9580,15 @@
 
 	do {
 		bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+
+		/* If we read all 0xFFs, means we are in PCI error state and
+		 * should bail out to avoid crashes on adapter's FW reads.
+		 */
+		if (bp->common.shmem_base == 0xFFFFFFFF) {
+			bp->flags |= NO_MCP_FLAG;
+			return -ENODEV;
+		}
+
 		if (bp->common.shmem_base) {
 			val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
 			if (val & SHR_MEM_VALIDITY_MB)
@@ -9923,10 +9942,18 @@
  */
 static void bnx2x_parity_recover(struct bnx2x *bp)
 {
-	bool global = false;
 	u32 error_recovered, error_unrecovered;
-	bool is_parity;
+	bool is_parity, global = false;
+#ifdef CONFIG_BNX2X_SRIOV
+	int vf_idx;
 
+	for (vf_idx = 0; vf_idx < bp->requested_nr_virtfn; vf_idx++) {
+		struct bnx2x_virtf *vf = BP_VF(bp, vf_idx);
+
+		if (vf)
+			vf->state = VF_LOST;
+	}
+#endif
 	DP(NETIF_MSG_HW, "Handling parity\n");
 	while (1) {
 		switch (bp->recovery_state) {
@@ -10213,6 +10240,12 @@
 		bp->sp_rtnl_state = 0;
 		smp_mb();
 
+		/* Immediately indicate link as down */
+		bp->link_vars.link_up = 0;
+		bp->force_link_down = true;
+		netif_carrier_off(bp->dev);
+		BNX2X_ERR("Indicating link is down due to Tx-timeout\n");
+
 		bnx2x_nic_unload(bp, UNLOAD_NORMAL, true);
 		bnx2x_nic_load(bp, LOAD_NORMAL);
 
@@ -12809,6 +12842,24 @@
 					      struct net_device *dev,
 					      netdev_features_t features)
 {
+	/*
+	 * A skb with gso_size + header length > 9700 will cause a
+	 * firmware panic. Drop GSO support.
+	 *
+	 * Eventually the upper layer should not pass these packets down.
+	 *
+	 * For speed, if the gso_size is <= 9000, assume there will
+	 * not be 700 bytes of headers and pass it through. Only do a
+	 * full (slow) validation if the gso_size is > 9000.
+	 *
+	 * (Due to the way SKB_BY_FRAGS works this will also do a full
+	 * validation in that case.)
+	 */
+	if (unlikely(skb_is_gso(skb) &&
+		     (skb_shinfo(skb)->gso_size > 9000) &&
+		     !skb_gso_validate_mac_len(skb, 9700)))
+		features &= ~NETIF_F_GSO_MASK;
+
 	features = vlan_features_check(skb, features);
 	return vxlan_features_check(skb, features);
 }
@@ -12830,52 +12881,71 @@
 	return rc;
 }
 
-int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp)
+static int bnx2x_vlan_configure_vid_list(struct bnx2x *bp)
 {
 	struct bnx2x_vlan_entry *vlan;
 	int rc = 0;
 
-	if (!bp->vlan_cnt) {
-		DP(NETIF_MSG_IFUP, "No need to re-configure vlan filters\n");
-		return 0;
-	}
-
+	/* Configure all non-configured entries */
 	list_for_each_entry(vlan, &bp->vlan_reg, link) {
-		/* Prepare for cleanup in case of errors */
-		if (rc) {
-			vlan->hw = false;
-			continue;
-		}
-
-		if (!vlan->hw)
+		if (vlan->hw)
 			continue;
 
-		DP(NETIF_MSG_IFUP, "Re-configuring vlan 0x%04x\n", vlan->vid);
+		if (bp->vlan_cnt >= bp->vlan_credit)
+			return -ENOBUFS;
 
 		rc = __bnx2x_vlan_configure_vid(bp, vlan->vid, true);
 		if (rc) {
-			BNX2X_ERR("Unable to configure VLAN %d\n", vlan->vid);
-			vlan->hw = false;
-			rc = -EINVAL;
-			continue;
+			BNX2X_ERR("Unable to config VLAN %d\n", vlan->vid);
+			return rc;
 		}
+
+		DP(NETIF_MSG_IFUP, "HW configured for VLAN %d\n", vlan->vid);
+		vlan->hw = true;
+		bp->vlan_cnt++;
 	}
 
-	return rc;
+	return 0;
+}
+
+static void bnx2x_vlan_configure(struct bnx2x *bp, bool set_rx_mode)
+{
+	bool need_accept_any_vlan;
+
+	need_accept_any_vlan = !!bnx2x_vlan_configure_vid_list(bp);
+
+	if (bp->accept_any_vlan != need_accept_any_vlan) {
+		bp->accept_any_vlan = need_accept_any_vlan;
+		DP(NETIF_MSG_IFUP, "Accept all VLAN %s\n",
+		   bp->accept_any_vlan ? "raised" : "cleared");
+		if (set_rx_mode) {
+			if (IS_PF(bp))
+				bnx2x_set_rx_mode_inner(bp);
+			else
+				bnx2x_vfpf_storm_rx_mode(bp);
+		}
+	}
+}
+
+int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp)
+{
+	struct bnx2x_vlan_entry *vlan;
+
+	/* The hw forgot all entries after reload */
+	list_for_each_entry(vlan, &bp->vlan_reg, link)
+		vlan->hw = false;
+	bp->vlan_cnt = 0;
+
+	/* Don't set rx mode here. Our caller will do it. */
+	bnx2x_vlan_configure(bp, false);
+
+	return 0;
 }
 
 static int bnx2x_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
 {
 	struct bnx2x *bp = netdev_priv(dev);
 	struct bnx2x_vlan_entry *vlan;
-	bool hw = false;
-	int rc = 0;
-
-	if (!netif_running(bp->dev)) {
-		DP(NETIF_MSG_IFUP,
-		   "Ignoring VLAN configuration the interface is down\n");
-		return -EFAULT;
-	}
 
 	DP(NETIF_MSG_IFUP, "Adding VLAN %d\n", vid);
 
@@ -12883,93 +12953,47 @@
 	if (!vlan)
 		return -ENOMEM;
 
-	bp->vlan_cnt++;
-	if (bp->vlan_cnt > bp->vlan_credit && !bp->accept_any_vlan) {
-		DP(NETIF_MSG_IFUP, "Accept all VLAN raised\n");
-		bp->accept_any_vlan = true;
-		if (IS_PF(bp))
-			bnx2x_set_rx_mode_inner(bp);
-		else
-			bnx2x_vfpf_storm_rx_mode(bp);
-	} else if (bp->vlan_cnt <= bp->vlan_credit) {
-		rc = __bnx2x_vlan_configure_vid(bp, vid, true);
-		hw = true;
-	}
-
 	vlan->vid = vid;
-	vlan->hw = hw;
+	vlan->hw = false;
+	list_add_tail(&vlan->link, &bp->vlan_reg);
 
-	if (!rc) {
-		list_add(&vlan->link, &bp->vlan_reg);
-	} else {
-		bp->vlan_cnt--;
-		kfree(vlan);
-	}
-
-	DP(NETIF_MSG_IFUP, "Adding VLAN result %d\n", rc);
+	if (netif_running(dev))
+		bnx2x_vlan_configure(bp, true);
 
-	return rc;
+	return 0;
 }
 
 static int bnx2x_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
 {
 	struct bnx2x *bp = netdev_priv(dev);
 	struct bnx2x_vlan_entry *vlan;
+	bool found = false;
 	int rc = 0;
 
-	if (!netif_running(bp->dev)) {
-		DP(NETIF_MSG_IFUP,
-		   "Ignoring VLAN configuration the interface is down\n");
-		return -EFAULT;
-	}
-
 	DP(NETIF_MSG_IFUP, "Removing VLAN %d\n", vid);
 
-	if (!bp->vlan_cnt) {
-		BNX2X_ERR("Unable to kill VLAN %d\n", vid);
-		return -EINVAL;
-	}
-
 	list_for_each_entry(vlan, &bp->vlan_reg, link)
-		if (vlan->vid == vid)
+		if (vlan->vid == vid) {
+			found = true;
 			break;
+		}
 
-	if (vlan->vid != vid) {
+	if (!found) {
 		BNX2X_ERR("Unable to kill VLAN %d - not found\n", vid);
 		return -EINVAL;
 	}
 
-	if (vlan->hw)
+	if (netif_running(dev) && vlan->hw) {
 		rc = __bnx2x_vlan_configure_vid(bp, vid, false);
+		DP(NETIF_MSG_IFUP, "HW deconfigured for VLAN %d\n", vid);
+		bp->vlan_cnt--;
+	}
 
 	list_del(&vlan->link);
 	kfree(vlan);
 
-	bp->vlan_cnt--;
-
-	if (bp->vlan_cnt <= bp->vlan_credit && bp->accept_any_vlan) {
-		/* Configure all non-configured entries */
-		list_for_each_entry(vlan, &bp->vlan_reg, link) {
-			if (vlan->hw)
-				continue;
-
-			rc = __bnx2x_vlan_configure_vid(bp, vlan->vid, true);
-			if (rc) {
-				BNX2X_ERR("Unable to config VLAN %d\n",
-					  vlan->vid);
-				continue;
-			}
-			DP(NETIF_MSG_IFUP, "HW configured for VLAN %d\n",
-			   vlan->vid);
-			vlan->hw = true;
-		}
-		DP(NETIF_MSG_IFUP, "Accept all VLAN Removed\n");
-		bp->accept_any_vlan = false;
-		if (IS_PF(bp))
-			bnx2x_set_rx_mode_inner(bp);
-		else
-			bnx2x_vfpf_storm_rx_mode(bp);
-	}
+	if (netif_running(dev))
+		bnx2x_vlan_configure(bp, true);
 
 	DP(NETIF_MSG_IFUP, "Removing VLAN result %d\n", rc);
 
@@ -12994,7 +13018,7 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= poll_bnx2x,
 #endif
-	.ndo_setup_tc		= bnx2x_setup_tc,
+	.ndo_setup_tc		= __bnx2x_setup_tc,
 #ifdef CONFIG_BNX2X_SRIOV
 	.ndo_set_vf_mac		= bnx2x_set_vf_mac,
 	.ndo_set_vf_vlan	= bnx2x_set_vf_vlan,
@@ -13646,7 +13670,7 @@
 	if (!netif_running(bp->dev)) {
 		DP(BNX2X_MSG_PTP,
 		   "PTP adjfreq called while the interface is down\n");
-		return -EFAULT;
+		return -ENETDOWN;
 	}
 
 	if (ppb < 0) {
@@ -13705,6 +13729,12 @@
 {
 	struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
 
+	if (!netif_running(bp->dev)) {
+		DP(BNX2X_MSG_PTP,
+		   "PTP adjtime called while the interface is down\n");
+		return -ENETDOWN;
+	}
+
 	DP(BNX2X_MSG_PTP, "PTP adjtime called, delta = %llx\n", delta);
 
 	timecounter_adjtime(&bp->timecounter, delta);
@@ -13717,6 +13747,12 @@
 	struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
 	u64 ns;
 
+	if (!netif_running(bp->dev)) {
+		DP(BNX2X_MSG_PTP,
+		   "PTP gettime called while the interface is down\n");
+		return -ENETDOWN;
+	}
+
 	ns = timecounter_read(&bp->timecounter);
 
 	DP(BNX2X_MSG_PTP, "PTP gettime called, ns = %llu\n", ns);
@@ -13732,6 +13768,12 @@
 	struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
 	u64 ns;
 
+	if (!netif_running(bp->dev)) {
+		DP(BNX2X_MSG_PTP,
+		   "PTP settime called while the interface is down\n");
+		return -ENETDOWN;
+	}
+
 	ns = timespec64_to_ns(ts);
 
 	DP(BNX2X_MSG_PTP, "PTP settime called, ns = %llu\n", ns);
@@ -14196,7 +14238,10 @@
 		BNX2X_ERR("IO slot reset --> driver unload\n");
 
 		/* MCP should have been reset; Need to wait for validity */
-		bnx2x_init_shmem(bp);
+		if (bnx2x_init_shmem(bp)) {
+			rtnl_unlock();
+			return PCI_ERS_RESULT_DISCONNECT;
+		}
 
 		if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
 			u32 v;
@@ -14819,6 +14864,10 @@
 	}
 
 	offset = SHMEM2_RD(bp, fc_npiv_nvram_tbl_addr[BP_PORT(bp)]);
+	if (!offset) {
+		DP(BNX2X_MSG_MCP, "No FC-NPIV in NVRAM\n");
+		goto out;
+	}
 	DP(BNX2X_MSG_MCP, "Offset of FC-NPIV in NVRAM: %08x\n", offset);
 
 	/* Read the table contents from nvram */
@@ -15069,11 +15118,24 @@
 	u32 val_seq;
 	u64 timestamp, ns;
 	struct skb_shared_hwtstamps shhwtstamps;
+	bool bail = true;
+	int i;
+
+	/* FW may take a while to complete timestamping; try a bit and if it's
+	 * still not complete, may indicate an error state - bail out then.
+	 */
+	for (i = 0; i < 10; i++) {
+		/* Read Tx timestamp registers */
+		val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+				 NIG_REG_P0_TLLH_PTP_BUF_SEQID);
+		if (val_seq & 0x10000) {
+			bail = false;
+			break;
+		}
+		msleep(1 << i);
+	}
 
-	/* Read Tx timestamp registers */
-	val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
-			 NIG_REG_P0_TLLH_PTP_BUF_SEQID);
-	if (val_seq & 0x10000) {
+	if (!bail) {
 		/* There is a valid timestamp value */
 		timestamp = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_TS_MSB :
 				   NIG_REG_P0_TLLH_PTP_BUF_TS_MSB);
@@ -15088,16 +15150,18 @@
 		memset(&shhwtstamps, 0, sizeof(shhwtstamps));
 		shhwtstamps.hwtstamp = ns_to_ktime(ns);
 		skb_tstamp_tx(bp->ptp_tx_skb, &shhwtstamps);
-		dev_kfree_skb_any(bp->ptp_tx_skb);
-		bp->ptp_tx_skb = NULL;
 
 		DP(BNX2X_MSG_PTP, "Tx timestamp, timestamp cycles = %llu, ns = %llu\n",
 		   timestamp, ns);
 	} else {
-		DP(BNX2X_MSG_PTP, "There is no valid Tx timestamp yet\n");
-		/* Reschedule to keep checking for a valid timestamp value */
-		schedule_work(&bp->ptp_task);
+		DP(BNX2X_MSG_PTP,
+		   "Tx timestamp is not recorded (register read=%u)\n",
+		   val_seq);
+		bp->eth_stats.ptp_skip_tx_ts++;
 	}
+
+	dev_kfree_skb_any(bp->ptp_tx_skb);
+	bp->ptp_tx_skb = NULL;
 }
 
 void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb)
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -5931,6 +5931,7 @@
 	rdata->sd_vlan_tag	= cpu_to_le16(start_params->sd_vlan_tag);
 	rdata->path_id		= BP_PATH(bp);
 	rdata->network_cos_mode	= start_params->network_cos_mode;
+	rdata->dmae_cmd_id	= BNX2X_FW_DMAE_C;
 
 	rdata->vxlan_dst_port	= cpu_to_le16(start_params->vxlan_dst_port);
 	rdata->geneve_dst_port	= cpu_to_le16(start_params->geneve_dst_port);
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -434,7 +434,9 @@
 
 	/* Add/Remove the filter */
 	rc = bnx2x_config_vlan_mac(bp, &ramrod);
-	if (rc && rc != -EEXIST) {
+	if (rc == -EEXIST)
+		return 0;
+	if (rc) {
 		BNX2X_ERR("Failed to %s %s\n",
 			  filter->add ? "add" : "delete",
 			  (filter->type == BNX2X_VF_FILTER_VLAN_MAC) ?
@@ -444,6 +446,8 @@
 		return rc;
 	}
 
+	filter->applied = true;
+
 	return 0;
 }
 
@@ -471,6 +475,8 @@
 		BNX2X_ERR("Managed only %d/%d filters - rolling back\n",
 			  i, filters->count + 1);
 		while (--i >= 0) {
+			if (!filters->filters[i].applied)
+				continue;
 			filters->filters[i].add = !filters->filters[i].add;
 			bnx2x_vf_mac_vlan_config(bp, vf, qid,
 						 &filters->filters[i],
@@ -2378,15 +2384,21 @@
 	/* send the ramrod on all the queues of the PF */
 	for_each_eth_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
+		int tx_idx;
 
 		/* Set the appropriate Queue object */
 		q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
 
-		/* Update the Queue state */
-		rc = bnx2x_queue_state_change(bp, &q_params);
-		if (rc) {
-			BNX2X_ERR("Failed to configure Tx switching\n");
-			return rc;
+		for (tx_idx = FIRST_TX_COS_INDEX;
+		     tx_idx < fp->max_cos; tx_idx++) {
+			q_params.params.update.cid_index = tx_idx;
+
+			/* Update the Queue state */
+			rc = bnx2x_queue_state_change(bp, &q_params);
+			if (rc) {
+				BNX2X_ERR("Failed to configure Tx switching\n");
+				return rc;
+			}
 		}
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -114,6 +114,7 @@
 	(BNX2X_VF_FILTER_MAC | BNX2X_VF_FILTER_VLAN) /*shortcut*/
 
 	bool add;
+	bool applied;
 	u8 *mac;
 	u16 vid;
 };
@@ -138,6 +139,7 @@
 #define VF_ACQUIRED	1	/* VF acquired, but not initialized */
 #define VF_ENABLED	2	/* VF Enabled */
 #define VF_RESET	3	/* VF FLR'd, pending cleanup */
+#define VF_LOST		4	/* Recovery while VFs are loaded */
 
 	bool flr_clnup_stage;	/* true during flr cleanup */
 
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -207,6 +207,9 @@
 	u32 driver_filtered_tx_pkt;
 	/* src: Clear-on-Read register; Will not survive PMF Migration */
 	u32 eee_tx_lpi;
+
+	/* PTP */
+	u32 ptp_skip_tx_ts;
 };
 
 struct bnx2x_eth_q_stats {
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -868,7 +868,7 @@
 	struct bnx2x *bp = netdev_priv(dev);
 	struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
 	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
-	int rc, i = 0;
+	int rc = 0, i = 0;
 	struct netdev_hw_addr *ha;
 
 	if (bp->state != BNX2X_STATE_OPEN) {
@@ -883,6 +883,15 @@
 	/* Get Rx mode requested */
 	DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags);
 
+	/* We support PFVF_MAX_MULTICAST_PER_VF mcast addresses tops */
+	if (netdev_mc_count(dev) > PFVF_MAX_MULTICAST_PER_VF) {
+		DP(NETIF_MSG_IFUP,
+		   "VF supports not more than %d multicast MAC addresses\n",
+		   PFVF_MAX_MULTICAST_PER_VF);
+		rc = -EINVAL;
+		goto out;
+	}
+
 	netdev_for_each_mc_addr(ha, dev) {
 		DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
 		   bnx2x_mc_addr(ha));
@@ -890,16 +899,6 @@
 		i++;
 	}
 
-	/* We support four PFVF_MAX_MULTICAST_PER_VF mcast
-	  * addresses tops
-	  */
-	if (i >= PFVF_MAX_MULTICAST_PER_VF) {
-		DP(NETIF_MSG_IFUP,
-		   "VF supports not more than %d multicast MAC addresses\n",
-		   PFVF_MAX_MULTICAST_PER_VF);
-		return -EINVAL;
-	}
-
 	req->n_multicast = i;
 	req->flags |= VFPF_SET_Q_FILTERS_MULTICAST_CHANGED;
 	req->vf_qid = 0;
@@ -924,7 +923,7 @@
 out:
 	bnx2x_vfpf_finalize(bp, &req->first_tlv);
 
-	return 0;
+	return rc;
 }
 
 /* request pf to add a vlan for the vf */
@@ -2096,6 +2095,18 @@
 {
 	int i;
 
+	if (vf->state == VF_LOST) {
+		/* Just ack the FW and return if VFs are lost
+		 * in case of parity error. VFs are supposed to be timedout
+		 * on waiting for PF response.
+		 */
+		DP(BNX2X_MSG_IOV,
+		   "VF 0x%x lost, not handling the request\n", vf->abs_vfid);
+
+		storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
+		return;
+	}
+
 	/* check if tlv type is known */
 	if (bnx2x_tlv_supported(mbx->first_tlv.tl.type)) {
 		/* Lock the per vf op mutex and note the locker's identity.
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -330,6 +330,12 @@
 	}
 
 	length >>= 9;
+	if (unlikely(length >= ARRAY_SIZE(bnxt_lhint_arr))) {
+		dev_warn_ratelimited(&pdev->dev, "Dropped oversize %d bytes TX packet.\n",
+				     skb->len);
+		i = 0;
+		goto tx_dma_error;
+	}
 	flags |= bnxt_lhint_arr[length];
 	txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
 
@@ -1134,6 +1140,8 @@
 		skb = bnxt_copy_skb(bnapi, data, len, dma_addr);
 		bnxt_reuse_rx_data(rxr, cons, data);
 		if (!skb) {
+			if (agg_bufs)
+				bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs);
 			rc = -ENOMEM;
 			goto next_rx;
 		}
@@ -1343,8 +1351,11 @@
 		if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) {
 			tx_pkts++;
 			/* return full budget so NAPI will complete. */
-			if (unlikely(tx_pkts > bp->tx_wake_thresh))
+			if (unlikely(tx_pkts > bp->tx_wake_thresh)) {
 				rx_pkts = budget;
+				raw_cons = NEXT_RAW_CMP(raw_cons);
+				break;
+			}
 		} else if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) {
 			rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &agg_event);
 			if (likely(rc >= 0))
@@ -1362,7 +1373,7 @@
 		}
 		raw_cons = NEXT_RAW_CMP(raw_cons);
 
-		if (rx_pkts == budget)
+		if (rx_pkts && rx_pkts == budget)
 			break;
 	}
 
@@ -1404,8 +1415,12 @@
 	while (1) {
 		work_done += bnxt_poll_work(bp, bnapi, budget - work_done);
 
-		if (work_done >= budget)
+		if (work_done >= budget) {
+			if (!budget)
+				BNXT_CP_DB_REARM(cpr->cp_doorbell,
+						 cpr->cp_raw_cons);
 			break;
+		}
 
 		if (!bnxt_has_work(bp, cpr)) {
 			napi_complete(napi);
@@ -2014,6 +2029,18 @@
 	return 0;
 }
 
+static void bnxt_init_cp_rings(struct bnxt *bp)
+{
+	int i;
+
+	for (i = 0; i < bp->cp_nr_rings; i++) {
+		struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring;
+		struct bnxt_ring_struct *ring = &cpr->cp_ring_struct;
+
+		ring->fw_ring_id = INVALID_HW_RING_ID;
+	}
+}
+
 static int bnxt_init_rx_rings(struct bnxt *bp)
 {
 	int i, rc = 0;
@@ -2473,7 +2500,8 @@
 		INIT_HLIST_HEAD(&bp->ntp_fltr_hash_tbl[i]);
 
 	bp->ntp_fltr_count = 0;
-	bp->ntp_fltr_bmap = kzalloc(BITS_TO_LONGS(BNXT_NTP_FLTR_MAX_FLTR),
+	bp->ntp_fltr_bmap = kcalloc(BITS_TO_LONGS(BNXT_NTP_FLTR_MAX_FLTR),
+				    sizeof(long),
 				    GFP_KERNEL);
 
 	if (!bp->ntp_fltr_bmap)
@@ -2912,6 +2940,9 @@
 	struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
 	struct hwrm_vnic_tpa_cfg_input req = {0};
 
+	if (vnic->fw_vnic_id == INVALID_HW_RING_ID)
+		return 0;
+
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_TPA_CFG, -1, -1);
 
 	if (tpa_flags) {
@@ -3976,6 +4007,7 @@
 
 static int bnxt_init_nic(struct bnxt *bp, bool irq_re_init)
 {
+	bnxt_init_cp_rings(bp);
 	bnxt_init_rx_rings(bp);
 	bnxt_init_tx_rings(bp);
 	bnxt_init_ring_grps(bp, irq_re_init);
@@ -4218,6 +4250,10 @@
 		napi_hash_del(&bnapi->napi);
 		netif_napi_del(&bnapi->napi);
 	}
+	/* We called napi_hash_del() before netif_napi_del(), we need
+	 * to respect an RCU grace period before freeing napi structures.
+	 */
+	synchronize_net();
 }
 
 static void bnxt_init_napi(struct bnxt *bp)
@@ -4274,14 +4310,13 @@
 			bnapi = bp->bnapi[i];
 			txr = &bnapi->tx_ring;
 			txq = netdev_get_tx_queue(bp->dev, i);
-			__netif_tx_lock(txq, smp_processor_id());
 			txr->dev_state = BNXT_DEV_STATE_CLOSING;
-			__netif_tx_unlock(txq);
 		}
 	}
+	/* Drop carrier first to prevent TX timeout */
+	netif_carrier_off(bp->dev);
 	/* Stop all TX queues */
 	netif_tx_disable(bp->dev);
-	netif_carrier_off(bp->dev);
 }
 
 static void bnxt_tx_enable(struct bnxt *bp)
@@ -4574,22 +4609,22 @@
 		rc = bnxt_request_irq(bp);
 		if (rc) {
 			netdev_err(bp->dev, "bnxt_request_irq err: %x\n", rc);
-			goto open_err;
+			goto open_err_irq;
 		}
 	}
 
-	bnxt_enable_napi(bp);
-
 	rc = bnxt_init_nic(bp, irq_re_init);
 	if (rc) {
 		netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
-		goto open_err;
+		goto open_err_irq;
 	}
 
+	bnxt_enable_napi(bp);
+
 	if (link_re_init) {
 		rc = bnxt_update_phy_setting(bp);
 		if (rc)
-			goto open_err;
+			netdev_warn(bp->dev, "failed to update phy settings\n");
 	}
 
 	if (irq_re_init) {
@@ -4610,8 +4645,7 @@
 
 	return 0;
 
-open_err:
-	bnxt_disable_napi(bp);
+open_err_irq:
 	bnxt_del_napi(bp);
 
 open_err_free_mem:
@@ -4925,8 +4959,15 @@
 
 skip_uc:
 	rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0);
+	if (rc && vnic->mc_list_count) {
+		netdev_info(bp->dev, "Failed setting MC filters rc: %d, turning on ALL_MCAST mode\n",
+			    rc);
+		vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST;
+		vnic->mc_list_count = 0;
+		rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0);
+	}
 	if (rc)
-		netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n",
+		netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %d\n",
 			   rc);
 
 	return rc;
@@ -5158,7 +5199,8 @@
 	if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) != 0 &&
 	    dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
 		dev_err(&pdev->dev, "System does not support DMA, aborting\n");
-		goto init_err_disable;
+		rc = -EIO;
+		goto init_err_release;
 	}
 
 	pci_set_master(pdev);
@@ -5269,20 +5311,27 @@
 		return -EINVAL;
 
 	if (netif_running(dev))
-		bnxt_close_nic(bp, false, false);
+		bnxt_close_nic(bp, true, false);
 
 	dev->mtu = new_mtu;
 	bnxt_set_ring_params(bp);
 
 	if (netif_running(dev))
-		return bnxt_open_nic(bp, false, false);
+		return bnxt_open_nic(bp, true, false);
 
 	return 0;
 }
 
-static int bnxt_setup_tc(struct net_device *dev, u8 tc)
+static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+			 struct tc_to_netdev *ntc)
 {
 	struct bnxt *bp = netdev_priv(dev);
+	u8 tc;
+
+	if (handle != TC_H_ROOT || ntc->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+
+	tc = ntc->tc;
 
 	if (tc > bp->max_tc) {
 		netdev_err(dev, "too many traffic classes requested: %d Max supported is %d\n",
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -991,6 +991,9 @@
 	if (rc != 0)
 		return rc;
 
+	if (!dir_entries || !entry_length)
+		return -EIO;
+
 	/* Insert 2 bytes of directory info (count and size of entries) */
 	if (len < 2)
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
@@ -29,7 +29,7 @@
 		netdev_err(bp->dev, "vf ndo called though sriov is disabled\n");
 		return -EINVAL;
 	}
-	if (vf_id >= bp->pf.max_vfs) {
+	if (vf_id >= bp->pf.active_vfs) {
 		netdev_err(bp->dev, "Invalid VF id %d\n", vf_id);
 		return -EINVAL;
 	}
@@ -295,6 +295,7 @@
 		}
 	}
 
+	bp->pf.active_vfs = 0;
 	kfree(bp->pf.vf);
 	bp->pf.vf = NULL;
 }
@@ -535,7 +536,6 @@
 
 	bnxt_free_vf_resources(bp);
 
-	bp->pf.active_vfs = 0;
 	bp->pf.max_pf_rx_rings = bp->pf.max_rx_rings;
 	bp->pf.max_pf_tx_rings = bp->pf.max_tx_rings;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1,7 +1,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) controller driver
  *
- * Copyright (c) 2014 Broadcom Corporation
+ * Copyright (c) 2014-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -778,8 +778,9 @@
 	STAT_GENET_RUNT("rx_runt_bytes", mib.rx_runt_bytes),
 	/* Misc UniMAC counters */
 	STAT_GENET_MISC("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt,
-			UMAC_RBUF_OVFL_CNT),
-	STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT),
+			UMAC_RBUF_OVFL_CNT_V1),
+	STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt,
+			UMAC_RBUF_ERR_CNT_V1),
 	STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT),
 	STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
 	STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed),
@@ -821,6 +822,45 @@
 	}
 }
 
+static u32 bcmgenet_update_stat_misc(struct bcmgenet_priv *priv, u16 offset)
+{
+	u16 new_offset;
+	u32 val;
+
+	switch (offset) {
+	case UMAC_RBUF_OVFL_CNT_V1:
+		if (GENET_IS_V2(priv))
+			new_offset = RBUF_OVFL_CNT_V2;
+		else
+			new_offset = RBUF_OVFL_CNT_V3PLUS;
+
+		val = bcmgenet_rbuf_readl(priv,	new_offset);
+		/* clear if overflowed */
+		if (val == ~0)
+			bcmgenet_rbuf_writel(priv, 0, new_offset);
+		break;
+	case UMAC_RBUF_ERR_CNT_V1:
+		if (GENET_IS_V2(priv))
+			new_offset = RBUF_ERR_CNT_V2;
+		else
+			new_offset = RBUF_ERR_CNT_V3PLUS;
+
+		val = bcmgenet_rbuf_readl(priv,	new_offset);
+		/* clear if overflowed */
+		if (val == ~0)
+			bcmgenet_rbuf_writel(priv, 0, new_offset);
+		break;
+	default:
+		val = bcmgenet_umac_readl(priv, offset);
+		/* clear if overflowed */
+		if (val == ~0)
+			bcmgenet_umac_writel(priv, 0, offset);
+		break;
+	}
+
+	return val;
+}
+
 static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
 {
 	int i, j = 0;
@@ -836,19 +876,28 @@
 		case BCMGENET_STAT_NETDEV:
 		case BCMGENET_STAT_SOFT:
 			continue;
-		case BCMGENET_STAT_MIB_RX:
-		case BCMGENET_STAT_MIB_TX:
 		case BCMGENET_STAT_RUNT:
-			if (s->type != BCMGENET_STAT_MIB_RX)
-				offset = BCMGENET_STAT_OFFSET;
+			offset += BCMGENET_STAT_OFFSET;
+			/* fall through */
+		case BCMGENET_STAT_MIB_TX:
+			offset += BCMGENET_STAT_OFFSET;
+			/* fall through */
+		case BCMGENET_STAT_MIB_RX:
 			val = bcmgenet_umac_readl(priv,
 						  UMAC_MIB_START + j + offset);
+			offset = 0;	/* Reset Offset */
 			break;
 		case BCMGENET_STAT_MISC:
-			val = bcmgenet_umac_readl(priv, s->reg_offset);
-			/* clear if overflowed */
-			if (val == ~0)
-				bcmgenet_umac_writel(priv, 0, s->reg_offset);
+			if (GENET_IS_V1(priv)) {
+				val = bcmgenet_umac_readl(priv, s->reg_offset);
+				/* clear if overflowed */
+				if (val == ~0)
+					bcmgenet_umac_writel(priv, 0,
+							     s->reg_offset);
+			} else {
+				val = bcmgenet_update_stat_misc(priv,
+								s->reg_offset);
+			}
 			break;
 		}
 
@@ -878,7 +927,11 @@
 		else
 			p = (char *)priv;
 		p += s->stat_offset;
-		data[i] = *(u32 *)p;
+		if (sizeof(unsigned long) != sizeof(u32) &&
+		    s->stat_sizeof == sizeof(unsigned long))
+			data[i] = *(unsigned long *)p;
+		else
+			data[i] = *(u32 *)p;
 	}
 }
 
@@ -1025,7 +1078,7 @@
 		break;
 	}
 
-	return 0;
+	return ret;
 }
 
 static void bcmgenet_power_up(struct bcmgenet_priv *priv,
@@ -1168,6 +1221,7 @@
 					  struct bcmgenet_tx_ring *ring)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
+	struct device *kdev = &priv->pdev->dev;
 	struct enet_cb *tx_cb_ptr;
 	struct netdev_queue *txq;
 	unsigned int pkts_compl = 0;
@@ -1195,15 +1249,15 @@
 			pkts_compl++;
 			dev->stats.tx_packets++;
 			dev->stats.tx_bytes += tx_cb_ptr->skb->len;
-			dma_unmap_single(&dev->dev,
+			dma_unmap_single(kdev,
 					 dma_unmap_addr(tx_cb_ptr, dma_addr),
-					 tx_cb_ptr->skb->len,
+					 dma_unmap_len(tx_cb_ptr, dma_len),
 					 DMA_TO_DEVICE);
 			bcmgenet_free_cb(tx_cb_ptr);
 		} else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) {
 			dev->stats.tx_bytes +=
 				dma_unmap_len(tx_cb_ptr, dma_len);
-			dma_unmap_page(&dev->dev,
+			dma_unmap_page(kdev,
 				       dma_unmap_addr(tx_cb_ptr, dma_addr),
 				       dma_unmap_len(tx_cb_ptr, dma_len),
 				       DMA_TO_DEVICE);
@@ -1296,7 +1350,7 @@
 
 	tx_cb_ptr->skb = skb;
 
-	skb_len = skb_headlen(skb) < ETH_ZLEN ? ETH_ZLEN : skb_headlen(skb);
+	skb_len = skb_headlen(skb);
 
 	mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE);
 	ret = dma_mapping_error(kdev, mapping);
@@ -1308,7 +1362,7 @@
 	}
 
 	dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
-	dma_unmap_len_set(tx_cb_ptr, dma_len, skb->len);
+	dma_unmap_len_set(tx_cb_ptr, dma_len, skb_len);
 	length_status = (skb_len << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
 			(priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT) |
 			DMA_TX_APPEND_CRC;
@@ -1525,7 +1579,8 @@
 	dma_addr_t mapping;
 
 	/* Allocate a new Rx skb */
-	skb = netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT);
+	skb = __netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT,
+				 GFP_ATOMIC | __GFP_NOWARN);
 	if (!skb) {
 		priv->mib.alloc_rx_buff_failed++;
 		netif_err(priv, rx_err, priv->dev,
@@ -1754,6 +1809,7 @@
 
 static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
 {
+	struct device *kdev = &priv->pdev->dev;
 	struct enet_cb *cb;
 	int i;
 
@@ -1761,7 +1817,7 @@
 		cb = &priv->rx_cbs[i];
 
 		if (dma_unmap_addr(cb, dma_addr)) {
-			dma_unmap_single(&priv->dev->dev,
+			dma_unmap_single(kdev,
 					 dma_unmap_addr(cb, dma_addr),
 					 priv->rx_buf_len, DMA_FROM_DEVICE);
 			dma_unmap_addr_set(cb, dma_addr, 0);
@@ -2899,6 +2955,8 @@
 err_fini_dma:
 	bcmgenet_fini_dma(priv);
 err_clk_disable:
+	if (priv->internal_phy)
+		bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
 	clk_disable_unprepare(priv->clk);
 	return ret;
 }
@@ -3037,39 +3095,42 @@
 	netif_tx_wake_all_queues(dev);
 }
 
-#define MAX_MC_COUNT	16
+#define MAX_MDF_FILTER	17
 
 static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv,
 					 unsigned char *addr,
-					 int *i,
-					 int *mc)
+					 int *i)
 {
-	u32 reg;
-
 	bcmgenet_umac_writel(priv, addr[0] << 8 | addr[1],
 			     UMAC_MDF_ADDR + (*i * 4));
 	bcmgenet_umac_writel(priv, addr[2] << 24 | addr[3] << 16 |
 			     addr[4] << 8 | addr[5],
 			     UMAC_MDF_ADDR + ((*i + 1) * 4));
-	reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL);
-	reg |= (1 << (MAX_MC_COUNT - *mc));
-	bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
 	*i += 2;
-	(*mc)++;
 }
 
 static void bcmgenet_set_rx_mode(struct net_device *dev)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 	struct netdev_hw_addr *ha;
-	int i, mc;
+	int i, nfilter;
 	u32 reg;
 
 	netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags);
 
-	/* Promiscuous mode */
+	/* Number of filters needed */
+	nfilter = netdev_uc_count(dev) + netdev_mc_count(dev) + 2;
+
+	/*
+	 * Turn on promicuous mode for three scenarios
+	 * 1. IFF_PROMISC flag is set
+	 * 2. IFF_ALLMULTI flag is set
+	 * 3. The number of filters needed exceeds the number filters
+	 *    supported by the hardware.
+	*/
 	reg = bcmgenet_umac_readl(priv, UMAC_CMD);
-	if (dev->flags & IFF_PROMISC) {
+	if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) ||
+	    (nfilter > MAX_MDF_FILTER)) {
 		reg |= CMD_PROMISC;
 		bcmgenet_umac_writel(priv, reg, UMAC_CMD);
 		bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
@@ -3079,32 +3140,24 @@
 		bcmgenet_umac_writel(priv, reg, UMAC_CMD);
 	}
 
-	/* UniMac doesn't support ALLMULTI */
-	if (dev->flags & IFF_ALLMULTI) {
-		netdev_warn(dev, "ALLMULTI is not supported\n");
-		return;
-	}
-
 	/* update MDF filter */
 	i = 0;
-	mc = 0;
 	/* Broadcast */
-	bcmgenet_set_mdf_addr(priv, dev->broadcast, &i, &mc);
+	bcmgenet_set_mdf_addr(priv, dev->broadcast, &i);
 	/* my own address.*/
-	bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i, &mc);
-	/* Unicast list*/
-	if (netdev_uc_count(dev) > (MAX_MC_COUNT - mc))
-		return;
+	bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i);
 
-	if (!netdev_uc_empty(dev))
-		netdev_for_each_uc_addr(ha, dev)
-			bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
-	/* Multicast */
-	if (netdev_mc_empty(dev) || netdev_mc_count(dev) >= (MAX_MC_COUNT - mc))
-		return;
+	/* Unicast */
+	netdev_for_each_uc_addr(ha, dev)
+		bcmgenet_set_mdf_addr(priv, ha->addr, &i);
 
+	/* Multicast */
 	netdev_for_each_mc_addr(ha, dev)
-		bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+		bcmgenet_set_mdf_addr(priv, ha->addr, &i);
+
+	/* Enable filters */
+	reg = GENMASK(MAX_MDF_FILTER - 1, MAX_MDF_FILTER - nfilter);
+	bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
 }
 
 /* Set the hardware MAC address. */
@@ -3275,6 +3328,12 @@
 	 */
 	gphy_rev = reg & 0xffff;
 
+	/* This is reserved so should require special treatment */
+	if (gphy_rev == 0 || gphy_rev == 0x01ff) {
+		pr_warn("Invalid GPHY revision detected: 0x%04x\n", gphy_rev);
+		return;
+	}
+
 	/* This is the good old scheme, just GPHY major, no minor nor patch */
 	if ((gphy_rev & 0xf0) != 0)
 		priv->gphy_rev = gphy_rev << 8;
@@ -3283,12 +3342,6 @@
 	else if ((gphy_rev & 0xff00) != 0)
 		priv->gphy_rev = gphy_rev;
 
-	/* This is reserved so should require special treatment */
-	else if (gphy_rev == 0 || gphy_rev == 0x01ff) {
-		pr_warn("Invalid GPHY revision detected: 0x%04x\n", gphy_rev);
-		return;
-	}
-
 #ifdef CONFIG_PHYS_ADDR_T_64BIT
 	if (!(params->flags & GENET_HAS_40BITS))
 		pr_warn("GENET does not support 40-bits PA\n");
@@ -3331,6 +3384,7 @@
 	const void *macaddr;
 	struct resource *r;
 	int err = -EIO;
+	const char *phy_mode_str;
 
 	/* Up to GENET_MAX_MQ_CNT + 1 TX queues and RX queues */
 	dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1,
@@ -3436,6 +3490,13 @@
 		priv->clk_eee = NULL;
 	}
 
+	/* If this is an internal GPHY, power it on now, before UniMAC is
+	 * brought out of reset as absolutely no UniMAC activity is allowed
+	 */
+	if (dn && !of_property_read_string(dn, "phy-mode", &phy_mode_str) &&
+	    !strcasecmp(phy_mode_str, "internal"))
+		bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
+
 	err = reset_umac(priv);
 	if (err)
 		goto err_clk_disable;
@@ -3457,8 +3518,10 @@
 	clk_disable_unprepare(priv->clk);
 
 	err = register_netdev(dev);
-	if (err)
+	if (err) {
+		bcmgenet_mii_exit(dev);
 		goto err;
+	}
 
 	return err;
 
@@ -3493,7 +3556,8 @@
 
 	bcmgenet_netif_stop(dev);
 
-	phy_suspend(priv->phydev);
+	if (!device_may_wakeup(d))
+		phy_suspend(priv->phydev);
 
 	netif_device_detach(dev);
 
@@ -3590,7 +3654,8 @@
 
 	netif_device_attach(dev);
 
-	phy_resume(priv->phydev);
+	if (!device_may_wakeup(d))
+		phy_resume(priv->phydev);
 
 	if (priv->eee.eee_enabled)
 		bcmgenet_eee_enable_set(dev, true);
@@ -3600,6 +3665,8 @@
 	return 0;
 
 out_clk_disable:
+	if (priv->internal_phy)
+		bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
 	clk_disable_unprepare(priv->clk);
 	return ret;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ linux-4.4.0/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Broadcom Corporation
+ * Copyright (c) 2014-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -185,6 +185,9 @@
 #define UMAC_MAC1			0x010
 #define UMAC_MAX_FRAME_LEN		0x014
 
+#define UMAC_MODE			0x44
+#define  MODE_LINK_STATUS		(1 << 5)
+
 #define UMAC_EEE_CTRL			0x064
 #define  EN_LPI_RX_PAUSE		(1 << 0)
 #define  EN_LPI_TX_PFC			(1 << 1)
@@ -214,7 +217,9 @@
 #define  MDIO_REG_SHIFT			16
 #define  MDIO_REG_MASK			0x1F
 
-#define UMAC_RBUF_OVFL_CNT		0x61C
+#define UMAC_RBUF_OVFL_CNT_V1		0x61C
+#define RBUF_OVFL_CNT_V2		0x80
+#define RBUF_OVFL_CNT_V3PLUS		0x94
 
 #define UMAC_MPD_CTRL			0x620
 #define  MPD_EN				(1 << 0)
@@ -224,7 +229,9 @@
 
 #define UMAC_MPD_PW_MS			0x624
 #define UMAC_MPD_PW_LS			0x628
-#define UMAC_RBUF_ERR_CNT		0x634
+#define UMAC_RBUF_ERR_CNT_V1		0x634
+#define RBUF_ERR_CNT_V2			0x84
+#define RBUF_ERR_CNT_V3PLUS		0x98
 #define UMAC_MDF_ERR_CNT		0x638
 #define UMAC_MDF_CTRL			0x650
 #define UMAC_MDF_ADDR			0x654
@@ -355,6 +362,7 @@
 #define  EXT_ENERGY_DET_MASK		(1 << 12)
 
 #define EXT_RGMII_OOB_CTRL		0x0C
+#define  RGMII_MODE_EN_V123		(1 << 0)
 #define  RGMII_LINK			(1 << 4)
 #define  OOB_DISABLE			(1 << 5)
 #define  RGMII_MODE_EN			(1 << 6)
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -167,8 +167,14 @@
 static int bcmgenet_fixed_phy_link_update(struct net_device *dev,
 					  struct fixed_phy_status *status)
 {
-	if (dev && dev->phydev && status)
-		status->link = dev->phydev->link;
+	struct bcmgenet_priv *priv;
+	u32 reg;
+
+	if (dev && dev->phydev && status) {
+		priv = netdev_priv(dev);
+		reg = bcmgenet_umac_readl(priv, UMAC_MODE);
+		status->link = !!(reg & MODE_LINK_STATUS);
+	}
 
 	return 0;
 }
@@ -220,20 +226,6 @@
 	udelay(60);
 }
 
-static void bcmgenet_internal_phy_setup(struct net_device *dev)
-{
-	struct bcmgenet_priv *priv = netdev_priv(dev);
-	u32 reg;
-
-	/* Power up PHY */
-	bcmgenet_phy_power_set(dev, true);
-	/* enable APD */
-	reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
-	reg |= EXT_PWR_DN_EN_LD;
-	bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
-	bcmgenet_mii_reset(dev);
-}
-
 static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
 {
 	u32 reg;
@@ -281,7 +273,6 @@
 
 		if (priv->internal_phy) {
 			phy_name = "internal PHY";
-			bcmgenet_internal_phy_setup(dev);
 		} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
 			phy_name = "MoCA";
 			bcmgenet_moca_phy_setup(priv);
@@ -337,7 +328,11 @@
 	 */
 	if (priv->ext_phy) {
 		reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
-		reg |= RGMII_MODE_EN | id_mode_dis;
+		reg |= id_mode_dis;
+		if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
+			reg |= RGMII_MODE_EN_V123;
+		else
+			reg |= RGMII_MODE_EN;
 		bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
 	}
 
@@ -351,11 +346,12 @@
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 	struct device_node *dn = priv->pdev->dev.of_node;
 	struct phy_device *phydev;
-	u32 phy_flags;
+	u32 phy_flags = 0;
 	int ret;
 
 	/* Communicate the integrated PHY revision */
-	phy_flags = priv->gphy_rev;
+	if (priv->internal_phy)
+		phy_flags = priv->gphy_rev;
 
 	/* Initialize link state variables that bcmgenet_mii_setup() uses */
 	priv->old_link = -1;
@@ -500,7 +496,7 @@
 	if (!compat)
 		return -ENOMEM;
 
-	priv->mdio_dn = of_find_compatible_node(dn, NULL, compat);
+	priv->mdio_dn = of_get_compatible_child(dn, compat);
 	kfree(compat);
 	if (!priv->mdio_dn) {
 		dev_err(kdev, "unable to find MDIO bus node\n");
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/sb1250-mac.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/sb1250-mac.c
@@ -300,7 +300,7 @@
 static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff);
 static uint64_t sbmac_addr2reg(unsigned char *ptr);
 static irqreturn_t sbmac_intr(int irq, void *dev_instance);
-static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
 static void sbmac_setmulti(struct sbmac_softc *sc);
 static int sbmac_init(struct platform_device *pldev, long long base);
 static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed);
@@ -2033,7 +2033,7 @@
  *  Return value:
  *  	   nothing
  ********************************************************************* */
-static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sbmac_softc *sc = netdev_priv(dev);
 	unsigned long flags;
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/tg3.c
+++ linux-4.4.0/drivers/net/ethernet/broadcom/tg3.c
@@ -329,6 +329,7 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57785)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57761)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57786)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791),
 	 .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795),
@@ -7203,8 +7204,8 @@
 
 static inline void tg3_reset_task_cancel(struct tg3 *tp)
 {
-	cancel_work_sync(&tp->reset_task);
-	tg3_flag_clear(tp, RESET_TASK_PENDING);
+	if (test_and_clear_bit(TG3_FLAG_RESET_TASK_PENDING, tp->tg3_flags))
+		cancel_work_sync(&tp->reset_task);
 	tg3_flag_clear(tp, TX_RECOVERY_PENDING);
 }
 
@@ -7833,6 +7834,14 @@
 	return ret;
 }
 
+static bool tg3_tso_bug_gso_check(struct tg3_napi *tnapi, struct sk_buff *skb)
+{
+	/* Check if we will never have enough descriptors,
+	 * as gso_segs can be more than current ring size
+	 */
+	return skb_shinfo(skb)->gso_segs < tnapi->tx_pending / 3;
+}
+
 static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *);
 
 /* Use GSO to workaround all TSO packets that meet HW bug conditions
@@ -7936,14 +7945,19 @@
 		 * vlan encapsulated.
 		 */
 		if (skb->protocol == htons(ETH_P_8021Q) ||
-		    skb->protocol == htons(ETH_P_8021AD))
-			return tg3_tso_bug(tp, tnapi, txq, skb);
+		    skb->protocol == htons(ETH_P_8021AD)) {
+			if (tg3_tso_bug_gso_check(tnapi, skb))
+				return tg3_tso_bug(tp, tnapi, txq, skb);
+			goto drop;
+		}
 
 		if (!skb_is_gso_v6(skb)) {
 			if (unlikely((ETH_HLEN + hdr_len) > 80) &&
-			    tg3_flag(tp, TSO_BUG))
-				return tg3_tso_bug(tp, tnapi, txq, skb);
-
+			    tg3_flag(tp, TSO_BUG)) {
+				if (tg3_tso_bug_gso_check(tnapi, skb))
+					return tg3_tso_bug(tp, tnapi, txq, skb);
+				goto drop;
+			}
 			ip_csum = iph->check;
 			ip_tot_len = iph->tot_len;
 			iph->check = 0;
@@ -8075,7 +8089,7 @@
 	if (would_hit_hwbug) {
 		tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i);
 
-		if (mss) {
+		if (mss && tg3_tso_bug_gso_check(tnapi, skb)) {
 			/* If it's a TSO packet, do GSO instead of
 			 * allocating and copying to a large linear SKB
 			 */
@@ -8709,6 +8723,10 @@
 	tg3_mem_rx_release(tp);
 	tg3_mem_tx_release(tp);
 
+	/* tp->hw_stats can be referenced safely:
+	 *     1. under rtnl_lock
+	 *     2. or under tp->lock if TG3_FLAG_INIT_COMPLETE is set.
+	 */
 	if (tp->hw_stats) {
 		dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats),
 				  tp->hw_stats, tp->stats_mapping);
@@ -9261,6 +9279,15 @@
 
 	tg3_restore_clk(tp);
 
+	/* Increase the core clock speed to fix tx timeout issue for 5762
+	 * with 100Mbps link speed.
+	 */
+	if (tg3_asic_rev(tp) == ASIC_REV_5762) {
+		val = tr32(TG3_CPMU_CLCK_ORIDE_ENABLE);
+		tw32(TG3_CPMU_CLCK_ORIDE_ENABLE, val |
+		     TG3_CPMU_MAC_ORIDE_ENABLE);
+	}
+
 	/* Reprobe ASF enable state.  */
 	tg3_flag_clear(tp, ENABLE_ASF);
 	tp->phy_flags &= ~(TG3_PHYFLG_1G_ON_VAUX_OK |
@@ -10035,6 +10062,16 @@
 
 	tw32(GRC_MODE, tp->grc_mode | val);
 
+	/* On one of the AMD platform, MRRS is restricted to 4000 because of
+	 * south bridge limitation. As a workaround, Driver is setting MRRS
+	 * to 2048 instead of default 4096.
+	 */
+	if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    tp->pdev->subsystem_device == TG3PCI_SUBDEVICE_ID_DELL_5762) {
+		val = tr32(TG3PCI_DEV_STATUS_CTRL) & ~MAX_READ_REQ_MASK;
+		tw32(TG3PCI_DEV_STATUS_CTRL, val | MAX_READ_REQ_SIZE_2048);
+	}
+
 	/* Setup the timer prescalar register.  Clock is always 66Mhz. */
 	val = tr32(GRC_MISC_CFG);
 	val &= ~0xff;
@@ -11140,18 +11177,27 @@
 
 	tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
 	err = tg3_init_hw(tp, true);
-	if (err)
+	if (err) {
+		tg3_full_unlock(tp);
+		tp->irq_sync = 0;
+		tg3_napi_enable(tp);
+		/* Clear this flag so that tg3_reset_task_cancel() will not
+		 * call cancel_work_sync() and wait forever.
+		 */
+		tg3_flag_clear(tp, RESET_TASK_PENDING);
+		dev_close(tp->dev);
 		goto out;
+	}
 
 	tg3_netif_start(tp);
 
-out:
 	tg3_full_unlock(tp);
 
 	if (!err)
 		tg3_phy_start(tp);
 
 	tg3_flag_clear(tp, RESET_TASK_PENDING);
+out:
 	rtnl_unlock();
 }
 
@@ -12018,7 +12064,7 @@
 	int ret;
 	u32 offset, len, b_offset, odd_len;
 	u8 *buf;
-	__be32 start, end;
+	__be32 start = 0, end;
 
 	if (tg3_flag(tp, NO_NVRAM) ||
 	    eeprom->magic != TG3_EEPROM_MAGIC)
@@ -12343,6 +12389,7 @@
 {
 	struct tg3 *tp = netdev_priv(dev);
 	int i, irq_sync = 0, err = 0;
+	bool reset_phy = false;
 
 	if ((ering->rx_pending > tp->rx_std_ring_mask) ||
 	    (ering->rx_jumbo_pending > tp->rx_jmb_ring_mask) ||
@@ -12374,7 +12421,13 @@
 
 	if (netif_running(dev)) {
 		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-		err = tg3_restart_hw(tp, false);
+		/* Reset PHY to avoid PHY lock up */
+		if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5719 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5720)
+			reset_phy = true;
+
+		err = tg3_restart_hw(tp, reset_phy);
 		if (!err)
 			tg3_netif_start(tp);
 	}
@@ -12408,6 +12461,7 @@
 {
 	struct tg3 *tp = netdev_priv(dev);
 	int err = 0;
+	bool reset_phy = false;
 
 	if (tp->link_config.autoneg == AUTONEG_ENABLE)
 		tg3_warn_mgmt_link_flap(tp);
@@ -12498,7 +12552,13 @@
 
 		if (netif_running(dev)) {
 			tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-			err = tg3_restart_hw(tp, false);
+			/* Reset PHY to avoid PHY lock up */
+			if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+			    tg3_asic_rev(tp) == ASIC_REV_5719 ||
+			    tg3_asic_rev(tp) == ASIC_REV_5720)
+				reset_phy = true;
+
+			err = tg3_restart_hw(tp, reset_phy);
 			if (!err)
 				tg3_netif_start(tp);
 		}
@@ -14137,7 +14197,7 @@
 	struct tg3 *tp = netdev_priv(dev);
 
 	spin_lock_bh(&tp->lock);
-	if (!tp->hw_stats) {
+	if (!tp->hw_stats || !tg3_flag(tp, INIT_COMPLETE)) {
 		*stats = tp->net_stats_prev;
 		spin_unlock_bh(&tp->lock);
 		return stats;
@@ -14212,7 +14272,10 @@
 	/* Reset PHY, otherwise the read DMA engine will be in a mode that
 	 * breaks all requests to 256 bytes.
 	 */
-	if (tg3_asic_rev(tp) == ASIC_REV_57766)
+	if (tg3_asic_rev(tp) == ASIC_REV_57766 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5719 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5720)
 		reset_phy = true;
 
 	err = tg3_restart_hw(tp, reset_phy);
@@ -18129,14 +18192,14 @@
 
 	rtnl_lock();
 
+	/* Could be second call or maybe we don't have netdev yet */
+	if (!netdev || tp->pcierr_recovery || !netif_running(netdev))
+		goto done;
+
 	/* We needn't recover from permanent error */
 	if (state == pci_channel_io_frozen)
 		tp->pcierr_recovery = true;
 
-	/* We probably don't have netdev yet */
-	if (!netdev || !netif_running(netdev))
-		goto done;
-
 	tg3_phy_stop(tp);
 
 	tg3_netif_stop(tp);
@@ -18233,7 +18296,7 @@
 
 	rtnl_lock();
 
-	if (!netif_running(netdev))
+	if (!netdev || !netif_running(netdev))
 		goto done;
 
 	tg3_full_lock(tp, 0);
--- linux-4.4.0.orig/drivers/net/ethernet/broadcom/tg3.h
+++ linux-4.4.0/drivers/net/ethernet/broadcom/tg3.h
@@ -95,6 +95,7 @@
 #define TG3PCI_SUBDEVICE_ID_DELL_JAGUAR		0x0106
 #define TG3PCI_SUBDEVICE_ID_DELL_MERLOT		0x0109
 #define TG3PCI_SUBDEVICE_ID_DELL_SLIM_MERLOT	0x010a
+#define TG3PCI_SUBDEVICE_ID_DELL_5762		0x07f0
 #define TG3PCI_SUBVENDOR_ID_COMPAQ		PCI_VENDOR_ID_COMPAQ
 #define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE	0x007c
 #define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE_2	0x009a
@@ -280,6 +281,9 @@
 #define TG3PCI_STD_RING_PROD_IDX	0x00000098 /* 64-bit */
 #define TG3PCI_RCV_RET_RING_CON_IDX	0x000000a0 /* 64-bit */
 /* 0xa8 --> 0xb8 unused */
+#define TG3PCI_DEV_STATUS_CTRL		0x000000b4
+#define  MAX_READ_REQ_SIZE_2048		 0x00004000
+#define  MAX_READ_REQ_MASK		 0x00007000
 #define TG3PCI_DUAL_MAC_CTRL		0x000000b8
 #define  DUAL_MAC_CTRL_CH_MASK		 0x00000003
 #define  DUAL_MAC_CTRL_ID		 0x00000004
--- linux-4.4.0.orig/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ linux-4.4.0/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -1930,13 +1930,13 @@
 bfa_ioc_send_enable(struct bfa_ioc *ioc)
 {
 	struct bfi_ioc_ctrl_req enable_req;
-	struct timeval tv;
 
 	bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
 		    bfa_ioc_portid(ioc));
 	enable_req.clscode = htons(ioc->clscode);
-	do_gettimeofday(&tv);
-	enable_req.tv_sec = ntohl(tv.tv_sec);
+	enable_req.rsvd = htons(0);
+	/* overflow in 2106 */
+	enable_req.tv_sec = ntohl(ktime_get_real_seconds());
 	bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req));
 }
 
@@ -1947,6 +1947,10 @@
 
 	bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
 		    bfa_ioc_portid(ioc));
+	disable_req.clscode = htons(ioc->clscode);
+	disable_req.rsvd = htons(0);
+	/* overflow in 2106 */
+	disable_req.tv_sec = ntohl(ktime_get_real_seconds());
 	bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req));
 }
 
@@ -2841,7 +2845,7 @@
 static void
 bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer)
 {
-	memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+	strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
 }
 
 static void
--- linux-4.4.0.orig/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
+++ linux-4.4.0/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
@@ -319,12 +319,12 @@
 	void *kern_buf;
 
 	/* Copy the user space buf */
-	kern_buf = memdup_user(buf, nbytes);
+	kern_buf = memdup_user_nul(buf, nbytes);
 	if (IS_ERR(kern_buf))
 		return PTR_ERR(kern_buf);
 
 	rc = sscanf(kern_buf, "%x:%x", &addr, &len);
-	if (rc < 2) {
+	if (rc < 2 || len > UINT_MAX >> 2) {
 		netdev_warn(bnad->netdev, "failed to read user buffer\n");
 		kfree(kern_buf);
 		return -EINVAL;
@@ -378,7 +378,7 @@
 	void *kern_buf;
 
 	/* Copy the user space buf */
-	kern_buf = memdup_user(buf, nbytes);
+	kern_buf = memdup_user_nul(buf, nbytes);
 	if (IS_ERR(kern_buf))
 		return PTR_ERR(kern_buf);
 
--- linux-4.4.0.orig/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
@@ -31,7 +31,7 @@
 #define BNAD_NUM_TXF_COUNTERS 12
 #define BNAD_NUM_RXF_COUNTERS 10
 #define BNAD_NUM_CQ_COUNTERS (3 + 5)
-#define BNAD_NUM_RXQ_COUNTERS 6
+#define BNAD_NUM_RXQ_COUNTERS 7
 #define BNAD_NUM_TXQ_COUNTERS 5
 
 #define BNAD_ETHTOOL_STATS_NUM						\
@@ -556,8 +556,8 @@
 		for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
 			BUG_ON(!(strlen(bnad_net_stats_strings[i]) <
 				   ETH_GSTRING_LEN));
-			memcpy(string, bnad_net_stats_strings[i],
-			       ETH_GSTRING_LEN);
+			strncpy(string, bnad_net_stats_strings[i],
+				ETH_GSTRING_LEN);
 			string += ETH_GSTRING_LEN;
 		}
 		bmap = bna_tx_rid_mask(&bnad->bna);
@@ -658,6 +658,8 @@
 				string += ETH_GSTRING_LEN;
 				sprintf(string, "rxq%d_allocbuf_failed", q_num);
 				string += ETH_GSTRING_LEN;
+				sprintf(string, "rxq%d_mapbuf_failed", q_num);
+				string += ETH_GSTRING_LEN;
 				sprintf(string, "rxq%d_producer_index", q_num);
 				string += ETH_GSTRING_LEN;
 				sprintf(string, "rxq%d_consumer_index", q_num);
@@ -678,6 +680,9 @@
 					sprintf(string, "rxq%d_allocbuf_failed",
 								q_num);
 					string += ETH_GSTRING_LEN;
+					sprintf(string, "rxq%d_mapbuf_failed",
+						q_num);
+					string += ETH_GSTRING_LEN;
 					sprintf(string, "rxq%d_producer_index",
 								q_num);
 					string += ETH_GSTRING_LEN;
--- linux-4.4.0.orig/drivers/net/ethernet/cadence/macb.c
+++ linux-4.4.0/drivers/net/ethernet/cadence/macb.c
@@ -523,7 +523,7 @@
 		if (!(status & MACB_BIT(TGO)))
 			return 0;
 
-		usleep_range(10, 250);
+		udelay(250);
 	} while (time_before(halt_time, timeout));
 
 	return -ETIMEDOUT;
@@ -1104,7 +1104,7 @@
 			macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
 
 			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
-				macb_writel(bp, ISR, MACB_BIT(RXUBR));
+				queue_writel(queue, ISR, MACB_BIT(RXUBR));
 		}
 
 		if (status & MACB_BIT(ISR_ROVR)) {
@@ -2275,14 +2275,14 @@
 	*pclk = devm_clk_get(&pdev->dev, "pclk");
 	if (IS_ERR(*pclk)) {
 		err = PTR_ERR(*pclk);
-		dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err);
+		dev_err(&pdev->dev, "failed to get macb_clk (%d)\n", err);
 		return err;
 	}
 
 	*hclk = devm_clk_get(&pdev->dev, "hclk");
 	if (IS_ERR(*hclk)) {
 		err = PTR_ERR(*hclk);
-		dev_err(&pdev->dev, "failed to get hclk (%u)\n", err);
+		dev_err(&pdev->dev, "failed to get hclk (%d)\n", err);
 		return err;
 	}
 
@@ -2292,19 +2292,19 @@
 
 	err = clk_prepare_enable(*pclk);
 	if (err) {
-		dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err);
+		dev_err(&pdev->dev, "failed to enable pclk (%d)\n", err);
 		return err;
 	}
 
 	err = clk_prepare_enable(*hclk);
 	if (err) {
-		dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err);
+		dev_err(&pdev->dev, "failed to enable hclk (%d)\n", err);
 		goto err_disable_pclk;
 	}
 
 	err = clk_prepare_enable(*tx_clk);
 	if (err) {
-		dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
+		dev_err(&pdev->dev, "failed to enable tx_clk (%d)\n", err);
 		goto err_disable_hclk;
 	}
 
@@ -2405,9 +2405,9 @@
 	if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII)
 		val = GEM_BIT(RGMII);
 	else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII &&
-		 (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII))
+		 (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII))
 		val = MACB_BIT(RMII);
-	else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII))
+	else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII))
 		val = MACB_BIT(MII);
 
 	if (bp->caps & MACB_CAPS_USRIO_HAS_CLKEN)
@@ -2704,7 +2704,7 @@
 
 	err = clk_prepare_enable(*pclk);
 	if (err) {
-		dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err);
+		dev_err(&pdev->dev, "failed to enable pclk (%d)\n", err);
 		return err;
 	}
 
@@ -2738,7 +2738,14 @@
 }
 
 static const struct macb_config at91sam9260_config = {
-	.caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII,
+	.caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
+	.clk_init = macb_clk_init,
+	.init = macb_init,
+};
+
+static const struct macb_config sama5d3macb_config = {
+	.caps = MACB_CAPS_SG_DISABLED
+	      | MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
 	.clk_init = macb_clk_init,
 	.init = macb_init,
 };
@@ -2751,21 +2758,22 @@
 };
 
 static const struct macb_config sama5d2_config = {
-	.caps = 0,
+	.caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
 	.dma_burst_length = 16,
 	.clk_init = macb_clk_init,
 	.init = macb_init,
 };
 
 static const struct macb_config sama5d3_config = {
-	.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
+	.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE
+	      | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
 	.dma_burst_length = 16,
 	.clk_init = macb_clk_init,
 	.init = macb_init,
 };
 
 static const struct macb_config sama5d4_config = {
-	.caps = 0,
+	.caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
 	.dma_burst_length = 4,
 	.clk_init = macb_clk_init,
 	.init = macb_init,
@@ -2800,6 +2808,7 @@
 	{ .compatible = "cdns,gem", .data = &pc302gem_config },
 	{ .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config },
 	{ .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config },
+	{ .compatible = "atmel,sama5d3-macb", .data = &sama5d3macb_config },
 	{ .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config },
 	{ .compatible = "cdns,at91rm9200-emac", .data = &emac_config },
 	{ .compatible = "cdns,emac", .data = &emac_config },
@@ -2895,7 +2904,7 @@
 	dev->irq = platform_get_irq(pdev, 0);
 	if (dev->irq < 0) {
 		err = dev->irq;
-		goto err_disable_clocks;
+		goto err_out_free_netdev;
 	}
 
 	mac = of_get_mac_address(np);
--- linux-4.4.0.orig/drivers/net/ethernet/cadence/macb.h
+++ linux-4.4.0/drivers/net/ethernet/cadence/macb.h
@@ -398,7 +398,7 @@
 /* Capability mask bits */
 #define MACB_CAPS_ISR_CLEAR_ON_WRITE		0x00000001
 #define MACB_CAPS_USRIO_HAS_CLKEN		0x00000002
-#define MACB_CAPS_USRIO_DEFAULT_IS_MII		0x00000004
+#define MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII	0x00000004
 #define MACB_CAPS_NO_GIGABIT_HALF		0x00000008
 #define MACB_CAPS_FIFO_MODE			0x10000000
 #define MACB_CAPS_GIGABIT_MODE_AVAILABLE	0x20000000
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/cavium/Kconfig
@@ -35,7 +35,7 @@
 	tristate "Thunder MAC interface driver (BGX)"
 	depends on 64BIT
 	select PHYLIB
-	select MDIO_OCTEON
+	select MDIO_THUNDER
 	---help---
 	  This driver supports programming and controlling of MAC
 	  interface from NIC physical function driver.
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ linux-4.4.0/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -1526,7 +1526,6 @@
 				struct timespec64 *ts)
 {
 	u64 ns;
-	u32 remainder;
 	unsigned long flags;
 	struct lio *lio = container_of(ptp, struct lio, ptp_info);
 	struct octeon_device *oct = (struct octeon_device *)lio->oct_dev;
@@ -1536,8 +1535,7 @@
 	ns += lio->ptp_adjust;
 	spin_unlock_irqrestore(&lio->ptp_lock, flags);
 
-	ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
-	ts->tv_nsec = remainder;
+	*ts = ns_to_timespec64(ns);
 
 	return 0;
 }
@@ -1685,7 +1683,7 @@
 	dev_dbg(&oct->pci_dev->dev, "Creating Droq: %d\n", q_no);
 	/* droq creation and local register settings. */
 	ret_val = octeon_create_droq(oct, q_no, num_descs, desc_size, app_ctx);
-	if (ret_val == -1)
+	if (ret_val < 0)
 		return ret_val;
 
 	if (ret_val == 1) {
@@ -2526,7 +2524,7 @@
 
 	octeon_swap_8B_data(&resp->timestamp, 1);
 
-	if (unlikely((skb_shinfo(skb)->tx_flags | SKBTX_IN_PROGRESS) != 0)) {
+	if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) != 0)) {
 		struct skb_shared_hwtstamps ts;
 		u64 ns = resp->timestamp;
 
@@ -2894,7 +2892,7 @@
 	else
 		status = octnet_send_nic_data_pkt(oct, &ndata, xmit_more);
 	if (status == IQ_SEND_FAILED)
-		goto lio_xmit_failed;
+		goto lio_xmit_dma_failed;
 
 	netif_info(lio, tx_queued, lio->netdev, "Transmit queued successfully\n");
 
@@ -2908,12 +2906,13 @@
 
 	return NETDEV_TX_OK;
 
+lio_xmit_dma_failed:
+	dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr,
+			 ndata.datasize, DMA_TO_DEVICE);
 lio_xmit_failed:
 	stats->tx_dropped++;
 	netif_info(lio, tx_err, lio->netdev, "IQ%d Transmit dropped:%llu\n",
 		   iq_no, stats->tx_dropped);
-	dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr,
-			 ndata.datasize, DMA_TO_DEVICE);
 	recv_buffer_free(skb);
 	return NETDEV_TX_OK;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
+++ linux-4.4.0/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
@@ -983,5 +983,5 @@
 
 create_droq_fail:
 	octeon_delete_droq(oct, q_no);
-	return -1;
+	return -ENOMEM;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/nic.h
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/nic.h
@@ -116,6 +116,15 @@
 #define NIC_PF_INTR_ID_MBOX0		8
 #define NIC_PF_INTR_ID_MBOX1		9
 
+/* Minimum FIFO level before all packets for the CQ are dropped
+ *
+ * This value ensures that once a packet has been "accepted"
+ * for reception it will not get dropped due to non-availability
+ * of CQ descriptor. An errata in HW mandates this value to be
+ * atleast 0x100.
+ */
+#define NICPF_CQM_MIN_DROP_LEVEL       0x100
+
 /* Global timer for CQ timer thresh interrupts
  * Calculated for SCLK of 700Mhz
  * value written should be a 1/16th of what is expected
@@ -248,10 +257,13 @@
 	u64 rx_frames_jumbo;
 	u64 rx_drops;
 
+	u64 rcv_buffer_alloc_failures;
+
 	/* Tx */
 	u64 tx_frames_ok;
 	u64 tx_drops;
 	u64 tx_tso;
+	u64 tx_timeout;
 	u64 txq_stop;
 	u64 txq_wake;
 };
@@ -260,44 +272,55 @@
 	struct nicvf		*pnicvf;
 	struct net_device	*netdev;
 	struct pci_dev		*pdev;
-	u8			vf_id;
-	u8			node;
-	u8			tns_mode:1;
-	u8			sqs_mode:1;
-	u8			loopback_supported:1;
-	u16			mtu;
+	void __iomem		*reg_base;
 	struct queue_set	*qs;
+	struct nicvf_cq_poll	*napi[8];
+	u8			vf_id;
+	u8			sqs_id;
+	bool                    sqs_mode;
+	bool			hw_tso;
+	bool			t88;
+
+	/* Receive buffer alloc */
+	u32			rb_page_offset;
+	u16			rb_pageref;
+	bool			rb_alloc_fail;
+	bool			rb_work_scheduled;
+	struct page		*rb_page;
+	struct delayed_work	rbdr_work;
+	struct tasklet_struct	rbdr_task;
+
+	/* Secondary Qset */
+	u8			sqs_count;
 #define	MAX_SQS_PER_VF_SINGLE_NODE		5
 #define	MAX_SQS_PER_VF				11
-	u8			sqs_id;
-	u8			sqs_count; /* Secondary Qset count */
 	struct nicvf		*snicvf[MAX_SQS_PER_VF];
+
+	/* Queue count */
 	u8			rx_queues;
 	u8			tx_queues;
 	u8			max_queues;
-	void __iomem		*reg_base;
+
+	u8			node;
+	u8			cpi_alg;
+	u16			mtu;
 	bool			link_up;
 	u8			duplex;
 	u32			speed;
-	struct page		*rb_page;
-	u32			rb_page_offset;
-	bool			rb_alloc_fail;
-	bool			rb_work_scheduled;
-	struct delayed_work	rbdr_work;
-	struct tasklet_struct	rbdr_task;
-	struct tasklet_struct	qs_err_task;
-	struct tasklet_struct	cq_task;
-	struct nicvf_cq_poll	*napi[8];
+	bool			tns_mode;
+	bool			loopback_supported;
 	struct nicvf_rss_info	rss_info;
-	u8			cpi_alg;
+	struct tasklet_struct	qs_err_task;
+	struct work_struct	reset_task;
+
 	/* Interrupt coalescing settings */
 	u32			cq_coalesce_usecs;
-
 	u32			msg_enable;
+
+	/* Stats */
 	struct nicvf_hw_stats   hw_stats;
 	struct nicvf_drv_stats  drv_stats;
 	struct bgx_stats	bgx_stats;
-	struct work_struct	reset_task;
 
 	/* MSI-X  */
 	bool			msix_enabled;
@@ -305,6 +328,7 @@
 	struct msix_entry	msix_entries[NIC_VF_MSIX_VECTORS];
 	char			irq_name[NIC_VF_MSIX_VECTORS][20];
 	bool			irq_allocated[NIC_VF_MSIX_VECTORS];
+	cpumask_var_t		affinity_mask[NIC_VF_MSIX_VECTORS];
 
 	/* VF <-> PF mailbox communication */
 	bool			pf_acked;
@@ -489,6 +513,11 @@
 	return ((addr >> NIC_NODE_ID_SHIFT) & NIC_NODE_ID_MASK);
 }
 
+static inline bool pass1_silicon(struct pci_dev *pdev)
+{
+	return pdev->revision < 8;
+}
+
 int nicvf_set_real_num_queues(struct net_device *netdev,
 			      int tx_queues, int rx_queues);
 int nicvf_open(struct net_device *netdev);
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -54,11 +54,6 @@
 	bool			irq_allocated[NIC_PF_MSIX_VECTORS];
 };
 
-static inline bool pass1_silicon(struct nicpf *nic)
-{
-	return nic->pdev->revision < 8;
-}
-
 /* Supported devices */
 static const struct pci_device_id nic_id_table[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_NIC_PF) },
@@ -122,7 +117,7 @@
 	 * when PF writes to MBOX(1), in next revisions when
 	 * PF writes to MBOX(0)
 	 */
-	if (pass1_silicon(nic)) {
+	if (pass1_silicon(nic->pdev)) {
 		/* see the comment for nic_reg_write()/nic_reg_read()
 		 * functions above
 		 */
@@ -256,9 +251,14 @@
 	int lmac;
 	u64 lmac_cfg;
 
-	/* Max value that can be set is 60 */
-	if (size > 60)
-		size = 60;
+	/* There is a issue in HW where-in while sending GSO sized
+	 * pkts as part of TSO, if pkt len falls below this size
+	 * NIC will zero PAD packet and also updates IP total length.
+	 * Hence set this value to lessthan min pkt size of MAC+IP+TCP
+	 * headers, BGX will do the padding to transmit 64 byte pkt.
+	 */
+	if (size > 52)
+		size = 52;
 
 	for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) {
 		lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3));
@@ -309,6 +309,7 @@
 static void nic_init_hw(struct nicpf *nic)
 {
 	int i;
+	u64 cqm_cfg;
 
 	/* Enable NIC HW block */
 	nic_reg_write(nic, NIC_PF_CFG, 0x3);
@@ -345,6 +346,11 @@
 	/* Enable VLAN ethertype matching and stripping */
 	nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7,
 		      (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q);
+
+	/* Check if HW expected value is higher (could be in future chips) */
+	cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG);
+	if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL)
+		nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL);
 }
 
 /* Channel parse index configuration */
@@ -397,7 +403,7 @@
 			padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */
 
 		/* Leave RSS_SIZE as '0' to disable RSS */
-		if (pass1_silicon(nic)) {
+		if (pass1_silicon(nic->pdev)) {
 			nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
 				      (vnic << 24) | (padd << 16) |
 				      (rssi_base + rssi));
@@ -467,7 +473,7 @@
 	}
 
 	cpi_base = nic->cpi_base[cfg->vf_id];
-	if (pass1_silicon(nic))
+	if (pass1_silicon(nic->pdev))
 		idx_addr = NIC_PF_CPI_0_2047_CFG;
 	else
 		idx_addr = NIC_PF_MPI_0_2047_CFG;
@@ -1084,6 +1090,9 @@
 {
 	struct nicpf *nic = pci_get_drvdata(pdev);
 
+	if (!nic)
+		return;
+
 	if (nic->flags & NIC_SRIOV_ENABLED)
 		pci_disable_sriov(pdev);
 
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/nic_reg.h
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/nic_reg.h
@@ -21,7 +21,7 @@
 #define   NIC_PF_TCP_TIMER			(0x0060)
 #define   NIC_PF_BP_CFG				(0x0080)
 #define   NIC_PF_RRM_CFG			(0x0088)
-#define   NIC_PF_CQM_CF				(0x00A0)
+#define   NIC_PF_CQM_CFG			(0x00A0)
 #define   NIC_PF_CNM_CF				(0x00A8)
 #define   NIC_PF_CNM_STATUS			(0x00B0)
 #define   NIC_PF_CQ_AVG_CFG			(0x00C0)
@@ -170,7 +170,6 @@
 #define   NIC_QSET_SQ_0_7_DOOR			(0x010838)
 #define   NIC_QSET_SQ_0_7_STATUS		(0x010840)
 #define   NIC_QSET_SQ_0_7_DEBUG			(0x010848)
-#define   NIC_QSET_SQ_0_7_CNM_CHG		(0x010860)
 #define   NIC_QSET_SQ_0_7_STAT_0_1		(0x010900)
 
 #define   NIC_QSET_RBDR_0_1_CFG			(0x010C00)
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
@@ -89,9 +89,11 @@
 	NICVF_DRV_STAT(rx_frames_1518),
 	NICVF_DRV_STAT(rx_frames_jumbo),
 	NICVF_DRV_STAT(rx_drops),
+	NICVF_DRV_STAT(rcv_buffer_alloc_failures),
 	NICVF_DRV_STAT(tx_frames_ok),
 	NICVF_DRV_STAT(tx_tso),
 	NICVF_DRV_STAT(tx_drops),
+	NICVF_DRV_STAT(tx_timeout),
 	NICVF_DRV_STAT(txq_stop),
 	NICVF_DRV_STAT(txq_wake),
 };
@@ -380,7 +382,10 @@
 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DOOR, q);
 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STATUS, q);
 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DEBUG, q);
-		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CNM_CHG, q);
+		/* Padding, was NIC_QSET_SQ_0_7_CNM_CHG, which
+		 * produces bus errors when read
+		 */
+		p[i++] = 0;
 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1, q);
 		reg_offset = NIC_QSET_SQ_0_7_STAT_0_1 | (1 << 3);
 		p[i++] = nicvf_queue_reg_read(nic, reg_offset, q);
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -513,6 +513,7 @@
 	struct nicvf *nic = netdev_priv(netdev);
 	struct snd_queue *sq;
 	struct sq_hdr_subdesc *hdr;
+	struct sq_hdr_subdesc *tso_sqe;
 
 	sq = &nic->qs->sq[cqe_tx->sq_idx];
 
@@ -525,14 +526,26 @@
 		   __func__, cqe_tx->sq_qs, cqe_tx->sq_idx,
 		   cqe_tx->sqe_ptr, hdr->subdesc_cnt);
 
-	nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
 	nicvf_check_cqe_tx_errs(nic, cq, cqe_tx);
 	skb = (struct sk_buff *)sq->skbuff[cqe_tx->sqe_ptr];
-	/* For TSO offloaded packets only one head SKB needs to be freed */
 	if (skb) {
+		/* Check for dummy descriptor used for HW TSO offload on 88xx */
+		if (hdr->dont_send) {
+			/* Get actual TSO descriptors and free them */
+			tso_sqe =
+			 (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, hdr->rsvd2);
+			nicvf_put_sq_desc(sq, tso_sqe->subdesc_cnt + 1);
+		}
+		nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
 		prefetch(skb);
 		dev_consume_skb_any(skb);
 		sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL;
+	} else {
+		/* In case of SW TSO on 88xx, only last segment will have
+		 * a SKB attached, so just free SQEs here.
+		 */
+		if (!nic->hw_tso)
+			nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
 	}
 }
 
@@ -566,8 +579,7 @@
 
 static void nicvf_rcv_pkt_handler(struct net_device *netdev,
 				  struct napi_struct *napi,
-				  struct cmp_queue *cq,
-				  struct cqe_rx_t *cqe_rx, int cqe_type)
+				  struct cqe_rx_t *cqe_rx)
 {
 	struct sk_buff *skb;
 	struct nicvf *nic = netdev_priv(netdev);
@@ -583,7 +595,7 @@
 	}
 
 	/* Check for errors */
-	err = nicvf_check_cqe_rx_errs(nic, cq, cqe_rx);
+	err = nicvf_check_cqe_rx_errs(nic, cqe_rx);
 	if (err && !cqe_rx->rb_cnt)
 		return;
 
@@ -674,8 +686,7 @@
 			   cq_idx, cq_desc->cqe_type);
 		switch (cq_desc->cqe_type) {
 		case CQE_TYPE_RX:
-			nicvf_rcv_pkt_handler(netdev, napi, cq,
-					      cq_desc, CQE_TYPE_RX);
+			nicvf_rcv_pkt_handler(netdev, napi, cq_desc);
 			work_done++;
 		break;
 		case CQE_TYPE_SEND:
@@ -820,7 +831,7 @@
 	nicvf_disable_intr(nic, NICVF_INTR_CQ, qidx);
 
 	/* Schedule NAPI */
-	napi_schedule(&cq_poll->napi);
+	napi_schedule_irqoff(&cq_poll->napi);
 
 	/* Clear interrupt */
 	nicvf_clear_intr(nic, NICVF_INTR_CQ, qidx);
@@ -891,6 +902,31 @@
 	}
 }
 
+static void nicvf_set_irq_affinity(struct nicvf *nic)
+{
+	int vec, cpu;
+	int irqnum;
+
+	for (vec = 0; vec < nic->num_vec; vec++) {
+		if (!nic->irq_allocated[vec])
+			continue;
+
+		if (!zalloc_cpumask_var(&nic->affinity_mask[vec], GFP_KERNEL))
+			return;
+		 /* CQ interrupts */
+		if (vec < NICVF_INTR_ID_SQ)
+			/* Leave CPU0 for RBDR and other interrupts */
+			cpu = nicvf_netdev_qidx(nic, vec) + 1;
+		else
+			cpu = 0;
+
+		cpumask_set_cpu(cpumask_local_spread(cpu, nic->node),
+				nic->affinity_mask[vec]);
+		irqnum = nic->msix_entries[vec].vector;
+		irq_set_affinity_hint(irqnum, nic->affinity_mask[vec]);
+	}
+}
+
 static int nicvf_register_interrupts(struct nicvf *nic)
 {
 	int irq, ret = 0;
@@ -936,8 +972,13 @@
 	ret = request_irq(nic->msix_entries[irq].vector,
 			  nicvf_qs_err_intr_handler,
 			  0, nic->irq_name[irq], nic);
-	if (!ret)
-		nic->irq_allocated[irq] = true;
+	if (ret)
+		goto err;
+
+	nic->irq_allocated[irq] = true;
+
+	/* Set IRQ affinities */
+	nicvf_set_irq_affinity(nic);
 
 err:
 	if (ret)
@@ -955,6 +996,9 @@
 		if (!nic->irq_allocated[irq])
 			continue;
 
+		irq_set_affinity_hint(nic->msix_entries[irq].vector, NULL);
+		free_cpumask_var(nic->affinity_mask[irq]);
+
 		if (irq < NICVF_INTR_ID_SQ)
 			free_irq(nic->msix_entries[irq].vector, nic->napi[irq]);
 		else
@@ -1117,7 +1161,6 @@
 
 	/* Clear multiqset info */
 	nic->pnicvf = nic;
-	nic->sqs_count = 0;
 
 	return 0;
 }
@@ -1346,6 +1389,9 @@
 	drv_stats->tx_frames_ok = stats->tx_ucast_frames_ok +
 				  stats->tx_bcast_frames_ok +
 				  stats->tx_mcast_frames_ok;
+	drv_stats->rx_frames_ok = stats->rx_ucast_frames +
+				  stats->rx_bcast_frames +
+				  stats->rx_mcast_frames;
 	drv_stats->rx_drops = stats->rx_drop_red +
 			      stats->rx_drop_overrun;
 	drv_stats->tx_drops = stats->tx_drops;
@@ -1386,6 +1432,7 @@
 		netdev_warn(dev, "%s: Transmit timed out, resetting\n",
 			    dev->name);
 
+	nic->drv_stats.tx_timeout++;
 	schedule_work(&nic->reset_task);
 }
 
@@ -1460,6 +1507,7 @@
 	struct net_device *netdev;
 	struct nicvf *nic;
 	int    err, qcount;
+	u16    sdevid;
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -1530,6 +1578,13 @@
 
 	nicvf_send_vf_struct(nic);
 
+	if (!pass1_silicon(nic->pdev))
+		nic->hw_tso = true;
+
+	pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid);
+	if (sdevid == 0xA134)
+		nic->t88 = true;
+
 	/* Check if this VF is in QS only mode */
 	if (nic->sqs_mode)
 		return 0;
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
@@ -18,13 +18,14 @@
 #include "q_struct.h"
 #include "nicvf_queues.h"
 
-struct rbuf_info {
-	struct page *page;
-	void	*data;
-	u64	offset;
-};
+static void nicvf_get_page(struct nicvf *nic)
+{
+	if (!nic->rb_pageref || !nic->rb_page)
+		return;
 
-#define GET_RBUF_INFO(x) ((struct rbuf_info *)(x - NICVF_RCV_BUF_ALIGN_BYTES))
+	atomic_add(nic->rb_pageref, &nic->rb_page->_count);
+	nic->rb_pageref = 0;
+}
 
 /* Poll a register for a specific value */
 static int nicvf_poll_reg(struct nicvf *nic, int qidx,
@@ -86,73 +87,53 @@
 static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, gfp_t gfp,
 					 u32 buf_len, u64 **rbuf)
 {
-	u64 data;
-	struct rbuf_info *rinfo;
-	int order = get_order(buf_len);
+	int order = (PAGE_SIZE <= 4096) ?  PAGE_ALLOC_COSTLY_ORDER : 0;
 
 	/* Check if request can be accomodated in previous allocated page */
-	if (nic->rb_page) {
-		if ((nic->rb_page_offset + buf_len + buf_len) >
-		    (PAGE_SIZE << order)) {
-			nic->rb_page = NULL;
-		} else {
-			nic->rb_page_offset += buf_len;
-			get_page(nic->rb_page);
-		}
+	if (nic->rb_page &&
+	    ((nic->rb_page_offset + buf_len) < (PAGE_SIZE << order))) {
+		nic->rb_pageref++;
+		goto ret;
 	}
 
+	nicvf_get_page(nic);
+	nic->rb_page = NULL;
+
 	/* Allocate a new page */
 	if (!nic->rb_page) {
 		nic->rb_page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN,
 					   order);
 		if (!nic->rb_page) {
-			netdev_err(nic->netdev,
-				   "Failed to allocate new rcv buffer\n");
+			nic->drv_stats.rcv_buffer_alloc_failures++;
 			return -ENOMEM;
 		}
 		nic->rb_page_offset = 0;
 	}
 
-	data = (u64)page_address(nic->rb_page) + nic->rb_page_offset;
-
-	/* Align buffer addr to cache line i.e 128 bytes */
-	rinfo = (struct rbuf_info *)(data + NICVF_RCV_BUF_ALIGN_LEN(data));
-	/* Save page address for reference updation */
-	rinfo->page = nic->rb_page;
-	/* Store start address for later retrieval */
-	rinfo->data = (void *)data;
-	/* Store alignment offset */
-	rinfo->offset = NICVF_RCV_BUF_ALIGN_LEN(data);
+ret:
+	*rbuf = (u64 *)((u64)page_address(nic->rb_page) + nic->rb_page_offset);
+	nic->rb_page_offset += buf_len;
 
-	data += rinfo->offset;
-
-	/* Give next aligned address to hw for DMA */
-	*rbuf = (u64 *)(data + NICVF_RCV_BUF_ALIGN_BYTES);
 	return 0;
 }
 
-/* Retrieve actual buffer start address and build skb for received packet */
+/* Build skb around receive buffer */
 static struct sk_buff *nicvf_rb_ptr_to_skb(struct nicvf *nic,
 					   u64 rb_ptr, int len)
 {
+	void *data;
 	struct sk_buff *skb;
-	struct rbuf_info *rinfo;
 
-	rb_ptr = (u64)phys_to_virt(rb_ptr);
-	/* Get buffer start address and alignment offset */
-	rinfo = GET_RBUF_INFO(rb_ptr);
+	data = phys_to_virt(rb_ptr);
 
 	/* Now build an skb to give to stack */
-	skb = build_skb(rinfo->data, RCV_FRAG_LEN);
+	skb = build_skb(data, RCV_FRAG_LEN);
 	if (!skb) {
-		put_page(rinfo->page);
+		put_page(virt_to_page(data));
 		return NULL;
 	}
 
-	/* Set correct skb->data */
-	skb_reserve(skb, rinfo->offset + NICVF_RCV_BUF_ALIGN_BYTES);
-
-	prefetch((void *)rb_ptr);
+	prefetch(skb->data);
 	return skb;
 }
 
@@ -187,6 +168,9 @@
 		desc = GET_RBDR_DESC(rbdr, idx);
 		desc->buf_addr = virt_to_phys(rbuf) >> NICVF_RCV_BUF_ALIGN;
 	}
+
+	nicvf_get_page(nic);
+
 	return 0;
 }
 
@@ -196,7 +180,6 @@
 	int head, tail;
 	u64 buf_addr;
 	struct rbdr_entry_t *desc;
-	struct rbuf_info *rinfo;
 
 	if (!rbdr)
 		return;
@@ -212,16 +195,14 @@
 	while (head != tail) {
 		desc = GET_RBDR_DESC(rbdr, head);
 		buf_addr = desc->buf_addr << NICVF_RCV_BUF_ALIGN;
-		rinfo = GET_RBUF_INFO((u64)phys_to_virt(buf_addr));
-		put_page(rinfo->page);
+		put_page(virt_to_page(phys_to_virt(buf_addr)));
 		head++;
 		head &= (rbdr->dmem.q_len - 1);
 	}
 	/* Free SKB of tail desc */
 	desc = GET_RBDR_DESC(rbdr, tail);
 	buf_addr = desc->buf_addr << NICVF_RCV_BUF_ALIGN;
-	rinfo = GET_RBUF_INFO((u64)phys_to_virt(buf_addr));
-	put_page(rinfo->page);
+	put_page(virt_to_page(phys_to_virt(buf_addr)));
 
 	/* Free RBDR ring */
 	nicvf_free_q_desc_mem(nic, &rbdr->dmem);
@@ -273,6 +254,8 @@
 		new_rb++;
 	}
 
+	nicvf_get_page(nic);
+
 	/* make sure all memory stores are done before ringing doorbell */
 	smp_wmb();
 
@@ -330,7 +313,7 @@
 		return err;
 
 	cq->desc = cq->dmem.base;
-	cq->thresh = CMP_QUEUE_CQE_THRESH;
+	cq->thresh = pass1_silicon(nic->pdev) ? 0 : CMP_QUEUE_CQE_THRESH;
 	nic->cq_coalesce_usecs = (CMP_QUEUE_TIMER_THRESH * 0.05) - 1;
 
 	return 0;
@@ -550,6 +533,7 @@
 		nicvf_config_vlan_stripping(nic, nic->netdev->features);
 
 	/* Enable Receive queue */
+	memset(&rq_cfg, 0, sizeof(struct rq_cfg));
 	rq_cfg.ena = 1;
 	rq_cfg.tcp_ena = 0;
 	nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, *(u64 *)&rq_cfg);
@@ -582,6 +566,7 @@
 			      qidx, (u64)(cq->dmem.phys_base));
 
 	/* Enable Completion queue */
+	memset(&cq_cfg, 0, sizeof(struct cq_cfg));
 	cq_cfg.ena = 1;
 	cq_cfg.reset = 0;
 	cq_cfg.caching = 0;
@@ -630,6 +615,7 @@
 			      qidx, (u64)(sq->dmem.phys_base));
 
 	/* Enable send queue  & set queue size */
+	memset(&sq_cfg, 0, sizeof(struct sq_cfg));
 	sq_cfg.ena = 1;
 	sq_cfg.reset = 0;
 	sq_cfg.ldwb = 0;
@@ -666,6 +652,7 @@
 
 	/* Enable RBDR  & set queue size */
 	/* Buffer size should be in multiples of 128 bytes */
+	memset(&rbdr_cfg, 0, sizeof(struct rbdr_cfg));
 	rbdr_cfg.ena = 1;
 	rbdr_cfg.reset = 0;
 	rbdr_cfg.ldwb = 0;
@@ -951,16 +938,22 @@
 	return num_edescs + sh->gso_segs;
 }
 
+#define POST_CQE_DESC_COUNT 2
+
 /* Get the number of SQ descriptors needed to xmit this skb */
 static int nicvf_sq_subdesc_required(struct nicvf *nic, struct sk_buff *skb)
 {
 	int subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT;
 
-	if (skb_shinfo(skb)->gso_size) {
+	if (skb_shinfo(skb)->gso_size && !nic->hw_tso) {
 		subdesc_cnt = nicvf_tso_count_subdescs(skb);
 		return subdesc_cnt;
 	}
 
+	/* Dummy descriptors to get TSO pkt completion notification */
+	if (nic->t88 && nic->hw_tso && skb_shinfo(skb)->gso_size)
+		subdesc_cnt += POST_CQE_DESC_COUNT;
+
 	if (skb_shinfo(skb)->nr_frags)
 		subdesc_cnt += skb_shinfo(skb)->nr_frags;
 
@@ -971,21 +964,28 @@
  * First subdescriptor for every send descriptor.
  */
 static inline void
-nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry,
+nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry,
 			 int subdesc_cnt, struct sk_buff *skb, int len)
 {
 	int proto;
 	struct sq_hdr_subdesc *hdr;
 
 	hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, qentry);
-	sq->skbuff[qentry] = (u64)skb;
-
 	memset(hdr, 0, SND_QUEUE_DESC_SIZE);
 	hdr->subdesc_type = SQ_DESC_TYPE_HEADER;
-	/* Enable notification via CQE after processing SQE */
-	hdr->post_cqe = 1;
-	/* No of subdescriptors following this */
-	hdr->subdesc_cnt = subdesc_cnt;
+
+	if (nic->t88 && nic->hw_tso && skb_shinfo(skb)->gso_size) {
+		/* post_cqe = 0, to avoid HW posting a CQE for every TSO
+		 * segment transmitted on 88xx.
+		 */
+		hdr->subdesc_cnt = subdesc_cnt - POST_CQE_DESC_COUNT;
+	} else {
+		sq->skbuff[qentry] = (u64)skb;
+		/* Enable notification via CQE after processing SQE */
+		hdr->post_cqe = 1;
+		/* No of subdescriptors following this */
+		hdr->subdesc_cnt = subdesc_cnt;
+	}
 	hdr->tot_len = len;
 
 	/* Offload checksum calculation to HW */
@@ -1007,6 +1007,15 @@
 			break;
 		}
 	}
+
+	if (nic->hw_tso && skb_shinfo(skb)->gso_size) {
+		hdr->tso = 1;
+		hdr->tso_start = skb_transport_offset(skb) + tcp_hdrlen(skb);
+		hdr->tso_max_paysize = skb_shinfo(skb)->gso_size;
+		/* For non-tunneled pkts, point this to L2 ethertype */
+		hdr->inner_l3_offset = skb_network_offset(skb) - 2;
+		nic->drv_stats.tx_tso++;
+	}
 }
 
 /* SQ GATHER subdescriptor
@@ -1027,6 +1036,37 @@
 	gather->addr = data;
 }
 
+/* Add HDR + IMMEDIATE subdescriptors right after descriptors of a TSO
+ * packet so that a CQE is posted as a notifation for transmission of
+ * TSO packet.
+ */
+static inline void nicvf_sq_add_cqe_subdesc(struct snd_queue *sq, int qentry,
+					    int tso_sqe, struct sk_buff *skb)
+{
+	struct sq_imm_subdesc *imm;
+	struct sq_hdr_subdesc *hdr;
+
+	sq->skbuff[qentry] = (u64)skb;
+
+	hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, qentry);
+	memset(hdr, 0, SND_QUEUE_DESC_SIZE);
+	hdr->subdesc_type = SQ_DESC_TYPE_HEADER;
+	/* Enable notification via CQE after processing SQE */
+	hdr->post_cqe = 1;
+	/* There is no packet to transmit here */
+	hdr->dont_send = 1;
+	hdr->subdesc_cnt = POST_CQE_DESC_COUNT - 1;
+	hdr->tot_len = 1;
+	/* Actual TSO header SQE index, needed for cleanup */
+	hdr->rsvd2 = tso_sqe;
+
+	qentry = nicvf_get_nxt_sqentry(sq, qentry);
+	imm = (struct sq_imm_subdesc *)GET_SQ_DESC(sq, qentry);
+	memset(imm, 0, SND_QUEUE_DESC_SIZE);
+	imm->subdesc_type = SQ_DESC_TYPE_IMMEDIATE;
+	imm->len = 1;
+}
+
 /* Segment a TSO packet into 'gso_size' segments and append
  * them to SQ for transfer
  */
@@ -1076,7 +1116,7 @@
 			data_left -= size;
 			tso_build_data(skb, &tso, size);
 		}
-		nicvf_sq_add_hdr_subdesc(sq, hdr_qentry,
+		nicvf_sq_add_hdr_subdesc(nic, sq, hdr_qentry,
 					 seg_subdescs - 1, skb, seg_len);
 		sq->skbuff[hdr_qentry] = (u64)NULL;
 		qentry = nicvf_get_nxt_sqentry(sq, qentry);
@@ -1100,7 +1140,7 @@
 int nicvf_sq_append_skb(struct nicvf *nic, struct sk_buff *skb)
 {
 	int i, size;
-	int subdesc_cnt;
+	int subdesc_cnt, tso_sqe = 0;
 	int sq_num, qentry;
 	struct queue_set *qs;
 	struct snd_queue *sq;
@@ -1129,11 +1169,13 @@
 	qentry = nicvf_get_sq_desc(sq, subdesc_cnt);
 
 	/* Check if its a TSO packet */
-	if (skb_shinfo(skb)->gso_size)
+	if (skb_shinfo(skb)->gso_size && !nic->hw_tso)
 		return nicvf_sq_append_tso(nic, sq, sq_num, qentry, skb);
 
 	/* Add SQ header subdesc */
-	nicvf_sq_add_hdr_subdesc(sq, qentry, subdesc_cnt - 1, skb, skb->len);
+	nicvf_sq_add_hdr_subdesc(nic, sq, qentry, subdesc_cnt - 1,
+				 skb, skb->len);
+	tso_sqe = qentry;
 
 	/* Add SQ gather subdescs */
 	qentry = nicvf_get_nxt_sqentry(sq, qentry);
@@ -1157,6 +1199,11 @@
 	}
 
 doorbell:
+	if (nic->t88 && skb_shinfo(skb)->gso_size) {
+		qentry = nicvf_get_nxt_sqentry(sq, qentry);
+		nicvf_sq_add_cqe_subdesc(sq, qentry, tso_sqe, skb);
+	}
+
 	/* make sure all memory stores are done before ringing doorbell */
 	smp_wmb();
 
@@ -1234,153 +1281,93 @@
 	return skb;
 }
 
-/* Enable interrupt */
-void nicvf_enable_intr(struct nicvf *nic, int int_type, int q_idx)
+static u64 nicvf_int_type_to_mask(int int_type, int q_idx)
 {
 	u64 reg_val;
 
-	reg_val = nicvf_reg_read(nic, NIC_VF_ENA_W1S);
-
 	switch (int_type) {
 	case NICVF_INTR_CQ:
-		reg_val |= ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
+		reg_val = ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
 		break;
 	case NICVF_INTR_SQ:
-		reg_val |= ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
+		reg_val = ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
 		break;
 	case NICVF_INTR_RBDR:
-		reg_val |= ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
+		reg_val = ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
 		break;
 	case NICVF_INTR_PKT_DROP:
-		reg_val |= (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
+		reg_val = (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
 		break;
 	case NICVF_INTR_TCP_TIMER:
-		reg_val |= (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
+		reg_val = (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
 		break;
 	case NICVF_INTR_MBOX:
-		reg_val |= (1ULL << NICVF_INTR_MBOX_SHIFT);
+		reg_val = (1ULL << NICVF_INTR_MBOX_SHIFT);
 		break;
 	case NICVF_INTR_QS_ERR:
-		reg_val |= (1ULL << NICVF_INTR_QS_ERR_SHIFT);
+		reg_val = (1ULL << NICVF_INTR_QS_ERR_SHIFT);
 		break;
 	default:
-		netdev_err(nic->netdev,
-			   "Failed to enable interrupt: unknown type\n");
-		break;
+		reg_val = 0;
 	}
 
-	nicvf_reg_write(nic, NIC_VF_ENA_W1S, reg_val);
+	return reg_val;
+}
+
+/* Enable interrupt */
+void nicvf_enable_intr(struct nicvf *nic, int int_type, int q_idx)
+{
+	u64 mask = nicvf_int_type_to_mask(int_type, q_idx);
+
+	if (!mask) {
+		netdev_dbg(nic->netdev,
+			   "Failed to enable interrupt: unknown type\n");
+		return;
+	}
+	nicvf_reg_write(nic, NIC_VF_ENA_W1S,
+			nicvf_reg_read(nic, NIC_VF_ENA_W1S) | mask);
 }
 
 /* Disable interrupt */
 void nicvf_disable_intr(struct nicvf *nic, int int_type, int q_idx)
 {
-	u64 reg_val = 0;
+	u64 mask = nicvf_int_type_to_mask(int_type, q_idx);
 
-	switch (int_type) {
-	case NICVF_INTR_CQ:
-		reg_val |= ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
-		break;
-	case NICVF_INTR_SQ:
-		reg_val |= ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
-		break;
-	case NICVF_INTR_RBDR:
-		reg_val |= ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
-		break;
-	case NICVF_INTR_PKT_DROP:
-		reg_val |= (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
-		break;
-	case NICVF_INTR_TCP_TIMER:
-		reg_val |= (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
-		break;
-	case NICVF_INTR_MBOX:
-		reg_val |= (1ULL << NICVF_INTR_MBOX_SHIFT);
-		break;
-	case NICVF_INTR_QS_ERR:
-		reg_val |= (1ULL << NICVF_INTR_QS_ERR_SHIFT);
-		break;
-	default:
-		netdev_err(nic->netdev,
+	if (!mask) {
+		netdev_dbg(nic->netdev,
 			   "Failed to disable interrupt: unknown type\n");
-		break;
+		return;
 	}
 
-	nicvf_reg_write(nic, NIC_VF_ENA_W1C, reg_val);
+	nicvf_reg_write(nic, NIC_VF_ENA_W1C, mask);
 }
 
 /* Clear interrupt */
 void nicvf_clear_intr(struct nicvf *nic, int int_type, int q_idx)
 {
-	u64 reg_val = 0;
+	u64 mask = nicvf_int_type_to_mask(int_type, q_idx);
 
-	switch (int_type) {
-	case NICVF_INTR_CQ:
-		reg_val = ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
-		break;
-	case NICVF_INTR_SQ:
-		reg_val = ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
-		break;
-	case NICVF_INTR_RBDR:
-		reg_val = ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
-		break;
-	case NICVF_INTR_PKT_DROP:
-		reg_val = (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
-		break;
-	case NICVF_INTR_TCP_TIMER:
-		reg_val = (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
-		break;
-	case NICVF_INTR_MBOX:
-		reg_val = (1ULL << NICVF_INTR_MBOX_SHIFT);
-		break;
-	case NICVF_INTR_QS_ERR:
-		reg_val |= (1ULL << NICVF_INTR_QS_ERR_SHIFT);
-		break;
-	default:
-		netdev_err(nic->netdev,
+	if (!mask) {
+		netdev_dbg(nic->netdev,
 			   "Failed to clear interrupt: unknown type\n");
-		break;
+		return;
 	}
 
-	nicvf_reg_write(nic, NIC_VF_INT, reg_val);
+	nicvf_reg_write(nic, NIC_VF_INT, mask);
 }
 
 /* Check if interrupt is enabled */
 int nicvf_is_intr_enabled(struct nicvf *nic, int int_type, int q_idx)
 {
-	u64 reg_val;
-	u64 mask = 0xff;
-
-	reg_val = nicvf_reg_read(nic, NIC_VF_ENA_W1S);
-
-	switch (int_type) {
-	case NICVF_INTR_CQ:
-		mask = ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
-		break;
-	case NICVF_INTR_SQ:
-		mask = ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
-		break;
-	case NICVF_INTR_RBDR:
-		mask = ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
-		break;
-	case NICVF_INTR_PKT_DROP:
-		mask = NICVF_INTR_PKT_DROP_MASK;
-		break;
-	case NICVF_INTR_TCP_TIMER:
-		mask = NICVF_INTR_TCP_TIMER_MASK;
-		break;
-	case NICVF_INTR_MBOX:
-		mask = NICVF_INTR_MBOX_MASK;
-		break;
-	case NICVF_INTR_QS_ERR:
-		mask = NICVF_INTR_QS_ERR_MASK;
-		break;
-	default:
-		netdev_err(nic->netdev,
+	u64 mask = nicvf_int_type_to_mask(int_type, q_idx);
+	/* If interrupt type is unknown, we treat it disabled. */
+	if (!mask) {
+		netdev_dbg(nic->netdev,
 			   "Failed to check interrupt enable: unknown type\n");
-		break;
+		return 0;
 	}
 
-	return (reg_val & mask);
+	return mask & nicvf_reg_read(nic, NIC_VF_ENA_W1S);
 }
 
 void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx)
@@ -1410,16 +1397,12 @@
 }
 
 /* Check for errors in the receive cmp.queue entry */
-int nicvf_check_cqe_rx_errs(struct nicvf *nic,
-			    struct cmp_queue *cq, struct cqe_rx_t *cqe_rx)
+int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
 {
 	struct nicvf_hw_stats *stats = &nic->hw_stats;
-	struct nicvf_drv_stats *drv_stats = &nic->drv_stats;
 
-	if (!cqe_rx->err_level && !cqe_rx->err_opcode) {
-		drv_stats->rx_frames_ok++;
+	if (!cqe_rx->err_level && !cqe_rx->err_opcode)
 		return 0;
-	}
 
 	if (netif_msg_rx_err(nic))
 		netdev_err(nic->netdev,
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
@@ -75,7 +75,7 @@
  */
 #define CMP_QSIZE		CMP_QUEUE_SIZE2
 #define CMP_QUEUE_LEN		(1ULL << (CMP_QSIZE + 10))
-#define CMP_QUEUE_CQE_THRESH	0
+#define CMP_QUEUE_CQE_THRESH	(NAPI_POLL_WEIGHT / 2)
 #define CMP_QUEUE_TIMER_THRESH	80 /* ~2usec */
 
 #define RBDR_SIZE		RBDR_SIZE0
@@ -83,10 +83,8 @@
 #define MAX_RCV_BUF_COUNT	(1ULL << (RBDR_SIZE6 + 13))
 #define RBDR_THRESH		(RCV_BUF_COUNT / 2)
 #define DMA_BUFFER_LEN		2048 /* In multiples of 128bytes */
-#define RCV_FRAG_LEN	(SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \
-			 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + \
-			 (NICVF_RCV_BUF_ALIGN_BYTES * 2))
-#define RCV_DATA_OFFSET		NICVF_RCV_BUF_ALIGN_BYTES
+#define RCV_FRAG_LEN	 (SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \
+			 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 
 #define MAX_CQES_FOR_TX		((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \
 				 MAX_CQE_PER_PKT_XMIT)
@@ -108,10 +106,6 @@
 #define NICVF_SQ_BASE_ALIGN_BYTES	128  /* 7 bits */
 
 #define NICVF_ALIGNED_ADDR(ADDR, ALIGN_BYTES)	ALIGN(ADDR, ALIGN_BYTES)
-#define NICVF_ADDR_ALIGN_LEN(ADDR, BYTES)\
-	(NICVF_ALIGNED_ADDR(ADDR, BYTES) - BYTES)
-#define NICVF_RCV_BUF_ALIGN_LEN(X)\
-	(NICVF_ALIGNED_ADDR(X, NICVF_RCV_BUF_ALIGN_BYTES) - X)
 
 /* Queue enable/disable */
 #define NICVF_SQ_EN		BIT_ULL(19)
@@ -344,8 +338,7 @@
 /* Stats */
 void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx);
 void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx);
-int nicvf_check_cqe_rx_errs(struct nicvf *nic,
-			    struct cmp_queue *cq, struct cqe_rx_t *cqe_rx);
+int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx);
 int nicvf_check_cqe_tx_errs(struct nicvf *nic,
 			    struct cmp_queue *cq, struct cqe_send_t *cqe_tx);
 #endif /* NICVF_QUEUES_H */
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/q_struct.h
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/q_struct.h
@@ -545,25 +545,28 @@
 	u64    subdesc_cnt:8;
 	u64    csum_l4:2;
 	u64    csum_l3:1;
-	u64    rsvd0:5;
+	u64    csum_inner_l4:2;
+	u64    csum_inner_l3:1;
+	u64    rsvd0:2;
 	u64    l4_offset:8;
 	u64    l3_offset:8;
 	u64    rsvd1:4;
 	u64    tot_len:20; /* W0 */
 
-	u64    tso_sdc_cont:8;
-	u64    tso_sdc_first:8;
-	u64    tso_l4_offset:8;
-	u64    tso_flags_last:12;
-	u64    tso_flags_first:12;
-	u64    rsvd2:2;
+	u64    rsvd2:24;
+	u64    inner_l4_offset:8;
+	u64    inner_l3_offset:8;
+	u64    tso_start:8;
+	u64    rsvd3:2;
 	u64    tso_max_paysize:14; /* W1 */
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
 	u64    tot_len:20;
 	u64    rsvd1:4;
 	u64    l3_offset:8;
 	u64    l4_offset:8;
-	u64    rsvd0:5;
+	u64    rsvd0:2;
+	u64    csum_inner_l3:1;
+	u64    csum_inner_l4:2;
 	u64    csum_l3:1;
 	u64    csum_l4:2;
 	u64    subdesc_cnt:8;
@@ -574,12 +577,11 @@
 	u64    subdesc_type:4; /* W0 */
 
 	u64    tso_max_paysize:14;
-	u64    rsvd2:2;
-	u64    tso_flags_first:12;
-	u64    tso_flags_last:12;
-	u64    tso_l4_offset:8;
-	u64    tso_sdc_first:8;
-	u64    tso_sdc_cont:8; /* W1 */
+	u64    rsvd3:2;
+	u64    tso_start:8;
+	u64    inner_l3_offset:8;
+	u64    inner_l4_offset:8;
+	u64    rsvd2:24; /* W1 */
 #endif
 };
 
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -434,12 +434,14 @@
 
 	bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_LOW_POWER);
 	/* Set interleaved running disparity for RXAUI */
-	if (bgx->lmac_type != BGX_MODE_RXAUI)
-		bgx_reg_modify(bgx, lmacid,
-			       BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
-	else
+	if (bgx->lmac_type == BGX_MODE_RXAUI)
 		bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL,
-			       SPU_MISC_CTL_RX_DIS | SPU_MISC_CTL_INTLV_RDISP);
+			       SPU_MISC_CTL_INTLV_RDISP);
+
+	/* Clear receive packet disable */
+	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_MISC_CONTROL);
+	cfg &= ~SPU_MISC_CTL_RX_DIS;
+	bgx_reg_write(bgx, lmacid, BGX_SPUX_MISC_CONTROL, cfg);
 
 	/* clear all interrupts */
 	cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_RX_INT);
@@ -512,7 +514,6 @@
 	int lmac_type = bgx->lmac_type;
 	u64 cfg;
 
-	bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
 	if (bgx->use_training) {
 		cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
 		if (!(cfg & (1ull << 13))) {
@@ -549,7 +550,9 @@
 	}
 
 	/* Clear rcvflt bit (latching high) and read it back */
-	bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS2, SPU_STATUS2_RCVFLT);
+	if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT)
+		bgx_reg_modify(bgx, lmacid,
+			       BGX_SPUX_STATUS2, SPU_STATUS2_RCVFLT);
 	if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
 		dev_err(&bgx->pdev->dev, "Receive fault, retry training\n");
 		if (bgx->use_training) {
@@ -568,13 +571,6 @@
 		return -1;
 	}
 
-	/* Wait for MAC RX to be ready */
-	if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_RX_CTL,
-			 SMU_RX_CTL_STATUS, true)) {
-		dev_err(&bgx->pdev->dev, "SMU RX link not okay\n");
-		return -1;
-	}
-
 	/* Wait for BGX RX to be idle */
 	if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL, SMU_CTL_RX_IDLE, false)) {
 		dev_err(&bgx->pdev->dev, "SMU RX not idle\n");
@@ -587,29 +583,25 @@
 		return -1;
 	}
 
-	if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
-		dev_err(&bgx->pdev->dev, "Receive fault\n");
-		return -1;
-	}
+	/* Check for MAC RX faults */
+	cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_RX_CTL);
+	/* 0 - Link is okay, 1 - Local fault, 2 - Remote fault */
+	cfg &= SMU_RX_CTL_STATUS;
+	if (!cfg)
+		return 0;
 
-	/* Receive link is latching low. Force it high and verify it */
-	bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS1, SPU_STATUS1_RCV_LNK);
-	if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_STATUS1,
-			 SPU_STATUS1_RCV_LNK, false)) {
-		dev_err(&bgx->pdev->dev, "SPU receive link down\n");
-		return -1;
-	}
+	/* Rx local/remote fault seen.
+	 * Do lmac reinit to see if condition recovers
+	 */
+	bgx_lmac_xaui_init(bgx, lmacid, bgx->lmac_type);
 
-	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_MISC_CONTROL);
-	cfg &= ~SPU_MISC_CTL_RX_DIS;
-	bgx_reg_write(bgx, lmacid, BGX_SPUX_MISC_CONTROL, cfg);
-	return 0;
+	return -1;
 }
 
 static void bgx_poll_for_link(struct work_struct *work)
 {
 	struct lmac *lmac;
-	u64 link;
+	u64 spu_link, smu_link;
 
 	lmac = container_of(work, struct lmac, dwork.work);
 
@@ -619,8 +611,11 @@
 	bgx_poll_reg(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1,
 		     SPU_STATUS1_RCV_LNK, false);
 
-	link = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1);
-	if (link & SPU_STATUS1_RCV_LNK) {
+	spu_link = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1);
+	smu_link = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SMUX_RX_CTL);
+
+	if ((spu_link & SPU_STATUS1_RCV_LNK) &&
+	    !(smu_link & SMU_RX_CTL_STATUS)) {
 		lmac->link_up = 1;
 		if (lmac->bgx->lmac_type == BGX_MODE_XLAUI)
 			lmac->last_speed = 40000;
@@ -634,9 +629,15 @@
 	}
 
 	if (lmac->last_link != lmac->link_up) {
+		if (lmac->link_up) {
+			if (bgx_xaui_check_link(lmac)) {
+				/* Errors, clear link_up state */
+				lmac->link_up = 0;
+				lmac->last_speed = SPEED_UNKNOWN;
+				lmac->last_duplex = DUPLEX_UNKNOWN;
+			}
+		}
 		lmac->last_link = lmac->link_up;
-		if (lmac->link_up)
-			bgx_xaui_check_link(lmac);
 	}
 
 	queue_delayed_work(lmac->check_link, &lmac->dwork, HZ * 2);
@@ -708,7 +709,7 @@
 static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
 {
 	struct lmac *lmac;
-	u64 cmrx_cfg;
+	u64 cfg;
 
 	lmac = &bgx->lmac[lmacid];
 	if (lmac->check_link) {
@@ -717,9 +718,33 @@
 		destroy_workqueue(lmac->check_link);
 	}
 
-	cmrx_cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
-	cmrx_cfg &= ~(1 << 15);
-	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cmrx_cfg);
+	/* Disable packet reception */
+	cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+	cfg &= ~CMR_PKT_RX_EN;
+	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+
+	/* Give chance for Rx/Tx FIFO to get drained */
+	bgx_poll_reg(bgx, lmacid, BGX_CMRX_RX_FIFO_LEN, (u64)0x1FFF, true);
+	bgx_poll_reg(bgx, lmacid, BGX_CMRX_TX_FIFO_LEN, (u64)0x3FFF, true);
+
+	/* Disable packet transmission */
+	cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+	cfg &= ~CMR_PKT_TX_EN;
+	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+
+	/* Disable serdes lanes */
+        if (!lmac->is_sgmii)
+                bgx_reg_modify(bgx, lmacid,
+                               BGX_SPUX_CONTROL1, SPU_CTL_LOW_POWER);
+        else
+                bgx_reg_modify(bgx, lmacid,
+                               BGX_GMP_PCS_MRX_CTL, PCS_MRX_CTL_PWR_DN);
+
+	/* Disable LMAC */
+	cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+	cfg &= ~CMR_EN;
+	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+
 	bgx_flush_dmac_addrs(bgx, lmacid);
 
 	if ((bgx->lmac_type != BGX_MODE_XFI) &&
@@ -886,7 +911,8 @@
 
 #ifdef CONFIG_ACPI
 
-static int acpi_get_mac_address(struct acpi_device *adev, u8 *dst)
+static int acpi_get_mac_address(struct device *dev, struct acpi_device *adev,
+				u8 *dst)
 {
 	u8 mac[ETH_ALEN];
 	int ret;
@@ -897,10 +923,13 @@
 		goto out;
 
 	if (!is_valid_ether_addr(mac)) {
+		dev_err(dev, "MAC address invalid: %pM\n", mac);
 		ret = -EINVAL;
 		goto out;
 	}
 
+	dev_info(dev, "MAC address set to: %pM\n", mac);
+
 	memcpy(dst, mac, ETH_ALEN);
 out:
 	return ret;
@@ -911,14 +940,15 @@
 					 u32 lvl, void *context, void **rv)
 {
 	struct bgx *bgx = context;
+	struct device *dev = &bgx->pdev->dev;
 	struct acpi_device *adev;
 
 	if (acpi_bus_get_device(handle, &adev))
 		goto out;
 
-	acpi_get_mac_address(adev, bgx->lmac[bgx->lmac_count].mac);
+	acpi_get_mac_address(dev, adev, bgx->lmac[bgx->lmac_count].mac);
 
-	SET_NETDEV_DEV(&bgx->lmac[bgx->lmac_count].netdev, &bgx->pdev->dev);
+	SET_NETDEV_DEV(&bgx->lmac[bgx->lmac_count].netdev, dev);
 
 	bgx->lmac[bgx->lmac_count].lmacid = bgx->lmac_count;
 out:
@@ -968,34 +998,45 @@
 
 static int bgx_init_of_phy(struct bgx *bgx)
 {
-	struct device_node *np;
-	struct device_node *np_child;
+	struct fwnode_handle *fwn;
 	u8 lmac = 0;
-	char bgx_sel[5];
 	const char *mac;
 
-	/* Get BGX node from DT */
-	snprintf(bgx_sel, 5, "bgx%d", bgx->bgx_id);
-	np = of_find_node_by_name(NULL, bgx_sel);
-	if (!np)
-		return -ENODEV;
-
-	for_each_child_of_node(np, np_child) {
-		struct device_node *phy_np = of_parse_phandle(np_child,
-							      "phy-handle", 0);
-		if (!phy_np)
-			continue;
-		bgx->lmac[lmac].phydev = of_phy_find_device(phy_np);
+	device_for_each_child_node(&bgx->pdev->dev, fwn) {
+		struct phy_device *pd;
+		struct device_node *phy_np;
+		struct device_node *node = to_of_node(fwn);
+
+		/* Should always be an OF node.  But if it is not, we
+		 * cannot handle it, so exit the loop.
+		 */
+		if (!node)
+			break;
 
-		mac = of_get_mac_address(np_child);
+		mac = of_get_mac_address(node);
 		if (mac)
 			ether_addr_copy(bgx->lmac[lmac].mac, mac);
 
 		SET_NETDEV_DEV(&bgx->lmac[lmac].netdev, &bgx->pdev->dev);
 		bgx->lmac[lmac].lmacid = lmac;
+
+		phy_np = of_parse_phandle(node, "phy-handle", 0);
+		/* If there is no phy or defective firmware presents
+		 * this cortina phy, for which there is no driver
+		 * support, ignore it.
+		 */
+		if (phy_np &&
+		    !of_device_is_compatible(phy_np, "cortina,cs4223-slice")) {
+			/* Wait until the phy drivers are available */
+			pd = of_phy_find_device(phy_np);
+			if (!pd)
+				return -EPROBE_DEFER;
+			bgx->lmac[lmac].phydev = pd;
+		}
+
 		lmac++;
 		if (lmac == MAX_LMAC_PER_BGX) {
-			of_node_put(np_child);
+			of_node_put(node);
 			break;
 		}
 	}
@@ -1026,9 +1067,6 @@
 	struct bgx *bgx = NULL;
 	u8 lmac;
 
-	/* Load octeon mdio driver */
-	octeon_mdiobus_force_mod_depencency();
-
 	bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL);
 	if (!bgx)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+++ linux-4.4.0/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
@@ -41,6 +41,7 @@
 #define BGX_CMRX_RX_STAT10		0xC0
 #define BGX_CMRX_RX_BP_DROP		0xC8
 #define BGX_CMRX_RX_DMAC_CTL		0x0E8
+#define BGX_CMRX_RX_FIFO_LEN		0x108
 #define BGX_CMR_RX_DMACX_CAM		0x200
 #define  RX_DMACX_CAM_EN			BIT_ULL(48)
 #define  RX_DMACX_CAM_LMACID(x)			(x << 49)
@@ -50,6 +51,7 @@
 #define BGX_CMR_CHAN_MSK_AND		0x450
 #define BGX_CMR_BIST_STATUS		0x460
 #define BGX_CMR_RX_LMACS		0x468
+#define BGX_CMRX_TX_FIFO_LEN		0x518
 #define BGX_CMRX_TX_STAT0		0x600
 #define BGX_CMRX_TX_STAT1		0x608
 #define BGX_CMRX_TX_STAT2		0x610
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -50,6 +50,7 @@
 #include <linux/stringify.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/nospec.h>
 #include <asm/uaccess.h>
 
 #include "common.h"
@@ -2146,6 +2147,8 @@
 			return -EPERM;
 		if (copy_from_user(&t, useraddr, sizeof(t)))
 			return -EFAULT;
+		if (t.cmd != CHELSIO_SET_QSET_PARAMS)
+			return -EINVAL;
 		if (t.qset_idx >= SGE_QSETS)
 			return -EINVAL;
 		if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
@@ -2245,6 +2248,9 @@
 		if (copy_from_user(&t, useraddr, sizeof(t)))
 			return -EFAULT;
 
+		if (t.cmd != CHELSIO_GET_QSET_PARAMS)
+			return -EINVAL;
+
 		/* Display qsets for all ports when offload enabled */
 		if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
 			q1 = 0;
@@ -2256,6 +2262,7 @@
 
 		if (t.qset_idx >= nqsets)
 			return -EINVAL;
+		t.qset_idx = array_index_nospec(t.qset_idx, nqsets);
 
 		q = &adapter->params.sge.qset[q1 + t.qset_idx];
 		t.rspq_size = q->rspq_size;
@@ -2289,6 +2296,8 @@
 			return -EBUSY;
 		if (copy_from_user(&edata, useraddr, sizeof(edata)))
 			return -EFAULT;
+		if (edata.cmd != CHELSIO_SET_QSET_NUM)
+			return -EINVAL;
 		if (edata.val < 1 ||
 			(edata.val > 1 && !(adapter->flags & USING_MSIX)))
 			return -EINVAL;
@@ -2329,6 +2338,8 @@
 			return -EPERM;
 		if (copy_from_user(&t, useraddr, sizeof(t)))
 			return -EFAULT;
+		if (t.cmd != CHELSIO_LOAD_FW)
+			return -EINVAL;
 		/* Check t.len sanity ? */
 		fw_data = memdup_user(useraddr + sizeof(t), t.len);
 		if (IS_ERR(fw_data))
@@ -2352,6 +2363,8 @@
 			return -EBUSY;
 		if (copy_from_user(&m, useraddr, sizeof(m)))
 			return -EFAULT;
+		if (m.cmd != CHELSIO_SETMTUTAB)
+			return -EINVAL;
 		if (m.nmtus != NMTUS)
 			return -EINVAL;
 		if (m.mtus[0] < 81)	/* accommodate SACK */
@@ -2393,6 +2406,8 @@
 			return -EBUSY;
 		if (copy_from_user(&m, useraddr, sizeof(m)))
 			return -EFAULT;
+		if (m.cmd != CHELSIO_SET_PM)
+			return -EINVAL;
 		if (!is_power_of_2(m.rx_pg_sz) ||
 			!is_power_of_2(m.tx_pg_sz))
 			return -EINVAL;	/* not power of 2 */
@@ -2422,10 +2437,14 @@
 
 		if (!is_offload(adapter))
 			return -EOPNOTSUPP;
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		if (!(adapter->flags & FULL_INIT_DONE))
 			return -EIO;	/* need the memory controllers */
 		if (copy_from_user(&t, useraddr, sizeof(t)))
 			return -EFAULT;
+		if (t.cmd != CHELSIO_GET_MEM)
+			return -EINVAL;
 		if ((t.addr & 7) || (t.len & 7))
 			return -EINVAL;
 		if (t.mem_id == MEM_CM)
@@ -2478,6 +2497,8 @@
 			return -EAGAIN;
 		if (copy_from_user(&t, useraddr, sizeof(t)))
 			return -EFAULT;
+		if (t.cmd != CHELSIO_SET_TRACE_FILTER)
+			return -EINVAL;
 
 		tp = (const struct trace_params *)&t.sip;
 		if (t.config_tx)
@@ -3241,7 +3262,7 @@
 	if (!adapter->regs) {
 		dev_err(&pdev->dev, "cannot map device registers\n");
 		err = -ENOMEM;
-		goto out_free_adapter;
+		goto out_free_adapter_nofail;
 	}
 
 	adapter->pdev = pdev;
@@ -3359,6 +3380,9 @@
 		if (adapter->port[i])
 			free_netdev(adapter->port[i]);
 
+out_free_adapter_nofail:
+	kfree_skb(adapter->nofail_skb);
+
 out_free_adapter:
 	kfree(adapter);
 
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb3/l2t.h
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb3/l2t.h
@@ -75,8 +75,8 @@
 	struct l2t_entry *rover;	/* starting point for next allocation */
 	atomic_t nfree;		/* number of free entries */
 	rwlock_t lock;
-	struct l2t_entry l2tab[0];
 	struct rcu_head rcu_head;	/* to handle rcu cleanup */
+	struct l2t_entry l2tab[];
 };
 
 typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -3111,6 +3111,7 @@
 			  GFP_KERNEL | __GFP_COMP);
 	if (!avail) {
 		CH_ALERT(adapter, "free list queue 0 initialization failed\n");
+		ret = -ENOMEM;
 		goto err;
 	}
 	if (avail < q->fl[0].size)
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
@@ -266,8 +266,8 @@
 		enum cxgb4_dcb_state_input input =
 			((pcmd->u.dcb.control.all_syncd_pkd &
 			  FW_PORT_CMD_ALL_SYNCD_F)
-			 ? CXGB4_DCB_STATE_FW_ALLSYNCED
-			 : CXGB4_DCB_STATE_FW_INCOMPLETE);
+			 ? CXGB4_DCB_INPUT_FW_ALLSYNCED
+			 : CXGB4_DCB_INPUT_FW_INCOMPLETE);
 
 		if (dcb->dcb_version != FW_PORT_DCB_VER_UNKNOWN) {
 			dcb_running_version = FW_PORT_CMD_DCB_VERSION_G(
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
@@ -67,7 +67,7 @@
 	do { \
 		if ((__dcb)->dcb_version == FW_PORT_DCB_VER_IEEE) \
 			cxgb4_dcb_state_fsm((__dev), \
-					    CXGB4_DCB_STATE_FW_ALLSYNCED); \
+					    CXGB4_DCB_INPUT_FW_ALLSYNCED); \
 	} while (0)
 
 /* States we can be in for a port's Data Center Bridging.
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -66,8 +66,7 @@
 static void *seq_tab_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	v = seq_tab_get_idx(seq->private, *pos + 1);
-	if (v)
-		++*pos;
+	++(*pos);
 	return v;
 }
 
@@ -2673,8 +2672,10 @@
 		return -ENOMEM;
 
 	err = bitmap_parse_user(ubuf, count, t, adap->sge.egr_sz);
-	if (err)
+	if (err) {
+		kvfree(t);
 		return err;
+	}
 
 	bitmap_copy(adap->sge.blocked_fl, t, adap->sge.egr_sz);
 	t4_free_mem(t);
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -338,7 +338,7 @@
 				"Can't %s DCB Priority on port %d, TX Queue %d: err=%d\n",
 				enable ? "set" : "unset", pi->port_id, i, -err);
 		else
-			txq->dcb_prio = value;
+			txq->dcb_prio = enable ? value : 0;
 	}
 }
 #endif /* CONFIG_CHELSIO_T4_DCB */
@@ -2714,10 +2714,14 @@
 		if (err)
 			goto irq_err;
 	}
+
+	mutex_lock(&uld_mutex);
 	enable_rx(adap);
 	t4_sge_start(adap);
 	t4_intr_enable(adap);
 	adap->flags |= FULL_INIT_DONE;
+	mutex_unlock(&uld_mutex);
+
 	notify_ulds(adap, CXGB4_STATE_UP);
 #if IS_ENABLED(CONFIG_IPV6)
 	update_clip(adap);
@@ -5057,15 +5061,24 @@
 
 	ret = pci_register_driver(&cxgb4_driver);
 	if (ret < 0)
-		debugfs_remove(cxgb4_debugfs_root);
+		goto err_pci;
 
 #if IS_ENABLED(CONFIG_IPV6)
 	if (!inet6addr_registered) {
-		register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
-		inet6addr_registered = true;
+		ret = register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
+		if (ret)
+			pci_unregister_driver(&cxgb4_driver);
+		else
+			inet6addr_registered = true;
 	}
 #endif
 
+	if (ret == 0)
+		return ret;
+
+err_pci:
+	debugfs_remove(cxgb4_debugfs_root);
+
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/l2t.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb4/l2t.c
@@ -604,8 +604,7 @@
 static void *l2t_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	v = l2t_get_idx(seq, *pos);
-	if (v)
-		++*pos;
+	++(*pos);
 	return v;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -1165,7 +1165,7 @@
 
 	/* Discard the packet if the length is greater than mtu */
 	max_pkt_len = ETH_HLEN + dev->mtu;
-	if (skb_vlan_tag_present(skb))
+	if (skb_vlan_tagged(skb))
 		max_pkt_len += VLAN_HLEN;
 	if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len)))
 		goto out_free;
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -3093,7 +3093,7 @@
 	drv_fw = &fw_info->fw_hdr;
 
 	/* Read the header of the firmware on the card */
-	ret = -t4_read_flash(adap, FLASH_FW_START,
+	ret = t4_read_flash(adap, FLASH_FW_START,
 			    sizeof(*card_fw) / sizeof(uint32_t),
 			    (uint32_t *)card_fw, 1);
 	if (ret == 0) {
@@ -3122,8 +3122,8 @@
 		   should_install_fs_fw(adap, card_fw_usable,
 					be32_to_cpu(fs_fw->fw_ver),
 					be32_to_cpu(card_fw->fw_ver))) {
-		ret = -t4_fw_upgrade(adap, adap->mbox, fw_data,
-				     fw_size, 0);
+		ret = t4_fw_upgrade(adap, adap->mbox, fw_data,
+				    fw_size, 0);
 		if (ret != 0) {
 			dev_err(adap->pdev_dev,
 				"failed to install firmware: %d\n", ret);
@@ -3154,7 +3154,7 @@
 			FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c),
 			FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k),
 			FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k));
-		ret = EINVAL;
+		ret = -EINVAL;
 		goto bye;
 	}
 
@@ -3341,7 +3341,7 @@
 		 FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_VERSION));
 	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
 			      &param, &val);
-	if (ret < 0)
+	if (ret)
 		return ret;
 	*phy_fw_ver = val;
 	return 0;
@@ -3482,7 +3482,7 @@
 	c.param[0].mnem =
 		cpu_to_be32(FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
 			    FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWCACHE));
-	c.param[0].val = (__force __be32)op;
+	c.param[0].val = cpu_to_be32(op);
 
 	return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL);
 }
@@ -6076,13 +6076,18 @@
 	if (!t4_fw_matches_chip(adap, fw_hdr))
 		return -EINVAL;
 
+	/* Disable FW_OK flag so that mbox commands with FW_OK flag set
+	 * wont be sent when we are flashing FW.
+	 */
+	adap->flags &= ~FW_OK;
+
 	ret = t4_fw_halt(adap, mbox, force);
 	if (ret < 0 && !force)
-		return ret;
+		goto out;
 
 	ret = t4_load_fw(adap, fw_data, size);
 	if (ret < 0)
-		return ret;
+		goto out;
 
 	/*
 	 * Older versions of the firmware don't understand the new
@@ -6093,7 +6098,17 @@
 	 * its header flags to see if it advertises the capability.
 	 */
 	reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
-	return t4_fw_restart(adap, mbox, reset);
+	ret = t4_fw_restart(adap, mbox, reset);
+
+	/* Grab potentially new Firmware Device Log parameters so we can see
+	 * how healthy the new Firmware is.  It's okay to contact the new
+	 * Firmware for these parameters even though, as far as it's
+	 * concerned, we've never said "HELLO" to it ...
+	 */
+	(void)t4_init_devlog_params(adap);
+out:
+	adap->flags |= FW_OK;
+	return ret;
 }
 
 /**
@@ -7696,7 +7711,16 @@
 		ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]);
 		if (ret)
 			break;
-		idx = (idx + 1) & UPDBGLARDPTR_M;
+
+		/* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to
+		 * identify the 32-bit portion of the full 312-bit data
+		 */
+		if (is_t6(adap->params.chip) && (idx & 0xf) >= 9)
+			idx = (idx & 0xff0) + 0x10;
+		else
+			idx++;
+		/* address can't exceed 0xfff */
+		idx &= UPDBGLARDPTR_M;
 	}
 restart:
 	if (cfg & UPDBGLAEN_F) {
--- linux-4.4.0.orig/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ linux-4.4.0/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -1188,7 +1188,7 @@
 
 	/* Discard the packet if the length is greater than mtu */
 	max_pkt_len = ETH_HLEN + dev->mtu;
-	if (skb_vlan_tag_present(skb))
+	if (skb_vlan_tagged(skb))
 		max_pkt_len += VLAN_HLEN;
 	if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len)))
 		goto out_free;
@@ -2604,8 +2604,8 @@
 int t4vf_sge_init(struct adapter *adapter)
 {
 	struct sge_params *sge_params = &adapter->params.sge;
-	u32 fl0 = sge_params->sge_fl_buffer_size[0];
-	u32 fl1 = sge_params->sge_fl_buffer_size[1];
+	u32 fl_small_pg = sge_params->sge_fl_buffer_size[0];
+	u32 fl_large_pg = sge_params->sge_fl_buffer_size[1];
 	struct sge *s = &adapter->sge;
 	unsigned int ingpadboundary, ingpackboundary;
 
@@ -2614,9 +2614,20 @@
 	 * the Physical Function Driver.  Ideally we should be able to deal
 	 * with _any_ configuration.  Practice is different ...
 	 */
-	if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) {
+
+	/* We only bother using the Large Page logic if the Large Page Buffer
+	 * is larger than our Page Size Buffer.
+	 */
+	if (fl_large_pg <= fl_small_pg)
+		fl_large_pg = 0;
+
+	/* The Page Size Buffer must be exactly equal to our Page Size and the
+	 * Large Page Size Buffer should be 0 (per above) or a power of 2.
+	 */
+	if (fl_small_pg != PAGE_SIZE ||
+	    (fl_large_pg & (fl_large_pg - 1)) != 0) {
 		dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n",
-			fl0, fl1);
+			fl_small_pg, fl_large_pg);
 		return -EINVAL;
 	}
 	if ((sge_params->sge_control & RXPKTCPLMODE_F) == 0) {
@@ -2627,8 +2638,8 @@
 	/*
 	 * Now translate the adapter parameters into our internal forms.
 	 */
-	if (fl1)
-		s->fl_pg_order = ilog2(fl1) - PAGE_SHIFT;
+	if (fl_large_pg)
+		s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT;
 	s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F)
 			? 128 : 64);
 	s->pktshift = PKTSHIFT_G(sge_params->sge_control);
--- linux-4.4.0.orig/drivers/net/ethernet/cirrus/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/cirrus/Kconfig
@@ -19,6 +19,7 @@
 config CS89x0
 	tristate "CS89x0 support"
 	depends on ISA || EISA || ARM
+	depends on !PPC32
 	---help---
 	  Support for CS89x0 chipset based Ethernet cards. If you have a
 	  network (Ethernet) card of this type, say Y and read the file
--- linux-4.4.0.orig/drivers/net/ethernet/cirrus/cs89x0.c
+++ linux-4.4.0/drivers/net/ethernet/cirrus/cs89x0.c
@@ -1703,12 +1703,12 @@
 static int dma;
 static int dmasize = 16;		/* or 64 */
 
-module_param(io, int, 0);
-module_param(irq, int, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
 module_param(debug, int, 0);
 module_param_string(media, media, sizeof(media), 0);
 module_param(duplex, int, 0);
-module_param(dma , int, 0);
+module_param_hw(dma , int, dma, 0);
 module_param(dmasize , int, 0);
 module_param(use_dma , int, 0);
 MODULE_PARM_DESC(io, "cs89x0 I/O base address");
--- linux-4.4.0.orig/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ linux-4.4.0/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@ -468,6 +468,9 @@
 	struct device *dev = ep->dev->dev.parent;
 	int i;
 
+	if (!ep->descs)
+		return;
+
 	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
 		dma_addr_t d;
 
@@ -490,6 +493,7 @@
 
 	dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs,
 							ep->descs_dma_addr);
+	ep->descs = NULL;
 }
 
 static int ep93xx_alloc_buffers(struct ep93xx_priv *ep)
@@ -776,6 +780,7 @@
 {
 	struct net_device *dev;
 	struct ep93xx_priv *ep;
+	struct resource *mem;
 
 	dev = platform_get_drvdata(pdev);
 	if (dev == NULL)
@@ -791,8 +796,8 @@
 		iounmap(ep->base_addr);
 
 	if (ep->res != NULL) {
-		release_resource(ep->res);
-		kfree(ep->res);
+		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		release_mem_region(mem->start, resource_size(mem));
 	}
 
 	free_netdev(dev);
--- linux-4.4.0.orig/drivers/net/ethernet/cisco/enic/enic.h
+++ linux-4.4.0/drivers/net/ethernet/cisco/enic/enic.h
@@ -33,7 +33,7 @@
 
 #define DRV_NAME		"enic"
 #define DRV_DESCRIPTION		"Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION		"2.3.0.12"
+#define DRV_VERSION		"2.3.0.20"
 #define DRV_COPYRIGHT		"Copyright 2008-2013 Cisco Systems, Inc"
 
 #define ENIC_BARS_MAX		6
@@ -163,6 +163,7 @@
 	u16 num_vfs;
 #endif
 	spinlock_t enic_api_lock;
+	bool enic_api_busy;
 	struct enic_port_profile *pp;
 
 	/* work queue cache line section */
--- linux-4.4.0.orig/drivers/net/ethernet/cisco/enic/enic_api.c
+++ linux-4.4.0/drivers/net/ethernet/cisco/enic/enic_api.c
@@ -34,6 +34,12 @@
 	struct vnic_dev *vdev = enic->vdev;
 
 	spin_lock(&enic->enic_api_lock);
+	while (enic->enic_api_busy) {
+		spin_unlock(&enic->enic_api_lock);
+		cpu_relax();
+		spin_lock(&enic->enic_api_lock);
+	}
+
 	spin_lock_bh(&enic->devcmd_lock);
 
 	vnic_dev_cmd_proxy_by_index_start(vdev, vf);
--- linux-4.4.0.orig/drivers/net/ethernet/cisco/enic/enic_clsf.c
+++ linux-4.4.0/drivers/net/ethernet/cisco/enic/enic_clsf.c
@@ -78,7 +78,6 @@
 	enic->rfs_h.max = enic->config.num_arfs;
 	enic->rfs_h.free = enic->rfs_h.max;
 	enic->rfs_h.toclean = 0;
-	enic_rfs_timer_start(enic);
 }
 
 void enic_rfs_flw_tbl_free(struct enic *enic)
@@ -87,7 +86,6 @@
 
 	enic_rfs_timer_stop(enic);
 	spin_lock_bh(&enic->rfs_h.lock);
-	enic->rfs_h.free = 0;
 	for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
 		struct hlist_head *hhead;
 		struct hlist_node *tmp;
@@ -98,6 +96,7 @@
 			enic_delfltr(enic, n->fltr_id);
 			hlist_del(&n->node);
 			kfree(n);
+			enic->rfs_h.free++;
 		}
 	}
 	spin_unlock_bh(&enic->rfs_h.lock);
--- linux-4.4.0.orig/drivers/net/ethernet/cisco/enic/enic_main.c
+++ linux-4.4.0/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -120,7 +120,7 @@
 
 	for (i = 0; i < enic->intr_count; i++) {
 		if (enic_is_err_intr(enic, i) || enic_is_notify_intr(enic, i) ||
-		    (enic->msix[i].affinity_mask &&
+		    (cpumask_available(enic->msix[i].affinity_mask) &&
 		     !cpumask_empty(enic->msix[i].affinity_mask)))
 			continue;
 		if (zalloc_cpumask_var(&enic->msix[i].affinity_mask,
@@ -149,7 +149,7 @@
 	for (i = 0; i < enic->intr_count; i++) {
 		if (enic_is_err_intr(enic, i)		||
 		    enic_is_notify_intr(enic, i)	||
-		    !enic->msix[i].affinity_mask	||
+		    !cpumask_available(enic->msix[i].affinity_mask) ||
 		    cpumask_empty(enic->msix[i].affinity_mask))
 			continue;
 		err = irq_set_affinity_hint(enic->msix_entry[i].vector,
@@ -162,7 +162,7 @@
 	for (i = 0; i < enic->wq_count; i++) {
 		int wq_intr = enic_msix_wq_intr(enic, i);
 
-		if (enic->msix[wq_intr].affinity_mask &&
+		if (cpumask_available(enic->msix[wq_intr].affinity_mask) &&
 		    !cpumask_empty(enic->msix[wq_intr].affinity_mask))
 			netif_set_xps_queue(enic->netdev,
 					    enic->msix[wq_intr].affinity_mask,
@@ -1180,7 +1180,7 @@
 		 * CHECSUM_UNNECESSARY.
 		 */
 		if ((netdev->features & NETIF_F_RXCSUM) && tcp_udp_csum_ok &&
-		    ipv4_csum_ok)
+		    (ipv4_csum_ok || ipv6))
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 
 		if (vlan_stripped)
@@ -1708,7 +1708,7 @@
 {
 	struct enic *enic = netdev_priv(netdev);
 	unsigned int i;
-	int err;
+	int err, ret;
 
 	err = enic_request_intr(enic);
 	if (err) {
@@ -1726,6 +1726,8 @@
 	}
 
 	for (i = 0; i < enic->rq_count; i++) {
+		/* enable rq before updating rq desc */
+		vnic_rq_enable(&enic->rq[i]);
 		vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf);
 		/* Need at least one buffer on ring to get going */
 		if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
@@ -1737,8 +1739,6 @@
 
 	for (i = 0; i < enic->wq_count; i++)
 		vnic_wq_enable(&enic->wq[i]);
-	for (i = 0; i < enic->rq_count; i++)
-		vnic_rq_enable(&enic->rq[i]);
 
 	if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic))
 		enic_dev_add_station_addr(enic);
@@ -1760,13 +1760,16 @@
 		vnic_intr_unmask(&enic->intr[i]);
 
 	enic_notify_timer_start(enic);
-	enic_rfs_flw_tbl_init(enic);
+	enic_rfs_timer_start(enic);
 
 	return 0;
 
 err_out_free_rq:
-	for (i = 0; i < enic->rq_count; i++)
-		vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
+	for (i = 0; i < enic->rq_count; i++) {
+		ret = vnic_rq_disable(&enic->rq[i]);
+		if (!ret)
+			vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
+	}
 	enic_dev_notify_unset(enic);
 err_out_free_intr:
 	enic_unset_affinity_hint(enic);
@@ -1803,10 +1806,10 @@
 	}
 
 	netif_carrier_off(netdev);
-	netif_tx_disable(netdev);
 	if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX)
 		for (i = 0; i < enic->wq_count; i++)
 			napi_disable(&enic->napi[enic_cq_wq(enic, i)]);
+	netif_tx_disable(netdev);
 
 	if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic))
 		enic_dev_del_station_addr(enic);
@@ -1838,10 +1841,32 @@
 	return 0;
 }
 
+static int _enic_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	bool running = netif_running(netdev);
+	int err = 0;
+
+	ASSERT_RTNL();
+	if (running) {
+		err = enic_stop(netdev);
+		if (err)
+			return err;
+	}
+
+	netdev->mtu = new_mtu;
+
+	if (running) {
+		err = enic_open(netdev);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int enic_change_mtu(struct net_device *netdev, int new_mtu)
 {
 	struct enic *enic = netdev_priv(netdev);
-	int running = netif_running(netdev);
 
 	if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU)
 		return -EINVAL;
@@ -1849,20 +1874,12 @@
 	if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic))
 		return -EOPNOTSUPP;
 
-	if (running)
-		enic_stop(netdev);
-
-	netdev->mtu = new_mtu;
-
 	if (netdev->mtu > enic->port_mtu)
 		netdev_warn(netdev,
-			"interface MTU (%d) set higher than port MTU (%d)\n",
-			netdev->mtu, enic->port_mtu);
-
-	if (running)
-		enic_open(netdev);
+			    "interface MTU (%d) set higher than port MTU (%d)\n",
+			    netdev->mtu, enic->port_mtu);
 
-	return 0;
+	return _enic_change_mtu(netdev, new_mtu);
 }
 
 static void enic_change_mtu_work(struct work_struct *work)
@@ -1870,47 +1887,9 @@
 	struct enic *enic = container_of(work, struct enic, change_mtu_work);
 	struct net_device *netdev = enic->netdev;
 	int new_mtu = vnic_dev_mtu(enic->vdev);
-	int err;
-	unsigned int i;
-
-	new_mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, new_mtu));
 
 	rtnl_lock();
-
-	/* Stop RQ */
-	del_timer_sync(&enic->notify_timer);
-
-	for (i = 0; i < enic->rq_count; i++)
-		napi_disable(&enic->napi[i]);
-
-	vnic_intr_mask(&enic->intr[0]);
-	enic_synchronize_irqs(enic);
-	err = vnic_rq_disable(&enic->rq[0]);
-	if (err) {
-		rtnl_unlock();
-		netdev_err(netdev, "Unable to disable RQ.\n");
-		return;
-	}
-	vnic_rq_clean(&enic->rq[0], enic_free_rq_buf);
-	vnic_cq_clean(&enic->cq[0]);
-	vnic_intr_clean(&enic->intr[0]);
-
-	/* Fill RQ with new_mtu-sized buffers */
-	netdev->mtu = new_mtu;
-	vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf);
-	/* Need at least one buffer on ring to get going */
-	if (vnic_rq_desc_used(&enic->rq[0]) == 0) {
-		rtnl_unlock();
-		netdev_err(netdev, "Unable to alloc receive buffers.\n");
-		return;
-	}
-
-	/* Start RQ */
-	vnic_rq_enable(&enic->rq[0]);
-	napi_enable(&enic->napi[0]);
-	vnic_intr_unmask(&enic->intr[0]);
-	enic_notify_timer_start(enic);
-
+	(void)_enic_change_mtu(netdev, new_mtu);
 	rtnl_unlock();
 
 	netdev_info(netdev, "interface MTU set as %d\n", netdev->mtu);
@@ -1959,8 +1938,6 @@
 	int done;
 	int err;
 
-	BUG_ON(in_interrupt());
-
 	err = start(vdev, arg);
 	if (err)
 		return err;
@@ -2137,6 +2114,13 @@
 		rss_hash_bits, rss_base_cpu, rss_enable);
 }
 
+static void enic_set_api_busy(struct enic *enic, bool busy)
+{
+	spin_lock(&enic->enic_api_lock);
+	enic->enic_api_busy = busy;
+	spin_unlock(&enic->enic_api_lock);
+}
+
 static void enic_reset(struct work_struct *work)
 {
 	struct enic *enic = container_of(work, struct enic, reset);
@@ -2146,7 +2130,9 @@
 
 	rtnl_lock();
 
-	spin_lock(&enic->enic_api_lock);
+	/* Stop any activity from infiniband */
+	enic_set_api_busy(enic, true);
+
 	enic_stop(enic->netdev);
 	enic_dev_soft_reset(enic);
 	enic_reset_addr_lists(enic);
@@ -2154,7 +2140,10 @@
 	enic_set_rss_nic_cfg(enic);
 	enic_dev_set_ig_vlan_rewrite_mode(enic);
 	enic_open(enic->netdev);
-	spin_unlock(&enic->enic_api_lock);
+
+	/* Allow infiniband to fiddle with the device again */
+	enic_set_api_busy(enic, false);
+
 	call_netdevice_notifiers(NETDEV_REBOOT, enic->netdev);
 
 	rtnl_unlock();
@@ -2166,7 +2155,9 @@
 
 	rtnl_lock();
 
-	spin_lock(&enic->enic_api_lock);
+	/* Stop any activity from infiniband */
+	enic_set_api_busy(enic, true);
+
 	enic_dev_hang_notify(enic);
 	enic_stop(enic->netdev);
 	enic_dev_hang_reset(enic);
@@ -2175,7 +2166,10 @@
 	enic_set_rss_nic_cfg(enic);
 	enic_dev_set_ig_vlan_rewrite_mode(enic);
 	enic_open(enic->netdev);
-	spin_unlock(&enic->enic_api_lock);
+
+	/* Allow infiniband to fiddle with the device again */
+	enic_set_api_busy(enic, false);
+
 	call_netdevice_notifiers(NETDEV_REBOOT, enic->netdev);
 
 	rtnl_unlock();
@@ -2539,11 +2533,11 @@
 	pci_set_master(pdev);
 
 	/* Query PCI controller on system for DMA addressing
-	 * limitation for the device.  Try 64-bit first, and
+	 * limitation for the device.  Try 47-bit first, and
 	 * fail to 32-bit.
 	 */
 
-	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(47));
 	if (err) {
 		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 		if (err) {
@@ -2557,10 +2551,10 @@
 			goto err_out_release_regions;
 		}
 	} else {
-		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(47));
 		if (err) {
 			dev_err(dev, "Unable to obtain %u-bit DMA "
-				"for consistent allocations, aborting\n", 64);
+				"for consistent allocations, aborting\n", 47);
 			goto err_out_release_regions;
 		}
 		using_dac = 1;
@@ -2690,6 +2684,7 @@
 	enic->notify_timer.function = enic_notify_timer;
 	enic->notify_timer.data = (unsigned long)enic;
 
+	enic_rfs_flw_tbl_init(enic);
 	enic_set_rx_coal_setting(enic);
 	INIT_WORK(&enic->reset, enic_reset);
 	INIT_WORK(&enic->tx_hang_reset, enic_tx_hang_reset);
@@ -2702,7 +2697,6 @@
 	 */
 
 	enic->port_mtu = enic->config.mtu;
-	(void)enic_change_mtu(netdev, enic->port_mtu);
 
 	err = enic_set_mac_addr(netdev, enic->mac_addr);
 	if (err) {
@@ -2751,6 +2745,7 @@
 		netdev->features |= NETIF_F_HIGHDMA;
 
 	netdev->priv_flags |= IFF_UNICAST_FLT;
+	netdev->mtu = enic->port_mtu;
 
 	err = register_netdev(netdev);
 	if (err) {
--- linux-4.4.0.orig/drivers/net/ethernet/cisco/enic/vnic_dev.c
+++ linux-4.4.0/drivers/net/ethernet/cisco/enic/vnic_dev.c
@@ -298,7 +298,8 @@
 			  int wait)
 {
 	struct devcmd2_controller *dc2c = vdev->devcmd2;
-	struct devcmd2_result *result = dc2c->result + dc2c->next_result;
+	struct devcmd2_result *result;
+	u8 color;
 	unsigned int i;
 	int delay, err;
 	u32 fetch_index, new_posted;
@@ -336,13 +337,17 @@
 	if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT)
 		return 0;
 
+	result = dc2c->result + dc2c->next_result;
+	color = dc2c->color;
+
+	dc2c->next_result++;
+	if (dc2c->next_result == dc2c->result_size) {
+		dc2c->next_result = 0;
+		dc2c->color = dc2c->color ? 0 : 1;
+	}
+
 	for (delay = 0; delay < wait; delay++) {
-		if (result->color == dc2c->color) {
-			dc2c->next_result++;
-			if (dc2c->next_result == dc2c->result_size) {
-				dc2c->next_result = 0;
-				dc2c->color = dc2c->color ? 0 : 1;
-			}
+		if (result->color == color) {
 			if (result->error) {
 				err = result->error;
 				if (err != ERR_ECMDUNKNOWN ||
--- linux-4.4.0.orig/drivers/net/ethernet/davicom/dm9000.c
+++ linux-4.4.0/drivers/net/ethernet/davicom/dm9000.c
@@ -144,6 +144,8 @@
 	u32		wake_state;
 
 	int		ip_summed;
+
+	struct regulator *power_supply;
 };
 
 /* debug code */
@@ -1462,7 +1464,7 @@
 		if (ret) {
 			dev_err(dev, "failed to request reset gpio %d: %d\n",
 				reset_gpios, ret);
-			return -ENODEV;
+			goto out_regulator_disable;
 		}
 
 		/* According to manual PWRST# Low Period Min 1ms */
@@ -1474,8 +1476,10 @@
 
 	if (!pdata) {
 		pdata = dm9000_parse_dt(&pdev->dev);
-		if (IS_ERR(pdata))
-			return PTR_ERR(pdata);
+		if (IS_ERR(pdata)) {
+			ret = PTR_ERR(pdata);
+			goto out_regulator_disable;
+		}
 	}
 
 	/* Init network device */
@@ -1492,6 +1496,8 @@
 
 	db->dev = &pdev->dev;
 	db->ndev = ndev;
+	if (!IS_ERR(power))
+		db->power_supply = power;
 
 	spin_lock_init(&db->lock);
 	mutex_init(&db->addr_lock);
@@ -1710,6 +1716,10 @@
 	dm9000_release_board(pdev, db);
 	free_netdev(ndev);
 
+out_regulator_disable:
+	if (!IS_ERR(power))
+		regulator_disable(power);
+
 	return ret;
 }
 
@@ -1769,9 +1779,13 @@
 dm9000_drv_remove(struct platform_device *pdev)
 {
 	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct board_info *dm = to_dm9000_board(ndev);
 
 	unregister_netdev(ndev);
-	dm9000_release_board(pdev, netdev_priv(ndev));
+	dm9000_release_board(pdev, dm);
+	if (dm->power_supply)
+		regulator_disable(dm->power_supply);
+
 	free_netdev(ndev);		/* free device structure */
 
 	dev_dbg(&pdev->dev, "released and freed device\n");
--- linux-4.4.0.orig/drivers/net/ethernet/dec/tulip/de2104x.c
+++ linux-4.4.0/drivers/net/ethernet/dec/tulip/de2104x.c
@@ -91,7 +91,7 @@
 #define DSL			CONFIG_DE2104X_DSL
 #endif
 
-#define DE_RX_RING_SIZE		64
+#define DE_RX_RING_SIZE		128
 #define DE_TX_RING_SIZE		64
 #define DE_RING_BYTES		\
 		((sizeof(struct de_desc) * DE_RX_RING_SIZE) +	\
--- linux-4.4.0.orig/drivers/net/ethernet/dec/tulip/de4x5.c
+++ linux-4.4.0/drivers/net/ethernet/dec/tulip/de4x5.c
@@ -1015,7 +1015,7 @@
 
 static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED        */
 
-module_param(io, int, 0);
+module_param_hw(io, int, ioport, 0);
 module_param(de4x5_debug, int, 0);
 module_param(dec_only, int, 0);
 module_param(args, charp, 0);
@@ -1990,7 +1990,7 @@
 
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 
-static int __init de4x5_eisa_probe (struct device *gendev)
+static int de4x5_eisa_probe(struct device *gendev)
 {
 	struct eisa_device *edev;
 	u_long iobase;
@@ -2106,7 +2106,6 @@
 		.remove  = de4x5_eisa_remove,
         }
 };
-MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids);
 #endif
 
 #ifdef CONFIG_PCI
--- linux-4.4.0.orig/drivers/net/ethernet/dec/tulip/dmfe.c
+++ linux-4.4.0/drivers/net/ethernet/dec/tulip/dmfe.c
@@ -2228,15 +2228,16 @@
 	if (cr6set)
 		dmfe_cr6_user_set = cr6set;
 
- 	switch(mode) {
-   	case DMFE_10MHF:
+	switch (mode) {
+	case DMFE_10MHF:
 	case DMFE_100MHF:
 	case DMFE_10MFD:
 	case DMFE_100MFD:
 	case DMFE_1M_HPNA:
 		dmfe_media_mode = mode;
 		break;
-	default:dmfe_media_mode = DMFE_AUTO;
+	default:
+		dmfe_media_mode = DMFE_AUTO;
 		break;
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/dec/tulip/uli526x.c
+++ linux-4.4.0/drivers/net/ethernet/dec/tulip/uli526x.c
@@ -1813,8 +1813,8 @@
 	if (cr6set)
 		uli526x_cr6_user_set = cr6set;
 
- 	switch (mode) {
-   	case ULI526X_10MHF:
+	switch (mode) {
+	case ULI526X_10MHF:
 	case ULI526X_100MHF:
 	case ULI526X_10MFD:
 	case ULI526X_100MFD:
--- linux-4.4.0.orig/drivers/net/ethernet/ec_bhf.c
+++ linux-4.4.0/drivers/net/ethernet/ec_bhf.c
@@ -589,10 +589,12 @@
 	struct ec_bhf_priv *priv = netdev_priv(net_dev);
 
 	unregister_netdev(net_dev);
-	free_netdev(net_dev);
 
 	pci_iounmap(dev, priv->dma_io);
 	pci_iounmap(dev, priv->io);
+
+	free_netdev(net_dev);
+
 	pci_release_regions(dev);
 	pci_clear_master(dev);
 	pci_disable_device(dev);
--- linux-4.4.0.orig/drivers/net/ethernet/emulex/benet/be.h
+++ linux-4.4.0/drivers/net/ethernet/emulex/benet/be.h
@@ -531,6 +531,7 @@
 
 	struct delayed_work be_err_detection_work;
 	u8 err_flags;
+	bool pcicfg_mapped;	/* pcicfg obtained via pci_iomap() */
 	u32 flags;
 	u32 cmd_privileges;
 	/* Ethtool knobs and info */
--- linux-4.4.0.orig/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ linux-4.4.0/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -1052,7 +1052,7 @@
 err:
 	spin_unlock_bh(&adapter->mcc_lock);
 
-	 if (status == MCC_STATUS_UNAUTHORIZED_REQUEST)
+	 if (base_status(status) == MCC_STATUS_UNAUTHORIZED_REQUEST)
 		status = -EPERM;
 
 	return status;
--- linux-4.4.0.orig/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -868,7 +868,7 @@
 			 u64 *data)
 {
 	struct be_adapter *adapter = netdev_priv(netdev);
-	int status;
+	int status, cnt;
 	u8 link_status = 0;
 
 	if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
@@ -879,6 +879,9 @@
 
 	memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
 
+	/* check link status before offline tests */
+	link_status = netif_carrier_ok(netdev);
+
 	if (test->flags & ETH_TEST_FL_OFFLINE) {
 		if (be_loopback_test(adapter, BE_MAC_LOOPBACK, &data[0]) != 0)
 			test->flags |= ETH_TEST_FL_FAILED;
@@ -899,13 +902,26 @@
 		test->flags |= ETH_TEST_FL_FAILED;
 	}
 
-	status = be_cmd_link_status_query(adapter, NULL, &link_status, 0);
-	if (status) {
-		test->flags |= ETH_TEST_FL_FAILED;
-		data[4] = -1;
-	} else if (!link_status) {
+	/* link status was down prior to test */
+	if (!link_status) {
 		test->flags |= ETH_TEST_FL_FAILED;
 		data[4] = 1;
+		return;
+	}
+
+	for (cnt = 10; cnt; cnt--) {
+		status = be_cmd_link_status_query(adapter, NULL, &link_status,
+						  0);
+		if (status) {
+			test->flags |= ETH_TEST_FL_FAILED;
+			data[4] = -1;
+			break;
+		}
+
+		if (link_status)
+			break;
+
+		msleep_interruptible(500);
 	}
 }
 
@@ -1050,7 +1066,7 @@
 		cmd->data = be_get_rss_hash_opts(adapter, cmd->flow_type);
 		break;
 	case ETHTOOL_GRXRINGS:
-		cmd->data = adapter->num_rx_qs - 1;
+		cmd->data = adapter->num_rx_qs;
 		break;
 	default:
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/net/ethernet/emulex/benet/be_main.c
+++ linux-4.4.0/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1306,10 +1306,8 @@
 	be_get_wrb_params_from_skb(adapter, skb, &wrb_params);
 
 	wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
-	if (unlikely(!wrb_cnt)) {
-		dev_kfree_skb_any(skb);
-		goto drop;
-	}
+	if (unlikely(!wrb_cnt))
+		goto drop_skb;
 
 	/* if os2bmc is enabled and if the pkt is destined to bmc,
 	 * enqueue the pkt a 2nd time with mgmt bit set.
@@ -1318,7 +1316,7 @@
 		BE_WRB_F_SET(wrb_params.features, OS2BMC, 1);
 		wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
 		if (unlikely(!wrb_cnt))
-			goto drop;
+			goto drop_skb;
 		else
 			skb_get(skb);
 	}
@@ -1332,6 +1330,8 @@
 		be_xmit_flush(adapter, txo);
 
 	return NETDEV_TX_OK;
+drop_skb:
+	dev_kfree_skb_any(skb);
 drop:
 	tx_stats(txo)->tx_drv_drops++;
 	/* Flush the already enqueued tx requests */
@@ -4307,8 +4307,12 @@
 	struct net_device *netdev = adapter->netdev;
 	int status;
 
-	if (netif_running(netdev))
+	if (netif_running(netdev)) {
+		/* device cannot transmit now, avoid dev_watchdog timeouts */
+		netif_carrier_off(netdev);
+
 		be_close(netdev);
+	}
 
 	be_cancel_worker(adapter);
 
@@ -5260,9 +5264,11 @@
 	struct be_adapter *adapter = netdev_priv(dev);
 	u8 l4_hdr = 0;
 
-	/* The code below restricts offload features for some tunneled packets.
+	/* The code below restricts offload features for some tunneled and
+	 * Q-in-Q packets.
 	 * Offload features for normal (non tunnel) packets are unchanged.
 	 */
+	features = vlan_features_check(skb, features);
 	if (!skb->encapsulation ||
 	    !(adapter->flags & BE_FLAGS_VXLAN_OFFLOADS))
 		return features;
@@ -5472,6 +5478,10 @@
 	struct be_rx_obj *rxo;
 	int i;
 
+	if (be_physfn(adapter) &&
+	    MODULO(adapter->work_counter, adapter->be_get_temp_freq) == 0)
+		be_cmd_get_die_temperature(adapter);
+
 	/* when interrupts are not yet enabled, just reap any pending
 	 * mcc completions
 	 */
@@ -5490,10 +5500,6 @@
 			be_cmd_get_stats(adapter, &adapter->stats_cmd);
 	}
 
-	if (be_physfn(adapter) &&
-	    MODULO(adapter->work_counter, adapter->be_get_temp_freq) == 0)
-		be_cmd_get_die_temperature(adapter);
-
 	for_all_rx_queues(adapter, rxo, i) {
 		/* Replenish RX-queues starved due to memory
 		 * allocation failures.
@@ -5520,6 +5526,8 @@
 		pci_iounmap(adapter->pdev, adapter->csr);
 	if (adapter->db)
 		pci_iounmap(adapter->pdev, adapter->db);
+	if (adapter->pcicfg && adapter->pcicfg_mapped)
+		pci_iounmap(adapter->pdev, adapter->pcicfg);
 }
 
 static int db_bar(struct be_adapter *adapter)
@@ -5571,8 +5579,10 @@
 			if (!addr)
 				goto pci_map_err;
 			adapter->pcicfg = addr;
+			adapter->pcicfg_mapped = true;
 		} else {
 			adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
+			adapter->pcicfg_mapped = false;
 		}
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/ethoc.c
+++ linux-4.4.0/drivers/net/ethernet/ethoc.c
@@ -713,6 +713,8 @@
 	if (ret)
 		return ret;
 
+	napi_enable(&priv->napi);
+
 	ethoc_init_ring(priv, dev->mem_start);
 	ethoc_reset(priv);
 
@@ -725,7 +727,6 @@
 	}
 
 	phy_start(priv->phy);
-	napi_enable(&priv->napi);
 
 	if (netif_msg_ifup(priv)) {
 		dev_info(&dev->dev, "I/O: %08lx Memory: %08lx-%08lx\n",
@@ -1087,7 +1088,7 @@
 	if (!priv->iobase) {
 		dev_err(&pdev->dev, "cannot remap I/O memory space\n");
 		ret = -ENXIO;
-		goto error;
+		goto free;
 	}
 
 	if (netdev->mem_end) {
@@ -1096,7 +1097,7 @@
 		if (!priv->membase) {
 			dev_err(&pdev->dev, "cannot remap memory space\n");
 			ret = -ENXIO;
-			goto error;
+			goto free;
 		}
 	} else {
 		/* Allocate buffer memory */
@@ -1107,7 +1108,7 @@
 			dev_err(&pdev->dev, "cannot allocate %dB buffer\n",
 				buffer_size);
 			ret = -ENOMEM;
-			goto error;
+			goto free;
 		}
 		netdev->mem_end = netdev->mem_start + buffer_size;
 		priv->dma_alloc = buffer_size;
@@ -1121,7 +1122,7 @@
 		128, (netdev->mem_end - netdev->mem_start + 1) / ETHOC_BUFSIZ);
 	if (num_bd < 4) {
 		ret = -ENODEV;
-		goto error;
+		goto free;
 	}
 	priv->num_bd = num_bd;
 	/* num_tx must be a power of two */
@@ -1134,7 +1135,7 @@
 	priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void *), GFP_KERNEL);
 	if (!priv->vma) {
 		ret = -ENOMEM;
-		goto error;
+		goto free;
 	}
 
 	/* Allow the platform setup code to pass in a MAC address. */
--- linux-4.4.0.orig/drivers/net/ethernet/faraday/ftgmac100.c
+++ linux-4.4.0/drivers/net/ethernet/faraday/ftgmac100.c
@@ -28,6 +28,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <linux/of.h>
 #include <linux/phy.h>
 #include <linux/platform_device.h>
 #include <net/ip.h>
--- linux-4.4.0.orig/drivers/net/ethernet/faraday/ftmac100.c
+++ linux-4.4.0/drivers/net/ethernet/faraday/ftmac100.c
@@ -865,11 +865,10 @@
 	struct net_device *netdev = dev_id;
 	struct ftmac100 *priv = netdev_priv(netdev);
 
-	if (likely(netif_running(netdev))) {
-		/* Disable interrupts for polling */
-		ftmac100_disable_all_int(priv);
+	/* Disable interrupts for polling */
+	ftmac100_disable_all_int(priv);
+	if (likely(netif_running(netdev)))
 		napi_schedule(&priv->napi);
-	}
 
 	return IRQ_HANDLED;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/fealnx.c
+++ linux-4.4.0/drivers/net/ethernet/fealnx.c
@@ -257,8 +257,8 @@
 	RXFSD = 0x00000800,	/* first descriptor */
 	RXLSD = 0x00000400,	/* last descriptor */
 	ErrorSummary = 0x80,	/* error summary */
-	RUNT = 0x40,		/* runt packet received */
-	LONG = 0x20,		/* long packet received */
+	RUNTPKT = 0x40,		/* runt packet received */
+	LONGPKT = 0x20,		/* long packet received */
 	FAE = 0x10,		/* frame align error */
 	CRC = 0x08,		/* crc error */
 	RXER = 0x04,		/* receive error */
@@ -1633,7 +1633,7 @@
 					       dev->name, rx_status);
 
 				dev->stats.rx_errors++;	/* end of a packet. */
-				if (rx_status & (LONG | RUNT))
+				if (rx_status & (LONGPKT | RUNTPKT))
 					dev->stats.rx_length_errors++;
 				if (rx_status & RXER)
 					dev->stats.rx_frame_errors++;
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/fec_main.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/fec_main.c
@@ -944,11 +944,11 @@
 	 * enet-mac reset will reset mac address registers too,
 	 * so need to reconfigure it.
 	 */
-	if (fep->quirks & FEC_QUIRK_ENET_MAC) {
-		memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
-		writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
-		writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
-	}
+	memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
+	writel((__force u32)cpu_to_be32(temp_mac[0]),
+	       fep->hwp + FEC_ADDR_LOW);
+	writel((__force u32)cpu_to_be32(temp_mac[1]),
+	       fep->hwp + FEC_ADDR_HIGH);
 
 	/* Clear any outstanding interrupt. */
 	writel(0xffffffff, fep->hwp + FEC_IEVENT);
@@ -1557,9 +1557,15 @@
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
 	for_each_set_bit(queue_id, &fep->work_rx, FEC_ENET_MAX_RX_QS) {
-		clear_bit(queue_id, &fep->work_rx);
-		pkt_received += fec_enet_rx_queue(ndev,
+		int ret;
+
+		ret = fec_enet_rx_queue(ndev,
 					budget - pkt_received, queue_id);
+
+		if (ret < budget - pkt_received)
+			clear_bit(queue_id, &fep->work_rx);
+
+		pkt_received += ret;
 	}
 	return pkt_received;
 }
@@ -1693,10 +1699,10 @@
 	 */
 	if (!is_valid_ether_addr(iap)) {
 		/* Report it and use a random ethernet address instead */
-		netdev_err(ndev, "Invalid MAC address: %pM\n", iap);
+		dev_err(&fep->pdev->dev, "Invalid MAC address: %pM\n", iap);
 		eth_hw_addr_random(ndev);
-		netdev_info(ndev, "Using random MAC address: %pM\n",
-			    ndev->dev_addr);
+		dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n",
+			 ndev->dev_addr);
 		return;
 	}
 
@@ -2504,15 +2510,15 @@
 		return -EINVAL;
 	}
 
-	cycle = fec_enet_us_to_itr_clock(ndev, fep->rx_time_itr);
+	cycle = fec_enet_us_to_itr_clock(ndev, ec->rx_coalesce_usecs);
 	if (cycle > 0xFFFF) {
 		pr_err("Rx coalesed usec exceeed hardware limiation");
 		return -EINVAL;
 	}
 
-	cycle = fec_enet_us_to_itr_clock(ndev, fep->tx_time_itr);
+	cycle = fec_enet_us_to_itr_clock(ndev, ec->tx_coalesce_usecs);
 	if (cycle > 0xFFFF) {
-		pr_err("Rx coalesed usec exceeed hardware limiation");
+		pr_err("Tx coalesed usec exceeed hardware limiation");
 		return -EINVAL;
 	}
 
@@ -2962,6 +2968,7 @@
 	struct netdev_hw_addr *ha;
 	unsigned int i, bit, data, crc, tmp;
 	unsigned char hash;
+	unsigned int hash_high = 0, hash_low = 0;
 
 	if (ndev->flags & IFF_PROMISC) {
 		tmp = readl(fep->hwp + FEC_R_CNTRL);
@@ -2984,11 +2991,7 @@
 		return;
 	}
 
-	/* Clear filter and add the addresses in hash register
-	 */
-	writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
-	writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
-
+	/* Add the addresses in hash register */
 	netdev_for_each_mc_addr(ha, ndev) {
 		/* calculate crc32 value of mac address */
 		crc = 0xffffffff;
@@ -3006,16 +3009,14 @@
 		 */
 		hash = (crc >> (32 - HASH_BITS)) & 0x3f;
 
-		if (hash > 31) {
-			tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
-			tmp |= 1 << (hash - 32);
-			writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
-		} else {
-			tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW);
-			tmp |= 1 << hash;
-			writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
-		}
+		if (hash > 31)
+			hash_high |= 1 << (hash - 32);
+		else
+			hash_low |= 1 << hash;
 	}
+
+	writel(hash_high, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+	writel(hash_low, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
 }
 
 /* Set a MAC change in hardware. */
@@ -3047,29 +3048,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/**
- * fec_poll_controller - FEC Poll controller function
- * @dev: The FEC network adapter
- *
- * Polled functionality used by netconsole and others in non interrupt mode
- *
- */
-static void fec_poll_controller(struct net_device *dev)
-{
-	int i;
-	struct fec_enet_private *fep = netdev_priv(dev);
-
-	for (i = 0; i < FEC_IRQ_NUM; i++) {
-		if (fep->irq[i] > 0) {
-			disable_irq(fep->irq[i]);
-			fec_enet_interrupt(fep->irq[i], dev);
-			enable_irq(fep->irq[i]);
-		}
-	}
-}
-#endif
-
 static inline void fec_enet_set_netdev_features(struct net_device *netdev,
 	netdev_features_t features)
 {
@@ -3119,9 +3097,6 @@
 	.ndo_tx_timeout		= fec_timeout,
 	.ndo_set_mac_address	= fec_set_mac_address,
 	.ndo_do_ioctl		= fec_enet_ioctl,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= fec_poll_controller,
-#endif
 	.ndo_set_features	= fec_set_features,
 };
 
@@ -3138,6 +3113,7 @@
 	dma_addr_t bd_dma;
 	int bd_size;
 	unsigned int i;
+	int ret;
 
 #if defined(CONFIG_ARM)
 	fep->rx_align = 0xf;
@@ -3147,7 +3123,9 @@
 	fep->tx_align = 0x3;
 #endif
 
-	fec_enet_alloc_queue(ndev);
+	ret = fec_enet_alloc_queue(ndev);
+	if (ret)
+		return ret;
 
 	if (fep->bufdesc_ex)
 		fep->bufdesc_size = sizeof(struct bufdesc_ex);
@@ -3160,7 +3138,8 @@
 	cbd_base = dmam_alloc_coherent(&fep->pdev->dev, bd_size, &bd_dma,
 				       GFP_KERNEL);
 	if (!cbd_base) {
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto free_queue_mem;
 	}
 
 	memset(cbd_base, 0, bd_size);
@@ -3233,6 +3212,10 @@
 	fec_restart(ndev);
 
 	return 0;
+
+free_queue_mem:
+	fec_enet_free_queue(ndev);
+	return ret;
 }
 
 #ifdef CONFIG_OF
@@ -3538,6 +3521,8 @@
 	fec_enet_mii_remove(fep);
 	if (fep->reg_phy)
 		regulator_disable(fep->reg_phy);
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 	of_node_put(fep->phy_node);
 	free_netdev(ndev);
 
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
@@ -231,3 +231,4 @@
 };
 
 module_platform_driver(fs_enet_bb_mdio_driver);
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
@@ -232,3 +232,4 @@
 };
 
 module_platform_driver(fs_enet_fec_mdio_driver);
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -382,7 +382,7 @@
 {
 	const struct of_device_id *id =
 		of_match_device(fsl_pq_mdio_match, &pdev->dev);
-	const struct fsl_pq_mdio_data *data = id->data;
+	const struct fsl_pq_mdio_data *data;
 	struct device_node *np = pdev->dev.of_node;
 	struct resource res;
 	struct device_node *tbi;
@@ -390,6 +390,13 @@
 	struct mii_bus *new_bus;
 	int err;
 
+	if (!id) {
+		dev_err(&pdev->dev, "Failed to match device\n");
+		return -ENODEV;
+	}
+
+	data = id->data;
+
 	dev_dbg(&pdev->dev, "found %s compatible node\n", id->compatible);
 
 	new_bus = mdiobus_alloc_size(sizeof(*priv));
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/gianfar.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/gianfar.c
@@ -845,8 +845,10 @@
 				continue;
 
 			err = gfar_parse_group(child, priv, model);
-			if (err)
+			if (err) {
+				of_node_put(child);
 				goto err_grp_init;
+			}
 		}
 	} else { /* SQ_SG_MODE */
 		err = gfar_parse_group(np, priv, model);
@@ -1375,13 +1377,15 @@
 
 	gfar_init_addr_hash_table(priv);
 
-	/* Insert receive time stamps into padding alignment bytes */
+	/* Insert receive time stamps into padding alignment bytes, and
+	 * plus 2 bytes padding to ensure the cpu alignment.
+	 */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
-		priv->padding = 8;
+		priv->padding = 8 + DEFAULT_PADDING;
 
 	if (dev->features & NETIF_F_IP_CSUM ||
 	    priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
-		dev->needed_headroom = GMAC_FCB_LEN;
+		dev->needed_headroom = GMAC_FCB_LEN + GMAC_TXPAL_LEN;
 
 	/* Initializing some of the rx/tx queue level parameters */
 	for (i = 0; i < priv->num_tx_queues; i++) {
@@ -1999,8 +2003,8 @@
 		if (!rxb->page)
 			continue;
 
-		dma_unmap_single(rx_queue->dev, rxb->dma,
-				 PAGE_SIZE, DMA_FROM_DEVICE);
+		dma_unmap_page(rx_queue->dev, rxb->dma,
+			       PAGE_SIZE, DMA_FROM_DEVICE);
 		__free_page(rxb->page);
 
 		rxb->page = NULL;
@@ -2349,20 +2353,12 @@
 		fcb_len = GMAC_FCB_LEN + GMAC_TXPAL_LEN;
 
 	/* make space for additional header when fcb is needed */
-	if (fcb_len && unlikely(skb_headroom(skb) < fcb_len)) {
-		struct sk_buff *skb_new;
-
-		skb_new = skb_realloc_headroom(skb, fcb_len);
-		if (!skb_new) {
+	if (fcb_len) {
+		if (unlikely(skb_cow_head(skb, fcb_len))) {
 			dev->stats.tx_errors++;
 			dev_kfree_skb_any(skb);
 			return NETDEV_TX_OK;
 		}
-
-		if (skb->sk)
-			skb_set_owner_w(skb_new, skb->sk);
-		dev_consume_skb_any(skb);
-		skb = skb_new;
 	}
 
 	/* total number of fragments in the SKB */
@@ -2677,13 +2673,17 @@
 	skb_dirtytx = tx_queue->skb_dirtytx;
 
 	while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) {
+		bool do_tstamp;
+
+		do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+			    priv->hwts_tx_en;
 
 		frags = skb_shinfo(skb)->nr_frags;
 
 		/* 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))
+		if (unlikely(do_tstamp))
 			nr_txbds = frags + 2;
 		else
 			nr_txbds = frags + 1;
@@ -2697,7 +2697,7 @@
 		    (lstatus & BD_LENGTH_MASK))
 			break;
 
-		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+		if (unlikely(do_tstamp)) {
 			next = next_txbd(bdp, base, tx_ring_size);
 			buflen = be16_to_cpu(next->length) +
 				 GMAC_FCB_LEN + GMAC_TXPAL_LEN;
@@ -2707,7 +2707,7 @@
 		dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr),
 				 buflen, DMA_TO_DEVICE);
 
-		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+		if (unlikely(do_tstamp)) {
 			struct skb_shared_hwtstamps shhwtstamps;
 			u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) &
 					  ~0x7UL);
@@ -2939,7 +2939,7 @@
 				size, GFAR_RXB_TRUESIZE);
 
 	/* try reuse page */
-	if (unlikely(page_count(page) != 1))
+	if (unlikely(page_count(page) != 1 || page_is_pfmemalloc(page)))
 		return false;
 
 	/* change offset to the other half */
@@ -3051,9 +3051,6 @@
 	if (ndev->features & NETIF_F_RXCSUM)
 		gfar_rx_checksum(skb, fcb);
 
-	/* Tell the skb what kind of packet this is */
-	skb->protocol = eth_type_trans(skb, ndev);
-
 	/* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here.
 	 * Even if vlan rx accel is disabled, on some chips
 	 * RXFCB_VLN is pseudo randomly set.
@@ -3124,13 +3121,15 @@
 			continue;
 		}
 
+		gfar_process_frame(ndev, skb);
+
 		/* Increment the number of packets */
 		total_pkts++;
 		total_bytes += skb->len;
 
 		skb_record_rx_queue(skb, rx_queue->qindex);
 
-		gfar_process_frame(ndev, skb);
+		skb->protocol = eth_type_trans(skb, ndev);
 
 		/* Send the packet up the stack */
 		napi_gro_receive(&rx_queue->grp->napi_rx, skb);
@@ -3676,7 +3675,7 @@
 		u32 tempval1 = gfar_read(&regs->maccfg1);
 		u32 tempval = gfar_read(&regs->maccfg2);
 		u32 ecntrl = gfar_read(&regs->ecntrl);
-		u32 tx_flow_oldval = (tempval & MACCFG1_TX_FLOW);
+		u32 tx_flow_oldval = (tempval1 & MACCFG1_TX_FLOW);
 
 		if (phydev->duplex != priv->oldduplex) {
 			if (!(phydev->duplex))
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/gianfar_ptp.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/gianfar_ptp.c
@@ -314,11 +314,10 @@
 	now = tmr_cnt_read(etsects);
 	now += delta;
 	tmr_cnt_write(etsects, now);
+	set_fipers(etsects);
 
 	spin_unlock_irqrestore(&etsects->lock, flags);
 
-	set_fipers(etsects);
-
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/ucc_geth.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/ucc_geth.c
@@ -45,6 +45,7 @@
 #include <asm/ucc.h>
 #include <asm/ucc_fast.h>
 #include <asm/machdep.h>
+#include <net/sch_generic.h>
 
 #include "ucc_geth.h"
 
@@ -1551,11 +1552,8 @@
 
 static void ugeth_quiesce(struct ucc_geth_private *ugeth)
 {
-	/* Prevent any further xmits, plus detach the device. */
-	netif_device_detach(ugeth->ndev);
-
-	/* Wait for any current xmits to finish. */
-	netif_tx_disable(ugeth->ndev);
+	/* Prevent any further xmits */
+	netif_tx_stop_all_queues(ugeth->ndev);
 
 	/* Disable the interrupt to avoid NAPI rescheduling. */
 	disable_irq(ugeth->ug_info->uf_info.irq);
@@ -1568,7 +1566,10 @@
 {
 	napi_enable(&ugeth->napi);
 	enable_irq(ugeth->ug_info->uf_info.irq);
-	netif_device_attach(ugeth->ndev);
+
+	/* allow to xmit again  */
+	netif_tx_wake_all_queues(ugeth->ndev);
+	__netdev_watchdog_up(ugeth->ndev);
 }
 
 /* Called every time the controller might need to be made
@@ -1888,6 +1889,8 @@
 	u16 i, j;
 	u8 __iomem *bd;
 
+	netdev_reset_queue(ugeth->ndev);
+
 	ug_info = ugeth->ug_info;
 	uf_info = &ug_info->uf_info;
 
@@ -3931,10 +3934,10 @@
 	struct ucc_geth_private *ugeth = netdev_priv(dev);
 
 	unregister_netdev(dev);
-	free_netdev(dev);
 	ucc_geth_memclean(ugeth);
 	of_node_put(ugeth->ug_info->tbi_node);
 	of_node_put(ugeth->ug_info->phy_node);
+	free_netdev(dev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/ucc_geth.h
+++ linux-4.4.0/drivers/net/ethernet/freescale/ucc_geth.h
@@ -580,7 +580,14 @@
 	u32 vtagtable[0x8];	/* 8 4-byte VLAN tags */
 	u32 tqptr;		/* a base pointer to the Tx Queues Memory
 				   Region */
-	u8 res2[0x80 - 0x74];
+	u8 res2[0x78 - 0x74];
+	u64 snums_en;
+	u32 l2l3baseptr;	/* top byte consists of a few other bit fields */
+
+	u16 mtu[8];
+	u8 res3[0xa8 - 0x94];
+	u32 wrrtablebase;	/* top byte is reserved */
+	u8 res4[0xc0 - 0xac];
 } __packed;
 
 /* structure representing Extended Filtering Global Parameters in PRAM */
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
@@ -253,14 +253,12 @@
 		return -EINVAL;
 	}
 
+	if (netif_running(netdev))
+		return -EBUSY;
+
 	ug_info->bdRingLenRx[queue] = ring->rx_pending;
 	ug_info->bdRingLenTx[queue] = ring->tx_pending;
 
-	if (netif_running(netdev)) {
-		/* FIXME: restart automatically */
-		netdev_info(netdev, "Please re-open the interface\n");
-	}
-
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/freescale/xgmac_mdio.c
+++ linux-4.4.0/drivers/net/ethernet/freescale/xgmac_mdio.c
@@ -49,6 +49,7 @@
 struct mdio_fsl_priv {
 	struct	tgec_mdio_controller __iomem *mdio_base;
 	bool	is_little_endian;
+	bool	has_a011043;
 };
 
 static u32 xgmac_read32(void __iomem *regs,
@@ -226,7 +227,8 @@
 		return ret;
 
 	/* Return all Fs if nothing was there */
-	if (xgmac_read32(&regs->mdio_stat, endian) & MDIO_STAT_RD_ER) {
+	if ((xgmac_read32(&regs->mdio_stat, endian) & MDIO_STAT_RD_ER) &&
+	    !priv->has_a011043) {
 		dev_err(&bus->dev,
 			"Error while reading PHY%d reg at %d.%hhu\n",
 			phy_id, dev_addr, regnum);
@@ -277,6 +279,9 @@
 	else
 		priv->is_little_endian = false;
 
+	priv->has_a011043 = of_property_read_bool(pdev->dev.of_node,
+						  "fsl,erratum-a011043");
+
 	ret = of_mdiobus_register(bus, np);
 	if (ret) {
 		dev_err(&pdev->dev, "cannot register MDIO bus\n");
--- linux-4.4.0.orig/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ linux-4.4.0/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -548,6 +548,11 @@
 	return -1;
 
     base = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
+    if (!base) {
+	pcmcia_release_window(link, link->resource[2]);
+	return -1;
+    }
+
     pcmcia_map_mem_page(link, link->resource[2], 0);
 
     /*
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -157,6 +157,7 @@
 	unsigned int reg_inten;
 
 	struct napi_struct napi;
+	struct device *dev;
 	struct net_device *ndev;
 
 	struct tx_desc *tx_desc;
@@ -173,6 +174,7 @@
 	dma_addr_t rx_phys[RX_DESC_NUM];
 	unsigned int rx_head;
 	unsigned int rx_buf_size;
+	unsigned int rx_cnt_remaining;
 
 	struct device_node *phy_node;
 	struct phy_device *phy;
@@ -185,7 +187,7 @@
 
 static inline unsigned int tx_count(unsigned int head, unsigned int tail)
 {
-	return (head - tail) % (TX_DESC_NUM - 1);
+	return (head - tail) % TX_DESC_NUM;
 }
 
 static void hip04_config_port(struct net_device *ndev, u32 speed, u32 duplex)
@@ -387,7 +389,7 @@
 		}
 
 		if (priv->tx_phys[tx_tail]) {
-			dma_unmap_single(&ndev->dev, priv->tx_phys[tx_tail],
+			dma_unmap_single(priv->dev, priv->tx_phys[tx_tail],
 					 priv->tx_skb[tx_tail]->len,
 					 DMA_TO_DEVICE);
 			priv->tx_phys[tx_tail] = 0;
@@ -437,8 +439,8 @@
 		return NETDEV_TX_BUSY;
 	}
 
-	phys = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE);
-	if (dma_mapping_error(&ndev->dev, phys)) {
+	phys = dma_map_single(priv->dev, skb->data, skb->len, DMA_TO_DEVICE);
+	if (dma_mapping_error(priv->dev, phys)) {
 		dev_kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
@@ -453,9 +455,9 @@
 	skb_tx_timestamp(skb);
 
 	hip04_set_xmit_desc(priv, phys);
-	priv->tx_head = TX_NEXT(tx_head);
 	count++;
 	netdev_sent_queue(ndev, skb->len);
+	priv->tx_head = TX_NEXT(tx_head);
 
 	stats->tx_bytes += skb->len;
 	stats->tx_packets++;
@@ -486,7 +488,6 @@
 	struct hip04_priv *priv = container_of(napi, struct hip04_priv, napi);
 	struct net_device *ndev = priv->ndev;
 	struct net_device_stats *stats = &ndev->stats;
-	unsigned int cnt = hip04_recv_cnt(priv);
 	struct rx_desc *desc;
 	struct sk_buff *skb;
 	unsigned char *buf;
@@ -497,13 +498,16 @@
 	u16 len;
 	u32 err;
 
-	while (cnt && !last) {
+	/* clean up tx descriptors */
+	tx_remaining = hip04_tx_reclaim(ndev, false);
+	priv->rx_cnt_remaining += hip04_recv_cnt(priv);
+	while (priv->rx_cnt_remaining && !last) {
 		buf = priv->rx_buf[priv->rx_head];
 		skb = build_skb(buf, priv->rx_buf_size);
 		if (unlikely(!skb))
 			net_dbg_ratelimited("build_skb failed\n");
 
-		dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head],
+		dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head],
 				 RX_BUF_SIZE, DMA_FROM_DEVICE);
 		priv->rx_phys[priv->rx_head] = 0;
 
@@ -531,20 +535,22 @@
 		buf = netdev_alloc_frag(priv->rx_buf_size);
 		if (!buf)
 			goto done;
-		phys = dma_map_single(&ndev->dev, buf,
+		phys = dma_map_single(priv->dev, buf,
 				      RX_BUF_SIZE, DMA_FROM_DEVICE);
-		if (dma_mapping_error(&ndev->dev, phys))
+		if (dma_mapping_error(priv->dev, phys))
 			goto done;
 		priv->rx_buf[priv->rx_head] = buf;
 		priv->rx_phys[priv->rx_head] = phys;
 		hip04_set_recv_desc(priv, phys);
 
 		priv->rx_head = RX_NEXT(priv->rx_head);
-		if (rx >= budget)
+		if (rx >= budget) {
+			--priv->rx_cnt_remaining;
 			goto done;
+		}
 
-		if (--cnt == 0)
-			cnt = hip04_recv_cnt(priv);
+		if (--priv->rx_cnt_remaining == 0)
+			priv->rx_cnt_remaining += hip04_recv_cnt(priv);
 	}
 
 	if (!(priv->reg_inten & RCV_INT)) {
@@ -554,8 +560,7 @@
 	}
 	napi_complete(napi);
 done:
-	/* clean up tx descriptors and start a new timer if necessary */
-	tx_remaining = hip04_tx_reclaim(ndev, false);
+	/* start a new timer if necessary */
 	if (rx < budget && tx_remaining)
 		hip04_start_tx_timer(priv);
 
@@ -630,6 +635,7 @@
 	int i;
 
 	priv->rx_head = 0;
+	priv->rx_cnt_remaining = 0;
 	priv->tx_head = 0;
 	priv->tx_tail = 0;
 	hip04_reset_ppe(priv);
@@ -637,9 +643,9 @@
 	for (i = 0; i < RX_DESC_NUM; i++) {
 		dma_addr_t phys;
 
-		phys = dma_map_single(&ndev->dev, priv->rx_buf[i],
+		phys = dma_map_single(priv->dev, priv->rx_buf[i],
 				      RX_BUF_SIZE, DMA_FROM_DEVICE);
-		if (dma_mapping_error(&ndev->dev, phys))
+		if (dma_mapping_error(priv->dev, phys))
 			return -EIO;
 
 		priv->rx_phys[i] = phys;
@@ -673,7 +679,7 @@
 
 	for (i = 0; i < RX_DESC_NUM; i++) {
 		if (priv->rx_phys[i]) {
-			dma_unmap_single(&ndev->dev, priv->rx_phys[i],
+			dma_unmap_single(priv->dev, priv->rx_phys[i],
 					 RX_BUF_SIZE, DMA_FROM_DEVICE);
 			priv->rx_phys[i] = 0;
 		}
@@ -824,6 +830,7 @@
 		return -ENOMEM;
 
 	priv = netdev_priv(ndev);
+	priv->dev = d;
 	priv->ndev = ndev;
 	platform_set_drvdata(pdev, ndev);
 
@@ -919,10 +926,8 @@
 	}
 
 	ret = register_netdev(ndev);
-	if (ret) {
-		free_netdev(ndev);
+	if (ret)
 		goto alloc_fail;
-	}
 
 	return 0;
 
@@ -945,7 +950,6 @@
 
 	hip04_free_ring(ndev, d);
 	unregister_netdev(ndev);
-	free_irq(ndev->irq, ndev);
 	of_node_put(priv->phy_node);
 	cancel_work_sync(&priv->tx_timeout_task);
 	free_netdev(ndev);
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
@@ -951,7 +951,7 @@
 		goto err_free_mdio;
 
 	priv->phy_mode = of_get_phy_mode(node);
-	if (priv->phy_mode < 0) {
+	if ((int)priv->phy_mode < 0) {
 		netdev_err(ndev, "not find phy-mode\n");
 		ret = -EINVAL;
 		goto err_mdiobus;
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hns/hnae.c
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hns/hnae.c
@@ -144,7 +144,6 @@
 /* free desc along with its attached buffer */
 static void hnae_free_desc(struct hnae_ring *ring)
 {
-	hnae_free_buffers(ring);
 	dma_unmap_single(ring_to_dev(ring), ring->desc_dma_addr,
 			 ring->desc_num * sizeof(ring->desc[0]),
 			 ring_to_dma_dir(ring));
@@ -177,6 +176,9 @@
 /* fini ring, also free the buffer for the ring */
 static void hnae_fini_ring(struct hnae_ring *ring)
 {
+	if (is_rx_ring(ring))
+		hnae_free_buffers(ring);
+
 	hnae_free_desc(ring);
 	kfree(ring->desc_cb);
 	ring->desc_cb = NULL;
@@ -329,8 +331,10 @@
 		return ERR_PTR(-ENODEV);
 
 	handle = dev->ops->get_handle(dev, port_id);
-	if (IS_ERR(handle))
+	if (IS_ERR(handle)) {
+		put_device(&dev->cls_dev);
 		return handle;
+	}
 
 	handle->dev = dev;
 	handle->owner_dev = owner_dev;
@@ -353,6 +357,8 @@
 	for (j = i - 1; j >= 0; j--)
 		hnae_fini_queue(handle->qs[j]);
 
+	put_device(&dev->cls_dev);
+
 	return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL(hnae_get_handle);
@@ -374,6 +380,8 @@
 		dev->ops->put_handle(h);
 
 	module_put(dev->owner);
+
+	put_device(&dev->cls_dev);
 }
 EXPORT_SYMBOL(hnae_put_handle);
 
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -171,10 +171,10 @@
 
 	/* priv data for the desc, e.g. skb when use with ip stack*/
 	void *priv;
-	u16 page_offset;
-	u16 reuse_flag;
+	u32 page_offset;
+	u32 length;     /* length of the buffer */
 
-	u16 length;     /* length of the buffer */
+	u16 reuse_flag;
 
        /* desc type, used by the ring user to mark the type of the priv data */
 	u16 type;
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -188,12 +188,10 @@
 	struct hnae_vf_cb *vf_cb = hns_ae_get_vf_cb(handle);
 	int i;
 
-	vf_cb->mac_cb	 = NULL;
-
-	kfree(vf_cb);
-
 	for (i = 0; i < handle->q_num; i++)
 		hns_ae_get_ring_pair(handle->qs[i])->used_by_vf = 0;
+
+	kfree(vf_cb);
 }
 
 static void hns_ae_ring_enable_all(struct hnae_handle *handle, int val)
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
@@ -900,9 +900,7 @@
 
 static inline void dsaf_write_reg(void __iomem *base, u32 reg, u32 value)
 {
-	u8 __iomem *reg_addr = ACCESS_ONCE(base);
-
-	writel(value, reg_addr + reg);
+	writel(value, base + reg);
 }
 
 #define dsaf_write_dev(a, reg, value) \
@@ -910,9 +908,7 @@
 
 static inline u32 dsaf_read_reg(u8 __iomem *base, u32 reg)
 {
-	u8 __iomem *reg_addr = ACCESS_ONCE(base);
-
-	return readl(reg_addr + reg);
+	return readl(base + reg);
 }
 
 #define dsaf_read_dev(a, reg) \
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
@@ -776,7 +776,7 @@
  */
 static int hns_xgmac_get_sset_count(int stringset)
 {
-	if (stringset == ETH_SS_STATS)
+	if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
 		return ARRAY_SIZE(g_xgmac_stats_string);
 
 	return 0;
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -28,9 +28,6 @@
 
 #define SERVICE_TIMER_HZ (1 * HZ)
 
-#define NIC_TX_CLEAN_MAX_NUM 256
-#define NIC_RX_CLEAN_MAX_NUM 64
-
 #define RCB_IRQ_NOT_INITED 0
 #define RCB_IRQ_INITED 1
 
@@ -105,8 +102,8 @@
 			struct hns_nic_ring_data *ring_data)
 {
 	struct hns_nic_priv *priv = netdev_priv(ndev);
-	struct device *dev = priv->dev;
 	struct hnae_ring *ring = ring_data->ring;
+	struct device *dev = ring_to_dev(ring);
 	struct netdev_queue *dev_queue;
 	struct skb_frag_struct *frag;
 	int buf_num;
@@ -1408,7 +1405,7 @@
 		rd->fini_process = hns_nic_tx_fini_pro;
 
 		netif_napi_add(priv->netdev, &rd->napi,
-			       hns_nic_common_poll, NIC_TX_CLEAN_MAX_NUM);
+			       hns_nic_common_poll, NAPI_POLL_WEIGHT);
 		rd->ring->irq_init_flag = RCB_IRQ_NOT_INITED;
 	}
 	for (i = h->q_num; i < h->q_num * 2; i++) {
@@ -1420,7 +1417,7 @@
 		rd->fini_process = hns_nic_rx_fini_pro;
 
 		netif_napi_add(priv->netdev, &rd->napi,
-			       hns_nic_common_poll, NIC_RX_CLEAN_MAX_NUM);
+			       hns_nic_common_poll, NAPI_POLL_WEIGHT);
 		rd->ring->irq_init_flag = RCB_IRQ_NOT_INITED;
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -351,6 +351,7 @@
 static int __lb_up(struct net_device *ndev,
 		   enum hnae_loop loop_mode)
 {
+#define NIC_LB_TEST_WAIT_PHY_LINK_TIME 300
 	struct hns_nic_priv *priv = netdev_priv(ndev);
 	struct hnae_handle *h = priv->ae_handle;
 	int speed, duplex;
@@ -389,6 +390,9 @@
 
 	h->dev->ops->adjust_link(h, speed, duplex);
 
+	/* wait adjust link done and phy ready */
+	msleep(NIC_LB_TEST_WAIT_PHY_LINK_TIME);
+
 	return 0;
 }
 
@@ -429,6 +433,10 @@
 	/* for mutl buffer*/
 	new_skb = skb_copy(skb, GFP_ATOMIC);
 	dev_kfree_skb_any(skb);
+	if (!new_skb) {
+		netdev_err(ndev, "skb alloc failed\n");
+		return;
+	}
 	skb = new_skb;
 
 	check_ok = 0;
@@ -1000,8 +1008,10 @@
 			cnt--;
 
 		return cnt;
-	} else {
+	} else if (stringset == ETH_SS_STATS) {
 		return (HNS_NET_STATS_CNT + ops->get_sset_count(h, stringset));
+	} else {
+		return -EOPNOTSUPP;
 	}
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/hisilicon/hns_mdio.c
+++ linux-4.4.0/drivers/net/ethernet/hisilicon/hns_mdio.c
@@ -156,11 +156,15 @@
 {
 	u32 time_cnt;
 	u32 reg_value;
+	int ret;
 
 	regmap_write(mdio_dev->subctrl_vbase, cfg_reg, set_val);
 
 	for (time_cnt = MDIO_TIMEOUT; time_cnt; time_cnt--) {
-		regmap_read(mdio_dev->subctrl_vbase, st_reg, &reg_value);
+		ret = regmap_read(mdio_dev->subctrl_vbase, st_reg, &reg_value);
+		if (ret)
+			return ret;
+
 		reg_value &= st_msk;
 		if ((!!check_st) == (!!reg_value))
 			break;
@@ -319,7 +323,7 @@
 		}
 
 		hns_mdio_cmd_write(mdio_dev, is_c45,
-				   MDIO_C45_WRITE_ADDR, phy_id, devad);
+				   MDIO_C45_READ, phy_id, devad);
 	}
 
 	/* Step 5: waitting for MDIO_COMMAND_REG 's mdio_start==0,*/
--- linux-4.4.0.orig/drivers/net/ethernet/hp/hp100.c
+++ linux-4.4.0/drivers/net/ethernet/hp/hp100.c
@@ -194,7 +194,6 @@
 };
 #endif
 
-#ifdef CONFIG_EISA
 static struct eisa_device_id hp100_eisa_tbl[] = {
 	{ "HWPF180" }, /* HP J2577 rev A */
 	{ "HWP1920" }, /* HP 27248B */
@@ -205,9 +204,7 @@
 	{ "" }	       /* Mandatory final entry ! */
 };
 MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl);
-#endif
 
-#ifdef CONFIG_PCI
 static const struct pci_device_id hp100_pci_tbl[] = {
 	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,},
 	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,},
@@ -219,7 +216,6 @@
 	{}			/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, hp100_pci_tbl);
-#endif
 
 static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
 static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
@@ -2640,7 +2636,7 @@
 		/* Wait for link to drop */
 		time = jiffies + (HZ / 10);
 		do {
-			if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST))
+			if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST))
 				break;
 			if (!in_interrupt())
 				schedule_timeout_interruptible(1);
@@ -2842,8 +2838,7 @@
 	free_netdev(d);
 }
 
-#ifdef CONFIG_EISA
-static int __init hp100_eisa_probe (struct device *gendev)
+static int hp100_eisa_probe(struct device *gendev)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
 	struct eisa_device *edev = to_eisa_device(gendev);
@@ -2884,9 +2879,7 @@
 		.remove  = hp100_eisa_remove,
         }
 };
-#endif
 
-#ifdef CONFIG_PCI
 static int hp100_pci_probe(struct pci_dev *pdev,
 			   const struct pci_device_id *ent)
 {
@@ -2955,7 +2948,6 @@
 	.probe		= hp100_pci_probe,
 	.remove		= hp100_pci_remove,
 };
-#endif
 
 /*
  *  module section
@@ -2976,7 +2968,7 @@
 #define HP100_DEVICES 5
 /* Parameters set by insmod */
 static int hp100_port[HP100_DEVICES] = { 0, [1 ... (HP100_DEVICES-1)] = -1 };
-module_param_array(hp100_port, int, NULL, 0);
+module_param_hw_array(hp100_port, int, ioport, NULL, 0);
 
 /* List of devices */
 static struct net_device *hp100_devlist[HP100_DEVICES];
@@ -3032,23 +3024,17 @@
 	err = hp100_isa_init();
 	if (err && err != -ENODEV)
 		goto out;
-#ifdef CONFIG_EISA
 	err = eisa_driver_register(&hp100_eisa_driver);
 	if (err && err != -ENODEV)
 		goto out2;
-#endif
-#ifdef CONFIG_PCI
 	err = pci_register_driver(&hp100_pci_driver);
 	if (err && err != -ENODEV)
 		goto out3;
-#endif
  out:
 	return err;
  out3:
-#ifdef CONFIG_EISA
 	eisa_driver_unregister (&hp100_eisa_driver);
  out2:
-#endif
 	hp100_isa_cleanup();
 	goto out;
 }
@@ -3057,12 +3043,8 @@
 static void __exit hp100_module_exit(void)
 {
 	hp100_isa_cleanup();
-#ifdef CONFIG_EISA
 	eisa_driver_unregister (&hp100_eisa_driver);
-#endif
-#ifdef CONFIG_PCI
 	pci_unregister_driver (&hp100_pci_driver);
-#endif
 }
 
 module_init(hp100_module_init)
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/ibm/Kconfig
@@ -37,4 +37,14 @@
 	  To compile the driver as a module, choose M here. The module
 	  will be called ehea.
 
+config IBMVNIC
+	tristate "IBM Virtual NIC support"
+	depends on PPC_PSERIES
+	---help---
+	  This driver supports Virtual NIC adapters on IBM i and IBM System p
+	  systems.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called ibmvnic.
+
 endif # NET_VENDOR_IBM
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/Makefile
+++ linux-4.4.0/drivers/net/ethernet/ibm/Makefile
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_IBMVETH) += ibmveth.o
+obj-$(CONFIG_IBMVNIC) += ibmvnic.o
 obj-$(CONFIG_IBM_EMAC) += emac/
 obj-$(CONFIG_EHEA) += ehea/
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ linux-4.4.0/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -1169,16 +1169,15 @@
 	ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe);
 	portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe);
 	port = ehea_get_port(adapter, portnum);
+	if (!port) {
+		netdev_err(NULL, "unknown portnum %x\n", portnum);
+		return;
+	}
 	dev = port->netdev;
 
 	switch (ec) {
 	case EHEA_EC_PORTSTATE_CHG:	/* port state change */
 
-		if (!port) {
-			netdev_err(dev, "unknown portnum %x\n", portnum);
-			break;
-		}
-
 		if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
 			if (!netif_carrier_ok(dev)) {
 				ret = ehea_sense_port_attr(port);
@@ -1477,7 +1476,7 @@
 
 	memset(pr, 0, sizeof(struct ehea_port_res));
 
-	pr->tx_bytes = rx_bytes;
+	pr->tx_bytes = tx_bytes;
 	pr->tx_packets = tx_packets;
 	pr->rx_bytes = rx_bytes;
 	pr->rx_packets = rx_packets;
@@ -3183,6 +3182,7 @@
 
 	if (ehea_add_adapter_mr(adapter)) {
 		pr_err("creating MR failed\n");
+		of_node_put(eth_dn);
 		return -EIO;
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/emac/core.c
+++ linux-4.4.0/drivers/net/ethernet/ibm/emac/core.c
@@ -342,6 +342,7 @@
 {
 	struct emac_regs __iomem *p = dev->emacp;
 	int n = 20;
+	bool __maybe_unused try_internal_clock = false;
 
 	DBG(dev, "reset" NL);
 
@@ -354,6 +355,7 @@
 	}
 
 #ifdef CONFIG_PPC_DCR_NATIVE
+do_retry:
 	/*
 	 * PPC460EX/GT Embedded Processor Advanced User's Manual
 	 * section 28.10.1 Mode Register 0 (EMACx_MR0) states:
@@ -361,10 +363,19 @@
 	 * of the EMAC. If none is present, select the internal clock
 	 * (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1).
 	 * After a soft reset, select the external clock.
+	 *
+	 * The AR8035-A PHY Meraki MR24 does not provide a TX Clk if the
+	 * ethernet cable is not attached. This causes the reset to timeout
+	 * and the PHY detection code in emac_init_phy() is unable to
+	 * communicate and detect the AR8035-A PHY. As a result, the emac
+	 * driver bails out early and the user has no ethernet.
+	 * In order to stay compatible with existing configurations, the
+	 * driver will temporarily switch to the internal clock, after
+	 * the first reset fails.
 	 */
 	if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
-		if (dev->phy_address == 0xffffffff &&
-		    dev->phy_map == 0xffffffff) {
+		if (try_internal_clock || (dev->phy_address == 0xffffffff &&
+					   dev->phy_map == 0xffffffff)) {
 			/* No PHY: select internal loop clock before reset */
 			dcri_clrset(SDR0, SDR0_ETH_CFG,
 				    0, SDR0_ETH_CFG_ECS << dev->cell_index);
@@ -382,8 +393,15 @@
 
 #ifdef CONFIG_PPC_DCR_NATIVE
 	if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
-		if (dev->phy_address == 0xffffffff &&
-		    dev->phy_map == 0xffffffff) {
+		if (!n && !try_internal_clock) {
+			/* first attempt has timed out. */
+			n = 20;
+			try_internal_clock = true;
+			goto do_retry;
+		}
+
+		if (try_internal_clock || (dev->phy_address == 0xffffffff &&
+					   dev->phy_map == 0xffffffff)) {
 			/* No PHY: restore external clock source after reset */
 			dcri_clrset(SDR0, SDR0_ETH_CFG,
 				    SDR0_ETH_CFG_ECS << dev->cell_index, 0);
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/emac/mal.c
+++ linux-4.4.0/drivers/net/ethernet/ibm/emac/mal.c
@@ -402,7 +402,7 @@
 	unsigned long flags;
 
 	MAL_DBG2(mal, "poll(%d)" NL, budget);
- again:
+
 	/* Process TX skbs */
 	list_for_each(l, &mal->poll_list) {
 		struct mal_commac *mc =
@@ -451,7 +451,6 @@
 			spin_lock_irqsave(&mal->lock, flags);
 			mal_disable_eob_irq(mal);
 			spin_unlock_irqrestore(&mal->lock, flags);
-			goto again;
 		}
 		mc->ops->poll_tx(mc->dev);
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/ibmveth.c
+++ linux-4.4.0/drivers/net/ethernet/ibm/ibmveth.c
@@ -58,7 +58,7 @@
 
 static const char ibmveth_driver_name[] = "ibmveth";
 static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver";
-#define ibmveth_driver_version "1.05"
+#define ibmveth_driver_version "1.06"
 
 MODULE_AUTHOR("Santiago Leon <santil@linux.vnet.ibm.com>");
 MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver");
@@ -137,6 +137,11 @@
 	return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK;
 }
 
+static inline int ibmveth_rxq_large_packet(struct ibmveth_adapter *adapter)
+{
+	return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_LRG_PKT;
+}
+
 static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
 {
 	return be32_to_cpu(adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
@@ -1158,11 +1163,15 @@
 
 map_failed_frags:
 	last = i+1;
-	for (i = 0; i < last; i++)
+	for (i = 1; i < last; i++)
 		dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address,
 			       descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK,
 			       DMA_TO_DEVICE);
 
+	dma_unmap_single(&adapter->vdev->dev,
+			 descs[0].fields.address,
+			 descs[0].fields.flags_len & IBMVETH_BUF_LEN_MASK,
+			 DMA_TO_DEVICE);
 map_failed:
 	if (!firmware_has_feature(FW_FEATURE_CMO))
 		netdev_err(netdev, "tx: unable to map xmit buffer\n");
@@ -1172,6 +1181,53 @@
 	goto retry_bounce;
 }
 
+static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
+{
+	struct tcphdr *tcph;
+	int offset = 0;
+	int hdr_len;
+
+	/* only TCP packets will be aggregated */
+	if (skb->protocol == htons(ETH_P_IP)) {
+		struct iphdr *iph = (struct iphdr *)skb->data;
+
+		if (iph->protocol == IPPROTO_TCP) {
+			offset = iph->ihl * 4;
+			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+		} else {
+			return;
+		}
+	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		struct ipv6hdr *iph6 = (struct ipv6hdr *)skb->data;
+
+		if (iph6->nexthdr == IPPROTO_TCP) {
+			offset = sizeof(struct ipv6hdr);
+			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+		} else {
+			return;
+		}
+	} else {
+		return;
+	}
+	/* if mss is not set through Large Packet bit/mss in rx buffer,
+	 * expect that the mss will be written to the tcp header checksum.
+	 */
+	tcph = (struct tcphdr *)(skb->data + offset);
+	if (lrg_pkt) {
+		skb_shinfo(skb)->gso_size = mss;
+	} else if (offset) {
+		skb_shinfo(skb)->gso_size = ntohs(tcph->check);
+		tcph->check = 0;
+	}
+
+	if (skb_shinfo(skb)->gso_size) {
+		hdr_len = offset + tcph->doff * 4;
+		skb_shinfo(skb)->gso_segs =
+				DIV_ROUND_UP(skb->len - hdr_len,
+					     skb_shinfo(skb)->gso_size);
+	}
+}
+
 static int ibmveth_poll(struct napi_struct *napi, int budget)
 {
 	struct ibmveth_adapter *adapter =
@@ -1180,8 +1236,8 @@
 	int frames_processed = 0;
 	unsigned long lpar_rc;
 	struct iphdr *iph;
+	u16 mss = 0;
 
-restart_poll:
 	while (frames_processed < budget) {
 		if (!ibmveth_rxq_pending_buffer(adapter))
 			break;
@@ -1197,9 +1253,22 @@
 			int length = ibmveth_rxq_frame_length(adapter);
 			int offset = ibmveth_rxq_frame_offset(adapter);
 			int csum_good = ibmveth_rxq_csum_good(adapter);
+			int lrg_pkt = ibmveth_rxq_large_packet(adapter);
+			__sum16 iph_check = 0;
 
 			skb = ibmveth_rxq_get_buffer(adapter);
 
+			/* if the large packet bit is set in the rx queue
+			 * descriptor, the mss will be written by PHYP eight
+			 * bytes from the start of the rx buffer, which is
+			 * skb->data at this stage
+			 */
+			if (lrg_pkt) {
+				__be64 *rxmss = (__be64 *)(skb->data + 8);
+
+				mss = (u16)be64_to_cpu(*rxmss);
+			}
+
 			new_skb = NULL;
 			if (length < rx_copybreak)
 				new_skb = netdev_alloc_skb(netdev, length);
@@ -1233,11 +1302,25 @@
 					if (iph->check == 0xffff) {
 						iph->check = 0;
 						iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-						adapter->rx_large_packets++;
 					}
 				}
 			}
 
+			/* PHYP without PLSO support places a -1 in the ip
+			 * checksum for large send frames.
+			 */
+			if (skb->protocol == cpu_to_be16(ETH_P_IP)) {
+				struct iphdr *iph = (struct iphdr *)skb->data;
+
+				iph_check = iph->check;
+			}
+
+			if ((length > netdev->mtu + ETH_HLEN) ||
+			    lrg_pkt || iph_check == 0xffff) {
+				ibmveth_rx_mss_helper(skb, mss, lrg_pkt);
+				adapter->rx_large_packets++;
+			}
+
 			napi_gro_receive(napi, skb);	/* send it up */
 
 			netdev->stats.rx_packets++;
@@ -1263,7 +1346,6 @@
 		    napi_reschedule(napi)) {
 			lpar_rc = h_vio_signal(adapter->vdev->unit_address,
 					       VIO_IRQ_DISABLE);
-			goto restart_poll;
 		}
 	}
 
@@ -1484,7 +1566,7 @@
 	struct net_device *netdev;
 	struct ibmveth_adapter *adapter;
 	unsigned char *mac_addr_p;
-	unsigned int *mcastFilterSize_p;
+	__be32 *mcastFilterSize_p;
 	long ret;
 	unsigned long ret_attr;
 
@@ -1506,8 +1588,9 @@
 		return -EINVAL;
 	}
 
-	mcastFilterSize_p = (unsigned int *)vio_get_attribute(dev,
-						VETH_MCAST_FILTER_SIZE, NULL);
+	mcastFilterSize_p = (__be32 *)vio_get_attribute(dev,
+							VETH_MCAST_FILTER_SIZE,
+							NULL);
 	if (!mcastFilterSize_p) {
 		dev_err(&dev->dev, "Can't find VETH_MCAST_FILTER_SIZE "
 			"attribute\n");
@@ -1524,7 +1607,7 @@
 
 	adapter->vdev = dev;
 	adapter->netdev = netdev;
-	adapter->mcastFilterSize = *mcastFilterSize_p;
+	adapter->mcastFilterSize = be32_to_cpu(*mcastFilterSize_p);
 	adapter->pool_config = 0;
 
 	netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
@@ -1533,8 +1616,11 @@
 	netdev->netdev_ops = &ibmveth_netdev_ops;
 	netdev->ethtool_ops = &netdev_ethtool_ops;
 	SET_NETDEV_DEV(netdev, &dev->dev);
-	netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
-		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+	netdev->hw_features = NETIF_F_SG;
+	if (vio_get_attribute(dev, "ibm,illan-options", NULL) != NULL) {
+		netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+				       NETIF_F_RXCSUM;
+	}
 
 	netdev->features |= netdev->hw_features;
 
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/ibmveth.h
+++ linux-4.4.0/drivers/net/ethernet/ibm/ibmveth.h
@@ -209,6 +209,7 @@
 #define IBMVETH_RXQ_TOGGLE		0x80000000
 #define IBMVETH_RXQ_TOGGLE_SHIFT	31
 #define IBMVETH_RXQ_VALID		0x40000000
+#define IBMVETH_RXQ_LRG_PKT		0x04000000
 #define IBMVETH_RXQ_NO_CSUM		0x02000000
 #define IBMVETH_RXQ_CSUM_GOOD		0x01000000
 #define IBMVETH_RXQ_OFF_MASK		0x0000FFFF
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/ibmvnic.c
+++ linux-4.4.0/drivers/net/ethernet/ibm/ibmvnic.c
@@ -0,0 +1,3598 @@
+/**************************************************************************/
+/*                                                                        */
+/*  IBM System i and System p Virtual NIC Device Driver                   */
+/*  Copyright (C) 2014 IBM Corp.                                          */
+/*  Santiago Leon (santi_leon@yahoo.com)                                  */
+/*  Thomas Falcon (tlfalcon@linux.vnet.ibm.com)                           */
+/*  John Allen (jallen@linux.vnet.ibm.com)                                */
+/*                                                                        */
+/*  This program is free software; you can redistribute it and/or modify  */
+/*  it under the terms of the GNU General Public License as published by  */
+/*  the Free Software Foundation; either version 2 of the License, or     */
+/*  (at your option) any later version.                                   */
+/*                                                                        */
+/*  This program is distributed in the hope that it will be useful,       */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*  GNU General Public License for more details.                          */
+/*                                                                        */
+/*  You should have received a copy of the GNU General Public License     */
+/*  along with this program.                                              */
+/*                                                                        */
+/* This module contains the implementation of a virtual ethernet device   */
+/* for use with IBM i/p Series LPAR Linux. It utilizes the logical LAN    */
+/* option of the RS/6000 Platform Architecture to interface with virtual  */
+/* ethernet NICs that are presented to the partition by the hypervisor.   */
+/*									   */
+/* Messages are passed between the VNIC driver and the VNIC server using  */
+/* Command/Response Queues (CRQs) and sub CRQs (sCRQs). CRQs are used to  */
+/* issue and receive commands that initiate communication with the server */
+/* on driver initialization. Sub CRQs (sCRQs) are similar to CRQs, but    */
+/* are used by the driver to notify the server that a packet is           */
+/* ready for transmission or that a buffer has been added to receive a    */
+/* packet. Subsequently, sCRQs are used by the server to notify the       */
+/* driver that a packet transmission has been completed or that a packet  */
+/* has been received and placed in a waiting buffer.                      */
+/*                                                                        */
+/* In lieu of a more conventional "on-the-fly" DMA mapping strategy in    */
+/* which skbs are DMA mapped and immediately unmapped when the transmit   */
+/* or receive has been completed, the VNIC driver is required to use      */
+/* "long term mapping". This entails that large, continuous DMA mapped    */
+/* buffers are allocated on driver initialization and these buffers are   */
+/* then continuously reused to pass skbs to and from the VNIC server.     */
+/*                                                                        */
+/**************************************************************************/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/completion.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/ethtool.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <net/net_namespace.h>
+#include <asm/hvcall.h>
+#include <linux/atomic.h>
+#include <asm/vio.h>
+#include <asm/iommu.h>
+#include <linux/uaccess.h>
+#include <asm/firmware.h>
+#include <linux/seq_file.h>
+
+#include "ibmvnic.h"
+
+static const char ibmvnic_driver_name[] = "ibmvnic";
+static const char ibmvnic_driver_string[] = "IBM System i/p Virtual NIC Driver";
+
+MODULE_AUTHOR("Santiago Leon <santi_leon@yahoo.com>");
+MODULE_DESCRIPTION("IBM System i/p Virtual NIC Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(IBMVNIC_DRIVER_VERSION);
+
+static int ibmvnic_version = IBMVNIC_INITIAL_VERSION;
+static int ibmvnic_remove(struct vio_dev *);
+static void release_sub_crqs(struct ibmvnic_adapter *);
+static int ibmvnic_reset_crq(struct ibmvnic_adapter *);
+static int ibmvnic_send_crq_init(struct ibmvnic_adapter *);
+static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *);
+static int ibmvnic_send_crq(struct ibmvnic_adapter *, union ibmvnic_crq *);
+static int send_subcrq(struct ibmvnic_adapter *adapter, u64 remote_handle,
+		       union sub_crq *sub_crq);
+static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance);
+static int enable_scrq_irq(struct ibmvnic_adapter *,
+			   struct ibmvnic_sub_crq_queue *);
+static int disable_scrq_irq(struct ibmvnic_adapter *,
+			    struct ibmvnic_sub_crq_queue *);
+static int pending_scrq(struct ibmvnic_adapter *,
+			struct ibmvnic_sub_crq_queue *);
+static union sub_crq *ibmvnic_next_scrq(struct ibmvnic_adapter *,
+					struct ibmvnic_sub_crq_queue *);
+static int ibmvnic_poll(struct napi_struct *napi, int data);
+static void send_map_query(struct ibmvnic_adapter *adapter);
+static void send_request_map(struct ibmvnic_adapter *, dma_addr_t, __be32, u8);
+static void send_request_unmap(struct ibmvnic_adapter *, u8);
+
+struct ibmvnic_stat {
+	char name[ETH_GSTRING_LEN];
+	int offset;
+};
+
+#define IBMVNIC_STAT_OFF(stat) (offsetof(struct ibmvnic_adapter, stats) + \
+			     offsetof(struct ibmvnic_statistics, stat))
+#define IBMVNIC_GET_STAT(a, off) (*((u64 *)(((unsigned long)(a)) + off)))
+
+static const struct ibmvnic_stat ibmvnic_stats[] = {
+	{"rx_packets", IBMVNIC_STAT_OFF(rx_packets)},
+	{"rx_bytes", IBMVNIC_STAT_OFF(rx_bytes)},
+	{"tx_packets", IBMVNIC_STAT_OFF(tx_packets)},
+	{"tx_bytes", IBMVNIC_STAT_OFF(tx_bytes)},
+	{"ucast_tx_packets", IBMVNIC_STAT_OFF(ucast_tx_packets)},
+	{"ucast_rx_packets", IBMVNIC_STAT_OFF(ucast_rx_packets)},
+	{"mcast_tx_packets", IBMVNIC_STAT_OFF(mcast_tx_packets)},
+	{"mcast_rx_packets", IBMVNIC_STAT_OFF(mcast_rx_packets)},
+	{"bcast_tx_packets", IBMVNIC_STAT_OFF(bcast_tx_packets)},
+	{"bcast_rx_packets", IBMVNIC_STAT_OFF(bcast_rx_packets)},
+	{"align_errors", IBMVNIC_STAT_OFF(align_errors)},
+	{"fcs_errors", IBMVNIC_STAT_OFF(fcs_errors)},
+	{"single_collision_frames", IBMVNIC_STAT_OFF(single_collision_frames)},
+	{"multi_collision_frames", IBMVNIC_STAT_OFF(multi_collision_frames)},
+	{"sqe_test_errors", IBMVNIC_STAT_OFF(sqe_test_errors)},
+	{"deferred_tx", IBMVNIC_STAT_OFF(deferred_tx)},
+	{"late_collisions", IBMVNIC_STAT_OFF(late_collisions)},
+	{"excess_collisions", IBMVNIC_STAT_OFF(excess_collisions)},
+	{"internal_mac_tx_errors", IBMVNIC_STAT_OFF(internal_mac_tx_errors)},
+	{"carrier_sense", IBMVNIC_STAT_OFF(carrier_sense)},
+	{"too_long_frames", IBMVNIC_STAT_OFF(too_long_frames)},
+	{"internal_mac_rx_errors", IBMVNIC_STAT_OFF(internal_mac_rx_errors)},
+};
+
+static long h_reg_sub_crq(unsigned long unit_address, unsigned long token,
+			  unsigned long length, unsigned long *number,
+			  unsigned long *irq)
+{
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+	long rc;
+
+	rc = plpar_hcall(H_REG_SUB_CRQ, retbuf, unit_address, token, length);
+	*number = retbuf[0];
+	*irq = retbuf[1];
+
+	return rc;
+}
+
+/* net_device_ops functions */
+
+static void init_rx_pool(struct ibmvnic_adapter *adapter,
+			 struct ibmvnic_rx_pool *rx_pool, int num, int index,
+			 int buff_size, int active)
+{
+	netdev_dbg(adapter->netdev,
+		   "Initializing rx_pool %d, %d buffs, %d bytes each\n",
+		   index, num, buff_size);
+	rx_pool->size = num;
+	rx_pool->index = index;
+	rx_pool->buff_size = buff_size;
+	rx_pool->active = active;
+}
+
+static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
+				struct ibmvnic_long_term_buff *ltb, int size)
+{
+	struct device *dev = &adapter->vdev->dev;
+
+	ltb->size = size;
+	ltb->buff = dma_alloc_coherent(dev, ltb->size, &ltb->addr,
+				       GFP_KERNEL);
+
+	if (!ltb->buff) {
+		dev_err(dev, "Couldn't alloc long term buffer\n");
+		return -ENOMEM;
+	}
+	ltb->map_id = adapter->map_id;
+	adapter->map_id++;
+	send_request_map(adapter, ltb->addr,
+			 ltb->size, ltb->map_id);
+	init_completion(&adapter->fw_done);
+	wait_for_completion(&adapter->fw_done);
+	return 0;
+}
+
+static void free_long_term_buff(struct ibmvnic_adapter *adapter,
+				struct ibmvnic_long_term_buff *ltb)
+{
+	struct device *dev = &adapter->vdev->dev;
+
+	dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
+	send_request_unmap(adapter, ltb->map_id);
+}
+
+static int alloc_rx_pool(struct ibmvnic_adapter *adapter,
+			 struct ibmvnic_rx_pool *pool)
+{
+	struct device *dev = &adapter->vdev->dev;
+	int i;
+
+	pool->free_map = kcalloc(pool->size, sizeof(int), GFP_KERNEL);
+	if (!pool->free_map)
+		return -ENOMEM;
+
+	pool->rx_buff = kcalloc(pool->size, sizeof(struct ibmvnic_rx_buff),
+				GFP_KERNEL);
+
+	if (!pool->rx_buff) {
+		dev_err(dev, "Couldn't alloc rx buffers\n");
+		kfree(pool->free_map);
+		return -ENOMEM;
+	}
+
+	if (alloc_long_term_buff(adapter, &pool->long_term_buff,
+				 pool->size * pool->buff_size)) {
+		kfree(pool->free_map);
+		kfree(pool->rx_buff);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < pool->size; ++i)
+		pool->free_map[i] = i;
+
+	atomic_set(&pool->available, 0);
+	pool->next_alloc = 0;
+	pool->next_free = 0;
+
+	return 0;
+}
+
+static void replenish_rx_pool(struct ibmvnic_adapter *adapter,
+			      struct ibmvnic_rx_pool *pool)
+{
+	int count = pool->size - atomic_read(&pool->available);
+	struct device *dev = &adapter->vdev->dev;
+	int buffers_added = 0;
+	unsigned long lpar_rc;
+	union sub_crq sub_crq;
+	struct sk_buff *skb;
+	unsigned int offset;
+	dma_addr_t dma_addr;
+	unsigned char *dst;
+	u64 *handle_array;
+	int shift = 0;
+	int index;
+	int i;
+
+	handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
+				      be32_to_cpu(adapter->login_rsp_buf->
+				      off_rxadd_subcrqs));
+
+	for (i = 0; i < count; ++i) {
+		skb = alloc_skb(pool->buff_size, GFP_ATOMIC);
+		if (!skb) {
+			dev_err(dev, "Couldn't replenish rx buff\n");
+			adapter->replenish_no_mem++;
+			break;
+		}
+
+		index = pool->free_map[pool->next_free];
+
+		if (pool->rx_buff[index].skb)
+			dev_err(dev, "Inconsistent free_map!\n");
+
+		/* Copy the skb to the long term mapped DMA buffer */
+		offset = index * pool->buff_size;
+		dst = pool->long_term_buff.buff + offset;
+		memset(dst, 0, pool->buff_size);
+		dma_addr = pool->long_term_buff.addr + offset;
+		pool->rx_buff[index].data = dst;
+
+		pool->free_map[pool->next_free] = IBMVNIC_INVALID_MAP;
+		pool->rx_buff[index].dma = dma_addr;
+		pool->rx_buff[index].skb = skb;
+		pool->rx_buff[index].pool_index = pool->index;
+		pool->rx_buff[index].size = pool->buff_size;
+
+		memset(&sub_crq, 0, sizeof(sub_crq));
+		sub_crq.rx_add.first = IBMVNIC_CRQ_CMD;
+		sub_crq.rx_add.correlator =
+		    cpu_to_be64((u64)&pool->rx_buff[index]);
+		sub_crq.rx_add.ioba = cpu_to_be32(dma_addr);
+		sub_crq.rx_add.map_id = pool->long_term_buff.map_id;
+
+		/* The length field of the sCRQ is defined to be 24 bits so the
+		 * buffer size needs to be left shifted by a byte before it is
+		 * converted to big endian to prevent the last byte from being
+		 * truncated.
+		 */
+#ifdef __LITTLE_ENDIAN__
+		shift = 8;
+#endif
+		sub_crq.rx_add.len = cpu_to_be32(pool->buff_size << shift);
+
+		lpar_rc = send_subcrq(adapter, handle_array[pool->index],
+				      &sub_crq);
+		if (lpar_rc != H_SUCCESS)
+			goto failure;
+
+		buffers_added++;
+		adapter->replenish_add_buff_success++;
+		pool->next_free = (pool->next_free + 1) % pool->size;
+	}
+	atomic_add(buffers_added, &pool->available);
+	return;
+
+failure:
+	dev_info(dev, "replenish pools failure\n");
+	pool->free_map[pool->next_free] = index;
+	pool->rx_buff[index].skb = NULL;
+	if (!dma_mapping_error(dev, dma_addr))
+		dma_unmap_single(dev, dma_addr, pool->buff_size,
+				 DMA_FROM_DEVICE);
+
+	dev_kfree_skb_any(skb);
+	adapter->replenish_add_buff_failure++;
+	atomic_add(buffers_added, &pool->available);
+}
+
+static void replenish_pools(struct ibmvnic_adapter *adapter)
+{
+	int i;
+
+	if (adapter->migrated)
+		return;
+
+	adapter->replenish_task_cycles++;
+	for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+	     i++) {
+		if (adapter->rx_pool[i].active)
+			replenish_rx_pool(adapter, &adapter->rx_pool[i]);
+	}
+}
+
+static void free_rx_pool(struct ibmvnic_adapter *adapter,
+			 struct ibmvnic_rx_pool *pool)
+{
+	int i;
+
+	kfree(pool->free_map);
+	pool->free_map = NULL;
+
+	if (!pool->rx_buff)
+		return;
+
+	for (i = 0; i < pool->size; i++) {
+		if (pool->rx_buff[i].skb) {
+			dev_kfree_skb_any(pool->rx_buff[i].skb);
+			pool->rx_buff[i].skb = NULL;
+		}
+	}
+	kfree(pool->rx_buff);
+	pool->rx_buff = NULL;
+}
+
+static int ibmvnic_open(struct net_device *netdev)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_tx_pool *tx_pool;
+	union ibmvnic_crq crq;
+	int rxadd_subcrqs;
+	u64 *size_array;
+	int tx_subcrqs;
+	int i, j;
+
+	rxadd_subcrqs =
+	    be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+	tx_subcrqs =
+	    be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
+	size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
+				  be32_to_cpu(adapter->login_rsp_buf->
+					      off_rxadd_buff_size));
+	adapter->map_id = 1;
+	adapter->napi = kcalloc(adapter->req_rx_queues,
+				sizeof(struct napi_struct), GFP_KERNEL);
+	if (!adapter->napi)
+		goto alloc_napi_failed;
+	for (i = 0; i < adapter->req_rx_queues; i++) {
+		netif_napi_add(netdev, &adapter->napi[i], ibmvnic_poll,
+			       NAPI_POLL_WEIGHT);
+		napi_enable(&adapter->napi[i]);
+	}
+	adapter->rx_pool =
+	    kcalloc(rxadd_subcrqs, sizeof(struct ibmvnic_rx_pool), GFP_KERNEL);
+
+	if (!adapter->rx_pool)
+		goto rx_pool_arr_alloc_failed;
+	send_map_query(adapter);
+	for (i = 0; i < rxadd_subcrqs; i++) {
+		init_rx_pool(adapter, &adapter->rx_pool[i],
+			     IBMVNIC_BUFFS_PER_POOL, i,
+			     be64_to_cpu(size_array[i]), 1);
+		if (alloc_rx_pool(adapter, &adapter->rx_pool[i])) {
+			dev_err(dev, "Couldn't alloc rx pool\n");
+			goto rx_pool_alloc_failed;
+		}
+	}
+	adapter->tx_pool =
+	    kcalloc(tx_subcrqs, sizeof(struct ibmvnic_tx_pool), GFP_KERNEL);
+
+	if (!adapter->tx_pool)
+		goto tx_pool_arr_alloc_failed;
+	for (i = 0; i < tx_subcrqs; i++) {
+		tx_pool = &adapter->tx_pool[i];
+		tx_pool->tx_buff =
+		    kcalloc(adapter->max_tx_entries_per_subcrq,
+			    sizeof(struct ibmvnic_tx_buff), GFP_KERNEL);
+		if (!tx_pool->tx_buff)
+			goto tx_pool_alloc_failed;
+
+		if (alloc_long_term_buff(adapter, &tx_pool->long_term_buff,
+					 adapter->max_tx_entries_per_subcrq *
+					 adapter->req_mtu))
+			goto tx_ltb_alloc_failed;
+
+		tx_pool->free_map =
+		    kcalloc(adapter->max_tx_entries_per_subcrq,
+			    sizeof(int), GFP_KERNEL);
+		if (!tx_pool->free_map)
+			goto tx_fm_alloc_failed;
+
+		for (j = 0; j < adapter->max_tx_entries_per_subcrq; j++)
+			tx_pool->free_map[j] = j;
+
+		tx_pool->consumer_index = 0;
+		tx_pool->producer_index = 0;
+	}
+	adapter->bounce_buffer_size =
+	    (netdev->mtu + ETH_HLEN - 1) / PAGE_SIZE + 1;
+	adapter->bounce_buffer = kmalloc(adapter->bounce_buffer_size,
+					 GFP_KERNEL);
+	if (!adapter->bounce_buffer)
+		goto bounce_alloc_failed;
+
+	adapter->bounce_buffer_dma = dma_map_single(dev, adapter->bounce_buffer,
+						    adapter->bounce_buffer_size,
+						    DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, adapter->bounce_buffer_dma)) {
+		dev_err(dev, "Couldn't map tx bounce buffer\n");
+		goto bounce_map_failed;
+	}
+	replenish_pools(adapter);
+
+	/* We're ready to receive frames, enable the sub-crq interrupts and
+	 * set the logical link state to up
+	 */
+	for (i = 0; i < adapter->req_rx_queues; i++)
+		enable_scrq_irq(adapter, adapter->rx_scrq[i]);
+
+	for (i = 0; i < adapter->req_tx_queues; i++)
+		enable_scrq_irq(adapter, adapter->tx_scrq[i]);
+
+	memset(&crq, 0, sizeof(crq));
+	crq.logical_link_state.first = IBMVNIC_CRQ_CMD;
+	crq.logical_link_state.cmd = LOGICAL_LINK_STATE;
+	crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_UP;
+	ibmvnic_send_crq(adapter, &crq);
+
+	netif_start_queue(netdev);
+	return 0;
+
+bounce_map_failed:
+	kfree(adapter->bounce_buffer);
+bounce_alloc_failed:
+	i = tx_subcrqs - 1;
+	kfree(adapter->tx_pool[i].free_map);
+tx_fm_alloc_failed:
+	free_long_term_buff(adapter, &adapter->tx_pool[i].long_term_buff);
+tx_ltb_alloc_failed:
+	kfree(adapter->tx_pool[i].tx_buff);
+tx_pool_alloc_failed:
+	for (j = 0; j < i; j++) {
+		kfree(adapter->tx_pool[j].tx_buff);
+		free_long_term_buff(adapter,
+				    &adapter->tx_pool[j].long_term_buff);
+		kfree(adapter->tx_pool[j].free_map);
+	}
+	kfree(adapter->tx_pool);
+	adapter->tx_pool = NULL;
+tx_pool_arr_alloc_failed:
+	i = rxadd_subcrqs;
+rx_pool_alloc_failed:
+	for (j = 0; j < i; j++) {
+		free_rx_pool(adapter, &adapter->rx_pool[j]);
+		free_long_term_buff(adapter,
+				    &adapter->rx_pool[j].long_term_buff);
+	}
+	kfree(adapter->rx_pool);
+	adapter->rx_pool = NULL;
+rx_pool_arr_alloc_failed:
+	for (i = 0; i < adapter->req_rx_queues; i++)
+		napi_enable(&adapter->napi[i]);
+alloc_napi_failed:
+	return -ENOMEM;
+}
+
+static int ibmvnic_close(struct net_device *netdev)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	struct device *dev = &adapter->vdev->dev;
+	union ibmvnic_crq crq;
+	int i;
+
+	adapter->closing = true;
+
+	for (i = 0; i < adapter->req_rx_queues; i++)
+		napi_disable(&adapter->napi[i]);
+
+	netif_stop_queue(netdev);
+
+	if (adapter->bounce_buffer) {
+		if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) {
+			dma_unmap_single(&adapter->vdev->dev,
+					 adapter->bounce_buffer_dma,
+					 adapter->bounce_buffer_size,
+					 DMA_BIDIRECTIONAL);
+			adapter->bounce_buffer_dma = DMA_ERROR_CODE;
+		}
+		kfree(adapter->bounce_buffer);
+		adapter->bounce_buffer = NULL;
+	}
+
+	memset(&crq, 0, sizeof(crq));
+	crq.logical_link_state.first = IBMVNIC_CRQ_CMD;
+	crq.logical_link_state.cmd = LOGICAL_LINK_STATE;
+	crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_DN;
+	ibmvnic_send_crq(adapter, &crq);
+
+	for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
+	     i++) {
+		kfree(adapter->tx_pool[i].tx_buff);
+		free_long_term_buff(adapter,
+				    &adapter->tx_pool[i].long_term_buff);
+		kfree(adapter->tx_pool[i].free_map);
+	}
+	kfree(adapter->tx_pool);
+	adapter->tx_pool = NULL;
+
+	for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+	     i++) {
+		free_rx_pool(adapter, &adapter->rx_pool[i]);
+		free_long_term_buff(adapter,
+				    &adapter->rx_pool[i].long_term_buff);
+	}
+	kfree(adapter->rx_pool);
+	adapter->rx_pool = NULL;
+
+	adapter->closing = false;
+
+	return 0;
+}
+
+static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	int queue_num = skb_get_queue_mapping(skb);
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_tx_buff *tx_buff = NULL;
+	struct ibmvnic_tx_pool *tx_pool;
+	unsigned int tx_send_failed = 0;
+	unsigned int tx_map_failed = 0;
+	unsigned int tx_dropped = 0;
+	unsigned int tx_packets = 0;
+	unsigned int tx_bytes = 0;
+	dma_addr_t data_dma_addr;
+	struct netdev_queue *txq;
+	bool used_bounce = false;
+	unsigned long lpar_rc;
+	unsigned int skblen;
+	union sub_crq tx_crq;
+	unsigned int offset;
+	unsigned char *dst;
+	u64 *handle_array;
+	int index = 0;
+	int ret = 0;
+
+	tx_pool = &adapter->tx_pool[queue_num];
+	txq = netdev_get_tx_queue(netdev, skb_get_queue_mapping(skb));
+	handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
+				   be32_to_cpu(adapter->login_rsp_buf->
+					       off_txsubm_subcrqs));
+	if (adapter->migrated) {
+		tx_send_failed++;
+		tx_dropped++;
+		ret = NETDEV_TX_BUSY;
+		goto out;
+	}
+
+	index = tx_pool->free_map[tx_pool->consumer_index];
+	offset = index * adapter->req_mtu;
+	dst = tx_pool->long_term_buff.buff + offset;
+	memset(dst, 0, adapter->req_mtu);
+	skb_copy_from_linear_data(skb, dst, skb->len);
+	data_dma_addr = tx_pool->long_term_buff.addr + offset;
+
+	tx_pool->consumer_index =
+	    (tx_pool->consumer_index + 1) %
+		adapter->max_tx_entries_per_subcrq;
+
+	tx_buff = &tx_pool->tx_buff[index];
+
+	/* Sanity checks on our free map to make sure it points to an index
+	 * that is not being occupied by another skb. If skb memory is
+	 * not freed then we see congestion control kick in and halt tx.
+	 */
+	if (unlikely(tx_buff->skb)) {
+		dev_warn_ratelimited(dev, "TX free map points to untracked skb (tx_pool %d idx=%d)\n",
+				     queue_num, index);
+		dev_kfree_skb_any(tx_buff->skb);
+	}
+
+	tx_buff->skb = skb;
+	tx_buff->data_dma[0] = data_dma_addr;
+	tx_buff->data_len[0] = skb->len;
+	tx_buff->index = index;
+	tx_buff->pool_index = queue_num;
+	tx_buff->last_frag = true;
+	tx_buff->used_bounce = used_bounce;
+	skblen = skb->len;
+
+	memset(&tx_crq, 0, sizeof(tx_crq));
+	tx_crq.v1.first = IBMVNIC_CRQ_CMD;
+	tx_crq.v1.type = IBMVNIC_TX_DESC;
+	tx_crq.v1.n_crq_elem = 1;
+	tx_crq.v1.n_sge = 1;
+	tx_crq.v1.flags1 = IBMVNIC_TX_COMP_NEEDED;
+	tx_crq.v1.correlator = cpu_to_be32(index);
+	tx_crq.v1.dma_reg = cpu_to_be16(tx_pool->long_term_buff.map_id);
+	tx_crq.v1.sge_len = cpu_to_be32(skb->len);
+	tx_crq.v1.ioba = cpu_to_be64(data_dma_addr);
+
+	if (adapter->vlan_header_insertion) {
+		tx_crq.v1.flags2 |= IBMVNIC_TX_VLAN_INSERT;
+		tx_crq.v1.vlan_id = cpu_to_be16(skb->vlan_tci);
+	}
+
+	if (skb->protocol == htons(ETH_P_IP)) {
+		if (ip_hdr(skb)->version == 4)
+			tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_IPV4;
+		else if (ip_hdr(skb)->version == 6)
+			tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_IPV6;
+
+		if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+			tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_TCP;
+		else if (ip_hdr(skb)->protocol != IPPROTO_TCP)
+			tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_UDP;
+	}
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL)
+		tx_crq.v1.flags1 |= IBMVNIC_TX_CHKSUM_OFFLOAD;
+
+	lpar_rc = send_subcrq(adapter, handle_array[0], &tx_crq);
+
+	if (lpar_rc != H_SUCCESS) {
+		dev_err(dev, "tx failed with code %ld\n", lpar_rc);
+
+		if (tx_pool->consumer_index == 0)
+			tx_pool->consumer_index =
+				adapter->max_tx_entries_per_subcrq - 1;
+		else
+			tx_pool->consumer_index--;
+
+		tx_send_failed++;
+		tx_dropped++;
+		ret = NETDEV_TX_BUSY;
+		goto out;
+	}
+	tx_packets++;
+	tx_bytes += skblen;
+	txq->trans_start = jiffies;
+	ret = NETDEV_TX_OK;
+
+out:
+	netdev->stats.tx_dropped += tx_dropped;
+	netdev->stats.tx_bytes += tx_bytes;
+	netdev->stats.tx_packets += tx_packets;
+	adapter->tx_send_failed += tx_send_failed;
+	adapter->tx_map_failed += tx_map_failed;
+
+	return ret;
+}
+
+static void ibmvnic_set_multi(struct net_device *netdev)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	struct netdev_hw_addr *ha;
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.request_capability.first = IBMVNIC_CRQ_CMD;
+	crq.request_capability.cmd = REQUEST_CAPABILITY;
+
+	if (netdev->flags & IFF_PROMISC) {
+		if (!adapter->promisc_supported)
+			return;
+	} else {
+		if (netdev->flags & IFF_ALLMULTI) {
+			/* Accept all multicast */
+			memset(&crq, 0, sizeof(crq));
+			crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
+			crq.multicast_ctrl.cmd = MULTICAST_CTRL;
+			crq.multicast_ctrl.flags = IBMVNIC_ENABLE_ALL;
+			ibmvnic_send_crq(adapter, &crq);
+		} else if (netdev_mc_empty(netdev)) {
+			/* Reject all multicast */
+			memset(&crq, 0, sizeof(crq));
+			crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
+			crq.multicast_ctrl.cmd = MULTICAST_CTRL;
+			crq.multicast_ctrl.flags = IBMVNIC_DISABLE_ALL;
+			ibmvnic_send_crq(adapter, &crq);
+		} else {
+			/* Accept one or more multicast(s) */
+			netdev_for_each_mc_addr(ha, netdev) {
+				memset(&crq, 0, sizeof(crq));
+				crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
+				crq.multicast_ctrl.cmd = MULTICAST_CTRL;
+				crq.multicast_ctrl.flags = IBMVNIC_ENABLE_MC;
+				ether_addr_copy(&crq.multicast_ctrl.mac_addr[0],
+						ha->addr);
+				ibmvnic_send_crq(adapter, &crq);
+			}
+		}
+	}
+}
+
+static int ibmvnic_set_mac(struct net_device *netdev, void *p)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+	union ibmvnic_crq crq;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.change_mac_addr.first = IBMVNIC_CRQ_CMD;
+	crq.change_mac_addr.cmd = CHANGE_MAC_ADDR;
+	ether_addr_copy(&crq.change_mac_addr.mac_addr[0], addr->sa_data);
+	ibmvnic_send_crq(adapter, &crq);
+	/* netdev->dev_addr is changed in handle_change_mac_rsp function */
+	return 0;
+}
+
+static int ibmvnic_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+	if (new_mtu > adapter->req_mtu || new_mtu < adapter->min_mtu)
+		return -EINVAL;
+
+	netdev->mtu = new_mtu;
+	return 0;
+}
+
+static void ibmvnic_tx_timeout(struct net_device *dev)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(dev);
+	int rc;
+
+	/* Adapter timed out, resetting it */
+	release_sub_crqs(adapter);
+	rc = ibmvnic_reset_crq(adapter);
+	if (rc)
+		dev_err(&adapter->vdev->dev, "Adapter timeout, reset failed\n");
+	else
+		ibmvnic_send_crq_init(adapter);
+}
+
+static void remove_buff_from_pool(struct ibmvnic_adapter *adapter,
+				  struct ibmvnic_rx_buff *rx_buff)
+{
+	struct ibmvnic_rx_pool *pool = &adapter->rx_pool[rx_buff->pool_index];
+
+	rx_buff->skb = NULL;
+
+	pool->free_map[pool->next_alloc] = (int)(rx_buff - pool->rx_buff);
+	pool->next_alloc = (pool->next_alloc + 1) % pool->size;
+
+	atomic_dec(&pool->available);
+}
+
+static int ibmvnic_poll(struct napi_struct *napi, int budget)
+{
+	struct net_device *netdev = napi->dev;
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	int scrq_num = (int)(napi - adapter->napi);
+	int frames_processed = 0;
+restart_poll:
+	while (frames_processed < budget) {
+		struct sk_buff *skb;
+		struct ibmvnic_rx_buff *rx_buff;
+		union sub_crq *next;
+		u32 length;
+		u16 offset;
+		u8 flags = 0;
+
+		if (!pending_scrq(adapter, adapter->rx_scrq[scrq_num]))
+			break;
+		next = ibmvnic_next_scrq(adapter, adapter->rx_scrq[scrq_num]);
+		rx_buff =
+		    (struct ibmvnic_rx_buff *)be64_to_cpu(next->
+							  rx_comp.correlator);
+		/* do error checking */
+		if (next->rx_comp.rc) {
+			netdev_err(netdev, "rx error %x\n", next->rx_comp.rc);
+			/* free the entry */
+			next->rx_comp.first = 0;
+			remove_buff_from_pool(adapter, rx_buff);
+			break;
+		}
+
+		length = be32_to_cpu(next->rx_comp.len);
+		offset = be16_to_cpu(next->rx_comp.off_frame_data);
+		flags = next->rx_comp.flags;
+		skb = rx_buff->skb;
+		skb_copy_to_linear_data(skb, rx_buff->data + offset,
+					length);
+		skb->vlan_tci = be16_to_cpu(next->rx_comp.vlan_tci);
+		/* free the entry */
+		next->rx_comp.first = 0;
+		remove_buff_from_pool(adapter, rx_buff);
+
+		skb_put(skb, length);
+		skb->protocol = eth_type_trans(skb, netdev);
+
+		if (flags & IBMVNIC_IP_CHKSUM_GOOD &&
+		    flags & IBMVNIC_TCP_UDP_CHKSUM_GOOD) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		}
+
+		length = skb->len;
+		napi_gro_receive(napi, skb); /* send it up */
+		netdev->stats.rx_packets++;
+		netdev->stats.rx_bytes += length;
+		frames_processed++;
+	}
+	replenish_pools(adapter);
+
+	if (frames_processed < budget) {
+		enable_scrq_irq(adapter, adapter->rx_scrq[scrq_num]);
+		napi_complete(napi);
+		if (pending_scrq(adapter, adapter->rx_scrq[scrq_num]) &&
+		    napi_reschedule(napi)) {
+			disable_scrq_irq(adapter, adapter->rx_scrq[scrq_num]);
+			goto restart_poll;
+		}
+	}
+	return frames_processed;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ibmvnic_netpoll_controller(struct net_device *dev)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(dev);
+	int i;
+
+	replenish_pools(netdev_priv(dev));
+	for (i = 0; i < adapter->req_rx_queues; i++)
+		ibmvnic_interrupt_rx(adapter->rx_scrq[i]->irq,
+				     adapter->rx_scrq[i]);
+}
+#endif
+
+static const struct net_device_ops ibmvnic_netdev_ops = {
+	.ndo_open		= ibmvnic_open,
+	.ndo_stop		= ibmvnic_close,
+	.ndo_start_xmit		= ibmvnic_xmit,
+	.ndo_set_rx_mode	= ibmvnic_set_multi,
+	.ndo_set_mac_address	= ibmvnic_set_mac,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= ibmvnic_change_mtu,
+	.ndo_tx_timeout		= ibmvnic_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ibmvnic_netpoll_controller,
+#endif
+};
+
+/* ethtool functions */
+
+static int ibmvnic_get_settings(struct net_device *netdev,
+				struct ethtool_cmd *cmd)
+{
+	cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+			  SUPPORTED_FIBRE);
+	cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
+			    ADVERTISED_FIBRE);
+	ethtool_cmd_speed_set(cmd, SPEED_1000);
+	cmd->duplex = DUPLEX_FULL;
+	cmd->port = PORT_FIBRE;
+	cmd->phy_address = 0;
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->autoneg = AUTONEG_ENABLE;
+	cmd->maxtxpkt = 0;
+	cmd->maxrxpkt = 1;
+	return 0;
+}
+
+static void ibmvnic_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
+	strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
+}
+
+static u32 ibmvnic_get_msglevel(struct net_device *netdev)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+	return adapter->msg_enable;
+}
+
+static void ibmvnic_set_msglevel(struct net_device *netdev, u32 data)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+	adapter->msg_enable = data;
+}
+
+static u32 ibmvnic_get_link(struct net_device *netdev)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+	/* Don't need to send a query because we request a logical link up at
+	 * init and then we wait for link state indications
+	 */
+	return adapter->logical_link_state;
+}
+
+static void ibmvnic_get_ringparam(struct net_device *netdev,
+				  struct ethtool_ringparam *ring)
+{
+	ring->rx_max_pending = 0;
+	ring->tx_max_pending = 0;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = 0;
+	ring->tx_pending = 0;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	int i;
+
+	if (stringset != ETH_SS_STATS)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++, data += ETH_GSTRING_LEN)
+		memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN);
+}
+
+static int ibmvnic_get_sset_count(struct net_device *dev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(ibmvnic_stats);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void ibmvnic_get_ethtool_stats(struct net_device *dev,
+				      struct ethtool_stats *stats, u64 *data)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(dev);
+	union ibmvnic_crq crq;
+	int i;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.request_statistics.first = IBMVNIC_CRQ_CMD;
+	crq.request_statistics.cmd = REQUEST_STATISTICS;
+	crq.request_statistics.ioba = cpu_to_be32(adapter->stats_token);
+	crq.request_statistics.len =
+	    cpu_to_be32(sizeof(struct ibmvnic_statistics));
+	ibmvnic_send_crq(adapter, &crq);
+
+	/* Wait for data to be written */
+	init_completion(&adapter->stats_done);
+	wait_for_completion(&adapter->stats_done);
+
+	for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++)
+		data[i] = IBMVNIC_GET_STAT(adapter, ibmvnic_stats[i].offset);
+}
+
+static const struct ethtool_ops ibmvnic_ethtool_ops = {
+	.get_settings		= ibmvnic_get_settings,
+	.get_drvinfo		= ibmvnic_get_drvinfo,
+	.get_msglevel		= ibmvnic_get_msglevel,
+	.set_msglevel		= ibmvnic_set_msglevel,
+	.get_link		= ibmvnic_get_link,
+	.get_ringparam		= ibmvnic_get_ringparam,
+	.get_strings            = ibmvnic_get_strings,
+	.get_sset_count         = ibmvnic_get_sset_count,
+	.get_ethtool_stats	= ibmvnic_get_ethtool_stats,
+};
+
+/* Routines for managing CRQs/sCRQs  */
+
+static void release_sub_crq_queue(struct ibmvnic_adapter *adapter,
+				  struct ibmvnic_sub_crq_queue *scrq)
+{
+	struct device *dev = &adapter->vdev->dev;
+	long rc;
+
+	netdev_dbg(adapter->netdev, "Releasing sub-CRQ\n");
+
+	/* Close the sub-crqs */
+	do {
+		rc = plpar_hcall_norets(H_FREE_SUB_CRQ,
+					adapter->vdev->unit_address,
+					scrq->crq_num);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE,
+			 DMA_BIDIRECTIONAL);
+	free_pages((unsigned long)scrq->msgs, 2);
+	kfree(scrq);
+}
+
+static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter
+							*adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_sub_crq_queue *scrq;
+	int rc;
+
+	scrq = kmalloc(sizeof(*scrq), GFP_ATOMIC);
+	if (!scrq)
+		return NULL;
+
+	scrq->msgs = (union sub_crq *)__get_free_pages(GFP_KERNEL, 2);
+	memset(scrq->msgs, 0, 4 * PAGE_SIZE);
+	if (!scrq->msgs) {
+		dev_warn(dev, "Couldn't allocate crq queue messages page\n");
+		goto zero_page_failed;
+	}
+
+	scrq->msg_token = dma_map_single(dev, scrq->msgs, 4 * PAGE_SIZE,
+					 DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, scrq->msg_token)) {
+		dev_warn(dev, "Couldn't map crq queue messages page\n");
+		goto map_failed;
+	}
+
+	rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token,
+			   4 * PAGE_SIZE, &scrq->crq_num, &scrq->hw_irq);
+
+	if (rc == H_RESOURCE)
+		rc = ibmvnic_reset_crq(adapter);
+
+	if (rc == H_CLOSED) {
+		dev_warn(dev, "Partner adapter not ready, waiting.\n");
+	} else if (rc) {
+		dev_warn(dev, "Error %d registering sub-crq\n", rc);
+		goto reg_failed;
+	}
+
+	scrq->irq = irq_create_mapping(NULL, scrq->hw_irq);
+	if (scrq->irq == NO_IRQ) {
+		dev_err(dev, "Error mapping irq\n");
+		goto map_irq_failed;
+	}
+
+	scrq->adapter = adapter;
+	scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs);
+	scrq->cur = 0;
+	scrq->rx_skb_top = NULL;
+	spin_lock_init(&scrq->lock);
+
+	netdev_dbg(adapter->netdev,
+		   "sub-crq initialized, num %lx, hw_irq=%lx, irq=%x\n",
+		   scrq->crq_num, scrq->hw_irq, scrq->irq);
+
+	return scrq;
+
+map_irq_failed:
+	do {
+		rc = plpar_hcall_norets(H_FREE_SUB_CRQ,
+					adapter->vdev->unit_address,
+					scrq->crq_num);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+reg_failed:
+	dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE,
+			 DMA_BIDIRECTIONAL);
+map_failed:
+	free_pages((unsigned long)scrq->msgs, 2);
+zero_page_failed:
+	kfree(scrq);
+
+	return NULL;
+}
+
+static void release_sub_crqs(struct ibmvnic_adapter *adapter)
+{
+	int i;
+
+	if (adapter->tx_scrq) {
+		for (i = 0; i < adapter->req_tx_queues; i++)
+			if (adapter->tx_scrq[i]) {
+				free_irq(adapter->tx_scrq[i]->irq,
+					 adapter->tx_scrq[i]);
+				release_sub_crq_queue(adapter,
+						      adapter->tx_scrq[i]);
+			}
+		adapter->tx_scrq = NULL;
+	}
+
+	if (adapter->rx_scrq) {
+		for (i = 0; i < adapter->req_rx_queues; i++)
+			if (adapter->rx_scrq[i]) {
+				free_irq(adapter->rx_scrq[i]->irq,
+					 adapter->rx_scrq[i]);
+				release_sub_crq_queue(adapter,
+						      adapter->rx_scrq[i]);
+			}
+		adapter->rx_scrq = NULL;
+	}
+
+	adapter->requested_caps = 0;
+}
+
+static int disable_scrq_irq(struct ibmvnic_adapter *adapter,
+			    struct ibmvnic_sub_crq_queue *scrq)
+{
+	struct device *dev = &adapter->vdev->dev;
+	unsigned long rc;
+
+	rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address,
+				H_DISABLE_VIO_INTERRUPT, scrq->hw_irq, 0, 0);
+	if (rc)
+		dev_err(dev, "Couldn't disable scrq irq 0x%lx. rc=%ld\n",
+			scrq->hw_irq, rc);
+	return rc;
+}
+
+static int enable_scrq_irq(struct ibmvnic_adapter *adapter,
+			   struct ibmvnic_sub_crq_queue *scrq)
+{
+	struct device *dev = &adapter->vdev->dev;
+	unsigned long rc;
+
+	if (scrq->hw_irq > 0x100000000ULL) {
+		dev_err(dev, "bad hw_irq = %lx\n", scrq->hw_irq);
+		return 1;
+	}
+
+	rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address,
+				H_ENABLE_VIO_INTERRUPT, scrq->hw_irq, 0, 0);
+	if (rc)
+		dev_err(dev, "Couldn't enable scrq irq 0x%lx. rc=%ld\n",
+			scrq->hw_irq, rc);
+	return rc;
+}
+
+static int ibmvnic_complete_tx(struct ibmvnic_adapter *adapter,
+			       struct ibmvnic_sub_crq_queue *scrq)
+{
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_tx_buff *txbuff;
+	union sub_crq *next;
+	int index;
+	int i, j;
+
+restart_loop:
+	while (pending_scrq(adapter, scrq)) {
+		unsigned int pool = scrq->pool_index;
+
+		next = ibmvnic_next_scrq(adapter, scrq);
+		for (i = 0; i < next->tx_comp.num_comps; i++) {
+			if (next->tx_comp.rcs[i]) {
+				dev_err(dev, "tx error %x\n",
+					next->tx_comp.rcs[i]);
+				continue;
+			}
+			index = be32_to_cpu(next->tx_comp.correlators[i]);
+			txbuff = &adapter->tx_pool[pool].tx_buff[index];
+
+			for (j = 0; j < IBMVNIC_MAX_FRAGS_PER_CRQ; j++) {
+				if (!txbuff->data_dma[j])
+					continue;
+
+				txbuff->data_dma[j] = 0;
+				txbuff->used_bounce = false;
+			}
+
+			if (txbuff->last_frag)
+				dev_kfree_skb_any(txbuff->skb);
+
+			adapter->tx_pool[pool].free_map[adapter->tx_pool[pool].
+						     producer_index] = index;
+			adapter->tx_pool[pool].producer_index =
+			    (adapter->tx_pool[pool].producer_index + 1) %
+			    adapter->max_tx_entries_per_subcrq;
+		}
+		/* remove tx_comp scrq*/
+		next->tx_comp.first = 0;
+	}
+
+	enable_scrq_irq(adapter, scrq);
+
+	if (pending_scrq(adapter, scrq)) {
+		disable_scrq_irq(adapter, scrq);
+		goto restart_loop;
+	}
+
+	return 0;
+}
+
+static irqreturn_t ibmvnic_interrupt_tx(int irq, void *instance)
+{
+	struct ibmvnic_sub_crq_queue *scrq = instance;
+	struct ibmvnic_adapter *adapter = scrq->adapter;
+
+	disable_scrq_irq(adapter, scrq);
+	ibmvnic_complete_tx(adapter, scrq);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance)
+{
+	struct ibmvnic_sub_crq_queue *scrq = instance;
+	struct ibmvnic_adapter *adapter = scrq->adapter;
+
+	if (napi_schedule_prep(&adapter->napi[scrq->scrq_num])) {
+		disable_scrq_irq(adapter, scrq);
+		__napi_schedule(&adapter->napi[scrq->scrq_num]);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
+{
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_sub_crq_queue **allqueues;
+	int registered_queues = 0;
+	union ibmvnic_crq crq;
+	int total_queues;
+	int more = 0;
+	int i, j;
+	int rc;
+
+	if (!retry) {
+		/* Sub-CRQ entries are 32 byte long */
+		int entries_page = 4 * PAGE_SIZE / (sizeof(u64) * 4);
+
+		if (adapter->min_tx_entries_per_subcrq > entries_page ||
+		    adapter->min_rx_add_entries_per_subcrq > entries_page) {
+			dev_err(dev, "Fatal, invalid entries per sub-crq\n");
+			goto allqueues_failed;
+		}
+
+		/* Get the minimum between the queried max and the entries
+		 * that fit in our PAGE_SIZE
+		 */
+		adapter->req_tx_entries_per_subcrq =
+		    adapter->max_tx_entries_per_subcrq > entries_page ?
+		    entries_page : adapter->max_tx_entries_per_subcrq;
+		adapter->req_rx_add_entries_per_subcrq =
+		    adapter->max_rx_add_entries_per_subcrq > entries_page ?
+		    entries_page : adapter->max_rx_add_entries_per_subcrq;
+
+		/* Choosing the maximum number of queues supported by firmware*/
+		adapter->req_tx_queues = adapter->min_tx_queues;
+		adapter->req_rx_queues = adapter->min_rx_queues;
+		adapter->req_rx_add_queues = adapter->min_rx_add_queues;
+
+		adapter->req_mtu = adapter->max_mtu;
+	}
+
+	total_queues = adapter->req_tx_queues + adapter->req_rx_queues;
+
+	allqueues = kcalloc(total_queues, sizeof(*allqueues), GFP_ATOMIC);
+	if (!allqueues)
+		goto allqueues_failed;
+
+	for (i = 0; i < total_queues; i++) {
+		allqueues[i] = init_sub_crq_queue(adapter);
+		if (!allqueues[i]) {
+			dev_warn(dev, "Couldn't allocate all sub-crqs\n");
+			break;
+		}
+		registered_queues++;
+	}
+
+	/* Make sure we were able to register the minimum number of queues */
+	if (registered_queues <
+	    adapter->min_tx_queues + adapter->min_rx_queues) {
+		dev_err(dev, "Fatal: Couldn't init  min number of sub-crqs\n");
+		goto tx_failed;
+	}
+
+	/* Distribute the failed allocated queues*/
+	for (i = 0; i < total_queues - registered_queues + more ; i++) {
+		netdev_dbg(adapter->netdev, "Reducing number of queues\n");
+		switch (i % 3) {
+		case 0:
+			if (adapter->req_rx_queues > adapter->min_rx_queues)
+				adapter->req_rx_queues--;
+			else
+				more++;
+			break;
+		case 1:
+			if (adapter->req_tx_queues > adapter->min_tx_queues)
+				adapter->req_tx_queues--;
+			else
+				more++;
+			break;
+		}
+	}
+
+	adapter->tx_scrq = kcalloc(adapter->req_tx_queues,
+				   sizeof(*adapter->tx_scrq), GFP_ATOMIC);
+	if (!adapter->tx_scrq)
+		goto tx_failed;
+
+	for (i = 0; i < adapter->req_tx_queues; i++) {
+		adapter->tx_scrq[i] = allqueues[i];
+		adapter->tx_scrq[i]->pool_index = i;
+		rc = request_irq(adapter->tx_scrq[i]->irq, ibmvnic_interrupt_tx,
+				 0, "ibmvnic_tx", adapter->tx_scrq[i]);
+		if (rc) {
+			dev_err(dev, "Couldn't register tx irq 0x%x. rc=%d\n",
+				adapter->tx_scrq[i]->irq, rc);
+			goto req_tx_irq_failed;
+		}
+	}
+
+	adapter->rx_scrq = kcalloc(adapter->req_rx_queues,
+				   sizeof(*adapter->rx_scrq), GFP_ATOMIC);
+	if (!adapter->rx_scrq)
+		goto rx_failed;
+
+	for (i = 0; i < adapter->req_rx_queues; i++) {
+		adapter->rx_scrq[i] = allqueues[i + adapter->req_tx_queues];
+		adapter->rx_scrq[i]->scrq_num = i;
+		rc = request_irq(adapter->rx_scrq[i]->irq, ibmvnic_interrupt_rx,
+				 0, "ibmvnic_rx", adapter->rx_scrq[i]);
+		if (rc) {
+			dev_err(dev, "Couldn't register rx irq 0x%x. rc=%d\n",
+				adapter->rx_scrq[i]->irq, rc);
+			goto req_rx_irq_failed;
+		}
+	}
+
+	memset(&crq, 0, sizeof(crq));
+	crq.request_capability.first = IBMVNIC_CRQ_CMD;
+	crq.request_capability.cmd = REQUEST_CAPABILITY;
+
+	crq.request_capability.capability = cpu_to_be16(REQ_TX_QUEUES);
+	crq.request_capability.number = cpu_to_be32(adapter->req_tx_queues);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES);
+	crq.request_capability.number = cpu_to_be32(adapter->req_rx_queues);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES);
+	crq.request_capability.number = cpu_to_be32(adapter->req_rx_add_queues);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.request_capability.capability =
+	    cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);
+	crq.request_capability.number =
+	    cpu_to_be32(adapter->req_tx_entries_per_subcrq);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.request_capability.capability =
+	    cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);
+	crq.request_capability.number =
+	    cpu_to_be32(adapter->req_rx_add_entries_per_subcrq);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.request_capability.capability = cpu_to_be16(REQ_MTU);
+	crq.request_capability.number = cpu_to_be32(adapter->req_mtu);
+	ibmvnic_send_crq(adapter, &crq);
+
+	if (adapter->netdev->flags & IFF_PROMISC) {
+		if (adapter->promisc_supported) {
+			crq.request_capability.capability =
+			    cpu_to_be16(PROMISC_REQUESTED);
+			crq.request_capability.number = cpu_to_be32(1);
+			ibmvnic_send_crq(adapter, &crq);
+		}
+	} else {
+		crq.request_capability.capability =
+		    cpu_to_be16(PROMISC_REQUESTED);
+		crq.request_capability.number = cpu_to_be32(0);
+		ibmvnic_send_crq(adapter, &crq);
+	}
+
+	kfree(allqueues);
+
+	return;
+
+req_rx_irq_failed:
+	for (j = 0; j < i; j++)
+		free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]);
+	i = adapter->req_tx_queues;
+req_tx_irq_failed:
+	for (j = 0; j < i; j++)
+		free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]);
+	kfree(adapter->rx_scrq);
+	adapter->rx_scrq = NULL;
+rx_failed:
+	kfree(adapter->tx_scrq);
+	adapter->tx_scrq = NULL;
+tx_failed:
+	for (i = 0; i < registered_queues; i++)
+		release_sub_crq_queue(adapter, allqueues[i]);
+	kfree(allqueues);
+allqueues_failed:
+	ibmvnic_remove(adapter->vdev);
+}
+
+static int pending_scrq(struct ibmvnic_adapter *adapter,
+			struct ibmvnic_sub_crq_queue *scrq)
+{
+	union sub_crq *entry = &scrq->msgs[scrq->cur];
+
+	if (entry->generic.first & IBMVNIC_CRQ_CMD_RSP || adapter->closing)
+		return 1;
+	else
+		return 0;
+}
+
+static union sub_crq *ibmvnic_next_scrq(struct ibmvnic_adapter *adapter,
+					struct ibmvnic_sub_crq_queue *scrq)
+{
+	union sub_crq *entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scrq->lock, flags);
+	entry = &scrq->msgs[scrq->cur];
+	if (entry->generic.first & IBMVNIC_CRQ_CMD_RSP) {
+		if (++scrq->cur == scrq->size)
+			scrq->cur = 0;
+	} else {
+		entry = NULL;
+	}
+	spin_unlock_irqrestore(&scrq->lock, flags);
+
+	return entry;
+}
+
+static union ibmvnic_crq *ibmvnic_next_crq(struct ibmvnic_adapter *adapter)
+{
+	struct ibmvnic_crq_queue *queue = &adapter->crq;
+	union ibmvnic_crq *crq;
+
+	crq = &queue->msgs[queue->cur];
+	if (crq->generic.first & IBMVNIC_CRQ_CMD_RSP) {
+		if (++queue->cur == queue->size)
+			queue->cur = 0;
+	} else {
+		crq = NULL;
+	}
+
+	return crq;
+}
+
+static int send_subcrq(struct ibmvnic_adapter *adapter, u64 remote_handle,
+		       union sub_crq *sub_crq)
+{
+	unsigned int ua = adapter->vdev->unit_address;
+	struct device *dev = &adapter->vdev->dev;
+	u64 *u64_crq = (u64 *)sub_crq;
+	int rc;
+
+	netdev_dbg(adapter->netdev,
+		   "Sending sCRQ %016lx: %016lx %016lx %016lx %016lx\n",
+		   (unsigned long int)cpu_to_be64(remote_handle),
+		   (unsigned long int)cpu_to_be64(u64_crq[0]),
+		   (unsigned long int)cpu_to_be64(u64_crq[1]),
+		   (unsigned long int)cpu_to_be64(u64_crq[2]),
+		   (unsigned long int)cpu_to_be64(u64_crq[3]));
+
+	/* Make sure the hypervisor sees the complete request */
+	mb();
+
+	rc = plpar_hcall_norets(H_SEND_SUB_CRQ, ua,
+				cpu_to_be64(remote_handle),
+				cpu_to_be64(u64_crq[0]),
+				cpu_to_be64(u64_crq[1]),
+				cpu_to_be64(u64_crq[2]),
+				cpu_to_be64(u64_crq[3]));
+
+	if (rc) {
+		if (rc == H_CLOSED)
+			dev_warn(dev, "CRQ Queue closed\n");
+		dev_err(dev, "Send error (rc=%d)\n", rc);
+	}
+
+	return rc;
+}
+
+static int ibmvnic_send_crq(struct ibmvnic_adapter *adapter,
+			    union ibmvnic_crq *crq)
+{
+	unsigned int ua = adapter->vdev->unit_address;
+	struct device *dev = &adapter->vdev->dev;
+	u64 *u64_crq = (u64 *)crq;
+	int rc;
+
+	netdev_dbg(adapter->netdev, "Sending CRQ: %016lx %016lx\n",
+		   (unsigned long int)cpu_to_be64(u64_crq[0]),
+		   (unsigned long int)cpu_to_be64(u64_crq[1]));
+
+	/* Make sure the hypervisor sees the complete request */
+	mb();
+
+	rc = plpar_hcall_norets(H_SEND_CRQ, ua,
+				cpu_to_be64(u64_crq[0]),
+				cpu_to_be64(u64_crq[1]));
+
+	if (rc) {
+		if (rc == H_CLOSED)
+			dev_warn(dev, "CRQ Queue closed\n");
+		dev_warn(dev, "Send error (rc=%d)\n", rc);
+	}
+
+	return rc;
+}
+
+static int ibmvnic_send_crq_init(struct ibmvnic_adapter *adapter)
+{
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.generic.first = IBMVNIC_CRQ_INIT_CMD;
+	crq.generic.cmd = IBMVNIC_CRQ_INIT;
+	netdev_dbg(adapter->netdev, "Sending CRQ init\n");
+
+	return ibmvnic_send_crq(adapter, &crq);
+}
+
+static int ibmvnic_send_crq_init_complete(struct ibmvnic_adapter *adapter)
+{
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.generic.first = IBMVNIC_CRQ_INIT_CMD;
+	crq.generic.cmd = IBMVNIC_CRQ_INIT_COMPLETE;
+	netdev_dbg(adapter->netdev, "Sending CRQ init complete\n");
+
+	return ibmvnic_send_crq(adapter, &crq);
+}
+
+static int send_version_xchg(struct ibmvnic_adapter *adapter)
+{
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.version_exchange.first = IBMVNIC_CRQ_CMD;
+	crq.version_exchange.cmd = VERSION_EXCHANGE;
+	crq.version_exchange.version = cpu_to_be16(ibmvnic_version);
+
+	return ibmvnic_send_crq(adapter, &crq);
+}
+
+static void send_login(struct ibmvnic_adapter *adapter)
+{
+	struct ibmvnic_login_rsp_buffer *login_rsp_buffer;
+	struct ibmvnic_login_buffer *login_buffer;
+	struct ibmvnic_inflight_cmd *inflight_cmd;
+	struct device *dev = &adapter->vdev->dev;
+	dma_addr_t rsp_buffer_token;
+	dma_addr_t buffer_token;
+	size_t rsp_buffer_size;
+	union ibmvnic_crq crq;
+	unsigned long flags;
+	size_t buffer_size;
+	__be64 *tx_list_p;
+	__be64 *rx_list_p;
+	int i;
+
+	buffer_size =
+	    sizeof(struct ibmvnic_login_buffer) +
+	    sizeof(u64) * (adapter->req_tx_queues + adapter->req_rx_queues);
+
+	login_buffer = kmalloc(buffer_size, GFP_ATOMIC);
+	if (!login_buffer)
+		goto buf_alloc_failed;
+
+	buffer_token = dma_map_single(dev, login_buffer, buffer_size,
+				      DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, buffer_token)) {
+		dev_err(dev, "Couldn't map login buffer\n");
+		goto buf_map_failed;
+	}
+
+	rsp_buffer_size =
+	    sizeof(struct ibmvnic_login_rsp_buffer) +
+	    sizeof(u64) * (adapter->req_tx_queues +
+			   adapter->req_rx_queues *
+			   adapter->req_rx_add_queues + adapter->
+			   req_rx_add_queues) +
+	    sizeof(u8) * (IBMVNIC_TX_DESC_VERSIONS);
+
+	login_rsp_buffer = kmalloc(rsp_buffer_size, GFP_ATOMIC);
+	if (!login_rsp_buffer)
+		goto buf_rsp_alloc_failed;
+
+	rsp_buffer_token = dma_map_single(dev, login_rsp_buffer,
+					  rsp_buffer_size, DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, rsp_buffer_token)) {
+		dev_err(dev, "Couldn't map login rsp buffer\n");
+		goto buf_rsp_map_failed;
+	}
+	inflight_cmd = kmalloc(sizeof(*inflight_cmd), GFP_ATOMIC);
+	if (!inflight_cmd) {
+		dev_err(dev, "Couldn't allocate inflight_cmd\n");
+		goto inflight_alloc_failed;
+	}
+	adapter->login_buf = login_buffer;
+	adapter->login_buf_token = buffer_token;
+	adapter->login_buf_sz = buffer_size;
+	adapter->login_rsp_buf = login_rsp_buffer;
+	adapter->login_rsp_buf_token = rsp_buffer_token;
+	adapter->login_rsp_buf_sz = rsp_buffer_size;
+
+	login_buffer->len = cpu_to_be32(buffer_size);
+	login_buffer->version = cpu_to_be32(INITIAL_VERSION_LB);
+	login_buffer->num_txcomp_subcrqs = cpu_to_be32(adapter->req_tx_queues);
+	login_buffer->off_txcomp_subcrqs =
+	    cpu_to_be32(sizeof(struct ibmvnic_login_buffer));
+	login_buffer->num_rxcomp_subcrqs = cpu_to_be32(adapter->req_rx_queues);
+	login_buffer->off_rxcomp_subcrqs =
+	    cpu_to_be32(sizeof(struct ibmvnic_login_buffer) +
+			sizeof(u64) * adapter->req_tx_queues);
+	login_buffer->login_rsp_ioba = cpu_to_be32(rsp_buffer_token);
+	login_buffer->login_rsp_len = cpu_to_be32(rsp_buffer_size);
+
+	tx_list_p = (__be64 *)((char *)login_buffer +
+				      sizeof(struct ibmvnic_login_buffer));
+	rx_list_p = (__be64 *)((char *)login_buffer +
+				      sizeof(struct ibmvnic_login_buffer) +
+				      sizeof(u64) * adapter->req_tx_queues);
+
+	for (i = 0; i < adapter->req_tx_queues; i++) {
+		if (adapter->tx_scrq[i]) {
+			tx_list_p[i] = cpu_to_be64(adapter->tx_scrq[i]->
+						   crq_num);
+		}
+	}
+
+	for (i = 0; i < adapter->req_rx_queues; i++) {
+		if (adapter->rx_scrq[i]) {
+			rx_list_p[i] = cpu_to_be64(adapter->rx_scrq[i]->
+						   crq_num);
+		}
+	}
+
+	netdev_dbg(adapter->netdev, "Login Buffer:\n");
+	for (i = 0; i < (adapter->login_buf_sz - 1) / 8 + 1; i++) {
+		netdev_dbg(adapter->netdev, "%016lx\n",
+			   ((unsigned long int *)(adapter->login_buf))[i]);
+	}
+
+	memset(&crq, 0, sizeof(crq));
+	crq.login.first = IBMVNIC_CRQ_CMD;
+	crq.login.cmd = LOGIN;
+	crq.login.ioba = cpu_to_be32(buffer_token);
+	crq.login.len = cpu_to_be32(buffer_size);
+
+	memcpy(&inflight_cmd->crq, &crq, sizeof(crq));
+
+	spin_lock_irqsave(&adapter->inflight_lock, flags);
+	list_add_tail(&inflight_cmd->list, &adapter->inflight);
+	spin_unlock_irqrestore(&adapter->inflight_lock, flags);
+
+	ibmvnic_send_crq(adapter, &crq);
+
+	return;
+
+inflight_alloc_failed:
+	dma_unmap_single(dev, rsp_buffer_token, rsp_buffer_size,
+			 DMA_FROM_DEVICE);
+buf_rsp_map_failed:
+	kfree(login_rsp_buffer);
+buf_rsp_alloc_failed:
+	dma_unmap_single(dev, buffer_token, buffer_size, DMA_TO_DEVICE);
+buf_map_failed:
+	kfree(login_buffer);
+buf_alloc_failed:
+	return;
+}
+
+static void send_request_map(struct ibmvnic_adapter *adapter, dma_addr_t addr,
+			     u32 len, u8 map_id)
+{
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.request_map.first = IBMVNIC_CRQ_CMD;
+	crq.request_map.cmd = REQUEST_MAP;
+	crq.request_map.map_id = map_id;
+	crq.request_map.ioba = cpu_to_be32(addr);
+	crq.request_map.len = cpu_to_be32(len);
+	ibmvnic_send_crq(adapter, &crq);
+}
+
+static void send_request_unmap(struct ibmvnic_adapter *adapter, u8 map_id)
+{
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.request_unmap.first = IBMVNIC_CRQ_CMD;
+	crq.request_unmap.cmd = REQUEST_UNMAP;
+	crq.request_unmap.map_id = map_id;
+	ibmvnic_send_crq(adapter, &crq);
+}
+
+static void send_map_query(struct ibmvnic_adapter *adapter)
+{
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.query_map.first = IBMVNIC_CRQ_CMD;
+	crq.query_map.cmd = QUERY_MAP;
+	ibmvnic_send_crq(adapter, &crq);
+}
+
+/* Send a series of CRQs requesting various capabilities of the VNIC server */
+static void send_cap_queries(struct ibmvnic_adapter *adapter)
+{
+	union ibmvnic_crq crq;
+
+	atomic_set(&adapter->running_cap_queries, 0);
+	memset(&crq, 0, sizeof(crq));
+	crq.query_capability.first = IBMVNIC_CRQ_CMD;
+	crq.query_capability.cmd = QUERY_CAPABILITY;
+
+	crq.query_capability.capability = cpu_to_be16(MIN_TX_QUEUES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MIN_RX_QUEUES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MIN_RX_ADD_QUEUES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MAX_TX_QUEUES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MAX_RX_QUEUES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MAX_RX_ADD_QUEUES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability =
+	    cpu_to_be16(MIN_TX_ENTRIES_PER_SUBCRQ);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability =
+	    cpu_to_be16(MIN_RX_ADD_ENTRIES_PER_SUBCRQ);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability =
+	    cpu_to_be16(MAX_TX_ENTRIES_PER_SUBCRQ);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability =
+	    cpu_to_be16(MAX_RX_ADD_ENTRIES_PER_SUBCRQ);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(TCP_IP_OFFLOAD);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(PROMISC_SUPPORTED);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MIN_MTU);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MAX_MTU);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MAX_MULTICAST_FILTERS);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(VLAN_HEADER_INSERTION);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(MAX_TX_SG_ENTRIES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(RX_SG_SUPPORTED);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(OPT_TX_COMP_SUB_QUEUES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(OPT_RX_COMP_QUEUES);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability =
+			cpu_to_be16(OPT_RX_BUFADD_Q_PER_RX_COMP_Q);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability =
+			cpu_to_be16(OPT_TX_ENTRIES_PER_SUBCRQ);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability =
+			cpu_to_be16(OPT_RXBA_ENTRIES_PER_SUBCRQ);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+
+	crq.query_capability.capability = cpu_to_be16(TX_RX_DESC_REQ);
+	atomic_inc(&adapter->running_cap_queries);
+	ibmvnic_send_crq(adapter, &crq);
+}
+
+static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_query_ip_offload_buffer *buf = &adapter->ip_offload_buf;
+	union ibmvnic_crq crq;
+	int i;
+
+	dma_unmap_single(dev, adapter->ip_offload_tok,
+			 sizeof(adapter->ip_offload_buf), DMA_FROM_DEVICE);
+
+	netdev_dbg(adapter->netdev, "Query IP Offload Buffer:\n");
+	for (i = 0; i < (sizeof(adapter->ip_offload_buf) - 1) / 8 + 1; i++)
+		netdev_dbg(adapter->netdev, "%016lx\n",
+			   ((unsigned long int *)(buf))[i]);
+
+	netdev_dbg(adapter->netdev, "ipv4_chksum = %d\n", buf->ipv4_chksum);
+	netdev_dbg(adapter->netdev, "ipv6_chksum = %d\n", buf->ipv6_chksum);
+	netdev_dbg(adapter->netdev, "tcp_ipv4_chksum = %d\n",
+		   buf->tcp_ipv4_chksum);
+	netdev_dbg(adapter->netdev, "tcp_ipv6_chksum = %d\n",
+		   buf->tcp_ipv6_chksum);
+	netdev_dbg(adapter->netdev, "udp_ipv4_chksum = %d\n",
+		   buf->udp_ipv4_chksum);
+	netdev_dbg(adapter->netdev, "udp_ipv6_chksum = %d\n",
+		   buf->udp_ipv6_chksum);
+	netdev_dbg(adapter->netdev, "large_tx_ipv4 = %d\n",
+		   buf->large_tx_ipv4);
+	netdev_dbg(adapter->netdev, "large_tx_ipv6 = %d\n",
+		   buf->large_tx_ipv6);
+	netdev_dbg(adapter->netdev, "large_rx_ipv4 = %d\n",
+		   buf->large_rx_ipv4);
+	netdev_dbg(adapter->netdev, "large_rx_ipv6 = %d\n",
+		   buf->large_rx_ipv6);
+	netdev_dbg(adapter->netdev, "max_ipv4_hdr_sz = %d\n",
+		   buf->max_ipv4_header_size);
+	netdev_dbg(adapter->netdev, "max_ipv6_hdr_sz = %d\n",
+		   buf->max_ipv6_header_size);
+	netdev_dbg(adapter->netdev, "max_tcp_hdr_size = %d\n",
+		   buf->max_tcp_header_size);
+	netdev_dbg(adapter->netdev, "max_udp_hdr_size = %d\n",
+		   buf->max_udp_header_size);
+	netdev_dbg(adapter->netdev, "max_large_tx_size = %d\n",
+		   buf->max_large_tx_size);
+	netdev_dbg(adapter->netdev, "max_large_rx_size = %d\n",
+		   buf->max_large_rx_size);
+	netdev_dbg(adapter->netdev, "ipv6_ext_hdr = %d\n",
+		   buf->ipv6_extension_header);
+	netdev_dbg(adapter->netdev, "tcp_pseudosum_req = %d\n",
+		   buf->tcp_pseudosum_req);
+	netdev_dbg(adapter->netdev, "num_ipv6_ext_hd = %d\n",
+		   buf->num_ipv6_ext_headers);
+	netdev_dbg(adapter->netdev, "off_ipv6_ext_hd = %d\n",
+		   buf->off_ipv6_ext_headers);
+
+	adapter->ip_offload_ctrl_tok =
+	    dma_map_single(dev, &adapter->ip_offload_ctrl,
+			   sizeof(adapter->ip_offload_ctrl), DMA_TO_DEVICE);
+
+	if (dma_mapping_error(dev, adapter->ip_offload_ctrl_tok)) {
+		dev_err(dev, "Couldn't map ip offload control buffer\n");
+		return;
+	}
+
+	adapter->ip_offload_ctrl.version = cpu_to_be32(INITIAL_VERSION_IOB);
+	adapter->ip_offload_ctrl.tcp_ipv4_chksum = buf->tcp_ipv4_chksum;
+	adapter->ip_offload_ctrl.udp_ipv4_chksum = buf->udp_ipv4_chksum;
+	adapter->ip_offload_ctrl.tcp_ipv6_chksum = buf->tcp_ipv6_chksum;
+	adapter->ip_offload_ctrl.udp_ipv6_chksum = buf->udp_ipv6_chksum;
+
+	/* large_tx/rx disabled for now, additional features needed */
+	adapter->ip_offload_ctrl.large_tx_ipv4 = 0;
+	adapter->ip_offload_ctrl.large_tx_ipv6 = 0;
+	adapter->ip_offload_ctrl.large_rx_ipv4 = 0;
+	adapter->ip_offload_ctrl.large_rx_ipv6 = 0;
+
+	adapter->netdev->features = NETIF_F_GSO;
+
+	if (buf->tcp_ipv4_chksum || buf->udp_ipv4_chksum)
+		adapter->netdev->features |= NETIF_F_IP_CSUM;
+
+	if (buf->tcp_ipv6_chksum || buf->udp_ipv6_chksum)
+		adapter->netdev->features |= NETIF_F_IPV6_CSUM;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.control_ip_offload.first = IBMVNIC_CRQ_CMD;
+	crq.control_ip_offload.cmd = CONTROL_IP_OFFLOAD;
+	crq.control_ip_offload.len =
+	    cpu_to_be32(sizeof(adapter->ip_offload_ctrl));
+	crq.control_ip_offload.ioba = cpu_to_be32(adapter->ip_offload_ctrl_tok);
+	ibmvnic_send_crq(adapter, &crq);
+}
+
+static void handle_error_info_rsp(union ibmvnic_crq *crq,
+				  struct ibmvnic_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_error_buff *error_buff, *tmp;
+	unsigned long flags;
+	bool found = false;
+	int i;
+
+	if (!crq->request_error_rsp.rc.code) {
+		dev_info(dev, "Request Error Rsp returned with rc=%x\n",
+			 crq->request_error_rsp.rc.code);
+		return;
+	}
+
+	spin_lock_irqsave(&adapter->error_list_lock, flags);
+	list_for_each_entry_safe(error_buff, tmp, &adapter->errors, list)
+		if (error_buff->error_id == crq->request_error_rsp.error_id) {
+			found = true;
+			list_del(&error_buff->list);
+			break;
+		}
+	spin_unlock_irqrestore(&adapter->error_list_lock, flags);
+
+	if (!found) {
+		dev_err(dev, "Couldn't find error id %x\n",
+			crq->request_error_rsp.error_id);
+		return;
+	}
+
+	dev_err(dev, "Detailed info for error id %x:",
+		crq->request_error_rsp.error_id);
+
+	for (i = 0; i < error_buff->len; i++) {
+		pr_cont("%02x", (int)error_buff->buff[i]);
+		if (i % 8 == 7)
+			pr_cont(" ");
+	}
+	pr_cont("\n");
+
+	dma_unmap_single(dev, error_buff->dma, error_buff->len,
+			 DMA_FROM_DEVICE);
+	kfree(error_buff->buff);
+	kfree(error_buff);
+}
+
+static void handle_dump_size_rsp(union ibmvnic_crq *crq,
+				 struct ibmvnic_adapter *adapter)
+{
+	int len = be32_to_cpu(crq->request_dump_size_rsp.len);
+	struct ibmvnic_inflight_cmd *inflight_cmd;
+	struct device *dev = &adapter->vdev->dev;
+	union ibmvnic_crq newcrq;
+	unsigned long flags;
+
+	/* allocate and map buffer */
+	adapter->dump_data = kmalloc(len, GFP_KERNEL);
+	if (!adapter->dump_data) {
+		complete(&adapter->fw_done);
+		return;
+	}
+
+	adapter->dump_data_token = dma_map_single(dev, adapter->dump_data, len,
+						  DMA_FROM_DEVICE);
+
+	if (dma_mapping_error(dev, adapter->dump_data_token)) {
+		if (!firmware_has_feature(FW_FEATURE_CMO))
+			dev_err(dev, "Couldn't map dump data\n");
+		kfree(adapter->dump_data);
+		complete(&adapter->fw_done);
+		return;
+	}
+
+	inflight_cmd = kmalloc(sizeof(*inflight_cmd), GFP_ATOMIC);
+	if (!inflight_cmd) {
+		dma_unmap_single(dev, adapter->dump_data_token, len,
+				 DMA_FROM_DEVICE);
+		kfree(adapter->dump_data);
+		complete(&adapter->fw_done);
+		return;
+	}
+
+	memset(&newcrq, 0, sizeof(newcrq));
+	newcrq.request_dump.first = IBMVNIC_CRQ_CMD;
+	newcrq.request_dump.cmd = REQUEST_DUMP;
+	newcrq.request_dump.ioba = cpu_to_be32(adapter->dump_data_token);
+	newcrq.request_dump.len = cpu_to_be32(adapter->dump_data_size);
+
+	memcpy(&inflight_cmd->crq, &newcrq, sizeof(newcrq));
+
+	spin_lock_irqsave(&adapter->inflight_lock, flags);
+	list_add_tail(&inflight_cmd->list, &adapter->inflight);
+	spin_unlock_irqrestore(&adapter->inflight_lock, flags);
+
+	ibmvnic_send_crq(adapter, &newcrq);
+}
+
+static void handle_error_indication(union ibmvnic_crq *crq,
+				    struct ibmvnic_adapter *adapter)
+{
+	int detail_len = be32_to_cpu(crq->error_indication.detail_error_sz);
+	struct ibmvnic_inflight_cmd *inflight_cmd;
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_error_buff *error_buff;
+	union ibmvnic_crq new_crq;
+	unsigned long flags;
+
+	dev_err(dev, "Firmware reports %serror id %x, cause %d\n",
+		crq->error_indication.
+		    flags & IBMVNIC_FATAL_ERROR ? "FATAL " : "",
+		crq->error_indication.error_id,
+		crq->error_indication.error_cause);
+
+	error_buff = kmalloc(sizeof(*error_buff), GFP_ATOMIC);
+	if (!error_buff)
+		return;
+
+	error_buff->buff = kmalloc(detail_len, GFP_ATOMIC);
+	if (!error_buff->buff) {
+		kfree(error_buff);
+		return;
+	}
+
+	error_buff->dma = dma_map_single(dev, error_buff->buff, detail_len,
+					 DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, error_buff->dma)) {
+		if (!firmware_has_feature(FW_FEATURE_CMO))
+			dev_err(dev, "Couldn't map error buffer\n");
+		kfree(error_buff->buff);
+		kfree(error_buff);
+		return;
+	}
+
+	inflight_cmd = kmalloc(sizeof(*inflight_cmd), GFP_ATOMIC);
+	if (!inflight_cmd) {
+		dma_unmap_single(dev, error_buff->dma, detail_len,
+				 DMA_FROM_DEVICE);
+		kfree(error_buff->buff);
+		kfree(error_buff);
+		return;
+	}
+
+	error_buff->len = detail_len;
+	error_buff->error_id = crq->error_indication.error_id;
+
+	spin_lock_irqsave(&adapter->error_list_lock, flags);
+	list_add_tail(&error_buff->list, &adapter->errors);
+	spin_unlock_irqrestore(&adapter->error_list_lock, flags);
+
+	memset(&new_crq, 0, sizeof(new_crq));
+	new_crq.request_error_info.first = IBMVNIC_CRQ_CMD;
+	new_crq.request_error_info.cmd = REQUEST_ERROR_INFO;
+	new_crq.request_error_info.ioba = cpu_to_be32(error_buff->dma);
+	new_crq.request_error_info.len = cpu_to_be32(detail_len);
+	new_crq.request_error_info.error_id = crq->error_indication.error_id;
+
+	memcpy(&inflight_cmd->crq, &crq, sizeof(crq));
+
+	spin_lock_irqsave(&adapter->inflight_lock, flags);
+	list_add_tail(&inflight_cmd->list, &adapter->inflight);
+	spin_unlock_irqrestore(&adapter->inflight_lock, flags);
+
+	ibmvnic_send_crq(adapter, &new_crq);
+}
+
+static void handle_change_mac_rsp(union ibmvnic_crq *crq,
+				  struct ibmvnic_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct device *dev = &adapter->vdev->dev;
+	long rc;
+
+	rc = crq->change_mac_addr_rsp.rc.code;
+	if (rc) {
+		dev_err(dev, "Error %ld in CHANGE_MAC_ADDR_RSP\n", rc);
+		return;
+	}
+	memcpy(netdev->dev_addr, &crq->change_mac_addr_rsp.mac_addr[0],
+	       ETH_ALEN);
+}
+
+static void handle_request_cap_rsp(union ibmvnic_crq *crq,
+				   struct ibmvnic_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	u64 *req_value;
+	char *name;
+
+	switch (be16_to_cpu(crq->request_capability_rsp.capability)) {
+	case REQ_TX_QUEUES:
+		req_value = &adapter->req_tx_queues;
+		name = "tx";
+		break;
+	case REQ_RX_QUEUES:
+		req_value = &adapter->req_rx_queues;
+		name = "rx";
+		break;
+	case REQ_RX_ADD_QUEUES:
+		req_value = &adapter->req_rx_add_queues;
+		name = "rx_add";
+		break;
+	case REQ_TX_ENTRIES_PER_SUBCRQ:
+		req_value = &adapter->req_tx_entries_per_subcrq;
+		name = "tx_entries_per_subcrq";
+		break;
+	case REQ_RX_ADD_ENTRIES_PER_SUBCRQ:
+		req_value = &adapter->req_rx_add_entries_per_subcrq;
+		name = "rx_add_entries_per_subcrq";
+		break;
+	case REQ_MTU:
+		req_value = &adapter->req_mtu;
+		name = "mtu";
+		break;
+	case PROMISC_REQUESTED:
+		req_value = &adapter->promisc;
+		name = "promisc";
+		break;
+	default:
+		dev_err(dev, "Got invalid cap request rsp %d\n",
+			crq->request_capability.capability);
+		return;
+	}
+
+	switch (crq->request_capability_rsp.rc.code) {
+	case SUCCESS:
+		break;
+	case PARTIALSUCCESS:
+		dev_info(dev, "req=%lld, rsp=%ld in %s queue, retrying.\n",
+			 *req_value,
+			 (long int)be32_to_cpu(crq->request_capability_rsp.
+					       number), name);
+		release_sub_crqs(adapter);
+		*req_value = be32_to_cpu(crq->request_capability_rsp.number);
+		complete(&adapter->init_done);
+		return;
+	default:
+		dev_err(dev, "Error %d in request cap rsp\n",
+			crq->request_capability_rsp.rc.code);
+		return;
+	}
+
+	/* Done receiving requested capabilities, query IP offload support */
+	if (++adapter->requested_caps == 7) {
+		union ibmvnic_crq newcrq;
+		int buf_sz = sizeof(struct ibmvnic_query_ip_offload_buffer);
+		struct ibmvnic_query_ip_offload_buffer *ip_offload_buf =
+		    &adapter->ip_offload_buf;
+
+		adapter->ip_offload_tok = dma_map_single(dev, ip_offload_buf,
+							 buf_sz,
+							 DMA_FROM_DEVICE);
+
+		if (dma_mapping_error(dev, adapter->ip_offload_tok)) {
+			if (!firmware_has_feature(FW_FEATURE_CMO))
+				dev_err(dev, "Couldn't map offload buffer\n");
+			return;
+		}
+
+		memset(&newcrq, 0, sizeof(newcrq));
+		newcrq.query_ip_offload.first = IBMVNIC_CRQ_CMD;
+		newcrq.query_ip_offload.cmd = QUERY_IP_OFFLOAD;
+		newcrq.query_ip_offload.len = cpu_to_be32(buf_sz);
+		newcrq.query_ip_offload.ioba =
+		    cpu_to_be32(adapter->ip_offload_tok);
+
+		ibmvnic_send_crq(adapter, &newcrq);
+	}
+}
+
+static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
+			    struct ibmvnic_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_login_rsp_buffer *login_rsp = adapter->login_rsp_buf;
+	struct ibmvnic_login_buffer *login = adapter->login_buf;
+	union ibmvnic_crq crq;
+	int i;
+
+	dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz,
+			 DMA_BIDIRECTIONAL);
+	dma_unmap_single(dev, adapter->login_rsp_buf_token,
+			 adapter->login_rsp_buf_sz, DMA_BIDIRECTIONAL);
+
+	netdev_dbg(adapter->netdev, "Login Response Buffer:\n");
+	for (i = 0; i < (adapter->login_rsp_buf_sz - 1) / 8 + 1; i++) {
+		netdev_dbg(adapter->netdev, "%016lx\n",
+			   ((unsigned long int *)(adapter->login_rsp_buf))[i]);
+	}
+
+	/* Sanity checks */
+	if (login->num_txcomp_subcrqs != login_rsp->num_txsubm_subcrqs ||
+	    (be32_to_cpu(login->num_rxcomp_subcrqs) *
+	     adapter->req_rx_add_queues !=
+	     be32_to_cpu(login_rsp->num_rxadd_subcrqs))) {
+		dev_err(dev, "FATAL: Inconsistent login and login rsp\n");
+		ibmvnic_remove(adapter->vdev);
+		return -EIO;
+	}
+	complete(&adapter->init_done);
+
+	memset(&crq, 0, sizeof(crq));
+	crq.request_ras_comp_num.first = IBMVNIC_CRQ_CMD;
+	crq.request_ras_comp_num.cmd = REQUEST_RAS_COMP_NUM;
+	ibmvnic_send_crq(adapter, &crq);
+
+	return 0;
+}
+
+static void handle_request_map_rsp(union ibmvnic_crq *crq,
+				   struct ibmvnic_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	u8 map_id = crq->request_map_rsp.map_id;
+	int tx_subcrqs;
+	int rx_subcrqs;
+	long rc;
+	int i;
+
+	tx_subcrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
+	rx_subcrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+
+	rc = crq->request_map_rsp.rc.code;
+	if (rc) {
+		dev_err(dev, "Error %ld in REQUEST_MAP_RSP\n", rc);
+		adapter->map_id--;
+		/* need to find and zero tx/rx_pool map_id */
+		for (i = 0; i < tx_subcrqs; i++) {
+			if (adapter->tx_pool[i].long_term_buff.map_id == map_id)
+				adapter->tx_pool[i].long_term_buff.map_id = 0;
+		}
+		for (i = 0; i < rx_subcrqs; i++) {
+			if (adapter->rx_pool[i].long_term_buff.map_id == map_id)
+				adapter->rx_pool[i].long_term_buff.map_id = 0;
+		}
+	}
+	complete(&adapter->fw_done);
+}
+
+static void handle_request_unmap_rsp(union ibmvnic_crq *crq,
+				     struct ibmvnic_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	long rc;
+
+	rc = crq->request_unmap_rsp.rc.code;
+	if (rc)
+		dev_err(dev, "Error %ld in REQUEST_UNMAP_RSP\n", rc);
+}
+
+static void handle_query_map_rsp(union ibmvnic_crq *crq,
+				 struct ibmvnic_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct device *dev = &adapter->vdev->dev;
+	long rc;
+
+	rc = crq->query_map_rsp.rc.code;
+	if (rc) {
+		dev_err(dev, "Error %ld in QUERY_MAP_RSP\n", rc);
+		return;
+	}
+	netdev_dbg(netdev, "page_size = %d\ntot_pages = %d\nfree_pages = %d\n",
+		   crq->query_map_rsp.page_size, crq->query_map_rsp.tot_pages,
+		   crq->query_map_rsp.free_pages);
+}
+
+static void handle_query_cap_rsp(union ibmvnic_crq *crq,
+				 struct ibmvnic_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct device *dev = &adapter->vdev->dev;
+	long rc;
+
+	atomic_dec(&adapter->running_cap_queries);
+	netdev_dbg(netdev, "Outstanding queries: %d\n",
+		   atomic_read(&adapter->running_cap_queries));
+	rc = crq->query_capability.rc.code;
+	if (rc) {
+		dev_err(dev, "Error %ld in QUERY_CAP_RSP\n", rc);
+		goto out;
+	}
+
+	switch (be16_to_cpu(crq->query_capability.capability)) {
+	case MIN_TX_QUEUES:
+		adapter->min_tx_queues =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "min_tx_queues = %lld\n",
+			   adapter->min_tx_queues);
+		break;
+	case MIN_RX_QUEUES:
+		adapter->min_rx_queues =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "min_rx_queues = %lld\n",
+			   adapter->min_rx_queues);
+		break;
+	case MIN_RX_ADD_QUEUES:
+		adapter->min_rx_add_queues =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "min_rx_add_queues = %lld\n",
+			   adapter->min_rx_add_queues);
+		break;
+	case MAX_TX_QUEUES:
+		adapter->max_tx_queues =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "max_tx_queues = %lld\n",
+			   adapter->max_tx_queues);
+		break;
+	case MAX_RX_QUEUES:
+		adapter->max_rx_queues =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "max_rx_queues = %lld\n",
+			   adapter->max_rx_queues);
+		break;
+	case MAX_RX_ADD_QUEUES:
+		adapter->max_rx_add_queues =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "max_rx_add_queues = %lld\n",
+			   adapter->max_rx_add_queues);
+		break;
+	case MIN_TX_ENTRIES_PER_SUBCRQ:
+		adapter->min_tx_entries_per_subcrq =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "min_tx_entries_per_subcrq = %lld\n",
+			   adapter->min_tx_entries_per_subcrq);
+		break;
+	case MIN_RX_ADD_ENTRIES_PER_SUBCRQ:
+		adapter->min_rx_add_entries_per_subcrq =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "min_rx_add_entrs_per_subcrq = %lld\n",
+			   adapter->min_rx_add_entries_per_subcrq);
+		break;
+	case MAX_TX_ENTRIES_PER_SUBCRQ:
+		adapter->max_tx_entries_per_subcrq =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "max_tx_entries_per_subcrq = %lld\n",
+			   adapter->max_tx_entries_per_subcrq);
+		break;
+	case MAX_RX_ADD_ENTRIES_PER_SUBCRQ:
+		adapter->max_rx_add_entries_per_subcrq =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "max_rx_add_entrs_per_subcrq = %lld\n",
+			   adapter->max_rx_add_entries_per_subcrq);
+		break;
+	case TCP_IP_OFFLOAD:
+		adapter->tcp_ip_offload =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "tcp_ip_offload = %lld\n",
+			   adapter->tcp_ip_offload);
+		break;
+	case PROMISC_SUPPORTED:
+		adapter->promisc_supported =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "promisc_supported = %lld\n",
+			   adapter->promisc_supported);
+		break;
+	case MIN_MTU:
+		adapter->min_mtu = be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "min_mtu = %lld\n", adapter->min_mtu);
+		break;
+	case MAX_MTU:
+		adapter->max_mtu = be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "max_mtu = %lld\n", adapter->max_mtu);
+		break;
+	case MAX_MULTICAST_FILTERS:
+		adapter->max_multicast_filters =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "max_multicast_filters = %lld\n",
+			   adapter->max_multicast_filters);
+		break;
+	case VLAN_HEADER_INSERTION:
+		adapter->vlan_header_insertion =
+		    be32_to_cpu(crq->query_capability.number);
+		if (adapter->vlan_header_insertion)
+			netdev->features |= NETIF_F_HW_VLAN_STAG_TX;
+		netdev_dbg(netdev, "vlan_header_insertion = %lld\n",
+			   adapter->vlan_header_insertion);
+		break;
+	case MAX_TX_SG_ENTRIES:
+		adapter->max_tx_sg_entries =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "max_tx_sg_entries = %lld\n",
+			   adapter->max_tx_sg_entries);
+		break;
+	case RX_SG_SUPPORTED:
+		adapter->rx_sg_supported =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "rx_sg_supported = %lld\n",
+			   adapter->rx_sg_supported);
+		break;
+	case OPT_TX_COMP_SUB_QUEUES:
+		adapter->opt_tx_comp_sub_queues =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "opt_tx_comp_sub_queues = %lld\n",
+			   adapter->opt_tx_comp_sub_queues);
+		break;
+	case OPT_RX_COMP_QUEUES:
+		adapter->opt_rx_comp_queues =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "opt_rx_comp_queues = %lld\n",
+			   adapter->opt_rx_comp_queues);
+		break;
+	case OPT_RX_BUFADD_Q_PER_RX_COMP_Q:
+		adapter->opt_rx_bufadd_q_per_rx_comp_q =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "opt_rx_bufadd_q_per_rx_comp_q = %lld\n",
+			   adapter->opt_rx_bufadd_q_per_rx_comp_q);
+		break;
+	case OPT_TX_ENTRIES_PER_SUBCRQ:
+		adapter->opt_tx_entries_per_subcrq =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "opt_tx_entries_per_subcrq = %lld\n",
+			   adapter->opt_tx_entries_per_subcrq);
+		break;
+	case OPT_RXBA_ENTRIES_PER_SUBCRQ:
+		adapter->opt_rxba_entries_per_subcrq =
+		    be32_to_cpu(crq->query_capability.number);
+		netdev_dbg(netdev, "opt_rxba_entries_per_subcrq = %lld\n",
+			   adapter->opt_rxba_entries_per_subcrq);
+		break;
+	case TX_RX_DESC_REQ:
+		adapter->tx_rx_desc_req = crq->query_capability.number;
+		netdev_dbg(netdev, "tx_rx_desc_req = %llx\n",
+			   adapter->tx_rx_desc_req);
+		break;
+
+	default:
+		netdev_err(netdev, "Got invalid cap rsp %d\n",
+			   crq->query_capability.capability);
+	}
+
+out:
+	if (atomic_read(&adapter->running_cap_queries) == 0)
+		complete(&adapter->init_done);
+		/* We're done querying the capabilities, initialize sub-crqs */
+}
+
+static void handle_control_ras_rsp(union ibmvnic_crq *crq,
+				   struct ibmvnic_adapter *adapter)
+{
+	u8 correlator = crq->control_ras_rsp.correlator;
+	struct device *dev = &adapter->vdev->dev;
+	bool found = false;
+	int i;
+
+	if (crq->control_ras_rsp.rc.code) {
+		dev_warn(dev, "Control ras failed rc=%d\n",
+			 crq->control_ras_rsp.rc.code);
+		return;
+	}
+
+	for (i = 0; i < adapter->ras_comp_num; i++) {
+		if (adapter->ras_comps[i].correlator == correlator) {
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		dev_warn(dev, "Correlator not found on control_ras_rsp\n");
+		return;
+	}
+
+	switch (crq->control_ras_rsp.op) {
+	case IBMVNIC_TRACE_LEVEL:
+		adapter->ras_comps[i].trace_level = crq->control_ras.level;
+		break;
+	case IBMVNIC_ERROR_LEVEL:
+		adapter->ras_comps[i].error_check_level =
+		    crq->control_ras.level;
+		break;
+	case IBMVNIC_TRACE_PAUSE:
+		adapter->ras_comp_int[i].paused = 1;
+		break;
+	case IBMVNIC_TRACE_RESUME:
+		adapter->ras_comp_int[i].paused = 0;
+		break;
+	case IBMVNIC_TRACE_ON:
+		adapter->ras_comps[i].trace_on = 1;
+		break;
+	case IBMVNIC_TRACE_OFF:
+		adapter->ras_comps[i].trace_on = 0;
+		break;
+	case IBMVNIC_CHG_TRACE_BUFF_SZ:
+		/* trace_buff_sz is 3 bytes, stuff it into an int */
+		((u8 *)(&adapter->ras_comps[i].trace_buff_size))[0] = 0;
+		((u8 *)(&adapter->ras_comps[i].trace_buff_size))[1] =
+		    crq->control_ras_rsp.trace_buff_sz[0];
+		((u8 *)(&adapter->ras_comps[i].trace_buff_size))[2] =
+		    crq->control_ras_rsp.trace_buff_sz[1];
+		((u8 *)(&adapter->ras_comps[i].trace_buff_size))[3] =
+		    crq->control_ras_rsp.trace_buff_sz[2];
+		break;
+	default:
+		dev_err(dev, "invalid op %d on control_ras_rsp",
+			crq->control_ras_rsp.op);
+	}
+}
+
+static int ibmvnic_fw_comp_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t trace_read(struct file *file, char __user *user_buf, size_t len,
+			  loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_fw_trace_entry *trace;
+	int num = ras_comp_int->num;
+	union ibmvnic_crq crq;
+	dma_addr_t trace_tok;
+
+	if (*ppos >= be32_to_cpu(adapter->ras_comps[num].trace_buff_size))
+		return 0;
+
+	trace =
+	    dma_alloc_coherent(dev,
+			       be32_to_cpu(adapter->ras_comps[num].
+					   trace_buff_size), &trace_tok,
+			       GFP_KERNEL);
+	if (!trace) {
+		dev_err(dev, "Couldn't alloc trace buffer\n");
+		return 0;
+	}
+
+	memset(&crq, 0, sizeof(crq));
+	crq.collect_fw_trace.first = IBMVNIC_CRQ_CMD;
+	crq.collect_fw_trace.cmd = COLLECT_FW_TRACE;
+	crq.collect_fw_trace.correlator = adapter->ras_comps[num].correlator;
+	crq.collect_fw_trace.ioba = cpu_to_be32(trace_tok);
+	crq.collect_fw_trace.len = adapter->ras_comps[num].trace_buff_size;
+	ibmvnic_send_crq(adapter, &crq);
+
+	init_completion(&adapter->fw_done);
+	wait_for_completion(&adapter->fw_done);
+
+	if (*ppos + len > be32_to_cpu(adapter->ras_comps[num].trace_buff_size))
+		len =
+		    be32_to_cpu(adapter->ras_comps[num].trace_buff_size) -
+		    *ppos;
+
+	copy_to_user(user_buf, &((u8 *)trace)[*ppos], len);
+
+	dma_free_coherent(dev,
+			  be32_to_cpu(adapter->ras_comps[num].trace_buff_size),
+			  trace, trace_tok);
+	*ppos += len;
+	return len;
+}
+
+static const struct file_operations trace_ops = {
+	.owner		= THIS_MODULE,
+	.open		= ibmvnic_fw_comp_open,
+	.read		= trace_read,
+};
+
+static ssize_t paused_read(struct file *file, char __user *user_buf, size_t len,
+			   loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	int num = ras_comp_int->num;
+	char buff[5]; /*  1 or 0 plus \n and \0 */
+	int size;
+
+	size = sprintf(buff, "%d\n", adapter->ras_comp_int[num].paused);
+
+	if (*ppos >= size)
+		return 0;
+
+	copy_to_user(user_buf, buff, size);
+	*ppos += size;
+	return size;
+}
+
+static ssize_t paused_write(struct file *file, const char __user *user_buf,
+			    size_t len, loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	int num = ras_comp_int->num;
+	union ibmvnic_crq crq;
+	unsigned long val;
+	char buff[9]; /* decimal max int plus \n and \0 */
+
+	copy_from_user(buff, user_buf, sizeof(buff));
+	val = kstrtoul(buff, 10, NULL);
+
+	adapter->ras_comp_int[num].paused = val ? 1 : 0;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.control_ras.first = IBMVNIC_CRQ_CMD;
+	crq.control_ras.cmd = CONTROL_RAS;
+	crq.control_ras.correlator = adapter->ras_comps[num].correlator;
+	crq.control_ras.op = val ? IBMVNIC_TRACE_PAUSE : IBMVNIC_TRACE_RESUME;
+	ibmvnic_send_crq(adapter, &crq);
+
+	return len;
+}
+
+static const struct file_operations paused_ops = {
+	.owner		= THIS_MODULE,
+	.open		= ibmvnic_fw_comp_open,
+	.read		= paused_read,
+	.write		= paused_write,
+};
+
+static ssize_t tracing_read(struct file *file, char __user *user_buf,
+			    size_t len, loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	int num = ras_comp_int->num;
+	char buff[5]; /*  1 or 0 plus \n and \0 */
+	int size;
+
+	size = sprintf(buff, "%d\n", adapter->ras_comps[num].trace_on);
+
+	if (*ppos >= size)
+		return 0;
+
+	copy_to_user(user_buf, buff, size);
+	*ppos += size;
+	return size;
+}
+
+static ssize_t tracing_write(struct file *file, const char __user *user_buf,
+			     size_t len, loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	int num = ras_comp_int->num;
+	union ibmvnic_crq crq;
+	unsigned long val;
+	char buff[9]; /* decimal max int plus \n and \0 */
+
+	copy_from_user(buff, user_buf, sizeof(buff));
+	val = kstrtoul(buff, 10, NULL);
+
+	memset(&crq, 0, sizeof(crq));
+	crq.control_ras.first = IBMVNIC_CRQ_CMD;
+	crq.control_ras.cmd = CONTROL_RAS;
+	crq.control_ras.correlator = adapter->ras_comps[num].correlator;
+	crq.control_ras.op = val ? IBMVNIC_TRACE_ON : IBMVNIC_TRACE_OFF;
+
+	return len;
+}
+
+static const struct file_operations tracing_ops = {
+	.owner		= THIS_MODULE,
+	.open		= ibmvnic_fw_comp_open,
+	.read		= tracing_read,
+	.write		= tracing_write,
+};
+
+static ssize_t error_level_read(struct file *file, char __user *user_buf,
+				size_t len, loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	int num = ras_comp_int->num;
+	char buff[5]; /* decimal max char plus \n and \0 */
+	int size;
+
+	size = sprintf(buff, "%d\n", adapter->ras_comps[num].error_check_level);
+
+	if (*ppos >= size)
+		return 0;
+
+	copy_to_user(user_buf, buff, size);
+	*ppos += size;
+	return size;
+}
+
+static ssize_t error_level_write(struct file *file, const char __user *user_buf,
+				 size_t len, loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	int num = ras_comp_int->num;
+	union ibmvnic_crq crq;
+	unsigned long val;
+	char buff[9]; /* decimal max int plus \n and \0 */
+
+	copy_from_user(buff, user_buf, sizeof(buff));
+	val = kstrtoul(buff, 10, NULL);
+
+	if (val > 9)
+		val = 9;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.control_ras.first = IBMVNIC_CRQ_CMD;
+	crq.control_ras.cmd = CONTROL_RAS;
+	crq.control_ras.correlator = adapter->ras_comps[num].correlator;
+	crq.control_ras.op = IBMVNIC_ERROR_LEVEL;
+	crq.control_ras.level = val;
+	ibmvnic_send_crq(adapter, &crq);
+
+	return len;
+}
+
+static const struct file_operations error_level_ops = {
+	.owner		= THIS_MODULE,
+	.open		= ibmvnic_fw_comp_open,
+	.read		= error_level_read,
+	.write		= error_level_write,
+};
+
+static ssize_t trace_level_read(struct file *file, char __user *user_buf,
+				size_t len, loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	int num = ras_comp_int->num;
+	char buff[5]; /* decimal max char plus \n and \0 */
+	int size;
+
+	size = sprintf(buff, "%d\n", adapter->ras_comps[num].trace_level);
+	if (*ppos >= size)
+		return 0;
+
+	copy_to_user(user_buf, buff, size);
+	*ppos += size;
+	return size;
+}
+
+static ssize_t trace_level_write(struct file *file, const char __user *user_buf,
+				 size_t len, loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	union ibmvnic_crq crq;
+	unsigned long val;
+	char buff[9]; /* decimal max int plus \n and \0 */
+
+	copy_from_user(buff, user_buf, sizeof(buff));
+	val = kstrtoul(buff, 10, NULL);
+	if (val > 9)
+		val = 9;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.control_ras.first = IBMVNIC_CRQ_CMD;
+	crq.control_ras.cmd = CONTROL_RAS;
+	crq.control_ras.correlator =
+	    adapter->ras_comps[ras_comp_int->num].correlator;
+	crq.control_ras.op = IBMVNIC_TRACE_LEVEL;
+	crq.control_ras.level = val;
+	ibmvnic_send_crq(adapter, &crq);
+
+	return len;
+}
+
+static const struct file_operations trace_level_ops = {
+	.owner		= THIS_MODULE,
+	.open		= ibmvnic_fw_comp_open,
+	.read		= trace_level_read,
+	.write		= trace_level_write,
+};
+
+static ssize_t trace_buff_size_read(struct file *file, char __user *user_buf,
+				    size_t len, loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	int num = ras_comp_int->num;
+	char buff[9]; /* decimal max int plus \n and \0 */
+	int size;
+
+	size = sprintf(buff, "%d\n", adapter->ras_comps[num].trace_buff_size);
+	if (*ppos >= size)
+		return 0;
+
+	copy_to_user(user_buf, buff, size);
+	*ppos += size;
+	return size;
+}
+
+static ssize_t trace_buff_size_write(struct file *file,
+				     const char __user *user_buf, size_t len,
+				     loff_t *ppos)
+{
+	struct ibmvnic_fw_comp_internal *ras_comp_int = file->private_data;
+	struct ibmvnic_adapter *adapter = ras_comp_int->adapter;
+	union ibmvnic_crq crq;
+	unsigned long val;
+	char buff[9]; /* decimal max int plus \n and \0 */
+
+	copy_from_user(buff, user_buf, sizeof(buff));
+	val = kstrtoul(buff, 10, NULL);
+
+	memset(&crq, 0, sizeof(crq));
+	crq.control_ras.first = IBMVNIC_CRQ_CMD;
+	crq.control_ras.cmd = CONTROL_RAS;
+	crq.control_ras.correlator =
+	    adapter->ras_comps[ras_comp_int->num].correlator;
+	crq.control_ras.op = IBMVNIC_CHG_TRACE_BUFF_SZ;
+	/* trace_buff_sz is 3 bytes, stuff an int into it */
+	crq.control_ras.trace_buff_sz[0] = ((u8 *)(&val))[5];
+	crq.control_ras.trace_buff_sz[1] = ((u8 *)(&val))[6];
+	crq.control_ras.trace_buff_sz[2] = ((u8 *)(&val))[7];
+	ibmvnic_send_crq(adapter, &crq);
+
+	return len;
+}
+
+static const struct file_operations trace_size_ops = {
+	.owner		= THIS_MODULE,
+	.open		= ibmvnic_fw_comp_open,
+	.read		= trace_buff_size_read,
+	.write		= trace_buff_size_write,
+};
+
+static void handle_request_ras_comps_rsp(union ibmvnic_crq *crq,
+					 struct ibmvnic_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	struct dentry *dir_ent;
+	struct dentry *ent;
+	int i;
+
+	debugfs_remove_recursive(adapter->ras_comps_ent);
+
+	adapter->ras_comps_ent = debugfs_create_dir("ras_comps",
+						    adapter->debugfs_dir);
+	if (!adapter->ras_comps_ent || IS_ERR(adapter->ras_comps_ent)) {
+		dev_info(dev, "debugfs create ras_comps dir failed\n");
+		return;
+	}
+
+	for (i = 0; i < adapter->ras_comp_num; i++) {
+		dir_ent = debugfs_create_dir(adapter->ras_comps[i].name,
+					     adapter->ras_comps_ent);
+		if (!dir_ent || IS_ERR(dir_ent)) {
+			dev_info(dev, "debugfs create %s dir failed\n",
+				 adapter->ras_comps[i].name);
+			continue;
+		}
+
+		adapter->ras_comp_int[i].adapter = adapter;
+		adapter->ras_comp_int[i].num = i;
+		adapter->ras_comp_int[i].desc_blob.data =
+		    &adapter->ras_comps[i].description;
+		adapter->ras_comp_int[i].desc_blob.size =
+		    sizeof(adapter->ras_comps[i].description);
+
+		/* Don't need to remember the dentry's because the debugfs dir
+		 * gets removed recursively
+		 */
+		ent = debugfs_create_blob("description", S_IRUGO, dir_ent,
+					  &adapter->ras_comp_int[i].desc_blob);
+		ent = debugfs_create_file("trace_buf_size", S_IRUGO | S_IWUSR,
+					  dir_ent, &adapter->ras_comp_int[i],
+					  &trace_size_ops);
+		ent = debugfs_create_file("trace_level",
+					  S_IRUGO |
+					  (adapter->ras_comps[i].trace_level !=
+					   0xFF  ? S_IWUSR : 0),
+					   dir_ent, &adapter->ras_comp_int[i],
+					   &trace_level_ops);
+		ent = debugfs_create_file("error_level",
+					  S_IRUGO |
+					  (adapter->
+					   ras_comps[i].error_check_level !=
+					   0xFF ? S_IWUSR : 0),
+					  dir_ent, &adapter->ras_comp_int[i],
+					  &trace_level_ops);
+		ent = debugfs_create_file("tracing", S_IRUGO | S_IWUSR,
+					  dir_ent, &adapter->ras_comp_int[i],
+					  &tracing_ops);
+		ent = debugfs_create_file("paused", S_IRUGO | S_IWUSR,
+					  dir_ent, &adapter->ras_comp_int[i],
+					  &paused_ops);
+		ent = debugfs_create_file("trace", S_IRUGO, dir_ent,
+					  &adapter->ras_comp_int[i],
+					  &trace_ops);
+	}
+}
+
+static void handle_request_ras_comp_num_rsp(union ibmvnic_crq *crq,
+					    struct ibmvnic_adapter *adapter)
+{
+	int len = adapter->ras_comp_num * sizeof(struct ibmvnic_fw_component);
+	struct device *dev = &adapter->vdev->dev;
+	union ibmvnic_crq newcrq;
+
+	adapter->ras_comps = dma_alloc_coherent(dev, len,
+						&adapter->ras_comps_tok,
+						GFP_KERNEL);
+	if (!adapter->ras_comps) {
+		if (!firmware_has_feature(FW_FEATURE_CMO))
+			dev_err(dev, "Couldn't alloc fw comps buffer\n");
+		return;
+	}
+
+	adapter->ras_comp_int = kmalloc(adapter->ras_comp_num *
+					sizeof(struct ibmvnic_fw_comp_internal),
+					GFP_KERNEL);
+	if (!adapter->ras_comp_int)
+		dma_free_coherent(dev, len, adapter->ras_comps,
+				  adapter->ras_comps_tok);
+
+	memset(&newcrq, 0, sizeof(newcrq));
+	newcrq.request_ras_comps.first = IBMVNIC_CRQ_CMD;
+	newcrq.request_ras_comps.cmd = REQUEST_RAS_COMPS;
+	newcrq.request_ras_comps.ioba = cpu_to_be32(adapter->ras_comps_tok);
+	newcrq.request_ras_comps.len = cpu_to_be32(len);
+	ibmvnic_send_crq(adapter, &newcrq);
+}
+
+static void ibmvnic_free_inflight(struct ibmvnic_adapter *adapter)
+{
+	struct ibmvnic_inflight_cmd *inflight_cmd, *tmp1;
+	struct device *dev = &adapter->vdev->dev;
+	struct ibmvnic_error_buff *error_buff, *tmp2;
+	unsigned long flags;
+	unsigned long flags2;
+
+	spin_lock_irqsave(&adapter->inflight_lock, flags);
+	list_for_each_entry_safe(inflight_cmd, tmp1, &adapter->inflight, list) {
+		switch (inflight_cmd->crq.generic.cmd) {
+		case LOGIN:
+			dma_unmap_single(dev, adapter->login_buf_token,
+					 adapter->login_buf_sz,
+					 DMA_BIDIRECTIONAL);
+			dma_unmap_single(dev, adapter->login_rsp_buf_token,
+					 adapter->login_rsp_buf_sz,
+					 DMA_BIDIRECTIONAL);
+			kfree(adapter->login_rsp_buf);
+			kfree(adapter->login_buf);
+			break;
+		case REQUEST_DUMP:
+			complete(&adapter->fw_done);
+			break;
+		case REQUEST_ERROR_INFO:
+			spin_lock_irqsave(&adapter->error_list_lock, flags2);
+			list_for_each_entry_safe(error_buff, tmp2,
+						 &adapter->errors, list) {
+				dma_unmap_single(dev, error_buff->dma,
+						 error_buff->len,
+						 DMA_FROM_DEVICE);
+				kfree(error_buff->buff);
+				list_del(&error_buff->list);
+				kfree(error_buff);
+			}
+			spin_unlock_irqrestore(&adapter->error_list_lock,
+					       flags2);
+			break;
+		}
+		list_del(&inflight_cmd->list);
+		kfree(inflight_cmd);
+	}
+	spin_unlock_irqrestore(&adapter->inflight_lock, flags);
+}
+
+static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
+			       struct ibmvnic_adapter *adapter)
+{
+	struct ibmvnic_generic_crq *gen_crq = &crq->generic;
+	struct net_device *netdev = adapter->netdev;
+	struct device *dev = &adapter->vdev->dev;
+	long rc;
+
+	netdev_dbg(netdev, "Handling CRQ: %016lx %016lx\n",
+		   ((unsigned long int *)crq)[0],
+		   ((unsigned long int *)crq)[1]);
+	switch (gen_crq->first) {
+	case IBMVNIC_CRQ_INIT_RSP:
+		switch (gen_crq->cmd) {
+		case IBMVNIC_CRQ_INIT:
+			dev_info(dev, "Partner initialized\n");
+			/* Send back a response */
+			rc = ibmvnic_send_crq_init_complete(adapter);
+			if (rc == 0)
+				send_version_xchg(adapter);
+			else
+				dev_err(dev, "Can't send initrsp rc=%ld\n", rc);
+			break;
+		case IBMVNIC_CRQ_INIT_COMPLETE:
+			dev_info(dev, "Partner initialization complete\n");
+			send_version_xchg(adapter);
+			break;
+		default:
+			dev_err(dev, "Unknown crq cmd: %d\n", gen_crq->cmd);
+		}
+		return;
+	case IBMVNIC_CRQ_XPORT_EVENT:
+		if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) {
+			dev_info(dev, "Re-enabling adapter\n");
+			adapter->migrated = true;
+			ibmvnic_free_inflight(adapter);
+			release_sub_crqs(adapter);
+			rc = ibmvnic_reenable_crq_queue(adapter);
+			if (rc)
+				dev_err(dev, "Error after enable rc=%ld\n", rc);
+			adapter->migrated = false;
+			rc = ibmvnic_send_crq_init(adapter);
+			if (rc)
+				dev_err(dev, "Error sending init rc=%ld\n", rc);
+		} else {
+			/* The adapter lost the connection */
+			dev_err(dev, "Virtual Adapter failed (rc=%d)\n",
+				gen_crq->cmd);
+			ibmvnic_free_inflight(adapter);
+			release_sub_crqs(adapter);
+		}
+		return;
+	case IBMVNIC_CRQ_CMD_RSP:
+		break;
+	default:
+		dev_err(dev, "Got an invalid msg type 0x%02x\n",
+			gen_crq->first);
+		return;
+	}
+
+	switch (gen_crq->cmd) {
+	case VERSION_EXCHANGE_RSP:
+		rc = crq->version_exchange_rsp.rc.code;
+		if (rc) {
+			dev_err(dev, "Error %ld in VERSION_EXCHG_RSP\n", rc);
+			break;
+		}
+		dev_info(dev, "Partner protocol version is %d\n",
+			 crq->version_exchange_rsp.version);
+		if (be16_to_cpu(crq->version_exchange_rsp.version) <
+		    ibmvnic_version)
+			ibmvnic_version =
+			    be16_to_cpu(crq->version_exchange_rsp.version);
+		send_cap_queries(adapter);
+		break;
+	case QUERY_CAPABILITY_RSP:
+		handle_query_cap_rsp(crq, adapter);
+		break;
+	case QUERY_MAP_RSP:
+		handle_query_map_rsp(crq, adapter);
+		break;
+	case REQUEST_MAP_RSP:
+		handle_request_map_rsp(crq, adapter);
+		break;
+	case REQUEST_UNMAP_RSP:
+		handle_request_unmap_rsp(crq, adapter);
+		break;
+	case REQUEST_CAPABILITY_RSP:
+		handle_request_cap_rsp(crq, adapter);
+		break;
+	case LOGIN_RSP:
+		netdev_dbg(netdev, "Got Login Response\n");
+		handle_login_rsp(crq, adapter);
+		break;
+	case LOGICAL_LINK_STATE_RSP:
+		netdev_dbg(netdev, "Got Logical Link State Response\n");
+		adapter->logical_link_state =
+		    crq->logical_link_state_rsp.link_state;
+		break;
+	case LINK_STATE_INDICATION:
+		netdev_dbg(netdev, "Got Logical Link State Indication\n");
+		adapter->phys_link_state =
+		    crq->link_state_indication.phys_link_state;
+		adapter->logical_link_state =
+		    crq->link_state_indication.logical_link_state;
+		break;
+	case CHANGE_MAC_ADDR_RSP:
+		netdev_dbg(netdev, "Got MAC address change Response\n");
+		handle_change_mac_rsp(crq, adapter);
+		break;
+	case ERROR_INDICATION:
+		netdev_dbg(netdev, "Got Error Indication\n");
+		handle_error_indication(crq, adapter);
+		break;
+	case REQUEST_ERROR_RSP:
+		netdev_dbg(netdev, "Got Error Detail Response\n");
+		handle_error_info_rsp(crq, adapter);
+		break;
+	case REQUEST_STATISTICS_RSP:
+		netdev_dbg(netdev, "Got Statistics Response\n");
+		complete(&adapter->stats_done);
+		break;
+	case REQUEST_DUMP_SIZE_RSP:
+		netdev_dbg(netdev, "Got Request Dump Size Response\n");
+		handle_dump_size_rsp(crq, adapter);
+		break;
+	case REQUEST_DUMP_RSP:
+		netdev_dbg(netdev, "Got Request Dump Response\n");
+		complete(&adapter->fw_done);
+		break;
+	case QUERY_IP_OFFLOAD_RSP:
+		netdev_dbg(netdev, "Got Query IP offload Response\n");
+		handle_query_ip_offload_rsp(adapter);
+		break;
+	case MULTICAST_CTRL_RSP:
+		netdev_dbg(netdev, "Got multicast control Response\n");
+		break;
+	case CONTROL_IP_OFFLOAD_RSP:
+		netdev_dbg(netdev, "Got Control IP offload Response\n");
+		dma_unmap_single(dev, adapter->ip_offload_ctrl_tok,
+				 sizeof(adapter->ip_offload_ctrl),
+				 DMA_TO_DEVICE);
+		/* We're done with the queries, perform the login */
+		send_login(adapter);
+		break;
+	case REQUEST_RAS_COMP_NUM_RSP:
+		netdev_dbg(netdev, "Got Request RAS Comp Num Response\n");
+		if (crq->request_ras_comp_num_rsp.rc.code == 10) {
+			netdev_dbg(netdev, "Request RAS Comp Num not supported\n");
+			break;
+		}
+		adapter->ras_comp_num =
+		    be32_to_cpu(crq->request_ras_comp_num_rsp.num_components);
+		handle_request_ras_comp_num_rsp(crq, adapter);
+		break;
+	case REQUEST_RAS_COMPS_RSP:
+		netdev_dbg(netdev, "Got Request RAS Comps Response\n");
+		handle_request_ras_comps_rsp(crq, adapter);
+		break;
+	case CONTROL_RAS_RSP:
+		netdev_dbg(netdev, "Got Control RAS Response\n");
+		handle_control_ras_rsp(crq, adapter);
+		break;
+	case COLLECT_FW_TRACE_RSP:
+		netdev_dbg(netdev, "Got Collect firmware trace Response\n");
+		complete(&adapter->fw_done);
+		break;
+	default:
+		netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
+			   gen_crq->cmd);
+	}
+}
+
+static irqreturn_t ibmvnic_interrupt(int irq, void *instance)
+{
+	struct ibmvnic_adapter *adapter = instance;
+	struct ibmvnic_crq_queue *queue = &adapter->crq;
+	struct vio_dev *vdev = adapter->vdev;
+	union ibmvnic_crq *crq;
+	unsigned long flags;
+	bool done = false;
+
+	spin_lock_irqsave(&queue->lock, flags);
+	vio_disable_interrupts(vdev);
+	while (!done) {
+		/* Pull all the valid messages off the CRQ */
+		while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
+			ibmvnic_handle_crq(crq, adapter);
+			crq->generic.first = 0;
+		}
+		vio_enable_interrupts(vdev);
+		crq = ibmvnic_next_crq(adapter);
+		if (crq) {
+			vio_disable_interrupts(vdev);
+			ibmvnic_handle_crq(crq, adapter);
+			crq->generic.first = 0;
+		} else {
+			done = true;
+		}
+	}
+	spin_unlock_irqrestore(&queue->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *adapter)
+{
+	struct vio_dev *vdev = adapter->vdev;
+	int rc;
+
+	do {
+		rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
+	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	if (rc)
+		dev_err(&vdev->dev, "Error enabling adapter (rc=%d)\n", rc);
+
+	return rc;
+}
+
+static int ibmvnic_reset_crq(struct ibmvnic_adapter *adapter)
+{
+	struct ibmvnic_crq_queue *crq = &adapter->crq;
+	struct device *dev = &adapter->vdev->dev;
+	struct vio_dev *vdev = adapter->vdev;
+	int rc;
+
+	/* Close the CRQ */
+	do {
+		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	/* Clean out the queue */
+	memset(crq->msgs, 0, PAGE_SIZE);
+	crq->cur = 0;
+
+	/* And re-open it again */
+	rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
+				crq->msg_token, PAGE_SIZE);
+
+	if (rc == H_CLOSED)
+		/* Adapter is good, but other end is not ready */
+		dev_warn(dev, "Partner adapter not ready\n");
+	else if (rc != 0)
+		dev_warn(dev, "Couldn't register crq (rc=%d)\n", rc);
+
+	return rc;
+}
+
+static void ibmvnic_release_crq_queue(struct ibmvnic_adapter *adapter)
+{
+	struct ibmvnic_crq_queue *crq = &adapter->crq;
+	struct vio_dev *vdev = adapter->vdev;
+	long rc;
+
+	netdev_dbg(adapter->netdev, "Releasing CRQ\n");
+	free_irq(vdev->irq, adapter);
+	do {
+		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	dma_unmap_single(&vdev->dev, crq->msg_token, PAGE_SIZE,
+			 DMA_BIDIRECTIONAL);
+	free_page((unsigned long)crq->msgs);
+}
+
+static int ibmvnic_init_crq_queue(struct ibmvnic_adapter *adapter)
+{
+	struct ibmvnic_crq_queue *crq = &adapter->crq;
+	struct device *dev = &adapter->vdev->dev;
+	struct vio_dev *vdev = adapter->vdev;
+	int rc, retrc = -ENOMEM;
+
+	crq->msgs = (union ibmvnic_crq *)get_zeroed_page(GFP_KERNEL);
+	/* Should we allocate more than one page? */
+
+	if (!crq->msgs)
+		return -ENOMEM;
+
+	crq->size = PAGE_SIZE / sizeof(*crq->msgs);
+	crq->msg_token = dma_map_single(dev, crq->msgs, PAGE_SIZE,
+					DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, crq->msg_token))
+		goto map_failed;
+
+	rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
+				crq->msg_token, PAGE_SIZE);
+
+	if (rc == H_RESOURCE)
+		/* maybe kexecing and resource is busy. try a reset */
+		rc = ibmvnic_reset_crq(adapter);
+	retrc = rc;
+
+	if (rc == H_CLOSED) {
+		dev_warn(dev, "Partner adapter not ready\n");
+	} else if (rc) {
+		dev_warn(dev, "Error %d opening adapter\n", rc);
+		goto reg_crq_failed;
+	}
+
+	retrc = 0;
+
+	netdev_dbg(adapter->netdev, "registering irq 0x%x\n", vdev->irq);
+	rc = request_irq(vdev->irq, ibmvnic_interrupt, 0, IBMVNIC_NAME,
+			 adapter);
+	if (rc) {
+		dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n",
+			vdev->irq, rc);
+		goto req_irq_failed;
+	}
+
+	rc = vio_enable_interrupts(vdev);
+	if (rc) {
+		dev_err(dev, "Error %d enabling interrupts\n", rc);
+		goto req_irq_failed;
+	}
+
+	crq->cur = 0;
+	spin_lock_init(&crq->lock);
+
+	return retrc;
+
+req_irq_failed:
+	do {
+		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+reg_crq_failed:
+	dma_unmap_single(dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL);
+map_failed:
+	free_page((unsigned long)crq->msgs);
+	return retrc;
+}
+
+/* debugfs for dump */
+static int ibmvnic_dump_show(struct seq_file *seq, void *v)
+{
+	struct net_device *netdev = seq->private;
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	struct device *dev = &adapter->vdev->dev;
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.request_dump_size.first = IBMVNIC_CRQ_CMD;
+	crq.request_dump_size.cmd = REQUEST_DUMP_SIZE;
+	ibmvnic_send_crq(adapter, &crq);
+
+	init_completion(&adapter->fw_done);
+	wait_for_completion(&adapter->fw_done);
+
+	seq_write(seq, adapter->dump_data, adapter->dump_data_size);
+
+	dma_unmap_single(dev, adapter->dump_data_token, adapter->dump_data_size,
+			 DMA_BIDIRECTIONAL);
+
+	kfree(adapter->dump_data);
+
+	return 0;
+}
+
+static int ibmvnic_dump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ibmvnic_dump_show, inode->i_private);
+}
+
+static const struct file_operations ibmvnic_dump_ops = {
+	.owner          = THIS_MODULE,
+	.open           = ibmvnic_dump_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release        = single_release,
+};
+
+static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+{
+	struct ibmvnic_adapter *adapter;
+	struct net_device *netdev;
+	unsigned char *mac_addr_p;
+	struct dentry *ent;
+	char buf[16]; /* debugfs name buf */
+	int rc;
+
+	dev_dbg(&dev->dev, "entering ibmvnic_probe for UA 0x%x\n",
+		dev->unit_address);
+
+	mac_addr_p = (unsigned char *)vio_get_attribute(dev,
+							VETH_MAC_ADDR, NULL);
+	if (!mac_addr_p) {
+		dev_err(&dev->dev,
+			"(%s:%3.3d) ERROR: Can't find MAC_ADDR attribute\n",
+			__FILE__, __LINE__);
+		return 0;
+	}
+
+	netdev = alloc_etherdev_mq(sizeof(struct ibmvnic_adapter),
+				   IBMVNIC_MAX_TX_QUEUES);
+	if (!netdev)
+		return -ENOMEM;
+
+	adapter = netdev_priv(netdev);
+	dev_set_drvdata(&dev->dev, netdev);
+	adapter->vdev = dev;
+	adapter->netdev = netdev;
+
+	ether_addr_copy(adapter->mac_addr, mac_addr_p);
+	ether_addr_copy(netdev->dev_addr, adapter->mac_addr);
+	netdev->irq = dev->irq;
+	netdev->netdev_ops = &ibmvnic_netdev_ops;
+	netdev->ethtool_ops = &ibmvnic_ethtool_ops;
+	SET_NETDEV_DEV(netdev, &dev->dev);
+
+	spin_lock_init(&adapter->stats_lock);
+
+	rc = ibmvnic_init_crq_queue(adapter);
+	if (rc) {
+		dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n", rc);
+		goto free_netdev;
+	}
+
+	INIT_LIST_HEAD(&adapter->errors);
+	INIT_LIST_HEAD(&adapter->inflight);
+	spin_lock_init(&adapter->error_list_lock);
+	spin_lock_init(&adapter->inflight_lock);
+
+	adapter->stats_token = dma_map_single(&dev->dev, &adapter->stats,
+					      sizeof(struct ibmvnic_statistics),
+					      DMA_FROM_DEVICE);
+	if (dma_mapping_error(&dev->dev, adapter->stats_token)) {
+		if (!firmware_has_feature(FW_FEATURE_CMO))
+			dev_err(&dev->dev, "Couldn't map stats buffer\n");
+		goto free_crq;
+	}
+
+	snprintf(buf, sizeof(buf), "ibmvnic_%x", dev->unit_address);
+	ent = debugfs_create_dir(buf, NULL);
+	if (!ent || IS_ERR(ent)) {
+		dev_info(&dev->dev, "debugfs create directory failed\n");
+		adapter->debugfs_dir = NULL;
+	} else {
+		adapter->debugfs_dir = ent;
+		ent = debugfs_create_file("dump", S_IRUGO, adapter->debugfs_dir,
+					  netdev, &ibmvnic_dump_ops);
+		if (!ent || IS_ERR(ent)) {
+			dev_info(&dev->dev,
+				 "debugfs create dump file failed\n");
+			adapter->debugfs_dump = NULL;
+		} else {
+			adapter->debugfs_dump = ent;
+		}
+	}
+	ibmvnic_send_crq_init(adapter);
+
+	init_completion(&adapter->init_done);
+	wait_for_completion(&adapter->init_done);
+
+	/* needed to pull init_sub_crqs outside of an interrupt context
+	 * because it creates IRQ mappings for the subCRQ queues, causing
+	 * a kernel warning
+	 */
+	init_sub_crqs(adapter, 0);
+
+	reinit_completion(&adapter->init_done);
+	wait_for_completion(&adapter->init_done);
+
+	/* if init_sub_crqs is partially successful, retry */
+	while (!adapter->tx_scrq || !adapter->rx_scrq) {
+		init_sub_crqs(adapter, 1);
+
+		reinit_completion(&adapter->init_done);
+		wait_for_completion(&adapter->init_done);
+	}
+
+	netdev->real_num_tx_queues = adapter->req_tx_queues;
+
+	rc = register_netdev(netdev);
+	if (rc) {
+		dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc);
+		goto free_debugfs;
+	}
+	dev_info(&dev->dev, "ibmvnic registered\n");
+
+	return 0;
+
+free_debugfs:
+	if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
+		debugfs_remove_recursive(adapter->debugfs_dir);
+free_crq:
+	ibmvnic_release_crq_queue(adapter);
+free_netdev:
+	free_netdev(netdev);
+	return rc;
+}
+
+static int ibmvnic_remove(struct vio_dev *dev)
+{
+	struct net_device *netdev = dev_get_drvdata(&dev->dev);
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+	unregister_netdev(netdev);
+
+	release_sub_crqs(adapter);
+
+	ibmvnic_release_crq_queue(adapter);
+
+	if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
+		debugfs_remove_recursive(adapter->debugfs_dir);
+
+	if (adapter->ras_comps)
+		dma_free_coherent(&dev->dev,
+				  adapter->ras_comp_num *
+				  sizeof(struct ibmvnic_fw_component),
+				  adapter->ras_comps, adapter->ras_comps_tok);
+
+	kfree(adapter->ras_comp_int);
+
+	free_netdev(netdev);
+	dev_set_drvdata(&dev->dev, NULL);
+
+	return 0;
+}
+
+static unsigned long ibmvnic_get_desired_dma(struct vio_dev *vdev)
+{
+	struct net_device *netdev = dev_get_drvdata(&vdev->dev);
+	struct ibmvnic_adapter *adapter;
+	struct iommu_table *tbl;
+	unsigned long ret = 0;
+	int i;
+
+	tbl = get_iommu_table_base(&vdev->dev);
+
+	/* netdev inits at probe time along with the structures we need below*/
+	if (!netdev)
+		return IOMMU_PAGE_ALIGN(IBMVNIC_IO_ENTITLEMENT_DEFAULT, tbl);
+
+	adapter = netdev_priv(netdev);
+
+	ret += PAGE_SIZE; /* the crq message queue */
+	ret += adapter->bounce_buffer_size;
+	ret += IOMMU_PAGE_ALIGN(sizeof(struct ibmvnic_statistics), tbl);
+
+	for (i = 0; i < adapter->req_tx_queues + adapter->req_rx_queues; i++)
+		ret += 4 * PAGE_SIZE; /* the scrq message queue */
+
+	for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+	     i++)
+		ret += adapter->rx_pool[i].size *
+		    IOMMU_PAGE_ALIGN(adapter->rx_pool[i].buff_size, tbl);
+
+	return ret;
+}
+
+static int ibmvnic_resume(struct device *dev)
+{
+	struct net_device *netdev = dev_get_drvdata(dev);
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	int i;
+
+	/* kick the interrupt handlers just in case we lost an interrupt */
+	for (i = 0; i < adapter->req_rx_queues; i++)
+		ibmvnic_interrupt_rx(adapter->rx_scrq[i]->irq,
+				     adapter->rx_scrq[i]);
+
+	return 0;
+}
+
+static struct vio_device_id ibmvnic_device_table[] = {
+	{"network", "IBM,vnic"},
+	{"", "" }
+};
+MODULE_DEVICE_TABLE(vio, ibmvnic_device_table);
+
+static const struct dev_pm_ops ibmvnic_pm_ops = {
+	.resume = ibmvnic_resume
+};
+
+static struct vio_driver ibmvnic_driver = {
+	.id_table       = ibmvnic_device_table,
+	.probe          = ibmvnic_probe,
+	.remove         = ibmvnic_remove,
+	.get_desired_dma = ibmvnic_get_desired_dma,
+	.name		= ibmvnic_driver_name,
+	.pm		= &ibmvnic_pm_ops,
+};
+
+/* module functions */
+static int __init ibmvnic_module_init(void)
+{
+	pr_info("%s: %s %s\n", ibmvnic_driver_name, ibmvnic_driver_string,
+		IBMVNIC_DRIVER_VERSION);
+
+	return vio_register_driver(&ibmvnic_driver);
+}
+
+static void __exit ibmvnic_module_exit(void)
+{
+	vio_unregister_driver(&ibmvnic_driver);
+}
+
+module_init(ibmvnic_module_init);
+module_exit(ibmvnic_module_exit);
--- linux-4.4.0.orig/drivers/net/ethernet/ibm/ibmvnic.h
+++ linux-4.4.0/drivers/net/ethernet/ibm/ibmvnic.h
@@ -0,0 +1,1046 @@
+/**************************************************************************/
+/*                                                                        */
+/*  IBM System i and System p Virtual NIC Device Driver                   */
+/*  Copyright (C) 2014 IBM Corp.                                          */
+/*  Santiago Leon (santi_leon@yahoo.com)                                  */
+/*  Thomas Falcon (tlfalcon@linux.vnet.ibm.com)                           */
+/*  John Allen (jallen@linux.vnet.ibm.com)                                */
+/*                                                                        */
+/*  This program is free software; you can redistribute it and/or modify  */
+/*  it under the terms of the GNU General Public License as published by  */
+/*  the Free Software Foundation; either version 2 of the License, or     */
+/*  (at your option) any later version.                                   */
+/*                                                                        */
+/*  This program is distributed in the hope that it will be useful,       */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*  GNU General Public License for more details.                          */
+/*                                                                        */
+/*  You should have received a copy of the GNU General Public License     */
+/*  along with this program.                                              */
+/*                                                                        */
+/* This module contains the implementation of a virtual ethernet device   */
+/* for use with IBM i/pSeries LPAR Linux.  It utilizes the logical LAN    */
+/* option of the RS/6000 Platform Architecture to interface with virtual */
+/* ethernet NICs that are presented to the partition by the hypervisor.   */
+/*                                                                        */
+/**************************************************************************/
+
+#define IBMVNIC_NAME		"ibmvnic"
+#define IBMVNIC_DRIVER_VERSION	"1.0"
+#define IBMVNIC_INVALID_MAP	-1
+#define IBMVNIC_STATS_TIMEOUT	1
+/* basic structures plus 100 2k buffers */
+#define IBMVNIC_IO_ENTITLEMENT_DEFAULT	610305
+
+/* Initial module_parameters */
+#define IBMVNIC_RX_WEIGHT		16
+/* when changing this, update IBMVNIC_IO_ENTITLEMENT_DEFAULT */
+#define IBMVNIC_BUFFS_PER_POOL	100
+#define IBMVNIC_MAX_TX_QUEUES	5
+
+struct ibmvnic_login_buffer {
+	__be32 len;
+	__be32 version;
+#define INITIAL_VERSION_LB 1
+	__be32 num_txcomp_subcrqs;
+	__be32 off_txcomp_subcrqs;
+	__be32 num_rxcomp_subcrqs;
+	__be32 off_rxcomp_subcrqs;
+	__be32 login_rsp_ioba;
+	__be32 login_rsp_len;
+} __packed __aligned(8);
+
+struct ibmvnic_login_rsp_buffer {
+	__be32 len;
+	__be32 version;
+#define INITIAL_VERSION_LRB 1
+	__be32 num_txsubm_subcrqs;
+	__be32 off_txsubm_subcrqs;
+	__be32 num_rxadd_subcrqs;
+	__be32 off_rxadd_subcrqs;
+	__be32 off_rxadd_buff_size;
+	__be32 num_supp_tx_desc;
+	__be32 off_supp_tx_desc;
+} __packed __aligned(8);
+
+struct ibmvnic_query_ip_offload_buffer {
+	__be32 len;
+	__be32 version;
+#define INITIAL_VERSION_IOB 1
+	u8 ipv4_chksum;
+	u8 ipv6_chksum;
+	u8 tcp_ipv4_chksum;
+	u8 tcp_ipv6_chksum;
+	u8 udp_ipv4_chksum;
+	u8 udp_ipv6_chksum;
+	u8 large_tx_ipv4;
+	u8 large_tx_ipv6;
+	u8 large_rx_ipv4;
+	u8 large_rx_ipv6;
+	u8 reserved1[14];
+	__be16 max_ipv4_header_size;
+	__be16 max_ipv6_header_size;
+	__be16 max_tcp_header_size;
+	__be16 max_udp_header_size;
+	__be32 max_large_tx_size;
+	__be32 max_large_rx_size;
+	u8 reserved2[16];
+	u8 ipv6_extension_header;
+#define IPV6_EH_NOT_SUPPORTED	0x00
+#define IPV6_EH_SUPPORTED_LIM	0x01
+#define IPV6_EH_SUPPORTED	0xFF
+	u8 tcp_pseudosum_req;
+#define TCP_PS_NOT_REQUIRED	0x00
+#define TCP_PS_REQUIRED		0x01
+	u8 reserved3[30];
+	__be16 num_ipv6_ext_headers;
+	__be32 off_ipv6_ext_headers;
+	u8 reserved4[154];
+} __packed __aligned(8);
+
+struct ibmvnic_control_ip_offload_buffer {
+	__be32 len;
+	__be32 version;
+#define INITIAL_VERSION_IOB 1
+	u8 ipv4_chksum;
+	u8 ipv6_chksum;
+	u8 tcp_ipv4_chksum;
+	u8 tcp_ipv6_chksum;
+	u8 udp_ipv4_chksum;
+	u8 udp_ipv6_chksum;
+	u8 large_tx_ipv4;
+	u8 large_tx_ipv6;
+	u8 bad_packet_rx;
+	u8 large_rx_ipv4;
+	u8 large_rx_ipv6;
+	u8 reserved4[111];
+} __packed __aligned(8);
+
+struct ibmvnic_fw_component {
+	u8 name[48];
+	__be32 trace_buff_size;
+	u8 correlator;
+	u8 trace_level;
+	u8 parent_correlator;
+	u8 error_check_level;
+	u8 trace_on;
+	u8 reserved[7];
+	u8 description[192];
+} __packed __aligned(8);
+
+struct ibmvnic_fw_trace_entry {
+	__be32 trace_id;
+	u8 num_valid_data;
+	u8 reserved[3];
+	__be64 pmc_registers;
+	__be64 timebase;
+	__be64 trace_data[5];
+} __packed __aligned(8);
+
+struct ibmvnic_statistics {
+	__be32 version;
+	__be32 promiscuous;
+	__be64 rx_packets;
+	__be64 rx_bytes;
+	__be64 tx_packets;
+	__be64 tx_bytes;
+	__be64 ucast_tx_packets;
+	__be64 ucast_rx_packets;
+	__be64 mcast_tx_packets;
+	__be64 mcast_rx_packets;
+	__be64 bcast_tx_packets;
+	__be64 bcast_rx_packets;
+	__be64 align_errors;
+	__be64 fcs_errors;
+	__be64 single_collision_frames;
+	__be64 multi_collision_frames;
+	__be64 sqe_test_errors;
+	__be64 deferred_tx;
+	__be64 late_collisions;
+	__be64 excess_collisions;
+	__be64 internal_mac_tx_errors;
+	__be64 carrier_sense;
+	__be64 too_long_frames;
+	__be64 internal_mac_rx_errors;
+	u8 reserved[72];
+} __packed __aligned(8);
+
+struct ibmvnic_acl_buffer {
+	__be32 len;
+	__be32 version;
+#define INITIAL_VERSION_IOB 1
+	u8 mac_acls_restrict;
+	u8 vlan_acls_restrict;
+	u8 reserved1[22];
+	__be32 num_mac_addrs;
+	__be32 offset_mac_addrs;
+	__be32 num_vlan_ids;
+	__be32 offset_vlan_ids;
+	u8 reserved2[80];
+} __packed __aligned(8);
+
+/* descriptors have been changed, how should this be defined?  1? 4? */
+
+#define IBMVNIC_TX_DESC_VERSIONS 3
+
+/* is this still needed? */
+struct ibmvnic_tx_comp_desc {
+	u8 first;
+	u8 num_comps;
+	__be16 rcs[5];
+	__be32 correlators[5];
+} __packed __aligned(8);
+
+/* some flags that included in v0 descriptor, which is gone
+ * only used for IBMVNIC_TCP_CHKSUM and IBMVNIC_UDP_CHKSUM
+ * and only in some offload_flags variable that doesn't seem
+ * to be used anywhere, can probably be removed?
+ */
+
+#define IBMVNIC_TCP_CHKSUM		0x20
+#define IBMVNIC_UDP_CHKSUM		0x08
+
+#define IBMVNIC_MAX_FRAGS_PER_CRQ 3
+
+struct ibmvnic_tx_desc {
+	u8 first;
+	u8 type;
+
+#define IBMVNIC_TX_DESC 0x10
+	u8 n_crq_elem;
+	u8 n_sge;
+	u8 flags1;
+#define IBMVNIC_TX_COMP_NEEDED		0x80
+#define IBMVNIC_TX_CHKSUM_OFFLOAD	0x40
+#define IBMVNIC_TX_LSO			0x20
+#define IBMVNIC_TX_PROT_TCP		0x10
+#define IBMVNIC_TX_PROT_UDP		0x08
+#define IBMVNIC_TX_PROT_IPV4		0x04
+#define IBMVNIC_TX_PROT_IPV6		0x02
+#define IBMVNIC_TX_VLAN_PRESENT		0x01
+	u8 flags2;
+#define IBMVNIC_TX_VLAN_INSERT		0x80
+	__be16 mss;
+	u8 reserved[4];
+	__be32 correlator;
+	__be16 vlan_id;
+	__be16 dma_reg;
+	__be32 sge_len;
+	__be64 ioba;
+} __packed __aligned(8);
+
+struct ibmvnic_hdr_desc {
+	u8 first;
+	u8 type;
+#define IBMVNIC_HDR_DESC		0x11
+	u8 len;
+	u8 l2_len;
+	__be16 l3_len;
+	u8 l4_len;
+	u8 flag;
+	u8 data[24];
+} __packed __aligned(8);
+
+struct ibmvnic_hdr_ext_desc {
+	u8 first;
+	u8 type;
+#define IBMVNIC_HDR_EXT_DESC		0x12
+	u8 len;
+	u8 data[29];
+} __packed __aligned(8);
+
+struct ibmvnic_sge_desc {
+	u8 first;
+	u8 type;
+#define IBMVNIC_SGE_DESC		0x30
+	__be16 sge1_dma_reg;
+	__be32 sge1_len;
+	__be64 sge1_ioba;
+	__be16 reserved;
+	__be16 sge2_dma_reg;
+	__be32 sge2_len;
+	__be64 sge2_ioba;
+} __packed __aligned(8);
+
+struct ibmvnic_rx_comp_desc {
+	u8 first;
+	u8 flags;
+#define IBMVNIC_IP_CHKSUM_GOOD		0x80
+#define IBMVNIC_TCP_UDP_CHKSUM_GOOD	0x40
+#define IBMVNIC_END_FRAME			0x20
+#define IBMVNIC_EXACT_MC			0x10
+#define IBMVNIC_VLAN_STRIPPED			0x08
+	__be16 off_frame_data;
+	__be32 len;
+	__be64 correlator;
+	__be16 vlan_tci;
+	__be16 rc;
+	u8 reserved[12];
+} __packed __aligned(8);
+
+struct ibmvnic_generic_scrq {
+	u8 first;
+	u8 reserved[31];
+} __packed __aligned(8);
+
+struct ibmvnic_rx_buff_add_desc {
+	u8 first;
+	u8 reserved[7];
+	__be64 correlator;
+	__be32 ioba;
+	u8 map_id;
+	__be32 len:24;
+	u8 reserved2[8];
+} __packed __aligned(8);
+
+struct ibmvnic_rc {
+	u8 code; /* one of enum ibmvnic_rc_codes */
+	u8 detailed_data[3];
+} __packed __aligned(4);
+
+struct ibmvnic_generic_crq {
+	u8 first;
+	u8 cmd;
+	u8 params[10];
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_version_exchange {
+	u8 first;
+	u8 cmd;
+	__be16 version;
+#define IBMVNIC_INITIAL_VERSION 1
+	u8 reserved[8];
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_capability {
+	u8 first;
+	u8 cmd;
+	__be16 capability; /* one of ibmvnic_capabilities */
+	struct ibmvnic_rc rc;
+	__be32 number; /*FIX: should be __be64, but I'm getting the least
+			* significant word first
+			*/
+} __packed __aligned(8);
+
+struct ibmvnic_login {
+	u8 first;
+	u8 cmd;
+	u8 reserved[6];
+	__be32 ioba;
+	__be32 len;
+} __packed __aligned(8);
+
+struct ibmvnic_phys_parms {
+	u8 first;
+	u8 cmd;
+	u8 flags1;
+#define IBMVNIC_EXTERNAL_LOOPBACK	0x80
+#define IBMVNIC_INTERNAL_LOOPBACK	0x40
+#define IBMVNIC_PROMISC		0x20
+#define IBMVNIC_PHYS_LINK_ACTIVE	0x10
+#define IBMVNIC_AUTONEG_DUPLEX	0x08
+#define IBMVNIC_FULL_DUPLEX	0x04
+#define IBMVNIC_HALF_DUPLEX	0x02
+#define IBMVNIC_CAN_CHG_PHYS_PARMS	0x01
+	u8 flags2;
+#define IBMVNIC_LOGICAL_LNK_ACTIVE 0x80
+	__be32 speed;
+#define IBMVNIC_AUTONEG		0x80
+#define IBMVNIC_10MBPS		0x40
+#define IBMVNIC_100MBPS		0x20
+#define IBMVNIC_1GBPS		0x10
+#define IBMVNIC_10GBPS		0x08
+	__be32 mtu;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_logical_link_state {
+	u8 first;
+	u8 cmd;
+	u8 link_state;
+#define IBMVNIC_LOGICAL_LNK_DN 0x00
+#define IBMVNIC_LOGICAL_LNK_UP 0x01
+#define IBMVNIC_LOGICAL_LNK_QUERY 0xff
+	u8 reserved[9];
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_query_ip_offload {
+	u8 first;
+	u8 cmd;
+	u8 reserved[2];
+	__be32 len;
+	__be32 ioba;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_control_ip_offload {
+	u8 first;
+	u8 cmd;
+	u8 reserved[2];
+	__be32 ioba;
+	__be32 len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_request_dump_size {
+	u8 first;
+	u8 cmd;
+	u8 reserved[6];
+	__be32 len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_request_dump {
+	u8 first;
+	u8 cmd;
+	u8 reserved1[2];
+	__be32 ioba;
+	__be32 len;
+	u8 reserved2[4];
+} __packed __aligned(8);
+
+struct ibmvnic_request_dump_rsp {
+	u8 first;
+	u8 cmd;
+	u8 reserved[6];
+	__be32 dumped_len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_request_ras_comp_num {
+	u8 first;
+	u8 cmd;
+	u8 reserved1[2];
+	__be32 num_components;
+	u8 reserved2[4];
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_request_ras_comps {
+	u8 first;
+	u8 cmd;
+	u8 reserved[2];
+	__be32 ioba;
+	__be32 len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_control_ras {
+	u8 first;
+	u8 cmd;
+	u8 correlator;
+	u8 level;
+	u8 op;
+#define IBMVNIC_TRACE_LEVEL	1
+#define IBMVNIC_ERROR_LEVEL	2
+#define IBMVNIC_TRACE_PAUSE	3
+#define IBMVNIC_TRACE_RESUME	4
+#define IBMVNIC_TRACE_ON		5
+#define IBMVNIC_TRACE_OFF		6
+#define IBMVNIC_CHG_TRACE_BUFF_SZ	7
+	u8 trace_buff_sz[3];
+	u8 reserved[4];
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_collect_fw_trace {
+	u8 first;
+	u8 cmd;
+	u8 correlator;
+	u8 reserved;
+	__be32 ioba;
+	__be32 len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_request_statistics {
+	u8 first;
+	u8 cmd;
+	u8 flags;
+#define IBMVNIC_PHYSICAL_PORT	0x80
+	u8 reserved1;
+	__be32 ioba;
+	__be32 len;
+	u8 reserved[4];
+} __packed __aligned(8);
+
+struct ibmvnic_request_debug_stats {
+	u8 first;
+	u8 cmd;
+	u8 reserved[2];
+	__be32 ioba;
+	__be32 len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_error_indication {
+	u8 first;
+	u8 cmd;
+	u8 flags;
+#define IBMVNIC_FATAL_ERROR	0x80
+	u8 reserved1;
+	__be32 error_id;
+	__be32 detail_error_sz;
+	__be16 error_cause;
+	u8 reserved2[2];
+} __packed __aligned(8);
+
+struct ibmvnic_request_error_info {
+	u8 first;
+	u8 cmd;
+	u8 reserved[2];
+	__be32 ioba;
+	__be32 len;
+	__be32 error_id;
+} __packed __aligned(8);
+
+struct ibmvnic_request_error_rsp {
+	u8 first;
+	u8 cmd;
+	u8 reserved[2];
+	__be32 error_id;
+	__be32 len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_link_state_indication {
+	u8 first;
+	u8 cmd;
+	u8 reserved1[2];
+	u8 phys_link_state;
+	u8 logical_link_state;
+	u8 reserved2[10];
+} __packed __aligned(8);
+
+struct ibmvnic_change_mac_addr {
+	u8 first;
+	u8 cmd;
+	u8 mac_addr[6];
+	struct ibmvnic_rc rc;
+	u8 reserved[4];
+} __packed __aligned(8);
+
+struct ibmvnic_multicast_ctrl {
+	u8 first;
+	u8 cmd;
+	u8 mac_addr[6];
+	u8 flags;
+#define IBMVNIC_ENABLE_MC		0x80
+#define IBMVNIC_DISABLE_MC		0x40
+#define IBMVNIC_ENABLE_ALL		0x20
+#define IBMVNIC_DISABLE_ALL	0x10
+	u8 reserved1;
+	__be16 reserved2; /* was num_enabled_mc_addr; */
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_get_vpd_size_rsp {
+	u8 first;
+	u8 cmd;
+	u8 reserved[2];
+	__be64 len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_get_vpd {
+	u8 first;
+	u8 cmd;
+	u8 reserved1[2];
+	__be32 ioba;
+	__be32 len;
+	u8 reserved[4];
+} __packed __aligned(8);
+
+struct ibmvnic_acl_change_indication {
+	u8 first;
+	u8 cmd;
+	__be16 change_type;
+#define IBMVNIC_MAC_ACL 0
+#define IBMVNIC_VLAN_ACL 1
+	u8 reserved[12];
+} __packed __aligned(8);
+
+struct ibmvnic_acl_query {
+	u8 first;
+	u8 cmd;
+	u8 reserved1[2];
+	__be32 ioba;
+	__be32 len;
+	u8 reserved2[4];
+} __packed __aligned(8);
+
+struct ibmvnic_tune {
+	u8 first;
+	u8 cmd;
+	u8 reserved1[2];
+	__be32 ioba;
+	__be32 len;
+	u8 reserved2[4];
+} __packed __aligned(8);
+
+struct ibmvnic_request_map {
+	u8 first;
+	u8 cmd;
+	u8 reserved1;
+	u8 map_id;
+	__be32 ioba;
+	__be32 len;
+	u8 reserved2[4];
+} __packed __aligned(8);
+
+struct ibmvnic_request_map_rsp {
+	u8 first;
+	u8 cmd;
+	u8 reserved1;
+	u8 map_id;
+	u8 reserved2[4];
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_request_unmap {
+	u8 first;
+	u8 cmd;
+	u8 reserved1;
+	u8 map_id;
+	u8 reserved2[12];
+} __packed __aligned(8);
+
+struct ibmvnic_request_unmap_rsp {
+	u8 first;
+	u8 cmd;
+	u8 reserved1;
+	u8 map_id;
+	u8 reserved2[8];
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+struct ibmvnic_query_map {
+	u8 first;
+	u8 cmd;
+	u8 reserved[14];
+} __packed __aligned(8);
+
+struct ibmvnic_query_map_rsp {
+	u8 first;
+	u8 cmd;
+	u8 reserved;
+	u8 page_size;
+	__be32 tot_pages;
+	__be32 free_pages;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
+union ibmvnic_crq {
+	struct ibmvnic_generic_crq generic;
+	struct ibmvnic_version_exchange version_exchange;
+	struct ibmvnic_version_exchange version_exchange_rsp;
+	struct ibmvnic_capability query_capability;
+	struct ibmvnic_capability query_capability_rsp;
+	struct ibmvnic_capability request_capability;
+	struct ibmvnic_capability request_capability_rsp;
+	struct ibmvnic_login login;
+	struct ibmvnic_generic_crq login_rsp;
+	struct ibmvnic_phys_parms query_phys_parms;
+	struct ibmvnic_phys_parms query_phys_parms_rsp;
+	struct ibmvnic_phys_parms query_phys_capabilities;
+	struct ibmvnic_phys_parms query_phys_capabilities_rsp;
+	struct ibmvnic_phys_parms set_phys_parms;
+	struct ibmvnic_phys_parms set_phys_parms_rsp;
+	struct ibmvnic_logical_link_state logical_link_state;
+	struct ibmvnic_logical_link_state logical_link_state_rsp;
+	struct ibmvnic_query_ip_offload query_ip_offload;
+	struct ibmvnic_query_ip_offload query_ip_offload_rsp;
+	struct ibmvnic_control_ip_offload control_ip_offload;
+	struct ibmvnic_control_ip_offload control_ip_offload_rsp;
+	struct ibmvnic_request_dump_size request_dump_size;
+	struct ibmvnic_request_dump_size request_dump_size_rsp;
+	struct ibmvnic_request_dump request_dump;
+	struct ibmvnic_request_dump_rsp request_dump_rsp;
+	struct ibmvnic_request_ras_comp_num request_ras_comp_num;
+	struct ibmvnic_request_ras_comp_num request_ras_comp_num_rsp;
+	struct ibmvnic_request_ras_comps request_ras_comps;
+	struct ibmvnic_request_ras_comps request_ras_comps_rsp;
+	struct ibmvnic_control_ras control_ras;
+	struct ibmvnic_control_ras control_ras_rsp;
+	struct ibmvnic_collect_fw_trace collect_fw_trace;
+	struct ibmvnic_collect_fw_trace collect_fw_trace_rsp;
+	struct ibmvnic_request_statistics request_statistics;
+	struct ibmvnic_generic_crq request_statistics_rsp;
+	struct ibmvnic_request_debug_stats request_debug_stats;
+	struct ibmvnic_request_debug_stats request_debug_stats_rsp;
+	struct ibmvnic_error_indication error_indication;
+	struct ibmvnic_request_error_info request_error_info;
+	struct ibmvnic_request_error_rsp request_error_rsp;
+	struct ibmvnic_link_state_indication link_state_indication;
+	struct ibmvnic_change_mac_addr change_mac_addr;
+	struct ibmvnic_change_mac_addr change_mac_addr_rsp;
+	struct ibmvnic_multicast_ctrl multicast_ctrl;
+	struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
+	struct ibmvnic_generic_crq get_vpd_size;
+	struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
+	struct ibmvnic_get_vpd get_vpd;
+	struct ibmvnic_generic_crq get_vpd_rsp;
+	struct ibmvnic_acl_change_indication acl_change_indication;
+	struct ibmvnic_acl_query acl_query;
+	struct ibmvnic_generic_crq acl_query_rsp;
+	struct ibmvnic_tune tune;
+	struct ibmvnic_generic_crq tune_rsp;
+	struct ibmvnic_request_map request_map;
+	struct ibmvnic_request_map_rsp request_map_rsp;
+	struct ibmvnic_request_unmap request_unmap;
+	struct ibmvnic_request_unmap_rsp request_unmap_rsp;
+	struct ibmvnic_query_map query_map;
+	struct ibmvnic_query_map_rsp query_map_rsp;
+};
+
+enum ibmvnic_rc_codes {
+	SUCCESS = 0,
+	PARTIALSUCCESS = 1,
+	PERMISSION = 2,
+	NOMEMORY = 3,
+	PARAMETER = 4,
+	UNKNOWNCOMMAND = 5,
+	ABORTED = 6,
+	INVALIDSTATE = 7,
+	INVALIDIOBA = 8,
+	INVALIDLENGTH = 9,
+	UNSUPPORTEDOPTION = 10,
+};
+
+enum ibmvnic_capabilities {
+	MIN_TX_QUEUES = 1,
+	MIN_RX_QUEUES = 2,
+	MIN_RX_ADD_QUEUES = 3,
+	MAX_TX_QUEUES = 4,
+	MAX_RX_QUEUES = 5,
+	MAX_RX_ADD_QUEUES = 6,
+	REQ_TX_QUEUES = 7,
+	REQ_RX_QUEUES = 8,
+	REQ_RX_ADD_QUEUES = 9,
+	MIN_TX_ENTRIES_PER_SUBCRQ = 10,
+	MIN_RX_ADD_ENTRIES_PER_SUBCRQ = 11,
+	MAX_TX_ENTRIES_PER_SUBCRQ = 12,
+	MAX_RX_ADD_ENTRIES_PER_SUBCRQ = 13,
+	REQ_TX_ENTRIES_PER_SUBCRQ = 14,
+	REQ_RX_ADD_ENTRIES_PER_SUBCRQ = 15,
+	TCP_IP_OFFLOAD = 16,
+	PROMISC_REQUESTED = 17,
+	PROMISC_SUPPORTED = 18,
+	MIN_MTU = 19,
+	MAX_MTU = 20,
+	REQ_MTU = 21,
+	MAX_MULTICAST_FILTERS = 22,
+	VLAN_HEADER_INSERTION = 23,
+	MAX_TX_SG_ENTRIES = 25,
+	RX_SG_SUPPORTED = 26,
+	RX_SG_REQUESTED = 27,
+	OPT_TX_COMP_SUB_QUEUES = 28,
+	OPT_RX_COMP_QUEUES = 29,
+	OPT_RX_BUFADD_Q_PER_RX_COMP_Q = 30,
+	OPT_TX_ENTRIES_PER_SUBCRQ = 31,
+	OPT_RXBA_ENTRIES_PER_SUBCRQ = 32,
+	TX_RX_DESC_REQ = 33,
+};
+
+enum ibmvnic_error_cause {
+	ADAPTER_PROBLEM = 0,
+	BUS_PROBLEM = 1,
+	FW_PROBLEM = 2,
+	DD_PROBLEM = 3,
+	EEH_RECOVERY = 4,
+	FW_UPDATED = 5,
+	LOW_MEMORY = 6,
+};
+
+enum ibmvnic_commands {
+	VERSION_EXCHANGE = 0x01,
+	VERSION_EXCHANGE_RSP = 0x81,
+	QUERY_CAPABILITY = 0x02,
+	QUERY_CAPABILITY_RSP = 0x82,
+	REQUEST_CAPABILITY = 0x03,
+	REQUEST_CAPABILITY_RSP = 0x83,
+	LOGIN = 0x04,
+	LOGIN_RSP = 0x84,
+	QUERY_PHYS_PARMS = 0x05,
+	QUERY_PHYS_PARMS_RSP = 0x85,
+	QUERY_PHYS_CAPABILITIES = 0x06,
+	QUERY_PHYS_CAPABILITIES_RSP = 0x86,
+	SET_PHYS_PARMS = 0x07,
+	SET_PHYS_PARMS_RSP = 0x87,
+	ERROR_INDICATION = 0x08,
+	REQUEST_ERROR_INFO = 0x09,
+	REQUEST_ERROR_RSP = 0x89,
+	REQUEST_DUMP_SIZE = 0x0A,
+	REQUEST_DUMP_SIZE_RSP = 0x8A,
+	REQUEST_DUMP = 0x0B,
+	REQUEST_DUMP_RSP = 0x8B,
+	LOGICAL_LINK_STATE = 0x0C,
+	LOGICAL_LINK_STATE_RSP = 0x8C,
+	REQUEST_STATISTICS = 0x0D,
+	REQUEST_STATISTICS_RSP = 0x8D,
+	REQUEST_RAS_COMP_NUM = 0x0E,
+	REQUEST_RAS_COMP_NUM_RSP = 0x8E,
+	REQUEST_RAS_COMPS = 0x0F,
+	REQUEST_RAS_COMPS_RSP = 0x8F,
+	CONTROL_RAS = 0x10,
+	CONTROL_RAS_RSP = 0x90,
+	COLLECT_FW_TRACE = 0x11,
+	COLLECT_FW_TRACE_RSP = 0x91,
+	LINK_STATE_INDICATION = 0x12,
+	CHANGE_MAC_ADDR = 0x13,
+	CHANGE_MAC_ADDR_RSP = 0x93,
+	MULTICAST_CTRL = 0x14,
+	MULTICAST_CTRL_RSP = 0x94,
+	GET_VPD_SIZE = 0x15,
+	GET_VPD_SIZE_RSP = 0x95,
+	GET_VPD = 0x16,
+	GET_VPD_RSP = 0x96,
+	TUNE = 0x17,
+	TUNE_RSP = 0x97,
+	QUERY_IP_OFFLOAD = 0x18,
+	QUERY_IP_OFFLOAD_RSP = 0x98,
+	CONTROL_IP_OFFLOAD = 0x19,
+	CONTROL_IP_OFFLOAD_RSP = 0x99,
+	ACL_CHANGE_INDICATION = 0x1A,
+	ACL_QUERY = 0x1B,
+	ACL_QUERY_RSP = 0x9B,
+	REQUEST_DEBUG_STATS = 0x1C,
+	REQUEST_DEBUG_STATS_RSP = 0x9C,
+	QUERY_MAP = 0x1D,
+	QUERY_MAP_RSP = 0x9D,
+	REQUEST_MAP = 0x1E,
+	REQUEST_MAP_RSP = 0x9E,
+	REQUEST_UNMAP = 0x1F,
+	REQUEST_UNMAP_RSP = 0x9F,
+	VLAN_CTRL = 0x20,
+	VLAN_CTRL_RSP = 0xA0,
+};
+
+enum ibmvnic_crq_type {
+	IBMVNIC_CRQ_CMD			= 0x80,
+	IBMVNIC_CRQ_CMD_RSP		= 0x80,
+	IBMVNIC_CRQ_INIT_CMD		= 0xC0,
+	IBMVNIC_CRQ_INIT_RSP		= 0xC0,
+	IBMVNIC_CRQ_XPORT_EVENT		= 0xFF,
+};
+
+enum ibmvfc_crq_format {
+	IBMVNIC_CRQ_INIT                 = 0x01,
+	IBMVNIC_CRQ_INIT_COMPLETE        = 0x02,
+	IBMVNIC_PARTITION_MIGRATED       = 0x06,
+};
+
+struct ibmvnic_crq_queue {
+	union ibmvnic_crq *msgs;
+	int size, cur;
+	dma_addr_t msg_token;
+	spinlock_t lock;
+};
+
+union sub_crq {
+	struct ibmvnic_generic_scrq generic;
+	struct ibmvnic_tx_comp_desc tx_comp;
+	struct ibmvnic_tx_desc v1;
+	struct ibmvnic_hdr_desc hdr;
+	struct ibmvnic_hdr_ext_desc hdr_ext;
+	struct ibmvnic_sge_desc sge;
+	struct ibmvnic_rx_comp_desc rx_comp;
+	struct ibmvnic_rx_buff_add_desc rx_add;
+};
+
+struct ibmvnic_sub_crq_queue {
+	union sub_crq *msgs;
+	int size, cur;
+	dma_addr_t msg_token;
+	unsigned long crq_num;
+	unsigned long hw_irq;
+	unsigned int irq;
+	unsigned int pool_index;
+	int scrq_num;
+	spinlock_t lock;
+	struct sk_buff *rx_skb_top;
+	struct ibmvnic_adapter *adapter;
+};
+
+struct ibmvnic_long_term_buff {
+	unsigned char *buff;
+	dma_addr_t addr;
+	u64 size;
+	u8 map_id;
+};
+
+struct ibmvnic_tx_buff {
+	struct sk_buff *skb;
+	dma_addr_t data_dma[IBMVNIC_MAX_FRAGS_PER_CRQ];
+	unsigned int data_len[IBMVNIC_MAX_FRAGS_PER_CRQ];
+	int index;
+	int pool_index;
+	bool last_frag;
+	bool used_bounce;
+};
+
+struct ibmvnic_tx_pool {
+	struct ibmvnic_tx_buff *tx_buff;
+	int *free_map;
+	int consumer_index;
+	int producer_index;
+	wait_queue_head_t ibmvnic_tx_comp_q;
+	struct task_struct *work_thread;
+	struct ibmvnic_long_term_buff long_term_buff;
+};
+
+struct ibmvnic_rx_buff {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	unsigned char *data;
+	int size;
+	int pool_index;
+};
+
+struct ibmvnic_rx_pool {
+	struct ibmvnic_rx_buff *rx_buff;
+	int size;
+	int index;
+	int buff_size;
+	atomic_t available;
+	int *free_map;
+	int next_free;
+	int next_alloc;
+	int active;
+	struct ibmvnic_long_term_buff long_term_buff;
+};
+
+struct ibmvnic_error_buff {
+	char *buff;
+	dma_addr_t dma;
+	int len;
+	struct list_head list;
+	__be32 error_id;
+};
+
+struct ibmvnic_fw_comp_internal {
+	struct ibmvnic_adapter *adapter;
+	int num;
+	struct debugfs_blob_wrapper desc_blob;
+	int paused;
+};
+
+struct ibmvnic_inflight_cmd {
+	union ibmvnic_crq crq;
+	struct list_head list;
+};
+
+struct ibmvnic_adapter {
+	struct vio_dev *vdev;
+	struct net_device *netdev;
+	struct ibmvnic_crq_queue crq;
+	u8 mac_addr[ETH_ALEN];
+	struct ibmvnic_query_ip_offload_buffer ip_offload_buf;
+	dma_addr_t ip_offload_tok;
+	struct ibmvnic_control_ip_offload_buffer ip_offload_ctrl;
+	dma_addr_t ip_offload_ctrl_tok;
+	bool migrated;
+	u32 msg_enable;
+	void *bounce_buffer;
+	int bounce_buffer_size;
+	dma_addr_t bounce_buffer_dma;
+
+	/* Statistics */
+	struct net_device_stats net_stats;
+	struct ibmvnic_statistics stats;
+	dma_addr_t stats_token;
+	struct completion stats_done;
+	spinlock_t stats_lock;
+	int replenish_no_mem;
+	int replenish_add_buff_success;
+	int replenish_add_buff_failure;
+	int replenish_task_cycles;
+	int tx_send_failed;
+	int tx_map_failed;
+
+	int phys_link_state;
+	int logical_link_state;
+
+	/* login data */
+	struct ibmvnic_login_buffer *login_buf;
+	dma_addr_t login_buf_token;
+	int login_buf_sz;
+
+	struct ibmvnic_login_rsp_buffer *login_rsp_buf;
+	dma_addr_t login_rsp_buf_token;
+	int login_rsp_buf_sz;
+
+	atomic_t running_cap_queries;
+
+	struct ibmvnic_sub_crq_queue **tx_scrq;
+	struct ibmvnic_sub_crq_queue **rx_scrq;
+	int requested_caps;
+
+	/* rx structs */
+	struct napi_struct *napi;
+	struct ibmvnic_rx_pool *rx_pool;
+	u64 promisc;
+
+	struct ibmvnic_tx_pool *tx_pool;
+	bool closing;
+	struct completion init_done;
+
+	struct list_head errors;
+	spinlock_t error_list_lock;
+
+	/* debugfs */
+	struct dentry *debugfs_dir;
+	struct dentry *debugfs_dump;
+	struct completion fw_done;
+	char *dump_data;
+	dma_addr_t dump_data_token;
+	int dump_data_size;
+	int ras_comp_num;
+	struct ibmvnic_fw_component *ras_comps;
+	struct ibmvnic_fw_comp_internal *ras_comp_int;
+	dma_addr_t ras_comps_tok;
+	struct dentry *ras_comps_ent;
+
+	/* in-flight commands that allocate and/or map memory*/
+	struct list_head inflight;
+	spinlock_t inflight_lock;
+
+	/* partner capabilities */
+	u64 min_tx_queues;
+	u64 min_rx_queues;
+	u64 min_rx_add_queues;
+	u64 max_tx_queues;
+	u64 max_rx_queues;
+	u64 max_rx_add_queues;
+	u64 req_tx_queues;
+	u64 req_rx_queues;
+	u64 req_rx_add_queues;
+	u64 min_tx_entries_per_subcrq;
+	u64 min_rx_add_entries_per_subcrq;
+	u64 max_tx_entries_per_subcrq;
+	u64 max_rx_add_entries_per_subcrq;
+	u64 req_tx_entries_per_subcrq;
+	u64 req_rx_add_entries_per_subcrq;
+	u64 tcp_ip_offload;
+	u64 promisc_requested;
+	u64 promisc_supported;
+	u64 min_mtu;
+	u64 max_mtu;
+	u64 req_mtu;
+	u64 max_multicast_filters;
+	u64 vlan_header_insertion;
+	u64 max_tx_sg_entries;
+	u64 rx_sg_supported;
+	u64 rx_sg_requested;
+	u64 opt_tx_comp_sub_queues;
+	u64 opt_rx_comp_queues;
+	u64 opt_rx_bufadd_q_per_rx_comp_q;
+	u64 opt_tx_entries_per_subcrq;
+	u64 opt_rxba_entries_per_subcrq;
+	__be64 tx_rx_desc_req;
+	u8 map_id;
+};
--- linux-4.4.0.orig/drivers/net/ethernet/intel/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/intel/Kconfig
@@ -83,6 +83,15 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called e1000e.
 
+config E1000E_HWTS
+	bool "Support HW cross-timestamp on PCH devices"
+	default y
+	depends on E1000E && X86
+	---help---
+	 Say Y to enable hardware supported cross-timestamping on PCH
+	 devices. The cross-timestamp is available through the PTP clock
+	 driver precise cross-timestamp ioctl (PTP_SYS_OFFSET_PRECISE).
+
 config IGB
 	tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
 	depends on PCI
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e100.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e100.c
@@ -1370,8 +1370,8 @@
 
 	fw = e100_request_firmware(nic);
 	/* If it's NULL, then no ucode is required */
-	if (!fw || IS_ERR(fw))
-		return PTR_ERR(fw);
+	if (IS_ERR_OR_NULL(fw))
+		return PTR_ERR_OR_ZERO(fw);
 
 	if ((err = e100_exec_cb(nic, (void *)fw, e100_setup_ucode)))
 		netif_err(nic, probe, nic->netdev,
@@ -1770,11 +1770,8 @@
 	dma_addr = pci_map_single(nic->pdev,
 				  skb->data, skb->len, PCI_DMA_TODEVICE);
 	/* If we can't map the skb, have the upper layer try later */
-	if (pci_dma_mapping_error(nic->pdev, dma_addr)) {
-		dev_kfree_skb_any(skb);
-		skb = NULL;
+	if (pci_dma_mapping_error(nic->pdev, dma_addr))
 		return -ENOMEM;
-	}
 
 	/*
 	 * Use the last 4 bytes of the SKB payload packet as the CRC, used for
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000/e1000.h
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000/e1000.h
@@ -213,8 +213,11 @@
 };
 
 #define E1000_DESC_UNUSED(R)						\
-	((((R)->next_to_clean > (R)->next_to_use)			\
-	  ? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
+({									\
+	unsigned int clean = smp_load_acquire(&(R)->next_to_clean);	\
+	unsigned int use = READ_ONCE((R)->next_to_use);			\
+	(clean > use ? 0 : (R)->count) + clean - use - 1;		\
+})
 
 #define E1000_RX_DESC_EXT(R, i)						\
 	(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
@@ -328,7 +331,8 @@
 enum e1000_state_t {
 	__E1000_TESTING,
 	__E1000_RESETTING,
-	__E1000_DOWN
+	__E1000_DOWN,
+	__E1000_DISABLED
 };
 
 #undef pr_fmt
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -628,6 +628,7 @@
 	for (i = 0; i < adapter->num_rx_queues; i++)
 		rxdr[i].count = rxdr->count;
 
+	err = 0;
 	if (netif_running(adapter->netdev)) {
 		/* Try to get new resources before deleting old */
 		err = e1000_setup_all_rx_resources(adapter);
@@ -645,17 +646,16 @@
 		adapter->tx_ring = tx_old;
 		e1000_free_all_rx_resources(adapter);
 		e1000_free_all_tx_resources(adapter);
-		kfree(tx_old);
-		kfree(rx_old);
 		adapter->rx_ring = rxdr;
 		adapter->tx_ring = txdr;
 		err = e1000_up(adapter);
-		if (err)
-			goto err_setup;
 	}
+	kfree(tx_old);
+	kfree(rx_old);
 
 	clear_bit(__E1000_RESETTING, &adapter->flags);
-	return 0;
+	return err;
+
 err_setup_tx:
 	e1000_free_all_rx_resources(adapter);
 err_setup_rx:
@@ -665,8 +665,8 @@
 err_alloc_rx:
 	kfree(txdr);
 err_alloc_tx:
-	e1000_up(adapter);
-err_setup:
+	if (netif_running(adapter->netdev))
+		e1000_up(adapter);
 	clear_bit(__E1000_RESETTING, &adapter->flags);
 	return err;
 }
@@ -1825,11 +1825,12 @@
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int i;
-	char *p = NULL;
 	const struct e1000_stats *stat = e1000_gstrings_stats;
 
 	e1000_update_stats(adapter);
-	for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
+	for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++, stat++) {
+		char *p;
+
 		switch (stat->type) {
 		case NETDEV_STATS:
 			p = (char *)netdev + stat->stat_offset;
@@ -1840,15 +1841,13 @@
 		default:
 			WARN_ONCE(1, "Invalid E1000 stat type: %u index %d\n",
 				  stat->type, i);
-			break;
+			continue;
 		}
 
 		if (stat->sizeof_stat == sizeof(u64))
 			data[i] = *(u64 *)p;
 		else
 			data[i] = *(u32 *)p;
-
-		stat++;
 	}
 /* BUG_ON(i != E1000_STATS_LEN); */
 }
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -1,5 +1,5 @@
 /*******************************************************************************
-
+*
   Intel PRO/1000 Linux driver
   Copyright(c) 1999 - 2006 Intel Corporation.
 
@@ -106,7 +106,7 @@
 	    120, 120
 };
 
-static DEFINE_SPINLOCK(e1000_eeprom_lock);
+static DEFINE_MUTEX(e1000_eeprom_lock);
 static DEFINE_SPINLOCK(e1000_phy_lock);
 
 /**
@@ -624,8 +624,8 @@
 		/* Workaround for PCI-X problem when BIOS sets MMRBC
 		 * incorrectly.
 		 */
-		if (hw->bus_type == e1000_bus_type_pcix
-		    && e1000_pcix_get_mmrbc(hw) > 2048)
+		if (hw->bus_type == e1000_bus_type_pcix &&
+		    e1000_pcix_get_mmrbc(hw) > 2048)
 			e1000_pcix_set_mmrbc(hw, 2048);
 		break;
 	}
@@ -683,10 +683,9 @@
 	}
 
 	ret_val = e1000_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1,
-	                            &eeprom_data);
-	if (ret_val) {
+				    &eeprom_data);
+	if (ret_val)
 		return ret_val;
-	}
 
 	if (eeprom_data != EEPROM_RESERVED_WORD) {
 		/* Adjust SERDES output amplitude only. */
@@ -1074,8 +1073,8 @@
 
 	if (hw->mac_type <= e1000_82543 ||
 	    hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
-	    hw->mac_type == e1000_82541_rev_2
-	    || hw->mac_type == e1000_82547_rev_2)
+	    hw->mac_type == e1000_82541_rev_2 ||
+	    hw->mac_type == e1000_82547_rev_2)
 		hw->phy_reset_disable = false;
 
 	return E1000_SUCCESS;
@@ -1652,7 +1651,7 @@
 		mii_1000t_ctrl_reg = 0;
 	} else {
 		ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
-		                              mii_1000t_ctrl_reg);
+					      mii_1000t_ctrl_reg);
 		if (ret_val)
 			return ret_val;
 	}
@@ -1881,10 +1880,11 @@
 		if (ret_val)
 			return ret_val;
 
-		if ((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543)
-		    && (!hw->autoneg)
-		    && (hw->forced_speed_duplex == e1000_10_full
-			|| hw->forced_speed_duplex == e1000_10_half)) {
+		if ((hw->mac_type == e1000_82544 ||
+		     hw->mac_type == e1000_82543) &&
+		    (!hw->autoneg) &&
+		    (hw->forced_speed_duplex == e1000_10_full ||
+		     hw->forced_speed_duplex == e1000_10_half)) {
 			ret_val = e1000_polarity_reversal_workaround(hw);
 			if (ret_val)
 				return ret_val;
@@ -2084,11 +2084,12 @@
 	 * so we had to force link.  In this case, we need to force the
 	 * configuration of the MAC to match the "fc" parameter.
 	 */
-	if (((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed))
-	    || ((hw->media_type == e1000_media_type_internal_serdes)
-		&& (hw->autoneg_failed))
-	    || ((hw->media_type == e1000_media_type_copper)
-		&& (!hw->autoneg))) {
+	if (((hw->media_type == e1000_media_type_fiber) &&
+	     (hw->autoneg_failed)) ||
+	    ((hw->media_type == e1000_media_type_internal_serdes) &&
+	     (hw->autoneg_failed)) ||
+	    ((hw->media_type == e1000_media_type_copper) &&
+	     (!hw->autoneg))) {
 		ret_val = e1000_force_mac_fc(hw);
 		if (ret_val) {
 			e_dbg("Error forcing flow control settings\n");
@@ -2193,8 +2194,7 @@
 			else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
 				 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
 				 (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-				 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR))
-			{
+				 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
 				hw->fc = E1000_FC_TX_PAUSE;
 				e_dbg
 				    ("Flow Control = TX PAUSE frames only.\n");
@@ -2210,8 +2210,7 @@
 			else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
 				 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
 				 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-				 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR))
-			{
+				 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
 				hw->fc = E1000_FC_RX_PAUSE;
 				e_dbg
 				    ("Flow Control = RX PAUSE frames only.\n");
@@ -2460,10 +2459,11 @@
 			 * happen due to the execution of this workaround.
 			 */
 
-			if ((hw->mac_type == e1000_82544
-			     || hw->mac_type == e1000_82543) && (!hw->autoneg)
-			    && (hw->forced_speed_duplex == e1000_10_full
-				|| hw->forced_speed_duplex == e1000_10_half)) {
+			if ((hw->mac_type == e1000_82544 ||
+			     hw->mac_type == e1000_82543) &&
+			    (!hw->autoneg) &&
+			    (hw->forced_speed_duplex == e1000_10_full ||
+			     hw->forced_speed_duplex == e1000_10_half)) {
 				ew32(IMC, 0xffffffff);
 				ret_val =
 				    e1000_polarity_reversal_workaround(hw);
@@ -2528,8 +2528,10 @@
 		 */
 		if (hw->tbi_compatibility_en) {
 			u16 speed, duplex;
+
 			ret_val =
 			    e1000_get_speed_and_duplex(hw, &speed, &duplex);
+
 			if (ret_val) {
 				e_dbg
 				    ("Error getting link speed and duplex\n");
@@ -2628,10 +2630,10 @@
 			    e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data);
 			if (ret_val)
 				return ret_val;
-			if ((*speed == SPEED_100
-			     && !(phy_data & NWAY_LPAR_100TX_FD_CAPS))
-			    || (*speed == SPEED_10
-				&& !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
+			if ((*speed == SPEED_100 &&
+			     !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
+			    (*speed == SPEED_10 &&
+			     !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
 				*duplex = HALF_DUPLEX;
 		}
 	}
@@ -2664,9 +2666,9 @@
 		ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
 		if (ret_val)
 			return ret_val;
-		if (phy_data & MII_SR_AUTONEG_COMPLETE) {
+		if (phy_data & MII_SR_AUTONEG_COMPLETE)
 			return E1000_SUCCESS;
-		}
+
 		msleep(100);
 	}
 	return E1000_SUCCESS;
@@ -2803,11 +2805,11 @@
 	return data;
 }
 
-
 /**
  * e1000_read_phy_reg - read a phy register
  * @hw: Struct containing variables accessed by shared code
  * @reg_addr: address of the PHY register to read
+ * @phy_data: pointer to the value on the PHY register
  *
  * Reads the value from a PHY register, if the value is on a specific non zero
  * page, sets the page first.
@@ -2823,14 +2825,13 @@
 	    (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
 		ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
 						 (u16) reg_addr);
-		if (ret_val) {
-			spin_unlock_irqrestore(&e1000_phy_lock, flags);
-			return ret_val;
-		}
+		if (ret_val)
+			goto out;
 	}
 
 	ret_val = e1000_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
 					phy_data);
+out:
 	spin_unlock_irqrestore(&e1000_phy_lock, flags);
 
 	return ret_val;
@@ -2881,7 +2882,7 @@
 				e_dbg("MDI Read Error\n");
 				return -E1000_ERR_PHY;
 			}
-			*phy_data = (u16) mdic;
+			*phy_data = (u16)mdic;
 		} else {
 			mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
 				(phy_addr << E1000_MDIC_PHY_SHIFT) |
@@ -2906,7 +2907,7 @@
 				e_dbg("MDI Error\n");
 				return -E1000_ERR_PHY;
 			}
-			*phy_data = (u16) mdic;
+			*phy_data = (u16)mdic;
 		}
 	} else {
 		/* We must first send a preamble through the MDIO pin to signal
@@ -2960,7 +2961,7 @@
 	if ((hw->phy_type == e1000_phy_igp) &&
 	    (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
 		ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
-						 (u16) reg_addr);
+						 (u16)reg_addr);
 		if (ret_val) {
 			spin_unlock_irqrestore(&e1000_phy_lock, flags);
 			return ret_val;
@@ -2993,7 +2994,7 @@
 		 * the desired data.
 		 */
 		if (hw->mac_type == e1000_ce4100) {
-			mdic = (((u32) phy_data) |
+			mdic = (((u32)phy_data) |
 				(reg_addr << E1000_MDIC_REG_SHIFT) |
 				(phy_addr << E1000_MDIC_PHY_SHIFT) |
 				(INTEL_CE_GBE_MDIC_OP_WRITE) |
@@ -3015,7 +3016,7 @@
 				return -E1000_ERR_PHY;
 			}
 		} else {
-			mdic = (((u32) phy_data) |
+			mdic = (((u32)phy_data) |
 				(reg_addr << E1000_MDIC_REG_SHIFT) |
 				(phy_addr << E1000_MDIC_PHY_SHIFT) |
 				(E1000_MDIC_OP_WRITE));
@@ -3053,7 +3054,7 @@
 		mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
 			(PHY_OP_WRITE << 12) | (PHY_SOF << 14));
 		mdic <<= 16;
-		mdic |= (u32) phy_data;
+		mdic |= (u32)phy_data;
 
 		e1000_shift_out_mdi_bits(hw, mdic, 32);
 	}
@@ -3176,14 +3177,14 @@
 	if (ret_val)
 		return ret_val;
 
-	hw->phy_id = (u32) (phy_id_high << 16);
+	hw->phy_id = (u32)(phy_id_high << 16);
 	udelay(20);
 	ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low);
 	if (ret_val)
 		return ret_val;
 
-	hw->phy_id |= (u32) (phy_id_low & PHY_REVISION_MASK);
-	hw->phy_revision = (u32) phy_id_low & ~PHY_REVISION_MASK;
+	hw->phy_id |= (u32)(phy_id_low & PHY_REVISION_MASK);
+	hw->phy_revision = (u32)phy_id_low & ~PHY_REVISION_MASK;
 
 	switch (hw->mac_type) {
 	case e1000_82543:
@@ -3401,7 +3402,6 @@
 		phy_info->remote_rx = ((phy_data & SR_1000T_REMOTE_RX_STATUS) >>
 				       SR_1000T_REMOTE_RX_STATUS_SHIFT) ?
 		    e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
-
 	}
 
 	return E1000_SUCCESS;
@@ -3449,7 +3449,7 @@
 	if (hw->phy_type == e1000_phy_igp)
 		return e1000_phy_igp_get_info(hw, phy_info);
 	else if ((hw->phy_type == e1000_phy_8211) ||
-	         (hw->phy_type == e1000_phy_8201))
+		 (hw->phy_type == e1000_phy_8201))
 		return E1000_SUCCESS;
 	else
 		return e1000_phy_m88_get_info(hw, phy_info);
@@ -3611,11 +3611,11 @@
 	 */
 	mask = 0x01 << (count - 1);
 	eecd = er32(EECD);
-	if (eeprom->type == e1000_eeprom_microwire) {
+	if (eeprom->type == e1000_eeprom_microwire)
 		eecd &= ~E1000_EECD_DO;
-	} else if (eeprom->type == e1000_eeprom_spi) {
+	else if (eeprom->type == e1000_eeprom_spi)
 		eecd |= E1000_EECD_DO;
-	}
+
 	do {
 		/* A "1" is shifted out to the EEPROM by setting bit "DI" to a
 		 * "1", and then raising and then lowering the clock (the SK bit
@@ -3851,7 +3851,7 @@
 	do {
 		e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
 					hw->eeprom.opcode_bits);
-		spi_stat_reg = (u8) e1000_shift_in_ee_bits(hw, 8);
+		spi_stat_reg = (u8)e1000_shift_in_ee_bits(hw, 8);
 		if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
 			break;
 
@@ -3882,9 +3882,10 @@
 s32 e1000_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 {
 	s32 ret;
-	spin_lock(&e1000_eeprom_lock);
+
+	mutex_lock(&e1000_eeprom_lock);
 	ret = e1000_do_read_eeprom(hw, offset, words, data);
-	spin_unlock(&e1000_eeprom_lock);
+	mutex_unlock(&e1000_eeprom_lock);
 	return ret;
 }
 
@@ -3896,15 +3897,16 @@
 
 	if (hw->mac_type == e1000_ce4100) {
 		GBE_CONFIG_FLASH_READ(GBE_CONFIG_BASE_VIRT, offset, words,
-		                      data);
+				      data);
 		return E1000_SUCCESS;
 	}
 
 	/* A check for invalid values:  offset too large, too many words, and
 	 * not enough words.
 	 */
-	if ((offset >= eeprom->word_size)
-	    || (words > eeprom->word_size - offset) || (words == 0)) {
+	if ((offset >= eeprom->word_size) ||
+	    (words > eeprom->word_size - offset) ||
+	    (words == 0)) {
 		e_dbg("\"words\" parameter out of bounds. Words = %d,"
 		      "size = %d\n", offset, eeprom->word_size);
 		return -E1000_ERR_EEPROM;
@@ -3940,7 +3942,7 @@
 
 		/* Send the READ command (opcode + addr)  */
 		e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
-		e1000_shift_out_ee_bits(hw, (u16) (offset * 2),
+		e1000_shift_out_ee_bits(hw, (u16)(offset * 2),
 					eeprom->address_bits);
 
 		/* Read the data.  The address of the eeprom internally
@@ -3960,7 +3962,7 @@
 			e1000_shift_out_ee_bits(hw,
 						EEPROM_READ_OPCODE_MICROWIRE,
 						eeprom->opcode_bits);
-			e1000_shift_out_ee_bits(hw, (u16) (offset + i),
+			e1000_shift_out_ee_bits(hw, (u16)(offset + i),
 						eeprom->address_bits);
 
 			/* Read the data.  For microwire, each word requires the
@@ -3968,6 +3970,7 @@
 			 */
 			data[i] = e1000_shift_in_ee_bits(hw, 16);
 			e1000_standby_eeprom(hw);
+			cond_resched();
 		}
 	}
 
@@ -4004,7 +4007,7 @@
 		return E1000_SUCCESS;
 
 #endif
-	if (checksum == (u16) EEPROM_SUM)
+	if (checksum == (u16)EEPROM_SUM)
 		return E1000_SUCCESS;
 	else {
 		e_dbg("EEPROM Checksum Invalid\n");
@@ -4031,7 +4034,7 @@
 		}
 		checksum += eeprom_data;
 	}
-	checksum = (u16) EEPROM_SUM - checksum;
+	checksum = (u16)EEPROM_SUM - checksum;
 	if (e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
 		e_dbg("EEPROM Write Error\n");
 		return -E1000_ERR_EEPROM;
@@ -4052,9 +4055,10 @@
 s32 e1000_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 {
 	s32 ret;
-	spin_lock(&e1000_eeprom_lock);
+
+	mutex_lock(&e1000_eeprom_lock);
 	ret = e1000_do_write_eeprom(hw, offset, words, data);
-	spin_unlock(&e1000_eeprom_lock);
+	mutex_unlock(&e1000_eeprom_lock);
 	return ret;
 }
 
@@ -4066,15 +4070,16 @@
 
 	if (hw->mac_type == e1000_ce4100) {
 		GBE_CONFIG_FLASH_WRITE(GBE_CONFIG_BASE_VIRT, offset, words,
-		                       data);
+				       data);
 		return E1000_SUCCESS;
 	}
 
 	/* A check for invalid values:  offset too large, too many words, and
 	 * not enough words.
 	 */
-	if ((offset >= eeprom->word_size)
-	    || (words > eeprom->word_size - offset) || (words == 0)) {
+	if ((offset >= eeprom->word_size) ||
+	    (words > eeprom->word_size - offset) ||
+	    (words == 0)) {
 		e_dbg("\"words\" parameter out of bounds\n");
 		return -E1000_ERR_EEPROM;
 	}
@@ -4116,6 +4121,7 @@
 			return -E1000_ERR_EEPROM;
 
 		e1000_standby_eeprom(hw);
+		cond_resched();
 
 		/*  Send the WRITE ENABLE command (8 bit opcode )  */
 		e1000_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI,
@@ -4132,7 +4138,7 @@
 		/* Send the Write command (8-bit opcode + addr) */
 		e1000_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits);
 
-		e1000_shift_out_ee_bits(hw, (u16) ((offset + widx) * 2),
+		e1000_shift_out_ee_bits(hw, (u16)((offset + widx) * 2),
 					eeprom->address_bits);
 
 		/* Send the data */
@@ -4142,6 +4148,7 @@
 		 */
 		while (widx < words) {
 			u16 word_out = data[widx];
+
 			word_out = (word_out >> 8) | (word_out << 8);
 			e1000_shift_out_ee_bits(hw, word_out, 16);
 			widx++;
@@ -4183,9 +4190,9 @@
 	 * EEPROM into write/erase mode.
 	 */
 	e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE,
-				(u16) (eeprom->opcode_bits + 2));
+				(u16)(eeprom->opcode_bits + 2));
 
-	e1000_shift_out_ee_bits(hw, 0, (u16) (eeprom->address_bits - 2));
+	e1000_shift_out_ee_bits(hw, 0, (u16)(eeprom->address_bits - 2));
 
 	/* Prepare the EEPROM */
 	e1000_standby_eeprom(hw);
@@ -4195,7 +4202,7 @@
 		e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE,
 					eeprom->opcode_bits);
 
-		e1000_shift_out_ee_bits(hw, (u16) (offset + words_written),
+		e1000_shift_out_ee_bits(hw, (u16)(offset + words_written),
 					eeprom->address_bits);
 
 		/* Send the data */
@@ -4224,6 +4231,7 @@
 
 		/* Recover from write */
 		e1000_standby_eeprom(hw);
+		cond_resched();
 
 		words_written++;
 	}
@@ -4235,9 +4243,9 @@
 	 * EEPROM out of write/erase mode.
 	 */
 	e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE,
-				(u16) (eeprom->opcode_bits + 2));
+				(u16)(eeprom->opcode_bits + 2));
 
-	e1000_shift_out_ee_bits(hw, 0, (u16) (eeprom->address_bits - 2));
+	e1000_shift_out_ee_bits(hw, 0, (u16)(eeprom->address_bits - 2));
 
 	return E1000_SUCCESS;
 }
@@ -4260,8 +4268,8 @@
 			e_dbg("EEPROM Read Error\n");
 			return -E1000_ERR_EEPROM;
 		}
-		hw->perm_mac_addr[i] = (u8) (eeprom_data & 0x00FF);
-		hw->perm_mac_addr[i + 1] = (u8) (eeprom_data >> 8);
+		hw->perm_mac_addr[i] = (u8)(eeprom_data & 0x00FF);
+		hw->perm_mac_addr[i + 1] = (u8)(eeprom_data >> 8);
 	}
 
 	switch (hw->mac_type) {
@@ -4328,19 +4336,19 @@
 		 */
 	case 0:
 		/* [47:36] i.e. 0x563 for above example address */
-		hash_value = ((mc_addr[4] >> 4) | (((u16) mc_addr[5]) << 4));
+		hash_value = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
 		break;
 	case 1:
 		/* [46:35] i.e. 0xAC6 for above example address */
-		hash_value = ((mc_addr[4] >> 3) | (((u16) mc_addr[5]) << 5));
+		hash_value = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
 		break;
 	case 2:
 		/* [45:34] i.e. 0x5D8 for above example address */
-		hash_value = ((mc_addr[4] >> 2) | (((u16) mc_addr[5]) << 6));
+		hash_value = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
 		break;
 	case 3:
 		/* [43:32] i.e. 0x634 for above example address */
-		hash_value = ((mc_addr[4]) | (((u16) mc_addr[5]) << 8));
+		hash_value = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
 		break;
 	}
 
@@ -4361,9 +4369,9 @@
 	/* HW expects these in little endian so we reverse the byte order
 	 * from network order (big endian) to little endian
 	 */
-	rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
-		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
-	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+	rar_low = ((u32)addr[0] | ((u32)addr[1] << 8) |
+		   ((u32)addr[2] << 16) | ((u32)addr[3] << 24));
+	rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
 
 	/* Disable Rx and flush all Rx frames before enabling RSS to avoid Rx
 	 * unit hang.
@@ -4537,7 +4545,7 @@
 		if (ret_val)
 			return ret_val;
 		ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
-					      (u16) (hw->phy_spd_default &
+					      (u16)(hw->phy_spd_default &
 						     ~IGP01E1000_GMII_SPD));
 		if (ret_val)
 			return ret_val;
@@ -4802,7 +4810,7 @@
 void e1000_update_adaptive(struct e1000_hw *hw)
 {
 	if (hw->adaptive_ifs) {
-		if ((hw->collision_delta *hw->ifs_ratio) > hw->tx_packet_delta) {
+		if ((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) {
 			if (hw->tx_packet_delta > MIN_NUM_XMITS) {
 				hw->in_ifs_mode = true;
 				if (hw->current_ifs_val < hw->ifs_max_val) {
@@ -4816,8 +4824,8 @@
 				}
 			}
 		} else {
-			if (hw->in_ifs_mode
-			    && (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+			if (hw->in_ifs_mode &&
+			    (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
 				hw->current_ifs_val = 0;
 				hw->in_ifs_mode = false;
 				ew32(AIT, 0);
@@ -4922,7 +4930,6 @@
 
 	/* Use old method for Phy older than IGP */
 	if (hw->phy_type == e1000_phy_m88) {
-
 		ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
 					     &phy_data);
 		if (ret_val)
@@ -4966,7 +4973,6 @@
 		};
 		/* Read the AGC registers for all channels */
 		for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
-
 			ret_val =
 			    e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data);
 			if (ret_val)
@@ -4976,8 +4982,8 @@
 
 			/* Value bound check. */
 			if ((cur_agc_value >=
-			     IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1)
-			    || (cur_agc_value == 0))
+			     IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+			    (cur_agc_value == 0))
 				return -E1000_ERR_PHY;
 
 			agc_value += cur_agc_value;
@@ -5054,7 +5060,6 @@
 		 */
 		if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
 		    IGP01E1000_PSSR_SPEED_1000MBPS) {
-
 			/* Read the GIG initialization PCS register (0x00B4) */
 			ret_val =
 			    e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
@@ -5175,8 +5180,8 @@
 				hw->ffe_config_state = e1000_ffe_config_active;
 
 				ret_val = e1000_write_phy_reg(hw,
-					      IGP01E1000_PHY_DSP_FFE,
-					      IGP01E1000_PHY_DSP_FFE_CM_CP);
+							      IGP01E1000_PHY_DSP_FFE,
+							      IGP01E1000_PHY_DSP_FFE_CM_CP);
 				if (ret_val)
 					return ret_val;
 				break;
@@ -5243,7 +5248,7 @@
 			msleep(20);
 
 			ret_val = e1000_write_phy_reg(hw, 0x0000,
-						    IGP01E1000_IEEE_FORCE_GIGA);
+						      IGP01E1000_IEEE_FORCE_GIGA);
 			if (ret_val)
 				return ret_val;
 			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
@@ -5264,7 +5269,7 @@
 			}
 
 			ret_val = e1000_write_phy_reg(hw, 0x0000,
-					IGP01E1000_IEEE_RESTART_AUTONEG);
+						      IGP01E1000_IEEE_RESTART_AUTONEG);
 			if (ret_val)
 				return ret_val;
 
@@ -5299,7 +5304,7 @@
 			msleep(20);
 
 			ret_val = e1000_write_phy_reg(hw, 0x0000,
-						    IGP01E1000_IEEE_FORCE_GIGA);
+						      IGP01E1000_IEEE_FORCE_GIGA);
 			if (ret_val)
 				return ret_val;
 			ret_val =
@@ -5309,7 +5314,7 @@
 				return ret_val;
 
 			ret_val = e1000_write_phy_reg(hw, 0x0000,
-					IGP01E1000_IEEE_RESTART_AUTONEG);
+						      IGP01E1000_IEEE_RESTART_AUTONEG);
 			if (ret_val)
 				return ret_val;
 
@@ -5346,9 +5351,8 @@
 		ret_val =
 		    e1000_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1,
 				      &eeprom_data);
-		if (ret_val) {
+		if (ret_val)
 			return ret_val;
-		}
 
 		if ((eeprom_data != EEPROM_RESERVED_WORD) &&
 		    (eeprom_data & EEPROM_PHY_CLASS_A)) {
@@ -5395,8 +5399,8 @@
 	 * from the lowest speeds starting from 10Mbps. The capability is used
 	 * for Dx transitions and states
 	 */
-	if (hw->mac_type == e1000_82541_rev_2
-	    || hw->mac_type == e1000_82547_rev_2) {
+	if (hw->mac_type == e1000_82541_rev_2 ||
+	    hw->mac_type == e1000_82547_rev_2) {
 		ret_val =
 		    e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
 		if (ret_val)
@@ -5446,11 +5450,9 @@
 			if (ret_val)
 				return ret_val;
 		}
-	} else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT)
-		   || (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL)
-		   || (hw->autoneg_advertised ==
-		       AUTONEG_ADVERTISE_10_100_ALL)) {
-
+	} else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
+		   (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL) ||
+		   (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
 		if (hw->mac_type == e1000_82541_rev_2 ||
 		    hw->mac_type == e1000_82547_rev_2) {
 			phy_data |= IGP01E1000_GMII_FLEX_SPD;
@@ -5474,7 +5476,6 @@
 					phy_data);
 		if (ret_val)
 			return ret_val;
-
 	}
 	return E1000_SUCCESS;
 }
@@ -5542,7 +5543,6 @@
 	return E1000_SUCCESS;
 }
 
-
 /**
  * e1000_enable_mng_pass_thru - check for bmc pass through
  * @hw: Struct containing variables accessed by shared code
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -99,13 +99,13 @@
 void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
 void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
 static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
-                             struct e1000_tx_ring *txdr);
+				    struct e1000_tx_ring *txdr);
 static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
-                             struct e1000_rx_ring *rxdr);
+				    struct e1000_rx_ring *rxdr);
 static void e1000_free_tx_resources(struct e1000_adapter *adapter,
-                             struct e1000_tx_ring *tx_ring);
+				    struct e1000_tx_ring *tx_ring);
 static void e1000_free_rx_resources(struct e1000_adapter *adapter,
-                             struct e1000_rx_ring *rx_ring);
+				    struct e1000_rx_ring *rx_ring);
 void e1000_update_stats(struct e1000_adapter *adapter);
 
 static int e1000_init_module(void);
@@ -122,16 +122,16 @@
 static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter);
 static void e1000_clean_all_rx_rings(struct e1000_adapter *adapter);
 static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
-                                struct e1000_tx_ring *tx_ring);
+				struct e1000_tx_ring *tx_ring);
 static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
-                                struct e1000_rx_ring *rx_ring);
+				struct e1000_rx_ring *rx_ring);
 static void e1000_set_rx_mode(struct net_device *netdev);
 static void e1000_update_phy_info_task(struct work_struct *work);
 static void e1000_watchdog(struct work_struct *work);
 static void e1000_82547_tx_fifo_stall_task(struct work_struct *work);
 static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
 				    struct net_device *netdev);
-static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
+static struct net_device_stats *e1000_get_stats(struct net_device *netdev);
 static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
 static int e1000_set_mac(struct net_device *netdev, void *p);
 static irqreturn_t e1000_intr(int irq, void *data);
@@ -164,7 +164,7 @@
 static void e1000_reset_task(struct work_struct *work);
 static void e1000_smartspeed(struct e1000_adapter *adapter);
 static int e1000_82547_fifo_workaround(struct e1000_adapter *adapter,
-                                       struct sk_buff *skb);
+				       struct sk_buff *skb);
 
 static bool e1000_vlan_used(struct e1000_adapter *adapter);
 static void e1000_vlan_mode(struct net_device *netdev,
@@ -195,7 +195,7 @@
 	"Maximum size of packet that is copied to a new buffer on receive");
 
 static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
-                     pci_channel_state_t state);
+						pci_channel_state_t state);
 static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
 static void e1000_io_resume(struct pci_dev *pdev);
 
@@ -287,7 +287,7 @@
 	int err;
 
 	err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
-	                  netdev);
+			  netdev);
 	if (err) {
 		e_err(probe, "Unable to allocate interrupt Error: %d\n", err);
 	}
@@ -521,8 +521,6 @@
 	struct net_device *netdev = adapter->netdev;
 	u32 rctl, tctl;
 
-	netif_carrier_off(netdev);
-
 	/* disable receives in the hardware */
 	rctl = er32(RCTL);
 	ew32(RCTL, rctl & ~E1000_RCTL_EN);
@@ -538,6 +536,15 @@
 	E1000_WRITE_FLUSH();
 	msleep(10);
 
+	/* Set the carrier off after transmits have been disabled in the
+	 * hardware, to avoid race conditions with e1000_watchdog() (which
+	 * may be running concurrently to us, checking for the carrier
+	 * bit to decide whether it should enable transmits again). Such
+	 * a race condition would result into transmission being disabled
+	 * in the hardware until the next IFF_DOWN+IFF_UP cycle.
+	 */
+	netif_carrier_off(netdev);
+
 	napi_disable(&adapter->napi);
 
 	e1000_irq_disable(adapter);
@@ -561,8 +568,13 @@
 	WARN_ON(in_interrupt());
 	while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
 		msleep(1);
-	e1000_down(adapter);
-	e1000_up(adapter);
+
+	/* only run the task if not already down */
+	if (!test_bit(__E1000_DOWN, &adapter->flags)) {
+		e1000_down(adapter);
+		e1000_up(adapter);
+	}
+
 	clear_bit(__E1000_RESETTING, &adapter->flags);
 }
 
@@ -636,8 +648,8 @@
 		 * but don't include ethernet FCS because hardware appends it
 		 */
 		min_tx_space = (hw->max_frame_size +
-		                sizeof(struct e1000_tx_desc) -
-		                ETH_FCS_LEN) * 2;
+				sizeof(struct e1000_tx_desc) -
+				ETH_FCS_LEN) * 2;
 		min_tx_space = ALIGN(min_tx_space, 1024);
 		min_tx_space >>= 10;
 		/* software strips receive CRC, so leave room for it */
@@ -940,16 +952,17 @@
 static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *netdev;
-	struct e1000_adapter *adapter;
+	struct e1000_adapter *adapter = NULL;
 	struct e1000_hw *hw;
 
-	static int cards_found = 0;
-	static int global_quad_port_a = 0; /* global ksp3 port a indication */
+	static int cards_found;
+	static int global_quad_port_a; /* global ksp3 port a indication */
 	int i, err, pci_using_dac;
 	u16 eeprom_data = 0;
 	u16 tmp = 0;
 	u16 eeprom_apme_mask = E1000_EEPROM_APME;
 	int bars, need_ioport;
+	bool disable_dev = false;
 
 	/* do not allocate ioport bars when not needed */
 	need_ioport = e1000_is_need_ioport(pdev);
@@ -1046,7 +1059,7 @@
 	if (hw->mac_type == e1000_ce4100) {
 		hw->ce4100_gbe_mdio_base_virt =
 					ioremap(pci_resource_start(pdev, BAR_1),
-		                                pci_resource_len(pdev, BAR_1));
+						pci_resource_len(pdev, BAR_1));
 
 		if (!hw->ce4100_gbe_mdio_base_virt)
 			goto err_mdio_ioremap;
@@ -1148,7 +1161,7 @@
 		break;
 	case e1000_82546:
 	case e1000_82546_rev_3:
-		if (er32(STATUS) & E1000_STATUS_FUNC_1){
+		if (er32(STATUS) & E1000_STATUS_FUNC_1) {
 			e1000_read_eeprom(hw,
 				EEPROM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
 			break;
@@ -1199,13 +1212,13 @@
 		for (i = 0; i < 32; i++) {
 			hw->phy_addr = i;
 			e1000_read_phy_reg(hw, PHY_ID2, &tmp);
-			if (tmp == 0 || tmp == 0xFF) {
-				if (i == 31)
-					goto err_eeprom;
-				continue;
-			} else
+
+			if (tmp != 0 && tmp != 0xFF)
 				break;
 		}
+
+		if (i >= 32)
+			goto err_eeprom;
 	}
 
 	/* reset the hardware with the new settings */
@@ -1250,11 +1263,13 @@
 	iounmap(hw->ce4100_gbe_mdio_base_virt);
 	iounmap(hw->hw_addr);
 err_ioremap:
+	disable_dev = !test_and_set_bit(__E1000_DISABLED, &adapter->flags);
 	free_netdev(netdev);
 err_alloc_etherdev:
 	pci_release_selected_regions(pdev, bars);
 err_pci_reg:
-	pci_disable_device(pdev);
+	if (!adapter || disable_dev)
+		pci_disable_device(pdev);
 	return err;
 }
 
@@ -1263,7 +1278,7 @@
  * @pdev: PCI device information struct
  *
  * e1000_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.  The could be caused by a
+ * that it should release a PCI device. That could be caused by a
  * Hot-Plug event, or because the driver is going to be removed from
  * memory.
  **/
@@ -1272,6 +1287,7 @@
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
+	bool disable_dev;
 
 	e1000_down_and_stop(adapter);
 	e1000_release_manageability(adapter);
@@ -1290,9 +1306,11 @@
 		iounmap(hw->flash_address);
 	pci_release_selected_regions(pdev, adapter->bars);
 
+	disable_dev = !test_and_set_bit(__E1000_DISABLED, &adapter->flags);
 	free_netdev(netdev);
 
-	pci_disable_device(pdev);
+	if (disable_dev)
+		pci_disable_device(pdev);
 }
 
 /**
@@ -1334,12 +1352,12 @@
 static int e1000_alloc_queues(struct e1000_adapter *adapter)
 {
 	adapter->tx_ring = kcalloc(adapter->num_tx_queues,
-	                           sizeof(struct e1000_tx_ring), GFP_KERNEL);
+				   sizeof(struct e1000_tx_ring), GFP_KERNEL);
 	if (!adapter->tx_ring)
 		return -ENOMEM;
 
 	adapter->rx_ring = kcalloc(adapter->num_rx_queues,
-	                           sizeof(struct e1000_rx_ring), GFP_KERNEL);
+				   sizeof(struct e1000_rx_ring), GFP_KERNEL);
 	if (!adapter->rx_ring) {
 		kfree(adapter->tx_ring);
 		return -ENOMEM;
@@ -1443,10 +1461,15 @@
 	struct e1000_hw *hw = &adapter->hw;
 	int count = E1000_CHECK_RESET_COUNT;
 
-	while (test_bit(__E1000_RESETTING, &adapter->flags) && count--)
+	while (test_and_set_bit(__E1000_RESETTING, &adapter->flags) && count--)
 		usleep_range(10000, 20000);
 
-	WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
+	WARN_ON(count < 0);
+
+	/* signal that we're down so that the reset task will no longer run */
+	set_bit(__E1000_DOWN, &adapter->flags);
+	clear_bit(__E1000_RESETTING, &adapter->flags);
+
 	e1000_down(adapter);
 	e1000_power_down_phy(adapter);
 	e1000_free_irq(adapter);
@@ -1811,20 +1834,20 @@
 	rctl &= ~E1000_RCTL_SZ_4096;
 	rctl |= E1000_RCTL_BSEX;
 	switch (adapter->rx_buffer_len) {
-		case E1000_RXBUFFER_2048:
-		default:
-			rctl |= E1000_RCTL_SZ_2048;
-			rctl &= ~E1000_RCTL_BSEX;
-			break;
-		case E1000_RXBUFFER_4096:
-			rctl |= E1000_RCTL_SZ_4096;
-			break;
-		case E1000_RXBUFFER_8192:
-			rctl |= E1000_RCTL_SZ_8192;
-			break;
-		case E1000_RXBUFFER_16384:
-			rctl |= E1000_RCTL_SZ_16384;
-			break;
+	case E1000_RXBUFFER_2048:
+	default:
+		rctl |= E1000_RCTL_SZ_2048;
+		rctl &= ~E1000_RCTL_BSEX;
+		break;
+	case E1000_RXBUFFER_4096:
+		rctl |= E1000_RCTL_SZ_4096;
+		break;
+	case E1000_RXBUFFER_8192:
+		rctl |= E1000_RCTL_SZ_8192;
+		break;
+	case E1000_RXBUFFER_16384:
+		rctl |= E1000_RCTL_SZ_16384;
+		break;
 	}
 
 	/* This is useful for sniffing bad packets. */
@@ -1861,12 +1884,12 @@
 
 	if (adapter->netdev->mtu > ETH_DATA_LEN) {
 		rdlen = adapter->rx_ring[0].count *
-		        sizeof(struct e1000_rx_desc);
+			sizeof(struct e1000_rx_desc);
 		adapter->clean_rx = e1000_clean_jumbo_rx_irq;
 		adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers;
 	} else {
 		rdlen = adapter->rx_ring[0].count *
-		        sizeof(struct e1000_rx_desc);
+			sizeof(struct e1000_rx_desc);
 		adapter->clean_rx = e1000_clean_rx_irq;
 		adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
 	}
@@ -2761,7 +2784,9 @@
 		buffer_info->time_stamp = jiffies;
 		buffer_info->next_to_watch = i;
 
-		if (++i == tx_ring->count) i = 0;
+		if (++i == tx_ring->count)
+			i = 0;
+
 		tx_ring->next_to_use = i;
 
 		return true;
@@ -2816,7 +2841,9 @@
 	buffer_info->time_stamp = jiffies;
 	buffer_info->next_to_watch = i;
 
-	if (unlikely(++i == tx_ring->count)) i = 0;
+	if (unlikely(++i == tx_ring->count))
+		i = 0;
+
 	tx_ring->next_to_use = i;
 
 	return true;
@@ -2865,8 +2892,8 @@
 		 * packet is smaller than 2048 - 16 - 16 (or 2016) bytes
 		 */
 		if (unlikely((hw->bus_type == e1000_bus_type_pcix) &&
-		                (size > 2015) && count == 0))
-		        size = 2015;
+			     (size > 2015) && count == 0))
+			size = 2015;
 
 		/* Workaround for potential 82544 hang in PCI-X.  Avoid
 		 * terminating buffers within evenly-aligned dwords.
@@ -2963,7 +2990,7 @@
 		count--;
 
 	while (count--) {
-		if (i==0)
+		if (i == 0)
 			i += tx_ring->count;
 		i--;
 		buffer_info = &tx_ring->buffer_info[i];
@@ -3013,7 +3040,8 @@
 		tx_desc->lower.data =
 			cpu_to_le32(txd_lower | buffer_info->length);
 		tx_desc->upper.data = cpu_to_le32(txd_upper);
-		if (unlikely(++i == tx_ring->count)) i = 0;
+		if (unlikely(++i == tx_ring->count))
+			i = 0;
 	}
 
 	tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
@@ -3101,7 +3129,7 @@
 	return __e1000_maybe_stop_tx(netdev, size);
 }
 
-#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
+#define TXD_USE_COUNT(S, X) (((S) + ((1 << (X)) - 1)) >> (X))
 static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
 				    struct net_device *netdev)
 {
@@ -3149,8 +3177,9 @@
 		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 		if (skb->data_len && hdr_len == len) {
 			switch (hw->mac_type) {
+			case e1000_82544: {
 				unsigned int pull_size;
-			case e1000_82544:
+
 				/* Make sure we have room to chop off 4 bytes,
 				 * and that the end alignment will work out to
 				 * this hardware's requirements
@@ -3171,6 +3200,7 @@
 				}
 				len = skb_headlen(skb);
 				break;
+			}
 			default:
 				/* do nothing */
 				break;
@@ -3251,12 +3281,29 @@
 			     nr_frags, mss);
 
 	if (count) {
+		/* The descriptors needed is higher than other Intel drivers
+		 * due to a number of workarounds.  The breakdown is below:
+		 * Data descriptors: MAX_SKB_FRAGS + 1
+		 * Context Descriptor: 1
+		 * Keep head from touching tail: 2
+		 * Workarounds: 3
+		 */
+		int desc_needed = MAX_SKB_FRAGS + 7;
+
 		netdev_sent_queue(netdev, skb->len);
 		skb_tx_timestamp(skb);
 
 		e1000_tx_queue(adapter, tx_ring, tx_flags, count);
+
+		/* 82544 potentially requires twice as many data descriptors
+		 * in order to guarantee buffers don't end on evenly-aligned
+		 * dwords
+		 */
+		if (adapter->pcix_82544)
+			desc_needed += MAX_SKB_FRAGS + 1;
+
 		/* Make sure there is space in the ring for the next send. */
-		e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
+		e1000_maybe_stop_tx(netdev, tx_ring, desc_needed);
 
 		if (!skb->xmit_more ||
 		    netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) {
@@ -3841,7 +3888,7 @@
 	struct e1000_tx_buffer *buffer_info;
 	unsigned int i, eop;
 	unsigned int count = 0;
-	unsigned int total_tx_bytes=0, total_tx_packets=0;
+	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
 	unsigned int bytes_compl = 0, pkts_compl = 0;
 
 	i = tx_ring->next_to_clean;
@@ -3869,14 +3916,18 @@
 			e1000_unmap_and_free_tx_resource(adapter, buffer_info);
 			tx_desc->upper.data = 0;
 
-			if (unlikely(++i == tx_ring->count)) i = 0;
+			if (unlikely(++i == tx_ring->count))
+				i = 0;
 		}
 
 		eop = tx_ring->buffer_info[i].next_to_watch;
 		eop_desc = E1000_TX_DESC(*tx_ring, eop);
 	}
 
-	tx_ring->next_to_clean = i;
+	/* Synchronize with E1000_DESC_UNUSED called from e1000_xmit_frame,
+	 * which will reuse the cleaned buffers.
+	 */
+	smp_store_release(&tx_ring->next_to_clean, i);
 
 	netdev_completed_queue(netdev, pkts_compl, bytes_compl);
 
@@ -3954,9 +4005,11 @@
 	skb_checksum_none_assert(skb);
 
 	/* 82543 or newer only */
-	if (unlikely(hw->mac_type < e1000_82543)) return;
+	if (unlikely(hw->mac_type < e1000_82543))
+		return;
 	/* Ignore Checksum bit is set */
-	if (unlikely(status & E1000_RXD_STAT_IXSM)) return;
+	if (unlikely(status & E1000_RXD_STAT_IXSM))
+		return;
 	/* TCP/UDP checksum error bit is set */
 	if (unlikely(errors & E1000_RXD_ERR_TCPE)) {
 		/* let the stack verify checksum errors */
@@ -4136,7 +4189,7 @@
 	unsigned int i;
 	int cleaned_count = 0;
 	bool cleaned = false;
-	unsigned int total_rx_bytes=0, total_rx_packets=0;
+	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
 
 	i = rx_ring->next_to_clean;
 	rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -4153,7 +4206,9 @@
 
 		status = rx_desc->status;
 
-		if (++i == rx_ring->count) i = 0;
+		if (++i == rx_ring->count)
+			i = 0;
+
 		next_rxd = E1000_RX_DESC(*rx_ring, i);
 		prefetch(next_rxd);
 
@@ -4356,7 +4411,7 @@
 	unsigned int i;
 	int cleaned_count = 0;
 	bool cleaned = false;
-	unsigned int total_rx_bytes=0, total_rx_packets=0;
+	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
 
 	i = rx_ring->next_to_clean;
 	rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -4395,7 +4450,9 @@
 			buffer_info->rxbuf.data = NULL;
 		}
 
-		if (++i == rx_ring->count) i = 0;
+		if (++i == rx_ring->count)
+			i = 0;
+
 		next_rxd = E1000_RX_DESC(*rx_ring, i);
 		prefetch(next_rxd);
 
@@ -4683,9 +4740,11 @@
 		 * we assume back-to-back
 		 */
 		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
-		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
+		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT))
+			return;
 		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
-		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
+		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT))
+			return;
 		e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl);
 		if (phy_ctrl & CR_1000T_MS_ENABLE) {
 			phy_ctrl &= ~CR_1000T_MS_ENABLE;
@@ -5132,7 +5191,8 @@
 	if (netif_running(netdev))
 		e1000_free_irq(adapter);
 
-	pci_disable_device(pdev);
+	if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags))
+		pci_disable_device(pdev);
 
 	return 0;
 }
@@ -5176,6 +5236,10 @@
 		pr_err("Cannot enable PCI device from suspend\n");
 		return err;
 	}
+
+	/* flush memory to make sure state is correct */
+	smp_mb__before_atomic();
+	clear_bit(__E1000_DISABLED, &adapter->flags);
 	pci_set_master(pdev);
 
 	pci_enable_wake(pdev, PCI_D3hot, 0);
@@ -5250,7 +5314,9 @@
 
 	if (netif_running(netdev))
 		e1000_down(adapter);
-	pci_disable_device(pdev);
+
+	if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags))
+		pci_disable_device(pdev);
 
 	/* Request a slot slot reset. */
 	return PCI_ERS_RESULT_NEED_RESET;
@@ -5278,6 +5344,10 @@
 		pr_err("Cannot re-enable PCI device after reset.\n");
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
+
+	/* flush memory to make sure state is correct */
+	smp_mb__before_atomic();
+	clear_bit(__E1000_DISABLED, &adapter->flags);
 	pci_set_master(pdev);
 
 	pci_enable_wake(pdev, PCI_D3hot, 0);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/defines.h
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/defines.h
@@ -398,6 +398,7 @@
 #define E1000_ICR_LSC           0x00000004 /* Link Status Change */
 #define E1000_ICR_RXSEQ         0x00000008 /* Rx sequence error */
 #define E1000_ICR_RXDMT0        0x00000010 /* Rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* Receiver Overrun */
 #define E1000_ICR_RXT0          0x00000080 /* Rx timer intr (ring 0) */
 #define E1000_ICR_ECCER         0x00400000 /* Uncorrectable ECC Error */
 /* If this bit asserted, the driver should claim the interrupt */
@@ -441,12 +442,13 @@
 #define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
 #define E1000_IMS_TXQ0      E1000_ICR_TXQ0      /* Tx Queue 0 Interrupt */
 #define E1000_IMS_TXQ1      E1000_ICR_TXQ1      /* Tx Queue 1 Interrupt */
-#define E1000_IMS_OTHER     E1000_ICR_OTHER     /* Other Interrupts */
+#define E1000_IMS_OTHER     E1000_ICR_OTHER     /* Other Interrupt */
 
 /* Interrupt Cause Set */
 #define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
 #define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
 #define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
+#define E1000_ICS_OTHER     E1000_ICR_OTHER     /* Other Interrupt */
 
 /* Transmit Descriptor Control */
 #define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
@@ -527,6 +529,11 @@
 #define E1000_RXCW_C          0x20000000        /* Receive config */
 #define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
 
+/* HH Time Sync */
+#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK	0x0000F000 /* max delay */
+#define E1000_TSYNCTXCTL_SYNC_COMP		0x40000000 /* sync complete */
+#define E1000_TSYNCTXCTL_START_SYNC		0x80000000 /* initiate sync */
+
 #define E1000_TSYNCTXCTL_VALID		0x00000001 /* Tx timestamp valid */
 #define E1000_TSYNCTXCTL_ENABLED	0x00000010 /* enable Tx timestamping */
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/e1000.h
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -480,7 +480,7 @@
 void e1000e_check_options(struct e1000_adapter *adapter);
 void e1000e_set_ethtool_ops(struct net_device *netdev);
 
-int e1000e_up(struct e1000_adapter *adapter);
+void e1000e_up(struct e1000_adapter *adapter);
 void e1000e_down(struct e1000_adapter *adapter, bool reset);
 void e1000e_reinit_locked(struct e1000_adapter *adapter);
 void e1000e_reset(struct e1000_adapter *adapter);
@@ -585,7 +585,6 @@
 
 #define er32(reg)	__er32(hw, E1000_##reg)
 
-s32 __ew32_prepare(struct e1000_hw *hw);
 void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val);
 
 #define ew32(reg, val)	__ew32(hw, E1000_##reg, (val))
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/hw.h
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/hw.h
@@ -91,6 +91,11 @@
 #define E1000_DEV_ID_PCH_SPT_I219_V		0x1570	/* SPT PCH */
 #define E1000_DEV_ID_PCH_SPT_I219_LM2		0x15B7	/* SPT-H PCH */
 #define E1000_DEV_ID_PCH_SPT_I219_V2		0x15B8	/* SPT-H PCH */
+#define E1000_DEV_ID_PCH_LBG_I219_LM3		0x15B9	/* LBG PCH */
+#define E1000_DEV_ID_PCH_SPT_I219_LM4		0x15D7
+#define E1000_DEV_ID_PCH_SPT_I219_V4		0x15D8
+#define E1000_DEV_ID_PCH_SPT_I219_LM5		0x15E3
+#define E1000_DEV_ID_PCH_SPT_I219_V5		0x15D6
 
 #define E1000_REVISION_4	4
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -1362,6 +1362,9 @@
  *  Checks to see of the link status of the hardware has changed.  If a
  *  change in link status has been detected, then we read the PHY registers
  *  to get the current speed/duplex if link exists.
+ *
+ *  Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
+ *  up).
  **/
 static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
 {
@@ -1377,7 +1380,7 @@
 	 * Change or Rx Sequence Error interrupt.
 	 */
 	if (!mac->get_link_status)
-		return 0;
+		return 1;
 
 	/* First we want to see if the MII Status Register reports
 	 * link.  If so, then we want to get the current speed/duplex
@@ -1571,7 +1574,7 @@
 	 * we have already determined whether we have link or not.
 	 */
 	if (!mac->autoneg)
-		return -E1000_ERR_CONFIG;
+		return 1;
 
 	/* Auto-Neg is enabled.  Auto Speed Detection takes care
 	 * of MAC speed/duplex configuration.  So we only need to
@@ -1585,10 +1588,12 @@
 	 * different link partner.
 	 */
 	ret_val = e1000e_config_fc_after_link_up(hw);
-	if (ret_val)
+	if (ret_val) {
 		e_dbg("Error configuring flow control\n");
+		return ret_val;
+	}
 
-	return ret_val;
+	return 1;
 }
 
 static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
@@ -1984,7 +1989,7 @@
 	int i = 0;
 
 	while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
-	       (i++ < 10))
+	       (i++ < 30))
 		usleep_range(10000, 20000);
 	return blocked ? E1000_BLK_PHY_RESET : 0;
 }
@@ -3093,24 +3098,45 @@
 	struct e1000_nvm_info *nvm = &hw->nvm;
 	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+	u32 nvm_dword = 0;
 	u8 sig_byte = 0;
 	s32 ret_val;
 
 	switch (hw->mac.type) {
-		/* In SPT, read from the CTRL_EXT reg instead of
-		 * accessing the sector valid bits from the nvm
-		 */
 	case e1000_pch_spt:
-		*bank = er32(CTRL_EXT)
-		    & E1000_CTRL_EXT_NVMVS;
-		if ((*bank == 0) || (*bank == 1)) {
-			e_dbg("ERROR: No valid NVM bank present\n");
-			return -E1000_ERR_NVM;
-		} else {
-			*bank = *bank - 2;
+		bank1_offset = nvm->flash_bank_size;
+		act_offset = E1000_ICH_NVM_SIG_WORD;
+
+		/* set bank to 0 in case flash read fails */
+		*bank = 0;
+
+		/* Check bank 0 */
+		ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset,
+							 &nvm_dword);
+		if (ret_val)
+			return ret_val;
+		sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
+		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+		    E1000_ICH_NVM_SIG_VALUE) {
+			*bank = 0;
 			return 0;
 		}
-		break;
+
+		/* Check bank 1 */
+		ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset +
+							 bank1_offset,
+							 &nvm_dword);
+		if (ret_val)
+			return ret_val;
+		sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
+		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+		    E1000_ICH_NVM_SIG_VALUE) {
+			*bank = 1;
+			return 0;
+		}
+
+		e_dbg("ERROR: No valid NVM bank present\n");
+		return -E1000_ERR_NVM;
 	case e1000_ich8lan:
 	case e1000_ich9lan:
 		eecd = er32(EECD);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/mac.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/mac.c
@@ -410,6 +410,9 @@
  *  Checks to see of the link status of the hardware has changed.  If a
  *  change in link status has been detected, then we read the PHY registers
  *  to get the current speed/duplex if link exists.
+ *
+ *  Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
+ *  up).
  **/
 s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
 {
@@ -423,7 +426,7 @@
 	 * Change or Rx Sequence Error interrupt.
 	 */
 	if (!mac->get_link_status)
-		return 0;
+		return 1;
 
 	/* First we want to see if the MII Status Register reports
 	 * link.  If so, then we want to get the current speed/duplex
@@ -447,7 +450,7 @@
 	 * we have already determined whether we have link or not.
 	 */
 	if (!mac->autoneg)
-		return -E1000_ERR_CONFIG;
+		return 1;
 
 	/* Auto-Neg is enabled.  Auto Speed Detection takes care
 	 * of MAC speed/duplex configuration.  So we only need to
@@ -461,10 +464,12 @@
 	 * different link partner.
 	 */
 	ret_val = e1000e_config_fc_after_link_up(hw);
-	if (ret_val)
+	if (ret_val) {
 		e_dbg("Error configuring flow control\n");
+		return ret_val;
+	}
 
-	return ret_val;
+	return 1;
 }
 
 /**
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/netdev.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -136,14 +136,12 @@
  * has bit 24 set while ME is accessing MAC CSR registers, wait if it is set
  * and try again a number of times.
  **/
-s32 __ew32_prepare(struct e1000_hw *hw)
+static void __ew32_prepare(struct e1000_hw *hw)
 {
 	s32 i = E1000_ICH_FWSM_PCIM2PCI_COUNT;
 
 	while ((er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI) && --i)
 		udelay(50);
-
-	return i;
 }
 
 void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
@@ -624,11 +622,11 @@
 {
 	struct e1000_adapter *adapter = rx_ring->adapter;
 	struct e1000_hw *hw = &adapter->hw;
-	s32 ret_val = __ew32_prepare(hw);
 
+	__ew32_prepare(hw);
 	writel(i, rx_ring->tail);
 
-	if (unlikely(!ret_val && (i != readl(rx_ring->tail)))) {
+	if (unlikely(i != readl(rx_ring->tail))) {
 		u32 rctl = er32(RCTL);
 
 		ew32(RCTL, rctl & ~E1000_RCTL_EN);
@@ -641,11 +639,11 @@
 {
 	struct e1000_adapter *adapter = tx_ring->adapter;
 	struct e1000_hw *hw = &adapter->hw;
-	s32 ret_val = __ew32_prepare(hw);
 
+	__ew32_prepare(hw);
 	writel(i, tx_ring->tail);
 
-	if (unlikely(!ret_val && (i != readl(tx_ring->tail)))) {
+	if (unlikely(i != readl(tx_ring->tail))) {
 		u32 tctl = er32(TCTL);
 
 		ew32(TCTL, tctl & ~E1000_TCTL_EN);
@@ -1182,6 +1180,7 @@
 	struct e1000_hw *hw = &adapter->hw;
 
 	if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
+		struct sk_buff *skb = adapter->tx_hwtstamp_skb;
 		struct skb_shared_hwtstamps shhwtstamps;
 		u64 txstmp;
 
@@ -1190,9 +1189,14 @@
 
 		e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp);
 
-		skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
-		dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+		/* Clear the global tx_hwtstamp_skb pointer and force writes
+		 * prior to notifying the stack of a Tx timestamp.
+		 */
 		adapter->tx_hwtstamp_skb = NULL;
+		wmb(); /* force write prior to skb_tstamp_tx */
+
+		skb_tstamp_tx(skb, &shhwtstamps);
+		dev_kfree_skb_any(skb);
 	} else if (time_after(jiffies, adapter->tx_hwtstamp_start
 			      + adapter->tx_timeout_factor * HZ)) {
 		dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
@@ -1905,29 +1909,30 @@
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	u32 icr = er32(ICR);
+	u32 icr;
+	bool enable = true;
 
-	if (!(icr & E1000_ICR_INT_ASSERTED)) {
-		if (!test_bit(__E1000_DOWN, &adapter->state))
-			ew32(IMS, E1000_IMS_OTHER);
-		return IRQ_NONE;
+	icr = er32(ICR);
+	if (icr & E1000_ICR_RXO) {
+		ew32(ICR, E1000_ICR_RXO);
+		enable = false;
+		/* napi poll will re-enable Other, make sure it runs */
+		if (napi_schedule_prep(&adapter->napi)) {
+			adapter->total_rx_bytes = 0;
+			adapter->total_rx_packets = 0;
+			__napi_schedule(&adapter->napi);
+		}
 	}
-
-	if (icr & adapter->eiac_mask)
-		ew32(ICS, (icr & adapter->eiac_mask));
-
-	if (icr & E1000_ICR_OTHER) {
-		if (!(icr & E1000_ICR_LSC))
-			goto no_link_interrupt;
+	if (icr & E1000_ICR_LSC) {
+		ew32(ICR, E1000_ICR_LSC);
 		hw->mac.get_link_status = true;
 		/* guard against interrupt when we're going down */
 		if (!test_bit(__E1000_DOWN, &adapter->state))
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
-no_link_interrupt:
-	if (!test_bit(__E1000_DOWN, &adapter->state))
-		ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
+	if (enable && !test_bit(__E1000_DOWN, &adapter->state))
+		ew32(IMS, E1000_IMS_OTHER);
 
 	return IRQ_HANDLED;
 }
@@ -1946,6 +1951,9 @@
 		/* Ring was not completely cleaned, so fire another interrupt */
 		ew32(ICS, tx_ring->ims_val);
 
+	if (!test_bit(__E1000_DOWN, &adapter->state))
+		ew32(IMS, adapter->tx_ring->ims_val);
+
 	return IRQ_HANDLED;
 }
 
@@ -1959,8 +1967,10 @@
 	 * previous interrupt.
 	 */
 	if (rx_ring->set_itr) {
-		writel(1000000000 / (rx_ring->itr_val * 256),
-		       rx_ring->itr_register);
+		u32 itr = rx_ring->itr_val ?
+			  1000000000 / (rx_ring->itr_val * 256) : 0;
+
+		writel(itr, rx_ring->itr_register);
 		rx_ring->set_itr = 0;
 	}
 
@@ -2025,6 +2035,7 @@
 		       hw->hw_addr + E1000_EITR_82574(vector));
 	else
 		writel(1, hw->hw_addr + E1000_EITR_82574(vector));
+	adapter->eiac_mask |= E1000_IMS_OTHER;
 
 	/* Cause Tx interrupts on every write back */
 	ivar |= (1 << 31);
@@ -2032,12 +2043,8 @@
 	ew32(IVAR, ivar);
 
 	/* enable MSI-X PBA support */
-	ctrl_ext = er32(CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
-
-	/* Auto-Mask Other interrupts upon ICR read */
-	ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
-	ctrl_ext |= E1000_CTRL_EXT_EIAME;
+	ctrl_ext = er32(CTRL_EXT) & ~E1000_CTRL_EXT_IAME;
+	ctrl_ext |= E1000_CTRL_EXT_PBA_CLR | E1000_CTRL_EXT_EIAME;
 	ew32(CTRL_EXT, ctrl_ext);
 	e1e_flush();
 }
@@ -2123,7 +2130,7 @@
 	if (strlen(netdev->name) < (IFNAMSIZ - 5))
 		snprintf(adapter->rx_ring->name,
 			 sizeof(adapter->rx_ring->name) - 1,
-			 "%s-rx-0", netdev->name);
+			 "%.14s-rx-0", netdev->name);
 	else
 		memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ);
 	err = request_irq(adapter->msix_entries[vector].vector,
@@ -2139,7 +2146,7 @@
 	if (strlen(netdev->name) < (IFNAMSIZ - 5))
 		snprintf(adapter->tx_ring->name,
 			 sizeof(adapter->tx_ring->name) - 1,
-			 "%s-tx-0", netdev->name);
+			 "%.14s-tx-0", netdev->name);
 	else
 		memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ);
 	err = request_irq(adapter->msix_entries[vector].vector,
@@ -2253,7 +2260,7 @@
 
 	if (adapter->msix_entries) {
 		ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
-		ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
+		ew32(IMS, adapter->eiac_mask | E1000_IMS_LSC);
 	} else if ((hw->mac.type == e1000_pch_lpt) ||
 		   (hw->mac.type == e1000_pch_spt)) {
 		ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
@@ -2322,8 +2329,8 @@
 {
 	struct pci_dev *pdev = adapter->pdev;
 
-	ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma,
-					GFP_KERNEL);
+	ring->desc = dma_zalloc_coherent(&pdev->dev, ring->size, &ring->dma,
+					 GFP_KERNEL);
 	if (!ring->desc)
 		return -ENOMEM;
 
@@ -2696,7 +2703,8 @@
 		napi_complete_done(napi, work_done);
 		if (!test_bit(__E1000_DOWN, &adapter->state)) {
 			if (adapter->msix_entries)
-				ew32(IMS, adapter->rx_ring->ims_val);
+				ew32(IMS, adapter->rx_ring->ims_val |
+				     E1000_IMS_OTHER);
 			else
 				e1000_irq_enable(adapter);
 		}
@@ -3524,6 +3532,12 @@
 
 	switch (hw->mac.type) {
 	case e1000_pch2lan:
+		/* Stable 96MHz frequency */
+		incperiod = INCPERIOD_96MHz;
+		incvalue = INCVALUE_96MHz;
+		shift = INCVALUE_SHIFT_96MHz;
+		adapter->cc.shift = shift + INCPERIOD_SHIFT_96MHz;
+		break;
 	case e1000_pch_lpt:
 		if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
 			/* Stable 96MHz frequency */
@@ -4144,10 +4158,24 @@
 
 }
 
-int e1000e_up(struct e1000_adapter *adapter)
+/**
+ * e1000e_trigger_lsc - trigger an LSC interrupt
+ * @adapter: 
+ *
+ * Fire a link status change interrupt to start the watchdog.
+ **/
+static void e1000e_trigger_lsc(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
 
+	if (adapter->msix_entries)
+		ew32(ICS, E1000_ICS_LSC | E1000_ICS_OTHER);
+	else
+		ew32(ICS, E1000_ICS_LSC);
+}
+
+void e1000e_up(struct e1000_adapter *adapter)
+{
 	/* hardware has been reset, we need to reload some things */
 	e1000_configure(adapter);
 
@@ -4157,15 +4185,9 @@
 		e1000_configure_msix(adapter);
 	e1000_irq_enable(adapter);
 
-	netif_start_queue(adapter->netdev);
-
-	/* fire a link change interrupt to start the watchdog */
-	if (adapter->msix_entries)
-		ew32(ICS, E1000_ICS_LSC | E1000_ICR_OTHER);
-	else
-		ew32(ICS, E1000_ICS_LSC);
+	/* Tx queue started by watchdog timer when link is up */
 
-	return 0;
+	e1000e_trigger_lsc(adapter);
 }
 
 static void e1000e_flush_descriptors(struct e1000_adapter *adapter)
@@ -4525,6 +4547,7 @@
 	pm_runtime_get_sync(&pdev->dev);
 
 	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
 
 	/* allocate transmit descriptors */
 	err = e1000e_setup_tx_resources(adapter->tx_ring);
@@ -4585,16 +4608,11 @@
 	e1000_irq_enable(adapter);
 
 	adapter->tx_hang_recheck = false;
-	netif_start_queue(netdev);
 
 	hw->mac.get_link_status = true;
 	pm_runtime_put(&pdev->dev);
 
-	/* fire a link status change interrupt to start the watchdog */
-	if (adapter->msix_entries)
-		ew32(ICS, E1000_ICS_LSC | E1000_ICR_OTHER);
-	else
-		ew32(ICS, E1000_ICS_LSC);
+	e1000e_trigger_lsc(adapter);
 
 	return 0;
 
@@ -5015,7 +5033,7 @@
 	case e1000_media_type_copper:
 		if (hw->mac.get_link_status) {
 			ret_val = hw->mac.ops.check_for_link(hw);
-			link_active = !hw->mac.get_link_status;
+			link_active = ret_val > 0;
 		} else {
 			link_active = true;
 		}
@@ -5033,7 +5051,7 @@
 		break;
 	}
 
-	if ((ret_val == E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) &&
+	if ((ret_val == -E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) &&
 	    (er32(CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) {
 		/* See e1000_kmrn_lock_loss_workaround_ich8lan() */
 		e_info("Gigabit has been disabled, downgrading speed\n");
@@ -5212,6 +5230,7 @@
 			if (phy->ops.cfg_on_link_up)
 				phy->ops.cfg_on_link_up(hw);
 
+			netif_wake_queue(netdev);
 			netif_carrier_on(netdev);
 
 			if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -5225,6 +5244,7 @@
 			/* Link status message must follow this format */
 			pr_info("%s NIC Link is Down\n", adapter->netdev->name);
 			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
 			if (!test_bit(__E1000_DOWN, &adapter->state))
 				mod_timer(&adapter->phy_info_timer,
 					  round_jiffies(jiffies + 2 * HZ));
@@ -6256,11 +6276,17 @@
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	u32 ctrl, ctrl_ext, rctl, status;
-	/* Runtime suspend should only enable wakeup for link changes */
-	u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
+	u32 ctrl, ctrl_ext, rctl, status, wufc;
 	int retval = 0;
 
+	/* Runtime suspend should only enable wakeup for link changes */
+	if (runtime)
+		wufc = E1000_WUFC_LNKC;
+	else if (device_may_wakeup(&pdev->dev))
+		wufc = adapter->wol;
+	else
+		wufc = 0;
+
 	status = er32(STATUS);
 	if (status & E1000_STATUS_LU)
 		wufc &= ~E1000_WUFC_LNKC;
@@ -6318,7 +6344,7 @@
 		e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
 	} else if ((hw->mac.type == e1000_pch_lpt) ||
 		   (hw->mac.type == e1000_pch_spt)) {
-		if (!(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC)))
+		if (wufc && !(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC)))
 			/* ULP does not support wake from unicast, multicast
 			 * or broadcast.
 			 */
@@ -6581,12 +6607,17 @@
 static int e1000e_pm_suspend(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
+	int rc;
 
 	e1000e_flush_lpic(pdev);
 
 	e1000e_pm_freeze(dev);
 
-	return __e1000_shutdown(pdev, false);
+	rc = __e1000_shutdown(pdev, false);
+	if (rc)
+		e1000e_pm_thaw(dev);
+
+	return rc;
 }
 
 static int e1000e_pm_resume(struct device *dev)
@@ -6631,7 +6662,7 @@
 		return rc;
 
 	if (netdev->flags & IFF_UP)
-		rc = e1000e_up(adapter);
+		e1000e_up(adapter);
 
 	return rc;
 }
@@ -6822,13 +6853,8 @@
 
 	e1000_init_manageability_pt(adapter);
 
-	if (netif_running(netdev)) {
-		if (e1000e_up(adapter)) {
-			dev_err(&pdev->dev,
-				"can't bring device back up after reset\n");
-			return;
-		}
-	}
+	if (netif_running(netdev))
+		e1000e_up(adapter);
 
 	netif_device_attach(netdev);
 
@@ -7465,6 +7491,11 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V), board_pch_spt },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM2), board_pch_spt },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V2), board_pch_spt },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LBG_I219_LM3), board_pch_spt },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM4), board_pch_spt },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V4), board_pch_spt },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM5), board_pch_spt },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V5), board_pch_spt },
 
 	{ 0, 0, 0, 0, 0, 0, 0 }	/* terminate list */
 };
@@ -7504,14 +7535,11 @@
  **/
 static int __init e1000_init_module(void)
 {
-	int ret;
-
 	pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
 		e1000e_driver_version);
 	pr_info("Copyright(c) 1999 - 2015 Intel Corporation.\n");
-	ret = pci_register_driver(&e1000_driver);
 
-	return ret;
+	return pci_register_driver(&e1000_driver);
 }
 module_init(e1000_init_module);
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/phy.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/phy.c
@@ -1744,6 +1744,7 @@
 	s32 ret_val = 0;
 	u16 i, phy_status;
 
+	*success = false;
 	for (i = 0; i < iterations; i++) {
 		/* Some PHYs require the MII_BMSR register to be read
 		 * twice due to the link bit being sticky.  No harm doing
@@ -1763,16 +1764,16 @@
 		ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
 		if (ret_val)
 			break;
-		if (phy_status & BMSR_LSTATUS)
+		if (phy_status & BMSR_LSTATUS) {
+			*success = true;
 			break;
+		}
 		if (usec_interval >= 1000)
 			msleep(usec_interval / 1000);
 		else
 			udelay(usec_interval);
 	}
 
-	*success = (i < iterations);
-
 	return ret_val;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/ptp.c
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -26,6 +26,12 @@
 
 #include "e1000.h"
 
+#ifdef CONFIG_E1000E_HWTS
+#include <linux/clocksource.h>
+#include <linux/ktime.h>
+#include <asm/tsc.h>
+#endif
+
 /**
  * e1000e_phc_adjfreq - adjust the frequency of the hardware clock
  * @ptp: ptp clock structure
@@ -98,6 +104,78 @@
 	return 0;
 }
 
+#ifdef CONFIG_E1000E_HWTS
+#define MAX_HW_WAIT_COUNT (3)
+
+/**
+ * e1000e_phc_get_syncdevicetime - Callback given to timekeeping code reads system/device registers
+ * @device: current device time
+ * @system: system counter value read synchronously with device time
+ * @ctx: context provided by timekeeping code
+ *
+ * Read device and system (ART) clock simultaneously and return the corrected
+ * clock values in ns.
+ **/
+static int e1000e_phc_get_syncdevicetime(ktime_t *device,
+					 struct system_counterval_t *system,
+					 void *ctx)
+{
+	struct e1000_adapter *adapter = (struct e1000_adapter *)ctx;
+	struct e1000_hw *hw = &adapter->hw;
+	unsigned long flags;
+	int i;
+	u32 tsync_ctrl;
+	cycle_t dev_cycles;
+	cycle_t sys_cycles;
+
+	tsync_ctrl = er32(TSYNCTXCTL);
+	tsync_ctrl |= E1000_TSYNCTXCTL_START_SYNC |
+		E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK;
+	ew32(TSYNCTXCTL, tsync_ctrl);
+	for (i = 0; i < MAX_HW_WAIT_COUNT; ++i) {
+		udelay(1);
+		tsync_ctrl = er32(TSYNCTXCTL);
+		if (tsync_ctrl & E1000_TSYNCTXCTL_SYNC_COMP)
+			break;
+	}
+
+	if (i == MAX_HW_WAIT_COUNT)
+		return -ETIMEDOUT;
+
+	dev_cycles = er32(SYSSTMPH);
+	dev_cycles <<= 32;
+	dev_cycles |= er32(SYSSTMPL);
+	spin_lock_irqsave(&adapter->systim_lock, flags);
+	*device = ns_to_ktime(timecounter_cyc2time(&adapter->tc, dev_cycles));
+	spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+	sys_cycles = er32(PLTSTMPH);
+	sys_cycles <<= 32;
+	sys_cycles |= er32(PLTSTMPL);
+	*system = convert_art_to_tsc(sys_cycles);
+
+	return 0;
+}
+
+/**
+ * e1000e_phc_getsynctime - Reads the current system/device cross timestamp
+ * @ptp: ptp clock structure
+ * @cts: structure containing timestamp
+ *
+ * Read device and system (ART) clock simultaneously and return the scaled
+ * clock values in ns.
+ **/
+static int e1000e_phc_getcrosststamp(struct ptp_clock_info *ptp,
+				     struct system_device_crosststamp *xtstamp)
+{
+	struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+						     ptp_clock_info);
+
+	return get_device_system_crosststamp(e1000e_phc_get_syncdevicetime,
+						adapter, NULL, xtstamp);
+}
+#endif/*CONFIG_E1000E_HWTS*/
+
 /**
  * e1000e_phc_gettime - Reads the current time from the hardware clock
  * @ptp: ptp clock structure
@@ -111,10 +189,14 @@
 	struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
 						     ptp_clock_info);
 	unsigned long flags;
-	u64 ns;
+	u64 cycles, ns;
 
 	spin_lock_irqsave(&adapter->systim_lock, flags);
-	ns = timecounter_read(&adapter->tc);
+
+	/* Use timecounter_cyc2time() to allow non-monotonic SYSTIM readings */
+	cycles = adapter->cc.read(&adapter->cc);
+	ns = timecounter_cyc2time(&adapter->tc, cycles);
+
 	spin_unlock_irqrestore(&adapter->systim_lock, flags);
 
 	*ts = ns_to_timespec64(ns);
@@ -170,9 +252,12 @@
 						     systim_overflow_work.work);
 	struct e1000_hw *hw = &adapter->hw;
 	struct timespec64 ts;
+	u64 ns;
 
-	adapter->ptp_clock_info.gettime64(&adapter->ptp_clock_info, &ts);
+	/* Update the timecounter */
+	ns = timecounter_read(&adapter->tc);
 
+	ts = ns_to_timespec64(ns);
 	e_dbg("SYSTIM overflow check at %lld.%09lu\n",
 	      (long long) ts.tv_sec, ts.tv_nsec);
 
@@ -236,6 +321,13 @@
 		break;
 	}
 
+#ifdef CONFIG_E1000E_HWTS
+	/* CPU must have ART and GBe must be from Sunrise Point or greater */
+	if (hw->mac.type >= e1000_pch_spt && boot_cpu_has(X86_FEATURE_ART))
+		adapter->ptp_clock_info.getcrosststamp =
+			e1000e_phc_getcrosststamp;
+#endif/*CONFIG_E1000E_HWTS*/
+
 	INIT_DELAYED_WORK(&adapter->systim_overflow_work,
 			  e1000e_systim_overflow_work);
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/e1000e/regs.h
+++ linux-4.4.0/drivers/net/ethernet/intel/e1000e/regs.h
@@ -245,6 +245,10 @@
 #define E1000_SYSTIML	0x0B600	/* System time register Low - RO */
 #define E1000_SYSTIMH	0x0B604	/* System time register High - RO */
 #define E1000_TIMINCA	0x0B608	/* Increment attributes register - RW */
+#define E1000_SYSSTMPL  0x0B648 /* HH Timesync system stamp low register */
+#define E1000_SYSSTMPH  0x0B64C /* HH Timesync system stamp hi register */
+#define E1000_PLTSTMPL  0x0B640 /* HH Timesync platform stamp low register */
+#define E1000_PLTSTMPH  0x0B644 /* HH Timesync platform stamp hi register */
 #define E1000_RXMTRL	0x0B634	/* Time sync Rx EtherType and Msg Type - RW */
 #define E1000_RXUDP	0x0B638	/* Time Sync Rx UDP Port - RW */
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/Makefile
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/Makefile
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel Ethernet Switch Host Interface Driver
-# Copyright(c) 2013 - 2014 Intel Corporation.
+# Copyright(c) 2013 - 2015 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
@@ -27,7 +27,17 @@
 
 obj-$(CONFIG_FM10K) += fm10k.o
 
-fm10k-objs := fm10k_main.o fm10k_common.o fm10k_pci.o \
-	      fm10k_netdev.o fm10k_ethtool.o fm10k_pf.o fm10k_vf.o \
-	      fm10k_mbx.o fm10k_iov.o fm10k_tlv.o \
-	      fm10k_debugfs.o fm10k_ptp.o fm10k_dcbnl.o
+fm10k-y := fm10k_main.o \
+	   fm10k_common.o \
+	   fm10k_pci.o \
+	   fm10k_ptp.o \
+	   fm10k_netdev.o \
+	   fm10k_ethtool.o \
+	   fm10k_pf.o \
+	   fm10k_vf.o \
+	   fm10k_mbx.o \
+	   fm10k_iov.o \
+	   fm10k_tlv.o
+
+fm10k-$(CONFIG_DEBUG_FS) += fm10k_debugfs.o
+fm10k-$(CONFIG_DCB) += fm10k_dcbnl.o
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k.h
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k.h
@@ -23,6 +23,7 @@
 
 #include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <linux/cpumask.h>
 #include <linux/rtnetlink.h>
 #include <linux/if_vlan.h>
 #include <linux/pci.h>
@@ -33,7 +34,7 @@
 #include "fm10k_pf.h"
 #include "fm10k_vf.h"
 
-#define FM10K_MAX_JUMBO_FRAME_SIZE	15358	/* Maximum supported size 15K */
+#define FM10K_MAX_JUMBO_FRAME_SIZE	15342	/* Maximum supported size 15K */
 
 #define MAX_QUEUES	FM10K_MAX_QUEUES_PF
 
@@ -66,6 +67,7 @@
 enum fm10k_ring_state_t {
 	__FM10K_TX_DETECT_HANG,
 	__FM10K_HANG_CHECK_ARMED,
+	__FM10K_TX_XPS_INIT_DONE,
 };
 
 #define check_for_tx_hang(ring) \
@@ -138,7 +140,7 @@
 					 * different for DCB and RSS modes
 					 */
 	u8 qos_pc;			/* priority class of queue */
-	u16 vid;			/* default vlan ID of queue */
+	u16 vid;			/* default VLAN ID of queue */
 	u16 count;			/* amount of descriptors */
 
 	u16 next_to_alloc;
@@ -164,14 +166,20 @@
 	unsigned int total_packets;	/* total packets processed this int */
 	u16 work_limit;			/* total work allowed per interrupt */
 	u16 itr;			/* interrupt throttle rate value */
+	u8 itr_scale;			/* ITR adjustment based on PCI speed */
 	u8 count;			/* total number of rings in vector */
 };
 
 #define FM10K_ITR_MAX		0x0FFF	/* maximum value for ITR */
 #define FM10K_ITR_10K		100	/* 100us */
 #define FM10K_ITR_20K		50	/* 50us */
+#define FM10K_ITR_40K		25	/* 25us */
 #define FM10K_ITR_ADAPTIVE	0x8000	/* adaptive interrupt moderation flag */
 
+#define ITR_IS_ADAPTIVE(itr) (!!(itr & FM10K_ITR_ADAPTIVE))
+
+#define FM10K_TX_ITR_DEFAULT	FM10K_ITR_40K
+#define FM10K_RX_ITR_DEFAULT	FM10K_ITR_20K
 #define FM10K_ITR_ENABLE	(FM10K_ITR_AUTOMASK | FM10K_ITR_MASK_CLEAR)
 
 static inline struct netdev_queue *txring_txq(const struct fm10k_ring *ring)
@@ -203,6 +211,7 @@
 	struct fm10k_ring_container rx, tx;
 
 	struct napi_struct napi;
+	cpumask_t affinity_mask;
 	char name[IFNAMSIZ + 9];
 
 #ifdef CONFIG_DEBUG_FS
@@ -413,7 +422,7 @@
 	 (&(((union fm10k_rx_desc *)((R)->desc))[i]))
 
 #define FM10K_MAX_TXD_PWR	14
-#define FM10K_MAX_DATA_PER_TXD	(1 << FM10K_MAX_TXD_PWR)
+#define FM10K_MAX_DATA_PER_TXD	BIT(FM10K_MAX_TXD_PWR)
 
 /* Tx Descriptors needed, worst case */
 #define TXD_USE_COUNT(S)	DIV_ROUND_UP((S), FM10K_MAX_DATA_PER_TXD)
@@ -434,7 +443,7 @@
 	struct {
 		/* dglort and sglort combined into a single 32bit desc read */
 		__le32 glort;
-		/* upper 16 bits of vlan are reserved 0 for swpri_type_user */
+		/* upper 16 bits of VLAN are reserved 0 for swpri_type_user */
 		__le32 vlan;
 	} d;
 	struct {
@@ -484,7 +493,7 @@
 #endif
 
 /* Netdev */
-struct net_device *fm10k_alloc_netdev(void);
+struct net_device *fm10k_alloc_netdev(const struct fm10k_info *info);
 int fm10k_setup_rx_resources(struct fm10k_ring *);
 int fm10k_setup_tx_resources(struct fm10k_ring *);
 void fm10k_free_rx_resources(struct fm10k_ring *);
@@ -551,5 +560,9 @@
 int fm10k_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
 
 /* DCB */
+#ifdef CONFIG_DCB
 void fm10k_dcbnl_set_ops(struct net_device *dev);
+#else
+static inline void fm10k_dcbnl_set_ops(struct net_device *dev) {}
+#endif
 #endif /* _FM10K_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c
@@ -20,7 +20,6 @@
 
 #include "fm10k.h"
 
-#ifdef CONFIG_DCB
 /**
  * fm10k_dcbnl_ieee_getets - get the ETS configuration for the device
  * @dev: netdev interface for the device
@@ -155,7 +154,6 @@
 	.setdcbx	= fm10k_dcbnl_setdcbx,
 };
 
-#endif /* CONFIG_DCB */
 /**
  * fm10k_dcbnl_set_ops - Configures dcbnl ops pointer for netdev
  * @dev: netdev interface for the device
@@ -164,11 +162,9 @@
  **/
 void fm10k_dcbnl_set_ops(struct net_device *dev)
 {
-#ifdef CONFIG_DCB
 	struct fm10k_intfc *interface = netdev_priv(dev);
 	struct fm10k_hw *hw = &interface->hw;
 
 	if (hw->mac.type == fm10k_mac_pf)
 		dev->dcbnl_ops = &fm10k_dcbnl_ops;
-#endif /* CONFIG_DCB */
 }
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c
@@ -18,8 +18,6 @@
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  */
 
-#ifdef CONFIG_DEBUG_FS
-
 #include "fm10k.h"
 
 #include <linux/debugfs.h>
@@ -258,5 +256,3 @@
 	debugfs_remove_recursive(dbg_root);
 	dbg_root = NULL;
 }
-
-#endif /* CONFIG_DEBUG_FS */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
@@ -111,12 +111,14 @@
 
 static const struct fm10k_stats fm10k_gstrings_mbx_stats[] = {
 	FM10K_MBX_STAT("mbx_tx_busy", tx_busy),
-	FM10K_MBX_STAT("mbx_tx_oversized", tx_dropped),
+	FM10K_MBX_STAT("mbx_tx_dropped", tx_dropped),
 	FM10K_MBX_STAT("mbx_tx_messages", tx_messages),
 	FM10K_MBX_STAT("mbx_tx_dwords", tx_dwords),
+	FM10K_MBX_STAT("mbx_tx_mbmem_pulled", tx_mbmem_pulled),
 	FM10K_MBX_STAT("mbx_rx_messages", rx_messages),
 	FM10K_MBX_STAT("mbx_rx_dwords", rx_dwords),
 	FM10K_MBX_STAT("mbx_rx_parse_err", rx_parse_err),
+	FM10K_MBX_STAT("mbx_rx_mbmem_pushed", rx_mbmem_pushed),
 };
 
 #define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats)
@@ -125,7 +127,7 @@
 #define FM10K_MBX_STATS_LEN ARRAY_SIZE(fm10k_gstrings_mbx_stats)
 
 #define FM10K_QUEUE_STATS_LEN(_n) \
-	( (_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64)))
+	((_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64)))
 
 #define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \
 				FM10K_NETDEV_STATS_LEN + \
@@ -257,7 +259,8 @@
 			stats_len += FM10K_DEBUG_STATS_LEN;
 
 			if (iov_data)
-				stats_len += FM10K_MBX_STATS_LEN * iov_data->num_vfs;
+				stats_len += FM10K_MBX_STATS_LEN *
+					iov_data->num_vfs;
 		}
 
 		return stats_len;
@@ -296,14 +299,16 @@
 
 	if (interface->flags & FM10K_FLAG_DEBUG_STATS) {
 		for (i = 0; i < FM10K_DEBUG_STATS_LEN; i++) {
-			p = (char *)interface + fm10k_gstrings_debug_stats[i].stat_offset;
+			p = (char *)interface +
+				fm10k_gstrings_debug_stats[i].stat_offset;
 			*(data++) = (fm10k_gstrings_debug_stats[i].sizeof_stat ==
 				     sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
 		}
 	}
 
 	for (i = 0; i < FM10K_MBX_STATS_LEN; i++) {
-		p = (char *)&interface->hw.mbx + fm10k_gstrings_mbx_stats[i].stat_offset;
+		p = (char *)&interface->hw.mbx +
+			fm10k_gstrings_mbx_stats[i].stat_offset;
 		*(data++) = (fm10k_gstrings_mbx_stats[i].sizeof_stat ==
 			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
 	}
@@ -320,6 +325,7 @@
 	if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) {
 		for (i = 0; i < iov_data->num_vfs; i++) {
 			struct fm10k_vf_info *vf_info;
+
 			vf_info = &iov_data->vf_info[i];
 
 			/* skip stats if we don't have a vf info */
@@ -329,7 +335,8 @@
 			}
 
 			for (j = 0; j < FM10K_MBX_STATS_LEN; j++) {
-				p = (char *)&vf_info->mbx + fm10k_gstrings_mbx_stats[j].stat_offset;
+				p = (char *)&vf_info->mbx +
+					fm10k_gstrings_mbx_stats[j].stat_offset;
 				*(data++) = (fm10k_gstrings_mbx_stats[j].sizeof_stat ==
 					     sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
 			}
@@ -699,12 +706,10 @@
 {
 	struct fm10k_intfc *interface = netdev_priv(dev);
 
-	ec->use_adaptive_tx_coalesce =
-		!!(interface->tx_itr & FM10K_ITR_ADAPTIVE);
+	ec->use_adaptive_tx_coalesce = ITR_IS_ADAPTIVE(interface->tx_itr);
 	ec->tx_coalesce_usecs = interface->tx_itr & ~FM10K_ITR_ADAPTIVE;
 
-	ec->use_adaptive_rx_coalesce =
-		!!(interface->rx_itr & FM10K_ITR_ADAPTIVE);
+	ec->use_adaptive_rx_coalesce = ITR_IS_ADAPTIVE(interface->rx_itr);
 	ec->rx_coalesce_usecs = interface->rx_itr & ~FM10K_ITR_ADAPTIVE;
 
 	return 0;
@@ -729,10 +734,10 @@
 
 	/* set initial values for adaptive ITR */
 	if (ec->use_adaptive_tx_coalesce)
-		tx_itr = FM10K_ITR_ADAPTIVE | FM10K_ITR_10K;
+		tx_itr = FM10K_ITR_ADAPTIVE | FM10K_TX_ITR_DEFAULT;
 
 	if (ec->use_adaptive_rx_coalesce)
-		rx_itr = FM10K_ITR_ADAPTIVE | FM10K_ITR_20K;
+		rx_itr = FM10K_ITR_ADAPTIVE | FM10K_RX_ITR_DEFAULT;
 
 	/* update interface */
 	interface->tx_itr = tx_itr;
@@ -983,7 +988,7 @@
 
 	memset(data, 0, sizeof(*data) * FM10K_TEST_LEN);
 
-	if (FM10K_REMOVED(hw)) {
+	if (FM10K_REMOVED(hw->hw_addr)) {
 		netif_err(interface, drv, dev,
 			  "Interface removed - test blocked\n");
 		eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1020,7 +1025,6 @@
 	return 0;
 }
 
-
 static u32 fm10k_get_reta_size(struct net_device __always_unused *netdev)
 {
 	return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_iov.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_iov.c
@@ -126,6 +126,9 @@
 		struct fm10k_mbx_info *mbx = &vf_info->mbx;
 		u16 glort = vf_info->glort;
 
+		/* process the SM mailbox first to drain outgoing messages */
+		hw->mbx.ops.process(hw, &hw->mbx);
+
 		/* verify port mapping is valid, if not reset port */
 		if (vf_info->vf_flags && !fm10k_glort_valid_pf(hw, glort))
 			hw->iov.ops.reset_lport(hw, vf_info);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -28,7 +28,7 @@
 
 #include "fm10k.h"
 
-#define DRV_VERSION	"0.15.2-k"
+#define DRV_VERSION	"0.19.3-k"
 const char fm10k_driver_version[] = DRV_VERSION;
 char fm10k_driver_name[] = "fm10k";
 static const char fm10k_driver_string[] =
@@ -42,7 +42,7 @@
 MODULE_VERSION(DRV_VERSION);
 
 /* single workqueue for entire fm10k driver */
-struct workqueue_struct *fm10k_workqueue = NULL;
+struct workqueue_struct *fm10k_workqueue;
 
 /**
  * fm10k_init_module - Driver Registration Routine
@@ -56,8 +56,7 @@
 	pr_info("%s\n", fm10k_copyright);
 
 	/* create driver workqueue */
-	if (!fm10k_workqueue)
-		fm10k_workqueue = create_workqueue("fm10k");
+	fm10k_workqueue = create_workqueue("fm10k");
 
 	fm10k_dbg_init();
 
@@ -80,7 +79,6 @@
 	/* destroy driver workqueue */
 	flush_workqueue(fm10k_workqueue);
 	destroy_workqueue(fm10k_workqueue);
-	fm10k_workqueue = NULL;
 }
 module_exit(fm10k_exit_module);
 
@@ -917,7 +915,7 @@
 	/* set timestamping bits */
 	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
 	    likely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
-			desc_flags |= FM10K_TXD_FLAG_TIME;
+		desc_flags |= FM10K_TXD_FLAG_TIME;
 
 	/* set checksum offload bits */
 	desc_flags |= FM10K_SET_FLAG(tx_flags, FM10K_TX_FLAGS_CSUM,
@@ -1094,11 +1092,11 @@
 netdev_tx_t fm10k_xmit_frame_ring(struct sk_buff *skb,
 				  struct fm10k_ring *tx_ring)
 {
+	u16 count = TXD_USE_COUNT(skb_headlen(skb));
 	struct fm10k_tx_buffer *first;
-	int tso;
-	u32 tx_flags = 0;
 	unsigned short f;
-	u16 count = TXD_USE_COUNT(skb_headlen(skb));
+	u32 tx_flags = 0;
+	int tso;
 
 	/* need: 1 descriptor per page * PAGE_SIZE/FM10K_MAX_DATA_PER_TXD,
 	 *       + 1 desc for skb_headlen/FM10K_MAX_DATA_PER_TXD,
@@ -1226,7 +1224,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		read_barrier_depends();
+		smp_rmb();
 
 		/* if DD is not set pending work has not been completed */
 		if (!(eop_desc->flags & FM10K_TXD_FLAG_DONE))
@@ -1363,10 +1361,10 @@
  **/
 static void fm10k_update_itr(struct fm10k_ring_container *ring_container)
 {
-	unsigned int avg_wire_size, packets;
+	unsigned int avg_wire_size, packets, itr_round;
 
 	/* Only update ITR if we are using adaptive setting */
-	if (!(ring_container->itr & FM10K_ITR_ADAPTIVE))
+	if (!ITR_IS_ADAPTIVE(ring_container->itr))
 		goto clear_counts;
 
 	packets = ring_container->total_packets;
@@ -1375,18 +1373,44 @@
 
 	avg_wire_size = ring_container->total_bytes / packets;
 
-	/* Add 24 bytes to size to account for CRC, preamble, and gap */
-	avg_wire_size += 24;
+	/* The following is a crude approximation of:
+	 *  wmem_default / (size + overhead) = desired_pkts_per_int
+	 *  rate / bits_per_byte / (size + ethernet overhead) = pkt_rate
+	 *  (desired_pkt_rate / pkt_rate) * usecs_per_sec = ITR value
+	 *
+	 * Assuming wmem_default is 212992 and overhead is 640 bytes per
+	 * packet, (256 skb, 64 headroom, 320 shared info), we can reduce the
+	 * formula down to
+	 *
+	 *  (34 * (size + 24)) / (size + 640) = ITR
+	 *
+	 * We first do some math on the packet size and then finally bitshift
+	 * by 8 after rounding up. We also have to account for PCIe link speed
+	 * difference as ITR scales based on this.
+	 */
+	if (avg_wire_size <= 360) {
+		/* Start at 250K ints/sec and gradually drop to 77K ints/sec */
+		avg_wire_size *= 8;
+		avg_wire_size += 376;
+	} else if (avg_wire_size <= 1152) {
+		/* 77K ints/sec to 45K ints/sec */
+		avg_wire_size *= 3;
+		avg_wire_size += 2176;
+	} else if (avg_wire_size <= 1920) {
+		/* 45K ints/sec to 38K ints/sec */
+		avg_wire_size += 4480;
+	} else {
+		/* plateau at a limit of 38K ints/sec */
+		avg_wire_size = 6656;
+	}
 
-	/* Don't starve jumbo frames */
-	if (avg_wire_size > 3000)
-		avg_wire_size = 3000;
-
-	/* Give a little boost to mid-size frames */
-	if ((avg_wire_size > 300) && (avg_wire_size < 1200))
-		avg_wire_size /= 3;
-	else
-		avg_wire_size /= 2;
+	/* Perform final bitshift for division after rounding up to ensure
+	 * that the calculation will never get below a 1. The bit shift
+	 * accounts for changes in the ITR due to PCIe link speed.
+	 */
+	itr_round = ACCESS_ONCE(ring_container->itr_scale) + 8;
+	avg_wire_size += (1 << itr_round) - 1;
+	avg_wire_size >>= itr_round;
 
 	/* write back value and retain adaptive flag */
 	ring_container->itr = avg_wire_size | FM10K_ITR_ADAPTIVE;
@@ -1428,11 +1452,15 @@
 	fm10k_for_each_ring(ring, q_vector->tx)
 		clean_complete &= fm10k_clean_tx_irq(q_vector, ring);
 
+	/* Handle case where we are called by netpoll with a budget of 0 */
+	if (budget <= 0)
+		return budget;
+
 	/* attempt to distribute budget to each queue fairly, but don't
 	 * allow the budget to go below 1 because we'll exit polling
 	 */
 	if (q_vector->rx.count > 1)
-		per_ring_budget = max(budget/q_vector->rx.count, 1);
+		per_ring_budget = max(budget / q_vector->rx.count, 1);
 	else
 		per_ring_budget = budget;
 
@@ -1600,6 +1628,7 @@
 	q_vector->tx.ring = ring;
 	q_vector->tx.work_limit = FM10K_DEFAULT_TX_WORK;
 	q_vector->tx.itr = interface->tx_itr;
+	q_vector->tx.itr_scale = interface->hw.mac.itr_scale;
 	q_vector->tx.count = txr_count;
 
 	while (txr_count) {
@@ -1628,6 +1657,7 @@
 	/* save Rx ring container info */
 	q_vector->rx.ring = ring;
 	q_vector->rx.itr = interface->rx_itr;
+	q_vector->rx.itr_scale = interface->hw.mac.itr_scale;
 	q_vector->rx.count = rxr_count;
 
 	while (rxr_count) {
@@ -1907,8 +1937,10 @@
 	u16 i, rss_i = interface->ring_feature[RING_F_RSS].indices;
 	u32 reta, base;
 
-	/* If the netdev is initialized we have to maintain table if possible */
-	if (interface->netdev->reg_state != NETREG_UNINITIALIZED) {
+	/* If the Rx flow indirection table has been configured manually, we
+	 * need to maintain it when possible.
+	 */
+	if (netif_is_rxfh_configured(interface->netdev)) {
 		for (i = FM10K_RETA_SIZE; i--;) {
 			reta = interface->reta[i];
 			if ((((reta << 24) >> 24) < rss_i) &&
@@ -1916,6 +1948,10 @@
 			    (((reta <<  8) >> 24) < rss_i) &&
 			    (((reta)       >> 24) < rss_i))
 				continue;
+
+			/* this should never happen */
+			dev_err(&interface->pdev->dev,
+				"RSS indirection table assigned flows out of queue bounds. Reconfiguring.\n");
 			goto repopulate_reta;
 		}
 
@@ -1966,8 +2002,10 @@
 
 	/* Allocate memory for queues */
 	err = fm10k_alloc_q_vectors(interface);
-	if (err)
+	if (err) {
+		fm10k_reset_msix_capability(interface);
 		return err;
+	}
 
 	/* Map rings to devices, and map devices to physical queues */
 	fm10k_assign_rings(interface);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
@@ -57,7 +57,7 @@
 }
 
 /**
- *  fm10k_fifo_empty - Test to verify if fifo is empty
+ *  fm10k_fifo_empty - Test to verify if FIFO is empty
  *  @fifo: pointer to FIFO
  *
  *  This function returns true if the FIFO is empty, else false
@@ -72,7 +72,7 @@
  *  @fifo: pointer to FIFO
  *  @offset: offset to add to head
  *
- *  This function returns the indices into the fifo based on head + offset
+ *  This function returns the indices into the FIFO based on head + offset
  **/
 static u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
 {
@@ -84,7 +84,7 @@
  *  @fifo: pointer to FIFO
  *  @offset: offset to add to tail
  *
- *  This function returns the indices into the fifo based on tail + offset
+ *  This function returns the indices into the FIFO based on tail + offset
  **/
 static u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
 {
@@ -160,7 +160,7 @@
 /**
  *  fm10k_mbx_tail_add - Determine new tail value with added offset
  *  @mbx: pointer to mailbox
- *  @offset: length to add to head offset
+ *  @offset: length to add to tail offset
  *
  *  This function takes the local tail index and recomputes it for
  *  a given length added as an offset.
@@ -176,7 +176,7 @@
 /**
  *  fm10k_mbx_tail_sub - Determine new tail value with subtracted offset
  *  @mbx: pointer to mailbox
- *  @offset: length to add to head offset
+ *  @offset: length to add to tail offset
  *
  *  This function takes the local tail index and recomputes it for
  *  a given length added as an offset.
@@ -240,7 +240,7 @@
 }
 
 /**
- *  fm10k_fifo_write_copy - pulls data off of msg and places it in fifo
+ *  fm10k_fifo_write_copy - pulls data off of msg and places it in FIFO
  *  @fifo: pointer to FIFO
  *  @msg: message array to populate
  *  @tail_offset: additional offset to add to tail pointer
@@ -336,6 +336,7 @@
 
 /**
  *  fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem
+ *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *
  *  This function will take a section of the Tx FIFO and copy it into the
@@ -375,6 +376,8 @@
 			if (!tail)
 				tail++;
 
+			mbx->tx_mbmem_pulled++;
+
 			/* write message to hardware FIFO */
 			fm10k_write_reg(hw, mbmem + tail++, *(head++));
 		} while (--len && --end);
@@ -459,6 +462,8 @@
 			if (!head)
 				head++;
 
+			mbx->rx_mbmem_pushed++;
+
 			/* read message from hardware FIFO */
 			*(tail++) = fm10k_read_reg(hw, mbmem + head++);
 		} while (--len && --end);
@@ -707,7 +712,7 @@
  *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *
- *  This function dequeues messages and hands them off to the tlv parser.
+ *  This function dequeues messages and hands them off to the TLV parser.
  *  It will return the number of messages processed when called.
  **/
 static u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw,
@@ -899,7 +904,7 @@
 }
 
 /**
- *  fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mailbox header
+ *  fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mbox hdr
  *  @mbx: pointer to mailbox
  *
  *  This function creates a fake disconnect header for loading into remote
@@ -920,7 +925,7 @@
 }
 
 /**
- *  fm10k_mbx_create_error_msg - Generate a error message
+ *  fm10k_mbx_create_error_msg - Generate an error message
  *  @mbx: pointer to mailbox
  *  @err: local error encountered
  *
@@ -953,7 +958,6 @@
 /**
  *  fm10k_mbx_validate_msg_hdr - Validate common fields in the message header
  *  @mbx: pointer to mailbox
- *  @msg: message array to read
  *
  *  This function will parse up the fields in the mailbox header and return
  *  an error if the header contains any of a number of invalid configurations
@@ -1017,11 +1021,12 @@
 
 /**
  *  fm10k_mbx_create_reply - Generate reply based on state and remote head
+ *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *  @head: acknowledgement number
  *
  *  This function will generate an outgoing message based on the current
- *  mailbox state and the remote fifo head.  It will return the length
+ *  mailbox state and the remote FIFO head.  It will return the length
  *  of the outgoing message excluding header on success, and a negative value
  *  on error.
  **/
@@ -1147,8 +1152,8 @@
 
 /**
  *  fm10k_mbx_process_connect - Process connect header
+ *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
- *  @msg: message array to process
  *
  *  This function will read an incoming connect header and reply with the
  *  appropriate message.  It will return a value indicating the number of
@@ -1194,6 +1199,7 @@
 
 /**
  *  fm10k_mbx_process_data - Process data header
+ *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *
  *  This function will read an incoming data header and reply with the
@@ -1235,6 +1241,7 @@
 
 /**
  *  fm10k_mbx_process_disconnect - Process disconnect header
+ *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *
  *  This function will read an incoming disconnect header and reply with the
@@ -1287,6 +1294,7 @@
 
 /**
  *  fm10k_mbx_process_error - Process error header
+ *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *
  *  This function will read an incoming error header and reply with the
@@ -1556,7 +1564,7 @@
  *  @id: ID reference for PF as it supports up to 64 PF/VF mailboxes
  *
  *  This function initializes the mailbox for use.  It will split the
- *  buffer provided an use that th populate both the Tx and Rx FIFO by
+ *  buffer provided and use that to populate both the Tx and Rx FIFO by
  *  evenly splitting it.  In order to allow for easy masking of head/tail
  *  the value reported in size must be a power of 2 and is reported in
  *  DWORDs, not bytes.  Any invalid values will cause the mailbox to return
@@ -1633,7 +1641,7 @@
  *  fm10k_sm_mbx_create_data_hdr - Generate a mailbox header for local FIFO
  *  @mbx: pointer to mailbox
  *
- *  This function returns a connection mailbox header
+ *  This function returns a data mailbox header
  **/
 static void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
 {
@@ -1726,8 +1734,6 @@
 	fm10k_sm_mbx_create_connect_hdr(mbx, 0);
 	fm10k_mbx_write(hw, mbx);
 
-	/* enable interrupt and notify other party of new message */
-
 	return 0;
 }
 
@@ -1771,7 +1777,7 @@
 }
 
 /**
- *  fm10k_mbx_validate_fifo_hdr - Validate fields in the remote FIFO header
+ *  fm10k_sm_mbx_validate_fifo_hdr - Validate fields in the remote FIFO header
  *  @mbx: pointer to mailbox
  *
  *  This function will parse up the fields in the mailbox header and return
@@ -1849,7 +1855,7 @@
 }
 
 /**
- *  fm10k_sm_mbx_create_error_message - Process an error in FIFO hdr
+ *  fm10k_sm_mbx_create_error_msg - Process an error in FIFO header
  *  @mbx: pointer to mailbox
  *  @err: local error encountered
  *
@@ -1879,6 +1885,7 @@
  *  fm10k_sm_mbx_receive - Take message from Rx mailbox FIFO and put it in Rx
  *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
+ *  @tail: tail index of message
  *
  *  This function will dequeue one message from the Rx switch manager mailbox
  *  FIFO and place it in the Rx mailbox FIFO for processing by software.
@@ -1918,6 +1925,7 @@
  *  fm10k_sm_mbx_transmit - Take message from Tx and put it in Tx mailbox FIFO
  *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
+ *  @head: head index of message
  *
  *  This function will dequeue one message from the Tx mailbox FIFO and place
  *  it in the Tx switch manager mailbox FIFO for processing by hardware.
@@ -1957,11 +1965,12 @@
 
 /**
  *  fm10k_sm_mbx_create_reply - Generate reply based on state and remote head
+ *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *  @head: acknowledgement number
  *
  *  This function will generate an outgoing message based on the current
- *  mailbox state and the remote fifo head.  It will return the length
+ *  mailbox state and the remote FIFO head.  It will return the length
  *  of the outgoing message excluding header on success, and a negative value
  *  on error.
  **/
@@ -2002,9 +2011,10 @@
  *  function can also be used to respond to an error as the connection
  *  resetting would also be a means of dealing with errors.
  **/
-static void fm10k_sm_mbx_process_reset(struct fm10k_hw *hw,
-				       struct fm10k_mbx_info *mbx)
+static s32 fm10k_sm_mbx_process_reset(struct fm10k_hw *hw,
+				      struct fm10k_mbx_info *mbx)
 {
+	s32 err = 0;
 	const enum fm10k_mbx_state state = mbx->state;
 
 	switch (state) {
@@ -2017,6 +2027,7 @@
 	case FM10K_STATE_OPEN:
 		/* flush any incomplete work */
 		fm10k_sm_mbx_connect_reset(mbx);
+		err = FM10K_ERR_RESET_REQUESTED;
 		break;
 	case FM10K_STATE_CONNECT:
 		/* Update remote value to match local value */
@@ -2026,6 +2037,8 @@
 	}
 
 	fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail);
+
+	return err;
 }
 
 /**
@@ -2073,7 +2086,7 @@
 }
 
 /**
- *  fm10k_sm_mbx_process - Process mailbox switch mailbox interrupt
+ *  fm10k_sm_mbx_process - Process switch manager mailbox interrupt
  *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *
@@ -2106,7 +2119,7 @@
 
 	switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) {
 	case 0:
-		fm10k_sm_mbx_process_reset(hw, mbx);
+		err = fm10k_sm_mbx_process_reset(hw, mbx);
 		break;
 	case FM10K_SM_MBX_VERSION:
 		err = fm10k_sm_mbx_process_version_1(hw, mbx);
@@ -2129,13 +2142,19 @@
  *  @mbx: pointer to mailbox
  *  @msg_data: handlers for mailbox events
  *
- *  This function for now is used to stub out the PF/SM mailbox
+ *  This function initializes the PF/SM mailbox for use.  It will split the
+ *  buffer provided and use that to populate both the Tx and Rx FIFO by
+ *  evenly splitting it.  In order to allow for easy masking of head/tail
+ *  the value reported in size must be a power of 2 and is reported in
+ *  DWORDs, not bytes.  Any invalid values will cause the mailbox to return
+ *  error.
  **/
 s32 fm10k_sm_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
 		      const struct fm10k_msg_data *msg_data)
 {
 	mbx->mbx_reg = FM10K_GMBX;
 	mbx->mbmem_reg = FM10K_MBMEM_PF(0);
+
 	/* start out in closed state */
 	mbx->state = FM10K_STATE_CLOSED;
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_mbx.h
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_mbx.h
@@ -1,5 +1,5 @@
 /* Intel Ethernet Switch Host Interface Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2015 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -128,11 +128,11 @@
  *		The maximum message size is provided during connect to avoid
  *		jamming the mailbox with messages that do not fit.
  * Err_no: Error number - Applies only to error headers
- *		The error number provides a indication of the type of error
+ *		The error number provides an indication of the type of error
  *		experienced.
  */
 
-/* macros for retriving and setting header values */
+/* macros for retrieving and setting header values */
 #define FM10K_MSG_HDR_MASK(name) \
 	((0x1u << FM10K_MSG_##name##_SIZE) - 1)
 #define FM10K_MSG_HDR_FIELD_SET(value, name) \
@@ -291,8 +291,10 @@
 	u64 tx_dropped;
 	u64 tx_messages;
 	u64 tx_dwords;
+	u64 tx_mbmem_pulled;
 	u64 rx_messages;
 	u64 rx_dwords;
+	u64 rx_mbmem_pushed;
 	u64 rx_parse_err;
 
 	/* Buffer to store messages */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
@@ -20,7 +20,7 @@
 
 #include "fm10k.h"
 #include <linux/vmalloc.h>
-#if IS_ENABLED(CONFIG_FM10K_VXLAN)
+#ifdef CONFIG_FM10K_VXLAN
 #include <net/vxlan.h>
 #endif /* CONFIG_FM10K_VXLAN */
 
@@ -556,11 +556,11 @@
 	if (err)
 		goto err_set_queues;
 
-#if IS_ENABLED(CONFIG_FM10K_VXLAN)
+#ifdef CONFIG_FM10K_VXLAN
 	/* update VXLAN port configuration */
 	vxlan_get_rx_port(netdev);
-
 #endif
+
 	fm10k_up(interface);
 
 	return 0;
@@ -608,7 +608,7 @@
 	unsigned int r_idx = skb->queue_mapping;
 	int err;
 
-	if ((skb->protocol ==  htons(ETH_P_8021Q)) &&
+	if ((skb->protocol == htons(ETH_P_8021Q)) &&
 	    !skb_vlan_tag_present(skb)) {
 		/* FM10K only supports hardware tagging, any tags in frame
 		 * are considered 2nd level or "outer" tags
@@ -632,7 +632,7 @@
 			return NETDEV_TX_OK;
 		}
 
-		/* locate vlan header */
+		/* locate VLAN header */
 		vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
 
 		/* pull the 2 key pieces of data out of it */
@@ -705,7 +705,7 @@
 	} else {
 		netif_info(interface, drv, netdev,
 			   "Fake Tx hang detected with timeout of %d seconds\n",
-			   netdev->watchdog_timeo/HZ);
+			   netdev->watchdog_timeo / HZ);
 
 		/* fake Tx hang - increase the kernel timeout */
 		if (netdev->watchdog_timeo < TX_TIMEO_LIMIT)
@@ -778,7 +778,7 @@
 	if (!set)
 		clear_bit(vid, interface->active_vlans);
 
-	/* disable the default VID on ring if we have an active VLAN */
+	/* disable the default VLAN ID on ring if we have an active VLAN */
 	for (i = 0; i < interface->num_rx_queues; i++) {
 		struct fm10k_ring *rx_ring = interface->rx_ring[i];
 		u16 rx_vid = rx_ring->vid & (VLAN_N_VID - 1);
@@ -789,7 +789,9 @@
 			rx_ring->vid &= ~FM10K_VLAN_CLEAR;
 	}
 
-	/* Do not remove default VID related entries from VLAN and MAC tables */
+	/* Do not remove default VLAN ID related entries from VLAN and MAC
+	 * tables
+	 */
 	if (!set && vid == hw->mac.default_vid)
 		return 0;
 
@@ -814,7 +816,7 @@
 	if (err)
 		goto err_out;
 
-	/* set vid prior to syncing/unsyncing the VLAN */
+	/* set VLAN ID prior to syncing/unsyncing the VLAN */
 	interface->vid = vid + (set ? VLAN_N_VID : 0);
 
 	/* Update the unicast and multicast address list to add/drop VLAN */
@@ -1151,6 +1153,7 @@
 int fm10k_setup_tc(struct net_device *dev, u8 tc)
 {
 	struct fm10k_intfc *interface = netdev_priv(dev);
+	int err;
 
 	/* Currently only the PF supports priority classes */
 	if (tc && (interface->hw.mac.type != fm10k_mac_pf))
@@ -1175,17 +1178,39 @@
 	netdev_reset_tc(dev);
 	netdev_set_num_tc(dev, tc);
 
-	fm10k_init_queueing_scheme(interface);
+	err = fm10k_init_queueing_scheme(interface);
+	if (err)
+		goto err_queueing_scheme;
 
-	fm10k_mbx_request_irq(interface);
+	err = fm10k_mbx_request_irq(interface);
+	if (err)
+		goto err_mbx_irq;
 
-	if (netif_running(dev))
-		fm10k_open(dev);
+	err = netif_running(dev) ? fm10k_open(dev) : 0;
+	if (err)
+		goto err_open;
 
 	/* flag to indicate SWPRI has yet to be updated */
 	interface->flags |= FM10K_FLAG_SWPRI_CONFIG;
 
 	return 0;
+err_open:
+	fm10k_mbx_free_irq(interface);
+err_mbx_irq:
+	fm10k_clear_queueing_scheme(interface);
+err_queueing_scheme:
+	netif_device_detach(dev);
+
+	return err;
+}
+
+static int __fm10k_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+			    struct tc_to_netdev *tc)
+{
+	if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+
+	return fm10k_setup_tc(dev, tc->tc);
 }
 
 static int fm10k_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
@@ -1370,7 +1395,7 @@
 	.ndo_vlan_rx_kill_vid	= fm10k_vlan_rx_kill_vid,
 	.ndo_set_rx_mode	= fm10k_set_rx_mode,
 	.ndo_get_stats64	= fm10k_get_stats64,
-	.ndo_setup_tc		= fm10k_setup_tc,
+	.ndo_setup_tc		= __fm10k_setup_tc,
 	.ndo_set_vf_mac		= fm10k_ndo_set_vf_mac,
 	.ndo_set_vf_vlan	= fm10k_ndo_set_vf_vlan,
 	.ndo_set_vf_rate	= fm10k_ndo_set_vf_bw,
@@ -1388,8 +1413,9 @@
 
 #define DEFAULT_DEBUG_LEVEL_SHIFT 3
 
-struct net_device *fm10k_alloc_netdev(void)
+struct net_device *fm10k_alloc_netdev(const struct fm10k_info *info)
 {
+	netdev_features_t hw_features;
 	struct fm10k_intfc *interface;
 	struct net_device *dev;
 
@@ -1412,27 +1438,31 @@
 			 NETIF_F_TSO |
 			 NETIF_F_TSO6 |
 			 NETIF_F_TSO_ECN |
-			 NETIF_F_GSO_UDP_TUNNEL |
 			 NETIF_F_RXHASH |
 			 NETIF_F_RXCSUM;
 
+	/* Only the PF can support VXLAN and NVGRE tunnel offloads */
+	if (info->mac == fm10k_mac_pf) {
+		dev->hw_enc_features = NETIF_F_IP_CSUM |
+				       NETIF_F_TSO |
+				       NETIF_F_TSO6 |
+				       NETIF_F_TSO_ECN |
+				       NETIF_F_GSO_UDP_TUNNEL |
+				       NETIF_F_IPV6_CSUM |
+				       NETIF_F_SG;
+
+		dev->features |= NETIF_F_GSO_UDP_TUNNEL;
+	}
+
 	/* all features defined to this point should be changeable */
-	dev->hw_features |= dev->features;
+	hw_features = dev->features;
 
 	/* allow user to enable L2 forwarding acceleration */
-	dev->hw_features |= NETIF_F_HW_L2FW_DOFFLOAD;
+	hw_features |= NETIF_F_HW_L2FW_DOFFLOAD;
 
 	/* configure VLAN features */
 	dev->vlan_features |= dev->features;
 
-	/* configure tunnel offloads */
-	dev->hw_enc_features |= NETIF_F_IP_CSUM |
-				NETIF_F_TSO |
-				NETIF_F_TSO6 |
-				NETIF_F_TSO_ECN |
-				NETIF_F_GSO_UDP_TUNNEL |
-				NETIF_F_IPV6_CSUM;
-
 	/* we want to leave these both on as we cannot disable VLAN tag
 	 * insertion or stripping on the hardware since it is contained
 	 * in the FTAG and not in the frame itself.
@@ -1443,5 +1473,7 @@
 
 	dev->priv_flags |= IFF_UNICAST_FLT;
 
+	dev->hw_features |= hw_features;
+
 	return dev;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
@@ -159,16 +159,40 @@
 
 	fm10k_mbx_free_irq(interface);
 
+	/* free interrupts */
+	fm10k_clear_queueing_scheme(interface);
+
 	/* delay any future reset requests */
 	interface->last_reset = jiffies + (10 * HZ);
 
 	/* reset and initialize the hardware so it is in a known state */
-	err = hw->mac.ops.reset_hw(hw) ? : hw->mac.ops.init_hw(hw);
-	if (err)
+	err = hw->mac.ops.reset_hw(hw);
+	if (err) {
+		dev_err(&interface->pdev->dev, "reset_hw failed: %d\n", err);
+		goto reinit_err;
+	}
+
+	err = hw->mac.ops.init_hw(hw);
+	if (err) {
 		dev_err(&interface->pdev->dev, "init_hw failed: %d\n", err);
+		goto reinit_err;
+	}
+
+	err = fm10k_init_queueing_scheme(interface);
+	if (err) {
+		dev_err(&interface->pdev->dev,
+			"init_queueing_scheme failed: %d\n", err);
+		goto reinit_err;
+	}
 
 	/* reassociate interrupts */
-	fm10k_mbx_request_irq(interface);
+	err = fm10k_mbx_request_irq(interface);
+	if (err)
+		goto err_mbx_irq;
+
+	err = fm10k_hw_ready(interface);
+	if (err)
+		goto err_open;
 
 	/* update hardware address for VFs if perm_addr has changed */
 	if (hw->mac.type == fm10k_mac_vf) {
@@ -188,14 +212,27 @@
 	/* reset clock */
 	fm10k_ts_reset(interface);
 
-	if (netif_running(netdev))
-		fm10k_open(netdev);
+	err = netif_running(netdev) ? fm10k_open(netdev) : 0;
+	if (err)
+		goto err_open;
 
 	fm10k_iov_resume(interface->pdev);
 
 	rtnl_unlock();
 
 	clear_bit(__FM10K_RESETTING, &interface->state);
+
+	return;
+err_open:
+	fm10k_mbx_free_irq(interface);
+err_mbx_irq:
+	fm10k_clear_queueing_scheme(interface);
+reinit_err:
+	netif_device_detach(netdev);
+
+	rtnl_unlock();
+
+	clear_bit(__FM10K_RESETTING, &interface->state);
 }
 
 static void fm10k_reset_subtask(struct fm10k_intfc *interface)
@@ -563,7 +600,7 @@
 	/* store tail pointer */
 	ring->tail = &interface->uc_addr[FM10K_TDT(reg_idx)];
 
-	/* reset ntu and ntc to place SW in sync with hardwdare */
+	/* reset ntu and ntc to place SW in sync with hardware */
 	ring->next_to_clean = 0;
 	ring->next_to_use = 0;
 
@@ -579,6 +616,13 @@
 	fm10k_write_reg(hw, FM10K_PFVTCTL(reg_idx),
 			FM10K_PFVTCTL_FTAG_DESC_ENABLE);
 
+	/* Initialize XPS */
+	if (!test_and_set_bit(__FM10K_TX_XPS_INIT_DONE, &ring->state) &&
+	    ring->q_vector)
+		netif_set_xps_queue(ring->netdev,
+				    &ring->q_vector->affinity_mask,
+				    ring->queue_index);
+
 	/* enable queue */
 	fm10k_write_reg(hw, FM10K_TXDCTL(reg_idx), txdctl);
 }
@@ -669,7 +713,7 @@
 	/* store tail pointer */
 	ring->tail = &interface->uc_addr[FM10K_RDT(reg_idx)];
 
-	/* reset ntu and ntc to place SW in sync with hardwdare */
+	/* reset ntu and ntc to place SW in sync with hardware */
 	ring->next_to_clean = 0;
 	ring->next_to_use = 0;
 	ring->next_to_alloc = 0;
@@ -694,7 +738,7 @@
 	/* assign default VLAN to queue */
 	ring->vid = hw->mac.default_vid;
 
-	/* if we have an active VLAN, disable default VID */
+	/* if we have an active VLAN, disable default VLAN ID */
 	if (test_bit(hw->mac.default_vid, interface->active_vlans))
 		ring->vid |= FM10K_VLAN_CLEAR;
 
@@ -846,7 +890,7 @@
 	struct fm10k_q_vector *q_vector = data;
 
 	if (q_vector->rx.count || q_vector->tx.count)
-		napi_schedule(&q_vector->napi);
+		napi_schedule_irqoff(&q_vector->napi);
 
 	return IRQ_HANDLED;
 }
@@ -859,7 +903,8 @@
 
 	/* re-enable mailbox interrupt and indicate 20us delay */
 	fm10k_write_reg(hw, FM10K_VFITR(FM10K_MBX_VECTOR),
-			FM10K_ITR_ENABLE | FM10K_MBX_INT_DELAY);
+			FM10K_ITR_ENABLE | (FM10K_MBX_INT_DELAY >>
+					    hw->mac.itr_scale));
 
 	/* service upstream mailbox */
 	if (fm10k_mbx_trylock(interface)) {
@@ -867,7 +912,7 @@
 		fm10k_mbx_unlock(interface);
 	}
 
-	hw->mac.get_host_state = 1;
+	hw->mac.get_host_state = true;
 	fm10k_service_event_schedule(interface);
 
 	return IRQ_HANDLED;
@@ -897,7 +942,7 @@
 #endif
 #define FM10K_ERR_MSG(type) case (type): error = #type; break
 static void fm10k_handle_fault(struct fm10k_intfc *interface, int type,
-			      struct fm10k_fault *fault)
+			       struct fm10k_fault *fault)
 {
 	struct pci_dev *pdev = interface->pdev;
 	struct fm10k_hw *hw = &interface->hw;
@@ -1051,6 +1096,7 @@
 	struct fm10k_hw *hw = &interface->hw;
 	struct fm10k_mbx_info *mbx = &hw->mbx;
 	u32 eicr;
+	s32 err = 0;
 
 	/* unmask any set bits related to this interrupt */
 	eicr = fm10k_read_reg(hw, FM10K_EICR);
@@ -1066,12 +1112,15 @@
 
 	/* service mailboxes */
 	if (fm10k_mbx_trylock(interface)) {
-		mbx->ops.process(hw, mbx);
+		err = mbx->ops.process(hw, mbx);
 		/* handle VFLRE events */
 		fm10k_iov_event(interface);
 		fm10k_mbx_unlock(interface);
 	}
 
+	if (err == FM10K_ERR_RESET_REQUESTED)
+		interface->flags |= FM10K_FLAG_RESET_REQUESTED;
+
 	/* if switch toggled state we should reset GLORTs */
 	if (eicr & FM10K_EICR_SWITCHNOTREADY) {
 		/* force link down for at least 4 seconds */
@@ -1083,14 +1132,15 @@
 	}
 
 	/* we should validate host state after interrupt event */
-	hw->mac.get_host_state = 1;
+	hw->mac.get_host_state = true;
 
 	/* validate host state, and handle VF mailboxes in the service task */
 	fm10k_service_event_schedule(interface);
 
 	/* re-enable mailbox interrupt and indicate 20us delay */
 	fm10k_write_reg(hw, FM10K_ITR(FM10K_MBX_VECTOR),
-			FM10K_ITR_ENABLE | FM10K_MBX_INT_DELAY);
+			FM10K_ITR_ENABLE | (FM10K_MBX_INT_DELAY >>
+					    hw->mac.itr_scale));
 
 	return IRQ_HANDLED;
 }
@@ -1101,6 +1151,10 @@
 	struct fm10k_hw *hw = &interface->hw;
 	int itr_reg;
 
+	/* no mailbox IRQ to free if MSI-X is not enabled */
+	if (!interface->msix_entries)
+		return;
+
 	/* disconnect the mailbox */
 	hw->mbx.ops.disconnect(hw, &hw->mbx);
 
@@ -1141,7 +1195,7 @@
 
 	/* MAC was changed so we need reset */
 	if (is_valid_ether_addr(hw->mac.perm_addr) &&
-	    memcmp(hw->mac.perm_addr, hw->mac.addr, ETH_ALEN))
+	    !ether_addr_equal(hw->mac.perm_addr, hw->mac.addr))
 		interface->flags |= FM10K_FLAG_RESET_REQUESTED;
 
 	/* VLAN override was changed, or default VLAN changed */
@@ -1269,7 +1323,7 @@
 	if (!fm10k_glort_valid_pf(hw, glort))
 		return FM10K_ERR_PARAM;
 
-	/* verify VID is valid */
+	/* verify VLAN ID is valid */
 	if (pvid >= FM10K_VLAN_TABLE_VID_MAX)
 		return FM10K_ERR_PARAM;
 
@@ -1388,14 +1442,14 @@
 	}
 
 	/* Enable interrupts w/ no moderation for "other" interrupts */
-	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_PCIeFault), other_itr);
-	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_SwitchUpDown), other_itr);
-	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_SRAM), other_itr);
-	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_MaxHoldTime), other_itr);
-	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_VFLR), other_itr);
+	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_pcie_fault), other_itr);
+	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_switch_up_down), other_itr);
+	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_sram), other_itr);
+	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_max_hold_time), other_itr);
+	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_vflr), other_itr);
 
 	/* Enable interrupts w/ moderation for mailbox */
-	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_Mailbox), mbx_itr);
+	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_mailbox), mbx_itr);
 
 	/* Enable individual interrupt causes */
 	fm10k_write_reg(hw, FM10K_EIMR, FM10K_EIMR_ENABLE(PCA_FAULT) |
@@ -1423,10 +1477,15 @@
 		err = fm10k_mbx_request_irq_pf(interface);
 	else
 		err = fm10k_mbx_request_irq_vf(interface);
+	if (err)
+		return err;
 
 	/* connect mailbox */
-	if (!err)
-		err = hw->mbx.ops.connect(hw, &hw->mbx);
+	err = hw->mbx.ops.connect(hw, &hw->mbx);
+
+	/* if the mailbox failed to connect, then free IRQ */
+	if (err)
+		fm10k_mbx_free_irq(interface);
 
 	return err;
 }
@@ -1455,8 +1514,10 @@
 		if (!q_vector->tx.count && !q_vector->rx.count)
 			continue;
 
-		/* disable interrupts */
+		/* clear the affinity_mask in the IRQ descriptor */
+		irq_set_affinity_hint(entry->vector, NULL);
 
+		/* disable interrupts */
 		writel(FM10K_ITR_MASK_SET, q_vector->itr);
 
 		free_irq(entry->vector, q_vector);
@@ -1514,6 +1575,9 @@
 			goto err_out;
 		}
 
+		/* assign the mask for this irq */
+		irq_set_affinity_hint(entry->vector, &q_vector->affinity_mask);
+
 		/* Enable q_vector */
 		writel(FM10K_ITR_ENABLE, q_vector->itr);
 
@@ -1534,8 +1598,10 @@
 		if (!q_vector->tx.count && !q_vector->rx.count)
 			continue;
 
-		/* disable interrupts */
+		/* clear the affinity_mask in the IRQ descriptor */
+		irq_set_affinity_hint(entry->vector, NULL);
 
+		/* disable interrupts */
 		writel(FM10K_ITR_MASK_SET, q_vector->itr);
 
 		free_irq(entry->vector, q_vector);
@@ -1573,7 +1639,7 @@
 	netif_tx_start_all_queues(interface->netdev);
 
 	/* kick off the service timer now */
-	hw->mac.get_host_state = 1;
+	hw->mac.get_host_state = true;
 	mod_timer(&interface->service_timer, jiffies);
 }
 
@@ -1684,7 +1750,13 @@
 	interface->last_reset = jiffies + (10 * HZ);
 
 	/* reset and initialize the hardware so it is in a known state */
-	err = hw->mac.ops.reset_hw(hw) ? : hw->mac.ops.init_hw(hw);
+	err = hw->mac.ops.reset_hw(hw);
+	if (err) {
+		dev_err(&pdev->dev, "reset_hw failed: %d\n", err);
+		return err;
+	}
+
+	err = hw->mac.ops.init_hw(hw);
 	if (err) {
 		dev_err(&pdev->dev, "init_hw failed: %d\n", err);
 		return err;
@@ -1722,13 +1794,6 @@
 					     pci_resource_len(pdev, 4));
 	hw->sw_addr = interface->sw_addr;
 
-	/* Only the PF can support VXLAN and NVGRE offloads */
-	if (hw->mac.type != fm10k_mac_pf) {
-		netdev->hw_enc_features = 0;
-		netdev->features &= ~NETIF_F_GSO_UDP_TUNNEL;
-		netdev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL;
-	}
-
 	/* initialize DCBNL interface */
 	fm10k_dcbnl_set_ops(netdev);
 
@@ -1749,8 +1814,8 @@
 	interface->rx_ring_count = FM10K_DEFAULT_RXD;
 
 	/* set default interrupt moderation */
-	interface->tx_itr = FM10K_ITR_10K;
-	interface->rx_itr = FM10K_ITR_ADAPTIVE | FM10K_ITR_20K;
+	interface->tx_itr = FM10K_TX_ITR_DEFAULT;
+	interface->rx_itr = FM10K_ITR_ADAPTIVE | FM10K_RX_ITR_DEFAULT;
 
 	/* initialize vxlan_port list */
 	INIT_LIST_HEAD(&interface->vxlan_port);
@@ -1835,17 +1900,18 @@
 		return;
 	}
 
-	if (max_gts < expected_gts) {
-		dev_warn(&interface->pdev->dev,
-			 "This device requires %dGT/s of bandwidth for optimal performance.\n",
-			 expected_gts);
-		dev_warn(&interface->pdev->dev,
-			 "A %sslot with x%d lanes is suggested.\n",
-			 (hw->bus_caps.speed == fm10k_bus_speed_2500 ? "2.5GT/s " :
-			  hw->bus_caps.speed == fm10k_bus_speed_5000 ? "5.0GT/s " :
-			  hw->bus_caps.speed == fm10k_bus_speed_8000 ? "8.0GT/s " : ""),
-			 hw->bus_caps.width);
-	}
+	if (max_gts >= expected_gts)
+		return;
+
+	dev_warn(&interface->pdev->dev,
+		 "This device requires %dGT/s of bandwidth for optimal performance.\n",
+		 expected_gts);
+	dev_warn(&interface->pdev->dev,
+		 "A %sslot with x%d lanes is suggested.\n",
+		 (hw->bus_caps.speed == fm10k_bus_speed_2500 ? "2.5GT/s " :
+		  hw->bus_caps.speed == fm10k_bus_speed_5000 ? "5.0GT/s " :
+		  hw->bus_caps.speed == fm10k_bus_speed_8000 ? "8.0GT/s " : ""),
+		 hw->bus_caps.width);
 }
 
 /**
@@ -1859,8 +1925,7 @@
  * The OS initialization, configuring of the interface private structure,
  * and a hardware reset occur.
  **/
-static int fm10k_probe(struct pci_dev *pdev,
-		       const struct pci_device_id *ent)
+static int fm10k_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *netdev;
 	struct fm10k_intfc *interface;
@@ -1894,7 +1959,7 @@
 	pci_set_master(pdev);
 	pci_save_state(pdev);
 
-	netdev = fm10k_alloc_netdev();
+	netdev = fm10k_alloc_netdev(fm10k_info_tbl[ent->driver_data]);
 	if (!netdev) {
 		err = -ENOMEM;
 		goto err_alloc_netdev;
@@ -2071,8 +2136,10 @@
 
 	/* reset hardware to known state */
 	err = hw->mac.ops.init_hw(&interface->hw);
-	if (err)
+	if (err) {
+		dev_err(&pdev->dev, "init_hw failed: %d\n", err);
 		return err;
+	}
 
 	/* reset statistics starting values */
 	hw->mac.ops.rebind_hw_stats(hw, &interface->stats);
@@ -2083,16 +2150,22 @@
 	rtnl_lock();
 
 	err = fm10k_init_queueing_scheme(interface);
-	if (!err) {
-		fm10k_mbx_request_irq(interface);
-		if (netif_running(netdev))
-			err = fm10k_open(netdev);
-	}
+	if (err)
+		goto err_queueing_scheme;
 
-	rtnl_unlock();
+	err = fm10k_mbx_request_irq(interface);
+	if (err)
+		goto err_mbx_irq;
 
+	err = fm10k_hw_ready(interface);
 	if (err)
-		return err;
+		goto err_open;
+
+	err = netif_running(netdev) ? fm10k_open(netdev) : 0;
+	if (err)
+		goto err_open;
+
+	rtnl_unlock();
 
 	/* assume host is not ready, to prevent race with watchdog in case we
 	 * actually don't have connection to the switch
@@ -2110,6 +2183,14 @@
 	netif_device_attach(netdev);
 
 	return 0;
+err_open:
+	fm10k_mbx_free_irq(interface);
+err_mbx_irq:
+	fm10k_clear_queueing_scheme(interface);
+err_queueing_scheme:
+	rtnl_unlock();
+
+	return err;
 }
 
 /**
@@ -2185,6 +2266,9 @@
 	if (netif_running(netdev))
 		fm10k_close(netdev);
 
+	/* free interrupts */
+	fm10k_clear_queueing_scheme(interface);
+
 	fm10k_mbx_free_irq(interface);
 
 	pci_disable_device(pdev);
@@ -2248,11 +2332,22 @@
 	int err = 0;
 
 	/* reset hardware to known state */
-	hw->mac.ops.init_hw(&interface->hw);
+	err = hw->mac.ops.init_hw(&interface->hw);
+	if (err) {
+		dev_err(&pdev->dev, "init_hw failed: %d\n", err);
+		return;
+	}
 
 	/* reset statistics starting values */
 	hw->mac.ops.rebind_hw_stats(hw, &interface->stats);
 
+	err = fm10k_init_queueing_scheme(interface);
+	if (err) {
+		dev_err(&interface->pdev->dev,
+			"init_queueing_scheme failed: %d\n", err);
+		return;
+	}
+
 	/* reassociate interrupts */
 	fm10k_mbx_request_irq(interface);
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
@@ -1,5 +1,5 @@
 /* Intel Ethernet Switch Host Interface Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2015 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -150,19 +150,26 @@
 				FM10K_TPH_RXCTRL_HDR_WROEN);
 	}
 
-	/* set max hold interval to align with 1.024 usec in all modes */
+	/* set max hold interval to align with 1.024 usec in all modes and
+	 * store ITR scale
+	 */
 	switch (hw->bus.speed) {
 	case fm10k_bus_speed_2500:
 		dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1;
+		hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN1;
 		break;
 	case fm10k_bus_speed_5000:
 		dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2;
+		hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN2;
 		break;
 	case fm10k_bus_speed_8000:
 		dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3;
+		hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3;
 		break;
 	default:
 		dma_ctrl = 0;
+		/* just in case, assume Gen3 ITR scale */
+		hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3;
 		break;
 	}
 
@@ -259,7 +266,6 @@
 {
 	u8 perm_addr[ETH_ALEN];
 	u32 serial_num;
-	int i;
 
 	serial_num = fm10k_read_reg(hw, FM10K_SM_AREA(1));
 
@@ -281,10 +287,8 @@
 	perm_addr[4] = (u8)(serial_num >> 8);
 	perm_addr[5] = (u8)(serial_num);
 
-	for (i = 0; i < ETH_ALEN; i++) {
-		hw->mac.perm_addr[i] = perm_addr[i];
-		hw->mac.addr[i] = perm_addr[i];
-	}
+	ether_addr_copy(hw->mac.perm_addr, perm_addr);
+	ether_addr_copy(hw->mac.addr, perm_addr);
 
 	return 0;
 }
@@ -325,7 +329,7 @@
 	/* clear set bit from VLAN ID */
 	vid &= ~FM10K_VLAN_CLEAR;
 
-	/* if glort or vlan are not valid return error */
+	/* if glort or VLAN are not valid return error */
 	if (!fm10k_glort_valid_pf(hw, glort) || vid >= FM10K_VLAN_TABLE_VID_MAX)
 		return FM10K_ERR_PARAM;
 
@@ -334,8 +338,8 @@
 						 ((u32)mac[3] << 16) |
 						 ((u32)mac[4] << 8) |
 						 ((u32)mac[5]));
-	mac_update.mac_upper = cpu_to_le16(((u32)mac[0] << 8) |
-						 ((u32)mac[1]));
+	mac_update.mac_upper = cpu_to_le16(((u16)mac[0] << 8) |
+					   ((u16)mac[1]));
 	mac_update.vlan = cpu_to_le16(vid);
 	mac_update.glort = cpu_to_le16(glort);
 	mac_update.action = add ? 0 : 1;
@@ -410,6 +414,7 @@
 
 	if (mode > FM10K_XCAST_MODE_NONE)
 		return FM10K_ERR_PARAM;
+
 	/* if glort is not valid return error */
 	if (!fm10k_glort_valid_pf(hw, glort))
 		return FM10K_ERR_PARAM;
@@ -903,6 +908,13 @@
 	fm10k_write_reg(hw, FM10K_TDBAL(vf_q_idx), tdbal);
 	fm10k_write_reg(hw, FM10K_TDBAH(vf_q_idx), tdbah);
 
+	/* Provide the VF the ITR scale, using software-defined fields in TDLEN
+	 * to pass the information during VF initialization. See definition of
+	 * FM10K_TDLEN_ITR_SCALE_SHIFT for more details.
+	 */
+	fm10k_write_reg(hw, FM10K_TDLEN(vf_q_idx), hw->mac.itr_scale <<
+						   FM10K_TDLEN_ITR_SCALE_SHIFT);
+
 err_out:
 	/* configure Queue control register */
 	txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) &
@@ -910,7 +922,7 @@
 	txqctl |= (vf_idx << FM10K_TXQCTL_TC_SHIFT) |
 		  FM10K_TXQCTL_VF | vf_idx;
 
-	/* assign VID */
+	/* assign VLAN ID */
 	for (i = 0; i < queues_per_pool; i++)
 		fm10k_write_reg(hw, FM10K_TXQCTL(vf_q_idx + i), txqctl);
 
@@ -1035,6 +1047,12 @@
 	for (i = queues_per_pool; i--;) {
 		fm10k_write_reg(hw, FM10K_TDBAL(vf_q_idx + i), tdbal);
 		fm10k_write_reg(hw, FM10K_TDBAH(vf_q_idx + i), tdbah);
+		/* See definition of FM10K_TDLEN_ITR_SCALE_SHIFT for an
+		 * explanation of how TDLEN is used.
+		 */
+		fm10k_write_reg(hw, FM10K_TDLEN(vf_q_idx + i),
+				hw->mac.itr_scale <<
+				FM10K_TDLEN_ITR_SCALE_SHIFT);
 		fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx + i), vf_q_idx + i);
 		fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx + i);
 	}
@@ -1155,14 +1173,14 @@
 }
 
 /**
- * fm10k_iov_select_vid - Select correct default VID
+ * fm10k_iov_select_vid - Select correct default VLAN ID
  * @hw: Pointer to hardware structure
- * @vid: VID to correct
+ * @vid: VLAN ID to correct
  *
- * Will report an error if VID is out of range. For VID = 0, it will return
- * either the pf_vid or sw_vid depending on which one is set.
+ * Will report an error if the VLAN ID is out of range. For VID = 0, it will
+ * return either the pf_vid or sw_vid depending on which one is set.
  */
-static inline s32 fm10k_iov_select_vid(struct fm10k_vf_info *vf_info, u16 vid)
+static s32 fm10k_iov_select_vid(struct fm10k_vf_info *vf_info, u16 vid)
 {
 	if (!vid)
 		return vf_info->pf_vid ? vf_info->pf_vid : vf_info->sw_vid;
@@ -1212,11 +1230,11 @@
 		set = !(vid & FM10K_VLAN_CLEAR);
 		vid &= ~FM10K_VLAN_CLEAR;
 
-		err = fm10k_iov_select_vid(vf_info, vid);
+		err = fm10k_iov_select_vid(vf_info, (u16)vid);
 		if (err < 0)
 			return err;
-		else
-			vid = err;
+
+		vid = err;
 
 		/* update VSI info for VF in regards to VLAN table */
 		err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, set);
@@ -1232,7 +1250,7 @@
 
 		/* block attempts to set MAC for a locked device */
 		if (is_valid_ether_addr(vf_info->mac) &&
-		    memcmp(mac, vf_info->mac, ETH_ALEN))
+		    !ether_addr_equal(mac, vf_info->mac))
 			return FM10K_ERR_PARAM;
 
 		set = !(vlan & FM10K_VLAN_CLEAR);
@@ -1241,8 +1259,8 @@
 		err = fm10k_iov_select_vid(vf_info, vlan);
 		if (err < 0)
 			return err;
-		else
-			vlan = err;
+
+		vlan = (u16)err;
 
 		/* notify switch of request for new unicast address */
 		err = hw->mac.ops.update_uc_addr(hw, vf_info->glort,
@@ -1267,8 +1285,8 @@
 		err = fm10k_iov_select_vid(vf_info, vlan);
 		if (err < 0)
 			return err;
-		else
-			vlan = err;
+
+		vlan = (u16)err;
 
 		/* notify switch of request for new multicast address */
 		err = hw->mac.ops.update_mc_addr(hw, vf_info->glort,
@@ -1396,14 +1414,6 @@
 	return err;
 }
 
-const struct fm10k_msg_data fm10k_iov_msg_data_pf[] = {
-	FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test),
-	FM10K_VF_MSG_MSIX_HANDLER(fm10k_iov_msg_msix_pf),
-	FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_iov_msg_mac_vlan_pf),
-	FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_iov_msg_lport_state_pf),
-	FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error),
-};
-
 /**
  *  fm10k_update_stats_hw_pf - Updates hardware related statistics of PF
  *  @hw: pointer to hardware structure
@@ -1431,9 +1441,10 @@
 		xec = fm10k_read_hw_stats_32b(hw, FM10K_STATS_XEC, &stats->xec);
 		vlan_drop = fm10k_read_hw_stats_32b(hw, FM10K_STATS_VLAN_DROP,
 						    &stats->vlan_drop);
-		loopback_drop = fm10k_read_hw_stats_32b(hw,
-							FM10K_STATS_LOOPBACK_DROP,
-							&stats->loopback_drop);
+		loopback_drop =
+			fm10k_read_hw_stats_32b(hw,
+						FM10K_STATS_LOOPBACK_DROP,
+						&stats->loopback_drop);
 		nodesc_drop = fm10k_read_hw_stats_32b(hw,
 						      FM10K_STATS_NODESC_DROP,
 						      &stats->nodesc_drop);
@@ -1678,8 +1689,8 @@
  *
  *  This handler configures the default VLAN for the PF
  **/
-s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *hw, u32 **results,
-			     struct fm10k_mbx_info *mbx)
+static s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *hw, u32 **results,
+				    struct fm10k_mbx_info *mbx)
 {
 	u16 glort, pvid;
 	u32 pvid_update;
@@ -1698,7 +1709,7 @@
 	if (!fm10k_glort_valid_pf(hw, glort))
 		return FM10K_ERR_PARAM;
 
-	/* verify VID is valid */
+	/* verify VLAN ID is valid */
 	if (pvid >= FM10K_VLAN_TABLE_VID_MAX)
 		return FM10K_ERR_PARAM;
 
@@ -1855,39 +1866,39 @@
 	FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error),
 };
 
-static struct fm10k_mac_ops mac_ops_pf = {
-	.get_bus_info		= &fm10k_get_bus_info_generic,
-	.reset_hw		= &fm10k_reset_hw_pf,
-	.init_hw		= &fm10k_init_hw_pf,
-	.start_hw		= &fm10k_start_hw_generic,
-	.stop_hw		= &fm10k_stop_hw_generic,
-	.update_vlan		= &fm10k_update_vlan_pf,
-	.read_mac_addr		= &fm10k_read_mac_addr_pf,
-	.update_uc_addr		= &fm10k_update_uc_addr_pf,
-	.update_mc_addr		= &fm10k_update_mc_addr_pf,
-	.update_xcast_mode	= &fm10k_update_xcast_mode_pf,
-	.update_int_moderator	= &fm10k_update_int_moderator_pf,
-	.update_lport_state	= &fm10k_update_lport_state_pf,
-	.update_hw_stats	= &fm10k_update_hw_stats_pf,
-	.rebind_hw_stats	= &fm10k_rebind_hw_stats_pf,
-	.configure_dglort_map	= &fm10k_configure_dglort_map_pf,
-	.set_dma_mask		= &fm10k_set_dma_mask_pf,
-	.get_fault		= &fm10k_get_fault_pf,
-	.get_host_state		= &fm10k_get_host_state_pf,
-	.adjust_systime		= &fm10k_adjust_systime_pf,
-	.read_systime		= &fm10k_read_systime_pf,
+static const struct fm10k_mac_ops mac_ops_pf = {
+	.get_bus_info		= fm10k_get_bus_info_generic,
+	.reset_hw		= fm10k_reset_hw_pf,
+	.init_hw		= fm10k_init_hw_pf,
+	.start_hw		= fm10k_start_hw_generic,
+	.stop_hw		= fm10k_stop_hw_generic,
+	.update_vlan		= fm10k_update_vlan_pf,
+	.read_mac_addr		= fm10k_read_mac_addr_pf,
+	.update_uc_addr		= fm10k_update_uc_addr_pf,
+	.update_mc_addr		= fm10k_update_mc_addr_pf,
+	.update_xcast_mode	= fm10k_update_xcast_mode_pf,
+	.update_int_moderator	= fm10k_update_int_moderator_pf,
+	.update_lport_state	= fm10k_update_lport_state_pf,
+	.update_hw_stats	= fm10k_update_hw_stats_pf,
+	.rebind_hw_stats	= fm10k_rebind_hw_stats_pf,
+	.configure_dglort_map	= fm10k_configure_dglort_map_pf,
+	.set_dma_mask		= fm10k_set_dma_mask_pf,
+	.get_fault		= fm10k_get_fault_pf,
+	.get_host_state		= fm10k_get_host_state_pf,
+	.adjust_systime		= fm10k_adjust_systime_pf,
+	.read_systime		= fm10k_read_systime_pf,
 };
 
-static struct fm10k_iov_ops iov_ops_pf = {
-	.assign_resources		= &fm10k_iov_assign_resources_pf,
-	.configure_tc			= &fm10k_iov_configure_tc_pf,
-	.assign_int_moderator		= &fm10k_iov_assign_int_moderator_pf,
+static const struct fm10k_iov_ops iov_ops_pf = {
+	.assign_resources		= fm10k_iov_assign_resources_pf,
+	.configure_tc			= fm10k_iov_configure_tc_pf,
+	.assign_int_moderator		= fm10k_iov_assign_int_moderator_pf,
 	.assign_default_mac_vlan	= fm10k_iov_assign_default_mac_vlan_pf,
-	.reset_resources		= &fm10k_iov_reset_resources_pf,
-	.set_lport			= &fm10k_iov_set_lport_pf,
-	.reset_lport			= &fm10k_iov_reset_lport_pf,
-	.update_stats			= &fm10k_iov_update_stats_pf,
-	.report_timestamp		= &fm10k_iov_report_timestamp_pf,
+	.reset_resources		= fm10k_iov_reset_resources_pf,
+	.set_lport			= fm10k_iov_set_lport_pf,
+	.reset_lport			= fm10k_iov_reset_lport_pf,
+	.update_stats			= fm10k_iov_update_stats_pf,
+	.report_timestamp		= fm10k_iov_report_timestamp_pf,
 };
 
 static s32 fm10k_get_invariants_pf(struct fm10k_hw *hw)
@@ -1897,9 +1908,9 @@
 	return fm10k_sm_mbx_init(hw, &hw->mbx, fm10k_msg_data_pf);
 }
 
-struct fm10k_info fm10k_pf_info = {
+const struct fm10k_info fm10k_pf_info = {
 	.mac		= fm10k_mac_pf,
-	.get_invariants	= &fm10k_get_invariants_pf,
+	.get_invariants	= fm10k_get_invariants_pf,
 	.mac_ops	= &mac_ops_pf,
 	.iov_ops	= &iov_ops_pf,
 };
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_pf.h
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_pf.h
@@ -1,5 +1,5 @@
 /* Intel Ethernet Switch Host Interface Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2015 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -74,6 +74,11 @@
 #define FM10K_MSG_UPDATE_PVID_PVID_SHIFT	16
 #define FM10K_MSG_UPDATE_PVID_PVID_SIZE		16
 
+/* The following data structures are overlayed directly onto TLV mailbox
+ * messages, and must not break 4 byte alignment. Ensure the structures line
+ * up correctly as per their TLV definition.
+ */
+
 struct fm10k_mac_update {
 	__le32	mac_lower;
 	__le16	mac_upper;
@@ -81,34 +86,32 @@
 	__le16	glort;
 	u8	flags;
 	u8	action;
-} __packed;
+} __aligned(4) __packed;
 
 struct fm10k_global_table_data {
 	__le32	used;
 	__le32	avail;
-} __packed;
+} __aligned(4) __packed;
 
 struct fm10k_swapi_error {
 	__le32				status;
 	struct fm10k_global_table_data	mac;
 	struct fm10k_global_table_data	nexthop;
 	struct fm10k_global_table_data	ffu;
-} __packed;
+} __aligned(4) __packed;
 
 struct fm10k_swapi_1588_timestamp {
 	__le64 egress;
 	__le64 ingress;
 	__le16 dglort;
 	__le16 sglort;
-} __packed;
+} __aligned(4) __packed;
 
 s32 fm10k_msg_lport_map_pf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *);
 extern const struct fm10k_tlv_attr fm10k_lport_map_msg_attr[];
 #define FM10K_PF_MSG_LPORT_MAP_HANDLER(func) \
 	FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_LPORT_MAP, \
 			  fm10k_lport_map_msg_attr, func)
-s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *, u32 **,
-			     struct fm10k_mbx_info *);
 extern const struct fm10k_tlv_attr fm10k_update_pvid_msg_attr[];
 #define FM10K_PF_MSG_UPDATE_PVID_HANDLER(func) \
 	FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_UPDATE_PVID, \
@@ -129,7 +132,6 @@
 			      struct fm10k_mbx_info *);
 s32 fm10k_iov_msg_lport_state_pf(struct fm10k_hw *, u32 **,
 				 struct fm10k_mbx_info *);
-extern const struct fm10k_msg_data fm10k_iov_msg_data_pf[];
 
-extern struct fm10k_info fm10k_pf_info;
+extern const struct fm10k_info fm10k_pf_info;
 #endif /* _FM10K_PF_H */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_tlv.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_tlv.c
@@ -1,5 +1,5 @@
 /* Intel Ethernet Switch Host Interface Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2015 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -48,8 +48,8 @@
  *  the attribute buffer.  It will return success if provided with a valid
  *  pointers.
  **/
-s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id,
-				   const unsigned char *string)
+static s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id,
+					  const unsigned char *string)
 {
 	u32 attr_data = 0, len = 0;
 	u32 *attr;
@@ -98,7 +98,7 @@
  *  it in the array pointed by by string.  It will return success if provided
  *  with a valid pointers.
  **/
-s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string)
+static s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string)
 {
 	u32 len;
 
@@ -353,7 +353,7 @@
  *  function will return NULL on failure, and a pointer to the start
  *  of the nested attributes on success.
  **/
-u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id)
+static u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id)
 {
 	u32 *attr;
 
@@ -370,7 +370,7 @@
 }
 
 /**
- *  fm10k_tlv_attr_nest_start - Start a set of nested attributes
+ *  fm10k_tlv_attr_nest_stop - Stop a set of nested attributes
  *  @msg: Pointer to message block
  *
  *  This function closes off an existing set of nested attributes.  The
@@ -378,7 +378,7 @@
  *  the case of a nest within the nest this would be the outer nest pointer.
  *  This function will return success provided all pointers are valid.
  **/
-s32 fm10k_tlv_attr_nest_stop(u32 *msg)
+static s32 fm10k_tlv_attr_nest_stop(u32 *msg)
 {
 	u32 *attr;
 	u32 len;
@@ -483,8 +483,8 @@
  *  FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array
  *  and 0 on success.
  **/
-s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
-			 const struct fm10k_tlv_attr *tlv_attr)
+static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
+				const struct fm10k_tlv_attr *tlv_attr)
 {
 	u32 i, attr_id, offset = 0;
 	s32 err = 0;
@@ -755,7 +755,7 @@
 		err = fm10k_tlv_attr_get_mac_vlan(
 					results[FM10K_TEST_MSG_MAC_ADDR],
 					result_mac, &result_vlan);
-		if (!err && memcmp(test_mac, result_mac, ETH_ALEN))
+		if (!err && !ether_addr_equal(test_mac, result_mac))
 			err = FM10K_ERR_INVALID_VALUE;
 		if (!err && test_vlan != result_vlan)
 			err = FM10K_ERR_INVALID_VALUE;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_tlv.h
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_tlv.h
@@ -1,5 +1,5 @@
 /* Intel Ethernet Switch Host Interface Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2015 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -38,9 +38,9 @@
  * mailbox size we will provide a message with the above header and it
  * will be segmented and transported to the mailbox to the other side where
  * it is reassembled.  It contains the following fields:
- * Len: Length of the message in bytes excluding the message header
+ * Length: Length of the message in bytes excluding the message header
  * Flags: TBD
- * Rule: These will be the message/argument types we pass
+ * Type/ID: These will be the message/argument types we pass
  */
 /* message data header */
 #define FM10K_TLV_ID_SHIFT		0
@@ -106,8 +106,6 @@
 #define FM10K_MSG_HANDLER(id, attr, func) { id, attr, func }
 
 s32 fm10k_tlv_msg_init(u32 *, u16);
-s32 fm10k_tlv_attr_put_null_string(u32 *, u16, const unsigned char *);
-s32 fm10k_tlv_attr_get_null_string(u32 *, unsigned char *);
 s32 fm10k_tlv_attr_put_mac_vlan(u32 *, u16, const u8 *, u16);
 s32 fm10k_tlv_attr_get_mac_vlan(u32 *, u8 *, u16 *);
 s32 fm10k_tlv_attr_put_bool(u32 *, u16);
@@ -147,9 +145,6 @@
 		fm10k_tlv_attr_get_value(attr, ptr, sizeof(s64))
 s32 fm10k_tlv_attr_put_le_struct(u32 *, u16, const void *, u32);
 s32 fm10k_tlv_attr_get_le_struct(u32 *, void *, u32);
-u32 *fm10k_tlv_attr_nest_start(u32 *, u16);
-s32 fm10k_tlv_attr_nest_stop(u32 *);
-s32 fm10k_tlv_attr_parse(u32 *, u32 **, const struct fm10k_tlv_attr *);
 s32 fm10k_tlv_msg_parse(struct fm10k_hw *, u32 *, struct fm10k_mbx_info *,
 			const struct fm10k_msg_data *);
 s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results,
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_type.h
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_type.h
@@ -1,5 +1,5 @@
 /* Intel Ethernet Switch Host Interface Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2015 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -77,6 +77,7 @@
 #define FM10K_PCIE_SRIOV_CTRL_VFARI		0x10
 
 #define FM10K_ERR_PARAM				-2
+#define FM10K_ERR_NO_RESOURCES			-3
 #define FM10K_ERR_REQUESTS_PENDING		-4
 #define FM10K_ERR_RESET_REQUESTED		-5
 #define FM10K_ERR_DMA_PENDING			-6
@@ -271,6 +272,20 @@
 #define FM10K_TDBAL(_n)		((0x40 * (_n)) + 0x8000)
 #define FM10K_TDBAH(_n)		((0x40 * (_n)) + 0x8001)
 #define FM10K_TDLEN(_n)		((0x40 * (_n)) + 0x8002)
+/* When fist initialized, VFs need to know the Interrupt Throttle Rate (ITR)
+ * scale which is based on the PCIe speed but the speed information in the PCI
+ * configuration space may not be accurate. The PF already knows the ITR scale
+ * but there is no defined method to pass that information from the PF to the
+ * VF. This is accomplished during VF initialization by temporarily co-opting
+ * the yet-to-be-used TDLEN register to have the PF store the ITR shift for
+ * the VF to retrieve before the VF needs to use the TDLEN register for its
+ * intended purpose, i.e. before the Tx resources are allocated.
+ */
+#define FM10K_TDLEN_ITR_SCALE_SHIFT		9
+#define FM10K_TDLEN_ITR_SCALE_MASK		0x00000E00
+#define FM10K_TDLEN_ITR_SCALE_GEN1		2
+#define FM10K_TDLEN_ITR_SCALE_GEN2		1
+#define FM10K_TDLEN_ITR_SCALE_GEN3		0
 #define FM10K_TPH_TXCTRL(_n)	((0x40 * (_n)) + 0x8003)
 #define FM10K_TPH_TXCTRL_DESC_TPHEN		0x00000020
 #define FM10K_TPH_TXCTRL_DESC_RROEN		0x00000200
@@ -339,7 +354,7 @@
 #define FM10K_VLAN_TABLE_VID_MAX		4096
 #define FM10K_VLAN_TABLE_VSI_MAX		64
 #define FM10K_VLAN_LENGTH_SHIFT			16
-#define FM10K_VLAN_CLEAR			(1 << 15)
+#define FM10K_VLAN_CLEAR			BIT(15)
 #define FM10K_VLAN_ALL \
 	((FM10K_VLAN_TABLE_VID_MAX - 1) << FM10K_VLAN_LENGTH_SHIFT)
 
@@ -373,13 +388,13 @@
 #define FM10K_SW_SYSTIME_PULSE(_n)	((_n) + 0x02252)
 
 enum fm10k_int_source {
-	fm10k_int_Mailbox	= 0,
-	fm10k_int_PCIeFault	= 1,
-	fm10k_int_SwitchUpDown	= 2,
-	fm10k_int_SwitchEvent	= 3,
-	fm10k_int_SRAM		= 4,
-	fm10k_int_VFLR		= 5,
-	fm10k_int_MaxHoldTime	= 6,
+	fm10k_int_mailbox		= 0,
+	fm10k_int_pcie_fault		= 1,
+	fm10k_int_switch_up_down	= 2,
+	fm10k_int_switch_event		= 3,
+	fm10k_int_sram			= 4,
+	fm10k_int_vflr			= 5,
+	fm10k_int_max_hold_time		= 6,
 	fm10k_int_sources_max_pf
 };
 
@@ -535,7 +550,6 @@
 				    struct fm10k_dglort_cfg *);
 	void (*set_dma_mask)(struct fm10k_hw *, u64);
 	s32 (*get_fault)(struct fm10k_hw *, int, struct fm10k_fault *);
-	void (*request_lport_map)(struct fm10k_hw *);
 	s32 (*adjust_systime)(struct fm10k_hw *, s32 ppb);
 	u64 (*read_systime)(struct fm10k_hw *);
 };
@@ -559,6 +573,7 @@
 	bool get_host_state;
 	bool tx_ready;
 	u32 dglort_map;
+	u8 itr_scale;
 };
 
 struct fm10k_swapi_table_info {
@@ -644,10 +659,10 @@
 };
 
 struct fm10k_info {
-	enum fm10k_mac_type	mac;
-	s32			(*get_invariants)(struct fm10k_hw *);
-	struct fm10k_mac_ops	*mac_ops;
-	struct fm10k_iov_ops	*iov_ops;
+	enum fm10k_mac_type		mac;
+	s32				(*get_invariants)(struct fm10k_hw *);
+	const struct fm10k_mac_ops	*mac_ops;
+	const struct fm10k_iov_ops	*iov_ops;
 };
 
 struct fm10k_hw {
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_vf.c
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_vf.c
@@ -28,7 +28,7 @@
 static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
 {
 	u8 *perm_addr = hw->mac.perm_addr;
-	u32 bal = 0, bah = 0;
+	u32 bal = 0, bah = 0, tdlen;
 	s32 err;
 	u16 i;
 
@@ -48,6 +48,9 @@
 		       ((u32)perm_addr[2]);
 	}
 
+	/* restore default itr_scale for next VF initialization */
+	tdlen = hw->mac.itr_scale << FM10K_TDLEN_ITR_SCALE_SHIFT;
+
 	/* The queues have already been disabled so we just need to
 	 * update their base address registers
 	 */
@@ -56,6 +59,12 @@
 		fm10k_write_reg(hw, FM10K_TDBAH(i), bah);
 		fm10k_write_reg(hw, FM10K_RDBAL(i), bal);
 		fm10k_write_reg(hw, FM10K_RDBAH(i), bah);
+		/* Restore ITR scale in software-defined mechanism in TDLEN
+		 * for next VF initialization. See definition of
+		 * FM10K_TDLEN_ITR_SCALE_SHIFT for more details on the use of
+		 * TDLEN here.
+		 */
+		fm10k_write_reg(hw, FM10K_TDLEN(i), tdlen);
 	}
 
 	return 0;
@@ -103,7 +112,14 @@
 	s32 err;
 	u16 i;
 
-	/* assume we always have at least 1 queue */
+	/* verify we have at least 1 queue */
+	if (!~fm10k_read_reg(hw, FM10K_TXQCTL(0)) ||
+	    !~fm10k_read_reg(hw, FM10K_RXQCTL(0))) {
+		err = FM10K_ERR_NO_RESOURCES;
+		goto reset_max_queues;
+	}
+
+	/* determine how many queues we have */
 	for (i = 1; tqdloc0 && (i < FM10K_MAX_QUEUES_POOL); i++) {
 		/* verify the Descriptor cache offsets are increasing */
 		tqdloc = ~fm10k_read_reg(hw, FM10K_TQDLOC(i));
@@ -119,16 +135,28 @@
 	/* shut down queues we own and reset DMA configuration */
 	err = fm10k_disable_queues_generic(hw, i);
 	if (err)
-		return err;
+		goto reset_max_queues;
 
 	/* record maximum queue count */
 	hw->mac.max_queues = i;
 
-	/* fetch default VLAN */
+	/* fetch default VLAN and ITR scale */
 	hw->mac.default_vid = (fm10k_read_reg(hw, FM10K_TXQCTL(0)) &
 			       FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT;
+	/* Read the ITR scale from TDLEN. See the definition of
+	 * FM10K_TDLEN_ITR_SCALE_SHIFT for more information about how TDLEN is
+	 * used here.
+	 */
+	hw->mac.itr_scale = (fm10k_read_reg(hw, FM10K_TDLEN(0)) &
+			     FM10K_TDLEN_ITR_SCALE_MASK) >>
+			    FM10K_TDLEN_ITR_SCALE_SHIFT;
 
 	return 0;
+
+reset_max_queues:
+	hw->mac.max_queues = 0;
+
+	return err;
 }
 
 /* This structure defines the attibutes to be parsed below */
@@ -270,7 +298,7 @@
 
 	/* verify we are not locked down on the MAC address */
 	if (is_valid_ether_addr(hw->mac.perm_addr) &&
-	    memcmp(hw->mac.perm_addr, mac, ETH_ALEN))
+	    !ether_addr_equal(hw->mac.perm_addr, mac))
 		return FM10K_ERR_PARAM;
 
 	/* add bit to notify us if this is a set or clear operation */
@@ -414,6 +442,7 @@
 
 	if (mode > FM10K_XCAST_MODE_NONE)
 		return FM10K_ERR_PARAM;
+
 	/* generate message requesting to change xcast mode */
 	fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE);
 	fm10k_tlv_attr_put_u8(msg, FM10K_LPORT_STATE_MSG_XCAST_MODE, mode);
@@ -533,25 +562,25 @@
 	FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error),
 };
 
-static struct fm10k_mac_ops mac_ops_vf = {
-	.get_bus_info		= &fm10k_get_bus_info_generic,
-	.reset_hw		= &fm10k_reset_hw_vf,
-	.init_hw		= &fm10k_init_hw_vf,
-	.start_hw		= &fm10k_start_hw_generic,
-	.stop_hw		= &fm10k_stop_hw_vf,
-	.update_vlan		= &fm10k_update_vlan_vf,
-	.read_mac_addr		= &fm10k_read_mac_addr_vf,
-	.update_uc_addr		= &fm10k_update_uc_addr_vf,
-	.update_mc_addr		= &fm10k_update_mc_addr_vf,
-	.update_xcast_mode	= &fm10k_update_xcast_mode_vf,
-	.update_int_moderator	= &fm10k_update_int_moderator_vf,
-	.update_lport_state	= &fm10k_update_lport_state_vf,
-	.update_hw_stats	= &fm10k_update_hw_stats_vf,
-	.rebind_hw_stats	= &fm10k_rebind_hw_stats_vf,
-	.configure_dglort_map	= &fm10k_configure_dglort_map_vf,
-	.get_host_state		= &fm10k_get_host_state_generic,
-	.adjust_systime		= &fm10k_adjust_systime_vf,
-	.read_systime		= &fm10k_read_systime_vf,
+static const struct fm10k_mac_ops mac_ops_vf = {
+	.get_bus_info		= fm10k_get_bus_info_generic,
+	.reset_hw		= fm10k_reset_hw_vf,
+	.init_hw		= fm10k_init_hw_vf,
+	.start_hw		= fm10k_start_hw_generic,
+	.stop_hw		= fm10k_stop_hw_vf,
+	.update_vlan		= fm10k_update_vlan_vf,
+	.read_mac_addr		= fm10k_read_mac_addr_vf,
+	.update_uc_addr		= fm10k_update_uc_addr_vf,
+	.update_mc_addr		= fm10k_update_mc_addr_vf,
+	.update_xcast_mode	= fm10k_update_xcast_mode_vf,
+	.update_int_moderator	= fm10k_update_int_moderator_vf,
+	.update_lport_state	= fm10k_update_lport_state_vf,
+	.update_hw_stats	= fm10k_update_hw_stats_vf,
+	.rebind_hw_stats	= fm10k_rebind_hw_stats_vf,
+	.configure_dglort_map	= fm10k_configure_dglort_map_vf,
+	.get_host_state		= fm10k_get_host_state_generic,
+	.adjust_systime		= fm10k_adjust_systime_vf,
+	.read_systime		= fm10k_read_systime_vf,
 };
 
 static s32 fm10k_get_invariants_vf(struct fm10k_hw *hw)
@@ -561,8 +590,8 @@
 	return fm10k_pfvf_mbx_init(hw, &hw->mbx, fm10k_msg_data_vf, 0);
 }
 
-struct fm10k_info fm10k_vf_info = {
+const struct fm10k_info fm10k_vf_info = {
 	.mac		= fm10k_mac_vf,
-	.get_invariants	= &fm10k_get_invariants_vf,
+	.get_invariants	= fm10k_get_invariants_vf,
 	.mac_ops	= &mac_ops_vf,
 };
--- linux-4.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_vf.h
+++ linux-4.4.0/drivers/net/ethernet/intel/fm10k/fm10k_vf.h
@@ -74,5 +74,5 @@
 #define FM10K_VF_MSG_1588_HANDLER(func) \
 	FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_1588, fm10k_1588_msg_attr, func)
 
-extern struct fm10k_info fm10k_vf_info;
+extern const struct fm10k_info fm10k_vf_info;
 #endif /* _FM10K_VF_H */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -42,7 +42,6 @@
 #include <linux/string.h>
 #include <linux/in.h>
 #include <linux/ip.h>
-#include <linux/tcp.h>
 #include <linux/sctp.h>
 #include <linux/pkt_sched.h>
 #include <linux/ipv6.h>
@@ -65,9 +64,6 @@
 #include "i40e_dcb.h"
 
 /* Useful i40e defaults */
-#define I40E_BASE_PF_SEID     16
-#define I40E_BASE_VSI_SEID    512
-#define I40E_BASE_VEB_SEID    288
 #define I40E_MAX_VEB          16
 
 #define I40E_MAX_NUM_DESCRIPTORS      4096
@@ -104,6 +100,7 @@
 #define I40E_PRIV_FLAGS_LINKPOLL_FLAG	BIT(1)
 #define I40E_PRIV_FLAGS_FD_ATR		BIT(2)
 #define I40E_PRIV_FLAGS_VEB_STATS	BIT(3)
+#define I40E_PRIV_FLAGS_HW_ATR_EVICT	BIT(5)
 
 #define I40E_NVM_VERSION_LO_SHIFT  0
 #define I40E_NVM_VERSION_LO_MASK   (0xff << I40E_NVM_VERSION_LO_SHIFT)
@@ -113,6 +110,7 @@
 #define I40E_OEM_VER_PATCH_MASK    0xff
 #define I40E_OEM_VER_BUILD_SHIFT   8
 #define I40E_OEM_VER_SHIFT         24
+#define I40E_PHY_DEBUG_PORT        BIT(4)
 
 /* The values in here are decimal coded as hex as is the case in the NVM map*/
 #define I40E_CURRENT_NVM_VERSION_HI 0x2
@@ -137,6 +135,19 @@
 /* default to trying for four seconds */
 #define I40E_TRY_LINK_TIMEOUT (4 * HZ)
 
+/**
+ * i40e_is_mac_710 - Return true if MAC is X710/XL710
+ * @hw: ptr to the hardware info
+ **/
+static inline bool i40e_is_mac_710(struct i40e_hw *hw)
+{
+	if ((hw->mac.type == I40E_MAC_X710) ||
+	    (hw->mac.type == I40E_MAC_XL710))
+		return true;
+
+	return false;
+}
+
 /* driver state flags */
 enum i40e_state_t {
 	__I40E_TESTING,
@@ -187,6 +198,7 @@
 #define I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR (I40E_FDIR_BUFFER_HEAD_ROOM * 4)
 
 #define I40E_HKEY_ARRAY_SIZE ((I40E_PFQF_HKEY_MAX_INDEX + 1) * 4)
+#define I40E_HLUT_ARRAY_SIZE ((I40E_PFQF_HLUT_MAX_INDEX + 1) * 4)
 
 enum i40e_fd_stat_idx {
 	I40E_FD_STAT_ATR,
@@ -244,6 +256,11 @@
 	struct i40e_tc_info tc_info[I40E_MAX_TRAFFIC_CLASS];
 };
 
+struct i40e_udp_port_config {
+	__be16 index;
+	u8 type;
+};
+
 /* struct that defines the Ethernet device */
 struct i40e_pf {
 	struct pci_dev *pdev;
@@ -264,8 +281,9 @@
 #endif /* I40E_FCOE */
 	u16 num_lan_qps;           /* num lan queues this PF has set up */
 	u16 num_lan_msix;          /* num queue vectors for the base PF vsi */
+	u16 num_fdsb_msix;         /* num queue vectors for sideband Fdir */
 	int queues_left;           /* queues left unclaimed */
-	u16 rss_size;              /* num queues in the RSS array */
+	u16 alloc_rss_size;        /* allocated RSS queues */
 	u16 rss_size_max;          /* HW defined max RSS queues */
 	u16 fdir_pf_filter_count;  /* num of guaranteed filters for this PF */
 	u16 num_alloc_vsi;         /* num VSIs this driver supports */
@@ -280,11 +298,9 @@
 	u32 fd_atr_cnt;
 	u32 fd_tcp_rule;
 
-#ifdef CONFIG_I40E_VXLAN
-	__be16  vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
-	u16 pending_vxlan_bitmap;
+	struct i40e_udp_port_config udp_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
+	u16 pending_udp_bitmap;
 
-#endif
 	enum i40e_interrupt_policy int_policy;
 	u16 rx_itr_default;
 	u16 tx_itr_default;
@@ -300,8 +316,6 @@
 #define I40E_FLAG_RX_CSUM_ENABLED		BIT_ULL(1)
 #define I40E_FLAG_MSI_ENABLED			BIT_ULL(2)
 #define I40E_FLAG_MSIX_ENABLED			BIT_ULL(3)
-#define I40E_FLAG_RX_1BUF_ENABLED		BIT_ULL(4)
-#define I40E_FLAG_RX_PS_ENABLED			BIT_ULL(5)
 #define I40E_FLAG_RSS_ENABLED			BIT_ULL(6)
 #define I40E_FLAG_VMDQ_ENABLED			BIT_ULL(7)
 #define I40E_FLAG_FDIR_REQUIRES_REINIT		BIT_ULL(8)
@@ -321,9 +335,7 @@
 #define I40E_FLAG_FD_ATR_ENABLED		BIT_ULL(22)
 #define I40E_FLAG_PTP				BIT_ULL(25)
 #define I40E_FLAG_MFP_ENABLED			BIT_ULL(26)
-#ifdef CONFIG_I40E_VXLAN
-#define I40E_FLAG_VXLAN_FILTER_SYNC		BIT_ULL(27)
-#endif
+#define I40E_FLAG_UDP_FILTER_SYNC		BIT_ULL(27)
 #define I40E_FLAG_PORT_ID_VALID			BIT_ULL(28)
 #define I40E_FLAG_DCB_CAPABLE			BIT_ULL(29)
 #define I40E_FLAG_RSS_AQ_CAPABLE		BIT_ULL(31)
@@ -335,7 +347,15 @@
 #define I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE	BIT_ULL(38)
 #define I40E_FLAG_LINK_POLLING_ENABLED		BIT_ULL(39)
 #define I40E_FLAG_VEB_MODE_ENABLED		BIT_ULL(40)
+#define I40E_FLAG_GENEVE_OFFLOAD_CAPABLE	BIT_ULL(41)
 #define I40E_FLAG_NO_PCI_LINK_CHECK		BIT_ULL(42)
+#define I40E_FLAG_100M_SGMII_CAPABLE		BIT_ULL(43)
+#define I40E_FLAG_RESTART_AUTONEG		BIT_ULL(44)
+#define I40E_FLAG_NO_DCB_SUPPORT		BIT_ULL(45)
+#define I40E_FLAG_USE_SET_LLDP_MIB		BIT_ULL(46)
+#define I40E_FLAG_STOP_FW_LLDP			BIT_ULL(47)
+#define I40E_FLAG_HAVE_10GBASET_PHY		BIT_ULL(48)
+#define I40E_FLAG_PF_MAC			BIT_ULL(50)
 
 	/* tracks features that get auto disabled by errors */
 	u64 auto_disable_flags;
@@ -387,6 +407,7 @@
 	struct i40e_vf *vf;
 	int num_alloc_vfs;	/* actual number of VFs allocated */
 	u32 vf_aq_requests;
+	u32 arq_overflows;	/* Not fatal, possibly indicative of problems */
 
 	/* DCBx/DCBNL capability for PF that indicates
 	 * whether DCBx is managed by firmware or host
@@ -412,13 +433,14 @@
 	u32 rx_hwtstamp_cleared;
 	bool ptp_tx;
 	bool ptp_rx;
-	u16 rss_table_size;
+	u16 rss_table_size; /* HW RSS table size */
 	/* These are only valid in NPAR modes */
 	u32 npar_max_bw;
 	u32 npar_min_bw;
 
 	u32 ioremap_len;
 	u32 fd_inv;
+	u16 phy_led_val;
 };
 
 struct i40e_mac_filter {
@@ -487,6 +509,8 @@
 	u32 tx_restart;
 	u32 tx_busy;
 	u64 tx_linearize;
+	u64 tx_force_wb;
+	u64 tx_lost_interrupt;
 	u32 rx_buf_failed;
 	u32 rx_page_failed;
 
@@ -504,8 +528,10 @@
 	u16 tx_itr_setting;
 	u16 int_rate_limit;  /* value in usecs */
 
-	u16 rss_table_size;
-	u16 rss_size;
+	u16 rss_table_size; /* HW RSS table size */
+	u16 rss_size;       /* Allocated RSS queues */
+	u8  *rss_hkey_user; /* User configured hash keys */
+	u8  *rss_lut_user;  /* User configured lookup table entries */
 
 	u16 max_frame;
 	u16 rx_hdr_len;
@@ -575,6 +601,9 @@
 
 	u8 num_ringpairs;	/* total number of ring pairs in vector */
 
+#define I40E_Q_VECTOR_HUNG_DETECT 0 /* Bit Index for hung detection logic */
+	unsigned long hung_detected; /* Set/Reset for hung_detection logic */
+
 	cpumask_t affinity_mask;
 	struct rcu_head rcu;	/* to avoid race with update stats on free */
 	char name[I40E_INT_NAME_STR_LEN];
@@ -602,8 +631,8 @@
 
 	full_ver = hw->nvm.oem_ver;
 	ver = (u8)(full_ver >> I40E_OEM_VER_SHIFT);
-	build = (u16)((full_ver >> I40E_OEM_VER_BUILD_SHIFT)
-		 & I40E_OEM_VER_BUILD_MASK);
+	build = (u16)((full_ver >> I40E_OEM_VER_BUILD_SHIFT) &
+		 I40E_OEM_VER_BUILD_MASK);
 	patch = (u8)(full_ver & I40E_OEM_VER_PATCH_MASK);
 
 	snprintf(buf, sizeof(buf),
@@ -668,6 +697,8 @@
 extern const char i40e_driver_version_str[];
 void i40e_do_reset_safe(struct i40e_pf *pf, u32 reset_flags);
 void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags);
+int i40e_config_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
+int i40e_get_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
 struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id);
 void i40e_update_stats(struct i40e_vsi *vsi);
 void i40e_update_eth_stats(struct i40e_vsi *vsi);
@@ -691,7 +722,7 @@
 					bool is_vf, bool is_netdev);
 void i40e_del_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan,
 		     bool is_vf, bool is_netdev);
-int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl);
+int i40e_sync_vsi_filters(struct i40e_vsi *vsi);
 struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
 				u16 uplink, u32 param1);
 int i40e_vsi_release(struct i40e_vsi *vsi);
@@ -709,7 +740,7 @@
 void i40e_veb_release(struct i40e_veb *veb);
 
 int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc);
-i40e_status i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid);
+int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid);
 void i40e_vsi_remove_pvid(struct i40e_vsi *vsi);
 void i40e_vsi_reset_stats(struct i40e_vsi *vsi);
 void i40e_pf_reset_stats(struct i40e_pf *pf);
@@ -735,6 +766,9 @@
 	struct i40e_hw *hw = &pf->hw;
 	u32 val;
 
+	/* definitely clear the PBA here, as this function is meant to
+	 * clean out all previous interrupts AND enable the interrupt
+	 */
 	val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
 	      I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
 	      (I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
@@ -742,9 +776,8 @@
 	/* skip the flush */
 }
 
-void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector);
 void i40e_irq_dynamic_disable_icr0(struct i40e_pf *pf);
-void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf);
+void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf, bool clearpba);
 #ifdef I40E_FCOE
 struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
 					     struct net_device *netdev,
@@ -767,12 +800,15 @@
 int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid);
 struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr,
 					     bool is_vf, bool is_netdev);
+int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, u8 *macaddr,
+			  bool is_vf, bool is_netdev);
 bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi);
 struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
 				      bool is_vf, bool is_netdev);
 #ifdef I40E_FCOE
 int i40e_close(struct net_device *netdev);
-int i40e_setup_tc(struct net_device *netdev, u8 tc);
+int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+		    struct tc_to_netdev *tc);
 void i40e_netpoll(struct net_device *netdev);
 int i40e_fcoe_enable(struct net_device *netdev);
 int i40e_fcoe_disable(struct net_device *netdev);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -953,6 +953,9 @@
 	u16 flags;
 	u16 ntu;
 
+	/* pre-clean the event info */
+	memset(&e->desc, 0, sizeof(e->desc));
+
 	/* take the lock before we start messing with the ring */
 	mutex_lock(&hw->aq.arq_mutex);
 
@@ -1020,14 +1023,6 @@
 	hw->aq.arq.next_to_clean = ntc;
 	hw->aq.arq.next_to_use = ntu;
 
-clean_arq_element_out:
-	/* Set pending if needed, unlock and return */
-	if (pending != NULL)
-		*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
-
-clean_arq_element_err:
-	mutex_unlock(&hw->aq.arq_mutex);
-
 	if (i40e_is_nvm_update_op(&e->desc)) {
 		if (hw->aq.nvm_release_on_done) {
 			i40e_release_nvm(hw);
@@ -1048,6 +1043,13 @@
 		}
 	}
 
+clean_arq_element_out:
+	/* Set pending if needed, unlock and return */
+	if (pending)
+		*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
+clean_arq_element_err:
+	mutex_unlock(&hw->aq.arq_mutex);
+
 	return ret_code;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -34,7 +34,7 @@
  */
 
 #define I40E_FW_API_VERSION_MAJOR	0x0001
-#define I40E_FW_API_VERSION_MINOR	0x0004
+#define I40E_FW_API_VERSION_MINOR	0x0005
 
 struct i40e_aq_desc {
 	__le16 flags;
@@ -145,6 +145,9 @@
 	i40e_aqc_opc_remove_statistics		= 0x0202,
 	i40e_aqc_opc_set_port_parameters	= 0x0203,
 	i40e_aqc_opc_get_switch_resource_alloc	= 0x0204,
+	i40e_aqc_opc_set_switch_config		= 0x0205,
+	i40e_aqc_opc_rx_ctl_reg_read		= 0x0206,
+	i40e_aqc_opc_rx_ctl_reg_write		= 0x0207,
 
 	i40e_aqc_opc_add_vsi			= 0x0210,
 	i40e_aqc_opc_update_vsi_parameters	= 0x0211,
@@ -220,6 +223,7 @@
 	i40e_aqc_opc_get_phy_wol_caps		= 0x0621,
 	i40e_aqc_opc_set_phy_debug		= 0x0622,
 	i40e_aqc_opc_upload_ext_phy_fm		= 0x0625,
+	i40e_aqc_opc_run_phy_activity		= 0x0626,
 
 	/* NVM commands */
 	i40e_aqc_opc_nvm_read			= 0x0701,
@@ -227,6 +231,8 @@
 	i40e_aqc_opc_nvm_update			= 0x0703,
 	i40e_aqc_opc_nvm_config_read		= 0x0704,
 	i40e_aqc_opc_nvm_config_write		= 0x0705,
+	i40e_aqc_opc_oem_post_update		= 0x0720,
+	i40e_aqc_opc_thermal_sensor		= 0x0721,
 
 	/* virtualization commands */
 	i40e_aqc_opc_send_msg_to_pf		= 0x0801,
@@ -401,6 +407,7 @@
 #define I40E_AQ_CAP_ID_OS2BMC_CAP	0x0004
 #define I40E_AQ_CAP_ID_FUNCTIONS_VALID	0x0005
 #define I40E_AQ_CAP_ID_ALTERNATE_RAM	0x0006
+#define I40E_AQ_CAP_ID_WOL_AND_PROXY	0x0008
 #define I40E_AQ_CAP_ID_SRIOV		0x0012
 #define I40E_AQ_CAP_ID_VF		0x0013
 #define I40E_AQ_CAP_ID_VMDQ		0x0014
@@ -421,6 +428,7 @@
 #define I40E_AQ_CAP_ID_LED		0x0061
 #define I40E_AQ_CAP_ID_SDP		0x0062
 #define I40E_AQ_CAP_ID_MDIO		0x0063
+#define I40E_AQ_CAP_ID_WSR_PROT		0x0064
 #define I40E_AQ_CAP_ID_FLEX10		0x00F1
 #define I40E_AQ_CAP_ID_CEM		0x00F2
 
@@ -679,6 +687,31 @@
 
 I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
 
+/* Set Switch Configuration (direct 0x0205) */
+struct i40e_aqc_set_switch_config {
+	__le16	flags;
+#define I40E_AQ_SET_SWITCH_CFG_PROMISC		0x0001
+#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER	0x0002
+	__le16	valid_flags;
+	u8	reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
+
+/* Read Receive control registers  (direct 0x0206)
+ * Write Receive control registers (direct 0x0207)
+ *     used for accessing Rx control registers that can be
+ *     slow and need special handling when under high Rx load
+ */
+struct i40e_aqc_rx_ctl_reg_read_write {
+	__le32 reserved1;
+	__le32 address;
+	__le32 reserved2;
+	__le32 value;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_rx_ctl_reg_read_write);
+
 /* Add VSI (indirect 0x0210)
  *    this indirect command uses struct i40e_aqc_vsi_properties_data
  *    as the indirect buffer (128 bytes)
@@ -905,7 +938,8 @@
 					I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT	0x2
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DATA		0x4
-#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER	0x8
+#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER	0x8     /* deprecated */
+#define I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS	0x10
 	u8	enable_tcs;
 	u8	reserved[9];
 };
@@ -972,6 +1006,7 @@
 #define I40E_AQC_MACVLAN_ADD_HASH_MATCH		0x0002
 #define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN	0x0004
 #define I40E_AQC_MACVLAN_ADD_TO_QUEUE		0x0008
+#define I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC	0x0010
 	__le16	queue_number;
 #define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT	0
 #define I40E_AQC_MACVLAN_CMD_QUEUE_MASK		(0x7FF << \
@@ -1068,6 +1103,7 @@
 #define I40E_AQC_SET_VSI_PROMISC_BROADCAST	0x04
 #define I40E_AQC_SET_VSI_DEFAULT		0x08
 #define I40E_AQC_SET_VSI_PROMISC_VLAN		0x10
+#define I40E_AQC_SET_VSI_PROMISC_TX		0x8000
 	__le16	seid;
 #define I40E_AQC_VSI_PROM_CMD_SEID_MASK		0x3FF
 	__le16	vlan_tag;
@@ -1256,10 +1292,16 @@
 
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT		9
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK		0x1E00
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_XVLAN		0
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN		0
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC		1
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE			2
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE		2
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP			3
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_RESERVED		4
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE		5
+
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_MAC	0x2000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_INNER_MAC	0x4000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_IP	0x8000
 
 	__le32	tenant_id;
 	u8	reserved[4];
@@ -1754,7 +1796,12 @@
 	u8	config;
 #define I40E_AQ_CONFIG_CRC_ENA		0x04
 #define I40E_AQ_CONFIG_PACING_MASK	0x78
-	u8	reserved[5];
+	u8	external_power_ability;
+#define I40E_AQ_LINK_POWER_CLASS_1	0x00
+#define I40E_AQ_LINK_POWER_CLASS_2	0x01
+#define I40E_AQ_LINK_POWER_CLASS_3	0x02
+#define I40E_AQ_LINK_POWER_CLASS_4	0x03
+	u8	reserved[4];
 };
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
@@ -1822,6 +1869,18 @@
 	I40E_AQC_PHY_REG_EXERNAL_MODULE	= 0x3
 };
 
+/* Run PHY Activity (0x0626) */
+struct i40e_aqc_run_phy_activity {
+	__le16  activity_id;
+	u8      flags;
+	u8      reserved1;
+	__le32  control;
+	__le32  data;
+	u8      reserved2[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity);
+
 /* NVM Read command (indirect 0x0701)
  * NVM Erase commands (direct 0x0702)
  * NVM Update commands (indirect 0x0703)
@@ -1891,6 +1950,42 @@
 
 I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field);
 
+/* OEM Post Update (indirect 0x0720)
+ * no command data struct used
+ */
+struct i40e_aqc_nvm_oem_post_update {
+#define I40E_AQ_NVM_OEM_POST_UPDATE_EXTERNAL_DATA	0x01
+	u8 sel_data;
+	u8 reserved[7];
+};
+
+I40E_CHECK_STRUCT_LEN(0x8, i40e_aqc_nvm_oem_post_update);
+
+struct i40e_aqc_nvm_oem_post_update_buffer {
+	u8 str_len;
+	u8 dev_addr;
+	__le16 eeprom_addr;
+	u8 data[36];
+};
+
+I40E_CHECK_STRUCT_LEN(0x28, i40e_aqc_nvm_oem_post_update_buffer);
+
+/* Thermal Sensor (indirect 0x0721)
+ *     read or set thermal sensor configs and values
+ *     takes a sensor and command specific data buffer, not detailed here
+ */
+struct i40e_aqc_thermal_sensor {
+	u8 sensor_action;
+#define I40E_AQ_THERMAL_SENSOR_READ_CONFIG	0
+#define I40E_AQ_THERMAL_SENSOR_SET_CONFIG	1
+#define I40E_AQ_THERMAL_SENSOR_READ_TEMP	2
+	u8 reserved[7];
+	__le32	addr_high;
+	__le32	addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_thermal_sensor);
+
 /* Send to PF command (indirect 0x0801) id is only used by PF
  * Send to VF command (indirect 0x0802) id is only used by PF
  * Send to Peer PF command (indirect 0x0803)
@@ -2170,6 +2265,7 @@
 #define I40E_AQC_TUNNEL_TYPE_VXLAN	0x00
 #define I40E_AQC_TUNNEL_TYPE_NGE	0x01
 #define I40E_AQC_TUNNEL_TYPE_TEREDO	0x10
+#define I40E_AQC_TUNNEL_TYPE_VXLAN_GPE	0x11
 	u8	reserved1[10];
 };
 
@@ -2403,4 +2499,4 @@
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_internals);
 
-#endif
+#endif /* _I40E_ADMINQ_CMD_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -44,7 +44,6 @@
 		switch (hw->device_id) {
 		case I40E_DEV_ID_SFP_XL710:
 		case I40E_DEV_ID_QEMU:
-		case I40E_DEV_ID_KX_A:
 		case I40E_DEV_ID_KX_B:
 		case I40E_DEV_ID_KX_C:
 		case I40E_DEV_ID_QSFP_A:
@@ -56,19 +55,13 @@
 		case I40E_DEV_ID_20G_KR2_A:
 			hw->mac.type = I40E_MAC_XL710;
 			break;
+		case I40E_DEV_ID_KX_X722:
+		case I40E_DEV_ID_QSFP_X722:
 		case I40E_DEV_ID_SFP_X722:
 		case I40E_DEV_ID_1G_BASE_T_X722:
 		case I40E_DEV_ID_10G_BASE_T_X722:
 			hw->mac.type = I40E_MAC_X722;
 			break;
-		case I40E_DEV_ID_X722_VF:
-		case I40E_DEV_ID_X722_VF_HV:
-			hw->mac.type = I40E_MAC_X722_VF;
-			break;
-		case I40E_DEV_ID_VF:
-		case I40E_DEV_ID_VF_HV:
-			hw->mac.type = I40E_MAC_VF;
-			break;
 		default:
 			hw->mac.type = I40E_MAC_GENERIC;
 			break;
@@ -302,13 +295,15 @@
 		   void *buffer, u16 buf_len)
 {
 	struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
-	u16 len = le16_to_cpu(aq_desc->datalen);
+	u16 len;
 	u8 *buf = (u8 *)buffer;
 	u16 i = 0;
 
 	if ((!(mask & hw->debug_mask)) || (desc == NULL))
 		return;
 
+	len = le16_to_cpu(aq_desc->datalen);
+
 	i40e_debug(hw, mask,
 		   "AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n",
 		   le16_to_cpu(aq_desc->opcode),
@@ -1246,7 +1241,13 @@
 	grst_del = (rd32(hw, I40E_GLGEN_RSTCTL) &
 		    I40E_GLGEN_RSTCTL_GRSTDEL_MASK) >>
 		    I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
-	for (cnt = 0; cnt < grst_del + 10; cnt++) {
+
+	/* It can take upto 15 secs for GRST steady state.
+	 * Bump it to 16 secs max to be safe.
+	 */
+	grst_del = grst_del * 20;
+
+	for (cnt = 0; cnt < grst_del; cnt++) {
 		reg = rd32(hw, I40E_GLGEN_RSTAT);
 		if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
 			break;
@@ -1895,6 +1896,32 @@
 }
 
 /**
+ * i40e_aq_set_phy_debug
+ * @hw: pointer to the hw struct
+ * @cmd_flags: debug command flags
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Reset the external PHY.
+ **/
+enum i40e_status_code i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags,
+					struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_set_phy_debug *cmd =
+		(struct i40e_aqc_set_phy_debug *)&desc.params.raw;
+	enum i40e_status_code status;
+
+	i40e_fill_default_direct_cmd_desc(&desc,
+					  i40e_aqc_opc_set_phy_debug);
+
+	cmd->command_flags = cmd_flags;
+
+	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+	return status;
+}
+
+/**
  * i40e_aq_add_vsi
  * @hw: pointer to the hw struct
  * @vsi_ctx: pointer to a vsi context struct
@@ -1959,12 +1986,19 @@
 	i40e_fill_default_direct_cmd_desc(&desc,
 					i40e_aqc_opc_set_vsi_promiscuous_modes);
 
-	if (set)
+	if (set) {
 		flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
+		if (((hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver >= 5)) ||
+		    (hw->aq.api_maj_ver > 1))
+			flags |= I40E_AQC_SET_VSI_PROMISC_TX;
+	}
 
 	cmd->promiscuous_flags = cpu_to_le16(flags);
 
 	cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST);
+	if (((hw->aq.api_maj_ver >= 1) && (hw->aq.api_min_ver >= 5)) ||
+	    (hw->aq.api_maj_ver > 1))
+		cmd->valid_flags |= cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_TX);
 
 	cmd->seid = cpu_to_le16(seid);
 	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
@@ -2040,6 +2074,37 @@
 }
 
 /**
+ * i40e_aq_set_vsi_vlan_promisc - control the VLAN promiscuous setting
+ * @hw: pointer to the hw struct
+ * @seid: vsi number
+ * @enable: set MAC L2 layer unicast promiscuous enable/disable for a given VLAN
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_set_vsi_vlan_promisc(struct i40e_hw *hw,
+				       u16 seid, bool enable,
+				       struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_set_vsi_promiscuous_modes *cmd =
+		(struct i40e_aqc_set_vsi_promiscuous_modes *)&desc.params.raw;
+	i40e_status status;
+	u16 flags = 0;
+
+	i40e_fill_default_direct_cmd_desc(&desc,
+					i40e_aqc_opc_set_vsi_promiscuous_modes);
+	if (enable)
+		flags |= I40E_AQC_SET_VSI_PROMISC_VLAN;
+
+	cmd->promiscuous_flags = cpu_to_le16(flags);
+	cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_VLAN);
+	cmd->seid = cpu_to_le16(seid);
+
+	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+	return status;
+}
+
+/**
  * i40e_get_vsi_params - get VSI configuration info
  * @hw: pointer to the hw struct
  * @vsi_ctx: pointer to a vsi context struct
@@ -2284,8 +2349,8 @@
  * @downlink_seid: the VSI SEID
  * @enabled_tc: bitmap of TCs to be enabled
  * @default_port: true for default port VSI, false for control port
- * @enable_l2_filtering: true to add L2 filter table rules to regular forwarding rules for cloud support
  * @veb_seid: pointer to where to put the resulting VEB SEID
+ * @enable_stats: true to turn on VEB stats
  * @cmd_details: pointer to command details structure or NULL
  *
  * This asks the FW to add a VEB between the uplink and downlink
@@ -2293,8 +2358,8 @@
  **/
 i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
 				u16 downlink_seid, u8 enabled_tc,
-				bool default_port, bool enable_l2_filtering,
-				u16 *veb_seid,
+				bool default_port, u16 *veb_seid,
+				bool enable_stats,
 				struct i40e_asq_cmd_details *cmd_details)
 {
 	struct i40e_aq_desc desc;
@@ -2321,8 +2386,9 @@
 	else
 		veb_flags |= I40E_AQC_ADD_VEB_PORT_TYPE_DATA;
 
-	if (enable_l2_filtering)
-		veb_flags |= I40E_AQC_ADD_VEB_ENABLE_L2_FILTER;
+	/* reverse logic here: set the bitflag to disable the stats */
+	if (!enable_stats)
+		veb_flags |= I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS;
 
 	cmd->veb_flags = cpu_to_le16(veb_flags);
 
@@ -2411,6 +2477,7 @@
 		(struct i40e_aqc_macvlan *)&desc.params.raw;
 	i40e_status status;
 	u16 buf_size;
+	int i;
 
 	if (count == 0 || !mv_list || !hw)
 		return I40E_ERR_PARAM;
@@ -2424,12 +2491,17 @@
 	cmd->seid[1] = 0;
 	cmd->seid[2] = 0;
 
+	for (i = 0; i < count; i++)
+		if (is_multicast_ether_addr(mv_list[i].mac_addr))
+			mv_list[i].flags |=
+			       cpu_to_le16(I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC);
+
 	desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
 	if (buf_size > I40E_AQ_LARGE_BUF)
 		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
 
 	status = i40e_asq_send_command(hw, &desc, mv_list, buf_size,
-				    cmd_details);
+				       cmd_details);
 
 	return status;
 }
@@ -2477,6 +2549,137 @@
 }
 
 /**
+ * i40e_mirrorrule_op - Internal helper function to add/delete mirror rule
+ * @hw: pointer to the hw struct
+ * @opcode: AQ opcode for add or delete mirror rule
+ * @sw_seid: Switch SEID (to which rule refers)
+ * @rule_type: Rule Type (ingress/egress/VLAN)
+ * @id: Destination VSI SEID or Rule ID
+ * @count: length of the list
+ * @mr_list: list of mirrored VSI SEIDs or VLAN IDs
+ * @cmd_details: pointer to command details structure or NULL
+ * @rule_id: Rule ID returned from FW
+ * @rule_used: Number of rules used in internal switch
+ * @rule_free: Number of rules free in internal switch
+ *
+ * Add/Delete a mirror rule to a specific switch. Mirror rules are supported for
+ * VEBs/VEPA elements only
+ **/
+static i40e_status i40e_mirrorrule_op(struct i40e_hw *hw,
+				u16 opcode, u16 sw_seid, u16 rule_type, u16 id,
+				u16 count, __le16 *mr_list,
+				struct i40e_asq_cmd_details *cmd_details,
+				u16 *rule_id, u16 *rules_used, u16 *rules_free)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_add_delete_mirror_rule *cmd =
+		(struct i40e_aqc_add_delete_mirror_rule *)&desc.params.raw;
+	struct i40e_aqc_add_delete_mirror_rule_completion *resp =
+	(struct i40e_aqc_add_delete_mirror_rule_completion *)&desc.params.raw;
+	i40e_status status;
+	u16 buf_size;
+
+	buf_size = count * sizeof(*mr_list);
+
+	/* prep the rest of the request */
+	i40e_fill_default_direct_cmd_desc(&desc, opcode);
+	cmd->seid = cpu_to_le16(sw_seid);
+	cmd->rule_type = cpu_to_le16(rule_type &
+				     I40E_AQC_MIRROR_RULE_TYPE_MASK);
+	cmd->num_entries = cpu_to_le16(count);
+	/* Dest VSI for add, rule_id for delete */
+	cmd->destination = cpu_to_le16(id);
+	if (mr_list) {
+		desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF |
+						I40E_AQ_FLAG_RD));
+		if (buf_size > I40E_AQ_LARGE_BUF)
+			desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+	}
+
+	status = i40e_asq_send_command(hw, &desc, mr_list, buf_size,
+				       cmd_details);
+	if (!status ||
+	    hw->aq.asq_last_status == I40E_AQ_RC_ENOSPC) {
+		if (rule_id)
+			*rule_id = le16_to_cpu(resp->rule_id);
+		if (rules_used)
+			*rules_used = le16_to_cpu(resp->mirror_rules_used);
+		if (rules_free)
+			*rules_free = le16_to_cpu(resp->mirror_rules_free);
+	}
+	return status;
+}
+
+/**
+ * i40e_aq_add_mirrorrule - add a mirror rule
+ * @hw: pointer to the hw struct
+ * @sw_seid: Switch SEID (to which rule refers)
+ * @rule_type: Rule Type (ingress/egress/VLAN)
+ * @dest_vsi: SEID of VSI to which packets will be mirrored
+ * @count: length of the list
+ * @mr_list: list of mirrored VSI SEIDs or VLAN IDs
+ * @cmd_details: pointer to command details structure or NULL
+ * @rule_id: Rule ID returned from FW
+ * @rule_used: Number of rules used in internal switch
+ * @rule_free: Number of rules free in internal switch
+ *
+ * Add mirror rule. Mirror rules are supported for VEBs or VEPA elements only
+ **/
+i40e_status i40e_aq_add_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
+			u16 rule_type, u16 dest_vsi, u16 count, __le16 *mr_list,
+			struct i40e_asq_cmd_details *cmd_details,
+			u16 *rule_id, u16 *rules_used, u16 *rules_free)
+{
+	if (!(rule_type == I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS ||
+	    rule_type == I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS)) {
+		if (count == 0 || !mr_list)
+			return I40E_ERR_PARAM;
+	}
+
+	return i40e_mirrorrule_op(hw, i40e_aqc_opc_add_mirror_rule, sw_seid,
+				  rule_type, dest_vsi, count, mr_list,
+				  cmd_details, rule_id, rules_used, rules_free);
+}
+
+/**
+ * i40e_aq_delete_mirrorrule - delete a mirror rule
+ * @hw: pointer to the hw struct
+ * @sw_seid: Switch SEID (to which rule refers)
+ * @rule_type: Rule Type (ingress/egress/VLAN)
+ * @count: length of the list
+ * @rule_id: Rule ID that is returned in the receive desc as part of
+ *		add_mirrorrule.
+ * @mr_list: list of mirrored VLAN IDs to be removed
+ * @cmd_details: pointer to command details structure or NULL
+ * @rule_used: Number of rules used in internal switch
+ * @rule_free: Number of rules free in internal switch
+ *
+ * Delete a mirror rule. Mirror rules are supported for VEBs/VEPA elements only
+ **/
+i40e_status i40e_aq_delete_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
+			u16 rule_type, u16 rule_id, u16 count, __le16 *mr_list,
+			struct i40e_asq_cmd_details *cmd_details,
+			u16 *rules_used, u16 *rules_free)
+{
+	/* Rule ID has to be valid except rule_type: INGRESS VLAN mirroring */
+	if (rule_type != I40E_AQC_MIRROR_RULE_TYPE_VLAN) {
+		if (!rule_id)
+			return I40E_ERR_PARAM;
+	} else {
+		/* count and mr_list shall be valid for rule_type INGRESS VLAN
+		 * mirroring. For other rule_type, count and rule_type should
+		 * not matter.
+		 */
+		if (count == 0 || !mr_list)
+			return I40E_ERR_PARAM;
+	}
+
+	return i40e_mirrorrule_op(hw, i40e_aqc_opc_delete_mirror_rule, sw_seid,
+				  rule_type, rule_id, count, mr_list,
+				  cmd_details, NULL, rules_used, rules_free);
+}
+
+/**
  * i40e_aq_send_msg_to_vf
  * @hw: pointer to the hardware structure
  * @vfid: VF id to send msg
@@ -2766,35 +2969,6 @@
 	return status;
 }
 
-#define I40E_DEV_FUNC_CAP_SWITCH_MODE	0x01
-#define I40E_DEV_FUNC_CAP_MGMT_MODE	0x02
-#define I40E_DEV_FUNC_CAP_NPAR		0x03
-#define I40E_DEV_FUNC_CAP_OS2BMC	0x04
-#define I40E_DEV_FUNC_CAP_VALID_FUNC	0x05
-#define I40E_DEV_FUNC_CAP_SRIOV_1_1	0x12
-#define I40E_DEV_FUNC_CAP_VF		0x13
-#define I40E_DEV_FUNC_CAP_VMDQ		0x14
-#define I40E_DEV_FUNC_CAP_802_1_QBG	0x15
-#define I40E_DEV_FUNC_CAP_802_1_QBH	0x16
-#define I40E_DEV_FUNC_CAP_VSI		0x17
-#define I40E_DEV_FUNC_CAP_DCB		0x18
-#define I40E_DEV_FUNC_CAP_FCOE		0x21
-#define I40E_DEV_FUNC_CAP_ISCSI		0x22
-#define I40E_DEV_FUNC_CAP_RSS		0x40
-#define I40E_DEV_FUNC_CAP_RX_QUEUES	0x41
-#define I40E_DEV_FUNC_CAP_TX_QUEUES	0x42
-#define I40E_DEV_FUNC_CAP_MSIX		0x43
-#define I40E_DEV_FUNC_CAP_MSIX_VF	0x44
-#define I40E_DEV_FUNC_CAP_FLOW_DIRECTOR	0x45
-#define I40E_DEV_FUNC_CAP_IEEE_1588	0x46
-#define I40E_DEV_FUNC_CAP_FLEX10	0xF1
-#define I40E_DEV_FUNC_CAP_CEM		0xF2
-#define I40E_DEV_FUNC_CAP_IWARP		0x51
-#define I40E_DEV_FUNC_CAP_LED		0x61
-#define I40E_DEV_FUNC_CAP_SDP		0x62
-#define I40E_DEV_FUNC_CAP_MDIO		0x63
-#define I40E_DEV_FUNC_CAP_WR_CSR_PROT	0x64
-
 /**
  * i40e_parse_discover_capabilities
  * @hw: pointer to the hw struct
@@ -2833,79 +3007,79 @@
 		major_rev = cap->major_rev;
 
 		switch (id) {
-		case I40E_DEV_FUNC_CAP_SWITCH_MODE:
+		case I40E_AQ_CAP_ID_SWITCH_MODE:
 			p->switch_mode = number;
 			break;
-		case I40E_DEV_FUNC_CAP_MGMT_MODE:
+		case I40E_AQ_CAP_ID_MNG_MODE:
 			p->management_mode = number;
 			break;
-		case I40E_DEV_FUNC_CAP_NPAR:
+		case I40E_AQ_CAP_ID_NPAR_ACTIVE:
 			p->npar_enable = number;
 			break;
-		case I40E_DEV_FUNC_CAP_OS2BMC:
+		case I40E_AQ_CAP_ID_OS2BMC_CAP:
 			p->os2bmc = number;
 			break;
-		case I40E_DEV_FUNC_CAP_VALID_FUNC:
+		case I40E_AQ_CAP_ID_FUNCTIONS_VALID:
 			p->valid_functions = number;
 			break;
-		case I40E_DEV_FUNC_CAP_SRIOV_1_1:
+		case I40E_AQ_CAP_ID_SRIOV:
 			if (number == 1)
 				p->sr_iov_1_1 = true;
 			break;
-		case I40E_DEV_FUNC_CAP_VF:
+		case I40E_AQ_CAP_ID_VF:
 			p->num_vfs = number;
 			p->vf_base_id = logical_id;
 			break;
-		case I40E_DEV_FUNC_CAP_VMDQ:
+		case I40E_AQ_CAP_ID_VMDQ:
 			if (number == 1)
 				p->vmdq = true;
 			break;
-		case I40E_DEV_FUNC_CAP_802_1_QBG:
+		case I40E_AQ_CAP_ID_8021QBG:
 			if (number == 1)
 				p->evb_802_1_qbg = true;
 			break;
-		case I40E_DEV_FUNC_CAP_802_1_QBH:
+		case I40E_AQ_CAP_ID_8021QBR:
 			if (number == 1)
 				p->evb_802_1_qbh = true;
 			break;
-		case I40E_DEV_FUNC_CAP_VSI:
+		case I40E_AQ_CAP_ID_VSI:
 			p->num_vsis = number;
 			break;
-		case I40E_DEV_FUNC_CAP_DCB:
+		case I40E_AQ_CAP_ID_DCB:
 			if (number == 1) {
 				p->dcb = true;
 				p->enabled_tcmap = logical_id;
 				p->maxtc = phys_id;
 			}
 			break;
-		case I40E_DEV_FUNC_CAP_FCOE:
+		case I40E_AQ_CAP_ID_FCOE:
 			if (number == 1)
 				p->fcoe = true;
 			break;
-		case I40E_DEV_FUNC_CAP_ISCSI:
+		case I40E_AQ_CAP_ID_ISCSI:
 			if (number == 1)
 				p->iscsi = true;
 			break;
-		case I40E_DEV_FUNC_CAP_RSS:
+		case I40E_AQ_CAP_ID_RSS:
 			p->rss = true;
 			p->rss_table_size = number;
 			p->rss_table_entry_width = logical_id;
 			break;
-		case I40E_DEV_FUNC_CAP_RX_QUEUES:
+		case I40E_AQ_CAP_ID_RXQ:
 			p->num_rx_qp = number;
 			p->base_queue = phys_id;
 			break;
-		case I40E_DEV_FUNC_CAP_TX_QUEUES:
+		case I40E_AQ_CAP_ID_TXQ:
 			p->num_tx_qp = number;
 			p->base_queue = phys_id;
 			break;
-		case I40E_DEV_FUNC_CAP_MSIX:
+		case I40E_AQ_CAP_ID_MSIX:
 			p->num_msix_vectors = number;
 			break;
-		case I40E_DEV_FUNC_CAP_MSIX_VF:
+		case I40E_AQ_CAP_ID_VF_MSIX:
 			p->num_msix_vectors_vf = number;
 			break;
-		case I40E_DEV_FUNC_CAP_FLEX10:
+		case I40E_AQ_CAP_ID_FLEX10:
 			if (major_rev == 1) {
 				if (number == 1) {
 					p->flex10_enable = true;
@@ -2921,38 +3095,38 @@
 			p->flex10_mode = logical_id;
 			p->flex10_status = phys_id;
 			break;
-		case I40E_DEV_FUNC_CAP_CEM:
+		case I40E_AQ_CAP_ID_CEM:
 			if (number == 1)
 				p->mgmt_cem = true;
 			break;
-		case I40E_DEV_FUNC_CAP_IWARP:
+		case I40E_AQ_CAP_ID_IWARP:
 			if (number == 1)
 				p->iwarp = true;
 			break;
-		case I40E_DEV_FUNC_CAP_LED:
+		case I40E_AQ_CAP_ID_LED:
 			if (phys_id < I40E_HW_CAP_MAX_GPIO)
 				p->led[phys_id] = true;
 			break;
-		case I40E_DEV_FUNC_CAP_SDP:
+		case I40E_AQ_CAP_ID_SDP:
 			if (phys_id < I40E_HW_CAP_MAX_GPIO)
 				p->sdp[phys_id] = true;
 			break;
-		case I40E_DEV_FUNC_CAP_MDIO:
+		case I40E_AQ_CAP_ID_MDIO:
 			if (number == 1) {
 				p->mdio_port_num = phys_id;
 				p->mdio_port_mode = logical_id;
 			}
 			break;
-		case I40E_DEV_FUNC_CAP_IEEE_1588:
+		case I40E_AQ_CAP_ID_1588:
 			if (number == 1)
 				p->ieee_1588 = true;
 			break;
-		case I40E_DEV_FUNC_CAP_FLOW_DIRECTOR:
+		case I40E_AQ_CAP_ID_FLOW_DIRECTOR:
 			p->fd = true;
 			p->fd_filters_guaranteed = number;
 			p->fd_filters_best_effort = logical_id;
 			break;
-		case I40E_DEV_FUNC_CAP_WR_CSR_PROT:
+		case I40E_AQ_CAP_ID_WSR_PROT:
 			p->wr_csr_prot = (u64)number;
 			p->wr_csr_prot |= (u64)logical_id << 32;
 			break;
@@ -3710,7 +3884,7 @@
 		return ret;
 
 	/* Read the PF Queue Filter control register */
-	val = rd32(hw, I40E_PFQF_CTL_0);
+	val = i40e_read_rx_ctl(hw, I40E_PFQF_CTL_0);
 
 	/* Program required PE hash buckets for the PF */
 	val &= ~I40E_PFQF_CTL_0_PEHSIZE_MASK;
@@ -3747,7 +3921,7 @@
 	if (settings->enable_macvlan)
 		val |= I40E_PFQF_CTL_0_MACVLAN_ENA_MASK;
 
-	wr32(hw, I40E_PFQF_CTL_0, val);
+	i40e_write_rx_ctl(hw, I40E_PFQF_CTL_0, val);
 
 	return 0;
 }
@@ -4074,3 +4248,454 @@
 
 	return status;
 }
+
+/**
+ * i40e_read_phy_register
+ * @hw: pointer to the HW structure
+ * @page: registers page number
+ * @reg: register address in the page
+ * @phy_adr: PHY address on MDIO interface
+ * @value: PHY register value
+ *
+ * Reads specified PHY register value
+ **/
+i40e_status i40e_read_phy_register(struct i40e_hw *hw,
+				   u8 page, u16 reg, u8 phy_addr,
+				   u16 *value)
+{
+	i40e_status status = I40E_ERR_TIMEOUT;
+	u32 command = 0;
+	u16 retry = 1000;
+	u8 port_num = hw->func_caps.mdio_port_num;
+
+	command = (reg << I40E_GLGEN_MSCA_MDIADD_SHIFT) |
+		  (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+		  (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+		  (I40E_MDIO_OPCODE_ADDRESS) |
+		  (I40E_MDIO_STCODE) |
+		  (I40E_GLGEN_MSCA_MDICMD_MASK) |
+		  (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+	wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+	do {
+		command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+		if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+			status = 0;
+			break;
+		}
+		usleep_range(10, 20);
+		retry--;
+	} while (retry);
+
+	if (status) {
+		i40e_debug(hw, I40E_DEBUG_PHY,
+			   "PHY: Can't write command to external PHY.\n");
+		goto phy_read_end;
+	}
+
+	command = (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+		  (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+		  (I40E_MDIO_OPCODE_READ) |
+		  (I40E_MDIO_STCODE) |
+		  (I40E_GLGEN_MSCA_MDICMD_MASK) |
+		  (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+	status = I40E_ERR_TIMEOUT;
+	retry = 1000;
+	wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+	do {
+		command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+		if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+			status = 0;
+			break;
+		}
+		usleep_range(10, 20);
+		retry--;
+	} while (retry);
+
+	if (!status) {
+		command = rd32(hw, I40E_GLGEN_MSRWD(port_num));
+		*value = (command & I40E_GLGEN_MSRWD_MDIRDDATA_MASK) >>
+			 I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT;
+	} else {
+		i40e_debug(hw, I40E_DEBUG_PHY,
+			   "PHY: Can't read register value from external PHY.\n");
+	}
+
+phy_read_end:
+	return status;
+}
+
+/**
+ * i40e_write_phy_register
+ * @hw: pointer to the HW structure
+ * @page: registers page number
+ * @reg: register address in the page
+ * @phy_adr: PHY address on MDIO interface
+ * @value: PHY register value
+ *
+ * Writes value to specified PHY register
+ **/
+i40e_status i40e_write_phy_register(struct i40e_hw *hw,
+				    u8 page, u16 reg, u8 phy_addr,
+				    u16 value)
+{
+	i40e_status status = I40E_ERR_TIMEOUT;
+	u32 command = 0;
+	u16 retry = 1000;
+	u8 port_num = hw->func_caps.mdio_port_num;
+
+	command = (reg << I40E_GLGEN_MSCA_MDIADD_SHIFT) |
+		  (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+		  (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+		  (I40E_MDIO_OPCODE_ADDRESS) |
+		  (I40E_MDIO_STCODE) |
+		  (I40E_GLGEN_MSCA_MDICMD_MASK) |
+		  (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+	wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+	do {
+		command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+		if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+			status = 0;
+			break;
+		}
+		usleep_range(10, 20);
+		retry--;
+	} while (retry);
+	if (status) {
+		i40e_debug(hw, I40E_DEBUG_PHY,
+			   "PHY: Can't write command to external PHY.\n");
+		goto phy_write_end;
+	}
+
+	command = value << I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT;
+	wr32(hw, I40E_GLGEN_MSRWD(port_num), command);
+
+	command = (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+		  (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+		  (I40E_MDIO_OPCODE_WRITE) |
+		  (I40E_MDIO_STCODE) |
+		  (I40E_GLGEN_MSCA_MDICMD_MASK) |
+		  (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+	status = I40E_ERR_TIMEOUT;
+	retry = 1000;
+	wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+	do {
+		command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+		if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+			status = 0;
+			break;
+		}
+		usleep_range(10, 20);
+		retry--;
+	} while (retry);
+
+phy_write_end:
+	return status;
+}
+
+/**
+ * i40e_get_phy_address
+ * @hw: pointer to the HW structure
+ * @dev_num: PHY port num that address we want
+ * @phy_addr: Returned PHY address
+ *
+ * Gets PHY address for current port
+ **/
+u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num)
+{
+	u8 port_num = hw->func_caps.mdio_port_num;
+	u32 reg_val = rd32(hw, I40E_GLGEN_MDIO_I2C_SEL(port_num));
+
+	return (u8)(reg_val >> ((dev_num + 1) * 5)) & 0x1f;
+}
+
+/**
+ * i40e_blink_phy_led
+ * @hw: pointer to the HW structure
+ * @time: time how long led will blinks in secs
+ * @interval: gap between LED on and off in msecs
+ *
+ * Blinks PHY link LED
+ **/
+i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
+				    u32 time, u32 interval)
+{
+	i40e_status status = 0;
+	u32 i;
+	u16 led_ctl;
+	u16 gpio_led_port;
+	u16 led_reg;
+	u16 led_addr = I40E_PHY_LED_PROV_REG_1;
+	u8 phy_addr = 0;
+	u8 port_num;
+
+	i = rd32(hw, I40E_PFGEN_PORTNUM);
+	port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+	phy_addr = i40e_get_phy_address(hw, port_num);
+
+	for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++,
+	     led_addr++) {
+		status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+						led_addr, phy_addr, &led_reg);
+		if (status)
+			goto phy_blinking_end;
+		led_ctl = led_reg;
+		if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) {
+			led_reg = 0;
+			status = i40e_write_phy_register(hw,
+							 I40E_PHY_COM_REG_PAGE,
+							 led_addr, phy_addr,
+							 led_reg);
+			if (status)
+				goto phy_blinking_end;
+			break;
+		}
+	}
+
+	if (time > 0 && interval > 0) {
+		for (i = 0; i < time * 1000; i += interval) {
+			status = i40e_read_phy_register(hw,
+							I40E_PHY_COM_REG_PAGE,
+							led_addr, phy_addr,
+							&led_reg);
+			if (status)
+				goto restore_config;
+			if (led_reg & I40E_PHY_LED_MANUAL_ON)
+				led_reg = 0;
+			else
+				led_reg = I40E_PHY_LED_MANUAL_ON;
+			status = i40e_write_phy_register(hw,
+							 I40E_PHY_COM_REG_PAGE,
+							 led_addr, phy_addr,
+							 led_reg);
+			if (status)
+				goto restore_config;
+			msleep(interval);
+		}
+	}
+
+restore_config:
+	status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+					 phy_addr, led_ctl);
+
+phy_blinking_end:
+	return status;
+}
+
+/**
+ * i40e_led_get_phy - return current on/off mode
+ * @hw: pointer to the hw struct
+ * @led_addr: address of led register to use
+ * @val: original value of register to use
+ *
+ **/
+i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
+			     u16 *val)
+{
+	i40e_status status = 0;
+	u16 gpio_led_port;
+	u8 phy_addr = 0;
+	u16 reg_val;
+	u16 temp_addr;
+	u8 port_num;
+	u32 i;
+
+	temp_addr = I40E_PHY_LED_PROV_REG_1;
+	i = rd32(hw, I40E_PFGEN_PORTNUM);
+	port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+	phy_addr = i40e_get_phy_address(hw, port_num);
+
+	for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++,
+	     temp_addr++) {
+		status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+						temp_addr, phy_addr, &reg_val);
+		if (status)
+			return status;
+		*val = reg_val;
+		if (reg_val & I40E_PHY_LED_LINK_MODE_MASK) {
+			*led_addr = temp_addr;
+			break;
+		}
+	}
+	return status;
+}
+
+/**
+ * i40e_led_set_phy
+ * @hw: pointer to the HW structure
+ * @on: true or false
+ * @mode: original val plus bit for set or ignore
+ * Set led's on or off when controlled by the PHY
+ *
+ **/
+i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on,
+			     u16 led_addr, u32 mode)
+{
+	i40e_status status = 0;
+	u16 led_ctl = 0;
+	u16 led_reg = 0;
+	u8 phy_addr = 0;
+	u8 port_num;
+	u32 i;
+
+	i = rd32(hw, I40E_PFGEN_PORTNUM);
+	port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+	phy_addr = i40e_get_phy_address(hw, port_num);
+
+	status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+					phy_addr, &led_reg);
+	if (status)
+		return status;
+	led_ctl = led_reg;
+	if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) {
+		led_reg = 0;
+		status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+						 led_addr, phy_addr, led_reg);
+		if (status)
+			return status;
+	}
+	status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+					led_addr, phy_addr, &led_reg);
+	if (status)
+		goto restore_config;
+	if (on)
+		led_reg = I40E_PHY_LED_MANUAL_ON;
+	else
+		led_reg = 0;
+	status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+					 led_addr, phy_addr, led_reg);
+	if (status)
+		goto restore_config;
+	if (mode & I40E_PHY_LED_MODE_ORIG) {
+		led_ctl = (mode & I40E_PHY_LED_MODE_MASK);
+		status = i40e_write_phy_register(hw,
+						 I40E_PHY_COM_REG_PAGE,
+						 led_addr, phy_addr, led_ctl);
+	}
+	return status;
+restore_config:
+	status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+					 phy_addr, led_ctl);
+	return status;
+}
+
+/**
+ * i40e_aq_rx_ctl_read_register - use FW to read from an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: ptr to register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Use the firmware to read the Rx control register,
+ * especially useful if the Rx unit is under heavy pressure
+ **/
+i40e_status i40e_aq_rx_ctl_read_register(struct i40e_hw *hw,
+				u32 reg_addr, u32 *reg_val,
+				struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_rx_ctl_reg_read_write *cmd_resp =
+		(struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
+	i40e_status status;
+
+	if (!reg_val)
+		return I40E_ERR_PARAM;
+
+	i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_rx_ctl_reg_read);
+
+	cmd_resp->address = cpu_to_le32(reg_addr);
+
+	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+	if (status == 0)
+		*reg_val = le32_to_cpu(cmd_resp->value);
+
+	return status;
+}
+
+/**
+ * i40e_read_rx_ctl - read from an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ **/
+u32 i40e_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr)
+{
+	i40e_status status = 0;
+	bool use_register;
+	int retry = 5;
+	u32 val = 0;
+
+	use_register = (hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver < 5);
+	if (!use_register) {
+do_retry:
+		status = i40e_aq_rx_ctl_read_register(hw, reg_addr, &val, NULL);
+		if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
+			usleep_range(1000, 2000);
+			retry--;
+			goto do_retry;
+		}
+	}
+
+	/* if the AQ access failed, try the old-fashioned way */
+	if (status || use_register)
+		val = rd32(hw, reg_addr);
+
+	return val;
+}
+
+/**
+ * i40e_aq_rx_ctl_write_register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Use the firmware to write to an Rx control register,
+ * especially useful if the Rx unit is under heavy pressure
+ **/
+i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
+				u32 reg_addr, u32 reg_val,
+				struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_rx_ctl_reg_read_write *cmd =
+		(struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
+	i40e_status status;
+
+	i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_rx_ctl_reg_write);
+
+	cmd->address = cpu_to_le32(reg_addr);
+	cmd->value = cpu_to_le32(reg_val);
+
+	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+	return status;
+}
+
+/**
+ * i40e_write_rx_ctl - write to an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ **/
+void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
+{
+	i40e_status status = 0;
+	bool use_register;
+	int retry = 5;
+
+	use_register = (hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver < 5);
+	if (!use_register) {
+do_retry:
+		status = i40e_aq_rx_ctl_write_register(hw, reg_addr,
+						       reg_val, NULL);
+		if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
+			usleep_range(1000, 2000);
+			retry--;
+			goto do_retry;
+		}
+	}
+
+	/* if the AQ access failed, try the old-fashioned way */
+	if (status || use_register)
+		wr32(hw, reg_addr, reg_val);
+}
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_dcb.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_dcb.c
@@ -380,17 +380,20 @@
 {
 	u16 length, typelength, offset = 0;
 	struct i40e_cee_app_prio *app;
-	u8 i, up, selector;
+	u8 i;
 
 	typelength = ntohs(tlv->hdr.typelen);
 	length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
 		       I40E_LLDP_TLV_LEN_SHIFT);
 
 	dcbcfg->numapps = length / sizeof(*app);
+
 	if (!dcbcfg->numapps)
 		return;
 
 	for (i = 0; i < dcbcfg->numapps; i++) {
+		u8 up, selector;
+
 		app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
 		for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
 			if (app->prio_map & BIT(up))
@@ -400,13 +403,17 @@
 
 		/* Get Selector from lower 2 bits, and convert to IEEE */
 		selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
-		if (selector == I40E_CEE_APP_SEL_ETHTYPE)
+		switch (selector) {
+		case I40E_CEE_APP_SEL_ETHTYPE:
 			dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
-		else if (selector == I40E_CEE_APP_SEL_TCPIP)
+			break;
+		case I40E_CEE_APP_SEL_TCPIP:
 			dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
-		else
+			break;
+		default:
 			/* Keep selector as it is for unknown types */
 			dcbcfg->app[i].selector = selector;
+		}
 
 		dcbcfg->app[i].protocolid = ntohs(app->protocol);
 		/* Move to next app */
@@ -814,13 +821,15 @@
 	struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
 	struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
 
-	/* If Firmware version < v4.33 IEEE only */
-	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
-	    (hw->aq.fw_maj_ver < 4))
+	/* If Firmware version < v4.33 on X710/XL710, IEEE only */
+	if ((hw->mac.type == I40E_MAC_XL710) &&
+	    (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
+	      (hw->aq.fw_maj_ver < 4)))
 		return i40e_get_ieee_dcb_config(hw);
 
-	/* If Firmware version == v4.33 use old CEE struct */
-	if ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33)) {
+	/* If Firmware version == v4.33 on X710/XL710, use old CEE struct */
+	if ((hw->mac.type == I40E_MAC_XL710) &&
+	    ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) {
 		ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
 						 sizeof(cee_v1_cfg), NULL);
 		if (!ret) {
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -61,257 +61,13 @@
 {
 	int i;
 
-	if ((seid < I40E_BASE_VEB_SEID) ||
-	    (seid > (I40E_BASE_VEB_SEID + I40E_MAX_VEB)))
-		dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
-	else
-		for (i = 0; i < I40E_MAX_VEB; i++)
-			if (pf->veb[i] && pf->veb[i]->seid == seid)
-				return pf->veb[i];
+	for (i = 0; i < I40E_MAX_VEB; i++)
+		if (pf->veb[i] && pf->veb[i]->seid == seid)
+			return pf->veb[i];
 	return NULL;
 }
 
 /**************************************************************
- * dump
- * The dump entry in debugfs is for getting a data snapshow of
- * the driver's current configuration and runtime details.
- * When the filesystem entry is written, a snapshot is taken.
- * When the entry is read, the most recent snapshot data is dumped.
- **************************************************************/
-static char *i40e_dbg_dump_buf;
-static ssize_t i40e_dbg_dump_data_len;
-static ssize_t i40e_dbg_dump_buffer_len;
-
-/**
- * i40e_dbg_dump_read - read the dump data
- * @filp: the opened file
- * @buffer: where to write the data for the user to read
- * @count: the size of the user's buffer
- * @ppos: file position offset
- **/
-static ssize_t i40e_dbg_dump_read(struct file *filp, char __user *buffer,
-				  size_t count, loff_t *ppos)
-{
-	int bytes_not_copied;
-	int len;
-
-	/* is *ppos bigger than the available data? */
-	if (*ppos >= i40e_dbg_dump_data_len || !i40e_dbg_dump_buf)
-		return 0;
-
-	/* be sure to not read beyond the end of available data */
-	len = min_t(int, count, (i40e_dbg_dump_data_len - *ppos));
-
-	bytes_not_copied = copy_to_user(buffer, &i40e_dbg_dump_buf[*ppos], len);
-	if (bytes_not_copied < 0)
-		return bytes_not_copied;
-
-	*ppos += len;
-	return len;
-}
-
-/**
- * i40e_dbg_prep_dump_buf
- * @pf: the PF we're working with
- * @buflen: the desired buffer length
- *
- * Return positive if success, 0 if failed
- **/
-static int i40e_dbg_prep_dump_buf(struct i40e_pf *pf, int buflen)
-{
-	/* if not already big enough, prep for re alloc */
-	if (i40e_dbg_dump_buffer_len && i40e_dbg_dump_buffer_len < buflen) {
-		kfree(i40e_dbg_dump_buf);
-		i40e_dbg_dump_buffer_len = 0;
-		i40e_dbg_dump_buf = NULL;
-	}
-
-	/* get a new buffer if needed */
-	if (!i40e_dbg_dump_buf) {
-		i40e_dbg_dump_buf = kzalloc(buflen, GFP_KERNEL);
-		if (i40e_dbg_dump_buf != NULL)
-			i40e_dbg_dump_buffer_len = buflen;
-	}
-
-	return i40e_dbg_dump_buffer_len;
-}
-
-/**
- * i40e_dbg_dump_write - trigger a datadump snapshot
- * @filp: the opened file
- * @buffer: where to find the user's data
- * @count: the length of the user's data
- * @ppos: file position offset
- *
- * Any write clears the stats
- **/
-static ssize_t i40e_dbg_dump_write(struct file *filp,
-				   const char __user *buffer,
-				   size_t count, loff_t *ppos)
-{
-	struct i40e_pf *pf = filp->private_data;
-	bool seid_found = false;
-	long seid = -1;
-	int buflen = 0;
-	int i, ret;
-	int len;
-	u8 *p;
-
-	/* don't allow partial writes */
-	if (*ppos != 0)
-		return 0;
-
-	/* decode the SEID given to be dumped */
-	ret = kstrtol_from_user(buffer, count, 0, &seid);
-
-	if (ret) {
-		dev_info(&pf->pdev->dev, "bad seid value\n");
-	} else if (seid == 0) {
-		seid_found = true;
-
-		kfree(i40e_dbg_dump_buf);
-		i40e_dbg_dump_buffer_len = 0;
-		i40e_dbg_dump_data_len = 0;
-		i40e_dbg_dump_buf = NULL;
-		dev_info(&pf->pdev->dev, "debug buffer freed\n");
-
-	} else if (seid == pf->pf_seid || seid == 1) {
-		seid_found = true;
-
-		buflen = sizeof(struct i40e_pf);
-		buflen += (sizeof(struct i40e_aq_desc)
-		     * (pf->hw.aq.num_arq_entries + pf->hw.aq.num_asq_entries));
-
-		if (i40e_dbg_prep_dump_buf(pf, buflen)) {
-			p = i40e_dbg_dump_buf;
-
-			len = sizeof(struct i40e_pf);
-			memcpy(p, pf, len);
-			p += len;
-
-			len = (sizeof(struct i40e_aq_desc)
-					* pf->hw.aq.num_asq_entries);
-			memcpy(p, pf->hw.aq.asq.desc_buf.va, len);
-			p += len;
-
-			len = (sizeof(struct i40e_aq_desc)
-					* pf->hw.aq.num_arq_entries);
-			memcpy(p, pf->hw.aq.arq.desc_buf.va, len);
-			p += len;
-
-			i40e_dbg_dump_data_len = buflen;
-			dev_info(&pf->pdev->dev,
-				 "PF seid %ld dumped %d bytes\n",
-				 seid, (int)i40e_dbg_dump_data_len);
-		}
-	} else if (seid >= I40E_BASE_VSI_SEID) {
-		struct i40e_vsi *vsi = NULL;
-		struct i40e_mac_filter *f;
-		int filter_count = 0;
-
-		mutex_lock(&pf->switch_mutex);
-		vsi = i40e_dbg_find_vsi(pf, seid);
-		if (!vsi) {
-			mutex_unlock(&pf->switch_mutex);
-			goto write_exit;
-		}
-
-		buflen = sizeof(struct i40e_vsi);
-		buflen += sizeof(struct i40e_q_vector) * vsi->num_q_vectors;
-		buflen += sizeof(struct i40e_ring) * 2 * vsi->num_queue_pairs;
-		buflen += sizeof(struct i40e_tx_buffer) * vsi->num_queue_pairs;
-		buflen += sizeof(struct i40e_rx_buffer) * vsi->num_queue_pairs;
-		list_for_each_entry(f, &vsi->mac_filter_list, list)
-			filter_count++;
-		buflen += sizeof(struct i40e_mac_filter) * filter_count;
-
-		if (i40e_dbg_prep_dump_buf(pf, buflen)) {
-			p = i40e_dbg_dump_buf;
-			seid_found = true;
-
-			len = sizeof(struct i40e_vsi);
-			memcpy(p, vsi, len);
-			p += len;
-
-			if (vsi->num_q_vectors) {
-				len = (sizeof(struct i40e_q_vector)
-					* vsi->num_q_vectors);
-				memcpy(p, vsi->q_vectors, len);
-				p += len;
-			}
-
-			if (vsi->num_queue_pairs) {
-				len = (sizeof(struct i40e_ring) *
-				      vsi->num_queue_pairs);
-				memcpy(p, vsi->tx_rings, len);
-				p += len;
-				memcpy(p, vsi->rx_rings, len);
-				p += len;
-			}
-
-			if (vsi->tx_rings[0]) {
-				len = sizeof(struct i40e_tx_buffer);
-				for (i = 0; i < vsi->num_queue_pairs; i++) {
-					memcpy(p, vsi->tx_rings[i]->tx_bi, len);
-					p += len;
-				}
-				len = sizeof(struct i40e_rx_buffer);
-				for (i = 0; i < vsi->num_queue_pairs; i++) {
-					memcpy(p, vsi->rx_rings[i]->rx_bi, len);
-					p += len;
-				}
-			}
-
-			/* macvlan filter list */
-			len = sizeof(struct i40e_mac_filter);
-			list_for_each_entry(f, &vsi->mac_filter_list, list) {
-				memcpy(p, f, len);
-				p += len;
-			}
-
-			i40e_dbg_dump_data_len = buflen;
-			dev_info(&pf->pdev->dev,
-				 "VSI seid %ld dumped %d bytes\n",
-				 seid, (int)i40e_dbg_dump_data_len);
-		}
-		mutex_unlock(&pf->switch_mutex);
-	} else if (seid >= I40E_BASE_VEB_SEID) {
-		struct i40e_veb *veb = NULL;
-
-		mutex_lock(&pf->switch_mutex);
-		veb = i40e_dbg_find_veb(pf, seid);
-		if (!veb) {
-			mutex_unlock(&pf->switch_mutex);
-			goto write_exit;
-		}
-
-		buflen = sizeof(struct i40e_veb);
-		if (i40e_dbg_prep_dump_buf(pf, buflen)) {
-			seid_found = true;
-			memcpy(i40e_dbg_dump_buf, veb, buflen);
-			i40e_dbg_dump_data_len = buflen;
-			dev_info(&pf->pdev->dev,
-				 "VEB seid %ld dumped %d bytes\n",
-				 seid, (int)i40e_dbg_dump_data_len);
-		}
-		mutex_unlock(&pf->switch_mutex);
-	}
-
-write_exit:
-	if (!seid_found)
-		dev_info(&pf->pdev->dev, "unknown seid %ld\n", seid);
-
-	return count;
-}
-
-static const struct file_operations i40e_dbg_dump_fops = {
-	.owner = THIS_MODULE,
-	.open =  simple_open,
-	.read =  i40e_dbg_dump_read,
-	.write = i40e_dbg_dump_write,
-};
-
-/**************************************************************
  * command
  * The command entry in debugfs is for giving the driver commands
  * to be executed - these may be for changing the internal switch
@@ -353,8 +109,8 @@
 	bytes_not_copied = copy_to_user(buffer, buf, len);
 	kfree(buf);
 
-	if (bytes_not_copied < 0)
-		return bytes_not_copied;
+	if (bytes_not_copied)
+		return -EFAULT;
 
 	*ppos = len;
 	return len;
@@ -379,19 +135,27 @@
 		return;
 	}
 	dev_info(&pf->pdev->dev, "vsi seid %d\n", seid);
-	if (vsi->netdev)
-		dev_info(&pf->pdev->dev,
-			 "    netdev: name = %s\n",
-			 vsi->netdev->name);
+	if (vsi->netdev) {
+		struct net_device *nd = vsi->netdev;
+
+		dev_info(&pf->pdev->dev, "    netdev: name = %s, state = %lu, flags = 0x%08x\n",
+			 nd->name, nd->state, nd->flags);
+		dev_info(&pf->pdev->dev, "        features      = 0x%08lx\n",
+			 (unsigned long int)nd->features);
+		dev_info(&pf->pdev->dev, "        hw_features   = 0x%08lx\n",
+			 (unsigned long int)nd->hw_features);
+		dev_info(&pf->pdev->dev, "        vlan_features = 0x%08lx\n",
+			 (unsigned long int)nd->vlan_features);
+	}
 	if (vsi->active_vlans)
 		dev_info(&pf->pdev->dev,
 			 "    vlgrp: & = %p\n", vsi->active_vlans);
 	dev_info(&pf->pdev->dev,
-		 "    netdev_registered = %i, current_netdev_flags = 0x%04x, state = %li flags = 0x%08lx\n",
-		 vsi->netdev_registered,
-		 vsi->current_netdev_flags, vsi->state, vsi->flags);
+		 "    state = %li flags = 0x%08lx, netdev_registered = %i, current_netdev_flags = 0x%04x\n",
+		 vsi->state, vsi->flags,
+		 vsi->netdev_registered, vsi->current_netdev_flags);
 	if (vsi == pf->vsi[pf->lan_vsi])
-		dev_info(&pf->pdev->dev, "MAC address: %pM SAN MAC: %pM Port MAC: %pM\n",
+		dev_info(&pf->pdev->dev, "    MAC address: %pM SAN MAC: %pM Port MAC: %pM\n",
 			 pf->hw.mac.addr,
 			 pf->hw.mac.san_addr,
 			 pf->hw.mac.port_addr);
@@ -510,8 +274,8 @@
 			 rx_ring->rx_buf_len,
 			 rx_ring->dtype);
 		dev_info(&pf->pdev->dev,
-			 "    rx_rings[%i]: hsplit = %d, next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
-			 i, rx_ring->hsplit,
+			 "    rx_rings[%i]: next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
+			 i,
 			 rx_ring->next_to_use,
 			 rx_ring->next_to_clean,
 			 rx_ring->ring_active);
@@ -526,6 +290,11 @@
 			 rx_ring->rx_stats.alloc_page_failed,
 			 rx_ring->rx_stats.alloc_buff_failed);
 		dev_info(&pf->pdev->dev,
+			 "    rx_rings[%i]: rx_stats: realloc_count = %lld, page_reuse_count = %lld\n",
+			 i,
+			 rx_ring->rx_stats.realloc_count,
+			 rx_ring->rx_stats.page_reuse_count);
+		dev_info(&pf->pdev->dev,
 			 "    rx_rings[%i]: size = %i, dma = 0x%08lx\n",
 			 i, rx_ring->size,
 			 (unsigned long int)rx_ring->dma);
@@ -557,8 +326,8 @@
 			 "    tx_rings[%i]: dtype = %d\n",
 			 i, tx_ring->dtype);
 		dev_info(&pf->pdev->dev,
-			 "    tx_rings[%i]: hsplit = %d, next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
-			 i, tx_ring->hsplit,
+			 "    tx_rings[%i]: next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
+			 i,
 			 tx_ring->next_to_use,
 			 tx_ring->next_to_clean,
 			 tx_ring->ring_active);
@@ -791,6 +560,14 @@
 		dev_info(&pf->pdev->dev, "vsi %d not found\n", vsi_seid);
 		return;
 	}
+	if (vsi->type != I40E_VSI_MAIN &&
+	    vsi->type != I40E_VSI_FDIR &&
+	    vsi->type != I40E_VSI_VMDQ2) {
+		dev_info(&pf->pdev->dev,
+			 "vsi %d type %d descriptor rings not available\n",
+			 vsi_seid, vsi->type);
+		return;
+	}
 	if (ring_id >= vsi->num_queue_pairs || ring_id < 0) {
 		dev_info(&pf->pdev->dev, "ring %d not found\n", ring_id);
 		return;
@@ -815,20 +592,20 @@
 			if (!is_rx_ring) {
 				txd = I40E_TX_DESC(ring, i);
 				dev_info(&pf->pdev->dev,
-					 "   d[%03i] = 0x%016llx 0x%016llx\n",
+					 "   d[%03x] = 0x%016llx 0x%016llx\n",
 					 i, txd->buffer_addr,
 					 txd->cmd_type_offset_bsz);
 			} else if (sizeof(union i40e_rx_desc) ==
 				   sizeof(union i40e_16byte_rx_desc)) {
 				rxd = I40E_RX_DESC(ring, i);
 				dev_info(&pf->pdev->dev,
-					 "   d[%03i] = 0x%016llx 0x%016llx\n",
+					 "   d[%03x] = 0x%016llx 0x%016llx\n",
 					 i, rxd->read.pkt_addr,
 					 rxd->read.hdr_addr);
 			} else {
 				rxd = I40E_RX_DESC(ring, i);
 				dev_info(&pf->pdev->dev,
-					 "   d[%03i] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
+					 "   d[%03x] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
 					 i, rxd->read.pkt_addr,
 					 rxd->read.hdr_addr,
 					 rxd->read.rsvd1, rxd->read.rsvd2);
@@ -843,20 +620,20 @@
 		if (!is_rx_ring) {
 			txd = I40E_TX_DESC(ring, desc_n);
 			dev_info(&pf->pdev->dev,
-				 "vsi = %02i tx ring = %02i d[%03i] = 0x%016llx 0x%016llx\n",
+				 "vsi = %02i tx ring = %02i d[%03x] = 0x%016llx 0x%016llx\n",
 				 vsi_seid, ring_id, desc_n,
 				 txd->buffer_addr, txd->cmd_type_offset_bsz);
 		} else if (sizeof(union i40e_rx_desc) ==
 			   sizeof(union i40e_16byte_rx_desc)) {
 			rxd = I40E_RX_DESC(ring, desc_n);
 			dev_info(&pf->pdev->dev,
-				 "vsi = %02i rx ring = %02i d[%03i] = 0x%016llx 0x%016llx\n",
+				 "vsi = %02i rx ring = %02i d[%03x] = 0x%016llx 0x%016llx\n",
 				 vsi_seid, ring_id, desc_n,
 				 rxd->read.pkt_addr, rxd->read.hdr_addr);
 		} else {
 			rxd = I40E_RX_DESC(ring, desc_n);
 			dev_info(&pf->pdev->dev,
-				 "vsi = %02i rx ring = %02i d[%03i] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
+				 "vsi = %02i rx ring = %02i d[%03x] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
 				 vsi_seid, ring_id, desc_n,
 				 rxd->read.pkt_addr, rxd->read.hdr_addr,
 				 rxd->read.rsvd1, rxd->read.rsvd2);
@@ -918,12 +695,6 @@
 {
 	struct i40e_veb *veb;
 
-	if ((seid < I40E_BASE_VEB_SEID) ||
-	    (seid >= (I40E_MAX_VEB + I40E_BASE_VEB_SEID))) {
-		dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
-		return;
-	}
-
 	veb = i40e_dbg_find_veb(pf, seid);
 	if (!veb) {
 		dev_info(&pf->pdev->dev, "can't find veb %d\n", seid);
@@ -981,12 +752,10 @@
 	if (!cmd_buf)
 		return count;
 	bytes_not_copied = copy_from_user(cmd_buf, buffer, count);
-	if (bytes_not_copied < 0) {
+	if (bytes_not_copied) {
 		kfree(cmd_buf);
-		return bytes_not_copied;
+		return -EFAULT;
 	}
-	if (bytes_not_copied > 0)
-		count -= bytes_not_copied;
 	cmd_buf[count] = '\0';
 
 	cmd_buf_tmp = strchr(cmd_buf, '\n');
@@ -1140,7 +909,7 @@
 		spin_lock_bh(&vsi->mac_filter_list_lock);
 		f = i40e_add_filter(vsi, ma, vlan, false, false);
 		spin_unlock_bh(&vsi->mac_filter_list_lock);
-		ret = i40e_sync_vsi_filters(vsi, true);
+		ret = i40e_sync_vsi_filters(vsi);
 		if (f && !ret)
 			dev_info(&pf->pdev->dev,
 				 "add macaddr: %pM vlan=%d added to VSI %d\n",
@@ -1179,7 +948,7 @@
 		spin_lock_bh(&vsi->mac_filter_list_lock);
 		i40e_del_filter(vsi, ma, vlan, false, false);
 		spin_unlock_bh(&vsi->mac_filter_list_lock);
-		ret = i40e_sync_vsi_filters(vsi, true);
+		ret = i40e_sync_vsi_filters(vsi);
 		if (!ret)
 			dev_info(&pf->pdev->dev,
 				 "del macaddr: %pM vlan=%d removed from VSI %d\n",
@@ -2034,8 +1803,8 @@
 	bytes_not_copied = copy_to_user(buffer, buf, len);
 	kfree(buf);
 
-	if (bytes_not_copied < 0)
-		return bytes_not_copied;
+	if (bytes_not_copied)
+		return -EFAULT;
 
 	*ppos = len;
 	return len;
@@ -2068,10 +1837,8 @@
 	memset(i40e_dbg_netdev_ops_buf, 0, sizeof(i40e_dbg_netdev_ops_buf));
 	bytes_not_copied = copy_from_user(i40e_dbg_netdev_ops_buf,
 					  buffer, count);
-	if (bytes_not_copied < 0)
-		return bytes_not_copied;
-	else if (bytes_not_copied > 0)
-		count -= bytes_not_copied;
+	if (bytes_not_copied)
+		return -EFAULT;
 	i40e_dbg_netdev_ops_buf[count] = '\0';
 
 	buf_tmp = strchr(i40e_dbg_netdev_ops_buf, '\n');
@@ -2206,11 +1973,6 @@
 	if (!pfile)
 		goto create_failed;
 
-	pfile = debugfs_create_file("dump", 0600, pf->i40e_dbg_pf, pf,
-				    &i40e_dbg_dump_fops);
-	if (!pfile)
-		goto create_failed;
-
 	pfile = debugfs_create_file("netdev_ops", 0600, pf->i40e_dbg_pf, pf,
 				    &i40e_dbg_netdev_ops_fops);
 	if (!pfile)
@@ -2231,9 +1993,6 @@
 {
 	debugfs_remove_recursive(pf->i40e_dbg_pf);
 	pf->i40e_dbg_pf = NULL;
-
-	kfree(i40e_dbg_dump_buf);
-	i40e_dbg_dump_buf = NULL;
 }
 
 /**
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_devids.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_devids.h
@@ -30,7 +30,6 @@
 /* Device IDs */
 #define I40E_DEV_ID_SFP_XL710		0x1572
 #define I40E_DEV_ID_QEMU		0x1574
-#define I40E_DEV_ID_KX_A		0x157F
 #define I40E_DEV_ID_KX_B		0x1580
 #define I40E_DEV_ID_KX_C		0x1581
 #define I40E_DEV_ID_QSFP_A		0x1583
@@ -40,13 +39,11 @@
 #define I40E_DEV_ID_20G_KR2		0x1587
 #define I40E_DEV_ID_20G_KR2_A		0x1588
 #define I40E_DEV_ID_10G_BASE_T4		0x1589
-#define I40E_DEV_ID_VF			0x154C
-#define I40E_DEV_ID_VF_HV		0x1571
+#define I40E_DEV_ID_KX_X722		0x37CE
+#define I40E_DEV_ID_QSFP_X722		0x37CF
 #define I40E_DEV_ID_SFP_X722		0x37D0
 #define I40E_DEV_ID_1G_BASE_T_X722	0x37D1
 #define I40E_DEV_ID_10G_BASE_T_X722	0x37D2
-#define I40E_DEV_ID_X722_VF		0x37CD
-#define I40E_DEV_ID_X722_VF_HV		0x37D9
 
 #define i40e_is_40G_device(d)		((d) == I40E_DEV_ID_QSFP_A  || \
 					 (d) == I40E_DEV_ID_QSFP_B  || \
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -88,6 +88,10 @@
 	I40E_VSI_STAT("tx_broadcast", eth_stats.tx_broadcast),
 	I40E_VSI_STAT("rx_unknown_protocol", eth_stats.rx_unknown_protocol),
 	I40E_VSI_STAT("tx_linearize", tx_linearize),
+	I40E_VSI_STAT("tx_force_wb", tx_force_wb),
+	I40E_VSI_STAT("tx_lost_interrupt", tx_lost_interrupt),
+	I40E_VSI_STAT("rx_alloc_fail", rx_buf_failed),
+	I40E_VSI_STAT("rx_pg_alloc_fail", rx_page_failed),
 };
 
 /* These PF_STATs might look like duplicates of some NETDEV_STATs,
@@ -142,6 +146,7 @@
 	I40E_PF_STAT("rx_oversize", stats.rx_oversize),
 	I40E_PF_STAT("rx_jabber", stats.rx_jabber),
 	I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
+	I40E_PF_STAT("arq_overflows", arq_overflows),
 	I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
 	I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt),
 	I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match),
@@ -230,6 +235,8 @@
 	"LinkPolling",
 	"flow-director-atr",
 	"veb-stats",
+	"packet-split",
+	"hw-atr-eviction",
 };
 
 #define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_priv_flags_strings)
@@ -338,7 +345,7 @@
 				  SUPPORTED_1000baseT_Full;
 		if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB)
 			ecmd->advertising |= ADVERTISED_1000baseT_Full;
-		if (pf->hw.mac.type == I40E_MAC_X722) {
+		if (pf->flags & I40E_FLAG_100M_SGMII_CAPABLE) {
 			ecmd->supported |= SUPPORTED_100baseT_Full;
 			if (hw_link_info->requested_speeds &
 			    I40E_LINK_SPEED_100MB)
@@ -409,6 +416,10 @@
 		if (pf->hw.mac.type == I40E_MAC_X722) {
 			ecmd->supported |= SUPPORTED_100baseT_Full;
 			ecmd->advertising |= ADVERTISED_100baseT_Full;
+			if (pf->flags & I40E_FLAG_100M_SGMII_CAPABLE) {
+				ecmd->supported |= SUPPORTED_100baseT_Full;
+				ecmd->advertising |= ADVERTISED_100baseT_Full;
+			}
 		}
 	}
 	if (phy_types & I40E_CAP_PHY_TYPE_XAUI ||
@@ -994,16 +1005,19 @@
 	/* check for NVMUpdate access method */
 	magic = hw->vendor_id | (hw->device_id << 16);
 	if (eeprom->magic && eeprom->magic != magic) {
-		struct i40e_nvm_access *cmd;
-		int errno;
+		struct i40e_nvm_access *cmd = (struct i40e_nvm_access *)eeprom;
+		int errno = 0;
 
 		/* make sure it is the right magic for NVMUpdate */
 		if ((eeprom->magic >> 16) != hw->device_id)
-			return -EINVAL;
+			errno = -EINVAL;
+		else if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
+			 test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
+			errno = -EBUSY;
+		else
+			ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
 
-		cmd = (struct i40e_nvm_access *)eeprom;
-		ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
-		if (ret_val && (hw->debug_mask & I40E_DEBUG_NVM))
+		if ((errno || ret_val) && (hw->debug_mask & I40E_DEBUG_NVM))
 			dev_info(&pf->pdev->dev,
 				 "NVMUpdate read failed err=%d status=0x%x errno=%d module=%d offset=0x%x size=%d\n",
 				 ret_val, hw->aq.asq_last_status, errno,
@@ -1073,6 +1087,11 @@
 	struct i40e_hw *hw = &np->vsi->back->hw;
 	u32 val;
 
+#define X722_EEPROM_SCOPE_LIMIT 0x5B9FFF
+	if (hw->mac.type == I40E_MAC_X722) {
+		val = X722_EEPROM_SCOPE_LIMIT + 1;
+		return val;
+	}
 	val = (rd32(hw, I40E_GLPCI_LBARCTRL)
 		& I40E_GLPCI_LBARCTRL_FL_SIZE_MASK)
 		>> I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT;
@@ -1087,27 +1106,25 @@
 	struct i40e_netdev_priv *np = netdev_priv(netdev);
 	struct i40e_hw *hw = &np->vsi->back->hw;
 	struct i40e_pf *pf = np->vsi->back;
-	struct i40e_nvm_access *cmd;
+	struct i40e_nvm_access *cmd = (struct i40e_nvm_access *)eeprom;
 	int ret_val = 0;
-	int errno;
+	int errno = 0;
 	u32 magic;
 
 	/* normal ethtool set_eeprom is not supported */
 	magic = hw->vendor_id | (hw->device_id << 16);
 	if (eeprom->magic == magic)
-		return -EOPNOTSUPP;
-
+		errno = -EOPNOTSUPP;
 	/* check for NVMUpdate access method */
-	if (!eeprom->magic || (eeprom->magic >> 16) != hw->device_id)
-		return -EINVAL;
-
-	if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
-	    test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
-		return -EBUSY;
+	else if (!eeprom->magic || (eeprom->magic >> 16) != hw->device_id)
+		errno = -EINVAL;
+	else if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
+		 test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
+		errno = -EBUSY;
+	else
+		ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
 
-	cmd = (struct i40e_nvm_access *)eeprom;
-	ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
-	if (ret_val && (hw->debug_mask & I40E_DEBUG_NVM))
+	if ((errno || ret_val) && (hw->debug_mask & I40E_DEBUG_NVM))
 		dev_info(&pf->pdev->dev,
 			 "NVMUpdate write failed err=%d status=0x%x errno=%d module=%d offset=0x%x size=%d\n",
 			 ret_val, hw->aq.asq_last_status, errno,
@@ -1814,28 +1831,52 @@
 			    enum ethtool_phys_id_state state)
 {
 	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	i40e_status ret = 0;
 	struct i40e_pf *pf = np->vsi->back;
 	struct i40e_hw *hw = &pf->hw;
 	int blink_freq = 2;
+	u16 temp_status;
 
 	switch (state) {
 	case ETHTOOL_ID_ACTIVE:
-		pf->led_status = i40e_led_get(hw);
+		if (!(pf->flags & I40E_FLAG_HAVE_10GBASET_PHY)) {
+			pf->led_status = i40e_led_get(hw);
+		} else {
+			i40e_aq_set_phy_debug(hw, I40E_PHY_DEBUG_PORT, NULL);
+			ret = i40e_led_get_phy(hw, &temp_status,
+					       &pf->phy_led_val);
+			pf->led_status = temp_status;
+		}
 		return blink_freq;
 	case ETHTOOL_ID_ON:
-		i40e_led_set(hw, 0xF, false);
+		if (!(pf->flags & I40E_FLAG_HAVE_10GBASET_PHY))
+			i40e_led_set(hw, 0xf, false);
+		else
+			ret = i40e_led_set_phy(hw, true, pf->led_status, 0);
 		break;
 	case ETHTOOL_ID_OFF:
-		i40e_led_set(hw, 0x0, false);
+		if (!(pf->flags & I40E_FLAG_HAVE_10GBASET_PHY))
+			i40e_led_set(hw, 0x0, false);
+		else
+			ret = i40e_led_set_phy(hw, false, pf->led_status, 0);
 		break;
 	case ETHTOOL_ID_INACTIVE:
-		i40e_led_set(hw, pf->led_status, false);
+		if (!(pf->flags & I40E_FLAG_HAVE_10GBASET_PHY)) {
+			i40e_led_set(hw, false, pf->led_status);
+		} else {
+			ret = i40e_led_set_phy(hw, false, pf->led_status,
+					       (pf->phy_led_val |
+					       I40E_PHY_LED_MODE_ORIG));
+			i40e_aq_set_phy_debug(hw, 0, NULL);
+		}
 		break;
 	default:
 		break;
 	}
-
-	return 0;
+		if (ret)
+			return -ENOENT;
+		else
+			return 0;
 }
 
 /* NOTE: i40e hardware uses a conversion factor of 2 for Interrupt
@@ -2110,7 +2151,7 @@
 
 	switch (cmd->cmd) {
 	case ETHTOOL_GRXRINGS:
-		cmd->data = vsi->alloc_queue_pairs;
+		cmd->data = vsi->num_queue_pairs;
 		ret = 0;
 		break;
 	case ETHTOOL_GRXFH:
@@ -2145,8 +2186,8 @@
 static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
 {
 	struct i40e_hw *hw = &pf->hw;
-	u64 hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
-		   ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
+	u64 hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
+		   ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
 
 	/* RSS does not support anything other than hashing
 	 * to queues on src and dst IPs and ports
@@ -2164,9 +2205,12 @@
 	case TCP_V4_FLOW:
 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
 		case 0:
-			hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
-			break;
+			return -EINVAL;
 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
+				hena |=
+			   BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
+
 			hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
 			break;
 		default:
@@ -2176,9 +2220,12 @@
 	case TCP_V6_FLOW:
 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
 		case 0:
-			hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
-			break;
+			return -EINVAL;
 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
+				hena |=
+			   BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK);
+
 			hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
 			break;
 		default:
@@ -2188,10 +2235,13 @@
 	case UDP_V4_FLOW:
 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
 		case 0:
-			hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
-				  BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
-			break;
+			return -EINVAL;
 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
+				hena |=
+			    BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
+			    BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP);
+
 			hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
 				 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
 			break;
@@ -2202,10 +2252,13 @@
 	case UDP_V6_FLOW:
 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
 		case 0:
-			hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
-				  BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
-			break;
+			return -EINVAL;
 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
+				hena |=
+			    BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
+			    BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP);
+
 			hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
 				 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
 			break;
@@ -2243,8 +2296,8 @@
 		return -EINVAL;
 	}
 
-	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
-	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
 	i40e_flush(hw);
 
 	/* Save setting for future output/update */
@@ -2583,7 +2636,6 @@
 		return -EINVAL;
 }
 
-#define I40E_HLUT_ARRAY_SIZE ((I40E_PFQF_HLUT_MAX_INDEX + 1) * 4)
 /**
  * i40e_get_rxfh_key_size - get the RSS hash key size
  * @netdev: network interface device structure
@@ -2611,10 +2663,9 @@
 {
 	struct i40e_netdev_priv *np = netdev_priv(netdev);
 	struct i40e_vsi *vsi = np->vsi;
-	struct i40e_pf *pf = vsi->back;
-	struct i40e_hw *hw = &pf->hw;
-	u32 reg_val;
-	int i, j;
+	u8 *lut, *seed = NULL;
+	int ret;
+	u16 i;
 
 	if (hfunc)
 		*hfunc = ETH_RSS_HASH_TOP;
@@ -2622,24 +2673,20 @@
 	if (!indir)
 		return 0;
 
-	for (i = 0, j = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++) {
-		reg_val = rd32(hw, I40E_PFQF_HLUT(i));
-		indir[j++] = reg_val & 0xff;
-		indir[j++] = (reg_val >> 8) & 0xff;
-		indir[j++] = (reg_val >> 16) & 0xff;
-		indir[j++] = (reg_val >> 24) & 0xff;
-	}
+	seed = key;
+	lut = kzalloc(I40E_HLUT_ARRAY_SIZE, GFP_KERNEL);
+	if (!lut)
+		return -ENOMEM;
+	ret = i40e_get_rss(vsi, seed, lut, I40E_HLUT_ARRAY_SIZE);
+	if (ret)
+		goto out;
+	for (i = 0; i < I40E_HLUT_ARRAY_SIZE; i++)
+		indir[i] = (u32)(lut[i]);
 
-	if (key) {
-		for (i = 0, j = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) {
-			reg_val = rd32(hw, I40E_PFQF_HKEY(i));
-			key[j++] = (u8)(reg_val & 0xff);
-			key[j++] = (u8)((reg_val >> 8) & 0xff);
-			key[j++] = (u8)((reg_val >> 16) & 0xff);
-			key[j++] = (u8)((reg_val >> 24) & 0xff);
-		}
-	}
-	return 0;
+out:
+	kfree(lut);
+
+	return ret;
 }
 
 /**
@@ -2656,10 +2703,8 @@
 {
 	struct i40e_netdev_priv *np = netdev_priv(netdev);
 	struct i40e_vsi *vsi = np->vsi;
-	struct i40e_pf *pf = vsi->back;
-	struct i40e_hw *hw = &pf->hw;
-	u32 reg_val;
-	int i, j;
+	u8 *seed = NULL;
+	u16 i;
 
 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
 		return -EOPNOTSUPP;
@@ -2667,24 +2712,28 @@
 	if (!indir)
 		return 0;
 
-	for (i = 0, j = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++) {
-		reg_val = indir[j++];
-		reg_val |= indir[j++] << 8;
-		reg_val |= indir[j++] << 16;
-		reg_val |= indir[j++] << 24;
-		wr32(hw, I40E_PFQF_HLUT(i), reg_val);
-	}
-
 	if (key) {
-		for (i = 0, j = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) {
-			reg_val = key[j++];
-			reg_val |= key[j++] << 8;
-			reg_val |= key[j++] << 16;
-			reg_val |= key[j++] << 24;
-			wr32(hw, I40E_PFQF_HKEY(i), reg_val);
-		}
-	}
-	return 0;
+		if (!vsi->rss_hkey_user) {
+			vsi->rss_hkey_user = kzalloc(I40E_HKEY_ARRAY_SIZE,
+						     GFP_KERNEL);
+			if (!vsi->rss_hkey_user)
+				return -ENOMEM;
+		}
+		memcpy(vsi->rss_hkey_user, key, I40E_HKEY_ARRAY_SIZE);
+		seed = vsi->rss_hkey_user;
+	}
+	if (!vsi->rss_lut_user) {
+		vsi->rss_lut_user = kzalloc(I40E_HLUT_ARRAY_SIZE, GFP_KERNEL);
+		if (!vsi->rss_lut_user)
+			return -ENOMEM;
+	}
+
+	/* Each 32 bits pointed by 'indir' is stored with a lut entry */
+	for (i = 0; i < I40E_HLUT_ARRAY_SIZE; i++)
+		vsi->rss_lut_user[i] = (u8)(indir[i]);
+
+	return i40e_config_rss(vsi, seed, vsi->rss_lut_user,
+			       I40E_HLUT_ARRAY_SIZE);
 }
 
 /**
@@ -2712,6 +2761,8 @@
 		I40E_PRIV_FLAGS_FD_ATR : 0;
 	ret_flags |= pf->flags & I40E_FLAG_VEB_STATS_ENABLED ?
 		I40E_PRIV_FLAGS_VEB_STATS : 0;
+	ret_flags |= pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE ?
+		0 : I40E_PRIV_FLAGS_HW_ATR_EVICT;
 
 	return ret_flags;
 }
@@ -2726,6 +2777,9 @@
 	struct i40e_netdev_priv *np = netdev_priv(dev);
 	struct i40e_vsi *vsi = np->vsi;
 	struct i40e_pf *pf = vsi->back;
+	bool reset_required = false;
+
+	/* NOTE: MFP is not settable */
 
 	if (flags & I40E_PRIV_FLAGS_LINKPOLL_FLAG)
 		pf->flags |= I40E_FLAG_LINK_POLLING_ENABLED;
@@ -2743,10 +2797,25 @@
 		pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
 	}
 
-	if (flags & I40E_PRIV_FLAGS_VEB_STATS)
+	if ((flags & I40E_PRIV_FLAGS_VEB_STATS) &&
+	    !(pf->flags & I40E_FLAG_VEB_STATS_ENABLED)) {
 		pf->flags |= I40E_FLAG_VEB_STATS_ENABLED;
-	else
+		reset_required = true;
+	} else if (!(flags & I40E_PRIV_FLAGS_VEB_STATS) &&
+		   (pf->flags & I40E_FLAG_VEB_STATS_ENABLED)) {
 		pf->flags &= ~I40E_FLAG_VEB_STATS_ENABLED;
+		reset_required = true;
+	}
+
+	if ((flags & I40E_PRIV_FLAGS_HW_ATR_EVICT) &&
+	    (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))
+		pf->auto_disable_flags &= ~I40E_FLAG_HW_ATR_EVICT_CAPABLE;
+	else
+		pf->auto_disable_flags |= I40E_FLAG_HW_ATR_EVICT_CAPABLE;
+
+	/* if needed, issue reset to cause things to take effect */
+	if (reset_required)
+		i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED));
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_fcoe.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_fcoe.c
@@ -295,11 +295,11 @@
 	}
 
 	/* enable FCoE hash filter */
-	val = rd32(hw, I40E_PFQF_HENA(1));
+	val = i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1));
 	val |= BIT(I40E_FILTER_PCTYPE_FCOE_OX - 32);
 	val |= BIT(I40E_FILTER_PCTYPE_FCOE_RX - 32);
 	val &= I40E_PFQF_HENA_PTYPE_ENA_MASK;
-	wr32(hw, I40E_PFQF_HENA(1), val);
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), val);
 
 	/* enable flag */
 	pf->flags |= I40E_FLAG_FCOE_ENABLED;
@@ -317,11 +317,11 @@
 	pf->filter_settings.fcoe_cntx_num = I40E_DMA_CNTX_SIZE_4K;
 
 	/* Setup max frame with FCoE_MTU plus L2 overheads */
-	val = rd32(hw, I40E_GLFCOE_RCTL);
+	val = i40e_read_rx_ctl(hw, I40E_GLFCOE_RCTL);
 	val &= ~I40E_GLFCOE_RCTL_MAX_SIZE_MASK;
 	val |= ((FCOE_MTU + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
 		 << I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT);
-	wr32(hw, I40E_GLFCOE_RCTL, val);
+	i40e_write_rx_ctl(hw, I40E_GLFCOE_RCTL, val);
 
 	dev_info(&pf->pdev->dev, "FCoE is supported.\n");
 }
@@ -1359,16 +1359,32 @@
 	struct i40e_ring *tx_ring = vsi->tx_rings[skb->queue_mapping];
 	struct i40e_tx_buffer *first;
 	u32 tx_flags = 0;
+	int fso, count;
 	u8 hdr_len = 0;
 	u8 sof = 0;
 	u8 eof = 0;
-	int fso;
 
 	if (i40e_fcoe_set_skb_header(skb))
 		goto out_drop;
 
-	if (!i40e_xmit_descriptor_count(skb, tx_ring))
+	count = i40e_xmit_descriptor_count(skb);
+	if (i40e_chk_linearize(skb, count)) {
+		if (__skb_linearize(skb))
+			goto out_drop;
+		count = i40e_txd_use_count(skb->len);
+		tx_ring->tx_stats.tx_linearize++;
+	}
+
+	/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
+	 *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
+	 *       + 4 desc gap to avoid the cache line where head is,
+	 *       + 1 desc for context descriptor,
+	 * otherwise try next time
+	 */
+	if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+		tx_ring->tx_stats.tx_busy++;
 		return NETDEV_TX_BUSY;
+	}
 
 	/* prepare the xmit flags */
 	if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
@@ -1457,7 +1473,7 @@
 	.ndo_tx_timeout		= i40e_tx_timeout,
 	.ndo_vlan_rx_add_vid	= i40e_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid	= i40e_vlan_rx_kill_vid,
-	.ndo_setup_tc		= i40e_setup_tc,
+	.ndo_setup_tc		= __i40e_setup_tc,
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= i40e_netpoll,
@@ -1544,8 +1560,6 @@
 	if (!(pf->flags & I40E_FLAG_FCOE_ENABLED))
 		return;
 
-	BUG_ON(!pf->vsi[pf->lan_vsi]);
-
 	for (i = 0; i < pf->num_alloc_vsi; i++) {
 		vsi = pf->vsi[i];
 		if (vsi && vsi->type == I40E_VSI_FCOE) {
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_hmc.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_hmc.c
@@ -49,7 +49,7 @@
 	struct i40e_hmc_sd_entry *sd_entry;
 	bool dma_mem_alloc_done = false;
 	struct i40e_dma_mem mem;
-	i40e_status ret_code;
+	i40e_status ret_code = I40E_SUCCESS;
 	u64 alloc_len;
 
 	if (NULL == hmc_info->sd_table.sd_entry) {
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
@@ -762,7 +762,7 @@
 
 	/* prepare the bits and mask */
 	shift_width = ce_info->lsb % 8;
-	mask = BIT(ce_info->width) - 1;
+	mask = (u8)(BIT(ce_info->width) - 1);
 
 	src_byte = *from;
 	src_byte &= mask;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -24,12 +24,19 @@
  *
  ******************************************************************************/
 
+#include <linux/etherdevice.h>
+#include <linux/of_net.h>
+#include <linux/pci.h>
+
 /* Local includes */
 #include "i40e.h"
 #include "i40e_diag.h"
-#ifdef CONFIG_I40E_VXLAN
+#if IS_ENABLED(CONFIG_VXLAN)
 #include <net/vxlan.h>
 #endif
+#if IS_ENABLED(CONFIG_GENEVE)
+#include <net/geneve.h>
+#endif
 
 const char i40e_driver_name[] = "i40e";
 static const char i40e_driver_string[] =
@@ -38,8 +45,8 @@
 #define DRV_KERN "-k"
 
 #define DRV_VERSION_MAJOR 1
-#define DRV_VERSION_MINOR 3
-#define DRV_VERSION_BUILD 46
+#define DRV_VERSION_MINOR 4
+#define DRV_VERSION_BUILD 25
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
 	     __stringify(DRV_VERSION_MINOR) "." \
 	     __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -55,6 +62,8 @@
 static int i40e_setup_misc_vector(struct i40e_pf *pf);
 static void i40e_determine_queue_usage(struct i40e_pf *pf);
 static int i40e_setup_pf_filter_control(struct i40e_pf *pf);
+static void i40e_fill_rss_lut(struct i40e_pf *pf, u8 *lut,
+			      u16 rss_table_size, u16 rss_size);
 static void i40e_fdir_sb_setup(struct i40e_pf *pf);
 static int i40e_veb_get_bw_info(struct i40e_veb *veb);
 
@@ -68,7 +77,6 @@
 static const struct pci_device_id i40e_pci_tbl[] = {
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_XL710), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_QEMU), 0},
-	{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_A), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_B), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_C), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_A), 0},
@@ -77,6 +85,8 @@
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T4), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2), 0},
+	{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_X722), 0},
+	{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_X722), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_1G_BASE_T_X722), 0},
 	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_X722), 0},
@@ -97,6 +107,8 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+static struct workqueue_struct *i40e_wq;
+
 /**
  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
  * @hw:   pointer to the HW structure
@@ -282,7 +294,7 @@
 	if (!test_bit(__I40E_DOWN, &pf->state) &&
 	    !test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) &&
 	    !test_and_set_bit(__I40E_SERVICE_SCHED, &pf->state))
-		schedule_work(&pf->service_task);
+		queue_work(i40e_wq, &pf->service_task);
 }
 
 /**
@@ -756,7 +768,7 @@
 	if (vsi->type != I40E_VSI_FCOE)
 		return;
 
-	idx = (pf->pf_seid - I40E_BASE_PF_SEID) + I40E_FCOE_PF_STAT_OFFSET;
+	idx = hw->pf_id + I40E_FCOE_PF_STAT_OFFSET;
 	fs = &vsi->fcoe_stats;
 	ofs = &vsi->fcoe_stats_offsets;
 
@@ -790,75 +802,6 @@
 
 #endif
 /**
- * i40e_update_link_xoff_rx - Update XOFF received in link flow control mode
- * @pf: the corresponding PF
- *
- * Update the Rx XOFF counter (PAUSE frames) in link flow control mode
- **/
-static void i40e_update_link_xoff_rx(struct i40e_pf *pf)
-{
-	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
-	struct i40e_hw_port_stats *nsd = &pf->stats;
-	struct i40e_hw *hw = &pf->hw;
-	u64 xoff = 0;
-
-	if ((hw->fc.current_mode != I40E_FC_FULL) &&
-	    (hw->fc.current_mode != I40E_FC_RX_PAUSE))
-		return;
-
-	xoff = nsd->link_xoff_rx;
-	i40e_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
-			   pf->stat_offsets_loaded,
-			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
-
-	/* No new LFC xoff rx */
-	if (!(nsd->link_xoff_rx - xoff))
-		return;
-
-}
-
-/**
- * i40e_update_prio_xoff_rx - Update XOFF received in PFC mode
- * @pf: the corresponding PF
- *
- * Update the Rx XOFF counter (PAUSE frames) in PFC mode
- **/
-static void i40e_update_prio_xoff_rx(struct i40e_pf *pf)
-{
-	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
-	struct i40e_hw_port_stats *nsd = &pf->stats;
-	bool xoff[I40E_MAX_TRAFFIC_CLASS] = {false};
-	struct i40e_dcbx_config *dcb_cfg;
-	struct i40e_hw *hw = &pf->hw;
-	u16 i;
-	u8 tc;
-
-	dcb_cfg = &hw->local_dcbx_config;
-
-	/* Collect Link XOFF stats when PFC is disabled */
-	if (!dcb_cfg->pfc.pfcenable) {
-		i40e_update_link_xoff_rx(pf);
-		return;
-	}
-
-	for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
-		u64 prio_xoff = nsd->priority_xoff_rx[i];
-
-		i40e_stat_update32(hw, I40E_GLPRT_PXOFFRXC(hw->port, i),
-				   pf->stat_offsets_loaded,
-				   &osd->priority_xoff_rx[i],
-				   &nsd->priority_xoff_rx[i]);
-
-		/* No new PFC xoff rx */
-		if (!(nsd->priority_xoff_rx[i] - prio_xoff))
-			continue;
-		/* Get the TC for given priority */
-		tc = dcb_cfg->etscfg.prioritytable[i];
-		xoff[tc] = true;
-	}
-}
-
-/**
  * i40e_update_vsi_stats - Update the vsi statistics counters.
  * @vsi: the VSI to be updated
  *
@@ -876,11 +819,13 @@
 	struct i40e_eth_stats *oes;
 	struct i40e_eth_stats *es;     /* device's eth stats */
 	u32 tx_restart, tx_busy;
+	u64 tx_lost_interrupt;
 	struct i40e_ring *p;
 	u32 rx_page, rx_buf;
 	u64 bytes, packets;
 	unsigned int start;
 	u64 tx_linearize;
+	u64 tx_force_wb;
 	u64 rx_p, rx_b;
 	u64 tx_p, tx_b;
 	u16 q;
@@ -899,7 +844,8 @@
 	 */
 	rx_b = rx_p = 0;
 	tx_b = tx_p = 0;
-	tx_restart = tx_busy = tx_linearize = 0;
+	tx_restart = tx_busy = tx_linearize = tx_force_wb = 0;
+	tx_lost_interrupt = 0;
 	rx_page = 0;
 	rx_buf = 0;
 	rcu_read_lock();
@@ -917,6 +863,8 @@
 		tx_restart += p->tx_stats.restart_queue;
 		tx_busy += p->tx_stats.tx_busy;
 		tx_linearize += p->tx_stats.tx_linearize;
+		tx_force_wb += p->tx_stats.tx_force_wb;
+		tx_lost_interrupt += p->tx_stats.tx_lost_interrupt;
 
 		/* Rx queue is part of the same block as Tx queue */
 		p = &p[1];
@@ -934,6 +882,8 @@
 	vsi->tx_restart = tx_restart;
 	vsi->tx_busy = tx_busy;
 	vsi->tx_linearize = tx_linearize;
+	vsi->tx_force_wb = tx_force_wb;
+	vsi->tx_lost_interrupt = tx_lost_interrupt;
 	vsi->rx_page_failed = rx_page;
 	vsi->rx_buf_failed = rx_buf;
 
@@ -1049,12 +999,18 @@
 	i40e_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
 			   pf->stat_offsets_loaded,
 			   &osd->link_xon_tx, &nsd->link_xon_tx);
-	i40e_update_prio_xoff_rx(pf);  /* handles I40E_GLPRT_LXOFFRXC */
+	i40e_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
+			   pf->stat_offsets_loaded,
+			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
 	i40e_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
 			   pf->stat_offsets_loaded,
 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
 
 	for (i = 0; i < 8; i++) {
+		i40e_stat_update32(hw, I40E_GLPRT_PXOFFRXC(hw->port, i),
+				   pf->stat_offsets_loaded,
+				   &osd->priority_xoff_rx[i],
+				   &nsd->priority_xoff_rx[i]);
 		i40e_stat_update32(hw, I40E_GLPRT_PXONRXC(hw->port, i),
 				   pf->stat_offsets_loaded,
 				   &osd->priority_xon_rx[i],
@@ -1317,6 +1273,42 @@
 }
 
 /**
+ * i40e_del_mac_all_vlan - Remove a MAC filter from all VLANS
+ * @vsi: the VSI to be searched
+ * @macaddr: the mac address to be removed
+ * @is_vf: true if it is a VF
+ * @is_netdev: true if it is a netdev
+ *
+ * Removes a given MAC address from a VSI, regardless of VLAN
+ *
+ * Returns 0 for success, or error
+ **/
+int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, u8 *macaddr,
+			  bool is_vf, bool is_netdev)
+{
+	struct i40e_mac_filter *f = NULL;
+	int changed = 0;
+
+	WARN(!spin_is_locked(&vsi->mac_filter_list_lock),
+	     "Missing mac_filter_list_lock\n");
+	list_for_each_entry(f, &vsi->mac_filter_list, list) {
+		if ((ether_addr_equal(macaddr, f->macaddr)) &&
+		    (is_vf == f->is_vf) &&
+		    (is_netdev == f->is_netdev)) {
+			f->counter--;
+			f->changed = true;
+			changed = 1;
+		}
+	}
+	if (changed) {
+		vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+		vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+		return 0;
+	}
+	return -ENOENT;
+}
+
+/**
  * i40e_rm_default_mac_filter - Remove the default MAC filter set by NVM
  * @vsi: the PF Main VSI - inappropriate for any other VSI
  * @macaddr: the MAC address
@@ -1379,7 +1371,7 @@
 		f->changed = true;
 
 		INIT_LIST_HEAD(&f->list);
-		list_add(&f->list, &vsi->mac_filter_list);
+		list_add_tail(&f->list, &vsi->mac_filter_list);
 	}
 
 	/* increment counter and add a new flag if needed */
@@ -1547,10 +1539,9 @@
 		spin_unlock_bh(&vsi->mac_filter_list_lock);
 	}
 
-	i40e_sync_vsi_filters(vsi, false);
 	ether_addr_copy(netdev->dev_addr, addr->sa_data);
 
-	return 0;
+	return i40e_sync_vsi_filters(vsi);
 }
 
 /**
@@ -1590,7 +1581,7 @@
 	if (enabled_tc && (vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
 		/* Find numtc from enabled TC bitmap */
 		for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-			if (enabled_tc & BIT_ULL(i)) /* TC is enabled */
+			if (enabled_tc & BIT(i)) /* TC is enabled */
 				numtc++;
 		}
 		if (!numtc) {
@@ -1619,13 +1610,14 @@
 	/* Setup queue offset/count for all TCs for given VSI */
 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
 		/* See if the given TC is enabled for the given VSI */
-		if (vsi->tc_config.enabled_tc & BIT_ULL(i)) {
+		if (vsi->tc_config.enabled_tc & BIT(i)) {
 			/* TC is enabled */
 			int pow, num_qps;
 
 			switch (vsi->type) {
 			case I40E_VSI_MAIN:
-				qcount = min_t(int, pf->rss_size, num_tc_qps);
+				qcount = min_t(int, pf->alloc_rss_size,
+					       num_tc_qps);
 				break;
 #ifdef I40E_FCOE
 			case I40E_VSI_FCOE:
@@ -1851,13 +1843,12 @@
 /**
  * i40e_sync_vsi_filters - Update the VSI filter list to the HW
  * @vsi: ptr to the VSI
- * @grab_rtnl: whether RTNL needs to be grabbed
  *
  * Push any outstanding VSI filter changes through the AdminQ.
  *
  * Returns 0 or error value
  **/
-int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
+int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 {
 	struct list_head tmp_del_list, tmp_add_list;
 	struct i40e_mac_filter *f, *ftmp, *fclone;
@@ -1865,8 +1856,9 @@
 	bool add_happened = false;
 	int filter_list_len = 0;
 	u32 changed_flags = 0;
+	i40e_status aq_ret = 0;
 	bool err_cond = false;
-	i40e_status ret = 0;
+	int retval = 0;
 	struct i40e_pf *pf;
 	int num_add = 0;
 	int num_del = 0;
@@ -1929,17 +1921,22 @@
 		}
 		spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-		if (err_cond)
+		if (err_cond) {
 			i40e_cleanup_add_list(&tmp_add_list);
+			retval = -ENOMEM;
+			goto out;
+		}
 	}
 
 	/* Now process 'del_list' outside the lock */
 	if (!list_empty(&tmp_del_list)) {
+		int del_list_size;
+
 		filter_list_len = pf->hw.aq.asq_buf_size /
 			    sizeof(struct i40e_aqc_remove_macvlan_element_data);
-		del_list = kcalloc(filter_list_len,
-			    sizeof(struct i40e_aqc_remove_macvlan_element_data),
-			    GFP_KERNEL);
+		del_list_size = filter_list_len *
+			    sizeof(struct i40e_aqc_remove_macvlan_element_data);
+		del_list = kzalloc(del_list_size, GFP_ATOMIC);
 		if (!del_list) {
 			i40e_cleanup_add_list(&tmp_add_list);
 
@@ -1948,7 +1945,8 @@
 			i40e_undo_del_filter_entries(vsi, &tmp_del_list);
 			i40e_undo_add_filter_entries(vsi);
 			spin_unlock_bh(&vsi->mac_filter_list_lock);
-			return -ENOMEM;
+			retval = -ENOMEM;
+			goto out;
 		}
 
 		list_for_each_entry_safe(f, ftmp, &tmp_del_list, list) {
@@ -1966,18 +1964,22 @@
 
 			/* flush a full buffer */
 			if (num_del == filter_list_len) {
-				ret = i40e_aq_remove_macvlan(&pf->hw,
-						  vsi->seid, del_list, num_del,
-						  NULL);
+				aq_ret = i40e_aq_remove_macvlan(&pf->hw,
+								vsi->seid,
+								del_list,
+								num_del,
+								NULL);
 				aq_err = pf->hw.aq.asq_last_status;
 				num_del = 0;
-				memset(del_list, 0, sizeof(*del_list));
+				memset(del_list, 0, del_list_size);
 
-				if (ret && aq_err != I40E_AQ_RC_ENOENT)
+				if (aq_ret && aq_err != I40E_AQ_RC_ENOENT) {
+					retval = -EIO;
 					dev_err(&pf->pdev->dev,
 						"ignoring delete macvlan error, err %s, aq_err %s while flushing a full buffer\n",
-						i40e_stat_str(&pf->hw, ret),
+						i40e_stat_str(&pf->hw, aq_ret),
 						i40e_aq_str(&pf->hw, aq_err));
+				}
 			}
 			/* Release memory for MAC filter entries which were
 			 * synced up with HW.
@@ -1987,15 +1989,16 @@
 		}
 
 		if (num_del) {
-			ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid,
-						     del_list, num_del, NULL);
+			aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid,
+							del_list, num_del,
+							NULL);
 			aq_err = pf->hw.aq.asq_last_status;
 			num_del = 0;
 
-			if (ret && aq_err != I40E_AQ_RC_ENOENT)
+			if (aq_ret && aq_err != I40E_AQ_RC_ENOENT)
 				dev_info(&pf->pdev->dev,
 					 "ignoring delete macvlan error, err %s aq_err %s\n",
-					 i40e_stat_str(&pf->hw, ret),
+					 i40e_stat_str(&pf->hw, aq_ret),
 					 i40e_aq_str(&pf->hw, aq_err));
 		}
 
@@ -2004,13 +2007,14 @@
 	}
 
 	if (!list_empty(&tmp_add_list)) {
+		int add_list_size;
 
 		/* do all the adds now */
 		filter_list_len = pf->hw.aq.asq_buf_size /
 			       sizeof(struct i40e_aqc_add_macvlan_element_data),
-		add_list = kcalloc(filter_list_len,
-			       sizeof(struct i40e_aqc_add_macvlan_element_data),
-			       GFP_KERNEL);
+		add_list_size = filter_list_len *
+			       sizeof(struct i40e_aqc_add_macvlan_element_data);
+		add_list = kzalloc(add_list_size, GFP_ATOMIC);
 		if (!add_list) {
 			/* Purge element from temporary lists */
 			i40e_cleanup_add_list(&tmp_add_list);
@@ -2019,7 +2023,8 @@
 			spin_lock_bh(&vsi->mac_filter_list_lock);
 			i40e_undo_add_filter_entries(vsi);
 			spin_unlock_bh(&vsi->mac_filter_list_lock);
-			return -ENOMEM;
+			retval = -ENOMEM;
+			goto out;
 		}
 
 		list_for_each_entry_safe(f, ftmp, &tmp_add_list, list) {
@@ -2040,15 +2045,15 @@
 
 			/* flush a full buffer */
 			if (num_add == filter_list_len) {
-				ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
-							  add_list, num_add,
-							  NULL);
+				aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
+							     add_list, num_add,
+							     NULL);
 				aq_err = pf->hw.aq.asq_last_status;
 				num_add = 0;
 
-				if (ret)
+				if (aq_ret)
 					break;
-				memset(add_list, 0, sizeof(*add_list));
+				memset(add_list, 0, add_list_size);
 			}
 			/* Entries from tmp_add_list were cloned from MAC
 			 * filter list, hence clean those cloned entries
@@ -2058,18 +2063,19 @@
 		}
 
 		if (num_add) {
-			ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
-						  add_list, num_add, NULL);
+			aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
+						     add_list, num_add, NULL);
 			aq_err = pf->hw.aq.asq_last_status;
 			num_add = 0;
 		}
 		kfree(add_list);
 		add_list = NULL;
 
-		if (add_happened && ret && aq_err != I40E_AQ_RC_EINVAL) {
+		if (add_happened && aq_ret && aq_err != I40E_AQ_RC_EINVAL) {
+			retval = i40e_aq_rc_to_posix(aq_ret, aq_err);
 			dev_info(&pf->pdev->dev,
 				 "add filter failed, err %s aq_err %s\n",
-				 i40e_stat_str(&pf->hw, ret),
+				 i40e_stat_str(&pf->hw, aq_ret),
 				 i40e_aq_str(&pf->hw, aq_err));
 			if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOSPC) &&
 			    !test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
@@ -2087,16 +2093,19 @@
 		bool cur_multipromisc;
 
 		cur_multipromisc = !!(vsi->current_netdev_flags & IFF_ALLMULTI);
-		ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw,
-							    vsi->seid,
-							    cur_multipromisc,
-							    NULL);
-		if (ret)
+		aq_ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw,
+							       vsi->seid,
+							       cur_multipromisc,
+							       NULL);
+		if (aq_ret) {
+			retval = i40e_aq_rc_to_posix(aq_ret,
+						     pf->hw.aq.asq_last_status);
 			dev_info(&pf->pdev->dev,
 				 "set multi promisc failed, err %s aq_err %s\n",
-				 i40e_stat_str(&pf->hw, ret),
+				 i40e_stat_str(&pf->hw, aq_ret),
 				 i40e_aq_str(&pf->hw,
 					     pf->hw.aq.asq_last_status));
+		}
 	}
 	if ((changed_flags & IFF_PROMISC) || promisc_forced_on) {
 		bool cur_promisc;
@@ -2104,7 +2113,9 @@
 		cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
 			       test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
 					&vsi->state));
-		if (vsi->type == I40E_VSI_MAIN && pf->lan_veb != I40E_NO_VEB) {
+		if ((vsi->type == I40E_VSI_MAIN) &&
+		    (pf->lan_veb != I40E_NO_VEB) &&
+		    !(pf->flags & I40E_FLAG_MFP_ENABLED)) {
 			/* set defport ON for Main VSI instead of true promisc
 			 * this way we will get all unicast/multicast and VLAN
 			 * promisc behavior but will not get VF or VMDq traffic
@@ -2112,44 +2123,54 @@
 			 */
 			if (pf->cur_promisc != cur_promisc) {
 				pf->cur_promisc = cur_promisc;
-				if (grab_rtnl)
-					i40e_do_reset_safe(pf,
-						BIT(__I40E_PF_RESET_REQUESTED));
-				else
-					i40e_do_reset(pf,
-						BIT(__I40E_PF_RESET_REQUESTED));
+				set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
 			}
 		} else {
-			ret = i40e_aq_set_vsi_unicast_promiscuous(
+			aq_ret = i40e_aq_set_vsi_unicast_promiscuous(
 							  &vsi->back->hw,
 							  vsi->seid,
 							  cur_promisc, NULL);
-			if (ret)
+			if (aq_ret) {
+				retval =
+				i40e_aq_rc_to_posix(aq_ret,
+						    pf->hw.aq.asq_last_status);
 				dev_info(&pf->pdev->dev,
 					 "set unicast promisc failed, err %d, aq_err %d\n",
-					 ret, pf->hw.aq.asq_last_status);
-			ret = i40e_aq_set_vsi_multicast_promiscuous(
+					 aq_ret, pf->hw.aq.asq_last_status);
+			}
+			aq_ret = i40e_aq_set_vsi_multicast_promiscuous(
 							  &vsi->back->hw,
 							  vsi->seid,
 							  cur_promisc, NULL);
-			if (ret)
+			if (aq_ret) {
+				retval =
+				i40e_aq_rc_to_posix(aq_ret,
+						    pf->hw.aq.asq_last_status);
 				dev_info(&pf->pdev->dev,
 					 "set multicast promisc failed, err %d, aq_err %d\n",
-					 ret, pf->hw.aq.asq_last_status);
+					 aq_ret, pf->hw.aq.asq_last_status);
+			}
 		}
-		ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw,
-						vsi->seid,
-						cur_promisc, NULL);
-		if (ret)
+		aq_ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw,
+						   vsi->seid,
+						   cur_promisc, NULL);
+		if (aq_ret) {
+			retval = i40e_aq_rc_to_posix(aq_ret,
+						     pf->hw.aq.asq_last_status);
 			dev_info(&pf->pdev->dev,
 				 "set brdcast promisc failed, err %s, aq_err %s\n",
-				 i40e_stat_str(&pf->hw, ret),
+				 i40e_stat_str(&pf->hw, aq_ret),
 				 i40e_aq_str(&pf->hw,
 					     pf->hw.aq.asq_last_status));
+		}
 	}
+out:
+	/* if something went wrong then set the changed flag so we try again */
+	if (retval)
+		vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
 
 	clear_bit(__I40E_CONFIG_BUSY, &vsi->state);
-	return 0;
+	return retval;
 }
 
 /**
@@ -2166,8 +2187,15 @@
 
 	for (v = 0; v < pf->num_alloc_vsi; v++) {
 		if (pf->vsi[v] &&
-		    (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED))
-			i40e_sync_vsi_filters(pf->vsi[v], true);
+		    (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED)) {
+			int ret = i40e_sync_vsi_filters(pf->vsi[v]);
+
+			if (ret) {
+				/* come back and try again later */
+				pf->flags |= I40E_FLAG_FILTER_SYNC;
+				break;
+			}
+		}
 	}
 }
 
@@ -2227,6 +2255,10 @@
 	struct i40e_vsi_context ctxt;
 	i40e_status ret;
 
+	/* Don't modify stripping options if a port VLAN is active */
+	if (vsi->info.pvid)
+		return;
+
 	if ((vsi->info.valid_sections &
 	     cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID)) &&
 	    ((vsi->info.port_vlan_flags & I40E_AQ_VSI_PVLAN_MODE_MASK) == 0))
@@ -2257,6 +2289,10 @@
 	struct i40e_vsi_context ctxt;
 	i40e_status ret;
 
+	/* Don't modify stripping options if a port VLAN is active */
+	if (vsi->info.pvid)
+		return;
+
 	if ((vsi->info.valid_sections &
 	     cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID)) &&
 	    ((vsi->info.port_vlan_flags & I40E_AQ_VSI_PVLAN_EMOD_MASK) ==
@@ -2377,16 +2413,13 @@
 		}
 	}
 
-	/* Make sure to release before sync_vsi_filter because that
-	 * function will lock/unlock as necessary
-	 */
 	spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-	if (test_bit(__I40E_DOWN, &vsi->back->state) ||
-	    test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
-		return 0;
-
-	return i40e_sync_vsi_filters(vsi, false);
+	/* schedule our worker thread which will take care of
+	 * applying the new filter changes
+	 */
+	i40e_service_event_schedule(vsi->back);
+	return 0;
 }
 
 /**
@@ -2459,16 +2492,13 @@
 		}
 	}
 
-	/* Make sure to release before sync_vsi_filter because that
-	 * function with lock/unlock as necessary
-	 */
 	spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-	if (test_bit(__I40E_DOWN, &vsi->back->state) ||
-	    test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
-		return 0;
-
-	return i40e_sync_vsi_filters(vsi, false);
+	/* schedule our worker thread which will take care of
+	 * applying the new filter changes
+	 */
+	i40e_service_event_schedule(vsi->back);
+	return 0;
 }
 
 /**
@@ -2711,6 +2741,11 @@
 		netif_set_xps_queue(ring->netdev, mask, ring->queue_index);
 		free_cpumask_var(mask);
 	}
+
+	/* schedule our worker thread which will take care of
+	 * applying the new filter changes
+	 */
+	i40e_service_event_schedule(vsi->back);
 }
 
 /**
@@ -2845,18 +2880,9 @@
 	}
 
 	rx_ctx.dtype = vsi->dtype;
-	if (vsi->dtype) {
-		set_ring_ps_enabled(ring);
-		rx_ctx.hsplit_0 = I40E_RX_SPLIT_L2      |
-				  I40E_RX_SPLIT_IP      |
-				  I40E_RX_SPLIT_TCP_UDP |
-				  I40E_RX_SPLIT_SCTP;
-	} else {
-		rx_ctx.hsplit_0 = 0;
-	}
+	rx_ctx.hsplit_0 = 0;
 
-	rx_ctx.rxmax = min_t(u16, vsi->max_frame,
-				  (chain_len * ring->rx_buf_len));
+	rx_ctx.rxmax = min_t(u16, vsi->max_frame, chain_len * ring->rx_buf_len);
 	if (hw->revision_id == 0)
 		rx_ctx.lrxqthresh = 0;
 	else
@@ -2893,12 +2919,7 @@
 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
 	writel(0, ring->tail);
 
-	if (ring_is_ps_enabled(ring)) {
-		i40e_alloc_rx_headers(ring);
-		i40e_alloc_rx_buffers_ps(ring, I40E_DESC_UNUSED(ring));
-	} else {
-		i40e_alloc_rx_buffers_1buf(ring, I40E_DESC_UNUSED(ring));
-	}
+	i40e_alloc_rx_buffers_1buf(ring, I40E_DESC_UNUSED(ring));
 
 	return 0;
 }
@@ -2937,25 +2958,9 @@
 	else
 		vsi->max_frame = I40E_RXBUFFER_2048;
 
-	/* figure out correct receive buffer length */
-	switch (vsi->back->flags & (I40E_FLAG_RX_1BUF_ENABLED |
-				    I40E_FLAG_RX_PS_ENABLED)) {
-	case I40E_FLAG_RX_1BUF_ENABLED:
-		vsi->rx_hdr_len = 0;
-		vsi->rx_buf_len = vsi->max_frame;
-		vsi->dtype = I40E_RX_DTYPE_NO_SPLIT;
-		break;
-	case I40E_FLAG_RX_PS_ENABLED:
-		vsi->rx_hdr_len = I40E_RX_HDR_SIZE;
-		vsi->rx_buf_len = I40E_RXBUFFER_2048;
-		vsi->dtype = I40E_RX_DTYPE_HEADER_SPLIT;
-		break;
-	default:
-		vsi->rx_hdr_len = I40E_RX_HDR_SIZE;
-		vsi->rx_buf_len = I40E_RXBUFFER_2048;
-		vsi->dtype = I40E_RX_DTYPE_SPLIT_ALWAYS;
-		break;
-	}
+	vsi->rx_hdr_len = 0;
+	vsi->rx_buf_len = vsi->max_frame;
+	vsi->dtype = I40E_RX_DTYPE_NO_SPLIT;
 
 #ifdef I40E_FCOE
 	/* setup rx buffer for FCoE */
@@ -3227,14 +3232,15 @@
 /**
  * i40e_irq_dynamic_enable_icr0 - Enable default interrupt generation for icr0
  * @pf: board private structure
+ * @clearpba: true when all pending interrupt events should be cleared
  **/
-void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf)
+void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf, bool clearpba)
 {
 	struct i40e_hw *hw = &pf->hw;
 	u32 val;
 
 	val = I40E_PFINT_DYN_CTL0_INTENA_MASK   |
-	      I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+	      (clearpba ? I40E_PFINT_DYN_CTL0_CLEARPBA_MASK : 0) |
 	      (I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
 
 	wr32(hw, I40E_PFINT_DYN_CTL0, val);
@@ -3242,22 +3248,6 @@
 }
 
 /**
- * i40e_irq_dynamic_disable - Disable default interrupt generation settings
- * @vsi: pointer to a vsi
- * @vector: disable a particular Hw Interrupt vector
- **/
-void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector)
-{
-	struct i40e_pf *pf = vsi->back;
-	struct i40e_hw *hw = &pf->hw;
-	u32 val;
-
-	val = I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
-	wr32(hw, I40E_PFINT_DYN_CTLN(vector - 1), val);
-	i40e_flush(hw);
-}
-
-/**
  * i40e_msix_clean_rings - MSIX mode Interrupt Handler
  * @irq: interrupt number
  * @data: pointer to a q_vector
@@ -3382,7 +3372,7 @@
 		for (i = 0; i < vsi->num_q_vectors; i++)
 			i40e_irq_dynamic_enable(vsi, i);
 	} else {
-		i40e_irq_dynamic_enable_icr0(pf);
+		i40e_irq_dynamic_enable_icr0(pf, true);
 	}
 
 	i40e_flush(&pf->hw);
@@ -3441,16 +3431,12 @@
 		struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
 		struct i40e_q_vector *q_vector = vsi->q_vectors[0];
 
-		/* temporarily disable queue cause for NAPI processing */
-		u32 qval = rd32(hw, I40E_QINT_RQCTL(0));
-
-		qval &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
-		wr32(hw, I40E_QINT_RQCTL(0), qval);
-
-		qval = rd32(hw, I40E_QINT_TQCTL(0));
-		qval &= ~I40E_QINT_TQCTL_CAUSE_ENA_MASK;
-		wr32(hw, I40E_QINT_TQCTL(0), qval);
-
+		/* We do not have a way to disarm Queue causes while leaving
+		 * interrupt enabled for all other causes, ideally
+		 * interrupt should be disabled while we are in NAPI but
+		 * this is not a performance path and napi_schedule()
+		 * can deal with rescheduling.
+		 */
 		if (!test_bit(__I40E_DOWN, &pf->state))
 			napi_schedule_irqoff(&q_vector->napi);
 	}
@@ -3458,6 +3444,7 @@
 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
 		ena_mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
 		set_bit(__I40E_ADMINQ_EVENT_PENDING, &pf->state);
+		i40e_debug(&pf->hw, I40E_DEBUG_NVM, "AdminQ event\n");
 	}
 
 	if (icr0 & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
@@ -3528,7 +3515,7 @@
 	wr32(hw, I40E_PFINT_ICR0_ENA, ena_mask);
 	if (!test_bit(__I40E_DOWN, &pf->state)) {
 		i40e_service_event_schedule(pf);
-		i40e_irq_dynamic_enable_icr0(pf);
+		i40e_irq_dynamic_enable_icr0(pf, false);
 	}
 
 	return ret;
@@ -3560,7 +3547,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		read_barrier_depends();
+		smp_rmb();
 
 		/* if the descriptor isn't done, no work yet to do */
 		if (!(eop_desc->cmd_type_offset_bsz &
@@ -3732,7 +3719,7 @@
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /**
- * i40e_netpoll - A Polling 'interrupt'handler
+ * i40e_netpoll - A Polling 'interrupt' handler
  * @netdev: network interface device structure
  *
  * This is used by netconsole to send skbs without having to re-enable
@@ -3911,6 +3898,9 @@
 		else
 			rx_reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
 		wr32(hw, I40E_QRX_ENA(pf_q), rx_reg);
+		/* No waiting for the Tx queue to disable */
+		if (!enable && test_bit(__I40E_PORT_TX_SUSPENDED, &pf->state))
+			continue;
 
 		/* wait for the change to finish */
 		ret = i40e_pf_rxq_wait(pf, pf_q, enable);
@@ -4166,8 +4156,12 @@
 	if (!vsi->netdev)
 		return;
 
-	for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++)
-		napi_enable(&vsi->q_vectors[q_idx]->napi);
+	for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) {
+		struct i40e_q_vector *q_vector = vsi->q_vectors[q_idx];
+
+		if (q_vector->rx.ring || q_vector->tx.ring)
+			napi_enable(&q_vector->napi);
+	}
 }
 
 /**
@@ -4181,8 +4175,12 @@
 	if (!vsi->netdev)
 		return;
 
-	for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++)
-		napi_disable(&vsi->q_vectors[q_idx]->napi);
+	for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) {
+		struct i40e_q_vector *q_vector = vsi->q_vectors[q_idx];
+
+		if (q_vector->rx.ring || q_vector->tx.ring)
+			napi_disable(&q_vector->napi);
+	}
 }
 
 /**
@@ -4269,12 +4267,12 @@
 
 #ifdef CONFIG_I40E_DCB
 /**
- * i40e_vsi_wait_txq_disabled - Wait for VSI's queues to be disabled
+ * i40e_vsi_wait_queues_disabled - Wait for VSI's queues to be disabled
  * @vsi: the VSI being configured
  *
- * This function waits for the given VSI's Tx queues to be disabled.
+ * This function waits for the given VSI's queues to be disabled.
  **/
-static int i40e_vsi_wait_txq_disabled(struct i40e_vsi *vsi)
+static int i40e_vsi_wait_queues_disabled(struct i40e_vsi *vsi)
 {
 	struct i40e_pf *pf = vsi->back;
 	int i, pf_q, ret;
@@ -4291,24 +4289,36 @@
 		}
 	}
 
+	pf_q = vsi->base_queue;
+	for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
+		/* Check and wait for the disable status of the queue */
+		ret = i40e_pf_rxq_wait(pf, pf_q, false);
+		if (ret) {
+			dev_info(&pf->pdev->dev,
+				 "VSI seid %d Rx ring %d disable timeout\n",
+				 vsi->seid, pf_q);
+			return ret;
+		}
+	}
+
 	return 0;
 }
 
 /**
- * i40e_pf_wait_txq_disabled - Wait for all queues of PF VSIs to be disabled
+ * i40e_pf_wait_queues_disabled - Wait for all queues of PF VSIs to be disabled
  * @pf: the PF
  *
- * This function waits for the Tx queues to be in disabled state for all the
+ * This function waits for the queues to be in disabled state for all the
  * VSIs that are managed by this PF.
  **/
-static int i40e_pf_wait_txq_disabled(struct i40e_pf *pf)
+static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf)
 {
 	int v, ret = 0;
 
 	for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
 		/* No need to wait for FCoE VSI queues */
 		if (pf->vsi[v] && pf->vsi[v]->type != I40E_VSI_FCOE) {
-			ret = i40e_vsi_wait_txq_disabled(pf->vsi[v]);
+			ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]);
 			if (ret)
 				break;
 		}
@@ -4334,7 +4344,7 @@
 {
 	struct i40e_ring *tx_ring = NULL;
 	struct i40e_pf	*pf;
-	u32 head, val, tx_pending;
+	u32 head, val, tx_pending_hw;
 	int i;
 
 	pf = vsi->back;
@@ -4362,15 +4372,43 @@
 
 	head = i40e_get_head(tx_ring);
 
-	tx_pending = i40e_get_tx_pending(tx_ring);
+	tx_pending_hw = i40e_get_tx_pending(tx_ring, false);
+
+	/* HW is done executing descriptors, updated HEAD write back,
+	 * but SW hasn't processed those descriptors. If interrupt is
+	 * not generated from this point ON, it could result into
+	 * dev_watchdog detecting timeout on those netdev_queue,
+	 * hence proactively trigger SW interrupt.
+	 */
+	if (tx_pending_hw && (!(val & I40E_PFINT_DYN_CTLN_INTENA_MASK))) {
+		/* NAPI Poll didn't run and clear since it was set */
+		if (test_and_clear_bit(I40E_Q_VECTOR_HUNG_DETECT,
+				       &tx_ring->q_vector->hung_detected)) {
+			netdev_info(vsi->netdev, "VSI_seid %d, Hung TX queue %d, tx_pending_hw: %d, NTC:0x%x, HWB: 0x%x, NTU: 0x%x, TAIL: 0x%x\n",
+				    vsi->seid, q_idx, tx_pending_hw,
+				    tx_ring->next_to_clean, head,
+				    tx_ring->next_to_use,
+				    readl(tx_ring->tail));
+			netdev_info(vsi->netdev, "VSI_seid %d, Issuing force_wb for TX queue %d, Interrupt Reg: 0x%x\n",
+				    vsi->seid, q_idx, val);
+			i40e_force_wb(vsi, tx_ring->q_vector);
+		} else {
+			/* First Chance - detected possible hung */
+			set_bit(I40E_Q_VECTOR_HUNG_DETECT,
+				&tx_ring->q_vector->hung_detected);
+		}
+	}
 
-	/* Interrupts are disabled and TX pending is non-zero,
-	 * trigger the SW interrupt (don't wait). Worst case
-	 * there will be one extra interrupt which may result
-	 * into not cleaning any queues because queues are cleaned.
+	/* This is the case where we have interrupts missing,
+	 * so the tx_pending in HW will most likely be 0, but we
+	 * will have tx_pending in SW since the WB happened but the
+	 * interrupt got lost.
 	 */
-	if (tx_pending && (!(val & I40E_PFINT_DYN_CTLN_INTENA_MASK)))
-		i40e_force_wb(vsi, tx_ring->q_vector);
+	if ((!tx_pending_hw) && i40e_get_tx_pending(tx_ring, true) &&
+	    (!(val & I40E_PFINT_DYN_CTLN_INTENA_MASK))) {
+		if (napi_reschedule(&tx_ring->q_vector->napi))
+			tx_ring->tx_stats.tx_lost_interrupt++;
+	}
 }
 
 /**
@@ -4441,7 +4479,7 @@
 		if (app.selector == I40E_APP_SEL_TCPIP &&
 		    app.protocolid == I40E_APP_PROTOID_ISCSI) {
 			tc = dcbcfg->etscfg.prioritytable[app.priority];
-			enabled_tc |= BIT_ULL(tc);
+			enabled_tc |= BIT(tc);
 			break;
 		}
 	}
@@ -4457,23 +4495,38 @@
  **/
 static u8 i40e_dcb_get_num_tc(struct i40e_dcbx_config *dcbcfg)
 {
+	int i, tc_unused = 0;
 	u8 num_tc = 0;
-	int i;
+	u8 ret = 0;
 
 	/* Scan the ETS Config Priority Table to find
 	 * traffic class enabled for a given priority
-	 * and use the traffic class index to get the
-	 * number of traffic classes enabled
+	 * and create a bitmask of enabled TCs
 	 */
-	for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
-		if (dcbcfg->etscfg.prioritytable[i] > num_tc)
-			num_tc = dcbcfg->etscfg.prioritytable[i];
-	}
+	for (i = 0; i < I40E_MAX_USER_PRIORITY; i++)
+		num_tc |= BIT(dcbcfg->etscfg.prioritytable[i]);
 
-	/* Traffic class index starts from zero so
-	 * increment to return the actual count
+	/* Now scan the bitmask to check for
+	 * contiguous TCs starting with TC0
 	 */
-	return num_tc + 1;
+	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+		if (num_tc & BIT(i)) {
+			if (!tc_unused) {
+				ret++;
+			} else {
+				pr_err("Non-contiguous TC - Disabling DCB\n");
+				return 1;
+			}
+		} else {
+			tc_unused = 1;
+		}
+	}
+
+	/* There is always at least TC0 */
+	if (!ret)
+		ret = 1;
+
+	return ret;
 }
 
 /**
@@ -4525,7 +4578,7 @@
 	/* At least have TC0 */
 	enabled_tc = (enabled_tc ? enabled_tc : 0x1);
 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-		if (enabled_tc & BIT_ULL(i))
+		if (enabled_tc & BIT(i))
 			num_tc++;
 	}
 	return num_tc;
@@ -4547,7 +4600,7 @@
 
 	/* Find the first enabled TC */
 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-		if (enabled_tc & BIT_ULL(i))
+		if (enabled_tc & BIT(i))
 			break;
 	}
 
@@ -4707,7 +4760,7 @@
 		 * will set the numtc for netdev as 2 that will be
 		 * referenced by the netdev layer as TC 0 and 1.
 		 */
-		if (vsi->tc_config.enabled_tc & BIT_ULL(i))
+		if (vsi->tc_config.enabled_tc & BIT(i))
 			netdev_set_tc_queue(netdev,
 					vsi->tc_config.tc_info[i].netdev_tc,
 					vsi->tc_config.tc_info[i].qcount,
@@ -4769,7 +4822,7 @@
 
 	/* Enable ETS TCs with equal BW Share for now across all VSIs */
 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-		if (enabled_tc & BIT_ULL(i))
+		if (enabled_tc & BIT(i))
 			bw_share[i] = 1;
 	}
 
@@ -4843,7 +4896,7 @@
 
 	/* Enable ETS TCs with equal BW Share for now */
 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-		if (enabled_tc & BIT_ULL(i))
+		if (enabled_tc & BIT(i))
 			bw_data.tc_bw_share_credits[i] = 1;
 	}
 
@@ -4974,8 +5027,7 @@
 	int err = 0;
 
 	/* Do not enable DCB for SW1 and SW2 images even if the FW is capable */
-	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
-	    (pf->hw.aq.fw_maj_ver < 4))
+	if (pf->flags & I40E_FLAG_NO_DCB_SUPPORT)
 		goto out;
 
 	/* Get the initial DCB configuration */
@@ -5207,11 +5259,7 @@
  * @netdev: net device to configure
  * @tc: number of traffic classes to enable
  **/
-#ifdef I40E_FCOE
-int i40e_setup_tc(struct net_device *netdev, u8 tc)
-#else
 static int i40e_setup_tc(struct net_device *netdev, u8 tc)
-#endif
 {
 	struct i40e_netdev_priv *np = netdev_priv(netdev);
 	struct i40e_vsi *vsi = np->vsi;
@@ -5240,7 +5288,7 @@
 
 	/* Generate TC map for number of tc requested */
 	for (i = 0; i < tc; i++)
-		enabled_tc |= BIT_ULL(i);
+		enabled_tc |= BIT(i);
 
 	/* Requesting same TC configuration as already enabled */
 	if (enabled_tc == vsi->tc_config.enabled_tc)
@@ -5264,6 +5312,19 @@
 	return ret;
 }
 
+#ifdef I40E_FCOE
+int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+		    struct tc_to_netdev *tc)
+#else
+static int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+			   struct tc_to_netdev *tc)
+#endif
+{
+	if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+	return i40e_setup_tc(netdev, tc->tc);
+}
+
 /**
  * i40e_open - Called when a network interface is made active
  * @netdev: network interface device structure
@@ -5305,6 +5366,10 @@
 #ifdef CONFIG_I40E_VXLAN
 	vxlan_get_rx_port(netdev);
 #endif
+#ifdef CONFIG_I40E_GENEVE
+	if (pf->flags & I40E_FLAG_GENEVE_OFFLOAD_CAPABLE)
+		geneve_get_rx_port(netdev);
+#endif
 
 	return 0;
 }
@@ -5668,8 +5733,8 @@
 	if (ret)
 		goto exit;
 
-	/* Wait for the PF's Tx queues to be disabled */
-	ret = i40e_pf_wait_txq_disabled(pf);
+	/* Wait for the PF's queues to be disabled */
+	ret = i40e_pf_wait_queues_disabled(pf);
 	if (ret) {
 		/* Schedule PF reset to recover */
 		set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
@@ -5738,7 +5803,7 @@
  **/
 static void i40e_service_event_complete(struct i40e_pf *pf)
 {
-	BUG_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state));
+	WARN_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state));
 
 	/* flush memory to make sure state is correct before next watchog */
 	smp_mb__before_atomic();
@@ -6013,6 +6078,9 @@
 	i40e_status status;
 	bool new_link, old_link;
 
+	/* save off old link status information */
+	pf->hw.phy.link_info_old = pf->hw.phy.link_info;
+
 	/* set this to force the get_link_status call to refresh state */
 	pf->hw.phy.get_link_info = true;
 
@@ -6101,23 +6169,23 @@
 
 	rtnl_lock();
 	if (test_bit(__I40E_REINIT_REQUESTED, &pf->state)) {
-		reset_flags |= BIT_ULL(__I40E_REINIT_REQUESTED);
+		reset_flags |= BIT(__I40E_REINIT_REQUESTED);
 		clear_bit(__I40E_REINIT_REQUESTED, &pf->state);
 	}
 	if (test_bit(__I40E_PF_RESET_REQUESTED, &pf->state)) {
-		reset_flags |= BIT_ULL(__I40E_PF_RESET_REQUESTED);
+		reset_flags |= BIT(__I40E_PF_RESET_REQUESTED);
 		clear_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
 	}
 	if (test_bit(__I40E_CORE_RESET_REQUESTED, &pf->state)) {
-		reset_flags |= BIT_ULL(__I40E_CORE_RESET_REQUESTED);
+		reset_flags |= BIT(__I40E_CORE_RESET_REQUESTED);
 		clear_bit(__I40E_CORE_RESET_REQUESTED, &pf->state);
 	}
 	if (test_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state)) {
-		reset_flags |= BIT_ULL(__I40E_GLOBAL_RESET_REQUESTED);
+		reset_flags |= BIT(__I40E_GLOBAL_RESET_REQUESTED);
 		clear_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state);
 	}
 	if (test_bit(__I40E_DOWN_REQUESTED, &pf->state)) {
-		reset_flags |= BIT_ULL(__I40E_DOWN_REQUESTED);
+		reset_flags |= BIT(__I40E_DOWN_REQUESTED);
 		clear_bit(__I40E_DOWN_REQUESTED, &pf->state);
 	}
 
@@ -6147,13 +6215,9 @@
 static void i40e_handle_link_event(struct i40e_pf *pf,
 				   struct i40e_arq_event_info *e)
 {
-	struct i40e_hw *hw = &pf->hw;
 	struct i40e_aqc_get_link_status *status =
 		(struct i40e_aqc_get_link_status *)&e->desc.params.raw;
 
-	/* save off old link status information */
-	hw->phy.link_info_old = hw->phy.link_info;
-
 	/* Do a new status request to re-enable LSE reporting
 	 * and load new status information into the hw struct
 	 * This completely ignores any state information
@@ -6192,15 +6256,19 @@
 	val = rd32(&pf->hw, pf->hw.aq.arq.len);
 	oldval = val;
 	if (val & I40E_PF_ARQLEN_ARQVFE_MASK) {
-		dev_info(&pf->pdev->dev, "ARQ VF Error detected\n");
+		if (hw->debug_mask & I40E_DEBUG_AQ)
+			dev_info(&pf->pdev->dev, "ARQ VF Error detected\n");
 		val &= ~I40E_PF_ARQLEN_ARQVFE_MASK;
 	}
 	if (val & I40E_PF_ARQLEN_ARQOVFL_MASK) {
-		dev_info(&pf->pdev->dev, "ARQ Overflow Error detected\n");
+		if (hw->debug_mask & I40E_DEBUG_AQ)
+			dev_info(&pf->pdev->dev, "ARQ Overflow Error detected\n");
 		val &= ~I40E_PF_ARQLEN_ARQOVFL_MASK;
+		pf->arq_overflows++;
 	}
 	if (val & I40E_PF_ARQLEN_ARQCRIT_MASK) {
-		dev_info(&pf->pdev->dev, "ARQ Critical Error detected\n");
+		if (hw->debug_mask & I40E_DEBUG_AQ)
+			dev_info(&pf->pdev->dev, "ARQ Critical Error detected\n");
 		val &= ~I40E_PF_ARQLEN_ARQCRIT_MASK;
 	}
 	if (oldval != val)
@@ -6209,15 +6277,18 @@
 	val = rd32(&pf->hw, pf->hw.aq.asq.len);
 	oldval = val;
 	if (val & I40E_PF_ATQLEN_ATQVFE_MASK) {
-		dev_info(&pf->pdev->dev, "ASQ VF Error detected\n");
+		if (pf->hw.debug_mask & I40E_DEBUG_AQ)
+			dev_info(&pf->pdev->dev, "ASQ VF Error detected\n");
 		val &= ~I40E_PF_ATQLEN_ATQVFE_MASK;
 	}
 	if (val & I40E_PF_ATQLEN_ATQOVFL_MASK) {
-		dev_info(&pf->pdev->dev, "ASQ Overflow Error detected\n");
+		if (pf->hw.debug_mask & I40E_DEBUG_AQ)
+			dev_info(&pf->pdev->dev, "ASQ Overflow Error detected\n");
 		val &= ~I40E_PF_ATQLEN_ATQOVFL_MASK;
 	}
 	if (val & I40E_PF_ATQLEN_ATQCRIT_MASK) {
-		dev_info(&pf->pdev->dev, "ASQ Critical Error detected\n");
+		if (pf->hw.debug_mask & I40E_DEBUG_AQ)
+			dev_info(&pf->pdev->dev, "ASQ Critical Error detected\n");
 		val &= ~I40E_PF_ATQLEN_ATQCRIT_MASK;
 	}
 	if (oldval != val)
@@ -6268,7 +6339,10 @@
 			break;
 		case i40e_aqc_opc_nvm_erase:
 		case i40e_aqc_opc_nvm_update:
-			i40e_debug(&pf->hw, I40E_DEBUG_NVM, "ARQ NVM operation completed\n");
+		case i40e_aqc_opc_oem_post_update:
+			i40e_debug(&pf->hw, I40E_DEBUG_NVM,
+				   "ARQ NVM operation 0x%04x completed\n",
+				   opcode);
 			break;
 		default:
 			dev_info(&pf->pdev->dev,
@@ -6685,6 +6759,7 @@
 	struct i40e_hw *hw = &pf->hw;
 	u8 set_fc_aq_fail = 0;
 	i40e_status ret;
+	u32 val;
 	u32 v;
 
 	/* Now we wait for GRST to settle out.
@@ -6751,12 +6826,12 @@
 	if (ret)
 		goto end_core_reset;
 
-	/* driver is only interested in link up/down and module qualification
-	 * reports from firmware
+	/* The driver only wants link up/down and module qualification
+	 * reports from firmware.  Note the negative logic.
 	 */
 	ret = i40e_aq_set_phy_int_mask(&pf->hw,
-				       I40E_AQ_EVENT_LINK_UPDOWN |
-				       I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
+				       ~(I40E_AQ_EVENT_LINK_UPDOWN |
+					 I40E_AQ_EVENT_MODULE_QUAL_FAIL), NULL);
 	if (ret)
 		dev_info(&pf->pdev->dev, "set phy mask fail, err %s aq_err %s\n",
 			 i40e_stat_str(&pf->hw, ret),
@@ -6823,8 +6898,21 @@
 		}
 	}
 
-	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
-	    (pf->hw.aq.fw_maj_ver < 4)) {
+	/* Reconfigure hardware for allowing smaller MSS in the case
+	 * of TSO, so that we avoid the MDD being fired and causing
+	 * a reset in the case of small MSS+TSO.
+	 */
+#define I40E_REG_MSS          0x000E64DC
+#define I40E_REG_MSS_MIN_MASK 0x3FF0000
+#define I40E_64BYTE_MSS       0x400000
+	val = rd32(hw, I40E_REG_MSS);
+	if ((val & I40E_REG_MSS_MIN_MASK) > I40E_64BYTE_MSS) {
+		val &= ~I40E_REG_MSS_MIN_MASK;
+		val |= I40E_64BYTE_MSS;
+		wr32(hw, I40E_REG_MSS, val);
+	}
+
+	if (pf->flags & I40E_FLAG_RESTART_AUTONEG) {
 		msleep(75);
 		ret = i40e_aq_set_link_restart_an(&pf->hw, true, NULL);
 		if (ret)
@@ -6886,7 +6974,6 @@
 {
 	struct i40e_hw *hw = &pf->hw;
 	bool mdd_detected = false;
-	bool pf_mdd_detected = false;
 	struct i40e_vf *vf;
 	u32 reg;
 	int i;
@@ -6932,19 +7019,12 @@
 		reg = rd32(hw, I40E_PF_MDET_TX);
 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
-			dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n");
-			pf_mdd_detected = true;
+			dev_dbg(&pf->pdev->dev, "TX driver issue detected on PF\n");
 		}
 		reg = rd32(hw, I40E_PF_MDET_RX);
 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
-			dev_info(&pf->pdev->dev, "RX driver issue detected, PF reset issued\n");
-			pf_mdd_detected = true;
-		}
-		/* Queue belongs to the PF, initiate a reset */
-		if (pf_mdd_detected) {
-			set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
-			i40e_service_event_schedule(pf);
+			dev_dbg(&pf->pdev->dev, "RX driver issue detected on PF\n");
 		}
 	}
 
@@ -6984,49 +7064,50 @@
 	i40e_flush(hw);
 }
 
-#ifdef CONFIG_I40E_VXLAN
 /**
- * i40e_sync_vxlan_filters_subtask - Sync the VSI filter list with HW
+ * i40e_sync_udp_filters_subtask - Sync the VSI filter list with HW
  * @pf: board private structure
  **/
-static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf)
+static void i40e_sync_udp_filters_subtask(struct i40e_pf *pf)
 {
+#if IS_ENABLED(CONFIG_VXLAN) || IS_ENABLED(CONFIG_GENEVE)
 	struct i40e_hw *hw = &pf->hw;
 	i40e_status ret;
 	__be16 port;
 	int i;
 
-	if (!(pf->flags & I40E_FLAG_VXLAN_FILTER_SYNC))
+	if (!(pf->flags & I40E_FLAG_UDP_FILTER_SYNC))
 		return;
 
-	pf->flags &= ~I40E_FLAG_VXLAN_FILTER_SYNC;
+	pf->flags &= ~I40E_FLAG_UDP_FILTER_SYNC;
 
 	for (i = 0; i < I40E_MAX_PF_UDP_OFFLOAD_PORTS; i++) {
-		if (pf->pending_vxlan_bitmap & BIT_ULL(i)) {
-			pf->pending_vxlan_bitmap &= ~BIT_ULL(i);
-			port = pf->vxlan_ports[i];
+		if (pf->pending_udp_bitmap & BIT_ULL(i)) {
+			pf->pending_udp_bitmap &= ~BIT_ULL(i);
+			port = pf->udp_ports[i].index;
 			if (port)
 				ret = i40e_aq_add_udp_tunnel(hw, ntohs(port),
-						     I40E_AQC_TUNNEL_TYPE_VXLAN,
+						     pf->udp_ports[i].type,
 						     NULL, NULL);
 			else
 				ret = i40e_aq_del_udp_tunnel(hw, i, NULL);
 
 			if (ret) {
-				dev_info(&pf->pdev->dev,
-					 "%s vxlan port %d, index %d failed, err %s aq_err %s\n",
-					 port ? "add" : "delete",
-					 ntohs(port), i,
-					 i40e_stat_str(&pf->hw, ret),
-					 i40e_aq_str(&pf->hw,
+				dev_dbg(&pf->pdev->dev,
+					"%s %s port %d, index %d failed, err %s aq_err %s\n",
+					pf->udp_ports[i].type ? "vxlan" : "geneve",
+					port ? "add" : "delete",
+					ntohs(port), i,
+					i40e_stat_str(&pf->hw, ret),
+					i40e_aq_str(&pf->hw,
 						    pf->hw.aq.asq_last_status));
-				pf->vxlan_ports[i] = 0;
+				pf->udp_ports[i].index = 0;
 			}
 		}
 	}
+#endif
 }
 
-#endif
 /**
  * i40e_service_task - Run the driver's async subtasks
  * @work: pointer to work_struct containing our data
@@ -7045,15 +7126,14 @@
 	}
 
 	i40e_detect_recover_hung(pf);
+	i40e_sync_filters_subtask(pf);
 	i40e_reset_subtask(pf);
 	i40e_handle_mdd_event(pf);
 	i40e_vc_process_vflr_event(pf);
 	i40e_watchdog_subtask(pf);
 	i40e_fdir_reinit_subtask(pf);
 	i40e_sync_filters_subtask(pf);
-#ifdef CONFIG_I40E_VXLAN
-	i40e_sync_vxlan_filters_subtask(pf);
-#endif
+	i40e_sync_udp_filters_subtask(pf);
 	i40e_clean_adminq_subtask(pf);
 
 	i40e_service_event_complete(pf);
@@ -7106,7 +7186,7 @@
 		vsi->alloc_queue_pairs = 1;
 		vsi->num_desc = ALIGN(I40E_FDIR_RING_COUNT,
 				      I40E_REQ_DESCRIPTOR_MULTIPLE);
-		vsi->num_q_vectors = 1;
+		vsi->num_q_vectors = pf->num_fdsb_msix;
 		break;
 
 	case I40E_VSI_VMDQ2:
@@ -7282,6 +7362,23 @@
 }
 
 /**
+ * i40e_clear_rss_config_user - clear the user configured RSS hash keys
+ * and lookup table
+ * @vsi: Pointer to VSI structure
+ */
+static void i40e_clear_rss_config_user(struct i40e_vsi *vsi)
+{
+	if (!vsi)
+		return;
+
+	kfree(vsi->rss_hkey_user);
+	vsi->rss_hkey_user = NULL;
+
+	kfree(vsi->rss_lut_user);
+	vsi->rss_lut_user = NULL;
+}
+
+/**
  * i40e_vsi_clear - Deallocate the VSI provided
  * @vsi: the VSI being un-configured
  **/
@@ -7318,6 +7415,7 @@
 	i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx);
 
 	i40e_vsi_free_arrays(vsi, true);
+	i40e_clear_rss_config_user(vsi);
 
 	pf->vsi[vsi->idx] = NULL;
 	if (vsi->idx < pf->next_vsi)
@@ -7376,8 +7474,6 @@
 		tx_ring->dcb_tc = 0;
 		if (vsi->back->flags & I40E_FLAG_WB_ON_ITR_CAPABLE)
 			tx_ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
-		if (vsi->back->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE)
-			tx_ring->flags |= I40E_TXR_FLAGS_OUTER_UDP_CSUM;
 		vsi->tx_rings[i] = tx_ring;
 
 		rx_ring = &tx_ring[1];
@@ -7476,9 +7572,11 @@
 	/* reserve one vector for sideband flow director */
 	if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
 		if (vectors_left) {
+			pf->num_fdsb_msix = 1;
 			v_budget++;
 			vectors_left--;
 		} else {
+			pf->num_fdsb_msix = 0;
 			pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
 		}
 	}
@@ -7612,10 +7710,11 @@
  * i40e_vsi_alloc_q_vector - Allocate memory for a single interrupt vector
  * @vsi: the VSI being configured
  * @v_idx: index of the vector in the vsi struct
+ * @cpu: cpu to be used on affinity_mask
  *
  * We allocate one q_vector.  If allocation fails we return -ENOMEM.
  **/
-static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
+static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx, int cpu)
 {
 	struct i40e_q_vector *q_vector;
 
@@ -7626,7 +7725,8 @@
 
 	q_vector->vsi = vsi;
 	q_vector->v_idx = v_idx;
-	cpumask_set_cpu(v_idx, &q_vector->affinity_mask);
+	cpumask_set_cpu(cpu, &q_vector->affinity_mask);
+
 	if (vsi->netdev)
 		netif_napi_add(vsi->netdev, &q_vector->napi,
 			       i40e_napi_poll, NAPI_POLL_WEIGHT);
@@ -7650,8 +7750,7 @@
 static int i40e_vsi_alloc_q_vectors(struct i40e_vsi *vsi)
 {
 	struct i40e_pf *pf = vsi->back;
-	int v_idx, num_q_vectors;
-	int err;
+	int err, v_idx, num_q_vectors, current_cpu;
 
 	/* if not MSIX, give the one vector only to the LAN VSI */
 	if (pf->flags & I40E_FLAG_MSIX_ENABLED)
@@ -7661,10 +7760,15 @@
 	else
 		return -EINVAL;
 
+	current_cpu = cpumask_first(cpu_online_mask);
+
 	for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
-		err = i40e_vsi_alloc_q_vector(vsi, v_idx);
+		err = i40e_vsi_alloc_q_vector(vsi, v_idx, current_cpu);
 		if (err)
 			goto err_out;
+		current_cpu = cpumask_next(current_cpu, cpu_online_mask);
+		if (unlikely(current_cpu >= nr_cpu_ids))
+			current_cpu = cpumask_first(cpu_online_mask);
 	}
 
 	return 0;
@@ -7770,7 +7874,7 @@
 
 	i40e_flush(hw);
 
-	i40e_irq_dynamic_enable_icr0(pf);
+	i40e_irq_dynamic_enable_icr0(pf, true);
 
 	return err;
 }
@@ -7780,7 +7884,8 @@
  * @vsi: vsi structure
  * @seed: RSS hash seed
  **/
-static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed)
+static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
+			      u8 *lut, u16 lut_size)
 {
 	struct i40e_aqc_get_set_rss_key_data rss_key;
 	struct i40e_pf *pf = vsi->back;
@@ -7833,43 +7938,103 @@
 {
 	u8 seed[I40E_HKEY_ARRAY_SIZE];
 	struct i40e_pf *pf = vsi->back;
+	u8 *lut;
+	int ret;
+
+	if (!(pf->flags & I40E_FLAG_RSS_AQ_CAPABLE))
+		return 0;
+
+	lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+	if (!lut)
+		return -ENOMEM;
 
+	i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
 	netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
-	vsi->rss_size = min_t(int, pf->rss_size, vsi->num_queue_pairs);
+	vsi->rss_size = min_t(int, pf->alloc_rss_size, vsi->num_queue_pairs);
+	ret = i40e_config_rss_aq(vsi, seed, lut, vsi->rss_table_size);
+	kfree(lut);
 
-	if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE)
-		return i40e_config_rss_aq(vsi, seed);
+	return ret;
+}
 
-	return 0;
+/**
+ * i40e_get_rss_aq - Get RSS keys and lut by using AQ commands
+ * @vsi: Pointer to vsi structure
+ * @seed: Buffter to store the hash keys
+ * @lut: Buffer to store the lookup table entries
+ * @lut_size: Size of buffer to store the lookup table entries
+ *
+ * Return 0 on success, negative on failure
+ */
+static int i40e_get_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
+			   u8 *lut, u16 lut_size)
+{
+	struct i40e_pf *pf = vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	int ret = 0;
+
+	if (seed) {
+		ret = i40e_aq_get_rss_key(hw, vsi->id,
+			(struct i40e_aqc_get_set_rss_key_data *)seed);
+		if (ret) {
+			dev_info(&pf->pdev->dev,
+				 "Cannot get RSS key, err %s aq_err %s\n",
+				 i40e_stat_str(&pf->hw, ret),
+				 i40e_aq_str(&pf->hw,
+					     pf->hw.aq.asq_last_status));
+			return ret;
+		}
+	}
+
+	if (lut) {
+		bool pf_lut = vsi->type == I40E_VSI_MAIN ? true : false;
+
+		ret = i40e_aq_get_rss_lut(hw, vsi->id, pf_lut, lut, lut_size);
+		if (ret) {
+			dev_info(&pf->pdev->dev,
+				 "Cannot get RSS lut, err %s aq_err %s\n",
+				 i40e_stat_str(&pf->hw, ret),
+				 i40e_aq_str(&pf->hw,
+					     pf->hw.aq.asq_last_status));
+			return ret;
+		}
+	}
+
+	return ret;
 }
 
 /**
- * i40e_config_rss_reg - Prepare for RSS if used
- * @pf: board private structure
+ * i40e_config_rss_reg - Configure RSS keys and lut by writing registers
+ * @vsi: Pointer to vsi structure
  * @seed: RSS hash seed
+ * @lut: Lookup table
+ * @lut_size: Lookup table size
+ *
+ * Returns 0 on success, negative on failure
  **/
-static int i40e_config_rss_reg(struct i40e_pf *pf, const u8 *seed)
+static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
+			       const u8 *lut, u16 lut_size)
 {
-	struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+	struct i40e_pf *pf = vsi->back;
 	struct i40e_hw *hw = &pf->hw;
-	u32 *seed_dw = (u32 *)seed;
-	u32 current_queue = 0;
-	u32 lut = 0;
-	int i, j;
+	u8 i;
 
 	/* Fill out hash function seed */
-	for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-		wr32(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
+	if (seed) {
+		u32 *seed_dw = (u32 *)seed;
 
-	for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++) {
-		lut = 0;
-		for (j = 0; j < 4; j++) {
-			if (current_queue == vsi->rss_size)
-				current_queue = 0;
-			lut |= ((current_queue) << (8 * j));
-			current_queue++;
-		}
-		wr32(&pf->hw, I40E_PFQF_HLUT(i), lut);
+		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+			i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
+	}
+
+	if (lut) {
+		u32 *lut_dw = (u32 *)lut;
+
+		if (lut_size != I40E_HLUT_ARRAY_SIZE)
+			return -EINVAL;
+
+		for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++)
+			wr32(hw, I40E_PFQF_HLUT(i), lut_dw[i]);
 	}
 	i40e_flush(hw);
 
@@ -7877,40 +8042,148 @@
 }
 
 /**
- * i40e_config_rss - Prepare for RSS if used
+ * i40e_get_rss_reg - Get the RSS keys and lut by reading registers
+ * @vsi: Pointer to VSI structure
+ * @seed: Buffer to store the keys
+ * @lut: Buffer to store the lookup table entries
+ * @lut_size: Size of buffer to store the lookup table entries
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int i40e_get_rss_reg(struct i40e_vsi *vsi, u8 *seed,
+			    u8 *lut, u16 lut_size)
+{
+	struct i40e_pf *pf = vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	u16 i;
+
+	if (seed) {
+		u32 *seed_dw = (u32 *)seed;
+
+		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+			seed_dw[i] = i40e_read_rx_ctl(hw, I40E_PFQF_HKEY(i));
+	}
+	if (lut) {
+		u32 *lut_dw = (u32 *)lut;
+
+		if (lut_size != I40E_HLUT_ARRAY_SIZE)
+			return -EINVAL;
+		for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++)
+			lut_dw[i] = rd32(hw, I40E_PFQF_HLUT(i));
+	}
+
+	return 0;
+}
+
+/**
+ * i40e_config_rss - Configure RSS keys and lut
+ * @vsi: Pointer to VSI structure
+ * @seed: RSS hash seed
+ * @lut: Lookup table
+ * @lut_size: Lookup table size
+ *
+ * Returns 0 on success, negative on failure
+ */
+int i40e_config_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
+{
+	struct i40e_pf *pf = vsi->back;
+
+	if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE)
+		return i40e_config_rss_aq(vsi, seed, lut, lut_size);
+	else
+		return i40e_config_rss_reg(vsi, seed, lut, lut_size);
+}
+
+/**
+ * i40e_get_rss - Get RSS keys and lut
+ * @vsi: Pointer to VSI structure
+ * @seed: Buffer to store the keys
+ * @lut: Buffer to store the lookup table entries
+ * lut_size: Size of buffer to store the lookup table entries
+ *
+ * Returns 0 on success, negative on failure
+ */
+int i40e_get_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
+{
+	struct i40e_pf *pf = vsi->back;
+
+	if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE)
+		return i40e_get_rss_aq(vsi, seed, lut, lut_size);
+	else
+		return i40e_get_rss_reg(vsi, seed, lut, lut_size);
+}
+
+/**
+ * i40e_fill_rss_lut - Fill the RSS lookup table with default values
+ * @pf: Pointer to board private structure
+ * @lut: Lookup table
+ * @rss_table_size: Lookup table size
+ * @rss_size: Range of queue number for hashing
+ */
+static void i40e_fill_rss_lut(struct i40e_pf *pf, u8 *lut,
+			      u16 rss_table_size, u16 rss_size)
+{
+	u16 i;
+
+	for (i = 0; i < rss_table_size; i++)
+		lut[i] = i % rss_size;
+}
+
+/**
+ * i40e_pf_config_rss - Prepare for RSS if used
  * @pf: board private structure
  **/
-static int i40e_config_rss(struct i40e_pf *pf)
+static int i40e_pf_config_rss(struct i40e_pf *pf)
 {
 	struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
 	u8 seed[I40E_HKEY_ARRAY_SIZE];
+	u8 *lut;
 	struct i40e_hw *hw = &pf->hw;
 	u32 reg_val;
 	u64 hena;
-
-	netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+	int ret;
 
 	/* By default we enable TCP/UDP with IPv4/IPv6 ptypes */
-	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
-		((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
+	hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
+		((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
 	hena |= i40e_pf_get_default_rss_hena(pf);
 
-	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
-	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
-
-	vsi->rss_size = min_t(int, pf->rss_size, vsi->num_queue_pairs);
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
 
 	/* Determine the RSS table size based on the hardware capabilities */
-	reg_val = rd32(hw, I40E_PFQF_CTL_0);
+	reg_val = i40e_read_rx_ctl(hw, I40E_PFQF_CTL_0);
 	reg_val = (pf->rss_table_size == 512) ?
 			(reg_val | I40E_PFQF_CTL_0_HASHLUTSIZE_512) :
 			(reg_val & ~I40E_PFQF_CTL_0_HASHLUTSIZE_512);
-	wr32(hw, I40E_PFQF_CTL_0, reg_val);
+	i40e_write_rx_ctl(hw, I40E_PFQF_CTL_0, reg_val);
 
-	if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE)
-		return i40e_config_rss_aq(pf->vsi[pf->lan_vsi], seed);
+	/* Determine the RSS size of the VSI */
+	if (!vsi->rss_size)
+		vsi->rss_size = min_t(int, pf->alloc_rss_size,
+				      vsi->num_queue_pairs);
+
+	lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+	if (!lut)
+		return -ENOMEM;
+
+	/* Use user configured lut if there is one, otherwise use default */
+	if (vsi->rss_lut_user)
+		memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
 	else
-		return i40e_config_rss_reg(pf, seed);
+		i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
+
+	/* Use user configured hash key if there is one, otherwise
+	 * use default.
+	 */
+	if (vsi->rss_hkey_user)
+		memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
+	else
+		netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+	ret = i40e_config_rss(vsi, seed, lut, vsi->rss_table_size);
+	kfree(lut);
+
+	return ret;
 }
 
 /**
@@ -7935,13 +8208,28 @@
 		vsi->req_queue_pairs = queue_count;
 		i40e_prep_for_reset(pf);
 
-		pf->rss_size = new_rss_size;
+		pf->alloc_rss_size = new_rss_size;
 
 		i40e_reset_and_rebuild(pf, true);
-		i40e_config_rss(pf);
+
+		/* Discard the user configured hash keys and lut, if less
+		 * queues are enabled.
+		 */
+		if (queue_count < vsi->rss_size) {
+			i40e_clear_rss_config_user(vsi);
+			dev_dbg(&pf->pdev->dev,
+				"discard user configured hash keys and lut\n");
+		}
+
+		/* Reset vsi->rss_size, as number of enabled queues changed */
+		vsi->rss_size = min_t(int, pf->alloc_rss_size,
+				      vsi->num_queue_pairs);
+
+		i40e_pf_config_rss(pf);
 	}
-	dev_info(&pf->pdev->dev, "RSS count:  %d\n", pf->rss_size);
-	return pf->rss_size;
+	dev_info(&pf->pdev->dev, "RSS count/HW max RSS count:  %d/%d\n",
+		 pf->alloc_rss_size, pf->rss_size_max);
+	return pf->alloc_rss_size;
 }
 
 /**
@@ -8099,11 +8387,6 @@
 		    I40E_FLAG_LINK_POLLING_ENABLED |
 		    I40E_FLAG_MSIX_ENABLED;
 
-	if (iommu_present(&pci_bus_type))
-		pf->flags |= I40E_FLAG_RX_PS_ENABLED;
-	else
-		pf->flags |= I40E_FLAG_RX_1BUF_ENABLED;
-
 	/* Set default ITR */
 	pf->rx_itr_default = I40E_ITR_DYNAMIC | I40E_ITR_RX_DEF;
 	pf->tx_itr_default = I40E_ITR_DYNAMIC | I40E_ITR_TX_DEF;
@@ -8112,13 +8395,14 @@
 	 * maximum might end up larger than the available queues
 	 */
 	pf->rss_size_max = BIT(pf->hw.func_caps.rss_table_entry_width);
-	pf->rss_size = 1;
+	pf->alloc_rss_size = 1;
 	pf->rss_table_size = pf->hw.func_caps.rss_table_size;
 	pf->rss_size_max = min_t(int, pf->rss_size_max,
 				 pf->hw.func_caps.num_tx_qp);
 	if (pf->hw.func_caps.rss) {
 		pf->flags |= I40E_FLAG_RSS_ENABLED;
-		pf->rss_size = min_t(int, pf->rss_size_max, num_online_cpus());
+		pf->alloc_rss_size = min_t(int, pf->rss_size_max,
+					   num_online_cpus());
 	}
 
 	/* MFP mode enabled */
@@ -8151,6 +8435,26 @@
 				 pf->hw.func_caps.fd_filters_best_effort;
 	}
 
+	if (i40e_is_mac_710(&pf->hw) &&
+	    (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
+	    (pf->hw.aq.fw_maj_ver < 4))) {
+		pf->flags |= I40E_FLAG_RESTART_AUTONEG;
+		/* No DCB support  for FW < v4.33 */
+		pf->flags |= I40E_FLAG_NO_DCB_SUPPORT;
+	}
+
+	/* Disable FW LLDP if FW < v4.3 */
+	if (i40e_is_mac_710(&pf->hw) &&
+	    (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
+	    (pf->hw.aq.fw_maj_ver < 4)))
+		pf->flags |= I40E_FLAG_STOP_FW_LLDP;
+
+	/* Use the FW Set LLDP MIB API if FW > v4.40 */
+	if (i40e_is_mac_710(&pf->hw) &&
+	    (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver >= 40)) ||
+	    (pf->hw.aq.fw_maj_ver >= 5)))
+		pf->flags |= I40E_FLAG_USE_SET_LLDP_MIB;
+
 	if (pf->hw.func_caps.vmdq) {
 		pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI;
 		pf->flags |= I40E_FLAG_VMDQ_ENABLED;
@@ -8176,8 +8480,20 @@
 			     I40E_FLAG_HW_ATR_EVICT_CAPABLE |
 			     I40E_FLAG_OUTER_UDP_CSUM_CAPABLE |
 			     I40E_FLAG_WB_ON_ITR_CAPABLE |
-			     I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE;
+			     I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE |
+			     I40E_FLAG_100M_SGMII_CAPABLE |
+			     I40E_FLAG_USE_SET_LLDP_MIB |
+			     I40E_FLAG_GENEVE_OFFLOAD_CAPABLE;
+	} else if ((pf->hw.aq.api_maj_ver > 1) ||
+		   ((pf->hw.aq.api_maj_ver == 1) &&
+		    (pf->hw.aq.api_min_ver > 4))) {
+		/* Supported in FW API version higher than 1.4 */
+		pf->flags |= I40E_FLAG_GENEVE_OFFLOAD_CAPABLE;
+		pf->auto_disable_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
+	} else {
+		pf->auto_disable_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
 	}
+
 	pf->eeprom_version = 0xDEAD;
 	pf->lan_veb = I40E_NO_VEB;
 	pf->lan_vsi = I40E_NO_VSI;
@@ -8226,7 +8542,9 @@
 		/* Enable filters and mark for reset */
 		if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
 			need_reset = true;
-		pf->flags |= I40E_FLAG_FD_SB_ENABLED;
+		/* enable FD_SB only if there is MSI-X vector */
+		if (pf->num_fdsb_msix > 0)
+			pf->flags |= I40E_FLAG_FD_SB_ENABLED;
 	} else {
 		/* turn off filters, mark for reset and clear SW filter list */
 		if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
@@ -8275,26 +8593,29 @@
 	return 0;
 }
 
-#ifdef CONFIG_I40E_VXLAN
+#if IS_ENABLED(CONFIG_VXLAN) || IS_ENABLED(CONFIG_GENEVE)
 /**
- * i40e_get_vxlan_port_idx - Lookup a possibly offloaded for Rx UDP port
+ * i40e_get_udp_port_idx - Lookup a possibly offloaded for Rx UDP port
  * @pf: board private structure
  * @port: The UDP port to look up
  *
  * Returns the index number or I40E_MAX_PF_UDP_OFFLOAD_PORTS if port not found
  **/
-static u8 i40e_get_vxlan_port_idx(struct i40e_pf *pf, __be16 port)
+static u8 i40e_get_udp_port_idx(struct i40e_pf *pf, __be16 port)
 {
 	u8 i;
 
 	for (i = 0; i < I40E_MAX_PF_UDP_OFFLOAD_PORTS; i++) {
-		if (pf->vxlan_ports[i] == port)
+		if (pf->udp_ports[i].index == port)
 			return i;
 	}
 
 	return i;
 }
 
+#endif
+
+#if IS_ENABLED(CONFIG_VXLAN)
 /**
  * i40e_add_vxlan_port - Get notifications about VXLAN ports that come up
  * @netdev: This physical port's netdev
@@ -8310,10 +8631,7 @@
 	u8 next_idx;
 	u8 idx;
 
-	if (sa_family == AF_INET6)
-		return;
-
-	idx = i40e_get_vxlan_port_idx(pf, port);
+	idx = i40e_get_udp_port_idx(pf, port);
 
 	/* Check if port already exists */
 	if (idx < I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
@@ -8323,7 +8641,7 @@
 	}
 
 	/* Now check if there is space to add the new port */
-	next_idx = i40e_get_vxlan_port_idx(pf, 0);
+	next_idx = i40e_get_udp_port_idx(pf, 0);
 
 	if (next_idx == I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
 		netdev_info(netdev, "maximum number of vxlan UDP ports reached, not adding port %d\n",
@@ -8332,9 +8650,10 @@
 	}
 
 	/* New port: add it and mark its index in the bitmap */
-	pf->vxlan_ports[next_idx] = port;
-	pf->pending_vxlan_bitmap |= BIT_ULL(next_idx);
-	pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC;
+	pf->udp_ports[next_idx].index = port;
+	pf->udp_ports[next_idx].type = I40E_AQC_TUNNEL_TYPE_VXLAN;
+	pf->pending_udp_bitmap |= BIT_ULL(next_idx);
+	pf->flags |= I40E_FLAG_UDP_FILTER_SYNC;
 }
 
 /**
@@ -8351,26 +8670,106 @@
 	struct i40e_pf *pf = vsi->back;
 	u8 idx;
 
-	if (sa_family == AF_INET6)
-		return;
-
-	idx = i40e_get_vxlan_port_idx(pf, port);
+	idx = i40e_get_udp_port_idx(pf, port);
 
 	/* Check if port already exists */
 	if (idx < I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
 		/* if port exists, set it to 0 (mark for deletion)
 		 * and make it pending
 		 */
-		pf->vxlan_ports[idx] = 0;
-		pf->pending_vxlan_bitmap |= BIT_ULL(idx);
-		pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC;
+		pf->udp_ports[idx].index = 0;
+		pf->pending_udp_bitmap |= BIT_ULL(idx);
+		pf->flags |= I40E_FLAG_UDP_FILTER_SYNC;
 	} else {
 		netdev_warn(netdev, "vxlan port %d was not found, not deleting\n",
 			    ntohs(port));
 	}
 }
+#endif
+
+#if IS_ENABLED(CONFIG_GENEVE)
+/**
+ * i40e_add_geneve_port - Get notifications about GENEVE ports that come up
+ * @netdev: This physical port's netdev
+ * @sa_family: Socket Family that GENEVE is notifying us about
+ * @port: New UDP port number that GENEVE started listening to
+ **/
+static void i40e_add_geneve_port(struct net_device *netdev,
+				 sa_family_t sa_family, __be16 port)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	u8 next_idx;
+	u8 idx;
+
+	if (!(pf->flags & I40E_FLAG_GENEVE_OFFLOAD_CAPABLE))
+		return;
+
+	idx = i40e_get_udp_port_idx(pf, port);
 
+	/* Check if port already exists */
+	if (idx < I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
+		netdev_info(netdev, "udp port %d already offloaded\n",
+			    ntohs(port));
+		return;
+	}
+
+	/* Now check if there is space to add the new port */
+	next_idx = i40e_get_udp_port_idx(pf, 0);
+
+	if (next_idx == I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
+		netdev_info(netdev, "maximum number of UDP ports reached, not adding port %d\n",
+			    ntohs(port));
+		return;
+	}
+
+	/* New port: add it and mark its index in the bitmap */
+	pf->udp_ports[next_idx].index = port;
+	pf->udp_ports[next_idx].type = I40E_AQC_TUNNEL_TYPE_NGE;
+	pf->pending_udp_bitmap |= BIT_ULL(next_idx);
+	pf->flags |= I40E_FLAG_UDP_FILTER_SYNC;
+
+	dev_info(&pf->pdev->dev, "adding geneve port %d\n", ntohs(port));
+}
+
+/**
+ * i40e_del_geneve_port - Get notifications about GENEVE ports that go away
+ * @netdev: This physical port's netdev
+ * @sa_family: Socket Family that GENEVE is notifying us about
+ * @port: UDP port number that GENEVE stopped listening to
+ **/
+static void i40e_del_geneve_port(struct net_device *netdev,
+				 sa_family_t sa_family, __be16 port)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	u8 idx;
+
+	if (!(pf->flags & I40E_FLAG_GENEVE_OFFLOAD_CAPABLE))
+		return;
+
+	idx = i40e_get_udp_port_idx(pf, port);
+
+	/* Check if port already exists */
+	if (idx < I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
+		/* if port exists, set it to 0 (mark for deletion)
+		 * and make it pending
+		 */
+		pf->udp_ports[idx].index = 0;
+		pf->pending_udp_bitmap |= BIT_ULL(idx);
+		pf->flags |= I40E_FLAG_UDP_FILTER_SYNC;
+
+		dev_info(&pf->pdev->dev, "deleting geneve port %d\n",
+			 ntohs(port));
+	} else {
+		netdev_warn(netdev, "geneve port %d was not found, not deleting\n",
+			    ntohs(port));
+	}
+}
 #endif
+
 static int i40e_get_phys_port_id(struct net_device *netdev,
 				 struct netdev_phys_item_id *ppid)
 {
@@ -8545,10 +8944,13 @@
 		return 0;
 
 	return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode,
-				       nlflags, 0, 0, filter_mask, NULL);
+				       0, 0, nlflags, filter_mask, NULL);
 }
 
-#define I40E_MAX_TUNNEL_HDR_LEN 80
+/* Hardware supports L4 tunnel length of 128B (=2^7) which includes
+ * inner mac plus all inner ethertypes.
+ */
+#define I40E_MAX_TUNNEL_HDR_LEN 128
 /**
  * i40e_features_check - Validate encapsulated packet conforms to limits
  * @skb: skb buff
@@ -8560,7 +8962,7 @@
 					     netdev_features_t features)
 {
 	if (skb->encapsulation &&
-	    (skb_inner_mac_header(skb) - skb_transport_header(skb) >
+	    ((skb_inner_network_header(skb) - skb_transport_header(skb)) >
 	     I40E_MAX_TUNNEL_HDR_LEN))
 		return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK);
 
@@ -8583,7 +8985,7 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= i40e_netpoll,
 #endif
-	.ndo_setup_tc		= i40e_setup_tc,
+	.ndo_setup_tc		= __i40e_setup_tc,
 #ifdef I40E_FCOE
 	.ndo_fcoe_enable	= i40e_fcoe_enable,
 	.ndo_fcoe_disable	= i40e_fcoe_disable,
@@ -8595,10 +8997,14 @@
 	.ndo_get_vf_config	= i40e_ndo_get_vf_config,
 	.ndo_set_vf_link_state	= i40e_ndo_set_vf_link_state,
 	.ndo_set_vf_spoofchk	= i40e_ndo_set_vf_spoofchk,
-#ifdef CONFIG_I40E_VXLAN
+#if IS_ENABLED(CONFIG_VXLAN)
 	.ndo_add_vxlan_port	= i40e_add_vxlan_port,
 	.ndo_del_vxlan_port	= i40e_del_vxlan_port,
 #endif
+#if IS_ENABLED(CONFIG_GENEVE)
+	.ndo_add_geneve_port	= i40e_add_geneve_port,
+	.ndo_del_geneve_port	= i40e_del_geneve_port,
+#endif
 	.ndo_get_phys_port_id	= i40e_get_phys_port_id,
 	.ndo_fdb_add		= i40e_ndo_fdb_add,
 	.ndo_features_check	= i40e_features_check,
@@ -8631,14 +9037,19 @@
 	np = netdev_priv(netdev);
 	np->vsi = vsi;
 
-	netdev->hw_enc_features |= NETIF_F_IP_CSUM	 |
-				  NETIF_F_GSO_UDP_TUNNEL |
-				  NETIF_F_GSO_GRE	 |
-				  NETIF_F_TSO;
+	netdev->hw_enc_features |= NETIF_F_IP_CSUM	       |
+				   NETIF_F_IPV6_CSUM	       |
+				   NETIF_F_TSO		       |
+				   NETIF_F_TSO6		       |
+				   NETIF_F_TSO_ECN	       |
+				   NETIF_F_GSO_GRE	       |
+				   NETIF_F_GSO_UDP_TUNNEL      |
+				   NETIF_F_GSO_UDP_TUNNEL_CSUM |
+				   0;
 
 	netdev->features = NETIF_F_SG		       |
 			   NETIF_F_IP_CSUM	       |
-			   NETIF_F_SCTP_CSUM	       |
+			   NETIF_F_SCTP_CRC	       |
 			   NETIF_F_HIGHDMA	       |
 			   NETIF_F_GSO_UDP_TUNNEL      |
 			   NETIF_F_GSO_GRE	       |
@@ -8655,6 +9066,8 @@
 
 	if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
 		netdev->features |= NETIF_F_NTUPLE;
+	if (pf->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE)
+		netdev->features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
 
 	/* copy netdev features into list of user selectable features */
 	netdev->hw_features |= netdev->features;
@@ -9051,7 +9464,7 @@
 				f->is_vf, f->is_netdev);
 	spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-	i40e_sync_vsi_filters(vsi, false);
+	i40e_sync_vsi_filters(vsi);
 
 	i40e_vsi_delete(vsi);
 	i40e_vsi_free_q_vectors(vsi);
@@ -9159,10 +9572,15 @@
  **/
 static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
 {
-	struct i40e_pf *pf = vsi->back;
+	struct i40e_pf *pf;
 	u8 enabled_tc;
 	int ret;
 
+	if (!vsi)
+		return NULL;
+
+	pf = vsi->back;
+
 	i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx);
 	i40e_vsi_clear_rings(vsi);
 
@@ -9213,6 +9631,44 @@
 }
 
 /**
+ * i40e_macaddr_init - explicitly write the mac address filters.
+ *
+ * @vsi: pointer to the vsi.
+ * @macaddr: the MAC address
+ *
+ * This is needed when the macaddr has been obtained by other
+ * means than the default, e.g., from Open Firmware or IDPROM.
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_macaddr_init(struct i40e_vsi *vsi, u8 *macaddr)
+{
+	int ret;
+	struct i40e_aqc_add_macvlan_element_data element;
+
+	ret = i40e_aq_mac_address_write(&vsi->back->hw,
+					I40E_AQC_WRITE_TYPE_LAA_WOL,
+					macaddr, NULL);
+	if (ret) {
+		dev_info(&vsi->back->pdev->dev,
+			 "Addr change for VSI failed: %d\n", ret);
+		return -EADDRNOTAVAIL;
+	}
+
+	memset(&element, 0, sizeof(element));
+	ether_addr_copy(element.mac_addr, macaddr);
+	element.flags = cpu_to_le16(I40E_AQC_MACVLAN_ADD_PERFECT_MATCH);
+	ret = i40e_aq_add_macvlan(&vsi->back->hw, vsi->seid, &element, 1, NULL);
+	if (ret) {
+		dev_info(&vsi->back->pdev->dev,
+			 "add filter failed err %s aq_err %s\n",
+			 i40e_stat_str(&vsi->back->hw, ret),
+			 i40e_aq_str(&vsi->back->hw,
+				     vsi->back->hw.aq.asq_last_status));
+	}
+	return ret;
+}
+
+/**
  * i40e_vsi_setup - Set up a VSI by a given type
  * @pf: board private structure
  * @type: VSI type
@@ -9336,6 +9792,17 @@
 	switch (vsi->type) {
 	/* setup the netdev if needed */
 	case I40E_VSI_MAIN:
+		/* Apply relevant filters if a platform-specific mac
+		 * address was selected.
+		 */
+		if (!!(pf->flags & I40E_FLAG_PF_MAC)) {
+			ret = i40e_macaddr_init(vsi, pf->hw.mac.addr);
+			if (ret) {
+				dev_warn(&pf->pdev->dev,
+					 "could not set up macaddr; err %d\n",
+					 ret);
+			}
+		}
 	case I40E_VSI_VMDQ2:
 	case I40E_VSI_FCOE:
 		ret = i40e_config_netdev(vsi);
@@ -9614,13 +10081,13 @@
 {
 	struct i40e_pf *pf = veb->pf;
 	bool is_default = veb->pf->cur_promisc;
-	bool is_cloud = false;
+	bool enable_stats = !!(pf->flags & I40E_FLAG_VEB_STATS_ENABLED);
 	int ret;
 
 	/* get a VEB from the hardware */
 	ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi->seid,
 			      veb->enabled_tc, is_default,
-			      is_cloud, &veb->seid, NULL);
+			      &veb->seid, enable_stats, NULL);
 	if (ret) {
 		dev_info(&pf->pdev->dev,
 			 "couldn't add VEB, err %s aq_err %s\n",
@@ -9947,7 +10414,7 @@
 	 * the hash
 	 */
 	if ((pf->flags & I40E_FLAG_RSS_ENABLED))
-		i40e_config_rss(pf);
+		i40e_pf_config_rss(pf);
 
 	/* fill in link information and enable LSE reporting */
 	i40e_update_link_info(&pf->hw);
@@ -9985,7 +10452,7 @@
 	    !(pf->flags & I40E_FLAG_MSIX_ENABLED)) {
 		/* one qp for PF, no queues for anything else */
 		queues_left = 0;
-		pf->rss_size = pf->num_lan_qps = 1;
+		pf->alloc_rss_size = pf->num_lan_qps = 1;
 
 		/* make sure all the fancies are disabled */
 		pf->flags &= ~(I40E_FLAG_RSS_ENABLED	|
@@ -10002,7 +10469,7 @@
 				  I40E_FLAG_FD_ATR_ENABLED |
 				  I40E_FLAG_DCB_CAPABLE))) {
 		/* one qp for PF */
-		pf->rss_size = pf->num_lan_qps = 1;
+		pf->alloc_rss_size = pf->num_lan_qps = 1;
 		queues_left -= pf->num_lan_qps;
 
 		pf->flags &= ~(I40E_FLAG_RSS_ENABLED	|
@@ -10072,8 +10539,9 @@
 		"qs_avail=%d FD SB=%d lan_qs=%d lan_tc0=%d vf=%d*%d vmdq=%d*%d, remaining=%d\n",
 		pf->hw.func_caps.num_tx_qp,
 		!!(pf->flags & I40E_FLAG_FD_SB_ENABLED),
-		pf->num_lan_qps, pf->rss_size, pf->num_req_vfs, pf->num_vf_qps,
-		pf->num_vmdq_vsis, pf->num_vmdq_qps, queues_left);
+		pf->num_lan_qps, pf->alloc_rss_size, pf->num_req_vfs,
+		pf->num_vf_qps, pf->num_vmdq_vsis, pf->num_vmdq_qps,
+		queues_left);
 #ifdef I40E_FCOE
 	dev_dbg(&pf->pdev->dev, "fcoe queues = %d\n", pf->num_fcoe_qps);
 #endif
@@ -10111,55 +10579,74 @@
 }
 
 #define INFO_STRING_LEN 255
+#define REMAIN(__x) (INFO_STRING_LEN - (__x))
 static void i40e_print_features(struct i40e_pf *pf)
 {
 	struct i40e_hw *hw = &pf->hw;
-	char *buf, *string;
+	char *buf;
+	int i;
 
-	string = kzalloc(INFO_STRING_LEN, GFP_KERNEL);
-	if (!string) {
-		dev_err(&pf->pdev->dev, "Features string allocation failed\n");
+	buf = kmalloc(INFO_STRING_LEN, GFP_KERNEL);
+	if (!buf)
 		return;
-	}
-
-	buf = string;
 
-	buf += sprintf(string, "Features: PF-id[%d] ", hw->pf_id);
+	i = snprintf(buf, INFO_STRING_LEN, "Features: PF-id[%d]", hw->pf_id);
 #ifdef CONFIG_PCI_IOV
-	buf += sprintf(buf, "VFs: %d ", pf->num_req_vfs);
+	i += snprintf(&buf[i], REMAIN(i), " VFs: %d", pf->num_req_vfs);
 #endif
-	buf += sprintf(buf, "VSIs: %d QP: %d RX: %s ",
-		       pf->hw.func_caps.num_vsis,
-		       pf->vsi[pf->lan_vsi]->num_queue_pairs,
-		       pf->flags & I40E_FLAG_RX_PS_ENABLED ? "PS" : "1BUF");
+	i += snprintf(&buf[i], REMAIN(i), " VSIs: %d QP: %d RX: %s",
+		      pf->hw.func_caps.num_vsis,
+		      pf->vsi[pf->lan_vsi]->num_queue_pairs,
+		      "1BUF");
 
 	if (pf->flags & I40E_FLAG_RSS_ENABLED)
-		buf += sprintf(buf, "RSS ");
+		i += snprintf(&buf[i], REMAIN(i), " RSS");
 	if (pf->flags & I40E_FLAG_FD_ATR_ENABLED)
-		buf += sprintf(buf, "FD_ATR ");
+		i += snprintf(&buf[i], REMAIN(i), " FD_ATR");
 	if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
-		buf += sprintf(buf, "FD_SB ");
-		buf += sprintf(buf, "NTUPLE ");
+		i += snprintf(&buf[i], REMAIN(i), " FD_SB");
+		i += snprintf(&buf[i], REMAIN(i), " NTUPLE");
 	}
 	if (pf->flags & I40E_FLAG_DCB_CAPABLE)
-		buf += sprintf(buf, "DCB ");
+		i += snprintf(&buf[i], REMAIN(i), " DCB");
 #if IS_ENABLED(CONFIG_VXLAN)
-	buf += sprintf(buf, "VxLAN ");
+	i += snprintf(&buf[i], REMAIN(i), " VxLAN");
+#endif
+#if IS_ENABLED(CONFIG_GENEVE)
+	i += snprintf(&buf[i], REMAIN(i), " Geneve");
 #endif
 	if (pf->flags & I40E_FLAG_PTP)
-		buf += sprintf(buf, "PTP ");
+		i += snprintf(&buf[i], REMAIN(i), " PTP");
 #ifdef I40E_FCOE
 	if (pf->flags & I40E_FLAG_FCOE_ENABLED)
-		buf += sprintf(buf, "FCOE ");
+		i += snprintf(&buf[i], REMAIN(i), " FCOE");
 #endif
 	if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED)
-		buf += sprintf(buf, "VEB ");
+		i += snprintf(&buf[i], REMAIN(i), " VEB");
 	else
-		buf += sprintf(buf, "VEPA ");
+		i += snprintf(&buf[i], REMAIN(i), " VEPA");
 
-	BUG_ON(buf > (string + INFO_STRING_LEN));
-	dev_info(&pf->pdev->dev, "%s\n", string);
-	kfree(string);
+	dev_info(&pf->pdev->dev, "%s\n", buf);
+	kfree(buf);
+	WARN_ON(i > INFO_STRING_LEN);
+}
+
+/**
+ * i40e_get_platform_mac_addr - get platform-specific MAC address
+ *
+ * @pdev: PCI device information struct
+ * @pf: board private structure
+ *
+ * Look up the MAC address in Open Firmware  on systems that support it,
+ * and use IDPROM on SPARC if no OF address is found. On return, the
+ * I40E_FLAG_PF_MAC will be wset in pf->flags if a platform-specific value
+ * has been selected.
+ **/
+static void i40e_get_platform_mac_addr(struct pci_dev *pdev, struct i40e_pf *pf)
+{
+	pf->flags &= ~I40E_FLAG_PF_MAC;
+	if (!eth_platform_get_mac_address(&pdev->dev, pf->hw.mac.addr))
+		pf->flags |= I40E_FLAG_PF_MAC;
 }
 
 /**
@@ -10182,7 +10669,7 @@
 	u16 wol_nvm_bits;
 	u16 link_status;
 	int err;
-	u32 len;
+	u32 val;
 	u32 i;
 	u8 set_fc_aq_fail;
 
@@ -10302,6 +10789,16 @@
 	mutex_init(&hw->aq.arq_mutex);
 
 	err = i40e_init_adminq(hw);
+	if (err) {
+		if (err == I40E_ERR_FIRMWARE_API_VERSION)
+			dev_info(&pdev->dev,
+				 "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n");
+		else
+			dev_info(&pdev->dev,
+				 "The driver for the device stopped because the device firmware failed to init. Try updating your NVM image.\n");
+
+		goto err_pf_reset;
+	}
 
 	/* provide nvm, fw, api versions */
 	dev_info(&pdev->dev, "fw %d.%d.%05d api %d.%d nvm %s\n",
@@ -10309,12 +10806,6 @@
 		 hw->aq.api_maj_ver, hw->aq.api_min_ver,
 		 i40e_nvm_version_str(hw));
 
-	if (err) {
-		dev_info(&pdev->dev,
-			 "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n");
-		goto err_pf_reset;
-	}
-
 	if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
 		dev_info(&pdev->dev,
@@ -10360,13 +10851,14 @@
 	 * Ignore error return codes because if it was already disabled via
 	 * hardware settings this will fail
 	 */
-	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
-	    (pf->hw.aq.fw_maj_ver < 4)) {
+	if (pf->flags & I40E_FLAG_STOP_FW_LLDP) {
 		dev_info(&pdev->dev, "Stopping firmware LLDP agent.\n");
 		i40e_aq_stop_lldp(hw, true, NULL);
 	}
 
 	i40e_get_mac_addr(hw, hw->mac.addr);
+	/* allow a platform config to override the HW addr */
+	i40e_get_platform_mac_addr(pdev, pf);
 	if (!is_valid_ether_addr(hw->mac.addr)) {
 		dev_info(&pdev->dev, "invalid MAC address %pM\n", hw->mac.addr);
 		err = -EIO;
@@ -10411,7 +10903,7 @@
 
 	/* NVM bit on means WoL disabled for the port */
 	i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits);
-	if ((1 << hw->port) & wol_nvm_bits || hw->partition_id != 1)
+	if (BIT (hw->port) & wol_nvm_bits || hw->partition_id != 1)
 		pf->wol_en = false;
 	else
 		pf->wol_en = true;
@@ -10434,8 +10926,8 @@
 		pf->num_alloc_vsi = pf->hw.func_caps.num_vsis;
 
 	/* Set up the *vsi struct and our local tracking of the MAIN PF vsi. */
-	len = sizeof(struct i40e_vsi *) * pf->num_alloc_vsi;
-	pf->vsi = kzalloc(len, GFP_KERNEL);
+	pf->vsi = kcalloc(pf->num_alloc_vsi, sizeof(struct i40e_vsi *),
+			  GFP_KERNEL);
 	if (!pf->vsi) {
 		err = -ENOMEM;
 		goto err_switch_setup;
@@ -10482,19 +10974,29 @@
 		}
 	}
 
-	/* driver is only interested in link up/down and module qualification
-	 * reports from firmware
+	/* The driver only wants link up/down and module qualification
+	 * reports from firmware.  Note the negative logic.
 	 */
 	err = i40e_aq_set_phy_int_mask(&pf->hw,
-				       I40E_AQ_EVENT_LINK_UPDOWN |
-				       I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
+				       ~(I40E_AQ_EVENT_LINK_UPDOWN |
+					 I40E_AQ_EVENT_MODULE_QUAL_FAIL), NULL);
 	if (err)
 		dev_info(&pf->pdev->dev, "set phy mask fail, err %s aq_err %s\n",
 			 i40e_stat_str(&pf->hw, err),
 			 i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
 
-	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
-	    (pf->hw.aq.fw_maj_ver < 4)) {
+	/* Reconfigure hardware for allowing smaller MSS in the case
+	 * of TSO, so that we avoid the MDD being fired and causing
+	 * a reset in the case of small MSS+TSO.
+	 */
+	val = rd32(hw, I40E_REG_MSS);
+	if ((val & I40E_REG_MSS_MIN_MASK) > I40E_64BYTE_MSS) {
+		val &= ~I40E_REG_MSS_MIN_MASK;
+		val |= I40E_64BYTE_MSS;
+		wr32(hw, I40E_REG_MSS, val);
+	}
+
+	if (pf->flags & I40E_FLAG_RESTART_AUTONEG) {
 		msleep(75);
 		err = i40e_aq_set_link_restart_an(&pf->hw, true, NULL);
 		if (err)
@@ -10528,8 +11030,6 @@
 	if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
 	    (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
 	    !test_bit(__I40E_BAD_EEPROM, &pf->state)) {
-		u32 val;
-
 		/* disable link interrupts for VFs */
 		val = rd32(hw, I40E_PFGEN_PORTMDIO_NUM);
 		val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
@@ -10640,6 +11140,10 @@
 	i40e_add_filter_to_drop_tx_flow_control_frames(&pf->hw,
 						       pf->main_vsi_seid);
 
+	if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) ||
+	    (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4))
+		pf->flags |= I40E_FLAG_HAVE_10GBASET_PHY;
+
 	/* print a string summarizing features */
 	i40e_print_features(pf);
 
@@ -10696,10 +11200,11 @@
 	i40e_ptp_stop(pf);
 
 	/* Disable RSS in hw */
-	wr32(hw, I40E_PFQF_HENA(0), 0);
-	wr32(hw, I40E_PFQF_HENA(1), 0);
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), 0);
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), 0);
 
 	/* no more scheduling of any task */
+	set_bit(__I40E_SUSPENDED, &pf->state);
 	set_bit(__I40E_DOWN, &pf->state);
 	del_timer_sync(&pf->service_timer);
 	cancel_work_sync(&pf->service_task);
@@ -10730,8 +11235,8 @@
 		i40e_vsi_release(pf->vsi[pf->lan_vsi]);
 
 	/* shutdown and destroy the HMC */
-	if (pf->hw.hmc.hmc_obj) {
-		ret_code = i40e_shutdown_lan_hmc(&pf->hw);
+	if (hw->hmc.hmc_obj) {
+		ret_code = i40e_shutdown_lan_hmc(hw);
 		if (ret_code)
 			dev_warn(&pdev->dev,
 				 "Failed to destroy the HMC resources: %d\n",
@@ -10739,7 +11244,7 @@
 	}
 
 	/* shutdown the adminq */
-	ret_code = i40e_shutdown_adminq(&pf->hw);
+	ret_code = i40e_shutdown_adminq(hw);
 	if (ret_code)
 		dev_warn(&pdev->dev,
 			 "Failed to destroy the Admin Queue resources: %d\n",
@@ -10750,6 +11255,7 @@
 	mutex_destroy(&hw->aq.asq_mutex);
 
 	/* Clear all dynamic memory lists of rings, q_vectors, and VSIs */
+	rtnl_lock();
 	i40e_clear_interrupt_scheme(pf);
 	for (i = 0; i < pf->num_alloc_vsi; i++) {
 		if (pf->vsi[i]) {
@@ -10758,6 +11264,7 @@
 			pf->vsi[i] = NULL;
 		}
 	}
+	rtnl_unlock();
 
 	for (i = 0; i < I40E_MAX_VEB; i++) {
 		kfree(pf->veb[i]);
@@ -10767,7 +11274,7 @@
 	kfree(pf->qp_pile);
 	kfree(pf->vsi);
 
-	iounmap(pf->hw.hw_addr);
+	iounmap(hw->hw_addr);
 	kfree(pf);
 	pci_release_selected_regions(pdev,
 				     pci_select_bars(pdev, IORESOURCE_MEM));
@@ -10791,6 +11298,12 @@
 
 	dev_info(&pdev->dev, "%s: error %d\n", __func__, error);
 
+	if (!pf) {
+		dev_info(&pdev->dev,
+			 "Cannot recover - error happened during device probe\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
 	/* shutdown all operations */
 	if (!test_bit(__I40E_SUSPENDED, &pf->state)) {
 		rtnl_lock();
@@ -10898,7 +11411,13 @@
 	wr32(hw, I40E_PFPM_WUFC,
 	     (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
 
+	/* Since we're going to destroy queues during the
+	 * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this
+	 * whole section
+	 */
+	rtnl_lock();
 	i40e_clear_interrupt_scheme(pf);
+	rtnl_unlock();
 
 	if (system_state == SYSTEM_POWER_OFF) {
 		pci_wake_from_d3(pdev, pf->wol_en);
@@ -11002,6 +11521,16 @@
 		i40e_driver_string, i40e_driver_version_str);
 	pr_info("%s: %s\n", i40e_driver_name, i40e_copyright);
 
+	/* we will see if single thread per module is enough for now,
+	 * it can't be any worse than using the system workqueue which
+	 * was already single threaded
+	 */
+	i40e_wq = create_singlethread_workqueue(i40e_driver_name);
+	if (!i40e_wq) {
+		pr_err("%s: Failed to create workqueue\n", i40e_driver_name);
+		return -ENOMEM;
+	}
+
 	i40e_dbg_init();
 	return pci_register_driver(&i40e_driver);
 }
@@ -11016,6 +11545,7 @@
 static void __exit i40e_exit_module(void)
 {
 	pci_unregister_driver(&i40e_driver);
+	destroy_workqueue(i40e_wq);
 	i40e_dbg_exit();
 }
 module_exit(i40e_exit_module);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_nvm.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_nvm.c
@@ -266,7 +266,7 @@
  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
  * @data: word read from the Shadow RAM
  *
- * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
+ * Reads one 16 bit word from the Shadow RAM using the AdminQ
  **/
 static i40e_status i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
 					 u16 *data)
@@ -280,27 +280,49 @@
 }
 
 /**
- * i40e_read_nvm_word - Reads Shadow RAM
+ * __i40e_read_nvm_word - Reads nvm word, assumes called does the locking
  * @hw: pointer to the HW structure
  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
  * @data: word read from the Shadow RAM
  *
- * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
+ * Reads one 16 bit word from the Shadow RAM.
+ *
+ * Do not use this function except in cases where the nvm lock is already
+ * taken via i40e_acquire_nvm().
+ **/
+static i40e_status __i40e_read_nvm_word(struct i40e_hw *hw,
+					u16 offset, u16 *data)
+{
+	i40e_status ret_code = 0;
+
+	if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
+		ret_code = i40e_read_nvm_word_aq(hw, offset, data);
+	else
+		ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
+	return ret_code;
+}
+
+/**
+ * i40e_read_nvm_word - Reads nvm word and acquire lock if necessary
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
+ * @data: word read from the Shadow RAM
+ *
+ * Reads one 16 bit word from the Shadow RAM.
  **/
 i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
 			       u16 *data)
 {
-	enum i40e_status_code ret_code = 0;
+	i40e_status ret_code = 0;
+
+	ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+	if (ret_code)
+		return ret_code;
+
+	ret_code = __i40e_read_nvm_word(hw, offset, data);
+
+	i40e_release_nvm(hw);
 
-	if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
-		ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
-		if (!ret_code) {
-			ret_code = i40e_read_nvm_word_aq(hw, offset, data);
-			i40e_release_nvm(hw);
-		}
-	} else {
-		ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
-	}
 	return ret_code;
 }
 
@@ -393,31 +415,25 @@
 }
 
 /**
- * i40e_read_nvm_buffer - Reads Shadow RAM buffer
+ * __i40e_read_nvm_buffer - Reads nvm buffer, caller must acquire lock
  * @hw: pointer to the HW structure
  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
  * @words: (in) number of words to read; (out) number of words actually read
  * @data: words read from the Shadow RAM
  *
  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
- * method. The buffer read is preceded by the NVM ownership take
- * and followed by the release.
+ * method.
  **/
-i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
-				 u16 *words, u16 *data)
+static i40e_status __i40e_read_nvm_buffer(struct i40e_hw *hw,
+					  u16 offset, u16 *words,
+					  u16 *data)
 {
-	enum i40e_status_code ret_code = 0;
+	i40e_status ret_code = 0;
 
-	if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
-		ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
-		if (!ret_code) {
-			ret_code = i40e_read_nvm_buffer_aq(hw, offset, words,
-							   data);
-			i40e_release_nvm(hw);
-		}
-	} else {
+	if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
+		ret_code = i40e_read_nvm_buffer_aq(hw, offset, words, data);
+	else
 		ret_code = i40e_read_nvm_buffer_srctl(hw, offset, words, data);
-	}
 	return ret_code;
 }
 
@@ -499,15 +515,15 @@
 	data = (u16 *)vmem.va;
 
 	/* read pointer to VPD area */
-	ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
+	ret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
 	if (ret_code) {
 		ret_code = I40E_ERR_NVM_CHECKSUM;
 		goto i40e_calc_nvm_checksum_exit;
 	}
 
 	/* read pointer to PCIe Alt Auto-load module */
-	ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
-				      &pcie_alt_module);
+	ret_code = __i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
+					&pcie_alt_module);
 	if (ret_code) {
 		ret_code = I40E_ERR_NVM_CHECKSUM;
 		goto i40e_calc_nvm_checksum_exit;
@@ -521,7 +537,7 @@
 		if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {
 			u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;
 
-			ret_code = i40e_read_nvm_buffer(hw, i, &words, data);
+			ret_code = __i40e_read_nvm_buffer(hw, i, &words, data);
 			if (ret_code) {
 				ret_code = I40E_ERR_NVM_CHECKSUM;
 				goto i40e_calc_nvm_checksum_exit;
@@ -593,14 +609,19 @@
 	u16 checksum_sr = 0;
 	u16 checksum_local = 0;
 
+	/* We must acquire the NVM lock in order to correctly synchronize the
+	 * NVM accesses across multiple PFs. Without doing so it is possible
+	 * for one of the PFs to read invalid data potentially indicating that
+	 * the checksum is invalid.
+	 */
+	ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+	if (ret_code)
+		return ret_code;
 	ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
+	__i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
+	i40e_release_nvm(hw);
 	if (ret_code)
-		goto i40e_validate_nvm_checksum_exit;
-
-	/* Do not use i40e_read_nvm_word() because we do not want to take
-	 * the synchronization semaphores twice here.
-	 */
-	i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
+		return ret_code;
 
 	/* Verify read checksum from EEPROM is the same as
 	 * calculated checksum
@@ -612,7 +633,6 @@
 	if (checksum)
 		*checksum = checksum_local;
 
-i40e_validate_nvm_checksum_exit:
 	return ret_code;
 }
 
@@ -693,10 +713,11 @@
 	/* early check for status command and debug msgs */
 	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
 
-	i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d\n",
+	i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d cmd 0x%08x config 0x%08x offset 0x%08x data_size 0x%08x\n",
 		   i40e_nvm_update_state_str[upd_cmd],
 		   hw->nvmupd_state,
-		   hw->aq.nvm_release_on_done);
+		   hw->aq.nvm_release_on_done,
+		   cmd->command, cmd->config, cmd->offset, cmd->data_size);
 
 	if (upd_cmd == I40E_NVMUPD_INVALID) {
 		*perrno = -EFAULT;
@@ -958,6 +979,7 @@
 		break;
 
 	case I40E_NVMUPD_CSUM_CON:
+		/* Assumes the caller has acquired the nvm */
 		status = i40e_update_nvm_checksum(hw);
 		if (status) {
 			*perrno = hw->aq.asq_last_status ?
@@ -971,6 +993,7 @@
 		break;
 
 	case I40E_NVMUPD_CSUM_LCB:
+		/* Assumes the caller has acquired the nvm */
 		status = i40e_update_nvm_checksum(hw);
 		if (status) {
 			*perrno = hw->aq.asq_last_status ?
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -74,6 +74,12 @@
 
 u32 i40e_led_get(struct i40e_hw *hw);
 void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink);
+i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on,
+			     u16 led_addr, u32 mode);
+i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
+			     u16 *val);
+i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
+				    u32 time, u32 interval);
 
 /* admin send queue commands */
 
@@ -127,6 +133,9 @@
 		u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_set_vsi_multicast_promiscuous(struct i40e_hw *hw,
 		u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_vsi_vlan_promisc(struct i40e_hw *hw,
+				u16 seid, bool enable,
+				struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw,
 				struct i40e_vsi_context *vsi_ctx,
 				struct i40e_asq_cmd_details *cmd_details);
@@ -135,8 +144,8 @@
 				struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
 				u16 downlink_seid, u8 enabled_tc,
-				bool default_port, bool enable_l2_filtering,
-				u16 *pveb_seid,
+				bool default_port, u16 *pveb_seid,
+				bool enable_stats,
 				struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_get_veb_parameters(struct i40e_hw *hw,
 				u16 veb_seid, u16 *switch_id, bool *floating,
@@ -149,6 +158,15 @@
 i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 vsi_id,
 			struct i40e_aqc_remove_macvlan_element_data *mv_list,
 			u16 count, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_add_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
+			u16 rule_type, u16 dest_vsi, u16 count, __le16 *mr_list,
+			struct i40e_asq_cmd_details *cmd_details,
+			u16 *rule_id, u16 *rules_used, u16 *rules_free);
+i40e_status i40e_aq_delete_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
+			u16 rule_type, u16 rule_id, u16 count, __le16 *mr_list,
+			struct i40e_asq_cmd_details *cmd_details,
+			u16 *rules_used, u16 *rules_free);
+
 i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid,
 				u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen,
 				struct i40e_asq_cmd_details *cmd_details);
@@ -282,8 +300,6 @@
 void i40e_release_nvm(struct i40e_hw *hw);
 i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
 					 u16 *data);
-i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
-					   u16 *words, u16 *data);
 i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw);
 i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
 						 u16 *checksum);
@@ -324,4 +340,19 @@
 			       struct i40e_asq_cmd_details *cmd_details);
 void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
 						    u16 vsi_seid);
+i40e_status i40e_aq_rx_ctl_read_register(struct i40e_hw *hw,
+				u32 reg_addr, u32 *reg_val,
+				struct i40e_asq_cmd_details *cmd_details);
+u32 i40e_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr);
+i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
+				u32 reg_addr, u32 reg_val,
+				struct i40e_asq_cmd_details *cmd_details);
+void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
+i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page,
+				   u16 reg, u8 phy_addr, u16 *value);
+i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page,
+				    u16 reg, u8 phy_addr, u16 value);
+u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
+i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
+				    u32 time, u32 interval);
 #endif /* _I40E_PROTOTYPE_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -605,7 +605,8 @@
 	if (!IS_ERR_OR_NULL(pf->ptp_clock))
 		return 0;
 
-	strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name));
+	strncpy(pf->ptp_caps.name, i40e_driver_name,
+		sizeof(pf->ptp_caps.name) - 1);
 	pf->ptp_caps.owner = THIS_MODULE;
 	pf->ptp_caps.max_adj = 999999999;
 	pf->ptp_caps.n_ext_ts = 0;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_register.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_register.h
@@ -2045,6 +2045,14 @@
 #define I40E_PRTPM_TLPIC 0x001E43C0 /* Reset: GLOBR */
 #define I40E_PRTPM_TLPIC_ETLPIC_SHIFT 0
 #define I40E_PRTPM_TLPIC_ETLPIC_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_TLPIC_ETLPIC_SHIFT)
+#define I40E_GL_PRS_FVBM(_i) (0x00269760 + ((_i) * 4)) /* _i=0...3 */ /* Reset: CORER */
+#define I40E_GL_PRS_FVBM_MAX_INDEX 3
+#define I40E_GL_PRS_FVBM_FV_BYTE_INDX_SHIFT 0
+#define I40E_GL_PRS_FVBM_FV_BYTE_INDX_MASK I40E_MASK(0x7F, I40E_GL_PRS_FVBM_FV_BYTE_INDX_SHIFT)
+#define I40E_GL_PRS_FVBM_RULE_BUS_INDX_SHIFT 8
+#define I40E_GL_PRS_FVBM_RULE_BUS_INDX_MASK I40E_MASK(0x3F, I40E_GL_PRS_FVBM_RULE_BUS_INDX_SHIFT)
+#define I40E_GL_PRS_FVBM_MSK_ENA_SHIFT 31
+#define I40E_GL_PRS_FVBM_MSK_ENA_MASK I40E_MASK(0x1, I40E_GL_PRS_FVBM_MSK_ENA_SHIFT)
 #define I40E_GLRPB_DPSS 0x000AC828 /* Reset: CORER */
 #define I40E_GLRPB_DPSS_DPS_TCN_SHIFT 0
 #define I40E_GLRPB_DPSS_DPS_TCN_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_DPSS_DPS_TCN_SHIFT)
@@ -2216,6 +2224,14 @@
 #define I40E_PRTQF_FD_FLXINSET_MAX_INDEX 63
 #define I40E_PRTQF_FD_FLXINSET_INSET_SHIFT 0
 #define I40E_PRTQF_FD_FLXINSET_INSET_MASK I40E_MASK(0xFF, I40E_PRTQF_FD_FLXINSET_INSET_SHIFT)
+#define I40E_PRTQF_FD_INSET(_i, _j) (0x00250000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */
+#define I40E_PRTQF_FD_INSET_MAX_INDEX 63
+#define I40E_PRTQF_FD_INSET_INSET_SHIFT 0
+#define I40E_PRTQF_FD_INSET_INSET_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTQF_FD_INSET_INSET_SHIFT)
+#define I40E_PRTQF_FD_INSET(_i, _j) (0x00250000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */
+#define I40E_PRTQF_FD_INSET_MAX_INDEX 63
+#define I40E_PRTQF_FD_INSET_INSET_SHIFT 0
+#define I40E_PRTQF_FD_INSET_INSET_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTQF_FD_INSET_INSET_SHIFT)
 #define I40E_PRTQF_FD_MSK(_i, _j) (0x00252000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */
 #define I40E_PRTQF_FD_MSK_MAX_INDEX 63
 #define I40E_PRTQF_FD_MSK_MASK_SHIFT 0
@@ -5155,6 +5171,38 @@
 #define I40E_GLQF_FD_PCTYPES_MAX_INDEX 63
 #define I40E_GLQF_FD_PCTYPES_FD_PCTYPE_SHIFT 0
 #define I40E_GLQF_FD_PCTYPES_FD_PCTYPE_MASK I40E_MASK(0x3F, I40E_GLQF_FD_PCTYPES_FD_PCTYPE_SHIFT)
+#define I40E_GLQF_FD_MSK(_i, _j) (0x00267200 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */
+#define I40E_GLQF_FD_MSK_MAX_INDEX 1
+#define I40E_GLQF_FD_MSK_MASK_SHIFT 0
+#define I40E_GLQF_FD_MSK_MASK_MASK I40E_MASK(0xFFFF, I40E_GLQF_FD_MSK_MASK_SHIFT)
+#define I40E_GLQF_FD_MSK_OFFSET_SHIFT 16
+#define I40E_GLQF_FD_MSK_OFFSET_MASK I40E_MASK(0x3F, I40E_GLQF_FD_MSK_OFFSET_SHIFT)
+#define I40E_GLQF_HASH_INSET(_i, _j) (0x00267600 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */
+#define I40E_GLQF_HASH_INSET_MAX_INDEX 1
+#define I40E_GLQF_HASH_INSET_INSET_SHIFT 0
+#define I40E_GLQF_HASH_INSET_INSET_MASK I40E_MASK(0xFFFFFFFF, I40E_GLQF_HASH_INSET_INSET_SHIFT)
+#define I40E_GLQF_HASH_MSK(_i, _j) (0x00267A00 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */
+#define I40E_GLQF_HASH_MSK_MAX_INDEX 1
+#define I40E_GLQF_HASH_MSK_MASK_SHIFT 0
+#define I40E_GLQF_HASH_MSK_MASK_MASK I40E_MASK(0xFFFF, I40E_GLQF_HASH_MSK_MASK_SHIFT)
+#define I40E_GLQF_HASH_MSK_OFFSET_SHIFT 16
+#define I40E_GLQF_HASH_MSK_OFFSET_MASK I40E_MASK(0x3F, I40E_GLQF_HASH_MSK_OFFSET_SHIFT)
+#define I40E_GLQF_ORT(_i) (0x00268900 + ((_i) * 4)) /* _i=0...63 */ /* Reset: CORER */
+#define I40E_GLQF_ORT_MAX_INDEX 63
+#define I40E_GLQF_ORT_PIT_INDX_SHIFT 0
+#define I40E_GLQF_ORT_PIT_INDX_MASK I40E_MASK(0x1F, I40E_GLQF_ORT_PIT_INDX_SHIFT)
+#define I40E_GLQF_ORT_FIELD_CNT_SHIFT 5
+#define I40E_GLQF_ORT_FIELD_CNT_MASK I40E_MASK(0x3, I40E_GLQF_ORT_FIELD_CNT_SHIFT)
+#define I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT 7
+#define I40E_GLQF_ORT_FLX_PAYLOAD_MASK I40E_MASK(0x1, I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT)
+#define I40E_GLQF_PIT(_i) (0x00268C80 + ((_i) * 4)) /* _i=0...23 */ /* Reset: CORER */
+#define I40E_GLQF_PIT_MAX_INDEX 23
+#define I40E_GLQF_PIT_SOURCE_OFF_SHIFT 0
+#define I40E_GLQF_PIT_SOURCE_OFF_MASK I40E_MASK(0x1F, I40E_GLQF_PIT_SOURCE_OFF_SHIFT)
+#define I40E_GLQF_PIT_FSIZE_SHIFT 5
+#define I40E_GLQF_PIT_FSIZE_MASK I40E_MASK(0x1F, I40E_GLQF_PIT_FSIZE_SHIFT)
+#define I40E_GLQF_PIT_DEST_OFF_SHIFT 10
+#define I40E_GLQF_PIT_DEST_OFF_MASK I40E_MASK(0x3F, I40E_GLQF_PIT_DEST_OFF_SHIFT)
 #define I40E_GLQF_FDEVICTENA(_i) (0x00270384 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */
 #define I40E_GLQF_FDEVICTENA_MAX_INDEX 1
 #define I40E_GLQF_FDEVICTENA_GLQF_FDEVICTENA_SHIFT 0
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -235,6 +235,9 @@
 				 "Filter deleted for PCTYPE %d loc = %d\n",
 				 fd_data->pctype, fd_data->fd_id);
 	}
+	if (err)
+		kfree(raw_packet);
+
 	return err ? -EOPNOTSUPP : 0;
 }
 
@@ -312,6 +315,9 @@
 				 fd_data->pctype, fd_data->fd_id);
 	}
 
+	if (err)
+		kfree(raw_packet);
+
 	return err ? -EOPNOTSUPP : 0;
 }
 
@@ -322,7 +328,7 @@
  * @fd_data: the flow director data required for the FDir descriptor
  * @add: true adds a filter, false removes it
  *
- * Always returns -EOPNOTSUPP
+ * Returns 0 if the filters were successfully added or removed
  **/
 static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
 				    struct i40e_fdir_filter *fd_data,
@@ -387,6 +393,9 @@
 		}
 	}
 
+	if (err)
+		kfree(raw_packet);
+
 	return err ? -EOPNOTSUPP : 0;
 }
 
@@ -506,9 +515,6 @@
 				pf->auto_disable_flags |=
 							I40E_FLAG_FD_SB_ENABLED;
 			}
-		} else {
-			dev_info(&pdev->dev,
-				"FD filter programming failed due to incorrect filter parameters\n");
 		}
 	} else if (error == BIT(I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {
 		if (I40E_DEBUG_FD & pf->hw.debug_mask)
@@ -526,11 +532,7 @@
 					    struct i40e_tx_buffer *tx_buffer)
 {
 	if (tx_buffer->skb) {
-		if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
-			kfree(tx_buffer->raw_buf);
-		else
-			dev_kfree_skb_any(tx_buffer->skb);
-
+		dev_kfree_skb_any(tx_buffer->skb);
 		if (dma_unmap_len(tx_buffer, len))
 			dma_unmap_single(ring->dev,
 					 dma_unmap_addr(tx_buffer, dma),
@@ -542,6 +544,10 @@
 			       dma_unmap_len(tx_buffer, len),
 			       DMA_TO_DEVICE);
 	}
+
+	if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
+		kfree(tx_buffer->raw_buf);
+
 	tx_buffer->next_to_watch = NULL;
 	tx_buffer->skb = NULL;
 	dma_unmap_len_set(tx_buffer, len, 0);
@@ -604,15 +610,19 @@
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
  * @tx_ring: the ring of descriptors
+ * @in_sw: is tx_pending being checked in SW or HW
  *
  * Since there is no access to the ring head register
  * in XL710, we need to use our local copies
  **/
-u32 i40e_get_tx_pending(struct i40e_ring *ring)
+u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw)
 {
 	u32 head, tail;
 
-	head = i40e_get_head(ring);
+	if (!in_sw)
+		head = i40e_get_head(ring);
+	else
+		head = ring->next_to_clean;
 	tail = readl(ring->tail);
 
 	if (head != tail)
@@ -654,7 +664,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		read_barrier_depends();
+		smp_rmb();
 
 		/* we have caught up to head, no work left to do */
 		if (tx_head == tx_desc)
@@ -735,7 +745,7 @@
 		 * them to be written back in case we stay in NAPI.
 		 * In this mode on X722 we do not enable Interrupt.
 		 */
-		j = i40e_get_tx_pending(tx_ring);
+		j = i40e_get_tx_pending(tx_ring, false);
 
 		if (budget &&
 		    ((j / (WB_STRIDE + 1)) == 0) && (j != 0) &&
@@ -768,29 +778,48 @@
 }
 
 /**
- * i40e_force_wb - Arm hardware to do a wb on noncache aligned descriptors
+ * i40e_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled
  * @vsi: the VSI we care about
- * @q_vector: the vector  on which to force writeback
+ * @q_vector: the vector on which to enable writeback
  *
  **/
-void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi,
+				  struct i40e_q_vector *q_vector)
 {
 	u16 flags = q_vector->tx.ring[0].flags;
+	u32 val;
 
-	if (flags & I40E_TXR_FLAGS_WB_ON_ITR) {
-		u32 val;
+	if (!(flags & I40E_TXR_FLAGS_WB_ON_ITR))
+		return;
 
-		if (q_vector->arm_wb_state)
-			return;
+	if (q_vector->arm_wb_state)
+		return;
 
-		val = I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK;
+	if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
+		val = I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK |
+		      I40E_PFINT_DYN_CTLN_ITR_INDX_MASK; /* set noitr */
 
 		wr32(&vsi->back->hw,
-		     I40E_PFINT_DYN_CTLN(q_vector->v_idx +
-					 vsi->base_vector - 1),
+		     I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1),
 		     val);
-		q_vector->arm_wb_state = true;
-	} else if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
+	} else {
+		val = I40E_PFINT_DYN_CTL0_WB_ON_ITR_MASK |
+		      I40E_PFINT_DYN_CTL0_ITR_INDX_MASK; /* set noitr */
+
+		wr32(&vsi->back->hw, I40E_PFINT_DYN_CTL0, val);
+	}
+	q_vector->arm_wb_state = true;
+}
+
+/**
+ * i40e_force_wb - Issue SW Interrupt so HW does a wb
+ * @vsi: the VSI we care about
+ * @q_vector: the vector  on which to force writeback
+ *
+ **/
+void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+{
+	if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
 		u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
 			  I40E_PFINT_DYN_CTLN_ITR_INDX_MASK | /* set noitr */
 			  I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK |
@@ -1001,22 +1030,6 @@
 	if (!rx_ring->rx_bi)
 		return;
 
-	if (ring_is_ps_enabled(rx_ring)) {
-		int bufsz = ALIGN(rx_ring->rx_hdr_len, 256) * rx_ring->count;
-
-		rx_bi = &rx_ring->rx_bi[0];
-		if (rx_bi->hdr_buf) {
-			dma_free_coherent(dev,
-					  bufsz,
-					  rx_bi->hdr_buf,
-					  rx_bi->dma);
-			for (i = 0; i < rx_ring->count; i++) {
-				rx_bi = &rx_ring->rx_bi[i];
-				rx_bi->dma = 0;
-				rx_bi->hdr_buf = NULL;
-			}
-		}
-	}
 	/* Free all the Rx ring sk_buffs */
 	for (i = 0; i < rx_ring->count; i++) {
 		rx_bi = &rx_ring->rx_bi[i];
@@ -1035,7 +1048,7 @@
 			if (rx_bi->page_dma) {
 				dma_unmap_page(dev,
 					       rx_bi->page_dma,
-					       PAGE_SIZE / 2,
+					       PAGE_SIZE,
 					       DMA_FROM_DEVICE);
 				rx_bi->page_dma = 0;
 			}
@@ -1170,16 +1183,19 @@
  * i40e_alloc_rx_buffers_ps - Replace used receive buffers; packet split
  * @rx_ring: ring to place buffers on
  * @cleaned_count: number of buffers to replace
+ *
+ * Returns true if any errors on allocation
  **/
-void i40e_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool i40e_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
 {
 	u16 i = rx_ring->next_to_use;
 	union i40e_rx_desc *rx_desc;
 	struct i40e_rx_buffer *bi;
+	const int current_node = numa_node_id();
 
 	/* do nothing if no valid netdev defined */
 	if (!rx_ring->netdev || !cleaned_count)
-		return;
+		return false;
 
 	while (cleaned_count--) {
 		rx_desc = I40E_RX_DESC(rx_ring, i);
@@ -1187,56 +1203,79 @@
 
 		if (bi->skb) /* desc is in use */
 			goto no_buffers;
+
+	/* If we've been moved to a different NUMA node, release the
+	 * page so we can get a new one on the current node.
+	 */
+		if (bi->page &&  page_to_nid(bi->page) != current_node) {
+			dma_unmap_page(rx_ring->dev,
+				       bi->page_dma,
+				       PAGE_SIZE,
+				       DMA_FROM_DEVICE);
+			__free_page(bi->page);
+			bi->page = NULL;
+			bi->page_dma = 0;
+			rx_ring->rx_stats.realloc_count++;
+		} else if (bi->page) {
+			rx_ring->rx_stats.page_reuse_count++;
+		}
+
 		if (!bi->page) {
 			bi->page = alloc_page(GFP_ATOMIC);
 			if (!bi->page) {
 				rx_ring->rx_stats.alloc_page_failed++;
 				goto no_buffers;
 			}
-		}
-
-		if (!bi->page_dma) {
-			/* use a half page if we're re-using */
-			bi->page_offset ^= PAGE_SIZE / 2;
 			bi->page_dma = dma_map_page(rx_ring->dev,
 						    bi->page,
-						    bi->page_offset,
-						    PAGE_SIZE / 2,
+						    0,
+						    PAGE_SIZE,
 						    DMA_FROM_DEVICE);
-			if (dma_mapping_error(rx_ring->dev,
-					      bi->page_dma)) {
+			if (dma_mapping_error(rx_ring->dev, bi->page_dma)) {
 				rx_ring->rx_stats.alloc_page_failed++;
+				__free_page(bi->page);
+				bi->page = NULL;
 				bi->page_dma = 0;
+				bi->page_offset = 0;
 				goto no_buffers;
 			}
+			bi->page_offset = 0;
 		}
 
-		dma_sync_single_range_for_device(rx_ring->dev,
-						 bi->dma,
-						 0,
-						 rx_ring->rx_hdr_len,
-						 DMA_FROM_DEVICE);
 		/* Refresh the desc even if buffer_addrs didn't change
 		 * because each write-back erases this info.
 		 */
-		rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+		rx_desc->read.pkt_addr =
+				cpu_to_le64(bi->page_dma + bi->page_offset);
 		rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
 		i++;
 		if (i == rx_ring->count)
 			i = 0;
 	}
 
+	if (rx_ring->next_to_use != i)
+		i40e_release_rx_desc(rx_ring, i);
+
+	return false;
+
 no_buffers:
 	if (rx_ring->next_to_use != i)
 		i40e_release_rx_desc(rx_ring, i);
+
+	/* make sure to come back via polling to try again after
+	 * allocation failure
+	 */
+	return true;
 }
 
 /**
  * i40e_alloc_rx_buffers_1buf - Replace used receive buffers; single buffer
  * @rx_ring: ring to place buffers on
  * @cleaned_count: number of buffers to replace
+ *
+ * Returns true if any errors on allocation
  **/
-void i40e_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool i40e_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
 {
 	u16 i = rx_ring->next_to_use;
 	union i40e_rx_desc *rx_desc;
@@ -1245,7 +1284,7 @@
 
 	/* do nothing if no valid netdev defined */
 	if (!rx_ring->netdev || !cleaned_count)
-		return;
+		return false;
 
 	while (cleaned_count--) {
 		rx_desc = I40E_RX_DESC(rx_ring, i);
@@ -1253,8 +1292,10 @@
 		skb = bi->skb;
 
 		if (!skb) {
-			skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-							rx_ring->rx_buf_len);
+			skb = __netdev_alloc_skb_ip_align(rx_ring->netdev,
+							  rx_ring->rx_buf_len,
+							  GFP_ATOMIC |
+							  __GFP_NOWARN);
 			if (!skb) {
 				rx_ring->rx_stats.alloc_buff_failed++;
 				goto no_buffers;
@@ -1272,6 +1313,8 @@
 			if (dma_mapping_error(rx_ring->dev, bi->dma)) {
 				rx_ring->rx_stats.alloc_buff_failed++;
 				bi->dma = 0;
+				dev_kfree_skb(bi->skb);
+				bi->skb = NULL;
 				goto no_buffers;
 			}
 		}
@@ -1283,9 +1326,19 @@
 			i = 0;
 	}
 
+	if (rx_ring->next_to_use != i)
+		i40e_release_rx_desc(rx_ring, i);
+
+	return false;
+
 no_buffers:
 	if (rx_ring->next_to_use != i)
 		i40e_release_rx_desc(rx_ring, i);
+
+	/* make sure to come back via polling to try again after
+	 * allocation failure
+	 */
+	return true;
 }
 
 /**
@@ -1320,16 +1373,7 @@
 				    u16 rx_ptype)
 {
 	struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype);
-	bool ipv4 = false, ipv6 = false;
-	bool ipv4_tunnel, ipv6_tunnel;
-	__wsum rx_udp_csum;
-	struct iphdr *iph;
-	__sum16 csum;
-
-	ipv4_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
-		     (rx_ptype <= I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
-	ipv6_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
-		     (rx_ptype <= I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
+	bool ipv4, ipv6, ipv4_tunnel, ipv6_tunnel;
 
 	skb->ip_summed = CHECKSUM_NONE;
 
@@ -1345,12 +1389,10 @@
 	if (!(decoded.known && decoded.outer_ip))
 		return;
 
-	if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
-	    decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4)
-		ipv4 = true;
-	else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
-		 decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6)
-		ipv6 = true;
+	ipv4 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
+	       (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4);
+	ipv6 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
+	       (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6);
 
 	if (ipv4 &&
 	    (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) |
@@ -1374,37 +1416,17 @@
 	if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT))
 		return;
 
-	/* If VXLAN traffic has an outer UDPv4 checksum we need to check
-	 * it in the driver, hardware does not do it for us.
-	 * Since L3L4P bit was set we assume a valid IHL value (>=5)
-	 * so the total length of IPv4 header is IHL*4 bytes
-	 * The UDP_0 bit *may* bet set if the *inner* header is UDP
-	 */
-	if (!(vsi->back->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE) &&
-	    (ipv4_tunnel)) {
-		skb->transport_header = skb->mac_header +
-					sizeof(struct ethhdr) +
-					(ip_hdr(skb)->ihl * 4);
-
-		/* Add 4 bytes for VLAN tagged packets */
-		skb->transport_header += (skb->protocol == htons(ETH_P_8021Q) ||
-					  skb->protocol == htons(ETH_P_8021AD))
-					  ? VLAN_HLEN : 0;
-
-		if ((ip_hdr(skb)->protocol == IPPROTO_UDP) &&
-		    (udp_hdr(skb)->check != 0)) {
-			rx_udp_csum = udp_csum(skb);
-			iph = ip_hdr(skb);
-			csum = csum_tcpudp_magic(
-					iph->saddr, iph->daddr,
-					(skb->len - skb_transport_offset(skb)),
-					IPPROTO_UDP, rx_udp_csum);
-
-			if (udp_hdr(skb)->check != csum)
-				goto checksum_fail;
+	/* The hardware supported by this driver does not validate outer
+	 * checksums for tunneled VXLAN or GENEVE frames.  I don't agree
+	 * with it but the specification states that you "MAY validate", it
+	 * doesn't make it a hard requirement so if we have validated the
+	 * inner checksum report CHECKSUM_UNNECESSARY.
+	 */
 
-		} /* else its GRE and so no outer UDP header */
-	}
+	ipv4_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
+		     (rx_ptype <= I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
+	ipv6_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
+		     (rx_ptype <= I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
 
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
 	skb->csum_level = ipv4_tunnel || ipv6_tunnel;
@@ -1416,31 +1438,12 @@
 }
 
 /**
- * i40e_rx_hash - returns the hash value from the Rx descriptor
- * @ring: descriptor ring
- * @rx_desc: specific descriptor
- **/
-static inline u32 i40e_rx_hash(struct i40e_ring *ring,
-			       union i40e_rx_desc *rx_desc)
-{
-	const __le64 rss_mask =
-		cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
-			    I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
-
-	if ((ring->netdev->features & NETIF_F_RXHASH) &&
-	    (rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask)
-		return le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
-	else
-		return 0;
-}
-
-/**
- * i40e_ptype_to_hash - get a hash type
+ * i40e_ptype_to_htype - get a hash type
  * @ptype: the ptype value from the descriptor
  *
  * Returns a hash type to be used by skb_set_hash
  **/
-static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+static inline enum pkt_hash_types i40e_ptype_to_htype(u8 ptype)
 {
 	struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
 
@@ -1458,195 +1461,27 @@
 }
 
 /**
- * i40e_clean_rx_irq_ps - Reclaim resources after receive; packet split
- * @rx_ring:  rx ring to clean
- * @budget:   how many cleans we're allowed
- *
- * Returns true if there's any budget left (e.g. the clean is finished)
+ * i40e_rx_hash - set the hash value in the skb
+ * @ring: descriptor ring
+ * @rx_desc: specific descriptor
  **/
-static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
+static inline void i40e_rx_hash(struct i40e_ring *ring,
+				union i40e_rx_desc *rx_desc,
+				struct sk_buff *skb,
+				u8 rx_ptype)
 {
-	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
-	u16 rx_packet_len, rx_header_len, rx_sph, rx_hbo;
-	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
-	const int current_node = numa_mem_id();
-	struct i40e_vsi *vsi = rx_ring->vsi;
-	u16 i = rx_ring->next_to_clean;
-	union i40e_rx_desc *rx_desc;
-	u32 rx_error, rx_status;
-	u8 rx_ptype;
-	u64 qword;
-
-	if (budget <= 0)
-		return 0;
-
-	do {
-		struct i40e_rx_buffer *rx_bi;
-		struct sk_buff *skb;
-		u16 vlan_tag;
-		/* return some buffers to hardware, one at a time is too slow */
-		if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
-			i40e_alloc_rx_buffers_ps(rx_ring, cleaned_count);
-			cleaned_count = 0;
-		}
-
-		i = rx_ring->next_to_clean;
-		rx_desc = I40E_RX_DESC(rx_ring, i);
-		qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
-		rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
-			I40E_RXD_QW1_STATUS_SHIFT;
-
-		if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT)))
-			break;
-
-		/* This memory barrier is needed to keep us from reading
-		 * any other fields out of the rx_desc until we know the
-		 * DD bit is set.
-		 */
-		dma_rmb();
-		if (i40e_rx_is_programming_status(qword)) {
-			i40e_clean_programming_status(rx_ring, rx_desc);
-			I40E_RX_INCREMENT(rx_ring, i);
-			continue;
-		}
-		rx_bi = &rx_ring->rx_bi[i];
-		skb = rx_bi->skb;
-		if (likely(!skb)) {
-			skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-							rx_ring->rx_hdr_len);
-			if (!skb) {
-				rx_ring->rx_stats.alloc_buff_failed++;
-				break;
-			}
-
-			/* initialize queue mapping */
-			skb_record_rx_queue(skb, rx_ring->queue_index);
-			/* we are reusing so sync this buffer for CPU use */
-			dma_sync_single_range_for_cpu(rx_ring->dev,
-						      rx_bi->dma,
-						      0,
-						      rx_ring->rx_hdr_len,
-						      DMA_FROM_DEVICE);
-		}
-		rx_packet_len = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
-				I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
-		rx_header_len = (qword & I40E_RXD_QW1_LENGTH_HBUF_MASK) >>
-				I40E_RXD_QW1_LENGTH_HBUF_SHIFT;
-		rx_sph = (qword & I40E_RXD_QW1_LENGTH_SPH_MASK) >>
-			 I40E_RXD_QW1_LENGTH_SPH_SHIFT;
-
-		rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >>
-			   I40E_RXD_QW1_ERROR_SHIFT;
-		rx_hbo = rx_error & BIT(I40E_RX_DESC_ERROR_HBO_SHIFT);
-		rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT);
-
-		rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
-			   I40E_RXD_QW1_PTYPE_SHIFT;
-		prefetch(rx_bi->page);
-		rx_bi->skb = NULL;
-		cleaned_count++;
-		if (rx_hbo || rx_sph) {
-			int len;
-
-			if (rx_hbo)
-				len = I40E_RX_HDR_SIZE;
-			else
-				len = rx_header_len;
-			memcpy(__skb_put(skb, len), rx_bi->hdr_buf, len);
-		} else if (skb->len == 0) {
-			int len;
-
-			len = (rx_packet_len > skb_headlen(skb) ?
-				skb_headlen(skb) : rx_packet_len);
-			memcpy(__skb_put(skb, len),
-			       rx_bi->page + rx_bi->page_offset,
-			       len);
-			rx_bi->page_offset += len;
-			rx_packet_len -= len;
-		}
-
-		/* Get the rest of the data if this was a header split */
-		if (rx_packet_len) {
-			skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
-					   rx_bi->page,
-					   rx_bi->page_offset,
-					   rx_packet_len);
-
-			skb->len += rx_packet_len;
-			skb->data_len += rx_packet_len;
-			skb->truesize += rx_packet_len;
-
-			if ((page_count(rx_bi->page) == 1) &&
-			    (page_to_nid(rx_bi->page) == current_node))
-				get_page(rx_bi->page);
-			else
-				rx_bi->page = NULL;
-
-			dma_unmap_page(rx_ring->dev,
-				       rx_bi->page_dma,
-				       PAGE_SIZE / 2,
-				       DMA_FROM_DEVICE);
-			rx_bi->page_dma = 0;
-		}
-		I40E_RX_INCREMENT(rx_ring, i);
-
-		if (unlikely(
-		    !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) {
-			struct i40e_rx_buffer *next_buffer;
-
-			next_buffer = &rx_ring->rx_bi[i];
-			next_buffer->skb = skb;
-			rx_ring->rx_stats.non_eop_descs++;
-			continue;
-		}
-
-		/* ERR_MASK will only have valid bits if EOP set */
-		if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) {
-			dev_kfree_skb_any(skb);
-			continue;
-		}
-
-		skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
-			     i40e_ptype_to_hash(rx_ptype));
-		if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) {
-			i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status &
-					   I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
-					   I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT);
-			rx_ring->last_rx_timestamp = jiffies;
-		}
-
-		/* probably a little skewed due to removing CRC */
-		total_rx_bytes += skb->len;
-		total_rx_packets++;
-
-		skb->protocol = eth_type_trans(skb, rx_ring->netdev);
-
-		i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype);
-
-		vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)
-			 ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1)
-			 : 0;
-#ifdef I40E_FCOE
-		if (!i40e_fcoe_handle_offload(rx_ring, rx_desc, skb)) {
-			dev_kfree_skb_any(skb);
-			continue;
-		}
-#endif
-		skb_mark_napi_id(skb, &rx_ring->q_vector->napi);
-		i40e_receive_skb(rx_ring, skb, vlan_tag);
-
-		rx_desc->wb.qword1.status_error_len = 0;
-
-	} while (likely(total_rx_packets < budget));
+	u32 hash;
+	const __le64 rss_mask  =
+		cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
+			    I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
 
-	u64_stats_update_begin(&rx_ring->syncp);
-	rx_ring->stats.packets += total_rx_packets;
-	rx_ring->stats.bytes += total_rx_bytes;
-	u64_stats_update_end(&rx_ring->syncp);
-	rx_ring->q_vector->rx.total_packets += total_rx_packets;
-	rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
+	if (ring->netdev->features & NETIF_F_RXHASH)
+		return;
 
-	return total_rx_packets;
+	if ((rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) {
+		hash = le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
+		skb_set_hash(skb, hash, i40e_ptype_to_htype(rx_ptype));
+	}
 }
 
 /**
@@ -1664,6 +1499,7 @@
 	union i40e_rx_desc *rx_desc;
 	u32 rx_error, rx_status;
 	u16 rx_packet_len;
+	bool failure = false;
 	u8 rx_ptype;
 	u64 qword;
 	u16 i;
@@ -1674,7 +1510,9 @@
 		u16 vlan_tag;
 		/* return some buffers to hardware, one at a time is too slow */
 		if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
-			i40e_alloc_rx_buffers_1buf(rx_ring, cleaned_count);
+			failure = failure ||
+				  i40e_alloc_rx_buffers_1buf(rx_ring,
+							     cleaned_count);
 			cleaned_count = 0;
 		}
 
@@ -1736,8 +1574,7 @@
 			continue;
 		}
 
-		skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
-			     i40e_ptype_to_hash(rx_ptype));
+		i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
 		if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) {
 			i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status &
 					   I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
@@ -1774,7 +1611,7 @@
 	rx_ring->q_vector->rx.total_packets += total_rx_packets;
 	rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
-	return total_rx_packets;
+	return failure ? budget : total_rx_packets;
 }
 
 static u32 i40e_buildreg_itr(const int type, const u16 itr)
@@ -1782,7 +1619,9 @@
 	u32 val;
 
 	val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
-	      I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+	      /* Don't clear PBA because that can cause lost interrupts that
+	       * came in while we were cleaning/polling
+	       */
 	      (type << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
 	      (itr << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT);
 
@@ -1864,7 +1703,6 @@
 		q_vector->itr_countdown--;
 	else
 		q_vector->itr_countdown = ITR_COUNTDOWN_START;
-
 }
 
 /**
@@ -1892,12 +1730,15 @@
 		return 0;
 	}
 
+	/* Clear hung_detected bit */
+	clear_bit(I40E_Q_VECTOR_HUNG_DETECT, &q_vector->hung_detected);
 	/* Since the actual Tx work is minimal, we can give the Tx a larger
 	 * budget and be more aggressive about cleaning up the Tx descriptors.
 	 */
 	i40e_for_each_ring(ring, q_vector->tx) {
-		clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit);
-		arm_wb |= ring->arm_wb;
+		clean_complete = clean_complete &&
+				 i40e_clean_tx_irq(ring, vsi->work_limit);
+		arm_wb = arm_wb || ring->arm_wb;
 		ring->arm_wb = false;
 	}
 
@@ -1913,21 +1754,20 @@
 	i40e_for_each_ring(ring, q_vector->rx) {
 		int cleaned;
 
-		if (ring_is_ps_enabled(ring))
-			cleaned = i40e_clean_rx_irq_ps(ring, budget_per_ring);
-		else
-			cleaned = i40e_clean_rx_irq_1buf(ring, budget_per_ring);
+		cleaned = i40e_clean_rx_irq_1buf(ring, budget_per_ring);
 
 		work_done += cleaned;
 		/* if we didn't clean as many as budgeted, we must be done */
-		clean_complete &= (budget_per_ring != cleaned);
+		clean_complete = clean_complete && (budget_per_ring > cleaned);
 	}
 
 	/* If work not completed, return budget and polling will return */
 	if (!clean_complete) {
 tx_only:
-		if (arm_wb)
-			i40e_force_wb(vsi, q_vector);
+		if (arm_wb) {
+			q_vector->tx.ring[0].tx_stats.tx_force_wb++;
+			i40e_enable_wb_on_itr(vsi, q_vector);
+		}
 		return budget;
 	}
 
@@ -1939,20 +1779,7 @@
 	if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
 		i40e_update_enable_itr(vsi, q_vector);
 	} else { /* Legacy mode */
-		struct i40e_hw *hw = &vsi->back->hw;
-		/* We re-enable the queue 0 cause, but
-		 * don't worry about dynamic_enable
-		 * because we left it on for the other
-		 * possible interrupts during napi
-		 */
-		u32 qval = rd32(hw, I40E_QINT_RQCTL(0)) |
-			   I40E_QINT_RQCTL_CAUSE_ENA_MASK;
-
-		wr32(hw, I40E_QINT_RQCTL(0), qval);
-		qval = rd32(hw, I40E_QINT_TQCTL(0)) |
-		       I40E_QINT_TQCTL_CAUSE_ENA_MASK;
-		wr32(hw, I40E_QINT_TQCTL(0), qval);
-		i40e_irq_dynamic_enable_icr0(vsi->back);
+		i40e_irq_dynamic_enable_icr0(vsi->back, false);
 	}
 	return 0;
 }
@@ -1962,10 +1789,9 @@
  * @tx_ring:  ring to add programming descriptor to
  * @skb:      send buffer
  * @tx_flags: send tx flags
- * @protocol: wire protocol
  **/
 static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
-		     u32 tx_flags, __be16 protocol)
+		     u32 tx_flags)
 {
 	struct i40e_filter_program_desc *fdir_desc;
 	struct i40e_pf *pf = tx_ring->vsi->back;
@@ -1977,6 +1803,7 @@
 	struct tcphdr *th;
 	unsigned int hlen;
 	u32 flex_ptype, dtype_cmd;
+	int l4_proto;
 	u16 i;
 
 	/* make sure ATR is enabled */
@@ -1990,36 +1817,28 @@
 	if (!tx_ring->atr_sample_rate)
 		return;
 
+	/* Currently only IPv4/IPv6 with TCP is supported */
 	if (!(tx_flags & (I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6)))
 		return;
 
-	if (!(tx_flags & I40E_TX_FLAGS_VXLAN_TUNNEL)) {
-		/* snag network header to get L4 type and address */
-		hdr.network = skb_network_header(skb);
+	/* snag network header to get L4 type and address */
+	hdr.network = (tx_flags & I40E_TX_FLAGS_UDP_TUNNEL) ?
+		      skb_inner_network_header(skb) : skb_network_header(skb);
 
-		/* Currently only IPv4/IPv6 with TCP is supported
-		 * access ihl as u8 to avoid unaligned access on ia64
-		 */
-		if (tx_flags & I40E_TX_FLAGS_IPV4)
-			hlen = (hdr.network[0] & 0x0F) << 2;
-		else if (protocol == htons(ETH_P_IPV6))
-			hlen = sizeof(struct ipv6hdr);
-		else
-			return;
+	/* Note: tx_flags gets modified to reflect inner protocols in
+	 * tx_enable_csum function if encap is enabled.
+	 */
+	if (tx_flags & I40E_TX_FLAGS_IPV4) {
+		/* access ihl as u8 to avoid unaligned access on ia64 */
+		hlen = (hdr.network[0] & 0x0F) << 2;
+		l4_proto = hdr.ipv4->protocol;
 	} else {
-		hdr.network = skb_inner_network_header(skb);
-		hlen = skb_inner_network_header_len(skb);
+		hlen = hdr.network - skb->data;
+		l4_proto = ipv6_find_hdr(skb, &hlen, IPPROTO_TCP, NULL, NULL);
+		hlen -= hdr.network - skb->data;
 	}
 
-	/* Currently only IPv4/IPv6 with TCP is supported
-	 * Note: tx_flags gets modified to reflect inner protocols in
-	 * tx_enable_csum function if encap is enabled.
-	 */
-	if ((tx_flags & I40E_TX_FLAGS_IPV4) &&
-	    (hdr.ipv4->protocol != IPPROTO_TCP))
-		return;
-	else if ((tx_flags & I40E_TX_FLAGS_IPV6) &&
-		 (hdr.ipv6->nexthdr != IPPROTO_TCP))
+	if (l4_proto != IPPROTO_TCP)
 		return;
 
 	th = (struct tcphdr *)(hdr.network + hlen);
@@ -2027,7 +1846,8 @@
 	/* Due to lack of space, no more new filters can be programmed */
 	if (th->syn && (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
 		return;
-	if (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) {
+	if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) &&
+	    (!(pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))) {
 		/* HW ATR eviction will take care of removing filters on FIN
 		 * and RST packets.
 		 */
@@ -2055,7 +1875,7 @@
 
 	flex_ptype = (tx_ring->queue_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
 		      I40E_TXD_FLTR_QW0_QINDEX_MASK;
-	flex_ptype |= (protocol == htons(ETH_P_IP)) ?
+	flex_ptype |= (tx_flags & I40E_TX_FLAGS_IPV4) ?
 		      (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
 		       I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
 		      (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
@@ -2078,7 +1898,7 @@
 		     I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
 
 	dtype_cmd |= I40E_TXD_FLTR_QW1_CNT_ENA_MASK;
-	if (!(tx_flags & I40E_TX_FLAGS_VXLAN_TUNNEL))
+	if (!(tx_flags & I40E_TX_FLAGS_UDP_TUNNEL))
 		dtype_cmd |=
 			((u32)I40E_FD_ATR_STAT_IDX(pf->hw.pf_id) <<
 			I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
@@ -2089,7 +1909,8 @@
 			I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
 			I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
 
-	if (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE)
+	if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) &&
+	    (!(pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE)))
 		dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK;
 
 	fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype);
@@ -2187,22 +2008,30 @@
  * @tx_ring:  ptr to the ring to send
  * @skb:      ptr to the skb we're sending
  * @hdr_len:  ptr to the size of the packet header
- * @cd_type_cmd_tso_mss: ptr to u64 object
- * @cd_tunneling: ptr to context descriptor bits
+ * @cd_type_cmd_tso_mss: Quad Word 1
  *
  * Returns 0 if no TSO can happen, 1 if tso is going, or error
  **/
 static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
-		    u8 *hdr_len, u64 *cd_type_cmd_tso_mss,
-		    u32 *cd_tunneling)
+		    u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
 {
-	u32 cd_cmd, cd_tso_len, cd_mss;
-	struct ipv6hdr *ipv6h;
-	struct tcphdr *tcph;
-	struct iphdr *iph;
-	u32 l4len;
+	u64 cd_cmd, cd_tso_len, cd_mss;
+	union {
+		struct iphdr *v4;
+		struct ipv6hdr *v6;
+		unsigned char *hdr;
+	} ip;
+	union {
+		struct tcphdr *tcp;
+		struct udphdr *udp;
+		unsigned char *hdr;
+	} l4;
+	u32 paylen, l4_offset;
 	int err;
 
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return 0;
+
 	if (!skb_is_gso(skb))
 		return 0;
 
@@ -2210,35 +2039,60 @@
 	if (err < 0)
 		return err;
 
-	iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
-	ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+	ip.hdr = skb_network_header(skb);
+	l4.hdr = skb_transport_header(skb);
+
+	/* initialize outer IP header fields */
+	if (ip.v4->version == 4) {
+		ip.v4->tot_len = 0;
+		ip.v4->check = 0;
+	} else {
+		ip.v6->payload_len = 0;
+	}
+
+	if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE |
+					 SKB_GSO_UDP_TUNNEL_CSUM)) {
+		if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+			/* determine offset of outer transport header */
+			l4_offset = l4.hdr - skb->data;
+
+			/* remove payload length from outer checksum */
+			paylen = (__force u16)l4.udp->check;
+			paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+			l4.udp->check = ~csum_fold((__force __wsum)paylen);
+		}
+
+		/* reset pointers to inner headers */
+		ip.hdr = skb_inner_network_header(skb);
+		l4.hdr = skb_inner_transport_header(skb);
+
+		/* initialize inner IP header fields */
+		if (ip.v4->version == 4) {
+			ip.v4->tot_len = 0;
+			ip.v4->check = 0;
+		} else {
+			ip.v6->payload_len = 0;
+		}
+	}
+
+	/* determine offset of inner transport header */
+	l4_offset = l4.hdr - skb->data;
+
+	/* remove payload length from inner checksum */
+	paylen = (__force u16)l4.tcp->check;
+	paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+	l4.tcp->check = ~csum_fold((__force __wsum)paylen);
 
-	if (iph->version == 4) {
-		tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
-		iph->tot_len = 0;
-		iph->check = 0;
-		tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-						 0, IPPROTO_TCP, 0);
-	} else if (ipv6h->version == 6) {
-		tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
-		ipv6h->payload_len = 0;
-		tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
-					       0, IPPROTO_TCP, 0);
-	}
-
-	l4len = skb->encapsulation ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb);
-	*hdr_len = (skb->encapsulation
-		    ? (skb_inner_transport_header(skb) - skb->data)
-		    : skb_transport_offset(skb)) + l4len;
+	/* compute length of segmentation header */
+	*hdr_len = (l4.tcp->doff * 4) + l4_offset;
 
 	/* find the field values */
 	cd_cmd = I40E_TX_CTX_DESC_TSO;
 	cd_tso_len = skb->len - *hdr_len;
 	cd_mss = skb_shinfo(skb)->gso_size;
-	*cd_type_cmd_tso_mss |= ((u64)cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
-				((u64)cd_tso_len <<
-				 I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
-				((u64)cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
+	*cd_type_cmd_tso_mss |= (cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
+				(cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
+				(cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
 	return 1;
 }
 
@@ -2247,7 +2101,7 @@
  * @tx_ring:  ptr to the ring to send
  * @skb:      ptr to the skb we're sending
  * @tx_flags: the collected send information
- * @cd_type_cmd_tso_mss: ptr to u64 object
+ * @cd_type_cmd_tso_mss: Quad Word 1
  *
  * Returns 0 if no Tx timestamp can happen and 1 if the timestamp will happen
  **/
@@ -2293,129 +2147,154 @@
  * @tx_ring: Tx descriptor ring
  * @cd_tunneling: ptr to context desc bits
  **/
-static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
-				u32 *td_cmd, u32 *td_offset,
-				struct i40e_ring *tx_ring,
-				u32 *cd_tunneling)
-{
-	struct ipv6hdr *this_ipv6_hdr;
-	unsigned int this_tcp_hdrlen;
-	struct iphdr *this_ip_hdr;
-	u32 network_hdr_len;
-	u8 l4_hdr = 0;
-	struct udphdr *oudph;
-	struct iphdr *oiph;
-	u32 l4_tunnel = 0;
+static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
+			       u32 *td_cmd, u32 *td_offset,
+			       struct i40e_ring *tx_ring,
+			       u32 *cd_tunneling)
+{
+	union {
+		struct iphdr *v4;
+		struct ipv6hdr *v6;
+		unsigned char *hdr;
+	} ip;
+	union {
+		struct tcphdr *tcp;
+		struct udphdr *udp;
+		unsigned char *hdr;
+	} l4;
+	unsigned char *exthdr;
+	u32 offset, cmd = 0, tunnel = 0;
+	__be16 frag_off;
+	u8 l4_proto = 0;
+
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return 0;
+
+	ip.hdr = skb_network_header(skb);
+	l4.hdr = skb_transport_header(skb);
+
+	/* compute outer L2 header size */
+	offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
 
 	if (skb->encapsulation) {
-		switch (ip_hdr(skb)->protocol) {
+		/* define outer network header type */
+		if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+			tunnel |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
+				  I40E_TX_CTX_EXT_IP_IPV4 :
+				  I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+
+			l4_proto = ip.v4->protocol;
+		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
+			tunnel |= I40E_TX_CTX_EXT_IP_IPV6;
+
+			exthdr = ip.hdr + sizeof(*ip.v6);
+			l4_proto = ip.v6->nexthdr;
+			if (l4.hdr != exthdr)
+				ipv6_skip_exthdr(skb, exthdr - skb->data,
+						 &l4_proto, &frag_off);
+		}
+
+		/* compute outer L3 header size */
+		tunnel |= ((l4.hdr - ip.hdr) / 4) <<
+			  I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT;
+
+		/* switch IP header pointer from outer to inner header */
+		ip.hdr = skb_inner_network_header(skb);
+
+		/* define outer transport */
+		switch (l4_proto) {
 		case IPPROTO_UDP:
-			oudph = udp_hdr(skb);
-			oiph = ip_hdr(skb);
-			l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
-			*tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
+			tunnel |= I40E_TXD_CTX_UDP_TUNNELING;
+			*tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL;
 			break;
 		case IPPROTO_GRE:
-			l4_tunnel = I40E_TXD_CTX_GRE_TUNNELING;
+			tunnel |= I40E_TXD_CTX_GRE_TUNNELING;
+			*tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL;
 			break;
 		default:
-			return;
-		}
-		network_hdr_len = skb_inner_network_header_len(skb);
-		this_ip_hdr = inner_ip_hdr(skb);
-		this_ipv6_hdr = inner_ipv6_hdr(skb);
-		this_tcp_hdrlen = inner_tcp_hdrlen(skb);
-
-		if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-			if (*tx_flags & I40E_TX_FLAGS_TSO) {
-				*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
-				ip_hdr(skb)->check = 0;
-			} else {
-				*cd_tunneling |=
-					 I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-			}
-		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-			*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
 			if (*tx_flags & I40E_TX_FLAGS_TSO)
-				ip_hdr(skb)->check = 0;
+				return -1;
+
+			skb_checksum_help(skb);
+			return 0;
 		}
 
-		/* Now set the ctx descriptor fields */
-		*cd_tunneling |= (skb_network_header_len(skb) >> 2) <<
-				   I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT      |
-				   l4_tunnel                             |
-				   ((skb_inner_network_offset(skb) -
-					skb_transport_offset(skb)) >> 1) <<
-				   I40E_TXD_CTX_QW0_NATLEN_SHIFT;
-		if (this_ip_hdr->version == 6) {
-			*tx_flags &= ~I40E_TX_FLAGS_IPV4;
+		/* compute tunnel header size */
+		tunnel |= ((ip.hdr - l4.hdr) / 2) <<
+			  I40E_TXD_CTX_QW0_NATLEN_SHIFT;
+
+		/* indicate if we need to offload outer UDP header */
+		if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
+		    (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
+			tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
+
+		/* record tunnel offload values */
+		*cd_tunneling |= tunnel;
+
+		/* switch L4 header pointer from outer to inner */
+		l4.hdr = skb_inner_transport_header(skb);
+		l4_proto = 0;
+
+		/* reset type as we transition from outer to inner headers */
+		*tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6);
+		if (ip.v4->version == 4)
+			*tx_flags |= I40E_TX_FLAGS_IPV4;
+		if (ip.v6->version == 6)
 			*tx_flags |= I40E_TX_FLAGS_IPV6;
-		}
-		if ((tx_ring->flags & I40E_TXR_FLAGS_OUTER_UDP_CSUM) &&
-		    (l4_tunnel == I40E_TXD_CTX_UDP_TUNNELING)        &&
-		    (*cd_tunneling & I40E_TXD_CTX_QW0_EXT_IP_MASK)) {
-			oudph->check = ~csum_tcpudp_magic(oiph->saddr,
-					oiph->daddr,
-					(skb->len - skb_transport_offset(skb)),
-					IPPROTO_UDP, 0);
-			*cd_tunneling |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
-		}
-	} else {
-		network_hdr_len = skb_network_header_len(skb);
-		this_ip_hdr = ip_hdr(skb);
-		this_ipv6_hdr = ipv6_hdr(skb);
-		this_tcp_hdrlen = tcp_hdrlen(skb);
 	}
 
 	/* Enable IP checksum offloads */
 	if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-		l4_hdr = this_ip_hdr->protocol;
+		l4_proto = ip.v4->protocol;
 		/* the stack computes the IP header already, the only time we
 		 * need the hardware to recompute it is in the case of TSO.
 		 */
-		if (*tx_flags & I40E_TX_FLAGS_TSO) {
-			*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
-			this_ip_hdr->check = 0;
-		} else {
-			*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
-		}
-		/* Now set the td_offset for IP header length */
-		*td_offset = (network_hdr_len >> 2) <<
-			      I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+		cmd |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
+		       I40E_TX_DESC_CMD_IIPT_IPV4_CSUM :
+		       I40E_TX_DESC_CMD_IIPT_IPV4;
 	} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-		l4_hdr = this_ipv6_hdr->nexthdr;
-		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
-		/* Now set the td_offset for IP header length */
-		*td_offset = (network_hdr_len >> 2) <<
-			      I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
-	}
-	/* words in MACLEN + dwords in IPLEN + dwords in L4Len */
-	*td_offset |= (skb_network_offset(skb) >> 1) <<
-		       I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
+		cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+
+		exthdr = ip.hdr + sizeof(*ip.v6);
+		l4_proto = ip.v6->nexthdr;
+		if (l4.hdr != exthdr)
+			ipv6_skip_exthdr(skb, exthdr - skb->data,
+					 &l4_proto, &frag_off);
+	}
+
+	/* compute inner L3 header size */
+	offset |= ((l4.hdr - ip.hdr) / 4) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
 
 	/* Enable L4 checksum offloads */
-	switch (l4_hdr) {
+	switch (l4_proto) {
 	case IPPROTO_TCP:
 		/* enable checksum offloads */
-		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
-		*td_offset |= (this_tcp_hdrlen >> 2) <<
-			       I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
+		offset |= l4.tcp->doff << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
 		break;
 	case IPPROTO_SCTP:
 		/* enable SCTP checksum offload */
-		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
-		*td_offset |= (sizeof(struct sctphdr) >> 2) <<
-			       I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
+		offset |= (sizeof(struct sctphdr) >> 2) <<
+			  I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
 		break;
 	case IPPROTO_UDP:
 		/* enable UDP checksum offload */
-		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
-		*td_offset |= (sizeof(struct udphdr) >> 2) <<
-			       I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
+		offset |= (sizeof(struct udphdr) >> 2) <<
+			  I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
 		break;
 	default:
-		break;
+		if (*tx_flags & I40E_TX_FLAGS_TSO)
+			return -1;
+		skb_checksum_help(skb);
+		return 0;
 	}
+
+	*td_cmd |= cmd;
+	*td_offset |= offset;
+
+	return 1;
 }
 
 /**
@@ -2456,7 +2335,7 @@
  *
  * Returns -EBUSY if a stop is needed, else 0
  **/
-static inline int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
 {
 	netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
 	/* Memory barrier before checking head and tail */
@@ -2473,77 +2352,87 @@
 }
 
 /**
- * i40e_maybe_stop_tx - 1st level check for tx stop conditions
- * @tx_ring: the ring to be checked
- * @size:    the size buffer we want to assure is available
- *
- * Returns 0 if stop is not needed
- **/
-#ifdef I40E_FCOE
-inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
-#else
-static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
-#endif
-{
-	if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
-		return 0;
-	return __i40e_maybe_stop_tx(tx_ring, size);
-}
-
-/**
- * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * __i40e_chk_linearize - Check if there are more than 8 buffers per packet
  * @skb:      send buffer
- * @tx_flags: collected send information
  *
- * Note: Our HW can't scatter-gather more than 8 fragments to build
- * a packet on the wire and so we need to figure out the cases where we
- * need to linearize the skb.
- **/
-static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags)
-{
-	struct skb_frag_struct *frag;
-	bool linearize = false;
-	unsigned int size = 0;
-	u16 num_frags;
-	u16 gso_segs;
+ * Note: Our HW can't DMA more than 8 buffers to build a packet on the wire
+ * and so we need to figure out the cases where we need to linearize the skb.
+ *
+ * For TSO we need to count the TSO header and segment payload separately.
+ * As such we need to check cases where we have 7 fragments or more as we
+ * can potentially require 9 DMA transactions, 1 for the TSO header, 1 for
+ * the segment payload in the first descriptor, and another 7 for the
+ * fragments.
+ **/
+bool __i40e_chk_linearize(struct sk_buff *skb)
+{
+	const struct skb_frag_struct *frag, *stale;
+	int nr_frags, sum;
+
+	/* no need to check if number of frags is less than 7 */
+	nr_frags = skb_shinfo(skb)->nr_frags;
+	if (nr_frags < (I40E_MAX_BUFFER_TXD - 1))
+		return false;
 
-	num_frags = skb_shinfo(skb)->nr_frags;
-	gso_segs = skb_shinfo(skb)->gso_segs;
+	/* We need to walk through the list and validate that each group
+	 * of 6 fragments totals at least gso_size.
+	 */
+	nr_frags -= I40E_MAX_BUFFER_TXD - 2;
+	frag = &skb_shinfo(skb)->frags[0];
 
-	if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
-		u16 j = 0;
+	/* Initialize size to the negative value of gso_size minus 1.  We
+	 * use this as the worst case scenerio in which the frag ahead
+	 * of us only provides one byte which is why we are limited to 6
+	 * descriptors for a single transmit as the header and previous
+	 * fragment are already consuming 2 descriptors.
+	 */
+	sum = 1 - skb_shinfo(skb)->gso_size;
 
-		if (num_frags < (I40E_MAX_BUFFER_TXD))
-			goto linearize_chk_done;
-		/* try the simple math, if we have too many frags per segment */
-		if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
-		    I40E_MAX_BUFFER_TXD) {
-			linearize = true;
-			goto linearize_chk_done;
-		}
-		frag = &skb_shinfo(skb)->frags[0];
-		/* we might still have more fragments per segment */
-		do {
-			size += skb_frag_size(frag);
-			frag++; j++;
-			if ((size >= skb_shinfo(skb)->gso_size) &&
-			    (j < I40E_MAX_BUFFER_TXD)) {
-				size = (size % skb_shinfo(skb)->gso_size);
-				j = (size) ? 1 : 0;
-			}
-			if (j == I40E_MAX_BUFFER_TXD) {
-				linearize = true;
-				break;
-			}
-			num_frags--;
-		} while (num_frags);
-	} else {
-		if (num_frags >= I40E_MAX_BUFFER_TXD)
-			linearize = true;
+	/* Add size of frags 0 through 4 to create our initial sum */
+	sum += skb_frag_size(frag++);
+	sum += skb_frag_size(frag++);
+	sum += skb_frag_size(frag++);
+	sum += skb_frag_size(frag++);
+	sum += skb_frag_size(frag++);
+
+	/* Walk through fragments adding latest fragment, testing it, and
+	 * then removing stale fragments from the sum.
+	 */
+	for (stale = &skb_shinfo(skb)->frags[0];; stale++) {
+		int stale_size = skb_frag_size(stale);
+
+		sum += skb_frag_size(frag++);
+
+		/* The stale fragment may present us with a smaller
+		 * descriptor than the actual fragment size. To account
+		 * for that we need to remove all the data on the front and
+		 * figure out what the remainder would be in the last
+		 * descriptor associated with the fragment.
+		 */
+		if (stale_size > I40E_MAX_DATA_PER_TXD) {
+			int align_pad = -(stale->page_offset) &
+					(I40E_MAX_READ_REQ_SIZE - 1);
+
+			sum -= align_pad;
+			stale_size -= align_pad;
+
+			do {
+				sum -= I40E_MAX_DATA_PER_TXD_ALIGNED;
+				stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED;
+			} while (stale_size > I40E_MAX_DATA_PER_TXD);
+		}
+
+		/* if sum is negative we failed to make sufficient progress */
+		if (sum < 0)
+			return true;
+
+		if (!nr_frags--)
+			break;
+
+		sum -= stale_size;
 	}
 
-linearize_chk_done:
-	return linearize;
+	return false;
 }
 
 /**
@@ -2602,6 +2491,8 @@
 	tx_bi = first;
 
 	for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
+		unsigned int max_data = I40E_MAX_DATA_PER_TXD_ALIGNED;
+
 		if (dma_mapping_error(tx_ring->dev, dma))
 			goto dma_error;
 
@@ -2609,12 +2500,14 @@
 		dma_unmap_len_set(tx_bi, len, size);
 		dma_unmap_addr_set(tx_bi, dma, dma);
 
+		/* align size to end of page */
+		max_data += -dma & (I40E_MAX_READ_REQ_SIZE - 1);
 		tx_desc->buffer_addr = cpu_to_le64(dma);
 
 		while (unlikely(size > I40E_MAX_DATA_PER_TXD)) {
 			tx_desc->cmd_type_offset_bsz =
 				build_ctob(td_cmd, td_offset,
-					   I40E_MAX_DATA_PER_TXD, td_tag);
+					   max_data, td_tag);
 
 			tx_desc++;
 			i++;
@@ -2625,9 +2518,10 @@
 				i = 0;
 			}
 
-			dma += I40E_MAX_DATA_PER_TXD;
-			size -= I40E_MAX_DATA_PER_TXD;
+			dma += max_data;
+			size -= max_data;
 
+			max_data = I40E_MAX_DATA_PER_TXD_ALIGNED;
 			tx_desc->buffer_addr = cpu_to_le64(dma);
 		}
 
@@ -2750,43 +2644,6 @@
 }
 
 /**
- * i40e_xmit_descriptor_count - calculate number of tx descriptors needed
- * @skb:     send buffer
- * @tx_ring: ring to send buffer on
- *
- * Returns number of data descriptors needed for this skb. Returns 0 to indicate
- * there is not enough descriptors available in this ring since we need at least
- * one descriptor.
- **/
-#ifdef I40E_FCOE
-inline int i40e_xmit_descriptor_count(struct sk_buff *skb,
-				      struct i40e_ring *tx_ring)
-#else
-static inline int i40e_xmit_descriptor_count(struct sk_buff *skb,
-					     struct i40e_ring *tx_ring)
-#endif
-{
-	unsigned int f;
-	int count = 0;
-
-	/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
-	 *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
-	 *       + 4 desc gap to avoid the cache line where head is,
-	 *       + 1 desc for context descriptor,
-	 * otherwise try next time
-	 */
-	for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
-		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
-
-	count += TXD_USE_COUNT(skb_headlen(skb));
-	if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
-		tx_ring->tx_stats.tx_busy++;
-		return 0;
-	}
-	return count;
-}
-
-/**
  * i40e_xmit_frame_ring - Sends buffer on Tx ring
  * @skb:     send buffer
  * @tx_ring: ring to send buffer on
@@ -2804,11 +2661,30 @@
 	__be16 protocol;
 	u32 td_cmd = 0;
 	u8 hdr_len = 0;
+	int tso, count;
 	int tsyn;
-	int tso;
 
-	if (0 == i40e_xmit_descriptor_count(skb, tx_ring))
+	/* prefetch the data, we'll need it later */
+	prefetch(skb->data);
+
+	count = i40e_xmit_descriptor_count(skb);
+	if (i40e_chk_linearize(skb, count)) {
+		if (__skb_linearize(skb))
+			goto out_drop;
+		count = i40e_txd_use_count(skb->len);
+		tx_ring->tx_stats.tx_linearize++;
+	}
+
+	/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
+	 *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
+	 *       + 4 desc gap to avoid the cache line where head is,
+	 *       + 1 desc for context descriptor,
+	 * otherwise try next time
+	 */
+	if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+		tx_ring->tx_stats.tx_busy++;
 		return NETDEV_TX_BUSY;
+	}
 
 	/* prepare the xmit flags */
 	if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
@@ -2826,37 +2702,29 @@
 	else if (protocol == htons(ETH_P_IPV6))
 		tx_flags |= I40E_TX_FLAGS_IPV6;
 
-	tso = i40e_tso(tx_ring, skb, &hdr_len,
-		       &cd_type_cmd_tso_mss, &cd_tunneling);
+	tso = i40e_tso(tx_ring, skb, &hdr_len, &cd_type_cmd_tso_mss);
 
 	if (tso < 0)
 		goto out_drop;
 	else if (tso)
 		tx_flags |= I40E_TX_FLAGS_TSO;
 
+	/* Always offload the checksum, since it's in the data descriptor */
+	tso = i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
+				  tx_ring, &cd_tunneling);
+	if (tso < 0)
+		goto out_drop;
+
 	tsyn = i40e_tsyn(tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss);
 
 	if (tsyn)
 		tx_flags |= I40E_TX_FLAGS_TSYN;
 
-	if (i40e_chk_linearize(skb, tx_flags)) {
-		if (skb_linearize(skb))
-			goto out_drop;
-		tx_ring->tx_stats.tx_linearize++;
-	}
 	skb_tx_timestamp(skb);
 
 	/* always enable CRC insertion offload */
 	td_cmd |= I40E_TX_DESC_CMD_ICRC;
 
-	/* Always offload the checksum, since it's in the data descriptor */
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		tx_flags |= I40E_TX_FLAGS_CSUM;
-
-		i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
-				    tx_ring, &cd_tunneling);
-	}
-
 	i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss,
 			   cd_tunneling, cd_l2tag2);
 
@@ -2864,7 +2732,7 @@
 	 *
 	 * NOTE: this must always be directly before the data descriptor.
 	 */
-	i40e_atr(tx_ring, skb, tx_flags, protocol);
+	i40e_atr(tx_ring, skb, tx_flags);
 
 	i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len,
 		    td_cmd, td_offset);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -146,14 +146,42 @@
 
 #define I40E_MAX_BUFFER_TXD	8
 #define I40E_MIN_TX_LEN		17
-#define I40E_MAX_DATA_PER_TXD	8192
+
+/* The size limit for a transmit buffer in a descriptor is (16K - 1).
+ * In order to align with the read requests we will align the value to
+ * the nearest 4K which represents our maximum read request size.
+ */
+#define I40E_MAX_READ_REQ_SIZE		4096
+#define I40E_MAX_DATA_PER_TXD		(16 * 1024 - 1)
+#define I40E_MAX_DATA_PER_TXD_ALIGNED \
+	(I40E_MAX_DATA_PER_TXD & ~(I40E_MAX_READ_REQ_SIZE - 1))
+
+/* This ugly bit of math is equivalent to DIV_ROUNDUP(size, X) where X is
+ * the value I40E_MAX_DATA_PER_TXD_ALIGNED.  It is needed due to the fact
+ * that 12K is not a power of 2 and division is expensive.  It is used to
+ * approximate the number of descriptors used per linear buffer.  Note
+ * that this will overestimate in some cases as it doesn't account for the
+ * fact that we will add up to 4K - 1 in aligning the 12K buffer, however
+ * the error should not impact things much as large buffers usually mean
+ * we will use fewer descriptors then there are frags in an skb.
+ */
+static inline unsigned int i40e_txd_use_count(unsigned int size)
+{
+	const unsigned int max = I40E_MAX_DATA_PER_TXD_ALIGNED;
+	const unsigned int reciprocal = ((1ull << 32) - 1 + (max / 2)) / max;
+	unsigned int adjust = ~(u32)0;
+
+	/* if we rounded up on the reciprocal pull down the adjustment */
+	if ((max * reciprocal) > adjust)
+		adjust = ~(u32)(reciprocal - 1);
+
+	return (u32)((((u64)size * reciprocal) + adjust) >> 32);
+}
 
 /* Tx Descriptors needed, worst case */
-#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
 #define I40E_MIN_DESC_PENDING	4
 
-#define I40E_TX_FLAGS_CSUM		BIT(0)
 #define I40E_TX_FLAGS_HW_VLAN		BIT(1)
 #define I40E_TX_FLAGS_SW_VLAN		BIT(2)
 #define I40E_TX_FLAGS_TSO		BIT(3)
@@ -163,7 +191,7 @@
 #define I40E_TX_FLAGS_FSO		BIT(7)
 #define I40E_TX_FLAGS_TSYN		BIT(8)
 #define I40E_TX_FLAGS_FD_SB		BIT(9)
-#define I40E_TX_FLAGS_VXLAN_TUNNEL	BIT(10)
+#define I40E_TX_FLAGS_UDP_TUNNEL	BIT(10)
 #define I40E_TX_FLAGS_VLAN_MASK		0xffff0000
 #define I40E_TX_FLAGS_VLAN_PRIO_MASK	0xe0000000
 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT	29
@@ -202,27 +230,24 @@
 	u64 tx_busy;
 	u64 tx_done_old;
 	u64 tx_linearize;
+	u64 tx_force_wb;
+	u64 tx_lost_interrupt;
 };
 
 struct i40e_rx_queue_stats {
 	u64 non_eop_descs;
 	u64 alloc_page_failed;
 	u64 alloc_buff_failed;
+	u64 page_reuse_count;
+	u64 realloc_count;
 };
 
 enum i40e_ring_state_t {
 	__I40E_TX_FDIR_INIT_DONE,
 	__I40E_TX_XPS_INIT_DONE,
-	__I40E_RX_PS_ENABLED,
 	__I40E_RX_16BYTE_DESC_ENABLED,
 };
 
-#define ring_is_ps_enabled(ring) \
-	test_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
-#define set_ring_ps_enabled(ring) \
-	set_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
-#define clear_ring_ps_enabled(ring) \
-	clear_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
 #define ring_is_16byte_desc_enabled(ring) \
 	test_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state)
 #define set_ring_16byte_desc_enabled(ring) \
@@ -253,7 +278,6 @@
 #define I40E_RX_DTYPE_NO_SPLIT      0
 #define I40E_RX_DTYPE_HEADER_SPLIT  1
 #define I40E_RX_DTYPE_SPLIT_ALWAYS  2
-	u8  hsplit;
 #define I40E_RX_SPLIT_L2      0x1
 #define I40E_RX_SPLIT_IP      0x2
 #define I40E_RX_SPLIT_TCP_UDP 0x4
@@ -274,7 +298,6 @@
 
 	u16 flags;
 #define I40E_TXR_FLAGS_WB_ON_ITR	BIT(0)
-#define I40E_TXR_FLAGS_OUTER_UDP_CSUM	BIT(1)
 #define I40E_TXR_FLAGS_LAST_XMIT_MORE_SET BIT(2)
 
 	/* stats structs */
@@ -315,8 +338,8 @@
 #define i40e_for_each_ring(pos, head) \
 	for (pos = (head).ring; pos != NULL; pos = pos->next)
 
-void i40e_alloc_rx_buffers_ps(struct i40e_ring *rxr, u16 cleaned_count);
-void i40e_alloc_rx_buffers_1buf(struct i40e_ring *rxr, u16 cleaned_count);
+bool i40e_alloc_rx_buffers_ps(struct i40e_ring *rxr, u16 cleaned_count);
+bool i40e_alloc_rx_buffers_1buf(struct i40e_ring *rxr, u16 cleaned_count);
 void i40e_alloc_rx_headers(struct i40e_ring *rxr);
 netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void i40e_clean_tx_ring(struct i40e_ring *tx_ring);
@@ -330,13 +353,13 @@
 void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
 		 struct i40e_tx_buffer *first, u32 tx_flags,
 		 const u8 hdr_len, u32 td_cmd, u32 td_offset);
-int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
-int i40e_xmit_descriptor_count(struct sk_buff *skb, struct i40e_ring *tx_ring);
 int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
 			       struct i40e_ring *tx_ring, u32 *flags);
 #endif
 void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
-u32 i40e_get_tx_pending(struct i40e_ring *ring);
+u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw);
+int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
+bool __i40e_chk_linearize(struct sk_buff *skb);
 
 /**
  * i40e_get_head - Retrieve head from head writeback
@@ -351,4 +374,67 @@
 
 	return le32_to_cpu(*(volatile __le32 *)head);
 }
+
+/**
+ * i40e_xmit_descriptor_count - calculate number of Tx descriptors needed
+ * @skb:     send buffer
+ * @tx_ring: ring to send buffer on
+ *
+ * Returns number of data descriptors needed for this skb. Returns 0 to indicate
+ * there is not enough descriptors available in this ring since we need at least
+ * one descriptor.
+ **/
+static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)
+{
+	const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+	int count = 0, size = skb_headlen(skb);
+
+	for (;;) {
+		count += i40e_txd_use_count(size);
+
+		if (!nr_frags--)
+			break;
+
+		size = skb_frag_size(frag++);
+	}
+
+	return count;
+}
+
+/**
+ * i40e_maybe_stop_tx - 1st level check for Tx stop conditions
+ * @tx_ring: the ring to be checked
+ * @size:    the size buffer we want to assure is available
+ *
+ * Returns 0 if stop is not needed
+ **/
+static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+{
+	if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
+		return 0;
+	return __i40e_maybe_stop_tx(tx_ring, size);
+}
+
+/**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @count:    number of buffers used
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static inline bool i40e_chk_linearize(struct sk_buff *skb, int count)
+{
+	/* Both TSO and single send will work if count is less than 8 */
+	if (likely(count < I40E_MAX_BUFFER_TXD))
+		return false;
+
+	if (skb_is_gso(skb))
+		return __i40e_chk_linearize(skb);
+
+	/* we can support up to 8 data buffers for a single send */
+	return count != I40E_MAX_BUFFER_TXD;
+}
 #endif /* _I40E_TXRX_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -90,6 +90,22 @@
 	I40E_DEBUG_ALL			= 0xFFFFFFFF
 };
 
+#define I40E_MDIO_STCODE                0
+#define I40E_MDIO_OPCODE_ADDRESS        0
+#define I40E_MDIO_OPCODE_WRITE          I40E_MASK(1, \
+						  I40E_GLGEN_MSCA_OPCODE_SHIFT)
+#define I40E_MDIO_OPCODE_READ_INC_ADDR  I40E_MASK(2, \
+						  I40E_GLGEN_MSCA_OPCODE_SHIFT)
+#define I40E_MDIO_OPCODE_READ           I40E_MASK(3, \
+						  I40E_GLGEN_MSCA_OPCODE_SHIFT)
+
+#define I40E_PHY_COM_REG_PAGE                   0x1E
+#define I40E_PHY_LED_LINK_MODE_MASK             0xF0
+#define I40E_PHY_LED_MANUAL_ON                  0x100
+#define I40E_PHY_LED_PROV_REG_1                 0xC430
+#define I40E_PHY_LED_MODE_MASK                  0xFFFF
+#define I40E_PHY_LED_MODE_ORIG                  0x80000000
+
 /* These are structs for managing the hardware information and the operations.
  * The structures of function pointers are filled out at init time when we
  * know for sure exactly which hardware we're working with.  This gives us the
@@ -1096,6 +1112,10 @@
 
 #define I40E_TXD_FLTR_QW1_ATR_SHIFT	(0xEULL + \
 					 I40E_TXD_FLTR_QW1_CMD_SHIFT)
+#define I40E_TXD_FLTR_QW1_ATR_MASK	BIT_ULL(I40E_TXD_FLTR_QW1_ATR_SHIFT)
+
+#define I40E_TXD_FLTR_QW1_ATR_SHIFT	(0xEULL + \
+					 I40E_TXD_FLTR_QW1_CMD_SHIFT)
 #define I40E_TXD_FLTR_QW1_ATR_MASK	BIT_ULL(I40E_TXD_FLTR_QW1_ATR_SHIFT)
 
 #define I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT 20
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h
@@ -153,6 +153,7 @@
 #define I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR	0x00000020
 #define I40E_VIRTCHNL_VF_OFFLOAD_VLAN		0x00010000
 #define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING	0x00020000
+#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2	0x00040000
 
 struct i40e_virtchnl_vf_resource {
 	u16 num_vsis;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -188,7 +188,7 @@
  * check for the valid queue id
  **/
 static inline bool i40e_vc_isvalid_queue_id(struct i40e_vf *vf, u16 vsi_id,
-					    u8 qid)
+					    u16 qid)
 {
 	struct i40e_pf *pf = vf->pf;
 	struct i40e_vsi *vsi = i40e_find_vsi_from_id(pf, vsi_id);
@@ -203,7 +203,7 @@
  *
  * check for the valid vector id
  **/
-static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u8 vector_id)
+static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u32 vector_id)
 {
 	struct i40e_pf *pf = vf->pf;
 
@@ -290,8 +290,8 @@
 	next_q = find_first_bit(&linklistmap,
 				(I40E_MAX_VSI_QP *
 				 I40E_VIRTCHNL_SUPPORTED_QTYPES));
-	vsi_queue_id = next_q/I40E_VIRTCHNL_SUPPORTED_QTYPES;
-	qtype = next_q%I40E_VIRTCHNL_SUPPORTED_QTYPES;
+	vsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES;
+	qtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES;
 	pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id);
 	reg = ((qtype << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) | pf_queue_id);
 
@@ -461,7 +461,7 @@
 		rx_ctx.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
 
 		/* set splitalways mode 10b */
-		rx_ctx.dtype = 0x2;
+		rx_ctx.dtype = I40E_RX_DTYPE_HEADER_SPLIT;
 	}
 
 	/* databuffer length validation */
@@ -549,12 +549,15 @@
 			i40e_vsi_add_pvid(vsi, vf->port_vlan_id);
 
 		spin_lock_bh(&vsi->mac_filter_list_lock);
-		f = i40e_add_filter(vsi, vf->default_lan_addr.addr,
-				    vf->port_vlan_id ? vf->port_vlan_id : -1,
-				    true, false);
-		if (!f)
-			dev_info(&pf->pdev->dev,
-				 "Could not allocate VF MAC addr\n");
+		if (is_valid_ether_addr(vf->default_lan_addr.addr)) {
+			f = i40e_add_filter(vsi, vf->default_lan_addr.addr,
+				       vf->port_vlan_id ? vf->port_vlan_id : -1,
+				       true, false);
+			if (!f)
+				dev_info(&pf->pdev->dev,
+					 "Could not add MAC filter %pM for VF %d\n",
+					vf->default_lan_addr.addr, vf->vf_id);
+		}
 		f = i40e_add_filter(vsi, brdcast,
 				    vf->port_vlan_id ? vf->port_vlan_id : -1,
 				    true, false);
@@ -565,7 +568,7 @@
 	}
 
 	/* program mac filter */
-	ret = i40e_sync_vsi_filters(vsi, false);
+	ret = i40e_sync_vsi_filters(vsi);
 	if (ret)
 		dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
 
@@ -599,8 +602,8 @@
 	 * that VF queues be mapped using this method, even when they are
 	 * contiguous in real life
 	 */
-	wr32(hw, I40E_VSILAN_QBASE(vf->lan_vsi_id),
-	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
+	i40e_write_rx_ctl(hw, I40E_VSILAN_QBASE(vf->lan_vsi_id),
+			  I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
 
 	/* enable VF vplan_qtable mappings */
 	reg = I40E_VPLAN_MAPENA_TXRX_ENA_MASK;
@@ -627,7 +630,8 @@
 						      (j * 2) + 1);
 			reg |= qid << 16;
 		}
-		wr32(hw, I40E_VSILAN_QTABLE(j, vf->lan_vsi_id), reg);
+		i40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(j, vf->lan_vsi_id),
+				  reg);
 	}
 
 	i40e_flush(hw);
@@ -977,7 +981,7 @@
 		i40e_free_vfs(pf);
 err_iov:
 	/* Re-enable interrupt 0. */
-	i40e_irq_dynamic_enable_icr0(pf);
+	i40e_irq_dynamic_enable_icr0(pf, false);
 	return ret;
 }
 
@@ -1094,8 +1098,8 @@
 	/* single place to detect unsuccessful return values */
 	if (v_retval) {
 		vf->num_invalid_msgs++;
-		dev_err(&pf->pdev->dev, "Failed opcode %d Error: %d\n",
-			v_opcode, v_retval);
+		dev_err(&pf->pdev->dev, "VF %d failed opcode %d, error: %d\n",
+			vf->vf_id, v_opcode, v_retval);
 		if (vf->num_invalid_msgs >
 		    I40E_DEFAULT_NUM_INVALID_MSGS_ALLOWED) {
 			dev_err(&pf->pdev->dev,
@@ -1210,9 +1214,21 @@
 		vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG;
 	}
 
+	if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) {
+		if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
+			vfres->vf_offload_flags |=
+				I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2;
+	}
+
 	if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING)
 		vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING;
 
+	if (pf->flags & I40E_FLAG_WB_ON_ITR_CAPABLE) {
+		if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
+			vfres->vf_offload_flags |=
+					I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
+	}
+
 	vfres->num_vsis = num_vsis;
 	vfres->num_queue_pairs = vf->num_queue_pairs;
 	vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
@@ -1623,7 +1639,8 @@
 
 		if (!f) {
 			dev_err(&pf->pdev->dev,
-				"Unable to add VF MAC filter\n");
+				"Unable to add MAC filter %pM for VF %d\n",
+				 al->list[i].addr, vf->vf_id);
 			ret = I40E_ERR_PARAM;
 			spin_unlock_bh(&vsi->mac_filter_list_lock);
 			goto error_param;
@@ -1632,8 +1649,10 @@
 	spin_unlock_bh(&vsi->mac_filter_list_lock);
 
 	/* program the updated filter list */
-	if (i40e_sync_vsi_filters(vsi, false))
-		dev_err(&pf->pdev->dev, "Unable to program VF MAC filters\n");
+	ret = i40e_sync_vsi_filters(vsi);
+	if (ret)
+		dev_err(&pf->pdev->dev, "Unable to program VF %d MAC filters, error %d\n",
+			vf->vf_id, ret);
 
 error_param:
 	/* send the response to the VF */
@@ -1669,24 +1688,40 @@
 	for (i = 0; i < al->num_elements; i++) {
 		if (is_broadcast_ether_addr(al->list[i].addr) ||
 		    is_zero_ether_addr(al->list[i].addr)) {
-			dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n",
-				al->list[i].addr);
+			dev_err(&pf->pdev->dev, "Invalid MAC addr %pM for VF %d\n",
+				al->list[i].addr, vf->vf_id);
 			ret = I40E_ERR_INVALID_MAC_ADDR;
 			goto error_param;
 		}
+
+		if (vf->pf_set_mac &&
+		    ether_addr_equal(al->list[i].addr,
+				     vf->default_lan_addr.addr)) {
+			dev_err(&pf->pdev->dev,
+				"MAC addr %pM has been set by PF, cannot delete it for VF %d, reset VF to change MAC addr\n",
+				vf->default_lan_addr.addr, vf->vf_id);
+			ret = I40E_ERR_PARAM;
+			goto error_param;
+		}
 	}
 	vsi = pf->vsi[vf->lan_vsi_idx];
 
 	spin_lock_bh(&vsi->mac_filter_list_lock);
 	/* delete addresses from the list */
 	for (i = 0; i < al->num_elements; i++)
-		i40e_del_filter(vsi, al->list[i].addr,
-				I40E_VLAN_ANY, true, false);
+		if (i40e_del_mac_all_vlan(vsi, al->list[i].addr, true, false)) {
+			ret = I40E_ERR_INVALID_MAC_ADDR;
+			spin_unlock_bh(&vsi->mac_filter_list_lock);
+			goto error_param;
+		}
+
 	spin_unlock_bh(&vsi->mac_filter_list_lock);
 
 	/* program the updated filter list */
-	if (i40e_sync_vsi_filters(vsi, false))
-		dev_err(&pf->pdev->dev, "Unable to program VF MAC filters\n");
+	ret = i40e_sync_vsi_filters(vsi);
+	if (ret)
+		dev_err(&pf->pdev->dev, "Unable to program VF %d MAC filters, error %d\n",
+			vf->vf_id, ret);
 
 error_param:
 	/* send the response to the VF */
@@ -1740,8 +1775,8 @@
 
 		if (ret)
 			dev_err(&pf->pdev->dev,
-				"Unable to add VF vlan filter %d, error %d\n",
-				vfl->vlan_id[i], ret);
+				"Unable to add VLAN filter %d for VF %d, error %d\n",
+				vfl->vlan_id[i], vf->vf_id, ret);
 	}
 
 error_param:
@@ -1792,8 +1827,8 @@
 
 		if (ret)
 			dev_err(&pf->pdev->dev,
-				"Unable to delete VF vlan filter %d, error %d\n",
-				vfl->vlan_id[i], ret);
+				"Unable to delete VLAN filter %d for VF %d, error %d\n",
+				vfl->vlan_id[i], vf->vf_id, ret);
 	}
 
 error_param:
@@ -2013,7 +2048,11 @@
 	if (!test_bit(__I40E_VFLR_EVENT_PENDING, &pf->state))
 		return 0;
 
-	/* re-enable vflr interrupt cause */
+	/* Re-enable the VFLR interrupt cause here, before looking for which
+	 * VF got reset. Otherwise, if another VF gets a reset while the
+	 * first one is being processed, that interrupt will be lost, and
+	 * that VF will be stuck in reset forever.
+	 */
 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
 	reg |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
@@ -2066,15 +2105,15 @@
 	vf = &(pf->vf[vf_id]);
 	vsi = pf->vsi[vf->lan_vsi_idx];
 	if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
-		dev_err(&pf->pdev->dev,
-			"Uninitialized VF %d\n", vf_id);
-		ret = -EINVAL;
+		dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+			vf_id);
+		ret = -EAGAIN;
 		goto error_param;
 	}
 
-	if (!is_valid_ether_addr(mac)) {
+	if (is_multicast_ether_addr(mac)) {
 		dev_err(&pf->pdev->dev,
-			"Invalid VF ethernet address\n");
+			"Invalid Ethernet address %pM for VF %d\n", mac, vf_id);
 		ret = -EINVAL;
 		goto error_param;
 	}
@@ -2085,9 +2124,10 @@
 	spin_lock_bh(&vsi->mac_filter_list_lock);
 
 	/* delete the temporary mac address */
-	i40e_del_filter(vsi, vf->default_lan_addr.addr,
-			vf->port_vlan_id ? vf->port_vlan_id : -1,
-			true, false);
+	if (!is_zero_ether_addr(vf->default_lan_addr.addr))
+		i40e_del_filter(vsi, vf->default_lan_addr.addr,
+				vf->port_vlan_id ? vf->port_vlan_id : -1,
+				true, false);
 
 	/* Delete all the filters for this VSI - we're going to kill it
 	 * anyway.
@@ -2099,7 +2139,7 @@
 
 	dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id);
 	/* program mac filter */
-	if (i40e_sync_vsi_filters(vsi, false)) {
+	if (i40e_sync_vsi_filters(vsi)) {
 		dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
 		ret = -EIO;
 		goto error_param;
@@ -2150,8 +2190,9 @@
 	vf = &(pf->vf[vf_id]);
 	vsi = pf->vsi[vf->lan_vsi_idx];
 	if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
-		dev_err(&pf->pdev->dev, "Uninitialized VF %d\n", vf_id);
-		ret = -EINVAL;
+		dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+			vf_id);
+		ret = -EAGAIN;
 		goto error_pvid;
 	}
 
@@ -2172,6 +2213,8 @@
 		 * and then reloading the VF driver.
 		 */
 		i40e_vc_disable_vf(pf, vf);
+		/* During reset the VF got a new VSI, so refresh the pointer. */
+		vsi = pf->vsi[vf->lan_vsi_idx];
 	}
 
 	/* Check for condition where there was already a port VLAN ID
@@ -2270,8 +2313,9 @@
 	vf = &(pf->vf[vf_id]);
 	vsi = pf->vsi[vf->lan_vsi_idx];
 	if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
-		dev_err(&pf->pdev->dev, "Uninitialized VF %d.\n", vf_id);
-		ret = -EINVAL;
+		dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+			vf_id);
+		ret = -EAGAIN;
 		goto error;
 	}
 
@@ -2279,6 +2323,9 @@
 	case I40E_LINK_SPEED_40GB:
 		speed = 40000;
 		break;
+	case I40E_LINK_SPEED_20GB:
+		speed = 20000;
+		break;
 	case I40E_LINK_SPEED_10GB:
 		speed = 10000;
 		break;
@@ -2344,8 +2391,9 @@
 	/* first vsi is always the LAN vsi */
 	vsi = pf->vsi[vf->lan_vsi_idx];
 	if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
-		dev_err(&pf->pdev->dev, "Uninitialized VF %d\n", vf_id);
-		ret = -EINVAL;
+		dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+			vf_id);
+		ret = -EAGAIN;
 		goto error_param;
 	}
 
@@ -2460,6 +2508,12 @@
 	}
 
 	vf = &(pf->vf[vf_id]);
+	if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
+		dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+			vf_id);
+		ret = -EAGAIN;
+		goto out;
+	}
 
 	if (enable == vf->spoofchk)
 		goto out;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -91,8 +91,8 @@
 	 * When assigned, these will be non-zero, because VSI 0 is always
 	 * the main LAN VSI for the PF.
 	 */
-	u8 lan_vsi_idx;	        /* index into PF struct */
-	u8 lan_vsi_id;		/* ID as used by firmware */
+	u16 lan_vsi_idx;	/* index into PF struct */
+	u16 lan_vsi_id;		/* ID as used by firmware */
 
 	u8 num_queue_pairs;	/* num of qps assigned to VF vsis */
 	u64 num_mdd_events;	/* num of mdd events detected */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -887,6 +887,9 @@
 	u16 flags;
 	u16 ntu;
 
+	/* pre-clean the event info */
+	memset(&e->desc, 0, sizeof(e->desc));
+
 	/* take the lock before we start messing with the ring */
 	mutex_lock(&hw->aq.arq_mutex);
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -34,7 +34,7 @@
  */
 
 #define I40E_FW_API_VERSION_MAJOR	0x0001
-#define I40E_FW_API_VERSION_MINOR	0x0004
+#define I40E_FW_API_VERSION_MINOR	0x0005
 
 struct i40e_aq_desc {
 	__le16 flags;
@@ -145,6 +145,9 @@
 	i40e_aqc_opc_remove_statistics		= 0x0202,
 	i40e_aqc_opc_set_port_parameters	= 0x0203,
 	i40e_aqc_opc_get_switch_resource_alloc	= 0x0204,
+	i40e_aqc_opc_set_switch_config		= 0x0205,
+	i40e_aqc_opc_rx_ctl_reg_read		= 0x0206,
+	i40e_aqc_opc_rx_ctl_reg_write		= 0x0207,
 
 	i40e_aqc_opc_add_vsi			= 0x0210,
 	i40e_aqc_opc_update_vsi_parameters	= 0x0211,
@@ -220,6 +223,7 @@
 	i40e_aqc_opc_get_phy_wol_caps		= 0x0621,
 	i40e_aqc_opc_set_phy_debug		= 0x0622,
 	i40e_aqc_opc_upload_ext_phy_fm		= 0x0625,
+	i40e_aqc_opc_run_phy_activity		= 0x0626,
 
 	/* NVM commands */
 	i40e_aqc_opc_nvm_read			= 0x0701,
@@ -227,6 +231,8 @@
 	i40e_aqc_opc_nvm_update			= 0x0703,
 	i40e_aqc_opc_nvm_config_read		= 0x0704,
 	i40e_aqc_opc_nvm_config_write		= 0x0705,
+	i40e_aqc_opc_oem_post_update		= 0x0720,
+	i40e_aqc_opc_thermal_sensor		= 0x0721,
 
 	/* virtualization commands */
 	i40e_aqc_opc_send_msg_to_pf		= 0x0801,
@@ -398,6 +404,7 @@
 #define I40E_AQ_CAP_ID_OS2BMC_CAP	0x0004
 #define I40E_AQ_CAP_ID_FUNCTIONS_VALID	0x0005
 #define I40E_AQ_CAP_ID_ALTERNATE_RAM	0x0006
+#define I40E_AQ_CAP_ID_WOL_AND_PROXY	0x0008
 #define I40E_AQ_CAP_ID_SRIOV		0x0012
 #define I40E_AQ_CAP_ID_VF		0x0013
 #define I40E_AQ_CAP_ID_VMDQ		0x0014
@@ -418,6 +425,7 @@
 #define I40E_AQ_CAP_ID_LED		0x0061
 #define I40E_AQ_CAP_ID_SDP		0x0062
 #define I40E_AQ_CAP_ID_MDIO		0x0063
+#define I40E_AQ_CAP_ID_WSR_PROT		0x0064
 #define I40E_AQ_CAP_ID_FLEX10		0x00F1
 #define I40E_AQ_CAP_ID_CEM		0x00F2
 
@@ -676,6 +684,31 @@
 
 I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
 
+/* Set Switch Configuration (direct 0x0205) */
+struct i40e_aqc_set_switch_config {
+	__le16	flags;
+#define I40E_AQ_SET_SWITCH_CFG_PROMISC		0x0001
+#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER	0x0002
+	__le16	valid_flags;
+	u8	reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
+
+/* Read Receive control registers  (direct 0x0206)
+ * Write Receive control registers (direct 0x0207)
+ *     used for accessing Rx control registers that can be
+ *     slow and need special handling when under high Rx load
+ */
+struct i40e_aqc_rx_ctl_reg_read_write {
+	__le32 reserved1;
+	__le32 address;
+	__le32 reserved2;
+	__le32 value;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_rx_ctl_reg_read_write);
+
 /* Add VSI (indirect 0x0210)
  *    this indirect command uses struct i40e_aqc_vsi_properties_data
  *    as the indirect buffer (128 bytes)
@@ -902,7 +935,8 @@
 					I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT	0x2
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DATA		0x4
-#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER	0x8
+#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER	0x8     /* deprecated */
+#define I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS	0x10
 	u8	enable_tcs;
 	u8	reserved[9];
 };
@@ -969,6 +1003,7 @@
 #define I40E_AQC_MACVLAN_ADD_HASH_MATCH		0x0002
 #define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN	0x0004
 #define I40E_AQC_MACVLAN_ADD_TO_QUEUE		0x0008
+#define I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC	0x0010
 	__le16	queue_number;
 #define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT	0
 #define I40E_AQC_MACVLAN_CMD_QUEUE_MASK		(0x7FF << \
@@ -1065,6 +1100,7 @@
 #define I40E_AQC_SET_VSI_PROMISC_BROADCAST	0x04
 #define I40E_AQC_SET_VSI_DEFAULT		0x08
 #define I40E_AQC_SET_VSI_PROMISC_VLAN		0x10
+#define I40E_AQC_SET_VSI_PROMISC_TX		0x8000
 	__le16	seid;
 #define I40E_AQC_VSI_PROM_CMD_SEID_MASK		0x3FF
 	__le16	vlan_tag;
@@ -1253,10 +1289,16 @@
 
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT		9
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK		0x1E00
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_XVLAN		0
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN		0
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC		1
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE			2
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE		2
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP			3
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_RESERVED		4
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE		5
+
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_MAC	0x2000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_INNER_MAC	0x4000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_IP	0x8000
 
 	__le32	tenant_id;
 	u8	reserved[4];
@@ -1751,7 +1793,12 @@
 	u8	config;
 #define I40E_AQ_CONFIG_CRC_ENA		0x04
 #define I40E_AQ_CONFIG_PACING_MASK	0x78
-	u8	reserved[5];
+	u8	external_power_ability;
+#define I40E_AQ_LINK_POWER_CLASS_1	0x00
+#define I40E_AQ_LINK_POWER_CLASS_2	0x01
+#define I40E_AQ_LINK_POWER_CLASS_3	0x02
+#define I40E_AQ_LINK_POWER_CLASS_4	0x03
+	u8	reserved[4];
 };
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
@@ -1819,6 +1866,18 @@
 	I40E_AQC_PHY_REG_EXERNAL_MODULE	= 0x3
 };
 
+/* Run PHY Activity (0x0626) */
+struct i40e_aqc_run_phy_activity {
+	__le16  activity_id;
+	u8      flags;
+	u8      reserved1;
+	__le32  control;
+	__le32  data;
+	u8      reserved2[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity);
+
 /* NVM Read command (indirect 0x0701)
  * NVM Erase commands (direct 0x0702)
  * NVM Update commands (indirect 0x0703)
@@ -1888,6 +1947,42 @@
 
 I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field);
 
+/* OEM Post Update (indirect 0x0720)
+ * no command data struct used
+ */
+ struct i40e_aqc_nvm_oem_post_update {
+#define I40E_AQ_NVM_OEM_POST_UPDATE_EXTERNAL_DATA	0x01
+	u8 sel_data;
+	u8 reserved[7];
+};
+
+I40E_CHECK_STRUCT_LEN(0x8, i40e_aqc_nvm_oem_post_update);
+
+struct i40e_aqc_nvm_oem_post_update_buffer {
+	u8 str_len;
+	u8 dev_addr;
+	__le16 eeprom_addr;
+	u8 data[36];
+};
+
+I40E_CHECK_STRUCT_LEN(0x28, i40e_aqc_nvm_oem_post_update_buffer);
+
+/* Thermal Sensor (indirect 0x0721)
+ *     read or set thermal sensor configs and values
+ *     takes a sensor and command specific data buffer, not detailed here
+ */
+struct i40e_aqc_thermal_sensor {
+	u8 sensor_action;
+#define I40E_AQ_THERMAL_SENSOR_READ_CONFIG	0
+#define I40E_AQ_THERMAL_SENSOR_SET_CONFIG	1
+#define I40E_AQ_THERMAL_SENSOR_READ_TEMP	2
+	u8 reserved[7];
+	__le32	addr_high;
+	__le32	addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_thermal_sensor);
+
 /* Send to PF command (indirect 0x0801) id is only used by PF
  * Send to VF command (indirect 0x0802) id is only used by PF
  * Send to Peer PF command (indirect 0x0803)
@@ -2062,6 +2157,7 @@
 #define I40E_AQC_TUNNEL_TYPE_VXLAN	0x00
 #define I40E_AQC_TUNNEL_TYPE_NGE	0x01
 #define I40E_AQC_TUNNEL_TYPE_TEREDO	0x10
+#define I40E_AQC_TUNNEL_TYPE_VXLAN_GPE	0x11
 	u8	reserved1[10];
 };
 
@@ -2311,4 +2407,4 @@
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_internals);
 
-#endif
+#endif /* _I40E_ADMINQ_CMD_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40e_common.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40e_common.c
@@ -44,7 +44,6 @@
 		switch (hw->device_id) {
 		case I40E_DEV_ID_SFP_XL710:
 		case I40E_DEV_ID_QEMU:
-		case I40E_DEV_ID_KX_A:
 		case I40E_DEV_ID_KX_B:
 		case I40E_DEV_ID_KX_C:
 		case I40E_DEV_ID_QSFP_A:
@@ -905,6 +904,131 @@
 };
 
 /**
+ * i40evf_aq_rx_ctl_read_register - use FW to read from an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: ptr to register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Use the firmware to read the Rx control register,
+ * especially useful if the Rx unit is under heavy pressure
+ **/
+i40e_status i40evf_aq_rx_ctl_read_register(struct i40e_hw *hw,
+				u32 reg_addr, u32 *reg_val,
+				struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_rx_ctl_reg_read_write *cmd_resp =
+		(struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
+	i40e_status status;
+
+	if (!reg_val)
+		return I40E_ERR_PARAM;
+
+	i40evf_fill_default_direct_cmd_desc(&desc,
+					    i40e_aqc_opc_rx_ctl_reg_read);
+
+	cmd_resp->address = cpu_to_le32(reg_addr);
+
+	status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+	if (status == 0)
+		*reg_val = le32_to_cpu(cmd_resp->value);
+
+	return status;
+}
+
+/**
+ * i40evf_read_rx_ctl - read from an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ **/
+u32 i40evf_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr)
+{
+	i40e_status status = 0;
+	bool use_register;
+	int retry = 5;
+	u32 val = 0;
+
+	use_register = (hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver < 5);
+	if (!use_register) {
+do_retry:
+		status = i40evf_aq_rx_ctl_read_register(hw, reg_addr,
+							&val, NULL);
+		if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
+			usleep_range(1000, 2000);
+			retry--;
+			goto do_retry;
+		}
+	}
+
+	/* if the AQ access failed, try the old-fashioned way */
+	if (status || use_register)
+		val = rd32(hw, reg_addr);
+
+	return val;
+}
+
+/**
+ * i40evf_aq_rx_ctl_write_register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Use the firmware to write to an Rx control register,
+ * especially useful if the Rx unit is under heavy pressure
+ **/
+i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw,
+				u32 reg_addr, u32 reg_val,
+				struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_rx_ctl_reg_read_write *cmd =
+		(struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
+	i40e_status status;
+
+	i40evf_fill_default_direct_cmd_desc(&desc,
+					    i40e_aqc_opc_rx_ctl_reg_write);
+
+	cmd->address = cpu_to_le32(reg_addr);
+	cmd->value = cpu_to_le32(reg_val);
+
+	status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+	return status;
+}
+
+/**
+ * i40evf_write_rx_ctl - write to an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ **/
+void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
+{
+	i40e_status status = 0;
+	bool use_register;
+	int retry = 5;
+
+	use_register = (hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver < 5);
+	if (!use_register) {
+do_retry:
+		status = i40evf_aq_rx_ctl_write_register(hw, reg_addr,
+							 reg_val, NULL);
+		if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
+			usleep_range(1000, 2000);
+			retry--;
+			goto do_retry;
+		}
+	}
+
+	/* if the AQ access failed, try the old-fashioned way */
+	if (status || use_register)
+		wr32(hw, reg_addr, reg_val);
+}
+
+/**
  * i40e_aq_send_msg_to_pf
  * @hw: pointer to the hardware structure
  * @v_opcode: opcodes for VF-PF communication
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40e_devids.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40e_devids.h
@@ -30,7 +30,6 @@
 /* Device IDs */
 #define I40E_DEV_ID_SFP_XL710		0x1572
 #define I40E_DEV_ID_QEMU		0x1574
-#define I40E_DEV_ID_KX_A		0x157F
 #define I40E_DEV_ID_KX_B		0x1580
 #define I40E_DEV_ID_KX_C		0x1581
 #define I40E_DEV_ID_QSFP_A		0x1583
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
@@ -103,4 +103,19 @@
 				struct i40e_asq_cmd_details *cmd_details);
 void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
 						    u16 vsi_seid);
+i40e_status i40evf_aq_rx_ctl_read_register(struct i40e_hw *hw,
+				u32 reg_addr, u32 *reg_val,
+				struct i40e_asq_cmd_details *cmd_details);
+u32 i40evf_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr);
+i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw,
+				u32 reg_addr, u32 reg_val,
+				struct i40e_asq_cmd_details *cmd_details);
+void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
+i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page,
+				   u16 reg, u8 phy_addr, u16 *value);
+i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page,
+				    u16 reg, u8 phy_addr, u16 value);
+u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
+i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
+				    u32 time, u32 interval);
 #endif /* _I40E_PROTOTYPE_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -51,11 +51,7 @@
 					    struct i40e_tx_buffer *tx_buffer)
 {
 	if (tx_buffer->skb) {
-		if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
-			kfree(tx_buffer->raw_buf);
-		else
-			dev_kfree_skb_any(tx_buffer->skb);
-
+		dev_kfree_skb_any(tx_buffer->skb);
 		if (dma_unmap_len(tx_buffer, len))
 			dma_unmap_single(ring->dev,
 					 dma_unmap_addr(tx_buffer, dma),
@@ -67,6 +63,10 @@
 			       dma_unmap_len(tx_buffer, len),
 			       DMA_TO_DEVICE);
 	}
+
+	if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
+		kfree(tx_buffer->raw_buf);
+
 	tx_buffer->next_to_watch = NULL;
 	tx_buffer->skb = NULL;
 	dma_unmap_len_set(tx_buffer, len, 0);
@@ -127,17 +127,28 @@
 }
 
 /**
- * i40e_get_head - Retrieve head from head writeback
- * @tx_ring:  tx ring to fetch head of
+ * i40evf_get_tx_pending - how many Tx descriptors not processed
+ * @tx_ring: the ring of descriptors
+ * @in_sw: is tx_pending being checked in SW or HW
  *
- * Returns value of Tx ring head based on value stored
- * in head write-back location
+ * Since there is no access to the ring head register
+ * in XL710, we need to use our local copies
  **/
-static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw)
 {
-	void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+	u32 head, tail;
 
-	return le32_to_cpu(*(volatile __le32 *)head);
+	if (!in_sw)
+		head = i40e_get_head(ring);
+	else
+		head = ring->next_to_clean;
+	tail = readl(ring->tail);
+
+	if (head != tail)
+		return (head < tail) ?
+			tail - head : (tail + ring->count - head);
+
+	return 0;
 }
 
 #define WB_STRIDE 0x3
@@ -172,7 +183,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		read_barrier_depends();
+		smp_rmb();
 
 		/* we have caught up to head, no work left to do */
 		if (tx_head == tx_desc)
@@ -245,15 +256,21 @@
 	tx_ring->q_vector->tx.total_bytes += total_bytes;
 	tx_ring->q_vector->tx.total_packets += total_packets;
 
-	/* check to see if there are any non-cache aligned descriptors
-	 * waiting to be written back, and kick the hardware to force
-	 * them to be written back in case of napi polling
-	 */
-	if (budget &&
-	    !((i & WB_STRIDE) == WB_STRIDE) &&
-	    !test_bit(__I40E_DOWN, &tx_ring->vsi->state) &&
-	    (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
-		tx_ring->arm_wb = true;
+	if (tx_ring->flags & I40E_TXR_FLAGS_WB_ON_ITR) {
+		unsigned int j = 0;
+		/* check to see if there are < 4 descriptors
+		 * waiting to be written back, then kick the hardware to force
+		 * them to be written back in case we stay in NAPI.
+		 * In this mode on X722 we do not enable Interrupt.
+		 */
+		j = i40evf_get_tx_pending(tx_ring, false);
+
+		if (budget &&
+		    ((j / (WB_STRIDE + 1)) == 0) && (j > 0) &&
+		    !test_bit(__I40E_DOWN, &tx_ring->vsi->state) &&
+		    (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
+			tx_ring->arm_wb = true;
+	}
 
 	netdev_tx_completed_queue(netdev_get_tx_queue(tx_ring->netdev,
 						      tx_ring->queue_index),
@@ -279,39 +296,49 @@
 }
 
 /**
- * i40evf_force_wb -Arm hardware to do a wb on noncache aligned descriptors
+ * i40evf_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled
  * @vsi: the VSI we care about
- * @q_vector: the vector  on which to force writeback
+ * @q_vector: the vector on which to enable writeback
  *
  **/
-static void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi,
+				  struct i40e_q_vector *q_vector)
 {
 	u16 flags = q_vector->tx.ring[0].flags;
+	u32 val;
 
-	if (flags & I40E_TXR_FLAGS_WB_ON_ITR) {
-		u32 val;
+	if (!(flags & I40E_TXR_FLAGS_WB_ON_ITR))
+		return;
 
-		if (q_vector->arm_wb_state)
-			return;
+	if (q_vector->arm_wb_state)
+		return;
 
-		val = I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK;
+	val = I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK |
+	      I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK; /* set noitr */
 
-		wr32(&vsi->back->hw,
-		     I40E_VFINT_DYN_CTLN1(q_vector->v_idx +
-					  vsi->base_vector - 1),
-		     val);
-		q_vector->arm_wb_state = true;
-	} else {
-		u32 val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
-			  I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */
-			  I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK |
-			  I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK;
-			  /* allow 00 to be written to the index */
-
-		wr32(&vsi->back->hw,
-		     I40E_VFINT_DYN_CTLN1(q_vector->v_idx +
-					  vsi->base_vector - 1), val);
-	}
+	wr32(&vsi->back->hw,
+	     I40E_VFINT_DYN_CTLN1(q_vector->v_idx +
+				  vsi->base_vector - 1), val);
+	q_vector->arm_wb_state = true;
+}
+
+/**
+ * i40evf_force_wb - Issue SW Interrupt so HW does a wb
+ * @vsi: the VSI we care about
+ * @q_vector: the vector  on which to force writeback
+ *
+ **/
+void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+{
+	u32 val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
+		  I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */
+		  I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK |
+		  I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK
+		  /* allow 00 to be written to the index */;
+
+	wr32(&vsi->back->hw,
+	     I40E_VFINT_DYN_CTLN1(q_vector->v_idx + vsi->base_vector - 1),
+	     val);
 }
 
 /**
@@ -414,7 +441,7 @@
 	return false;
 }
 
-/*
+/**
  * i40evf_setup_tx_descriptors - Allocate the Tx descriptors
  * @tx_ring: the tx ring to set up
  *
@@ -509,7 +536,7 @@
 			if (rx_bi->page_dma) {
 				dma_unmap_page(dev,
 					       rx_bi->page_dma,
-					       PAGE_SIZE / 2,
+					       PAGE_SIZE,
 					       DMA_FROM_DEVICE);
 				rx_bi->page_dma = 0;
 			}
@@ -644,16 +671,19 @@
  * i40evf_alloc_rx_buffers_ps - Replace used receive buffers; packet split
  * @rx_ring: ring to place buffers on
  * @cleaned_count: number of buffers to replace
+ *
+ * Returns true if any errors on allocation
  **/
-void i40evf_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool i40evf_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
 {
 	u16 i = rx_ring->next_to_use;
 	union i40e_rx_desc *rx_desc;
 	struct i40e_rx_buffer *bi;
+	const int current_node = numa_node_id();
 
 	/* do nothing if no valid netdev defined */
 	if (!rx_ring->netdev || !cleaned_count)
-		return;
+		return false;
 
 	while (cleaned_count--) {
 		rx_desc = I40E_RX_DESC(rx_ring, i);
@@ -661,56 +691,79 @@
 
 		if (bi->skb) /* desc is in use */
 			goto no_buffers;
+
+	/* If we've been moved to a different NUMA node, release the
+	 * page so we can get a new one on the current node.
+	 */
+		if (bi->page &&  page_to_nid(bi->page) != current_node) {
+			dma_unmap_page(rx_ring->dev,
+				       bi->page_dma,
+				       PAGE_SIZE,
+				       DMA_FROM_DEVICE);
+			__free_page(bi->page);
+			bi->page = NULL;
+			bi->page_dma = 0;
+			rx_ring->rx_stats.realloc_count++;
+		} else if (bi->page) {
+			rx_ring->rx_stats.page_reuse_count++;
+		}
+
 		if (!bi->page) {
 			bi->page = alloc_page(GFP_ATOMIC);
 			if (!bi->page) {
 				rx_ring->rx_stats.alloc_page_failed++;
 				goto no_buffers;
 			}
-		}
-
-		if (!bi->page_dma) {
-			/* use a half page if we're re-using */
-			bi->page_offset ^= PAGE_SIZE / 2;
 			bi->page_dma = dma_map_page(rx_ring->dev,
 						    bi->page,
-						    bi->page_offset,
-						    PAGE_SIZE / 2,
+						    0,
+						    PAGE_SIZE,
 						    DMA_FROM_DEVICE);
-			if (dma_mapping_error(rx_ring->dev,
-					      bi->page_dma)) {
+			if (dma_mapping_error(rx_ring->dev, bi->page_dma)) {
 				rx_ring->rx_stats.alloc_page_failed++;
+				__free_page(bi->page);
+				bi->page = NULL;
 				bi->page_dma = 0;
+				bi->page_offset = 0;
 				goto no_buffers;
 			}
+			bi->page_offset = 0;
 		}
 
-		dma_sync_single_range_for_device(rx_ring->dev,
-						 bi->dma,
-						 0,
-						 rx_ring->rx_hdr_len,
-						 DMA_FROM_DEVICE);
 		/* Refresh the desc even if buffer_addrs didn't change
 		 * because each write-back erases this info.
 		 */
-		rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+		rx_desc->read.pkt_addr =
+				cpu_to_le64(bi->page_dma + bi->page_offset);
 		rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
 		i++;
 		if (i == rx_ring->count)
 			i = 0;
 	}
 
+	if (rx_ring->next_to_use != i)
+		i40e_release_rx_desc(rx_ring, i);
+
+	return false;
+
 no_buffers:
 	if (rx_ring->next_to_use != i)
 		i40e_release_rx_desc(rx_ring, i);
+
+	/* make sure to come back via polling to try again after
+	 * allocation failure
+	 */
+	return true;
 }
 
 /**
  * i40evf_alloc_rx_buffers_1buf - Replace used receive buffers; single buffer
  * @rx_ring: ring to place buffers on
  * @cleaned_count: number of buffers to replace
+ *
+ * Returns true if any errors on allocation
  **/
-void i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
 {
 	u16 i = rx_ring->next_to_use;
 	union i40e_rx_desc *rx_desc;
@@ -719,7 +772,7 @@
 
 	/* do nothing if no valid netdev defined */
 	if (!rx_ring->netdev || !cleaned_count)
-		return;
+		return false;
 
 	while (cleaned_count--) {
 		rx_desc = I40E_RX_DESC(rx_ring, i);
@@ -727,8 +780,10 @@
 		skb = bi->skb;
 
 		if (!skb) {
-			skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-							rx_ring->rx_buf_len);
+			skb = __netdev_alloc_skb_ip_align(rx_ring->netdev,
+							  rx_ring->rx_buf_len,
+							  GFP_ATOMIC |
+							  __GFP_NOWARN);
 			if (!skb) {
 				rx_ring->rx_stats.alloc_buff_failed++;
 				goto no_buffers;
@@ -746,6 +801,8 @@
 			if (dma_mapping_error(rx_ring->dev, bi->dma)) {
 				rx_ring->rx_stats.alloc_buff_failed++;
 				bi->dma = 0;
+				dev_kfree_skb(bi->skb);
+				bi->skb = NULL;
 				goto no_buffers;
 			}
 		}
@@ -757,9 +814,19 @@
 			i = 0;
 	}
 
+	if (rx_ring->next_to_use != i)
+		i40e_release_rx_desc(rx_ring, i);
+
+	return false;
+
 no_buffers:
 	if (rx_ring->next_to_use != i)
 		i40e_release_rx_desc(rx_ring, i);
+
+	/* make sure to come back via polling to try again after
+	 * allocation failure
+	 */
+	return true;
 }
 
 /**
@@ -794,16 +861,7 @@
 				    u16 rx_ptype)
 {
 	struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype);
-	bool ipv4 = false, ipv6 = false;
-	bool ipv4_tunnel, ipv6_tunnel;
-	__wsum rx_udp_csum;
-	struct iphdr *iph;
-	__sum16 csum;
-
-	ipv4_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
-		     (rx_ptype <= I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
-	ipv6_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
-		     (rx_ptype <= I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
+	bool ipv4, ipv6, ipv4_tunnel, ipv6_tunnel;
 
 	skb->ip_summed = CHECKSUM_NONE;
 
@@ -819,12 +877,10 @@
 	if (!(decoded.known && decoded.outer_ip))
 		return;
 
-	if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
-	    decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4)
-		ipv4 = true;
-	else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
-		 decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6)
-		ipv6 = true;
+	ipv4 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
+	       (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4);
+	ipv6 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
+	       (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6);
 
 	if (ipv4 &&
 	    (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) |
@@ -848,36 +904,17 @@
 	if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT))
 		return;
 
-	/* If VXLAN traffic has an outer UDPv4 checksum we need to check
-	 * it in the driver, hardware does not do it for us.
-	 * Since L3L4P bit was set we assume a valid IHL value (>=5)
-	 * so the total length of IPv4 header is IHL*4 bytes
-	 * The UDP_0 bit *may* bet set if the *inner* header is UDP
+	/* The hardware supported by this driver does not validate outer
+	 * checksums for tunneled VXLAN or GENEVE frames.  I don't agree
+	 * with it but the specification states that you "MAY validate", it
+	 * doesn't make it a hard requirement so if we have validated the
+	 * inner checksum report CHECKSUM_UNNECESSARY.
 	 */
-	if (ipv4_tunnel) {
-		skb->transport_header = skb->mac_header +
-					sizeof(struct ethhdr) +
-					(ip_hdr(skb)->ihl * 4);
-
-		/* Add 4 bytes for VLAN tagged packets */
-		skb->transport_header += (skb->protocol == htons(ETH_P_8021Q) ||
-					  skb->protocol == htons(ETH_P_8021AD))
-					  ? VLAN_HLEN : 0;
-
-		if ((ip_hdr(skb)->protocol == IPPROTO_UDP) &&
-		    (udp_hdr(skb)->check != 0)) {
-			rx_udp_csum = udp_csum(skb);
-			iph = ip_hdr(skb);
-			csum = csum_tcpudp_magic(iph->saddr, iph->daddr,
-						 (skb->len -
-						  skb_transport_offset(skb)),
-						 IPPROTO_UDP, rx_udp_csum);
 
-			if (udp_hdr(skb)->check != csum)
-				goto checksum_fail;
-
-		} /* else its GRE and so no outer UDP header */
-	}
+	ipv4_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
+		     (rx_ptype <= I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
+	ipv6_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
+		     (rx_ptype <= I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
 
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
 	skb->csum_level = ipv4_tunnel || ipv6_tunnel;
@@ -889,31 +926,12 @@
 }
 
 /**
- * i40e_rx_hash - returns the hash value from the Rx descriptor
- * @ring: descriptor ring
- * @rx_desc: specific descriptor
- **/
-static inline u32 i40e_rx_hash(struct i40e_ring *ring,
-			       union i40e_rx_desc *rx_desc)
-{
-	const __le64 rss_mask =
-		cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
-			    I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
-
-	if ((ring->netdev->features & NETIF_F_RXHASH) &&
-	    (rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask)
-		return le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
-	else
-		return 0;
-}
-
-/**
- * i40e_ptype_to_hash - get a hash type
+ * i40e_ptype_to_htype - get a hash type
  * @ptype: the ptype value from the descriptor
  *
  * Returns a hash type to be used by skb_set_hash
  **/
-static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+static inline enum pkt_hash_types i40e_ptype_to_htype(u8 ptype)
 {
 	struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
 
@@ -931,24 +949,49 @@
 }
 
 /**
+ * i40e_rx_hash - set the hash value in the skb
+ * @ring: descriptor ring
+ * @rx_desc: specific descriptor
+ **/
+static inline void i40e_rx_hash(struct i40e_ring *ring,
+				union i40e_rx_desc *rx_desc,
+				struct sk_buff *skb,
+				u8 rx_ptype)
+{
+	u32 hash;
+	const __le64 rss_mask  =
+		cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
+			    I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
+
+	if (ring->netdev->features & NETIF_F_RXHASH)
+		return;
+
+	if ((rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) {
+		hash = le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
+		skb_set_hash(skb, hash, i40e_ptype_to_htype(rx_ptype));
+	}
+}
+
+/**
  * i40e_clean_rx_irq_ps - Reclaim resources after receive; packet split
  * @rx_ring:  rx ring to clean
  * @budget:   how many cleans we're allowed
  *
  * Returns true if there's any budget left (e.g. the clean is finished)
  **/
-static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
+static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, const int budget)
 {
 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
 	u16 rx_packet_len, rx_header_len, rx_sph, rx_hbo;
 	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
-	const int current_node = numa_mem_id();
 	struct i40e_vsi *vsi = rx_ring->vsi;
 	u16 i = rx_ring->next_to_clean;
 	union i40e_rx_desc *rx_desc;
 	u32 rx_error, rx_status;
+	bool failure = false;
 	u8 rx_ptype;
 	u64 qword;
+	u32 copysize;
 
 	do {
 		struct i40e_rx_buffer *rx_bi;
@@ -956,7 +999,9 @@
 		u16 vlan_tag;
 		/* return some buffers to hardware, one at a time is too slow */
 		if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
-			i40evf_alloc_rx_buffers_ps(rx_ring, cleaned_count);
+			failure = failure ||
+				  i40evf_alloc_rx_buffers_ps(rx_ring,
+							     cleaned_count);
 			cleaned_count = 0;
 		}
 
@@ -974,13 +1019,22 @@
 		 * DD bit is set.
 		 */
 		dma_rmb();
+		/* sync header buffer for reading */
+		dma_sync_single_range_for_cpu(rx_ring->dev,
+					      rx_ring->rx_bi[0].dma,
+					      i * rx_ring->rx_hdr_len,
+					      rx_ring->rx_hdr_len,
+					      DMA_FROM_DEVICE);
 		rx_bi = &rx_ring->rx_bi[i];
 		skb = rx_bi->skb;
 		if (likely(!skb)) {
-			skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-							rx_ring->rx_hdr_len);
+			skb = __netdev_alloc_skb_ip_align(rx_ring->netdev,
+							  rx_ring->rx_hdr_len,
+							  GFP_ATOMIC |
+							  __GFP_NOWARN);
 			if (!skb) {
 				rx_ring->rx_stats.alloc_buff_failed++;
+				failure = true;
 				break;
 			}
 
@@ -988,8 +1042,8 @@
 			skb_record_rx_queue(skb, rx_ring->queue_index);
 			/* we are reusing so sync this buffer for CPU use */
 			dma_sync_single_range_for_cpu(rx_ring->dev,
-						      rx_bi->dma,
-						      0,
+						      rx_ring->rx_bi[0].dma,
+						      i * rx_ring->rx_hdr_len,
 						      rx_ring->rx_hdr_len,
 						      DMA_FROM_DEVICE);
 		}
@@ -1007,9 +1061,16 @@
 
 		rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
 			   I40E_RXD_QW1_PTYPE_SHIFT;
-		prefetch(rx_bi->page);
+		/* sync half-page for reading */
+		dma_sync_single_range_for_cpu(rx_ring->dev,
+					      rx_bi->page_dma,
+					      rx_bi->page_offset,
+					      PAGE_SIZE / 2,
+					      DMA_FROM_DEVICE);
+		prefetch(page_address(rx_bi->page) + rx_bi->page_offset);
 		rx_bi->skb = NULL;
 		cleaned_count++;
+		copysize = 0;
 		if (rx_hbo || rx_sph) {
 			int len;
 
@@ -1020,38 +1081,50 @@
 			memcpy(__skb_put(skb, len), rx_bi->hdr_buf, len);
 		} else if (skb->len == 0) {
 			int len;
+			unsigned char *va = page_address(rx_bi->page) +
+					    rx_bi->page_offset;
 
-			len = (rx_packet_len > skb_headlen(skb) ?
-				skb_headlen(skb) : rx_packet_len);
-			memcpy(__skb_put(skb, len),
-			       rx_bi->page + rx_bi->page_offset,
-			       len);
-			rx_bi->page_offset += len;
+			len = min(rx_packet_len, rx_ring->rx_hdr_len);
+			memcpy(__skb_put(skb, len), va, len);
+			copysize = len;
 			rx_packet_len -= len;
 		}
-
 		/* Get the rest of the data if this was a header split */
 		if (rx_packet_len) {
-			skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
-					   rx_bi->page,
-					   rx_bi->page_offset,
-					   rx_packet_len);
-
-			skb->len += rx_packet_len;
-			skb->data_len += rx_packet_len;
-			skb->truesize += rx_packet_len;
-
-			if ((page_count(rx_bi->page) == 1) &&
-			    (page_to_nid(rx_bi->page) == current_node))
-				get_page(rx_bi->page);
-			else
+			skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+					rx_bi->page,
+					rx_bi->page_offset + copysize,
+					rx_packet_len, I40E_RXBUFFER_2048);
+
+			/* If the page count is more than 2, then both halves
+			 * of the page are used and we need to free it. Do it
+			 * here instead of in the alloc code. Otherwise one
+			 * of the half-pages might be released between now and
+			 * then, and we wouldn't know which one to use.
+			 * Don't call get_page and free_page since those are
+			 * both expensive atomic operations that just change
+			 * the refcount in opposite directions. Just give the
+			 * page to the stack; he can have our refcount.
+			 */
+			if (page_count(rx_bi->page) > 2) {
+				dma_unmap_page(rx_ring->dev,
+					       rx_bi->page_dma,
+					       PAGE_SIZE,
+					       DMA_FROM_DEVICE);
 				rx_bi->page = NULL;
+				rx_bi->page_dma = 0;
+				rx_ring->rx_stats.realloc_count++;
+			} else {
+				get_page(rx_bi->page);
+				/* switch to the other half-page here; the
+				 * allocation code programs the right addr
+				 * into HW. If we haven't used this half-page,
+				 * the address won't be changed, and HW can
+				 * just use it next time through.
+				 */
+				rx_bi->page_offset ^= PAGE_SIZE / 2;
+			}
 
-			dma_unmap_page(rx_ring->dev,
-				       rx_bi->page_dma,
-				       PAGE_SIZE / 2,
-				       DMA_FROM_DEVICE);
-			rx_bi->page_dma = 0;
 		}
 		I40E_RX_INCREMENT(rx_ring, i);
 
@@ -1071,8 +1144,8 @@
 			continue;
 		}
 
-		skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
-			     i40e_ptype_to_hash(rx_ptype));
+		i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
+
 		/* probably a little skewed due to removing CRC */
 		total_rx_bytes += skb->len;
 		total_rx_packets++;
@@ -1104,7 +1177,7 @@
 	rx_ring->q_vector->rx.total_packets += total_rx_packets;
 	rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
-	return total_rx_packets;
+	return failure ? budget : total_rx_packets;
 }
 
 /**
@@ -1122,6 +1195,7 @@
 	union i40e_rx_desc *rx_desc;
 	u32 rx_error, rx_status;
 	u16 rx_packet_len;
+	bool failure = false;
 	u8 rx_ptype;
 	u64 qword;
 	u16 i;
@@ -1132,7 +1206,9 @@
 		u16 vlan_tag;
 		/* return some buffers to hardware, one at a time is too slow */
 		if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
-			i40evf_alloc_rx_buffers_1buf(rx_ring, cleaned_count);
+			failure = failure ||
+				  i40evf_alloc_rx_buffers_1buf(rx_ring,
+							       cleaned_count);
 			cleaned_count = 0;
 		}
 
@@ -1189,8 +1265,7 @@
 			continue;
 		}
 
-		skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
-			     i40e_ptype_to_hash(rx_ptype));
+		i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
 		/* probably a little skewed due to removing CRC */
 		total_rx_bytes += skb->len;
 		total_rx_packets++;
@@ -1214,7 +1289,7 @@
 	rx_ring->q_vector->rx.total_packets += total_rx_packets;
 	rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
-	return total_rx_packets;
+	return failure ? budget : total_rx_packets;
 }
 
 static u32 i40e_buildreg_itr(const int type, const u16 itr)
@@ -1222,7 +1297,9 @@
 	u32 val;
 
 	val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
-	      I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK |
+	      /* Don't clear PBA because that can cause lost interrupts that
+	       * came in while we were cleaning/polling
+	       */
 	      (type << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
 	      (itr << I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT);
 
@@ -1263,10 +1340,12 @@
 		rx = i40e_set_new_dynamic_itr(&q_vector->rx);
 		rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr);
 	}
+
 	if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) {
 		tx = i40e_set_new_dynamic_itr(&q_vector->tx);
 		txval = i40e_buildreg_itr(I40E_TX_ITR, q_vector->tx.itr);
 	}
+
 	if (rx || tx) {
 		/* get the higher of the two ITR adjustments and
 		 * use the same value for both ITR registers
@@ -1302,7 +1381,6 @@
 		q_vector->itr_countdown--;
 	else
 		q_vector->itr_countdown = ITR_COUNTDOWN_START;
-
 }
 
 /**
@@ -1334,8 +1412,9 @@
 	 * budget and be more aggressive about cleaning up the Tx descriptors.
 	 */
 	i40e_for_each_ring(ring, q_vector->tx) {
-		clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit);
-		arm_wb |= ring->arm_wb;
+		clean_complete = clean_complete &&
+				 i40e_clean_tx_irq(ring, vsi->work_limit);
+		arm_wb = arm_wb || ring->arm_wb;
 		ring->arm_wb = false;
 	}
 
@@ -1358,14 +1437,16 @@
 
 		work_done += cleaned;
 		/* if we didn't clean as many as budgeted, we must be done */
-		clean_complete &= (budget_per_ring != cleaned);
+		clean_complete = clean_complete && (budget_per_ring > cleaned);
 	}
 
 	/* If work not completed, return budget and polling will return */
 	if (!clean_complete) {
 tx_only:
-		if (arm_wb)
-			i40evf_force_wb(vsi, q_vector);
+		if (arm_wb) {
+			q_vector->tx.ring[0].tx_stats.tx_force_wb++;
+			i40e_enable_wb_on_itr(vsi, q_vector);
+		}
 		return budget;
 	}
 
@@ -1437,21 +1518,30 @@
  * @tx_ring:  ptr to the ring to send
  * @skb:      ptr to the skb we're sending
  * @hdr_len:  ptr to the size of the packet header
- * @cd_tunneling: ptr to context descriptor bits
+ * @cd_type_cmd_tso_mss: Quad Word 1
  *
  * Returns 0 if no TSO can happen, 1 if tso is going, or error
  **/
 static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
-		    u8 *hdr_len, u64 *cd_type_cmd_tso_mss,
-		    u32 *cd_tunneling)
+		    u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
 {
-	u32 cd_cmd, cd_tso_len, cd_mss;
-	struct ipv6hdr *ipv6h;
-	struct tcphdr *tcph;
-	struct iphdr *iph;
-	u32 l4len;
+	u64 cd_cmd, cd_tso_len, cd_mss;
+	union {
+		struct iphdr *v4;
+		struct ipv6hdr *v6;
+		unsigned char *hdr;
+	} ip;
+	union {
+		struct tcphdr *tcp;
+		struct udphdr *udp;
+		unsigned char *hdr;
+	} l4;
+	u32 paylen, l4_offset;
 	int err;
 
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return 0;
+
 	if (!skb_is_gso(skb))
 		return 0;
 
@@ -1459,35 +1549,60 @@
 	if (err < 0)
 		return err;
 
-	iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
-	ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+	ip.hdr = skb_network_header(skb);
+	l4.hdr = skb_transport_header(skb);
+
+	/* initialize outer IP header fields */
+	if (ip.v4->version == 4) {
+		ip.v4->tot_len = 0;
+		ip.v4->check = 0;
+	} else {
+		ip.v6->payload_len = 0;
+	}
+
+	if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE |
+					 SKB_GSO_UDP_TUNNEL_CSUM)) {
+		if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+			/* determine offset of outer transport header */
+			l4_offset = l4.hdr - skb->data;
+
+			/* remove payload length from outer checksum */
+			paylen = (__force u16)l4.udp->check;
+			paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+			l4.udp->check = ~csum_fold((__force __wsum)paylen);
+		}
 
-	if (iph->version == 4) {
-		tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
-		iph->tot_len = 0;
-		iph->check = 0;
-		tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-						 0, IPPROTO_TCP, 0);
-	} else if (ipv6h->version == 6) {
-		tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
-		ipv6h->payload_len = 0;
-		tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
-					       0, IPPROTO_TCP, 0);
-	}
-
-	l4len = skb->encapsulation ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb);
-	*hdr_len = (skb->encapsulation
-		    ? (skb_inner_transport_header(skb) - skb->data)
-		    : skb_transport_offset(skb)) + l4len;
+		/* reset pointers to inner headers */
+		ip.hdr = skb_inner_network_header(skb);
+		l4.hdr = skb_inner_transport_header(skb);
+
+		/* initialize inner IP header fields */
+		if (ip.v4->version == 4) {
+			ip.v4->tot_len = 0;
+			ip.v4->check = 0;
+		} else {
+			ip.v6->payload_len = 0;
+		}
+	}
+
+	/* determine offset of inner transport header */
+	l4_offset = l4.hdr - skb->data;
+
+	/* remove payload length from inner checksum */
+	paylen = (__force u16)l4.tcp->check;
+	paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+	l4.tcp->check = ~csum_fold((__force __wsum)paylen);
+
+	/* compute length of segmentation header */
+	*hdr_len = (l4.tcp->doff * 4) + l4_offset;
 
 	/* find the field values */
 	cd_cmd = I40E_TX_CTX_DESC_TSO;
 	cd_tso_len = skb->len - *hdr_len;
 	cd_mss = skb_shinfo(skb)->gso_size;
-	*cd_type_cmd_tso_mss |= ((u64)cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
-				((u64)cd_tso_len <<
-				 I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
-				((u64)cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
+	*cd_type_cmd_tso_mss |= (cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
+				(cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
+				(cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
 	return 1;
 }
 
@@ -1497,130 +1612,157 @@
  * @tx_flags: pointer to Tx flags currently set
  * @td_cmd: Tx descriptor command bits to set
  * @td_offset: Tx descriptor header offsets to set
+ * @tx_ring: Tx descriptor ring
  * @cd_tunneling: ptr to context desc bits
  **/
-static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
-				u32 *td_cmd, u32 *td_offset,
-				struct i40e_ring *tx_ring,
-				u32 *cd_tunneling)
-{
-	struct ipv6hdr *this_ipv6_hdr;
-	unsigned int this_tcp_hdrlen;
-	struct iphdr *this_ip_hdr;
-	u32 network_hdr_len;
-	u8 l4_hdr = 0;
-	struct udphdr *oudph;
-	struct iphdr *oiph;
-	u32 l4_tunnel = 0;
+static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
+			       u32 *td_cmd, u32 *td_offset,
+			       struct i40e_ring *tx_ring,
+			       u32 *cd_tunneling)
+{
+	union {
+		struct iphdr *v4;
+		struct ipv6hdr *v6;
+		unsigned char *hdr;
+	} ip;
+	union {
+		struct tcphdr *tcp;
+		struct udphdr *udp;
+		unsigned char *hdr;
+	} l4;
+	unsigned char *exthdr;
+	u32 offset, cmd = 0, tunnel = 0;
+	__be16 frag_off;
+	u8 l4_proto = 0;
+
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return 0;
+
+	ip.hdr = skb_network_header(skb);
+	l4.hdr = skb_transport_header(skb);
+
+	/* compute outer L2 header size */
+	offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
 
 	if (skb->encapsulation) {
-		switch (ip_hdr(skb)->protocol) {
+		/* define outer network header type */
+		if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+			tunnel |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
+				  I40E_TX_CTX_EXT_IP_IPV4 :
+				  I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+
+			l4_proto = ip.v4->protocol;
+		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
+			tunnel |= I40E_TX_CTX_EXT_IP_IPV6;
+
+			exthdr = ip.hdr + sizeof(*ip.v6);
+			l4_proto = ip.v6->nexthdr;
+			if (l4.hdr != exthdr)
+				ipv6_skip_exthdr(skb, exthdr - skb->data,
+						 &l4_proto, &frag_off);
+		}
+
+		/* compute outer L3 header size */
+		tunnel |= ((l4.hdr - ip.hdr) / 4) <<
+			  I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT;
+
+		/* switch IP header pointer from outer to inner header */
+		ip.hdr = skb_inner_network_header(skb);
+
+		/* define outer transport */
+		switch (l4_proto) {
 		case IPPROTO_UDP:
-			oudph = udp_hdr(skb);
-			oiph = ip_hdr(skb);
-			l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
+			tunnel |= I40E_TXD_CTX_UDP_TUNNELING;
+			*tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
+			break;
+		case IPPROTO_GRE:
+			tunnel |= I40E_TXD_CTX_GRE_TUNNELING;
 			*tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
 			break;
 		default:
-			return;
-		}
-		network_hdr_len = skb_inner_network_header_len(skb);
-		this_ip_hdr = inner_ip_hdr(skb);
-		this_ipv6_hdr = inner_ipv6_hdr(skb);
-		this_tcp_hdrlen = inner_tcp_hdrlen(skb);
-
-		if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-			if (*tx_flags & I40E_TX_FLAGS_TSO) {
-				*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
-				ip_hdr(skb)->check = 0;
-			} else {
-				*cd_tunneling |=
-					 I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-			}
-		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-			*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
 			if (*tx_flags & I40E_TX_FLAGS_TSO)
-				ip_hdr(skb)->check = 0;
-		}
+				return -1;
 
-		/* Now set the ctx descriptor fields */
-		*cd_tunneling |= (skb_network_header_len(skb) >> 2) <<
-				   I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT      |
-				   l4_tunnel                             |
-				   ((skb_inner_network_offset(skb) -
-					skb_transport_offset(skb)) >> 1) <<
-				   I40E_TXD_CTX_QW0_NATLEN_SHIFT;
-		if (this_ip_hdr->version == 6) {
-			*tx_flags &= ~I40E_TX_FLAGS_IPV4;
-			*tx_flags |= I40E_TX_FLAGS_IPV6;
+			skb_checksum_help(skb);
+			return 0;
 		}
 
+		/* compute tunnel header size */
+		tunnel |= ((ip.hdr - l4.hdr) / 2) <<
+			  I40E_TXD_CTX_QW0_NATLEN_SHIFT;
 
-		if ((tx_ring->flags & I40E_TXR_FLAGS_OUTER_UDP_CSUM) &&
-		    (l4_tunnel == I40E_TXD_CTX_UDP_TUNNELING)        &&
-		    (*cd_tunneling & I40E_TXD_CTX_QW0_EXT_IP_MASK)) {
-			oudph->check = ~csum_tcpudp_magic(oiph->saddr,
-					oiph->daddr,
-					(skb->len - skb_transport_offset(skb)),
-					IPPROTO_UDP, 0);
-			*cd_tunneling |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
-		}
-	} else {
-		network_hdr_len = skb_network_header_len(skb);
-		this_ip_hdr = ip_hdr(skb);
-		this_ipv6_hdr = ipv6_hdr(skb);
-		this_tcp_hdrlen = tcp_hdrlen(skb);
+		/* indicate if we need to offload outer UDP header */
+		if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
+		    (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
+			tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
+
+		/* record tunnel offload values */
+		*cd_tunneling |= tunnel;
+
+		/* switch L4 header pointer from outer to inner */
+		l4.hdr = skb_inner_transport_header(skb);
+		l4_proto = 0;
+
+		/* reset type as we transition from outer to inner headers */
+		*tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6);
+		if (ip.v4->version == 4)
+			*tx_flags |= I40E_TX_FLAGS_IPV4;
+		if (ip.v6->version == 6)
+			*tx_flags |= I40E_TX_FLAGS_IPV6;
 	}
 
 	/* Enable IP checksum offloads */
 	if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-		l4_hdr = this_ip_hdr->protocol;
+		l4_proto = ip.v4->protocol;
 		/* the stack computes the IP header already, the only time we
 		 * need the hardware to recompute it is in the case of TSO.
 		 */
-		if (*tx_flags & I40E_TX_FLAGS_TSO) {
-			*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
-			this_ip_hdr->check = 0;
-		} else {
-			*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
-		}
-		/* Now set the td_offset for IP header length */
-		*td_offset = (network_hdr_len >> 2) <<
-			      I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+		cmd |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
+		       I40E_TX_DESC_CMD_IIPT_IPV4_CSUM :
+		       I40E_TX_DESC_CMD_IIPT_IPV4;
 	} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-		l4_hdr = this_ipv6_hdr->nexthdr;
-		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
-		/* Now set the td_offset for IP header length */
-		*td_offset = (network_hdr_len >> 2) <<
-			      I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
-	}
-	/* words in MACLEN + dwords in IPLEN + dwords in L4Len */
-	*td_offset |= (skb_network_offset(skb) >> 1) <<
-		       I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
+		cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+
+		exthdr = ip.hdr + sizeof(*ip.v6);
+		l4_proto = ip.v6->nexthdr;
+		if (l4.hdr != exthdr)
+			ipv6_skip_exthdr(skb, exthdr - skb->data,
+					 &l4_proto, &frag_off);
+	}
+
+	/* compute inner L3 header size */
+	offset |= ((l4.hdr - ip.hdr) / 4) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
 
 	/* Enable L4 checksum offloads */
-	switch (l4_hdr) {
+	switch (l4_proto) {
 	case IPPROTO_TCP:
 		/* enable checksum offloads */
-		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
-		*td_offset |= (this_tcp_hdrlen >> 2) <<
-			       I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
+		offset |= l4.tcp->doff << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
 		break;
 	case IPPROTO_SCTP:
 		/* enable SCTP checksum offload */
-		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
-		*td_offset |= (sizeof(struct sctphdr) >> 2) <<
-			       I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
+		offset |= (sizeof(struct sctphdr) >> 2) <<
+			  I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
 		break;
 	case IPPROTO_UDP:
 		/* enable UDP checksum offload */
-		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
-		*td_offset |= (sizeof(struct udphdr) >> 2) <<
-			       I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
+		offset |= (sizeof(struct udphdr) >> 2) <<
+			  I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
 		break;
 	default:
-		break;
+		if (*tx_flags & I40E_TX_FLAGS_TSO)
+			return -1;
+		skb_checksum_help(skb);
+		return 0;
 	}
+
+	*td_cmd |= cmd;
+	*td_offset |= offset;
+
+	return 1;
 }
 
 /**
@@ -1654,60 +1796,88 @@
 	context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss);
 }
 
- /**
- * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+/**
+ * __i40evf_chk_linearize - Check if there are more than 8 buffers per packet
  * @skb:      send buffer
- * @tx_flags: collected send information
  *
- * Note: Our HW can't scatter-gather more than 8 fragments to build
- * a packet on the wire and so we need to figure out the cases where we
- * need to linearize the skb.
- **/
-static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags)
-{
-	struct skb_frag_struct *frag;
-	bool linearize = false;
-	unsigned int size = 0;
-	u16 num_frags;
-	u16 gso_segs;
+ * Note: Our HW can't DMA more than 8 buffers to build a packet on the wire
+ * and so we need to figure out the cases where we need to linearize the skb.
+ *
+ * For TSO we need to count the TSO header and segment payload separately.
+ * As such we need to check cases where we have 7 fragments or more as we
+ * can potentially require 9 DMA transactions, 1 for the TSO header, 1 for
+ * the segment payload in the first descriptor, and another 7 for the
+ * fragments.
+ **/
+bool __i40evf_chk_linearize(struct sk_buff *skb)
+{
+	const struct skb_frag_struct *frag, *stale;
+	int nr_frags, sum;
+
+	/* no need to check if number of frags is less than 7 */
+	nr_frags = skb_shinfo(skb)->nr_frags;
+	if (nr_frags < (I40E_MAX_BUFFER_TXD - 1))
+		return false;
 
-	num_frags = skb_shinfo(skb)->nr_frags;
-	gso_segs = skb_shinfo(skb)->gso_segs;
+	/* We need to walk through the list and validate that each group
+	 * of 6 fragments totals at least gso_size.
+	 */
+	nr_frags -= I40E_MAX_BUFFER_TXD - 2;
+	frag = &skb_shinfo(skb)->frags[0];
 
-	if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
-		u16 j = 0;
+	/* Initialize size to the negative value of gso_size minus 1.  We
+	 * use this as the worst case scenerio in which the frag ahead
+	 * of us only provides one byte which is why we are limited to 6
+	 * descriptors for a single transmit as the header and previous
+	 * fragment are already consuming 2 descriptors.
+	 */
+	sum = 1 - skb_shinfo(skb)->gso_size;
 
-		if (num_frags < (I40E_MAX_BUFFER_TXD))
-			goto linearize_chk_done;
-		/* try the simple math, if we have too many frags per segment */
-		if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
-		    I40E_MAX_BUFFER_TXD) {
-			linearize = true;
-			goto linearize_chk_done;
-		}
-		frag = &skb_shinfo(skb)->frags[0];
-		/* we might still have more fragments per segment */
-		do {
-			size += skb_frag_size(frag);
-			frag++; j++;
-			if ((size >= skb_shinfo(skb)->gso_size) &&
-			    (j < I40E_MAX_BUFFER_TXD)) {
-				size = (size % skb_shinfo(skb)->gso_size);
-				j = (size) ? 1 : 0;
-			}
-			if (j == I40E_MAX_BUFFER_TXD) {
-				linearize = true;
-				break;
-			}
-			num_frags--;
-		} while (num_frags);
-	} else {
-		if (num_frags >= I40E_MAX_BUFFER_TXD)
-			linearize = true;
+	/* Add size of frags 0 through 4 to create our initial sum */
+	sum += skb_frag_size(frag++);
+	sum += skb_frag_size(frag++);
+	sum += skb_frag_size(frag++);
+	sum += skb_frag_size(frag++);
+	sum += skb_frag_size(frag++);
+
+	/* Walk through fragments adding latest fragment, testing it, and
+	 * then removing stale fragments from the sum.
+	 */
+	for (stale = &skb_shinfo(skb)->frags[0];; stale++) {
+		int stale_size = skb_frag_size(stale);
+
+		sum += skb_frag_size(frag++);
+
+		/* The stale fragment may present us with a smaller
+		 * descriptor than the actual fragment size. To account
+		 * for that we need to remove all the data on the front and
+		 * figure out what the remainder would be in the last
+		 * descriptor associated with the fragment.
+		 */
+		if (stale_size > I40E_MAX_DATA_PER_TXD) {
+			int align_pad = -(stale->page_offset) &
+					(I40E_MAX_READ_REQ_SIZE - 1);
+
+			sum -= align_pad;
+			stale_size -= align_pad;
+
+			do {
+				sum -= I40E_MAX_DATA_PER_TXD_ALIGNED;
+				stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED;
+			} while (stale_size > I40E_MAX_DATA_PER_TXD);
+		}
+
+		/* if sum is negative we failed to make sufficient progress */
+		if (sum < 0)
+			return true;
+
+		if (!nr_frags--)
+			break;
+
+		sum -= stale_size;
 	}
 
-linearize_chk_done:
-	return linearize;
+	return false;
 }
 
 /**
@@ -1717,7 +1887,7 @@
  *
  * Returns -EBUSY if a stop is needed, else 0
  **/
-static inline int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
 {
 	netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
 	/* Memory barrier before checking head and tail */
@@ -1734,20 +1904,6 @@
 }
 
 /**
- * i40evf_maybe_stop_tx - 1st level check for tx stop conditions
- * @tx_ring: the ring to be checked
- * @size:    the size buffer we want to assure is available
- *
- * Returns 0 if stop is not needed
- **/
-static inline int i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
-{
-	if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
-		return 0;
-	return __i40evf_maybe_stop_tx(tx_ring, size);
-}
-
-/**
  * i40evf_tx_map - Build the Tx descriptor
  * @tx_ring:  ring to send buffer on
  * @skb:      send buffer
@@ -1770,6 +1926,9 @@
 	u32 td_tag = 0;
 	dma_addr_t dma;
 	u16 gso_segs;
+	u16 desc_count = 0;
+	bool tail_bump = true;
+	bool do_rs = false;
 
 	if (tx_flags & I40E_TX_FLAGS_HW_VLAN) {
 		td_cmd |= I40E_TX_DESC_CMD_IL2TAG1;
@@ -1794,6 +1953,8 @@
 	tx_bi = first;
 
 	for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
+		unsigned int max_data = I40E_MAX_DATA_PER_TXD_ALIGNED;
+
 		if (dma_mapping_error(tx_ring->dev, dma))
 			goto dma_error;
 
@@ -1801,23 +1962,28 @@
 		dma_unmap_len_set(tx_bi, len, size);
 		dma_unmap_addr_set(tx_bi, dma, dma);
 
+		/* align size to end of page */
+		max_data += -dma & (I40E_MAX_READ_REQ_SIZE - 1);
 		tx_desc->buffer_addr = cpu_to_le64(dma);
 
 		while (unlikely(size > I40E_MAX_DATA_PER_TXD)) {
 			tx_desc->cmd_type_offset_bsz =
 				build_ctob(td_cmd, td_offset,
-					   I40E_MAX_DATA_PER_TXD, td_tag);
+					   max_data, td_tag);
 
 			tx_desc++;
 			i++;
+			desc_count++;
+
 			if (i == tx_ring->count) {
 				tx_desc = I40E_TX_DESC(tx_ring, 0);
 				i = 0;
 			}
 
-			dma += I40E_MAX_DATA_PER_TXD;
-			size -= I40E_MAX_DATA_PER_TXD;
+			dma += max_data;
+			size -= max_data;
 
+			max_data = I40E_MAX_DATA_PER_TXD_ALIGNED;
 			tx_desc->buffer_addr = cpu_to_le64(dma);
 		}
 
@@ -1829,6 +1995,8 @@
 
 		tx_desc++;
 		i++;
+		desc_count++;
+
 		if (i == tx_ring->count) {
 			tx_desc = I40E_TX_DESC(tx_ring, 0);
 			i = 0;
@@ -1843,35 +2011,6 @@
 		tx_bi = &tx_ring->tx_bi[i];
 	}
 
-	/* Place RS bit on last descriptor of any packet that spans across the
-	 * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.
-	 */
-#define WB_STRIDE 0x3
-	if (((i & WB_STRIDE) != WB_STRIDE) &&
-	    (first <= &tx_ring->tx_bi[i]) &&
-	    (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) {
-		tx_desc->cmd_type_offset_bsz =
-			build_ctob(td_cmd, td_offset, size, td_tag) |
-			cpu_to_le64((u64)I40E_TX_DESC_CMD_EOP <<
-					 I40E_TXD_QW1_CMD_SHIFT);
-	} else {
-		tx_desc->cmd_type_offset_bsz =
-			build_ctob(td_cmd, td_offset, size, td_tag) |
-			cpu_to_le64((u64)I40E_TXD_CMD <<
-					 I40E_TXD_QW1_CMD_SHIFT);
-	}
-
-	netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
-						 tx_ring->queue_index),
-			     first->bytecount);
-
-	/* Force memory writes to complete before letting h/w
-	 * know there are new descriptors to fetch.  (Only
-	 * applicable for weak-ordered memory model archs,
-	 * such as IA-64).
-	 */
-	wmb();
-
 	/* set next_to_watch value indicating a packet is present */
 	first->next_to_watch = tx_desc;
 
@@ -1881,15 +2020,72 @@
 
 	tx_ring->next_to_use = i;
 
-	i40evf_maybe_stop_tx(tx_ring, DESC_NEEDED);
+	netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
+						 tx_ring->queue_index),
+						 first->bytecount);
+	i40e_maybe_stop_tx(tx_ring, DESC_NEEDED);
+
+	/* Algorithm to optimize tail and RS bit setting:
+	 * if xmit_more is supported
+	 *	if xmit_more is true
+	 *		do not update tail and do not mark RS bit.
+	 *	if xmit_more is false and last xmit_more was false
+	 *		if every packet spanned less than 4 desc
+	 *			then set RS bit on 4th packet and update tail
+	 *			on every packet
+	 *		else
+	 *			update tail and set RS bit on every packet.
+	 *	if xmit_more is false and last_xmit_more was true
+	 *		update tail and set RS bit.
+	 *
+	 * Optimization: wmb to be issued only in case of tail update.
+	 * Also optimize the Descriptor WB path for RS bit with the same
+	 * algorithm.
+	 *
+	 * Note: If there are less than 4 packets
+	 * pending and interrupts were disabled the service task will
+	 * trigger a force WB.
+	 */
+	if (skb->xmit_more  &&
+	    !netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev,
+						    tx_ring->queue_index))) {
+		tx_ring->flags |= I40E_TXR_FLAGS_LAST_XMIT_MORE_SET;
+		tail_bump = false;
+	} else if (!skb->xmit_more &&
+		   !netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev,
+						       tx_ring->queue_index)) &&
+		   (!(tx_ring->flags & I40E_TXR_FLAGS_LAST_XMIT_MORE_SET)) &&
+		   (tx_ring->packet_stride < WB_STRIDE) &&
+		   (desc_count < WB_STRIDE)) {
+		tx_ring->packet_stride++;
+	} else {
+		tx_ring->packet_stride = 0;
+		tx_ring->flags &= ~I40E_TXR_FLAGS_LAST_XMIT_MORE_SET;
+		do_rs = true;
+	}
+	if (do_rs)
+		tx_ring->packet_stride = 0;
+
+	tx_desc->cmd_type_offset_bsz =
+			build_ctob(td_cmd, td_offset, size, td_tag) |
+			cpu_to_le64((u64)(do_rs ? I40E_TXD_CMD :
+						  I40E_TX_DESC_CMD_EOP) <<
+						  I40E_TXD_QW1_CMD_SHIFT);
+
 	/* notify HW of packet */
-	if (!skb->xmit_more ||
-	    netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev,
-						   tx_ring->queue_index)))
-		writel(i, tx_ring->tail);
-	else
+	if (!tail_bump)
 		prefetchw(tx_desc + 1);
 
+	if (tail_bump) {
+		/* Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64).
+		 */
+		wmb();
+		writel(i, tx_ring->tail);
+	}
+
 	return;
 
 dma_error:
@@ -1910,38 +2106,6 @@
 }
 
 /**
- * i40evf_xmit_descriptor_count - calculate number of tx descriptors needed
- * @skb:     send buffer
- * @tx_ring: ring to send buffer on
- *
- * Returns number of data descriptors needed for this skb. Returns 0 to indicate
- * there is not enough descriptors available in this ring since we need at least
- * one descriptor.
- **/
-static inline int i40evf_xmit_descriptor_count(struct sk_buff *skb,
-					       struct i40e_ring *tx_ring)
-{
-	unsigned int f;
-	int count = 0;
-
-	/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
-	 *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
-	 *       + 4 desc gap to avoid the cache line where head is,
-	 *       + 1 desc for context descriptor,
-	 * otherwise try next time
-	 */
-	for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
-		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
-
-	count += TXD_USE_COUNT(skb_headlen(skb));
-	if (i40evf_maybe_stop_tx(tx_ring, count + 4 + 1)) {
-		tx_ring->tx_stats.tx_busy++;
-		return 0;
-	}
-	return count;
-}
-
-/**
  * i40e_xmit_frame_ring - Sends buffer on Tx ring
  * @skb:     send buffer
  * @tx_ring: ring to send buffer on
@@ -1959,10 +2123,29 @@
 	__be16 protocol;
 	u32 td_cmd = 0;
 	u8 hdr_len = 0;
-	int tso;
+	int tso, count;
+
+	/* prefetch the data, we'll need it later */
+	prefetch(skb->data);
 
-	if (0 == i40evf_xmit_descriptor_count(skb, tx_ring))
+	count = i40e_xmit_descriptor_count(skb);
+	if (i40e_chk_linearize(skb, count)) {
+		if (__skb_linearize(skb))
+			goto out_drop;
+		count = i40e_txd_use_count(skb->len);
+		tx_ring->tx_stats.tx_linearize++;
+	}
+
+	/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
+	 *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
+	 *       + 4 desc gap to avoid the cache line where head is,
+	 *       + 1 desc for context descriptor,
+	 * otherwise try next time
+	 */
+	if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+		tx_ring->tx_stats.tx_busy++;
 		return NETDEV_TX_BUSY;
+	}
 
 	/* prepare the xmit flags */
 	if (i40evf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
@@ -1980,32 +2163,24 @@
 	else if (protocol == htons(ETH_P_IPV6))
 		tx_flags |= I40E_TX_FLAGS_IPV6;
 
-	tso = i40e_tso(tx_ring, skb, &hdr_len,
-		       &cd_type_cmd_tso_mss, &cd_tunneling);
+	tso = i40e_tso(tx_ring, skb, &hdr_len, &cd_type_cmd_tso_mss);
 
 	if (tso < 0)
 		goto out_drop;
 	else if (tso)
 		tx_flags |= I40E_TX_FLAGS_TSO;
 
-	if (i40e_chk_linearize(skb, tx_flags)) {
-		if (skb_linearize(skb))
-			goto out_drop;
-		tx_ring->tx_stats.tx_linearize++;
-	}
+	/* Always offload the checksum, since it's in the data descriptor */
+	tso = i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
+				  tx_ring, &cd_tunneling);
+	if (tso < 0)
+		goto out_drop;
+
 	skb_tx_timestamp(skb);
 
 	/* always enable CRC insertion offload */
 	td_cmd |= I40E_TX_DESC_CMD_ICRC;
 
-	/* Always offload the checksum, since it's in the data descriptor */
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		tx_flags |= I40E_TX_FLAGS_CSUM;
-
-		i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
-				    tx_ring, &cd_tunneling);
-	}
-
 	i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss,
 			   cd_tunneling, cd_l2tag2);
 
@@ -2029,7 +2204,7 @@
 netdev_tx_t i40evf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct i40evf_adapter *adapter = netdev_priv(netdev);
-	struct i40e_ring *tx_ring = adapter->tx_rings[skb->queue_mapping];
+	struct i40e_ring *tx_ring = &adapter->tx_rings[skb->queue_mapping];
 
 	/* hardware can't handle really short frames, hardware padding works
 	 * beyond this point
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -146,14 +146,42 @@
 
 #define I40E_MAX_BUFFER_TXD	8
 #define I40E_MIN_TX_LEN		17
-#define I40E_MAX_DATA_PER_TXD	8192
+
+/* The size limit for a transmit buffer in a descriptor is (16K - 1).
+ * In order to align with the read requests we will align the value to
+ * the nearest 4K which represents our maximum read request size.
+ */
+#define I40E_MAX_READ_REQ_SIZE		4096
+#define I40E_MAX_DATA_PER_TXD		(16 * 1024 - 1)
+#define I40E_MAX_DATA_PER_TXD_ALIGNED \
+	(I40E_MAX_DATA_PER_TXD & ~(I40E_MAX_READ_REQ_SIZE - 1))
+
+/* This ugly bit of math is equivalent to DIV_ROUNDUP(size, X) where X is
+ * the value I40E_MAX_DATA_PER_TXD_ALIGNED.  It is needed due to the fact
+ * that 12K is not a power of 2 and division is expensive.  It is used to
+ * approximate the number of descriptors used per linear buffer.  Note
+ * that this will overestimate in some cases as it doesn't account for the
+ * fact that we will add up to 4K - 1 in aligning the 12K buffer, however
+ * the error should not impact things much as large buffers usually mean
+ * we will use fewer descriptors then there are frags in an skb.
+ */
+static inline unsigned int i40e_txd_use_count(unsigned int size)
+{
+	const unsigned int max = I40E_MAX_DATA_PER_TXD_ALIGNED;
+	const unsigned int reciprocal = ((1ull << 32) - 1 + (max / 2)) / max;
+	unsigned int adjust = ~(u32)0;
+
+	/* if we rounded up on the reciprocal pull down the adjustment */
+	if ((max * reciprocal) > adjust)
+		adjust = ~(u32)(reciprocal - 1);
+
+	return (u32)((((u64)size * reciprocal) + adjust) >> 32);
+}
 
 /* Tx Descriptors needed, worst case */
-#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
 #define I40E_MIN_DESC_PENDING	4
 
-#define I40E_TX_FLAGS_CSUM		BIT(0)
 #define I40E_TX_FLAGS_HW_VLAN		BIT(1)
 #define I40E_TX_FLAGS_SW_VLAN		BIT(2)
 #define I40E_TX_FLAGS_TSO		BIT(3)
@@ -201,12 +229,16 @@
 	u64 tx_busy;
 	u64 tx_done_old;
 	u64 tx_linearize;
+	u64 tx_force_wb;
+	u64 tx_lost_interrupt;
 };
 
 struct i40e_rx_queue_stats {
 	u64 non_eop_descs;
 	u64 alloc_page_failed;
 	u64 alloc_buff_failed;
+	u64 page_reuse_count;
+	u64 realloc_count;
 };
 
 enum i40e_ring_state_t {
@@ -252,7 +284,6 @@
 #define I40E_RX_DTYPE_NO_SPLIT      0
 #define I40E_RX_DTYPE_HEADER_SPLIT  1
 #define I40E_RX_DTYPE_SPLIT_ALWAYS  2
-	u8  hsplit;
 #define I40E_RX_SPLIT_L2      0x1
 #define I40E_RX_SPLIT_IP      0x2
 #define I40E_RX_SPLIT_TCP_UDP 0x4
@@ -267,10 +298,11 @@
 
 	bool ring_active;		/* is ring online or not */
 	bool arm_wb;		/* do something to arm write back */
+	u8 packet_stride;
+#define I40E_TXR_FLAGS_LAST_XMIT_MORE_SET BIT(2)
 
 	u16 flags;
 #define I40E_TXR_FLAGS_WB_ON_ITR	BIT(0)
-#define I40E_TXR_FLAGS_OUTER_UDP_CSUM	BIT(1)
 
 	/* stats structs */
 	struct i40e_queue_stats	stats;
@@ -310,8 +342,8 @@
 #define i40e_for_each_ring(pos, head) \
 	for (pos = (head).ring; pos != NULL; pos = pos->next)
 
-void i40evf_alloc_rx_buffers_ps(struct i40e_ring *rxr, u16 cleaned_count);
-void i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rxr, u16 cleaned_count);
+bool i40evf_alloc_rx_buffers_ps(struct i40e_ring *rxr, u16 cleaned_count);
+bool i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rxr, u16 cleaned_count);
 void i40evf_alloc_rx_headers(struct i40e_ring *rxr);
 netdev_tx_t i40evf_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void i40evf_clean_tx_ring(struct i40e_ring *tx_ring);
@@ -321,4 +353,85 @@
 void i40evf_free_tx_resources(struct i40e_ring *tx_ring);
 void i40evf_free_rx_resources(struct i40e_ring *rx_ring);
 int i40evf_napi_poll(struct napi_struct *napi, int budget);
+void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
+u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw);
+int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
+bool __i40evf_chk_linearize(struct sk_buff *skb);
+
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring: Tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+	void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+	return le32_to_cpu(*(volatile __le32 *)head);
+}
+
+/**
+ * i40e_xmit_descriptor_count - calculate number of Tx descriptors needed
+ * @skb:     send buffer
+ * @tx_ring: ring to send buffer on
+ *
+ * Returns number of data descriptors needed for this skb. Returns 0 to indicate
+ * there is not enough descriptors available in this ring since we need at least
+ * one descriptor.
+ **/
+static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)
+{
+	const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+	int count = 0, size = skb_headlen(skb);
+
+	for (;;) {
+		count += i40e_txd_use_count(size);
+
+		if (!nr_frags--)
+			break;
+
+		size = skb_frag_size(frag++);
+	}
+
+	return count;
+}
+
+/**
+ * i40e_maybe_stop_tx - 1st level check for Tx stop conditions
+ * @tx_ring: the ring to be checked
+ * @size:    the size buffer we want to assure is available
+ *
+ * Returns 0 if stop is not needed
+ **/
+static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+{
+	if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
+		return 0;
+	return __i40evf_maybe_stop_tx(tx_ring, size);
+}
+
+/**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @count:    number of buffers used
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static inline bool i40e_chk_linearize(struct sk_buff *skb, int count)
+{
+	/* Both TSO and single send will work if count is less than 8 */
+	if (likely(count < I40E_MAX_BUFFER_TXD))
+		return false;
+
+	if (skb_is_gso(skb))
+		return __i40evf_chk_linearize(skb);
+
+	/* we can support up to 8 data buffers for a single send */
+	return count != I40E_MAX_BUFFER_TXD;
+}
 #endif /* _I40E_TXRX_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h
@@ -153,6 +153,7 @@
 #define I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR	0x00000020
 #define I40E_VIRTCHNL_VF_OFFLOAD_VLAN		0x00010000
 #define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING	0x00020000
+#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2	0x00040000
 
 struct i40e_virtchnl_vf_resource {
 	u16 num_vsis;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40evf.h
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40evf.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -67,6 +67,8 @@
 	u16 rx_itr_setting;
 	u16 tx_itr_setting;
 	u16 qs_handle;
+	u8 *rss_hkey_user; /* User configured hash keys */
+	u8 *rss_lut_user;  /* User configured lookup table entries */
 };
 
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
@@ -95,10 +97,10 @@
 #define I40E_TX_DESC(R, i) (&(((struct i40e_tx_desc *)((R)->desc))[i]))
 #define I40E_TX_CTXTDESC(R, i) \
 	(&(((struct i40e_tx_context_desc *)((R)->desc))[i]))
-#define MAX_RX_QUEUES 8
-#define MAX_TX_QUEUES MAX_RX_QUEUES
+#define MAX_QUEUES 16
 
 #define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4)
+#define I40EVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4)
 
 /* MAX_MSIX_Q_VECTORS of these are allocated,
  * but we only use one per queue-specific vector.
@@ -142,9 +144,6 @@
 #define OTHER_VECTOR 1
 #define NONQ_VECS (OTHER_VECTOR)
 
-#define MAX_MSIX_Q_VECTORS 4
-#define MAX_MSIX_COUNT 5
-
 #define MIN_MSIX_Q_VECTORS 1
 #define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NONQ_VECS)
 
@@ -174,6 +173,7 @@
 	__I40EVF_RESETTING,		/* in reset */
 	/* Below here, watchdog is running */
 	__I40EVF_DOWN,			/* ready, can be opened */
+	__I40EVF_DOWN_PENDING,		/* descending, waiting for watchdog */
 	__I40EVF_TESTING,		/* in ethtool self-test */
 	__I40EVF_RUNNING,		/* opened, working */
 };
@@ -190,19 +190,19 @@
 	struct work_struct reset_task;
 	struct work_struct adminq_task;
 	struct delayed_work init_task;
-	struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
+	struct i40e_q_vector *q_vectors;
 	struct list_head vlan_filter_list;
 	char misc_vector_name[IFNAMSIZ + 9];
 	int num_active_queues;
 
 	/* TX */
-	struct i40e_ring *tx_rings[I40E_MAX_VSI_QP];
+	struct i40e_ring *tx_rings;
 	u32 tx_timeout_count;
 	struct list_head mac_filter_list;
 	u32 tx_desc_count;
 
 	/* RX */
-	struct i40e_ring *rx_rings[I40E_MAX_VSI_QP];
+	struct i40e_ring *rx_rings;
 	u64 hw_csum_rx_error;
 	u32 rx_desc_count;
 	int num_msix_vectors;
@@ -274,6 +274,9 @@
 };
 
 
+/* Ethtool Private Flags */
+#define I40EVF_PRIV_FLAGS_PS		BIT(0)
+
 /* needed by i40evf_ethtool.c */
 extern char i40evf_driver_name[];
 extern const char i40evf_driver_version[];
@@ -281,6 +284,7 @@
 int i40evf_up(struct i40evf_adapter *adapter);
 void i40evf_down(struct i40evf_adapter *adapter);
 int i40evf_process_config(struct i40evf_adapter *adapter);
+void i40evf_schedule_reset(struct i40evf_adapter *adapter);
 void i40evf_reset(struct i40evf_adapter *adapter);
 void i40evf_set_ethtool_ops(struct net_device *netdev);
 void i40evf_update_stats(struct i40evf_adapter *adapter);
@@ -313,4 +317,8 @@
 void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
 				enum i40e_virtchnl_ops v_opcode,
 				i40e_status v_retval, u8 *msg, u16 msglen);
+int i40evf_config_rss(struct i40e_vsi *vsi, const u8 *seed, u8 *lut,
+		      u16 lut_size);
+int i40evf_get_rss(struct i40e_vsi *vsi, const u8 *seed, u8 *lut,
+		   u16 lut_size);
 #endif /* _I40EVF_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -63,6 +63,12 @@
 #define I40EVF_STATS_LEN(_dev) \
 	(I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev))
 
+static const char i40evf_priv_flags_strings[][ETH_GSTRING_LEN] = {
+	"packet-split",
+};
+
+#define I40EVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40evf_priv_flags_strings)
+
 /**
  * i40evf_get_settings - Get Link Speed and Duplex settings
  * @netdev: network interface device structure
@@ -97,6 +103,8 @@
 {
 	if (sset == ETH_SS_STATS)
 		return I40EVF_STATS_LEN(netdev);
+	else if (sset == ETH_SS_PRIV_FLAGS)
+		return I40EVF_PRIV_FLAGS_STR_LEN;
 	else
 		return -EINVAL;
 }
@@ -121,12 +129,12 @@
 		data[i] =  *(u64 *)p;
 	}
 	for (j = 0; j < adapter->num_active_queues; j++) {
-		data[i++] = adapter->tx_rings[j]->stats.packets;
-		data[i++] = adapter->tx_rings[j]->stats.bytes;
+		data[i++] = adapter->tx_rings[j].stats.packets;
+		data[i++] = adapter->tx_rings[j].stats.bytes;
 	}
 	for (j = 0; j < adapter->num_active_queues; j++) {
-		data[i++] = adapter->rx_rings[j]->stats.packets;
-		data[i++] = adapter->rx_rings[j]->stats.bytes;
+		data[i++] = adapter->rx_rings[j].stats.packets;
+		data[i++] = adapter->rx_rings[j].stats.bytes;
 	}
 }
 
@@ -162,6 +170,12 @@
 			snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i);
 			p += ETH_GSTRING_LEN;
 		}
+	} else if (sset == ETH_SS_PRIV_FLAGS) {
+		for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) {
+			memcpy(data, i40evf_priv_flags_strings[i],
+			       ETH_GSTRING_LEN);
+			data += ETH_GSTRING_LEN;
+		}
 	}
 }
 
@@ -211,6 +225,7 @@
 	strlcpy(drvinfo->version, i40evf_driver_version, 32);
 	strlcpy(drvinfo->fw_version, "N/A", 4);
 	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+	drvinfo->n_priv_flags = I40EVF_PRIV_FLAGS_STR_LEN;
 }
 
 /**
@@ -351,7 +366,7 @@
 		vsi->tx_itr_setting &= ~I40E_ITR_DYNAMIC;
 
 	for (i = 0; i < adapter->num_msix_vectors - NONQ_VECS; i++) {
-		q_vector = adapter->q_vector[i];
+		q_vector = &adapter->q_vectors[i];
 		q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
 		wr32(hw, I40E_VFINT_ITRN1(0, i), q_vector->rx.itr);
 		q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
@@ -459,6 +474,7 @@
 				   struct ethtool_rxnfc *nfc)
 {
 	struct i40e_hw *hw = &adapter->hw;
+	u32 flags = adapter->vf_res->vf_offload_flags;
 
 	u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) |
 		   ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32);
@@ -477,54 +493,50 @@
 
 	switch (nfc->flow_type) {
 	case TCP_V4_FLOW:
-		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
-		case 0:
-			hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
-			break;
-		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+		if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+			if (flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
+				hena |=
+			   BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
+
 			hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
-			break;
-		default:
+		} else {
 			return -EINVAL;
 		}
 		break;
 	case TCP_V6_FLOW:
-		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
-		case 0:
-			hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
-			break;
-		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+		if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+			if (flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
+				hena |=
+			   BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK);
+
 			hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
-			break;
-		default:
+		} else {
 			return -EINVAL;
 		}
 		break;
 	case UDP_V4_FLOW:
-		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
-		case 0:
-			hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
-				  BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
-			break;
-		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+		if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+			if (flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
+				hena |=
+			    BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
+			    BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP);
+
 			hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
 				 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
-			break;
-		default:
+		} else {
 			return -EINVAL;
 		}
 		break;
 	case UDP_V6_FLOW:
-		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
-		case 0:
-			hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
-				  BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
-			break;
-		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+		if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+			if (flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
+				hena |=
+			    BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
+			    BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP);
+
 			hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
 				 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
-			break;
-		default:
+		} else {
 			return -EINVAL;
 		}
 		break;
@@ -634,25 +646,34 @@
 			   u8 *hfunc)
 {
 	struct i40evf_adapter *adapter = netdev_priv(netdev);
-	struct i40e_hw *hw = &adapter->hw;
-	u32 hlut_val;
-	int i, j;
+	struct i40e_vsi *vsi = &adapter->vsi;
+	u8 *seed = NULL, *lut;
+	int ret;
+	u16 i;
 
 	if (hfunc)
 		*hfunc = ETH_RSS_HASH_TOP;
 	if (!indir)
 		return 0;
 
-	if (indir) {
-		for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
-			hlut_val = rd32(hw, I40E_VFQF_HLUT(i));
-			indir[j++] = hlut_val & 0xff;
-			indir[j++] = (hlut_val >> 8) & 0xff;
-			indir[j++] = (hlut_val >> 16) & 0xff;
-			indir[j++] = (hlut_val >> 24) & 0xff;
-		}
-	}
-	return 0;
+	seed = key;
+
+	lut = kzalloc(I40EVF_HLUT_ARRAY_SIZE, GFP_KERNEL);
+	if (!lut)
+		return -ENOMEM;
+
+	ret = i40evf_get_rss(vsi, seed, lut, I40EVF_HLUT_ARRAY_SIZE);
+	if (ret)
+		goto out;
+
+	/* Each 32 bits pointed by 'indir' is stored with a lut entry */
+	for (i = 0; i < I40EVF_HLUT_ARRAY_SIZE; i++)
+		indir[i] = (u32)lut[i];
+
+out:
+	kfree(lut);
+
+	return ret;
 }
 
 /**
@@ -668,9 +689,9 @@
 			   const u8 *key, const u8 hfunc)
 {
 	struct i40evf_adapter *adapter = netdev_priv(netdev);
-	struct i40e_hw *hw = &adapter->hw;
-	u32 hlut_val;
-	int i, j;
+	struct i40e_vsi *vsi = &adapter->vsi;
+	u8 *seed = NULL;
+	u16 i;
 
 	/* We do not allow change in unsupported parameters */
 	if (key ||
@@ -679,14 +700,76 @@
 	if (!indir)
 		return 0;
 
-	for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
-		hlut_val = indir[j++];
-		hlut_val |= indir[j++] << 8;
-		hlut_val |= indir[j++] << 16;
-		hlut_val |= indir[j++] << 24;
-		wr32(hw, I40E_VFQF_HLUT(i), hlut_val);
+	if (key) {
+		if (!vsi->rss_hkey_user) {
+			vsi->rss_hkey_user = kzalloc(I40EVF_HKEY_ARRAY_SIZE,
+						     GFP_KERNEL);
+			if (!vsi->rss_hkey_user)
+				return -ENOMEM;
+		}
+		memcpy(vsi->rss_hkey_user, key, I40EVF_HKEY_ARRAY_SIZE);
+		seed = vsi->rss_hkey_user;
+	}
+	if (!vsi->rss_lut_user) {
+		vsi->rss_lut_user = kzalloc(I40EVF_HLUT_ARRAY_SIZE,
+					    GFP_KERNEL);
+		if (!vsi->rss_lut_user)
+			return -ENOMEM;
 	}
 
+	/* Each 32 bits pointed by 'indir' is stored with a lut entry */
+	for (i = 0; i < I40EVF_HLUT_ARRAY_SIZE; i++)
+		vsi->rss_lut_user[i] = (u8)(indir[i]);
+
+	return i40evf_config_rss(vsi, seed, vsi->rss_lut_user,
+				 I40EVF_HLUT_ARRAY_SIZE);
+}
+
+/**
+ * i40evf_get_priv_flags - report device private flags
+ * @dev: network interface device structure
+ *
+ * The get string set count and the string set should be matched for each
+ * flag returned.  Add new strings for each flag to the i40e_priv_flags_strings
+ * array.
+ *
+ * Returns a u32 bitmap of flags.
+ **/
+static u32 i40evf_get_priv_flags(struct net_device *dev)
+{
+	struct i40evf_adapter *adapter = netdev_priv(dev);
+	u32 ret_flags = 0;
+
+	ret_flags |= adapter->flags & I40EVF_FLAG_RX_PS_ENABLED ?
+		I40EVF_PRIV_FLAGS_PS : 0;
+
+	return ret_flags;
+}
+
+/**
+ * i40evf_set_priv_flags - set private flags
+ * @dev: network interface device structure
+ * @flags: bit flags to be set
+ **/
+static int i40evf_set_priv_flags(struct net_device *dev, u32 flags)
+{
+	struct i40evf_adapter *adapter = netdev_priv(dev);
+	bool reset_required = false;
+
+	if ((flags & I40EVF_PRIV_FLAGS_PS) &&
+	    !(adapter->flags & I40EVF_FLAG_RX_PS_ENABLED)) {
+		adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
+		reset_required = true;
+	} else if (!(flags & I40EVF_PRIV_FLAGS_PS) &&
+		   (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED)) {
+		adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
+		reset_required = true;
+	}
+
+	/* if needed, issue reset to cause things to take effect */
+	if (reset_required)
+		i40evf_schedule_reset(adapter);
+
 	return 0;
 }
 
@@ -699,6 +782,8 @@
 	.get_strings		= i40evf_get_strings,
 	.get_ethtool_stats	= i40evf_get_ethtool_stats,
 	.get_sset_count		= i40evf_get_sset_count,
+	.get_priv_flags		= i40evf_get_priv_flags,
+	.set_priv_flags		= i40evf_set_priv_flags,
 	.get_msglevel		= i40evf_get_msglevel,
 	.set_msglevel		= i40evf_set_msglevel,
 	.get_coalesce		= i40evf_get_coalesce,
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -32,9 +32,17 @@
 
 char i40evf_driver_name[] = "i40evf";
 static const char i40evf_driver_string[] =
-	"Intel(R) XL710/X710 Virtual Function Network Driver";
+	"Intel(R) 40-10 Gigabit Virtual Function Network Driver";
 
-#define DRV_VERSION "1.3.33"
+#define DRV_KERN "-k"
+
+#define DRV_VERSION_MAJOR 1
+#define DRV_VERSION_MINOR 4
+#define DRV_VERSION_BUILD 15
+#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
+	     __stringify(DRV_VERSION_MINOR) "." \
+	     __stringify(DRV_VERSION_BUILD) \
+	     DRV_KERN
 const char i40evf_driver_version[] = DRV_VERSION;
 static const char i40evf_copyright[] =
 	"Copyright (c) 2013 - 2015 Intel Corporation.";
@@ -61,6 +69,8 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+static struct workqueue_struct *i40evf_wq;
+
 /**
  * i40evf_allocate_dma_mem_d - OS specific memory alloc for shared code
  * @hw:   pointer to the HW structure
@@ -163,6 +173,19 @@
 }
 
 /**
+ * i40evf_schedule_reset - Set the flags and schedule a reset event
+ * @adapter: board private structure
+ **/
+void i40evf_schedule_reset(struct i40evf_adapter *adapter)
+{
+	if (!(adapter->flags &
+	      (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED))) {
+		adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
+		schedule_work(&adapter->reset_task);
+	}
+}
+
+/**
  * i40evf_tx_timeout - Respond to a Tx Hang
  * @netdev: network interface device structure
  **/
@@ -171,11 +194,7 @@
 	struct i40evf_adapter *adapter = netdev_priv(netdev);
 
 	adapter->tx_timeout_count++;
-	if (!(adapter->flags & (I40EVF_FLAG_RESET_PENDING |
-				I40EVF_FLAG_RESET_NEEDED))) {
-		adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
-		schedule_work(&adapter->reset_task);
-	}
+	i40evf_schedule_reset(adapter);
 }
 
 /**
@@ -259,7 +278,7 @@
 {
 	struct i40e_hw *hw = &adapter->hw;
 	int i;
-	uint32_t dyn_ctl;
+	u32 dyn_ctl;
 
 	if (mask & 1) {
 		dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTL01);
@@ -307,10 +326,9 @@
 	struct i40e_hw *hw = &adapter->hw;
 	u32 val;
 
-	/* handle non-queue interrupts */
-	rd32(hw, I40E_VFINT_ICR01);
-	rd32(hw, I40E_VFINT_ICR0_ENA1);
-
+	/* handle non-queue interrupts, these reads clear the registers */
+	val = rd32(hw, I40E_VFINT_ICR01);
+	val = rd32(hw, I40E_VFINT_ICR0_ENA1);
 
 	val = rd32(hw, I40E_VFINT_DYN_CTL01) |
 	      I40E_VFINT_DYN_CTL01_CLEARPBA_MASK;
@@ -348,8 +366,8 @@
 static void
 i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx)
 {
-	struct i40e_q_vector *q_vector = adapter->q_vector[v_idx];
-	struct i40e_ring *rx_ring = adapter->rx_rings[r_idx];
+	struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx];
+	struct i40e_ring *rx_ring = &adapter->rx_rings[r_idx];
 
 	rx_ring->q_vector = q_vector;
 	rx_ring->next = q_vector->rx.ring;
@@ -369,8 +387,8 @@
 static void
 i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx)
 {
-	struct i40e_q_vector *q_vector = adapter->q_vector[v_idx];
-	struct i40e_ring *tx_ring = adapter->tx_rings[t_idx];
+	struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx];
+	struct i40e_ring *tx_ring = &adapter->tx_rings[t_idx];
 
 	tx_ring->q_vector = q_vector;
 	tx_ring->next = q_vector->tx.ring;
@@ -465,7 +483,7 @@
 		return;
 
 	for (i = 0; i < q_vectors; i++)
-		i40evf_msix_clean_rings(0, adapter->q_vector[i]);
+		i40evf_msix_clean_rings(0, &adapter->q_vectors[i]);
 }
 
 #endif
@@ -487,7 +505,7 @@
 	q_vectors = adapter->num_msix_vectors - NONQ_VECS;
 
 	for (vector = 0; vector < q_vectors; vector++) {
-		struct i40e_q_vector *q_vector = adapter->q_vector[vector];
+		struct i40e_q_vector *q_vector = &adapter->q_vectors[vector];
 
 		if (q_vector->tx.ring && q_vector->rx.ring) {
 			snprintf(q_vector->name, sizeof(q_vector->name) - 1,
@@ -532,7 +550,7 @@
 			adapter->msix_entries[vector + NONQ_VECS].vector,
 			NULL);
 		free_irq(adapter->msix_entries[vector + NONQ_VECS].vector,
-			 adapter->q_vector[vector]);
+			 &adapter->q_vectors[vector]);
 	}
 	return err;
 }
@@ -582,7 +600,7 @@
 		irq_set_affinity_hint(adapter->msix_entries[i+1].vector,
 				      NULL);
 		free_irq(adapter->msix_entries[i+1].vector,
-			 adapter->q_vector[i]);
+			 &adapter->q_vectors[i]);
 	}
 }
 
@@ -611,7 +629,7 @@
 	int i;
 
 	for (i = 0; i < adapter->num_active_queues; i++)
-		adapter->tx_rings[i]->tail = hw->hw_addr + I40E_QTX_TAIL1(i);
+		adapter->tx_rings[i].tail = hw->hw_addr + I40E_QTX_TAIL1(i);
 }
 
 /**
@@ -629,35 +647,22 @@
 	int rx_buf_len;
 
 
-	adapter->flags &= ~I40EVF_FLAG_RX_PS_CAPABLE;
-	adapter->flags |= I40EVF_FLAG_RX_1BUF_CAPABLE;
-
-	/* Decide whether to use packet split mode or not */
-	if (netdev->mtu > ETH_DATA_LEN) {
-		if (adapter->flags & I40EVF_FLAG_RX_PS_CAPABLE)
-			adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
-		else
-			adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
-	} else {
-		if (adapter->flags & I40EVF_FLAG_RX_1BUF_CAPABLE)
-			adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
-		else
-			adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
-	}
-
 	/* Set the RX buffer length according to the mode */
-	if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
-		rx_buf_len = I40E_RX_HDR_SIZE;
-	} else {
-		if (netdev->mtu <= ETH_DATA_LEN)
-			rx_buf_len = I40EVF_RXBUFFER_2048;
-		else
-			rx_buf_len = ALIGN(max_frame, 1024);
-	}
+	if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED ||
+	    netdev->mtu <= ETH_DATA_LEN)
+		rx_buf_len = I40EVF_RXBUFFER_2048;
+	else
+		rx_buf_len = ALIGN(max_frame, 1024);
 
 	for (i = 0; i < adapter->num_active_queues; i++) {
-		adapter->rx_rings[i]->tail = hw->hw_addr + I40E_QRX_TAIL1(i);
-		adapter->rx_rings[i]->rx_buf_len = rx_buf_len;
+		adapter->rx_rings[i].tail = hw->hw_addr + I40E_QRX_TAIL1(i);
+		adapter->rx_rings[i].rx_buf_len = rx_buf_len;
+		if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
+			set_ring_ps_enabled(&adapter->rx_rings[i]);
+			adapter->rx_rings[i].rx_hdr_len = I40E_RX_HDR_SIZE;
+		} else {
+			clear_ring_ps_enabled(&adapter->rx_rings[i]);
+		}
 	}
 }
 
@@ -954,7 +959,7 @@
 	for (q_idx = 0; q_idx < q_vectors; q_idx++) {
 		struct napi_struct *napi;
 
-		q_vector = adapter->q_vector[q_idx];
+		q_vector = &adapter->q_vectors[q_idx];
 		napi = &q_vector->napi;
 		napi_enable(napi);
 	}
@@ -971,7 +976,7 @@
 	int q_vectors = adapter->num_msix_vectors - NONQ_VECS;
 
 	for (q_idx = 0; q_idx < q_vectors; q_idx++) {
-		q_vector = adapter->q_vector[q_idx];
+		q_vector = &adapter->q_vectors[q_idx];
 		napi_disable(&q_vector->napi);
 	}
 }
@@ -992,9 +997,14 @@
 	adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_QUEUES;
 
 	for (i = 0; i < adapter->num_active_queues; i++) {
-		struct i40e_ring *ring = adapter->rx_rings[i];
+		struct i40e_ring *ring = &adapter->rx_rings[i];
 
+	if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
+		i40evf_alloc_rx_headers(ring);
+		i40evf_alloc_rx_buffers_ps(ring, ring->count);
+	} else {
 		i40evf_alloc_rx_buffers_1buf(ring, ring->count);
+	}
 		ring->next_to_use = ring->count - 1;
 		writel(ring->next_to_use, ring->tail);
 	}
@@ -1025,7 +1035,7 @@
 	struct net_device *netdev = adapter->netdev;
 	struct i40evf_mac_filter *f;
 
-	if (adapter->state == __I40EVF_DOWN)
+	if (adapter->state <= __I40EVF_DOWN_PENDING)
 		return;
 
 	while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
@@ -1112,16 +1122,12 @@
  **/
 static void i40evf_free_queues(struct i40evf_adapter *adapter)
 {
-	int i;
-
 	if (!adapter->vsi_res)
 		return;
-	for (i = 0; i < adapter->num_active_queues; i++) {
-		if (adapter->tx_rings[i])
-			kfree_rcu(adapter->tx_rings[i], rcu);
-		adapter->tx_rings[i] = NULL;
-		adapter->rx_rings[i] = NULL;
-	}
+	kfree(adapter->tx_rings);
+	adapter->tx_rings = NULL;
+	kfree(adapter->rx_rings);
+	adapter->rx_rings = NULL;
 }
 
 /**
@@ -1136,13 +1142,20 @@
 {
 	int i;
 
+	adapter->tx_rings = kcalloc(adapter->num_active_queues,
+				    sizeof(struct i40e_ring), GFP_KERNEL);
+	if (!adapter->tx_rings)
+		goto err_out;
+	adapter->rx_rings = kcalloc(adapter->num_active_queues,
+				    sizeof(struct i40e_ring), GFP_KERNEL);
+	if (!adapter->rx_rings)
+		goto err_out;
+
 	for (i = 0; i < adapter->num_active_queues; i++) {
 		struct i40e_ring *tx_ring;
 		struct i40e_ring *rx_ring;
 
-		tx_ring = kzalloc(sizeof(*tx_ring) * 2, GFP_KERNEL);
-		if (!tx_ring)
-			goto err_out;
+		tx_ring = &adapter->tx_rings[i];
 
 		tx_ring->queue_index = i;
 		tx_ring->netdev = adapter->netdev;
@@ -1150,14 +1163,12 @@
 		tx_ring->count = adapter->tx_desc_count;
 		if (adapter->flags & I40E_FLAG_WB_ON_ITR_CAPABLE)
 			tx_ring->flags |= I40E_TXR_FLAGS_WB_ON_ITR;
-		adapter->tx_rings[i] = tx_ring;
 
-		rx_ring = &tx_ring[1];
+		rx_ring = &adapter->rx_rings[i];
 		rx_ring->queue_index = i;
 		rx_ring->netdev = adapter->netdev;
 		rx_ring->dev = &adapter->pdev->dev;
 		rx_ring->count = adapter->rx_desc_count;
-		adapter->rx_rings[i] = rx_ring;
 	}
 
 	return 0;
@@ -1207,115 +1218,277 @@
 	err = i40evf_acquire_msix_vectors(adapter, v_budget);
 
 out:
-	adapter->netdev->real_num_tx_queues = pairs;
+	netif_set_real_num_rx_queues(adapter->netdev, pairs);
+	netif_set_real_num_tx_queues(adapter->netdev, pairs);
 	return err;
 }
 
 /**
- * i40e_configure_rss_aq - Prepare for RSS using AQ commands
+ * i40e_config_rss_aq - Prepare for RSS using AQ commands
  * @vsi: vsi structure
  * @seed: RSS hash seed
+ * @lut: Lookup table
+ * @lut_size: Lookup table size
+ *
+ * Return 0 on success, negative on failure
  **/
-static void i40evf_configure_rss_aq(struct i40e_vsi *vsi, const u8 *seed)
+static int i40evf_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
+				u8 *lut, u16 lut_size)
 {
-	struct i40e_aqc_get_set_rss_key_data rss_key;
 	struct i40evf_adapter *adapter = vsi->back;
 	struct i40e_hw *hw = &adapter->hw;
-	int ret = 0, i;
-	u8 *rss_lut;
+	int ret = 0;
 
 	if (!vsi->id)
-		return;
+		return -EINVAL;
 
 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
 		/* bail because we already have a command pending */
 		dev_err(&adapter->pdev->dev, "Cannot confiure RSS, command %d pending\n",
 			adapter->current_op);
-		return;
+		return -EBUSY;
 	}
 
-	memset(&rss_key, 0, sizeof(rss_key));
-	memcpy(&rss_key, seed, sizeof(rss_key));
+	if (seed) {
+		struct i40e_aqc_get_set_rss_key_data *rss_key =
+			(struct i40e_aqc_get_set_rss_key_data *)seed;
+		ret = i40evf_aq_set_rss_key(hw, vsi->id, rss_key);
+		if (ret) {
+			dev_err(&adapter->pdev->dev, "Cannot set RSS key, err %s aq_err %s\n",
+				i40evf_stat_str(hw, ret),
+				i40evf_aq_str(hw, hw->aq.asq_last_status));
+			return ret;
+		}
+	}
 
-	rss_lut = kzalloc(((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4), GFP_KERNEL);
-	if (!rss_lut)
-		return;
+	if (lut) {
+		ret = i40evf_aq_set_rss_lut(hw, vsi->id, false, lut, lut_size);
+		if (ret) {
+			dev_err(&adapter->pdev->dev,
+				"Cannot set RSS lut, err %s aq_err %s\n",
+				i40evf_stat_str(hw, ret),
+				i40evf_aq_str(hw, hw->aq.asq_last_status));
+			return ret;
+		}
+	}
 
-	/* Populate the LUT with max no. PF queues in round robin fashion */
-	for (i = 0; i <= (I40E_VFQF_HLUT_MAX_INDEX * 4); i++)
-		rss_lut[i] = i % adapter->num_active_queues;
+	return ret;
+}
 
-	ret = i40evf_aq_set_rss_key(hw, vsi->id, &rss_key);
-	if (ret) {
-		dev_err(&adapter->pdev->dev,
-			"Cannot set RSS key, err %s aq_err %s\n",
-			i40evf_stat_str(hw, ret),
-			i40evf_aq_str(hw, hw->aq.asq_last_status));
-		return;
+/**
+ * i40evf_config_rss_reg - Configure RSS keys and lut by writing registers
+ * @vsi: Pointer to vsi structure
+ * @seed: RSS hash seed
+ * @lut: Lookup table
+ * @lut_size: Lookup table size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40evf_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
+				 const u8 *lut, u16 lut_size)
+{
+	struct i40evf_adapter *adapter = vsi->back;
+	struct i40e_hw *hw = &adapter->hw;
+	u16 i;
+
+	if (seed) {
+		u32 *seed_dw = (u32 *)seed;
+
+		for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
+			wr32(hw, I40E_VFQF_HKEY(i), seed_dw[i]);
 	}
 
-	ret = i40evf_aq_set_rss_lut(hw, vsi->id, false, rss_lut,
-				    (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4);
-	if (ret)
-		dev_err(&adapter->pdev->dev,
-			"Cannot set RSS lut, err %s aq_err %s\n",
-			i40evf_stat_str(hw, ret),
-			i40evf_aq_str(hw, hw->aq.asq_last_status));
+	if (lut) {
+		u32 *lut_dw = (u32 *)lut;
+
+		if (lut_size != I40EVF_HLUT_ARRAY_SIZE)
+			return -EINVAL;
+
+		for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++)
+			wr32(hw, I40E_VFQF_HLUT(i), lut_dw[i]);
+	}
+	i40e_flush(hw);
+
+	return 0;
 }
 
 /**
- * i40e_configure_rss_reg - Prepare for RSS if used
- * @adapter: board private structure
- * @seed: RSS hash seed
+ *  * i40evf_get_rss_aq - Get RSS keys and lut by using AQ commands
+ *  @vsi: Pointer to vsi structure
+ *  @seed: RSS hash seed
+ *  @lut: Lookup table
+ *  @lut_size: Lookup table size
+ *
+ *  Return 0 on success, negative on failure
  **/
-static void i40evf_configure_rss_reg(struct i40evf_adapter *adapter,
-				     const u8 *seed)
+static int i40evf_get_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
+			     u8 *lut, u16 lut_size)
 {
+	struct i40evf_adapter *adapter = vsi->back;
 	struct i40e_hw *hw = &adapter->hw;
-	u32 *seed_dw = (u32 *)seed;
-	u32 cqueue = 0;
-	u32 lut = 0;
-	int i, j;
+	int ret = 0;
 
-	/* Fill out hash function seed */
-	for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
-		wr32(hw, I40E_VFQF_HKEY(i), seed_dw[i]);
-
-	/* Populate the LUT with max no. PF queues in round robin fashion */
-	for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
-		lut = 0;
-		for (j = 0; j < 4; j++) {
-			if (cqueue == adapter->num_active_queues)
-				cqueue = 0;
-			lut |= ((cqueue) << (8 * j));
-			cqueue++;
+	if (seed) {
+		ret = i40evf_aq_get_rss_key(hw, vsi->id,
+			(struct i40e_aqc_get_set_rss_key_data *)seed);
+		if (ret) {
+			dev_err(&adapter->pdev->dev,
+				"Cannot get RSS key, err %s aq_err %s\n",
+				i40evf_stat_str(hw, ret),
+				i40evf_aq_str(hw, hw->aq.asq_last_status));
+			return ret;
 		}
-		wr32(hw, I40E_VFQF_HLUT(i), lut);
 	}
-	i40e_flush(hw);
+
+	if (lut) {
+		ret = i40evf_aq_get_rss_lut(hw, vsi->id, seed, lut, lut_size);
+		if (ret) {
+			dev_err(&adapter->pdev->dev,
+				"Cannot get RSS lut, err %s aq_err %s\n",
+				i40evf_stat_str(hw, ret),
+				i40evf_aq_str(hw, hw->aq.asq_last_status));
+			return ret;
+		}
+	}
+
+	return ret;
 }
 
 /**
- * i40evf_configure_rss - Prepare for RSS
+ *  * i40evf_get_rss_reg - Get RSS keys and lut by reading registers
+ *  @vsi: Pointer to vsi structure
+ *  @seed: RSS hash seed
+ *  @lut: Lookup table
+ *  @lut_size: Lookup table size
+ *
+ *  Returns 0 on success, negative on failure
+ **/
+static int i40evf_get_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
+			      const u8 *lut, u16 lut_size)
+{
+	struct i40evf_adapter *adapter = vsi->back;
+	struct i40e_hw *hw = &adapter->hw;
+	u16 i;
+
+	if (seed) {
+		u32 *seed_dw = (u32 *)seed;
+
+		for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
+			seed_dw[i] = rd32(hw, I40E_VFQF_HKEY(i));
+	}
+
+	if (lut) {
+		u32 *lut_dw = (u32 *)lut;
+
+		if (lut_size != I40EVF_HLUT_ARRAY_SIZE)
+			return -EINVAL;
+
+		for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++)
+			lut_dw[i] = rd32(hw, I40E_VFQF_HLUT(i));
+	}
+
+	return 0;
+}
+
+/**
+ * i40evf_config_rss - Configure RSS keys and lut
+ * @vsi: Pointer to vsi structure
+ * @seed: RSS hash seed
+ * @lut: Lookup table
+ * @lut_size: Lookup table size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int i40evf_config_rss(struct i40e_vsi *vsi, const u8 *seed,
+		      u8 *lut, u16 lut_size)
+{
+	struct i40evf_adapter *adapter = vsi->back;
+
+	if (RSS_AQ(adapter))
+		return i40evf_config_rss_aq(vsi, seed, lut, lut_size);
+	else
+		return i40evf_config_rss_reg(vsi, seed, lut, lut_size);
+}
+
+/**
+ * i40evf_get_rss - Get RSS keys and lut
+ * @vsi: Pointer to vsi structure
+ * @seed: RSS hash seed
+ * @lut: Lookup table
+ * @lut_size: Lookup table size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int i40evf_get_rss(struct i40e_vsi *vsi, const u8 *seed, u8 *lut, u16 lut_size)
+{
+	struct i40evf_adapter *adapter = vsi->back;
+
+	if (RSS_AQ(adapter))
+		return i40evf_get_rss_aq(vsi, seed, lut, lut_size);
+	else
+		return i40evf_get_rss_reg(vsi, seed, lut, lut_size);
+}
+
+/**
+ * i40evf_fill_rss_lut - Fill the lut with default values
+ * @lut: Lookup table to be filled with
+ * @rss_table_size: Lookup table size
+ * @rss_size: Range of queue number for hashing
+ **/
+static void i40evf_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size)
+{
+	u16 i;
+
+	for (i = 0; i < rss_table_size; i++)
+		lut[i] = i % rss_size;
+}
+
+/**
+ * i40evf_init_rss - Prepare for RSS
  * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
  **/
-static void i40evf_configure_rss(struct i40evf_adapter *adapter)
+static int i40evf_init_rss(struct i40evf_adapter *adapter)
 {
+	struct i40e_vsi *vsi = &adapter->vsi;
 	struct i40e_hw *hw = &adapter->hw;
 	u8 seed[I40EVF_HKEY_ARRAY_SIZE];
 	u64 hena;
-
-	netdev_rss_key_fill((void *)seed, I40EVF_HKEY_ARRAY_SIZE);
+	u8 *lut;
+	int ret;
 
 	/* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */
-	hena = I40E_DEFAULT_RSS_HENA;
+	if (adapter->vf_res->vf_offload_flags &
+					I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
+		hena = I40E_DEFAULT_RSS_HENA_EXPANDED;
+	else
+		hena = I40E_DEFAULT_RSS_HENA;
 	wr32(hw, I40E_VFQF_HENA(0), (u32)hena);
 	wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
 
-	if (RSS_AQ(adapter))
-		i40evf_configure_rss_aq(&adapter->vsi, seed);
+	lut = kzalloc(I40EVF_HLUT_ARRAY_SIZE, GFP_KERNEL);
+	if (!lut)
+		return -ENOMEM;
+
+	/* Use user configured lut if there is one, otherwise use default */
+	if (vsi->rss_lut_user)
+		memcpy(lut, vsi->rss_lut_user, I40EVF_HLUT_ARRAY_SIZE);
 	else
-		i40evf_configure_rss_reg(adapter, seed);
+		i40evf_fill_rss_lut(lut, I40EVF_HLUT_ARRAY_SIZE,
+				    adapter->num_active_queues);
+
+	/* Use user configured hash key if there is one, otherwise
+	 * user default.
+	 */
+	if (vsi->rss_hkey_user)
+		memcpy(seed, vsi->rss_hkey_user, I40EVF_HKEY_ARRAY_SIZE);
+	else
+		netdev_rss_key_fill((void *)seed, I40EVF_HKEY_ARRAY_SIZE);
+	ret = i40evf_config_rss(vsi, seed, lut, I40EVF_HLUT_ARRAY_SIZE);
+	kfree(lut);
+
+	return ret;
 }
 
 /**
@@ -1327,21 +1500,22 @@
  **/
 static int i40evf_alloc_q_vectors(struct i40evf_adapter *adapter)
 {
-	int q_idx, num_q_vectors;
+	int q_idx = 0, num_q_vectors;
 	struct i40e_q_vector *q_vector;
 
 	num_q_vectors = adapter->num_msix_vectors - NONQ_VECS;
+	adapter->q_vectors = kcalloc(num_q_vectors, sizeof(*q_vector),
+				     GFP_KERNEL);
+	if (!adapter->q_vectors)
+		goto err_out;
 
 	for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
-		q_vector = kzalloc(sizeof(*q_vector), GFP_KERNEL);
-		if (!q_vector)
-			goto err_out;
+		q_vector = &adapter->q_vectors[q_idx];
 		q_vector->adapter = adapter;
 		q_vector->vsi = &adapter->vsi;
 		q_vector->v_idx = q_idx;
 		netif_napi_add(adapter->netdev, &q_vector->napi,
 			       i40evf_napi_poll, NAPI_POLL_WEIGHT);
-		adapter->q_vector[q_idx] = q_vector;
 	}
 
 	return 0;
@@ -1349,11 +1523,10 @@
 err_out:
 	while (q_idx) {
 		q_idx--;
-		q_vector = adapter->q_vector[q_idx];
+		q_vector = &adapter->q_vectors[q_idx];
 		netif_napi_del(&q_vector->napi);
-		kfree(q_vector);
-		adapter->q_vector[q_idx] = NULL;
 	}
+	kfree(adapter->q_vectors);
 	return -ENOMEM;
 }
 
@@ -1374,13 +1547,11 @@
 	napi_vectors = adapter->num_active_queues;
 
 	for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
-		struct i40e_q_vector *q_vector = adapter->q_vector[q_idx];
-
-		adapter->q_vector[q_idx] = NULL;
+		struct i40e_q_vector *q_vector = &adapter->q_vectors[q_idx];
 		if (q_idx < napi_vectors)
 			netif_napi_del(&q_vector->napi);
-		kfree(q_vector);
 	}
+	kfree(adapter->q_vectors);
 }
 
 /**
@@ -1439,6 +1610,22 @@
 }
 
 /**
+ * i40evf_clear_rss_config_user - Clear user configurations of RSS
+ * @vsi: Pointer to VSI structure
+ **/
+static void i40evf_clear_rss_config_user(struct i40e_vsi *vsi)
+{
+	if (!vsi)
+		return;
+
+	kfree(vsi->rss_hkey_user);
+	vsi->rss_hkey_user = NULL;
+
+	kfree(vsi->rss_lut_user);
+	vsi->rss_lut_user = NULL;
+}
+
+/**
  * i40evf_watchdog_timer - Periodic call-back timer
  * @data: pointer to adapter disguised as unsigned long
  **/
@@ -1565,7 +1752,7 @@
 		 * PF, so we don't have to set current_op as we will
 		 * not get a response through the ARQ.
 		 */
-		i40evf_configure_rss(adapter);
+		i40evf_init_rss(adapter);
 		adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_RSS;
 		goto watchdog_done;
 	}
@@ -1651,6 +1838,7 @@
 			break;
 		msleep(I40EVF_RESET_WAIT_MS);
 	}
+	pci_set_master(adapter->pdev);
 	/* extra wait to make sure minimum wait is met */
 	msleep(I40EVF_RESET_WAIT_MS);
 	if (i == I40EVF_RESET_WAIT_COUNT) {
@@ -1695,6 +1883,7 @@
 		adapter->netdev->flags &= ~IFF_UP;
 		clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
 		adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
+		adapter->state = __I40EVF_DOWN;
 		dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n");
 		return; /* Do not attempt to reinit. It's dead, Jim. */
 	}
@@ -1864,9 +2053,12 @@
 {
 	int i;
 
+	if (!adapter->tx_rings)
+		return;
+
 	for (i = 0; i < adapter->num_active_queues; i++)
-		if (adapter->tx_rings[i]->desc)
-			i40evf_free_tx_resources(adapter->tx_rings[i]);
+		if (adapter->tx_rings[i].desc)
+			i40evf_free_tx_resources(&adapter->tx_rings[i]);
 }
 
 /**
@@ -1884,8 +2076,8 @@
 	int i, err = 0;
 
 	for (i = 0; i < adapter->num_active_queues; i++) {
-		adapter->tx_rings[i]->count = adapter->tx_desc_count;
-		err = i40evf_setup_tx_descriptors(adapter->tx_rings[i]);
+		adapter->tx_rings[i].count = adapter->tx_desc_count;
+		err = i40evf_setup_tx_descriptors(&adapter->tx_rings[i]);
 		if (!err)
 			continue;
 		dev_err(&adapter->pdev->dev,
@@ -1911,8 +2103,8 @@
 	int i, err = 0;
 
 	for (i = 0; i < adapter->num_active_queues; i++) {
-		adapter->rx_rings[i]->count = adapter->rx_desc_count;
-		err = i40evf_setup_rx_descriptors(adapter->rx_rings[i]);
+		adapter->rx_rings[i].count = adapter->rx_desc_count;
+		err = i40evf_setup_rx_descriptors(&adapter->rx_rings[i]);
 		if (!err)
 			continue;
 		dev_err(&adapter->pdev->dev,
@@ -1932,9 +2124,12 @@
 {
 	int i;
 
+	if (!adapter->rx_rings)
+		return;
+
 	for (i = 0; i < adapter->num_active_queues; i++)
-		if (adapter->rx_rings[i]->desc)
-			i40evf_free_rx_resources(adapter->rx_rings[i]);
+		if (adapter->rx_rings[i].desc)
+			i40evf_free_rx_resources(&adapter->rx_rings[i]);
 }
 
 /**
@@ -1958,7 +2153,8 @@
 		dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n");
 		return -EIO;
 	}
-	if (adapter->state != __I40EVF_DOWN || adapter->aq_required)
+
+	if (adapter->state != __I40EVF_DOWN)
 		return -EBUSY;
 
 	/* allocate transmit descriptors */
@@ -2013,14 +2209,14 @@
 {
 	struct i40evf_adapter *adapter = netdev_priv(netdev);
 
-	if (adapter->state <= __I40EVF_DOWN)
+	if (adapter->state <= __I40EVF_DOWN_PENDING)
 		return 0;
 
 
 	set_bit(__I40E_DOWN, &adapter->vsi.state);
 
 	i40evf_down(adapter);
-	adapter->state = __I40EVF_DOWN;
+	adapter->state = __I40EVF_DOWN_PENDING;
 	i40evf_free_traffic_irqs(adapter);
 
 	return 0;
@@ -2137,13 +2333,28 @@
 	netdev->features |= NETIF_F_HIGHDMA |
 			    NETIF_F_SG |
 			    NETIF_F_IP_CSUM |
-			    NETIF_F_SCTP_CSUM |
+			    NETIF_F_SCTP_CRC |
 			    NETIF_F_IPV6_CSUM |
 			    NETIF_F_TSO |
 			    NETIF_F_TSO6 |
+			    NETIF_F_TSO_ECN |
+			    NETIF_F_GSO_GRE	       |
+			    NETIF_F_GSO_UDP_TUNNEL |
 			    NETIF_F_RXCSUM |
 			    NETIF_F_GRO;
 
+	netdev->hw_enc_features |= NETIF_F_IP_CSUM	       |
+				   NETIF_F_IPV6_CSUM	       |
+				   NETIF_F_TSO		       |
+				   NETIF_F_TSO6		       |
+				   NETIF_F_TSO_ECN	       |
+				   NETIF_F_GSO_GRE	       |
+				   NETIF_F_GSO_UDP_TUNNEL      |
+				   NETIF_F_GSO_UDP_TUNNEL_CSUM;
+
+	if (adapter->flags & I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE)
+		netdev->features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
+
 	/* copy netdev features into list of user selectable features */
 	netdev->hw_features |= netdev->features;
 	netdev->hw_features &= ~NETIF_F_RXCSUM;
@@ -2263,6 +2474,14 @@
 		if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
 			err = i40evf_send_vf_config_msg(adapter);
 			goto err;
+		} else if (err == I40E_ERR_PARAM) {
+			/* We only get ERR_PARAM if the device is in a very bad
+			 * state or if we've been disabled for previous bad
+			 * behavior. Either way, we're done now.
+			 */
+			i40evf_shutdown_adminq(hw);
+			dev_err(&pdev->dev, "Unable to get VF config due to PF error condition, not retrying\n");
+			return;
 		}
 		if (err) {
 			dev_err(&pdev->dev, "Unable to get VF config (%d)\n",
@@ -2274,11 +2493,20 @@
 	default:
 		goto err_alloc;
 	}
+
+	if (hw->mac.type == I40E_MAC_X722_VF)
+		adapter->flags |= I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE;
+
 	if (i40evf_process_config(adapter))
 		goto err_alloc;
 	adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
 
 	adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED;
+	adapter->flags |= I40EVF_FLAG_RX_1BUF_CAPABLE;
+	adapter->flags |= I40EVF_FLAG_RX_PS_CAPABLE;
+
+	/* Default to single buffer rx, can be changed through ethtool. */
+	adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
 
 	netdev->netdev_ops = &i40evf_netdev_ops;
 	i40evf_set_ethtool_ops(netdev);
@@ -2310,10 +2538,9 @@
 		goto err_sw_init;
 	i40evf_map_rings_to_vectors(adapter);
 	if (adapter->vf_res->vf_offload_flags &
-		    I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
+	    I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
 		adapter->flags |= I40EVF_FLAG_WB_ON_ITR_CAPABLE;
-	if (!RSS_AQ(adapter))
-		i40evf_configure_rss(adapter);
+
 	err = i40evf_request_misc_irq(adapter);
 	if (err)
 		goto err_sw_init;
@@ -2334,7 +2561,6 @@
 	if (netdev->features & NETIF_F_GRO)
 		dev_info(&pdev->dev, "GRO is enabled\n");
 
-	dev_info(&pdev->dev, "%s\n", i40evf_driver_string);
 	adapter->state = __I40EVF_DOWN;
 	set_bit(__I40E_DOWN, &adapter->vsi.state);
 	i40evf_misc_irq_enable(adapter);
@@ -2343,7 +2569,7 @@
 		adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS;
 		mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
 	} else {
-		i40evf_configure_rss(adapter);
+		i40evf_init_rss(adapter);
 	}
 	return;
 restart:
@@ -2438,8 +2664,7 @@
 
 	pci_set_master(pdev);
 
-	netdev = alloc_etherdev_mq(sizeof(struct i40evf_adapter),
-				   MAX_TX_QUEUES);
+	netdev = alloc_etherdev_mq(sizeof(struct i40evf_adapter), MAX_QUEUES);
 	if (!netdev) {
 		err = -ENOMEM;
 		goto err_alloc_etherdev;
@@ -2632,6 +2857,9 @@
 
 	flush_scheduled_work();
 
+	/* Clear user configurations for RSS */
+	i40evf_clear_rss_config_user(&adapter->vsi);
+
 	if (hw->aq.asq.count)
 		i40evf_shutdown_adminq(hw);
 
@@ -2692,6 +2920,11 @@
 
 	pr_info("%s\n", i40evf_copyright);
 
+	i40evf_wq = create_singlethread_workqueue(i40evf_driver_name);
+	if (!i40evf_wq) {
+		pr_err("%s: Failed to create workqueue\n", i40evf_driver_name);
+		return -ENOMEM;
+	}
 	ret = pci_register_driver(&i40evf_driver);
 	return ret;
 }
@@ -2707,6 +2940,7 @@
 static void __exit i40evf_exit_module(void)
 {
 	pci_unregister_driver(&i40evf_driver);
+	destroy_workqueue(i40evf_wq);
 }
 
 module_exit(i40evf_exit_module);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ linux-4.4.0/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
@@ -157,7 +157,9 @@
 	       I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ |
 	       I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG |
 	       I40E_VIRTCHNL_VF_OFFLOAD_VLAN |
-	       I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
+	       I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR |
+	       I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2;
+
 	adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES;
 	adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG;
 	if (PF_IS_V11(adapter))
@@ -242,7 +244,7 @@
 	adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES;
 	len = sizeof(struct i40e_virtchnl_vsi_queue_config_info) +
 		       (sizeof(struct i40e_virtchnl_queue_pair_info) * pairs);
-	vqci = kzalloc(len, GFP_ATOMIC);
+	vqci = kzalloc(len, GFP_KERNEL);
 	if (!vqci)
 		return;
 
@@ -255,19 +257,23 @@
 	for (i = 0; i < pairs; i++) {
 		vqpi->txq.vsi_id = vqci->vsi_id;
 		vqpi->txq.queue_id = i;
-		vqpi->txq.ring_len = adapter->tx_rings[i]->count;
-		vqpi->txq.dma_ring_addr = adapter->tx_rings[i]->dma;
+		vqpi->txq.ring_len = adapter->tx_rings[i].count;
+		vqpi->txq.dma_ring_addr = adapter->tx_rings[i].dma;
 		vqpi->txq.headwb_enabled = 1;
 		vqpi->txq.dma_headwb_addr = vqpi->txq.dma_ring_addr +
 		    (vqpi->txq.ring_len * sizeof(struct i40e_tx_desc));
 
 		vqpi->rxq.vsi_id = vqci->vsi_id;
 		vqpi->rxq.queue_id = i;
-		vqpi->rxq.ring_len = adapter->rx_rings[i]->count;
-		vqpi->rxq.dma_ring_addr = adapter->rx_rings[i]->dma;
+		vqpi->rxq.ring_len = adapter->rx_rings[i].count;
+		vqpi->rxq.dma_ring_addr = adapter->rx_rings[i].dma;
 		vqpi->rxq.max_pkt_size = adapter->netdev->mtu
 					+ ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
-		vqpi->rxq.databuffer_size = adapter->rx_rings[i]->rx_buf_len;
+		vqpi->rxq.databuffer_size = adapter->rx_rings[i].rx_buf_len;
+		if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
+			vqpi->rxq.splithdr_enabled = true;
+			vqpi->rxq.hdr_size = I40E_RX_HDR_SIZE;
+		}
 		vqpi++;
 	}
 
@@ -353,14 +359,14 @@
 	len = sizeof(struct i40e_virtchnl_irq_map_info) +
 	      (adapter->num_msix_vectors *
 		sizeof(struct i40e_virtchnl_vector_map));
-	vimi = kzalloc(len, GFP_ATOMIC);
+	vimi = kzalloc(len, GFP_KERNEL);
 	if (!vimi)
 		return;
 
 	vimi->num_vectors = adapter->num_msix_vectors;
 	/* Queue vectors first */
 	for (v_idx = 0; v_idx < q_vectors; v_idx++) {
-		q_vector = adapter->q_vector[v_idx];
+		q_vector = adapter->q_vectors + v_idx;
 		vimi->vecmap[v_idx].vsi_id = adapter->vsi_res->vsi_id;
 		vimi->vecmap[v_idx].vector_id = v_idx + NONQ_VECS;
 		vimi->vecmap[v_idx].txq_map = q_vector->ring_mask;
@@ -391,6 +397,7 @@
 	struct i40e_virtchnl_ether_addr_list *veal;
 	int len, i = 0, count = 0;
 	struct i40evf_mac_filter *f;
+	bool more = false;
 
 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
 		/* bail because we already have a command pending */
@@ -415,10 +422,12 @@
 		count = (I40EVF_MAX_AQ_BUF_SIZE -
 			 sizeof(struct i40e_virtchnl_ether_addr_list)) /
 			sizeof(struct i40e_virtchnl_ether_addr);
-		len = I40EVF_MAX_AQ_BUF_SIZE;
+		len = sizeof(struct i40e_virtchnl_ether_addr_list) +
+		      (count * sizeof(struct i40e_virtchnl_ether_addr));
+		more = true;
 	}
 
-	veal = kzalloc(len, GFP_ATOMIC);
+	veal = kzalloc(len, GFP_KERNEL);
 	if (!veal)
 		return;
 
@@ -431,7 +440,8 @@
 			f->add = false;
 		}
 	}
-	adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER;
+	if (!more)
+		adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER;
 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
 			   (u8 *)veal, len);
 	kfree(veal);
@@ -450,6 +460,7 @@
 	struct i40e_virtchnl_ether_addr_list *veal;
 	struct i40evf_mac_filter *f, *ftmp;
 	int len, i = 0, count = 0;
+	bool more = false;
 
 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
 		/* bail because we already have a command pending */
@@ -474,9 +485,11 @@
 		count = (I40EVF_MAX_AQ_BUF_SIZE -
 			 sizeof(struct i40e_virtchnl_ether_addr_list)) /
 			sizeof(struct i40e_virtchnl_ether_addr);
-		len = I40EVF_MAX_AQ_BUF_SIZE;
+		len = sizeof(struct i40e_virtchnl_ether_addr_list) +
+		      (count * sizeof(struct i40e_virtchnl_ether_addr));
+		more = true;
 	}
-	veal = kzalloc(len, GFP_ATOMIC);
+	veal = kzalloc(len, GFP_KERNEL);
 	if (!veal)
 		return;
 
@@ -490,7 +503,8 @@
 			kfree(f);
 		}
 	}
-	adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+	if (!more)
+		adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER;
 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS,
 			   (u8 *)veal, len);
 	kfree(veal);
@@ -509,6 +523,7 @@
 	struct i40e_virtchnl_vlan_filter_list *vvfl;
 	int len, i = 0, count = 0;
 	struct i40evf_vlan_filter *f;
+	bool more = false;
 
 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
 		/* bail because we already have a command pending */
@@ -534,9 +549,11 @@
 		count = (I40EVF_MAX_AQ_BUF_SIZE -
 			 sizeof(struct i40e_virtchnl_vlan_filter_list)) /
 			sizeof(u16);
-		len = I40EVF_MAX_AQ_BUF_SIZE;
+		len = sizeof(struct i40e_virtchnl_vlan_filter_list) +
+		      (count * sizeof(u16));
+		more = true;
 	}
-	vvfl = kzalloc(len, GFP_ATOMIC);
+	vvfl = kzalloc(len, GFP_KERNEL);
 	if (!vvfl)
 		return;
 
@@ -549,7 +566,8 @@
 			f->add = false;
 		}
 	}
-	adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
+	if (!more)
+		adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
 	kfree(vvfl);
 }
@@ -567,6 +585,7 @@
 	struct i40e_virtchnl_vlan_filter_list *vvfl;
 	struct i40evf_vlan_filter *f, *ftmp;
 	int len, i = 0, count = 0;
+	bool more = false;
 
 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
 		/* bail because we already have a command pending */
@@ -592,9 +611,11 @@
 		count = (I40EVF_MAX_AQ_BUF_SIZE -
 			 sizeof(struct i40e_virtchnl_vlan_filter_list)) /
 			sizeof(u16);
-		len = I40EVF_MAX_AQ_BUF_SIZE;
+		len = sizeof(struct i40e_virtchnl_vlan_filter_list) +
+		      (count * sizeof(u16));
+		more = true;
 	}
-	vvfl = kzalloc(len, GFP_ATOMIC);
+	vvfl = kzalloc(len, GFP_KERNEL);
 	if (!vvfl)
 		return;
 
@@ -608,7 +629,8 @@
 			kfree(f);
 		}
 	}
-	adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
+	if (!more)
+		adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len);
 	kfree(vvfl);
 }
@@ -724,9 +746,29 @@
 		return;
 	}
 	if (v_retval) {
-		dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
-			v_retval, i40evf_stat_str(&adapter->hw, v_retval),
-			v_opcode);
+		switch (v_opcode) {
+		case I40E_VIRTCHNL_OP_ADD_VLAN:
+			dev_err(&adapter->pdev->dev, "Failed to add VLAN filter, error %s\n",
+				i40evf_stat_str(&adapter->hw, v_retval));
+			break;
+		case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
+			dev_err(&adapter->pdev->dev, "Failed to add MAC filter, error %s\n",
+				i40evf_stat_str(&adapter->hw, v_retval));
+			break;
+		case I40E_VIRTCHNL_OP_DEL_VLAN:
+			dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
+				i40evf_stat_str(&adapter->hw, v_retval));
+			break;
+		case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
+			dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
+				i40evf_stat_str(&adapter->hw, v_retval));
+			break;
+		default:
+			dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
+				v_retval,
+				i40evf_stat_str(&adapter->hw, v_retval),
+				v_opcode);
+		}
 	}
 	switch (v_opcode) {
 	case I40E_VIRTCHNL_OP_GET_STATS: {
@@ -766,6 +808,8 @@
 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
 		i40evf_free_all_tx_resources(adapter);
 		i40evf_free_all_rx_resources(adapter);
+		if (adapter->state == __I40EVF_DOWN_PENDING)
+			adapter->state = __I40EVF_DOWN;
 		break;
 	case I40E_VIRTCHNL_OP_VERSION:
 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -34,6 +34,7 @@
 #include "e1000_mac.h"
 #include "e1000_82575.h"
 #include "e1000_i210.h"
+#include "igb.h"
 
 static s32  igb_get_invariants_82575(struct e1000_hw *);
 static s32  igb_acquire_phy_82575(struct e1000_hw *);
@@ -45,8 +46,6 @@
 static s32  igb_init_hw_82575(struct e1000_hw *);
 static s32  igb_phy_hw_reset_sgmii_82575(struct e1000_hw *);
 static s32  igb_read_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16 *);
-static s32  igb_read_phy_reg_82580(struct e1000_hw *, u32, u16 *);
-static s32  igb_write_phy_reg_82580(struct e1000_hw *, u32, u16);
 static s32  igb_reset_hw_82575(struct e1000_hw *);
 static s32  igb_reset_hw_82580(struct e1000_hw *);
 static s32  igb_set_d0_lplu_state_82575(struct e1000_hw *, bool);
@@ -73,6 +72,32 @@
 static const u16 e1000_82580_rxpbs_table[] = {
 	36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140 };
 
+/* Due to a hw errata, if the host tries to  configure the VFTA register
+ * while performing queries from the BMC or DMA, then the VFTA in some
+ * cases won't be written.
+ */
+
+/**
+ *  igb_write_vfta_i350 - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+static void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	struct igb_adapter *adapter = hw->back;
+	int i;
+
+	for (i = 10; i--;)
+		array_wr32(E1000_VFTA, offset, value);
+
+	wrfl();
+	adapter->shadow_vfta[offset] = value;
+}
+
 /**
  *  igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
  *  @hw: pointer to the HW structure
@@ -205,13 +230,10 @@
 		case e1000_82580:
 		case e1000_i350:
 		case e1000_i354:
-			phy->ops.read_reg = igb_read_phy_reg_82580;
-			phy->ops.write_reg = igb_write_phy_reg_82580;
-			break;
 		case e1000_i210:
 		case e1000_i211:
-			phy->ops.read_reg = igb_read_phy_reg_gs40g;
-			phy->ops.write_reg = igb_write_phy_reg_gs40g;
+			phy->ops.read_reg = igb_read_phy_reg_82580;
+			phy->ops.write_reg = igb_write_phy_reg_82580;
 			break;
 		default:
 			phy->ops.read_reg = igb_read_phy_reg_igp;
@@ -272,6 +294,11 @@
 			if (ret_val)
 				goto out;
 		}
+		if (phy->id == M88E1543_E_PHY_ID) {
+			ret_val = igb_initialize_M88E1543_phy(hw);
+			if (ret_val)
+				goto out;
+		}
 		break;
 	case IGP03E1000_E_PHY_ID:
 		phy->type = e1000_phy_igp_3;
@@ -294,12 +321,16 @@
 	case I210_I_PHY_ID:
 		phy->type		= e1000_phy_i210;
 		phy->ops.check_polarity	= igb_check_polarity_m88;
+		phy->ops.get_cfg_done	= igb_get_cfg_done_i210;
 		phy->ops.get_phy_info	= igb_get_phy_info_m88;
 		phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
 		phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
 		phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
 		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
 		break;
+	case BCM54616_E_PHY_ID:
+		phy->type = e1000_phy_bcm54616;
+		break;
 	default:
 		ret_val = -E1000_ERR_PHY;
 		goto out;
@@ -397,6 +428,8 @@
 
 	/* Set mta register count */
 	mac->mta_reg_count = 128;
+	/* Set uta register count */
+	mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128;
 	/* Set rar entry count */
 	switch (mac->type) {
 	case e1000_82576:
@@ -428,6 +461,11 @@
 		mac->ops.release_swfw_sync = igb_release_swfw_sync_82575;
 	}
 
+	if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
+		mac->ops.write_vfta = igb_write_vfta_i350;
+	else
+		mac->ops.write_vfta = igb_write_vfta;
+
 	/* Set if part includes ASF firmware */
 	mac->asf_firmware_present = true;
 	/* Set if manageability features are enabled. */
@@ -925,6 +963,8 @@
 
 	if (phy->id == M88E1512_E_PHY_ID)
 		ret_val = igb_initialize_M88E1512_phy(hw);
+	if (phy->id == M88E1543_E_PHY_ID)
+		ret_val = igb_initialize_M88E1543_phy(hw);
 out:
 	return ret_val;
 }
@@ -1514,10 +1554,7 @@
 
 	/* Disabling VLAN filtering */
 	hw_dbg("Initializing the IEEE VLAN\n");
-	if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
-		igb_clear_vfta_i350(hw);
-	else
-		igb_clear_vfta(hw);
+	igb_clear_vfta(hw);
 
 	/* Setup the receive address */
 	igb_init_rx_addrs(hw, rar_count);
@@ -1569,6 +1606,7 @@
 	case e1000_i350:
 	case e1000_i210:
 	case e1000_i211:
+	case e1000_i354:
 		phpm_reg = rd32(E1000_82580_PHY_POWER_MGMT);
 		phpm_reg &= ~E1000_82580_PM_GO_LINKD;
 		wr32(E1000_82580_PHY_POWER_MGMT, phpm_reg);
@@ -1613,6 +1651,8 @@
 	case e1000_phy_82580:
 		ret_val = igb_copper_link_setup_82580(hw);
 		break;
+	case e1000_phy_bcm54616:
+		break;
 	default:
 		ret_val = -E1000_ERR_PHY;
 		break;
@@ -2145,7 +2185,7 @@
  *  Reads the MDI control register in the PHY at offset and stores the
  *  information read to data.
  **/
-static s32 igb_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data)
+s32 igb_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data)
 {
 	s32 ret_val;
 
@@ -2169,7 +2209,7 @@
  *
  *  Writes data to MDI control register in the PHY at offset.
  **/
-static s32 igb_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data)
+s32 igb_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data)
 {
 	s32 ret_val;
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -193,6 +193,8 @@
 /* enable link status from external LINK_0 and LINK_1 pins */
 #define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
 #define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_ADVD3WUC 0x00100000  /* D3 WUC */
+#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 /* PHY PM enable */
 #define E1000_CTRL_SDP0_DIR 0x00400000  /* SDP0 Data direction */
 #define E1000_CTRL_SDP1_DIR 0x00800000  /* SDP1 Data direction */
 #define E1000_CTRL_RST      0x04000000  /* Global reset */
@@ -356,7 +358,8 @@
 /* Ethertype field values */
 #define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
 
-#define MAX_JUMBO_FRAME_SIZE    0x3F00
+/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
+#define MAX_JUMBO_FRAME_SIZE	0x2600
 
 /* PBA constants */
 #define E1000_PBA_34K 0x0022
@@ -866,6 +869,7 @@
 #define I210_I_PHY_ID        0x01410C00
 #define M88E1543_E_PHY_ID    0x01410EA0
 #define M88E1512_E_PHY_ID    0x01410DD0
+#define BCM54616_E_PHY_ID    0x03625D10
 
 /* M88E1000 Specific Registers */
 #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
@@ -927,7 +931,10 @@
 
 /* Intel i347-AT4 Registers */
 
-#define I347AT4_PCDL                   0x10 /* PHY Cable Diagnostics Length */
+#define I347AT4_PCDL0                  0x10 /* Pair 0 PHY Cable Diagnostics Length */
+#define I347AT4_PCDL1                  0x11 /* Pair 1 PHY Cable Diagnostics Length */
+#define I347AT4_PCDL2                  0x12 /* Pair 2 PHY Cable Diagnostics Length */
+#define I347AT4_PCDL3                  0x13 /* Pair 3 PHY Cable Diagnostics Length */
 #define I347AT4_PCDC                   0x15 /* PHY Cable Diagnostics Control */
 #define I347AT4_PAGE_SELECT            0x16
 
@@ -990,6 +997,7 @@
 #define E1000_M88E1543_PAGE_ADDR	0x16       /* Page Offset Register */
 #define E1000_M88E1543_EEE_CTRL_1	0x0
 #define E1000_M88E1543_EEE_CTRL_1_MS	0x0001     /* EEE Master/Slave */
+#define E1000_M88E1543_FIBER_CTRL	0x0
 #define E1000_EEE_ADV_DEV_I354		7
 #define E1000_EEE_ADV_ADDR_I354		60
 #define E1000_EEE_ADV_100_SUPPORTED	(1 << 1)   /* 100BaseTx EEE Supported */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_hw.h
@@ -128,6 +128,7 @@
 	e1000_phy_ife,
 	e1000_phy_82580,
 	e1000_phy_i210,
+	e1000_phy_bcm54616,
 };
 
 enum e1000_bus_type {
@@ -325,7 +326,7 @@
 	s32 (*get_thermal_sensor_data)(struct e1000_hw *);
 	s32 (*init_thermal_sensor_thresh)(struct e1000_hw *);
 #endif
-
+	void (*write_vfta)(struct e1000_hw *, u32, u32);
 };
 
 struct e1000_phy_operations {
@@ -441,6 +442,7 @@
 	u16 cable_length;
 	u16 max_cable_length;
 	u16 min_cable_length;
+	u16 pair_length[4];
 
 	u8 mdix;
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_i210.c
@@ -699,9 +699,9 @@
 
 	ret_val = igb_pool_flash_update_done_i210(hw);
 	if (ret_val)
-		hw_dbg("Flash update complete\n");
-	else
 		hw_dbg("Flash update time out\n");
+	else
+		hw_dbg("Flash update complete\n");
 
 out:
 	return ret_val;
@@ -861,10 +861,10 @@
 	if (ret_val)
 		nvm_word = E1000_INVM_DEFAULT_AL;
 	tmp_nvm = nvm_word | E1000_INVM_PLL_WO_VAL;
+	igb_write_phy_reg_82580(hw, I347AT4_PAGE_SELECT, E1000_PHY_PLL_FREQ_PAGE);
 	for (i = 0; i < E1000_MAX_PLL_TRIES; i++) {
 		/* check current state directly from internal PHY */
-		igb_read_phy_reg_gs40g(hw, (E1000_PHY_PLL_FREQ_PAGE |
-					 E1000_PHY_PLL_FREQ_REG), &phy_word);
+		igb_read_phy_reg_82580(hw, E1000_PHY_PLL_FREQ_REG, &phy_word);
 		if ((phy_word & E1000_PHY_PLL_UNCONF)
 		    != E1000_PHY_PLL_UNCONF) {
 			ret_val = 0;
@@ -896,7 +896,35 @@
 		/* restore WUC register */
 		wr32(E1000_WUC, wuc);
 	}
+	igb_write_phy_reg_82580(hw, I347AT4_PAGE_SELECT, 0);
 	/* restore MDICNFG setting */
 	wr32(E1000_MDICNFG, mdicnfg);
 	return ret_val;
 }
+
+/**
+ *  igb_get_cfg_done_i210 - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  0.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+s32 igb_get_cfg_done_i210(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+	while (timeout) {
+		if (rd32(E1000_EEMNGCTL_I210) & mask)
+			break;
+		usleep_range(1000, 2000);
+		timeout--;
+	}
+	if (!timeout)
+		hw_dbg("MNG configuration cycle has not completed.\n");
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_i210.h
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_i210.h
@@ -34,6 +34,7 @@
 s32 igb_init_nvm_params_i210(struct e1000_hw *hw);
 bool igb_get_flash_presence_i210(struct e1000_hw *hw);
 s32 igb_pll_workaround_i210(struct e1000_hw *hw);
+s32 igb_get_cfg_done_i210(struct e1000_hw *hw);
 
 #define E1000_STM_OPCODE		0xDB00
 #define E1000_EEPROM_FLASH_SIZE_WORD	0x11
@@ -84,7 +85,7 @@
 #define E1000_PCI_PMCSR_D3		0x03
 #define E1000_MAX_PLL_TRIES		5
 #define E1000_PHY_PLL_UNCONF		0xFF
-#define E1000_PHY_PLL_FREQ_PAGE		0xFC0000
+#define E1000_PHY_PLL_FREQ_PAGE		0xFC
 #define E1000_PHY_PLL_FREQ_REG		0x000E
 #define E1000_INVM_DEFAULT_AL		0x202F
 #define E1000_INVM_AUTOLOAD		0x0A
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -92,10 +92,8 @@
 {
 	u32 offset;
 
-	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-		array_wr32(E1000_VFTA, offset, 0);
-		wrfl();
-	}
+	for (offset = E1000_VLAN_FILTER_TBL_SIZE; offset--;)
+		hw->mac.ops.write_vfta(hw, offset, 0);
 }
 
 /**
@@ -107,54 +105,14 @@
  *  Writes value at the given offset in the register array which stores
  *  the VLAN filter table.
  **/
-static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
 {
+	struct igb_adapter *adapter = hw->back;
+
 	array_wr32(E1000_VFTA, offset, value);
 	wrfl();
-}
-
-/* Due to a hw errata, if the host tries to  configure the VFTA register
- * while performing queries from the BMC or DMA, then the VFTA in some
- * cases won't be written.
- */
-
-/**
- *  igb_clear_vfta_i350 - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  Clears the register array which contains the VLAN filter table by
- *  setting all the values to 0.
- **/
-void igb_clear_vfta_i350(struct e1000_hw *hw)
-{
-	u32 offset;
-	int i;
 
-	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-		for (i = 0; i < 10; i++)
-			array_wr32(E1000_VFTA, offset, 0);
-
-		wrfl();
-	}
-}
-
-/**
- *  igb_write_vfta_i350 - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: register offset in VLAN filter table
- *  @value: register value written to VLAN filter table
- *
- *  Writes value at the given offset in the register array which stores
- *  the VLAN filter table.
- **/
-static void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	int i;
-
-	for (i = 0; i < 10; i++)
-		array_wr32(E1000_VFTA, offset, value);
-
-	wrfl();
+	adapter->shadow_vfta[offset] = value;
 }
 
 /**
@@ -183,40 +141,155 @@
 }
 
 /**
+ *  igb_find_vlvf_slot - find the VLAN id or the first empty slot
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vlvf_bypass: skip VLVF if no match is found
+ *
+ *  return the VLVF index where this VLAN id should be placed
+ *
+ **/
+static s32 igb_find_vlvf_slot(struct e1000_hw *hw, u32 vlan, bool vlvf_bypass)
+{
+	s32 regindex, first_empty_slot;
+	u32 bits;
+
+	/* short cut the special case */
+	if (vlan == 0)
+		return 0;
+
+	/* if vlvf_bypass is set we don't want to use an empty slot, we
+	 * will simply bypass the VLVF if there are no entries present in the
+	 * VLVF that contain our VLAN
+	 */
+	first_empty_slot = vlvf_bypass ? -E1000_ERR_NO_SPACE : 0;
+
+	/* Search for the VLAN id in the VLVF entries. Save off the first empty
+	 * slot found along the way.
+	 *
+	 * pre-decrement loop covering (IXGBE_VLVF_ENTRIES - 1) .. 1
+	 */
+	for (regindex = E1000_VLVF_ARRAY_SIZE; --regindex > 0;) {
+		bits = rd32(E1000_VLVF(regindex)) & E1000_VLVF_VLANID_MASK;
+		if (bits == vlan)
+			return regindex;
+		if (!first_empty_slot && !bits)
+			first_empty_slot = regindex;
+	}
+
+	return first_empty_slot ? : -E1000_ERR_NO_SPACE;
+}
+
+/**
  *  igb_vfta_set - enable or disable vlan in VLAN filter table
  *  @hw: pointer to the HW structure
- *  @vid: VLAN id to add or remove
- *  @add: if true add filter, if false remove
+ *  @vlan: VLAN id to add or remove
+ *  @vind: VMDq output index that maps queue to VLAN id
+ *  @vlan_on: if true add filter, if false remove
  *
  *  Sets or clears a bit in the VLAN filter table array based on VLAN id
  *  and if we are adding or removing the filter
  **/
-s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)
+s32 igb_vfta_set(struct e1000_hw *hw, u32 vlan, u32 vind,
+		 bool vlan_on, bool vlvf_bypass)
 {
-	u32 index = (vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
-	u32 mask = 1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
-	u32 vfta;
 	struct igb_adapter *adapter = hw->back;
-	s32 ret_val = 0;
+	u32 regidx, vfta_delta, vfta, bits;
+	s32 vlvf_index;
 
-	vfta = adapter->shadow_vfta[index];
+	if ((vlan > 4095) || (vind > 7))
+		return -E1000_ERR_PARAM;
 
-	/* bit was set/cleared before we started */
-	if ((!!(vfta & mask)) == add) {
-		ret_val = -E1000_ERR_CONFIG;
-	} else {
-		if (add)
-			vfta |= mask;
-		else
-			vfta &= ~mask;
+	/* this is a 2 part operation - first the VFTA, then the
+	 * VLVF and VLVFB if VT Mode is set
+	 * We don't write the VFTA until we know the VLVF part succeeded.
+	 */
+
+	/* Part 1
+	 * The VFTA is a bitstring made up of 128 32-bit registers
+	 * that enable the particular VLAN id, much like the MTA:
+	 *    bits[11-5]: which register
+	 *    bits[4-0]:  which bit in the register
+	 */
+	regidx = vlan / 32;
+	vfta_delta = 1 << (vlan % 32);
+	vfta = adapter->shadow_vfta[regidx];
+
+	/* vfta_delta represents the difference between the current value
+	 * of vfta and the value we want in the register.  Since the diff
+	 * is an XOR mask we can just update vfta using an XOR.
+	 */
+	vfta_delta &= vlan_on ? ~vfta : vfta;
+	vfta ^= vfta_delta;
+
+	/* Part 2
+	 * If VT Mode is set
+	 *   Either vlan_on
+	 *     make sure the VLAN is in VLVF
+	 *     set the vind bit in the matching VLVFB
+	 *   Or !vlan_on
+	 *     clear the pool bit and possibly the vind
+	 */
+	if (!adapter->vfs_allocated_count)
+		goto vfta_update;
+
+	vlvf_index = igb_find_vlvf_slot(hw, vlan, vlvf_bypass);
+	if (vlvf_index < 0) {
+		if (vlvf_bypass)
+			goto vfta_update;
+		return vlvf_index;
 	}
-	if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
-		igb_write_vfta_i350(hw, index, vfta);
-	else
-		igb_write_vfta(hw, index, vfta);
-	adapter->shadow_vfta[index] = vfta;
 
-	return ret_val;
+	bits = rd32(E1000_VLVF(vlvf_index));
+
+	/* set the pool bit */
+	bits |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vind);
+	if (vlan_on)
+		goto vlvf_update;
+
+	/* clear the pool bit */
+	bits ^= 1 << (E1000_VLVF_POOLSEL_SHIFT + vind);
+
+	if (!(bits & E1000_VLVF_POOLSEL_MASK)) {
+		/* Clear VFTA first, then disable VLVF.  Otherwise
+		 * we run the risk of stray packets leaking into
+		 * the PF via the default pool
+		 */
+		if (vfta_delta)
+			hw->mac.ops.write_vfta(hw, regidx, vfta);
+
+		/* disable VLVF and clear remaining bit from pool */
+		wr32(E1000_VLVF(vlvf_index), 0);
+
+		return 0;
+	}
+
+	/* If there are still bits set in the VLVFB registers
+	 * for the VLAN ID indicated we need to see if the
+	 * caller is requesting that we clear the VFTA entry bit.
+	 * If the caller has requested that we clear the VFTA
+	 * entry bit but there are still pools/VFs using this VLAN
+	 * ID entry then ignore the request.  We're not worried
+	 * about the case where we're turning the VFTA VLAN ID
+	 * entry bit on, only when requested to turn it off as
+	 * there may be multiple pools and/or VFs using the
+	 * VLAN ID entry.  In that case we cannot clear the
+	 * VFTA bit until all pools/VFs using that VLAN ID have also
+	 * been cleared.  This will be indicated by "bits" being
+	 * zero.
+	 */
+	vfta_delta = 0;
+
+vlvf_update:
+	/* record pool change and enable VLAN ID if not already enabled */
+	wr32(E1000_VLVF(vlvf_index), bits | vlan | E1000_VLVF_VLANID_ENABLE);
+
+vfta_update:
+	/* bit was set/cleared before we started */
+	if (vfta_delta)
+		hw->mac.ops.write_vfta(hw, regidx, vfta);
+
+	return 0;
 }
 
 /**
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_mac.h
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_mac.h
@@ -56,8 +56,9 @@
 
 void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
 void igb_clear_vfta(struct e1000_hw *hw);
-void igb_clear_vfta_i350(struct e1000_hw *hw);
-s32  igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+s32  igb_vfta_set(struct e1000_hw *hw, u32 vid, u32 vind,
+		  bool vlan_on, bool vlvf_bypass);
 void igb_config_collision_dist(struct e1000_hw *hw);
 void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
 void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_mbx.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_mbx.c
@@ -322,14 +322,20 @@
 {
 	s32 ret_val = -E1000_ERR_MBX;
 	u32 p2v_mailbox;
+	int count = 10;
 
-	/* Take ownership of the buffer */
-	wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
+	do {
+		/* Take ownership of the buffer */
+		wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
 
-	/* reserve mailbox for vf use */
-	p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
-	if (p2v_mailbox & E1000_P2VMAILBOX_PFU)
-		ret_val = 0;
+		/* reserve mailbox for vf use */
+		p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
+		if (p2v_mailbox & E1000_P2VMAILBOX_PFU) {
+			ret_val = 0;
+			break;
+		}
+		udelay(1000);
+	} while (count-- > 0);
 
 	return ret_val;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -77,6 +77,10 @@
 	s32 ret_val = 0;
 	u16 phy_id;
 
+	/* ensure PHY page selection to fix misconfigured i210 */
+	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
+		phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0);
+
 	ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
 	if (ret_val)
 		goto out;
@@ -1717,59 +1721,76 @@
 	struct e1000_phy_info *phy = &hw->phy;
 	s32 ret_val;
 	u16 phy_data, phy_data2, index, default_page, is_cm;
+	int len_tot = 0;
+	u16 len_min;
+	u16 len_max;
 
 	switch (hw->phy.id) {
+	case M88E1543_E_PHY_ID:
+	case M88E1512_E_PHY_ID:
+	case I347AT4_E_PHY_ID:
 	case I210_I_PHY_ID:
-		/* Get cable length from PHY Cable Diagnostics Control Reg */
-		ret_val = phy->ops.read_reg(hw, (0x7 << GS40G_PAGE_SHIFT) +
-					    (I347AT4_PCDL + phy->addr),
-					    &phy_data);
+		/* Remember the original page select and set it to 7 */
+		ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
+					    &default_page);
 		if (ret_val)
-			return ret_val;
+			goto out;
+
+		ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x07);
+		if (ret_val)
+			goto out;
 
 		/* Check if the unit of cable length is meters or cm */
-		ret_val = phy->ops.read_reg(hw, (0x7 << GS40G_PAGE_SHIFT) +
-					    I347AT4_PCDC, &phy_data2);
+		ret_val = phy->ops.read_reg(hw, I347AT4_PCDC, &phy_data2);
 		if (ret_val)
-			return ret_val;
+			goto out;
 
 		is_cm = !(phy_data2 & I347AT4_PCDC_CABLE_LENGTH_UNIT);
 
-		/* Populate the phy structure with cable length in meters */
-		phy->min_cable_length = phy_data / (is_cm ? 100 : 1);
-		phy->max_cable_length = phy_data / (is_cm ? 100 : 1);
-		phy->cable_length = phy_data / (is_cm ? 100 : 1);
-		break;
-	case M88E1543_E_PHY_ID:
-	case M88E1512_E_PHY_ID:
-	case I347AT4_E_PHY_ID:
-		/* Remember the original page select and set it to 7 */
-		ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
-					    &default_page);
+		/* Get cable length from Pair 0 length Regs */
+		ret_val = phy->ops.read_reg(hw, I347AT4_PCDL0, &phy_data);
 		if (ret_val)
 			goto out;
 
-		ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x07);
+		phy->pair_length[0] = phy_data / (is_cm ? 100 : 1);
+		len_tot = phy->pair_length[0];
+		len_min = phy->pair_length[0];
+		len_max = phy->pair_length[0];
+
+		/* Get cable length from Pair 1 length Regs */
+		ret_val = phy->ops.read_reg(hw, I347AT4_PCDL1, &phy_data);
 		if (ret_val)
 			goto out;
 
-		/* Get cable length from PHY Cable Diagnostics Control Reg */
-		ret_val = phy->ops.read_reg(hw, (I347AT4_PCDL + phy->addr),
-					    &phy_data);
+		phy->pair_length[1] = phy_data / (is_cm ? 100 : 1);
+		len_tot += phy->pair_length[1];
+		len_min = min(len_min, phy->pair_length[1]);
+		len_max = max(len_max, phy->pair_length[1]);
+
+		/* Get cable length from Pair 2 length Regs */
+		ret_val = phy->ops.read_reg(hw, I347AT4_PCDL2, &phy_data);
 		if (ret_val)
 			goto out;
 
-		/* Check if the unit of cable length is meters or cm */
-		ret_val = phy->ops.read_reg(hw, I347AT4_PCDC, &phy_data2);
+		phy->pair_length[2] = phy_data / (is_cm ? 100 : 1);
+		len_tot += phy->pair_length[2];
+		len_min = min(len_min, phy->pair_length[2]);
+		len_max = max(len_max, phy->pair_length[2]);
+
+		/* Get cable length from Pair 3 length Regs */
+		ret_val = phy->ops.read_reg(hw, I347AT4_PCDL3, &phy_data);
 		if (ret_val)
 			goto out;
 
-		is_cm = !(phy_data2 & I347AT4_PCDC_CABLE_LENGTH_UNIT);
+		phy->pair_length[3] = phy_data / (is_cm ? 100 : 1);
+		len_tot += phy->pair_length[3];
+		len_min = min(len_min, phy->pair_length[3]);
+		len_max = max(len_max, phy->pair_length[3]);
 
 		/* Populate the phy structure with cable length in meters */
-		phy->min_cable_length = phy_data / (is_cm ? 100 : 1);
-		phy->max_cable_length = phy_data / (is_cm ? 100 : 1);
-		phy->cable_length = phy_data / (is_cm ? 100 : 1);
+		phy->min_cable_length = len_min;
+		phy->max_cable_length = len_max;
+		phy->cable_length = len_tot / 4;
 
 		/* Reset the page selec to its original value */
 		ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
@@ -2278,6 +2299,100 @@
 }
 
 /**
+ *  igb_initialize_M88E1543_phy - Initialize M88E1512 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize Marvell 1543 to work correctly with Avoton.
+ **/
+s32 igb_initialize_M88E1543_phy(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = 0;
+
+	/* Switch to PHY page 0xFF. */
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FF);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x214B);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2144);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x0C28);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2146);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xB233);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x214D);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xDC0C);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2159);
+	if (ret_val)
+		goto out;
+
+	/* Switch to PHY page 0xFB. */
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FB);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_3, 0x0C0D);
+	if (ret_val)
+		goto out;
+
+	/* Switch to PHY page 0x12. */
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x12);
+	if (ret_val)
+		goto out;
+
+	/* Change mode to SGMII-to-Copper */
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_MODE, 0x8001);
+	if (ret_val)
+		goto out;
+
+	/* Switch to PHY page 1. */
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x1);
+	if (ret_val)
+		goto out;
+
+	/* Change mode to 1000BASE-X/SGMII and autoneg enable */
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_FIBER_CTRL, 0x9140);
+	if (ret_val)
+		goto out;
+
+	/* Return the PHY to page 0. */
+	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_phy_sw_reset(hw);
+	if (ret_val) {
+		hw_dbg("Error committing the PHY changes\n");
+		return ret_val;
+	}
+
+	/* msec_delay(1000); */
+	usleep_range(1000, 2000);
+out:
+	return ret_val;
+}
+
+/**
  * igb_power_up_phy_copper - Restore copper link in case of PHY power down
  * @hw: pointer to the HW structure
  *
@@ -2493,66 +2608,6 @@
 	return ret_val;
 }
 
-/**
- *  igb_write_phy_reg_gs40g - Write GS40G PHY register
- *  @hw: pointer to the HW structure
- *  @offset: lower half is register offset to write to
- *     upper half is page to use.
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val;
-	u16 page = offset >> GS40G_PAGE_SHIFT;
-
-	offset = offset & GS40G_OFFSET_MASK;
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page);
-	if (ret_val)
-		goto release;
-	ret_val = igb_write_phy_reg_mdic(hw, offset, data);
-
-release:
-	hw->phy.ops.release(hw);
-	return ret_val;
-}
-
-/**
- *  igb_read_phy_reg_gs40g - Read GS40G  PHY register
- *  @hw: pointer to the HW structure
- *  @offset: lower half is register offset to read to
- *     upper half is page to use.
- *  @data: data to read at register offset
- *
- *  Acquires semaphore, if necessary, then reads the data in the PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val;
-	u16 page = offset >> GS40G_PAGE_SHIFT;
-
-	offset = offset & GS40G_OFFSET_MASK;
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page);
-	if (ret_val)
-		goto release;
-	ret_val = igb_read_phy_reg_mdic(hw, offset, data);
-
-release:
-	hw->phy.ops.release(hw);
-	return ret_val;
-}
-
 /**
  *  igb_set_master_slave_mode - Setup PHY for Master/slave mode
  *  @hw: pointer to the HW structure
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_phy.h
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_phy.h
@@ -62,6 +62,7 @@
 void igb_power_down_phy_copper(struct e1000_hw *hw);
 s32  igb_phy_init_script_igp3(struct e1000_hw *hw);
 s32  igb_initialize_M88E1512_phy(struct e1000_hw *hw);
+s32  igb_initialize_M88E1543_phy(struct e1000_hw *hw);
 s32  igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
 s32  igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
 s32  igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
@@ -71,8 +72,8 @@
 s32  igb_get_phy_info_82580(struct e1000_hw *hw);
 s32  igb_phy_force_speed_duplex_82580(struct e1000_hw *hw);
 s32  igb_get_cable_length_82580(struct e1000_hw *hw);
-s32  igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data);
 s32  igb_check_polarity_m88(struct e1000_hw *hw);
 
 /* IGP01E1000 Specific Registers */
@@ -143,17 +144,6 @@
 
 #define E1000_CABLE_LENGTH_UNDEFINED      0xFF
 
-/* GS40G - I210 PHY defines */
-#define GS40G_PAGE_SELECT		0x16
-#define GS40G_PAGE_SHIFT		16
-#define GS40G_OFFSET_MASK		0xFFFF
-#define GS40G_PAGE_2			0x20000
-#define GS40G_MAC_REG2			0x15
-#define GS40G_MAC_LB			0x4140
-#define GS40G_MAC_SPEED_1G		0X0006
-#define GS40G_COPPER_SPEC		0x0010
-#define GS40G_LINE_LB			0x4000
-
 /* SFP modules ID memory locations */
 #define E1000_SFF_IDENTIFIER_OFFSET	0x00
 #define E1000_SFF_IDENTIFIER_SFF	0x02
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/e1000_regs.h
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -66,6 +66,7 @@
 #define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
 #define E1000_PBS      0x01008  /* Packet Buffer Size */
 #define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEMNGCTL_I210 0x12030  /* MNG EEprom Control */
 #define E1000_EEARBC_I210 0x12024  /* EEPROM Auto Read Bus Control */
 #define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
 #define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
@@ -385,8 +386,7 @@
 #define array_wr32(reg, offset, value) \
 	wr32((reg) + ((offset) << 2), (value))
 
-#define array_rd32(reg, offset) \
-	(readl(hw->hw_addr + reg + ((offset) << 2)))
+#define array_rd32(reg, offset) (igb_rd32(hw, reg + ((offset) << 2)))
 
 /* DMA Coalescing registers */
 #define E1000_PCIEMISC	0x05BB8 /* PCIE misc config register */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/igb.h
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/igb.h
@@ -95,7 +95,6 @@
 	unsigned char vf_mac_addresses[ETH_ALEN];
 	u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES];
 	u16 num_vf_mc_hashes;
-	u16 vlans_enabled;
 	u32 flags;
 	unsigned long last_nack;
 	u16 pf_vlan; /* When set, guest VLAN config not allowed. */
@@ -389,6 +388,8 @@
 	u16 link_speed;
 	u16 link_duplex;
 
+	u8 __iomem *io_addr; /* Mainly for iounmap use */
+
 	struct work_struct reset_task;
 	struct work_struct watchdog_task;
 	bool fc_autoneg;
@@ -480,6 +481,7 @@
 #define IGB_FLAG_MAS_ENABLE		(1 << 12)
 #define IGB_FLAG_HAS_MSIX		(1 << 13)
 #define IGB_FLAG_EEE			(1 << 14)
+#define IGB_FLAG_VLAN_PROMISC		BIT(15)
 
 /* Media Auto Sense */
 #define IGB_MAS_ENABLE_0		0X0001
@@ -534,6 +536,7 @@
 void igb_ptp_init(struct igb_adapter *adapter);
 void igb_ptp_stop(struct igb_adapter *adapter);
 void igb_ptp_reset(struct igb_adapter *adapter);
+void igb_ptp_suspend(struct igb_adapter *adapter);
 void igb_ptp_rx_hang(struct igb_adapter *adapter);
 void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb);
 void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va,
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -127,10 +127,20 @@
 #define IGB_STATS_LEN \
 	(IGB_GLOBAL_STATS_LEN + IGB_NETDEV_STATS_LEN + IGB_QUEUE_STATS_LEN)
 
+enum igb_diagnostics_results {
+	TEST_REG = 0,
+	TEST_EEP,
+	TEST_IRQ,
+	TEST_LOOP,
+	TEST_LINK
+};
+
 static const char igb_gstrings_test[][ETH_GSTRING_LEN] = {
-	"Register test  (offline)", "Eeprom test    (offline)",
-	"Interrupt test (offline)", "Loopback test  (offline)",
-	"Link test   (on/offline)"
+	[TEST_REG]  = "Register test  (offline)",
+	[TEST_EEP]  = "Eeprom test    (offline)",
+	[TEST_IRQ]  = "Interrupt test (offline)",
+	[TEST_LOOP] = "Loopback test  (offline)",
+	[TEST_LINK] = "Link test   (on/offline)"
 };
 #define IGB_TEST_LEN (sizeof(igb_gstrings_test) / ETH_GSTRING_LEN)
 
@@ -143,7 +153,8 @@
 	u32 status;
 	u32 speed;
 
-	status = rd32(E1000_STATUS);
+	status = pm_runtime_suspended(&adapter->pdev->dev) ?
+		 0 : rd32(E1000_STATUS);
 	if (hw->phy.media_type == e1000_media_type_copper) {
 
 		ecmd->supported = (SUPPORTED_10baseT_Half |
@@ -2002,7 +2013,7 @@
 		/* Link test performed before hardware reset so autoneg doesn't
 		 * interfere with test result
 		 */
-		if (igb_link_test(adapter, &data[4]))
+		if (igb_link_test(adapter, &data[TEST_LINK]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		if (if_running)
@@ -2011,21 +2022,21 @@
 		else
 			igb_reset(adapter);
 
-		if (igb_reg_test(adapter, &data[0]))
+		if (igb_reg_test(adapter, &data[TEST_REG]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		igb_reset(adapter);
-		if (igb_eeprom_test(adapter, &data[1]))
+		if (igb_eeprom_test(adapter, &data[TEST_EEP]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		igb_reset(adapter);
-		if (igb_intr_test(adapter, &data[2]))
+		if (igb_intr_test(adapter, &data[TEST_IRQ]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		igb_reset(adapter);
 		/* power up link for loopback test */
 		igb_power_up_link(adapter);
-		if (igb_loopback_test(adapter, &data[3]))
+		if (igb_loopback_test(adapter, &data[TEST_LOOP]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		/* restore speed, duplex, autoneg settings */
@@ -2045,16 +2056,16 @@
 		dev_info(&adapter->pdev->dev, "online testing starting\n");
 
 		/* PHY is powered down when interface is down */
-		if (if_running && igb_link_test(adapter, &data[4]))
+		if (if_running && igb_link_test(adapter, &data[TEST_LINK]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 		else
-			data[4] = 0;
+			data[TEST_LINK] = 0;
 
 		/* Online tests aren't run; pass by default */
-		data[0] = 0;
-		data[1] = 0;
-		data[2] = 0;
-		data[3] = 0;
+		data[TEST_REG] = 0;
+		data[TEST_EEP] = 0;
+		data[TEST_IRQ] = 0;
+		data[TEST_LOOP] = 0;
 
 		clear_bit(__IGB_TESTING, &adapter->state);
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/igb_main.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/igb_main.c
@@ -108,6 +108,7 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII), board_82575 },
 	/* required last entry */
 	{0, }
 };
@@ -140,7 +141,7 @@
 					  struct rtnl_link_stats64 *stats);
 static int igb_change_mtu(struct net_device *, int);
 static int igb_set_mac(struct net_device *, void *);
-static void igb_set_uta(struct igb_adapter *adapter);
+static void igb_set_uta(struct igb_adapter *adapter, bool set);
 static irqreturn_t igb_intr(int irq, void *);
 static irqreturn_t igb_intr_msi(int irq, void *);
 static irqreturn_t igb_msix_other(int irq, void *);
@@ -946,7 +947,6 @@
 static int igb_request_msix(struct igb_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	struct e1000_hw *hw = &adapter->hw;
 	int i, err = 0, vector = 0, free_vector = 0;
 
 	err = request_irq(adapter->msix_entries[vector].vector,
@@ -959,7 +959,7 @@
 
 		vector++;
 
-		q_vector->itr_register = hw->hw_addr + E1000_EITR(vector);
+		q_vector->itr_register = adapter->io_addr + E1000_EITR(vector);
 
 		if (q_vector->rx.ring && q_vector->tx.ring)
 			sprintf(q_vector->name, "%s-TxRx-%u", netdev->name,
@@ -1230,7 +1230,7 @@
 	q_vector->tx.work_limit = adapter->tx_work_limit;
 
 	/* initialize ITR configuration */
-	q_vector->itr_register = adapter->hw.hw_addr + E1000_EITR(0);
+	q_vector->itr_register = adapter->io_addr + E1000_EITR(0);
 	q_vector->itr_val = IGB_START_ITR;
 
 	/* initialize pointer to rings */
@@ -1535,12 +1535,13 @@
 static void igb_update_mng_vlan(struct igb_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
+	u16 pf_id = adapter->vfs_allocated_count;
 	u16 vid = adapter->hw.mng_cookie.vlan_id;
 	u16 old_vid = adapter->mng_vlan_id;
 
 	if (hw->mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
 		/* add VID to filter table */
-		igb_vfta_set(hw, vid, true);
+		igb_vfta_set(hw, vid, pf_id, true, true);
 		adapter->mng_vlan_id = vid;
 	} else {
 		adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
@@ -1550,7 +1551,7 @@
 	    (vid != old_vid) &&
 	    !test_bit(old_vid, adapter->active_vlans)) {
 		/* remove VID from filter table */
-		igb_vfta_set(hw, old_vid, false);
+		igb_vfta_set(hw, vid, pf_id, false, true);
 	}
 }
 
@@ -1673,7 +1674,8 @@
 	if ((hw->phy.media_type == e1000_media_type_copper) &&
 	    (!(connsw & E1000_CONNSW_AUTOSENSE_EN))) {
 		swap_now = true;
-	} else if (!(connsw & E1000_CONNSW_SERDESD)) {
+	} else if ((hw->phy.media_type != e1000_media_type_copper) &&
+		   !(connsw & E1000_CONNSW_SERDESD)) {
 		/* copper signal takes time to appear */
 		if (adapter->copper_tries < 4) {
 			adapter->copper_tries++;
@@ -1819,6 +1821,10 @@
 
 	if (!pci_channel_offline(adapter->pdev))
 		igb_reset(adapter);
+
+	/* clear VLAN promisc flag so VFTA will be updated if necessary */
+	adapter->flags &= ~IGB_FLAG_VLAN_PROMISC;
+
 	igb_clean_all_tx_rings(adapter);
 	igb_clean_all_rx_rings(adapter);
 #ifdef CONFIG_IGB_DCA
@@ -1863,7 +1869,7 @@
 	struct e1000_hw *hw = &adapter->hw;
 	struct e1000_mac_info *mac = &hw->mac;
 	struct e1000_fc_info *fc = &hw->fc;
-	u32 pba = 0, tx_space, min_tx_space, min_rx_space, hwm;
+	u32 pba, hwm;
 
 	/* Repartition Pba for greater than 9k mtu
 	 * To take effect CTRL.RST is required.
@@ -1887,9 +1893,10 @@
 		break;
 	}
 
-	if ((adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) &&
-	    (mac->type < e1000_82576)) {
-		/* adjust PBA for jumbo frames */
+	if (mac->type == e1000_82575) {
+		u32 min_rx_space, min_tx_space, needed_tx_space;
+
+		/* write Rx PBA so that hardware can report correct Tx PBA */
 		wr32(E1000_PBA, pba);
 
 		/* To maintain wire speed transmits, the Tx FIFO should be
@@ -1899,31 +1906,26 @@
 		 * one full receive packet and is similarly rounded up and
 		 * expressed in KB.
 		 */
-		pba = rd32(E1000_PBA);
-		/* upper 16 bits has Tx packet buffer allocation size in KB */
-		tx_space = pba >> 16;
-		/* lower 16 bits has Rx packet buffer allocation size in KB */
-		pba &= 0xffff;
-		/* the Tx fifo also stores 16 bytes of information about the Tx
-		 * but don't include ethernet FCS because hardware appends it
+		min_rx_space = DIV_ROUND_UP(MAX_JUMBO_FRAME_SIZE, 1024);
+
+		/* The Tx FIFO also stores 16 bytes of information about the Tx
+		 * but don't include Ethernet FCS because hardware appends it.
+		 * We only need to round down to the nearest 512 byte block
+		 * count since the value we care about is 2 frames, not 1.
 		 */
-		min_tx_space = (adapter->max_frame_size +
-				sizeof(union e1000_adv_tx_desc) -
-				ETH_FCS_LEN) * 2;
-		min_tx_space = ALIGN(min_tx_space, 1024);
-		min_tx_space >>= 10;
-		/* software strips receive CRC, so leave room for it */
-		min_rx_space = adapter->max_frame_size;
-		min_rx_space = ALIGN(min_rx_space, 1024);
-		min_rx_space >>= 10;
+		min_tx_space = adapter->max_frame_size;
+		min_tx_space += sizeof(union e1000_adv_tx_desc) - ETH_FCS_LEN;
+		min_tx_space = DIV_ROUND_UP(min_tx_space, 512);
+
+		/* upper 16 bits has Tx packet buffer allocation size in KB */
+		needed_tx_space = min_tx_space - (rd32(E1000_PBA) >> 16);
 
 		/* If current Tx allocation is less than the min Tx FIFO size,
 		 * and the min Tx FIFO size is less than the current Rx FIFO
-		 * allocation, take space away from current Rx allocation
+		 * allocation, take space away from current Rx allocation.
 		 */
-		if (tx_space < min_tx_space &&
-		    ((min_tx_space - tx_space) < pba)) {
-			pba = pba - (min_tx_space - tx_space);
+		if (needed_tx_space < pba) {
+			pba -= needed_tx_space;
 
 			/* if short on Rx space, Rx wins and must trump Tx
 			 * adjustment
@@ -1931,18 +1933,20 @@
 			if (pba < min_rx_space)
 				pba = min_rx_space;
 		}
+
+		/* adjust PBA for jumbo frames */
 		wr32(E1000_PBA, pba);
 	}
 
-	/* flow control settings */
-	/* The high water mark must be low enough to fit one full frame
-	 * (or the size used for early receive) above it in the Rx FIFO.
-	 * Set it to the lower of:
-	 * - 90% of the Rx FIFO size, or
-	 * - the full Rx FIFO size minus one full frame
+	/* flow control settings
+	 * The high water mark must be low enough to fit one full frame
+	 * after transmitting the pause frame.  As such we must have enough
+	 * space to allow for us to complete our current transmit and then
+	 * receive the frame that is in progress from the link partner.
+	 * Set it to:
+	 * - the full Rx FIFO size minus one full Tx plus one full Rx frame
 	 */
-	hwm = min(((pba << 10) * 9 / 10),
-			((pba << 10) - 2 * adapter->max_frame_size));
+	hwm = (pba << 10) - (adapter->max_frame_size + MAX_JUMBO_FRAME_SIZE);
 
 	fc->high_water = hwm & 0xFFFFFFF0;	/* 16-byte granularity */
 	fc->low_water = fc->high_water - 16;
@@ -2052,7 +2056,7 @@
 	if (changed & NETIF_F_HW_VLAN_CTAG_RX)
 		igb_vlan_mode(netdev, features);
 
-	if (!(changed & NETIF_F_RXALL))
+	if (!(changed & (NETIF_F_RXALL | NETIF_F_NTUPLE)))
 		return 0;
 
 	netdev->features = features;
@@ -2065,6 +2069,25 @@
 	return 0;
 }
 
+static int igb_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+			   struct net_device *dev,
+			   const unsigned char *addr, u16 vid,
+			   u16 flags)
+{
+	/* guarantee we can provide a unique filter for the unicast address */
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) {
+		struct igb_adapter *adapter = netdev_priv(dev);
+		struct e1000_hw *hw = &adapter->hw;
+		int vfn = adapter->vfs_allocated_count;
+		int rar_entries = hw->mac.rar_entry_count - (vfn + 1);
+
+		if (netdev_uc_count(dev) >= rar_entries)
+			return -ENOMEM;
+	}
+
+	return ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, flags);
+}
+
 static const struct net_device_ops igb_netdev_ops = {
 	.ndo_open		= igb_open,
 	.ndo_stop		= igb_close,
@@ -2088,6 +2111,7 @@
 #endif
 	.ndo_fix_features	= igb_fix_features,
 	.ndo_set_features	= igb_set_features,
+	.ndo_fdb_add		= igb_ndo_fdb_add,
 	.ndo_features_check	= passthru_features_check,
 };
 
@@ -2294,9 +2318,11 @@
 	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
 	err = -EIO;
-	hw->hw_addr = pci_iomap(pdev, 0, 0);
-	if (!hw->hw_addr)
+	adapter->io_addr = pci_iomap(pdev, 0, 0);
+	if (!adapter->io_addr)
 		goto err_ioremap;
+	/* hw->hw_addr can be altered, we'll use adapter->io_addr for unmap */
+	hw->hw_addr = adapter->io_addr;
 
 	netdev->netdev_ops = &igb_netdev_ops;
 	igb_set_ethtool_ops(netdev);
@@ -2378,8 +2404,8 @@
 	}
 
 	if (hw->mac.type >= e1000_82576) {
-		netdev->hw_features |= NETIF_F_SCTP_CSUM;
-		netdev->features |= NETIF_F_SCTP_CSUM;
+		netdev->hw_features |= NETIF_F_SCTP_CRC;
+		netdev->features |= NETIF_F_SCTP_CRC;
 	}
 
 	netdev->priv_flags |= IFF_UNICAST_FLT;
@@ -2656,7 +2682,7 @@
 #ifdef CONFIG_PCI_IOV
 	igb_disable_sriov(pdev);
 #endif
-	pci_iounmap(pdev, hw->hw_addr);
+	pci_iounmap(pdev, adapter->io_addr);
 err_ioremap:
 	free_netdev(netdev);
 err_alloc_etherdev:
@@ -2823,7 +2849,7 @@
 
 	igb_clear_interrupt_scheme(adapter);
 
-	pci_iounmap(pdev, hw->hw_addr);
+	pci_iounmap(pdev, adapter->io_addr);
 	if (hw->flash_address)
 		iounmap(hw->flash_address);
 	pci_release_selected_regions(pdev,
@@ -2856,6 +2882,13 @@
 	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
 		return;
 
+	/* Of the below we really only want the effect of getting
+	 * IGB_FLAG_HAS_MSIX set (if available), without which
+	 * igb_enable_sriov() has no effect.
+	 */
+	igb_set_interrupt_capability(adapter, true);
+	igb_reset_interrupt_capability(adapter);
+
 	pci_sriov_set_totalvfs(pdev, 7);
 	igb_enable_sriov(pdev, max_vfs);
 
@@ -2913,14 +2946,6 @@
 		/* 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_i354:
@@ -2931,6 +2956,8 @@
 		 */
 		if (adapter->rss_queues > (max_rss_queues / 2))
 			adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
+		else
+			adapter->flags &= ~IGB_FLAG_QUEUE_PAIRS;
 		break;
 	}
 }
@@ -2996,6 +3023,8 @@
 	/* Setup and initialize a copy of the hw vlan table array */
 	adapter->shadow_vfta = kcalloc(E1000_VLAN_FILTER_TBL_SIZE, sizeof(u32),
 				       GFP_ATOMIC);
+	if (!adapter->shadow_vfta)
+		return -ENOMEM;
 
 	/* This call may decrease the number of queues */
 	if (igb_init_interrupt_scheme(adapter, true)) {
@@ -3163,7 +3192,9 @@
 
 static int igb_close(struct net_device *netdev)
 {
-	return __igb_close(netdev, false);
+	if (netif_device_present(netdev) || netdev->dismantle)
+		return __igb_close(netdev, false);
+	return 0;
 }
 
 /**
@@ -3282,7 +3313,7 @@
 	     tdba & 0x00000000ffffffffULL);
 	wr32(E1000_TDBAH(reg_idx), tdba >> 32);
 
-	ring->tail = hw->hw_addr + E1000_TDT(reg_idx);
+	ring->tail = adapter->io_addr + E1000_TDT(reg_idx);
 	wr32(E1000_TDH(reg_idx), 0);
 	writel(0, ring->tail);
 
@@ -3490,7 +3521,7 @@
 	/* disable store bad packets and clear size bits. */
 	rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_SZ_256);
 
-	/* enable LPE to prevent packets larger than max_frame_size */
+	/* enable LPE to allow for reception of jumbo frames */
 	rctl |= E1000_RCTL_LPE;
 
 	/* disable queue 0 to prevent tail write w/o re-config */
@@ -3514,8 +3545,11 @@
 			 E1000_RCTL_BAM | /* RX All Bcast Pkts */
 			 E1000_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
 
-		rctl &= ~(E1000_RCTL_VFE | /* Disable VLAN filter */
-			  E1000_RCTL_DPF | /* Allow filtered pause */
+		/* Actually, disable bad packets as that might lead to
+		 * larger-than-MTU packets that won't fit in the RX buffers */
+		rctl &= ~(E1000_RCTL_SBP);
+
+		rctl &= ~(E1000_RCTL_DPF | /* Allow filtered pause */
 			  E1000_RCTL_CFIEN); /* Dis VLAN CFIEN Filter */
 		/* Do not mess with E1000_CTRL_VME, it affects transmit as well,
 		 * and that breaks VLANs.
@@ -3531,12 +3565,8 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 vmolr;
 
-	/* if it isn't the PF check to see if VFs are enabled and
-	 * increase the size to support vlan tags
-	 */
-	if (vfn < adapter->vfs_allocated_count &&
-	    adapter->vf_data[vfn].vlans_enabled)
-		size += VLAN_TAG_SIZE;
+	if (size > MAX_JUMBO_FRAME_SIZE)
+		size = MAX_JUMBO_FRAME_SIZE;
 
 	vmolr = rd32(E1000_VMOLR(vfn));
 	vmolr &= ~E1000_VMOLR_RLPML_MASK;
@@ -3546,32 +3576,6 @@
 	return 0;
 }
 
-/**
- *  igb_rlpml_set - set maximum receive packet size
- *  @adapter: board private structure
- *
- *  Configure maximum receivable packet size.
- **/
-static void igb_rlpml_set(struct igb_adapter *adapter)
-{
-	u32 max_frame_size = adapter->max_frame_size;
-	struct e1000_hw *hw = &adapter->hw;
-	u16 pf_id = adapter->vfs_allocated_count;
-
-	if (pf_id) {
-		igb_set_vf_rlpml(adapter, max_frame_size, pf_id);
-		/* If we're in VMDQ or SR-IOV mode, then set global RLPML
-		 * to our max jumbo frame size, in case we need to enable
-		 * jumbo frames on one of the rings later.
-		 * This will not pass over-length frames into the default
-		 * queue because it's gated by the VMOLR.RLPML.
-		 */
-		max_frame_size = MAX_JUMBO_FRAME_SIZE;
-	}
-
-	wr32(E1000_RLPML, max_frame_size);
-}
-
 static inline void igb_set_vmolr(struct igb_adapter *adapter,
 				 int vfn, bool aupe)
 {
@@ -3638,7 +3642,7 @@
 	     ring->count * sizeof(union e1000_adv_rx_desc));
 
 	/* initialize head and tail */
-	ring->tail = hw->hw_addr + E1000_RDT(reg_idx);
+	ring->tail = adapter->io_addr + E1000_RDT(reg_idx);
 	wr32(E1000_RDH(reg_idx), 0);
 	writel(0, ring->tail);
 
@@ -3676,9 +3680,6 @@
 {
 	int i;
 
-	/* set UTA to appropriate mode */
-	igb_set_uta(adapter);
-
 	/* set the correct pool for the PF default MAC address in entry 0 */
 	igb_rar_set_qsel(adapter, adapter->hw.mac.addr, 0,
 			 adapter->vfs_allocated_count);
@@ -3996,6 +3997,130 @@
 	return count;
 }
 
+static int igb_vlan_promisc_enable(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 i, pf_id;
+
+	switch (hw->mac.type) {
+	case e1000_i210:
+	case e1000_i211:
+	case e1000_i350:
+		/* VLAN filtering needed for VLAN prio filter */
+		if (adapter->netdev->features & NETIF_F_NTUPLE)
+			break;
+		/* fall through */
+	case e1000_82576:
+	case e1000_82580:
+	case e1000_i354:
+		/* VLAN filtering needed for pool filtering */
+		if (adapter->vfs_allocated_count)
+			break;
+		/* fall through */
+	default:
+		return 1;
+	}
+
+	/* We are already in VLAN promisc, nothing to do */
+	if (adapter->flags & IGB_FLAG_VLAN_PROMISC)
+		return 0;
+
+	if (!adapter->vfs_allocated_count)
+		goto set_vfta;
+
+	/* Add PF to all active pools */
+	pf_id = adapter->vfs_allocated_count + E1000_VLVF_POOLSEL_SHIFT;
+
+	for (i = E1000_VLVF_ARRAY_SIZE; --i;) {
+		u32 vlvf = rd32(E1000_VLVF(i));
+
+		vlvf |= 1 << pf_id;
+		wr32(E1000_VLVF(i), vlvf);
+	}
+
+set_vfta:
+	/* Set all bits in the VLAN filter table array */
+	for (i = E1000_VLAN_FILTER_TBL_SIZE; i--;)
+		hw->mac.ops.write_vfta(hw, i, ~0U);
+
+	/* Set flag so we don't redo unnecessary work */
+	adapter->flags |= IGB_FLAG_VLAN_PROMISC;
+
+	return 0;
+}
+
+#define VFTA_BLOCK_SIZE 8
+static void igb_scrub_vfta(struct igb_adapter *adapter, u32 vfta_offset)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 vfta[VFTA_BLOCK_SIZE] = { 0 };
+	u32 vid_start = vfta_offset * 32;
+	u32 vid_end = vid_start + (VFTA_BLOCK_SIZE * 32);
+	u32 i, vid, word, bits, pf_id;
+
+	/* guarantee that we don't scrub out management VLAN */
+	vid = adapter->mng_vlan_id;
+	if (vid >= vid_start && vid < vid_end)
+		vfta[(vid - vid_start) / 32] |= 1 << (vid % 32);
+
+	if (!adapter->vfs_allocated_count)
+		goto set_vfta;
+
+	pf_id = adapter->vfs_allocated_count + E1000_VLVF_POOLSEL_SHIFT;
+
+	for (i = E1000_VLVF_ARRAY_SIZE; --i;) {
+		u32 vlvf = rd32(E1000_VLVF(i));
+
+		/* pull VLAN ID from VLVF */
+		vid = vlvf & VLAN_VID_MASK;
+
+		/* only concern ourselves with a certain range */
+		if (vid < vid_start || vid >= vid_end)
+			continue;
+
+		if (vlvf & E1000_VLVF_VLANID_ENABLE) {
+			/* record VLAN ID in VFTA */
+			vfta[(vid - vid_start) / 32] |= 1 << (vid % 32);
+
+			/* if PF is part of this then continue */
+			if (test_bit(vid, adapter->active_vlans))
+				continue;
+		}
+
+		/* remove PF from the pool */
+		bits = ~(1 << pf_id);
+		bits &= rd32(E1000_VLVF(i));
+		wr32(E1000_VLVF(i), bits);
+	}
+
+set_vfta:
+	/* extract values from active_vlans and write back to VFTA */
+	for (i = VFTA_BLOCK_SIZE; i--;) {
+		vid = (vfta_offset + i) * 32;
+		word = vid / BITS_PER_LONG;
+		bits = vid % BITS_PER_LONG;
+
+		vfta[i] |= adapter->active_vlans[word] >> bits;
+
+		hw->mac.ops.write_vfta(hw, vfta_offset + i, vfta[i]);
+	}
+}
+
+static void igb_vlan_promisc_disable(struct igb_adapter *adapter)
+{
+	u32 i;
+
+	/* We are not in VLAN promisc, nothing to do */
+	if (!(adapter->flags & IGB_FLAG_VLAN_PROMISC))
+		return;
+
+	/* Set flag so we don't redo unnecessary work */
+	adapter->flags &= ~IGB_FLAG_VLAN_PROMISC;
+
+	for (i = 0; i < E1000_VLAN_FILTER_TBL_SIZE; i += VFTA_BLOCK_SIZE)
+		igb_scrub_vfta(adapter, i);
+}
+
 /**
  *  igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
  *  @netdev: network interface device structure
@@ -4010,21 +4135,17 @@
 	struct igb_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	unsigned int vfn = adapter->vfs_allocated_count;
-	u32 rctl, vmolr = 0;
+	u32 rctl = 0, vmolr = 0;
 	int count;
 
 	/* Check for Promiscuous and All Multicast modes */
-	rctl = rd32(E1000_RCTL);
-
-	/* clear the effected bits */
-	rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);
-
 	if (netdev->flags & IFF_PROMISC) {
-		/* retain VLAN HW filtering if in VT mode */
-		if (adapter->vfs_allocated_count)
-			rctl |= E1000_RCTL_VFE;
-		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
-		vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
+		rctl |= E1000_RCTL_UPE | E1000_RCTL_MPE;
+		vmolr |= E1000_VMOLR_MPME;
+
+		/* enable use of UTA filter to force packets to default pool */
+		if (hw->mac.type == e1000_82576)
+			vmolr |= E1000_VMOLR_ROPE;
 	} else {
 		if (netdev->flags & IFF_ALLMULTI) {
 			rctl |= E1000_RCTL_MPE;
@@ -4042,17 +4163,34 @@
 				vmolr |= E1000_VMOLR_ROMPE;
 			}
 		}
-		/* Write addresses to available RAR registers, if there is not
-		 * sufficient space to store all the addresses then enable
-		 * unicast promiscuous mode
-		 */
-		count = igb_write_uc_addr_list(netdev);
-		if (count < 0) {
-			rctl |= E1000_RCTL_UPE;
-			vmolr |= E1000_VMOLR_ROPE;
-		}
-		rctl |= E1000_RCTL_VFE;
 	}
+
+	/* Write addresses to available RAR registers, if there is not
+	 * sufficient space to store all the addresses then enable
+	 * unicast promiscuous mode
+	 */
+	count = igb_write_uc_addr_list(netdev);
+	if (count < 0) {
+		rctl |= E1000_RCTL_UPE;
+		vmolr |= E1000_VMOLR_ROPE;
+	}
+
+	/* enable VLAN filtering by default */
+	rctl |= E1000_RCTL_VFE;
+
+	/* disable VLAN filtering for modes that require it */
+	if ((netdev->flags & IFF_PROMISC) ||
+	    (netdev->features & NETIF_F_RXALL)) {
+		/* if we fail to set all rules then just clear VFE */
+		if (igb_vlan_promisc_enable(adapter))
+			rctl &= ~E1000_RCTL_VFE;
+	} else {
+		igb_vlan_promisc_disable(adapter);
+	}
+
+	/* update state of unicast, multicast, and VLAN filtering modes */
+	rctl |= rd32(E1000_RCTL) & ~(E1000_RCTL_UPE | E1000_RCTL_MPE |
+				     E1000_RCTL_VFE);
 	wr32(E1000_RCTL, rctl);
 
 	/* In order to support SR-IOV and eventually VMDq it is necessary to set
@@ -4063,9 +4201,19 @@
 	if ((hw->mac.type < e1000_82576) || (hw->mac.type > e1000_i350))
 		return;
 
+	/* set UTA to appropriate mode */
+	igb_set_uta(adapter, !!(vmolr & E1000_VMOLR_ROPE));
+
 	vmolr |= rd32(E1000_VMOLR(vfn)) &
 		 ~(E1000_VMOLR_ROPE | E1000_VMOLR_MPME | E1000_VMOLR_ROMPE);
+
+	/* enable Rx jumbo frames, no need for restriction */
+	vmolr &= ~E1000_VMOLR_RLPML_MASK;
+	vmolr |= MAX_JUMBO_FRAME_SIZE | E1000_VMOLR_LPE;
+
 	wr32(E1000_VMOLR(vfn), vmolr);
+	wr32(E1000_RLPML, MAX_JUMBO_FRAME_SIZE);
+
 	igb_restore_vf_multicasts(adapter);
 }
 
@@ -5080,16 +5228,6 @@
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
 
-	if (test_bit(__IGB_DOWN, &adapter->state)) {
-		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
-	}
-
-	if (skb->len <= 0) {
-		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
-	}
-
 	/* The minimum packet size with TCTL.PSP set is 17 so pad the skb
 	 * in order to meet this minimum size requirement.
 	 */
@@ -5124,9 +5262,18 @@
 	struct igb_adapter *adapter;
 	adapter = container_of(work, struct igb_adapter, reset_task);
 
+	rtnl_lock();
+	/* If we're already down or resetting, just bail */
+	if (test_bit(__IGB_DOWN, &adapter->state) ||
+	    test_bit(__IGB_RESETTING, &adapter->state)) {
+		rtnl_unlock();
+		return;
+	}
+
 	igb_dump(adapter);
 	netdev_err(adapter->netdev, "Reset adapter\n");
 	igb_reinit_locked(adapter);
+	rtnl_unlock();
 }
 
 /**
@@ -5399,8 +5546,6 @@
 		event.type = PTP_CLOCK_PPS;
 		if (adapter->ptp_caps.pps)
 			ptp_clock_event(adapter->ptp_clock, &event);
-		else
-			dev_err(&adapter->pdev->dev, "unexpected SYS WRAP");
 		ack |= TSINTR_SYS_WRAP;
 	}
 
@@ -5784,125 +5929,132 @@
 static void igb_clear_vf_vfta(struct igb_adapter *adapter, u32 vf)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	u32 pool_mask, reg, vid;
-	int i;
+	u32 pool_mask, vlvf_mask, i;
 
-	pool_mask = 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
+	/* create mask for VF and other pools */
+	pool_mask = E1000_VLVF_POOLSEL_MASK;
+	vlvf_mask = 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
+
+	/* drop PF from pool bits */
+	pool_mask &= ~(1 << (E1000_VLVF_POOLSEL_SHIFT +
+			     adapter->vfs_allocated_count));
 
 	/* Find the vlan filter for this id */
-	for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
-		reg = rd32(E1000_VLVF(i));
+	for (i = E1000_VLVF_ARRAY_SIZE; i--;) {
+		u32 vlvf = rd32(E1000_VLVF(i));
+		u32 vfta_mask, vid, vfta;
 
 		/* remove the vf from the pool */
-		reg &= ~pool_mask;
+		if (!(vlvf & vlvf_mask))
+			continue;
 
-		/* if pool is empty then remove entry from vfta */
-		if (!(reg & E1000_VLVF_POOLSEL_MASK) &&
-		    (reg & E1000_VLVF_VLANID_ENABLE)) {
-			reg = 0;
-			vid = reg & E1000_VLVF_VLANID_MASK;
-			igb_vfta_set(hw, vid, false);
-		}
+		/* clear out bit from VLVF */
+		vlvf ^= vlvf_mask;
 
-		wr32(E1000_VLVF(i), reg);
+		/* if other pools are present, just remove ourselves */
+		if (vlvf & pool_mask)
+			goto update_vlvfb;
+
+		/* if PF is present, leave VFTA */
+		if (vlvf & E1000_VLVF_POOLSEL_MASK)
+			goto update_vlvf;
+
+		vid = vlvf & E1000_VLVF_VLANID_MASK;
+		vfta_mask = 1 << (vid % 32);
+
+		/* clear bit from VFTA */
+		vfta = adapter->shadow_vfta[vid / 32];
+		if (vfta & vfta_mask)
+			hw->mac.ops.write_vfta(hw, vid / 32, vfta ^ vfta_mask);
+update_vlvf:
+		/* clear pool selection enable */
+		if (adapter->flags & IGB_FLAG_VLAN_PROMISC)
+			vlvf &= E1000_VLVF_POOLSEL_MASK;
+		else
+			vlvf = 0;
+update_vlvfb:
+		/* clear pool bits */
+		wr32(E1000_VLVF(i), vlvf);
 	}
+}
+
+static int igb_find_vlvf_entry(struct e1000_hw *hw, u32 vlan)
+{
+	u32 vlvf;
+	int idx;
+
+	/* short cut the special case */
+	if (vlan == 0)
+		return 0;
 
-	adapter->vf_data[vf].vlans_enabled = 0;
+	/* Search for the VLAN id in the VLVF entries */
+	for (idx = E1000_VLVF_ARRAY_SIZE; --idx;) {
+		vlvf = rd32(E1000_VLVF(idx));
+		if ((vlvf & VLAN_VID_MASK) == vlan)
+			break;
+	}
+
+	return idx;
 }
 
-static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
+void igb_update_pf_vlvf(struct igb_adapter *adapter, u32 vid)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	u32 reg, i;
+	u32 bits, pf_id;
+	int idx;
 
-	/* The vlvf table only exists on 82576 hardware and newer */
-	if (hw->mac.type < e1000_82576)
-		return -1;
+	idx = igb_find_vlvf_entry(hw, vid);
+	if (!idx)
+		return;
 
-	/* we only need to do this if VMDq is enabled */
-	if (!adapter->vfs_allocated_count)
-		return -1;
+	/* See if any other pools are set for this VLAN filter
+	 * entry other than the PF.
+	 */
+	pf_id = adapter->vfs_allocated_count + E1000_VLVF_POOLSEL_SHIFT;
+	bits = ~(1 << pf_id) & E1000_VLVF_POOLSEL_MASK;
+	bits &= rd32(E1000_VLVF(idx));
+
+	/* Disable the filter so this falls into the default pool. */
+	if (!bits) {
+		if (adapter->flags & IGB_FLAG_VLAN_PROMISC)
+			wr32(E1000_VLVF(idx), 1 << pf_id);
+		else
+			wr32(E1000_VLVF(idx), 0);
+	}
+}
 
-	/* Find the vlan filter for this id */
-	for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
-		reg = rd32(E1000_VLVF(i));
-		if ((reg & E1000_VLVF_VLANID_ENABLE) &&
-		    vid == (reg & E1000_VLVF_VLANID_MASK))
-			break;
+static s32 igb_set_vf_vlan(struct igb_adapter *adapter, u32 vid,
+			   bool add, u32 vf)
+{
+	int pf_id = adapter->vfs_allocated_count;
+	struct e1000_hw *hw = &adapter->hw;
+	int err;
+
+	/* If VLAN overlaps with one the PF is currently monitoring make
+	 * sure that we are able to allocate a VLVF entry.  This may be
+	 * redundant but it guarantees PF will maintain visibility to
+	 * the VLAN.
+	 */
+	if (add && test_bit(vid, adapter->active_vlans)) {
+		err = igb_vfta_set(hw, vid, pf_id, true, false);
+		if (err)
+			return err;
 	}
 
-	if (add) {
-		if (i == E1000_VLVF_ARRAY_SIZE) {
-			/* Did not find a matching VLAN ID entry that was
-			 * enabled.  Search for a free filter entry, i.e.
-			 * one without the enable bit set
-			 */
-			for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
-				reg = rd32(E1000_VLVF(i));
-				if (!(reg & E1000_VLVF_VLANID_ENABLE))
-					break;
-			}
-		}
-		if (i < E1000_VLVF_ARRAY_SIZE) {
-			/* Found an enabled/available entry */
-			reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
-
-			/* if !enabled we need to set this up in vfta */
-			if (!(reg & E1000_VLVF_VLANID_ENABLE)) {
-				/* add VID to filter table */
-				igb_vfta_set(hw, vid, true);
-				reg |= E1000_VLVF_VLANID_ENABLE;
-			}
-			reg &= ~E1000_VLVF_VLANID_MASK;
-			reg |= vid;
-			wr32(E1000_VLVF(i), reg);
-
-			/* do not modify RLPML for PF devices */
-			if (vf >= adapter->vfs_allocated_count)
-				return 0;
-
-			if (!adapter->vf_data[vf].vlans_enabled) {
-				u32 size;
-
-				reg = rd32(E1000_VMOLR(vf));
-				size = reg & E1000_VMOLR_RLPML_MASK;
-				size += 4;
-				reg &= ~E1000_VMOLR_RLPML_MASK;
-				reg |= size;
-				wr32(E1000_VMOLR(vf), reg);
-			}
+	err = igb_vfta_set(hw, vid, vf, add, false);
 
-			adapter->vf_data[vf].vlans_enabled++;
-		}
-	} else {
-		if (i < E1000_VLVF_ARRAY_SIZE) {
-			/* remove vf from the pool */
-			reg &= ~(1 << (E1000_VLVF_POOLSEL_SHIFT + vf));
-			/* if pool is empty then remove entry from vfta */
-			if (!(reg & E1000_VLVF_POOLSEL_MASK)) {
-				reg = 0;
-				igb_vfta_set(hw, vid, false);
-			}
-			wr32(E1000_VLVF(i), reg);
+	if (add && !err)
+		return err;
 
-			/* do not modify RLPML for PF devices */
-			if (vf >= adapter->vfs_allocated_count)
-				return 0;
-
-			adapter->vf_data[vf].vlans_enabled--;
-			if (!adapter->vf_data[vf].vlans_enabled) {
-				u32 size;
-
-				reg = rd32(E1000_VMOLR(vf));
-				size = reg & E1000_VMOLR_RLPML_MASK;
-				size -= 4;
-				reg &= ~E1000_VMOLR_RLPML_MASK;
-				reg |= size;
-				wr32(E1000_VMOLR(vf), reg);
-			}
-		}
-	}
-	return 0;
+	/* If we failed to add the VF VLAN or we are removing the VF VLAN
+	 * we may need to drop the PF pool bit in order to allow us to free
+	 * up the VLVF resources.
+	 */
+	if (test_bit(vid, adapter->active_vlans) ||
+	    (adapter->flags & IGB_FLAG_VLAN_PROMISC))
+		igb_update_pf_vlvf(adapter, vid);
+
+	return err;
 }
 
 static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
@@ -5915,130 +6067,97 @@
 		wr32(E1000_VMVIR(vf), 0);
 }
 
-static int igb_ndo_set_vf_vlan(struct net_device *netdev,
-			       int vf, u16 vlan, u8 qos)
+static int igb_enable_port_vlan(struct igb_adapter *adapter, int vf,
+				u16 vlan, u8 qos)
 {
-	int err = 0;
-	struct igb_adapter *adapter = netdev_priv(netdev);
+	int err;
 
-	if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7))
-		return -EINVAL;
-	if (vlan || qos) {
-		err = igb_vlvf_set(adapter, vlan, !!vlan, vf);
-		if (err)
-			goto out;
-		igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
-		igb_set_vmolr(adapter, vf, !vlan);
-		adapter->vf_data[vf].pf_vlan = vlan;
-		adapter->vf_data[vf].pf_qos = qos;
-		dev_info(&adapter->pdev->dev,
-			 "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
-		if (test_bit(__IGB_DOWN, &adapter->state)) {
-			dev_warn(&adapter->pdev->dev,
-				 "The VF VLAN has been set, but the PF device is not up.\n");
-			dev_warn(&adapter->pdev->dev,
-				 "Bring the PF device up before attempting to use the VF device.\n");
-		}
-	} else {
-		igb_vlvf_set(adapter, adapter->vf_data[vf].pf_vlan,
-			     false, vf);
-		igb_set_vmvir(adapter, vlan, vf);
-		igb_set_vmolr(adapter, vf, true);
-		adapter->vf_data[vf].pf_vlan = 0;
-		adapter->vf_data[vf].pf_qos = 0;
+	err = igb_set_vf_vlan(adapter, vlan, true, vf);
+	if (err)
+		return err;
+
+	igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
+	igb_set_vmolr(adapter, vf, !vlan);
+
+	/* revoke access to previous VLAN */
+	if (vlan != adapter->vf_data[vf].pf_vlan)
+		igb_set_vf_vlan(adapter, adapter->vf_data[vf].pf_vlan,
+				false, vf);
+
+	adapter->vf_data[vf].pf_vlan = vlan;
+	adapter->vf_data[vf].pf_qos = qos;
+	dev_info(&adapter->pdev->dev,
+		 "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
+	if (test_bit(__IGB_DOWN, &adapter->state)) {
+		dev_warn(&adapter->pdev->dev,
+			 "The VF VLAN has been set, but the PF device is not up.\n");
+		dev_warn(&adapter->pdev->dev,
+			 "Bring the PF device up before attempting to use the VF device.\n");
 	}
-out:
+
 	return err;
 }
 
-static int igb_find_vlvf_entry(struct igb_adapter *adapter, int vid)
+static int igb_disable_port_vlan(struct igb_adapter *adapter, int vf)
 {
-	struct e1000_hw *hw = &adapter->hw;
-	int i;
-	u32 reg;
+	/* Restore tagless access via VLAN 0 */
+	igb_set_vf_vlan(adapter, 0, true, vf);
 
-	/* Find the vlan filter for this id */
-	for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
-		reg = rd32(E1000_VLVF(i));
-		if ((reg & E1000_VLVF_VLANID_ENABLE) &&
-		    vid == (reg & E1000_VLVF_VLANID_MASK))
-			break;
-	}
+	igb_set_vmvir(adapter, 0, vf);
+	igb_set_vmolr(adapter, vf, true);
+
+	/* Remove any PF assigned VLAN */
+	if (adapter->vf_data[vf].pf_vlan)
+		igb_set_vf_vlan(adapter, adapter->vf_data[vf].pf_vlan,
+				false, vf);
 
-	if (i >= E1000_VLVF_ARRAY_SIZE)
-		i = -1;
+	adapter->vf_data[vf].pf_vlan = 0;
+	adapter->vf_data[vf].pf_qos = 0;
 
-	return i;
+	return 0;
 }
 
-static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+			       int vf, u16 vlan, u8 qos)
 {
-	struct e1000_hw *hw = &adapter->hw;
-	int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
-	int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
-	int err = 0;
+	struct igb_adapter *adapter = netdev_priv(netdev);
 
-	/* If in promiscuous mode we need to make sure the PF also has
-	 * the VLAN filter set.
-	 */
-	if (add && (adapter->netdev->flags & IFF_PROMISC))
-		err = igb_vlvf_set(adapter, vid, add,
-				   adapter->vfs_allocated_count);
-	if (err)
-		goto out;
+	if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7))
+		return -EINVAL;
 
-	err = igb_vlvf_set(adapter, vid, add, vf);
+	return (vlan || qos) ? igb_enable_port_vlan(adapter, vf, vlan, qos) :
+			       igb_disable_port_vlan(adapter, vf);
+}
 
-	if (err)
-		goto out;
+static int igb_set_vf_vlan_msg(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
+{
+	int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
+	int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
 
-	/* Go through all the checks to see if the VLAN filter should
-	 * be wiped completely.
-	 */
-	if (!add && (adapter->netdev->flags & IFF_PROMISC)) {
-		u32 vlvf, bits;
-		int regndx = igb_find_vlvf_entry(adapter, vid);
-
-		if (regndx < 0)
-			goto out;
-		/* See if any other pools are set for this VLAN filter
-		 * entry other than the PF.
-		 */
-		vlvf = bits = rd32(E1000_VLVF(regndx));
-		bits &= 1 << (E1000_VLVF_POOLSEL_SHIFT +
-			      adapter->vfs_allocated_count);
-		/* If the filter was removed then ensure PF pool bit
-		 * is cleared if the PF only added itself to the pool
-		 * because the PF is in promiscuous mode.
-		 */
-		if ((vlvf & VLAN_VID_MASK) == vid &&
-		    !test_bit(vid, adapter->active_vlans) &&
-		    !bits)
-			igb_vlvf_set(adapter, vid, add,
-				     adapter->vfs_allocated_count);
-	}
+	if (adapter->vf_data[vf].pf_vlan)
+		return -1;
 
-out:
-	return err;
+	/* VLAN 0 is a special case, don't allow it to be removed */
+	if (!vid && !add)
+		return 0;
+
+	return igb_set_vf_vlan(adapter, vid, !!add, vf);
 }
 
 static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
 {
-	/* clear flags - except flag that indicates PF has set the MAC */
-	adapter->vf_data[vf].flags &= IGB_VF_FLAG_PF_SET_MAC;
-	adapter->vf_data[vf].last_nack = jiffies;
+	struct vf_data_storage *vf_data = &adapter->vf_data[vf];
 
-	/* reset offloads to defaults */
-	igb_set_vmolr(adapter, vf, true);
+	/* clear flags - except flag that indicates PF has set the MAC */
+	vf_data->flags &= IGB_VF_FLAG_PF_SET_MAC;
+	vf_data->last_nack = jiffies;
 
 	/* reset vlans for device */
 	igb_clear_vf_vfta(adapter, vf);
-	if (adapter->vf_data[vf].pf_vlan)
-		igb_ndo_set_vf_vlan(adapter->netdev, vf,
-				    adapter->vf_data[vf].pf_vlan,
-				    adapter->vf_data[vf].pf_qos);
-	else
-		igb_clear_vf_vfta(adapter, vf);
+	igb_set_vf_vlan(adapter, vf_data->pf_vlan, true, vf);
+	igb_set_vmvir(adapter, vf_data->pf_vlan |
+			       (vf_data->pf_qos << VLAN_PRIO_SHIFT), vf);
+	igb_set_vmolr(adapter, vf, !vf_data->pf_vlan);
 
 	/* reset multicast table array for vf */
 	adapter->vf_data[vf].num_vf_mc_hashes = 0;
@@ -6183,7 +6302,7 @@
 				 "VF %d attempted to override administratively set VLAN tag\nReload the VF driver to resume operations\n",
 				 vf);
 		else
-			retval = igb_set_vf_vlan(adapter, msgbuf, vf);
+			retval = igb_set_vf_vlan_msg(adapter, msgbuf, vf);
 		break;
 	default:
 		dev_err(&pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
@@ -6225,6 +6344,7 @@
 /**
  *  igb_set_uta - Set unicast filter table address
  *  @adapter: board private structure
+ *  @set: boolean indicating if we are setting or clearing bits
  *
  *  The unicast table address is a register array of 32-bit registers.
  *  The table is meant to be used in a way similar to how the MTA is used
@@ -6232,21 +6352,18 @@
  *  set all the hash bits to 1 and use the VMOLR ROPE bit as a promiscuous
  *  enable bit to allow vlan tag stripping when promiscuous mode is enabled
  **/
-static void igb_set_uta(struct igb_adapter *adapter)
+static void igb_set_uta(struct igb_adapter *adapter, bool set)
 {
 	struct e1000_hw *hw = &adapter->hw;
+	u32 uta = set ? ~0 : 0;
 	int i;
 
-	/* The UTA table only exists on 82576 hardware and newer */
-	if (hw->mac.type < e1000_82576)
-		return;
-
 	/* we only need to do this if VMDq is enabled */
 	if (!adapter->vfs_allocated_count)
 		return;
 
-	for (i = 0; i < hw->mac.uta_reg_count; i++)
-		array_wr32(E1000_UTA, i, ~0);
+	for (i = hw->mac.uta_reg_count; i--;)
+		array_wr32(E1000_UTA, i, uta);
 }
 
 /**
@@ -6422,7 +6539,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		read_barrier_depends();
+		smp_rmb();
 
 		/* if DD is not set pending work has not been completed */
 		if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
@@ -7193,8 +7310,6 @@
 		ctrl &= ~E1000_CTRL_VME;
 		wr32(E1000_CTRL, ctrl);
 	}
-
-	igb_rlpml_set(adapter);
 }
 
 static int igb_vlan_rx_add_vid(struct net_device *netdev,
@@ -7204,11 +7319,9 @@
 	struct e1000_hw *hw = &adapter->hw;
 	int pf_id = adapter->vfs_allocated_count;
 
-	/* attempt to add filter to vlvf array */
-	igb_vlvf_set(adapter, vid, true, pf_id);
-
 	/* add the filter since PF can receive vlans w/o entry in vlvf */
-	igb_vfta_set(hw, vid, true);
+	if (!vid || !(adapter->flags & IGB_FLAG_VLAN_PROMISC))
+		igb_vfta_set(hw, vid, pf_id, true, !!vid);
 
 	set_bit(vid, adapter->active_vlans);
 
@@ -7219,16 +7332,12 @@
 				__be16 proto, u16 vid)
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
-	struct e1000_hw *hw = &adapter->hw;
 	int pf_id = adapter->vfs_allocated_count;
-	s32 err;
+	struct e1000_hw *hw = &adapter->hw;
 
-	/* remove vlan from VLVF table array */
-	err = igb_vlvf_set(adapter, vid, false, pf_id);
-
-	/* if vid was not present in VLVF just remove it from table */
-	if (err)
-		igb_vfta_set(hw, vid, false);
+	/* remove VID from filter table */
+	if (vid && !(adapter->flags & IGB_FLAG_VLAN_PROMISC))
+		igb_vfta_set(hw, vid, pf_id, false, true);
 
 	clear_bit(vid, adapter->active_vlans);
 
@@ -7237,11 +7346,12 @@
 
 static void igb_restore_vlan(struct igb_adapter *adapter)
 {
-	u16 vid;
+	u16 vid = 1;
 
 	igb_vlan_mode(adapter->netdev, adapter->netdev->features);
+	igb_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), 0);
 
-	for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
+	for_each_set_bit_from(vid, adapter->active_vlans, VLAN_N_VID)
 		igb_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
 }
 
@@ -7312,22 +7422,18 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 ctrl, rctl, status;
 	u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
-#ifdef CONFIG_PM
-	int retval = 0;
-#endif
+	bool wake;
 
+	rtnl_lock();
 	netif_device_detach(netdev);
 
 	if (netif_running(netdev))
 		__igb_close(netdev, true);
 
-	igb_clear_interrupt_scheme(adapter);
+	igb_ptp_suspend(adapter);
 
-#ifdef CONFIG_PM
-	retval = pci_save_state(pdev);
-	if (retval)
-		return retval;
-#endif
+	igb_clear_interrupt_scheme(adapter);
+	rtnl_unlock();
 
 	status = rd32(E1000_STATUS);
 	if (status & E1000_STATUS_LU)
@@ -7345,10 +7451,6 @@
 		}
 
 		ctrl = rd32(E1000_CTRL);
-		/* advertise wake from D3Cold */
-		#define E1000_CTRL_ADVD3WUC 0x00100000
-		/* phy power management enable */
-		#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
 		ctrl |= E1000_CTRL_ADVD3WUC;
 		wr32(E1000_CTRL, ctrl);
 
@@ -7362,12 +7464,15 @@
 		wr32(E1000_WUFC, 0);
 	}
 
-	*enable_wake = wufc || adapter->en_mng_pt;
-	if (!*enable_wake)
+	wake = wufc || adapter->en_mng_pt;
+	if (!wake)
 		igb_power_down_link(adapter);
 	else
 		igb_power_up_link(adapter);
 
+	if (enable_wake)
+		*enable_wake = wake;
+
 	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
 	 * would have already happened in close and is redundant.
 	 */
@@ -7382,22 +7487,7 @@
 #ifdef CONFIG_PM_SLEEP
 static int igb_suspend(struct device *dev)
 {
-	int retval;
-	bool wake;
-	struct pci_dev *pdev = to_pci_dev(dev);
-
-	retval = __igb_shutdown(pdev, &wake, 0);
-	if (retval)
-		return retval;
-
-	if (wake) {
-		pci_prepare_to_sleep(pdev);
-	} else {
-		pci_wake_from_d3(pdev, false);
-		pci_set_power_state(pdev, PCI_D3hot);
-	}
-
-	return 0;
+	return __igb_shutdown(to_pci_dev(dev), NULL, 0);
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -7441,16 +7531,15 @@
 
 	wr32(E1000_WUS, ~0);
 
-	if (netdev->flags & IFF_UP) {
-		rtnl_lock();
+	rtnl_lock();
+	if (!err && netif_running(netdev))
 		err = __igb_open(netdev, true);
-		rtnl_unlock();
-		if (err)
-			return err;
-	}
 
-	netif_device_attach(netdev);
-	return 0;
+	if (!err)
+		netif_device_attach(netdev);
+	rtnl_unlock();
+
+	return err;
 }
 
 static int igb_runtime_idle(struct device *dev)
@@ -7467,22 +7556,7 @@
 
 static int igb_runtime_suspend(struct device *dev)
 {
-	struct pci_dev *pdev = to_pci_dev(dev);
-	int retval;
-	bool wake;
-
-	retval = __igb_shutdown(pdev, &wake, 1);
-	if (retval)
-		return retval;
-
-	if (wake) {
-		pci_prepare_to_sleep(pdev);
-	} else {
-		pci_wake_from_d3(pdev, false);
-		pci_set_power_state(pdev, PCI_D3hot);
-	}
-
-	return 0;
+	return __igb_shutdown(to_pci_dev(dev), NULL, 1);
 }
 
 static int igb_runtime_resume(struct device *dev)
@@ -7649,6 +7723,11 @@
 		pci_enable_wake(pdev, PCI_D3hot, 0);
 		pci_enable_wake(pdev, PCI_D3cold, 0);
 
+		/* In case of PCI error, adapter lose its HW address
+		 * so we should re-assign it here.
+		 */
+		hw->hw_addr = adapter->io_addr;
+
 		igb_reset(adapter);
 		wr32(E1000_WUS, ~0);
 		result = PCI_ERS_RESULT_RECOVERED;
@@ -7696,15 +7775,14 @@
 static void igb_rar_set_qsel(struct igb_adapter *adapter, u8 *addr, u32 index,
 			     u8 qsel)
 {
-	u32 rar_low, rar_high;
 	struct e1000_hw *hw = &adapter->hw;
+	u32 rar_low, rar_high;
 
 	/* HW expects these in little endian so we reverse the byte order
-	 * from network order (big endian) to little endian
+	 * from network order (big endian) to CPU endian
 	 */
-	rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
-		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
-	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+	rar_low = le32_to_cpup((__be32 *)(addr));
+	rar_high = le16_to_cpup((__be16 *)(addr + 4));
 
 	/* Indicate to hardware the Address is Valid. */
 	rar_high |= E1000_RAH_AV;
@@ -7951,9 +8029,7 @@
 			 * than the Rx threshold. Set hwm to PBA - max frame
 			 * size in 16B units, capping it at PBA - 6KB.
 			 */
-			hwm = 64 * pba - adapter->max_frame_size / 16;
-			if (hwm < 64 * (pba - 6))
-				hwm = 64 * (pba - 6);
+			hwm = 64 * (pba - 6);
 			reg = rd32(E1000_FCRTC);
 			reg &= ~E1000_FCRTC_RTH_COAL_MASK;
 			reg |= ((hwm << E1000_FCRTC_RTH_COAL_SHIFT)
@@ -7963,9 +8039,7 @@
 			/* Set the DMA Coalescing Rx threshold to PBA - 2 * max
 			 * frame size, capping it at PBA - 10KB.
 			 */
-			dmac_thr = pba - adapter->max_frame_size / 512;
-			if (dmac_thr < pba - 10)
-				dmac_thr = pba - 10;
+			dmac_thr = pba - 10;
 			reg = rd32(E1000_DMACR);
 			reg &= ~E1000_DMACR_DMACTHR_MASK;
 			reg |= ((dmac_thr << E1000_DMACR_DMACTHR_SHIFT)
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -65,9 +65,15 @@
  *
  * The 40 bit 82580 SYSTIM overflows every
  *   2^40 * 10^-9 /  60  = 18.3 minutes.
+ *
+ * SYSTIM is converted to real time using a timecounter. As
+ * timecounter_cyc2time() allows old timestamps, the timecounter
+ * needs to be updated at least once per half of the SYSTIM interval.
+ * Scheduling of delayed work is not very accurate, so we aim for 8
+ * minutes to be sure the actual interval is shorter than 9.16 minutes.
  */
 
-#define IGB_SYSTIM_OVERFLOW_PERIOD	(HZ * 60 * 9)
+#define IGB_SYSTIM_OVERFLOW_PERIOD	(HZ * 60 * 8)
 #define IGB_PTP_TX_TIMEOUT		(HZ * 15)
 #define INCPERIOD_82576			(1 << E1000_TIMINCA_16NS_SHIFT)
 #define INCVALUE_82576_MASK		((1 << E1000_TIMINCA_16NS_SHIFT) - 1)
@@ -1124,12 +1130,13 @@
 }
 
 /**
- * igb_ptp_stop - Disable PTP device and stop the overflow check.
- * @adapter: Board private structure.
+ * igb_ptp_suspend - Disable PTP work items and prepare for suspend
+ * @adapter: Board private structure
  *
- * This function stops the PTP support and cancels the delayed work.
- **/
-void igb_ptp_stop(struct igb_adapter *adapter)
+ * This function stops the overflow check work and PTP Tx timestamp work, and
+ * will prepare the device for OS suspend.
+ */
+void igb_ptp_suspend(struct igb_adapter *adapter)
 {
 	switch (adapter->hw.mac.type) {
 	case e1000_82576:
@@ -1152,6 +1159,17 @@
 		adapter->ptp_tx_skb = NULL;
 		clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
 	}
+}
+
+/**
+ * igb_ptp_stop - Disable PTP device and stop the overflow check.
+ * @adapter: Board private structure.
+ *
+ * This function stops the PTP support and cancels the delayed work.
+ **/
+void igb_ptp_stop(struct igb_adapter *adapter)
+{
+	igb_ptp_suspend(adapter);
 
 	if (adapter->ptp_clock) {
 		ptp_clock_unregister(adapter->ptp_clock);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igbvf/mbx.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igbvf/mbx.c
@@ -234,13 +234,19 @@
 static s32 e1000_obtain_mbx_lock_vf(struct e1000_hw *hw)
 {
 	s32 ret_val = -E1000_ERR_MBX;
+	int count = 10;
 
-	/* Take ownership of the buffer */
-	ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_VFU);
+	do {
+		/* Take ownership of the buffer */
+		ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_VFU);
 
-	/* reserve mailbox for VF use */
-	if (e1000_read_v2p_mailbox(hw) & E1000_V2PMAILBOX_VFU)
-		ret_val = E1000_SUCCESS;
+		/* reserve mailbox for VF use */
+		if (e1000_read_v2p_mailbox(hw) & E1000_V2PMAILBOX_VFU) {
+			ret_val = 0;
+			break;
+		}
+		udelay(1000);
+	} while (count-- > 0);
 
 	return ret_val;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/intel/igbvf/netdev.c
+++ linux-4.4.0/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -809,7 +809,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		read_barrier_depends();
+		smp_rmb();
 
 		/* if DD is not set pending work has not been completed */
 		if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
@@ -2793,6 +2793,7 @@
 	return 0;
 
 err_hw_init:
+	netif_napi_del(&adapter->rx_ring->napi);
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
 err_sw_init:
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -139,6 +139,7 @@
 #define IXGBE_X540_VF_DEVICE_ID         0x1515
 
 struct vf_data_storage {
+	struct pci_dev *vfdev;
 	unsigned char vf_mac_addresses[ETH_ALEN];
 	u16 vf_mc_hashes[IXGBE_MAX_VF_MC_ENTRIES];
 	u16 num_vf_mc_hashes;
@@ -224,6 +225,8 @@
 	u64 csum_err;
 };
 
+#define IXGBE_TS_HDR_LEN 8
+
 enum ixgbe_ring_state_t {
 	__IXGBE_TX_FDIR_INIT_DONE,
 	__IXGBE_TX_XPS_INIT_DONE,
@@ -282,6 +285,8 @@
 	u16 next_to_use;
 	u16 next_to_clean;
 
+	unsigned long last_rx_timestamp;
+
 	union {
 		u16 next_to_alloc;
 		struct {
@@ -312,7 +317,7 @@
 };
 
 #define IXGBE_MAX_RSS_INDICES		16
-#define IXGBE_MAX_RSS_INDICES_X550	64
+#define IXGBE_MAX_RSS_INDICES_X550	63
 #define IXGBE_MAX_VMDQ_INDICES		64
 #define IXGBE_MAX_FDIR_INDICES		63	/* based on q_vector limit */
 #define IXGBE_MAX_FCOE_INDICES		8
@@ -587,9 +592,10 @@
 
 struct ixgbe_mac_addr {
 	u8 addr[ETH_ALEN];
-	u16 queue;
+	u16 pool;
 	u16 state; /* bitmask */
 };
+
 #define IXGBE_MAC_STATE_DEFAULT		0x1
 #define IXGBE_MAC_STATE_MODIFIED	0x2
 #define IXGBE_MAC_STATE_IN_USE		0x4
@@ -639,6 +645,8 @@
 #define IXGBE_FLAG_SRIOV_CAPABLE                (u32)(1 << 22)
 #define IXGBE_FLAG_SRIOV_ENABLED                (u32)(1 << 23)
 #define IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE	BIT(24)
+#define IXGBE_FLAG_RX_HWTSTAMP_ENABLED		BIT(25)
+#define IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER	BIT(26)
 
 	u32 flags2;
 #define IXGBE_FLAG2_RSC_CAPABLE                 (u32)(1 << 0)
@@ -656,6 +664,7 @@
 #ifdef CONFIG_IXGBE_VXLAN
 #define IXGBE_FLAG2_VXLAN_REREG_NEEDED		BIT(12)
 #endif
+#define IXGBE_FLAG2_VLAN_PROMISC		BIT(13)
 
 	/* Tx fast path data */
 	int num_tx_queues;
@@ -755,9 +764,12 @@
 	unsigned long last_rx_ptp_check;
 	unsigned long last_rx_timestamp;
 	spinlock_t tmreg_lock;
-	struct cyclecounter cc;
-	struct timecounter tc;
+	struct cyclecounter hw_cc;
+	struct timecounter hw_tc;
 	u32 base_incval;
+	u32 tx_hwtstamp_timeouts;
+	u32 rx_hwtstamp_cleared;
+	void (*ptp_setup_sdp)(struct ixgbe_adapter *);
 
 	/* SR-IOV */
 	DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
@@ -784,6 +796,10 @@
 	u8 default_up;
 	unsigned long fwd_bitmask; /* Bitmask indicating in use pools */
 
+#define IXGBE_MAX_LINK_HANDLE 10
+	struct ixgbe_mat_field *jump_tables[IXGBE_MAX_LINK_HANDLE];
+	unsigned long tables;
+
 /* maximum number of RETA entries among all devices supported by ixgbe
  * driver: currently it's x550 device in non-SRIOV mode
  */
@@ -883,9 +899,10 @@
 void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter);
 #endif
 int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter,
-			 u8 *addr, u16 queue);
+			 const u8 *addr, u16 queue);
 int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter,
-			 u8 *addr, u16 queue);
+			 const u8 *addr, u16 queue);
+void ixgbe_update_pf_promisc_vlvf(struct ixgbe_adapter *adapter, u32 vid);
 void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
 netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *, struct ixgbe_adapter *,
 				  struct ixgbe_ring *);
@@ -912,6 +929,9 @@
 					  u16 soft_id);
 void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input,
 					  union ixgbe_atr_input *mask);
+int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
+				    struct ixgbe_fdir_filter *input,
+				    u16 sw_idx);
 void ixgbe_set_rx_mode(struct net_device *netdev);
 #ifdef CONFIG_IXGBE_DCB
 void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter);
@@ -968,12 +988,33 @@
 void ixgbe_ptp_stop(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter);
-void ixgbe_ptp_rx_hwtstamp(struct ixgbe_adapter *adapter, struct sk_buff *skb);
+void ixgbe_ptp_rx_pktstamp(struct ixgbe_q_vector *, struct sk_buff *);
+void ixgbe_ptp_rx_rgtstamp(struct ixgbe_q_vector *, struct sk_buff *skb);
+static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
+					 union ixgbe_adv_rx_desc *rx_desc,
+					 struct sk_buff *skb)
+{
+	if (unlikely(ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_TSIP))) {
+		ixgbe_ptp_rx_pktstamp(rx_ring->q_vector, skb);
+		return;
+	}
+
+	if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
+		return;
+
+	ixgbe_ptp_rx_rgtstamp(rx_ring->q_vector, skb);
+
+	/* Update the last_rx_timestamp timer in order to enable watchdog check
+	 * for error case of latched timestamp on a dropped packet.
+	 */
+	rx_ring->last_rx_timestamp = jiffies;
+}
+
 int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr);
 int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr);
 void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_reset(struct ixgbe_adapter *adapter);
-void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr);
+void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter);
 #ifdef CONFIG_PCI_IOV
 void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter);
 #endif
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2014 Intel Corporation.
+  Copyright(c) 1999 - 2015 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -765,13 +765,14 @@
 	ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL) | IXGBE_CTRL_RST;
 	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
 	IXGBE_WRITE_FLUSH(hw);
+	usleep_range(1000, 1200);
 
 	/* Poll for reset bit to self-clear indicating reset is complete */
 	for (i = 0; i < 10; i++) {
-		udelay(1);
 		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
 		if (!(ctrl & IXGBE_CTRL_RST))
 			break;
+		udelay(1);
 	}
 	if (ctrl & IXGBE_CTRL_RST) {
 		status = IXGBE_ERR_RESET_FAILED;
@@ -879,11 +880,12 @@
  *  @vlan: VLAN id to write to VLAN filter
  *  @vind: VMDq output index that maps queue to VLAN id in VFTA
  *  @vlan_on: boolean flag to turn on/off VLAN in VFTA
+ *  @vlvf_bypass: boolean flag - unused
  *
  *  Turn on/off specified VLAN in the VLAN filter table.
  **/
 static s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind,
-				bool vlan_on)
+				bool vlan_on, bool vlvf_bypass)
 {
 	u32 regindex;
 	u32 bitindex;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -990,13 +990,14 @@
 	ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
 	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
 	IXGBE_WRITE_FLUSH(hw);
+	usleep_range(1000, 1200);
 
 	/* Poll for reset bit to self-clear indicating reset is complete */
 	for (i = 0; i < 10; i++) {
-		udelay(1);
 		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
 		if (!(ctrl & IXGBE_CTRL_RST_MASK))
 			break;
+		udelay(1);
 	}
 
 	if (ctrl & IXGBE_CTRL_RST_MASK) {
@@ -1082,12 +1083,16 @@
 
 	/* Add the SAN MAC address to the RAR only if it's a valid address */
 	if (is_valid_ether_addr(hw->mac.san_addr)) {
-		hw->mac.ops.set_rar(hw, hw->mac.num_rar_entries - 1,
-				    hw->mac.san_addr, 0, IXGBE_RAH_AV);
-
 		/* Save the SAN MAC RAR index */
 		hw->mac.san_mac_rar_index = hw->mac.num_rar_entries - 1;
 
+		hw->mac.ops.set_rar(hw, hw->mac.san_mac_rar_index,
+				    hw->mac.san_addr, 0, IXGBE_RAH_AV);
+
+		/* clear VMDq pool/queue selection for this RAR */
+		hw->mac.ops.clear_vmdq(hw, hw->mac.san_mac_rar_index,
+				       IXGBE_CLEAR_VMDQ_ALL);
+
 		/* Reserve the last RAR for the SAN MAC address */
 		hw->mac.num_rar_entries--;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2014 Intel Corporation.
+  Copyright(c) 1999 - 2015 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -1814,7 +1814,12 @@
 	if (enable_addr != 0)
 		rar_high |= IXGBE_RAH_AV;
 
+	/* Record lower 32 bits of MAC address and then make
+	 * sure that write is flushed to hardware before writing
+	 * the upper 16 bits and setting the valid bit.
+	 */
 	IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low);
+	IXGBE_WRITE_FLUSH(hw);
 	IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
 
 	return 0;
@@ -1846,8 +1851,13 @@
 	rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index));
 	rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV);
 
-	IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0);
+	/* Clear the address valid bit and upper 16 bits of the address
+	 * before clearing the lower bits. This way we aren't updating
+	 * a live filter.
+	 */
 	IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+	IXGBE_WRITE_FLUSH(hw);
+	IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0);
 
 	/* clear VMDq pool/queue selection for this RAR */
 	hw->mac.ops.clear_vmdq(hw, index, IXGBE_CLEAR_VMDQ_ALL);
@@ -1884,10 +1894,11 @@
 		hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr);
 
 		hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
-
-		/*  clear VMDq pool/queue selection for RAR 0 */
-		hw->mac.ops.clear_vmdq(hw, 0, IXGBE_CLEAR_VMDQ_ALL);
 	}
+
+	/*  clear VMDq pool/queue selection for RAR 0 */
+	hw->mac.ops.clear_vmdq(hw, 0, IXGBE_CLEAR_VMDQ_ALL);
+
 	hw->addr_ctrl.overflow_promisc = 0;
 
 	hw->addr_ctrl.rar_used_count = 1;
@@ -2175,7 +2186,7 @@
 	}
 
 	/* Configure pause time (2 TCs per register) */
-	reg = hw->fc.pause_time * 0x00010001;
+	reg = hw->fc.pause_time * 0x00010001U;
 	for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++)
 		IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg);
 
@@ -2454,6 +2465,17 @@
 	/* Always set this bit to ensure any future transactions are blocked */
 	IXGBE_WRITE_REG(hw, IXGBE_CTRL, IXGBE_CTRL_GIO_DIS);
 
+	/* Poll for bit to read as set */
+	for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+		if (IXGBE_READ_REG(hw, IXGBE_CTRL) & IXGBE_CTRL_GIO_DIS)
+			break;
+		usleep_range(100, 120);
+	}
+	if (i >= IXGBE_PCI_MASTER_DISABLE_TIMEOUT) {
+		hw_dbg(hw, "GIO disable did not set - requesting resets\n");
+		goto gio_disable_fail;
+	}
+
 	/* Exit if master requests are blocked */
 	if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO) ||
 	    ixgbe_removed(hw->hw_addr))
@@ -2475,6 +2497,7 @@
 	 * again to clear out any effects they may have had on our device.
 	 */
 	hw_dbg(hw, "GIO Master Disable bit didn't clear - requesting resets\n");
+gio_disable_fail:
 	hw->mac.flags |= IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
 
 	if (hw->mac.type >= ixgbe_mac_X550)
@@ -2987,43 +3010,44 @@
  *  return the VLVF index where this VLAN id should be placed
  *
  **/
-static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan)
+static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass)
 {
-	u32 bits = 0;
-	u32 first_empty_slot = 0;
-	s32 regindex;
+	s32 regindex, first_empty_slot;
+	u32 bits;
 
 	/* short cut the special case */
 	if (vlan == 0)
 		return 0;
 
-	/*
-	  * Search for the vlan id in the VLVF entries. Save off the first empty
-	  * slot found along the way
-	  */
-	for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) {
+	/* if vlvf_bypass is set we don't want to use an empty slot, we
+	 * will simply bypass the VLVF if there are no entries present in the
+	 * VLVF that contain our VLAN
+	 */
+	first_empty_slot = vlvf_bypass ? IXGBE_ERR_NO_SPACE : 0;
+
+	/* add VLAN enable bit for comparison */
+	vlan |= IXGBE_VLVF_VIEN;
+
+	/* Search for the vlan id in the VLVF entries. Save off the first empty
+	 * slot found along the way.
+	 *
+	 * pre-decrement loop covering (IXGBE_VLVF_ENTRIES - 1) .. 1
+	 */
+	for (regindex = IXGBE_VLVF_ENTRIES; --regindex;) {
 		bits = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex));
-		if (!bits && !(first_empty_slot))
+		if (bits == vlan)
+			return regindex;
+		if (!first_empty_slot && !bits)
 			first_empty_slot = regindex;
-		else if ((bits & 0x0FFF) == vlan)
-			break;
 	}
 
-	/*
-	  * If regindex is less than IXGBE_VLVF_ENTRIES, then we found the vlan
-	  * in the VLVF. Else use the first empty VLVF register for this
-	  * vlan id.
-	  */
-	if (regindex >= IXGBE_VLVF_ENTRIES) {
-		if (first_empty_slot)
-			regindex = first_empty_slot;
-		else {
-			hw_dbg(hw, "No space in VLVF.\n");
-			regindex = IXGBE_ERR_NO_SPACE;
-		}
-	}
+	/* If we are here then we didn't find the VLAN.  Return first empty
+	 * slot we found during our search, else error.
+	 */
+	if (!first_empty_slot)
+		hw_dbg(hw, "No space in VLVF.\n");
 
-	return regindex;
+	return first_empty_slot ? : IXGBE_ERR_NO_SPACE;
 }
 
 /**
@@ -3032,21 +3056,17 @@
  *  @vlan: VLAN id to write to VLAN filter
  *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
  *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
+ *  @vlvf_bypass: boolean flag indicating updating default pool is okay
  *
  *  Turn on/off specified VLAN in the VLAN filter table.
  **/
 s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
-			   bool vlan_on)
+			   bool vlan_on, bool vlvf_bypass)
 {
-	s32 regindex;
-	u32 bitindex;
-	u32 vfta;
-	u32 bits;
-	u32 vt;
-	u32 targetbit;
-	bool vfta_changed = false;
+	u32 regidx, vfta_delta, vfta, bits;
+	s32 vlvf_index;
 
-	if (vlan > 4095)
+	if ((vlan > 4095) || (vind > 63))
 		return IXGBE_ERR_PARAM;
 
 	/*
@@ -3061,22 +3081,16 @@
 	 *    bits[11-5]: which register
 	 *    bits[4-0]:  which bit in the register
 	 */
-	regindex = (vlan >> 5) & 0x7F;
-	bitindex = vlan & 0x1F;
-	targetbit = (1 << bitindex);
-	vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex));
-
-	if (vlan_on) {
-		if (!(vfta & targetbit)) {
-			vfta |= targetbit;
-			vfta_changed = true;
-		}
-	} else {
-		if ((vfta & targetbit)) {
-			vfta &= ~targetbit;
-			vfta_changed = true;
-		}
-	}
+	regidx = vlan / 32;
+	vfta_delta = 1 << (vlan % 32);
+	vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regidx));
+
+	/* vfta_delta represents the difference between the current value
+	 * of vfta and the value we want in the register.  Since the diff
+	 * is an XOR mask we can just update vfta using an XOR.
+	 */
+	vfta_delta &= vlan_on ? ~vfta : vfta;
+	vfta ^= vfta_delta;
 
 	/* Part 2
 	 * If VT Mode is set
@@ -3086,85 +3100,67 @@
 	 *   Or !vlan_on
 	 *     clear the pool bit and possibly the vind
 	 */
-	vt = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
-	if (vt & IXGBE_VT_CTL_VT_ENABLE) {
-		s32 vlvf_index;
-
-		vlvf_index = ixgbe_find_vlvf_slot(hw, vlan);
-		if (vlvf_index < 0)
-			return vlvf_index;
-
-		if (vlan_on) {
-			/* set the pool bit */
-			if (vind < 32) {
-				bits = IXGBE_READ_REG(hw,
-						IXGBE_VLVFB(vlvf_index*2));
-				bits |= (1 << vind);
-				IXGBE_WRITE_REG(hw,
-						IXGBE_VLVFB(vlvf_index*2),
-						bits);
-			} else {
-				bits = IXGBE_READ_REG(hw,
-						IXGBE_VLVFB((vlvf_index*2)+1));
-				bits |= (1 << (vind-32));
-				IXGBE_WRITE_REG(hw,
-						IXGBE_VLVFB((vlvf_index*2)+1),
-						bits);
-			}
-		} else {
-			/* clear the pool bit */
-			if (vind < 32) {
-				bits = IXGBE_READ_REG(hw,
-						IXGBE_VLVFB(vlvf_index*2));
-				bits &= ~(1 << vind);
-				IXGBE_WRITE_REG(hw,
-						IXGBE_VLVFB(vlvf_index*2),
-						bits);
-				bits |= IXGBE_READ_REG(hw,
-						IXGBE_VLVFB((vlvf_index*2)+1));
-			} else {
-				bits = IXGBE_READ_REG(hw,
-						IXGBE_VLVFB((vlvf_index*2)+1));
-				bits &= ~(1 << (vind-32));
-				IXGBE_WRITE_REG(hw,
-						IXGBE_VLVFB((vlvf_index*2)+1),
-						bits);
-				bits |= IXGBE_READ_REG(hw,
-						IXGBE_VLVFB(vlvf_index*2));
-			}
-		}
+	if (!(IXGBE_READ_REG(hw, IXGBE_VT_CTL) & IXGBE_VT_CTL_VT_ENABLE))
+		goto vfta_update;
 
-		/*
-		 * If there are still bits set in the VLVFB registers
-		 * for the VLAN ID indicated we need to see if the
-		 * caller is requesting that we clear the VFTA entry bit.
-		 * If the caller has requested that we clear the VFTA
-		 * entry bit but there are still pools/VFs using this VLAN
-		 * ID entry then ignore the request.  We're not worried
-		 * about the case where we're turning the VFTA VLAN ID
-		 * entry bit on, only when requested to turn it off as
-		 * there may be multiple pools and/or VFs using the
-		 * VLAN ID entry.  In that case we cannot clear the
-		 * VFTA bit until all pools/VFs using that VLAN ID have also
-		 * been cleared.  This will be indicated by "bits" being
-		 * zero.
+	vlvf_index = ixgbe_find_vlvf_slot(hw, vlan, vlvf_bypass);
+	if (vlvf_index < 0) {
+		if (vlvf_bypass)
+			goto vfta_update;
+		return vlvf_index;
+	}
+
+	bits = IXGBE_READ_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32));
+
+	/* set the pool bit */
+	bits |= 1 << (vind % 32);
+	if (vlan_on)
+		goto vlvf_update;
+
+	/* clear the pool bit */
+	bits ^= 1 << (vind % 32);
+
+	if (!bits &&
+	    !IXGBE_READ_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + 1 - vind / 32))) {
+		/* Clear VFTA first, then disable VLVF.  Otherwise
+		 * we run the risk of stray packets leaking into
+		 * the PF via the default pool
 		 */
-		if (bits) {
-			IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index),
-					(IXGBE_VLVF_VIEN | vlan));
-			if (!vlan_on) {
-				/* someone wants to clear the vfta entry
-				 * but some pools/VFs are still using it.
-				 * Ignore it. */
-				vfta_changed = false;
-			}
-		} else {
-			IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0);
-		}
+		if (vfta_delta)
+			IXGBE_WRITE_REG(hw, IXGBE_VFTA(regidx), vfta);
+
+		/* disable VLVF and clear remaining bit from pool */
+		IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32), 0);
+
+		return 0;
 	}
 
-	if (vfta_changed)
-		IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), vfta);
+	/* If there are still bits set in the VLVFB registers
+	 * for the VLAN ID indicated we need to see if the
+	 * caller is requesting that we clear the VFTA entry bit.
+	 * If the caller has requested that we clear the VFTA
+	 * entry bit but there are still pools/VFs using this VLAN
+	 * ID entry then ignore the request.  We're not worried
+	 * about the case where we're turning the VFTA VLAN ID
+	 * entry bit on, only when requested to turn it off as
+	 * there may be multiple pools and/or VFs using the
+	 * VLAN ID entry.  In that case we cannot clear the
+	 * VFTA bit until all pools/VFs using that VLAN ID have also
+	 * been cleared.  This will be indicated by "bits" being
+	 * zero.
+	 */
+	vfta_delta = 0;
+
+vlvf_update:
+	/* record pool change and enable VLAN ID if not already enabled */
+	IXGBE_WRITE_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32), bits);
+	IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), IXGBE_VLVF_VIEN | vlan);
+
+vfta_update:
+	/* Update VFTA now that we are ready for traffic */
+	if (vfta_delta)
+		IXGBE_WRITE_REG(hw, IXGBE_VFTA(regidx), vfta);
 
 	return 0;
 }
@@ -3184,8 +3180,8 @@
 
 	for (offset = 0; offset < IXGBE_VLVF_ENTRIES; offset++) {
 		IXGBE_WRITE_REG(hw, IXGBE_VLVF(offset), 0);
-		IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset*2), 0);
-		IXGBE_WRITE_REG(hw, IXGBE_VLVFB((offset*2)+1), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2 + 1), 0);
 	}
 
 	return 0;
@@ -3620,10 +3616,10 @@
 	fw_cmd.ver_build = build;
 	fw_cmd.ver_sub = sub;
 	fw_cmd.hdr.checksum = 0;
-	fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd,
-				(FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len));
 	fw_cmd.pad = 0;
 	fw_cmd.pad2 = 0;
+	fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd,
+				(FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len));
 
 	for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
 		ret_val = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd,
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -92,7 +92,7 @@
 s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq);
 s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw);
 s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan,
-			   u32 vind, bool vlan_on);
+			   u32 vind, bool vlan_on, bool vlvf_bypass);
 s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw);
 s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw,
 				 ixgbe_link_speed *speed,
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
@@ -139,6 +139,11 @@
 		/* Calculate credit refill ratio using multiplier */
 		credit_refill = min(link_percentage * min_multiplier,
 				    MAX_CREDIT_REFILL);
+
+		/* Refill at least minimum credit */
+		if (credit_refill < min_credit)
+			credit_refill = min_credit;
+
 		p->data_credits_refill = (u16)credit_refill;
 
 		/* Calculate maximum credit for the TC */
@@ -149,7 +154,7 @@
 		 * of a TC is too small, the maximum credit may not be
 		 * enough to send out a jumbo frame in data plane arbitration.
 		 */
-		if (credit_max && (credit_max < min_credit))
+		if (credit_max < min_credit)
 			credit_max = min_credit;
 
 		if (direction == DCB_TX_CONFIG) {
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
@@ -223,13 +223,13 @@
 	reg |= IXGBE_MFLCN_DPF;
 
 	/*
-	 * X540 supports per TC Rx priority flow control.  So
-	 * clear all TCs and only enable those that should be
+	 * X540 & X550 supports per TC Rx priority flow control.
+	 * So clear all TCs and only enable those that should be
 	 * enabled.
 	 */
 	reg &= ~(IXGBE_MFLCN_RPFCE_MASK | IXGBE_MFLCN_RFCE);
 
-	if (hw->mac.type == ixgbe_mac_X540)
+	if (hw->mac.type >= ixgbe_mac_X540)
 		reg |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT;
 
 	if (pfc_en)
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -151,47 +151,70 @@
 };
 #define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN
 
+/* currently supported speeds for 10G */
+#define ADVRTSD_MSK_10G (SUPPORTED_10000baseT_Full | \
+			 SUPPORTED_10000baseKX4_Full | \
+			 SUPPORTED_10000baseKR_Full)
+
+#define ixgbe_isbackplane(type) ((type) == ixgbe_media_type_backplane)
+
+static u32 ixgbe_get_supported_10gtypes(struct ixgbe_hw *hw)
+{
+	if (!ixgbe_isbackplane(hw->phy.media_type))
+		return SUPPORTED_10000baseT_Full;
+
+	switch (hw->device_id) {
+	case IXGBE_DEV_ID_82598:
+	case IXGBE_DEV_ID_82599_KX4:
+	case IXGBE_DEV_ID_82599_KX4_MEZZ:
+	case IXGBE_DEV_ID_X550EM_X_KX4:
+		return SUPPORTED_10000baseKX4_Full;
+	case IXGBE_DEV_ID_82598_BX:
+	case IXGBE_DEV_ID_82599_KR:
+	case IXGBE_DEV_ID_X550EM_X_KR:
+		return SUPPORTED_10000baseKR_Full;
+	default:
+		return SUPPORTED_10000baseKX4_Full |
+		       SUPPORTED_10000baseKR_Full;
+	}
+}
+
 static int ixgbe_get_settings(struct net_device *netdev,
 			      struct ethtool_cmd *ecmd)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
 	ixgbe_link_speed supported_link;
-	u32 link_speed = 0;
 	bool autoneg = false;
-	bool link_up;
 
 	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_2_5GB_FULL)
-		ecmd->supported |= SUPPORTED_2500baseX_Full;
+		ecmd->supported |= ixgbe_get_supported_10gtypes(hw);
 	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;
+		ecmd->supported |= ixgbe_isbackplane(hw->phy.media_type) ?
+				   SUPPORTED_1000baseKX_Full :
+				   SUPPORTED_1000baseT_Full;
 
+	/* default advertised speed if phy.autoneg_advertised isn't set */
+	ecmd->advertising = ecmd->supported;
 	/* set the advertised speeds */
 	if (hw->phy.autoneg_advertised) {
+		ecmd->advertising = 0;
 		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_2_5GB_FULL)
-			ecmd->advertising |= ADVERTISED_2500baseX_Full;
-		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
-			ecmd->advertising |= ADVERTISED_1000baseT_Full;
+			ecmd->advertising |= ecmd->supported & ADVRTSD_MSK_10G;
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) {
+			if (ecmd->supported & SUPPORTED_1000baseKX_Full)
+				ecmd->advertising |= ADVERTISED_1000baseKX_Full;
+			else
+				ecmd->advertising |= ADVERTISED_1000baseT_Full;
+		}
 	} else {
-		/* 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;
-
 		if (hw->phy.multispeed_fiber && !autoneg) {
 			if (supported_link & IXGBE_LINK_SPEED_10GB_FULL)
 				ecmd->advertising = ADVERTISED_10000baseT_Full;
@@ -229,6 +252,10 @@
 	case ixgbe_phy_sfp_avago:
 	case ixgbe_phy_sfp_intel:
 	case ixgbe_phy_sfp_unknown:
+	case ixgbe_phy_qsfp_passive_unknown:
+	case ixgbe_phy_qsfp_active_unknown:
+	case ixgbe_phy_qsfp_intel:
+	case ixgbe_phy_qsfp_unknown:
 		/* SFP+ devices, further checking needed */
 		switch (adapter->hw.phy.sfp_type) {
 		case ixgbe_sfp_type_da_cu:
@@ -284,9 +311,8 @@
 		break;
 	}
 
-	hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
-	if (link_up) {
-		switch (link_speed) {
+	if (netif_carrier_ok(netdev)) {
+		switch (adapter->link_speed) {
 		case IXGBE_LINK_SPEED_10GB_FULL:
 			ethtool_cmd_speed_set(ecmd, SPEED_10000);
 			break;
@@ -2494,9 +2520,9 @@
 	return ret;
 }
 
-static int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
-					   struct ixgbe_fdir_filter *input,
-					   u16 sw_idx)
+int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
+				    struct ixgbe_fdir_filter *input,
+				    u16 sw_idx)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct hlist_node *node2;
@@ -3133,7 +3159,8 @@
 		page_swap = true;
 	}
 
-	if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap) {
+	if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap ||
+	    !(addr_mode & IXGBE_SFF_DDM_IMPLEMENTED)) {
 		/* We have a SFP, but it does not support SFF-8472 */
 		modinfo->type = ETH_MODULE_SFF_8079;
 		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -77,7 +77,7 @@
 	if (!netdev)
 		return 0;
 
-	if (xid >= IXGBE_FCOE_DDP_MAX)
+	if (xid >= netdev->fcoe_ddp_xid)
 		return 0;
 
 	adapter = netdev_priv(netdev);
@@ -177,7 +177,7 @@
 		return 0;
 
 	adapter = netdev_priv(netdev);
-	if (xid >= IXGBE_FCOE_DDP_MAX) {
+	if (xid >= netdev->fcoe_ddp_xid) {
 		e_warn(drv, "xid=0x%x out-of-range\n", xid);
 		return 0;
 	}
@@ -517,6 +517,7 @@
 	u32 vlan_macip_lens;
 	u32 fcoe_sof_eof = 0;
 	u32 mss_l4len_idx;
+	u32 type_tucmd = IXGBE_ADVTXT_TUCMD_FCOE;
 	u8 sof, eof;
 
 	if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) {
@@ -593,6 +594,8 @@
 					       skb_shinfo(skb)->gso_size);
 		first->bytecount += (first->gso_segs - 1) * *hdr_len;
 		first->tx_flags |= IXGBE_TX_FLAGS_TSO;
+		/* Hardware expects L4T to be RSV for FCoE TSO */
+		type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_RSV;
 	}
 
 	/* set flag indicating FCOE to ixgbe_tx_map call */
@@ -610,7 +613,7 @@
 
 	/* write context desc */
 	ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, fcoe_sof_eof,
-			  IXGBE_ADVTXT_TUCMD_FCOE, mss_l4len_idx);
+			  type_tucmd, mss_l4len_idx);
 
 	return 0;
 }
@@ -620,8 +623,7 @@
 	struct ixgbe_fcoe_ddp_pool *ddp_pool;
 
 	ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu);
-	if (ddp_pool->pool)
-		dma_pool_destroy(ddp_pool->pool);
+	dma_pool_destroy(ddp_pool->pool);
 	ddp_pool->pool = NULL;
 }
 
@@ -997,8 +999,7 @@
 		return -EINVAL;
 
 	/* Don't return information on unsupported devices */
-	if (hw->mac.type != ixgbe_mac_82599EB &&
-	    hw->mac.type != ixgbe_mac_X540)
+	if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
 		return -EINVAL;
 
 	/* Manufacturer */
@@ -1044,6 +1045,10 @@
 		snprintf(info->model,
 			 sizeof(info->model),
 			 "Intel 82599");
+	} else if (hw->mac.type == ixgbe_mac_X550) {
+		snprintf(info->model,
+			 sizeof(info->model),
+			 "Intel X550");
 	} else {
 		snprintf(info->model,
 			 sizeof(info->model),
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -307,6 +307,7 @@
 	ixgbe_cache_ring_rss(adapter);
 }
 
+#define IXGBE_RSS_64Q_MASK	0x3F
 #define IXGBE_RSS_16Q_MASK	0xF
 #define IXGBE_RSS_8Q_MASK	0x7
 #define IXGBE_RSS_4Q_MASK	0x3
@@ -602,6 +603,7 @@
  **/
 static bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
 {
+	struct ixgbe_hw *hw = &adapter->hw;
 	struct ixgbe_ring_feature *f;
 	u16 rss_i;
 
@@ -610,7 +612,11 @@
 	rss_i = f->limit;
 
 	f->indices = rss_i;
-	f->mask = IXGBE_RSS_16Q_MASK;
+
+	if (hw->mac.type < ixgbe_mac_X550)
+		f->mask = IXGBE_RSS_16Q_MASK;
+	else
+		f->mask = IXGBE_RSS_64Q_MASK;
 
 	/* disable ATR by default, it will be configured below */
 	adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -51,6 +51,8 @@
 #include <linux/prefetch.h>
 #include <scsi/fc/fc_fcoe.h>
 #include <net/vxlan.h>
+#include <net/pkt_cls.h>
+#include <net/tc_act/tc_gact.h>
 
 #ifdef CONFIG_OF
 #include <linux/of_net.h>
@@ -65,9 +67,7 @@
 #include "ixgbe_common.h"
 #include "ixgbe_dcb_82599.h"
 #include "ixgbe_sriov.h"
-#ifdef CONFIG_IXGBE_VXLAN
-#include <net/vxlan.h>
-#endif
+#include "ixgbe_model.h"
 
 char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
@@ -175,6 +175,8 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+static struct workqueue_struct *ixgbe_wq;
+
 static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev);
 
 static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
@@ -316,7 +318,7 @@
 	if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
 	    !test_bit(__IXGBE_REMOVING, &adapter->state) &&
 	    !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state))
-		schedule_work(&adapter->service_task);
+		queue_work(ixgbe_wq, &adapter->service_task);
 }
 
 static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
@@ -1088,9 +1090,10 @@
  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
  * @q_vector: structure containing interrupt and ring information
  * @tx_ring: tx ring to clean
+ * @napi_budget: Used to determine if we are in netpoll
  **/
 static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
-			       struct ixgbe_ring *tx_ring)
+			       struct ixgbe_ring *tx_ring, int napi_budget)
 {
 	struct ixgbe_adapter *adapter = q_vector->adapter;
 	struct ixgbe_tx_buffer *tx_buffer;
@@ -1114,7 +1117,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		read_barrier_depends();
+		smp_rmb();
 
 		/* if DD is not set pending work has not been completed */
 		if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
@@ -1128,7 +1131,7 @@
 		total_packets += tx_buffer->gso_segs;
 
 		/* free the skb */
-		dev_consume_skb_any(tx_buffer->skb);
+		napi_consume_skb(tx_buffer->skb, napi_budget);
 
 		/* unmap skb header data */
 		dma_unmap_single(tx_ring->dev,
@@ -1484,7 +1487,7 @@
 			return;
 
 		if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_OUTERIPER)) {
-			ring->rx_stats.csum_err++;
+			skb->ip_summed = CHECKSUM_NONE;
 			return;
 		}
 		/* If we checked the outer header let the stack know */
@@ -1635,6 +1638,7 @@
 				     struct sk_buff *skb)
 {
 	struct net_device *dev = rx_ring->netdev;
+	u32 flags = rx_ring->q_vector->adapter->flags;
 
 	ixgbe_update_rsc_stats(rx_ring, skb);
 
@@ -1642,8 +1646,8 @@
 
 	ixgbe_rx_checksum(rx_ring, rx_desc, skb);
 
-	if (unlikely(ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
-		ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector->adapter, skb);
+	if (unlikely(flags & IXGBE_FLAG_RX_HWTSTAMP_ENABLED))
+		ixgbe_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
 
 	if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
 	    ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
@@ -2741,7 +2745,7 @@
 	ixgbe_check_fan_failure(adapter, eicr);
 
 	if (unlikely(eicr & IXGBE_EICR_TIMESYNC))
-		ixgbe_ptp_check_pps_event(adapter, eicr);
+		ixgbe_ptp_check_pps_event(adapter);
 
 	/* re-enable the original interrupt state, no lsc, no queues */
 	if (!test_bit(__IXGBE_DOWN, &adapter->state))
@@ -2757,7 +2761,7 @@
 	/* EIAM disabled interrupts (on this vector) for us */
 
 	if (q_vector->rx.ring || q_vector->tx.ring)
-		napi_schedule(&q_vector->napi);
+		napi_schedule_irqoff(&q_vector->napi);
 
 	return IRQ_HANDLED;
 }
@@ -2783,10 +2787,13 @@
 		ixgbe_update_dca(q_vector);
 #endif
 
-	ixgbe_for_each_ring(ring, q_vector->tx)
-		clean_complete &= !!ixgbe_clean_tx_irq(q_vector, ring);
+	ixgbe_for_each_ring(ring, q_vector->tx) {
+		if (!ixgbe_clean_tx_irq(q_vector, ring, budget))
+			clean_complete = false;
+	}
 
-	if (!ixgbe_qv_lock_napi(q_vector))
+	/* Exit if we are called by netpoll or busy polling is active */
+	if ((budget <= 0) || !ixgbe_qv_lock_napi(q_vector))
 		return budget;
 
 	/* attempt to distribute budget to each queue fairly, but don't allow
@@ -2801,7 +2808,8 @@
 						 per_ring_budget);
 
 		work_done += cleaned;
-		clean_complete &= (cleaned < per_ring_budget);
+		if (cleaned >= per_ring_budget)
+			clean_complete = false;
 	}
 
 	ixgbe_qv_unlock_napi(q_vector);
@@ -2947,10 +2955,10 @@
 
 	ixgbe_check_fan_failure(adapter, eicr);
 	if (unlikely(eicr & IXGBE_EICR_TIMESYNC))
-		ixgbe_ptp_check_pps_event(adapter, eicr);
+		ixgbe_ptp_check_pps_event(adapter);
 
 	/* would disable interrupts here but EIAM disabled it */
-	napi_schedule(&q_vector->napi);
+	napi_schedule_irqoff(&q_vector->napi);
 
 	/*
 	 * re-enable link(maybe) and non-queue interrupts, no flush.
@@ -3315,8 +3323,7 @@
 }
 
 /**
- * Return a number of entries in the RSS indirection table
- *
+ * ixgbe_rss_indir_tbl_entries - Return RSS indirection table entries
  * @adapter: device handle
  *
  *  - 82598/82599/X540:     128
@@ -3334,8 +3341,7 @@
 }
 
 /**
- * Write the RETA table to HW
- *
+ * ixgbe_store_reta - Write the RETA table to HW
  * @adapter: device handle
  *
  * Write the RSS redirection table stored in adapter.rss_indir_tbl[] to HW.
@@ -3374,8 +3380,7 @@
 }
 
 /**
- * Write the RETA table to HW (for x550 devices in SRIOV mode)
- *
+ * ixgbe_store_vfreta - Write the RETA table to HW (x550 devices in SRIOV mode)
  * @adapter: device handle
  *
  * Write the RSS redirection table stored in adapter.rss_indir_tbl[] to HW.
@@ -3621,6 +3626,9 @@
 	IXGBE_WRITE_REG(hw, IXGBE_RDBAH(reg_idx), (rdba >> 32));
 	IXGBE_WRITE_REG(hw, IXGBE_RDLEN(reg_idx),
 			ring->count * sizeof(union ixgbe_adv_rx_desc));
+	/* Force flushing of IXGBE_RDLEN to prevent MDD */
+	IXGBE_WRITE_FLUSH(hw);
+
 	IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0);
 	IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0);
 	ring->tail = adapter->io_addr + IXGBE_RDT(reg_idx);
@@ -3704,6 +3712,9 @@
 	/* Map PF MAC address in RAR Entry 0 to first pool following VFs */
 	hw->mac.ops.set_vmdq(hw, 0, VMDQ_P(0));
 
+	/* clear VLAN promisc flag so VFTA will be updated if necessary */
+	adapter->flags2 &= ~IXGBE_FLAG2_VLAN_PROMISC;
+
 	/*
 	 * Set up VF register offsets for selected VT Mode,
 	 * i.e. 32 or 64 VFs for SR-IOV
@@ -3901,12 +3912,56 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 
 	/* add VID to filter table */
-	hw->mac.ops.set_vfta(&adapter->hw, vid, VMDQ_P(0), true);
+	hw->mac.ops.set_vfta(&adapter->hw, vid, VMDQ_P(0), true, true);
 	set_bit(vid, adapter->active_vlans);
 
 	return 0;
 }
 
+static int ixgbe_find_vlvf_entry(struct ixgbe_hw *hw, u32 vlan)
+{
+	u32 vlvf;
+	int idx;
+
+	/* short cut the special case */
+	if (vlan == 0)
+		return 0;
+
+	/* Search for the vlan id in the VLVF entries */
+	for (idx = IXGBE_VLVF_ENTRIES; --idx;) {
+		vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(idx));
+		if ((vlvf & VLAN_VID_MASK) == vlan)
+			break;
+	}
+
+	return idx;
+}
+
+void ixgbe_update_pf_promisc_vlvf(struct ixgbe_adapter *adapter, u32 vid)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 bits, word;
+	int idx;
+
+	idx = ixgbe_find_vlvf_entry(hw, vid);
+	if (!idx)
+		return;
+
+	/* See if any other pools are set for this VLAN filter
+	 * entry other than the PF.
+	 */
+	word = idx * 2 + (VMDQ_P(0) / 32);
+	bits = ~(1 << (VMDQ_P(0)) % 32);
+	bits &= IXGBE_READ_REG(hw, IXGBE_VLVFB(word));
+
+	/* Disable the filter so this falls into the default pool. */
+	if (!bits && !IXGBE_READ_REG(hw, IXGBE_VLVFB(word ^ 1))) {
+		if (!(adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC))
+			IXGBE_WRITE_REG(hw, IXGBE_VLVFB(word), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_VLVF(idx), 0);
+	}
+}
+
 static int ixgbe_vlan_rx_kill_vid(struct net_device *netdev,
 				  __be16 proto, u16 vid)
 {
@@ -3914,7 +3969,11 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 
 	/* remove VID from filter table */
-	hw->mac.ops.set_vfta(&adapter->hw, vid, VMDQ_P(0), false);
+	if (adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC)
+		ixgbe_update_pf_promisc_vlvf(adapter, vid);
+	else
+		hw->mac.ops.set_vfta(hw, vid, VMDQ_P(0), false, true);
+
 	clear_bit(vid, adapter->active_vlans);
 
 	return 0;
@@ -3992,6 +4051,135 @@
 	}
 }
 
+static void ixgbe_vlan_promisc_enable(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 vlnctrl, i;
+
+	vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+
+	switch (hw->mac.type) {
+	case ixgbe_mac_82599EB:
+	case ixgbe_mac_X540:
+	case ixgbe_mac_X550:
+	case ixgbe_mac_X550EM_x:
+	default:
+		if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED)
+			break;
+		/* fall through */
+	case ixgbe_mac_82598EB:
+		/* legacy case, we can just disable VLAN filtering */
+		vlnctrl &= ~IXGBE_VLNCTRL_VFE;
+		IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+		return;
+	}
+
+	/* We are already in VLAN promisc, nothing to do */
+	if (adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC)
+		return;
+
+	/* Set flag so we don't redo unnecessary work */
+	adapter->flags2 |= IXGBE_FLAG2_VLAN_PROMISC;
+
+	/* For VMDq and SR-IOV we must leave VLAN filtering enabled */
+	vlnctrl |= IXGBE_VLNCTRL_VFE;
+	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+
+	/* Add PF to all active pools */
+	for (i = IXGBE_VLVF_ENTRIES; --i;) {
+		u32 reg_offset = IXGBE_VLVFB(i * 2 + VMDQ_P(0) / 32);
+		u32 vlvfb = IXGBE_READ_REG(hw, reg_offset);
+
+		vlvfb |= 1 << (VMDQ_P(0) % 32);
+		IXGBE_WRITE_REG(hw, reg_offset, vlvfb);
+	}
+
+	/* Set all bits in the VLAN filter table array */
+	for (i = hw->mac.vft_size; i--;)
+		IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), ~0U);
+}
+
+#define VFTA_BLOCK_SIZE 8
+static void ixgbe_scrub_vfta(struct ixgbe_adapter *adapter, u32 vfta_offset)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 vfta[VFTA_BLOCK_SIZE] = { 0 };
+	u32 vid_start = vfta_offset * 32;
+	u32 vid_end = vid_start + (VFTA_BLOCK_SIZE * 32);
+	u32 i, vid, word, bits;
+
+	for (i = IXGBE_VLVF_ENTRIES; --i;) {
+		u32 vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(i));
+
+		/* pull VLAN ID from VLVF */
+		vid = vlvf & VLAN_VID_MASK;
+
+		/* only concern outselves with a certain range */
+		if (vid < vid_start || vid >= vid_end)
+			continue;
+
+		if (vlvf) {
+			/* record VLAN ID in VFTA */
+			vfta[(vid - vid_start) / 32] |= 1 << (vid % 32);
+
+			/* if PF is part of this then continue */
+			if (test_bit(vid, adapter->active_vlans))
+				continue;
+		}
+
+		/* remove PF from the pool */
+		word = i * 2 + VMDQ_P(0) / 32;
+		bits = ~(1 << (VMDQ_P(0) % 32));
+		bits &= IXGBE_READ_REG(hw, IXGBE_VLVFB(word));
+		IXGBE_WRITE_REG(hw, IXGBE_VLVFB(word), bits);
+	}
+
+	/* extract values from active_vlans and write back to VFTA */
+	for (i = VFTA_BLOCK_SIZE; i--;) {
+		vid = (vfta_offset + i) * 32;
+		word = vid / BITS_PER_LONG;
+		bits = vid % BITS_PER_LONG;
+
+		vfta[i] |= adapter->active_vlans[word] >> bits;
+
+		IXGBE_WRITE_REG(hw, IXGBE_VFTA(vfta_offset + i), vfta[i]);
+	}
+}
+
+static void ixgbe_vlan_promisc_disable(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 vlnctrl, i;
+
+	/* Set VLAN filtering to enabled */
+	vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+	vlnctrl |= IXGBE_VLNCTRL_VFE;
+	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+
+	switch (hw->mac.type) {
+	case ixgbe_mac_82599EB:
+	case ixgbe_mac_X540:
+	case ixgbe_mac_X550:
+	case ixgbe_mac_X550EM_x:
+	default:
+		if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED)
+			break;
+		/* fall through */
+	case ixgbe_mac_82598EB:
+		return;
+	}
+
+	/* We are not in VLAN promisc, nothing to do */
+	if (!(adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC))
+		return;
+
+	/* Set flag so we don't redo unnecessary work */
+	adapter->flags2 &= ~IXGBE_FLAG2_VLAN_PROMISC;
+
+	for (i = 0; i < hw->mac.vft_size; i += VFTA_BLOCK_SIZE)
+		ixgbe_scrub_vfta(adapter, i);
+}
+
 static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
 {
 	u16 vid;
@@ -4034,124 +4222,156 @@
 #ifdef CONFIG_PCI_IOV
 void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter)
 {
+	struct ixgbe_mac_addr *mac_table = &adapter->mac_table[0];
 	struct ixgbe_hw *hw = &adapter->hw;
 	int i;
-	for (i = 0; i < hw->mac.num_rar_entries; i++) {
-		if (adapter->mac_table[i].state & IXGBE_MAC_STATE_IN_USE)
-			hw->mac.ops.set_rar(hw, i, adapter->mac_table[i].addr,
-					    adapter->mac_table[i].queue,
+
+	for (i = 0; i < hw->mac.num_rar_entries; i++, mac_table++) {
+		mac_table->state &= ~IXGBE_MAC_STATE_MODIFIED;
+
+		if (mac_table->state & IXGBE_MAC_STATE_IN_USE)
+			hw->mac.ops.set_rar(hw, i,
+					    mac_table->addr,
+					    mac_table->pool,
 					    IXGBE_RAH_AV);
 		else
 			hw->mac.ops.clear_rar(hw, i);
-
-		adapter->mac_table[i].state &= ~(IXGBE_MAC_STATE_MODIFIED);
 	}
 }
-#endif
 
+#endif
 static void ixgbe_sync_mac_table(struct ixgbe_adapter *adapter)
 {
+	struct ixgbe_mac_addr *mac_table = &adapter->mac_table[0];
 	struct ixgbe_hw *hw = &adapter->hw;
 	int i;
-	for (i = 0; i < hw->mac.num_rar_entries; i++) {
-		if (adapter->mac_table[i].state & IXGBE_MAC_STATE_MODIFIED) {
-			if (adapter->mac_table[i].state &
-			    IXGBE_MAC_STATE_IN_USE)
-				hw->mac.ops.set_rar(hw, i,
-						adapter->mac_table[i].addr,
-						adapter->mac_table[i].queue,
-						IXGBE_RAH_AV);
-			else
-				hw->mac.ops.clear_rar(hw, i);
 
-			adapter->mac_table[i].state &=
-						~(IXGBE_MAC_STATE_MODIFIED);
-		}
+	for (i = 0; i < hw->mac.num_rar_entries; i++, mac_table++) {
+		if (!(mac_table->state & IXGBE_MAC_STATE_MODIFIED))
+			continue;
+
+		mac_table->state &= ~IXGBE_MAC_STATE_MODIFIED;
+
+		if (mac_table->state & IXGBE_MAC_STATE_IN_USE)
+			hw->mac.ops.set_rar(hw, i,
+					    mac_table->addr,
+					    mac_table->pool,
+					    IXGBE_RAH_AV);
+		else
+			hw->mac.ops.clear_rar(hw, i);
 	}
 }
 
 static void ixgbe_flush_sw_mac_table(struct ixgbe_adapter *adapter)
 {
-	int i;
+	struct ixgbe_mac_addr *mac_table = &adapter->mac_table[0];
 	struct ixgbe_hw *hw = &adapter->hw;
+	int i;
 
-	for (i = 0; i < hw->mac.num_rar_entries; i++) {
-		adapter->mac_table[i].state |= IXGBE_MAC_STATE_MODIFIED;
-		adapter->mac_table[i].state &= ~IXGBE_MAC_STATE_IN_USE;
-		eth_zero_addr(adapter->mac_table[i].addr);
-		adapter->mac_table[i].queue = 0;
+	for (i = 0; i < hw->mac.num_rar_entries; i++, mac_table++) {
+		mac_table->state |= IXGBE_MAC_STATE_MODIFIED;
+		mac_table->state &= ~IXGBE_MAC_STATE_IN_USE;
 	}
+
 	ixgbe_sync_mac_table(adapter);
 }
 
-static int ixgbe_available_rars(struct ixgbe_adapter *adapter)
+static int ixgbe_available_rars(struct ixgbe_adapter *adapter, u16 pool)
 {
+	struct ixgbe_mac_addr *mac_table = &adapter->mac_table[0];
 	struct ixgbe_hw *hw = &adapter->hw;
 	int i, count = 0;
 
-	for (i = 0; i < hw->mac.num_rar_entries; i++) {
-		if (adapter->mac_table[i].state == 0)
-			count++;
+	for (i = 0; i < hw->mac.num_rar_entries; i++, mac_table++) {
+		/* do not count default RAR as available */
+		if (mac_table->state & IXGBE_MAC_STATE_DEFAULT)
+			continue;
+
+		/* only count unused and addresses that belong to us */
+		if (mac_table->state & IXGBE_MAC_STATE_IN_USE) {
+			if (mac_table->pool != pool)
+				continue;
+		}
+
+		count++;
 	}
+
 	return count;
 }
 
 /* this function destroys the first RAR entry */
-static void ixgbe_mac_set_default_filter(struct ixgbe_adapter *adapter,
-					 u8 *addr)
+static void ixgbe_mac_set_default_filter(struct ixgbe_adapter *adapter)
 {
+	struct ixgbe_mac_addr *mac_table = &adapter->mac_table[0];
 	struct ixgbe_hw *hw = &adapter->hw;
 
-	memcpy(&adapter->mac_table[0].addr, addr, ETH_ALEN);
-	adapter->mac_table[0].queue = VMDQ_P(0);
-	adapter->mac_table[0].state = (IXGBE_MAC_STATE_DEFAULT |
-				       IXGBE_MAC_STATE_IN_USE);
-	hw->mac.ops.set_rar(hw, 0, adapter->mac_table[0].addr,
-			    adapter->mac_table[0].queue,
+	memcpy(&mac_table->addr, hw->mac.addr, ETH_ALEN);
+	mac_table->pool = VMDQ_P(0);
+
+	mac_table->state = IXGBE_MAC_STATE_DEFAULT | IXGBE_MAC_STATE_IN_USE;
+
+	hw->mac.ops.set_rar(hw, 0, mac_table->addr, mac_table->pool,
 			    IXGBE_RAH_AV);
 }
 
-int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter, u8 *addr, u16 queue)
+int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter,
+			 const u8 *addr, u16 pool)
 {
+	struct ixgbe_mac_addr *mac_table = &adapter->mac_table[0];
 	struct ixgbe_hw *hw = &adapter->hw;
 	int i;
 
 	if (is_zero_ether_addr(addr))
 		return -EINVAL;
 
-	for (i = 0; i < hw->mac.num_rar_entries; i++) {
-		if (adapter->mac_table[i].state & IXGBE_MAC_STATE_IN_USE)
+	for (i = 0; i < hw->mac.num_rar_entries; i++, mac_table++) {
+		if (mac_table->state & IXGBE_MAC_STATE_IN_USE)
 			continue;
-		adapter->mac_table[i].state |= (IXGBE_MAC_STATE_MODIFIED |
-						IXGBE_MAC_STATE_IN_USE);
-		ether_addr_copy(adapter->mac_table[i].addr, addr);
-		adapter->mac_table[i].queue = queue;
+
+		ether_addr_copy(mac_table->addr, addr);
+		mac_table->pool = pool;
+
+		mac_table->state |= IXGBE_MAC_STATE_MODIFIED |
+				    IXGBE_MAC_STATE_IN_USE;
+
 		ixgbe_sync_mac_table(adapter);
+
 		return i;
 	}
+
 	return -ENOMEM;
 }
 
-int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter, u8 *addr, u16 queue)
+int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter,
+			 const u8 *addr, u16 pool)
 {
-	/* search table for addr, if found, set to 0 and sync */
-	int i;
+	struct ixgbe_mac_addr *mac_table = &adapter->mac_table[0];
 	struct ixgbe_hw *hw = &adapter->hw;
+	int i;
 
 	if (is_zero_ether_addr(addr))
 		return -EINVAL;
 
-	for (i = 0; i < hw->mac.num_rar_entries; i++) {
-		if (ether_addr_equal(addr, adapter->mac_table[i].addr) &&
-		    adapter->mac_table[i].queue == queue) {
-			adapter->mac_table[i].state |= IXGBE_MAC_STATE_MODIFIED;
-			adapter->mac_table[i].state &= ~IXGBE_MAC_STATE_IN_USE;
-			eth_zero_addr(adapter->mac_table[i].addr);
-			adapter->mac_table[i].queue = 0;
-			ixgbe_sync_mac_table(adapter);
-			return 0;
-		}
+	/* search table for addr, if found clear IN_USE flag and sync */
+	for (i = 0; i < hw->mac.num_rar_entries; i++, mac_table++) {
+		/* we can only delete an entry if it is in use */
+		if (!(mac_table->state & IXGBE_MAC_STATE_IN_USE))
+			continue;
+		/* we only care about entries that belong to the given pool */
+		if (mac_table->pool != pool)
+			continue;
+		/* we only care about a specific MAC address */
+		if (!ether_addr_equal(addr, mac_table->addr))
+			continue;
+
+		mac_table->state |= IXGBE_MAC_STATE_MODIFIED;
+		mac_table->state &= ~IXGBE_MAC_STATE_IN_USE;
+
+		ixgbe_sync_mac_table(adapter);
+
+		return 0;
 	}
+
 	return -ENOMEM;
 }
 /**
@@ -4169,7 +4389,7 @@
 	int count = 0;
 
 	/* return ENOMEM indicating insufficient memory for addresses */
-	if (netdev_uc_count(netdev) > ixgbe_available_rars(adapter))
+	if (netdev_uc_count(netdev) > ixgbe_available_rars(adapter, vfn))
 		return -ENOMEM;
 
 	if (!netdev_uc_empty(netdev)) {
@@ -4183,6 +4403,25 @@
 	return count;
 }
 
+static int ixgbe_uc_sync(struct net_device *netdev, const unsigned char *addr)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	int ret;
+
+	ret = ixgbe_add_mac_filter(adapter, addr, VMDQ_P(0));
+
+	return min_t(int, ret, 0);
+}
+
+static int ixgbe_uc_unsync(struct net_device *netdev, const unsigned char *addr)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	ixgbe_del_mac_filter(adapter, addr, VMDQ_P(0));
+
+	return 0;
+}
+
 /**
  * ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set
  * @netdev: network interface device structure
@@ -4197,12 +4436,10 @@
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE;
-	u32 vlnctrl;
 	int count;
 
 	/* Check for Promiscuous and All Multicast modes */
 	fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
-	vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
 
 	/* set all bits that we expect to always be set */
 	fctrl &= ~IXGBE_FCTRL_SBP; /* disable store-bad-packets */
@@ -4212,25 +4449,18 @@
 
 	/* clear the bits we are changing the status of */
 	fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
-	vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
 	if (netdev->flags & IFF_PROMISC) {
 		hw->addr_ctrl.user_set_promisc = true;
 		fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
 		vmolr |= IXGBE_VMOLR_MPE;
-		/* Only disable hardware filter vlans in promiscuous mode
-		 * if SR-IOV and VMDQ are disabled - otherwise ensure
-		 * that hardware VLAN filters remain enabled.
-		 */
-		if (adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
-				      IXGBE_FLAG_SRIOV_ENABLED))
-			vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
+		ixgbe_vlan_promisc_enable(adapter);
 	} else {
 		if (netdev->flags & IFF_ALLMULTI) {
 			fctrl |= IXGBE_FCTRL_MPE;
 			vmolr |= IXGBE_VMOLR_MPE;
 		}
-		vlnctrl |= IXGBE_VLNCTRL_VFE;
 		hw->addr_ctrl.user_set_promisc = false;
+		ixgbe_vlan_promisc_disable(adapter);
 	}
 
 	/*
@@ -4238,8 +4468,7 @@
 	 * sufficient space to store all the addresses then enable
 	 * unicast promiscuous mode
 	 */
-	count = ixgbe_write_uc_addr_list(netdev, VMDQ_P(0));
-	if (count < 0) {
+	if (__dev_uc_sync(netdev, ixgbe_uc_sync, ixgbe_uc_unsync)) {
 		fctrl |= IXGBE_FCTRL_UPE;
 		vmolr |= IXGBE_VMOLR_ROPE;
 	}
@@ -4275,7 +4504,6 @@
 		/* NOTE:  VLAN filtering is disabled by setting PROMISC */
 	}
 
-	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
 
 	if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
@@ -4531,6 +4759,7 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct hlist_node *node2;
 	struct ixgbe_fdir_filter *filter;
+	u8 queue;
 
 	spin_lock(&adapter->fdir_perfect_lock);
 
@@ -4539,12 +4768,34 @@
 
 	hlist_for_each_entry_safe(filter, node2,
 				  &adapter->fdir_filter_list, fdir_node) {
+		if (filter->action == IXGBE_FDIR_DROP_QUEUE) {
+			queue = IXGBE_FDIR_DROP_QUEUE;
+		} else {
+			u32 ring = ethtool_get_flow_spec_ring(filter->action);
+			u8 vf = ethtool_get_flow_spec_ring_vf(filter->action);
+
+			if (!vf && (ring >= adapter->num_rx_queues)) {
+				e_err(drv, "FDIR restore failed without VF, ring: %u\n",
+				      ring);
+				continue;
+			} else if (vf &&
+				   ((vf > adapter->num_vfs) ||
+				     ring >= adapter->num_rx_queues_per_pool)) {
+				e_err(drv, "FDIR restore failed with VF, vf: %hhu, ring: %u\n",
+				      vf, ring);
+				continue;
+			}
+
+			/* Map the ring onto the absolute queue index */
+			if (!vf)
+				queue = adapter->rx_ring[ring]->reg_idx;
+			else
+				queue = ((vf - 1) *
+					adapter->num_rx_queues_per_pool) + ring;
+		}
+
 		ixgbe_fdir_write_perfect_filter_82599(hw,
-				&filter->filter,
-				filter->sw_idx,
-				(filter->action == IXGBE_FDIR_DROP_QUEUE) ?
-				IXGBE_FDIR_DROP_QUEUE :
-				adapter->rx_ring[filter->action]->reg_idx);
+				&filter->filter, filter->sw_idx, queue);
 	}
 
 	spin_unlock(&adapter->fdir_perfect_lock);
@@ -5042,7 +5293,6 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct net_device *netdev = adapter->netdev;
 	int err;
-	u8 old_addr[ETH_ALEN];
 
 	if (ixgbe_removed(hw->hw_addr))
 		return;
@@ -5078,10 +5328,13 @@
 	}
 
 	clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
-	/* do not flush user set addresses */
-	memcpy(old_addr, &adapter->mac_table[0].addr, netdev->addr_len);
+
+	/* flush entries out of MAC table */
 	ixgbe_flush_sw_mac_table(adapter);
-	ixgbe_mac_set_default_filter(adapter, old_addr);
+	__dev_uc_unsync(netdev, NULL);
+
+	/* do not flush user set addresses */
+	ixgbe_mac_set_default_filter(adapter);
 
 	/* update SAN MAC vmdq pool selection */
 	if (hw->mac.san_mac_rar_index)
@@ -5328,9 +5581,14 @@
 #endif /* CONFIG_IXGBE_DCB */
 #endif /* IXGBE_FCOE */
 
+	/* initialize static ixgbe jump table entries */
+	adapter->jump_tables[0] = ixgbe_ipv4_fields;
+
 	adapter->mac_table = kzalloc(sizeof(struct ixgbe_mac_addr) *
 				     hw->mac.num_rar_entries,
 				     GFP_ATOMIC);
+	if (!adapter->mac_table)
+		return -ENOMEM;
 
 	/* Set MAC specific capability flags and exceptions */
 	switch (hw->mac.type) {
@@ -5877,7 +6135,8 @@
 
 	ixgbe_ptp_stop(adapter);
 
-	ixgbe_close_suspend(adapter);
+	if (netif_device_present(netdev))
+		ixgbe_close_suspend(adapter);
 
 	ixgbe_fdir_filter_exit(adapter);
 
@@ -5922,14 +6181,12 @@
 	if (!err && netif_running(netdev))
 		err = ixgbe_open(netdev);
 
-	rtnl_unlock();
-
-	if (err)
-		return err;
 
-	netif_device_attach(netdev);
+	if (!err)
+		netif_device_attach(netdev);
+	rtnl_unlock();
 
-	return 0;
+	return err;
 }
 #endif /* CONFIG_PM */
 
@@ -5944,14 +6201,14 @@
 	int retval = 0;
 #endif
 
+	rtnl_lock();
 	netif_device_detach(netdev);
 
-	rtnl_lock();
 	if (netif_running(netdev))
 		ixgbe_close_suspend(adapter);
-	rtnl_unlock();
 
 	ixgbe_clear_interrupt_scheme(adapter);
+	rtnl_unlock();
 
 #ifdef CONFIG_PM
 	retval = pci_save_state(pdev);
@@ -6616,10 +6873,8 @@
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct pci_dev *pdev = adapter->pdev;
-	struct pci_dev *vfdev;
+	unsigned int vf;
 	u32 gpc;
-	int pos;
-	unsigned short vf_id;
 
 	if (!(netif_carrier_ok(adapter->netdev)))
 		return;
@@ -6636,26 +6891,17 @@
 	if (!pdev)
 		return;
 
-	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
-	if (!pos)
-		return;
-
-	/* get the device ID for the VF */
-	pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &vf_id);
-
 	/* check status reg for all VFs owned by this PF */
-	vfdev = pci_get_device(pdev->vendor, vf_id, NULL);
-	while (vfdev) {
-		if (vfdev->is_virtfn && (vfdev->physfn == pdev)) {
-			u16 status_reg;
-
-			pci_read_config_word(vfdev, PCI_STATUS, &status_reg);
-			if (status_reg & PCI_STATUS_REC_MASTER_ABORT)
-				/* issue VFLR */
-				ixgbe_issue_vf_flr(adapter, vfdev);
-		}
+	for (vf = 0; vf < adapter->num_vfs; ++vf) {
+		struct pci_dev *vfdev = adapter->vfinfo[vf].vfdev;
+		u16 status_reg;
 
-		vfdev = pci_get_device(pdev->vendor, vf_id, vfdev);
+		if (!vfdev)
+			continue;
+		pci_read_config_word(vfdev, PCI_STATUS, &status_reg);
+		if (status_reg != IXGBE_FAILED_READ_CFG_WORD &&
+		    status_reg & PCI_STATUS_REC_MASTER_ABORT)
+			ixgbe_issue_vf_flr(adapter, vfdev);
 	}
 }
 
@@ -7024,6 +7270,7 @@
 			struct tcphdr *tcphdr;
 			u8 *raw;
 		} transport_hdr;
+		__be16 frag_off;
 
 		if (skb->encapsulation) {
 			network_hdr.raw = skb_inner_network_header(skb);
@@ -7047,13 +7294,17 @@
 		case 6:
 			vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
 			l4_hdr = network_hdr.ipv6->nexthdr;
+			if (likely((transport_hdr.raw - network_hdr.raw) ==
+				   sizeof(struct ipv6hdr)))
+				break;
+			ipv6_skip_exthdr(skb, network_hdr.raw - skb->data +
+					      sizeof(struct ipv6hdr),
+					 &l4_hdr, &frag_off);
+			if (unlikely(frag_off))
+				l4_hdr = NEXTHDR_FRAGMENT;
 			break;
 		default:
-			if (unlikely(net_ratelimit())) {
-				dev_warn(tx_ring->dev,
-					 "partial checksum but version=%d\n",
-					 network_hdr.ipv4->version);
-			}
+			break;
 		}
 
 		switch (l4_hdr) {
@@ -7074,16 +7325,18 @@
 		default:
 			if (unlikely(net_ratelimit())) {
 				dev_warn(tx_ring->dev,
-				 "partial checksum but l4 proto=%x!\n",
-				 l4_hdr);
+					 "partial checksum, version=%d, l4 proto=%x\n",
+					 network_hdr.ipv4->version, l4_hdr);
 			}
-			break;
+			skb_checksum_help(skb);
+			goto no_csum;
 		}
 
 		/* update TX checksum flag */
 		first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
 	}
 
+no_csum:
 	/* vlan_macip_lens: MACLEN, VLAN tag */
 	vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
 
@@ -7358,7 +7611,9 @@
 	/* snag network header to get L4 type and address */
 	skb = first->skb;
 	hdr.network = skb_network_header(skb);
-	if (skb->encapsulation) {
+	if (!skb->encapsulation) {
+		th = tcp_hdr(skb);
+	} else {
 #ifdef CONFIG_IXGBE_VXLAN
 		struct ixgbe_adapter *adapter = q_vector->adapter;
 
@@ -7377,14 +7632,34 @@
 #else
 		return;
 #endif /* CONFIG_IXGBE_VXLAN */
-	} else {
-		/* Currently only IPv4/IPv6 with TCP is supported */
-		if ((first->protocol != htons(ETH_P_IPV6) ||
-		     hdr.ipv6->nexthdr != IPPROTO_TCP) &&
-		    (first->protocol != htons(ETH_P_IP) ||
-		     hdr.ipv4->protocol != IPPROTO_TCP))
+	}
+
+	/* Currently only IPv4/IPv6 with TCP is supported */
+	switch (hdr.ipv4->version) {
+	case IPVERSION:
+		if (hdr.ipv4->protocol != IPPROTO_TCP)
 			return;
-		th = tcp_hdr(skb);
+		break;
+	case 6:
+		if (likely((unsigned char *)th - hdr.network ==
+			   sizeof(struct ipv6hdr))) {
+			if (hdr.ipv6->nexthdr != IPPROTO_TCP)
+				return;
+		} else {
+			__be16 frag_off;
+			u8 l4_hdr;
+
+			ipv6_skip_exthdr(skb, hdr.network - skb->data +
+					      sizeof(struct ipv6hdr),
+					 &l4_hdr, &frag_off);
+			if (unlikely(frag_off))
+				return;
+			if (l4_hdr != IPPROTO_TCP)
+				return;
+		}
+		break;
+	default:
+		return;
 	}
 
 	/* skip this packet since it is invalid or the socket is closing */
@@ -7419,10 +7694,12 @@
 		common.port.src ^= th->dest ^ first->protocol;
 	common.port.dst ^= th->source;
 
-	if (first->protocol == htons(ETH_P_IP)) {
+	switch (hdr.ipv4->version) {
+	case IPVERSION:
 		input.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
 		common.ip ^= hdr.ipv4->saddr ^ hdr.ipv4->daddr;
-	} else {
+		break;
+	case 6:
 		input.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV6;
 		common.ip ^= hdr.ipv6->saddr.s6_addr32[0] ^
 			     hdr.ipv6->saddr.s6_addr32[1] ^
@@ -7432,6 +7709,9 @@
 			     hdr.ipv6->daddr.s6_addr32[1] ^
 			     hdr.ipv6->daddr.s6_addr32[2] ^
 			     hdr.ipv6->daddr.s6_addr32[3];
+		break;
+	default:
+		break;
 	}
 
 #ifdef CONFIG_IXGBE_VXLAN
@@ -7659,17 +7939,16 @@
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct sockaddr *addr = p;
-	int ret;
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
-	ixgbe_del_mac_filter(adapter, hw->mac.addr, VMDQ_P(0));
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 	memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
 
-	ret = ixgbe_add_mac_filter(adapter, hw->mac.addr, VMDQ_P(0));
-	return ret > 0 ? 0 : ret;
+	ixgbe_mac_set_default_filter(adapter);
+
+	return 0;
 }
 
 static int
@@ -7959,6 +8238,228 @@
 	return 0;
 }
 
+static int ixgbe_delete_clsu32(struct ixgbe_adapter *adapter,
+			       struct tc_cls_u32_offload *cls)
+{
+	int err;
+
+	spin_lock(&adapter->fdir_perfect_lock);
+	err = ixgbe_update_ethtool_fdir_entry(adapter, NULL, cls->knode.handle);
+	spin_unlock(&adapter->fdir_perfect_lock);
+	return err;
+}
+
+static int ixgbe_configure_clsu32_add_hnode(struct ixgbe_adapter *adapter,
+					    __be16 protocol,
+					    struct tc_cls_u32_offload *cls)
+{
+	/* This ixgbe devices do not support hash tables at the moment
+	 * so abort when given hash tables.
+	 */
+	if (cls->hnode.divisor > 0)
+		return -EINVAL;
+
+	set_bit(TC_U32_USERHTID(cls->hnode.handle), &adapter->tables);
+	return 0;
+}
+
+static int ixgbe_configure_clsu32_del_hnode(struct ixgbe_adapter *adapter,
+					    struct tc_cls_u32_offload *cls)
+{
+	clear_bit(TC_U32_USERHTID(cls->hnode.handle), &adapter->tables);
+	return 0;
+}
+
+static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
+				  __be16 protocol,
+				  struct tc_cls_u32_offload *cls)
+{
+	u32 loc = cls->knode.handle & 0xfffff;
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct ixgbe_mat_field *field_ptr;
+	struct ixgbe_fdir_filter *input;
+	union ixgbe_atr_input mask;
+#ifdef CONFIG_NET_CLS_ACT
+	const struct tc_action *a;
+#endif
+	int i, err = 0;
+	u8 queue;
+	u32 handle;
+
+	memset(&mask, 0, sizeof(union ixgbe_atr_input));
+	handle = cls->knode.handle;
+
+	/* At the moment cls_u32 jumps to transport layer and skips past
+	 * L2 headers. The canonical method to match L2 frames is to use
+	 * negative values. However this is error prone at best but really
+	 * just broken because there is no way to "know" what sort of hdr
+	 * is in front of the transport layer. Fix cls_u32 to support L2
+	 * headers when needed.
+	 */
+	if (protocol != htons(ETH_P_IP))
+		return -EINVAL;
+
+	if (cls->knode.link_handle ||
+	    cls->knode.link_handle >= IXGBE_MAX_LINK_HANDLE) {
+		struct ixgbe_nexthdr *nexthdr = ixgbe_ipv4_jumps;
+		u32 uhtid = TC_U32_USERHTID(cls->knode.link_handle);
+
+		if (!test_bit(uhtid, &adapter->tables))
+			return -EINVAL;
+
+		for (i = 0; nexthdr[i].jump; i++) {
+			if (nexthdr->o != cls->knode.sel->offoff ||
+			    nexthdr->s != cls->knode.sel->offshift ||
+			    nexthdr->m != cls->knode.sel->offmask ||
+			    /* do not support multiple key jumps its just mad */
+			    cls->knode.sel->nkeys > 1)
+				return -EINVAL;
+
+			if (nexthdr->off != cls->knode.sel->keys[0].off ||
+			    nexthdr->val != cls->knode.sel->keys[0].val ||
+			    nexthdr->mask != cls->knode.sel->keys[0].mask)
+				return -EINVAL;
+
+			if (uhtid >= IXGBE_MAX_LINK_HANDLE)
+				return -EINVAL;
+
+			adapter->jump_tables[uhtid] = nexthdr->jump;
+		}
+		return 0;
+	}
+
+	if (loc >= ((1024 << adapter->fdir_pballoc) - 2)) {
+		e_err(drv, "Location out of range\n");
+		return -EINVAL;
+	}
+
+	/* cls u32 is a graph starting at root node 0x800. The driver tracks
+	 * links and also the fields used to advance the parser across each
+	 * link (e.g. nexthdr/eat parameters from 'tc'). This way we can map
+	 * the u32 graph onto the hardware parse graph denoted in ixgbe_model.h
+	 * To add support for new nodes update ixgbe_model.h parse structures
+	 * this function _should_ be generic try not to hardcode values here.
+	 */
+	if (TC_U32_USERHTID(handle) == 0x800) {
+		field_ptr = adapter->jump_tables[0];
+	} else {
+		if (TC_U32_USERHTID(handle) >= ARRAY_SIZE(adapter->jump_tables))
+			return -EINVAL;
+
+		field_ptr = adapter->jump_tables[TC_U32_USERHTID(handle)];
+	}
+
+	if (!field_ptr)
+		return -EINVAL;
+
+	input = kzalloc(sizeof(*input), GFP_KERNEL);
+	if (!input)
+		return -ENOMEM;
+
+	for (i = 0; i < cls->knode.sel->nkeys; i++) {
+		int off = cls->knode.sel->keys[i].off;
+		__be32 val = cls->knode.sel->keys[i].val;
+		__be32 m = cls->knode.sel->keys[i].mask;
+		bool found_entry = false;
+		int j;
+
+		for (j = 0; field_ptr[j].val; j++) {
+			if (field_ptr[j].off == off &&
+			    field_ptr[j].mask == m) {
+				field_ptr[j].val(input, &mask, val, m);
+				input->filter.formatted.flow_type |=
+					field_ptr[j].type;
+				found_entry = true;
+				break;
+			}
+		}
+
+		if (!found_entry)
+			goto err_out;
+	}
+
+	mask.formatted.flow_type = IXGBE_ATR_L4TYPE_IPV6_MASK |
+				   IXGBE_ATR_L4TYPE_MASK;
+
+	if (input->filter.formatted.flow_type == IXGBE_ATR_FLOW_TYPE_IPV4)
+		mask.formatted.flow_type &= IXGBE_ATR_L4TYPE_IPV6_MASK;
+
+#ifdef CONFIG_NET_CLS_ACT
+	if (list_empty(&cls->knode.exts->actions))
+		goto err_out;
+
+	list_for_each_entry(a, &cls->knode.exts->actions, list) {
+		if (!is_tcf_gact_shot(a))
+			goto err_out;
+	}
+#endif
+
+	input->action = IXGBE_FDIR_DROP_QUEUE;
+	queue = IXGBE_FDIR_DROP_QUEUE;
+	input->sw_idx = loc;
+
+	spin_lock(&adapter->fdir_perfect_lock);
+
+	if (hlist_empty(&adapter->fdir_filter_list)) {
+		memcpy(&adapter->fdir_mask, &mask, sizeof(mask));
+		err = ixgbe_fdir_set_input_mask_82599(hw, &mask);
+		if (err)
+			goto err_out_w_lock;
+	} else if (memcmp(&adapter->fdir_mask, &mask, sizeof(mask))) {
+		err = -EINVAL;
+		goto err_out_w_lock;
+	}
+
+	ixgbe_atr_compute_perfect_hash_82599(&input->filter, &mask);
+	err = ixgbe_fdir_write_perfect_filter_82599(hw, &input->filter,
+						    input->sw_idx, queue);
+	if (!err)
+		ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);
+	spin_unlock(&adapter->fdir_perfect_lock);
+
+	return err;
+err_out_w_lock:
+	spin_unlock(&adapter->fdir_perfect_lock);
+err_out:
+	kfree(input);
+	return -EINVAL;
+}
+
+int __ixgbe_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+		     struct tc_to_netdev *tc)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+
+	if (TC_H_MAJ(handle) == TC_H_MAJ(TC_H_INGRESS) &&
+	    tc->type == TC_SETUP_CLSU32) {
+		if (!(dev->features & NETIF_F_HW_TC))
+			return -EINVAL;
+
+		switch (tc->cls_u32->command) {
+		case TC_CLSU32_NEW_KNODE:
+		case TC_CLSU32_REPLACE_KNODE:
+			return ixgbe_configure_clsu32(adapter,
+						      proto, tc->cls_u32);
+		case TC_CLSU32_DELETE_KNODE:
+			return ixgbe_delete_clsu32(adapter, tc->cls_u32);
+		case TC_CLSU32_NEW_HNODE:
+		case TC_CLSU32_REPLACE_HNODE:
+			return ixgbe_configure_clsu32_add_hnode(adapter, proto,
+								tc->cls_u32);
+		case TC_CLSU32_DELETE_HNODE:
+			return ixgbe_configure_clsu32_del_hnode(adapter,
+								tc->cls_u32);
+		default:
+			return -EINVAL;
+		}
+	}
+
+	if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+
+	return ixgbe_setup_tc(dev, tc->tc);
+}
+
 #ifdef CONFIG_PCI_IOV
 void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter)
 {
@@ -8021,19 +8522,17 @@
 	}
 
 	/*
-	 * Check if Flow Director n-tuple support was enabled or disabled.  If
-	 * the state changed, we need to reset.
+	 * Check if Flow Director n-tuple support or hw_tc support was
+	 * enabled or disabled.  If the state changed, we need to reset.
 	 */
-	switch (features & NETIF_F_NTUPLE) {
-	case NETIF_F_NTUPLE:
+	if ((features & NETIF_F_NTUPLE) || (features & NETIF_F_HW_TC)) {
 		/* turn off ATR, enable perfect filters and reset */
 		if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
 			need_reset = true;
 
 		adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
 		adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
-		break;
-	default:
+	} else {
 		/* turn off perfect filters, enable ATR and reset */
 		if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
 			need_reset = true;
@@ -8041,23 +8540,16 @@
 		adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
 
 		/* We cannot enable ATR if SR-IOV is enabled */
-		if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
-			break;
-
-		/* We cannot enable ATR if we have 2 or more traffic classes */
-		if (netdev_get_num_tc(netdev) > 1)
-			break;
-
-		/* We cannot enable ATR if RSS is disabled */
-		if (adapter->ring_feature[RING_F_RSS].limit <= 1)
-			break;
-
-		/* A sample rate of 0 indicates ATR disabled */
-		if (!adapter->atr_sample_rate)
-			break;
-
-		adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
-		break;
+		if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED ||
+		    /* We cannot enable ATR if we have 2 or more tcs */
+		    (netdev_get_num_tc(netdev) > 1) ||
+		    /* We cannot enable ATR if RSS is disabled */
+		    (adapter->ring_feature[RING_F_RSS].limit <= 1) ||
+		    /* A sample rate of 0 indicates ATR disabled */
+		    (!adapter->atr_sample_rate))
+			; /* do nothing not supported */
+		else /* otherwise supported and set the flag */
+			adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
 	}
 
 	if (features & NETIF_F_HW_VLAN_CTAG_RX)
@@ -8155,7 +8647,10 @@
 {
 	/* guarantee we can provide a unique filter for the unicast address */
 	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) {
-		if (IXGBE_MAX_PF_MACVLANS <= netdev_uc_count(dev))
+		struct ixgbe_adapter *adapter = netdev_priv(dev);
+		u16 pool = VMDQ_P(0);
+
+		if (netdev_uc_count(dev) >= ixgbe_available_rars(adapter, pool))
 			return -ENOMEM;
 	}
 
@@ -8413,9 +8908,7 @@
 	.ndo_set_vf_trust	= ixgbe_ndo_set_vf_trust,
 	.ndo_get_vf_config	= ixgbe_ndo_get_vf_config,
 	.ndo_get_stats64	= ixgbe_get_stats64,
-#ifdef CONFIG_IXGBE_DCB
-	.ndo_setup_tc		= ixgbe_setup_tc,
-#endif
+	.ndo_setup_tc		= __ixgbe_setup_tc,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= ixgbe_netpoll,
 #endif
@@ -8784,9 +9277,10 @@
 	case ixgbe_mac_X540:
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
-		netdev->features |= NETIF_F_SCTP_CSUM;
-		netdev->hw_features |= NETIF_F_SCTP_CSUM |
-				       NETIF_F_NTUPLE;
+		netdev->features |= NETIF_F_SCTP_CRC;
+		netdev->hw_features |= NETIF_F_SCTP_CRC |
+				       NETIF_F_NTUPLE |
+				       NETIF_F_HW_TC;
 		break;
 	default:
 		break;
@@ -8801,8 +9295,7 @@
 	netdev->vlan_features |= NETIF_F_IPV6_CSUM;
 	netdev->vlan_features |= NETIF_F_SG;
 
-	netdev->hw_enc_features |= NETIF_F_SG | NETIF_F_IP_CSUM |
-				   NETIF_F_IPV6_CSUM;
+	netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 
 	netdev->priv_flags |= IFF_UNICAST_FLT;
 	netdev->priv_flags |= IFF_SUPP_NOFCS;
@@ -8811,9 +9304,7 @@
 	switch (adapter->hw.mac.type) {
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
-		netdev->hw_enc_features |= NETIF_F_RXCSUM |
-					   NETIF_F_IP_CSUM |
-					   NETIF_F_IPV6_CSUM;
+		netdev->hw_enc_features |= NETIF_F_RXCSUM;
 		break;
 	default:
 		break;
@@ -8873,7 +9364,7 @@
 		goto err_sw_init;
 	}
 
-	ixgbe_mac_set_default_filter(adapter, hw->mac.perm_addr);
+	ixgbe_mac_set_default_filter(adapter);
 
 	setup_timer(&adapter->service_timer, &ixgbe_service_timer,
 		    (unsigned long) adapter);
@@ -9220,7 +9711,7 @@
 	}
 
 	if (netif_running(netdev))
-		ixgbe_down(adapter);
+		ixgbe_close_suspend(adapter);
 
 	if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
 		pci_disable_device(pdev);
@@ -9290,10 +9781,12 @@
 	}
 
 #endif
+	rtnl_lock();
 	if (netif_running(netdev))
-		ixgbe_up(adapter);
+		ixgbe_open(netdev);
 
 	netif_device_attach(netdev);
+	rtnl_unlock();
 }
 
 static const struct pci_error_handlers ixgbe_err_handler = {
@@ -9328,6 +9821,12 @@
 	pr_info("%s - version %s\n", ixgbe_driver_string, ixgbe_driver_version);
 	pr_info("%s\n", ixgbe_copyright);
 
+	ixgbe_wq = create_singlethread_workqueue(ixgbe_driver_name);
+	if (!ixgbe_wq) {
+		pr_err("%s: Failed to create workqueue\n", ixgbe_driver_name);
+		return -ENOMEM;
+	}
+
 	ixgbe_dbg_init();
 
 	ret = pci_register_driver(&ixgbe_driver);
@@ -9359,6 +9858,10 @@
 	pci_unregister_driver(&ixgbe_driver);
 
 	ixgbe_dbg_exit();
+	if (ixgbe_wq) {
+		destroy_workqueue(ixgbe_wq);
+		ixgbe_wq = NULL;
+	}
 }
 
 #ifdef CONFIG_IXGBE_DCA
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_model.h
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_model.h
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ *
+ * Intel 10 Gigabit PCI Express Linux drive
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _IXGBE_MODEL_H_
+#define _IXGBE_MODEL_H_
+
+#include "ixgbe.h"
+#include "ixgbe_type.h"
+
+struct ixgbe_mat_field {
+	unsigned int off;
+	unsigned int mask;
+	int (*val)(struct ixgbe_fdir_filter *input,
+		   union ixgbe_atr_input *mask,
+		   u32 val, u32 m);
+	unsigned int type;
+};
+
+static inline int ixgbe_mat_prgm_sip(struct ixgbe_fdir_filter *input,
+				     union ixgbe_atr_input *mask,
+				     u32 val, u32 m)
+{
+	input->filter.formatted.src_ip[0] = val;
+	mask->formatted.src_ip[0] = m;
+	return 0;
+}
+
+static inline int ixgbe_mat_prgm_dip(struct ixgbe_fdir_filter *input,
+				     union ixgbe_atr_input *mask,
+				     u32 val, u32 m)
+{
+	input->filter.formatted.dst_ip[0] = val;
+	mask->formatted.dst_ip[0] = m;
+	return 0;
+}
+
+static struct ixgbe_mat_field ixgbe_ipv4_fields[] = {
+	{ .off = 12, .mask = -1, .val = ixgbe_mat_prgm_sip,
+	  .type = IXGBE_ATR_FLOW_TYPE_IPV4},
+	{ .off = 16, .mask = -1, .val = ixgbe_mat_prgm_dip,
+	  .type = IXGBE_ATR_FLOW_TYPE_IPV4},
+	{ .val = NULL } /* terminal node */
+};
+
+static inline int ixgbe_mat_prgm_sport(struct ixgbe_fdir_filter *input,
+				       union ixgbe_atr_input *mask,
+				       u32 val, u32 m)
+{
+	input->filter.formatted.src_port = val & 0xffff;
+	mask->formatted.src_port = m & 0xffff;
+	return 0;
+};
+
+static inline int ixgbe_mat_prgm_dport(struct ixgbe_fdir_filter *input,
+				       union ixgbe_atr_input *mask,
+				       u32 val, u32 m)
+{
+	input->filter.formatted.dst_port = val & 0xffff;
+	mask->formatted.dst_port = m & 0xffff;
+	return 0;
+};
+
+static struct ixgbe_mat_field ixgbe_tcp_fields[] = {
+	{.off = 0, .mask = 0xffff, .val = ixgbe_mat_prgm_sport,
+	 .type = IXGBE_ATR_FLOW_TYPE_TCPV4},
+	{.off = 2, .mask = 0xffff, .val = ixgbe_mat_prgm_dport,
+	 .type = IXGBE_ATR_FLOW_TYPE_TCPV4},
+	{ .val = NULL } /* terminal node */
+};
+
+struct ixgbe_nexthdr {
+	/* offset, shift, and mask of position to next header */
+	unsigned int o;
+	u32 s;
+	u32 m;
+	/* match criteria to make this jump*/
+	unsigned int off;
+	u32 val;
+	u32 mask;
+	/* location of jump to make */
+	struct ixgbe_mat_field *jump;
+};
+
+static struct ixgbe_nexthdr ixgbe_ipv4_jumps[] = {
+	{ .o = 0, .s = 6, .m = 0xf,
+	  .off = 8, .val = 0x600, .mask = 0xff00, .jump = ixgbe_tcp_fields},
+	{ .jump = NULL } /* terminal node */
+};
+#endif /* _IXGBE_MODEL_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -113,7 +113,7 @@
 					       u16 reg, u16 *val, bool lock)
 {
 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
-	int max_retry = 10;
+	int max_retry = 3;
 	int retry = 0;
 	u8 csum_byte;
 	u8 high_bits;
@@ -1764,6 +1764,8 @@
 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
 	bool nack = true;
 
+	if (hw->mac.type >= ixgbe_mac_X550)
+		max_retry = 3;
 	if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr))
 		max_retry = IXGBE_SFP_DETECT_RETRIES;
 
@@ -2393,6 +2395,9 @@
 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
 		return 0;
 
+	if (!on && ixgbe_mng_present(hw))
+		return 0;
+
 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
 				      &reg);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -70,6 +70,7 @@
 #define IXGBE_SFF_SOFT_RS_SELECT_10G		0x8
 #define IXGBE_SFF_SOFT_RS_SELECT_1G		0x0
 #define IXGBE_SFF_ADDRESSING_MODE		0x4
+#define IXGBE_SFF_DDM_IMPLEMENTED		0x40
 #define IXGBE_SFF_QSFP_DA_ACTIVE_CABLE		0x1
 #define IXGBE_SFF_QSFP_DA_PASSIVE_CABLE		0x8
 #define IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE	0x23
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2015 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -27,6 +27,7 @@
 *******************************************************************************/
 #include "ixgbe.h"
 #include <linux/ptp_classify.h>
+#include <linux/clocksource.h>
 
 /*
  * The 82599 and the X540 do not have true 64bit nanosecond scale
@@ -93,7 +94,6 @@
 
 #define IXGBE_INCVAL_SHIFT_82599 7
 #define IXGBE_INCPER_SHIFT_82599 24
-#define IXGBE_MAX_TIMEADJ_VALUE  0x7FFFFFFFFFFFFFFFULL
 
 #define IXGBE_OVERFLOW_PERIOD    (HZ * 30)
 #define IXGBE_PTP_TX_TIMEOUT     (HZ * 15)
@@ -104,8 +104,68 @@
  */
 #define IXGBE_PTP_PPS_HALF_SECOND 500000000ULL
 
+/* In contrast, the X550 controller has two registers, SYSTIMEH and SYSTIMEL
+ * which contain measurements of seconds and nanoseconds respectively. This
+ * matches the standard linux representation of time in the kernel. In addition,
+ * the X550 also has a SYSTIMER register which represents residue, or
+ * subnanosecond overflow adjustments. To control clock adjustment, the TIMINCA
+ * register is used, but it is unlike the X540 and 82599 devices. TIMINCA
+ * represents units of 2^-32 nanoseconds, and uses 31 bits for this, with the
+ * high bit representing whether the adjustent is positive or negative. Every
+ * clock cycle, the X550 will add 12.5 ns + TIMINCA which can result in a range
+ * of 12 to 13 nanoseconds adjustment. Unlike the 82599 and X540 devices, the
+ * X550's clock for purposes of SYSTIME generation is constant and not dependent
+ * on the link speed.
+ *
+ *           SYSTIMEH           SYSTIMEL        SYSTIMER
+ *       +--------------+  +--------------+  +-------------+
+ * X550  |      32      |  |      32      |  |     32      |
+ *       *--------------+  +--------------+  +-------------+
+ *       \____seconds___/   \_nanoseconds_/  \__2^-32 ns__/
+ *
+ * This results in a full 96 bits to represent the clock, with 32 bits for
+ * seconds, 32 bits for nanoseconds (largest value is 0d999999999 or just under
+ * 1 second) and an additional 32 bits to measure sub nanosecond adjustments for
+ * underflow of adjustments.
+ *
+ * The 32 bits of seconds for the X550 overflows every
+ *   2^32 / ( 365.25 * 24 * 60 * 60 ) = ~136 years.
+ *
+ * In order to adjust the clock frequency for the X550, the TIMINCA register is
+ * provided. This register represents a + or minus nearly 0.5 ns adjustment to
+ * the base frequency. It is measured in 2^-32 ns units, with the high bit being
+ * the sign bit. This register enables software to calculate frequency
+ * adjustments and apply them directly to the clock rate.
+ *
+ * The math for converting ppb into TIMINCA values is fairly straightforward.
+ *   TIMINCA value = ( Base_Frequency * ppb ) / 1000000000ULL
+ *
+ * This assumes that ppb is never high enough to create a value bigger than
+ * TIMINCA's 31 bits can store. This is ensured by the stack. Calculating this
+ * value is also simple.
+ *   Max ppb = ( Max Adjustment / Base Frequency ) / 1000000000ULL
+ *
+ * For the X550, the Max adjustment is +/- 0.5 ns, and the base frequency is
+ * 12.5 nanoseconds. This means that the Max ppb is 39999999
+ *   Note: We subtract one in order to ensure no overflow, because the TIMINCA
+ *         register can only hold slightly under 0.5 nanoseconds.
+ *
+ * Because TIMINCA is measured in 2^-32 ns units, we have to convert 12.5 ns
+ * into 2^-32 units, which is
+ *
+ *  12.5 * 2^32 = C80000000
+ *
+ * Some revisions of hardware have a faster base frequency than the registers
+ * were defined for. To fix this, we use a timecounter structure with the
+ * proper mult and shift to convert the cycles into nanoseconds of time.
+ */
+#define IXGBE_X550_BASE_PERIOD 0xC80000000ULL
+#define INCVALUE_MASK	0x7FFFFFFF
+#define ISGN		0x80000000
+#define MAX_TIMADJ	0x7FFFFFFF
+
 /**
- * ixgbe_ptp_setup_sdp
+ * ixgbe_ptp_setup_sdp_x540
  * @hw: the hardware private structure
  *
  * this function enables or disables the clock out feature on SDP0 for
@@ -116,83 +176,116 @@
  * aligns the start of the PPS signal to that value. The shift is
  * necessary because it can change based on the link speed.
  */
-static void ixgbe_ptp_setup_sdp(struct ixgbe_adapter *adapter)
+static void ixgbe_ptp_setup_sdp_x540(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
-	int shift = adapter->cc.shift;
+	int shift = adapter->hw_cc.shift;
 	u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh, rem;
 	u64 ns = 0, clock_edge = 0;
 
-	if ((adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED) &&
-	    (hw->mac.type == ixgbe_mac_X540)) {
+	/* disable the pin first */
+	IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0);
+	IXGBE_WRITE_FLUSH(hw);
 
-		/* disable the pin first */
-		IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0);
-		IXGBE_WRITE_FLUSH(hw);
+	if (!(adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED))
+		return;
 
-		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+	esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
 
-		/*
-		 * enable the SDP0 pin as output, and connected to the
-		 * native function for Timesync (ClockOut)
-		 */
-		esdp |= (IXGBE_ESDP_SDP0_DIR |
-			 IXGBE_ESDP_SDP0_NATIVE);
+	/* enable the SDP0 pin as output, and connected to the
+	 * native function for Timesync (ClockOut)
+	 */
+	esdp |= IXGBE_ESDP_SDP0_DIR |
+		IXGBE_ESDP_SDP0_NATIVE;
 
-		/*
-		 * enable the Clock Out feature on SDP0, and allow
-		 * interrupts to occur when the pin changes
-		 */
-		tsauxc = (IXGBE_TSAUXC_EN_CLK |
-			  IXGBE_TSAUXC_SYNCLK |
-			  IXGBE_TSAUXC_SDP0_INT);
-
-		/* clock period (or pulse length) */
-		clktiml = (u32)(IXGBE_PTP_PPS_HALF_SECOND << shift);
-		clktimh = (u32)((IXGBE_PTP_PPS_HALF_SECOND << shift) >> 32);
+	/* enable the Clock Out feature on SDP0, and allow
+	 * interrupts to occur when the pin changes
+	 */
+	tsauxc = IXGBE_TSAUXC_EN_CLK |
+		 IXGBE_TSAUXC_SYNCLK |
+		 IXGBE_TSAUXC_SDP0_INT;
+
+	/* clock period (or pulse length) */
+	clktiml = (u32)(IXGBE_PTP_PPS_HALF_SECOND << shift);
+	clktimh = (u32)((IXGBE_PTP_PPS_HALF_SECOND << shift) >> 32);
+
+	/* Account for the cyclecounter wrap-around value by
+	 * using the converted ns value of the current time to
+	 * check for when the next aligned second would occur.
+	 */
+	clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML);
+	clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32;
+	ns = timecounter_cyc2time(&adapter->hw_tc, clock_edge);
+
+	div_u64_rem(ns, IXGBE_PTP_PPS_HALF_SECOND, &rem);
+	clock_edge += ((IXGBE_PTP_PPS_HALF_SECOND - (u64)rem) << shift);
+
+	/* specify the initial clock start time */
+	trgttiml = (u32)clock_edge;
+	trgttimh = (u32)(clock_edge >> 32);
+
+	IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml);
+	IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh);
+	IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml);
+	IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh);
 
-		/*
-		 * Account for the cyclecounter wrap-around value by
-		 * using the converted ns value of the current time to
-		 * check for when the next aligned second would occur.
-		 */
-		clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML);
-		clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32;
-		ns = timecounter_cyc2time(&adapter->tc, clock_edge);
-
-		div_u64_rem(ns, IXGBE_PTP_PPS_HALF_SECOND, &rem);
-		clock_edge += ((IXGBE_PTP_PPS_HALF_SECOND - (u64)rem) << shift);
-
-		/* specify the initial clock start time */
-		trgttiml = (u32)clock_edge;
-		trgttimh = (u32)(clock_edge >> 32);
-
-		IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml);
-		IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh);
-		IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml);
-		IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh);
-
-		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
-		IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc);
-	} else {
-		IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0);
-	}
+	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+	IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc);
 
 	IXGBE_WRITE_FLUSH(hw);
 }
 
 /**
- * ixgbe_ptp_read - read raw cycle counter (to be used by time counter)
+ * ixgbe_ptp_read_X550 - read cycle counter value
+ * @hw_cc: cyclecounter structure
+ *
+ * This function reads SYSTIME registers. It is called by the cyclecounter
+ * structure to convert from internal representation into nanoseconds. We need
+ * this for X550 since some skews do not have expected clock frequency and
+ * result of SYSTIME is 32bits of "billions of cycles" and 32 bits of
+ * "cycles", rather than seconds and nanoseconds.
+ */
+static cycle_t ixgbe_ptp_read_X550(const struct cyclecounter *hw_cc)
+{
+	struct ixgbe_adapter *adapter =
+			container_of(hw_cc, struct ixgbe_adapter, hw_cc);
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct timespec64 ts;
+
+	/* storage is 32 bits of 'billions of cycles' and 32 bits of 'cycles'.
+	 * Some revisions of hardware run at a higher frequency and so the
+	 * cycles are not guaranteed to be nanoseconds. The timespec64 created
+	 * here is used for its math/conversions but does not necessarily
+	 * represent nominal time.
+	 *
+	 * It should be noted that this cyclecounter will overflow at a
+	 * non-bitmask field since we have to convert our billions of cycles
+	 * into an actual cycles count. This results in some possible weird
+	 * situations at high cycle counter stamps. However given that 32 bits
+	 * of "seconds" is ~138 years this isn't a problem. Even at the
+	 * increased frequency of some revisions, this is still ~103 years.
+	 * Since the SYSTIME values start at 0 and we never write them, it is
+	 * highly unlikely for the cyclecounter to overflow in practice.
+	 */
+	IXGBE_READ_REG(hw, IXGBE_SYSTIMR);
+	ts.tv_nsec = IXGBE_READ_REG(hw, IXGBE_SYSTIML);
+	ts.tv_sec = IXGBE_READ_REG(hw, IXGBE_SYSTIMH);
+
+	return (u64)timespec64_to_ns(&ts);
+}
+
+/**
+ * ixgbe_ptp_read_82599 - read raw cycle counter (to be used by time counter)
  * @cc: the cyclecounter structure
  *
  * this function reads the cyclecounter registers and is called by the
  * cyclecounter structure used to construct a ns counter from the
  * arbitrary fixed point registers
  */
-static cycle_t ixgbe_ptp_read(const struct cyclecounter *cc)
+static cycle_t ixgbe_ptp_read_82599(const struct cyclecounter *cc)
 {
 	struct ixgbe_adapter *adapter =
-		container_of(cc, struct ixgbe_adapter, cc);
+		container_of(cc, struct ixgbe_adapter, hw_cc);
 	struct ixgbe_hw *hw = &adapter->hw;
 	u64 stamp = 0;
 
@@ -203,20 +296,79 @@
 }
 
 /**
- * ixgbe_ptp_adjfreq
+ * ixgbe_ptp_convert_to_hwtstamp - convert register value to hw timestamp
+ * @adapter: private adapter structure
+ * @hwtstamp: stack timestamp structure
+ * @systim: unsigned 64bit system time value
+ *
+ * We need to convert the adapter's RX/TXSTMP registers into a hwtstamp value
+ * which can be used by the stack's ptp functions.
+ *
+ * The lock is used to protect consistency of the cyclecounter and the SYSTIME
+ * registers. However, it does not need to protect against the Rx or Tx
+ * timestamp registers, as there can't be a new timestamp until the old one is
+ * unlatched by reading.
+ *
+ * In addition to the timestamp in hardware, some controllers need a software
+ * overflow cyclecounter, and this function takes this into account as well.
+ **/
+static void ixgbe_ptp_convert_to_hwtstamp(struct ixgbe_adapter *adapter,
+					  struct skb_shared_hwtstamps *hwtstamp,
+					  u64 timestamp)
+{
+	unsigned long flags;
+	struct timespec64 systime;
+	u64 ns;
+
+	memset(hwtstamp, 0, sizeof(*hwtstamp));
+
+	switch (adapter->hw.mac.type) {
+	/* X550 and later hardware supposedly represent time using a seconds
+	 * and nanoseconds counter, instead of raw 64bits nanoseconds. We need
+	 * to convert the timestamp into cycles before it can be fed to the
+	 * cyclecounter. We need an actual cyclecounter because some revisions
+	 * of hardware run at a higher frequency and thus the counter does
+	 * not represent seconds/nanoseconds. Instead it can be thought of as
+	 * cycles and billions of cycles.
+	 */
+	case ixgbe_mac_X550:
+	case ixgbe_mac_X550EM_x:
+		/* Upper 32 bits represent billions of cycles, lower 32 bits
+		 * represent cycles. However, we use timespec64_to_ns for the
+		 * correct math even though the units haven't been corrected
+		 * yet.
+		 */
+		systime.tv_sec = timestamp >> 32;
+		systime.tv_nsec = timestamp & 0xFFFFFFFF;
+
+		timestamp = timespec64_to_ns(&systime);
+		break;
+	default:
+		break;
+	}
+
+	spin_lock_irqsave(&adapter->tmreg_lock, flags);
+	ns = timecounter_cyc2time(&adapter->hw_tc, timestamp);
+	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+	hwtstamp->hwtstamp = ns_to_ktime(ns);
+}
+
+/**
+ * ixgbe_ptp_adjfreq_82599
  * @ptp: the ptp clock structure
  * @ppb: parts per billion adjustment from base
  *
  * adjust the frequency of the ptp cycle counter by the
  * indicated ppb from the base frequency.
  */
-static int ixgbe_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+static int ixgbe_ptp_adjfreq_82599(struct ptp_clock_info *ptp, s32 ppb)
 {
 	struct ixgbe_adapter *adapter =
 		container_of(ptp, struct ixgbe_adapter, ptp_caps);
 	struct ixgbe_hw *hw = &adapter->hw;
-	u64 freq;
-	u32 diff, incval;
+	u64 freq, incval;
+	u32 diff;
 	int neg_adj = 0;
 
 	if (ppb < 0) {
@@ -235,12 +387,16 @@
 
 	switch (hw->mac.type) {
 	case ixgbe_mac_X540:
-		IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, incval);
+		if (incval > 0xFFFFFFFFULL)
+			e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n");
+		IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, (u32)incval);
 		break;
 	case ixgbe_mac_82599EB:
+		if (incval > 0x00FFFFFFULL)
+			e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n");
 		IXGBE_WRITE_REG(hw, IXGBE_TIMINCA,
 				(1 << IXGBE_INCPER_SHIFT_82599) |
-				incval);
+				((u32)incval & 0x00FFFFFFUL));
 		break;
 	default:
 		break;
@@ -250,6 +406,43 @@
 }
 
 /**
+ * ixgbe_ptp_adjfreq_X550
+ * @ptp: the ptp clock structure
+ * @ppb: parts per billion adjustment from base
+ *
+ * adjust the frequency of the SYSTIME registers by the indicated ppb from base
+ * frequency
+ */
+static int ixgbe_ptp_adjfreq_X550(struct ptp_clock_info *ptp, s32 ppb)
+{
+	struct ixgbe_adapter *adapter =
+			container_of(ptp, struct ixgbe_adapter, ptp_caps);
+	struct ixgbe_hw *hw = &adapter->hw;
+	int neg_adj = 0;
+	u64 rate = IXGBE_X550_BASE_PERIOD;
+	u32 inca;
+
+	if (ppb < 0) {
+		neg_adj = 1;
+		ppb = -ppb;
+	}
+	rate *= ppb;
+	rate = div_u64(rate, 1000000000ULL);
+
+	/* warn if rate is too large */
+	if (rate >= INCVALUE_MASK)
+		e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n");
+
+	inca = rate & INCVALUE_MASK;
+	if (neg_adj)
+		inca |= ISGN;
+
+	IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, inca);
+
+	return 0;
+}
+
+/**
  * ixgbe_ptp_adjtime
  * @ptp: the ptp clock structure
  * @delta: offset to adjust the cycle counter by
@@ -263,10 +456,11 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
-	timecounter_adjtime(&adapter->tc, delta);
+	timecounter_adjtime(&adapter->hw_tc, delta);
 	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
 
-	ixgbe_ptp_setup_sdp(adapter);
+	if (adapter->ptp_setup_sdp)
+		adapter->ptp_setup_sdp(adapter);
 
 	return 0;
 }
@@ -283,11 +477,11 @@
 {
 	struct ixgbe_adapter *adapter =
 		container_of(ptp, struct ixgbe_adapter, ptp_caps);
-	u64 ns;
 	unsigned long flags;
+	u64 ns;
 
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
-	ns = timecounter_read(&adapter->tc);
+	ns = timecounter_read(&adapter->hw_tc);
 	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
 
 	*ts = ns_to_timespec64(ns);
@@ -308,17 +502,16 @@
 {
 	struct ixgbe_adapter *adapter =
 		container_of(ptp, struct ixgbe_adapter, ptp_caps);
-	u64 ns;
 	unsigned long flags;
-
-	ns = timespec64_to_ns(ts);
+	u64 ns = timespec64_to_ns(ts);
 
 	/* reset the timecounter */
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
-	timecounter_init(&adapter->tc, &adapter->cc, ns);
+	timecounter_init(&adapter->hw_tc, &adapter->hw_cc, ns);
 	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
 
-	ixgbe_ptp_setup_sdp(adapter);
+	if (adapter->ptp_setup_sdp)
+		adapter->ptp_setup_sdp(adapter);
 	return 0;
 }
 
@@ -343,33 +536,26 @@
 	 * event when the clock SDP triggers. Clear mask when PPS is
 	 * disabled
 	 */
-	if (rq->type == PTP_CLK_REQ_PPS) {
-		switch (adapter->hw.mac.type) {
-		case ixgbe_mac_X540:
-			if (on)
-				adapter->flags2 |= IXGBE_FLAG2_PTP_PPS_ENABLED;
-			else
-				adapter->flags2 &= ~IXGBE_FLAG2_PTP_PPS_ENABLED;
-
-			ixgbe_ptp_setup_sdp(adapter);
-			return 0;
-		default:
-			break;
-		}
-	}
+	if (rq->type != PTP_CLK_REQ_PPS || !adapter->ptp_setup_sdp)
+		return -ENOTSUPP;
 
-	return -ENOTSUPP;
+	if (on)
+		adapter->flags2 |= IXGBE_FLAG2_PTP_PPS_ENABLED;
+	else
+		adapter->flags2 &= ~IXGBE_FLAG2_PTP_PPS_ENABLED;
+
+	adapter->ptp_setup_sdp(adapter);
+	return 0;
 }
 
 /**
  * ixgbe_ptp_check_pps_event
  * @adapter: the private adapter structure
- * @eicr: the interrupt cause register value
  *
  * This function is called by the interrupt routine when checking for
  * interrupts. It will check and handle a pps event.
  */
-void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr)
+void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct ptp_clock_event event;
@@ -425,7 +611,9 @@
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
+	struct ixgbe_ring *rx_ring;
 	unsigned long rx_event;
+	int n;
 
 	/* if we don't have a valid timestamp in the registers, just update the
 	 * timeout counter and exit
@@ -437,19 +625,43 @@
 
 	/* determine the most recent watchdog or rx_timestamp event */
 	rx_event = adapter->last_rx_ptp_check;
-	if (time_after(adapter->last_rx_timestamp, rx_event))
-		rx_event = adapter->last_rx_timestamp;
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = adapter->rx_ring[n];
+		if (time_after(rx_ring->last_rx_timestamp, rx_event))
+			rx_event = rx_ring->last_rx_timestamp;
+	}
 
 	/* only need to read the high RXSTMP register to clear the lock */
-	if (time_is_before_jiffies(rx_event + 5*HZ)) {
+	if (time_is_before_jiffies(rx_event + 5 * HZ)) {
 		IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
 		adapter->last_rx_ptp_check = jiffies;
 
+		adapter->rx_hwtstamp_cleared++;
 		e_warn(drv, "clearing RX Timestamp hang\n");
 	}
 }
 
 /**
+ * ixgbe_ptp_clear_tx_timestamp - utility function to clear Tx timestamp state
+ * @adapter: the private adapter structure
+ *
+ * This function should be called whenever the state related to a Tx timestamp
+ * needs to be cleared. This helps ensure that all related bits are reset for
+ * the next Tx timestamp event.
+ */
+static void ixgbe_ptp_clear_tx_timestamp(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	IXGBE_READ_REG(hw, IXGBE_TXSTMPH);
+	if (adapter->ptp_tx_skb) {
+		dev_kfree_skb_any(adapter->ptp_tx_skb);
+		adapter->ptp_tx_skb = NULL;
+	}
+	clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
+}
+
+/**
  * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
  * @adapter: the private adapter struct
  *
@@ -461,23 +673,15 @@
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct skb_shared_hwtstamps shhwtstamps;
-	u64 regval = 0, ns;
-	unsigned long flags;
+	u64 regval = 0;
 
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL);
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32;
 
-	spin_lock_irqsave(&adapter->tmreg_lock, flags);
-	ns = timecounter_cyc2time(&adapter->tc, regval);
-	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
-
-	memset(&shhwtstamps, 0, sizeof(shhwtstamps));
-	shhwtstamps.hwtstamp = ns_to_ktime(ns);
+	ixgbe_ptp_convert_to_hwtstamp(adapter, &shhwtstamps, regval);
 	skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
 
-	dev_kfree_skb_any(adapter->ptp_tx_skb);
-	adapter->ptp_tx_skb = NULL;
-	clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
+	ixgbe_ptp_clear_tx_timestamp(adapter);
 }
 
 /**
@@ -497,38 +701,85 @@
 					      IXGBE_PTP_TX_TIMEOUT);
 	u32 tsynctxctl;
 
-	if (timeout) {
-		dev_kfree_skb_any(adapter->ptp_tx_skb);
-		adapter->ptp_tx_skb = NULL;
-		clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
-		e_warn(drv, "clearing Tx Timestamp hang\n");
+	/* we have to have a valid skb to poll for a timestamp */
+	if (!adapter->ptp_tx_skb) {
+		ixgbe_ptp_clear_tx_timestamp(adapter);
 		return;
 	}
 
+	/* stop polling once we have a valid timestamp */
 	tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
-	if (tsynctxctl & IXGBE_TSYNCTXCTL_VALID)
+	if (tsynctxctl & IXGBE_TSYNCTXCTL_VALID) {
 		ixgbe_ptp_tx_hwtstamp(adapter);
-	else
+		return;
+	}
+
+	if (timeout) {
+		ixgbe_ptp_clear_tx_timestamp(adapter);
+		adapter->tx_hwtstamp_timeouts++;
+		e_warn(drv, "clearing Tx Timestamp hang\n");
+	} else {
 		/* reschedule to keep checking if it's not available yet */
 		schedule_work(&adapter->ptp_tx_work);
+	}
 }
 
 /**
- * ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
- * @adapter: pointer to adapter struct
+ * ixgbe_ptp_rx_pktstamp - utility function to get RX time stamp from buffer
+ * @q_vector: structure containing interrupt and ring information
+ * @skb: the packet
+ *
+ * This function will be called by the Rx routine of the timestamp for this
+ * packet is stored in the buffer. The value is stored in little endian format
+ * starting at the end of the packet data.
+ */
+void ixgbe_ptp_rx_pktstamp(struct ixgbe_q_vector *q_vector,
+			   struct sk_buff *skb)
+{
+	__le64 regval;
+
+	/* copy the bits out of the skb, and then trim the skb length */
+	skb_copy_bits(skb, skb->len - IXGBE_TS_HDR_LEN, &regval,
+		      IXGBE_TS_HDR_LEN);
+	__pskb_trim(skb, skb->len - IXGBE_TS_HDR_LEN);
+
+	/* The timestamp is recorded in little endian format, and is stored at
+	 * the end of the packet.
+	 *
+	 * DWORD: N              N + 1      N + 2
+	 * Field: End of Packet  SYSTIMH    SYSTIML
+	 */
+	ixgbe_ptp_convert_to_hwtstamp(q_vector->adapter, skb_hwtstamps(skb),
+				      le64_to_cpu(regval));
+}
+
+/**
+ * ixgbe_ptp_rx_rgtstamp - utility function which checks for RX time stamp
+ * @q_vector: structure containing interrupt and ring information
  * @skb: particular skb to send timestamp with
  *
  * if the timestamp is valid, we convert it into the timecounter ns
  * value, then store that result into the shhwtstamps structure which
  * is passed up the network stack
  */
-void ixgbe_ptp_rx_hwtstamp(struct ixgbe_adapter *adapter, struct sk_buff *skb)
+void ixgbe_ptp_rx_rgtstamp(struct ixgbe_q_vector *q_vector,
+			   struct sk_buff *skb)
 {
-	struct ixgbe_hw *hw = &adapter->hw;
-	struct skb_shared_hwtstamps *shhwtstamps;
-	u64 regval = 0, ns;
+	struct ixgbe_adapter *adapter;
+	struct ixgbe_hw *hw;
+	u64 regval = 0;
 	u32 tsyncrxctl;
-	unsigned long flags;
+
+	/* we cannot process timestamps on a ring without a q_vector */
+	if (!q_vector || !q_vector->adapter)
+		return;
+
+	adapter = q_vector->adapter;
+	hw = &adapter->hw;
+
+	/* Read the tsyncrxctl register afterwards in order to prevent taking an
+	 * I/O hit on every packet.
+	 */
 
 	tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
 	if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID))
@@ -537,17 +788,7 @@
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPL);
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPH) << 32;
 
-	spin_lock_irqsave(&adapter->tmreg_lock, flags);
-	ns = timecounter_cyc2time(&adapter->tc, regval);
-	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
-
-	shhwtstamps = skb_hwtstamps(skb);
-	shhwtstamps->hwtstamp = ns_to_ktime(ns);
-
-	/* Update the last_rx_timestamp timer in order to enable watchdog check
-	 * for error case of latched timestamp on a dropped packet.
-	 */
-	adapter->last_rx_timestamp = jiffies;
+	ixgbe_ptp_convert_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
 }
 
 int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
@@ -610,14 +851,20 @@
 	case HWTSTAMP_FILTER_NONE:
 		tsync_rx_ctl = 0;
 		tsync_rx_mtrl = 0;
+		adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				    IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
 		break;
 	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
 		tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1;
 		tsync_rx_mtrl |= IXGBE_RXMTRL_V1_SYNC_MSG;
+		adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				    IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
 		break;
 	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
 		tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1;
 		tsync_rx_mtrl |= IXGBE_RXMTRL_V1_DELAY_REQ_MSG;
+		adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				    IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
 		break;
 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
@@ -631,9 +878,21 @@
 		tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_EVENT_V2;
 		is_l2 = true;
 		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+		adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				    IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
 		break;
 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
 	case HWTSTAMP_FILTER_ALL:
+		/* The X550 controller is capable of timestamping all packets,
+		 * which allows it to accept any filter.
+		 */
+		if (hw->mac.type >= ixgbe_mac_X550) {
+			tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_ALL;
+			config->rx_filter = HWTSTAMP_FILTER_ALL;
+			adapter->flags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED;
+			break;
+		}
+		/* fall through */
 	default:
 		/*
 		 * register RXMTRL must be set in order to do V1 packets,
@@ -641,16 +900,46 @@
 		 * Delay_Req messages and hardware does not support
 		 * timestamping all packets => return error
 		 */
+		adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				    IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
 		config->rx_filter = HWTSTAMP_FILTER_NONE;
 		return -ERANGE;
 	}
 
 	if (hw->mac.type == ixgbe_mac_82598EB) {
+		adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				    IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
 		if (tsync_rx_ctl | tsync_tx_ctl)
 			return -ERANGE;
 		return 0;
 	}
 
+	/* Per-packet timestamping only works if the filter is set to all
+	 * packets. Since this is desired, always timestamp all packets as long
+	 * as any Rx filter was configured.
+	 */
+	switch (hw->mac.type) {
+	case ixgbe_mac_X550:
+	case ixgbe_mac_X550EM_x:
+		/* enable timestamping all packets only if at least some
+		 * packets were requested. Otherwise, play nice and disable
+		 * timestamping
+		 */
+		if (config->rx_filter == HWTSTAMP_FILTER_NONE)
+			break;
+
+		tsync_rx_ctl = IXGBE_TSYNCRXCTL_ENABLED |
+			       IXGBE_TSYNCRXCTL_TYPE_ALL |
+			       IXGBE_TSYNCRXCTL_TSIP_UT_EN;
+		config->rx_filter = HWTSTAMP_FILTER_ALL;
+		adapter->flags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED;
+		adapter->flags &= ~IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER;
+		is_l2 = true;
+		break;
+	default:
+		break;
+	}
+
 	/* define ethertype filter for timestamping L2 packets */
 	if (is_l2)
 		IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588),
@@ -678,8 +967,8 @@
 	IXGBE_WRITE_FLUSH(hw);
 
 	/* clear TX/RX time stamp registers, just to be sure */
-	regval = IXGBE_READ_REG(hw, IXGBE_TXSTMPH);
-	regval = IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
+	ixgbe_ptp_clear_tx_timestamp(adapter);
+	IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
 
 	return 0;
 }
@@ -712,23 +1001,9 @@
 		-EFAULT : 0;
 }
 
-/**
- * ixgbe_ptp_start_cyclecounter - create the cycle counter from hw
- * @adapter: pointer to the adapter structure
- *
- * This function should be called to set the proper values for the TIMINCA
- * register and tell the cyclecounter structure what the tick rate of SYSTIME
- * is. It does not directly modify SYSTIME registers or the timecounter
- * structure. It should be called whenever a new TIMINCA value is necessary,
- * such as during initialization or when the link speed changes.
- */
-void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
+static void ixgbe_ptp_link_speed_adjust(struct ixgbe_adapter *adapter,
+					u32 *shift, u32 *incval)
 {
-	struct ixgbe_hw *hw = &adapter->hw;
-	u32 incval = 0;
-	u32 shift = 0;
-	unsigned long flags;
-
 	/**
 	 * Scale the NIC cycle counter by a large factor so that
 	 * relatively small corrections to the frequency can be added
@@ -745,36 +1020,98 @@
 	 */
 	switch (adapter->link_speed) {
 	case IXGBE_LINK_SPEED_100_FULL:
-		incval = IXGBE_INCVAL_100;
-		shift = IXGBE_INCVAL_SHIFT_100;
+		*shift = IXGBE_INCVAL_SHIFT_100;
+		*incval = IXGBE_INCVAL_100;
 		break;
 	case IXGBE_LINK_SPEED_1GB_FULL:
-		incval = IXGBE_INCVAL_1GB;
-		shift = IXGBE_INCVAL_SHIFT_1GB;
+		*shift = IXGBE_INCVAL_SHIFT_1GB;
+		*incval = IXGBE_INCVAL_1GB;
 		break;
 	case IXGBE_LINK_SPEED_10GB_FULL:
 	default:
-		incval = IXGBE_INCVAL_10GB;
-		shift = IXGBE_INCVAL_SHIFT_10GB;
+		*shift = IXGBE_INCVAL_SHIFT_10GB;
+		*incval = IXGBE_INCVAL_10GB;
 		break;
 	}
+}
 
-	/**
-	 * Modify the calculated values to fit within the correct
-	 * number of bits specified by the hardware. The 82599 doesn't
-	 * have the same space as the X540, so bitshift the calculated
-	 * values to fit.
+/**
+ * ixgbe_ptp_start_cyclecounter - create the cycle counter from hw
+ * @adapter: pointer to the adapter structure
+ *
+ * This function should be called to set the proper values for the TIMINCA
+ * register and tell the cyclecounter structure what the tick rate of SYSTIME
+ * is. It does not directly modify SYSTIME registers or the timecounter
+ * structure. It should be called whenever a new TIMINCA value is necessary,
+ * such as during initialization or when the link speed changes.
+ */
+void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct cyclecounter cc;
+	unsigned long flags;
+	u32 incval = 0;
+	u32 tsauxc = 0;
+	u32 fuse0 = 0;
+
+	/* For some of the boards below this mask is technically incorrect.
+	 * The timestamp mask overflows at approximately 61bits. However the
+	 * particular hardware does not overflow on an even bitmask value.
+	 * Instead, it overflows due to conversion of upper 32bits billions of
+	 * cycles. Timecounters are not really intended for this purpose so
+	 * they do not properly function if the overflow point isn't 2^N-1.
+	 * However, the actual SYSTIME values in question take ~138 years to
+	 * overflow. In practice this means they won't actually overflow. A
+	 * proper fix to this problem would require modification of the
+	 * timecounter delta calculations.
 	 */
+	cc.mask = CLOCKSOURCE_MASK(64);
+	cc.mult = 1;
+	cc.shift = 0;
+
 	switch (hw->mac.type) {
+	case ixgbe_mac_X550EM_x:
+		/* SYSTIME assumes X550EM_x board frequency is 300Mhz, and is
+		 * designed to represent seconds and nanoseconds when this is
+		 * the case. However, some revisions of hardware have a 400Mhz
+		 * clock and we have to compensate for this frequency
+		 * variation using corrected mult and shift values.
+		 */
+		fuse0 = IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0));
+		if (!(fuse0 & IXGBE_FUSES0_300MHZ)) {
+			cc.mult = 3;
+			cc.shift = 2;
+		}
+		/* fallthrough */
+	case ixgbe_mac_X550:
+		cc.read = ixgbe_ptp_read_X550;
+
+		/* enable SYSTIME counter */
+		IXGBE_WRITE_REG(hw, IXGBE_SYSTIMR, 0);
+		IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0);
+		IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0);
+		tsauxc = IXGBE_READ_REG(hw, IXGBE_TSAUXC);
+		IXGBE_WRITE_REG(hw, IXGBE_TSAUXC,
+				tsauxc & ~IXGBE_TSAUXC_DISABLE_SYSTIME);
+		IXGBE_WRITE_REG(hw, IXGBE_TSIM, IXGBE_TSIM_TXTS);
+		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_TIMESYNC);
+
+		IXGBE_WRITE_FLUSH(hw);
+		break;
 	case ixgbe_mac_X540:
+		cc.read = ixgbe_ptp_read_82599;
+
+		ixgbe_ptp_link_speed_adjust(adapter, &cc.shift, &incval);
 		IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, incval);
 		break;
 	case ixgbe_mac_82599EB:
+		cc.read = ixgbe_ptp_read_82599;
+
+		ixgbe_ptp_link_speed_adjust(adapter, &cc.shift, &incval);
 		incval >>= IXGBE_INCVAL_SHIFT_82599;
-		shift -= IXGBE_INCVAL_SHIFT_82599;
+		cc.shift -= IXGBE_INCVAL_SHIFT_82599;
 		IXGBE_WRITE_REG(hw, IXGBE_TIMINCA,
-				(1 << IXGBE_INCPER_SHIFT_82599) |
-				incval);
+				(1 << IXGBE_INCPER_SHIFT_82599) | incval);
 		break;
 	default:
 		/* other devices aren't supported */
@@ -787,13 +1124,7 @@
 
 	/* need lock to prevent incorrect read while modifying cyclecounter */
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
-
-	memset(&adapter->cc, 0, sizeof(adapter->cc));
-	adapter->cc.read = ixgbe_ptp_read;
-	adapter->cc.mask = CYCLECOUNTER_MASK(64);
-	adapter->cc.shift = shift;
-	adapter->cc.mult = 1;
-
+	memcpy(&adapter->hw_cc, &cc, sizeof(adapter->hw_cc));
 	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
 }
 
@@ -814,29 +1145,27 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	unsigned long flags;
 
-	/* set SYSTIME registers to 0 just in case */
-	IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0x00000000);
-	IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000);
-	IXGBE_WRITE_FLUSH(hw);
-
 	/* reset the hardware timestamping mode */
 	ixgbe_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
 
+	/* 82598 does not support PTP */
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		return;
+
 	ixgbe_ptp_start_cyclecounter(adapter);
 
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
-
-	/* reset the ns time counter */
-	timecounter_init(&adapter->tc, &adapter->cc,
+	timecounter_init(&adapter->hw_tc, &adapter->hw_cc,
 			 ktime_to_ns(ktime_get_real()));
-
 	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
 
-	/*
-	 * Now that the shift has been calculated and the systime
+	adapter->last_overflow_check = jiffies;
+
+	/* Now that the shift has been calculated and the systime
 	 * registers reset, (re-)enable the Clock out feature
 	 */
-	ixgbe_ptp_setup_sdp(adapter);
+	if (adapter->ptp_setup_sdp)
+		adapter->ptp_setup_sdp(adapter);
 }
 
 /**
@@ -845,11 +1174,11 @@
  *
  * This function performs setup of the user entry point function table and
  * initializes the PTP clock device, which is used to access the clock-like
- * features of the PTP core. It will be called by ixgbe_ptp_init, only if
- * there isn't already a clock device (such as after a suspend/resume cycle,
- * where the clock device wasn't destroyed).
+ * features of the PTP core. It will be called by ixgbe_ptp_init, and may
+ * reuse a previously initialized clock (such as during a suspend/resume
+ * cycle).
  */
-static int ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter)
+static long ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
 	long err;
@@ -869,11 +1198,12 @@
 		adapter->ptp_caps.n_ext_ts = 0;
 		adapter->ptp_caps.n_per_out = 0;
 		adapter->ptp_caps.pps = 1;
-		adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq;
+		adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_82599;
 		adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
 		adapter->ptp_caps.gettime64 = ixgbe_ptp_gettime;
 		adapter->ptp_caps.settime64 = ixgbe_ptp_settime;
 		adapter->ptp_caps.enable = ixgbe_ptp_feature_enable;
+		adapter->ptp_setup_sdp = ixgbe_ptp_setup_sdp_x540;
 		break;
 	case ixgbe_mac_82599EB:
 		snprintf(adapter->ptp_caps.name,
@@ -885,14 +1215,31 @@
 		adapter->ptp_caps.n_ext_ts = 0;
 		adapter->ptp_caps.n_per_out = 0;
 		adapter->ptp_caps.pps = 0;
-		adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq;
+		adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_82599;
+		adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
+		adapter->ptp_caps.gettime64 = ixgbe_ptp_gettime;
+		adapter->ptp_caps.settime64 = ixgbe_ptp_settime;
+		adapter->ptp_caps.enable = ixgbe_ptp_feature_enable;
+		break;
+	case ixgbe_mac_X550:
+	case ixgbe_mac_X550EM_x:
+		snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name);
+		adapter->ptp_caps.owner = THIS_MODULE;
+		adapter->ptp_caps.max_adj = 30000000;
+		adapter->ptp_caps.n_alarm = 0;
+		adapter->ptp_caps.n_ext_ts = 0;
+		adapter->ptp_caps.n_per_out = 0;
+		adapter->ptp_caps.pps = 0;
+		adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_X550;
 		adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
 		adapter->ptp_caps.gettime64 = ixgbe_ptp_gettime;
 		adapter->ptp_caps.settime64 = ixgbe_ptp_settime;
 		adapter->ptp_caps.enable = ixgbe_ptp_feature_enable;
+		adapter->ptp_setup_sdp = NULL;
 		break;
 	default:
 		adapter->ptp_clock = NULL;
+		adapter->ptp_setup_sdp = NULL;
 		return -EOPNOTSUPP;
 	}
 
@@ -961,18 +1308,13 @@
 	if (!test_and_clear_bit(__IXGBE_PTP_RUNNING, &adapter->state))
 		return;
 
-	/* since this might be called in suspend, we don't clear the state,
-	 * but simply reset the auxiliary PPS signal control register
-	 */
-	IXGBE_WRITE_REG(&adapter->hw, IXGBE_TSAUXC, 0x0);
+	adapter->flags2 &= ~IXGBE_FLAG2_PTP_PPS_ENABLED;
+	if (adapter->ptp_setup_sdp)
+		adapter->ptp_setup_sdp(adapter);
 
 	/* ensure that we cancel any pending PTP Tx work item in progress */
 	cancel_work_sync(&adapter->ptp_tx_work);
-	if (adapter->ptp_tx_skb) {
-		dev_kfree_skb_any(adapter->ptp_tx_skb);
-		adapter->ptp_tx_skb = NULL;
-		clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
-	}
+	ixgbe_ptp_clear_tx_timestamp(adapter);
 }
 
 /**
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2014 Intel Corporation.
+  Copyright(c) 1999 - 2015 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -130,6 +130,38 @@
 	return -ENOMEM;
 }
 
+/**
+ * ixgbe_get_vfs - Find and take references to all vf devices
+ * @adapter: Pointer to adapter struct
+ */
+static void ixgbe_get_vfs(struct ixgbe_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	u16 vendor = pdev->vendor;
+	struct pci_dev *vfdev;
+	int vf = 0;
+	u16 vf_id;
+	int pos;
+
+	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+	if (!pos)
+		return;
+	pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &vf_id);
+
+	vfdev = pci_get_device(vendor, vf_id, NULL);
+	for (; vfdev; vfdev = pci_get_device(vendor, vf_id, vfdev)) {
+		if (!vfdev->is_virtfn)
+			continue;
+		if (vfdev->physfn != pdev)
+			continue;
+		if (vf >= adapter->num_vfs)
+			continue;
+		pci_dev_get(vfdev);
+		adapter->vfinfo[vf].vfdev = vfdev;
+		++vf;
+	}
+}
+
 /* Note this function is called when the user wants to enable SR-IOV
  * VFs using the now deprecated module parameter
  */
@@ -170,8 +202,10 @@
 		}
 	}
 
-	if (!__ixgbe_enable_sriov(adapter))
+	if (!__ixgbe_enable_sriov(adapter)) {
+		ixgbe_get_vfs(adapter);
 		return;
+	}
 
 	/* If we have gotten to this point then there is no memory available
 	 * to manage the VF devices - print message and bail.
@@ -184,6 +218,7 @@
 #endif /* #ifdef CONFIG_PCI_IOV */
 int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 {
+	unsigned int num_vfs = adapter->num_vfs, vf;
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 gpie;
 	u32 vmdctl;
@@ -192,6 +227,16 @@
 	/* set num VFs to 0 to prevent access to vfinfo */
 	adapter->num_vfs = 0;
 
+	/* put the reference to all of the vf devices */
+	for (vf = 0; vf < num_vfs; ++vf) {
+		struct pci_dev *vfdev = adapter->vfinfo[vf].vfdev;
+
+		if (!vfdev)
+			continue;
+		adapter->vfinfo[vf].vfdev = NULL;
+		pci_dev_put(vfdev);
+	}
+
 	/* free VF control structures */
 	kfree(adapter->vfinfo);
 	adapter->vfinfo = NULL;
@@ -289,6 +334,7 @@
 		e_dev_warn("Failed to enable PCI sriov: %d\n", err);
 		return err;
 	}
+	ixgbe_get_vfs(adapter);
 	ixgbe_sriov_reinit(adapter);
 
 	return num_vfs;
@@ -406,19 +452,46 @@
 static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
 			     u32 vf)
 {
-	/* VLAN 0 is a special case, don't allow it to be removed */
-	if (!vid && !add)
-		return 0;
+	struct ixgbe_hw *hw = &adapter->hw;
+	int err;
+
+	/* If VLAN overlaps with one the PF is currently monitoring make
+	 * sure that we are able to allocate a VLVF entry.  This may be
+	 * redundant but it guarantees PF will maintain visibility to
+	 * the VLAN.
+	 */
+	if (add && test_bit(vid, adapter->active_vlans)) {
+		err = hw->mac.ops.set_vfta(hw, vid, VMDQ_P(0), true, false);
+		if (err)
+			return err;
+	}
+
+	err = hw->mac.ops.set_vfta(hw, vid, vf, !!add, false);
 
-	return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add);
+	if (add && !err)
+		return err;
+
+	/* If we failed to add the VF VLAN or we are removing the VF VLAN
+	 * we may need to drop the PF pool bit in order to allow us to free
+	 * up the VLVF resources.
+	 */
+	if (test_bit(vid, adapter->active_vlans) ||
+	    (adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC))
+		ixgbe_update_pf_promisc_vlvf(adapter, vid);
+
+	return err;
 }
 
-static s32 ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
+static int ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 max_frame, u32 vf)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
-	int max_frame = msgbuf[1];
 	u32 max_frs;
 
+	if (max_frame < ETH_MIN_MTU || max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE) {
+		e_err(drv, "VF max_frame %d out of range\n", max_frame);
+		return -EINVAL;
+	}
+
 	/*
 	 * For 82599EB we have to keep all PFs and VFs operating with
 	 * the same max_frame value in order to avoid sending an oversize
@@ -478,12 +551,6 @@
 		}
 	}
 
-	/* MTU < 68 is an error and causes problems on some kernels */
-	if (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE) {
-		e_err(drv, "VF max_frame %d out of range\n", max_frame);
-		return -EINVAL;
-	}
-
 	/* pull current max frame size from hardware */
 	max_frs = IXGBE_READ_REG(hw, IXGBE_MAXFRS);
 	max_frs &= IXGBE_MHADD_MFS_MASK;
@@ -516,13 +583,75 @@
 
 	IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), 0);
 }
+
+static void ixgbe_clear_vf_vlans(struct ixgbe_adapter *adapter, u32 vf)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 i;
+
+	/* post increment loop, covers VLVF_ENTRIES - 1 to 0 */
+	for (i = IXGBE_VLVF_ENTRIES; i--;) {
+		u32 bits[2], vlvfb, vid, vfta, vlvf;
+		u32 word = i * 2 + vf / 32;
+		u32 mask = 1 << (vf % 32);
+
+		vlvfb = IXGBE_READ_REG(hw, IXGBE_VLVFB(word));
+
+		/* if our bit isn't set we can skip it */
+		if (!(vlvfb & mask))
+			continue;
+
+		/* clear our bit from vlvfb */
+		vlvfb ^= mask;
+
+		/* create 64b mask to chedk to see if we should clear VLVF */
+		bits[word % 2] = vlvfb;
+		bits[~word % 2] = IXGBE_READ_REG(hw, IXGBE_VLVFB(word ^ 1));
+
+		/* if promisc is enabled, PF will be present, leave VFTA */
+		if (adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC) {
+			bits[VMDQ_P(0) / 32] &= ~(1 << (VMDQ_P(0) % 32));
+
+			if (bits[0] || bits[1])
+				goto update_vlvfb;
+			goto update_vlvf;
+		}
+
+		/* if other pools are present, just remove ourselves */
+		if (bits[0] || bits[1])
+			goto update_vlvfb;
+
+		/* if we cannot determine VLAN just remove ourselves */
+		vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(i));
+		if (!vlvf)
+			goto update_vlvfb;
+
+		vid = vlvf & VLAN_VID_MASK;
+		mask = 1 << (vid % 32);
+
+		/* clear bit from VFTA */
+		vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(vid / 32));
+		if (vfta & mask)
+			IXGBE_WRITE_REG(hw, IXGBE_VFTA(vid / 32), vfta ^ mask);
+update_vlvf:
+		/* clear POOL selection enable */
+		IXGBE_WRITE_REG(hw, IXGBE_VLVF(i), 0);
+update_vlvfb:
+		/* clear pool bits */
+		IXGBE_WRITE_REG(hw, IXGBE_VLVFB(word), vlvfb);
+	}
+}
+
 static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
 	u8 num_tcs = netdev_get_num_tc(adapter->netdev);
 
-	/* add PF assigned VLAN or VLAN 0 */
+	/* remove VLAN filters beloning to this VF */
+	ixgbe_clear_vf_vlans(adapter, vf);
+
+	/* add back PF assigned VLAN or VLAN 0 */
 	ixgbe_set_vf_vlan(adapter, true, vfinfo->pf_vlan, vf);
 
 	/* reset offloads to defaults */
@@ -768,40 +897,14 @@
 	return ixgbe_set_vf_mac(adapter, vf, new_mac) < 0;
 }
 
-static int ixgbe_find_vlvf_entry(struct ixgbe_hw *hw, u32 vlan)
-{
-	u32 vlvf;
-	s32 regindex;
-
-	/* short cut the special case */
-	if (vlan == 0)
-		return 0;
-
-	/* Search for the vlan id in the VLVF entries */
-	for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) {
-		vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex));
-		if ((vlvf & VLAN_VID_MASK) == vlan)
-			break;
-	}
-
-	/* Return a negative value if not found */
-	if (regindex >= IXGBE_VLVF_ENTRIES)
-		regindex = -1;
-
-	return regindex;
-}
-
 static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
 				 u32 *msgbuf, u32 vf)
 {
+	u32 add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
+	u32 vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
-	int add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
-	int vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
 	int err;
-	s32 reg_ndx;
-	u32 vlvf;
-	u32 bits;
-	u8 tcs = netdev_get_num_tc(adapter->netdev);
 
 	if (adapter->vfinfo[vf].pf_vlan || tcs) {
 		e_warn(drv,
@@ -811,54 +914,23 @@
 		return -1;
 	}
 
-	if (add)
-		adapter->vfinfo[vf].vlan_count++;
-	else if (adapter->vfinfo[vf].vlan_count)
-		adapter->vfinfo[vf].vlan_count--;
-
-	/* in case of promiscuous mode any VLAN filter set for a VF must
-	 * also have the PF pool added to it.
-	 */
-	if (add && adapter->netdev->flags & IFF_PROMISC)
-		err = ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
+	/* VLAN 0 is a special case, don't allow it to be removed */
+	if (!vid && !add)
+		return 0;
 
 	err = ixgbe_set_vf_vlan(adapter, add, vid, vf);
-	if (!err && adapter->vfinfo[vf].spoofchk_enabled)
-		hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
+	if (err)
+		return err;
 
-	/* Go through all the checks to see if the VLAN filter should
-	 * be wiped completely.
-	 */
-	if (!add && adapter->netdev->flags & IFF_PROMISC) {
-		reg_ndx = ixgbe_find_vlvf_entry(hw, vid);
-		if (reg_ndx < 0)
-			return err;
-		vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(reg_ndx));
-		/* See if any other pools are set for this VLAN filter
-		 * entry other than the PF.
-		 */
-		if (VMDQ_P(0) < 32) {
-			bits = IXGBE_READ_REG(hw, IXGBE_VLVFB(reg_ndx * 2));
-			bits &= ~(1 << VMDQ_P(0));
-			bits |= IXGBE_READ_REG(hw,
-					       IXGBE_VLVFB(reg_ndx * 2) + 1);
-		} else {
-			bits = IXGBE_READ_REG(hw,
-					      IXGBE_VLVFB(reg_ndx * 2) + 1);
-			bits &= ~(1 << (VMDQ_P(0) - 32));
-			bits |= IXGBE_READ_REG(hw, IXGBE_VLVFB(reg_ndx * 2));
-		}
+	if (adapter->vfinfo[vf].spoofchk_enabled)
+		hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
 
-		/* If the filter was removed then ensure PF pool bit
-		 * is cleared if the PF only added itself to the pool
-		 * because the PF is in promiscuous mode.
-		 */
-		if ((vlvf & VLAN_VID_MASK) == vid &&
-		    !test_bit(vid, adapter->active_vlans) && !bits)
-			ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
-	}
+	if (add)
+		adapter->vfinfo[vf].vlan_count++;
+	else if (adapter->vfinfo[vf].vlan_count)
+		adapter->vfinfo[vf].vlan_count--;
 
-	return err;
+	return 0;
 }
 
 static int ixgbe_set_vf_macvlan_msg(struct ixgbe_adapter *adapter,
@@ -1105,7 +1177,7 @@
 		retval = ixgbe_set_vf_vlan_msg(adapter, msgbuf, vf);
 		break;
 	case IXGBE_VF_SET_LPE:
-		retval = ixgbe_set_vf_lpe(adapter, msgbuf, vf);
+		retval = ixgbe_set_vf_lpe(adapter, msgbuf[1], vf);
 		break;
 	case IXGBE_VF_SET_MACVLAN:
 		retval = ixgbe_set_vf_macvlan_msg(adapter, msgbuf, vf);
@@ -1239,6 +1311,9 @@
 	if (err)
 		goto out;
 
+	/* Revoke tagless access via VLAN 0 */
+	ixgbe_set_vf_vlan(adapter, false, 0, vf);
+
 	ixgbe_set_vmvir(adapter, vlan, qos, vf);
 	ixgbe_set_vmolr(hw, vf, false);
 	if (adapter->vfinfo[vf].spoofchk_enabled)
@@ -1272,6 +1347,8 @@
 
 	err = ixgbe_set_vf_vlan(adapter, false,
 				adapter->vfinfo[vf].pf_vlan, vf);
+	/* Restore tagless access via VLAN 0 */
+	ixgbe_set_vf_vlan(adapter, true, 0, vf);
 	ixgbe_clear_vmvir(adapter, vf);
 	ixgbe_set_vmolr(hw, vf, true);
 	hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -1020,6 +1020,7 @@
 #define IXGBE_TXSTMPH    0x08C08 /* Tx timestamp value High - RO */
 #define IXGBE_SYSTIML    0x08C0C /* System time register Low - RO */
 #define IXGBE_SYSTIMH    0x08C10 /* System time register High - RO */
+#define IXGBE_SYSTIMR    0x08C58 /* System time register Residue - RO */
 #define IXGBE_TIMINCA    0x08C14 /* Increment attributes register - RW */
 #define IXGBE_TIMADJL    0x08C18 /* Time Adjustment Offset register Low - RW */
 #define IXGBE_TIMADJH    0x08C1C /* Time Adjustment Offset register High - RW */
@@ -1036,6 +1037,7 @@
 #define IXGBE_AUXSTMPH0  0x08C40 /* Auxiliary Time Stamp 0 register High - RO */
 #define IXGBE_AUXSTMPL1  0x08C44 /* Auxiliary Time Stamp 1 register Low - RO */
 #define IXGBE_AUXSTMPH1  0x08C48 /* Auxiliary Time Stamp 1 register High - RO */
+#define IXGBE_TSIM       0x08C68 /* TimeSync Interrupt Mask Register - RW */
 
 /* Diagnostic Registers */
 #define IXGBE_RDSTATCTL   0x02C20
@@ -1345,7 +1347,10 @@
 #define IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK	0xFF01 /* int chip-wide mask */
 #define IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG	0xFC01 /* int chip-wide mask */
 #define IXGBE_MDIO_GLOBAL_ALARM_1		0xCC00 /* Global alarm 1 */
+#define IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT	0x0010 /* device fault */
 #define IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL	0x4000 /* high temp failure */
+#define IXGBE_MDIO_GLOBAL_FAULT_MSG		0xC850 /* global fault msg */
+#define IXGBE_MDIO_GLOBAL_FAULT_MSG_HI_TMP	0x8007 /* high temp failure */
 #define IXGBE_MDIO_GLOBAL_INT_MASK		0xD400 /* Global int mask */
 /* autoneg vendor alarm int enable */
 #define IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN	0x1000
@@ -1353,6 +1358,7 @@
 #define IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN	0x1 /* vendor alarm int enable */
 #define IXGBE_MDIO_GLOBAL_STD_ALM2_INT		0x200 /* vendor alarm2 int mask */
 #define IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN	0x4000 /* int high temp enable */
+#define IXGBE_MDIO_GLOBAL_INT_DEV_FAULT_EN	0x0010 /*int dev fault enable */
 
 #define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR	0xC30A /* PHY_XS SDA/SCL Addr Reg */
 #define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA	0xC30B /* PHY_XS SDA/SCL Data Reg */
@@ -2209,6 +2215,7 @@
 #define IXGBE_TSAUXC_EN_CLK   0x00000004
 #define IXGBE_TSAUXC_SYNCLK   0x00000008
 #define IXGBE_TSAUXC_SDP0_INT 0x00000040
+#define IXGBE_TSAUXC_DISABLE_SYSTIME	0x80000000
 
 #define IXGBE_TSYNCTXCTL_VALID		0x00000001 /* Tx timestamp valid */
 #define IXGBE_TSYNCTXCTL_ENABLED	0x00000010 /* Tx timestamping enabled */
@@ -2218,8 +2225,12 @@
 #define IXGBE_TSYNCRXCTL_TYPE_L2_V2	0x00
 #define IXGBE_TSYNCRXCTL_TYPE_L4_V1	0x02
 #define IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2	0x04
+#define IXGBE_TSYNCRXCTL_TYPE_ALL	0x08
 #define IXGBE_TSYNCRXCTL_TYPE_EVENT_V2	0x0A
 #define IXGBE_TSYNCRXCTL_ENABLED	0x00000010 /* Rx Timestamping enabled */
+#define IXGBE_TSYNCRXCTL_TSIP_UT_EN	0x00800000 /* Rx Timestamp in Packet */
+
+#define IXGBE_TSIM_TXTS			0x00000002
 
 #define IXGBE_RXMTRL_V1_CTRLT_MASK	0x000000FF
 #define IXGBE_RXMTRL_V1_SYNC_MSG	0x00
@@ -2332,6 +2343,7 @@
 #define IXGBE_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
 #define IXGBE_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
 #define IXGBE_RXD_STAT_LLINT    0x800   /* Pkt caused Low Latency Interrupt */
+#define IXGBE_RXD_STAT_TSIP     0x08000 /* Time Stamp in packet buffer */
 #define IXGBE_RXD_STAT_TS       0x10000 /* Time Stamp */
 #define IXGBE_RXD_STAT_SECP     0x20000 /* Security Processing */
 #define IXGBE_RXD_STAT_LB       0x40000 /* Loopback Status */
@@ -2768,6 +2780,7 @@
 #define IXGBE_ADVTXD_TUCMD_L4T_UDP   0x00000000  /* L4 Packet TYPE of UDP */
 #define IXGBE_ADVTXD_TUCMD_L4T_TCP   0x00000800  /* L4 Packet TYPE of TCP */
 #define IXGBE_ADVTXD_TUCMD_L4T_SCTP  0x00001000  /* L4 Packet TYPE of SCTP */
+#define IXGBE_ADVTXD_TUCMD_L4T_RSV     0x00001800 /* RSV L4 Packet TYPE */
 #define IXGBE_ADVTXD_TUCMD_MKRREQ    0x00002000 /*Req requires Markers and CRC*/
 #define IXGBE_ADVTXD_POPTS_IPSEC      0x00000400 /* IPSec offload request */
 #define IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */
@@ -3288,7 +3301,7 @@
 	s32 (*enable_mc)(struct ixgbe_hw *);
 	s32 (*disable_mc)(struct ixgbe_hw *);
 	s32 (*clear_vfta)(struct ixgbe_hw *);
-	s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool);
+	s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool, bool);
 	s32 (*init_uta_tables)(struct ixgbe_hw *);
 	void (*set_mac_anti_spoofing)(struct ixgbe_hw *, bool, int);
 	void (*set_vlan_anti_spoofing)(struct ixgbe_hw *, bool, int);
@@ -3508,7 +3521,7 @@
 
 #define IXGBE_FUSES0_GROUP(_i)		(0x11158 + ((_i) * 4))
 #define IXGBE_FUSES0_300MHZ		BIT(5)
-#define IXGBE_FUSES0_REV1		BIT(6)
+#define IXGBE_FUSES0_REV_MASK		(3 << 6)
 
 #define IXGBE_KRM_PORT_CAR_GEN_CTRL(P)	((P) ? 0x8010 : 0x4010)
 #define IXGBE_KRM_LINK_CTRL_1(P)	((P) ? 0x820C : 0x420C)
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -57,8 +57,7 @@
 	struct ixgbe_phy_info *phy = &hw->phy;
 
 	/* set_phy_power was set by default to NULL */
-	if (!ixgbe_mng_present(hw))
-		phy->ops.set_phy_power = ixgbe_set_copper_phy_power;
+	phy->ops.set_phy_power = ixgbe_set_copper_phy_power;
 
 	mac->mcft_size = IXGBE_X540_MC_TBL_SIZE;
 	mac->vft_size = IXGBE_X540_VFT_TBL_SIZE;
@@ -110,13 +109,14 @@
 	ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
 	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
 	IXGBE_WRITE_FLUSH(hw);
+	usleep_range(1000, 1200);
 
 	/* Poll for reset bit to self-clear indicating reset is complete */
 	for (i = 0; i < 10; i++) {
-		udelay(1);
 		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
 		if (!(ctrl & IXGBE_CTRL_RST_MASK))
 			break;
+		udelay(1);
 	}
 
 	if (ctrl & IXGBE_CTRL_RST_MASK) {
@@ -154,12 +154,16 @@
 
 	/* Add the SAN MAC address to the RAR only if it's a valid address */
 	if (is_valid_ether_addr(hw->mac.san_addr)) {
-		hw->mac.ops.set_rar(hw, hw->mac.num_rar_entries - 1,
-				    hw->mac.san_addr, 0, IXGBE_RAH_AV);
-
 		/* Save the SAN MAC RAR index */
 		hw->mac.san_mac_rar_index = hw->mac.num_rar_entries - 1;
 
+		hw->mac.ops.set_rar(hw, hw->mac.san_mac_rar_index,
+				    hw->mac.san_addr, 0, IXGBE_RAH_AV);
+
+		/* clear VMDq pool/queue selection for this RAR */
+		hw->mac.ops.clear_vmdq(hw, hw->mac.san_mac_rar_index,
+				       IXGBE_CLEAR_VMDQ_ALL);
+
 		/* Reserve the last RAR for the SAN MAC address */
 		hw->mac.num_rar_entries--;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -26,6 +26,8 @@
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
 
+static s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *, ixgbe_link_speed);
+
 static s32 ixgbe_get_invariants_X550_x(struct ixgbe_hw *hw)
 {
 	struct ixgbe_mac_info *mac = &hw->mac;
@@ -85,79 +87,6 @@
 }
 
 /**
- * ixgbe_check_cs4227_reg - Perform diag on a CS4227 register
- * @hw: pointer to hardware structure
- * @reg: the register to check
- *
- * Performs a diagnostic on a register in the CS4227 chip. Returns an error
- * if it is not operating correctly.
- * This function assumes that the caller has acquired the proper semaphore.
- */
-static s32 ixgbe_check_cs4227_reg(struct ixgbe_hw *hw, u16 reg)
-{
-	s32 status;
-	u32 retry;
-	u16 reg_val;
-
-	reg_val = (IXGBE_CS4227_EDC_MODE_DIAG << 1) | 1;
-	status = ixgbe_write_cs4227(hw, reg, reg_val);
-	if (status)
-		return status;
-	for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) {
-		msleep(IXGBE_CS4227_CHECK_DELAY);
-		reg_val = 0xFFFF;
-		ixgbe_read_cs4227(hw, reg, &reg_val);
-		if (!reg_val)
-			break;
-	}
-	if (reg_val) {
-		hw_err(hw, "CS4227 reg 0x%04X failed diagnostic\n", reg);
-		return status;
-	}
-
-	return 0;
-}
-
-/**
- * ixgbe_get_cs4227_status - Return CS4227 status
- * @hw: pointer to hardware structure
- *
- * Performs a diagnostic on the CS4227 chip. Returns an error if it is
- * not operating correctly.
- * This function assumes that the caller has acquired the proper semaphore.
- */
-static s32 ixgbe_get_cs4227_status(struct ixgbe_hw *hw)
-{
-	s32 status;
-	u16 value = 0;
-
-	/* Exit if the diagnostic has already been performed. */
-	status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value);
-	if (status)
-		return status;
-	if (value == IXGBE_CS4227_RESET_COMPLETE)
-		return 0;
-
-	/* Check port 0. */
-	status = ixgbe_check_cs4227_reg(hw, IXGBE_CS4227_LINE_SPARE24_LSB);
-	if (status)
-		return status;
-
-	status = ixgbe_check_cs4227_reg(hw, IXGBE_CS4227_HOST_SPARE24_LSB);
-	if (status)
-		return status;
-
-	/* Check port 1. */
-	status = ixgbe_check_cs4227_reg(hw, IXGBE_CS4227_LINE_SPARE24_LSB +
-					(1 << 12));
-	if (status)
-		return status;
-
-	return ixgbe_check_cs4227_reg(hw, IXGBE_CS4227_HOST_SPARE24_LSB +
-				      (1 << 12));
-}
-
-/**
  * ixgbe_read_pe - Read register from port expander
  * @hw: pointer to hardware structure
  * @reg: register number to read
@@ -326,13 +255,6 @@
 		return;
 	}
 
-	/* Is the CS4227 working correctly? */
-	status = ixgbe_get_cs4227_status(hw);
-	if (status) {
-		hw_err(hw, "CS4227 status failed: %d", status);
-		goto out;
-	}
-
 	/* Record completion for next time. */
 	status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
 				    IXGBE_CS4227_RESET_COMPLETE);
@@ -564,6 +486,8 @@
 		/* convert offset from words to bytes */
 		buffer.address = cpu_to_be32((offset + current_word) * 2);
 		buffer.length = cpu_to_be16(words_to_read * 2);
+		buffer.pad2 = 0;
+		buffer.pad3 = 0;
 
 		status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
 						      sizeof(buffer),
@@ -1257,31 +1181,71 @@
 	if (status)
 		return status;
 
-	/* Configure CS4227 LINE side to 10G SR. */
-	slice = IXGBE_CS4227_LINE_SPARE22_MSB + (hw->bus.lan_id << 12);
-	value = IXGBE_CS4227_SPEED_10G;
-	status = ixgbe_write_i2c_combined_generic(hw, IXGBE_CS4227, slice,
-						  value);
-
-	/* Configure CS4227 for HOST connection rate then type. */
-	slice = IXGBE_CS4227_HOST_SPARE22_MSB + (hw->bus.lan_id << 12);
-	value = speed & IXGBE_LINK_SPEED_10GB_FULL ?
-		IXGBE_CS4227_SPEED_10G : IXGBE_CS4227_SPEED_1G;
-	status = ixgbe_write_i2c_combined_generic(hw, IXGBE_CS4227, slice,
-						  value);
-
-	slice = IXGBE_CS4227_HOST_SPARE24_LSB + (hw->bus.lan_id << 12);
-	if (setup_linear)
-		value = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 1;
-	else
+	if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+		/* Configure CS4227 LINE side to 10G SR. */
+		slice = IXGBE_CS4227_LINE_SPARE22_MSB + (hw->bus.lan_id << 12);
+		value = IXGBE_CS4227_SPEED_10G;
+		status = ixgbe_write_i2c_combined_generic(hw, IXGBE_CS4227,
+							  slice, value);
+		if (status)
+			goto i2c_err;
+
+		slice = IXGBE_CS4227_LINE_SPARE24_LSB + (hw->bus.lan_id << 12);
 		value = (IXGBE_CS4227_EDC_MODE_SR << 1) | 1;
-	status = ixgbe_write_i2c_combined_generic(hw, IXGBE_CS4227, slice,
-						  value);
+		status = ixgbe_write_i2c_combined_generic(hw, IXGBE_CS4227,
+							  slice, value);
+		if (status)
+			goto i2c_err;
 
-	/* If internal link mode is XFI, then setup XFI internal link. */
-	if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE))
+		/* Configure CS4227 for HOST connection rate then type. */
+		slice = IXGBE_CS4227_HOST_SPARE22_MSB + (hw->bus.lan_id << 12);
+		value = speed & IXGBE_LINK_SPEED_10GB_FULL ?
+			IXGBE_CS4227_SPEED_10G : IXGBE_CS4227_SPEED_1G;
+		status = ixgbe_write_i2c_combined_generic(hw, IXGBE_CS4227,
+							  slice, value);
+		if (status)
+			goto i2c_err;
+
+		slice = IXGBE_CS4227_HOST_SPARE24_LSB + (hw->bus.lan_id << 12);
+		if (setup_linear)
+			value = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 1;
+		else
+			value = (IXGBE_CS4227_EDC_MODE_SR << 1) | 1;
+		status = ixgbe_write_i2c_combined_generic(hw, IXGBE_CS4227,
+							  slice, value);
+		if (status)
+			goto i2c_err;
+
+		/* Setup XFI internal link. */
 		status = ixgbe_setup_ixfi_x550em(hw, &speed);
+		if (status) {
+			hw_dbg(hw, "setup_ixfi failed with %d\n", status);
+			return status;
+		}
+	} else {
+		/* Configure internal PHY for KR/KX. */
+		status = ixgbe_setup_kr_speed_x550em(hw, speed);
+		if (status) {
+			hw_dbg(hw, "setup_kr_speed failed with %d\n", status);
+			return status;
+		}
+
+		/* Configure CS4227 LINE side to proper mode. */
+		slice = IXGBE_CS4227_LINE_SPARE24_LSB + (hw->bus.lan_id << 12);
+		if (setup_linear)
+			value = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 1;
+		else
+			value = (IXGBE_CS4227_EDC_MODE_SR << 1) | 1;
+		status = ixgbe_write_i2c_combined_generic(hw, IXGBE_CS4227,
+							  slice, value);
+		if (status)
+			goto i2c_err;
+	}
 
+	return 0;
+
+i2c_err:
+	hw_dbg(hw, "combined i2c access failed with %d\n", status);
 	return status;
 }
 
@@ -1427,7 +1391,9 @@
 		*autoneg = false;
 
 		if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
-		    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
+		    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
+		    hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+		    hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1) {
 			*speed = IXGBE_LINK_SPEED_1GB_FULL;
 			return 0;
 		}
@@ -1482,7 +1448,7 @@
 				IXGBE_MDIO_GLOBAL_ALARM_1_INT)))
 		return status;
 
-	/* High temperature failure alarm triggered */
+	/* Global alarm triggered */
 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1,
 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
 				      &reg);
@@ -1496,6 +1462,21 @@
 		ixgbe_set_copper_phy_power(hw, false);
 		return IXGBE_ERR_OVERTEMP;
 	}
+	if (reg & IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT) {
+		/*  device fault alarm triggered */
+		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_FAULT_MSG,
+					  IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+					  &reg);
+		if (status)
+			return status;
+
+		/* if device fault was due to high temp alarm handle and exit */
+		if (reg == IXGBE_MDIO_GLOBAL_FAULT_MSG_HI_TMP) {
+			/* power down the PHY in case the PHY FW didn't */
+			ixgbe_set_copper_phy_power(hw, false);
+			return IXGBE_ERR_OVERTEMP;
+		}
+	}
 
 	/* Vendor alarm 2 triggered */
 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
@@ -1549,14 +1530,15 @@
 	if (status)
 		return status;
 
-	/* Enables high temperature failure alarm */
+	/* Enable high temperature failure and global fault alarms */
 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
 				      &reg);
 	if (status)
 		return status;
 
-	reg |= IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN;
+	reg |= (IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN |
+		IXGBE_MDIO_GLOBAL_INT_DEV_FAULT_EN);
 
 	status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
 				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
@@ -1643,8 +1625,6 @@
 		return status;
 
 	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
-	reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ |
-		     IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC);
 	reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
 		     IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
 
@@ -1765,6 +1745,12 @@
 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
 		return IXGBE_ERR_CONFIG;
 
+	if (hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) {
+		speed = IXGBE_LINK_SPEED_10GB_FULL |
+			IXGBE_LINK_SPEED_1GB_FULL;
+		return ixgbe_setup_kr_speed_x550em(hw, speed);
+	}
+
 	/* If link is not up, then there is no setup necessary so return  */
 	status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
 	if (status)
@@ -1873,10 +1859,6 @@
 	u32 save_autoneg;
 	bool link_up;
 
-	/* SW LPLU not required on later HW revisions. */
-	if (IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)))
-		return 0;
-
 	/* If blocked by MNG FW, then don't restart AN */
 	if (ixgbe_check_reset_blocked(hw))
 		return 0;
@@ -1969,7 +1951,6 @@
 static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
 {
 	struct ixgbe_phy_info *phy = &hw->phy;
-	ixgbe_link_speed speed;
 	s32 ret_val;
 
 	hw->mac.ops.set_lan_id(hw);
@@ -1982,13 +1963,6 @@
 		 * to determine internal PHY mode.
 		 */
 		phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
-
-		/* If internal PHY mode is KR, then initialize KR link */
-		if (phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) {
-			speed = IXGBE_LINK_SPEED_10GB_FULL |
-				IXGBE_LINK_SPEED_1GB_FULL;
-			ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
-		}
 	}
 
 	/* Identify the PHY or SFP module */
@@ -2020,18 +1994,13 @@
 		/* If internal link mode is XFI, then setup iXFI internal link,
 		 * else setup KR now.
 		 */
-		if (!(phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
-			phy->ops.setup_internal_link =
-					ixgbe_setup_internal_phy_t_x550em;
-		} else {
-			speed = IXGBE_LINK_SPEED_10GB_FULL |
-				IXGBE_LINK_SPEED_1GB_FULL;
-			ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
-		}
+		phy->ops.setup_internal_link =
+					      ixgbe_setup_internal_phy_t_x550em;
 
 		/* setup SW LPLU only for first revision */
-		if (!(IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw,
-							IXGBE_FUSES0_GROUP(0))))
+		if (hw->mac.type == ixgbe_mac_X550EM_x &&
+		    !(IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)) &
+		      IXGBE_FUSES0_REV_MASK))
 			phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em;
 
 		phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em;
@@ -2176,13 +2145,14 @@
 	ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
 	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
 	IXGBE_WRITE_FLUSH(hw);
+	usleep_range(1000, 1200);
 
 	/* Poll for reset bit to self-clear meaning reset is complete */
 	for (i = 0; i < 10; i++) {
-		udelay(1);
 		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
 		if (!(ctrl & IXGBE_CTRL_RST_MASK))
 			break;
+		udelay(1);
 	}
 
 	if (ctrl & IXGBE_CTRL_RST_MASK) {
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbevf/defines.h
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbevf/defines.h
@@ -33,6 +33,11 @@
 #define IXGBE_DEV_ID_X550_VF		0x1565
 #define IXGBE_DEV_ID_X550EM_X_VF	0x15A8
 
+#define IXGBE_DEV_ID_82599_VF_HV	0x152E
+#define IXGBE_DEV_ID_X540_VF_HV		0x1530
+#define IXGBE_DEV_ID_X550_VF_HV		0x1564
+#define IXGBE_DEV_ID_X550EM_X_VF_HV	0x15A9
+
 #define IXGBE_VF_IRQ_CLEAR_MASK		7
 #define IXGBE_VF_MAX_TX_QUEUES		8
 #define IXGBE_VF_MAX_RX_QUEUES		8
@@ -74,7 +79,7 @@
 #define IXGBE_RXDCTL_RLPML_EN	0x00008000
 
 /* DCA Control */
-#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
+#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN BIT(11) /* Tx Desc writeback RO bit */
 
 /* PSRTYPE bit definitions */
 #define IXGBE_PSRTYPE_TCPHDR	0x00000010
@@ -296,16 +301,16 @@
 #define IXGBE_TXDCTL_SWFLSH		0x04000000 /* Tx Desc. wr-bk flushing */
 #define IXGBE_TXDCTL_WTHRESH_SHIFT	16	   /* shift to WTHRESH bits */
 
-#define IXGBE_DCA_RXCTRL_DESC_DCA_EN	(1 << 5)  /* Rx Desc enable */
-#define IXGBE_DCA_RXCTRL_HEAD_DCA_EN	(1 << 6)  /* Rx Desc header ena */
-#define IXGBE_DCA_RXCTRL_DATA_DCA_EN	(1 << 7)  /* Rx Desc payload ena */
-#define IXGBE_DCA_RXCTRL_DESC_RRO_EN	(1 << 9)  /* Rx rd Desc Relax Order */
-#define IXGBE_DCA_RXCTRL_DATA_WRO_EN	(1 << 13) /* Rx wr data Relax Order */
-#define IXGBE_DCA_RXCTRL_HEAD_WRO_EN	(1 << 15) /* Rx wr header RO */
-
-#define IXGBE_DCA_TXCTRL_DESC_DCA_EN	(1 << 5)  /* DCA Tx Desc enable */
-#define IXGBE_DCA_TXCTRL_DESC_RRO_EN	(1 << 9)  /* Tx rd Desc Relax Order */
-#define IXGBE_DCA_TXCTRL_DESC_WRO_EN	(1 << 11) /* Tx Desc writeback RO bit */
-#define IXGBE_DCA_TXCTRL_DATA_RRO_EN	(1 << 13) /* Tx rd data Relax Order */
+#define IXGBE_DCA_RXCTRL_DESC_DCA_EN	BIT(5)  /* Rx Desc enable */
+#define IXGBE_DCA_RXCTRL_HEAD_DCA_EN	BIT(6)  /* Rx Desc header ena */
+#define IXGBE_DCA_RXCTRL_DATA_DCA_EN	BIT(7)  /* Rx Desc payload ena */
+#define IXGBE_DCA_RXCTRL_DESC_RRO_EN	BIT(9)  /* Rx rd Desc Relax Order */
+#define IXGBE_DCA_RXCTRL_DATA_WRO_EN	BIT(13) /* Rx wr data Relax Order */
+#define IXGBE_DCA_RXCTRL_HEAD_WRO_EN	BIT(15) /* Rx wr header RO */
+
+#define IXGBE_DCA_TXCTRL_DESC_DCA_EN	BIT(5)  /* DCA Tx Desc enable */
+#define IXGBE_DCA_TXCTRL_DESC_RRO_EN	BIT(9)  /* Tx rd Desc Relax Order */
+#define IXGBE_DCA_TXCTRL_DESC_WRO_EN	BIT(11) /* Tx Desc writeback RO bit */
+#define IXGBE_DCA_TXCTRL_DATA_RRO_EN	BIT(13) /* Tx rd data Relax Order */
 
 #endif /* _IXGBEVF_DEFINES_H_ */
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbevf/ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbevf/ethtool.c
@@ -42,86 +42,69 @@
 
 #define IXGBE_ALL_RAR_ENTRIES 16
 
+enum {NETDEV_STATS, IXGBEVF_STATS};
+
 struct ixgbe_stats {
 	char stat_string[ETH_GSTRING_LEN];
-	struct {
-		int sizeof_stat;
-		int stat_offset;
-		int base_stat_offset;
-		int saved_reset_offset;
-	};
+	int type;
+	int sizeof_stat;
+	int stat_offset;
 };
 
-#define IXGBEVF_STAT(m, b, r) { \
-	.sizeof_stat = FIELD_SIZEOF(struct ixgbevf_adapter, m), \
-	.stat_offset = offsetof(struct ixgbevf_adapter, m), \
-	.base_stat_offset = offsetof(struct ixgbevf_adapter, b), \
-	.saved_reset_offset = offsetof(struct ixgbevf_adapter, r) \
-}
-
-#define IXGBEVF_ZSTAT(m) { \
-	.sizeof_stat = FIELD_SIZEOF(struct ixgbevf_adapter, m), \
-	.stat_offset = offsetof(struct ixgbevf_adapter, m), \
-	.base_stat_offset = -1, \
-	.saved_reset_offset = -1 \
-}
-
-static const struct ixgbe_stats ixgbe_gstrings_stats[] = {
-	{"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc,
-				    stats.saved_reset_vfgprc)},
-	{"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc,
-				    stats.saved_reset_vfgptc)},
-	{"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc,
-				  stats.saved_reset_vfgorc)},
-	{"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc,
-				  stats.saved_reset_vfgotc)},
-	{"tx_busy", IXGBEVF_ZSTAT(tx_busy)},
-	{"tx_restart_queue", IXGBEVF_ZSTAT(restart_queue)},
-	{"tx_timeout_count", IXGBEVF_ZSTAT(tx_timeout_count)},
-	{"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc,
-				   stats.saved_reset_vfmprc)},
-	{"rx_csum_offload_errors", IXGBEVF_ZSTAT(hw_csum_rx_error)},
-#ifdef BP_EXTENDED_STATS
-	{"rx_bp_poll_yield", IXGBEVF_ZSTAT(bp_rx_yields)},
-	{"rx_bp_cleaned", IXGBEVF_ZSTAT(bp_rx_cleaned)},
-	{"rx_bp_misses", IXGBEVF_ZSTAT(bp_rx_missed)},
-	{"tx_bp_napi_yield", IXGBEVF_ZSTAT(bp_tx_yields)},
-	{"tx_bp_cleaned", IXGBEVF_ZSTAT(bp_tx_cleaned)},
-	{"tx_bp_misses", IXGBEVF_ZSTAT(bp_tx_missed)},
-#endif
+#define IXGBEVF_STAT(_name, _stat) { \
+	.stat_string = _name, \
+	.type = IXGBEVF_STATS, \
+	.sizeof_stat = FIELD_SIZEOF(struct ixgbevf_adapter, _stat), \
+	.stat_offset = offsetof(struct ixgbevf_adapter, _stat) \
+}
+
+#define IXGBEVF_NETDEV_STAT(_net_stat) { \
+	.stat_string = #_net_stat, \
+	.type = NETDEV_STATS, \
+	.sizeof_stat = FIELD_SIZEOF(struct net_device_stats, _net_stat), \
+	.stat_offset = offsetof(struct net_device_stats, _net_stat) \
+}
+
+static struct ixgbe_stats ixgbevf_gstrings_stats[] = {
+	IXGBEVF_NETDEV_STAT(rx_packets),
+	IXGBEVF_NETDEV_STAT(tx_packets),
+	IXGBEVF_NETDEV_STAT(rx_bytes),
+	IXGBEVF_NETDEV_STAT(tx_bytes),
+	IXGBEVF_STAT("tx_busy", tx_busy),
+	IXGBEVF_STAT("tx_restart_queue", restart_queue),
+	IXGBEVF_STAT("tx_timeout_count", tx_timeout_count),
+	IXGBEVF_NETDEV_STAT(multicast),
+	IXGBEVF_STAT("rx_csum_offload_errors", hw_csum_rx_error),
 };
 
-#define IXGBE_QUEUE_STATS_LEN 0
-#define IXGBE_GLOBAL_STATS_LEN	ARRAY_SIZE(ixgbe_gstrings_stats)
+#define IXGBEVF_QUEUE_STATS_LEN ( \
+	(((struct ixgbevf_adapter *)netdev_priv(netdev))->num_tx_queues + \
+	 ((struct ixgbevf_adapter *)netdev_priv(netdev))->num_rx_queues) * \
+	 (sizeof(struct ixgbe_stats) / sizeof(u64)))
+#define IXGBEVF_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbevf_gstrings_stats)
 
-#define IXGBEVF_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+#define IXGBEVF_STATS_LEN (IXGBEVF_GLOBAL_STATS_LEN + IXGBEVF_QUEUE_STATS_LEN)
 static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Register test  (offline)",
 	"Link test   (on/offline)"
 };
 
-#define IXGBE_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN)
+#define IXGBEVF_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN)
 
 static int ixgbevf_get_settings(struct net_device *netdev,
 				struct ethtool_cmd *ecmd)
 {
 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
-	struct ixgbe_hw *hw = &adapter->hw;
-	u32 link_speed = 0;
-	bool link_up;
 
 	ecmd->supported = SUPPORTED_10000baseT_Full;
 	ecmd->autoneg = AUTONEG_DISABLE;
 	ecmd->transceiver = XCVR_DUMMY1;
 	ecmd->port = -1;
 
-	hw->mac.get_link_status = 1;
-	hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
-
-	if (link_up) {
+	if (adapter->link_up) {
 		__u32 speed = SPEED_10000;
 
-		switch (link_speed) {
+		switch (adapter->link_speed) {
 		case IXGBE_LINK_SPEED_10GB_FULL:
 			speed = SPEED_10000;
 			break;
@@ -177,7 +160,8 @@
 
 	memset(p, 0, regs_len);
 
-	regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
+	/* generate a number suitable for ethtool's register version */
+	regs->version = (1u << 24) | (hw->revision_id << 16) | hw->device_id;
 
 	/* General Registers */
 	regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_VFCTRL);
@@ -392,13 +376,13 @@
 	return err;
 }
 
-static int ixgbevf_get_sset_count(struct net_device *dev, int stringset)
+static int ixgbevf_get_sset_count(struct net_device *netdev, int stringset)
 {
 	switch (stringset) {
 	case ETH_SS_TEST:
-		return IXGBE_TEST_LEN;
+		return IXGBEVF_TEST_LEN;
 	case ETH_SS_STATS:
-		return IXGBE_GLOBAL_STATS_LEN;
+		return IXGBEVF_STATS_LEN;
 	default:
 		return -EINVAL;
 	}
@@ -408,70 +392,138 @@
 				      struct ethtool_stats *stats, u64 *data)
 {
 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
-	char *base = (char *)adapter;
-	int i;
-#ifdef BP_EXTENDED_STATS
-	u64 rx_yields = 0, rx_cleaned = 0, rx_missed = 0,
-	    tx_yields = 0, tx_cleaned = 0, tx_missed = 0;
+	struct rtnl_link_stats64 temp;
+	const struct rtnl_link_stats64 *net_stats;
+	unsigned int start;
+	struct ixgbevf_ring *ring;
+	int i, j;
+	char *p;
 
-	for (i = 0; i < adapter->num_rx_queues; i++) {
-		rx_yields += adapter->rx_ring[i]->stats.yields;
-		rx_cleaned += adapter->rx_ring[i]->stats.cleaned;
-		rx_yields += adapter->rx_ring[i]->stats.yields;
-	}
+	ixgbevf_update_stats(adapter);
+	net_stats = dev_get_stats(netdev, &temp);
+	for (i = 0; i < IXGBEVF_GLOBAL_STATS_LEN; i++) {
+		switch (ixgbevf_gstrings_stats[i].type) {
+		case NETDEV_STATS:
+			p = (char *)net_stats +
+					ixgbevf_gstrings_stats[i].stat_offset;
+			break;
+		case IXGBEVF_STATS:
+			p = (char *)adapter +
+					ixgbevf_gstrings_stats[i].stat_offset;
+			break;
+		default:
+			data[i] = 0;
+			continue;
+		}
 
-	for (i = 0; i < adapter->num_tx_queues; i++) {
-		tx_yields += adapter->tx_ring[i]->stats.yields;
-		tx_cleaned += adapter->tx_ring[i]->stats.cleaned;
-		tx_yields += adapter->tx_ring[i]->stats.yields;
+		data[i] = (ixgbevf_gstrings_stats[i].sizeof_stat ==
+			   sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
 	}
 
-	adapter->bp_rx_yields = rx_yields;
-	adapter->bp_rx_cleaned = rx_cleaned;
-	adapter->bp_rx_missed = rx_missed;
+	/* populate Tx queue data */
+	for (j = 0; j < adapter->num_tx_queues; j++) {
+		ring = adapter->tx_ring[j];
+		if (!ring) {
+			data[i++] = 0;
+			data[i++] = 0;
+#ifdef BP_EXTENDED_STATS
+			data[i++] = 0;
+			data[i++] = 0;
+			data[i++] = 0;
+#endif
+			continue;
+		}
 
-	adapter->bp_tx_yields = tx_yields;
-	adapter->bp_tx_cleaned = tx_cleaned;
-	adapter->bp_tx_missed = tx_missed;
+		do {
+			start = u64_stats_fetch_begin_irq(&ring->syncp);
+			data[i]   = ring->stats.packets;
+			data[i + 1] = ring->stats.bytes;
+		} while (u64_stats_fetch_retry_irq(&ring->syncp, start));
+		i += 2;
+#ifdef BP_EXTENDED_STATS
+		data[i] = ring->stats.yields;
+		data[i + 1] = ring->stats.misses;
+		data[i + 2] = ring->stats.cleaned;
+		i += 3;
 #endif
+	}
 
-	ixgbevf_update_stats(adapter);
-	for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
-		char *p = base + ixgbe_gstrings_stats[i].stat_offset;
-		char *b = base + ixgbe_gstrings_stats[i].base_stat_offset;
-		char *r = base + ixgbe_gstrings_stats[i].saved_reset_offset;
-
-		if (ixgbe_gstrings_stats[i].sizeof_stat == sizeof(u64)) {
-			if (ixgbe_gstrings_stats[i].base_stat_offset >= 0)
-				data[i] = *(u64 *)p - *(u64 *)b + *(u64 *)r;
-			else
-				data[i] = *(u64 *)p;
-		} else {
-			if (ixgbe_gstrings_stats[i].base_stat_offset >= 0)
-				data[i] = *(u32 *)p - *(u32 *)b + *(u32 *)r;
-			else
-				data[i] = *(u32 *)p;
+	/* populate Rx queue data */
+	for (j = 0; j < adapter->num_rx_queues; j++) {
+		ring = adapter->rx_ring[j];
+		if (!ring) {
+			data[i++] = 0;
+			data[i++] = 0;
+#ifdef BP_EXTENDED_STATS
+			data[i++] = 0;
+			data[i++] = 0;
+			data[i++] = 0;
+#endif
+			continue;
 		}
+
+		do {
+			start = u64_stats_fetch_begin_irq(&ring->syncp);
+			data[i]   = ring->stats.packets;
+			data[i + 1] = ring->stats.bytes;
+		} while (u64_stats_fetch_retry_irq(&ring->syncp, start));
+		i += 2;
+#ifdef BP_EXTENDED_STATS
+		data[i] = ring->stats.yields;
+		data[i + 1] = ring->stats.misses;
+		data[i + 2] = ring->stats.cleaned;
+		i += 3;
+#endif
 	}
 }
 
 static void ixgbevf_get_strings(struct net_device *netdev, u32 stringset,
 				u8 *data)
 {
+	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 	char *p = (char *)data;
 	int i;
 
 	switch (stringset) {
 	case ETH_SS_TEST:
 		memcpy(data, *ixgbe_gstrings_test,
-		       IXGBE_TEST_LEN * ETH_GSTRING_LEN);
+		       IXGBEVF_TEST_LEN * ETH_GSTRING_LEN);
 		break;
 	case ETH_SS_STATS:
-		for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
-			memcpy(p, ixgbe_gstrings_stats[i].stat_string,
+		for (i = 0; i < IXGBEVF_GLOBAL_STATS_LEN; i++) {
+			memcpy(p, ixgbevf_gstrings_stats[i].stat_string,
 			       ETH_GSTRING_LEN);
 			p += ETH_GSTRING_LEN;
 		}
+
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			sprintf(p, "tx_queue_%u_packets", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_queue_%u_bytes", i);
+			p += ETH_GSTRING_LEN;
+#ifdef BP_EXTENDED_STATS
+			sprintf(p, "tx_queue_%u_bp_napi_yield", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_queue_%u_bp_misses", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_queue_%u_bp_cleaned", i);
+			p += ETH_GSTRING_LEN;
+#endif /* BP_EXTENDED_STATS */
+		}
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+			sprintf(p, "rx_queue_%u_packets", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_bytes", i);
+			p += ETH_GSTRING_LEN;
+#ifdef BP_EXTENDED_STATS
+			sprintf(p, "rx_queue_%u_bp_poll_yield", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_bp_misses", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_bp_cleaned", i);
+			p += ETH_GSTRING_LEN;
+#endif /* BP_EXTENDED_STATS */
+		}
 		break;
 	}
 }
@@ -680,7 +732,7 @@
 
 		if (if_running)
 			/* indicate we're in test mode */
-			dev_close(netdev);
+			ixgbevf_close(netdev);
 		else
 			ixgbevf_reset(adapter);
 
@@ -692,7 +744,7 @@
 
 		clear_bit(__IXGBEVF_TESTING, &adapter->state);
 		if (if_running)
-			dev_open(netdev);
+			ixgbevf_open(netdev);
 	} else {
 		hw_dbg(&adapter->hw, "online testing starting\n");
 		/* Online tests */
@@ -774,7 +826,7 @@
 		adapter->tx_itr_setting = ec->tx_coalesce_usecs;
 
 	if (adapter->tx_itr_setting == 1)
-		tx_itr_param = IXGBE_10K_ITR;
+		tx_itr_param = IXGBE_12K_ITR;
 	else
 		tx_itr_param = adapter->tx_itr_setting;
 
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -166,10 +166,10 @@
 
 #define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
 
-#define IXGBE_TX_FLAGS_CSUM		(u32)(1)
-#define IXGBE_TX_FLAGS_VLAN		(u32)(1 << 1)
-#define IXGBE_TX_FLAGS_TSO		(u32)(1 << 2)
-#define IXGBE_TX_FLAGS_IPV4		(u32)(1 << 3)
+#define IXGBE_TX_FLAGS_CSUM		BIT(0)
+#define IXGBE_TX_FLAGS_VLAN		BIT(1)
+#define IXGBE_TX_FLAGS_TSO		BIT(2)
+#define IXGBE_TX_FLAGS_IPV4		BIT(3)
 #define IXGBE_TX_FLAGS_VLAN_MASK	0xffff0000
 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK	0x0000e000
 #define IXGBE_TX_FLAGS_VLAN_SHIFT	16
@@ -326,8 +326,7 @@
 #define IXGBE_MIN_RSC_ITR	24
 #define IXGBE_100K_ITR		40
 #define IXGBE_20K_ITR		200
-#define IXGBE_10K_ITR		400
-#define IXGBE_8K_ITR		500
+#define IXGBE_12K_ITR		336
 
 /* Helper macros to switch between ints/sec and what the register uses.
  * And yes, it's the same math going both ways.  The lowest value
@@ -404,13 +403,6 @@
 	u32 alloc_rx_page_failed;
 	u32 alloc_rx_buff_failed;
 
-	/* Some features need tri-state capability,
-	 * thus the additional *_CAPABLE flags.
-	 */
-	u32 flags;
-#define IXGBEVF_FLAG_RESET_REQUESTED		(u32)(1)
-#define IXGBEVF_FLAG_QUEUE_RESET_REQUESTED	(u32)(1 << 2)
-
 	struct msix_entry *msix_entries;
 
 	/* OS defined structs */
@@ -430,16 +422,6 @@
 	unsigned int tx_ring_count;
 	unsigned int rx_ring_count;
 
-#ifdef BP_EXTENDED_STATS
-	u64 bp_rx_yields;
-	u64 bp_rx_cleaned;
-	u64 bp_rx_missed;
-
-	u64 bp_tx_yields;
-	u64 bp_tx_cleaned;
-	u64 bp_tx_missed;
-#endif
-
 	u8 __iomem *io_addr; /* Mainly for iounmap use */
 	u32 link_speed;
 	bool link_up;
@@ -462,13 +444,19 @@
 	__IXGBEVF_REMOVING,
 	__IXGBEVF_SERVICE_SCHED,
 	__IXGBEVF_SERVICE_INITED,
+	__IXGBEVF_RESET_REQUESTED,
+	__IXGBEVF_QUEUE_RESET_REQUESTED,
 };
 
 enum ixgbevf_boards {
 	board_82599_vf,
+	board_82599_vf_hv,
 	board_X540_vf,
+	board_X540_vf_hv,
 	board_X550_vf,
+	board_X550_vf_hv,
 	board_X550EM_x_vf,
+	board_X550EM_x_vf_hv,
 };
 
 enum ixgbevf_xcast_modes {
@@ -483,10 +471,18 @@
 extern const struct ixgbevf_info ixgbevf_X550EM_x_vf_info;
 extern const struct ixgbe_mbx_operations ixgbevf_mbx_ops;
 
+extern const struct ixgbevf_info ixgbevf_82599_vf_hv_info;
+extern const struct ixgbevf_info ixgbevf_X540_vf_hv_info;
+extern const struct ixgbevf_info ixgbevf_X550_vf_hv_info;
+extern const struct ixgbevf_info ixgbevf_X550EM_x_vf_hv_info;
+extern const struct ixgbe_mbx_operations ixgbevf_hv_mbx_ops;
+
 /* needed by ethtool.c */
 extern const char ixgbevf_driver_name[];
 extern const char ixgbevf_driver_version[];
 
+int ixgbevf_open(struct net_device *netdev);
+int ixgbevf_close(struct net_device *netdev);
 void ixgbevf_up(struct ixgbevf_adapter *adapter);
 void ixgbevf_down(struct ixgbevf_adapter *adapter);
 void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter);
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -59,13 +59,17 @@
 #define DRV_VERSION "2.12.1-k"
 const char ixgbevf_driver_version[] = DRV_VERSION;
 static char ixgbevf_copyright[] =
-	"Copyright (c) 2009 - 2012 Intel Corporation.";
+	"Copyright (c) 2009 - 2015 Intel Corporation.";
 
 static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
-	[board_82599_vf] = &ixgbevf_82599_vf_info,
-	[board_X540_vf]  = &ixgbevf_X540_vf_info,
-	[board_X550_vf]  = &ixgbevf_X550_vf_info,
-	[board_X550EM_x_vf] = &ixgbevf_X550EM_x_vf_info,
+	[board_82599_vf]	= &ixgbevf_82599_vf_info,
+	[board_82599_vf_hv]	= &ixgbevf_82599_vf_hv_info,
+	[board_X540_vf]		= &ixgbevf_X540_vf_info,
+	[board_X540_vf_hv]	= &ixgbevf_X540_vf_hv_info,
+	[board_X550_vf]		= &ixgbevf_X550_vf_info,
+	[board_X550_vf_hv]	= &ixgbevf_X550_vf_hv_info,
+	[board_X550EM_x_vf]	= &ixgbevf_X550EM_x_vf_info,
+	[board_X550EM_x_vf_hv]	= &ixgbevf_X550EM_x_vf_hv_info,
 };
 
 /* ixgbevf_pci_tbl - PCI Device ID Table
@@ -78,9 +82,13 @@
  */
 static const struct pci_device_id ixgbevf_pci_tbl[] = {
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF), board_82599_vf },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF_HV), board_82599_vf_hv },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF), board_X540_vf },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF_HV), board_X540_vf_hv },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550_VF), board_X550_vf },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550_VF_HV), board_X550_vf_hv },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_VF), board_X550EM_x_vf },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_VF_HV), board_X550EM_x_vf_hv},
 	/* required last entry */
 	{0, }
 };
@@ -96,12 +104,14 @@
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
+static struct workqueue_struct *ixgbevf_wq;
+
 static void ixgbevf_service_event_schedule(struct ixgbevf_adapter *adapter)
 {
 	if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
 	    !test_bit(__IXGBEVF_REMOVING, &adapter->state) &&
 	    !test_and_set_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state))
-		schedule_work(&adapter->service_task);
+		queue_work(ixgbevf_wq, &adapter->service_task);
 }
 
 static void ixgbevf_service_event_complete(struct ixgbevf_adapter *adapter)
@@ -266,7 +276,7 @@
 {
 	/* Do the reset outside of interrupt context */
 	if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) {
-		adapter->flags |= IXGBEVF_FLAG_RESET_REQUESTED;
+		set_bit(__IXGBEVF_RESET_REQUESTED, &adapter->state);
 		ixgbevf_service_event_schedule(adapter);
 	}
 }
@@ -286,9 +296,10 @@
  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
  * @q_vector: board private structure
  * @tx_ring: tx ring to clean
+ * @napi_budget: Used to determine if we are in netpoll
  **/
 static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
-				 struct ixgbevf_ring *tx_ring)
+				 struct ixgbevf_ring *tx_ring, int napi_budget)
 {
 	struct ixgbevf_adapter *adapter = q_vector->adapter;
 	struct ixgbevf_tx_buffer *tx_buffer;
@@ -312,7 +323,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		read_barrier_depends();
+		smp_rmb();
 
 		/* if DD is not set pending work has not been completed */
 		if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
@@ -326,7 +337,7 @@
 		total_packets += tx_buffer->gso_segs;
 
 		/* free the skb */
-		dev_kfree_skb_any(tx_buffer->skb);
+		napi_consume_skb(tx_buffer->skb, napi_budget);
 
 		/* unmap skb header data */
 		dma_unmap_single(tx_ring->dev,
@@ -1011,9 +1022,13 @@
 	int per_ring_budget, work_done = 0;
 	bool clean_complete = true;
 
-	ixgbevf_for_each_ring(ring, q_vector->tx)
-		clean_complete &= ixgbevf_clean_tx_irq(q_vector, ring);
+	ixgbevf_for_each_ring(ring, q_vector->tx) {
+		if (!ixgbevf_clean_tx_irq(q_vector, ring, budget))
+			clean_complete = false;
+	}
 
+	if (budget <= 0)
+		return budget;
 #ifdef CONFIG_NET_RX_BUSY_POLL
 	if (!ixgbevf_qv_lock_napi(q_vector))
 		return budget;
@@ -1031,7 +1046,8 @@
 		int cleaned = ixgbevf_clean_rx_irq(q_vector, ring,
 						   per_ring_budget);
 		work_done += cleaned;
-		clean_complete &= (cleaned < per_ring_budget);
+		if (cleaned >= per_ring_budget)
+			clean_complete = false;
 	}
 
 #ifdef CONFIG_NET_RX_BUSY_POLL
@@ -1043,12 +1059,12 @@
 		return budget;
 	/* all work done, exit the polling mode */
 	napi_complete_done(napi, work_done);
-	if (adapter->rx_itr_setting & 1)
+	if (adapter->rx_itr_setting == 1)
 		ixgbevf_set_itr(q_vector);
 	if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
 	    !test_bit(__IXGBEVF_REMOVING, &adapter->state))
 		ixgbevf_irq_enable_queues(adapter,
-					  1 << q_vector->v_idx);
+					  BIT(q_vector->v_idx));
 
 	return 0;
 }
@@ -1138,7 +1154,7 @@
 		if (q_vector->tx.ring && !q_vector->rx.ring) {
 			/* Tx only vector */
 			if (adapter->tx_itr_setting == 1)
-				q_vector->itr = IXGBE_10K_ITR;
+				q_vector->itr = IXGBE_12K_ITR;
 			else
 				q_vector->itr = adapter->tx_itr_setting;
 		} else {
@@ -1150,14 +1166,14 @@
 		}
 
 		/* add q_vector eims value to global eims_enable_mask */
-		adapter->eims_enable_mask |= 1 << v_idx;
+		adapter->eims_enable_mask |= BIT(v_idx);
 
 		ixgbevf_write_eitr(q_vector);
 	}
 
 	ixgbevf_set_ivar(adapter, -1, 1, v_idx);
 	/* setup eims_other and add value to global eims_enable_mask */
-	adapter->eims_other = 1 << v_idx;
+	adapter->eims_other = BIT(v_idx);
 	adapter->eims_enable_mask |= adapter->eims_other;
 }
 
@@ -1196,7 +1212,7 @@
 	/* simple throttle rate management
 	 *    0-20MB/s lowest (100000 ints/s)
 	 *   20-100MB/s low   (20000 ints/s)
-	 *  100-1249MB/s bulk (8000 ints/s)
+	 *  100-1249MB/s bulk (12000 ints/s)
 	 */
 	/* what was last interrupt timeslice? */
 	timepassed_us = q_vector->itr >> 2;
@@ -1246,8 +1262,9 @@
 		new_itr = IXGBE_20K_ITR;
 		break;
 	case bulk_latency:
+		new_itr = IXGBE_12K_ITR;
+		break;
 	default:
-		new_itr = IXGBE_8K_ITR;
 		break;
 	}
 
@@ -1288,7 +1305,7 @@
 
 	/* EIAM disabled interrupts (on this vector) for us */
 	if (q_vector->rx.ring || q_vector->tx.ring)
-		napi_schedule(&q_vector->napi);
+		napi_schedule_irqoff(&q_vector->napi);
 
 	return IRQ_HANDLED;
 }
@@ -1332,7 +1349,6 @@
 	int txr_remaining = adapter->num_tx_queues;
 	int i, j;
 	int rqpv, tqpv;
-	int err = 0;
 
 	q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
 
@@ -1345,7 +1361,7 @@
 
 		for (; txr_idx < txr_remaining; v_start++, txr_idx++)
 			map_vector_to_txq(adapter, v_start, txr_idx);
-		goto out;
+		return 0;
 	}
 
 	/* If we don't have enough vectors for a 1-to-1
@@ -1370,8 +1386,7 @@
 		}
 	}
 
-out:
-	return err;
+	return 0;
 }
 
 /**
@@ -1469,9 +1484,7 @@
  **/
 static int ixgbevf_request_irq(struct ixgbevf_adapter *adapter)
 {
-	int err = 0;
-
-	err = ixgbevf_request_msix_irqs(adapter);
+	int err = ixgbevf_request_msix_irqs(adapter);
 
 	if (err)
 		hw_dbg(&adapter->hw, "request_irq failed, Error %d\n", err);
@@ -1584,8 +1597,8 @@
 	txdctl |= (8 << 16);    /* WTHRESH = 8 */
 
 	/* Setting PTHRESH to 32 both improves performance */
-	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
-		  32;          /* PTHRESH = 32 */
+	txdctl |= (1u << 8) |    /* HTHRESH = 1 */
+		   32;           /* PTHRESH = 32 */
 
 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
 
@@ -1641,7 +1654,7 @@
 		      IXGBE_PSRTYPE_L2HDR;
 
 	if (adapter->num_rx_queues > 1)
-		psrtype |= 1 << 29;
+		psrtype |= BIT(29);
 
 	IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype);
 }
@@ -1747,9 +1760,15 @@
 	IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(reg_idx),
 			ring->count * sizeof(union ixgbe_adv_rx_desc));
 
+#ifndef CONFIG_SPARC
 	/* enable relaxed ordering */
 	IXGBE_WRITE_REG(hw, IXGBE_VFDCA_RXCTRL(reg_idx),
 			IXGBE_DCA_RXCTRL_DESC_RRO_EN);
+#else
+	IXGBE_WRITE_REG(hw, IXGBE_VFDCA_RXCTRL(reg_idx),
+			IXGBE_DCA_RXCTRL_DESC_RRO_EN |
+			IXGBE_DCA_RXCTRL_DATA_WRO_EN);
+#endif
 
 	/* reset head and tail pointers */
 	IXGBE_WRITE_REG(hw, IXGBE_VFRDH(reg_idx), 0);
@@ -1790,7 +1809,7 @@
 		ixgbevf_setup_vfmrqc(adapter);
 
 	/* notify the PF of our intent to use this size of frame */
-	ixgbevf_rlpml_set_vf(hw, netdev->mtu + ETH_HLEN + ETH_FCS_LEN);
+	hw->mac.ops.set_rlpml(hw, netdev->mtu + ETH_HLEN + ETH_FCS_LEN);
 
 	/* Setup the HW Rx Head and Tail Descriptor Pointers and
 	 * the Base and Length of the Rx Descriptor Ring
@@ -1830,7 +1849,7 @@
 {
 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
-	int err = -EOPNOTSUPP;
+	int err;
 
 	spin_lock_bh(&adapter->mbx_lock);
 
@@ -1859,11 +1878,6 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	int count = 0;
 
-	if ((netdev_uc_count(netdev)) > 10) {
-		pr_err("Too many unicast filters - No Space\n");
-		return -ENOSPC;
-	}
-
 	if (!netdev_uc_empty(netdev)) {
 		struct netdev_hw_addr *ha;
 
@@ -1983,7 +1997,7 @@
 		hw->mbx.timeout = 0;
 
 		/* wait for watchdog to come around and bail us out */
-		adapter->flags |= IXGBEVF_FLAG_QUEUE_RESET_REQUESTED;
+		set_bit(__IXGBEVF_QUEUE_RESET_REQUESTED, &adapter->state);
 	}
 
 	return 0;
@@ -2046,12 +2060,12 @@
 		      ixgbe_mbox_api_11,
 		      ixgbe_mbox_api_10,
 		      ixgbe_mbox_api_unknown };
-	int err = 0, idx = 0;
+	int err, idx = 0;
 
 	spin_lock_bh(&adapter->mbx_lock);
 
 	while (api[idx] != ixgbe_mbox_api_unknown) {
-		err = ixgbevf_negotiate_api_version(hw, api[idx]);
+		err = hw->mac.ops.negotiate_api_version(hw, api[idx]);
 		if (!err)
 			break;
 		idx++;
@@ -2260,10 +2274,8 @@
 	}
 
 	if (is_valid_ether_addr(adapter->hw.mac.addr)) {
-		memcpy(netdev->dev_addr, adapter->hw.mac.addr,
-		       netdev->addr_len);
-		memcpy(netdev->perm_addr, adapter->hw.mac.addr,
-		       netdev->addr_len);
+		ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
+		ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
 	}
 
 	adapter->last_reset = jiffies;
@@ -2421,7 +2433,7 @@
 static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	int err = 0;
+	int err;
 	int vector, v_budget;
 
 	/* It's easy to be greedy for MSI-X vectors, but it really
@@ -2439,26 +2451,21 @@
 	 */
 	adapter->msix_entries = kcalloc(v_budget,
 					sizeof(struct msix_entry), GFP_KERNEL);
-	if (!adapter->msix_entries) {
-		err = -ENOMEM;
-		goto out;
-	}
+	if (!adapter->msix_entries)
+		return -ENOMEM;
 
 	for (vector = 0; vector < v_budget; vector++)
 		adapter->msix_entries[vector].entry = vector;
 
 	err = ixgbevf_acquire_msix_vectors(adapter, v_budget);
 	if (err)
-		goto out;
+		return err;
 
 	err = netif_set_real_num_tx_queues(netdev, adapter->num_tx_queues);
 	if (err)
-		goto out;
-
-	err = netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues);
+		return err;
 
-out:
-	return err;
+	return netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues);
 }
 
 /**
@@ -2662,13 +2669,14 @@
 		else if (is_zero_ether_addr(adapter->hw.mac.addr))
 			dev_info(&pdev->dev,
 				 "MAC address not assigned by administrator.\n");
-		memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
+		ether_addr_copy(netdev->dev_addr, hw->mac.addr);
 	}
 
 	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		dev_info(&pdev->dev, "Assigning random MAC address\n");
 		eth_hw_addr_random(netdev);
-		memcpy(hw->mac.addr, netdev->dev_addr, netdev->addr_len);
+		ether_addr_copy(hw->mac.addr, netdev->dev_addr);
+		ether_addr_copy(hw->mac.perm_addr, netdev->dev_addr);
 	}
 
 	/* Enable dynamic interrupt throttling rates */
@@ -2757,11 +2765,9 @@
 
 static void ixgbevf_reset_subtask(struct ixgbevf_adapter *adapter)
 {
-	if (!(adapter->flags & IXGBEVF_FLAG_RESET_REQUESTED))
+	if (!test_and_clear_bit(__IXGBEVF_RESET_REQUESTED, &adapter->state))
 		return;
 
-	adapter->flags &= ~IXGBEVF_FLAG_RESET_REQUESTED;
-
 	/* If we're already down or resetting, just bail */
 	if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
 	    test_bit(__IXGBEVF_RESETTING, &adapter->state))
@@ -2803,7 +2809,7 @@
 		struct ixgbevf_q_vector *qv = adapter->q_vector[i];
 
 		if (qv->rx.ring || qv->tx.ring)
-			eics |= 1 << i;
+			eics |= BIT(i);
 	}
 
 	/* Cause software interrupt to ensure rings are cleaned */
@@ -2829,7 +2835,7 @@
 
 	/* if check for link returns error we will need to reset */
 	if (err && time_after(jiffies, adapter->last_reset + (10 * HZ))) {
-		adapter->flags |= IXGBEVF_FLAG_RESET_REQUESTED;
+		set_bit(__IXGBEVF_RESET_REQUESTED, &adapter->state);
 		link_up = false;
 	}
 
@@ -3130,7 +3136,7 @@
  * handler is registered with the OS, the watchdog timer is started,
  * and the stack is notified that the interface is ready.
  **/
-static int ixgbevf_open(struct net_device *netdev)
+int ixgbevf_open(struct net_device *netdev)
 {
 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -3213,7 +3219,7 @@
  * needs to be disabled.  A global MAC reset is issued to stop the
  * hardware, and all transmit and receive resources are freed.
  **/
-static int ixgbevf_close(struct net_device *netdev)
+int ixgbevf_close(struct net_device *netdev)
 {
 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 
@@ -3230,11 +3236,10 @@
 {
 	struct net_device *dev = adapter->netdev;
 
-	if (!(adapter->flags & IXGBEVF_FLAG_QUEUE_RESET_REQUESTED))
+	if (!test_and_clear_bit(__IXGBEVF_QUEUE_RESET_REQUESTED,
+				&adapter->state))
 		return;
 
-	adapter->flags &= ~IXGBEVF_FLAG_QUEUE_RESET_REQUESTED;
-
 	/* if interface is down do nothing */
 	if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
 	    test_bit(__IXGBEVF_RESETTING, &adapter->state))
@@ -3332,7 +3337,7 @@
 	/* mss_l4len_id: use 1 as index for TSO */
 	mss_l4len_idx = l4len << IXGBE_ADVTXD_L4LEN_SHIFT;
 	mss_l4len_idx |= skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
-	mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT;
+	mss_l4len_idx |= (1u << IXGBE_ADVTXD_IDX_SHIFT);
 
 	/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
 	vlan_macip_lens = skb_network_header_len(skb);
@@ -3345,70 +3350,55 @@
 	return 1;
 }
 
+static inline bool ixgbevf_ipv6_csum_is_sctp(struct sk_buff *skb)
+{
+	unsigned int offset = 0;
+
+	ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
+
+	return offset == skb_checksum_start_offset(skb);
+}
+
 static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring,
 			    struct ixgbevf_tx_buffer *first)
 {
 	struct sk_buff *skb = first->skb;
 	u32 vlan_macip_lens = 0;
-	u32 mss_l4len_idx = 0;
 	u32 type_tucmd = 0;
 
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		u8 l4_hdr = 0;
-
-		switch (first->protocol) {
-		case htons(ETH_P_IP):
-			vlan_macip_lens |= skb_network_header_len(skb);
-			type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
-			l4_hdr = ip_hdr(skb)->protocol;
-			break;
-		case htons(ETH_P_IPV6):
-			vlan_macip_lens |= skb_network_header_len(skb);
-			l4_hdr = ipv6_hdr(skb)->nexthdr;
-			break;
-		default:
-			if (unlikely(net_ratelimit())) {
-				dev_warn(tx_ring->dev,
-					 "partial checksum but proto=%x!\n",
-					 first->protocol);
-			}
-			break;
-		}
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		goto no_csum;
 
-		switch (l4_hdr) {
-		case IPPROTO_TCP:
-			type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
-			mss_l4len_idx = tcp_hdrlen(skb) <<
-					IXGBE_ADVTXD_L4LEN_SHIFT;
-			break;
-		case IPPROTO_SCTP:
-			type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
-			mss_l4len_idx = sizeof(struct sctphdr) <<
-					IXGBE_ADVTXD_L4LEN_SHIFT;
-			break;
-		case IPPROTO_UDP:
-			mss_l4len_idx = sizeof(struct udphdr) <<
-					IXGBE_ADVTXD_L4LEN_SHIFT;
-			break;
-		default:
-			if (unlikely(net_ratelimit())) {
-				dev_warn(tx_ring->dev,
-					 "partial checksum but l4 proto=%x!\n",
-					 l4_hdr);
-			}
+	switch (skb->csum_offset) {
+	case offsetof(struct tcphdr, check):
+		type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
+		/* fall through */
+	case offsetof(struct udphdr, check):
+		break;
+	case offsetof(struct sctphdr, checksum):
+		/* validate that this is actually an SCTP request */
+		if (((first->protocol == htons(ETH_P_IP)) &&
+		     (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+		    ((first->protocol == htons(ETH_P_IPV6)) &&
+		     ixgbevf_ipv6_csum_is_sctp(skb))) {
+			type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_SCTP;
 			break;
 		}
-
-		/* update TX checksum flag */
-		first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
+		/* fall through */
+	default:
+		skb_checksum_help(skb);
+		goto no_csum;
 	}
-
+	/* update TX checksum flag */
+	first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
+	vlan_macip_lens = skb_checksum_start_offset(skb) -
+			  skb_network_offset(skb);
+no_csum:
 	/* vlan_macip_lens: MACLEN, VLAN tag */
 	vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT;
 	vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
 
-	ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens,
-			    type_tucmd, mss_l4len_idx);
+	ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
 }
 
 static __le32 ixgbevf_tx_cmd_type(u32 tx_flags)
@@ -3444,7 +3434,7 @@
 
 	/* use index 1 context for TSO/FSO/FCOE */
 	if (tx_flags & IXGBE_TX_FLAGS_TSO)
-		olinfo_status |= cpu_to_le32(1 << IXGBE_ADVTXD_IDX_SHIFT);
+		olinfo_status |= cpu_to_le32(1u << IXGBE_ADVTXD_IDX_SHIFT);
 
 	/* Check Context must be set if Tx switch is enabled, which it
 	 * always is for case where virtual functions are running
@@ -3694,19 +3684,23 @@
 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct sockaddr *addr = p;
+	int err;
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
-	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-	memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
-
 	spin_lock_bh(&adapter->mbx_lock);
 
-	hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0);
+	err = hw->mac.ops.set_rar(hw, 0, addr->sa_data, 0);
 
 	spin_unlock_bh(&adapter->mbx_lock);
 
+	if (err)
+		return -EPERM;
+
+	ether_addr_copy(hw->mac.addr, addr->sa_data);
+	ether_addr_copy(netdev->dev_addr, addr->sa_data);
+
 	return 0;
 }
 
@@ -3745,7 +3739,7 @@
 	netdev->mtu = new_mtu;
 
 	/* notify the PF of our intent to use this size of frame */
-	ixgbevf_rlpml_set_vf(hw, max_frame);
+	hw->mac.ops.set_rlpml(hw, max_frame);
 
 	return 0;
 }
@@ -4011,22 +4005,25 @@
 	}
 
 	netdev->hw_features = NETIF_F_SG |
-			      NETIF_F_IP_CSUM |
-			      NETIF_F_IPV6_CSUM |
 			      NETIF_F_TSO |
 			      NETIF_F_TSO6 |
-			      NETIF_F_RXCSUM;
+			      NETIF_F_RXCSUM |
+			      NETIF_F_HW_CSUM |
+			      NETIF_F_SCTP_CRC;
 
 	netdev->features = netdev->hw_features |
 			   NETIF_F_HW_VLAN_CTAG_TX |
 			   NETIF_F_HW_VLAN_CTAG_RX |
 			   NETIF_F_HW_VLAN_CTAG_FILTER;
 
-	netdev->vlan_features |= NETIF_F_TSO |
+	netdev->vlan_features |= NETIF_F_SG |
+				 NETIF_F_TSO |
 				 NETIF_F_TSO6 |
-				 NETIF_F_IP_CSUM |
-				 NETIF_F_IPV6_CSUM |
-				 NETIF_F_SG;
+				 NETIF_F_HW_CSUM |
+				 NETIF_F_SCTP_CRC;
+
+	netdev->mpls_features |= NETIF_F_HW_CSUM;
+	netdev->hw_enc_features |= NETIF_F_HW_CSUM;
 
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
@@ -4248,15 +4245,17 @@
  **/
 static int __init ixgbevf_init_module(void)
 {
-	int ret;
-
 	pr_info("%s - version %s\n", ixgbevf_driver_string,
 		ixgbevf_driver_version);
 
 	pr_info("%s\n", ixgbevf_copyright);
+	ixgbevf_wq = create_singlethread_workqueue(ixgbevf_driver_name);
+	if (!ixgbevf_wq) {
+		pr_err("%s: Failed to create workqueue\n", ixgbevf_driver_name);
+		return -ENOMEM;
+	}
 
-	ret = pci_register_driver(&ixgbevf_driver);
-	return ret;
+	return pci_register_driver(&ixgbevf_driver);
 }
 
 module_init(ixgbevf_init_module);
@@ -4270,6 +4269,10 @@
 static void __exit ixgbevf_exit_module(void)
 {
 	pci_unregister_driver(&ixgbevf_driver);
+	if (ixgbevf_wq) {
+		destroy_workqueue(ixgbevf_wq);
+		ixgbevf_wq = NULL;
+	}
 }
 
 #ifdef DEBUG
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbevf/mbx.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbevf/mbx.c
@@ -346,3 +346,14 @@
 	.check_for_rst	= ixgbevf_check_for_rst_vf,
 };
 
+/* Mailbox operations when running on Hyper-V.
+ * On Hyper-V, PF/VF communication is not through the
+ * hardware mailbox; this communication is through
+ * a software mediated path.
+ * Most mail box operations are noop while running on
+ * Hyper-V.
+ */
+const struct ixgbe_mbx_operations ixgbevf_hv_mbx_ops = {
+	.init_params	= ixgbevf_init_mbx_params_vf,
+	.check_for_rst	= ixgbevf_check_for_rst_vf,
+};
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -27,6 +27,12 @@
 #include "vf.h"
 #include "ixgbevf.h"
 
+/* On Hyper-V, to reset, we need to read from this offset
+ * from the PCI config space. This is the mechanism used on
+ * Hyper-V to support PF/VF communication.
+ */
+#define IXGBE_HV_RESET_OFFSET           0x201
+
 /**
  *  ixgbevf_start_hw_vf - Prepare hardware for Tx/Rx
  *  @hw: pointer to hardware structure
@@ -117,13 +123,36 @@
 	    msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_NACK))
 		return IXGBE_ERR_INVALID_MAC_ADDR;
 
-	ether_addr_copy(hw->mac.perm_addr, addr);
+	if (msgbuf[0] == (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK))
+		ether_addr_copy(hw->mac.perm_addr, addr);
+
 	hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD];
 
 	return 0;
 }
 
 /**
+ * Hyper-V variant; the VF/PF communication is through the PCI
+ * config space.
+ */
+static s32 ixgbevf_hv_reset_hw_vf(struct ixgbe_hw *hw)
+{
+#if IS_ENABLED(CONFIG_PCI_MMCONFIG)
+	struct ixgbevf_adapter *adapter = hw->back;
+	int i;
+
+	for (i = 0; i < 6; i++)
+		pci_read_config_byte(adapter->pdev,
+				     (i + IXGBE_HV_RESET_OFFSET),
+				     &hw->mac.perm_addr[i]);
+	return 0;
+#else
+	pr_err("PCI_MMCONFIG needs to be enabled for Hyper-V\n");
+	return -EOPNOTSUPP;
+#endif
+}
+
+/**
  *  ixgbevf_stop_hw_vf - Generic stop Tx/Rx units
  *  @hw: pointer to hardware structure
  *
@@ -256,6 +285,11 @@
 	return ret_val;
 }
 
+static s32 ixgbevf_hv_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr)
+{
+	return -EOPNOTSUPP;
+}
+
 /**
  * ixgbevf_get_reta_locked - get the RSS redirection table (RETA) contents.
  * @adapter: pointer to the port handle
@@ -406,12 +440,34 @@
 
 	/* if nacked the address was rejected, use "perm_addr" */
 	if (!ret_val &&
-	    (msgbuf[0] == (IXGBE_VF_SET_MAC_ADDR | IXGBE_VT_MSGTYPE_NACK)))
+	    (msgbuf[0] == (IXGBE_VF_SET_MAC_ADDR | IXGBE_VT_MSGTYPE_NACK))) {
 		ixgbevf_get_mac_addr_vf(hw, hw->mac.addr);
+		return IXGBE_ERR_MBX;
+	}
 
 	return ret_val;
 }
 
+/**
+ *  ixgbevf_hv_set_rar_vf - set device MAC address Hyper-V variant
+ *  @hw: pointer to hardware structure
+ *  @index: Receive address register to write
+ *  @addr: Address to put into receive address register
+ *  @vmdq: Unused in this implementation
+ *
+ * We don't really allow setting the device MAC address. However,
+ * if the address being set is the permanent MAC address we will
+ * permit that.
+ **/
+static s32 ixgbevf_hv_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr,
+				 u32 vmdq)
+{
+	if (ether_addr_equal(addr, hw->mac.perm_addr))
+		return 0;
+
+	return -EOPNOTSUPP;
+}
+
 static void ixgbevf_write_msg_read_ack(struct ixgbe_hw *hw,
 				       u32 *msg, u16 size)
 {
@@ -469,6 +525,15 @@
 }
 
 /**
+ * Hyper-V variant - just a stub.
+ */
+static s32 ixgbevf_hv_update_mc_addr_list_vf(struct ixgbe_hw *hw,
+					     struct net_device *netdev)
+{
+	return -EOPNOTSUPP;
+}
+
+/**
  *  ixgbevf_update_xcast_mode - Update Multicast mode
  *  @hw: pointer to the HW structure
  *  @netdev: pointer to net device structure
@@ -509,6 +574,16 @@
 }
 
 /**
+ * Hyper-V variant - just a stub.
+ */
+static s32 ixgbevf_hv_update_xcast_mode(struct ixgbe_hw *hw,
+					struct net_device *netdev,
+					int xcast_mode)
+{
+	return -EOPNOTSUPP;
+}
+
+/**
  *  ixgbevf_set_vfta_vf - Set/Unset VLAN filter table address
  *  @hw: pointer to the HW structure
  *  @vlan: 12 bit VLAN ID
@@ -547,6 +622,15 @@
 }
 
 /**
+ * Hyper-V variant - just a stub.
+ */
+static s32 ixgbevf_hv_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+				  bool vlan_on)
+{
+	return -EOPNOTSUPP;
+}
+
+/**
  *  ixgbevf_setup_mac_link_vf - Setup MAC link settings
  *  @hw: pointer to hardware structure
  *  @speed: Unused in this implementation
@@ -652,11 +736,72 @@
 }
 
 /**
- *  ixgbevf_rlpml_set_vf - Set the maximum receive packet length
+ * Hyper-V variant; there is no mailbox communication.
+ */
+static s32 ixgbevf_hv_check_mac_link_vf(struct ixgbe_hw *hw,
+					ixgbe_link_speed *speed,
+					bool *link_up,
+					bool autoneg_wait_to_complete)
+{
+	struct ixgbe_mbx_info *mbx = &hw->mbx;
+	struct ixgbe_mac_info *mac = &hw->mac;
+	u32 links_reg;
+
+	/* If we were hit with a reset drop the link */
+	if (!mbx->ops.check_for_rst(hw) || !mbx->timeout)
+		mac->get_link_status = true;
+
+	if (!mac->get_link_status)
+		goto out;
+
+	/* if link status is down no point in checking to see if pf is up */
+	links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+	if (!(links_reg & IXGBE_LINKS_UP))
+		goto out;
+
+	/* for SFP+ modules and DA cables on 82599 it can take up to 500usecs
+	 * before the link status is correct
+	 */
+	if (mac->type == ixgbe_mac_82599_vf) {
+		int i;
+
+		for (i = 0; i < 5; i++) {
+			udelay(100);
+			links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+
+			if (!(links_reg & IXGBE_LINKS_UP))
+				goto out;
+		}
+	}
+
+	switch (links_reg & IXGBE_LINKS_SPEED_82599) {
+	case IXGBE_LINKS_SPEED_10G_82599:
+		*speed = IXGBE_LINK_SPEED_10GB_FULL;
+		break;
+	case IXGBE_LINKS_SPEED_1G_82599:
+		*speed = IXGBE_LINK_SPEED_1GB_FULL;
+		break;
+	case IXGBE_LINKS_SPEED_100_82599:
+		*speed = IXGBE_LINK_SPEED_100_FULL;
+		break;
+	}
+
+	/* if we passed all the tests above then the link is up and we no
+	 * longer need to check for link
+	 */
+	mac->get_link_status = false;
+
+out:
+	*link_up = !mac->get_link_status;
+	return 0;
+}
+
+/**
+ *  ixgbevf_set_rlpml_vf - Set the maximum receive packet length
  *  @hw: pointer to the HW structure
  *  @max_size: value to assign to max frame size
  **/
-void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size)
+static void ixgbevf_set_rlpml_vf(struct ixgbe_hw *hw, u16 max_size)
 {
 	u32 msgbuf[2];
 
@@ -666,11 +811,30 @@
 }
 
 /**
- *  ixgbevf_negotiate_api_version - Negotiate supported API version
+ * ixgbevf_hv_set_rlpml_vf - Set the maximum receive packet length
+ * @hw: pointer to the HW structure
+ * @max_size: value to assign to max frame size
+ * Hyper-V variant.
+ **/
+static void ixgbevf_hv_set_rlpml_vf(struct ixgbe_hw *hw, u16 max_size)
+{
+	u32 reg;
+
+	/* If we are on Hyper-V, we implement this functionality
+	 * differently.
+	 */
+	reg =  IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(0));
+	/* CRC == 4 */
+	reg |= ((max_size + 4) | IXGBE_RXDCTL_RLPML_EN);
+	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(0), reg);
+}
+
+/**
+ *  ixgbevf_negotiate_api_version_vf - Negotiate supported API version
  *  @hw: pointer to the HW structure
  *  @api: integer containing requested API version
  **/
-int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api)
+static int ixgbevf_negotiate_api_version_vf(struct ixgbe_hw *hw, int api)
 {
 	int err;
 	u32 msg[3];
@@ -699,6 +863,21 @@
 	return err;
 }
 
+/**
+ *  ixgbevf_hv_negotiate_api_version_vf - Negotiate supported API version
+ *  @hw: pointer to the HW structure
+ *  @api: integer containing requested API version
+ *  Hyper-V version - only ixgbe_mbox_api_10 supported.
+ **/
+static int ixgbevf_hv_negotiate_api_version_vf(struct ixgbe_hw *hw, int api)
+{
+	/* Hyper-V only supports api version ixgbe_mbox_api_10 */
+	if (api != ixgbe_mbox_api_10)
+		return IXGBE_ERR_INVALID_ARGUMENT;
+
+	return 0;
+}
+
 int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
 		       unsigned int *default_tc)
 {
@@ -765,11 +944,30 @@
 	.stop_adapter		= ixgbevf_stop_hw_vf,
 	.setup_link		= ixgbevf_setup_mac_link_vf,
 	.check_link		= ixgbevf_check_mac_link_vf,
+	.negotiate_api_version	= ixgbevf_negotiate_api_version_vf,
 	.set_rar		= ixgbevf_set_rar_vf,
 	.update_mc_addr_list	= ixgbevf_update_mc_addr_list_vf,
 	.update_xcast_mode	= ixgbevf_update_xcast_mode,
 	.set_uc_addr		= ixgbevf_set_uc_addr_vf,
 	.set_vfta		= ixgbevf_set_vfta_vf,
+	.set_rlpml		= ixgbevf_set_rlpml_vf,
+};
+
+static const struct ixgbe_mac_operations ixgbevf_hv_mac_ops = {
+	.init_hw		= ixgbevf_init_hw_vf,
+	.reset_hw		= ixgbevf_hv_reset_hw_vf,
+	.start_hw		= ixgbevf_start_hw_vf,
+	.get_mac_addr		= ixgbevf_get_mac_addr_vf,
+	.stop_adapter		= ixgbevf_stop_hw_vf,
+	.setup_link		= ixgbevf_setup_mac_link_vf,
+	.check_link		= ixgbevf_hv_check_mac_link_vf,
+	.negotiate_api_version	= ixgbevf_hv_negotiate_api_version_vf,
+	.set_rar		= ixgbevf_hv_set_rar_vf,
+	.update_mc_addr_list	= ixgbevf_hv_update_mc_addr_list_vf,
+	.update_xcast_mode	= ixgbevf_hv_update_xcast_mode,
+	.set_uc_addr		= ixgbevf_hv_set_uc_addr_vf,
+	.set_vfta		= ixgbevf_hv_set_vfta_vf,
+	.set_rlpml		= ixgbevf_hv_set_rlpml_vf,
 };
 
 const struct ixgbevf_info ixgbevf_82599_vf_info = {
@@ -777,17 +975,37 @@
 	.mac_ops = &ixgbevf_mac_ops,
 };
 
+const struct ixgbevf_info ixgbevf_82599_vf_hv_info = {
+	.mac = ixgbe_mac_82599_vf,
+	.mac_ops = &ixgbevf_hv_mac_ops,
+};
+
 const struct ixgbevf_info ixgbevf_X540_vf_info = {
 	.mac = ixgbe_mac_X540_vf,
 	.mac_ops = &ixgbevf_mac_ops,
 };
 
+const struct ixgbevf_info ixgbevf_X540_vf_hv_info = {
+	.mac = ixgbe_mac_X540_vf,
+	.mac_ops = &ixgbevf_hv_mac_ops,
+};
+
 const struct ixgbevf_info ixgbevf_X550_vf_info = {
 	.mac = ixgbe_mac_X550_vf,
 	.mac_ops = &ixgbevf_mac_ops,
 };
 
+const struct ixgbevf_info ixgbevf_X550_vf_hv_info = {
+	.mac = ixgbe_mac_X550_vf,
+	.mac_ops = &ixgbevf_hv_mac_ops,
+};
+
 const struct ixgbevf_info ixgbevf_X550EM_x_vf_info = {
 	.mac = ixgbe_mac_X550EM_x_vf,
 	.mac_ops = &ixgbevf_mac_ops,
 };
+
+const struct ixgbevf_info ixgbevf_X550EM_x_vf_hv_info = {
+	.mac = ixgbe_mac_X550EM_x_vf,
+	.mac_ops = &ixgbevf_hv_mac_ops,
+};
--- linux-4.4.0.orig/drivers/net/ethernet/intel/ixgbevf/vf.h
+++ linux-4.4.0/drivers/net/ethernet/intel/ixgbevf/vf.h
@@ -51,6 +51,7 @@
 	s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *);
 	s32 (*stop_adapter)(struct ixgbe_hw *);
 	s32 (*get_bus_info)(struct ixgbe_hw *);
+	s32 (*negotiate_api_version)(struct ixgbe_hw *hw, int api);
 
 	/* Link */
 	s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);
@@ -68,6 +69,7 @@
 	s32 (*disable_mc)(struct ixgbe_hw *);
 	s32 (*clear_vfta)(struct ixgbe_hw *);
 	s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool);
+	void (*set_rlpml)(struct ixgbe_hw *, u16);
 };
 
 enum ixgbe_mac_type {
@@ -207,8 +209,6 @@
 
 #define IXGBE_READ_REG_ARRAY(h, r, o) ixgbe_read_reg_array(h, r, o)
 
-void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size);
-int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api);
 int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
 		       unsigned int *default_tc);
 int ixgbevf_get_reta_locked(struct ixgbe_hw *hw, u32 *reta, int num_rx_queues);
--- linux-4.4.0.orig/drivers/net/ethernet/jme.c
+++ linux-4.4.0/drivers/net/ethernet/jme.c
@@ -270,11 +270,17 @@
 }
 
 static inline void
-jme_clear_pm(struct jme_adapter *jme)
+jme_clear_pm_enable_wol(struct jme_adapter *jme)
 {
 	jwrite32(jme, JME_PMCS, PMCS_STMASK | jme->reg_pmcs);
 }
 
+static inline void
+jme_clear_pm_disable_wol(struct jme_adapter *jme)
+{
+	jwrite32(jme, JME_PMCS, PMCS_STMASK);
+}
+
 static int
 jme_reload_eeprom(struct jme_adapter *jme)
 {
@@ -1853,7 +1859,7 @@
 	struct jme_adapter *jme = netdev_priv(netdev);
 	int rc;
 
-	jme_clear_pm(jme);
+	jme_clear_pm_disable_wol(jme);
 	JME_NAPI_ENABLE(jme);
 
 	tasklet_init(&jme->linkch_task, jme_link_change_tasklet,
@@ -1925,11 +1931,11 @@
 static void
 jme_powersave_phy(struct jme_adapter *jme)
 {
-	if (jme->reg_pmcs) {
+	if (jme->reg_pmcs && device_may_wakeup(&jme->pdev->dev)) {
 		jme_set_100m_half(jme);
 		if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
 			jme_wait_link(jme);
-		jme_clear_pm(jme);
+		jme_clear_pm_enable_wol(jme);
 	} else {
 		jme_phy_off(jme);
 	}
@@ -2646,9 +2652,6 @@
 	if (wol->wolopts & WAKE_MAGIC)
 		jme->reg_pmcs |= PMCS_MFEN;
 
-	jwrite32(jme, JME_PMCS, jme->reg_pmcs);
-	device_set_wakeup_enable(&jme->pdev->dev, !!(jme->reg_pmcs));
-
 	return 0;
 }
 
@@ -3172,8 +3175,8 @@
 	jme->mii_if.mdio_read = jme_mdio_read;
 	jme->mii_if.mdio_write = jme_mdio_write;
 
-	jme_clear_pm(jme);
-	device_set_wakeup_enable(&pdev->dev, true);
+	jme_clear_pm_disable_wol(jme);
+	device_init_wakeup(&pdev->dev, true);
 
 	jme_set_phyfifo_5level(jme);
 	jme->pcirev = pdev->revision;
@@ -3304,7 +3307,7 @@
 	if (!netif_running(netdev))
 		return 0;
 
-	jme_clear_pm(jme);
+	jme_clear_pm_disable_wol(jme);
 	jme_phy_on(jme);
 	if (test_bit(JME_FLAG_SSET, &jme->flags))
 		jme_set_settings(netdev, &jme->old_ecmd);
@@ -3312,13 +3315,14 @@
 		jme_reset_phy_processor(jme);
 	jme_phy_calibration(jme);
 	jme_phy_setEA(jme);
-	jme_start_irq(jme);
 	netif_device_attach(netdev);
 
 	atomic_inc(&jme->link_changing);
 
 	jme_reset_link(jme);
 
+	jme_start_irq(jme);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/korina.c
+++ linux-4.4.0/drivers/net/ethernet/korina.c
@@ -216,7 +216,7 @@
 			dev_kfree_skb_any(skb);
 			spin_unlock_irqrestore(&lp->lock, flags);
 
-			return NETDEV_TX_BUSY;
+			return NETDEV_TX_OK;
 		}
 	}
 
@@ -900,10 +900,10 @@
 				DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR,
 				&lp->rx_dma_regs->dmasm);
 
-	korina_free_ring(dev);
-
 	napi_disable(&lp->napi);
 
+	korina_free_ring(dev);
+
 	if (korina_init(dev) < 0) {
 		printk(KERN_ERR "%s: cannot restart device\n", dev->name);
 		return;
@@ -1064,12 +1064,12 @@
 	tmp = tmp | DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR;
 	writel(tmp, &lp->rx_dma_regs->dmasm);
 
-	korina_free_ring(dev);
-
 	napi_disable(&lp->napi);
 
 	cancel_work_sync(&lp->restart_task);
 
+	korina_free_ring(dev);
+
 	free_irq(lp->rx_irq, dev);
 	free_irq(lp->tx_irq, dev);
 	free_irq(lp->ovr_irq, dev);
@@ -1188,7 +1188,7 @@
 	return rc;
 
 probe_err_register:
-	kfree(lp->td_ring);
+	kfree((struct dma_desc *)KSEG0ADDR(lp->td_ring));
 probe_err_td_ring:
 	iounmap(lp->tx_dma_regs);
 probe_err_dma_tx:
@@ -1208,6 +1208,7 @@
 	iounmap(lp->eth_regs);
 	iounmap(lp->rx_dma_regs);
 	iounmap(lp->tx_dma_regs);
+	kfree((struct dma_desc *)KSEG0ADDR(lp->td_ring));
 
 	unregister_netdev(bif->dev);
 	free_netdev(bif->dev);
--- linux-4.4.0.orig/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ linux-4.4.0/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -762,10 +762,10 @@
 
 	if (length <= 8 && (uintptr_t)data & 0x7) {
 		/* Copy unaligned small data fragment to TSO header data area */
-		memcpy(txq->tso_hdrs + txq->tx_curr_desc * TSO_HEADER_SIZE,
+		memcpy(txq->tso_hdrs + tx_index * TSO_HEADER_SIZE,
 		       data, length);
 		desc->buf_ptr = txq->tso_hdrs_dma
-			+ txq->tx_curr_desc * TSO_HEADER_SIZE;
+			+ tx_index * TSO_HEADER_SIZE;
 	} else {
 		/* Alignment is okay, map buffer and hand off to hardware */
 		txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE;
@@ -2884,7 +2884,7 @@
 
 	ret = mv643xx_eth_shared_of_probe(pdev);
 	if (ret)
-		return ret;
+		goto err_put_clk;
 	pd = dev_get_platdata(&pdev->dev);
 
 	msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
@@ -2892,6 +2892,11 @@
 	infer_hw_params(msp);
 
 	return 0;
+
+err_put_clk:
+	if (!IS_ERR(msp->clk))
+		clk_disable_unprepare(msp->clk);
+	return ret;
 }
 
 static int mv643xx_eth_shared_remove(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/net/ethernet/marvell/mvmdio.c
+++ linux-4.4.0/drivers/net/ethernet/marvell/mvmdio.c
@@ -241,7 +241,8 @@
 			dev->regs + MVMDIO_ERR_INT_MASK);
 
 	} else if (dev->err_interrupt == -EPROBE_DEFER) {
-		return -EPROBE_DEFER;
+		ret = -EPROBE_DEFER;
+		goto out_mdio;
 	}
 
 	mutex_init(&dev->lock);
--- linux-4.4.0.orig/drivers/net/ethernet/marvell/mvneta.c
+++ linux-4.4.0/drivers/net/ethernet/marvell/mvneta.c
@@ -226,7 +226,7 @@
 /* Various constants */
 
 /* Coalescing */
-#define MVNETA_TXDONE_COAL_PKTS		1
+#define MVNETA_TXDONE_COAL_PKTS		0	/* interrupt per packet */
 #define MVNETA_RX_COAL_PKTS		32
 #define MVNETA_RX_COAL_USEC		100
 
@@ -818,6 +818,7 @@
 	}
 	mvreg_write(pp, MVNETA_TXQ_CMD, q_map);
 
+	q_map = 0;
 	/* Enable all initialized RXQs. */
 	mvreg_write(pp, MVNETA_RXQ_CMD, BIT(rxq_def));
 }
@@ -914,6 +915,10 @@
 	val &= ~MVNETA_GMAC0_PORT_ENABLE;
 	mvreg_write(pp, MVNETA_GMAC_CTRL_0, val);
 
+	pp->link = 0;
+	pp->duplex = -1;
+	pp->speed = 0;
+
 	udelay(200);
 }
 
@@ -2446,7 +2451,7 @@
 	mvneta_port_enable(pp);
 
 	/* Enable polling on the port */
-	for_each_present_cpu(cpu) {
+	for_each_online_cpu(cpu) {
 		struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 
 		napi_enable(&port->napi);
@@ -2472,7 +2477,7 @@
 
 	phy_stop(pp->phy_dev);
 
-	for_each_present_cpu(cpu) {
+	for_each_online_cpu(cpu) {
 		struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 
 		napi_disable(&port->napi);
@@ -2564,7 +2569,6 @@
 	}
 
 	mvneta_start_dev(pp);
-	mvneta_port_up(pp);
 
 	netdev_update_features(dev);
 
@@ -2902,13 +2906,11 @@
 static int mvneta_stop(struct net_device *dev)
 {
 	struct mvneta_port *pp = netdev_priv(dev);
-	int cpu;
 
 	mvneta_stop_dev(pp);
 	mvneta_mdio_remove(pp);
 	unregister_cpu_notifier(&pp->cpu_notifier);
-	for_each_present_cpu(cpu)
-		smp_call_function_single(cpu, mvneta_percpu_disable, pp, true);
+	on_each_cpu(mvneta_percpu_disable, pp, true);
 	free_percpu_irq(dev->irq, pp->ports);
 	mvneta_cleanup_rxqs(pp);
 	mvneta_cleanup_txqs(pp);
@@ -3056,26 +3058,25 @@
 	const struct mvneta_statistic *s;
 	void __iomem *base = pp->base;
 	u32 high, low, val;
+	u64 val64;
 	int i;
 
 	for (i = 0, s = mvneta_statistics;
 	     s < mvneta_statistics + ARRAY_SIZE(mvneta_statistics);
 	     s++, i++) {
-		val = 0;
-
 		switch (s->type) {
 		case T_REG_32:
 			val = readl_relaxed(base + s->offset);
+			pp->ethtool_stats[i] += val;
 			break;
 		case T_REG_64:
 			/* Docs say to read low 32-bit then high */
 			low = readl_relaxed(base + s->offset);
 			high = readl_relaxed(base + s->offset + 4);
-			val = (u64)high << 32 | low;
+			val64 = (u64)high << 32 | low;
+			pp->ethtool_stats[i] += val64;
 			break;
 		}
-
-		pp->ethtool_stats[i] += val;
 	}
 }
 
@@ -3404,7 +3405,7 @@
 	dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
 	dev->hw_features |= dev->features;
 	dev->vlan_features |= dev->features;
-	dev->priv_flags |= IFF_UNICAST_FLT;
+	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 	dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
 
 	err = register_netdev(dev);
--- linux-4.4.0.orig/drivers/net/ethernet/marvell/mvpp2.c
+++ linux-4.4.0/drivers/net/ethernet/marvell/mvpp2.c
@@ -29,6 +29,7 @@
 #include <linux/clk.h>
 #include <linux/hrtimer.h>
 #include <linux/ktime.h>
+#include <linux/if_vlan.h>
 #include <uapi/linux/ppp_defs.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -772,6 +773,17 @@
 	u32 reserved8;
 };
 
+struct mvpp2_txq_pcpu_buf {
+	/* Transmitted SKB */
+	struct sk_buff *skb;
+
+	/* Physical address of transmitted buffer */
+	dma_addr_t phys;
+
+	/* Size transmitted */
+	size_t size;
+};
+
 /* Per-CPU Tx queue control */
 struct mvpp2_txq_pcpu {
 	int cpu;
@@ -787,11 +799,8 @@
 	/* Number of Tx DMA descriptors reserved for each CPU */
 	int reserved_num;
 
-	/* Array of transmitted skb */
-	struct sk_buff **tx_skb;
-
-	/* Array of transmitted buffers' physical addresses */
-	dma_addr_t *tx_buffs;
+	/* Infos about transmitted buffers */
+	struct mvpp2_txq_pcpu_buf *buffs;
 
 	/* Index of last TX DMA descriptor that was inserted */
 	int txq_put_index;
@@ -981,10 +990,11 @@
 			      struct sk_buff *skb,
 			      struct mvpp2_tx_desc *tx_desc)
 {
-	txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb;
-	if (skb)
-		txq_pcpu->tx_buffs[txq_pcpu->txq_put_index] =
-							 tx_desc->buf_phys_addr;
+	struct mvpp2_txq_pcpu_buf *tx_buf =
+		txq_pcpu->buffs + txq_pcpu->txq_put_index;
+	tx_buf->skb = skb;
+	tx_buf->size = tx_desc->data_size;
+	tx_buf->phys = tx_desc->buf_phys_addr + tx_desc->packet_offset;
 	txq_pcpu->txq_put_index++;
 	if (txq_pcpu->txq_put_index == txq_pcpu->size)
 		txq_pcpu->txq_put_index = 0;
@@ -3295,7 +3305,7 @@
 	mvpp2_write(priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);
 
 	/* Clear classifier flow table */
-	memset(&fe.data, 0, MVPP2_CLS_FLOWS_TBL_DATA_WORDS);
+	memset(&fe.data, 0, sizeof(fe.data));
 	for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) {
 		fe.index = index;
 		mvpp2_cls_flow_write(priv, &fe);
@@ -3930,7 +3940,7 @@
 /* Set defaults to the MVPP2 port */
 static void mvpp2_defaults_set(struct mvpp2_port *port)
 {
-	int tx_port_num, val, queue, ptxq, lrxq;
+	int tx_port_num, val, queue, lrxq;
 
 	/* Configure port to loopback if needed */
 	if (port->flags & MVPP2_F_LOOPBACK)
@@ -3950,11 +3960,9 @@
 	mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0);
 
 	/* Close bandwidth for all queues */
-	for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) {
-		ptxq = mvpp2_txq_phys(port->id, queue);
+	for (queue = 0; queue < MVPP2_MAX_TXQ; queue++)
 		mvpp2_write(port->priv,
-			    MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(ptxq), 0);
-	}
+			    MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(queue), 0);
 
 	/* Set refill period to 1 usec, refill tokens
 	 * and bucket size to maximum
@@ -4259,7 +4267,7 @@
 }
 
 /* Set Tx descriptors fields relevant for CSUM calculation */
-static u32 mvpp2_txq_desc_csum(int l3_offs, int l3_proto,
+static u32 mvpp2_txq_desc_csum(int l3_offs, __be16 l3_proto,
 			       int ip_hdr_len, int l4_proto)
 {
 	u32 command;
@@ -4403,17 +4411,15 @@
 	int i;
 
 	for (i = 0; i < num; i++) {
-		dma_addr_t buf_phys_addr =
-				    txq_pcpu->tx_buffs[txq_pcpu->txq_get_index];
-		struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index];
+		struct mvpp2_txq_pcpu_buf *tx_buf =
+			txq_pcpu->buffs + txq_pcpu->txq_get_index;
 
-		mvpp2_txq_inc_get(txq_pcpu);
+		dma_unmap_single(port->dev->dev.parent, tx_buf->phys,
+				 tx_buf->size, DMA_TO_DEVICE);
+		if (tx_buf->skb)
+			dev_kfree_skb_any(tx_buf->skb);
 
-		dma_unmap_single(port->dev->dev.parent, buf_phys_addr,
-				 skb_headlen(skb), DMA_TO_DEVICE);
-		if (!skb)
-			continue;
-		dev_kfree_skb_any(skb);
+		mvpp2_txq_inc_get(txq_pcpu);
 	}
 }
 
@@ -4664,15 +4670,10 @@
 	for_each_present_cpu(cpu) {
 		txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
 		txq_pcpu->size = txq->size;
-		txq_pcpu->tx_skb = kmalloc(txq_pcpu->size *
-					   sizeof(*txq_pcpu->tx_skb),
-					   GFP_KERNEL);
-		if (!txq_pcpu->tx_skb)
-			goto error;
-
-		txq_pcpu->tx_buffs = kmalloc(txq_pcpu->size *
-					     sizeof(dma_addr_t), GFP_KERNEL);
-		if (!txq_pcpu->tx_buffs)
+		txq_pcpu->buffs = kmalloc(txq_pcpu->size *
+					  sizeof(struct mvpp2_txq_pcpu_buf),
+					  GFP_KERNEL);
+		if (!txq_pcpu->buffs)
 			goto error;
 
 		txq_pcpu->count = 0;
@@ -4686,8 +4687,7 @@
 error:
 	for_each_present_cpu(cpu) {
 		txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
-		kfree(txq_pcpu->tx_skb);
-		kfree(txq_pcpu->tx_buffs);
+		kfree(txq_pcpu->buffs);
 	}
 
 	dma_free_coherent(port->dev->dev.parent,
@@ -4706,8 +4706,7 @@
 
 	for_each_present_cpu(cpu) {
 		txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
-		kfree(txq_pcpu->tx_skb);
-		kfree(txq_pcpu->tx_buffs);
+		kfree(txq_pcpu->buffs);
 	}
 
 	if (txq->descs)
@@ -4721,7 +4720,7 @@
 	txq->descs_phys        = 0;
 
 	/* Set minimum bandwidth for disabled TXQs */
-	mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->id), 0);
+	mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->log_id), 0);
 
 	/* Set Tx descriptors queue starting address and size */
 	mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id);
@@ -5032,14 +5031,15 @@
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		int ip_hdr_len = 0;
 		u8 l4_proto;
+		__be16 l3_proto = vlan_get_protocol(skb);
 
-		if (skb->protocol == htons(ETH_P_IP)) {
+		if (l3_proto == htons(ETH_P_IP)) {
 			struct iphdr *ip4h = ip_hdr(skb);
 
 			/* Calculate IPv4 checksum and L4 checksum */
 			ip_hdr_len = ip4h->ihl;
 			l4_proto = ip4h->protocol;
-		} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		} else if (l3_proto == htons(ETH_P_IPV6)) {
 			struct ipv6hdr *ip6h = ipv6_hdr(skb);
 
 			/* Read l4_protocol from one of IPv6 extra headers */
@@ -5051,7 +5051,7 @@
 		}
 
 		return mvpp2_txq_desc_csum(skb_network_offset(skb),
-				skb->protocol, ip_hdr_len, l4_proto);
+					   l3_proto, ip_hdr_len, l4_proto);
 	}
 
 	return MVPP2_TXD_L4_CSUM_NOT | MVPP2_TXD_IP_CSUM_DISABLE;
@@ -5666,6 +5666,7 @@
 	int id = port->id;
 	bool allmulti = dev->flags & IFF_ALLMULTI;
 
+retry:
 	mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC);
 	mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti);
 	mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti);
@@ -5673,9 +5674,13 @@
 	/* Remove all port->id's mcast enries */
 	mvpp2_prs_mcast_del_all(priv, id);
 
-	if (allmulti && !netdev_mc_empty(dev)) {
-		netdev_for_each_mc_addr(ha, dev)
-			mvpp2_prs_mac_da_accept(priv, id, ha->addr, true);
+	if (!allmulti) {
+		netdev_for_each_mc_addr(ha, dev) {
+			if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) {
+				allmulti = true;
+				goto retry;
+			}
+		}
 	}
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/marvell/skge.c
+++ linux-4.4.0/drivers/net/ethernet/marvell/skge.c
@@ -152,8 +152,10 @@
 	memset(p, 0, regs->len);
 	memcpy_fromio(p, io, B3_RAM_ADDR);
 
-	memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1,
-		      regs->len - B3_RI_WTO_R1);
+	if (regs->len > B3_RI_WTO_R1) {
+		memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1,
+			      regs->len - B3_RI_WTO_R1);
+	}
 }
 
 /* Wake on Lan only supported on Yukon chips with rev 1 or above */
@@ -3112,7 +3114,7 @@
 	skb_put(skb, len);
 
 	if (dev->features & NETIF_F_RXCSUM) {
-		skb->csum = csum;
+		skb->csum = le16_to_cpu(csum);
 		skb->ip_summed = CHECKSUM_COMPLETE;
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/marvell/sky2.c
+++ linux-4.4.0/drivers/net/ethernet/marvell/sky2.c
@@ -46,6 +46,7 @@
 #include <linux/mii.h>
 #include <linux/of_device.h>
 #include <linux/of_net.h>
+#include <linux/dmi.h>
 
 #include <asm/irq.h>
 
@@ -93,7 +94,7 @@
 module_param(copybreak, int, 0);
 MODULE_PARM_DESC(copybreak, "Receive copy threshold");
 
-static int disable_msi = 0;
+static int disable_msi = -1;
 module_param(disable_msi, int, 0);
 MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
 
@@ -214,7 +215,7 @@
 
 static inline u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
 {
-	u16 v;
+	u16 v = 0;
 	__gm_phy_read(hw, port, reg, &v);
 	return v;
 }
@@ -4923,6 +4924,38 @@
 	return buf;
 }
 
+static const struct dmi_system_id msi_blacklist[] = {
+	{
+		.ident = "Dell Inspiron 1545",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1545"),
+		},
+	},
+	{
+		.ident = "Gateway P-79",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Gateway"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P-79"),
+		},
+	},
+	{
+		.ident = "ASUS P6T",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "P6T"),
+		},
+	},
+	{
+		.ident = "ASUS P6X",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "P6X"),
+		},
+	},
+	{}
+};
+
 static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *dev, *dev1;
@@ -5034,6 +5067,9 @@
 		goto err_out_free_pci;
 	}
 
+	if (disable_msi == -1)
+		disable_msi = !!dmi_check_system(msi_blacklist);
+
 	if (!disable_msi && pci_enable_msi(pdev) == 0) {
 		err = sky2_test_msi(hw);
 		if (err) {
@@ -5079,7 +5115,7 @@
 	INIT_WORK(&hw->restart_work, sky2_restart);
 
 	pci_set_drvdata(pdev, hw);
-	pdev->d3_delay = 150;
+	pdev->d3_delay = 300;
 
 	return 0;
 
@@ -5220,6 +5256,19 @@
 
 static void sky2_shutdown(struct pci_dev *pdev)
 {
+	struct sky2_hw *hw = pci_get_drvdata(pdev);
+	int port;
+
+	for (port = 0; port < hw->ports; port++) {
+		struct net_device *ndev = hw->dev[port];
+
+		rtnl_lock();
+		if (netif_running(ndev)) {
+			dev_close(ndev);
+			netif_device_detach(ndev);
+		}
+		rtnl_unlock();
+	}
 	sky2_suspend(&pdev->dev);
 	pci_wake_from_d3(pdev, device_may_wakeup(&pdev->dev));
 	pci_set_power_state(pdev, PCI_D3hot);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/alloc.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/alloc.c
@@ -339,7 +339,7 @@
 static u32 __mlx4_alloc_from_zone(struct mlx4_zone_entry *zone, int count,
 				  int align, u32 skip_mask, u32 *puid)
 {
-	u32 uid;
+	u32 uid = 0;
 	u32 res;
 	struct mlx4_zone_allocator *zone_alloc = zone->allocator;
 	struct mlx4_zone_entry *curr_node;
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/catas.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/catas.c
@@ -158,7 +158,7 @@
 	return -ETIMEDOUT;
 }
 
-static int mlx4_comm_internal_err(u32 slave_read)
+int mlx4_comm_internal_err(u32 slave_read)
 {
 	return (u32)COMM_CHAN_EVENT_INTERNAL_ERR ==
 		(slave_read & (u32)COMM_CHAN_EVENT_INTERNAL_ERR) ? 1 : 0;
@@ -182,10 +182,17 @@
 		err = mlx4_reset_slave(dev);
 	else
 		err = mlx4_reset_master(dev);
-	BUG_ON(err != 0);
 
+	if (!err) {
+		mlx4_err(dev, "device was reset successfully\n");
+	} else {
+		/* EEH could have disabled the PCI channel during reset. That's
+		 * recoverable and the PCI error flow will handle it.
+		 */
+		if (!pci_channel_offline(dev->persist->pdev))
+			BUG_ON(1);
+	}
 	dev->persist->state |= MLX4_DEVICE_STATE_INTERNAL_ERROR;
-	mlx4_err(dev, "device was reset successfully\n");
 	mutex_unlock(&persist->device_state_mutex);
 
 	/* At that step HW was already reset, now notify clients */
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -2278,6 +2278,17 @@
 		rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read));
 		if (wr_toggle == 0xffffffff || rd_toggle == 0xffffffff) {
 			/* PCI might be offline */
+
+			/* If device removal has been requested,
+			 * do not continue retrying.
+			 */
+			if (dev->persist->interface_state &
+			    MLX4_INTERFACE_STATE_NOWAIT) {
+				mlx4_warn(dev,
+					  "communication channel is offline\n");
+				return -EIO;
+			}
+
 			msleep(100);
 			wr_toggle = swab32(readl(&priv->mfunc.comm->
 					   slave_write));
@@ -2440,6 +2451,7 @@
 	kfree(priv->mfunc.master.slave_state);
 err_comm:
 	iounmap(priv->mfunc.comm);
+	priv->mfunc.comm = NULL;
 err_vhcr:
 	dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
 			  priv->mfunc.vhcr,
@@ -2507,6 +2519,13 @@
 	int slave;
 	u32 slave_read;
 
+	/* If the comm channel has not yet been initialized,
+	 * skip reporting the internal error event to all
+	 * the communication channels.
+	 */
+	if (!priv->mfunc.comm)
+		return;
+
 	/* Report an internal error event to all
 	 * communication channels.
 	 */
@@ -2541,6 +2560,7 @@
 	}
 
 	iounmap(priv->mfunc.comm);
+	priv->mfunc.comm = NULL;
 }
 
 void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask)
@@ -2625,6 +2645,7 @@
 		down(&priv->cmd.event_sem);
 
 	kfree(priv->cmd.context);
+	priv->cmd.context = NULL;
 
 	up(&priv->cmd.poll_sem);
 }
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/cq.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/cq.c
@@ -101,13 +101,19 @@
 {
 	struct mlx4_cq *cq;
 
+	rcu_read_lock();
 	cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree,
 			       cqn & (dev->caps.num_cqs - 1));
+	rcu_read_unlock();
+
 	if (!cq) {
 		mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn);
 		return;
 	}
 
+	/* Acessing the CQ outside of rcu_read_lock is safe, because
+	 * the CQ is freed only after interrupt handling is completed.
+	 */
 	++cq->arm_sn;
 
 	cq->comp(cq);
@@ -118,23 +124,19 @@
 	struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
 	struct mlx4_cq *cq;
 
-	spin_lock(&cq_table->lock);
-
+	rcu_read_lock();
 	cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1));
-	if (cq)
-		atomic_inc(&cq->refcount);
-
-	spin_unlock(&cq_table->lock);
+	rcu_read_unlock();
 
 	if (!cq) {
-		mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn);
+		mlx4_dbg(dev, "Async event for bogus CQ %08x\n", cqn);
 		return;
 	}
 
+	/* Acessing the CQ outside of rcu_read_lock is safe, because
+	 * the CQ is freed only after interrupt handling is completed.
+	 */
 	cq->event(cq, event_type);
-
-	if (atomic_dec_and_test(&cq->refcount))
-		complete(&cq->free);
 }
 
 static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
@@ -301,9 +303,9 @@
 	if (err)
 		return err;
 
-	spin_lock_irq(&cq_table->lock);
+	spin_lock(&cq_table->lock);
 	err = radix_tree_insert(&cq_table->tree, cq->cqn, cq);
-	spin_unlock_irq(&cq_table->lock);
+	spin_unlock(&cq_table->lock);
 	if (err)
 		goto err_icm;
 
@@ -318,7 +320,9 @@
 	if (timestamp_en)
 		cq_context->flags  |= cpu_to_be32(1 << 19);
 
-	cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
+	cq_context->logsize_usrpage =
+		cpu_to_be32((ilog2(nent) << 24) |
+			    mlx4_to_hw_uar_index(dev, uar->index));
 	cq_context->comp_eqn	    = priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn;
 	cq_context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
 
@@ -347,9 +351,9 @@
 	return 0;
 
 err_radix:
-	spin_lock_irq(&cq_table->lock);
+	spin_lock(&cq_table->lock);
 	radix_tree_delete(&cq_table->tree, cq->cqn);
-	spin_unlock_irq(&cq_table->lock);
+	spin_unlock(&cq_table->lock);
 
 err_icm:
 	mlx4_cq_free_icm(dev, cq->cqn);
@@ -368,15 +372,15 @@
 	if (err)
 		mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn);
 
+	spin_lock(&cq_table->lock);
+	radix_tree_delete(&cq_table->tree, cq->cqn);
+	spin_unlock(&cq_table->lock);
+
 	synchronize_irq(priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq);
 	if (priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq !=
 	    priv->eq_table.eq[MLX4_EQ_ASYNC].irq)
 		synchronize_irq(priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
 
-	spin_lock_irq(&cq_table->lock);
-	radix_tree_delete(&cq_table->tree, cq->cqn);
-	spin_unlock_irq(&cq_table->lock);
-
 	if (atomic_dec_and_test(&cq->refcount))
 		complete(&cq->free);
 	wait_for_completion(&cq->free);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_clock.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/en_clock.c
@@ -88,10 +88,17 @@
 	}
 }
 
+#define MLX4_EN_WRAP_AROUND_SEC	10UL
+/* By scheduling the overflow check every 5 seconds, we have a reasonably
+ * good chance we wont miss a wrap around.
+ * TOTO: Use a timer instead of a work queue to increase the guarantee.
+ */
+#define MLX4_EN_OVERFLOW_PERIOD (MLX4_EN_WRAP_AROUND_SEC * HZ / 2)
+
 void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev)
 {
 	bool timeout = time_is_before_jiffies(mdev->last_overflow_check +
-					      mdev->overflow_period);
+					      MLX4_EN_OVERFLOW_PERIOD);
 	unsigned long flags;
 
 	if (timeout) {
@@ -236,11 +243,30 @@
 	.enable		= mlx4_en_phc_enable,
 };
 
+
+/* This function calculates the max shift that enables the user range
+ * of MLX4_EN_WRAP_AROUND_SEC values in the cycles register.
+ */
+static u32 freq_to_shift(u16 freq)
+{
+	u32 freq_khz = freq * 1000;
+	u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC;
+	u64 tmp_rounded =
+		roundup_pow_of_two(max_val_cycles) > max_val_cycles ?
+		roundup_pow_of_two(max_val_cycles) - 1 : UINT_MAX;
+	u64 max_val_cycles_rounded = is_power_of_2(max_val_cycles + 1) ?
+		max_val_cycles : tmp_rounded;
+	/* calculate max possible multiplier in order to fit in 64bit */
+	u64 max_mul = div_u64(0xffffffffffffffffULL, max_val_cycles_rounded);
+
+	/* This comes from the reverse of clocksource_khz2mult */
+	return ilog2(div_u64(max_mul * freq_khz, 1000000));
+}
+
 void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
 {
 	struct mlx4_dev *dev = mdev->dev;
 	unsigned long flags;
-	u64 ns, zero = 0;
 
 	/* mlx4_en_init_timestamp is called for each netdev.
 	 * mdev->ptp_clock is common for all ports, skip initialization if
@@ -254,12 +280,7 @@
 	memset(&mdev->cycles, 0, sizeof(mdev->cycles));
 	mdev->cycles.read = mlx4_en_read_clock;
 	mdev->cycles.mask = CLOCKSOURCE_MASK(48);
-	/* Using shift to make calculation more accurate. Since current HW
-	 * clock frequency is 427 MHz, and cycles are given using a 48 bits
-	 * register, the biggest shift when calculating using u64, is 14
-	 * (max_cycles * multiplier < 2^64)
-	 */
-	mdev->cycles.shift = 14;
+	mdev->cycles.shift = freq_to_shift(dev->caps.hca_core_clock);
 	mdev->cycles.mult =
 		clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
 	mdev->nominal_c_mult = mdev->cycles.mult;
@@ -269,13 +290,6 @@
 			 ktime_to_ns(ktime_get_real()));
 	write_unlock_irqrestore(&mdev->clock_lock, flags);
 
-	/* Calculate period in seconds to call the overflow watchdog - to make
-	 * sure counter is checked at least once every wrap around.
-	 */
-	ns = cyclecounter_cyc2ns(&mdev->cycles, mdev->cycles.mask, zero, &zero);
-	do_div(ns, NSEC_PER_SEC / 2 / HZ);
-	mdev->overflow_period = ns;
-
 	/* Configure the PHC */
 	mdev->ptp_clock_info = mlx4_en_ptp_clock_info;
 	snprintf(mdev->ptp_clock_info.name, 16, "mlx4 ptp");
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -47,7 +47,7 @@
 #define EN_ETHTOOL_SHORT_MASK cpu_to_be16(0xffff)
 #define EN_ETHTOOL_WORD_MASK  cpu_to_be32(0xffffffff)
 
-static int mlx4_en_moderation_update(struct mlx4_en_priv *priv)
+int mlx4_en_moderation_update(struct mlx4_en_priv *priv)
 {
 	int i;
 	int err = 0;
@@ -967,6 +967,22 @@
 	if (!coal->tx_max_coalesced_frames_irq)
 		return -EINVAL;
 
+	if (coal->tx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME ||
+	    coal->rx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME ||
+	    coal->rx_coalesce_usecs_low > MLX4_EN_MAX_COAL_TIME ||
+	    coal->rx_coalesce_usecs_high > MLX4_EN_MAX_COAL_TIME) {
+		netdev_info(dev, "%s: maximum coalesce time supported is %d usecs\n",
+			    __func__, MLX4_EN_MAX_COAL_TIME);
+		return -ERANGE;
+	}
+
+	if (coal->tx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS ||
+	    coal->rx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS) {
+		netdev_info(dev, "%s: maximum coalesced frames supported is %d\n",
+			    __func__, MLX4_EN_MAX_COAL_PKTS);
+		return -ERANGE;
+	}
+
 	priv->rx_frames = (coal->rx_max_coalesced_frames ==
 			   MLX4_EN_AUTO_CONF) ?
 				MLX4_EN_RX_COAL_TARGET :
@@ -1651,6 +1667,7 @@
 		err = mlx4_en_get_flow(dev, cmd, cmd->fs.location);
 		break;
 	case ETHTOOL_GRXCLSRLALL:
+		cmd->data = MAX_NUM_OF_FS_RULES;
 		while ((!err || err == -ENOENT) && priority < cmd->rule_cnt) {
 			err = mlx4_en_get_flow(dev, cmd, i);
 			if (!err)
@@ -1890,6 +1907,8 @@
 	return ret;
 }
 
+#define MLX4_EEPROM_PAGE_LEN 256
+
 static int mlx4_en_get_module_info(struct net_device *dev,
 				   struct ethtool_modinfo *modinfo)
 {
@@ -1924,7 +1943,7 @@
 		break;
 	case MLX4_MODULE_ID_SFP:
 		modinfo->type = ETH_MODULE_SFF_8472;
-		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+		modinfo->eeprom_len = MLX4_EEPROM_PAGE_LEN;
 		break;
 	default:
 		return -ENOSYS;
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -97,6 +97,15 @@
 }
 #endif	/* CONFIG_NET_RX_BUSY_POLL */
 
+static int __mlx4_en_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+			      struct tc_to_netdev *tc)
+{
+	if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+
+	return mlx4_en_setup_tc(dev, tc->tc);
+}
+
 #ifdef CONFIG_RFS_ACCEL
 
 struct mlx4_en_filter {
@@ -424,14 +433,18 @@
 	mutex_lock(&mdev->state_lock);
 	if (mdev->device_up && priv->port_up) {
 		err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
-		if (err)
+		if (err) {
 			en_err(priv, "Failed configuring VLAN filter\n");
+			goto out;
+		}
 	}
-	if (mlx4_register_vlan(mdev->dev, priv->port, vid, &idx))
-		en_dbg(HW, priv, "failed adding vlan %d\n", vid);
-	mutex_unlock(&mdev->state_lock);
+	err = mlx4_register_vlan(mdev->dev, priv->port, vid, &idx);
+	if (err)
+		en_dbg(HW, priv, "Failed adding vlan %d\n", vid);
 
-	return 0;
+out:
+	mutex_unlock(&mdev->state_lock);
+	return err;
 }
 
 static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev,
@@ -439,7 +452,7 @@
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_en_dev *mdev = priv->mdev;
-	int err;
+	int err = 0;
 
 	en_dbg(HW, priv, "Killing VID:%d\n", vid);
 
@@ -456,7 +469,7 @@
 	}
 	mutex_unlock(&mdev->state_lock);
 
-	return 0;
+	return err;
 }
 
 static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)
@@ -1309,8 +1322,10 @@
 	}
 
 	priv->port_stats.tx_timeout++;
-	en_dbg(DRV, priv, "Scheduling watchdog\n");
-	queue_work(mdev->workqueue, &priv->watchdog_task);
+	if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state)) {
+		en_dbg(DRV, priv, "Scheduling port restart\n");
+		queue_work(mdev->workqueue, &priv->restart_task);
+	}
 }
 
 
@@ -1716,6 +1731,17 @@
 		vxlan_get_rx_port(dev);
 #endif
 	priv->port_up = true;
+
+	/* Process all completions if exist to prevent
+	 * the queues freezing if they are full
+	 */
+	for (i = 0; i < priv->rx_ring_num; i++) {
+		local_bh_disable();
+		napi_schedule(&priv->rx_cq[i]->napi);
+		local_bh_enable();
+	}
+
+	clear_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state);
 	netif_tx_start_all_queues(dev);
 	netif_device_attach(dev);
 
@@ -1877,7 +1903,7 @@
 static void mlx4_en_restart(struct work_struct *work)
 {
 	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
-						 watchdog_task);
+						 restart_task);
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct net_device *dev = priv->dev;
 
@@ -2107,7 +2133,7 @@
 	if (netif_running(dev)) {
 		mutex_lock(&mdev->state_lock);
 		if (!mdev->device_up) {
-			/* NIC is probably restarting - let watchdog task reset
+			/* NIC is probably restarting - let restart task reset
 			 * the port */
 			en_dbg(DRV, priv, "Change MTU called with card down!?\n");
 		} else {
@@ -2116,7 +2142,9 @@
 			if (err) {
 				en_err(priv, "Failed restarting port:%d\n",
 					 priv->port);
-				queue_work(mdev->workqueue, &priv->watchdog_task);
+				if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING,
+						      &priv->state))
+					queue_work(mdev->workqueue, &priv->restart_task);
 			}
 		}
 		mutex_unlock(&mdev->state_lock);
@@ -2282,7 +2310,7 @@
 	struct mlx4_en_dev *mdev = en_priv->mdev;
 	u64 mac_u64 = mlx4_mac_to_u64(mac);
 
-	if (!is_valid_ether_addr(mac))
+	if (is_multicast_ether_addr(mac))
 		return -EINVAL;
 
 	return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64);
@@ -2381,8 +2409,6 @@
 	/* set offloads */
 	priv->dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
 				      NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL;
-	priv->dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
-	priv->dev->features    |= NETIF_F_GSO_UDP_TUNNEL;
 }
 
 static void mlx4_en_del_vxlan_offloads(struct work_struct *work)
@@ -2393,8 +2419,6 @@
 	/* unset offloads */
 	priv->dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
 				      NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL);
-	priv->dev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL;
-	priv->dev->features    &= ~NETIF_F_GSO_UDP_TUNNEL;
 
 	ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port,
 				  VXLAN_STEER_BY_OUTER_MAC, 0);
@@ -2503,7 +2527,7 @@
 #endif
 	.ndo_set_features	= mlx4_en_set_features,
 	.ndo_fix_features	= mlx4_en_fix_features,
-	.ndo_setup_tc		= mlx4_en_setup_tc,
+	.ndo_setup_tc		= __mlx4_en_setup_tc,
 #ifdef CONFIG_RFS_ACCEL
 	.ndo_rx_flow_steer	= mlx4_en_filter_rfs,
 #endif
@@ -2544,7 +2568,7 @@
 #endif
 	.ndo_set_features	= mlx4_en_set_features,
 	.ndo_fix_features	= mlx4_en_fix_features,
-	.ndo_setup_tc		= mlx4_en_setup_tc,
+	.ndo_setup_tc		= __mlx4_en_setup_tc,
 #ifdef CONFIG_RFS_ACCEL
 	.ndo_rx_flow_steer	= mlx4_en_filter_rfs,
 #endif
@@ -2840,7 +2864,7 @@
 	priv->counter_index = MLX4_SINK_COUNTER_INDEX(mdev->dev);
 	spin_lock_init(&priv->stats_lock);
 	INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode);
-	INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
+	INIT_WORK(&priv->restart_task, mlx4_en_restart);
 	INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
 	INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
 	INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task);
@@ -3020,6 +3044,11 @@
 		priv->rss_hash_fn = ETH_RSS_HASH_TOP;
 	}
 
+	if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
+		dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+		dev->features    |= NETIF_F_GSO_UDP_TUNNEL;
+	}
+
 	mdev->pndev[port] = dev;
 	mdev->upper[port] = NULL;
 
@@ -3168,6 +3197,8 @@
 			en_err(priv, "Failed starting port\n");
 	}
 
+	if (!err)
+		err = mlx4_en_moderation_update(priv);
 out:
 	mutex_unlock(&mdev->state_lock);
 	netdev_features_change(dev);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_port.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -164,7 +164,7 @@
 		return PTR_ERR(mailbox);
 	err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0,
 			   MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
-			   MLX4_CMD_WRAPPED);
+			   MLX4_CMD_NATIVE);
 	if (err)
 		goto out;
 
@@ -238,11 +238,11 @@
 	stats->collisions = 0;
 	stats->rx_dropped = be32_to_cpu(mlx4_en_stats->RDROP);
 	stats->rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength);
-	stats->rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+	stats->rx_over_errors = 0;
 	stats->rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC);
 	stats->rx_frame_errors = 0;
 	stats->rx_fifo_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
-	stats->rx_missed_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+	stats->rx_missed_errors = 0;
 	stats->tx_aborted_errors = 0;
 	stats->tx_carrier_errors = 0;
 	stats->tx_fifo_errors = 0;
@@ -325,7 +325,7 @@
 		err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma,
 				   in_mod | MLX4_DUMP_ETH_STATS_FLOW_CONTROL,
 				   0, MLX4_CMD_DUMP_ETH_STATS,
-				   MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
+				   MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
 		if (err)
 			goto out;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_resources.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/en_resources.c
@@ -58,7 +58,8 @@
 	} else {
 		context->sq_size_stride = ilog2(TXBB_SIZE) - 4;
 	}
-	context->usr_page = cpu_to_be32(mdev->priv_uar.index);
+	context->usr_page = cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev,
+					mdev->priv_uar.index));
 	context->local_qpn = cpu_to_be32(qpn);
 	context->pri_path.ackto = 1 & 0x07;
 	context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6;
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -439,8 +439,14 @@
 		ring->cqn = priv->rx_cq[ring_ind]->mcq.cqn;
 
 		ring->stride = stride;
-		if (ring->stride <= TXBB_SIZE)
+		if (ring->stride <= TXBB_SIZE) {
+			/* Stamp first unused send wqe */
+			__be32 *ptr = (__be32 *)ring->buf;
+			__be32 stamp = cpu_to_be32(1 << STAMP_SHIFT);
+			*ptr = stamp;
+			/* Move pointer to start of rx section */
 			ring->buf += TXBB_SIZE;
+		}
 
 		ring->log_stride = ffs(ring->stride) - 1;
 		ring->buf_size = ring->size * ring->stride;
@@ -502,8 +508,11 @@
 		return;
 
 	for (ring = 0; ring < priv->rx_ring_num; ring++) {
-		if (mlx4_en_is_ring_empty(priv->rx_ring[ring]))
+		if (mlx4_en_is_ring_empty(priv->rx_ring[ring])) {
+			local_bh_disable();
 			napi_reschedule(&priv->rx_cq[ring]->napi);
+			local_bh_enable();
+		}
 	}
 }
 
@@ -704,7 +713,7 @@
 
 	if (ipv6h->nexthdr == IPPROTO_FRAGMENT || ipv6h->nexthdr == IPPROTO_HOPOPTS)
 		return -1;
-	hw_checksum = csum_add(hw_checksum, (__force __wsum)(ipv6h->nexthdr << 8));
+	hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(ipv6h->nexthdr));
 
 	csum_pseudo_hdr = csum_partial(&ipv6h->saddr,
 				       sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0);
@@ -716,13 +725,27 @@
 	return 0;
 }
 #endif
+
+#define short_frame(size) ((size) <= ETH_ZLEN + ETH_FCS_LEN)
+
 static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va,
 		      netdev_features_t dev_features)
 {
 	__wsum hw_checksum = 0;
+	void *hdr;
 
-	void *hdr = (u8 *)va + sizeof(struct ethhdr);
+	/* CQE csum doesn't cover padding octets in short ethernet
+	 * frames. And the pad field is appended prior to calculating
+	 * and appending the FCS field.
+	 *
+	 * Detecting these padded frames requires to verify and parse
+	 * IP headers, so we simply force all those small frames to skip
+	 * checksum complete.
+	 */
+	if (short_frame(skb->len))
+		return -EINVAL;
 
+	hdr = (u8 *)va + sizeof(struct ethhdr);
 	hw_checksum = csum_unfold((__force __sum16)cqe->checksum);
 
 	if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK) &&
@@ -842,6 +865,11 @@
 			(cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_L2_TUNNEL));
 
 		if (likely(dev->features & NETIF_F_RXCSUM)) {
+			/* TODO: For IP non TCP/UDP packets when csum complete is
+			 * not an option (not supported or any other reason) we can
+			 * actually check cqe IPOK status bit and report
+			 * CHECKSUM_UNNECESSARY rather than CHECKSUM_NONE
+			 */
 			if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
 						      MLX4_CQE_STATUS_UDP)) {
 				if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -213,7 +213,9 @@
 	mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
 				ring->cqn, user_prio, &ring->context);
 	if (ring->bf_alloced)
-		ring->context.usr_page = cpu_to_be32(ring->bf.uar->index);
+		ring->context.usr_page =
+			cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev,
+							 ring->bf.uar->index));
 
 	err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context,
 			       &ring->qp, &ring->qp_state);
@@ -400,7 +402,6 @@
 	u32 packets = 0;
 	u32 bytes = 0;
 	int factor = priv->cqe_factor;
-	u64 timestamp = 0;
 	int done = 0;
 	int budget = priv->tx_work_limit;
 	u32 last_nr_txbb;
@@ -440,9 +441,12 @@
 		new_index = be16_to_cpu(cqe->wqe_index) & size_mask;
 
 		do {
+			u64 timestamp = 0;
+
 			txbbs_skipped += last_nr_txbb;
 			ring_index = (ring_index + last_nr_txbb) & size_mask;
-			if (ring->tx_info[ring_index].ts_requested)
+
+			if (unlikely(ring->tx_info[ring_index].ts_requested))
 				timestamp = mlx4_en_get_cqe_ts(cqe);
 
 			/* free next descriptor */
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -228,7 +228,8 @@
 	struct mlx4_dev *dev = &priv->dev;
 	struct mlx4_eq *eq = &priv->eq_table.eq[vec];
 
-	if (!eq->affinity_mask || cpumask_empty(eq->affinity_mask))
+	if (!cpumask_available(eq->affinity_mask) ||
+	    cpumask_empty(eq->affinity_mask))
 		return;
 
 	hint_err = irq_set_affinity_hint(eq->irq, eq->affinity_mask);
@@ -542,8 +543,9 @@
 			break;
 
 		case MLX4_EVENT_TYPE_SRQ_LIMIT:
-			mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n",
-				 __func__);
+			mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT. srq_no=0x%x, eq 0x%x\n",
+				 __func__, be32_to_cpu(eqe->event.srq.srqn),
+				 eq->eqn);
 		case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
 			if (mlx4_is_master(dev)) {
 				/* forward only to slave owning the SRQ */
@@ -558,15 +560,19 @@
 						  eq->eqn, eq->cons_index, ret);
 					break;
 				}
-				mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n",
-					  __func__, slave,
-					  be32_to_cpu(eqe->event.srq.srqn),
-					  eqe->type, eqe->subtype);
+				if (eqe->type ==
+				    MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)
+					mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n",
+						  __func__, slave,
+						  be32_to_cpu(eqe->event.srq.srqn),
+						  eqe->type, eqe->subtype);
 
 				if (!ret && slave != dev->caps.function) {
-					mlx4_warn(dev, "%s: sending event %02x(%02x) to slave:%d\n",
-						  __func__, eqe->type,
-						  eqe->subtype, slave);
+					if (eqe->type ==
+					    MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)
+						mlx4_warn(dev, "%s: sending event %02x(%02x) to slave:%d\n",
+							  __func__, eqe->type,
+							  eqe->subtype, slave);
 					mlx4_slave_event(dev, slave, eqe);
 					break;
 				}
@@ -924,9 +930,10 @@
 
 	if (!priv->eq_table.uar_map[index]) {
 		priv->eq_table.uar_map[index] =
-			ioremap(pci_resource_start(dev->persist->pdev, 2) +
-				((eq->eqn / 4) << PAGE_SHIFT),
-				PAGE_SIZE);
+			ioremap(
+				pci_resource_start(dev->persist->pdev, 2) +
+				((eq->eqn / 4) << (dev->uar_page_shift)),
+				(1 << (dev->uar_page_shift)));
 		if (!priv->eq_table.uar_map[index]) {
 			mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n",
 				 eq->eqn);
@@ -1234,9 +1241,8 @@
 					mlx4_warn(dev, "Failed adding irq rmap\n");
 			}
 #endif
-			err = mlx4_create_eq(dev, dev->caps.num_cqs -
-						  dev->caps.reserved_cqs +
-						  MLX4_NUM_SPARE_EQE,
+			err = mlx4_create_eq(dev, dev->quotas.cq +
+					     MLX4_NUM_SPARE_EQE,
 					     (dev->flags & MLX4_FLAG_MSI_X) ?
 					     i + 1 - !!(i > MLX4_EQ_ASYNC) : 0,
 					     eq);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -610,8 +610,7 @@
 		MLX4_GET(func_cap->phys_port_id, outbox,
 			 QUERY_FUNC_CAP_PHYS_PORT_ID);
 
-	MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET);
-	func_cap->flags |= (field & QUERY_FUNC_CAP_PHV_BIT);
+	MLX4_GET(func_cap->flags0, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET);
 
 	/* All other resources are allocated by the master, but we still report
 	 * 'num' and 'reserved' capabilities as follows:
@@ -1712,14 +1711,14 @@
 #define	 INIT_HCA_LOG_RD_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x77)
 #define INIT_HCA_MCAST_OFFSET		 0x0c0
 #define	 INIT_HCA_MC_BASE_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x00)
-#define	 INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12)
-#define	 INIT_HCA_LOG_MC_HASH_SZ_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x16)
+#define	 INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x13)
+#define	 INIT_HCA_LOG_MC_HASH_SZ_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x17)
 #define  INIT_HCA_UC_STEERING_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x18)
 #define	 INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b)
 #define  INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN	0x6
 #define  INIT_HCA_FS_PARAM_OFFSET         0x1d0
 #define  INIT_HCA_FS_BASE_OFFSET          (INIT_HCA_FS_PARAM_OFFSET + 0x00)
-#define  INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x12)
+#define  INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x13)
 #define  INIT_HCA_FS_A0_OFFSET		  (INIT_HCA_FS_PARAM_OFFSET + 0x18)
 #define  INIT_HCA_FS_LOG_TABLE_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x1b)
 #define  INIT_HCA_FS_ETH_BITS_OFFSET      (INIT_HCA_FS_PARAM_OFFSET + 0x21)
@@ -1906,9 +1905,11 @@
 {
 	struct mlx4_cmd_mailbox *mailbox;
 	__be32 *outbox;
+	u64 qword_field;
 	u32 dword_field;
-	int err;
+	u16 word_field;
 	u8 byte_field;
+	int err;
 	static const u8 a0_dmfs_query_hw_steering[] =  {
 		[0] = MLX4_STEERING_DMFS_A0_DEFAULT,
 		[1] = MLX4_STEERING_DMFS_A0_DYNAMIC,
@@ -1936,19 +1937,32 @@
 
 	/* QPC/EEC/CQC/EQC/RDMARC attributes */
 
-	MLX4_GET(param->qpc_base,      outbox, INIT_HCA_QPC_BASE_OFFSET);
-	MLX4_GET(param->log_num_qps,   outbox, INIT_HCA_LOG_QP_OFFSET);
-	MLX4_GET(param->srqc_base,     outbox, INIT_HCA_SRQC_BASE_OFFSET);
-	MLX4_GET(param->log_num_srqs,  outbox, INIT_HCA_LOG_SRQ_OFFSET);
-	MLX4_GET(param->cqc_base,      outbox, INIT_HCA_CQC_BASE_OFFSET);
-	MLX4_GET(param->log_num_cqs,   outbox, INIT_HCA_LOG_CQ_OFFSET);
-	MLX4_GET(param->altc_base,     outbox, INIT_HCA_ALTC_BASE_OFFSET);
-	MLX4_GET(param->auxc_base,     outbox, INIT_HCA_AUXC_BASE_OFFSET);
-	MLX4_GET(param->eqc_base,      outbox, INIT_HCA_EQC_BASE_OFFSET);
-	MLX4_GET(param->log_num_eqs,   outbox, INIT_HCA_LOG_EQ_OFFSET);
-	MLX4_GET(param->num_sys_eqs,   outbox, INIT_HCA_NUM_SYS_EQS_OFFSET);
-	MLX4_GET(param->rdmarc_base,   outbox, INIT_HCA_RDMARC_BASE_OFFSET);
-	MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET);
+	MLX4_GET(qword_field, outbox, INIT_HCA_QPC_BASE_OFFSET);
+	param->qpc_base = qword_field & ~((u64)0x1f);
+	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_QP_OFFSET);
+	param->log_num_qps = byte_field & 0x1f;
+	MLX4_GET(qword_field, outbox, INIT_HCA_SRQC_BASE_OFFSET);
+	param->srqc_base = qword_field & ~((u64)0x1f);
+	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_SRQ_OFFSET);
+	param->log_num_srqs = byte_field & 0x1f;
+	MLX4_GET(qword_field, outbox, INIT_HCA_CQC_BASE_OFFSET);
+	param->cqc_base = qword_field & ~((u64)0x1f);
+	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_CQ_OFFSET);
+	param->log_num_cqs = byte_field & 0x1f;
+	MLX4_GET(qword_field, outbox, INIT_HCA_ALTC_BASE_OFFSET);
+	param->altc_base = qword_field;
+	MLX4_GET(qword_field, outbox, INIT_HCA_AUXC_BASE_OFFSET);
+	param->auxc_base = qword_field;
+	MLX4_GET(qword_field, outbox, INIT_HCA_EQC_BASE_OFFSET);
+	param->eqc_base = qword_field & ~((u64)0x1f);
+	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_EQ_OFFSET);
+	param->log_num_eqs = byte_field & 0x1f;
+	MLX4_GET(word_field, outbox, INIT_HCA_NUM_SYS_EQS_OFFSET);
+	param->num_sys_eqs = word_field & 0xfff;
+	MLX4_GET(qword_field, outbox, INIT_HCA_RDMARC_BASE_OFFSET);
+	param->rdmarc_base = qword_field & ~((u64)0x1f);
+	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_RD_OFFSET);
+	param->log_rd_per_qp = byte_field & 0x7;
 
 	MLX4_GET(dword_field, outbox, INIT_HCA_FLAGS_OFFSET);
 	if (dword_field & (1 << INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN)) {
@@ -1967,22 +1981,21 @@
 	/* steering attributes */
 	if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
 		MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET);
-		MLX4_GET(param->log_mc_entry_sz, outbox,
-			 INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
-		MLX4_GET(param->log_mc_table_sz, outbox,
-			 INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
-		MLX4_GET(byte_field, outbox,
-			 INIT_HCA_FS_A0_OFFSET);
+		MLX4_GET(byte_field, outbox, INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
+		param->log_mc_entry_sz = byte_field & 0x1f;
+		MLX4_GET(byte_field, outbox, INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
+		param->log_mc_table_sz = byte_field & 0x1f;
+		MLX4_GET(byte_field, outbox, INIT_HCA_FS_A0_OFFSET);
 		param->dmfs_high_steer_mode =
 			a0_dmfs_query_hw_steering[(byte_field >> 6) & 3];
 	} else {
 		MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET);
-		MLX4_GET(param->log_mc_entry_sz, outbox,
-			 INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
-		MLX4_GET(param->log_mc_hash_sz,  outbox,
-			 INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
-		MLX4_GET(param->log_mc_table_sz, outbox,
-			 INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
+		MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
+		param->log_mc_entry_sz = byte_field & 0x1f;
+		MLX4_GET(byte_field,  outbox, INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
+		param->log_mc_hash_sz = byte_field & 0x1f;
+		MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
+		param->log_mc_table_sz = byte_field & 0x1f;
 	}
 
 	/* CX3 is capable of extending CQEs/EQEs from 32 to 64 bytes */
@@ -2006,15 +2019,18 @@
 	/* TPT attributes */
 
 	MLX4_GET(param->dmpt_base,  outbox, INIT_HCA_DMPT_BASE_OFFSET);
-	MLX4_GET(param->mw_enabled, outbox, INIT_HCA_TPT_MW_OFFSET);
-	MLX4_GET(param->log_mpt_sz, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET);
+	MLX4_GET(byte_field, outbox, INIT_HCA_TPT_MW_OFFSET);
+	param->mw_enabled = byte_field >> 7;
+	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET);
+	param->log_mpt_sz = byte_field & 0x3f;
 	MLX4_GET(param->mtt_base,   outbox, INIT_HCA_MTT_BASE_OFFSET);
 	MLX4_GET(param->cmpt_base,  outbox, INIT_HCA_CMPT_BASE_OFFSET);
 
 	/* UAR attributes */
 
 	MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET);
-	MLX4_GET(param->log_uar_sz, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET);
+	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET);
+	param->log_uar_sz = byte_field & 0xf;
 
 	/* phv_check enable */
 	MLX4_GET(byte_field, outbox, INIT_HCA_CACHELINE_SZ_OFFSET);
@@ -2506,7 +2522,7 @@
 		if (err) {
 			mlx4_err(dev, "Failed to retrieve required operation: %d\n",
 				 err);
-			return;
+			goto out;
 		}
 		MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET);
 		MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET);
@@ -2823,7 +2839,7 @@
 	memset(&func_cap, 0, sizeof(func_cap));
 	err = mlx4_QUERY_FUNC_CAP(dev, port, &func_cap);
 	if (!err)
-		*phv = func_cap.flags & QUERY_FUNC_CAP_PHV_BIT;
+		*phv = func_cap.flags0 & QUERY_FUNC_CAP_PHV_BIT;
 	return err;
 }
 EXPORT_SYMBOL(get_phv_bit);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/fw.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/fw.h
@@ -150,7 +150,7 @@
 	u32	qp1_proxy_qpn;
 	u32	reserved_lkey;
 	u8	physical_port;
-	u8	port_flags;
+	u8	flags0;
 	u8	flags1;
 	u64	phys_port_id;
 	u32	extra_flags;
@@ -184,8 +184,8 @@
 	u64 cmpt_base;
 	u64 mtt_base;
 	u64 global_caps;
-	u16 log_mc_entry_sz;
-	u16 log_mc_hash_sz;
+	u8 log_mc_entry_sz;
+	u8 log_mc_hash_sz;
 	u16 hca_core_clock; /* Internal Clock Frequency (in MHz) */
 	u8  log_num_qps;
 	u8  log_num_srqs;
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/icm.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/icm.c
@@ -118,8 +118,13 @@
 	if (!buf)
 		return -ENOMEM;
 
+	if (offset_in_page(buf)) {
+		dma_free_coherent(dev, PAGE_SIZE << order,
+				  buf, sg_dma_address(mem));
+		return -ENOMEM;
+	}
+
 	sg_set_buf(mem, buf, PAGE_SIZE << order);
-	BUG_ON(mem->offset);
 	sg_dma_len(mem) = PAGE_SIZE << order;
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/intf.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/intf.c
@@ -217,7 +217,22 @@
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	struct mlx4_interface *intf;
 
+	if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP))
+		return;
+
 	mlx4_stop_catas_poll(dev);
+	if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION &&
+	    mlx4_is_slave(dev)) {
+		/* In mlx4_remove_one on a VF */
+		u32 slave_read =
+			swab32(readl(&mlx4_priv(dev)->mfunc.comm->slave_read));
+
+		if (mlx4_comm_internal_err(slave_read)) {
+			mlx4_dbg(dev, "%s: comm channel is down, entering error state.\n",
+				 __func__);
+			mlx4_enter_error_state(dev->persist);
+		}
+	}
 	mutex_lock(&intf_mutex);
 
 	list_for_each_entry(intf, &intf_list, list)
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/main.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -168,6 +168,20 @@
 
 static atomic_t pf_loading = ATOMIC_INIT(0);
 
+static inline void mlx4_set_num_reserved_uars(struct mlx4_dev *dev,
+					      struct mlx4_dev_cap *dev_cap)
+{
+	/* The reserved_uars is calculated by system page size unit.
+	 * Therefore, adjustment is added when the uar page size is less
+	 * than the system page size
+	 */
+	dev->caps.reserved_uars	=
+		max_t(int,
+		      mlx4_get_num_reserved_uar(dev),
+		      dev_cap->reserved_uars /
+			(1 << (PAGE_SHIFT - dev->uar_page_shift)));
+}
+
 int mlx4_check_port_params(struct mlx4_dev *dev,
 			   enum mlx4_port_type *port_type)
 {
@@ -386,8 +400,6 @@
 	dev->caps.reserved_mtts      = dev_cap->reserved_mtts;
 	dev->caps.reserved_mrws	     = dev_cap->reserved_mrws;
 
-	/* The first 128 UARs are used for EQ doorbells */
-	dev->caps.reserved_uars	     = max_t(int, 128, dev_cap->reserved_uars);
 	dev->caps.reserved_pds	     = dev_cap->reserved_pds;
 	dev->caps.reserved_xrcds     = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ?
 					dev_cap->reserved_xrcds : 0;
@@ -405,6 +417,15 @@
 	dev->caps.max_gso_sz	     = dev_cap->max_gso_sz;
 	dev->caps.max_rss_tbl_sz     = dev_cap->max_rss_tbl_sz;
 
+	/* Save uar page shift */
+	if (!mlx4_is_slave(dev)) {
+		/* Virtual PCI function needs to determine UAR page size from
+		 * firmware. Only master PCI function can set the uar page size
+		 */
+		dev->uar_page_shift = DEFAULT_UAR_PAGE_SHIFT;
+		mlx4_set_num_reserved_uars(dev, dev_cap);
+	}
+
 	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN) {
 		struct mlx4_init_hca_param hca_param;
 
@@ -791,8 +812,6 @@
 		return -ENOSYS;
 	}
 
-	mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz;
-
 	dev->caps.hca_core_clock = hca_param.hca_core_clock;
 
 	memset(&dev_cap, 0, sizeof(dev_cap));
@@ -815,15 +834,24 @@
 		return -ENODEV;
 	}
 
-	/* slave gets uar page size from QUERY_HCA fw command */
-	dev->caps.uar_page_size = 1 << (hca_param.uar_page_sz + 12);
+	/* Set uar_page_shift for VF */
+	dev->uar_page_shift = hca_param.uar_page_sz + 12;
 
-	/* TODO: relax this assumption */
-	if (dev->caps.uar_page_size != PAGE_SIZE) {
-		mlx4_err(dev, "UAR size:%d != kernel PAGE_SIZE of %ld\n",
-			 dev->caps.uar_page_size, PAGE_SIZE);
-		return -ENODEV;
-	}
+	/* Make sure the master uar page size is valid */
+	if (dev->uar_page_shift > PAGE_SHIFT) {
+		mlx4_err(dev,
+			 "Invalid configuration: uar page size is larger than system page size\n");
+		return  -ENODEV;
+	}
+
+	/* Set reserved_uars based on the uar_page_shift */
+	mlx4_set_num_reserved_uars(dev, &dev_cap);
+
+	/* Although uar page size in FW differs from system page size,
+	 * upper software layers (mlx4_ib, mlx4_en and part of mlx4_core)
+	 * still works with assumption that uar page size == system page size
+	 */
+	dev->caps.uar_page_size = PAGE_SIZE;
 
 	memset(&func_cap, 0, sizeof(func_cap));
 	err = mlx4_QUERY_FUNC_CAP(dev, 0, &func_cap);
@@ -1765,6 +1793,14 @@
 			       (u32)(1 << COMM_CHAN_OFFLINE_OFFSET));
 		if (!offline_bit)
 			return 0;
+
+		/* If device removal has been requested,
+		 * do not continue retrying.
+		 */
+		if (dev->persist->interface_state &
+		    MLX4_INTERFACE_STATE_NOWAIT)
+			break;
+
 		/* There are cases as part of AER/Reset flow that PF needs
 		 * around 100 msec to load. We therefore sleep for 100 msec
 		 * to allow other tasks to make use of that CPU during this
@@ -2092,8 +2128,12 @@
 
 		dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1;
 
-		init_hca.log_uar_sz = ilog2(dev->caps.num_uars);
-		init_hca.uar_page_sz = PAGE_SHIFT - 12;
+		/* Always set UAR page size 4KB, set log_uar_sz accordingly */
+		init_hca.log_uar_sz = ilog2(dev->caps.num_uars) +
+				      PAGE_SHIFT -
+				      DEFAULT_UAR_PAGE_SHIFT;
+		init_hca.uar_page_sz = DEFAULT_UAR_PAGE_SHIFT - 12;
+
 		init_hca.mw_enabled = 0;
 		if (dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW ||
 		    dev->caps.bmme_flags & MLX4_BMME_FLAG_TYPE_2_WIN)
@@ -2289,6 +2329,7 @@
 
 		if (!err || err == -ENOSPC) {
 			priv->def_counter[port] = idx;
+			err = 0;
 		} else if (err == -ENOENT) {
 			err = 0;
 			continue;
@@ -2338,7 +2379,8 @@
 				   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
 		if (!err)
 			*idx = get_param_l(&out_param);
-
+		if (WARN_ON(err == -ENOSPC))
+			err = -EINVAL;
 		return err;
 	}
 	return __mlx4_counter_alloc(dev, idx);
@@ -3009,6 +3051,34 @@
 	return 0;
 }
 
+static int mlx4_pci_enable_device(struct mlx4_dev *dev)
+{
+	struct pci_dev *pdev = dev->persist->pdev;
+	int err = 0;
+
+	mutex_lock(&dev->persist->pci_status_mutex);
+	if (dev->persist->pci_status == MLX4_PCI_STATUS_DISABLED) {
+		err = pci_enable_device(pdev);
+		if (!err)
+			dev->persist->pci_status = MLX4_PCI_STATUS_ENABLED;
+	}
+	mutex_unlock(&dev->persist->pci_status_mutex);
+
+	return err;
+}
+
+static void mlx4_pci_disable_device(struct mlx4_dev *dev)
+{
+	struct pci_dev *pdev = dev->persist->pdev;
+
+	mutex_lock(&dev->persist->pci_status_mutex);
+	if (dev->persist->pci_status == MLX4_PCI_STATUS_ENABLED) {
+		pci_disable_device(pdev);
+		dev->persist->pci_status = MLX4_PCI_STATUS_DISABLED;
+	}
+	mutex_unlock(&dev->persist->pci_status_mutex);
+}
+
 static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
 			 int total_vfs, int *nvfs, struct mlx4_priv *priv,
 			 int reset_flow)
@@ -3281,6 +3351,8 @@
 			goto err_disable_msix;
 	}
 
+	mlx4_init_quotas(dev);
+
 	err = mlx4_setup_hca(dev);
 	if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X) &&
 	    !mlx4_is_mfunc(dev)) {
@@ -3293,7 +3365,6 @@
 	if (err)
 		goto err_steer;
 
-	mlx4_init_quotas(dev);
 	/* When PF resources are ready arm its comm channel to enable
 	 * getting commands
 	 */
@@ -3419,7 +3490,7 @@
 
 	pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev));
 
-	err = pci_enable_device(pdev);
+	err = mlx4_pci_enable_device(&priv->dev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
 		return err;
@@ -3552,7 +3623,7 @@
 	pci_release_regions(pdev);
 
 err_disable_pdev:
-	pci_disable_device(pdev);
+	mlx4_pci_disable_device(&priv->dev);
 	pci_set_drvdata(pdev, NULL);
 	return err;
 }
@@ -3581,6 +3652,7 @@
 	priv->pci_dev_data = id->driver_data;
 	mutex_init(&dev->persist->device_state_mutex);
 	mutex_init(&dev->persist->interface_state_mutex);
+	mutex_init(&dev->persist->pci_status_mutex);
 
 	ret =  __mlx4_init_one(pdev, id->driver_data, priv);
 	if (ret) {
@@ -3692,6 +3764,9 @@
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int active_vfs = 0;
 
+	if (mlx4_is_slave(dev))
+		persist->interface_state |= MLX4_INTERFACE_STATE_NOWAIT;
+
 	mutex_lock(&persist->interface_state_mutex);
 	persist->interface_state |= MLX4_INTERFACE_STATE_DELETION;
 	mutex_unlock(&persist->interface_state_mutex);
@@ -3719,7 +3794,7 @@
 	}
 
 	pci_release_regions(pdev);
-	pci_disable_device(pdev);
+	mlx4_pci_disable_device(dev);
 	kfree(dev->persist);
 	kfree(priv);
 	pci_set_drvdata(pdev, NULL);
@@ -3837,7 +3912,7 @@
 	if (state == pci_channel_io_perm_failure)
 		return PCI_ERS_RESULT_DISCONNECT;
 
-	pci_disable_device(pdev);
+	mlx4_pci_disable_device(persist->dev);
 	return PCI_ERS_RESULT_NEED_RESET;
 }
 
@@ -3845,45 +3920,53 @@
 {
 	struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
 	struct mlx4_dev	 *dev  = persist->dev;
-	struct mlx4_priv *priv = mlx4_priv(dev);
-	int               ret;
-	int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0};
-	int total_vfs;
+	int err;
 
 	mlx4_err(dev, "mlx4_pci_slot_reset was called\n");
-	ret = pci_enable_device(pdev);
-	if (ret) {
-		mlx4_err(dev, "Can not re-enable device, ret=%d\n", ret);
+	err = mlx4_pci_enable_device(dev);
+	if (err) {
+		mlx4_err(dev, "Can not re-enable device, err=%d\n", err);
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 
 	pci_set_master(pdev);
 	pci_restore_state(pdev);
 	pci_save_state(pdev);
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void mlx4_pci_resume(struct pci_dev *pdev)
+{
+	struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
+	struct mlx4_dev	 *dev  = persist->dev;
+	struct mlx4_priv *priv = mlx4_priv(dev);
+	int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0};
+	int total_vfs;
+	int err;
 
+	mlx4_err(dev, "%s was called\n", __func__);
 	total_vfs = dev->persist->num_vfs;
 	memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs));
 
 	mutex_lock(&persist->interface_state_mutex);
 	if (!(persist->interface_state & MLX4_INTERFACE_STATE_UP)) {
-		ret = mlx4_load_one(pdev, priv->pci_dev_data, total_vfs, nvfs,
+		err = mlx4_load_one(pdev, priv->pci_dev_data, total_vfs, nvfs,
 				    priv, 1);
-		if (ret) {
-			mlx4_err(dev, "%s: mlx4_load_one failed, ret=%d\n",
-				 __func__,  ret);
+		if (err) {
+			mlx4_err(dev, "%s: mlx4_load_one failed, err=%d\n",
+				 __func__,  err);
 			goto end;
 		}
 
-		ret = restore_current_port_types(dev, dev->persist->
+		err = restore_current_port_types(dev, dev->persist->
 						 curr_port_type, dev->persist->
 						 curr_port_poss_type);
-		if (ret)
-			mlx4_err(dev, "could not restore original port types (%d)\n", ret);
+		if (err)
+			mlx4_err(dev, "could not restore original port types (%d)\n", err);
 	}
 end:
 	mutex_unlock(&persist->interface_state_mutex);
 
-	return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
 }
 
 static void mlx4_shutdown(struct pci_dev *pdev)
@@ -3900,6 +3983,7 @@
 static const struct pci_error_handlers mlx4_err_handler = {
 	.error_detected = mlx4_pci_err_detected,
 	.slot_reset     = mlx4_pci_slot_reset,
+	.resume		= mlx4_pci_resume,
 };
 
 static struct pci_driver mlx4_driver = {
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -35,6 +35,7 @@
 #include <linux/etherdevice.h>
 
 #include <linux/mlx4/cmd.h>
+#include <linux/mlx4/qp.h>
 #include <linux/export.h>
 
 #include "mlx4.h"
@@ -985,16 +986,21 @@
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 
+	if (!mlx4_qp_lookup(dev, rule->qpn)) {
+		mlx4_err_rule(dev, "QP doesn't exist\n", rule);
+		ret = -EINVAL;
+		goto out;
+	}
+
 	trans_rule_ctrl_to_hw(rule, mailbox->buf);
 
 	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
 
 	list_for_each_entry(cur, &rule->list, list) {
 		ret = parse_trans_rule(dev, cur, mailbox->buf + size);
-		if (ret < 0) {
-			mlx4_free_cmd_mailbox(dev, mailbox);
-			return ret;
-		}
+		if (ret < 0)
+			goto out;
+
 		size += ret;
 	}
 
@@ -1021,6 +1027,7 @@
 		}
 	}
 
+out:
 	mlx4_free_cmd_mailbox(dev, mailbox);
 
 	return ret;
@@ -1102,7 +1109,7 @@
 	struct mlx4_cmd_mailbox *mailbox;
 	struct mlx4_mgm *mgm;
 	u32 members_count;
-	int index, prev;
+	int index = -1, prev;
 	int link = 0;
 	int i;
 	int err;
@@ -1181,7 +1188,7 @@
 		goto out;
 
 out:
-	if (prot == MLX4_PROT_ETH) {
+	if (prot == MLX4_PROT_ETH && index != -1) {
 		/* manage the steering entry for promisc mode */
 		if (new_entry)
 			err = new_steering_entry(dev, port, steer,
@@ -1457,7 +1464,12 @@
 int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
 				u32 qpn, enum mlx4_net_trans_promisc_mode mode)
 {
-	struct mlx4_net_trans_rule rule;
+	struct mlx4_net_trans_rule rule = {
+		.queue_mode = MLX4_NET_TRANS_Q_FIFO,
+		.exclusive = 0,
+		.allow_loopback = 1,
+	};
+
 	u64 *regid_p;
 
 	switch (mode) {
@@ -1478,7 +1490,7 @@
 	rule.port = port;
 	rule.qpn = qpn;
 	INIT_LIST_HEAD(&rule.list);
-	mlx4_err(dev, "going promisc on %x\n", port);
+	mlx4_info(dev, "going promisc on %x\n", port);
 
 	return  mlx4_flow_attach(dev, &rule, regid_p);
 }
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -143,9 +143,10 @@
 	RES_MTT,
 	RES_MAC,
 	RES_VLAN,
-	RES_EQ,
+	RES_NPORT_ID,
 	RES_COUNTER,
 	RES_FS_RULE,
+	RES_EQ,
 	MLX4_NUM_OF_RESOURCE_TYPE
 };
 
@@ -537,8 +538,8 @@
 struct resource_allocator {
 	spinlock_t alloc_lock; /* protect quotas */
 	union {
-		int res_reserved;
-		int res_port_rsvd[MLX4_MAX_PORTS];
+		unsigned int res_reserved;
+		unsigned int res_port_rsvd[MLX4_MAX_PORTS];
 	};
 	union {
 		int res_free;
@@ -1205,6 +1206,7 @@
 void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type);
 
 void mlx4_enter_error_state(struct mlx4_dev_persistent *persist);
+int mlx4_comm_internal_err(u32 slave_read);
 
 int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port,
 		    enum mlx4_port_type *type);
@@ -1311,8 +1313,6 @@
 			       struct mlx4_cmd_info *cmd);
 int mlx4_common_set_vlan_fltr(struct mlx4_dev *dev, int function,
 				     int port, void *buf);
-int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, u32 in_mod,
-				struct mlx4_cmd_mailbox *outbox);
 int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
 				   struct mlx4_vhcr *vhcr,
 				   struct mlx4_cmd_mailbox *inbox,
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -140,6 +140,9 @@
 #define MLX4_EN_TX_COAL_PKTS	16
 #define MLX4_EN_TX_COAL_TIME	0x10
 
+#define MLX4_EN_MAX_COAL_PKTS	U16_MAX
+#define MLX4_EN_MAX_COAL_TIME	U16_MAX
+
 #define MLX4_EN_RX_RATE_LOW		400000
 #define MLX4_EN_RX_COAL_TIME_LOW	0
 #define MLX4_EN_RX_RATE_HIGH		450000
@@ -409,7 +412,6 @@
 	struct cyclecounter	cycles;
 	struct timecounter	clock;
 	unsigned long		last_overflow_check;
-	unsigned long		overflow_period;
 	struct ptp_clock	*ptp_clock;
 	struct ptp_clock_info	ptp_clock_info;
 	struct notifier_block	nb;
@@ -493,6 +495,10 @@
 	struct mutex mutex; /* for mutual access to stats bitmap */
 };
 
+enum {
+	MLX4_EN_STATE_FLAG_RESTARTING,
+};
+
 struct mlx4_en_priv {
 	struct mlx4_en_dev *mdev;
 	struct mlx4_en_port_profile *prof;
@@ -519,8 +525,8 @@
 	u16 rx_usecs_low;
 	u32 pkt_rate_high;
 	u16 rx_usecs_high;
-	u16 sample_interval;
-	u16 adaptive_rx_coal;
+	u32 sample_interval;
+	u32 adaptive_rx_coal;
 	u32 msg_enable;
 	u32 loopback_ok;
 	u32 validate_loopback;
@@ -558,7 +564,7 @@
 	struct mlx4_en_cq *rx_cq[MAX_RX_RINGS];
 	struct mlx4_qp drop_qp;
 	struct work_struct rx_mode_task;
-	struct work_struct watchdog_task;
+	struct work_struct restart_task;
 	struct work_struct linkstate_task;
 	struct delayed_work stats_task;
 	struct delayed_work service_task;
@@ -603,6 +609,7 @@
 	u32 pflags;
 	u8 rss_key[MLX4_EN_RSS_KEY_SIZE];
 	u8 rss_hash_fn;
+	unsigned long state;
 };
 
 enum mlx4_en_wol {
@@ -832,6 +839,7 @@
 #define DEV_FEATURE_CHANGED(dev, new_features, feature) \
 	((dev->features & feature) ^ (new_features & feature))
 
+int mlx4_en_moderation_update(struct mlx4_en_priv *priv);
 int mlx4_en_reset_config(struct net_device *dev,
 			 struct hwtstamp_config ts_config,
 			 netdev_features_t new_features);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/mr.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/mr.c
@@ -114,7 +114,7 @@
 		goto err_out;
 
 	for (i = 0; i <= buddy->max_order; ++i) {
-		s = BITS_TO_LONGS(1 << (buddy->max_order - i));
+		s = BITS_TO_LONGS(1UL << (buddy->max_order - i));
 		buddy->bits[i] = kcalloc(s, sizeof (long), GFP_KERNEL | __GFP_NOWARN);
 		if (!buddy->bits[i]) {
 			buddy->bits[i] = vzalloc(s * sizeof(long));
@@ -366,6 +366,7 @@
 			container_of((void *)mpt_entry, struct mlx4_cmd_mailbox,
 				     buf);
 
+		(*mpt_entry)->lkey = 0;
 		err = mlx4_SW2HW_MPT(dev, mailbox, key);
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/pd.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/pd.c
@@ -269,9 +269,15 @@
 
 int mlx4_init_uar_table(struct mlx4_dev *dev)
 {
-	if (dev->caps.num_uars <= 128) {
-		mlx4_err(dev, "Only %d UAR pages (need more than 128)\n",
-			 dev->caps.num_uars);
+	int num_reserved_uar = mlx4_get_num_reserved_uar(dev);
+
+	mlx4_dbg(dev, "uar_page_shift = %d", dev->uar_page_shift);
+	mlx4_dbg(dev, "Effective reserved_uars=%d", dev->caps.reserved_uars);
+
+	if (dev->caps.num_uars <= num_reserved_uar) {
+		mlx4_err(
+			dev, "Only %d UAR pages (need more than %d)\n",
+			dev->caps.num_uars, num_reserved_uar);
 		mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n");
 		return -ENODEV;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/port.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -1155,24 +1155,13 @@
 	return err;
 }
 
-int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave,
-			       u32 in_mod, struct mlx4_cmd_mailbox *outbox)
-{
-	return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0,
-			    MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
-			    MLX4_CMD_NATIVE);
-}
-
 int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
 				struct mlx4_vhcr *vhcr,
 				struct mlx4_cmd_mailbox *inbox,
 				struct mlx4_cmd_mailbox *outbox,
 				struct mlx4_cmd_info *cmd)
 {
-	if (slave != dev->caps.function)
-		return 0;
-	return mlx4_common_dump_eth_stats(dev, slave,
-					  vhcr->in_modifier, outbox);
+	return 0;
 }
 
 int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
@@ -1398,11 +1387,6 @@
 		size -= offset + size - I2C_PAGE_SIZE;
 
 	i2c_addr = I2C_ADDR_LOW;
-	if (offset >= I2C_PAGE_SIZE) {
-		/* Reset offset to high page */
-		i2c_addr = I2C_ADDR_HIGH;
-		offset -= I2C_PAGE_SIZE;
-	}
 
 	cable_info = (struct mlx4_cable_info *)inmad->data;
 	cable_info->dev_mem_address = cpu_to_be16(offset);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -280,6 +280,9 @@
 	u64 in_param = 0;
 	int err;
 
+	if (!cnt)
+		return;
+
 	if (mlx4_is_mfunc(dev)) {
 		set_param_l(&in_param, base_qpn);
 		set_param_h(&in_param, cnt);
@@ -378,6 +381,19 @@
 		__mlx4_qp_free_icm(dev, qpn);
 }
 
+struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn)
+{
+	struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
+	struct mlx4_qp *qp;
+
+	spin_lock_irq(&qp_table->lock);
+
+	qp = __mlx4_qp_lookup(dev, qpn);
+
+	spin_unlock_irq(&qp_table->lock);
+	return qp;
+}
+
 int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
@@ -465,6 +481,12 @@
 	}
 
 	if (attr & MLX4_UPDATE_QP_QOS_VPORT) {
+		if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) {
+			mlx4_warn(dev, "Granular QoS per VF is not enabled\n");
+			err = -EOPNOTSUPP;
+			goto out;
+		}
+
 		qp_mask |= 1ULL << MLX4_UPD_QP_MASK_QOS_VPP;
 		cmd->qp_context.qos_vport = params->qos_vport;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -463,12 +463,31 @@
 		priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf];
 }
 
-static int get_max_gauranteed_vfs_counter(struct mlx4_dev *dev)
-{
-	/* reduce the sink counter */
-	return (dev->caps.max_counters - 1 -
-		(MLX4_PF_COUNTERS_PER_PORT * MLX4_MAX_PORTS))
-		/ MLX4_MAX_PORTS;
+static int
+mlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev,
+				 struct resource_allocator *res_alloc,
+				 int vf)
+{
+	struct mlx4_active_ports actv_ports;
+	int ports, counters_guaranteed;
+
+	/* For master, only allocate according to the number of phys ports */
+	if (vf == mlx4_master_func_num(dev))
+		return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports;
+
+	/* calculate real number of ports for the VF */
+	actv_ports = mlx4_get_active_ports(dev, vf);
+	ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
+	counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT;
+
+	/* If we do not have enough counters for this VF, do not
+	 * allocate any for it. '-1' to reduce the sink counter.
+	 */
+	if ((res_alloc->res_reserved + counters_guaranteed) >
+	    (dev->caps.max_counters - 1))
+		return 0;
+
+	return counters_guaranteed;
 }
 
 int mlx4_init_resource_tracker(struct mlx4_dev *dev)
@@ -476,7 +495,6 @@
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int i, j;
 	int t;
-	int max_vfs_guarantee_counter = get_max_gauranteed_vfs_counter(dev);
 
 	priv->mfunc.master.res_tracker.slave_list =
 		kzalloc(dev->num_slaves * sizeof(struct slave_list),
@@ -593,16 +611,8 @@
 				break;
 			case RES_COUNTER:
 				res_alloc->quota[t] = dev->caps.max_counters;
-				if (t == mlx4_master_func_num(dev))
-					res_alloc->guaranteed[t] =
-						MLX4_PF_COUNTERS_PER_PORT *
-						MLX4_MAX_PORTS;
-				else if (t <= max_vfs_guarantee_counter)
-					res_alloc->guaranteed[t] =
-						MLX4_VF_COUNTERS_PER_PORT *
-						MLX4_MAX_PORTS;
-				else
-					res_alloc->guaranteed[t] = 0;
+				res_alloc->guaranteed[t] =
+					mlx4_calc_res_counter_guaranteed(dev, res_alloc, t);
 				res_alloc->res_free -= res_alloc->guaranteed[t];
 				break;
 			default:
@@ -908,11 +918,13 @@
 
 	spin_lock_irq(mlx4_tlock(dev));
 	r = find_res(dev, counter_index, RES_COUNTER);
-	if (!r || r->owner != slave)
+	if (!r || r->owner != slave) {
 		ret = -EINVAL;
-	counter = container_of(r, struct res_counter, com);
-	if (!counter->port)
-		counter->port = port;
+	} else {
+		counter = container_of(r, struct res_counter, com);
+		if (!counter->port)
+			counter->port = port;
+	}
 
 	spin_unlock_irq(mlx4_tlock(dev));
 	return ret;
@@ -2652,13 +2664,13 @@
 	int total_pages;
 	int total_mem;
 	int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f;
+	int tot;
 
 	sq_size = 1 << (log_sq_size + log_sq_sride + 4);
 	rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4));
 	total_mem = sq_size + rq_size;
-	total_pages =
-		roundup_pow_of_two((total_mem + (page_offset << 6)) >>
-				   page_shift);
+	tot = (total_mem + (page_offset << 6)) >> page_shift;
+	total_pages = !tot ? 1 : roundup_pow_of_two(tot);
 
 	return total_pages;
 }
@@ -2891,7 +2903,7 @@
 	u32 srqn = qp_get_srqn(qpc) & 0xffffff;
 	int use_srq = (qp_get_srqn(qpc) >> 24) & 1;
 	struct res_srq *srq;
-	int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff;
+	int local_qpn = vhcr->in_modifier & 0xffffff;
 
 	err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
 	if (err)
@@ -2955,6 +2967,9 @@
 		put_res(dev, slave, srqn, RES_SRQ);
 		qp->srq = srq;
 	}
+
+	/* Save param3 for dynamic changes from VST back to VGT */
+	qp->param3 = qpc->param3;
 	put_res(dev, slave, rcqn, RES_CQ);
 	put_res(dev, slave, mtt_base, RES_MTT);
 	res_end_move(dev, slave, RES_QP, qpn);
@@ -3132,7 +3147,7 @@
 		case QP_TRANS_RTS2RTS:
 		case QP_TRANS_SQD2SQD:
 		case QP_TRANS_SQD2RTS:
-			if (slave != mlx4_master_func_num(dev))
+			if (slave != mlx4_master_func_num(dev)) {
 				if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
 					port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
 					if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
@@ -3151,6 +3166,7 @@
 					if (qp_ctx->alt_path.mgid_index >= num_gids)
 						return -EINVAL;
 				}
+			}
 			break;
 		default:
 			break;
@@ -3746,7 +3762,6 @@
 	int qpn = vhcr->in_modifier & 0x7fffff;
 	struct res_qp *qp;
 	u8 orig_sched_queue;
-	__be32	orig_param3 = qpc->param3;
 	u8 orig_vlan_control = qpc->pri_path.vlan_control;
 	u8 orig_fvl_rx = qpc->pri_path.fvl_rx;
 	u8 orig_pri_path_fl = qpc->pri_path.fl;
@@ -3788,7 +3803,6 @@
 	 */
 	if (!err) {
 		qp->sched_queue = orig_sched_queue;
-		qp->param3	= orig_param3;
 		qp->vlan_control = orig_vlan_control;
 		qp->fvl_rx	=  orig_fvl_rx;
 		qp->pri_path_fl = orig_pri_path_fl;
@@ -5038,6 +5052,13 @@
 	mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
 }
 
+static void update_qos_vpp(struct mlx4_update_qp_context *ctx,
+			   struct mlx4_vf_immed_vlan_work *work)
+{
+	ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP);
+	ctx->qp_context.qos_vport = work->qos_vport;
+}
+
 void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
 {
 	struct mlx4_vf_immed_vlan_work *work =
@@ -5142,11 +5163,10 @@
 					qp->sched_queue & 0xC7;
 				upd_context->qp_context.pri_path.sched_queue |=
 					((work->qos & 0x7) << 3);
-				upd_context->qp_mask |=
-					cpu_to_be64(1ULL <<
-						    MLX4_UPD_QP_MASK_QOS_VPP);
-				upd_context->qp_context.qos_vport =
-					work->qos_vport;
+
+				if (dev->caps.flags2 &
+				    MLX4_DEV_CAP_FLAG2_QOS_VPP)
+					update_qos_vpp(upd_context, work);
 			}
 
 			err = mlx4_cmd(dev, mailbox->dma,
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -2,7 +2,7 @@
 
 mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
 		health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o   \
-		mad.o transobj.o vport.o
-mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o flow_table.o \
+		mad.o transobj.o vport.o sriov.o
+mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o flow_table.o eswitch.o \
 		en_main.o en_flow_table.o en_ethtool.o en_tx.o en_rx.o \
 		en_txrx.o
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -143,13 +143,14 @@
 	return cmd->cmd_buf + (idx << cmd->log_stride);
 }
 
-static u8 xor8_buf(void *buf, int len)
+static u8 xor8_buf(void *buf, size_t offset, int len)
 {
 	u8 *ptr = buf;
 	u8 sum = 0;
 	int i;
+	int end = len + offset;
 
-	for (i = 0; i < len; i++)
+	for (i = offset; i < end; i++)
 		sum ^= ptr[i];
 
 	return sum;
@@ -157,41 +158,49 @@
 
 static int verify_block_sig(struct mlx5_cmd_prot_block *block)
 {
-	if (xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 1) != 0xff)
+	size_t rsvd0_off = offsetof(struct mlx5_cmd_prot_block, rsvd0);
+	int xor_len = sizeof(*block) - sizeof(block->data) - 1;
+
+	if (xor8_buf(block, rsvd0_off, xor_len) != 0xff)
 		return -EINVAL;
 
-	if (xor8_buf(block, sizeof(*block)) != 0xff)
+	if (xor8_buf(block, 0, sizeof(*block)) != 0xff)
 		return -EINVAL;
 
 	return 0;
 }
 
-static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token,
-			   int csum)
+static void calc_block_sig(struct mlx5_cmd_prot_block *block)
 {
-	block->token = token;
-	if (csum) {
-		block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) -
-					    sizeof(block->data) - 2);
-		block->sig = ~xor8_buf(block, sizeof(*block) - 1);
-	}
+	int ctrl_xor_len = sizeof(*block) - sizeof(block->data) - 2;
+	size_t rsvd0_off = offsetof(struct mlx5_cmd_prot_block, rsvd0);
+
+	block->ctrl_sig = ~xor8_buf(block, rsvd0_off, ctrl_xor_len);
+	block->sig = ~xor8_buf(block, 0, sizeof(*block) - 1);
 }
 
-static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token, int csum)
+static void calc_chain_sig(struct mlx5_cmd_msg *msg)
 {
 	struct mlx5_cmd_mailbox *next = msg->next;
+	int size = msg->len;
+	int blen = size - min_t(int, sizeof(msg->first.data), size);
+	int n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1)
+		/ MLX5_CMD_DATA_BLOCK_SIZE;
+	int i = 0;
 
-	while (next) {
-		calc_block_sig(next->buf, token, csum);
+	for (i = 0; i < n && next; i++)  {
+		calc_block_sig(next->buf);
 		next = next->next;
 	}
 }
 
 static void set_signature(struct mlx5_cmd_work_ent *ent, int csum)
 {
-	ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay));
-	calc_chain_sig(ent->in, ent->token, csum);
-	calc_chain_sig(ent->out, ent->token, csum);
+	ent->lay->sig = ~xor8_buf(ent->lay, 0,  sizeof(*ent->lay));
+	if (csum) {
+		calc_chain_sig(ent->in);
+		calc_chain_sig(ent->out);
+	}
 }
 
 static void poll_timeout(struct mlx5_cmd_work_ent *ent)
@@ -222,12 +231,17 @@
 	struct mlx5_cmd_mailbox *next = ent->out->next;
 	int err;
 	u8 sig;
+	int size = ent->out->len;
+	int blen = size - min_t(int, sizeof(ent->out->first.data), size);
+	int n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1)
+		/ MLX5_CMD_DATA_BLOCK_SIZE;
+	int i = 0;
 
-	sig = xor8_buf(ent->lay, sizeof(*ent->lay));
+	sig = xor8_buf(ent->lay, 0, sizeof(*ent->lay));
 	if (sig != 0xff)
 		return -EINVAL;
 
-	while (next) {
+	for (i = 0; i < n && next; i++) {
 		err = verify_block_sig(next->buf);
 		if (err)
 			return err;
@@ -616,24 +630,66 @@
 		pr_debug("\n");
 }
 
+static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
+static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
+			      struct mlx5_cmd_msg *msg);
+
+static u16 msg_to_opcode(struct mlx5_cmd_msg *in)
+{
+	struct mlx5_inbox_hdr *hdr = (struct mlx5_inbox_hdr *)(in->first.data);
+
+	return be16_to_cpu(hdr->opcode);
+}
+
+static void cb_timeout_handler(struct work_struct *work)
+{
+	struct delayed_work *dwork = container_of(work, struct delayed_work,
+						  work);
+	struct mlx5_cmd_work_ent *ent = container_of(dwork,
+						     struct mlx5_cmd_work_ent,
+						     cb_timeout_work);
+	struct mlx5_core_dev *dev = container_of(ent->cmd, struct mlx5_core_dev,
+						 cmd);
+
+	ent->ret = -ETIMEDOUT;
+	mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
+		       mlx5_command_str(msg_to_opcode(ent->in)),
+		       msg_to_opcode(ent->in));
+	mlx5_cmd_comp_handler(dev, 1UL << ent->idx);
+}
+
 static void cmd_work_handler(struct work_struct *work)
 {
 	struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
 	struct mlx5_cmd *cmd = ent->cmd;
 	struct mlx5_core_dev *dev = container_of(cmd, struct mlx5_core_dev, cmd);
+	unsigned long cb_timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC);
 	struct mlx5_cmd_layout *lay;
 	struct semaphore *sem;
 	unsigned long flags;
+	int alloc_ret;
+	int cmd_mode;
 
+	complete(&ent->handling);
 	sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
 	down(sem);
 	if (!ent->page_queue) {
-		ent->idx = alloc_ent(cmd);
-		if (ent->idx < 0) {
+		alloc_ret = alloc_ent(cmd);
+		if (alloc_ret < 0) {
+			if (ent->callback) {
+				ent->callback(-EAGAIN, ent->context);
+				mlx5_free_cmd_msg(dev, ent->out);
+				free_msg(dev, ent->in);
+				free_cmd(ent);
+			} else {
+				ent->ret = -EAGAIN;
+				complete(&ent->done);
+			}
 			mlx5_core_err(dev, "failed to allocate command entry\n");
 			up(sem);
 			return;
 		}
+		ent->idx = alloc_ret;
 	} else {
 		ent->idx = cmd->max_reg_cmds;
 		spin_lock_irqsave(&cmd->alloc_lock, flags);
@@ -641,7 +697,6 @@
 		spin_unlock_irqrestore(&cmd->alloc_lock, flags);
 	}
 
-	ent->token = alloc_token(cmd);
 	cmd->ent_arr[ent->idx] = ent;
 	lay = get_inst(cmd, ent->idx);
 	ent->lay = lay;
@@ -660,6 +715,10 @@
 	set_signature(ent, !cmd->checksum_disabled);
 	dump_command(dev, ent, 1);
 	ent->ts1 = ktime_get_ns();
+	cmd_mode = cmd->mode;
+
+	if (ent->callback)
+		schedule_delayed_work(&ent->cb_timeout_work, cb_timeout);
 
 	/* ring doorbell after the descriptor is valid */
 	mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx);
@@ -667,7 +726,7 @@
 	iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell);
 	mmiowb();
 	/* if not in polling don't use ent after this point */
-	if (cmd->mode == CMD_MODE_POLLING) {
+	if (cmd_mode == CMD_MODE_POLLING) {
 		poll_timeout(ent);
 		/* make sure we read the descriptor after ownership is SW */
 		rmb();
@@ -705,32 +764,36 @@
 	}
 }
 
-static u16 msg_to_opcode(struct mlx5_cmd_msg *in)
-{
-	struct mlx5_inbox_hdr *hdr = (struct mlx5_inbox_hdr *)(in->first.data);
-
-	return be16_to_cpu(hdr->opcode);
-}
-
 static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
 {
 	unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC);
 	struct mlx5_cmd *cmd = &dev->cmd;
 	int err;
 
+	if (!wait_for_completion_timeout(&ent->handling, timeout) &&
+	    cancel_work_sync(&ent->work)) {
+		ent->ret = -ECANCELED;
+		goto out_err;
+	}
+
 	if (cmd->mode == CMD_MODE_POLLING) {
 		wait_for_completion(&ent->done);
-		err = ent->ret;
-	} else {
-		if (!wait_for_completion_timeout(&ent->done, timeout))
-			err = -ETIMEDOUT;
-		else
-			err = 0;
+	} else if (!wait_for_completion_timeout(&ent->done, timeout)) {
+		ent->ret = -ETIMEDOUT;
+		mlx5_cmd_comp_handler(dev, 1UL << ent->idx);
 	}
+
+out_err:
+	err = ent->ret;
+
 	if (err == -ETIMEDOUT) {
 		mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
 			       mlx5_command_str(msg_to_opcode(ent->in)),
 			       msg_to_opcode(ent->in));
+	} else if (err == -ECANCELED) {
+		mlx5_core_warn(dev, "%s(0x%x) canceled on out of queue timeout.\n",
+			       mlx5_command_str(msg_to_opcode(ent->in)),
+			       msg_to_opcode(ent->in));
 	}
 	mlx5_core_dbg(dev, "err %d, delivery status %s(%d)\n",
 		      err, deliv_status_to_str(ent->status), ent->status);
@@ -755,7 +818,8 @@
 static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
 			   struct mlx5_cmd_msg *out, void *uout, int uout_size,
 			   mlx5_cmd_cbk_t callback,
-			   void *context, int page_queue, u8 *status)
+			   void *context, int page_queue, u8 *status,
+			   u8 token)
 {
 	struct mlx5_cmd *cmd = &dev->cmd;
 	struct mlx5_cmd_work_ent *ent;
@@ -772,9 +836,13 @@
 	if (IS_ERR(ent))
 		return PTR_ERR(ent);
 
+	ent->token = token;
+
+	init_completion(&ent->handling);
 	if (!callback)
 		init_completion(&ent->done);
 
+	INIT_DELAYED_WORK(&ent->cb_timeout_work, cb_timeout_handler);
 	INIT_WORK(&ent->work, cmd_work_handler);
 	if (page_queue) {
 		cmd_work_handler(&ent->work);
@@ -784,28 +852,28 @@
 		goto out_free;
 	}
 
-	if (!callback) {
-		err = wait_func(dev, ent);
-		if (err == -ETIMEDOUT)
-			goto out;
-
-		ds = ent->ts2 - ent->ts1;
-		op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
-		if (op < ARRAY_SIZE(cmd->stats)) {
-			stats = &cmd->stats[op];
-			spin_lock_irq(&stats->lock);
-			stats->sum += ds;
-			++stats->n;
-			spin_unlock_irq(&stats->lock);
-		}
-		mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME,
-				   "fw exec time for %s is %lld nsec\n",
-				   mlx5_command_str(op), ds);
-		*status = ent->status;
-		free_cmd(ent);
-	}
+	if (callback)
+		goto out;
+	if (err == -ECANCELED)
+		goto out_free;
 
-	return err;
+	err = wait_func(dev, ent);
+	if (err == -ETIMEDOUT)
+		goto out_free;
+
+	ds = ent->ts2 - ent->ts1;
+	op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
+	if (op < ARRAY_SIZE(cmd->stats)) {
+		stats = &cmd->stats[op];
+		spin_lock_irq(&stats->lock);
+		stats->sum += ds;
+		++stats->n;
+		spin_unlock_irq(&stats->lock);
+	}
+	mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME,
+			   "fw exec time for %s is %lld nsec\n",
+			   mlx5_command_str(op), ds);
+	*status = ent->status;
 
 out_free:
 	free_cmd(ent);
@@ -844,7 +912,8 @@
 	.write	= dbg_write,
 };
 
-static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size)
+static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size,
+			    u8 token)
 {
 	struct mlx5_cmd_prot_block *block;
 	struct mlx5_cmd_mailbox *next;
@@ -870,6 +939,7 @@
 		memcpy(block->data, from, copy);
 		from += copy;
 		size -= copy;
+		block->token = token;
 		next = next->next;
 	}
 
@@ -939,7 +1009,8 @@
 }
 
 static struct mlx5_cmd_msg *mlx5_alloc_cmd_msg(struct mlx5_core_dev *dev,
-					       gfp_t flags, int size)
+					       gfp_t flags, int size,
+					       u8 token)
 {
 	struct mlx5_cmd_mailbox *tmp, *head = NULL;
 	struct mlx5_cmd_prot_block *block;
@@ -968,6 +1039,7 @@
 		tmp->next = head;
 		block->next = cpu_to_be64(tmp->next ? tmp->next->dma : 0);
 		block->block_num = cpu_to_be32(n - i - 1);
+		block->token = token;
 		head = tmp;
 	}
 	msg->next = head;
@@ -1091,7 +1163,7 @@
 {
 	struct mlx5_core_dev *dev = filp->private_data;
 	struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
-	char outlen_str[8];
+	char outlen_str[8] = {0};
 	int outlen;
 	void *ptr;
 	int err;
@@ -1106,8 +1178,6 @@
 	if (copy_from_user(outlen_str, buf, count))
 		return -EFAULT;
 
-	outlen_str[7] = 0;
-
 	err = sscanf(outlen_str, "%d", &outlen);
 	if (err < 0)
 		return err;
@@ -1195,41 +1265,30 @@
 	return err;
 }
 
-void mlx5_cmd_use_events(struct mlx5_core_dev *dev)
+static void mlx5_cmd_change_mod(struct mlx5_core_dev *dev, int mode)
 {
 	struct mlx5_cmd *cmd = &dev->cmd;
 	int i;
 
 	for (i = 0; i < cmd->max_reg_cmds; i++)
 		down(&cmd->sem);
-
 	down(&cmd->pages_sem);
 
-	flush_workqueue(cmd->wq);
-
-	cmd->mode = CMD_MODE_EVENTS;
+	cmd->mode = mode;
 
 	up(&cmd->pages_sem);
 	for (i = 0; i < cmd->max_reg_cmds; i++)
 		up(&cmd->sem);
 }
 
-void mlx5_cmd_use_polling(struct mlx5_core_dev *dev)
+void mlx5_cmd_use_events(struct mlx5_core_dev *dev)
 {
-	struct mlx5_cmd *cmd = &dev->cmd;
-	int i;
-
-	for (i = 0; i < cmd->max_reg_cmds; i++)
-		down(&cmd->sem);
-
-	down(&cmd->pages_sem);
-
-	flush_workqueue(cmd->wq);
-	cmd->mode = CMD_MODE_POLLING;
+	mlx5_cmd_change_mod(dev, CMD_MODE_EVENTS);
+}
 
-	up(&cmd->pages_sem);
-	for (i = 0; i < cmd->max_reg_cmds; i++)
-		up(&cmd->sem);
+void mlx5_cmd_use_polling(struct mlx5_core_dev *dev)
+{
+	mlx5_cmd_change_mod(dev, CMD_MODE_POLLING);
 }
 
 static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
@@ -1265,6 +1324,8 @@
 			struct semaphore *sem;
 
 			ent = cmd->ent_arr[i];
+			if (ent->callback)
+				cancel_delayed_work(&ent->cb_timeout_work);
 			if (ent->page_queue)
 				sem = &cmd->pages_sem;
 			else
@@ -1351,7 +1412,7 @@
 	}
 
 	if (IS_ERR(msg))
-		msg = mlx5_alloc_cmd_msg(dev, gfp, in_size);
+		msg = mlx5_alloc_cmd_msg(dev, gfp, in_size, 0);
 
 	return msg;
 }
@@ -1376,6 +1437,7 @@
 	int err;
 	u8 status = 0;
 	u32 drv_synd;
+	u8 token;
 
 	if (pci_channel_offline(dev->pdev) ||
 	    dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
@@ -1394,20 +1456,22 @@
 		return err;
 	}
 
-	err = mlx5_copy_to_msg(inb, in, in_size);
+	token = alloc_token(&dev->cmd);
+
+	err = mlx5_copy_to_msg(inb, in, in_size, token);
 	if (err) {
 		mlx5_core_warn(dev, "err %d\n", err);
 		goto out_in;
 	}
 
-	outb = mlx5_alloc_cmd_msg(dev, gfp, out_size);
+	outb = mlx5_alloc_cmd_msg(dev, gfp, out_size, token);
 	if (IS_ERR(outb)) {
 		err = PTR_ERR(outb);
 		goto out_in;
 	}
 
 	err = mlx5_cmd_invoke(dev, inb, outb, out, out_size, callback, context,
-			      pages_queue, &status);
+			      pages_queue, &status, token);
 	if (err)
 		goto out_out;
 
@@ -1475,7 +1539,7 @@
 	INIT_LIST_HEAD(&cmd->cache.med.head);
 
 	for (i = 0; i < NUM_LONG_LISTS; i++) {
-		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE);
+		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE, 0);
 		if (IS_ERR(msg)) {
 			err = PTR_ERR(msg);
 			goto ex_err;
@@ -1485,7 +1549,7 @@
 	}
 
 	for (i = 0; i < NUM_MED_LISTS; i++) {
-		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE);
+		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE, 0);
 		if (IS_ERR(msg)) {
 			err = PTR_ERR(msg);
 			goto ex_err;
@@ -1585,7 +1649,7 @@
 
 	cmd->checksum_disabled = 1;
 	cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
-	cmd->bitmask = (1 << cmd->max_reg_cmds) - 1;
+	cmd->bitmask = (1UL << cmd->max_reg_cmds) - 1;
 
 	cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16;
 	if (cmd->cmdif_rev > CMD_IF_REV) {
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -35,6 +35,7 @@
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/qp.h>
 #include <linux/mlx5/cq.h>
+#include <linux/mlx5/port.h>
 #include <linux/mlx5/vport.h>
 #include "wq.h"
 #include "transobj.h"
@@ -465,6 +466,7 @@
 };
 
 struct mlx5e_vlan_db {
+	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
 	u32           active_vlans_ft_ix[VLAN_N_VID];
 	u32           untagged_rule_ft_ix;
 	u32           any_vlan_rule_ft_ix;
@@ -543,7 +545,7 @@
 	MLX5E_100GBASE_KR4	 = 22,
 	MLX5E_100GBASE_LR4	 = 23,
 	MLX5E_100BASE_TX	 = 24,
-	MLX5E_100BASE_T		 = 25,
+	MLX5E_1000BASE_T	 = 25,
 	MLX5E_10GBASE_T		 = 26,
 	MLX5E_25GBASE_CR	 = 27,
 	MLX5E_25GBASE_KR	 = 28,
@@ -586,6 +588,8 @@
 
 int mlx5e_open_locked(struct net_device *netdev);
 int mlx5e_close_locked(struct net_device *netdev);
+void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len,
+				   int num_channels);
 
 static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq,
 				      struct mlx5e_tx_wqe *wqe, int bf_sz)
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -138,10 +138,10 @@
 	[MLX5E_100BASE_TX]   = {
 		.speed      = 100,
 	},
-	[MLX5E_100BASE_T]    = {
-		.supported  = SUPPORTED_100baseT_Full,
-		.advertised = ADVERTISED_100baseT_Full,
-		.speed      = 100,
+	[MLX5E_1000BASE_T]    = {
+		.supported  = SUPPORTED_1000baseT_Full,
+		.advertised = ADVERTISED_1000baseT_Full,
+		.speed      = 1000,
 	},
 	[MLX5E_10GBASE_T]    = {
 		.supported  = SUPPORTED_10000baseT_Full,
@@ -385,6 +385,8 @@
 		mlx5e_close_locked(dev);
 
 	priv->params.num_channels = count;
+	mlx5e_build_default_indir_rqt(priv->params.indirection_rqt,
+				      MLX5E_INDIR_RQT_SIZE, count);
 
 	if (was_opened)
 		err = mlx5e_open_locked(dev);
@@ -399,6 +401,9 @@
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 
+	if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
+		return -ENOTSUPP;
+
 	coal->rx_coalesce_usecs       = priv->params.rx_cq_moderation_usec;
 	coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts;
 	coal->tx_coalesce_usecs       = priv->params.tx_cq_moderation_usec;
@@ -416,11 +421,18 @@
 	int tc;
 	int i;
 
+	if (!MLX5_CAP_GEN(mdev, cq_moderation))
+		return -ENOTSUPP;
+
+	mutex_lock(&priv->state_lock);
 	priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs;
 	priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames;
 	priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs;
 	priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames;
 
+	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
+		goto out;
+
 	for (i = 0; i < priv->params.num_channels; ++i) {
 		c = priv->channel[i];
 
@@ -436,6 +448,8 @@
 					       coal->rx_max_coalesced_frames);
 	}
 
+out:
+	mutex_unlock(&priv->state_lock);
 	return 0;
 }
 
@@ -841,6 +855,9 @@
 	struct mlx5_core_dev *mdev = priv->mdev;
 	int err;
 
+	if (!MLX5_CAP_GEN(mdev, vport_group_manager))
+		return -EOPNOTSUPP;
+
 	if (pauseparam->autoneg)
 		return -EINVAL;
 
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c
@@ -502,6 +502,49 @@
 	return err;
 }
 
+static int mlx5e_vport_context_update_vlans(struct mlx5e_priv *priv)
+{
+	struct net_device *ndev = priv->netdev;
+	int max_list_size;
+	int list_size;
+	u16 *vlans;
+	int vlan;
+	int err;
+	int i;
+
+	list_size = 0;
+	for_each_set_bit(vlan, priv->vlan.active_vlans, VLAN_N_VID)
+		list_size++;
+
+	max_list_size = 1 << MLX5_CAP_GEN(priv->mdev, log_max_vlan_list);
+
+	if (list_size > max_list_size) {
+		netdev_warn(ndev,
+			    "netdev vlans list size (%d) > (%d) max vport list size, some vlans will be dropped\n",
+			    list_size, max_list_size);
+		list_size = max_list_size;
+	}
+
+	vlans = kcalloc(list_size, sizeof(*vlans), GFP_KERNEL);
+	if (!vlans)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_set_bit(vlan, priv->vlan.active_vlans, VLAN_N_VID) {
+		if (i >= list_size)
+			break;
+		vlans[i++] = vlan;
+	}
+
+	err = mlx5_modify_nic_vport_vlans(priv->mdev, vlans, list_size);
+	if (err)
+		netdev_err(ndev, "Failed to modify vport vlans list err(%d)\n",
+			   err);
+
+	kfree(vlans);
+	return err;
+}
+
 enum mlx5e_vlan_rule_type {
 	MLX5E_VLAN_RULE_TYPE_UNTAGGED,
 	MLX5E_VLAN_RULE_TYPE_ANY_VID,
@@ -552,6 +595,10 @@
 			 1);
 		break;
 	default: /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */
+		err = mlx5e_vport_context_update_vlans(priv);
+		if (err)
+			goto add_vlan_rule_out;
+
 		ft_ix = &priv->vlan.active_vlans_ft_ix[vid];
 		MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag,
 			 1);
@@ -588,6 +635,7 @@
 	case MLX5E_VLAN_RULE_TYPE_MATCH_VID:
 		mlx5_del_flow_table_entry(priv->ft.vlan,
 					  priv->vlan.active_vlans_ft_ix[vid]);
+		mlx5e_vport_context_update_vlans(priv);
 		break;
 	}
 }
@@ -619,6 +667,8 @@
 {
 	struct mlx5e_priv *priv = netdev_priv(dev);
 
+	set_bit(vid, priv->vlan.active_vlans);
+
 	return mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
 }
 
@@ -627,6 +677,8 @@
 {
 	struct mlx5e_priv *priv = netdev_priv(dev);
 
+	clear_bit(vid, priv->vlan.active_vlans);
+
 	mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
 
 	return 0;
@@ -671,6 +723,91 @@
 	netif_addr_unlock_bh(netdev);
 }
 
+static void mlx5e_fill_addr_array(struct mlx5e_priv *priv, int list_type,
+				  u8 addr_array[][ETH_ALEN], int size)
+{
+	bool is_uc = (list_type == MLX5_NVPRT_LIST_TYPE_UC);
+	struct net_device *ndev = priv->netdev;
+	struct mlx5e_eth_addr_hash_node *hn;
+	struct hlist_head *addr_list;
+	struct hlist_node *tmp;
+	int i = 0;
+	int hi;
+
+	addr_list = is_uc ? priv->eth_addr.netdev_uc : priv->eth_addr.netdev_mc;
+
+	if (is_uc) /* Make sure our own address is pushed first */
+		ether_addr_copy(addr_array[i++], ndev->dev_addr);
+	else if (priv->eth_addr.broadcast_enabled)
+		ether_addr_copy(addr_array[i++], ndev->broadcast);
+
+	mlx5e_for_each_hash_node(hn, tmp, addr_list, hi) {
+		if (ether_addr_equal(ndev->dev_addr, hn->ai.addr))
+			continue;
+		if (i >= size)
+			break;
+		ether_addr_copy(addr_array[i++], hn->ai.addr);
+	}
+}
+
+static void mlx5e_vport_context_update_addr_list(struct mlx5e_priv *priv,
+						 int list_type)
+{
+	bool is_uc = (list_type == MLX5_NVPRT_LIST_TYPE_UC);
+	struct mlx5e_eth_addr_hash_node *hn;
+	u8 (*addr_array)[ETH_ALEN] = NULL;
+	struct hlist_head *addr_list;
+	struct hlist_node *tmp;
+	int max_size;
+	int size;
+	int err;
+	int hi;
+
+	size = is_uc ? 0 : (priv->eth_addr.broadcast_enabled ? 1 : 0);
+	max_size = is_uc ?
+		1 << MLX5_CAP_GEN(priv->mdev, log_max_current_uc_list) :
+		1 << MLX5_CAP_GEN(priv->mdev, log_max_current_mc_list);
+
+	addr_list = is_uc ? priv->eth_addr.netdev_uc : priv->eth_addr.netdev_mc;
+	mlx5e_for_each_hash_node(hn, tmp, addr_list, hi)
+		size++;
+
+	if (size > max_size) {
+		netdev_warn(priv->netdev,
+			    "netdev %s list size (%d) > (%d) max vport list size, some addresses will be dropped\n",
+			    is_uc ? "UC" : "MC", size, max_size);
+		size = max_size;
+	}
+
+	if (size) {
+		addr_array = kcalloc(size, ETH_ALEN, GFP_KERNEL);
+		if (!addr_array) {
+			err = -ENOMEM;
+			goto out;
+		}
+		mlx5e_fill_addr_array(priv, list_type, addr_array, size);
+	}
+
+	err = mlx5_modify_nic_vport_mac_list(priv->mdev, list_type, addr_array, size);
+out:
+	if (err)
+		netdev_err(priv->netdev,
+			   "Failed to modify vport %s list err(%d)\n",
+			   is_uc ? "UC" : "MC", err);
+	kfree(addr_array);
+}
+
+static void mlx5e_vport_context_update(struct mlx5e_priv *priv)
+{
+	struct mlx5e_eth_addr_db *ea = &priv->eth_addr;
+
+	mlx5e_vport_context_update_addr_list(priv, MLX5_NVPRT_LIST_TYPE_UC);
+	mlx5e_vport_context_update_addr_list(priv, MLX5_NVPRT_LIST_TYPE_MC);
+	mlx5_modify_nic_vport_promisc(priv->mdev, 0,
+				      ea->allmulti_enabled,
+				      ea->promisc_enabled);
+}
+
 static void mlx5e_apply_netdev_addr(struct mlx5e_priv *priv)
 {
 	struct mlx5e_eth_addr_hash_node *hn;
@@ -748,6 +885,8 @@
 	ea->promisc_enabled   = promisc_enabled;
 	ea->allmulti_enabled  = allmulti_enabled;
 	ea->broadcast_enabled = broadcast_enabled;
+
+	mlx5e_vport_context_update(priv);
 }
 
 void mlx5e_init_eth_addr(struct mlx5e_priv *priv)
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -32,6 +32,7 @@
 
 #include <linux/mlx5/flow_table.h>
 #include "en.h"
+#include "eswitch.h"
 
 struct mlx5e_rq_param {
 	u32                        rqc[MLX5_ST_SZ_DW(rqc)];
@@ -63,7 +64,7 @@
 	u8 port_state;
 
 	port_state = mlx5_query_vport_state(mdev,
-		MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT);
+		MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT, 0);
 
 	if (port_state == VPORT_STATE_UP)
 		netif_carrier_on(priv->netdev);
@@ -746,7 +747,7 @@
 	struct mlx5_core_dev *mdev = priv->mdev;
 	struct mlx5_core_cq *mcq = &cq->mcq;
 	int eqn_not_used;
-	int irqn;
+	unsigned int irqn;
 	int err;
 	u32 i;
 
@@ -800,7 +801,7 @@
 	void *in;
 	void *cqc;
 	int inlen;
-	int irqn_not_used;
+	unsigned int irqn_not_used;
 	int eqn;
 	int err;
 
@@ -863,12 +864,10 @@
 	if (err)
 		goto err_destroy_cq;
 
-	err = mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
-					     moderation_usecs,
-					     moderation_frames);
-	if (err)
-		goto err_destroy_cq;
-
+	if (MLX5_CAP_GEN(mdev, cq_moderation))
+		mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
+					       moderation_usecs,
+					       moderation_frames);
 	return 0;
 
 err_destroy_cq:
@@ -1188,7 +1187,6 @@
 			ix = mlx5e_bits_invert(i, MLX5E_LOG_INDIR_RQT_SIZE);
 
 		ix = priv->params.indirection_rqt[ix];
-		ix = ix % priv->params.num_channels;
 		MLX5_SET(rqtc, rqtc, rq_num[i],
 			 test_bit(MLX5E_STATE_OPENED, &priv->state) ?
 			 priv->channel[ix]->rq.rqn :
@@ -1306,7 +1304,7 @@
 			      lro_timer_supported_periods[2]));
 }
 
-static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
+static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
 {
 	struct mlx5_core_dev *mdev = priv->mdev;
 
@@ -1314,6 +1312,7 @@
 	void *tirc;
 	int inlen;
 	int err;
+	int tt;
 
 	inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
 	in = mlx5_vzalloc(inlen);
@@ -1325,7 +1324,11 @@
 
 	mlx5e_build_tir_ctx_lro(tirc, priv);
 
-	err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen);
+	for (tt = 0; tt < MLX5E_NUM_TT; tt++) {
+		err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen);
+		if (err)
+			break;
+	}
 
 	kvfree(in);
 
@@ -1372,7 +1375,7 @@
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 	struct mlx5_core_dev *mdev = priv->mdev;
-	int hw_mtu;
+	u16 hw_mtu;
 	int err;
 
 	err = mlx5_set_port_mtu(mdev, MLX5E_SW2HW_MTU(netdev->mtu), 1);
@@ -1504,7 +1507,7 @@
 	struct mlx5_core_dev *mdev = priv->mdev;
 	struct mlx5_core_cq *mcq = &cq->mcq;
 	int eqn_not_used;
-	int irqn;
+	unsigned int irqn;
 	int err;
 
 	err = mlx5_cqwq_create(mdev, &param->wq, param->cqc, &cq->wq,
@@ -1872,8 +1875,10 @@
 			mlx5e_close_locked(priv->netdev);
 
 		priv->params.lro_en = !!(features & NETIF_F_LRO);
-		mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV4_TCP);
-		mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV6_TCP);
+		err = mlx5e_modify_tirs_lro(priv);
+		if (err)
+			mlx5_core_warn(priv->mdev, "lro modify failed, %d\n",
+				       err);
 
 		if (was_opened)
 			err = mlx5e_open_locked(priv->netdev);
@@ -1891,22 +1896,27 @@
 	return err;
 }
 
+#define MXL5_HW_MIN_MTU 64
+#define MXL5E_MIN_MTU (MXL5_HW_MIN_MTU + ETH_FCS_LEN)
+
 static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 	struct mlx5_core_dev *mdev = priv->mdev;
 	bool was_opened;
-	int max_mtu;
+	u16 max_mtu;
+	u16 min_mtu;
 	int err = 0;
 
 	mlx5_query_port_max_mtu(mdev, &max_mtu, 1);
 
 	max_mtu = MLX5E_HW2SW_MTU(max_mtu);
+	min_mtu = MLX5E_HW2SW_MTU(MXL5E_MIN_MTU);
 
-	if (new_mtu > max_mtu) {
+	if (new_mtu > max_mtu || new_mtu < min_mtu) {
 		netdev_err(netdev,
-			   "%s: Bad MTU (%d) > (%d) Max\n",
-			   __func__, new_mtu, max_mtu);
+			   "%s: Bad MTU (%d), valid range is: [%d..%d]\n",
+			   __func__, new_mtu, min_mtu, max_mtu);
 		return -EINVAL;
 	}
 
@@ -1926,6 +1936,79 @@
 	return err;
 }
 
+static int mlx5e_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
+{
+	struct mlx5e_priv *priv = netdev_priv(dev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+
+	return mlx5_eswitch_set_vport_mac(mdev->priv.eswitch, vf + 1, mac);
+}
+
+static int mlx5e_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos)
+{
+	struct mlx5e_priv *priv = netdev_priv(dev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+
+	return mlx5_eswitch_set_vport_vlan(mdev->priv.eswitch, vf + 1,
+					   vlan, qos);
+}
+
+static int mlx5_vport_link2ifla(u8 esw_link)
+{
+	switch (esw_link) {
+	case MLX5_ESW_VPORT_ADMIN_STATE_DOWN:
+		return IFLA_VF_LINK_STATE_DISABLE;
+	case MLX5_ESW_VPORT_ADMIN_STATE_UP:
+		return IFLA_VF_LINK_STATE_ENABLE;
+	}
+	return IFLA_VF_LINK_STATE_AUTO;
+}
+
+static int mlx5_ifla_link2vport(u8 ifla_link)
+{
+	switch (ifla_link) {
+	case IFLA_VF_LINK_STATE_DISABLE:
+		return MLX5_ESW_VPORT_ADMIN_STATE_DOWN;
+	case IFLA_VF_LINK_STATE_ENABLE:
+		return MLX5_ESW_VPORT_ADMIN_STATE_UP;
+	}
+	return MLX5_ESW_VPORT_ADMIN_STATE_AUTO;
+}
+
+static int mlx5e_set_vf_link_state(struct net_device *dev, int vf,
+				   int link_state)
+{
+	struct mlx5e_priv *priv = netdev_priv(dev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+
+	return mlx5_eswitch_set_vport_state(mdev->priv.eswitch, vf + 1,
+					    mlx5_ifla_link2vport(link_state));
+}
+
+static int mlx5e_get_vf_config(struct net_device *dev,
+			       int vf, struct ifla_vf_info *ivi)
+{
+	struct mlx5e_priv *priv = netdev_priv(dev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+	int err;
+
+	err = mlx5_eswitch_get_vport_config(mdev->priv.eswitch, vf + 1, ivi);
+	if (err)
+		return err;
+	ivi->linkstate = mlx5_vport_link2ifla(ivi->linkstate);
+	return 0;
+}
+
+static int mlx5e_get_vf_stats(struct net_device *dev,
+			      int vf, struct ifla_vf_stats *vf_stats)
+{
+	struct mlx5e_priv *priv = netdev_priv(dev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+
+	return mlx5_eswitch_get_vport_stats(mdev->priv.eswitch, vf + 1,
+					    vf_stats);
+}
+
 static struct net_device_ops mlx5e_netdev_ops = {
 	.ndo_open                = mlx5e_open,
 	.ndo_stop                = mlx5e_close,
@@ -1936,7 +2019,7 @@
 	.ndo_vlan_rx_add_vid	 = mlx5e_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid	 = mlx5e_vlan_rx_kill_vid,
 	.ndo_set_features        = mlx5e_set_features,
-	.ndo_change_mtu		 = mlx5e_change_mtu,
+	.ndo_change_mtu		 = mlx5e_change_mtu
 };
 
 static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
@@ -1958,6 +2041,8 @@
 	}
 	if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable))
 		mlx5_core_warn(mdev, "Self loop back prevention is not supported\n");
+	if (!MLX5_CAP_GEN(mdev, cq_moderation))
+		mlx5_core_warn(mdev, "CQ modiration is not supported\n");
 
 	return 0;
 }
@@ -1971,12 +2056,20 @@
 	       2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/;
 }
 
+void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len,
+				   int num_channels)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		indirection_rqt[i] = i % num_channels;
+}
+
 static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
 				    struct net_device *netdev,
 				    int num_channels)
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
-	int i;
 
 	priv->params.log_sq_size           =
 		MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
@@ -2000,8 +2093,8 @@
 	netdev_rss_key_fill(priv->params.toeplitz_hash_key,
 			    sizeof(priv->params.toeplitz_hash_key));
 
-	for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++)
-		priv->params.indirection_rqt[i] = i % num_channels;
+	mlx5e_build_default_indir_rqt(priv->params.indirection_rqt,
+				      MLX5E_INDIR_RQT_SIZE, num_channels);
 
 	priv->params.lro_wqe_sz            =
 		MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ;
@@ -2023,7 +2116,12 @@
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 
-	mlx5_query_nic_vport_mac_address(priv->mdev, netdev->dev_addr);
+	mlx5_query_nic_vport_mac_address(priv->mdev, 0, netdev->dev_addr);
+	if (is_zero_ether_addr(netdev->dev_addr) &&
+	    !MLX5_CAP_GEN(priv->mdev, vport_group_manager)) {
+		eth_hw_addr_random(netdev);
+		mlx5_core_info(priv->mdev, "Assigned random MAC address %pM\n", netdev->dev_addr);
+	}
 }
 
 static void mlx5e_build_netdev(struct net_device *netdev)
@@ -2036,6 +2134,14 @@
 	if (priv->params.num_tc > 1)
 		mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue;
 
+	if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
+		mlx5e_netdev_ops.ndo_set_vf_mac = mlx5e_set_vf_mac;
+		mlx5e_netdev_ops.ndo_set_vf_vlan = mlx5e_set_vf_vlan;
+		mlx5e_netdev_ops.ndo_get_vf_config = mlx5e_get_vf_config;
+		mlx5e_netdev_ops.ndo_set_vf_link_state = mlx5e_set_vf_link_state;
+		mlx5e_netdev_ops.ndo_get_vf_stats = mlx5e_get_vf_stats;
+	}
+
 	netdev->netdev_ops        = &mlx5e_netdev_ops;
 	netdev->watchdog_timeo    = 15 * HZ;
 
@@ -2236,7 +2342,16 @@
 	schedule_work(&priv->set_rx_mode_work);
 	mlx5e_disable_async_events(priv);
 	flush_scheduled_work();
-	unregister_netdev(netdev);
+	if (test_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &mdev->intf_state)) {
+		netif_device_detach(netdev);
+		mutex_lock(&priv->state_lock);
+		if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+			mlx5e_close_locked(netdev);
+		mutex_unlock(&priv->state_lock);
+	} else {
+		unregister_netdev(netdev);
+	}
+
 	mlx5e_destroy_flow_tables(priv);
 	mlx5e_destroy_tirs(priv);
 	mlx5e_destroy_rqt(priv, MLX5E_SINGLE_RQ_RQT);
@@ -2247,7 +2362,9 @@
 	mlx5_dealloc_transport_domain(priv->mdev, priv->tdn);
 	mlx5_core_dealloc_pd(priv->mdev, priv->pdn);
 	mlx5_unmap_free_uar(priv->mdev, &priv->cq_uar);
-	free_netdev(netdev);
+
+	if (!test_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &mdev->intf_state))
+		free_netdev(netdev);
 }
 
 static void *mlx5e_get_netdev(void *vpriv)
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -197,6 +197,10 @@
 	if (lro_num_seg > 1) {
 		mlx5e_lro_update_hdr(skb, cqe);
 		skb_shinfo(skb)->gso_size = DIV_ROUND_UP(cqe_bcnt, lro_num_seg);
+		/* Subtract one since we already counted this as one
+		 * "regular" packet in mlx5e_complete_rx_cqe()
+		 */
+		rq->stats.packets += lro_num_seg - 1;
 		rq->stats.lro_packets++;
 		rq->stats.lro_bytes += cqe_bcnt;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -124,7 +124,7 @@
 	 * headers and occur before the data gather.
 	 * Therefore these headers must be copied into the WQE
 	 */
-#define MLX5E_MIN_INLINE ETH_HLEN
+#define MLX5E_MIN_INLINE (ETH_HLEN + VLAN_HLEN)
 
 	if (bf) {
 		u16 ihs = skb_headlen(skb);
@@ -136,7 +136,7 @@
 			return skb_headlen(skb);
 	}
 
-	return MLX5E_MIN_INLINE;
+	return max(skb_network_offset(skb), MLX5E_MIN_INLINE);
 }
 
 static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs)
@@ -290,7 +290,8 @@
 	while ((sq->pc & wq->sz_m1) > sq->edge)
 		mlx5e_send_nop(sq, false);
 
-	sq->bf_budget = bf ? sq->bf_budget - 1 : 0;
+	if (bf)
+		sq->bf_budget--;
 
 	sq->stats.packets++;
 	return NETDEV_TX_OK;
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -35,6 +35,9 @@
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/cmd.h>
 #include "mlx5_core.h"
+#ifdef CONFIG_MLX5_CORE_EN
+#include "eswitch.h"
+#endif
 
 enum {
 	MLX5_EQE_SIZE		= sizeof(struct mlx5_eqe),
@@ -287,6 +290,11 @@
 			break;
 #endif
 
+#ifdef CONFIG_MLX5_CORE_EN
+		case MLX5_EVENT_TYPE_NIC_VPORT_CHANGE:
+			mlx5_eswitch_vport_event(dev->priv.eswitch, eqe);
+			break;
+#endif
 		default:
 			mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n",
 				       eqe->type, eq->eqn);
@@ -459,6 +467,11 @@
 	if (MLX5_CAP_GEN(dev, pg))
 		async_event_mask |= (1ull << MLX5_EVENT_TYPE_PAGE_FAULT);
 
+	if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_ETH &&
+	    MLX5_CAP_GEN(dev, vport_group_manager) &&
+	    mlx5_core_is_pf(dev))
+		async_event_mask |= (1ull << MLX5_EVENT_TYPE_NIC_VPORT_CHANGE);
+
 	err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD,
 				 MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD,
 				 "mlx5_cmd_eq", &dev->priv.uuari.uars[0]);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -0,0 +1,1282 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/mlx5_ifc.h>
+#include <linux/mlx5/vport.h>
+#include <linux/mlx5/flow_table.h>
+#include "mlx5_core.h"
+#include "eswitch.h"
+
+#define UPLINK_VPORT 0xFFFF
+
+#define MLX5_DEBUG_ESWITCH_MASK BIT(3)
+
+#define esw_info(dev, format, ...)				\
+	pr_info("(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
+
+#define esw_warn(dev, format, ...)				\
+	pr_warn("(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
+
+#define esw_debug(dev, format, ...)				\
+	mlx5_core_dbg_mask(dev, MLX5_DEBUG_ESWITCH_MASK, format, ##__VA_ARGS__)
+
+enum {
+	MLX5_ACTION_NONE = 0,
+	MLX5_ACTION_ADD  = 1,
+	MLX5_ACTION_DEL  = 2,
+};
+
+/* E-Switch UC L2 table hash node */
+struct esw_uc_addr {
+	struct l2addr_node node;
+	u32                table_index;
+	u32                vport;
+};
+
+/* E-Switch MC FDB table hash node */
+struct esw_mc_addr { /* SRIOV only */
+	struct l2addr_node     node;
+	struct mlx5_flow_rule *uplink_rule; /* Forward to uplink rule */
+	u32                    refcnt;
+};
+
+/* Vport UC/MC hash node */
+struct vport_addr {
+	struct l2addr_node     node;
+	u8                     action;
+	u32                    vport;
+	struct mlx5_flow_rule *flow_rule; /* SRIOV only */
+};
+
+enum {
+	UC_ADDR_CHANGE = BIT(0),
+	MC_ADDR_CHANGE = BIT(1),
+};
+
+/* Vport context events */
+#define SRIOV_VPORT_EVENTS (UC_ADDR_CHANGE | \
+			    MC_ADDR_CHANGE)
+
+static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,
+					u32 events_mask)
+{
+	int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)];
+	int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)];
+	void *nic_vport_ctx;
+	int err;
+
+	memset(out, 0, sizeof(out));
+	memset(in, 0, sizeof(in));
+
+	MLX5_SET(modify_nic_vport_context_in, in,
+		 opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
+	MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1);
+	MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
+	if (vport)
+		MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
+	nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
+				     in, nic_vport_context);
+
+	MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1);
+
+	if (events_mask & UC_ADDR_CHANGE)
+		MLX5_SET(nic_vport_context, nic_vport_ctx,
+			 event_on_uc_address_change, 1);
+	if (events_mask & MC_ADDR_CHANGE)
+		MLX5_SET(nic_vport_context, nic_vport_ctx,
+			 event_on_mc_address_change, 1);
+
+	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+	if (err)
+		goto ex;
+	err = mlx5_cmd_status_to_err_v2(out);
+	if (err)
+		goto ex;
+	return 0;
+ex:
+	return err;
+}
+
+/* E-Switch vport context HW commands */
+static int query_esw_vport_context_cmd(struct mlx5_core_dev *mdev, u32 vport,
+				       u32 *out, int outlen)
+{
+	u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)];
+
+	memset(in, 0, sizeof(in));
+
+	MLX5_SET(query_nic_vport_context_in, in, opcode,
+		 MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
+
+	MLX5_SET(query_esw_vport_context_in, in, vport_number, vport);
+	if (vport)
+		MLX5_SET(query_esw_vport_context_in, in, other_vport, 1);
+
+	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen);
+}
+
+static int query_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
+				 u16 *vlan, u8 *qos)
+{
+	u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)];
+	int err;
+	bool cvlan_strip;
+	bool cvlan_insert;
+
+	memset(out, 0, sizeof(out));
+
+	*vlan = 0;
+	*qos = 0;
+
+	if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
+	    !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
+		return -ENOTSUPP;
+
+	err = query_esw_vport_context_cmd(dev, vport, out, sizeof(out));
+	if (err)
+		goto out;
+
+	cvlan_strip = MLX5_GET(query_esw_vport_context_out, out,
+			       esw_vport_context.vport_cvlan_strip);
+
+	cvlan_insert = MLX5_GET(query_esw_vport_context_out, out,
+				esw_vport_context.vport_cvlan_insert);
+
+	if (cvlan_strip || cvlan_insert) {
+		*vlan = MLX5_GET(query_esw_vport_context_out, out,
+				 esw_vport_context.cvlan_id);
+		*qos = MLX5_GET(query_esw_vport_context_out, out,
+				esw_vport_context.cvlan_pcp);
+	}
+
+	esw_debug(dev, "Query Vport[%d] cvlan: VLAN %d qos=%d\n",
+		  vport, *vlan, *qos);
+out:
+	return err;
+}
+
+static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport,
+					void *in, int inlen)
+{
+	u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)];
+
+	memset(out, 0, sizeof(out));
+
+	MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
+	if (vport)
+		MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1);
+
+	MLX5_SET(modify_esw_vport_context_in, in, opcode,
+		 MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);
+
+	return mlx5_cmd_exec_check_status(dev, in, inlen,
+					  out, sizeof(out));
+}
+
+static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
+				  u16 vlan, u8 qos, bool set)
+{
+	u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)];
+
+	memset(in, 0, sizeof(in));
+
+	if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
+	    !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
+		return -ENOTSUPP;
+
+	esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%d\n",
+		  vport, vlan, qos, set);
+
+	if (set) {
+		MLX5_SET(modify_esw_vport_context_in, in,
+			 esw_vport_context.vport_cvlan_strip, 1);
+		/* insert only if no vlan in packet */
+		MLX5_SET(modify_esw_vport_context_in, in,
+			 esw_vport_context.vport_cvlan_insert, 1);
+		MLX5_SET(modify_esw_vport_context_in, in,
+			 esw_vport_context.cvlan_pcp, qos);
+		MLX5_SET(modify_esw_vport_context_in, in,
+			 esw_vport_context.cvlan_id, vlan);
+	}
+
+	MLX5_SET(modify_esw_vport_context_in, in,
+		 field_select.vport_cvlan_strip, 1);
+	MLX5_SET(modify_esw_vport_context_in, in,
+		 field_select.vport_cvlan_insert, 1);
+
+	return modify_esw_vport_context_cmd(dev, vport, in, sizeof(in));
+}
+
+/* HW L2 Table (MPFS) management */
+static int set_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index,
+				  u8 *mac, u8 vlan_valid, u16 vlan)
+{
+	u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)];
+	u32 out[MLX5_ST_SZ_DW(set_l2_table_entry_out)];
+	u8 *in_mac_addr;
+
+	memset(in, 0, sizeof(in));
+	memset(out, 0, sizeof(out));
+
+	MLX5_SET(set_l2_table_entry_in, in, opcode,
+		 MLX5_CMD_OP_SET_L2_TABLE_ENTRY);
+	MLX5_SET(set_l2_table_entry_in, in, table_index, index);
+	MLX5_SET(set_l2_table_entry_in, in, vlan_valid, vlan_valid);
+	MLX5_SET(set_l2_table_entry_in, in, vlan, vlan);
+
+	in_mac_addr = MLX5_ADDR_OF(set_l2_table_entry_in, in, mac_address);
+	ether_addr_copy(&in_mac_addr[2], mac);
+
+	return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
+					  out, sizeof(out));
+}
+
+static int del_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index)
+{
+	u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)];
+	u32 out[MLX5_ST_SZ_DW(delete_l2_table_entry_out)];
+
+	memset(in, 0, sizeof(in));
+	memset(out, 0, sizeof(out));
+
+	MLX5_SET(delete_l2_table_entry_in, in, opcode,
+		 MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY);
+	MLX5_SET(delete_l2_table_entry_in, in, table_index, index);
+	return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
+					  out, sizeof(out));
+}
+
+static int alloc_l2_table_index(struct mlx5_l2_table *l2_table, u32 *ix)
+{
+	int err = 0;
+
+	*ix = find_first_zero_bit(l2_table->bitmap, l2_table->size);
+	if (*ix >= l2_table->size)
+		err = -ENOSPC;
+	else
+		__set_bit(*ix, l2_table->bitmap);
+
+	return err;
+}
+
+static void free_l2_table_index(struct mlx5_l2_table *l2_table, u32 ix)
+{
+	__clear_bit(ix, l2_table->bitmap);
+}
+
+static int set_l2_table_entry(struct mlx5_core_dev *dev, u8 *mac,
+			      u8 vlan_valid, u16 vlan,
+			      u32 *index)
+{
+	struct mlx5_l2_table *l2_table = &dev->priv.eswitch->l2_table;
+	int err;
+
+	err = alloc_l2_table_index(l2_table, index);
+	if (err)
+		return err;
+
+	err = set_l2_table_entry_cmd(dev, *index, mac, vlan_valid, vlan);
+	if (err)
+		free_l2_table_index(l2_table, *index);
+
+	return err;
+}
+
+static void del_l2_table_entry(struct mlx5_core_dev *dev, u32 index)
+{
+	struct mlx5_l2_table *l2_table = &dev->priv.eswitch->l2_table;
+
+	del_l2_table_entry_cmd(dev, index);
+	free_l2_table_index(l2_table, index);
+}
+
+/* E-Switch FDB flow steering */
+struct dest_node {
+	struct list_head list;
+	struct mlx5_flow_destination dest;
+};
+
+static int _mlx5_flow_rule_apply(struct mlx5_flow_rule *fr)
+{
+	bool was_valid = fr->valid;
+	struct dest_node *dest_n;
+	u32 dest_list_size = 0;
+	void *in_match_value;
+	u32 *flow_context;
+	u32 flow_index;
+	int err;
+	int i;
+
+	if (list_empty(&fr->dest_list)) {
+		if (fr->valid)
+			mlx5_del_flow_table_entry(fr->ft, fr->fi);
+		fr->valid = false;
+		return 0;
+	}
+
+	list_for_each_entry(dest_n, &fr->dest_list, list)
+		dest_list_size++;
+
+	flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) +
+				    MLX5_ST_SZ_BYTES(dest_format_struct) *
+				    dest_list_size);
+	if (!flow_context)
+		return -ENOMEM;
+
+	MLX5_SET(flow_context, flow_context, flow_tag, fr->flow_tag);
+	MLX5_SET(flow_context, flow_context, action, fr->action);
+	MLX5_SET(flow_context, flow_context, destination_list_size,
+		 dest_list_size);
+
+	i = 0;
+	list_for_each_entry(dest_n, &fr->dest_list, list) {
+		void *dest_addr = MLX5_ADDR_OF(flow_context, flow_context,
+					       destination[i++]);
+
+		MLX5_SET(dest_format_struct, dest_addr, destination_type,
+			 dest_n->dest.type);
+		MLX5_SET(dest_format_struct, dest_addr, destination_id,
+			 dest_n->dest.vport_num);
+	}
+
+	in_match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
+	memcpy(in_match_value, fr->match_value, MLX5_ST_SZ_BYTES(fte_match_param));
+
+	err = mlx5_add_flow_table_entry(fr->ft, fr->match_criteria_enable,
+					fr->match_criteria, flow_context,
+					&flow_index);
+	if (!err) {
+		if (was_valid)
+			mlx5_del_flow_table_entry(fr->ft, fr->fi);
+		fr->fi = flow_index;
+		fr->valid = true;
+	}
+	kfree(flow_context);
+	return err;
+}
+
+static int mlx5_flow_rule_add_dest(struct mlx5_flow_rule *fr,
+				   struct mlx5_flow_destination *new_dest)
+{
+	struct dest_node *dest_n;
+	int err;
+
+	dest_n = kzalloc(sizeof(*dest_n), GFP_KERNEL);
+	if (!dest_n)
+		return -ENOMEM;
+
+	memcpy(&dest_n->dest, new_dest, sizeof(dest_n->dest));
+	mutex_lock(&fr->mutex);
+	list_add(&dest_n->list, &fr->dest_list);
+	err = _mlx5_flow_rule_apply(fr);
+	if (err) {
+		list_del(&dest_n->list);
+		kfree(dest_n);
+	}
+	mutex_unlock(&fr->mutex);
+	return err;
+}
+
+static int mlx5_flow_rule_del_dest(struct mlx5_flow_rule *fr,
+				   struct mlx5_flow_destination *dest)
+{
+	struct dest_node *dest_n;
+	struct dest_node *n;
+	int err;
+
+	mutex_lock(&fr->mutex);
+	list_for_each_entry_safe(dest_n, n, &fr->dest_list, list) {
+		if (dest->vport_num == dest_n->dest.vport_num)
+			goto found;
+	}
+	mutex_unlock(&fr->mutex);
+	return -ENOENT;
+
+found:
+	list_del(&dest_n->list);
+	err = _mlx5_flow_rule_apply(fr);
+	mutex_unlock(&fr->mutex);
+	kfree(dest_n);
+
+	return err;
+}
+
+static struct mlx5_flow_rule *find_fr(struct mlx5_eswitch *esw,
+				      u8 match_criteria_enable,
+				      u32 *match_value)
+{
+	struct hlist_head *hash = esw->mc_table;
+	struct esw_mc_addr *esw_mc;
+	u8 *dmac_v;
+
+	dmac_v = MLX5_ADDR_OF(fte_match_param, match_value,
+			      outer_headers.dmac_47_16);
+
+	/* UNICAST FULL MATCH */
+	if (!is_multicast_ether_addr(dmac_v))
+		return NULL;
+
+	/* MULTICAST FULL MATCH */
+	esw_mc = l2addr_hash_find(hash, dmac_v, struct esw_mc_addr);
+
+	return esw_mc ? esw_mc->uplink_rule : NULL;
+}
+
+static struct mlx5_flow_rule *alloc_fr(void *ft,
+				       u8 match_criteria_enable,
+				       u32 *match_criteria,
+				       u32 *match_value,
+				       u32 action,
+				       u32 flow_tag)
+{
+	struct mlx5_flow_rule *fr = kzalloc(sizeof(*fr), GFP_KERNEL);
+
+	if (!fr)
+		return NULL;
+
+	fr->match_criteria = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
+	fr->match_value = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
+	if (!fr->match_criteria || !fr->match_value) {
+		kfree(fr->match_criteria);
+		kfree(fr->match_value);
+		kfree(fr);
+		return NULL;
+	}
+
+	memcpy(fr->match_criteria, match_criteria, MLX5_ST_SZ_BYTES(fte_match_param));
+	memcpy(fr->match_value, match_value, MLX5_ST_SZ_BYTES(fte_match_param));
+	fr->match_criteria_enable = match_criteria_enable;
+	fr->flow_tag = flow_tag;
+	fr->action = action;
+
+	mutex_init(&fr->mutex);
+	INIT_LIST_HEAD(&fr->dest_list);
+	atomic_set(&fr->refcount, 0);
+	fr->ft = ft;
+	return fr;
+}
+
+static void deref_fr(struct mlx5_flow_rule *fr)
+{
+	if (!atomic_dec_and_test(&fr->refcount))
+		return;
+
+	kfree(fr->match_criteria);
+	kfree(fr->match_value);
+	kfree(fr);
+}
+
+static struct mlx5_flow_rule *
+mlx5_add_flow_rule(struct mlx5_eswitch *esw,
+		   u8 match_criteria_enable,
+		   u32 *match_criteria,
+		   u32 *match_value,
+		   u32 action,
+		   u32 flow_tag,
+		   struct mlx5_flow_destination *dest)
+{
+	struct mlx5_flow_rule *fr;
+	int err;
+
+	fr = find_fr(esw, match_criteria_enable, match_value);
+	fr = fr ? fr : alloc_fr(esw->fdb_table.fdb, match_criteria_enable, match_criteria,
+				match_value, action, flow_tag);
+	if (!fr)
+		return NULL;
+
+	atomic_inc(&fr->refcount);
+
+	err = mlx5_flow_rule_add_dest(fr, dest);
+	if (err) {
+		deref_fr(fr);
+		return NULL;
+	}
+
+	return fr;
+}
+
+static void mlx5_del_flow_rule(struct mlx5_flow_rule *fr, u32 vport)
+{
+	struct mlx5_flow_destination dest;
+
+	dest.vport_num = vport;
+	mlx5_flow_rule_del_dest(fr, &dest);
+	deref_fr(fr);
+}
+
+/* E-Switch FDB */
+static struct mlx5_flow_rule *
+esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u8 mac[ETH_ALEN], u32 vport)
+{
+	int match_header = MLX5_MATCH_OUTER_HEADERS;
+	struct mlx5_flow_destination dest;
+	struct mlx5_flow_rule *flow_rule = NULL;
+	u32 *match_v;
+	u32 *match_c;
+	u8 *dmac_v;
+	u8 *dmac_c;
+
+	match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
+	match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
+	if (!match_v || !match_c) {
+		pr_warn("FDB: Failed to alloc match parameters\n");
+		goto out;
+	}
+	dmac_v = MLX5_ADDR_OF(fte_match_param, match_v,
+			      outer_headers.dmac_47_16);
+	dmac_c = MLX5_ADDR_OF(fte_match_param, match_c,
+			      outer_headers.dmac_47_16);
+
+	ether_addr_copy(dmac_v, mac);
+	/* Match criteria mask */
+	memset(dmac_c, 0xff, 6);
+
+	dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
+	dest.vport_num = vport;
+
+	esw_debug(esw->dev,
+		  "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",
+		  dmac_v, dmac_c, vport);
+	flow_rule =
+		mlx5_add_flow_rule(esw,
+				   match_header,
+				   match_c,
+				   match_v,
+				   MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
+				   0, &dest);
+	if (IS_ERR_OR_NULL(flow_rule)) {
+		pr_warn(
+			"FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n",
+			 dmac_v, dmac_c, vport, PTR_ERR(flow_rule));
+		flow_rule = NULL;
+	}
+out:
+	kfree(match_v);
+	kfree(match_c);
+	return flow_rule;
+}
+
+static int esw_create_fdb_table(struct mlx5_eswitch *esw, int nvports)
+{
+	struct mlx5_core_dev *dev = esw->dev;
+	struct mlx5_flow_table_group g;
+	struct mlx5_flow_table *fdb;
+	u8 *dmac;
+
+	esw_debug(dev, "Create FDB log_max_size(%d)\n",
+		  MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
+
+	memset(&g, 0, sizeof(g));
+	/* UC MC Full match rules*/
+	g.log_sz = MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size);
+	g.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+	dmac = MLX5_ADDR_OF(fte_match_param, g.match_criteria,
+			    outer_headers.dmac_47_16);
+	/* Match criteria mask */
+	memset(dmac, 0xff, 6);
+
+	fdb = mlx5_create_flow_table(dev, 0,
+				     MLX5_FLOW_TABLE_TYPE_ESWITCH,
+				     1, &g);
+	if (fdb)
+		esw_debug(dev, "ESW: FDB Table created fdb->id %d\n", mlx5_get_flow_table_id(fdb));
+	else
+		esw_warn(dev, "ESW: Failed to create FDB Table\n");
+
+	esw->fdb_table.fdb = fdb;
+	return fdb ? 0 : -ENOMEM;
+}
+
+static void esw_destroy_fdb_table(struct mlx5_eswitch *esw)
+{
+	if (!esw->fdb_table.fdb)
+		return;
+
+	esw_debug(esw->dev, "Destroy FDB Table fdb(%d)\n",
+		  mlx5_get_flow_table_id(esw->fdb_table.fdb));
+	mlx5_destroy_flow_table(esw->fdb_table.fdb);
+	esw->fdb_table.fdb = NULL;
+}
+
+/* E-Switch vport UC/MC lists management */
+typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,
+				 struct vport_addr *vaddr);
+
+static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
+{
+	struct hlist_head *hash = esw->l2_table.l2_hash;
+	struct esw_uc_addr *esw_uc;
+	u8 *mac = vaddr->node.addr;
+	u32 vport = vaddr->vport;
+	int err;
+
+	esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr);
+	if (esw_uc) {
+		esw_warn(esw->dev,
+			 "Failed to set L2 mac(%pM) for vport(%d), mac is already in use by vport(%d)\n",
+			 mac, vport, esw_uc->vport);
+		return -EEXIST;
+	}
+
+	esw_uc = l2addr_hash_add(hash, mac, struct esw_uc_addr, GFP_KERNEL);
+	if (!esw_uc)
+		return -ENOMEM;
+	esw_uc->vport = vport;
+
+	err = set_l2_table_entry(esw->dev, mac, 0, 0, &esw_uc->table_index);
+	if (err)
+		goto abort;
+
+	if (esw->fdb_table.fdb) /* SRIOV is enabled: Forward UC MAC to vport */
+		vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
+
+	esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM index:%d fr(%p)\n",
+		  vport, mac, esw_uc->table_index, vaddr->flow_rule);
+	return err;
+abort:
+	l2addr_hash_del(esw_uc);
+	return err;
+}
+
+static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
+{
+	struct hlist_head *hash = esw->l2_table.l2_hash;
+	struct esw_uc_addr *esw_uc;
+	u8 *mac = vaddr->node.addr;
+	u32 vport = vaddr->vport;
+
+	esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr);
+	if (!esw_uc || esw_uc->vport != vport) {
+		esw_debug(esw->dev,
+			  "MAC(%pM) doesn't belong to vport (%d)\n",
+			  mac, vport);
+		return -EINVAL;
+	}
+	esw_debug(esw->dev, "\tDELETE UC MAC: vport[%d] %pM index:%d fr(%p)\n",
+		  vport, mac, esw_uc->table_index, vaddr->flow_rule);
+
+	del_l2_table_entry(esw->dev, esw_uc->table_index);
+
+	if (vaddr->flow_rule)
+		mlx5_del_flow_rule(vaddr->flow_rule, vport);
+	vaddr->flow_rule = NULL;
+
+	l2addr_hash_del(esw_uc);
+	return 0;
+}
+
+static int esw_add_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
+{
+	struct hlist_head *hash = esw->mc_table;
+	struct esw_mc_addr *esw_mc;
+	u8 *mac = vaddr->node.addr;
+	u32 vport = vaddr->vport;
+
+	if (!esw->fdb_table.fdb)
+		return 0;
+
+	esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
+	if (esw_mc)
+		goto add;
+
+	esw_mc = l2addr_hash_add(hash, mac, struct esw_mc_addr, GFP_KERNEL);
+	if (!esw_mc)
+		return -ENOMEM;
+
+	esw_mc->uplink_rule = /* Forward MC MAC to Uplink */
+		esw_fdb_set_vport_rule(esw, mac, UPLINK_VPORT);
+add:
+	esw_mc->refcnt++;
+	/* Forward MC MAC to vport */
+	vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
+	esw_debug(esw->dev,
+		  "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
+		  vport, mac, vaddr->flow_rule,
+		  esw_mc->refcnt, esw_mc->uplink_rule);
+	return 0;
+}
+
+static int esw_del_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
+{
+	struct hlist_head *hash = esw->mc_table;
+	struct esw_mc_addr *esw_mc;
+	u8 *mac = vaddr->node.addr;
+	u32 vport = vaddr->vport;
+
+	if (!esw->fdb_table.fdb)
+		return 0;
+
+	esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
+	if (!esw_mc) {
+		esw_warn(esw->dev,
+			 "Failed to find eswitch MC addr for MAC(%pM) vport(%d)",
+			 mac, vport);
+		return -EINVAL;
+	}
+	esw_debug(esw->dev,
+		  "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
+		  vport, mac, vaddr->flow_rule, esw_mc->refcnt,
+		  esw_mc->uplink_rule);
+
+	if (vaddr->flow_rule)
+		mlx5_del_flow_rule(vaddr->flow_rule, vport);
+	vaddr->flow_rule = NULL;
+
+	if (--esw_mc->refcnt)
+		return 0;
+
+	if (esw_mc->uplink_rule)
+		mlx5_del_flow_rule(esw_mc->uplink_rule, UPLINK_VPORT);
+
+	l2addr_hash_del(esw_mc);
+	return 0;
+}
+
+/* Apply vport UC/MC list to HW l2 table and FDB table */
+static void esw_apply_vport_addr_list(struct mlx5_eswitch *esw,
+				      u32 vport_num, int list_type)
+{
+	struct mlx5_vport *vport = &esw->vports[vport_num];
+	bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
+	vport_addr_action vport_addr_add;
+	vport_addr_action vport_addr_del;
+	struct vport_addr *addr;
+	struct l2addr_node *node;
+	struct hlist_head *hash;
+	struct hlist_node *tmp;
+	int hi;
+
+	vport_addr_add = is_uc ? esw_add_uc_addr :
+				 esw_add_mc_addr;
+	vport_addr_del = is_uc ? esw_del_uc_addr :
+				 esw_del_mc_addr;
+
+	hash = is_uc ? vport->uc_list : vport->mc_list;
+	for_each_l2hash_node(node, tmp, hash, hi) {
+		addr = container_of(node, struct vport_addr, node);
+		switch (addr->action) {
+		case MLX5_ACTION_ADD:
+			vport_addr_add(esw, addr);
+			addr->action = MLX5_ACTION_NONE;
+			break;
+		case MLX5_ACTION_DEL:
+			vport_addr_del(esw, addr);
+			l2addr_hash_del(addr);
+			break;
+		}
+	}
+}
+
+/* Sync vport UC/MC list from vport context */
+static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
+				       u32 vport_num, int list_type)
+{
+	struct mlx5_vport *vport = &esw->vports[vport_num];
+	bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
+	u8 (*mac_list)[ETH_ALEN];
+	struct l2addr_node *node;
+	struct vport_addr *addr;
+	struct hlist_head *hash;
+	struct hlist_node *tmp;
+	int size;
+	int err;
+	int hi;
+	int i;
+
+	size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :
+		       MLX5_MAX_MC_PER_VPORT(esw->dev);
+
+	mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
+	if (!mac_list)
+		return;
+
+	hash = is_uc ? vport->uc_list : vport->mc_list;
+
+	for_each_l2hash_node(node, tmp, hash, hi) {
+		addr = container_of(node, struct vport_addr, node);
+		addr->action = MLX5_ACTION_DEL;
+	}
+
+	err = mlx5_query_nic_vport_mac_list(esw->dev, vport_num, list_type,
+					    mac_list, &size);
+	if (err)
+		return;
+	esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
+		  vport_num, is_uc ? "UC" : "MC", size);
+
+	for (i = 0; i < size; i++) {
+		if (is_uc && !is_valid_ether_addr(mac_list[i]))
+			continue;
+
+		if (!is_uc && !is_multicast_ether_addr(mac_list[i]))
+			continue;
+
+		addr = l2addr_hash_find(hash, mac_list[i], struct vport_addr);
+		if (addr) {
+			addr->action = MLX5_ACTION_NONE;
+			continue;
+		}
+
+		addr = l2addr_hash_add(hash, mac_list[i], struct vport_addr,
+				       GFP_KERNEL);
+		if (!addr) {
+			esw_warn(esw->dev,
+				 "Failed to add MAC(%pM) to vport[%d] DB\n",
+				 mac_list[i], vport_num);
+			continue;
+		}
+		addr->vport = vport_num;
+		addr->action = MLX5_ACTION_ADD;
+	}
+	kfree(mac_list);
+}
+
+static void esw_vport_change_handler(struct work_struct *work)
+{
+	struct mlx5_vport *vport =
+		container_of(work, struct mlx5_vport, vport_change_handler);
+	struct mlx5_core_dev *dev = vport->dev;
+	struct mlx5_eswitch *esw = dev->priv.eswitch;
+	u8 mac[ETH_ALEN];
+
+	mlx5_query_nic_vport_mac_address(dev, vport->vport, mac);
+	esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",
+		  vport->vport, mac);
+
+	if (vport->enabled_events & UC_ADDR_CHANGE) {
+		esw_update_vport_addr_list(esw, vport->vport,
+					   MLX5_NVPRT_LIST_TYPE_UC);
+		esw_apply_vport_addr_list(esw, vport->vport,
+					  MLX5_NVPRT_LIST_TYPE_UC);
+	}
+
+	if (vport->enabled_events & MC_ADDR_CHANGE) {
+		esw_update_vport_addr_list(esw, vport->vport,
+					   MLX5_NVPRT_LIST_TYPE_MC);
+		esw_apply_vport_addr_list(esw, vport->vport,
+					  MLX5_NVPRT_LIST_TYPE_MC);
+	}
+
+	esw_debug(esw->dev, "vport[%d] Context Changed: Done\n", vport->vport);
+	if (vport->enabled)
+		arm_vport_context_events_cmd(dev, vport->vport,
+					     vport->enabled_events);
+}
+
+static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
+			     int enable_events)
+{
+	struct mlx5_vport *vport = &esw->vports[vport_num];
+	unsigned long flags;
+
+	WARN_ON(vport->enabled);
+
+	esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
+	mlx5_modify_vport_admin_state(esw->dev,
+				      MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
+				      vport_num,
+				      MLX5_ESW_VPORT_ADMIN_STATE_AUTO);
+
+	/* Sync with current vport context */
+	vport->enabled_events = enable_events;
+	esw_vport_change_handler(&vport->vport_change_handler);
+
+	spin_lock_irqsave(&vport->lock, flags);
+	vport->enabled = true;
+	spin_unlock_irqrestore(&vport->lock, flags);
+
+	arm_vport_context_events_cmd(esw->dev, vport_num, enable_events);
+
+	esw->enabled_vports++;
+	esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num);
+}
+
+static void esw_cleanup_vport(struct mlx5_eswitch *esw, u16 vport_num)
+{
+	struct mlx5_vport *vport = &esw->vports[vport_num];
+	struct l2addr_node *node;
+	struct vport_addr *addr;
+	struct hlist_node *tmp;
+	int hi;
+
+	for_each_l2hash_node(node, tmp, vport->uc_list, hi) {
+		addr = container_of(node, struct vport_addr, node);
+		addr->action = MLX5_ACTION_DEL;
+	}
+	esw_apply_vport_addr_list(esw, vport_num, MLX5_NVPRT_LIST_TYPE_UC);
+
+	for_each_l2hash_node(node, tmp, vport->mc_list, hi) {
+		addr = container_of(node, struct vport_addr, node);
+		addr->action = MLX5_ACTION_DEL;
+	}
+	esw_apply_vport_addr_list(esw, vport_num, MLX5_NVPRT_LIST_TYPE_MC);
+}
+
+static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
+{
+	struct mlx5_vport *vport = &esw->vports[vport_num];
+	unsigned long flags;
+
+	if (!vport->enabled)
+		return;
+
+	esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num);
+	/* Mark this vport as disabled to discard new events */
+	spin_lock_irqsave(&vport->lock, flags);
+	vport->enabled = false;
+	vport->enabled_events = 0;
+	spin_unlock_irqrestore(&vport->lock, flags);
+
+	mlx5_modify_vport_admin_state(esw->dev,
+				      MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
+				      vport_num,
+				      MLX5_ESW_VPORT_ADMIN_STATE_DOWN);
+	/* Wait for current already scheduled events to complete */
+	flush_workqueue(esw->work_queue);
+	/* Disable events from this vport */
+	arm_vport_context_events_cmd(esw->dev, vport->vport, 0);
+	/* We don't assume VFs will cleanup after themselves */
+	esw_cleanup_vport(esw, vport_num);
+	esw->enabled_vports--;
+}
+
+/* Public E-Switch API */
+int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs)
+{
+	int err;
+	int i;
+
+	if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
+	    MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
+		return 0;
+
+	if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) ||
+	    !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
+		esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n");
+		return -ENOTSUPP;
+	}
+
+	esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d)\n", nvfs);
+
+	esw_disable_vport(esw, 0);
+
+	err = esw_create_fdb_table(esw, nvfs + 1);
+	if (err)
+		goto abort;
+
+	for (i = 0; i <= nvfs; i++)
+		esw_enable_vport(esw, i, SRIOV_VPORT_EVENTS);
+
+	esw_info(esw->dev, "SRIOV enabled: active vports(%d)\n",
+		 esw->enabled_vports);
+	return 0;
+
+abort:
+	esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
+	return err;
+}
+
+void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
+{
+	int i;
+
+	if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
+	    MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
+		return;
+
+	esw_info(esw->dev, "disable SRIOV: active vports(%d)\n",
+		 esw->enabled_vports);
+
+	for (i = 0; i < esw->total_vports; i++)
+		esw_disable_vport(esw, i);
+
+	esw_destroy_fdb_table(esw);
+
+	/* VPORT 0 (PF) must be enabled back with non-sriov configuration */
+	esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
+}
+
+int mlx5_eswitch_init(struct mlx5_core_dev *dev)
+{
+	int l2_table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table);
+	int total_vports = 1 + pci_sriov_get_totalvfs(dev->pdev);
+	struct mlx5_eswitch *esw;
+	int vport_num;
+	int err;
+
+	if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
+	    MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
+		return 0;
+
+	esw_info(dev,
+		 "Total vports %d, l2 table size(%d), per vport: max uc(%d) max mc(%d)\n",
+		 total_vports, l2_table_size,
+		 MLX5_MAX_UC_PER_VPORT(dev),
+		 MLX5_MAX_MC_PER_VPORT(dev));
+
+	esw = kzalloc(sizeof(*esw), GFP_KERNEL);
+	if (!esw)
+		return -ENOMEM;
+
+	esw->dev = dev;
+
+	esw->l2_table.bitmap = kcalloc(BITS_TO_LONGS(l2_table_size),
+				   sizeof(uintptr_t), GFP_KERNEL);
+	if (!esw->l2_table.bitmap) {
+		err = -ENOMEM;
+		goto abort;
+	}
+	esw->l2_table.size = l2_table_size;
+
+	esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
+	if (!esw->work_queue) {
+		err = -ENOMEM;
+		goto abort;
+	}
+
+	esw->vports = kcalloc(total_vports, sizeof(struct mlx5_vport),
+			      GFP_KERNEL);
+	if (!esw->vports) {
+		err = -ENOMEM;
+		goto abort;
+	}
+
+	for (vport_num = 0; vport_num < total_vports; vport_num++) {
+		struct mlx5_vport *vport = &esw->vports[vport_num];
+
+		vport->vport = vport_num;
+		vport->dev = dev;
+		INIT_WORK(&vport->vport_change_handler,
+			  esw_vport_change_handler);
+		spin_lock_init(&vport->lock);
+	}
+
+	esw->total_vports = total_vports;
+	esw->enabled_vports = 0;
+
+	dev->priv.eswitch = esw;
+	esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
+	/* VF Vports will be enabled when SRIOV is enabled */
+	return 0;
+abort:
+	if (esw->work_queue)
+		destroy_workqueue(esw->work_queue);
+	kfree(esw->l2_table.bitmap);
+	kfree(esw->vports);
+	kfree(esw);
+	return err;
+}
+
+void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
+{
+	if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
+	    MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
+		return;
+
+	esw_info(esw->dev, "cleanup\n");
+	esw_disable_vport(esw, 0);
+
+	esw->dev->priv.eswitch = NULL;
+	destroy_workqueue(esw->work_queue);
+	kfree(esw->l2_table.bitmap);
+	kfree(esw->vports);
+	kfree(esw);
+}
+
+void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe)
+{
+	struct mlx5_eqe_vport_change *vc_eqe = &eqe->data.vport_change;
+	u16 vport_num = be16_to_cpu(vc_eqe->vport_num);
+	struct mlx5_vport *vport;
+
+	if (!esw) {
+		pr_warn("MLX5 E-Switch: vport %d got an event while eswitch is not initialized\n",
+			vport_num);
+		return;
+	}
+
+	vport = &esw->vports[vport_num];
+	spin_lock(&vport->lock);
+	if (vport->enabled)
+		queue_work(esw->work_queue, &vport->vport_change_handler);
+	spin_unlock(&vport->lock);
+}
+
+/* Vport Administration */
+#define ESW_ALLOWED(esw) \
+	(esw && MLX5_CAP_GEN(esw->dev, vport_group_manager) && mlx5_core_is_pf(esw->dev))
+#define LEGAL_VPORT(esw, vport) (vport >= 0 && vport < esw->total_vports)
+
+int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
+			       int vport, u8 mac[ETH_ALEN])
+{
+	int err = 0;
+
+	if (!ESW_ALLOWED(esw))
+		return -EPERM;
+	if (!LEGAL_VPORT(esw, vport))
+		return -EINVAL;
+
+	err = mlx5_modify_nic_vport_mac_address(esw->dev, vport, mac);
+	if (err) {
+		mlx5_core_warn(esw->dev,
+			       "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n",
+			       vport, err);
+		return err;
+	}
+
+	return err;
+}
+
+int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
+				 int vport, int link_state)
+{
+	if (!ESW_ALLOWED(esw))
+		return -EPERM;
+	if (!LEGAL_VPORT(esw, vport))
+		return -EINVAL;
+
+	return mlx5_modify_vport_admin_state(esw->dev,
+					     MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
+					     vport, link_state);
+}
+
+int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
+				  int vport, struct ifla_vf_info *ivi)
+{
+	u16 vlan;
+	u8 qos;
+
+	if (!ESW_ALLOWED(esw))
+		return -EPERM;
+	if (!LEGAL_VPORT(esw, vport))
+		return -EINVAL;
+
+	memset(ivi, 0, sizeof(*ivi));
+	ivi->vf = vport - 1;
+
+	mlx5_query_nic_vport_mac_address(esw->dev, vport, ivi->mac);
+	ivi->linkstate = mlx5_query_vport_admin_state(esw->dev,
+						      MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
+						      vport);
+	query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos);
+	ivi->vlan = vlan;
+	ivi->qos = qos;
+	ivi->spoofchk = 0;
+
+	return 0;
+}
+
+int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
+				int vport, u16 vlan, u8 qos)
+{
+	int set = 0;
+
+	if (!ESW_ALLOWED(esw))
+		return -EPERM;
+	if (!LEGAL_VPORT(esw, vport) || (vlan > 4095) || (qos > 7))
+		return -EINVAL;
+
+	if (vlan || qos)
+		set = 1;
+
+	return modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set);
+}
+
+int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
+				 int vport,
+				 struct ifla_vf_stats *vf_stats)
+{
+	int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
+	u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)];
+	int err = 0;
+	u32 *out;
+
+	if (!ESW_ALLOWED(esw))
+		return -EPERM;
+	if (!LEGAL_VPORT(esw, vport))
+		return -EINVAL;
+
+	out = mlx5_vzalloc(outlen);
+	if (!out)
+		return -ENOMEM;
+
+	memset(in, 0, sizeof(in));
+
+	MLX5_SET(query_vport_counter_in, in, opcode,
+		 MLX5_CMD_OP_QUERY_VPORT_COUNTER);
+	MLX5_SET(query_vport_counter_in, in, op_mod, 0);
+	MLX5_SET(query_vport_counter_in, in, vport_number, vport);
+	if (vport)
+		MLX5_SET(query_vport_counter_in, in, other_vport, 1);
+
+	memset(out, 0, outlen);
+	err = mlx5_cmd_exec(esw->dev, in, sizeof(in), out, outlen);
+	if (err)
+		goto free_out;
+
+	#define MLX5_GET_CTR(p, x) \
+		MLX5_GET64(query_vport_counter_out, p, x)
+
+	memset(vf_stats, 0, sizeof(*vf_stats));
+	vf_stats->rx_packets =
+		MLX5_GET_CTR(out, received_eth_unicast.packets) +
+		MLX5_GET_CTR(out, received_eth_multicast.packets) +
+		MLX5_GET_CTR(out, received_eth_broadcast.packets);
+
+	vf_stats->rx_bytes =
+		MLX5_GET_CTR(out, received_eth_unicast.octets) +
+		MLX5_GET_CTR(out, received_eth_multicast.octets) +
+		MLX5_GET_CTR(out, received_eth_broadcast.octets);
+
+	vf_stats->tx_packets =
+		MLX5_GET_CTR(out, transmitted_eth_unicast.packets) +
+		MLX5_GET_CTR(out, transmitted_eth_multicast.packets) +
+		MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);
+
+	vf_stats->tx_bytes =
+		MLX5_GET_CTR(out, transmitted_eth_unicast.octets) +
+		MLX5_GET_CTR(out, transmitted_eth_multicast.octets) +
+		MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
+
+	vf_stats->multicast =
+		MLX5_GET_CTR(out, received_eth_multicast.packets);
+
+	vf_stats->broadcast =
+		MLX5_GET_CTR(out, received_eth_broadcast.packets);
+
+free_out:
+	kvfree(out);
+	return err;
+}
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_ESWITCH_H__
+#define __MLX5_ESWITCH_H__
+
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/mlx5/device.h>
+
+#define MLX5_MAX_UC_PER_VPORT(dev) \
+	(1 << MLX5_CAP_GEN(dev, log_max_current_uc_list))
+
+#define MLX5_MAX_MC_PER_VPORT(dev) \
+	(1 << MLX5_CAP_GEN(dev, log_max_current_mc_list))
+
+#define MLX5_L2_ADDR_HASH_SIZE (BIT(BITS_PER_BYTE))
+#define MLX5_L2_ADDR_HASH(addr) (addr[5])
+
+/* L2 -mac address based- hash helpers */
+struct l2addr_node {
+	struct hlist_node hlist;
+	u8                addr[ETH_ALEN];
+};
+
+#define for_each_l2hash_node(hn, tmp, hash, i) \
+	for (i = 0; i < MLX5_L2_ADDR_HASH_SIZE; i++) \
+		hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist)
+
+#define l2addr_hash_find(hash, mac, type) ({                \
+	int ix = MLX5_L2_ADDR_HASH(mac);                    \
+	bool found = false;                                 \
+	type *ptr = NULL;                                   \
+							    \
+	hlist_for_each_entry(ptr, &hash[ix], node.hlist)    \
+		if (ether_addr_equal(ptr->node.addr, mac)) {\
+			found = true;                       \
+			break;                              \
+		}                                           \
+	if (!found)                                         \
+		ptr = NULL;                                 \
+	ptr;                                                \
+})
+
+#define l2addr_hash_add(hash, mac, type, gfp) ({            \
+	int ix = MLX5_L2_ADDR_HASH(mac);                    \
+	type *ptr = NULL;                                   \
+							    \
+	ptr = kzalloc(sizeof(type), gfp);                   \
+	if (ptr) {                                          \
+		ether_addr_copy(ptr->node.addr, mac);       \
+		hlist_add_head(&ptr->node.hlist, &hash[ix]);\
+	}                                                   \
+	ptr;                                                \
+})
+
+#define l2addr_hash_del(ptr) ({                             \
+	hlist_del(&ptr->node.hlist);                        \
+	kfree(ptr);                                         \
+})
+
+struct mlx5_flow_rule {
+	void             *ft;
+	u32              fi;
+	u8               match_criteria_enable;
+	u32              *match_criteria;
+	u32              *match_value;
+	u32              action;
+	u32              flow_tag;
+	bool             valid;
+	atomic_t         refcount;
+	struct mutex     mutex; /* protect flow rule updates */
+	struct list_head dest_list;
+};
+
+struct mlx5_vport {
+	struct mlx5_core_dev    *dev;
+	int                     vport;
+	struct hlist_head       uc_list[MLX5_L2_ADDR_HASH_SIZE];
+	struct hlist_head       mc_list[MLX5_L2_ADDR_HASH_SIZE];
+	struct work_struct      vport_change_handler;
+
+	/* This spinlock protects access to vport data, between
+	 * "esw_vport_disable" and ongoing interrupt "mlx5_eswitch_vport_event"
+	 * once vport marked as disabled new interrupts are discarded.
+	 */
+	spinlock_t              lock; /* vport events sync */
+	bool                    enabled;
+	u16                     enabled_events;
+};
+
+struct mlx5_l2_table {
+	struct hlist_head l2_hash[MLX5_L2_ADDR_HASH_SIZE];
+	u32                  size;
+	unsigned long        *bitmap;
+};
+
+struct mlx5_eswitch_fdb {
+	void *fdb;
+};
+
+struct mlx5_eswitch {
+	struct mlx5_core_dev    *dev;
+	struct mlx5_l2_table    l2_table;
+	struct mlx5_eswitch_fdb fdb_table;
+	struct hlist_head       mc_table[MLX5_L2_ADDR_HASH_SIZE];
+	struct workqueue_struct *work_queue;
+	struct mlx5_vport       *vports;
+	int                     total_vports;
+	int                     enabled_vports;
+};
+
+/* E-Switch API */
+int mlx5_eswitch_init(struct mlx5_core_dev *dev);
+void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw);
+void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe);
+int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs);
+void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw);
+int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
+			       int vport, u8 mac[ETH_ALEN]);
+int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
+				 int vport, int link_state);
+int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
+				int vport, u16 vlan, u8 qos);
+int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
+				  int vport, struct ifla_vf_info *ivi);
+int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
+				 int vport,
+				 struct ifla_vf_stats *vf_stats);
+
+#endif /* __MLX5_ESWITCH_H__ */
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -160,6 +160,30 @@
 		if (err)
 			return err;
 	}
+
+	if (MLX5_CAP_GEN(dev, vport_group_manager) &&
+	    MLX5_CAP_GEN(dev, eswitch_flow_table)) {
+		err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE,
+					 HCA_CAP_OPMOD_GET_CUR);
+		if (err)
+			return err;
+		err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE,
+					 HCA_CAP_OPMOD_GET_MAX);
+		if (err)
+			return err;
+	}
+
+	if (MLX5_CAP_GEN(dev, eswitch_flow_table)) {
+		err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH,
+					 HCA_CAP_OPMOD_GET_CUR);
+		if (err)
+			return err;
+		err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH,
+					 HCA_CAP_OPMOD_GET_MAX);
+		if (err)
+			return err;
+	}
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -108,15 +108,21 @@
 
 void mlx5_enter_error_state(struct mlx5_core_dev *dev)
 {
+	mutex_lock(&dev->intf_state_mutex);
 	if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
-		return;
+		goto unlock;
 
 	mlx5_core_err(dev, "start\n");
-	if (pci_channel_offline(dev->pdev) || in_fatal(dev))
+	if (pci_channel_offline(dev->pdev) || in_fatal(dev)) {
 		dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
+		trigger_cmd_completions(dev);
+	}
 
 	mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 0);
 	mlx5_core_err(dev, "end\n");
+
+unlock:
+	mutex_unlock(&dev->intf_state_mutex);
 }
 
 static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
@@ -245,7 +251,6 @@
 	u32 count;
 
 	if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
-		trigger_cmd_completions(dev);
 		mod_timer(&health->timer, get_next_poll_jiffies());
 		return;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -49,6 +49,9 @@
 #include <linux/delay.h>
 #include <linux/mlx5/mlx5_ifc.h>
 #include "mlx5_core.h"
+#ifdef CONFIG_MLX5_CORE_EN
+#include "eswitch.h"
+#endif
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver");
@@ -85,7 +88,7 @@
 	[2] = {
 		.mask		= MLX5_PROF_MASK_QP_SIZE |
 				  MLX5_PROF_MASK_MR_CACHE,
-		.log_max_qp	= 17,
+		.log_max_qp	= 18,
 		.mr_cache[0]	= {
 			.size	= 500,
 			.limit	= 250
@@ -153,8 +156,9 @@
 	},
 };
 
-#define FW_INIT_TIMEOUT_MILI	2000
-#define FW_INIT_WAIT_MS		2
+#define FW_INIT_TIMEOUT_MILI		2000
+#define FW_INIT_WAIT_MS			2
+#define FW_PRE_INIT_TIMEOUT_MILI	10000
 
 static int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili)
 {
@@ -432,6 +436,13 @@
 	MLX5_SET(cmd_hca_cap, set_hca_cap, pkey_table_size,
 		 to_fw_pkey_sz(128));
 
+	/* Check log_max_qp from HCA caps to set in current profile */
+	if (MLX5_CAP_GEN_MAX(dev, log_max_qp) < profile[prof_sel].log_max_qp) {
+		mlx5_core_warn(dev, "log_max_qp value in current profile is %d, changing it to HCA capability limit (%d)\n",
+			       profile[prof_sel].log_max_qp,
+			       MLX5_CAP_GEN_MAX(dev, log_max_qp));
+		profile[prof_sel].log_max_qp = MLX5_CAP_GEN_MAX(dev, log_max_qp);
+	}
 	if (prof->mask & MLX5_PROF_MASK_QP_SIZE)
 		MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_qp,
 			 prof->log_max_qp);
@@ -454,6 +465,9 @@
 	struct mlx5_reg_host_endianess he_out;
 	int err;
 
+	if (!mlx5_core_is_pf(dev))
+		return 0;
+
 	memset(&he_in, 0, sizeof(he_in));
 	he_in.he = MLX5_SET_HOST_ENDIANNESS;
 	err = mlx5_core_access_reg(dev, &he_in,  sizeof(he_in),
@@ -462,42 +476,39 @@
 	return err;
 }
 
-static int mlx5_core_enable_hca(struct mlx5_core_dev *dev)
+int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id)
 {
+	u32 out[MLX5_ST_SZ_DW(enable_hca_out)];
+	u32 in[MLX5_ST_SZ_DW(enable_hca_in)];
 	int err;
-	struct mlx5_enable_hca_mbox_in in;
-	struct mlx5_enable_hca_mbox_out out;
 
-	memset(&in, 0, sizeof(in));
-	memset(&out, 0, sizeof(out));
-	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ENABLE_HCA);
+	memset(in, 0, sizeof(in));
+	MLX5_SET(enable_hca_in, in, opcode, MLX5_CMD_OP_ENABLE_HCA);
+	MLX5_SET(enable_hca_in, in, function_id, func_id);
+	memset(out, 0, sizeof(out));
+
 	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
 	if (err)
 		return err;
 
-	if (out.hdr.status)
-		return mlx5_cmd_status_to_err(&out.hdr);
-
-	return 0;
+	return mlx5_cmd_status_to_err_v2(out);
 }
 
-static int mlx5_core_disable_hca(struct mlx5_core_dev *dev)
+int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id)
 {
+	u32 out[MLX5_ST_SZ_DW(disable_hca_out)];
+	u32 in[MLX5_ST_SZ_DW(disable_hca_in)];
 	int err;
-	struct mlx5_disable_hca_mbox_in in;
-	struct mlx5_disable_hca_mbox_out out;
 
-	memset(&in, 0, sizeof(in));
-	memset(&out, 0, sizeof(out));
-	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DISABLE_HCA);
-	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+	memset(in, 0, sizeof(in));
+	MLX5_SET(disable_hca_in, in, opcode, MLX5_CMD_OP_DISABLE_HCA);
+	MLX5_SET(disable_hca_in, in, function_id, func_id);
+	memset(out, 0, sizeof(out));
+	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 	if (err)
 		return err;
 
-	if (out.hdr.status)
-		return mlx5_cmd_status_to_err(&out.hdr);
-
-	return 0;
+	return mlx5_cmd_status_to_err_v2(out);
 }
 
 static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i)
@@ -505,29 +516,20 @@
 	struct mlx5_priv *priv  = &mdev->priv;
 	struct msix_entry *msix = priv->msix_arr;
 	int irq                 = msix[i + MLX5_EQ_VEC_COMP_BASE].vector;
-	int numa_node           = priv->numa_node;
-	int err;
 
 	if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) {
 		mlx5_core_warn(mdev, "zalloc_cpumask_var failed");
 		return -ENOMEM;
 	}
 
-	cpumask_set_cpu(cpumask_local_spread(i, numa_node),
+	cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node),
 			priv->irq_info[i].mask);
 
-	err = irq_set_affinity_hint(irq, priv->irq_info[i].mask);
-	if (err) {
-		mlx5_core_warn(mdev, "irq_set_affinity_hint failed,irq 0x%.4x",
-			       irq);
-		goto err_clear_mask;
-	}
+	if (IS_ENABLED(CONFIG_SMP) &&
+	    irq_set_affinity_hint(irq, priv->irq_info[i].mask))
+		mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x", irq);
 
 	return 0;
-
-err_clear_mask:
-	free_cpumask_var(priv->irq_info[i].mask);
-	return err;
 }
 
 static void mlx5_irq_clear_affinity_hint(struct mlx5_core_dev *mdev, int i)
@@ -568,7 +570,8 @@
 		mlx5_irq_clear_affinity_hint(mdev, i);
 }
 
-int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn)
+int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn,
+		    unsigned int *irqn)
 {
 	struct mlx5_eq_table *table = &dev->priv.eq_table;
 	struct mlx5_eq *eq, *n;
@@ -778,7 +781,7 @@
 	struct mlx5_interface *intf;
 
 	mutex_lock(&intf_mutex);
-	list_for_each_entry(intf, &intf_list, list)
+	list_for_each_entry_reverse(intf, &intf_list, list)
 		mlx5_remove_device(intf, priv);
 	list_del(&priv->dev_list);
 	mutex_unlock(&intf_mutex);
@@ -913,7 +916,7 @@
 	int err;
 
 	mutex_lock(&dev->intf_state_mutex);
-	if (dev->interface_state == MLX5_INTERFACE_STATE_UP) {
+	if (test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) {
 		dev_warn(&dev->pdev->dev, "%s: interface is up, NOP\n",
 			 __func__);
 		goto out;
@@ -927,6 +930,15 @@
 	 */
 	dev->state = MLX5_DEVICE_STATE_UP;
 
+	/* wait for firmware to accept initialization segments configurations
+	 */
+	err = wait_fw_init(dev, FW_PRE_INIT_TIMEOUT_MILI);
+	if (err) {
+		dev_err(&dev->pdev->dev, "Firmware over %d MS in pre-initializing state, aborting\n",
+			FW_PRE_INIT_TIMEOUT_MILI);
+		goto out_err;
+	}
+
 	err = mlx5_cmd_init(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Failed initializing command interface, aborting\n");
@@ -942,7 +954,7 @@
 
 	mlx5_pagealloc_init(dev);
 
-	err = mlx5_core_enable_hca(dev);
+	err = mlx5_core_enable_hca(dev, 0);
 	if (err) {
 		dev_err(&pdev->dev, "enable hca failed\n");
 		goto err_pagealloc_cleanup;
@@ -1052,6 +1064,20 @@
 	mlx5_init_srq_table(dev);
 	mlx5_init_mr_table(dev);
 
+#ifdef CONFIG_MLX5_CORE_EN
+	err = mlx5_eswitch_init(dev);
+	if (err) {
+		dev_err(&pdev->dev, "eswitch init failed %d\n", err);
+		goto err_reg_dev;
+	}
+#endif
+
+	err = mlx5_sriov_init(dev);
+	if (err) {
+		dev_err(&pdev->dev, "sriov init failed %d\n", err);
+		goto err_sriov;
+	}
+
 	err = mlx5_register_device(dev);
 	if (err) {
 		dev_err(&pdev->dev, "mlx5_register_device failed %d\n", err);
@@ -1062,12 +1088,20 @@
 	if (err)
 		pr_info("failed request module on %s\n", MLX5_IB_MOD);
 
-	dev->interface_state = MLX5_INTERFACE_STATE_UP;
+	clear_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state);
+	set_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state);
 out:
 	mutex_unlock(&dev->intf_state_mutex);
 
 	return 0;
 
+err_sriov:
+	if (mlx5_sriov_cleanup(dev))
+		dev_err(&dev->pdev->dev, "sriov cleanup failed\n");
+
+#ifdef CONFIG_MLX5_CORE_EN
+	mlx5_eswitch_cleanup(dev->priv.eswitch);
+#endif
 err_reg_dev:
 	mlx5_cleanup_mr_table(dev);
 	mlx5_cleanup_srq_table(dev);
@@ -1106,7 +1140,7 @@
 	mlx5_reclaim_startup_pages(dev);
 
 err_disable_hca:
-	mlx5_core_disable_hca(dev);
+	mlx5_core_disable_hca(dev, 0);
 
 err_pagealloc_cleanup:
 	mlx5_pagealloc_cleanup(dev);
@@ -1123,13 +1157,24 @@
 {
 	int err = 0;
 
+	err = mlx5_sriov_cleanup(dev);
+	if (err) {
+		dev_warn(&dev->pdev->dev, "%s: sriov cleanup failed - abort\n",
+			 __func__);
+		return err;
+	}
+
 	mutex_lock(&dev->intf_state_mutex);
-	if (dev->interface_state == MLX5_INTERFACE_STATE_DOWN) {
+	if (test_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state)) {
 		dev_warn(&dev->pdev->dev, "%s: interface is down, NOP\n",
 			 __func__);
 		goto out;
 	}
 	mlx5_unregister_device(dev);
+#ifdef CONFIG_MLX5_CORE_EN
+	mlx5_eswitch_cleanup(dev->priv.eswitch);
+#endif
+
 	mlx5_cleanup_mr_table(dev);
 	mlx5_cleanup_srq_table(dev);
 	mlx5_cleanup_qp_table(dev);
@@ -1149,12 +1194,13 @@
 	}
 	mlx5_pagealloc_stop(dev);
 	mlx5_reclaim_startup_pages(dev);
-	mlx5_core_disable_hca(dev);
+	mlx5_core_disable_hca(dev, 0);
 	mlx5_pagealloc_cleanup(dev);
 	mlx5_cmd_cleanup(dev);
 
 out:
-	dev->interface_state = MLX5_INTERFACE_STATE_DOWN;
+	clear_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state);
+	set_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state);
 	mutex_unlock(&dev->intf_state_mutex);
 	return err;
 }
@@ -1195,6 +1241,7 @@
 		return -ENOMEM;
 	}
 	priv = &dev->priv;
+	priv->pci_dev_data = id->driver_data;
 
 	pci_set_drvdata(pdev, dev);
 
@@ -1267,15 +1314,43 @@
 	dev_info(&pdev->dev, "%s was called\n", __func__);
 	mlx5_enter_error_state(dev);
 	mlx5_unload_one(dev, priv);
+	pci_save_state(pdev);
 	mlx5_pci_disable_device(dev);
 	return state == pci_channel_io_perm_failure ?
 		PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
 }
 
+/* wait for the device to show vital signs by waiting
+ * for the health counter to start counting.
+ */
+static int wait_vital(struct pci_dev *pdev)
+{
+	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
+	struct mlx5_core_health *health = &dev->priv.health;
+	const int niter = 100;
+	u32 last_count = 0;
+	u32 count;
+	int i;
+
+	for (i = 0; i < niter; i++) {
+		count = ioread32be(health->health_counter);
+		if (count && count != 0xffffffff) {
+			if (last_count && last_count != count) {
+				dev_info(&pdev->dev, "Counter value 0x%x after %d iterations\n", count, i);
+				return 0;
+			}
+			last_count = count;
+		}
+		msleep(50);
+	}
+
+	return -ETIMEDOUT;
+}
+
 static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev)
 {
 	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
-	int err = 0;
+	int err;
 
 	dev_info(&pdev->dev, "%s was called\n", __func__);
 
@@ -1285,11 +1360,16 @@
 			, __func__, err);
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
+
 	pci_set_master(pdev);
-	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 
-	return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
+	if (wait_vital(pdev)) {
+		dev_err(&pdev->dev, "%s: wait_vital timed out\n", __func__);
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	return PCI_ERS_RESULT_RECOVERED;
 }
 
 void mlx5_disable_device(struct mlx5_core_dev *dev)
@@ -1297,48 +1377,6 @@
 	mlx5_pci_err_detected(dev->pdev, 0);
 }
 
-/* wait for the device to show vital signs. For now we check
- * that we can read the device ID and that the health buffer
- * shows a non zero value which is different than 0xffffffff
- */
-static void wait_vital(struct pci_dev *pdev)
-{
-	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
-	struct mlx5_core_health *health = &dev->priv.health;
-	const int niter = 100;
-	u32 count;
-	u16 did;
-	int i;
-
-	/* Wait for firmware to be ready after reset */
-	msleep(1000);
-	for (i = 0; i < niter; i++) {
-		if (pci_read_config_word(pdev, 2, &did)) {
-			dev_warn(&pdev->dev, "failed reading config word\n");
-			break;
-		}
-		if (did == pdev->device) {
-			dev_info(&pdev->dev, "device ID correctly read after %d iterations\n", i);
-			break;
-		}
-		msleep(50);
-	}
-	if (i == niter)
-		dev_warn(&pdev->dev, "%s-%d: could not read device ID\n", __func__, __LINE__);
-
-	for (i = 0; i < niter; i++) {
-		count = ioread32be(health->health_counter);
-		if (count && count != 0xffffffff) {
-			dev_info(&pdev->dev, "Counter value 0x%x after %d iterations\n", count, i);
-			break;
-		}
-		msleep(50);
-	}
-
-	if (i == niter)
-		dev_warn(&pdev->dev, "%s-%d: could not read device ID\n", __func__, __LINE__);
-}
-
 static void mlx5_pci_resume(struct pci_dev *pdev)
 {
 	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
@@ -1347,9 +1385,6 @@
 
 	dev_info(&pdev->dev, "%s was called\n", __func__);
 
-	pci_save_state(pdev);
-	wait_vital(pdev);
-
 	err = mlx5_load_one(dev, priv);
 	if (err)
 		dev_err(&pdev->dev, "%s: mlx5_load_one failed with error code: %d\n"
@@ -1364,13 +1399,25 @@
 	.resume		= mlx5_pci_resume
 };
 
+static void shutdown(struct pci_dev *pdev)
+{
+	struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
+	struct mlx5_priv *priv = &dev->priv;
+
+	dev_info(&pdev->dev, "Shutdown was called\n");
+	/* Notify mlx5 clients that the kernel is being shut down */
+	set_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &dev->intf_state);
+	mlx5_unload_one(dev, priv);
+	mlx5_pci_disable_device(dev);
+}
+
 static const struct pci_device_id mlx5_core_pci_table[] = {
-	{ PCI_VDEVICE(MELLANOX, 0x1011) }, /* Connect-IB */
-	{ PCI_VDEVICE(MELLANOX, 0x1012) }, /* Connect-IB VF */
-	{ PCI_VDEVICE(MELLANOX, 0x1013) }, /* ConnectX-4 */
-	{ PCI_VDEVICE(MELLANOX, 0x1014) }, /* ConnectX-4 VF */
-	{ PCI_VDEVICE(MELLANOX, 0x1015) }, /* ConnectX-4LX */
-	{ PCI_VDEVICE(MELLANOX, 0x1016) }, /* ConnectX-4LX VF */
+	{ PCI_VDEVICE(MELLANOX, 0x1011) },			/* Connect-IB */
+	{ PCI_VDEVICE(MELLANOX, 0x1012), MLX5_PCI_DEV_IS_VF},	/* Connect-IB VF */
+	{ PCI_VDEVICE(MELLANOX, 0x1013) },			/* ConnectX-4 */
+	{ PCI_VDEVICE(MELLANOX, 0x1014), MLX5_PCI_DEV_IS_VF},	/* ConnectX-4 VF */
+	{ PCI_VDEVICE(MELLANOX, 0x1015) },			/* ConnectX-4LX */
+	{ PCI_VDEVICE(MELLANOX, 0x1016), MLX5_PCI_DEV_IS_VF},	/* ConnectX-4LX VF */
 	{ 0, }
 };
 
@@ -1381,7 +1428,9 @@
 	.id_table       = mlx5_core_pci_table,
 	.probe          = init_one,
 	.remove         = remove_one,
-	.err_handler	= &mlx5_err_handler
+	.shutdown	= shutdown,
+	.err_handler	= &mlx5_err_handler,
+	.sriov_configure   = mlx5_core_sriov_configure,
 };
 
 static int __init init(void)
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -36,6 +36,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/if_link.h>
 
 #define DRIVER_NAME "mlx5_core"
 #define DRIVER_VERSION "3.0-1"
@@ -64,6 +65,9 @@
 		(__dev)->priv.name, __func__, __LINE__, current->pid,	\
 		##__VA_ARGS__)
 
+#define mlx5_core_info(__dev, format, ...)				\
+	dev_info(&(__dev)->pdev->dev, format, ##__VA_ARGS__)
+
 enum {
 	MLX5_CMD_DATA, /* print command payload only */
 	MLX5_CMD_TIME, /* print command execution time */
@@ -90,6 +94,10 @@
 		     unsigned long param);
 void mlx5_enter_error_state(struct mlx5_core_dev *dev);
 void mlx5_disable_device(struct mlx5_core_dev *dev);
+int mlx5_core_sriov_configure(struct pci_dev *dev, int num_vfs);
+int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id);
+int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id);
+int mlx5_wait_for_vf_pages(struct mlx5_core_dev *dev);
 
 void mlx5e_init(void);
 void mlx5e_cleanup(void);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
@@ -33,6 +33,7 @@
 #include <linux/highmem.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/cmd.h>
 #include "mlx5_core.h"
@@ -95,6 +96,7 @@
 
 enum {
 	MAX_RECLAIM_TIME_MSECS	= 5000,
+	MAX_RECLAIM_VFS_PAGES_TIME_MSECS = 2 * 1000 * 60,
 };
 
 enum {
@@ -243,6 +245,7 @@
 static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id)
 {
 	struct page *page;
+	u64 zero_addr = 1;
 	u64 addr;
 	int err;
 	int nid = dev_to_node(&dev->pdev->dev);
@@ -252,26 +255,35 @@
 		mlx5_core_warn(dev, "failed to allocate page\n");
 		return -ENOMEM;
 	}
+map:
 	addr = dma_map_page(&dev->pdev->dev, page, 0,
 			    PAGE_SIZE, DMA_BIDIRECTIONAL);
 	if (dma_mapping_error(&dev->pdev->dev, addr)) {
 		mlx5_core_warn(dev, "failed dma mapping page\n");
 		err = -ENOMEM;
-		goto out_alloc;
+		goto err_mapping;
 	}
+
+	/* Firmware doesn't support page with physical address 0 */
+	if (addr == 0) {
+		zero_addr = addr;
+		goto map;
+	}
+
 	err = insert_page(dev, addr, page, func_id);
 	if (err) {
 		mlx5_core_err(dev, "failed to track allocated page\n");
-		goto out_mapping;
+		dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE,
+			       DMA_BIDIRECTIONAL);
 	}
 
-	return 0;
-
-out_mapping:
-	dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+err_mapping:
+	if (err)
+		__free_page(page);
 
-out_alloc:
-	__free_page(page);
+	if (zero_addr == 0)
+		dma_unmap_page(&dev->pdev->dev, zero_addr, PAGE_SIZE,
+			       DMA_BIDIRECTIONAL);
 
 	return err;
 }
@@ -352,6 +364,10 @@
 		goto out_4k;
 	}
 
+	dev->priv.fw_pages += npages;
+	if (func_id)
+		dev->priv.vfs_pages += npages;
+
 	mlx5_core_dbg(dev, "err %d\n", err);
 
 	kvfree(in);
@@ -405,6 +421,12 @@
 	}
 
 	num_claimed = be32_to_cpu(out->num_entries);
+	if (num_claimed > npages) {
+		mlx5_core_warn(dev, "fw returned %d, driver asked %d => corruption\n",
+			       num_claimed, npages);
+		err = -EINVAL;
+		goto out_free;
+	}
 	if (nclaimed)
 		*nclaimed = num_claimed;
 
@@ -412,6 +434,9 @@
 		addr = be64_to_cpu(out->pas[i]);
 		free_4k(dev, addr);
 	}
+	dev->priv.fw_pages -= num_claimed;
+	if (func_id)
+		dev->priv.vfs_pages -= num_claimed;
 
 out_free:
 	kvfree(out);
@@ -548,3 +573,26 @@
 {
 	destroy_workqueue(dev->priv.pg_wq);
 }
+
+int mlx5_wait_for_vf_pages(struct mlx5_core_dev *dev)
+{
+	unsigned long end = jiffies + msecs_to_jiffies(MAX_RECLAIM_VFS_PAGES_TIME_MSECS);
+	int prev_vfs_pages = dev->priv.vfs_pages;
+
+	mlx5_core_dbg(dev, "Waiting for %d pages from %s\n", prev_vfs_pages,
+		      dev->priv.name);
+	while (dev->priv.vfs_pages) {
+		if (time_after(jiffies, end)) {
+			mlx5_core_warn(dev, "aborting while there are %d pending pages\n", dev->priv.vfs_pages);
+			return -ETIMEDOUT;
+		}
+		if (dev->priv.vfs_pages < prev_vfs_pages) {
+			end = jiffies + msecs_to_jiffies(MAX_RECLAIM_VFS_PAGES_TIME_MSECS);
+			prev_vfs_pages = dev->priv.vfs_pages;
+		}
+		msleep(50);
+	}
+
+	mlx5_core_dbg(dev, "All pages received from %s\n", dev->priv.name);
+	return 0;
+}
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/port.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -32,6 +32,7 @@
 
 #include <linux/module.h>
 #include <linux/mlx5/driver.h>
+#include <linux/mlx5/port.h>
 #include <linux/mlx5/cmd.h>
 #include "mlx5_core.h"
 
@@ -246,8 +247,8 @@
 }
 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
 
-static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, int *admin_mtu,
-				int *max_mtu, int *oper_mtu, u8 port)
+static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
+				u16 *max_mtu, u16 *oper_mtu, u8 port)
 {
 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
@@ -267,7 +268,7 @@
 		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
 }
 
-int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu, u8 port)
+int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
 {
 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
@@ -282,14 +283,14 @@
 }
 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
 
-void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu,
+void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
 			     u8 port)
 {
 	mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
 }
 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
 
-void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu,
+void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
 			      u8 port)
 {
 	mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/qp.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/qp.c
@@ -393,7 +393,7 @@
 	if (out.hdr.status)
 		err = mlx5_cmd_status_to_err(&out.hdr);
 	else
-		*xrcdn = be32_to_cpu(out.xrcdn);
+		*xrcdn = be32_to_cpu(out.xrcdn) & 0xffffff;
 
 	return err;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2014, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/pci.h>
+#include <linux/mlx5/driver.h>
+#include "mlx5_core.h"
+#ifdef CONFIG_MLX5_CORE_EN
+#include "eswitch.h"
+#endif
+
+static void enable_vfs(struct mlx5_core_dev *dev, int num_vfs)
+{
+	struct mlx5_core_sriov *sriov = &dev->priv.sriov;
+	int err;
+	int vf;
+
+	for (vf = 1; vf <= num_vfs; vf++) {
+		err = mlx5_core_enable_hca(dev, vf);
+		if (err) {
+			mlx5_core_warn(dev, "failed to enable VF %d\n", vf - 1);
+		} else {
+			sriov->vfs_ctx[vf - 1].enabled = 1;
+			mlx5_core_dbg(dev, "successfully enabled VF %d\n", vf - 1);
+		}
+	}
+}
+
+static void disable_vfs(struct mlx5_core_dev *dev, int num_vfs)
+{
+	struct mlx5_core_sriov *sriov = &dev->priv.sriov;
+	int vf;
+
+	for (vf = 1; vf <= num_vfs; vf++) {
+		if (sriov->vfs_ctx[vf - 1].enabled) {
+			if (mlx5_core_disable_hca(dev, vf))
+				mlx5_core_warn(dev, "failed to disable VF %d\n", vf - 1);
+			else
+				sriov->vfs_ctx[vf - 1].enabled = 0;
+		}
+	}
+}
+
+static int mlx5_core_create_vfs(struct pci_dev *pdev, int num_vfs)
+{
+	struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
+	int err;
+
+	if (pci_num_vf(pdev))
+		pci_disable_sriov(pdev);
+
+	enable_vfs(dev, num_vfs);
+
+	err = pci_enable_sriov(pdev, num_vfs);
+	if (err) {
+		dev_warn(&pdev->dev, "enable sriov failed %d\n", err);
+		goto ex;
+	}
+
+	return 0;
+
+ex:
+	disable_vfs(dev, num_vfs);
+	return err;
+}
+
+static int mlx5_core_sriov_enable(struct pci_dev *pdev, int num_vfs)
+{
+	struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
+	struct mlx5_core_sriov *sriov = &dev->priv.sriov;
+	int err;
+
+	kfree(sriov->vfs_ctx);
+	sriov->vfs_ctx = kcalloc(num_vfs, sizeof(*sriov->vfs_ctx), GFP_ATOMIC);
+	if (!sriov->vfs_ctx)
+		return -ENOMEM;
+
+	sriov->enabled_vfs = num_vfs;
+	err = mlx5_core_create_vfs(pdev, num_vfs);
+	if (err) {
+		kfree(sriov->vfs_ctx);
+		sriov->vfs_ctx = NULL;
+		return err;
+	}
+
+	return 0;
+}
+
+static void mlx5_core_init_vfs(struct mlx5_core_dev *dev, int num_vfs)
+{
+	struct mlx5_core_sriov *sriov = &dev->priv.sriov;
+
+	sriov->num_vfs = num_vfs;
+}
+
+static void mlx5_core_cleanup_vfs(struct mlx5_core_dev *dev)
+{
+	struct mlx5_core_sriov *sriov;
+
+	sriov = &dev->priv.sriov;
+	disable_vfs(dev, sriov->num_vfs);
+
+	if (mlx5_wait_for_vf_pages(dev))
+		mlx5_core_warn(dev, "timeout claiming VFs pages\n");
+
+	sriov->num_vfs = 0;
+}
+
+int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+	struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
+	struct mlx5_core_sriov *sriov = &dev->priv.sriov;
+	int err;
+
+	mlx5_core_dbg(dev, "requsted num_vfs %d\n", num_vfs);
+	if (!mlx5_core_is_pf(dev))
+		return -EPERM;
+
+	mlx5_core_cleanup_vfs(dev);
+
+	if (!num_vfs) {
+#ifdef CONFIG_MLX5_CORE_EN
+		mlx5_eswitch_disable_sriov(dev->priv.eswitch);
+#endif
+		kfree(sriov->vfs_ctx);
+		sriov->vfs_ctx = NULL;
+		if (!pci_vfs_assigned(pdev))
+			pci_disable_sriov(pdev);
+		else
+			pr_info("unloading PF driver while leaving orphan VFs\n");
+		return 0;
+	}
+
+	err = mlx5_core_sriov_enable(pdev, num_vfs);
+	if (err) {
+		dev_warn(&pdev->dev, "mlx5_core_sriov_enable failed %d\n", err);
+		return err;
+	}
+
+	mlx5_core_init_vfs(dev, num_vfs);
+#ifdef CONFIG_MLX5_CORE_EN
+	mlx5_eswitch_enable_sriov(dev->priv.eswitch, num_vfs);
+#endif
+
+	return num_vfs;
+}
+
+static int sync_required(struct pci_dev *pdev)
+{
+	struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
+	struct mlx5_core_sriov *sriov = &dev->priv.sriov;
+	int cur_vfs = pci_num_vf(pdev);
+
+	if (cur_vfs != sriov->num_vfs) {
+		pr_info("current VFs %d, registered %d - sync needed\n", cur_vfs, sriov->num_vfs);
+		return 1;
+	}
+
+	return 0;
+}
+
+int mlx5_sriov_init(struct mlx5_core_dev *dev)
+{
+	struct mlx5_core_sriov *sriov = &dev->priv.sriov;
+	struct pci_dev *pdev = dev->pdev;
+	int cur_vfs;
+
+	if (!mlx5_core_is_pf(dev))
+		return 0;
+
+	if (!sync_required(dev->pdev))
+		return 0;
+
+	cur_vfs = pci_num_vf(pdev);
+	sriov->vfs_ctx = kcalloc(cur_vfs, sizeof(*sriov->vfs_ctx), GFP_KERNEL);
+	if (!sriov->vfs_ctx)
+		return -ENOMEM;
+
+	sriov->enabled_vfs = cur_vfs;
+
+	mlx5_core_init_vfs(dev, cur_vfs);
+#ifdef CONFIG_MLX5_CORE_EN
+	if (cur_vfs)
+		mlx5_eswitch_enable_sriov(dev->priv.eswitch, cur_vfs);
+#endif
+
+	enable_vfs(dev, cur_vfs);
+
+	return 0;
+}
+
+int mlx5_sriov_cleanup(struct mlx5_core_dev *dev)
+{
+	struct pci_dev *pdev = dev->pdev;
+	int err;
+
+	if (!mlx5_core_is_pf(dev))
+		return 0;
+
+	err = mlx5_core_sriov_configure(pdev, 0);
+	if (err)
+		return err;
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/vport.c
@@ -36,54 +36,399 @@
 #include <linux/mlx5/vport.h>
 #include "mlx5_core.h"
 
-u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod)
+static int _mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod,
+				   u16 vport, u32 *out, int outlen)
 {
-	u32 in[MLX5_ST_SZ_DW(query_vport_state_in)];
-	u32 out[MLX5_ST_SZ_DW(query_vport_state_out)];
 	int err;
+	u32 in[MLX5_ST_SZ_DW(query_vport_state_in)];
 
 	memset(in, 0, sizeof(in));
 
 	MLX5_SET(query_vport_state_in, in, opcode,
 		 MLX5_CMD_OP_QUERY_VPORT_STATE);
 	MLX5_SET(query_vport_state_in, in, op_mod, opmod);
+	MLX5_SET(query_vport_state_in, in, vport_number, vport);
+	if (vport)
+		MLX5_SET(query_vport_state_in, in, other_vport, 1);
 
-	err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out,
-					 sizeof(out));
+	err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen);
 	if (err)
 		mlx5_core_warn(mdev, "MLX5_CMD_OP_QUERY_VPORT_STATE failed\n");
 
+	return err;
+}
+
+u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport)
+{
+	u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {0};
+
+	_mlx5_query_vport_state(mdev, opmod, vport, out, sizeof(out));
+
 	return MLX5_GET(query_vport_state_out, out, state);
 }
-EXPORT_SYMBOL(mlx5_query_vport_state);
+EXPORT_SYMBOL_GPL(mlx5_query_vport_state);
+
+u8 mlx5_query_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport)
+{
+	u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {0};
+
+	_mlx5_query_vport_state(mdev, opmod, vport, out, sizeof(out));
+
+	return MLX5_GET(query_vport_state_out, out, admin_state);
+}
+EXPORT_SYMBOL(mlx5_query_vport_admin_state);
+
+int mlx5_modify_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod,
+				  u16 vport, u8 state)
+{
+	u32 in[MLX5_ST_SZ_DW(modify_vport_state_in)];
+	u32 out[MLX5_ST_SZ_DW(modify_vport_state_out)];
+	int err;
+
+	memset(in, 0, sizeof(in));
+
+	MLX5_SET(modify_vport_state_in, in, opcode,
+		 MLX5_CMD_OP_MODIFY_VPORT_STATE);
+	MLX5_SET(modify_vport_state_in, in, op_mod, opmod);
+	MLX5_SET(modify_vport_state_in, in, vport_number, vport);
+
+	if (vport)
+		MLX5_SET(modify_vport_state_in, in, other_vport, 1);
+
+	MLX5_SET(modify_vport_state_in, in, admin_state, state);
+
+	err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out,
+					 sizeof(out));
+	if (err)
+		mlx5_core_warn(mdev, "MLX5_CMD_OP_MODIFY_VPORT_STATE failed\n");
+
+	return err;
+}
+EXPORT_SYMBOL(mlx5_modify_vport_admin_state);
+
+static int mlx5_query_nic_vport_context(struct mlx5_core_dev *mdev, u16 vport,
+					u32 *out, int outlen)
+{
+	u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)];
+
+	memset(in, 0, sizeof(in));
+
+	MLX5_SET(query_nic_vport_context_in, in, opcode,
+		 MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT);
+
+	MLX5_SET(query_nic_vport_context_in, in, vport_number, vport);
+	if (vport)
+		MLX5_SET(query_nic_vport_context_in, in, other_vport, 1);
+
+	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen);
+}
+
+static int mlx5_modify_nic_vport_context(struct mlx5_core_dev *mdev, void *in,
+					 int inlen)
+{
+	u32 out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)];
+
+	MLX5_SET(modify_nic_vport_context_in, in, opcode,
+		 MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
+
+	memset(out, 0, sizeof(out));
+	return mlx5_cmd_exec_check_status(mdev, in, inlen, out, sizeof(out));
+}
 
-void mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr)
+int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev,
+				     u16 vport, u8 *addr)
 {
-	u32  in[MLX5_ST_SZ_DW(query_nic_vport_context_in)];
 	u32 *out;
 	int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out);
 	u8 *out_addr;
+	int err;
 
 	out = mlx5_vzalloc(outlen);
 	if (!out)
-		return;
+		return -ENOMEM;
 
 	out_addr = MLX5_ADDR_OF(query_nic_vport_context_out, out,
 				nic_vport_context.permanent_address);
 
+	err = mlx5_query_nic_vport_context(mdev, vport, out, outlen);
+	if (err)
+		goto out;
+
+	ether_addr_copy(addr, &out_addr[2]);
+
+out:
+	kvfree(out);
+	return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_mac_address);
+
+int mlx5_modify_nic_vport_mac_address(struct mlx5_core_dev *mdev,
+				      u16 vport, u8 *addr)
+{
+	void *in;
+	int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in);
+	int err;
+	void *nic_vport_ctx;
+	u8 *perm_mac;
+
+	in = mlx5_vzalloc(inlen);
+	if (!in) {
+		mlx5_core_warn(mdev, "failed to allocate inbox\n");
+		return -ENOMEM;
+	}
+
+	MLX5_SET(modify_nic_vport_context_in, in,
+		 field_select.permanent_address, 1);
+	MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
+
+	if (vport)
+		MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
+
+	nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
+				     in, nic_vport_context);
+	perm_mac = MLX5_ADDR_OF(nic_vport_context, nic_vport_ctx,
+				permanent_address);
+
+	ether_addr_copy(&perm_mac[2], addr);
+
+	err = mlx5_modify_nic_vport_context(mdev, in, inlen);
+
+	kvfree(in);
+
+	return err;
+}
+EXPORT_SYMBOL(mlx5_modify_nic_vport_mac_address);
+
+int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,
+				  u32 vport,
+				  enum mlx5_list_type list_type,
+				  u8 addr_list[][ETH_ALEN],
+				  int *list_size)
+{
+	u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)];
+	void *nic_vport_ctx;
+	int max_list_size;
+	int req_list_size;
+	int out_sz;
+	void *out;
+	int err;
+	int i;
+
+	req_list_size = *list_size;
+
+	max_list_size = list_type == MLX5_NVPRT_LIST_TYPE_UC ?
+		1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) :
+		1 << MLX5_CAP_GEN(dev, log_max_current_mc_list);
+
+	if (req_list_size > max_list_size) {
+		mlx5_core_warn(dev, "Requested list size (%d) > (%d) max_list_size\n",
+			       req_list_size, max_list_size);
+		req_list_size = max_list_size;
+	}
+
+	out_sz = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in) +
+			req_list_size * MLX5_ST_SZ_BYTES(mac_address_layout);
+
 	memset(in, 0, sizeof(in));
+	out = kzalloc(out_sz, GFP_KERNEL);
+	if (!out)
+		return -ENOMEM;
 
 	MLX5_SET(query_nic_vport_context_in, in, opcode,
 		 MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT);
+	MLX5_SET(query_nic_vport_context_in, in, allowed_list_type, list_type);
+	MLX5_SET(query_nic_vport_context_in, in, vport_number, vport);
 
-	memset(out, 0, outlen);
-	mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen);
+	if (vport)
+		MLX5_SET(query_nic_vport_context_in, in, other_vport, 1);
 
-	ether_addr_copy(addr, &out_addr[2]);
+	err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, out_sz);
+	if (err)
+		goto out;
 
-	kvfree(out);
+	nic_vport_ctx = MLX5_ADDR_OF(query_nic_vport_context_out, out,
+				     nic_vport_context);
+	req_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx,
+				 allowed_list_size);
+
+	*list_size = req_list_size;
+	for (i = 0; i < req_list_size; i++) {
+		u8 *mac_addr = MLX5_ADDR_OF(nic_vport_context,
+					nic_vport_ctx,
+					current_uc_mac_address[i]) + 2;
+		ether_addr_copy(addr_list[i], mac_addr);
+	}
+out:
+	kfree(out);
+	return err;
 }
-EXPORT_SYMBOL(mlx5_query_nic_vport_mac_address);
+EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_mac_list);
+
+int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev,
+				   enum mlx5_list_type list_type,
+				   u8 addr_list[][ETH_ALEN],
+				   int list_size)
+{
+	u32 out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)];
+	void *nic_vport_ctx;
+	int max_list_size;
+	int in_sz;
+	void *in;
+	int err;
+	int i;
+
+	max_list_size = list_type == MLX5_NVPRT_LIST_TYPE_UC ?
+		 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) :
+		 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list);
+
+	if (list_size > max_list_size)
+		return -ENOSPC;
+
+	in_sz = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in) +
+		list_size * MLX5_ST_SZ_BYTES(mac_address_layout);
+
+	memset(out, 0, sizeof(out));
+	in = kzalloc(in_sz, GFP_KERNEL);
+	if (!in)
+		return -ENOMEM;
+
+	MLX5_SET(modify_nic_vport_context_in, in, opcode,
+		 MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
+	MLX5_SET(modify_nic_vport_context_in, in,
+		 field_select.addresses_list, 1);
+
+	nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in, in,
+				     nic_vport_context);
+
+	MLX5_SET(nic_vport_context, nic_vport_ctx,
+		 allowed_list_type, list_type);
+	MLX5_SET(nic_vport_context, nic_vport_ctx,
+		 allowed_list_size, list_size);
+
+	for (i = 0; i < list_size; i++) {
+		u8 *curr_mac = MLX5_ADDR_OF(nic_vport_context,
+					    nic_vport_ctx,
+					    current_uc_mac_address[i]) + 2;
+		ether_addr_copy(curr_mac, addr_list[i]);
+	}
+
+	err = mlx5_cmd_exec_check_status(dev, in, in_sz, out, sizeof(out));
+	kfree(in);
+	return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_mac_list);
+
+int mlx5_query_nic_vport_vlans(struct mlx5_core_dev *dev,
+			       u32 vport,
+			       u16 vlans[],
+			       int *size)
+{
+	u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)];
+	void *nic_vport_ctx;
+	int req_list_size;
+	int max_list_size;
+	int out_sz;
+	void *out;
+	int err;
+	int i;
+
+	req_list_size = *size;
+	max_list_size = 1 << MLX5_CAP_GEN(dev, log_max_vlan_list);
+	if (req_list_size > max_list_size) {
+		mlx5_core_warn(dev, "Requested list size (%d) > (%d) max list size\n",
+			       req_list_size, max_list_size);
+		req_list_size = max_list_size;
+	}
+
+	out_sz = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in) +
+			req_list_size * MLX5_ST_SZ_BYTES(vlan_layout);
+
+	memset(in, 0, sizeof(in));
+	out = kzalloc(out_sz, GFP_KERNEL);
+	if (!out)
+		return -ENOMEM;
+
+	MLX5_SET(query_nic_vport_context_in, in, opcode,
+		 MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT);
+	MLX5_SET(query_nic_vport_context_in, in, allowed_list_type,
+		 MLX5_NVPRT_LIST_TYPE_VLAN);
+	MLX5_SET(query_nic_vport_context_in, in, vport_number, vport);
+
+	if (vport)
+		MLX5_SET(query_nic_vport_context_in, in, other_vport, 1);
+
+	err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, out_sz);
+	if (err)
+		goto out;
+
+	nic_vport_ctx = MLX5_ADDR_OF(query_nic_vport_context_out, out,
+				     nic_vport_context);
+	req_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx,
+				 allowed_list_size);
+
+	*size = req_list_size;
+	for (i = 0; i < req_list_size; i++) {
+		void *vlan_addr = MLX5_ADDR_OF(nic_vport_context,
+					       nic_vport_ctx,
+					       current_uc_mac_address[i]);
+		vlans[i] = MLX5_GET(vlan_layout, vlan_addr, vlan);
+	}
+out:
+	kfree(out);
+	return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_vlans);
+
+int mlx5_modify_nic_vport_vlans(struct mlx5_core_dev *dev,
+				u16 vlans[],
+				int list_size)
+{
+	u32 out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)];
+	void *nic_vport_ctx;
+	int max_list_size;
+	int in_sz;
+	void *in;
+	int err;
+	int i;
+
+	max_list_size = 1 << MLX5_CAP_GEN(dev, log_max_vlan_list);
+
+	if (list_size > max_list_size)
+		return -ENOSPC;
+
+	in_sz = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in) +
+		list_size * MLX5_ST_SZ_BYTES(vlan_layout);
+
+	memset(out, 0, sizeof(out));
+	in = kzalloc(in_sz, GFP_KERNEL);
+	if (!in)
+		return -ENOMEM;
+
+	MLX5_SET(modify_nic_vport_context_in, in, opcode,
+		 MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
+	MLX5_SET(modify_nic_vport_context_in, in,
+		 field_select.addresses_list, 1);
+
+	nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in, in,
+				     nic_vport_context);
+
+	MLX5_SET(nic_vport_context, nic_vport_ctx,
+		 allowed_list_type, MLX5_NVPRT_LIST_TYPE_VLAN);
+	MLX5_SET(nic_vport_context, nic_vport_ctx,
+		 allowed_list_size, list_size);
+
+	for (i = 0; i < list_size; i++) {
+		void *vlan_addr = MLX5_ADDR_OF(nic_vport_context,
+					       nic_vport_ctx,
+					       current_uc_mac_address[i]);
+		MLX5_SET(vlan_layout, vlan_addr, vlan, vlans[i]);
+	}
+
+	err = mlx5_cmd_exec_check_status(dev, in, in_sz, out, sizeof(out));
+	kfree(in);
+	return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_vlans);
 
 int mlx5_query_hca_vport_gid(struct mlx5_core_dev *dev, u8 other_vport,
 			     u8 port_num, u16  vf_num, u16 gid_index,
@@ -343,3 +688,65 @@
 	return err;
 }
 EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_node_guid);
+
+int mlx5_query_nic_vport_promisc(struct mlx5_core_dev *mdev,
+				 u32 vport,
+				 int *promisc_uc,
+				 int *promisc_mc,
+				 int *promisc_all)
+{
+	u32 *out;
+	int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out);
+	int err;
+
+	out = kzalloc(outlen, GFP_KERNEL);
+	if (!out)
+		return -ENOMEM;
+
+	err = mlx5_query_nic_vport_context(mdev, vport, out, outlen);
+	if (err)
+		goto out;
+
+	*promisc_uc = MLX5_GET(query_nic_vport_context_out, out,
+			       nic_vport_context.promisc_uc);
+	*promisc_mc = MLX5_GET(query_nic_vport_context_out, out,
+			       nic_vport_context.promisc_mc);
+	*promisc_all = MLX5_GET(query_nic_vport_context_out, out,
+				nic_vport_context.promisc_all);
+
+out:
+	kfree(out);
+	return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_promisc);
+
+int mlx5_modify_nic_vport_promisc(struct mlx5_core_dev *mdev,
+				  int promisc_uc,
+				  int promisc_mc,
+				  int promisc_all)
+{
+	void *in;
+	int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in);
+	int err;
+
+	in = mlx5_vzalloc(inlen);
+	if (!in) {
+		mlx5_core_err(mdev, "failed to allocate inbox\n");
+		return -ENOMEM;
+	}
+
+	MLX5_SET(modify_nic_vport_context_in, in, field_select.promisc, 1);
+	MLX5_SET(modify_nic_vport_context_in, in,
+		 nic_vport_context.promisc_uc, promisc_uc);
+	MLX5_SET(modify_nic_vport_context_in, in,
+		 nic_vport_context.promisc_mc, promisc_mc);
+	MLX5_SET(modify_nic_vport_context_in, in,
+		 nic_vport_context.promisc_all, promisc_all);
+
+	err = mlx5_modify_nic_vport_context(mdev, in, inlen);
+
+	kvfree(in);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_promisc);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/wq.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlx5/core/wq.c
@@ -75,14 +75,14 @@
 
 	err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node);
 	if (err) {
-		mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err);
+		mlx5_core_warn(mdev, "mlx5_db_alloc_node() failed, %d\n", err);
 		return err;
 	}
 
 	err = mlx5_buf_alloc_node(mdev, mlx5_wq_cyc_get_byte_size(wq),
 				  &wq_ctrl->buf, param->buf_numa_node);
 	if (err) {
-		mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err);
+		mlx5_core_warn(mdev, "mlx5_buf_alloc_node() failed, %d\n", err);
 		goto err_db_free;
 	}
 
@@ -111,14 +111,14 @@
 
 	err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node);
 	if (err) {
-		mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err);
+		mlx5_core_warn(mdev, "mlx5_db_alloc_node() failed, %d\n", err);
 		return err;
 	}
 
 	err = mlx5_buf_alloc_node(mdev, mlx5_cqwq_get_byte_size(wq),
 				  &wq_ctrl->buf, param->buf_numa_node);
 	if (err) {
-		mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err);
+		mlx5_core_warn(mdev, "mlx5_buf_alloc_node() failed, %d\n", err);
 		goto err_db_free;
 	}
 
@@ -148,13 +148,14 @@
 
 	err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node);
 	if (err) {
-		mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err);
+		mlx5_core_warn(mdev, "mlx5_db_alloc_node() failed, %d\n", err);
 		return err;
 	}
 
-	err = mlx5_buf_alloc(mdev, mlx5_wq_ll_get_byte_size(wq), &wq_ctrl->buf);
+	err = mlx5_buf_alloc_node(mdev, mlx5_wq_ll_get_byte_size(wq),
+				  &wq_ctrl->buf, param->buf_numa_node);
 	if (err) {
-		mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err);
+		mlx5_core_warn(mdev, "mlx5_buf_alloc_node() failed, %d\n", err);
 		goto err_db_free;
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -1208,9 +1208,10 @@
 			break;
 		}
 	}
-	rcu_read_unlock();
-	if (!found)
+	if (!found) {
+		rcu_read_unlock();
 		goto drop;
+	}
 
 	pcpu_stats = this_cpu_ptr(mlxsw_core->pcpu_stats);
 	u64_stats_update_begin(&pcpu_stats->syncp);
@@ -1221,6 +1222,7 @@
 	u64_stats_update_end(&pcpu_stats->syncp);
 
 	rxl->func(skb, local_port, rxl_item->priv);
+	rcu_read_unlock();
 	return;
 
 drop:
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -215,7 +215,7 @@
 {
 	int index = q->producer_counter & (q->count - 1);
 
-	if ((q->producer_counter - q->consumer_counter) == q->count)
+	if ((u16) (q->producer_counter - q->consumer_counter) == q->count)
 		return NULL;
 	return mlxsw_pci_queue_elem_info_get(q, index);
 }
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/pci.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/pci.h
@@ -206,21 +206,21 @@
 /* pci_eqe_cmd_token
  * Command completion event - token
  */
-MLXSW_ITEM32(pci, eqe, cmd_token, 0x08, 16, 16);
+MLXSW_ITEM32(pci, eqe, cmd_token, 0x00, 16, 16);
 
 /* pci_eqe_cmd_status
  * Command completion event - status
  */
-MLXSW_ITEM32(pci, eqe, cmd_status, 0x08, 0, 8);
+MLXSW_ITEM32(pci, eqe, cmd_status, 0x00, 0, 8);
 
 /* pci_eqe_cmd_out_param_h
  * Command completion event - output parameter - higher part
  */
-MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x0C, 0, 32);
+MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x04, 0, 32);
 
 /* pci_eqe_cmd_out_param_l
  * Command completion event - output parameter - lower part
  */
-MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x10, 0, 32);
+MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x08, 0, 32);
 
 #endif
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/port.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/port.h
@@ -49,7 +49,7 @@
 #define MLXSW_PORT_MID			0xd000
 
 #define MLXSW_PORT_MAX_PHY_PORTS	0x40
-#define MLXSW_PORT_MAX_PORTS		MLXSW_PORT_MAX_PHY_PORTS
+#define MLXSW_PORT_MAX_PORTS		(MLXSW_PORT_MAX_PHY_PORTS + 1)
 
 #define MLXSW_PORT_DEVID_BITS_OFFSET	10
 #define MLXSW_PORT_PHY_BITS_OFFSET	4
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -599,7 +599,7 @@
 #define MLXSW_REG_SPVM_ID 0x200F
 #define MLXSW_REG_SPVM_BASE_LEN 0x04 /* base length, without records */
 #define MLXSW_REG_SPVM_REC_LEN 0x04 /* record length */
-#define MLXSW_REG_SPVM_REC_MAX_COUNT 256
+#define MLXSW_REG_SPVM_REC_MAX_COUNT 255
 #define MLXSW_REG_SPVM_LEN (MLXSW_REG_SPVM_BASE_LEN +	\
 		    MLXSW_REG_SPVM_REC_LEN * MLXSW_REG_SPVM_REC_MAX_COUNT)
 
@@ -1139,7 +1139,7 @@
 #define MLXSW_REG_SPVMLR_ID 0x2020
 #define MLXSW_REG_SPVMLR_BASE_LEN 0x04 /* base length, without records */
 #define MLXSW_REG_SPVMLR_REC_LEN 0x04 /* record length */
-#define MLXSW_REG_SPVMLR_REC_MAX_COUNT 256
+#define MLXSW_REG_SPVMLR_REC_MAX_COUNT 255
 #define MLXSW_REG_SPVMLR_LEN (MLXSW_REG_SPVMLR_BASE_LEN + \
 			      MLXSW_REG_SPVMLR_REC_LEN * \
 			      MLXSW_REG_SPVMLR_REC_MAX_COUNT)
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -390,6 +390,7 @@
 			dev_kfree_skb_any(skb_orig);
 			return NETDEV_TX_OK;
 		}
+		dev_consume_skb_any(skb_orig);
 	}
 
 	if (eth_skb_pad(skb)) {
@@ -398,7 +399,11 @@
 	}
 
 	mlxsw_sp_txhdr_construct(skb, &tx_info);
-	len = skb->len;
+	/* TX header is consumed by HW on the way so we shouldn't count its
+	 * bytes as being sent.
+	 */
+	len = skb->len - MLXSW_TXHDR_LEN;
+
 	/* Due to a race we might fail here because of a full queue. In that
 	 * unlikely case we simply drop the packet.
 	 */
@@ -1099,7 +1104,8 @@
 
 	cmd->supported = mlxsw_sp_from_ptys_supported_port(eth_proto_cap) |
 			 mlxsw_sp_from_ptys_supported_link(eth_proto_cap) |
-			 SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+			 SUPPORTED_Pause | SUPPORTED_Asym_Pause |
+			 SUPPORTED_Autoneg;
 	cmd->advertising = mlxsw_sp_from_ptys_advert_link(eth_proto_admin);
 	mlxsw_sp_from_ptys_speed_duplex(netif_carrier_ok(dev),
 					eth_proto_oper, cmd);
@@ -1255,7 +1261,7 @@
 	/* Each packet needs to have a Tx header (metadata) on top all other
 	 * headers.
 	 */
-	dev->hard_header_len += MLXSW_TXHDR_LEN;
+	dev->needed_headroom = MLXSW_TXHDR_LEN;
 
 	err = mlxsw_sp_port_module_check(mlxsw_sp_port, &usable);
 	if (err) {
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -61,6 +61,8 @@
 #define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100
 		unsigned int interval; /* ms */
 	} fdb_notify;
+#define MLXSW_SP_MIN_AGEING_TIME 10
+#define MLXSW_SP_MAX_AGEING_TIME 1000000
 #define MLXSW_SP_DEFAULT_AGEING_TIME 300
 	u32 ageing_time;
 	struct {
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -45,6 +45,7 @@
 #include <linux/if_bridge.h>
 #include <linux/workqueue.h>
 #include <linux/jiffies.h>
+#include <linux/rtnetlink.h>
 #include <net/switchdev.h>
 
 #include "spectrum.h"
@@ -86,14 +87,14 @@
 	int err;
 
 	switch (state) {
-	case BR_STATE_DISABLED: /* fall-through */
 	case BR_STATE_FORWARDING:
 		spms_state = MLXSW_REG_SPMS_STATE_FORWARDING;
 		break;
-	case BR_STATE_LISTENING: /* fall-through */
 	case BR_STATE_LEARNING:
 		spms_state = MLXSW_REG_SPMS_STATE_LEARNING;
 		break;
+	case BR_STATE_LISTENING: /* fall-through */
+	case BR_STATE_DISABLED: /* fall-through */
 	case BR_STATE_BLOCKING:
 		spms_state = MLXSW_REG_SPMS_STATE_DISCARDING;
 		break;
@@ -231,8 +232,13 @@
 	unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
 	u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
 
-	if (switchdev_trans_ph_prepare(trans))
-		return 0;
+	if (switchdev_trans_ph_prepare(trans)) {
+		if (ageing_time < MLXSW_SP_MIN_AGEING_TIME ||
+		    ageing_time > MLXSW_SP_MAX_AGEING_TIME)
+			return -ERANGE;
+		else
+			return 0;
+	}
 
 	return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
 }
@@ -812,6 +818,7 @@
 
 	mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work);
 
+	rtnl_lock();
 	do {
 		mlxsw_reg_sfn_pack(sfn_pl);
 		err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
@@ -824,6 +831,7 @@
 			mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
 
 	} while (num_rec);
+	rtnl_unlock();
 
 	kfree(sfn_pl);
 	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
--- linux-4.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ linux-4.4.0/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
@@ -313,6 +313,7 @@
 			dev_kfree_skb_any(skb_orig);
 			return NETDEV_TX_OK;
 		}
+		dev_consume_skb_any(skb_orig);
 	}
 	mlxsw_sx_txhdr_construct(skb, &tx_info);
 	len = skb->len;
@@ -992,7 +993,7 @@
 	/* Each packet needs to have a Tx header (metadata) on top all other
 	 * headers.
 	 */
-	dev->hard_header_len += MLXSW_TXHDR_LEN;
+	dev->needed_headroom = MLXSW_TXHDR_LEN;
 
 	err = mlxsw_sx_port_module_check(mlxsw_sx_port, &usable);
 	if (err) {
@@ -1073,6 +1074,7 @@
 err_port_admin_status_set:
 err_port_mtu_set:
 err_port_speed_set:
+	mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
 err_port_swid_set:
 err_port_system_port_mapping_set:
 port_not_usable:
--- linux-4.4.0.orig/drivers/net/ethernet/micrel/ks8695net.c
+++ linux-4.4.0/drivers/net/ethernet/micrel/ks8695net.c
@@ -1156,7 +1156,7 @@
  *	sk_buff and adds it to the TX ring. It then kicks the TX DMA
  *	engine to ensure transmission begins.
  */
-static int
+static netdev_tx_t
 ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct ks8695_priv *ksp = netdev_priv(ndev);
--- linux-4.4.0.orig/drivers/net/ethernet/micrel/ks8842.c
+++ linux-4.4.0/drivers/net/ethernet/micrel/ks8842.c
@@ -561,8 +561,8 @@
 		sg_init_table(sg, 1);
 		sg_dma_address(sg) = dma_map_single(adapter->dev,
 			ctl->skb->data, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
-		err = dma_mapping_error(adapter->dev, sg_dma_address(sg));
-		if (unlikely(err)) {
+		if (dma_mapping_error(adapter->dev, sg_dma_address(sg))) {
+			err = -ENOMEM;
 			sg_dma_address(sg) = 0;
 			goto out;
 		}
@@ -572,8 +572,10 @@
 		ctl->adesc = dmaengine_prep_slave_sg(ctl->chan,
 			sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
 
-		if (!ctl->adesc)
+		if (!ctl->adesc) {
+			err = -ENOMEM;
 			goto out;
+		}
 
 		ctl->adesc->callback_param = netdev;
 		ctl->adesc->callback = ks8842_dma_rx_cb;
@@ -584,7 +586,7 @@
 		goto out;
 	}
 
-	return err;
+	return 0;
 out:
 	if (sg_dma_address(sg))
 		dma_unmap_single(adapter->dev, sg_dma_address(sg),
--- linux-4.4.0.orig/drivers/net/ethernet/micrel/ks8851.c
+++ linux-4.4.0/drivers/net/ethernet/micrel/ks8851.c
@@ -547,9 +547,8 @@
 		/* set dma read address */
 		ks8851_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI | 0x00);
 
-		/* start the packet dma process, and set auto-dequeue rx */
-		ks8851_wrreg16(ks, KS_RXQCR,
-			       ks->rc_rxqcr | RXQCR_SDA | RXQCR_ADRFE);
+		/* start DMA access */
+		ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA);
 
 		if (rxlen > 4) {
 			unsigned int rxalign;
@@ -580,7 +579,8 @@
 			}
 		}
 
-		ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr);
+		/* end DMA access and dequeue packet */
+		ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_RRXEF);
 	}
 }
 
@@ -797,6 +797,15 @@
 static int ks8851_net_open(struct net_device *dev)
 {
 	struct ks8851_net *ks = netdev_priv(dev);
+	int ret;
+
+	ret = request_threaded_irq(dev->irq, NULL, ks8851_irq,
+				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				   dev->name, ks);
+	if (ret < 0) {
+		netdev_err(dev, "failed to get irq\n");
+		return ret;
+	}
 
 	/* lock the card, even if we may not actually be doing anything
 	 * else at the moment */
@@ -861,6 +870,7 @@
 	netif_dbg(ks, ifup, ks->netdev, "network device up\n");
 
 	mutex_unlock(&ks->lock);
+	mii_check_link(&ks->mii);
 	return 0;
 }
 
@@ -911,6 +921,8 @@
 		dev_kfree_skb(txb);
 	}
 
+	free_irq(dev->irq, ks);
+
 	return 0;
 }
 
@@ -1516,6 +1528,7 @@
 
 	spi_set_drvdata(spi, ks);
 
+	netif_carrier_off(ks->netdev);
 	ndev->if_port = IF_PORT_100BASET;
 	ndev->netdev_ops = &ks8851_netdev_ops;
 	ndev->irq = spi->irq;
@@ -1542,14 +1555,6 @@
 	ks8851_read_selftest(ks);
 	ks8851_init_mac(ks);
 
-	ret = request_threaded_irq(spi->irq, NULL, ks8851_irq,
-				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-				   ndev->name, ks);
-	if (ret < 0) {
-		dev_err(&spi->dev, "failed to get irq\n");
-		goto err_irq;
-	}
-
 	ret = register_netdev(ndev);
 	if (ret) {
 		dev_err(&spi->dev, "failed to register network device\n");
@@ -1562,14 +1567,10 @@
 
 	return 0;
 
-
 err_netdev:
-	free_irq(ndev->irq, ks);
-
-err_irq:
+err_id:
 	if (gpio_is_valid(gpio))
 		gpio_set_value(gpio, 0);
-err_id:
 	regulator_disable(ks->vdd_reg);
 err_reg:
 	regulator_disable(ks->vdd_io);
@@ -1587,7 +1588,6 @@
 		dev_info(&spi->dev, "remove\n");
 
 	unregister_netdev(priv->netdev);
-	free_irq(spi->irq, priv);
 	if (gpio_is_valid(priv->gpio))
 		gpio_set_value(priv->gpio, 0);
 	regulator_disable(priv->vdd_reg);
--- linux-4.4.0.orig/drivers/net/ethernet/micrel/ks8851_mll.c
+++ linux-4.4.0/drivers/net/ethernet/micrel/ks8851_mll.c
@@ -475,21 +475,47 @@
  */
 
 /**
- * ks_rdreg8 - read 8 bit register from device
+ * ks_check_endian - Check whether endianness of the bus is correct
  * @ks	  : The chip information
- * @offset: The register address
  *
- * Read a 8bit register from the chip, returning the result
+ * The KS8851-16MLL EESK pin allows selecting the endianness of the 16bit
+ * bus. To maintain optimum performance, the bus endianness should be set
+ * such that it matches the endianness of the CPU.
  */
-static u8 ks_rdreg8(struct ks_net *ks, int offset)
+
+static int ks_check_endian(struct ks_net *ks)
 {
-	u16 data;
-	u8 shift_bit = offset & 0x03;
-	u8 shift_data = (offset & 1) << 3;
-	ks->cmd_reg_cache = (u16) offset | (u16)(BE0 << shift_bit);
-	iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd);
-	data  = ioread16(ks->hw_addr);
-	return (u8)(data >> shift_data);
+	u16 cider;
+
+	/*
+	 * Read CIDER register first, however read it the "wrong" way around.
+	 * If the endian strap on the KS8851-16MLL in incorrect and the chip
+	 * is operating in different endianness than the CPU, then the meaning
+	 * of BE[3:0] byte-enable bits is also swapped such that:
+	 *    BE[3,2,1,0] becomes BE[1,0,3,2]
+	 *
+	 * Luckily for us, the byte-enable bits are the top four MSbits of
+	 * the address register and the CIDER register is at offset 0xc0.
+	 * Hence, by reading address 0xc0c0, which is not impacted by endian
+	 * swapping, we assert either BE[3:2] or BE[1:0] while reading the
+	 * CIDER register.
+	 *
+	 * If the bus configuration is correct, reading 0xc0c0 asserts
+	 * BE[3:2] and this read returns 0x0000, because to read register
+	 * with bottom two LSbits of address set to 0, BE[1:0] must be
+	 * asserted.
+	 *
+	 * If the bus configuration is NOT correct, reading 0xc0c0 asserts
+	 * BE[1:0] and this read returns non-zero 0x8872 value.
+	 */
+	iowrite16(BE3 | BE2 | KS_CIDER, ks->hw_addr_cmd);
+	cider = ioread16(ks->hw_addr);
+	if (!cider)
+		return 0;
+
+	netdev_err(ks->netdev, "incorrect EESK endian strap setting\n");
+
+	return -EINVAL;
 }
 
 /**
@@ -508,22 +534,6 @@
 }
 
 /**
- * ks_wrreg8 - write 8bit register value to chip
- * @ks: The chip information
- * @offset: The register address
- * @value: The value to write
- *
- */
-static void ks_wrreg8(struct ks_net *ks, int offset, u8 value)
-{
-	u8  shift_bit = (offset & 0x03);
-	u16 value_write = (u16)(value << ((offset & 1) << 3));
-	ks->cmd_reg_cache = (u16)offset | (BE0 << shift_bit);
-	iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd);
-	iowrite16(value_write, ks->hw_addr);
-}
-
-/**
  * ks_wrreg16 - write 16bit register value to chip
  * @ks: The chip information
  * @offset: The register address
@@ -642,8 +652,7 @@
 	u16 reg_data = 0;
 
 	/* Regardless of bus width, 8 bit read should always work.*/
-	reg_data = ks_rdreg8(ks, KS_CCR) & 0x00FF;
-	reg_data |= ks_rdreg8(ks, KS_CCR+1) << 8;
+	reg_data = ks_rdreg16(ks, KS_CCR);
 
 	/* addr/data bus are multiplexed */
 	ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED;
@@ -747,7 +756,7 @@
 
 	/* 1. set sudo DMA mode */
 	ks_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI);
-	ks_wrreg8(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
+	ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA);
 
 	/* 2. read prepend data */
 	/**
@@ -764,7 +773,7 @@
 	ks_inblk(ks, buf, ALIGN(len, 4));
 
 	/* 4. reset sudo DMA Mode */
-	ks_wrreg8(ks, KS_RXQCR, ks->rc_rxqcr);
+	ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr);
 }
 
 /**
@@ -866,14 +875,17 @@
 {
 	struct net_device *netdev = pw;
 	struct ks_net *ks = netdev_priv(netdev);
+	unsigned long flags;
 	u16 status;
 
+	spin_lock_irqsave(&ks->statelock, flags);
 	/*this should be the first in IRQ handler */
 	ks_save_cmd_reg(ks);
 
 	status = ks_rdreg16(ks, KS_ISR);
 	if (unlikely(!status)) {
 		ks_restore_cmd_reg(ks);
+		spin_unlock_irqrestore(&ks->statelock, flags);
 		return IRQ_NONE;
 	}
 
@@ -899,6 +911,7 @@
 		ks->netdev->stats.rx_over_errors++;
 	/* this should be the last in IRQ handler*/
 	ks_restore_cmd_reg(ks);
+	spin_unlock_irqrestore(&ks->statelock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -968,6 +981,7 @@
 
 	/* shutdown RX/TX QMU */
 	ks_disable_qmu(ks);
+	ks_disable_int(ks);
 
 	/* set powermode to soft power down to save power */
 	ks_set_powermode(ks, PMECR_PM_SOFTDOWN);
@@ -997,13 +1011,13 @@
 	ks->txh.txw[1] = cpu_to_le16(len);
 
 	/* 1. set sudo-DMA mode */
-	ks_wrreg8(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
+	ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA);
 	/* 2. write status/lenth info */
 	ks_outblk(ks, ks->txh.txw, 4);
 	/* 3. write pkt data */
 	ks_outblk(ks, (u16 *)pdata, ALIGN(len, 4));
 	/* 4. reset sudo-DMA mode */
-	ks_wrreg8(ks, KS_RXQCR, ks->rc_rxqcr);
+	ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr);
 	/* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */
 	ks_wrreg16(ks, KS_TXQCR, TXQCR_METFE);
 	/* 6. wait until TXQCR_METFE is auto-cleared */
@@ -1020,14 +1034,13 @@
  * spin_lock_irqsave is required because tx and rx should be mutual exclusive.
  * So while tx is in-progress, prevent IRQ interrupt from happenning.
  */
-static int ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	int retv = NETDEV_TX_OK;
+	netdev_tx_t retv = NETDEV_TX_OK;
 	struct ks_net *ks = netdev_priv(netdev);
+	unsigned long flags;
 
-	disable_irq(netdev->irq);
-	ks_disable_int(ks);
-	spin_lock(&ks->statelock);
+	spin_lock_irqsave(&ks->statelock, flags);
 
 	/* Extra space are required:
 	*  4 byte for alignment, 4 for status/length, 4 for CRC
@@ -1041,9 +1054,7 @@
 		dev_kfree_skb(skb);
 	} else
 		retv = NETDEV_TX_BUSY;
-	spin_unlock(&ks->statelock);
-	ks_enable_int(ks);
-	enable_irq(netdev->irq);
+	spin_unlock_irqrestore(&ks->statelock, flags);
 	return retv;
 }
 
@@ -1568,6 +1579,10 @@
 		goto err_free;
 	}
 
+	err = ks_check_endian(ks);
+	if (err)
+		goto err_free;
+
 	netdev->irq = platform_get_irq(pdev, 0);
 
 	if ((int)netdev->irq < 0) {
--- linux-4.4.0.orig/drivers/net/ethernet/moxa/moxart_ether.c
+++ linux-4.4.0/drivers/net/ethernet/moxa/moxart_ether.c
@@ -460,9 +460,9 @@
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	ndev->base_addr = res->start;
 	priv->base = devm_ioremap_resource(p_dev, res);
-	ret = IS_ERR(priv->base);
-	if (ret) {
+	if (IS_ERR(priv->base)) {
 		dev_err(p_dev, "devm_ioremap_resource failed\n");
+		ret = PTR_ERR(priv->base);
 		goto init_fail;
 	}
 
@@ -541,7 +541,7 @@
 	struct net_device *ndev = platform_get_drvdata(pdev);
 
 	unregister_netdev(ndev);
-	free_irq(ndev->irq, ndev);
+	devm_free_irq(&pdev->dev, ndev->irq, ndev);
 	moxart_mac_free_memory(ndev);
 	free_netdev(ndev);
 
--- linux-4.4.0.orig/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ linux-4.4.0/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -4114,7 +4114,7 @@
 	 * setup (if available). */
 	status = myri10ge_request_irq(mgp);
 	if (status != 0)
-		goto abort_with_firmware;
+		goto abort_with_slices;
 	myri10ge_free_irq(mgp);
 
 	/* Save configuration space to be restored if the
--- linux-4.4.0.orig/drivers/net/ethernet/natsemi/jazzsonic.c
+++ linux-4.4.0/drivers/net/ethernet/natsemi/jazzsonic.c
@@ -247,13 +247,15 @@
 		goto out;
 	err = register_netdev(dev);
 	if (err)
-		goto out1;
+		goto undo_probe1;
 
 	printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq);
 
 	return 0;
 
-out1:
+undo_probe1:
+	dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+			  lp->descriptors, lp->descriptors_laddr);
 	release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
 out:
 	free_netdev(dev);
--- linux-4.4.0.orig/drivers/net/ethernet/natsemi/sonic.c
+++ linux-4.4.0/drivers/net/ethernet/natsemi/sonic.c
@@ -50,6 +50,8 @@
 	if (sonic_debug > 2)
 		printk("sonic_open: initializing sonic driver.\n");
 
+	spin_lock_init(&lp->lock);
+
 	for (i = 0; i < SONIC_NUM_RRS; i++) {
 		struct sk_buff *skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
 		if (skb == NULL) {
@@ -71,7 +73,7 @@
 	for (i = 0; i < SONIC_NUM_RRS; i++) {
 		dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE),
 		                                  SONIC_RBSIZE, DMA_FROM_DEVICE);
-		if (!laddr) {
+		if (dma_mapping_error(lp->device, laddr)) {
 			while(i > 0) { /* free any that were mapped successfully */
 				i--;
 				dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE);
@@ -101,6 +103,24 @@
 	return 0;
 }
 
+/* Wait for the SONIC to become idle. */
+static void sonic_quiesce(struct net_device *dev, u16 mask)
+{
+	struct sonic_local * __maybe_unused lp = netdev_priv(dev);
+	int i;
+	u16 bits;
+
+	for (i = 0; i < 1000; ++i) {
+		bits = SONIC_READ(SONIC_CMD) & mask;
+		if (!bits)
+			return;
+		if (irqs_disabled() || in_interrupt())
+			udelay(20);
+		else
+			usleep_range(100, 200);
+	}
+	WARN_ONCE(1, "command deadline expired! 0x%04x\n", bits);
+}
 
 /*
  * Close the SONIC device
@@ -118,6 +138,9 @@
 	/*
 	 * stop the SONIC, disable interrupts
 	 */
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
+	sonic_quiesce(dev, SONIC_CR_ALL);
+
 	SONIC_WRITE(SONIC_IMR, 0);
 	SONIC_WRITE(SONIC_ISR, 0x7fff);
 	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
@@ -157,6 +180,9 @@
 	 * put the Sonic into software-reset mode and
 	 * disable all interrupts before releasing DMA buffers
 	 */
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
+	sonic_quiesce(dev, SONIC_CR_ALL);
+
 	SONIC_WRITE(SONIC_IMR, 0);
 	SONIC_WRITE(SONIC_ISR, 0x7fff);
 	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
@@ -194,8 +220,6 @@
  *   wake the tx queue
  * Concurrently with all of this, the SONIC is potentially writing to
  * the status flags of the TDs.
- * Until some mutual exclusion is added, this code will not work with SMP. However,
- * MIPS Jazz machines and m68k Macs were all uni-processor machines.
  */
 
 static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
@@ -203,7 +227,8 @@
 	struct sonic_local *lp = netdev_priv(dev);
 	dma_addr_t laddr;
 	int length;
-	int entry = lp->next_tx;
+	int entry;
+	unsigned long flags;
 
 	if (sonic_debug > 2)
 		printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev);
@@ -221,11 +246,15 @@
 
 	laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE);
 	if (!laddr) {
-		printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name);
-		dev_kfree_skb(skb);
-		return NETDEV_TX_BUSY;
+		pr_err_ratelimited("%s: failed to map tx DMA buffer.\n", dev->name);
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
 	}
 
+	spin_lock_irqsave(&lp->lock, flags);
+
+	entry = lp->next_tx;
+
 	sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0);       /* clear status */
 	sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1);   /* single fragment */
 	sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */
@@ -235,10 +264,6 @@
 	sonic_tda_put(dev, entry, SONIC_TD_LINK,
 		sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL);
 
-	/*
-	 * Must set tx_skb[entry] only after clearing status, and
-	 * before clearing EOL and before stopping queue
-	 */
 	wmb();
 	lp->tx_len[entry] = length;
 	lp->tx_laddr[entry] = laddr;
@@ -263,6 +288,8 @@
 
 	SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
 
+	spin_unlock_irqrestore(&lp->lock, flags);
+
 	return NETDEV_TX_OK;
 }
 
@@ -275,9 +302,21 @@
 	struct net_device *dev = dev_id;
 	struct sonic_local *lp = netdev_priv(dev);
 	int status;
+	unsigned long flags;
+
+	/* The lock has two purposes. Firstly, it synchronizes sonic_interrupt()
+	 * with sonic_send_packet() so that the two functions can share state.
+	 * Secondly, it makes sonic_interrupt() re-entrant, as that is required
+	 * by macsonic which must use two IRQs with different priority levels.
+	 */
+	spin_lock_irqsave(&lp->lock, flags);
+
+	status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT;
+	if (!status) {
+		spin_unlock_irqrestore(&lp->lock, flags);
 
-	if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT))
 		return IRQ_NONE;
+	}
 
 	do {
 		if (status & SONIC_INT_PKTRX) {
@@ -292,11 +331,12 @@
 			int td_status;
 			int freed_some = 0;
 
-			/* At this point, cur_tx is the index of a TD that is one of:
-			 *   unallocated/freed                          (status set   & tx_skb[entry] clear)
-			 *   allocated and sent                         (status set   & tx_skb[entry] set  )
-			 *   allocated and not yet sent                 (status clear & tx_skb[entry] set  )
-			 *   still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear)
+			/* The state of a Transmit Descriptor may be inferred
+			 * from { tx_skb[entry], td_status } as follows.
+			 * { clear, clear } => the TD has never been used
+			 * { set,   clear } => the TD was handed to SONIC
+			 * { set,   set   } => the TD was handed back
+			 * { clear, set   } => the TD is available for re-use
 			 */
 
 			if (sonic_debug > 2)
@@ -398,10 +438,30 @@
 		/* load CAM done */
 		if (status & SONIC_INT_LCD)
 			SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */
-	} while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT));
+
+		status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT;
+	} while (status);
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+
 	return IRQ_HANDLED;
 }
 
+/* Return the array index corresponding to a given Receive Buffer pointer. */
+static int index_from_addr(struct sonic_local *lp, dma_addr_t addr,
+			   unsigned int last)
+{
+	unsigned int i = last;
+
+	do {
+		i = (i + 1) & SONIC_RRS_MASK;
+		if (addr == lp->rx_laddr[i])
+			return i;
+	} while (i != last);
+
+	return -ENOENT;
+}
+
 /*
  * We have a good packet(s), pass it/them up the network stack.
  */
@@ -421,6 +481,16 @@
 
 		status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
 		if (status & SONIC_RCR_PRX) {
+			u32 addr = (sonic_rda_get(dev, entry,
+						  SONIC_RD_PKTPTR_H) << 16) |
+				   sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L);
+			int i = index_from_addr(lp, addr, entry);
+
+			if (i < 0) {
+				WARN_ONCE(1, "failed to find buffer!\n");
+				break;
+			}
+
 			/* Malloc up new buffer. */
 			new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
 			if (new_skb == NULL) {
@@ -442,7 +512,7 @@
 
 			/* now we have a new skb to replace it, pass the used one up the stack */
 			dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE);
-			used_skb = lp->rx_skb[entry];
+			used_skb = lp->rx_skb[i];
 			pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN);
 			skb_trim(used_skb, pkt_len);
 			used_skb->protocol = eth_type_trans(used_skb, dev);
@@ -451,13 +521,13 @@
 			lp->stats.rx_bytes += pkt_len;
 
 			/* and insert the new skb */
-			lp->rx_laddr[entry] = new_laddr;
-			lp->rx_skb[entry] = new_skb;
+			lp->rx_laddr[i] = new_laddr;
+			lp->rx_skb[i] = new_skb;
 
 			bufadr_l = (unsigned long)new_laddr & 0xffff;
 			bufadr_h = (unsigned long)new_laddr >> 16;
-			sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l);
-			sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h);
+			sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
+			sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
 		} else {
 			/* This should only happen, if we enable accepting broken packets. */
 			lp->stats.rx_errors++;
@@ -592,6 +662,7 @@
 	 */
 	SONIC_WRITE(SONIC_CMD, 0);
 	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
+	sonic_quiesce(dev, SONIC_CR_ALL);
 
 	/*
 	 * initialize the receive resource area
--- linux-4.4.0.orig/drivers/net/ethernet/natsemi/sonic.h
+++ linux-4.4.0/drivers/net/ethernet/natsemi/sonic.h
@@ -109,6 +109,9 @@
 #define SONIC_CR_TXP            0x0002
 #define SONIC_CR_HTX            0x0001
 
+#define SONIC_CR_ALL (SONIC_CR_LCAM | SONIC_CR_RRRA | \
+		      SONIC_CR_RXEN | SONIC_CR_TXP)
+
 /*
  * SONIC data configuration bits
  */
@@ -273,8 +276,9 @@
 #define SONIC_NUM_RDS   SONIC_NUM_RRS /* number of receive descriptors */
 #define SONIC_NUM_TDS   16            /* number of transmit descriptors */
 
-#define SONIC_RDS_MASK  (SONIC_NUM_RDS-1)
-#define SONIC_TDS_MASK  (SONIC_NUM_TDS-1)
+#define SONIC_RRS_MASK  (SONIC_NUM_RRS - 1)
+#define SONIC_RDS_MASK  (SONIC_NUM_RDS - 1)
+#define SONIC_TDS_MASK  (SONIC_NUM_TDS - 1)
 
 #define SONIC_RBSIZE	1520          /* size of one resource buffer */
 
@@ -320,6 +324,7 @@
 	unsigned int next_tx;          /* next free TD */
 	struct device *device;         /* generic device */
 	struct net_device_stats stats;
+	spinlock_t lock;
 };
 
 #define TX_TIMEOUT (3 * HZ)
@@ -341,30 +346,30 @@
    as far as we can tell. */
 /* OpenBSD calls this "SWO".  I'd like to think that sonic_buf_put()
    is a much better name. */
-static inline void sonic_buf_put(void* base, int bitmode,
+static inline void sonic_buf_put(u16 *base, int bitmode,
 				 int offset, __u16 val)
 {
 	if (bitmode)
 #ifdef __BIG_ENDIAN
-		((__u16 *) base + (offset*2))[1] = val;
+		__raw_writew(val, base + (offset * 2) + 1);
 #else
-		((__u16 *) base + (offset*2))[0] = val;
+		__raw_writew(val, base + (offset * 2) + 0);
 #endif
 	else
-	 	((__u16 *) base)[offset] = val;
+		__raw_writew(val, base + (offset * 1) + 0);
 }
 
-static inline __u16 sonic_buf_get(void* base, int bitmode,
+static inline __u16 sonic_buf_get(u16 *base, int bitmode,
 				  int offset)
 {
 	if (bitmode)
 #ifdef __BIG_ENDIAN
-		return ((volatile __u16 *) base + (offset*2))[1];
+		return __raw_readw(base + (offset * 2) + 1);
 #else
-		return ((volatile __u16 *) base + (offset*2))[0];
+		return __raw_readw(base + (offset * 2) + 0);
 #endif
 	else
-		return ((volatile __u16 *) base)[offset];
+		return __raw_readw(base + (offset * 1) + 0);
 }
 
 /* Inlines that you should actually use for reading/writing DMA buffers */
--- linux-4.4.0.orig/drivers/net/ethernet/neterion/vxge/vxge-config.h
+++ linux-4.4.0/drivers/net/ethernet/neterion/vxge/vxge-config.h
@@ -2065,7 +2065,7 @@
 	if ((level >= VXGE_ERR && VXGE_COMPONENT_LL & VXGE_DEBUG_ERR_MASK) ||  \
 	    (level >= VXGE_TRACE && VXGE_COMPONENT_LL & VXGE_DEBUG_TRACE_MASK))\
 		if ((mask & VXGE_DEBUG_MASK) == mask)			       \
-			printk(fmt "\n", __VA_ARGS__);			       \
+			printk(fmt "\n", ##__VA_ARGS__);		       \
 } while (0)
 #else
 #define vxge_debug_ll(level, mask, fmt, ...)
--- linux-4.4.0.orig/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ linux-4.4.0/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -2223,8 +2223,6 @@
 	return IRQ_NONE;
 }
 
-#ifdef CONFIG_PCI_MSI
-
 static irqreturn_t vxge_tx_msix_handle(int irq, void *dev_id)
 {
 	struct vxge_fifo *fifo = (struct vxge_fifo *)dev_id;
@@ -2442,16 +2440,13 @@
 	if (vdev->config.intr_type == MSI_X)
 		pci_disable_msix(vdev->pdev);
 }
-#endif
 
 static void vxge_rem_isr(struct vxgedev *vdev)
 {
-#ifdef CONFIG_PCI_MSI
-	if (vdev->config.intr_type == MSI_X) {
+	if (IS_ENABLED(CONFIG_PCI_MSI) &&
+	    vdev->config.intr_type == MSI_X) {
 		vxge_rem_msix_isr(vdev);
-	} else
-#endif
-	if (vdev->config.intr_type == INTA) {
+	} else if (vdev->config.intr_type == INTA) {
 			synchronize_irq(vdev->pdev->irq);
 			free_irq(vdev->pdev->irq, vdev);
 	}
@@ -2460,11 +2455,10 @@
 static int vxge_add_isr(struct vxgedev *vdev)
 {
 	int ret = 0;
-#ifdef CONFIG_PCI_MSI
 	int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0;
 	int pci_fun = PCI_FUNC(vdev->pdev->devfn);
 
-	if (vdev->config.intr_type == MSI_X)
+	if (IS_ENABLED(CONFIG_PCI_MSI) && vdev->config.intr_type == MSI_X)
 		ret = vxge_enable_msix(vdev);
 
 	if (ret) {
@@ -2475,7 +2469,7 @@
 		vdev->config.intr_type = INTA;
 	}
 
-	if (vdev->config.intr_type == MSI_X) {
+	if (IS_ENABLED(CONFIG_PCI_MSI) && vdev->config.intr_type == MSI_X) {
 		for (intr_idx = 0;
 		     intr_idx < (vdev->no_of_vpath *
 			VXGE_HW_VPATH_MSIX_ACTIVE); intr_idx++) {
@@ -2576,9 +2570,8 @@
 		vdev->vxge_entries[intr_cnt].in_use = 1;
 		vdev->vxge_entries[intr_cnt].arg = &vdev->vpaths[0];
 	}
-INTA_MODE:
-#endif
 
+INTA_MODE:
 	if (vdev->config.intr_type == INTA) {
 		snprintf(vdev->desc[0], VXGE_INTR_STRLEN,
 			"%s:vxge:INTA", vdev->ndev->name);
@@ -3889,12 +3882,12 @@
 	if (max_mac_vpath > VXGE_MAX_MAC_ADDR_COUNT)
 		max_mac_vpath = VXGE_MAX_MAC_ADDR_COUNT;
 
-#ifndef CONFIG_PCI_MSI
-	vxge_debug_init(VXGE_ERR,
-		"%s: This Kernel does not support "
-		"MSI-X. Defaulting to INTA", VXGE_DRIVER_NAME);
-	*intr_type = INTA;
-#endif
+	if (!IS_ENABLED(CONFIG_PCI_MSI)) {
+		vxge_debug_init(VXGE_ERR,
+			"%s: This Kernel does not support "
+			"MSI-X. Defaulting to INTA", VXGE_DRIVER_NAME);
+		*intr_type = INTA;
+	}
 
 	/* Configure whether MSI-X or IRQL. */
 	switch (*intr_type) {
@@ -4219,6 +4212,9 @@
 	return ret;
 }
 
+#define VXGE_PXE_FIRMWARE "vxge/X3fw-pxe.ncf"
+#define VXGE_FIRMWARE "vxge/X3fw.ncf"
+
 static int vxge_probe_fw_update(struct vxgedev *vdev)
 {
 	u32 maj, min, bld;
@@ -4261,9 +4257,9 @@
 			}
 	}
 	if (gpxe)
-		fw_name = "vxge/X3fw-pxe.ncf";
+		fw_name = VXGE_PXE_FIRMWARE;
 	else
-		fw_name = "vxge/X3fw.ncf";
+		fw_name = VXGE_FIRMWARE;
 
 	ret = vxge_fw_upgrade(vdev, fw_name, 0);
 	/* -EINVAL and -ENOENT are not fatal errors for flashing firmware on
@@ -4868,3 +4864,5 @@
 }
 module_init(vxge_starter);
 module_exit(vxge_closer);
+MODULE_FIRMWARE(VXGE_PXE_FIRMWARE);
+MODULE_FIRMWARE(VXGE_FIRMWARE);
--- linux-4.4.0.orig/drivers/net/ethernet/neterion/vxge/vxge-main.h
+++ linux-4.4.0/drivers/net/ethernet/neterion/vxge/vxge-main.h
@@ -454,49 +454,49 @@
 
 #if (VXGE_DEBUG_LL_CONFIG & VXGE_DEBUG_MASK)
 #define vxge_debug_ll_config(level, fmt, ...) \
-	vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, __VA_ARGS__)
+	vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_ll_config(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_INIT & VXGE_DEBUG_MASK)
 #define vxge_debug_init(level, fmt, ...) \
-	vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, __VA_ARGS__)
+	vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_init(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_TX & VXGE_DEBUG_MASK)
 #define vxge_debug_tx(level, fmt, ...) \
-	vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, __VA_ARGS__)
+	vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_tx(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_RX & VXGE_DEBUG_MASK)
 #define vxge_debug_rx(level, fmt, ...) \
-	vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, __VA_ARGS__)
+	vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_rx(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_MEM & VXGE_DEBUG_MASK)
 #define vxge_debug_mem(level, fmt, ...) \
-	vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, __VA_ARGS__)
+	vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_mem(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)
 #define vxge_debug_entryexit(level, fmt, ...) \
-	vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, __VA_ARGS__)
+	vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_entryexit(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_INTR & VXGE_DEBUG_MASK)
 #define vxge_debug_intr(level, fmt, ...) \
-	vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, __VA_ARGS__)
+	vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_intr(level, fmt, ...)
 #endif
--- linux-4.4.0.orig/drivers/net/ethernet/nxp/lpc_eth.c
+++ linux-4.4.0/drivers/net/ethernet/nxp/lpc_eth.c
@@ -865,7 +865,8 @@
 	if (mdiobus_register(pldat->mii_bus))
 		goto err_out_free_mdio_irq;
 
-	if (lpc_mii_probe(pldat->ndev) != 0)
+	err = lpc_mii_probe(pldat->ndev);
+	if (err)
 		goto err_out_unregister_bus;
 
 	return 0;
@@ -1417,13 +1418,14 @@
 	pldat->dma_buff_base_p = dma_handle;
 
 	netdev_dbg(ndev, "IO address space     :%pR\n", res);
-	netdev_dbg(ndev, "IO address size      :%d\n", resource_size(res));
+	netdev_dbg(ndev, "IO address size      :%zd\n",
+			(size_t)resource_size(res));
 	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);
-	netdev_dbg(ndev, "DMA buffer P address :0x%08x\n",
-			pldat->dma_buff_base_p);
+	netdev_dbg(ndev, "DMA buffer size      :%zd\n", pldat->dma_buff_size);
+	netdev_dbg(ndev, "DMA buffer P address :%pad\n",
+			&pldat->dma_buff_base_p);
 	netdev_dbg(ndev, "DMA buffer V address :0x%p\n",
 			pldat->dma_buff_base_v);
 
@@ -1470,8 +1472,8 @@
 	if (ret)
 		goto err_out_unregister_netdev;
 
-	netdev_info(ndev, "LPC mac at 0x%08x irq %d\n",
-	       res->start, ndev->irq);
+	netdev_info(ndev, "LPC mac at 0x%08lx irq %d\n",
+	       (unsigned long)res->start, ndev->irq);
 
 	phydev = pldat->phy_dev;
 
--- linux-4.4.0.orig/drivers/net/ethernet/pasemi/pasemi_mac.c
+++ linux-4.4.0/drivers/net/ethernet/pasemi/pasemi_mac.c
@@ -1091,7 +1091,6 @@
 
 	dn = pci_device_to_OF_node(mac->pdev);
 	phy_dn = of_parse_phandle(dn, "phy-handle", 0);
-	of_node_put(phy_dn);
 
 	mac->link = 0;
 	mac->speed = 0;
@@ -1100,6 +1099,7 @@
 	phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0,
 				PHY_INTERFACE_MODE_SGMII);
 
+	of_node_put(phy_dn);
 	if (!phydev) {
 		printk(KERN_ERR "%s: Could not attach to phy\n", dev->name);
 		return -ENODEV;
@@ -1129,16 +1129,20 @@
 
 	mac->tx = pasemi_mac_setup_tx_resources(dev);
 
-	if (!mac->tx)
+	if (!mac->tx) {
+		ret = -ENOMEM;
 		goto out_tx_ring;
+	}
 
 	/* We might already have allocated rings in case mtu was changed
 	 * before interface was brought up.
 	 */
 	if (dev->mtu > 1500 && !mac->num_cs) {
 		pasemi_mac_setup_csrings(mac);
-		if (!mac->num_cs)
+		if (!mac->num_cs) {
+			ret = -ENOMEM;
 			goto out_tx_ring;
+		}
 	}
 
 	/* Zero out rmon counters */
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
@@ -247,7 +247,7 @@
 	cmd.req.arg3 = 0;
 
 	if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE)
-		netxen_issue_cmd(adapter, &cmd);
+		rcode = netxen_issue_cmd(adapter, &cmd);
 
 	if (rcode != NX_RCODE_SUCCESS)
 		return -EIO;
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -586,11 +586,6 @@
 #endif
 };
 
-static inline bool netxen_function_zero(struct pci_dev *pdev)
-{
-	return (PCI_FUNC(pdev->devfn) == 0) ? true : false;
-}
-
 static inline void netxen_set_interrupt_mode(struct netxen_adapter *adapter,
 					     u32 mode)
 {
@@ -686,7 +681,7 @@
 	netxen_initialize_interrupt_registers(adapter);
 	netxen_set_msix_bit(pdev, 0);
 
-	if (netxen_function_zero(pdev)) {
+	if (adapter->portnum == 0) {
 		if (!netxen_setup_msi_interrupts(adapter, num_msix))
 			netxen_set_interrupt_mode(adapter, NETXEN_MSI_MODE);
 		else
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -43,7 +43,7 @@
 #define ILT_CFG_REG(cli, reg)	PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET
 
 /* ILT entry structure */
-#define ILT_ENTRY_PHY_ADDR_MASK		0x000FFFFFFFFFFFULL
+#define ILT_ENTRY_PHY_ADDR_MASK		(~0ULL >> 12)
 #define ILT_ENTRY_PHY_ADDR_SHIFT	0
 #define ILT_ENTRY_VALID_MASK		0x1ULL
 #define ILT_ENTRY_VALID_SHIFT		52
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_int.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qed/qed_int.c
@@ -177,6 +177,8 @@
 	 */
 	do {
 		index = p_sb_attn->sb_index;
+		/* finish reading index before the loop condition */
+		dma_rmb();
 		attn_bits = le32_to_cpu(p_sb_attn->atten_bits);
 		attn_acks = le32_to_cpu(p_sb_attn->atten_ack);
 	} while (index != p_sb_attn->sb_index);
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -22,6 +22,7 @@
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/qed/qed_if.h>
+#include <linux/crash_dump.h>
 
 #include "qed.h"
 #include "qed_sp.h"
@@ -45,6 +46,8 @@
 #define QED_FW_FILE_NAME	\
 	"qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin"
 
+MODULE_FIRMWARE(QED_FW_FILE_NAME);
+
 static int __init qed_init(void)
 {
 	pr_notice("qed_init called\n");
@@ -460,8 +463,16 @@
 		/* Fastpath interrupts */
 		for (j = 0; j < 64; j++) {
 			if ((0x2ULL << j) & status) {
-				hwfn->simd_proto_handler[j].func(
-					hwfn->simd_proto_handler[j].token);
+				struct qed_simd_fp_handler *p_handler =
+					&hwfn->simd_proto_handler[j];
+
+				if (p_handler->func)
+					p_handler->func(p_handler->token);
+				else
+					DP_NOTICE(hwfn,
+						  "Not calling fastpath handler as it is NULL [handler #%d, status 0x%llx]\n",
+						  j, status);
+
 				status &= ~(0x2ULL << j);
 				rc = IRQ_HANDLED;
 			}
@@ -634,6 +645,14 @@
 	/* We want a minimum of one slowpath and one fastpath vector per hwfn */
 	cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2;
 
+	if (is_kdump_kernel()) {
+		DP_INFO(cdev,
+			"Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n",
+			cdev->int_params.in.min_msix_cnt);
+		cdev->int_params.in.num_vectors =
+			cdev->int_params.in.min_msix_cnt;
+	}
+
 	rc = qed_set_int_mode(cdev, false);
 	if (rc)  {
 		DP_ERR(cdev, "qed_slowpath_setup_int ERR\n");
@@ -1107,9 +1126,9 @@
 			return -EBUSY;
 		}
 		rc = qed_mcp_drain(hwfn, ptt);
+		qed_ptt_release(hwfn, ptt);
 		if (rc)
 			return rc;
-		qed_ptt_release(hwfn, ptt);
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -420,6 +420,7 @@
 		break;
 	default:
 		p_link->speed = 0;
+		p_link->link_up = 0;
 	}
 
 	/* Correct speed according to bandwidth allocation */
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_spq.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qed/qed_spq.c
@@ -794,13 +794,12 @@
 			 * in a bitmap and increasing the chain consumer only
 			 * for the first successive completed entries.
 			 */
-			bitmap_set(p_spq->p_comp_bitmap, pos, SPQ_RING_SIZE);
+			__set_bit(pos, p_spq->p_comp_bitmap);
 
 			while (test_bit(p_spq->comp_bitmap_idx,
 					p_spq->p_comp_bitmap)) {
-				bitmap_clear(p_spq->p_comp_bitmap,
-					     p_spq->comp_bitmap_idx,
-					     SPQ_RING_SIZE);
+				__clear_bit(p_spq->comp_bitmap_idx,
+					    p_spq->p_comp_bitmap);
 				p_spq->comp_bitmap_idx++;
 				qed_chain_return_produced(&p_spq->chain);
 			}
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -400,7 +400,7 @@
 	u8 xmit_type;
 	u16 idx;
 	u16 hlen;
-	bool data_split;
+	bool data_split = false;
 
 	/* Get tx-queue context and netdev index */
 	txq_index = skb_get_queue_mapping(skb);
@@ -1465,8 +1465,16 @@
 static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
-	struct qede_dev *edev = netdev_priv(ndev);
-	struct qed_dev *cdev = edev->cdev;
+	struct qede_dev *edev;
+	struct qed_dev *cdev;
+
+	if (!ndev) {
+		dev_info(&pdev->dev, "Device has already been removed\n");
+		return;
+	}
+
+	edev = netdev_priv(ndev);
+	cdev = edev->cdev;
 
 	DP_INFO(edev, "Starting qede_remove\n");
 
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qla3xxx.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -380,8 +380,6 @@
 
 	qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;
 	ql_write_nvram_reg(qdev, spir, ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
-	ql_write_nvram_reg(qdev, spir,
-			   ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
 }
 
 /*
@@ -2754,6 +2752,9 @@
 	int err;
 
 	for (i = 0; i < qdev->num_large_buffers; i++) {
+		lrg_buf_cb = &qdev->lrg_buf[i];
+		memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
+
 		skb = netdev_alloc_skb(qdev->ndev,
 				       qdev->lrg_buffer_len);
 		if (unlikely(!skb)) {
@@ -2764,11 +2765,7 @@
 			ql_free_large_buffers(qdev);
 			return -ENOMEM;
 		} else {
-
-			lrg_buf_cb = &qdev->lrg_buf[i];
-			memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
 			lrg_buf_cb->index = i;
-			lrg_buf_cb->skb = skb;
 			/*
 			 * We save some space to copy the ethhdr from first
 			 * buffer
@@ -2785,10 +2782,12 @@
 				netdev_err(qdev->ndev,
 					   "PCI mapping failed with error: %d\n",
 					   err);
+				dev_kfree_skb_irq(skb);
 				ql_free_large_buffers(qdev);
 				return -ENOMEM;
 			}
 
+			lrg_buf_cb->skb = skb;
 			dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
 			dma_unmap_len_set(lrg_buf_cb, maplen,
 					  qdev->lrg_buffer_len -
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -566,6 +566,7 @@
 	u64  tx_dma_map_error;
 	u64  spurious_intr;
 	u64  mac_filter_limit_overrun;
+	u64  mbx_spurious_intr;
 };
 
 /*
@@ -1099,7 +1100,7 @@
 	unsigned long		status;
 	spinlock_t		queue_lock;	/* Mailbox queue lock */
 	spinlock_t		aen_lock;	/* Mailbox response/AEN lock */
-	atomic_t		rsp_status;
+	u32			rsp_status;
 	u32			num_cmds;
 };
 
@@ -1801,7 +1802,8 @@
 	int (*config_loopback) (struct qlcnic_adapter *, u8);
 	int (*clear_loopback) (struct qlcnic_adapter *, u8);
 	int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
-	void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16);
+	void (*change_l2_filter)(struct qlcnic_adapter *adapter, u64 *addr,
+				 u16 vlan, struct qlcnic_host_tx_ring *tx_ring);
 	int (*get_board_info) (struct qlcnic_adapter *);
 	void (*set_mac_filter_count) (struct qlcnic_adapter *);
 	void (*free_mac_list) (struct qlcnic_adapter *);
@@ -2043,9 +2045,10 @@
 }
 
 static inline void qlcnic_change_filter(struct qlcnic_adapter *adapter,
-					u64 *addr, u16 id)
+					u64 *addr, u16 vlan,
+					struct qlcnic_host_tx_ring *tx_ring)
 {
-	adapter->ahw->hw_ops->change_l2_filter(adapter, addr, id);
+	adapter->ahw->hw_ops->change_l2_filter(adapter, addr, vlan, tx_ring);
 }
 
 static inline int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -491,7 +491,7 @@
 
 static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx)
 {
-	atomic_set(&mbx->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED);
+	mbx->rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
 	complete(&mbx->completion);
 }
 
@@ -510,7 +510,7 @@
 	if (event &  QLCNIC_MBX_ASYNC_EVENT) {
 		__qlcnic_83xx_process_aen(adapter);
 	} else {
-		if (atomic_read(&mbx->rsp_status) != rsp_status)
+		if (mbx->rsp_status != rsp_status)
 			qlcnic_83xx_notify_mbx_response(mbx);
 	}
 out:
@@ -1023,7 +1023,7 @@
 		if (event &  QLCNIC_MBX_ASYNC_EVENT) {
 			__qlcnic_83xx_process_aen(adapter);
 		} else {
-			if (atomic_read(&mbx->rsp_status) != rsp_status)
+			if (mbx->rsp_status != rsp_status)
 				qlcnic_83xx_notify_mbx_response(mbx);
 		}
 	}
@@ -1076,8 +1076,14 @@
 	sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
 	context_id = recv_ctx->context_id;
 	num_sds = adapter->drv_sds_rings - QLCNIC_MAX_SDS_RINGS;
-	ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
-				    QLCNIC_CMD_ADD_RCV_RINGS);
+	err = ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+					QLCNIC_CMD_ADD_RCV_RINGS);
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to alloc mbx args %d\n", err);
+		return err;
+	}
+
 	cmd.req.arg[1] = 0 | (num_sds << 8) | (context_id << 16);
 
 	/* set up status rings, mbx 2-81 */
@@ -2132,7 +2138,8 @@
 }
 
 void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
-				  u16 vlan_id)
+				  u16 vlan_id,
+				  struct qlcnic_host_tx_ring *tx_ring)
 {
 	u8 mac[ETH_ALEN];
 	memcpy(&mac, addr, ETH_ALEN);
@@ -2338,9 +2345,9 @@
 
 static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
 {
+	u32 mask, resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
 	struct qlcnic_adapter *adapter = data;
 	struct qlcnic_mailbox *mbx;
-	u32 mask, resp, event;
 	unsigned long flags;
 
 	mbx = adapter->ahw->mailbox;
@@ -2350,10 +2357,14 @@
 		goto out;
 
 	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
-	if (event &  QLCNIC_MBX_ASYNC_EVENT)
+	if (event &  QLCNIC_MBX_ASYNC_EVENT) {
 		__qlcnic_83xx_process_aen(adapter);
-	else
-		qlcnic_83xx_notify_mbx_response(mbx);
+	} else {
+		if (mbx->rsp_status != rsp_status)
+			qlcnic_83xx_notify_mbx_response(mbx);
+		else
+			adapter->stats.mbx_spurious_intr++;
+	}
 
 out:
 	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
@@ -3604,7 +3615,7 @@
 	ahw->diag_cnt = 0;
 	ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
 	if (ret)
-		goto fail_diag_irq;
+		goto fail_mbx_args;
 
 	if (adapter->flags & QLCNIC_MSIX_ENABLED)
 		intrpt_id = ahw->intr_tbl[0].id;
@@ -3634,6 +3645,8 @@
 
 done:
 	qlcnic_free_mbx_args(&cmd);
+
+fail_mbx_args:
 	qlcnic_83xx_diag_free_res(netdev, drv_sds_rings);
 
 fail_diag_irq:
@@ -3846,7 +3859,7 @@
 	struct list_head *head = &mbx->cmd_q;
 	struct qlcnic_cmd_args *cmd = NULL;
 
-	spin_lock(&mbx->queue_lock);
+	spin_lock_bh(&mbx->queue_lock);
 
 	while (!list_empty(head)) {
 		cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
@@ -3857,7 +3870,7 @@
 		qlcnic_83xx_notify_cmd_completion(adapter, cmd);
 	}
 
-	spin_unlock(&mbx->queue_lock);
+	spin_unlock_bh(&mbx->queue_lock);
 }
 
 static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter)
@@ -3893,12 +3906,12 @@
 {
 	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 
-	spin_lock(&mbx->queue_lock);
+	spin_lock_bh(&mbx->queue_lock);
 
 	list_del(&cmd->list);
 	mbx->num_cmds--;
 
-	spin_unlock(&mbx->queue_lock);
+	spin_unlock_bh(&mbx->queue_lock);
 
 	qlcnic_83xx_notify_cmd_completion(adapter, cmd);
 }
@@ -3963,7 +3976,7 @@
 		init_completion(&cmd->completion);
 		cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN;
 
-		spin_lock(&mbx->queue_lock);
+		spin_lock_bh(&mbx->queue_lock);
 
 		list_add_tail(&cmd->list, &mbx->cmd_q);
 		mbx->num_cmds++;
@@ -3971,7 +3984,7 @@
 		*timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT;
 		queue_work(mbx->work_q, &mbx->work);
 
-		spin_unlock(&mbx->queue_lock);
+		spin_unlock_bh(&mbx->queue_lock);
 
 		return 0;
 	}
@@ -4050,10 +4063,10 @@
 	struct qlcnic_adapter *adapter = mbx->adapter;
 	const struct qlcnic_mbx_ops *mbx_ops = mbx->ops;
 	struct device *dev = &adapter->pdev->dev;
-	atomic_t *rsp_status = &mbx->rsp_status;
 	struct list_head *head = &mbx->cmd_q;
 	struct qlcnic_hardware_context *ahw;
 	struct qlcnic_cmd_args *cmd = NULL;
+	unsigned long flags;
 
 	ahw = adapter->ahw;
 
@@ -4063,17 +4076,19 @@
 			return;
 		}
 
-		atomic_set(rsp_status, QLC_83XX_MBX_RESPONSE_WAIT);
+		spin_lock_irqsave(&mbx->aen_lock, flags);
+		mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;
+		spin_unlock_irqrestore(&mbx->aen_lock, flags);
 
-		spin_lock(&mbx->queue_lock);
+		spin_lock_bh(&mbx->queue_lock);
 
 		if (list_empty(head)) {
-			spin_unlock(&mbx->queue_lock);
+			spin_unlock_bh(&mbx->queue_lock);
 			return;
 		}
 		cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
 
-		spin_unlock(&mbx->queue_lock);
+		spin_unlock_bh(&mbx->queue_lock);
 
 		mbx_ops->encode_cmd(adapter, cmd);
 		mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST);
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -550,7 +550,8 @@
 int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
 int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int);
 int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int);
-void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, u16);
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
+				  u16 vlan, struct qlcnic_host_tx_ring *ring);
 int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *);
 int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
 void qlcnic_83xx_initialize_nic(struct qlcnic_adapter *, int);
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -1724,7 +1724,7 @@
 
 	ahw->reset.seq_error = 0;
 	ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
-	if (p_dev->ahw->reset.buff == NULL)
+	if (ahw->reset.buff == NULL)
 		return -ENOMEM;
 
 	p_buff = p_dev->ahw->reset.buff;
@@ -2047,6 +2047,7 @@
 			break;
 		}
 		entry += p_hdr->size;
+		cond_resched();
 	}
 	p_dev->ahw->reset.seq_index = index;
 }
@@ -2254,7 +2255,8 @@
 
 	/* Boot either flash image or firmware image from host file system */
 	if (qlcnic_load_fw_file == 1) {
-		if (qlcnic_83xx_load_fw_image_from_host(adapter))
+		err = qlcnic_83xx_load_fw_image_from_host(adapter);
+		if (err)
 			return err;
 	} else {
 		QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
@@ -883,7 +883,7 @@
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
 	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))
-		return 0;
+		return 1;
 
 	switch (capid) {
 	case DCB_CAP_ATTR_PG:
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -59,7 +59,8 @@
 	 QLC_OFF(stats.mac_filter_limit_overrun)},
 	{"spurious intr", QLC_SIZEOF(stats.spurious_intr),
 	 QLC_OFF(stats.spurious_intr)},
-
+	{"mbx spurious intr", QLC_SIZEOF(stats.mbx_spurious_intr),
+	 QLC_OFF(stats.mbx_spurious_intr)},
 };
 
 static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
@@ -1037,6 +1038,8 @@
 
 	for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
 		skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
+		if (!skb)
+			break;
 		qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
 		skb_put(skb, QLCNIC_ILB_PKT_SIZE);
 		adapter->ahw->diag_cnt = 0;
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -341,7 +341,7 @@
 			}
 			return -EIO;
 		}
-		usleep_range(1000, 1500);
+		udelay(1200);
 	}
 
 	if (id_reg)
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -173,7 +173,8 @@
 			 struct net_device *netdev);
 void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *);
 void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter,
-			       u64 *uaddr, u16 vlan_id);
+			       u64 *uaddr, u16 vlan_id,
+			       struct qlcnic_host_tx_ring *tx_ring);
 int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *,
 				     struct ethtool_coalesce *);
 int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *);
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -269,13 +269,12 @@
 }
 
 void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
-			       u16 vlan_id)
+			       u16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
 {
 	struct cmd_desc_type0 *hwdesc;
 	struct qlcnic_nic_req *req;
 	struct qlcnic_mac_req *mac_req;
 	struct qlcnic_vlan_req *vlan_req;
-	struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 	u32 producer;
 	u64 word;
 
@@ -302,7 +301,8 @@
 
 static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
 			       struct cmd_desc_type0 *first_desc,
-			       struct sk_buff *skb)
+			       struct sk_buff *skb,
+			       struct qlcnic_host_tx_ring *tx_ring)
 {
 	struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data);
 	struct ethhdr *phdr = (struct ethhdr *)(skb->data);
@@ -336,7 +336,7 @@
 		    tmp_fil->vlan_id == vlan_id) {
 			if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
 				qlcnic_change_filter(adapter, &src_addr,
-						     vlan_id);
+						     vlan_id, tx_ring);
 			tmp_fil->ftime = jiffies;
 			return;
 		}
@@ -351,7 +351,7 @@
 	if (!fil)
 		return;
 
-	qlcnic_change_filter(adapter, &src_addr, vlan_id);
+	qlcnic_change_filter(adapter, &src_addr, vlan_id, tx_ring);
 	fil->ftime = jiffies;
 	fil->vlan_id = vlan_id;
 	memcpy(fil->faddr, &src_addr, ETH_ALEN);
@@ -767,7 +767,7 @@
 	}
 
 	if (adapter->drv_mac_learn)
-		qlcnic_send_filter(adapter, first_desc, skb);
+		qlcnic_send_filter(adapter, first_desc, skb, tx_ring);
 
 	tx_ring->tx_stats.tx_bytes += skb->len;
 	tx_ring->tx_stats.xmit_called++;
@@ -2220,7 +2220,7 @@
 	if (!opcode)
 		return;
 
-	ring = QLCNIC_FETCH_RING_ID(qlcnic_83xx_hndl(sts_data[0]));
+	ring = QLCNIC_FETCH_RING_ID(sts_data[0]);
 	qlcnic_83xx_process_rcv_diag(adapter, ring, sts_data);
 	desc = &sds_ring->desc_head[consumer];
 	desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -2506,6 +2506,7 @@
 		qlcnic_sriov_vf_register_map(ahw);
 		break;
 	default:
+		err = -EINVAL;
 		goto err_out_free_hw_res;
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -703,6 +703,7 @@
 		addr += 16;
 		reg_read -= 16;
 		ret += 16;
+		cond_resched();
 	}
 out:
 	mutex_unlock(&adapter->ahw->mem_lock);
@@ -1383,6 +1384,7 @@
 		buf_offset += entry->hdr.cap_size;
 		entry_offset += entry->hdr.offset;
 		buffer = fw_dump->data + buf_offset;
+		cond_resched();
 	}
 
 	fw_dump->clr = 1;
@@ -1417,6 +1419,7 @@
 	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
 	struct pci_dev *pdev = adapter->pdev;
 	bool extended = false;
+	int ret;
 
 	prev_version = adapter->fw_version;
 	current_version = qlcnic_83xx_get_fw_version(adapter);
@@ -1427,8 +1430,11 @@
 		if (qlcnic_83xx_md_check_extended_dump_capability(adapter))
 			extended = !qlcnic_83xx_extend_md_capab(adapter);
 
-		if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
-			dev_info(&pdev->dev, "Supports FW dump capability\n");
+		ret = qlcnic_fw_cmd_get_minidump_temp(adapter);
+		if (ret)
+			return;
+
+		dev_info(&pdev->dev, "Supports FW dump capability\n");
 
 		/* Once we have minidump template with extended iSCSI dump
 		 * capability, update the minidump capture mask to 0x1f as
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -127,6 +127,8 @@
 		return 0;
 
 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+	if (!pos)
+		return 0;
 	pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
 	pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
 
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -1128,6 +1128,8 @@
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 
 	ret = kstrtoul(buf, 16, &data);
+	if (ret)
+		return ret;
 
 	switch (data) {
 	case QLC_83XX_FLASH_SECTOR_ERASE_CMD:
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
@@ -724,7 +724,7 @@
 	seg_hdr->cookie = MPI_COREDUMP_COOKIE;
 	seg_hdr->segNum = seg_number;
 	seg_hdr->segSize = seg_size;
-	memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
+	strncpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
 }
 
 /*
@@ -765,7 +765,7 @@
 		sizeof(struct mpi_coredump_global_header);
 	mpi_coredump->mpi_global_header.imageSize =
 		sizeof(struct ql_mpi_coredump);
-	memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+	strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
 		sizeof(mpi_coredump->mpi_global_header.idString));
 
 	/* Get generic NIC reg dump */
@@ -1255,7 +1255,7 @@
 		sizeof(struct mpi_coredump_global_header);
 	mpi_coredump->mpi_global_header.imageSize =
 		sizeof(struct ql_reg_dump);
-	memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+	strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
 		sizeof(mpi_coredump->mpi_global_header.idString));
 
 
--- linux-4.4.0.orig/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ linux-4.4.0/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -1648,7 +1648,18 @@
 		return;
 	}
 	skb_reserve(new_skb, NET_IP_ALIGN);
+
+	pci_dma_sync_single_for_cpu(qdev->pdev,
+				    dma_unmap_addr(sbq_desc, mapaddr),
+				    dma_unmap_len(sbq_desc, maplen),
+				    PCI_DMA_FROMDEVICE);
+
 	memcpy(skb_put(new_skb, length), skb->data, length);
+
+	pci_dma_sync_single_for_device(qdev->pdev,
+				       dma_unmap_addr(sbq_desc, mapaddr),
+				       dma_unmap_len(sbq_desc, maplen),
+				       PCI_DMA_FROMDEVICE);
 	skb = new_skb;
 
 	/* Frame error, so drop the packet. */
@@ -2377,26 +2388,20 @@
 	return status;
 }
 
-static netdev_features_t qlge_fix_features(struct net_device *ndev,
-	netdev_features_t features)
-{
-	int err;
-
-	/* Update the behavior of vlan accel in the adapter */
-	err = qlge_update_hw_vlan_features(ndev, features);
-	if (err)
-		return err;
-
-	return features;
-}
-
 static int qlge_set_features(struct net_device *ndev,
 	netdev_features_t features)
 {
 	netdev_features_t changed = ndev->features ^ features;
+	int err;
+
+	if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
+		/* Update the behavior of vlan accel in the adapter */
+		err = qlge_update_hw_vlan_features(ndev, features);
+		if (err)
+			return err;
 
-	if (changed & NETIF_F_HW_VLAN_CTAG_RX)
 		qlge_vlan_mode(ndev, features);
+	}
 
 	return 0;
 }
@@ -4709,7 +4714,6 @@
 	.ndo_set_mac_address	= qlge_set_mac_address,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_tx_timeout		= qlge_tx_timeout,
-	.ndo_fix_features	= qlge_fix_features,
 	.ndo_set_features	= qlge_set_features,
 	.ndo_vlan_rx_add_vid	= qlge_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid	= qlge_vlan_rx_kill_vid,
--- linux-4.4.0.orig/drivers/net/ethernet/qualcomm/qca_spi.c
+++ linux-4.4.0/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -296,8 +296,9 @@
 
 	/* Allocate rx SKB if we don't have one available. */
 	if (!qca->rx_skb) {
-		qca->rx_skb = netdev_alloc_skb(net_dev,
-					       net_dev->mtu + VLAN_ETH_HLEN);
+		qca->rx_skb = netdev_alloc_skb_ip_align(net_dev,
+							net_dev->mtu +
+							VLAN_ETH_HLEN);
 		if (!qca->rx_skb) {
 			netdev_dbg(net_dev, "out of RX resources\n");
 			qca->stats.out_of_mem++;
@@ -377,7 +378,7 @@
 					qca->rx_skb, qca->rx_skb->dev);
 				qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
 				netif_rx_ni(qca->rx_skb);
-				qca->rx_skb = netdev_alloc_skb(net_dev,
+				qca->rx_skb = netdev_alloc_skb_ip_align(net_dev,
 					net_dev->mtu + VLAN_ETH_HLEN);
 				if (!qca->rx_skb) {
 					netdev_dbg(net_dev, "out of RX resources\n");
@@ -437,7 +438,6 @@
 	u16 signature = 0;
 	u16 spi_config;
 	u16 wrbuf_space = 0;
-	static u16 reset_count;
 
 	if (event == QCASPI_EVENT_CPUON) {
 		/* Read signature twice, if not valid
@@ -490,13 +490,13 @@
 
 		qca->sync = QCASPI_SYNC_RESET;
 		qca->stats.trig_reset++;
-		reset_count = 0;
+		qca->reset_count = 0;
 		break;
 	case QCASPI_SYNC_RESET:
-		reset_count++;
+		qca->reset_count++;
 		netdev_dbg(qca->net_dev, "sync: waiting for CPU on, count %u.\n",
-			   reset_count);
-		if (reset_count >= QCASPI_RESET_TIMEOUT) {
+			   qca->reset_count);
+		if (qca->reset_count >= QCASPI_RESET_TIMEOUT) {
 			/* reset did not seem to take place, try again */
 			qca->sync = QCASPI_SYNC_UNKNOWN;
 			qca->stats.reset_timeout++;
@@ -634,7 +634,7 @@
 		return ret;
 	}
 
-	netif_start_queue(qca->net_dev);
+	/* SPI thread takes care of TX queue */
 
 	return 0;
 }
@@ -738,6 +738,9 @@
 	qca->net_dev->stats.tx_errors++;
 	/* Trigger tx queue flush and QCA7000 reset */
 	qca->sync = QCASPI_SYNC_UNKNOWN;
+
+	if (qca->spi_thread)
+		wake_up_process(qca->spi_thread);
 }
 
 static int
@@ -759,7 +762,8 @@
 	if (!qca->rx_buffer)
 		return -ENOBUFS;
 
-	qca->rx_skb = netdev_alloc_skb(dev, qca->net_dev->mtu + VLAN_ETH_HLEN);
+	qca->rx_skb = netdev_alloc_skb_ip_align(dev, qca->net_dev->mtu +
+						VLAN_ETH_HLEN);
 	if (!qca->rx_skb) {
 		kfree(qca->rx_buffer);
 		netdev_info(qca->net_dev, "Failed to allocate RX sk_buff.\n");
@@ -811,7 +815,7 @@
 	dev->netdev_ops = &qcaspi_netdev_ops;
 	qcaspi_set_ethtool_ops(dev);
 	dev->watchdog_timeo = QCASPI_TX_TIMEOUT;
-	dev->flags = IFF_MULTICAST;
+	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 	dev->tx_queue_len = 100;
 
 	qca = netdev_priv(dev);
@@ -863,22 +867,22 @@
 
 	if ((qcaspi_clkspeed < QCASPI_CLK_SPEED_MIN) ||
 	    (qcaspi_clkspeed > QCASPI_CLK_SPEED_MAX)) {
-		dev_info(&spi->dev, "Invalid clkspeed: %d\n",
-			 qcaspi_clkspeed);
+		dev_err(&spi->dev, "Invalid clkspeed: %d\n",
+			qcaspi_clkspeed);
 		return -EINVAL;
 	}
 
 	if ((qcaspi_burst_len < QCASPI_BURST_LEN_MIN) ||
 	    (qcaspi_burst_len > QCASPI_BURST_LEN_MAX)) {
-		dev_info(&spi->dev, "Invalid burst len: %d\n",
-			 qcaspi_burst_len);
+		dev_err(&spi->dev, "Invalid burst len: %d\n",
+			qcaspi_burst_len);
 		return -EINVAL;
 	}
 
 	if ((qcaspi_pluggable < QCASPI_PLUGGABLE_MIN) ||
 	    (qcaspi_pluggable > QCASPI_PLUGGABLE_MAX)) {
-		dev_info(&spi->dev, "Invalid pluggable: %d\n",
-			 qcaspi_pluggable);
+		dev_err(&spi->dev, "Invalid pluggable: %d\n",
+			qcaspi_pluggable);
 		return -EINVAL;
 	}
 
@@ -939,8 +943,8 @@
 	}
 
 	if (register_netdev(qcaspi_devs)) {
-		dev_info(&spi->dev, "Unable to register net device %s\n",
-			 qcaspi_devs->name);
+		dev_err(&spi->dev, "Unable to register net device %s\n",
+			qcaspi_devs->name);
 		free_netdev(qcaspi_devs);
 		return -EFAULT;
 	}
--- linux-4.4.0.orig/drivers/net/ethernet/qualcomm/qca_spi.h
+++ linux-4.4.0/drivers/net/ethernet/qualcomm/qca_spi.h
@@ -97,6 +97,7 @@
 
 	unsigned int intr_req;
 	unsigned int intr_svc;
+	u16 reset_count;
 
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *device_root;
--- linux-4.4.0.orig/drivers/net/ethernet/realtek/8139cp.c
+++ linux-4.4.0/drivers/net/ethernet/realtek/8139cp.c
@@ -578,6 +578,7 @@
 	struct cp_private *cp;
 	int handled = 0;
 	u16 status;
+	u16 mask;
 
 	if (unlikely(dev == NULL))
 		return IRQ_NONE;
@@ -585,6 +586,10 @@
 
 	spin_lock(&cp->lock);
 
+	mask = cpr16(IntrMask);
+	if (!mask)
+		goto out_unlock;
+
 	status = cpr16(IntrStatus);
 	if (!status || (status == 0xFFFF))
 		goto out_unlock;
--- linux-4.4.0.orig/drivers/net/ethernet/realtek/8139too.c
+++ linux-4.4.0/drivers/net/ethernet/realtek/8139too.c
@@ -2229,7 +2229,7 @@
 	struct rtl8139_private *tp = netdev_priv(dev);
 	const int irq = tp->pci_dev->irq;
 
-	disable_irq(irq);
+	disable_irq_nosync(irq);
 	rtl8139_interrupt(irq, dev);
 	enable_irq(irq);
 }
--- linux-4.4.0.orig/drivers/net/ethernet/realtek/atp.c
+++ linux-4.4.0/drivers/net/ethernet/realtek/atp.c
@@ -151,8 +151,8 @@
 
 module_param(max_interrupt_work, int, 0);
 module_param(debug, int, 0);
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param_array(xcvr, int, NULL, 0);
 MODULE_PARM_DESC(max_interrupt_work, "ATP maximum events handled per interrupt");
 MODULE_PARM_DESC(debug, "ATP debug level (0-7)");
--- linux-4.4.0.orig/drivers/net/ethernet/realtek/r8169.c
+++ linux-4.4.0/drivers/net/ethernet/realtek/r8169.c
@@ -324,8 +324,11 @@
 };
 
 static const struct pci_device_id rtl8169_pci_tbl[] = {
+	{ PCI_VDEVICE(REALTEK,	0x2502), RTL_CFG_1 },
+	{ PCI_VDEVICE(REALTEK,	0x2600), RTL_CFG_1 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8129), 0, 0, RTL_CFG_0 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8136), 0, 0, RTL_CFG_2 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8161), 0, 0, RTL_CFG_1 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8167), 0, 0, RTL_CFG_0 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8168), 0, 0, RTL_CFG_1 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8169), 0, 0, RTL_CFG_0 },
@@ -758,7 +761,7 @@
 };
 
 enum rtl_flag {
-	RTL_FLAG_TASK_ENABLED,
+	RTL_FLAG_TASK_ENABLED = 0,
 	RTL_FLAG_TASK_SLOW_PENDING,
 	RTL_FLAG_TASK_RESET_PENDING,
 	RTL_FLAG_TASK_PHY_PENDING,
@@ -1386,7 +1389,7 @@
 {
 	void __iomem *ioaddr = tp->mmio_addr;
 
-	return RTL_R8(IBISR0) & 0x02;
+	return RTL_R8(IBISR0) & 0x20;
 }
 
 static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
@@ -1394,7 +1397,7 @@
 	void __iomem *ioaddr = tp->mmio_addr;
 
 	RTL_W8(IBCR2, RTL_R8(IBCR2) & ~0x01);
-	rtl_msleep_loop_wait_low(tp, &rtl_ocp_tx_cond, 50, 2000);
+	rtl_msleep_loop_wait_high(tp, &rtl_ocp_tx_cond, 50, 2000);
 	RTL_W8(IBISR0, RTL_R8(IBISR0) | 0x20);
 	RTL_W8(IBCR0, RTL_R8(IBCR0) & ~0x01);
 }
@@ -2204,19 +2207,14 @@
 	void __iomem *ioaddr = tp->mmio_addr;
 	dma_addr_t paddr = tp->counters_phys_addr;
 	u32 cmd;
-	bool ret;
 
 	RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
+	RTL_R32(CounterAddrHigh);
 	cmd = (u64)paddr & DMA_BIT_MASK(32);
 	RTL_W32(CounterAddrLow, cmd);
 	RTL_W32(CounterAddrLow, cmd | counter_cmd);
 
-	ret = rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000);
-
-	RTL_W32(CounterAddrLow, 0);
-	RTL_W32(CounterAddrHigh, 0);
-
-	return ret;
+	return rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000);
 }
 
 static bool rtl8169_reset_counters(struct net_device *dev)
@@ -4454,6 +4452,62 @@
 	rtl_unlock_work(tp);
 }
 
+static void rtl_init_rxcfg(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_01:
+	case RTL_GIGA_MAC_VER_02:
+	case RTL_GIGA_MAC_VER_03:
+	case RTL_GIGA_MAC_VER_04:
+	case RTL_GIGA_MAC_VER_05:
+	case RTL_GIGA_MAC_VER_06:
+	case RTL_GIGA_MAC_VER_10:
+	case RTL_GIGA_MAC_VER_11:
+	case RTL_GIGA_MAC_VER_12:
+	case RTL_GIGA_MAC_VER_13:
+	case RTL_GIGA_MAC_VER_14:
+	case RTL_GIGA_MAC_VER_15:
+	case RTL_GIGA_MAC_VER_16:
+	case RTL_GIGA_MAC_VER_17:
+		RTL_W32(RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
+		break;
+	case RTL_GIGA_MAC_VER_18:
+	case RTL_GIGA_MAC_VER_19:
+	case RTL_GIGA_MAC_VER_20:
+	case RTL_GIGA_MAC_VER_21:
+	case RTL_GIGA_MAC_VER_22:
+	case RTL_GIGA_MAC_VER_23:
+	case RTL_GIGA_MAC_VER_24:
+	case RTL_GIGA_MAC_VER_34:
+	case RTL_GIGA_MAC_VER_35:
+		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
+		break;
+	case RTL_GIGA_MAC_VER_40:
+		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
+		break;
+	case RTL_GIGA_MAC_VER_41:
+	case RTL_GIGA_MAC_VER_42:
+	case RTL_GIGA_MAC_VER_43:
+	case RTL_GIGA_MAC_VER_44:
+	case RTL_GIGA_MAC_VER_45:
+	case RTL_GIGA_MAC_VER_46:
+	case RTL_GIGA_MAC_VER_47:
+	case RTL_GIGA_MAC_VER_48:
+		RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
+		break;
+	case RTL_GIGA_MAC_VER_49:
+	case RTL_GIGA_MAC_VER_50:
+	case RTL_GIGA_MAC_VER_51:
+		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
+		break;
+	default:
+		RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
+		break;
+	}
+}
+
 static int rtl_set_mac_address(struct net_device *dev, void *p)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -4466,6 +4520,10 @@
 
 	rtl_rar_set(tp, dev->dev_addr);
 
+	/* Reportedly at least Asus X453MA truncates packets otherwise */
+	if (tp->mac_version == RTL_GIGA_MAC_VER_37)
+		rtl_init_rxcfg(tp);
+
 	return 0;
 }
 
@@ -4836,6 +4894,9 @@
 static void rtl_pll_power_up(struct rtl8169_private *tp)
 {
 	rtl_generic_op(tp, tp->pll_power_ops.up);
+
+	/* give MAC/PHY some time to resume */
+	msleep(20);
 }
 
 static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
@@ -4900,62 +4961,6 @@
 	}
 }
 
-static void rtl_init_rxcfg(struct rtl8169_private *tp)
-{
-	void __iomem *ioaddr = tp->mmio_addr;
-
-	switch (tp->mac_version) {
-	case RTL_GIGA_MAC_VER_01:
-	case RTL_GIGA_MAC_VER_02:
-	case RTL_GIGA_MAC_VER_03:
-	case RTL_GIGA_MAC_VER_04:
-	case RTL_GIGA_MAC_VER_05:
-	case RTL_GIGA_MAC_VER_06:
-	case RTL_GIGA_MAC_VER_10:
-	case RTL_GIGA_MAC_VER_11:
-	case RTL_GIGA_MAC_VER_12:
-	case RTL_GIGA_MAC_VER_13:
-	case RTL_GIGA_MAC_VER_14:
-	case RTL_GIGA_MAC_VER_15:
-	case RTL_GIGA_MAC_VER_16:
-	case RTL_GIGA_MAC_VER_17:
-		RTL_W32(RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
-		break;
-	case RTL_GIGA_MAC_VER_18:
-	case RTL_GIGA_MAC_VER_19:
-	case RTL_GIGA_MAC_VER_20:
-	case RTL_GIGA_MAC_VER_21:
-	case RTL_GIGA_MAC_VER_22:
-	case RTL_GIGA_MAC_VER_23:
-	case RTL_GIGA_MAC_VER_24:
-	case RTL_GIGA_MAC_VER_34:
-	case RTL_GIGA_MAC_VER_35:
-		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
-		break;
-	case RTL_GIGA_MAC_VER_40:
-		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
-		break;
-	case RTL_GIGA_MAC_VER_41:
-	case RTL_GIGA_MAC_VER_42:
-	case RTL_GIGA_MAC_VER_43:
-	case RTL_GIGA_MAC_VER_44:
-	case RTL_GIGA_MAC_VER_45:
-	case RTL_GIGA_MAC_VER_46:
-	case RTL_GIGA_MAC_VER_47:
-	case RTL_GIGA_MAC_VER_48:
-		RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
-		break;
-	case RTL_GIGA_MAC_VER_49:
-	case RTL_GIGA_MAC_VER_50:
-	case RTL_GIGA_MAC_VER_51:
-		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
-		break;
-	default:
-		RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
-		break;
-	}
-}
-
 static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
 {
 	tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
@@ -7541,17 +7546,15 @@
 	struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
 	struct net_device *dev = tp->dev;
 	u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
-	int work_done= 0;
+	int work_done;
 	u16 status;
 
 	status = rtl_get_events(tp);
 	rtl_ack_events(tp, status & ~tp->event_slow);
 
-	if (status & RTL_EVENT_NAPI_RX)
-		work_done = rtl_rx(dev, tp, (u32) budget);
+	work_done = rtl_rx(dev, tp, (u32) budget);
 
-	if (status & RTL_EVENT_NAPI_TX)
-		rtl_tx(dev, tp);
+	rtl_tx(dev, tp);
 
 	if (status & tp->event_slow) {
 		enable_mask &= ~tp->event_slow;
@@ -7619,7 +7622,8 @@
 	rtl8169_update_counters(dev);
 
 	rtl_lock_work(tp);
-	clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
+	/* Clear all task flags */
+	bitmap_zero(tp->wk.flags, RTL_FLAG_MAX);
 
 	rtl8169_down(dev);
 	rtl_unlock_work(tp);
@@ -7796,7 +7800,9 @@
 
 	rtl_lock_work(tp);
 	napi_disable(&tp->napi);
-	clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
+	/* Clear all task flags */
+	bitmap_zero(tp->wk.flags, RTL_FLAG_MAX);
+
 	rtl_unlock_work(tp);
 
 	rtl_pll_power_down(tp);
@@ -8415,12 +8421,12 @@
 		goto err_out_msi_4;
 	}
 
+	pci_set_drvdata(pdev, dev);
+
 	rc = register_netdev(dev);
 	if (rc < 0)
 		goto err_out_cnt_5;
 
-	pci_set_drvdata(pdev, dev);
-
 	netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
 		   rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
 		   (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
--- linux-4.4.0.orig/drivers/net/ethernet/renesas/ravb_main.c
+++ linux-4.4.0/drivers/net/ethernet/renesas/ravb_main.c
@@ -1,6 +1,6 @@
 /* Renesas Ethernet AVB device driver
  *
- * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-2019 Renesas Electronics Corporation
  * Copyright (C) 2015 Renesas Solutions Corp.
  * Copyright (C) 2015 Cogent Embedded, Inc. <source@cogentembedded.com>
  *
@@ -171,34 +171,67 @@
 	.get_mdio_data = ravb_get_mdio_data,
 };
 
-/* Free skb's and DMA buffers for Ethernet AVB */
-static void ravb_ring_free(struct net_device *ndev, int q)
+/* Free TX skb function for AVB-IP */
+static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only)
 {
 	struct ravb_private *priv = netdev_priv(ndev);
-	int ring_size;
-	int i;
+	struct net_device_stats *stats = &priv->stats[q];
+	struct ravb_tx_desc *desc;
+	int free_num = 0;
+	int entry;
+	u32 size;
 
-	/* Free RX skb ringbuffer */
-	if (priv->rx_skb[q]) {
-		for (i = 0; i < priv->num_rx_ring[q]; i++)
-			dev_kfree_skb(priv->rx_skb[q][i]);
-	}
-	kfree(priv->rx_skb[q]);
-	priv->rx_skb[q] = NULL;
+	for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) {
+		bool txed;
 
-	/* Free TX skb ringbuffer */
-	if (priv->tx_skb[q]) {
-		for (i = 0; i < priv->num_tx_ring[q]; i++)
-			dev_kfree_skb(priv->tx_skb[q][i]);
+		entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] *
+					     NUM_TX_DESC);
+		desc = &priv->tx_ring[q][entry];
+		txed = desc->die_dt == DT_FEMPTY;
+		if (free_txed_only && !txed)
+			break;
+		/* Descriptor type must be checked before all other reads */
+		dma_rmb();
+		size = le16_to_cpu(desc->ds_tagl) & TX_DS;
+		/* Free the original skb. */
+		if (priv->tx_skb[q][entry / NUM_TX_DESC]) {
+			dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
+					 size, DMA_TO_DEVICE);
+			/* Last packet descriptor? */
+			if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) {
+				entry /= NUM_TX_DESC;
+				dev_kfree_skb_any(priv->tx_skb[q][entry]);
+				priv->tx_skb[q][entry] = NULL;
+				if (txed)
+					stats->tx_packets++;
+			}
+			free_num++;
+		}
+		if (txed)
+			stats->tx_bytes += size;
+		desc->die_dt = DT_EEMPTY;
 	}
-	kfree(priv->tx_skb[q]);
-	priv->tx_skb[q] = NULL;
+	return free_num;
+}
 
-	/* Free aligned TX buffers */
-	kfree(priv->tx_align[q]);
-	priv->tx_align[q] = NULL;
+/* Free skb's and DMA buffers for Ethernet AVB */
+static void ravb_ring_free(struct net_device *ndev, int q)
+{
+	struct ravb_private *priv = netdev_priv(ndev);
+	int ring_size;
+	int i;
 
 	if (priv->rx_ring[q]) {
+		for (i = 0; i < priv->num_rx_ring[q]; i++) {
+			struct ravb_ex_rx_desc *desc = &priv->rx_ring[q][i];
+
+			if (!dma_mapping_error(ndev->dev.parent,
+					       le32_to_cpu(desc->dptr)))
+				dma_unmap_single(ndev->dev.parent,
+						 le32_to_cpu(desc->dptr),
+						 PKT_BUF_SZ,
+						 DMA_FROM_DEVICE);
+		}
 		ring_size = sizeof(struct ravb_ex_rx_desc) *
 			    (priv->num_rx_ring[q] + 1);
 		dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q],
@@ -207,12 +240,32 @@
 	}
 
 	if (priv->tx_ring[q]) {
+		ravb_tx_free(ndev, q, false);
+
 		ring_size = sizeof(struct ravb_tx_desc) *
 			    (priv->num_tx_ring[q] * NUM_TX_DESC + 1);
 		dma_free_coherent(ndev->dev.parent, ring_size, priv->tx_ring[q],
 				  priv->tx_desc_dma[q]);
 		priv->tx_ring[q] = NULL;
 	}
+
+	/* Free RX skb ringbuffer */
+	if (priv->rx_skb[q]) {
+		for (i = 0; i < priv->num_rx_ring[q]; i++)
+			dev_kfree_skb(priv->rx_skb[q][i]);
+	}
+	kfree(priv->rx_skb[q]);
+	priv->rx_skb[q] = NULL;
+
+	/* Free aligned TX buffers */
+	kfree(priv->tx_align[q]);
+	priv->tx_align[q] = NULL;
+
+	/* Free TX skb ringbuffer.
+	 * SKBs are freed by ravb_tx_free() call above.
+	 */
+	kfree(priv->tx_skb[q]);
+	priv->tx_skb[q] = NULL;
 }
 
 /* Format skb and descriptor buffer for Ethernet AVB */
@@ -400,7 +453,7 @@
 	ravb_write(ndev, RCR_EFFS | RCR_ENCF | RCR_ETS0 | 0x18000000, RCR);
 
 	/* Set FIFO size */
-	ravb_write(ndev, TGC_TQP_AVBMODE1 | 0x00222200, TGC);
+	ravb_write(ndev, TGC_TQP_AVBMODE1 | 0x00112200, TGC);
 
 	/* Timestamp enable */
 	ravb_write(ndev, TCCR_TFEN, TCCR);
@@ -420,44 +473,6 @@
 	return 0;
 }
 
-/* Free TX skb function for AVB-IP */
-static int ravb_tx_free(struct net_device *ndev, int q)
-{
-	struct ravb_private *priv = netdev_priv(ndev);
-	struct net_device_stats *stats = &priv->stats[q];
-	struct ravb_tx_desc *desc;
-	int free_num = 0;
-	int entry;
-	u32 size;
-
-	for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) {
-		entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] *
-					     NUM_TX_DESC);
-		desc = &priv->tx_ring[q][entry];
-		if (desc->die_dt != DT_FEMPTY)
-			break;
-		/* Descriptor type must be checked before all other reads */
-		dma_rmb();
-		size = le16_to_cpu(desc->ds_tagl) & TX_DS;
-		/* Free the original skb. */
-		if (priv->tx_skb[q][entry / NUM_TX_DESC]) {
-			dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
-					 size, DMA_TO_DEVICE);
-			/* Last packet descriptor? */
-			if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) {
-				entry /= NUM_TX_DESC;
-				dev_kfree_skb_any(priv->tx_skb[q][entry]);
-				priv->tx_skb[q][entry] = NULL;
-				stats->tx_packets++;
-			}
-			free_num++;
-		}
-		stats->tx_bytes += size;
-		desc->die_dt = DT_EEMPTY;
-	}
-	return free_num;
-}
-
 static void ravb_get_tx_tstamp(struct net_device *ndev)
 {
 	struct ravb_private *priv = netdev_priv(ndev);
@@ -486,7 +501,10 @@
 			kfree(ts_skb);
 			if (tag == tfa_tag) {
 				skb_tstamp_tx(skb, &shhwtstamps);
+				dev_consume_skb_any(skb);
 				break;
+			} else {
+				dev_kfree_skb_any(skb);
 			}
 		}
 		ravb_write(ndev, ravb_read(ndev, TCCR) | TCCR_TFR, TCCR);
@@ -797,7 +815,7 @@
 			spin_lock_irqsave(&priv->lock, flags);
 			/* Clear TX interrupt */
 			ravb_write(ndev, ~mask, TIS);
-			ravb_tx_free(ndev, q);
+			ravb_tx_free(ndev, q, true);
 			netif_wake_subqueue(ndev, q);
 			mmiowb();
 			spin_unlock_irqrestore(&priv->lock, flags);
@@ -816,14 +834,10 @@
 	/* Receive error message handling */
 	priv->rx_over_errors =  priv->stats[RAVB_BE].rx_over_errors;
 	priv->rx_over_errors += priv->stats[RAVB_NC].rx_over_errors;
-	if (priv->rx_over_errors != ndev->stats.rx_over_errors) {
+	if (priv->rx_over_errors != ndev->stats.rx_over_errors)
 		ndev->stats.rx_over_errors = priv->rx_over_errors;
-		netif_err(priv, rx_err, ndev, "Receive Descriptor Empty\n");
-	}
-	if (priv->rx_fifo_errors != ndev->stats.rx_fifo_errors) {
+	if (priv->rx_fifo_errors != ndev->stats.rx_fifo_errors)
 		ndev->stats.rx_fifo_errors = priv->rx_fifo_errors;
-		netif_err(priv, rx_err, ndev, "Receive FIFO Overflow\n");
-	}
 out:
 	return budget - quota;
 }
@@ -1277,6 +1291,7 @@
 	struct ravb_private *priv = container_of(work, struct ravb_private,
 						 work);
 	struct net_device *ndev = priv->ndev;
+	int error;
 
 	netif_tx_stop_all_queues(ndev);
 
@@ -1284,15 +1299,36 @@
 	ravb_ptp_stop(ndev);
 
 	/* Wait for DMA stopping */
-	ravb_stop_dma(ndev);
+	if (ravb_stop_dma(ndev)) {
+		/* If ravb_stop_dma() fails, the hardware is still operating
+		 * for TX and/or RX. So, this should not call the following
+		 * functions because ravb_dmac_init() is possible to fail too.
+		 * Also, this should not retry ravb_stop_dma() again and again
+		 * here because it's possible to wait forever. So, this just
+		 * re-enables the TX and RX and skip the following
+		 * re-initialization procedure.
+		 */
+		ravb_rcv_snd_enable(ndev);
+		goto out;
+	}
 
 	ravb_ring_free(ndev, RAVB_BE);
 	ravb_ring_free(ndev, RAVB_NC);
 
 	/* Device init */
-	ravb_dmac_init(ndev);
+	error = ravb_dmac_init(ndev);
+	if (error) {
+		/* If ravb_dmac_init() fails, descriptors are freed. So, this
+		 * should return here to avoid re-enabling the TX and RX in
+		 * ravb_emac_init().
+		 */
+		netdev_err(ndev, "%s: ravb_dmac_init() failed, error %d\n",
+			   __func__, error);
+		return;
+	}
 	ravb_emac_init(ndev);
 
+out:
 	/* Initialise PTP Clock driver */
 	ravb_ptp_init(ndev, priv->pdev);
 
@@ -1330,6 +1366,19 @@
 	buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) +
 		 entry / NUM_TX_DESC * DPTR_ALIGN;
 	len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data;
+	/* Zero length DMA descriptors are problematic as they seem to
+	 * terminate DMA transfers. Avoid them by simply using a length of
+	 * DPTR_ALIGN (4) when skb data is aligned to DPTR_ALIGN.
+	 *
+	 * As skb is guaranteed to have at least ETH_ZLEN (60) bytes of
+	 * data by the call to skb_put_padto() above this is safe with
+	 * respect to both the length of the first DMA descriptor (len)
+	 * overflowing the available data and the length of the second DMA
+	 * descriptor (skb->len - len) being negative.
+	 */
+	if (len == 0)
+		len = DPTR_ALIGN;
+
 	memcpy(buffer, skb->data, len);
 	dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE);
 	if (dma_mapping_error(ndev->dev.parent, dma_addr))
@@ -1358,7 +1407,7 @@
 					 DMA_TO_DEVICE);
 			goto unmap;
 		}
-		ts_skb->skb = skb;
+		ts_skb->skb = skb_get(skb);
 		ts_skb->tag = priv->ts_skb_tag++;
 		priv->ts_skb_tag &= 0x3ff;
 		list_add_tail(&ts_skb->list, &priv->ts_skb_list);
@@ -1380,7 +1429,8 @@
 
 	priv->cur_tx[q] += NUM_TX_DESC;
 	if (priv->cur_tx[q] - priv->dirty_tx[q] >
-	    (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && !ravb_tx_free(ndev, q))
+	    (priv->num_tx_ring[q] - 1) * NUM_TX_DESC &&
+	    !ravb_tx_free(ndev, q, true))
 		netif_stop_subqueue(ndev, q);
 
 exit:
@@ -1489,6 +1539,7 @@
 	/* Clear the timestamp list */
 	list_for_each_entry_safe(ts_skb, ts_skb2, &priv->ts_skb_list, list) {
 		list_del(&ts_skb->list);
+		kfree_skb(ts_skb->skb);
 		kfree(ts_skb);
 	}
 
@@ -1499,6 +1550,10 @@
 		priv->phydev = NULL;
 	}
 
+	cancel_work_sync(&priv->work);
+
+	if (priv->chip_id == RCAR_GEN3)
+		free_irq(priv->emac_irq, ndev);
 	free_irq(ndev->irq, ndev);
 
 	napi_disable(&priv->napi[RAVB_NC]);
@@ -1519,12 +1574,16 @@
 	config.flags = 0;
 	config.tx_type = priv->tstamp_tx_ctrl ? HWTSTAMP_TX_ON :
 						HWTSTAMP_TX_OFF;
-	if (priv->tstamp_rx_ctrl & RAVB_RXTSTAMP_TYPE_V2_L2_EVENT)
+	switch (priv->tstamp_rx_ctrl & RAVB_RXTSTAMP_TYPE) {
+	case RAVB_RXTSTAMP_TYPE_V2_L2_EVENT:
 		config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
-	else if (priv->tstamp_rx_ctrl & RAVB_RXTSTAMP_TYPE_ALL)
+		break;
+	case RAVB_RXTSTAMP_TYPE_ALL:
 		config.rx_filter = HWTSTAMP_FILTER_ALL;
-	else
+		break;
+	default:
 		config.rx_filter = HWTSTAMP_FILTER_NONE;
+	}
 
 	return copy_to_user(req->ifr_data, &config, sizeof(config)) ?
 		-EFAULT : 0;
--- linux-4.4.0.orig/drivers/net/ethernet/renesas/sh_eth.c
+++ linux-4.4.0/drivers/net/ethernet/renesas/sh_eth.c
@@ -750,6 +750,7 @@
 	.tsu		= 1,
 	.hw_crc		= 1,
 	.select_mii	= 1,
+	.shift_rd0	= 1,
 };
 
 /* SH7763 */
@@ -818,6 +819,7 @@
 	.rpadir_value   = 2 << 16,
 	.no_trimd	= 1,
 	.no_ade		= 1,
+	.hw_crc		= 1,
 	.tsu		= 1,
 	.select_mii	= 1,
 	.shift_rd0	= 1,
@@ -832,7 +834,7 @@
 
 	.ecsr_value	= ECSR_ICD,
 	.ecsipr_value	= ECSIPR_ICDIP,
-	.eesipr_value	= 0xff7f009f,
+	.eesipr_value	= 0xe77f009f,
 
 	.tx_check	= EESR_TC1 | EESR_FTC,
 	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
@@ -1185,11 +1187,8 @@
 			break;
 		sh_eth_set_receive_align(skb);
 
-		/* RX descriptor */
-		rxdesc = &mdp->rx_ring[i];
 		/* The size of the buffer is a multiple of 32 bytes. */
 		buf_len = ALIGN(mdp->rx_buf_sz, 32);
-		rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
 		dma_addr = dma_map_single(&ndev->dev, skb->data, buf_len,
 					  DMA_FROM_DEVICE);
 		if (dma_mapping_error(&ndev->dev, dma_addr)) {
@@ -1197,6 +1196,10 @@
 			break;
 		}
 		mdp->rx_skbuff[i] = skb;
+
+		/* RX descriptor */
+		rxdesc = &mdp->rx_ring[i];
+		rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
 		rxdesc->addr = cpu_to_edmac(mdp, dma_addr);
 		rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 
@@ -1212,7 +1215,8 @@
 	mdp->dirty_rx = (u32) (i - mdp->num_rx_ring);
 
 	/* Mark the last entry as wrapping the ring. */
-	rxdesc->status |= cpu_to_edmac(mdp, RD_RDLE);
+	if (rxdesc)
+		rxdesc->status |= cpu_to_edmac(mdp, RD_RDLE);
 
 	memset(mdp->tx_ring, 0, tx_ringsize);
 
@@ -1404,6 +1408,10 @@
 	sh_eth_get_stats(ndev);
 	sh_eth_reset(ndev);
 
+	/* Set the RMII mode again if required */
+	if (mdp->cd->rmiimode)
+		sh_eth_write(ndev, 0x1, RMIIMODE);
+
 	/* Set MAC address again */
 	update_mac_address(ndev);
 }
@@ -2499,10 +2507,10 @@
 	/* Free all the skbuffs in the Rx queue and the DMA buffer. */
 	sh_eth_ring_free(ndev);
 
-	pm_runtime_put_sync(&mdp->pdev->dev);
-
 	mdp->is_opened = 0;
 
+	pm_runtime_put(&mdp->pdev->dev);
+
 	return 0;
 }
 
@@ -3032,12 +3040,16 @@
 	struct device_node *np = dev->of_node;
 	struct sh_eth_plat_data *pdata;
 	const char *mac_addr;
+	int ret;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
 		return NULL;
 
-	pdata->phy_interface = of_get_phy_mode(np);
+	ret = of_get_phy_mode(np);
+	if (ret < 0)
+		return NULL;
+	pdata->phy_interface = ret;
 
 	mac_addr = of_get_mac_address(np);
 	if (mac_addr)
@@ -3172,18 +3184,37 @@
 	/* ioremap the TSU registers */
 	if (mdp->cd->tsu) {
 		struct resource *rtsu;
+
 		rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-		mdp->tsu_addr = devm_ioremap_resource(&pdev->dev, rtsu);
-		if (IS_ERR(mdp->tsu_addr)) {
-			ret = PTR_ERR(mdp->tsu_addr);
+		if (!rtsu) {
+			dev_err(&pdev->dev, "no TSU resource\n");
+			ret = -ENODEV;
+			goto out_release;
+		}
+		/* We can only request the  TSU region  for the first port
+		 * of the two  sharing this TSU for the probe to succeed...
+		 */
+		if (devno % 2 == 0 &&
+		    !devm_request_mem_region(&pdev->dev, rtsu->start,
+					     resource_size(rtsu),
+					     dev_name(&pdev->dev))) {
+			dev_err(&pdev->dev, "can't request TSU resource.\n");
+			ret = -EBUSY;
+			goto out_release;
+		}
+		mdp->tsu_addr = devm_ioremap(&pdev->dev, rtsu->start,
+					     resource_size(rtsu));
+		if (!mdp->tsu_addr) {
+			dev_err(&pdev->dev, "TSU region ioremap() failed.\n");
+			ret = -ENOMEM;
 			goto out_release;
 		}
 		mdp->port = devno % 2;
 		ndev->features = NETIF_F_HW_VLAN_CTAG_FILTER;
 	}
 
-	/* initialize first or needed device */
-	if (!devno || pd->needs_init) {
+	/* Need to init only the first port of the two sharing a TSU */
+	if (devno % 2 == 0) {
 		if (mdp->cd->chip_reset)
 			mdp->cd->chip_reset(ndev);
 
@@ -3199,7 +3230,7 @@
 	/* MDIO bus init */
 	ret = sh_mdio_init(mdp, pd);
 	if (ret) {
-		dev_err(&ndev->dev, "failed to initialise MDIO\n");
+		dev_err(&pdev->dev, "failed to initialise MDIO\n");
 		goto out_release;
 	}
 
--- linux-4.4.0.orig/drivers/net/ethernet/renesas/sh_eth.h
+++ linux-4.4.0/drivers/net/ethernet/renesas/sh_eth.h
@@ -339,7 +339,7 @@
 	ECMR_DPAD = 0x00200000, ECMR_RZPF = 0x00100000,
 	ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000,
 	ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000,
-	ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020,
+	ECMR_MPDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020,
 	ECMR_RTM = 0x00000010, ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004,
 	ECMR_DM = 0x00000002, ECMR_PRM = 0x00000001,
 };
--- linux-4.4.0.orig/drivers/net/ethernet/rocker/rocker.c
+++ linux-4.4.0/drivers/net/ethernet/rocker/rocker.c
@@ -239,6 +239,7 @@
 	struct {
 		u64 id;
 	} hw;
+	unsigned long ageing_time;
 	spinlock_t cmd_ring_lock;		/* for cmd ring accesses */
 	struct rocker_dma_ring_info cmd_ring;
 	struct rocker_dma_ring_info event_ring;
@@ -820,37 +821,49 @@
 static int rocker_tlv_put_u8(struct rocker_desc_info *desc_info,
 			     int attrtype, u8 value)
 {
-	return rocker_tlv_put(desc_info, attrtype, sizeof(u8), &value);
+	u8 tmp = value; /* work around GCC PR81715 */
+
+	return rocker_tlv_put(desc_info, attrtype, sizeof(u8), &tmp);
 }
 
 static int rocker_tlv_put_u16(struct rocker_desc_info *desc_info,
 			      int attrtype, u16 value)
 {
-	return rocker_tlv_put(desc_info, attrtype, sizeof(u16), &value);
+	u16 tmp = value;
+
+	return rocker_tlv_put(desc_info, attrtype, sizeof(u16), &tmp);
 }
 
 static int rocker_tlv_put_be16(struct rocker_desc_info *desc_info,
 			       int attrtype, __be16 value)
 {
-	return rocker_tlv_put(desc_info, attrtype, sizeof(__be16), &value);
+	__be16 tmp = value;
+
+	return rocker_tlv_put(desc_info, attrtype, sizeof(__be16), &tmp);
 }
 
 static int rocker_tlv_put_u32(struct rocker_desc_info *desc_info,
 			      int attrtype, u32 value)
 {
-	return rocker_tlv_put(desc_info, attrtype, sizeof(u32), &value);
+	u32 tmp = value;
+
+	return rocker_tlv_put(desc_info, attrtype, sizeof(u32), &tmp);
 }
 
 static int rocker_tlv_put_be32(struct rocker_desc_info *desc_info,
 			       int attrtype, __be32 value)
 {
-	return rocker_tlv_put(desc_info, attrtype, sizeof(__be32), &value);
+	__be32 tmp = value;
+
+	return rocker_tlv_put(desc_info, attrtype, sizeof(__be32), &tmp);
 }
 
 static int rocker_tlv_put_u64(struct rocker_desc_info *desc_info,
 			      int attrtype, u64 value)
 {
-	return rocker_tlv_put(desc_info, attrtype, sizeof(u64), &value);
+	u64 tmp = value;
+
+	return rocker_tlv_put(desc_info, attrtype, sizeof(u64), &tmp);
 }
 
 static struct rocker_tlv *
@@ -3531,12 +3544,14 @@
 	info.addr = lw->addr;
 	info.vid = lw->vid;
 
+	rtnl_lock();
 	if (learned && removing)
 		call_switchdev_notifiers(SWITCHDEV_FDB_DEL,
 					 lw->rocker_port->dev, &info.info);
 	else if (learned && !removing)
 		call_switchdev_notifiers(SWITCHDEV_FDB_ADD,
 					 lw->rocker_port->dev, &info.info);
+	rtnl_unlock();
 
 	rocker_port_kfree(lw->trans, work);
 }
@@ -3702,7 +3717,7 @@
 	struct rocker_port *rocker_port;
 	struct rocker_fdb_tbl_entry *entry;
 	struct hlist_node *tmp;
-	unsigned long next_timer = jiffies + BR_MIN_AGEING_TIME;
+	unsigned long next_timer = jiffies + rocker->ageing_time;
 	unsigned long expires;
 	unsigned long lock_flags;
 	int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE |
@@ -4365,8 +4380,12 @@
 					  struct switchdev_trans *trans,
 					  u32 ageing_time)
 {
+	struct rocker *rocker = rocker_port->rocker;
+
 	if (!switchdev_trans_ph_prepare(trans)) {
 		rocker_port->ageing_time = clock_t_to_jiffies(ageing_time);
+		if (rocker_port->ageing_time < rocker->ageing_time)
+			rocker->ageing_time = rocker_port->ageing_time;
 		mod_timer(&rocker_port->rocker->fdb_cleanup_timer, jiffies);
 	}
 
@@ -4468,7 +4487,7 @@
 		fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
 		err = rocker_port_fib_ipv4(rocker_port, trans,
 					   htonl(fib4->dst), fib4->dst_len,
-					   &fib4->fi, fib4->tb_id, 0);
+					   fib4->fi, fib4->tb_id, 0);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
 		err = rocker_port_fdb_add(rocker_port, trans,
@@ -4540,7 +4559,7 @@
 		fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
 		err = rocker_port_fib_ipv4(rocker_port, NULL,
 					   htonl(fib4->dst), fib4->dst_len,
-					   &fib4->fi, fib4->tb_id,
+					   fib4->fi, fib4->tb_id,
 					   ROCKER_OP_FLAG_REMOVE);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
@@ -5204,10 +5223,13 @@
 		goto err_init_tbls;
 	}
 
+	rocker->ageing_time = BR_DEFAULT_AGEING_TIME;
 	setup_timer(&rocker->fdb_cleanup_timer, rocker_fdb_cleanup,
 		    (unsigned long) rocker);
 	mod_timer(&rocker->fdb_cleanup_timer, jiffies);
 
+	rocker->ageing_time = BR_DEFAULT_AGEING_TIME;
+
 	err = rocker_probe_ports(rocker);
 	if (err) {
 		dev_err(&pdev->dev, "failed to probe ports\n");
--- linux-4.4.0.orig/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ linux-4.4.0/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -2315,7 +2315,7 @@
 	if (!str || !*str)
 		return -EINVAL;
 	while ((opt = strsep(&str, ",")) != NULL) {
-		if (!strncmp(opt, "eee_timer:", 6)) {
+		if (!strncmp(opt, "eee_timer:", 10)) {
 			if (kstrtoint(opt + 10, 0, &eee_timer))
 				goto err;
 		}
--- linux-4.4.0.orig/drivers/net/ethernet/seeq/sgiseeq.c
+++ linux-4.4.0/drivers/net/ethernet/seeq/sgiseeq.c
@@ -792,15 +792,16 @@
 		printk(KERN_ERR "Sgiseeq: Cannot register net device, "
 		       "aborting.\n");
 		err = -ENODEV;
-		goto err_out_free_page;
+		goto err_out_free_attrs;
 	}
 
 	printk(KERN_INFO "%s: %s %pM\n", dev->name, sgiseeqstr, dev->dev_addr);
 
 	return 0;
 
-err_out_free_page:
-	free_page((unsigned long) sp->srings);
+err_out_free_attrs:
+	dma_free_attrs(&pdev->dev, sizeof(*sp->srings), sp->srings,
+		       sp->srings_dma, DMA_ATTR_NON_CONSISTENT);
 err_out_free_dev:
 	free_netdev(dev);
 
--- linux-4.4.0.orig/drivers/net/ethernet/sfc/ef10.c
+++ linux-4.4.0/drivers/net/ethernet/sfc/ef10.c
@@ -181,13 +181,6 @@
 		MCDI_WORD(outbuf, GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID);
 
 	if (!(nic_data->datapath_caps &
-	      (1 << MC_CMD_GET_CAPABILITIES_OUT_TX_TSO_LBN))) {
-		netif_err(efx, drv, efx->net_dev,
-			  "current firmware does not support TSO\n");
-		return -ENODEV;
-	}
-
-	if (!(nic_data->datapath_caps &
 	      (1 << MC_CMD_GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14_LBN))) {
 		netif_err(efx, probe, efx->net_dev,
 			  "current firmware does not support an RX prefix\n");
@@ -619,6 +612,17 @@
 	return rc;
 }
 
+static void efx_ef10_forget_old_piobufs(struct efx_nic *efx)
+{
+	struct efx_channel *channel;
+	struct efx_tx_queue *tx_queue;
+
+	/* All our existing PIO buffers went away */
+	efx_for_each_channel(channel, efx)
+		efx_for_each_channel_tx_queue(tx_queue, channel)
+			tx_queue->piobuf = NULL;
+}
+
 #else /* !EFX_USE_PIO */
 
 static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n)
@@ -635,6 +639,10 @@
 {
 }
 
+static void efx_ef10_forget_old_piobufs(struct efx_nic *efx)
+{
+}
+
 #endif /* EFX_USE_PIO */
 
 static void efx_ef10_remove(struct efx_nic *efx)
@@ -1018,6 +1026,7 @@
 	nic_data->must_realloc_vis = true;
 	nic_data->must_restore_filters = true;
 	nic_data->must_restore_piobufs = true;
+	efx_ef10_forget_old_piobufs(efx);
 	nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID;
 
 	/* Driver-created vswitches and vports must be re-created */
@@ -1288,13 +1297,14 @@
 	}
 
 #if BITS_PER_LONG == 64
+	BUILD_BUG_ON(BITS_TO_LONGS(EF10_STAT_COUNT) != 2);
 	mask[0] = raw_mask[0];
 	mask[1] = raw_mask[1];
 #else
+	BUILD_BUG_ON(BITS_TO_LONGS(EF10_STAT_COUNT) != 3);
 	mask[0] = raw_mask[0] & 0xffffffff;
 	mask[1] = raw_mask[0] >> 32;
 	mask[2] = raw_mask[1] & 0xffffffff;
-	mask[3] = raw_mask[1] >> 32;
 #endif
 }
 
@@ -1797,6 +1807,12 @@
 			     ESF_DZ_TX_OPTION_UDP_TCP_CSUM, csum_offload,
 			     ESF_DZ_TX_OPTION_IP_CSUM, csum_offload);
 	tx_queue->write_count = 1;
+
+	if (nic_data->datapath_caps &
+	    (1 << MC_CMD_GET_CAPABILITIES_OUT_TX_TSO_LBN)) {
+		tx_queue->tso_version = 1;
+	}
+
 	wmb();
 	efx_ef10_push_tx_desc(tx_queue, txd);
 
@@ -4291,7 +4307,7 @@
 		 * MCFW do not support VFs.
 		 */
 		rc = efx_ef10_vport_set_mac_address(efx);
-	} else {
+	} else if (rc) {
 		efx_mcdi_display_error(efx, MC_CMD_VADAPTOR_SET_MAC,
 				       sizeof(inbuf), NULL, 0, rc);
 	}
@@ -4417,22 +4433,25 @@
 	{ NVRAM_PARTITION_TYPE_LICENSE,		   0,    0, "sfc_license" },
 	{ NVRAM_PARTITION_TYPE_PHY_MIN,		   0xff, 0, "sfc_phy_fw" },
 };
+#define EF10_NVRAM_PARTITION_COUNT	ARRAY_SIZE(efx_ef10_nvram_types)
 
 static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
 					struct efx_mcdi_mtd_partition *part,
-					unsigned int type)
+					unsigned int type,
+					unsigned long *found)
 {
 	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
 	MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_METADATA_OUT_LENMAX);
 	const struct efx_ef10_nvram_type_info *info;
 	size_t size, erase_size, outlen;
+	int type_idx = 0;
 	bool protected;
 	int rc;
 
-	for (info = efx_ef10_nvram_types; ; info++) {
-		if (info ==
-		    efx_ef10_nvram_types + ARRAY_SIZE(efx_ef10_nvram_types))
+	for (type_idx = 0; ; type_idx++) {
+		if (type_idx == EF10_NVRAM_PARTITION_COUNT)
 			return -ENODEV;
+		info = efx_ef10_nvram_types + type_idx;
 		if ((type & ~info->type_mask) == info->type)
 			break;
 	}
@@ -4445,6 +4464,13 @@
 	if (protected)
 		return -ENODEV; /* hide it */
 
+	/* If we've already exposed a partition of this type, hide this
+	 * duplicate.  All operations on MTDs are keyed by the type anyway,
+	 * so we can't act on the duplicate.
+	 */
+	if (__test_and_set_bit(type_idx, found))
+		return -EEXIST;
+
 	part->nvram_type = type;
 
 	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
@@ -4473,6 +4499,7 @@
 static int efx_ef10_mtd_probe(struct efx_nic *efx)
 {
 	MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX);
+	DECLARE_BITMAP(found, EF10_NVRAM_PARTITION_COUNT) = { 0 };
 	struct efx_mcdi_mtd_partition *parts;
 	size_t outlen, n_parts_total, i, n_parts;
 	unsigned int type;
@@ -4501,11 +4528,13 @@
 	for (i = 0; i < n_parts_total; i++) {
 		type = MCDI_ARRAY_DWORD(outbuf, NVRAM_PARTITIONS_OUT_TYPE_ID,
 					i);
-		rc = efx_ef10_mtd_probe_partition(efx, &parts[n_parts], type);
-		if (rc == 0)
-			n_parts++;
-		else if (rc != -ENODEV)
+		rc = efx_ef10_mtd_probe_partition(efx, &parts[n_parts], type,
+						  found);
+		if (rc == -EEXIST || rc == -ENODEV)
+			continue;
+		if (rc)
 			goto fail;
+		n_parts++;
 	}
 
 	rc = efx_mtd_add(efx, &parts[0].common, n_parts, sizeof(*parts));
--- linux-4.4.0.orig/drivers/net/ethernet/sfc/efx.c
+++ linux-4.4.0/drivers/net/ethernet/sfc/efx.c
@@ -479,6 +479,9 @@
 	*channel = *old_channel;
 
 	channel->napi_dev = NULL;
+	INIT_HLIST_NODE(&channel->napi_str.napi_hash_node);
+	channel->napi_str.napi_id = 0;
+	channel->napi_str.state = 0;
 	memset(&channel->eventq, 0, sizeof(channel->eventq));
 
 	for (j = 0; j < EFX_TXQ_TYPES; j++) {
@@ -2785,6 +2788,12 @@
 	 .driver_data = (unsigned long) &efx_hunt_a0_vf_nic_type},
 	{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0923),  /* SFC9140 PF */
 	 .driver_data = (unsigned long) &efx_hunt_a0_nic_type},
+	{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x1923),  /* SFC9140 VF */
+	 .driver_data = (unsigned long) &efx_hunt_a0_vf_nic_type},
+	{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0a03),  /* SFC9220 PF */
+	 .driver_data = (unsigned long) &efx_hunt_a0_nic_type},
+	{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x1a03),  /* SFC9220 VF */
+	 .driver_data = (unsigned long) &efx_hunt_a0_vf_nic_type},
 	{0}			/* end of list */
 };
 
--- linux-4.4.0.orig/drivers/net/ethernet/sfc/efx.h
+++ linux-4.4.0/drivers/net/ethernet/sfc/efx.h
@@ -32,7 +32,8 @@
 				struct net_device *net_dev);
 netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
 void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
-int efx_setup_tc(struct net_device *net_dev, u8 num_tc);
+int efx_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto,
+		 struct tc_to_netdev *tc);
 unsigned int efx_tx_max_skb_descs(struct efx_nic *efx);
 extern unsigned int efx_piobuf_size;
 extern bool efx_separate_tx_channels;
--- linux-4.4.0.orig/drivers/net/ethernet/sfc/falcon.c
+++ linux-4.4.0/drivers/net/ethernet/sfc/falcon.c
@@ -2796,6 +2796,11 @@
 	.timer_period_max =  1 << FRF_AB_TC_TIMER_VAL_WIDTH,
 	.offload_features = NETIF_F_IP_CSUM,
 	.mcdi_max_ver = -1,
+#ifdef CONFIG_SFC_SRIOV
+	.vswitching_probe = efx_port_dummy_op_int,
+	.vswitching_restore = efx_port_dummy_op_int,
+	.vswitching_remove = efx_port_dummy_op_void,
+#endif
 };
 
 const struct efx_nic_type falcon_b0_nic_type = {
@@ -2897,4 +2902,9 @@
 	.offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE,
 	.mcdi_max_ver = -1,
 	.max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS,
+#ifdef CONFIG_SFC_SRIOV
+	.vswitching_probe = efx_port_dummy_op_int,
+	.vswitching_restore = efx_port_dummy_op_int,
+	.vswitching_remove = efx_port_dummy_op_void,
+#endif
 };
--- linux-4.4.0.orig/drivers/net/ethernet/sfc/net_driver.h
+++ linux-4.4.0/drivers/net/ethernet/sfc/net_driver.h
@@ -182,6 +182,7 @@
  *
  * @efx: The associated Efx NIC
  * @queue: DMA queue number
+ * @tso_version: Version of TSO in use for this queue.
  * @channel: The associated channel
  * @core_txq: The networking core TX queue structure
  * @buffer: The software buffer ring
@@ -228,6 +229,7 @@
 	/* Members which don't change on the fast path */
 	struct efx_nic *efx ____cacheline_aligned_in_smp;
 	unsigned queue;
+	unsigned int tso_version;
 	struct efx_channel *channel;
 	struct netdev_queue *core_txq;
 	struct efx_tx_buffer *buffer;
--- linux-4.4.0.orig/drivers/net/ethernet/sfc/ptp.c
+++ linux-4.4.0/drivers/net/ethernet/sfc/ptp.c
@@ -1320,7 +1320,8 @@
 	(void)efx_ptp_disable(efx);
 
 	cancel_work_sync(&efx->ptp_data->work);
-	cancel_work_sync(&efx->ptp_data->pps_work);
+	if (efx->ptp_data->pps_workwq)
+		cancel_work_sync(&efx->ptp_data->pps_work);
 
 	skb_queue_purge(&efx->ptp_data->rxq);
 	skb_queue_purge(&efx->ptp_data->txq);
--- linux-4.4.0.orig/drivers/net/ethernet/sfc/tx.c
+++ linux-4.4.0/drivers/net/ethernet/sfc/tx.c
@@ -562,14 +562,20 @@
 				     efx->n_tx_channels : 0));
 }
 
-int efx_setup_tc(struct net_device *net_dev, u8 num_tc)
+int efx_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto,
+		 struct tc_to_netdev *ntc)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_channel *channel;
 	struct efx_tx_queue *tx_queue;
-	unsigned tc;
+	unsigned tc, num_tc;
 	int rc;
 
+	if (handle != TC_H_ROOT || ntc->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+
+	num_tc = ntc->tc;
+
 	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0 || num_tc > EFX_MAX_TX_TC)
 		return -EINVAL;
 
@@ -1010,13 +1016,17 @@
 
 /* Parse the SKB header and initialise state. */
 static int tso_start(struct tso_state *st, struct efx_nic *efx,
+		     struct efx_tx_queue *tx_queue,
 		     const struct sk_buff *skb)
 {
-	bool use_opt_desc = efx_nic_rev(efx) >= EFX_REV_HUNT_A0;
 	struct device *dma_dev = &efx->pci_dev->dev;
 	unsigned int header_len, in_len;
+	bool use_opt_desc = false;
 	dma_addr_t dma_addr;
 
+	if (tx_queue->tso_version == 1)
+		use_opt_desc = true;
+
 	st->ip_off = skb_network_header(skb) - skb->data;
 	st->tcp_off = skb_transport_header(skb) - skb->data;
 	header_len = st->tcp_off + (tcp_hdr(skb)->doff << 2u);
@@ -1271,7 +1281,7 @@
 	/* Find the packet protocol and sanity-check it */
 	state.protocol = efx_tso_check_protocol(skb);
 
-	rc = tso_start(&state, efx, skb);
+	rc = tso_start(&state, efx, tx_queue, skb);
 	if (rc)
 		goto mem_err;
 
--- linux-4.4.0.orig/drivers/net/ethernet/sis/sis900.c
+++ linux-4.4.0/drivers/net/ethernet/sis/sis900.c
@@ -1058,7 +1058,7 @@
 	sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
 
 	/* Enable all known interrupts by setting the interrupt mask. */
-	sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+	sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
 	sw32(cr, RxENA | sr32(cr));
 	sw32(ier, IE);
 
@@ -1581,7 +1581,7 @@
 	sw32(txdp, sis_priv->tx_ring_dma);
 
 	/* Enable all known interrupts by setting the interrupt mask. */
-	sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+	sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
 }
 
 /**
@@ -1621,7 +1621,7 @@
 			spin_unlock_irqrestore(&sis_priv->lock, flags);
 			return NETDEV_TX_OK;
 	}
-	sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
+	sis_priv->tx_ring[entry].cmdsts = (OWN | INTR | skb->len);
 	sw32(cr, TxENA | sr32(cr));
 
 	sis_priv->cur_tx ++;
@@ -1677,7 +1677,7 @@
 	do {
 		status = sr32(isr);
 
-		if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
+		if ((status & (HIBERR|TxURN|TxERR|TxIDLE|TxDESC|RxORN|RxERR|RxOK)) == 0)
 			/* nothing intresting happened */
 			break;
 		handled = 1;
@@ -1687,7 +1687,7 @@
 			/* Rx interrupt */
 			sis900_rx(net_dev);
 
-		if (status & (TxURN | TxERR | TxIDLE))
+		if (status & (TxURN | TxERR | TxIDLE | TxDESC))
 			/* Tx interrupt */
 			sis900_finish_xmit(net_dev);
 
@@ -1899,8 +1899,8 @@
 
 		if (tx_status & OWN) {
 			/* The packet is not transmitted yet (owned by hardware) !
-			 * Note: the interrupt is generated only when Tx Machine
-			 * is idle, so this is an almost impossible case */
+			 * Note: this is an almost impossible condition
+			 * in case of TxDESC ('descriptor interrupt') */
 			break;
 		}
 
@@ -2476,7 +2476,7 @@
 	sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
 
 	/* Enable all known interrupts by setting the interrupt mask. */
-	sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+	sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
 	sw32(cr, RxENA | sr32(cr));
 	sw32(ier, IE);
 
--- linux-4.4.0.orig/drivers/net/ethernet/smsc/smc911x.c
+++ linux-4.4.0/drivers/net/ethernet/smsc/smc911x.c
@@ -511,7 +511,8 @@
  * now, or set the card to generates an interrupt when ready
  * for the packet.
  */
-static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	unsigned int free;
@@ -944,7 +945,7 @@
 	if (lp->ctl_rspeed != 100)
 		my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF);
 
-	 if (!lp->ctl_rfduplx)
+	if (!lp->ctl_rfduplx)
 		my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL);
 
 	/* Update our Auto-Neg Advertisement Register */
--- linux-4.4.0.orig/drivers/net/ethernet/smsc/smc9194.c
+++ linux-4.4.0/drivers/net/ethernet/smsc/smc9194.c
@@ -1502,8 +1502,8 @@
 static struct net_device *devSMC9194;
 MODULE_LICENSE("GPL");
 
-module_param(io, int, 0);
-module_param(irq, int, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
 module_param(ifport, int, 0);
 MODULE_PARM_DESC(io, "SMC 99194 I/O base address");
 MODULE_PARM_DESC(irq, "SMC 99194 IRQ number");
--- linux-4.4.0.orig/drivers/net/ethernet/smsc/smc91x.c
+++ linux-4.4.0/drivers/net/ethernet/smsc/smc91x.c
@@ -540,7 +540,7 @@
 #define smc_special_lock(lock, flags)		spin_lock_irqsave(lock, flags)
 #define smc_special_unlock(lock, flags) 	spin_unlock_irqrestore(lock, flags)
 #else
-#define smc_special_trylock(lock, flags)	(flags == flags)
+#define smc_special_trylock(lock, flags)	((void)flags, true)
 #define smc_special_lock(lock, flags)   	do { flags = 0; } while (0)
 #define smc_special_unlock(lock, flags)	do { flags = 0; } while (0)
 #endif
@@ -637,7 +637,8 @@
  * now, or set the card to generates an interrupt when ready
  * for the packet.
  */
-static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct smc_local *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
@@ -2269,6 +2270,13 @@
 	if (pd) {
 		memcpy(&lp->cfg, pd, sizeof(lp->cfg));
 		lp->io_shift = SMC91X_IO_SHIFT(lp->cfg.flags);
+
+		if (!SMC_8BIT(lp) && !SMC_16BIT(lp)) {
+			dev_err(&pdev->dev,
+				"at least one of 8-bit or 16-bit access support is required.\n");
+			ret = -ENXIO;
+			goto out_free_netdev;
+		}
 	}
 
 #if IS_BUILTIN(CONFIG_OF)
@@ -2281,7 +2289,7 @@
 		ret = try_toggle_control_gpio(&pdev->dev, &lp->power_gpio,
 					      "power", 0, 0, 100);
 		if (ret)
-			return ret;
+			goto out_free_netdev;
 
 		/*
 		 * Optional reset GPIO configured? Minimum 100 ns reset needed
@@ -2290,7 +2298,7 @@
 		ret = try_toggle_control_gpio(&pdev->dev, &lp->reset_gpio,
 					      "reset", 0, 0, 100);
 		if (ret)
-			return ret;
+			goto out_free_netdev;
 
 		/*
 		 * Need to wait for optional EEPROM to load, max 750 us according
--- linux-4.4.0.orig/drivers/net/ethernet/smsc/smc91x.h
+++ linux-4.4.0/drivers/net/ethernet/smsc/smc91x.h
@@ -37,6 +37,27 @@
 #include <linux/smc91x.h>
 
 /*
+ * Any 16-bit access is performed with two 8-bit accesses if the hardware
+ * can't do it directly. Most registers are 16-bit so those are mandatory.
+ */
+#define SMC_outw_b(x, a, r)						\
+	do {								\
+		unsigned int __val16 = (x);				\
+		unsigned int __reg = (r);				\
+		SMC_outb(__val16, a, __reg);				\
+		SMC_outb(__val16 >> 8, a, __reg + (1 << SMC_IO_SHIFT));	\
+	} while (0)
+
+#define SMC_inw_b(a, r)							\
+	({								\
+		unsigned int __val16;					\
+		unsigned int __reg = r;					\
+		__val16  = SMC_inb(a, __reg);				\
+		__val16 |= SMC_inb(a, __reg + (1 << SMC_IO_SHIFT)) << 8; \
+		__val16;						\
+	})
+
+/*
  * Define your architecture specific bus configuration parameters here.
  */
 
@@ -55,10 +76,30 @@
 #define SMC_IO_SHIFT		(lp->io_shift)
 
 #define SMC_inb(a, r)		readb((a) + (r))
-#define SMC_inw(a, r)		readw((a) + (r))
+#define SMC_inw(a, r)							\
+	({								\
+		unsigned int __smc_r = r;				\
+		SMC_16BIT(lp) ? readw((a) + __smc_r) :			\
+		SMC_8BIT(lp) ? SMC_inw_b(a, __smc_r) :			\
+		({ BUG(); 0; });					\
+	})
+
 #define SMC_inl(a, r)		readl((a) + (r))
 #define SMC_outb(v, a, r)	writeb(v, (a) + (r))
+#define SMC_outw(v, a, r)						\
+	do {								\
+		unsigned int __v = v, __smc_r = r;			\
+		if (SMC_16BIT(lp))					\
+			__SMC_outw(__v, a, __smc_r);			\
+		else if (SMC_8BIT(lp))					\
+			SMC_outw_b(__v, a, __smc_r);			\
+		else							\
+			BUG();						\
+	} while (0)
+
 #define SMC_outl(v, a, r)	writel(v, (a) + (r))
+#define SMC_insb(a, r, p, l)	readsb((a) + (r), p, l)
+#define SMC_outsb(a, r, p, l)	writesb((a) + (r), p, l)
 #define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
 #define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
 #define SMC_insl(a, r, p, l)	readsl((a) + (r), p, l)
@@ -66,7 +107,7 @@
 #define SMC_IRQ_FLAGS		(-1)	/* from resource */
 
 /* We actually can't write halfwords properly if not word aligned */
-static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
+static inline void __SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 {
 	if ((machine_is_mainstone() || machine_is_stargate2() ||
 	     machine_is_pxa_idp()) && reg & 2) {
@@ -405,24 +446,8 @@
 
 #if ! SMC_CAN_USE_16BIT
 
-/*
- * Any 16-bit access is performed with two 8-bit accesses if the hardware
- * can't do it directly. Most registers are 16-bit so those are mandatory.
- */
-#define SMC_outw(x, ioaddr, reg)					\
-	do {								\
-		unsigned int __val16 = (x);				\
-		SMC_outb( __val16, ioaddr, reg );			\
-		SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\
-	} while (0)
-#define SMC_inw(ioaddr, reg)						\
-	({								\
-		unsigned int __val16;					\
-		__val16 =  SMC_inb( ioaddr, reg );			\
-		__val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \
-		__val16;						\
-	})
-
+#define SMC_outw(x, ioaddr, reg)	SMC_outw_b(x, ioaddr, reg)
+#define SMC_inw(ioaddr, reg)		SMC_inw_b(ioaddr, reg)
 #define SMC_insw(a, r, p, l)		BUG()
 #define SMC_outsw(a, r, p, l)		BUG()
 
--- linux-4.4.0.orig/drivers/net/ethernet/smsc/smsc911x.c
+++ linux-4.4.0/drivers/net/ethernet/smsc/smsc911x.c
@@ -1677,7 +1677,8 @@
 }
 
 /* Entry point for transmitting a packet */
-static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct smsc911x_data *pdata = netdev_priv(dev);
 	unsigned int freespace;
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/common.h
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -273,8 +273,8 @@
 	unsigned int enh_desc;
 };
 
-/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
-#define BUF_SIZE_16KiB 16384
+/* RX Buffer size must be multiple of 4/8/16 bytes */
+#define BUF_SIZE_16KiB 16368
 #define BUF_SIZE_8KiB 8192
 #define BUF_SIZE_4KiB 4096
 #define BUF_SIZE_2KiB 2048
@@ -301,7 +301,7 @@
 struct stmmac_desc_ops {
 	/* DMA RX descriptor ring initialization */
 	void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode,
-			      int end);
+			      int end, int bfsize);
 	/* DMA TX descriptor ring initialization */
 	void (*init_tx_desc) (struct dma_desc *p, int mode, int end);
 
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -33,9 +33,10 @@
 /* Specific functions used for Ring mode */
 
 /* Enhanced descriptors */
-static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
+static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end, int bfsize)
 {
-	p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
+	if (bfsize == BUF_SIZE_16KiB)
+		p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
 	if (end)
 		p->des01.erx.end_ring = 1;
 }
@@ -61,9 +62,14 @@
 }
 
 /* Normal descriptors */
-static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end)
+static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end, int bfsize)
 {
-	p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
+	int size;
+
+	if (bfsize >= BUF_SIZE_2KiB) {
+		size = min(bfsize - BUF_SIZE_2KiB + 1, BUF_SIZE_2KiB - 1);
+		p->des01.rx.buffer2_size = size;
+	}
 	if (end)
 		p->des01.rx.end_ring = 1;
 }
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
@@ -53,7 +53,17 @@
 			return ret;
 	}
 
-	return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+	if (ret)
+		goto err_exit;
+
+	return 0;
+
+err_exit:
+	if (plat_dat->exit)
+		plat_dat->exit(pdev, plat_dat->bsp_priv);
+
+	return ret;
 }
 
 static const struct of_device_id dwmac_generic_match[] = {
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -203,7 +203,7 @@
 	struct device *dev = &gmac->pdev->dev;
 
 	gmac->phy_mode = of_get_phy_mode(dev->of_node);
-	if (gmac->phy_mode < 0) {
+	if ((int)gmac->phy_mode < 0) {
 		dev_err(dev, "missing phy mode property\n");
 		return ERR_PTR(-EINVAL);
 	}
@@ -328,6 +328,19 @@
 	/* Enable PTP clock */
 	regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
 	val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id);
+	switch (gmac->phy_mode) {
+	case PHY_INTERFACE_MODE_RGMII:
+		val |= NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
+			NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
+		break;
+	case PHY_INTERFACE_MODE_SGMII:
+		val |= NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) |
+				NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id);
+		break;
+	default:
+		/* We don't get here; the switch above will have errored out */
+		unreachable();
+	}
 	regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
 
 	if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
@@ -347,6 +360,7 @@
 	plat_dat->has_gmac = true;
 	plat_dat->bsp_priv = gmac;
 	plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed;
+	plat_dat->multicast_filter_bins = 0;
 
 	return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
 }
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -429,10 +429,8 @@
 	int ret;
 	struct device *dev = &bsp_priv->pdev->dev;
 
-	if (!ldo) {
-		dev_err(dev, "no regulator found\n");
-		return -1;
-	}
+	if (!ldo)
+		return 0;
 
 	if (enable) {
 		ret = regulator_enable(ldo);
@@ -535,8 +533,10 @@
 	int ret;
 
 	ret = phy_power_on(bsp_priv, true);
-	if (ret)
+	if (ret) {
+		gmac_clk_enable(bsp_priv, false);
 		return ret;
+	}
 
 	ret = gmac_clk_enable(bsp_priv, true);
 	if (ret)
@@ -600,7 +600,16 @@
 	if (ret)
 		return ret;
 
-	return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+	if (ret)
+		goto err_gmac_exit;
+
+	return 0;
+
+err_gmac_exit:
+	rk_gmac_exit(pdev, plat_dat->bsp_priv);
+
+	return ret;
 }
 
 static const struct of_device_id rk_gmac_dwmac_match[] = {
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
@@ -365,7 +365,16 @@
 	if (ret)
 		return ret;
 
-	return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+	if (ret)
+		goto err_dwmac_exit;
+
+	return 0;
+
+err_dwmac_exit:
+	sti_dwmac_exit(pdev, plat_dat->bsp_priv);
+
+	return ret;
 }
 
 static const struct sti_dwmac_of_data stih4xx_dwmac_data = {
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
@@ -53,13 +53,15 @@
 	 * rate, which then uses the auto-reparenting feature of the
 	 * clock driver, and enabling/disabling the clock.
 	 */
-	if (gmac->interface == PHY_INTERFACE_MODE_RGMII) {
+	if (phy_interface_mode_is_rgmii(gmac->interface)) {
 		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE);
 		clk_prepare_enable(gmac->tx_clk);
 		gmac->clk_enabled = 1;
 	} else {
 		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE);
-		clk_prepare(gmac->tx_clk);
+		ret = clk_prepare(gmac->tx_clk);
+		if (ret)
+			return ret;
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -146,6 +146,9 @@
 		value = GMAC_FRAME_FILTER_PR;
 	} else if (dev->flags & IFF_ALLMULTI) {
 		value = GMAC_FRAME_FILTER_PM;	/* pass all multi */
+	} else if (!netdev_mc_empty(dev) && (mcbitslog2 == 0)) {
+		/* Fall back to all multicast if we've no filter */
+		value = GMAC_FRAME_FILTER_PM;
 	} else if (!netdev_mc_empty(dev)) {
 		struct netdev_hw_addr *ha;
 
@@ -187,6 +190,12 @@
 					    GMAC_ADDR_LOW(reg));
 			reg++;
 		}
+
+		while (reg < perfect_addr_number) {
+			writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
+			writel(0, ioaddr + GMAC_ADDR_LOW(reg));
+			reg++;
+		}
 	}
 
 #ifdef FRAME_FILTER_DEBUG
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -238,16 +238,20 @@
 }
 
 static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
-				  int mode, int end)
+				  int mode, int end, int bfsize)
 {
+	int bfsize1;
+
 	p->des01.all_flags = 0;
 	p->des01.erx.own = 1;
-	p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
+
+	bfsize1 = min(bfsize, BUF_SIZE_8KiB - 1);
+	p->des01.erx.buffer1_size = bfsize1;
 
 	if (mode == STMMAC_CHAIN_MODE)
 		ehn_desc_rx_set_on_chain(p, end);
 	else
-		ehn_desc_rx_set_on_ring(p, end);
+		ehn_desc_rx_set_on_ring(p, end, bfsize);
 
 	if (disable_rx_ic)
 		p->des01.erx.disable_ic = 1;
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -121,16 +121,20 @@
 }
 
 static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
-			       int end)
+			       int end, int bfsize)
 {
+	int bfsize1;
+
 	p->des01.all_flags = 0;
 	p->des01.rx.own = 1;
-	p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
+
+	bfsize1 = min(bfsize, (BUF_SIZE_2KiB - 1));
+	p->des01.rx.buffer1_size = bfsize1;
 
 	if (mode == STMMAC_CHAIN_MODE)
 		ndesc_rx_set_on_chain(p, end);
 	else
-		ndesc_rx_set_on_ring(p, end);
+		ndesc_rx_set_on_ring(p, end, bfsize);
 
 	if (disable_rx_ic)
 		p->des01.rx.disable_ic = 1;
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -614,25 +614,20 @@
 				     struct ethtool_eee *edata)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
+	int ret;
 
-	priv->eee_enabled = edata->eee_enabled;
+	if (!priv->dma_cap.eee)
+		return -EOPNOTSUPP;
 
-	if (!priv->eee_enabled)
+	if (!edata->eee_enabled)
 		stmmac_disable_eee_mode(priv);
-	else {
-		/* We are asking for enabling the EEE but it is safe
-		 * to verify all by invoking the eee_init function.
-		 * In case of failure it will return an error.
-		 */
-		priv->eee_enabled = stmmac_eee_init(priv);
-		if (!priv->eee_enabled)
-			return -EOPNOTSUPP;
 
-		/* Do not change tx_lpi_timer in case of failure */
-		priv->tx_lpi_timer = edata->tx_lpi_timer;
-	}
+	ret = phy_ethtool_set_eee(dev->phydev, edata);
+	if (ret)
+		return ret;
 
-	return phy_ethtool_set_eee(priv->phydev, edata);
+	priv->tx_lpi_timer = edata->tx_lpi_timer;
+	return 0;
 }
 
 static u32 stmmac_usec2riwt(u32 usec, struct stmmac_priv *priv)
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -54,7 +54,7 @@
 #include <linux/reset.h>
 #include <linux/of_mdio.h>
 
-#define STMMAC_ALIGN(x)	L1_CACHE_ALIGN(x)
+#define	STMMAC_ALIGN(x)		__ALIGN_KERNEL(x, SMP_CACHE_BYTES)
 
 /* Module parameters */
 #define TX_TIMEO	5000
@@ -272,8 +272,14 @@
 {
 	char *phy_bus_name = priv->plat->phy_bus_name;
 	unsigned long flags;
+	int interface = priv->plat->interface;
 	bool ret = false;
 
+	if ((interface != PHY_INTERFACE_MODE_MII) &&
+	    (interface != PHY_INTERFACE_MODE_GMII) &&
+	    !phy_interface_mode_is_rgmii(interface))
+		goto out;
+
 	/* Using PCS we cannot dial with the phy registers at this stage
 	 * so we do not support extra feature like EEE.
 	 */
@@ -929,7 +935,9 @@
 {
 	int ret = bufsize;
 
-	if (mtu >= BUF_SIZE_4KiB)
+	if (mtu >= BUF_SIZE_8KiB)
+		ret = BUF_SIZE_16KiB;
+	else if (mtu >= BUF_SIZE_4KiB)
 		ret = BUF_SIZE_8KiB;
 	else if (mtu >= BUF_SIZE_2KiB)
 		ret = BUF_SIZE_4KiB;
@@ -958,11 +966,11 @@
 		if (priv->extend_desc)
 			priv->hw->desc->init_rx_desc(&priv->dma_erx[i].basic,
 						     priv->use_riwt, priv->mode,
-						     (i == rxsize - 1));
+						     (i == rxsize - 1), priv->dma_buf_sz);
 		else
 			priv->hw->desc->init_rx_desc(&priv->dma_rx[i],
 						     priv->use_riwt, priv->mode,
-						     (i == rxsize - 1));
+						     (i == rxsize - 1), priv->dma_buf_sz);
 	for (i = 0; i < txsize; i++)
 		if (priv->extend_desc)
 			priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic,
@@ -1786,8 +1794,6 @@
 	struct stmmac_priv *priv = netdev_priv(dev);
 	int ret;
 
-	stmmac_check_ether_addr(priv);
-
 	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
 	    priv->pcs != STMMAC_PCS_RTBI) {
 		ret = stmmac_init_phy(dev);
@@ -1891,9 +1897,6 @@
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
 
-	if (priv->eee_enabled)
-		del_timer_sync(&priv->eee_ctrl_timer);
-
 	/* Stop and disconnect the PHY */
 	if (priv->phydev) {
 		phy_stop(priv->phydev);
@@ -1914,6 +1917,11 @@
 	if (priv->lpi_irq > 0)
 		free_irq(priv->lpi_irq, dev);
 
+	if (priv->eee_enabled) {
+		priv->tx_path_in_lpi_mode = false;
+		del_timer_sync(&priv->eee_ctrl_timer);
+	}
+
 	/* Stop TX/RX DMA and clear the descriptors */
 	priv->hw->dma->stop_tx(priv->ioaddr);
 	priv->hw->dma->stop_rx(priv->ioaddr);
@@ -2172,8 +2180,7 @@
 static int stmmac_rx(struct stmmac_priv *priv, int limit)
 {
 	unsigned int rxsize = priv->dma_rx_size;
-	unsigned int entry = priv->cur_rx % rxsize;
-	unsigned int next_entry;
+	unsigned int next_entry = priv->cur_rx % rxsize;
 	unsigned int count = 0;
 	int coe = priv->hw->rx_csum;
 
@@ -2185,9 +2192,11 @@
 			stmmac_display_ring((void *)priv->dma_rx, rxsize, 0);
 	}
 	while (count < limit) {
-		int status;
+		int status, entry;
 		struct dma_desc *p;
 
+		entry = next_entry;
+
 		if (priv->extend_desc)
 			p = (struct dma_desc *)(priv->dma_erx + entry);
 		else
@@ -2235,7 +2244,7 @@
 			/*  check if frame_len fits the preallocated memory */
 			if (frame_len > priv->dma_buf_sz) {
 				priv->dev->stats.rx_length_errors++;
-				break;
+				continue;
 			}
 
 			/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
@@ -2256,7 +2265,7 @@
 				pr_err("%s: Inconsistent Rx descriptor chain\n",
 				       priv->dev->name);
 				priv->dev->stats.rx_dropped++;
-				break;
+				continue;
 			}
 			prefetch(skb->data - NET_IP_ALIGN);
 			priv->rx_skbuff[entry] = NULL;
@@ -2287,7 +2296,6 @@
 			priv->dev->stats.rx_packets++;
 			priv->dev->stats.rx_bytes += frame_len;
 		}
-		entry = next_entry;
 	}
 
 	stmmac_rx_refill(priv);
@@ -2523,6 +2531,20 @@
 	return ret;
 }
 
+static int stmmac_set_mac_address(struct net_device *ndev, void *addr)
+{
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	int ret = 0;
+
+	ret = eth_mac_addr(ndev, addr);
+	if (ret)
+		return ret;
+
+	priv->hw->mac->set_umac_addr(priv->hw, ndev->dev_addr, 0);
+
+	return ret;
+}
+
 #ifdef CONFIG_DEBUG_FS
 static struct dentry *stmmac_fs_dir;
 
@@ -2724,7 +2746,7 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller = stmmac_poll_controller,
 #endif
-	.ndo_set_mac_address = eth_mac_addr,
+	.ndo_set_mac_address = stmmac_set_mac_address,
 };
 
 /**
@@ -2909,6 +2931,8 @@
 	if (ret)
 		goto error_hw_init;
 
+	stmmac_check_ether_addr(priv);
+
 	ndev->netdev_ops = &stmmac_netdev_ops;
 
 	ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
@@ -2939,12 +2963,6 @@
 	spin_lock_init(&priv->lock);
 	spin_lock_init(&priv->tx_lock);
 
-	ret = register_netdev(ndev);
-	if (ret) {
-		pr_err("%s: ERROR %i registering the device\n", __func__, ret);
-		goto error_netdev_register;
-	}
-
 	/* If a specific clk_csr value is passed from the platform
 	 * this means that the CSR Clock Range selection cannot be
 	 * changed at run-time and it is fixed. Viceversa the driver'll try to
@@ -2969,11 +2987,21 @@
 		}
 	}
 
-	return 0;
+	ret = register_netdev(ndev);
+	if (ret) {
+		netdev_err(priv->dev, "%s: ERROR %i registering the device\n",
+			   __func__, ret);
+		goto error_netdev_register;
+	}
+
+	return ret;
 
-error_mdio_register:
-	unregister_netdev(ndev);
 error_netdev_register:
+	if (priv->pcs != STMMAC_PCS_RGMII &&
+	    priv->pcs != STMMAC_PCS_TBI &&
+	    priv->pcs != STMMAC_PCS_RTBI)
+		stmmac_mdio_unregister(ndev);
+error_mdio_register:
 	netif_napi_del(&priv->napi);
 error_hw_init:
 	clk_disable_unprepare(priv->pclk);
@@ -3042,6 +3070,11 @@
 
 	napi_disable(&priv->napi);
 
+	if (priv->eee_enabled) {
+		priv->tx_path_in_lpi_mode = false;
+		del_timer_sync(&priv->eee_ctrl_timer);
+	}
+
 	/* Stop TX/RX DMA */
 	priv->hw->dma->stop_tx(priv->ioaddr);
 	priv->hw->dma->stop_rx(priv->ioaddr);
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -130,7 +130,7 @@
  */
 int stmmac_mdio_reset(struct mii_bus *bus)
 {
-#if defined(CONFIG_STMMAC_PLATFORM)
+#if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
 	struct net_device *ndev = bus->priv;
 	struct stmmac_priv *priv = netdev_priv(ndev);
 	unsigned int mii_address = priv->hw->mii.addr;
@@ -154,7 +154,8 @@
 			of_property_read_u32_array(np,
 				"snps,reset-delays-us", data->delays, 3);
 
-			if (gpio_request(data->reset_gpio, "mdio-reset"))
+			if (devm_gpio_request(priv->device, data->reset_gpio,
+					      "mdio-reset"))
 				return 0;
 		}
 
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -71,7 +71,7 @@
  * Description:
  * This function validates the number of Unicast address entries supported
  * by a particular Synopsys 10/100/1000 controller. The Synopsys controller
- * supports 1, 32, 64, or 128 Unicast filter entries for it's Unicast filter
+ * supports 1..32, 64, or 128 Unicast filter entries for it's Unicast filter
  * logic. This function validates a valid, supported configuration is
  * selected, and defaults to 1 Unicast address if an unsupported
  * configuration is selected.
@@ -81,8 +81,7 @@
 	int x = ucast_entries;
 
 	switch (x) {
-	case 1:
-	case 32:
+	case 1 ... 32:
 	case 64:
 	case 128:
 		break;
--- linux-4.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ linux-4.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -157,7 +157,7 @@
 /* structure describing a PTP hardware clock */
 static struct ptp_clock_info stmmac_ptp_clock_ops = {
 	.owner = THIS_MODULE,
-	.name = "stmmac_ptp_clock",
+	.name = "stmmac ptp",
 	.max_adj = 62500000,
 	.n_alarm = 0,
 	.n_ext_ts = 0,
--- linux-4.4.0.orig/drivers/net/ethernet/sun/cassini.c
+++ linux-4.4.0/drivers/net/ethernet/sun/cassini.c
@@ -4980,7 +4980,7 @@
 					  cas_cacheline_size)) {
 			dev_err(&pdev->dev, "Could not set PCI cache "
 			       "line size\n");
-			goto err_write_cacheline;
+			goto err_out_free_res;
 		}
 	}
 #endif
@@ -5151,7 +5151,6 @@
 err_out_free_res:
 	pci_release_regions(pdev);
 
-err_write_cacheline:
 	/* Try to restore it in case the error occurred after we
 	 * set it.
 	 */
--- linux-4.4.0.orig/drivers/net/ethernet/sun/niu.c
+++ linux-4.4.0/drivers/net/ethernet/sun/niu.c
@@ -3442,7 +3442,7 @@
 
 		len = (val & RCR_ENTRY_L2_LEN) >>
 			RCR_ENTRY_L2_LEN_SHIFT;
-		len -= ETH_FCS_LEN;
+		append_size = len + ETH_HLEN + ETH_FCS_LEN;
 
 		addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
 			RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
@@ -3452,7 +3452,6 @@
 					 RCR_ENTRY_PKTBUFSZ_SHIFT];
 
 		off = addr & ~PAGE_MASK;
-		append_size = rcr_size;
 		if (num_rcr == 1) {
 			int ptype;
 
@@ -3465,7 +3464,7 @@
 			else
 				skb_checksum_none_assert(skb);
 		} else if (!(val & RCR_ENTRY_MULTI))
-			append_size = len - skb->len;
+			append_size = append_size - skb->len;
 
 		niu_rx_skb_append(skb, page, off, append_size, rcr_size);
 		if ((page->index + rp->rbr_block_size) - rcr_size == addr) {
@@ -8122,6 +8121,8 @@
 		start += 3;
 
 		prop_len = niu_pci_eeprom_read(np, start + 4);
+		if (prop_len < 0)
+			return prop_len;
 		err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64);
 		if (err < 0)
 			return err;
@@ -8166,8 +8167,12 @@
 			netif_printk(np, probe, KERN_DEBUG, np->dev,
 				     "VPD_SCAN: Reading in property [%s] len[%d]\n",
 				     namebuf, prop_len);
-			for (i = 0; i < prop_len; i++)
-				*prop_buf++ = niu_pci_eeprom_read(np, off + i);
+			for (i = 0; i < prop_len; i++) {
+				err = niu_pci_eeprom_read(np, off + i);
+				if (err >= 0)
+					*prop_buf = err;
+				++prop_buf;
+			}
 		}
 
 		start += len;
--- linux-4.4.0.orig/drivers/net/ethernet/sun/sungem.c
+++ linux-4.4.0/drivers/net/ethernet/sun/sungem.c
@@ -60,8 +60,7 @@
 #include <linux/sungem_phy.h>
 #include "sungem.h"
 
-/* Stripping FCS is causing problems, disabled for now */
-#undef STRIP_FCS
+#define STRIP_FCS
 
 #define DEFAULT_MSG	(NETIF_MSG_DRV		| \
 			 NETIF_MSG_PROBE	| \
@@ -435,7 +434,7 @@
 	writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
 	writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
 	val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
-	       ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
+	       (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128);
 	writel(val, gp->regs + RXDMA_CFG);
 	if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
 		writel(((5 & RXDMA_BLANK_IPKTS) |
@@ -760,7 +759,6 @@
 	struct net_device *dev = gp->dev;
 	int entry, drops, work_done = 0;
 	u32 done;
-	__sum16 csum;
 
 	if (netif_msg_rx_status(gp))
 		printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n",
@@ -855,9 +853,13 @@
 			skb = copy_skb;
 		}
 
-		csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff);
-		skb->csum = csum_unfold(csum);
-		skb->ip_summed = CHECKSUM_COMPLETE;
+		if (likely(dev->features & NETIF_F_RXCSUM)) {
+			__sum16 csum;
+
+			csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff);
+			skb->csum = csum_unfold(csum);
+			skb->ip_summed = CHECKSUM_COMPLETE;
+		}
 		skb->protocol = eth_type_trans(skb, gp->dev);
 
 		napi_gro_receive(&gp->napi, skb);
@@ -957,17 +959,6 @@
 	return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void gem_poll_controller(struct net_device *dev)
-{
-	struct gem *gp = netdev_priv(dev);
-
-	disable_irq(gp->pdev->irq);
-	gem_interrupt(gp->pdev->irq, dev);
-	enable_irq(gp->pdev->irq);
-}
-#endif
-
 static void gem_tx_timeout(struct net_device *dev)
 {
 	struct gem *gp = netdev_priv(dev);
@@ -1755,7 +1746,7 @@
 	writel(0, gp->regs + TXDMA_KICK);
 
 	val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
-	       ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
+	       (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128);
 	writel(val, gp->regs + RXDMA_CFG);
 
 	writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
@@ -2819,9 +2810,6 @@
 	.ndo_change_mtu		= gem_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_set_mac_address    = gem_set_mac_address,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller    = gem_poll_controller,
-#endif
 };
 
 static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -2973,8 +2961,8 @@
 	pci_set_drvdata(pdev, dev);
 
 	/* We can do scatter/gather and HW checksum */
-	dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
-	dev->features |= dev->hw_features | NETIF_F_RXCSUM;
+	dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
+	dev->features = dev->hw_features;
 	if (pci_using_dac)
 		dev->features |= NETIF_F_HIGHDMA;
 
--- linux-4.4.0.orig/drivers/net/ethernet/sun/sunvnet.c
+++ linux-4.4.0/drivers/net/ethernet/sun/sunvnet.c
@@ -1787,7 +1787,7 @@
 	dev->ethtool_ops = &vnet_ethtool_ops;
 	dev->watchdog_timeo = VNET_TX_TIMEOUT;
 
-	dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE |
+	dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_ALL_TSO |
 			   NETIF_F_HW_CSUM | NETIF_F_SG;
 	dev->features = dev->hw_features;
 
--- linux-4.4.0.orig/drivers/net/ethernet/synopsys/dwc_eth_qos.c
+++ linux-4.4.0/drivers/net/ethernet/synopsys/dwc_eth_qos.c
@@ -2107,7 +2107,7 @@
 			dd = &lp->tx_descs[lp->tx_next];
 
 			/* Set DMA Descriptor fields */
-			dd->des0 = dma_handle;
+			dd->des0 = dma_handle + consumed_size;
 			dd->des1 = 0;
 			dd->des2 = dma_size;
 
--- linux-4.4.0.orig/drivers/net/ethernet/ti/cpmac.c
+++ linux-4.4.0/drivers/net/ethernet/ti/cpmac.c
@@ -549,7 +549,8 @@
 
 static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	int queue, len;
+	int queue;
+	unsigned int len;
 	struct cpmac_desc *desc;
 	struct cpmac_priv *priv = netdev_priv(dev);
 
@@ -559,7 +560,7 @@
 	if (unlikely(skb_padto(skb, ETH_ZLEN)))
 		return NETDEV_TX_OK;
 
-	len = max(skb->len, ETH_ZLEN);
+	len = max_t(unsigned int, skb->len, ETH_ZLEN);
 	queue = skb_get_queue_mapping(skb);
 	netif_stop_subqueue(dev, queue);
 
@@ -1236,7 +1237,7 @@
 		goto fail_alloc;
 	}
 
-#warning FIXME: unhardcode gpio&reset bits
+	/* FIXME: unhardcode gpio&reset bits */
 	ar7_gpio_disable(26);
 	ar7_gpio_disable(27);
 	ar7_device_reset(AR7_RESET_BIT_CPMAC_LO);
--- linux-4.4.0.orig/drivers/net/ethernet/ti/cpsw-phy-sel.c
+++ linux-4.4.0/drivers/net/ethernet/ti/cpsw-phy-sel.c
@@ -154,9 +154,12 @@
 	}
 
 	dev = bus_find_device(&platform_bus_type, NULL, node, match);
+	of_node_put(node);
 	priv = dev_get_drvdata(dev);
 
 	priv->cpsw_phy_sel(priv, phy_mode, slave);
+
+	put_device(dev);
 }
 EXPORT_SYMBOL_GPL(cpsw_phy_sel);
 
--- linux-4.4.0.orig/drivers/net/ethernet/ti/cpsw.c
+++ linux-4.4.0/drivers/net/ethernet/ti/cpsw.c
@@ -280,6 +280,10 @@
 /* Bit definitions for the CPSW1_TS_SEQ_LTYPE register */
 #define CPSW_V1_SEQ_ID_OFS_SHIFT	16
 
+#define CPSW_MAX_BLKS_TX		15
+#define CPSW_MAX_BLKS_TX_SHIFT		4
+#define CPSW_MAX_BLKS_RX		5
+
 struct cpsw_host_regs {
 	u32	max_blks;
 	u32	blk_cnt;
@@ -367,7 +371,6 @@
 	spinlock_t			lock;
 	struct platform_device		*pdev;
 	struct net_device		*ndev;
-	struct device_node		*phy_node;
 	struct napi_struct		napi_rx;
 	struct napi_struct		napi_tx;
 	struct device			*dev;
@@ -742,6 +745,7 @@
 		netif_receive_skb(skb);
 		ndev->stats.rx_bytes += len;
 		ndev->stats.rx_packets++;
+		kmemleak_not_leak(new_skb);
 	} else {
 		ndev->stats.rx_dropped++;
 		new_skb = skb;
@@ -774,8 +778,8 @@
 {
 	struct cpsw_priv *priv = dev_id;
 
-	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
 	writel(0, &priv->wr_regs->rx_en);
+	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
 
 	if (priv->quirk_irq) {
 		disable_irq_nosync(priv->irqs_table[0]);
@@ -878,7 +882,8 @@
 		/* set speed_in input in case RMII mode is used in 100Mbps */
 		if (phy->speed == 100)
 			mac_control |= BIT(15);
-		else if (phy->speed == 10)
+		/* in band mode only works in 10Mbps RGMII mode */
+		else if ((phy->speed == 10) && phy_interface_is_rgmii(phy))
 			mac_control |= BIT(18); /* In Band mode */
 
 		if (priv->rx_pause)
@@ -1126,11 +1131,23 @@
 	switch (priv->version) {
 	case CPSW_VERSION_1:
 		slave_write(slave, TX_PRIORITY_MAPPING, CPSW1_TX_PRI_MAP);
+		/* Increase RX FIFO size to 5 for supporting fullduplex
+		 * flow control mode
+		 */
+		slave_write(slave,
+			    (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) |
+			    CPSW_MAX_BLKS_RX, CPSW1_MAX_BLKS);
 		break;
 	case CPSW_VERSION_2:
 	case CPSW_VERSION_3:
 	case CPSW_VERSION_4:
 		slave_write(slave, TX_PRIORITY_MAPPING, CPSW2_TX_PRI_MAP);
+		/* Increase RX FIFO size to 5 for supporting fullduplex
+		 * flow control mode
+		 */
+		slave_write(slave,
+			    (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) |
+			    CPSW_MAX_BLKS_RX, CPSW2_MAX_BLKS);
 		break;
 	}
 
@@ -1148,25 +1165,34 @@
 		cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
 				   1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
 
-	if (priv->phy_node)
-		slave->phy = of_phy_connect(priv->ndev, priv->phy_node,
+	if (slave->data->phy_node) {
+		slave->phy = of_phy_connect(priv->ndev, slave->data->phy_node,
 				 &cpsw_adjust_link, 0, slave->data->phy_if);
-	else
+		if (!slave->phy) {
+			dev_err(priv->dev, "phy \"%s\" not found on slave %d\n",
+				slave->data->phy_node->full_name,
+				slave->slave_num);
+			return;
+		}
+	} else {
 		slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
 				 &cpsw_adjust_link, slave->data->phy_if);
-	if (IS_ERR(slave->phy)) {
-		dev_err(priv->dev, "phy %s not found on slave %d\n",
-			slave->data->phy_id, slave->slave_num);
-		slave->phy = NULL;
-	} else {
-		dev_info(priv->dev, "phy found : id is : 0x%x\n",
-			 slave->phy->phy_id);
-		phy_start(slave->phy);
-
-		/* Configure GMII_SEL register */
-		cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface,
-			     slave->slave_num);
+		if (IS_ERR(slave->phy)) {
+			dev_err(priv->dev,
+				"phy \"%s\" not found on slave %d, err %ld\n",
+				slave->data->phy_id, slave->slave_num,
+				PTR_ERR(slave->phy));
+			slave->phy = NULL;
+			return;
+		}
 	}
+
+	dev_info(priv->dev, "phy found : id is : 0x%x\n", slave->phy->phy_id);
+
+	phy_start(slave->phy);
+
+	/* Configure GMII_SEL register */
+	cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface, slave->slave_num);
 }
 
 static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
@@ -1243,6 +1269,7 @@
 	slave->phy = NULL;
 	cpsw_ale_control_set(priv->ale, slave_port,
 			     ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
+	soft_reset_slave(slave);
 }
 
 static int cpsw_ndo_open(struct net_device *ndev)
@@ -1251,12 +1278,16 @@
 	int i, ret;
 	u32 reg;
 
+	ret = pm_runtime_get_sync(&priv->pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&priv->pdev->dev);
+		return ret;
+	}
+
 	if (!cpsw_common_res_usage_state(priv))
 		cpsw_intr_disable(priv);
 	netif_carrier_off(ndev);
 
-	pm_runtime_get_sync(&priv->pdev->dev);
-
 	reg = priv->version;
 
 	dev_info(priv->dev, "initializing cpsw version %d.%d (%d)\n",
@@ -1322,6 +1353,7 @@
 				kfree_skb(skb);
 				goto err_cleanup;
 			}
+			kmemleak_not_leak(skb);
 		}
 		/* continue even if we didn't manage to submit all
 		 * receive descs
@@ -1611,10 +1643,17 @@
 	struct sockaddr *addr = (struct sockaddr *)p;
 	int flags = 0;
 	u16 vid = 0;
+	int ret;
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
+	ret = pm_runtime_get_sync(&priv->pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&priv->pdev->dev);
+		return ret;
+	}
+
 	if (priv->data.dual_emac) {
 		vid = priv->slaves[priv->emac_port].port_vlan;
 		flags = ALE_VLAN;
@@ -1629,6 +1668,8 @@
 	memcpy(ndev->dev_addr, priv->mac_addr, ETH_ALEN);
 	for_each_slave(priv, cpsw_set_slave_mac, priv);
 
+	pm_runtime_put(&priv->pdev->dev);
+
 	return 0;
 }
 
@@ -1693,10 +1734,17 @@
 				    __be16 proto, u16 vid)
 {
 	struct cpsw_priv *priv = netdev_priv(ndev);
+	int ret;
 
 	if (vid == priv->data.default_vlan)
 		return 0;
 
+	ret = pm_runtime_get_sync(&priv->pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&priv->pdev->dev);
+		return ret;
+	}
+
 	if (priv->data.dual_emac) {
 		/* In dual EMAC, reserved VLAN id should not be used for
 		 * creating VLAN interfaces as this can break the dual
@@ -1711,7 +1759,10 @@
 	}
 
 	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
-	return cpsw_add_vlan_ale_entry(priv, vid);
+	ret = cpsw_add_vlan_ale_entry(priv, vid);
+
+	pm_runtime_put(&priv->pdev->dev);
+	return ret;
 }
 
 static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
@@ -1723,6 +1774,12 @@
 	if (vid == priv->data.default_vlan)
 		return 0;
 
+	ret = pm_runtime_get_sync(&priv->pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&priv->pdev->dev);
+		return ret;
+	}
+
 	if (priv->data.dual_emac) {
 		int i;
 
@@ -1742,8 +1799,10 @@
 	if (ret != 0)
 		return ret;
 
-	return cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast,
-				  0, ALE_VLAN, vid);
+	ret = cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast,
+				 0, ALE_VLAN, vid);
+	pm_runtime_put(&priv->pdev->dev);
+	return ret;
 }
 
 static const struct net_device_ops cpsw_netdev_ops = {
@@ -1902,10 +1961,33 @@
 	priv->tx_pause = pause->tx_pause ? true : false;
 
 	for_each_slave(priv, _cpsw_adjust_link, priv, &link);
-
 	return 0;
 }
 
+static int cpsw_ethtool_op_begin(struct net_device *ndev)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+	int ret;
+
+	ret = pm_runtime_get_sync(&priv->pdev->dev);
+	if (ret < 0) {
+		cpsw_err(priv, drv, "ethtool begin failed %d\n", ret);
+		pm_runtime_put_noidle(&priv->pdev->dev);
+	}
+
+	return ret;
+}
+
+static void cpsw_ethtool_op_complete(struct net_device *ndev)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+	int ret;
+
+	ret = pm_runtime_put(&priv->pdev->dev);
+	if (ret < 0)
+		cpsw_err(priv, drv, "ethtool complete failed %d\n", ret);
+}
+
 static const struct ethtool_ops cpsw_ethtool_ops = {
 	.get_drvinfo	= cpsw_get_drvinfo,
 	.get_msglevel	= cpsw_get_msglevel,
@@ -1925,6 +2007,8 @@
 	.set_wol	= cpsw_set_wol,
 	.get_regs_len	= cpsw_get_regs_len,
 	.get_regs	= cpsw_get_regs,
+	.begin		= cpsw_ethtool_op_begin,
+	.complete	= cpsw_ethtool_op_complete,
 };
 
 static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1940,12 +2024,11 @@
 	slave->port_vlan = data->dual_emac_res_vlan;
 }
 
-static int cpsw_probe_dt(struct cpsw_priv *priv,
+static int cpsw_probe_dt(struct cpsw_platform_data *data,
 			 struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
 	struct device_node *slave_node;
-	struct cpsw_platform_data *data = &priv->data;
 	int i = 0, ret;
 	u32 prop;
 
@@ -2033,9 +2116,14 @@
 		if (strcmp(slave_node->name, "slave"))
 			continue;
 
-		priv->phy_node = of_parse_phandle(slave_node, "phy-handle", 0);
+		slave_data->phy_node = of_parse_phandle(slave_node,
+							"phy-handle", 0);
 		parp = of_get_property(slave_node, "phy_id", &lenp);
-		if (of_phy_is_fixed_link(slave_node)) {
+		if (slave_data->phy_node) {
+			dev_dbg(&pdev->dev,
+				"slave[%d] using phy-handle=\"%s\"\n",
+				i, slave_data->phy_node->full_name);
+		} else if (of_phy_is_fixed_link(slave_node)) {
 			struct device_node *phy_node;
 			struct phy_device *phy_dev;
 
@@ -2070,8 +2158,11 @@
 			}
 			snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
 				 PHY_ID_FMT, mdio->name, phyid);
+			put_device(&mdio->dev);
 		} else {
-			dev_err(&pdev->dev, "No slave[%d] phy_id or fixed-link property\n", i);
+			dev_err(&pdev->dev,
+				"No slave[%d] phy_id, phy-handle, or fixed-link property\n",
+				i);
 			goto no_phy_slave;
 		}
 		slave_data->phy_if = of_get_phy_mode(slave_node);
@@ -2274,7 +2365,7 @@
 	/* Select default pin state */
 	pinctrl_pm_select_default_state(&pdev->dev);
 
-	if (cpsw_probe_dt(priv, pdev)) {
+	if (cpsw_probe_dt(&priv->data, pdev)) {
 		dev_err(&pdev->dev, "cpsw: platform data missing\n");
 		ret = -ENODEV;
 		goto clean_runtime_disable_ret;
@@ -2325,7 +2416,11 @@
 	/* Need to enable clocks with runtime PM api to access module
 	 * registers
 	 */
-	pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&pdev->dev);
+		goto clean_runtime_disable_ret;
+	}
 	priv->version = readl(&priv->regs->id_ver);
 	pm_runtime_put_sync(&pdev->dev);
 
@@ -2500,12 +2595,14 @@
 		ret = cpsw_probe_dual_emac(pdev, priv);
 		if (ret) {
 			cpsw_err(priv, probe, "error probe slave 2 emac interface\n");
-			goto clean_ale_ret;
+			goto clean_unregister_netdev_ret;
 		}
 	}
 
 	return 0;
 
+clean_unregister_netdev_ret:
+	unregister_netdev(ndev);
 clean_ale_ret:
 	cpsw_ale_destroy(priv->ale);
 clean_dma_ret:
@@ -2519,19 +2616,17 @@
 	return ret;
 }
 
-static int cpsw_remove_child_device(struct device *dev, void *c)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-
-	of_device_unregister(pdev);
-
-	return 0;
-}
-
 static int cpsw_remove(struct platform_device *pdev)
 {
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct cpsw_priv *priv = netdev_priv(ndev);
+	int ret;
+
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&pdev->dev);
+		return ret;
+	}
 
 	if (priv->data.dual_emac)
 		unregister_netdev(cpsw_get_slave_ndev(priv, 1));
@@ -2541,8 +2636,9 @@
 	cpdma_chan_destroy(priv->txch);
 	cpdma_chan_destroy(priv->rxch);
 	cpdma_ctlr_destroy(priv->dma);
+	of_platform_depopulate(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
-	device_for_each_child(&pdev->dev, NULL, cpsw_remove_child_device);
 	if (priv->data.dual_emac)
 		free_netdev(cpsw_get_slave_ndev(priv, 1));
 	free_netdev(ndev);
@@ -2562,16 +2658,12 @@
 		for (i = 0; i < priv->data.slaves; i++) {
 			if (netif_running(priv->slaves[i].ndev))
 				cpsw_ndo_stop(priv->slaves[i].ndev);
-			soft_reset_slave(priv->slaves + i);
 		}
 	} else {
 		if (netif_running(ndev))
 			cpsw_ndo_stop(ndev);
-		for_each_slave(priv, soft_reset_slave);
 	}
 
-	pm_runtime_put_sync(&pdev->dev);
-
 	/* Select sleep pin state */
 	pinctrl_pm_select_sleep_state(&pdev->dev);
 
@@ -2584,8 +2676,6 @@
 	struct net_device	*ndev = platform_get_drvdata(pdev);
 	struct cpsw_priv	*priv = netdev_priv(ndev);
 
-	pm_runtime_get_sync(&pdev->dev);
-
 	/* Select default pin state */
 	pinctrl_pm_select_default_state(&pdev->dev);
 
--- linux-4.4.0.orig/drivers/net/ethernet/ti/cpsw.h
+++ linux-4.4.0/drivers/net/ethernet/ti/cpsw.h
@@ -18,6 +18,7 @@
 #include <linux/phy.h>
 
 struct cpsw_slave_data {
+	struct device_node *phy_node;
 	char		phy_id[MII_BUS_ID_SIZE];
 	int		phy_if;
 	u8		mac_addr[ETH_ALEN];
--- linux-4.4.0.orig/drivers/net/ethernet/ti/davinci_cpdma.c
+++ linux-4.4.0/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -82,7 +82,7 @@
 
 struct cpdma_desc_pool {
 	phys_addr_t		phys;
-	u32			hw_addr;
+	dma_addr_t		hw_addr;
 	void __iomem		*iomap;		/* ioremap map */
 	void			*cpumap;	/* dma_alloc map */
 	int			desc_size, mem_size;
@@ -152,7 +152,7 @@
  * abstract out these details
  */
 static struct cpdma_desc_pool *
-cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr,
+cpdma_desc_pool_create(struct device *dev, u32 phys, dma_addr_t hw_addr,
 				int size, int align)
 {
 	int bitmap_size;
@@ -176,13 +176,13 @@
 
 	if (phys) {
 		pool->phys  = phys;
-		pool->iomap = ioremap(phys, size);
+		pool->iomap = ioremap(phys, size); /* should be memremap? */
 		pool->hw_addr = hw_addr;
 	} else {
-		pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys,
+		pool->cpumap = dma_alloc_coherent(dev, size, &pool->hw_addr,
 						  GFP_KERNEL);
-		pool->iomap = pool->cpumap;
-		pool->hw_addr = pool->phys;
+		pool->iomap = (void __iomem __force *)pool->cpumap;
+		pool->phys = pool->hw_addr; /* assumes no IOMMU, don't use this value */
 	}
 
 	if (pool->iomap)
@@ -442,13 +442,11 @@
 
 int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
 {
-	unsigned long flags;
 	int ret = 0, i;
 
 	if (!ctlr)
 		return -EINVAL;
 
-	spin_lock_irqsave(&ctlr->lock, flags);
 	if (ctlr->state != CPDMA_STATE_IDLE)
 		cpdma_ctlr_stop(ctlr);
 
@@ -456,7 +454,6 @@
 		cpdma_chan_destroy(ctlr->channels[i]);
 
 	cpdma_desc_pool_destroy(ctlr->pool);
-	spin_unlock_irqrestore(&ctlr->lock, flags);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy);
--- linux-4.4.0.orig/drivers/net/ethernet/ti/davinci_emac.c
+++ linux-4.4.0/drivers/net/ethernet/ti/davinci_emac.c
@@ -1512,11 +1512,18 @@
 
 	/* TODO: Add phy read and write and private statistics get feature */
 
-	return phy_mii_ioctl(priv->phydev, ifrq, cmd);
+	if (priv->phydev)
+		return phy_mii_ioctl(priv->phydev, ifrq, cmd);
+	else
+		return -EOPNOTSUPP;
 }
 
 static int match_first_device(struct device *dev, void *data)
 {
+	if (dev->parent && dev->parent->of_node)
+		return of_device_is_compatible(dev->parent->of_node,
+					       "ti,davinci_mdio");
+
 	return !strncmp(dev_name(dev), "davinci_mdio", 12);
 }
 
@@ -1881,8 +1888,6 @@
 		pdata->hw_ram_addr = auxdata->hw_ram_addr;
 	}
 
-	pdev->dev.platform_data = pdata;
-
 	return  pdata;
 }
 
@@ -2104,6 +2109,7 @@
 	cpdma_ctlr_destroy(priv->dma);
 
 	unregister_netdev(ndev);
+	of_node_put(priv->phy_node);
 	free_netdev(ndev);
 
 	return 0;
--- linux-4.4.0.orig/drivers/net/ethernet/ti/netcp_core.c
+++ linux-4.4.0/drivers/net/ethernet/ti/netcp_core.c
@@ -1811,22 +1811,26 @@
 	return 0;
 }
 
-static int netcp_setup_tc(struct net_device *dev, u8 num_tc)
+static int netcp_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+			  struct tc_to_netdev tc)
 {
 	int i;
 
 	/* setup tc must be called under rtnl lock */
 	ASSERT_RTNL();
 
+	if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
+		return -EINVAL;
+
 	/* Sanity-check the number of traffic classes requested */
 	if ((dev->real_num_tx_queues <= 1) ||
-	    (dev->real_num_tx_queues < num_tc))
+	    (dev->real_num_tx_queues < tc->tc))
 		return -EINVAL;
 
 	/* Configure traffic class to queue mappings */
-	if (num_tc) {
-		netdev_set_num_tc(dev, num_tc);
-		for (i = 0; i < num_tc; i++)
+	if (tc->tc) {
+		netdev_set_num_tc(dev, tc->tc);
+		for (i = 0; i < tc->tc; i++)
 			netdev_set_tc_queue(dev, i, 1, i);
 	} else {
 		netdev_reset_tc(dev);
--- linux-4.4.0.orig/drivers/net/ethernet/ti/netcp_ethss.c
+++ linux-4.4.0/drivers/net/ethernet/ti/netcp_ethss.c
@@ -3122,12 +3122,16 @@
 
 	ret = netcp_txpipe_init(&gbe_dev->tx_pipe, netcp_device,
 				gbe_dev->dma_chan_name, gbe_dev->tx_queue_id);
-	if (ret)
+	if (ret) {
+		of_node_put(interfaces);
 		return ret;
+	}
 
 	ret = netcp_txpipe_open(&gbe_dev->tx_pipe);
-	if (ret)
+	if (ret) {
+		of_node_put(interfaces);
 		return ret;
+	}
 
 	/* Create network interfaces */
 	INIT_LIST_HEAD(&gbe_dev->gbe_intf_head);
--- linux-4.4.0.orig/drivers/net/ethernet/ti/tlan.c
+++ linux-4.4.0/drivers/net/ethernet/ti/tlan.c
@@ -610,8 +610,8 @@
 #ifdef CONFIG_PCI
 	if (pdev)
 		pci_release_regions(pdev);
-#endif
 err_out:
+#endif
 	if (pdev)
 		pci_disable_device(pdev);
 	return rc;
--- linux-4.4.0.orig/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ linux-4.4.0/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -845,9 +845,9 @@
  * @skb: packet to send out
  * @netdev: interface device structure
  *
- * returns 0 on success, <0 on failure
+ * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure
  */
-int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
+netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct gelic_card *card = netdev_card(netdev);
 	struct gelic_descr *descr;
--- linux-4.4.0.orig/drivers/net/ethernet/toshiba/ps3_gelic_net.h
+++ linux-4.4.0/drivers/net/ethernet/toshiba/ps3_gelic_net.h
@@ -370,7 +370,7 @@
 void gelic_card_down(struct gelic_card *card);
 int gelic_net_open(struct net_device *netdev);
 int gelic_net_stop(struct net_device *netdev);
-int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev);
+netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev);
 void gelic_net_set_multi(struct net_device *netdev);
 void gelic_net_tx_timeout(struct net_device *netdev);
 int gelic_net_change_mtu(struct net_device *netdev, int new_mtu);
--- linux-4.4.0.orig/drivers/net/ethernet/toshiba/spider_net.c
+++ linux-4.4.0/drivers/net/ethernet/toshiba/spider_net.c
@@ -297,8 +297,8 @@
 		descr = descr->next;
 	} while (descr != chain->ring);
 
-	dma_free_coherent(&card->pdev->dev, chain->num_desc,
-	    chain->hwring, chain->dma_addr);
+	dma_free_coherent(&card->pdev->dev, chain->num_desc * sizeof(struct spider_net_hw_descr),
+			  chain->hwring, chain->dma_addr);
 }
 
 /**
@@ -881,9 +881,9 @@
  * @skb: packet to send out
  * @netdev: interface device structure
  *
- * returns 0 on success, !0 on failure
+ * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure
  */
-static int
+static netdev_tx_t
 spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	int cnt;
--- linux-4.4.0.orig/drivers/net/ethernet/toshiba/tc35815.c
+++ linux-4.4.0/drivers/net/ethernet/toshiba/tc35815.c
@@ -475,7 +475,8 @@
 /* Index to functions, as function prototypes. */
 
 static int	tc35815_open(struct net_device *dev);
-static int	tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t	tc35815_send_packet(struct sk_buff *skb,
+					    struct net_device *dev);
 static irqreturn_t	tc35815_interrupt(int irq, void *dev_id);
 static int	tc35815_rx(struct net_device *dev, int limit);
 static int	tc35815_poll(struct napi_struct *napi, int budget);
@@ -1279,7 +1280,8 @@
  * invariant will hold if you make sure that the netif_*_queue()
  * calls are done at the proper times.
  */
-static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tc35815_local *lp = netdev_priv(dev);
 	struct TxFD *txfd;
@@ -1528,7 +1530,7 @@
 			pci_unmap_single(lp->pci_dev,
 					 lp->rx_skbs[cur_bd].skb_dma,
 					 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-			if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN)
+			if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN != 0)
 				memmove(skb->data, skb->data - NET_IP_ALIGN,
 					pkt_len);
 			data = skb_put(skb, pkt_len);
--- linux-4.4.0.orig/drivers/net/ethernet/tundra/tsi108_eth.c
+++ linux-4.4.0/drivers/net/ethernet/tundra/tsi108_eth.c
@@ -379,9 +379,10 @@
 static void tsi108_stat_carry(struct net_device *dev)
 {
 	struct tsi108_prv_data *data = netdev_priv(dev);
+	unsigned long flags;
 	u32 carry1, carry2;
 
-	spin_lock_irq(&data->misclock);
+	spin_lock_irqsave(&data->misclock, flags);
 
 	carry1 = TSI_READ(TSI108_STAT_CARRY1);
 	carry2 = TSI_READ(TSI108_STAT_CARRY2);
@@ -449,7 +450,7 @@
 			      TSI108_STAT_TXPAUSEDROP_CARRY,
 			      &data->tx_pause_drop);
 
-	spin_unlock_irq(&data->misclock);
+	spin_unlock_irqrestore(&data->misclock, flags);
 }
 
 /* Read a stat counter atomically with respect to carries.
--- linux-4.4.0.orig/drivers/net/ethernet/xilinx/Kconfig
+++ linux-4.4.0/drivers/net/ethernet/xilinx/Kconfig
@@ -34,6 +34,7 @@
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
 	depends on (PPC || MICROBLAZE)
+	depends on !64BIT || BROKEN
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
--- linux-4.4.0.orig/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ linux-4.4.0/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -673,7 +673,8 @@
 	return 0;
 }
 
-static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t
+temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct cdmac_bd *cur_p;
--- linux-4.4.0.orig/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ linux-4.4.0/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -613,6 +613,10 @@
 
 	ndev->stats.tx_packets += packets;
 	ndev->stats.tx_bytes += size;
+
+	/* Matches barrier in axienet_start_xmit */
+	smp_mb();
+
 	netif_wake_queue(ndev);
 }
 
@@ -652,7 +656,8 @@
  * start the transmission. Additionally if checksum offloading is supported,
  * it populates AXI Stream Control fields with appropriate values.
  */
-static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t
+axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	u32 ii;
 	u32 num_frag;
@@ -667,9 +672,19 @@
 	cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
 	if (axienet_check_tx_bd_space(lp, num_frag)) {
-		if (!netif_queue_stopped(ndev))
-			netif_stop_queue(ndev);
-		return NETDEV_TX_BUSY;
+		if (netif_queue_stopped(ndev))
+			return NETDEV_TX_BUSY;
+
+		netif_stop_queue(ndev);
+
+		/* Matches barrier in axienet_start_xmit_done */
+		smp_mb();
+
+		/* Space might have just been freed - check again */
+		if (axienet_check_tx_bd_space(lp, num_frag))
+			return NETDEV_TX_BUSY;
+
+		netif_wake_queue(ndev);
 	}
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -1587,20 +1602,22 @@
 
 	/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
 	np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);
-	if (IS_ERR(np)) {
+	if (!np) {
 		dev_err(&pdev->dev, "could not find DMA node\n");
-		ret = PTR_ERR(np);
+		ret = -ENODEV;
 		goto free_netdev;
 	}
 	ret = of_address_to_resource(np, 0, &dmares);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to get DMA resource\n");
+		of_node_put(np);
 		goto free_netdev;
 	}
 	lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares);
 	if (IS_ERR(lp->dma_regs)) {
 		dev_err(&pdev->dev, "could not map DMA regs\n");
 		ret = PTR_ERR(lp->dma_regs);
+		of_node_put(np);
 		goto free_netdev;
 	}
 	lp->rx_irq = irq_of_parse_and_map(np, 1);
--- linux-4.4.0.orig/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+++ linux-4.4.0/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
@@ -218,6 +218,7 @@
 	ret = of_mdiobus_register(bus, np1);
 	if (ret) {
 		mdiobus_free(bus);
+		lp->mii_bus = NULL;
 		return ret;
 	}
 	return 0;
--- linux-4.4.0.orig/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ linux-4.4.0/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -100,6 +100,14 @@
 /* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */
 #define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32) adr)) % ALIGNMENT)
 
+#ifdef __BIG_ENDIAN
+#define xemaclite_readl		ioread32be
+#define xemaclite_writel	iowrite32be
+#else
+#define xemaclite_readl		ioread32
+#define xemaclite_writel	iowrite32
+#endif
+
 /**
  * struct net_local - Our private per device data
  * @ndev:		instance of the network device
@@ -158,15 +166,15 @@
 	u32 reg_data;
 
 	/* Enable the Tx interrupts for the first Buffer */
-	reg_data = __raw_readl(drvdata->base_addr + XEL_TSR_OFFSET);
-	__raw_writel(reg_data | XEL_TSR_XMIT_IE_MASK,
-		     drvdata->base_addr + XEL_TSR_OFFSET);
+	reg_data = xemaclite_readl(drvdata->base_addr + XEL_TSR_OFFSET);
+	xemaclite_writel(reg_data | XEL_TSR_XMIT_IE_MASK,
+			 drvdata->base_addr + XEL_TSR_OFFSET);
 
 	/* Enable the Rx interrupts for the first buffer */
-	__raw_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr + XEL_RSR_OFFSET);
+	xemaclite_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr + XEL_RSR_OFFSET);
 
 	/* Enable the Global Interrupt Enable */
-	__raw_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET);
+	xemaclite_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET);
 }
 
 /**
@@ -181,17 +189,17 @@
 	u32 reg_data;
 
 	/* Disable the Global Interrupt Enable */
-	__raw_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET);
+	xemaclite_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET);
 
 	/* Disable the Tx interrupts for the first buffer */
-	reg_data = __raw_readl(drvdata->base_addr + XEL_TSR_OFFSET);
-	__raw_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK),
-		     drvdata->base_addr + XEL_TSR_OFFSET);
+	reg_data = xemaclite_readl(drvdata->base_addr + XEL_TSR_OFFSET);
+	xemaclite_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK),
+			 drvdata->base_addr + XEL_TSR_OFFSET);
 
 	/* Disable the Rx interrupts for the first buffer */
-	reg_data = __raw_readl(drvdata->base_addr + XEL_RSR_OFFSET);
-	__raw_writel(reg_data & (~XEL_RSR_RECV_IE_MASK),
-		     drvdata->base_addr + XEL_RSR_OFFSET);
+	reg_data = xemaclite_readl(drvdata->base_addr + XEL_RSR_OFFSET);
+	xemaclite_writel(reg_data & (~XEL_RSR_RECV_IE_MASK),
+			 drvdata->base_addr + XEL_RSR_OFFSET);
 }
 
 /**
@@ -323,7 +331,7 @@
 		byte_count = ETH_FRAME_LEN;
 
 	/* Check if the expected buffer is available */
-	reg_data = __raw_readl(addr + XEL_TSR_OFFSET);
+	reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET);
 	if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK |
 	     XEL_TSR_XMIT_ACTIVE_MASK)) == 0) {
 
@@ -336,7 +344,7 @@
 
 		addr = (void __iomem __force *)((u32 __force)addr ^
 						 XEL_BUFFER_OFFSET);
-		reg_data = __raw_readl(addr + XEL_TSR_OFFSET);
+		reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET);
 
 		if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK |
 		     XEL_TSR_XMIT_ACTIVE_MASK)) != 0)
@@ -347,16 +355,16 @@
 	/* Write the frame to the buffer */
 	xemaclite_aligned_write(data, (u32 __force *) addr, byte_count);
 
-	__raw_writel((byte_count & XEL_TPLR_LENGTH_MASK),
-		     addr + XEL_TPLR_OFFSET);
+	xemaclite_writel((byte_count & XEL_TPLR_LENGTH_MASK),
+			 addr + XEL_TPLR_OFFSET);
 
 	/* Update the Tx Status Register to indicate that there is a
 	 * frame to send. Set the XEL_TSR_XMIT_ACTIVE_MASK flag which
 	 * is used by the interrupt handler to check whether a frame
 	 * has been transmitted */
-	reg_data = __raw_readl(addr + XEL_TSR_OFFSET);
+	reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET);
 	reg_data |= (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK);
-	__raw_writel(reg_data, addr + XEL_TSR_OFFSET);
+	xemaclite_writel(reg_data, addr + XEL_TSR_OFFSET);
 
 	return 0;
 }
@@ -371,7 +379,7 @@
  *
  * Return:	Total number of bytes received
  */
-static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
+static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data, int maxlen)
 {
 	void __iomem *addr;
 	u16 length, proto_type;
@@ -381,7 +389,7 @@
 	addr = (drvdata->base_addr + drvdata->next_rx_buf_to_use);
 
 	/* Verify which buffer has valid data */
-	reg_data = __raw_readl(addr + XEL_RSR_OFFSET);
+	reg_data = xemaclite_readl(addr + XEL_RSR_OFFSET);
 
 	if ((reg_data & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
 		if (drvdata->rx_ping_pong != 0)
@@ -398,27 +406,28 @@
 			return 0;	/* No data was available */
 
 		/* Verify that buffer has valid data */
-		reg_data = __raw_readl(addr + XEL_RSR_OFFSET);
+		reg_data = xemaclite_readl(addr + XEL_RSR_OFFSET);
 		if ((reg_data & XEL_RSR_RECV_DONE_MASK) !=
 		     XEL_RSR_RECV_DONE_MASK)
 			return 0;	/* No data was available */
 	}
 
 	/* Get the protocol type of the ethernet frame that arrived */
-	proto_type = ((ntohl(__raw_readl(addr + XEL_HEADER_OFFSET +
+	proto_type = ((ntohl(xemaclite_readl(addr + XEL_HEADER_OFFSET +
 			XEL_RXBUFF_OFFSET)) >> XEL_HEADER_SHIFT) &
 			XEL_RPLR_LENGTH_MASK);
 
 	/* Check if received ethernet frame is a raw ethernet frame
 	 * or an IP packet or an ARP packet */
-	if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
+	if (proto_type > ETH_DATA_LEN) {
 
 		if (proto_type == ETH_P_IP) {
-			length = ((ntohl(__raw_readl(addr +
+			length = ((ntohl(xemaclite_readl(addr +
 					XEL_HEADER_IP_LENGTH_OFFSET +
 					XEL_RXBUFF_OFFSET)) >>
 					XEL_HEADER_SHIFT) &
 					XEL_RPLR_LENGTH_MASK);
+			length = min_t(u16, length, ETH_DATA_LEN);
 			length += ETH_HLEN + ETH_FCS_LEN;
 
 		} else if (proto_type == ETH_P_ARP)
@@ -431,14 +440,17 @@
 		/* Use the length in the frame, plus the header and trailer */
 		length = proto_type + ETH_HLEN + ETH_FCS_LEN;
 
+	if (WARN_ON(length > maxlen))
+		length = maxlen;
+
 	/* Read from the EmacLite device */
 	xemaclite_aligned_read((u32 __force *) (addr + XEL_RXBUFF_OFFSET),
 				data, length);
 
 	/* Acknowledge the frame */
-	reg_data = __raw_readl(addr + XEL_RSR_OFFSET);
+	reg_data = xemaclite_readl(addr + XEL_RSR_OFFSET);
 	reg_data &= ~XEL_RSR_RECV_DONE_MASK;
-	__raw_writel(reg_data, addr + XEL_RSR_OFFSET);
+	xemaclite_writel(reg_data, addr + XEL_RSR_OFFSET);
 
 	return length;
 }
@@ -465,14 +477,14 @@
 
 	xemaclite_aligned_write(address_ptr, (u32 __force *) addr, ETH_ALEN);
 
-	__raw_writel(ETH_ALEN, addr + XEL_TPLR_OFFSET);
+	xemaclite_writel(ETH_ALEN, addr + XEL_TPLR_OFFSET);
 
 	/* Update the MAC address in the EmacLite */
-	reg_data = __raw_readl(addr + XEL_TSR_OFFSET);
-	__raw_writel(reg_data | XEL_TSR_PROG_MAC_ADDR, addr + XEL_TSR_OFFSET);
+	reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET);
+	xemaclite_writel(reg_data | XEL_TSR_PROG_MAC_ADDR, addr + XEL_TSR_OFFSET);
 
 	/* Wait for EmacLite to finish with the MAC address update */
-	while ((__raw_readl(addr + XEL_TSR_OFFSET) &
+	while ((xemaclite_readl(addr + XEL_TSR_OFFSET) &
 		XEL_TSR_PROG_MAC_ADDR) != 0)
 		;
 }
@@ -605,7 +617,7 @@
 
 	skb_reserve(skb, 2);
 
-	len = xemaclite_recv_data(lp, (u8 *) skb->data);
+	len = xemaclite_recv_data(lp, (u8 *) skb->data, len);
 
 	if (!len) {
 		dev->stats.rx_errors++;
@@ -642,32 +654,32 @@
 	u32 tx_status;
 
 	/* Check if there is Rx Data available */
-	if ((__raw_readl(base_addr + XEL_RSR_OFFSET) &
+	if ((xemaclite_readl(base_addr + XEL_RSR_OFFSET) &
 			 XEL_RSR_RECV_DONE_MASK) ||
-	    (__raw_readl(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET)
+	    (xemaclite_readl(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET)
 			 & XEL_RSR_RECV_DONE_MASK))
 
 		xemaclite_rx_handler(dev);
 
 	/* Check if the Transmission for the first buffer is completed */
-	tx_status = __raw_readl(base_addr + XEL_TSR_OFFSET);
+	tx_status = xemaclite_readl(base_addr + XEL_TSR_OFFSET);
 	if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) &&
 		(tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) {
 
 		tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK;
-		__raw_writel(tx_status, base_addr + XEL_TSR_OFFSET);
+		xemaclite_writel(tx_status, base_addr + XEL_TSR_OFFSET);
 
 		tx_complete = true;
 	}
 
 	/* Check if the Transmission for the second buffer is completed */
-	tx_status = __raw_readl(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
+	tx_status = xemaclite_readl(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
 	if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) &&
 		(tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) {
 
 		tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK;
-		__raw_writel(tx_status, base_addr + XEL_BUFFER_OFFSET +
-			     XEL_TSR_OFFSET);
+		xemaclite_writel(tx_status, base_addr + XEL_BUFFER_OFFSET +
+				 XEL_TSR_OFFSET);
 
 		tx_complete = true;
 	}
@@ -700,7 +712,7 @@
 	/* wait for the MDIO interface to not be busy or timeout
 	   after some time.
 	*/
-	while (__raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
+	while (xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
 			XEL_MDIOCTRL_MDIOSTS_MASK) {
 		if (time_before_eq(end, jiffies)) {
 			WARN_ON(1);
@@ -736,17 +748,17 @@
 	 * MDIO Address register. Set the Status bit in the MDIO Control
 	 * register to start a MDIO read transaction.
 	 */
-	ctrl_reg = __raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET);
-	__raw_writel(XEL_MDIOADDR_OP_MASK |
-		     ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg),
-		     lp->base_addr + XEL_MDIOADDR_OFFSET);
-	__raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK,
-		     lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	ctrl_reg = xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	xemaclite_writel(XEL_MDIOADDR_OP_MASK |
+			 ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg),
+			 lp->base_addr + XEL_MDIOADDR_OFFSET);
+	xemaclite_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK,
+			 lp->base_addr + XEL_MDIOCTRL_OFFSET);
 
 	if (xemaclite_mdio_wait(lp))
 		return -ETIMEDOUT;
 
-	rc = __raw_readl(lp->base_addr + XEL_MDIORD_OFFSET);
+	rc = xemaclite_readl(lp->base_addr + XEL_MDIORD_OFFSET);
 
 	dev_dbg(&lp->ndev->dev,
 		"xemaclite_mdio_read(phy_id=%i, reg=%x) == %x\n",
@@ -783,13 +795,13 @@
 	 * Data register. Finally, set the Status bit in the MDIO Control
 	 * register to start a MDIO write transaction.
 	 */
-	ctrl_reg = __raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET);
-	__raw_writel(~XEL_MDIOADDR_OP_MASK &
-		     ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg),
-		     lp->base_addr + XEL_MDIOADDR_OFFSET);
-	__raw_writel(val, lp->base_addr + XEL_MDIOWR_OFFSET);
-	__raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK,
-		     lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	ctrl_reg = xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	xemaclite_writel(~XEL_MDIOADDR_OP_MASK &
+			 ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg),
+			 lp->base_addr + XEL_MDIOADDR_OFFSET);
+	xemaclite_writel(val, lp->base_addr + XEL_MDIOWR_OFFSET);
+	xemaclite_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK,
+			 lp->base_addr + XEL_MDIOCTRL_OFFSET);
 
 	return 0;
 }
@@ -836,8 +848,8 @@
 	/* Enable the MDIO bus by asserting the enable bit in MDIO Control
 	 * register.
 	 */
-	__raw_writel(XEL_MDIOCTRL_MDIOEN_MASK,
-		     lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	xemaclite_writel(XEL_MDIOCTRL_MDIOEN_MASK,
+			 lp->base_addr + XEL_MDIOCTRL_OFFSET);
 
 	bus = mdiobus_alloc();
 	if (!bus) {
@@ -996,9 +1008,10 @@
  * deferred and the Tx queue is stopped so that the deferred socket buffer can
  * be transmitted when the Emaclite device is free to transmit data.
  *
- * Return:	0, always.
+ * Return:	NETDEV_TX_OK, always.
  */
-static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
+static netdev_tx_t
+xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
 {
 	struct net_local *lp = netdev_priv(dev);
 	struct sk_buff *new_skb;
@@ -1019,7 +1032,7 @@
 		/* Take the time stamp now, since we can't do this in an ISR. */
 		skb_tx_timestamp(new_skb);
 		spin_unlock_irqrestore(&lp->reset_lock, flags);
-		return 0;
+		return NETDEV_TX_OK;
 	}
 	spin_unlock_irqrestore(&lp->reset_lock, flags);
 
@@ -1028,7 +1041,7 @@
 	dev->stats.tx_bytes += len;
 	dev_consume_skb_any(new_skb);
 
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 /**
@@ -1141,8 +1154,8 @@
 		dev_warn(dev, "No MAC address found\n");
 
 	/* Clear the Tx CSR's in case this is a restart */
-	__raw_writel(0, lp->base_addr + XEL_TSR_OFFSET);
-	__raw_writel(0, lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
+	xemaclite_writel(0, lp->base_addr + XEL_TSR_OFFSET);
+	xemaclite_writel(0, lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
 
 	/* Set the MAC address in the EmacLite device */
 	xemaclite_update_address(lp, ndev->dev_addr);
--- linux-4.4.0.orig/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ linux-4.4.0/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -504,6 +504,11 @@
 xirc2ps_detach(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
+    struct local_info *local = netdev_priv(dev);
+
+    netif_carrier_off(dev);
+    netif_tx_disable(dev);
+    cancel_work_sync(&local->tx_timeout_task);
 
     dev_dbg(&link->dev, "detach\n");
 
--- linux-4.4.0.orig/drivers/net/fjes/fjes_main.c
+++ linux-4.4.0/drivers/net/fjes/fjes_main.c
@@ -149,6 +149,9 @@
 	/* create platform_device */
 	plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource,
 						   ARRAY_SIZE(fjes_resource));
+	if (IS_ERR(plat_dev))
+		return PTR_ERR(plat_dev);
+
 	device->driver_data = plat_dev;
 
 	return 0;
@@ -1116,7 +1119,16 @@
 	adapter->open_guard = false;
 
 	adapter->txrx_wq = create_workqueue(DRV_NAME "/txrx");
+	if (unlikely(!adapter->txrx_wq)) {
+		err = -ENOMEM;
+		goto err_free_netdev;
+	}
+
 	adapter->control_wq = create_workqueue(DRV_NAME "/control");
+	if (unlikely(!adapter->control_wq)) {
+		err = -ENOMEM;
+		goto err_free_txrx_wq;
+	}
 
 	INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task);
 	INIT_WORK(&adapter->raise_intr_rxdata_task,
@@ -1133,7 +1145,7 @@
 	hw->hw_res.irq = platform_get_irq(plat_dev, 0);
 	err = fjes_hw_init(&adapter->hw);
 	if (err)
-		goto err_free_netdev;
+		goto err_free_control_wq;
 
 	/* setup MAC address (02:00:00:00:00:[epid])*/
 	netdev->dev_addr[0] = 2;
@@ -1153,6 +1165,10 @@
 
 err_hw_exit:
 	fjes_hw_exit(&adapter->hw);
+err_free_control_wq:
+	destroy_workqueue(adapter->control_wq);
+err_free_txrx_wq:
+	destroy_workqueue(adapter->txrx_wq);
 err_free_netdev:
 	free_netdev(netdev);
 err_out:
@@ -1205,7 +1221,7 @@
 	fjes_set_ethtool_ops(netdev);
 	netdev->mtu = fjes_support_mtu[0];
 	netdev->flags |= IFF_BROADCAST;
-	netdev->features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER;
+	netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 }
 
 static void fjes_irq_watch_task(struct work_struct *work)
--- linux-4.4.0.orig/drivers/net/geneve.c
+++ linux-4.4.0/drivers/net/geneve.c
@@ -71,8 +71,14 @@
 	__be16		   dst_port;
 	bool		   collect_md;
 	struct gro_cells   gro_cells;
+	u32		   flags;
 };
 
+/* Geneve device flags */
+#define GENEVE_F_UDP_CSUM		BIT(0)
+#define GENEVE_F_UDP_ZERO_CSUM6_TX	BIT(1)
+#define GENEVE_F_UDP_ZERO_CSUM6_RX	BIT(2)
+
 struct geneve_sock {
 	bool			collect_md;
 	struct list_head	list;
@@ -81,6 +87,7 @@
 	int			refcnt;
 	struct udp_offload	udp_offloads;
 	struct hlist_head	vni_list[VNI_HASH_SIZE];
+	u32			flags;
 };
 
 static inline __u32 geneve_net_vni_hash(u8 vni[3])
@@ -102,6 +109,11 @@
 #endif
 }
 
+static sa_family_t geneve_get_sk_family(struct geneve_sock *gs)
+{
+	return gs->sock->sk->sk_family;
+}
+
 static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
 					__be32 addr, u8 vni[])
 {
@@ -145,58 +157,80 @@
 	return (struct genevehdr *)(udp_hdr(skb) + 1);
 }
 
-/* geneve receive/decap routine */
-static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
+static struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
+					    struct sk_buff *skb)
 {
-	struct genevehdr *gnvh = geneve_hdr(skb);
-	struct metadata_dst *tun_dst = NULL;
-	struct geneve_dev *geneve = NULL;
-	struct pcpu_sw_netstats *stats;
-	struct iphdr *iph = NULL;
+	u8 *vni;
 	__be32 addr;
 	static u8 zero_vni[3];
-	u8 *vni;
-	int err = 0;
-	sa_family_t sa_family;
 #if IS_ENABLED(CONFIG_IPV6)
-	struct ipv6hdr *ip6h = NULL;
-	struct in6_addr addr6;
 	static struct in6_addr zero_addr6;
 #endif
 
-	sa_family = gs->sock->sk->sk_family;
+	if (geneve_get_sk_family(gs) == AF_INET) {
+		struct iphdr *iph;
 
-	if (sa_family == AF_INET) {
 		iph = ip_hdr(skb); /* outer IP header... */
 
 		if (gs->collect_md) {
 			vni = zero_vni;
 			addr = 0;
 		} else {
-			vni = gnvh->vni;
-
+			vni = geneve_hdr(skb)->vni;
 			addr = iph->saddr;
 		}
 
-		geneve = geneve_lookup(gs, addr, vni);
+		return geneve_lookup(gs, addr, vni);
 #if IS_ENABLED(CONFIG_IPV6)
-	} else if (sa_family == AF_INET6) {
+	} else if (geneve_get_sk_family(gs) == AF_INET6) {
+		struct ipv6hdr *ip6h;
+		struct in6_addr addr6;
+
 		ip6h = ipv6_hdr(skb); /* outer IPv6 header... */
 
 		if (gs->collect_md) {
 			vni = zero_vni;
 			addr6 = zero_addr6;
 		} else {
-			vni = gnvh->vni;
-
+			vni = geneve_hdr(skb)->vni;
 			addr6 = ip6h->saddr;
 		}
 
-		geneve = geneve6_lookup(gs, addr6, vni);
+		return geneve6_lookup(gs, addr6, vni);
 #endif
 	}
-	if (!geneve)
-		goto drop;
+	return NULL;
+}
+
+static inline bool geneve_pskb_inet_may_pull(struct sk_buff *skb)
+{
+	int nhlen;
+
+	switch (skb->protocol) {
+#if IS_ENABLED(CONFIG_IPV6)
+	case htons(ETH_P_IPV6):
+		nhlen = sizeof(struct ipv6hdr);
+		break;
+#endif
+	case htons(ETH_P_IP):
+		nhlen = sizeof(struct iphdr);
+		break;
+	default:
+		nhlen = 0;
+	}
+
+	return pskb_network_may_pull(skb, nhlen);
+}
+
+/* geneve receive/decap routine */
+static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
+		      struct sk_buff *skb)
+{
+	struct genevehdr *gnvh = geneve_hdr(skb);
+	struct metadata_dst *tun_dst = NULL;
+	struct pcpu_sw_netstats *stats;
+	int nh, err = 0;
+	void *oiph;
 
 	if (ip_tunnel_collect_metadata() || gs->collect_md) {
 		__be16 flags;
@@ -205,7 +239,7 @@
 			(gnvh->oam ? TUNNEL_OAM : 0) |
 			(gnvh->critical ? TUNNEL_CRIT_OPT : 0);
 
-		tun_dst = udp_tun_rx_dst(skb, sa_family, flags,
+		tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
 					 vni_to_tunnel_id(gnvh->vni),
 					 gnvh->opt_len * 4);
 		if (!tun_dst)
@@ -233,25 +267,41 @@
 	if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr))
 		goto drop;
 
+	/* Save offset of outer header relative to skb->head,
+	 * because we are going to reset the network header to the inner header
+	 * and might change skb->head.
+	 */
+	nh = skb_network_header(skb) - skb->head;
+
 	skb_reset_network_header(skb);
 
-	if (iph)
-		err = IP_ECN_decapsulate(iph, skb);
+	if (!geneve_pskb_inet_may_pull(skb)) {
+		geneve->dev->stats.rx_length_errors++;
+		geneve->dev->stats.rx_errors++;
+		goto drop;
+	}
+
+	/* Get the outer header. */
+	oiph = skb->head + nh;
+
+	if (geneve_get_sk_family(gs) == AF_INET)
+		err = IP_ECN_decapsulate(oiph, skb);
 #if IS_ENABLED(CONFIG_IPV6)
-	if (ip6h)
-		err = IP6_ECN_decapsulate(ip6h, skb);
+	else
+		err = IP6_ECN_decapsulate(oiph, skb);
 #endif
 
 	if (unlikely(err)) {
 		if (log_ecn_error) {
-			if (iph)
+			if (geneve_get_sk_family(gs) == AF_INET)
 				net_info_ratelimited("non-ECT from %pI4 "
 						     "with TOS=%#x\n",
-						     &iph->saddr, iph->tos);
+						     &((struct iphdr *)oiph)->saddr,
+						     ((struct iphdr *)oiph)->tos);
 #if IS_ENABLED(CONFIG_IPV6)
-			if (ip6h)
+			else
 				net_info_ratelimited("non-ECT from %pI6\n",
-						     &ip6h->saddr);
+						     &((struct ipv6hdr *)oiph)->saddr);
 #endif
 		}
 		if (err > 1) {
@@ -305,45 +355,46 @@
 static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
 	struct genevehdr *geneveh;
+	struct geneve_dev *geneve;
 	struct geneve_sock *gs;
 	int opts_len;
 
 	/* Need Geneve and inner Ethernet header to be present */
 	if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
-		goto error;
+		goto drop;
 
 	/* Return packets with reserved bits set */
 	geneveh = geneve_hdr(skb);
 	if (unlikely(geneveh->ver != GENEVE_VER))
-		goto error;
+		goto drop;
 
 	if (unlikely(geneveh->proto_type != htons(ETH_P_TEB)))
-		goto error;
-
-	opts_len = geneveh->opt_len * 4;
-	if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
-				 htons(ETH_P_TEB)))
 		goto drop;
 
 	gs = rcu_dereference_sk_user_data(sk);
 	if (!gs)
 		goto drop;
 
-	geneve_rx(gs, skb);
+	geneve = geneve_lookup_skb(gs, skb);
+	if (!geneve)
+		goto drop;
+
+	opts_len = geneveh->opt_len * 4;
+	if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
+				 htons(ETH_P_TEB)))
+		goto drop;
+
+	geneve_rx(geneve, gs, skb);
 	return 0;
 
 drop:
 	/* Consume bad packet */
 	kfree_skb(skb);
 	return 0;
-
-error:
-	/* Let the UDP layer deal with the skb */
-	return 1;
 }
 
 static struct socket *geneve_create_sock(struct net *net, bool ipv6,
-					 __be16 port)
+					 __be16 port, u32 flags)
 {
 	struct socket *sock;
 	struct udp_port_cfg udp_conf;
@@ -354,6 +405,8 @@
 	if (ipv6) {
 		udp_conf.family = AF_INET6;
 		udp_conf.ipv6_v6only = 1;
+		udp_conf.use_udp6_rx_checksums =
+		    !(flags & GENEVE_F_UDP_ZERO_CSUM6_RX);
 	} else {
 		udp_conf.family = AF_INET;
 		udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
@@ -371,8 +424,11 @@
 
 static void geneve_notify_add_rx_port(struct geneve_sock *gs)
 {
+	struct net_device *dev;
 	struct sock *sk = gs->sock->sk;
-	sa_family_t sa_family = sk->sk_family;
+	struct net *net = sock_net(sk);
+	sa_family_t sa_family = geneve_get_sk_family(gs);
+	__be16 port = inet_sk(sk)->inet_sport;
 	int err;
 
 	if (sa_family == AF_INET) {
@@ -381,6 +437,14 @@
 			pr_warn("geneve: udp_add_offload failed with status %d\n",
 				err);
 	}
+
+	rcu_read_lock();
+	for_each_netdev_rcu(net, dev) {
+		if (dev->netdev_ops->ndo_add_geneve_port)
+			dev->netdev_ops->ndo_add_geneve_port(dev, sa_family,
+							     port);
+	}
+	rcu_read_unlock();
 }
 
 static int geneve_hlen(struct genevehdr *gh)
@@ -444,7 +508,7 @@
 
 	skb_gro_pull(skb, gh_len);
 	skb_gro_postpull_rcsum(skb, gh, gh_len);
-	pp = ptype->callbacks.gro_receive(head, skb);
+	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
 
 out_unlock:
 	rcu_read_unlock();
@@ -480,7 +544,7 @@
 
 /* Create new listen socket if needed */
 static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
-						bool ipv6)
+						bool ipv6, u32 flags)
 {
 	struct geneve_net *gn = net_generic(net, geneve_net_id);
 	struct geneve_sock *gs;
@@ -492,7 +556,7 @@
 	if (!gs)
 		return ERR_PTR(-ENOMEM);
 
-	sock = geneve_create_sock(net, ipv6, port);
+	sock = geneve_create_sock(net, ipv6, port, flags);
 	if (IS_ERR(sock)) {
 		kfree(gs);
 		return ERR_CAST(sock);
@@ -521,8 +585,20 @@
 
 static void geneve_notify_del_rx_port(struct geneve_sock *gs)
 {
+	struct net_device *dev;
 	struct sock *sk = gs->sock->sk;
-	sa_family_t sa_family = sk->sk_family;
+	struct net *net = sock_net(sk);
+	sa_family_t sa_family = geneve_get_sk_family(gs);
+	__be16 port = inet_sk(sk)->inet_sport;
+
+	rcu_read_lock();
+	for_each_netdev_rcu(net, dev) {
+		if (dev->netdev_ops->ndo_del_geneve_port)
+			dev->netdev_ops->ndo_del_geneve_port(dev, sa_family,
+							     port);
+	}
+
+	rcu_read_unlock();
 
 	if (sa_family == AF_INET)
 		udp_del_offload(&gs->udp_offloads);
@@ -555,7 +631,7 @@
 
 	list_for_each_entry(gs, &gn->sock_list, list) {
 		if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
-		    inet_sk(gs->sock->sk)->sk.sk_family == family) {
+		    geneve_get_sk_family(gs) == family) {
 			return gs;
 		}
 	}
@@ -575,12 +651,13 @@
 		goto out;
 	}
 
-	gs = geneve_socket_create(net, geneve->dst_port, ipv6);
+	gs = geneve_socket_create(net, geneve->dst_port, ipv6, geneve->flags);
 	if (IS_ERR(gs))
 		return PTR_ERR(gs);
 
 out:
 	gs->collect_md = geneve->collect_md;
+	gs->flags = geneve->flags;
 #if IS_ENABLED(CONFIG_IPV6)
 	if (ipv6)
 		geneve->sock6 = gs;
@@ -598,15 +675,19 @@
 	struct geneve_dev *geneve = netdev_priv(dev);
 	bool ipv6 = geneve->remote.sa.sa_family == AF_INET6;
 	bool metadata = geneve->collect_md;
+	bool ipv4 = !ipv6 || metadata;
 	int ret = 0;
 
 	geneve->sock4 = NULL;
 #if IS_ENABLED(CONFIG_IPV6)
 	geneve->sock6 = NULL;
-	if (ipv6 || metadata)
+	if (ipv6) {
 		ret = geneve_sock_add(geneve, true);
+		if (ret < 0 && ret != -EAFNOSUPPORT)
+			ipv4 = false;
+	}
 #endif
-	if (!ret && (!ipv6 || metadata))
+	if (ipv4)
 		ret = geneve_sock_add(geneve, false);
 	if (ret < 0)
 		geneve_sock_release(geneve);
@@ -642,11 +723,12 @@
 
 static int geneve_build_skb(struct rtable *rt, struct sk_buff *skb,
 			    __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt,
-			    bool csum, bool xnet)
+			    u32 flags, bool xnet)
 {
 	struct genevehdr *gnvh;
 	int min_headroom;
 	int err;
+	bool udp_sum = !!(flags & GENEVE_F_UDP_CSUM);
 
 	skb_scrub_packet(skb, xnet);
 
@@ -658,7 +740,7 @@
 		goto free_rt;
 	}
 
-	skb = udp_tunnel_handle_offloads(skb, csum);
+	skb = udp_tunnel_handle_offloads(skb, udp_sum);
 	if (IS_ERR(skb)) {
 		err = PTR_ERR(skb);
 		goto free_rt;
@@ -678,11 +760,12 @@
 #if IS_ENABLED(CONFIG_IPV6)
 static int geneve6_build_skb(struct dst_entry *dst, struct sk_buff *skb,
 			     __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt,
-			     bool csum, bool xnet)
+			     u32 flags, bool xnet)
 {
 	struct genevehdr *gnvh;
 	int min_headroom;
 	int err;
+	bool udp_sum = !(flags & GENEVE_F_UDP_ZERO_CSUM6_TX);
 
 	skb_scrub_packet(skb, xnet);
 
@@ -694,7 +777,7 @@
 		goto free_dst;
 	}
 
-	skb = udp_tunnel_handle_offloads(skb, csum);
+	skb = udp_tunnel_handle_offloads(skb, udp_sum);
 	if (IS_ERR(skb)) {
 		err = PTR_ERR(skb);
 		goto free_dst;
@@ -715,7 +798,8 @@
 static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
 				       struct net_device *dev,
 				       struct flowi4 *fl4,
-				       struct ip_tunnel_info *info)
+				       struct ip_tunnel_info *info,
+				       __be16 dport, __be16 sport)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
 	struct rtable *rt = NULL;
@@ -724,6 +808,8 @@
 	memset(fl4, 0, sizeof(*fl4));
 	fl4->flowi4_mark = skb->mark;
 	fl4->flowi4_proto = IPPROTO_UDP;
+	fl4->fl4_dport = dport;
+	fl4->fl4_sport = sport;
 
 	if (info) {
 		fl4->daddr = info->key.u.ipv4.dst;
@@ -758,7 +844,8 @@
 static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
 					   struct net_device *dev,
 					   struct flowi6 *fl6,
-					   struct ip_tunnel_info *info)
+					   struct ip_tunnel_info *info,
+					   __be16 dport, __be16 sport)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
 	struct geneve_sock *gs6 = geneve->sock6;
@@ -768,6 +855,8 @@
 	memset(fl6, 0, sizeof(*fl6));
 	fl6->flowi6_mark = skb->mark;
 	fl6->flowi6_proto = IPPROTO_UDP;
+	fl6->fl6_dport = dport;
+	fl6->fl6_sport = sport;
 
 	if (info) {
 		fl6->daddr = info->key.u.ipv6.dst;
@@ -785,7 +874,9 @@
 		fl6->daddr = geneve->remote.sin6.sin6_addr;
 	}
 
-	if (ipv6_stub->ipv6_dst_lookup(geneve->net, gs6->sock->sk, &dst, fl6)) {
+	dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6,
+					      NULL);
+	if (IS_ERR(dst)) {
 		netdev_dbg(dev, "no route to %pI6\n", &fl6->daddr);
 		return ERR_PTR(-ENETUNREACH);
 	}
@@ -819,14 +910,13 @@
 	struct geneve_dev *geneve = netdev_priv(dev);
 	struct geneve_sock *gs4 = geneve->sock4;
 	struct rtable *rt = NULL;
-	const struct iphdr *iip; /* interior IP header */
 	int err = -EINVAL;
 	struct flowi4 fl4;
 	__u8 tos, ttl;
 	__be16 sport;
-	bool udp_csum;
 	__be16 df;
 	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
+	u32 flags = geneve->flags;
 
 	if (geneve->collect_md) {
 		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
@@ -837,17 +927,15 @@
 			goto tx_error;
 	}
 
-	rt = geneve_get_v4_rt(skb, dev, &fl4, info);
+	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
+	rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port, sport);
 	if (IS_ERR(rt)) {
 		err = PTR_ERR(rt);
 		goto tx_error;
 	}
 
-	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
 	skb_reset_mac_header(skb);
 
-	iip = ip_hdr(skb);
-
 	if (info) {
 		const struct ip_tunnel_key *key = &info->key;
 		u8 *opts = NULL;
@@ -857,23 +945,26 @@
 		if (key->tun_flags & TUNNEL_GENEVE_OPT)
 			opts = ip_tunnel_info_opts(info);
 
-		udp_csum = !!(key->tun_flags & TUNNEL_CSUM);
+		if (key->tun_flags & TUNNEL_CSUM)
+			flags |= GENEVE_F_UDP_CSUM;
+		else
+			flags &= ~GENEVE_F_UDP_CSUM;
+
 		err = geneve_build_skb(rt, skb, key->tun_flags, vni,
-				       info->options_len, opts, udp_csum, xnet);
+				       info->options_len, opts, flags, xnet);
 		if (unlikely(err))
 			goto err;
 
-		tos = ip_tunnel_ecn_encap(key->tos, iip, skb);
+		tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
 		ttl = key->ttl;
 		df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
 	} else {
-		udp_csum = false;
 		err = geneve_build_skb(rt, skb, 0, geneve->vni,
-				       0, NULL, udp_csum, xnet);
+				       0, NULL, flags, xnet);
 		if (unlikely(err))
 			goto err;
 
-		tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, iip, skb);
+		tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, ip_hdr(skb), skb);
 		ttl = geneve->ttl;
 		if (!ttl && IN_MULTICAST(ntohl(fl4.daddr)))
 			ttl = 1;
@@ -883,7 +974,7 @@
 	err = udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
 				  tos, ttl, df, sport, geneve->dst_port,
 				  !net_eq(geneve->net, dev_net(geneve->dev)),
-				  !udp_csum);
+				  !(flags & GENEVE_F_UDP_CSUM));
 
 	iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
 	return NETDEV_TX_OK;
@@ -907,13 +998,12 @@
 	struct geneve_dev *geneve = netdev_priv(dev);
 	struct geneve_sock *gs6 = geneve->sock6;
 	struct dst_entry *dst = NULL;
-	const struct iphdr *iip; /* interior IP header */
 	int err = -EINVAL;
 	struct flowi6 fl6;
 	__u8 prio, ttl;
 	__be16 sport;
-	bool udp_csum;
 	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
+	u32 flags = geneve->flags;
 
 	if (geneve->collect_md) {
 		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
@@ -922,17 +1012,15 @@
 		}
 	}
 
-	dst = geneve_get_v6_dst(skb, dev, &fl6, info);
+	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
+	dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port, sport);
 	if (IS_ERR(dst)) {
 		err = PTR_ERR(dst);
 		goto tx_error;
 	}
 
-	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
 	skb_reset_mac_header(skb);
 
-	iip = ip_hdr(skb);
-
 	if (info) {
 		const struct ip_tunnel_key *key = &info->key;
 		u8 *opts = NULL;
@@ -942,23 +1030,26 @@
 		if (key->tun_flags & TUNNEL_GENEVE_OPT)
 			opts = ip_tunnel_info_opts(info);
 
-		udp_csum = !!(key->tun_flags & TUNNEL_CSUM);
+		if (key->tun_flags & TUNNEL_CSUM)
+			flags |= GENEVE_F_UDP_CSUM;
+		else
+			flags &= ~GENEVE_F_UDP_CSUM;
+
 		err = geneve6_build_skb(dst, skb, key->tun_flags, vni,
 					info->options_len, opts,
-					udp_csum, xnet);
+					flags, xnet);
 		if (unlikely(err))
 			goto err;
 
-		prio = ip_tunnel_ecn_encap(key->tos, iip, skb);
+		prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
 		ttl = key->ttl;
 	} else {
-		udp_csum = false;
 		err = geneve6_build_skb(dst, skb, 0, geneve->vni,
-					0, NULL, udp_csum, xnet);
+					0, NULL, flags, xnet);
 		if (unlikely(err))
 			goto err;
 
-		prio = ip_tunnel_ecn_encap(fl6.flowi6_tos, iip, skb);
+		prio = ip_tunnel_ecn_encap(fl6.flowi6_tos, ip_hdr(skb), skb);
 		ttl = geneve->ttl;
 		if (!ttl && ipv6_addr_is_multicast(&fl6.daddr))
 			ttl = 1;
@@ -966,7 +1057,10 @@
 	}
 	err = udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
 				   &fl6.saddr, &fl6.daddr, prio, ttl,
-				   sport, geneve->dst_port, !udp_csum);
+				   sport, geneve->dst_port,
+				   !!(flags & GENEVE_F_UDP_ZERO_CSUM6_TX));
+
+	iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
 	return NETDEV_TX_OK;
 
 tx_error:
@@ -998,10 +1092,22 @@
 	return geneve_xmit_skb(skb, dev, info);
 }
 
+static int geneve_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* GENEVE overhead is not fixed, so we can't enforce a more
+	 * precise max MTU.
+	 */
+	if (new_mtu < 68 || new_mtu > IP_MAX_MTU)
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
 static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 {
 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
 	struct geneve_dev *geneve = netdev_priv(dev);
+	__be16 sport;
 	struct rtable *rt;
 	struct flowi4 fl4;
 #if IS_ENABLED(CONFIG_IPV6)
@@ -1010,7 +1116,10 @@
 #endif
 
 	if (ip_tunnel_info_af(info) == AF_INET) {
-		rt = geneve_get_v4_rt(skb, dev, &fl4, info);
+		sport = udp_flow_src_port(geneve->net, skb,
+					  1, USHRT_MAX, true);
+		rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port,
+				      sport);
 		if (IS_ERR(rt))
 			return PTR_ERR(rt);
 
@@ -1018,7 +1127,10 @@
 		info->key.u.ipv4.src = fl4.saddr;
 #if IS_ENABLED(CONFIG_IPV6)
 	} else if (ip_tunnel_info_af(info) == AF_INET6) {
-		dst = geneve_get_v6_dst(skb, dev, &fl6, info);
+		sport = udp_flow_src_port(geneve->net, skb,
+					  1, USHRT_MAX, true);
+		dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port,
+					sport);
 		if (IS_ERR(dst))
 			return PTR_ERR(dst);
 
@@ -1029,8 +1141,7 @@
 		return -EINVAL;
 	}
 
-	info->key.tp_src = udp_flow_src_port(geneve->net, skb,
-					     1, USHRT_MAX, true);
+	info->key.tp_src = sport;
 	info->key.tp_dst = geneve->dst_port;
 	return 0;
 }
@@ -1042,7 +1153,7 @@
 	.ndo_stop		= geneve_stop,
 	.ndo_start_xmit		= geneve_xmit,
 	.ndo_get_stats64	= ip_tunnel_get_stats64,
-	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_change_mtu		= geneve_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_set_mac_address	= eth_mac_addr,
 	.ndo_fill_metadata_dst	= geneve_fill_metadata_dst,
@@ -1065,6 +1176,30 @@
 	.name = "geneve",
 };
 
+/* Calls the ndo_add_geneve_port of the caller in order to
+ * supply the listening GENEVE udp ports. Callers are expected
+ * to implement the ndo_add_geneve_port.
+ */
+void geneve_get_rx_port(struct net_device *dev)
+{
+	struct net *net = dev_net(dev);
+	struct geneve_net *gn = net_generic(net, geneve_net_id);
+	struct geneve_sock *gs;
+	sa_family_t sa_family;
+	struct sock *sk;
+	__be16 port;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(gs, &gn->sock_list, list) {
+		sk = gs->sock->sk;
+		sa_family = sk->sk_family;
+		port = inet_sk(sk)->inet_sport;
+		dev->netdev_ops->ndo_add_geneve_port(dev, sa_family, port);
+	}
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(geneve_get_rx_port);
+
 /* Initialize the device structure. */
 static void geneve_setup(struct net_device *dev)
 {
@@ -1097,6 +1232,9 @@
 	[IFLA_GENEVE_TOS]		= { .type = NLA_U8 },
 	[IFLA_GENEVE_PORT]		= { .type = NLA_U16 },
 	[IFLA_GENEVE_COLLECT_METADATA]	= { .type = NLA_FLAG },
+	[IFLA_GENEVE_UDP_CSUM]		= { .type = NLA_U8 },
+	[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]	= { .type = NLA_U8 },
+	[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]	= { .type = NLA_U8 },
 };
 
 static int geneve_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -1150,7 +1288,7 @@
 static int geneve_configure(struct net *net, struct net_device *dev,
 			    union geneve_addr *remote,
 			    __u32 vni, __u8 ttl, __u8 tos, __be16 dst_port,
-			    bool metadata)
+			    bool metadata, u32 flags)
 {
 	struct geneve_net *gn = net_generic(net, geneve_net_id);
 	struct geneve_dev *t, *geneve = netdev_priv(dev);
@@ -1181,6 +1319,7 @@
 	geneve->tos = tos;
 	geneve->dst_port = dst_port;
 	geneve->collect_md = metadata;
+	geneve->flags = flags;
 
 	t = geneve_find_dev(gn, dst_port, remote, geneve->vni,
 			    &tun_on_same_port, &tun_collect_md);
@@ -1219,6 +1358,7 @@
 	bool metadata = false;
 	union geneve_addr remote = geneve_remote_unspec;
 	__u32 vni = 0;
+	u32 flags = 0;
 
 	if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6])
 		return -EINVAL;
@@ -1259,8 +1399,20 @@
 	if (data[IFLA_GENEVE_COLLECT_METADATA])
 		metadata = true;
 
+	if (data[IFLA_GENEVE_UDP_CSUM] &&
+	    nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
+		flags |= GENEVE_F_UDP_CSUM;
+
+	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX] &&
+	    nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
+		flags |= GENEVE_F_UDP_ZERO_CSUM6_TX;
+
+	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX] &&
+	    nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
+		flags |= GENEVE_F_UDP_ZERO_CSUM6_RX;
+
 	return geneve_configure(net, dev, &remote, vni, ttl, tos, dst_port,
-				metadata);
+				metadata, flags);
 }
 
 static void geneve_dellink(struct net_device *dev, struct list_head *head)
@@ -1279,6 +1431,9 @@
 		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TOS */
 		nla_total_size(sizeof(__be16)) +  /* IFLA_GENEVE_PORT */
 		nla_total_size(0) +	 /* IFLA_GENEVE_COLLECT_METADATA */
+		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
+		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */
+		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */
 		0;
 }
 
@@ -1315,6 +1470,14 @@
 			goto nla_put_failure;
 	}
 
+	if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM,
+		       !!(geneve->flags & GENEVE_F_UDP_CSUM)) ||
+	    nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
+		       !!(geneve->flags & GENEVE_F_UDP_ZERO_CSUM6_TX)) ||
+	    nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
+		       !!(geneve->flags & GENEVE_F_UDP_ZERO_CSUM6_RX)))
+		goto nla_put_failure;
+
 	return 0;
 
 nla_put_failure:
@@ -1339,6 +1502,7 @@
 {
 	struct nlattr *tb[IFLA_MAX + 1];
 	struct net_device *dev;
+	LIST_HEAD(list_kill);
 	int err;
 
 	memset(tb, 0, sizeof(tb));
@@ -1348,12 +1512,29 @@
 		return dev;
 
 	err = geneve_configure(net, dev, &geneve_remote_unspec,
-			       0, 0, 0, htons(dst_port), true);
+			       0, 0, 0, htons(dst_port), true, 0);
 	if (err) {
 		free_netdev(dev);
 		return ERR_PTR(err);
 	}
+
+	/* openvswitch users expect packet sizes to be unrestricted,
+	 * so set the largest MTU we can.
+	 */
+	err = geneve_change_mtu(dev, IP_MAX_MTU);
+	if (err)
+		goto err;
+
+	err = rtnl_configure_link(dev, NULL);
+	if (err < 0)
+		goto err;
+
 	return dev;
+
+ err:
+	geneve_dellink(dev, &list_kill);
+	unregister_netdevice_many(&list_kill);
+	return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(geneve_dev_create_fb);
 
--- linux-4.4.0.orig/drivers/net/hamradio/6pack.c
+++ linux-4.4.0/drivers/net/hamradio/6pack.c
@@ -311,7 +311,6 @@
 {
 	/* Finish setting up the DEVICE info. */
 	dev->netdev_ops		= &sp_netdev_ops;
-	dev->destructor		= free_netdev;
 	dev->mtu		= SIXP_MTU;
 	dev->hard_header_len	= AX25_MAX_HEADER_LEN;
 	dev->header_ops 	= &ax25_header_ops;
@@ -669,10 +668,10 @@
 {
 	struct sixpack *sp;
 
-	write_lock_bh(&disc_data_lock);
+	write_lock_irq(&disc_data_lock);
 	sp = tty->disc_data;
 	tty->disc_data = NULL;
-	write_unlock_bh(&disc_data_lock);
+	write_unlock_irq(&disc_data_lock);
 	if (!sp)
 		return;
 
@@ -692,11 +691,13 @@
 	del_timer_sync(&sp->tx_t);
 	del_timer_sync(&sp->resync_t);
 
-	/* Free all 6pack frame buffers. */
+	unregister_netdev(sp->dev);
+
+	/* Free all 6pack frame buffers after unreg. */
 	kfree(sp->rbuff);
 	kfree(sp->xbuff);
 
-	unregister_netdev(sp->dev);
+	free_netdev(sp->dev);
 }
 
 /* Perform I/O control on an active 6pack channel. */
@@ -874,6 +875,12 @@
 		return;
 	}
 
+	if (sp->rx_count_cooked + 2 >= sizeof(sp->cooked_buf)) {
+		pr_err("6pack: cooked buffer overrun, data loss\n");
+		sp->rx_count = 0;
+		return;
+	}
+
 	buf = sp->raw_buf;
 	sp->cooked_buf[sp->rx_count_cooked++] =
 		buf[0] | ((buf[1] << 2) & 0xc0);
--- linux-4.4.0.orig/drivers/net/hamradio/baycom_epp.c
+++ linux-4.4.0/drivers/net/hamradio/baycom_epp.c
@@ -1170,7 +1170,7 @@
 
 module_param_array(mode, charp, NULL, 0);
 MODULE_PARM_DESC(mode, "baycom operating mode");
-module_param_array(iobase, int, NULL, 0);
+module_param_hw_array(iobase, int, ioport, NULL, 0);
 MODULE_PARM_DESC(iobase, "baycom io base address");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
--- linux-4.4.0.orig/drivers/net/hamradio/baycom_par.c
+++ linux-4.4.0/drivers/net/hamradio/baycom_par.c
@@ -481,7 +481,7 @@
 
 module_param_array(mode, charp, NULL, 0);
 MODULE_PARM_DESC(mode, "baycom operating mode; eg. par96 or picpar");
-module_param_array(iobase, int, NULL, 0);
+module_param_hw_array(iobase, int, ioport, NULL, 0);
 MODULE_PARM_DESC(iobase, "baycom io base address");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
--- linux-4.4.0.orig/drivers/net/hamradio/baycom_ser_fdx.c
+++ linux-4.4.0/drivers/net/hamradio/baycom_ser_fdx.c
@@ -612,9 +612,9 @@
 
 module_param_array(mode, charp, NULL, 0);
 MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
-module_param_array(iobase, int, NULL, 0);
+module_param_hw_array(iobase, int, ioport, NULL, 0);
 MODULE_PARM_DESC(iobase, "baycom io base address");
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(irq, "baycom irq number");
 module_param_array(baud, int, NULL, 0);
 MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)");
--- linux-4.4.0.orig/drivers/net/hamradio/baycom_ser_hdx.c
+++ linux-4.4.0/drivers/net/hamradio/baycom_ser_hdx.c
@@ -642,9 +642,9 @@
 
 module_param_array(mode, charp, NULL, 0);
 MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
-module_param_array(iobase, int, NULL, 0);
+module_param_hw_array(iobase, int, ioport, NULL, 0);
 MODULE_PARM_DESC(iobase, "baycom io base address");
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(irq, "baycom irq number");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
--- linux-4.4.0.orig/drivers/net/hamradio/bpqether.c
+++ linux-4.4.0/drivers/net/hamradio/bpqether.c
@@ -89,10 +89,6 @@
 static const char banner[] __initconst = KERN_INFO \
 	"AX.25: bpqether driver version 004\n";
 
-static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
-
-static char bpq_eth_addr[6];
-
 static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 static int bpq_device_event(struct notifier_block *, unsigned long, void *);
 
@@ -515,8 +511,8 @@
 	bpq->ethdev = edev;
 	bpq->axdev = ndev;
 
-	memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr));
-	memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr));
+	eth_broadcast_addr(bpq->dest_addr);
+	eth_broadcast_addr(bpq->acpt_addr);
 
 	err = register_netdevice(ndev);
 	if (err)
--- linux-4.4.0.orig/drivers/net/hamradio/dmascc.c
+++ linux-4.4.0/drivers/net/hamradio/dmascc.c
@@ -274,7 +274,7 @@
 
 MODULE_AUTHOR("Klaus Kudielka");
 MODULE_DESCRIPTION("Driver for high-speed SCC boards");
-module_param_array(io, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
 MODULE_LICENSE("GPL");
 
 static void __exit dmascc_exit(void)
--- linux-4.4.0.orig/drivers/net/hamradio/hdlcdrv.c
+++ linux-4.4.0/drivers/net/hamradio/hdlcdrv.c
@@ -574,6 +574,8 @@
 	case HDLCDRVCTL_CALIBRATE:
 		if(!capable(CAP_SYS_RAWIO))
 			return -EPERM;
+		if (s->par.bitrate <= 0)
+			return -EINVAL;
 		if (bi.data.calibrate > INT_MAX / s->par.bitrate)
 			return -EINVAL;
 		s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16;
--- linux-4.4.0.orig/drivers/net/hamradio/mkiss.c
+++ linux-4.4.0/drivers/net/hamradio/mkiss.c
@@ -648,8 +648,8 @@
 {
 	/* Finish setting up the DEVICE info. */
 	dev->mtu             = AX_MTU;
-	dev->hard_header_len = 0;
-	dev->addr_len        = 0;
+	dev->hard_header_len = AX25_MAX_HEADER_LEN;
+	dev->addr_len        = AX25_ADDR_LEN;
 	dev->type            = ARPHRD_AX25;
 	dev->tx_queue_len    = 10;
 	dev->header_ops      = &ax25_header_ops;
@@ -783,10 +783,10 @@
 {
 	struct mkiss *ax;
 
-	write_lock_bh(&disc_data_lock);
+	write_lock_irq(&disc_data_lock);
 	ax = tty->disc_data;
 	tty->disc_data = NULL;
-	write_unlock_bh(&disc_data_lock);
+	write_unlock_irq(&disc_data_lock);
 
 	if (!ax)
 		return;
@@ -803,13 +803,15 @@
 	 */
 	netif_stop_queue(ax->dev);
 
-	/* Free all AX25 frame buffers. */
+	unregister_netdev(ax->dev);
+
+	/* Free all AX25 frame buffers after unreg. */
 	kfree(ax->rbuff);
 	kfree(ax->xbuff);
 
 	ax->tty = NULL;
 
-	unregister_netdev(ax->dev);
+	free_netdev(ax->dev);
 }
 
 /* Perform I/O control on an active ax25 channel. */
--- linux-4.4.0.orig/drivers/net/hamradio/yam.c
+++ linux-4.4.0/drivers/net/hamradio/yam.c
@@ -1160,6 +1160,7 @@
 		err = register_netdev(dev);
 		if (err) {
 			printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
+			free_netdev(dev);
 			goto error;
 		}
 		yam_devs[i] = dev;
--- linux-4.4.0.orig/drivers/net/hippi/rrunner.c
+++ linux-4.4.0/drivers/net/hippi/rrunner.c
@@ -1250,7 +1250,7 @@
 		rrpriv->info = NULL;
 	}
 	if (rrpriv->rx_ctrl) {
-		pci_free_consistent(pdev, sizeof(struct ring_ctrl),
+		pci_free_consistent(pdev, 256 * sizeof(struct ring_ctrl),
 				    rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma);
 		rrpriv->rx_ctrl = NULL;
 	}
@@ -1381,8 +1381,8 @@
 			    rrpriv->info_dma);
 	rrpriv->info = NULL;
 
-	free_irq(pdev->irq, dev);
 	spin_unlock_irqrestore(&rrpriv->lock, flags);
+	free_irq(pdev->irq, dev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/hyperv/hyperv_net.h
+++ linux-4.4.0/drivers/net/hyperv/hyperv_net.h
@@ -84,8 +84,6 @@
 #define NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2   40
 
 #define ITAB_NUM 128
-#define HASH_KEYLEN NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2
-extern u8 netvsc_hash_key[];
 
 struct ndis_recv_scale_param { /* NDIS_RECEIVE_SCALE_PARAMETERS */
 	struct ndis_obj_header hdr;
@@ -124,37 +122,22 @@
 /*
  * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame
  * within the RNDIS
+ *
+ * The size of this structure is less than 48 bytes and we can now
+ * place this structure in the skb->cb field.
  */
 struct hv_netvsc_packet {
 	/* Bookkeeping stuff */
-	u32 status;
-
-	bool is_data_pkt;
-	bool xmit_more; /* from skb */
-	bool cp_partial; /* partial copy into send buffer */
+	u8 cp_partial; /* partial copy into send buffer */
 
-	u16 vlan_tci;
+	u8 rmsg_size; /* RNDIS header and PPI size */
+	u8 rmsg_pgcnt; /* page count of RNDIS header and PPI */
+	u8 page_buf_cnt;
 
 	u16 q_idx;
-	struct vmbus_channel *channel;
-
-	u64 send_completion_tid;
-	void *send_completion_ctx;
-	void (*send_completion)(void *context);
-
 	u32 send_buf_index;
 
-	/* This points to the memory after page_buf */
-	struct rndis_message *rndis_msg;
-
-	u32 rmsg_size; /* RNDIS header and PPI size */
-	u32 rmsg_pgcnt; /* page count of RNDIS header and PPI */
-
 	u32 total_data_buflen;
-	/* Points to the send/receive buffer where the ethernet frame is */
-	void *data;
-	u32 page_buf_cnt;
-	struct hv_page_buffer *page_buf;
 };
 
 struct netvsc_device_info {
@@ -173,11 +156,10 @@
 };
 
 struct rndis_device {
-	struct netvsc_device *net_dev;
+	struct net_device *ndev;
 
 	enum rndis_device_state state;
 	bool link_state;
-	bool link_change;
 	atomic_t new_req_id;
 
 	spinlock_t request_lock;
@@ -188,28 +170,38 @@
 
 
 /* Interface */
+struct rndis_message;
+struct netvsc_device;
 int netvsc_device_add(struct hv_device *device, void *additional_info);
-int netvsc_device_remove(struct hv_device *device);
+void netvsc_device_remove(struct hv_device *device);
 int netvsc_send(struct hv_device *device,
-		struct hv_netvsc_packet *packet);
+		struct hv_netvsc_packet *packet,
+		struct rndis_message *rndis_msg,
+		struct hv_page_buffer **page_buffer,
+		struct sk_buff *skb);
 void netvsc_linkstatus_callback(struct hv_device *device_obj,
 				struct rndis_message *resp);
-void netvsc_xmit_completion(void *context);
 int netvsc_recv_callback(struct hv_device *device_obj,
 			struct hv_netvsc_packet *packet,
-			struct ndis_tcp_ip_checksum_info *csum_info);
+			void **data,
+			struct ndis_tcp_ip_checksum_info *csum_info,
+			struct vmbus_channel *channel,
+			u16 vlan_tci);
 void netvsc_channel_cb(void *context);
-int rndis_filter_open(struct hv_device *dev);
-int rndis_filter_close(struct hv_device *dev);
+int rndis_filter_open(struct netvsc_device *nvdev);
+int rndis_filter_close(struct netvsc_device *nvdev);
 int rndis_filter_device_add(struct hv_device *dev,
 			void *additional_info);
 void rndis_filter_device_remove(struct hv_device *dev);
 int rndis_filter_receive(struct hv_device *dev,
-			struct hv_netvsc_packet *pkt);
+			struct hv_netvsc_packet *pkt,
+			void **data,
+			struct vmbus_channel *channel);
 
 int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
-int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
+int rndis_filter_set_device_mac(struct net_device *ndev, char *mac);
 
+void netvsc_switch_datapath(struct net_device *nv_dev, bool vf);
 
 #define NVSP_INVALID_PROTOCOL_VERSION	((u32)0xFFFFFFFF)
 
@@ -441,7 +433,7 @@
  */
 struct nvsp_1_message_send_rndis_packet {
 	/*
-	 * This field is specified by RNIDS. They assume there's two different
+	 * This field is specified by RNDIS. They assume there's two different
 	 * channels of communication. However, the Network VSP only has one.
 	 * Therefore, the channel travels with the RNDIS packet.
 	 */
@@ -496,6 +488,7 @@
 			u64 sriov:1;
 			u64 ieee8021q:1;
 			u64 correlation_id:1;
+			u64 teaming:1;
 		};
 	};
 } __packed;
@@ -585,7 +578,7 @@
 	/* The number of entries in the send indirection table */
 	u32 count;
 
-	/* The offset of the send indireciton table from top of this struct.
+	/* The offset of the send indirection table from top of this struct.
 	 * The send indirection table tells which channel to put the send
 	 * traffic on. Each entry is a channel number.
 	 */
@@ -628,43 +621,96 @@
 #define NETVSC_PACKET_SIZE                      4096
 
 #define VRSS_SEND_TAB_SIZE 16
+#define VRSS_CHANNEL_MAX 64
 
 #define RNDIS_MAX_PKT_DEFAULT 8
 #define RNDIS_PKT_ALIGN_DEFAULT 8
 
 struct multi_send_data {
-	spinlock_t lock; /* protect struct multi_send_data */
+	struct sk_buff *skb; /* skb containing the pkt */
 	struct hv_netvsc_packet *pkt; /* netvsc pkt pending */
 	u32 count; /* counter of batched packets */
 };
 
+struct recv_comp_data {
+	u64 tid; /* transaction id */
+	u32 status;
+};
+
+/* Netvsc Receive Slots Max */
+#define NETVSC_RECVSLOT_MAX (NETVSC_RECEIVE_BUFFER_SIZE / ETH_DATA_LEN + 1)
+
+struct multi_recv_comp {
+	void *buf; /* queued receive completions */
+	u32 first; /* first data entry */
+	u32 next; /* next entry for writing */
+};
+
 struct netvsc_stats {
 	u64 packets;
 	u64 bytes;
+	u64 broadcast;
+	u64 multicast;
 	struct u64_stats_sync syncp;
 };
 
+struct netvsc_ethtool_stats {
+	unsigned long tx_scattered;
+	unsigned long tx_no_memory;
+	unsigned long tx_no_space;
+	unsigned long tx_too_big;
+	unsigned long tx_busy;
+};
+
+struct netvsc_reconfig {
+	struct list_head list;
+	u32 event;
+};
+
 /* The context of the netvsc device  */
 struct net_device_context {
 	/* point back to our device context */
 	struct hv_device *device_ctx;
+	/* netvsc_device */
+	struct netvsc_device *nvdev;
+	/* reconfigure work */
 	struct delayed_work dwork;
+	/* last reconfig time */
+	unsigned long last_reconfig;
+	/* reconfig events */
+	struct list_head reconfig_events;
+	/* list protection */
+	spinlock_t lock;
+
 	struct work_struct work;
 	u32 msg_enable; /* debug level */
 
 	struct netvsc_stats __percpu *tx_stats;
 	struct netvsc_stats __percpu *rx_stats;
+
+	/* Ethtool settings */
+	u8 duplex;
+	u32 speed;
+	struct netvsc_ethtool_stats eth_stats;
+
+	/* the device is going away */
+	bool start_remove;
+
+	/* State to manage the associated VF interface. */
+	struct net_device __rcu *vf_netdev;
+
+	/* 1: allocated, serial number is valid. 0: not allocated */
+	u32 vf_alloc;
+	/* Serial number of the VF to team with */
+	u32 vf_serial;
 };
 
 /* Per netvsc device */
 struct netvsc_device {
-	struct hv_device *dev;
-
 	u32 nvsp_version;
 
 	atomic_t num_outstanding_sends;
 	wait_queue_head_t wait_drain;
-	bool start_remove;
 	bool destroy;
 
 	/* Receive buffer allocated by us but manages by NetVSP */
@@ -688,17 +734,14 @@
 	struct nvsp_message channel_init_pkt;
 
 	struct nvsp_message revoke_packet;
-	/* unsigned char HwMacAddr[HW_MACADDR_LEN]; */
-
-	struct net_device *ndev;
 
-	struct vmbus_channel *chn_table[NR_CPUS];
+	struct vmbus_channel *chn_table[VRSS_CHANNEL_MAX];
 	u32 send_table[VRSS_SEND_TAB_SIZE];
 	u32 max_chn;
 	u32 num_chn;
 	spinlock_t sc_lock; /* Protects num_sc_offered variable */
 	u32 num_sc_offered;
-	atomic_t queue_sends[NR_CPUS];
+	atomic_t queue_sends[VRSS_CHANNEL_MAX];
 
 	/* Holds rndis device info */
 	void *extension;
@@ -710,19 +753,28 @@
 	/* The sub channel callback buffer */
 	unsigned char *sub_cb_buf;
 
-	struct multi_send_data msd[NR_CPUS];
+	struct multi_send_data msd[VRSS_CHANNEL_MAX];
 	u32 max_pkt; /* max number of pkt in one send, e.g. 8 */
 	u32 pkt_align; /* alignment bytes, e.g. 8 */
 
-	/* The net device context */
-	struct net_device_context *nd_ctx;
+	struct multi_recv_comp mrc[VRSS_CHANNEL_MAX];
+	atomic_t num_outstanding_recvs;
 
-	/* 1: allocated, serial number is valid. 0: not allocated */
-	u32 vf_alloc;
-	/* Serial number of the VF to team with */
-	u32 vf_serial;
+	atomic_t open_cnt;
 };
 
+static inline struct netvsc_device *
+net_device_to_netvsc_device(struct net_device *ndev)
+{
+	return ((struct net_device_context *)netdev_priv(ndev))->nvdev;
+}
+
+static inline struct netvsc_device *
+hv_device_to_netvsc_device(struct hv_device *device)
+{
+	return net_device_to_netvsc_device(hv_get_drvdata(device));
+}
+
 /* NdisInitialize message */
 struct rndis_initialize_request {
 	u32 req_id;
@@ -1186,7 +1238,7 @@
 	u32 ndis_msg_type;
 
 	/* Total length of this message, from the beginning */
-	/* of the sruct rndis_message, in bytes. */
+	/* of the struct rndis_message, in bytes. */
 	u32 msg_len;
 
 	/* Actual message */
@@ -1260,5 +1312,4 @@
 #define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP)
 #define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP)
 
-
 #endif /* _HYPERV_NET_H */
--- linux-4.4.0.orig/drivers/net/hyperv/netvsc.c
+++ linux-4.4.0/drivers/net/hyperv/netvsc.c
@@ -33,12 +33,35 @@
 
 #include "hyperv_net.h"
 
+/*
+ * Switch the data path from the synthetic interface to the VF
+ * interface.
+ */
+void netvsc_switch_datapath(struct net_device *ndev, bool vf)
+{
+	struct net_device_context *net_device_ctx = netdev_priv(ndev);
+	struct hv_device *dev = net_device_ctx->device_ctx;
+	struct netvsc_device *nv_dev = net_device_ctx->nvdev;
+	struct nvsp_message *init_pkt = &nv_dev->channel_init_pkt;
+
+	memset(init_pkt, 0, sizeof(struct nvsp_message));
+	init_pkt->hdr.msg_type = NVSP_MSG4_TYPE_SWITCH_DATA_PATH;
+	if (vf)
+		init_pkt->msg.v4_msg.active_dp.active_datapath =
+			NVSP_DATAPATH_VF;
+	else
+		init_pkt->msg.v4_msg.active_dp.active_datapath =
+			NVSP_DATAPATH_SYNTHETIC;
 
-static struct netvsc_device *alloc_net_device(struct hv_device *device)
+	vmbus_sendpacket(dev->channel, init_pkt,
+			       sizeof(struct nvsp_message),
+			       (unsigned long)init_pkt,
+			       VM_PKT_DATA_INBAND, 0);
+}
+
+static struct netvsc_device *alloc_net_device(void)
 {
 	struct netvsc_device *net_device;
-	struct net_device *ndev = hv_get_drvdata(device);
-	int i;
 
 	net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL);
 	if (!net_device)
@@ -50,32 +73,34 @@
 		return NULL;
 	}
 
+	net_device->mrc[0].buf = vzalloc(NETVSC_RECVSLOT_MAX *
+					 sizeof(struct recv_comp_data));
+
 	init_waitqueue_head(&net_device->wait_drain);
-	net_device->start_remove = false;
 	net_device->destroy = false;
-	net_device->dev = device;
-	net_device->ndev = ndev;
+	atomic_set(&net_device->open_cnt, 0);
 	net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
 	net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
+	init_completion(&net_device->channel_init_wait);
 
-	for (i = 0; i < num_online_cpus(); i++)
-		spin_lock_init(&net_device->msd[i].lock);
-
-	hv_set_drvdata(device, net_device);
 	return net_device;
 }
 
 static void free_netvsc_device(struct netvsc_device *nvdev)
 {
+	int i;
+
+	for (i = 0; i < VRSS_CHANNEL_MAX; i++)
+		vfree(nvdev->mrc[i].buf);
+
 	kfree(nvdev->cb_buffer);
 	kfree(nvdev);
 }
 
 static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 {
-	struct netvsc_device *net_device;
+	struct netvsc_device *net_device = hv_device_to_netvsc_device(device);
 
-	net_device = hv_get_drvdata(device);
 	if (net_device && net_device->destroy)
 		net_device = NULL;
 
@@ -84,27 +109,26 @@
 
 static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
 {
-	struct netvsc_device *net_device;
-
-	net_device = hv_get_drvdata(device);
+	struct netvsc_device *net_device = hv_device_to_netvsc_device(device);
 
 	if (!net_device)
 		goto get_in_err;
 
 	if (net_device->destroy &&
-		atomic_read(&net_device->num_outstanding_sends) == 0)
+	    atomic_read(&net_device->num_outstanding_sends) == 0 &&
+	    atomic_read(&net_device->num_outstanding_recvs) == 0)
 		net_device = NULL;
 
 get_in_err:
 	return net_device;
 }
 
-
-static int netvsc_destroy_buf(struct netvsc_device *net_device)
+static void netvsc_destroy_buf(struct hv_device *device)
 {
 	struct nvsp_message *revoke_packet;
-	int ret = 0;
-	struct net_device *ndev = net_device->ndev;
+	struct net_device *ndev = hv_get_drvdata(device);
+	struct netvsc_device *net_device = net_device_to_netvsc_device(ndev);
+	int ret;
 
 	/*
 	 * If we got a section count, it means we received a
@@ -122,7 +146,7 @@
 		revoke_packet->msg.v1_msg.
 		revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
 
-		ret = vmbus_sendpacket(net_device->dev->channel,
+		ret = vmbus_sendpacket(device->channel,
 				       revoke_packet,
 				       sizeof(struct nvsp_message),
 				       (unsigned long)revoke_packet,
@@ -134,14 +158,14 @@
 		if (ret != 0) {
 			netdev_err(ndev, "unable to send "
 				"revoke receive buffer to netvsp\n");
-			return ret;
+			return;
 		}
 	}
 
 	/* Teardown the gpadl on the vsp end */
 	if (net_device->recv_buf_gpadl_handle) {
-		ret = vmbus_teardown_gpadl(net_device->dev->channel,
-			   net_device->recv_buf_gpadl_handle);
+		ret = vmbus_teardown_gpadl(device->channel,
+					   net_device->recv_buf_gpadl_handle);
 
 		/* If we failed here, we might as well return and have a leak
 		 * rather than continue and a bugchk
@@ -149,7 +173,7 @@
 		if (ret != 0) {
 			netdev_err(ndev,
 				   "unable to teardown receive buffer's gpadl\n");
-			return ret;
+			return;
 		}
 		net_device->recv_buf_gpadl_handle = 0;
 	}
@@ -182,7 +206,7 @@
 		revoke_packet->msg.v1_msg.revoke_send_buf.id =
 			NETVSC_SEND_BUFFER_ID;
 
-		ret = vmbus_sendpacket(net_device->dev->channel,
+		ret = vmbus_sendpacket(device->channel,
 				       revoke_packet,
 				       sizeof(struct nvsp_message),
 				       (unsigned long)revoke_packet,
@@ -193,12 +217,12 @@
 		if (ret != 0) {
 			netdev_err(ndev, "unable to send "
 				   "revoke send buffer to netvsp\n");
-			return ret;
+			return;
 		}
 	}
 	/* Teardown the gpadl on the vsp end */
 	if (net_device->send_buf_gpadl_handle) {
-		ret = vmbus_teardown_gpadl(net_device->dev->channel,
+		ret = vmbus_teardown_gpadl(device->channel,
 					   net_device->send_buf_gpadl_handle);
 
 		/* If we failed here, we might as well return and have a leak
@@ -207,7 +231,7 @@
 		if (ret != 0) {
 			netdev_err(ndev,
 				   "unable to teardown send buffer's gpadl\n");
-			return ret;
+			return;
 		}
 		net_device->send_buf_gpadl_handle = 0;
 	}
@@ -217,14 +241,11 @@
 		net_device->send_buf = NULL;
 	}
 	kfree(net_device->send_section_map);
-
-	return ret;
 }
 
 static int netvsc_init_buf(struct hv_device *device)
 {
 	int ret = 0;
-	unsigned long t;
 	struct netvsc_device *net_device;
 	struct nvsp_message *init_packet;
 	struct net_device *ndev;
@@ -233,7 +254,7 @@
 	net_device = get_outbound_net_device(device);
 	if (!net_device)
 		return -ENODEV;
-	ndev = net_device->ndev;
+	ndev = hv_get_drvdata(device);
 
 	node = cpu_to_node(device->channel->target_cpu);
 	net_device->recv_buf = vzalloc_node(net_device->recv_buf_size, node);
@@ -261,7 +282,6 @@
 		goto cleanup;
 	}
 
-
 	/* Notify the NetVsp of the gpadl handle */
 	init_packet = &net_device->channel_init_pkt;
 
@@ -285,9 +305,7 @@
 		goto cleanup;
 	}
 
-	t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
-	BUG_ON(t == 0);
-
+	wait_for_completion(&net_device->channel_init_wait);
 
 	/* Check the response */
 	if (init_packet->msg.v1_msg.
@@ -370,8 +388,7 @@
 		goto cleanup;
 	}
 
-	t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
-	BUG_ON(t == 0);
+	wait_for_completion(&net_device->channel_init_wait);
 
 	/* Check the response */
 	if (init_packet->msg.v1_msg.
@@ -391,7 +408,7 @@
 	/* Section count is simply the size divided by the section size.
 	 */
 	net_device->send_section_cnt =
-		net_device->send_buf_size/net_device->send_section_size;
+		net_device->send_buf_size / net_device->send_section_size;
 
 	dev_info(&device->device, "Send section size: %d, Section count:%d\n",
 		 net_device->send_section_size, net_device->send_section_cnt);
@@ -400,8 +417,8 @@
 	net_device->map_words = DIV_ROUND_UP(net_device->send_section_cnt,
 					     BITS_PER_LONG);
 
-	net_device->send_section_map =
-		kzalloc(net_device->map_words * sizeof(ulong), GFP_KERNEL);
+	net_device->send_section_map = kcalloc(net_device->map_words,
+					       sizeof(ulong), GFP_KERNEL);
 	if (net_device->send_section_map == NULL) {
 		ret = -ENOMEM;
 		goto cleanup;
@@ -410,21 +427,20 @@
 	goto exit;
 
 cleanup:
-	netvsc_destroy_buf(net_device);
+	netvsc_destroy_buf(device);
 
 exit:
 	return ret;
 }
 
-
 /* Negotiate NVSP protocol version */
 static int negotiate_nvsp_ver(struct hv_device *device,
 			      struct netvsc_device *net_device,
 			      struct nvsp_message *init_packet,
 			      u32 nvsp_ver)
 {
+	struct net_device *ndev = hv_get_drvdata(device);
 	int ret;
-	unsigned long t;
 
 	memset(init_packet, 0, sizeof(struct nvsp_message));
 	init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT;
@@ -441,10 +457,7 @@
 	if (ret != 0)
 		return ret;
 
-	t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
-
-	if (t == 0)
-		return -ETIMEDOUT;
+	wait_for_completion(&net_device->channel_init_wait);
 
 	if (init_packet->msg.init_msg.init_complete.status !=
 	    NVSP_STAT_SUCCESS)
@@ -456,13 +469,16 @@
 	/* NVSPv2 or later: Send NDIS config */
 	memset(init_packet, 0, sizeof(struct nvsp_message));
 	init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
-	init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu +
-						       ETH_HLEN;
+	init_packet->msg.v2_msg.send_ndis_config.mtu = ndev->mtu + ETH_HLEN;
 	init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1;
 
-	if (nvsp_ver >= NVSP_PROTOCOL_VERSION_5)
+	if (nvsp_ver >= NVSP_PROTOCOL_VERSION_5) {
 		init_packet->msg.v2_msg.send_ndis_config.capability.sriov = 1;
 
+		/* Teaming bit is needed to receive link speed updates */
+		init_packet->msg.v2_msg.send_ndis_config.capability.teaming = 1;
+	}
+
 	ret = vmbus_sendpacket(device->channel, init_packet,
 				sizeof(struct nvsp_message),
 				(unsigned long)init_packet,
@@ -477,20 +493,19 @@
 	struct netvsc_device *net_device;
 	struct nvsp_message *init_packet;
 	int ndis_version;
-	struct net_device *ndev;
-	u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
+	const u32 ver_list[] = {
+		NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
 		NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 };
-	int i, num_ver = 4; /* number of different NVSP versions */
+	int i;
 
 	net_device = get_outbound_net_device(device);
 	if (!net_device)
 		return -ENODEV;
-	ndev = net_device->ndev;
 
 	init_packet = &net_device->channel_init_pkt;
 
 	/* Negotiate the latest NVSP protocol supported */
-	for (i = num_ver - 1; i >= 0; i--)
+	for (i = ARRAY_SIZE(ver_list) - 1; i >= 0; i--)
 		if (negotiate_nvsp_ver(device, net_device, init_packet,
 				       ver_list[i])  == 0) {
 			net_device->nvsp_version = ver_list[i];
@@ -541,34 +556,23 @@
 	return ret;
 }
 
-static void netvsc_disconnect_vsp(struct netvsc_device *net_device)
+static void netvsc_disconnect_vsp(struct hv_device *device)
 {
-	netvsc_destroy_buf(net_device);
+	netvsc_destroy_buf(device);
 }
 
 /*
  * netvsc_device_remove - Callback when the root bus device is removed
  */
-int netvsc_device_remove(struct hv_device *device)
+void netvsc_device_remove(struct hv_device *device)
 {
-	struct netvsc_device *net_device;
-	unsigned long flags;
-
-	net_device = hv_get_drvdata(device);
-
-	netvsc_disconnect_vsp(net_device);
+	struct net_device *ndev = hv_get_drvdata(device);
+	struct net_device_context *net_device_ctx = netdev_priv(ndev);
+	struct netvsc_device *net_device = net_device_ctx->nvdev;
 
-	/*
-	 * Since we have already drained, we don't need to busy wait
-	 * as was done in final_release_stor_device()
-	 * Note that we cannot set the ext pointer to NULL until
-	 * we have drained - to drain the outgoing packets, we need to
-	 * allow incoming packets.
-	 */
+	netvsc_disconnect_vsp(device);
 
-	spin_lock_irqsave(&device->channel->inbound_lock, flags);
-	hv_set_drvdata(device, NULL);
-	spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
+	net_device_ctx->nvdev = NULL;
 
 	/*
 	 * At this point, no one should be accessing net_device
@@ -582,10 +586,8 @@
 	/* Release all resources */
 	vfree(net_device->sub_cb_buf);
 	free_netvsc_device(net_device);
-	return 0;
 }
 
-
 #define RING_AVAIL_PERCENT_HIWATER 20
 #define RING_AVAIL_PERCENT_LOWATER 10
 
@@ -609,72 +611,79 @@
 	sync_change_bit(index, net_device->send_section_map);
 }
 
+static void netvsc_send_tx_complete(struct netvsc_device *net_device,
+				    struct vmbus_channel *incoming_channel,
+				    struct hv_device *device,
+				    struct vmpacket_descriptor *packet)
+{
+	struct sk_buff *skb = (struct sk_buff *)(unsigned long)packet->trans_id;
+	struct net_device *ndev = hv_get_drvdata(device);
+	struct net_device_context *net_device_ctx = netdev_priv(ndev);
+	struct vmbus_channel *channel = device->channel;
+	int num_outstanding_sends;
+	u16 q_idx = 0;
+	int queue_sends;
+
+	/* Notify the layer above us */
+	if (likely(skb)) {
+		struct hv_netvsc_packet *nvsc_packet
+			= (struct hv_netvsc_packet *)skb->cb;
+		u32 send_index = nvsc_packet->send_buf_index;
+
+		if (send_index != NETVSC_INVALID_INDEX)
+			netvsc_free_send_slot(net_device, send_index);
+		q_idx = nvsc_packet->q_idx;
+		channel = incoming_channel;
+
+		dev_consume_skb_any(skb);
+	}
+
+	num_outstanding_sends =
+		atomic_dec_return(&net_device->num_outstanding_sends);
+	queue_sends = atomic_dec_return(&net_device->queue_sends[q_idx]);
+
+	if (net_device->destroy && num_outstanding_sends == 0)
+		wake_up(&net_device->wait_drain);
+
+	if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
+	    !net_device_ctx->start_remove &&
+	    (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER ||
+	     queue_sends < 1))
+		netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx));
+}
+
 static void netvsc_send_completion(struct netvsc_device *net_device,
+				   struct vmbus_channel *incoming_channel,
 				   struct hv_device *device,
 				   struct vmpacket_descriptor *packet)
 {
 	struct nvsp_message *nvsp_packet;
-	struct hv_netvsc_packet *nvsc_packet;
-	struct net_device *ndev;
-	u32 send_index;
-
-	ndev = net_device->ndev;
+	struct net_device *ndev = hv_get_drvdata(device);
 
 	nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
-			(packet->offset8 << 3));
+					      (packet->offset8 << 3));
 
-	if ((nvsp_packet->hdr.msg_type == NVSP_MSG_TYPE_INIT_COMPLETE) ||
-	    (nvsp_packet->hdr.msg_type ==
-	     NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) ||
-	    (nvsp_packet->hdr.msg_type ==
-	     NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE) ||
-	    (nvsp_packet->hdr.msg_type ==
-	     NVSP_MSG5_TYPE_SUBCHANNEL)) {
+	switch (nvsp_packet->hdr.msg_type) {
+	case NVSP_MSG_TYPE_INIT_COMPLETE:
+	case NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE:
+	case NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE:
+	case NVSP_MSG5_TYPE_SUBCHANNEL:
 		/* Copy the response back */
 		memcpy(&net_device->channel_init_pkt, nvsp_packet,
 		       sizeof(struct nvsp_message));
 		complete(&net_device->channel_init_wait);
-	} else if (nvsp_packet->hdr.msg_type ==
-		   NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) {
-		int num_outstanding_sends;
-		u16 q_idx = 0;
-		struct vmbus_channel *channel = device->channel;
-		int queue_sends;
-
-		/* Get the send context */
-		nvsc_packet = (struct hv_netvsc_packet *)(unsigned long)
-			packet->trans_id;
-
-		/* Notify the layer above us */
-		if (nvsc_packet) {
-			send_index = nvsc_packet->send_buf_index;
-			if (send_index != NETVSC_INVALID_INDEX)
-				netvsc_free_send_slot(net_device, send_index);
-			q_idx = nvsc_packet->q_idx;
-			channel = nvsc_packet->channel;
-			nvsc_packet->send_completion(nvsc_packet->
-						     send_completion_ctx);
-		}
+		break;
 
-		num_outstanding_sends =
-			atomic_dec_return(&net_device->num_outstanding_sends);
-		queue_sends = atomic_dec_return(&net_device->
-						queue_sends[q_idx]);
-
-		if (net_device->destroy && num_outstanding_sends == 0)
-			wake_up(&net_device->wait_drain);
-
-		if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
-		    !net_device->start_remove &&
-		    (hv_ringbuf_avail_percent(&channel->outbound) >
-		     RING_AVAIL_PERCENT_HIWATER || queue_sends < 1))
-				netif_tx_wake_queue(netdev_get_tx_queue(
-						    ndev, q_idx));
-	} else {
-		netdev_err(ndev, "Unknown send completion packet type- "
-			   "%d received!!\n", nvsp_packet->hdr.msg_type);
-	}
+	case NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE:
+		netvsc_send_tx_complete(net_device, incoming_channel,
+					device, packet);
+		break;
 
+	default:
+		netdev_err(ndev,
+			   "Unknown send completion type %d received!!\n",
+			   nvsp_packet->hdr.msg_type);
+	}
 }
 
 static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
@@ -705,12 +714,17 @@
 static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
 				   unsigned int section_index,
 				   u32 pend_size,
-				   struct hv_netvsc_packet *packet)
+				   struct hv_netvsc_packet *packet,
+				   struct rndis_message *rndis_msg,
+				   struct hv_page_buffer **pb,
+				   struct sk_buff *skb)
 {
 	char *start = net_device->send_buf;
 	char *dest = start + (section_index * net_device->send_section_size)
 		     + pend_size;
 	int i;
+	bool is_data_pkt = (skb != NULL) ? true : false;
+	bool xmit_more = (skb != NULL) ? skb->xmit_more : false;
 	u32 msg_size = 0;
 	u32 padding = 0;
 	u32 remain = packet->total_data_buflen % net_device->pkt_align;
@@ -718,17 +732,17 @@
 		packet->page_buf_cnt;
 
 	/* Add padding */
-	if (packet->is_data_pkt && packet->xmit_more && remain &&
+	if (is_data_pkt && xmit_more && remain &&
 	    !packet->cp_partial) {
 		padding = net_device->pkt_align - remain;
-		packet->rndis_msg->msg_len += padding;
+		rndis_msg->msg_len += padding;
 		packet->total_data_buflen += padding;
 	}
 
 	for (i = 0; i < page_count; i++) {
-		char *src = phys_to_virt(packet->page_buf[i].pfn << PAGE_SHIFT);
-		u32 offset = packet->page_buf[i].offset;
-		u32 len = packet->page_buf[i].len;
+		char *src = phys_to_virt((*pb)[i].pfn << PAGE_SHIFT);
+		u32 offset = (*pb)[i].offset;
+		u32 len = (*pb)[i].len;
 
 		memcpy(dest, (src + offset), len);
 		msg_size += len;
@@ -744,20 +758,24 @@
 }
 
 static inline int netvsc_send_pkt(
+	struct hv_device *device,
 	struct hv_netvsc_packet *packet,
-	struct netvsc_device *net_device)
+	struct netvsc_device *net_device,
+	struct hv_page_buffer **pb,
+	struct sk_buff *skb)
 {
 	struct nvsp_message nvmsg;
-	struct vmbus_channel *out_channel = packet->channel;
 	u16 q_idx = packet->q_idx;
-	struct net_device *ndev = net_device->ndev;
+	struct vmbus_channel *out_channel = net_device->chn_table[q_idx];
+	struct net_device *ndev = hv_get_drvdata(device);
 	u64 req_id;
 	int ret;
 	struct hv_page_buffer *pgbuf;
 	u32 ring_avail = hv_ringbuf_avail_percent(&out_channel->outbound);
+	bool xmit_more = (skb != NULL) ? skb->xmit_more : false;
 
 	nvmsg.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
-	if (packet->is_data_pkt) {
+	if (skb != NULL) {
 		/* 0 is RMC_DATA; */
 		nvmsg.msg.v1_msg.send_rndis_pkt.channel_type = 0;
 	} else {
@@ -773,10 +791,7 @@
 		nvmsg.msg.v1_msg.send_rndis_pkt.send_buf_section_size =
 			packet->total_data_buflen;
 
-	if (packet->send_completion)
-		req_id = (ulong)packet;
-	else
-		req_id = 0;
+	req_id = (ulong)skb;
 
 	if (out_channel->rescind)
 		return -ENODEV;
@@ -789,11 +804,11 @@
 	 * unnecessarily.
 	 */
 	if (ring_avail < (RING_AVAIL_PERCENT_LOWATER + 1))
-		packet->xmit_more = false;
+		xmit_more = false;
 
 	if (packet->page_buf_cnt) {
-		pgbuf = packet->cp_partial ? packet->page_buf +
-			packet->rmsg_pgcnt : packet->page_buf;
+		pgbuf = packet->cp_partial ? (*pb) +
+			packet->rmsg_pgcnt : (*pb);
 		ret = vmbus_sendpacket_pagebuffer_ctl(out_channel,
 						      pgbuf,
 						      packet->page_buf_cnt,
@@ -801,14 +816,14 @@
 						      sizeof(struct nvsp_message),
 						      req_id,
 						      VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED,
-						      !packet->xmit_more);
+						      !xmit_more);
 	} else {
 		ret = vmbus_sendpacket_ctl(out_channel, &nvmsg,
 					   sizeof(struct nvsp_message),
 					   req_id,
 					   VM_PKT_DATA_INBAND,
 					   VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED,
-					   !packet->xmit_more);
+					   !xmit_more);
 	}
 
 	if (ret == 0) {
@@ -839,42 +854,60 @@
 	return ret;
 }
 
+/* Move packet out of multi send data (msd), and clear msd */
+static inline void move_pkt_msd(struct hv_netvsc_packet **msd_send,
+				struct sk_buff **msd_skb,
+				struct multi_send_data *msdp)
+{
+	*msd_skb = msdp->skb;
+	*msd_send = msdp->pkt;
+	msdp->skb = NULL;
+	msdp->pkt = NULL;
+	msdp->count = 0;
+}
+
 int netvsc_send(struct hv_device *device,
-		struct hv_netvsc_packet *packet)
+		struct hv_netvsc_packet *packet,
+		struct rndis_message *rndis_msg,
+		struct hv_page_buffer **pb,
+		struct sk_buff *skb)
 {
 	struct netvsc_device *net_device;
-	int ret = 0, m_ret = 0;
+	int ret = 0;
 	struct vmbus_channel *out_channel;
 	u16 q_idx = packet->q_idx;
 	u32 pktlen = packet->total_data_buflen, msd_len = 0;
 	unsigned int section_index = NETVSC_INVALID_INDEX;
-	unsigned long flag;
 	struct multi_send_data *msdp;
 	struct hv_netvsc_packet *msd_send = NULL, *cur_send = NULL;
+	struct sk_buff *msd_skb = NULL;
 	bool try_batch;
+	bool xmit_more = (skb != NULL) ? skb->xmit_more : false;
 
 	net_device = get_outbound_net_device(device);
 	if (!net_device)
 		return -ENODEV;
 
 	out_channel = net_device->chn_table[q_idx];
-	if (!out_channel) {
-		out_channel = device->channel;
-		q_idx = 0;
-		packet->q_idx = 0;
-	}
-	packet->channel = out_channel;
+
 	packet->send_buf_index = NETVSC_INVALID_INDEX;
 	packet->cp_partial = false;
 
+	/* Send control message directly without accessing msd (Multi-Send
+	 * Data) field which may be changed during data packet processing.
+	 */
+	if (!skb) {
+		cur_send = packet;
+		goto send_now;
+	}
+
 	msdp = &net_device->msd[q_idx];
 
 	/* batch packets in send buffer if possible */
-	spin_lock_irqsave(&msdp->lock, flag);
 	if (msdp->pkt)
 		msd_len = msdp->pkt->total_data_buflen;
 
-	try_batch = packet->is_data_pkt && msd_len > 0 && msdp->count <
+	try_batch = (skb != NULL) && msd_len > 0 && msdp->count <
 		    net_device->max_pkt;
 
 	if (try_batch && msd_len + pktlen + net_device->pkt_align <
@@ -886,21 +919,19 @@
 		section_index = msdp->pkt->send_buf_index;
 		packet->cp_partial = true;
 
-	} else if (packet->is_data_pkt && pktlen + net_device->pkt_align <
+	} else if ((skb != NULL) && pktlen + net_device->pkt_align <
 		   net_device->send_section_size) {
 		section_index = netvsc_get_next_send_section(net_device);
 		if (section_index != NETVSC_INVALID_INDEX) {
-				msd_send = msdp->pkt;
-				msdp->pkt = NULL;
-				msdp->count = 0;
-				msd_len = 0;
+			move_pkt_msd(&msd_send, &msd_skb, msdp);
+			msd_len = 0;
 		}
 	}
 
 	if (section_index != NETVSC_INVALID_INDEX) {
 		netvsc_copy_to_send_buf(net_device,
 					section_index, msd_len,
-					packet);
+					packet, rndis_msg, pb, skb);
 
 		packet->send_buf_index = section_index;
 
@@ -912,38 +943,38 @@
 			packet->total_data_buflen += msd_len;
 		}
 
-		if (msdp->pkt)
-			netvsc_xmit_completion(msdp->pkt);
+		if (msdp->skb)
+			dev_consume_skb_any(msdp->skb);
 
-		if (packet->xmit_more && !packet->cp_partial) {
+		if (xmit_more && !packet->cp_partial) {
+			msdp->skb = skb;
 			msdp->pkt = packet;
 			msdp->count++;
 		} else {
 			cur_send = packet;
+			msdp->skb = NULL;
 			msdp->pkt = NULL;
 			msdp->count = 0;
 		}
 	} else {
-		msd_send = msdp->pkt;
-		msdp->pkt = NULL;
-		msdp->count = 0;
+		move_pkt_msd(&msd_send, &msd_skb, msdp);
 		cur_send = packet;
 	}
 
-	spin_unlock_irqrestore(&msdp->lock, flag);
-
 	if (msd_send) {
-		m_ret = netvsc_send_pkt(msd_send, net_device);
+		int m_ret = netvsc_send_pkt(device, msd_send, net_device,
+					    NULL, msd_skb);
 
 		if (m_ret != 0) {
 			netvsc_free_send_slot(net_device,
 					      msd_send->send_buf_index);
-			netvsc_xmit_completion(msd_send);
+			dev_kfree_skb_any(msd_skb);
 		}
 	}
 
+send_now:
 	if (cur_send)
-		ret = netvsc_send_pkt(cur_send, net_device);
+		ret = netvsc_send_pkt(device, cur_send, net_device, pb, skb);
 
 	if (ret != 0 && section_index != NETVSC_INVALID_INDEX)
 		netvsc_free_send_slot(net_device, section_index);
@@ -951,51 +982,121 @@
 	return ret;
 }
 
-static void netvsc_send_recv_completion(struct hv_device *device,
-					struct vmbus_channel *channel,
-					struct netvsc_device *net_device,
-					u64 transaction_id, u32 status)
+static int netvsc_send_recv_completion(struct vmbus_channel *channel,
+				       u64 transaction_id, u32 status)
 {
 	struct nvsp_message recvcompMessage;
-	int retries = 0;
 	int ret;
-	struct net_device *ndev;
-
-	ndev = net_device->ndev;
 
 	recvcompMessage.hdr.msg_type =
 				NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
 
 	recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = status;
 
-retry_send_cmplt:
 	/* Send the completion */
 	ret = vmbus_sendpacket(channel, &recvcompMessage,
-			       sizeof(struct nvsp_message), transaction_id,
-			       VM_PKT_COMP, 0);
-	if (ret == 0) {
-		/* success */
-		/* no-op */
-	} else if (ret == -EAGAIN) {
-		/* no more room...wait a bit and attempt to retry 3 times */
-		retries++;
-		netdev_err(ndev, "unable to send receive completion pkt"
-			" (tid %llx)...retrying %d\n", transaction_id, retries);
-
-		if (retries < 4) {
-			udelay(100);
-			goto retry_send_cmplt;
-		} else {
-			netdev_err(ndev, "unable to send receive "
-				"completion pkt (tid %llx)...give up retrying\n",
-				transaction_id);
-		}
-	} else {
-		netdev_err(ndev, "unable to send receive "
-			"completion pkt - %llx\n", transaction_id);
+			       sizeof(struct nvsp_message_header) + sizeof(u32),
+			       transaction_id, VM_PKT_COMP, 0);
+
+	return ret;
+}
+
+static inline void count_recv_comp_slot(struct netvsc_device *nvdev, u16 q_idx,
+					u32 *filled, u32 *avail)
+{
+	u32 first = nvdev->mrc[q_idx].first;
+	u32 next = nvdev->mrc[q_idx].next;
+
+	*filled = (first > next) ? NETVSC_RECVSLOT_MAX - first + next :
+		  next - first;
+
+	*avail = NETVSC_RECVSLOT_MAX - *filled - 1;
+}
+
+/* Read the first filled slot, no change to index */
+static inline struct recv_comp_data *read_recv_comp_slot(struct netvsc_device
+							 *nvdev, u16 q_idx)
+{
+	u32 filled, avail;
+
+	if (!nvdev->mrc[q_idx].buf)
+		return NULL;
+
+	count_recv_comp_slot(nvdev, q_idx, &filled, &avail);
+	if (!filled)
+		return NULL;
+
+	return nvdev->mrc[q_idx].buf + nvdev->mrc[q_idx].first *
+	       sizeof(struct recv_comp_data);
+}
+
+/* Put the first filled slot back to available pool */
+static inline void put_recv_comp_slot(struct netvsc_device *nvdev, u16 q_idx)
+{
+	int num_recv;
+
+	nvdev->mrc[q_idx].first = (nvdev->mrc[q_idx].first + 1) %
+				  NETVSC_RECVSLOT_MAX;
+
+	num_recv = atomic_dec_return(&nvdev->num_outstanding_recvs);
+
+	if (nvdev->destroy && num_recv == 0)
+		wake_up(&nvdev->wait_drain);
+}
+
+/* Check and send pending recv completions */
+static void netvsc_chk_recv_comp(struct netvsc_device *nvdev,
+				 struct vmbus_channel *channel, u16 q_idx)
+{
+	struct recv_comp_data *rcd;
+	int ret;
+
+	while (true) {
+		rcd = read_recv_comp_slot(nvdev, q_idx);
+		if (!rcd)
+			break;
+
+		ret = netvsc_send_recv_completion(channel, rcd->tid,
+						  rcd->status);
+		if (ret)
+			break;
+
+		put_recv_comp_slot(nvdev, q_idx);
 	}
 }
 
+#define NETVSC_RCD_WATERMARK 80
+
+/* Get next available slot */
+static inline struct recv_comp_data *get_recv_comp_slot(
+	struct netvsc_device *nvdev, struct vmbus_channel *channel, u16 q_idx)
+{
+	u32 filled, avail, next;
+	struct recv_comp_data *rcd;
+
+	if (!nvdev->recv_section)
+		return NULL;
+
+	if (!nvdev->mrc[q_idx].buf)
+		return NULL;
+
+	if (atomic_read(&nvdev->num_outstanding_recvs) >
+	    nvdev->recv_section->num_sub_allocs * NETVSC_RCD_WATERMARK / 100)
+		netvsc_chk_recv_comp(nvdev, channel, q_idx);
+
+	count_recv_comp_slot(nvdev, q_idx, &filled, &avail);
+	if (!avail)
+		return NULL;
+
+	next = nvdev->mrc[q_idx].next;
+	rcd = nvdev->mrc[q_idx].buf + next * sizeof(struct recv_comp_data);
+	nvdev->mrc[q_idx].next = (next + 1) % NETVSC_RECVSLOT_MAX;
+
+	atomic_inc(&nvdev->num_outstanding_recvs);
+
+	return rcd;
+}
+
 static void netvsc_receive(struct netvsc_device *net_device,
 			struct vmbus_channel *channel,
 			struct hv_device *device,
@@ -1008,9 +1109,11 @@
 	u32 status = NVSP_STAT_SUCCESS;
 	int i;
 	int count = 0;
-	struct net_device *ndev;
-
-	ndev = net_device->ndev;
+	struct net_device *ndev = hv_get_drvdata(device);
+	void *data;
+	int ret;
+	struct recv_comp_data *rcd;
+	u16 q_idx = channel->offermsg.offer.sub_channel_index;
 
 	/*
 	 * All inbound packets other than send completion should be xfer page
@@ -1043,41 +1146,53 @@
 	}
 
 	count = vmxferpage_packet->range_cnt;
-	netvsc_packet->channel = channel;
 
 	/* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
 	for (i = 0; i < count; i++) {
 		/* Initialize the netvsc packet */
-		netvsc_packet->status = NVSP_STAT_SUCCESS;
-		netvsc_packet->data = (void *)((unsigned long)net_device->
+		data = (void *)((unsigned long)net_device->
 			recv_buf + vmxferpage_packet->ranges[i].byte_offset);
 		netvsc_packet->total_data_buflen =
 					vmxferpage_packet->ranges[i].byte_count;
 
 		/* Pass it to the upper layer */
-		rndis_filter_receive(device, netvsc_packet);
+		status = rndis_filter_receive(device, netvsc_packet, &data,
+					      channel);
+	}
 
-		if (netvsc_packet->status != NVSP_STAT_SUCCESS)
-			status = NVSP_STAT_FAIL;
+	if (!net_device->mrc[q_idx].buf) {
+		ret = netvsc_send_recv_completion(channel,
+						  vmxferpage_packet->d.trans_id,
+						  status);
+		if (ret)
+			netdev_err(ndev, "Recv_comp q:%hd, tid:%llx, err:%d\n",
+				   q_idx, vmxferpage_packet->d.trans_id, ret);
+		return;
 	}
 
-	netvsc_send_recv_completion(device, channel, net_device,
-				    vmxferpage_packet->d.trans_id, status);
-}
+	rcd = get_recv_comp_slot(net_device, channel, q_idx);
 
+	if (!rcd) {
+		netdev_err(ndev, "Recv_comp full buf q:%hd, tid:%llx\n",
+			   q_idx, vmxferpage_packet->d.trans_id);
+		return;
+	}
+
+	rcd->tid = vmxferpage_packet->d.trans_id;
+	rcd->status = status;
+}
 
 static void netvsc_send_table(struct hv_device *hdev,
 			      struct nvsp_message *nvmsg)
 {
 	struct netvsc_device *nvscdev;
-	struct net_device *ndev;
+	struct net_device *ndev = hv_get_drvdata(hdev);
 	int i;
 	u32 count, *tab;
 
 	nvscdev = get_outbound_net_device(hdev);
 	if (!nvscdev)
 		return;
-	ndev = nvscdev->ndev;
 
 	count = nvmsg->msg.v5_msg.send_table.count;
 	if (count != VRSS_SEND_TAB_SIZE) {
@@ -1092,16 +1207,16 @@
 		nvscdev->send_table[i] = tab[i];
 }
 
-static void netvsc_send_vf(struct netvsc_device *nvdev,
+static void netvsc_send_vf(struct net_device_context *net_device_ctx,
 			   struct nvsp_message *nvmsg)
 {
-	nvdev->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated;
-	nvdev->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial;
+	net_device_ctx->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated;
+	net_device_ctx->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial;
 }
 
 static inline void netvsc_receive_inband(struct hv_device *hdev,
-					 struct netvsc_device *nvdev,
-					 struct nvsp_message *nvmsg)
+				 struct net_device_context *net_device_ctx,
+				 struct nvsp_message *nvmsg)
 {
 	switch (nvmsg->hdr.msg_type) {
 	case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE:
@@ -1109,7 +1224,40 @@
 		break;
 
 	case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
-		netvsc_send_vf(nvdev, nvmsg);
+		netvsc_send_vf(net_device_ctx, nvmsg);
+		break;
+	}
+}
+
+static void netvsc_process_raw_pkt(struct hv_device *device,
+				   struct vmbus_channel *channel,
+				   struct netvsc_device *net_device,
+				   struct net_device *ndev,
+				   u64 request_id,
+				   struct vmpacket_descriptor *desc)
+{
+	struct nvsp_message *nvmsg;
+	struct net_device_context *net_device_ctx = netdev_priv(ndev);
+
+	nvmsg = (struct nvsp_message *)((unsigned long)
+		desc + (desc->offset8 << 3));
+
+	switch (desc->type) {
+	case VM_PKT_COMP:
+		netvsc_send_completion(net_device, channel, device, desc);
+		break;
+
+	case VM_PKT_DATA_USING_XFER_PAGES:
+		netvsc_receive(net_device, channel, device, desc);
+		break;
+
+	case VM_PKT_DATA_INBAND:
+		netvsc_receive_inband(device, net_device_ctx, nvmsg);
+		break;
+
+	default:
+		netdev_err(ndev, "unhandled packet type %d, tid %llx\n",
+			   desc->type, request_id);
 		break;
 	}
 }
@@ -1118,6 +1266,7 @@
 {
 	int ret;
 	struct vmbus_channel *channel = (struct vmbus_channel *)context;
+	u16 q_idx = channel->offermsg.offer.sub_channel_index;
 	struct hv_device *device;
 	struct netvsc_device *net_device;
 	u32 bytes_recvd;
@@ -1126,7 +1275,7 @@
 	unsigned char *buffer;
 	int bufferlen = NETVSC_PACKET_SIZE;
 	struct net_device *ndev;
-	struct nvsp_message *nvmsg;
+	bool need_to_commit = false;
 
 	if (channel->primary_channel != NULL)
 		device = channel->primary_channel->device_obj;
@@ -1136,43 +1285,42 @@
 	net_device = get_inbound_net_device(device);
 	if (!net_device)
 		return;
-	ndev = net_device->ndev;
+	ndev = hv_get_drvdata(device);
 	buffer = get_per_channel_state(channel);
 
+	/* commit_rd_index() -> hv_signal_on_read() needs this. */
+	init_cached_read_index(channel);
+
 	do {
+		desc = get_next_pkt_raw(channel);
+		if (desc != NULL) {
+			netvsc_process_raw_pkt(device,
+					       channel,
+					       net_device,
+					       ndev,
+					       desc->trans_id,
+					       desc);
+
+			put_pkt_raw(channel, desc);
+			need_to_commit = true;
+			continue;
+		}
+		if (need_to_commit) {
+			need_to_commit = false;
+			commit_rd_index(channel);
+		}
+
 		ret = vmbus_recvpacket_raw(channel, buffer, bufferlen,
 					   &bytes_recvd, &request_id);
 		if (ret == 0) {
 			if (bytes_recvd > 0) {
 				desc = (struct vmpacket_descriptor *)buffer;
-				nvmsg = (struct nvsp_message *)((unsigned long)
-					 desc + (desc->offset8 << 3));
-				switch (desc->type) {
-				case VM_PKT_COMP:
-					netvsc_send_completion(net_device,
-								device, desc);
-					break;
-
-				case VM_PKT_DATA_USING_XFER_PAGES:
-					netvsc_receive(net_device, channel,
-						       device, desc);
-					break;
-
-				case VM_PKT_DATA_INBAND:
-					netvsc_receive_inband(device,
-							      net_device,
-							      nvmsg);
-					break;
-
-				default:
-					netdev_err(ndev,
-						   "unhandled packet type %d, "
-						   "tid %llx len %d\n",
-						   desc->type, request_id,
-						   bytes_recvd);
-					break;
-				}
-
+				netvsc_process_raw_pkt(device,
+						       channel,
+						       net_device,
+						       ndev,
+						       request_id,
+						       desc);
 			} else {
 				/*
 				 * We are done for this pass.
@@ -1195,11 +1343,15 @@
 
 			bufferlen = bytes_recvd;
 		}
+
+		init_cached_read_index(channel);
+
 	} while (1);
 
 	if (bufferlen > NETVSC_PACKET_SIZE)
 		kfree(buffer);
-	return;
+
+	netvsc_chk_recv_comp(net_device, channel, q_idx);
 }
 
 /*
@@ -1208,33 +1360,19 @@
  */
 int netvsc_device_add(struct hv_device *device, void *additional_info)
 {
-	int ret = 0;
+	int i, ret = 0;
 	int ring_size =
 	((struct netvsc_device_info *)additional_info)->ring_size;
 	struct netvsc_device *net_device;
-	struct net_device *ndev;
+	struct net_device *ndev = hv_get_drvdata(device);
+	struct net_device_context *net_device_ctx = netdev_priv(ndev);
 
-	net_device = alloc_net_device(device);
+	net_device = alloc_net_device();
 	if (!net_device)
 		return -ENOMEM;
 
 	net_device->ring_size = ring_size;
 
-	/*
-	 * Coming into this function, struct net_device * is
-	 * registered as the driver private data.
-	 * In alloc_net_device(), we register struct netvsc_device *
-	 * as the driver private data and stash away struct net_device *
-	 * in struct netvsc_device *.
-	 */
-	ndev = net_device->ndev;
-
-	/* Add netvsc_device context to netvsc_device */
-	net_device->nd_ctx = netdev_priv(ndev);
-
-	/* Initialize the NetVSC channel extension */
-	init_completion(&net_device->channel_init_wait);
-
 	set_per_channel_state(device->channel, net_device->cb_buffer);
 
 	/* Open the channel */
@@ -1250,7 +1388,19 @@
 	/* Channel is opened */
 	pr_info("hv_netvsc channel opened successfully\n");
 
-	net_device->chn_table[0] = device->channel;
+	/* If we're reopening the device we may have multiple queues, fill the
+	 * chn_table with the default channel to use it before subchannels are
+	 * opened.
+	 */
+	for (i = 0; i < VRSS_CHANNEL_MAX; i++)
+		net_device->chn_table[i] = device->channel;
+
+	/* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is
+	 * populated.
+	 */
+	wmb();
+
+	net_device_ctx->nvdev = net_device;
 
 	/* Connect with the NetVsp */
 	ret = netvsc_connect_vsp(device);
--- linux-4.4.0.orig/drivers/net/hyperv/netvsc_drv.c
+++ linux-4.4.0/drivers/net/hyperv/netvsc_drv.c
@@ -40,8 +40,20 @@
 
 #include "hyperv_net.h"
 
+/* Restrict GSO size to account for NVGRE */
+#define NETVSC_GSO_MAX_SIZE	62768
 
 #define RING_SIZE_MIN 64
+#define LINKCHANGE_INT (2 * HZ)
+#define NETVSC_HW_FEATURES	(NETIF_F_RXCSUM | \
+				 NETIF_F_SG | \
+				 NETIF_F_TSO | \
+				 NETIF_F_TSO6 | \
+				 NETIF_F_HW_CSUM)
+
+/* Restrict GSO size to account for NVGRE */
+#define NETVSC_GSO_MAX_SIZE	62768
+
 static int ring_size = 128;
 module_param(ring_size, int, S_IRUGO);
 MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
@@ -61,18 +73,19 @@
 {
 	struct net_device_context *ndevctx =
 		container_of(w, struct net_device_context, work);
-	struct netvsc_device *nvdev;
+	struct hv_device *device_obj = ndevctx->device_ctx;
+	struct net_device *ndev = hv_get_drvdata(device_obj);
+	struct netvsc_device *nvdev = ndevctx->nvdev;
 	struct rndis_device *rdev;
 
-	nvdev = hv_get_drvdata(ndevctx->device_ctx);
-	if (nvdev == NULL || nvdev->ndev == NULL)
+	if (!nvdev)
 		return;
 
 	rdev = nvdev->extension;
 	if (rdev == NULL)
 		return;
 
-	if (nvdev->ndev->flags & IFF_PROMISC)
+	if (ndev->flags & IFF_PROMISC)
 		rndis_filter_set_packet_filter(rdev,
 			NDIS_PACKET_TYPE_PROMISCUOUS);
 	else
@@ -91,16 +104,14 @@
 
 static int netvsc_open(struct net_device *net)
 {
-	struct net_device_context *net_device_ctx = netdev_priv(net);
-	struct hv_device *device_obj = net_device_ctx->device_ctx;
-	struct netvsc_device *nvdev;
+	struct netvsc_device *nvdev = net_device_to_netvsc_device(net);
 	struct rndis_device *rdev;
 	int ret = 0;
 
 	netif_carrier_off(net);
 
 	/* Open up the device */
-	ret = rndis_filter_open(device_obj);
+	ret = rndis_filter_open(nvdev);
 	if (ret != 0) {
 		netdev_err(net, "unable to open device (ret %d).\n", ret);
 		return ret;
@@ -108,7 +119,6 @@
 
 	netif_tx_wake_all_queues(net);
 
-	nvdev = hv_get_drvdata(device_obj);
 	rdev = nvdev->extension;
 	if (!rdev->link_state)
 		netif_carrier_on(net);
@@ -119,8 +129,7 @@
 static int netvsc_close(struct net_device *net)
 {
 	struct net_device_context *net_device_ctx = netdev_priv(net);
-	struct hv_device *device_obj = net_device_ctx->device_ctx;
-	struct netvsc_device *nvdev = hv_get_drvdata(device_obj);
+	struct netvsc_device *nvdev = net_device_ctx->nvdev;
 	int ret;
 	u32 aread, awrite, i, msec = 10, retry = 0, retry_max = 20;
 	struct vmbus_channel *chn;
@@ -129,7 +138,7 @@
 
 	/* Make sure netvsc_set_multicast_list doesn't re-enable filter! */
 	cancel_work_sync(&net_device_ctx->work);
-	ret = rndis_filter_close(device_obj);
+	ret = rndis_filter_close(nvdev);
 	if (ret != 0) {
 		netdev_err(net, "unable to close device (ret %d).\n", ret);
 		return ret;
@@ -195,94 +204,55 @@
 	return ppi;
 }
 
-union sub_key {
-	u64 k;
-	struct {
-		u8 pad[3];
-		u8 kb;
-		u32 ka;
-	};
-};
-
-/* Toeplitz hash function
- * data: network byte order
- * return: host byte order
+/* Azure hosts don't support non-TCP port numbers in hashing yet. We compute
+ * hash for non-TCP traffic with only IP numbers.
  */
-static u32 comp_hash(u8 *key, int klen, void *data, int dlen)
-{
-	union sub_key subk;
-	int k_next = 4;
-	u8 dt;
-	int i, j;
-	u32 ret = 0;
-
-	subk.k = 0;
-	subk.ka = ntohl(*(u32 *)key);
-
-	for (i = 0; i < dlen; i++) {
-		subk.kb = key[k_next];
-		k_next = (k_next + 1) % klen;
-		dt = ((u8 *)data)[i];
-		for (j = 0; j < 8; j++) {
-			if (dt & 0x80)
-				ret ^= subk.ka;
-			dt <<= 1;
-			subk.k <<= 1;
-		}
-	}
-
-	return ret;
-}
-
-static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb)
+static inline u32 netvsc_get_hash(struct sk_buff *skb, struct sock *sk)
 {
 	struct flow_keys flow;
-	int data_len;
+	u32 hash;
+	static u32 hashrnd __read_mostly;
 
-	if (!skb_flow_dissect_flow_keys(skb, &flow, 0) ||
-	    !(flow.basic.n_proto == htons(ETH_P_IP) ||
-	      flow.basic.n_proto == htons(ETH_P_IPV6)))
-		return false;
+	net_get_random_once(&hashrnd, sizeof(hashrnd));
 
-	if (flow.basic.ip_proto == IPPROTO_TCP)
-		data_len = 12;
-	else
-		data_len = 8;
+	if (!skb_flow_dissect_flow_keys(skb, &flow, 0))
+		return 0;
 
-	*hash = comp_hash(netvsc_hash_key, HASH_KEYLEN, &flow, data_len);
+	if (flow.basic.ip_proto == IPPROTO_TCP) {
+		return skb_get_hash(skb);
+	} else {
+		if (flow.basic.n_proto == htons(ETH_P_IP))
+			hash = jhash2((u32 *)&flow.addrs.v4addrs, 2, hashrnd);
+		else if (flow.basic.n_proto == htons(ETH_P_IPV6))
+			hash = jhash2((u32 *)&flow.addrs.v6addrs, 8, hashrnd);
+		else
+			hash = 0;
 
-	return true;
+		skb_set_hash(skb, hash, PKT_HASH_TYPE_L3);
+	}
+
+	return hash;
 }
 
 static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
 			void *accel_priv, select_queue_fallback_t fallback)
 {
 	struct net_device_context *net_device_ctx = netdev_priv(ndev);
-	struct hv_device *hdev =  net_device_ctx->device_ctx;
-	struct netvsc_device *nvsc_dev = hv_get_drvdata(hdev);
+	struct netvsc_device *nvsc_dev = net_device_ctx->nvdev;
 	u32 hash;
 	u16 q_idx = 0;
 
 	if (nvsc_dev == NULL || ndev->real_num_tx_queues <= 1)
 		return 0;
 
-	if (netvsc_set_hash(&hash, skb)) {
-		q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] %
-			ndev->real_num_tx_queues;
-		skb_set_hash(skb, hash, PKT_HASH_TYPE_L3);
-	}
+	hash = netvsc_get_hash(skb, skb->sk);
+	q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] %
+		ndev->real_num_tx_queues;
 
-	return q_idx;
-}
-
-void netvsc_xmit_completion(void *context)
-{
-	struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
-	struct sk_buff *skb = (struct sk_buff *)
-		(unsigned long)packet->send_completion_tid;
+	if (!nvsc_dev->chn_table[q_idx])
+		q_idx = 0;
 
-	if (skb)
-		dev_kfree_skb_any(skb);
+	return q_idx;
 }
 
 static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
@@ -320,9 +290,10 @@
 }
 
 static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
-			   struct hv_netvsc_packet *packet)
+			   struct hv_netvsc_packet *packet,
+			   struct hv_page_buffer **page_buf)
 {
-	struct hv_page_buffer *pb = packet->page_buf;
+	struct hv_page_buffer *pb = *page_buf;
 	u32 slots_used = 0;
 	char *data = skb->data;
 	int frags = skb_shinfo(skb)->nr_frags;
@@ -423,18 +394,14 @@
 	struct rndis_message *rndis_msg;
 	struct rndis_packet *rndis_pkt;
 	u32 rndis_msg_size;
-	bool isvlan;
-	bool linear = false;
 	struct rndis_per_packet_info *ppi;
 	struct ndis_tcp_ip_checksum_info *csum_info;
-	struct ndis_tcp_lso_info *lso_info;
 	int  hdr_offset;
 	u32 net_trans_info;
 	u32 hash;
 	u32 skb_length;
-	u32 pkt_sz;
 	struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
-	struct netvsc_stats *tx_stats = this_cpu_ptr(net_device_ctx->tx_stats);
+	struct hv_page_buffer *pb = page_buf;
 
 	/* We will atmost need two pages to describe the rndis
 	 * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
@@ -442,60 +409,45 @@
 	 * more pages we try linearizing it.
 	 */
 
-check_size:
 	skb_length = skb->len;
 	num_data_pgs = netvsc_get_slots(skb) + 2;
-	if (num_data_pgs > MAX_PAGE_BUFFER_COUNT && linear) {
-		net_alert_ratelimited("packet too big: %u pages (%u bytes)\n",
-				      num_data_pgs, skb->len);
-		ret = -EFAULT;
-		goto drop;
-	} else if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
-		if (skb_linearize(skb)) {
-			net_alert_ratelimited("failed to linearize skb\n");
-			ret = -ENOMEM;
-			goto drop;
-		}
-		linear = true;
-		goto check_size;
-	}
 
-	pkt_sz = sizeof(struct hv_netvsc_packet) + RNDIS_AND_PPI_SIZE;
+	if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
+		++net_device_ctx->eth_stats.tx_scattered;
 
-	ret = skb_cow_head(skb, pkt_sz);
-	if (ret) {
-		netdev_err(net, "unable to alloc hv_netvsc_packet\n");
-		ret = -ENOMEM;
-		goto drop;
+		if (skb_linearize(skb))
+			goto no_memory;
+
+		num_data_pgs = netvsc_get_slots(skb) + 2;
+		if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
+			++net_device_ctx->eth_stats.tx_too_big;
+			goto drop;
+		}
 	}
-	/* Use the headroom for building up the packet */
-	packet = (struct hv_netvsc_packet *)skb->head;
 
-	packet->status = 0;
-	packet->xmit_more = skb->xmit_more;
+	/*
+	 * Place the rndis header in the skb head room and
+	 * the skb->cb will be used for hv_netvsc_packet
+	 * structure.
+	 */
+	ret = skb_cow_head(skb, RNDIS_AND_PPI_SIZE);
+	if (ret)
+		goto no_memory;
 
-	packet->vlan_tci = skb->vlan_tci;
-	packet->page_buf = page_buf;
+	/* Use the skb control buffer for building up the packet */
+	BUILD_BUG_ON(sizeof(struct hv_netvsc_packet) >
+			FIELD_SIZEOF(struct sk_buff, cb));
+	packet = (struct hv_netvsc_packet *)skb->cb;
 
 	packet->q_idx = skb_get_queue_mapping(skb);
 
-	packet->is_data_pkt = true;
 	packet->total_data_buflen = skb->len;
 
-	packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
-				sizeof(struct hv_netvsc_packet));
-
-	memset(packet->rndis_msg, 0, RNDIS_AND_PPI_SIZE);
+	rndis_msg = (struct rndis_message *)skb->head;
 
-	/* Set the completion routine */
-	packet->send_completion = netvsc_xmit_completion;
-	packet->send_completion_ctx = packet;
-	packet->send_completion_tid = (unsigned long)skb;
-
-	isvlan = packet->vlan_tci & VLAN_TAG_PRESENT;
+	memset(rndis_msg, 0, RNDIS_AND_PPI_SIZE);
 
 	/* Add the rndis header */
-	rndis_msg = packet->rndis_msg;
 	rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
 	rndis_msg->msg_len = packet->total_data_buflen;
 	rndis_pkt = &rndis_msg->msg.pkt;
@@ -513,7 +465,7 @@
 		*(u32 *)((void *)ppi + ppi->ppi_offset) = hash;
 	}
 
-	if (isvlan) {
+	if (skb_vlan_tag_present(skb)) {
 		struct ndis_pkt_8021q_info *vlan;
 
 		rndis_msg_size += NDIS_VLAN_PPI_SIZE;
@@ -521,120 +473,106 @@
 					IEEE_8021Q_INFO);
 		vlan = (struct ndis_pkt_8021q_info *)((void *)ppi +
 						ppi->ppi_offset);
-		vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK;
-		vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >>
+		vlan->vlanid = skb->vlan_tci & VLAN_VID_MASK;
+		vlan->pri = (skb->vlan_tci & VLAN_PRIO_MASK) >>
 				VLAN_PRIO_SHIFT;
 	}
 
 	net_trans_info = get_net_transport_info(skb, &hdr_offset);
-	if (net_trans_info == TRANSPORT_INFO_NOT_IP)
-		goto do_send;
 
 	/*
 	 * Setup the sendside checksum offload only if this is not a
 	 * GSO packet.
 	 */
-	if (skb_is_gso(skb))
-		goto do_lso;
-
-	if ((skb->ip_summed == CHECKSUM_NONE) ||
-	    (skb->ip_summed == CHECKSUM_UNNECESSARY))
-		goto do_send;
-
-	rndis_msg_size += NDIS_CSUM_PPI_SIZE;
-	ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
-			    TCPIP_CHKSUM_PKTINFO);
-
-	csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
-			ppi->ppi_offset);
-
-	if (net_trans_info & (INFO_IPV4 << 16))
-		csum_info->transmit.is_ipv4 = 1;
-	else
-		csum_info->transmit.is_ipv6 = 1;
-
-	if (net_trans_info & INFO_TCP) {
-		csum_info->transmit.tcp_checksum = 1;
-		csum_info->transmit.tcp_header_offset = hdr_offset;
-	} else if (net_trans_info & INFO_UDP) {
-		/* UDP checksum offload is not supported on ws2008r2.
-		 * Furthermore, on ws2012 and ws2012r2, there are some
-		 * issues with udp checksum offload from Linux guests.
-		 * (these are host issues).
-		 * For now compute the checksum here.
-		 */
-		struct udphdr *uh;
-		u16 udp_len;
+	if ((net_trans_info & (INFO_TCP | INFO_UDP)) && skb_is_gso(skb)) {
+		struct ndis_tcp_lso_info *lso_info;
 
-		ret = skb_cow_head(skb, 0);
-		if (ret)
-			goto drop;
-
-		uh = udp_hdr(skb);
-		udp_len = ntohs(uh->len);
-		uh->check = 0;
-		uh->check = csum_tcpudp_magic(ip_hdr(skb)->saddr,
-					      ip_hdr(skb)->daddr,
-					      udp_len, IPPROTO_UDP,
-					      csum_partial(uh, udp_len, 0));
-		if (uh->check == 0)
-			uh->check = CSUM_MANGLED_0;
-
-		csum_info->transmit.udp_checksum = 0;
-	}
-	goto do_send;
-
-do_lso:
-	rndis_msg_size += NDIS_LSO_PPI_SIZE;
-	ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
-			    TCP_LARGESEND_PKTINFO);
-
-	lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
-			ppi->ppi_offset);
-
-	lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
-	if (net_trans_info & (INFO_IPV4 << 16)) {
-		lso_info->lso_v2_transmit.ip_version =
-			NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
-		ip_hdr(skb)->tot_len = 0;
-		ip_hdr(skb)->check = 0;
-		tcp_hdr(skb)->check =
-		~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-				   ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
-	} else {
-		lso_info->lso_v2_transmit.ip_version =
-			NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
-		ipv6_hdr(skb)->payload_len = 0;
-		tcp_hdr(skb)->check =
-		~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-				&ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
+		rndis_msg_size += NDIS_LSO_PPI_SIZE;
+		ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
+				    TCP_LARGESEND_PKTINFO);
+
+		lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
+							ppi->ppi_offset);
+
+		lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
+		if (net_trans_info & (INFO_IPV4 << 16)) {
+			lso_info->lso_v2_transmit.ip_version =
+				NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
+			ip_hdr(skb)->tot_len = 0;
+			ip_hdr(skb)->check = 0;
+			tcp_hdr(skb)->check =
+				~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+						   ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
+		} else {
+			lso_info->lso_v2_transmit.ip_version =
+				NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
+			ipv6_hdr(skb)->payload_len = 0;
+			tcp_hdr(skb)->check =
+				~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+						 &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
+		}
+		lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
+		lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
+	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		if (net_trans_info & INFO_TCP) {
+			rndis_msg_size += NDIS_CSUM_PPI_SIZE;
+			ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
+					    TCPIP_CHKSUM_PKTINFO);
+
+			csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
+									 ppi->ppi_offset);
+
+			if (net_trans_info & (INFO_IPV4 << 16))
+				csum_info->transmit.is_ipv4 = 1;
+			else
+				csum_info->transmit.is_ipv6 = 1;
+
+			csum_info->transmit.tcp_checksum = 1;
+			csum_info->transmit.tcp_header_offset = hdr_offset;
+		} else {
+			/* UDP checksum (and other) offload is not supported. */
+			if (skb_checksum_help(skb))
+				goto drop;
+		}
 	}
-	lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
-	lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
 
-do_send:
 	/* Start filling in the page buffers with the rndis hdr */
 	rndis_msg->msg_len += rndis_msg_size;
 	packet->total_data_buflen = rndis_msg->msg_len;
 	packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
-					       skb, packet);
+					       skb, packet, &pb);
 
-	ret = netvsc_send(net_device_ctx->device_ctx, packet);
+	/* timestamp packet in software */
+	skb_tx_timestamp(skb);
+	ret = netvsc_send(net_device_ctx->device_ctx, packet,
+			  rndis_msg, &pb, skb);
+	if (likely(ret == 0)) {
+		struct netvsc_stats *tx_stats = this_cpu_ptr(net_device_ctx->tx_stats);
 
-drop:
-	if (ret == 0) {
 		u64_stats_update_begin(&tx_stats->syncp);
 		tx_stats->packets++;
 		tx_stats->bytes += skb_length;
 		u64_stats_update_end(&tx_stats->syncp);
-	} else {
-		if (ret != -EAGAIN) {
-			dev_kfree_skb_any(skb);
-			net->stats.tx_dropped++;
-		}
+		return NETDEV_TX_OK;
 	}
 
-	return (ret == -EAGAIN) ? NETDEV_TX_BUSY : NETDEV_TX_OK;
+	if (ret == -EAGAIN) {
+		++net_device_ctx->eth_stats.tx_busy;
+		return NETDEV_TX_BUSY;
+	}
+
+	if (ret == -ENOSPC)
+		++net_device_ctx->eth_stats.tx_no_space;
+
+drop:
+	dev_kfree_skb_any(skb);
+	net->stats.tx_dropped++;
+
+	return NETDEV_TX_OK;
+
+no_memory:
+	++net_device_ctx->eth_stats.tx_no_memory;
+	goto drop;
 }
 
 /*
@@ -646,38 +584,85 @@
 	struct rndis_indicate_status *indicate = &resp->msg.indicate_status;
 	struct net_device *net;
 	struct net_device_context *ndev_ctx;
-	struct netvsc_device *net_device;
-	struct rndis_device *rdev;
+	struct netvsc_reconfig *event;
+	unsigned long flags;
 
-	net_device = hv_get_drvdata(device_obj);
-	rdev = net_device->extension;
+	net = hv_get_drvdata(device_obj);
 
-	switch (indicate->status) {
-	case RNDIS_STATUS_MEDIA_CONNECT:
-		rdev->link_state = false;
-		break;
-	case RNDIS_STATUS_MEDIA_DISCONNECT:
-		rdev->link_state = true;
-		break;
-	case RNDIS_STATUS_NETWORK_CHANGE:
-		rdev->link_change = true;
-		break;
-	default:
+	if (!net)
+		return;
+
+	ndev_ctx = netdev_priv(net);
+
+	/* Update the physical link speed when changing to another vSwitch */
+	if (indicate->status == RNDIS_STATUS_LINK_SPEED_CHANGE) {
+		u32 speed;
+
+		speed = *(u32 *)((void *)indicate + indicate->
+				 status_buf_offset) / 10000;
+		ndev_ctx->speed = speed;
 		return;
 	}
 
-	net = net_device->ndev;
+	/* Handle these link change statuses below */
+	if (indicate->status != RNDIS_STATUS_NETWORK_CHANGE &&
+	    indicate->status != RNDIS_STATUS_MEDIA_CONNECT &&
+	    indicate->status != RNDIS_STATUS_MEDIA_DISCONNECT)
+		return;
 
-	if (!net || net->reg_state != NETREG_REGISTERED)
+	if (net->reg_state != NETREG_REGISTERED)
 		return;
 
-	ndev_ctx = netdev_priv(net);
-	if (!rdev->link_state) {
-		schedule_delayed_work(&ndev_ctx->dwork, 0);
-		schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
-	} else {
-		schedule_delayed_work(&ndev_ctx->dwork, 0);
+	event = kzalloc(sizeof(*event), GFP_ATOMIC);
+	if (!event)
+		return;
+	event->event = indicate->status;
+
+	spin_lock_irqsave(&ndev_ctx->lock, flags);
+	list_add_tail(&event->list, &ndev_ctx->reconfig_events);
+	spin_unlock_irqrestore(&ndev_ctx->lock, flags);
+
+	schedule_delayed_work(&ndev_ctx->dwork, 0);
+}
+
+static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
+				struct hv_netvsc_packet *packet,
+				struct ndis_tcp_ip_checksum_info *csum_info,
+				void *data, u16 vlan_tci)
+{
+	struct sk_buff *skb;
+
+	skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen);
+	if (!skb)
+		return skb;
+
+	/*
+	 * Copy to skb. This copy is needed here since the memory pointed by
+	 * hv_netvsc_packet cannot be deallocated
+	 */
+	memcpy(skb_put(skb, packet->total_data_buflen), data,
+	       packet->total_data_buflen);
+
+	skb->protocol = eth_type_trans(skb, net);
+
+	/* skb is already created with CHECKSUM_NONE */
+	skb_checksum_none_assert(skb);
+
+	/*
+	 * In Linux, the IP checksum is always checked.
+	 * Do L4 checksum offload if enabled and present.
+	 */
+	if (csum_info && (net->features & NETIF_F_RXCSUM)) {
+		if (csum_info->receive.tcp_checksum_succeeded ||
+		    csum_info->receive.udp_checksum_succeeded)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
+
+	if (vlan_tci & VLAN_TAG_PRESENT)
+		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+				       vlan_tci);
+
+	return skb;
 }
 
 /*
@@ -686,58 +671,58 @@
  */
 int netvsc_recv_callback(struct hv_device *device_obj,
 				struct hv_netvsc_packet *packet,
-				struct ndis_tcp_ip_checksum_info *csum_info)
+				void **data,
+				struct ndis_tcp_ip_checksum_info *csum_info,
+				struct vmbus_channel *channel,
+				u16 vlan_tci)
 {
-	struct net_device *net;
-	struct net_device_context *net_device_ctx;
+	struct net_device *net = hv_get_drvdata(device_obj);
+	struct net_device_context *net_device_ctx = netdev_priv(net);
+	struct net_device *vf_netdev;
 	struct sk_buff *skb;
 	struct netvsc_stats *rx_stats;
 
-	net = ((struct netvsc_device *)hv_get_drvdata(device_obj))->ndev;
-	if (!net || net->reg_state != NETREG_REGISTERED) {
-		packet->status = NVSP_STAT_FAIL;
-		return 0;
-	}
-	net_device_ctx = netdev_priv(net);
-	rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
+	if (net->reg_state != NETREG_REGISTERED)
+		return NVSP_STAT_FAIL;
+
+	/*
+	 * If necessary, inject this packet into the VF interface.
+	 * On Hyper-V, multicast and brodcast packets are only delivered
+	 * to the synthetic interface (after subjecting these to
+	 * policy filters on the host). Deliver these via the VF
+	 * interface in the guest.
+	 */
+	rcu_read_lock();
+	vf_netdev = rcu_dereference(net_device_ctx->vf_netdev);
+	if (vf_netdev && (vf_netdev->flags & IFF_UP))
+		net = vf_netdev;
 
 	/* Allocate a skb - TODO direct I/O to pages? */
-	skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen);
+	skb = netvsc_alloc_recv_skb(net, packet, csum_info, *data, vlan_tci);
 	if (unlikely(!skb)) {
 		++net->stats.rx_dropped;
-		packet->status = NVSP_STAT_FAIL;
-		return 0;
+		rcu_read_unlock();
+		return NVSP_STAT_FAIL;
 	}
 
+	if (net != vf_netdev)
+		skb_record_rx_queue(skb,
+				    channel->offermsg.offer.sub_channel_index);
+
 	/*
-	 * Copy to skb. This copy is needed here since the memory pointed by
-	 * hv_netvsc_packet cannot be deallocated
+	 * Even if injecting the packet, record the statistics
+	 * on the synthetic device because modifying the VF device
+	 * statistics will not work correctly.
 	 */
-	memcpy(skb_put(skb, packet->total_data_buflen), packet->data,
-		packet->total_data_buflen);
-
-	skb->protocol = eth_type_trans(skb, net);
-	if (csum_info) {
-		/* We only look at the IP checksum here.
-		 * Should we be dropping the packet if checksum
-		 * failed? How do we deal with other checksums - TCP/UDP?
-		 */
-		if (csum_info->receive.ip_checksum_succeeded)
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
-		else
-			skb->ip_summed = CHECKSUM_NONE;
-	}
-
-	if (packet->vlan_tci & VLAN_TAG_PRESENT)
-		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
-				       packet->vlan_tci);
-
-	skb_record_rx_queue(skb, packet->channel->
-			    offermsg.offer.sub_channel_index);
-
+	rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
 	u64_stats_update_begin(&rx_stats->syncp);
 	rx_stats->packets++;
 	rx_stats->bytes += packet->total_data_buflen;
+
+	if (skb->pkt_type == PACKET_BROADCAST)
+		++rx_stats->broadcast;
+	else if (skb->pkt_type == PACKET_MULTICAST)
+		++rx_stats->multicast;
 	u64_stats_update_end(&rx_stats->syncp);
 
 	/*
@@ -746,6 +731,7 @@
 	 * TODO - use NAPI?
 	 */
 	netif_rx(skb);
+	rcu_read_unlock();
 
 	return 0;
 }
@@ -761,8 +747,7 @@
 				struct ethtool_channels *channel)
 {
 	struct net_device_context *net_device_ctx = netdev_priv(net);
-	struct hv_device *dev = net_device_ctx->device_ctx;
-	struct netvsc_device *nvdev = hv_get_drvdata(dev);
+	struct netvsc_device *nvdev = net_device_ctx->nvdev;
 
 	if (nvdev) {
 		channel->max_combined	= nvdev->max_chn;
@@ -775,14 +760,14 @@
 {
 	struct net_device_context *net_device_ctx = netdev_priv(net);
 	struct hv_device *dev = net_device_ctx->device_ctx;
-	struct netvsc_device *nvdev = hv_get_drvdata(dev);
+	struct netvsc_device *nvdev = net_device_ctx->nvdev;
 	struct netvsc_device_info device_info;
 	u32 num_chn;
 	u32 max_chn;
 	int ret = 0;
 	bool recovering = false;
 
-	if (!nvdev || nvdev->destroy)
+	if (net_device_ctx->start_remove || !nvdev || nvdev->destroy)
 		return -ENODEV;
 
 	num_chn = nvdev->num_chn;
@@ -811,14 +796,11 @@
 		goto out;
 
  do_set:
-	nvdev->start_remove = true;
+	net_device_ctx->start_remove = true;
 	rndis_filter_device_remove(dev);
 
 	nvdev->num_chn = channels->combined_count;
 
-	net_device_ctx->device_ctx = dev;
-	hv_set_drvdata(dev, net);
-
 	memset(&device_info, 0, sizeof(device_info));
 	device_info.num_chn = nvdev->num_chn; /* passed to RNDIS */
 	device_info.ring_size = ring_size;
@@ -833,7 +815,7 @@
 		goto recover;
 	}
 
-	nvdev = hv_get_drvdata(dev);
+	nvdev = net_device_ctx->nvdev;
 
 	ret = netif_set_real_num_tx_queues(net, nvdev->num_chn);
 	if (ret) {
@@ -855,6 +837,9 @@
 
  out:
 	netvsc_open(net);
+	net_device_ctx->start_remove = false;
+	/* We may have missed link change notifications */
+	schedule_delayed_work(&net_device_ctx->dwork, 0);
 
 	return ret;
 
@@ -868,16 +853,69 @@
 	goto do_set;
 }
 
+static bool netvsc_validate_ethtool_ss_cmd(const struct ethtool_cmd *cmd)
+{
+	struct ethtool_cmd diff1 = *cmd;
+	struct ethtool_cmd diff2 = {};
+
+	ethtool_cmd_speed_set(&diff1, 0);
+	diff1.duplex = 0;
+	/* advertising and cmd are usually set */
+	diff1.advertising = 0;
+	diff1.cmd = 0;
+	/* We set port to PORT_OTHER */
+	diff2.port = PORT_OTHER;
+
+	return !memcmp(&diff1, &diff2, sizeof(diff1));
+}
+
+static void netvsc_init_settings(struct net_device *dev)
+{
+	struct net_device_context *ndc = netdev_priv(dev);
+
+	ndc->speed = SPEED_UNKNOWN;
+	ndc->duplex = DUPLEX_UNKNOWN;
+}
+
+static int netvsc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct net_device_context *ndc = netdev_priv(dev);
+
+	ethtool_cmd_speed_set(cmd, ndc->speed);
+	cmd->duplex = ndc->duplex;
+	cmd->port = PORT_OTHER;
+
+	return 0;
+}
+
+static int netvsc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct net_device_context *ndc = netdev_priv(dev);
+	u32 speed;
+
+	speed = ethtool_cmd_speed(cmd);
+	if (!ethtool_validate_speed(speed) ||
+	    !ethtool_validate_duplex(cmd->duplex) ||
+	    !netvsc_validate_ethtool_ss_cmd(cmd))
+		return -EINVAL;
+
+	ndc->speed = speed;
+	ndc->duplex = cmd->duplex;
+
+	return 0;
+}
+
 static int netvsc_change_mtu(struct net_device *ndev, int mtu)
 {
 	struct net_device_context *ndevctx = netdev_priv(ndev);
-	struct hv_device *hdev =  ndevctx->device_ctx;
-	struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+	struct netvsc_device *nvdev = ndevctx->nvdev;
+	struct hv_device *hdev = ndevctx->device_ctx;
 	struct netvsc_device_info device_info;
 	int limit = ETH_DATA_LEN;
+	u32 num_chn;
 	int ret = 0;
 
-	if (nvdev == NULL || nvdev->destroy)
+	if (ndevctx->start_remove || !nvdev || nvdev->destroy)
 		return -ENODEV;
 
 	if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
@@ -890,22 +928,25 @@
 	if (ret)
 		goto out;
 
-	nvdev->start_remove = true;
+	num_chn = nvdev->num_chn;
+
+	ndevctx->start_remove = true;
 	rndis_filter_device_remove(hdev);
 
 	ndev->mtu = mtu;
 
-	ndevctx->device_ctx = hdev;
-	hv_set_drvdata(hdev, ndev);
-
 	memset(&device_info, 0, sizeof(device_info));
 	device_info.ring_size = ring_size;
-	device_info.num_chn = nvdev->num_chn;
+	device_info.num_chn = num_chn;
 	device_info.max_num_vrss_chns = max_num_vrss_chns;
 	rndis_filter_device_add(hdev, &device_info);
 
 out:
 	netvsc_open(ndev);
+	ndevctx->start_remove = false;
+
+	/* We may have missed link change notifications */
+	schedule_delayed_work(&ndevctx->dwork, 0);
 
 	return ret;
 }
@@ -921,7 +962,7 @@
 							    cpu);
 		struct netvsc_stats *rx_stats = per_cpu_ptr(ndev_ctx->rx_stats,
 							    cpu);
-		u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
+		u64 tx_packets, tx_bytes, rx_packets, rx_bytes, rx_multicast;
 		unsigned int start;
 
 		do {
@@ -934,12 +975,14 @@
 			start = u64_stats_fetch_begin_irq(&rx_stats->syncp);
 			rx_packets = rx_stats->packets;
 			rx_bytes = rx_stats->bytes;
+			rx_multicast = rx_stats->multicast + rx_stats->broadcast;
 		} while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start));
 
 		t->tx_bytes	+= tx_bytes;
 		t->tx_packets	+= tx_packets;
 		t->rx_bytes	+= rx_bytes;
 		t->rx_packets	+= rx_packets;
+		t->multicast	+= rx_multicast;
 	}
 
 	t->tx_dropped	= net->stats.tx_dropped;
@@ -953,8 +996,6 @@
 
 static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
 {
-	struct net_device_context *ndevctx = netdev_priv(ndev);
-	struct hv_device *hdev =  ndevctx->device_ctx;
 	struct sockaddr *addr = p;
 	char save_adr[ETH_ALEN];
 	unsigned char save_aatype;
@@ -967,7 +1008,7 @@
 	if (err != 0)
 		return err;
 
-	err = rndis_filter_set_device_mac(hdev, addr->sa_data);
+	err = rndis_filter_set_device_mac(ndev, addr->sa_data);
 	if (err != 0) {
 		/* roll back to saved MAC */
 		memcpy(ndev->dev_addr, save_adr, ETH_ALEN);
@@ -977,6 +1018,51 @@
 	return err;
 }
 
+static const struct {
+	char name[ETH_GSTRING_LEN];
+	u16 offset;
+} netvsc_stats[] = {
+	{ "tx_scattered", offsetof(struct netvsc_ethtool_stats, tx_scattered) },
+	{ "tx_no_memory",  offsetof(struct netvsc_ethtool_stats, tx_no_memory) },
+	{ "tx_no_space",  offsetof(struct netvsc_ethtool_stats, tx_no_space) },
+	{ "tx_too_big",	  offsetof(struct netvsc_ethtool_stats, tx_too_big) },
+	{ "tx_busy",	  offsetof(struct netvsc_ethtool_stats, tx_busy) },
+};
+
+static int netvsc_get_sset_count(struct net_device *dev, int string_set)
+{
+	switch (string_set) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(netvsc_stats);
+	default:
+		return -EINVAL;
+	}
+}
+
+static void netvsc_get_ethtool_stats(struct net_device *dev,
+				     struct ethtool_stats *stats, u64 *data)
+{
+	struct net_device_context *ndc = netdev_priv(dev);
+	const void *nds = &ndc->eth_stats;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(netvsc_stats); i++)
+		data[i] = *(unsigned long *)(nds + netvsc_stats[i].offset);
+}
+
+static void netvsc_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < ARRAY_SIZE(netvsc_stats); i++)
+			memcpy(data + i * ETH_GSTRING_LEN,
+			       netvsc_stats[i].name, ETH_GSTRING_LEN);
+		break;
+	}
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void netvsc_poll_controller(struct net_device *net)
 {
@@ -989,8 +1075,14 @@
 static const struct ethtool_ops ethtool_ops = {
 	.get_drvinfo	= netvsc_get_drvinfo,
 	.get_link	= ethtool_op_get_link,
+	.get_ethtool_stats = netvsc_get_ethtool_stats,
+	.get_sset_count = netvsc_get_sset_count,
+	.get_strings	= netvsc_get_strings,
 	.get_channels   = netvsc_get_channels,
 	.set_channels   = netvsc_set_channels,
+	.get_ts_info	= ethtool_op_get_ts_info,
+	.get_settings	= netvsc_get_settings,
+	.set_settings	= netvsc_set_settings,
 };
 
 static const struct net_device_ops device_ops = {
@@ -1009,49 +1101,106 @@
 };
 
 /*
- * Send GARP packet to network peers after migrations.
- * After Quick Migration, the network is not immediately operational in the
- * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
- * another netif_notify_peers() into a delayed work, otherwise GARP packet
- * will not be sent after quick migration, and cause network disconnection.
- * Also, we update the carrier status here.
+ * Handle link status changes. For RNDIS_STATUS_NETWORK_CHANGE emulate link
+ * down/up sequence. In case of RNDIS_STATUS_MEDIA_CONNECT when carrier is
+ * present send GARP packet to network peers with netif_notify_peers().
  */
 static void netvsc_link_change(struct work_struct *w)
 {
-	struct net_device_context *ndev_ctx;
-	struct net_device *net;
+	struct net_device_context *ndev_ctx =
+		container_of(w, struct net_device_context, dwork.work);
+	struct hv_device *device_obj = ndev_ctx->device_ctx;
+	struct net_device *net = hv_get_drvdata(device_obj);
 	struct netvsc_device *net_device;
 	struct rndis_device *rdev;
-	bool notify, refresh = false;
-	char *argv[] = { "/etc/init.d/network", "restart", NULL };
-	char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+	struct netvsc_reconfig *event = NULL;
+	bool notify = false, reschedule = false;
+	unsigned long flags, next_reconfig, delay;
 
 	rtnl_lock();
+	if (ndev_ctx->start_remove)
+		goto out_unlock;
 
-	ndev_ctx = container_of(w, struct net_device_context, dwork.work);
-	net_device = hv_get_drvdata(ndev_ctx->device_ctx);
+	net_device = ndev_ctx->nvdev;
 	rdev = net_device->extension;
-	net = net_device->ndev;
 
-	if (rdev->link_state) {
-		netif_carrier_off(net);
-		notify = false;
-	} else {
-		netif_carrier_on(net);
-		notify = true;
-		if (rdev->link_change) {
-			rdev->link_change = false;
-			refresh = true;
+	next_reconfig = ndev_ctx->last_reconfig + LINKCHANGE_INT;
+	if (time_is_after_jiffies(next_reconfig)) {
+		/* link_watch only sends one notification with current state
+		 * per second, avoid doing reconfig more frequently. Handle
+		 * wrap around.
+		 */
+		delay = next_reconfig - jiffies;
+		delay = delay < LINKCHANGE_INT ? delay : LINKCHANGE_INT;
+		schedule_delayed_work(&ndev_ctx->dwork, delay);
+		goto out_unlock;
+	}
+	ndev_ctx->last_reconfig = jiffies;
+
+	spin_lock_irqsave(&ndev_ctx->lock, flags);
+	if (!list_empty(&ndev_ctx->reconfig_events)) {
+		event = list_first_entry(&ndev_ctx->reconfig_events,
+					 struct netvsc_reconfig, list);
+		list_del(&event->list);
+		reschedule = !list_empty(&ndev_ctx->reconfig_events);
+	}
+	spin_unlock_irqrestore(&ndev_ctx->lock, flags);
+
+	if (!event)
+		goto out_unlock;
+
+	switch (event->event) {
+		/* Only the following events are possible due to the check in
+		 * netvsc_linkstatus_callback()
+		 */
+	case RNDIS_STATUS_MEDIA_CONNECT:
+		if (rdev->link_state) {
+			rdev->link_state = false;
+			netif_carrier_on(net);
+			netif_tx_wake_all_queues(net);
+		} else {
+			notify = true;
 		}
+		kfree(event);
+		break;
+	case RNDIS_STATUS_MEDIA_DISCONNECT:
+		if (!rdev->link_state) {
+			rdev->link_state = true;
+			netif_carrier_off(net);
+			netif_tx_stop_all_queues(net);
+		}
+		kfree(event);
+		break;
+	case RNDIS_STATUS_NETWORK_CHANGE:
+		/* Only makes sense if carrier is present */
+		if (!rdev->link_state) {
+			rdev->link_state = true;
+			netif_carrier_off(net);
+			netif_tx_stop_all_queues(net);
+			event->event = RNDIS_STATUS_MEDIA_CONNECT;
+			spin_lock_irqsave(&ndev_ctx->lock, flags);
+			list_add(&event->list, &ndev_ctx->reconfig_events);
+			spin_unlock_irqrestore(&ndev_ctx->lock, flags);
+			reschedule = true;
+		}
+		break;
 	}
 
 	rtnl_unlock();
 
-	if (refresh)
-		call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
-
 	if (notify)
 		netdev_notify_peers(net);
+
+	/* link_watch only sends one notification with current state per
+	 * second, handle next reconfig event in 2 seconds.
+	 */
+	if (reschedule)
+		schedule_delayed_work(&ndev_ctx->dwork, LINKCHANGE_INT);
+
+	return;
+
+out_unlock:
+	rtnl_unlock();
 }
 
 static void netvsc_free_netdev(struct net_device *netdev)
@@ -1063,6 +1212,160 @@
 	free_netdev(netdev);
 }
 
+static struct net_device *get_netvsc_bymac(const u8 *mac)
+{
+	struct net_device *dev;
+
+	ASSERT_RTNL();
+
+	for_each_netdev(&init_net, dev) {
+		if (dev->netdev_ops != &device_ops)
+			continue;	/* not a netvsc device */
+
+		if (ether_addr_equal(mac, dev->perm_addr))
+			return dev;
+	}
+
+	return NULL;
+}
+
+static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
+{
+	struct net_device *dev;
+
+	ASSERT_RTNL();
+
+	for_each_netdev(&init_net, dev) {
+		struct net_device_context *net_device_ctx;
+
+		if (dev->netdev_ops != &device_ops)
+			continue;	/* not a netvsc device */
+
+		net_device_ctx = netdev_priv(dev);
+		if (net_device_ctx->nvdev == NULL)
+			continue;	/* device is removed */
+
+		if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev)
+			return dev;	/* a match */
+	}
+
+	return NULL;
+}
+
+static int netvsc_register_vf(struct net_device *vf_netdev)
+{
+	struct net_device *ndev;
+	struct net_device_context *net_device_ctx;
+	struct netvsc_device *netvsc_dev;
+
+	if (vf_netdev->addr_len != ETH_ALEN)
+		return NOTIFY_DONE;
+
+	/*
+	 * We will use the MAC address to locate the synthetic interface to
+	 * associate with the VF interface. If we don't find a matching
+	 * synthetic interface, move on.
+	 */
+	ndev = get_netvsc_bymac(vf_netdev->perm_addr);
+	if (!ndev)
+		return NOTIFY_DONE;
+
+	net_device_ctx = netdev_priv(ndev);
+	netvsc_dev = net_device_ctx->nvdev;
+	if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev))
+		return NOTIFY_DONE;
+
+	netdev_info(ndev, "VF registering: %s\n", vf_netdev->name);
+	/*
+	 * Take a reference on the module.
+	 */
+	try_module_get(THIS_MODULE);
+
+	dev_hold(vf_netdev);
+	rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
+	return NOTIFY_OK;
+}
+
+static int netvsc_vf_up(struct net_device *vf_netdev)
+{
+	struct net_device *ndev;
+	struct netvsc_device *netvsc_dev;
+	struct net_device_context *net_device_ctx;
+
+	ndev = get_netvsc_byref(vf_netdev);
+	if (!ndev)
+		return NOTIFY_DONE;
+
+	net_device_ctx = netdev_priv(ndev);
+	netvsc_dev = net_device_ctx->nvdev;
+
+	netdev_info(ndev, "VF up: %s\n", vf_netdev->name);
+
+	/*
+	 * Open the device before switching data path.
+	 */
+	rndis_filter_open(netvsc_dev);
+
+	/*
+	 * notify the host to switch the data path.
+	 */
+	netvsc_switch_datapath(ndev, true);
+	netdev_info(ndev, "Data path switched to VF: %s\n", vf_netdev->name);
+
+	netif_carrier_off(ndev);
+
+	/* Now notify peers through VF device. */
+	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, vf_netdev);
+
+	return NOTIFY_OK;
+}
+
+static int netvsc_vf_down(struct net_device *vf_netdev)
+{
+	struct net_device *ndev;
+	struct netvsc_device *netvsc_dev;
+	struct net_device_context *net_device_ctx;
+
+	ndev = get_netvsc_byref(vf_netdev);
+	if (!ndev)
+		return NOTIFY_DONE;
+
+	net_device_ctx = netdev_priv(ndev);
+	netvsc_dev = net_device_ctx->nvdev;
+
+	netdev_info(ndev, "VF down: %s\n", vf_netdev->name);
+	netvsc_switch_datapath(ndev, false);
+	netdev_info(ndev, "Data path switched from VF: %s\n", vf_netdev->name);
+	rndis_filter_close(netvsc_dev);
+	netif_carrier_on(ndev);
+
+	/* Now notify peers through netvsc device. */
+	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, ndev);
+
+	return NOTIFY_OK;
+}
+
+static int netvsc_unregister_vf(struct net_device *vf_netdev)
+{
+	struct net_device *ndev;
+	struct netvsc_device *netvsc_dev;
+	struct net_device_context *net_device_ctx;
+
+	ndev = get_netvsc_byref(vf_netdev);
+	if (!ndev)
+		return NOTIFY_DONE;
+
+	net_device_ctx = netdev_priv(ndev);
+	netvsc_dev = net_device_ctx->nvdev;
+
+	netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
+
+	RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
+	dev_put(vf_netdev);
+	module_put(THIS_MODULE);
+	return NOTIFY_OK;
+}
+
 static int netvsc_probe(struct hv_device *dev,
 			const struct hv_vmbus_device_id *dev_id)
 {
@@ -1071,18 +1374,16 @@
 	struct netvsc_device_info device_info;
 	struct netvsc_device *nvdev;
 	int ret;
-	u32 max_needed_headroom;
 
 	net = alloc_etherdev_mq(sizeof(struct net_device_context),
 				num_online_cpus());
 	if (!net)
 		return -ENOMEM;
 
-	max_needed_headroom = sizeof(struct hv_netvsc_packet) +
-			      RNDIS_AND_PPI_SIZE;
-
 	netif_carrier_off(net);
 
+	netvsc_init_settings(net);
+
 	net_device_ctx = netdev_priv(net);
 	net_device_ctx->device_ctx = dev;
 	net_device_ctx->msg_enable = netif_msg_init(debug, default_msg);
@@ -1103,25 +1404,25 @@
 	}
 
 	hv_set_drvdata(dev, net);
+
+	net_device_ctx->start_remove = false;
+
 	INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
 	INIT_WORK(&net_device_ctx->work, do_set_multicast);
 
+	spin_lock_init(&net_device_ctx->lock);
+	INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
+
 	net->netdev_ops = &device_ops;
 
-	net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM |
-				NETIF_F_TSO;
-	net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM |
-			NETIF_F_IP_CSUM | NETIF_F_TSO;
+	net->hw_features = NETVSC_HW_FEATURES;
+	net->features = NETVSC_HW_FEATURES | NETIF_F_HW_VLAN_CTAG_TX;
 
 	net->ethtool_ops = &ethtool_ops;
 	SET_NETDEV_DEV(net, &dev->device);
 
-	/*
-	 * Request additional head room in the skb.
-	 * We will use this space to build the rndis
-	 * heaser and other state we need to maintain.
-	 */
-	net->needed_headroom = max_needed_headroom;
+	/* We always need headroom for rndis header */
+	net->needed_headroom = RNDIS_AND_PPI_SIZE;
 
 	/* Notify the netvsc driver of the new device */
 	memset(&device_info, 0, sizeof(device_info));
@@ -1136,17 +1437,16 @@
 	}
 	memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
 
-	nvdev = hv_get_drvdata(dev);
+	nvdev = net_device_ctx->nvdev;
 	netif_set_real_num_tx_queues(net, nvdev->num_chn);
 	netif_set_real_num_rx_queues(net, nvdev->num_chn);
+	netif_set_gso_max_size(net, NETVSC_GSO_MAX_SIZE);
 
 	ret = register_netdev(net);
 	if (ret != 0) {
 		pr_err("Unable to register netdev.\n");
 		rndis_filter_device_remove(dev);
 		netvsc_free_netdev(net);
-	} else {
-		schedule_delayed_work(&net_device_ctx->dwork, 0);
 	}
 
 	return ret;
@@ -1158,17 +1458,23 @@
 	struct net_device_context *ndev_ctx;
 	struct netvsc_device *net_device;
 
-	net_device = hv_get_drvdata(dev);
-	net = net_device->ndev;
+	net = hv_get_drvdata(dev);
 
 	if (net == NULL) {
 		dev_err(&dev->device, "No net device to remove\n");
 		return 0;
 	}
 
-	net_device->start_remove = true;
-
 	ndev_ctx = netdev_priv(net);
+	net_device = ndev_ctx->nvdev;
+
+	/* Avoid racing with netvsc_change_mtu()/netvsc_set_channels()
+	 * removing the device.
+	 */
+	rtnl_lock();
+	ndev_ctx->start_remove = true;
+	rtnl_unlock();
+
 	cancel_delayed_work_sync(&ndev_ctx->dwork);
 	cancel_work_sync(&ndev_ctx->work);
 
@@ -1183,6 +1489,8 @@
 	 */
 	rndis_filter_device_remove(dev);
 
+	hv_set_drvdata(dev, NULL);
+
 	netvsc_free_netdev(net);
 	return 0;
 }
@@ -1203,19 +1511,74 @@
 	.remove = netvsc_remove,
 };
 
+/*
+ * On Hyper-V, every VF interface is matched with a corresponding
+ * synthetic interface. The synthetic interface is presented first
+ * to the guest. When the corresponding VF instance is registered,
+ * we will take care of switching the data path.
+ */
+static int netvsc_netdev_event(struct notifier_block *this,
+			       unsigned long event, void *ptr)
+{
+	struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
+
+	/* Skip our own events */
+	if (event_dev->netdev_ops == &device_ops)
+		return NOTIFY_DONE;
+
+	/* Avoid non-Ethernet type devices */
+	if (event_dev->type != ARPHRD_ETHER)
+		return NOTIFY_DONE;
+
+	/* Avoid Vlan dev with same MAC registering as VF */
+	if (event_dev->priv_flags & IFF_802_1Q_VLAN)
+		return NOTIFY_DONE;
+
+	/* Avoid Bonding master dev with same MAC registering as VF */
+	if ((event_dev->priv_flags & IFF_BONDING) &&
+	    (event_dev->flags & IFF_MASTER))
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_REGISTER:
+		return netvsc_register_vf(event_dev);
+	case NETDEV_UNREGISTER:
+		return netvsc_unregister_vf(event_dev);
+	case NETDEV_UP:
+		return netvsc_vf_up(event_dev);
+	case NETDEV_DOWN:
+		return netvsc_vf_down(event_dev);
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static struct notifier_block netvsc_netdev_notifier = {
+	.notifier_call = netvsc_netdev_event,
+};
+
 static void __exit netvsc_drv_exit(void)
 {
+	unregister_netdevice_notifier(&netvsc_netdev_notifier);
 	vmbus_driver_unregister(&netvsc_drv);
 }
 
 static int __init netvsc_drv_init(void)
 {
+	int ret;
+
 	if (ring_size < RING_SIZE_MIN) {
 		ring_size = RING_SIZE_MIN;
 		pr_info("Increased ring_size to %d (min allowed)\n",
 			ring_size);
 	}
-	return vmbus_driver_register(&netvsc_drv);
+	ret = vmbus_driver_register(&netvsc_drv);
+
+	if (ret)
+		return ret;
+
+	register_netdevice_notifier(&netvsc_netdev_notifier);
+	return 0;
 }
 
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/hyperv/rndis_filter.c
+++ linux-4.4.0/drivers/net/hyperv/rndis_filter.c
@@ -126,11 +126,7 @@
 static void dump_rndis_message(struct hv_device *hv_dev,
 			struct rndis_message *rndis_msg)
 {
-	struct net_device *netdev;
-	struct netvsc_device *net_device;
-
-	net_device = hv_get_drvdata(hv_dev);
-	netdev = net_device->ndev;
+	struct net_device *netdev = hv_get_drvdata(hv_dev);
 
 	switch (rndis_msg->ndis_msg_type) {
 	case RNDIS_MSG_PACKET:
@@ -210,37 +206,34 @@
 	int ret;
 	struct hv_netvsc_packet *packet;
 	struct hv_page_buffer page_buf[2];
+	struct hv_page_buffer *pb = page_buf;
+	struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
 
 	/* Setup the packet to send it */
 	packet = &req->pkt;
 
-	packet->is_data_pkt = false;
 	packet->total_data_buflen = req->request_msg.msg_len;
 	packet->page_buf_cnt = 1;
-	packet->page_buf = page_buf;
 
-	packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
+	pb[0].pfn = virt_to_phys(&req->request_msg) >>
 					PAGE_SHIFT;
-	packet->page_buf[0].len = req->request_msg.msg_len;
-	packet->page_buf[0].offset =
+	pb[0].len = req->request_msg.msg_len;
+	pb[0].offset =
 		(unsigned long)&req->request_msg & (PAGE_SIZE - 1);
 
 	/* Add one page_buf when request_msg crossing page boundary */
-	if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) {
+	if (pb[0].offset + pb[0].len > PAGE_SIZE) {
 		packet->page_buf_cnt++;
-		packet->page_buf[0].len = PAGE_SIZE -
-			packet->page_buf[0].offset;
-		packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg
-			+ packet->page_buf[0].len) >> PAGE_SHIFT;
-		packet->page_buf[1].offset = 0;
-		packet->page_buf[1].len = req->request_msg.msg_len -
-			packet->page_buf[0].len;
+		pb[0].len = PAGE_SIZE -
+			pb[0].offset;
+		pb[1].pfn = virt_to_phys((void *)&req->request_msg
+			+ pb[0].len) >> PAGE_SHIFT;
+		pb[1].offset = 0;
+		pb[1].len = req->request_msg.msg_len -
+			pb[0].len;
 	}
 
-	packet->send_completion = NULL;
-	packet->xmit_more = false;
-
-	ret = netvsc_send(dev->net_dev->dev, packet);
+	ret = netvsc_send(net_device_ctx->device_ctx, packet, NULL, &pb, NULL);
 	return ret;
 }
 
@@ -266,9 +259,7 @@
 	struct rndis_request *request = NULL;
 	bool found = false;
 	unsigned long flags;
-	struct net_device *ndev;
-
-	ndev = dev->net_dev->ndev;
+	struct net_device *ndev = dev->ndev;
 
 	spin_lock_irqsave(&dev->request_lock, flags);
 	list_for_each_entry(request, &dev->req_list, list_ent) {
@@ -348,14 +339,18 @@
 	return NULL;
 }
 
-static void rndis_filter_receive_data(struct rndis_device *dev,
+static int rndis_filter_receive_data(struct rndis_device *dev,
 				   struct rndis_message *msg,
-				   struct hv_netvsc_packet *pkt)
+				   struct hv_netvsc_packet *pkt,
+				   void **data,
+				   struct vmbus_channel *channel)
 {
 	struct rndis_packet *rndis_pkt;
 	u32 data_offset;
 	struct ndis_pkt_8021q_info *vlan;
 	struct ndis_tcp_ip_checksum_info *csum_info;
+	u16 vlan_tci = 0;
+	struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
 
 	rndis_pkt = &msg->msg.pkt;
 
@@ -369,11 +364,11 @@
 	 * should be the data packet size plus the trailer padding size
 	 */
 	if (pkt->total_data_buflen < rndis_pkt->data_len) {
-		netdev_err(dev->net_dev->ndev, "rndis message buffer "
+		netdev_err(dev->ndev, "rndis message buffer "
 			   "overflow detected (got %u, min %u)"
 			   "...dropping this message!\n",
 			   pkt->total_data_buflen, rndis_pkt->data_len);
-		return;
+		return NVSP_STAT_FAIL;
 	}
 
 	/*
@@ -382,41 +377,41 @@
 	 * the data packet to the stack, without the rndis trailer padding
 	 */
 	pkt->total_data_buflen = rndis_pkt->data_len;
-	pkt->data = (void *)((unsigned long)pkt->data + data_offset);
+	*data = (void *)((unsigned long)(*data) + data_offset);
 
 	vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
 	if (vlan) {
-		pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
+		vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
 			(vlan->pri << VLAN_PRIO_SHIFT);
-	} else {
-		pkt->vlan_tci = 0;
 	}
 
 	csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
-	netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info);
+	return netvsc_recv_callback(net_device_ctx->device_ctx, pkt, data,
+				    csum_info, channel, vlan_tci);
 }
 
 int rndis_filter_receive(struct hv_device *dev,
-				struct hv_netvsc_packet	*pkt)
-{
-	struct netvsc_device *net_dev = hv_get_drvdata(dev);
+				struct hv_netvsc_packet	*pkt,
+				void **data,
+				struct vmbus_channel *channel)
+{
+	struct net_device *ndev = hv_get_drvdata(dev);
+	struct net_device_context *net_device_ctx = netdev_priv(ndev);
+	struct netvsc_device *net_dev = net_device_ctx->nvdev;
 	struct rndis_device *rndis_dev;
 	struct rndis_message *rndis_msg;
-	struct net_device *ndev;
 	int ret = 0;
 
 	if (!net_dev) {
-		ret = -EINVAL;
+		ret = NVSP_STAT_FAIL;
 		goto exit;
 	}
 
-	ndev = net_dev->ndev;
-
 	/* Make sure the rndis device state is initialized */
 	if (!net_dev->extension) {
 		netdev_err(ndev, "got rndis message but no rndis device - "
 			  "dropping this message!\n");
-		ret = -ENODEV;
+		ret = NVSP_STAT_FAIL;
 		goto exit;
 	}
 
@@ -424,19 +419,20 @@
 	if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
 		netdev_err(ndev, "got rndis message but rndis device "
 			   "uninitialized...dropping this message!\n");
-		ret = -ENODEV;
+		ret = NVSP_STAT_FAIL;
 		goto exit;
 	}
 
-	rndis_msg = pkt->data;
+	rndis_msg = *data;
 
-	if (netif_msg_rx_err(net_dev->nd_ctx))
+	if (netif_msg_rx_err(net_device_ctx))
 		dump_rndis_message(dev, rndis_msg);
 
 	switch (rndis_msg->ndis_msg_type) {
 	case RNDIS_MSG_PACKET:
 		/* data msg */
-		rndis_filter_receive_data(rndis_dev, rndis_msg, pkt);
+		ret = rndis_filter_receive_data(rndis_dev, rndis_msg, pkt,
+						data, channel);
 		break;
 
 	case RNDIS_MSG_INIT_C:
@@ -459,9 +455,6 @@
 	}
 
 exit:
-	if (ret != 0)
-		pkt->status = NVSP_STAT_FAIL;
-
 	return ret;
 }
 
@@ -473,7 +466,6 @@
 	struct rndis_query_request *query;
 	struct rndis_query_complete *query_complete;
 	int ret = 0;
-	unsigned long t;
 
 	if (!result)
 		return -EINVAL;
@@ -510,11 +502,7 @@
 	if (ret != 0)
 		goto cleanup;
 
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
+	wait_for_completion(&request->wait_event);
 
 	/* Copy the response back */
 	query_complete = &request->response_msg.msg.query_complete;
@@ -550,11 +538,10 @@
 #define NWADR_STR "NetworkAddress"
 #define NWADR_STRLEN 14
 
-int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
+int rndis_filter_set_device_mac(struct net_device *ndev, char *mac)
 {
-	struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+	struct netvsc_device *nvdev = net_device_to_netvsc_device(ndev);
 	struct rndis_device *rdev = nvdev->extension;
-	struct net_device *ndev = nvdev->ndev;
 	struct rndis_request *request;
 	struct rndis_set_request *set;
 	struct rndis_config_parameter_info *cpi;
@@ -564,7 +551,6 @@
 	u32 extlen = sizeof(struct rndis_config_parameter_info) +
 		2*NWADR_STRLEN + 4*ETH_ALEN;
 	int ret;
-	unsigned long t;
 
 	request = get_rndis_request(rdev, RNDIS_MSG_SET,
 		RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
@@ -605,21 +591,13 @@
 	if (ret != 0)
 		goto cleanup;
 
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		netdev_err(ndev, "timeout before we got a set response...\n");
-		/*
-		 * can't put_rndis_request, since we may still receive a
-		 * send-completion.
-		 */
-		return -EBUSY;
-	} else {
-		set_complete = &request->response_msg.msg.set_complete;
-		if (set_complete->status != RNDIS_STATUS_SUCCESS) {
-			netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
-				   set_complete->status);
-			ret = -EINVAL;
-		}
+	wait_for_completion(&request->wait_event);
+
+	set_complete = &request->response_msg.msg.set_complete;
+	if (set_complete->status != RNDIS_STATUS_SUCCESS) {
+		netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
+			   set_complete->status);
+		ret = -EINVAL;
 	}
 
 cleanup:
@@ -628,19 +606,17 @@
 }
 
 static int
-rndis_filter_set_offload_params(struct hv_device *hdev,
+rndis_filter_set_offload_params(struct net_device *ndev,
 				struct ndis_offload_params *req_offloads)
 {
-	struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+	struct netvsc_device *nvdev = net_device_to_netvsc_device(ndev);
 	struct rndis_device *rdev = nvdev->extension;
-	struct net_device *ndev = nvdev->ndev;
 	struct rndis_request *request;
 	struct rndis_set_request *set;
 	struct ndis_offload_params *offload_params;
 	struct rndis_set_complete *set_complete;
 	u32 extlen = sizeof(struct ndis_offload_params);
 	int ret;
-	unsigned long t;
 	u32 vsp_version = nvdev->nvsp_version;
 
 	if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
@@ -674,20 +650,12 @@
 	if (ret != 0)
 		goto cleanup;
 
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n");
-		/* can't put_rndis_request, since we may still receive a
-		 * send-completion.
-		 */
-		return -EBUSY;
-	} else {
-		set_complete = &request->response_msg.msg.set_complete;
-		if (set_complete->status != RNDIS_STATUS_SUCCESS) {
-			netdev_err(ndev, "Fail to set offload on host side:0x%x\n",
-				   set_complete->status);
-			ret = -EINVAL;
-		}
+	wait_for_completion(&request->wait_event);
+	set_complete = &request->response_msg.msg.set_complete;
+	if (set_complete->status != RNDIS_STATUS_SUCCESS) {
+		netdev_err(ndev, "Fail to set offload on host side:0x%x\n",
+			   set_complete->status);
+		ret = -EINVAL;
 	}
 
 cleanup:
@@ -695,17 +663,18 @@
 	return ret;
 }
 
-u8 netvsc_hash_key[HASH_KEYLEN] = {
+static const u8 netvsc_hash_key[] = {
 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
 };
+#define HASH_KEYLEN ARRAY_SIZE(netvsc_hash_key)
 
 static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
 {
-	struct net_device *ndev = rdev->net_dev->ndev;
+	struct net_device *ndev = rdev->ndev;
 	struct rndis_request *request;
 	struct rndis_set_request *set;
 	struct rndis_set_complete *set_complete;
@@ -715,7 +684,6 @@
 	u32 *itab;
 	u8 *keyp;
 	int i, ret;
-	unsigned long t;
 
 	request = get_rndis_request(
 			rdev, RNDIS_MSG_SET,
@@ -753,25 +721,16 @@
 	for (i = 0; i < HASH_KEYLEN; i++)
 		keyp[i] = netvsc_hash_key[i];
 
-
 	ret = rndis_filter_send_request(rdev, request);
 	if (ret != 0)
 		goto cleanup;
 
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		netdev_err(ndev, "timeout before we got a set response...\n");
-		/* can't put_rndis_request, since we may still receive a
-		 * send-completion.
-		 */
-		return -ETIMEDOUT;
-	} else {
-		set_complete = &request->response_msg.msg.set_complete;
-		if (set_complete->status != RNDIS_STATUS_SUCCESS) {
-			netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
-				   set_complete->status);
-			ret = -EINVAL;
-		}
+	wait_for_completion(&request->wait_event);
+	set_complete = &request->response_msg.msg.set_complete;
+	if (set_complete->status != RNDIS_STATUS_SUCCESS) {
+		netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
+			   set_complete->status);
+		ret = -EINVAL;
 	}
 
 cleanup:
@@ -779,7 +738,6 @@
 	return ret;
 }
 
-
 static int rndis_filter_query_device_link_status(struct rndis_device *dev)
 {
 	u32 size = sizeof(u32);
@@ -793,6 +751,28 @@
 	return ret;
 }
 
+static int rndis_filter_query_link_speed(struct rndis_device *dev)
+{
+	u32 size = sizeof(u32);
+	u32 link_speed;
+	struct net_device_context *ndc;
+	int ret;
+
+	ret = rndis_filter_query_device(dev, RNDIS_OID_GEN_LINK_SPEED,
+					&link_speed, &size);
+
+	if (!ret) {
+		ndc = netdev_priv(dev->ndev);
+
+		/* The link speed reported from host is in 100bps unit, so
+		 * we convert it to Mbps here.
+		 */
+		ndc->speed = link_speed / 10000;
+	}
+
+	return ret;
+}
+
 int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
 {
 	struct rndis_request *request;
@@ -800,10 +780,6 @@
 	struct rndis_set_complete *set_complete;
 	u32 status;
 	int ret;
-	unsigned long t;
-	struct net_device *ndev;
-
-	ndev = dev->net_dev->ndev;
 
 	request = get_rndis_request(dev, RNDIS_MSG_SET,
 			RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
@@ -826,30 +802,17 @@
 	if (ret != 0)
 		goto cleanup;
 
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+	wait_for_completion(&request->wait_event);
 
-	if (t == 0) {
-		netdev_err(ndev,
-			"timeout before we got a set response...\n");
-		ret = -ETIMEDOUT;
-		/*
-		 * We can't deallocate the request since we may still receive a
-		 * send completion for it.
-		 */
-		goto exit;
-	} else {
-		set_complete = &request->response_msg.msg.set_complete;
-		status = set_complete->status;
-	}
+	set_complete = &request->response_msg.msg.set_complete;
+	status = set_complete->status;
 
 cleanup:
 	if (request)
 		put_rndis_request(dev, request);
-exit:
 	return ret;
 }
 
-
 static int rndis_filter_init_device(struct rndis_device *dev)
 {
 	struct rndis_request *request;
@@ -857,8 +820,7 @@
 	struct rndis_initialize_complete *init_complete;
 	u32 status;
 	int ret;
-	unsigned long t;
-	struct netvsc_device *nvdev = dev->net_dev;
+	struct netvsc_device *nvdev = net_device_to_netvsc_device(dev->ndev);
 
 	request = get_rndis_request(dev, RNDIS_MSG_INIT,
 			RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
@@ -881,13 +843,7 @@
 		goto cleanup;
 	}
 
-
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
+	wait_for_completion(&request->wait_event);
 
 	init_complete = &request->response_msg.msg.init_complete;
 	status = init_complete->status;
@@ -912,8 +868,9 @@
 {
 	struct rndis_request *request;
 	struct rndis_halt_request *halt;
-	struct netvsc_device *nvdev = dev->net_dev;
-	struct hv_device *hdev = nvdev->dev;
+	struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
+	struct netvsc_device *nvdev = net_device_ctx->nvdev;
+	struct hv_device *hdev = net_device_ctx->device_ctx;
 	ulong flags;
 
 	/* Attempt to do a rndis device halt */
@@ -938,11 +895,11 @@
 
 	/* Wait for all send completions */
 	wait_event(nvdev->wait_drain,
-		atomic_read(&nvdev->num_outstanding_sends) == 0);
+		   atomic_read(&nvdev->num_outstanding_sends) == 0 &&
+		   atomic_read(&nvdev->num_outstanding_recvs) == 0);
 
 	if (request)
 		put_rndis_request(dev, request);
-	return;
 }
 
 static int rndis_filter_open_device(struct rndis_device *dev)
@@ -981,43 +938,47 @@
 
 static void netvsc_sc_open(struct vmbus_channel *new_sc)
 {
-	struct netvsc_device *nvscdev;
+	struct net_device *ndev =
+		hv_get_drvdata(new_sc->primary_channel->device_obj);
+	struct netvsc_device *nvscdev = net_device_to_netvsc_device(ndev);
 	u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
 	int ret;
 	unsigned long flags;
 
-	nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj);
-
-	spin_lock_irqsave(&nvscdev->sc_lock, flags);
-	nvscdev->num_sc_offered--;
-	spin_unlock_irqrestore(&nvscdev->sc_lock, flags);
-	if (nvscdev->num_sc_offered == 0)
-		complete(&nvscdev->channel_init_wait);
-
 	if (chn_index >= nvscdev->num_chn)
 		return;
 
 	set_per_channel_state(new_sc, nvscdev->sub_cb_buf + (chn_index - 1) *
 			      NETVSC_PACKET_SIZE);
 
+	nvscdev->mrc[chn_index].buf = vzalloc(NETVSC_RECVSLOT_MAX *
+					      sizeof(struct recv_comp_data));
+
 	ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE,
 			 nvscdev->ring_size * PAGE_SIZE, NULL, 0,
 			 netvsc_channel_cb, new_sc);
 
 	if (ret == 0)
 		nvscdev->chn_table[chn_index] = new_sc;
+
+	spin_lock_irqsave(&nvscdev->sc_lock, flags);
+	nvscdev->num_sc_offered--;
+	spin_unlock_irqrestore(&nvscdev->sc_lock, flags);
+	if (nvscdev->num_sc_offered == 0)
+		complete(&nvscdev->channel_init_wait);
 }
 
 int rndis_filter_device_add(struct hv_device *dev,
-				  void *additional_info)
+			    void *additional_info)
 {
 	int ret;
+	struct net_device *net = hv_get_drvdata(dev);
+	struct net_device_context *net_device_ctx = netdev_priv(net);
 	struct netvsc_device *net_device;
 	struct rndis_device *rndis_device;
 	struct netvsc_device_info *device_info = additional_info;
 	struct ndis_offload_params offloads;
 	struct nvsp_message *init_packet;
-	unsigned long t;
 	struct ndis_recv_scale_cap rsscap;
 	u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
 	u32 mtu, size;
@@ -1042,16 +1003,15 @@
 		return ret;
 	}
 
-
 	/* Initialize the rndis device */
-	net_device = hv_get_drvdata(dev);
+	net_device = net_device_ctx->nvdev;
 	net_device->max_chn = 1;
 	net_device->num_chn = 1;
 
 	spin_lock_init(&net_device->sc_lock);
 
 	net_device->extension = rndis_device;
-	rndis_device->net_dev = net_device;
+	rndis_device->ndev = net;
 
 	/* Send the rndis initialization message */
 	ret = rndis_filter_init_device(rndis_device);
@@ -1065,8 +1025,8 @@
 	ret = rndis_filter_query_device(rndis_device,
 					RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
 					&mtu, &size);
-	if (ret == 0 && size == sizeof(u32) && mtu < net_device->ndev->mtu)
-		net_device->ndev->mtu = mtu;
+	if (ret == 0 && size == sizeof(u32) && mtu < net->mtu)
+		net->mtu = mtu;
 
 	/* Get the mac address */
 	ret = rndis_filter_query_device_mac(rndis_device);
@@ -1091,8 +1051,7 @@
 	offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
 	offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
 
-
-	ret = rndis_filter_set_offload_params(dev, &offloads);
+	ret = rndis_filter_set_offload_params(net, &offloads);
 	if (ret)
 		goto err_dev_remv;
 
@@ -1107,6 +1066,8 @@
 	if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
 		return 0;
 
+	rndis_filter_query_link_speed(rndis_device);
+
 	/* vRSS setup */
 	memset(&rsscap, 0, rsscap_size);
 	ret = rndis_filter_query_device(rndis_device,
@@ -1115,9 +1076,9 @@
 	if (ret || rsscap.num_recv_que < 2)
 		goto out;
 
-	num_rss_qs = min(device_info->max_num_vrss_chns, rsscap.num_recv_que);
+	net_device->max_chn = min_t(u32, VRSS_CHANNEL_MAX, rsscap.num_recv_que);
 
-	net_device->max_chn = rsscap.num_recv_que;
+	num_rss_qs = min(device_info->max_num_vrss_chns, net_device->max_chn);
 
 	/*
 	 * We will limit the VRSS channels to the number CPUs in the NUMA node
@@ -1161,11 +1122,8 @@
 			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 	if (ret)
 		goto out;
-	t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto out;
-	}
+	wait_for_completion(&net_device->channel_init_wait);
+
 	if (init_packet->msg.v5_msg.subchn_comp.status !=
 	    NVSP_STAT_SUCCESS) {
 		ret = -ENODEV;
@@ -1177,22 +1135,18 @@
 	ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
 
 	/*
-	 * Wait for the host to send us the sub-channel offers.
+	 * Set the number of sub-channels to be received.
 	 */
 	spin_lock_irqsave(&net_device->sc_lock, flags);
 	sc_delta = num_rss_qs - (net_device->num_chn - 1);
 	net_device->num_sc_offered -= sc_delta;
 	spin_unlock_irqrestore(&net_device->sc_lock, flags);
 
-	while (net_device->num_sc_offered != 0) {
-		t = wait_for_completion_timeout(&net_device->channel_init_wait, 10*HZ);
-		if (t == 0)
-			WARN(1, "Netvsc: Waiting for sub-channel processing");
-	}
 out:
 	if (ret) {
 		net_device->max_chn = 1;
 		net_device->num_chn = 1;
+		net_device->num_sc_offered = 0;
 	}
 
 	return 0; /* return 0 because primary channel can be used alone */
@@ -1204,9 +1158,15 @@
 
 void rndis_filter_device_remove(struct hv_device *dev)
 {
-	struct netvsc_device *net_dev = hv_get_drvdata(dev);
+	struct netvsc_device *net_dev = hv_device_to_netvsc_device(dev);
 	struct rndis_device *rndis_dev = net_dev->extension;
 
+	/* If not all subchannel offers are complete, wait for them until
+	 * completion to avoid race.
+	 */
+	if (net_dev->num_sc_offered > 0)
+		wait_for_completion(&net_dev->channel_init_wait);
+
 	/* Halt and release the rndis device */
 	rndis_filter_halt_device(rndis_dev);
 
@@ -1216,23 +1176,24 @@
 	netvsc_device_remove(dev);
 }
 
-
-int rndis_filter_open(struct hv_device *dev)
+int rndis_filter_open(struct netvsc_device *nvdev)
 {
-	struct netvsc_device *net_device = hv_get_drvdata(dev);
-
-	if (!net_device)
+	if (!nvdev)
 		return -EINVAL;
 
-	return rndis_filter_open_device(net_device->extension);
+	if (atomic_inc_return(&nvdev->open_cnt) != 1)
+		return 0;
+
+	return rndis_filter_open_device(nvdev->extension);
 }
 
-int rndis_filter_close(struct hv_device *dev)
+int rndis_filter_close(struct netvsc_device *nvdev)
 {
-	struct netvsc_device *nvdev = hv_get_drvdata(dev);
-
 	if (!nvdev)
 		return -EINVAL;
 
+	if (atomic_dec_return(&nvdev->open_cnt) != 0)
+		return 0;
+
 	return rndis_filter_close_device(nvdev->extension);
 }
--- linux-4.4.0.orig/drivers/net/ieee802154/at86rf230.c
+++ linux-4.4.0/drivers/net/ieee802154/at86rf230.c
@@ -932,7 +932,7 @@
 static int
 at86rf230_ed(struct ieee802154_hw *hw, u8 *level)
 {
-	BUG_ON(!level);
+	WARN_ON(!level);
 	*level = 0xbe;
 	return 0;
 }
@@ -1108,8 +1108,7 @@
 	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
 		u16 addr = le16_to_cpu(filt->short_addr);
 
-		dev_vdbg(&lp->spi->dev,
-			 "at86rf230_set_hw_addr_filt called for saddr\n");
+		dev_vdbg(&lp->spi->dev, "%s called for saddr\n", __func__);
 		__at86rf230_write(lp, RG_SHORT_ADDR_0, addr);
 		__at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
 	}
@@ -1117,8 +1116,7 @@
 	if (changed & IEEE802154_AFILT_PANID_CHANGED) {
 		u16 pan = le16_to_cpu(filt->pan_id);
 
-		dev_vdbg(&lp->spi->dev,
-			 "at86rf230_set_hw_addr_filt called for pan id\n");
+		dev_vdbg(&lp->spi->dev, "%s called for pan id\n", __func__);
 		__at86rf230_write(lp, RG_PAN_ID_0, pan);
 		__at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
 	}
@@ -1127,15 +1125,13 @@
 		u8 i, addr[8];
 
 		memcpy(addr, &filt->ieee_addr, 8);
-		dev_vdbg(&lp->spi->dev,
-			 "at86rf230_set_hw_addr_filt called for IEEE addr\n");
+		dev_vdbg(&lp->spi->dev, "%s called for IEEE addr\n", __func__);
 		for (i = 0; i < 8; i++)
 			__at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
 	}
 
 	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
-		dev_vdbg(&lp->spi->dev,
-			 "at86rf230_set_hw_addr_filt called for panc change\n");
+		dev_vdbg(&lp->spi->dev, "%s called for panc change\n", __func__);
 		if (filt->pan_coord)
 			at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1);
 		else
@@ -1239,7 +1235,6 @@
 	return at86rf230_write_subreg(lp, SR_CCA_MODE, val);
 }
 
-
 static int
 at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
 {
--- linux-4.4.0.orig/drivers/net/ieee802154/atusb.c
+++ linux-4.4.0/drivers/net/ieee802154/atusb.c
@@ -110,13 +110,26 @@
 {
 	struct usb_device *usb_dev = atusb->usb_dev;
 	int ret;
+	uint8_t *buffer;
 	uint8_t value;
 
+	buffer = kmalloc(1, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
 	dev_dbg(&usb_dev->dev, "atusb: reg = 0x%x\n", reg);
 	ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
 				ATUSB_REG_READ, ATUSB_REQ_FROM_DEV,
-				0, reg, &value, 1, 1000);
-	return ret >= 0 ? value : ret;
+				0, reg, buffer, 1, 1000);
+
+	if (ret >= 0) {
+		value = buffer[0];
+		kfree(buffer);
+		return value;
+	} else {
+		kfree(buffer);
+		return ret;
+	}
 }
 
 static int atusb_write_subreg(struct atusb *atusb, uint8_t reg, uint8_t mask,
@@ -517,9 +530,13 @@
 static int atusb_get_and_show_revision(struct atusb *atusb)
 {
 	struct usb_device *usb_dev = atusb->usb_dev;
-	unsigned char buffer[3];
+	unsigned char *buffer;
 	int ret;
 
+	buffer = kmalloc(3, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
 	/* Get a couple of the ATMega Firmware values */
 	ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
 				ATUSB_ID, ATUSB_REQ_FROM_DEV, 0, 0,
@@ -535,15 +552,20 @@
 		dev_info(&usb_dev->dev, "Please update to version 0.2 or newer");
 	}
 
+	kfree(buffer);
 	return ret;
 }
 
 static int atusb_get_and_show_build(struct atusb *atusb)
 {
 	struct usb_device *usb_dev = atusb->usb_dev;
-	char build[ATUSB_BUILD_SIZE + 1];
+	char *build;
 	int ret;
 
+	build = kmalloc(ATUSB_BUILD_SIZE + 1, GFP_KERNEL);
+	if (!build)
+		return -ENOMEM;
+
 	ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
 				ATUSB_BUILD, ATUSB_REQ_FROM_DEV, 0, 0,
 				build, ATUSB_BUILD_SIZE, 1000);
@@ -552,6 +574,7 @@
 		dev_info(&usb_dev->dev, "Firmware: build %s\n", build);
 	}
 
+	kfree(build);
 	return ret;
 }
 
@@ -733,10 +756,11 @@
 
 	ieee802154_unregister_hw(atusb->hw);
 
+	usb_put_dev(atusb->usb_dev);
+
 	ieee802154_free_hw(atusb->hw);
 
 	usb_set_intfdata(interface, NULL);
-	usb_put_dev(atusb->usb_dev);
 
 	pr_debug("atusb_disconnect done\n");
 }
--- linux-4.4.0.orig/drivers/net/ieee802154/fakelb.c
+++ linux-4.4.0/drivers/net/ieee802154/fakelb.c
@@ -30,7 +30,7 @@
 static int numlbs = 2;
 
 static LIST_HEAD(fakelb_phys);
-static DEFINE_SPINLOCK(fakelb_phys_lock);
+static DEFINE_MUTEX(fakelb_phys_lock);
 
 static LIST_HEAD(fakelb_ifup_phys);
 static DEFINE_RWLOCK(fakelb_ifup_phys_lock);
@@ -49,7 +49,7 @@
 
 static int fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)
 {
-	BUG_ON(!level);
+	WARN_ON(!level);
 	*level = 0xbe;
 
 	return 0;
@@ -180,9 +180,9 @@
 	if (err)
 		goto err_reg;
 
-	spin_lock(&fakelb_phys_lock);
+	mutex_lock(&fakelb_phys_lock);
 	list_add_tail(&phy->list, &fakelb_phys);
-	spin_unlock(&fakelb_phys_lock);
+	mutex_unlock(&fakelb_phys_lock);
 
 	return 0;
 
@@ -214,10 +214,10 @@
 	return 0;
 
 err_slave:
-	spin_lock(&fakelb_phys_lock);
+	mutex_lock(&fakelb_phys_lock);
 	list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
 		fakelb_del(phy);
-	spin_unlock(&fakelb_phys_lock);
+	mutex_unlock(&fakelb_phys_lock);
 	return err;
 }
 
@@ -225,10 +225,10 @@
 {
 	struct fakelb_phy *phy, *tmp;
 
-	spin_lock(&fakelb_phys_lock);
+	mutex_lock(&fakelb_phys_lock);
 	list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
 		fakelb_del(phy);
-	spin_unlock(&fakelb_phys_lock);
+	mutex_unlock(&fakelb_phys_lock);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/net/ipvlan/ipvlan_core.c
+++ linux-4.4.0/drivers/net/ipvlan/ipvlan_core.c
@@ -251,6 +251,7 @@
 		} else {
 			kfree_skb(skb);
 		}
+		cond_resched();
 	}
 }
 
@@ -282,6 +283,10 @@
 		if (dev_forward_skb(ipvlan->dev, skb) == NET_RX_SUCCESS)
 			success = true;
 	} else {
+		if (!ether_addr_equal_64bits(eth_hdr(skb)->h_dest,
+					     ipvlan->phy_dev->dev_addr))
+			skb->pkt_type = PACKET_OTHERHOST;
+
 		ret = RX_HANDLER_ANOTHER;
 		success = true;
 	}
@@ -353,6 +358,7 @@
 		.flowi4_oif = dev->ifindex,
 		.flowi4_tos = RT_TOS(ip4h->tos),
 		.flowi4_flags = FLOWI_FLAG_ANYSRC,
+		.flowi4_mark = skb->mark,
 		.daddr = ip4h->daddr,
 		.saddr = ip4h->saddr,
 	};
@@ -367,6 +373,9 @@
 	}
 	skb_dst_drop(skb);
 	skb_dst_set(skb, &rt->dst);
+
+	memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+
 	err = ip_local_out(net, skb->sk, skb);
 	if (unlikely(net_xmit_eval(err)))
 		dev->stats.tx_errors++;
@@ -388,7 +397,7 @@
 	struct dst_entry *dst;
 	int err, ret = NET_XMIT_DROP;
 	struct flowi6 fl6 = {
-		.flowi6_iif = dev->ifindex,
+		.flowi6_oif = dev->ifindex,
 		.daddr = ip6h->daddr,
 		.saddr = ip6h->saddr,
 		.flowi6_flags = FLOWI_FLAG_ANYSRC,
@@ -405,6 +414,9 @@
 	}
 	skb_dst_drop(skb);
 	skb_dst_set(skb, dst);
+
+	memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+
 	err = ip6_local_out(net, skb->sk, skb);
 	if (unlikely(net_xmit_eval(err)))
 		dev->stats.tx_errors++;
@@ -424,19 +436,21 @@
 	struct ethhdr *ethh = eth_hdr(skb);
 	int ret = NET_XMIT_DROP;
 
-	/* In this mode we dont care about multicast and broadcast traffic */
-	if (is_multicast_ether_addr(ethh->h_dest)) {
-		pr_warn_ratelimited("Dropped {multi|broad}cast of type= [%x]\n",
-				    ntohs(skb->protocol));
-		kfree_skb(skb);
-		goto out;
-	}
-
 	/* The ipvlan is a pseudo-L2 device, so the packets that we receive
 	 * will have L2; which need to discarded and processed further
 	 * in the net-ns of the main-device.
 	 */
 	if (skb_mac_header_was_set(skb)) {
+		/* In this mode we dont care about
+		 * multicast and broadcast traffic */
+		if (is_multicast_ether_addr(ethh->h_dest)) {
+			pr_debug_ratelimited(
+				"Dropped {multi|broad}cast of type=[%x]\n",
+				ntohs(skb->protocol));
+			kfree_skb(skb);
+			goto out;
+		}
+
 		skb_pull(skb, sizeof(*ethh));
 		skb->mac_header = (typeof(skb->mac_header))~0U;
 		skb_reset_network_header(skb);
--- linux-4.4.0.orig/drivers/net/ipvlan/ipvlan_main.c
+++ linux-4.4.0/drivers/net/ipvlan/ipvlan_main.c
@@ -87,12 +87,21 @@
 static struct lock_class_key ipvlan_netdev_xmit_lock_key;
 static struct lock_class_key ipvlan_netdev_addr_lock_key;
 
+#define IPVLAN_ALWAYS_ON_OFLOADS \
+	(NETIF_F_SG | NETIF_F_HW_CSUM | \
+	 NETIF_F_GSO_ROBUST | NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ENCAP_ALL)
+
+#define IPVLAN_ALWAYS_ON \
+	(IPVLAN_ALWAYS_ON_OFLOADS | NETIF_F_LLTX | NETIF_F_VLAN_CHALLENGED)
+
 #define IPVLAN_FEATURES \
 	(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
 	 NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
 	 NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \
 	 NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER)
 
+	/* NETIF_F_GSO_ENCAP_ALL NETIF_F_GSO_SOFTWARE Newly added */
+
 #define IPVLAN_STATE_MASK \
 	((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
 
@@ -117,7 +126,9 @@
 	dev->state = (dev->state & ~IPVLAN_STATE_MASK) |
 		     (phy_dev->state & IPVLAN_STATE_MASK);
 	dev->features = phy_dev->features & IPVLAN_FEATURES;
-	dev->features |= NETIF_F_LLTX;
+	dev->features |= IPVLAN_ALWAYS_ON;
+	dev->vlan_features = phy_dev->vlan_features & IPVLAN_FEATURES;
+	dev->vlan_features |= IPVLAN_ALWAYS_ON_OFLOADS;
 	dev->gso_max_size = phy_dev->gso_max_size;
 	dev->hard_header_len = phy_dev->hard_header_len;
 
@@ -145,7 +156,6 @@
 static int ipvlan_open(struct net_device *dev)
 {
 	struct ipvl_dev *ipvlan = netdev_priv(dev);
-	struct net_device *phy_dev = ipvlan->phy_dev;
 	struct ipvl_addr *addr;
 
 	if (ipvlan->port->mode == IPVLAN_MODE_L3)
@@ -156,7 +166,7 @@
 	list_for_each_entry(addr, &ipvlan->addrs, anode)
 		ipvlan_ht_addr_add(ipvlan, addr);
 
-	return dev_uc_add(phy_dev, phy_dev->dev_addr);
+	return 0;
 }
 
 static int ipvlan_stop(struct net_device *dev)
@@ -168,8 +178,6 @@
 	dev_uc_unsync(phy_dev, dev);
 	dev_mc_unsync(phy_dev, dev);
 
-	dev_uc_del(phy_dev, phy_dev->dev_addr);
-
 	list_for_each_entry(addr, &ipvlan->addrs, anode)
 		ipvlan_ht_addr_del(addr);
 
@@ -204,7 +212,14 @@
 {
 	struct ipvl_dev *ipvlan = netdev_priv(dev);
 
-	return features & (ipvlan->sfeatures | ~IPVLAN_FEATURES);
+	features |= NETIF_F_ALL_FOR_ALL;
+	features &= (ipvlan->sfeatures | ~IPVLAN_FEATURES);
+	features = netdev_increment_features(ipvlan->phy_dev->features,
+					     features, features);
+	features |= IPVLAN_ALWAYS_ON;
+	features &= (IPVLAN_FEATURES | IPVLAN_ALWAYS_ON);
+
+	return features;
 }
 
 static void ipvlan_change_rx_flags(struct net_device *dev, int change)
@@ -389,7 +404,12 @@
 	struct ipvl_dev *ipvlan = netdev_priv(dev);
 	struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev);
 
-	if (data && data[IFLA_IPVLAN_MODE]) {
+	if (!data)
+		return 0;
+	if (!ns_capable(dev_net(ipvlan->phy_dev)->user_ns, CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (data[IFLA_IPVLAN_MODE]) {
 		u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
 
 		ipvlan_set_port_mode(port, nmode);
@@ -454,6 +474,8 @@
 		struct ipvl_dev *tmp = netdev_priv(phy_dev);
 
 		phy_dev = tmp->phy_dev;
+		if (!ns_capable(dev_net(phy_dev)->user_ns, CAP_NET_ADMIN))
+			return -EPERM;
 	} else if (!netif_is_ipvlan_port(phy_dev)) {
 		err = ipvlan_port_create(phy_dev);
 		if (err < 0)
@@ -586,9 +608,8 @@
 
 	case NETDEV_FEAT_CHANGE:
 		list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
-			ipvlan->dev->features = dev->features & IPVLAN_FEATURES;
 			ipvlan->dev->gso_max_size = dev->gso_max_size;
-			netdev_features_change(ipvlan->dev);
+			netdev_update_features(ipvlan->dev);
 		}
 		break;
 
--- linux-4.4.0.orig/drivers/net/irda/ali-ircc.c
+++ linux-4.4.0/drivers/net/irda/ali-ircc.c
@@ -2207,11 +2207,11 @@
 MODULE_ALIAS("platform:" ALI_IRCC_DRIVER_NAME);
 
 
-module_param_array(io, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
 MODULE_PARM_DESC(io, "Base I/O addresses");
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(irq, "IRQ lines");
-module_param_array(dma, int, NULL, 0);
+module_param_hw_array(dma, int, dma, NULL, 0);
 MODULE_PARM_DESC(dma, "DMA channels");
 
 module_init(ali_ircc_init);
--- linux-4.4.0.orig/drivers/net/irda/irda-usb.c
+++ linux-4.4.0/drivers/net/irda/irda-usb.c
@@ -1077,7 +1077,7 @@
          * are "42101001.sb" or "42101002.sb"
          */
         sprintf(stir421x_fw_name, "4210%4X.sb",
-                self->usbdev->descriptor.bcdDevice);
+		le16_to_cpu(self->usbdev->descriptor.bcdDevice));
         ret = request_firmware(&fw, stir421x_fw_name, &self->usbdev->dev);
         if (ret < 0)
                 return ret;
--- linux-4.4.0.orig/drivers/net/irda/irtty-sir.c
+++ linux-4.4.0/drivers/net/irda/irtty-sir.c
@@ -430,16 +430,6 @@
 
 	/* Module stuff handled via irda_ldisc.owner - Jean II */
 
-	/* First make sure we're not already connected. */
-	if (tty->disc_data != NULL) {
-		priv = tty->disc_data;
-		if (priv && priv->magic == IRTTY_MAGIC) {
-			ret = -EEXIST;
-			goto out;
-		}
-		tty->disc_data = NULL;		/* ### */
-	}
-
 	/* stop the underlying  driver */
 	irtty_stop_receiver(tty, TRUE);
 	if (tty->ops->stop)
--- linux-4.4.0.orig/drivers/net/irda/mcs7780.c
+++ linux-4.4.0/drivers/net/irda/mcs7780.c
@@ -141,9 +141,19 @@
 static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val)
 {
 	struct usb_device *dev = mcs->usbdev;
-	int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
-				  MCS_RD_RTYPE, 0, reg, val, 2,
-				  msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+	void *dmabuf;
+	int ret;
+
+	dmabuf = kmalloc(sizeof(__u16), GFP_KERNEL);
+	if (!dmabuf)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+			      MCS_RD_RTYPE, 0, reg, dmabuf, 2,
+			      msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+
+	memcpy(val, dmabuf, sizeof(__u16));
+	kfree(dmabuf);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/net/irda/nsc-ircc.c
+++ linux-4.4.0/drivers/net/irda/nsc-ircc.c
@@ -2395,11 +2395,11 @@
 
 module_param(qos_mtt_bits, int, 0);
 MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
-module_param_array(io, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
 MODULE_PARM_DESC(io, "Base I/O addresses");
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(irq, "IRQ lines");
-module_param_array(dma, int, NULL, 0);
+module_param_hw_array(dma, int, dma, NULL, 0);
 MODULE_PARM_DESC(dma, "DMA channels");
 module_param(dongle_id, int, 0);
 MODULE_PARM_DESC(dongle_id, "Type-id of used dongle");
--- linux-4.4.0.orig/drivers/net/irda/smsc-ircc2.c
+++ linux-4.4.0/drivers/net/irda/smsc-ircc2.c
@@ -82,24 +82,24 @@
 
 #define DMA_INVAL 255
 static int ircc_dma = DMA_INVAL;
-module_param(ircc_dma, int, 0);
+module_param_hw(ircc_dma, int, dma, 0);
 MODULE_PARM_DESC(ircc_dma, "DMA channel");
 
 #define IRQ_INVAL 255
 static int ircc_irq = IRQ_INVAL;
-module_param(ircc_irq, int, 0);
+module_param_hw(ircc_irq, int, irq, 0);
 MODULE_PARM_DESC(ircc_irq, "IRQ line");
 
 static int ircc_fir;
-module_param(ircc_fir, int, 0);
+module_param_hw(ircc_fir, int, ioport, 0);
 MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
 
 static int ircc_sir;
-module_param(ircc_sir, int, 0);
+module_param_hw(ircc_sir, int, ioport, 0);
 MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
 
 static int ircc_cfg;
-module_param(ircc_cfg, int, 0);
+module_param_hw(ircc_cfg, int, ioport, 0);
 MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
 
 static int ircc_transceiver;
--- linux-4.4.0.orig/drivers/net/irda/vlsi_ir.c
+++ linux-4.4.0/drivers/net/irda/vlsi_ir.c
@@ -418,8 +418,9 @@
 		memset(rd, 0, sizeof(*rd));
 		rd->hw = hwmap + i;
 		rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA);
-		if (rd->buf == NULL ||
-		    !(busaddr = pci_map_single(pdev, rd->buf, len, dir))) {
+		if (rd->buf)
+			busaddr = pci_map_single(pdev, rd->buf, len, dir);
+		if (rd->buf == NULL || pci_dma_mapping_error(pdev, busaddr)) {
 			if (rd->buf) {
 				net_err_ratelimited("%s: failed to create PCI-MAP for %p\n",
 						    __func__, rd->buf);
@@ -430,8 +431,7 @@
 				rd = r->rd + j;
 				busaddr = rd_get_addr(rd);
 				rd_set_addr_status(rd, 0, 0);
-				if (busaddr)
-					pci_unmap_single(pdev, busaddr, len, dir);
+				pci_unmap_single(pdev, busaddr, len, dir);
 				kfree(rd->buf);
 				rd->buf = NULL;
 			}
--- linux-4.4.0.orig/drivers/net/irda/w83977af_ir.c
+++ linux-4.4.0/drivers/net/irda/w83977af_ir.c
@@ -518,7 +518,9 @@
 		
 		mtt = irda_get_mtt(skb);
 		pr_debug("%s(%ld), mtt=%d\n", __func__ , jiffies, mtt);
-			if (mtt)
+			if (mtt > 1000)
+				mdelay(mtt/1000);
+			else if (mtt)
 				udelay(mtt);
 
 			/* Enable DMA interrupt */
@@ -1264,9 +1266,9 @@
 
 module_param(qos_mtt_bits, int, 0);
 MODULE_PARM_DESC(qos_mtt_bits, "Mimimum Turn Time");
-module_param_array(io, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
 MODULE_PARM_DESC(io, "Base I/O addresses");
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(irq, "IRQ lines");
 
 /*
--- linux-4.4.0.orig/drivers/net/loopback.c
+++ linux-4.4.0/drivers/net/loopback.c
@@ -164,6 +164,7 @@
 {
 	dev->mtu		= 64 * 1024;
 	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
+	dev->min_header_len	= ETH_HLEN;	/* 14	*/
 	dev->addr_len		= ETH_ALEN;	/* 6	*/
 	dev->type		= ARPHRD_LOOPBACK;	/* 0x0001*/
 	dev->flags		= IFF_LOOPBACK;
@@ -175,7 +176,7 @@
 		| NETIF_F_UFO
 		| NETIF_F_HW_CSUM
 		| NETIF_F_RXCSUM
-		| NETIF_F_SCTP_CSUM
+		| NETIF_F_SCTP_CRC
 		| NETIF_F_HIGHDMA
 		| NETIF_F_LLTX
 		| NETIF_F_NETNS_LOCAL
--- linux-4.4.0.orig/drivers/net/macvlan.c
+++ linux-4.4.0/drivers/net/macvlan.c
@@ -305,11 +305,16 @@
 
 		rcu_read_unlock();
 
+		if (src)
+			dev_put(src->dev);
 		kfree_skb(skb);
+
+		cond_resched();
 	}
 }
 
 static void macvlan_broadcast_enqueue(struct macvlan_port *port,
+				      const struct macvlan_dev *src,
 				      struct sk_buff *skb)
 {
 	struct sk_buff *nskb;
@@ -319,17 +324,22 @@
 	if (!nskb)
 		goto err;
 
+	MACVLAN_SKB_CB(nskb)->src = src;
+
 	spin_lock(&port->bc_queue.lock);
 	if (skb_queue_len(&port->bc_queue) < MACVLAN_BC_QUEUE_LEN) {
+		if (src)
+			dev_hold(src->dev);
 		__skb_queue_tail(&port->bc_queue, nskb);
 		err = 0;
 	}
 	spin_unlock(&port->bc_queue.lock);
 
+	schedule_work(&port->bc_work);
+
 	if (err)
 		goto free_nskb;
 
-	schedule_work(&port->bc_work);
 	return;
 
 free_nskb:
@@ -410,6 +420,10 @@
 	int ret;
 	rx_handler_result_t handle_res;
 
+	/* Packets from dev_loopback_xmit() do not have L2 header, bail out */
+	if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
+		return RX_HANDLER_PASS;
+
 	port = macvlan_port_get_rcu(skb->dev);
 	if (is_multicast_ether_addr(eth->h_dest)) {
 		skb = ip_check_defrag(dev_net(skb->dev), skb, IP_DEFRAG_MACVLAN);
@@ -429,8 +443,7 @@
 			goto out;
 		}
 
-		MACVLAN_SKB_CB(skb)->src = src;
-		macvlan_broadcast_enqueue(port, skb);
+		macvlan_broadcast_enqueue(port, src, skb);
 
 		return RX_HANDLER_PASS;
 	}
@@ -441,7 +454,7 @@
 					      struct macvlan_dev, list);
 	else
 		vlan = macvlan_hash_lookup(port, eth->h_dest);
-	if (vlan == NULL)
+	if (!vlan || vlan->mode == MACVLAN_MODE_SOURCE)
 		return RX_HANDLER_PASS;
 
 	dev = vlan->dev;
@@ -475,10 +488,11 @@
 	const struct macvlan_dev *dest;
 
 	if (vlan->mode == MACVLAN_MODE_BRIDGE) {
-		const struct ethhdr *eth = (void *)skb->data;
+		const struct ethhdr *eth = skb_eth_hdr(skb);
 
 		/* send to other bridge ports directly */
 		if (is_multicast_ether_addr(eth->h_dest)) {
+			skb_reset_mac_header(skb);
 			macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE);
 			goto xmit_world;
 		}
@@ -1110,6 +1124,7 @@
 static void macvlan_port_destroy(struct net_device *dev)
 {
 	struct macvlan_port *port = macvlan_port_get_rtnl(dev);
+	struct sk_buff *skb;
 
 	dev->priv_flags &= ~IFF_MACVLAN_PORT;
 	netdev_rx_handler_unregister(dev);
@@ -1118,7 +1133,15 @@
 	 * but we need to cancel it and purge left skbs if any.
 	 */
 	cancel_work_sync(&port->bc_work);
-	__skb_queue_purge(&port->bc_queue);
+
+	while ((skb = __skb_dequeue(&port->bc_queue))) {
+		const struct macvlan_dev *src = MACVLAN_SKB_CB(skb)->src;
+
+		if (src)
+			dev_put(src->dev);
+
+		kfree_skb(skb);
+	}
 
 	kfree_rcu(port, rcu);
 }
@@ -1548,7 +1571,7 @@
 						struct macvlan_dev,
 						list);
 
-		if (macvlan_sync_address(vlan->dev, dev->dev_addr))
+		if (vlan && macvlan_sync_address(vlan->dev, dev->dev_addr))
 			return NOTIFY_BAD;
 
 		break;
--- linux-4.4.0.orig/drivers/net/macvtap.c
+++ linux-4.4.0/drivers/net/macvtap.c
@@ -373,7 +373,7 @@
 			goto wake_up;
 		}
 
-		kfree_skb(skb);
+		consume_skb(skb);
 		while (segs) {
 			struct sk_buff *nskb = segs->next;
 
@@ -725,7 +725,7 @@
 	ssize_t n;
 
 	if (q->flags & IFF_VNET_HDR) {
-		vnet_hdr_len = q->vnet_hdr_sz;
+		vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
 
 		err = -EINVAL;
 		if (len < vnet_hdr_len)
@@ -760,6 +760,8 @@
 			macvtap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
 		if (copylen > good_linear)
 			copylen = good_linear;
+		else if (copylen < ETH_HLEN)
+			copylen = ETH_HLEN;
 		linear = copylen;
 		i = *from;
 		iov_iter_advance(&i, copylen);
@@ -769,10 +771,11 @@
 
 	if (!zerocopy) {
 		copylen = len;
-		if (macvtap16_to_cpu(q, vnet_hdr.hdr_len) > good_linear)
+		linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
+		if (linear > good_linear)
 			linear = good_linear;
-		else
-			linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
+		else if (linear < ETH_HLEN)
+			linear = ETH_HLEN;
 	}
 
 	skb = macvtap_alloc_skb(&q->sk, MACVTAP_RESERVE, copylen,
@@ -862,7 +865,7 @@
 
 	if (q->flags & IFF_VNET_HDR) {
 		struct virtio_net_hdr vnet_hdr;
-		vnet_hdr_len = q->vnet_hdr_sz;
+		vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
 		if (iov_iter_count(iter) < vnet_hdr_len)
 			return -EINVAL;
 
@@ -1114,6 +1117,8 @@
 	case TUNSETSNDBUF:
 		if (get_user(s, sp))
 			return -EFAULT;
+		if (s <= 0)
+			return -EINVAL;
 
 		q->sk.sk_sndbuf = s;
 		return 0;
--- linux-4.4.0.orig/drivers/net/ntb_netdev.c
+++ linux-4.4.0/drivers/net/ntb_netdev.c
@@ -236,7 +236,7 @@
 	struct ntb_netdev *dev = netdev_priv(ndev);
 
 	if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {
-		mod_timer(&dev->tx_timer, jiffies + msecs_to_jiffies(tx_time));
+		mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
 	} else {
 		/* Make sure anybody stopping the queue after this sees the new
 		 * value of ntb_transport_tx_free_entry()
--- linux-4.4.0.orig/drivers/net/phy/Kconfig
+++ linux-4.4.0/drivers/net/phy/Kconfig
@@ -183,14 +183,28 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called mdio-gpio.
 
+config MDIO_CAVIUM
+	tristate
+
 config MDIO_OCTEON
-	tristate "Support for MDIO buses on Octeon and ThunderX SOCs"
+	tristate "Support for MDIO buses on Octeon and some ThunderX SOCs"
 	depends on 64BIT
+	select MDIO_CAVIUM
 	help
-
 	  This module provides a driver for the Octeon and ThunderX MDIO
-	  busses. It is required by the Octeon and ThunderX ethernet device
-	  drivers.
+	  buses. It is required by the Octeon and ThunderX ethernet device
+	  drivers on some systems.
+
+config MDIO_THUNDER
+	tristate "Support for MDIO buses on ThunderX SOCs"
+	depends on 64BIT
+	depends on PCI
+	select MDIO_CAVIUM
+	help
+	  This driver supports the MDIO interfaces found on Cavium
+	  ThunderX SoCs when the MDIO bus device appears as a PCI
+	  device.
+
 
 config MDIO_SUN4I
 	tristate "Allwinner sun4i MDIO interface support"
@@ -256,6 +270,12 @@
 	  This module provides a driver for the MDIO busses found in the
 	  Broadcom iProc SoC's.
 
+config MDIO_XGENE
+	tristate "APM X-Gene SoC MDIO bus controller"
+	help
+	  This module provides a driver for the MDIO busses found in the
+	  APM X-Gene SoC's.
+
 endif # PHYLIB
 
 config MICREL_KS8995MA
--- linux-4.4.0.orig/drivers/net/phy/Makefile
+++ linux-4.4.0/drivers/net/phy/Makefile
@@ -31,6 +31,8 @@
 obj-$(CONFIG_STE10XP)		+= ste10Xp.o
 obj-$(CONFIG_MICREL_PHY)	+= micrel.o
 obj-$(CONFIG_MDIO_OCTEON)	+= mdio-octeon.o
+obj-$(CONFIG_MDIO_THUNDER)	+= mdio-thunder.o
+obj-$(CONFIG_MDIO_CAVIUM)	+= mdio-cavium.o
 obj-$(CONFIG_MICREL_KS8995MA)	+= spi_ks8995.o
 obj-$(CONFIG_AT803X_PHY)	+= at803x.o
 obj-$(CONFIG_AMD_PHY)		+= amd.o
@@ -42,3 +44,4 @@
 obj-$(CONFIG_MDIO_BCM_UNIMAC)	+= mdio-bcm-unimac.o
 obj-$(CONFIG_MICROCHIP_PHY)	+= microchip.o
 obj-$(CONFIG_MDIO_BCM_IPROC)	+= mdio-bcm-iproc.o
+obj-$(CONFIG_MDIO_XGENE)	+= mdio-xgene.o
--- linux-4.4.0.orig/drivers/net/phy/at803x.c
+++ linux-4.4.0/drivers/net/phy/at803x.c
@@ -105,7 +105,7 @@
 		mac = (const u8 *) ndev->dev_addr;
 
 		if (!is_valid_ether_addr(mac))
-			return -EFAULT;
+			return -EINVAL;
 
 		for (i = 0; i < 3; i++) {
 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
@@ -198,7 +198,7 @@
 	if (!priv)
 		return -ENOMEM;
 
-	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(gpiod_reset))
 		return PTR_ERR(gpiod_reset);
 
@@ -274,10 +274,10 @@
 
 				at803x_context_save(phydev, &context);
 
-				gpiod_set_value(priv->gpiod_reset, 0);
-				msleep(1);
 				gpiod_set_value(priv->gpiod_reset, 1);
 				msleep(1);
+				gpiod_set_value(priv->gpiod_reset, 0);
+				msleep(1);
 
 				at803x_context_restore(phydev, &context);
 
--- linux-4.4.0.orig/drivers/net/phy/bcm-cygnus.c
+++ linux-4.4.0/drivers/net/phy/bcm-cygnus.c
@@ -61,17 +61,17 @@
 		return rc;
 
 	/* make rcal=100, since rdb default is 000 */
-	rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB1, 0x10);
+	rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10);
 	if (rc < 0)
 		return rc;
 
 	/* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */
-	rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x10);
+	rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10);
 	if (rc < 0)
 		return rc;
 
 	/* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */
-	rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x00);
+	rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/phy/bcm-phy-lib.h
+++ linux-4.4.0/drivers/net/phy/bcm-phy-lib.h
@@ -14,11 +14,18 @@
 #ifndef _LINUX_BCM_PHY_LIB_H
 #define _LINUX_BCM_PHY_LIB_H
 
+#include <linux/brcmphy.h>
 #include <linux/phy.h>
 
 int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
 int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
 
+static inline int bcm_phy_write_exp_sel(struct phy_device *phydev,
+					u16 reg, u16 val)
+{
+	return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val);
+}
+
 int bcm_phy_write_misc(struct phy_device *phydev,
 		       u16 reg, u16 chl, u16 value);
 int bcm_phy_read_misc(struct phy_device *phydev,
--- linux-4.4.0.orig/drivers/net/phy/bcm63xx.c
+++ linux-4.4.0/drivers/net/phy/bcm63xx.c
@@ -21,6 +21,23 @@
 MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
 MODULE_LICENSE("GPL");
 
+static int bcm63xx_config_intr(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM63XX_IR);
+	if (reg < 0)
+		return reg;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		reg &= ~MII_BCM63XX_IR_GMASK;
+	else
+		reg |= MII_BCM63XX_IR_GMASK;
+
+	err = phy_write(phydev, MII_BCM63XX_IR, reg);
+	return err;
+}
+
 static int bcm63xx_config_init(struct phy_device *phydev)
 {
 	int reg, err;
@@ -55,7 +72,7 @@
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
 	.ack_interrupt	= bcm_phy_ack_intr,
-	.config_intr	= bcm_phy_config_intr,
+	.config_intr	= bcm63xx_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	/* same phy as above, with just a different OUI */
@@ -68,7 +85,7 @@
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
 	.ack_interrupt	= bcm_phy_ack_intr,
-	.config_intr	= bcm_phy_config_intr,
+	.config_intr	= bcm63xx_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 } };
 
--- linux-4.4.0.orig/drivers/net/phy/bcm7xxx.c
+++ linux-4.4.0/drivers/net/phy/bcm7xxx.c
@@ -48,10 +48,10 @@
 static void r_rc_cal_reset(struct phy_device *phydev)
 {
 	/* Reset R_CAL/RC_CAL Engine */
-	bcm_phy_write_exp(phydev, 0x00b0, 0x0010);
+	bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010);
 
 	/* Disable Reset R_AL/RC_CAL Engine */
-	bcm_phy_write_exp(phydev, 0x00b0, 0x0000);
+	bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000);
 }
 
 static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
@@ -270,7 +270,7 @@
 	phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
 
 	/* reset shadow mode 2 */
-	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0);
+	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
 	if (ret < 0)
 		return ret;
 
--- linux-4.4.0.orig/drivers/net/phy/dp83640.c
+++ linux-4.4.0/drivers/net/phy/dp83640.c
@@ -845,6 +845,11 @@
 	struct skb_shared_hwtstamps *shhwtstamps = NULL;
 	struct sk_buff *skb;
 	unsigned long flags;
+	u8 overflow;
+
+	overflow = (phy_rxts->ns_hi >> 14) & 0x3;
+	if (overflow)
+		pr_debug("rx timestamp queue overflow, count %d\n", overflow);
 
 	spin_lock_irqsave(&dp83640->rx_lock, flags);
 
@@ -885,17 +890,34 @@
 			struct phy_txts *phy_txts)
 {
 	struct skb_shared_hwtstamps shhwtstamps;
+	struct dp83640_skb_info *skb_info;
 	struct sk_buff *skb;
+	u8 overflow;
 	u64 ns;
 
 	/* We must already have the skb that triggered this. */
-
+again:
 	skb = skb_dequeue(&dp83640->tx_queue);
-
 	if (!skb) {
 		pr_debug("have timestamp but tx_queue empty\n");
 		return;
 	}
+
+	overflow = (phy_txts->ns_hi >> 14) & 0x3;
+	if (overflow) {
+		pr_debug("tx timestamp queue overflow, count %d\n", overflow);
+		while (skb) {
+			kfree_skb(skb);
+			skb = skb_dequeue(&dp83640->tx_queue);
+		}
+		return;
+	}
+	skb_info = (struct dp83640_skb_info *)skb->cb;
+	if (time_after(jiffies, skb_info->tmo)) {
+		kfree_skb(skb);
+		goto again;
+	}
+
 	ns = phy2txts(phy_txts);
 	memset(&shhwtstamps, 0, sizeof(shhwtstamps));
 	shhwtstamps.hwtstamp = ns_to_ktime(ns);
@@ -1085,7 +1107,7 @@
 		goto out;
 	}
 	dp83640_clock_init(clock, bus);
-	list_add_tail(&phyter_clocks, &clock->list);
+	list_add_tail(&clock->list, &phyter_clocks);
 out:
 	mutex_unlock(&phyter_clocks_lock);
 
@@ -1186,6 +1208,23 @@
 	kfree(dp83640);
 }
 
+static int dp83640_soft_reset(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = genphy_soft_reset(phydev);
+	if (ret < 0)
+		return ret;
+
+	/* From DP83640 datasheet: "Software driver code must wait 3 us
+	 * following a software reset before allowing further serial MII
+	 * operations with the DP83640."
+	 */
+	udelay(10);		/* Taking udelay inaccuracy into account */
+
+	return 0;
+}
+
 static int dp83640_config_init(struct phy_device *phydev)
 {
 	struct dp83640_private *dp83640 = phydev->priv;
@@ -1296,6 +1335,7 @@
 		dp83640->hwts_rx_en = 1;
 		dp83640->layer = PTP_CLASS_L4;
 		dp83640->version = PTP_CLASS_V1;
+		cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
 		break;
 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
@@ -1303,6 +1343,7 @@
 		dp83640->hwts_rx_en = 1;
 		dp83640->layer = PTP_CLASS_L4;
 		dp83640->version = PTP_CLASS_V2;
+		cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
 		break;
 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
@@ -1310,6 +1351,7 @@
 		dp83640->hwts_rx_en = 1;
 		dp83640->layer = PTP_CLASS_L2;
 		dp83640->version = PTP_CLASS_V2;
+		cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
 		break;
 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
@@ -1317,6 +1359,7 @@
 		dp83640->hwts_rx_en = 1;
 		dp83640->layer = PTP_CLASS_L4 | PTP_CLASS_L2;
 		dp83640->version = PTP_CLASS_V2;
+		cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 		break;
 	default:
 		return -ERANGE;
@@ -1419,8 +1462,6 @@
 		skb_info->tmo = jiffies + SKB_TIMESTAMP_TIMEOUT;
 		skb_queue_tail(&dp83640->rx_queue, skb);
 		schedule_delayed_work(&dp83640->ts_work, SKB_TIMESTAMP_TIMEOUT);
-	} else {
-		netif_rx_ni(skb);
 	}
 
 	return true;
@@ -1429,6 +1470,7 @@
 static void dp83640_txtstamp(struct phy_device *phydev,
 			     struct sk_buff *skb, int type)
 {
+	struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb;
 	struct dp83640_private *dp83640 = phydev->priv;
 
 	switch (dp83640->hwts_tx_en) {
@@ -1441,6 +1483,7 @@
 		/* fall through */
 	case HWTSTAMP_TX_ON:
 		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+		skb_info->tmo = jiffies + SKB_TIMESTAMP_TIMEOUT;
 		skb_queue_tail(&dp83640->tx_queue, skb);
 		break;
 
@@ -1481,6 +1524,7 @@
 	.flags		= PHY_HAS_INTERRUPT,
 	.probe		= dp83640_probe,
 	.remove		= dp83640_remove,
+	.soft_reset	= dp83640_soft_reset,
 	.config_init	= dp83640_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
--- linux-4.4.0.orig/drivers/net/phy/dp83867.c
+++ linux-4.4.0/drivers/net/phy/dp83867.c
@@ -29,6 +29,7 @@
 #define MII_DP83867_MICR	0x12
 #define MII_DP83867_ISR		0x13
 #define DP83867_CTRL		0x1f
+#define DP83867_CFG3		0x1e
 
 /* Extended Registers */
 #define DP83867_RGMIICTL	0x0032
@@ -89,6 +90,8 @@
 		micr_status |=
 			(MII_DP83867_MICR_AN_ERR_INT_EN |
 			MII_DP83867_MICR_SPEED_CHNG_INT_EN |
+			MII_DP83867_MICR_AUTONEG_COMP_INT_EN |
+			MII_DP83867_MICR_LINK_STS_CHNG_INT_EN |
 			MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
 			MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
 
@@ -184,6 +187,13 @@
 				       DP83867_DEVADDR, phydev->addr, delay);
 	}
 
+	/* Enable Interrupt output INT_OE in CFG3 register */
+	if (phy_interrupt_is_valid(phydev)) {
+		val = phy_read(phydev, DP83867_CFG3);
+		val |= BIT(7);
+		phy_write(phydev, DP83867_CFG3, val);
+	}
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/net/phy/fixed_phy.c
+++ linux-4.4.0/drivers/net/phy/fixed_phy.c
@@ -5,6 +5,7 @@
  *         Anton Vorontsov <avorontsov@ru.mvista.com>
  *
  * Copyright (c) 2006-2007 MontaVista Software, Inc.
+ * Copyright 2009 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
@@ -17,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/list.h>
 #include <linux/mii.h>
+#include <linux/mdio.h>
 #include <linux/phy.h>
 #include <linux/phy_fixed.h>
 #include <linux/err.h>
@@ -59,6 +61,9 @@
 
 	if (fp->status.duplex) {
 		switch (fp->status.speed) {
+		case 10000:
+			fp->regs[MDIO_STAT2] = MDIO_STAT2_DEVPRST_VAL;
+			break;
 		case 1000:
 			bmsr |= BMSR_ESTATEN;
 			break;
@@ -73,6 +78,9 @@
 		}
 	} else {
 		switch (fp->status.speed) {
+		case 10000:
+			fp->regs[MDIO_STAT2] = MDIO_STAT2_DEVPRST_VAL;
+			break;
 		case 1000:
 			bmsr |= BMSR_ESTATEN;
 			break;
--- linux-4.4.0.orig/drivers/net/phy/marvell.c
+++ linux-4.4.0/drivers/net/phy/marvell.c
@@ -203,34 +203,6 @@
 {
 	int err;
 
-	/* The Marvell PHY has an errata which requires
-	 * that certain registers get written in order
-	 * to restart autonegotiation */
-	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
-
-	if (err < 0)
-		return err;
-
-	err = phy_write(phydev, 0x1d, 0x1f);
-	if (err < 0)
-		return err;
-
-	err = phy_write(phydev, 0x1e, 0x200c);
-	if (err < 0)
-		return err;
-
-	err = phy_write(phydev, 0x1d, 0x5);
-	if (err < 0)
-		return err;
-
-	err = phy_write(phydev, 0x1e, 0);
-	if (err < 0)
-		return err;
-
-	err = phy_write(phydev, 0x1e, 0x100);
-	if (err < 0)
-		return err;
-
 	err = marvell_set_polarity(phydev, phydev->mdix);
 	if (err < 0)
 		return err;
@@ -264,6 +236,42 @@
 	return 0;
 }
 
+static int m88e1101_config_aneg(struct phy_device *phydev)
+{
+	int err;
+
+	/* This Marvell PHY has an errata which requires
+	 * that certain registers get written in order
+	 * to restart autonegotiation
+	 */
+	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1d, 0x1f);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1e, 0x200c);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1d, 0x5);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1e, 0);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1e, 0x100);
+	if (err < 0)
+		return err;
+
+	return marvell_config_aneg(phydev);
+}
+
 #ifdef CONFIG_OF_MDIO
 /*
  * Set and/or override some configuration registers based on the
@@ -814,8 +822,6 @@
 		phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) |
 					 mii_lpa_to_ethtool_lpa_t(lpa);
 
-		lpa &= adv;
-
 		if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
 			phydev->duplex = DUPLEX_FULL;
 		else
@@ -993,7 +999,7 @@
 		.name = "Marvell 88E1101",
 		.features = PHY_GBIT_FEATURES,
 		.flags = PHY_HAS_INTERRUPT,
-		.config_aneg = &marvell_config_aneg,
+		.config_aneg = &m88e1101_config_aneg,
 		.read_status = &genphy_read_status,
 		.ack_interrupt = &marvell_ack_interrupt,
 		.config_intr = &marvell_config_intr,
@@ -1085,7 +1091,7 @@
 		.features = PHY_GBIT_FEATURES,
 		.flags = PHY_HAS_INTERRUPT,
 		.config_init = &m88e1145_config_init,
-		.config_aneg = &marvell_config_aneg,
+		.config_aneg = &m88e1101_config_aneg,
 		.read_status = &genphy_read_status,
 		.ack_interrupt = &marvell_ack_interrupt,
 		.config_intr = &marvell_config_intr,
--- linux-4.4.0.orig/drivers/net/phy/mdio-bcm-iproc.c
+++ linux-4.4.0/drivers/net/phy/mdio-bcm-iproc.c
@@ -81,8 +81,6 @@
 	if (rc)
 		return rc;
 
-	iproc_mdio_config_clk(priv->base);
-
 	/* Prepare the read operation */
 	cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) |
 		(reg << MII_DATA_RA_SHIFT) |
@@ -112,8 +110,6 @@
 	if (rc)
 		return rc;
 
-	iproc_mdio_config_clk(priv->base);
-
 	/* Prepare the write operation */
 	cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) |
 		(reg << MII_DATA_RA_SHIFT) |
@@ -163,6 +159,8 @@
 	bus->read = iproc_mdio_read;
 	bus->write = iproc_mdio_write;
 
+	iproc_mdio_config_clk(priv->base);
+
 	rc = of_mdiobus_register(bus, pdev->dev.of_node);
 	if (rc) {
 		dev_err(&pdev->dev, "MDIO bus registration failed\n");
@@ -190,6 +188,23 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+int iproc_mdio_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct iproc_mdio_priv *priv = platform_get_drvdata(pdev);
+
+	/* restore the mii clock configuration */
+	iproc_mdio_config_clk(priv->base);
+
+	return 0;
+}
+
+static const struct dev_pm_ops iproc_mdio_pm_ops = {
+	.resume = iproc_mdio_resume
+};
+#endif /* CONFIG_PM_SLEEP */
+
 static const struct of_device_id iproc_mdio_of_match[] = {
 	{ .compatible = "brcm,iproc-mdio", },
 	{ /* sentinel */ },
@@ -200,6 +215,9 @@
 	.driver = {
 		.name = "iproc-mdio",
 		.of_match_table = iproc_mdio_of_match,
+#ifdef CONFIG_PM_SLEEP
+		.pm = &iproc_mdio_pm_ops,
+#endif
 	},
 	.probe = iproc_mdio_probe,
 	.remove = iproc_mdio_remove,
--- linux-4.4.0.orig/drivers/net/phy/mdio-bcm-unimac.c
+++ linux-4.4.0/drivers/net/phy/mdio-bcm-unimac.c
@@ -177,6 +177,8 @@
 		return -ENOMEM;
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -EINVAL;
 
 	/* Just ioremap, as this MDIO block is usually integrated into an
 	 * Ethernet MAC controller register range
--- linux-4.4.0.orig/drivers/net/phy/mdio-cavium.c
+++ linux-4.4.0/drivers/net/phy/mdio-cavium.c
@@ -0,0 +1,153 @@
+/*
+ * 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-2016 Cavium, Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/io.h>
+
+#include "mdio-cavium.h"
+
+static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p,
+				    enum cavium_mdiobus_mode m)
+{
+	union cvmx_smix_clk smi_clk;
+
+	if (m == p->mode)
+		return;
+
+	smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK);
+	smi_clk.s.mode = (m == C45) ? 1 : 0;
+	smi_clk.s.preamble = 1;
+	oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK);
+	p->mode = m;
+}
+
+static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,
+				   int phy_id, int regnum)
+{
+	union cvmx_smix_cmd smi_cmd;
+	union cvmx_smix_wr_dat smi_wr;
+	int timeout = 1000;
+
+	cavium_mdiobus_set_mode(p, C45);
+
+	smi_wr.u64 = 0;
+	smi_wr.s.dat = regnum & 0xffff;
+	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
+
+	regnum = (regnum >> 16) & 0x1f;
+
+	smi_cmd.u64 = 0;
+	smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */
+	smi_cmd.s.phy_adr = phy_id;
+	smi_cmd.s.reg_adr = regnum;
+	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
+
+	do {
+		/* Wait 1000 clocks so we don't saturate the RSL bus
+		 * doing reads.
+		 */
+		__delay(1000);
+		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
+	} while (smi_wr.s.pending && --timeout);
+
+	if (timeout <= 0)
+		return -EIO;
+	return 0;
+}
+
+int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+	struct cavium_mdiobus *p = bus->priv;
+	union cvmx_smix_cmd smi_cmd;
+	union cvmx_smix_rd_dat smi_rd;
+	unsigned int op = 1; /* MDIO_CLAUSE_22_READ */
+	int timeout = 1000;
+
+	if (regnum & MII_ADDR_C45) {
+		int r = cavium_mdiobus_c45_addr(p, phy_id, regnum);
+
+		if (r < 0)
+			return r;
+
+		regnum = (regnum >> 16) & 0x1f;
+		op = 3; /* MDIO_CLAUSE_45_READ */
+	} else {
+		cavium_mdiobus_set_mode(p, C22);
+	}
+
+	smi_cmd.u64 = 0;
+	smi_cmd.s.phy_op = op;
+	smi_cmd.s.phy_adr = phy_id;
+	smi_cmd.s.reg_adr = regnum;
+	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
+
+	do {
+		/* Wait 1000 clocks so we don't saturate the RSL bus
+		 * doing reads.
+		 */
+		__delay(1000);
+		smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
+	} while (smi_rd.s.pending && --timeout);
+
+	if (smi_rd.s.val)
+		return smi_rd.s.dat;
+	else
+		return -EIO;
+}
+EXPORT_SYMBOL(cavium_mdiobus_read);
+
+int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
+{
+	struct cavium_mdiobus *p = bus->priv;
+	union cvmx_smix_cmd smi_cmd;
+	union cvmx_smix_wr_dat smi_wr;
+	unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */
+	int timeout = 1000;
+
+	if (regnum & MII_ADDR_C45) {
+		int r = cavium_mdiobus_c45_addr(p, phy_id, regnum);
+
+		if (r < 0)
+			return r;
+
+		regnum = (regnum >> 16) & 0x1f;
+		op = 1; /* MDIO_CLAUSE_45_WRITE */
+	} else {
+		cavium_mdiobus_set_mode(p, C22);
+	}
+
+	smi_wr.u64 = 0;
+	smi_wr.s.dat = val;
+	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
+
+	smi_cmd.u64 = 0;
+	smi_cmd.s.phy_op = op;
+	smi_cmd.s.phy_adr = phy_id;
+	smi_cmd.s.reg_adr = regnum;
+	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
+
+	do {
+		/* Wait 1000 clocks so we don't saturate the RSL bus
+		 * doing reads.
+		 */
+		__delay(1000);
+		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
+	} while (smi_wr.s.pending && --timeout);
+
+	if (timeout <= 0)
+		return -EIO;
+
+	return 0;
+}
+EXPORT_SYMBOL(cavium_mdiobus_write);
+
+MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers");
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/phy/mdio-cavium.h
+++ linux-4.4.0/drivers/net/phy/mdio-cavium.h
@@ -0,0 +1,120 @@
+/*
+ * 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-2016 Cavium, Inc.
+ */
+
+enum cavium_mdiobus_mode {
+	UNINIT = 0,
+	C22,
+	C45
+};
+
+#define SMI_CMD		0x0
+#define SMI_WR_DAT	0x8
+#define SMI_RD_DAT	0x10
+#define SMI_CLK		0x18
+#define SMI_EN		0x20
+
+#ifdef __BIG_ENDIAN_BITFIELD
+#define OCT_MDIO_BITFIELD_FIELD(field, more)	\
+	field;					\
+	more
+
+#else
+#define OCT_MDIO_BITFIELD_FIELD(field, more)	\
+	more					\
+	field;
+
+#endif
+
+union cvmx_smix_clk {
+	u64 u64;
+	struct cvmx_smix_clk_s {
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_25_63:39,
+	  OCT_MDIO_BITFIELD_FIELD(u64 mode:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_21_23:3,
+	  OCT_MDIO_BITFIELD_FIELD(u64 sample_hi:5,
+	  OCT_MDIO_BITFIELD_FIELD(u64 sample_mode:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_14_14:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 clk_idle:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 preamble:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 sample:4,
+	  OCT_MDIO_BITFIELD_FIELD(u64 phase:8,
+	  ;))))))))))
+	} s;
+};
+
+union cvmx_smix_cmd {
+	u64 u64;
+	struct cvmx_smix_cmd_s {
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
+	  OCT_MDIO_BITFIELD_FIELD(u64 phy_op:2,
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_13_15:3,
+	  OCT_MDIO_BITFIELD_FIELD(u64 phy_adr:5,
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_5_7:3,
+	  OCT_MDIO_BITFIELD_FIELD(u64 reg_adr:5,
+	  ;))))))
+	} s;
+};
+
+union cvmx_smix_en {
+	u64 u64;
+	struct cvmx_smix_en_s {
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_1_63:63,
+	  OCT_MDIO_BITFIELD_FIELD(u64 en:1,
+	  ;))
+	} s;
+};
+
+union cvmx_smix_rd_dat {
+	u64 u64;
+	struct cvmx_smix_rd_dat_s {
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
+	  OCT_MDIO_BITFIELD_FIELD(u64 pending:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 val:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 dat:16,
+	  ;))))
+	} s;
+};
+
+union cvmx_smix_wr_dat {
+	u64 u64;
+	struct cvmx_smix_wr_dat_s {
+	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
+	  OCT_MDIO_BITFIELD_FIELD(u64 pending:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 val:1,
+	  OCT_MDIO_BITFIELD_FIELD(u64 dat:16,
+	  ;))))
+	} s;
+};
+
+struct cavium_mdiobus {
+	struct mii_bus *mii_bus;
+	u64 register_base;
+	enum cavium_mdiobus_mode mode;
+	int phy_irq[PHY_MAX_ADDR];
+};
+
+#ifdef CONFIG_CAVIUM_OCTEON_SOC
+
+#include <asm/octeon/octeon.h>
+
+static inline void oct_mdio_writeq(u64 val, u64 addr)
+{
+	cvmx_write_csr(addr, val);
+}
+
+static inline u64 oct_mdio_readq(u64 addr)
+{
+	return cvmx_read_csr(addr);
+}
+#else
+#define oct_mdio_writeq(val, addr)	writeq(val, (void *)addr)
+#define oct_mdio_readq(addr)		readq((void *)addr)
+#endif
+
+int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum);
+int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val);
--- linux-4.4.0.orig/drivers/net/phy/mdio-octeon.c
+++ linux-4.4.0/drivers/net/phy/mdio-octeon.c
@@ -3,272 +3,25 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2009-2012 Cavium, Inc.
+ * Copyright (C) 2009-2015 Cavium, Inc.
  */
 
 #include <linux/platform_device.h>
 #include <linux/of_address.h>
 #include <linux/of_mdio.h>
-#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/phy.h>
 #include <linux/io.h>
 
-#ifdef CONFIG_CAVIUM_OCTEON_SOC
-#include <asm/octeon/octeon.h>
-#endif
-
-#define DRV_VERSION "1.1"
-#define DRV_DESCRIPTION "Cavium Networks Octeon/ThunderX SMI/MDIO driver"
-
-#define SMI_CMD		0x0
-#define SMI_WR_DAT	0x8
-#define SMI_RD_DAT	0x10
-#define SMI_CLK		0x18
-#define SMI_EN		0x20
-
-#ifdef __BIG_ENDIAN_BITFIELD
-#define OCT_MDIO_BITFIELD_FIELD(field, more)	\
-	field;					\
-	more
-
-#else
-#define OCT_MDIO_BITFIELD_FIELD(field, more)	\
-	more					\
-	field;
-
-#endif
-
-union cvmx_smix_clk {
-	u64 u64;
-	struct cvmx_smix_clk_s {
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_25_63:39,
-	  OCT_MDIO_BITFIELD_FIELD(u64 mode:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_21_23:3,
-	  OCT_MDIO_BITFIELD_FIELD(u64 sample_hi:5,
-	  OCT_MDIO_BITFIELD_FIELD(u64 sample_mode:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_14_14:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 clk_idle:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 preamble:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 sample:4,
-	  OCT_MDIO_BITFIELD_FIELD(u64 phase:8,
-	  ;))))))))))
-	} s;
-};
-
-union cvmx_smix_cmd {
-	u64 u64;
-	struct cvmx_smix_cmd_s {
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
-	  OCT_MDIO_BITFIELD_FIELD(u64 phy_op:2,
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_13_15:3,
-	  OCT_MDIO_BITFIELD_FIELD(u64 phy_adr:5,
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_5_7:3,
-	  OCT_MDIO_BITFIELD_FIELD(u64 reg_adr:5,
-	  ;))))))
-	} s;
-};
-
-union cvmx_smix_en {
-	u64 u64;
-	struct cvmx_smix_en_s {
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_1_63:63,
-	  OCT_MDIO_BITFIELD_FIELD(u64 en:1,
-	  ;))
-	} s;
-};
-
-union cvmx_smix_rd_dat {
-	u64 u64;
-	struct cvmx_smix_rd_dat_s {
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
-	  OCT_MDIO_BITFIELD_FIELD(u64 pending:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 val:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 dat:16,
-	  ;))))
-	} s;
-};
-
-union cvmx_smix_wr_dat {
-	u64 u64;
-	struct cvmx_smix_wr_dat_s {
-	  OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
-	  OCT_MDIO_BITFIELD_FIELD(u64 pending:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 val:1,
-	  OCT_MDIO_BITFIELD_FIELD(u64 dat:16,
-	  ;))))
-	} s;
-};
-
-enum octeon_mdiobus_mode {
-	UNINIT = 0,
-	C22,
-	C45
-};
-
-struct octeon_mdiobus {
-	struct mii_bus *mii_bus;
-	u64 register_base;
-	resource_size_t mdio_phys;
-	resource_size_t regsize;
-	enum octeon_mdiobus_mode mode;
-	int phy_irq[PHY_MAX_ADDR];
-};
-
-#ifdef CONFIG_CAVIUM_OCTEON_SOC
-static void oct_mdio_writeq(u64 val, u64 addr)
-{
-	cvmx_write_csr(addr, val);
-}
-
-static u64 oct_mdio_readq(u64 addr)
-{
-	return cvmx_read_csr(addr);
-}
-#else
-#define oct_mdio_writeq(val, addr)	writeq_relaxed(val, (void *)addr)
-#define oct_mdio_readq(addr)		readq_relaxed((void *)addr)
-#endif
-
-static void octeon_mdiobus_set_mode(struct octeon_mdiobus *p,
-				    enum octeon_mdiobus_mode m)
-{
-	union cvmx_smix_clk smi_clk;
-
-	if (m == p->mode)
-		return;
-
-	smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK);
-	smi_clk.s.mode = (m == C45) ? 1 : 0;
-	smi_clk.s.preamble = 1;
-	oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK);
-	p->mode = m;
-}
-
-static int octeon_mdiobus_c45_addr(struct octeon_mdiobus *p,
-				   int phy_id, int regnum)
-{
-	union cvmx_smix_cmd smi_cmd;
-	union cvmx_smix_wr_dat smi_wr;
-	int timeout = 1000;
-
-	octeon_mdiobus_set_mode(p, C45);
-
-	smi_wr.u64 = 0;
-	smi_wr.s.dat = regnum & 0xffff;
-	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
-
-	regnum = (regnum >> 16) & 0x1f;
-
-	smi_cmd.u64 = 0;
-	smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */
-	smi_cmd.s.phy_adr = phy_id;
-	smi_cmd.s.reg_adr = regnum;
-	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
-
-	do {
-		/* Wait 1000 clocks so we don't saturate the RSL bus
-		 * doing reads.
-		 */
-		__delay(1000);
-		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
-	} while (smi_wr.s.pending && --timeout);
-
-	if (timeout <= 0)
-		return -EIO;
-	return 0;
-}
-
-static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
-{
-	struct octeon_mdiobus *p = bus->priv;
-	union cvmx_smix_cmd smi_cmd;
-	union cvmx_smix_rd_dat smi_rd;
-	unsigned int op = 1; /* MDIO_CLAUSE_22_READ */
-	int timeout = 1000;
-
-	if (regnum & MII_ADDR_C45) {
-		int r = octeon_mdiobus_c45_addr(p, phy_id, regnum);
-		if (r < 0)
-			return r;
-
-		regnum = (regnum >> 16) & 0x1f;
-		op = 3; /* MDIO_CLAUSE_45_READ */
-	} else {
-		octeon_mdiobus_set_mode(p, C22);
-	}
-
-
-	smi_cmd.u64 = 0;
-	smi_cmd.s.phy_op = op;
-	smi_cmd.s.phy_adr = phy_id;
-	smi_cmd.s.reg_adr = regnum;
-	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
-
-	do {
-		/* Wait 1000 clocks so we don't saturate the RSL bus
-		 * doing reads.
-		 */
-		__delay(1000);
-		smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
-	} while (smi_rd.s.pending && --timeout);
-
-	if (smi_rd.s.val)
-		return smi_rd.s.dat;
-	else
-		return -EIO;
-}
-
-static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
-				int regnum, u16 val)
-{
-	struct octeon_mdiobus *p = bus->priv;
-	union cvmx_smix_cmd smi_cmd;
-	union cvmx_smix_wr_dat smi_wr;
-	unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */
-	int timeout = 1000;
-
-
-	if (regnum & MII_ADDR_C45) {
-		int r = octeon_mdiobus_c45_addr(p, phy_id, regnum);
-		if (r < 0)
-			return r;
-
-		regnum = (regnum >> 16) & 0x1f;
-		op = 1; /* MDIO_CLAUSE_45_WRITE */
-	} else {
-		octeon_mdiobus_set_mode(p, C22);
-	}
-
-	smi_wr.u64 = 0;
-	smi_wr.s.dat = val;
-	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
-
-	smi_cmd.u64 = 0;
-	smi_cmd.s.phy_op = op;
-	smi_cmd.s.phy_adr = phy_id;
-	smi_cmd.s.reg_adr = regnum;
-	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
-
-	do {
-		/* Wait 1000 clocks so we don't saturate the RSL bus
-		 * doing reads.
-		 */
-		__delay(1000);
-		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
-	} while (smi_wr.s.pending && --timeout);
-
-	if (timeout <= 0)
-		return -EIO;
-
-	return 0;
-}
+#include "mdio-cavium.h"
 
 static int octeon_mdiobus_probe(struct platform_device *pdev)
 {
-	struct octeon_mdiobus *bus;
+	struct cavium_mdiobus *bus;
 	struct resource *res_mem;
+	resource_size_t mdio_phys;
+	resource_size_t regsize;
 	union cvmx_smix_en smi_en;
 	int err = -ENOENT;
 
@@ -282,17 +35,17 @@
 		return -ENXIO;
 	}
 
-	bus->mdio_phys = res_mem->start;
-	bus->regsize = resource_size(res_mem);
+	mdio_phys = res_mem->start;
+	regsize = resource_size(res_mem);
 
-	if (!devm_request_mem_region(&pdev->dev, bus->mdio_phys, bus->regsize,
+	if (!devm_request_mem_region(&pdev->dev, mdio_phys, regsize,
 				     res_mem->name)) {
 		dev_err(&pdev->dev, "request_mem_region failed\n");
 		return -ENXIO;
 	}
 
 	bus->register_base =
-		(u64)devm_ioremap(&pdev->dev, bus->mdio_phys, bus->regsize);
+		(u64)devm_ioremap(&pdev->dev, mdio_phys, regsize);
 	if (!bus->register_base) {
 		dev_err(&pdev->dev, "dev_ioremap failed\n");
 		return -ENOMEM;
@@ -306,14 +59,13 @@
 	smi_en.s.en = 1;
 	oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
 
-	bus->mii_bus->priv = bus;
 	bus->mii_bus->irq = bus->phy_irq;
-	bus->mii_bus->name = "mdio-octeon";
+	bus->mii_bus->name = KBUILD_MODNAME;
 	snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base);
 	bus->mii_bus->parent = &pdev->dev;
 
-	bus->mii_bus->read = octeon_mdiobus_read;
-	bus->mii_bus->write = octeon_mdiobus_write;
+	bus->mii_bus->read = cavium_mdiobus_read;
+	bus->mii_bus->write = cavium_mdiobus_write;
 
 	platform_set_drvdata(pdev, bus);
 
@@ -321,7 +73,7 @@
 	if (err)
 		goto fail_register;
 
-	dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
+	dev_info(&pdev->dev, "Probed\n");
 
 	return 0;
 fail_register:
@@ -334,7 +86,7 @@
 
 static int octeon_mdiobus_remove(struct platform_device *pdev)
 {
-	struct octeon_mdiobus *bus;
+	struct cavium_mdiobus *bus;
 	union cvmx_smix_en smi_en;
 
 	bus = platform_get_drvdata(pdev);
@@ -356,7 +108,7 @@
 
 static struct platform_driver octeon_mdiobus_driver = {
 	.driver = {
-		.name		= "mdio-octeon",
+		.name		= KBUILD_MODNAME,
 		.of_match_table = octeon_mdiobus_match,
 	},
 	.probe		= octeon_mdiobus_probe,
@@ -371,7 +123,6 @@
 
 module_platform_driver(octeon_mdiobus_driver);
 
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Cavium OCTEON MDIO bus driver");
 MODULE_AUTHOR("David Daney");
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/phy/mdio-sun4i.c
+++ linux-4.4.0/drivers/net/phy/mdio-sun4i.c
@@ -128,10 +128,13 @@
 
 	data->regulator = devm_regulator_get(&pdev->dev, "phy");
 	if (IS_ERR(data->regulator)) {
-		if (PTR_ERR(data->regulator) == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
+		if (PTR_ERR(data->regulator) == -EPROBE_DEFER) {
+			ret = -EPROBE_DEFER;
+			goto err_out_free_mdiobus;
+		}
 
 		dev_info(&pdev->dev, "no regulator found\n");
+		data->regulator = NULL;
 	} else {
 		ret = regulator_enable(data->regulator);
 		if (ret)
@@ -147,7 +150,8 @@
 	return 0;
 
 err_out_disable_regulator:
-	regulator_disable(data->regulator);
+	if (data->regulator)
+		regulator_disable(data->regulator);
 err_out_free_mdiobus:
 	mdiobus_free(bus);
 	return ret;
--- linux-4.4.0.orig/drivers/net/phy/mdio-thunder.c
+++ linux-4.4.0/drivers/net/phy/mdio-thunder.c
@@ -0,0 +1,154 @@
+/*
+ * 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-2016 Cavium, Inc.
+ */
+
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/module.h>
+#include <linux/gfp.h>
+#include <linux/phy.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+
+#include "mdio-cavium.h"
+
+struct thunder_mdiobus_nexus {
+	void __iomem *bar0;
+	struct cavium_mdiobus *buses[4];
+};
+
+static int thunder_mdiobus_pci_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	struct device_node *node;
+	struct fwnode_handle *fwn;
+	struct thunder_mdiobus_nexus *nexus;
+	int err;
+	int i;
+
+	nexus = devm_kzalloc(&pdev->dev, sizeof(*nexus), GFP_KERNEL);
+	if (!nexus)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, nexus);
+
+	err = pcim_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to enable PCI device\n");
+		pci_set_drvdata(pdev, NULL);
+		return err;
+	}
+
+	err = pci_request_regions(pdev, KBUILD_MODNAME);
+	if (err) {
+		dev_err(&pdev->dev, "pci_request_regions failed\n");
+		goto err_disable_device;
+	}
+
+	nexus->bar0 = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!nexus->bar0) {
+		err = -ENOMEM;
+		goto err_release_regions;
+	}
+
+	i = 0;
+	device_for_each_child_node(&pdev->dev, fwn) {
+		struct resource r;
+		struct mii_bus *mii_bus;
+		struct cavium_mdiobus *bus;
+		union cvmx_smix_en smi_en;
+
+		/* If it is not an OF node we cannot handle it yet, so
+		 * exit the loop.
+		 */
+		node = to_of_node(fwn);
+		if (!node)
+			break;
+
+		err = of_address_to_resource(node, 0, &r);
+		if (err) {
+			dev_err(&pdev->dev,
+				"Couldn't translate address for \"%s\"\n",
+				node->name);
+			break;
+		}
+
+		mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus));
+		if (!mii_bus)
+			break;
+		bus = mii_bus->priv;
+		bus->mii_bus = mii_bus;
+
+		nexus->buses[i] = bus;
+		i++;
+
+		bus->register_base = (u64)nexus->bar0 +
+			r.start - pci_resource_start(pdev, 0);
+
+		smi_en.u64 = 0;
+		smi_en.s.en = 1;
+		oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
+		bus->mii_bus->name = KBUILD_MODNAME;
+		snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", r.start);
+		bus->mii_bus->parent = &pdev->dev;
+		bus->mii_bus->read = cavium_mdiobus_read;
+		bus->mii_bus->write = cavium_mdiobus_write;
+
+		err = of_mdiobus_register(bus->mii_bus, node);
+		if (err)
+			dev_err(&pdev->dev, "of_mdiobus_register failed\n");
+
+		dev_info(&pdev->dev, "Added bus at %llx\n", r.start);
+		if (i >= ARRAY_SIZE(nexus->buses))
+			break;
+	}
+	return 0;
+
+err_release_regions:
+	pci_release_regions(pdev);
+
+err_disable_device:
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void thunder_mdiobus_pci_remove(struct pci_dev *pdev)
+{
+	int i;
+	struct thunder_mdiobus_nexus *nexus = pci_get_drvdata(pdev);
+
+	for (i = 0; i < ARRAY_SIZE(nexus->buses); i++) {
+		struct cavium_mdiobus *bus = nexus->buses[i];
+
+		if (!bus)
+			continue;
+
+		mdiobus_unregister(bus->mii_bus);
+		mdiobus_free(bus->mii_bus);
+		oct_mdio_writeq(0, bus->register_base + SMI_EN);
+	}
+	pci_set_drvdata(pdev, NULL);
+}
+
+static const struct pci_device_id thunder_mdiobus_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa02b) },
+	{ 0, } /* End of table. */
+};
+MODULE_DEVICE_TABLE(pci, thunder_mdiobus_id_table);
+
+static struct pci_driver thunder_mdiobus_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = thunder_mdiobus_id_table,
+	.probe = thunder_mdiobus_pci_probe,
+	.remove = thunder_mdiobus_pci_remove,
+};
+
+module_pci_driver(thunder_mdiobus_driver);
+
+MODULE_DESCRIPTION("Cavium ThunderX MDIO bus driver");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/phy/mdio-xgene.c
+++ linux-4.4.0/drivers/net/phy/mdio-xgene.c
@@ -0,0 +1,477 @@
+/* Applied Micro X-Gene SoC MDIO Driver
+ *
+ * Copyright (c) 2016, Applied Micro Circuits Corporation
+ * Author: Iyappan Subramanian <isubramanian@apm.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/efi.h>
+#include <linux/if_vlan.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/prefetch.h>
+#include <linux/phy.h>
+#include <net/ip.h>
+#include "mdio-xgene.h"
+
+static bool xgene_mdio_status;
+
+static u32 xgene_enet_rd_mac(void __iomem *base_addr, u32 rd_addr)
+{
+	void __iomem *addr, *rd, *cmd, *cmd_done;
+	u32 done, rd_data = BUSY_MASK;
+	u8 wait = 10;
+
+	addr = base_addr + MAC_ADDR_REG_OFFSET;
+	rd = base_addr + MAC_READ_REG_OFFSET;
+	cmd = base_addr + MAC_COMMAND_REG_OFFSET;
+	cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET;
+
+	iowrite32(rd_addr, addr);
+	iowrite32(XGENE_ENET_RD_CMD, cmd);
+
+	while (wait--) {
+		done = ioread32(cmd_done);
+		if (done)
+			break;
+		udelay(1);
+	}
+
+	if (!done)
+		return rd_data;
+
+	rd_data = ioread32(rd);
+	iowrite32(0, cmd);
+
+	return rd_data;
+}
+
+static void xgene_enet_wr_mac(void __iomem *base_addr, u32 wr_addr, u32 wr_data)
+{
+	void __iomem *addr, *wr, *cmd, *cmd_done;
+	u8 wait = 10;
+	u32 done;
+
+	addr = base_addr + MAC_ADDR_REG_OFFSET;
+	wr = base_addr + MAC_WRITE_REG_OFFSET;
+	cmd = base_addr + MAC_COMMAND_REG_OFFSET;
+	cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET;
+
+	iowrite32(wr_addr, addr);
+	iowrite32(wr_data, wr);
+	iowrite32(XGENE_ENET_WR_CMD, cmd);
+
+	while (wait--) {
+		done = ioread32(cmd_done);
+		if (done)
+			break;
+		udelay(1);
+	}
+
+	if (!done)
+		pr_err("MCX mac write failed, addr: 0x%04x\n", wr_addr);
+
+	iowrite32(0, cmd);
+}
+
+int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg)
+{
+	void __iomem *addr = (void __iomem *)bus->priv;
+	u32 data, done;
+	u8 wait = 10;
+
+	data = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg);
+	xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, data);
+	xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK);
+	do {
+		usleep_range(5, 10);
+		done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR);
+	} while ((done & BUSY_MASK) && wait--);
+
+	if (done & BUSY_MASK) {
+		dev_err(&bus->dev, "MII_MGMT read failed\n");
+		return -EBUSY;
+	}
+
+	data = xgene_enet_rd_mac(addr, MII_MGMT_STATUS_ADDR);
+	xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, 0);
+
+	return data;
+}
+EXPORT_SYMBOL(xgene_mdio_rgmii_read);
+
+int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
+{
+	void __iomem *addr = (void __iomem *)bus->priv;
+	u32 val, done;
+	u8 wait = 10;
+
+	val = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg);
+	xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, val);
+
+	xgene_enet_wr_mac(addr, MII_MGMT_CONTROL_ADDR, data);
+	do {
+		usleep_range(5, 10);
+		done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR);
+	} while ((done & BUSY_MASK) && wait--);
+
+	if (done & BUSY_MASK) {
+		dev_err(&bus->dev, "MII_MGMT write failed\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(xgene_mdio_rgmii_write);
+
+static u32 xgene_menet_rd_diag_csr(struct xgene_mdio_pdata *pdata, u32 offset)
+{
+	return ioread32(pdata->diag_csr_addr + offset);
+}
+
+static void xgene_menet_wr_diag_csr(struct xgene_mdio_pdata *pdata,
+				    u32 offset, u32 val)
+{
+	iowrite32(val, pdata->diag_csr_addr + offset);
+}
+
+static int xgene_enet_ecc_init(struct xgene_mdio_pdata *pdata)
+{
+	u32 data;
+	u8 wait = 10;
+
+	xgene_menet_wr_diag_csr(pdata, MENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0);
+	do {
+		usleep_range(100, 110);
+		data = xgene_menet_rd_diag_csr(pdata, MENET_BLOCK_MEM_RDY_ADDR);
+	} while ((data != 0xffffffff) && wait--);
+
+	if (data != 0xffffffff) {
+		dev_err(pdata->dev, "Failed to release memory from shutdown\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void xgene_gmac_reset(struct xgene_mdio_pdata *pdata)
+{
+	xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, SOFT_RESET);
+	xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, 0);
+}
+
+static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata)
+{
+	int ret;
+
+	if (pdata->dev->of_node) {
+		clk_prepare_enable(pdata->clk);
+		udelay(5);
+		clk_disable_unprepare(pdata->clk);
+		udelay(5);
+		clk_prepare_enable(pdata->clk);
+		udelay(5);
+	} else {
+#ifdef CONFIG_ACPI
+		acpi_evaluate_object(ACPI_HANDLE(pdata->dev),
+				     "_RST", NULL, NULL);
+#endif
+	}
+
+	ret = xgene_enet_ecc_init(pdata);
+	if (ret)
+		return ret;
+	xgene_gmac_reset(pdata);
+
+	return 0;
+}
+
+static void xgene_enet_rd_mdio_csr(void __iomem *base_addr,
+				   u32 offset, u32 *val)
+{
+	void __iomem *addr = base_addr  + offset;
+
+	*val = ioread32(addr);
+}
+
+static void xgene_enet_wr_mdio_csr(void __iomem *base_addr,
+				   u32 offset, u32 val)
+{
+	void __iomem *addr = base_addr  + offset;
+
+	iowrite32(val, addr);
+}
+
+static int xgene_xfi_mdio_write(struct mii_bus *bus, int phy_id,
+				int reg, u16 data)
+{
+	void __iomem *addr = (void __iomem *)bus->priv;
+	int timeout = 100;
+	u32 status, val;
+
+	val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg) |
+	      SET_VAL(HSTMIIMWRDAT, data);
+	xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, data);
+
+	val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_WRITE);
+	xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val);
+
+	do {
+		usleep_range(5, 10);
+		xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status);
+	} while ((status & BUSY_MASK) && timeout--);
+
+	xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0);
+
+	return 0;
+}
+
+static int xgene_xfi_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+	void __iomem *addr = (void __iomem *)bus->priv;
+	u32 data, status, val;
+	int timeout = 100;
+
+	val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg);
+	xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, val);
+
+	val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_READ);
+	xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val);
+
+	do {
+		usleep_range(5, 10);
+		xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status);
+	} while ((status & BUSY_MASK) && timeout--);
+
+	if (status & BUSY_MASK) {
+		pr_err("XGENET_MII_MGMT write failed\n");
+		return -EBUSY;
+	}
+
+	xgene_enet_rd_mdio_csr(addr, MIIMRD_FIELD_ADDR, &data);
+	xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0);
+
+	return data;
+}
+
+struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr)
+{
+	struct phy_device *phy_dev;
+
+	phy_dev = get_phy_device(bus, phy_addr, false);
+	if (!phy_dev || IS_ERR(phy_dev))
+		return NULL;
+
+	if (phy_device_register(phy_dev))
+		phy_device_free(phy_dev);
+
+	return phy_dev;
+}
+EXPORT_SYMBOL(xgene_enet_phy_register);
+
+#ifdef CONFIG_ACPI
+static acpi_status acpi_register_phy(acpi_handle handle, u32 lvl,
+				     void *context, void **ret)
+{
+	struct mii_bus *mdio = context;
+	struct acpi_device *adev;
+	struct phy_device *phy_dev;
+	const union acpi_object *obj;
+	u32 phy_addr;
+
+	if (acpi_bus_get_device(handle, &adev))
+		return AE_OK;
+
+	if (acpi_dev_get_property(adev, "phy-channel", ACPI_TYPE_INTEGER, &obj))
+		return AE_OK;
+	phy_addr = obj->integer.value;
+
+	phy_dev = xgene_enet_phy_register(mdio, phy_addr);
+	adev->driver_data = phy_dev;
+
+	return AE_OK;
+}
+#endif
+
+static int xgene_mdio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mii_bus *mdio_bus;
+	const struct of_device_id *of_id;
+	struct resource *res;
+	struct xgene_mdio_pdata *pdata;
+	void __iomem *csr_base;
+	int mdio_id = 0, ret = 0;
+
+	of_id = of_match_device(xgene_mdio_of_match, &pdev->dev);
+	if (of_id) {
+		mdio_id = (enum xgene_mdio_id)of_id->data;
+	} else {
+#ifdef CONFIG_ACPI
+		const struct acpi_device_id *acpi_id;
+
+		acpi_id = acpi_match_device(xgene_mdio_acpi_match, &pdev->dev);
+		if (acpi_id)
+			mdio_id = (enum xgene_mdio_id)acpi_id->driver_data;
+#endif
+	}
+
+	if (!mdio_id)
+		return -ENODEV;
+
+	pdata = devm_kzalloc(dev, sizeof(struct xgene_mdio_pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+	pdata->mdio_id = mdio_id;
+	pdata->dev = dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	csr_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(csr_base)) {
+		dev_err(dev, "Unable to retrieve mac CSR region\n");
+		return PTR_ERR(csr_base);
+	}
+	pdata->mac_csr_addr = csr_base;
+	pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET;
+	pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET;
+
+	if (dev->of_node) {
+		pdata->clk = devm_clk_get(dev, NULL);
+		if (IS_ERR(pdata->clk)) {
+			dev_err(dev, "Unable to retrieve clk\n");
+			return PTR_ERR(pdata->clk);
+		}
+	}
+
+	ret = xgene_mdio_reset(pdata);
+	if (ret)
+		return ret;
+
+	mdio_bus = mdiobus_alloc();
+	if (!mdio_bus)
+		return -ENOMEM;
+
+	mdio_bus->name = "APM X-Gene MDIO bus";
+
+	if (mdio_id == XGENE_MDIO_RGMII) {
+		mdio_bus->read = xgene_mdio_rgmii_read;
+		mdio_bus->write = xgene_mdio_rgmii_write;
+		mdio_bus->priv = (void __force *)pdata->mac_csr_addr;
+		snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s",
+			 "xgene-mii-rgmii");
+	} else {
+		mdio_bus->read = xgene_xfi_mdio_read;
+		mdio_bus->write = xgene_xfi_mdio_write;
+		mdio_bus->priv = (void __force *)pdata->mdio_csr_addr;
+		snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s",
+			 "xgene-mii-xfi");
+	}
+
+	mdio_bus->parent = dev;
+	platform_set_drvdata(pdev, pdata);
+
+	if (dev->of_node) {
+		ret = of_mdiobus_register(mdio_bus, dev->of_node);
+	} else {
+#ifdef CONFIG_ACPI
+		/* Mask out all PHYs from auto probing. */
+		mdio_bus->phy_mask = ~0;
+		ret = mdiobus_register(mdio_bus);
+		if (ret)
+			goto out;
+
+		acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_HANDLE(dev), 1,
+				    acpi_register_phy, NULL, mdio_bus, NULL);
+#endif
+	}
+
+	if (ret)
+		goto out;
+
+	pdata->mdio_bus = mdio_bus;
+	xgene_mdio_status = true;
+
+	return 0;
+
+out:
+	mdiobus_free(mdio_bus);
+
+	return ret;
+}
+
+static int xgene_mdio_remove(struct platform_device *pdev)
+{
+	struct xgene_mdio_pdata *pdata = platform_get_drvdata(pdev);
+	struct mii_bus *mdio_bus = pdata->mdio_bus;
+	struct device *dev = &pdev->dev;
+
+	mdiobus_unregister(mdio_bus);
+	mdiobus_free(mdio_bus);
+
+	if (dev->of_node) {
+		if (IS_ERR(pdata->clk))
+			clk_disable_unprepare(pdata->clk);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id xgene_mdio_of_match[] = {
+	{
+		.compatible = "apm,xgene-mdio-rgmii",
+		.data = (void *)XGENE_MDIO_RGMII
+	},
+	{
+		.compatible = "apm,xgene-mdio-xfi",
+		.data = (void *)XGENE_MDIO_XFI
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, xgene_mdio_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_mdio_acpi_match[] = {
+	{ "APMC0D65", XGENE_MDIO_RGMII },
+	{ "APMC0D66", XGENE_MDIO_XFI },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match);
+#endif
+
+static struct platform_driver xgene_mdio_driver = {
+	.driver = {
+		.name = "xgene-mdio",
+		.of_match_table = of_match_ptr(xgene_mdio_of_match),
+		.acpi_match_table = ACPI_PTR(xgene_mdio_acpi_match),
+	},
+	.probe = xgene_mdio_probe,
+	.remove = xgene_mdio_remove,
+};
+
+module_platform_driver(xgene_mdio_driver);
+
+MODULE_DESCRIPTION("APM X-Gene SoC MDIO driver");
+MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/phy/mdio-xgene.h
+++ linux-4.4.0/drivers/net/phy/mdio-xgene.h
@@ -0,0 +1,143 @@
+/* Applied Micro X-Gene SoC MDIO Driver
+ *
+ * Copyright (c) 2016, Applied Micro Circuits Corporation
+ * Author: Iyappan Subramanian <isubramanian@apm.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MDIO_XGENE_H__
+#define __MDIO_XGENE_H__
+
+#define BLOCK_XG_MDIO_CSR_OFFSET	0x5000
+#define BLOCK_DIAG_CSR_OFFSET		0xd000
+#define XGENET_CONFIG_REG_ADDR		0x20
+
+#define MAC_ADDR_REG_OFFSET		0x00
+#define MAC_COMMAND_REG_OFFSET		0x04
+#define MAC_WRITE_REG_OFFSET		0x08
+#define MAC_READ_REG_OFFSET		0x0c
+#define MAC_COMMAND_DONE_REG_OFFSET	0x10
+
+#define CLKEN_OFFSET			0x08
+#define SRST_OFFSET			0x00
+
+#define MENET_CFG_MEM_RAM_SHUTDOWN_ADDR	0x70
+#define MENET_BLOCK_MEM_RDY_ADDR	0x74
+
+#define MAC_CONFIG_1_ADDR		0x00
+#define MII_MGMT_COMMAND_ADDR		0x24
+#define MII_MGMT_ADDRESS_ADDR		0x28
+#define MII_MGMT_CONTROL_ADDR		0x2c
+#define MII_MGMT_STATUS_ADDR		0x30
+#define MII_MGMT_INDICATORS_ADDR	0x34
+#define SOFT_RESET			BIT(31)
+
+#define MII_MGMT_CONFIG_ADDR            0x20
+#define MII_MGMT_COMMAND_ADDR           0x24
+#define MII_MGMT_ADDRESS_ADDR           0x28
+#define MII_MGMT_CONTROL_ADDR           0x2c
+#define MII_MGMT_STATUS_ADDR            0x30
+#define MII_MGMT_INDICATORS_ADDR        0x34
+
+#define MIIM_COMMAND_ADDR               0x20
+#define MIIM_FIELD_ADDR                 0x24
+#define MIIM_CONFIGURATION_ADDR         0x28
+#define MIIM_LINKFAILVECTOR_ADDR        0x2c
+#define MIIM_INDICATOR_ADDR             0x30
+#define MIIMRD_FIELD_ADDR               0x34
+
+#define MDIO_CSR_OFFSET			0x5000
+
+#define REG_ADDR_POS			0
+#define REG_ADDR_LEN			5
+#define PHY_ADDR_POS			8
+#define PHY_ADDR_LEN			5
+
+#define HSTMIIMWRDAT_POS		0
+#define HSTMIIMWRDAT_LEN		16
+#define HSTPHYADX_POS			23
+#define HSTPHYADX_LEN			5
+#define HSTREGADX_POS			18
+#define HSTREGADX_LEN			5
+#define HSTLDCMD			BIT(3)
+#define HSTMIIMCMD_POS			0
+#define HSTMIIMCMD_LEN			3
+
+#define BUSY_MASK			BIT(0)
+#define READ_CYCLE_MASK			BIT(0)
+
+enum xgene_enet_cmd {
+	XGENE_ENET_WR_CMD = BIT(31),
+	XGENE_ENET_RD_CMD = BIT(30)
+};
+
+enum {
+	MIIM_CMD_IDLE,
+	MIIM_CMD_LEGACY_WRITE,
+	MIIM_CMD_LEGACY_READ,
+};
+
+enum xgene_mdio_id {
+	XGENE_MDIO_RGMII = 1,
+	XGENE_MDIO_XFI
+};
+
+struct xgene_mdio_pdata {
+	struct clk *clk;
+	struct device *dev;
+	void __iomem *mac_csr_addr;
+	void __iomem *diag_csr_addr;
+	void __iomem *mdio_csr_addr;
+	struct mii_bus *mdio_bus;
+	int mdio_id;
+};
+
+/* Set the specified value into a bit-field defined by its starting position
+ * and length within a single u64.
+ */
+static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val)
+{
+	return (val & ((1ULL << len) - 1)) << pos;
+}
+
+#define SET_VAL(field, val) \
+		xgene_enet_set_field_value(field ## _POS, field ## _LEN, val)
+
+#define SET_BIT(field) \
+		xgene_enet_set_field_value(field ## _POS, 1, 1)
+
+/* Get the value from a bit-field defined by its starting position
+ * and length within the specified u64.
+ */
+static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src)
+{
+	return (src >> pos) & ((1ULL << len) - 1);
+}
+
+#define GET_VAL(field, src) \
+		xgene_enet_get_field_value(field ## _POS, field ## _LEN, src)
+
+#define GET_BIT(field, src) \
+		xgene_enet_get_field_value(field ## _POS, 1, src)
+
+static const struct of_device_id xgene_mdio_of_match[];
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_mdio_acpi_match[];
+#endif
+int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg);
+int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data);
+struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr);
+
+#endif  /* __MDIO_XGENE_H__ */
--- linux-4.4.0.orig/drivers/net/phy/mdio_bus.c
+++ linux-4.4.0/drivers/net/phy/mdio_bus.c
@@ -267,7 +267,6 @@
 	err = device_register(&bus->dev);
 	if (err) {
 		pr_err("mii_bus %s failed to register\n", bus->id);
-		put_device(&bus->dev);
 		return -EINVAL;
 	}
 
--- linux-4.4.0.orig/drivers/net/phy/micrel.c
+++ linux-4.4.0/drivers/net/phy/micrel.c
@@ -28,6 +28,7 @@
 #include <linux/micrel_phy.h>
 #include <linux/of.h>
 #include <linux/clk.h>
+#include <uapi/linux/mdio.h>
 
 /* Operation Mode Strap Override */
 #define MII_KSZPHY_OMSO				0x16
@@ -287,6 +288,17 @@
 	return 0;
 }
 
+static int ksz8061_config_init(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_DEVID1, 0xB61A);
+	if (ret)
+		return ret;
+
+	return kszphy_config_init(phydev);
+}
+
 static int ksz9021_load_values_from_of(struct phy_device *phydev,
 				       const struct device_node *of_node,
 				       u16 reg,
@@ -470,9 +482,17 @@
 		"txd2-skew-ps", "txd3-skew-ps"
 	};
 	static const char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
+	const struct device *dev_walker;
 
-	if (!of_node && dev->parent->of_node)
-		of_node = dev->parent->of_node;
+	/* The Micrel driver has a deprecated option to place phy OF
+	 * properties in the MAC node. Walk up the tree of devices to
+	 * find a device with an OF node.
+	 */
+	dev_walker = &phydev->dev;
+	do {
+		of_node = dev_walker->of_node;
+		dev_walker = dev_walker->parent;
+	} while (!of_node && dev_walker);
 
 	if (of_node) {
 		ksz9031_of_load_skew_values(phydev, of_node,
@@ -539,6 +559,9 @@
 	if ((regval & 0xFF) == 0xFF) {
 		phy_init_hw(phydev);
 		phydev->link = 0;
+		if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev))
+			phydev->drv->config_intr(phydev);
+		return genphy_config_aneg(phydev);
 	}
 
 	return 0;
@@ -569,6 +592,21 @@
 {
 }
 
+static int kszphy_resume(struct phy_device *phydev)
+{
+	int value;
+
+	mutex_lock(&phydev->lock);
+
+	value = phy_read(phydev, MII_BMCR);
+	phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+	kszphy_config_intr(phydev);
+	mutex_unlock(&phydev->lock);
+
+	return 0;
+}
+
 static int kszphy_probe(struct phy_device *phydev)
 {
 	const struct kszphy_type *type = phydev->drv->driver_data;
@@ -760,7 +798,7 @@
 	.ack_interrupt	= kszphy_ack_interrupt,
 	.config_intr	= kszphy_config_intr,
 	.suspend	= genphy_suspend,
-	.resume		= genphy_resume,
+	.resume		= kszphy_resume,
 	.driver		= { .owner = THIS_MODULE,},
 }, {
 	.phy_id		= PHY_ID_KSZ8061,
@@ -768,7 +806,7 @@
 	.phy_id_mask	= 0x00fffff0,
 	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
-	.config_init	= kszphy_config_init,
+	.config_init	= ksz8061_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
 	.ack_interrupt	= kszphy_ack_interrupt,
--- linux-4.4.0.orig/drivers/net/phy/national.c
+++ linux-4.4.0/drivers/net/phy/national.c
@@ -110,14 +110,17 @@
 
 static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)
 {
+	u16 lb_dis = BIT(1);
+
 	if (disable)
-		ns_exp_write(phydev, 0x1c0, ns_exp_read(phydev, 0x1c0) | 1);
+		ns_exp_write(phydev, 0x1c0,
+			     ns_exp_read(phydev, 0x1c0) | lb_dis);
 	else
 		ns_exp_write(phydev, 0x1c0,
-			     ns_exp_read(phydev, 0x1c0) & 0xfffe);
+			     ns_exp_read(phydev, 0x1c0) & ~lb_dis);
 
 	pr_debug("10BASE-T HDX loopback %s\n",
-		 (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on");
+		 (ns_exp_read(phydev, 0x1c0) & lb_dis) ? "off" : "on");
 }
 
 static int ns_config_init(struct phy_device *phydev)
--- linux-4.4.0.orig/drivers/net/phy/phy.c
+++ linux-4.4.0/drivers/net/phy/phy.c
@@ -148,6 +148,12 @@
 	if (phydev->drv->aneg_done)
 		return phydev->drv->aneg_done(phydev);
 
+	/* Avoid genphy_aneg_done() if the Clause 45 PHY does not
+	 * implement Clause 22 registers
+	 */
+	if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)))
+		return -EINVAL;
+
 	return genphy_aneg_done(phydev);
 }
 
@@ -538,7 +544,7 @@
 	cancel_delayed_work_sync(&phydev->state_queue);
 
 	mutex_lock(&phydev->lock);
-	if (phydev->state > PHY_UP)
+	if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)
 		phydev->state = PHY_UP;
 	mutex_unlock(&phydev->lock);
 }
@@ -640,8 +646,10 @@
 int phy_start_interrupts(struct phy_device *phydev)
 {
 	atomic_set(&phydev->irq_disable, 0);
-	if (request_irq(phydev->irq, phy_interrupt, 0, "phy_interrupt",
-			phydev) < 0) {
+	if (request_irq(phydev->irq, phy_interrupt,
+				IRQF_SHARED,
+				"phy_interrupt",
+				phydev) < 0) {
 		pr_warn("%s: Can't get IRQ %d (PHY)\n",
 			phydev->bus->name, phydev->irq);
 		phydev->irq = PHY_POLL;
@@ -691,25 +699,29 @@
 	struct phy_device *phydev =
 		container_of(work, struct phy_device, phy_queue);
 
-	if (phydev->drv->did_interrupt &&
-	    !phydev->drv->did_interrupt(phydev))
-		goto ignore;
+	if (phy_interrupt_is_valid(phydev)) {
+		if (phydev->drv->did_interrupt &&
+		    !phydev->drv->did_interrupt(phydev))
+			goto ignore;
 
-	if (phy_disable_interrupts(phydev))
-		goto phy_err;
+		if (phy_disable_interrupts(phydev))
+			goto phy_err;
+	}
 
 	mutex_lock(&phydev->lock);
 	if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
 		phydev->state = PHY_CHANGELINK;
 	mutex_unlock(&phydev->lock);
 
-	atomic_dec(&phydev->irq_disable);
-	enable_irq(phydev->irq);
+	if (phy_interrupt_is_valid(phydev)) {
+		atomic_dec(&phydev->irq_disable);
+		enable_irq(phydev->irq);
 
-	/* Reenable interrupts */
-	if (PHY_HALTED != phydev->state &&
-	    phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED))
-		goto irq_enable_err;
+		/* Reenable interrupts */
+		if (PHY_HALTED != phydev->state &&
+		    phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED))
+			goto irq_enable_err;
+	}
 
 	/* reschedule state queue work to run as soon as possible */
 	cancel_delayed_work_sync(&phydev->state_queue);
@@ -785,9 +797,11 @@
 		break;
 	case PHY_HALTED:
 		/* make sure interrupts are re-enabled for the PHY */
-		err = phy_enable_interrupts(phydev);
-		if (err < 0)
-			break;
+		if (phy_interrupt_is_valid(phydev)) {
+			err = phy_enable_interrupts(phydev);
+			if (err < 0)
+				break;
+		}
 
 		phydev->state = PHY_RESUMING;
 		do_resume = true;
@@ -916,6 +930,15 @@
 			if (old_link != phydev->link)
 				phydev->state = PHY_CHANGELINK;
 		}
+		/*
+		 * Failsafe: check that nobody set phydev->link=0 between two
+		 * poll cycles, otherwise we won't leave RUNNING state as long
+		 * as link remains down.
+		 */
+		if (!phydev->link && phydev->state == PHY_RUNNING) {
+			phydev->state = PHY_CHANGELINK;
+			dev_err(&phydev->dev, "no link in PHY_RUNNING\n");
+		}
 		break;
 	case PHY_CHANGELINK:
 		err = phy_read_status(phydev);
@@ -1004,9 +1027,10 @@
 
 void phy_mac_interrupt(struct phy_device *phydev, int new_link)
 {
-	cancel_work_sync(&phydev->phy_queue);
 	phydev->link = new_link;
-	schedule_work(&phydev->phy_queue);
+
+	/* Trigger a state machine change */
+	queue_work(system_power_efficient_wq, &phydev->phy_queue);
 }
 EXPORT_SYMBOL(phy_mac_interrupt);
 
--- linux-4.4.0.orig/drivers/net/phy/phy_device.c
+++ linux-4.4.0/drivers/net/phy/phy_device.c
@@ -161,8 +161,8 @@
 
 	dev->dev.release = phy_device_release;
 
-	dev->speed = 0;
-	dev->duplex = -1;
+	dev->speed = SPEED_UNKNOWN;
+	dev->duplex = DUPLEX_UNKNOWN;
 	dev->pause = 0;
 	dev->asym_pause = 0;
 	dev->link = 1;
@@ -472,6 +472,9 @@
 {
 	int rc;
 
+	if (!dev)
+		return -EINVAL;
+
 	rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
 	if (rc)
 		return rc;
@@ -519,6 +522,7 @@
 	phydev = to_phy_device(d);
 
 	rc = phy_connect_direct(dev, phydev, handler, interface);
+	put_device(d);
 	if (rc)
 		return ERR_PTR(rc);
 
@@ -704,6 +708,9 @@
 	struct device *d;
 	int rc;
 
+	if (!dev)
+		return ERR_PTR(-EINVAL);
+
 	/* Search the list of PHY devices on the mdio bus for the
 	 * PHY with the requested name
 	 */
@@ -715,6 +722,7 @@
 	phydev = to_phy_device(d);
 
 	rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
+	put_device(d);
 	if (rc)
 		return ERR_PTR(rc);
 
@@ -1265,23 +1273,17 @@
 
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
-	/* The default values for phydev->supported are provided by the PHY
-	 * driver "features" member, we want to reset to sane defaults first
-	 * before supporting higher speeds.
-	 */
-	phydev->supported &= PHY_DEFAULT_FEATURES;
-
 	switch (max_speed) {
-	default:
-		return -ENOTSUPP;
-	case SPEED_1000:
-		phydev->supported |= PHY_1000BT_FEATURES;
+	case SPEED_10:
+		phydev->supported &= ~PHY_100BT_FEATURES;
 		/* fall through */
 	case SPEED_100:
-		phydev->supported |= PHY_100BT_FEATURES;
-		/* fall through */
-	case SPEED_10:
-		phydev->supported |= PHY_10BT_FEATURES;
+		phydev->supported &= ~PHY_1000BT_FEATURES;
+		break;
+	case SPEED_1000:
+		break;
+	default:
+		return -ENOTSUPP;
 	}
 
 	return 0;
@@ -1368,6 +1370,8 @@
 {
 	struct phy_device *phydev = to_phy_device(dev);
 
+	cancel_delayed_work_sync(&phydev->state_queue);
+
 	mutex_lock(&phydev->lock);
 	phydev->state = PHY_DOWN;
 	mutex_unlock(&phydev->lock);
@@ -1442,7 +1446,7 @@
 	.phy_id		= 0xffffffff,
 	.phy_id_mask	= 0xffffffff,
 	.name		= "Generic PHY",
-	.soft_reset	= genphy_soft_reset,
+	.soft_reset	= genphy_no_soft_reset,
 	.config_init	= genphy_config_init,
 	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
 			  SUPPORTED_AUI | SUPPORTED_FIBRE |
--- linux-4.4.0.orig/drivers/net/phy/spi_ks8995.c
+++ linux-4.4.0/drivers/net/phy/spi_ks8995.c
@@ -310,6 +310,7 @@
 	if (err)
 		return err;
 
+	sysfs_attr_init(&ks->regs_attr.attr);
 	err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr);
 	if (err) {
 		dev_err(&spi->dev, "unable to create sysfs file, err=%d\n",
--- linux-4.4.0.orig/drivers/net/phy/vitesse.c
+++ linux-4.4.0/drivers/net/phy/vitesse.c
@@ -75,7 +75,7 @@
 MODULE_AUTHOR("Kriston Carson");
 MODULE_LICENSE("GPL");
 
-static int vsc824x_add_skew(struct phy_device *phydev)
+int vsc824x_add_skew(struct phy_device *phydev)
 {
 	int err;
 	int extcon;
@@ -95,6 +95,7 @@
 
 	return err;
 }
+EXPORT_SYMBOL(vsc824x_add_skew);
 
 static int vsc824x_config_init(struct phy_device *phydev)
 {
--- linux-4.4.0.orig/drivers/net/ppp/ppp_async.c
+++ linux-4.4.0/drivers/net/ppp/ppp_async.c
@@ -474,6 +474,10 @@
 	case PPPIOCSMRU:
 		if (get_user(val, p))
 			break;
+		if (val > U16_MAX) {
+			err = -EINVAL;
+			break;
+		}
 		if (val < PPP_MRU)
 			val = PPP_MRU;
 		ap->mru = val;
@@ -878,15 +882,15 @@
 				skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
 				if (!skb)
 					goto nomem;
- 				ap->rpkt = skb;
- 			}
- 			if (skb->len == 0) {
- 				/* Try to get the payload 4-byte aligned.
- 				 * This should match the
- 				 * PPP_ALLSTATIONS/PPP_UI/compressed tests in
- 				 * process_input_packet, but we do not have
- 				 * enough chars here to test buf[1] and buf[2].
- 				 */
+				ap->rpkt = skb;
+			}
+			if (skb->len == 0) {
+				/* Try to get the payload 4-byte aligned.
+				 * This should match the
+				 * PPP_ALLSTATIONS/PPP_UI/compressed tests in
+				 * process_input_packet, but we do not have
+				 * enough chars here to test buf[1] and buf[2].
+				 */
 				if (buf[0] != PPP_ALLSTATIONS)
 					skb_reserve(skb, 2 + (buf[0] & 1));
 			}
--- linux-4.4.0.orig/drivers/net/ppp/ppp_deflate.c
+++ linux-4.4.0/drivers/net/ppp/ppp_deflate.c
@@ -610,12 +610,20 @@
 
 static int __init deflate_init(void)
 {
-        int answer = ppp_register_compressor(&ppp_deflate);
-        if (answer == 0)
-                printk(KERN_INFO
-		       "PPP Deflate Compression module registered\n");
-	ppp_register_compressor(&ppp_deflate_draft);
-        return answer;
+	int rc;
+
+	rc = ppp_register_compressor(&ppp_deflate);
+	if (rc)
+		return rc;
+
+	rc = ppp_register_compressor(&ppp_deflate_draft);
+	if (rc) {
+		ppp_unregister_compressor(&ppp_deflate);
+		return rc;
+	}
+
+	pr_info("PPP Deflate Compression module registered\n");
+	return 0;
 }
 
 static void __exit deflate_cleanup(void)
--- linux-4.4.0.orig/drivers/net/ppp/ppp_generic.c
+++ linux-4.4.0/drivers/net/ppp/ppp_generic.c
@@ -567,7 +567,7 @@
 
 static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct ppp_file *pf = file->private_data;
+	struct ppp_file *pf;
 	struct ppp *ppp;
 	int err = -EFAULT, val, val2, i;
 	struct ppp_idle idle;
@@ -577,9 +577,14 @@
 	void __user *argp = (void __user *)arg;
 	int __user *p = argp;
 
-	if (!pf)
-		return ppp_unattached_ioctl(current->nsproxy->net_ns,
-					pf, file, cmd, arg);
+	mutex_lock(&ppp_mutex);
+
+	pf = file->private_data;
+	if (!pf) {
+		err = ppp_unattached_ioctl(current->nsproxy->net_ns,
+					   pf, file, cmd, arg);
+		goto out;
+	}
 
 	if (cmd == PPPIOCDETACH) {
 		/*
@@ -594,7 +599,6 @@
 		 * this fd and reopening /dev/ppp.
 		 */
 		err = -EINVAL;
-		mutex_lock(&ppp_mutex);
 		if (pf->kind == INTERFACE) {
 			ppp = PF_TO_PPP(pf);
 			rtnl_lock();
@@ -608,15 +612,13 @@
 		} else
 			pr_warn("PPPIOCDETACH file->f_count=%ld\n",
 				atomic_long_read(&file->f_count));
-		mutex_unlock(&ppp_mutex);
-		return err;
+		goto out;
 	}
 
 	if (pf->kind == CHANNEL) {
 		struct channel *pch;
 		struct ppp_channel *chan;
 
-		mutex_lock(&ppp_mutex);
 		pch = PF_TO_CHANNEL(pf);
 
 		switch (cmd) {
@@ -638,17 +640,16 @@
 				err = chan->ops->ioctl(chan, cmd, arg);
 			up_read(&pch->chan_sem);
 		}
-		mutex_unlock(&ppp_mutex);
-		return err;
+		goto out;
 	}
 
 	if (pf->kind != INTERFACE) {
 		/* can't happen */
 		pr_err("PPP: not interface or channel??\n");
-		return -EINVAL;
+		err = -EINVAL;
+		goto out;
 	}
 
-	mutex_lock(&ppp_mutex);
 	ppp = PF_TO_PPP(pf);
 	switch (cmd) {
 	case PPPIOCSMRU:
@@ -823,7 +824,10 @@
 	default:
 		err = -ENOTTY;
 	}
+
+out:
 	mutex_unlock(&ppp_mutex);
+
 	return err;
 }
 
@@ -836,7 +840,6 @@
 	struct ppp_net *pn;
 	int __user *p = (int __user *)arg;
 
-	mutex_lock(&ppp_mutex);
 	switch (cmd) {
 	case PPPIOCNEWUNIT:
 		/* Create a new ppp unit */
@@ -886,7 +889,7 @@
 	default:
 		err = -ENOTTY;
 	}
-	mutex_unlock(&ppp_mutex);
+
 	return err;
 }
 
@@ -939,6 +942,7 @@
 	unregister_netdevice_many(&list);
 	rtnl_unlock();
 
+	mutex_destroy(&pn->all_ppp_mutex);
 	idr_destroy(&pn->units_idr);
 }
 
@@ -1107,7 +1111,17 @@
 static struct lock_class_key ppp_tx_busylock;
 static int ppp_dev_init(struct net_device *dev)
 {
+	struct ppp *ppp;
+
 	dev->qdisc_tx_busylock = &ppp_tx_busylock;
+
+	ppp = netdev_priv(dev);
+	/* Let the netdevice take a reference on the ppp file. This ensures
+	 * that ppp_destroy_interface() won't run before the device gets
+	 * unregistered.
+	 */
+	atomic_inc(&ppp->file.refcnt);
+
 	return 0;
 }
 
@@ -1130,6 +1144,15 @@
 	wake_up_interruptible(&ppp->file.rwait);
 }
 
+static void ppp_dev_priv_destructor(struct net_device *dev)
+{
+	struct ppp *ppp;
+
+	ppp = netdev_priv(dev);
+	if (atomic_dec_and_test(&ppp->file.refcnt))
+		ppp_destroy_interface(ppp);
+}
+
 static const struct net_device_ops ppp_netdev_ops = {
 	.ndo_init	 = ppp_dev_init,
 	.ndo_uninit      = ppp_dev_uninit,
@@ -1147,6 +1170,7 @@
 	dev->tx_queue_len = 3;
 	dev->type = ARPHRD_PPP;
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+	dev->destructor = ppp_dev_priv_destructor;
 	netif_keep_dst(dev);
 }
 
@@ -2290,7 +2314,7 @@
 
 	pch->ppp = NULL;
 	pch->chan = chan;
-	pch->chan_net = net;
+	pch->chan_net = get_net(net);
 	chan->ppp = pch;
 	init_ppp_file(&pch->file, CHANNEL);
 	pch->file.hdrlen = chan->hdrlen;
@@ -2803,6 +2827,7 @@
 
 out2:
 	mutex_unlock(&pn->all_ppp_mutex);
+	rtnl_unlock();
 	free_netdev(dev);
 out1:
 	*retp = ret;
@@ -2927,6 +2952,15 @@
 		goto outl;
 
 	ppp_lock(ppp);
+	spin_lock_bh(&pch->downl);
+	if (!pch->chan) {
+		/* Don't connect unregistered channels */
+		spin_unlock_bh(&pch->downl);
+		ppp_unlock(ppp);
+		ret = -ENOTCONN;
+		goto outl;
+	}
+	spin_unlock_bh(&pch->downl);
 	if (pch->file.hdrlen > ppp->file.hdrlen)
 		ppp->file.hdrlen = pch->file.hdrlen;
 	hdrlen = pch->file.hdrlen + 2;	/* for protocol bytes */
@@ -2978,6 +3012,9 @@
  */
 static void ppp_destroy_channel(struct channel *pch)
 {
+	put_net(pch->chan_net);
+	pch->chan_net = NULL;
+
 	atomic_dec(&channel_count);
 
 	if (!pch->file.dead) {
--- linux-4.4.0.orig/drivers/net/ppp/ppp_mppe.c
+++ linux-4.4.0/drivers/net/ppp/ppp_mppe.c
@@ -62,6 +62,7 @@
 MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
+MODULE_SOFTDEP("pre: arc4");
 MODULE_VERSION("1.0.2");
 
 static unsigned int
--- linux-4.4.0.orig/drivers/net/ppp/pppoe.c
+++ linux-4.4.0/drivers/net/ppp/pppoe.c
@@ -395,6 +395,8 @@
 
 		if (!__pppoe_xmit(sk_pppox(relay_po), skb))
 			goto abort_put;
+
+		sock_put(sk_pppox(relay_po));
 	} else {
 		if (sock_queue_rcv_skb(sk, skb))
 			goto abort_kfree;
@@ -440,6 +442,7 @@
 	if (pskb_trim_rcsum(skb, len))
 		goto drop;
 
+	ph = pppoe_hdr(skb);
 	pn = pppoe_pernet(dev_net(dev));
 
 	/* Note that get_item does a sock_hold(), so sk_pppox(po)
@@ -491,6 +494,9 @@
 	if (!skb)
 		goto out;
 
+	if (skb->pkt_type != PACKET_HOST)
+		goto abort;
+
 	if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
 		goto abort;
 
@@ -636,6 +642,10 @@
 	lock_sock(sk);
 
 	error = -EINVAL;
+
+	if (sockaddr_len != sizeof(struct sockaddr_pppox))
+		goto end;
+
 	if (sp->sa_protocol != PX_PROTO_OE)
 		goto end;
 
@@ -858,6 +868,7 @@
 	struct pppoe_hdr *ph;
 	struct net_device *dev;
 	char *start;
+	int hlen;
 
 	lock_sock(sk);
 	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) {
@@ -876,16 +887,16 @@
 	if (total_len > (dev->mtu + dev->hard_header_len))
 		goto end;
 
-
-	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
-			   0, GFP_KERNEL);
+	hlen = LL_RESERVED_SPACE(dev);
+	skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len +
+			   dev->needed_tailroom, 0, GFP_KERNEL);
 	if (!skb) {
 		error = -ENOMEM;
 		goto end;
 	}
 
 	/* Reserve space for headers. */
-	skb_reserve(skb, dev->hard_header_len);
+	skb_reserve(skb, hlen);
 	skb_reset_network_header(skb);
 
 	skb->dev = dev;
@@ -946,7 +957,7 @@
 	/* Copy the data if there is no space for the header or if it's
 	 * read-only.
 	 */
-	if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
+	if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph)))
 		goto abort;
 
 	__skb_push(skb, sizeof(*ph));
@@ -1144,6 +1155,9 @@
 	.recvmsg	= pppoe_recvmsg,
 	.mmap		= sock_no_mmap,
 	.ioctl		= pppox_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= pppox_compat_ioctl,
+#endif
 };
 
 static const struct pppox_proto pppoe_proto = {
--- linux-4.4.0.orig/drivers/net/ppp/pppox.c
+++ linux-4.4.0/drivers/net/ppp/pppox.c
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/compat.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/net.h>
@@ -103,6 +104,18 @@
 
 EXPORT_SYMBOL(pppox_ioctl);
 
+#ifdef CONFIG_COMPAT
+int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	if (cmd == PPPOEIOCSFWD32)
+		cmd = PPPOEIOCSFWD;
+
+	return pppox_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
+}
+
+EXPORT_SYMBOL(pppox_compat_ioctl);
+#endif
+
 static int pppox_create(struct net *net, struct socket *sock, int protocol,
 			int kern)
 {
--- linux-4.4.0.orig/drivers/net/ppp/pptp.c
+++ linux-4.4.0/drivers/net/ppp/pptp.c
@@ -129,24 +129,27 @@
 	return i < MAX_CALLID;
 }
 
-static int add_chan(struct pppox_sock *sock)
+static int add_chan(struct pppox_sock *sock,
+		    struct pptp_addr *sa)
 {
 	static int call_id;
 
 	spin_lock(&chan_lock);
-	if (!sock->proto.pptp.src_addr.call_id)	{
+	if (!sa->call_id)	{
 		call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1);
 		if (call_id == MAX_CALLID) {
 			call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1);
 			if (call_id == MAX_CALLID)
 				goto out_err;
 		}
-		sock->proto.pptp.src_addr.call_id = call_id;
-	} else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap))
+		sa->call_id = call_id;
+	} else if (test_bit(sa->call_id, callid_bitmap)) {
 		goto out_err;
+	}
 
-	set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
-	rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock);
+	sock->proto.pptp.src_addr = *sa;
+	set_bit(sa->call_id, callid_bitmap);
+	rcu_assign_pointer(callid_sock[sa->call_id], sock);
 	spin_unlock(&chan_lock);
 
 	return 0;
@@ -416,7 +419,6 @@
 	struct sock *sk = sock->sk;
 	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
 	struct pppox_sock *po = pppox_sk(sk);
-	struct pptp_opt *opt = &po->proto.pptp;
 	int error = 0;
 
 	if (sockaddr_len < sizeof(struct sockaddr_pppox))
@@ -424,10 +426,22 @@
 
 	lock_sock(sk);
 
-	opt->src_addr = sp->sa_addr.pptp;
-	if (add_chan(po))
+	if (sk->sk_state & PPPOX_DEAD) {
+		error = -EALREADY;
+		goto out;
+	}
+
+	if (sk->sk_state & PPPOX_BOUND) {
 		error = -EBUSY;
+		goto out;
+	}
+
+	if (add_chan(po, &sp->sa_addr.pptp))
+		error = -EBUSY;
+	else
+		sk->sk_state |= PPPOX_BOUND;
 
+out:
 	release_sock(sk);
 	return error;
 }
@@ -487,7 +501,6 @@
 	po->chan.mtu = dst_mtu(&rt->dst);
 	if (!po->chan.mtu)
 		po->chan.mtu = PPP_MRU;
-	ip_rt_put(rt);
 	po->chan.mtu -= PPTP_HEADER_OVERHEAD;
 
 	po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
@@ -498,7 +511,7 @@
 	}
 
 	opt->dst_addr = sp->sa_addr.pptp;
-	sk->sk_state = PPPOX_CONNECTED;
+	sk->sk_state |= PPPOX_CONNECTED;
 
  end:
 	release_sock(sk);
@@ -564,6 +577,7 @@
 		pppox_unbind_sock(sk);
 	}
 	skb_queue_purge(&sk->sk_receive_queue);
+	dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));
 }
 
 static int pptp_create(struct net *net, struct socket *sock, int kern)
@@ -660,6 +674,9 @@
 	.recvmsg    = sock_no_recvmsg,
 	.mmap       = sock_no_mmap,
 	.ioctl      = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = pppox_compat_ioctl,
+#endif
 };
 
 static const struct pppox_proto pppox_pptp_proto = {
--- linux-4.4.0.orig/drivers/net/rionet.c
+++ linux-4.4.0/drivers/net/rionet.c
@@ -215,9 +215,9 @@
 			 * it just report sending a packet to the target
 			 * (without actual packet transfer).
 			 */
-			dev_kfree_skb_any(skb);
 			ndev->stats.tx_packets++;
 			ndev->stats.tx_bytes += skb->len;
+			dev_kfree_skb_any(skb);
 		}
 	}
 
@@ -280,7 +280,7 @@
 	struct net_device *ndev = dev_id;
 	struct rionet_private *rnet = netdev_priv(ndev);
 
-	spin_lock(&rnet->lock);
+	spin_lock(&rnet->tx_lock);
 
 	if (netif_msg_intr(rnet))
 		printk(KERN_INFO
@@ -299,7 +299,7 @@
 	if (rnet->tx_cnt < RIONET_TX_RING_SIZE)
 		netif_wake_queue(ndev);
 
-	spin_unlock(&rnet->lock);
+	spin_unlock(&rnet->tx_lock);
 }
 
 static int rionet_open(struct net_device *ndev)
--- linux-4.4.0.orig/drivers/net/slip/slhc.c
+++ linux-4.4.0/drivers/net/slip/slhc.c
@@ -153,7 +153,7 @@
 void
 slhc_free(struct slcompress *comp)
 {
-	if ( comp == NULLSLCOMPR )
+	if ( IS_ERR_OR_NULL(comp) )
 		return;
 
 	if ( comp->tstate != NULLSLSTATE )
@@ -232,7 +232,7 @@
 	register struct cstate *cs = lcs->next;
 	register unsigned long deltaS, deltaA;
 	register short changes = 0;
-	int hlen;
+	int nlen, hlen;
 	unsigned char new_seq[16];
 	register unsigned char *cp = new_seq;
 	struct iphdr *ip;
@@ -248,6 +248,8 @@
 		return isize;
 
 	ip = (struct iphdr *) icp;
+	if (ip->version != 4 || ip->ihl < 5)
+		return isize;
 
 	/* Bail if this packet isn't TCP, or is an IP fragment */
 	if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
@@ -258,10 +260,14 @@
 			comp->sls_o_tcp++;
 		return isize;
 	}
-	/* Extract TCP header */
+	nlen = ip->ihl * 4;
+	if (isize < nlen + sizeof(*th))
+		return isize;
 
-	th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
-	hlen = ip->ihl*4 + th->doff*4;
+	th = (struct tcphdr *)(icp + nlen);
+	if (th->doff < sizeof(struct tcphdr) / 4)
+		return isize;
+	hlen = nlen + th->doff * 4;
 
 	/*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
 	 *  some other control bit is set). Also uncompressible if
@@ -509,6 +515,10 @@
 		if(x < 0 || x > comp->rslot_limit)
 			goto bad;
 
+		/* Check if the cstate is initialized */
+		if (!comp->rstate[x].initialized)
+			goto bad;
+
 		comp->flags &=~ SLF_TOSS;
 		comp->recv_current = x;
 	} else {
@@ -673,6 +683,7 @@
 	if (cs->cs_tcp.doff > 5)
 	  memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
 	cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
+	cs->initialized = true;
 	/* Put headers back on packet
 	 * Neither header checksum is recalculated
 	 */
--- linux-4.4.0.orig/drivers/net/slip/slip.c
+++ linux-4.4.0/drivers/net/slip/slip.c
@@ -452,9 +452,16 @@
  */
 static void slip_write_wakeup(struct tty_struct *tty)
 {
-	struct slip *sl = tty->disc_data;
+	struct slip *sl;
+
+	rcu_read_lock();
+	sl = rcu_dereference(tty->disc_data);
+	if (!sl)
+		goto out;
 
 	schedule_work(&sl->tx_work);
+out:
+	rcu_read_unlock();
 }
 
 static void sl_tx_timeout(struct net_device *dev)
@@ -464,7 +471,7 @@
 	spin_lock(&sl->lock);
 
 	if (netif_queue_stopped(dev)) {
-		if (!netif_running(dev))
+		if (!netif_running(dev) || !sl->tty)
 			goto out;
 
 		/* May be we must check transmitter timeout here ?
@@ -860,6 +867,10 @@
 	sl->tty = NULL;
 	tty->disc_data = NULL;
 	clear_bit(SLF_INUSE, &sl->flags);
+	/* do not call free_netdev before rtnl_unlock */
+	rtnl_unlock();
+	sl_free_netdev(sl->dev);
+	return err;
 
 err_exit:
 	rtnl_unlock();
@@ -885,10 +896,11 @@
 		return;
 
 	spin_lock_bh(&sl->lock);
-	tty->disc_data = NULL;
+	rcu_assign_pointer(tty->disc_data, NULL);
 	sl->tty = NULL;
 	spin_unlock_bh(&sl->lock);
 
+	synchronize_rcu();
 	flush_work(&sl->tx_work);
 
 	/* VSV = very important to remove timers */
--- linux-4.4.0.orig/drivers/net/team/team.c
+++ linux-4.4.0/drivers/net/team/team.c
@@ -285,7 +285,7 @@
 	for (i--; i >= 0; i--)
 		__team_option_inst_del_option(team, dst_opts[i]);
 
-	i = option_count - 1;
+	i = option_count;
 alloc_rollback:
 	for (i--; i >= 0; i--)
 		kfree(dst_opts[i]);
@@ -466,6 +466,9 @@
 	struct team_mode_item *mitem;
 	const struct team_mode *mode = NULL;
 
+	if (!try_module_get(THIS_MODULE))
+		return NULL;
+
 	spin_lock(&mode_list_lock);
 	mitem = __find_mode(kind);
 	if (!mitem) {
@@ -481,6 +484,7 @@
 	}
 
 	spin_unlock(&mode_list_lock);
+	module_put(THIS_MODULE);
 	return mode;
 }
 
@@ -969,10 +973,11 @@
 			    NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
 			    NETIF_F_HIGHDMA | NETIF_F_LRO)
 
-static void __team_compute_features(struct team *team)
+static void ___team_compute_features(struct team *team)
 {
 	struct team_port *port;
-	u32 vlan_features = TEAM_VLAN_FEATURES & NETIF_F_ALL_FOR_ALL;
+	netdev_features_t vlan_features = TEAM_VLAN_FEATURES &
+					  NETIF_F_ALL_FOR_ALL;
 	unsigned short max_hard_header_len = ETH_HLEN;
 	unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
 					IFF_XMIT_DST_RELEASE_PERM;
@@ -993,15 +998,20 @@
 	team->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
 	if (dst_release_flag == (IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM))
 		team->dev->priv_flags |= IFF_XMIT_DST_RELEASE;
+}
 
+static void __team_compute_features(struct team *team)
+{
+	___team_compute_features(team);
 	netdev_change_features(team->dev);
 }
 
 static void team_compute_features(struct team *team)
 {
 	mutex_lock(&team->lock);
-	__team_compute_features(team);
+	___team_compute_features(team);
 	mutex_unlock(&team->lock);
+	netdev_change_features(team->dev);
 }
 
 static int team_port_enter(struct team *team, struct team_port *port)
@@ -1034,14 +1044,11 @@
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int __team_port_enable_netpoll(struct team_port *port)
 {
 	struct netpoll *np;
 	int err;
 
-	if (!team->dev->npinfo)
-		return 0;
-
 	np = kzalloc(sizeof(*np), GFP_KERNEL);
 	if (!np)
 		return -ENOMEM;
@@ -1055,6 +1062,14 @@
 	return err;
 }
 
+static int team_port_enable_netpoll(struct team_port *port)
+{
+	if (!port->team->dev->npinfo)
+		return 0;
+
+	return __team_port_enable_netpoll(port);
+}
+
 static void team_port_disable_netpoll(struct team_port *port)
 {
 	struct netpoll *np = port->np;
@@ -1069,7 +1084,7 @@
 	kfree(np);
 }
 #else
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team_port *port)
 {
 	return 0;
 }
@@ -1120,6 +1135,17 @@
 		return -EBUSY;
 	}
 
+	if (dev == port_dev) {
+		netdev_err(dev, "Cannot enslave team device to itself\n");
+		return -EINVAL;
+	}
+
+	if (netdev_has_upper_dev(dev, port_dev)) {
+		netdev_err(dev, "Device %s is already an upper device of the team interface\n",
+			   portname);
+		return -EBUSY;
+	}
+
 	if (port_dev->features & NETIF_F_VLAN_CHALLENGED &&
 	    vlan_uses_dev(dev)) {
 		netdev_err(dev, "Device %s is VLAN challenged and team device has VLAN set up\n",
@@ -1176,7 +1202,7 @@
 		goto err_vids_add;
 	}
 
-	err = team_port_enable_netpoll(team, port);
+	err = team_port_enable_netpoll(port);
 	if (err) {
 		netdev_err(dev, "Failed to enable netpoll on device %s\n",
 			   portname);
@@ -1845,10 +1871,10 @@
 	struct team *team = netdev_priv(dev);
 	struct team_port *port;
 
-	rcu_read_lock();
-	list_for_each_entry_rcu(port, &team->port_list, list)
+	mutex_lock(&team->lock);
+	list_for_each_entry(port, &team->port_list, list)
 		vlan_vid_del(port->dev, proto, vid);
-	rcu_read_unlock();
+	mutex_unlock(&team->lock);
 
 	return 0;
 }
@@ -1884,7 +1910,7 @@
 
 	mutex_lock(&team->lock);
 	list_for_each_entry(port, &team->port_list, list) {
-		err = team_port_enable_netpoll(team, port);
+		err = __team_port_enable_netpoll(port);
 		if (err) {
 			__team_netpoll_cleanup(team);
 			break;
@@ -2009,9 +2035,15 @@
 static void team_setup_by_port(struct net_device *dev,
 			       struct net_device *port_dev)
 {
-	dev->header_ops	= port_dev->header_ops;
+	struct team *team = netdev_priv(dev);
+
+	if (port_dev->type == ARPHRD_ETHER)
+		dev->header_ops	= team->header_ops_cache;
+	else
+		dev->header_ops	= port_dev->header_ops;
 	dev->type = port_dev->type;
 	dev->hard_header_len = port_dev->hard_header_len;
+	dev->needed_headroom = port_dev->needed_headroom;
 	dev->addr_len = port_dev->addr_len;
 	dev->mtu = port_dev->mtu;
 	memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
@@ -2046,7 +2078,10 @@
 
 static void team_setup(struct net_device *dev)
 {
+	struct team *team = netdev_priv(dev);
+
 	ether_setup(dev);
+	team->header_ops_cache = dev->header_ops;
 
 	dev->netdev_ops = &team_netdev_ops;
 	dev->ethtool_ops = &team_ethtool_ops;
@@ -2054,6 +2089,7 @@
 	dev->flags |= IFF_MULTICAST;
 	dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
 	dev->priv_flags |= IFF_NO_QUEUE;
+	dev->priv_flags |= IFF_TEAM;
 
 	/*
 	 * Indicate we support unicast address filtering. That way core won't
@@ -2069,12 +2105,12 @@
 	dev->features |= NETIF_F_NETNS_LOCAL;
 
 	dev->hw_features = TEAM_VLAN_FEATURES |
-			   NETIF_F_HW_VLAN_CTAG_TX |
 			   NETIF_F_HW_VLAN_CTAG_RX |
 			   NETIF_F_HW_VLAN_CTAG_FILTER;
 
 	dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
 	dev->features |= dev->hw_features;
+	dev->features |= NETIF_F_HW_VLAN_CTAG_TX;
 }
 
 static int team_newlink(struct net *src_net, struct net_device *dev,
@@ -2147,6 +2183,8 @@
 	[TEAM_ATTR_OPTION_CHANGED]		= { .type = NLA_FLAG },
 	[TEAM_ATTR_OPTION_TYPE]			= { .type = NLA_U8 },
 	[TEAM_ATTR_OPTION_DATA]			= { .type = NLA_BINARY },
+	[TEAM_ATTR_OPTION_PORT_IFINDEX]		= { .type = NLA_U32 },
+	[TEAM_ATTR_OPTION_ARRAY_INDEX]		= { .type = NLA_U32 },
 };
 
 static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
@@ -2338,8 +2376,10 @@
 
 	hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags | NLM_F_MULTI,
 			  TEAM_CMD_OPTIONS_GET);
-	if (!hdr)
+	if (!hdr) {
+		nlmsg_free(skb);
 		return -EMSGSIZE;
+	}
 
 	if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex))
 		goto nla_put_failure;
@@ -2373,7 +2413,7 @@
 	if (!nlh) {
 		err = __send_and_alloc_skb(&skb, team, portid, send_func);
 		if (err)
-			goto errout;
+			return err;
 		goto send_done;
 	}
 
@@ -2418,7 +2458,6 @@
 	int err = 0;
 	int i;
 	struct nlattr *nl_option;
-	LIST_HEAD(opt_inst_list);
 
 	team = team_nl_team_get(info);
 	if (!team)
@@ -2434,6 +2473,7 @@
 		struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1];
 		struct nlattr *attr;
 		struct nlattr *attr_data;
+		LIST_HEAD(opt_inst_list);
 		enum team_option_type opt_type;
 		int opt_port_ifindex = 0; /* != 0 for per-port options */
 		u32 opt_array_index = 0;
@@ -2543,9 +2583,11 @@
 			err = -ENOENT;
 			goto team_put;
 		}
-	}
 
-	err = team_nl_send_event_options_get(team, &opt_inst_list);
+		err = team_nl_send_event_options_get(team, &opt_inst_list);
+		if (err)
+			break;
+	}
 
 team_put:
 	team_nl_team_put(team);
@@ -2606,8 +2648,10 @@
 
 	hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags | NLM_F_MULTI,
 			  TEAM_CMD_PORT_LIST_GET);
-	if (!hdr)
+	if (!hdr) {
+		nlmsg_free(skb);
 		return -EMSGSIZE;
+	}
 
 	if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex))
 		goto nla_put_failure;
@@ -2651,7 +2695,7 @@
 	if (!nlh) {
 		err = __send_and_alloc_skb(&skb, team, portid, send_func);
 		if (err)
-			goto errout;
+			return err;
 		goto send_done;
 	}
 
--- linux-4.4.0.orig/drivers/net/team/team_mode_loadbalance.c
+++ linux-4.4.0/drivers/net/team/team_mode_loadbalance.c
@@ -305,6 +305,20 @@
 	return 0;
 }
 
+static void lb_bpf_func_free(struct team *team)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	struct bpf_prog *fp;
+
+	if (!lb_priv->ex->orig_fprog)
+		return;
+
+	__fprog_destroy(lb_priv->ex->orig_fprog);
+	fp = rcu_dereference_protected(lb_priv->fp,
+				       lockdep_is_held(&team->lock));
+	bpf_prog_destroy(fp);
+}
+
 static int lb_tx_method_get(struct team *team, struct team_gsetter_ctx *ctx)
 {
 	struct lb_priv *lb_priv = get_lb_priv(team);
@@ -619,6 +633,7 @@
 
 	team_options_unregister(team, lb_options,
 				ARRAY_SIZE(lb_options));
+	lb_bpf_func_free(team);
 	cancel_delayed_work_sync(&lb_priv->ex->stats.refresh_dw);
 	free_percpu(lb_priv->pcpu_stats);
 	kfree(lb_priv->ex);
--- linux-4.4.0.orig/drivers/net/tun.c
+++ linux-4.4.0/drivers/net/tun.c
@@ -567,11 +567,13 @@
 	for (i = 0; i < n; i++) {
 		tfile = rtnl_dereference(tun->tfiles[i]);
 		BUG_ON(!tfile);
+		tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN;
 		tfile->socket.sk->sk_data_ready(tfile->socket.sk);
 		RCU_INIT_POINTER(tfile->tun, NULL);
 		--tun->numqueues;
 	}
 	list_for_each_entry(tfile, &tun->disabled, next) {
+		tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN;
 		tfile->socket.sk->sk_data_ready(tfile->socket.sk);
 		RCU_INIT_POINTER(tfile->tun, NULL);
 	}
@@ -595,7 +597,8 @@
 		module_put(THIS_MODULE);
 }
 
-static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filter)
+static int tun_attach(struct tun_struct *tun, struct file *file,
+		      bool skip_filter, bool publish_tun)
 {
 	struct tun_file *tfile = file->private_data;
 	int err;
@@ -621,12 +624,15 @@
 
 	/* Re-attach the filter to persist device */
 	if (!skip_filter && (tun->filter_attached == true)) {
-		err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
+		err = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
+					 lockdep_rtnl_is_held());
 		if (!err)
 			goto out;
 	}
 	tfile->queue_index = tun->numqueues;
-	rcu_assign_pointer(tfile->tun, tun);
+	tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN;
+	if (publish_tun)
+		rcu_assign_pointer(tfile->tun, tun);
 	rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile);
 	tun->numqueues++;
 
@@ -1000,7 +1006,6 @@
 		/* Zero header length */
 		dev->type = ARPHRD_NONE;
 		dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
-		dev->tx_queue_len = TUN_READQ_SIZE;  /* We prefer our own queue length */
 		break;
 
 	case IFF_TAP:
@@ -1012,7 +1017,6 @@
 
 		eth_hw_addr_random(dev);
 
-		dev->tx_queue_len = TUN_READQ_SIZE;  /* We prefer our own queue length */
 		break;
 	}
 }
@@ -1106,9 +1110,11 @@
 	}
 
 	if (tun->flags & IFF_VNET_HDR) {
-		if (len < tun->vnet_hdr_sz)
+		int vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
+
+		if (len < vnet_hdr_sz)
 			return -EINVAL;
-		len -= tun->vnet_hdr_sz;
+		len -= vnet_hdr_sz;
 
 		n = copy_from_iter(&gso, sizeof(gso), from);
 		if (n != sizeof(gso))
@@ -1120,7 +1126,7 @@
 
 		if (tun16_to_cpu(tun, gso.hdr_len) > len)
 			return -EINVAL;
-		iov_iter_advance(from, tun->vnet_hdr_sz - sizeof(gso));
+		iov_iter_advance(from, vnet_hdr_sz - sizeof(gso));
 	}
 
 	if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) {
@@ -1191,11 +1197,13 @@
 	switch (tun->flags & TUN_TYPE_MASK) {
 	case IFF_TUN:
 		if (tun->flags & IFF_NO_PI) {
-			switch (skb->data[0] & 0xf0) {
-			case 0x40:
+			u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0;
+
+			switch (ip_version) {
+			case 4:
 				pi.proto = htons(ETH_P_IP);
 				break;
-			case 0x60:
+			case 6:
 				pi.proto = htons(ETH_P_IPV6);
 				break;
 			default:
@@ -1299,7 +1307,7 @@
 		vlan_hlen = VLAN_HLEN;
 
 	if (tun->flags & IFF_VNET_HDR)
-		vnet_hdr_sz = tun->vnet_hdr_sz;
+		vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
 
 	total = skb->len + vlan_hlen + vnet_hdr_sz;
 
@@ -1335,14 +1343,15 @@
 			else if (sinfo->gso_type & SKB_GSO_UDP)
 				gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
 			else {
-				pr_err("unexpected GSO type: "
-				       "0x%x, gso_size %d, hdr_len %d\n",
-				       sinfo->gso_type, tun16_to_cpu(tun, gso.gso_size),
-				       tun16_to_cpu(tun, gso.hdr_len));
-				print_hex_dump(KERN_ERR, "tun: ",
-					       DUMP_PREFIX_NONE,
-					       16, 1, skb->head,
-					       min((int)tun16_to_cpu(tun, gso.hdr_len), 64), true);
+				if (net_ratelimit()) {
+					netdev_err(tun->dev, "unexpected GSO type: 0x%x, gso_size %d, hdr_len %d\n",
+						   sinfo->gso_type, tun16_to_cpu(tun, gso.gso_size),
+						   tun16_to_cpu(tun, gso.hdr_len));
+					print_hex_dump(KERN_ERR, "tun: ",
+						       DUMP_PREFIX_NONE,
+						       16, 1, skb->head,
+						       min((int)tun16_to_cpu(tun, gso.hdr_len), 64), true);
+				}
 				WARN_ON_ONCE(1);
 				return -EINVAL;
 			}
@@ -1409,9 +1418,6 @@
 	if (!iov_iter_count(to))
 		return 0;
 
-	if (tun->dev->reg_state != NETREG_REGISTERED)
-		return -EIO;
-
 	/* Read frames from queue */
 	skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0,
 				  &peeked, &off, &err);
@@ -1463,6 +1469,8 @@
 
 	dev->ethtool_ops = &tun_ethtool_ops;
 	dev->destructor = tun_free_netdev;
+	/* We prefer our own queue length */
+	dev->tx_queue_len = TUN_READQ_SIZE;
 }
 
 /* Trivial set of netlink ops to allow deleting tun or tap
@@ -1470,7 +1478,9 @@
  */
 static int tun_validate(struct nlattr *tb[], struct nlattr *data[])
 {
-	return -EINVAL;
+	/* NL_SET_ERR_MSG(extack,
+		       "tun/tap creation via rtnetlink is not supported."); */
+	return -EOPNOTSUPP;
 }
 
 static struct rtnl_link_ops tun_link_ops __read_mostly = {
@@ -1634,7 +1644,7 @@
 		if (err < 0)
 			return err;
 
-		err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER);
+		err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER, true);
 		if (err < 0)
 			return err;
 
@@ -1679,6 +1689,9 @@
 
 		if (!dev)
 			return -ENOMEM;
+		err = dev_get_valid_name(net, dev, name);
+		if (err < 0)
+			goto err_free_dev;
 
 		dev_net_set(dev, net);
 		dev->rtnl_link_ops = &tun_link_ops;
@@ -1712,13 +1725,17 @@
 				       NETIF_F_HW_VLAN_STAG_TX);
 
 		INIT_LIST_HEAD(&tun->disabled);
-		err = tun_attach(tun, file, false);
+		err = tun_attach(tun, file, false, false);
 		if (err < 0)
 			goto err_free_flow;
 
 		err = register_netdevice(tun->dev);
 		if (err < 0)
 			goto err_detach;
+		/* free_netdev() won't check refcnt, to aovid race
+		 * with dev_put() we need publish tun after registration.
+		 */
+		rcu_assign_pointer(tfile->tun, tun);
 	}
 
 	netif_carrier_on(tun->dev);
@@ -1804,7 +1821,7 @@
 
 	for (i = 0; i < n; i++) {
 		tfile = rtnl_dereference(tun->tfiles[i]);
-		sk_detach_filter(tfile->socket.sk);
+		__sk_detach_filter(tfile->socket.sk, lockdep_rtnl_is_held());
 	}
 
 	tun->filter_attached = false;
@@ -1817,7 +1834,8 @@
 
 	for (i = 0; i < tun->numqueues; i++) {
 		tfile = rtnl_dereference(tun->tfiles[i]);
-		ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
+		ret = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
+					 lockdep_rtnl_is_held());
 		if (ret) {
 			tun_detach_filter(tun, i);
 			return ret;
@@ -1856,7 +1874,7 @@
 		ret = security_tun_dev_attach_queue(tun->security);
 		if (ret < 0)
 			goto unlock;
-		ret = tun_attach(tun, file, false);
+		ret = tun_attach(tun, file, false, true);
 	} else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
 		tun = rtnl_dereference(tfile->tun);
 		if (!tun || !(tun->flags & IFF_MULTI_QUEUE) || tfile->detached)
@@ -2059,6 +2077,10 @@
 			ret = -EFAULT;
 			break;
 		}
+		if (sndbuf <= 0) {
+			ret = -EINVAL;
+			break;
+		}
 
 		tun->sndbuf = sndbuf;
 		tun_set_sndbuf(tun);
--- linux-4.4.0.orig/drivers/net/usb/Kconfig
+++ linux-4.4.0/drivers/net/usb/Kconfig
@@ -364,7 +364,7 @@
 	  optionally with LEDs that indicate traffic
 
 config USB_NET_PLUSB
-	tristate "Prolific PL-2301/2302/25A1 based cables"
+	tristate "Prolific PL-2301/2302/25A1/27A1 based cables"
 	# if the handshake/init/reset problems, from original 'plusb',
 	# are ever resolved ... then remove "experimental"
 	depends on USB_USBNET
@@ -395,6 +395,10 @@
 	  The protocol specification is incomplete, and is controlled by
 	  (and for) Microsoft; it isn't an "Open" ecosystem or market.
 
+config USB_NET_CDC_SUBSET_ENABLE
+	tristate
+	depends on USB_NET_CDC_SUBSET
+
 config USB_NET_CDC_SUBSET
 	tristate "Simple USB Network Links (CDC Ethernet subset)"
 	depends on USB_USBNET
@@ -413,6 +417,7 @@
 config USB_ALI_M5632
 	bool "ALi M5632 based 'USB 2.0 Data Link' cables"
 	depends on USB_NET_CDC_SUBSET
+	select USB_NET_CDC_SUBSET_ENABLE
 	help
 	  Choose this option if you're using a host-to-host cable
 	  based on this design, which supports USB 2.0 high speed.
@@ -420,6 +425,7 @@
 config USB_AN2720
 	bool "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
 	depends on USB_NET_CDC_SUBSET
+	select USB_NET_CDC_SUBSET_ENABLE
 	help
 	  Choose this option if you're using a host-to-host cable
 	  based on this design.  Note that AnchorChips is now a
@@ -428,6 +434,7 @@
 config USB_BELKIN
 	bool "eTEK based host-to-host cables (Advance, Belkin, ...)"
 	depends on USB_NET_CDC_SUBSET
+	select USB_NET_CDC_SUBSET_ENABLE
 	default y
 	help
 	  Choose this option if you're using a host-to-host cable
@@ -437,6 +444,7 @@
 config USB_ARMLINUX
 	bool "Embedded ARM Linux links (iPaq, ...)"
 	depends on USB_NET_CDC_SUBSET
+	select USB_NET_CDC_SUBSET_ENABLE
 	default y
 	help
 	  Choose this option to support the "usb-eth" networking driver
@@ -454,6 +462,7 @@
 config USB_EPSON2888
 	bool "Epson 2888 based firmware (DEVELOPMENT)"
 	depends on USB_NET_CDC_SUBSET
+	select USB_NET_CDC_SUBSET_ENABLE
 	help
 	  Choose this option to support the usb networking links used
 	  by some sample firmware from Epson.
@@ -461,6 +470,7 @@
 config USB_KC2190
 	bool "KT Technology KC2190 based cables (InstaNet)"
 	depends on USB_NET_CDC_SUBSET
+	select USB_NET_CDC_SUBSET_ENABLE
 	help
 	  Choose this option if you're using a host-to-host cable
 	  with one of these chips.
--- linux-4.4.0.orig/drivers/net/usb/Makefile
+++ linux-4.4.0/drivers/net/usb/Makefile
@@ -23,7 +23,7 @@
 obj-$(CONFIG_USB_NET_NET1080)	+= net1080.o
 obj-$(CONFIG_USB_NET_PLUSB)	+= plusb.o
 obj-$(CONFIG_USB_NET_RNDIS_HOST)	+= rndis_host.o
-obj-$(CONFIG_USB_NET_CDC_SUBSET)	+= cdc_subset.o
+obj-$(CONFIG_USB_NET_CDC_SUBSET_ENABLE)	+= cdc_subset.o
 obj-$(CONFIG_USB_NET_ZAURUS)	+= zaurus.o
 obj-$(CONFIG_USB_NET_MCS7830)	+= mcs7830.o
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
--- linux-4.4.0.orig/drivers/net/usb/asix_common.c
+++ linux-4.4.0/drivers/net/usb/asix_common.c
@@ -66,7 +66,7 @@
 	 * buffer.
 	 */
 	if (rx->remaining && (rx->remaining + sizeof(u32) <= skb->len)) {
-		offset = ((rx->remaining + 1) & 0xfffe) + sizeof(u32);
+		offset = ((rx->remaining + 1) & 0xfffe);
 		rx->header = get_unaligned_le32(skb->data + offset);
 		offset = 0;
 
@@ -251,7 +251,7 @@
 
 	netdev_dbg(dev->net, "asix_get_phy_addr()\n");
 
-	if (ret < 0) {
+	if (ret < 2) {
 		netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
 		goto out;
 	}
@@ -449,6 +449,9 @@
 	struct usbnet *dev = netdev_priv(net);
 	u8 opt = 0;
 
+	if (wolinfo->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
+		return -EINVAL;
+
 	if (wolinfo->wolopts & WAKE_PHY)
 		opt |= AX_MONITOR_LINK;
 	if (wolinfo->wolopts & WAKE_MAGIC)
--- linux-4.4.0.orig/drivers/net/usb/ax88172a.c
+++ linux-4.4.0/drivers/net/usb/ax88172a.c
@@ -243,8 +243,9 @@
 
 	/* Get the MAC address */
 	ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
-	if (ret < 0) {
+	if (ret < ETH_ALEN) {
 		netdev_err(dev->net, "Failed to read MAC address: %d\n", ret);
+		ret = -EIO;
 		goto free;
 	}
 	memcpy(dev->net->dev_addr, buf, ETH_ALEN);
--- linux-4.4.0.orig/drivers/net/usb/ax88179_178a.c
+++ linux-4.4.0/drivers/net/usb/ax88179_178a.c
@@ -566,6 +566,9 @@
 	struct usbnet *dev = netdev_priv(net);
 	u8 opt = 0;
 
+	if (wolinfo->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
+		return -EINVAL;
+
 	if (wolinfo->wolopts & WAKE_PHY)
 		opt |= AX_MONITOR_MODE_RWLC;
 	if (wolinfo->wolopts & WAKE_MAGIC)
@@ -1366,58 +1369,68 @@
 	u16 hdr_off;
 	u32 *pkt_hdr;
 
-	/* This check is no longer done by usbnet */
-	if (skb->len < dev->net->hard_header_len)
+	/* At the end of the SKB, there's a header telling us how many packets
+	 * are bundled into this buffer and where we can find an array of
+	 * per-packet metadata (which contains elements encoded into u16).
+	 */
+	if (skb->len < 4)
 		return 0;
-
 	skb_trim(skb, skb->len - 4);
-	memcpy(&rx_hdr, skb_tail_pointer(skb), 4);
-	le32_to_cpus(&rx_hdr);
-
+	rx_hdr = get_unaligned_le32(skb_tail_pointer(skb));
 	pkt_cnt = (u16)rx_hdr;
 	hdr_off = (u16)(rx_hdr >> 16);
+
+	if (pkt_cnt == 0)
+		return 0;
+
+	/* Make sure that the bounds of the metadata array are inside the SKB
+	 * (and in front of the counter at the end).
+	 */
+	if (pkt_cnt * 2 + hdr_off > skb->len)
+		return 0;
 	pkt_hdr = (u32 *)(skb->data + hdr_off);
 
-	while (pkt_cnt--) {
+	/* Packets must not overlap the metadata array */
+	skb_trim(skb, hdr_off);
+
+	for (; ; pkt_cnt--, pkt_hdr++) {
 		u16 pkt_len;
 
 		le32_to_cpus(pkt_hdr);
 		pkt_len = (*pkt_hdr >> 16) & 0x1fff;
 
-		/* Check CRC or runt packet */
-		if ((*pkt_hdr & AX_RXHDR_CRC_ERR) ||
-		    (*pkt_hdr & AX_RXHDR_DROP_ERR)) {
-			skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-			pkt_hdr++;
-			continue;
-		}
-
-		if (pkt_cnt == 0) {
-			/* Skip IP alignment psudo header */
-			skb_pull(skb, 2);
-			skb->len = pkt_len;
-			skb_set_tail_pointer(skb, pkt_len);
-			skb->truesize = pkt_len + sizeof(struct sk_buff);
-			ax88179_rx_checksum(skb, pkt_hdr);
-			return 1;
-		}
+		if (pkt_len > skb->len)
+			return 0;
 
-		ax_skb = skb_clone(skb, GFP_ATOMIC);
-		if (ax_skb) {
+		/* Check CRC or runt packet */
+		if (((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) == 0) &&
+		    pkt_len >= 2 + ETH_HLEN) {
+			bool last = (pkt_cnt == 0);
+
+			if (last) {
+				ax_skb = skb;
+			} else {
+				ax_skb = skb_clone(skb, GFP_ATOMIC);
+				if (!ax_skb)
+					return 0;
+			}
 			ax_skb->len = pkt_len;
-			ax_skb->data = skb->data + 2;
-			skb_set_tail_pointer(ax_skb, pkt_len);
+			/* Skip IP alignment pseudo header */
+			skb_pull(ax_skb, 2);
+			skb_set_tail_pointer(ax_skb, ax_skb->len);
 			ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
 			ax88179_rx_checksum(ax_skb, pkt_hdr);
+
+			if (last)
+				return 1;
+
 			usbnet_skb_return(dev, ax_skb);
-		} else {
-			return 0;
 		}
 
-		skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-		pkt_hdr++;
+		/* Trim this packet away from the SKB */
+		if (!skb_pull(skb, (pkt_len + 7) & 0xFFF8))
+			return 0;
 	}
-	return 1;
 }
 
 static struct sk_buff *
--- linux-4.4.0.orig/drivers/net/usb/catc.c
+++ linux-4.4.0/drivers/net/usb/catc.c
@@ -777,7 +777,7 @@
 	struct net_device *netdev;
 	struct catc *catc;
 	u8 broadcast[ETH_ALEN];
-	int i, pktsz;
+	int pktsz, ret;
 
 	if (usb_set_interface(usbdev,
 			intf->altsetting->desc.bInterfaceNumber, 1)) {
@@ -812,12 +812,8 @@
 	if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
 	    (!catc->rx_urb) || (!catc->irq_urb)) {
 		dev_err(&intf->dev, "No free urbs available.\n");
-		usb_free_urb(catc->ctrl_urb);
-		usb_free_urb(catc->tx_urb);
-		usb_free_urb(catc->rx_urb);
-		usb_free_urb(catc->irq_urb);
-		free_netdev(netdev);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto fail_free;
 	}
 
 	/* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */
@@ -845,15 +841,24 @@
                 catc->irq_buf, 2, catc_irq_done, catc, 1);
 
 	if (!catc->is_f5u011) {
+		u32 *buf;
+		int i;
+
 		dev_dbg(dev, "Checking memory size\n");
 
-		i = 0x12345678;
-		catc_write_mem(catc, 0x7a80, &i, 4);
-		i = 0x87654321;	
-		catc_write_mem(catc, 0xfa80, &i, 4);
-		catc_read_mem(catc, 0x7a80, &i, 4);
+		buf = kmalloc(4, GFP_KERNEL);
+		if (!buf) {
+			ret = -ENOMEM;
+			goto fail_free;
+		}
+
+		*buf = 0x12345678;
+		catc_write_mem(catc, 0x7a80, buf, 4);
+		*buf = 0x87654321;
+		catc_write_mem(catc, 0xfa80, buf, 4);
+		catc_read_mem(catc, 0x7a80, buf, 4);
 	  
-		switch (i) {
+		switch (*buf) {
 		case 0x12345678:
 			catc_set_reg(catc, TxBufCount, 8);
 			catc_set_reg(catc, RxBufCount, 32);
@@ -868,6 +873,8 @@
 			dev_dbg(dev, "32k Memory\n");
 			break;
 		}
+
+		kfree(buf);
 	  
 		dev_dbg(dev, "Getting MAC from SEEROM.\n");
 	  
@@ -914,16 +921,21 @@
 	usb_set_intfdata(intf, catc);
 
 	SET_NETDEV_DEV(netdev, &intf->dev);
-	if (register_netdev(netdev) != 0) {
-		usb_set_intfdata(intf, NULL);
-		usb_free_urb(catc->ctrl_urb);
-		usb_free_urb(catc->tx_urb);
-		usb_free_urb(catc->rx_urb);
-		usb_free_urb(catc->irq_urb);
-		free_netdev(netdev);
-		return -EIO;
-	}
+	ret = register_netdev(netdev);
+	if (ret)
+		goto fail_clear_intfdata;
+
 	return 0;
+
+fail_clear_intfdata:
+	usb_set_intfdata(intf, NULL);
+fail_free:
+	usb_free_urb(catc->ctrl_urb);
+	usb_free_urb(catc->tx_urb);
+	usb_free_urb(catc->rx_urb);
+	usb_free_urb(catc->irq_urb);
+	free_netdev(netdev);
+	return ret;
 }
 
 static void catc_disconnect(struct usb_interface *intf)
--- linux-4.4.0.orig/drivers/net/usb/cdc_ether.c
+++ linux-4.4.0/drivers/net/usb/cdc_ether.c
@@ -160,6 +160,12 @@
 	info->u = header.usb_cdc_union_desc;
 	info->header = header.usb_cdc_header_desc;
 	info->ether = header.usb_cdc_ether_desc;
+	if (!info->u) {
+		if (rndis)
+			goto skip;
+		else /* in that case a quirk is mandatory */
+			goto bad_desc;
+	}
 	/* we need a master/control interface (what we're
 	 * probed with) and a slave/data interface; union
 	 * descriptors sort this all out.
@@ -206,16 +212,23 @@
 		goto bad_desc;
 	}
 skip:
-	if (	rndis &&
-		header.usb_cdc_acm_descriptor &&
-		header.usb_cdc_acm_descriptor->bmCapabilities) {
+	/* Communcation class functions with bmCapabilities are not
+	 * RNDIS.  But some Wireless class RNDIS functions use
+	 * bmCapabilities for their own purpose. The failsafe is
+	 * therefore applied only to Communication class RNDIS
+	 * functions.  The rndis test is redundant, but a cheap
+	 * optimization.
+	 */
+	if (rndis && is_rndis(&intf->cur_altsetting->desc) &&
+	    header.usb_cdc_acm_descriptor &&
+	    header.usb_cdc_acm_descriptor->bmCapabilities) {
 			dev_dbg(&intf->dev,
 				"ACM capabilities %02x, not really RNDIS?\n",
 				header.usb_cdc_acm_descriptor->bmCapabilities);
 			goto bad_desc;
 	}
 
-	if (header.usb_cdc_ether_desc) {
+	if (header.usb_cdc_ether_desc && info->ether->wMaxSegmentSize) {
 		dev->hard_mtu = le16_to_cpu(info->ether->wMaxSegmentSize);
 		/* because of Zaurus, we may be ignoring the host
 		 * side link address we were given.
@@ -256,7 +269,7 @@
 			goto bad_desc;
 		}
 
-	} else if (!info->header || !info->u || (!rndis && !info->ether)) {
+	} else if (!info->header || (!rndis && !info->ether)) {
 		dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
 			info->header ? "" : "header ",
 			info->u ? "" : "union ",
@@ -455,7 +468,9 @@
 #define REALTEK_VENDOR_ID	0x0bda
 #define SAMSUNG_VENDOR_ID	0x04e8
 #define LENOVO_VENDOR_ID	0x17ef
+#define LINKSYS_VENDOR_ID	0x13b1
 #define NVIDIA_VENDOR_ID	0x0955
+#define HP_VENDOR_ID		0x03f0
 
 static const struct usb_device_id	products[] = {
 /* BLACKLIST !!
@@ -602,6 +617,13 @@
 	.driver_info = 0,
 },
 
+/* HP lt2523 (Novatel E371) - handled by qmi_wwan */
+{
+	USB_DEVICE_AND_INTERFACE_INFO(HP_VENDOR_ID, 0x421d, USB_CLASS_COMM,
+				      USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+	.driver_info = 0,
+},
+
 /* AnyDATA ADU960S - handled by qmi_wwan */
 {
 	USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM,
@@ -636,6 +658,15 @@
 	.driver_info = 0,
 },
 
+#if IS_ENABLED(CONFIG_USB_RTL8152)
+/* Linksys USB3GIGV1 Ethernet Adapter */
+{
+	USB_DEVICE_AND_INTERFACE_INFO(LINKSYS_VENDOR_ID, 0x0041, USB_CLASS_COMM,
+			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+	.driver_info = 0,
+},
+#endif
+
 /* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
 {
 	USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM,
@@ -690,6 +721,12 @@
 				      USB_CDC_SUBCLASS_ETHERNET,
 				      USB_CDC_PROTO_NONE),
 	.driver_info = (unsigned long)&wwan_info,
+}, {
+	/* Cinterion AHS3 modem by GEMALTO */
+	USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0055, USB_CLASS_COMM,
+				      USB_CDC_SUBCLASS_ETHERNET,
+				      USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long)&wwan_info,
 }, {
 	/* Telit modules */
 	USB_VENDOR_AND_INTERFACE_INFO(0x1bc7, USB_CLASS_COMM,
--- linux-4.4.0.orig/drivers/net/usb/cdc_mbim.c
+++ linux-4.4.0/drivers/net/usb/cdc_mbim.c
@@ -593,7 +593,7 @@
  */
 static const struct driver_info cdc_mbim_info_ndp_to_end = {
 	.description = "CDC MBIM",
-	.flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
+	.flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP,
 	.bind = cdc_mbim_bind,
 	.unbind = cdc_mbim_unbind,
 	.manage_power = cdc_mbim_manage_power,
@@ -617,10 +617,23 @@
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0bdb, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
 	  .driver_info = (unsigned long)&cdc_mbim_info,
 	},
-	/* Huawei E3372 fails unless NDP comes after the IP packets */
-	{ USB_DEVICE_AND_INTERFACE_INFO(0x12d1, 0x157d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+
+	/* Some Huawei devices, ME906s-158 (12d1:15c1) and E3372
+	 * (12d1:157d), are known to fail unless the NDP is placed
+	 * after the IP packets.  Applying the quirk to all Huawei
+	 * devices is broader than necessary, but harmless.
+	 */
+	{ USB_VENDOR_AND_INTERFACE_INFO(0x12d1, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
 	  .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end,
 	},
+
+	/* The HP lt4132 (03f0:a31d) is a rebranded Huawei ME906s-158,
+	 * therefore it too requires the above "NDP to end" quirk.
+	 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+	  .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end,
+	},
+
 	/* default entry */
 	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
 	  .driver_info = (unsigned long)&cdc_mbim_info_zlp,
--- linux-4.4.0.orig/drivers/net/usb/cdc_ncm.c
+++ linux-4.4.0/drivers/net/usb/cdc_ncm.c
@@ -533,8 +533,8 @@
 	/* read current mtu value from device */
 	err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE,
 			      USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
-			      0, iface_no, &max_datagram_size, 2);
-	if (err < 0) {
+			      0, iface_no, &max_datagram_size, sizeof(max_datagram_size));
+	if (err != sizeof(max_datagram_size)) {
 		dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n");
 		goto out;
 	}
@@ -545,7 +545,7 @@
 	max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
 	err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE,
 			       USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
-			       0, iface_no, &max_datagram_size, 2);
+			       0, iface_no, &max_datagram_size, sizeof(max_datagram_size));
 	if (err < 0)
 		dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n");
 
@@ -636,8 +636,12 @@
 	u8 ep;
 
 	for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) {
-
 		e = intf->cur_altsetting->endpoint + ep;
+
+		/* ignore endpoints which cannot transfer data */
+		if (!usb_endpoint_maxp(&e->desc))
+			continue;
+
 		switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
 		case USB_ENDPOINT_XFER_INT:
 			if (usb_endpoint_dir_in(&e->desc)) {
@@ -724,8 +728,10 @@
 	u8 *buf;
 	int len;
 	int temp;
+	int err;
 	u8 iface_no;
 	struct usb_cdc_parsed_header hdr;
+	__le16 curr_ntb_format;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
@@ -794,7 +800,11 @@
 
 	iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
 
-	/* reset data interface */
+	/* Reset data interface. Some devices will not reset properly
+	 * unless they are configured first.  Toggle the altsetting to
+	 * force a reset
+	 */
+	usb_set_interface(dev->udev, iface_no, data_altsetting);
 	temp = usb_set_interface(dev->udev, iface_no, 0);
 	if (temp) {
 		dev_dbg(&intf->dev, "set interface failed\n");
@@ -805,6 +815,13 @@
 	if (cdc_ncm_init(dev))
 		goto error2;
 
+	/* Some firmwares need a pause here or they will silently fail
+	 * to set up the interface properly.  This value was decided
+	 * empirically on a Sierra Wireless MC7455 running 02.08.02.00
+	 * firmware.
+	 */
+	usleep_range(10000, 20000);
+
 	/* configure data interface */
 	temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
 	if (temp) {
@@ -812,6 +829,35 @@
 		goto error2;
 	}
 
+	/* Device-specific flags */
+	ctx->drvflags = drvflags;
+
+	/*
+	 * Some Huawei devices have been observed to come out of reset in NDP32 mode.
+	 * Let's check if this is the case, and set the device to NDP16 mode again if
+	 * needed.
+	*/
+	if (ctx->drvflags & CDC_NCM_FLAG_RESET_NTB16) {
+		err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_FORMAT,
+				      USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+				      0, iface_no, &curr_ntb_format, 2);
+		if (err < 0) {
+			goto error2;
+		}
+
+		if (curr_ntb_format == cpu_to_le16(USB_CDC_NCM_NTB32_FORMAT)) {
+			dev_info(&intf->dev, "resetting NTB format to 16-bit");
+			err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
+					       USB_TYPE_CLASS | USB_DIR_OUT
+					       | USB_RECIP_INTERFACE,
+					       USB_CDC_NCM_NTB16_FORMAT,
+					       iface_no, NULL, 0);
+
+			if (err < 0)
+				goto error2;
+		}
+	}
+
 	cdc_ncm_find_endpoints(dev, ctx->data);
 	cdc_ncm_find_endpoints(dev, ctx->control);
 	if (!dev->in || !dev->out || !dev->status) {
@@ -834,9 +880,6 @@
 	/* finish setting up the device specific data */
 	cdc_ncm_setup(dev);
 
-	/* Device-specific flags */
-	ctx->drvflags = drvflags;
-
 	/* Allocate the delayed NDP if needed. */
 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
 		ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
@@ -941,8 +984,6 @@
 
 static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
 {
-	int ret;
-
 	/* MBIM backwards compatible function? */
 	if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
 		return -ENODEV;
@@ -951,16 +992,7 @@
 	 * Additionally, generic NCM devices are assumed to accept arbitrarily
 	 * placed NDP.
 	 */
-	ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
-
-	/*
-	 * We should get an event when network connection is "connected" or
-	 * "disconnected". Set network connection in "disconnected" state
-	 * (carrier is OFF) during attach, so the IP network stack does not
-	 * start IPv6 negotiation and more.
-	 */
-	usbnet_link_change(dev, 0, 0);
-	return ret;
+	return cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
 }
 
 static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max)
@@ -1041,12 +1073,16 @@
 	u16 n = 0, index, ndplen;
 	u8 ready2send = 0;
 	u32 delayed_ndp_size;
+	size_t padding_count;
 
 	/* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
 	 * accordingly. Otherwise, we should check here.
 	 */
 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
-		delayed_ndp_size = ctx->max_ndp_size;
+		delayed_ndp_size = ctx->max_ndp_size +
+			max_t(u32,
+			      ctx->tx_ndp_modulus,
+			      ctx->tx_modulus + ctx->tx_remainder) - 1;
 	else
 		delayed_ndp_size = 0;
 
@@ -1179,7 +1215,7 @@
 	/* If requested, put NDP at end of frame. */
 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
 		nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
-		cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max);
+		cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max - ctx->max_ndp_size);
 		nth16->wNdpIndex = cpu_to_le16(skb_out->len);
 		memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size);
 
@@ -1197,11 +1233,14 @@
 	 * a ZLP after full sized NTBs.
 	 */
 	if (!(dev->driver_info->flags & FLAG_SEND_ZLP) &&
-	    skb_out->len > ctx->min_tx_pkt)
-		memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0,
-		       ctx->tx_max - skb_out->len);
-	else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0)
+	    skb_out->len > ctx->min_tx_pkt) {
+		padding_count = ctx->tx_max - skb_out->len;
+		if (!WARN_ON(padding_count > ctx->tx_max))
+			memset(skb_put(skb_out, padding_count), 0, padding_count);
+	} else if (skb_out->len < ctx->tx_max &&
+		   (skb_out->len % dev->maxpacket) == 0) {
 		*skb_put(skb_out, 1) = 0;	/* force short packet */
+	}
 
 	/* set final frame length */
 	nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
@@ -1389,10 +1428,10 @@
 {
 	struct sk_buff *skb;
 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
-	int len;
+	unsigned int len;
 	int nframes;
 	int x;
-	int offset;
+	unsigned int offset;
 	struct usb_cdc_ncm_ndp16 *ndp16;
 	struct usb_cdc_ncm_dpe16 *dpe16;
 	int ndpoffset;
@@ -1432,8 +1471,8 @@
 			break;
 		}
 
-		/* sanity checking */
-		if (((offset + len) > skb_in->len) ||
+		/* sanity checking - watch out for integer wrap*/
+		if ((offset > skb_in->len) || (len > skb_in->len - offset) ||
 				(len > ctx->rx_max) || (len < ETH_HLEN)) {
 			netif_dbg(dev, rx_err, dev->net,
 				  "invalid frame detected (ignored) offset[%u]=%u, length=%u, skb=%p\n",
@@ -1518,9 +1557,6 @@
 		 * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
 		 * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
 		 */
-		netif_info(dev, link, dev->net,
-			   "network connection: %sconnected\n",
-			   !!event->wValue ? "" : "dis");
 		usbnet_link_change(dev, !!event->wValue, 0);
 		break;
 
@@ -1543,7 +1579,8 @@
 
 static const struct driver_info cdc_ncm_info = {
 	.description = "CDC NCM",
-	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET,
+	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
+			| FLAG_LINK_INTR,
 	.bind = cdc_ncm_bind,
 	.unbind = cdc_ncm_unbind,
 	.manage_power = usbnet_manage_power,
@@ -1556,7 +1593,7 @@
 static const struct driver_info wwan_info = {
 	.description = "Mobile Broadband Network Device",
 	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
-			| FLAG_WWAN,
+			| FLAG_LINK_INTR | FLAG_WWAN,
 	.bind = cdc_ncm_bind,
 	.unbind = cdc_ncm_unbind,
 	.manage_power = usbnet_manage_power,
@@ -1569,7 +1606,7 @@
 static const struct driver_info wwan_noarp_info = {
 	.description = "Mobile Broadband Network Device (NO ARP)",
 	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
-			| FLAG_WWAN | FLAG_NOARP,
+			| FLAG_LINK_INTR | FLAG_WWAN | FLAG_NOARP,
 	.bind = cdc_ncm_bind,
 	.unbind = cdc_ncm_unbind,
 	.manage_power = usbnet_manage_power,
--- linux-4.4.0.orig/drivers/net/usb/ch9200.c
+++ linux-4.4.0/drivers/net/usb/ch9200.c
@@ -255,14 +255,9 @@
 	tx_overhead = 0x40;
 
 	len = skb->len;
-	if (skb_headroom(skb) < tx_overhead) {
-		struct sk_buff *skb2;
-
-		skb2 = skb_copy_expand(skb, tx_overhead, 0, flags);
+	if (skb_cow_head(skb, tx_overhead)) {
 		dev_kfree_skb_any(skb);
-		skb = skb2;
-		if (!skb)
-			return NULL;
+		return NULL;
 	}
 
 	__skb_push(skb, tx_overhead);
--- linux-4.4.0.orig/drivers/net/usb/cx82310_eth.c
+++ linux-4.4.0/drivers/net/usb/cx82310_eth.c
@@ -175,7 +175,8 @@
 	}
 	if (!timeout) {
 		dev_err(&udev->dev, "firmware not ready in time\n");
-		return -ETIMEDOUT;
+		ret = -ETIMEDOUT;
+		goto err;
 	}
 
 	/* enable ethernet mode (?) */
@@ -293,12 +294,9 @@
 {
 	int len = skb->len;
 
-	if (skb_headroom(skb) < 2) {
-		struct sk_buff *skb2 = skb_copy_expand(skb, 2, 0, flags);
+	if (skb_cow_head(skb, 2)) {
 		dev_kfree_skb_any(skb);
-		skb = skb2;
-		if (!skb)
-			return NULL;
+		return NULL;
 	}
 	skb_push(skb, 2);
 
--- linux-4.4.0.orig/drivers/net/usb/dm9601.c
+++ linux-4.4.0/drivers/net/usb/dm9601.c
@@ -624,6 +624,10 @@
 	 USB_DEVICE(0x0a46, 0x1269),	/* DM9621A USB to Fast Ethernet Adapter */
 	 .driver_info = (unsigned long)&dm9601_info,
 	},
+	{
+	 USB_DEVICE(0x0586, 0x3427),	/* ZyXEL Keenetic Plus DSL xDSL modem */
+	 .driver_info = (unsigned long)&dm9601_info,
+	},
 	{},			// END
 };
 
--- linux-4.4.0.orig/drivers/net/usb/hso.c
+++ linux-4.4.0/drivers/net/usb/hso.c
@@ -635,7 +635,7 @@
 	return serial;
 }
 
-static int get_free_serial_index(void)
+static int obtain_minor(struct hso_serial *serial)
 {
 	int index;
 	unsigned long flags;
@@ -643,8 +643,10 @@
 	spin_lock_irqsave(&serial_table_lock, flags);
 	for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) {
 		if (serial_table[index] == NULL) {
+			serial_table[index] = serial->parent;
+			serial->minor = index;
 			spin_unlock_irqrestore(&serial_table_lock, flags);
-			return index;
+			return 0;
 		}
 	}
 	spin_unlock_irqrestore(&serial_table_lock, flags);
@@ -653,15 +655,12 @@
 	return -1;
 }
 
-static void set_serial_by_index(unsigned index, struct hso_serial *serial)
+static void release_minor(struct hso_serial *serial)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&serial_table_lock, flags);
-	if (serial)
-		serial_table[index] = serial->parent;
-	else
-		serial_table[index] = NULL;
+	serial_table[serial->minor] = NULL;
 	spin_unlock_irqrestore(&serial_table_lock, flags);
 }
 
@@ -2249,6 +2248,7 @@
 static void hso_serial_tty_unregister(struct hso_serial *serial)
 {
 	tty_unregister_device(tty_drv, serial->minor);
+	release_minor(serial);
 }
 
 static void hso_serial_common_free(struct hso_serial *serial)
@@ -2273,23 +2273,23 @@
 				    int rx_size, int tx_size)
 {
 	struct device *dev;
-	int minor;
 	int i;
 
 	tty_port_init(&serial->port);
 
-	minor = get_free_serial_index();
-	if (minor < 0)
-		goto exit;
+	if (obtain_minor(serial))
+		goto exit2;
 
 	/* register our minor number */
 	serial->parent->dev = tty_port_register_device_attr(&serial->port,
-			tty_drv, minor, &serial->parent->interface->dev,
+			tty_drv, serial->minor, &serial->parent->interface->dev,
 			serial->parent, hso_serial_dev_groups);
+	if (IS_ERR(serial->parent->dev)) {
+		release_minor(serial);
+		goto exit2;
+	}
 	dev = serial->parent->dev;
 
-	/* fill in specific data for later use */
-	serial->minor = minor;
 	serial->magic = HSO_SERIAL_MAGIC;
 	spin_lock_init(&serial->serial_lock);
 	serial->num_rx_urbs = num_urbs;
@@ -2300,10 +2300,8 @@
 	serial->rx_data_length = rx_size;
 	for (i = 0; i < serial->num_rx_urbs; i++) {
 		serial->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
-		if (!serial->rx_urb[i]) {
-			dev_err(dev, "Could not allocate urb?\n");
+		if (!serial->rx_urb[i])
 			goto exit;
-		}
 		serial->rx_urb[i]->transfer_buffer = NULL;
 		serial->rx_urb[i]->transfer_buffer_length = 0;
 		serial->rx_data[i] = kzalloc(serial->rx_data_length,
@@ -2314,10 +2312,8 @@
 
 	/* TX, allocate urb and initialize */
 	serial->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!serial->tx_urb) {
-		dev_err(dev, "Could not allocate urb?\n");
+	if (!serial->tx_urb)
 		goto exit;
-	}
 	serial->tx_urb->transfer_buffer = NULL;
 	serial->tx_urb->transfer_buffer_length = 0;
 	/* prepare our TX buffer */
@@ -2335,6 +2331,7 @@
 	return 0;
 exit:
 	hso_serial_tty_unregister(serial);
+exit2:
 	hso_serial_common_free(serial);
 	return -1;
 }
@@ -2521,7 +2518,7 @@
 			   hso_net_init);
 	if (!net) {
 		dev_err(&interface->dev, "Unable to create ethernet device\n");
-		goto exit;
+		goto err_hso_dev;
 	}
 
 	hso_net = netdev_priv(net);
@@ -2534,54 +2531,63 @@
 				      USB_DIR_IN);
 	if (!hso_net->in_endp) {
 		dev_err(&interface->dev, "Can't find BULK IN endpoint\n");
-		goto exit;
+		goto err_net;
 	}
 	hso_net->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK,
 				       USB_DIR_OUT);
 	if (!hso_net->out_endp) {
 		dev_err(&interface->dev, "Can't find BULK OUT endpoint\n");
-		goto exit;
+		goto err_net;
 	}
 	SET_NETDEV_DEV(net, &interface->dev);
 	SET_NETDEV_DEVTYPE(net, &hso_type);
 
-	/* registering our net device */
-	result = register_netdev(net);
-	if (result) {
-		dev_err(&interface->dev, "Failed to register device\n");
-		goto exit;
-	}
-
 	/* start allocating */
 	for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
 		hso_net->mux_bulk_rx_urb_pool[i] = usb_alloc_urb(0, GFP_KERNEL);
-		if (!hso_net->mux_bulk_rx_urb_pool[i]) {
-			dev_err(&interface->dev, "Could not allocate rx urb\n");
-			goto exit;
-		}
+		if (!hso_net->mux_bulk_rx_urb_pool[i])
+			goto err_mux_bulk_rx;
 		hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE,
 							   GFP_KERNEL);
 		if (!hso_net->mux_bulk_rx_buf_pool[i])
-			goto exit;
+			goto err_mux_bulk_rx;
 	}
 	hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!hso_net->mux_bulk_tx_urb) {
-		dev_err(&interface->dev, "Could not allocate tx urb\n");
-		goto exit;
-	}
+	if (!hso_net->mux_bulk_tx_urb)
+		goto err_mux_bulk_rx;
 	hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL);
 	if (!hso_net->mux_bulk_tx_buf)
-		goto exit;
+		goto err_free_tx_urb;
 
 	add_net_device(hso_dev);
 
+	/* registering our net device */
+	result = register_netdev(net);
+	if (result) {
+		dev_err(&interface->dev, "Failed to register device\n");
+		goto err_free_tx_buf;
+	}
+
 	hso_log_port(hso_dev);
 
 	hso_create_rfkill(hso_dev, interface);
 
 	return hso_dev;
-exit:
-	hso_free_net_device(hso_dev);
+
+err_free_tx_buf:
+	remove_net_device(hso_dev);
+	kfree(hso_net->mux_bulk_tx_buf);
+err_free_tx_urb:
+	usb_free_urb(hso_net->mux_bulk_tx_urb);
+err_mux_bulk_rx:
+	for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
+		usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]);
+		kfree(hso_net->mux_bulk_rx_buf_pool[i]);
+	}
+err_net:
+	free_netdev(net);
+err_hso_dev:
+	kfree(hso_dev);
 	return NULL;
 }
 
@@ -2650,14 +2656,18 @@
 		 */
 		if (serial->tiocmget) {
 			tiocmget = serial->tiocmget;
+			tiocmget->endp = hso_get_ep(interface,
+						    USB_ENDPOINT_XFER_INT,
+						    USB_DIR_IN);
+			if (!tiocmget->endp) {
+				dev_err(&interface->dev, "Failed to find INT IN ep\n");
+				goto exit;
+			}
+
 			tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
 			if (tiocmget->urb) {
 				mutex_init(&tiocmget->mutex);
 				init_waitqueue_head(&tiocmget->waitq);
-				tiocmget->endp = hso_get_ep(
-					interface,
-					USB_ENDPOINT_XFER_INT,
-					USB_DIR_IN);
 			} else
 				hso_free_tiomget(serial);
 		}
@@ -2685,9 +2695,6 @@
 
 	serial->write_data = hso_std_serial_write_data;
 
-	/* and record this serial */
-	set_serial_by_index(serial->minor, serial);
-
 	/* setup the proc dirs and files if needed */
 	hso_log_port(hso_dev);
 
@@ -2744,9 +2751,6 @@
 	serial->shared_int->ref_count++;
 	mutex_unlock(&serial->shared_int->shared_int_lock);
 
-	/* and record this serial */
-	set_serial_by_index(serial->minor, serial);
-
 	/* setup the proc dirs and files if needed */
 	hso_log_port(hso_dev);
 
@@ -2787,10 +2791,8 @@
 	}
 
 	mux->shared_intr_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!mux->shared_intr_urb) {
-		dev_err(&interface->dev, "Could not allocate intr urb?\n");
+	if (!mux->shared_intr_urb)
 		goto exit;
-	}
 	mux->shared_intr_buf =
 		kzalloc(le16_to_cpu(mux->intr_endp->wMaxPacketSize),
 			GFP_KERNEL);
@@ -2825,6 +2827,12 @@
 		return -EIO;
 	}
 
+	/* check if we have a valid interface */
+	if (if_num > 16) {
+		kfree(config_data);
+		return -EINVAL;
+	}
+
 	switch (config_data[if_num]) {
 	case 0x0:
 		result = 0;
@@ -2895,10 +2903,18 @@
 
 	/* Get the interface/port specification from either driver_info or from
 	 * the device itself */
-	if (id->driver_info)
+	if (id->driver_info) {
+		/* if_num is controlled by the device, driver_info is a 0 terminated
+		 * array. Make sure, the access is in bounds! */
+		for (i = 0; i <= if_num; ++i)
+			if (((u32 *)(id->driver_info))[i] == 0)
+				goto exit;
 		port_spec = ((u32 *)(id->driver_info))[if_num];
-	else
+	} else {
 		port_spec = hso_get_config_data(interface);
+		if (port_spec < 0)
+			goto exit;
+	}
 
 	/* Check if we need to switch to alt interfaces prior to port
 	 * configuration */
@@ -3118,8 +3134,7 @@
 			cancel_work_sync(&serial_table[i]->async_put_intf);
 			cancel_work_sync(&serial_table[i]->async_get_intf);
 			hso_serial_tty_unregister(serial);
-			kref_put(&serial_table[i]->ref, hso_serial_ref_free);
-			set_serial_by_index(i, NULL);
+			kref_put(&serial->parent->ref, hso_serial_ref_free);
 		}
 	}
 
--- linux-4.4.0.orig/drivers/net/usb/huawei_cdc_ncm.c
+++ linux-4.4.0/drivers/net/usb/huawei_cdc_ncm.c
@@ -80,6 +80,12 @@
 	 * be at the end of the frame.
 	 */
 	drvflags |= CDC_NCM_FLAG_NDP_TO_END;
+
+	/* Additionally, it has been reported that some Huawei E3372H devices, with
+	 * firmware version 21.318.01.00.541, come out of reset in NTB32 format mode, hence
+	 * needing to be set to the NTB16 one again.
+	 */
+	drvflags |= CDC_NCM_FLAG_RESET_NTB16;
 	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags);
 	if (ret)
 		goto err;
--- linux-4.4.0.orig/drivers/net/usb/ipheth.c
+++ linux-4.4.0/drivers/net/usb/ipheth.c
@@ -70,7 +70,7 @@
 #define IPHETH_USBINTF_SUBCLASS 253
 #define IPHETH_USBINTF_PROTO    1
 
-#define IPHETH_BUF_SIZE         1516
+#define IPHETH_BUF_SIZE         1514
 #define IPHETH_IP_ALIGN		2	/* padding at front of URB */
 #define IPHETH_TX_TIMEOUT       (5 * HZ)
 
@@ -140,7 +140,6 @@
 	struct usb_device *udev;
 	struct usb_interface *intf;
 	struct net_device *net;
-	struct sk_buff *tx_skb;
 	struct urb *tx_urb;
 	struct urb *rx_urb;
 	unsigned char *tx_buf;
@@ -149,6 +148,7 @@
 	u8 bulk_in;
 	u8 bulk_out;
 	struct delayed_work carrier_work;
+	bool confirmed_pairing;
 };
 
 static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);
@@ -229,6 +229,7 @@
 	case -ENOENT:
 	case -ECONNRESET:
 	case -ESHUTDOWN:
+	case -EPROTO:
 		return;
 	case 0:
 		break;
@@ -259,7 +260,7 @@
 
 	dev->net->stats.rx_packets++;
 	dev->net->stats.rx_bytes += len;
-
+	dev->confirmed_pairing = true;
 	netif_rx(skb);
 	ipheth_rx_submit(dev, GFP_ATOMIC);
 }
@@ -280,15 +281,24 @@
 		dev_err(&dev->intf->dev, "%s: urb status: %d\n",
 		__func__, status);
 
-	dev_kfree_skb_irq(dev->tx_skb);
-	netif_wake_queue(dev->net);
+	if (status == 0)
+		netif_wake_queue(dev->net);
+	else
+		// on URB error, trigger immediate poll
+		schedule_delayed_work(&dev->carrier_work, 0);
 }
 
 static int ipheth_carrier_set(struct ipheth_device *dev)
 {
-	struct usb_device *udev = dev->udev;
+	struct usb_device *udev;
 	int retval;
 
+	if (!dev)
+		return 0;
+	if (!dev->confirmed_pairing)
+		return 0;
+
+	udev = dev->udev;
 	retval = usb_control_msg(udev,
 			usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
 			IPHETH_CMD_CARRIER_CHECK, /* request */
@@ -303,11 +313,14 @@
 		return retval;
 	}
 
-	if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON)
+	if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) {
 		netif_carrier_on(dev->net);
-	else
+		if (dev->tx_urb->status != -EINPROGRESS)
+			netif_wake_queue(dev->net);
+	} else {
 		netif_carrier_off(dev->net);
-
+		netif_stop_queue(dev->net);
+	}
 	return 0;
 }
 
@@ -387,7 +400,6 @@
 		return retval;
 
 	schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
-	netif_start_queue(net);
 	return retval;
 }
 
@@ -410,7 +422,7 @@
 	if (skb->len > IPHETH_BUF_SIZE) {
 		WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len);
 		dev->net->stats.tx_dropped++;
-		dev_kfree_skb_irq(skb);
+		dev_kfree_skb_any(skb);
 		return NETDEV_TX_OK;
 	}
 
@@ -425,18 +437,18 @@
 			  dev);
 	dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
+	netif_stop_queue(net);
 	retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
 	if (retval) {
 		dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
 			__func__, retval);
 		dev->net->stats.tx_errors++;
-		dev_kfree_skb_irq(skb);
+		dev_kfree_skb_any(skb);
+		netif_wake_queue(net);
 	} else {
-		dev->tx_skb = skb;
-
 		dev->net->stats.tx_packets++;
 		dev->net->stats.tx_bytes += skb->len;
-		netif_stop_queue(net);
+		dev_consume_skb_any(skb);
 	}
 
 	return NETDEV_TX_OK;
@@ -491,7 +503,7 @@
 	dev->udev = udev;
 	dev->net = netdev;
 	dev->intf = intf;
-
+	dev->confirmed_pairing = false;
 	/* Set up endpoints */
 	hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
 	if (hintf == NULL) {
@@ -542,7 +554,9 @@
 		retval = -EIO;
 		goto err_register_netdev;
 	}
-
+	// carrier down and transmit queues stopped until packet from device
+	netif_carrier_off(netdev);
+	netif_tx_stop_all_queues(netdev);
 	dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");
 	return 0;
 
--- linux-4.4.0.orig/drivers/net/usb/kalmia.c
+++ linux-4.4.0/drivers/net/usb/kalmia.c
@@ -117,16 +117,16 @@
 	status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_1)
 		/ sizeof(init_msg_1[0]), usb_buf, 24);
 	if (status != 0)
-		return status;
+		goto out;
 
 	memcpy(usb_buf, init_msg_2, 12);
 	status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_2)
 		/ sizeof(init_msg_2[0]), usb_buf, 28);
 	if (status != 0)
-		return status;
+		goto out;
 
 	memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN);
-
+out:
 	kfree(usb_buf);
 	return status;
 }
--- linux-4.4.0.orig/drivers/net/usb/kaweth.c
+++ linux-4.4.0/drivers/net/usb/kaweth.c
@@ -812,18 +812,12 @@
 	}
 
 	/* We now decide whether we can put our special header into the sk_buff */
-	if (skb_cloned(skb) || skb_headroom(skb) < 2) {
-		/* no such luck - we make our own */
-		struct sk_buff *copied_skb;
-		copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC);
-		dev_kfree_skb_irq(skb);
-		skb = copied_skb;
-		if (!copied_skb) {
-			kaweth->stats.tx_errors++;
-			netif_start_queue(net);
-			spin_unlock_irq(&kaweth->device_lock);
-			return NETDEV_TX_OK;
-		}
+	if (skb_cow_head(skb, 2)) {
+		kaweth->stats.tx_errors++;
+		netif_start_queue(net);
+		spin_unlock_irq(&kaweth->device_lock);
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
 	}
 
 	private_header = (__le16 *)__skb_push(skb, 2);
@@ -1009,6 +1003,7 @@
 	struct net_device *netdev;
 	const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 	int result = 0;
+	int rv = -EIO;
 
 	dev_dbg(dev,
 		"Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x\n",
@@ -1029,6 +1024,7 @@
 	kaweth = netdev_priv(netdev);
 	kaweth->dev = udev;
 	kaweth->net = netdev;
+	kaweth->intf = intf;
 
 	spin_lock_init(&kaweth->device_lock);
 	init_waitqueue_head(&kaweth->term_wait);
@@ -1048,6 +1044,10 @@
 		/* Download the firmware */
 		dev_info(dev, "Downloading firmware...\n");
 		kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
+		if (!kaweth->firmware_buf) {
+			rv = -ENOMEM;
+			goto err_free_netdev;
+		}
 		if ((result = kaweth_download_firmware(kaweth,
 						      "kaweth/new_code.bin",
 						      100,
@@ -1139,8 +1139,6 @@
 
 	dev_dbg(dev, "Initializing net device.\n");
 
-	kaweth->intf = intf;
-
 	kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!kaweth->tx_urb)
 		goto err_free_netdev;
@@ -1204,7 +1202,7 @@
 err_free_netdev:
 	free_netdev(netdev);
 
-	return -EIO;
+	return rv;
 }
 
 /****************************************************************
--- linux-4.4.0.orig/drivers/net/usb/lan78xx.c
+++ linux-4.4.0/drivers/net/usb/lan78xx.c
@@ -30,6 +30,7 @@
 #include <linux/ipv6.h>
 #include <linux/mdio.h>
 #include <net/ip6_checksum.h>
+#include <net/vxlan.h>
 #include <linux/microchipphy.h>
 #include "lan78xx.h"
 
@@ -250,10 +251,6 @@
 	struct tasklet_struct	bh;
 	struct delayed_work	wq;
 
-	struct usb_host_endpoint *ep_blkin;
-	struct usb_host_endpoint *ep_blkout;
-	struct usb_host_endpoint *ep_intr;
-
 	int			msg_enable;
 
 	struct urb		*urb_intr;
@@ -370,7 +367,7 @@
 		}
 	} else {
 		netdev_warn(dev->net,
-			    "Failed to read stat ret = 0x%x", ret);
+			    "Failed to read stat ret = %d", ret);
 	}
 
 	kfree(stats);
@@ -618,7 +615,8 @@
 			offset += 0x100;
 		else
 			ret = -EINVAL;
-		ret = lan78xx_read_raw_otp(dev, offset, length, data);
+		if (!ret)
+			ret = lan78xx_read_raw_otp(dev, offset, length, data);
 	}
 
 	return ret;
@@ -901,6 +899,8 @@
 
 		ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv);
 		netif_carrier_on(dev->net);
+
+		tasklet_schedule(&dev->bh);
 	}
 
 	return ret;
@@ -1048,19 +1048,10 @@
 	if (ret < 0)
 		return ret;
 
-	pdata->wol = 0;
-	if (wol->wolopts & WAKE_UCAST)
-		pdata->wol |= WAKE_UCAST;
-	if (wol->wolopts & WAKE_MCAST)
-		pdata->wol |= WAKE_MCAST;
-	if (wol->wolopts & WAKE_BCAST)
-		pdata->wol |= WAKE_BCAST;
-	if (wol->wolopts & WAKE_MAGIC)
-		pdata->wol |= WAKE_MAGIC;
-	if (wol->wolopts & WAKE_PHY)
-		pdata->wol |= WAKE_PHY;
-	if (wol->wolopts & WAKE_ARP)
-		pdata->wol |= WAKE_ARP;
+	if (wol->wolopts & ~WAKE_ALL)
+		return -EINVAL;
+
+	pdata->wol = wol->wolopts;
 
 	device_set_wakeup_enable(&dev->udev->dev, (bool)wol->wolopts);
 
@@ -1454,6 +1445,7 @@
 	dev->mdiobus->read = lan78xx_mdiobus_read;
 	dev->mdiobus->write = lan78xx_mdiobus_write;
 	dev->mdiobus->name = "lan78xx-mdiobus";
+	dev->mdiobus->parent = &dev->udev->dev;
 
 	snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
 		 dev->udev->bus->busnum, dev->udev->devnum);
@@ -1859,6 +1851,7 @@
 		buf = DEFAULT_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
 		dev->rx_urb_size = DEFAULT_BURST_CAP_SIZE;
 		dev->rx_qlen = 4;
+		dev->tx_qlen = 4;
 	}
 
 	ret = lan78xx_write_reg(dev, BURST_CAP, buf);
@@ -2040,28 +2033,20 @@
 	return 0;
 }
 
-static int lan78xx_linearize(struct sk_buff *skb)
-{
-	return skb_linearize(skb);
-}
-
 static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev,
 				       struct sk_buff *skb, gfp_t flags)
 {
 	u32 tx_cmd_a, tx_cmd_b;
 
-	if (skb_headroom(skb) < TX_OVERHEAD) {
-		struct sk_buff *skb2;
-
-		skb2 = skb_copy_expand(skb, TX_OVERHEAD, 0, flags);
+	if (skb_cow_head(skb, TX_OVERHEAD)) {
 		dev_kfree_skb_any(skb);
-		skb = skb2;
-		if (!skb)
-			return NULL;
+		return NULL;
 	}
 
-	if (lan78xx_linearize(skb) < 0)
+	if (skb_linearize(skb)) {
+		dev_kfree_skb_any(skb);
 		return NULL;
+	}
 
 	tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN_MASK_) | TX_CMD_A_FCS_;
 
@@ -2191,72 +2176,12 @@
 	return NETDEV_TX_OK;
 }
 
-int lan78xx_get_endpoints(struct lan78xx_net *dev, struct usb_interface *intf)
-{
-	int tmp;
-	struct usb_host_interface *alt = NULL;
-	struct usb_host_endpoint *in = NULL, *out = NULL;
-	struct usb_host_endpoint *status = NULL;
-
-	for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
-		unsigned ep;
-
-		in = NULL;
-		out = NULL;
-		status = NULL;
-		alt = intf->altsetting + tmp;
-
-		for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {
-			struct usb_host_endpoint *e;
-			int intr = 0;
-
-			e = alt->endpoint + ep;
-			switch (e->desc.bmAttributes) {
-			case USB_ENDPOINT_XFER_INT:
-				if (!usb_endpoint_dir_in(&e->desc))
-					continue;
-				intr = 1;
-				/* FALLTHROUGH */
-			case USB_ENDPOINT_XFER_BULK:
-				break;
-			default:
-				continue;
-			}
-			if (usb_endpoint_dir_in(&e->desc)) {
-				if (!intr && !in)
-					in = e;
-				else if (intr && !status)
-					status = e;
-			} else {
-				if (!out)
-					out = e;
-			}
-		}
-		if (in && out)
-			break;
-	}
-	if (!alt || !in || !out)
-		return -EINVAL;
-
-	dev->pipe_in = usb_rcvbulkpipe(dev->udev,
-				       in->desc.bEndpointAddress &
-				       USB_ENDPOINT_NUMBER_MASK);
-	dev->pipe_out = usb_sndbulkpipe(dev->udev,
-					out->desc.bEndpointAddress &
-					USB_ENDPOINT_NUMBER_MASK);
-	dev->ep_intr = status;
-
-	return 0;
-}
-
 static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)
 {
 	struct lan78xx_priv *pdata = NULL;
 	int ret;
 	int i;
 
-	ret = lan78xx_get_endpoints(dev, intf);
-
 	dev->data[0] = (unsigned long)kzalloc(sizeof(*pdata), GFP_KERNEL);
 
 	pdata = (struct lan78xx_priv *)(dev->data[0]);
@@ -2900,6 +2825,19 @@
 	tasklet_schedule(&dev->bh);
 }
 
+static netdev_features_t lan78xx_features_check(struct sk_buff *skb,
+						struct net_device *netdev,
+						netdev_features_t features)
+{
+	if (skb->len + TX_OVERHEAD > MAX_SINGLE_PACKET_SIZE)
+		features &= ~NETIF_F_GSO_MASK;
+
+	features = vlan_features_check(skb, features);
+	features = vxlan_features_check(skb, features);
+
+	return features;
+}
+
 static const struct net_device_ops lan78xx_netdev_ops = {
 	.ndo_open		= lan78xx_open,
 	.ndo_stop		= lan78xx_stop,
@@ -2913,11 +2851,13 @@
 	.ndo_set_features	= lan78xx_set_features,
 	.ndo_vlan_rx_add_vid	= lan78xx_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid	= lan78xx_vlan_rx_kill_vid,
+	.ndo_features_check	= lan78xx_features_check,
 };
 
 static int lan78xx_probe(struct usb_interface *intf,
 			 const struct usb_device_id *id)
 {
+	struct usb_host_endpoint *ep_blkin, *ep_blkout, *ep_intr;
 	struct lan78xx_net *dev;
 	struct net_device *netdev;
 	struct usb_device *udev;
@@ -2961,6 +2901,34 @@
 	netdev->watchdog_timeo = TX_TIMEOUT_JIFFIES;
 	netdev->ethtool_ops = &lan78xx_ethtool_ops;
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 3) {
+		ret = -ENODEV;
+		goto out2;
+	}
+
+	dev->pipe_in = usb_rcvbulkpipe(udev, BULK_IN_PIPE);
+	ep_blkin = usb_pipe_endpoint(udev, dev->pipe_in);
+	if (!ep_blkin || !usb_endpoint_is_bulk_in(&ep_blkin->desc)) {
+		ret = -ENODEV;
+		goto out2;
+	}
+
+	dev->pipe_out = usb_sndbulkpipe(udev, BULK_OUT_PIPE);
+	ep_blkout = usb_pipe_endpoint(udev, dev->pipe_out);
+	if (!ep_blkout || !usb_endpoint_is_bulk_out(&ep_blkout->desc)) {
+		ret = -ENODEV;
+		goto out2;
+	}
+
+	ep_intr = &intf->cur_altsetting->endpoint[2];
+	if (!usb_endpoint_is_int_in(&ep_intr->desc)) {
+		ret = -ENODEV;
+		goto out2;
+	}
+
+	dev->pipe_intr = usb_rcvintpipe(dev->udev,
+					usb_endpoint_num(&ep_intr->desc));
+
 	ret = lan78xx_bind(dev, intf);
 	if (ret < 0)
 		goto out2;
@@ -2968,19 +2936,9 @@
 
 	if (netdev->mtu > (dev->hard_mtu - netdev->hard_header_len))
 		netdev->mtu = dev->hard_mtu - netdev->hard_header_len;
+	netif_set_gso_max_size(netdev, MAX_SINGLE_PACKET_SIZE - MAX_HEADER);
 
-	dev->ep_blkin = (intf->cur_altsetting)->endpoint + 0;
-	dev->ep_blkout = (intf->cur_altsetting)->endpoint + 1;
-	dev->ep_intr = (intf->cur_altsetting)->endpoint + 2;
-
-	dev->pipe_in = usb_rcvbulkpipe(udev, BULK_IN_PIPE);
-	dev->pipe_out = usb_sndbulkpipe(udev, BULK_OUT_PIPE);
-
-	dev->pipe_intr = usb_rcvintpipe(dev->udev,
-					dev->ep_intr->desc.bEndpointAddress &
-					USB_ENDPOINT_NUMBER_MASK);
-	period = dev->ep_intr->desc.bInterval;
-
+	period = ep_intr->desc.bInterval;
 	maxp = usb_maxpacket(dev->udev, dev->pipe_intr, 0);
 	buf = kmalloc(maxp, GFP_KERNEL);
 	if (buf) {
@@ -2992,6 +2950,7 @@
 			usb_fill_int_urb(dev->urb_intr, dev->udev,
 					 dev->pipe_intr, buf, maxp,
 					 intr_complete, dev, period);
+			dev->urb_intr->transfer_flags |= URB_FREE_BUFFER;
 		}
 	}
 
--- linux-4.4.0.orig/drivers/net/usb/pegasus.c
+++ linux-4.4.0/drivers/net/usb/pegasus.c
@@ -126,40 +126,61 @@
 
 static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
+	u8 *buf;
 	int ret;
 
+	buf = kmalloc(size, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
 	ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0),
 			      PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0,
-			      indx, data, size, 1000);
+			      indx, buf, size, 1000);
 	if (ret < 0)
 		netif_dbg(pegasus, drv, pegasus->net,
 			  "%s returned %d\n", __func__, ret);
+	else if (ret <= size)
+		memcpy(data, buf, ret);
+	kfree(buf);
 	return ret;
 }
 
-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
+static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
+			 const void *data)
 {
+	u8 *buf;
 	int ret;
 
+	buf = kmemdup(data, size, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
 	ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
 			      PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0,
-			      indx, data, size, 100);
+			      indx, buf, size, 100);
 	if (ret < 0)
 		netif_dbg(pegasus, drv, pegasus->net,
 			  "%s returned %d\n", __func__, ret);
+	kfree(buf);
 	return ret;
 }
 
 static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
 {
+	u8 *buf;
 	int ret;
 
+	buf = kmemdup(&data, 1, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
 	ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
 			      PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data,
-			      indx, &data, 1, 1000);
+			      indx, buf, 1, 1000);
 	if (ret < 0)
 		netif_dbg(pegasus, drv, pegasus->net,
 			  "%s returned %d\n", __func__, ret);
+	kfree(buf);
 	return ret;
 }
 
@@ -264,7 +285,7 @@
 static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata)
 {
 	int i;
-	__u8 tmp;
+	__u8 tmp = 0;
 	__le16 retdatai;
 	int ret;
 
--- linux-4.4.0.orig/drivers/net/usb/plusb.c
+++ linux-4.4.0/drivers/net/usb/plusb.c
@@ -102,7 +102,7 @@
 }
 
 static const struct driver_info	prolific_info = {
-	.description =	"Prolific PL-2301/PL-2302/PL-25A1",
+	.description =	"Prolific PL-2301/PL-2302/PL-25A1/PL-27A1",
 	.flags =	FLAG_POINTTOPOINT | FLAG_NO_SETINT,
 		/* some PL-2302 versions seem to fail usb_set_interface() */
 	.reset =	pl_reset,
@@ -139,6 +139,17 @@
 					 * Host-to-Host Cable
 					 */
 	.driver_info =  (unsigned long) &prolific_info,
+
+},
+
+/* super speed cables */
+{
+	USB_DEVICE(0x067b, 0x27a1),     /* PL-27A1, no eeprom
+					 * also: goobay Active USB 3.0
+					 * Data Link,
+					 * Unitek Y-3501
+					 */
+	.driver_info =  (unsigned long) &prolific_info,
 },
 
 	{ },		// END
@@ -158,5 +169,5 @@
 module_usb_driver(plusb_driver);
 
 MODULE_AUTHOR("David Brownell");
-MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver");
+MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1/27A1 USB Host to Host Link Driver");
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/usb/qmi_wwan.c
+++ linux-4.4.0/drivers/net/usb/qmi_wwan.c
@@ -14,7 +14,9 @@
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
+#include <linux/if_arp.h>
 #include <linux/mii.h>
+#include <linux/rtnetlink.h>
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb/usbnet.h>
@@ -48,11 +50,104 @@
 struct qmi_wwan_state {
 	struct usb_driver *subdriver;
 	atomic_t pmcount;
-	unsigned long unused;
+	unsigned long flags;
 	struct usb_interface *control;
 	struct usb_interface *data;
 };
 
+enum qmi_wwan_flags {
+	QMI_WWAN_FLAG_RAWIP = 1 << 0,
+};
+
+enum qmi_wwan_quirks {
+	QMI_WWAN_QUIRK_DTR = 1 << 0,	/* needs "set DTR" request */
+};
+
+static void qmi_wwan_netdev_setup(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	struct qmi_wwan_state *info = (void *)&dev->data;
+
+	if (info->flags & QMI_WWAN_FLAG_RAWIP) {
+		net->header_ops      = NULL;  /* No header */
+		net->type            = ARPHRD_NONE;
+		net->hard_header_len = 0;
+		net->addr_len        = 0;
+		net->flags           = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+		netdev_dbg(net, "mode: raw IP\n");
+	} else if (!net->header_ops) { /* don't bother if already set */
+		ether_setup(net);
+		netdev_dbg(net, "mode: Ethernet\n");
+	}
+
+	/* recalculate buffers after changing hard_header_len */
+	usbnet_change_mtu(net, net->mtu);
+}
+
+static ssize_t raw_ip_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct usbnet *dev = netdev_priv(to_net_dev(d));
+	struct qmi_wwan_state *info = (void *)&dev->data;
+
+	return sprintf(buf, "%c\n", info->flags & QMI_WWAN_FLAG_RAWIP ? 'Y' : 'N');
+}
+
+static ssize_t raw_ip_store(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct usbnet *dev = netdev_priv(to_net_dev(d));
+	struct qmi_wwan_state *info = (void *)&dev->data;
+	bool enable;
+	int ret;
+
+	if (strtobool(buf, &enable))
+		return -EINVAL;
+
+	/* no change? */
+	if (enable == (info->flags & QMI_WWAN_FLAG_RAWIP))
+		return len;
+
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	/* we don't want to modify a running netdev */
+	if (netif_running(dev->net)) {
+		netdev_err(dev->net, "Cannot change a running device\n");
+		ret = -EBUSY;
+		goto err;
+	}
+
+	/* let other drivers deny the change */
+	ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net);
+	ret = notifier_to_errno(ret);
+	if (ret) {
+		netdev_err(dev->net, "Type change was refused\n");
+		goto err;
+	}
+
+	if (enable)
+		info->flags |= QMI_WWAN_FLAG_RAWIP;
+	else
+		info->flags &= ~QMI_WWAN_FLAG_RAWIP;
+	qmi_wwan_netdev_setup(dev->net);
+	call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev->net);
+	ret = len;
+err:
+	rtnl_unlock();
+	return ret;
+}
+
+static DEVICE_ATTR_RW(raw_ip);
+
+static struct attribute *qmi_wwan_sysfs_attrs[] = {
+	&dev_attr_raw_ip.attr,
+	NULL,
+};
+
+static struct attribute_group qmi_wwan_sysfs_attr_group = {
+	.name = "qmi",
+	.attrs = qmi_wwan_sysfs_attrs,
+};
+
 /* default ethernet address used by the modem */
 static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
 
@@ -80,6 +175,8 @@
  */
 static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
+	struct qmi_wwan_state *info = (void *)&dev->data;
+	bool rawip = info->flags & QMI_WWAN_FLAG_RAWIP;
 	__be16 proto;
 
 	/* This check is no longer done by usbnet */
@@ -94,15 +191,25 @@
 		proto = htons(ETH_P_IPV6);
 		break;
 	case 0x00:
+		if (rawip)
+			return 0;
 		if (is_multicast_ether_addr(skb->data))
 			return 1;
 		/* possibly bogus destination - rewrite just in case */
 		skb_reset_mac_header(skb);
 		goto fix_dest;
 	default:
+		if (rawip)
+			return 0;
 		/* pass along other packets without modifications */
 		return 1;
 	}
+	if (rawip) {
+		skb->dev = dev->net; /* normally set by eth_type_trans */
+		skb->protocol = proto;
+		return 1;
+	}
+
 	if (skb_headroom(skb) < ETH_HLEN)
 		return 0;
 	skb_push(skb, ETH_HLEN);
@@ -223,6 +330,20 @@
 	return rv;
 }
 
+/* Send CDC SetControlLineState request, setting or clearing the DTR.
+ * "Required for Autoconnect and 9x30 to wake up" according to the
+ * GobiNet driver. The requirement has been verified on an MDM9230
+ * based Sierra Wireless MC7455
+ */
+static int qmi_wwan_change_dtr(struct usbnet *dev, bool on)
+{
+	u8 intf = dev->intf->cur_altsetting->desc.bInterfaceNumber;
+
+	return usbnet_write_cmd(dev, USB_CDC_REQ_SET_CONTROL_LINE_STATE,
+				USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				on ? 0x01 : 0x00, intf, NULL, 0);
+}
+
 static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
 {
 	int status = -1;
@@ -257,12 +378,15 @@
 				"bogus CDC Union: master=%u, slave=%u\n",
 				cdc_union->bMasterInterface0,
 				cdc_union->bSlaveInterface0);
-			goto err;
+
+			/* ignore and continue... */
+			cdc_union = NULL;
+			info->data = intf;
 		}
 	}
 
 	/* errors aren't fatal - we can live with the dynamic address */
-	if (cdc_ether) {
+	if (cdc_ether && cdc_ether->wMaxSegmentSize) {
 		dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize);
 		usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
 	}
@@ -280,6 +404,29 @@
 		usb_driver_release_interface(driver, info->data);
 	}
 
+	/* disabling remote wakeup on MDM9x30 devices has the same
+	 * effect as clearing DTR. The device will not respond to QMI
+	 * requests until we set DTR again.  This is similar to a
+	 * QMI_CTL SYNC request, clearing a lot of firmware state
+	 * including the client ID allocations.
+	 *
+	 * Our usage model allows a session to span multiple
+	 * open/close events, so we must prevent the firmware from
+	 * clearing out state the clients might need.
+	 *
+	 * MDM9x30 is the first QMI chipset with USB3 support. Abuse
+	 * this fact to enable the quirk for all USB3 devices.
+	 *
+	 * There are also chipsets with the same "set DTR" requirement
+	 * but without USB3 support.  Devices based on these chips
+	 * need a quirk flag in the device ID table.
+	 */
+	if (dev->driver_info->data & QMI_WWAN_QUIRK_DTR ||
+	    le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) {
+		qmi_wwan_manage_power(dev, 1);
+		qmi_wwan_change_dtr(dev, true);
+	}
+
 	/* Never use the same address on both ends of the link, even if the
 	 * buggy firmware told us to. Or, if device is assigned the well-known
 	 * buggy firmware MAC address, replace it with a random address,
@@ -294,6 +441,7 @@
 		dev->net->dev_addr[0] &= 0xbf;	/* clear "IP" bit */
 	}
 	dev->net->netdev_ops = &qmi_wwan_netdev_ops;
+	dev->net->sysfs_groups[0] = &qmi_wwan_sysfs_attr_group;
 err:
 	return status;
 }
@@ -307,6 +455,12 @@
 	if (info->subdriver && info->subdriver->disconnect)
 		info->subdriver->disconnect(info->control);
 
+	/* disable MDM9x30 quirk */
+	if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) {
+		qmi_wwan_change_dtr(dev, false);
+		qmi_wwan_manage_power(dev, 0);
+	}
+
 	/* allow user to unbind using either control or data */
 	if (intf == info->control)
 		other = info->data;
@@ -381,6 +535,16 @@
 	.rx_fixup       = qmi_wwan_rx_fixup,
 };
 
+static const struct driver_info	qmi_wwan_info_quirk_dtr = {
+	.description	= "WWAN/QMI device",
+	.flags		= FLAG_WWAN,
+	.bind		= qmi_wwan_bind,
+	.unbind		= qmi_wwan_unbind,
+	.manage_power	= qmi_wwan_manage_power,
+	.rx_fixup       = qmi_wwan_rx_fixup,
+	.data           = QMI_WWAN_QUIRK_DTR,
+};
+
 #define HUAWEI_VENDOR_ID	0x12D1
 
 /* map QMI/wwan function by a fixed interface number */
@@ -388,6 +552,11 @@
 	USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \
 	.driver_info = (unsigned long)&qmi_wwan_info
 
+/* devices requiring "set DTR" quirk */
+#define QMI_QUIRK_SET_DTR(vend, prod, num) \
+	USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \
+	.driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr
+
 /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */
 #define QMI_GOBI1K_DEVICE(vend, prod) \
 	QMI_FIXED_INTF(vend, prod, 3)
@@ -410,6 +579,10 @@
 		USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x69),
 		.driver_info        = (unsigned long)&qmi_wwan_info,
 	},
+	{	/* Motorola Mapphone devices with MDM6600 */
+		USB_VENDOR_AND_INTERFACE_INFO(0x22b8, USB_CLASS_VENDOR_SPEC, 0xfb, 0xff),
+		.driver_info        = (unsigned long)&qmi_wwan_info,
+	},
 
 	/* 2. Combined interface devices matching on class+protocol */
 	{	/* Huawei E367 and possibly others in "Windows mode" */
@@ -485,6 +658,13 @@
 					      USB_CDC_PROTO_NONE),
 		.driver_info        = (unsigned long)&qmi_wwan_info,
 	},
+	{	/* HP lt2523 (Novatel E371) */
+		USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d,
+					      USB_CLASS_COMM,
+					      USB_CDC_SUBCLASS_ETHERNET,
+					      USB_CDC_PROTO_NONE),
+		.driver_info        = (unsigned long)&qmi_wwan_info,
+	},
 	{	/* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */
 		USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
 		.driver_info = (unsigned long)&qmi_wwan_info,
@@ -492,6 +672,7 @@
 
 	/* 3. Combined interface devices matching on interface number */
 	{QMI_FIXED_INTF(0x0408, 0xea42, 4)},	/* Yota / Megafon M100-1 */
+	{QMI_FIXED_INTF(0x05c6, 0x6001, 3)},	/* 4G LTE usb-modem U901 */
 	{QMI_FIXED_INTF(0x05c6, 0x7000, 0)},
 	{QMI_FIXED_INTF(0x05c6, 0x7001, 1)},
 	{QMI_FIXED_INTF(0x05c6, 0x7002, 1)},
@@ -521,7 +702,7 @@
 	{QMI_FIXED_INTF(0x05c6, 0x9011, 4)},
 	{QMI_FIXED_INTF(0x05c6, 0x9021, 1)},
 	{QMI_FIXED_INTF(0x05c6, 0x9022, 2)},
-	{QMI_FIXED_INTF(0x05c6, 0x9025, 4)},	/* Alcatel-sbell ASB TL131 TDD LTE  (China Mobile) */
+	{QMI_QUIRK_SET_DTR(0x05c6, 0x9025, 4)},	/* Alcatel-sbell ASB TL131 TDD LTE (China Mobile) */
 	{QMI_FIXED_INTF(0x05c6, 0x9026, 3)},
 	{QMI_FIXED_INTF(0x05c6, 0x902e, 5)},
 	{QMI_FIXED_INTF(0x05c6, 0x9031, 5)},
@@ -619,11 +800,16 @@
 	{QMI_FIXED_INTF(0x05c6, 0x9080, 8)},
 	{QMI_FIXED_INTF(0x05c6, 0x9083, 3)},
 	{QMI_FIXED_INTF(0x05c6, 0x9084, 4)},
+	{QMI_FIXED_INTF(0x05c6, 0x90b2, 3)},    /* ublox R410M */
 	{QMI_FIXED_INTF(0x05c6, 0x920d, 0)},
 	{QMI_FIXED_INTF(0x05c6, 0x920d, 5)},
 	{QMI_FIXED_INTF(0x0846, 0x68a2, 8)},
+	{QMI_FIXED_INTF(0x0846, 0x68d3, 8)},	/* Netgear Aircard 779S */
 	{QMI_FIXED_INTF(0x12d1, 0x140c, 1)},	/* Huawei E173 */
 	{QMI_FIXED_INTF(0x12d1, 0x14ac, 1)},	/* Huawei E1820 */
+	{QMI_FIXED_INTF(0x1435, 0xd181, 3)},	/* Wistron NeWeb D18Q1 */
+	{QMI_FIXED_INTF(0x1435, 0xd181, 4)},	/* Wistron NeWeb D18Q1 */
+	{QMI_FIXED_INTF(0x1435, 0xd181, 5)},	/* Wistron NeWeb D18Q1 */
 	{QMI_FIXED_INTF(0x16d8, 0x6003, 0)},	/* CMOTech 6003 */
 	{QMI_FIXED_INTF(0x16d8, 0x6007, 0)},	/* CMOTech CHE-628S */
 	{QMI_FIXED_INTF(0x16d8, 0x6008, 0)},	/* CMOTech CMU-301 */
@@ -691,6 +877,7 @@
 	{QMI_FIXED_INTF(0x19d2, 0x1255, 4)},
 	{QMI_FIXED_INTF(0x19d2, 0x1256, 4)},
 	{QMI_FIXED_INTF(0x19d2, 0x1270, 5)},	/* ZTE MF667 */
+	{QMI_FIXED_INTF(0x19d2, 0x1275, 3)},	/* ZTE P685M */
 	{QMI_FIXED_INTF(0x19d2, 0x1401, 2)},
 	{QMI_FIXED_INTF(0x19d2, 0x1402, 2)},	/* ZTE MF60 */
 	{QMI_FIXED_INTF(0x19d2, 0x1424, 2)},
@@ -698,6 +885,12 @@
 	{QMI_FIXED_INTF(0x19d2, 0x1426, 2)},	/* ZTE MF91 */
 	{QMI_FIXED_INTF(0x19d2, 0x1428, 2)},	/* Telewell TW-LTE 4G v2 */
 	{QMI_FIXED_INTF(0x19d2, 0x2002, 4)},	/* ZTE (Vodafone) K3765-Z */
+	{QMI_FIXED_INTF(0x2001, 0x7e19, 4)},	/* D-Link DWM-221 B1 */
+	{QMI_FIXED_INTF(0x2001, 0x7e35, 4)},	/* D-Link DWM-222 */
+	{QMI_FIXED_INTF(0x2001, 0x7e3d, 4)},	/* D-Link DWM-222 A2 */
+	{QMI_FIXED_INTF(0x2020, 0x2031, 4)},	/* Olicard 600 */
+	{QMI_FIXED_INTF(0x2020, 0x2033, 4)},	/* BroadMobi BM806U */
+	{QMI_FIXED_INTF(0x2020, 0x2060, 4)},	/* BroadMobi BM818 */
 	{QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
 	{QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
 	{QMI_FIXED_INTF(0x1199, 0x68a2, 8)},	/* Sierra Wireless MC7710 in QMI mode */
@@ -717,14 +910,22 @@
 	{QMI_FIXED_INTF(0x1199, 0x9061, 8)},	/* Sierra Wireless Modem */
 	{QMI_FIXED_INTF(0x1199, 0x9070, 8)},	/* Sierra Wireless MC74xx/EM74xx */
 	{QMI_FIXED_INTF(0x1199, 0x9070, 10)},	/* Sierra Wireless MC74xx/EM74xx */
-	{QMI_FIXED_INTF(0x1199, 0x9071, 8)},	/* Sierra Wireless MC74xx/EM74xx */
-	{QMI_FIXED_INTF(0x1199, 0x9071, 10)},	/* Sierra Wireless MC74xx/EM74xx */
+	{QMI_FIXED_INTF(0x1199, 0x9071, 8)},	/* Sierra Wireless MC74xx */
+	{QMI_FIXED_INTF(0x1199, 0x9071, 10)},	/* Sierra Wireless MC74xx */
+	{QMI_FIXED_INTF(0x1199, 0x9079, 8)},	/* Sierra Wireless EM74xx */
+	{QMI_FIXED_INTF(0x1199, 0x9079, 10)},	/* Sierra Wireless EM74xx */
+	{QMI_FIXED_INTF(0x1199, 0x907b, 8)},	/* Sierra Wireless EM74xx */
+	{QMI_FIXED_INTF(0x1199, 0x907b, 10)},	/* Sierra Wireless EM74xx */
+	{QMI_FIXED_INTF(0x1199, 0x9091, 8)},	/* Sierra Wireless EM7565 */
 	{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},	/* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
 	{QMI_FIXED_INTF(0x1bbb, 0x0203, 2)},	/* Alcatel L800MA */
 	{QMI_FIXED_INTF(0x2357, 0x0201, 4)},	/* TP-LINK HSUPA Modem MA180 */
 	{QMI_FIXED_INTF(0x2357, 0x9000, 4)},	/* TP-LINK MA260 */
+	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)},	/* Telit LE922A */
+	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)},	/* Telit FN980 */
+	{QMI_FIXED_INTF(0x1bc7, 0x1100, 3)},	/* Telit ME910 */
 	{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},	/* Telit LE920 */
-	{QMI_FIXED_INTF(0x1bc7, 0x1201, 2)},	/* Telit LE920 */
+	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1201, 2)},	/* Telit LE920, LE920A4 */
 	{QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)},	/* XS Stick W100-2 from 4G Systems */
 	{QMI_FIXED_INTF(0x0b3c, 0xc000, 4)},	/* Olivetti Olicard 100 */
 	{QMI_FIXED_INTF(0x0b3c, 0xc001, 4)},	/* Olivetti Olicard 120 */
@@ -734,15 +935,24 @@
 	{QMI_FIXED_INTF(0x0b3c, 0xc00a, 6)},	/* Olivetti Olicard 160 */
 	{QMI_FIXED_INTF(0x0b3c, 0xc00b, 4)},	/* Olivetti Olicard 500 */
 	{QMI_FIXED_INTF(0x1e2d, 0x0060, 4)},	/* Cinterion PLxx */
+	{QMI_QUIRK_SET_DTR(0x1e2d, 0x006f, 8)}, /* Cinterion PLS83/PLS63 */
 	{QMI_FIXED_INTF(0x1e2d, 0x0053, 4)},	/* Cinterion PHxx,PXxx */
+	{QMI_FIXED_INTF(0x1e2d, 0x0082, 4)},	/* Cinterion PHxx,PXxx (2 RmNet) */
+	{QMI_FIXED_INTF(0x1e2d, 0x0082, 5)},	/* Cinterion PHxx,PXxx (2 RmNet) */
+	{QMI_FIXED_INTF(0x1e2d, 0x0083, 4)},	/* Cinterion PHxx,PXxx (1 RmNet + USB Audio)*/
 	{QMI_FIXED_INTF(0x413c, 0x81a2, 8)},	/* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
 	{QMI_FIXED_INTF(0x413c, 0x81a3, 8)},	/* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
 	{QMI_FIXED_INTF(0x413c, 0x81a4, 8)},	/* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
 	{QMI_FIXED_INTF(0x413c, 0x81a8, 8)},	/* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
 	{QMI_FIXED_INTF(0x413c, 0x81a9, 8)},	/* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
 	{QMI_FIXED_INTF(0x413c, 0x81b1, 8)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
+	{QMI_FIXED_INTF(0x413c, 0x81b3, 8)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
 	{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},	/* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
+	{QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)},	/* HP lt4120 Snapdragon X5 LTE */
 	{QMI_FIXED_INTF(0x22de, 0x9061, 3)},	/* WeTelecom WPD-600N */
+	{QMI_FIXED_INTF(0x1e0e, 0x9001, 5)},	/* SIMCom 7230E */
+	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)},	/* Quectel EC25, EC20 R2.0  Mini PCIe */
+	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)},	/* Quectel EC21 Mini PCIe */
 
 	/* 4. Gobi 1000 devices */
 	{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
@@ -834,6 +1044,18 @@
 		id->driver_info = (unsigned long)&qmi_wwan_info;
 	}
 
+	/* There are devices where the same interface number can be
+	 * configured as different functions. We should only bind to
+	 * vendor specific functions when matching on interface number
+	 */
+	if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER &&
+	    desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) {
+		dev_dbg(&intf->dev,
+			"Rejecting interface number match for class %02x\n",
+			desc->bInterfaceClass);
+		return -ENODEV;
+	}
+
 	/* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */
 	if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) {
 		dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n");
--- linux-4.4.0.orig/drivers/net/usb/r8152.c
+++ linux-4.4.0/drivers/net/usb/r8152.c
@@ -25,12 +25,14 @@
 #include <uapi/linux/mdio.h>
 #include <linux/mdio.h>
 #include <linux/usb/cdc.h>
+#include <linux/suspend.h>
+#include <linux/acpi.h>
 
 /* Information for net-next */
 #define NETNEXT_VERSION		"08"
 
 /* Information for net */
-#define NET_VERSION		"2"
+#define NET_VERSION		"3"
 
 #define DRIVER_VERSION		"v1." NETNEXT_VERSION "." NET_VERSION
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
@@ -454,6 +456,11 @@
 /* SRAM_IMPEDANCE */
 #define RX_DRIVING_MASK		0x6000
 
+/* MAC PASSTHRU */
+#define AD_MASK			0xfee0
+#define EFUSE			0xcfdb
+#define PASS_THRU_MASK		0x1
+
 enum rtl_register_content {
 	_1000bps	= 0x10,
 	_100bps		= 0x08,
@@ -499,12 +506,14 @@
 	SELECTIVE_SUSPEND,
 	PHY_RESET,
 	SCHEDULE_NAPI,
+	DELL_TB_RX_AGG_BUG,
 };
 
 /* Define these values to match your device */
 #define VENDOR_ID_REALTEK		0x0bda
 #define VENDOR_ID_SAMSUNG		0x04e8
 #define VENDOR_ID_LENOVO		0x17ef
+#define VENDOR_ID_LINKSYS		0x13b1
 #define VENDOR_ID_NVIDIA		0x0955
 
 #define MCU_TYPE_PLA			0x0100
@@ -604,6 +613,9 @@
 	struct delayed_work schedule;
 	struct mii_if_info mii;
 	struct mutex control;	/* use for hw setting */
+#ifdef CONFIG_PM_SLEEP
+	struct notifier_block pm_notifier;
+#endif
 
 	struct rtl_ops {
 		void (*init)(struct r8152 *);
@@ -666,8 +678,11 @@
 	ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
 			      RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
 			      value, index, tmp, size, 500);
+	if (ret < 0)
+		memset(data, 0xff, size);
+	else
+		memcpy(data, tmp, size);
 
-	memcpy(data, tmp, size);
 	kfree(tmp);
 
 	return ret;
@@ -1026,6 +1041,65 @@
 	return ret;
 }
 
+/* Devices containing RTL8153-AD can support a persistent
+ * host system provided MAC address.
+ * Examples of this are Dell TB15 and Dell WD15 docks
+ */
+static int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	int ret = -EINVAL;
+	u32 ocp_data;
+	unsigned char buf[6];
+
+	/* test for -AD variant of RTL8153 */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+	if ((ocp_data & AD_MASK) != 0x1000)
+		return -ENODEV;
+
+	/* test for MAC address pass-through bit */
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE);
+	if ((ocp_data & PASS_THRU_MASK) != 1)
+		return -ENODEV;
+
+	/* returns _AUXMAC_#AABBCCDDEEFF# */
+	status = acpi_evaluate_object(NULL, "\\_SB.AMAC", NULL, &buffer);
+	obj = (union acpi_object *)buffer.pointer;
+	if (!ACPI_SUCCESS(status))
+		return -ENODEV;
+	if (obj->type != ACPI_TYPE_BUFFER || obj->string.length != 0x17) {
+		netif_warn(tp, probe, tp->netdev,
+			   "Invalid buffer when reading pass-thru MAC addr: "
+			   "(%d, %d)\n",
+			   obj->type, obj->string.length);
+		goto amacout;
+	}
+	if (strncmp(obj->string.pointer, "_AUXMAC_#", 9) != 0 ||
+	    strncmp(obj->string.pointer + 0x15, "#", 1) != 0) {
+		netif_warn(tp, probe, tp->netdev,
+			   "Invalid header when reading pass-thru MAC addr\n");
+		goto amacout;
+	}
+	ret = hex2bin(buf, obj->string.pointer + 9, 6);
+	if (!(ret == 0 && is_valid_ether_addr(buf))) {
+		netif_warn(tp, probe, tp->netdev,
+			   "Invalid MAC when reading pass-thru MAC addr: "
+			   "%d, %pM\n", ret, buf);
+		ret = -EINVAL;
+		goto amacout;
+	}
+	memcpy(sa->sa_data, buf, 6);
+	ether_addr_copy(tp->netdev->dev_addr, sa->sa_data);
+	netif_info(tp, probe, tp->netdev,
+		   "Using pass-thru MAC addr %pM\n", sa->sa_data);
+
+amacout:
+	kfree(obj);
+	return ret;
+}
+
 static int set_ethernet_addr(struct r8152 *tp)
 {
 	struct net_device *dev = tp->netdev;
@@ -1034,8 +1108,15 @@
 
 	if (tp->version == RTL_VER_01)
 		ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data);
-	else
-		ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data);
+	else {
+		/* if this is not an RTL8153-AD, no eFuse mac pass thru set,
+		 * or system doesn't provide valid _SB.AMAC this will be
+		 * be expected to non-zero
+		 */
+		ret = vendor_mac_passthru_addr_read(tp, &sa);
+		if (ret < 0)
+			ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data);
+	}
 
 	if (ret < 0) {
 		netif_err(tp, probe, dev, "Get ether addr fail\n");
@@ -1191,7 +1272,9 @@
 			   "Stop submitting intr, status %d\n", status);
 		return;
 	case -EOVERFLOW:
-		netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n");
+		if (net_ratelimit())
+			netif_info(tp, intr, tp->netdev,
+				   "intr status -EOVERFLOW\n");
 		goto resubmit;
 	/* -EPIPE:  should clear the halt */
 	default:
@@ -1207,6 +1290,7 @@
 		}
 	} else {
 		if (netif_carrier_ok(tp->netdev)) {
+			netif_stop_queue(tp->netdev);
 			set_bit(RTL8152_LINK_CHG, &tp->flags);
 			schedule_delayed_work(&tp->schedule, 0);
 		}
@@ -1277,6 +1361,7 @@
 	spin_lock_init(&tp->rx_lock);
 	spin_lock_init(&tp->tx_lock);
 	INIT_LIST_HEAD(&tp->tx_free);
+	INIT_LIST_HEAD(&tp->rx_done);
 	skb_queue_head_init(&tp->tx_queue);
 	skb_queue_head_init(&tp->rx_queue);
 
@@ -1603,11 +1688,14 @@
 
 		tx_data += len;
 		agg->skb_len += len;
-		agg->skb_num++;
+		agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1;
 
 		dev_kfree_skb_any(skb);
 
 		remain = agg_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
+
+		if (test_bit(DELL_TB_RX_AGG_BUG, &tp->flags))
+			break;
 	}
 
 	if (!skb_queue_empty(&skb_head)) {
@@ -1645,7 +1733,7 @@
 	u8 checksum = CHECKSUM_NONE;
 	u32 opts2, opts3;
 
-	if (tp->version == RTL_VER_01)
+	if (!(tp->netdev->features & NETIF_F_RXCSUM))
 		goto return_result;
 
 	opts2 = le32_to_cpu(rx_desc->opts2);
@@ -1851,6 +1939,9 @@
 		napi_complete(napi);
 		if (!list_empty(&tp->rx_done))
 			napi_schedule(napi);
+		else if (!skb_queue_empty(&tp->tx_queue) &&
+			 !list_empty(&tp->tx_free))
+			napi_schedule(napi);
 	}
 
 	return work_done;
@@ -1938,7 +2029,6 @@
 	__le32 tmp[2];
 	u32 ocp_data;
 
-	clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
 	netif_stop_queue(netdev);
 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
 	ocp_data &= ~RCR_ACPT_ALL;
@@ -2424,8 +2514,6 @@
 	u16 data;
 	int i;
 
-	clear_bit(PHY_RESET, &tp->flags);
-
 	data = r8152_mdio_read(tp, MII_BMCR);
 
 	/* don't reset again before the previous one complete */
@@ -2455,23 +2543,23 @@
 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
 }
 
-static void r8152b_disable_aldps(struct r8152 *tp)
+static void r8152_aldps_en(struct r8152 *tp, bool enable)
 {
-	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
-	msleep(20);
-}
-
-static inline void r8152b_enable_aldps(struct r8152 *tp)
-{
-	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
-					    LINKENA | DIS_SDSAVE);
+	if (enable) {
+		ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
+						    LINKENA | DIS_SDSAVE);
+	} else {
+		ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA |
+						    DIS_SDSAVE);
+		msleep(20);
+	}
 }
 
 static void rtl8152_disable(struct r8152 *tp)
 {
-	r8152b_disable_aldps(tp);
+	r8152_aldps_en(tp, false);
 	rtl_disable(tp);
-	r8152b_enable_aldps(tp);
+	r8152_aldps_en(tp, true);
 }
 
 static void r8152b_hw_phy_cfg(struct r8152 *tp)
@@ -2728,6 +2816,9 @@
 	/* rx aggregation */
 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
 	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
+	if (test_bit(DELL_TB_RX_AGG_BUG, &tp->flags))
+		ocp_data |= RX_AGG_DISABLE;
+
 	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
 }
 
@@ -2783,30 +2874,26 @@
 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
 }
 
-static void r8153_disable_aldps(struct r8152 *tp)
+static void r8153_aldps_en(struct r8152 *tp, bool enable)
 {
 	u16 data;
 
 	data = ocp_reg_read(tp, OCP_POWER_CFG);
-	data &= ~EN_ALDPS;
-	ocp_reg_write(tp, OCP_POWER_CFG, data);
-	msleep(20);
-}
-
-static void r8153_enable_aldps(struct r8152 *tp)
-{
-	u16 data;
-
-	data = ocp_reg_read(tp, OCP_POWER_CFG);
-	data |= EN_ALDPS;
-	ocp_reg_write(tp, OCP_POWER_CFG, data);
+	if (enable) {
+		data |= EN_ALDPS;
+		ocp_reg_write(tp, OCP_POWER_CFG, data);
+	} else {
+		data &= ~EN_ALDPS;
+		ocp_reg_write(tp, OCP_POWER_CFG, data);
+		msleep(20);
+	}
 }
 
 static void rtl8153_disable(struct r8152 *tp)
 {
-	r8153_disable_aldps(tp);
+	r8153_aldps_en(tp, false);
 	rtl_disable(tp);
-	r8153_enable_aldps(tp);
+	r8153_aldps_en(tp, true);
 	usb_enable_lpm(tp->udev);
 }
 
@@ -2884,10 +2971,9 @@
 	r8152_mdio_write(tp, MII_ADVERTISE, anar);
 	r8152_mdio_write(tp, MII_BMCR, bmcr);
 
-	if (test_bit(PHY_RESET, &tp->flags)) {
+	if (test_and_clear_bit(PHY_RESET, &tp->flags)) {
 		int i;
 
-		clear_bit(PHY_RESET, &tp->flags);
 		for (i = 0; i < 50; i++) {
 			msleep(20);
 			if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
@@ -2896,7 +2982,6 @@
 	}
 
 out:
-
 	return ret;
 }
 
@@ -2905,9 +2990,9 @@
 	if (test_bit(RTL8152_UNPLUG, &tp->flags))
 		return;
 
-	r8152b_disable_aldps(tp);
+	r8152_aldps_en(tp, false);
 	r8152b_exit_oob(tp);
-	r8152b_enable_aldps(tp);
+	r8152_aldps_en(tp, true);
 }
 
 static void rtl8152_down(struct r8152 *tp)
@@ -2918,9 +3003,9 @@
 	}
 
 	r8152_power_cut_en(tp, false);
-	r8152b_disable_aldps(tp);
+	r8152_aldps_en(tp, false);
 	r8152b_enter_oob(tp);
-	r8152b_enable_aldps(tp);
+	r8152_aldps_en(tp, true);
 }
 
 static void rtl8153_up(struct r8152 *tp)
@@ -2929,9 +3014,9 @@
 		return;
 
 	r8153_u1u2en(tp, false);
-	r8153_disable_aldps(tp);
+	r8153_aldps_en(tp, false);
 	r8153_first_init(tp);
-	r8153_enable_aldps(tp);
+	r8153_aldps_en(tp, true);
 	r8153_u2p3en(tp, true);
 	r8153_u1u2en(tp, true);
 	usb_enable_lpm(tp->udev);
@@ -2947,9 +3032,9 @@
 	r8153_u1u2en(tp, false);
 	r8153_u2p3en(tp, false);
 	r8153_power_cut_en(tp, false);
-	r8153_disable_aldps(tp);
+	r8153_aldps_en(tp, false);
 	r8153_enter_oob(tp);
-	r8153_enable_aldps(tp);
+	r8153_aldps_en(tp, true);
 }
 
 static bool rtl8152_in_nway(struct r8152 *tp)
@@ -2983,17 +3068,22 @@
 	struct net_device *netdev = tp->netdev;
 	u8 speed;
 
-	clear_bit(RTL8152_LINK_CHG, &tp->flags);
 	speed = rtl8152_get_speed(tp);
 
 	if (speed & LINK_STATUS) {
 		if (!netif_carrier_ok(netdev)) {
 			tp->rtl_ops.enable(tp);
 			set_bit(RTL8152_SET_RX_MODE, &tp->flags);
+			netif_stop_queue(netdev);
 			napi_disable(&tp->napi);
 			netif_carrier_on(netdev);
 			rtl_start_rx(tp);
 			napi_enable(&tp->napi);
+			netif_wake_queue(netdev);
+			netif_info(tp, link, netdev, "carrier on\n");
+		} else if (netif_queue_stopped(netdev) &&
+			   skb_queue_len(&tp->tx_queue) < tp->tx_qlen) {
+			netif_wake_queue(netdev);
 		}
 	} else {
 		if (netif_carrier_ok(netdev)) {
@@ -3001,6 +3091,7 @@
 			napi_disable(&tp->napi);
 			tp->rtl_ops.disable(tp);
 			napi_enable(&tp->napi);
+			netif_info(tp, link, netdev, "carrier off\n");
 		}
 	}
 }
@@ -3026,20 +3117,18 @@
 		goto out1;
 	}
 
-	if (test_bit(RTL8152_LINK_CHG, &tp->flags))
+	if (test_and_clear_bit(RTL8152_LINK_CHG, &tp->flags))
 		set_carrier(tp);
 
-	if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
+	if (test_and_clear_bit(RTL8152_SET_RX_MODE, &tp->flags))
 		_rtl8152_set_rx_mode(tp->netdev);
 
 	/* don't schedule napi before linking */
-	if (test_bit(SCHEDULE_NAPI, &tp->flags) &&
-	    netif_carrier_ok(tp->netdev)) {
-		clear_bit(SCHEDULE_NAPI, &tp->flags);
+	if (test_and_clear_bit(SCHEDULE_NAPI, &tp->flags) &&
+	    netif_carrier_ok(tp->netdev))
 		napi_schedule(&tp->napi);
-	}
 
-	if (test_bit(PHY_RESET, &tp->flags))
+	if (test_and_clear_bit(PHY_RESET, &tp->flags))
 		rtl_phy_reset(tp);
 
 	mutex_unlock(&tp->control);
@@ -3048,6 +3137,33 @@
 	usb_autopm_put_interface(tp->intf);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rtl_notifier(struct notifier_block *nb, unsigned long action,
+			void *data)
+{
+	struct r8152 *tp = container_of(nb, struct r8152, pm_notifier);
+
+	switch (action) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		usb_autopm_get_interface(tp->intf);
+		break;
+
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		usb_autopm_put_interface(tp->intf);
+		break;
+
+	case PM_POST_RESTORE:
+	case PM_RESTORE_PREPARE:
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+#endif
+
 static int rtl8152_open(struct net_device *netdev)
 {
 	struct r8152 *tp = netdev_priv(netdev);
@@ -3090,6 +3206,10 @@
 	mutex_unlock(&tp->control);
 
 	usb_autopm_put_interface(tp->intf);
+#ifdef CONFIG_PM_SLEEP
+	tp->pm_notifier.notifier_call = rtl_notifier;
+	register_pm_notifier(&tp->pm_notifier);
+#endif
 
 out:
 	return res;
@@ -3100,7 +3220,11 @@
 	struct r8152 *tp = netdev_priv(netdev);
 	int res = 0;
 
-	napi_disable(&tp->napi);
+#ifdef CONFIG_PM_SLEEP
+	unregister_pm_notifier(&tp->pm_notifier);
+#endif
+	if (!test_bit(RTL8152_UNPLUG, &tp->flags))
+		napi_disable(&tp->napi);
 	clear_bit(WORK_ENABLE, &tp->flags);
 	usb_kill_urb(tp->intr_urb);
 	cancel_delayed_work_sync(&tp->schedule);
@@ -3238,7 +3362,7 @@
 	if (test_bit(RTL8152_UNPLUG, &tp->flags))
 		return;
 
-	r8152b_disable_aldps(tp);
+	r8152_aldps_en(tp, false);
 
 	if (tp->version == RTL_VER_01) {
 		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
@@ -3260,7 +3384,7 @@
 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
 
 	r8152b_enable_eee(tp);
-	r8152b_enable_aldps(tp);
+	r8152_aldps_en(tp, true);
 	r8152b_enable_fc(tp);
 	rtl_tally_reset(tp);
 
@@ -3278,21 +3402,27 @@
 	if (test_bit(RTL8152_UNPLUG, &tp->flags))
 		return;
 
-	r8153_disable_aldps(tp);
+	r8153_aldps_en(tp, false);
 	r8153_u1u2en(tp, false);
 
 	for (i = 0; i < 500; i++) {
 		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
 		    AUTOLOAD_DONE)
 			break;
+
 		msleep(20);
+		if (test_bit(RTL8152_UNPLUG, &tp->flags))
+			break;
 	}
 
 	for (i = 0; i < 500; i++) {
 		ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK;
 		if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN)
 			break;
+
 		msleep(20);
+		if (test_bit(RTL8152_UNPLUG, &tp->flags))
+			break;
 	}
 
 	usb_disable_lpm(tp->udev);
@@ -3367,7 +3497,7 @@
 		       EEE_SPDWN_EN);
 
 	r8153_enable_eee(tp);
-	r8153_enable_aldps(tp);
+	r8153_aldps_en(tp, true);
 	r8152b_enable_fc(tp);
 	rtl_tally_reset(tp);
 	r8153_u2p3en(tp, true);
@@ -3385,12 +3515,12 @@
 	if (!netif_running(netdev))
 		return 0;
 
+	netif_stop_queue(netdev);
 	napi_disable(&tp->napi);
 	clear_bit(WORK_ENABLE, &tp->flags);
 	usb_kill_urb(tp->intr_urb);
 	cancel_delayed_work_sync(&tp->schedule);
 	if (netif_carrier_ok(netdev)) {
-		netif_stop_queue(netdev);
 		mutex_lock(&tp->control);
 		tp->rtl_ops.disable(tp);
 		mutex_unlock(&tp->control);
@@ -3415,12 +3545,14 @@
 	if (netif_carrier_ok(netdev)) {
 		mutex_lock(&tp->control);
 		tp->rtl_ops.enable(tp);
+		rtl_start_rx(tp);
 		rtl8152_set_rx_mode(netdev);
 		mutex_unlock(&tp->control);
-		netif_wake_queue(netdev);
 	}
 
 	napi_enable(&tp->napi);
+	netif_wake_queue(netdev);
+	usb_submit_urb(tp->intr_urb, GFP_KERNEL);
 
 	return 0;
 }
@@ -3442,43 +3574,93 @@
 	 */
 	if (!sw_linking && tp->rtl_ops.in_nway(tp))
 		return true;
+	else if (!skb_queue_empty(&tp->tx_queue))
+		return true;
 	else
 		return false;
 }
 
-static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
+static int rtl8152_rumtime_suspend(struct r8152 *tp)
 {
-	struct r8152 *tp = usb_get_intfdata(intf);
 	struct net_device *netdev = tp->netdev;
 	int ret = 0;
 
-	mutex_lock(&tp->control);
+	if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
+		u32 rcr = 0;
 
-	if (PMSG_IS_AUTO(message)) {
-		if (netif_running(netdev) && delay_autosuspend(tp)) {
+		if (delay_autosuspend(tp)) {
 			ret = -EBUSY;
 			goto out1;
 		}
 
-		set_bit(SELECTIVE_SUSPEND, &tp->flags);
-	} else {
-		netif_device_detach(netdev);
+		if (netif_carrier_ok(netdev)) {
+			u32 ocp_data;
+
+			rcr = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+			ocp_data = rcr & ~RCR_ACPT_ALL;
+			ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+			rxdy_gated_en(tp, true);
+			ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA,
+						 PLA_OOB_CTRL);
+			if (!(ocp_data & RXFIFO_EMPTY)) {
+				rxdy_gated_en(tp, false);
+				ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);
+				ret = -EBUSY;
+				goto out1;
+			}
+		}
+
+		clear_bit(WORK_ENABLE, &tp->flags);
+		usb_kill_urb(tp->intr_urb);
+
+		rtl_runtime_suspend_enable(tp, true);
+
+		if (netif_carrier_ok(netdev)) {
+			napi_disable(&tp->napi);
+			rtl_stop_rx(tp);
+			rxdy_gated_en(tp, false);
+			ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);
+			napi_enable(&tp->napi);
+		}
 	}
 
+	set_bit(SELECTIVE_SUSPEND, &tp->flags);
+
+out1:
+	return ret;
+}
+
+static int rtl8152_system_suspend(struct r8152 *tp)
+{
+	struct net_device *netdev = tp->netdev;
+	int ret = 0;
+
+	netif_device_detach(netdev);
+
 	if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
 		clear_bit(WORK_ENABLE, &tp->flags);
 		usb_kill_urb(tp->intr_urb);
 		napi_disable(&tp->napi);
-		if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
-			rtl_stop_rx(tp);
-			rtl_runtime_suspend_enable(tp, true);
-		} else {
-			cancel_delayed_work_sync(&tp->schedule);
-			tp->rtl_ops.down(tp);
-		}
+		cancel_delayed_work_sync(&tp->schedule);
+		tp->rtl_ops.down(tp);
 		napi_enable(&tp->napi);
 	}
-out1:
+
+	return ret;
+}
+
+static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct r8152 *tp = usb_get_intfdata(intf);
+	int ret;
+
+	mutex_lock(&tp->control);
+
+	if (PMSG_IS_AUTO(message))
+		ret = rtl8152_rumtime_suspend(tp);
+	else
+		ret = rtl8152_system_suspend(tp);
+
 	mutex_unlock(&tp->control);
 
 	return ret;
@@ -3501,8 +3683,18 @@
 			clear_bit(SELECTIVE_SUSPEND, &tp->flags);
 			napi_disable(&tp->napi);
 			set_bit(WORK_ENABLE, &tp->flags);
-			if (netif_carrier_ok(tp->netdev))
-				rtl_start_rx(tp);
+
+			if (netif_carrier_ok(tp->netdev)) {
+				if (rtl8152_get_speed(tp) & LINK_STATUS) {
+					rtl_start_rx(tp);
+				} else {
+					netif_carrier_off(tp->netdev);
+					tp->rtl_ops.disable(tp);
+					netif_info(tp, link, tp->netdev,
+						   "linking down\n");
+				}
+			}
+
 			napi_enable(&tp->napi);
 		} else {
 			tp->rtl_ops.up(tp);
@@ -3561,6 +3753,9 @@
 	if (!rtl_can_wakeup(tp))
 		return -EOPNOTSUPP;
 
+	if (wol->wolopts & ~WAKE_ANY)
+		return -EINVAL;
+
 	ret = usb_autopm_get_interface(tp->intf);
 	if (ret < 0)
 		goto out_set_wol;
@@ -4135,6 +4330,9 @@
 		return -ENODEV;
 	}
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 3)
+		return -ENODEV;
+
 	usb_reset_device(udev);
 	netdev = alloc_etherdev(sizeof(struct r8152));
 	if (!netdev) {
@@ -4173,6 +4371,17 @@
 				NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
 				NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
 
+	if (tp->version == RTL_VER_01) {
+		netdev->features &= ~NETIF_F_RXCSUM;
+		netdev->hw_features &= ~NETIF_F_RXCSUM;
+	}
+
+	if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 &&
+	    udev->serial && !strcmp(udev->serial, "000001000000")) {
+		dev_info(&udev->dev, "Dell TB16 Dock, disable RX aggregation");
+		set_bit(DELL_TB_RX_AGG_BUG, &tp->flags);
+	}
+
 	netdev->ethtool_ops = &ops;
 	netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE);
 
@@ -4197,6 +4406,11 @@
 
 	intf->needs_remote_wakeup = 1;
 
+	if (!rtl_can_wakeup(tp))
+		__rtl_set_wol(tp, 0);
+	else
+		tp->saved_wolopts = __rtl_get_wol(tp);
+
 	tp->rtl_ops.init(tp);
 	set_ethernet_addr(tp);
 
@@ -4209,10 +4423,6 @@
 		goto out1;
 	}
 
-	if (!rtl_can_wakeup(tp))
-		__rtl_set_wol(tp, 0);
-
-	tp->saved_wolopts = __rtl_get_wol(tp);
 	if (tp->saved_wolopts)
 		device_set_wakeup_enable(&udev->dev, true);
 	else
@@ -4271,6 +4481,7 @@
 	{REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x7205)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x304f)},
+	{REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA,  0x09ff)},
 	{}
 };
--- linux-4.4.0.orig/drivers/net/usb/rndis_host.c
+++ linux-4.4.0/drivers/net/usb/rndis_host.c
@@ -213,7 +213,7 @@
 			dev_dbg(&info->control->dev,
 				"rndis response error, code %d\n", retval);
 		}
-		msleep(20);
+		msleep(40);
 	}
 	dev_dbg(&info->control->dev, "rndis response timeout\n");
 	return -ETIMEDOUT;
@@ -398,7 +398,7 @@
 	reply_len = sizeof *phym;
 	retval = rndis_query(dev, intf, u.buf,
 			     RNDIS_OID_GEN_PHYSICAL_MEDIUM,
-			     0, (void **) &phym, &reply_len);
+			     reply_len, (void **)&phym, &reply_len);
 	if (retval != 0 || !phym) {
 		/* OID is optional so don't fail here. */
 		phym_unspec = cpu_to_le32(RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED);
--- linux-4.4.0.orig/drivers/net/usb/rtl8150.c
+++ linux-4.4.0/drivers/net/usb/rtl8150.c
@@ -155,16 +155,36 @@
 */
 static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
-			       RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
-			       indx, 0, data, size, 500);
-}
+	void *buf;
+	int ret;
 
-static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
-{
-	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
-			       RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
-			       indx, 0, data, size, 500);
+	buf = kmalloc(size, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+			      RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
+			      indx, 0, buf, size, 500);
+	if (ret > 0 && ret <= size)
+		memcpy(data, buf, ret);
+	kfree(buf);
+	return ret;
+}
+
+static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data)
+{
+	void *buf;
+	int ret;
+
+	buf = kmemdup(data, size, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+			      RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
+			      indx, 0, buf, size, 500);
+	kfree(buf);
+	return ret;
 }
 
 static void async_set_reg_cb(struct urb *urb)
@@ -257,12 +277,20 @@
 		return 1;
 }
 
-static inline void set_ethernet_addr(rtl8150_t * dev)
+static void set_ethernet_addr(rtl8150_t *dev)
 {
-	u8 node_id[6];
+	u8 node_id[ETH_ALEN];
+	int ret;
+
+	ret = get_registers(dev, IDR, sizeof(node_id), node_id);
 
-	get_registers(dev, IDR, sizeof(node_id), node_id);
-	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
+	if (ret == sizeof(node_id)) {
+		ether_addr_copy(dev->netdev->dev_addr, node_id);
+	} else {
+		eth_hw_addr_random(dev->netdev);
+		netdev_notice(dev->netdev, "Assigned a random MAC address: %pM\n",
+			      dev->netdev->dev_addr);
+	}
 }
 
 static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
@@ -661,7 +689,7 @@
 		   (netdev->flags & IFF_ALLMULTI)) {
 		rx_creg &= 0xfffe;
 		rx_creg |= 0x0002;
-		dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name);
+		dev_dbg(&netdev->dev, "%s: allmulti set\n", netdev->name);
 	} else {
 		/* ~RX_MULTICAST, ~RX_PROMISCUOUS */
 		rx_creg &= 0x00fc;
--- linux-4.4.0.orig/drivers/net/usb/sierra_net.c
+++ linux-4.4.0/drivers/net/usb/sierra_net.c
@@ -73,8 +73,6 @@
 /* Private data structure */
 struct sierra_net_data {
 
-	u8 ethr_hdr_tmpl[ETH_HLEN]; /* ethernet header template for rx'd pkts */
-
 	u16 link_up;		/* air link up or down */
 	u8 tx_hdr_template[4];	/* part of HIP hdr for tx'd packets */
 
@@ -122,6 +120,7 @@
 
 /* LSI Protocol types */
 #define SIERRA_NET_PROTOCOL_UMTS      0x01
+#define SIERRA_NET_PROTOCOL_UMTS_DS   0x04
 /* LSI Coverage */
 #define SIERRA_NET_COVERAGE_NONE      0x00
 #define SIERRA_NET_COVERAGE_NOPACKET  0x01
@@ -129,7 +128,8 @@
 /* LSI Session */
 #define SIERRA_NET_SESSION_IDLE       0x00
 /* LSI Link types */
-#define SIERRA_NET_AS_LINK_TYPE_IPv4  0x00
+#define SIERRA_NET_AS_LINK_TYPE_IPV4  0x00
+#define SIERRA_NET_AS_LINK_TYPE_IPV6  0x02
 
 struct lsi_umts {
 	u8 protocol;
@@ -137,9 +137,14 @@
 	__be16 length;
 	/* eventually use a union for the rest - assume umts for now */
 	u8 coverage;
-	u8 unused2[41];
+	u8 network_len; /* network name len */
+	u8 network[40]; /* network name (UCS2, bigendian) */
 	u8 session_state;
 	u8 unused3[33];
+} __packed;
+
+struct lsi_umts_single {
+	struct lsi_umts lsi;
 	u8 link_type;
 	u8 pdp_addr_len; /* NW-supplied PDP address len */
 	u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */
@@ -158,10 +163,31 @@
 	u8 reserved[8];
 } __packed;
 
+struct lsi_umts_dual {
+	struct lsi_umts lsi;
+	u8 pdp_addr4_len; /* NW-supplied PDP IPv4 address len */
+	u8 pdp_addr4[4];  /* NW-supplied PDP IPv4 address (bigendian)) */
+	u8 pdp_addr6_len; /* NW-supplied PDP IPv6 address len */
+	u8 pdp_addr6[16]; /* NW-supplied PDP IPv6 address (bigendian)) */
+	u8 unused4[23];
+	u8 dns1_addr4_len; /* NW-supplied 1st DNS v4 address len (bigendian) */
+	u8 dns1_addr4[4];  /* NW-supplied 1st DNS v4 address */
+	u8 dns1_addr6_len; /* NW-supplied 1st DNS v6 address len */
+	u8 dns1_addr6[16]; /* NW-supplied 1st DNS v6 address (bigendian)*/
+	u8 dns2_addr4_len; /* NW-supplied 2nd DNS v4 address len (bigendian) */
+	u8 dns2_addr4[4];  /* NW-supplied 2nd DNS v4 address */
+	u8 dns2_addr6_len; /* NW-supplied 2nd DNS v6 address len */
+	u8 dns2_addr6[16]; /* NW-supplied 2nd DNS v6 address (bigendian)*/
+	u8 unused5[68];
+} __packed;
+
 #define SIERRA_NET_LSI_COMMON_LEN      4
-#define SIERRA_NET_LSI_UMTS_LEN        (sizeof(struct lsi_umts))
+#define SIERRA_NET_LSI_UMTS_LEN        (sizeof(struct lsi_umts_single))
 #define SIERRA_NET_LSI_UMTS_STATUS_LEN \
 	(SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN)
+#define SIERRA_NET_LSI_UMTS_DS_LEN     (sizeof(struct lsi_umts_dual))
+#define SIERRA_NET_LSI_UMTS_DS_STATUS_LEN \
+	(SIERRA_NET_LSI_UMTS_DS_LEN - SIERRA_NET_LSI_COMMON_LEN)
 
 /* Forward definitions */
 static void sierra_sync_timer(unsigned long syncdata);
@@ -191,10 +217,11 @@
 	dev->data[0] = (unsigned long)priv;
 }
 
-/* is packet IPv4 */
+/* is packet IPv4/IPv6 */
 static inline int is_ip(struct sk_buff *skb)
 {
-	return skb->protocol == cpu_to_be16(ETH_P_IP);
+	return skb->protocol == cpu_to_be16(ETH_P_IP) ||
+	       skb->protocol == cpu_to_be16(ETH_P_IPV6);
 }
 
 /*
@@ -350,49 +377,54 @@
 static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
 {
 	struct lsi_umts *lsi = (struct lsi_umts *)data;
+	u32 expected_length;
 
-	if (datalen < sizeof(struct lsi_umts)) {
-		netdev_err(dev->net, "%s: Data length %d, exp %Zu\n",
-				__func__, datalen,
-				sizeof(struct lsi_umts));
+	if (datalen < sizeof(struct lsi_umts_single)) {
+		netdev_err(dev->net, "%s: Data length %d, exp >= %Zu\n",
+			   __func__, datalen, sizeof(struct lsi_umts_single));
 		return -1;
 	}
 
-	if (lsi->length != cpu_to_be16(SIERRA_NET_LSI_UMTS_STATUS_LEN)) {
-		netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n",
-				__func__, be16_to_cpu(lsi->length),
-				(u32)SIERRA_NET_LSI_UMTS_STATUS_LEN);
-		return -1;
+	/* Validate the session state */
+	if (lsi->session_state == SIERRA_NET_SESSION_IDLE) {
+		netdev_err(dev->net, "Session idle, 0x%02x\n",
+			   lsi->session_state);
+		return 0;
 	}
 
 	/* Validate the protocol  - only support UMTS for now */
-	if (lsi->protocol != SIERRA_NET_PROTOCOL_UMTS) {
+	if (lsi->protocol == SIERRA_NET_PROTOCOL_UMTS) {
+		struct lsi_umts_single *single = (struct lsi_umts_single *)lsi;
+
+		/* Validate the link type */
+		if (single->link_type != SIERRA_NET_AS_LINK_TYPE_IPV4 &&
+		    single->link_type != SIERRA_NET_AS_LINK_TYPE_IPV6) {
+			netdev_err(dev->net, "Link type unsupported: 0x%02x\n",
+				   single->link_type);
+			return -1;
+		}
+		expected_length = SIERRA_NET_LSI_UMTS_STATUS_LEN;
+	} else if (lsi->protocol == SIERRA_NET_PROTOCOL_UMTS_DS) {
+		expected_length = SIERRA_NET_LSI_UMTS_DS_STATUS_LEN;
+	} else {
 		netdev_err(dev->net, "Protocol unsupported, 0x%02x\n",
-			lsi->protocol);
+			   lsi->protocol);
 		return -1;
 	}
 
-	/* Validate the link type */
-	if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) {
-		netdev_err(dev->net, "Link type unsupported: 0x%02x\n",
-			lsi->link_type);
+	if (be16_to_cpu(lsi->length) != expected_length) {
+		netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n",
+			   __func__, be16_to_cpu(lsi->length), expected_length);
 		return -1;
 	}
 
 	/* Validate the coverage */
-	if (lsi->coverage == SIERRA_NET_COVERAGE_NONE
-	   || lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) {
+	if (lsi->coverage == SIERRA_NET_COVERAGE_NONE ||
+	    lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) {
 		netdev_err(dev->net, "No coverage, 0x%02x\n", lsi->coverage);
 		return 0;
 	}
 
-	/* Validate the session state */
-	if (lsi->session_state == SIERRA_NET_SESSION_IDLE) {
-		netdev_err(dev->net, "Session idle, 0x%02x\n",
-			lsi->session_state);
-		return 0;
-	}
-
 	/* Set link_sense true */
 	return 1;
 }
@@ -662,7 +694,6 @@
 	u8	numendpoints;
 	u16	fwattr = 0;
 	int	status;
-	struct ethhdr *eth;
 	struct sierra_net_data *priv;
 	static const u8 sync_tmplate[sizeof(priv->sync_msg)] = {
 		0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00};
@@ -700,11 +731,6 @@
 	dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter);
 	dev->net->dev_addr[ETH_ALEN-1] = ifacenum;
 
-	/* we will have to manufacture ethernet headers, prepare template */
-	eth = (struct ethhdr *)priv->ethr_hdr_tmpl;
-	memcpy(&eth->h_dest, dev->net->dev_addr, ETH_ALEN);
-	eth->h_proto = cpu_to_be16(ETH_P_IP);
-
 	/* prepare shutdown message template */
 	memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg));
 	/* set context index initially to 0 - prepares tx hdr template */
@@ -833,9 +859,14 @@
 
 		skb_pull(skb, hh.hdrlen);
 
-		/* We are going to accept this packet, prepare it */
-		memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl,
-			ETH_HLEN);
+		/* We are going to accept this packet, prepare it.
+		 * In case protocol is IPv6, keep it, otherwise force IPv4.
+		 */
+		skb_reset_mac_header(skb);
+		if (eth_hdr(skb)->h_proto != cpu_to_be16(ETH_P_IPV6))
+			eth_hdr(skb)->h_proto = cpu_to_be16(ETH_P_IP);
+		eth_zero_addr(eth_hdr(skb)->h_source);
+		memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
 
 		/* Last packet in batch handled by usbnet */
 		if (hh.payload_len.word == skb->len)
--- linux-4.4.0.orig/drivers/net/usb/smsc75xx.c
+++ linux-4.4.0/drivers/net/usb/smsc75xx.c
@@ -81,6 +81,9 @@
 module_param(turbo_mode, bool, 0644);
 MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
 
+static int smsc75xx_link_ok_nopm(struct usbnet *dev);
+static int smsc75xx_phy_gig_workaround(struct usbnet *dev);
+
 static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
 					    u32 *data, int in_pm)
 {
@@ -98,9 +101,13 @@
 	ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN
 		 | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 		 0, index, &buf, 4);
-	if (unlikely(ret < 0))
+	if (unlikely(ret < 4)) {
+		ret = ret < 0 ? ret : -ENODATA;
+
 		netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n",
 			    index, ret);
+		return ret;
+	}
 
 	le32_to_cpus(&buf);
 	*data = buf;
@@ -725,6 +732,9 @@
 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
 	int ret;
 
+	if (wolinfo->wolopts & ~SUPPORTED_WAKE)
+		return -EINVAL;
+
 	pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
 
 	ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts);
@@ -840,6 +850,9 @@
 		return -EIO;
 	}
 
+	/* phy workaround for gig link */
+	smsc75xx_phy_gig_workaround(dev);
+
 	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
 		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
 		ADVERTISE_PAUSE_ASYM);
@@ -945,10 +958,11 @@
 	/* it's racing here! */
 
 	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
-	if (ret < 0)
+	if (ret < 0) {
 		netdev_warn(dev->net, "Error writing RFE_CTL\n");
-
-	return ret;
+		return ret;
+	}
+	return 0;
 }
 
 static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
@@ -977,6 +991,62 @@
 	return -EIO;
 }
 
+static int smsc75xx_phy_gig_workaround(struct usbnet *dev)
+{
+	struct mii_if_info *mii = &dev->mii;
+	int ret = 0, timeout = 0;
+	u32 buf, link_up = 0;
+
+	/* Set the phy in Gig loopback */
+	smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040);
+
+	/* Wait for the link up */
+	do {
+		link_up = smsc75xx_link_ok_nopm(dev);
+		usleep_range(10000, 20000);
+		timeout++;
+	} while ((!link_up) && (timeout < 1000));
+
+	if (timeout >= 1000) {
+		netdev_warn(dev->net, "Timeout waiting for PHY link up\n");
+		return -EIO;
+	}
+
+	/* phy reset */
+	ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
+	if (ret < 0) {
+		netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
+		return ret;
+	}
+
+	buf |= PMT_CTL_PHY_RST;
+
+	ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
+	if (ret < 0) {
+		netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret);
+		return ret;
+	}
+
+	timeout = 0;
+	do {
+		usleep_range(10000, 20000);
+		ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
+		if (ret < 0) {
+			netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n",
+				    ret);
+			return ret;
+		}
+		timeout++;
+	} while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
+
+	if (timeout >= 100) {
+		netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
 static int smsc75xx_reset(struct usbnet *dev)
 {
 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
@@ -1419,7 +1489,7 @@
 	ret = smsc75xx_wait_ready(dev, 0);
 	if (ret < 0) {
 		netdev_warn(dev->net, "device not ready in smsc75xx_bind\n");
-		return ret;
+		goto free_pdata;
 	}
 
 	smsc75xx_init_mac_address(dev);
@@ -1428,7 +1498,7 @@
 	ret = smsc75xx_reset(dev);
 	if (ret < 0) {
 		netdev_warn(dev->net, "smsc75xx_reset error %d\n", ret);
-		return ret;
+		goto cancel_work;
 	}
 
 	dev->net->netdev_ops = &smsc75xx_netdev_ops;
@@ -1437,15 +1507,22 @@
 	dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD;
 	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
 	return 0;
+
+cancel_work:
+	cancel_work_sync(&pdata->set_multicast);
+free_pdata:
+	kfree(pdata);
+	dev->data[0] = 0;
+	return ret;
 }
 
 static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
 {
 	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
 	if (pdata) {
+		cancel_work_sync(&pdata->set_multicast);
 		netif_dbg(dev, ifdown, dev->net, "free pdata\n");
 		kfree(pdata);
-		pdata = NULL;
 		dev->data[0] = 0;
 	}
 }
@@ -2193,13 +2270,9 @@
 {
 	u32 tx_cmd_a, tx_cmd_b;
 
-	if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) {
-		struct sk_buff *skb2 =
-			skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags);
+	if (skb_cow_head(skb, SMSC75XX_TX_OVERHEAD)) {
 		dev_kfree_skb_any(skb);
-		skb = skb2;
-		if (!skb)
-			return NULL;
+		return NULL;
 	}
 
 	tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS;
--- linux-4.4.0.orig/drivers/net/usb/smsc95xx.c
+++ linux-4.4.0/drivers/net/usb/smsc95xx.c
@@ -727,6 +727,9 @@
 	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
 	int ret;
 
+	if (wolinfo->wolopts & ~SUPPORTED_WAKE)
+		return -EINVAL;
+
 	pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
 
 	ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts);
@@ -1133,11 +1136,14 @@
 
 	/* Init all registers */
 	ret = smsc95xx_reset(dev);
+	if (ret)
+		goto free_pdata;
 
 	/* detect device revision as different features may be available */
 	ret = smsc95xx_read_reg(dev, ID_REV, &val);
 	if (ret < 0)
-		return ret;
+		goto free_pdata;
+
 	val >>= 16;
 
 	if ((val == ID_REV_CHIP_ID_9500A_) || (val == ID_REV_CHIP_ID_9530_) ||
@@ -1154,6 +1160,10 @@
 	dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM;
 	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
 	return 0;
+
+free_pdata:
+	kfree(pdata);
+	return ret;
 }
 
 static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
@@ -1835,13 +1845,13 @@
 	/* We do not advertise SG, so skbs should be already linearized */
 	BUG_ON(skb_shinfo(skb)->nr_frags);
 
-	if (skb_headroom(skb) < overhead) {
-		struct sk_buff *skb2 = skb_copy_expand(skb,
-			overhead, 0, flags);
+	/* Make writable and expand header space by overhead if required */
+	if (skb_cow_head(skb, overhead)) {
+		/* Must deallocate here as returning NULL to indicate error
+		 * means the skb won't be deallocated in the caller.
+		 */
 		dev_kfree_skb_any(skb);
-		skb = skb2;
-		if (!skb)
-			return NULL;
+		return NULL;
 	}
 
 	if (csum) {
--- linux-4.4.0.orig/drivers/net/usb/sr9700.c
+++ linux-4.4.0/drivers/net/usb/sr9700.c
@@ -456,14 +456,9 @@
 
 	len = skb->len;
 
-	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
-		struct sk_buff *skb2;
-
-		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+	if (skb_cow_head(skb, SR_TX_OVERHEAD)) {
 		dev_kfree_skb_any(skb);
-		skb = skb2;
-		if (!skb)
-			return NULL;
+		return NULL;
 	}
 
 	__skb_push(skb, SR_TX_OVERHEAD);
--- linux-4.4.0.orig/drivers/net/usb/sr9800.c
+++ linux-4.4.0/drivers/net/usb/sr9800.c
@@ -336,7 +336,7 @@
 static int sr_mdio_read(struct net_device *net, int phy_id, int loc)
 {
 	struct usbnet *dev = netdev_priv(net);
-	__le16 res;
+	__le16 res = 0;
 
 	mutex_lock(&dev->phy_mutex);
 	sr_set_sw_mii(dev);
@@ -421,6 +421,9 @@
 	struct usbnet *dev = netdev_priv(net);
 	u8 opt = 0;
 
+	if (wolinfo->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
+		return -EINVAL;
+
 	if (wolinfo->wolopts & WAKE_PHY)
 		opt |= SR_MONITOR_LINK;
 	if (wolinfo->wolopts & WAKE_MAGIC)
@@ -733,7 +736,9 @@
 
 	data->eeprom_len = SR9800_EEPROM_LEN;
 
-	usbnet_get_endpoints(dev, intf);
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
 
 	/* LED Setting Rule :
 	 * AABB:CCDD
--- linux-4.4.0.orig/drivers/net/usb/usbnet.c
+++ linux-4.4.0/drivers/net/usb/usbnet.c
@@ -115,6 +115,11 @@
 			int				intr = 0;
 
 			e = alt->endpoint + ep;
+
+			/* ignore endpoints which cannot transfer data */
+			if (!usb_endpoint_maxp(&e->desc))
+				continue;
+
 			switch (e->desc.bmAttributes) {
 			case USB_ENDPOINT_XFER_INT:
 				if (!usb_endpoint_dir_in(&e->desc))
@@ -347,6 +352,8 @@
 {
 	enum usb_device_speed speed = dev->udev->speed;
 
+	if (!dev->rx_urb_size || !dev->hard_mtu)
+		goto insanity;
 	switch (speed) {
 	case USB_SPEED_HIGH:
 		dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size;
@@ -362,6 +369,7 @@
 		dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu;
 		break;
 	default:
+insanity:
 		dev->rx_qlen = dev->tx_qlen = 4;
 	}
 }
@@ -499,6 +507,7 @@
 
 	if (netif_running (dev->net) &&
 	    netif_device_present (dev->net) &&
+	    test_bit(EVENT_DEV_OPEN, &dev->flags) &&
 	    !test_bit (EVENT_RX_HALT, &dev->flags) &&
 	    !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) {
 		switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
@@ -1385,6 +1394,11 @@
 		spin_unlock_irqrestore(&dev->txq.lock, flags);
 		goto drop;
 	}
+	if (netif_queue_stopped(net)) {
+		usb_autopm_put_interface_async(dev->intf);
+		spin_unlock_irqrestore(&dev->txq.lock, flags);
+		goto drop;
+	}
 
 #ifdef CONFIG_PM
 	/* if this triggers the device is still a sleep */
@@ -1766,6 +1780,13 @@
 	if (info->unbind)
 		info->unbind (dev, udev);
 out1:
+	/* subdrivers must undo all they did in bind() if they
+	 * fail it, but we may fail later and a deferred kevent
+	 * may trigger an error resubmitting itself and, worse,
+	 * schedule a timer. So we kill it all just in case.
+	 */
+	cancel_work_sync(&dev->kevent);
+	del_timer_sync(&dev->delay);
 	free_netdev(net);
 out:
 	return status;
@@ -1983,6 +2004,10 @@
 			elength = 1;
 			goto next_desc;
 		}
+		if ((buflen < elength) || (elength < 3)) {
+			dev_err(&intf->dev, "invalid descriptor buffer length\n");
+			break;
+		}
 		if (buffer[1] != USB_DT_CS_INTERFACE) {
 			dev_err(&intf->dev, "skipping garbage\n");
 			goto next_desc;
--- linux-4.4.0.orig/drivers/net/veth.c
+++ linux-4.4.0/drivers/net/veth.c
@@ -399,6 +399,9 @@
 	if (ifmp && (dev->ifindex != 0))
 		peer->ifindex = ifmp->ifi_index;
 
+	peer->gso_max_size = dev->gso_max_size;
+	peer->gso_max_segs = dev->gso_max_segs;
+
 	err = register_netdevice(peer);
 	put_net(net);
 	net = NULL;
--- linux-4.4.0.orig/drivers/net/virtio_net.c
+++ linux-4.4.0/drivers/net/virtio_net.c
@@ -47,8 +47,16 @@
  */
 DECLARE_EWMA(pkt_len, 1, 64)
 
+/* With mergeable buffers we align buffer address and use the low bits to
+ * encode its true size. Buffer size is up to 1 page so we need to align to
+ * square root of page size to ensure we reserve enough bits to encode the true
+ * size.
+ */
+#define MERGEABLE_BUFFER_MIN_ALIGN_SHIFT ((PAGE_SHIFT + 1) / 2)
+
 /* Minimum alignment for mergeable packet buffers. */
-#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256)
+#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, \
+				   1 << MERGEABLE_BUFFER_MIN_ALIGN_SHIFT)
 
 #define VIRTNET_DRIVER_VERSION "1.0.0"
 
@@ -146,6 +154,10 @@
 	virtio_net_ctrl_ack ctrl_status;
 	u8 ctrl_promisc;
 	u8 ctrl_allmulti;
+
+	/* Ethtool settings */
+	u8 duplex;
+	u32 speed;
 };
 
 struct padded_vnet_hdr {
@@ -548,7 +560,12 @@
 	hdr = skb_vnet_hdr(skb);
 	sg_init_table(rq->sg, 2);
 	sg_set_buf(rq->sg, hdr, vi->hdr_len);
-	skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
+
+	err = skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
+	if (unlikely(err < 0)) {
+		dev_kfree_skb(skb);
+		return err;
+	}
 
 	err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp);
 	if (err < 0)
@@ -850,7 +867,7 @@
 	struct virtio_net_hdr_mrg_rxbuf *hdr;
 	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
 	struct virtnet_info *vi = sq->vq->vdev->priv;
-	unsigned num_sg;
+	int num_sg;
 	unsigned hdr_len = vi->hdr_len;
 	bool can_push;
 
@@ -903,11 +920,16 @@
 	if (can_push) {
 		__skb_push(skb, hdr_len);
 		num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len);
+		if (unlikely(num_sg < 0))
+			return num_sg;
 		/* Pull header back to avoid skew in tx bytes calculations. */
 		__skb_pull(skb, hdr_len);
 	} else {
 		sg_set_buf(sq->sg, hdr, hdr_len);
-		num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
+		num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len);
+		if (unlikely(num_sg < 0))
+			return num_sg;
+		num_sg++;
 	}
 	return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC);
 }
@@ -1354,14 +1376,16 @@
 
 	get_online_cpus();
 	err = virtnet_set_queues(vi, queue_pairs);
-	if (!err) {
-		netif_set_real_num_tx_queues(dev, queue_pairs);
-		netif_set_real_num_rx_queues(dev, queue_pairs);
-
-		virtnet_set_affinity(vi);
+	if (err) {
+		put_online_cpus();
+		goto err;
 	}
+	virtnet_set_affinity(vi);
 	put_online_cpus();
 
+	netif_set_real_num_tx_queues(dev, queue_pairs);
+	netif_set_real_num_rx_queues(dev, queue_pairs);
+err:
 	return err;
 }
 
@@ -1378,6 +1402,60 @@
 	channels->other_count = 0;
 }
 
+/* Check if the user is trying to change anything besides speed/duplex */
+static bool virtnet_validate_ethtool_cmd(const struct ethtool_cmd *cmd)
+{
+	struct ethtool_cmd diff1 = *cmd;
+	struct ethtool_cmd diff2 = {};
+
+	/* cmd is always set so we need to clear it, validate the port type
+	 * and also without autonegotiation we can ignore advertising
+	 */
+	ethtool_cmd_speed_set(&diff1, 0);
+	diff2.port = PORT_OTHER;
+	diff1.advertising = 0;
+	diff1.duplex = 0;
+	diff1.cmd = 0;
+
+	return !memcmp(&diff1, &diff2, sizeof(diff1));
+}
+
+static int virtnet_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	u32 speed;
+
+	speed = ethtool_cmd_speed(cmd);
+	/* don't allow custom speed and duplex */
+	if (!ethtool_validate_speed(speed) ||
+	    !ethtool_validate_duplex(cmd->duplex) ||
+	    !virtnet_validate_ethtool_cmd(cmd))
+		return -EINVAL;
+	vi->speed = speed;
+	vi->duplex = cmd->duplex;
+
+	return 0;
+}
+
+static int virtnet_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+
+	ethtool_cmd_speed_set(cmd, vi->speed);
+	cmd->duplex = vi->duplex;
+	cmd->port = PORT_OTHER;
+
+	return 0;
+}
+
+static void virtnet_init_settings(struct net_device *dev)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+
+	vi->speed = SPEED_UNKNOWN;
+	vi->duplex = DUPLEX_UNKNOWN;
+}
+
 static const struct ethtool_ops virtnet_ethtool_ops = {
 	.get_drvinfo = virtnet_get_drvinfo,
 	.get_link = ethtool_op_get_link,
@@ -1385,6 +1463,8 @@
 	.set_channels = virtnet_set_channels,
 	.get_channels = virtnet_get_channels,
 	.get_ts_info = ethtool_op_get_ts_info,
+	.get_settings = virtnet_get_settings,
+	.set_settings = virtnet_set_settings,
 };
 
 #define MIN_MTU 68
@@ -1415,6 +1495,7 @@
 #ifdef CONFIG_NET_RX_BUSY_POLL
 	.ndo_busy_poll		= virtnet_busy_poll,
 #endif
+	.ndo_features_check	= passthru_features_check,
 };
 
 static void virtnet_config_changed_work(struct work_struct *work)
@@ -1465,6 +1546,11 @@
 		netif_napi_del(&vi->rq[i].napi);
 	}
 
+	/* We called napi_hash_del() before netif_napi_del(),
+	 * we need to respect an RCU grace period before freeing vi->rq
+	 */
+	synchronize_net();
+
 	kfree(vi->rq);
 	kfree(vi->sq);
 }
@@ -1858,6 +1944,8 @@
 	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
 	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
 
+	virtnet_init_settings(dev);
+
 	err = register_netdev(dev);
 	if (err) {
 		pr_debug("virtio_net: registering device failed\n");
@@ -1888,8 +1976,8 @@
 
 	/* Assume link up if device can't report link status,
 	   otherwise get link status from config. */
+	netif_carrier_off(dev);
 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-		netif_carrier_off(dev);
 		schedule_work(&vi->config_work);
 	} else {
 		vi->status = VIRTIO_NET_S_LINK_UP;
--- linux-4.4.0.orig/drivers/net/vmxnet3/vmxnet3_drv.c
+++ linux-4.4.0/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -590,6 +590,7 @@
 				if (dma_mapping_error(&adapter->pdev->dev,
 						      rbi->dma_addr)) {
 					dev_kfree_skb_any(rbi->skb);
+					rbi->skb = NULL;
 					rq->stats.rx_buf_alloc_failure++;
 					break;
 				}
@@ -614,6 +615,7 @@
 				if (dma_mapping_error(&adapter->pdev->dev,
 						      rbi->dma_addr)) {
 					put_page(rbi->page);
+					rbi->page = NULL;
 					rq->stats.rx_buf_alloc_failure++;
 					break;
 				}
@@ -957,6 +959,8 @@
 {
 	int ret;
 	u32 count;
+	int num_pkts;
+	int tx_num_deferred;
 	unsigned long flags;
 	struct vmxnet3_tx_ctx ctx;
 	union Vmxnet3_GenericDesc *gdesc;
@@ -1051,12 +1055,12 @@
 #else
 	gdesc = ctx.sop_txd;
 #endif
+	tx_num_deferred = le32_to_cpu(tq->shared->txNumDeferred);
 	if (ctx.mss) {
 		gdesc->txd.hlen = ctx.eth_ip_hdr_size + ctx.l4_hdr_size;
 		gdesc->txd.om = VMXNET3_OM_TSO;
 		gdesc->txd.msscof = ctx.mss;
-		le32_add_cpu(&tq->shared->txNumDeferred, (skb->len -
-			     gdesc->txd.hlen + ctx.mss - 1) / ctx.mss);
+		num_pkts = (skb->len - gdesc->txd.hlen + ctx.mss - 1) / ctx.mss;
 	} else {
 		if (skb->ip_summed == CHECKSUM_PARTIAL) {
 			gdesc->txd.hlen = ctx.eth_ip_hdr_size;
@@ -1067,8 +1071,10 @@
 			gdesc->txd.om = 0;
 			gdesc->txd.msscof = 0;
 		}
-		le32_add_cpu(&tq->shared->txNumDeferred, 1);
+		num_pkts = 1;
 	}
+	le32_add_cpu(&tq->shared->txNumDeferred, num_pkts);
+	tx_num_deferred += num_pkts;
 
 	if (skb_vlan_tag_present(skb)) {
 		gdesc->txd.ti = 1;
@@ -1094,8 +1100,7 @@
 
 	spin_unlock_irqrestore(&tq->tx_lock, flags);
 
-	if (le32_to_cpu(tq->shared->txNumDeferred) >=
-					le32_to_cpu(tq->shared->txThreshold)) {
+	if (tx_num_deferred >= le32_to_cpu(tq->shared->txThreshold)) {
 		tq->shared->txNumDeferred = 0;
 		VMXNET3_WRITE_BAR0_REG(adapter,
 				       VMXNET3_REG_TXPROD + tq->qid * 8,
@@ -1133,12 +1138,16 @@
 		union Vmxnet3_GenericDesc *gdesc)
 {
 	if (!gdesc->rcd.cnc && adapter->netdev->features & NETIF_F_RXCSUM) {
-		/* typical case: TCP/UDP over IP and both csums are correct */
-		if ((le32_to_cpu(gdesc->dword[3]) & VMXNET3_RCD_CSUM_OK) ==
-							VMXNET3_RCD_CSUM_OK) {
+		if (gdesc->rcd.v4 &&
+		    (le32_to_cpu(gdesc->dword[3]) &
+		     VMXNET3_RCD_CSUM_OK) == VMXNET3_RCD_CSUM_OK) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			BUG_ON(!(gdesc->rcd.tcp || gdesc->rcd.udp));
+			BUG_ON(gdesc->rcd.frg);
+		} else if (gdesc->rcd.v6 && (le32_to_cpu(gdesc->dword[3]) &
+					     (1 << VMXNET3_RCD_TUC_SHIFT))) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			BUG_ON(!(gdesc->rcd.tcp || gdesc->rcd.udp));
-			BUG_ON(!(gdesc->rcd.v4  || gdesc->rcd.v6));
 			BUG_ON(gdesc->rcd.frg);
 		} else {
 			if (gdesc->rcd.csum) {
@@ -1189,6 +1198,7 @@
 	union {
 		void *ptr;
 		struct ethhdr *eth;
+		struct vlan_ethhdr *veth;
 		struct iphdr *ipv4;
 		struct ipv6hdr *ipv6;
 		struct tcphdr *tcp;
@@ -1199,16 +1209,24 @@
 	if (unlikely(sizeof(struct iphdr) + sizeof(struct tcphdr) > maplen))
 		return 0;
 
+	if (skb->protocol == cpu_to_be16(ETH_P_8021Q) ||
+	    skb->protocol == cpu_to_be16(ETH_P_8021AD))
+		hlen = sizeof(struct vlan_ethhdr);
+	else
+		hlen = sizeof(struct ethhdr);
+
 	hdr.eth = eth_hdr(skb);
 	if (gdesc->rcd.v4) {
-		BUG_ON(hdr.eth->h_proto != htons(ETH_P_IP));
-		hdr.ptr += sizeof(struct ethhdr);
+		BUG_ON(hdr.eth->h_proto != htons(ETH_P_IP) &&
+		       hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IP));
+		hdr.ptr += hlen;
 		BUG_ON(hdr.ipv4->protocol != IPPROTO_TCP);
 		hlen = hdr.ipv4->ihl << 2;
 		hdr.ptr += hdr.ipv4->ihl << 2;
 	} else if (gdesc->rcd.v6) {
-		BUG_ON(hdr.eth->h_proto != htons(ETH_P_IPV6));
-		hdr.ptr += sizeof(struct ethhdr);
+		BUG_ON(hdr.eth->h_proto != htons(ETH_P_IPV6) &&
+		       hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IPV6));
+		hdr.ptr += hlen;
 		/* Use an estimated value, since we also need to handle
 		 * TSO case.
 		 */
@@ -1346,7 +1364,7 @@
 				rcdlro = (struct Vmxnet3_RxCompDescExt *)rcd;
 
 				segCnt = rcdlro->segCnt;
-				BUG_ON(segCnt <= 1);
+				WARN_ON_ONCE(segCnt == 0);
 				mss = rcdlro->mss;
 				if (unlikely(segCnt <= 1))
 					segCnt = 0;
@@ -1417,7 +1435,8 @@
 			vmxnet3_rx_csum(adapter, skb,
 					(union Vmxnet3_GenericDesc *)rcd);
 			skb->protocol = eth_type_trans(skb, adapter->netdev);
-			if (!rcd->tcp || !adapter->lro)
+			if (!rcd->tcp ||
+			    !(adapter->netdev->features & NETIF_F_LRO))
 				goto not_lro;
 
 			if (segCnt != 0 && mss != 0) {
@@ -1496,6 +1515,10 @@
 	u32 i, ring_idx;
 	struct Vmxnet3_RxDesc *rxd;
 
+	/* ring has already been cleaned up */
+	if (!rq->rx_ring[0].base)
+		return;
+
 	for (ring_idx = 0; ring_idx < 2; ring_idx++) {
 		for (i = 0; i < rq->rx_ring[ring_idx].size; i++) {
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -1563,7 +1586,6 @@
 					  rq->rx_ring[i].basePA);
 			rq->rx_ring[i].base = NULL;
 		}
-		rq->buf_info[i] = NULL;
 	}
 
 	if (rq->comp_ring.base) {
@@ -1578,6 +1600,7 @@
 			(rq->rx_ring[0].size + rq->rx_ring[1].size);
 		dma_free_coherent(&adapter->pdev->dev, sz, rq->buf_info[0],
 				  rq->buf_info_pa);
+		rq->buf_info[0] = rq->buf_info[1] = NULL;
 	}
 }
 
@@ -2789,6 +2812,11 @@
 	/* we need to enable NAPI, otherwise dev_close will deadlock */
 	for (i = 0; i < adapter->num_rx_queues; i++)
 		napi_enable(&adapter->rx_queue[i].napi);
+	/*
+	 * Need to clear the quiesce bit to ensure that vmxnet3_close
+	 * can quiesce the device properly
+	 */
+	clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
 	dev_close(adapter->netdev);
 }
 
--- linux-4.4.0.orig/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ linux-4.4.0/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -664,6 +664,8 @@
 		*hfunc = ETH_RSS_HASH_TOP;
 	if (!p)
 		return 0;
+	if (n > UPT1_RSS_MAX_IND_TABLE_SIZE)
+		return 0;
 	while (n--)
 		p[n] = rssConf->indTable[n];
 	return 0;
--- linux-4.4.0.orig/drivers/net/vmxnet3/vmxnet3_int.h
+++ linux-4.4.0/drivers/net/vmxnet3/vmxnet3_int.h
@@ -69,10 +69,10 @@
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.4.5.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.4.14.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01040500
+#define VMXNET3_DRIVER_VERSION_NUM      0x01040e00
 
 #if defined(CONFIG_PCI_MSI)
 	/* RSS only makes sense if MSI-X is supported. */
@@ -331,7 +331,6 @@
 	u8                              version;
 
 	bool				rxcsum;
-	bool				lro;
 
 #ifdef VMXNET3_RSS
 	struct UPT1_RSSConf		*rss_conf;
--- linux-4.4.0.orig/drivers/net/vrf.c
+++ linux-4.4.0/drivers/net/vrf.c
@@ -71,41 +71,6 @@
 	struct u64_stats_sync	syncp;
 };
 
-static struct dst_entry *vrf_ip_check(struct dst_entry *dst, u32 cookie)
-{
-	return dst;
-}
-
-static int vrf_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
-{
-	return ip_local_out(net, sk, skb);
-}
-
-static unsigned int vrf_v4_mtu(const struct dst_entry *dst)
-{
-	/* TO-DO: return max ethernet size? */
-	return dst->dev->mtu;
-}
-
-static void vrf_dst_destroy(struct dst_entry *dst)
-{
-	/* our dst lives forever - or until the device is closed */
-}
-
-static unsigned int vrf_default_advmss(const struct dst_entry *dst)
-{
-	return 65535 - 40;
-}
-
-static struct dst_ops vrf_dst_ops = {
-	.family		= AF_INET,
-	.local_out	= vrf_ip_local_out,
-	.check		= vrf_ip_check,
-	.mtu		= vrf_v4_mtu,
-	.destroy	= vrf_dst_destroy,
-	.default_advmss	= vrf_default_advmss,
-};
-
 /* neighbor handling is done with actual device; do not want
  * to flip skb->dev for those ndisc packets. This really fails
  * for multiple next protocols (e.g., NEXTHDR_HOP). But it is
@@ -114,20 +79,23 @@
 #if IS_ENABLED(CONFIG_IPV6)
 static bool check_ipv6_frame(const struct sk_buff *skb)
 {
-	const struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->data;
-	size_t hlen = sizeof(*ipv6h);
+	const struct ipv6hdr *ipv6h;
+	struct ipv6hdr _ipv6h;
 	bool rc = true;
 
-	if (skb->len < hlen)
+	ipv6h = skb_header_pointer(skb, 0, sizeof(_ipv6h), &_ipv6h);
+	if (!ipv6h)
 		goto out;
 
 	if (ipv6h->nexthdr == NEXTHDR_ICMP) {
 		const struct icmp6hdr *icmph;
+		struct icmp6hdr _icmph;
 
-		if (skb->len < hlen + sizeof(*icmph))
+		icmph = skb_header_pointer(skb, sizeof(_ipv6h),
+					   sizeof(_icmph), &_icmph);
+		if (!icmph)
 			goto out;
 
-		icmph = (struct icmp6hdr *)(skb->data + sizeof(*ipv6h));
 		switch (icmph->icmp6_type) {
 		case NDISC_ROUTER_SOLICITATION:
 		case NDISC_ROUTER_ADVERTISEMENT:
@@ -298,7 +266,9 @@
 		.flowi4_tos = RT_TOS(ip4h->tos),
 		.flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_L3MDEV_SRC |
 				FLOWI_FLAG_SKIP_NH_OIF,
+		.flowi4_proto = ip4h->protocol,
 		.daddr = ip4h->daddr,
+		.saddr = ip4h->saddr,
 	};
 
 	if (vrf_send_v4_prep(skb, &fl4, vrf_dev))
@@ -340,6 +310,7 @@
 
 static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	int len = skb->len;
 	netdev_tx_t ret = is_ip_tx_frame(skb, dev);
 
 	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
@@ -347,7 +318,7 @@
 
 		u64_stats_update_begin(&dstats->syncp);
 		dstats->tx_pkts++;
-		dstats->tx_bytes += skb->len;
+		dstats->tx_bytes += len;
 		u64_stats_update_end(&dstats->syncp);
 	} else {
 		this_cpu_inc(dev->dstats->tx_drps);
@@ -357,46 +328,6 @@
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
-static struct dst_entry *vrf_ip6_check(struct dst_entry *dst, u32 cookie)
-{
-	return dst;
-}
-
-static struct dst_ops vrf_dst_ops6 = {
-	.family		= AF_INET6,
-	.local_out	= ip6_local_out,
-	.check		= vrf_ip6_check,
-	.mtu		= vrf_v4_mtu,
-	.destroy	= vrf_dst_destroy,
-	.default_advmss	= vrf_default_advmss,
-};
-
-static int init_dst_ops6_kmem_cachep(void)
-{
-	vrf_dst_ops6.kmem_cachep = kmem_cache_create("vrf_ip6_dst_cache",
-						     sizeof(struct rt6_info),
-						     0,
-						     SLAB_HWCACHE_ALIGN,
-						     NULL);
-
-	if (!vrf_dst_ops6.kmem_cachep)
-		return -ENOMEM;
-
-	return 0;
-}
-
-static void free_dst_ops6_kmem_cachep(void)
-{
-	kmem_cache_destroy(vrf_dst_ops6.kmem_cachep);
-}
-
-static int vrf_input6(struct sk_buff *skb)
-{
-	skb->dev->stats.rx_errors++;
-	kfree_skb(skb);
-	return 0;
-}
-
 /* modelled after ip6_finish_output2 */
 static int vrf_finish_output6(struct net *net, struct sock *sk,
 			      struct sk_buff *skb)
@@ -407,6 +338,8 @@
 	struct in6_addr *nexthop;
 	int ret;
 
+	nf_reset(skb);
+
 	skb->protocol = htons(ETH_P_IPV6);
 	skb->dev = dev;
 
@@ -416,6 +349,7 @@
 	if (unlikely(!neigh))
 		neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
 	if (!IS_ERR(neigh)) {
+		sock_confirm_neigh(skb, neigh);
 		ret = dst_neigh_output(dst, neigh, skb);
 		rcu_read_unlock_bh();
 		return ret;
@@ -437,67 +371,34 @@
 			    !(IP6CB(skb)->flags & IP6SKB_REROUTED));
 }
 
-static void vrf_rt6_destroy(struct net_vrf *vrf)
+static void vrf_rt6_release(struct net_vrf *vrf)
 {
-	dst_destroy(&vrf->rt6->dst);
-	free_percpu(vrf->rt6->rt6i_pcpu);
+	dst_release(&vrf->rt6->dst);
 	vrf->rt6 = NULL;
 }
 
 static int vrf_rt6_create(struct net_device *dev)
 {
 	struct net_vrf *vrf = netdev_priv(dev);
-	struct dst_entry *dst;
+	struct net *net = dev_net(dev);
 	struct rt6_info *rt6;
-	int cpu;
 	int rc = -ENOMEM;
 
-	rt6 = dst_alloc(&vrf_dst_ops6, dev, 0,
-			DST_OBSOLETE_NONE,
-			(DST_HOST | DST_NOPOLICY | DST_NOXFRM));
+	rt6 = ip6_dst_alloc(net, dev,
+			    DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE);
 	if (!rt6)
 		goto out;
 
-	dst = &rt6->dst;
-
-	rt6->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_KERNEL);
-	if (!rt6->rt6i_pcpu) {
-		dst_destroy(dst);
-		goto out;
-	}
-	for_each_possible_cpu(cpu) {
-		struct rt6_info **p = per_cpu_ptr(rt6->rt6i_pcpu, cpu);
-		*p =  NULL;
-	}
-
-	memset(dst + 1, 0, sizeof(*rt6) - sizeof(*dst));
-
-	INIT_LIST_HEAD(&rt6->rt6i_siblings);
-	INIT_LIST_HEAD(&rt6->rt6i_uncached);
-
-	rt6->dst.input	= vrf_input6;
 	rt6->dst.output	= vrf_output6;
-
-	rt6->rt6i_table = fib6_get_table(dev_net(dev), vrf->tb_id);
-
-	atomic_set(&rt6->dst.__refcnt, 2);
-
+	rt6->rt6i_table = fib6_get_table(net, vrf->tb_id);
+	dst_hold(&rt6->dst);
 	vrf->rt6 = rt6;
 	rc = 0;
 out:
 	return rc;
 }
 #else
-static int init_dst_ops6_kmem_cachep(void)
-{
-	return 0;
-}
-
-static void free_dst_ops6_kmem_cachep(void)
-{
-}
-
-static void vrf_rt6_destroy(struct net_vrf *vrf)
+static void vrf_rt6_release(struct net_vrf *vrf)
 {
 }
 
@@ -518,6 +419,8 @@
 	u32 nexthop;
 	int ret = -EINVAL;
 
+	nf_reset(skb);
+
 	/* Be paranoid, rather than too clever. */
 	if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
 		struct sk_buff *skb2;
@@ -540,13 +443,16 @@
 	neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
 	if (unlikely(!neigh))
 		neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
-	if (!IS_ERR(neigh))
+	if (!IS_ERR(neigh)) {
+		sock_confirm_neigh(skb, neigh);
 		ret = dst_neigh_output(dst, neigh, skb);
+		rcu_read_unlock_bh();
+		return ret;
+	}
 
 	rcu_read_unlock_bh();
 err:
-	if (unlikely(ret < 0))
-		vrf_tx_error(skb->dev, skb);
+	vrf_tx_error(skb->dev, skb);
 	return ret;
 }
 
@@ -565,11 +471,11 @@
 			    !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
 
-static void vrf_rtable_destroy(struct net_vrf *vrf)
+static void vrf_rtable_release(struct net_vrf *vrf)
 {
 	struct dst_entry *dst = (struct dst_entry *)vrf->rth;
 
-	dst_destroy(dst);
+	dst_release(dst);
 	vrf->rth = NULL;
 }
 
@@ -578,22 +484,10 @@
 	struct net_vrf *vrf = netdev_priv(dev);
 	struct rtable *rth;
 
-	rth = dst_alloc(&vrf_dst_ops, dev, 2,
-			DST_OBSOLETE_NONE,
-			(DST_HOST | DST_NOPOLICY | DST_NOXFRM));
+	rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1, 0);
 	if (rth) {
 		rth->dst.output	= vrf_output;
-		rth->rt_genid	= rt_genid_ipv4(dev_net(dev));
-		rth->rt_flags	= 0;
-		rth->rt_type	= RTN_UNICAST;
-		rth->rt_is_input = 0;
-		rth->rt_iif	= 0;
-		rth->rt_pmtu	= 0;
-		rth->rt_gateway	= 0;
-		rth->rt_uses_gateway = 0;
 		rth->rt_table_id = vrf->tb_id;
-		INIT_LIST_HEAD(&rth->rt_uncached);
-		rth->rt_uncached_list = NULL;
 	}
 
 	return rth;
@@ -723,15 +617,15 @@
 static void vrf_dev_uninit(struct net_device *dev)
 {
 	struct net_vrf *vrf = netdev_priv(dev);
-	struct slave_queue *queue = &vrf->queue;
-	struct list_head *head = &queue->all_slaves;
-	struct slave *slave, *next;
+//	struct slave_queue *queue = &vrf->queue;
+//	struct list_head *head = &queue->all_slaves;
+//	struct slave *slave, *next;
 
-	vrf_rtable_destroy(vrf);
-	vrf_rt6_destroy(vrf);
+	vrf_rtable_release(vrf);
+	vrf_rt6_release(vrf);
 
-	list_for_each_entry_safe(slave, next, head, list)
-		vrf_del_slave(dev, slave->dev);
+//	list_for_each_entry_safe(slave, next, head, list)
+//		vrf_del_slave(dev, slave->dev);
 
 	free_percpu(dev->dstats);
 	dev->dstats = NULL;
@@ -760,7 +654,7 @@
 	return 0;
 
 out_rth:
-	vrf_rtable_destroy(vrf);
+	vrf_rtable_release(vrf);
 out_stats:
 	free_percpu(dev->dstats);
 	dev->dstats = NULL;
@@ -793,7 +687,7 @@
 		struct net_vrf *vrf = netdev_priv(dev);
 
 		rth = vrf->rth;
-		atomic_inc(&rth->dst.__refcnt);
+		dst_hold(&rth->dst);
 	}
 
 	return rth;
@@ -844,7 +738,7 @@
 		struct net_vrf *vrf = netdev_priv(dev);
 
 		rt = vrf->rt6;
-		atomic_inc(&rt->dst.__refcnt);
+		dst_hold(&rt->dst);
 	}
 
 	return (struct dst_entry *)rt;
@@ -904,6 +798,14 @@
 
 static void vrf_dellink(struct net_device *dev, struct list_head *head)
 {
+	struct net_vrf *vrf = netdev_priv(dev);
+	struct slave_queue *queue = &vrf->queue;
+	struct list_head *all_slaves = &queue->all_slaves;
+	struct slave *slave, *next;
+
+	list_for_each_entry_safe(slave, next, all_slaves, list)
+		vrf_del_slave(dev, slave->dev);
+
 	unregister_netdevice_queue(dev, head);
 }
 
@@ -916,6 +818,8 @@
 		return -EINVAL;
 
 	vrf->tb_id = nla_get_u32(data[IFLA_VRF_TABLE]);
+	if (vrf->tb_id == RT_TABLE_UNSPEC)
+		return -EINVAL;
 
 	dev->priv_flags |= IFF_L3MDEV_MASTER;
 
@@ -981,19 +885,6 @@
 {
 	int rc;
 
-	vrf_dst_ops.kmem_cachep =
-		kmem_cache_create("vrf_ip_dst_cache",
-				  sizeof(struct rtable), 0,
-				  SLAB_HWCACHE_ALIGN,
-				  NULL);
-
-	if (!vrf_dst_ops.kmem_cachep)
-		return -ENOMEM;
-
-	rc = init_dst_ops6_kmem_cachep();
-	if (rc != 0)
-		goto error2;
-
 	register_netdevice_notifier(&vrf_notifier_block);
 
 	rc = rtnl_link_register(&vrf_link_ops);
@@ -1004,22 +895,10 @@
 
 error:
 	unregister_netdevice_notifier(&vrf_notifier_block);
-	free_dst_ops6_kmem_cachep();
-error2:
-	kmem_cache_destroy(vrf_dst_ops.kmem_cachep);
 	return rc;
 }
 
-static void __exit vrf_cleanup_module(void)
-{
-	rtnl_link_unregister(&vrf_link_ops);
-	unregister_netdevice_notifier(&vrf_notifier_block);
-	kmem_cache_destroy(vrf_dst_ops.kmem_cachep);
-	free_dst_ops6_kmem_cachep();
-}
-
 module_init(vrf_init_module);
-module_exit(vrf_cleanup_module);
 MODULE_AUTHOR("Shrijeet Mukherjee, David Ahern");
 MODULE_DESCRIPTION("Device driver to instantiate VRF domains");
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/net/vxlan.c
+++ linux-4.4.0/drivers/net/vxlan.c
@@ -23,6 +23,7 @@
 #include <linux/udp.h>
 #include <linux/igmp.h>
 #include <linux/etherdevice.h>
+#include <linux/inetdevice.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
 #include <linux/hash.h>
@@ -77,6 +78,8 @@
 
 static int vxlan_sock_add(struct vxlan_dev *vxlan);
 
+static void vxlan_vs_del_dev(struct vxlan_dev *vxlan);
+
 /* per-network namespace private data for this module */
 struct vxlan_net {
 	struct list_head  vxlan_list;
@@ -106,6 +109,167 @@
 	       ip_tunnel_collect_metadata();
 }
 
+static struct ip_fan_map *vxlan_fan_find_map(struct vxlan_dev *vxlan, __be32 daddr)
+{
+	struct ip_fan_map *fan_map;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(fan_map, &vxlan->fan.fan_maps, list) {
+		if (fan_map->overlay ==
+		    (daddr & inet_make_mask(fan_map->overlay_prefix))) {
+			rcu_read_unlock();
+			return fan_map;
+		}
+	}
+	rcu_read_unlock();
+
+	return NULL;
+}
+
+static void vxlan_fan_flush_map(struct vxlan_dev *vxlan)
+{
+	struct ip_fan_map *fan_map;
+
+	list_for_each_entry_rcu(fan_map, &vxlan->fan.fan_maps, list) {
+		list_del_rcu(&fan_map->list);
+		kfree_rcu(fan_map, rcu);
+	}
+}
+
+static int vxlan_fan_del_map(struct vxlan_dev *vxlan, __be32 overlay)
+{
+	struct ip_fan_map *fan_map;
+
+	fan_map = vxlan_fan_find_map(vxlan, overlay);
+	if (!fan_map)
+		return -ENOENT;
+
+	list_del_rcu(&fan_map->list);
+	kfree_rcu(fan_map, rcu);
+
+	return 0;
+}
+
+static int vxlan_fan_add_map(struct vxlan_dev *vxlan, struct ifla_fan_map *map)
+{
+	__be32 overlay_mask, underlay_mask;
+	struct ip_fan_map *fan_map;
+
+	overlay_mask = inet_make_mask(map->overlay_prefix);
+	underlay_mask = inet_make_mask(map->underlay_prefix);
+
+	netdev_dbg(vxlan->dev, "vfam: map: o %x/%d u %x/%d om %x um %x\n",
+		   map->overlay, map->overlay_prefix,
+		   map->underlay, map->underlay_prefix,
+		   overlay_mask, underlay_mask);
+
+	if ((map->overlay & ~overlay_mask) || (map->underlay & ~underlay_mask))
+		return -EINVAL;
+
+	if (!(map->overlay & overlay_mask) && (map->underlay & underlay_mask))
+		return -EINVAL;
+
+	/* Special case: overlay 0 and underlay 0: flush all mappings */
+	if (!map->overlay && !map->underlay) {
+		vxlan_fan_flush_map(vxlan);
+		return 0;
+	}
+	
+	/* Special case: overlay set and underlay 0: clear map for overlay */
+	if (!map->underlay)
+		return vxlan_fan_del_map(vxlan, map->overlay);
+
+	if (vxlan_fan_find_map(vxlan, map->overlay))
+		return -EEXIST;
+
+	fan_map = kmalloc(sizeof(*fan_map), GFP_KERNEL);
+	fan_map->underlay = map->underlay;
+	fan_map->overlay = map->overlay;
+	fan_map->underlay_prefix = map->underlay_prefix;
+	fan_map->overlay_mask = ntohl(overlay_mask);
+	fan_map->overlay_prefix = map->overlay_prefix;
+
+	list_add_tail_rcu(&fan_map->list, &vxlan->fan.fan_maps);
+
+	return 0;
+}
+	
+static int vxlan_parse_fan_map(struct nlattr *data[], struct vxlan_dev *vxlan)
+{
+	struct ifla_fan_map *map;
+	struct nlattr *attr;
+	int rem, rv;
+
+	nla_for_each_nested(attr, data[IFLA_IPTUN_FAN_MAP], rem) {
+		map = nla_data(attr);
+		rv = vxlan_fan_add_map(vxlan, map);
+		if (rv)
+			return rv;
+	}
+
+	return 0;
+}
+
+static int vxlan_fan_build_rdst(struct vxlan_dev *vxlan, struct sk_buff *skb,
+				      struct vxlan_rdst *fan_rdst)
+{
+	struct ip_fan_map *f_map;
+	union vxlan_addr *va;
+	u32 daddr, underlay;
+	struct arphdr *arp;
+	void *arp_ptr;
+	struct ethhdr *eth;
+	struct iphdr *iph;
+
+	eth = eth_hdr(skb);
+	switch (eth->h_proto) {
+	case htons(ETH_P_IP):
+		iph = ip_hdr(skb);
+		if (!iph)
+			return -EINVAL;
+		daddr = iph->daddr;
+		break;
+	case htons(ETH_P_ARP):
+		arp = arp_hdr(skb);
+		if (!arp)
+			return -EINVAL;
+		arp_ptr = arp + 1;
+		netdev_dbg(vxlan->dev,
+			   "vfbr: arp sha %pM sip %pI4 tha %pM tip %pI4\n",
+			   arp_ptr, arp_ptr + skb->dev->addr_len,
+			   arp_ptr + skb->dev->addr_len + 4,
+			   arp_ptr + (skb->dev->addr_len * 2) + 4);
+		arp_ptr += (skb->dev->addr_len * 2) + 4;
+		memcpy(&daddr, arp_ptr, 4);
+		break;
+	default:
+		netdev_dbg(vxlan->dev, "vfbr: unknown eth p %x\n", eth->h_proto);
+		return -EINVAL;
+	}
+
+	f_map = vxlan_fan_find_map(vxlan, daddr);
+	if (!f_map)
+		return -EINVAL;
+
+	daddr = ntohl(daddr);
+	underlay = ntohl(f_map->underlay);
+	if (!underlay)
+		return -EINVAL;
+
+	memset(fan_rdst, 0, sizeof(*fan_rdst));
+	va = &fan_rdst->remote_ip;
+	va->sa.sa_family = AF_INET;
+	fan_rdst->remote_vni = vxlan->default_dst.remote_vni;
+	va->sin.sin_addr.s_addr = htonl(underlay |
+					((daddr & ~f_map->overlay_mask) >>
+					 (32 - f_map->overlay_prefix -
+					  (32 - f_map->underlay_prefix))));
+	netdev_dbg(vxlan->dev, "vfbr: daddr %x ul %x dst %x\n",
+		   daddr, underlay, va->sin.sin_addr.s_addr);
+
+	return 0;
+}
+
 #if IS_ENABLED(CONFIG_IPV6)
 static inline
 bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
@@ -593,7 +757,7 @@
 		}
 	}
 
-	pp = eth_gro_receive(head, skb);
+	pp = call_gro_receive(eth_gro_receive, head, skb);
 
 out:
 	skb_gro_remcsum_cleanup(skb, &grc);
@@ -919,6 +1083,7 @@
 		struct vxlan_fdb *f;
 		int err;
 
+		rcu_read_lock();
 		hlist_for_each_entry_rcu(f, &vxlan->fdb_head[h], hlist) {
 			struct vxlan_rdst *rd;
 
@@ -931,12 +1096,15 @@
 						     cb->nlh->nlmsg_seq,
 						     RTM_NEWNEIGH,
 						     NLM_F_MULTI, rd);
-				if (err < 0)
+				if (err < 0) {
+					rcu_read_unlock();
 					goto out;
+				}
 skip:
 				++idx;
 			}
 		}
+		rcu_read_unlock();
 	}
 out:
 	return idx;
@@ -960,7 +1128,7 @@
 			return false;
 
 		/* Don't migrate static entries, drop packets */
-		if (f->state & NUD_NOARP)
+		if (f->state & (NUD_PERMANENT | NUD_NOARP))
 			return true;
 
 		if (net_ratelimit())
@@ -1052,6 +1220,8 @@
 
 static void vxlan_sock_release(struct vxlan_dev *vxlan)
 {
+	vxlan_vs_del_dev(vxlan);
+
 	__vxlan_sock_release(vxlan->vn4_sock);
 #if IS_ENABLED(CONFIG_IPV6)
 	__vxlan_sock_release(vxlan->vn6_sock);
@@ -1225,6 +1395,14 @@
 		}
 	}
 
+	rcu_read_lock();
+
+	if (unlikely(!(vxlan->dev->flags & IFF_UP))) {
+		rcu_read_unlock();
+		atomic_long_inc(&vxlan->dev->rx_dropped);
+		goto drop;
+	}
+
 	stats = this_cpu_ptr(vxlan->dev->tstats);
 	u64_stats_update_begin(&stats->syncp);
 	stats->rx_packets++;
@@ -1233,6 +1411,8 @@
 
 	gro_cells_receive(&vxlan->gro_cells, skb);
 
+	rcu_read_unlock();
+
 	return;
 drop:
 	if (tun_dst)
@@ -1254,7 +1434,7 @@
 
 	/* Need Vxlan and inner Ethernet header to be present */
 	if (!pskb_may_pull(skb, VXLAN_HLEN))
-		goto error;
+		goto drop;
 
 	vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
 	flags = ntohl(vxh->vx_flags);
@@ -1306,8 +1486,10 @@
 		gbp = (struct vxlanhdr_gbp *)vxh;
 		md->gbp = ntohs(gbp->policy_id);
 
-		if (tun_dst)
+		if (tun_dst) {
 			tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
+			tun_dst->u.tun_info.options_len = sizeof(*md);
+		}
 
 		if (gbp->dont_learn)
 			md->gbp |= VXLAN_GBP_DONT_LEARN;
@@ -1342,13 +1524,7 @@
 bad_flags:
 	netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
 		   ntohl(vxh->vx_flags), ntohl(vxh->vx_vni));
-
-error:
-	if (tun_dst)
-		dst_release((struct dst_entry *)tun_dst);
-
-	/* Return non vxlan pkt */
-	return 1;
+	goto drop;
 }
 
 static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
@@ -1466,6 +1642,10 @@
 	daddr = eth_hdr(request)->h_source;
 	ns_olen = request->len - skb_transport_offset(request) - sizeof(*ns);
 	for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
+		if (!ns->opt[i + 1]) {
+			kfree_skb(reply);
+			return NULL;
+		}
 		if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
 			daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
 			break;
@@ -1854,7 +2034,6 @@
 {
 	struct dst_entry *ndst;
 	struct flowi6 fl6;
-	int err;
 
 	memset(&fl6, 0, sizeof(fl6));
 	fl6.flowi6_oif = oif;
@@ -1863,11 +2042,11 @@
 	fl6.flowi6_mark = skb->mark;
 	fl6.flowi6_proto = IPPROTO_UDP;
 
-	err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
-					 vxlan->vn6_sock->sock->sk,
-					 &ndst, &fl6);
-	if (err < 0)
-		return ERR_PTR(err);
+	ndst = ipv6_stub->ipv6_dst_lookup_flow(vxlan->net,
+					       vxlan->vn6_sock->sock->sk,
+					       &fl6, NULL);
+	if (IS_ERR(ndst))
+		return ndst;
 
 	*saddr = fl6.saddr;
 	return ndst;
@@ -1881,7 +2060,7 @@
 	struct pcpu_sw_netstats *tx_stats, *rx_stats;
 	union vxlan_addr loopback;
 	union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip;
-	struct net_device *dev = skb->dev;
+	struct net_device *dev;
 	int len = skb->len;
 
 	tx_stats = this_cpu_ptr(src_vxlan->dev->tstats);
@@ -1901,8 +2080,15 @@
 #endif
 	}
 
+	rcu_read_lock();
+	dev = skb->dev;
+	if (unlikely(!(dev->flags & IFF_UP))) {
+		kfree_skb(skb);
+		goto drop;
+	}
+
 	if (dst_vxlan->flags & VXLAN_F_LEARN)
-		vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source);
+		vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source);
 
 	u64_stats_update_begin(&tx_stats->syncp);
 	tx_stats->tx_packets++;
@@ -1915,8 +2101,10 @@
 		rx_stats->rx_bytes += len;
 		u64_stats_update_end(&rx_stats->syncp);
 	} else {
+drop:
 		dev->stats.rx_dropped++;
 	}
+	rcu_read_unlock();
 }
 
 static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
@@ -1984,16 +2172,14 @@
 				     vxlan->cfg.port_max, true);
 
 	if (info) {
-		if (info->key.tun_flags & TUNNEL_CSUM)
-			flags |= VXLAN_F_UDP_CSUM;
-		else
-			flags &= ~VXLAN_F_UDP_CSUM;
-
 		ttl = info->key.ttl;
 		tos = info->key.tos;
 
-		if (info->options_len)
+		if (info->options_len) {
+			if (info->options_len < sizeof(*md))
+				goto drop;
 			md = ip_tunnel_info_opts(info);
+		}
 	} else {
 		md->gbp = skb->mark;
 	}
@@ -2003,8 +2189,15 @@
 			goto drop;
 		sk = vxlan->vn4_sock->sock->sk;
 
-		if (info && (info->key.tun_flags & TUNNEL_DONT_FRAGMENT))
-			df = htons(IP_DF);
+		if (info) {
+			if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)
+				df = htons(IP_DF);
+
+			if (info->key.tun_flags & TUNNEL_CSUM)
+				flags |= VXLAN_F_UDP_CSUM;
+			else
+				flags &= ~VXLAN_F_UDP_CSUM;
+		}
 
 		memset(&fl4, 0, sizeof(fl4));
 		fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0;
@@ -2029,8 +2222,15 @@
 			goto rt_tx_error;
 		}
 
+		if (fan_has_map(&vxlan->fan) && rt->rt_flags & RTCF_LOCAL) {
+			netdev_dbg(dev, "discard fan to localhost %pI4\n",
+				   &dst->sin.sin_addr.s_addr);
+			ip_rt_put(rt);
+			goto tx_free;
+		}
+
 		/* Bypass encapsulation if the destination is local */
-		if (rt->rt_flags & RTCF_LOCAL &&
+		if (!info && rt->rt_flags & RTCF_LOCAL &&
 		    !(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
 			struct vxlan_dev *dst_vxlan;
 
@@ -2088,7 +2288,7 @@
 
 		/* Bypass encapsulation if the destination is local */
 		rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags;
-		if (rt6i_flags & RTF_LOCAL &&
+		if (!info && rt6i_flags & RTF_LOCAL &&
 		    !(rt6i_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
 			struct vxlan_dev *dst_vxlan;
 
@@ -2102,6 +2302,13 @@
 			return;
 		}
 
+		if (info) {
+			if (info->key.tun_flags & TUNNEL_CSUM)
+				flags &= ~VXLAN_F_UDP_ZERO_CSUM6_TX;
+			else
+				flags |= VXLAN_F_UDP_ZERO_CSUM6_TX;
+		}
+
 		ttl = ttl ? : ip6_dst_hoplimit(ndst);
 		err = vxlan6_xmit_skb(ndst, sk, skb, dev, &saddr, &dst->sin6.sin6_addr,
 				      0, ttl, src_port, dst_port, htonl(vni << 8), md,
@@ -2169,6 +2376,20 @@
 		return NETDEV_TX_OK;
 	}
 
+	if (fan_has_map(&vxlan->fan)) {
+		struct vxlan_rdst fan_rdst;
+
+		netdev_dbg(vxlan->dev, "vxlan_xmit p %x d %pM\n",
+			   eth->h_proto, eth->h_dest);
+		if (vxlan_fan_build_rdst(vxlan, skb, &fan_rdst)) {
+			dev->stats.tx_dropped++;
+			kfree_skb(skb);
+			return NETDEV_TX_OK;
+		}
+		vxlan_xmit_one(skb, dev, &fan_rdst, 0);
+		return NETDEV_TX_OK;
+	}
+
 	f = vxlan_find_mac(vxlan, eth->h_dest);
 	did_rsc = false;
 
@@ -2231,7 +2452,7 @@
 				= container_of(p, struct vxlan_fdb, hlist);
 			unsigned long timeout;
 
-			if (f->state & NUD_PERMANENT)
+			if (f->state & (NUD_PERMANENT | NUD_NOARP))
 				continue;
 
 			timeout = f->used + vxlan->cfg.age_interval * HZ;
@@ -2250,6 +2471,15 @@
 	mod_timer(&vxlan->age_timer, next_timer);
 }
 
+static void vxlan_vs_del_dev(struct vxlan_dev *vxlan)
+{
+	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
+
+	spin_lock(&vn->sock_lock);
+	hlist_del_init_rcu(&vxlan->hlist);
+	spin_unlock(&vn->sock_lock);
+}
+
 static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
 {
 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
@@ -2263,10 +2493,19 @@
 /* Setup stats when device is created */
 static int vxlan_init(struct net_device *dev)
 {
+	struct vxlan_dev *vxlan = netdev_priv(dev);
+	int err;
+
 	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
 	if (!dev->tstats)
 		return -ENOMEM;
 
+	err = gro_cells_init(&vxlan->gro_cells, dev);
+	if (err) {
+		free_percpu(dev->tstats);
+		return err;
+	}
+
 	return 0;
 }
 
@@ -2285,6 +2524,8 @@
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 
+	gro_cells_destroy(&vxlan->gro_cells);
+
 	vxlan_fdb_delete_default(vxlan);
 
 	free_percpu(dev->tstats);
@@ -2359,29 +2600,43 @@
 {
 }
 
-static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
+static int __vxlan_change_mtu(struct net_device *dev,
+			      struct net_device *lowerdev,
+			      struct vxlan_rdst *dst, int new_mtu, bool strict)
 {
-	struct vxlan_dev *vxlan = netdev_priv(dev);
-	struct vxlan_rdst *dst = &vxlan->default_dst;
-	struct net_device *lowerdev;
-	int max_mtu;
+	int max_mtu = IP_MAX_MTU;
 
-	lowerdev = __dev_get_by_index(vxlan->net, dst->remote_ifindex);
-	if (lowerdev == NULL)
-		return eth_change_mtu(dev, new_mtu);
+	if (lowerdev)
+		max_mtu = lowerdev->mtu;
 
 	if (dst->remote_ip.sa.sa_family == AF_INET6)
-		max_mtu = lowerdev->mtu - VXLAN6_HEADROOM;
+		max_mtu -= VXLAN6_HEADROOM;
 	else
-		max_mtu = lowerdev->mtu - VXLAN_HEADROOM;
+		max_mtu -= VXLAN_HEADROOM;
 
-	if (new_mtu < 68 || new_mtu > max_mtu)
+	if (new_mtu < 68)
 		return -EINVAL;
 
+	if (new_mtu > max_mtu) {
+		if (strict)
+			return -EINVAL;
+
+		new_mtu = max_mtu;
+	}
+
 	dev->mtu = new_mtu;
 	return 0;
 }
 
+static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct vxlan_dev *vxlan = netdev_priv(dev);
+	struct vxlan_rdst *dst = &vxlan->default_dst;
+	struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
+							 dst->remote_ifindex);
+	return __vxlan_change_mtu(dev, lowerdev, dst, new_mtu, true);
+}
+
 static int egress_ipv4_tun_info(struct net_device *dev, struct sk_buff *skb,
 				struct ip_tunnel_info *info,
 				__be16 sport, __be16 dport)
@@ -2528,10 +2783,10 @@
 
 	vxlan->dev = dev;
 
-	gro_cells_init(&vxlan->gro_cells, dev);
-
 	for (h = 0; h < FDB_HASH_SIZE; ++h)
 		INIT_HLIST_HEAD(&vxlan->fdb_head[h]);
+
+	INIT_LIST_HEAD(&vxlan->fan.fan_maps);
 }
 
 static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
@@ -2581,7 +2836,7 @@
 
 	if (data[IFLA_VXLAN_ID]) {
 		__u32 id = nla_get_u32(data[IFLA_VXLAN_ID]);
-		if (id >= VXLAN_VID_MASK)
+		if (id >= VXLAN_N_VID)
 			return -ERANGE;
 	}
 
@@ -2730,17 +2985,21 @@
 
 static int vxlan_sock_add(struct vxlan_dev *vxlan)
 {
-	bool ipv6 = vxlan->flags & VXLAN_F_IPV6;
 	bool metadata = vxlan->flags & VXLAN_F_COLLECT_METADATA;
+	bool ipv6 = vxlan->flags & VXLAN_F_IPV6 || metadata;
+	bool ipv4 = !ipv6 || metadata;
 	int ret = 0;
 
 	vxlan->vn4_sock = NULL;
 #if IS_ENABLED(CONFIG_IPV6)
 	vxlan->vn6_sock = NULL;
-	if (ipv6 || metadata)
+	if (ipv6) {
 		ret = __vxlan_sock_add(vxlan, true);
+		if (ret < 0 && ret != -EAFNOSUPPORT)
+			ipv4 = false;
+	}
 #endif
-	if (!ret && (!ipv6 || metadata))
+	if (ipv4)
 		ret = __vxlan_sock_add(vxlan, false);
 	if (ret < 0)
 		vxlan_sock_release(vxlan);
@@ -2751,12 +3010,13 @@
 			       struct vxlan_config *conf)
 {
 	struct vxlan_net *vn = net_generic(src_net, vxlan_net_id);
-	struct vxlan_dev *vxlan = netdev_priv(dev);
+	struct vxlan_dev *vxlan = netdev_priv(dev), *tmp;
 	struct vxlan_rdst *dst = &vxlan->default_dst;
 	unsigned short needed_headroom = ETH_HLEN;
 	int err;
 	bool use_ipv6 = false;
 	__be16 default_port = vxlan->cfg.dst_port;
+	struct net_device *lowerdev = NULL;
 
 	vxlan->net = src_net;
 
@@ -2777,9 +3037,7 @@
 	}
 
 	if (conf->remote_ifindex) {
-		struct net_device *lowerdev
-			 = __dev_get_by_index(src_net, conf->remote_ifindex);
-
+		lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
 		dst->remote_ifindex = conf->remote_ifindex;
 
 		if (!lowerdev) {
@@ -2803,6 +3061,17 @@
 		needed_headroom = lowerdev->hard_header_len;
 	}
 
+	if (lowerdev) {
+		dev->gso_max_size = lowerdev->gso_max_size;
+		dev->gso_max_segs = lowerdev->gso_max_segs;
+	}
+
+	if (conf->mtu) {
+		err = __vxlan_change_mtu(dev, lowerdev, dst, conf->mtu, false);
+		if (err)
+			return err;
+	}
+
 	if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
 		needed_headroom += VXLAN6_HEADROOM;
 	else
@@ -2817,9 +3086,15 @@
 	if (!vxlan->cfg.age_interval)
 		vxlan->cfg.age_interval = FDB_AGE_DEFAULT;
 
-	if (vxlan_find_vni(src_net, conf->vni, use_ipv6 ? AF_INET6 : AF_INET,
-			   vxlan->cfg.dst_port, vxlan->flags))
+	list_for_each_entry(tmp, &vn->vxlan_list, next) {
+		if (tmp->cfg.vni == conf->vni &&
+		    (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 ||
+		     tmp->cfg.saddr.sa.sa_family == AF_INET6) == use_ipv6 &&
+		    tmp->cfg.dst_port == vxlan->cfg.dst_port &&
+		    (tmp->flags & VXLAN_F_RCV_FLAGS) ==
+		    (vxlan->flags & VXLAN_F_RCV_FLAGS))
 		return -EEXIST;
+	}
 
 	dev->ethtool_ops = &vxlan_ethtool_ops;
 
@@ -2848,33 +3123,10 @@
 	return 0;
 }
 
-struct net_device *vxlan_dev_create(struct net *net, const char *name,
-				    u8 name_assign_type, struct vxlan_config *conf)
-{
-	struct nlattr *tb[IFLA_MAX+1];
-	struct net_device *dev;
-	int err;
-
-	memset(&tb, 0, sizeof(tb));
-
-	dev = rtnl_create_link(net, name, name_assign_type,
-			       &vxlan_link_ops, tb);
-	if (IS_ERR(dev))
-		return dev;
-
-	err = vxlan_dev_configure(net, dev, conf);
-	if (err < 0) {
-		free_netdev(dev);
-		return ERR_PTR(err);
-	}
-
-	return dev;
-}
-EXPORT_SYMBOL_GPL(vxlan_dev_create);
-
 static int vxlan_newlink(struct net *src_net, struct net_device *dev,
 			 struct nlattr *tb[], struct nlattr *data[])
 {
+	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_config conf;
 	int err;
 
@@ -2893,6 +3145,12 @@
 		conf.remote_ip.sa.sa_family = AF_INET6;
 	}
 
+	if (data[IFLA_VXLAN_FAN_MAP]) {
+		err = vxlan_parse_fan_map(data, vxlan);
+		if (err)
+			return err;
+	}
+
 	if (data[IFLA_VXLAN_LOCAL]) {
 		conf.saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]);
 		conf.saddr.sa.sa_family = AF_INET;
@@ -2974,6 +3232,9 @@
 	if (data[IFLA_VXLAN_REMCSUM_NOPARTIAL])
 		conf.flags |= VXLAN_F_REMCSUM_NOPARTIAL;
 
+	if (tb[IFLA_MTU])
+		conf.mtu = nla_get_u32(tb[IFLA_MTU]);
+
 	err = vxlan_dev_configure(src_net, dev, &conf);
 	switch (err) {
 	case -ENODEV:
@@ -2995,14 +3256,7 @@
 static void vxlan_dellink(struct net_device *dev, struct list_head *head)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
-	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
-
-	spin_lock(&vn->sock_lock);
-	if (!hlist_unhashed(&vxlan->hlist))
-		hlist_del_rcu(&vxlan->hlist);
-	spin_unlock(&vn->sock_lock);
 
-	gro_cells_destroy(&vxlan->gro_cells);
 	list_del(&vxlan->next);
 	unregister_netdevice_queue(dev, head);
 }
@@ -3031,6 +3285,7 @@
 		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */
 		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */
 		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */
+		nla_total_size(sizeof(struct ip_fan_map) * 256) +
 		0;
 }
 
@@ -3077,6 +3332,26 @@
 		}
 	}
 
+	if (fan_has_map(&vxlan->fan)) {
+		struct nlattr *fan_nest;
+		struct ip_fan_map *fan_map;
+
+		fan_nest = nla_nest_start(skb, IFLA_VXLAN_FAN_MAP);
+		if (!fan_nest)
+			goto nla_put_failure;
+		list_for_each_entry_rcu(fan_map, &vxlan->fan.fan_maps, list) {
+			struct ifla_fan_map map;
+
+			map.underlay = fan_map->underlay;
+			map.underlay_prefix = fan_map->underlay_prefix;
+			map.overlay = fan_map->overlay;
+			map.overlay_prefix = fan_map->overlay_prefix;
+			if (nla_put(skb, IFLA_FAN_MAPPING, sizeof(map), &map))
+				goto nla_put_failure;
+		}
+		nla_nest_end(skb, fan_nest);
+	}
+
 	if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->cfg.ttl) ||
 	    nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) ||
 	    nla_put_u8(skb, IFLA_VXLAN_LEARNING,
@@ -3143,6 +3418,40 @@
 	.get_link_net	= vxlan_get_link_net,
 };
 
+struct net_device *vxlan_dev_create(struct net *net, const char *name,
+				    u8 name_assign_type,
+				    struct vxlan_config *conf)
+{
+	struct nlattr *tb[IFLA_MAX + 1];
+	struct net_device *dev;
+	int err;
+
+	memset(&tb, 0, sizeof(tb));
+
+	dev = rtnl_create_link(net, name, name_assign_type,
+			       &vxlan_link_ops, tb);
+	if (IS_ERR(dev))
+		return dev;
+
+	err = vxlan_dev_configure(net, dev, conf);
+	if (err < 0) {
+		free_netdev(dev);
+		return ERR_PTR(err);
+	}
+
+	err = rtnl_configure_link(dev, NULL);
+	if (err < 0) {
+		LIST_HEAD(list_kill);
+
+		vxlan_dellink(dev, &list_kill);
+		unregister_netdevice_many(&list_kill);
+		return ERR_PTR(err);
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(vxlan_dev_create);
+
 static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn,
 					     struct net_device *dev)
 {
@@ -3195,6 +3504,22 @@
 	return 0;
 }
 
+#ifdef CONFIG_SYSCTL
+static struct ctl_table_header *vxlan_fan_header;
+static unsigned int vxlan_fan_version = 4;
+
+static struct ctl_table vxlan_fan_sysctls[] = {
+	{
+		.procname	= "vxlan",
+		.data		= &vxlan_fan_version,
+		.maxlen		= sizeof(vxlan_fan_version),
+		.mode		= 0444,
+		.proc_handler	= proc_dointvec,
+	},
+	{},
+};
+#endif /* CONFIG_SYSCTL */
+
 static void __net_exit vxlan_exit_net(struct net *net)
 {
 	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
@@ -3211,10 +3536,8 @@
 		/* If vxlan->dev is in the same netns, it has already been added
 		 * to the list by the previous loop.
 		 */
-		if (!net_eq(dev_net(vxlan->dev), net)) {
-			gro_cells_destroy(&vxlan->gro_cells);
+		if (!net_eq(dev_net(vxlan->dev), net))
 			unregister_netdevice_queue(vxlan->dev, &list);
-		}
 	}
 
 	unregister_netdevice_many(&list);
@@ -3250,7 +3573,20 @@
 	if (rc)
 		goto out3;
 
+#ifdef CONFIG_SYSCTL
+	vxlan_fan_header = register_net_sysctl(&init_net, "net/fan",
+					      vxlan_fan_sysctls);
+	if (!vxlan_fan_header) {
+		rc = -ENOMEM;
+		goto sysctl_failed;
+	}
+#endif /* CONFIG_SYSCTL */
+
 	return 0;
+#ifdef CONFIG_SYSCTL
+sysctl_failed:
+	rtnl_link_unregister(&vxlan_link_ops);
+#endif /* CONFIG_SYSCTL */
 out3:
 	unregister_netdevice_notifier(&vxlan_notifier_block);
 out2:
@@ -3263,6 +3599,9 @@
 
 static void __exit vxlan_cleanup_module(void)
 {
+#ifdef CONFIG_SYSCTL
+	unregister_net_sysctl_table(vxlan_fan_header);
+#endif /* CONFIG_SYSCTL */
 	rtnl_link_unregister(&vxlan_link_ops);
 	unregister_netdevice_notifier(&vxlan_notifier_block);
 	destroy_workqueue(vxlan_wq);
--- linux-4.4.0.orig/drivers/net/wan/cosa.c
+++ linux-4.4.0/drivers/net/wan/cosa.c
@@ -232,11 +232,11 @@
 static struct class *cosa_class;
 
 #ifdef MODULE
-module_param_array(io, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
 MODULE_PARM_DESC(io, "The I/O bases of the COSA or SRP cards");
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(irq, "The IRQ lines of the COSA or SRP cards");
-module_param_array(dma, int, NULL, 0);
+module_param_hw_array(dma, int, dma, NULL, 0);
 MODULE_PARM_DESC(dma, "The DMA channels of the COSA or SRP cards");
 
 MODULE_AUTHOR("Jan \"Yenya\" Kasprzak, <kas@fi.muni.cz>");
@@ -903,6 +903,7 @@
 			chan->tx_status = 1;
 			spin_unlock_irqrestore(&cosa->lock, flags);
 			up(&chan->wsem);
+			kfree(kbuf);
 			return -ERESTARTSYS;
 		}
 	}
--- linux-4.4.0.orig/drivers/net/wan/farsync.c
+++ linux-4.4.0/drivers/net/wan/farsync.c
@@ -2516,7 +2516,7 @@
                 dev->mem_start   = card->phys_mem
                                  + BUF_OFFSET ( txBuffer[i][0][0]);
                 dev->mem_end     = card->phys_mem
-                                 + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]);
+                                 + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER - 1][LEN_RX_BUFFER - 1]);
                 dev->base_addr   = card->pci_conf;
                 dev->irq         = card->irq;
 
--- linux-4.4.0.orig/drivers/net/wan/hdlc.c
+++ linux-4.4.0/drivers/net/wan/hdlc.c
@@ -57,7 +57,15 @@
 static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
 		    struct packet_type *p, struct net_device *orig_dev)
 {
-	struct hdlc_device *hdlc = dev_to_hdlc(dev);
+	struct hdlc_device *hdlc;
+
+	/* First make sure "dev" is an HDLC device */
+	if (!(dev->priv_flags & IFF_WAN_HDLC)) {
+		kfree_skb(skb);
+		return NET_RX_SUCCESS;
+	}
+
+	hdlc = dev_to_hdlc(dev);
 
 	if (!net_eq(dev_net(dev), &init_net)) {
 		kfree_skb(skb);
--- linux-4.4.0.orig/drivers/net/wan/hdlc_cisco.c
+++ linux-4.4.0/drivers/net/wan/hdlc_cisco.c
@@ -120,6 +120,7 @@
 	skb_put(skb, sizeof(struct cisco_packet));
 	skb->priority = TC_PRIO_CONTROL;
 	skb->dev = dev;
+	skb->protocol = htons(ETH_P_HDLC);
 	skb_reset_network_header(skb);
 
 	dev_queue_xmit(skb);
@@ -377,6 +378,7 @@
 		memcpy(&state(hdlc)->settings, &new_settings, size);
 		spin_lock_init(&state(hdlc)->lock);
 		dev->header_ops = &cisco_header_ops;
+		dev->hard_header_len = sizeof(struct hdlc_header);
 		dev->type = ARPHRD_CISCO;
 		netif_dormant_on(dev);
 		return 0;
--- linux-4.4.0.orig/drivers/net/wan/hdlc_fr.c
+++ linux-4.4.0/drivers/net/wan/hdlc_fr.c
@@ -275,63 +275,69 @@
 
 static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
 {
-	u16 head_len;
 	struct sk_buff *skb = *skb_p;
 
-	switch (skb->protocol) {
-	case cpu_to_be16(NLPID_CCITT_ANSI_LMI):
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = NLPID_CCITT_ANSI_LMI;
-		break;
-
-	case cpu_to_be16(NLPID_CISCO_LMI):
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = NLPID_CISCO_LMI;
-		break;
-
-	case cpu_to_be16(ETH_P_IP):
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = NLPID_IP;
-		break;
-
-	case cpu_to_be16(ETH_P_IPV6):
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = NLPID_IPV6;
-		break;
-
-	case cpu_to_be16(ETH_P_802_3):
-		head_len = 10;
-		if (skb_headroom(skb) < head_len) {
-			struct sk_buff *skb2 = skb_realloc_headroom(skb,
-								    head_len);
+	if (!skb->dev) { /* Control packets */
+		switch (dlci) {
+		case LMI_CCITT_ANSI_DLCI:
+			skb_push(skb, 4);
+			skb->data[3] = NLPID_CCITT_ANSI_LMI;
+			break;
+
+		case LMI_CISCO_DLCI:
+			skb_push(skb, 4);
+			skb->data[3] = NLPID_CISCO_LMI;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+	} else if (skb->dev->type == ARPHRD_DLCI) {
+		switch (skb->protocol) {
+		case htons(ETH_P_IP):
+			skb_push(skb, 4);
+			skb->data[3] = NLPID_IP;
+			break;
+
+		case htons(ETH_P_IPV6):
+			skb_push(skb, 4);
+			skb->data[3] = NLPID_IPV6;
+			break;
+
+		default:
+			skb_push(skb, 10);
+			skb->data[3] = FR_PAD;
+			skb->data[4] = NLPID_SNAP;
+			/* OUI 00-00-00 indicates an Ethertype follows */
+			skb->data[5] = 0x00;
+			skb->data[6] = 0x00;
+			skb->data[7] = 0x00;
+			/* This should be an Ethertype: */
+			*(__be16 *)(skb->data + 8) = skb->protocol;
+		}
+
+	} else if (skb->dev->type == ARPHRD_ETHER) {
+		if (skb_headroom(skb) < 10) {
+			struct sk_buff *skb2 = skb_realloc_headroom(skb, 10);
 			if (!skb2)
 				return -ENOBUFS;
 			dev_kfree_skb(skb);
 			skb = *skb_p = skb2;
 		}
-		skb_push(skb, head_len);
+		skb_push(skb, 10);
 		skb->data[3] = FR_PAD;
 		skb->data[4] = NLPID_SNAP;
-		skb->data[5] = FR_PAD;
+		/* OUI 00-80-C2 stands for the 802.1 organization */
+		skb->data[5] = 0x00;
 		skb->data[6] = 0x80;
 		skb->data[7] = 0xC2;
+		/* PID 00-07 stands for Ethernet frames without FCS */
 		skb->data[8] = 0x00;
-		skb->data[9] = 0x07; /* bridged Ethernet frame w/out FCS */
-		break;
+		skb->data[9] = 0x07;
 
-	default:
-		head_len = 10;
-		skb_push(skb, head_len);
-		skb->data[3] = FR_PAD;
-		skb->data[4] = NLPID_SNAP;
-		skb->data[5] = FR_PAD;
-		skb->data[6] = FR_PAD;
-		skb->data[7] = FR_PAD;
-		*(__be16*)(skb->data + 8) = skb->protocol;
+	} else {
+		return -EINVAL;
 	}
 
 	dlci_to_q922(skb->data, dlci);
@@ -427,14 +433,16 @@
 				skb_put(skb, pad);
 				memset(skb->data + len, 0, pad);
 			}
-			skb->protocol = cpu_to_be16(ETH_P_802_3);
 		}
+		skb->dev = dev;
 		if (!fr_hard_header(&skb, pvc->dlci)) {
 			dev->stats.tx_bytes += skb->len;
 			dev->stats.tx_packets++;
 			if (pvc->state.fecn) /* TX Congestion counter */
 				dev->stats.tx_compressed++;
 			skb->dev = pvc->frad;
+			skb->protocol = htons(ETH_P_HDLC);
+			skb_reset_network_header(skb);
 			dev_queue_xmit(skb);
 			return NETDEV_TX_OK;
 		}
@@ -494,10 +502,8 @@
 	memset(skb->data, 0, len);
 	skb_reserve(skb, 4);
 	if (lmi == LMI_CISCO) {
-		skb->protocol = cpu_to_be16(NLPID_CISCO_LMI);
 		fr_hard_header(&skb, LMI_CISCO_DLCI);
 	} else {
-		skb->protocol = cpu_to_be16(NLPID_CCITT_ANSI_LMI);
 		fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI);
 	}
 	data = skb_tail_pointer(skb);
@@ -557,6 +563,7 @@
 	skb_put(skb, i);
 	skb->priority = TC_PRIO_CONTROL;
 	skb->dev = dev;
+	skb->protocol = htons(ETH_P_HDLC);
 	skb_reset_network_header(skb);
 
 	dev_queue_xmit(skb);
--- linux-4.4.0.orig/drivers/net/wan/hdlc_ppp.c
+++ linux-4.4.0/drivers/net/wan/hdlc_ppp.c
@@ -254,6 +254,7 @@
 
 	skb->priority = TC_PRIO_CONTROL;
 	skb->dev = dev;
+	skb->protocol = htons(ETH_P_HDLC);
 	skb_reset_network_header(skb);
 	skb_queue_tail(&tx_queue, skb);
 }
@@ -386,11 +387,8 @@
 	}
 
 	for (opt = data; len; len -= opt[1], opt += opt[1]) {
-		if (len < 2 || len < opt[1]) {
-			dev->stats.rx_errors++;
-			kfree(out);
-			return; /* bad packet, drop silently */
-		}
+		if (len < 2 || opt[1] < 2 || len < opt[1])
+			goto err_out;
 
 		if (pid == PID_LCP)
 			switch (opt[0]) {
@@ -398,6 +396,8 @@
 				continue; /* MRU always OK and > 1500 bytes? */
 
 			case LCP_OPTION_ACCM: /* async control character map */
+				if (opt[1] < sizeof(valid_accm))
+					goto err_out;
 				if (!memcmp(opt, valid_accm,
 					    sizeof(valid_accm)))
 					continue;
@@ -409,6 +409,8 @@
 				}
 				break;
 			case LCP_OPTION_MAGIC:
+				if (len < 6)
+					goto err_out;
 				if (opt[1] != 6 || (!opt[2] && !opt[3] &&
 						    !opt[4] && !opt[5]))
 					break; /* reject invalid magic number */
@@ -427,6 +429,11 @@
 		ppp_cp_event(dev, pid, RCR_GOOD, CP_CONF_ACK, id, req_len, data);
 
 	kfree(out);
+	return;
+
+err_out:
+	dev->stats.rx_errors++;
+	kfree(out);
 }
 
 static int ppp_rx(struct sk_buff *skb)
@@ -565,6 +572,13 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&ppp->lock, flags);
+	/* mod_timer could be called after we entered this function but
+	 * before we got the lock.
+	 */
+	if (timer_pending(&proto->timer)) {
+		spin_unlock_irqrestore(&ppp->lock, flags);
+		return;
+	}
 	switch (proto->state) {
 	case STOPPING:
 	case REQ_SENT:
@@ -574,7 +588,10 @@
 			ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0,
 				     0, NULL);
 			proto->restart_counter--;
-		} else
+		} else if (netif_carrier_ok(proto->dev))
+			ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0,
+				     0, NULL);
+		else
 			ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0,
 				     0, NULL);
 		break;
--- linux-4.4.0.orig/drivers/net/wan/hdlc_raw_eth.c
+++ linux-4.4.0/drivers/net/wan/hdlc_raw_eth.c
@@ -101,6 +101,7 @@
 		old_qlen = dev->tx_queue_len;
 		ether_setup(dev);
 		dev->tx_queue_len = old_qlen;
+		dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 		eth_hw_addr_random(dev);
 		netif_dormant_off(dev);
 		return 0;
--- linux-4.4.0.orig/drivers/net/wan/hostess_sv11.c
+++ linux-4.4.0/drivers/net/wan/hostess_sv11.c
@@ -325,11 +325,11 @@
 static int io = 0x200;
 static int irq = 9;
 
-module_param(io, int, 0);
+module_param_hw(io, int, ioport, 0);
 MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card");
-module_param(dma, int, 0);
+module_param_hw(dma, int, dma, 0);
 MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX");
-module_param(irq, int, 0);
+module_param_hw(irq, int, irq, 0);
 MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card");
 
 MODULE_AUTHOR("Alan Cox");
--- linux-4.4.0.orig/drivers/net/wan/ixp4xx_hss.c
+++ linux-4.4.0/drivers/net/wan/ixp4xx_hss.c
@@ -261,7 +261,7 @@
 	struct hss_plat_info *plat;
 	buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
 	struct desc *desc_tab;	/* coherent */
-	u32 desc_tab_phys;
+	dma_addr_t desc_tab_phys;
 	unsigned int id;
 	unsigned int clock_type, clock_rate, loopback;
 	unsigned int initialized, carrier;
@@ -861,7 +861,7 @@
 		dev->stats.tx_dropped++;
 		return NETDEV_TX_OK;
 	}
-	memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
+	memcpy_swab32(mem, (u32 *)((uintptr_t)skb->data & ~3), bytes / 4);
 	dev_kfree_skb(skb);
 #endif
 
--- linux-4.4.0.orig/drivers/net/wan/lapbether.c
+++ linux-4.4.0/drivers/net/wan/lapbether.c
@@ -160,6 +160,12 @@
 	if (!netif_running(dev))
 		goto drop;
 
+	/* There should be a pseudo header of 1 byte added by upper layers.
+	 * Check to make sure it is there before reading it.
+	 */
+	if (skb->len < 1)
+		goto drop;
+
 	switch (skb->data[0]) {
 	case X25_IFACE_DATA:
 		break;
@@ -195,8 +201,6 @@
 	struct net_device *dev;
 	int size = skb->len;
 
-	skb->protocol = htons(ETH_P_X25);
-
 	ptr = skb_push(skb, 2);
 
 	*ptr++ = size % 256;
@@ -207,6 +211,10 @@
 
 	skb->dev = dev = lapbeth->ethdev;
 
+	skb->protocol = htons(ETH_P_DEC);
+
+	skb_reset_network_header(skb);
+
 	dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
 
 	dev_queue_xmit(skb);
@@ -278,7 +286,6 @@
 		return -ENODEV;
 	}
 
-	netif_start_queue(dev);
 	return 0;
 }
 
@@ -286,8 +293,6 @@
 {
 	int err;
 
-	netif_stop_queue(dev);
-
 	if ((err = lapb_unregister(dev)) != LAPB_OK)
 		pr_err("lapb_unregister error: %d\n", err);
 
@@ -308,7 +313,7 @@
 	dev->netdev_ops	     = &lapbeth_netdev_ops;
 	dev->destructor	     = free_netdev;
 	dev->type            = ARPHRD_X25;
-	dev->hard_header_len = 3;
+	dev->hard_header_len = 0;
 	dev->mtu             = 1000;
 	dev->addr_len        = 0;
 }
@@ -329,6 +334,16 @@
 	if (!ndev)
 		goto out;
 
+	/* When transmitting data:
+	 * first this driver removes a pseudo header of 1 byte,
+	 * then the lapb module prepends an LAPB header of at most 3 bytes,
+	 * then this driver prepends a length field of 2 bytes,
+	 * then the underlying Ethernet device prepends its own header.
+	 */
+	ndev->needed_headroom = -1 + 3 + 2 + dev->hard_header_len
+					   + dev->needed_headroom;
+	ndev->needed_tailroom = dev->needed_tailroom;
+
 	lapbeth = netdev_priv(ndev);
 	lapbeth->axdev = ndev;
 
--- linux-4.4.0.orig/drivers/net/wan/lmc/lmc_main.c
+++ linux-4.4.0/drivers/net/wan/lmc/lmc_main.c
@@ -1385,7 +1385,7 @@
             case 0x001:
                 printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name);
                 break;
-            case 0x010:
+            case 0x002:
                 printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name);
                 break;
             default:
--- linux-4.4.0.orig/drivers/net/wan/pc300too.c
+++ linux-4.4.0/drivers/net/wan/pc300too.c
@@ -347,6 +347,7 @@
 	    card->rambase == NULL) {
 		pr_err("ioremap() failed\n");
 		pc300_pci_remove_one(pdev);
+		return -ENOMEM;
 	}
 
 	/* PLX PCI 9050 workaround for local configuration register read bug */
--- linux-4.4.0.orig/drivers/net/wan/sbni.c
+++ linux-4.4.0/drivers/net/wan/sbni.c
@@ -1464,8 +1464,8 @@
 
 
 #ifdef MODULE
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param_array(baud, int, NULL, 0);
 module_param_array(rxl, int, NULL, 0);
 module_param_array(mac, int, NULL, 0);
--- linux-4.4.0.orig/drivers/net/wan/sdla.c
+++ linux-4.4.0/drivers/net/wan/sdla.c
@@ -711,7 +711,7 @@
 
 					spin_lock_irqsave(&sdla_lock, flags);
 					SDLA_WINDOW(dev, addr);
-					pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
+					pbuf = (void *)(dev->mem_start + (addr & SDLA_ADDR_MASK));
 					__sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
 					SDLA_WINDOW(dev, addr);
 					pbuf->opp_flag = 1;
--- linux-4.4.0.orig/drivers/net/wan/sealevel.c
+++ linux-4.4.0/drivers/net/wan/sealevel.c
@@ -364,13 +364,13 @@
 static int irq=5;
 static bool slow=false;
 
-module_param(io, int, 0);
+module_param_hw(io, int, ioport, 0);
 MODULE_PARM_DESC(io, "The I/O base of the Sealevel card");
-module_param(txdma, int, 0);
+module_param_hw(txdma, int, dma, 0);
 MODULE_PARM_DESC(txdma, "Transmit DMA channel");
-module_param(rxdma, int, 0);
+module_param_hw(rxdma, int, dma, 0);
 MODULE_PARM_DESC(rxdma, "Receive DMA channel");
-module_param(irq, int, 0);
+module_param_hw(irq, int, irq, 0);
 MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card");
 module_param(slow, bool, 0);
 MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012");
--- linux-4.4.0.orig/drivers/net/wan/x25_asy.c
+++ linux-4.4.0/drivers/net/wan/x25_asy.c
@@ -186,7 +186,7 @@
 	netif_wake_queue(sl->dev);
 }
 
-/* Send one completely decapsulated IP datagram to the IP layer. */
+/* Send an LAPB frame to the LAPB module to process. */
 
 static void x25_asy_bump(struct x25_asy *sl)
 {
@@ -198,13 +198,12 @@
 	count = sl->rcount;
 	dev->stats.rx_bytes += count;
 
-	skb = dev_alloc_skb(count+1);
+	skb = dev_alloc_skb(count);
 	if (skb == NULL) {
 		netdev_warn(sl->dev, "memory squeeze, dropping packet\n");
 		dev->stats.rx_dropped++;
 		return;
 	}
-	skb_push(skb, 1);	/* LAPB internal control */
 	memcpy(skb_put(skb, count), sl->rbuff, count);
 	skb->protocol = x25_type_trans(skb, sl->dev);
 	err = lapb_data_received(skb->dev, skb);
@@ -212,7 +211,6 @@
 		kfree_skb(skb);
 		printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
 	} else {
-		netif_rx(skb);
 		dev->stats.rx_packets++;
 	}
 }
@@ -358,12 +356,21 @@
  */
 
 /*
- *	Called when I frame data arrives. We did the work above - throw it
- *	at the net layer.
+ *	Called when I frame data arrive. We add a pseudo header for upper
+ *	layers and pass it to upper layers.
  */
 
 static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
 {
+	if (skb_cow(skb, 1)) {
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+	skb_push(skb, 1);
+	skb->data[0] = X25_IFACE_DATA;
+
+	skb->protocol = x25_type_trans(skb, dev);
+
 	return netif_rx(skb);
 }
 
@@ -655,7 +662,7 @@
 	switch (s) {
 	case X25_END:
 		if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
-		    sl->rcount > 2)
+		    sl->rcount >= 2)
 			x25_asy_bump(sl);
 		clear_bit(SLF_ESCAPE, &sl->flags);
 		sl->rcount = 0;
--- linux-4.4.0.orig/drivers/net/wimax/i2400m/fw.c
+++ linux-4.4.0/drivers/net/wimax/i2400m/fw.c
@@ -351,13 +351,15 @@
 			}
 			result = i2400m_barker_db_add(barker);
 			if (result < 0)
-				goto error_add;
+				goto error_parse_add;
 		}
 		kfree(options_orig);
 	}
 	return 0;
 
+error_parse_add:
 error_parse:
+	kfree(options_orig);
 error_add:
 	kfree(i2400m_barker_db);
 	return result;
--- linux-4.4.0.orig/drivers/net/wimax/i2400m/op-rfkill.c
+++ linux-4.4.0/drivers/net/wimax/i2400m/op-rfkill.c
@@ -147,6 +147,7 @@
 error_alloc:
 	d_fnend(4, dev, "(wimax_dev %p state %d) = %d\n",
 		wimax_dev, state, result);
+	kfree(cmd);
 	return result;
 }
 
--- linux-4.4.0.orig/drivers/net/wimax/i2400m/usb-fw.c
+++ linux-4.4.0/drivers/net/wimax/i2400m/usb-fw.c
@@ -354,6 +354,7 @@
 		usb_autopm_put_interface(i2400mu->usb_iface);
 	d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %ld\n",
 		i2400m, ack, ack_size, (long) result);
+	usb_put_urb(&notif_urb);
 	return result;
 
 error_exceeded:
--- linux-4.4.0.orig/drivers/net/wimax/i2400m/usb.c
+++ linux-4.4.0/drivers/net/wimax/i2400m/usb.c
@@ -467,6 +467,9 @@
 	struct i2400mu *i2400mu;
 	struct usb_device *usb_dev = interface_to_usbdev(iface);
 
+	if (iface->cur_altsetting->desc.bNumEndpoints < 4)
+		return -ENODEV;
+
 	if (usb_dev->speed != USB_SPEED_HIGH)
 		dev_err(dev, "device not connected as high speed\n");
 
--- linux-4.4.0.orig/drivers/net/wireless/airo.c
+++ linux-4.4.0/drivers/net/wireless/airo.c
@@ -246,8 +246,8 @@
 		   "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs.");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param_array(rates, int, NULL, 0);
 module_param_array(ssids, charp, NULL, 0);
 module_param(auto_wep, int, 0);
@@ -5484,7 +5484,7 @@
            we have to add a spin lock... */
 	rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
 	while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
-		ptr += sprintf(ptr, "%pM %*s rssi = %d",
+		ptr += sprintf(ptr, "%pM %.*s rssi = %d",
 			       BSSList_rid.bssid,
 				(int)BSSList_rid.ssidLen,
 				BSSList_rid.ssid,
@@ -7808,16 +7808,8 @@
 	case AIROGVLIST:    ridcode = RID_APLIST;       break;
 	case AIROGDRVNAM:   ridcode = RID_DRVNAME;      break;
 	case AIROGEHTENC:   ridcode = RID_ETHERENCAP;   break;
-	case AIROGWEPKTMP:  ridcode = RID_WEP_TEMP;
-		/* Only super-user can read WEP keys */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		break;
-	case AIROGWEPKNV:   ridcode = RID_WEP_PERM;
-		/* Only super-user can read WEP keys */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		break;
+	case AIROGWEPKTMP:  ridcode = RID_WEP_TEMP;	break;
+	case AIROGWEPKNV:   ridcode = RID_WEP_PERM;	break;
 	case AIROGSTAT:     ridcode = RID_STATUS;       break;
 	case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
 	case AIROGSTATSC32: ridcode = RID_STATS;        break;
@@ -7831,7 +7823,13 @@
 		return -EINVAL;
 	}
 
-	if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
+	if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) {
+		/* Only super-user can read WEP keys */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+	}
+
+	if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
 	PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1);
--- linux-4.4.0.orig/drivers/net/wireless/at76c50x-usb.c
+++ linux-4.4.0/drivers/net/wireless/at76c50x-usb.c
@@ -2582,8 +2582,8 @@
 	if (result < 0)
 		printk(KERN_ERR DRIVER_NAME
 		       ": usb_register failed (status %d)\n", result);
-
-	led_trigger_register_simple("at76_usb-tx", &ledtrig_tx);
+	else
+		led_trigger_register_simple("at76_usb-tx", &ledtrig_tx);
 	return result;
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ar5523/ar5523.c
+++ linux-4.4.0/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -255,7 +255,8 @@
 
 	if (flags & AR5523_CMD_FLAG_MAGIC)
 		hdr->magic = cpu_to_be32(1 << 24);
-	memcpy(hdr + 1, idata, ilen);
+	if (ilen)
+		memcpy(hdr + 1, idata, ilen);
 
 	cmd->odata = odata;
 	cmd->olen = olen;
@@ -1773,6 +1774,8 @@
 	AR5523_DEVICE_UX(0x0846, 0x4300),	/* Netgear / WG111U */
 	AR5523_DEVICE_UG(0x0846, 0x4250),	/* Netgear / WG111T */
 	AR5523_DEVICE_UG(0x0846, 0x5f00),	/* Netgear / WPN111 */
+	AR5523_DEVICE_UG(0x083a, 0x4506),	/* SMC / EZ Connect
+						   SMCWUSBT-G2 */
 	AR5523_DEVICE_UG(0x157e, 0x3006),	/* Umedia / AR5523_1 */
 	AR5523_DEVICE_UX(0x157e, 0x3205),	/* Umedia / AR5523_2 */
 	AR5523_DEVICE_UG(0x157e, 0x3006),	/* Umedia / TEW444UBEU */
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath.h
@@ -199,12 +199,13 @@
 bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr);
 
 void ath_hw_setbssidmask(struct ath_common *common);
-void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key);
+void ath_key_delete(struct ath_common *common, u8 hw_key_idx);
 int ath_key_config(struct ath_common *common,
 			  struct ieee80211_vif *vif,
 			  struct ieee80211_sta *sta,
 			  struct ieee80211_key_conf *key);
 bool ath_hw_keyreset(struct ath_common *common, u16 entry);
+bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac);
 void ath_hw_cycle_counters_update(struct ath_common *common);
 int32_t ath_hw_get_listen_time(struct ath_common *common);
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/core.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/core.c
@@ -18,6 +18,9 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/of.h>
+#include <linux/dmi.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
 
 #include "core.h"
 #include "mac.h"
@@ -67,6 +70,7 @@
 			.board_size = QCA988X_BOARD_DATA_SZ,
 			.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
 		},
+		.decap_align_bytes = 4,
 	},
 	{
 		.id = QCA6174_HW_2_1_VERSION,
@@ -85,6 +89,7 @@
 			.board_size = QCA6174_BOARD_DATA_SZ,
 			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
 		},
+		.decap_align_bytes = 4,
 	},
 	{
 		.id = QCA6174_HW_2_1_VERSION,
@@ -103,6 +108,7 @@
 			.board_size = QCA6174_BOARD_DATA_SZ,
 			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
 		},
+		.decap_align_bytes = 4,
 	},
 	{
 		.id = QCA6174_HW_3_0_VERSION,
@@ -121,6 +127,7 @@
 			.board_size = QCA6174_BOARD_DATA_SZ,
 			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
 		},
+		.decap_align_bytes = 4,
 	},
 	{
 		.id = QCA6174_HW_3_2_VERSION,
@@ -140,6 +147,7 @@
 			.board_size = QCA6174_BOARD_DATA_SZ,
 			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
 		},
+		.decap_align_bytes = 4,
 	},
 	{
 		.id = QCA99X0_HW_2_0_DEV_VERSION,
@@ -159,6 +167,7 @@
 			.board_size = QCA99X0_BOARD_DATA_SZ,
 			.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
 		},
+		.decap_align_bytes = 1,
 	},
 	{
 		.id = QCA9377_HW_1_0_DEV_VERSION,
@@ -177,6 +186,7 @@
 			.board_size = QCA9377_BOARD_DATA_SZ,
 			.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
 		},
+		.decap_align_bytes = 4,
 	},
 	{
 		.id = QCA9377_HW_1_1_DEV_VERSION,
@@ -195,6 +205,7 @@
 			.board_size = QCA9377_BOARD_DATA_SZ,
 			.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
 		},
+		.decap_align_bytes = 4,
 	},
 };
 
@@ -548,8 +559,11 @@
 		   "boot get otp board id result 0x%08x board_id %d chip_id %d\n",
 		   result, board_id, chip_id);
 
-	if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0)
+	if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 ||
+	    (board_id == 0)) {
+		ath10k_warn(ar, "board id is not exist in otp, ignore it\n");
 		return -EOPNOTSUPP;
+	}
 
 	ar->id.bmi_ids_valid = true;
 	ar->id.bmi_board_id = board_id;
@@ -558,6 +572,72 @@
 	return 0;
 }
 
+static void ath10k_core_check_bdfext(const struct dmi_header *hdr, void *data)
+{
+	struct ath10k *ar = data;
+	const char *bdf_ext;
+	const char *magic = ATH10K_SMBIOS_BDF_EXT_MAGIC;
+	u8 bdf_enabled;
+	int i;
+
+	if (hdr->type != ATH10K_SMBIOS_BDF_EXT_TYPE)
+		return;
+
+	if (hdr->length != ATH10K_SMBIOS_BDF_EXT_LENGTH) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
+			   "wrong smbios bdf ext type length (%d).\n",
+			   hdr->length);
+		return;
+	}
+
+	bdf_enabled = *((u8 *)hdr + ATH10K_SMBIOS_BDF_EXT_OFFSET);
+	if (!bdf_enabled) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not found.\n");
+		return;
+	}
+
+	/* Only one string exists (per spec) */
+	bdf_ext = (char *)hdr + hdr->length;
+
+	if (memcmp(bdf_ext, magic, strlen(magic)) != 0) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
+			   "bdf variant magic does not match.\n");
+		return;
+	}
+
+	for (i = 0; i < strlen(bdf_ext); i++) {
+		if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) {
+			ath10k_dbg(ar, ATH10K_DBG_BOOT,
+				   "bdf variant name contains non ascii chars.\n");
+			return;
+		}
+	}
+
+	/* Copy extension name without magic suffix */
+	if (strscpy(ar->id.bdf_ext, bdf_ext + strlen(magic),
+		    sizeof(ar->id.bdf_ext)) < 0) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
+			   "bdf variant string is longer than the buffer can accommodate (variant: %s)\n",
+			    bdf_ext);
+		return;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
+		   "found and validated bdf variant smbios_type 0x%x bdf %s\n",
+		   ATH10K_SMBIOS_BDF_EXT_TYPE, bdf_ext);
+}
+
+static int ath10k_core_check_smbios(struct ath10k *ar)
+{
+	ar->id.bdf_ext[0] = '\0';
+	dmi_walk(ath10k_core_check_bdfext, ar);
+
+	if (ar->id.bdf_ext[0] == '\0')
+		return -ENODATA;
+
+	return 0;
+}
+
 static int ath10k_download_and_run_otp(struct ath10k *ar)
 {
 	u32 result, address = ar->hw_params.patch_load_addr;
@@ -865,6 +945,23 @@
 		case ATH10K_BD_IE_BOARD:
 			ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,
 							    boardname);
+			if (ret == -ENOENT && ar->id.bdf_ext[0] != '\0') {
+				/* try default bdf if variant was not found */
+				char *s, *v = ",variant=";
+				char boardname2[100];
+
+				strlcpy(boardname2, boardname,
+					sizeof(boardname2));
+
+				s = strstr(boardname2, v);
+				if (s)
+					*s = '\0';  /* strip ",variant=%s" */
+
+				ret = ath10k_core_parse_bd_ie_board(ar, data,
+								    ie_len,
+								    boardname2);
+			}
+
 			if (ret == -ENOENT)
 				/* no match found, continue */
 				break;
@@ -902,6 +999,9 @@
 static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
 					 size_t name_len)
 {
+	/* strlen(',variant=') + strlen(ar->id.bdf_ext) */
+	char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 };
+
 	if (ar->id.bmi_ids_valid) {
 		scnprintf(name, name_len,
 			  "bus=%s,bmi-chip-id=%d,bmi-board-id=%d",
@@ -911,12 +1011,15 @@
 		goto out;
 	}
 
+	if (ar->id.bdf_ext[0] != '\0')
+		scnprintf(variant, sizeof(variant), ",variant=%s",
+			  ar->id.bdf_ext);
+
 	scnprintf(name, name_len,
-		  "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x",
+		  "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s",
 		  ath10k_bus_str(ar->hif.bus),
 		  ar->id.vendor, ar->id.device,
-		  ar->id.subsystem_vendor, ar->id.subsystem_device);
-
+		  ar->id.subsystem_vendor, ar->id.subsystem_device, variant);
 out:
 	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name);
 
@@ -1607,6 +1710,12 @@
 		goto err_wmi_detach;
 	}
 
+	/* If firmware indicates Full Rx Reorder support it must be used in a
+	 * slightly different manner. Let HTT code know.
+	 */
+	ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
+						ar->wmi.svc_map));
+
 	status = ath10k_htt_rx_alloc(&ar->htt);
 	if (status) {
 		ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
@@ -1669,18 +1778,16 @@
 		goto err_hif_stop;
 	}
 
-	/* If firmware indicates Full Rx Reorder support it must be used in a
-	 * slightly different manner. Let HTT code know.
-	 */
-	ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
-						ar->wmi.svc_map));
-
 	status = ath10k_htt_rx_ring_refill(ar);
 	if (status) {
 		ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);
 		goto err_hif_stop;
 	}
 
+	ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
+
+	INIT_LIST_HEAD(&ar->arvifs);
+
 	/* we don't care about HTT in UTF mode */
 	if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
 		status = ath10k_htt_setup(&ar->htt);
@@ -1694,10 +1801,6 @@
 	if (status)
 		goto err_hif_stop;
 
-	ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
-
-	INIT_LIST_HEAD(&ar->arvifs);
-
 	return 0;
 
 err_hif_stop:
@@ -1794,9 +1897,13 @@
 	if (ret && ret != -EOPNOTSUPP) {
 		ath10k_err(ar, "failed to get board id from otp for qca99x0: %d\n",
 			   ret);
-		return ret;
+		goto err_free_firmware_files;
 	}
 
+	ret = ath10k_core_check_smbios(ar);
+	if (ret)
+		ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not set.\n");
+
 	ret = ath10k_core_fetch_board_file(ar);
 	if (ret) {
 		ath10k_err(ar, "failed to fetch board file: %d\n", ret);
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/core.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/core.h
@@ -65,6 +65,27 @@
 #define ATH10K_KEEPALIVE_MAX_IDLE 3895
 #define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900
 
+/* NAPI poll budget */
+#define ATH10K_NAPI_BUDGET      64
+#define ATH10K_NAPI_QUOTA_LIMIT 60
+
+/* SMBIOS type containing Board Data File Name Extension */
+#define ATH10K_SMBIOS_BDF_EXT_TYPE 0xF8
+
+/* SMBIOS type structure length (excluding strings-set) */
+#define ATH10K_SMBIOS_BDF_EXT_LENGTH 0x9
+
+/* Offset pointing to Board Data File Name Extension */
+#define ATH10K_SMBIOS_BDF_EXT_OFFSET 0x8
+
+/* Board Data File Name Extension string length.
+ * String format: BDF_<Customer ID>_<Extension>\0
+ */
+#define ATH10K_SMBIOS_BDF_EXT_STR_LENGTH 0x20
+
+/* The magic used by QCA spec */
+#define ATH10K_SMBIOS_BDF_EXT_MAGIC "BDF_"
+
 struct ath10k;
 
 enum ath10k_bus {
@@ -304,6 +325,14 @@
 
 	/* protected by ar->data_lock */
 	struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
+	union htt_rx_pn_t tids_last_pn[ATH10K_TXRX_NUM_EXT_TIDS];
+	bool tids_last_pn_valid[ATH10K_TXRX_NUM_EXT_TIDS];
+	union htt_rx_pn_t frag_tids_last_pn[ATH10K_TXRX_NUM_EXT_TIDS];
+	u32 frag_tids_seq[ATH10K_TXRX_NUM_EXT_TIDS];
+	struct {
+		enum htt_security_types sec_type;
+		int pn_len;
+	} rx_pn[ATH10K_HTT_TXRX_PEER_SECURITY_MAX];
 };
 
 struct ath10k_sta {
@@ -670,6 +699,10 @@
 			size_t board_size;
 			size_t board_ext_size;
 		} fw;
+
+		/* Number of bytes used for alignment in rx_hdr_status */
+		int decap_align_bytes;
+
 	} hw_params;
 
 	const struct firmware *board;
@@ -701,6 +734,8 @@
 		bool bmi_ids_valid;
 		u8 bmi_board_id;
 		u8 bmi_chip_id;
+
+		char bdf_ext[ATH10K_SMBIOS_BDF_EXT_STR_LENGTH];
 	} id;
 
 	int fw_api;
@@ -751,6 +786,7 @@
 
 	struct completion install_key_done;
 
+	int last_wmi_vdev_start_status;
 	struct completion vdev_setup_done;
 
 	struct workqueue_struct *workqueue;
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/debug.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/debug.c
@@ -1892,6 +1892,15 @@
 					   size_t count, loff_t *ppos)
 {
 	struct ath10k *ar = file->private_data;
+	struct ath10k_vif *arvif;
+
+	/* Just check for for the first vif alone, as all the vifs will be
+	 * sharing the same channel and if the channel is disabled, all the
+	 * vifs will share the same 'is_started' state.
+	 */
+	arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);
+	if (!arvif->is_started)
+		return -EINVAL;
 
 	ieee80211_radar_detected(ar->hw);
 
@@ -1986,7 +1995,12 @@
 		goto out;
 	}
 
-	if (filter && (filter != ar->debug.pktlog_filter)) {
+	if (filter == ar->debug.pktlog_filter) {
+		ret = count;
+		goto out;
+	}
+
+	if (filter) {
 		ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
 		if (ret) {
 			ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/htt.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/htt.h
@@ -636,6 +636,20 @@
 	struct htt_rx_indication_mpdu_range mpdu_ranges[0];
 } __packed;
 
+struct htt_hl_rx_desc {
+	__le32 info;
+	__le32 pn_31_0;
+	union {
+		struct {
+			__le16 pn_47_32;
+			__le16 pn_63_48;
+		} pn16;
+		__le32 pn_63_32;
+	} u0;
+	__le32 pn_95_64;
+	__le32 pn_127_96;
+} __packed;
+
 static inline struct htt_rx_indication_mpdu_range *
 		htt_rx_ind_get_mpdu_ranges(struct htt_rx_indication *rx_ind)
 {
@@ -681,6 +695,21 @@
 	__le16 peer_id;
 } __packed;
 
+enum htt_txrx_sec_cast_type {
+	HTT_TXRX_SEC_MCAST = 0,
+	HTT_TXRX_SEC_UCAST
+};
+
+enum htt_rx_pn_check_type {
+	HTT_RX_NON_PN_CHECK = 0,
+	HTT_RX_PN_CHECK
+};
+
+enum htt_rx_tkip_demic_type {
+	HTT_RX_NON_TKIP_MIC = 0,
+	HTT_RX_TKIP_MIC
+};
+
 enum htt_security_types {
 	HTT_SECURITY_NONE,
 	HTT_SECURITY_WEP128,
@@ -694,6 +723,10 @@
 	HTT_NUM_SECURITY_TYPES /* keep this last! */
 };
 
+#define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2
+#define ATH10K_TXRX_NUM_EXT_TIDS 19
+#define ATH10K_TXRX_NON_QOS_TID 16
+
 enum htt_security_flags {
 #define HTT_SECURITY_TYPE_MASK 0x7F
 #define HTT_SECURITY_TYPE_LSB  0
@@ -804,6 +837,11 @@
 	u8 fw_msdu_rx_desc[0];
 } __packed;
 
+#define ATH10K_IEEE80211_EXTIV               BIT(5)
+#define ATH10K_IEEE80211_TKIP_MICLEN         8   /* trailing MIC */
+
+#define HTT_RX_FRAG_IND_INFO0_HEADER_LEN     16
+
 #define HTT_RX_FRAG_IND_INFO0_EXT_TID_MASK     0x1F
 #define HTT_RX_FRAG_IND_INFO0_EXT_TID_LSB      0
 #define HTT_RX_FRAG_IND_INFO0_FLUSH_VALID_MASK 0x20
@@ -1541,6 +1579,9 @@
 	u8 msdu_payload[0];
 };
 
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK       0x00010000
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB        16
+
 #define HTT_RX_DESC_ALIGN 8
 
 #define HTT_MAC_ADDR_LEN 6
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -99,6 +99,14 @@
 	BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2);
 
 	idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr);
+
+	if (idx < 0 || idx >= htt->rx_ring.size) {
+		ath10k_err(htt->ar, "rx ring index is not valid, firmware malfunctioning?\n");
+		idx &= htt->rx_ring.size_mask;
+		ret = -ENOMEM;
+		goto fail;
+	}
+
 	while (num > 0) {
 		skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN);
 		if (!skb) {
@@ -212,11 +220,12 @@
 	spin_lock_bh(&htt->rx_ring.lock);
 	ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level -
 					      htt->rx_ring.fill_cnt));
-	spin_unlock_bh(&htt->rx_ring.lock);
 
 	if (ret)
 		ath10k_htt_rx_ring_free(htt);
 
+	spin_unlock_bh(&htt->rx_ring.lock);
+
 	return ret;
 }
 
@@ -230,7 +239,9 @@
 	skb_queue_purge(&htt->rx_compl_q);
 	skb_queue_purge(&htt->rx_in_ord_compl_q);
 
+	spin_lock_bh(&htt->rx_ring.lock);
 	ath10k_htt_rx_ring_free(htt);
+	spin_unlock_bh(&htt->rx_ring.lock);
 
 	dma_free_coherent(htt->ar->dev,
 			  (htt->rx_ring.size *
@@ -654,6 +665,7 @@
 	u8 preamble = 0;
 	u8 group_id;
 	u32 info1, info2, info3;
+	u32 stbc, nsts_su;
 
 	info1 = __le32_to_cpu(rxd->ppdu_start.info1);
 	info2 = __le32_to_cpu(rxd->ppdu_start.info2);
@@ -697,11 +709,16 @@
 		   TODO check this */
 		bw = info2 & 3;
 		sgi = info3 & 1;
+		stbc = (info2 >> 3) & 1;
 		group_id = (info2 >> 4) & 0x3F;
 
 		if (GROUP_ID_IS_SU_MIMO(group_id)) {
 			mcs = (info3 >> 4) & 0x0F;
-			nss = ((info2 >> 10) & 0x07) + 1;
+			nsts_su = ((info2 >> 10) & 0x07);
+			if (stbc)
+				nss = (nsts_su >> 2) + 1;
+			else
+				nss = (nsts_su + 1);
 		} else {
 			/* Hardware doesn't decode VHT-SIG-B into Rx descriptor
 			 * so it's impossible to decode MCS. Also since
@@ -875,6 +892,19 @@
 				   struct ieee80211_rx_status *status,
 				   struct htt_rx_desc *rxd)
 {
+	int i;
+
+	for (i = 0; i < IEEE80211_MAX_CHAINS ; i++) {
+		status->chains &= ~BIT(i);
+
+		if (rxd->ppdu_start.rssi_chains[i].pri20_mhz != 0x80) {
+			status->chain_signal[i] = ATH10K_DEFAULT_NOISE_FLOOR +
+				rxd->ppdu_start.rssi_chains[i].pri20_mhz;
+
+			status->chains |= BIT(i);
+		}
+	}
+
 	/* FIXME: Get real NF */
 	status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
 			 rxd->ppdu_start.rssi_comb;
@@ -979,7 +1009,7 @@
 	*status = *rx_status;
 
 	ath10k_dbg(ar, ATH10K_DBG_DATA,
-		   "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
+		   "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%llx fcs-err %i mic-err %i amsdu-more %i\n",
 		   skb,
 		   skb->len,
 		   ieee80211_get_SA(hdr),
@@ -1076,7 +1106,21 @@
 	hdr = (void *)msdu->data;
 
 	/* Tail */
-	skb_trim(msdu, msdu->len - ath10k_htt_rx_crypto_tail_len(ar, enctype));
+	if (status->flag & RX_FLAG_IV_STRIPPED) {
+		skb_trim(msdu, msdu->len -
+			 ath10k_htt_rx_crypto_tail_len(ar, enctype));
+	} else {
+		/* MIC */
+		if ((status->flag & RX_FLAG_MIC_STRIPPED) &&
+		    enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
+			skb_trim(msdu, msdu->len - 8);
+
+		/* ICV */
+		if (status->flag & RX_FLAG_ICV_STRIPPED &&
+		    enctype != HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
+			skb_trim(msdu, msdu->len -
+				 ath10k_htt_rx_crypto_tail_len(ar, enctype));
+	}
 
 	/* MMIC */
 	if (!ieee80211_has_morefrags(hdr->frame_control) &&
@@ -1095,12 +1139,14 @@
 static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
 					  struct sk_buff *msdu,
 					  struct ieee80211_rx_status *status,
-					  const u8 first_hdr[64])
+					  const u8 first_hdr[64],
+					  enum htt_rx_mpdu_encrypt_type enctype)
 {
 	struct ieee80211_hdr *hdr;
 	size_t hdr_len;
 	u8 da[ETH_ALEN];
 	u8 sa[ETH_ALEN];
+	int bytes_aligned = ar->hw_params.decap_align_bytes;
 
 	/* Delivered decapped frame:
 	 * [nwifi 802.11 header] <-- replaced with 802.11 hdr
@@ -1123,6 +1169,14 @@
 	/* push original 802.11 header */
 	hdr = (struct ieee80211_hdr *)first_hdr;
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+
+	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+		memcpy(skb_push(msdu,
+				ath10k_htt_rx_crypto_param_len(ar, enctype)),
+		       (void *)hdr + round_up(hdr_len, bytes_aligned),
+			ath10k_htt_rx_crypto_param_len(ar, enctype));
+	}
+
 	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
 
 	/* original 802.11 header has a different DA and in
@@ -1142,6 +1196,7 @@
 	size_t hdr_len, crypto_len;
 	void *rfc1042;
 	bool is_first, is_last, is_amsdu;
+	int bytes_aligned = ar->hw_params.decap_align_bytes;
 
 	rxd = (void *)msdu->data - sizeof(*rxd);
 	hdr = (void *)rxd->rx_hdr_status;
@@ -1158,8 +1213,8 @@
 		hdr_len = ieee80211_hdrlen(hdr->frame_control);
 		crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
 
-		rfc1042 += round_up(hdr_len, 4) +
-			   round_up(crypto_len, 4);
+		rfc1042 += round_up(hdr_len, bytes_aligned) +
+			   round_up(crypto_len, bytes_aligned);
 	}
 
 	if (is_amsdu)
@@ -1180,6 +1235,7 @@
 	void *rfc1042;
 	u8 da[ETH_ALEN];
 	u8 sa[ETH_ALEN];
+	int bytes_aligned = ar->hw_params.decap_align_bytes;
 
 	/* Delivered decapped frame:
 	 * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc
@@ -1203,6 +1259,14 @@
 	/* push original 802.11 header */
 	hdr = (struct ieee80211_hdr *)first_hdr;
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+
+	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+		memcpy(skb_push(msdu,
+				ath10k_htt_rx_crypto_param_len(ar, enctype)),
+		       (void *)hdr + round_up(hdr_len, bytes_aligned),
+			ath10k_htt_rx_crypto_param_len(ar, enctype));
+	}
+
 	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
 
 	/* original 802.11 header has a different DA and in
@@ -1216,10 +1280,12 @@
 static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar,
 					 struct sk_buff *msdu,
 					 struct ieee80211_rx_status *status,
-					 const u8 first_hdr[64])
+					 const u8 first_hdr[64],
+					 enum htt_rx_mpdu_encrypt_type enctype)
 {
 	struct ieee80211_hdr *hdr;
 	size_t hdr_len;
+	int bytes_aligned = ar->hw_params.decap_align_bytes;
 
 	/* Delivered decapped frame:
 	 * [amsdu header] <-- replaced with 802.11 hdr
@@ -1231,6 +1297,14 @@
 
 	hdr = (struct ieee80211_hdr *)first_hdr;
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+
+	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+		memcpy(skb_push(msdu,
+				ath10k_htt_rx_crypto_param_len(ar, enctype)),
+		       (void *)hdr + round_up(hdr_len, bytes_aligned),
+			ath10k_htt_rx_crypto_param_len(ar, enctype));
+	}
+
 	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
 }
 
@@ -1265,13 +1339,15 @@
 					    is_decrypted);
 		break;
 	case RX_MSDU_DECAP_NATIVE_WIFI:
-		ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr);
+		ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr,
+					      enctype);
 		break;
 	case RX_MSDU_DECAP_ETHERNET2_DIX:
 		ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype);
 		break;
 	case RX_MSDU_DECAP_8023_SNAP_LLC:
-		ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr);
+		ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr,
+					     enctype);
 		break;
 	}
 }
@@ -1312,25 +1388,107 @@
 	msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu);
 }
 
+static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb,
+				  u16 offset,
+				  enum htt_rx_mpdu_encrypt_type enctype)
+{
+	struct ieee80211_hdr *hdr;
+	u64 pn = 0;
+	u8 *ehdr;
+
+	hdr = (struct ieee80211_hdr *)(skb->data + offset);
+	ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control);
+
+	if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) {
+		pn = ehdr[0];
+		pn |= (u64)ehdr[1] << 8;
+		pn |= (u64)ehdr[4] << 16;
+		pn |= (u64)ehdr[5] << 24;
+		pn |= (u64)ehdr[6] << 32;
+		pn |= (u64)ehdr[7] << 40;
+	}
+	return pn;
+}
+
+static bool ath10k_htt_rx_h_frag_multicast_check(struct ath10k *ar,
+						 struct sk_buff *skb,
+						 u16 offset)
+{
+	struct ieee80211_hdr *hdr;
+
+	hdr = (struct ieee80211_hdr *)(skb->data + offset);
+	return !is_multicast_ether_addr(hdr->addr1);
+}
+
+static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar,
+					  struct sk_buff *skb,
+					  u16 peer_id,
+					  u16 offset,
+					  enum htt_rx_mpdu_encrypt_type enctype)
+{
+	struct ath10k_peer *peer;
+	union htt_rx_pn_t *last_pn, new_pn = {0};
+	struct ieee80211_hdr *hdr;
+	bool more_frags;
+	u8 tid, frag_number;
+	u32 seq;
+
+	peer = ath10k_peer_find_by_id(ar, peer_id);
+	if (!peer) {
+		ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer for frag pn check\n");
+		return false;
+	}
+
+	hdr = (struct ieee80211_hdr *)(skb->data + offset);
+	if (ieee80211_is_data_qos(hdr->frame_control))
+		tid = ieee80211_get_tid(hdr);
+	else
+		tid = ATH10K_TXRX_NON_QOS_TID;
+
+	last_pn = &peer->frag_tids_last_pn[tid];
+	new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype);
+	more_frags = ieee80211_has_morefrags(hdr->frame_control);
+	frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
+	seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+
+	if (frag_number == 0) {
+		last_pn->pn48 = new_pn.pn48;
+		peer->frag_tids_seq[tid] = seq;
+	} else {
+		if (seq != peer->frag_tids_seq[tid])
+			return false;
+
+		if (new_pn.pn48 != last_pn->pn48 + 1)
+			return false;
+
+		last_pn->pn48 = new_pn.pn48;
+	}
+
+	return true;
+}
+
 static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 				 struct sk_buff_head *amsdu,
-				 struct ieee80211_rx_status *status)
+				 struct ieee80211_rx_status *status,
+				 bool fill_crypt_header,
+				 u16 peer_id,
+				 bool frag)
 {
 	struct sk_buff *first;
 	struct sk_buff *last;
-	struct sk_buff *msdu;
+	struct sk_buff *msdu, *temp;
 	struct htt_rx_desc *rxd;
 	struct ieee80211_hdr *hdr;
 	enum htt_rx_mpdu_encrypt_type enctype;
 	u8 first_hdr[64];
 	u8 *qos;
-	size_t hdr_len;
 	bool has_fcs_err;
 	bool has_crypto_err;
 	bool has_tkip_err;
 	bool has_peer_idx_invalid;
 	bool is_decrypted;
 	u32 attention;
+	bool frag_pn_check = true, multicast_check = true;
 
 	if (skb_queue_empty(amsdu))
 		return;
@@ -1345,15 +1503,17 @@
 	 * decapped header. It'll be used for undecapping of each MSDU.
 	 */
 	hdr = (void *)rxd->rx_hdr_status;
-	hdr_len = ieee80211_hdrlen(hdr->frame_control);
-	memcpy(first_hdr, hdr, hdr_len);
+	memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
 
 	/* Each A-MSDU subframe will use the original header as the base and be
 	 * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
 	 */
 	hdr = (void *)first_hdr;
-	qos = ieee80211_get_qos_ctl(hdr);
-	qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		qos = ieee80211_get_qos_ctl(hdr);
+		qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+	}
 
 	/* Some attention flags are valid only in the last MSDU. */
 	last = skb_peek_tail(amsdu);
@@ -1387,13 +1547,49 @@
 	if (has_tkip_err)
 		status->flag |= RX_FLAG_MMIC_ERROR;
 
-	if (is_decrypted)
+	if (is_decrypted) {
 		status->flag |= RX_FLAG_DECRYPTED |
-				RX_FLAG_IV_STRIPPED |
 				RX_FLAG_MMIC_STRIPPED;
 
+		if (fill_crypt_header)
+			status->flag |= RX_FLAG_MIC_STRIPPED |
+					RX_FLAG_ICV_STRIPPED;
+		else
+			status->flag |= RX_FLAG_IV_STRIPPED;
+	}
+
 	skb_queue_walk(amsdu, msdu) {
+		if (frag && !fill_crypt_header && is_decrypted &&
+		    enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
+			frag_pn_check = ath10k_htt_rx_h_frag_pn_check(ar,
+								      msdu,
+								      peer_id,
+								      0,
+								      enctype);
+
+		if (frag)
+			multicast_check = ath10k_htt_rx_h_frag_multicast_check(ar,
+									       msdu,
+									       0);
+
+		if (!frag_pn_check || !multicast_check) {
+			/* Discard the fragment with invalid PN or multicast DA
+			 */
+			temp = msdu->prev;
+			__skb_unlink(msdu, amsdu);
+			dev_kfree_skb_any(msdu);
+			msdu = temp;
+			frag_pn_check = true;
+			multicast_check = true;
+			continue;
+		}
+
 		ath10k_htt_rx_h_csum_offload(msdu);
+
+		if (frag && !fill_crypt_header &&
+		    enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
+			status->flag &= ~RX_FLAG_MMIC_STRIPPED;
+
 		ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
 					is_decrypted);
 
@@ -1404,8 +1600,16 @@
 		if (!is_decrypted)
 			continue;
 
+		if (fill_crypt_header)
+			continue;
+
 		hdr = (void *)msdu->data;
 		hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+
+		if (frag && !fill_crypt_header &&
+		    enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
+			status->flag &= ~RX_FLAG_IV_STRIPPED &
+					~RX_FLAG_MMIC_STRIPPED;
 	}
 }
 
@@ -1414,6 +1618,9 @@
 				    struct ieee80211_rx_status *status)
 {
 	struct sk_buff *msdu;
+	struct sk_buff *first_subframe;
+
+	first_subframe = skb_peek(amsdu);
 
 	while ((msdu = __skb_dequeue(amsdu))) {
 		/* Setup per-MSDU flags */
@@ -1422,6 +1629,13 @@
 		else
 			status->flag |= RX_FLAG_AMSDU_MORE;
 
+		if (msdu == first_subframe) {
+			first_subframe = NULL;
+			status->flag &= ~RX_FLAG_ALLOW_SAME_PN;
+		} else {
+			status->flag |= RX_FLAG_ALLOW_SAME_PN;
+		}
+
 		ath10k_process_rx(ar, status, msdu);
 	}
 }
@@ -1607,7 +1821,7 @@
 		ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
 		ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
 		ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
-		ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
+		ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, 0, false);
 		ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
 	}
 
@@ -1653,7 +1867,7 @@
 
 	ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
 	ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
-	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
+	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, 0, false);
 	ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
 
 	if (fw_desc_len > 0) {
@@ -1952,7 +2166,7 @@
 			 */
 			ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
 			ath10k_htt_rx_h_filter(ar, &amsdu, status);
-			ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
+			ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, peer_id, frag);
 			ath10k_htt_rx_h_deliver(ar, &amsdu, status);
 			break;
 		case -EAGAIN:
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/hw.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/hw.c
@@ -128,7 +128,7 @@
 };
 
 const struct ath10k_hw_values qca99x0_values = {
-	.rtc_state_val_on		= 5,
+	.rtc_state_val_on		= 7,
 	.ce_count			= 12,
 	.msi_assign_ce_max		= 12,
 	.num_target_ce_config_wlan	= 10,
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/hw.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/hw.h
@@ -429,7 +429,7 @@
 
 #define TARGET_10_4_TX_DBG_LOG_SIZE		1024
 #define TARGET_10_4_NUM_WDS_ENTRIES		32
-#define TARGET_10_4_DMA_BURST_SIZE		0
+#define TARGET_10_4_DMA_BURST_SIZE		1
 #define TARGET_10_4_MAC_AGGR_DELIM		0
 #define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1
 #define TARGET_10_4_VOW_CONFIG			0
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/mac.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/mac.c
@@ -850,7 +850,7 @@
 	if (time_left == 0)
 		return -ETIMEDOUT;
 
-	return 0;
+	return ar->last_wmi_vdev_start_status;
 }
 
 static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
@@ -1127,6 +1127,36 @@
 		return ath10k_monitor_stop(ar);
 }
 
+static bool ath10k_mac_can_set_cts_prot(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	if (!arvif->is_started) {
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "defer cts setup, vdev is not ready yet\n");
+		return false;
+	}
+
+	return true;
+}
+
+static int ath10k_mac_set_cts_prot(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+	u32 vdev_param;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	vdev_param = ar->wmi.vdev_param->protection_mode;
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_protection %d\n",
+		   arvif->vdev_id, arvif->use_cts_prot);
+
+	return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+					 arvif->use_cts_prot ? 1 : 0);
+}
+
 static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
 {
 	struct ath10k *ar = arvif->ar;
@@ -1472,6 +1502,10 @@
 	if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
 		return 0;
 
+	 /* For mesh, probe response and beacon share the same template */
+	if (ieee80211_vif_is_mesh(vif))
+		return 0;
+
 	prb = ieee80211_proberesp_get(hw, vif);
 	if (!prb) {
 		ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
@@ -2871,6 +2905,13 @@
 			passive = channel->flags & IEEE80211_CHAN_NO_IR;
 			ch->passive = passive;
 
+			/* the firmware is ignoring the "radar" flag of the
+			 * channel and is scanning actively using Probe Requests
+			 * on "Radar detection"/DFS channels which are not
+			 * marked as "available"
+			 */
+			ch->passive |= ch->chan_radar;
+
 			ch->freq = channel->center_freq;
 			ch->band_center_freq1 = channel->center_freq;
 			ch->min_power = 0;
@@ -3295,23 +3336,16 @@
 static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue;
-	int ret = 0;
-
-	spin_lock_bh(&ar->data_lock);
 
-	if (skb_queue_len(q) == ATH10K_MAX_NUM_MGMT_PENDING) {
+	if (skb_queue_len_lockless(q) >= ATH10K_MAX_NUM_MGMT_PENDING) {
 		ath10k_warn(ar, "wmi mgmt tx queue is full\n");
-		ret = -ENOSPC;
-		goto unlock;
+		return -ENOSPC;
 	}
 
-	__skb_queue_tail(q, skb);
+	skb_queue_tail(q, skb);
 	ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
 
-unlock:
-	spin_unlock_bh(&ar->data_lock);
-
-	return ret;
+	return 0;
 }
 
 static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
@@ -3637,6 +3671,8 @@
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	__le16 fc = hdr->frame_control;
 
+	skb_orphan(skb);
+
 	/* We should disable CCK RATE due to P2P */
 	if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
 		ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
@@ -4180,7 +4216,8 @@
 	lockdep_assert_held(&ar->conf_mutex);
 
 	list_for_each_entry(arvif, &ar->arvifs, list) {
-		WARN_ON(arvif->txpower < 0);
+		if (arvif->txpower <= 0)
+			continue;
 
 		if (txpower == -1)
 			txpower = arvif->txpower;
@@ -4188,8 +4225,8 @@
 			txpower = min(txpower, arvif->txpower);
 	}
 
-	if (WARN_ON(txpower == -1))
-		return -EINVAL;
+	if (txpower == -1)
+		return 0;
 
 	ret = ath10k_mac_txpower_setup(ar, txpower);
 	if (ret) {
@@ -4432,7 +4469,9 @@
 	}
 
 	ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
+	spin_lock_bh(&ar->data_lock);
 	list_add(&arvif->list, &ar->arvifs);
+	spin_unlock_bh(&ar->data_lock);
 
 	/* It makes no sense to have firmware do keepalives. mac80211 already
 	 * takes care of this with idle connection polling.
@@ -4456,7 +4495,10 @@
 		goto err_vdev_delete;
 	}
 
-	if (ar->cfg_tx_chainmask) {
+	/* Configuring number of spatial stream for monitor interface is causing
+	 * target assert in qca9888 and qca6174.
+	 */
+	if (ar->cfg_tx_chainmask && (vif->type != NL80211_IFTYPE_MONITOR)) {
 		u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
 
 		vdev_param = ar->wmi.vdev_param->nss;
@@ -4562,7 +4604,9 @@
 err_vdev_delete:
 	ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
 	ar->free_vdev_map |= 1LL << arvif->vdev_id;
+	spin_lock_bh(&ar->data_lock);
 	list_del(&arvif->list);
+	spin_unlock_bh(&ar->data_lock);
 
 err:
 	if (arvif->beacon_buf) {
@@ -4606,7 +4650,9 @@
 			    arvif->vdev_id, ret);
 
 	ar->free_vdev_map |= 1LL << arvif->vdev_id;
+	spin_lock_bh(&ar->data_lock);
 	list_del(&arvif->list);
+	spin_unlock_bh(&ar->data_lock);
 
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
 	    arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
@@ -4784,20 +4830,18 @@
 
 	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
 		arvif->use_cts_prot = info->use_cts_prot;
-		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
-			   arvif->vdev_id, info->use_cts_prot);
 
 		ret = ath10k_recalc_rtscts_prot(arvif);
 		if (ret)
 			ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
 				    arvif->vdev_id, ret);
 
-		vdev_param = ar->wmi.vdev_param->protection_mode;
-		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
-						info->use_cts_prot ? 1 : 0);
-		if (ret)
-			ath10k_warn(ar, "failed to set protection mode %d on vdev %i: %d\n",
-				    info->use_cts_prot, arvif->vdev_id, ret);
+		if (ath10k_mac_can_set_cts_prot(arvif)) {
+			ret = ath10k_mac_set_cts_prot(arvif);
+			if (ret)
+				ath10k_warn(ar, "failed to set cts protection for vdev %d: %d\n",
+					    arvif->vdev_id, ret);
+		}
 	}
 
 	if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -5253,9 +5297,8 @@
 				    sta->addr, smps, err);
 	}
 
-	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED ||
-	    changed & IEEE80211_RC_NSS_CHANGED) {
-		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
+	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
 			   sta->addr);
 
 		err = ath10k_station_assoc(ar, arvif->vif, sta, true);
@@ -5465,6 +5508,16 @@
 			   "mac vdev %d peer delete %pM (sta gone)\n",
 			   arvif->vdev_id, sta->addr);
 
+		if (sta->tdls) {
+			ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id,
+							  sta,
+							  WMI_TDLS_PEER_STATE_TEARDOWN);
+			if (ret)
+				ath10k_warn(ar, "failed to update tdls peer state for %pM state %d: %i\n",
+					    sta->addr,
+					    WMI_TDLS_PEER_STATE_TEARDOWN, ret);
+		}
+
 		ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
 		if (ret)
 			ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
@@ -6270,10 +6323,20 @@
 {
 	struct ath10k *ar = hw->priv;
 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+	struct ath10k_vif *arvif = (void *)vif->drv_priv;
+	struct ath10k_peer *peer;
 	u32 bw, smps;
 
 	spin_lock_bh(&ar->data_lock);
 
+	peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr);
+	if (!peer) {
+		spin_unlock_bh(&ar->data_lock);
+		ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n",
+			    sta->addr, arvif->vdev_id);
+		return;
+	}
+
 	ath10k_dbg(ar, ATH10K_DBG_MAC,
 		   "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
 		   sta->addr, changed, sta->bandwidth, sta->rx_nss,
@@ -6348,12 +6411,13 @@
 
 static int ath10k_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, bool amsdu)
+			       struct ieee80211_ampdu_params *params)
 {
 	struct ath10k *ar = hw->priv;
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
 
 	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
 		   arvif->vdev_id, sta->addr, tid, action);
@@ -6394,7 +6458,7 @@
 	lockdep_assert_held(&ar->data_lock);
 
 	WARN_ON(ctx && vifs);
-	WARN_ON(vifs && n_vifs != 1);
+	WARN_ON(vifs && !n_vifs);
 
 	/* FIXME: Sort of an optimization and a workaround. Peers and vifs are
 	 * on a linked list now. Doing a lookup peer -> vif -> chanctx for each
@@ -6416,7 +6480,13 @@
 			def = &vifs[0].new_ctx->def;
 
 		ar->rx_channel = def->chan;
-	} else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) {
+	} else if ((ctx && ath10k_mac_num_chanctxs(ar) == 0) ||
+		   (ctx && (ar->state == ATH10K_STATE_RESTARTED))) {
+		/* During driver restart due to firmware assert, since mac80211
+		 * already has valid channel context for given radio, channel
+		 * context iteration return num_chanctx > 0. So fix rx_channel
+		 * when restart is in progress.
+		 */
 		ar->rx_channel = ctx->def.chan;
 	} else {
 		ar->rx_channel = NULL;
@@ -6702,6 +6772,13 @@
 		arvif->is_up = true;
 	}
 
+	if (ath10k_mac_can_set_cts_prot(arvif)) {
+		ret = ath10k_mac_set_cts_prot(arvif);
+		if (ret)
+			ath10k_warn(ar, "failed to set cts protection for vdev %d: %d\n",
+				    arvif->vdev_id, ret);
+	}
+
 	mutex_unlock(&ar->conf_mutex);
 	return 0;
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/pci.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/pci.c
@@ -1886,7 +1886,7 @@
 		}
 		break;
 	case QCA9377_1_0_DEVICE_ID:
-		return 2;
+		return 9;
 	}
 
 	ath10k_warn(ar, "unknown number of banks, assuming 1\n");
@@ -3050,7 +3050,7 @@
 		goto err_core_destroy;
 	}
 
-	if (QCA_REV_6174(ar))
+	if (QCA_REV_6174(ar) || QCA_REV_9377(ar))
 		ath10k_pci_override_ce_config(ar);
 
 	ret = ath10k_pci_alloc_pipes(ar);
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/spectral.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/spectral.c
@@ -338,7 +338,7 @@
 		} else {
 			res = -EINVAL;
 		}
-	} else if (strncmp("background", buf, 9) == 0) {
+	} else if (strncmp("background", buf, 10) == 0) {
 		res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
 	} else if (strncmp("manual", buf, 6) == 0) {
 		res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/trace.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/trace.h
@@ -152,10 +152,9 @@
 );
 
 TRACE_EVENT(ath10k_wmi_cmd,
-	TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len,
-		 int ret),
+	TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
 
-	TP_ARGS(ar, id, buf, buf_len, ret),
+	TP_ARGS(ar, id, buf, buf_len),
 
 	TP_STRUCT__entry(
 		__string(device, dev_name(ar->dev))
@@ -163,7 +162,6 @@
 		__field(unsigned int, id)
 		__field(size_t, buf_len)
 		__dynamic_array(u8, buf, buf_len)
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
@@ -171,17 +169,15 @@
 		__assign_str(driver, dev_driver_string(ar->dev));
 		__entry->id = id;
 		__entry->buf_len = buf_len;
-		__entry->ret = ret;
 		memcpy(__get_dynamic_array(buf), buf, buf_len);
 	),
 
 	TP_printk(
-		"%s %s id %d len %zu ret %d",
+		"%s %s id %d len %zu",
 		__get_str(driver),
 		__get_str(device),
 		__entry->id,
-		__entry->buf_len,
-		__entry->ret
+		__entry->buf_len
 	)
 );
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/txrx.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/txrx.c
@@ -96,6 +96,8 @@
 
 	info = IEEE80211_SKB_CB(msdu);
 	memset(&info->status, 0, sizeof(info->status));
+	info->status.rates[0].idx = -1;
+
 	trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
 
 	if (tx_done->discard) {
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -639,6 +639,9 @@
 	struct sk_buff *skb;
 	u32 cmd_id;
 
+	if (!ar->wmi.ops->gen_vdev_spectral_conf)
+		return -EOPNOTSUPP;
+
 	skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
@@ -654,6 +657,9 @@
 	struct sk_buff *skb;
 	u32 cmd_id;
 
+	if (!ar->wmi.ops->gen_vdev_spectral_enable)
+		return -EOPNOTSUPP;
+
 	skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger,
 						    enable);
 	if (IS_ERR(skb))
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1105,8 +1105,10 @@
 		struct ath10k_fw_stats_pdev *dst;
 
 		src = data;
-		if (data_len < sizeof(*src))
+		if (data_len < sizeof(*src)) {
+			kfree(tb);
 			return -EPROTO;
+		}
 
 		data += sizeof(*src);
 		data_len -= sizeof(*src);
@@ -1126,8 +1128,10 @@
 		struct ath10k_fw_stats_vdev *dst;
 
 		src = data;
-		if (data_len < sizeof(*src))
+		if (data_len < sizeof(*src)) {
+			kfree(tb);
 			return -EPROTO;
+		}
 
 		data += sizeof(*src);
 		data_len -= sizeof(*src);
@@ -1145,8 +1149,10 @@
 		struct ath10k_fw_stats_peer *dst;
 
 		src = data;
-		if (data_len < sizeof(*src))
+		if (data_len < sizeof(*src)) {
+			kfree(tb);
 			return -EPROTO;
+		}
 
 		data += sizeof(*src);
 		data_len -= sizeof(*src);
@@ -1418,6 +1424,11 @@
 	cfg->keep_alive_pattern_size = __cpu_to_le32(0);
 	cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1);
 	cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1);
+	cfg->wmi_send_separate = __cpu_to_le32(0);
+	cfg->num_ocb_vdevs = __cpu_to_le32(0);
+	cfg->num_ocb_channels = __cpu_to_le32(0);
+	cfg->num_ocb_schedules = __cpu_to_le32(0);
+	cfg->host_capab = __cpu_to_le32(0);
 
 	ath10k_wmi_put_host_mem_chunks(ar, chunks);
 
@@ -1448,10 +1459,10 @@
 	bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr);
 	ie_len = roundup(arg->ie_len, 4);
 	len = (sizeof(*tlv) + sizeof(*cmd)) +
-	      (arg->n_channels ? sizeof(*tlv) + chan_len : 0) +
-	      (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) +
-	      (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) +
-	      (arg->ie_len ? sizeof(*tlv) + ie_len : 0);
+	      sizeof(*tlv) + chan_len +
+	      sizeof(*tlv) + ssid_len +
+	      sizeof(*tlv) + bssid_len +
+	      sizeof(*tlv) + ie_len;
 
 	skb = ath10k_wmi_alloc_skb(ar, len);
 	if (!skb)
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -1209,6 +1209,11 @@
 	__le32 keep_alive_pattern_size;
 	__le32 max_tdls_concurrent_sleep_sta;
 	__le32 max_tdls_concurrent_buffer_sta;
+	__le32 wmi_send_separate;
+	__le32 num_ocb_vdevs;
+	__le32 num_ocb_channels;
+	__le32 num_ocb_schedules;
+	__le32 host_capab;
 } __packed;
 
 struct wmi_tlv_init_cmd {
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/wmi.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1573,6 +1573,7 @@
 	ch->max_power = arg->max_power;
 	ch->reg_power = arg->max_reg_power;
 	ch->antenna_max = arg->max_antenna_gain;
+	ch->max_tx_power = arg->max_power;
 
 	/* mode & flags share storage */
 	ch->mode = arg->mode;
@@ -1642,8 +1643,8 @@
 	cmd_hdr->cmd_id = __cpu_to_le32(cmd);
 
 	memset(skb_cb, 0, sizeof(*skb_cb));
+	trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len);
 	ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
-	trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret);
 
 	if (ret)
 		goto err_pull;
@@ -1749,6 +1750,12 @@
 	if (ret)
 		dev_kfree_skb_any(skb);
 
+	if (ret == -EAGAIN) {
+		ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n",
+			    cmd_id);
+		queue_work(ar->workqueue, &ar->restart_work);
+	}
+
 	return ret;
 }
 
@@ -2288,7 +2295,8 @@
 		   status->freq, status->band, status->signal,
 		   status->rate_idx);
 
-	ieee80211_rx(ar->hw, skb);
+	ieee80211_rx_ni(ar->hw, skb);
+
 	return 0;
 }
 
@@ -2938,18 +2946,31 @@
 {
 	struct wmi_vdev_start_ev_arg arg = {};
 	int ret;
+	u32 status;
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
 
+	ar->last_wmi_vdev_start_status = 0;
+
 	ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret);
-		return;
+		ar->last_wmi_vdev_start_status = ret;
+		goto out;
 	}
 
-	if (WARN_ON(__le32_to_cpu(arg.status)))
-		return;
+	status = __le32_to_cpu(arg.status);
+	if (WARN_ON_ONCE(status)) {
+		ath10k_warn(ar, "vdev-start-response reports status error: %d (%s)\n",
+			    status, (status == WMI_VDEV_START_CHAN_INVALID) ?
+			    "chan-invalid" : "unknown");
+		/* Setup is done one way or another though, so we should still
+		 * do the completion, so don't return here.
+		 */
+		ar->last_wmi_vdev_start_status = -EINVAL;
+	}
 
+out:
 	complete(&ar->vdev_setup_done);
 }
 
@@ -4059,7 +4080,7 @@
 							    rate_code[i],
 							    type);
 			snprintf(buff, sizeof(buff), "%8d ", tpc[j]);
-			strncat(tpc_value, buff, strlen(buff));
+			strlcat(tpc_value, buff, sizeof(tpc_value));
 		}
 		tpc_stats->tpc_table[type].pream_idx[i] = pream_idx;
 		tpc_stats->tpc_table[type].rate_code[i] = rate_code[i];
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath10k/wmi.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath10k/wmi.h
@@ -1732,6 +1732,7 @@
 		__le32 reginfo1;
 		struct {
 			u8 antenna_max;
+			u8 max_tx_power;
 		} __packed;
 	} __packed;
 } __packed;
@@ -4826,7 +4827,8 @@
 #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
 
 #define WMI_TXBF_STS_CAP_OFFSET_LSB	4
-#define WMI_TXBF_STS_CAP_OFFSET_MASK	0xf0
+#define WMI_TXBF_STS_CAP_OFFSET_MASK	0x70
+#define WMI_TXBF_CONF_IMPLICIT_BF       BIT(7)
 #define WMI_BF_SOUND_DIM_OFFSET_LSB	8
 #define WMI_BF_SOUND_DIM_OFFSET_MASK	0xf00
 
@@ -5968,11 +5970,17 @@
 	__le32 rx_frame_count;
 };
 
+/* From 10.4 firmware, not sure all have the same values. */
+enum wmi_vdev_start_status {
+	WMI_VDEV_START_OK = 0,
+	WMI_VDEV_START_CHAN_INVALID,
+};
+
 struct wmi_vdev_start_ev_arg {
 	__le32 vdev_id;
 	__le32 req_id;
 	__le32 resp_type; /* %WMI_VDEV_RESP_ */
-	__le32 status;
+	__le32 status; /* See wmi_vdev_start_status enum above */
 };
 
 struct wmi_peer_kick_ev_arg {
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath5k/debug.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath5k/debug.c
@@ -939,7 +939,10 @@
 	}
 
 	for (i = 0; i < eesize; ++i) {
-		AR5K_EEPROM_READ(i, val);
+		if (!ath5k_hw_nvram_read(ah, i, &val)) {
+			ret = -EIO;
+			goto freebuf;
+		}
 		buf[i] = val;
 	}
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath5k/led.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath5k/led.c
@@ -77,7 +77,7 @@
 	/* HP Compaq CQ60-206US (ddreggors@jumptv.com) */
 	{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) },
 	/* HP Compaq C700 (nitrousnrg@gmail.com) */
-	{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) },
+	{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 0) },
 	/* LiteOn AR5BXB63 (magooz@salug.it) */
 	{ ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) },
 	/* IBM-specific AR5212 (all others) */
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -502,8 +502,7 @@
 			break;
 		return -EOPNOTSUPP;
 	default:
-		WARN_ON(1);
-		return -EINVAL;
+		return -EOPNOTSUPP;
 	}
 
 	mutex_lock(&ah->lock);
@@ -523,7 +522,7 @@
 		}
 		break;
 	case DISABLE_KEY:
-		ath_key_delete(common, key);
+		ath_key_delete(common, key->hw_key_idx);
 		break;
 	default:
 		ret = -EINVAL;
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -932,7 +932,7 @@
 		else
 			ssid_list[i].flag = ANY_SSID_FLAG;
 
-		if (n_match_ssid == 0)
+		if (ar->wiphy->max_match_sets != 0 && n_match_ssid == 0)
 			ssid_list[i].flag |= MATCH_SSID_FLAG;
 	}
 
@@ -1083,7 +1083,7 @@
 	if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
 		for (i = 0; i < vif->scan_req->n_ssids; i++) {
 			ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
-						  i + 1, DISABLE_SSID_FLAG,
+						  i, DISABLE_SSID_FLAG,
 						  0, NULL);
 		}
 	}
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath6kl/main.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath6kl/main.c
@@ -430,6 +430,9 @@
 
 	ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid);
 
+	if (aid < 1 || aid > AP_MAX_NUM_STA)
+		return;
+
 	if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) {
 		struct ieee80211_mgmt *mgmt =
 			(struct ieee80211_mgmt *) assoc_info;
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath6kl/usb.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath6kl/usb.c
@@ -132,6 +132,10 @@
 	struct ath6kl_urb_context *urb_context = NULL;
 	unsigned long flags;
 
+	/* bail if this pipe is not initialized */
+	if (!pipe->ar_usb)
+		return NULL;
+
 	spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
 	if (!list_empty(&pipe->urb_list_head)) {
 		urb_context =
@@ -150,6 +154,10 @@
 {
 	unsigned long flags;
 
+	/* bail if this pipe is not initialized */
+	if (!pipe->ar_usb)
+		return;
+
 	spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
 	pipe->urb_cnt++;
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath6kl/wmi.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -1178,6 +1178,10 @@
 		return -EINVAL;
 
 	ev = (struct wmi_pstream_timeout_event *) datap;
+	if (ev->traffic_class >= WMM_NUM_AC) {
+		ath6kl_err("invalid traffic class: %d\n", ev->traffic_class);
+		return -EINVAL;
+	}
 
 	/*
 	 * When the pstream (fat pipe == AC) timesout, it means there were
@@ -1519,6 +1523,10 @@
 		return -EINVAL;
 
 	reply = (struct wmi_cac_event *) datap;
+	if (reply->ac >= WMM_NUM_AC) {
+		ath6kl_err("invalid AC: %d\n", reply->ac);
+		return -EINVAL;
+	}
 
 	if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
 	    (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
@@ -2631,11 +2639,16 @@
 	u16 active_tsids = 0;
 	int ret;
 
-	if (traffic_class > 3) {
+	if (traffic_class >= WMM_NUM_AC) {
 		ath6kl_err("invalid traffic class: %d\n", traffic_class);
 		return -EINVAL;
 	}
 
+	if (tsid >= 16) {
+		ath6kl_err("invalid tsid: %d\n", tsid);
+		return -EINVAL;
+	}
+
 	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -274,6 +274,9 @@
 	};
 	static const int inc[4] = { 0, 100, 0, 0 };
 
+	memset(&mask_m, 0, sizeof(int8_t) * 123);
+	memset(&mask_p, 0, sizeof(int8_t) * 123);
+
 	cur_bin = -6000;
 	upper = bin + 100;
 	lower = bin - 100;
@@ -424,14 +427,9 @@
 	int tmp, new;
 	int i;
 
-	int8_t mask_m[123];
-	int8_t mask_p[123];
 	int cur_bb_spur;
 	bool is2GHz = IS_CHAN_2GHZ(chan);
 
-	memset(&mask_m, 0, sizeof(int8_t) * 123);
-	memset(&mask_p, 0, sizeof(int8_t) * 123);
-
 	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
 		cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
 		if (AR_NO_SPUR == cur_bb_spur)
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -178,14 +178,9 @@
 	int i;
 	struct chan_centers centers;
 
-	int8_t mask_m[123];
-	int8_t mask_p[123];
 	int cur_bb_spur;
 	bool is2GHz = IS_CHAN_2GHZ(chan);
 
-	memset(&mask_m, 0, sizeof(int8_t) * 123);
-	memset(&mask_p, 0, sizeof(int8_t) * 123);
-
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 	freq = centers.synth_center;
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -4114,7 +4114,7 @@
 
 static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah)
 {
-	u32 data, ko, kg;
+	u32 data = 0, ko, kg;
 
 	if (!AR_SREV_9462_20_OR_LATER(ah))
 		return;
@@ -4176,7 +4176,7 @@
 	if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))
 		ar9003_hw_internal_regulator_apply(ah);
 	ar9003_hw_apply_tuning_caps(ah);
-	ar9003_hw_apply_minccapwr_thresh(ah, chan);
+	ar9003_hw_apply_minccapwr_thresh(ah, is2ghz);
 	ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz);
 	ar9003_hw_thermometer_apply(ah);
 	ar9003_hw_thermo_cal_apply(ah);
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -73,13 +73,13 @@
 #define AR9300_OTP_BASE \
 		((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000)
 #define AR9300_OTP_STATUS \
-		((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18)
+		((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x31018 : 0x15f18)
 #define AR9300_OTP_STATUS_TYPE		0x7
 #define AR9300_OTP_STATUS_VALID		0x4
 #define AR9300_OTP_STATUS_ACCESS_BUSY	0x2
 #define AR9300_OTP_STATUS_SM_BUSY	0x1
 #define AR9300_OTP_READ_DATA \
-		((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c)
+		((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3101c : 0x15f1c)
 
 enum targetPowerHTRates {
 	HT_TARGET_RATE_0_8_16,
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1815,8 +1815,6 @@
 static void ar9003_hw_tx99_start(struct ath_hw *ah, u32 qnum)
 {
 	REG_SET_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR);
-	REG_SET_BIT(ah, 0x9864, 0x7f000);
-	REG_SET_BIT(ah, 0x9924, 0x7f00fe);
 	REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
 	REG_WRITE(ah, AR_CR, AR_CR_RXD);
 	REG_WRITE(ah, AR_DLCL_IFS(qnum), 0);
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/ath9k.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -178,7 +178,8 @@
 	s8 txq;
 	u8 keyix;
 	u8 rtscts_rate;
-	u8 retries : 7;
+	u8 retries : 6;
+	u8 dyn_smps : 1;
 	u8 baw_tracked : 1;
 	u8 tx_power;
 	enum ath9k_key_type keytype:2;
@@ -959,6 +960,7 @@
 	struct survey_info *cur_survey;
 	struct survey_info survey[ATH9K_NUM_CHANNELS];
 
+	spinlock_t intr_lock;
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct bcon_tasklet;
 	struct ath_hw *sc_ah;
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -411,7 +411,7 @@
 
 		ath_dbg(common, SPECTRAL_SCAN,
 			"Calculated new upper max 0x%X at %i\n",
-			tmp_mag, i);
+			tmp_mag, fft_sample_40.upper_max_index);
 	} else
 	for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
 		if (fft_sample_40.data[i] == (upper_mag >> max_exp))
@@ -528,6 +528,9 @@
 	if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
 		return 0;
 
+	if (!spec_priv->rfs_chan_spec_scan)
+		return 1;
+
 	/* Output buffers are full, no need to process anything
 	 * since there is no space to put the result anyway
 	 */
@@ -1072,7 +1075,7 @@
 
 void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
 {
-	if (config_enabled(CONFIG_ATH9K_DEBUGFS)) {
+	if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) {
 		relay_close(spec_priv->rfs_chan_spec_scan);
 		spec_priv->rfs_chan_spec_scan = NULL;
 	}
@@ -1086,6 +1089,9 @@
 					    debugfs_phy,
 					    1024, 256, &rfs_spec_scan_cb,
 					    NULL);
+	if (!spec_priv->rfs_chan_spec_scan)
+		return;
+
 	debugfs_create_file("spectral_scan_ctl",
 			    S_IRUSR | S_IWUSR,
 			    debugfs_phy, spec_priv,
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/dynack.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/dynack.c
@@ -285,9 +285,9 @@
 
 	an->ackto = ackto;
 
-	spin_lock(&da->qlock);
+	spin_lock_bh(&da->qlock);
 	list_add_tail(&an->list, &da->nodes);
-	spin_unlock(&da->qlock);
+	spin_unlock_bh(&da->qlock);
 }
 EXPORT_SYMBOL(ath_dynack_node_init);
 
@@ -301,9 +301,9 @@
 {
 	struct ath_dynack *da = &ah->dynack;
 
-	spin_lock(&da->qlock);
+	spin_lock_bh(&da->qlock);
 	list_del(&an->list);
-	spin_unlock(&da->qlock);
+	spin_unlock_bh(&da->qlock);
 }
 EXPORT_SYMBOL(ath_dynack_node_deinit);
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/eeprom.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -403,10 +403,9 @@
 
 	if (match) {
 		if (AR_SREV_9287(ah)) {
-			/* FIXME: array overrun? */
 			for (i = 0; i < numXpdGains; i++) {
 				minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
-				maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
+				maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1];
 				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 						data_9287[idxL].pwrPdg[i],
 						data_9287[idxL].vpdPdg[i],
@@ -416,7 +415,7 @@
 		} else if (eeprom_4k) {
 			for (i = 0; i < numXpdGains; i++) {
 				minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
-				maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
+				maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1];
 				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 						data_4k[idxL].pwrPdg[i],
 						data_4k[idxL].vpdPdg[i],
@@ -426,7 +425,7 @@
 		} else {
 			for (i = 0; i < numXpdGains; i++) {
 				minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
-				maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
+				maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1];
 				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 						data_def[idxL].pwrPdg[i],
 						data_def[idxL].vpdPdg[i],
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -37,6 +37,7 @@
 	{ USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */
 	{ USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
 	{ USB_DEVICE(0x0471, 0x209e) }, /* Philips (or NXP) PTA01 */
+	{ USB_DEVICE(0x1eda, 0x2315) }, /* AirTies */
 
 	{ USB_DEVICE(0x0cf3, 0x7015),
 	  .driver_info = AR9287_USB },  /* Atheros */
@@ -444,10 +445,19 @@
 	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 
 	/* The pending URBs have to be canceled. */
+	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 	list_for_each_entry_safe(tx_buf, tx_buf_tmp,
 				 &hif_dev->tx.tx_pending, list) {
+		usb_get_urb(tx_buf->urb);
+		spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 		usb_kill_urb(tx_buf->urb);
+		list_del(&tx_buf->list);
+		usb_free_urb(tx_buf->urb);
+		kfree(tx_buf->buf);
+		kfree(tx_buf);
+		spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 	}
+	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 
 	usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
 }
@@ -607,6 +617,11 @@
 			hif_dev->remain_skb = nskb;
 			spin_unlock(&hif_dev->rx_lock);
 		} else {
+			if (pool_index == MAX_PKT_NUM_IN_TRANSFER) {
+				dev_err(&hif_dev->udev->dev,
+					"ath9k_htc: over RX MAX_PKT_NUM\n");
+				goto err;
+			}
 			nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
 			if (!nskb) {
 				dev_err(&hif_dev->udev->dev,
@@ -633,9 +648,9 @@
 
 static void ath9k_hif_usb_rx_cb(struct urb *urb)
 {
-	struct sk_buff *skb = (struct sk_buff *) urb->context;
-	struct hif_device_usb *hif_dev =
-		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+	struct rx_buf *rx_buf = (struct rx_buf *)urb->context;
+	struct hif_device_usb *hif_dev = rx_buf->hif_dev;
+	struct sk_buff *skb = rx_buf->skb;
 	int ret;
 
 	if (!skb)
@@ -675,14 +690,15 @@
 	return;
 free:
 	kfree_skb(skb);
+	kfree(rx_buf);
 }
 
 static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 {
-	struct sk_buff *skb = (struct sk_buff *) urb->context;
+	struct rx_buf *rx_buf = (struct rx_buf *)urb->context;
+	struct hif_device_usb *hif_dev = rx_buf->hif_dev;
+	struct sk_buff *skb = rx_buf->skb;
 	struct sk_buff *nskb;
-	struct hif_device_usb *hif_dev =
-		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
 	int ret;
 
 	if (!skb)
@@ -722,11 +738,13 @@
 			return;
 		}
 
+		rx_buf->skb = nskb;
+
 		usb_fill_int_urb(urb, hif_dev->udev,
 				 usb_rcvintpipe(hif_dev->udev,
 						 USB_REG_IN_PIPE),
 				 nskb->data, MAX_REG_IN_BUF_SIZE,
-				 ath9k_hif_usb_reg_in_cb, nskb, 1);
+				 ath9k_hif_usb_reg_in_cb, rx_buf, 1);
 	}
 
 resubmit:
@@ -740,6 +758,7 @@
 	return;
 free:
 	kfree_skb(skb);
+	kfree(rx_buf);
 	urb->context = NULL;
 }
 
@@ -748,27 +767,37 @@
 	struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
 	unsigned long flags;
 
+	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 	list_for_each_entry_safe(tx_buf, tx_buf_tmp,
 				 &hif_dev->tx.tx_buf, list) {
+		usb_get_urb(tx_buf->urb);
+		spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 		usb_kill_urb(tx_buf->urb);
 		list_del(&tx_buf->list);
 		usb_free_urb(tx_buf->urb);
 		kfree(tx_buf->buf);
 		kfree(tx_buf);
+		spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 	}
+	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 
 	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 	hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
 	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 
+	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 	list_for_each_entry_safe(tx_buf, tx_buf_tmp,
 				 &hif_dev->tx.tx_pending, list) {
+		usb_get_urb(tx_buf->urb);
+		spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 		usb_kill_urb(tx_buf->urb);
 		list_del(&tx_buf->list);
 		usb_free_urb(tx_buf->urb);
 		kfree(tx_buf->buf);
 		kfree(tx_buf);
+		spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 	}
+	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 
 	usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
 }
@@ -785,7 +814,7 @@
 	init_usb_anchor(&hif_dev->mgmt_submitted);
 
 	for (i = 0; i < MAX_TX_URB_NUM; i++) {
-		tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
+		tx_buf = kzalloc(sizeof(*tx_buf), GFP_KERNEL);
 		if (!tx_buf)
 			goto err;
 
@@ -822,8 +851,9 @@
 
 static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
 {
-	struct urb *urb = NULL;
+	struct rx_buf *rx_buf = NULL;
 	struct sk_buff *skb = NULL;
+	struct urb *urb = NULL;
 	int i, ret;
 
 	init_usb_anchor(&hif_dev->rx_submitted);
@@ -831,6 +861,12 @@
 
 	for (i = 0; i < MAX_RX_URB_NUM; i++) {
 
+		rx_buf = kzalloc(sizeof(*rx_buf), GFP_KERNEL);
+		if (!rx_buf) {
+			ret = -ENOMEM;
+			goto err_rxb;
+		}
+
 		/* Allocate URB */
 		urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (urb == NULL) {
@@ -845,11 +881,14 @@
 			goto err_skb;
 		}
 
+		rx_buf->hif_dev = hif_dev;
+		rx_buf->skb = skb;
+
 		usb_fill_bulk_urb(urb, hif_dev->udev,
 				  usb_rcvbulkpipe(hif_dev->udev,
 						  USB_WLAN_RX_PIPE),
 				  skb->data, MAX_RX_BUF_SIZE,
-				  ath9k_hif_usb_rx_cb, skb);
+				  ath9k_hif_usb_rx_cb, rx_buf);
 
 		/* Anchor URB */
 		usb_anchor_urb(urb, &hif_dev->rx_submitted);
@@ -875,6 +914,8 @@
 err_skb:
 	usb_free_urb(urb);
 err_urb:
+	kfree(rx_buf);
+err_rxb:
 	ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
 	return ret;
 }
@@ -886,14 +927,21 @@
 
 static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
 {
-	struct urb *urb = NULL;
+	struct rx_buf *rx_buf = NULL;
 	struct sk_buff *skb = NULL;
+	struct urb *urb = NULL;
 	int i, ret;
 
 	init_usb_anchor(&hif_dev->reg_in_submitted);
 
 	for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
 
+		rx_buf = kzalloc(sizeof(*rx_buf), GFP_KERNEL);
+		if (!rx_buf) {
+			ret = -ENOMEM;
+			goto err_rxb;
+		}
+
 		/* Allocate URB */
 		urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (urb == NULL) {
@@ -908,11 +956,14 @@
 			goto err_skb;
 		}
 
+		rx_buf->hif_dev = hif_dev;
+		rx_buf->skb = skb;
+
 		usb_fill_int_urb(urb, hif_dev->udev,
 				  usb_rcvintpipe(hif_dev->udev,
 						  USB_REG_IN_PIPE),
 				  skb->data, MAX_REG_IN_BUF_SIZE,
-				  ath9k_hif_usb_reg_in_cb, skb, 1);
+				  ath9k_hif_usb_reg_in_cb, rx_buf, 1);
 
 		/* Anchor URB */
 		usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
@@ -938,6 +989,8 @@
 err_skb:
 	usb_free_urb(urb);
 err_urb:
+	kfree(rx_buf);
+err_rxb:
 	ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
 	return ret;
 }
@@ -968,7 +1021,7 @@
 	return -ENOMEM;
 }
 
-static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
+void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
 {
 	usb_kill_anchored_urbs(&hif_dev->regout_submitted);
 	ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
@@ -1210,12 +1263,15 @@
 static int send_eject_command(struct usb_interface *interface)
 {
 	struct usb_device *udev = interface_to_usbdev(interface);
-	struct usb_host_interface *iface_desc = &interface->altsetting[0];
+	struct usb_host_interface *iface_desc = interface->cur_altsetting;
 	struct usb_endpoint_descriptor *endpoint;
 	unsigned char *cmd;
 	u8 bulk_out_ep;
 	int r;
 
+	if (iface_desc->desc.bNumEndpoints < 2)
+		return -ENODEV;
+
 	/* Find bulk out endpoint */
 	for (r = 1; r >= 0; r--) {
 		endpoint = &iface_desc->endpoint[r].desc;
@@ -1332,8 +1388,9 @@
 
 	if (hif_dev->flags & HIF_USB_READY) {
 		ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
-		ath9k_htc_hw_free(hif_dev->htc_handle);
 		ath9k_hif_usb_dev_deinit(hif_dev);
+		ath9k_destoy_wmi(hif_dev->htc_handle->drv_priv);
+		ath9k_htc_hw_free(hif_dev->htc_handle);
 	}
 
 	usb_set_intfdata(interface, NULL);
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -84,6 +84,11 @@
 	struct list_head list;
 };
 
+struct rx_buf {
+	struct sk_buff *skb;
+	struct hif_device_usb *hif_dev;
+};
+
 #define HIF_USB_TX_STOP  BIT(0)
 #define HIF_USB_TX_FLUSH BIT(1)
 
@@ -131,5 +136,6 @@
 
 int ath9k_hif_usb_init(void);
 void ath9k_hif_usb_exit(void);
+void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev);
 
 #endif /* HTC_USB_H */
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/htc.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/htc.h
@@ -325,11 +325,11 @@
 }
 
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
-
-#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
-#define TX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c += a)
-#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.skbrx_stats.c++)
-#define RX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.skbrx_stats.c += a)
+#define __STAT_SAFE(expr) (hif_dev->htc_handle->drv_priv ? (expr) : 0)
+#define TX_STAT_INC(c) __STAT_SAFE(hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
+#define TX_STAT_ADD(c, a) __STAT_SAFE(hif_dev->htc_handle->drv_priv->debug.tx_stats.c += a)
+#define RX_STAT_INC(c) __STAT_SAFE(hif_dev->htc_handle->drv_priv->debug.skbrx_stats.c++)
+#define RX_STAT_ADD(c, a) __STAT_SAFE(hif_dev->htc_handle->drv_priv->debug.skbrx_stats.c += a)
 #define CAB_STAT_INC   priv->debug.tx_stats.cab_queued++
 
 #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -931,8 +931,9 @@
 int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
 			   u16 devid, char *product, u32 drv_info)
 {
-	struct ieee80211_hw *hw;
+	struct hif_device_usb *hif_dev;
 	struct ath9k_htc_priv *priv;
+	struct ieee80211_hw *hw;
 	int ret;
 
 	hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops);
@@ -943,7 +944,6 @@
 	priv->hw = hw;
 	priv->htc = htc_handle;
 	priv->dev = dev;
-	htc_handle->drv_priv = priv;
 	SET_IEEE80211_DEV(hw, priv->dev);
 
 	ret = ath9k_htc_wait_for_target(priv);
@@ -964,10 +964,15 @@
 	if (ret)
 		goto err_init;
 
+	htc_handle->drv_priv = priv;
+
 	return 0;
 
 err_init:
-	ath9k_deinit_wmi(priv);
+	ath9k_stop_wmi(priv);
+	hif_dev = (struct hif_device_usb *)htc_handle->hif_dev;
+	ath9k_hif_usb_dealloc_urbs(hif_dev);
+	ath9k_destoy_wmi(priv);
 err_free:
 	ieee80211_free_hw(hw);
 	return ret;
@@ -982,7 +987,7 @@
 			htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED;
 
 		ath9k_deinit_device(htc_handle->drv_priv);
-		ath9k_deinit_wmi(htc_handle->drv_priv);
+		ath9k_stop_wmi(htc_handle->drv_priv);
 		ieee80211_free_hw(htc_handle->drv_priv->hw);
 	}
 }
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1463,7 +1463,7 @@
 		}
 		break;
 	case DISABLE_KEY:
-		ath_key_delete(common, key);
+		ath_key_delete(common, key->hw_key_idx);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1657,13 +1657,14 @@
 
 static int ath9k_htc_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, bool amsdu)
+				  struct ieee80211_ampdu_params *params)
 {
 	struct ath9k_htc_priv *priv = hw->priv;
 	struct ath9k_htc_sta *ista;
 	int ret = 0;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
 
 	mutex_lock(&priv->mutex);
 	ath9k_htc_ps_wakeup(priv);
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -647,9 +647,10 @@
 	struct ath9k_htc_tx_event *tx_pend;
 	int i;
 
-	for (i = 0; i < txs->cnt; i++) {
-		WARN_ON(txs->cnt > HTC_MAX_TX_STATUS);
+	if (WARN_ON_ONCE(txs->cnt > HTC_MAX_TX_STATUS))
+		return;
 
+	for (i = 0; i < txs->cnt; i++) {
 		__txs = &txs->txstatus[i];
 
 		skb = ath9k_htc_tx_get_packet(priv, __txs);
@@ -972,6 +973,8 @@
 	struct ath_htc_rx_status *rxstatus;
 	struct ath_rx_status rx_stats;
 	bool decrypt_error = false;
+	u16 rs_datalen;
+	bool is_phyerr;
 
 	if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
 		ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
@@ -981,11 +984,24 @@
 
 	rxstatus = (struct ath_htc_rx_status *)skb->data;
 
-	if (be16_to_cpu(rxstatus->rs_datalen) -
-	    (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
+	rs_datalen = be16_to_cpu(rxstatus->rs_datalen);
+	if (unlikely(rs_datalen -
+	    (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0)) {
 		ath_err(common,
 			"Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n",
-			rxstatus->rs_datalen, skb->len);
+			rs_datalen, skb->len);
+		goto rx_next;
+	}
+
+	is_phyerr = rxstatus->rs_status & ATH9K_RXERR_PHY;
+	/*
+	 * Discard zero-length packets and packets smaller than an ACK
+	 * which are not PHY_ERROR (short radar pulses have a length of 3)
+	 */
+	if (unlikely(!rs_datalen || (rs_datalen < 10 && !is_phyerr))) {
+		ath_dbg(common, ANY,
+			"Short RX data len, dropping (dlen: %d)\n",
+			rs_datalen);
 		goto rx_next;
 	}
 
@@ -1010,7 +1026,7 @@
 	 * Process PHY errors and return so that the packet
 	 * can be dropped.
 	 */
-	if (rx_stats.rs_status & ATH9K_RXERR_PHY) {
+	if (unlikely(is_phyerr)) {
 		/* TODO: Not using DFS processing now. */
 		if (ath_cmn_process_fft(&priv->spec_priv, hdr,
 				    &rx_stats, rx_status->mactime)) {
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -114,6 +114,9 @@
 
 	if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
 		epid = svc_rspmsg->endpoint_id;
+		if (epid < 0 || epid >= ENDPOINT_MAX)
+			return;
+
 		service_id = be16_to_cpu(svc_rspmsg->service_id);
 		max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
 		endpoint = &target->endpoint[epid];
@@ -172,6 +175,7 @@
 	time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 	if (!time_left) {
 		dev_err(target->dev, "HTC credit config timeout\n");
+		kfree_skb(skb);
 		return -ETIMEDOUT;
 	}
 
@@ -208,6 +212,7 @@
 	time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 	if (!time_left) {
 		dev_err(target->dev, "HTC start timeout\n");
+		kfree_skb(skb);
 		return -ETIMEDOUT;
 	}
 
@@ -281,9 +286,13 @@
 	if (!time_left) {
 		dev_err(target->dev, "Service connection timeout for: %d\n",
 			service_connreq->service_id);
+		kfree_skb(skb);
 		return -ETIMEDOUT;
 	}
 
+	if (target->conn_rsp_epid < 0 || target->conn_rsp_epid >= ENDPOINT_MAX)
+		return -EINVAL;
+
 	*conn_rsp_epid = target->conn_rsp_epid;
 	return 0;
 err:
@@ -340,6 +349,8 @@
 
 	if (skb) {
 		htc_hdr = (struct htc_frame_hdr *) skb->data;
+		if (htc_hdr->endpoint_id >= ARRAY_SIZE(htc_handle->endpoint))
+			goto ret;
 		endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
 		skb_pull(skb, sizeof(struct htc_frame_hdr));
 
@@ -414,7 +425,7 @@
 		return;
 	}
 
-	if (epid >= ENDPOINT_MAX) {
+	if (epid < 0 || epid >= ENDPOINT_MAX) {
 		if (pipe_id != USB_REG_IN_PIPE)
 			dev_kfree_skb_any(skb);
 		else
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/hw.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/hw.c
@@ -250,8 +250,9 @@
 /* Chip Revisions */
 /******************/
 
-static void ath9k_hw_read_revisions(struct ath_hw *ah)
+static bool ath9k_hw_read_revisions(struct ath_hw *ah)
 {
+	u32 srev;
 	u32 val;
 
 	if (ah->get_mac_revision)
@@ -267,25 +268,33 @@
 			val = REG_READ(ah, AR_SREV);
 			ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
 		}
-		return;
+		return true;
 	case AR9300_DEVID_AR9340:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9340;
-		return;
+		return true;
 	case AR9300_DEVID_QCA955X:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9550;
-		return;
+		return true;
 	case AR9300_DEVID_AR953X:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9531;
-		return;
+		return true;
 	case AR9300_DEVID_QCA956X:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9561;
-		return;
+		return true;
 	}
 
-	val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
+	srev = REG_READ(ah, AR_SREV);
+
+	if (srev == -EIO) {
+		ath_err(ath9k_hw_common(ah),
+			"Failed to read SREV register");
+		return false;
+	}
+
+	val = srev & AR_SREV_ID;
 
 	if (val == 0xFF) {
-		val = REG_READ(ah, AR_SREV);
+		val = srev;
 		ah->hw_version.macVersion =
 			(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
 		ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
@@ -304,6 +313,8 @@
 		if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)
 			ah->is_pciexpress = true;
 	}
+
+	return true;
 }
 
 /************************************/
@@ -556,7 +567,10 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 	int r = 0;
 
-	ath9k_hw_read_revisions(ah);
+	if (!ath9k_hw_read_revisions(ah)) {
+		ath_err(common, "Could not read hardware revisions");
+		return -EOPNOTSUPP;
+	}
 
 	switch (ah->hw_version.macVersion) {
 	case AR_SREV_VERSION_5416_PCI:
@@ -1595,6 +1609,10 @@
 	int count = 50;
 	u32 reg, last_val;
 
+	/* Check if chip failed to wake up */
+	if (REG_READ(ah, AR_CFG) == 0xdeadbeef)
+		return false;
+
 	if (AR_SREV_9300(ah))
 		return !ath9k_hw_detect_mac_hang(ah);
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/hw.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/hw.h
@@ -814,6 +814,7 @@
 	struct ath9k_pacal_info pacal_info;
 	struct ar5416Stats stats;
 	struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
+	DECLARE_BITMAP(pending_del_keymap, ATH_KEYMAX);
 
 	enum ath9k_int imask;
 	u32 imrs2_reg;
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/init.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/init.c
@@ -49,6 +49,10 @@
 module_param_named(blink, ath9k_led_blink, int, 0444);
 MODULE_PARM_DESC(blink, "Enable LED blink on activity");
 
+static int ath9k_led_active_high = -1;
+module_param_named(led_active_high, ath9k_led_active_high, int, 0444);
+MODULE_PARM_DESC(led_active_high, "Invert LED polarity");
+
 static int ath9k_btcoex_enable;
 module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
 MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
@@ -600,6 +604,9 @@
 	if (ret)
 		return ret;
 
+	if (ath9k_led_active_high != -1)
+		ah->config.led_active_high = ath9k_led_active_high == 1;
+
 	/*
 	 * Enable WLAN/BT RX Antenna diversity only when:
 	 *
@@ -612,6 +619,7 @@
 		common->bt_ant_diversity = 1;
 
 	spin_lock_init(&common->cc_lock);
+	spin_lock_init(&sc->intr_lock);
 	spin_lock_init(&sc->sc_serial_rw);
 	spin_lock_init(&sc->sc_pm_lock);
 	spin_lock_init(&sc->chan_lock);
@@ -862,8 +870,8 @@
 			hw->wiphy->interface_modes |=
 					BIT(NL80211_IFTYPE_P2P_DEVICE);
 
-			hw->wiphy->iface_combinations = if_comb;
-			hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+		hw->wiphy->iface_combinations = if_comb;
+		hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
 	}
 
 	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/mac.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/mac.c
@@ -805,21 +805,12 @@
 }
 EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
 
-void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+static void __ath9k_hw_enable_interrupts(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	u32 sync_default = AR_INTR_SYNC_DEFAULT;
 	u32 async_mask;
 
-	if (!(ah->imask & ATH9K_INT_GLOBAL))
-		return;
-
-	if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
-		ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
-			atomic_read(&ah->intr_ref_cnt));
-		return;
-	}
-
 	if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
 	    AR_SREV_9561(ah))
 		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
@@ -841,6 +832,39 @@
 	ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
 		REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
 }
+
+void ath9k_hw_resume_interrupts(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!(ah->imask & ATH9K_INT_GLOBAL))
+		return;
+
+	if (atomic_read(&ah->intr_ref_cnt) != 0) {
+		ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
+			atomic_read(&ah->intr_ref_cnt));
+		return;
+	}
+
+	__ath9k_hw_enable_interrupts(ah);
+}
+EXPORT_SYMBOL(ath9k_hw_resume_interrupts);
+
+void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!(ah->imask & ATH9K_INT_GLOBAL))
+		return;
+
+	if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
+		ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
+			atomic_read(&ah->intr_ref_cnt));
+		return;
+	}
+
+	__ath9k_hw_enable_interrupts(ah);
+}
 EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
 
 void ath9k_hw_set_interrupts(struct ath_hw *ah)
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/mac.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/mac.h
@@ -748,6 +748,7 @@
 void ath9k_hw_enable_interrupts(struct ath_hw *ah);
 void ath9k_hw_disable_interrupts(struct ath_hw *ah);
 void ath9k_hw_kill_interrupts(struct ath_hw *ah);
+void ath9k_hw_resume_interrupts(struct ath_hw *ah);
 
 void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/main.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/main.c
@@ -373,21 +373,20 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 	enum ath_reset_type type;
 	unsigned long flags;
-	u32 status = sc->intrstatus;
+	u32 status;
 	u32 rxmask;
 
+	spin_lock_irqsave(&sc->intr_lock, flags);
+	status = sc->intrstatus;
+	sc->intrstatus = 0;
+	spin_unlock_irqrestore(&sc->intr_lock, flags);
+
 	ath9k_ps_wakeup(sc);
 	spin_lock(&sc->sc_pcu_lock);
 
 	if (status & ATH9K_INT_FATAL) {
 		type = RESET_TYPE_FATAL_INT;
 		ath9k_queue_reset(sc, type);
-
-		/*
-		 * Increment the ref. counter here so that
-		 * interrupts are enabled in the reset routine.
-		 */
-		atomic_inc(&ah->intr_ref_cnt);
 		ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
 		goto out;
 	}
@@ -403,11 +402,6 @@
 			type = RESET_TYPE_BB_WATCHDOG;
 			ath9k_queue_reset(sc, type);
 
-			/*
-			 * Increment the ref. counter here so that
-			 * interrupts are enabled in the reset routine.
-			 */
-			atomic_inc(&ah->intr_ref_cnt);
 			ath_dbg(common, RESET,
 				"BB_WATCHDOG: Skipping interrupts\n");
 			goto out;
@@ -420,7 +414,6 @@
 		if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) {
 			type = RESET_TYPE_TX_GTT;
 			ath9k_queue_reset(sc, type);
-			atomic_inc(&ah->intr_ref_cnt);
 			ath_dbg(common, RESET,
 				"GTT: Skipping interrupts\n");
 			goto out;
@@ -477,7 +470,7 @@
 	ath9k_btcoex_handle_interrupt(sc, status);
 
 	/* re-enable hardware interrupt */
-	ath9k_hw_enable_interrupts(ah);
+	ath9k_hw_resume_interrupts(ah);
 out:
 	spin_unlock(&sc->sc_pcu_lock);
 	ath9k_ps_restore(sc);
@@ -541,7 +534,9 @@
 		return IRQ_NONE;
 
 	/* Cache the status */
-	sc->intrstatus = status;
+	spin_lock(&sc->intr_lock);
+	sc->intrstatus |= status;
+	spin_unlock(&sc->intr_lock);
 
 	if (status & SCHED_INTR)
 		sched = true;
@@ -587,7 +582,7 @@
 
 	if (sched) {
 		/* turn off every interrupt */
-		ath9k_hw_disable_interrupts(ah);
+		ath9k_hw_kill_interrupts(ah);
 		tasklet_schedule(&sc->intr_tq);
 	}
 
@@ -819,12 +814,80 @@
 	ieee80211_free_txskb(hw, skb);
 }
 
+static bool ath9k_txq_list_has_key(struct list_head *txq_list, u32 keyix)
+{
+	struct ath_buf *bf;
+	struct ieee80211_tx_info *txinfo;
+	struct ath_frame_info *fi;
+
+	list_for_each_entry(bf, txq_list, list) {
+		if (bf->bf_state.stale || !bf->bf_mpdu)
+			continue;
+
+		txinfo = IEEE80211_SKB_CB(bf->bf_mpdu);
+		fi = (struct ath_frame_info *)&txinfo->rate_driver_data[0];
+		if (fi->keyix == keyix)
+			return true;
+	}
+
+	return false;
+}
+
+static bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	int i;
+	struct ath_txq *txq;
+	bool key_in_use = false;
+
+	for (i = 0; !key_in_use && i < ATH9K_NUM_TX_QUEUES; i++) {
+		if (!ATH_TXQ_SETUP(sc, i))
+			continue;
+		txq = &sc->tx.txq[i];
+		if (!txq->axq_depth)
+			continue;
+		if (!ath9k_hw_numtxpending(ah, txq->axq_qnum))
+			continue;
+
+		ath_txq_lock(sc, txq);
+		key_in_use = ath9k_txq_list_has_key(&txq->axq_q, keyix);
+		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+			int idx = txq->txq_tailidx;
+
+			while (!key_in_use &&
+			       !list_empty(&txq->txq_fifo[idx])) {
+				key_in_use = ath9k_txq_list_has_key(
+					&txq->txq_fifo[idx], keyix);
+				INCR(idx, ATH_TXFIFO_DEPTH);
+			}
+		}
+		ath_txq_unlock(sc, txq);
+	}
+
+	return key_in_use;
+}
+
+static void ath9k_pending_key_del(struct ath_softc *sc, u8 keyix)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!test_bit(keyix, ah->pending_del_keymap) ||
+	    ath9k_txq_has_key(sc, keyix))
+		return;
+
+	/* No more TXQ frames point to this key cache entry, so delete it. */
+	clear_bit(keyix, ah->pending_del_keymap);
+	ath_key_delete(common, keyix);
+}
+
 static void ath9k_stop(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 	bool prev_idle;
+	int i;
 
 	ath9k_deinit_channel_context(sc);
 
@@ -890,6 +953,14 @@
 
 	spin_unlock_bh(&sc->sc_pcu_lock);
 
+	for (i = 0; i < ATH_KEYMAX; i++)
+		ath9k_pending_key_del(sc, i);
+
+	/* Clear key cache entries explicitly to get rid of any potentially
+	 * remaining keys.
+	 */
+	ath9k_cmn_init_crypto(sc->sc_ah);
+
 	ath9k_ps_restore(sc);
 
 	sc->ps_idle = prev_idle;
@@ -1442,6 +1513,9 @@
 		ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef);
 	}
 
+	if (changed & IEEE80211_CONF_CHANGE_POWER)
+		ath9k_set_txpower(sc, NULL);
+
 	mutex_unlock(&sc->mutex);
 	ath9k_ps_restore(sc);
 
@@ -1518,12 +1592,11 @@
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_node *an = (struct ath_node *) sta->drv_priv;
-	struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
 
 	if (!an->ps_key)
 	    return;
 
-	ath_key_delete(common, &ps_key);
+	ath_key_delete(common, an->ps_key);
 	an->ps_key = 0;
 	an->key_idx[0] = 0;
 }
@@ -1550,13 +1623,13 @@
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	int ret = 0;
 
-	if (old_state == IEEE80211_STA_AUTH &&
-	    new_state == IEEE80211_STA_ASSOC) {
+	if (old_state == IEEE80211_STA_NOTEXIST &&
+	    new_state == IEEE80211_STA_NONE) {
 		ret = ath9k_sta_add(hw, vif, sta);
 		ath_dbg(common, CONFIG,
 			"Add station: %pM\n", sta->addr);
-	} else if (old_state == IEEE80211_STA_ASSOC &&
-		   new_state == IEEE80211_STA_AUTH) {
+	} else if (old_state == IEEE80211_STA_NONE &&
+		   new_state == IEEE80211_STA_NOTEXIST) {
 		ret = ath9k_sta_remove(hw, vif, sta);
 		ath_dbg(common, CONFIG,
 			"Remove station: %pM\n", sta->addr);
@@ -1685,6 +1758,12 @@
 	if (sta)
 		an = (struct ath_node *)sta->drv_priv;
 
+	/* Delete pending key cache entries if no more frames are pointing to
+	 * them in TXQs.
+	 */
+	for (i = 0; i < ATH_KEYMAX; i++)
+		ath9k_pending_key_del(sc, i);
+
 	switch (cmd) {
 	case SET_KEY:
 		if (sta)
@@ -1714,7 +1793,15 @@
 		}
 		break;
 	case DISABLE_KEY:
-		ath_key_delete(common, key);
+		if (ath9k_txq_has_key(sc, key->hw_key_idx)) {
+			/* Delay key cache entry deletion until there are no
+			 * remaining TXQ frames pointing to this entry.
+			 */
+			set_bit(key->hw_key_idx, sc->sc_ah->pending_del_keymap);
+			ath_hw_keysetmac(common, key->hw_key_idx, NULL);
+		} else {
+			ath_key_delete(common, key->hw_key_idx);
+		}
 		if (an) {
 			for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
 				if (an->key_idx[i] != key->hw_key_idx)
@@ -1860,14 +1947,16 @@
 
 static int ath9k_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, bool amsdu)
+			      struct ieee80211_ampdu_params *params)
 {
 	struct ath_softc *sc = hw->priv;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	bool flush = false;
 	int ret = 0;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
 
 	mutex_lock(&sc->mutex);
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/pci.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/pci.c
@@ -27,8 +27,17 @@
 	{ PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI   */
 	{ PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
 	{ PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI   */
+
+#ifdef CONFIG_ATH9K_PCOEM
+	/* Mini PCI AR9220 MB92 cards: Compex WLM200NX, Wistron DNMA-92 */
+	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+			 0x0029,
+			 PCI_VENDOR_ID_ATHEROS,
+			 0x2096),
+	  .driver_data = ATH9K_PCI_LED_ACT_HI },
+#endif
+
 	{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
-	{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
 
 #ifdef CONFIG_ATH9K_PCOEM
 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
@@ -76,7 +85,11 @@
 			 0x10CF, /* Fujitsu */
 			 0x1536),
 	  .driver_data = ATH9K_PCI_D3_L1_WAR },
+#endif
+
+	{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
 
+#ifdef CONFIG_ATH9K_PCOEM
 	/* AR9285 card for Asus */
 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
 			 0x002B,
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/tx99.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/tx99.c
@@ -180,6 +180,9 @@
 	ssize_t len;
 	int r;
 
+	if (count < 1)
+		return -EINVAL;
+
 	if (sc->cur_chan->nvifs > 1)
 		return -EOPNOTSUPP;
 
@@ -187,25 +190,32 @@
 	if (copy_from_user(buf, user_buf, len))
 		return -EFAULT;
 
+	buf[len] = '\0';
+
 	if (strtobool(buf, &start))
 		return -EINVAL;
 
+	mutex_lock(&sc->mutex);
+
 	if (start == sc->tx99_state) {
 		if (!start)
-			return count;
+			goto out;
 		ath_dbg(common, XMIT, "Resetting TX99\n");
 		ath9k_tx99_deinit(sc);
 	}
 
 	if (!start) {
 		ath9k_tx99_deinit(sc);
-		return count;
+		goto out;
 	}
 
 	r = ath9k_tx99_init(sc);
-	if (r)
+	if (r) {
+		mutex_unlock(&sc->mutex);
 		return r;
-
+	}
+out:
+	mutex_unlock(&sc->mutex);
 	return count;
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/wmi.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/wmi.c
@@ -112,14 +112,17 @@
 	return wmi;
 }
 
-void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
+void ath9k_stop_wmi(struct ath9k_htc_priv *priv)
 {
 	struct wmi *wmi = priv->wmi;
 
 	mutex_lock(&wmi->op_mutex);
 	wmi->stopped = true;
 	mutex_unlock(&wmi->op_mutex);
+}
 
+void ath9k_destoy_wmi(struct ath9k_htc_priv *priv)
+{
 	kfree(priv->wmi);
 }
 
@@ -337,6 +340,7 @@
 		ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n",
 			wmi_cmd_to_name(cmd_id));
 		mutex_unlock(&wmi->op_mutex);
+		kfree_skb(skb);
 		return -ETIMEDOUT;
 	}
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/wmi.h
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/wmi.h
@@ -179,7 +179,6 @@
 };
 
 struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);
-void ath9k_deinit_wmi(struct ath9k_htc_priv *priv);
 int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
 		      enum htc_endpoint_id *wmi_ctrl_epid);
 int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
@@ -189,6 +188,8 @@
 void ath9k_wmi_event_tasklet(unsigned long data);
 void ath9k_fatal_work(struct work_struct *work);
 void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv);
+void ath9k_stop_wmi(struct ath9k_htc_priv *priv);
+void ath9k_destoy_wmi(struct ath9k_htc_priv *priv);
 
 #define WMI_CMD(_wmi_cmd)						\
 	do {								\
--- linux-4.4.0.orig/drivers/net/wireless/ath/ath9k/xmit.c
+++ linux-4.4.0/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1228,6 +1228,11 @@
 				 is_40, is_sgi, is_sp);
 			if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
 				info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
+			if (rix >= 8 && fi->dyn_smps) {
+				info->rates[i].RateFlags |=
+					ATH9K_RATESERIES_RTS_CTS;
+				info->flags |= ATH9K_TXDESC_CTSENA;
+			}
 
 			info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
 								is_40, false);
@@ -2114,6 +2119,7 @@
 		fi->keyix = an->ps_key;
 	else
 		fi->keyix = ATH9K_TXKEYIX_INVALID;
+	fi->dyn_smps = sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC;
 	fi->keytype = keytype;
 	fi->framelen = framelen;
 	fi->tx_power = txpower;
--- linux-4.4.0.orig/drivers/net/wireless/ath/carl9170/fw.c
+++ linux-4.4.0/drivers/net/wireless/ath/carl9170/fw.c
@@ -351,9 +351,7 @@
 		ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
 
 		if (SUPP(CARL9170FW_WLANTX_CAB)) {
-			if_comb_types |=
-				BIT(NL80211_IFTYPE_AP) |
-				BIT(NL80211_IFTYPE_P2P_GO);
+			if_comb_types |= BIT(NL80211_IFTYPE_AP);
 
 #ifdef CONFIG_MAC80211_MESH
 			if_comb_types |=
--- linux-4.4.0.orig/drivers/net/wireless/ath/carl9170/main.c
+++ linux-4.4.0/drivers/net/wireless/ath/carl9170/main.c
@@ -41,6 +41,7 @@
 #include <linux/module.h>
 #include <linux/etherdevice.h>
 #include <linux/random.h>
+#include <linux/nospec.h>
 #include <net/mac80211.h>
 #include <net/cfg80211.h>
 #include "hw.h"
@@ -582,11 +583,10 @@
 	ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) &&
 	    (vif->type != NL80211_IFTYPE_AP));
 
-	/* While the driver supports HW offload in a single
-	 * P2P client configuration, it doesn't support HW
-	 * offload in the favourit, concurrent P2P GO+CLIENT
-	 * configuration. Hence, HW offload will always be
-	 * disabled for P2P.
+	/* The driver used to have P2P GO+CLIENT support,
+	 * but since this was dropped and we don't know if
+	 * there are any gremlins lurking in the shadows,
+	 * so best we keep HW offload disabled for P2P.
 	 */
 	ar->disable_offload |= vif->p2p;
 
@@ -639,18 +639,6 @@
 			if (vif->type == NL80211_IFTYPE_STATION)
 				break;
 
-			/* P2P GO [master] use-case
-			 * Because the P2P GO station is selected dynamically
-			 * by all participating peers of a WIFI Direct network,
-			 * the driver has be able to change the main interface
-			 * operating mode on the fly.
-			 */
-			if (main_vif->p2p && vif->p2p &&
-			    vif->type == NL80211_IFTYPE_AP) {
-				old_main = main_vif;
-				break;
-			}
-
 			err = -EBUSY;
 			rcu_read_unlock();
 
@@ -1388,6 +1376,7 @@
 
 	mutex_lock(&ar->mutex);
 	if (queue < ar->hw->queues) {
+		queue = array_index_nospec(queue, ar->hw->queues); /* needed? */
 		memcpy(&ar->edcf[ar9170_qmap[queue]], param, sizeof(*param));
 		ret = carl9170_set_qos(ar);
 	} else {
@@ -1413,10 +1402,12 @@
 
 static int carl9170_op_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, bool amsdu)
+				    struct ieee80211_ampdu_params *params)
 {
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
 	struct ar9170 *ar = hw->priv;
 	struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
 	struct carl9170_sta_tid *tid_info;
--- linux-4.4.0.orig/drivers/net/wireless/ath/carl9170/usb.c
+++ linux-4.4.0/drivers/net/wireless/ath/carl9170/usb.c
@@ -128,6 +128,8 @@
 };
 MODULE_DEVICE_TABLE(usb, carl9170_usb_ids);
 
+static struct usb_driver carl9170_driver;
+
 static void carl9170_usb_submit_data_urb(struct ar9170 *ar)
 {
 	struct urb *urb;
@@ -968,32 +970,28 @@
 
 static void carl9170_usb_firmware_failed(struct ar9170 *ar)
 {
-	struct device *parent = ar->udev->dev.parent;
-	struct usb_device *udev;
-
-	/*
-	 * Store a copy of the usb_device pointer locally.
-	 * This is because device_release_driver initiates
-	 * carl9170_usb_disconnect, which in turn frees our
-	 * driver context (ar).
+	/* Store a copies of the usb_interface and usb_device pointer locally.
+	 * This is because release_driver initiates carl9170_usb_disconnect,
+	 * which in turn frees our driver context (ar).
 	 */
-	udev = ar->udev;
+	struct usb_interface *intf = ar->intf;
+	struct usb_device *udev = ar->udev;
 
 	complete(&ar->fw_load_wait);
+	/* at this point 'ar' could be already freed. Don't use it anymore */
+	ar = NULL;
 
 	/* unbind anything failed */
-	if (parent)
-		device_lock(parent);
-
-	device_release_driver(&udev->dev);
-	if (parent)
-		device_unlock(parent);
+	usb_lock_device(udev);
+	usb_driver_release_interface(&carl9170_driver, intf);
+	usb_unlock_device(udev);
 
-	usb_put_dev(udev);
+	usb_put_intf(intf);
 }
 
 static void carl9170_usb_firmware_finish(struct ar9170 *ar)
 {
+	struct usb_interface *intf = ar->intf;
 	int err;
 
 	err = carl9170_parse_firmware(ar);
@@ -1011,7 +1009,7 @@
 		goto err_unrx;
 
 	complete(&ar->fw_load_wait);
-	usb_put_dev(ar->udev);
+	usb_put_intf(intf);
 	return;
 
 err_unrx:
@@ -1054,7 +1052,6 @@
 		return PTR_ERR(ar);
 
 	udev = interface_to_usbdev(intf);
-	usb_get_dev(udev);
 	ar->udev = udev;
 	ar->intf = intf;
 	ar->features = id->driver_info;
@@ -1074,6 +1071,38 @@
 			ar->usb_ep_cmd_is_bulk = true;
 	}
 
+	/* Verify that all expected endpoints are present */
+	if (ar->usb_ep_cmd_is_bulk) {
+		u8 bulk_ep_addr[] = {
+			AR9170_USB_EP_RX | USB_DIR_IN,
+			AR9170_USB_EP_TX | USB_DIR_OUT,
+			AR9170_USB_EP_CMD | USB_DIR_OUT,
+			0};
+		u8 int_ep_addr[] = {
+			AR9170_USB_EP_IRQ | USB_DIR_IN,
+			0};
+		if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
+		    !usb_check_int_endpoints(intf, int_ep_addr))
+			err = -ENODEV;
+	} else {
+		u8 bulk_ep_addr[] = {
+			AR9170_USB_EP_RX | USB_DIR_IN,
+			AR9170_USB_EP_TX | USB_DIR_OUT,
+			0};
+		u8 int_ep_addr[] = {
+			AR9170_USB_EP_IRQ | USB_DIR_IN,
+			AR9170_USB_EP_CMD | USB_DIR_OUT,
+			0};
+		if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
+		    !usb_check_int_endpoints(intf, int_ep_addr))
+			err = -ENODEV;
+	}
+
+	if (err) {
+		carl9170_free(ar);
+		return err;
+	}
+
 	usb_set_intfdata(intf, ar);
 	SET_IEEE80211_DEV(ar->hw, &intf->dev);
 
@@ -1096,15 +1125,14 @@
 	atomic_set(&ar->rx_anch_urbs, 0);
 	atomic_set(&ar->rx_pool_urbs, 0);
 
-	usb_get_dev(ar->udev);
+	usb_get_intf(intf);
 
 	carl9170_set_state(ar, CARL9170_STOPPED);
 
 	err = request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME,
 		&ar->udev->dev, GFP_KERNEL, ar, carl9170_usb_firmware_step2);
 	if (err) {
-		usb_put_dev(udev);
-		usb_put_dev(udev);
+		usb_put_intf(intf);
 		carl9170_free(ar);
 	}
 	return err;
@@ -1133,7 +1161,6 @@
 
 	carl9170_release_firmware(ar);
 	carl9170_free(ar);
-	usb_put_dev(udev);
 }
 
 #ifdef CONFIG_PM
--- linux-4.4.0.orig/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ linux-4.4.0/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -111,7 +111,7 @@
 	JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18, 29, false),
 	JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18, 29, false),
 	JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18, 50, false),
-	JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18, 50, false),
+	JP_PATTERN(3, 0, 4, 4000, 4000, 1, 18, 50, false),
 	JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
 	JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
 	JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
--- linux-4.4.0.orig/drivers/net/wireless/ath/key.c
+++ linux-4.4.0/drivers/net/wireless/ath/key.c
@@ -84,8 +84,7 @@
 }
 EXPORT_SYMBOL(ath_hw_keyreset);
 
-static bool ath_hw_keysetmac(struct ath_common *common,
-			     u16 entry, const u8 *mac)
+bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
 {
 	u32 macHi, macLo;
 	u32 unicast_flag = AR_KEYTABLE_VALID;
@@ -125,6 +124,7 @@
 
 	return true;
 }
+EXPORT_SYMBOL(ath_hw_keysetmac);
 
 static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
 				      const struct ath_keyval *k,
@@ -581,29 +581,38 @@
 /*
  * Delete Key.
  */
-void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
+void ath_key_delete(struct ath_common *common, u8 hw_key_idx)
 {
-	ath_hw_keyreset(common, key->hw_key_idx);
-	if (key->hw_key_idx < IEEE80211_WEP_NKID)
+	/* Leave CCMP and TKIP (main key) configured to avoid disabling
+	 * encryption for potentially pending frames already in a TXQ with the
+	 * keyix pointing to this key entry. Instead, only clear the MAC address
+	 * to prevent RX processing from using this key cache entry.
+	 */
+	if (test_bit(hw_key_idx, common->ccmp_keymap) ||
+	    test_bit(hw_key_idx, common->tkip_keymap))
+		ath_hw_keysetmac(common, hw_key_idx, NULL);
+	else
+		ath_hw_keyreset(common, hw_key_idx);
+	if (hw_key_idx < IEEE80211_WEP_NKID)
 		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)
+	clear_bit(hw_key_idx, common->keymap);
+	clear_bit(hw_key_idx, common->ccmp_keymap);
+	if (!test_bit(hw_key_idx, common->tkip_keymap))
 		return;
 
-	clear_bit(key->hw_key_idx + 64, common->keymap);
+	clear_bit(hw_key_idx + 64, common->keymap);
 
-	clear_bit(key->hw_key_idx, common->tkip_keymap);
-	clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
+	clear_bit(hw_key_idx, common->tkip_keymap);
+	clear_bit(hw_key_idx + 64, common->tkip_keymap);
 
 	if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
-		ath_hw_keyreset(common, key->hw_key_idx + 32);
-		clear_bit(key->hw_key_idx + 32, common->keymap);
-		clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
+		ath_hw_keyreset(common, hw_key_idx + 32);
+		clear_bit(hw_key_idx + 32, common->keymap);
+		clear_bit(hw_key_idx + 64 + 32, common->keymap);
 
-		clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
-		clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
+		clear_bit(hw_key_idx + 32, common->tkip_keymap);
+		clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap);
 	}
 }
 EXPORT_SYMBOL(ath_key_delete);
--- linux-4.4.0.orig/drivers/net/wireless/ath/regd.c
+++ linux-4.4.0/drivers/net/wireless/ath/regd.c
@@ -254,8 +254,12 @@
 EXPORT_SYMBOL(ath_is_49ghz_allowed);
 
 /* Frequency is one where radar detection is required */
-static bool ath_is_radar_freq(u16 center_freq)
+static bool ath_is_radar_freq(u16 center_freq,
+			      struct ath_regulatory *reg)
+
 {
+	if (reg->country_code == CTRY_INDIA)
+		return (center_freq >= 5500 && center_freq <= 5700);
 	return (center_freq >= 5260 && center_freq <= 5700);
 }
 
@@ -306,7 +310,7 @@
 				enum nl80211_reg_initiator initiator,
 				struct ieee80211_channel *ch)
 {
-	if (ath_is_radar_freq(ch->center_freq) ||
+	if (ath_is_radar_freq(ch->center_freq, reg) ||
 	    (ch->flags & IEEE80211_CHAN_RADAR))
 		return;
 
@@ -395,8 +399,9 @@
 	}
 }
 
-/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
-static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
+/* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */
+static void ath_reg_apply_radar_flags(struct wiphy *wiphy,
+				      struct ath_regulatory *reg)
 {
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *ch;
@@ -409,7 +414,7 @@
 
 	for (i = 0; i < sband->n_channels; i++) {
 		ch = &sband->channels[i];
-		if (!ath_is_radar_freq(ch->center_freq))
+		if (!ath_is_radar_freq(ch->center_freq, reg))
 			continue;
 		/* We always enable radar detection/DFS on this
 		 * frequency range. Additionally we also apply on
@@ -505,7 +510,7 @@
 	struct ath_common *common = container_of(reg, struct ath_common,
 						 regulatory);
 	/* We always apply this */
-	ath_reg_apply_radar_flags(wiphy);
+	ath_reg_apply_radar_flags(wiphy, reg);
 
 	/*
 	 * This would happen when we have sent a custom regulatory request
@@ -653,7 +658,7 @@
 	}
 
 	wiphy_apply_custom_regulatory(wiphy, regd);
-	ath_reg_apply_radar_flags(wiphy);
+	ath_reg_apply_radar_flags(wiphy, reg);
 	ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/wireless/ath/regd.h
+++ linux-4.4.0/drivers/net/wireless/ath/regd.h
@@ -68,12 +68,14 @@
 	CTRY_AUSTRALIA = 36,
 	CTRY_AUSTRIA = 40,
 	CTRY_AZERBAIJAN = 31,
+	CTRY_BAHAMAS = 44,
 	CTRY_BAHRAIN = 48,
 	CTRY_BANGLADESH = 50,
 	CTRY_BARBADOS = 52,
 	CTRY_BELARUS = 112,
 	CTRY_BELGIUM = 56,
 	CTRY_BELIZE = 84,
+	CTRY_BERMUDA = 60,
 	CTRY_BOLIVIA = 68,
 	CTRY_BOSNIA_HERZ = 70,
 	CTRY_BRAZIL = 76,
@@ -159,6 +161,7 @@
 	CTRY_ROMANIA = 642,
 	CTRY_RUSSIA = 643,
 	CTRY_SAUDI_ARABIA = 682,
+	CTRY_SERBIA = 688,
 	CTRY_SERBIA_MONTENEGRO = 891,
 	CTRY_SINGAPORE = 702,
 	CTRY_SLOVAKIA = 703,
@@ -170,11 +173,13 @@
 	CTRY_SWITZERLAND = 756,
 	CTRY_SYRIA = 760,
 	CTRY_TAIWAN = 158,
+	CTRY_TANZANIA = 834,
 	CTRY_THAILAND = 764,
 	CTRY_TRINIDAD_Y_TOBAGO = 780,
 	CTRY_TUNISIA = 788,
 	CTRY_TURKEY = 792,
 	CTRY_UAE = 784,
+	CTRY_UGANDA = 800,
 	CTRY_UKRAINE = 804,
 	CTRY_UNITED_KINGDOM = 826,
 	CTRY_UNITED_STATES = 840,
--- linux-4.4.0.orig/drivers/net/wireless/ath/regd_common.h
+++ linux-4.4.0/drivers/net/wireless/ath/regd_common.h
@@ -35,6 +35,7 @@
 	FRANCE_RES = 0x31,
 	FCC3_FCCA = 0x3A,
 	FCC3_WORLD = 0x3B,
+	FCC3_ETSIC = 0x3F,
 
 	ETSI1_WORLD = 0x37,
 	ETSI3_ETSIA = 0x32,
@@ -44,6 +45,7 @@
 	ETSI4_ETSIC = 0x38,
 	ETSI5_WORLD = 0x39,
 	ETSI6_WORLD = 0x34,
+	ETSI8_WORLD = 0x3D,
 	ETSI_RESERVED = 0x33,
 
 	MKK1_MKKA = 0x40,
@@ -59,6 +61,7 @@
 	MKK1_MKKA1 = 0x4A,
 	MKK1_MKKA2 = 0x4B,
 	MKK1_MKKC = 0x4C,
+	APL2_FCCA = 0x4D,
 
 	APL3_FCCA = 0x50,
 	APL1_WORLD = 0x52,
@@ -67,6 +70,7 @@
 	APL1_ETSIC = 0x55,
 	APL2_ETSIC = 0x56,
 	APL5_WORLD = 0x58,
+	APL13_WORLD = 0x5A,
 	APL6_WORLD = 0x5B,
 	APL7_FCCA = 0x5C,
 	APL8_WORLD = 0x5D,
@@ -168,6 +172,7 @@
 	{FCC2_ETSIC, CTL_FCC, CTL_ETSI},
 	{FCC3_FCCA, CTL_FCC, CTL_FCC},
 	{FCC3_WORLD, CTL_FCC, CTL_ETSI},
+	{FCC3_ETSIC, CTL_FCC, CTL_ETSI},
 	{FCC4_FCCA, CTL_FCC, CTL_FCC},
 	{FCC5_FCCA, CTL_FCC, CTL_FCC},
 	{FCC6_FCCA, CTL_FCC, CTL_FCC},
@@ -179,6 +184,7 @@
 	{ETSI4_WORLD, CTL_ETSI, CTL_ETSI},
 	{ETSI5_WORLD, CTL_ETSI, CTL_ETSI},
 	{ETSI6_WORLD, CTL_ETSI, CTL_ETSI},
+	{ETSI8_WORLD, CTL_ETSI, CTL_ETSI},
 
 	/* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */
 	{ETSI3_ETSIA, CTL_ETSI, CTL_ETSI},
@@ -188,9 +194,11 @@
 	{FCC1_FCCA, CTL_FCC, CTL_FCC},
 	{APL1_WORLD, CTL_FCC, CTL_ETSI},
 	{APL2_WORLD, CTL_FCC, CTL_ETSI},
+	{APL2_FCCA, CTL_FCC, CTL_FCC},
 	{APL3_WORLD, CTL_FCC, CTL_ETSI},
 	{APL4_WORLD, CTL_FCC, CTL_ETSI},
 	{APL5_WORLD, CTL_FCC, CTL_ETSI},
+	{APL13_WORLD, CTL_ETSI, CTL_ETSI},
 	{APL6_WORLD, CTL_ETSI, CTL_ETSI},
 	{APL8_WORLD, CTL_ETSI, CTL_ETSI},
 	{APL9_WORLD, CTL_ETSI, CTL_ETSI},
@@ -298,6 +306,7 @@
 	{CTRY_AUSTRALIA2, FCC6_WORLD, "AU"},
 	{CTRY_AUSTRIA, ETSI1_WORLD, "AT"},
 	{CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"},
+	{CTRY_BAHAMAS, FCC3_WORLD, "BS"},
 	{CTRY_BAHRAIN, APL6_WORLD, "BH"},
 	{CTRY_BANGLADESH, NULL1_WORLD, "BD"},
 	{CTRY_BARBADOS, FCC2_WORLD, "BB"},
@@ -305,6 +314,7 @@
 	{CTRY_BELGIUM, ETSI1_WORLD, "BE"},
 	{CTRY_BELGIUM2, ETSI4_WORLD, "BL"},
 	{CTRY_BELIZE, APL1_ETSIC, "BZ"},
+	{CTRY_BERMUDA, FCC3_FCCA, "BM"},
 	{CTRY_BOLIVIA, APL1_ETSIC, "BO"},
 	{CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"},
 	{CTRY_BRAZIL, FCC3_WORLD, "BR"},
@@ -444,6 +454,7 @@
 	{CTRY_ROMANIA, NULL1_WORLD, "RO"},
 	{CTRY_RUSSIA, NULL1_WORLD, "RU"},
 	{CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"},
+	{CTRY_SERBIA, ETSI1_WORLD, "RS"},
 	{CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"},
 	{CTRY_SINGAPORE, APL6_WORLD, "SG"},
 	{CTRY_SLOVAKIA, ETSI1_WORLD, "SK"},
@@ -455,10 +466,12 @@
 	{CTRY_SWITZERLAND, ETSI1_WORLD, "CH"},
 	{CTRY_SYRIA, NULL1_WORLD, "SY"},
 	{CTRY_TAIWAN, APL3_FCCA, "TW"},
+	{CTRY_TANZANIA, APL1_WORLD, "TZ"},
 	{CTRY_THAILAND, FCC3_WORLD, "TH"},
 	{CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"},
 	{CTRY_TUNISIA, ETSI3_WORLD, "TN"},
 	{CTRY_TURKEY, ETSI3_WORLD, "TR"},
+	{CTRY_UGANDA, FCC3_WORLD, "UG"},
 	{CTRY_UKRAINE, NULL1_WORLD, "UA"},
 	{CTRY_UAE, NULL1_WORLD, "AE"},
 	{CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"},
--- linux-4.4.0.orig/drivers/net/wireless/ath/wcn36xx/main.c
+++ linux-4.4.0/drivers/net/wireless/ath/wcn36xx/main.c
@@ -156,7 +156,7 @@
 		.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),
+			.rx_highest = cpu_to_le16(150),
 			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
 		}
 	}
@@ -857,12 +857,14 @@
 
 static int wcn36xx_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, bool amsdu)
+		    struct ieee80211_ampdu_params *params)
 {
 	struct wcn36xx *wcn = hw->priv;
 	struct wcn36xx_sta *sta_priv = NULL;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
 
 	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
 		    action, tid);
--- linux-4.4.0.orig/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ linux-4.4.0/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -57,7 +57,7 @@
 		       RX_FLAG_MMIC_STRIPPED |
 		       RX_FLAG_DECRYPTED;
 
-	wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag);
+	wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%llx\n", status.flag);
 
 	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
 
--- linux-4.4.0.orig/drivers/net/wireless/ath/wil6210/Kconfig
+++ linux-4.4.0/drivers/net/wireless/ath/wil6210/Kconfig
@@ -1,6 +1,7 @@
 config WIL6210
 	tristate "Wilocity 60g WiFi card wil6210 support"
 	select WANT_DEV_COREDUMP
+	select CRC32
 	depends on CFG80211
 	depends on PCI
 	default n
--- linux-4.4.0.orig/drivers/net/wireless/ath/wil6210/debugfs.c
+++ linux-4.4.0/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1088,7 +1088,7 @@
 };
 
 /*---------temp------------*/
-static void print_temp(struct seq_file *s, const char *prefix, u32 t)
+static void print_temp(struct seq_file *s, const char *prefix, s32 t)
 {
 	switch (t) {
 	case 0:
@@ -1096,7 +1096,8 @@
 		seq_printf(s, "%s N/A\n", prefix);
 	break;
 	default:
-		seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
+		seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""),
+			   abs(t / 1000), abs(t % 1000));
 		break;
 	}
 }
@@ -1104,7 +1105,7 @@
 static int wil_temp_debugfs_show(struct seq_file *s, void *data)
 {
 	struct wil6210_priv *wil = s->private;
-	u32 t_m, t_r;
+	s32 t_m, t_r;
 	int rc = wmi_get_temperature(wil, &t_m, &t_r);
 
 	if (rc) {
--- linux-4.4.0.orig/drivers/net/wireless/ath/wil6210/main.c
+++ linux-4.4.0/drivers/net/wireless/ath/wil6210/main.c
@@ -125,9 +125,15 @@
 	u32 *d = dst;
 	const volatile u32 __iomem *s = src;
 
-	/* size_t is unsigned, if (count%4 != 0) it will wrap */
-	for (count += 4; count > 4; count -= 4)
+	for (; count >= 4; count -= 4)
 		*d++ = __raw_readl(s++);
+
+	if (unlikely(count)) {
+		/* count can be 1..3 */
+		u32 tmp = __raw_readl(s);
+
+		memcpy(d, &tmp, count);
+	}
 }
 
 void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
@@ -136,8 +142,16 @@
 	volatile u32 __iomem *d = dst;
 	const u32 *s = src;
 
-	for (count += 4; count > 4; count -= 4)
+	for (; count >= 4; count -= 4)
 		__raw_writel(*s++, d++);
+
+	if (unlikely(count)) {
+		/* count can be 1..3 */
+		u32 tmp = 0;
+
+		memcpy(&tmp, s, count);
+		__raw_writel(tmp, d);
+	}
 }
 
 static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
@@ -330,18 +344,19 @@
 
 	wil->last_fw_recovery = jiffies;
 
+	wil_info(wil, "fw error recovery requested (try %d)...\n",
+		 wil->recovery_count);
+	if (!no_fw_recovery)
+		wil->recovery_state = fw_recovery_running;
+	if (wil_wait_for_recovery(wil) != 0)
+		return;
+
 	mutex_lock(&wil->mutex);
 	switch (wdev->iftype) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_P2P_CLIENT:
 	case NL80211_IFTYPE_MONITOR:
-		wil_info(wil, "fw error recovery requested (try %d)...\n",
-			 wil->recovery_count);
-		if (!no_fw_recovery)
-			wil->recovery_state = fw_recovery_running;
-		if (0 != wil_wait_for_recovery(wil))
-			break;
-
+		/* silent recovery, upper layers will see disconnect */
 		__wil_down(wil);
 		__wil_up(wil);
 		break;
@@ -726,7 +741,7 @@
 
 static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
 {
-	ulong to = msecs_to_jiffies(1000);
+	ulong to = msecs_to_jiffies(2000);
 	ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
 
 	if (0 == left) {
--- linux-4.4.0.orig/drivers/net/wireless/ath/wil6210/txrx.c
+++ linux-4.4.0/drivers/net/wireless/ath/wil6210/txrx.c
@@ -538,8 +538,8 @@
 			v->swtail = next_tail) {
 		rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom);
 		if (unlikely(rc)) {
-			wil_err(wil, "Error %d in wil_rx_refill[%d]\n",
-				rc, v->swtail);
+			wil_err_ratelimited(wil, "Error %d in rx refill[%d]\n",
+					    rc, v->swtail);
 			break;
 		}
 	}
--- linux-4.4.0.orig/drivers/net/wireless/ath/wil6210/wmi.c
+++ linux-4.4.0/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1035,8 +1035,14 @@
 	};
 	int rc;
 	u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
-	struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
+	struct wmi_set_appie_cmd *cmd;
 
+	if (len < ie_len) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	cmd = kzalloc(len, GFP_KERNEL);
 	if (!cmd) {
 		rc = -ENOMEM;
 		goto out;
--- linux-4.4.0.orig/drivers/net/wireless/b43/b43.h
+++ linux-4.4.0/drivers/net/wireless/b43/b43.h
@@ -1081,6 +1081,22 @@
 	return dev->__using_pio_transfers;
 }
 
+static inline void b43_wake_queue(struct b43_wldev *dev, int queue_prio)
+{
+	if (dev->qos_enabled)
+		ieee80211_wake_queue(dev->wl->hw, queue_prio);
+	else
+		ieee80211_wake_queue(dev->wl->hw, 0);
+}
+
+static inline void b43_stop_queue(struct b43_wldev *dev, int queue_prio)
+{
+	if (dev->qos_enabled)
+		ieee80211_stop_queue(dev->wl->hw, queue_prio);
+	else
+		ieee80211_stop_queue(dev->wl->hw, 0);
+}
+
 /* Message printing */
 __printf(2, 3) void b43info(struct b43_wl *wl, const char *fmt, ...);
 __printf(2, 3) void b43err(struct b43_wl *wl, const char *fmt, ...);
--- linux-4.4.0.orig/drivers/net/wireless/b43/dma.c
+++ linux-4.4.0/drivers/net/wireless/b43/dma.c
@@ -1461,8 +1461,8 @@
 	    should_inject_overflow(ring)) {
 		/* This TX ring is full. */
 		unsigned int skb_mapping = skb_get_queue_mapping(skb);
-		ieee80211_stop_queue(dev->wl->hw, skb_mapping);
-		dev->wl->tx_queue_stopped[skb_mapping] = 1;
+		b43_stop_queue(dev, skb_mapping);
+		dev->wl->tx_queue_stopped[skb_mapping] = true;
 		ring->stopped = true;
 		if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
 			b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
@@ -1626,11 +1626,11 @@
 	}
 
 	if (dev->wl->tx_queue_stopped[ring->queue_prio]) {
-		dev->wl->tx_queue_stopped[ring->queue_prio] = 0;
+		dev->wl->tx_queue_stopped[ring->queue_prio] = false;
 	} else {
 		/* If the driver queue is running wake the corresponding
 		 * mac80211 queue. */
-		ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
+		b43_wake_queue(dev, ring->queue_prio);
 		if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
 			b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
 		}
--- linux-4.4.0.orig/drivers/net/wireless/b43/main.c
+++ linux-4.4.0/drivers/net/wireless/b43/main.c
@@ -5611,7 +5611,7 @@
 	/* fill hw info */
 	ieee80211_hw_set(hw, RX_INCLUDES_FCS);
 	ieee80211_hw_set(hw, SIGNAL_DBM);
-
+	ieee80211_hw_set(hw, MFP_CAPABLE);
 	hw->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_AP) |
 		BIT(NL80211_IFTYPE_MESH_POINT) |
--- linux-4.4.0.orig/drivers/net/wireless/b43/phy_common.c
+++ linux-4.4.0/drivers/net/wireless/b43/phy_common.c
@@ -616,7 +616,7 @@
 	u8 i;
 	s32 tmp;
 	s8 signx = 1;
-	u32 angle = 0;
+	s32 angle = 0;
 	struct b43_c32 ret = { .i = 39797, .q = 0, };
 
 	while (theta > (180 << 16))
--- linux-4.4.0.orig/drivers/net/wireless/b43/phy_lp.c
+++ linux-4.4.0/drivers/net/wireless/b43/phy_lp.c
@@ -1834,7 +1834,7 @@
 static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
-	struct lpphy_tx_gains gains, oldgains;
+	struct lpphy_tx_gains oldgains;
 	int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
 
 	lpphy_read_tx_pctl_mode_from_hardware(dev);
@@ -1848,9 +1848,9 @@
 	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
 
 	if (dev->dev->chip_id == 0x4325 && dev->dev->chip_rev == 0)
-		lpphy_papd_cal(dev, gains, 0, 1, 30);
+		lpphy_papd_cal(dev, oldgains, 0, 1, 30);
 	else
-		lpphy_papd_cal(dev, gains, 0, 1, 65);
+		lpphy_papd_cal(dev, oldgains, 0, 1, 65);
 
 	if (old_afe_ovr)
 		lpphy_set_tx_gains(dev, oldgains);
--- linux-4.4.0.orig/drivers/net/wireless/b43/phy_n.c
+++ linux-4.4.0/drivers/net/wireless/b43/phy_n.c
@@ -5320,7 +5320,7 @@
 
 	for (i = 0; i < 4; i++) {
 		if (dev->phy.rev >= 3)
-			table[i] = coef[i];
+			coef[i] = table[i];
 		else
 			coef[i] = 0;
 	}
--- linux-4.4.0.orig/drivers/net/wireless/b43legacy/main.c
+++ linux-4.4.0/drivers/net/wireless/b43legacy/main.c
@@ -1304,8 +1304,9 @@
 }
 
 /* Interrupt handler bottom-half */
-static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
+static void b43legacy_interrupt_tasklet(unsigned long data)
 {
+	struct b43legacy_wldev *dev = (struct b43legacy_wldev *)data;
 	u32 reason;
 	u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
 	u32 merged_dma_reason = 0;
@@ -3775,7 +3776,7 @@
 	b43legacy_set_status(wldev, B43legacy_STAT_UNINIT);
 	wldev->bad_frames_preempt = modparam_bad_frames_preempt;
 	tasklet_init(&wldev->isr_tasklet,
-		     (void (*)(unsigned long))b43legacy_interrupt_tasklet,
+		     b43legacy_interrupt_tasklet,
 		     (unsigned long)wldev);
 	if (modparam_pio)
 		wldev->__using_pio = true;
@@ -3834,6 +3835,7 @@
 	/* fill hw info */
 	ieee80211_hw_set(hw, RX_INCLUDES_FCS);
 	ieee80211_hw_set(hw, SIGNAL_DBM);
+	ieee80211_hw_set(hw, MFP_CAPABLE); /* Allow WPA3 in software */
 
 	hw->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_AP) |
--- linux-4.4.0.orig/drivers/net/wireless/b43legacy/xmit.c
+++ linux-4.4.0/drivers/net/wireless/b43legacy/xmit.c
@@ -571,6 +571,7 @@
 	default:
 		b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
 		       chanstat);
+		goto drop;
 	}
 
 	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -705,7 +705,7 @@
 int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
 			   struct sk_buff_head *pktq, uint totlen)
 {
-	struct sk_buff *glom_skb;
+	struct sk_buff *glom_skb = NULL;
 	struct sk_buff *skb;
 	u32 addr = sdiodev->sbwad;
 	int err = 0;
@@ -738,6 +738,7 @@
 					    pktq);
 
 done:
+	brcmu_pkt_buf_free_skb(glom_skb);
 	return err;
 }
 
@@ -891,7 +892,7 @@
 		return;
 
 	nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz);
-	nents += (nents >> 4) + 1;
+	nents *= 2;
 
 	WARN_ON(nents > sdiodev->max_segment_count);
 
@@ -1107,6 +1108,7 @@
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362),
+ 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345),
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/bus.h
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/bus.h
@@ -214,7 +214,9 @@
 		      int prec);
 
 /* Receive frame for delivery to OS.  Callee disposes of rxp. */
-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
+void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event);
+/* Receive async event packet from firmware. Callee disposes of rxp. */
+void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
 
 /* Indication from bus module regarding presence/insertion of dongle. */
 int brcmf_attach(struct device *dev);
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -679,8 +679,7 @@
 	scan_request = cfg->scan_request;
 	cfg->scan_request = NULL;
 
-	if (timer_pending(&cfg->escan_timeout))
-		del_timer_sync(&cfg->escan_timeout);
+	del_timer_sync(&cfg->escan_timeout);
 
 	if (fw_abort) {
 		/* Do a scan abort to stop the driver's scan engine */
@@ -876,7 +875,7 @@
 
 	eth_broadcast_addr(params_le->bssid);
 	params_le->bss_type = DOT11_BSSTYPE_ANY;
-	params_le->scan_type = 0;
+	params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
 	params_le->channel_num = 0;
 	params_le->nprobes = cpu_to_le32(-1);
 	params_le->active_time = cpu_to_le32(-1);
@@ -884,12 +883,9 @@
 	params_le->home_time = cpu_to_le32(-1);
 	memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
 
-	/* if request is null exit so it will be all channel broadcast scan */
-	if (!request)
-		return;
-
 	n_ssids = request->n_ssids;
 	n_channels = request->n_channels;
+
 	/* Copy channel array if applicable */
 	brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
 		  n_channels);
@@ -926,16 +922,8 @@
 			ptr += sizeof(ssid_le);
 		}
 	} else {
-		brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
-		if ((request->ssids) && request->ssids->ssid_len) {
-			brcmf_dbg(SCAN, "SSID %s len=%d\n",
-				  params_le->ssid_le.SSID,
-				  request->ssids->ssid_len);
-			params_le->ssid_le.SSID_len =
-				cpu_to_le32(request->ssids->ssid_len);
-			memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
-				request->ssids->ssid_len);
-		}
+		brcmf_dbg(SCAN, "Performing passive scan\n");
+		params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
 	}
 	/* Adding mask to channel numbers */
 	params_le->channel_num =
@@ -2408,7 +2396,7 @@
 				     WL_BSS_INFO_MAX);
 	if (err) {
 		brcmf_err("Failed to get bss info (%d)\n", err);
-		return;
+		goto out_kfree;
 	}
 	si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
 	si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
@@ -2420,6 +2408,9 @@
 		si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
 	if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
 		si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+
+out_kfree:
+	kfree(buf);
 }
 
 static s32
@@ -2427,12 +2418,14 @@
 			   const u8 *mac, struct station_info *sinfo)
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
+	struct brcmf_scb_val_le scb_val;
 	s32 err = 0;
 	struct brcmf_sta_info_le sta_info_le;
 	u32 sta_flags;
 	u32 is_tdls_peer;
 	s32 total_rssi;
 	s32 count_rssi;
+	int rssi;
 	u32 i;
 
 	brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
@@ -2513,6 +2506,20 @@
 			sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
 			total_rssi /= count_rssi;
 			sinfo->signal = total_rssi;
+		} else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
+			&ifp->vif->sme_state)) {
+			memset(&scb_val, 0, sizeof(scb_val));
+			err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
+						     &scb_val, sizeof(scb_val));
+			if (err) {
+				brcmf_err("Could not get rssi (%d)\n", err);
+				goto done;
+			} else {
+				rssi = le32_to_cpu(scb_val.val);
+				sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+				sinfo->signal = rssi;
+				brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
+			}
 		}
 	}
 done:
@@ -2911,6 +2918,7 @@
 	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
 	s32 status;
 	struct brcmf_escan_result_le *escan_result_le;
+	u32 escan_buflen;
 	struct brcmf_bss_info_le *bss_info_le;
 	struct brcmf_bss_info_le *bss = NULL;
 	u32 bi_length;
@@ -2927,11 +2935,23 @@
 
 	if (status == BRCMF_E_STATUS_PARTIAL) {
 		brcmf_dbg(SCAN, "ESCAN Partial result\n");
+		if (e->datalen < sizeof(*escan_result_le)) {
+			brcmf_err("invalid event data length\n");
+			goto exit;
+		}
 		escan_result_le = (struct brcmf_escan_result_le *) data;
 		if (!escan_result_le) {
 			brcmf_err("Invalid escan result (NULL pointer)\n");
 			goto exit;
 		}
+		escan_buflen = le32_to_cpu(escan_result_le->buflen);
+		if (escan_buflen > WL_ESCAN_BUF_SIZE ||
+		    escan_buflen > e->datalen ||
+		    escan_buflen < sizeof(*escan_result_le)) {
+			brcmf_err("Invalid escan buffer length: %d\n",
+				  escan_buflen);
+			goto exit;
+		}
 		if (le16_to_cpu(escan_result_le->bss_count) != 1) {
 			brcmf_err("Invalid bss_count %d: ignoring\n",
 				  escan_result_le->bss_count);
@@ -2948,9 +2968,8 @@
 		}
 
 		bi_length = le32_to_cpu(bss_info_le->length);
-		if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
-					WL_ESCAN_RESULTS_FIXED_SIZE)) {
-			brcmf_err("Invalid bss_info length %d: ignoring\n",
+		if (bi_length != escan_buflen -	WL_ESCAN_RESULTS_FIXED_SIZE) {
+			brcmf_err("Ignoring invalid bss_info length: %d\n",
 				  bi_length);
 			goto exit;
 		}
@@ -3324,9 +3343,15 @@
 	struct brcmf_pno_scanresults_le *pfn_result;
 	u32 result_count;
 	u32 status;
+	u32 datalen;
 
 	brcmf_dbg(SCAN, "Enter\n");
 
+	if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
+		brcmf_dbg(SCAN, "Event data to small. Ignore\n");
+		return 0;
+	}
+
 	if (e->event_code == BRCMF_E_PFN_NET_LOST) {
 		brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
 		return 0;
@@ -3345,6 +3370,14 @@
 	if (result_count > 0) {
 		int i;
 
+		data += sizeof(struct brcmf_pno_scanresults_le);
+		netinfo_start = (struct brcmf_pno_net_info_le *)data;
+		datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
+		if (datalen < result_count * sizeof(*netinfo)) {
+			brcmf_err("insufficient event data\n");
+			goto out_err;
+		}
+
 		request = kzalloc(sizeof(*request), GFP_KERNEL);
 		ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
 		channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
@@ -3354,9 +3387,6 @@
 		}
 
 		request->wiphy = wiphy;
-		data += sizeof(struct brcmf_pno_scanresults_le);
-		netinfo_start = (struct brcmf_pno_net_info_le *)data;
-
 		for (i = 0; i < result_count; i++) {
 			netinfo = &netinfo_start[i];
 			if (!netinfo) {
@@ -3366,6 +3396,8 @@
 				goto out_err;
 			}
 
+			if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
+				netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
 			brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
 				  netinfo->SSID, netinfo->channel);
 			memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
@@ -4099,7 +4131,7 @@
 				(u8 *)&settings->beacon.head[ie_offset],
 				settings->beacon.head_len - ie_offset,
 				WLAN_EID_SSID);
-		if (!ssid_ie)
+		if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
 			return -EINVAL;
 
 		memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
@@ -4291,9 +4323,6 @@
 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
 		if (err < 0)
 			brcmf_err("setting AP mode failed %d\n", err);
-		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
-		if (err < 0)
-			brcmf_err("setting INFRA mode failed %d\n", err);
 		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
 			brcmf_fil_iovar_int_set(ifp, "mbss", 0);
 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
@@ -4469,6 +4498,11 @@
 		cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
 					GFP_KERNEL);
 	} else if (ieee80211_is_action(mgmt->frame_control)) {
+		if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
+			brcmf_err("invalid action frame length\n");
+			err = -EINVAL;
+			goto exit;
+		}
 		af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
 		if (af_params == NULL) {
 			brcmf_err("unable to allocate frame\n");
@@ -4818,6 +4852,11 @@
 		(struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
 	req_len = le32_to_cpu(assoc_info->req_len);
 	resp_len = le32_to_cpu(assoc_info->resp_len);
+	if (req_len > WL_EXTRA_BUF_MAX || resp_len > WL_EXTRA_BUF_MAX) {
+		brcmf_err("invalid lengths in assoc info: req %u resp %u\n",
+			 req_len, resp_len);
+		return -EINVAL;
+	}
 	if (req_len) {
 		err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
 					       cfg->extra_buf,
@@ -4830,6 +4869,8 @@
 		conn_info->req_ie =
 		    kmemdup(cfg->extra_buf, conn_info->req_ie_len,
 			    GFP_KERNEL);
+		if (!conn_info->req_ie)
+			conn_info->req_ie_len = 0;
 	} else {
 		conn_info->req_ie_len = 0;
 		conn_info->req_ie = NULL;
@@ -4846,6 +4887,8 @@
 		conn_info->resp_ie =
 		    kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
 			    GFP_KERNEL);
+		if (!conn_info->resp_ie)
+			conn_info->resp_ie_len = 0;
 	} else {
 		conn_info->resp_ie_len = 0;
 		conn_info->resp_ie = NULL;
@@ -6161,7 +6204,7 @@
 		  req->alpha2[0], req->alpha2[1]);
 
 	/* ignore non-ISO3166 country codes */
-	for (i = 0; i < sizeof(req->alpha2); i++)
+	for (i = 0; i < 2; i++)
 		if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
 			brcmf_err("not a ISO3166 code\n");
 			return;
@@ -6353,5 +6396,6 @@
 	brcmf_btcoex_detach(cfg);
 	wiphy_unregister(cfg->wiphy);
 	wl_deinit_priv(cfg);
+	cancel_work_sync(&cfg->escan_timeout_work);
 	brcmf_free_wiphy(cfg->wiphy);
 }
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -211,7 +211,7 @@
 	int ret;
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_pub *drvr = ifp->drvr;
-	struct ethhdr *eh = (struct ethhdr *)(skb->data);
+	struct ethhdr *eh;
 
 	brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx);
 
@@ -232,22 +232,13 @@
 		goto done;
 	}
 
-	/* Make sure there's enough room for any header */
-	if (skb_headroom(skb) < drvr->hdrlen) {
-		struct sk_buff *skb2;
-
-		brcmf_dbg(INFO, "%s: insufficient headroom\n",
+	/* Make sure there's enough writable headroom*/
+	ret = skb_cow_head(skb, drvr->hdrlen);
+	if (ret < 0) {
+		brcmf_err("%s: skb_cow_head failed\n",
 			  brcmf_ifname(drvr, ifp->bssidx));
-		drvr->bus_if->tx_realloc++;
-		skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
 		dev_kfree_skb(skb);
-		skb = skb2;
-		if (skb == NULL) {
-			brcmf_err("%s: skb_realloc_headroom failed\n",
-				  brcmf_ifname(drvr, ifp->bssidx));
-			ret = -ENOMEM;
-			goto done;
-		}
+		goto done;
 	}
 
 	/* validate length for ether packet */
@@ -257,6 +248,8 @@
 		goto done;
 	}
 
+	eh = (struct ethhdr *)(skb->data);
+
 	if (eh->h_proto == htons(ETH_P_PAE))
 		atomic_inc(&ifp->pend_8021x_cnt);
 
@@ -310,15 +303,9 @@
 
 void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
 {
-	skb->dev = ifp->ndev;
-	skb->protocol = eth_type_trans(skb, skb->dev);
-
 	if (skb->pkt_type == PACKET_MULTICAST)
 		ifp->stats.multicast++;
 
-	/* Process special event packets */
-	brcmf_fweh_process_skb(ifp->drvr, skb);
-
 	if (!(ifp->ndev->flags & IFF_UP)) {
 		brcmu_pkt_buf_free_skb(skb);
 		return;
@@ -533,7 +520,7 @@
 	}
 }
 
-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
+void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
 {
 	struct brcmf_if *ifp;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -553,11 +540,44 @@
 		return;
 	}
 
+	skb->protocol = eth_type_trans(skb, ifp->ndev);
+
 	rd = (struct brcmf_skb_reorder_data *)skb->cb;
-	if (rd->reorder)
+	if (rd->reorder) {
 		brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
-	else
+	} else {
+		/* Process special event packets */
+		if (handle_event)
+			brcmf_fweh_process_skb(ifp->drvr, skb,
+					       BCMILCP_SUBTYPE_VENDOR_LONG);
+
 		brcmf_netif_rx(ifp, skb);
+	}
+}
+
+void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
+{
+	struct brcmf_if *ifp;
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_pub *drvr = bus_if->drvr;
+	int ret;
+
+	brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
+
+	/* process and remove protocol-specific header */
+	ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
+
+	if (ret || !ifp || !ifp->ndev) {
+		if (ret != -ENODATA && ifp)
+			ifp->stats.rx_errors++;
+		brcmu_pkt_buf_free_skb(skb);
+		return;
+	}
+
+	skb->protocol = eth_type_trans(skb, ifp->ndev);
+
+	brcmf_fweh_process_skb(ifp->drvr, skb, 0);
+	brcmu_pkt_buf_free_skb(skb);
 }
 
 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -26,50 +26,6 @@
 #include "fwil.h"
 
 /**
- * struct brcm_ethhdr - broadcom specific ether header.
- *
- * @subtype: subtype for this packet.
- * @length: TODO: length of appended data.
- * @version: version indication.
- * @oui: OUI of this packet.
- * @usr_subtype: subtype for this OUI.
- */
-struct brcm_ethhdr {
-	__be16 subtype;
-	__be16 length;
-	u8 version;
-	u8 oui[3];
-	__be16 usr_subtype;
-} __packed;
-
-struct brcmf_event_msg_be {
-	__be16 version;
-	__be16 flags;
-	__be32 event_type;
-	__be32 status;
-	__be32 reason;
-	__be32 auth_type;
-	__be32 datalen;
-	u8 addr[ETH_ALEN];
-	char ifname[IFNAMSIZ];
-	u8 ifidx;
-	u8 bsscfgidx;
-} __packed;
-
-/**
- * struct brcmf_event - contents of broadcom event packet.
- *
- * @eth: standard ether header.
- * @hdr: broadcom specific ether header.
- * @msg: common part of the actual event message.
- */
-struct brcmf_event {
-	struct ethhdr eth;
-	struct brcm_ethhdr hdr;
-	struct brcmf_event_msg_be msg;
-} __packed;
-
-/**
  * struct brcmf_fweh_queue_item - event item on event queue.
  *
  * @q: list element for queuing.
@@ -85,6 +41,7 @@
 	u8 ifidx;
 	u8 ifaddr[ETH_ALEN];
 	struct brcmf_event_msg_be emsg;
+	u32 datalen;
 	u8 data[0];
 };
 
@@ -274,6 +231,10 @@
 			  brcmf_fweh_event_name(event->code), event->code,
 			  event->emsg.ifidx, event->emsg.bsscfgidx,
 			  event->emsg.addr);
+		if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) {
+			brcmf_err("invalid bsscfg index: %u\n", event->emsg.bsscfgidx);
+			goto event_free;
+		}
 
 		/* convert event message */
 		emsg_be = &event->emsg;
@@ -294,6 +255,11 @@
 		brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
 				   min_t(u32, emsg.datalen, 64),
 				   "event payload, len=%d\n", emsg.datalen);
+		if (emsg.datalen > event->datalen) {
+			brcmf_err("event invalid length header=%d, msg=%d\n",
+				  event->datalen, emsg.datalen);
+			goto event_free;
+		}
 
 		/* special handling of interface event */
 		if (event->code == BRCMF_E_IF) {
@@ -439,7 +405,8 @@
  * dispatch the event to a registered handler (using worker).
  */
 void brcmf_fweh_process_event(struct brcmf_pub *drvr,
-			      struct brcmf_event *event_packet)
+			      struct brcmf_event *event_packet,
+			      u32 packet_len)
 {
 	enum brcmf_fweh_event_code code;
 	struct brcmf_fweh_info *fweh = &drvr->fweh;
@@ -459,6 +426,9 @@
 	if (code != BRCMF_E_IF && !fweh->evt_handler[code])
 		return;
 
+	if (datalen > BRCMF_DCMD_MAXLEN)
+		return;
+
 	if (in_interrupt())
 		alloc_flag = GFP_ATOMIC;
 
@@ -472,6 +442,7 @@
 	/* use memcpy to get aligned event message */
 	memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
 	memcpy(event->data, data, datalen);
+	event->datalen = datalen;
 	memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
 
 	brcmf_fweh_queue_event(fweh, event);
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
@@ -27,7 +27,6 @@
 struct brcmf_pub;
 struct brcmf_if;
 struct brcmf_cfg80211_info;
-struct brcmf_event;
 
 /* list of firmware events */
 #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
@@ -180,11 +179,53 @@
 /**
  * definitions for event packet validation.
  */
-#define BRCMF_EVENT_OUI_OFFSET		19
-#define BRCM_OUI			"\x00\x10\x18"
-#define DOT11_OUI_LEN			3
-#define BCMILCP_BCM_SUBTYPE_EVENT	1
+#define BRCM_OUI				"\x00\x10\x18"
+#define BCMILCP_BCM_SUBTYPE_EVENT		1
+#define BCMILCP_SUBTYPE_VENDOR_LONG		32769
 
+/**
+ * struct brcm_ethhdr - broadcom specific ether header.
+ *
+ * @subtype: subtype for this packet.
+ * @length: TODO: length of appended data.
+ * @version: version indication.
+ * @oui: OUI of this packet.
+ * @usr_subtype: subtype for this OUI.
+ */
+struct brcm_ethhdr {
+	__be16 subtype;
+	__be16 length;
+	u8 version;
+	u8 oui[3];
+	__be16 usr_subtype;
+} __packed;
+
+struct brcmf_event_msg_be {
+	__be16 version;
+	__be16 flags;
+	__be32 event_type;
+	__be32 status;
+	__be32 reason;
+	__be32 auth_type;
+	__be32 datalen;
+	u8 addr[ETH_ALEN];
+	char ifname[IFNAMSIZ];
+	u8 ifidx;
+	u8 bsscfgidx;
+} __packed;
+
+/**
+ * struct brcmf_event - contents of broadcom event packet.
+ *
+ * @eth: standard ether header.
+ * @hdr: broadcom specific ether header.
+ * @msg: common part of the actual event message.
+ */
+struct brcmf_event {
+	struct ethhdr eth;
+	struct brcm_ethhdr hdr;
+	struct brcmf_event_msg_be msg;
+} __packed;
 
 /**
  * struct brcmf_event_msg - firmware event message.
@@ -256,34 +297,43 @@
 			   enum brcmf_fweh_event_code code);
 int brcmf_fweh_activate_events(struct brcmf_if *ifp);
 void brcmf_fweh_process_event(struct brcmf_pub *drvr,
-			      struct brcmf_event *event_packet);
+			      struct brcmf_event *event_packet,
+			      u32 packet_len);
 void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
 
 static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
-					  struct sk_buff *skb)
+					  struct sk_buff *skb, u16 stype)
 {
 	struct brcmf_event *event_packet;
-	u8 *data;
-	u16 usr_stype;
+	u16 subtype, usr_stype;
 
 	/* only process events when protocol matches */
 	if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
 		return;
 
-	/* check for BRCM oui match */
+	if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
+		return;
+
 	event_packet = (struct brcmf_event *)skb_mac_header(skb);
-	data = (u8 *)event_packet;
-	data += BRCMF_EVENT_OUI_OFFSET;
-	if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
+
+	/* check subtype if needed */
+	if (unlikely(stype)) {
+		subtype = get_unaligned_be16(&event_packet->hdr.subtype);
+		if (subtype != stype)
+			return;
+	}
+
+	/* check for BRCM oui match */
+	if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
+		   sizeof(event_packet->hdr.oui)))
 		return;
 
 	/* final match on usr_subtype */
-	data += DOT11_OUI_LEN;
-	usr_stype = get_unaligned_be16(data);
+	usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
 	if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
 		return;
 
-	brcmf_fweh_process_event(drvr, event_packet);
+	brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
 }
 
 #endif /* FWEH_H_ */
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -30,7 +30,7 @@
 #define BRCMF_ARP_OL_PEER_AUTO_REPLY	0x00000008
 
 #define	BRCMF_BSS_INFO_VERSION	109 /* curr ver of brcmf_bss_info_le struct */
-#define BRCMF_BSS_RSSI_ON_CHANNEL	0x0002
+#define BRCMF_BSS_RSSI_ON_CHANNEL	0x0004
 
 #define BRCMF_STA_WME              0x00000002      /* WMM association */
 #define BRCMF_STA_AUTHE            0x00000008      /* Authenticated */
@@ -45,6 +45,11 @@
 #define BRCMF_SCAN_PARAMS_COUNT_MASK	0x0000ffff
 #define BRCMF_SCAN_PARAMS_NSSID_SHIFT	16
 
+/* scan type definitions */
+#define BRCMF_SCANTYPE_DEFAULT		0xFF
+#define BRCMF_SCANTYPE_ACTIVE		0
+#define BRCMF_SCANTYPE_PASSIVE		1
+
 /* primary (ie tx) key */
 #define BRCMF_PRIMARY_KEY		(1 << 1)
 #define DOT11_BSSTYPE_ANY		2
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -2262,10 +2262,22 @@
 void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
 {
 	struct brcmf_fws_info *fws = drvr->fws;
+	struct brcmf_if *ifp;
+	int i;
 
-	fws->bus_flow_blocked = flow_blocked;
-	if (!flow_blocked)
-		brcmf_fws_schedule_deq(fws);
-	else
-		fws->stats.bus_flow_block++;
+	if (fws->avoid_queueing) {
+		for (i = 0; i < BRCMF_MAX_IFS; i++) {
+			ifp = drvr->iflist[i];
+			if (!ifp || !ifp->ndev)
+				continue;
+			brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW,
+					     flow_blocked);
+		}
+	} else {
+		fws->bus_flow_blocked = flow_blocked;
+		if (!flow_blocked)
+			brcmf_fws_schedule_deq(fws);
+		else
+			fws->stats.bus_flow_block++;
+	}
 }
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -20,6 +20,7 @@
 
 #include <linux/types.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
@@ -1076,28 +1077,13 @@
 }
 
 
-static void
-brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
-		    u8 ifidx)
-{
-	struct brcmf_if *ifp;
-
-	ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
-	if (!ifp || !ifp->ndev) {
-		brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
-		brcmu_pkt_buf_free_skb(skb);
-		return;
-	}
-	brcmf_netif_rx(ifp, skb);
-}
-
-
 static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
 {
 	struct msgbuf_rx_event *event;
 	u32 idx;
 	u16 buflen;
 	struct sk_buff *skb;
+	struct brcmf_if *ifp;
 
 	event = (struct msgbuf_rx_event *)buf;
 	idx = le32_to_cpu(event->msg.request_id);
@@ -1117,7 +1103,19 @@
 
 	skb_trim(skb, buflen);
 
-	brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
+	ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
+	if (!ifp || !ifp->ndev) {
+		brcmf_err("Received pkt for invalid ifidx %d\n",
+			  event->msg.ifidx);
+		goto exit;
+	}
+
+	skb->protocol = eth_type_trans(skb, ifp->ndev);
+
+	brcmf_fweh_process_skb(ifp->drvr, skb, 0);
+
+exit:
+	brcmu_pkt_buf_free_skb(skb);
 }
 
 
@@ -1129,6 +1127,7 @@
 	u16 data_offset;
 	u16 buflen;
 	u32 idx;
+	struct brcmf_if *ifp;
 
 	brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
 
@@ -1149,7 +1148,16 @@
 
 	skb_trim(skb, buflen);
 
-	brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
+	ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
+	if (!ifp || !ifp->ndev) {
+		brcmf_err("Received pkt for invalid ifidx %d\n",
+			  rx_complete->msg.ifidx);
+		brcmu_pkt_buf_free_skb(skb);
+		return;
+	}
+
+	skb->protocol = eth_type_trans(skb, ifp->ndev);
+	brcmf_netif_rx(ifp, skb);
 }
 
 
@@ -1522,6 +1530,8 @@
 					  BRCMF_TX_IOCTL_MAX_MSG_SIZE,
 					  msgbuf->ioctbuf,
 					  msgbuf->ioctbuf_handle);
+		if (msgbuf->txflow_wq)
+			destroy_workqueue(msgbuf->txflow_wq);
 		kfree(msgbuf);
 	}
 	return -ENOMEM;
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -461,25 +461,23 @@
  * @dev_addr: optional device address.
  *
  * P2P needs mac addresses for P2P device and interface. If no device
- * address it specified, these are derived from the primary net device, ie.
- * the permanent ethernet address of the device.
+ * address it specified, these are derived from a random ethernet
+ * address.
  */
 static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
 {
-	struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
-	bool local_admin = false;
+	bool random_addr = false;
 
-	if (!dev_addr || is_zero_ether_addr(dev_addr)) {
-		dev_addr = pri_ifp->mac_addr;
-		local_admin = true;
-	}
+	if (!dev_addr || is_zero_ether_addr(dev_addr))
+		random_addr = true;
 
-	/* Generate the P2P Device Address.  This consists of the device's
-	 * primary MAC address with the locally administered bit set.
+	/* Generate the P2P Device Address obtaining a random ethernet
+	 * address with the locally administered bit set.
 	 */
-	memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
-	if (local_admin)
-		p2p->dev_addr[0] |= 0x02;
+	if (random_addr)
+		eth_random_addr(p2p->dev_addr);
+	else
+		memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
 
 	/* Generate the P2P Interface Address.  If the discovery and connection
 	 * BSSCFGs need to simultaneously co-exist, then this address must be
@@ -1367,6 +1365,11 @@
 	u16 mgmt_type;
 	u8 action;
 
+	if (e->datalen < sizeof(*rxframe)) {
+		brcmf_dbg(SCAN, "Event data to small. Ignore\n");
+		return 0;
+	}
+
 	ch.chspec = be16_to_cpu(rxframe->chanspec);
 	cfg->d11inf.decchspec(&ch);
 	/* Check if wpa_supplicant has registered for this frame */
@@ -1466,10 +1469,12 @@
 		return 0;
 
 	if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) {
-		if (e->status == BRCMF_E_STATUS_SUCCESS)
+		if (e->status == BRCMF_E_STATUS_SUCCESS) {
 			set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
 				&p2p->status);
-		else {
+			if (!p2p->wait_for_offchan_complete)
+				complete(&p2p->send_af_done);
+		} else {
 			set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
 			/* If there is no ack, we don't need to wait for
 			 * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event
@@ -1520,6 +1525,17 @@
 	p2p->af_sent_channel = le32_to_cpu(af_params->channel);
 	p2p->af_tx_sent_jiffies = jiffies;
 
+	if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status) &&
+	    p2p->af_sent_channel ==
+	    ieee80211_frequency_to_channel(p2p->remain_on_channel.center_freq))
+		p2p->wait_for_offchan_complete = false;
+	else
+		p2p->wait_for_offchan_complete = true;
+
+	brcmf_dbg(TRACE, "Waiting for %s tx completion event\n",
+		  (p2p->wait_for_offchan_complete) ?
+		   "off-channel" : "on-channel");
+
 	timeout = wait_for_completion_timeout(&p2p->send_af_done,
 					msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME));
 
@@ -1864,6 +1880,11 @@
 	brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
 		  e->reason);
 
+	if (e->datalen < sizeof(*rxframe)) {
+		brcmf_dbg(SCAN, "Event data to small. Ignore\n");
+		return 0;
+	}
+
 	ch.chspec = be16_to_cpu(rxframe->chanspec);
 	cfg->d11inf.decchspec(&ch);
 
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
@@ -125,6 +125,7 @@
  * @gon_req_action: about to send go negotiation requets frame.
  * @block_gon_req_tx: drop tx go negotiation requets frame.
  * @p2pdev_dynamically: is p2p device if created by module param or supplicant.
+ * @wait_for_offchan_complete: wait for off-channel tx completion event.
  */
 struct brcmf_p2p_info {
 	struct brcmf_cfg80211_info *cfg;
@@ -146,6 +147,7 @@
 	bool gon_req_action;
 	bool block_gon_req_tx;
 	bool p2pdev_dynamically;
+	bool wait_for_offchan_complete;
 };
 
 s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced);
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
@@ -1394,6 +1394,17 @@
 	return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
 }
 
+static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
+{
+	u32 hdrvalue;
+	u8 ret;
+
+	hdrvalue = *(u32 *)swheader;
+	ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
+
+	return (ret == SDPCM_EVENT_CHANNEL);
+}
+
 static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
 			      struct brcmf_sdio_hdrinfo *rd,
 			      enum brcmf_sdio_frmtype type)
@@ -1754,7 +1765,11 @@
 					   pfirst->len, pfirst->next,
 					   pfirst->prev);
 			skb_unlink(pfirst, &bus->glom);
-			brcmf_rx_frame(bus->sdiodev->dev, pfirst);
+			if (brcmf_sdio_fromevntchan(&dptr[SDPCM_HWHDR_LEN]))
+				brcmf_rx_event(bus->sdiodev->dev, pfirst);
+			else
+				brcmf_rx_frame(bus->sdiodev->dev, pfirst,
+					       false);
 			bus->sdcnt.rxglompkts++;
 		}
 
@@ -2012,6 +2027,7 @@
 					       BRCMF_SDIO_FT_NORMAL)) {
 				rd->len = 0;
 				brcmu_pkt_buf_free_skb(pkt);
+				continue;
 			}
 			bus->sdcnt.rx_readahead_cnt++;
 			if (rd->len != roundup(rd_new.len, 16)) {
@@ -2081,18 +2097,19 @@
 		__skb_trim(pkt, rd->len);
 		skb_pull(pkt, rd->dat_offset);
 
+		if (pkt->len == 0)
+			brcmu_pkt_buf_free_skb(pkt);
+		else if (rd->channel == SDPCM_EVENT_CHANNEL)
+			brcmf_rx_event(bus->sdiodev->dev, pkt);
+		else
+			brcmf_rx_frame(bus->sdiodev->dev, pkt,
+				       false);
+
 		/* prepare the descriptor for the next read */
 		rd->len = rd->len_nxtfrm << 4;
 		rd->len_nxtfrm = 0;
 		/* treat all packet as event if we don't know */
 		rd->channel = SDPCM_EVENT_CHANNEL;
-
-		if (pkt->len == 0) {
-			brcmu_pkt_buf_free_skb(pkt);
-			continue;
-		}
-
-		brcmf_rx_frame(bus->sdiodev->dev, pkt);
 	}
 
 	rxcount = maxframes - rxleft;
@@ -4291,6 +4308,13 @@
 	brcmf_dbg(TRACE, "Enter\n");
 
 	if (bus) {
+		/* Stop watchdog task */
+		if (bus->watchdog_tsk) {
+			send_sig(SIGTERM, bus->watchdog_tsk, 1);
+			kthread_stop(bus->watchdog_tsk);
+			bus->watchdog_tsk = NULL;
+		}
+
 		/* De-register interrupt handler */
 		brcmf_sdiod_intr_unregister(bus->sdiodev);
 
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -144,7 +144,7 @@
 
 	struct usb_device *usbdev;
 	struct device *dev;
-	struct mutex dev_init_lock;
+	struct completion dev_init_done;
 
 	int ctl_in_pipe, ctl_out_pipe;
 	struct urb *ctl_urb; /* URB for control endpoint */
@@ -426,6 +426,7 @@
 			usb_free_urb(req->urb);
 		list_del(q->next);
 	}
+	kfree(reqs);
 	return NULL;
 
 }
@@ -502,7 +503,7 @@
 
 	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
 		skb_put(skb, urb->actual_length);
-		brcmf_rx_frame(devinfo->dev, skb);
+		brcmf_rx_frame(devinfo->dev, skb, true);
 		brcmf_usb_rx_refill(devinfo, req);
 	} else {
 		brcmu_pkt_buf_free_skb(skb);
@@ -669,12 +670,18 @@
 
 static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
 {
+	int i;
+
 	if (devinfo->ctl_urb)
 		usb_kill_urb(devinfo->ctl_urb);
 	if (devinfo->bulk_urb)
 		usb_kill_urb(devinfo->bulk_urb);
-	brcmf_usb_free_q(&devinfo->tx_postq, true);
-	brcmf_usb_free_q(&devinfo->rx_postq, true);
+	if (devinfo->tx_reqs)
+		for (i = 0; i < devinfo->bus_pub.ntxq; i++)
+			usb_kill_urb(devinfo->tx_reqs[i].urb);
+	if (devinfo->rx_reqs)
+		for (i = 0; i < devinfo->bus_pub.nrxq; i++)
+			usb_kill_urb(devinfo->rx_reqs[i].urb);
 }
 
 static void brcmf_usb_down(struct device *dev)
@@ -1226,11 +1233,11 @@
 	if (ret)
 		goto error;
 
-	mutex_unlock(&devinfo->dev_init_lock);
+	complete(&devinfo->dev_init_done);
 	return;
 error:
 	brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
-	mutex_unlock(&devinfo->dev_init_lock);
+	complete(&devinfo->dev_init_done);
 	device_release_driver(dev);
 }
 
@@ -1268,7 +1275,7 @@
 		if (ret)
 			goto fail;
 		/* we are done */
-		mutex_unlock(&devinfo->dev_init_lock);
+		complete(&devinfo->dev_init_done);
 		return 0;
 	}
 	bus->chip = bus_pub->devid;
@@ -1322,11 +1329,10 @@
 
 	devinfo->usbdev = usb;
 	devinfo->dev = &usb->dev;
-	/* Take an init lock, to protect for disconnect while still loading.
+	/* Init completion, to protect for disconnect while still loading.
 	 * Necessary because of the asynchronous firmware load construction
 	 */
-	mutex_init(&devinfo->dev_init_lock);
-	mutex_lock(&devinfo->dev_init_lock);
+	init_completion(&devinfo->dev_init_done);
 
 	usb_set_intfdata(intf, devinfo);
 
@@ -1347,7 +1353,7 @@
 		goto fail;
 	}
 
-	desc = &intf->altsetting[0].desc;
+	desc = &intf->cur_altsetting->desc;
 	if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
 	    (desc->bInterfaceSubClass != 2) ||
 	    (desc->bInterfaceProtocol != 0xff)) {
@@ -1360,7 +1366,7 @@
 
 	num_of_eps = desc->bNumEndpoints;
 	for (ep = 0; ep < num_of_eps; ep++) {
-		endpoint = &intf->altsetting[0].endpoint[ep].desc;
+		endpoint = &intf->cur_altsetting->endpoint[ep].desc;
 		endpoint_num = usb_endpoint_num(endpoint);
 		if (!usb_endpoint_xfer_bulk(endpoint))
 			continue;
@@ -1402,7 +1408,7 @@
 	return 0;
 
 fail:
-	mutex_unlock(&devinfo->dev_init_lock);
+	complete(&devinfo->dev_init_done);
 	kfree(devinfo);
 	usb_set_intfdata(intf, NULL);
 	return ret;
@@ -1417,7 +1423,7 @@
 	devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
 
 	if (devinfo) {
-		mutex_lock(&devinfo->dev_init_lock);
+		wait_for_completion(&devinfo->dev_init_done);
 		/* Make sure that devinfo still exists. Firmware probe routines
 		 * may have released the device and cleared the intfdata.
 		 */
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmfmac/vendor.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmfmac/vendor.c
@@ -35,9 +35,10 @@
 	struct brcmf_if *ifp;
 	const struct brcmf_vndr_dcmd_hdr *cmdhdr = data;
 	struct sk_buff *reply;
-	int ret, payload, ret_len;
+	unsigned int payload, ret_len;
 	void *dcmd_buf = NULL, *wr_pointer;
 	u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
+	int ret;
 
 	if (len < sizeof(*cmdhdr)) {
 		brcmf_err("vendor command too short: %d\n", len);
@@ -65,7 +66,7 @@
 			brcmf_err("oversize return buffer %d\n", ret_len);
 			ret_len = BRCMF_DCMD_MAXLEN;
 		}
-		payload = max(ret_len, len) + 1;
+		payload = max_t(unsigned int, ret_len, len) + 1;
 		dcmd_buf = vzalloc(payload);
 		if (NULL == dcmd_buf)
 			return -ENOMEM;
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmsmac/dma.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmsmac/dma.c
@@ -1079,8 +1079,10 @@
 
 		pa = dma_map_single(di->dmadev, p->data, di->rxbufsize,
 				    DMA_FROM_DEVICE);
-		if (dma_mapping_error(di->dmadev, pa))
+		if (dma_mapping_error(di->dmadev, pa)) {
+			brcmu_pkt_buf_free_skb(p);
 			return false;
+		}
 
 		/* save the free packet pointer */
 		di->rxp[rxout] = p;
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -502,6 +502,7 @@
 	}
 
 	spin_lock_bh(&wl->lock);
+	wl->wlc->vif = vif;
 	wl->mute_tx = false;
 	brcms_c_mute(wl->wlc, false);
 	if (vif->type == NL80211_IFTYPE_STATION)
@@ -519,6 +520,11 @@
 static void
 brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
+	struct brcms_info *wl = hw->priv;
+
+	spin_lock_bh(&wl->lock);
+	wl->wlc->vif = NULL;
+	spin_unlock_bh(&wl->lock);
 }
 
 static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
@@ -818,13 +824,15 @@
 static int
 brcms_ops_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, bool amsdu)
+		    struct ieee80211_ampdu_params *params)
 {
 	struct brcms_info *wl = hw->priv;
 	struct scb *scb = &wl->wlc->pri_scb;
 	int status;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u8 buf_size = params->buf_size;
 
 	if (WARN_ON(scb->magic != SCB_MAGIC))
 		return -EIDRM;
@@ -838,8 +846,8 @@
 		status = brcms_c_aggregatable(wl->wlc, tid);
 		spin_unlock_bh(&wl->lock);
 		if (!status) {
-			brcms_err(wl->wlc->hw->d11core,
-				  "START: tid %d is not agg\'able\n", tid);
+			brcms_dbg_ht(wl->wlc->hw->d11core,
+				     "START: tid %d is not agg\'able\n", tid);
 			return -EINVAL;
 		}
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -935,6 +943,25 @@
 	spin_unlock_bh(&wl->lock);
 }
 
+static int brcms_ops_beacon_set_tim(struct ieee80211_hw *hw,
+				 struct ieee80211_sta *sta, bool set)
+{
+	struct brcms_info *wl = hw->priv;
+	struct sk_buff *beacon = NULL;
+	u16 tim_offset = 0;
+
+	spin_lock_bh(&wl->lock);
+	if (wl->wlc->vif)
+		beacon = ieee80211_beacon_get_tim(hw, wl->wlc->vif,
+						  &tim_offset, NULL);
+	if (beacon)
+		brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset,
+				       wl->wlc->vif->bss_conf.dtim_period);
+	spin_unlock_bh(&wl->lock);
+
+	return 0;
+}
+
 static const struct ieee80211_ops brcms_ops = {
 	.tx = brcms_ops_tx,
 	.start = brcms_ops_start,
@@ -953,6 +980,7 @@
 	.flush = brcms_ops_flush,
 	.get_tsf = brcms_ops_get_tsf,
 	.set_tsf = brcms_ops_set_tsf,
+	.set_tim = brcms_ops_beacon_set_tim,
 };
 
 void brcms_dpc(unsigned long data)
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmsmac/main.h
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmsmac/main.h
@@ -563,6 +563,7 @@
 
 	struct wiphy *wiphy;
 	struct scb pri_scb;
+	struct ieee80211_vif *vif;
 
 	struct sk_buff *beacon;
 	u16 beacon_tim_offset;
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -5090,8 +5090,10 @@
 	pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
 	pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
 
-	if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
+	if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) {
+		kfree(pi->u.pi_lcnphy);
 		return false;
+	}
 
 	if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
 		if (pi_lcn->lcnphy_tempsense_option == 3) {
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -14764,8 +14764,8 @@
 }
 
 static void
-wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *events, u8 *dlys,
-		       u8 len)
+wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, const u8 *events,
+		       const u8 *dlys, u8 len)
 {
 	u32 t1_offset, t2_offset;
 	u8 ctr;
@@ -15240,16 +15240,16 @@
 static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi)
 {
 	u16 currband;
-	s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 };
-	s8 *lna1_gain_db = NULL;
-	s8 *lna1_gain_db_2 = NULL;
-	s8 *lna2_gain_db = NULL;
-	s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 };
-	s8 *tia_gain_db;
-	s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 };
-	s8 *tia_gainbits;
-	u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f };
-	u16 *rfseq_init_gain;
+	static const s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 };
+	const s8 *lna1_gain_db = NULL;
+	const s8 *lna1_gain_db_2 = NULL;
+	const s8 *lna2_gain_db = NULL;
+	static const s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 };
+	const s8 *tia_gain_db;
+	static const s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 };
+	const s8 *tia_gainbits;
+	static const u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f };
+	const u16 *rfseq_init_gain;
 	u16 init_gaincode;
 	u16 clip1hi_gaincode;
 	u16 clip1md_gaincode = 0;
@@ -15310,10 +15310,9 @@
 
 			if ((freq <= 5080) || (freq == 5825)) {
 
-				s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 };
-				s8 lna1A_gain_db_2_rev7[] = {
-					11, 17, 22, 25};
-				s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
+				static const s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 };
+				static const s8 lna1A_gain_db_2_rev7[] = { 11, 17, 22, 25};
+				static const s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
 
 				crsminu_th = 0x3e;
 				lna1_gain_db = lna1A_gain_db_rev7;
@@ -15321,10 +15320,9 @@
 				lna2_gain_db = lna2A_gain_db_rev7;
 			} else if ((freq >= 5500) && (freq <= 5700)) {
 
-				s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 };
-				s8 lna1A_gain_db_2_rev7[] = {
-					12, 18, 22, 26};
-				s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 };
+				static const s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 };
+				static const s8 lna1A_gain_db_2_rev7[] = { 12, 18, 22, 26};
+				static const s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 };
 
 				crsminu_th = 0x45;
 				clip1md_gaincode_B = 0x14;
@@ -15335,10 +15333,9 @@
 				lna2_gain_db = lna2A_gain_db_rev7;
 			} else {
 
-				s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 };
-				s8 lna1A_gain_db_2_rev7[] = {
-					12, 18, 22, 26};
-				s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
+				static const s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 };
+				static const s8 lna1A_gain_db_2_rev7[] = { 12, 18, 22, 26};
+				static const s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
 
 				crsminu_th = 0x41;
 				lna1_gain_db = lna1A_gain_db_rev7;
@@ -15450,65 +15447,65 @@
 		NPHY_RFSEQ_CMD_CLR_HIQ_DIS,
 		NPHY_RFSEQ_CMD_SET_HPF_BW
 	};
-	u8 rfseq_updategainu_dlys[] = { 10, 30, 1 };
-	s8 lna1G_gain_db[] = { 7, 11, 16, 23 };
-	s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 };
-	s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 };
-	s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 };
-	s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 };
-	s8 lna1A_gain_db[] = { 7, 11, 17, 23 };
-	s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 };
-	s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 };
-	s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 };
-	s8 *lna1_gain_db = NULL;
-	s8 lna2G_gain_db[] = { -5, 6, 10, 14 };
-	s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 };
-	s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 };
-	s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 };
-	s8 lna2A_gain_db[] = { -6, 2, 6, 10 };
-	s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 };
-	s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 };
-	s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 };
-	s8 *lna2_gain_db = NULL;
-	s8 tiaG_gain_db[] = {
+	static const u8 rfseq_updategainu_dlys[] = { 10, 30, 1 };
+	static const s8 lna1G_gain_db[] = { 7, 11, 16, 23 };
+	static const s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 };
+	static const s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 };
+	static const s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 };
+	static const s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 };
+	static const s8 lna1A_gain_db[] = { 7, 11, 17, 23 };
+	static const s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 };
+	static const s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 };
+	static const s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 };
+	const s8 *lna1_gain_db = NULL;
+	static const s8 lna2G_gain_db[] = { -5, 6, 10, 14 };
+	static const s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 };
+	static const s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 };
+	static const s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 };
+	static const s8 lna2A_gain_db[] = { -6, 2, 6, 10 };
+	static const s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 };
+	static const s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 };
+	static const s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 };
+	const s8 *lna2_gain_db = NULL;
+	static const s8 tiaG_gain_db[] = {
 		0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A };
-	s8 tiaA_gain_db[] = {
+	static const s8 tiaA_gain_db[] = {
 		0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 };
-	s8 tiaA_gain_db_rev4[] = {
+	static const s8 tiaA_gain_db_rev4[] = {
 		0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
-	s8 tiaA_gain_db_rev5[] = {
+	static const s8 tiaA_gain_db_rev5[] = {
 		0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
-	s8 tiaA_gain_db_rev6[] = {
+	static const s8 tiaA_gain_db_rev6[] = {
 		0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
-	s8 *tia_gain_db;
-	s8 tiaG_gainbits[] = {
+	const s8 *tia_gain_db;
+	static const s8 tiaG_gainbits[] = {
 		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
-	s8 tiaA_gainbits[] = {
+	static const s8 tiaA_gainbits[] = {
 		0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 };
-	s8 tiaA_gainbits_rev4[] = {
+	static const s8 tiaA_gainbits_rev4[] = {
 		0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
-	s8 tiaA_gainbits_rev5[] = {
+	static const s8 tiaA_gainbits_rev5[] = {
 		0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
-	s8 tiaA_gainbits_rev6[] = {
+	static const s8 tiaA_gainbits_rev6[] = {
 		0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
-	s8 *tia_gainbits;
-	s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 };
-	s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 };
-	u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f };
-	u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f };
-	u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f };
-	u16 rfseqG_init_gain_rev5_elna[] = {
+	const s8 *tia_gainbits;
+	static const s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 };
+	static const s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 };
+	static const u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f };
+	static const u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f };
+	static const u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f };
+	static const u16 rfseqG_init_gain_rev5_elna[] = {
 		0x013f, 0x013f, 0x013f, 0x013f };
-	u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f };
-	u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f };
-	u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f };
-	u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f };
-	u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f };
-	u16 rfseqA_init_gain_rev4_elna[] = {
+	static const u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f };
+	static const u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f };
+	static const u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f };
+	static const u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f };
+	static const u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f };
+	static const u16 rfseqA_init_gain_rev4_elna[] = {
 		0x314f, 0x314f, 0x314f, 0x314f };
-	u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f };
-	u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f };
-	u16 *rfseq_init_gain;
+	static const u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f };
+	static const u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f };
+	const u16 *rfseq_init_gain;
 	u16 initG_gaincode = 0x627e;
 	u16 initG_gaincode_rev4 = 0x527e;
 	u16 initG_gaincode_rev5 = 0x427e;
@@ -15538,10 +15535,10 @@
 	u16 clip1mdA_gaincode_rev6 = 0x2084;
 	u16 clip1md_gaincode = 0;
 	u16 clip1loG_gaincode = 0x0074;
-	u16 clip1loG_gaincode_rev5[] = {
+	static const u16 clip1loG_gaincode_rev5[] = {
 		0x0062, 0x0064, 0x006a, 0x106a, 0x106c, 0x1074, 0x107c, 0x207c
 	};
-	u16 clip1loG_gaincode_rev6[] = {
+	static const u16 clip1loG_gaincode_rev6[] = {
 		0x106a, 0x106c, 0x1074, 0x107c, 0x007e, 0x107e, 0x207e, 0x307e
 	};
 	u16 clip1loG_gaincode_rev6_224B0 = 0x1074;
@@ -16066,7 +16063,7 @@
 
 static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
 {
-	u8 rfseq_rx2tx_events[] = {
+	static const u8 rfseq_rx2tx_events[] = {
 		NPHY_RFSEQ_CMD_NOP,
 		NPHY_RFSEQ_CMD_RXG_FBW,
 		NPHY_RFSEQ_CMD_TR_SWITCH,
@@ -16076,7 +16073,7 @@
 		NPHY_RFSEQ_CMD_EXT_PA
 	};
 	u8 rfseq_rx2tx_dlys[] = { 8, 6, 6, 2, 4, 60, 1 };
-	u8 rfseq_tx2rx_events[] = {
+	static const u8 rfseq_tx2rx_events[] = {
 		NPHY_RFSEQ_CMD_NOP,
 		NPHY_RFSEQ_CMD_EXT_PA,
 		NPHY_RFSEQ_CMD_TX_GAIN,
@@ -16085,8 +16082,8 @@
 		NPHY_RFSEQ_CMD_RXG_FBW,
 		NPHY_RFSEQ_CMD_CLR_HIQ_DIS
 	};
-	u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 };
-	u8 rfseq_tx2rx_events_rev3[] = {
+	static const u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 };
+	static const u8 rfseq_tx2rx_events_rev3[] = {
 		NPHY_REV3_RFSEQ_CMD_EXT_PA,
 		NPHY_REV3_RFSEQ_CMD_INT_PA_PU,
 		NPHY_REV3_RFSEQ_CMD_TX_GAIN,
@@ -16096,7 +16093,7 @@
 		NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS,
 		NPHY_REV3_RFSEQ_CMD_END
 	};
-	u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 };
+	static const u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 };
 	u8 rfseq_rx2tx_events_rev3[] = {
 		NPHY_REV3_RFSEQ_CMD_NOP,
 		NPHY_REV3_RFSEQ_CMD_RXG_FBW,
@@ -16110,7 +16107,7 @@
 	};
 	u8 rfseq_rx2tx_dlys_rev3[] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 };
 
-	u8 rfseq_rx2tx_events_rev3_ipa[] = {
+	static const u8 rfseq_rx2tx_events_rev3_ipa[] = {
 		NPHY_REV3_RFSEQ_CMD_NOP,
 		NPHY_REV3_RFSEQ_CMD_RXG_FBW,
 		NPHY_REV3_RFSEQ_CMD_TR_SWITCH,
@@ -16121,15 +16118,15 @@
 		NPHY_REV3_RFSEQ_CMD_INT_PA_PU,
 		NPHY_REV3_RFSEQ_CMD_END
 	};
-	u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
-	u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f };
+	static const u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
+	static const u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f };
 
 	s16 alpha0, alpha1, alpha2;
 	s16 beta0, beta1, beta2;
 	u32 leg_data_weights, ht_data_weights, nss1_data_weights,
 	    stbc_data_weights;
 	u8 chan_freq_range = 0;
-	u16 dac_control = 0x0002;
+	static const u16 dac_control = 0x0002;
 	u16 aux_adc_vmid_rev7_core0[] = { 0x8e, 0x96, 0x96, 0x96 };
 	u16 aux_adc_vmid_rev7_core1[] = { 0x8f, 0x9f, 0x9f, 0x96 };
 	u16 aux_adc_vmid_rev4[] = { 0xa2, 0xb4, 0xb4, 0x89 };
@@ -16139,8 +16136,8 @@
 	u16 aux_adc_gain_rev4[] = { 0x02, 0x02, 0x02, 0x00 };
 	u16 aux_adc_gain_rev3[] = { 0x02, 0x02, 0x02, 0x00 };
 	u16 *aux_adc_gain;
-	u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 };
-	u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 };
+	static const u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 };
+	static const u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 };
 	s32 min_nvar_val = 0x18d;
 	s32 min_nvar_offset_6mbps = 20;
 	u8 pdetrange;
@@ -16151,9 +16148,9 @@
 	u16 rfseq_rx2tx_lpf_h_hpc_rev7 = 0x77;
 	u16 rfseq_tx2rx_lpf_h_hpc_rev7 = 0x77;
 	u16 rfseq_pktgn_lpf_h_hpc_rev7 = 0x77;
-	u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 };
-	u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 };
-	u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 };
+	static const u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 };
+	static const u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 };
+	static const u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 };
 	u16 ipalvlshift_3p3_war_en = 0;
 	u16 rccal_bcap_val, rccal_scap_val;
 	u16 rccal_tx20_11b_bcap = 0;
@@ -24291,13 +24288,13 @@
 	u16 bbmult;
 	u16 tblentry;
 
-	struct nphy_txiqcal_ladder ladder_lo[] = {
+	static const struct nphy_txiqcal_ladder ladder_lo[] = {
 		{3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0},
 		{25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5},
 		{25, 6}, {25, 7}, {35, 7}, {50, 7}, {71, 7}, {100, 7}
 	};
 
-	struct nphy_txiqcal_ladder ladder_iq[] = {
+	static const struct nphy_txiqcal_ladder ladder_iq[] = {
 		{3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0},
 		{25, 0}, {35, 0}, {50, 0}, {71, 0}, {100, 0}, {100, 1},
 		{100, 2}, {100, 3}, {100, 4}, {100, 5}, {100, 6}, {100, 7}
@@ -25773,67 +25770,67 @@
 	u16 cal_gain[2];
 	struct nphy_iqcal_params cal_params[2];
 	u32 tbl_len;
-	void *tbl_ptr;
+	const void *tbl_ptr;
 	bool ladder_updated[2];
 	u8 mphase_cal_lastphase = 0;
 	int bcmerror = 0;
 	bool phyhang_avoid_state = false;
 
-	u16 tbl_tx_iqlo_cal_loft_ladder_20[] = {
+	static const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = {
 		0x0300, 0x0500, 0x0700, 0x0900, 0x0d00, 0x1100, 0x1900, 0x1901,
 		0x1902,
 		0x1903, 0x1904, 0x1905, 0x1906, 0x1907, 0x2407, 0x3207, 0x4607,
 		0x6407
 	};
 
-	u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = {
+	static const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = {
 		0x0200, 0x0300, 0x0600, 0x0900, 0x0d00, 0x1100, 0x1900, 0x2400,
 		0x3200,
 		0x4600, 0x6400, 0x6401, 0x6402, 0x6403, 0x6404, 0x6405, 0x6406,
 		0x6407
 	};
 
-	u16 tbl_tx_iqlo_cal_loft_ladder_40[] = {
+	static const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = {
 		0x0200, 0x0300, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1201,
 		0x1202,
 		0x1203, 0x1204, 0x1205, 0x1206, 0x1207, 0x1907, 0x2307, 0x3207,
 		0x4707
 	};
 
-	u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = {
+	static const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = {
 		0x0100, 0x0200, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1900,
 		0x2300,
 		0x3200, 0x4700, 0x4701, 0x4702, 0x4703, 0x4704, 0x4705, 0x4706,
 		0x4707
 	};
 
-	u16 tbl_tx_iqlo_cal_startcoefs[] = {
+	static const u16 tbl_tx_iqlo_cal_startcoefs[] = {
 		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 		0x0000
 	};
 
-	u16 tbl_tx_iqlo_cal_cmds_fullcal[] = {
+	static const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = {
 		0x8123, 0x8264, 0x8086, 0x8245, 0x8056,
 		0x9123, 0x9264, 0x9086, 0x9245, 0x9056
 	};
 
-	u16 tbl_tx_iqlo_cal_cmds_recal[] = {
+	static const u16 tbl_tx_iqlo_cal_cmds_recal[] = {
 		0x8101, 0x8253, 0x8053, 0x8234, 0x8034,
 		0x9101, 0x9253, 0x9053, 0x9234, 0x9034
 	};
 
-	u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = {
+	static const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = {
 		0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 		0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 		0x0000
 	};
 
-	u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = {
+	static const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = {
 		0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234,
 		0x9434, 0x9334, 0x9084, 0x9267, 0x9056, 0x9234
 	};
 
-	u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = {
+	static const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = {
 		0x8423, 0x8323, 0x8073, 0x8256, 0x8045, 0x8223,
 		0x9423, 0x9323, 0x9073, 0x9256, 0x9045, 0x9223
 	};
--- linux-4.4.0.orig/drivers/net/wireless/brcm80211/brcmsmac/stf.c
+++ linux-4.4.0/drivers/net/wireless/brcm80211/brcmsmac/stf.c
@@ -87,7 +87,7 @@
 brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
 			    u16 chanspec)
 {
-	struct tx_power power;
+	struct tx_power power = { };
 	u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id;
 
 	/* Clear previous settings */
--- linux-4.4.0.orig/drivers/net/wireless/cw1200/cw1200_spi.c
+++ linux-4.4.0/drivers/net/wireless/cw1200/cw1200_spi.c
@@ -446,8 +446,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int cw1200_spi_suspend(struct device *dev)
+static int __maybe_unused cw1200_spi_suspend(struct device *dev)
 {
 	struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev));
 
@@ -460,16 +459,12 @@
 
 static SIMPLE_DEV_PM_OPS(cw1200_pm_ops, cw1200_spi_suspend, NULL);
 
-#endif
-
 static struct spi_driver spi_driver = {
 	.probe		= cw1200_spi_probe,
 	.remove		= cw1200_spi_disconnect,
 	.driver = {
 		.name		= "cw1200_wlan_spi",
-#ifdef CONFIG_PM
-		.pm		= &cw1200_pm_ops,
-#endif
+		.pm		= IS_ENABLED(CONFIG_PM) ? &cw1200_pm_ops : NULL,
 	},
 };
 
--- linux-4.4.0.orig/drivers/net/wireless/cw1200/fwio.c
+++ linux-4.4.0/drivers/net/wireless/cw1200/fwio.c
@@ -323,12 +323,12 @@
 		goto out;
 	}
 
-	priv->hw_type = cw1200_get_hw_type(val32, &major_revision);
-	if (priv->hw_type < 0) {
+	ret = cw1200_get_hw_type(val32, &major_revision);
+	if (ret < 0) {
 		pr_err("Can't deduce hardware type.\n");
-		ret = -ENOTSUPP;
 		goto out;
 	}
+	priv->hw_type = ret;
 
 	/* Set DPLL Reg value, and read back to confirm writes work */
 	ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID,
--- linux-4.4.0.orig/drivers/net/wireless/cw1200/main.c
+++ linux-4.4.0/drivers/net/wireless/cw1200/main.c
@@ -345,6 +345,11 @@
 	mutex_init(&priv->wsm_cmd_mux);
 	mutex_init(&priv->conf_mutex);
 	priv->workqueue = create_singlethread_workqueue("cw1200_wq");
+	if (!priv->workqueue) {
+		ieee80211_free_hw(hw);
+		return NULL;
+	}
+
 	sema_init(&priv->scan.lock, 1);
 	INIT_WORK(&priv->scan.work, cw1200_scan_work);
 	INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
@@ -380,6 +385,7 @@
 				    CW1200_LINK_ID_MAX,
 				    cw1200_skb_dtor,
 				    priv)) {
+		destroy_workqueue(priv->workqueue);
 		ieee80211_free_hw(hw);
 		return NULL;
 	}
@@ -391,6 +397,7 @@
 			for (; i > 0; i--)
 				cw1200_queue_deinit(&priv->tx_queue[i - 1]);
 			cw1200_queue_stats_deinit(&priv->tx_queue_stats);
+			destroy_workqueue(priv->workqueue);
 			ieee80211_free_hw(hw);
 			return NULL;
 		}
--- linux-4.4.0.orig/drivers/net/wireless/cw1200/pm.h
+++ linux-4.4.0/drivers/net/wireless/cw1200/pm.h
@@ -31,13 +31,18 @@
 void cw1200_pm_deinit(struct cw1200_pm_state *pm);
 int cw1200_wow_suspend(struct ieee80211_hw *hw,
 		       struct cfg80211_wowlan *wowlan);
-int cw1200_wow_resume(struct ieee80211_hw *hw);
 int cw1200_can_suspend(struct cw1200_common *priv);
+int cw1200_wow_resume(struct ieee80211_hw *hw);
 void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
 			  unsigned long tmo);
 #else
 static inline void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
-					unsigned long tmo) {
+					unsigned long tmo)
+{
+}
+static inline int cw1200_can_suspend(struct cw1200_common *priv)
+{
+	return 0;
 }
 #endif
 #endif
--- linux-4.4.0.orig/drivers/net/wireless/cw1200/scan.c
+++ linux-4.4.0/drivers/net/wireless/cw1200/scan.c
@@ -78,27 +78,30 @@
 	if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS)
 		return -EINVAL;
 
+	/* will be unlocked in cw1200_scan_work() */
+	down(&priv->scan.lock);
+	mutex_lock(&priv->conf_mutex);
+
 	frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
 		req->ie_len);
-	if (!frame.skb)
+	if (!frame.skb) {
+		mutex_unlock(&priv->conf_mutex);
+		up(&priv->scan.lock);
 		return -ENOMEM;
+	}
 
 	if (req->ie_len)
 		memcpy(skb_put(frame.skb, req->ie_len), req->ie, req->ie_len);
 
-	/* will be unlocked in cw1200_scan_work() */
-	down(&priv->scan.lock);
-	mutex_lock(&priv->conf_mutex);
-
 	ret = wsm_set_template_frame(priv, &frame);
 	if (!ret) {
 		/* Host want to be the probe responder. */
 		ret = wsm_set_probe_responder(priv, true);
 	}
 	if (ret) {
+		dev_kfree_skb(frame.skb);
 		mutex_unlock(&priv->conf_mutex);
 		up(&priv->scan.lock);
-		dev_kfree_skb(frame.skb);
 		return ret;
 	}
 
@@ -120,10 +123,9 @@
 		++priv->scan.n_ssids;
 	}
 
-	mutex_unlock(&priv->conf_mutex);
-
 	if (frame.skb)
 		dev_kfree_skb(frame.skb);
+	mutex_unlock(&priv->conf_mutex);
 	queue_work(priv->workqueue, &priv->scan.work);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/wireless/cw1200/sta.c
+++ linux-4.4.0/drivers/net/wireless/cw1200/sta.c
@@ -2135,9 +2135,7 @@
 
 int cw1200_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, bool amsdu)
+			struct ieee80211_ampdu_params *params)
 {
 	/* Aggregation is implemented fully in firmware,
 	 * including block ack negotiation. Do not allow
--- linux-4.4.0.orig/drivers/net/wireless/cw1200/sta.h
+++ linux-4.4.0/drivers/net/wireless/cw1200/sta.h
@@ -109,9 +109,7 @@
 			     u32 changed);
 int cw1200_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, bool amsdu);
+			struct ieee80211_ampdu_params *params);
 
 void cw1200_suspend_resume(struct cw1200_common *priv,
 			  struct wsm_suspend_resume *arg);
--- linux-4.4.0.orig/drivers/net/wireless/cw1200/wsm.c
+++ linux-4.4.0/drivers/net/wireless/cw1200/wsm.c
@@ -379,7 +379,6 @@
 {
 	int ret;
 	int count;
-	int i;
 
 	count = WSM_GET32(buf);
 	if (WARN_ON(count <= 0))
@@ -395,11 +394,10 @@
 	}
 
 	cw1200_debug_txed_multi(priv, count);
-	for (i = 0; i < count; ++i) {
+	do {
 		ret = wsm_tx_confirm(priv, buf, link_id);
-		if (ret)
-			return ret;
-	}
+	} while (!ret && --count);
+
 	return ret;
 
 underflow:
@@ -1807,16 +1805,18 @@
 {
 	size_t pos = buf->data - buf->begin;
 	size_t size = pos + extra_size;
+	u8 *tmp;
 
 	size = round_up(size, FWLOAD_BLOCK_SIZE);
 
-	buf->begin = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA);
-	if (buf->begin) {
-		buf->data = &buf->begin[pos];
-		buf->end = &buf->begin[size];
-		return 0;
-	} else {
-		buf->end = buf->data = buf->begin;
+	tmp = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA);
+	if (!tmp) {
+		wsm_buf_deinit(buf);
 		return -ENOMEM;
 	}
+
+	buf->begin = tmp;
+	buf->data = &buf->begin[pos];
+	buf->end = &buf->begin[size];
+	return 0;
 }
--- linux-4.4.0.orig/drivers/net/wireless/hostap/hostap_ap.c
+++ linux-4.4.0/drivers/net/wireless/hostap/hostap_ap.c
@@ -2570,7 +2570,7 @@
 		sta->supported_rates[0] = 2;
 	if (sta->tx_supp_rates & WLAN_RATE_2M)
 		sta->supported_rates[1] = 4;
- 	if (sta->tx_supp_rates & WLAN_RATE_5M5)
+	if (sta->tx_supp_rates & WLAN_RATE_5M5)
 		sta->supported_rates[2] = 11;
 	if (sta->tx_supp_rates & WLAN_RATE_11M)
 		sta->supported_rates[3] = 22;
--- linux-4.4.0.orig/drivers/net/wireless/hostap/hostap_hw.c
+++ linux-4.4.0/drivers/net/wireless/hostap/hostap_hw.c
@@ -69,7 +69,7 @@
 module_param_string(essid, essid, sizeof(essid), 0444);
 MODULE_PARM_DESC(essid, "Host AP's ESSID");
 
-static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS };
+static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_INFRA, DEF_INTS };
 module_param_array(iw_mode, int, NULL, 0444);
 MODULE_PARM_DESC(iw_mode, "Initial operation mode");
 
@@ -836,25 +836,30 @@
 	spin_lock_bh(&local->baplock);
 
 	res = hfa384x_setup_bap(dev, BAP0, rid, 0);
-	if (!res)
-		res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+	if (res)
+		goto unlock;
+
+	res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+	if (res)
+		goto unlock;
 
 	if (le16_to_cpu(rec.len) == 0) {
 		/* RID not available */
 		res = -ENODATA;
+		goto unlock;
 	}
 
 	rlen = (le16_to_cpu(rec.len) - 1) * 2;
-	if (!res && exact_len && rlen != len) {
+	if (exact_len && rlen != len) {
 		printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
 		       "rid=0x%04x, len=%d (expected %d)\n",
 		       dev->name, rid, rlen, len);
 		res = -ENODATA;
 	}
 
-	if (!res)
-		res = hfa384x_from_bap(dev, BAP0, buf, len);
+	res = hfa384x_from_bap(dev, BAP0, buf, len);
 
+unlock:
 	spin_unlock_bh(&local->baplock);
 	mutex_unlock(&local->rid_bap_mtx);
 
--- linux-4.4.0.orig/drivers/net/wireless/ipw2x00/ipw2100.c
+++ linux-4.4.0/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -3213,8 +3213,9 @@
 	}
 }
 
-static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
+static void ipw2100_irq_tasklet(unsigned long data)
 {
+	struct ipw2100_priv *priv = (struct ipw2100_priv *)data;
 	struct net_device *dev = priv->net_dev;
 	unsigned long flags;
 	u32 inta, tmp;
@@ -6022,7 +6023,7 @@
 	spin_unlock_irqrestore(&priv->low_lock, flags);
 }
 
-static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
+static void ipw2100_irq_tasklet(unsigned long data);
 
 static const struct net_device_ops ipw2100_netdev_ops = {
 	.ndo_open		= ipw2100_open,
@@ -6151,7 +6152,7 @@
 	INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
 	INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event);
 
-	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+	tasklet_init(&priv->irq_tasklet,
 		     ipw2100_irq_tasklet, (unsigned long)priv);
 
 	/* NOTE:  We do not start the deferred work for status checks yet */
--- linux-4.4.0.orig/drivers/net/wireless/ipw2x00/ipw2200.c
+++ linux-4.4.0/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -1968,8 +1968,9 @@
 	wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
 }
 
-static void ipw_irq_tasklet(struct ipw_priv *priv)
+static void ipw_irq_tasklet(unsigned long data)
 {
+	struct ipw_priv *priv = (struct ipw_priv *)data;
 	u32 inta, inta_mask, handled = 0;
 	unsigned long flags;
 	int rc = 0;
@@ -10705,7 +10706,7 @@
 	INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate);
 #endif				/* CONFIG_IPW2200_QOS */
 
-	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+	tasklet_init(&priv->irq_tasklet,
 		     ipw_irq_tasklet, (unsigned long)priv);
 
 	return ret;
--- linux-4.4.0.orig/drivers/net/wireless/iwlegacy/3945-mac.c
+++ linux-4.4.0/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -1399,8 +1399,9 @@
 }
 
 static void
-il3945_irq_tasklet(struct il_priv *il)
+il3945_irq_tasklet(unsigned long data)
 {
+	struct il_priv *il = (struct il_priv *)data;
 	u32 inta, handled = 0;
 	u32 inta_fh;
 	unsigned long flags;
@@ -3432,7 +3433,7 @@
 	setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il);
 
 	tasklet_init(&il->irq_tasklet,
-		     (void (*)(unsigned long))il3945_irq_tasklet,
+		     il3945_irq_tasklet,
 		     (unsigned long)il);
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/iwlegacy/3945.c
+++ linux-4.4.0/drivers/net/wireless/iwlegacy/3945.c
@@ -1019,12 +1019,13 @@
 	int txq_id;
 
 	/* Tx queues */
-	if (il->txq)
+	if (il->txq) {
 		for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++)
 			if (txq_id == IL39_CMD_QUEUE_NUM)
 				il_cmd_queue_free(il);
 			else
 				il_tx_queue_free(il, txq_id);
+	}
 
 	/* free tx queue structure */
 	il_free_txq_mem(il);
--- linux-4.4.0.orig/drivers/net/wireless/iwlegacy/4965-mac.c
+++ linux-4.4.0/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -4361,8 +4361,9 @@
 }
 
 static void
-il4965_irq_tasklet(struct il_priv *il)
+il4965_irq_tasklet(unsigned long data)
 {
+	struct il_priv *il = (struct il_priv *)data;
 	u32 inta, handled = 0;
 	u32 inta_fh;
 	unsigned long flags;
@@ -5982,12 +5983,14 @@
 
 int
 il4965_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, bool amsdu)
+			struct ieee80211_ampdu_params *params)
 {
 	struct il_priv *il = hw->priv;
 	int ret = -EINVAL;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
 
 	D_HT("A-MPDU action on addr %pM tid %d\n", sta->addr, tid);
 
@@ -6255,7 +6258,7 @@
 	setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il);
 
 	tasklet_init(&il->irq_tasklet,
-		     (void (*)(unsigned long))il4965_irq_tasklet,
+		     il4965_irq_tasklet,
 		     (unsigned long)il);
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/iwlegacy/4965.h
+++ linux-4.4.0/drivers/net/wireless/iwlegacy/4965.h
@@ -182,9 +182,7 @@
 				struct ieee80211_sta *sta, u32 iv32,
 				u16 *phase1key);
 int il4965_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, bool amsdu);
+			    struct ieee80211_ampdu_params *params);
 int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta);
 void
--- linux-4.4.0.orig/drivers/net/wireless/iwlegacy/common.c
+++ linux-4.4.0/drivers/net/wireless/iwlegacy/common.c
@@ -717,7 +717,7 @@
 	u32 gp = _il_rd(il, CSR_EEPROM_GP);
 	int sz;
 	int ret;
-	u16 addr;
+	int addr;
 
 	/* allocate eeprom */
 	sz = il->cfg->eeprom_size;
@@ -4294,8 +4294,8 @@
 	 *    power savings, even without L1.
 	 */
 	if (il->cfg->set_l0s) {
-		pcie_capability_read_word(il->pci_dev, PCI_EXP_LNKCTL, &lctl);
-		if (lctl & PCI_EXP_LNKCTL_ASPM_L1) {
+		ret = pcie_capability_read_word(il->pci_dev, PCI_EXP_LNKCTL, &lctl);
+		if (!ret && (lctl & PCI_EXP_LNKCTL_ASPM_L1)) {
 			/* L1-ASPM enabled; disable(!) L0S  */
 			il_set_bit(il, CSR_GIO_REG,
 				   CSR_GIO_REG_VAL_L0S_ENABLED);
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/dvm/calib.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/dvm/calib.c
@@ -901,7 +901,7 @@
 		/* 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);
+			(s32) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
 
 		if (delta_g < 0)
 			/*
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/dvm/led.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/dvm/led.c
@@ -184,6 +184,9 @@
 
 	priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
 				   wiphy_name(priv->hw->wiphy));
+	if (!priv->led.name)
+		return;
+
 	priv->led.brightness_set = iwl_led_brightness_set;
 	priv->led.blink_set = iwl_led_blink_set;
 	priv->led.max_brightness = 1;
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/dvm/lib.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/dvm/lib.c
@@ -1154,6 +1154,9 @@
 
 	priv->ucode_loaded = false;
 	iwl_trans_stop_device(priv->trans);
+	ret = iwl_trans_start_hw(priv->trans);
+	if (ret)
+		goto out;
 
 	priv->wowlan = true;
 
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -729,12 +729,15 @@
 
 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, bool amsdu)
+				   struct ieee80211_ampdu_params *params)
 {
 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	int ret = -EINVAL;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
+	u8 buf_size = params->buf_size;
 	struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
 
 	IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -70,7 +70,7 @@
 
 /* Highest firmware API version supported */
 #define IWL7260_UCODE_API_MAX	17
-#define IWL7265_UCODE_API_MAX	19
+#define IWL7265_UCODE_API_MAX	17
 #define IWL7265D_UCODE_API_MAX	19
 
 /* Oldest version we won't warn about */
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -73,6 +73,7 @@
 /* NVM offsets (in words) definitions */
 enum wkp_nvm_offsets {
 	/* NVM HW-Section offset (in words) definitions */
+	SUBSYSTEM_ID = 0x0A,
 	HW_ADDR = 0x15,
 
 	/* NVM SW-Section offset (in words) definitions */
@@ -257,13 +258,12 @@
 static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 				struct iwl_nvm_data *data,
 				const __le16 * const nvm_ch_flags,
-				bool lar_supported)
+				bool lar_supported, bool no_wide_in_5ghz)
 {
 	int ch_idx;
 	int n_channels = 0;
 	struct ieee80211_channel *channel;
 	u16 ch_flags;
-	bool is_5ghz;
 	int num_of_ch, num_2ghz_channels;
 	const u8 *nvm_chan;
 
@@ -278,12 +278,20 @@
 	}
 
 	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
+		bool is_5ghz = (ch_idx >= num_2ghz_channels);
+
 		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 
-		if (ch_idx >= num_2ghz_channels &&
-		    !data->sku_cap_band_52GHz_enable)
+		if (is_5ghz && !data->sku_cap_band_52GHz_enable)
 			continue;
 
+		/* workaround to disable wide channels in 5GHz */
+		if (no_wide_in_5ghz && is_5ghz) {
+			ch_flags &= ~(NVM_CHANNEL_40MHZ |
+				     NVM_CHANNEL_80MHZ |
+				     NVM_CHANNEL_160MHZ);
+		}
+
 		if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
 			/*
 			 * Channels might become valid later if lar is
@@ -303,8 +311,8 @@
 		n_channels++;
 
 		channel->hw_value = nvm_chan[ch_idx];
-		channel->band = (ch_idx < num_2ghz_channels) ?
-				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+		channel->band = is_5ghz ?
+				IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
 		channel->center_freq =
 			ieee80211_channel_to_frequency(
 				channel->hw_value, channel->band);
@@ -316,7 +324,6 @@
 		 * is not used in mvm, and is used for backwards compatibility
 		 */
 		channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
-		is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
 
 		/* don't put limitations in case we're using LAR */
 		if (!lar_supported)
@@ -405,7 +412,8 @@
 static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 			    struct iwl_nvm_data *data,
 			    const __le16 *ch_section,
-			    u8 tx_chains, u8 rx_chains, bool lar_supported)
+			    u8 tx_chains, u8 rx_chains, bool lar_supported,
+			    bool no_wide_in_5ghz)
 {
 	int n_channels;
 	int n_used = 0;
@@ -414,12 +422,14 @@
 	if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 		n_channels = iwl_init_channel_map(
 				dev, cfg, data,
-				&ch_section[NVM_CHANNELS], lar_supported);
+				&ch_section[NVM_CHANNELS], lar_supported,
+				no_wide_in_5ghz);
 	else
 		n_channels = iwl_init_channel_map(
 				dev, cfg, data,
 				&ch_section[NVM_CHANNELS_FAMILY_8000],
-				lar_supported);
+				lar_supported,
+				no_wide_in_5ghz);
 
 	sband = &data->bands[IEEE80211_BAND_2GHZ];
 	sband->band = IEEE80211_BAND_2GHZ;
@@ -582,6 +592,39 @@
 
 #define IWL_4165_DEVICE_ID 0x5501
 
+static bool
+iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg,
+			const __le16 *nvm_hw)
+{
+	/*
+	 * Workaround a bug in Indonesia SKUs where the regulatory in
+	 * some 7000-family OTPs erroneously allow wide channels in
+	 * 5GHz.  To check for Indonesia, we take the SKU value from
+	 * bits 1-4 in the subsystem ID and check if it is either 5 or
+	 * 9.  In those cases, we need to force-disable wide channels
+	 * in 5GHz otherwise the FW will throw a sysassert when we try
+	 * to use them.
+	 */
+	if (cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		/*
+		 * Unlike the other sections in the NVM, the hw
+		 * section uses big-endian.
+		 */
+		u16 subsystem_id = be16_to_cpup((const __be16 *)nvm_hw
+						+ SUBSYSTEM_ID);
+		u8 sku = (subsystem_id & 0x1e) >> 1;
+
+		if (sku == 5 || sku == 9) {
+			IWL_DEBUG_EEPROM(dev,
+					 "disabling wide channels in 5GHz (0x%0x %d)\n",
+					 subsystem_id, sku);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 		   const __le16 *nvm_hw, const __le16 *nvm_sw,
@@ -591,6 +634,7 @@
 		   u32 mac_addr0, u32 mac_addr1, u32 hw_id)
 {
 	struct iwl_nvm_data *data;
+	bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw);
 	u32 sku;
 	u32 radio_cfg;
 	u16 lar_config;
@@ -657,7 +701,8 @@
 		iwl_set_hw_address(cfg, data, nvm_hw);
 
 		iwl_init_sbands(dev, cfg, data, nvm_sw,
-				tx_chains, rx_chains, lar_fw_supported);
+				tx_chains, rx_chains, lar_fw_supported,
+				no_wide_in_5ghz);
 	} else {
 		u16 lar_offset = data->nvm_version < 0xE39 ?
 				 NVM_LAR_OFFSET_FAMILY_8000_OLD :
@@ -673,7 +718,8 @@
 
 		iwl_init_sbands(dev, cfg, data, regulatory,
 				tx_chains, rx_chains,
-				lar_fw_supported && data->lar_enabled);
+				lar_fw_supported && data->lar_enabled,
+				no_wide_in_5ghz);
 	}
 
 	data->calib_version = 255;
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -106,7 +106,7 @@
 				    sizeof(tx_ant_cmd), &tx_ant_cmd);
 }
 
-static void iwl_free_fw_paging(struct iwl_mvm *mvm)
+void iwl_free_fw_paging(struct iwl_mvm *mvm)
 {
 	int i;
 
@@ -126,6 +126,8 @@
 			     get_order(mvm->fw_paging_db[i].fw_paging_size));
 	}
 	kfree(mvm->trans->paging_download_buf);
+	mvm->trans->paging_download_buf = NULL;
+
 	memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db));
 }
 
@@ -754,7 +756,7 @@
 		mvm->nvm_data->bands[0].n_channels = 1;
 		mvm->nvm_data->bands[0].n_bitrates = 1;
 		mvm->nvm_data->bands[0].bitrates =
-			(void *)mvm->nvm_data->channels + 1;
+			(void *)(mvm->nvm_data->channels + 1);
 		mvm->nvm_data->bands[0].bitrates->hw_value = 10;
 	}
 
@@ -933,7 +935,8 @@
 	}
 
 	mvm->fw_dbg_conf = conf_id;
-	return ret;
+
+	return 0;
 }
 
 static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/led.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/led.c
@@ -109,6 +109,9 @@
 
 	mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",
 				   wiphy_name(mvm->hw->wiphy));
+	if (!mvm->led.name)
+		return -ENOMEM;
+
 	mvm->led.brightness_set = iwl_led_brightness_set;
 	mvm->led.max_brightness = 1;
 
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -322,8 +322,12 @@
 		goto out;
 	}
 
-	if (changed)
-		*changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE);
+	if (changed) {
+		u32 status = le32_to_cpu(resp->status);
+
+		*changed = (status == MCC_RESP_NEW_CHAN_PROFILE ||
+			    status == MCC_RESP_ILLEGAL);
+	}
 
 	regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg,
 				      __le32_to_cpu(resp->n_channels),
@@ -737,6 +741,21 @@
 		     !ieee80211_is_action(hdr->frame_control)))
 		sta = NULL;
 
+	/* If there is no sta, and it's not offchannel - send through AP */
+	if (info->control.vif->type == NL80211_IFTYPE_STATION &&
+	    info->hw_queue != IWL_MVM_OFFCHANNEL_QUEUE && !sta) {
+		struct iwl_mvm_vif *mvmvif =
+			iwl_mvm_vif_from_mac80211(info->control.vif);
+		u8 ap_sta_id = READ_ONCE(mvmvif->ap_sta_id);
+
+		if (ap_sta_id < IWL_MVM_STATION_COUNT) {
+			/* mac80211 holds rcu read lock */
+			sta = rcu_dereference(mvm->fw_id_to_mac_id[ap_sta_id]);
+			if (IS_ERR_OR_NULL(sta))
+				goto drop;
+		}
+	}
+
 	if (sta) {
 		if (iwl_mvm_defer_tx(mvm, sta, skb))
 			return;
@@ -826,13 +845,16 @@
 
 static int iwl_mvm_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, bool amsdu)
+				    struct ieee80211_ampdu_params *params)
 {
 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 	int ret;
 	bool tx_agg_ref = false;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
+	u8 buf_size = params->buf_size;
 
 	IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
 		     sta->addr, tid, action);
@@ -1557,6 +1579,8 @@
 	/* the fw is stopped, the aux sta is dead: clean up driver state */
 	iwl_mvm_del_aux_sta(mvm);
 
+	iwl_free_fw_paging(mvm);
+
 	/*
 	 * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete()
 	 * won't be called in this case).
@@ -1901,6 +1925,11 @@
 	struct iwl_mvm_mc_iter_data *data = _data;
 	struct iwl_mvm *mvm = data->mvm;
 	struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd;
+	struct iwl_host_cmd hcmd = {
+		.id = MCAST_FILTER_CMD,
+		.flags = CMD_ASYNC,
+		.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+	};
 	int ret, len;
 
 	/* if we don't have free ports, mcast frames will be dropped */
@@ -1915,7 +1944,10 @@
 	memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
 	len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4);
 
-	ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd);
+	hcmd.len[0] = len;
+	hcmd.data[0] = cmd;
+
+	ret = iwl_mvm_send_cmd(mvm, &hcmd);
 	if (ret)
 		IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);
 }
@@ -3990,8 +4022,8 @@
 	if (idx != 0)
 		return -ENOENT;
 
-	if (fw_has_capa(&mvm->fw->ucode_capa,
-			IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
+	if (!fw_has_capa(&mvm->fw->ucode_capa,
+			 IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
 		return -ENOENT;
 
 	mutex_lock(&mvm->mutex);
@@ -4037,10 +4069,6 @@
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 
-	if (fw_has_capa(&mvm->fw->ucode_capa,
-			IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
-		return;
-
 	/* if beacon filtering isn't on mac80211 does it anyway */
 	if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))
 		return;
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -1190,6 +1190,9 @@
 void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
 					      struct iwl_rx_cmd_buffer *rxb);
 
+/* Paging */
+void iwl_free_fw_paging(struct iwl_mvm *mvm);
+
 /* MVM debugfs */
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir);
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -667,9 +667,8 @@
 
 	n_channels =  __le32_to_cpu(mcc_resp->n_channels);
 	IWL_DEBUG_LAR(mvm,
-		      "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n",
-		      status, mcc, mcc >> 8, mcc & 0xff,
-		      !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels);
+		      "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') n_chans: %d\n",
+		      status, mcc, mcc >> 8, mcc & 0xff, n_channels);
 
 	resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32);
 	resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -909,6 +909,7 @@
 	reprobe = container_of(wk, struct iwl_mvm_reprobe, work);
 	if (device_reprobe(reprobe->dev))
 		dev_err(reprobe->dev, "reprobe failed!\n");
+	put_device(reprobe->dev);
 	kfree(reprobe);
 	module_put(THIS_MODULE);
 }
@@ -991,7 +992,7 @@
 			module_put(THIS_MODULE);
 			return;
 		}
-		reprobe->dev = mvm->trans->dev;
+		reprobe->dev = get_device(mvm->trans->dev);
 		INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
 		schedule_work(&reprobe->work);
 	} else if (mvm->cur_ucode == IWL_UCODE_REGULAR) {
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -1267,6 +1267,10 @@
 		return -EBUSY;
 	}
 
+	/* we don't support "match all" in the firmware */
+	if (!req->n_match_sets)
+		return -EOPNOTSUPP;
+
 	ret = iwl_mvm_check_running_scans(mvm, type);
 	if (ret)
 		return ret;
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/sf.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/sf.c
@@ -215,7 +215,7 @@
 			     enum iwl_sf_state new_state)
 {
 	struct iwl_sf_cfg_cmd sf_cmd = {
-		.state = cpu_to_le32(SF_FULL_ON),
+		.state = cpu_to_le32(new_state),
 	};
 	struct ieee80211_sta *sta;
 	int ret = 0;
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -421,6 +421,15 @@
 		return -1;
 	}
 
+	/*
+	 * Increase the pending frames counter, so that later when a reply comes
+	 * in and the counter is decreased - we don't start getting negative
+	 * values.
+	 * Note that we don't need to make sure it isn't agg'd, since we're
+	 * TXing non-sta
+	 */
+	atomic_inc(&mvm->pending_frames[sta_id]);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -384,6 +384,7 @@
 	{IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)},
 	{IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x095A, 0x5C10, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)},
@@ -401,10 +402,10 @@
 	{IWL_PCI_DEVICE(0x095A, 0x900A, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)},
-	{IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x095B, 0x9210, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095B, 0x9200, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)},
-	{IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x095B, 0x9310, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x5020, iwl7265_2n_cfg)},
 	{IWL_PCI_DEVICE(0x095A, 0x502A, iwl7265_2n_cfg)},
@@ -474,48 +475,64 @@
 MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
 
 #ifdef CONFIG_ACPI
-#define SPL_METHOD		"SPLC"
-#define SPL_DOMAINTYPE_MODULE	BIT(0)
-#define SPL_DOMAINTYPE_WIFI	BIT(1)
-#define SPL_DOMAINTYPE_WIGIG	BIT(2)
-#define SPL_DOMAINTYPE_RFEM	BIT(3)
+#define ACPI_SPLC_METHOD	"SPLC"
+#define ACPI_SPLC_DOMAIN_WIFI	(0x07)
 
-static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx)
+static u64 splc_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splc)
 {
-	union acpi_object *limits, *domain_type, *power_limit;
+	union acpi_object *data_pkg, *dflt_pwr_limit;
+	int i;
 
-	if (splx->type != ACPI_TYPE_PACKAGE ||
-	    splx->package.count != 2 ||
-	    splx->package.elements[0].type != ACPI_TYPE_INTEGER ||
-	    splx->package.elements[0].integer.value != 0) {
-		IWL_ERR(trans, "Unsupported splx structure\n");
+	/* We need at least two elements, one for the revision and one
+	 * for the data itself.  Also check that the revision is
+	 * supported (currently only revision 0).
+	*/
+	if (splc->type != ACPI_TYPE_PACKAGE ||
+	    splc->package.count < 2 ||
+	    splc->package.elements[0].type != ACPI_TYPE_INTEGER ||
+	    splc->package.elements[0].integer.value != 0) {
+		IWL_DEBUG_INFO(trans,
+			       "Unsupported structure returned by the SPLC method.  Ignoring.\n");
 		return 0;
 	}
 
-	limits = &splx->package.elements[1];
-	if (limits->type != ACPI_TYPE_PACKAGE ||
-	    limits->package.count < 2 ||
-	    limits->package.elements[0].type != ACPI_TYPE_INTEGER ||
-	    limits->package.elements[1].type != ACPI_TYPE_INTEGER) {
-		IWL_ERR(trans, "Invalid limits element\n");
-		return 0;
+	/* loop through all the packages to find the one for WiFi */
+	for (i = 1; i < splc->package.count; i++) {
+		union acpi_object *domain;
+
+		data_pkg = &splc->package.elements[i];
+
+		/* Skip anything that is not a package with the right
+		 * amount of elements (i.e. at least 2 integers).
+		 */
+		if (data_pkg->type != ACPI_TYPE_PACKAGE ||
+		    data_pkg->package.count < 2 ||
+		    data_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
+		    data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
+			continue;
+
+		domain = &data_pkg->package.elements[0];
+		if (domain->integer.value == ACPI_SPLC_DOMAIN_WIFI)
+			break;
+
+		data_pkg = NULL;
 	}
 
-	domain_type = &limits->package.elements[0];
-	power_limit = &limits->package.elements[1];
-	if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) {
-		IWL_DEBUG_INFO(trans, "WiFi power is not limited\n");
+	if (!data_pkg) {
+		IWL_DEBUG_INFO(trans,
+			       "No element for the WiFi domain returned by the SPLC method.\n");
 		return 0;
 	}
 
-	return power_limit->integer.value;
+	dflt_pwr_limit = &data_pkg->package.elements[1];
+	return dflt_pwr_limit->integer.value;
 }
 
 static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)
 {
 	acpi_handle pxsx_handle;
 	acpi_handle handle;
-	struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_buffer splc = {ACPI_ALLOCATE_BUFFER, NULL};
 	acpi_status status;
 
 	pxsx_handle = ACPI_HANDLE(&pdev->dev);
@@ -526,23 +543,24 @@
 	}
 
 	/* Get the method's handle */
-	status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle);
+	status = acpi_get_handle(pxsx_handle, (acpi_string)ACPI_SPLC_METHOD,
+				 &handle);
 	if (ACPI_FAILURE(status)) {
-		IWL_DEBUG_INFO(trans, "SPL method not found\n");
+		IWL_DEBUG_INFO(trans, "SPLC method not found\n");
 		return;
 	}
 
 	/* Call SPLC with no arguments */
-	status = acpi_evaluate_object(handle, NULL, NULL, &splx);
+	status = acpi_evaluate_object(handle, NULL, NULL, &splc);
 	if (ACPI_FAILURE(status)) {
 		IWL_ERR(trans, "SPLC invocation failed (0x%x)\n", status);
 		return;
 	}
 
-	trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer);
+	trans->dflt_pwr_limit = splc_get_pwr_limit(trans, splc.pointer);
 	IWL_DEBUG_INFO(trans, "Default power limit set to %lld\n",
 		       trans->dflt_pwr_limit);
-	kfree(splx.pointer);
+	kfree(splc.pointer);
 }
 
 #else /* CONFIG_ACPI */
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -708,11 +708,17 @@
 		if (err)
 			return err;
 	}
-	if (!rba->alloc_wq)
+	if (!rba->alloc_wq) {
 		rba->alloc_wq = alloc_workqueue("rb_allocator",
 						WQ_HIGHPRI | WQ_UNBOUND, 1);
+		if (!rba->alloc_wq)
+			return -ENOMEM;
+	}
+
 	INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work);
 
+	cancel_work_sync(&rba->rx_alloc);
+
 	spin_lock(&rba->lock);
 	atomic_set(&rba->req_pending, 0);
 	atomic_set(&rba->req_ready, 0);
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * 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
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -729,8 +731,8 @@
 	 */
 	val = iwl_read_prph(trans, PREG_AUX_BUS_WPROT_0);
 	if (val & (BIT(1) | BIT(17))) {
-		IWL_INFO(trans,
-			 "can't access the RSA semaphore it is write protected\n");
+		IWL_DEBUG_INFO(trans,
+			       "can't access the RSA semaphore it is write protected\n");
 		return 0;
 	}
 
@@ -924,9 +926,16 @@
 	if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) {
 		iwl_write_prph(trans, le32_to_cpu(dest->base_reg),
 			       trans_pcie->fw_mon_phys >> dest->base_shift);
-		iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
-			       (trans_pcie->fw_mon_phys +
-				trans_pcie->fw_mon_size) >> dest->end_shift);
+		if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+			iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
+				       (trans_pcie->fw_mon_phys +
+					trans_pcie->fw_mon_size - 256) >>
+						dest->end_shift);
+		else
+			iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
+				       (trans_pcie->fw_mon_phys +
+					trans_pcie->fw_mon_size) >>
+						dest->end_shift);
 	}
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ linux-4.4.0/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -583,7 +583,14 @@
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 	struct iwl_txq *txq = &trans_pcie->txq[txq_id];
-	struct iwl_queue *q = &txq->q;
+	struct iwl_queue *q;
+
+	if (!txq) {
+		IWL_ERR(trans, "Trying to free a queue that wasn't allocated?\n");
+		return;
+	}
+
+	q = &txq->q;
 
 	spin_lock_bh(&txq->lock);
 	while (q->write_ptr != q->read_ptr) {
@@ -1508,9 +1515,9 @@
 
 	/* start the TFD with the scratchbuf */
 	scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE);
-	memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size);
+	memcpy(&txq->scratchbufs[idx], &out_cmd->hdr, scratch_size);
 	iwl_pcie_txq_build_tfd(trans, txq,
-			       iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr),
+			       iwl_pcie_get_scratchbuf_dma(txq, idx),
 			       scratch_size, true);
 
 	/* map first command fragment, if any remains */
--- linux-4.4.0.orig/drivers/net/wireless/libertas/cfg.c
+++ linux-4.4.0/drivers/net/wireless/libertas/cfg.c
@@ -272,6 +272,10 @@
 	int hw, ap, ap_max = ie[1];
 	u8 hw_rate;
 
+	if (ap_max > MAX_RATES) {
+		lbs_deb_assoc("invalid rates\n");
+		return tlv;
+	}
 	/* Advance past IE header */
 	ie += 2;
 
@@ -1783,6 +1787,9 @@
 	struct cmd_ds_802_11_ad_hoc_join cmd;
 	u8 preamble = RADIO_PREAMBLE_SHORT;
 	int ret = 0;
+	int hw, i;
+	u8 rates_max;
+	u8 *rates;
 
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
@@ -1843,9 +1850,14 @@
 	if (!rates_eid) {
 		lbs_add_rates(cmd.bss.rates);
 	} else {
-		int hw, i;
-		u8 rates_max = rates_eid[1];
-		u8 *rates = cmd.bss.rates;
+		rates_max = rates_eid[1];
+		if (rates_max > MAX_RATES) {
+			lbs_deb_join("invalid rates");
+			rcu_read_unlock();
+			ret = -EINVAL;
+			goto out;
+		}
+		rates = cmd.bss.rates;
 		for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
 			u8 hw_rate = lbs_rates[hw].bitrate / 5;
 			for (i = 0; i < rates_max; i++) {
--- linux-4.4.0.orig/drivers/net/wireless/libertas/if_sdio.c
+++ linux-4.4.0/drivers/net/wireless/libertas/if_sdio.c
@@ -1229,6 +1229,10 @@
 
 	spin_lock_init(&card->lock);
 	card->workqueue = create_workqueue("libertas_sdio");
+	if (unlikely(!card->workqueue)) {
+		ret = -ENOMEM;
+		goto err_queue;
+	}
 	INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
 	init_waitqueue_head(&card->pwron_waitq);
 
@@ -1282,6 +1286,7 @@
 	lbs_remove_card(priv);
 free:
 	destroy_workqueue(card->workqueue);
+err_queue:
 	while (card->packets) {
 		packet = card->packets;
 		card->packets = card->packets->next;
--- linux-4.4.0.orig/drivers/net/wireless/libertas/if_usb.c
+++ linux-4.4.0/drivers/net/wireless/libertas/if_usb.c
@@ -49,7 +49,8 @@
 	{ MODEL_8388, "libertas/usb8388_v5.bin", NULL },
 	{ MODEL_8388, "libertas/usb8388.bin", NULL },
 	{ MODEL_8388, "usb8388.bin", NULL },
-	{ MODEL_8682, "libertas/usb8682.bin", NULL }
+	{ MODEL_8682, "libertas/usb8682.bin", NULL },
+	{ 0, NULL, NULL }
 };
 
 static struct usb_device_id if_usb_table[] = {
--- linux-4.4.0.orig/drivers/net/wireless/libertas_tf/cmd.c
+++ linux-4.4.0/drivers/net/wireless/libertas_tf/cmd.c
@@ -69,7 +69,7 @@
 			break;
 		}
 
-	for (ch = priv->range.start; ch < priv->range.end; ch++)
+	for (ch = range->start; ch < range->end; ch++)
 		priv->channels[CHAN_TO_IDX(ch)].flags = 0;
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/mac80211_hwsim.c
+++ linux-4.4.0/drivers/net/wireless/mac80211_hwsim.c
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/ktime.h>
 #include <net/genetlink.h>
+#include <linux/nospec.h>
 #include "mac80211_hwsim.h"
 
 #define WARN_QUEUE 100
@@ -699,16 +700,21 @@
 	    val != PS_MANUAL_POLL)
 		return -EINVAL;
 
-	old_ps = data->ps;
-	data->ps = val;
-
-	local_bh_disable();
 	if (val == PS_MANUAL_POLL) {
+		if (data->ps != PS_ENABLED)
+			return -EINVAL;
+		local_bh_disable();
 		ieee80211_iterate_active_interfaces_atomic(
 			data->hw, IEEE80211_IFACE_ITER_NORMAL,
 			hwsim_send_ps_poll, data);
-		data->ps_poll_pending = true;
-	} else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
+		local_bh_enable();
+		return 0;
+	}
+	old_ps = data->ps;
+	data->ps = val;
+
+	local_bh_disable();
+	if (old_ps == PS_DISABLED && val != PS_DISABLED) {
 		ieee80211_iterate_active_interfaces_atomic(
 			data->hw, IEEE80211_IFACE_ITER_NORMAL,
 			hwsim_send_nullfunc_ps, data);
@@ -1817,10 +1823,12 @@
 
 static int mac80211_hwsim_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, bool amsdu)
+				       struct ieee80211_ampdu_params *params)
 {
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+
 	switch (action) {
 	case IEEE80211_AMPDU_TX_START:
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -2446,9 +2454,6 @@
 				IEEE80211_VHT_CAP_SHORT_GI_80 |
 				IEEE80211_VHT_CAP_SHORT_GI_160 |
 				IEEE80211_VHT_CAP_TXSTBC |
-				IEEE80211_VHT_CAP_RXSTBC_1 |
-				IEEE80211_VHT_CAP_RXSTBC_2 |
-				IEEE80211_VHT_CAP_RXSTBC_3 |
 				IEEE80211_VHT_CAP_RXSTBC_4 |
 				IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
 			sband->vht_cap.vht_mcs.rx_mcs_map =
@@ -2511,6 +2516,10 @@
 	if (param->no_vif)
 		ieee80211_hw_set(hw, NO_AUTO_VIF);
 
+	tasklet_hrtimer_init(&data->beacon_timer,
+			     mac80211_hwsim_beacon,
+			     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+
 	err = ieee80211_register_hw(hw);
 	if (err < 0) {
 		printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
@@ -2535,16 +2544,11 @@
 				    data->debugfs,
 				    data, &hwsim_simulate_radar);
 
-	tasklet_hrtimer_init(&data->beacon_timer,
-			     mac80211_hwsim_beacon,
-			     CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
-
 	spin_lock_bh(&hwsim_radio_lock);
 	list_add_tail(&data->list, &hwsim_radios);
 	spin_unlock_bh(&hwsim_radio_lock);
 
-	if (idx > 0)
-		hwsim_mcast_new_radio(idx, info, param);
+	hwsim_mcast_new_radio(idx, info, param);
 
 	return idx;
 
@@ -2723,6 +2727,7 @@
 	if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
 	    !info->attrs[HWSIM_ATTR_FLAGS] ||
 	    !info->attrs[HWSIM_ATTR_COOKIE] ||
+	    !info->attrs[HWSIM_ATTR_SIGNAL] ||
 	    !info->attrs[HWSIM_ATTR_TX_INFO])
 		goto out;
 
@@ -2881,6 +2886,8 @@
 static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
 {
 	struct hwsim_new_radio_params param = { 0 };
+	const char *hwname = NULL;
+	int ret;
 
 	param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
 	param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
@@ -2894,8 +2901,14 @@
 	if (info->attrs[HWSIM_ATTR_NO_VIF])
 		param.no_vif = true;
 
-	if (info->attrs[HWSIM_ATTR_RADIO_NAME])
-		param.hwname = nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]);
+	if (info->attrs[HWSIM_ATTR_RADIO_NAME]) {
+		hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]),
+				  nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]),
+				  GFP_KERNEL);
+		if (!hwname)
+			return -ENOMEM;
+		param.hwname = hwname;
+	}
 
 	if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
 		param.use_chanctx = true;
@@ -2909,12 +2922,19 @@
 	if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) {
 		u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]);
 
-		if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom))
+		if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) {
+			kfree(hwname);
 			return -EINVAL;
+		}
+
+		idx = array_index_nospec(idx,
+					 ARRAY_SIZE(hwsim_world_regdom_custom));
 		param.regd = hwsim_world_regdom_custom[idx];
 	}
 
-	return mac80211_hwsim_new_radio(info, &param);
+	ret = mac80211_hwsim_new_radio(info, &param);
+	kfree(hwname);
+	return ret;
 }
 
 static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
@@ -2923,11 +2943,15 @@
 	s64 idx = -1;
 	const char *hwname = NULL;
 
-	if (info->attrs[HWSIM_ATTR_RADIO_ID])
+	if (info->attrs[HWSIM_ATTR_RADIO_ID]) {
 		idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
-	else if (info->attrs[HWSIM_ATTR_RADIO_NAME])
-		hwname = (void *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]);
-	else
+	} else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) {
+		hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]),
+				  nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]),
+				  GFP_KERNEL);
+		if (!hwname)
+			return -ENOMEM;
+	} else
 		return -EINVAL;
 
 	spin_lock_bh(&hwsim_radio_lock);
@@ -2936,7 +2960,8 @@
 			if (data->idx != idx)
 				continue;
 		} else {
-			if (strcmp(hwname, wiphy_name(data->hw->wiphy)))
+			if (!hwname ||
+			    strcmp(hwname, wiphy_name(data->hw->wiphy)))
 				continue;
 		}
 
@@ -2944,10 +2969,12 @@
 		spin_unlock_bh(&hwsim_radio_lock);
 		mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
 					 info);
+		kfree(hwname);
 		return 0;
 	}
 	spin_unlock_bh(&hwsim_radio_lock);
 
+	kfree(hwname);
 	return -ENODEV;
 }
 
@@ -2979,7 +3006,7 @@
 			goto out_err;
 		}
 
-		genlmsg_reply(skb, info);
+		res = genlmsg_reply(skb, info);
 		break;
 	}
 
@@ -3172,16 +3199,16 @@
 	if (err)
 		return err;
 
+	err = hwsim_init_netlink();
+	if (err)
+		goto out_unregister_driver;
+
 	hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
 	if (IS_ERR(hwsim_class)) {
 		err = PTR_ERR(hwsim_class);
-		goto out_unregister_driver;
+		goto out_exit_netlink;
 	}
 
-	err = hwsim_init_netlink();
-	if (err < 0)
-		goto out_unregister_driver;
-
 	for (i = 0; i < radios; i++) {
 		struct hwsim_new_radio_params param = { 0 };
 
@@ -3287,6 +3314,8 @@
 	free_netdev(hwsim_mon);
 out_free_radios:
 	mac80211_hwsim_free();
+out_exit_netlink:
+	hwsim_exit_netlink();
 out_unregister_driver:
 	platform_driver_unregister(&mac80211_hwsim_driver);
 	return err;
--- linux-4.4.0.orig/drivers/net/wireless/mediatek/mt7601u/dma.c
+++ linux-4.4.0/drivers/net/wireless/mediatek/mt7601u/dma.c
@@ -160,8 +160,7 @@
 
 	if (new_p) {
 		/* we have one extra ref from the allocator */
-		__free_pages(e->p, MT_RX_ORDER);
-
+		put_page(e->p);
 		e->p = new_p;
 	}
 }
@@ -193,10 +192,23 @@
 	struct mt7601u_rx_queue *q = &dev->rx_q;
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev->rx_lock, flags);
+	/* do no schedule rx tasklet if urb has been unlinked
+	 * or the device has been removed
+	 */
+	switch (urb->status) {
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+	case -ENOENT:
+		return;
+	default:
+		dev_err_ratelimited(dev->dev, "rx urb failed: %d\n",
+				    urb->status);
+		/* fall through */
+	case 0:
+		break;
+	}
 
-	if (mt7601u_urb_has_error(urb))
-		dev_err(dev->dev, "Error: RX urb failed:%d\n", urb->status);
+	spin_lock_irqsave(&dev->rx_lock, flags);
 	if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch"))
 		goto out;
 
@@ -228,14 +240,25 @@
 	struct sk_buff *skb;
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev->tx_lock, flags);
+	switch (urb->status) {
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+	case -ENOENT:
+		return;
+	default:
+		dev_err_ratelimited(dev->dev, "tx urb failed: %d\n",
+				    urb->status);
+		/* fall through */
+	case 0:
+		break;
+	}
 
-	if (mt7601u_urb_has_error(urb))
-		dev_err(dev->dev, "Error: TX urb failed:%d\n", urb->status);
+	spin_lock_irqsave(&dev->tx_lock, flags);
 	if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch"))
 		goto out;
 
 	skb = q->e[q->start].skb;
+	q->e[q->start].skb = NULL;
 	trace_mt_tx_dma_done(dev, skb);
 
 	__skb_queue_tail(&dev->tx_skb_done, skb);
@@ -294,7 +317,6 @@
 	}
 
 	e = &q->e[q->end];
-	e->skb = skb;
 	usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len,
 			  mt7601u_complete_tx, q);
 	ret = usb_submit_urb(e->urb, GFP_ATOMIC);
@@ -312,6 +334,7 @@
 
 	q->end = (q->end + 1) % q->entries;
 	q->used++;
+	e->skb = skb;
 
 	if (q->used >= q->entries)
 		ieee80211_stop_queue(dev->hw, skb_get_queue_mapping(skb));
@@ -363,19 +386,9 @@
 static void mt7601u_kill_rx(struct mt7601u_dev *dev)
 {
 	int i;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->rx_lock, flags);
-
-	for (i = 0; i < dev->rx_q.entries; i++) {
-		int next = dev->rx_q.end;
 
-		spin_unlock_irqrestore(&dev->rx_lock, flags);
-		usb_poison_urb(dev->rx_q.e[next].urb);
-		spin_lock_irqsave(&dev->rx_lock, flags);
-	}
-
-	spin_unlock_irqrestore(&dev->rx_lock, flags);
+	for (i = 0; i < dev->rx_q.entries; i++)
+		usb_poison_urb(dev->rx_q.e[i].urb);
 }
 
 static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev,
@@ -445,10 +458,10 @@
 {
 	int i;
 
-	WARN_ON(q->used);
-
 	for (i = 0; i < q->entries; i++)  {
 		usb_poison_urb(q->e[i].urb);
+		if (q->e[i].skb)
+			mt7601u_tx_status(q->dev, q->e[i].skb);
 		usb_free_urb(q->e[i].urb);
 	}
 }
--- linux-4.4.0.orig/drivers/net/wireless/mediatek/mt7601u/eeprom.h
+++ linux-4.4.0/drivers/net/wireless/mediatek/mt7601u/eeprom.h
@@ -17,7 +17,7 @@
 
 struct mt7601u_dev;
 
-#define MT7601U_EE_MAX_VER			0x0c
+#define MT7601U_EE_MAX_VER			0x0d
 #define MT7601U_EEPROM_SIZE			256
 
 #define MT7601U_DEFAULT_TX_POWER		6
--- linux-4.4.0.orig/drivers/net/wireless/mediatek/mt7601u/main.c
+++ linux-4.4.0/drivers/net/wireless/mediatek/mt7601u/main.c
@@ -334,11 +334,13 @@
 
 static int
 mt76_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,
-		  bool amsdu)
+		  struct ieee80211_ampdu_params *params)
 {
 	struct mt7601u_dev *dev = hw->priv;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
 	struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
 
 	WARN_ON(msta->wcid.idx > GROUP_WCID(0));
--- linux-4.4.0.orig/drivers/net/wireless/mediatek/mt7601u/mcu.c
+++ linux-4.4.0/drivers/net/wireless/mediatek/mt7601u/mcu.c
@@ -66,8 +66,10 @@
 	WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */
 
 	skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
-	skb_reserve(skb, MT_DMA_HDR_LEN);
-	memcpy(skb_put(skb, len), data, len);
+	if (skb) {
+		skb_reserve(skb, MT_DMA_HDR_LEN);
+		memcpy(skb_put(skb, len), data, len);
+	}
 
 	return skb;
 }
@@ -170,6 +172,8 @@
 	};
 
 	skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg));
+	if (!skb)
+		return -ENOMEM;
 	return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5);
 }
 
@@ -205,6 +209,8 @@
 	};
 
 	skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg));
+	if (!skb)
+		return -ENOMEM;
 	return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true);
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/mediatek/mt7601u/phy.c
+++ linux-4.4.0/drivers/net/wireless/mediatek/mt7601u/phy.c
@@ -219,7 +219,7 @@
 
 	do {
 		val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION);
-		if (val && ~val)
+		if (val && val != 0xff)
 			break;
 	} while (--i);
 
--- linux-4.4.0.orig/drivers/net/wireless/mediatek/mt7601u/tx.c
+++ linux-4.4.0/drivers/net/wireless/mediatek/mt7601u/tx.c
@@ -117,9 +117,9 @@
 	info->status.rates[0].idx = -1;
 	info->flags |= IEEE80211_TX_STAT_ACK;
 
-	spin_lock(&dev->mac_lock);
+	spin_lock_bh(&dev->mac_lock);
 	ieee80211_tx_status(dev->hw, skb);
-	spin_unlock(&dev->mac_lock);
+	spin_unlock_bh(&dev->mac_lock);
 }
 
 static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb)
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/11n_aggr.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -101,13 +101,6 @@
 {
 	struct txpd *local_tx_pd;
 	struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
-	unsigned int pad;
-	int headroom = (priv->adapter->iface_type ==
-			MWIFIEX_USB) ? 0 : INTF_HEADER_LEN;
-
-	pad = ((void *)skb->data - sizeof(*local_tx_pd) -
-		headroom - NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1);
-	skb_push(skb, pad);
 
 	skb_push(skb, sizeof(*local_tx_pd));
 
@@ -121,12 +114,10 @@
 	local_tx_pd->bss_num = priv->bss_num;
 	local_tx_pd->bss_type = priv->bss_type;
 	/* Always zero as the data is followed by struct txpd */
-	local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) +
-						 pad);
+	local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
 	local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
 	local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
-						 sizeof(*local_tx_pd) -
-						 pad);
+						 sizeof(*local_tx_pd));
 
 	if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT)
 		local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET;
@@ -190,7 +181,11 @@
 				       ra_list_flags);
 		return -1;
 	}
-	skb_reserve(skb_aggr, MWIFIEX_MIN_DATA_HEADER_LEN);
+
+	/* skb_aggr->data already 64 byte align, just reserve bus interface
+	 * header and txpd.
+	 */
+	skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
 	tx_info_aggr =  MWIFIEX_SKB_TXCB(skb_aggr);
 
 	memset(tx_info_aggr, 0, sizeof(*tx_info_aggr));
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/Makefile
+++ linux-4.4.0/drivers/net/wireless/mwifiex/Makefile
@@ -42,6 +42,7 @@
 mwifiex-y += ethtool.o
 mwifiex-y += 11h.o
 mwifiex-y += tdls.o
+mwifiex-y += vendor.o
 mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_MWIFIEX) += mwifiex.o
 
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/cfg80211.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/cfg80211.c
@@ -365,11 +365,20 @@
 	struct mwifiex_power_cfg power_cfg;
 	int dbm = MBM_TO_DBM(mbm);
 
-	if (type == NL80211_TX_POWER_FIXED) {
+	switch (type) {
+	case NL80211_TX_POWER_FIXED:
 		power_cfg.is_power_auto = 0;
+		power_cfg.is_power_fixed = 1;
 		power_cfg.power_level = dbm;
-	} else {
+		break;
+	case NL80211_TX_POWER_LIMITED:
+		power_cfg.is_power_auto = 0;
+		power_cfg.is_power_fixed = 0;
+		power_cfg.power_level = dbm;
+		break;
+	case NL80211_TX_POWER_AUTOMATIC:
 		power_cfg.is_power_auto = 1;
+		break;
 	}
 
 	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
@@ -1056,6 +1065,12 @@
 	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 	enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype;
 
+	if (priv->scan_request) {
+		mwifiex_dbg(priv->adapter, ERROR,
+			    "change virtual interface: scan in process\n");
+		return -EBUSY;
+	}
+
 	switch (curr_iftype) {
 	case NL80211_IFTYPE_ADHOC:
 		switch (type) {
@@ -1150,6 +1165,12 @@
 			priv->adapter->curr_iface_comb.p2p_intf--;
 			priv->adapter->curr_iface_comb.sta_intf++;
 			dev->ieee80211_ptr->iftype = type;
+			if (mwifiex_deinit_priv_params(priv))
+				return -1;
+			if (mwifiex_init_new_priv_params(priv, dev, type))
+				return -1;
+			if (mwifiex_sta_init_cmd(priv, false, false))
+				return -1;
 			break;
 		case NL80211_IFTYPE_ADHOC:
 			if (mwifiex_cfg80211_deinit_p2p(priv))
@@ -1372,7 +1393,8 @@
 			      int idx, u8 *mac, struct station_info *sinfo)
 {
 	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
-	static struct mwifiex_sta_node *node;
+	struct mwifiex_sta_node *node;
+	int i;
 
 	if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
 	    priv->media_connected && idx == 0) {
@@ -1382,13 +1404,10 @@
 		mwifiex_send_cmd(priv, HOST_CMD_APCMD_STA_LIST,
 				 HostCmd_ACT_GEN_GET, 0, NULL, true);
 
-		if (node && (&node->list == &priv->sta_list)) {
-			node = NULL;
-			return -ENOENT;
-		}
-
-		node = list_prepare_entry(node, &priv->sta_list, list);
-		list_for_each_entry_continue(node, &priv->sta_list, list) {
+		i = 0;
+		list_for_each_entry(node, &priv->sta_list, list) {
+			if (i++ != idx)
+				continue;
 			ether_addr_copy(mac, node->mac_addr);
 			return mwifiex_dump_station_info(priv, node, sinfo);
 		}
@@ -2144,8 +2163,9 @@
 			is_scanning_required = 1;
 		} else {
 			mwifiex_dbg(priv->adapter, MSG,
-				    "info: trying to associate to '%s' bssid %pM\n",
-				    (char *)req_ssid.ssid, bss->bssid);
+				    "info: trying to associate to '%.*s' bssid %pM\n",
+				    req_ssid.ssid_len, (char *)req_ssid.ssid,
+				    bss->bssid);
 			memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN);
 			break;
 		}
@@ -2202,8 +2222,8 @@
 	}
 
 	mwifiex_dbg(adapter, INFO,
-		    "info: Trying to associate to %s and bssid %pM\n",
-		    (char *)sme->ssid, sme->bssid);
+		    "info: Trying to associate to %.*s and bssid %pM\n",
+		    (int)sme->ssid_len, (char *)sme->ssid, sme->bssid);
 
 	ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
 				     priv->bss_mode, sme->channel, sme, 0);
@@ -2333,8 +2353,8 @@
 	}
 
 	mwifiex_dbg(priv->adapter, MSG,
-		    "info: trying to join to %s and bssid %pM\n",
-		    (char *)params->ssid, params->bssid);
+		    "info: trying to join to %.*s and bssid %pM\n",
+		    params->ssid_len, (char *)params->ssid, params->bssid);
 
 	mwifiex_set_ibss_params(priv, params);
 
@@ -2838,8 +2858,10 @@
 
 	mwifiex_stop_net_dev_queue(priv->netdev, adapter);
 
-	skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
+	skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) {
+		skb_unlink(skb, &priv->bypass_txq);
 		mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
+	}
 
 	if (netif_carrier_ok(priv->netdev))
 		netif_carrier_off(priv->netdev);
@@ -3739,7 +3761,7 @@
 	if (adapter->config_bands & BAND_A)
 		n_channels_a = mwifiex_band_5ghz.n_channels;
 
-	adapter->num_in_chan_stats = max_t(u32, n_channels_bg, n_channels_a);
+	adapter->num_in_chan_stats = n_channels_bg + n_channels_a;
 	adapter->chan_stats = vmalloc(sizeof(*adapter->chan_stats) *
 				      adapter->num_in_chan_stats);
 
@@ -3802,6 +3824,10 @@
 	wiphy->cipher_suites = mwifiex_cipher_suites;
 	wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
 
+	if (adapter->region_code)
+		wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
+					   REGULATORY_COUNTRY_IE_IGNORE;
+
 	ether_addr_copy(wiphy->perm_addr, adapter->perm_addr);
 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 	wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
@@ -3838,6 +3864,8 @@
 	if (adapter->fw_api_ver == MWIFIEX_FW_V15)
 		wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
 
+	marvell_set_vendor_commands(wiphy);
+
 	/* Reserve space for mwifiex specific private data for BSS */
 	wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
 
@@ -3862,11 +3890,15 @@
 			    "driver hint alpha2: %2.2s\n", reg_alpha2);
 		regulatory_hint(wiphy, reg_alpha2);
 	} else {
-		country_code = mwifiex_11d_code_2_region(adapter->region_code);
-		if (country_code)
-			mwifiex_dbg(adapter, WARN,
-				    "ignoring F/W country code %2.2s\n",
-				    country_code);
+		if (adapter->region_code == 0x00) {
+			mwifiex_dbg(adapter, WARN, "Ignore world regulatory domain\n");
+		} else {
+			country_code =
+				mwifiex_11d_code_2_region(adapter->region_code);
+			if (country_code &&
+			    regulatory_hint(wiphy, country_code))
+				mwifiex_dbg(priv->adapter, ERROR, "regulatory_hint() failed\n");
+		}
 	}
 
 	mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/cfp.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/cfp.c
@@ -66,8 +66,8 @@
 					0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
 					0x60, 0x6c, 0 };
 
-u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
-						0x32, 0x40, 0x41, 0xff };
+u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x00, 0x10, 0x20, 0x30,
+						0x31, 0x32, 0x40, 0x41, 0x50 };
 
 static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
 
@@ -168,7 +168,7 @@
 static struct region_code_mapping region_code_mapping_t[] = {
 	{ 0x10, "US " }, /* US FCC */
 	{ 0x20, "CA " }, /* IC Canada */
-	{ 0x30, "EU " }, /* ETSI */
+	{ 0x30, "FR " }, /* France */
 	{ 0x31, "ES " }, /* Spain */
 	{ 0x32, "FR " }, /* France */
 	{ 0x40, "JP " }, /* Japan */
@@ -533,5 +533,8 @@
 		rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ?
 			      rx_rate - 1 : rx_rate;
 
+	if (rate_index >= MWIFIEX_MAX_AC_RX_RATES)
+		rate_index = MWIFIEX_MAX_AC_RX_RATES - 1;
+
 	return rate_index;
 }
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/cmdevt.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/cmdevt.c
@@ -1637,9 +1637,9 @@
 		if (adapter->region_code == region_code_index[i])
 			break;
 
-	/* If it's unidentified region code, use the default (USA) */
+	/* If it's unidentified region code, use the default (world) */
 	if (i >= MWIFIEX_MAX_REGION_CODE) {
-		adapter->region_code = 0x10;
+		adapter->region_code = 0x00;
 		mwifiex_dbg(adapter, WARN,
 			    "cmd: unknown region code, use default (USA)\n");
 	}
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/debugfs.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/debugfs.c
@@ -115,7 +115,8 @@
 	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
 		p += sprintf(p, "multicast_count=\"%d\"\n",
 			     netdev_mc_count(netdev));
-		p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
+		p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len,
+			     info.ssid.ssid);
 		p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
 		p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
 		p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
@@ -294,15 +295,13 @@
 		     "total samples = %d\n",
 		     atomic_read(&phist_data->num_samples));
 
-	p += sprintf(p, "rx rates (in Mbps): 0=1M   1=2M");
-	p += sprintf(p, "2=5.5M  3=11M   4=6M   5=9M  6=12M\n");
-	p += sprintf(p, "7=18M  8=24M  9=36M  10=48M  11=54M");
-	p += sprintf(p, "12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");
+	p += sprintf(p,
+		     "rx rates (in Mbps): 0=1M   1=2M 2=5.5M  3=11M   4=6M   5=9M  6=12M\n"
+		     "7=18M  8=24M  9=36M  10=48M  11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");
 
 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
-		p += sprintf(p, "44-53=MCS0-9(VHT:BW20)");
-		p += sprintf(p, "54-63=MCS0-9(VHT:BW40)");
-		p += sprintf(p, "64-73=MCS0-9(VHT:BW80)\n\n");
+		p += sprintf(p,
+			     "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n");
 	} else {
 		p += sprintf(p, "\n");
 	}
@@ -331,7 +330,7 @@
 	for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) {
 		value = atomic_read(&phist_data->noise_flr[i]);
 		if (value)
-			p += sprintf(p, "noise_flr[-%02ddBm] = %d\n",
+			p += sprintf(p, "noise_flr[%02ddBm] = %d\n",
 				(int)(i-128), value);
 	}
 	for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) {
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/fw.h
+++ linux-4.4.0/drivers/net/wireless/mwifiex/fw.h
@@ -185,6 +185,7 @@
 #define TLV_TYPE_CHANNEL_STATS      (PROPRIETARY_TLV_BASE_ID + 198)
 #define TLV_BTCOEX_WL_AGGR_WINSIZE  (PROPRIETARY_TLV_BASE_ID + 202)
 #define TLV_BTCOEX_WL_SCANTIME      (PROPRIETARY_TLV_BASE_ID + 203)
+#define TLV_TYPE_LED_CONTROL        (PROPRIETARY_TLV_BASE_ID + 205)
 #define TLV_TYPE_BSS_MODE           (PROPRIETARY_TLV_BASE_ID + 206)
 
 #define MWIFIEX_TX_DATA_BUF_SIZE_2K        2048
@@ -329,6 +330,7 @@
 #define HostCmd_CMD_802_11_AD_HOC_JOIN                0x002c
 #define HostCmd_CMD_802_11_AD_HOC_STOP                0x0040
 #define HostCmd_CMD_802_11_MAC_ADDRESS                0x004D
+#define HostCmd_CMD_802_11_LED_CONTROL			0X004E
 #define HostCmd_CMD_802_11D_DOMAIN_INFO               0x005b
 #define HostCmd_CMD_802_11_KEY_MATERIAL               0x005e
 #define HostCmd_CMD_802_11_BG_SCAN_QUERY              0x006c
@@ -848,7 +850,7 @@
 struct mwifiex_aes_param {
 	u8 pn[WPA_PN_SIZE];
 	__le16 key_len;
-	u8 key[WLAN_KEY_LEN_CCMP];
+	u8 key[WLAN_KEY_LEN_CCMP_256];
 } __packed;
 
 struct mwifiex_wapi_param {
@@ -1080,6 +1082,16 @@
 	u8 oper_mode;
 } __packed;
 
+struct mwifiex_led_param {
+	__le16 mode;
+	__le16 on;
+} __packed;
+
+struct mwifiex_ie_types_led_param {
+	struct mwifiex_ie_types_header header;
+	struct mwifiex_led_param led_cfg;
+} __packed;
+
 struct host_cmd_ds_802_11_ad_hoc_start {
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 bss_mode;
@@ -1092,9 +1104,15 @@
 	u8 data_rate[HOSTCMD_SUPPORTED_RATES];
 } __packed;
 
-struct host_cmd_ds_802_11_ad_hoc_result {
+struct host_cmd_ds_802_11_ad_hoc_start_result {
 	u8 pad[3];
 	u8 bssid[ETH_ALEN];
+	u8 pad2[2];
+	u8 result;
+} __packed;
+
+struct host_cmd_ds_802_11_ad_hoc_join_result {
+	u8 result;
 } __packed;
 
 struct adhoc_bss_desc {
@@ -1197,6 +1215,11 @@
 	} params;
 } __packed;
 
+struct host_cmd_ds_802_11_led_control {
+	__le16 action;
+	__le16 num_led;
+} __packed;
+
 enum SNMP_MIB_INDEX {
 	OP_RATE_SET_I = 1,
 	DTIM_PERIOD_I = 3,
@@ -1206,6 +1229,7 @@
 	FRAG_THRESH_I = 8,
 	DOT11D_I = 9,
 	DOT11H_I = 10,
+	TURBO_MODE_I = 39,
 };
 
 enum mwifiex_assocmd_failurepoint {
@@ -1589,9 +1613,10 @@
 struct ieee_types_vendor_header {
 	u8 element_id;
 	u8 len;
-	u8 oui[4];	/* 0~2: oui, 3: oui_type */
-	u8 oui_subtype;
-	u8 version;
+	struct {
+		u8 oui[3];
+		u8 oui_type;
+	} __packed oui;
 } __packed;
 
 struct ieee_types_wmm_parameter {
@@ -1605,6 +1630,9 @@
 	 *   Version     [1]
 	 */
 	struct ieee_types_vendor_header vend_hdr;
+	u8 oui_subtype;
+	u8 version;
+
 	u8 qos_info_bitmap;
 	u8 reserved;
 	struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS];
@@ -1622,6 +1650,8 @@
 	 *   Version     [1]
 	 */
 	struct ieee_types_vendor_header vend_hdr;
+	u8 oui_subtype;
+	u8 version;
 
 	u8 qos_info_bitmap;
 } __packed;
@@ -2124,7 +2154,8 @@
 		struct host_cmd_ds_802_11_associate_rsp associate_rsp;
 		struct host_cmd_ds_802_11_deauthenticate deauth;
 		struct host_cmd_ds_802_11_ad_hoc_start adhoc_start;
-		struct host_cmd_ds_802_11_ad_hoc_result adhoc_result;
+		struct host_cmd_ds_802_11_ad_hoc_start_result start_result;
+		struct host_cmd_ds_802_11_ad_hoc_join_result join_result;
 		struct host_cmd_ds_802_11_ad_hoc_join adhoc_join;
 		struct host_cmd_ds_802_11d_domain_info domain_info;
 		struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp;
@@ -2163,6 +2194,7 @@
 		struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg;
 		struct host_cmd_ds_multi_chan_policy mc_policy;
 		struct host_cmd_ds_robust_coex coex;
+		struct host_cmd_ds_802_11_led_control led_cfg;
 	} params;
 } __packed;
 
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/ie.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/ie.c
@@ -140,7 +140,7 @@
 	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
 		return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
 					HostCmd_ACT_GEN_SET,
-					UAP_CUSTOM_IE_I, ie_list, false);
+					UAP_CUSTOM_IE_I, ie_list, true);
 
 	return 0;
 }
@@ -240,6 +240,9 @@
 		}
 
 		vs_ie = (struct ieee_types_header *)vendor_ie;
+		if (le16_to_cpu(ie->ie_length) + vs_ie->len + 2 >
+			IEEE_MAX_IE_SIZE)
+			return -EINVAL;
 		memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length),
 		       vs_ie, vs_ie->len + 2);
 		le16_add_cpu(&ie->ie_length, vs_ie->len + 2);
@@ -328,6 +331,8 @@
 	struct ieee80211_vendor_ie *vendorhdr;
 	u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
 	int left_len, parsed_len = 0;
+	unsigned int token_len;
+	int err = 0;
 
 	if (!info->tail || !info->tail_len)
 		return 0;
@@ -343,6 +348,12 @@
 	 */
 	while (left_len > sizeof(struct ieee_types_header)) {
 		hdr = (void *)(info->tail + parsed_len);
+		token_len = hdr->len + sizeof(struct ieee_types_header);
+		if (token_len > left_len) {
+			err = -EINVAL;
+			goto out;
+		}
+
 		switch (hdr->element_id) {
 		case WLAN_EID_SSID:
 		case WLAN_EID_SUPP_RATES:
@@ -356,13 +367,16 @@
 		case WLAN_EID_VENDOR_SPECIFIC:
 			break;
 		default:
-			memcpy(gen_ie->ie_buffer + ie_len, hdr,
-			       hdr->len + sizeof(struct ieee_types_header));
-			ie_len += hdr->len + sizeof(struct ieee_types_header);
+			if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
+				err = -EINVAL;
+				goto out;
+			}
+			memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len);
+			ie_len += token_len;
 			break;
 		}
-		left_len -= hdr->len + sizeof(struct ieee_types_header);
-		parsed_len += hdr->len + sizeof(struct ieee_types_header);
+		left_len -= token_len;
+		parsed_len += token_len;
 	}
 
 	/* parse only WPA vendor IE from tail, WMM IE is configured by
@@ -372,15 +386,17 @@
 						    WLAN_OUI_TYPE_MICROSOFT_WPA,
 						    info->tail, info->tail_len);
 	if (vendorhdr) {
-		memcpy(gen_ie->ie_buffer + ie_len, vendorhdr,
-		       vendorhdr->len + sizeof(struct ieee_types_header));
-		ie_len += vendorhdr->len + sizeof(struct ieee_types_header);
+		token_len = vendorhdr->len + sizeof(struct ieee_types_header);
+		if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
+			err = -EINVAL;
+			goto out;
+		}
+		memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len);
+		ie_len += token_len;
 	}
 
-	if (!ie_len) {
-		kfree(gen_ie);
-		return 0;
-	}
+	if (!ie_len)
+		goto out;
 
 	gen_ie->ie_index = cpu_to_le16(gen_idx);
 	gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
@@ -390,13 +406,15 @@
 
 	if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL,
 					 NULL, NULL)) {
-		kfree(gen_ie);
-		return -1;
+		err = -EINVAL;
+		goto out;
 	}
 
 	priv->gen_idx = gen_idx;
+
+ out:
 	kfree(gen_ie);
-	return 0;
+	return err;
 }
 
 /* This function parses different IEs-head & tail IEs, beacon IEs,
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/ioctl.h
+++ linux-4.4.0/drivers/net/wireless/mwifiex/ioctl.h
@@ -256,6 +256,7 @@
 
 struct mwifiex_power_cfg {
 	u32 is_power_auto;
+	u32 is_power_fixed;
 	u32 power_level;
 };
 
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/join.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/join.c
@@ -661,9 +661,8 @@
 	priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
 				   sizeof(priv->assoc_rsp_buf));
 
-	memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
-
 	assoc_rsp->a_id = cpu_to_le16(aid);
+	memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
 
 	if (status_code) {
 		priv->adapter->dbg.num_cmd_assoc_failure++;
@@ -857,6 +856,8 @@
 
 	memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN);
 
+	if (req_ssid->ssid_len > IEEE80211_MAX_SSID_LEN)
+		req_ssid->ssid_len = IEEE80211_MAX_SSID_LEN;
 	memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len);
 
 	mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n",
@@ -1247,20 +1248,26 @@
 {
 	int ret = 0;
 	struct mwifiex_adapter *adapter = priv->adapter;
-	struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result;
+	struct host_cmd_ds_802_11_ad_hoc_start_result *start_result =
+				&resp->params.start_result;
+	struct host_cmd_ds_802_11_ad_hoc_join_result *join_result =
+				&resp->params.join_result;
 	struct mwifiex_bssdescriptor *bss_desc;
-	u16 reason_code;
+	u16 cmd = le16_to_cpu(resp->command);
+	u8 result;
 
-	adhoc_result = &resp->params.adhoc_result;
+	if (cmd == HostCmd_CMD_802_11_AD_HOC_START)
+		result = start_result->result;
+	else
+		result = join_result->result;
 
 	bss_desc = priv->attempted_bss_desc;
 
 	/* Join result code 0 --> SUCCESS */
-	reason_code = le16_to_cpu(resp->result);
-	if (reason_code) {
+	if (result) {
 		mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n");
 		if (priv->media_connected)
-			mwifiex_reset_connect_state(priv, reason_code);
+			mwifiex_reset_connect_state(priv, result);
 
 		memset(&priv->curr_bss_params.bss_descriptor,
 		       0x00, sizeof(struct mwifiex_bssdescriptor));
@@ -1278,7 +1285,7 @@
 
 		/* Update the created network descriptor with the new BSSID */
 		memcpy(bss_desc->mac_address,
-		       adhoc_result->bssid, ETH_ALEN);
+		       start_result->bssid, ETH_ALEN);
 
 		priv->adhoc_state = ADHOC_STARTED;
 	} else {
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/main.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/main.c
@@ -674,8 +674,10 @@
 static int
 mwifiex_open(struct net_device *dev)
 {
-	netif_carrier_off(dev);
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 
+	netif_carrier_off(dev);
+	mwifiex_set_led(priv->adapter, MWIFIEX_LED_ON);
 	return 0;
 }
 
@@ -695,6 +697,7 @@
 		priv->scan_aborting = true;
 	}
 
+	mwifiex_set_led(priv->adapter, MWIFIEX_LED_OFF);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/main.h
+++ linux-4.4.0/drivers/net/wireless/mwifiex/main.h
@@ -84,7 +84,7 @@
 
 #define MWIFIEX_KEY_BUFFER_SIZE			16
 #define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10
-#define MWIFIEX_MAX_REGION_CODE         7
+#define MWIFIEX_MAX_REGION_CODE         9
 
 #define DEFAULT_BCN_AVG_FACTOR          8
 #define DEFAULT_DATA_AVG_FACTOR         8
@@ -108,6 +108,7 @@
 
 #define MWIFIEX_MAX_TOTAL_SCAN_TIME	(MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
 
+#define WPA_GTK_OUI_OFFSET				2
 #define RSN_GTK_OUI_OFFSET				2
 
 #define MWIFIEX_OUI_NOT_PRESENT			0
@@ -115,6 +116,10 @@
 
 #define PKT_TYPE_MGMT	0xE5
 
+#define MWIFIEX_LED_ON		1
+#define MWIFIEX_LED_OFF		0
+#define MWIFIEX_LED_MAX		3
+
 /*
  * Do not check for data_received for USB, as data_received
  * is handled in mwifiex_usb_recv for USB
@@ -667,6 +672,7 @@
 	struct mwifiex_ds_mem_rw mem_rw;
 	struct sk_buff_head bypass_txq;
 	struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX];
+	bool is_edge_gateway;
 };
 
 
@@ -994,6 +1000,8 @@
 	u8 active_scan_triggered;
 	bool usb_mc_status;
 	bool usb_mc_setup;
+	u8 *cfg_data;
+	int cfg_len;
 };
 
 void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
@@ -1375,6 +1383,7 @@
 				struct cmd_ctrl_node *cmd_queued);
 int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
 		      struct cfg80211_ssid *req_ssid);
+int mwifiex_set_led(struct mwifiex_adapter *adapter, int on);
 int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type);
 int mwifiex_enable_hs(struct mwifiex_adapter *adapter);
 int mwifiex_disable_auto_ds(struct mwifiex_private *priv);
@@ -1569,6 +1578,8 @@
 				      struct sk_buff *event_skb);
 void mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter);
 
+void marvell_set_vendor_commands(struct wiphy *wiphy);
+
 #ifdef CONFIG_DEBUG_FS
 void mwifiex_debugfs_init(void);
 void mwifiex_debugfs_remove(void);
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/pcie.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/pcie.c
@@ -17,6 +17,7 @@
  * this warranty disclaimer.
  */
 
+#include <linux/dmi.h>
 #include <linux/firmware.h>
 
 #include "decl.h"
@@ -189,6 +190,8 @@
 					const struct pci_device_id *ent)
 {
 	struct pcie_service_card *card;
+	struct mwifiex_private *priv;
+	struct pci_dev *pdev_host;
 
 	pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
 		 pdev->vendor, pdev->device, pdev->revision);
@@ -216,6 +219,14 @@
 		return -1;
 	}
 
+	priv = mwifiex_get_priv(card->adapter, MWIFIEX_BSS_ROLE_STA);
+	pdev_host = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, 0x1028, 0x0720, NULL);
+	if (!pdev_host)
+		pdev_host = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, 0x1028, 0x0733, NULL);
+	if (pdev_host) {
+		priv->is_edge_gateway = true;
+		pci_dev_put(pdev_host);
+	}
 	return 0;
 }
 
@@ -577,8 +588,11 @@
 		skb_put(skb, MAX_EVENT_SIZE);
 
 		if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
-					   PCI_DMA_FROMDEVICE))
+					   PCI_DMA_FROMDEVICE)) {
+			kfree_skb(skb);
+			kfree(card->evtbd_ring_vbase);
 			return -1;
+		}
 
 		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
 
@@ -918,8 +932,10 @@
 	}
 	skb_put(skb, MWIFIEX_UPLD_SIZE);
 	if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
-				   PCI_DMA_FROMDEVICE))
+				   PCI_DMA_FROMDEVICE)) {
+		kfree_skb(skb);
 		return -1;
+	}
 
 	card->cmdrsp_buf = skb;
 
@@ -947,6 +963,7 @@
 	if (card && card->cmd_buf) {
 		mwifiex_unmap_pci_memory(adapter, card->cmd_buf,
 					 PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(card->cmd_buf);
 	}
 	return 0;
 }
@@ -1513,6 +1530,11 @@
 		return -1;
 
 	card->cmd_buf = skb;
+	/*
+	 * Need to keep a reference, since core driver might free up this
+	 * buffer before we've unmapped it.
+	 */
+	skb_get(skb);
 
 	/* To send a command, the driver will:
 		1. Write the 64bit physical address of the data buffer to
@@ -1610,6 +1632,7 @@
 	if (card->cmd_buf) {
 		mwifiex_unmap_pci_memory(adapter, card->cmd_buf,
 					 PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(card->cmd_buf);
 		card->cmd_buf = NULL;
 	}
 
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/pcie.h
+++ linux-4.4.0/drivers/net/wireless/mwifiex/pcie.h
@@ -210,17 +210,17 @@
 	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
 	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
 	.tx_rdptr = 0xC1A4,
-	.tx_wrptr = 0xC1A8,
-	.rx_rdptr = 0xC1A8,
+	.tx_wrptr = 0xC174,
+	.rx_rdptr = 0xC174,
 	.rx_wrptr = 0xC1A4,
 	.evt_rdptr = PCIE_SCRATCH_10_REG,
 	.evt_wrptr = PCIE_SCRATCH_11_REG,
 	.drv_rdy = PCIE_SCRATCH_12_REG,
 	.tx_start_ptr = 16,
 	.tx_mask = 0x0FFF0000,
-	.tx_wrap_mask = 0x01FF0000,
+	.tx_wrap_mask = 0x1FFF0000,
 	.rx_mask = 0x00000FFF,
-	.rx_wrap_mask = 0x000001FF,
+	.rx_wrap_mask = 0x00001FFF,
 	.tx_rollover_ind = BIT(28),
 	.rx_rollover_ind = BIT(12),
 	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND,
@@ -342,6 +342,7 @@
 			return 1;
 		break;
 	case PCIE_DEVICE_ID_MARVELL_88W8897:
+	case PCIE_DEVICE_ID_MARVELL_88W8997:
 		if (((card->txbd_wrptr & reg->tx_mask) ==
 		     (rdptr & reg->tx_mask)) &&
 		    ((card->txbd_wrptr & reg->tx_rollover_ind) ==
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/scan.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/scan.c
@@ -151,7 +151,8 @@
 	if (((bss_desc->bcn_wpa_ie) &&
 	     ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id ==
 	      WLAN_EID_VENDOR_SPECIFIC))) {
-		iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
+		iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data +
+					    WPA_GTK_OUI_OFFSET);
 		oui = &mwifiex_wpa_oui[cipher][0];
 		ret = mwifiex_search_oui_in_ie(iebody, oui);
 		if (ret)
@@ -1219,6 +1220,8 @@
 		}
 		switch (element_id) {
 		case WLAN_EID_SSID:
+			if (element_len > IEEE80211_MAX_SSID_LEN)
+				return -EINVAL;
 			bss_entry->ssid.ssid_len = element_len;
 			memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
 			       element_len);
@@ -1228,6 +1231,8 @@
 			break;
 
 		case WLAN_EID_SUPP_RATES:
+			if (element_len > MWIFIEX_SUPPORTED_RATES)
+				return -EINVAL;
 			memcpy(bss_entry->data_rates, current_ptr + 2,
 			       element_len);
 			memcpy(bss_entry->supported_rates, current_ptr + 2,
@@ -1237,6 +1242,8 @@
 			break;
 
 		case WLAN_EID_FH_PARAMS:
+			if (element_len + 2 < sizeof(*fh_param_set))
+				return -EINVAL;
 			fh_param_set =
 				(struct ieee_types_fh_param_set *) current_ptr;
 			memcpy(&bss_entry->phy_param_set.fh_param_set,
@@ -1245,6 +1252,8 @@
 			break;
 
 		case WLAN_EID_DS_PARAMS:
+			if (element_len + 2 < sizeof(*ds_param_set))
+				return -EINVAL;
 			ds_param_set =
 				(struct ieee_types_ds_param_set *) current_ptr;
 
@@ -1256,6 +1265,8 @@
 			break;
 
 		case WLAN_EID_CF_PARAMS:
+			if (element_len + 2 < sizeof(*cf_param_set))
+				return -EINVAL;
 			cf_param_set =
 				(struct ieee_types_cf_param_set *) current_ptr;
 			memcpy(&bss_entry->ss_param_set.cf_param_set,
@@ -1264,6 +1275,8 @@
 			break;
 
 		case WLAN_EID_IBSS_PARAMS:
+			if (element_len + 2 < sizeof(*ibss_param_set))
+				return -EINVAL;
 			ibss_param_set =
 				(struct ieee_types_ibss_param_set *)
 				current_ptr;
@@ -1273,10 +1286,14 @@
 			break;
 
 		case WLAN_EID_ERP_INFO:
+			if (!element_len)
+				return -EINVAL;
 			bss_entry->erp_flags = *(current_ptr + 2);
 			break;
 
 		case WLAN_EID_PWR_CONSTRAINT:
+			if (!element_len)
+				return -EINVAL;
 			bss_entry->local_constraint = *(current_ptr + 2);
 			bss_entry->sensed_11h = true;
 			break;
@@ -1319,15 +1336,22 @@
 			vendor_ie = (struct ieee_types_vendor_specific *)
 					current_ptr;
 
-			if (!memcmp
-			    (vendor_ie->vend_hdr.oui, wpa_oui,
-			     sizeof(wpa_oui))) {
+			/* 802.11 requires at least 3-byte OUI. */
+			if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui))
+				return -EINVAL;
+
+			/* Not long enough for a match? Skip it. */
+			if (element_len < sizeof(wpa_oui))
+				break;
+
+			if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui,
+				    sizeof(wpa_oui))) {
 				bss_entry->bcn_wpa_ie =
 					(struct ieee_types_vendor_specific *)
 					current_ptr;
 				bss_entry->wpa_offset = (u16)
 					(current_ptr - bss_entry->beacon_buf);
-			} else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
+			} else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui,
 				    sizeof(wmm_oui))) {
 				if (total_ie_len ==
 				    sizeof(struct ieee_types_wmm_parameter) ||
@@ -1838,7 +1862,7 @@
 					    chan, CFG80211_BSS_FTYPE_UNKNOWN,
 					    bssid, timestamp,
 					    cap_info_bitmap, beacon_period,
-					    ie_buf, ie_len, rssi, GFP_KERNEL);
+					    ie_buf, ie_len, rssi, GFP_ATOMIC);
 			if (bss) {
 				bss_priv = (struct mwifiex_bss_priv *)bss->priv;
 				bss_priv->band = band;
@@ -1849,15 +1873,17 @@
 					    ETH_ALEN))
 					mwifiex_update_curr_bss_params(priv,
 								       bss);
-				cfg80211_put_bss(priv->wdev.wiphy, bss);
-			}
 
-			if ((chan->flags & IEEE80211_CHAN_RADAR) ||
-			    (chan->flags & IEEE80211_CHAN_NO_IR)) {
-				mwifiex_dbg(adapter, INFO,
-					    "radar or passive channel %d\n",
-					    channel);
-				mwifiex_save_hidden_ssid_channels(priv, bss);
+				if ((chan->flags & IEEE80211_CHAN_RADAR) ||
+				    (chan->flags & IEEE80211_CHAN_NO_IR)) {
+					mwifiex_dbg(adapter, INFO,
+						    "radar or passive channel %d\n",
+						    channel);
+					mwifiex_save_hidden_ssid_channels(priv,
+									  bss);
+				}
+
+				cfg80211_put_bss(priv->wdev.wiphy, bss);
 			}
 		}
 	} else {
@@ -2170,6 +2196,12 @@
 					      sizeof(struct mwifiex_chan_stats);
 
 	for (i = 0 ; i < num_chan; i++) {
+		if (adapter->survey_idx >= adapter->num_in_chan_stats) {
+			mwifiex_dbg(adapter, WARN,
+				    "FW reported too many channel results (max %d)\n",
+				    adapter->num_in_chan_stats);
+			return;
+		}
 		chan_stats.chan_num = fw_chan_stats->chan_num;
 		chan_stats.bandcfg = fw_chan_stats->bandcfg;
 		chan_stats.flags = fw_chan_stats->flags;
@@ -2536,6 +2568,13 @@
 			vs_param_set->header.len =
 				cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
 				& 0x00FF) + 2);
+			if (le16_to_cpu(vs_param_set->header.len) >
+				MWIFIEX_MAX_VSIE_LEN) {
+				mwifiex_dbg(priv->adapter, ERROR,
+					    "Invalid param length!\n");
+				break;
+			}
+
 			memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
 			       le16_to_cpu(vs_param_set->header.len));
 			*buffer += le16_to_cpu(vs_param_set->header.len) +
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/sdio.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/sdio.c
@@ -1928,6 +1928,8 @@
 		kfree(card->mpa_rx.buf);
 		card->mpa_tx.buf_size = 0;
 		card->mpa_rx.buf_size = 0;
+		card->mpa_tx.buf = NULL;
+		card->mpa_rx.buf = NULL;
 	}
 
 	return ret;
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/sta_cmd.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -393,6 +393,31 @@
 	return 0;
 }
 
+static int mwifiex_cmd_802_11_led_cfg(struct mwifiex_private *priv,
+					struct host_cmd_ds_command *cmd,
+					u16 cmd_action,
+					struct mwifiex_led_param *ledcfg_param)
+{
+	struct host_cmd_ds_802_11_led_control *led_cfg = &cmd->params.led_cfg;
+	struct mwifiex_ie_types_led_param *led_tlv;
+	u8 *pos;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_LED_CONTROL);
+	cmd->size = cpu_to_le16(S_DS_GEN);
+	le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_802_11_led_control));
+
+	led_cfg->action = cpu_to_le16(cmd_action);
+	led_cfg->num_led = cpu_to_le16(MWIFIEX_LED_MAX);
+
+	pos = (u8 *)led_cfg + sizeof(struct host_cmd_ds_802_11_led_control);
+	led_tlv = (void *)pos;
+	led_tlv->header.type = cpu_to_le16(TLV_TYPE_LED_CONTROL);
+	led_tlv->header.len = cpu_to_le16(sizeof(struct mwifiex_led_param));
+	memcpy(&led_tlv->led_cfg, ledcfg_param, sizeof(struct mwifiex_led_param));
+	le16_add_cpu(&cmd->size, sizeof(struct mwifiex_ie_types_led_param));
+	return 0;
+}
+
 /*
  * This function prepares command to set/get MAC address.
  *
@@ -1487,9 +1512,10 @@
 {
 	struct mwifiex_adapter *adapter = priv->adapter;
 	struct property *prop = data_buf;
-	u32 len;
+	u32 len = 0;
 	u8 *data = (u8 *)cmd + S_DS_GEN;
 	int ret;
+	const struct firmware *cal_data = adapter->cal_data;
 
 	if (prop) {
 		len = prop->length;
@@ -1500,11 +1526,19 @@
 		mwifiex_dbg(adapter, INFO,
 			    "download cfg_data from device tree: %s\n",
 			    prop->name);
-	} else if (adapter->cal_data->data && adapter->cal_data->size > 0) {
-		len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
-					    adapter->cal_data->size, data);
-		mwifiex_dbg(adapter, INFO,
-			    "download cfg_data from config file\n");
+	} else if (cal_data) {
+		if (cal_data->data && cal_data->size > 0) {
+			len = mwifiex_parse_cal_cfg((u8 *)cal_data->data,
+						    cal_data->size, data);
+			mwifiex_dbg(adapter, INFO,
+				    "download cfg_data from config file\n");
+		} else {
+			return -1;
+		}
+	} else if (adapter->cfg_data && adapter->cfg_len > 0) {
+		len = mwifiex_parse_cal_cfg(adapter->cfg_data,
+					    adapter->cfg_len, data);
+		mwifiex_dbg(adapter, INFO, "download cfg_data from iw vendor command\n");
 	} else {
 		return -1;
 	}
@@ -1870,6 +1904,10 @@
 		ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
 				(struct mwifiex_hs_config_param *) data_buf);
 		break;
+	case HostCmd_CMD_802_11_LED_CONTROL:
+		ret = mwifiex_cmd_802_11_led_cfg(priv, cmd_ptr, cmd_action,
+						data_buf);
+		break;
 	case HostCmd_CMD_802_11_SCAN:
 		ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
 		break;
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -592,6 +592,11 @@
 {
 	struct host_cmd_ds_802_11_key_material *key =
 						&resp->params.key_material;
+	int len;
+
+	len = le16_to_cpu(key->key_param_set.key_len);
+	if (len > sizeof(key->key_param_set.key))
+		return -EINVAL;
 
 	if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
 		if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
@@ -605,9 +610,8 @@
 
 	memset(priv->aes_key.key_param_set.key, 0,
 	       sizeof(key->key_param_set.key));
-	priv->aes_key.key_param_set.key_len = key->key_param_set.key_len;
-	memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key,
-	       le16_to_cpu(priv->aes_key.key_param_set.key_len));
+	priv->aes_key.key_param_set.key_len = cpu_to_le16(len);
+	memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, len);
 
 	return 0;
 }
@@ -622,9 +626,14 @@
 					      struct host_cmd_ds_command *resp)
 {
 	struct host_cmd_ds_802_11_key_material_v2 *key_v2;
-	__le16 len;
+	int len;
 
 	key_v2 = &resp->params.key_material_v2;
+
+	len = le16_to_cpu(key_v2->key_param_set.key_params.aes.key_len);
+	if (len > sizeof(key_v2->key_param_set.key_params.aes.key))
+		return -EINVAL;
+
 	if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) {
 		if ((le16_to_cpu(key_v2->key_param_set.key_info) & KEY_MCAST)) {
 			mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n");
@@ -638,12 +647,11 @@
 		return 0;
 
 	memset(priv->aes_key_v2.key_param_set.key_params.aes.key, 0,
-	       WLAN_KEY_LEN_CCMP);
+	       sizeof(key_v2->key_param_set.key_params.aes.key));
 	priv->aes_key_v2.key_param_set.key_params.aes.key_len =
-				key_v2->key_param_set.key_params.aes.key_len;
-	len = priv->aes_key_v2.key_param_set.key_params.aes.key_len;
+				cpu_to_le16(len);
 	memcpy(priv->aes_key_v2.key_param_set.key_params.aes.key,
-	       key_v2->key_param_set.key_params.aes.key, le16_to_cpu(len));
+	       key_v2->key_param_set.key_params.aes.key, len);
 
 	return 0;
 }
@@ -1238,6 +1246,8 @@
 	case HostCmd_CMD_ROBUST_COEX:
 		ret = mwifiex_ret_robust_coex(priv, resp, data_buf);
 		break;
+	case HostCmd_CMD_802_11_LED_CONTROL:
+		break;
 	default:
 		mwifiex_dbg(adapter, ERROR,
 			    "CMD_RESP: unknown cmd response %#x\n",
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/sta_event.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/sta_event.c
@@ -607,11 +607,13 @@
 
 	case EVENT_PS_AWAKE:
 		mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n");
-		if (!adapter->pps_uapsd_mode && priv->port_open &&
+		if (!adapter->pps_uapsd_mode &&
+		    (priv->port_open ||
+		     (priv->bss_mode == NL80211_IFTYPE_ADHOC)) &&
 		    priv->media_connected && adapter->sleep_period.period) {
-				adapter->pps_uapsd_mode = true;
-				mwifiex_dbg(adapter, EVENT,
-					    "event: PPS/UAPSD mode activated\n");
+			adapter->pps_uapsd_mode = true;
+			mwifiex_dbg(adapter, EVENT,
+				    "event: PPS/UAPSD mode activated\n");
 		}
 		adapter->tx_lock_flag = false;
 		if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -17,6 +17,8 @@
  * this warranty disclaimer.
  */
 
+#include <linux/dmi.h>
+
 #include "decl.h"
 #include "ioctl.h"
 #include "util.h"
@@ -229,6 +231,14 @@
 			    "11D: skip setting domain info in FW\n");
 		return 0;
 	}
+
+	if (country_ie_len >
+	    (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) {
+		rcu_read_unlock();
+		mwifiex_dbg(priv->adapter, ERROR,
+			    "11D: country_ie_len overflow!, deauth AP\n");
+		return -EINVAL;
+	}
 	memcpy(priv->adapter->country_code, &country_ie[2], 2);
 
 	domain_info->country_code[0] = country_ie[2];
@@ -272,7 +282,9 @@
 	priv->scan_block = false;
 
 	if (bss) {
-		mwifiex_process_country_ie(priv, bss);
+		if (adapter->region_code == 0x00 &&
+		    mwifiex_process_country_ie(priv, bss))
+			return -EINVAL;
 
 		/* Allocate and fill new bss descriptor */
 		bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
@@ -313,6 +325,7 @@
 			mwifiex_dbg(adapter, ERROR,
 				    "Attempt to reconnect on csa closed chan(%d)\n",
 				    bss_desc->channel);
+			ret = -1;
 			goto done;
 		}
 
@@ -538,6 +551,24 @@
 }
 EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
 
+int mwifiex_set_led(struct mwifiex_adapter *adapter, int on)
+{
+	struct mwifiex_private *priv;
+	struct mwifiex_led_param ledcfg;
+
+	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+	if (!priv->is_edge_gateway)
+		return -ENODEV;
+
+	memset(&ledcfg, 0, sizeof(struct mwifiex_led_param));
+	ledcfg.on = cpu_to_le16(on);
+
+	return mwifiex_send_cmd(priv,
+				HostCmd_CMD_802_11_LED_CONTROL,
+				HostCmd_ACT_GEN_SET, 0,
+				&ledcfg, true);
+}
+
 /*
  * IOCTL request handler to get BSS information.
  *
@@ -665,6 +696,9 @@
 	txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
 	txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
 	if (!power_cfg->is_power_auto) {
+		u16 dbm_min = power_cfg->is_power_fixed ?
+			      dbm : priv->min_tx_power_level;
+
 		txp_cfg->mode = cpu_to_le32(1);
 		pg_tlv = (struct mwifiex_types_power_group *)
 			 (buf + sizeof(struct host_cmd_ds_txpwr_cfg));
@@ -679,7 +713,7 @@
 		pg->last_rate_code = 0x03;
 		pg->modulation_class = MOD_CLASS_HR_DSSS;
 		pg->power_step = 0;
-		pg->power_min = (s8) dbm;
+		pg->power_min = (s8) dbm_min;
 		pg->power_max = (s8) dbm;
 		pg++;
 		/* Power group for modulation class OFDM */
@@ -687,7 +721,7 @@
 		pg->last_rate_code = 0x07;
 		pg->modulation_class = MOD_CLASS_OFDM;
 		pg->power_step = 0;
-		pg->power_min = (s8) dbm;
+		pg->power_min = (s8) dbm_min;
 		pg->power_max = (s8) dbm;
 		pg++;
 		/* Power group for modulation class HTBW20 */
@@ -695,7 +729,7 @@
 		pg->last_rate_code = 0x20;
 		pg->modulation_class = MOD_CLASS_HT;
 		pg->power_step = 0;
-		pg->power_min = (s8) dbm;
+		pg->power_min = (s8) dbm_min;
 		pg->power_max = (s8) dbm;
 		pg->ht_bandwidth = HT_BW_20;
 		pg++;
@@ -704,7 +738,7 @@
 		pg->last_rate_code = 0x20;
 		pg->modulation_class = MOD_CLASS_HT;
 		pg->power_step = 0;
-		pg->power_min = (s8) dbm;
+		pg->power_min = (s8) dbm_min;
 		pg->power_max = (s8) dbm;
 		pg->ht_bandwidth = HT_BW_40;
 	}
@@ -1097,8 +1131,6 @@
 			encrypt_key.is_rx_seq_valid = true;
 		}
 	} else {
-		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
-			return 0;
 		encrypt_key.key_disable = true;
 		if (mac_addr)
 			memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
@@ -1306,7 +1338,7 @@
 	pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
 	/* Test to see if it is a WPA IE, if not, then it is a gen IE */
 	if (((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) &&
-	     (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) ||
+	     (!memcmp(&pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) ||
 	    (pvendor_ie->element_id == WLAN_EID_RSN)) {
 
 		/* IE is a WPA/WPA2 IE so call set_wpa function */
@@ -1331,7 +1363,7 @@
 		 */
 		pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
 		if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) &&
-		    (!memcmp(pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) {
+		    (!memcmp(&pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) {
 			priv->wps.session_enable = true;
 			mwifiex_dbg(priv->adapter, INFO,
 				    "info: WPS Session Enabled.\n");
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/tdls.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/tdls.c
@@ -910,59 +910,116 @@
 
 		switch (*pos) {
 		case WLAN_EID_SUPP_RATES:
+			if (pos[1] > 32)
+				return;
 			sta_ptr->tdls_cap.rates_len = pos[1];
 			for (i = 0; i < pos[1]; i++)
 				sta_ptr->tdls_cap.rates[i] = pos[i + 2];
 			break;
 
 		case WLAN_EID_EXT_SUPP_RATES:
+			if (pos[1] > 32)
+				return;
 			basic = sta_ptr->tdls_cap.rates_len;
+			if (pos[1] > 32 - basic)
+				return;
 			for (i = 0; i < pos[1]; i++)
 				sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];
 			sta_ptr->tdls_cap.rates_len += pos[1];
 			break;
 		case WLAN_EID_HT_CAPABILITY:
-			memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,
+			if (pos > end - sizeof(struct ieee80211_ht_cap) - 2)
+				return;
+			if (pos[1] != sizeof(struct ieee80211_ht_cap))
+				return;
+			/* copy the ie's value into ht_capb*/
+			memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2,
 			       sizeof(struct ieee80211_ht_cap));
 			sta_ptr->is_11n_enabled = 1;
 			break;
 		case WLAN_EID_HT_OPERATION:
-			memcpy(&sta_ptr->tdls_cap.ht_oper, pos,
+			if (pos > end -
+			    sizeof(struct ieee80211_ht_operation) - 2)
+				return;
+			if (pos[1] != sizeof(struct ieee80211_ht_operation))
+				return;
+			memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2,
 			       sizeof(struct ieee80211_ht_operation));
 			break;
 		case WLAN_EID_BSS_COEX_2040:
+			if (pos > end - 3)
+				return;
+			if (pos[1] != 1)
+				return;
 			sta_ptr->tdls_cap.coex_2040 = pos[2];
 			break;
 		case WLAN_EID_EXT_CAPABILITY:
+			if (pos > end - sizeof(struct ieee_types_header))
+				return;
+			if (pos[1] < sizeof(struct ieee_types_header))
+				return;
+			if (pos[1] > 8)
+				return;
 			memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,
 			       sizeof(struct ieee_types_header) +
 			       min_t(u8, pos[1], 8));
 			break;
 		case WLAN_EID_RSN:
+			if (pos > end - sizeof(struct ieee_types_header))
+				return;
+			if (pos[1] < sizeof(struct ieee_types_header))
+				return;
+			if (pos[1] > IEEE_MAX_IE_SIZE -
+			    sizeof(struct ieee_types_header))
+				return;
 			memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
 			       sizeof(struct ieee_types_header) +
 			       min_t(u8, pos[1], IEEE_MAX_IE_SIZE -
 				     sizeof(struct ieee_types_header)));
 			break;
 		case WLAN_EID_QOS_CAPA:
+			if (pos > end - 3)
+				return;
+			if (pos[1] != 1)
+				return;
 			sta_ptr->tdls_cap.qos_info = pos[2];
 			break;
 		case WLAN_EID_VHT_OPERATION:
-			if (priv->adapter->is_hw_11ac_capable)
-				memcpy(&sta_ptr->tdls_cap.vhtoper, pos,
+			if (priv->adapter->is_hw_11ac_capable) {
+				if (pos > end -
+				    sizeof(struct ieee80211_vht_operation) - 2)
+					return;
+				if (pos[1] !=
+				    sizeof(struct ieee80211_vht_operation))
+					return;
+				/* copy the ie's value into vhtoper*/
+				memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2,
 				       sizeof(struct ieee80211_vht_operation));
+			}
 			break;
 		case WLAN_EID_VHT_CAPABILITY:
 			if (priv->adapter->is_hw_11ac_capable) {
-				memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos,
+				if (pos > end -
+				    sizeof(struct ieee80211_vht_cap) - 2)
+					return;
+				if (pos[1] != sizeof(struct ieee80211_vht_cap))
+					return;
+				/* copy the ie's value into vhtcap*/
+				memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2,
 				       sizeof(struct ieee80211_vht_cap));
 				sta_ptr->is_11ac_enabled = 1;
 			}
 			break;
 		case WLAN_EID_AID:
-			if (priv->adapter->is_hw_11ac_capable)
+			if (priv->adapter->is_hw_11ac_capable) {
+				if (pos > end - 4)
+					return;
+				if (pos[1] != 2)
+					return;
 				sta_ptr->tdls_cap.aid =
 					      le16_to_cpu(*(__le16 *)(pos + 2));
+			}
+			break;
 		default:
 			break;
 		}
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/uap_cmd.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -286,6 +286,8 @@
 
 	rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
 	if (rate_ie) {
+		if (rate_ie->len > MWIFIEX_SUPPORTED_RATES)
+			return;
 		memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len);
 		rate_len = rate_ie->len;
 	}
@@ -293,8 +295,11 @@
 	rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,
 					   params->beacon.tail,
 					   params->beacon.tail_len);
-	if (rate_ie)
+	if (rate_ie) {
+		if (rate_ie->len > MWIFIEX_SUPPORTED_RATES - rate_len)
+			return;
 		memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len);
+	}
 
 	return;
 }
@@ -412,6 +417,8 @@
 					    params->beacon.tail_len);
 	if (vendor_ie) {
 		wmm_ie = (struct ieee_types_header *)vendor_ie;
+		if (*(vendor_ie + 1) > sizeof(struct mwifiex_types_wmm_info))
+			return;
 		memcpy(&bss_cfg->wmm_info, wmm_ie + 1,
 		       sizeof(bss_cfg->wmm_info));
 		priv->wmm_enabled = 1;
@@ -848,9 +855,9 @@
 
 	if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
 			     HostCmd_ACT_GEN_SET,
-			     UAP_BSS_PARAMS_I, bss_cfg, false)) {
+			     UAP_BSS_PARAMS_I, bss_cfg, true)) {
 		mwifiex_dbg(priv->adapter, ERROR,
-			    "Failed to set the SSID\n");
+			    "Failed to set AP configuration\n");
 		return -1;
 	}
 
@@ -865,7 +872,7 @@
 	}
 
 	if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
-			     HostCmd_ACT_GEN_SET, 0, NULL, false)) {
+			     HostCmd_ACT_GEN_SET, 0, NULL, true)) {
 		mwifiex_dbg(priv->adapter, ERROR,
 			    "Failed to start the BSS\n");
 		return -1;
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/usb.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/usb.c
@@ -132,7 +132,8 @@
 		default:
 			mwifiex_dbg(adapter, ERROR,
 				    "unknown recv_type %#x\n", recv_type);
-			return -1;
+			ret = -1;
+			goto exit_restore_skb;
 		}
 		break;
 	case MWIFIEX_USB_EP_DATA:
@@ -624,6 +625,9 @@
 					 MWIFIEX_FUNC_SHUTDOWN);
 	}
 
+	if (adapter->workqueue)
+		flush_workqueue(adapter->workqueue);
+
 	mwifiex_usb_free(card);
 
 	mwifiex_dbg(adapter, FATAL,
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/util.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/util.c
@@ -702,12 +702,14 @@
 			   s8 nflr)
 {
 	struct mwifiex_histogram_data *phist_data = priv->hist_data;
+	s8 nf   = -nflr;
+	s8 rssi = snr - nflr;
 
 	atomic_inc(&phist_data->num_samples);
 	atomic_inc(&phist_data->rx_rate[rx_rate]);
-	atomic_inc(&phist_data->snr[snr]);
-	atomic_inc(&phist_data->noise_flr[128 + nflr]);
-	atomic_inc(&phist_data->sig_str[nflr - snr]);
+	atomic_inc(&phist_data->snr[snr + 128]);
+	atomic_inc(&phist_data->noise_flr[nf + 128]);
+	atomic_inc(&phist_data->sig_str[rssi + 128]);
 }
 
 /* function to reset histogram data during init/reset */
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/vendor.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/vendor.c
@@ -0,0 +1,83 @@
+/* Marvell Wireless LAN device driver: TDLS handling
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <net/mac80211.h>
+#include <net/netlink.h>
+#include "vendor.h"
+#include "main.h"
+
+static int
+marvell_vendor_cmd_set_turbo_mode(struct wiphy *wiphy,
+				  struct wireless_dev *wdev,
+				  const void *data, int data_len)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+	u8 mode = *(u8 *)data;
+	int ret;
+
+	ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+			       HostCmd_ACT_GEN_SET, TURBO_MODE_I, &mode, true);
+
+	return 0;
+}
+
+static int
+mwifiex_vendor_cmd_set_cfg_data(struct wiphy *wiphy,
+				struct wireless_dev *wdev,
+				const void *data, int data_len)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+	int ret;
+
+	priv->adapter->cfg_data = (u8 *)data;
+	priv->adapter->cfg_len = data_len;
+
+	ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA,
+			       HostCmd_ACT_GEN_SET, 0, NULL, true);
+
+	priv->adapter->cfg_data = NULL;
+	priv->adapter->cfg_len = 0;
+
+	return 0;
+}
+
+static const struct wiphy_vendor_command marvell_vendor_commands[] = {
+	{
+		.info = {
+			.vendor_id = MARVELL_OUI,
+			.subcmd = MARVELL_VENDOR_CMD_SET_TURBO_MODE,
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = marvell_vendor_cmd_set_turbo_mode,
+	},
+	{
+		.info = {
+			.vendor_id = MARVELL_OUI,
+			.subcmd = MARVELL_VENDOR_CMD_SET_CONF_DATA,
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = mwifiex_vendor_cmd_set_cfg_data,
+	},
+};
+
+void marvell_set_vendor_commands(struct wiphy *wiphy)
+{
+	wiphy->vendor_commands = marvell_vendor_commands;
+	wiphy->n_vendor_commands = ARRAY_SIZE(marvell_vendor_commands);
+}
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/vendor.h
+++ linux-4.4.0/drivers/net/wireless/mwifiex/vendor.h
@@ -0,0 +1,28 @@
+/* Marvell Wireless LAN device driver: TDLS handling
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef __MARVELL_VENDOR_H__
+#define __MARVELL_VENDOR_H__
+
+#define MARVELL_OUI	0x005043
+
+enum marvell_vendor_commands {
+	MARVELL_VENDOR_CMD_SET_TURBO_MODE,
+	MARVELL_VENDOR_CMD_SET_CONF_DATA,
+};
+
+#endif /* __MARVELL_VENDOR_H__ */
--- linux-4.4.0.orig/drivers/net/wireless/mwifiex/wmm.c
+++ linux-4.4.0/drivers/net/wireless/mwifiex/wmm.c
@@ -240,7 +240,7 @@
 	mwifiex_dbg(priv->adapter, INFO,
 		    "info: WMM Parameter IE: version=%d,\t"
 		    "qos_info Parameter Set Count=%d, Reserved=%#x\n",
-		    wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
+		    wmm_ie->version, wmm_ie->qos_info_bitmap &
 		    IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
 		    wmm_ie->reserved);
 
@@ -475,7 +475,8 @@
 		priv = adapter->priv[i];
 		if (!priv)
 			continue;
-		if (!priv->port_open)
+		if (!priv->port_open &&
+		    (priv->bss_mode != NL80211_IFTYPE_ADHOC))
 			continue;
 		if (adapter->if_ops.is_port_ready &&
 		    !adapter->if_ops.is_port_ready(priv))
@@ -501,8 +502,10 @@
 	struct mwifiex_adapter *adapter = priv->adapter;
 	struct sk_buff *skb, *tmp;
 
-	skb_queue_walk_safe(&ra_list->skb_head, skb, tmp)
+	skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) {
+		skb_unlink(skb, &ra_list->skb_head);
 		mwifiex_write_data_complete(adapter, skb, 0, -1);
+	}
 }
 
 /*
@@ -598,11 +601,15 @@
 		priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
 	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 
-	skb_queue_walk_safe(&priv->tdls_txq, skb, tmp)
+	skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
+		skb_unlink(skb, &priv->tdls_txq);
 		mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
+	}
 
-	skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
+	skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) {
+		skb_unlink(skb, &priv->bypass_txq);
 		mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
+	}
 	atomic_set(&priv->adapter->bypass_tx_pending, 0);
 
 	idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL);
@@ -972,6 +979,10 @@
 				    "WMM Parameter Set Count: %d\n",
 				    wmm_param_ie->qos_info_bitmap & mask);
 
+			if (wmm_param_ie->vend_hdr.len + 2 >
+				sizeof(struct ieee_types_wmm_parameter))
+				break;
+
 			memcpy((u8 *) &priv->curr_bss_params.bss_descriptor.
 			       wmm_ie, wmm_param_ie,
 			       wmm_param_ie->vend_hdr.len + 2);
@@ -1099,7 +1110,8 @@
 
 			priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv;
 
-			if (!priv_tmp->port_open ||
+			if (((priv_tmp->bss_mode != NL80211_IFTYPE_ADHOC) &&
+			     !priv_tmp->port_open) ||
 			    (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0))
 				continue;
 
--- linux-4.4.0.orig/drivers/net/wireless/mwl8k.c
+++ linux-4.4.0/drivers/net/wireless/mwl8k.c
@@ -5421,11 +5421,13 @@
 
 static int
 mwl8k_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, bool amsdu)
+		   struct ieee80211_ampdu_params *params)
 {
-
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
+	u8 buf_size = params->buf_size;
 	int i, rc = 0;
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_ampdu_stream *stream;
--- linux-4.4.0.orig/drivers/net/wireless/orinoco/orinoco_usb.c
+++ linux-4.4.0/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1224,13 +1224,6 @@
 	if (skb->len < ETH_HLEN)
 		goto drop;
 
-	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
-	if (!ctx)
-		goto busy;
-
-	memset(ctx->buf, 0, BULK_BUF_SIZE);
-	buf = ctx->buf->data;
-
 	tx_control = 0;
 
 	err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
@@ -1238,6 +1231,13 @@
 	if (err)
 		goto drop;
 
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
+	if (!ctx)
+		goto drop;
+
+	memset(ctx->buf, 0, BULK_BUF_SIZE);
+	buf = ctx->buf->data;
+
 	{
 		__le16 *tx_cntl = (__le16 *)buf;
 		*tx_cntl = cpu_to_le16(tx_control);
@@ -1351,7 +1351,8 @@
 	int retval;
 
 	BUG_ON(in_interrupt());
-	BUG_ON(!upriv);
+	if (!upriv)
+		return -EINVAL;
 
 	upriv->reply_count = 0;
 	/* Write the MAGIC number on the simulated registers to keep
@@ -1601,9 +1602,9 @@
 	/* set up the endpoint information */
 	/* check out the endpoints */
 
-	iface_desc = &interface->altsetting[0].desc;
+	iface_desc = &interface->cur_altsetting->desc;
 	for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
-		ep = &interface->altsetting[0].endpoint[i].desc;
+		ep = &interface->cur_altsetting->endpoint[i].desc;
 
 		if (usb_endpoint_is_bulk_in(ep)) {
 			/* we found a bulk in endpoint */
--- linux-4.4.0.orig/drivers/net/wireless/p54/fwio.c
+++ linux-4.4.0/drivers/net/wireless/p54/fwio.c
@@ -488,7 +488,7 @@
 
 			entry += sizeof(__le16);
 			chan->pa_points_per_curve = 8;
-			memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+			memset(chan->curve_data, 0, sizeof(chan->curve_data));
 			memcpy(chan->curve_data, entry,
 			       sizeof(struct p54_pa_curve_data_sample) *
 			       min((u8)8, curve_data->points_per_channel));
--- linux-4.4.0.orig/drivers/net/wireless/p54/p54usb.c
+++ linux-4.4.0/drivers/net/wireless/p54/p54usb.c
@@ -33,6 +33,8 @@
 MODULE_FIRMWARE("isl3886usb");
 MODULE_FIRMWARE("isl3887usb");
 
+static struct usb_driver p54u_driver;
+
 /*
  * Note:
  *
@@ -921,9 +923,9 @@
 {
 	struct p54u_priv *priv = context;
 	struct usb_device *udev = priv->udev;
+	struct usb_interface *intf = priv->intf;
 	int err;
 
-	complete(&priv->fw_wait_load);
 	if (firmware) {
 		priv->fw = firmware;
 		err = p54u_start_ops(priv);
@@ -932,26 +934,22 @@
 		dev_err(&udev->dev, "Firmware not found.\n");
 	}
 
-	if (err) {
-		struct device *parent = priv->udev->dev.parent;
-
-		dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
-
-		if (parent)
-			device_lock(parent);
+	complete(&priv->fw_wait_load);
+	/*
+	 * At this point p54u_disconnect may have already freed
+	 * the "priv" context. Do not use it anymore!
+	 */
+	priv = NULL;
 
-		device_release_driver(&udev->dev);
-		/*
-		 * At this point p54u_disconnect has already freed
-		 * the "priv" context. Do not use it anymore!
-		 */
-		priv = NULL;
+	if (err) {
+		dev_err(&intf->dev, "failed to initialize device (%d)\n", err);
 
-		if (parent)
-			device_unlock(parent);
+		usb_lock_device(udev);
+		usb_driver_release_interface(&p54u_driver, intf);
+		usb_unlock_device(udev);
 	}
 
-	usb_put_dev(udev);
+	usb_put_intf(intf);
 }
 
 static int p54u_load_firmware(struct ieee80211_hw *dev,
@@ -972,14 +970,14 @@
 	dev_info(&priv->udev->dev, "Loading firmware file %s\n",
 	       p54u_fwlist[i].fw);
 
-	usb_get_dev(udev);
+	usb_get_intf(intf);
 	err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
 				      device, GFP_KERNEL, priv,
 				      p54u_load_firmware_cb);
 	if (err) {
 		dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
 					  "(%d)!\n", p54u_fwlist[i].fw, err);
-		usb_put_dev(udev);
+		usb_put_intf(intf);
 	}
 
 	return err;
@@ -1011,8 +1009,6 @@
 	skb_queue_head_init(&priv->rx_queue);
 	init_usb_anchor(&priv->submitted);
 
-	usb_get_dev(udev);
-
 	/* really lazy and simple way of figuring out if we're a 3887 */
 	/* TODO: should just stick the identification in the device table */
 	i = intf->altsetting->desc.bNumEndpoints;
@@ -1053,10 +1049,8 @@
 		priv->upload_fw = p54u_upload_firmware_net2280;
 	}
 	err = p54u_load_firmware(dev, intf);
-	if (err) {
-		usb_put_dev(udev);
+	if (err)
 		p54_free_common(dev);
-	}
 	return err;
 }
 
@@ -1072,7 +1066,6 @@
 	wait_for_completion(&priv->fw_wait_load);
 	p54_unregister_common(dev);
 
-	usb_put_dev(interface_to_usbdev(intf));
 	release_firmware(priv->fw);
 	p54_free_common(dev);
 }
--- linux-4.4.0.orig/drivers/net/wireless/ray_cs.c
+++ linux-4.4.0/drivers/net/wireless/ray_cs.c
@@ -247,7 +247,10 @@
 	0x04, 0x08,		/* Noise gain, limit offset */
 	0x28, 0x28,		/* det rssi, med busy offsets */
 	7,			/* det sync thresh */
-	0, 2, 2			/* test mode, min, max */
+	0, 2, 2,		/* test mode, min, max */
+	0,			/* rx/tx delay */
+	0, 0, 0, 0, 0, 0,	/* current BSS id */
+	0			/* hop set */
 };
 
 /*===========================================================================*/
@@ -598,7 +601,7 @@
 	 *    a_beacon_period = hops    a_beacon_period = KuS
 	 *//* 64ms = 010000 */
 	if (local->fw_ver == 0x55) {
-		memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms,
+		memcpy(&local->sparm.b4, b4_default_startup_parms,
 		       sizeof(struct b4_startup_params));
 		/* Translate sane kus input values to old build 4/5 format */
 		/* i = hop time in uS truncated to 3 bytes */
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -446,12 +446,13 @@
 		skb_queue_tail(&priv->rx_queue, skb);
 		usb_anchor_urb(entry, &priv->anchored);
 		ret = usb_submit_urb(entry, GFP_KERNEL);
-		usb_put_urb(entry);
 		if (ret) {
 			skb_unlink(skb, &priv->rx_queue);
 			usb_unanchor_urb(entry);
+			usb_put_urb(entry);
 			goto err;
 		}
+		usb_put_urb(entry);
 	}
 	return ret;
 
@@ -1454,6 +1455,7 @@
 		goto err_free_dev;
 	}
 	mutex_init(&priv->io_mutex);
+	mutex_init(&priv->conf_mutex);
 
 	SET_IEEE80211_DEV(dev, &intf->dev);
 	usb_set_intfdata(intf, dev);
@@ -1627,7 +1629,6 @@
 		printk(KERN_ERR "rtl8187: Cannot register device\n");
 		goto err_free_dmabuf;
 	}
-	mutex_init(&priv->conf_mutex);
 	skb_queue_head_init(&priv->b_tx_status.queue);
 
 	wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
@@ -146,7 +146,7 @@
 	led->dev = dev;
 	led->ledpin = ledpin;
 	led->is_radio = is_radio;
-	strncpy(led->name, name, sizeof(led->name));
+	strlcpy(led->name, name, sizeof(led->name));
 
 	led->led_dev.name = led->name;
 	led->led_dev.default_trigger = default_trigger;
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c
@@ -5143,6 +5143,7 @@
 	rtl8xxxu_write32(priv, REG_USB_HIMR, val32);
 
 error:
+	usb_free_urb(urb);
 	return ret;
 }
 
@@ -5331,6 +5332,7 @@
 		break;
 	case WLAN_CIPHER_SUITE_TKIP:
 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+		break;
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -5375,13 +5377,13 @@
 
 static int
 rtl8xxxu_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,
-		      bool amsdu)
+		      struct ieee80211_ampdu_params *params)
 {
 	struct rtl8xxxu_priv *priv = hw->priv;
 	struct device *dev = &priv->udev->dev;
 	u8 ampdu_factor, ampdu_density;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
 
 	switch (action) {
 	case IEEE80211_AMPDU_TX_START:
@@ -5422,6 +5424,7 @@
 	struct rtl8xxxu_priv *priv = hw->priv;
 	struct rtl8xxxu_rx_urb *rx_urb;
 	struct rtl8xxxu_tx_urb *tx_urb;
+	struct sk_buff *skb;
 	unsigned long flags;
 	int ret, i;
 
@@ -5470,6 +5473,13 @@
 		rx_urb->hw = hw;
 
 		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
+		if (ret) {
+			if (ret != -ENOMEM) {
+				skb = (struct sk_buff *)rx_urb->urb.context;
+				dev_kfree_skb(skb);
+			}
+			rtl8xxxu_queue_rx_urb(priv, rx_urb);
+		}
 	}
 exit:
 	/*
@@ -5553,7 +5563,7 @@
 	u8 dir, xtype, num;
 	int ret = 0;
 
-	host_interface = &interface->altsetting[0];
+	host_interface = interface->cur_altsetting;
 	interface_desc = &host_interface->desc;
 	endpoints = interface_desc->bNumEndpoints;
 
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/base.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/base.c
@@ -466,6 +466,11 @@
 	/* <2> work queue */
 	rtlpriv->works.hw = hw;
 	rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name);
+	if (unlikely(!rtlpriv->works.rtl_wq)) {
+		pr_err("Failed to allocate work queue\n");
+		return;
+	}
+
 	INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq,
 			  (void *)rtl_watchdog_wq_callback);
 	INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
@@ -1303,12 +1308,13 @@
 
 static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc)
 {
+	struct ieee80211_hw *hw = rtlpriv->hw;
+
 	rtlpriv->ra.is_special_data = true;
 	if (rtlpriv->cfg->ops->get_btc_status())
 		rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
 					rtlpriv, 1);
-	rtlpriv->enter_ps = false;
-	schedule_work(&rtlpriv->works.lps_change_work);
+	rtl_lps_leave(hw);
 	ppsc->last_delaylps_stamp_jiffies = jiffies;
 }
 
@@ -1381,8 +1387,7 @@
 
 		if (is_tx) {
 			rtlpriv->ra.is_special_data = true;
-			rtlpriv->enter_ps = false;
-			schedule_work(&rtlpriv->works.lps_change_work);
+			rtl_lps_leave(hw);
 			ppsc->last_delaylps_stamp_jiffies = jiffies;
 		}
 
@@ -1660,9 +1665,9 @@
 		if (((rtlpriv->link_info.num_rx_inperiod +
 		      rtlpriv->link_info.num_tx_inperiod) > 8) ||
 		    (rtlpriv->link_info.num_rx_inperiod > 2))
-			rtl_lps_enter(hw);
-		else
 			rtl_lps_leave(hw);
+		else
+			rtl_lps_enter(hw);
 	}
 
 	rtlpriv->link_info.num_rx_inperiod = 0;
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c
@@ -1203,7 +1203,6 @@
 
 		/* Force GNT_BT to low */
 		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
-		btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
 
 		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
 			/* tell firmware "no antenna inverse" */
@@ -1211,19 +1210,25 @@
 			h2c_parameter[1] = 1;  /* ext switch type */
 			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
 						h2c_parameter);
+			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
 		} else {
 			/* tell firmware "antenna inverse" */
 			h2c_parameter[0] = 1;
 			h2c_parameter[1] = 1;  /* ext switch type */
 			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
 						h2c_parameter);
+			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
 		}
 	}
 
 	/* ext switch setting */
 	if (use_ext_switch) {
 		/* fixed internal switch S1->WiFi, S0->BT */
-		btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+		else
+			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+
 		switch (antpos_type) {
 		case BTC_ANT_WIFI_AT_MAIN:
 			/* ext switch main at wifi */
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -965,13 +965,38 @@
 	}
 }
 
-void exhalbtc_set_ant_num(u8 type, u8 ant_num)
+void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num)
 {
 	if (BT_COEX_ANT_TYPE_PG == type) {
 		gl_bt_coexist.board_info.pg_ant_num = ant_num;
 		gl_bt_coexist.board_info.btdm_ant_num = ant_num;
+		/* The antenna position:
+		 * Main (default) or Aux for pgAntNum=2 && btdmAntNum =1.
+		 * The antenna position should be determined by
+		 * auto-detect mechanism.
+		 * The following is assumed to main,
+		 * and those must be modified
+		 * if y auto-detect mechanism is ready
+		 */
+		if ((gl_bt_coexist.board_info.pg_ant_num == 2) &&
+		    (gl_bt_coexist.board_info.btdm_ant_num == 1))
+			gl_bt_coexist.board_info.btdm_ant_pos =
+						       BTC_ANTENNA_AT_MAIN_PORT;
+		else
+			gl_bt_coexist.board_info.btdm_ant_pos =
+						       BTC_ANTENNA_AT_MAIN_PORT;
 	} else if (BT_COEX_ANT_TYPE_ANTDIV == type) {
 		gl_bt_coexist.board_info.btdm_ant_num = ant_num;
+		gl_bt_coexist.board_info.btdm_ant_pos =
+						       BTC_ANTENNA_AT_MAIN_PORT;
+	} else if (type == BT_COEX_ANT_TYPE_DETECTED) {
+		gl_bt_coexist.board_info.btdm_ant_num = ant_num;
+		if (rtlpriv->cfg->mod_params->ant_sel == 1)
+			gl_bt_coexist.board_info.btdm_ant_pos =
+				BTC_ANTENNA_AT_AUX_PORT;
+		else
+			gl_bt_coexist.board_info.btdm_ant_pos =
+				BTC_ANTENNA_AT_MAIN_PORT;
 	}
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -535,7 +535,7 @@
 void exhalbtc_update_min_bt_rssi(char bt_rssi);
 void exhalbtc_set_bt_exist(bool bt_exist);
 void exhalbtc_set_chip_type(u8 chip_type);
-void exhalbtc_set_ant_num(u8 type, u8 ant_num);
+void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num);
 void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist);
 void exhalbtc_signal_compensation(struct btc_coexist *btcoexist,
 				  u8 *rssi_wifi, u8 *rssi_bt);
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
@@ -72,7 +72,10 @@
 		 __func__, bt_type);
 	exhalbtc_set_chip_type(bt_type);
 
-	exhalbtc_set_ant_num(BT_COEX_ANT_TYPE_PG, ant_num);
+	if (rtlpriv->cfg->mod_params->ant_sel == 1)
+		exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_DETECTED, 1);
+	else
+		exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_PG, ant_num);
 }
 
 void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv)
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/core.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/core.c
@@ -135,7 +135,6 @@
 		       firmware->size);
 		rtlpriv->rtlhal.wowlan_fwsize = firmware->size;
 	}
-	rtlpriv->rtlhal.fwsize = firmware->size;
 	release_firmware(firmware);
 }
 
@@ -1153,10 +1152,8 @@
 		} else {
 			mstatus = RT_MEDIA_DISCONNECT;
 
-			if (mac->link_state == MAC80211_LINKED) {
-				rtlpriv->enter_ps = false;
-				schedule_work(&rtlpriv->works.lps_change_work);
-			}
+			if (mac->link_state == MAC80211_LINKED)
+				rtl_lps_leave(hw);
 			if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
 				rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
 			mac->link_state = MAC80211_NOLINK;
@@ -1371,11 +1368,13 @@
 
 static int rtl_op_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, bool amsdu)
+			       struct ieee80211_ampdu_params *params)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
 
 	switch (action) {
 	case IEEE80211_AMPDU_TX_START:
@@ -1432,8 +1431,7 @@
 	}
 
 	if (mac->link_state == MAC80211_LINKED) {
-		rtlpriv->enter_ps = false;
-		schedule_work(&rtlpriv->works.lps_change_work);
+		rtl_lps_leave(hw);
 		mac->link_state = MAC80211_LINKED_SCANNING;
 	} else {
 		rtl_ips_nic_on(hw);
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/pci.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/pci.c
@@ -664,11 +664,9 @@
 	}
 
 	if (((rtlpriv->link_info.num_rx_inperiod +
-		rtlpriv->link_info.num_tx_inperiod) > 8) ||
-		(rtlpriv->link_info.num_rx_inperiod > 2)) {
-		rtlpriv->enter_ps = false;
-		schedule_work(&rtlpriv->works.lps_change_work);
-	}
+	      rtlpriv->link_info.num_tx_inperiod) > 8) ||
+	      (rtlpriv->link_info.num_rx_inperiod > 2))
+		rtl_lps_leave(hw);
 }
 
 static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
@@ -801,7 +799,9 @@
 								      hw_queue);
 			if (rx_remained_cnt == 0)
 				return;
-
+			buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc[
+				rtlpci->rx_ring[rxring_idx].idx];
+			pdesc = (struct rtl_rx_desc *)skb->data;
 		} else {	/* rx descriptor */
 			pdesc = &rtlpci->rx_ring[rxring_idx].desc[
 				rtlpci->rx_ring[rxring_idx].idx];
@@ -824,13 +824,6 @@
 		new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
 		if (unlikely(!new_skb))
 			goto no_new;
-		if (rtlpriv->use_new_trx_flow) {
-			buffer_desc =
-			  &rtlpci->rx_ring[rxring_idx].buffer_desc
-				[rtlpci->rx_ring[rxring_idx].idx];
-			/*means rx wifi info*/
-			pdesc = (struct rtl_rx_desc *)skb->data;
-		}
 		memset(&rx_status , 0 , sizeof(rx_status));
 		rtlpriv->cfg->ops->query_rx_desc(hw, &stats,
 						 &rx_status, (u8 *)pdesc, skb);
@@ -924,10 +917,8 @@
 		}
 		if (((rtlpriv->link_info.num_rx_inperiod +
 		      rtlpriv->link_info.num_tx_inperiod) > 8) ||
-		      (rtlpriv->link_info.num_rx_inperiod > 2)) {
-			rtlpriv->enter_ps = false;
-			schedule_work(&rtlpriv->works.lps_change_work);
-		}
+		      (rtlpriv->link_info.num_rx_inperiod > 2))
+			rtl_lps_leave(hw);
 		skb = new_skb;
 no_new:
 		if (rtlpriv->use_new_trx_flow) {
@@ -1105,13 +1096,15 @@
 	return ret;
 }
 
-static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
+static void _rtl_pci_irq_tasklet(unsigned long data)
 {
+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
 	_rtl_pci_tx_chk_waitq(hw);
 }
 
-static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
+static void _rtl_pci_prepare_bcn_tasklet(unsigned long data)
 {
+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -1232,10 +1225,10 @@
 
 	/*task */
 	tasklet_init(&rtlpriv->works.irq_tasklet,
-		     (void (*)(unsigned long))_rtl_pci_irq_tasklet,
+		     _rtl_pci_irq_tasklet,
 		     (unsigned long)hw);
 	tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet,
-		     (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet,
+		     _rtl_pci_prepare_bcn_tasklet,
 		     (unsigned long)hw);
 	INIT_WORK(&rtlpriv->works.lps_change_work,
 		  rtl_lps_change_work_callback);
@@ -1578,10 +1571,17 @@
 							 true,
 							 HW_DESC_TXBUFF_ADDR),
 						 skb->len, PCI_DMA_TODEVICE);
-				kfree_skb(skb);
+				dev_kfree_skb_irq(skb);
 				ring->idx = (ring->idx + 1) % ring->entries;
 			}
+
+			if (rtlpriv->use_new_trx_flow) {
+				rtlpci->tx_ring[i].cur_tx_rp = 0;
+				rtlpci->tx_ring[i].cur_tx_wp = 0;
+			}
+
 			ring->idx = 0;
+			ring->entries = rtlpci->txringcount[i];
 		}
 	}
 	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
@@ -2278,7 +2278,7 @@
 	/* find adapter */
 	if (!_rtl_pci_find_adapter(pdev, hw)) {
 		err = -ENODEV;
-		goto fail3;
+		goto fail2;
 	}
 
 	/* Init IO handler */
@@ -2348,10 +2348,10 @@
 	pci_set_drvdata(pdev, NULL);
 	rtl_deinit_core(hw);
 
+fail2:
 	if (rtlpriv->io.pci_mem_start != 0)
 		pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
 
-fail2:
 	pci_release_regions(pdev);
 	complete(&rtlpriv->firmware_loading_complete);
 
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/pci.h
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/pci.h
@@ -275,10 +275,10 @@
 };
 
 struct rtl_pci_priv {
+	struct bt_coexist_info bt_coexist;
+	struct rtl_led_ctl ledctl;
 	struct rtl_pci dev;
 	struct mp_adapter ndis_adapter;
-	struct rtl_led_ctl ledctl;
-	struct bt_coexist_info bt_coexist;
 };
 
 #define rtl_pcipriv(hw)		(((struct rtl_pci_priv *)(rtl_priv(hw))->priv))
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/ps.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/ps.c
@@ -414,8 +414,8 @@
 	}
 }
 
-/*Enter the leisure power save mode.*/
-void rtl_lps_enter(struct ieee80211_hw *hw)
+/* Interrupt safe routine to enter the leisure power save mode.*/
+static void rtl_lps_enter_core(struct ieee80211_hw *hw)
 {
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -455,10 +455,9 @@
 
 	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 }
-EXPORT_SYMBOL(rtl_lps_enter);
 
-/*Leave the leisure power save mode.*/
-void rtl_lps_leave(struct ieee80211_hw *hw)
+/* Interrupt safe routine to leave the leisure power save mode.*/
+static void rtl_lps_leave_core(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -488,7 +487,6 @@
 	}
 	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 }
-EXPORT_SYMBOL(rtl_lps_leave);
 
 /* For sw LPS*/
 void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
@@ -681,12 +679,34 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	if (rtlpriv->enter_ps)
-		rtl_lps_enter(hw);
+		rtl_lps_enter_core(hw);
 	else
-		rtl_lps_leave(hw);
+		rtl_lps_leave_core(hw);
 }
 EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);
 
+void rtl_lps_enter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (!in_interrupt())
+		return rtl_lps_enter_core(hw);
+	rtlpriv->enter_ps = true;
+	schedule_work(&rtlpriv->works.lps_change_work);
+}
+EXPORT_SYMBOL_GPL(rtl_lps_enter);
+
+void rtl_lps_leave(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (!in_interrupt())
+		return rtl_lps_leave_core(hw);
+	rtlpriv->enter_ps = false;
+	schedule_work(&rtlpriv->works.lps_change_work);
+}
+EXPORT_SYMBOL_GPL(rtl_lps_leave);
+
 void rtl_swlps_wq_callback(void *data)
 {
 	struct rtl_works *rtlworks = container_of_dwork_rtl(data,
@@ -760,7 +780,8 @@
 					 noa_len);
 				return;
 			} else {
-				noa_num = (noa_len - 2) / 13;
+				noa_num = min((noa_len - 2) / 13,
+					      P2P_MAX_NOA_NUM);
 			}
 			noa_index = ie[3];
 			if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
@@ -854,7 +875,8 @@
 					 noa_len);
 				return;
 			} else {
-				noa_num = (noa_len - 2) / 13;
+				noa_num = min((noa_len - 2) / 13,
+					      P2P_MAX_NOA_NUM);
 			}
 			noa_index = ie[3];
 			if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/regd.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/regd.c
@@ -345,13 +345,12 @@
 		return &rtl_regdom_no_midband;
 	case COUNTRY_CODE_IC:
 		return &rtl_regdom_11;
-	case COUNTRY_CODE_ETSI:
 	case COUNTRY_CODE_TELEC_NETGEAR:
 		return &rtl_regdom_60_64;
+	case COUNTRY_CODE_ETSI:
 	case COUNTRY_CODE_SPAIN:
 	case COUNTRY_CODE_FRANCE:
 	case COUNTRY_CODE_ISRAEL:
-	case COUNTRY_CODE_WORLD_WIDE_13:
 		return &rtl_regdom_12_13;
 	case COUNTRY_CODE_MKK:
 	case COUNTRY_CODE_MKK1:
@@ -360,6 +359,7 @@
 		return &rtl_regdom_14_60_64;
 	case COUNTRY_CODE_GLOBAL_DOMAIN:
 		return &rtl_regdom_14;
+	case COUNTRY_CODE_WORLD_WIDE_13:
 	case COUNTRY_CODE_WORLD_WIDE_13_5G_ALL:
 		return &rtl_regdom_12_13_5g_all;
 	default:
@@ -406,6 +406,8 @@
 		return COUNTRY_CODE_WORLD_WIDE_13;
 	case 0x22:
 		return COUNTRY_CODE_IC;
+	case 0x25:
+		return COUNTRY_CODE_ETSI;
 	case 0x32:
 		return COUNTRY_CODE_TELEC_NETGEAR;
 	case 0x41:
@@ -425,7 +427,7 @@
 	struct wiphy *wiphy = hw->wiphy;
 	struct country_code_to_enum_rd *country = NULL;
 
-	if (wiphy == NULL || &rtlpriv->regd == NULL)
+	if (!wiphy)
 		return -EINVAL;
 
 	/* init country_code from efuse channel plan */
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
@@ -88,8 +88,6 @@
 	u8 tid;
 
 	rtl8188ee_bt_reg_init(hw);
-	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
-
 	rtlpriv->dm.dm_initialgain_enable = 1;
 	rtlpriv->dm.dm_flag = 0;
 	rtlpriv->dm.disable_framebursting = 0;
@@ -138,6 +136,11 @@
 	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+	rtlpriv->cfg->mod_params->sw_crypto =
+		rtlpriv->cfg->mod_params->sw_crypto;
+	rtlpriv->cfg->mod_params->disable_watchdog =
+		rtlpriv->cfg->mod_params->disable_watchdog;
 	if (rtlpriv->cfg->mod_params->disable_watchdog)
 		pr_info("watchdog disabled\n");
 	if (!rtlpriv->psc.inactiveps)
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
@@ -139,6 +139,8 @@
 	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	rtlpriv->cfg->mod_params->sw_crypto =
+		rtlpriv->cfg->mod_params->sw_crypto;
 	if (!rtlpriv->psc.inactiveps)
 		pr_info("rtl8192ce: Power Save off (module option)\n");
 	if (!rtlpriv->psc.fwctrl_lps)
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c
@@ -1601,6 +1601,8 @@
    * This is maybe necessary:
    * rtlpriv->cfg->ops->fill_tx_cmddesc(hw, buffer, 1, 1, skb);
    */
+	dev_kfree_skb(skb);
+
 	return true;
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c
@@ -304,9 +304,6 @@
 			writeVal = 0x00000000;
 		if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
 			writeVal = writeVal - 0x06060606;
-		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
-			 TXHIGHPWRLEVEL_BT2)
-			writeVal = writeVal;
 		*(p_outwriteval + rf) = writeVal;
 	}
 }
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c
@@ -65,6 +65,8 @@
 	rtlpriv->dm.disable_framebursting = false;
 	rtlpriv->dm.thermalvalue = 0;
 	rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
+	rtlpriv->cfg->mod_params->sw_crypto =
+		rtlpriv->cfg->mod_params->sw_crypto;
 
 	/* for firmware buf */
 	rtlpriv->rtlhal.pfirmware = vzalloc(0x4000);
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c
@@ -234,7 +234,7 @@
 			 rtl_read_byte(rtlpriv, FW_MAC1_READY));
 	}
 	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
-		 "Polling FW ready fail!! REG_MCUFWDL:0x%08ul\n",
+		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x\n",
 		 rtl_read_dword(rtlpriv, REG_MCUFWDL));
 	return -1;
 }
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c
@@ -1206,6 +1206,7 @@
 
 	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
 	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+	rtlpci->irq_enabled = true;
 }
 
 void rtl92de_disable_interrupt(struct ieee80211_hw *hw)
@@ -1215,7 +1216,7 @@
 
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
-	synchronize_irq(rtlpci->pdev->irq);
+	rtlpci->irq_enabled = false;
 }
 
 static void _rtl92de_poweroff_adapter(struct ieee80211_hw *hw)
@@ -1386,7 +1387,7 @@
 
 	bcn_interval = mac->beacon_interval;
 	atim_window = 2;
-	/*rtl92de_disable_interrupt(hw);  */
+	rtl92de_disable_interrupt(hw);
 	rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
 	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
 	rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
@@ -1406,9 +1407,9 @@
 
 	RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
 		 "beacon_interval:%d\n", bcn_interval);
-	/* rtl92de_disable_interrupt(hw); */
+	rtl92de_disable_interrupt(hw);
 	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
-	/* rtl92de_enable_interrupt(hw); */
+	rtl92de_enable_interrupt(hw);
 }
 
 void rtl92de_update_interrupt_mask(struct ieee80211_hw *hw,
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c
@@ -242,6 +242,7 @@
 	.led_control = rtl92de_led_control,
 	.set_desc = rtl92de_set_desc,
 	.get_desc = rtl92de_get_desc,
+	.is_tx_desc_closed = rtl92de_is_tx_desc_closed,
 	.tx_polling = rtl92de_tx_polling,
 	.enable_hw_sec = rtl92de_enable_hw_security_config,
 	.set_key = rtl92de_set_key,
@@ -376,8 +377,8 @@
 module_param_named(fwlps, rtl92de_mod_params.fwctrl_lps, bool, 0444);
 MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
 MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
-MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
-MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 1)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 0)\n");
 MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
 
 static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c
@@ -843,13 +843,15 @@
 			break;
 		}
 	} else {
-		struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc;
 		switch (desc_name) {
 		case HW_DESC_OWN:
-			ret = GET_RX_DESC_OWN(pdesc);
+			ret = GET_RX_DESC_OWN(p_desc);
 			break;
 		case HW_DESC_RXPKT_LEN:
-			ret = GET_RX_DESC_PKT_LEN(pdesc);
+			ret = GET_RX_DESC_PKT_LEN(p_desc);
+			break;
+		case HW_DESC_RXBUFF_ADDR:
+			ret = GET_RX_DESC_BUFF_ADDR(p_desc);
 			break;
 		default:
 			RT_ASSERT(false, "ERR rxdesc :%d not process\n",
@@ -860,6 +862,23 @@
 	return ret;
 }
 
+bool rtl92de_is_tx_desc_closed(struct ieee80211_hw *hw,
+			       u8 hw_queue, u16 index)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+	u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+	u8 own = (u8)rtl92de_get_desc(entry, true, HW_DESC_OWN);
+
+	/* a beacon packet will only use the first
+	 * descriptor by defaut, and the own bit may not
+	 * be cleared by the hardware
+	 */
+	if (own)
+		return false;
+	return true;
+}
+
 void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h
@@ -740,6 +740,8 @@
 void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
 		      u8 desc_name, u8 *val);
 u32 rtl92de_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+bool rtl92de_is_tx_desc_closed(struct ieee80211_hw *hw,
+			       u8 hw_queue, u16 index);
 void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
 			     bool b_firstseg, bool b_lastseg,
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c
@@ -664,7 +664,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct sk_buff *skb = NULL;
-
+	bool rtstatus;
 	u32 totalpacketlen;
 	u8 u1rsvdpageloc[5] = { 0 };
 	bool b_dlok = false;
@@ -727,7 +727,9 @@
 	memcpy((u8 *)skb_put(skb, totalpacketlen),
 	       &reserved_page_packet, totalpacketlen);
 
-	b_dlok = true;
+	rtstatus = rtl_cmd_send_packet(hw, skb);
+	if (rtstatus)
+		b_dlok = true;
 
 	if (b_dlok) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
@@ -1003,7 +1003,7 @@
 	rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x100a);
 
 	/* Note Data sheet don't define */
-	rtl_write_word(rtlpriv, 0x4C7, 0x80);
+	rtl_write_byte(rtlpriv, 0x4C7, 0x80);
 
 	rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20);
 
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c
@@ -187,6 +187,8 @@
 	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	rtlpriv->cfg->mod_params->sw_crypto =
+		rtlpriv->cfg->mod_params->sw_crypto;
 	if (!rtlpriv->psc.inactiveps)
 		pr_info("Power Save off (module option)\n");
 	if (!rtlpriv->psc.fwctrl_lps)
@@ -425,8 +427,8 @@
 module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444);
 MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
 MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
-MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
-MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 1)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 0)\n");
 MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
 
 static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
@@ -150,6 +150,11 @@
 	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+	rtlpriv->cfg->mod_params->sw_crypto =
+		rtlpriv->cfg->mod_params->sw_crypto;
+	rtlpriv->cfg->mod_params->disable_watchdog =
+		rtlpriv->cfg->mod_params->disable_watchdog;
 	if (rtlpriv->cfg->mod_params->disable_watchdog)
 		pr_info("watchdog disabled\n");
 	rtlpriv->psc.reg_fwctrl_lps = 3;
@@ -267,6 +272,8 @@
 	.swctrl_lps = false,
 	.fwctrl_lps = true,
 	.debug = DBG_EMERG,
+	.msi_support = false,
+	.disable_watchdog = false,
 };
 
 static struct rtl_hal_cfg rtl8723e_hal_cfg = {
@@ -383,12 +390,14 @@
 module_param_named(ips, rtl8723e_mod_params.inactiveps, bool, 0444);
 module_param_named(swlps, rtl8723e_mod_params.swctrl_lps, bool, 0444);
 module_param_named(fwlps, rtl8723e_mod_params.fwctrl_lps, bool, 0444);
+module_param_named(msi, rtl8723e_mod_params.msi_support, bool, 0444);
 module_param_named(disable_watchdog, rtl8723e_mod_params.disable_watchdog,
 		   bool, 0444);
 MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
 MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
 MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
 MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 0)\n");
 MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
 MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
 
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
@@ -1123,7 +1123,8 @@
 
 	/* Configuration Space offset 0x70f BIT7 is used to control L0S */
 	tmp8 = _rtl8723be_dbi_read(rtlpriv, 0x70f);
-	_rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7));
+	_rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7) |
+			     ASPM_L1_LATENCY << 3);
 
 	/* Configuration Space offset 0x719 Bit3 is for L1
 	 * BIT4 is for clock request
@@ -2684,6 +2685,7 @@
 					      bool auto_load_fail, u8 *hwinfo)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mod_params *mod_params = rtlpriv->cfg->mod_params;
 	u8 value;
 	u32 tmpu_32;
 
@@ -2702,6 +2704,10 @@
 		rtlpriv->btcoexist.btc_info.ant_num = ANT_X2;
 	}
 
+	/* override ant_num / ant_path */
+	if (mod_params->ant_sel)
+		rtlpriv->btcoexist.btc_info.ant_num =
+			(mod_params->ant_sel == 1 ? ANT_X2 : ANT_X1);
 }
 
 void rtl8723be_bt_reg_init(struct ieee80211_hw *hw)
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c
@@ -93,7 +93,6 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 
 	rtl8723be_bt_reg_init(hw);
-	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
 	rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
 
 	rtlpriv->dm.dm_initialgain_enable = 1;
@@ -151,6 +150,10 @@
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
 	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+	rtlpriv->cfg->mod_params->sw_crypto =
+		 rtlpriv->cfg->mod_params->sw_crypto;
+	rtlpriv->cfg->mod_params->disable_watchdog =
+		 rtlpriv->cfg->mod_params->disable_watchdog;
 	if (rtlpriv->cfg->mod_params->disable_watchdog)
 		pr_info("watchdog disabled\n");
 	rtlpriv->psc.reg_fwctrl_lps = 3;
@@ -267,6 +270,10 @@
 	.inactiveps = true,
 	.swctrl_lps = false,
 	.fwctrl_lps = true,
+	.msi_support = false,
+	.disable_watchdog = false,
+	.debug = DBG_EMERG,
+	.ant_sel = 0,
 };
 
 static struct rtl_hal_cfg rtl8723be_hal_cfg = {
@@ -388,6 +395,7 @@
 module_param_named(msi, rtl8723be_mod_params.msi_support, bool, 0444);
 module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog,
 		   bool, 0444);
+module_param_named(ant_sel, rtl8723be_mod_params.ant_sel, int, 0444);
 MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
 MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
 MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
@@ -396,6 +404,7 @@
 MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
 MODULE_PARM_DESC(disable_watchdog,
 		 "Set to 1 to disable the watchdog (default 0)\n");
+MODULE_PARM_DESC(ant_sel, "Set to 1 or 2 to force antenna number (default 0)\n");
 
 static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
 
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
@@ -2488,9 +2488,9 @@
 		for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++)
 			rtldm->swing_idx_ofdm_base[p] = rtldm->swing_idx_ofdm[p];
 
-			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-				 "pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n",
-				 rtldm->thermalvalue, thermal_value);
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n",
+			 rtldm->thermalvalue, thermal_value);
 		/*Record last Power Tracking Thermal Value*/
 		rtldm->thermalvalue = thermal_value;
 	}
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
@@ -1127,7 +1127,7 @@
 	}
 	if (0 == tmp) {
 		read_addr = REG_DBI_RDATA + addr % 4;
-		ret = rtl_read_word(rtlpriv, read_addr);
+		ret = rtl_read_byte(rtlpriv, read_addr);
 	}
 	return ret;
 }
@@ -1169,7 +1169,8 @@
 	}
 
 	tmp = _rtl8821ae_dbi_read(rtlpriv, 0x70f);
-	_rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7));
+	_rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7) |
+			     ASPM_L1_LATENCY << 3);
 
 	tmp = _rtl8821ae_dbi_read(rtlpriv, 0x719);
 	_rtl8821ae_dbi_write(rtlpriv, 0x719, tmp | BIT(3) | BIT(4));
@@ -1377,6 +1378,7 @@
 
 	ppsc->wakeup_reason = 0;
 
+	do_gettimeofday(&ts);
 	rtlhal->last_suspend_sec = ts.tv_sec;
 
 	switch (fw_reason) {
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
@@ -359,6 +359,107 @@
 	return rtl8821ae_phy_rf6052_config(hw);
 }
 
+static void _rtl8812ae_phy_set_rfe_reg_24g(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 tmp;
+
+	switch (rtlhal->rfe_type) {
+	case 3:
+		rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x54337770);
+		rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x54337770);
+		rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x010);
+		rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010);
+		rtl_set_bbreg(hw, 0x900, 0x00000303, 0x1);
+		break;
+	case 4:
+		rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77777777);
+		rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77777777);
+		rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x001);
+		rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x001);
+		break;
+	case 5:
+		rtl_write_byte(rtlpriv, RA_RFE_PINMUX + 2, 0x77);
+		rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77777777);
+		tmp = rtl_read_byte(rtlpriv, RA_RFE_INV + 3);
+		rtl_write_byte(rtlpriv, RA_RFE_INV + 3, tmp & ~0x1);
+		rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000);
+		break;
+	case 1:
+		if (rtlpriv->btcoexist.bt_coexistence) {
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xffffff, 0x777777);
+			rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD,
+				      0x77777777);
+			rtl_set_bbreg(hw, RA_RFE_INV, 0x33f00000, 0x000);
+			rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000);
+			break;
+		}
+	case 0:
+	case 2:
+	default:
+		rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77777777);
+		rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77777777);
+		rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x000);
+		rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000);
+		break;
+	}
+}
+
+static void _rtl8812ae_phy_set_rfe_reg_5g(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 tmp;
+
+	switch (rtlhal->rfe_type) {
+	case 0:
+		rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77337717);
+		rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77337717);
+		rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x010);
+		rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010);
+		break;
+	case 1:
+		if (rtlpriv->btcoexist.bt_coexistence) {
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xffffff, 0x337717);
+			rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD,
+				      0x77337717);
+			rtl_set_bbreg(hw, RA_RFE_INV, 0x33f00000, 0x000);
+			rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000);
+		} else {
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD,
+				      0x77337717);
+			rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD,
+				      0x77337717);
+			rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x000);
+			rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000);
+		}
+		break;
+	case 3:
+		rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x54337717);
+		rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x54337717);
+		rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x010);
+		rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010);
+		rtl_set_bbreg(hw, 0x900, 0x00000303, 0x1);
+		break;
+	case 5:
+		rtl_write_byte(rtlpriv, RA_RFE_PINMUX + 2, 0x33);
+		rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77337777);
+		tmp = rtl_read_byte(rtlpriv, RA_RFE_INV + 3);
+		rtl_write_byte(rtlpriv, RA_RFE_INV + 3, tmp | 0x1);
+		rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010);
+		break;
+	case 2:
+	case 4:
+	default:
+		rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77337777);
+		rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77337777);
+		rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x010);
+		rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010);
+		break;
+	}
+}
+
 u32 phy_get_tx_swing_8812A(struct ieee80211_hw *hw, u8	band,
 			   u8 rf_path)
 {
@@ -553,14 +654,9 @@
 			/* 0x82C[1:0] = 2b'00 */
 			rtl_set_bbreg(hw, 0x82c, 0x3, 0);
 		}
-		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
-			rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD,
-				      0x77777777);
-			rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD,
-				      0x77777777);
-			rtl_set_bbreg(hw, RA_RFE_INV, 0x3ff00000, 0x000);
-			rtl_set_bbreg(hw, RB_RFE_INV, 0x3ff00000, 0x000);
-		}
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			_rtl8812ae_phy_set_rfe_reg_24g(hw);
 
 		rtl_set_bbreg(hw, RTXPATH, 0xf0, 0x1);
 		rtl_set_bbreg(hw, RCCK_RX, 0x0f000000, 0x1);
@@ -615,14 +711,8 @@
 			/* 0x82C[1:0] = 2'b00 */
 			rtl_set_bbreg(hw, 0x82c, 0x3, 1);
 
-		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
-			rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD,
-				      0x77337777);
-			rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD,
-				      0x77337777);
-			rtl_set_bbreg(hw, RA_RFE_INV, 0x3ff00000, 0x010);
-			rtl_set_bbreg(hw, RB_RFE_INV, 0x3ff00000, 0x010);
-		}
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			_rtl8812ae_phy_set_rfe_reg_5g(hw);
 
 		rtl_set_bbreg(hw, RTXPATH, 0xf0, 0);
 		rtl_set_bbreg(hw, RCCK_RX, 0x0f000000, 0xf);
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h
@@ -2424,6 +2424,7 @@
 #define	BMASKH4BITS			0xf0000000
 #define BMASKOFDM_D			0xffc00000
 #define	BMASKCCK			0x3f3f3f3f
+#define BMASKRFEINV			0x3ff00000
 
 #define BRFREGOFFSETMASK		0xfffff
 
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
@@ -95,8 +95,6 @@
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
 	rtl8821ae_bt_reg_init(hw);
-	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
-	rtlpci->int_clear = rtlpriv->cfg->mod_params->int_clear;
 	rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
 
 	rtlpriv->dm.dm_initialgain_enable = 1;
@@ -168,12 +166,15 @@
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
 	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
-	rtlpci->msi_support = rtlpriv->cfg->mod_params->int_clear;
+	rtlpci->int_clear = rtlpriv->cfg->mod_params->int_clear;
+	rtlpriv->cfg->mod_params->sw_crypto =
+		rtlpriv->cfg->mod_params->sw_crypto;
+	rtlpriv->cfg->mod_params->disable_watchdog =
+		rtlpriv->cfg->mod_params->disable_watchdog;
 	if (rtlpriv->cfg->mod_params->disable_watchdog)
 		pr_info("watchdog disabled\n");
 	rtlpriv->psc.reg_fwctrl_lps = 3;
 	rtlpriv->psc.reg_max_lps_awakeintvl = 5;
-	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
 
 	/* for ASPM, you can close aspm through
 	 * set const_support_pciaspm = 0
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/usb.c
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/usb.c
@@ -531,6 +531,8 @@
 			ieee80211_rx(hw, skb);
 		else
 			dev_kfree_skb_any(skb);
+	} else {
+		dev_kfree_skb_any(skb);
 	}
 }
 
@@ -753,8 +755,11 @@
 
 		usb_anchor_urb(urb, &rtlusb->rx_submitted);
 		err = usb_submit_urb(urb, GFP_KERNEL);
-		if (err)
+		if (err) {
+			usb_unanchor_urb(urb);
+			usb_free_urb(urb);
 			goto err_out;
+		}
 		usb_free_urb(urb);
 	}
 	return 0;
@@ -832,12 +837,30 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
+	struct urb *urb;
 
 	/* should after adapter start and interrupt enable. */
 	set_hal_stop(rtlhal);
 	cancel_work_sync(&rtlpriv->works.fill_h2c_cmd);
 	/* Enable software */
 	SET_USB_STOP(rtlusb);
+
+	/* free pre-allocated URBs from rtl_usb_start() */
+	usb_kill_anchored_urbs(&rtlusb->rx_submitted);
+
+	tasklet_kill(&rtlusb->rx_work_tasklet);
+	cancel_work_sync(&rtlpriv->works.lps_change_work);
+
+	flush_workqueue(rtlpriv->works.rtl_wq);
+
+	skb_queue_purge(&rtlusb->rx_queue);
+
+	while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) {
+		usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+				urb->transfer_buffer, urb->transfer_dma);
+		usb_free_urb(urb);
+	}
+
 	rtlpriv->cfg->ops->hw_disable(hw);
 }
 
@@ -1071,10 +1094,13 @@
 		return -ENOMEM;
 	}
 	rtlpriv = hw->priv;
+	rtlpriv->hw = hw;
 	rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32),
 				    GFP_KERNEL);
-	if (!rtlpriv->usb_data)
+	if (!rtlpriv->usb_data) {
+		ieee80211_free_hw(hw);
 		return -ENOMEM;
+	}
 
 	/* this spin lock must be initialized early */
 	spin_lock_init(&rtlpriv->locks.usb_lock);
@@ -1137,6 +1163,7 @@
 	_rtl_usb_io_handler_release(hw);
 	usb_put_dev(udev);
 	complete(&rtlpriv->firmware_loading_complete);
+	kfree(rtlpriv->usb_data);
 	return -ENODEV;
 }
 EXPORT_SYMBOL(rtl_usb_probe);
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/usb.h
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/usb.h
@@ -150,8 +150,9 @@
 };
 
 struct rtl_usb_priv {
-	struct rtl_usb dev;
+	struct bt_coexist_info bt_coexist;
 	struct rtl_led_ctl ledctl;
+	struct rtl_usb dev;
 };
 
 #define rtl_usbpriv(hw)	 (((struct rtl_usb_priv *)(rtl_priv(hw))->priv))
--- linux-4.4.0.orig/drivers/net/wireless/realtek/rtlwifi/wifi.h
+++ linux-4.4.0/drivers/net/wireless/realtek/rtlwifi/wifi.h
@@ -99,6 +99,7 @@
 #define RTL_USB_MAX_RX_COUNT			100
 #define QBSS_LOAD_SIZE				5
 #define MAX_WMMELE_LENGTH			64
+#define ASPM_L1_LATENCY				7
 
 #define TOTAL_CAM_ENTRY				32
 
@@ -2252,6 +2253,9 @@
 
 	/* default 0: 1 means do not disable interrupts */
 	bool int_clear;
+
+	/* select antenna */
+	int ant_sel;
 };
 
 struct rtl_hal_usbint_cfg {
--- linux-4.4.0.orig/drivers/net/wireless/rndis_wlan.c
+++ linux-4.4.0/drivers/net/wireless/rndis_wlan.c
@@ -712,8 +712,8 @@
 		struct rndis_query	*get;
 		struct rndis_query_c	*get_c;
 	} u;
-	int ret, buflen;
-	int resplen, respoffs, copylen;
+	int ret;
+	size_t buflen, resplen, respoffs, copylen;
 
 	buflen = *len + sizeof(*u.get);
 	if (buflen < CONTROL_BUFFER_SIZE)
@@ -748,22 +748,15 @@
 
 		if (respoffs > buflen) {
 			/* Device returned data offset outside buffer, error. */
-			netdev_dbg(dev->net, "%s(%s): received invalid "
-				"data offset: %d > %d\n", __func__,
-				oid_to_string(oid), respoffs, buflen);
+			netdev_dbg(dev->net,
+				   "%s(%s): received invalid data offset: %zu > %zu\n",
+				   __func__, oid_to_string(oid), respoffs, buflen);
 
 			ret = -EINVAL;
 			goto exit_unlock;
 		}
 
-		if ((resplen + respoffs) > buflen) {
-			/* Device would have returned more data if buffer would
-			 * have been big enough. Copy just the bits that we got.
-			 */
-			copylen = buflen - respoffs;
-		} else {
-			copylen = resplen;
-		}
+		copylen = min(resplen, buflen - respoffs);
 
 		if (copylen > *len)
 			copylen = *len;
@@ -2919,6 +2912,8 @@
 
 	while (buflen >= sizeof(*auth_req)) {
 		auth_req = (void *)buf;
+		if (buflen < le32_to_cpu(auth_req->length))
+			return;
 		type = "unknown";
 		flags = le32_to_cpu(auth_req->flags);
 		pairwise_error = false;
@@ -3425,6 +3420,10 @@
 
 	/* because rndis_command() sleeps we need to use workqueue */
 	priv->workqueue = create_singlethread_workqueue("rndis_wlan");
+	if (!priv->workqueue) {
+		wiphy_free(wiphy);
+		return -ENOMEM;
+	}
 	INIT_WORK(&priv->work, rndis_wlan_worker);
 	INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller);
 	INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results);
--- linux-4.4.0.orig/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ linux-4.4.0/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -199,6 +199,7 @@
 		ieee80211_stop_queues(hw);
 		ieee80211_unregister_hw(hw);
 		ieee80211_free_hw(hw);
+		adapter->hw = NULL;
 	}
 
 	rsi_remove_dbgfs(adapter);
@@ -659,29 +660,24 @@
  *				 informs the f/w regarding this.
  * @hw: Pointer to the ieee80211_hw structure.
  * @vif: Pointer to the ieee80211_vif structure.
- * @action: ieee80211_ampdu_mlme_action enum.
- * @sta: Pointer to the ieee80211_sta structure.
- * @tid: Traffic identifier.
- * @ssn: Pointer to ssn value.
- * @buf_size: Buffer size (for kernel version > 2.6.38).
- * @amsdu: is AMSDU in AMPDU allowed
+ * @params: Pointer to A-MPDU action parameters
  *
  * Return: status: 0 on success, negative error code on failure.
  */
 static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw,
 				     struct ieee80211_vif *vif,
-				     enum ieee80211_ampdu_mlme_action action,
-				     struct ieee80211_sta *sta,
-				     unsigned short tid,
-				     unsigned short *ssn,
-				     unsigned char buf_size,
-				     bool amsdu)
+				     struct ieee80211_ampdu_params *params)
 {
 	int status = -EOPNOTSUPP;
 	struct rsi_hw *adapter = hw->priv;
 	struct rsi_common *common = adapter->priv;
 	u16 seq_no = 0;
 	u8 ii = 0;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
+	u8 buf_size = params->buf_size;
 
 	for (ii = 0; ii < RSI_MAX_VIFS; ii++) {
 		if (vif == adapter->vifs[ii])
--- linux-4.4.0.orig/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ linux-4.4.0/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -155,7 +155,6 @@
 	int err;
 	struct mmc_card *card = pfunction->card;
 	struct mmc_host *host = card->host;
-	s32 bit = (fls(host->ocr_avail) - 1);
 	u8 cmd52_resp;
 	u32 clock, resp, i;
 	u16 rca;
@@ -175,7 +174,6 @@
 	msleep(20);
 
 	/* Initialize the SDIO card */
-	host->ios.vdd = bit;
 	host->ios.chip_select = MMC_CS_DONTCARE;
 	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
 	host->ios.power_mode = MMC_POWER_UP;
@@ -796,7 +794,7 @@
 	{ SDIO_DEVICE(0x303, 0x100) },
 	{ SDIO_DEVICE(0x041B, 0x0301) },
 	{ SDIO_DEVICE(0x041B, 0x0201) },
-	{ SDIO_DEVICE(0x041B, 0x9330) },
+	/* { SDIO_DEVICE(0x041B, 0x9330) }, LP:#1657682 replaced by ubuntu/rsi/ */
 	{ /* Blank */},
 };
 
--- linux-4.4.0.orig/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ linux-4.4.0/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -103,7 +103,7 @@
 	__le16 buffer_size;
 	int ii, bep_found = 0;
 
-	iface_desc = &(interface->altsetting[0]);
+	iface_desc = interface->cur_altsetting;
 
 	for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) {
 		endpoint = &(iface_desc->endpoint[ii].desc);
@@ -553,7 +553,7 @@
 	{ USB_DEVICE(0x0303, 0x0100) },
 	{ USB_DEVICE(0x041B, 0x0301) },
 	{ USB_DEVICE(0x041B, 0x0201) },
-	{ USB_DEVICE(0x041B, 0x9330) },
+	/* { USB_DEVICE(0x041B, 0x9330) }, LP:#1657682 replaced by ubuntu/rsi/ */
 	{ /* Blank */},
 };
 
--- linux-4.4.0.orig/drivers/net/wireless/rsi/rsi_common.h
+++ linux-4.4.0/drivers/net/wireless/rsi/rsi_common.h
@@ -75,7 +75,6 @@
 	atomic_inc(&handle->thread_done);
 	rsi_set_event(&handle->event);
 
-	wait_for_completion(&handle->completion);
 	return kthread_stop(handle->task);
 }
 
--- linux-4.4.0.orig/drivers/net/wireless/rt2x00/rt2800lib.c
+++ linux-4.4.0/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -7935,10 +7935,11 @@
 EXPORT_SYMBOL_GPL(rt2800_get_tsf);
 
 int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-			enum ieee80211_ampdu_mlme_action action,
-			struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-			u8 buf_size, bool amsdu)
+			struct ieee80211_ampdu_params *params)
 {
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
 	struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
 	int ret = 0;
 
--- linux-4.4.0.orig/drivers/net/wireless/rt2x00/rt2800lib.h
+++ linux-4.4.0/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -218,9 +218,7 @@
 		   const struct ieee80211_tx_queue_params *params);
 u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-			enum ieee80211_ampdu_mlme_action action,
-			struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-			u8 buf_size, bool amsdu);
+			struct ieee80211_ampdu_params *params);
 int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
 		      struct survey_info *survey);
 void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
--- linux-4.4.0.orig/drivers/net/wireless/ti/wl1251/event.c
+++ linux-4.4.0/drivers/net/wireless/ti/wl1251/event.c
@@ -80,7 +80,7 @@
 		break;
 	}
 
-	return 0;
+	return ret;
 }
 
 static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
--- linux-4.4.0.orig/drivers/net/wireless/ti/wl1251/main.c
+++ linux-4.4.0/drivers/net/wireless/ti/wl1251/main.c
@@ -1196,8 +1196,7 @@
 		WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
 
 		enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc;
-		wl1251_acx_arp_ip_filter(wl, enable, addr);
-
+		ret = wl1251_acx_arp_ip_filter(wl, enable, addr);
 		if (ret < 0)
 			goto out_sleep;
 	}
@@ -1567,6 +1566,7 @@
 
 	wl->state = WL1251_STATE_OFF;
 	mutex_init(&wl->mutex);
+	spin_lock_init(&wl->wl_lock);
 
 	wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
 	wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
--- linux-4.4.0.orig/drivers/net/wireless/ti/wl12xx/main.c
+++ linux-4.4.0/drivers/net/wireless/ti/wl12xx/main.c
@@ -647,7 +647,6 @@
 		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
 			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
-			      WLCORE_QUIRK_START_STA_FAILS |
 			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
 		wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
 		wl->mr_fw_name = WL127X_FW_NAME_MULTI;
@@ -671,7 +670,6 @@
 		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
 			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
-			      WLCORE_QUIRK_START_STA_FAILS |
 			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
 		wl->plt_fw_name = WL127X_PLT_FW_NAME;
 		wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
@@ -700,7 +698,6 @@
 		wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
 			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
-			      WLCORE_QUIRK_START_STA_FAILS |
 			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
 
 		wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER,
--- linux-4.4.0.orig/drivers/net/wireless/ti/wl18xx/event.c
+++ linux-4.4.0/drivers/net/wireless/ti/wl18xx/event.c
@@ -206,5 +206,33 @@
 						 mbox->sc_pwd_len,
 						 mbox->sc_pwd);
 
+	if (vector & RX_BA_WIN_SIZE_CHANGE_EVENT_ID) {
+		struct wl12xx_vif *wlvif;
+		struct ieee80211_vif *vif;
+		struct ieee80211_sta *sta;
+		u8 link_id = mbox->rx_ba_link_id;
+		u8 win_size = mbox->rx_ba_win_size;
+		const u8 *addr;
+
+		wlvif = wl->links[link_id].wlvif;
+		vif = wl12xx_wlvif_to_vif(wlvif);
+
+		/* Update RX aggregation window size and call
+		 * MAC routine to stop active RX aggregations for this link
+		 */
+		if (wlvif->bss_type != BSS_TYPE_AP_BSS)
+			addr = vif->bss_conf.bssid;
+		else
+			addr = wl->links[link_id].addr;
+
+		sta = ieee80211_find_sta(vif, addr);
+		if (sta) {
+			sta->max_rx_aggregation_subframes = win_size;
+			ieee80211_stop_rx_ba_session(vif,
+						wl->links[link_id].ba_bitmap,
+						addr);
+		}
+	}
+
 	return 0;
 }
--- linux-4.4.0.orig/drivers/net/wireless/ti/wl18xx/event.h
+++ linux-4.4.0/drivers/net/wireless/ti/wl18xx/event.h
@@ -38,6 +38,7 @@
 	REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID      = BIT(18),
 	DFS_CHANNELS_CONFIG_COMPLETE_EVENT       = BIT(19),
 	PERIODIC_SCAN_REPORT_EVENT_ID            = BIT(20),
+	RX_BA_WIN_SIZE_CHANGE_EVENT_ID           = BIT(21),
 	SMART_CONFIG_SYNC_EVENT_ID               = BIT(22),
 	SMART_CONFIG_DECODE_EVENT_ID             = BIT(23),
 	TIME_SYNC_EVENT_ID                       = BIT(24),
--- linux-4.4.0.orig/drivers/net/wireless/ti/wl18xx/main.c
+++ linux-4.4.0/drivers/net/wireless/ti/wl18xx/main.c
@@ -1029,7 +1029,8 @@
 		DFS_CHANNELS_CONFIG_COMPLETE_EVENT |
 		SMART_CONFIG_SYNC_EVENT_ID |
 		SMART_CONFIG_DECODE_EVENT_ID |
-		TIME_SYNC_EVENT_ID;
+		TIME_SYNC_EVENT_ID |
+		RX_BA_WIN_SIZE_CHANGE_EVENT_ID;
 
 	wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID;
 
--- linux-4.4.0.orig/drivers/net/wireless/ti/wlcore/acx.c
+++ linux-4.4.0/drivers/net/wireless/ti/wlcore/acx.c
@@ -1419,7 +1419,8 @@
 
 /* setup BA session receiver setting in the FW. */
 int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
-				       u16 ssn, bool enable, u8 peer_hlid)
+				       u16 ssn, bool enable, u8 peer_hlid,
+				       u8 win_size)
 {
 	struct wl1271_acx_ba_receiver_setup *acx;
 	int ret;
@@ -1435,7 +1436,7 @@
 	acx->hlid = peer_hlid;
 	acx->tid = tid_index;
 	acx->enable = enable;
-	acx->win_size = wl->conf.ht.rx_ba_win_size;
+	acx->win_size =	win_size;
 	acx->ssn = ssn;
 
 	ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx,
--- linux-4.4.0.orig/drivers/net/wireless/ti/wlcore/acx.h
+++ linux-4.4.0/drivers/net/wireless/ti/wlcore/acx.h
@@ -1112,7 +1112,8 @@
 int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
 				       struct wl12xx_vif *wlvif);
 int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
-				       u16 ssn, bool enable, u8 peer_hlid);
+				       u16 ssn, bool enable, u8 peer_hlid,
+				       u8 win_size);
 int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			u64 *mactime);
 int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
--- linux-4.4.0.orig/drivers/net/wireless/ti/wlcore/io.h
+++ linux-4.4.0/drivers/net/wireless/ti/wlcore/io.h
@@ -207,19 +207,23 @@
 
 static inline void wl1271_power_off(struct wl1271 *wl)
 {
-	int ret;
+	int ret = 0;
 
 	if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags))
 		return;
 
-	ret = wl->if_ops->power(wl->dev, false);
+	if (wl->if_ops->power)
+		ret = wl->if_ops->power(wl->dev, false);
 	if (!ret)
 		clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
 }
 
 static inline int wl1271_power_on(struct wl1271 *wl)
 {
-	int ret = wl->if_ops->power(wl->dev, true);
+	int ret = 0;
+
+	if (wl->if_ops->power)
+		ret = wl->if_ops->power(wl->dev, true);
 	if (ret == 0)
 		set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
 
--- linux-4.4.0.orig/drivers/net/wireless/ti/wlcore/main.c
+++ linux-4.4.0/drivers/net/wireless/ti/wlcore/main.c
@@ -1123,8 +1123,11 @@
 		goto out;
 
 	ret = wl12xx_fetch_firmware(wl, plt);
-	if (ret < 0)
-		goto out;
+	if (ret < 0) {
+		kfree(wl->fw_status);
+		kfree(wl->raw_fw_status);
+		kfree(wl->tx_res_if);
+	}
 
 out:
 	return ret;
@@ -2886,21 +2889,8 @@
 
 	if (is_ibss)
 		ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
-	else {
-		if (wl->quirks & WLCORE_QUIRK_START_STA_FAILS) {
-			/*
-			 * TODO: this is an ugly workaround for wl12xx fw
-			 * bug - we are not able to tx/rx after the first
-			 * start_sta, so make dummy start+stop calls,
-			 * and then call start_sta again.
-			 * this should be fixed in the fw.
-			 */
-			wl12xx_cmd_role_start_sta(wl, wlvif);
-			wl12xx_cmd_role_stop_sta(wl, wlvif);
-		}
-
+	else
 		ret = wl12xx_cmd_role_start_sta(wl, wlvif);
-	}
 
 	return ret;
 }
@@ -5261,14 +5251,16 @@
 
 static int wl1271_op_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, bool amsdu)
+				  struct ieee80211_ampdu_params *params)
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	int ret;
 	u8 hlid, *ba_bitmap;
+	struct ieee80211_sta *sta = params->sta;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
 		     tid);
@@ -5326,7 +5318,9 @@
 		}
 
 		ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
-							 hlid);
+				hlid,
+				params->buf_size);
+
 		if (!ret) {
 			*ba_bitmap |= BIT(tid);
 			wl->ba_rx_session_count++;
@@ -5347,7 +5341,7 @@
 		}
 
 		ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
-							 hlid);
+							 hlid, 0);
 		if (!ret) {
 			*ba_bitmap &= ~BIT(tid);
 			wl->ba_rx_session_count--;
--- linux-4.4.0.orig/drivers/net/wireless/ti/wlcore/sdio.c
+++ linux-4.4.0/drivers/net/wireless/ti/wlcore/sdio.c
@@ -388,6 +388,11 @@
 	mmc_pm_flag_t sdio_flags;
 	int ret = 0;
 
+	if (!wl) {
+		dev_err(dev, "no wilink module was probed\n");
+		goto out;
+	}
+
 	dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n",
 		wl->wow_enabled);
 
--- linux-4.4.0.orig/drivers/net/wireless/ti/wlcore/spi.c
+++ linux-4.4.0/drivers/net/wireless/ti/wlcore/spi.c
@@ -71,9 +71,12 @@
  * only support SPI for 12xx - this code should be reworked when 18xx
  * support is introduced
  */
-#define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
+#define SPI_AGGR_BUFFER_SIZE (4 * SZ_4K)
+
+/* Maximum number of SPI write chunks */
+#define WSPI_MAX_NUM_OF_CHUNKS \
+	((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1)
 
-#define WSPI_MAX_NUM_OF_CHUNKS (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
 
 struct wl12xx_spi_glue {
 	struct device *dev;
@@ -268,9 +271,10 @@
 					     void *buf, size_t len, bool fixed)
 {
 	struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
-	struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)];
+	/* SPI write buffers - 2 for each chunk */
+	struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
 	struct spi_message m;
-	u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
+	u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */
 	u32 *cmd;
 	u32 chunk_len;
 	int i;
--- linux-4.4.0.orig/drivers/net/wireless/ti/wlcore/vendor_cmd.c
+++ linux-4.4.0/drivers/net/wireless/ti/wlcore/vendor_cmd.c
@@ -66,7 +66,7 @@
 out:
 	mutex_unlock(&wl->mutex);
 
-	return 0;
+	return ret;
 }
 
 static int
--- linux-4.4.0.orig/drivers/net/wireless/ti/wlcore/wlcore.h
+++ linux-4.4.0/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -556,9 +556,6 @@
 /* Each RX/TX transaction requires an end-of-transaction transfer */
 #define WLCORE_QUIRK_END_OF_TRANSACTION		BIT(0)
 
-/* the first start_role(sta) sometimes doesn't work on wl12xx */
-#define WLCORE_QUIRK_START_STA_FAILS		BIT(1)
-
 /* wl127x and SPI don't support SDIO block size alignment */
 #define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN		BIT(2)
 
--- linux-4.4.0.orig/drivers/net/wireless/zd1211rw/zd_usb.c
+++ linux-4.4.0/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -1272,7 +1272,7 @@
 static int eject_installer(struct usb_interface *intf)
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
-	struct usb_host_interface *iface_desc = &intf->altsetting[0];
+	struct usb_host_interface *iface_desc = intf->cur_altsetting;
 	struct usb_endpoint_descriptor *endpoint;
 	unsigned char *cmd;
 	u8 bulk_out_ep;
--- linux-4.4.0.orig/drivers/net/xen-netback/common.h
+++ linux-4.4.0/drivers/net/xen-netback/common.h
@@ -52,6 +52,7 @@
 
 struct pending_tx_info {
 	struct xen_netif_tx_request req; /* tx request */
+	unsigned int extra_count;
 	/* Callback data for released SKBs. The callback is always
 	 * xenvif_zerocopy_callback, desc contains the pending_idx, which is
 	 * also an index in pending_tx_info array. It is initialized in
@@ -137,6 +138,20 @@
 	char name[QUEUE_NAME_SIZE]; /* DEVNAME-qN */
 	struct xenvif *vif; /* Parent VIF */
 
+	/*
+	 * TX/RX common EOI handling.
+	 * When feature-split-event-channels = 0, interrupt handler sets
+	 * NETBK_COMMON_EOI, otherwise NETBK_RX_EOI and NETBK_TX_EOI are set
+	 * by the RX and TX interrupt handlers.
+	 * RX and TX handler threads will issue an EOI when either
+	 * NETBK_COMMON_EOI or their specific bits (NETBK_RX_EOI or
+	 * NETBK_TX_EOI) are set and they will reset those bits.
+	 */
+	atomic_t eoi_pending;
+#define NETBK_RX_EOI		0x01
+#define NETBK_TX_EOI		0x02
+#define NETBK_COMMON_EOI	0x04
+
 	/* Use NAPI for guest TX */
 	struct napi_struct napi;
 	/* When feature-split-event-channels = 0, tx_irq = rx_irq. */
@@ -201,6 +216,7 @@
 	unsigned long   remaining_credit;
 	struct timer_list credit_timeout;
 	u64 credit_window_start;
+	bool rate_limited;
 
 	/* Statistics */
 	struct xenvif_stats stats;
@@ -316,6 +332,7 @@
 
 int xenvif_dealloc_kthread(void *data);
 
+bool xenvif_have_rx_work(struct xenvif_queue *queue, bool test_kthread);
 void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb);
 
 void xenvif_carrier_on(struct xenvif *vif);
@@ -352,4 +369,28 @@
 bool xenvif_mcast_match(struct xenvif *vif, const u8 *addr);
 void xenvif_mcast_addr_list_free(struct xenvif *vif);
 
+#include <linux/atomic.h>
+
+static inline int xenvif_atomic_fetch_or(int i, atomic_t *v)
+{
+	int c, old;
+
+	c = v->counter;
+	while ((old = cmpxchg(&v->counter, c, c | i)) != c)
+		c = old;
+
+	return c;
+}
+
+static inline int xenvif_atomic_fetch_andnot(int i, atomic_t *v)
+{
+	int c, old;
+
+	c = v->counter;
+	while ((old = cmpxchg(&v->counter, c, c & ~i)) != c)
+		c = old;
+
+	return c;
+}
+
 #endif /* __XEN_NETBACK__COMMON_H__ */
--- linux-4.4.0.orig/drivers/net/xen-netback/interface.c
+++ linux-4.4.0/drivers/net/xen-netback/interface.c
@@ -76,12 +76,28 @@
 		!vif->disabled;
 }
 
+static bool xenvif_handle_tx_interrupt(struct xenvif_queue *queue)
+{
+	bool rc;
+
+	rc = RING_HAS_UNCONSUMED_REQUESTS(&queue->tx);
+	if (rc)
+		napi_schedule(&queue->napi);
+	return rc;
+}
+
 static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id)
 {
 	struct xenvif_queue *queue = dev_id;
+	int old;
 
-	if (RING_HAS_UNCONSUMED_REQUESTS(&queue->tx))
-		napi_schedule(&queue->napi);
+	old = xenvif_atomic_fetch_or(NETBK_TX_EOI, &queue->eoi_pending);
+	WARN(old & NETBK_TX_EOI, "Interrupt while EOI pending\n");
+
+	if (!xenvif_handle_tx_interrupt(queue)) {
+		atomic_andnot(NETBK_TX_EOI, &queue->eoi_pending);
+		xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -105,25 +121,58 @@
 
 	if (work_done < budget) {
 		napi_complete(napi);
-		xenvif_napi_schedule_or_enable_events(queue);
+		/* If the queue is rate-limited, it shall be
+		 * rescheduled in the timer callback.
+		 */
+		if (likely(!queue->rate_limited))
+			xenvif_napi_schedule_or_enable_events(queue);
 	}
 
 	return work_done;
 }
 
+static bool xenvif_handle_rx_interrupt(struct xenvif_queue *queue)
+{
+	bool rc;
+
+	rc = xenvif_have_rx_work(queue, false);
+	if (rc)
+		xenvif_kick_thread(queue);
+	return rc;
+}
+
 static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id)
 {
 	struct xenvif_queue *queue = dev_id;
+	int old;
 
-	xenvif_kick_thread(queue);
+	old = xenvif_atomic_fetch_or(NETBK_RX_EOI, &queue->eoi_pending);
+	WARN(old & NETBK_RX_EOI, "Interrupt while EOI pending\n");
+
+	if (!xenvif_handle_rx_interrupt(queue)) {
+		atomic_andnot(NETBK_RX_EOI, &queue->eoi_pending);
+		xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
+	}
 
 	return IRQ_HANDLED;
 }
 
 irqreturn_t xenvif_interrupt(int irq, void *dev_id)
 {
-	xenvif_tx_interrupt(irq, dev_id);
-	xenvif_rx_interrupt(irq, dev_id);
+	struct xenvif_queue *queue = dev_id;
+	int old;
+	bool has_rx, has_tx;
+
+	old = xenvif_atomic_fetch_or(NETBK_COMMON_EOI, &queue->eoi_pending);
+	WARN(old, "Interrupt while EOI pending\n");
+
+	has_tx = xenvif_handle_tx_interrupt(queue);
+	has_rx = xenvif_handle_rx_interrupt(queue);
+
+	if (!has_rx && !has_tx) {
+		atomic_andnot(NETBK_COMMON_EOI, &queue->eoi_pending);
+		xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -551,7 +600,7 @@
 
 	if (tx_evtchn == rx_evtchn) {
 		/* feature-split-event-channels == 0 */
-		err = bind_interdomain_evtchn_to_irqhandler(
+		err = bind_interdomain_evtchn_to_irqhandler_lateeoi(
 			queue->vif->domid, tx_evtchn, xenvif_interrupt, 0,
 			queue->name, queue);
 		if (err < 0)
@@ -562,7 +611,7 @@
 		/* feature-split-event-channels == 1 */
 		snprintf(queue->tx_irq_name, sizeof(queue->tx_irq_name),
 			 "%s-tx", queue->name);
-		err = bind_interdomain_evtchn_to_irqhandler(
+		err = bind_interdomain_evtchn_to_irqhandler_lateeoi(
 			queue->vif->domid, tx_evtchn, xenvif_tx_interrupt, 0,
 			queue->tx_irq_name, queue);
 		if (err < 0)
@@ -572,7 +621,7 @@
 
 		snprintf(queue->rx_irq_name, sizeof(queue->rx_irq_name),
 			 "%s-rx", queue->name);
-		err = bind_interdomain_evtchn_to_irqhandler(
+		err = bind_interdomain_evtchn_to_irqhandler_lateeoi(
 			queue->vif->domid, rx_evtchn, xenvif_rx_interrupt, 0,
 			queue->rx_irq_name, queue);
 		if (err < 0)
@@ -615,8 +664,8 @@
 	queue->tx_irq = 0;
 err_unmap:
 	xenvif_unmap_frontend_rings(queue);
+	netif_napi_del(&queue->napi);
 err:
-	module_put(THIS_MODULE);
 	return err;
 }
 
--- linux-4.4.0.orig/drivers/net/xen-netback/netback.c
+++ linux-4.4.0/drivers/net/xen-netback/netback.c
@@ -67,6 +67,7 @@
 unsigned int rx_stall_timeout_msecs = 60000;
 module_param(rx_stall_timeout_msecs, uint, 0444);
 
+#define MAX_QUEUES_DEFAULT 8
 unsigned int xenvif_max_queues;
 module_param_named(max_queues, xenvif_max_queues, uint, 0644);
 MODULE_PARM_DESC(max_queues,
@@ -95,6 +96,7 @@
 
 static void make_tx_response(struct xenvif_queue *queue,
 			     struct xen_netif_tx_request *txp,
+			     unsigned int extra_count,
 			     s8       st);
 static void push_tx_responses(struct xenvif_queue *queue);
 
@@ -669,6 +671,10 @@
 
 	if (more_to_do)
 		napi_schedule(&queue->napi);
+	else if (xenvif_atomic_fetch_andnot(NETBK_TX_EOI | NETBK_COMMON_EOI,
+				     &queue->eoi_pending) &
+		 (NETBK_TX_EOI | NETBK_COMMON_EOI))
+		xen_irq_lateeoi(queue->tx_irq, 0);
 }
 
 static void tx_add_credit(struct xenvif_queue *queue)
@@ -687,6 +693,7 @@
 		max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
 
 	queue->remaining_credit = min(max_credit, max_burst);
+	queue->rate_limited = false;
 }
 
 void xenvif_tx_credit_callback(unsigned long data)
@@ -697,19 +704,21 @@
 }
 
 static void xenvif_tx_err(struct xenvif_queue *queue,
-			  struct xen_netif_tx_request *txp, RING_IDX end)
+			  struct xen_netif_tx_request *txp,
+			  unsigned int extra_count, RING_IDX end)
 {
 	RING_IDX cons = queue->tx.req_cons;
 	unsigned long flags;
 
 	do {
 		spin_lock_irqsave(&queue->response_lock, flags);
-		make_tx_response(queue, txp, XEN_NETIF_RSP_ERROR);
+		make_tx_response(queue, txp, extra_count, XEN_NETIF_RSP_ERROR);
 		push_tx_responses(queue);
 		spin_unlock_irqrestore(&queue->response_lock, flags);
 		if (cons == end)
 			break;
 		RING_COPY_REQUEST(&queue->tx, cons++, txp);
+		extra_count = 0; /* only the first frag can have extras */
 	} while (1);
 	queue->tx.req_cons = cons;
 }
@@ -725,6 +734,7 @@
 
 static int xenvif_count_requests(struct xenvif_queue *queue,
 				 struct xen_netif_tx_request *first,
+				 unsigned int extra_count,
 				 struct xen_netif_tx_request *txp,
 				 int work_to_do)
 {
@@ -813,7 +823,7 @@
 	} while (more_data);
 
 	if (drop_err) {
-		xenvif_tx_err(queue, first, cons + slots);
+		xenvif_tx_err(queue, first, extra_count, cons + slots);
 		return drop_err;
 	}
 
@@ -822,15 +832,19 @@
 
 
 struct xenvif_tx_cb {
-	u16 pending_idx;
+	u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1];
+	u8 copy_count;
 };
 
 #define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
+#define copy_pending_idx(skb, i) (XENVIF_TX_CB(skb)->copy_pending_idx[i])
+#define copy_count(skb) (XENVIF_TX_CB(skb)->copy_count)
 
 static inline void xenvif_tx_create_map_op(struct xenvif_queue *queue,
-					  u16 pending_idx,
-					  struct xen_netif_tx_request *txp,
-					  struct gnttab_map_grant_ref *mop)
+					   u16 pending_idx,
+					   struct xen_netif_tx_request *txp,
+					   unsigned int extra_count,
+					   struct gnttab_map_grant_ref *mop)
 {
 	queue->pages_to_map[mop-queue->tx_map_ops] = queue->mmap_pages[pending_idx];
 	gnttab_set_map_op(mop, idx_to_kaddr(queue, pending_idx),
@@ -839,6 +853,7 @@
 
 	memcpy(&queue->pending_tx_info[pending_idx].req, txp,
 	       sizeof(*txp));
+	queue->pending_tx_info[pending_idx].extra_count = extra_count;
 }
 
 static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
@@ -858,51 +873,120 @@
 	return skb;
 }
 
-static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *queue,
-							struct sk_buff *skb,
-							struct xen_netif_tx_request *txp,
-							struct gnttab_map_grant_ref *gop,
-							unsigned int frag_overflow,
-							struct sk_buff *nskb)
+static void xenvif_get_requests(struct xenvif_queue *queue,
+				struct sk_buff *skb,
+				struct xen_netif_tx_request *first,
+				struct xen_netif_tx_request *txfrags,
+			        unsigned *copy_ops,
+			        unsigned *map_ops,
+				unsigned int frag_overflow,
+				struct sk_buff *nskb,
+				unsigned int extra_count,
+				unsigned int data_len)
 {
 	struct skb_shared_info *shinfo = skb_shinfo(skb);
 	skb_frag_t *frags = shinfo->frags;
-	u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
-	int start;
+	u16 pending_idx;
 	pending_ring_idx_t index;
 	unsigned int nr_slots;
+	struct gnttab_copy *cop = queue->tx_copy_ops + *copy_ops;
+	struct gnttab_map_grant_ref *gop = queue->tx_map_ops + *map_ops;
+	struct xen_netif_tx_request *txp = first;
+
+	nr_slots = shinfo->nr_frags + frag_overflow + 1;
+
+	copy_count(skb) = 0;
+
+	/* Create copy ops for exactly data_len bytes into the skb head. */
+	__skb_put(skb, data_len);
+	while (data_len > 0) {
+		int amount = data_len > txp->size ? txp->size : data_len;
+
+		cop->source.u.ref = txp->gref;
+		cop->source.domid = queue->vif->domid;
+		cop->source.offset = txp->offset;
+
+		cop->dest.domid = DOMID_SELF;
+		cop->dest.offset = (offset_in_page(skb->data +
+						   skb_headlen(skb) -
+						   data_len)) & ~XEN_PAGE_MASK;
+		cop->dest.u.gmfn = virt_to_gfn(skb->data + skb_headlen(skb)
+				               - data_len);
 
-	nr_slots = shinfo->nr_frags;
+		cop->len = amount;
+		cop->flags = GNTCOPY_source_gref;
 
-	/* Skip first skb fragment if it is on same page as header fragment. */
-	start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
+		index = pending_index(queue->pending_cons);
+		pending_idx = queue->pending_ring[index];
+		callback_param(queue, pending_idx).ctx = NULL;
+		copy_pending_idx(skb, copy_count(skb)) = pending_idx;
+		copy_count(skb)++;
+
+		cop++;
+		data_len -= amount;
 
-	for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots;
-	     shinfo->nr_frags++, txp++, gop++) {
+		if (amount == txp->size) {
+			/* The copy op covered the full tx_request */
+
+			memcpy(&queue->pending_tx_info[pending_idx].req,
+			       txp, sizeof(*txp));
+			queue->pending_tx_info[pending_idx].extra_count =
+				(txp == first) ? extra_count : 0;
+
+			if (txp == first)
+				txp = txfrags;
+			else
+				txp++;
+			queue->pending_cons++;
+			nr_slots--;
+		} else {
+			/* The copy op partially covered the tx_request.
+			 * The remainder will be mapped.
+			 */
+			txp->offset += amount;
+			txp->size -= amount;
+		}
+	}
+
+	for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS;
+	     shinfo->nr_frags++, gop++, nr_slots--) {
 		index = pending_index(queue->pending_cons++);
 		pending_idx = queue->pending_ring[index];
-		xenvif_tx_create_map_op(queue, pending_idx, txp, gop);
+		xenvif_tx_create_map_op(queue, pending_idx, txp,
+				        txp == first ? extra_count : 0, gop);
 		frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx);
+
+		if (txp == first)
+			txp = txfrags;
+		else
+			txp++;
 	}
 
-	if (frag_overflow) {
+	if (nr_slots > 0) {
 
 		shinfo = skb_shinfo(nskb);
 		frags = shinfo->frags;
 
-		for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow;
+		for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots;
 		     shinfo->nr_frags++, txp++, gop++) {
 			index = pending_index(queue->pending_cons++);
 			pending_idx = queue->pending_ring[index];
-			xenvif_tx_create_map_op(queue, pending_idx, txp, gop);
+			xenvif_tx_create_map_op(queue, pending_idx, txp, 0,
+						gop);
 			frag_set_pending_idx(&frags[shinfo->nr_frags],
 					     pending_idx);
 		}
 
 		skb_shinfo(skb)->frag_list = nskb;
+	} else if (nskb) {
+		/* A frag_list skb was allocated but it is no longer needed
+		 * because enough slots were converted to copy ops above.
+		 */
+		kfree_skb(nskb);
 	}
 
-	return gop;
+	(*copy_ops) = cop - queue->tx_copy_ops;
+	(*map_ops) = gop - queue->tx_map_ops;
 }
 
 static inline void xenvif_grant_handle_set(struct xenvif_queue *queue,
@@ -938,7 +1022,7 @@
 			       struct gnttab_copy **gopp_copy)
 {
 	struct gnttab_map_grant_ref *gop_map = *gopp_map;
-	u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+	u16 pending_idx;
 	/* This always points to the shinfo of the skb being checked, which
 	 * could be either the first or the one on the frag_list
 	 */
@@ -949,24 +1033,37 @@
 	struct skb_shared_info *first_shinfo = NULL;
 	int nr_frags = shinfo->nr_frags;
 	const bool sharedslot = nr_frags &&
-				frag_get_pending_idx(&shinfo->frags[0]) == pending_idx;
-	int i, err;
+				frag_get_pending_idx(&shinfo->frags[0]) ==
+				    copy_pending_idx(skb, copy_count(skb) - 1);
+	int i, err = 0;
 
-	/* Check status of header. */
-	err = (*gopp_copy)->status;
-	if (unlikely(err)) {
-		if (net_ratelimit())
-			netdev_dbg(queue->vif->dev,
-				   "Grant copy of header failed! status: %d pending_idx: %u ref: %u\n",
-				   (*gopp_copy)->status,
-				   pending_idx,
-				   (*gopp_copy)->source.u.ref);
-		/* The first frag might still have this slot mapped */
-		if (!sharedslot)
-			xenvif_idx_release(queue, pending_idx,
-					   XEN_NETIF_RSP_ERROR);
+	for (i = 0; i < copy_count(skb); i++) {
+		int newerr;
+
+		/* Check status of header. */
+		pending_idx = copy_pending_idx(skb, i);
+
+		newerr = (*gopp_copy)->status;
+		if (likely(!newerr)) {
+			/* The first frag might still have this slot mapped */
+			if (i < copy_count(skb) - 1 || !sharedslot)
+				xenvif_idx_release(queue, pending_idx,
+						   XEN_NETIF_RSP_OKAY);
+		} else {
+			err = newerr;
+			if (net_ratelimit())
+				netdev_dbg(queue->vif->dev,
+					   "Grant copy of header failed! status: %d pending_idx: %u ref: %u\n",
+					   (*gopp_copy)->status,
+					   pending_idx,
+					   (*gopp_copy)->source.u.ref);
+			/* The first frag might still have this slot mapped */
+			if (i < copy_count(skb) - 1 || !sharedslot)
+				xenvif_idx_release(queue, pending_idx,
+						   XEN_NETIF_RSP_ERROR);
+		}
+		(*gopp_copy)++;
 	}
-	(*gopp_copy)++;
 
 check_frags:
 	for (i = 0; i < nr_frags; i++, gop_map++) {
@@ -1013,14 +1110,6 @@
 		if (err)
 			continue;
 
-		/* First error: if the header haven't shared a slot with the
-		 * first frag, release it as well.
-		 */
-		if (!sharedslot)
-			xenvif_idx_release(queue,
-					   XENVIF_TX_CB(skb)->pending_idx,
-					   XEN_NETIF_RSP_OKAY);
-
 		/* Invalidate preceding fragments of this skb. */
 		for (j = 0; j < i; j++) {
 			pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
@@ -1096,8 +1185,9 @@
 }
 
 static int xenvif_get_extras(struct xenvif_queue *queue,
-				struct xen_netif_extra_info *extras,
-				int work_to_do)
+			     struct xen_netif_extra_info *extras,
+			     unsigned int *extra_count,
+			     int work_to_do)
 {
 	struct xen_netif_extra_info extra;
 	RING_IDX cons = queue->tx.req_cons;
@@ -1110,9 +1200,12 @@
 		}
 
 		RING_COPY_REQUEST(&queue->tx, cons, &extra);
+
+		queue->tx.req_cons = ++cons;
+		(*extra_count)++;
+
 		if (unlikely(!extra.type ||
 			     extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
-			queue->tx.req_cons = ++cons;
 			netdev_err(queue->vif->dev,
 				   "Invalid extra type: %d\n", extra.type);
 			xenvif_fatal_tx_err(queue->vif);
@@ -1120,7 +1213,6 @@
 		}
 
 		memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
-		queue->tx.req_cons = ++cons;
 	} while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
 
 	return work_to_do;
@@ -1184,8 +1276,10 @@
 		msecs_to_jiffies(queue->credit_usec / 1000);
 
 	/* Timer could already be pending in rare cases. */
-	if (timer_pending(&queue->credit_timeout))
+	if (timer_pending(&queue->credit_timeout)) {
+		queue->rate_limited = true;
 		return true;
+	}
 
 	/* Passed the point where we can replenish credit? */
 	if (time_after_eq64(now, next_credit)) {
@@ -1200,6 +1294,7 @@
 		mod_timer(&queue->credit_timeout,
 			  next_credit);
 		queue->credit_window_start = next_credit;
+		queue->rate_limited = true;
 
 		return true;
 	}
@@ -1286,7 +1381,6 @@
 				     unsigned *copy_ops,
 				     unsigned *map_ops)
 {
-	struct gnttab_map_grant_ref *gop = queue->tx_map_ops;
 	struct sk_buff *skb, *nskb;
 	int ret;
 	unsigned int frag_overflow;
@@ -1295,6 +1389,7 @@
 		struct xen_netif_tx_request txreq;
 		struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX];
 		struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
+		unsigned int extra_count;
 		u16 pending_idx;
 		RING_IDX idx;
 		int work_to_do;
@@ -1331,8 +1426,10 @@
 		queue->tx.req_cons = ++idx;
 
 		memset(extras, 0, sizeof(extras));
+		extra_count = 0;
 		if (txreq.flags & XEN_NETTXF_extra_info) {
 			work_to_do = xenvif_get_extras(queue, extras,
+						       &extra_count,
 						       work_to_do);
 			idx = queue->tx.req_cons;
 			if (unlikely(work_to_do < 0))
@@ -1345,7 +1442,7 @@
 			extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_ADD - 1];
 			ret = xenvif_mcast_add(queue->vif, extra->u.mcast.addr);
 
-			make_tx_response(queue, &txreq,
+			make_tx_response(queue, &txreq, extra_count,
 					 (ret == 0) ?
 					 XEN_NETIF_RSP_OKAY :
 					 XEN_NETIF_RSP_ERROR);
@@ -1359,12 +1456,18 @@
 			extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_DEL - 1];
 			xenvif_mcast_del(queue->vif, extra->u.mcast.addr);
 
-			make_tx_response(queue, &txreq, XEN_NETIF_RSP_OKAY);
+			make_tx_response(queue, &txreq, extra_count,
+					 XEN_NETIF_RSP_OKAY);
 			push_tx_responses(queue);
 			continue;
 		}
 
-		ret = xenvif_count_requests(queue, &txreq, txfrags, work_to_do);
+		data_len = (txreq.size > XEN_NETBACK_TX_COPY_LEN) ?
+			XEN_NETBACK_TX_COPY_LEN : txreq.size;
+
+		ret = xenvif_count_requests(queue, &txreq, extra_count,
+					    txfrags, work_to_do);
+
 		if (unlikely(ret < 0))
 			break;
 
@@ -1373,7 +1476,7 @@
 		if (unlikely(txreq.size < ETH_HLEN)) {
 			netdev_dbg(queue->vif->dev,
 				   "Bad packet size: %d\n", txreq.size);
-			xenvif_tx_err(queue, &txreq, idx);
+			xenvif_tx_err(queue, &txreq, extra_count, idx);
 			break;
 		}
 
@@ -1390,21 +1493,18 @@
 		index = pending_index(queue->pending_cons);
 		pending_idx = queue->pending_ring[index];
 
-		data_len = (txreq.size > XEN_NETBACK_TX_COPY_LEN &&
-			    ret < XEN_NETBK_LEGACY_SLOTS_MAX) ?
-			XEN_NETBACK_TX_COPY_LEN : txreq.size;
+		if (ret >= XEN_NETBK_LEGACY_SLOTS_MAX - 1 && data_len < txreq.size)
+			data_len = txreq.size;
 
 		skb = xenvif_alloc_skb(data_len);
 		if (unlikely(skb == NULL)) {
 			netdev_dbg(queue->vif->dev,
 				   "Can't allocate a skb in start_xmit.\n");
-			xenvif_tx_err(queue, &txreq, idx);
+			xenvif_tx_err(queue, &txreq, extra_count, idx);
 			break;
 		}
 
 		skb_shinfo(skb)->nr_frags = ret;
-		if (data_len < txreq.size)
-			skb_shinfo(skb)->nr_frags++;
 		/* At this point shinfo->nr_frags is in fact the number of
 		 * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
 		 */
@@ -1416,8 +1516,9 @@
 			skb_shinfo(skb)->nr_frags = MAX_SKB_FRAGS;
 			nskb = xenvif_alloc_skb(0);
 			if (unlikely(nskb == NULL)) {
+				skb_shinfo(skb)->nr_frags = 0;
 				kfree_skb(skb);
-				xenvif_tx_err(queue, &txreq, idx);
+				xenvif_tx_err(queue, &txreq, extra_count, idx);
 				if (net_ratelimit())
 					netdev_err(queue->vif->dev,
 						   "Can't allocate the frag_list skb.\n");
@@ -1431,57 +1532,26 @@
 
 			if (xenvif_set_skb_gso(queue->vif, skb, gso)) {
 				/* Failure in xenvif_set_skb_gso is fatal. */
+				skb_shinfo(skb)->nr_frags = 0;
 				kfree_skb(skb);
 				kfree_skb(nskb);
 				break;
 			}
 		}
 
-		XENVIF_TX_CB(skb)->pending_idx = pending_idx;
-
-		__skb_put(skb, data_len);
-		queue->tx_copy_ops[*copy_ops].source.u.ref = txreq.gref;
-		queue->tx_copy_ops[*copy_ops].source.domid = queue->vif->domid;
-		queue->tx_copy_ops[*copy_ops].source.offset = txreq.offset;
-
-		queue->tx_copy_ops[*copy_ops].dest.u.gmfn =
-			virt_to_gfn(skb->data);
-		queue->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF;
-		queue->tx_copy_ops[*copy_ops].dest.offset =
-			offset_in_page(skb->data) & ~XEN_PAGE_MASK;
-
-		queue->tx_copy_ops[*copy_ops].len = data_len;
-		queue->tx_copy_ops[*copy_ops].flags = GNTCOPY_source_gref;
-
-		(*copy_ops)++;
-
-		if (data_len < txreq.size) {
-			frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
-					     pending_idx);
-			xenvif_tx_create_map_op(queue, pending_idx, &txreq, gop);
-			gop++;
-		} else {
-			frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
-					     INVALID_PENDING_IDX);
-			memcpy(&queue->pending_tx_info[pending_idx].req, &txreq,
-			       sizeof(txreq));
-		}
-
-		queue->pending_cons++;
-
-		gop = xenvif_get_requests(queue, skb, txfrags, gop,
-				          frag_overflow, nskb);
+		xenvif_get_requests(queue, skb, &txreq, txfrags, copy_ops,
+				    map_ops, frag_overflow, nskb, extra_count,
+				    data_len);
 
 		__skb_queue_tail(&queue->tx_queue, skb);
 
 		queue->tx.req_cons = idx;
 
-		if (((gop-queue->tx_map_ops) >= ARRAY_SIZE(queue->tx_map_ops)) ||
+		if ((*map_ops >= ARRAY_SIZE(queue->tx_map_ops)) ||
 		    (*copy_ops >= ARRAY_SIZE(queue->tx_copy_ops)))
 			break;
 	}
 
-	(*map_ops) = gop - queue->tx_map_ops;
 	return;
 }
 
@@ -1533,11 +1603,6 @@
 		skb_frag_size_set(&frags[i], len);
 	}
 
-	/* Copied all the bits from the frag list -- free it. */
-	skb_frag_list_init(skb);
-	xenvif_skb_zerocopy_prepare(queue, nskb);
-	kfree_skb(nskb);
-
 	/* Release all the original (foreign) frags. */
 	for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
 		skb_frag_unref(skb, f);
@@ -1565,9 +1630,8 @@
 	while ((skb = __skb_dequeue(&queue->tx_queue)) != NULL) {
 		struct xen_netif_tx_request *txp;
 		u16 pending_idx;
-		unsigned data_len;
 
-		pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+		pending_idx = copy_pending_idx(skb, 0);
 		txp = &queue->pending_tx_info[pending_idx].req;
 
 		/* Check the remap error code. */
@@ -1586,18 +1650,6 @@
 			continue;
 		}
 
-		data_len = skb->len;
-		callback_param(queue, pending_idx).ctx = NULL;
-		if (data_len < txp->size) {
-			/* Append the packet payload as a fragment. */
-			txp->offset += data_len;
-			txp->size -= data_len;
-		} else {
-			/* Schedule a response immediately. */
-			xenvif_idx_release(queue, pending_idx,
-					   XEN_NETIF_RSP_OKAY);
-		}
-
 		if (txp->flags & XEN_NETTXF_csum_blank)
 			skb->ip_summed = CHECKSUM_PARTIAL;
 		else if (txp->flags & XEN_NETTXF_data_validated)
@@ -1606,6 +1658,8 @@
 		xenvif_fill_frags(queue, skb);
 
 		if (unlikely(skb_has_frag_list(skb))) {
+			struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
+			xenvif_skb_zerocopy_prepare(queue, nskb);
 			if (xenvif_handle_frag_list(queue, skb)) {
 				if (net_ratelimit())
 					netdev_err(queue->vif->dev,
@@ -1614,6 +1668,9 @@
 				kfree_skb(skb);
 				continue;
 			}
+			/* Copied all the bits from the frag list -- free it. */
+			skb_frag_list_init(skb);
+			kfree_skb(nskb);
 		}
 
 		skb->dev      = queue->vif->dev;
@@ -1769,7 +1826,7 @@
 /* Called after netfront has transmitted */
 int xenvif_tx_action(struct xenvif_queue *queue, int budget)
 {
-	unsigned nr_mops, nr_cops = 0;
+	unsigned nr_mops = 0, nr_cops = 0;
 	int work_done, ret;
 
 	if (unlikely(!tx_work_todo(queue)))
@@ -1786,7 +1843,15 @@
 				      NULL,
 				      queue->pages_to_map,
 				      nr_mops);
-		BUG_ON(ret);
+		if (ret) {
+			unsigned int i;
+
+			netdev_err(queue->vif->dev, "Map fail: nr %u ret %d\n",
+				   nr_mops, ret);
+			for (i = 0; i < nr_mops; ++i)
+				WARN_ON_ONCE(queue->tx_map_ops[i].status ==
+				             GNTST_okay);
+		}
 	}
 
 	work_done = xenvif_tx_submit(queue);
@@ -1805,7 +1870,8 @@
 
 	spin_lock_irqsave(&queue->response_lock, flags);
 
-	make_tx_response(queue, &pending_tx_info->req, status);
+	make_tx_response(queue, &pending_tx_info->req,
+			 pending_tx_info->extra_count, status);
 
 	/* Release the pending index before pusing the Tx response so
 	 * its available before a new Tx request is pushed by the
@@ -1822,6 +1888,7 @@
 
 static void make_tx_response(struct xenvif_queue *queue,
 			     struct xen_netif_tx_request *txp,
+			     unsigned int extra_count,
 			     s8       st)
 {
 	RING_IDX i = queue->tx.rsp_prod_pvt;
@@ -1831,7 +1898,7 @@
 	resp->id     = txp->id;
 	resp->status = st;
 
-	if (txp->flags & XEN_NETTXF_extra_info)
+	while (extra_count-- != 0)
 		RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
 
 	queue->tx.rsp_prod_pvt = ++i;
@@ -2003,14 +2070,14 @@
 	return queue->stalled && prod - cons >= 1;
 }
 
-static bool xenvif_have_rx_work(struct xenvif_queue *queue)
+bool xenvif_have_rx_work(struct xenvif_queue *queue, bool test_kthread)
 {
 	return (!skb_queue_empty(&queue->rx_queue)
 		&& xenvif_rx_ring_slots_available(queue))
 		|| (queue->vif->stall_timeout &&
 		    (xenvif_rx_queue_stalled(queue)
 		     || xenvif_rx_queue_ready(queue)))
-		|| kthread_should_stop()
+		|| (test_kthread && kthread_should_stop())
 		|| queue->vif->disabled;
 }
 
@@ -2041,15 +2108,20 @@
 {
 	DEFINE_WAIT(wait);
 
-	if (xenvif_have_rx_work(queue))
+	if (xenvif_have_rx_work(queue, true))
 		return;
 
 	for (;;) {
 		long ret;
 
 		prepare_to_wait(&queue->wq, &wait, TASK_INTERRUPTIBLE);
-		if (xenvif_have_rx_work(queue))
+		if (xenvif_have_rx_work(queue, true))
 			break;
+		if (xenvif_atomic_fetch_andnot(NETBK_RX_EOI | NETBK_COMMON_EOI,
+					&queue->eoi_pending) &
+		    (NETBK_RX_EOI | NETBK_COMMON_EOI))
+			xen_irq_lateeoi(queue->rx_irq, 0);
+
 		ret = schedule_timeout(xenvif_rx_queue_timeout(queue));
 		if (!ret)
 			break;
@@ -2153,11 +2225,12 @@
 	if (!xen_domain())
 		return -ENODEV;
 
-	/* Allow as many queues as there are CPUs if user has not
+	/* Allow as many queues as there are CPUs but max. 8 if user has not
 	 * specified a value.
 	 */
 	if (xenvif_max_queues == 0)
-		xenvif_max_queues = num_online_cpus();
+		xenvif_max_queues = min_t(unsigned int, MAX_QUEUES_DEFAULT,
+					  num_online_cpus());
 
 	if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) {
 		pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n",
--- linux-4.4.0.orig/drivers/net/xen-netback/xenbus.c
+++ linux-4.4.0/drivers/net/xen-netback/xenbus.c
@@ -697,12 +697,14 @@
 		return -ENOMEM;
 	snprintf(node, maxlen, "%s/rate", dev->nodename);
 	vif->credit_watch.node = node;
+	vif->credit_watch.will_handle = NULL;
 	vif->credit_watch.callback = xen_net_rate_changed;
 	err = register_xenbus_watch(&vif->credit_watch);
 	if (err) {
 		pr_err("Failed to set watcher %s\n", vif->credit_watch.node);
 		kfree(node);
 		vif->credit_watch.node = NULL;
+		vif->credit_watch.will_handle = NULL;
 		vif->credit_watch.callback = NULL;
 	}
 	return err;
@@ -847,7 +849,7 @@
 	xenvif_carrier_on(be->vif);
 
 	unregister_hotplug_status_watch(be);
-	err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
+	err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, NULL,
 				   hotplug_status_changed,
 				   "%s/%s", dev->nodename, "hotplug-status");
 	if (!err)
--- linux-4.4.0.orig/drivers/net/xen-netfront.c
+++ linux-4.4.0/drivers/net/xen-netfront.c
@@ -62,6 +62,12 @@
 MODULE_PARM_DESC(max_queues,
 		 "Maximum number of queues per virtual interface");
 
+static bool __read_mostly xennet_trusted = true;
+module_param_named(trusted, xennet_trusted, bool, 0644);
+MODULE_PARM_DESC(trusted, "Is the backend trusted");
+
+#define XENNET_TIMEOUT  (5 * HZ)
+
 static const struct ethtool_ops xennet_ethtool_ops;
 
 struct netfront_cb {
@@ -86,6 +92,8 @@
 /* IRQ name is queue name with "-tx" or "-rx" appended */
 #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3)
 
+static DECLARE_WAIT_QUEUE_HEAD(module_wq);
+
 struct netfront_stats {
 	u64			packets;
 	u64			bytes;
@@ -116,21 +124,17 @@
 
 	/*
 	 * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
-	 * are linked from tx_skb_freelist through skb_entry.link.
-	 *
-	 *  NB. Freelist index entries are always going to be less than
-	 *  PAGE_OFFSET, whereas pointers to skbs will always be equal or
-	 *  greater than PAGE_OFFSET: we use this property to distinguish
-	 *  them.
+	 * are linked from tx_skb_freelist through tx_link.
 	 */
-	union skb_entry {
-		struct sk_buff *skb;
-		unsigned long link;
-	} tx_skbs[NET_TX_RING_SIZE];
+	struct sk_buff *tx_skbs[NET_TX_RING_SIZE];
+	unsigned short tx_link[NET_TX_RING_SIZE];
+#define TX_LINK_NONE 0xffff
+#define TX_PENDING   0xfffe
 	grant_ref_t gref_tx_head;
 	grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
 	struct page *grant_tx_page[NET_TX_RING_SIZE];
 	unsigned tx_skb_freelist;
+	unsigned int tx_pend_queue;
 
 	spinlock_t   rx_lock ____cacheline_aligned_in_smp;
 	struct xen_netif_rx_front_ring rx;
@@ -141,6 +145,9 @@
 	struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
 	grant_ref_t gref_rx_head;
 	grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
+
+	unsigned int rx_rsp_unconsumed;
+	spinlock_t rx_cons_lock;
 };
 
 struct netfront_info {
@@ -156,6 +163,12 @@
 	struct netfront_stats __percpu *rx_stats;
 	struct netfront_stats __percpu *tx_stats;
 
+	/* Should skbs be bounced into a zeroed buffer? */
+	bool bounce;
+
+	/* Is device behaving sane? */
+	bool broken;
+
 	atomic_t rx_gso_checksum_fixup;
 };
 
@@ -164,33 +177,25 @@
 	struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
 };
 
-static void skb_entry_set_link(union skb_entry *list, unsigned short id)
-{
-	list->link = id;
-}
-
-static int skb_entry_is_link(const union skb_entry *list)
-{
-	BUILD_BUG_ON(sizeof(list->skb) != sizeof(list->link));
-	return (unsigned long)list->skb < PAGE_OFFSET;
-}
-
 /*
  * Access macros for acquiring freeing slots in tx_skbs[].
  */
 
-static void add_id_to_freelist(unsigned *head, union skb_entry *list,
-			       unsigned short id)
+static void add_id_to_list(unsigned *head, unsigned short *list,
+			   unsigned short id)
 {
-	skb_entry_set_link(&list[id], *head);
+	list[id] = *head;
 	*head = id;
 }
 
-static unsigned short get_id_from_freelist(unsigned *head,
-					   union skb_entry *list)
+static unsigned short get_id_from_list(unsigned *head, unsigned short *list)
 {
 	unsigned int id = *head;
-	*head = list[id].link;
+
+	if (id != TX_LINK_NONE) {
+		*head = list[id];
+		list[id] = TX_LINK_NONE;
+	}
 	return id;
 }
 
@@ -236,7 +241,7 @@
 static int netfront_tx_slot_available(struct netfront_queue *queue)
 {
 	return (queue->tx.req_prod_pvt - queue->tx.rsp_cons) <
-		(NET_TX_RING_SIZE - MAX_SKB_FRAGS - 2);
+		(NET_TX_RING_SIZE - XEN_NETIF_NR_SLOTS_MIN - 1);
 }
 
 static void xennet_maybe_wake_tx(struct netfront_queue *queue)
@@ -262,7 +267,7 @@
 	if (unlikely(!skb))
 		return NULL;
 
-	page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+	page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO);
 	if (!page) {
 		kfree_skb(skb);
 		return NULL;
@@ -281,6 +286,7 @@
 {
 	RING_IDX req_prod = queue->rx.req_prod_pvt;
 	int notify;
+	int err = 0;
 
 	if (unlikely(!netif_carrier_ok(queue->info->netdev)))
 		return;
@@ -295,8 +301,10 @@
 		struct xen_netif_rx_request *req;
 
 		skb = xennet_alloc_one_rx_buffer(queue);
-		if (!skb)
+		if (!skb) {
+			err = -ENOMEM;
 			break;
+		}
 
 		id = xennet_rxidx(req_prod);
 
@@ -304,7 +312,7 @@
 		queue->rx_skbs[id] = skb;
 
 		ref = gnttab_claim_grant_reference(&queue->gref_rx_head);
-		BUG_ON((signed short)ref < 0);
+		WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref));
 		queue->grant_rx_ref[id] = ref;
 
 		page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
@@ -320,8 +328,13 @@
 
 	queue->rx.req_prod_pvt = req_prod;
 
-	/* Not enough requests? Try again later. */
-	if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN) {
+	/* Try again later if there are not enough requests or skb allocation
+	 * failed.
+	 * Enough requests is quantified as the sum of newly created slots and
+	 * the unconsumed slots at the backend.
+	 */
+	if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN ||
+	    unlikely(err)) {
 		mod_timer(&queue->rx_refill_timer, jiffies + (HZ/10));
 		return;
 	}
@@ -340,6 +353,9 @@
 	unsigned int i = 0;
 	struct netfront_queue *queue = NULL;
 
+	if (!np->queues || np->broken)
+		return -ENODEV;
+
 	for (i = 0; i < num_queues; ++i) {
 		queue = &np->queues[i];
 		napi_enable(&queue->napi);
@@ -359,32 +375,55 @@
 	return 0;
 }
 
-static void xennet_tx_buf_gc(struct netfront_queue *queue)
+static bool xennet_tx_buf_gc(struct netfront_queue *queue)
 {
 	RING_IDX cons, prod;
 	unsigned short id;
 	struct sk_buff *skb;
+	bool work_done = false;
+	const struct device *dev = &queue->info->netdev->dev;
 
 	BUG_ON(!netif_carrier_ok(queue->info->netdev));
 
 	do {
 		prod = queue->tx.sring->rsp_prod;
+		if (RING_RESPONSE_PROD_OVERFLOW(&queue->tx, prod)) {
+			dev_alert(dev, "Illegal number of responses %u\n",
+				  prod - queue->tx.rsp_cons);
+			goto err;
+		}
 		rmb(); /* Ensure we see responses up to 'rp'. */
 
 		for (cons = queue->tx.rsp_cons; cons != prod; cons++) {
-			struct xen_netif_tx_response *txrsp;
+			struct xen_netif_tx_response txrsp;
+
+			work_done = true;
 
-			txrsp = RING_GET_RESPONSE(&queue->tx, cons);
-			if (txrsp->status == XEN_NETIF_RSP_NULL)
+			RING_COPY_RESPONSE(&queue->tx, cons, &txrsp);
+			if (txrsp.status == XEN_NETIF_RSP_NULL)
 				continue;
 
-			id  = txrsp->id;
-			skb = queue->tx_skbs[id].skb;
+			id = txrsp.id;
+			if (id >= RING_SIZE(&queue->tx)) {
+				dev_alert(dev,
+					  "Response has incorrect id (%u)\n",
+					  id);
+				goto err;
+			}
+			if (queue->tx_link[id] != TX_PENDING) {
+				dev_alert(dev,
+					  "Response for inactive request\n");
+				goto err;
+			}
+
+			queue->tx_link[id] = TX_LINK_NONE;
+			skb = queue->tx_skbs[id];
+			queue->tx_skbs[id] = NULL;
 			if (unlikely(gnttab_query_foreign_access(
 				queue->grant_tx_ref[id]) != 0)) {
-				pr_alert("%s: warning -- grant still in use by backend domain\n",
-					 __func__);
-				BUG();
+				dev_alert(dev,
+					  "Grant still in use by backend domain\n");
+				goto err;
 			}
 			gnttab_end_foreign_access_ref(
 				queue->grant_tx_ref[id], GNTMAP_readonly);
@@ -392,7 +431,7 @@
 				&queue->gref_tx_head, queue->grant_tx_ref[id]);
 			queue->grant_tx_ref[id] = GRANT_INVALID_REF;
 			queue->grant_tx_page[id] = NULL;
-			add_id_to_freelist(&queue->tx_skb_freelist, queue->tx_skbs, id);
+			add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, id);
 			dev_kfree_skb_irq(skb);
 		}
 
@@ -412,6 +451,14 @@
 	} while ((cons == prod) && (prod != queue->tx.sring->rsp_prod));
 
 	xennet_maybe_wake_tx(queue);
+
+	return work_done;
+
+ err:
+	queue->info->broken = true;
+	dev_alert(dev, "Disabled for further use\n");
+
+	return work_done;
 }
 
 struct xennet_gnttab_make_txreq {
@@ -434,15 +481,15 @@
 	struct netfront_queue *queue = info->queue;
 	struct sk_buff *skb = info->skb;
 
-	id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs);
+	id = get_id_from_list(&queue->tx_skb_freelist, queue->tx_link);
 	tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++);
 	ref = gnttab_claim_grant_reference(&queue->gref_tx_head);
-	BUG_ON((signed short)ref < 0);
+	WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref));
 
 	gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id,
 					gfn, GNTMAP_readonly);
 
-	queue->tx_skbs[id].skb = skb;
+	queue->tx_skbs[id] = skb;
 	queue->grant_tx_page[id] = page;
 	queue->grant_tx_ref[id] = ref;
 
@@ -452,6 +499,12 @@
 	tx->size = len;
 	tx->flags = 0;
 
+	/*
+	 * Put the request in the pending queue, it will be set to be pending
+	 * when the producer index is about to be raised.
+	 */
+	add_id_to_list(&queue->tx_pend_queue, queue->tx_link, id);
+
 	info->tx = tx;
 	info->size += tx->size;
 }
@@ -557,6 +610,43 @@
 	return queue_idx;
 }
 
+struct sk_buff *bounce_skb(const struct sk_buff *skb)
+{
+	unsigned int headerlen = skb_headroom(skb);
+	/* Align size to allocate full pages and avoid contiguous data leaks */
+	unsigned int size = ALIGN(skb_end_offset(skb) + skb->data_len,
+				  XEN_PAGE_SIZE);
+	struct sk_buff *n = alloc_skb(size, GFP_ATOMIC | __GFP_ZERO);
+
+	if (!n)
+		return NULL;
+
+	if (!IS_ALIGNED((uintptr_t)n->head, XEN_PAGE_SIZE)) {
+		WARN_ONCE(1, "misaligned skb allocated\n");
+		kfree_skb(n);
+		return NULL;
+	}
+
+	/* Set the data pointer */
+	skb_reserve(n, headerlen);
+	/* Set the tail pointer and length */
+	skb_put(n, skb->len);
+
+	BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len));
+
+	skb_copy_header(n, skb);
+	return n;
+}
+
+static void xennet_mark_tx_pending(struct netfront_queue *queue)
+{
+	unsigned int i;
+
+	while ((i = get_id_from_list(&queue->tx_pend_queue, queue->tx_link)) !=
+		TX_LINK_NONE)
+		queue->tx_link[i] = TX_PENDING;
+}
+
 #define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1)
 
 static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -574,10 +664,13 @@
 	struct netfront_queue *queue = NULL;
 	unsigned int num_queues = dev->real_num_tx_queues;
 	u16 queue_index;
+	struct sk_buff *nskb;
 
 	/* Drop the packet if no queues are set up */
 	if (num_queues < 1)
 		goto drop;
+	if (unlikely(np->broken))
+		goto drop;
 	/* Determine which queue to transmit this SKB on */
 	queue_index = skb_get_queue_mapping(skb);
 	queue = &np->queues[queue_index];
@@ -602,6 +695,24 @@
 
 	page = virt_to_page(skb->data);
 	offset = offset_in_page(skb->data);
+
+	/* The first req should be at least ETH_HLEN size or the packet will be
+	 * dropped by netback.
+	 *
+	 * If the backend is not trusted bounce all data to zeroed pages to
+	 * avoid exposing contiguous data on the granted page not belonging to
+	 * the skb.
+	 */
+	if (np->bounce || unlikely(PAGE_SIZE - offset < ETH_HLEN)) {
+		nskb = bounce_skb(skb);
+		if (!nskb)
+			goto drop;
+		dev_kfree_skb_any(skb);
+		skb = nskb;
+		page = virt_to_page(skb->data);
+		offset = offset_in_page(skb->data);
+	}
+
 	len = skb_headlen(skb);
 
 	spin_lock_irqsave(&queue->tx_lock, flags);
@@ -664,6 +775,8 @@
 	/* First request has the packet length. */
 	first_tx->size = skb->len;
 
+	xennet_mark_tx_pending(queue);
+
 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&queue->tx, notify);
 	if (notify)
 		notify_remote_via_irq(queue->tx_irq);
@@ -703,6 +816,16 @@
 	return 0;
 }
 
+static void xennet_set_rx_rsp_cons(struct netfront_queue *queue, RING_IDX val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->rx_cons_lock, flags);
+	queue->rx.rsp_cons = val;
+	queue->rx_rsp_unconsumed = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx);
+	spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
+}
+
 static void xennet_move_rx_slot(struct netfront_queue *queue, struct sk_buff *skb,
 				grant_ref_t ref)
 {
@@ -721,7 +844,7 @@
 			     RING_IDX rp)
 
 {
-	struct xen_netif_extra_info *extra;
+	struct xen_netif_extra_info extra;
 	struct device *dev = &queue->info->netdev->dev;
 	RING_IDX cons = queue->rx.rsp_cons;
 	int err = 0;
@@ -737,26 +860,24 @@
 			break;
 		}
 
-		extra = (struct xen_netif_extra_info *)
-			RING_GET_RESPONSE(&queue->rx, ++cons);
+		RING_COPY_RESPONSE(&queue->rx, ++cons, &extra);
 
-		if (unlikely(!extra->type ||
-			     extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+		if (unlikely(!extra.type ||
+			     extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
 			if (net_ratelimit())
 				dev_warn(dev, "Invalid extra type: %d\n",
-					extra->type);
+					 extra.type);
 			err = -EINVAL;
 		} else {
-			memcpy(&extras[extra->type - 1], extra,
-			       sizeof(*extra));
+			extras[extra.type - 1] = extra;
 		}
 
 		skb = xennet_get_rx_skb(queue, cons);
 		ref = xennet_get_rx_ref(queue, cons);
 		xennet_move_rx_slot(queue, skb, ref);
-	} while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
+	} while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
 
-	queue->rx.rsp_cons = cons;
+	xennet_set_rx_rsp_cons(queue, cons);
 	return err;
 }
 
@@ -764,13 +885,13 @@
 				struct netfront_rx_info *rinfo, RING_IDX rp,
 				struct sk_buff_head *list)
 {
-	struct xen_netif_rx_response *rx = &rinfo->rx;
+	struct xen_netif_rx_response *rx = &rinfo->rx, rx_local;
 	struct xen_netif_extra_info *extras = rinfo->extras;
 	struct device *dev = &queue->info->netdev->dev;
 	RING_IDX cons = queue->rx.rsp_cons;
 	struct sk_buff *skb = xennet_get_rx_skb(queue, cons);
 	grant_ref_t ref = xennet_get_rx_ref(queue, cons);
-	int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
+	int max = XEN_NETIF_NR_SLOTS_MIN + (rx->status <= RX_COPY_THRESHOLD);
 	int slots = 1;
 	int err = 0;
 	unsigned long ret;
@@ -822,7 +943,8 @@
 			break;
 		}
 
-		rx = RING_GET_RESPONSE(&queue->rx, cons + slots);
+		RING_COPY_RESPONSE(&queue->rx, cons + slots, &rx_local);
+		rx = &rx_local;
 		skb = xennet_get_rx_skb(queue, cons + slots);
 		ref = xennet_get_rx_ref(queue, cons + slots);
 		slots++;
@@ -835,7 +957,7 @@
 	}
 
 	if (unlikely(err))
-		queue->rx.rsp_cons = cons + slots;
+		xennet_set_rx_rsp_cons(queue, cons + slots);
 
 	return err;
 }
@@ -869,35 +991,43 @@
 	return 0;
 }
 
-static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
-				  struct sk_buff *skb,
-				  struct sk_buff_head *list)
+static int xennet_fill_frags(struct netfront_queue *queue,
+			     struct sk_buff *skb,
+			     struct sk_buff_head *list)
 {
-	struct skb_shared_info *shinfo = skb_shinfo(skb);
 	RING_IDX cons = queue->rx.rsp_cons;
 	struct sk_buff *nskb;
 
 	while ((nskb = __skb_dequeue(list))) {
-		struct xen_netif_rx_response *rx =
-			RING_GET_RESPONSE(&queue->rx, ++cons);
+		struct xen_netif_rx_response rx;
 		skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0];
 
-		if (shinfo->nr_frags == MAX_SKB_FRAGS) {
+		RING_COPY_RESPONSE(&queue->rx, ++cons, &rx);
+
+		if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) {
 			unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
 
-			BUG_ON(pull_to <= skb_headlen(skb));
+			BUG_ON(pull_to < skb_headlen(skb));
 			__pskb_pull_tail(skb, pull_to - skb_headlen(skb));
 		}
-		BUG_ON(shinfo->nr_frags >= MAX_SKB_FRAGS);
+		if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {
+			xennet_set_rx_rsp_cons(queue,
+					       ++cons + skb_queue_len(list));
+			kfree_skb(nskb);
+			return -ENOENT;
+		}
 
-		skb_add_rx_frag(skb, shinfo->nr_frags, skb_frag_page(nfrag),
-				rx->offset, rx->status, PAGE_SIZE);
+		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+				skb_frag_page(nfrag),
+				rx.offset, rx.status, PAGE_SIZE);
 
 		skb_shinfo(nskb)->nr_frags = 0;
 		kfree_skb(nskb);
 	}
 
-	return cons;
+	xennet_set_rx_rsp_cons(queue, cons);
+
+	return 0;
 }
 
 static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
@@ -982,12 +1112,19 @@
 	skb_queue_head_init(&tmpq);
 
 	rp = queue->rx.sring->rsp_prod;
+	if (RING_RESPONSE_PROD_OVERFLOW(&queue->rx, rp)) {
+		dev_alert(&dev->dev, "Illegal number of responses %u\n",
+			  rp - queue->rx.rsp_cons);
+		queue->info->broken = true;
+		spin_unlock(&queue->rx_lock);
+		return 0;
+	}
 	rmb(); /* Ensure we see queued responses up to 'rp'. */
 
 	i = queue->rx.rsp_cons;
 	work_done = 0;
 	while ((i != rp) && (work_done < budget)) {
-		memcpy(rx, RING_GET_RESPONSE(&queue->rx, i), sizeof(*rx));
+		RING_COPY_RESPONSE(&queue->rx, i, rx);
 		memset(extras, 0, sizeof(rinfo.extras));
 
 		err = xennet_get_responses(queue, &rinfo, rp, &tmpq);
@@ -1009,7 +1146,9 @@
 
 			if (unlikely(xennet_set_skb_gso(skb, gso))) {
 				__skb_queue_head(&tmpq, skb);
-				queue->rx.rsp_cons += skb_queue_len(&tmpq);
+				xennet_set_rx_rsp_cons(queue,
+						       queue->rx.rsp_cons +
+						       skb_queue_len(&tmpq));
 				goto err;
 			}
 		}
@@ -1023,7 +1162,8 @@
 		skb->data_len = rx->status;
 		skb->len += rx->status;
 
-		i = xennet_fill_frags(queue, skb, &tmpq);
+		if (unlikely(xennet_fill_frags(queue, skb, &tmpq)))
+			goto err;
 
 		if (rx->flags & XEN_NETRXF_csum_blank)
 			skb->ip_summed = CHECKSUM_PARTIAL;
@@ -1032,7 +1172,8 @@
 
 		__skb_queue_tail(&rxq, skb);
 
-		queue->rx.rsp_cons = ++i;
+		i = queue->rx.rsp_cons + 1;
+		xennet_set_rx_rsp_cons(queue, i);
 		work_done++;
 	}
 
@@ -1110,17 +1251,18 @@
 
 	for (i = 0; i < NET_TX_RING_SIZE; i++) {
 		/* Skip over entries which are actually freelist references */
-		if (skb_entry_is_link(&queue->tx_skbs[i]))
+		if (!queue->tx_skbs[i])
 			continue;
 
-		skb = queue->tx_skbs[i].skb;
+		skb = queue->tx_skbs[i];
+		queue->tx_skbs[i] = NULL;
 		get_page(queue->grant_tx_page[i]);
 		gnttab_end_foreign_access(queue->grant_tx_ref[i],
 					  GNTMAP_readonly,
 					  (unsigned long)page_address(queue->grant_tx_page[i]));
 		queue->grant_tx_page[i] = NULL;
 		queue->grant_tx_ref[i] = GRANT_INVALID_REF;
-		add_id_to_freelist(&queue->tx_skb_freelist, queue->tx_skbs, i);
+		add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, i);
 		dev_kfree_skb_irq(skb);
 	}
 }
@@ -1215,34 +1357,79 @@
 	return 0;
 }
 
-static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id)
+static bool xennet_handle_tx(struct netfront_queue *queue, unsigned int *eoi)
 {
-	struct netfront_queue *queue = dev_id;
 	unsigned long flags;
 
+	if (unlikely(queue->info->broken))
+		return false;
+
 	spin_lock_irqsave(&queue->tx_lock, flags);
-	xennet_tx_buf_gc(queue);
+	if (xennet_tx_buf_gc(queue))
+		*eoi = 0;
 	spin_unlock_irqrestore(&queue->tx_lock, flags);
 
+	return true;
+}
+
+static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id)
+{
+	unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
+
+	if (likely(xennet_handle_tx(dev_id, &eoiflag)))
+		xen_irq_lateeoi(irq, eoiflag);
+
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id)
+static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi)
 {
-	struct netfront_queue *queue = dev_id;
-	struct net_device *dev = queue->info->netdev;
+	unsigned int work_queued;
+	unsigned long flags;
+
+	if (unlikely(queue->info->broken))
+		return false;
+
+	spin_lock_irqsave(&queue->rx_cons_lock, flags);
+	work_queued = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx);
+	if (work_queued > queue->rx_rsp_unconsumed) {
+		queue->rx_rsp_unconsumed = work_queued;
+		*eoi = 0;
+	} else if (unlikely(work_queued < queue->rx_rsp_unconsumed)) {
+		const struct device *dev = &queue->info->netdev->dev;
+
+		spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
+		dev_alert(dev, "RX producer index going backwards\n");
+		dev_alert(dev, "Disabled for further use\n");
+		queue->info->broken = true;
+		return false;
+	}
+	spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
 
-	if (likely(netif_carrier_ok(dev) &&
-		   RING_HAS_UNCONSUMED_RESPONSES(&queue->rx)))
+	if (likely(netif_carrier_ok(queue->info->netdev) && work_queued))
 		napi_schedule(&queue->napi);
 
+	return true;
+}
+
+static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id)
+{
+	unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
+
+	if (likely(xennet_handle_rx(dev_id, &eoiflag)))
+		xen_irq_lateeoi(irq, eoiflag);
+
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t xennet_interrupt(int irq, void *dev_id)
 {
-	xennet_tx_interrupt(irq, dev_id);
-	xennet_rx_interrupt(irq, dev_id);
+	unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
+
+	if (xennet_handle_tx(dev_id, &eoiflag) &&
+	    xennet_handle_rx(dev_id, &eoiflag))
+		xen_irq_lateeoi(irq, eoiflag);
+
 	return IRQ_HANDLED;
 }
 
@@ -1253,6 +1440,10 @@
 	struct netfront_info *info = netdev_priv(dev);
 	unsigned int num_queues = dev->real_num_tx_queues;
 	unsigned int i;
+
+	if (info->broken)
+		return;
+
 	for (i = 0; i < num_queues; ++i)
 		xennet_interrupt(0, &info->queues[i]);
 }
@@ -1329,6 +1520,15 @@
 
 	netif_carrier_off(netdev);
 
+	do {
+		xenbus_switch_state(dev, XenbusStateInitialising);
+		err = wait_event_timeout(module_wq,
+				 xenbus_read_driver_state(dev->otherend) !=
+				 XenbusStateClosed &&
+				 xenbus_read_driver_state(dev->otherend) !=
+				 XenbusStateUnknown, XENNET_TIMEOUT);
+	} while (!err);
+
 	return netdev;
 
  exit:
@@ -1360,18 +1560,8 @@
 #ifdef CONFIG_SYSFS
 	info->netdev->sysfs_groups[0] = &xennet_dev_group;
 #endif
-	err = register_netdev(info->netdev);
-	if (err) {
-		pr_warn("%s: register_netdev err=%d\n", __func__, err);
-		goto fail;
-	}
 
 	return 0;
-
- fail:
-	xennet_free_netdev(netdev);
-	dev_set_drvdata(&dev->dev, NULL);
-	return err;
 }
 
 static void xennet_end_access(int ref, void *page)
@@ -1391,6 +1581,8 @@
 	for (i = 0; i < num_queues && info->queues; ++i) {
 		struct netfront_queue *queue = &info->queues[i];
 
+		del_timer_sync(&queue->rx_refill_timer);
+
 		if (queue->tx_irq && (queue->tx_irq == queue->rx_irq))
 			unbind_from_irqhandler(queue->tx_irq, queue);
 		if (queue->tx_irq && (queue->tx_irq != queue->rx_irq)) {
@@ -1465,9 +1657,10 @@
 	if (err < 0)
 		goto fail;
 
-	err = bind_evtchn_to_irqhandler(queue->tx_evtchn,
-					xennet_interrupt,
-					0, queue->info->netdev->name, queue);
+	err = bind_evtchn_to_irqhandler_lateeoi(queue->tx_evtchn,
+						xennet_interrupt, 0,
+						queue->info->netdev->name,
+						queue);
 	if (err < 0)
 		goto bind_fail;
 	queue->rx_evtchn = queue->tx_evtchn;
@@ -1495,18 +1688,18 @@
 
 	snprintf(queue->tx_irq_name, sizeof(queue->tx_irq_name),
 		 "%s-tx", queue->name);
-	err = bind_evtchn_to_irqhandler(queue->tx_evtchn,
-					xennet_tx_interrupt,
-					0, queue->tx_irq_name, queue);
+	err = bind_evtchn_to_irqhandler_lateeoi(queue->tx_evtchn,
+						xennet_tx_interrupt, 0,
+						queue->tx_irq_name, queue);
 	if (err < 0)
 		goto bind_tx_fail;
 	queue->tx_irq = err;
 
 	snprintf(queue->rx_irq_name, sizeof(queue->rx_irq_name),
 		 "%s-rx", queue->name);
-	err = bind_evtchn_to_irqhandler(queue->rx_evtchn,
-					xennet_rx_interrupt,
-					0, queue->rx_irq_name, queue);
+	err = bind_evtchn_to_irqhandler_lateeoi(queue->rx_evtchn,
+						xennet_rx_interrupt, 0,
+						queue->rx_irq_name, queue);
 	if (err < 0)
 		goto bind_rx_fail;
 	queue->rx_irq = err;
@@ -1604,23 +1797,28 @@
 {
 	unsigned short i;
 	int err = 0;
+	char *devid;
 
 	spin_lock_init(&queue->tx_lock);
 	spin_lock_init(&queue->rx_lock);
+	spin_lock_init(&queue->rx_cons_lock);
 
 	setup_timer(&queue->rx_refill_timer, rx_refill_timeout,
 		    (unsigned long)queue);
 
-	snprintf(queue->name, sizeof(queue->name), "%s-q%u",
-		 queue->info->netdev->name, queue->id);
+	devid = strrchr(queue->info->xbdev->nodename, '/') + 1;
+	snprintf(queue->name, sizeof(queue->name), "vif%s-q%u",
+		 devid, queue->id);
 
-	/* Initialise tx_skbs as a free chain containing every entry. */
+	/* Initialise tx_skb_freelist as a free chain containing every entry. */
 	queue->tx_skb_freelist = 0;
+	queue->tx_pend_queue = TX_LINK_NONE;
 	for (i = 0; i < NET_TX_RING_SIZE; i++) {
-		skb_entry_set_link(&queue->tx_skbs[i], i+1);
+		queue->tx_link[i] = i + 1;
 		queue->grant_tx_ref[i] = GRANT_INVALID_REF;
 		queue->grant_tx_page[i] = NULL;
 	}
+	queue->tx_link[NET_TX_RING_SIZE - 1] = TX_LINK_NONE;
 
 	/* Clear out rx_skbs */
 	for (i = 0; i < NET_RX_RING_SIZE; i++) {
@@ -1738,19 +1936,14 @@
 {
 	unsigned int i;
 
-	rtnl_lock();
-
 	for (i = 0; i < info->netdev->real_num_tx_queues; i++) {
 		struct netfront_queue *queue = &info->queues[i];
 
 		if (netif_running(info->netdev))
 			napi_disable(&queue->napi);
-		del_timer_sync(&queue->rx_refill_timer);
 		netif_napi_del(&queue->napi);
 	}
 
-	rtnl_unlock();
-
 	kfree(info->queues);
 	info->queues = NULL;
 }
@@ -1766,8 +1959,6 @@
 	if (!info->queues)
 		return -ENOMEM;
 
-	rtnl_lock();
-
 	for (i = 0; i < *num_queues; i++) {
 		struct netfront_queue *queue = &info->queues[i];
 
@@ -1776,7 +1967,7 @@
 
 		ret = xennet_init_queue(queue);
 		if (ret < 0) {
-			dev_warn(&info->netdev->dev,
+			dev_warn(&info->xbdev->dev,
 				 "only created %d queues\n", i);
 			*num_queues = i;
 			break;
@@ -1790,10 +1981,8 @@
 
 	netif_set_real_num_tx_queues(info->netdev, *num_queues);
 
-	rtnl_unlock();
-
 	if (*num_queues == 0) {
-		dev_err(&info->netdev->dev, "no queues\n");
+		dev_err(&info->xbdev->dev, "no queues\n");
 		return -EINVAL;
 	}
 	return 0;
@@ -1811,9 +2000,16 @@
 	unsigned int max_queues = 0;
 	struct netfront_queue *queue = NULL;
 	unsigned int num_queues = 1;
+	unsigned int trusted;
 
 	info->netdev->irq = 0;
 
+	/* Check if backend is trusted. */
+	err = xenbus_scanf(XBT_NIL, dev->nodename, "trusted", "%u", &trusted);
+	if (err < 0)
+		trusted = 1;
+	info->bounce = !xennet_trusted || !trusted;
+
 	/* Check if backend supports multiple queues */
 	err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
 			   "multi-queue-max-queues", "%u", &max_queues);
@@ -1832,34 +2028,31 @@
 	err = xen_net_read_mac(dev, info->netdev->dev_addr);
 	if (err) {
 		xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
-		goto out;
+		goto out_unlocked;
 	}
 
+	rtnl_lock();
 	if (info->queues)
 		xennet_destroy_queues(info);
 
+	/* For the case of a reconnect reset the "broken" indicator. */
+	info->broken = false;
+
 	err = xennet_create_queues(info, &num_queues);
-	if (err < 0)
-		goto destroy_ring;
+	if (err < 0) {
+		xenbus_dev_fatal(dev, err, "creating queues");
+		kfree(info->queues);
+		info->queues = NULL;
+		goto out;
+	}
+	rtnl_unlock();
 
 	/* Create shared ring, alloc event channel -- for each queue */
 	for (i = 0; i < num_queues; ++i) {
 		queue = &info->queues[i];
 		err = setup_netfront(dev, queue, feature_split_evtchn);
-		if (err) {
-			/* setup_netfront() will tidy up the current
-			 * queue on error, but we need to clean up
-			 * those already allocated.
-			 */
-			if (i > 0) {
-				rtnl_lock();
-				netif_set_real_num_tx_queues(info->netdev, i);
-				rtnl_unlock();
-				goto destroy_ring;
-			} else {
-				goto out;
-			}
-		}
+		if (err)
+			goto destroy_ring;
 	}
 
 again:
@@ -1949,9 +2142,12 @@
 	xenbus_transaction_end(xbt, 1);
  destroy_ring:
 	xennet_disconnect_backend(info);
-	kfree(info->queues);
-	info->queues = NULL;
+	rtnl_lock();
+	xennet_destroy_queues(info);
  out:
+	rtnl_unlock();
+out_unlocked:
+	device_unregister(&dev->dev);
 	return err;
 }
 
@@ -1978,10 +2174,22 @@
 	err = talk_to_netback(np->xbdev, np);
 	if (err)
 		return err;
+	if (np->bounce)
+		dev_info(&np->xbdev->dev,
+			 "bouncing transmitted data to zeroed pages\n");
 
 	/* talk_to_netback() sets the correct number of queues */
 	num_queues = dev->real_num_tx_queues;
 
+	if (dev->reg_state == NETREG_UNINITIALIZED) {
+		err = register_netdev(dev);
+		if (err) {
+			pr_warn("%s: register_netdev err=%d\n", __func__, err);
+			device_unregister(&np->xbdev->dev);
+			return err;
+		}
+	}
+
 	rtnl_lock();
 	netdev_update_features(dev);
 	rtnl_unlock();
@@ -2023,6 +2231,8 @@
 
 	dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
 
+	wake_up_all(&module_wq);
+
 	switch (backend_state) {
 	case XenbusStateInitialising:
 	case XenbusStateInitialised:
@@ -2147,18 +2357,53 @@
 };
 #endif /* CONFIG_SYSFS */
 
+static void xennet_bus_close(struct xenbus_device *dev)
+{
+	int ret;
+
+	if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed)
+		return;
+	do {
+		xenbus_switch_state(dev, XenbusStateClosing);
+		ret = wait_event_timeout(module_wq,
+				   xenbus_read_driver_state(dev->otherend) ==
+				   XenbusStateClosing ||
+				   xenbus_read_driver_state(dev->otherend) ==
+				   XenbusStateClosed ||
+				   xenbus_read_driver_state(dev->otherend) ==
+				   XenbusStateUnknown,
+				   XENNET_TIMEOUT);
+	} while (!ret);
+
+	if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed)
+		return;
+
+	do {
+		xenbus_switch_state(dev, XenbusStateClosed);
+		ret = wait_event_timeout(module_wq,
+				   xenbus_read_driver_state(dev->otherend) ==
+				   XenbusStateClosed ||
+				   xenbus_read_driver_state(dev->otherend) ==
+				   XenbusStateUnknown,
+				   XENNET_TIMEOUT);
+	} while (!ret);
+}
+
 static int xennet_remove(struct xenbus_device *dev)
 {
 	struct netfront_info *info = dev_get_drvdata(&dev->dev);
 
-	dev_dbg(&dev->dev, "%s\n", dev->nodename);
-
+	xennet_bus_close(dev);
 	xennet_disconnect_backend(info);
 
-	unregister_netdev(info->netdev);
+	if (info->netdev->reg_state == NETREG_REGISTERED)
+		unregister_netdev(info->netdev);
 
-	if (info->queues)
+	if (info->queues) {
+		rtnl_lock();
 		xennet_destroy_queues(info);
+		rtnl_unlock();
+	}
 	xennet_free_netdev(info->netdev);
 
 	return 0;
--- linux-4.4.0.orig/drivers/nfc/fdp/fdp.c
+++ linux-4.4.0/drivers/nfc/fdp/fdp.c
@@ -191,7 +191,7 @@
 	const struct firmware *fw;
 	struct sk_buff *skb;
 	unsigned long len;
-	u8 max_size, payload_size;
+	int max_size, payload_size;
 	int rc = 0;
 
 	if ((type == NCI_PATCH_TYPE_OTP && !info->otp_patch) ||
@@ -214,8 +214,7 @@
 
 	while (len) {
 
-		payload_size = min_t(unsigned long, (unsigned long) max_size,
-				     len);
+		payload_size = min_t(unsigned long, max_size, len);
 
 		skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + payload_size),
 				    GFP_KERNEL);
@@ -352,7 +351,7 @@
 {
 	struct fdp_nci_info *info = nci_get_drvdata(ndev);
 	struct device *dev = &info->phy->i2c_dev->dev;
-	u8 conn_id;
+	int conn_id;
 	int r = 0;
 
 	if (info->otp_version >= info->otp_patch_version)
@@ -423,7 +422,7 @@
 {
 	struct fdp_nci_info *info = nci_get_drvdata(ndev);
 	struct device *dev = &info->phy->i2c_dev->dev;
-	u8 conn_id;
+	int conn_id;
 	int r = 0;
 
 	if (info->ram_version >= info->ram_patch_version)
--- linux-4.4.0.orig/drivers/nfc/fdp/i2c.c
+++ linux-4.4.0/drivers/nfc/fdp/i2c.c
@@ -210,14 +210,14 @@
 	struct sk_buff *skb;
 	int r;
 
-	client = phy->i2c_dev;
-	dev_dbg(&client->dev, "%s\n", __func__);
-
 	if (!phy || irq != phy->i2c_dev->irq) {
 		WARN_ON_ONCE(1);
 		return IRQ_NONE;
 	}
 
+	client = phy->i2c_dev;
+	dev_dbg(&client->dev, "%s\n", __func__);
+
 	r = fdp_nci_i2c_read(phy, &skb);
 
 	if (r == -EREMOTEIO)
@@ -268,7 +268,7 @@
 						  *fw_vsc_cfg, len);
 
 		if (r) {
-			devm_kfree(dev, fw_vsc_cfg);
+			devm_kfree(dev, *fw_vsc_cfg);
 			goto vsc_read_err;
 		}
 	} else {
--- linux-4.4.0.orig/drivers/nfc/mei_phy.c
+++ linux-4.4.0/drivers/nfc/mei_phy.c
@@ -133,7 +133,7 @@
 		return -ENOMEM;
 
 	bytes_recv = mei_cldev_recv(phy->cldev, (u8 *)reply, if_version_length);
-	if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+	if (bytes_recv < 0 || bytes_recv < if_version_length) {
 		pr_err("Could not read IF version\n");
 		r = -EIO;
 		goto err;
--- linux-4.4.0.orig/drivers/nfc/nfcmrvl/fw_dnld.c
+++ linux-4.4.0/drivers/nfc/nfcmrvl/fw_dnld.c
@@ -17,7 +17,7 @@
  */
 
 #include <linux/module.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 #include <linux/firmware.h>
 #include <linux/nfc.h>
 #include <net/nfc/nci.h>
@@ -459,7 +459,7 @@
 
 	INIT_WORK(&priv->fw_dnld.rx_work, fw_dnld_rx_work);
 	snprintf(name, sizeof(name), "%s_nfcmrvl_fw_dnld_rx_wq",
-		 dev_name(priv->dev));
+		 dev_name(&priv->ndev->nfc_dev->dev));
 	priv->fw_dnld.rx_wq = create_singlethread_workqueue(name);
 	if (!priv->fw_dnld.rx_wq)
 		return -ENOMEM;
@@ -496,6 +496,7 @@
 {
 	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
 	struct nfcmrvl_fw_dnld *fw_dnld = &priv->fw_dnld;
+	int res;
 
 	if (!priv->support_fw_dnld)
 		return -ENOTSUPP;
@@ -511,7 +512,9 @@
 	 */
 
 	/* Retrieve FW binary */
-	if (request_firmware(&fw_dnld->fw, firmware_name, priv->dev) < 0) {
+	res = request_firmware(&fw_dnld->fw, firmware_name,
+			       &ndev->nfc_dev->dev);
+	if (res < 0) {
 		nfc_err(priv->dev, "failed to retrieve FW %s", firmware_name);
 		return -ENOENT;
 	}
--- linux-4.4.0.orig/drivers/nfc/nfcmrvl/main.c
+++ linux-4.4.0/drivers/nfc/nfcmrvl/main.c
@@ -124,12 +124,13 @@
 	memcpy(&priv->config, pdata, sizeof(*pdata));
 
 	if (priv->config.reset_n_io) {
-		rc = devm_gpio_request_one(dev,
-					   priv->config.reset_n_io,
-					   GPIOF_OUT_INIT_LOW,
-					   "nfcmrvl_reset_n");
-		if (rc < 0)
+		rc = gpio_request_one(priv->config.reset_n_io,
+				      GPIOF_OUT_INIT_LOW,
+				      "nfcmrvl_reset_n");
+		if (rc < 0) {
+			priv->config.reset_n_io = 0;
 			nfc_err(dev, "failed to request reset_n io\n");
+		}
 	}
 
 	if (phy == NFCMRVL_PHY_SPI) {
@@ -154,7 +155,13 @@
 	if (!priv->ndev) {
 		nfc_err(dev, "nci_allocate_device failed\n");
 		rc = -ENOMEM;
-		goto error;
+		goto error_free_gpio;
+	}
+
+	rc = nfcmrvl_fw_dnld_init(priv);
+	if (rc) {
+		nfc_err(dev, "failed to initialize FW download %d\n", rc);
+		goto error_free_dev;
 	}
 
 	nci_set_drvdata(priv->ndev, priv);
@@ -162,24 +169,22 @@
 	rc = nci_register_device(priv->ndev);
 	if (rc) {
 		nfc_err(dev, "nci_register_device failed %d\n", rc);
-		goto error_free_dev;
+		goto error_fw_dnld_deinit;
 	}
 
 	/* Ensure that controller is powered off */
 	nfcmrvl_chip_halt(priv);
 
-	rc = nfcmrvl_fw_dnld_init(priv);
-	if (rc) {
-		nfc_err(dev, "failed to initialize FW download %d\n", rc);
-		goto error_free_dev;
-	}
-
 	nfc_info(dev, "registered with nci successfully\n");
 	return priv;
 
+error_fw_dnld_deinit:
+	nfcmrvl_fw_dnld_deinit(priv);
 error_free_dev:
 	nci_free_device(priv->ndev);
-error:
+error_free_gpio:
+	if (priv->config.reset_n_io)
+		gpio_free(priv->config.reset_n_io);
 	kfree(priv);
 	return ERR_PTR(rc);
 }
@@ -189,15 +194,15 @@
 {
 	struct nci_dev *ndev = priv->ndev;
 
+	nci_unregister_device(ndev);
 	if (priv->ndev->nfc_dev->fw_download_in_progress)
 		nfcmrvl_fw_dnld_abort(priv);
 
 	nfcmrvl_fw_dnld_deinit(priv);
 
 	if (priv->config.reset_n_io)
-		devm_gpio_free(priv->dev, priv->config.reset_n_io);
+		gpio_free(priv->config.reset_n_io);
 
-	nci_unregister_device(ndev);
 	nci_free_device(ndev);
 	kfree(priv);
 }
--- linux-4.4.0.orig/drivers/nfc/nfcmrvl/spi.c
+++ linux-4.4.0/drivers/nfc/nfcmrvl/spi.c
@@ -96,10 +96,9 @@
 	/* Send the SPI packet */
 	err = nci_spi_send(drv_data->nci_spi, &drv_data->handshake_completion,
 			   skb);
-	if (err != 0) {
+	if (err)
 		nfc_err(priv->dev, "spi_send failed %d", err);
-		kfree_skb(skb);
-	}
+
 	return err;
 }
 
--- linux-4.4.0.orig/drivers/nfc/nfcmrvl/uart.c
+++ linux-4.4.0/drivers/nfc/nfcmrvl/uart.c
@@ -73,10 +73,9 @@
 	struct device_node *matched_node;
 	int ret;
 
-	matched_node = of_find_compatible_node(node, NULL, "marvell,nfc-uart");
+	matched_node = of_get_compatible_child(node, "marvell,nfc-uart");
 	if (!matched_node) {
-		matched_node = of_find_compatible_node(node, NULL,
-						       "mrvl,nfc-uart");
+		matched_node = of_get_compatible_child(node, "mrvl,nfc-uart");
 		if (!matched_node)
 			return -ENODEV;
 	}
@@ -109,6 +108,7 @@
 	struct nfcmrvl_private *priv;
 	struct nfcmrvl_platform_data *pdata = NULL;
 	struct nfcmrvl_platform_data config;
+	struct device *dev = nu->tty->dev;
 
 	/*
 	 * Platform data cannot be used here since usually it is already used
@@ -116,9 +116,8 @@
 	 * and check if DT entries were added.
 	 */
 
-	if (nu->tty->dev->parent && nu->tty->dev->parent->of_node)
-		if (nfcmrvl_uart_parse_dt(nu->tty->dev->parent->of_node,
-					  &config) == 0)
+	if (dev && dev->parent && dev->parent->of_node)
+		if (nfcmrvl_uart_parse_dt(dev->parent->of_node, &config) == 0)
 			pdata = &config;
 
 	if (!pdata) {
@@ -131,7 +130,7 @@
 	}
 
 	priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_UART, nu, &uart_ops,
-					nu->tty->dev, pdata);
+					dev, pdata);
 	if (IS_ERR(priv))
 		return PTR_ERR(priv);
 
--- linux-4.4.0.orig/drivers/nfc/nxp-nci/firmware.c
+++ linux-4.4.0/drivers/nfc/nxp-nci/firmware.c
@@ -24,7 +24,7 @@
 #include <linux/completion.h>
 #include <linux/firmware.h>
 #include <linux/nfc.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 
 #include "nxp-nci.h"
 
--- linux-4.4.0.orig/drivers/nfc/nxp-nci/i2c.c
+++ linux-4.4.0/drivers/nfc/nxp-nci/i2c.c
@@ -36,7 +36,7 @@
 #include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/platform_data/nxp-nci.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 
 #include <net/nfc/nfc.h>
 
@@ -239,8 +239,10 @@
 
 	if (r == -EREMOTEIO) {
 		phy->hard_fault = r;
-		skb = NULL;
-	} else if (r < 0) {
+		if (info->mode == NXP_NCI_MODE_FW)
+			nxp_nci_fw_recv_frame(phy->ndev, NULL);
+	}
+	if (r < 0) {
 		nfc_err(&client->dev, "Read failed with error %d\n", r);
 		goto exit_irq_handled;
 	}
--- linux-4.4.0.orig/drivers/nfc/pn544/i2c.c
+++ linux-4.4.0/drivers/nfc/pn544/i2c.c
@@ -241,6 +241,7 @@
 
 out:
 	gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
+	usleep_range(10000, 15000);
 }
 
 static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode)
--- linux-4.4.0.orig/drivers/nfc/pn544/pn544.c
+++ linux-4.4.0/drivers/nfc/pn544/pn544.c
@@ -704,7 +704,7 @@
 		    target->nfcid1_len != 10)
 			return -EOPNOTSUPP;
 
-		 return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
+		return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
 				     PN544_RF_READER_CMD_ACTIVATE_NEXT,
 				     target->nfcid1, target->nfcid1_len, NULL);
 	} else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK |
--- linux-4.4.0.orig/drivers/nfc/port100.c
+++ linux-4.4.0/drivers/nfc/port100.c
@@ -545,7 +545,7 @@
 {
 	struct port100_frame *frame = _frame;
 
-	frame->datalen = cpu_to_le16(le16_to_cpu(frame->datalen) + len);
+	le16_add_cpu(&frame->datalen, len);
 }
 
 static bool port100_rx_frame_is_valid(void *_frame)
@@ -1536,7 +1536,9 @@
 	nfc_digital_free_device(dev->nfc_digital_dev);
 
 error:
+	usb_kill_urb(dev->in_urb);
 	usb_free_urb(dev->in_urb);
+	usb_kill_urb(dev->out_urb);
 	usb_free_urb(dev->out_urb);
 	usb_put_dev(dev->udev);
 
--- linux-4.4.0.orig/drivers/nfc/s3fwrn5/core.c
+++ linux-4.4.0/drivers/nfc/s3fwrn5/core.c
@@ -209,6 +209,7 @@
 	case S3FWRN5_MODE_FW:
 		return s3fwrn5_fw_recv_frame(ndev, skb);
 	default:
+		kfree_skb(skb);
 		return -ENODEV;
 	}
 }
--- linux-4.4.0.orig/drivers/nfc/s3fwrn5/firmware.c
+++ linux-4.4.0/drivers/nfc/s3fwrn5/firmware.c
@@ -304,8 +304,10 @@
 	if (ret < 0)
 		return ret;
 
-	if (fw->fw->size < S3FWRN5_FW_IMAGE_HEADER_SIZE)
+	if (fw->fw->size < S3FWRN5_FW_IMAGE_HEADER_SIZE) {
+		release_firmware(fw->fw);
 		return -EINVAL;
+	}
 
 	memcpy(fw->date, fw->fw->data + 0x00, 12);
 	fw->date[12] = '\0';
--- linux-4.4.0.orig/drivers/nfc/s3fwrn5/i2c.c
+++ linux-4.4.0/drivers/nfc/s3fwrn5/i2c.c
@@ -37,8 +37,8 @@
 	struct i2c_client *i2c_dev;
 	struct nci_dev *ndev;
 
-	unsigned int gpio_en;
-	unsigned int gpio_fw_wake;
+	int gpio_en;
+	int gpio_fw_wake;
 
 	struct mutex mutex;
 
--- linux-4.4.0.orig/drivers/nfc/st-nci/ndlc.c
+++ linux-4.4.0/drivers/nfc/st-nci/ndlc.c
@@ -303,13 +303,15 @@
 
 void ndlc_remove(struct llt_ndlc *ndlc)
 {
-	st_nci_remove(ndlc->ndev);
-
 	/* cancel timers */
 	del_timer_sync(&ndlc->t1_timer);
 	del_timer_sync(&ndlc->t2_timer);
 	ndlc->t2_active = false;
 	ndlc->t1_active = false;
+	/* cancel work */
+	cancel_work_sync(&ndlc->sm_work);
+
+	st_nci_remove(ndlc->ndev);
 
 	skb_queue_purge(&ndlc->rcv_q);
 	skb_queue_purge(&ndlc->send_q);
--- linux-4.4.0.orig/drivers/nfc/st-nci/se.c
+++ linux-4.4.0/drivers/nfc/st-nci/se.c
@@ -346,6 +346,8 @@
 
 		transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
 					    skb->len - 2, GFP_KERNEL);
+		if (!transaction)
+			return -ENOMEM;
 
 		transaction->aid_len = skb->data[1];
 		memcpy(transaction->aid, &skb->data[2], transaction->aid_len);
--- linux-4.4.0.orig/drivers/nfc/st21nfca/core.c
+++ linux-4.4.0/drivers/nfc/st21nfca/core.c
@@ -726,6 +726,7 @@
 							NFC_PROTO_FELICA_MASK;
 		} else {
 			kfree_skb(nfcid_skb);
+			nfcid_skb = NULL;
 			/* P2P in type A */
 			r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
 					ST21NFCA_RF_READER_F_NFCID1,
--- linux-4.4.0.orig/drivers/nfc/st21nfca/dep.c
+++ linux-4.4.0/drivers/nfc/st21nfca/dep.c
@@ -184,8 +184,10 @@
 		memcpy(atr_res->gbi, atr_req->gbi, gb_len);
 		r = nfc_set_remote_general_bytes(hdev->ndev, atr_res->gbi,
 						  gb_len);
-		if (r < 0)
+		if (r < 0) {
+			kfree_skb(skb);
 			return r;
+		}
 	}
 
 	info->dep_info.curr_nfc_dep_pni = 0;
--- linux-4.4.0.orig/drivers/nfc/st21nfca/i2c.c
+++ linux-4.4.0/drivers/nfc/st21nfca/i2c.c
@@ -620,23 +620,24 @@
 		r = st21nfca_hci_i2c_of_request_resources(client);
 		if (r) {
 			nfc_err(&client->dev, "No platform data\n");
-			return r;
+			goto out_free;
 		}
 	} else if (pdata) {
 		r = st21nfca_hci_i2c_request_resources(client);
 		if (r) {
 			nfc_err(&client->dev, "Cannot get platform resources\n");
-			return r;
+			goto out_free;
 		}
 	} else {
 		nfc_err(&client->dev, "st21nfca platform resources not available\n");
-		return -ENODEV;
+		r = -ENODEV;
+		goto out_free;
 	}
 
 	r = st21nfca_hci_platform_init(phy);
 	if (r < 0) {
 		nfc_err(&client->dev, "Unable to reboot st21nfca\n");
-		return r;
+		goto out_free;
 	}
 
 	r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
@@ -645,15 +646,23 @@
 				ST21NFCA_HCI_DRIVER_NAME, phy);
 	if (r < 0) {
 		nfc_err(&client->dev, "Unable to register IRQ handler\n");
-		return r;
+		goto out_free;
 	}
 
-	return st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
-					ST21NFCA_FRAME_HEADROOM,
-					ST21NFCA_FRAME_TAILROOM,
-					ST21NFCA_HCI_LLC_MAX_PAYLOAD,
-					&phy->hdev,
-					&phy->se_status);
+	r = st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
+			       ST21NFCA_FRAME_HEADROOM,
+			       ST21NFCA_FRAME_TAILROOM,
+			       ST21NFCA_HCI_LLC_MAX_PAYLOAD,
+			       &phy->hdev,
+			       &phy->se_status);
+	if (r)
+		goto out_free;
+
+	return 0;
+
+out_free:
+	kfree_skb(phy->pending_skb);
+	return r;
 }
 
 static int st21nfca_hci_i2c_remove(struct i2c_client *client)
@@ -666,6 +675,8 @@
 
 	if (phy->powered)
 		st21nfca_hci_i2c_disable(phy);
+	if (phy->pending_skb)
+		kfree_skb(phy->pending_skb);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/nfc/st21nfca/se.c
+++ linux-4.4.0/drivers/nfc/st21nfca/se.c
@@ -327,8 +327,15 @@
 
 		transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
 						   skb->len - 2, GFP_KERNEL);
+		if (!transaction)
+			return -ENOMEM;
 
 		transaction->aid_len = skb->data[1];
+
+		/* Checking if the length of the AID is valid */
+		if (transaction->aid_len > sizeof(transaction->aid))
+			return -EINVAL;
+
 		memcpy(transaction->aid, &skb->data[2],
 		       transaction->aid_len);
 
@@ -338,6 +345,11 @@
 			return -EPROTO;
 
 		transaction->params_len = skb->data[transaction->aid_len + 3];
+
+		/* Total size is allocated (skb->len - 2) minus fixed array members */
+		if (transaction->params_len > ((skb->len - 2) - sizeof(struct nfc_evt_transaction)))
+			return -EINVAL;
+
 		memcpy(transaction->params, skb->data +
 		       transaction->aid_len + 4, transaction->params_len);
 
--- linux-4.4.0.orig/drivers/ntb/hw/Kconfig
+++ linux-4.4.0/drivers/ntb/hw/Kconfig
@@ -1 +1,2 @@
+source "drivers/ntb/hw/amd/Kconfig"
 source "drivers/ntb/hw/intel/Kconfig"
--- linux-4.4.0.orig/drivers/ntb/hw/Makefile
+++ linux-4.4.0/drivers/ntb/hw/Makefile
@@ -1 +1,2 @@
+obj-$(CONFIG_NTB_AMD)	+= amd/
 obj-$(CONFIG_NTB_INTEL)	+= intel/
--- linux-4.4.0.orig/drivers/ntb/hw/amd/Kconfig
+++ linux-4.4.0/drivers/ntb/hw/amd/Kconfig
@@ -0,0 +1,7 @@
+config NTB_AMD
+	tristate "AMD Non-Transparent Bridge support"
+	depends on X86_64
+	help
+	 This driver supports AMD NTB on capable Zeppelin hardware.
+
+	 If unsure, say N.
--- linux-4.4.0.orig/drivers/ntb/hw/amd/Makefile
+++ linux-4.4.0/drivers/ntb/hw/amd/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_NTB_AMD) += ntb_hw_amd.o
--- linux-4.4.0.orig/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ linux-4.4.0/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -0,0 +1,1143 @@
+/*
+ * 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) 2016 Advanced Micro Devices, Inc. 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.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of AMD 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.
+ *
+ * AMD PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Xiangliang Yu <Xiangliang.Yu@amd.com>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/ntb.h>
+
+#include "ntb_hw_amd.h"
+
+#define NTB_NAME	"ntb_hw_amd"
+#define NTB_DESC	"AMD(R) PCI-E Non-Transparent Bridge Driver"
+#define NTB_VER		"1.0"
+
+MODULE_DESCRIPTION(NTB_DESC);
+MODULE_VERSION(NTB_VER);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("AMD Inc.");
+
+static const struct file_operations amd_ntb_debugfs_info;
+static struct dentry *debugfs_dir;
+
+static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
+{
+	if (idx < 0 || idx > ndev->mw_count)
+		return -EINVAL;
+
+	return 1 << idx;
+}
+
+static int amd_ntb_mw_count(struct ntb_dev *ntb)
+{
+	return ntb_ndev(ntb)->mw_count;
+}
+
+static int amd_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
+				phys_addr_t *base,
+				resource_size_t *size,
+				resource_size_t *align,
+				resource_size_t *align_size)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	int bar;
+
+	bar = ndev_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
+
+	if (base)
+		*base = pci_resource_start(ndev->ntb.pdev, bar);
+
+	if (size)
+		*size = pci_resource_len(ndev->ntb.pdev, bar);
+
+	if (align)
+		*align = SZ_4K;
+
+	if (align_size)
+		*align_size = 1;
+
+	return 0;
+}
+
+static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+				dma_addr_t addr, resource_size_t size)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	unsigned long xlat_reg, limit_reg = 0;
+	resource_size_t mw_size;
+	void __iomem *mmio, *peer_mmio;
+	u64 base_addr, limit, reg_val;
+	int bar;
+
+	bar = ndev_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
+
+	mw_size = pci_resource_len(ndev->ntb.pdev, bar);
+
+	/* make sure the range fits in the usable mw size */
+	if (size > mw_size)
+		return -EINVAL;
+
+	mmio = ndev->self_mmio;
+	peer_mmio = ndev->peer_mmio;
+
+	base_addr = pci_resource_start(ndev->ntb.pdev, bar);
+
+	if (bar != 1) {
+		xlat_reg = AMD_BAR23XLAT_OFFSET + ((bar - 2) << 3);
+		limit_reg = AMD_BAR23LMT_OFFSET + ((bar - 2) << 3);
+
+		/* Set the limit if supported */
+		limit = base_addr + size;
+
+		/* set and verify setting the translation address */
+		write64(addr, peer_mmio + xlat_reg);
+		reg_val = read64(peer_mmio + xlat_reg);
+		if (reg_val != addr) {
+			write64(0, peer_mmio + xlat_reg);
+			return -EIO;
+		}
+
+		/* set and verify setting the limit */
+		write64(limit, mmio + limit_reg);
+		reg_val = read64(mmio + limit_reg);
+		if (reg_val != limit) {
+			write64(base_addr, mmio + limit_reg);
+			write64(0, peer_mmio + xlat_reg);
+			return -EIO;
+		}
+	} else {
+		xlat_reg = AMD_BAR1XLAT_OFFSET;
+		limit_reg = AMD_BAR1LMT_OFFSET;
+
+		/* split bar addr range must all be 32 bit */
+		if (addr & (~0ull << 32))
+			return -EINVAL;
+		if ((addr + size) & (~0ull << 32))
+			return -EINVAL;
+
+		/* Set the limit if supported */
+		limit = base_addr + size;
+
+		/* set and verify setting the translation address */
+		write64(addr, peer_mmio + xlat_reg);
+		reg_val = read64(peer_mmio + xlat_reg);
+		if (reg_val != addr) {
+			write64(0, peer_mmio + xlat_reg);
+			return -EIO;
+		}
+
+		/* set and verify setting the limit */
+		writel(limit, mmio + limit_reg);
+		reg_val = readl(mmio + limit_reg);
+		if (reg_val != limit) {
+			writel(base_addr, mmio + limit_reg);
+			writel(0, peer_mmio + xlat_reg);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static int amd_link_is_up(struct amd_ntb_dev *ndev)
+{
+	if (!ndev->peer_sta)
+		return NTB_LNK_STA_ACTIVE(ndev->cntl_sta);
+
+	/* If peer_sta is reset or D0 event, the ISR has
+	 * started a timer to check link status of hardware.
+	 * So here just clear status bit. And if peer_sta is
+	 * D3 or PME_TO, D0/reset event will be happened when
+	 * system wakeup/poweron, so do nothing here.
+	 */
+	if (ndev->peer_sta & AMD_PEER_RESET_EVENT)
+		ndev->peer_sta &= ~AMD_PEER_RESET_EVENT;
+	else if (ndev->peer_sta & AMD_PEER_D0_EVENT)
+		ndev->peer_sta = 0;
+
+	return 0;
+}
+
+static int amd_ntb_link_is_up(struct ntb_dev *ntb,
+			      enum ntb_speed *speed,
+			      enum ntb_width *width)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	int ret = 0;
+
+	if (amd_link_is_up(ndev)) {
+		if (speed)
+			*speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
+		if (width)
+			*width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
+
+		dev_dbg(ndev_dev(ndev), "link is up.\n");
+
+		ret = 1;
+	} else {
+		if (speed)
+			*speed = NTB_SPEED_NONE;
+		if (width)
+			*width = NTB_WIDTH_NONE;
+
+		dev_dbg(ndev_dev(ndev), "link is down.\n");
+	}
+
+	return ret;
+}
+
+static int amd_ntb_link_enable(struct ntb_dev *ntb,
+			       enum ntb_speed max_speed,
+			       enum ntb_width max_width)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+	u32 ntb_ctl;
+
+	/* Enable event interrupt */
+	ndev->int_mask &= ~AMD_EVENT_INTMASK;
+	writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
+
+	if (ndev->ntb.topo == NTB_TOPO_SEC)
+		return -EINVAL;
+	dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
+
+	ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
+	ntb_ctl |= (PMM_REG_CTL | SMM_REG_CTL);
+	writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
+
+	return 0;
+}
+
+static int amd_ntb_link_disable(struct ntb_dev *ntb)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+	u32 ntb_ctl;
+
+	/* Disable event interrupt */
+	ndev->int_mask |= AMD_EVENT_INTMASK;
+	writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
+
+	if (ndev->ntb.topo == NTB_TOPO_SEC)
+		return -EINVAL;
+	dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
+
+	ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
+	ntb_ctl &= ~(PMM_REG_CTL | SMM_REG_CTL);
+	writel(ntb_ctl, mmio + AMD_CNTL_OFFSET);
+
+	return 0;
+}
+
+static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
+{
+	return ntb_ndev(ntb)->db_valid_mask;
+}
+
+static int amd_ntb_db_vector_count(struct ntb_dev *ntb)
+{
+	return ntb_ndev(ntb)->db_count;
+}
+
+static u64 amd_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+
+	if (db_vector < 0 || db_vector > ndev->db_count)
+		return 0;
+
+	return ntb_ndev(ntb)->db_valid_mask & (1 << db_vector);
+}
+
+static u64 amd_ntb_db_read(struct ntb_dev *ntb)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+
+	return (u64)readw(mmio + AMD_DBSTAT_OFFSET);
+}
+
+static int amd_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+
+	writew((u16)db_bits, mmio + AMD_DBSTAT_OFFSET);
+
+	return 0;
+}
+
+static int amd_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+	unsigned long flags;
+
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ndev->db_mask_lock, flags);
+	ndev->db_mask |= db_bits;
+	writew((u16)ndev->db_mask, mmio + AMD_DBMASK_OFFSET);
+	spin_unlock_irqrestore(&ndev->db_mask_lock, flags);
+
+	return 0;
+}
+
+static int amd_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+	unsigned long flags;
+
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ndev->db_mask_lock, flags);
+	ndev->db_mask &= ~db_bits;
+	writew((u16)ndev->db_mask, mmio + AMD_DBMASK_OFFSET);
+	spin_unlock_irqrestore(&ndev->db_mask_lock, flags);
+
+	return 0;
+}
+
+static int amd_ntb_peer_db_addr(struct ntb_dev *ntb,
+				phys_addr_t *db_addr,
+				resource_size_t *db_size)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+
+	if (db_addr)
+		*db_addr = (phys_addr_t)(ndev->peer_mmio + AMD_DBREQ_OFFSET);
+	if (db_size)
+		*db_size = sizeof(u32);
+
+	return 0;
+}
+
+static int amd_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+
+	writew((u16)db_bits, mmio + AMD_DBREQ_OFFSET);
+
+	return 0;
+}
+
+static int amd_ntb_spad_count(struct ntb_dev *ntb)
+{
+	return ntb_ndev(ntb)->spad_count;
+}
+
+static u32 amd_ntb_spad_read(struct ntb_dev *ntb, int idx)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+	u32 offset;
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return 0;
+
+	offset = ndev->self_spad + (idx << 2);
+	return readl(mmio + AMD_SPAD_OFFSET + offset);
+}
+
+static int amd_ntb_spad_write(struct ntb_dev *ntb,
+			      int idx, u32 val)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+	u32 offset;
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	offset = ndev->self_spad + (idx << 2);
+	writel(val, mmio + AMD_SPAD_OFFSET + offset);
+
+	return 0;
+}
+
+static int amd_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+				  phys_addr_t *spad_addr)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	if (spad_addr)
+		*spad_addr = (phys_addr_t)(ndev->self_mmio + AMD_SPAD_OFFSET +
+					   ndev->peer_spad + (idx << 2));
+	return 0;
+}
+
+static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+	u32 offset;
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	offset = ndev->peer_spad + (idx << 2);
+	return readl(mmio + AMD_SPAD_OFFSET + offset);
+}
+
+static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
+				   int idx, u32 val)
+{
+	struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+	void __iomem *mmio = ndev->self_mmio;
+	u32 offset;
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	offset = ndev->peer_spad + (idx << 2);
+	writel(val, mmio + AMD_SPAD_OFFSET + offset);
+
+	return 0;
+}
+
+static const struct ntb_dev_ops amd_ntb_ops = {
+	.mw_count		= amd_ntb_mw_count,
+	.mw_get_range		= amd_ntb_mw_get_range,
+	.mw_set_trans		= amd_ntb_mw_set_trans,
+	.link_is_up		= amd_ntb_link_is_up,
+	.link_enable		= amd_ntb_link_enable,
+	.link_disable		= amd_ntb_link_disable,
+	.db_valid_mask		= amd_ntb_db_valid_mask,
+	.db_vector_count	= amd_ntb_db_vector_count,
+	.db_vector_mask		= amd_ntb_db_vector_mask,
+	.db_read		= amd_ntb_db_read,
+	.db_clear		= amd_ntb_db_clear,
+	.db_set_mask		= amd_ntb_db_set_mask,
+	.db_clear_mask		= amd_ntb_db_clear_mask,
+	.peer_db_addr		= amd_ntb_peer_db_addr,
+	.peer_db_set		= amd_ntb_peer_db_set,
+	.spad_count		= amd_ntb_spad_count,
+	.spad_read		= amd_ntb_spad_read,
+	.spad_write		= amd_ntb_spad_write,
+	.peer_spad_addr		= amd_ntb_peer_spad_addr,
+	.peer_spad_read		= amd_ntb_peer_spad_read,
+	.peer_spad_write	= amd_ntb_peer_spad_write,
+};
+
+static void amd_ack_smu(struct amd_ntb_dev *ndev, u32 bit)
+{
+	void __iomem *mmio = ndev->self_mmio;
+	int reg;
+
+	reg = readl(mmio + AMD_SMUACK_OFFSET);
+	reg |= bit;
+	writel(reg, mmio + AMD_SMUACK_OFFSET);
+
+	ndev->peer_sta |= bit;
+}
+
+static void amd_handle_event(struct amd_ntb_dev *ndev, int vec)
+{
+	void __iomem *mmio = ndev->self_mmio;
+	u32 status;
+
+	status = readl(mmio + AMD_INTSTAT_OFFSET);
+	if (!(status & AMD_EVENT_INTMASK))
+		return;
+
+	dev_dbg(ndev_dev(ndev), "status = 0x%x and vec = %d\n", status, vec);
+
+	status &= AMD_EVENT_INTMASK;
+	switch (status) {
+	case AMD_PEER_FLUSH_EVENT:
+		dev_info(ndev_dev(ndev), "Flush is done.\n");
+		break;
+	case AMD_PEER_RESET_EVENT:
+		amd_ack_smu(ndev, AMD_PEER_RESET_EVENT);
+
+		/* link down first */
+		ntb_link_event(&ndev->ntb);
+		/* polling peer status */
+		schedule_delayed_work(&ndev->hb_timer, AMD_LINK_HB_TIMEOUT);
+
+		break;
+	case AMD_PEER_D3_EVENT:
+	case AMD_PEER_PMETO_EVENT:
+		amd_ack_smu(ndev, status);
+
+		/* link down */
+		ntb_link_event(&ndev->ntb);
+
+		break;
+	case AMD_PEER_D0_EVENT:
+		mmio = ndev->peer_mmio;
+		status = readl(mmio + AMD_PMESTAT_OFFSET);
+		/* check if this is WAKEUP event */
+		if (status & 0x1)
+			dev_info(ndev_dev(ndev), "Wakeup is done.\n");
+
+		amd_ack_smu(ndev, AMD_PEER_D0_EVENT);
+
+		/* start a timer to poll link status */
+		schedule_delayed_work(&ndev->hb_timer,
+				      AMD_LINK_HB_TIMEOUT);
+		break;
+	default:
+		dev_info(ndev_dev(ndev), "event status = 0x%x.\n", status);
+		break;
+	}
+}
+
+static irqreturn_t ndev_interrupt(struct amd_ntb_dev *ndev, int vec)
+{
+	dev_dbg(ndev_dev(ndev), "vec %d\n", vec);
+
+	if (vec > (AMD_DB_CNT - 1) || (ndev->msix_vec_count == 1))
+		amd_handle_event(ndev, vec);
+
+	if (vec < AMD_DB_CNT)
+		ntb_db_event(&ndev->ntb, vec);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t ndev_vec_isr(int irq, void *dev)
+{
+	struct amd_ntb_vec *nvec = dev;
+
+	return ndev_interrupt(nvec->ndev, nvec->num);
+}
+
+static irqreturn_t ndev_irq_isr(int irq, void *dev)
+{
+	struct amd_ntb_dev *ndev = dev;
+
+	return ndev_interrupt(ndev, irq - ndev_pdev(ndev)->irq);
+}
+
+static int ndev_init_isr(struct amd_ntb_dev *ndev,
+			 int msix_min, int msix_max)
+{
+	struct pci_dev *pdev;
+	int rc, i, msix_count, node;
+
+	pdev = ndev_pdev(ndev);
+
+	node = dev_to_node(&pdev->dev);
+
+	ndev->db_mask = ndev->db_valid_mask;
+
+	/* Try to set up msix irq */
+	ndev->vec = kzalloc_node(msix_max * sizeof(*ndev->vec),
+				 GFP_KERNEL, node);
+	if (!ndev->vec)
+		goto err_msix_vec_alloc;
+
+	ndev->msix = kzalloc_node(msix_max * sizeof(*ndev->msix),
+				  GFP_KERNEL, node);
+	if (!ndev->msix)
+		goto err_msix_alloc;
+
+	for (i = 0; i < msix_max; ++i)
+		ndev->msix[i].entry = i;
+
+	msix_count = pci_enable_msix_range(pdev, ndev->msix,
+					   msix_min, msix_max);
+	if (msix_count < 0)
+		goto err_msix_enable;
+
+	/* NOTE: Disable MSIX if msix count is less than 16 because of
+	 * hardware limitation.
+	 */
+	if (msix_count < msix_min) {
+		pci_disable_msix(pdev);
+		goto err_msix_enable;
+	}
+
+	for (i = 0; i < msix_count; ++i) {
+		ndev->vec[i].ndev = ndev;
+		ndev->vec[i].num = i;
+		rc = request_irq(ndev->msix[i].vector, ndev_vec_isr, 0,
+				 "ndev_vec_isr", &ndev->vec[i]);
+		if (rc)
+			goto err_msix_request;
+	}
+
+	dev_dbg(ndev_dev(ndev), "Using msix interrupts\n");
+	ndev->db_count = msix_min;
+	ndev->msix_vec_count = msix_max;
+	return 0;
+
+err_msix_request:
+	while (i-- > 0)
+		free_irq(ndev->msix[i].vector, ndev);
+	pci_disable_msix(pdev);
+err_msix_enable:
+	kfree(ndev->msix);
+err_msix_alloc:
+	kfree(ndev->vec);
+err_msix_vec_alloc:
+	ndev->msix = NULL;
+	ndev->vec = NULL;
+
+	/* Try to set up msi irq */
+	rc = pci_enable_msi(pdev);
+	if (rc)
+		goto err_msi_enable;
+
+	rc = request_irq(pdev->irq, ndev_irq_isr, 0,
+			 "ndev_irq_isr", ndev);
+	if (rc)
+		goto err_msi_request;
+
+	dev_dbg(ndev_dev(ndev), "Using msi interrupts\n");
+	ndev->db_count = 1;
+	ndev->msix_vec_count = 1;
+	return 0;
+
+err_msi_request:
+	pci_disable_msi(pdev);
+err_msi_enable:
+
+	/* Try to set up intx irq */
+	pci_intx(pdev, 1);
+
+	rc = request_irq(pdev->irq, ndev_irq_isr, IRQF_SHARED,
+			 "ndev_irq_isr", ndev);
+	if (rc)
+		goto err_intx_request;
+
+	dev_dbg(ndev_dev(ndev), "Using intx interrupts\n");
+	ndev->db_count = 1;
+	ndev->msix_vec_count = 1;
+	return 0;
+
+err_intx_request:
+	return rc;
+}
+
+static void ndev_deinit_isr(struct amd_ntb_dev *ndev)
+{
+	struct pci_dev *pdev;
+	void __iomem *mmio = ndev->self_mmio;
+	int i;
+
+	pdev = ndev_pdev(ndev);
+
+	/* Mask all doorbell interrupts */
+	ndev->db_mask = ndev->db_valid_mask;
+	writel(ndev->db_mask, mmio + AMD_DBMASK_OFFSET);
+
+	if (ndev->msix) {
+		i = ndev->msix_vec_count;
+		while (i--)
+			free_irq(ndev->msix[i].vector, &ndev->vec[i]);
+		pci_disable_msix(pdev);
+		kfree(ndev->msix);
+		kfree(ndev->vec);
+	} else {
+		free_irq(pdev->irq, ndev);
+		if (pci_dev_msi_enabled(pdev))
+			pci_disable_msi(pdev);
+		else
+			pci_intx(pdev, 0);
+	}
+}
+
+static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
+				 size_t count, loff_t *offp)
+{
+	struct amd_ntb_dev *ndev;
+	void __iomem *mmio;
+	char *buf;
+	size_t buf_size;
+	ssize_t ret, off;
+	union { u64 v64; u32 v32; u16 v16; } u;
+
+	ndev = filp->private_data;
+	mmio = ndev->self_mmio;
+
+	buf_size = min(count, 0x800ul);
+
+	buf = kmalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	off = 0;
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "NTB Device Information:\n");
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Connection Topology -\t%s\n",
+			 ntb_topo_string(ndev->ntb.topo));
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "LNK STA -\t\t%#06x\n", ndev->lnk_sta);
+
+	if (!amd_link_is_up(ndev)) {
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Status -\t\tDown\n");
+	} else {
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Status -\t\tUp\n");
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Speed -\t\tPCI-E Gen %u\n",
+				 NTB_LNK_STA_SPEED(ndev->lnk_sta));
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Width -\t\tx%u\n",
+				 NTB_LNK_STA_WIDTH(ndev->lnk_sta));
+	}
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Memory Window Count -\t%u\n", ndev->mw_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Scratchpad Count -\t%u\n", ndev->spad_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Count -\t%u\n", ndev->db_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "MSIX Vector Count -\t%u\n", ndev->msix_vec_count);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask);
+
+	u.v32 = readl(ndev->self_mmio + AMD_DBMASK_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Mask -\t\t\t%#06x\n", u.v32);
+
+	u.v32 = readl(mmio + AMD_DBSTAT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Bell -\t\t\t%#06x\n", u.v32);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "\nNTB Incoming XLAT:\n");
+
+	u.v64 = read64(mmio + AMD_BAR1XLAT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "XLAT1 -\t\t%#018llx\n", u.v64);
+
+	u.v64 = read64(ndev->self_mmio + AMD_BAR23XLAT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "XLAT23 -\t\t%#018llx\n", u.v64);
+
+	u.v64 = read64(ndev->self_mmio + AMD_BAR45XLAT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "XLAT45 -\t\t%#018llx\n", u.v64);
+
+	u.v32 = readl(mmio + AMD_BAR1LMT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "LMT1 -\t\t\t%#06x\n", u.v32);
+
+	u.v64 = read64(ndev->self_mmio + AMD_BAR23LMT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "LMT23 -\t\t\t%#018llx\n", u.v64);
+
+	u.v64 = read64(ndev->self_mmio + AMD_BAR45LMT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "LMT45 -\t\t\t%#018llx\n", u.v64);
+
+	ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
+	kfree(buf);
+	return ret;
+}
+
+static void ndev_init_debugfs(struct amd_ntb_dev *ndev)
+{
+	if (!debugfs_dir) {
+		ndev->debugfs_dir = NULL;
+		ndev->debugfs_info = NULL;
+	} else {
+		ndev->debugfs_dir =
+			debugfs_create_dir(ndev_name(ndev), debugfs_dir);
+		if (!ndev->debugfs_dir)
+			ndev->debugfs_info = NULL;
+		else
+			ndev->debugfs_info =
+				debugfs_create_file("info", S_IRUSR,
+						    ndev->debugfs_dir, ndev,
+						    &amd_ntb_debugfs_info);
+	}
+}
+
+static void ndev_deinit_debugfs(struct amd_ntb_dev *ndev)
+{
+	debugfs_remove_recursive(ndev->debugfs_dir);
+}
+
+static inline void ndev_init_struct(struct amd_ntb_dev *ndev,
+				    struct pci_dev *pdev)
+{
+	ndev->ntb.pdev = pdev;
+	ndev->ntb.topo = NTB_TOPO_NONE;
+	ndev->ntb.ops = &amd_ntb_ops;
+	ndev->int_mask = AMD_EVENT_INTMASK;
+	spin_lock_init(&ndev->db_mask_lock);
+}
+
+static int amd_poll_link(struct amd_ntb_dev *ndev)
+{
+	void __iomem *mmio = ndev->peer_mmio;
+	u32 reg, stat;
+	int rc;
+
+	reg = readl(mmio + AMD_SIDEINFO_OFFSET);
+	reg &= NTB_LIN_STA_ACTIVE_BIT;
+
+	dev_dbg(ndev_dev(ndev), "%s: reg_val = 0x%x.\n", __func__, reg);
+
+	if (reg == ndev->cntl_sta)
+		return 0;
+
+	ndev->cntl_sta = reg;
+
+	rc = pci_read_config_dword(ndev->ntb.pdev,
+				   AMD_LINK_STATUS_OFFSET, &stat);
+	if (rc)
+		return 0;
+	ndev->lnk_sta = stat;
+
+	return 1;
+}
+
+static void amd_link_hb(struct work_struct *work)
+{
+	struct amd_ntb_dev *ndev = hb_ndev(work);
+
+	if (amd_poll_link(ndev))
+		ntb_link_event(&ndev->ntb);
+
+	if (!amd_link_is_up(ndev))
+		schedule_delayed_work(&ndev->hb_timer, AMD_LINK_HB_TIMEOUT);
+}
+
+static int amd_init_isr(struct amd_ntb_dev *ndev)
+{
+	return ndev_init_isr(ndev, AMD_DB_CNT, AMD_MSIX_VECTOR_CNT);
+}
+
+static void amd_init_side_info(struct amd_ntb_dev *ndev)
+{
+	void __iomem *mmio = ndev->self_mmio;
+	unsigned int reg;
+
+	reg = readl(mmio + AMD_SIDEINFO_OFFSET);
+	if (!(reg & AMD_SIDE_READY)) {
+		reg |= AMD_SIDE_READY;
+		writel(reg, mmio + AMD_SIDEINFO_OFFSET);
+	}
+}
+
+static void amd_deinit_side_info(struct amd_ntb_dev *ndev)
+{
+	void __iomem *mmio = ndev->self_mmio;
+	unsigned int reg;
+
+	reg = readl(mmio + AMD_SIDEINFO_OFFSET);
+	if (reg & AMD_SIDE_READY) {
+		reg &= ~AMD_SIDE_READY;
+		writel(reg, mmio + AMD_SIDEINFO_OFFSET);
+		readl(mmio + AMD_SIDEINFO_OFFSET);
+	}
+}
+
+static int amd_init_ntb(struct amd_ntb_dev *ndev)
+{
+	void __iomem *mmio = ndev->self_mmio;
+
+	ndev->mw_count = AMD_MW_CNT;
+	ndev->spad_count = AMD_SPADS_CNT;
+	ndev->db_count = AMD_DB_CNT;
+
+	switch (ndev->ntb.topo) {
+	case NTB_TOPO_PRI:
+	case NTB_TOPO_SEC:
+		ndev->spad_count >>= 1;
+		if (ndev->ntb.topo == NTB_TOPO_PRI) {
+			ndev->self_spad = 0;
+			ndev->peer_spad = 0x20;
+		} else {
+			ndev->self_spad = 0x20;
+			ndev->peer_spad = 0;
+		}
+
+		INIT_DELAYED_WORK(&ndev->hb_timer, amd_link_hb);
+		schedule_delayed_work(&ndev->hb_timer, AMD_LINK_HB_TIMEOUT);
+
+		break;
+	default:
+		dev_err(ndev_dev(ndev), "AMD NTB does not support B2B mode.\n");
+		return -EINVAL;
+	}
+
+	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
+
+	/* Mask event interrupts */
+	writel(ndev->int_mask, mmio + AMD_INTMASK_OFFSET);
+
+	return 0;
+}
+
+static enum ntb_topo amd_get_topo(struct amd_ntb_dev *ndev)
+{
+	void __iomem *mmio = ndev->self_mmio;
+	u32 info;
+
+	info = readl(mmio + AMD_SIDEINFO_OFFSET);
+	if (info & AMD_SIDE_MASK)
+		return NTB_TOPO_SEC;
+	else
+		return NTB_TOPO_PRI;
+}
+
+static int amd_init_dev(struct amd_ntb_dev *ndev)
+{
+	struct pci_dev *pdev;
+	int rc = 0;
+
+	pdev = ndev_pdev(ndev);
+
+	ndev->ntb.topo = amd_get_topo(ndev);
+	dev_dbg(ndev_dev(ndev), "AMD NTB topo is %s\n",
+		ntb_topo_string(ndev->ntb.topo));
+
+	rc = amd_init_ntb(ndev);
+	if (rc)
+		return rc;
+
+	rc = amd_init_isr(ndev);
+	if (rc) {
+		dev_err(ndev_dev(ndev), "fail to init isr.\n");
+		return rc;
+	}
+
+	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
+
+	return 0;
+}
+
+static void amd_deinit_dev(struct amd_ntb_dev *ndev)
+{
+	cancel_delayed_work_sync(&ndev->hb_timer);
+
+	ndev_deinit_isr(ndev);
+}
+
+static int amd_ntb_init_pci(struct amd_ntb_dev *ndev,
+			    struct pci_dev *pdev)
+{
+	int rc;
+
+	pci_set_drvdata(pdev, ndev);
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_pci_enable;
+
+	rc = pci_request_regions(pdev, NTB_NAME);
+	if (rc)
+		goto err_pci_regions;
+
+	pci_set_master(pdev);
+
+	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (rc) {
+		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc)
+			goto err_dma_mask;
+		dev_warn(ndev_dev(ndev), "Cannot DMA highmem\n");
+	}
+
+	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (rc) {
+		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc)
+			goto err_dma_mask;
+		dev_warn(ndev_dev(ndev), "Cannot DMA consistent highmem\n");
+	}
+
+	ndev->self_mmio = pci_iomap(pdev, 0, 0);
+	if (!ndev->self_mmio) {
+		rc = -EIO;
+		goto err_dma_mask;
+	}
+	ndev->peer_mmio = ndev->self_mmio + AMD_PEER_OFFSET;
+
+	return 0;
+
+err_dma_mask:
+	pci_clear_master(pdev);
+err_pci_regions:
+	pci_disable_device(pdev);
+err_pci_enable:
+	pci_set_drvdata(pdev, NULL);
+	return rc;
+}
+
+static void amd_ntb_deinit_pci(struct amd_ntb_dev *ndev)
+{
+	struct pci_dev *pdev = ndev_pdev(ndev);
+
+	pci_iounmap(pdev, ndev->self_mmio);
+
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int amd_ntb_pci_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *id)
+{
+	struct amd_ntb_dev *ndev;
+	int rc, node;
+
+	node = dev_to_node(&pdev->dev);
+
+	ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node);
+	if (!ndev) {
+		rc = -ENOMEM;
+		goto err_ndev;
+	}
+
+	ndev_init_struct(ndev, pdev);
+
+	rc = amd_ntb_init_pci(ndev, pdev);
+	if (rc)
+		goto err_init_pci;
+
+	rc = amd_init_dev(ndev);
+	if (rc)
+		goto err_init_dev;
+
+	/* write side info */
+	amd_init_side_info(ndev);
+
+	amd_poll_link(ndev);
+
+	ndev_init_debugfs(ndev);
+
+	rc = ntb_register_device(&ndev->ntb);
+	if (rc)
+		goto err_register;
+
+	dev_info(&pdev->dev, "NTB device registered.\n");
+
+	return 0;
+
+err_register:
+	ndev_deinit_debugfs(ndev);
+	amd_deinit_dev(ndev);
+err_init_dev:
+	amd_ntb_deinit_pci(ndev);
+err_init_pci:
+	kfree(ndev);
+err_ndev:
+	return rc;
+}
+
+static void amd_ntb_pci_remove(struct pci_dev *pdev)
+{
+	struct amd_ntb_dev *ndev = pci_get_drvdata(pdev);
+
+	ntb_unregister_device(&ndev->ntb);
+	ndev_deinit_debugfs(ndev);
+	amd_deinit_side_info(ndev);
+	amd_deinit_dev(ndev);
+	amd_ntb_deinit_pci(ndev);
+	kfree(ndev);
+}
+
+static const struct file_operations amd_ntb_debugfs_info = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = ndev_debugfs_read,
+};
+
+static const struct pci_device_id amd_ntb_pci_tbl[] = {
+	{PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NTB)},
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, amd_ntb_pci_tbl);
+
+static struct pci_driver amd_ntb_pci_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= amd_ntb_pci_tbl,
+	.probe		= amd_ntb_pci_probe,
+	.remove		= amd_ntb_pci_remove,
+};
+
+static int __init amd_ntb_pci_driver_init(void)
+{
+	pr_info("%s %s\n", NTB_DESC, NTB_VER);
+
+	if (debugfs_initialized())
+		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+	return pci_register_driver(&amd_ntb_pci_driver);
+}
+module_init(amd_ntb_pci_driver_init);
+
+static void __exit amd_ntb_pci_driver_exit(void)
+{
+	pci_unregister_driver(&amd_ntb_pci_driver);
+	debugfs_remove_recursive(debugfs_dir);
+}
+module_exit(amd_ntb_pci_driver_exit);
--- linux-4.4.0.orig/drivers/ntb/hw/amd/ntb_hw_amd.h
+++ linux-4.4.0/drivers/ntb/hw/amd/ntb_hw_amd.h
@@ -0,0 +1,217 @@
+/*
+ * 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) 2016 Advanced Micro Devices, Inc. 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.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of AMD 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.
+ *
+ * AMD PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Xiangliang Yu <Xiangliang.Yu@amd.com>
+ */
+
+#ifndef NTB_HW_AMD_H
+#define NTB_HW_AMD_H
+
+#include <linux/ntb.h>
+#include <linux/pci.h>
+
+#define PCI_DEVICE_ID_AMD_NTB	0x145B
+#define AMD_LINK_HB_TIMEOUT	msecs_to_jiffies(1000)
+#define AMD_LINK_STATUS_OFFSET	0x68
+#define NTB_LIN_STA_ACTIVE_BIT	0x00000002
+#define NTB_LNK_STA_SPEED_MASK	0x000F0000
+#define NTB_LNK_STA_WIDTH_MASK	0x03F00000
+#define NTB_LNK_STA_ACTIVE(x)	(!!((x) & NTB_LIN_STA_ACTIVE_BIT))
+#define NTB_LNK_STA_SPEED(x)	(((x) & NTB_LNK_STA_SPEED_MASK) >> 16)
+#define NTB_LNK_STA_WIDTH(x)	(((x) & NTB_LNK_STA_WIDTH_MASK) >> 20)
+
+#ifndef read64
+#ifdef readq
+#define read64 readq
+#else
+#define read64 _read64
+static inline u64 _read64(void __iomem *mmio)
+{
+	u64 low, high;
+
+	low = readl(mmio);
+	high = readl(mmio + sizeof(u32));
+	return low | (high << 32);
+}
+#endif
+#endif
+
+#ifndef write64
+#ifdef writeq
+#define write64 writeq
+#else
+#define write64 _write64
+static inline void _write64(u64 val, void __iomem *mmio)
+{
+	writel(val, mmio);
+	writel(val >> 32, mmio + sizeof(u32));
+}
+#endif
+#endif
+
+enum {
+	/* AMD NTB Capability */
+	AMD_MW_CNT		= 3,
+	AMD_DB_CNT		= 16,
+	AMD_MSIX_VECTOR_CNT	= 24,
+	AMD_SPADS_CNT		= 16,
+
+	/*  AMD NTB register offset */
+	AMD_CNTL_OFFSET		= 0x200,
+
+	/* NTB control register bits */
+	PMM_REG_CTL		= BIT(21),
+	SMM_REG_CTL		= BIT(20),
+	SMM_REG_ACC_PATH	= BIT(18),
+	PMM_REG_ACC_PATH	= BIT(17),
+	NTB_CLK_EN		= BIT(16),
+
+	AMD_STA_OFFSET		= 0x204,
+	AMD_PGSLV_OFFSET	= 0x208,
+	AMD_SPAD_MUX_OFFSET	= 0x20C,
+	AMD_SPAD_OFFSET		= 0x210,
+	AMD_RSMU_HCID		= 0x250,
+	AMD_RSMU_SIID		= 0x254,
+	AMD_PSION_OFFSET	= 0x300,
+	AMD_SSION_OFFSET	= 0x330,
+	AMD_MMINDEX_OFFSET	= 0x400,
+	AMD_MMDATA_OFFSET	= 0x404,
+	AMD_SIDEINFO_OFFSET	= 0x408,
+
+	AMD_SIDE_MASK		= BIT(0),
+	AMD_SIDE_READY		= BIT(1),
+
+	/* limit register */
+	AMD_ROMBARLMT_OFFSET	= 0x410,
+	AMD_BAR1LMT_OFFSET	= 0x414,
+	AMD_BAR23LMT_OFFSET	= 0x418,
+	AMD_BAR45LMT_OFFSET	= 0x420,
+	/* xlat address */
+	AMD_POMBARXLAT_OFFSET	= 0x428,
+	AMD_BAR1XLAT_OFFSET	= 0x430,
+	AMD_BAR23XLAT_OFFSET	= 0x438,
+	AMD_BAR45XLAT_OFFSET	= 0x440,
+	/* doorbell and interrupt */
+	AMD_DBFM_OFFSET		= 0x450,
+	AMD_DBREQ_OFFSET	= 0x454,
+	AMD_MIRRDBSTAT_OFFSET	= 0x458,
+	AMD_DBMASK_OFFSET	= 0x45C,
+	AMD_DBSTAT_OFFSET	= 0x460,
+	AMD_INTMASK_OFFSET	= 0x470,
+	AMD_INTSTAT_OFFSET	= 0x474,
+
+	/* event type */
+	AMD_PEER_FLUSH_EVENT	= BIT(0),
+	AMD_PEER_RESET_EVENT	= BIT(1),
+	AMD_PEER_D3_EVENT	= BIT(2),
+	AMD_PEER_PMETO_EVENT	= BIT(3),
+	AMD_PEER_D0_EVENT	= BIT(4),
+	AMD_EVENT_INTMASK	= (AMD_PEER_FLUSH_EVENT |
+				AMD_PEER_RESET_EVENT | AMD_PEER_D3_EVENT |
+				AMD_PEER_PMETO_EVENT | AMD_PEER_D0_EVENT),
+
+	AMD_PMESTAT_OFFSET	= 0x480,
+	AMD_PMSGTRIG_OFFSET	= 0x490,
+	AMD_LTRLATENCY_OFFSET	= 0x494,
+	AMD_FLUSHTRIG_OFFSET	= 0x498,
+
+	/* SMU register*/
+	AMD_SMUACK_OFFSET	= 0x4A0,
+	AMD_SINRST_OFFSET	= 0x4A4,
+	AMD_RSPNUM_OFFSET	= 0x4A8,
+	AMD_SMU_SPADMUTEX	= 0x4B0,
+	AMD_SMU_SPADOFFSET	= 0x4B4,
+
+	AMD_PEER_OFFSET		= 0x400,
+};
+
+struct amd_ntb_dev;
+
+struct amd_ntb_vec {
+	struct amd_ntb_dev	*ndev;
+	int			num;
+};
+
+struct amd_ntb_dev {
+	struct ntb_dev ntb;
+
+	u32 ntb_side;
+	u32 lnk_sta;
+	u32 cntl_sta;
+	u32 peer_sta;
+
+	unsigned char mw_count;
+	unsigned char spad_count;
+	unsigned char db_count;
+	unsigned char msix_vec_count;
+
+	u64 db_valid_mask;
+	u64 db_mask;
+	u32 int_mask;
+
+	struct msix_entry *msix;
+	struct amd_ntb_vec *vec;
+
+	/* synchronize rmw access of db_mask and hw reg */
+	spinlock_t db_mask_lock;
+
+	void __iomem *self_mmio;
+	void __iomem *peer_mmio;
+	unsigned int self_spad;
+	unsigned int peer_spad;
+
+	struct delayed_work hb_timer;
+
+	struct dentry *debugfs_dir;
+	struct dentry *debugfs_info;
+};
+
+#define ndev_pdev(ndev) ((ndev)->ntb.pdev)
+#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
+#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
+#define ntb_ndev(__ntb) container_of(__ntb, struct amd_ntb_dev, ntb)
+#define hb_ndev(__work) container_of(__work, struct amd_ntb_dev, hb_timer.work)
+
+#endif
--- linux-4.4.0.orig/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ linux-4.4.0/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -330,7 +330,7 @@
 	return 0;
 }
 
-static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
+static inline u64 ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
 {
 	u64 shift, mask;
 
--- linux-4.4.0.orig/drivers/ntb/ntb_transport.c
+++ linux-4.4.0/drivers/ntb/ntb_transport.c
@@ -599,7 +599,7 @@
 	if (!mw->virt_addr)
 		return -ENOMEM;
 
-	if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
+	if (mw_num < qp_count % mw_count)
 		num_qps_mw = qp_count / mw_count + 1;
 	else
 		num_qps_mw = qp_count / mw_count;
@@ -947,7 +947,7 @@
 	qp->event_handler = NULL;
 	ntb_qp_link_down_reset(qp);
 
-	if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
+	if (mw_num < qp_count % mw_count)
 		num_qps_mw = qp_count / mw_count + 1;
 	else
 		num_qps_mw = qp_count / mw_count;
@@ -955,6 +955,9 @@
 	mw_base = nt->mw_vec[mw_num].phys_addr;
 	mw_size = nt->mw_vec[mw_num].phys_size;
 
+	if (max_mw_size && mw_size > max_mw_size)
+		mw_size = max_mw_size;
+
 	tx_size = (unsigned int)mw_size / num_qps_mw;
 	qp_offset = tx_size * (qp_num / mw_count);
 
@@ -1065,8 +1068,8 @@
 	qp_count = ilog2(qp_bitmap);
 	if (max_num_clients && max_num_clients < qp_count)
 		qp_count = max_num_clients;
-	else if (mw_count < qp_count)
-		qp_count = mw_count;
+	else if (nt->mw_count < qp_count)
+		qp_count = nt->mw_count;
 
 	qp_bitmap &= BIT_ULL(qp_count) - 1;
 
@@ -1623,7 +1626,7 @@
 
 	node = dev_to_node(&ndev->dev);
 
-	free_queue = ffs(nt->qp_bitmap);
+	free_queue = ffs(nt->qp_bitmap_free);
 	if (!free_queue)
 		goto err;
 
@@ -2082,9 +2085,8 @@
 
 static void __exit ntb_transport_exit(void)
 {
-	debugfs_remove_recursive(nt_debugfs_dir);
-
 	ntb_unregister_client(&ntb_transport_client);
 	bus_unregister(&ntb_transport_bus);
+	debugfs_remove_recursive(nt_debugfs_dir);
 }
 module_exit(ntb_transport_exit);
--- linux-4.4.0.orig/drivers/nvdimm/btt.c
+++ linux-4.4.0/drivers/nvdimm/btt.c
@@ -443,9 +443,9 @@
 
 static int btt_freelist_init(struct arena_info *arena)
 {
-	int old, new, ret;
+	int new, ret;
 	u32 i, map_entry;
-	struct log_entry log_new, log_old;
+	struct log_entry log_new;
 
 	arena->freelist = kcalloc(arena->nfree, sizeof(struct free_entry),
 					GFP_KERNEL);
@@ -453,10 +453,6 @@
 		return -ENOMEM;
 
 	for (i = 0; i < arena->nfree; i++) {
-		old = btt_log_read(arena, i, &log_old, LOG_OLD_ENT);
-		if (old < 0)
-			return old;
-
 		new = btt_log_read(arena, i, &log_new, LOG_NEW_ENT);
 		if (new < 0)
 			return new;
@@ -1205,10 +1201,13 @@
 		struct page *page, int rw)
 {
 	struct btt *btt = bdev->bd_disk->private_data;
+	int rc;
 
-	btt_do_bvec(btt, NULL, page, PAGE_CACHE_SIZE, 0, rw, sector);
-	page_endio(page, rw & WRITE, 0);
-	return 0;
+	rc = btt_do_bvec(btt, NULL, page, PAGE_CACHE_SIZE, 0, rw, sector);
+	if (rc == 0)
+		page_endio(page, rw & WRITE, 0);
+
+	return rc;
 }
 
 
--- linux-4.4.0.orig/drivers/nvdimm/btt_devs.c
+++ linux-4.4.0/drivers/nvdimm/btt_devs.c
@@ -170,14 +170,15 @@
 		return NULL;
 
 	nd_btt->id = ida_simple_get(&nd_region->btt_ida, 0, 0, GFP_KERNEL);
-	if (nd_btt->id < 0) {
-		kfree(nd_btt);
-		return NULL;
-	}
+	if (nd_btt->id < 0)
+		goto out_nd_btt;
 
 	nd_btt->lbasize = lbasize;
-	if (uuid)
+	if (uuid) {
 		uuid = kmemdup(uuid, 16, GFP_KERNEL);
+		if (!uuid)
+			goto out_put_id;
+	}
 	nd_btt->uuid = uuid;
 	dev = &nd_btt->dev;
 	dev_set_name(dev, "btt%d.%d", nd_region->id, nd_btt->id);
@@ -192,6 +193,13 @@
 		return NULL;
 	}
 	return dev;
+
+out_put_id:
+	ida_simple_remove(&nd_region->btt_ida, nd_btt->id);
+
+out_nd_btt:
+	kfree(nd_btt);
+	return NULL;
 }
 
 struct device *nd_btt_create(struct nd_region *nd_region)
--- linux-4.4.0.orig/drivers/nvdimm/bus.c
+++ linux-4.4.0/drivers/nvdimm/bus.c
@@ -158,6 +158,8 @@
 		put_device(dev);
 	}
 	put_device(dev);
+	if (dev->parent)
+		put_device(dev->parent);
 }
 
 static void nd_async_device_unregister(void *d, async_cookie_t cookie)
@@ -175,6 +177,8 @@
 void __nd_device_register(struct device *dev)
 {
 	dev->bus = &nvdimm_bus_type;
+	if (dev->parent)
+		get_device(dev->parent);
 	get_device(dev);
 	async_schedule_domain(nd_async_device_register, dev,
 			&nd_async_domain);
@@ -237,14 +241,18 @@
 {
 	struct device *dev = disk->driverfs_dev;
 	struct nd_region *nd_region = to_nd_region(dev->parent);
-	const char *pol = nd_region->ro ? "only" : "write";
+	int disk_ro = get_disk_ro(disk);
 
-	if (nd_region->ro == get_disk_ro(disk))
+	/*
+	 * Upgrade to read-only if the region is read-only preserve as
+	 * read-only if the disk is already read-only.
+	 */
+	if (disk_ro || nd_region->ro == disk_ro)
 		return 0;
 
-	dev_info(dev, "%s read-%s, marking %s read-%s\n",
-			dev_name(&nd_region->dev), pol, disk->disk_name, pol);
-	set_disk_ro(disk, nd_region->ro);
+	dev_info(dev, "%s read-only, marking %s read-only\n",
+			dev_name(&nd_region->dev), disk->disk_name);
+	set_disk_ro(disk, 1);
 
 	return 0;
 
@@ -335,7 +343,7 @@
 	[ND_CMD_IMPLEMENTED] = { },
 	[ND_CMD_SMART] = {
 		.out_num = 2,
-		.out_sizes = { 4, 8, },
+		.out_sizes = { 4, 128, },
 	},
 	[ND_CMD_SMART_THRESHOLD] = {
 		.out_num = 2,
@@ -513,10 +521,10 @@
 
 	/* fail write commands (when read-only) */
 	if (read_only)
-		switch (ioctl_cmd) {
-		case ND_IOCTL_VENDOR:
-		case ND_IOCTL_SET_CONFIG_DATA:
-		case ND_IOCTL_ARS_START:
+		switch (cmd) {
+		case ND_CMD_VENDOR:
+		case ND_CMD_SET_CONFIG_DATA:
+		case ND_CMD_ARS_START:
 			dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
 					nvdimm ? nvdimm_cmd_name(cmd)
 					: nvdimm_bus_cmd_name(cmd));
@@ -590,8 +598,14 @@
 	rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len);
 	if (rc < 0)
 		goto out_unlock;
+	nvdimm_bus_unlock(&nvdimm_bus->dev);
+
 	if (copy_to_user(p, buf, buf_len))
 		rc = -EFAULT;
+
+	vfree(buf);
+	return rc;
+
  out_unlock:
 	nvdimm_bus_unlock(&nvdimm_bus->dev);
  out:
--- linux-4.4.0.orig/drivers/nvdimm/dimm_devs.c
+++ linux-4.4.0/drivers/nvdimm/dimm_devs.c
@@ -303,16 +303,16 @@
 }
 static DEVICE_ATTR_RO(state);
 
-static ssize_t available_slots_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t __available_slots_show(struct nvdimm_drvdata *ndd, char *buf)
 {
-	struct nvdimm_drvdata *ndd = dev_get_drvdata(dev);
+	struct device *dev;
 	ssize_t rc;
 	u32 nfree;
 
 	if (!ndd)
 		return -ENXIO;
 
+	dev = ndd->dev;
 	nvdimm_bus_lock(dev);
 	nfree = nd_label_nfree(ndd);
 	if (nfree - 1 > nfree) {
@@ -324,6 +324,18 @@
 	nvdimm_bus_unlock(dev);
 	return rc;
 }
+
+static ssize_t available_slots_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	ssize_t rc;
+
+	device_lock(dev);
+	rc = __available_slots_show(dev_get_drvdata(dev), buf);
+	device_unlock(dev);
+
+	return rc;
+}
 static DEVICE_ATTR_RO(available_slots);
 
 static struct attribute *nvdimm_attributes[] = {
--- linux-4.4.0.orig/drivers/nvdimm/label.c
+++ linux-4.4.0/drivers/nvdimm/label.c
@@ -823,7 +823,7 @@
 	nsindex = to_namespace_index(ndd, 0);
 	memset(nsindex, 0, ndd->nsarea.config_size);
 	for (i = 0; i < 2; i++) {
-		int rc = nd_label_write_index(ndd, i, i*2, ND_NSINDEX_INIT);
+		int rc = nd_label_write_index(ndd, i, 3 - i, ND_NSINDEX_INIT);
 
 		if (rc)
 			return rc;
--- linux-4.4.0.orig/drivers/nvdimm/namespace_devs.c
+++ linux-4.4.0/drivers/nvdimm/namespace_devs.c
@@ -77,6 +77,59 @@
 	return dev ? dev->type == &namespace_io_device_type : false;
 }
 
+static int is_uuid_busy(struct device *dev, void *data)
+{
+	u8 *uuid1 = data, *uuid2 = NULL;
+
+	if (is_namespace_pmem(dev)) {
+		struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
+
+		uuid2 = nspm->uuid;
+	} else if (is_namespace_blk(dev)) {
+		struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
+
+		uuid2 = nsblk->uuid;
+	} else if (is_nd_btt(dev)) {
+		struct nd_btt *nd_btt = to_nd_btt(dev);
+
+		uuid2 = nd_btt->uuid;
+	} else if (is_nd_pfn(dev)) {
+		struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+
+		uuid2 = nd_pfn->uuid;
+	}
+
+	if (uuid2 && memcmp(uuid1, uuid2, NSLABEL_UUID_LEN) == 0)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int is_namespace_uuid_busy(struct device *dev, void *data)
+{
+	if (is_nd_pmem(dev) || is_nd_blk(dev))
+		return device_for_each_child(dev, data, is_uuid_busy);
+	return 0;
+}
+
+/**
+ * nd_is_uuid_unique - verify that no other namespace has @uuid
+ * @dev: any device on a nvdimm_bus
+ * @uuid: uuid to check
+ */
+bool nd_is_uuid_unique(struct device *dev, u8 *uuid)
+{
+	struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+
+	if (!nvdimm_bus)
+		return false;
+	WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm_bus->dev));
+	if (device_for_each_child(&nvdimm_bus->dev, uuid,
+				is_namespace_uuid_busy) != 0)
+		return false;
+	return true;
+}
+
 bool pmem_should_map_pages(struct device *dev)
 {
 	struct nd_region *nd_region = to_nd_region(dev->parent);
@@ -1252,7 +1305,7 @@
 	if (a == &dev_attr_resource.attr) {
 		if (is_namespace_blk(dev))
 			return 0;
-		return a->mode;
+		return 0400;
 	}
 
 	if (is_namespace_pmem(dev) || is_namespace_blk(dev)) {
@@ -1481,6 +1534,7 @@
 static int find_pmem_label_set(struct nd_region *nd_region,
 		struct nd_namespace_pmem *nspm)
 {
+	u64 altcookie = nd_region_interleave_set_altcookie(nd_region);
 	u64 cookie = nd_region_interleave_set_cookie(nd_region);
 	struct nd_namespace_label *nd_label;
 	u8 select_id[NSLABEL_UUID_LEN];
@@ -1489,8 +1543,10 @@
 	int rc = -ENODEV, l;
 	u16 i;
 
-	if (cookie == 0)
+	if (cookie == 0) {
+		dev_dbg(&nd_region->dev, "invalid interleave-set-cookie\n");
 		return -ENXIO;
+	}
 
 	/*
 	 * Find a complete set of labels by uuid.  By definition we can start
@@ -1499,13 +1555,24 @@
 	for_each_label(l, nd_label, nd_region->mapping[0].labels) {
 		u64 isetcookie = __le64_to_cpu(nd_label->isetcookie);
 
-		if (isetcookie != cookie)
-			continue;
+		if (isetcookie != cookie) {
+			dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n",
+					nd_label->uuid);
+			if (isetcookie != altcookie)
+				continue;
+
+			dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n",
+					nd_label->uuid);
+		}
+
+		for (i = 0; nd_region->ndr_mappings; i++) {
+			if (has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i))
+				continue;
+			if (has_uuid_at_pos(nd_region, nd_label->uuid, altcookie, i))
+				continue;
+			break;
+		}
 
-		for (i = 0; nd_region->ndr_mappings; i++)
-			if (!has_uuid_at_pos(nd_region, nd_label->uuid,
-						cookie, i))
-				break;
 		if (i < nd_region->ndr_mappings) {
 			/*
 			 * Give up if we don't find an instance of a
--- linux-4.4.0.orig/drivers/nvdimm/nd.h
+++ linux-4.4.0/drivers/nvdimm/nd.h
@@ -27,7 +27,6 @@
 	 * BTT instance
 	 */
 	ND_MAX_LANES = 256,
-	SECTOR_SHIFT = 9,
 	INT_LBASIZE_ALIGNMENT = 64,
 #if IS_ENABLED(CONFIG_NVDIMM_PFN)
 	ND_PFN_ALIGN = PAGES_PER_SECTION * PAGE_SIZE,
@@ -245,6 +244,7 @@
 int nd_region_to_nstype(struct nd_region *nd_region);
 int nd_region_register_namespaces(struct nd_region *nd_region, int *err);
 u64 nd_region_interleave_set_cookie(struct nd_region *nd_region);
+u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region);
 void nvdimm_bus_lock(struct device *dev);
 void nvdimm_bus_unlock(struct device *dev);
 bool is_nvdimm_bus_locked(struct device *dev);
--- linux-4.4.0.orig/drivers/nvdimm/pfn_devs.c
+++ linux-4.4.0/drivers/nvdimm/pfn_devs.c
@@ -275,7 +275,7 @@
 	} else {
 		/* from init we validate */
 		if (memcmp(nd_pfn->uuid, pfn_sb->uuid, 16) != 0)
-			return -EINVAL;
+			return -ENODEV;
 	}
 
 	/*
--- linux-4.4.0.orig/drivers/nvdimm/region_devs.c
+++ linux-4.4.0/drivers/nvdimm/region_devs.c
@@ -134,62 +134,6 @@
 }
 EXPORT_SYMBOL(nd_region_to_nstype);
 
-static int is_uuid_busy(struct device *dev, void *data)
-{
-	struct nd_region *nd_region = to_nd_region(dev->parent);
-	u8 *uuid = data;
-
-	switch (nd_region_to_nstype(nd_region)) {
-	case ND_DEVICE_NAMESPACE_PMEM: {
-		struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
-
-		if (!nspm->uuid)
-			break;
-		if (memcmp(uuid, nspm->uuid, NSLABEL_UUID_LEN) == 0)
-			return -EBUSY;
-		break;
-	}
-	case ND_DEVICE_NAMESPACE_BLK: {
-		struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
-
-		if (!nsblk->uuid)
-			break;
-		if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) == 0)
-			return -EBUSY;
-		break;
-	}
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int is_namespace_uuid_busy(struct device *dev, void *data)
-{
-	if (is_nd_pmem(dev) || is_nd_blk(dev))
-		return device_for_each_child(dev, data, is_uuid_busy);
-	return 0;
-}
-
-/**
- * nd_is_uuid_unique - verify that no other namespace has @uuid
- * @dev: any device on a nvdimm_bus
- * @uuid: uuid to check
- */
-bool nd_is_uuid_unique(struct device *dev, u8 *uuid)
-{
-	struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
-
-	if (!nvdimm_bus)
-		return false;
-	WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm_bus->dev));
-	if (device_for_each_child(&nvdimm_bus->dev, uuid,
-				is_namespace_uuid_busy) != 0)
-		return false;
-	return true;
-}
-
 static ssize_t size_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -435,6 +379,15 @@
 	return 0;
 }
 
+u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region)
+{
+	struct nd_interleave_set *nd_set = nd_region->nd_set;
+
+	if (nd_set)
+		return nd_set->altcookie;
+	return 0;
+}
+
 /*
  * Upon successful probe/remove, take/release a reference on the
  * associated interleave set (if present), and plant new btt + namespace
--- linux-4.4.0.orig/drivers/nvme/host/Kconfig
+++ linux-4.4.0/drivers/nvme/host/Kconfig
@@ -8,3 +8,23 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called nvme.
+
+config BLK_DEV_NVME_SCSI
+	bool "SCSI emulation for NVMe device nodes"
+	depends on BLK_DEV_NVME
+	---help---
+	  This adds support for the SG_IO ioctl on the NVMe character
+	  and block devices nodes, as well a a translation for a small
+	  number of selected SCSI commands to NVMe commands to the NVMe
+	  driver.  If you don't know what this means you probably want
+	  to say N here, unless you run a distro that abuses the SCSI
+	  emulation to provide stable device names for mount by id, like
+	  some OpenSuSE and SLES versions.
+
+config NVME_VENDOR_EXT_GOOGLE
+	bool "NVMe Vendor Extension for Improved Virtualization"
+	depends on BLK_DEV_NVME
+	---help---
+	  Google extension to reduce the number of MMIO doorbell
+	  writes for the NVMe driver
+
--- linux-4.4.0.orig/drivers/nvme/host/Makefile
+++ linux-4.4.0/drivers/nvme/host/Makefile
@@ -1,5 +1,6 @@
 
 obj-$(CONFIG_BLK_DEV_NVME)     += nvme.o
 
-lightnvm-$(CONFIG_NVM)	:= lightnvm.o
-nvme-y		+= pci.o scsi.o $(lightnvm-y)
+lightnvm-$(CONFIG_NVM)			:= lightnvm.o
+nvme-y					+= core.o pci.o $(lightnvm-y)
+nvme-$(CONFIG_BLK_DEV_NVME_SCSI)        += scsi.o
--- linux-4.4.0.orig/drivers/nvme/host/core.c
+++ linux-4.4.0/drivers/nvme/host/core.c
@@ -0,0 +1,1758 @@
+/*
+ * NVM Express device driver
+ * Copyright (c) 2011-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list_sort.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pr.h>
+#include <linux/ptrace.h>
+#include <linux/nvme_ioctl.h>
+#include <linux/t10-pi.h>
+#include <linux/pm_qos.h>
+#include <scsi/sg.h>
+#include <asm/unaligned.h>
+
+#include "nvme.h"
+
+#define NVME_MINORS		(1U << MINORBITS)
+
+static int nvme_major;
+module_param(nvme_major, int, 0);
+
+static int nvme_char_major;
+module_param(nvme_char_major, int, 0);
+
+static unsigned long default_ps_max_latency_us = 100000;
+module_param(default_ps_max_latency_us, ulong, 0644);
+MODULE_PARM_DESC(default_ps_max_latency_us,
+		 "max power saving latency for new devices; use PM QOS to change per device");
+
+static LIST_HEAD(nvme_ctrl_list);
+DEFINE_SPINLOCK(dev_list_lock);
+
+static struct class *nvme_class;
+
+static void nvme_free_ns(struct kref *kref)
+{
+	struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref);
+
+	if (ns->type == NVME_NS_LIGHTNVM)
+		nvme_nvm_unregister(ns->queue, ns->disk->disk_name);
+
+	spin_lock(&dev_list_lock);
+	ns->disk->private_data = NULL;
+	spin_unlock(&dev_list_lock);
+
+	nvme_put_ctrl(ns->ctrl);
+	put_disk(ns->disk);
+	kfree(ns);
+}
+
+static void nvme_put_ns(struct nvme_ns *ns)
+{
+	kref_put(&ns->kref, nvme_free_ns);
+}
+
+static struct nvme_ns *nvme_get_ns_from_disk(struct gendisk *disk)
+{
+	struct nvme_ns *ns;
+
+	spin_lock(&dev_list_lock);
+	ns = disk->private_data;
+	if (ns && !kref_get_unless_zero(&ns->kref))
+		ns = NULL;
+	spin_unlock(&dev_list_lock);
+
+	return ns;
+}
+
+void nvme_requeue_req(struct request *req)
+{
+	unsigned long flags;
+
+	blk_mq_requeue_request(req);
+	spin_lock_irqsave(req->q->queue_lock, flags);
+	if (!blk_queue_stopped(req->q))
+		blk_mq_kick_requeue_list(req->q);
+	spin_unlock_irqrestore(req->q->queue_lock, flags);
+}
+
+struct request *nvme_alloc_request(struct request_queue *q,
+		struct nvme_command *cmd, unsigned int flags, int qid)
+{
+	struct request *req;
+
+	if (qid == NVME_QID_ANY) {
+		req = blk_mq_alloc_request(q, nvme_is_write(cmd), flags);
+	} else {
+		req = blk_mq_alloc_request_hctx(q, nvme_is_write(cmd), flags,
+				qid ? qid - 1 : 0);
+	}
+	if (IS_ERR(req))
+		return req;
+
+	req->cmd_type = REQ_TYPE_DRV_PRIV;
+	req->cmd_flags |= REQ_FAILFAST_DRIVER;
+	req->__data_len = 0;
+	req->__sector = (sector_t) -1;
+	req->bio = req->biotail = NULL;
+
+	req->cmd = (unsigned char *)cmd;
+	req->cmd_len = sizeof(struct nvme_command);
+
+	return req;
+}
+
+/*
+ * Returns 0 on success.  If the result is negative, it's a Linux error code;
+ * if the result is positive, it's an NVM Express status code
+ */
+int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
+		struct nvme_completion *cqe, void *buffer, unsigned bufflen,
+		unsigned timeout, int qid, int at_head, int flags)
+{
+	struct request *req;
+	int ret;
+
+	req = nvme_alloc_request(q, cmd, flags, qid);
+	if (IS_ERR(req))
+		return PTR_ERR(req);
+
+	req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
+	req->special = cqe;
+
+	if (buffer && bufflen) {
+		ret = blk_rq_map_kern(q, req, buffer, bufflen, GFP_KERNEL);
+		if (ret)
+			goto out;
+	}
+
+	blk_execute_rq(req->q, NULL, req, at_head);
+	ret = req->errors;
+ out:
+	blk_mq_free_request(req);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__nvme_submit_sync_cmd);
+
+int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
+		void *buffer, unsigned bufflen)
+{
+	return __nvme_submit_sync_cmd(q, cmd, NULL, buffer, bufflen, 0,
+			NVME_QID_ANY, 0, 0);
+}
+
+int __nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
+		void __user *ubuffer, unsigned bufflen,
+		void __user *meta_buffer, unsigned meta_len, u32 meta_seed,
+		u32 *result, unsigned timeout)
+{
+	bool write = nvme_is_write(cmd);
+	struct nvme_completion cqe;
+	struct nvme_ns *ns = q->queuedata;
+	struct gendisk *disk = ns ? ns->disk : NULL;
+	struct request *req;
+	struct bio *bio = NULL;
+	void *meta = NULL;
+	int ret;
+
+	req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
+	if (IS_ERR(req))
+		return PTR_ERR(req);
+
+	req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
+	req->special = &cqe;
+
+	if (ubuffer && bufflen) {
+		ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen,
+				GFP_KERNEL);
+		if (ret)
+			goto out;
+		bio = req->bio;
+
+		if (!disk)
+			goto submit;
+		bio->bi_bdev = bdget_disk(disk, 0);
+		if (!bio->bi_bdev) {
+			ret = -ENODEV;
+			goto out_unmap;
+		}
+
+		if (meta_buffer) {
+			struct bio_integrity_payload *bip;
+
+			meta = kmalloc(meta_len, GFP_KERNEL);
+			if (!meta) {
+				ret = -ENOMEM;
+				goto out_unmap;
+			}
+
+			if (write) {
+				if (copy_from_user(meta, meta_buffer,
+						meta_len)) {
+					ret = -EFAULT;
+					goto out_free_meta;
+				}
+			}
+
+			bip = bio_integrity_alloc(bio, GFP_KERNEL, 1);
+			if (IS_ERR(bip)) {
+				ret = PTR_ERR(bip);
+				goto out_free_meta;
+			}
+
+			bip->bip_iter.bi_size = meta_len;
+			bip->bip_iter.bi_sector = meta_seed;
+
+			ret = bio_integrity_add_page(bio, virt_to_page(meta),
+					meta_len, offset_in_page(meta));
+			if (ret != meta_len) {
+				ret = -ENOMEM;
+				goto out_free_meta;
+			}
+		}
+	}
+ submit:
+	blk_execute_rq(req->q, disk, req, 0);
+	ret = req->errors;
+	if (result)
+		*result = le32_to_cpu(cqe.result);
+	if (meta && !ret && !write) {
+		if (copy_to_user(meta_buffer, meta, meta_len))
+			ret = -EFAULT;
+	}
+ out_free_meta:
+	kfree(meta);
+ out_unmap:
+	if (bio) {
+		if (disk && bio->bi_bdev)
+			bdput(bio->bi_bdev);
+		blk_rq_unmap_user(bio);
+	}
+ out:
+	blk_mq_free_request(req);
+	return ret;
+}
+
+int nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
+		void __user *ubuffer, unsigned bufflen, u32 *result,
+		unsigned timeout)
+{
+	return __nvme_submit_user_cmd(q, cmd, ubuffer, bufflen, NULL, 0, 0,
+			result, timeout);
+}
+
+int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
+{
+	struct nvme_command c = { };
+	int error;
+
+	/* gcc-4.4.4 (at least) has issues with initializers and anon unions */
+	c.identify.opcode = nvme_admin_identify;
+	c.identify.cns = cpu_to_le32(1);
+
+	*id = kmalloc(sizeof(struct nvme_id_ctrl), GFP_KERNEL);
+	if (!*id)
+		return -ENOMEM;
+
+	error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
+			sizeof(struct nvme_id_ctrl));
+	if (error)
+		kfree(*id);
+	return error;
+}
+
+static int nvme_identify_ns_list(struct nvme_ctrl *dev, unsigned nsid, __le32 *ns_list)
+{
+	struct nvme_command c = { };
+
+	c.identify.opcode = nvme_admin_identify;
+	c.identify.cns = cpu_to_le32(2);
+	c.identify.nsid = cpu_to_le32(nsid);
+	return nvme_submit_sync_cmd(dev->admin_q, &c, ns_list, 0x1000);
+}
+
+int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
+		struct nvme_id_ns **id)
+{
+	struct nvme_command c = { };
+	int error;
+
+	/* gcc-4.4.4 (at least) has issues with initializers and anon unions */
+	c.identify.opcode = nvme_admin_identify,
+	c.identify.nsid = cpu_to_le32(nsid),
+
+	*id = kmalloc(sizeof(struct nvme_id_ns), GFP_KERNEL);
+	if (!*id)
+		return -ENOMEM;
+
+	error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
+			sizeof(struct nvme_id_ns));
+	if (error)
+		kfree(*id);
+	return error;
+}
+
+int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
+		      void *buffer, size_t buflen, u32 *result)
+{
+	struct nvme_command c;
+	struct nvme_completion cqe;
+	int ret;
+
+	memset(&c, 0, sizeof(c));
+	c.features.opcode = nvme_admin_get_features;
+	c.features.nsid = cpu_to_le32(nsid);
+	c.features.fid = cpu_to_le32(fid);
+
+	ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, buffer, buflen, 0,
+			NVME_QID_ANY, 0, 0);
+	if (ret >= 0 && result)
+		*result = le32_to_cpu(cqe.result);
+	return ret;
+}
+
+int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
+		      void *buffer, size_t buflen, u32 *result)
+{
+	struct nvme_command c;
+	struct nvme_completion cqe;
+	int ret;
+
+	memset(&c, 0, sizeof(c));
+	c.features.opcode = nvme_admin_set_features;
+	c.features.fid = cpu_to_le32(fid);
+	c.features.dword11 = cpu_to_le32(dword11);
+
+	ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe,
+			buffer, buflen, 0, NVME_QID_ANY, 0, 0);
+	if (ret >= 0 && result)
+		*result = le32_to_cpu(cqe.result);
+	return ret;
+}
+
+int nvme_get_log_page(struct nvme_ctrl *dev, struct nvme_smart_log **log)
+{
+	struct nvme_command c = { };
+	int error;
+
+	c.common.opcode = nvme_admin_get_log_page,
+	c.common.nsid = cpu_to_le32(0xFFFFFFFF),
+	c.common.cdw10[0] = cpu_to_le32(
+			(((sizeof(struct nvme_smart_log) / 4) - 1) << 16) |
+			 NVME_LOG_SMART),
+
+	*log = kmalloc(sizeof(struct nvme_smart_log), GFP_KERNEL);
+	if (!*log)
+		return -ENOMEM;
+
+	error = nvme_submit_sync_cmd(dev->admin_q, &c, *log,
+			sizeof(struct nvme_smart_log));
+	if (error)
+		kfree(*log);
+	return error;
+}
+
+int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
+{
+	u32 q_count = (*count - 1) | ((*count - 1) << 16);
+	u32 result;
+	int status, nr_io_queues;
+
+	status = nvme_set_features(ctrl, NVME_FEAT_NUM_QUEUES, q_count, NULL, 0,
+			&result);
+	if (status)
+		return status;
+
+	nr_io_queues = min(result & 0xffff, result >> 16) + 1;
+	*count = min(*count, nr_io_queues);
+	return 0;
+}
+
+static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
+{
+	struct nvme_user_io io;
+	struct nvme_command c;
+	unsigned length, meta_len;
+	void __user *metadata;
+
+	if (copy_from_user(&io, uio, sizeof(io)))
+		return -EFAULT;
+
+	switch (io.opcode) {
+	case nvme_cmd_write:
+	case nvme_cmd_read:
+	case nvme_cmd_compare:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	length = (io.nblocks + 1) << ns->lba_shift;
+	meta_len = (io.nblocks + 1) * ns->ms;
+	metadata = (void __user *)(uintptr_t)io.metadata;
+
+	if (ns->ext) {
+		length += meta_len;
+		meta_len = 0;
+	} else if (meta_len) {
+		if ((io.metadata & 3) || !io.metadata)
+			return -EINVAL;
+	}
+
+	memset(&c, 0, sizeof(c));
+	c.rw.opcode = io.opcode;
+	c.rw.flags = io.flags;
+	c.rw.nsid = cpu_to_le32(ns->ns_id);
+	c.rw.slba = cpu_to_le64(io.slba);
+	c.rw.length = cpu_to_le16(io.nblocks);
+	c.rw.control = cpu_to_le16(io.control);
+	c.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
+	c.rw.reftag = cpu_to_le32(io.reftag);
+	c.rw.apptag = cpu_to_le16(io.apptag);
+	c.rw.appmask = cpu_to_le16(io.appmask);
+
+	return __nvme_submit_user_cmd(ns->queue, &c,
+			(void __user *)(uintptr_t)io.addr, length,
+			metadata, meta_len, io.slba, NULL, 0);
+}
+
+static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+			struct nvme_passthru_cmd __user *ucmd)
+{
+	struct nvme_passthru_cmd cmd;
+	struct nvme_command c;
+	unsigned timeout = 0;
+	int status;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
+		return -EFAULT;
+
+	memset(&c, 0, sizeof(c));
+	c.common.opcode = cmd.opcode;
+	c.common.flags = cmd.flags;
+	c.common.nsid = cpu_to_le32(cmd.nsid);
+	c.common.cdw2[0] = cpu_to_le32(cmd.cdw2);
+	c.common.cdw2[1] = cpu_to_le32(cmd.cdw3);
+	c.common.cdw10[0] = cpu_to_le32(cmd.cdw10);
+	c.common.cdw10[1] = cpu_to_le32(cmd.cdw11);
+	c.common.cdw10[2] = cpu_to_le32(cmd.cdw12);
+	c.common.cdw10[3] = cpu_to_le32(cmd.cdw13);
+	c.common.cdw10[4] = cpu_to_le32(cmd.cdw14);
+	c.common.cdw10[5] = cpu_to_le32(cmd.cdw15);
+
+	if (cmd.timeout_ms)
+		timeout = msecs_to_jiffies(cmd.timeout_ms);
+
+	status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
+			(void __user *)(uintptr_t)cmd.addr, cmd.data_len,
+			&cmd.result, timeout);
+	if (status >= 0) {
+		if (put_user(cmd.result, &ucmd->result))
+			return -EFAULT;
+	}
+
+	return status;
+}
+
+static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
+		unsigned int cmd, unsigned long arg)
+{
+	struct nvme_ns *ns = bdev->bd_disk->private_data;
+
+	switch (cmd) {
+	case NVME_IOCTL_ID:
+		force_successful_syscall_return();
+		return ns->ns_id;
+	case NVME_IOCTL_ADMIN_CMD:
+		return nvme_user_cmd(ns->ctrl, NULL, (void __user *)arg);
+	case NVME_IOCTL_IO_CMD:
+		return nvme_user_cmd(ns->ctrl, ns, (void __user *)arg);
+	case NVME_IOCTL_SUBMIT_IO:
+		return nvme_submit_io(ns, (void __user *)arg);
+#ifdef CONFIG_BLK_DEV_NVME_SCSI
+	case SG_GET_VERSION_NUM:
+		return nvme_sg_get_version_num((void __user *)arg);
+	case SG_IO:
+		return nvme_sg_io(ns, (void __user *)arg);
+#endif
+	default:
+		return -ENOTTY;
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
+			unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case SG_IO:
+		return -ENOIOCTLCMD;
+	}
+	return nvme_ioctl(bdev, mode, cmd, arg);
+}
+#else
+#define nvme_compat_ioctl	NULL
+#endif
+
+static int nvme_open(struct block_device *bdev, fmode_t mode)
+{
+	return nvme_get_ns_from_disk(bdev->bd_disk) ? 0 : -ENXIO;
+}
+
+static void nvme_release(struct gendisk *disk, fmode_t mode)
+{
+	nvme_put_ns(disk->private_data);
+}
+
+static int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+	/* some standard values */
+	geo->heads = 1 << 6;
+	geo->sectors = 1 << 5;
+	geo->cylinders = get_capacity(bdev->bd_disk) >> 11;
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_INTEGRITY
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+	struct blk_integrity integrity;
+
+	switch (ns->pi_type) {
+	case NVME_NS_DPS_PI_TYPE3:
+		integrity.profile = &t10_pi_type3_crc;
+		break;
+	case NVME_NS_DPS_PI_TYPE1:
+	case NVME_NS_DPS_PI_TYPE2:
+		integrity.profile = &t10_pi_type1_crc;
+		break;
+	default:
+		integrity.profile = NULL;
+		break;
+	}
+	integrity.tuple_size = ns->ms;
+	blk_integrity_register(ns->disk, &integrity);
+	blk_queue_max_integrity_segments(ns->queue, 1);
+}
+#else
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+}
+#endif /* CONFIG_BLK_DEV_INTEGRITY */
+
+static void nvme_config_discard(struct nvme_ns *ns)
+{
+	struct nvme_ctrl *ctrl = ns->ctrl;
+	u32 logical_block_size = queue_logical_block_size(ns->queue);
+
+	if (ctrl->quirks & NVME_QUIRK_DISCARD_ZEROES)
+		ns->queue->limits.discard_zeroes_data = 1;
+	else
+		ns->queue->limits.discard_zeroes_data = 0;
+
+	ns->queue->limits.discard_alignment = logical_block_size;
+	ns->queue->limits.discard_granularity = logical_block_size;
+	blk_queue_max_discard_sectors(ns->queue, 0xffffffff);
+	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
+}
+
+static int nvme_revalidate_disk(struct gendisk *disk)
+{
+	struct nvme_ns *ns = disk->private_data;
+	struct nvme_id_ns *id;
+	u8 lbaf, pi_type;
+	u16 old_ms;
+	unsigned short bs;
+
+	if (test_bit(NVME_NS_DEAD, &ns->flags)) {
+		set_capacity(disk, 0);
+		return -ENODEV;
+	}
+	if (nvme_identify_ns(ns->ctrl, ns->ns_id, &id)) {
+		dev_warn(ns->ctrl->dev, "%s: Identify failure nvme%dn%d\n",
+				__func__, ns->ctrl->instance, ns->ns_id);
+		return -ENODEV;
+	}
+	if (id->ncap == 0) {
+		kfree(id);
+		return -ENODEV;
+	}
+
+	if (nvme_nvm_ns_supported(ns, id) && ns->type != NVME_NS_LIGHTNVM) {
+		if (nvme_nvm_register(ns->queue, disk->disk_name)) {
+			dev_warn(ns->ctrl->dev,
+				"%s: LightNVM init failure\n", __func__);
+			kfree(id);
+			return -ENODEV;
+		}
+		ns->type = NVME_NS_LIGHTNVM;
+	}
+
+	if (ns->ctrl->vs >= NVME_VS(1, 1))
+		memcpy(ns->eui, id->eui64, sizeof(ns->eui));
+	if (ns->ctrl->vs >= NVME_VS(1, 2))
+		memcpy(ns->uuid, id->nguid, sizeof(ns->uuid));
+
+	old_ms = ns->ms;
+	lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
+	ns->lba_shift = id->lbaf[lbaf].ds;
+	ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
+	ns->ext = ns->ms && (id->flbas & NVME_NS_FLBAS_META_EXT);
+
+	/*
+	 * If identify namespace failed, use default 512 byte block size so
+	 * block layer can use before failing read/write for 0 capacity.
+	 */
+	if (ns->lba_shift == 0)
+		ns->lba_shift = 9;
+	bs = 1 << ns->lba_shift;
+	/* XXX: PI implementation requires metadata equal t10 pi tuple size */
+	pi_type = ns->ms == sizeof(struct t10_pi_tuple) ?
+					id->dps & NVME_NS_DPS_PI_MASK : 0;
+
+	blk_mq_freeze_queue(disk->queue);
+	if (blk_get_integrity(disk) && (ns->pi_type != pi_type ||
+				ns->ms != old_ms ||
+				bs != queue_logical_block_size(disk->queue) ||
+				(ns->ms && ns->ext)))
+		blk_integrity_unregister(disk);
+
+	ns->pi_type = pi_type;
+	blk_queue_logical_block_size(ns->queue, bs);
+
+	if (ns->ms && !blk_get_integrity(disk) && !ns->ext)
+		nvme_init_integrity(ns);
+	if (ns->ms && !(ns->ms == 8 && ns->pi_type) && !blk_get_integrity(disk))
+		set_capacity(disk, 0);
+	else
+		set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
+
+	if (ns->ctrl->oncs & NVME_CTRL_ONCS_DSM)
+		nvme_config_discard(ns);
+	blk_mq_unfreeze_queue(disk->queue);
+
+	kfree(id);
+	return 0;
+}
+
+static char nvme_pr_type(enum pr_type type)
+{
+	switch (type) {
+	case PR_WRITE_EXCLUSIVE:
+		return 1;
+	case PR_EXCLUSIVE_ACCESS:
+		return 2;
+	case PR_WRITE_EXCLUSIVE_REG_ONLY:
+		return 3;
+	case PR_EXCLUSIVE_ACCESS_REG_ONLY:
+		return 4;
+	case PR_WRITE_EXCLUSIVE_ALL_REGS:
+		return 5;
+	case PR_EXCLUSIVE_ACCESS_ALL_REGS:
+		return 6;
+	default:
+		return 0;
+	}
+};
+
+static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
+				u64 key, u64 sa_key, u8 op)
+{
+	struct nvme_ns *ns = bdev->bd_disk->private_data;
+	struct nvme_command c;
+	u8 data[16] = { 0, };
+
+	put_unaligned_le64(key, &data[0]);
+	put_unaligned_le64(sa_key, &data[8]);
+
+	memset(&c, 0, sizeof(c));
+	c.common.opcode = op;
+	c.common.nsid = cpu_to_le32(ns->ns_id);
+	c.common.cdw10[0] = cpu_to_le32(cdw10);
+
+	return nvme_submit_sync_cmd(ns->queue, &c, data, 16);
+}
+
+static int nvme_pr_register(struct block_device *bdev, u64 old,
+		u64 new, unsigned flags)
+{
+	u32 cdw10;
+
+	if (flags & ~PR_FL_IGNORE_KEY)
+		return -EOPNOTSUPP;
+
+	cdw10 = old ? 2 : 0;
+	cdw10 |= (flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0;
+	cdw10 |= (1 << 30) | (1 << 31); /* PTPL=1 */
+	return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_register);
+}
+
+static int nvme_pr_reserve(struct block_device *bdev, u64 key,
+		enum pr_type type, unsigned flags)
+{
+	u32 cdw10;
+
+	if (flags & ~PR_FL_IGNORE_KEY)
+		return -EOPNOTSUPP;
+
+	cdw10 = nvme_pr_type(type) << 8;
+	cdw10 |= ((flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0);
+	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_acquire);
+}
+
+static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new,
+		enum pr_type type, bool abort)
+{
+	u32 cdw10 = nvme_pr_type(type) << 8 | abort ? 2 : 1;
+	return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire);
+}
+
+static int nvme_pr_clear(struct block_device *bdev, u64 key)
+{
+	u32 cdw10 = 1 | (key ? 1 << 3 : 0);
+	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_register);
+}
+
+static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
+{
+	u32 cdw10 = nvme_pr_type(type) << 8 | key ? 1 << 3 : 0;
+	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
+}
+
+static const struct pr_ops nvme_pr_ops = {
+	.pr_register	= nvme_pr_register,
+	.pr_reserve	= nvme_pr_reserve,
+	.pr_release	= nvme_pr_release,
+	.pr_preempt	= nvme_pr_preempt,
+	.pr_clear	= nvme_pr_clear,
+};
+
+static const struct block_device_operations nvme_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= nvme_ioctl,
+	.compat_ioctl	= nvme_compat_ioctl,
+	.open		= nvme_open,
+	.release	= nvme_release,
+	.getgeo		= nvme_getgeo,
+	.revalidate_disk= nvme_revalidate_disk,
+	.pr_ops		= &nvme_pr_ops,
+};
+
+static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled)
+{
+	unsigned long timeout =
+		((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies;
+	u32 csts, bit = enabled ? NVME_CSTS_RDY : 0;
+	int ret;
+
+	while ((ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &csts)) == 0) {
+		if ((csts & NVME_CSTS_RDY) == bit)
+			break;
+
+		msleep(100);
+		if (fatal_signal_pending(current))
+			return -EINTR;
+		if (time_after(jiffies, timeout)) {
+			dev_err(ctrl->dev,
+				"Device not ready; aborting %s\n", enabled ?
+						"initialisation" : "reset");
+			return -ENODEV;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * If the device has been passed off to us in an enabled state, just clear
+ * the enabled bit.  The spec says we should set the 'shutdown notification
+ * bits', but doing so may cause the device to complete commands to the
+ * admin queue ... and we don't know what memory that might be pointing at!
+ */
+int nvme_disable_ctrl(struct nvme_ctrl *ctrl, u64 cap)
+{
+	int ret;
+
+	ctrl->ctrl_config &= ~NVME_CC_SHN_MASK;
+	ctrl->ctrl_config &= ~NVME_CC_ENABLE;
+
+	ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config);
+	if (ret)
+		return ret;
+
+	if (ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY)
+		msleep(NVME_QUIRK_DELAY_AMOUNT);
+
+	return nvme_wait_ready(ctrl, cap, false);
+}
+
+int nvme_enable_ctrl(struct nvme_ctrl *ctrl, u64 cap)
+{
+	/*
+	 * Default to a 4K page size, with the intention to update this
+	 * path in the future to accomodate architectures with differing
+	 * kernel and IO page sizes.
+	 */
+	unsigned dev_page_min = NVME_CAP_MPSMIN(cap) + 12, page_shift = 12;
+	int ret;
+
+	if (page_shift < dev_page_min) {
+		dev_err(ctrl->dev,
+			"Minimum device page size %u too large for host (%u)\n",
+			1 << dev_page_min, 1 << page_shift);
+		return -ENODEV;
+	}
+
+	ctrl->page_size = 1 << page_shift;
+
+	ctrl->ctrl_config = NVME_CC_CSS_NVM;
+	ctrl->ctrl_config |= (page_shift - 12) << NVME_CC_MPS_SHIFT;
+	ctrl->ctrl_config |= NVME_CC_ARB_RR | NVME_CC_SHN_NONE;
+	ctrl->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;
+	ctrl->ctrl_config |= NVME_CC_ENABLE;
+
+	ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config);
+	if (ret)
+		return ret;
+	return nvme_wait_ready(ctrl, cap, true);
+}
+
+int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl)
+{
+	unsigned long timeout = SHUTDOWN_TIMEOUT + jiffies;
+	u32 csts;
+	int ret;
+
+	ctrl->ctrl_config &= ~NVME_CC_SHN_MASK;
+	ctrl->ctrl_config |= NVME_CC_SHN_NORMAL;
+
+	ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config);
+	if (ret)
+		return ret;
+
+	while ((ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &csts)) == 0) {
+		if ((csts & NVME_CSTS_SHST_MASK) == NVME_CSTS_SHST_CMPLT)
+			break;
+
+		msleep(100);
+		if (fatal_signal_pending(current))
+			return -EINTR;
+		if (time_after(jiffies, timeout)) {
+			dev_err(ctrl->dev,
+				"Device shutdown incomplete; abort shutdown\n");
+			return -ENODEV;
+		}
+	}
+
+	return ret;
+}
+
+static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
+		struct request_queue *q)
+{
+	if (ctrl->max_hw_sectors) {
+		u32 max_segments =
+			(ctrl->max_hw_sectors / (ctrl->page_size >> 9)) + 1;
+
+		blk_queue_max_hw_sectors(q, ctrl->max_hw_sectors);
+		blk_queue_max_segments(q, min_t(u32, max_segments, USHRT_MAX));
+	}
+	if (ctrl->stripe_size)
+		blk_queue_chunk_sectors(q, ctrl->stripe_size >> 9);
+	if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
+		blk_queue_flush(q, REQ_FLUSH | REQ_FUA);
+	blk_queue_virt_boundary(q, ctrl->page_size - 1);
+}
+
+static void nvme_configure_apst(struct nvme_ctrl *ctrl)
+{
+	/*
+	 * APST (Autonomous Power State Transition) lets us program a
+	 * table of power state transitions that the controller will
+	 * perform automatically.  We configure it with a simple
+	 * heuristic: we are willing to spend at most 2% of the time
+	 * transitioning between power states.  Therefore, when running
+	 * in any given state, we will enter the next lower-power
+	 * non-operational state after waiting 50 * (enlat + exlat)
+	 * microseconds, as long as that state's exit latency is under
+	 * the requested maximum latency.
+	 *
+	 * We will not autonomously enter any non-operational state for
+	 * which the total latency exceeds ps_max_latency_us.  Users
+	 * can set ps_max_latency_us to zero to turn off APST.
+	 */
+
+	unsigned apste;
+	struct nvme_feat_auto_pst *table;
+	int ret;
+
+	/*
+	 * If APST isn't supported or if we haven't been initialized yet,
+	 * then don't do anything.
+	 */
+	if (!ctrl->apsta)
+		return;
+
+	if (ctrl->npss > 31) {
+		dev_warn(ctrl->device, "NPSS is invalid; not using APST\n");
+		return;
+	}
+
+	table = kzalloc(sizeof(*table), GFP_KERNEL);
+	if (!table)
+		return;
+
+	if (ctrl->ps_max_latency_us == 0) {
+		/* Turn off APST. */
+		apste = 0;
+	} else {
+		__le64 target = cpu_to_le64(0);
+		int state;
+
+		/*
+		 * Walk through all states from lowest- to highest-power.
+		 * According to the spec, lower-numbered states use more
+		 * power.  NPSS, despite the name, is the index of the
+		 * lowest-power state, not the number of states.
+		 */
+		for (state = (int)ctrl->npss; state >= 0; state--) {
+			u64 total_latency_us, exit_latency_us, transition_ms;
+
+			if (target)
+				table->entries[state] = target;
+
+			/*
+			 * Don't allow transitions to the deepest state
+			 * if it's quirked off.
+			 */
+			if (state == ctrl->npss &&
+			    (ctrl->quirks & NVME_QUIRK_NO_DEEPEST_PS))
+				continue;
+
+			/*
+			 * Is this state a useful non-operational state for
+			 * higher-power states to autonomously transition to?
+			 */
+			if (!(ctrl->psd[state].flags &
+			      NVME_PS_FLAGS_NON_OP_STATE))
+				continue;
+
+			exit_latency_us =
+				(u64)le32_to_cpu(ctrl->psd[state].exit_lat);
+			if (exit_latency_us > ctrl->ps_max_latency_us)
+				continue;
+
+			total_latency_us =
+				exit_latency_us +
+				le32_to_cpu(ctrl->psd[state].entry_lat);
+
+			/*
+			 * This state is good.  Use it as the APST idle
+			 * target for higher power states.
+			 */
+			transition_ms = total_latency_us + 19;
+			do_div(transition_ms, 20);
+			if (transition_ms > (1 << 24) - 1)
+				transition_ms = (1 << 24) - 1;
+
+			target = cpu_to_le64((state << 3) |
+					     (transition_ms << 8));
+		}
+
+		apste = 1;
+	}
+
+	ret = nvme_set_features(ctrl, NVME_FEAT_AUTO_PST, apste,
+				table, sizeof(*table), NULL);
+	if (ret)
+		dev_err(ctrl->device, "failed to set APST feature (%d)\n", ret);
+
+	kfree(table);
+}
+
+static void nvme_set_latency_tolerance(struct device *dev, s32 val)
+{
+	struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+	u64 latency;
+
+	switch (val) {
+	case PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT:
+	case PM_QOS_LATENCY_ANY:
+		latency = U64_MAX;
+		break;
+
+	default:
+		latency = val;
+	}
+
+	if (ctrl->ps_max_latency_us != latency) {
+		ctrl->ps_max_latency_us = latency;
+		nvme_configure_apst(ctrl);
+	}
+}
+
+struct nvme_core_quirk_entry {
+	/*
+	 * NVMe model and firmware strings are padded with spaces.  For
+	 * simplicity, strings in the quirk table are padded with NULLs
+	 * instead.
+	 */
+	u16 vid;
+	const char *mn;
+	const char *fr;
+	unsigned long quirks;
+};
+
+static const struct nvme_core_quirk_entry core_quirks[] = {
+	{
+		/*
+		 * This Toshiba device seems to die using any APST states.  See:
+		 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1678184/comments/11
+		 */
+		.vid = 0x1179,
+		.mn = "THNSF5256GPUK TOSHIBA",
+		.quirks = NVME_QUIRK_NO_APST,
+	}
+};
+
+/* match is null-terminated but idstr is space-padded. */
+static bool string_matches(const char *idstr, const char *match, size_t len)
+{
+	size_t matchlen;
+
+	if (!match)
+		return true;
+
+	matchlen = strlen(match);
+	WARN_ON_ONCE(matchlen > len);
+
+	if (memcmp(idstr, match, matchlen))
+		return false;
+
+	for (; matchlen < len; matchlen++)
+		if (idstr[matchlen] != ' ')
+			return false;
+
+	return true;
+}
+
+static bool quirk_matches(const struct nvme_id_ctrl *id,
+			  const struct nvme_core_quirk_entry *q)
+{
+	return q->vid == le16_to_cpu(id->vid) &&
+		string_matches(id->mn, q->mn, sizeof(id->mn)) &&
+		string_matches(id->fr, q->fr, sizeof(id->fr));
+}
+
+/*
+ * Initialize the cached copies of the Identify data and various controller
+ * register in our nvme_ctrl structure.  This should be called as soon as
+ * the admin queue is fully up and running.
+ */
+int nvme_init_identify(struct nvme_ctrl *ctrl)
+{
+	struct nvme_id_ctrl *id;
+	u64 cap;
+	int ret, page_shift;
+	u8 prev_apsta;
+
+	ret = ctrl->ops->reg_read32(ctrl, NVME_REG_VS, &ctrl->vs);
+	if (ret) {
+		dev_err(ctrl->dev, "Reading VS failed (%d)\n", ret);
+		return ret;
+	}
+
+	ret = ctrl->ops->reg_read64(ctrl, NVME_REG_CAP, &cap);
+	if (ret) {
+		dev_err(ctrl->dev, "Reading CAP failed (%d)\n", ret);
+		return ret;
+	}
+	page_shift = NVME_CAP_MPSMIN(cap) + 12;
+
+	if (ctrl->vs >= NVME_VS(1, 1))
+		ctrl->subsystem = NVME_CAP_NSSRC(cap);
+
+	ret = nvme_identify_ctrl(ctrl, &id);
+	if (ret) {
+		dev_err(ctrl->dev, "Identify Controller failed (%d)\n", ret);
+		return -EIO;
+	}
+
+	if (!ctrl->identified) {
+		/*
+		 * Check for quirks.  Quirk can depend on firmware version,
+		 * so, in principle, the set of quirks present can change
+		 * across a reset.  As a possible future enhancement, we
+		 * could re-scan for quirks every time we reinitialize
+		 * the device, but we'd have to make sure that the driver
+		 * behaves intelligently if the quirks change.
+		 */
+
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(core_quirks); i++) {
+			if (quirk_matches(id, &core_quirks[i]))
+				ctrl->quirks |= core_quirks[i].quirks;
+		}
+	}
+
+	ctrl->oncs = le16_to_cpup(&id->oncs);
+	atomic_set(&ctrl->abort_limit, id->acl + 1);
+	ctrl->vwc = id->vwc;
+	memcpy(ctrl->serial, id->sn, sizeof(id->sn));
+	memcpy(ctrl->model, id->mn, sizeof(id->mn));
+	memcpy(ctrl->firmware_rev, id->fr, sizeof(id->fr));
+	if (id->mdts)
+		ctrl->max_hw_sectors = 1 << (id->mdts + page_shift - 9);
+	else
+		ctrl->max_hw_sectors = UINT_MAX;
+
+	if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) && id->vs[3]) {
+		unsigned int max_hw_sectors;
+
+		ctrl->stripe_size = 1 << (id->vs[3] + page_shift);
+		max_hw_sectors = ctrl->stripe_size >> (page_shift - 9);
+		if (ctrl->max_hw_sectors) {
+			ctrl->max_hw_sectors = min(max_hw_sectors,
+							ctrl->max_hw_sectors);
+		} else {
+			ctrl->max_hw_sectors = max_hw_sectors;
+		}
+	}
+
+	nvme_set_queue_limits(ctrl, ctrl->admin_q);
+
+	ctrl->npss = id->npss;
+	prev_apsta = ctrl->apsta;
+	ctrl->apsta = (ctrl->quirks & NVME_QUIRK_NO_APST) ? 0 : id->apsta;
+	memcpy(ctrl->psd, id->psd, sizeof(ctrl->psd));
+
+	kfree(id);
+
+	if (ctrl->apsta && !prev_apsta)
+		dev_pm_qos_expose_latency_tolerance(ctrl->device);
+	else if (!ctrl->apsta && prev_apsta)
+		dev_pm_qos_hide_latency_tolerance(ctrl->device);
+
+	nvme_configure_apst(ctrl);
+
+	ctrl->identified = true;
+
+	return ret;
+}
+
+static int nvme_dev_open(struct inode *inode, struct file *file)
+{
+	struct nvme_ctrl *ctrl;
+	int instance = iminor(inode);
+	int ret = -ENODEV;
+
+	spin_lock(&dev_list_lock);
+	list_for_each_entry(ctrl, &nvme_ctrl_list, node) {
+		if (ctrl->instance != instance)
+			continue;
+
+		if (!ctrl->admin_q) {
+			ret = -EWOULDBLOCK;
+			break;
+		}
+		if (!kref_get_unless_zero(&ctrl->kref))
+			break;
+		file->private_data = ctrl;
+		ret = 0;
+		break;
+	}
+	spin_unlock(&dev_list_lock);
+
+	return ret;
+}
+
+static int nvme_dev_release(struct inode *inode, struct file *file)
+{
+	nvme_put_ctrl(file->private_data);
+	return 0;
+}
+
+static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp)
+{
+	struct nvme_ns *ns;
+	int ret;
+
+	mutex_lock(&ctrl->namespaces_mutex);
+	if (list_empty(&ctrl->namespaces)) {
+		ret = -ENOTTY;
+		goto out_unlock;
+	}
+
+	ns = list_first_entry(&ctrl->namespaces, struct nvme_ns, list);
+	if (ns != list_last_entry(&ctrl->namespaces, struct nvme_ns, list)) {
+		dev_warn(ctrl->dev,
+			"NVME_IOCTL_IO_CMD not supported when multiple namespaces present!\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	dev_warn(ctrl->dev,
+		"using deprecated NVME_IOCTL_IO_CMD ioctl on the char device!\n");
+	kref_get(&ns->kref);
+	mutex_unlock(&ctrl->namespaces_mutex);
+
+	ret = nvme_user_cmd(ctrl, ns, argp);
+	nvme_put_ns(ns);
+	return ret;
+
+out_unlock:
+	mutex_unlock(&ctrl->namespaces_mutex);
+	return ret;
+}
+
+static long nvme_dev_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct nvme_ctrl *ctrl = file->private_data;
+	void __user *argp = (void __user *)arg;
+
+	switch (cmd) {
+	case NVME_IOCTL_ADMIN_CMD:
+		return nvme_user_cmd(ctrl, NULL, argp);
+	case NVME_IOCTL_IO_CMD:
+		return nvme_dev_user_cmd(ctrl, argp);
+	case NVME_IOCTL_RESET:
+		dev_warn(ctrl->dev, "resetting controller\n");
+		return ctrl->ops->reset_ctrl(ctrl);
+	case NVME_IOCTL_SUBSYS_RESET:
+		return nvme_reset_subsystem(ctrl);
+	default:
+		return -ENOTTY;
+	}
+}
+
+static const struct file_operations nvme_dev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= nvme_dev_open,
+	.release	= nvme_dev_release,
+	.unlocked_ioctl	= nvme_dev_ioctl,
+	.compat_ioctl	= nvme_dev_ioctl,
+};
+
+static ssize_t nvme_sysfs_reset(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+	int ret;
+
+	ret = ctrl->ops->reset_ctrl(ctrl);
+	if (ret < 0)
+		return ret;
+	return count;
+}
+static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_sysfs_reset);
+
+static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
+								char *buf)
+{
+	struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+	return sprintf(buf, "%pU\n", ns->uuid);
+}
+static DEVICE_ATTR(uuid, S_IRUGO, uuid_show, NULL);
+
+static ssize_t eui_show(struct device *dev, struct device_attribute *attr,
+								char *buf)
+{
+	struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+	return sprintf(buf, "%8phd\n", ns->eui);
+}
+static DEVICE_ATTR(eui, S_IRUGO, eui_show, NULL);
+
+static ssize_t nsid_show(struct device *dev, struct device_attribute *attr,
+								char *buf)
+{
+	struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+	return sprintf(buf, "%d\n", ns->ns_id);
+}
+static DEVICE_ATTR(nsid, S_IRUGO, nsid_show, NULL);
+
+static struct attribute *nvme_ns_attrs[] = {
+	&dev_attr_uuid.attr,
+	&dev_attr_eui.attr,
+	&dev_attr_nsid.attr,
+	NULL,
+};
+
+static umode_t nvme_attrs_are_visible(struct kobject *kobj,
+		struct attribute *a, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+
+	if (a == &dev_attr_uuid.attr) {
+		if (!memchr_inv(ns->uuid, 0, sizeof(ns->uuid)))
+			return 0;
+	}
+	if (a == &dev_attr_eui.attr) {
+		if (!memchr_inv(ns->eui, 0, sizeof(ns->eui)))
+			return 0;
+	}
+	return a->mode;
+}
+
+static const struct attribute_group nvme_ns_attr_group = {
+	.attrs		= nvme_ns_attrs,
+	.is_visible	= nvme_attrs_are_visible,
+};
+
+#define nvme_show_function(field)						\
+static ssize_t  field##_show(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)		\
+{										\
+        struct nvme_ctrl *ctrl = dev_get_drvdata(dev);				\
+        return sprintf(buf, "%.*s\n", (int)sizeof(ctrl->field), ctrl->field);	\
+}										\
+static DEVICE_ATTR(field, S_IRUGO, field##_show, NULL);
+
+nvme_show_function(model);
+nvme_show_function(serial);
+nvme_show_function(firmware_rev);
+
+static struct attribute *nvme_dev_attrs[] = {
+	&dev_attr_reset_controller.attr,
+	&dev_attr_model.attr,
+	&dev_attr_serial.attr,
+	&dev_attr_firmware_rev.attr,
+	NULL
+};
+
+static struct attribute_group nvme_dev_attrs_group = {
+	.attrs = nvme_dev_attrs,
+};
+
+static const struct attribute_group *nvme_dev_attr_groups[] = {
+	&nvme_dev_attrs_group,
+	NULL,
+};
+
+static int ns_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct nvme_ns *nsa = container_of(a, struct nvme_ns, list);
+	struct nvme_ns *nsb = container_of(b, struct nvme_ns, list);
+
+	return nsa->ns_id - nsb->ns_id;
+}
+
+static struct nvme_ns *nvme_find_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+{
+	struct nvme_ns *ns;
+
+	lockdep_assert_held(&ctrl->namespaces_mutex);
+
+	list_for_each_entry(ns, &ctrl->namespaces, list) {
+		if (ns->ns_id == nsid)
+			return ns;
+		if (ns->ns_id > nsid)
+			break;
+	}
+	return NULL;
+}
+
+static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+{
+	struct nvme_ns *ns;
+	struct gendisk *disk;
+	int node = dev_to_node(ctrl->dev);
+
+	lockdep_assert_held(&ctrl->namespaces_mutex);
+
+	ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
+	if (!ns)
+		return;
+
+	ns->queue = blk_mq_init_queue(ctrl->tagset);
+	if (IS_ERR(ns->queue))
+		goto out_free_ns;
+	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, ns->queue);
+	ns->queue->queuedata = ns;
+	ns->ctrl = ctrl;
+
+	disk = alloc_disk_node(0, node);
+	if (!disk)
+		goto out_free_queue;
+
+	kref_init(&ns->kref);
+	ns->ns_id = nsid;
+	ns->disk = disk;
+	ns->lba_shift = 9; /* set to a default value for 512 until disk is validated */
+
+
+	blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
+	nvme_set_queue_limits(ctrl, ns->queue);
+
+	disk->major = nvme_major;
+	disk->first_minor = 0;
+	disk->fops = &nvme_fops;
+	disk->private_data = ns;
+	disk->queue = ns->queue;
+	disk->driverfs_dev = ctrl->device;
+	disk->flags = GENHD_FL_EXT_DEVT;
+	sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance, nsid);
+
+	if (nvme_revalidate_disk(ns->disk))
+		goto out_free_disk;
+
+	list_add_tail(&ns->list, &ctrl->namespaces);
+	kref_get(&ctrl->kref);
+	if (ns->type == NVME_NS_LIGHTNVM)
+		return;
+
+	add_disk(ns->disk);
+	if (sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
+					&nvme_ns_attr_group))
+		pr_warn("%s: failed to create sysfs group for identification\n",
+			ns->disk->disk_name);
+	return;
+ out_free_disk:
+	kfree(disk);
+ out_free_queue:
+	blk_cleanup_queue(ns->queue);
+ out_free_ns:
+	kfree(ns);
+}
+
+static void nvme_ns_remove(struct nvme_ns *ns)
+{
+	if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
+		return;
+
+	if (ns->disk->flags & GENHD_FL_UP) {
+		if (blk_get_integrity(ns->disk))
+			blk_integrity_unregister(ns->disk);
+		sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
+					&nvme_ns_attr_group);
+		del_gendisk(ns->disk);
+		blk_mq_abort_requeue_list(ns->queue);
+		blk_cleanup_queue(ns->queue);
+	}
+	mutex_lock(&ns->ctrl->namespaces_mutex);
+	list_del_init(&ns->list);
+	mutex_unlock(&ns->ctrl->namespaces_mutex);
+	nvme_put_ns(ns);
+}
+
+static void nvme_validate_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+{
+	struct nvme_ns *ns;
+
+	ns = nvme_find_ns(ctrl, nsid);
+	if (ns) {
+		if (revalidate_disk(ns->disk))
+			nvme_ns_remove(ns);
+	} else
+		nvme_alloc_ns(ctrl, nsid);
+}
+
+static int nvme_scan_ns_list(struct nvme_ctrl *ctrl, unsigned nn)
+{
+	struct nvme_ns *ns;
+	__le32 *ns_list;
+	unsigned i, j, nsid, prev = 0, num_lists = DIV_ROUND_UP(nn, 1024);
+	int ret = 0;
+
+	ns_list = kzalloc(0x1000, GFP_KERNEL);
+	if (!ns_list)
+		return -ENOMEM;
+
+	for (i = 0; i < num_lists; i++) {
+		ret = nvme_identify_ns_list(ctrl, prev, ns_list);
+		if (ret)
+			goto out;
+
+		for (j = 0; j < min(nn, 1024U); j++) {
+			nsid = le32_to_cpu(ns_list[j]);
+			if (!nsid)
+				goto out;
+
+			nvme_validate_ns(ctrl, nsid);
+
+			while (++prev < nsid) {
+				ns = nvme_find_ns(ctrl, prev);
+				if (ns)
+					nvme_ns_remove(ns);
+			}
+		}
+		nn -= j;
+	}
+ out:
+	kfree(ns_list);
+	return ret;
+}
+
+static void __nvme_scan_namespaces(struct nvme_ctrl *ctrl, unsigned nn)
+{
+	struct nvme_ns *ns, *next;
+	unsigned i;
+
+	lockdep_assert_held(&ctrl->namespaces_mutex);
+
+	for (i = 1; i <= nn; i++)
+		nvme_validate_ns(ctrl, i);
+
+	list_for_each_entry_safe(ns, next, &ctrl->namespaces, list) {
+		if (ns->ns_id > nn)
+			nvme_ns_remove(ns);
+	}
+}
+
+void nvme_scan_namespaces(struct nvme_ctrl *ctrl)
+{
+	struct nvme_id_ctrl *id;
+	unsigned nn;
+
+	if (nvme_identify_ctrl(ctrl, &id))
+		return;
+
+	mutex_lock(&ctrl->namespaces_mutex);
+	nn = le32_to_cpu(id->nn);
+	if (ctrl->vs >= NVME_VS(1, 1) &&
+	    !(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) {
+		if (!nvme_scan_ns_list(ctrl, nn))
+			goto done;
+	}
+	__nvme_scan_namespaces(ctrl, le32_to_cpup(&id->nn));
+ done:
+	list_sort(NULL, &ctrl->namespaces, ns_cmp);
+	mutex_unlock(&ctrl->namespaces_mutex);
+	kfree(id);
+}
+
+void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
+{
+	struct nvme_ns *ns, *next;
+
+	list_for_each_entry_safe(ns, next, &ctrl->namespaces, list)
+		nvme_ns_remove(ns);
+}
+
+static DEFINE_IDA(nvme_instance_ida);
+
+static int nvme_set_instance(struct nvme_ctrl *ctrl)
+{
+	int instance, error;
+
+	do {
+		if (!ida_pre_get(&nvme_instance_ida, GFP_KERNEL))
+			return -ENODEV;
+
+		spin_lock(&dev_list_lock);
+		error = ida_get_new(&nvme_instance_ida, &instance);
+		spin_unlock(&dev_list_lock);
+	} while (error == -EAGAIN);
+
+	if (error)
+		return -ENODEV;
+
+	ctrl->instance = instance;
+	return 0;
+}
+
+static void nvme_release_instance(struct nvme_ctrl *ctrl)
+{
+	spin_lock(&dev_list_lock);
+	ida_remove(&nvme_instance_ida, ctrl->instance);
+	spin_unlock(&dev_list_lock);
+}
+
+void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
+ {
+	device_destroy(nvme_class, MKDEV(nvme_char_major, ctrl->instance));
+
+	spin_lock(&dev_list_lock);
+	list_del(&ctrl->node);
+	spin_unlock(&dev_list_lock);
+}
+
+static void nvme_free_ctrl(struct kref *kref)
+{
+	struct nvme_ctrl *ctrl = container_of(kref, struct nvme_ctrl, kref);
+
+	put_device(ctrl->device);
+	nvme_release_instance(ctrl);
+
+	ctrl->ops->free_ctrl(ctrl);
+}
+
+void nvme_put_ctrl(struct nvme_ctrl *ctrl)
+{
+	kref_put(&ctrl->kref, nvme_free_ctrl);
+}
+
+/*
+ * Initialize a NVMe controller structures.  This needs to be called during
+ * earliest initialization so that we have the initialized structured around
+ * during probing.
+ */
+int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
+		const struct nvme_ctrl_ops *ops, unsigned long quirks)
+{
+	int ret;
+
+	INIT_LIST_HEAD(&ctrl->namespaces);
+	mutex_init(&ctrl->namespaces_mutex);
+	kref_init(&ctrl->kref);
+	ctrl->dev = dev;
+	ctrl->ops = ops;
+	ctrl->quirks = quirks;
+
+	ret = nvme_set_instance(ctrl);
+	if (ret)
+		goto out;
+
+	ctrl->device = device_create_with_groups(nvme_class, ctrl->dev,
+				MKDEV(nvme_char_major, ctrl->instance),
+				dev, nvme_dev_attr_groups,
+				"nvme%d", ctrl->instance);
+	if (IS_ERR(ctrl->device)) {
+		ret = PTR_ERR(ctrl->device);
+		goto out_release_instance;
+	}
+	get_device(ctrl->device);
+	dev_set_drvdata(ctrl->device, ctrl);
+
+	spin_lock(&dev_list_lock);
+	list_add_tail(&ctrl->node, &nvme_ctrl_list);
+	spin_unlock(&dev_list_lock);
+
+	/*
+	 * Initialize latency tolerance controls.  The sysfs files won't
+	 * be visible to userspace unless the device actually supports APST.
+	 */
+	ctrl->device->power.set_latency_tolerance = nvme_set_latency_tolerance;
+	dev_pm_qos_update_user_latency_tolerance(ctrl->device,
+		min(default_ps_max_latency_us, (unsigned long)S32_MAX));
+
+	return 0;
+out_release_instance:
+	nvme_release_instance(ctrl);
+out:
+	return ret;
+}
+
+/**
+ * nvme_kill_queues(): Ends all namespace queues
+ * @ctrl: the dead controller that needs to end
+ *
+ * Call this function when the driver determines it is unable to get the
+ * controller in a state capable of servicing IO.
+ */
+void nvme_kill_queues(struct nvme_ctrl *ctrl)
+{
+	struct nvme_ns *ns;
+
+	mutex_lock(&ctrl->namespaces_mutex);
+	list_for_each_entry(ns, &ctrl->namespaces, list) {
+		if (!kref_get_unless_zero(&ns->kref))
+			continue;
+
+		/*
+		 * Revalidating a dead namespace sets capacity to 0. This will
+		 * end buffered writers dirtying pages that can't be synced.
+		 */
+		if (!test_and_set_bit(NVME_NS_DEAD, &ns->flags))
+			revalidate_disk(ns->disk);
+
+		blk_set_queue_dying(ns->queue);
+		blk_mq_abort_requeue_list(ns->queue);
+		blk_mq_start_stopped_hw_queues(ns->queue, true);
+
+		nvme_put_ns(ns);
+	}
+	mutex_unlock(&ctrl->namespaces_mutex);
+}
+
+void nvme_stop_queues(struct nvme_ctrl *ctrl)
+{
+	struct nvme_ns *ns;
+
+	mutex_lock(&ctrl->namespaces_mutex);
+	list_for_each_entry(ns, &ctrl->namespaces, list) {
+		spin_lock_irq(ns->queue->queue_lock);
+		queue_flag_set(QUEUE_FLAG_STOPPED, ns->queue);
+		spin_unlock_irq(ns->queue->queue_lock);
+
+		blk_mq_cancel_requeue_work(ns->queue);
+		blk_mq_stop_hw_queues(ns->queue);
+	}
+	mutex_unlock(&ctrl->namespaces_mutex);
+}
+
+void nvme_start_queues(struct nvme_ctrl *ctrl)
+{
+	struct nvme_ns *ns;
+
+	mutex_lock(&ctrl->namespaces_mutex);
+	list_for_each_entry(ns, &ctrl->namespaces, list) {
+		queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, ns->queue);
+		blk_mq_start_stopped_hw_queues(ns->queue, true);
+		blk_mq_kick_requeue_list(ns->queue);
+	}
+	mutex_unlock(&ctrl->namespaces_mutex);
+}
+
+int __init nvme_core_init(void)
+{
+	int result;
+
+	result = register_blkdev(nvme_major, "nvme");
+	if (result < 0)
+		return result;
+	else if (result > 0)
+		nvme_major = result;
+
+	result = __register_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme",
+							&nvme_dev_fops);
+	if (result < 0)
+		goto unregister_blkdev;
+	else if (result > 0)
+		nvme_char_major = result;
+
+	nvme_class = class_create(THIS_MODULE, "nvme");
+	if (IS_ERR(nvme_class)) {
+		result = PTR_ERR(nvme_class);
+		goto unregister_chrdev;
+	}
+
+	return 0;
+
+ unregister_chrdev:
+	__unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
+ unregister_blkdev:
+	unregister_blkdev(nvme_major, "nvme");
+	return result;
+}
+
+void nvme_core_exit(void)
+{
+	unregister_blkdev(nvme_major, "nvme");
+	class_destroy(nvme_class);
+	__unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
+}
--- linux-4.4.0.orig/drivers/nvme/host/lightnvm.c
+++ linux-4.4.0/drivers/nvme/host/lightnvm.c
@@ -146,6 +146,16 @@
 	};
 };
 
+struct nvme_nvm_lp_mlc {
+	__u16			num_pairs;
+	__u8			pairs[886];
+};
+
+struct nvme_nvm_lp_tbl {
+	__u8			id[8];
+	struct nvme_nvm_lp_mlc	mlc;
+};
+
 struct nvme_nvm_id_group {
 	__u8			mtype;
 	__u8			fmtype;
@@ -169,7 +179,8 @@
 	__le32			mpos;
 	__le32			mccap;
 	__le16			cpar;
-	__u8			reserved[906];
+	__u8			reserved[10];
+	struct nvme_nvm_lp_tbl lptbl;
 } __packed;
 
 struct nvme_nvm_addr_format {
@@ -266,6 +277,15 @@
 		dst->mccap = le32_to_cpu(src->mccap);
 
 		dst->cpar = le16_to_cpu(src->cpar);
+
+		if (dst->fmtype == NVM_ID_FMTYPE_MLC) {
+			memcpy(dst->lptbl.id, src->lptbl.id, 8);
+			dst->lptbl.mlc.num_pairs =
+					le16_to_cpu(src->lptbl.mlc.num_pairs);
+			/* 4 bits per pair */
+			memcpy(dst->lptbl.mlc.pairs, src->lptbl.mlc.pairs,
+						dst->lptbl.mlc.num_pairs >> 1);
+		}
 	}
 
 	return 0;
@@ -274,7 +294,6 @@
 static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
 {
 	struct nvme_ns *ns = nvmdev->q->queuedata;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_nvm_id *nvme_nvm_id;
 	struct nvme_nvm_command c = {};
 	int ret;
@@ -287,7 +306,7 @@
 	if (!nvme_nvm_id)
 		return -ENOMEM;
 
-	ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+	ret = nvme_submit_sync_cmd(ns->ctrl->admin_q, (struct nvme_command *)&c,
 				nvme_nvm_id, sizeof(struct nvme_nvm_id));
 	if (ret) {
 		ret = -EIO;
@@ -312,9 +331,8 @@
 				nvm_l2p_update_fn *update_l2p, void *priv)
 {
 	struct nvme_ns *ns = nvmdev->q->queuedata;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_nvm_command c = {};
-	u32 len = queue_max_hw_sectors(dev->admin_q) << 9;
+	u32 len = queue_max_hw_sectors(ns->ctrl->admin_q) << 9;
 	u32 nlb_pr_rq = len / sizeof(u64);
 	u64 cmd_slba = slba;
 	void *entries;
@@ -332,10 +350,10 @@
 		c.l2p.slba = cpu_to_le64(cmd_slba);
 		c.l2p.nlb = cpu_to_le32(cmd_nlb);
 
-		ret = nvme_submit_sync_cmd(dev->admin_q,
+		ret = nvme_submit_sync_cmd(ns->ctrl->admin_q,
 				(struct nvme_command *)&c, entries, len);
 		if (ret) {
-			dev_err(dev->dev, "L2P table transfer failed (%d)\n",
+			dev_err(ns->ctrl->dev, "L2P table transfer failed (%d)\n",
 									ret);
 			ret = -EIO;
 			goto out;
@@ -361,7 +379,7 @@
 {
 	struct request_queue *q = nvmdev->q;
 	struct nvme_ns *ns = q->queuedata;
-	struct nvme_dev *dev = ns->dev;
+	struct nvme_ctrl *ctrl = ns->ctrl;
 	struct nvme_nvm_command c = {};
 	struct nvme_nvm_bb_tbl *bb_tbl;
 	int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blocks;
@@ -375,41 +393,36 @@
 	if (!bb_tbl)
 		return -ENOMEM;
 
-	ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+	ret = nvme_submit_sync_cmd(ctrl->admin_q, (struct nvme_command *)&c,
 								bb_tbl, tblsz);
 	if (ret) {
-		dev_err(dev->dev, "get bad block table failed (%d)\n", ret);
+		dev_err(ctrl->dev, "get bad block table failed (%d)\n", ret);
 		ret = -EIO;
 		goto out;
 	}
 
 	if (bb_tbl->tblid[0] != 'B' || bb_tbl->tblid[1] != 'B' ||
 		bb_tbl->tblid[2] != 'L' || bb_tbl->tblid[3] != 'T') {
-		dev_err(dev->dev, "bbt format mismatch\n");
+		dev_err(ctrl->dev, "bbt format mismatch\n");
 		ret = -EINVAL;
 		goto out;
 	}
 
 	if (le16_to_cpu(bb_tbl->verid) != 1) {
 		ret = -EINVAL;
-		dev_err(dev->dev, "bbt version not supported\n");
+		dev_err(ctrl->dev, "bbt version not supported\n");
 		goto out;
 	}
 
 	if (le32_to_cpu(bb_tbl->tblks) != nr_blocks) {
 		ret = -EINVAL;
-		dev_err(dev->dev, "bbt unsuspected blocks returned (%u!=%u)",
+		dev_err(ctrl->dev, "bbt unsuspected blocks returned (%u!=%u)",
 					le32_to_cpu(bb_tbl->tblks), nr_blocks);
 		goto out;
 	}
 
 	ppa = dev_to_generic_addr(nvmdev, ppa);
 	ret = update_bbtbl(ppa, nr_blocks, bb_tbl->blk, priv);
-	if (ret) {
-		ret = -EINTR;
-		goto out;
-	}
-
 out:
 	kfree(bb_tbl);
 	return ret;
@@ -419,7 +432,6 @@
 								int type)
 {
 	struct nvme_ns *ns = nvmdev->q->queuedata;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_nvm_command c = {};
 	int ret = 0;
 
@@ -429,10 +441,10 @@
 	c.set_bb.nlb = cpu_to_le16(rqd->nr_pages - 1);
 	c.set_bb.value = type;
 
-	ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+	ret = nvme_submit_sync_cmd(ns->ctrl->admin_q, (struct nvme_command *)&c,
 								NULL, 0);
 	if (ret)
-		dev_err(dev->dev, "set bad block table failed (%d)\n", ret);
+		dev_err(ns->ctrl->dev, "set bad block table failed (%d)\n", ret);
 	return ret;
 }
 
@@ -453,11 +465,8 @@
 static void nvme_nvm_end_io(struct request *rq, int error)
 {
 	struct nvm_rq *rqd = rq->end_io_data;
-	struct nvm_dev *dev = rqd->dev;
 
-	if (dev->mt && dev->mt->end_io(rqd, error))
-		pr_err("nvme: err status: %x result: %lx\n",
-				rq->errors, (unsigned long)rq->special);
+	nvm_end_io(rqd, error);
 
 	kfree(rq->cmd);
 	blk_mq_free_request(rq);
@@ -471,7 +480,7 @@
 	struct bio *bio = rqd->bio;
 	struct nvme_nvm_command *cmd;
 
-	rq = blk_mq_alloc_request(q, bio_rw(bio), GFP_KERNEL, 0);
+	rq = blk_mq_alloc_request(q, bio_rw(bio), 0);
 	if (IS_ERR(rq))
 		return -ENOMEM;
 
@@ -520,9 +529,8 @@
 static void *nvme_nvm_create_dma_pool(struct nvm_dev *nvmdev, char *name)
 {
 	struct nvme_ns *ns = nvmdev->q->queuedata;
-	struct nvme_dev *dev = ns->dev;
 
-	return dma_pool_create(name, dev->dev, PAGE_SIZE, PAGE_SIZE, 0);
+	return dma_pool_create(name, ns->ctrl->dev, PAGE_SIZE, PAGE_SIZE, 0);
 }
 
 static void nvme_nvm_destroy_dma_pool(void *pool)
@@ -580,8 +588,9 @@
 
 int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
 {
-	struct nvme_dev *dev = ns->dev;
-	struct pci_dev *pdev = to_pci_dev(dev->dev);
+	struct nvme_ctrl *ctrl = ns->ctrl;
+	/* XXX: this is poking into PCI structures from generic code! */
+	struct pci_dev *pdev = to_pci_dev(ctrl->dev);
 
 	/* QEMU NVMe simulator - PCI ID + Vendor specific bit */
 	if (pdev->vendor == PCI_VENDOR_ID_CNEX &&
--- linux-4.4.0.orig/drivers/nvme/host/nvme.h
+++ linux-4.4.0/drivers/nvme/host/nvme.h
@@ -19,58 +19,113 @@
 #include <linux/kref.h>
 #include <linux/blk-mq.h>
 
-extern unsigned char nvme_io_timeout;
+enum {
+	/*
+	 * Driver internal status code for commands that were cancelled due
+	 * to timeouts or controller shutdown.  The value is negative so
+	 * that it a) doesn't overlap with the unsigned hardware error codes,
+	 * and b) can easily be tested for.
+	 */
+	NVME_SC_CANCELLED		= -EINTR,
+};
+
+extern unsigned int nvme_io_timeout;
 #define NVME_IO_TIMEOUT	(nvme_io_timeout * HZ)
 
+extern unsigned int admin_timeout;
+#define ADMIN_TIMEOUT	(admin_timeout * HZ)
+
+extern unsigned char shutdown_timeout;
+#define SHUTDOWN_TIMEOUT	(shutdown_timeout * HZ)
+
 enum {
 	NVME_NS_LBA		= 0,
 	NVME_NS_LIGHTNVM	= 1,
 };
 
 /*
- * Represents an NVM Express device.  Each nvme_dev is a PCI function.
+ * List of workarounds for devices that required behavior not specified in
+ * the standard.
  */
-struct nvme_dev {
-	struct list_head node;
-	struct nvme_queue **queues;
+enum nvme_quirks {
+	/*
+	 * Prefers I/O aligned to a stripe size specified in a vendor
+	 * specific Identify field.
+	 */
+	NVME_QUIRK_STRIPE_SIZE			= (1 << 0),
+
+	/*
+	 * The controller doesn't handle Identify value others than 0 or 1
+	 * correctly.
+	 */
+	NVME_QUIRK_IDENTIFY_CNS			= (1 << 1),
+
+	/*
+	 * The controller deterministically returns O's on reads to discarded
+	 * logical blocks.
+	 */
+	NVME_QUIRK_DISCARD_ZEROES		= (1 << 2),
+
+	/*
+	 * The controller needs a delay before starts checking the device
+	 * readiness, which is done by reading the NVME_CSTS_RDY bit.
+	 */
+	NVME_QUIRK_DELAY_BEFORE_CHK_RDY		= (1 << 3),
+
+	/*
+	 * APST should not be used.
+	 */
+	NVME_QUIRK_NO_APST			= (1 << 4),
+
+	/*
+	 * The deepest sleep state should not be used.
+	 */
+	NVME_QUIRK_NO_DEEPEST_PS		= (1 << 5),
+};
+
+/* The below value is the specific amount of delay needed before checking
+ * readiness in case of the PCI_DEVICE(0x1c58, 0x0003), which needs the
+ * NVME_QUIRK_DELAY_BEFORE_CHK_RDY quirk enabled. The value (in ms) was
+ * found empirically.
+ */
+#define NVME_QUIRK_DELAY_AMOUNT		2000
+
+struct nvme_ctrl {
+	bool identified;
+	const struct nvme_ctrl_ops *ops;
 	struct request_queue *admin_q;
-	struct blk_mq_tag_set tagset;
-	struct blk_mq_tag_set admin_tagset;
-	u32 __iomem *dbs;
 	struct device *dev;
-	struct dma_pool *prp_page_pool;
-	struct dma_pool *prp_small_pool;
+	struct kref kref;
 	int instance;
-	unsigned queue_count;
-	unsigned online_queues;
-	unsigned max_qid;
-	int q_depth;
-	u32 db_stride;
-	u32 ctrl_config;
-	struct msix_entry *entry;
-	struct nvme_bar __iomem *bar;
+	struct blk_mq_tag_set *tagset;
 	struct list_head namespaces;
-	struct kref kref;
-	struct device *device;
-	struct work_struct reset_work;
-	struct work_struct probe_work;
-	struct work_struct scan_work;
+	struct mutex namespaces_mutex;
+	struct device *device;	/* char device */
+	struct list_head node;
+
 	char name[12];
 	char serial[20];
 	char model[40];
 	char firmware_rev[8];
-	bool subsystem;
+
+	u32 ctrl_config;
+
+	u32 page_size;
 	u32 max_hw_sectors;
 	u32 stripe_size;
-	u32 page_size;
-	void __iomem *cmb;
-	dma_addr_t cmb_dma_addr;
-	u64 cmb_size;
-	u32 cmbsz;
 	u16 oncs;
-	u16 abort_limit;
+	atomic_t abort_limit;
 	u8 event_limit;
 	u8 vwc;
+	u32 vs;
+	u8 npss;
+	u8 apsta;
+	bool subsystem;
+	unsigned long quirks;
+	struct nvme_id_power_state psd[32];
+
+	/* Power saving configuration */
+	u64 ps_max_latency_us;
 };
 
 /*
@@ -79,56 +134,182 @@
 struct nvme_ns {
 	struct list_head list;
 
-	struct nvme_dev *dev;
+	struct nvme_ctrl *ctrl;
 	struct request_queue *queue;
 	struct gendisk *disk;
 	struct kref kref;
 
+	u8 eui[8];
+	u8 uuid[16];
+
 	unsigned ns_id;
 	int lba_shift;
 	u16 ms;
 	bool ext;
 	u8 pi_type;
 	int type;
+	unsigned long flags;
+
+#define NVME_NS_REMOVING 0
+#define NVME_NS_DEAD     1
+
 	u64 mode_select_num_blocks;
 	u32 mode_select_block_len;
 };
 
-/*
- * The nvme_iod describes the data in an I/O, including the list of PRP
- * entries.  You can't see it in this data structure because C doesn't let
- * me express that.  Use nvme_alloc_iod to ensure there's enough space
- * allocated to store the PRP list.
- */
-struct nvme_iod {
-	unsigned long private;	/* For the use of the submitter of the I/O */
-	int npages;		/* In the PRP list. 0 means small pool in use */
-	int offset;		/* Of PRP list */
-	int nents;		/* Used in scatterlist */
-	int length;		/* Of data, in bytes */
-	dma_addr_t first_dma;
-	struct scatterlist meta_sg[1]; /* metadata requires single contiguous buffer */
-	struct scatterlist sg[0];
+struct nvme_ctrl_ops {
+	int (*reg_read32)(struct nvme_ctrl *ctrl, u32 off, u32 *val);
+	int (*reg_write32)(struct nvme_ctrl *ctrl, u32 off, u32 val);
+	int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val);
+	bool (*io_incapable)(struct nvme_ctrl *ctrl);
+	int (*reset_ctrl)(struct nvme_ctrl *ctrl);
+	void (*free_ctrl)(struct nvme_ctrl *ctrl);
 };
 
+static inline bool nvme_ctrl_ready(struct nvme_ctrl *ctrl)
+{
+	u32 val = 0;
+
+	if (ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &val))
+		return false;
+	return val & NVME_CSTS_RDY;
+}
+
+static inline bool nvme_io_incapable(struct nvme_ctrl *ctrl)
+{
+	u32 val = 0;
+
+	if (ctrl->ops->io_incapable(ctrl))
+		return false;
+	if (ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &val))
+		return false;
+	return val & NVME_CSTS_CFS;
+}
+
+static inline int nvme_reset_subsystem(struct nvme_ctrl *ctrl)
+{
+	if (!ctrl->subsystem)
+		return -ENOTTY;
+	return ctrl->ops->reg_write32(ctrl, NVME_REG_NSSR, 0x4E564D65);
+}
+
 static inline u64 nvme_block_nr(struct nvme_ns *ns, sector_t sector)
 {
 	return (sector >> (ns->lba_shift - 9));
 }
 
+static inline void nvme_setup_flush(struct nvme_ns *ns,
+		struct nvme_command *cmnd)
+{
+	memset(cmnd, 0, sizeof(*cmnd));
+	cmnd->common.opcode = nvme_cmd_flush;
+	cmnd->common.nsid = cpu_to_le32(ns->ns_id);
+}
+
+static inline void nvme_setup_rw(struct nvme_ns *ns, struct request *req,
+		struct nvme_command *cmnd)
+{
+	u16 control = 0;
+	u32 dsmgmt = 0;
+
+	if (req->cmd_flags & REQ_FUA)
+		control |= NVME_RW_FUA;
+	if (req->cmd_flags & (REQ_FAILFAST_DEV | REQ_RAHEAD))
+		control |= NVME_RW_LR;
+
+	if (req->cmd_flags & REQ_RAHEAD)
+		dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH;
+
+	memset(cmnd, 0, sizeof(*cmnd));
+	cmnd->rw.opcode = (rq_data_dir(req) ? nvme_cmd_write : nvme_cmd_read);
+	cmnd->rw.command_id = req->tag;
+	cmnd->rw.nsid = cpu_to_le32(ns->ns_id);
+	cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
+	cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
+
+	if (ns->ms) {
+		switch (ns->pi_type) {
+		case NVME_NS_DPS_PI_TYPE3:
+			control |= NVME_RW_PRINFO_PRCHK_GUARD;
+			break;
+		case NVME_NS_DPS_PI_TYPE1:
+		case NVME_NS_DPS_PI_TYPE2:
+			control |= NVME_RW_PRINFO_PRCHK_GUARD |
+					NVME_RW_PRINFO_PRCHK_REF;
+			cmnd->rw.reftag = cpu_to_le32(
+					nvme_block_nr(ns, blk_rq_pos(req)));
+			break;
+		}
+		if (!blk_integrity_rq(req))
+			control |= NVME_RW_PRINFO_PRACT;
+	}
+
+	cmnd->rw.control = cpu_to_le16(control);
+	cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
+}
+
+
+static inline int nvme_error_status(u16 status)
+{
+	switch (status & 0x7ff) {
+	case NVME_SC_SUCCESS:
+		return 0;
+	case NVME_SC_CAP_EXCEEDED:
+		return -ENOSPC;
+	default:
+		return -EIO;
+	}
+}
+
+static inline bool nvme_req_needs_retry(struct request *req, u16 status)
+{
+	return !(status & NVME_SC_DNR || blk_noretry_request(req)) &&
+		(jiffies - req->start_time) < req->timeout;
+}
+
+int nvme_disable_ctrl(struct nvme_ctrl *ctrl, u64 cap);
+int nvme_enable_ctrl(struct nvme_ctrl *ctrl, u64 cap);
+int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl);
+int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
+		const struct nvme_ctrl_ops *ops, unsigned long quirks);
+void nvme_uninit_ctrl(struct nvme_ctrl *ctrl);
+void nvme_put_ctrl(struct nvme_ctrl *ctrl);
+int nvme_init_identify(struct nvme_ctrl *ctrl);
+
+void nvme_scan_namespaces(struct nvme_ctrl *ctrl);
+void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
+
+void nvme_stop_queues(struct nvme_ctrl *ctrl);
+void nvme_start_queues(struct nvme_ctrl *ctrl);
+void nvme_kill_queues(struct nvme_ctrl *ctrl);
+
+#define NVME_QID_ANY -1
+struct request *nvme_alloc_request(struct request_queue *q,
+		struct nvme_command *cmd, unsigned int flags, int qid);
+void nvme_requeue_req(struct request *req);
 int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
 		void *buf, unsigned bufflen);
 int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
-		void *buffer, void __user *ubuffer, unsigned bufflen,
+		struct nvme_completion *cqe, void *buffer, unsigned bufflen,
+		unsigned timeout, int qid, int at_head, int flags);
+int nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
+		void __user *ubuffer, unsigned bufflen, u32 *result,
+		unsigned timeout);
+int __nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
+		void __user *ubuffer, unsigned bufflen,
+		void __user *meta_buffer, unsigned meta_len, u32 meta_seed,
 		u32 *result, unsigned timeout);
-int nvme_identify_ctrl(struct nvme_dev *dev, struct nvme_id_ctrl **id);
-int nvme_identify_ns(struct nvme_dev *dev, unsigned nsid,
+int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id);
+int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
 		struct nvme_id_ns **id);
-int nvme_get_log_page(struct nvme_dev *dev, struct nvme_smart_log **log);
-int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
-			dma_addr_t dma_addr, u32 *result);
-int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
-			dma_addr_t dma_addr, u32 *result);
+int nvme_get_log_page(struct nvme_ctrl *dev, struct nvme_smart_log **log);
+int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
+		      void *buffer, size_t buflen, u32 *result);
+int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
+		      void *buffer, size_t buflen, u32 *result);
+int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count);
+
+extern spinlock_t dev_list_lock;
 
 struct sg_io_hdr;
 
@@ -154,4 +335,7 @@
 }
 #endif /* CONFIG_NVM */
 
+int __init nvme_core_init(void);
+void nvme_core_exit(void);
+
 #endif /* _NVME_H */
--- linux-4.4.0.orig/drivers/nvme/host/pci.c
+++ linux-4.4.0/drivers/nvme/host/pci.c
@@ -12,11 +12,14 @@
  * more details.
  */
 
+#include <linux/aer.h>
 #include <linux/bitops.h>
 #include <linux/blkdev.h>
 #include <linux/blk-mq.h>
 #include <linux/cpu.h>
 #include <linux/delay.h>
+#include <linux/dma-attrs.h>
+#include <linux/dmi.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
@@ -26,53 +29,51 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kdev_t.h>
-#include <linux/kthread.h>
 #include <linux/kernel.h>
-#include <linux/list_sort.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/poison.h>
 #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/t10-pi.h>
+#include <linux/timer.h>
 #include <linux/types.h>
-#include <linux/pr.h>
-#include <scsi/sg.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <asm/unaligned.h>
 
-#include <uapi/linux/nvme_ioctl.h>
 #include "nvme.h"
 
-#define NVME_MINORS		(1U << MINORBITS)
 #define NVME_Q_DEPTH		1024
 #define NVME_AQ_DEPTH		256
 #define SQ_SIZE(depth)		(depth * sizeof(struct nvme_command))
 #define CQ_SIZE(depth)		(depth * sizeof(struct nvme_completion))
-#define ADMIN_TIMEOUT		(admin_timeout * HZ)
-#define SHUTDOWN_TIMEOUT	(shutdown_timeout * HZ)
+		
+/* Google Vendor ID is not in include/linux/pci_ids.h */
+#define PCI_VENDOR_ID_GOOGLE 0x1AE0
 
-static unsigned char admin_timeout = 60;
-module_param(admin_timeout, byte, 0644);
+/*
+ * We handle AEN commands ourselves and don't even let the
+ * block layer know about them.
+ */
+#define NVME_NR_AEN_COMMANDS	1
+#define NVME_AQ_BLKMQ_DEPTH	(NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS)
+
+unsigned int admin_timeout = 60;
+module_param(admin_timeout, uint, 0644);
 MODULE_PARM_DESC(admin_timeout, "timeout in seconds for admin commands");
 
-unsigned char nvme_io_timeout = 30;
-module_param_named(io_timeout, nvme_io_timeout, byte, 0644);
+unsigned int nvme_io_timeout = 30;
+module_param_named(io_timeout, nvme_io_timeout, uint, 0644);
 MODULE_PARM_DESC(io_timeout, "timeout in seconds for I/O");
 
-static unsigned char shutdown_timeout = 5;
+unsigned char shutdown_timeout = 5;
 module_param(shutdown_timeout, byte, 0644);
 MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
 
-static int nvme_major;
-module_param(nvme_major, int, 0);
-
-static int nvme_char_major;
-module_param(nvme_char_major, int, 0);
-
 static int use_threaded_interrupts;
 module_param(use_threaded_interrupts, int, 0);
 
@@ -80,28 +81,67 @@
 module_param(use_cmb_sqes, bool, 0644);
 MODULE_PARM_DESC(use_cmb_sqes, "use controller's memory buffer for I/O SQes");
 
-static DEFINE_SPINLOCK(dev_list_lock);
-static LIST_HEAD(dev_list);
-static struct task_struct *nvme_thread;
 static struct workqueue_struct *nvme_workq;
-static wait_queue_head_t nvme_kthread_wait;
 
-static struct class *nvme_class;
+static DEFINE_DMA_ATTRS(nvme_dma_attrs);
+
+struct nvme_dev;
+struct nvme_queue;
 
-static int __nvme_reset(struct nvme_dev *dev);
 static int nvme_reset(struct nvme_dev *dev);
 static void nvme_process_cq(struct nvme_queue *nvmeq);
-static void nvme_dead_ctrl(struct nvme_dev *dev);
+static void nvme_remove_dead_ctrl(struct nvme_dev *dev);
+static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown);
 
-struct async_cmd_info {
-	struct kthread_work work;
-	struct kthread_worker *worker;
-	struct request *req;
-	u32 result;
-	int status;
-	void *ctx;
+/*
+ * Represents an NVM Express device.  Each nvme_dev is a PCI function.
+ */
+struct nvme_dev {
+	struct nvme_queue **queues;
+	struct blk_mq_tag_set tagset;
+	struct blk_mq_tag_set admin_tagset;
+	u32 __iomem *dbs;
+	struct device *dev;
+	struct dma_pool *prp_page_pool;
+	struct dma_pool *prp_small_pool;
+	unsigned queue_count;
+	unsigned online_queues;
+	unsigned max_qid;
+	int q_depth;
+	u32 db_stride;
+	struct msix_entry *entry;
+	void __iomem *bar;
+	struct work_struct reset_work;
+	struct work_struct scan_work;
+	struct work_struct remove_work;
+	struct work_struct async_work;
+	struct timer_list watchdog_timer;
+	struct mutex shutdown_lock;
+	bool subsystem;
+	void __iomem *cmb;
+	dma_addr_t cmb_dma_addr;
+	u64 cmb_size;
+	u32 cmbsz;
+	unsigned long flags;
+
+#define NVME_CTRL_RESETTING    0
+#define NVME_CTRL_REMOVING     1
+
+	struct nvme_ctrl ctrl;
+	struct completion ioq_wait;
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	u32 *db_mem;
+	dma_addr_t doorbell;
+	u32 *ei_mem;
+	dma_addr_t eventidx;
+#endif
 };
 
+static inline struct nvme_dev *to_nvme_dev(struct nvme_ctrl *ctrl)
+{
+	return container_of(ctrl, struct nvme_dev, ctrl);
+}
+
 /*
  * An NVM Express queue.  Each device has at least two (one for admin
  * commands and one for I/O commands).
@@ -126,7 +166,30 @@
 	u16 qid;
 	u8 cq_phase;
 	u8 cqe_seen;
-	struct async_cmd_info cmdinfo;
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	u32 *sq_doorbell_addr;
+	u32 *sq_eventidx_addr;
+	u32 *cq_doorbell_addr;
+	u32 *cq_eventidx_addr;
+#endif
+};
+
+/*
+ * The nvme_iod describes the data in an I/O, including the list of PRP
+ * entries.  You can't see it in this data structure because C doesn't let
+ * me express that.  Use nvme_init_iod to ensure there's enough space
+ * allocated to store the PRP list.
+ */
+struct nvme_iod {
+	struct nvme_queue *nvmeq;
+	int aborted;
+	int npages;		/* In the PRP list. 0 means small pool in use */
+	int nents;		/* Used in scatterlist */
+	int length;		/* Of data, in bytes */
+	dma_addr_t first_dma;
+	struct scatterlist meta_sg; /* metadata requires single contiguous buffer */
+	struct scatterlist *sg;
+	struct scatterlist inline_sg[0];
 };
 
 /*
@@ -146,25 +209,16 @@
 	BUILD_BUG_ON(sizeof(struct nvme_id_ns) != 4096);
 	BUILD_BUG_ON(sizeof(struct nvme_lba_range_type) != 64);
 	BUILD_BUG_ON(sizeof(struct nvme_smart_log) != 512);
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	BUILD_BUG_ON(sizeof(struct nvme_doorbell_memory) != 64);
+#endif
 }
 
-typedef void (*nvme_completion_fn)(struct nvme_queue *, void *,
-						struct nvme_completion *);
-
-struct nvme_cmd_info {
-	nvme_completion_fn fn;
-	void *ctx;
-	int aborted;
-	struct nvme_queue *nvmeq;
-	struct nvme_iod iod[0];
-};
-
 /*
  * Max size of iod being embedded in the request payload
  */
 #define NVME_INT_PAGES		2
-#define NVME_INT_BYTES(dev)	(NVME_INT_PAGES * (dev)->page_size)
-#define NVME_INT_MASK		0x01
+#define NVME_INT_BYTES(dev)	(NVME_INT_PAGES * (dev)->ctrl.page_size)
 
 /*
  * Will slightly overestimate the number of pages needed.  This is OK
@@ -173,19 +227,22 @@
  */
 static int nvme_npages(unsigned size, struct nvme_dev *dev)
 {
-	unsigned nprps = DIV_ROUND_UP(size + dev->page_size, dev->page_size);
+	unsigned nprps = DIV_ROUND_UP(size + dev->ctrl.page_size,
+				      dev->ctrl.page_size);
 	return DIV_ROUND_UP(8 * nprps, PAGE_SIZE - 8);
 }
 
-static unsigned int nvme_cmd_size(struct nvme_dev *dev)
+static unsigned int nvme_iod_alloc_size(struct nvme_dev *dev,
+		unsigned int size, unsigned int nseg)
 {
-	unsigned int ret = sizeof(struct nvme_cmd_info);
-
-	ret += sizeof(struct nvme_iod);
-	ret += sizeof(__le64 *) * nvme_npages(NVME_INT_BYTES(dev), dev);
-	ret += sizeof(struct scatterlist) * NVME_INT_PAGES;
+	return sizeof(__le64 *) * nvme_npages(size, dev) +
+			sizeof(struct scatterlist) * nseg;
+}
 
-	return ret;
+static unsigned int nvme_cmd_size(struct nvme_dev *dev)
+{
+	return sizeof(struct nvme_iod) +
+		nvme_iod_alloc_size(dev, NVME_INT_BYTES(dev), NVME_INT_PAGES);
 }
 
 static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
@@ -215,11 +272,11 @@
 				unsigned int numa_node)
 {
 	struct nvme_dev *dev = data;
-	struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(req);
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 	struct nvme_queue *nvmeq = dev->queues[0];
 
 	BUG_ON(!nvmeq);
-	cmd->nvmeq = nvmeq;
+	iod->nvmeq = nvmeq;
 	return 0;
 }
 
@@ -242,148 +299,101 @@
 				unsigned int numa_node)
 {
 	struct nvme_dev *dev = data;
-	struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(req);
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 	struct nvme_queue *nvmeq = dev->queues[hctx_idx + 1];
 
 	BUG_ON(!nvmeq);
-	cmd->nvmeq = nvmeq;
+	iod->nvmeq = nvmeq;
 	return 0;
 }
 
-static void nvme_set_info(struct nvme_cmd_info *cmd, void *ctx,
-				nvme_completion_fn handler)
-{
-	cmd->fn = handler;
-	cmd->ctx = ctx;
-	cmd->aborted = 0;
-	blk_mq_start_request(blk_mq_rq_from_pdu(cmd));
-}
-
-static void *iod_get_private(struct nvme_iod *iod)
-{
-	return (void *) (iod->private & ~0x1UL);
-}
-
-/*
- * If bit 0 is set, the iod is embedded in the request payload.
- */
-static bool iod_should_kfree(struct nvme_iod *iod)
-{
-	return (iod->private & NVME_INT_MASK) == 0;
-}
-
-/* Special values must be less than 0x1000 */
-#define CMD_CTX_BASE		((void *)POISON_POINTER_DELTA)
-#define CMD_CTX_CANCELLED	(0x30C + CMD_CTX_BASE)
-#define CMD_CTX_COMPLETED	(0x310 + CMD_CTX_BASE)
-#define CMD_CTX_INVALID		(0x314 + CMD_CTX_BASE)
-
-static void special_completion(struct nvme_queue *nvmeq, void *ctx,
-						struct nvme_completion *cqe)
+static void nvme_queue_scan(struct nvme_dev *dev)
 {
-	if (ctx == CMD_CTX_CANCELLED)
-		return;
-	if (ctx == CMD_CTX_COMPLETED) {
-		dev_warn(nvmeq->q_dmadev,
-				"completed id %d twice on queue %d\n",
-				cqe->command_id, le16_to_cpup(&cqe->sq_id));
-		return;
-	}
-	if (ctx == CMD_CTX_INVALID) {
-		dev_warn(nvmeq->q_dmadev,
-				"invalid id %d completed on queue %d\n",
-				cqe->command_id, le16_to_cpup(&cqe->sq_id));
+	/*
+	 * Do not queue new scan work when a controller is reset during
+	 * removal.
+	 */
+	if (test_bit(NVME_CTRL_REMOVING, &dev->flags))
 		return;
-	}
-	dev_warn(nvmeq->q_dmadev, "Unknown special completion %p\n", ctx);
+	queue_work(nvme_workq, &dev->scan_work);
 }
 
-static void *cancel_cmd_info(struct nvme_cmd_info *cmd, nvme_completion_fn *fn)
+static void nvme_complete_async_event(struct nvme_dev *dev,
+		struct nvme_completion *cqe)
 {
-	void *ctx;
+	u16 status = le16_to_cpu(cqe->status) >> 1;
+	u32 result = le32_to_cpu(cqe->result);
 
-	if (fn)
-		*fn = cmd->fn;
-	ctx = cmd->ctx;
-	cmd->fn = special_completion;
-	cmd->ctx = CMD_CTX_CANCELLED;
-	return ctx;
-}
-
-static void async_req_completion(struct nvme_queue *nvmeq, void *ctx,
-						struct nvme_completion *cqe)
-{
-	u32 result = le32_to_cpup(&cqe->result);
-	u16 status = le16_to_cpup(&cqe->status) >> 1;
+	if (status == NVME_SC_SUCCESS || status == NVME_SC_ABORT_REQ) {
+		++dev->ctrl.event_limit;
+		queue_work(nvme_workq, &dev->async_work);
+	}
 
-	if (status == NVME_SC_SUCCESS || status == NVME_SC_ABORT_REQ)
-		++nvmeq->dev->event_limit;
 	if (status != NVME_SC_SUCCESS)
 		return;
 
 	switch (result & 0xff07) {
 	case NVME_AER_NOTICE_NS_CHANGED:
-		dev_info(nvmeq->q_dmadev, "rescanning\n");
-		schedule_work(&nvmeq->dev->scan_work);
+		dev_info(dev->dev, "rescanning\n");
+		nvme_queue_scan(dev);
 	default:
-		dev_warn(nvmeq->q_dmadev, "async event result %08x\n", result);
+		dev_warn(dev->dev, "async event result %08x\n", result);
 	}
 }
 
-static void abort_completion(struct nvme_queue *nvmeq, void *ctx,
-						struct nvme_completion *cqe)
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+static int nvme_vendor_memory_size(struct nvme_dev *dev)
 {
-	struct request *req = ctx;
+	return ((num_possible_cpus() + 1) * 8 * dev->db_stride);
+}
 
-	u16 status = le16_to_cpup(&cqe->status) >> 1;
-	u32 result = le32_to_cpup(&cqe->result);
+static int nvme_set_doorbell_memory(struct nvme_dev *dev)
+{
+	struct nvme_command c;
 
-	blk_mq_free_request(req);
+	memset(&c, 0, sizeof(c));
+	c.doorbell_memory.opcode = nvme_admin_doorbell_memory;
+	c.doorbell_memory.prp1 = cpu_to_le64(dev->doorbell);
+	c.doorbell_memory.prp2 = cpu_to_le64(dev->eventidx);
 
-	dev_warn(nvmeq->q_dmadev, "Abort status:%x result:%x", status, result);
-	++nvmeq->dev->abort_limit;
+	return nvme_submit_sync_cmd(dev->ctrl.admin_q, &c, NULL, 0);
 }
 
-static void async_completion(struct nvme_queue *nvmeq, void *ctx,
-						struct nvme_completion *cqe)
+static inline int nvme_ext_need_event(u16 event_idx, u16 new_idx, u16 old)
 {
-	struct async_cmd_info *cmdinfo = ctx;
-	cmdinfo->result = le32_to_cpup(&cqe->result);
-	cmdinfo->status = le16_to_cpup(&cqe->status) >> 1;
-	queue_kthread_work(cmdinfo->worker, &cmdinfo->work);
-	blk_mq_free_request(cmdinfo->req);
+	/* Borrowed from vring_need_event */
+	return (u16)(new_idx - event_idx - 1) < (u16)(new_idx - old);
 }
 
-static inline struct nvme_cmd_info *get_cmd_from_tag(struct nvme_queue *nvmeq,
-				  unsigned int tag)
+static void nvme_ext_write_doorbell(u16 value, u32 __iomem* q_db,
+			   u32* db_addr, volatile u32* event_idx)
 {
-	struct request *req = blk_mq_tag_to_rq(*nvmeq->tags, tag);
+	u16 old_value;
+	if (!db_addr)
+		goto ring_doorbell;
 
-	return blk_mq_rq_to_pdu(req);
-}
+	old_value = *db_addr;
+	*db_addr = value;
 
-/*
- * Called with local interrupts disabled and the q_lock held.  May not sleep.
- */
-static void *nvme_finish_cmd(struct nvme_queue *nvmeq, int tag,
-						nvme_completion_fn *fn)
-{
-	struct nvme_cmd_info *cmd = get_cmd_from_tag(nvmeq, tag);
-	void *ctx;
-	if (tag >= nvmeq->q_depth) {
-		*fn = special_completion;
-		return CMD_CTX_INVALID;
-	}
-	if (fn)
-		*fn = cmd->fn;
-	ctx = cmd->ctx;
-	cmd->fn = special_completion;
-	cmd->ctx = CMD_CTX_COMPLETED;
-	return ctx;
+	/*
+	 * Ensure that the doorbell is updated before reading the event
+	 * index from memory.  The controller needs to provide similar
+	 * ordering to ensure the envent index is updated before reading
+	 * the doorbell.
+	 */
+	mb();
+	if (!nvme_ext_need_event(*event_idx, value, old_value))
+		goto no_doorbell;
+
+ring_doorbell:
+	writel(value, q_db);
+no_doorbell:
+	return;
 }
+#endif
 
 /**
- * nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
+ * __nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
  * @nvmeq: The queue to use
  * @cmd: The command to send
  *
@@ -399,75 +409,60 @@
 	else
 		memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd));
 
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	if (nvmeq->sq_doorbell_addr)
+		wmb();
+#endif
+
 	if (++tail == nvmeq->q_depth)
 		tail = 0;
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	nvme_ext_write_doorbell(tail, nvmeq->q_db,
+		nvmeq->sq_doorbell_addr, nvmeq->sq_eventidx_addr);
+#else
 	writel(tail, nvmeq->q_db);
+#endif
 	nvmeq->sq_tail = tail;
 }
 
-static void nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&nvmeq->q_lock, flags);
-	__nvme_submit_cmd(nvmeq, cmd);
-	spin_unlock_irqrestore(&nvmeq->q_lock, flags);
-}
-
-static __le64 **iod_list(struct nvme_iod *iod)
-{
-	return ((void *)iod) + iod->offset;
-}
-
-static inline void iod_init(struct nvme_iod *iod, unsigned nbytes,
-			    unsigned nseg, unsigned long private)
-{
-	iod->private = private;
-	iod->offset = offsetof(struct nvme_iod, sg[nseg]);
-	iod->npages = -1;
-	iod->length = nbytes;
-	iod->nents = 0;
-}
-
-static struct nvme_iod *
-__nvme_alloc_iod(unsigned nseg, unsigned bytes, struct nvme_dev *dev,
-		 unsigned long priv, gfp_t gfp)
+static __le64 **iod_list(struct request *req)
 {
-	struct nvme_iod *iod = kmalloc(sizeof(struct nvme_iod) +
-				sizeof(__le64 *) * nvme_npages(bytes, dev) +
-				sizeof(struct scatterlist) * nseg, gfp);
-
-	if (iod)
-		iod_init(iod, bytes, nseg, priv);
-
-	return iod;
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	return (__le64 **)(iod->sg + req->nr_phys_segments);
 }
 
-static struct nvme_iod *nvme_alloc_iod(struct request *rq, struct nvme_dev *dev,
-			               gfp_t gfp)
+static int nvme_init_iod(struct request *rq, struct nvme_dev *dev)
 {
-	unsigned size = !(rq->cmd_flags & REQ_DISCARD) ? blk_rq_bytes(rq) :
-                                                sizeof(struct nvme_dsm_range);
-	struct nvme_iod *iod;
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(rq);
+	int nseg = rq->nr_phys_segments;
+	unsigned size;
 
-	if (rq->nr_phys_segments <= NVME_INT_PAGES &&
-	    size <= NVME_INT_BYTES(dev)) {
-		struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(rq);
+	if (rq->cmd_flags & REQ_DISCARD)
+		size = sizeof(struct nvme_dsm_range);
+	else
+		size = blk_rq_bytes(rq);
 
-		iod = cmd->iod;
-		iod_init(iod, size, rq->nr_phys_segments,
-				(unsigned long) rq | NVME_INT_MASK);
-		return iod;
+	if (nseg > NVME_INT_PAGES || size > NVME_INT_BYTES(dev)) {
+		iod->sg = kmalloc(nvme_iod_alloc_size(dev, size, nseg), GFP_ATOMIC);
+		if (!iod->sg)
+			return BLK_MQ_RQ_QUEUE_BUSY;
+	} else {
+		iod->sg = iod->inline_sg;
 	}
 
-	return __nvme_alloc_iod(rq->nr_phys_segments, size, dev,
-				(unsigned long) rq, gfp);
+	iod->aborted = 0;
+	iod->npages = -1;
+	iod->nents = 0;
+	iod->length = size;
+	return 0;
 }
 
-static void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
+static void nvme_free_iod(struct nvme_dev *dev, struct request *req)
 {
-	const int last_prp = dev->page_size / 8 - 1;
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	const int last_prp = dev->ctrl.page_size / 8 - 1;
 	int i;
-	__le64 **list = iod_list(iod);
+	__le64 **list = iod_list(req);
 	dma_addr_t prp_dma = iod->first_dma;
 
 	if (iod->npages == 0)
@@ -479,20 +474,8 @@
 		prp_dma = next_prp_dma;
 	}
 
-	if (iod_should_kfree(iod))
-		kfree(iod);
-}
-
-static int nvme_error_status(u16 status)
-{
-	switch (status & 0x7ff) {
-	case NVME_SC_SUCCESS:
-		return 0;
-	case NVME_SC_CAP_EXCEEDED:
-		return -ENOSPC;
-	default:
-		return -EIO;
-	}
+	if (iod->sg != iod->inline_sg)
+		kfree(iod->sg);
 }
 
 #ifdef CONFIG_BLK_DEV_INTEGRITY
@@ -549,27 +532,6 @@
 	}
 	kunmap_atomic(pmap);
 }
-
-static void nvme_init_integrity(struct nvme_ns *ns)
-{
-	struct blk_integrity integrity;
-
-	switch (ns->pi_type) {
-	case NVME_NS_DPS_PI_TYPE3:
-		integrity.profile = &t10_pi_type3_crc;
-		break;
-	case NVME_NS_DPS_PI_TYPE1:
-	case NVME_NS_DPS_PI_TYPE2:
-		integrity.profile = &t10_pi_type1_crc;
-		break;
-	default:
-		integrity.profile = NULL;
-		break;
-	}
-	integrity.tuple_size = ns->ms;
-	blk_integrity_register(ns->disk, &integrity);
-	blk_queue_max_integrity_segments(ns->queue, 1);
-}
 #else /* CONFIG_BLK_DEV_INTEGRITY */
 static void nvme_dif_remap(struct request *req,
 			void (*dif_swap)(u32 p, u32 v, struct t10_pi_tuple *pi))
@@ -581,91 +543,27 @@
 static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
 {
 }
-static void nvme_init_integrity(struct nvme_ns *ns)
-{
-}
 #endif
 
-static void req_completion(struct nvme_queue *nvmeq, void *ctx,
-						struct nvme_completion *cqe)
-{
-	struct nvme_iod *iod = ctx;
-	struct request *req = iod_get_private(iod);
-	struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req);
-	u16 status = le16_to_cpup(&cqe->status) >> 1;
-	bool requeue = false;
-	int error = 0;
-
-	if (unlikely(status)) {
-		if (!(status & NVME_SC_DNR || blk_noretry_request(req))
-		    && (jiffies - req->start_time) < req->timeout) {
-			unsigned long flags;
-
-			requeue = true;
-			blk_mq_requeue_request(req);
-			spin_lock_irqsave(req->q->queue_lock, flags);
-			if (!blk_queue_stopped(req->q))
-				blk_mq_kick_requeue_list(req->q);
-			spin_unlock_irqrestore(req->q->queue_lock, flags);
-			goto release_iod;
-		}
-
-		if (req->cmd_type == REQ_TYPE_DRV_PRIV) {
-			if (cmd_rq->ctx == CMD_CTX_CANCELLED)
-				error = -EINTR;
-			else
-				error = status;
-		} else {
-			error = nvme_error_status(status);
-		}
-	}
-
-	if (req->cmd_type == REQ_TYPE_DRV_PRIV) {
-		u32 result = le32_to_cpup(&cqe->result);
-		req->special = (void *)(uintptr_t)result;
-	}
-
-	if (cmd_rq->aborted)
-		dev_warn(nvmeq->dev->dev,
-			"completing aborted command with status:%04x\n",
-			error);
-
-release_iod:
-	if (iod->nents) {
-		dma_unmap_sg(nvmeq->dev->dev, iod->sg, iod->nents,
-			rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		if (blk_integrity_rq(req)) {
-			if (!rq_data_dir(req))
-				nvme_dif_remap(req, nvme_dif_complete);
-			dma_unmap_sg(nvmeq->dev->dev, iod->meta_sg, 1,
-				rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		}
-	}
-	nvme_free_iod(nvmeq->dev, iod);
-
-	if (likely(!requeue))
-		blk_mq_complete_request(req, error);
-}
-
-/* length is in bytes.  gfp flags indicates whether we may sleep. */
-static int nvme_setup_prps(struct nvme_dev *dev, struct nvme_iod *iod,
-		int total_len, gfp_t gfp)
+static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req,
+		int total_len)
 {
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 	struct dma_pool *pool;
 	int length = total_len;
 	struct scatterlist *sg = iod->sg;
 	int dma_len = sg_dma_len(sg);
 	u64 dma_addr = sg_dma_address(sg);
-	u32 page_size = dev->page_size;
+	u32 page_size = dev->ctrl.page_size;
 	int offset = dma_addr & (page_size - 1);
 	__le64 *prp_list;
-	__le64 **list = iod_list(iod);
+	__le64 **list = iod_list(req);
 	dma_addr_t prp_dma;
 	int nprps, i;
 
 	length -= (page_size - offset);
 	if (length <= 0)
-		return total_len;
+		return true;
 
 	dma_len -= (page_size - offset);
 	if (dma_len) {
@@ -678,7 +576,7 @@
 
 	if (length <= page_size) {
 		iod->first_dma = dma_addr;
-		return total_len;
+		return true;
 	}
 
 	nprps = DIV_ROUND_UP(length, page_size);
@@ -690,11 +588,11 @@
 		iod->npages = 1;
 	}
 
-	prp_list = dma_pool_alloc(pool, gfp, &prp_dma);
+	prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma);
 	if (!prp_list) {
 		iod->first_dma = dma_addr;
 		iod->npages = -1;
-		return (total_len - length) + page_size;
+		return false;
 	}
 	list[0] = prp_list;
 	iod->first_dma = prp_dma;
@@ -702,9 +600,9 @@
 	for (;;) {
 		if (i == page_size >> 3) {
 			__le64 *old_prp_list = prp_list;
-			prp_list = dma_pool_alloc(pool, gfp, &prp_dma);
+			prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma);
 			if (!prp_list)
-				return total_len - length;
+				return false;
 			list[iod->npages++] = prp_list;
 			prp_list[0] = old_prp_list[i - 1];
 			old_prp_list[i - 1] = cpu_to_le64(prp_dma);
@@ -724,115 +622,106 @@
 		dma_len = sg_dma_len(sg);
 	}
 
-	return total_len;
+	return true;
 }
 
-static void nvme_submit_priv(struct nvme_queue *nvmeq, struct request *req,
-		struct nvme_iod *iod)
+static int nvme_map_data(struct nvme_dev *dev, struct request *req,
+		struct nvme_command *cmnd)
 {
-	struct nvme_command cmnd;
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	struct request_queue *q = req->q;
+	enum dma_data_direction dma_dir = rq_data_dir(req) ?
+			DMA_TO_DEVICE : DMA_FROM_DEVICE;
+	int ret = BLK_MQ_RQ_QUEUE_ERROR;
 
-	memcpy(&cmnd, req->cmd, sizeof(cmnd));
-	cmnd.rw.command_id = req->tag;
-	if (req->nr_phys_segments) {
-		cmnd.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
-		cmnd.rw.prp2 = cpu_to_le64(iod->first_dma);
-	}
+	sg_init_table(iod->sg, req->nr_phys_segments);
+	iod->nents = blk_rq_map_sg(q, req, iod->sg);
+	if (!iod->nents)
+		goto out;
 
-	__nvme_submit_cmd(nvmeq, &cmnd);
-}
+	ret = BLK_MQ_RQ_QUEUE_BUSY;
+	if (!dma_map_sg_attrs(dev->dev, iod->sg, iod->nents, dma_dir,
+				&nvme_dma_attrs))
+		goto out;
 
-/*
- * We reuse the small pool to allocate the 16-byte range here as it is not
- * worth having a special pool for these or additional cases to handle freeing
- * the iod.
- */
-static void nvme_submit_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns,
-		struct request *req, struct nvme_iod *iod)
-{
-	struct nvme_dsm_range *range =
-				(struct nvme_dsm_range *)iod_list(iod)[0];
-	struct nvme_command cmnd;
+	if (!nvme_setup_prps(dev, req, blk_rq_bytes(req)))
+		goto out_unmap;
 
-	range->cattr = cpu_to_le32(0);
-	range->nlb = cpu_to_le32(blk_rq_bytes(req) >> ns->lba_shift);
-	range->slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
+	ret = BLK_MQ_RQ_QUEUE_ERROR;
+	if (blk_integrity_rq(req)) {
+		if (blk_rq_count_integrity_sg(q, req->bio) != 1)
+			goto out_unmap;
 
-	memset(&cmnd, 0, sizeof(cmnd));
-	cmnd.dsm.opcode = nvme_cmd_dsm;
-	cmnd.dsm.command_id = req->tag;
-	cmnd.dsm.nsid = cpu_to_le32(ns->ns_id);
-	cmnd.dsm.prp1 = cpu_to_le64(iod->first_dma);
-	cmnd.dsm.nr = 0;
-	cmnd.dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD);
+		sg_init_table(&iod->meta_sg, 1);
+		if (blk_rq_map_integrity_sg(q, req->bio, &iod->meta_sg) != 1)
+			goto out_unmap;
 
-	__nvme_submit_cmd(nvmeq, &cmnd);
-}
+		if (rq_data_dir(req))
+			nvme_dif_remap(req, nvme_dif_prep);
 
-static void nvme_submit_flush(struct nvme_queue *nvmeq, struct nvme_ns *ns,
-								int cmdid)
-{
-	struct nvme_command cmnd;
+		if (!dma_map_sg(dev->dev, &iod->meta_sg, 1, dma_dir))
+			goto out_unmap;
+	}
 
-	memset(&cmnd, 0, sizeof(cmnd));
-	cmnd.common.opcode = nvme_cmd_flush;
-	cmnd.common.command_id = cmdid;
-	cmnd.common.nsid = cpu_to_le32(ns->ns_id);
+	cmnd->rw.dptr.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
+	cmnd->rw.dptr.prp2 = cpu_to_le64(iod->first_dma);
+	if (blk_integrity_rq(req))
+		cmnd->rw.metadata = cpu_to_le64(sg_dma_address(&iod->meta_sg));
+	return BLK_MQ_RQ_QUEUE_OK;
 
-	__nvme_submit_cmd(nvmeq, &cmnd);
+out_unmap:
+	dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir);
+out:
+	return ret;
 }
 
-static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod,
-							struct nvme_ns *ns)
+static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
 {
-	struct request *req = iod_get_private(iod);
-	struct nvme_command cmnd;
-	u16 control = 0;
-	u32 dsmgmt = 0;
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	enum dma_data_direction dma_dir = rq_data_dir(req) ?
+			DMA_TO_DEVICE : DMA_FROM_DEVICE;
 
-	if (req->cmd_flags & REQ_FUA)
-		control |= NVME_RW_FUA;
-	if (req->cmd_flags & (REQ_FAILFAST_DEV | REQ_RAHEAD))
-		control |= NVME_RW_LR;
-
-	if (req->cmd_flags & REQ_RAHEAD)
-		dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH;
-
-	memset(&cmnd, 0, sizeof(cmnd));
-	cmnd.rw.opcode = (rq_data_dir(req) ? nvme_cmd_write : nvme_cmd_read);
-	cmnd.rw.command_id = req->tag;
-	cmnd.rw.nsid = cpu_to_le32(ns->ns_id);
-	cmnd.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
-	cmnd.rw.prp2 = cpu_to_le64(iod->first_dma);
-	cmnd.rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
-	cmnd.rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
-
-	if (ns->ms) {
-		switch (ns->pi_type) {
-		case NVME_NS_DPS_PI_TYPE3:
-			control |= NVME_RW_PRINFO_PRCHK_GUARD;
-			break;
-		case NVME_NS_DPS_PI_TYPE1:
-		case NVME_NS_DPS_PI_TYPE2:
-			control |= NVME_RW_PRINFO_PRCHK_GUARD |
-					NVME_RW_PRINFO_PRCHK_REF;
-			cmnd.rw.reftag = cpu_to_le32(
-					nvme_block_nr(ns, blk_rq_pos(req)));
-			break;
+	if (iod->nents) {
+		dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir);
+		if (blk_integrity_rq(req)) {
+			if (!rq_data_dir(req))
+				nvme_dif_remap(req, nvme_dif_complete);
+			dma_unmap_sg(dev->dev, &iod->meta_sg, 1, dma_dir);
 		}
-		if (blk_integrity_rq(req))
-			cmnd.rw.metadata =
-				cpu_to_le64(sg_dma_address(iod->meta_sg));
-		else
-			control |= NVME_RW_PRINFO_PRACT;
 	}
 
-	cmnd.rw.control = cpu_to_le16(control);
-	cmnd.rw.dsmgmt = cpu_to_le32(dsmgmt);
+	nvme_free_iod(dev, req);
+}
 
-	__nvme_submit_cmd(nvmeq, &cmnd);
+/*
+ * We reuse the small pool to allocate the 16-byte range here as it is not
+ * worth having a special pool for these or additional cases to handle freeing
+ * the iod.
+ */
+static int nvme_setup_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns,
+		struct request *req, struct nvme_command *cmnd)
+{
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	struct nvme_dsm_range *range;
 
-	return 0;
+	range = dma_pool_alloc(nvmeq->dev->prp_small_pool, GFP_ATOMIC,
+						&iod->first_dma);
+	if (!range)
+		return BLK_MQ_RQ_QUEUE_BUSY;
+	iod_list(req)[0] = (__le64 *)range;
+	iod->npages = 0;
+
+	range->cattr = cpu_to_le32(0);
+	range->nlb = cpu_to_le32(blk_rq_bytes(req) >> ns->lba_shift);
+	range->slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
+
+	memset(cmnd, 0, sizeof(*cmnd));
+	cmnd->dsm.opcode = nvme_cmd_dsm;
+	cmnd->dsm.nsid = cpu_to_le32(ns->ns_id);
+	cmnd->dsm.dptr.prp1 = cpu_to_le64(iod->first_dma);
+	cmnd->dsm.nr = 0;
+	cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD);
+	return BLK_MQ_RQ_QUEUE_OK;
 }
 
 /*
@@ -845,9 +734,8 @@
 	struct nvme_queue *nvmeq = hctx->driver_data;
 	struct nvme_dev *dev = nvmeq->dev;
 	struct request *req = bd->rq;
-	struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(req);
-	struct nvme_iod *iod;
-	enum dma_data_direction dma_dir;
+	struct nvme_command cmnd;
+	int ret = BLK_MQ_RQ_QUEUE_OK;
 
 	/*
 	 * If formated with metadata, require the block layer provide a buffer
@@ -857,91 +745,87 @@
 	if (ns && ns->ms && !blk_integrity_rq(req)) {
 		if (!(ns->pi_type && ns->ms == 8) &&
 					req->cmd_type != REQ_TYPE_DRV_PRIV) {
-			blk_mq_complete_request(req, -EFAULT);
+			blk_mq_end_request(req, -EFAULT);
 			return BLK_MQ_RQ_QUEUE_OK;
 		}
 	}
 
-	iod = nvme_alloc_iod(req, dev, GFP_ATOMIC);
-	if (!iod)
-		return BLK_MQ_RQ_QUEUE_BUSY;
+	ret = nvme_init_iod(req, dev);
+	if (ret)
+		return ret;
 
 	if (req->cmd_flags & REQ_DISCARD) {
-		void *range;
-		/*
-		 * We reuse the small pool to allocate the 16-byte range here
-		 * as it is not worth having a special pool for these or
-		 * additional cases to handle freeing the iod.
-		 */
-		range = dma_pool_alloc(dev->prp_small_pool, GFP_ATOMIC,
-						&iod->first_dma);
-		if (!range)
-			goto retry_cmd;
-		iod_list(iod)[0] = (__le64 *)range;
-		iod->npages = 0;
-	} else if (req->nr_phys_segments) {
-		dma_dir = rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-
-		sg_init_table(iod->sg, req->nr_phys_segments);
-		iod->nents = blk_rq_map_sg(req->q, req, iod->sg);
-		if (!iod->nents)
-			goto error_cmd;
-
-		if (!dma_map_sg(nvmeq->q_dmadev, iod->sg, iod->nents, dma_dir))
-			goto retry_cmd;
-
-		if (blk_rq_bytes(req) !=
-                    nvme_setup_prps(dev, iod, blk_rq_bytes(req), GFP_ATOMIC)) {
-			dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir);
-			goto retry_cmd;
-		}
-		if (blk_integrity_rq(req)) {
-			if (blk_rq_count_integrity_sg(req->q, req->bio) != 1) {
-				dma_unmap_sg(dev->dev, iod->sg, iod->nents,
-						dma_dir);
-				goto error_cmd;
-			}
+		ret = nvme_setup_discard(nvmeq, ns, req, &cmnd);
+	} else {
+		if (req->cmd_type == REQ_TYPE_DRV_PRIV)
+			memcpy(&cmnd, req->cmd, sizeof(cmnd));
+		else if (req->cmd_flags & REQ_FLUSH)
+			nvme_setup_flush(ns, &cmnd);
+		else
+			nvme_setup_rw(ns, req, &cmnd);
 
-			sg_init_table(iod->meta_sg, 1);
-			if (blk_rq_map_integrity_sg(
-					req->q, req->bio, iod->meta_sg) != 1) {
-				dma_unmap_sg(dev->dev, iod->sg, iod->nents,
-						dma_dir);
-				goto error_cmd;
-			}
+		if (req->nr_phys_segments)
+			ret = nvme_map_data(dev, req, &cmnd);
+	}
 
-			if (rq_data_dir(req))
-				nvme_dif_remap(req, nvme_dif_prep);
+	if (ret)
+		goto out;
 
-			if (!dma_map_sg(nvmeq->q_dmadev, iod->meta_sg, 1, dma_dir)) {
-				dma_unmap_sg(dev->dev, iod->sg, iod->nents,
-						dma_dir);
-				goto error_cmd;
-			}
-		}
-	}
+	cmnd.common.command_id = req->tag;
+	blk_mq_start_request(req);
 
-	nvme_set_info(cmd, iod, req_completion);
 	spin_lock_irq(&nvmeq->q_lock);
-	if (req->cmd_type == REQ_TYPE_DRV_PRIV)
-		nvme_submit_priv(nvmeq, req, iod);
-	else if (req->cmd_flags & REQ_DISCARD)
-		nvme_submit_discard(nvmeq, ns, req, iod);
-	else if (req->cmd_flags & REQ_FLUSH)
-		nvme_submit_flush(nvmeq, ns, req->tag);
-	else
-		nvme_submit_iod(nvmeq, iod, ns);
-
+	if (unlikely(nvmeq->cq_vector < 0)) {
+		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
+			ret = BLK_MQ_RQ_QUEUE_BUSY;
+		else
+			ret = BLK_MQ_RQ_QUEUE_ERROR;
+		spin_unlock_irq(&nvmeq->q_lock);
+		goto out;
+	}
+	__nvme_submit_cmd(nvmeq, &cmnd);
 	nvme_process_cq(nvmeq);
 	spin_unlock_irq(&nvmeq->q_lock);
 	return BLK_MQ_RQ_QUEUE_OK;
+out:
+	nvme_free_iod(dev, req);
+	return ret;
+}
+
+static void nvme_complete_rq(struct request *req)
+{
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	struct nvme_dev *dev = iod->nvmeq->dev;
+	int error = 0;
+
+	nvme_unmap_data(dev, req);
+
+	if (unlikely(req->errors)) {
+		if (nvme_req_needs_retry(req, req->errors)) {
+			nvme_requeue_req(req);
+			return;
+		}
+
+		if (req->cmd_type == REQ_TYPE_DRV_PRIV)
+			error = req->errors;
+		else
+			error = nvme_error_status(req->errors);
+	}
+
+	if (unlikely(iod->aborted)) {
+		dev_warn(dev->dev,
+			"completing aborted command with status: %04x\n",
+			req->errors);
+	}
+
+	blk_mq_end_request(req, error);
+}
 
- error_cmd:
-	nvme_free_iod(dev, iod);
-	return BLK_MQ_RQ_QUEUE_ERROR;
- retry_cmd:
-	nvme_free_iod(dev, iod);
-	return BLK_MQ_RQ_QUEUE_BUSY;
+/* We read the CQE phase first to check if the rest of the entry is valid */
+static inline bool nvme_cqe_valid(struct nvme_queue *nvmeq, u16 head,
+		u16 phase)
+{
+	return (le16_to_cpu(nvmeq->cqes[head].status) & 1) == phase;
 }
 
 static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag)
@@ -951,21 +835,49 @@
 	head = nvmeq->cq_head;
 	phase = nvmeq->cq_phase;
 
-	for (;;) {
-		void *ctx;
-		nvme_completion_fn fn;
+	while (nvme_cqe_valid(nvmeq, head, phase)) {
 		struct nvme_completion cqe = nvmeq->cqes[head];
-		if ((le16_to_cpu(cqe.status) & 1) != phase)
-			break;
+		struct request *req;
+
 		nvmeq->sq_head = le16_to_cpu(cqe.sq_head);
+
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+		if (to_pci_dev(nvmeq->dev->dev)->vendor == PCI_VENDOR_ID_GOOGLE)
+			rmb();
+#endif
+
 		if (++head == nvmeq->q_depth) {
 			head = 0;
 			phase = !phase;
 		}
+
 		if (tag && *tag == cqe.command_id)
 			*tag = -1;
-		ctx = nvme_finish_cmd(nvmeq, cqe.command_id, &fn);
-		fn(nvmeq, ctx, &cqe);
+
+		if (unlikely(cqe.command_id >= nvmeq->q_depth)) {
+			dev_warn(nvmeq->q_dmadev,
+				"invalid id %d completed on queue %d\n",
+				cqe.command_id, le16_to_cpu(cqe.sq_id));
+			continue;
+		}
+
+		/*
+		 * AEN requests are special as they don't time out and can
+		 * survive any kind of queue freeze and often don't respond to
+		 * aborts.  We don't even bother to allocate a struct request
+		 * for them but rather special case them here.
+		 */
+		if (unlikely(nvmeq->qid == 0 &&
+				cqe.command_id >= NVME_AQ_BLKMQ_DEPTH)) {
+			nvme_complete_async_event(nvmeq->dev, &cqe);
+			continue;
+		}
+
+		req = blk_mq_tag_to_rq(*nvmeq->tags, cqe.command_id);
+		if (req->cmd_type == REQ_TYPE_DRV_PRIV && req->special)
+			memcpy(req->special, &cqe, sizeof(cqe));
+		blk_mq_complete_request(req, le16_to_cpu(cqe.status) >> 1);
+
 	}
 
 	/* If the controller ignores the cq head doorbell and continuously
@@ -978,7 +890,14 @@
 		return;
 
 	if (likely(nvmeq->cq_vector >= 0))
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+		nvme_ext_write_doorbell(head,
+			nvmeq->q_db + nvmeq->dev->db_stride,
+			nvmeq->cq_doorbell_addr,
+			nvmeq->cq_eventidx_addr);
+#else
 		writel(head, nvmeq->q_db + nvmeq->dev->db_stride);
+#endif
 	nvmeq->cq_head = head;
 	nvmeq->cq_phase = phase;
 
@@ -1005,18 +924,14 @@
 static irqreturn_t nvme_irq_check(int irq, void *data)
 {
 	struct nvme_queue *nvmeq = data;
-	struct nvme_completion cqe = nvmeq->cqes[nvmeq->cq_head];
-	if ((le16_to_cpu(cqe.status) & 1) != nvmeq->cq_phase)
-		return IRQ_NONE;
-	return IRQ_WAKE_THREAD;
+	if (nvme_cqe_valid(nvmeq, nvmeq->cq_head, nvmeq->cq_phase))
+		return IRQ_WAKE_THREAD;
+	return IRQ_NONE;
 }
 
-static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
+static int __nvme_poll(struct nvme_queue *nvmeq, unsigned int tag)
 {
-	struct nvme_queue *nvmeq = hctx->driver_data;
-
-	if ((le16_to_cpu(nvmeq->cqes[nvmeq->cq_head].status) & 1) ==
-	    nvmeq->cq_phase) {
+	if (nvme_cqe_valid(nvmeq, nvmeq->cq_head, nvmeq->cq_phase)) {
 		spin_lock_irq(&nvmeq->q_lock);
 		__nvme_process_cq(nvmeq, &tag);
 		spin_unlock_irq(&nvmeq->q_lock);
@@ -1028,111 +943,29 @@
 	return 0;
 }
 
-/*
- * Returns 0 on success.  If the result is negative, it's a Linux error code;
- * if the result is positive, it's an NVM Express status code
- */
-int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
-		void *buffer, void __user *ubuffer, unsigned bufflen,
-		u32 *result, unsigned timeout)
+static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
 {
-	bool write = cmd->common.opcode & 1;
-	struct bio *bio = NULL;
-	struct request *req;
-	int ret;
+	struct nvme_queue *nvmeq = hctx->driver_data;
 
-	req = blk_mq_alloc_request(q, write, GFP_KERNEL, false);
-	if (IS_ERR(req))
-		return PTR_ERR(req);
+	return __nvme_poll(nvmeq, tag);
+}
 
-	req->cmd_type = REQ_TYPE_DRV_PRIV;
-	req->cmd_flags |= REQ_FAILFAST_DRIVER;
-	req->__data_len = 0;
-	req->__sector = (sector_t) -1;
-	req->bio = req->biotail = NULL;
-
-	req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
-
-	req->cmd = (unsigned char *)cmd;
-	req->cmd_len = sizeof(struct nvme_command);
-	req->special = (void *)0;
-
-	if (buffer && bufflen) {
-		ret = blk_rq_map_kern(q, req, buffer, bufflen,
-				      __GFP_DIRECT_RECLAIM);
-		if (ret)
-			goto out;
-	} else if (ubuffer && bufflen) {
-		ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen,
-				      __GFP_DIRECT_RECLAIM);
-		if (ret)
-			goto out;
-		bio = req->bio;
-	}
-
-	blk_execute_rq(req->q, NULL, req, 0);
-	if (bio)
-		blk_rq_unmap_user(bio);
-	if (result)
-		*result = (u32)(uintptr_t)req->special;
-	ret = req->errors;
- out:
-	blk_mq_free_request(req);
-	return ret;
-}
-
-int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
-		void *buffer, unsigned bufflen)
-{
-	return __nvme_submit_sync_cmd(q, cmd, buffer, NULL, bufflen, NULL, 0);
-}
-
-static int nvme_submit_async_admin_req(struct nvme_dev *dev)
+static void nvme_async_event_work(struct work_struct *work)
 {
+	struct nvme_dev *dev = container_of(work, struct nvme_dev, async_work);
 	struct nvme_queue *nvmeq = dev->queues[0];
 	struct nvme_command c;
-	struct nvme_cmd_info *cmd_info;
-	struct request *req;
-
-	req = blk_mq_alloc_request(dev->admin_q, WRITE, GFP_ATOMIC, true);
-	if (IS_ERR(req))
-		return PTR_ERR(req);
-
-	req->cmd_flags |= REQ_NO_TIMEOUT;
-	cmd_info = blk_mq_rq_to_pdu(req);
-	nvme_set_info(cmd_info, NULL, async_req_completion);
 
 	memset(&c, 0, sizeof(c));
 	c.common.opcode = nvme_admin_async_event;
-	c.common.command_id = req->tag;
-
-	blk_mq_free_request(req);
-	__nvme_submit_cmd(nvmeq, &c);
-	return 0;
-}
-
-static int nvme_submit_admin_async_cmd(struct nvme_dev *dev,
-			struct nvme_command *cmd,
-			struct async_cmd_info *cmdinfo, unsigned timeout)
-{
-	struct nvme_queue *nvmeq = dev->queues[0];
-	struct request *req;
-	struct nvme_cmd_info *cmd_rq;
-
-	req = blk_mq_alloc_request(dev->admin_q, WRITE, GFP_KERNEL, false);
-	if (IS_ERR(req))
-		return PTR_ERR(req);
-
-	req->timeout = timeout;
-	cmd_rq = blk_mq_rq_to_pdu(req);
-	cmdinfo->req = req;
-	nvme_set_info(cmd_rq, cmdinfo, async_completion);
-	cmdinfo->status = -EINTR;
 
-	cmd->common.command_id = req->tag;
-
-	nvme_submit_cmd(nvmeq, cmd);
-	return 0;
+	spin_lock_irq(&nvmeq->q_lock);
+	while (dev->ctrl.event_limit > 0) {
+		c.common.command_id = NVME_AQ_BLKMQ_DEPTH +
+			--dev->ctrl.event_limit;
+		__nvme_submit_cmd(nvmeq, &c);
+	}
+	spin_unlock_irq(&nvmeq->q_lock);
 }
 
 static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id)
@@ -1143,7 +976,7 @@
 	c.delete_queue.opcode = opcode;
 	c.delete_queue.qid = cpu_to_le16(id);
 
-	return nvme_submit_sync_cmd(dev->admin_q, &c, NULL, 0);
+	return nvme_submit_sync_cmd(dev->ctrl.admin_q, &c, NULL, 0);
 }
 
 static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid,
@@ -1164,7 +997,7 @@
 	c.create_cq.cq_flags = cpu_to_le16(flags);
 	c.create_cq.irq_vector = cpu_to_le16(nvmeq->cq_vector);
 
-	return nvme_submit_sync_cmd(dev->admin_q, &c, NULL, 0);
+	return nvme_submit_sync_cmd(dev->ctrl.admin_q, &c, NULL, 0);
 }
 
 static int adapter_alloc_sq(struct nvme_dev *dev, u16 qid,
@@ -1185,7 +1018,7 @@
 	c.create_sq.sq_flags = cpu_to_le16(flags);
 	c.create_sq.cqid = cpu_to_le16(qid);
 
-	return nvme_submit_sync_cmd(dev->admin_q, &c, NULL, 0);
+	return nvme_submit_sync_cmd(dev->ctrl.admin_q, &c, NULL, 0);
 }
 
 static int adapter_delete_cq(struct nvme_dev *dev, u16 cqid)
@@ -1198,195 +1031,119 @@
 	return adapter_delete_queue(dev, nvme_admin_delete_sq, sqid);
 }
 
-int nvme_identify_ctrl(struct nvme_dev *dev, struct nvme_id_ctrl **id)
-{
-	struct nvme_command c = { };
-	int error;
-
-	/* gcc-4.4.4 (at least) has issues with initializers and anon unions */
-	c.identify.opcode = nvme_admin_identify;
-	c.identify.cns = cpu_to_le32(1);
-
-	*id = kmalloc(sizeof(struct nvme_id_ctrl), GFP_KERNEL);
-	if (!*id)
-		return -ENOMEM;
-
-	error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
-			sizeof(struct nvme_id_ctrl));
-	if (error)
-		kfree(*id);
-	return error;
-}
-
-int nvme_identify_ns(struct nvme_dev *dev, unsigned nsid,
-		struct nvme_id_ns **id)
-{
-	struct nvme_command c = { };
-	int error;
-
-	/* gcc-4.4.4 (at least) has issues with initializers and anon unions */
-	c.identify.opcode = nvme_admin_identify,
-	c.identify.nsid = cpu_to_le32(nsid),
-
-	*id = kmalloc(sizeof(struct nvme_id_ns), GFP_KERNEL);
-	if (!*id)
-		return -ENOMEM;
-
-	error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
-			sizeof(struct nvme_id_ns));
-	if (error)
-		kfree(*id);
-	return error;
-}
-
-int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
-					dma_addr_t dma_addr, u32 *result)
-{
-	struct nvme_command c;
-
-	memset(&c, 0, sizeof(c));
-	c.features.opcode = nvme_admin_get_features;
-	c.features.nsid = cpu_to_le32(nsid);
-	c.features.prp1 = cpu_to_le64(dma_addr);
-	c.features.fid = cpu_to_le32(fid);
-
-	return __nvme_submit_sync_cmd(dev->admin_q, &c, NULL, NULL, 0,
-			result, 0);
-}
-
-int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
-					dma_addr_t dma_addr, u32 *result)
-{
-	struct nvme_command c;
-
-	memset(&c, 0, sizeof(c));
-	c.features.opcode = nvme_admin_set_features;
-	c.features.prp1 = cpu_to_le64(dma_addr);
-	c.features.fid = cpu_to_le32(fid);
-	c.features.dword11 = cpu_to_le32(dword11);
-
-	return __nvme_submit_sync_cmd(dev->admin_q, &c, NULL, NULL, 0,
-			result, 0);
-}
-
-int nvme_get_log_page(struct nvme_dev *dev, struct nvme_smart_log **log)
+static void abort_endio(struct request *req, int error)
 {
-	struct nvme_command c = { };
-	int error;
-
-	c.common.opcode = nvme_admin_get_log_page,
-	c.common.nsid = cpu_to_le32(0xFFFFFFFF),
-	c.common.cdw10[0] = cpu_to_le32(
-			(((sizeof(struct nvme_smart_log) / 4) - 1) << 16) |
-			 NVME_LOG_SMART),
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	struct nvme_queue *nvmeq = iod->nvmeq;
+	u16 status = req->errors;
 
-	*log = kmalloc(sizeof(struct nvme_smart_log), GFP_KERNEL);
-	if (!*log)
-		return -ENOMEM;
-
-	error = nvme_submit_sync_cmd(dev->admin_q, &c, *log,
-			sizeof(struct nvme_smart_log));
-	if (error)
-		kfree(*log);
-	return error;
+	dev_warn(nvmeq->dev->ctrl.device, "Abort status: 0x%x", status);
+	atomic_inc(&nvmeq->dev->ctrl.abort_limit);
+	blk_mq_free_request(req);
 }
 
-/**
- * nvme_abort_req - Attempt aborting a request
- *
- * Schedule controller reset if the command was already aborted once before and
- * still hasn't been returned to the driver, or if this is the admin queue.
- */
-static void nvme_abort_req(struct request *req)
+static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
 {
-	struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req);
-	struct nvme_queue *nvmeq = cmd_rq->nvmeq;
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	struct nvme_queue *nvmeq = iod->nvmeq;
 	struct nvme_dev *dev = nvmeq->dev;
 	struct request *abort_req;
-	struct nvme_cmd_info *abort_cmd;
 	struct nvme_command cmd;
 
-	if (!nvmeq->qid || cmd_rq->aborted) {
-		spin_lock(&dev_list_lock);
-		if (!__nvme_reset(dev)) {
-			dev_warn(dev->dev,
-				 "I/O %d QID %d timeout, reset controller\n",
-				 req->tag, nvmeq->qid);
-		}
-		spin_unlock(&dev_list_lock);
-		return;
+	/*
+	* Did we miss an interrupt?
+	*/
+	if (__nvme_poll(nvmeq, req->tag)) {
+		dev_warn(dev->dev,
+			"I/O %d QID %d timeout, completion polled\n",
+			req->tag, nvmeq->qid);
+		return BLK_EH_HANDLED;
 	}
 
-	if (!dev->abort_limit)
-		return;
+	/*
+	 * Shutdown immediately if controller times out while starting. The
+	 * reset work will see the pci device disabled when it gets the forced
+	 * cancellation error. All outstanding requests are completed on
+	 * shutdown, so we return BLK_EH_HANDLED.
+	 */
+	if (test_bit(NVME_CTRL_RESETTING, &dev->flags)) {
+		dev_warn(dev->dev,
+			 "I/O %d QID %d timeout, disable controller\n",
+			 req->tag, nvmeq->qid);
+		nvme_dev_disable(dev, false);
+		req->errors = NVME_SC_CANCELLED;
+		return BLK_EH_HANDLED;
+	}
 
-	abort_req = blk_mq_alloc_request(dev->admin_q, WRITE, GFP_ATOMIC,
-									false);
-	if (IS_ERR(abort_req))
-		return;
+	/*
+ 	 * Shutdown the controller immediately and schedule a reset if the
+ 	 * command was already aborted once before and still hasn't been
+ 	 * returned to the driver, or if this is the admin queue.
+	 */
+	if (!nvmeq->qid || iod->aborted) {
+		dev_warn(dev->dev,
+			 "I/O %d QID %d timeout, reset controller\n",
+			 req->tag, nvmeq->qid);
+		nvme_dev_disable(dev, false);
+		queue_work(nvme_workq, &dev->reset_work);
+
+		/*
+		 * Mark the request as handled, since the inline shutdown
+		 * forces all outstanding requests to complete.
+		 */
+		req->errors = NVME_SC_CANCELLED;
+		return BLK_EH_HANDLED;
+	}
+
+	iod->aborted = 1;
 
-	abort_cmd = blk_mq_rq_to_pdu(abort_req);
-	nvme_set_info(abort_cmd, abort_req, abort_completion);
+	if (atomic_dec_return(&dev->ctrl.abort_limit) < 0) {
+		atomic_inc(&dev->ctrl.abort_limit);
+		return BLK_EH_RESET_TIMER;
+	}
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.abort.opcode = nvme_admin_abort_cmd;
 	cmd.abort.cid = req->tag;
 	cmd.abort.sqid = cpu_to_le16(nvmeq->qid);
-	cmd.abort.command_id = abort_req->tag;
 
-	--dev->abort_limit;
-	cmd_rq->aborted = 1;
+	dev_warn(nvmeq->q_dmadev, "I/O %d QID %d timeout, aborting\n",
+				 req->tag, nvmeq->qid);
+
+	abort_req = nvme_alloc_request(dev->ctrl.admin_q, &cmd,
+			BLK_MQ_REQ_NOWAIT, NVME_QID_ANY);
+	if (IS_ERR(abort_req)) {
+		atomic_inc(&dev->ctrl.abort_limit);
+		return BLK_EH_RESET_TIMER;
+	}
+
+	abort_req->timeout = ADMIN_TIMEOUT;
+	abort_req->end_io_data = NULL;
+	blk_execute_rq_nowait(abort_req->q, NULL, abort_req, 0, abort_endio);
 
-	dev_warn(nvmeq->q_dmadev, "Aborting I/O %d QID %d\n", req->tag,
-							nvmeq->qid);
-	nvme_submit_cmd(dev->queues[0], &cmd);
+	/*
+	 * The aborted req will be completed on receiving the abort req.
+	 * We enable the timer again. If hit twice, it'll cause a device reset,
+	 * as the device then is in a faulty state.
+	 */
+	return BLK_EH_RESET_TIMER;
 }
 
 static void nvme_cancel_queue_ios(struct request *req, void *data, bool reserved)
 {
 	struct nvme_queue *nvmeq = data;
-	void *ctx;
-	nvme_completion_fn fn;
-	struct nvme_cmd_info *cmd;
-	struct nvme_completion cqe;
+	int status;
 
 	if (!blk_mq_request_started(req))
 		return;
 
-	cmd = blk_mq_rq_to_pdu(req);
-
-	if (cmd->ctx == CMD_CTX_CANCELLED)
-		return;
+	dev_warn(nvmeq->q_dmadev,
+		 "Cancelling I/O %d QID %d\n", req->tag, nvmeq->qid);
 
+	status = NVME_SC_ABORT_REQ;
 	if (blk_queue_dying(req->q))
-		cqe.status = cpu_to_le16((NVME_SC_ABORT_REQ | NVME_SC_DNR) << 1);
-	else
-		cqe.status = cpu_to_le16(NVME_SC_ABORT_REQ << 1);
-
-
-	dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d QID %d\n",
-						req->tag, nvmeq->qid);
-	ctx = cancel_cmd_info(cmd, &fn);
-	fn(nvmeq, ctx, &cqe);
-}
-
-static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
-{
-	struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(req);
-	struct nvme_queue *nvmeq = cmd->nvmeq;
-
-	dev_warn(nvmeq->q_dmadev, "Timeout I/O %d QID %d\n", req->tag,
-							nvmeq->qid);
-	spin_lock_irq(&nvmeq->q_lock);
-	nvme_abort_req(req);
-	spin_unlock_irq(&nvmeq->q_lock);
-
-	/*
-	 * The aborted req will be completed on receiving the abort req.
-	 * We enable the timer again. If hit twice, it'll cause a device reset,
-	 * as the device then is in a faulty state.
-	 */
-	return BLK_EH_RESET_TIMER;
+		status |= NVME_SC_DNR;
+	blk_mq_complete_request(req, status);
 }
 
 static void nvme_free_queue(struct nvme_queue *nvmeq)
@@ -1429,8 +1186,8 @@
 	nvmeq->cq_vector = -1;
 	spin_unlock_irq(&nvmeq->q_lock);
 
-	if (!nvmeq->qid && nvmeq->dev->admin_q)
-		blk_mq_freeze_queue_start(nvmeq->dev->admin_q);
+	if (!nvmeq->qid && nvmeq->dev->ctrl.admin_q)
+		blk_mq_stop_hw_queues(nvmeq->dev->ctrl.admin_q);
 
 	irq_set_affinity_hint(vector, NULL);
 	free_irq(vector, nvmeq);
@@ -1446,21 +1203,20 @@
 	spin_unlock_irq(&nvmeq->q_lock);
 }
 
-static void nvme_disable_queue(struct nvme_dev *dev, int qid)
+static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown)
 {
-	struct nvme_queue *nvmeq = dev->queues[qid];
+	struct nvme_queue *nvmeq = dev->queues[0];
 
 	if (!nvmeq)
 		return;
 	if (nvme_suspend_queue(nvmeq))
 		return;
 
-	/* Don't tell the adapter to delete the admin queue.
-	 * Don't tell a removed adapter to delete IO queues. */
-	if (qid && readl(&dev->bar->csts) != -1) {
-		adapter_delete_sq(dev, qid);
-		adapter_delete_cq(dev, qid);
-	}
+	if (shutdown)
+		nvme_shutdown_ctrl(&dev->ctrl);
+	else
+		nvme_disable_ctrl(&dev->ctrl, lo_hi_readq(
+						dev->bar + NVME_REG_CAP));
 
 	spin_lock_irq(&nvmeq->q_lock);
 	nvme_process_cq(nvmeq);
@@ -1471,11 +1227,12 @@
 				int entry_size)
 {
 	int q_depth = dev->q_depth;
-	unsigned q_size_aligned = roundup(q_depth * entry_size, dev->page_size);
+	unsigned q_size_aligned = roundup(q_depth * entry_size,
+					  dev->ctrl.page_size);
 
 	if (q_size_aligned * nr_io_queues > dev->cmb_size) {
 		u64 mem_per_q = div_u64(dev->cmb_size, nr_io_queues);
-		mem_per_q = round_down(mem_per_q, dev->page_size);
+		mem_per_q = round_down(mem_per_q, dev->ctrl.page_size);
 		q_depth = div_u64(mem_per_q, entry_size);
 
 		/*
@@ -1494,8 +1251,8 @@
 				int qid, int depth)
 {
 	if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev->cmbsz)) {
-		unsigned offset = (qid - 1) *
-					roundup(SQ_SIZE(depth), dev->page_size);
+		unsigned offset = (qid - 1) * roundup(SQ_SIZE(depth),
+						      dev->ctrl.page_size);
 		nvmeq->sq_dma_addr = dev->cmb_dma_addr + offset;
 		nvmeq->sq_cmds_io = dev->cmb + offset;
 	} else {
@@ -1526,7 +1283,7 @@
 	nvmeq->q_dmadev = dev->dev;
 	nvmeq->dev = dev;
 	snprintf(nvmeq->irqname, sizeof(nvmeq->irqname), "nvme%dq%d",
-			dev->instance, qid);
+			dev->ctrl.instance, qid);
 	spin_lock_init(&nvmeq->q_lock);
 	nvmeq->cq_head = 0;
 	nvmeq->cq_phase = 1;
@@ -1535,11 +1292,19 @@
 	nvmeq->qid = qid;
 	nvmeq->cq_vector = -1;
 	dev->queues[qid] = nvmeq;
-
-	/* make sure queue descriptor is set before queue count, for kthread */
-	mb();
 	dev->queue_count++;
 
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	if (dev->db_mem && dev->ei_mem && qid != 0) {
+		nvmeq->sq_doorbell_addr = &dev->db_mem[qid * 2 * dev->db_stride];
+		nvmeq->cq_doorbell_addr =
+			&dev->db_mem[(qid * 2 + 1) * dev->db_stride];
+		nvmeq->sq_eventidx_addr = &dev->ei_mem[qid * 2 * dev->db_stride];
+		nvmeq->cq_eventidx_addr =
+			&dev->ei_mem[(qid * 2 + 1) * dev->db_stride];
+	}
+#endif
+
 	return nvmeq;
 
  free_cqdma:
@@ -1570,6 +1335,16 @@
 	nvmeq->cq_head = 0;
 	nvmeq->cq_phase = 1;
 	nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride];
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	if (to_pci_dev(dev->dev)->vendor == PCI_VENDOR_ID_GOOGLE && qid != 0) {
+		nvmeq->sq_doorbell_addr = &dev->db_mem[qid * 2 * dev->db_stride];
+		nvmeq->cq_doorbell_addr =
+			&dev->db_mem[(qid * 2 + 1) * dev->db_stride];
+		nvmeq->sq_eventidx_addr = &dev->ei_mem[qid * 2 * dev->db_stride];
+		nvmeq->cq_eventidx_addr =
+			&dev->ei_mem[(qid * 2 + 1) * dev->db_stride];
+	}
+#endif
 	memset((void *)nvmeq->cqes, 0, CQ_SIZE(nvmeq->q_depth));
 	dev->online_queues++;
 	spin_unlock_irq(&nvmeq->q_lock);
@@ -1583,99 +1358,32 @@
 	nvmeq->cq_vector = qid - 1;
 	result = adapter_alloc_cq(dev, qid, nvmeq);
 	if (result < 0)
-		return result;
+		goto release_vector;
 
 	result = adapter_alloc_sq(dev, qid, nvmeq);
 	if (result < 0)
 		goto release_cq;
 
+	nvme_init_queue(nvmeq, qid);
 	result = queue_request_irq(dev, nvmeq, nvmeq->irqname);
 	if (result < 0)
 		goto release_sq;
 
-	nvme_init_queue(nvmeq, qid);
 	return result;
 
  release_sq:
+	dev->online_queues--;
 	adapter_delete_sq(dev, qid);
  release_cq:
 	adapter_delete_cq(dev, qid);
+ release_vector:
+	nvmeq->cq_vector = -1;
 	return result;
 }
 
-static int nvme_wait_ready(struct nvme_dev *dev, u64 cap, bool enabled)
-{
-	unsigned long timeout;
-	u32 bit = enabled ? NVME_CSTS_RDY : 0;
-
-	timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies;
-
-	while ((readl(&dev->bar->csts) & NVME_CSTS_RDY) != bit) {
-		msleep(100);
-		if (fatal_signal_pending(current))
-			return -EINTR;
-		if (time_after(jiffies, timeout)) {
-			dev_err(dev->dev,
-				"Device not ready; aborting %s\n", enabled ?
-						"initialisation" : "reset");
-			return -ENODEV;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * If the device has been passed off to us in an enabled state, just clear
- * the enabled bit.  The spec says we should set the 'shutdown notification
- * bits', but doing so may cause the device to complete commands to the
- * admin queue ... and we don't know what memory that might be pointing at!
- */
-static int nvme_disable_ctrl(struct nvme_dev *dev, u64 cap)
-{
-	dev->ctrl_config &= ~NVME_CC_SHN_MASK;
-	dev->ctrl_config &= ~NVME_CC_ENABLE;
-	writel(dev->ctrl_config, &dev->bar->cc);
-
-	return nvme_wait_ready(dev, cap, false);
-}
-
-static int nvme_enable_ctrl(struct nvme_dev *dev, u64 cap)
-{
-	dev->ctrl_config &= ~NVME_CC_SHN_MASK;
-	dev->ctrl_config |= NVME_CC_ENABLE;
-	writel(dev->ctrl_config, &dev->bar->cc);
-
-	return nvme_wait_ready(dev, cap, true);
-}
-
-static int nvme_shutdown_ctrl(struct nvme_dev *dev)
-{
-	unsigned long timeout;
-
-	dev->ctrl_config &= ~NVME_CC_SHN_MASK;
-	dev->ctrl_config |= NVME_CC_SHN_NORMAL;
-
-	writel(dev->ctrl_config, &dev->bar->cc);
-
-	timeout = SHUTDOWN_TIMEOUT + jiffies;
-	while ((readl(&dev->bar->csts) & NVME_CSTS_SHST_MASK) !=
-							NVME_CSTS_SHST_CMPLT) {
-		msleep(100);
-		if (fatal_signal_pending(current))
-			return -EINTR;
-		if (time_after(jiffies, timeout)) {
-			dev_err(dev->dev,
-				"Device shutdown incomplete; abort shutdown\n");
-			return -ENODEV;
-		}
-	}
-
-	return 0;
-}
-
 static struct blk_mq_ops nvme_mq_admin_ops = {
 	.queue_rq	= nvme_queue_rq,
+	.complete	= nvme_complete_rq,
 	.map_queue	= blk_mq_map_queue,
 	.init_hctx	= nvme_admin_init_hctx,
 	.exit_hctx      = nvme_admin_exit_hctx,
@@ -1685,6 +1393,7 @@
 
 static struct blk_mq_ops nvme_mq_ops = {
 	.queue_rq	= nvme_queue_rq,
+	.complete	= nvme_complete_rq,
 	.map_queue	= blk_mq_map_queue,
 	.init_hctx	= nvme_init_hctx,
 	.init_request	= nvme_init_request,
@@ -1694,19 +1403,29 @@
 
 static void nvme_dev_remove_admin(struct nvme_dev *dev)
 {
-	if (dev->admin_q && !blk_queue_dying(dev->admin_q)) {
-		blk_cleanup_queue(dev->admin_q);
+	if (dev->ctrl.admin_q && !blk_queue_dying(dev->ctrl.admin_q)) {
+		/*
+		 * If the controller was reset during removal, it's possible
+		 * user requests may be waiting on a stopped queue. Start the
+		 * queue to flush these to completion.
+		 */
+		blk_mq_start_stopped_hw_queues(dev->ctrl.admin_q, true);
+		blk_cleanup_queue(dev->ctrl.admin_q);
 		blk_mq_free_tag_set(&dev->admin_tagset);
 	}
 }
 
 static int nvme_alloc_admin_tags(struct nvme_dev *dev)
 {
-	if (!dev->admin_q) {
+	if (!dev->ctrl.admin_q) {
 		dev->admin_tagset.ops = &nvme_mq_admin_ops;
 		dev->admin_tagset.nr_hw_queues = 1;
-		dev->admin_tagset.queue_depth = NVME_AQ_DEPTH - 1;
-		dev->admin_tagset.reserved_tags = 1;
+
+		/*
+		 * Subtract one to leave an empty queue entry for 'Full Queue'
+		 * condition. See NVM-Express 1.2 specification, section 4.1.2.
+		 */
+		dev->admin_tagset.queue_depth = NVME_AQ_BLKMQ_DEPTH - 1;
 		dev->admin_tagset.timeout = ADMIN_TIMEOUT;
 		dev->admin_tagset.numa_node = dev_to_node(dev->dev);
 		dev->admin_tagset.cmd_size = nvme_cmd_size(dev);
@@ -1715,18 +1434,18 @@
 		if (blk_mq_alloc_tag_set(&dev->admin_tagset))
 			return -ENOMEM;
 
-		dev->admin_q = blk_mq_init_queue(&dev->admin_tagset);
-		if (IS_ERR(dev->admin_q)) {
+		dev->ctrl.admin_q = blk_mq_init_queue(&dev->admin_tagset);
+		if (IS_ERR(dev->ctrl.admin_q)) {
 			blk_mq_free_tag_set(&dev->admin_tagset);
 			return -ENOMEM;
 		}
-		if (!blk_get_queue(dev->admin_q)) {
+		if (!blk_get_queue(dev->ctrl.admin_q)) {
 			nvme_dev_remove_admin(dev);
-			dev->admin_q = NULL;
+			dev->ctrl.admin_q = NULL;
 			return -ENODEV;
 		}
 	} else
-		blk_mq_unfreeze_queue(dev->admin_q);
+		blk_mq_start_stopped_hw_queues(dev->ctrl.admin_q, true);
 
 	return 0;
 }
@@ -1735,31 +1454,17 @@
 {
 	int result;
 	u32 aqa;
-	u64 cap = lo_hi_readq(&dev->bar->cap);
+	u64 cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
 	struct nvme_queue *nvmeq;
-	/*
-	 * default to a 4K page size, with the intention to update this
-	 * path in the future to accomodate architectures with differing
-	 * kernel and IO page sizes.
-	 */
-	unsigned page_shift = 12;
-	unsigned dev_page_min = NVME_CAP_MPSMIN(cap) + 12;
-
-	if (page_shift < dev_page_min) {
-		dev_err(dev->dev,
-				"Minimum device page size (%u) too large for "
-				"host (%u)\n", 1 << dev_page_min,
-				1 << page_shift);
-		return -ENODEV;
-	}
 
-	dev->subsystem = readl(&dev->bar->vs) >= NVME_VS(1, 1) ?
+	dev->subsystem = readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 1) ?
 						NVME_CAP_NSSRC(cap) : 0;
 
-	if (dev->subsystem && (readl(&dev->bar->csts) & NVME_CSTS_NSSRO))
-		writel(NVME_CSTS_NSSRO, &dev->bar->csts);
+	if (dev->subsystem &&
+	    (readl(dev->bar + NVME_REG_CSTS) & NVME_CSTS_NSSRO))
+		writel(NVME_CSTS_NSSRO, dev->bar + NVME_REG_CSTS);
 
-	result = nvme_disable_ctrl(dev, cap);
+	result = nvme_disable_ctrl(&dev->ctrl, cap);
 	if (result < 0)
 		return result;
 
@@ -1773,22 +1478,16 @@
 	aqa = nvmeq->q_depth - 1;
 	aqa |= aqa << 16;
 
-	dev->page_size = 1 << page_shift;
+	writel(aqa, dev->bar + NVME_REG_AQA);
+	lo_hi_writeq(nvmeq->sq_dma_addr, dev->bar + NVME_REG_ASQ);
+	lo_hi_writeq(nvmeq->cq_dma_addr, dev->bar + NVME_REG_ACQ);
 
-	dev->ctrl_config = NVME_CC_CSS_NVM;
-	dev->ctrl_config |= (page_shift - 12) << NVME_CC_MPS_SHIFT;
-	dev->ctrl_config |= NVME_CC_ARB_RR | NVME_CC_SHN_NONE;
-	dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;
-
-	writel(aqa, &dev->bar->aqa);
-	lo_hi_writeq(nvmeq->sq_dma_addr, &dev->bar->asq);
-	lo_hi_writeq(nvmeq->cq_dma_addr, &dev->bar->acq);
-
-	result = nvme_enable_ctrl(dev, cap);
+	result = nvme_enable_ctrl(&dev->ctrl, cap);
 	if (result)
 		goto free_nvmeq;
 
 	nvmeq->cq_vector = 0;
+	nvme_init_queue(nvmeq, 0);
 	result = queue_request_irq(dev, nvmeq, nvmeq->irqname);
 	if (result) {
 		nvmeq->cq_vector = -1;
@@ -1802,625 +1501,134 @@
 	return result;
 }
 
-static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
+static bool nvme_should_reset(struct nvme_dev *dev, u32 csts)
 {
-	struct nvme_dev *dev = ns->dev;
-	struct nvme_user_io io;
-	struct nvme_command c;
-	unsigned length, meta_len;
-	int status, write;
-	dma_addr_t meta_dma = 0;
-	void *meta = NULL;
-	void __user *metadata;
-
-	if (copy_from_user(&io, uio, sizeof(io)))
-		return -EFAULT;
-
-	switch (io.opcode) {
-	case nvme_cmd_write:
-	case nvme_cmd_read:
-	case nvme_cmd_compare:
-		break;
-	default:
-		return -EINVAL;
-	}
 
-	length = (io.nblocks + 1) << ns->lba_shift;
-	meta_len = (io.nblocks + 1) * ns->ms;
-	metadata = (void __user *)(uintptr_t)io.metadata;
-	write = io.opcode & 1;
-
-	if (ns->ext) {
-		length += meta_len;
-		meta_len = 0;
-	}
-	if (meta_len) {
-		if (((io.metadata & 3) || !io.metadata) && !ns->ext)
-			return -EINVAL;
+	/* If true, indicates loss of adapter communication, possibly by a
+	 * NVMe Subsystem reset.
+	 */
+	bool nssro = dev->subsystem && (csts & NVME_CSTS_NSSRO);
 
-		meta = dma_alloc_coherent(dev->dev, meta_len,
-						&meta_dma, GFP_KERNEL);
+	/* If there is a reset ongoing, we shouldn't reset again. */
+	if (work_busy(&dev->reset_work))
+		return false;
 
-		if (!meta) {
-			status = -ENOMEM;
-			goto unmap;
-		}
-		if (write) {
-			if (copy_from_user(meta, metadata, meta_len)) {
-				status = -EFAULT;
-				goto unmap;
-			}
-		}
-	}
+	/* We shouldn't reset unless the controller is on fatal error state
+	 * _or_ if we lost the communication with it.
+	 */
+	if (!(csts & NVME_CSTS_CFS) && !nssro)
+		return false;
 
-	memset(&c, 0, sizeof(c));
-	c.rw.opcode = io.opcode;
-	c.rw.flags = io.flags;
-	c.rw.nsid = cpu_to_le32(ns->ns_id);
-	c.rw.slba = cpu_to_le64(io.slba);
-	c.rw.length = cpu_to_le16(io.nblocks);
-	c.rw.control = cpu_to_le16(io.control);
-	c.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
-	c.rw.reftag = cpu_to_le32(io.reftag);
-	c.rw.apptag = cpu_to_le16(io.apptag);
-	c.rw.appmask = cpu_to_le16(io.appmask);
-	c.rw.metadata = cpu_to_le64(meta_dma);
+	/* If PCI error recovery process is happening, we cannot reset or
+	 * the recovery mechanism will surely fail.
+	 */
+	if (pci_channel_offline(to_pci_dev(dev->dev)))
+		return false;
 
-	status = __nvme_submit_sync_cmd(ns->queue, &c, NULL,
-			(void __user *)(uintptr_t)io.addr, length, NULL, 0);
- unmap:
-	if (meta) {
-		if (status == NVME_SC_SUCCESS && !write) {
-			if (copy_to_user(metadata, meta, meta_len))
-				status = -EFAULT;
-		}
-		dma_free_coherent(dev->dev, meta_len, meta, meta_dma);
-	}
-	return status;
+	return true;
 }
 
-static int nvme_user_cmd(struct nvme_dev *dev, struct nvme_ns *ns,
-			struct nvme_passthru_cmd __user *ucmd)
+static void nvme_watchdog_timer(unsigned long data)
 {
-	struct nvme_passthru_cmd cmd;
-	struct nvme_command c;
-	unsigned timeout = 0;
-	int status;
+	struct nvme_dev *dev = (struct nvme_dev *)data;
+	u32 csts = readl(dev->bar + NVME_REG_CSTS);
 
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-	if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
-		return -EFAULT;
+	/* Skip controllers under certain specific conditions. */
+	if (nvme_should_reset(dev, csts)) {
+		if (queue_work(nvme_workq, &dev->reset_work))
+			dev_warn(dev->dev,
+				"Failed status: 0x%x, reset controller.\n",
+				csts);
+		return;
+	}
 
-	memset(&c, 0, sizeof(c));
-	c.common.opcode = cmd.opcode;
-	c.common.flags = cmd.flags;
-	c.common.nsid = cpu_to_le32(cmd.nsid);
-	c.common.cdw2[0] = cpu_to_le32(cmd.cdw2);
-	c.common.cdw2[1] = cpu_to_le32(cmd.cdw3);
-	c.common.cdw10[0] = cpu_to_le32(cmd.cdw10);
-	c.common.cdw10[1] = cpu_to_le32(cmd.cdw11);
-	c.common.cdw10[2] = cpu_to_le32(cmd.cdw12);
-	c.common.cdw10[3] = cpu_to_le32(cmd.cdw13);
-	c.common.cdw10[4] = cpu_to_le32(cmd.cdw14);
-	c.common.cdw10[5] = cpu_to_le32(cmd.cdw15);
-
-	if (cmd.timeout_ms)
-		timeout = msecs_to_jiffies(cmd.timeout_ms);
-
-	status = __nvme_submit_sync_cmd(ns ? ns->queue : dev->admin_q, &c,
-			NULL, (void __user *)(uintptr_t)cmd.addr, cmd.data_len,
-			&cmd.result, timeout);
-	if (status >= 0) {
-		if (put_user(cmd.result, &ucmd->result))
-			return -EFAULT;
-	}
-
-	return status;
-}
-
-static int nvme_subsys_reset(struct nvme_dev *dev)
-{
-	if (!dev->subsystem)
-		return -ENOTTY;
-
-	writel(0x4E564D65, &dev->bar->nssr); /* "NVMe" */
-	return 0;
+	mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + HZ));
 }
 
-static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
-							unsigned long arg)
-{
-	struct nvme_ns *ns = bdev->bd_disk->private_data;
-
-	switch (cmd) {
-	case NVME_IOCTL_ID:
-		force_successful_syscall_return();
-		return ns->ns_id;
-	case NVME_IOCTL_ADMIN_CMD:
-		return nvme_user_cmd(ns->dev, NULL, (void __user *)arg);
-	case NVME_IOCTL_IO_CMD:
-		return nvme_user_cmd(ns->dev, ns, (void __user *)arg);
-	case NVME_IOCTL_SUBMIT_IO:
-		return nvme_submit_io(ns, (void __user *)arg);
-	case SG_GET_VERSION_NUM:
-		return nvme_sg_get_version_num((void __user *)arg);
-	case SG_IO:
-		return nvme_sg_io(ns, (void __user *)arg);
-	default:
-		return -ENOTTY;
+static int nvme_create_io_queues(struct nvme_dev *dev)
+{
+	unsigned i;
+	int ret = 0;
+
+	for (i = dev->queue_count; i <= dev->max_qid; i++) {
+		if (!nvme_alloc_queue(dev, i, dev->q_depth)) {
+			ret = -ENOMEM;
+			break;
+		}
 	}
-}
 
-#ifdef CONFIG_COMPAT
-static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
-					unsigned int cmd, unsigned long arg)
-{
-	switch (cmd) {
-	case SG_IO:
-		return -ENOIOCTLCMD;
+	for (i = dev->online_queues; i <= dev->queue_count - 1; i++) {
+		ret = nvme_create_queue(dev->queues[i], i);
+		if (ret) {
+			nvme_free_queues(dev, i);
+			break;
+		}
 	}
-	return nvme_ioctl(bdev, mode, cmd, arg);
+
+	/*
+	 * Ignore failing Create SQ/CQ commands, we can continue with less
+	 * than the desired aount of queues, and even a controller without
+	 * I/O queues an still be used to issue admin commands.  This might
+	 * be useful to upgrade a buggy firmware for example.
+	 */
+	return ret >= 0 ? 0 : ret;
 }
-#else
-#define nvme_compat_ioctl	NULL
-#endif
 
-static void nvme_free_dev(struct kref *kref);
-static void nvme_free_ns(struct kref *kref)
+static void __iomem *nvme_map_cmb(struct nvme_dev *dev)
 {
-	struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref);
+	u64 szu, size, offset;
+	u32 cmbloc;
+	resource_size_t bar_size;
+	struct pci_dev *pdev = to_pci_dev(dev->dev);
+	void __iomem *cmb;
+	dma_addr_t dma_addr;
 
-	if (ns->type == NVME_NS_LIGHTNVM)
-		nvme_nvm_unregister(ns->queue, ns->disk->disk_name);
+	if (!use_cmb_sqes)
+		return NULL;
 
-	spin_lock(&dev_list_lock);
-	ns->disk->private_data = NULL;
-	spin_unlock(&dev_list_lock);
+	dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
+	if (!(NVME_CMB_SZ(dev->cmbsz)))
+		return NULL;
 
-	kref_put(&ns->dev->kref, nvme_free_dev);
-	put_disk(ns->disk);
-	kfree(ns);
-}
+	cmbloc = readl(dev->bar + NVME_REG_CMBLOC);
 
-static int nvme_open(struct block_device *bdev, fmode_t mode)
-{
-	int ret = 0;
-	struct nvme_ns *ns;
+	szu = (u64)1 << (12 + 4 * NVME_CMB_SZU(dev->cmbsz));
+	size = szu * NVME_CMB_SZ(dev->cmbsz);
+	offset = szu * NVME_CMB_OFST(cmbloc);
+	bar_size = pci_resource_len(pdev, NVME_CMB_BIR(cmbloc));
 
-	spin_lock(&dev_list_lock);
-	ns = bdev->bd_disk->private_data;
-	if (!ns)
-		ret = -ENXIO;
-	else if (!kref_get_unless_zero(&ns->kref))
-		ret = -ENXIO;
-	spin_unlock(&dev_list_lock);
+	if (offset > bar_size)
+		return NULL;
 
-	return ret;
+	/*
+	 * Controllers may support a CMB size larger than their BAR,
+	 * for example, due to being behind a bridge. Reduce the CMB to
+	 * the reported size of the BAR
+	 */
+	if (size > bar_size - offset)
+		size = bar_size - offset;
+
+	dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(cmbloc)) + offset;
+	cmb = ioremap_wc(dma_addr, size);
+	if (!cmb)
+		return NULL;
+
+	dev->cmb_dma_addr = dma_addr;
+	dev->cmb_size = size;
+	return cmb;
 }
 
-static void nvme_release(struct gendisk *disk, fmode_t mode)
+static inline void nvme_release_cmb(struct nvme_dev *dev)
 {
-	struct nvme_ns *ns = disk->private_data;
-	kref_put(&ns->kref, nvme_free_ns);
+	if (dev->cmb) {
+		iounmap(dev->cmb);
+		dev->cmb = NULL;
+	}
 }
 
-static int nvme_getgeo(struct block_device *bd, struct hd_geometry *geo)
+static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues)
 {
-	/* some standard values */
-	geo->heads = 1 << 6;
-	geo->sectors = 1 << 5;
-	geo->cylinders = get_capacity(bd->bd_disk) >> 11;
-	return 0;
-}
-
-static void nvme_config_discard(struct nvme_ns *ns)
-{
-	u32 logical_block_size = queue_logical_block_size(ns->queue);
-	ns->queue->limits.discard_zeroes_data = 0;
-	ns->queue->limits.discard_alignment = logical_block_size;
-	ns->queue->limits.discard_granularity = logical_block_size;
-	blk_queue_max_discard_sectors(ns->queue, 0xffffffff);
-	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
-}
-
-static int nvme_revalidate_disk(struct gendisk *disk)
-{
-	struct nvme_ns *ns = disk->private_data;
-	struct nvme_dev *dev = ns->dev;
-	struct nvme_id_ns *id;
-	u8 lbaf, pi_type;
-	u16 old_ms;
-	unsigned short bs;
-
-	if (nvme_identify_ns(dev, ns->ns_id, &id)) {
-		dev_warn(dev->dev, "%s: Identify failure nvme%dn%d\n", __func__,
-						dev->instance, ns->ns_id);
-		return -ENODEV;
-	}
-	if (id->ncap == 0) {
-		kfree(id);
-		return -ENODEV;
-	}
-
-	if (nvme_nvm_ns_supported(ns, id) && ns->type != NVME_NS_LIGHTNVM) {
-		if (nvme_nvm_register(ns->queue, disk->disk_name)) {
-			dev_warn(dev->dev,
-				"%s: LightNVM init failure\n", __func__);
-			kfree(id);
-			return -ENODEV;
-		}
-		ns->type = NVME_NS_LIGHTNVM;
-	}
-
-	old_ms = ns->ms;
-	lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
-	ns->lba_shift = id->lbaf[lbaf].ds;
-	ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
-	ns->ext = ns->ms && (id->flbas & NVME_NS_FLBAS_META_EXT);
-
-	/*
-	 * If identify namespace failed, use default 512 byte block size so
-	 * block layer can use before failing read/write for 0 capacity.
-	 */
-	if (ns->lba_shift == 0)
-		ns->lba_shift = 9;
-	bs = 1 << ns->lba_shift;
-
-	/* XXX: PI implementation requires metadata equal t10 pi tuple size */
-	pi_type = ns->ms == sizeof(struct t10_pi_tuple) ?
-					id->dps & NVME_NS_DPS_PI_MASK : 0;
-
-	blk_mq_freeze_queue(disk->queue);
-	if (blk_get_integrity(disk) && (ns->pi_type != pi_type ||
-				ns->ms != old_ms ||
-				bs != queue_logical_block_size(disk->queue) ||
-				(ns->ms && ns->ext)))
-		blk_integrity_unregister(disk);
-
-	ns->pi_type = pi_type;
-	blk_queue_logical_block_size(ns->queue, bs);
-
-	if (ns->ms && !ns->ext)
-		nvme_init_integrity(ns);
-
-	if ((ns->ms && !(ns->ms == 8 && ns->pi_type) &&
-						!blk_get_integrity(disk)) ||
-						ns->type == NVME_NS_LIGHTNVM)
-		set_capacity(disk, 0);
-	else
-		set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
-
-	if (dev->oncs & NVME_CTRL_ONCS_DSM)
-		nvme_config_discard(ns);
-	blk_mq_unfreeze_queue(disk->queue);
-
-	kfree(id);
-	return 0;
-}
-
-static char nvme_pr_type(enum pr_type type)
-{
-	switch (type) {
-	case PR_WRITE_EXCLUSIVE:
-		return 1;
-	case PR_EXCLUSIVE_ACCESS:
-		return 2;
-	case PR_WRITE_EXCLUSIVE_REG_ONLY:
-		return 3;
-	case PR_EXCLUSIVE_ACCESS_REG_ONLY:
-		return 4;
-	case PR_WRITE_EXCLUSIVE_ALL_REGS:
-		return 5;
-	case PR_EXCLUSIVE_ACCESS_ALL_REGS:
-		return 6;
-	default:
-		return 0;
-	}
-};
-
-static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
-				u64 key, u64 sa_key, u8 op)
-{
-	struct nvme_ns *ns = bdev->bd_disk->private_data;
-	struct nvme_command c;
-	u8 data[16] = { 0, };
-
-	put_unaligned_le64(key, &data[0]);
-	put_unaligned_le64(sa_key, &data[8]);
-
-	memset(&c, 0, sizeof(c));
-	c.common.opcode = op;
-	c.common.nsid = cpu_to_le32(ns->ns_id);
-	c.common.cdw10[0] = cpu_to_le32(cdw10);
-
-	return nvme_submit_sync_cmd(ns->queue, &c, data, 16);
-}
-
-static int nvme_pr_register(struct block_device *bdev, u64 old,
-		u64 new, unsigned flags)
-{
-	u32 cdw10;
-
-	if (flags & ~PR_FL_IGNORE_KEY)
-		return -EOPNOTSUPP;
-
-	cdw10 = old ? 2 : 0;
-	cdw10 |= (flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0;
-	cdw10 |= (1 << 30) | (1 << 31); /* PTPL=1 */
-	return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_register);
-}
-
-static int nvme_pr_reserve(struct block_device *bdev, u64 key,
-		enum pr_type type, unsigned flags)
-{
-	u32 cdw10;
-
-	if (flags & ~PR_FL_IGNORE_KEY)
-		return -EOPNOTSUPP;
-
-	cdw10 = nvme_pr_type(type) << 8;
-	cdw10 |= ((flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0);
-	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_acquire);
-}
-
-static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new,
-		enum pr_type type, bool abort)
-{
-	u32 cdw10 = nvme_pr_type(type) << 8 | abort ? 2 : 1;
-	return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire);
-}
-
-static int nvme_pr_clear(struct block_device *bdev, u64 key)
-{
-	u32 cdw10 = 1 | (key ? 1 << 3 : 0);
-	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_register);
-}
-
-static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
-{
-	u32 cdw10 = nvme_pr_type(type) << 8 | key ? 1 << 3 : 0;
-	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
-}
-
-static const struct pr_ops nvme_pr_ops = {
-	.pr_register	= nvme_pr_register,
-	.pr_reserve	= nvme_pr_reserve,
-	.pr_release	= nvme_pr_release,
-	.pr_preempt	= nvme_pr_preempt,
-	.pr_clear	= nvme_pr_clear,
-};
-
-static const struct block_device_operations nvme_fops = {
-	.owner		= THIS_MODULE,
-	.ioctl		= nvme_ioctl,
-	.compat_ioctl	= nvme_compat_ioctl,
-	.open		= nvme_open,
-	.release	= nvme_release,
-	.getgeo		= nvme_getgeo,
-	.revalidate_disk= nvme_revalidate_disk,
-	.pr_ops		= &nvme_pr_ops,
-};
-
-static int nvme_kthread(void *data)
-{
-	struct nvme_dev *dev, *next;
-
-	while (!kthread_should_stop()) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock(&dev_list_lock);
-		list_for_each_entry_safe(dev, next, &dev_list, node) {
-			int i;
-			u32 csts = readl(&dev->bar->csts);
-
-			if ((dev->subsystem && (csts & NVME_CSTS_NSSRO)) ||
-							csts & NVME_CSTS_CFS) {
-				if (!__nvme_reset(dev)) {
-					dev_warn(dev->dev,
-						"Failed status: %x, reset controller\n",
-						readl(&dev->bar->csts));
-				}
-				continue;
-			}
-			for (i = 0; i < dev->queue_count; i++) {
-				struct nvme_queue *nvmeq = dev->queues[i];
-				if (!nvmeq)
-					continue;
-				spin_lock_irq(&nvmeq->q_lock);
-				nvme_process_cq(nvmeq);
-
-				while ((i == 0) && (dev->event_limit > 0)) {
-					if (nvme_submit_async_admin_req(dev))
-						break;
-					dev->event_limit--;
-				}
-				spin_unlock_irq(&nvmeq->q_lock);
-			}
-		}
-		spin_unlock(&dev_list_lock);
-		schedule_timeout(round_jiffies_relative(HZ));
-	}
-	return 0;
-}
-
-static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
-{
-	struct nvme_ns *ns;
-	struct gendisk *disk;
-	int node = dev_to_node(dev->dev);
-
-	ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
-	if (!ns)
-		return;
-
-	ns->queue = blk_mq_init_queue(&dev->tagset);
-	if (IS_ERR(ns->queue))
-		goto out_free_ns;
-	queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, ns->queue);
-	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, ns->queue);
-	ns->dev = dev;
-	ns->queue->queuedata = ns;
-
-	disk = alloc_disk_node(0, node);
-	if (!disk)
-		goto out_free_queue;
-
-	kref_init(&ns->kref);
-	ns->ns_id = nsid;
-	ns->disk = disk;
-	ns->lba_shift = 9; /* set to a default value for 512 until disk is validated */
-	list_add_tail(&ns->list, &dev->namespaces);
-
-	blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
-	if (dev->max_hw_sectors) {
-		blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors);
-		blk_queue_max_segments(ns->queue,
-			(dev->max_hw_sectors / (dev->page_size >> 9)) + 1);
-	}
-	if (dev->stripe_size)
-		blk_queue_chunk_sectors(ns->queue, dev->stripe_size >> 9);
-	if (dev->vwc & NVME_CTRL_VWC_PRESENT)
-		blk_queue_flush(ns->queue, REQ_FLUSH | REQ_FUA);
-	blk_queue_virt_boundary(ns->queue, dev->page_size - 1);
-
-	disk->major = nvme_major;
-	disk->first_minor = 0;
-	disk->fops = &nvme_fops;
-	disk->private_data = ns;
-	disk->queue = ns->queue;
-	disk->driverfs_dev = dev->device;
-	disk->flags = GENHD_FL_EXT_DEVT;
-	sprintf(disk->disk_name, "nvme%dn%d", dev->instance, nsid);
-
-	/*
-	 * Initialize capacity to 0 until we establish the namespace format and
-	 * setup integrity extentions if necessary. The revalidate_disk after
-	 * add_disk allows the driver to register with integrity if the format
-	 * requires it.
-	 */
-	set_capacity(disk, 0);
-	if (nvme_revalidate_disk(ns->disk))
-		goto out_free_disk;
-
-	kref_get(&dev->kref);
-	if (ns->type != NVME_NS_LIGHTNVM) {
-		add_disk(ns->disk);
-		if (ns->ms) {
-			struct block_device *bd = bdget_disk(ns->disk, 0);
-			if (!bd)
-				return;
-			if (blkdev_get(bd, FMODE_READ, NULL)) {
-				bdput(bd);
-				return;
-			}
-			blkdev_reread_part(bd);
-			blkdev_put(bd, FMODE_READ);
-		}
-	}
-	return;
- out_free_disk:
-	kfree(disk);
-	list_del(&ns->list);
- out_free_queue:
-	blk_cleanup_queue(ns->queue);
- out_free_ns:
-	kfree(ns);
-}
-
-/*
- * Create I/O queues.  Failing to create an I/O queue is not an issue,
- * we can continue with less than the desired amount of queues, and
- * even a controller without I/O queues an still be used to issue
- * admin commands.  This might be useful to upgrade a buggy firmware
- * for example.
- */
-static void nvme_create_io_queues(struct nvme_dev *dev)
-{
-	unsigned i;
-
-	for (i = dev->queue_count; i <= dev->max_qid; i++)
-		if (!nvme_alloc_queue(dev, i, dev->q_depth))
-			break;
-
-	for (i = dev->online_queues; i <= dev->queue_count - 1; i++)
-		if (nvme_create_queue(dev->queues[i], i)) {
-			nvme_free_queues(dev, i);
-			break;
-		}
-}
-
-static int set_queue_count(struct nvme_dev *dev, int count)
-{
-	int status;
-	u32 result;
-	u32 q_count = (count - 1) | ((count - 1) << 16);
-
-	status = nvme_set_features(dev, NVME_FEAT_NUM_QUEUES, q_count, 0,
-								&result);
-	if (status < 0)
-		return status;
-	if (status > 0) {
-		dev_err(dev->dev, "Could not set queue count (%d)\n", status);
-		return 0;
-	}
-	return min(result & 0xffff, result >> 16) + 1;
-}
-
-static void __iomem *nvme_map_cmb(struct nvme_dev *dev)
-{
-	u64 szu, size, offset;
-	u32 cmbloc;
-	resource_size_t bar_size;
-	struct pci_dev *pdev = to_pci_dev(dev->dev);
-	void __iomem *cmb;
-	dma_addr_t dma_addr;
-
-	if (!use_cmb_sqes)
-		return NULL;
-
-	dev->cmbsz = readl(&dev->bar->cmbsz);
-	if (!(NVME_CMB_SZ(dev->cmbsz)))
-		return NULL;
-
-	cmbloc = readl(&dev->bar->cmbloc);
-
-	szu = (u64)1 << (12 + 4 * NVME_CMB_SZU(dev->cmbsz));
-	size = szu * NVME_CMB_SZ(dev->cmbsz);
-	offset = szu * NVME_CMB_OFST(cmbloc);
-	bar_size = pci_resource_len(pdev, NVME_CMB_BIR(cmbloc));
-
-	if (offset > bar_size)
-		return NULL;
-
-	/*
-	 * Controllers may support a CMB size larger than their BAR,
-	 * for example, due to being behind a bridge. Reduce the CMB to
-	 * the reported size of the BAR
-	 */
-	if (size > bar_size - offset)
-		size = bar_size - offset;
-
-	dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(cmbloc)) + offset;
-	cmb = ioremap_wc(dma_addr, size);
-	if (!cmb)
-		return NULL;
-
-	dev->cmb_dma_addr = dma_addr;
-	dev->cmb_size = size;
-	return cmb;
-}
-
-static inline void nvme_release_cmb(struct nvme_dev *dev)
-{
-	if (dev->cmb) {
-		iounmap(dev->cmb);
-		dev->cmb = NULL;
-	}
-}
-
-static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues)
-{
-	return 4096 + ((nr_io_queues + 1) * 8 * dev->db_stride);
+	return 4096 + ((nr_io_queues + 1) * 8 * dev->db_stride);
 }
 
 static int nvme_setup_io_queues(struct nvme_dev *dev)
@@ -2430,11 +1638,20 @@
 	int result, i, vecs, nr_io_queues, size;
 
 	nr_io_queues = num_possible_cpus();
-	result = set_queue_count(dev, nr_io_queues);
-	if (result <= 0)
+	result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues);
+	if (result < 0)
 		return result;
-	if (result < nr_io_queues)
-		nr_io_queues = result;
+
+	/*
+	 * Degraded controllers might return an error when setting the queue
+	 * count.  We still want to be able to bring them online and offer
+	 * access to the admin queue, as that might be only way to fix them up.
+	 */
+	if (result > 0) {
+		dev_err(dev->ctrl.device,
+			"Could not set queue count (%d)\n", result);
+		return 0;
+	}
 
 	if (dev->cmb && NVME_CMB_SQS(dev->cmbsz)) {
 		result = nvme_cmb_qdepth(dev, nr_io_queues,
@@ -2456,7 +1673,7 @@
 				return -ENOMEM;
 			size = db_bar_size(dev, nr_io_queues);
 		} while (1);
-		dev->dbs = ((void __iomem *)dev->bar) + 4096;
+		dev->dbs = dev->bar + 4096;
 		adminq->q_db = dev->dbs;
 	}
 
@@ -2467,7 +1684,9 @@
 	 * If we enable msix early due to not intx, disable it again before
 	 * setting up the full range we need.
 	 */
-	if (!pdev->irq)
+	if (pdev->msi_enabled)
+		pci_disable_msi(pdev);
+	else if (pdev->msix_enabled)
 		pci_disable_msix(pdev);
 
 	for (i = 0; i < nr_io_queues; i++)
@@ -2500,115 +1719,110 @@
 
 	/* Free previously allocated queues that are no longer usable */
 	nvme_free_queues(dev, nr_io_queues + 1);
-	nvme_create_io_queues(dev);
-
-	return 0;
+	return nvme_create_io_queues(dev);
 
  free_queues:
 	nvme_free_queues(dev, 1);
 	return result;
 }
 
-static int ns_cmp(void *priv, struct list_head *a, struct list_head *b)
+static void nvme_set_irq_hints(struct nvme_dev *dev)
 {
-	struct nvme_ns *nsa = container_of(a, struct nvme_ns, list);
-	struct nvme_ns *nsb = container_of(b, struct nvme_ns, list);
+	struct nvme_queue *nvmeq;
+	int i;
 
-	return nsa->ns_id - nsb->ns_id;
-}
+	for (i = 0; i < dev->online_queues; i++) {
+		nvmeq = dev->queues[i];
 
-static struct nvme_ns *nvme_find_ns(struct nvme_dev *dev, unsigned nsid)
-{
-	struct nvme_ns *ns;
+		if (!nvmeq->tags || !(*nvmeq->tags))
+			continue;
 
-	list_for_each_entry(ns, &dev->namespaces, list) {
-		if (ns->ns_id == nsid)
-			return ns;
-		if (ns->ns_id > nsid)
-			break;
+		irq_set_affinity_hint(dev->entry[nvmeq->cq_vector].vector,
+					blk_mq_tags_cpumask(*nvmeq->tags));
 	}
-	return NULL;
 }
 
-static inline bool nvme_io_incapable(struct nvme_dev *dev)
+static void nvme_dev_scan(struct work_struct *work)
 {
-	return (!dev->bar || readl(&dev->bar->csts) & NVME_CSTS_CFS ||
-							dev->online_queues < 2);
+	struct nvme_dev *dev = container_of(work, struct nvme_dev, scan_work);
+
+	if (!dev->tagset.tags)
+		return;
+	nvme_scan_namespaces(&dev->ctrl);
+	nvme_set_irq_hints(dev);
 }
 
-static void nvme_ns_remove(struct nvme_ns *ns)
+static void nvme_del_queue_end(struct request *req, int error)
 {
-	bool kill = nvme_io_incapable(ns->dev) && !blk_queue_dying(ns->queue);
-
-	if (kill) {
-		blk_set_queue_dying(ns->queue);
+	struct nvme_queue *nvmeq = req->end_io_data;
 
-		/*
-		 * The controller was shutdown first if we got here through
-		 * device removal. The shutdown may requeue outstanding
-		 * requests. These need to be aborted immediately so
-		 * del_gendisk doesn't block indefinitely for their completion.
-		 */
-		blk_mq_abort_requeue_list(ns->queue);
-	}
-	if (ns->disk->flags & GENHD_FL_UP)
-		del_gendisk(ns->disk);
-	if (kill || !blk_queue_dying(ns->queue)) {
-		blk_mq_abort_requeue_list(ns->queue);
-		blk_cleanup_queue(ns->queue);
-	}
-	list_del_init(&ns->list);
-	kref_put(&ns->kref, nvme_free_ns);
+	blk_mq_free_request(req);
+	complete(&nvmeq->dev->ioq_wait);
 }
 
-static void nvme_scan_namespaces(struct nvme_dev *dev, unsigned nn)
+static void nvme_del_cq_end(struct request *req, int error)
 {
-	struct nvme_ns *ns, *next;
-	unsigned i;
+	struct nvme_queue *nvmeq = req->end_io_data;
 
-	for (i = 1; i <= nn; i++) {
-		ns = nvme_find_ns(dev, i);
-		if (ns) {
-			if (revalidate_disk(ns->disk))
-				nvme_ns_remove(ns);
-		} else
-			nvme_alloc_ns(dev, i);
-	}
-	list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
-		if (ns->ns_id > nn)
-			nvme_ns_remove(ns);
+	if (!error) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&nvmeq->q_lock, flags);
+		nvme_process_cq(nvmeq);
+		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
 	}
-	list_sort(NULL, &dev->namespaces, ns_cmp);
+
+	nvme_del_queue_end(req, error);
 }
 
-static void nvme_set_irq_hints(struct nvme_dev *dev)
+static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode)
 {
-	struct nvme_queue *nvmeq;
-	int i;
+	struct request_queue *q = nvmeq->dev->ctrl.admin_q;
+	struct request *req;
+	struct nvme_command cmd;
 
-	for (i = 0; i < dev->online_queues; i++) {
-		nvmeq = dev->queues[i];
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.delete_queue.opcode = opcode;
+	cmd.delete_queue.qid = cpu_to_le16(nvmeq->qid);
 
-		if (!nvmeq->tags || !(*nvmeq->tags))
-			continue;
+	req = nvme_alloc_request(q, &cmd, BLK_MQ_REQ_NOWAIT, NVME_QID_ANY);
+	if (IS_ERR(req))
+		return PTR_ERR(req);
 
-		irq_set_affinity_hint(dev->entry[nvmeq->cq_vector].vector,
-					blk_mq_tags_cpumask(*nvmeq->tags));
-	}
+	req->timeout = ADMIN_TIMEOUT;
+	req->end_io_data = nvmeq;
+
+	blk_execute_rq_nowait(q, NULL, req, false,
+			opcode == nvme_admin_delete_cq ?
+				nvme_del_cq_end : nvme_del_queue_end);
+	return 0;
 }
 
-static void nvme_dev_scan(struct work_struct *work)
+static void nvme_disable_io_queues(struct nvme_dev *dev)
 {
-	struct nvme_dev *dev = container_of(work, struct nvme_dev, scan_work);
-	struct nvme_id_ctrl *ctrl;
+	int pass;
+	unsigned long timeout;
+	u8 opcode = nvme_admin_delete_sq;
 
-	if (!dev->tagset.tags)
-		return;
-	if (nvme_identify_ctrl(dev, &ctrl))
-		return;
-	nvme_scan_namespaces(dev, le32_to_cpup(&ctrl->nn));
-	kfree(ctrl);
-	nvme_set_irq_hints(dev);
+	for (pass = 0; pass < 2; pass++) {
+		int sent = 0, i = dev->queue_count - 1;
+
+		reinit_completion(&dev->ioq_wait);
+ retry:
+		timeout = ADMIN_TIMEOUT;
+		for (; i > 0; i--, sent++)
+			if (nvme_delete_queue(dev->queues[i], opcode))
+				break;
+
+		while (sent--) {
+			timeout = wait_for_completion_io_timeout(&dev->ioq_wait, timeout);
+			if (timeout == 0)
+				return;
+			if (i)
+				goto retry;
+		}
+		opcode = nvme_admin_delete_cq;
+	}
 }
 
 /*
@@ -2619,42 +1833,7 @@
  */
 static int nvme_dev_add(struct nvme_dev *dev)
 {
-	struct pci_dev *pdev = to_pci_dev(dev->dev);
-	int res;
-	struct nvme_id_ctrl *ctrl;
-	int shift = NVME_CAP_MPSMIN(lo_hi_readq(&dev->bar->cap)) + 12;
-
-	res = nvme_identify_ctrl(dev, &ctrl);
-	if (res) {
-		dev_err(dev->dev, "Identify Controller failed (%d)\n", res);
-		return -EIO;
-	}
-
-	dev->oncs = le16_to_cpup(&ctrl->oncs);
-	dev->abort_limit = ctrl->acl + 1;
-	dev->vwc = ctrl->vwc;
-	memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn));
-	memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn));
-	memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr));
-	if (ctrl->mdts)
-		dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9);
-	else
-		dev->max_hw_sectors = UINT_MAX;
-	if ((pdev->vendor == PCI_VENDOR_ID_INTEL) &&
-			(pdev->device == 0x0953) && ctrl->vs[3]) {
-		unsigned int max_hw_sectors;
-
-		dev->stripe_size = 1 << (ctrl->vs[3] + shift);
-		max_hw_sectors = dev->stripe_size >> (shift - 9);
-		if (dev->max_hw_sectors) {
-			dev->max_hw_sectors = min(max_hw_sectors,
-							dev->max_hw_sectors);
-		} else
-			dev->max_hw_sectors = max_hw_sectors;
-	}
-	kfree(ctrl);
-
-	if (!dev->tagset.tags) {
+	if (!dev->ctrl.tagset) {
 		dev->tagset.ops = &nvme_mq_ops;
 		dev->tagset.nr_hw_queues = dev->online_queues - 1;
 		dev->tagset.timeout = NVME_IO_TIMEOUT;
@@ -2667,56 +1846,65 @@
 
 		if (blk_mq_alloc_tag_set(&dev->tagset))
 			return 0;
+		dev->ctrl.tagset = &dev->tagset;
+
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+		if (to_pci_dev(dev->dev)->vendor == PCI_VENDOR_ID_GOOGLE) {
+			int res = nvme_set_doorbell_memory(dev);
+			if (res) {
+				// Free memory and continue on.
+				dma_free_coherent(dev->dev, 8192, dev->db_mem, dev->doorbell);
+				dma_free_coherent(dev->dev, 8192, dev->ei_mem, dev->doorbell);
+				dev->db_mem = 0;
+				dev->ei_mem = 0;
+			}
+		}
+#endif
 	}
-	schedule_work(&dev->scan_work);
+	nvme_queue_scan(dev);
 	return 0;
 }
 
-static int nvme_dev_map(struct nvme_dev *dev)
+static int nvme_pci_enable(struct nvme_dev *dev)
 {
 	u64 cap;
-	int bars, result = -ENOMEM;
+	int result = -ENOMEM;
 	struct pci_dev *pdev = to_pci_dev(dev->dev);
 
 	if (pci_enable_device_mem(pdev))
 		return result;
 
-	dev->entry[0].vector = pdev->irq;
 	pci_set_master(pdev);
-	bars = pci_select_bars(pdev, IORESOURCE_MEM);
-	if (!bars)
-		goto disable_pci;
-
-	if (pci_request_selected_regions(pdev, bars, "nvme"))
-		goto disable_pci;
 
 	if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) &&
 	    dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(32)))
 		goto disable;
 
-	dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
-	if (!dev->bar)
-		goto disable;
-
-	if (readl(&dev->bar->csts) == -1) {
+	if (readl(dev->bar + NVME_REG_CSTS) == -1) {
 		result = -ENODEV;
-		goto unmap;
+		goto disable;
 	}
 
 	/*
-	 * Some devices don't advertse INTx interrupts, pre-enable a single
-	 * MSIX vec for setup. We'll adjust this later.
+	 * Some devices and/or platforms don't advertise or work with INTx
+	 * interrupts. Pre-enable a single MSIX or MSI vec for setup. We'll
+	 * adjust this later.
 	 */
-	if (!pdev->irq) {
-		result = pci_enable_msix(pdev, dev->entry, 1);
-		if (result < 0)
-			goto unmap;
+	if (pci_enable_msix(pdev, dev->entry, 1)) {
+		pci_enable_msi(pdev);
+		dev->entry[0].vector = pdev->irq;
+	}
+
+	if (!dev->entry[0].vector) {
+		result = -ENODEV;
+		goto disable;
 	}
 
-	cap = lo_hi_readq(&dev->bar->cap);
+	cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
+
 	dev->q_depth = min_t(int, NVME_CAP_MQES(cap) + 1, NVME_Q_DEPTH);
 	dev->db_stride = 1 << NVME_CAP_STRIDE(cap);
-	dev->dbs = ((void __iomem *)dev->bar) + 4096;
+	dev->dbs = dev->bar + 4096;
 
 	/*
 	 * Temporary fix for the Apple controller found in the MacBook8,1 and
@@ -2727,276 +1915,112 @@
 		dev_warn(dev->dev, "detected Apple NVMe controller, set "
 			"queue depth=%u to work around controller resets\n",
 			dev->q_depth);
+	} else if (pdev->vendor == PCI_VENDOR_ID_SAMSUNG &&
+		   (pdev->device == 0xa821 || pdev->device == 0xa822) &&
+		   NVME_CAP_MQES(cap) == 0) {
+		dev->q_depth = 64;
+		dev_err(dev->ctrl.device, "detected PM1725 NVMe controller, "
+                        "set queue depth=%u\n", dev->q_depth);
 	}
 
-	if (readl(&dev->bar->vs) >= NVME_VS(1, 2))
+	if (readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 2))
 		dev->cmb = nvme_map_cmb(dev);
 
+	pci_enable_pcie_error_reporting(pdev);
+	pci_save_state(pdev);
+
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	if (pdev->vendor == PCI_VENDOR_ID_GOOGLE) {
+		int mem_size = nvme_vendor_memory_size(dev);
+		dev->db_mem = dma_alloc_coherent(&pdev->dev, mem_size, &dev->doorbell, GFP_KERNEL);
+		if (!dev->db_mem) {
+			result = -ENOMEM;
+			goto disable;
+		}
+		dev->ei_mem = dma_alloc_coherent(&pdev->dev, mem_size, &dev->eventidx, GFP_KERNEL);
+		if (!dev->ei_mem) {
+			result = -ENOMEM;
+			goto dma_free;
+		}
+	}
+#endif
+
 	return 0;
 
- unmap:
-	iounmap(dev->bar);
-	dev->bar = NULL;
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+  dma_free:
+	dma_free_coherent(&pdev->dev, nvme_vendor_memory_size(dev), dev->db_mem, dev->doorbell);
+	dev->db_mem = 0;
+#endif
+
  disable:
-	pci_release_regions(pdev);
- disable_pci:
 	pci_disable_device(pdev);
+
 	return result;
 }
 
 static void nvme_dev_unmap(struct nvme_dev *dev)
 {
+	if (dev->bar)
+		iounmap(dev->bar);
+	pci_release_regions(to_pci_dev(dev->dev));
+}
+
+static void nvme_pci_disable(struct nvme_dev *dev)
+{
 	struct pci_dev *pdev = to_pci_dev(dev->dev);
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	int mem_size = nvme_vendor_memory_size(dev);
+
+	if (dev->db_mem)
+		dma_free_coherent(&pdev->dev, mem_size, dev->db_mem, dev->doorbell);
+	if (dev->ei_mem)
+		dma_free_coherent(&pdev->dev, mem_size, dev->ei_mem, dev->eventidx);
+#endif
 
 	if (pdev->msi_enabled)
 		pci_disable_msi(pdev);
 	else if (pdev->msix_enabled)
 		pci_disable_msix(pdev);
 
-	if (dev->bar) {
-		iounmap(dev->bar);
-		dev->bar = NULL;
-		pci_release_regions(pdev);
-	}
-
-	if (pci_is_enabled(pdev))
+	if (pci_is_enabled(pdev)) {
+		pci_disable_pcie_error_reporting(pdev);
 		pci_disable_device(pdev);
-}
-
-struct nvme_delq_ctx {
-	struct task_struct *waiter;
-	struct kthread_worker *worker;
-	atomic_t refcount;
-};
-
-static void nvme_wait_dq(struct nvme_delq_ctx *dq, struct nvme_dev *dev)
-{
-	dq->waiter = current;
-	mb();
-
-	for (;;) {
-		set_current_state(TASK_KILLABLE);
-		if (!atomic_read(&dq->refcount))
-			break;
-		if (!schedule_timeout(ADMIN_TIMEOUT) ||
-					fatal_signal_pending(current)) {
-			/*
-			 * Disable the controller first since we can't trust it
-			 * at this point, but leave the admin queue enabled
-			 * until all queue deletion requests are flushed.
-			 * FIXME: This may take a while if there are more h/w
-			 * queues than admin tags.
-			 */
-			set_current_state(TASK_RUNNING);
-			nvme_disable_ctrl(dev, lo_hi_readq(&dev->bar->cap));
-			nvme_clear_queue(dev->queues[0]);
-			flush_kthread_worker(dq->worker);
-			nvme_disable_queue(dev, 0);
-			return;
-		}
 	}
-	set_current_state(TASK_RUNNING);
-}
-
-static void nvme_put_dq(struct nvme_delq_ctx *dq)
-{
-	atomic_dec(&dq->refcount);
-	if (dq->waiter)
-		wake_up_process(dq->waiter);
-}
-
-static struct nvme_delq_ctx *nvme_get_dq(struct nvme_delq_ctx *dq)
-{
-	atomic_inc(&dq->refcount);
-	return dq;
-}
-
-static void nvme_del_queue_end(struct nvme_queue *nvmeq)
-{
-	struct nvme_delq_ctx *dq = nvmeq->cmdinfo.ctx;
-	nvme_put_dq(dq);
-
-	spin_lock_irq(&nvmeq->q_lock);
-	nvme_process_cq(nvmeq);
-	spin_unlock_irq(&nvmeq->q_lock);
-}
-
-static int adapter_async_del_queue(struct nvme_queue *nvmeq, u8 opcode,
-						kthread_work_func_t fn)
-{
-	struct nvme_command c;
-
-	memset(&c, 0, sizeof(c));
-	c.delete_queue.opcode = opcode;
-	c.delete_queue.qid = cpu_to_le16(nvmeq->qid);
-
-	init_kthread_work(&nvmeq->cmdinfo.work, fn);
-	return nvme_submit_admin_async_cmd(nvmeq->dev, &c, &nvmeq->cmdinfo,
-								ADMIN_TIMEOUT);
-}
-
-static void nvme_del_cq_work_handler(struct kthread_work *work)
-{
-	struct nvme_queue *nvmeq = container_of(work, struct nvme_queue,
-							cmdinfo.work);
-	nvme_del_queue_end(nvmeq);
-}
-
-static int nvme_delete_cq(struct nvme_queue *nvmeq)
-{
-	return adapter_async_del_queue(nvmeq, nvme_admin_delete_cq,
-						nvme_del_cq_work_handler);
-}
-
-static void nvme_del_sq_work_handler(struct kthread_work *work)
-{
-	struct nvme_queue *nvmeq = container_of(work, struct nvme_queue,
-							cmdinfo.work);
-	int status = nvmeq->cmdinfo.status;
-
-	if (!status)
-		status = nvme_delete_cq(nvmeq);
-	if (status)
-		nvme_del_queue_end(nvmeq);
 }
 
-static int nvme_delete_sq(struct nvme_queue *nvmeq)
-{
-	return adapter_async_del_queue(nvmeq, nvme_admin_delete_sq,
-						nvme_del_sq_work_handler);
-}
-
-static void nvme_del_queue_start(struct kthread_work *work)
-{
-	struct nvme_queue *nvmeq = container_of(work, struct nvme_queue,
-							cmdinfo.work);
-	if (nvme_delete_sq(nvmeq))
-		nvme_del_queue_end(nvmeq);
-}
-
-static void nvme_disable_io_queues(struct nvme_dev *dev)
+static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
 {
 	int i;
-	DEFINE_KTHREAD_WORKER_ONSTACK(worker);
-	struct nvme_delq_ctx dq;
-	struct task_struct *kworker_task = kthread_run(kthread_worker_fn,
-					&worker, "nvme%d", dev->instance);
-
-	if (IS_ERR(kworker_task)) {
-		dev_err(dev->dev,
-			"Failed to create queue del task\n");
-		for (i = dev->queue_count - 1; i > 0; i--)
-			nvme_disable_queue(dev, i);
-		return;
-	}
-
-	dq.waiter = NULL;
-	atomic_set(&dq.refcount, 0);
-	dq.worker = &worker;
-	for (i = dev->queue_count - 1; i > 0; i--) {
-		struct nvme_queue *nvmeq = dev->queues[i];
-
-		if (nvme_suspend_queue(nvmeq))
-			continue;
-		nvmeq->cmdinfo.ctx = nvme_get_dq(&dq);
-		nvmeq->cmdinfo.worker = dq.worker;
-		init_kthread_work(&nvmeq->cmdinfo.work, nvme_del_queue_start);
-		queue_kthread_work(dq.worker, &nvmeq->cmdinfo.work);
-	}
-	nvme_wait_dq(&dq, dev);
-	kthread_stop(kworker_task);
-}
-
-/*
-* Remove the node from the device list and check
-* for whether or not we need to stop the nvme_thread.
-*/
-static void nvme_dev_list_remove(struct nvme_dev *dev)
-{
-	struct task_struct *tmp = NULL;
-
-	spin_lock(&dev_list_lock);
-	list_del_init(&dev->node);
-	if (list_empty(&dev_list) && !IS_ERR_OR_NULL(nvme_thread)) {
-		tmp = nvme_thread;
-		nvme_thread = NULL;
-	}
-	spin_unlock(&dev_list_lock);
-
-	if (tmp)
-		kthread_stop(tmp);
-}
-
-static void nvme_freeze_queues(struct nvme_dev *dev)
-{
-	struct nvme_ns *ns;
-
-	list_for_each_entry(ns, &dev->namespaces, list) {
-		blk_mq_freeze_queue_start(ns->queue);
-
-		spin_lock_irq(ns->queue->queue_lock);
-		queue_flag_set(QUEUE_FLAG_STOPPED, ns->queue);
-		spin_unlock_irq(ns->queue->queue_lock);
-
-		blk_mq_cancel_requeue_work(ns->queue);
-		blk_mq_stop_hw_queues(ns->queue);
-	}
-}
+	u32 csts = -1;
 
-static void nvme_unfreeze_queues(struct nvme_dev *dev)
-{
-	struct nvme_ns *ns;
+	del_timer_sync(&dev->watchdog_timer);
 
-	list_for_each_entry(ns, &dev->namespaces, list) {
-		queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, ns->queue);
-		blk_mq_unfreeze_queue(ns->queue);
-		blk_mq_start_stopped_hw_queues(ns->queue, true);
-		blk_mq_kick_requeue_list(ns->queue);
+	mutex_lock(&dev->shutdown_lock);
+	if (pci_is_enabled(to_pci_dev(dev->dev))) {
+		nvme_stop_queues(&dev->ctrl);
+		csts = readl(dev->bar + NVME_REG_CSTS);
 	}
-}
-
-static void nvme_dev_shutdown(struct nvme_dev *dev)
-{
-	int i;
-	u32 csts = -1;
 
-	nvme_dev_list_remove(dev);
+	for (i = dev->queue_count - 1; i > 0; i--)
+		nvme_suspend_queue(dev->queues[i]);
 
-	if (dev->bar) {
-		nvme_freeze_queues(dev);
-		csts = readl(&dev->bar->csts);
-	}
 	if (csts & NVME_CSTS_CFS || !(csts & NVME_CSTS_RDY)) {
-		for (i = dev->queue_count - 1; i >= 0; i--) {
-			struct nvme_queue *nvmeq = dev->queues[i];
-			nvme_suspend_queue(nvmeq);
-		}
+		/* A device might become IO incapable very soon during
+		 * probe, before the admin queue is configured. Thus,
+		 * queue_count can be 0 here.
+		 */
+		if (dev->queue_count)
+			nvme_suspend_queue(dev->queues[0]);
 	} else {
 		nvme_disable_io_queues(dev);
-		nvme_shutdown_ctrl(dev);
-		nvme_disable_queue(dev, 0);
+		nvme_disable_admin_queue(dev, shutdown);
 	}
-	nvme_dev_unmap(dev);
+	nvme_pci_disable(dev);
 
 	for (i = dev->queue_count - 1; i >= 0; i--)
 		nvme_clear_queue(dev->queues[i]);
-}
-
-static void nvme_dev_remove(struct nvme_dev *dev)
-{
-	struct nvme_ns *ns, *next;
-
-	if (nvme_io_incapable(dev)) {
-		/*
-		 * If the device is not capable of IO (surprise hot-removal,
-		 * for example), we need to quiesce prior to deleting the
-		 * namespaces. This will end outstanding requests and prevent
-		 * attempts to sync dirty data.
-		 */
-		nvme_dev_shutdown(dev);
-	}
-	list_for_each_entry_safe(ns, next, &dev->namespaces, list)
-		nvme_ns_remove(ns);
+	mutex_unlock(&dev->shutdown_lock);
 }
 
 static int nvme_setup_prp_pools(struct nvme_dev *dev)
@@ -3022,121 +2046,41 @@
 	dma_pool_destroy(dev->prp_small_pool);
 }
 
-static DEFINE_IDA(nvme_instance_ida);
-
-static int nvme_set_instance(struct nvme_dev *dev)
+static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
 {
-	int instance, error;
-
-	do {
-		if (!ida_pre_get(&nvme_instance_ida, GFP_KERNEL))
-			return -ENODEV;
-
-		spin_lock(&dev_list_lock);
-		error = ida_get_new(&nvme_instance_ida, &instance);
-		spin_unlock(&dev_list_lock);
-	} while (error == -EAGAIN);
-
-	if (error)
-		return -ENODEV;
-
-	dev->instance = instance;
-	return 0;
-}
-
-static void nvme_release_instance(struct nvme_dev *dev)
-{
-	spin_lock(&dev_list_lock);
-	ida_remove(&nvme_instance_ida, dev->instance);
-	spin_unlock(&dev_list_lock);
-}
-
-static void nvme_free_dev(struct kref *kref)
-{
-	struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);
+	struct nvme_dev *dev = to_nvme_dev(ctrl);
 
 	put_device(dev->dev);
-	put_device(dev->device);
-	nvme_release_instance(dev);
 	if (dev->tagset.tags)
 		blk_mq_free_tag_set(&dev->tagset);
-	if (dev->admin_q)
-		blk_put_queue(dev->admin_q);
+	if (dev->ctrl.admin_q)
+		blk_put_queue(dev->ctrl.admin_q);
 	kfree(dev->queues);
 	kfree(dev->entry);
 	kfree(dev);
 }
 
-static int nvme_dev_open(struct inode *inode, struct file *f)
+static void nvme_reset_work(struct work_struct *work)
 {
-	struct nvme_dev *dev;
-	int instance = iminor(inode);
-	int ret = -ENODEV;
-
-	spin_lock(&dev_list_lock);
-	list_for_each_entry(dev, &dev_list, node) {
-		if (dev->instance == instance) {
-			if (!dev->admin_q) {
-				ret = -EWOULDBLOCK;
-				break;
-			}
-			if (!kref_get_unless_zero(&dev->kref))
-				break;
-			f->private_data = dev;
-			ret = 0;
-			break;
-		}
-	}
-	spin_unlock(&dev_list_lock);
-
-	return ret;
-}
+	struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
+	int result;
 
-static int nvme_dev_release(struct inode *inode, struct file *f)
-{
-	struct nvme_dev *dev = f->private_data;
-	kref_put(&dev->kref, nvme_free_dev);
-	return 0;
-}
+	if (WARN_ON(test_bit(NVME_CTRL_RESETTING, &dev->flags)))
+		goto out;
 
-static long nvme_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
-{
-	struct nvme_dev *dev = f->private_data;
-	struct nvme_ns *ns;
-
-	switch (cmd) {
-	case NVME_IOCTL_ADMIN_CMD:
-		return nvme_user_cmd(dev, NULL, (void __user *)arg);
-	case NVME_IOCTL_IO_CMD:
-		if (list_empty(&dev->namespaces))
-			return -ENOTTY;
-		ns = list_first_entry(&dev->namespaces, struct nvme_ns, list);
-		return nvme_user_cmd(dev, ns, (void __user *)arg);
-	case NVME_IOCTL_RESET:
-		dev_warn(dev->dev, "resetting controller\n");
-		return nvme_reset(dev);
-	case NVME_IOCTL_SUBSYS_RESET:
-		return nvme_subsys_reset(dev);
-	default:
-		return -ENOTTY;
-	}
-}
+	/*
+	 * If we're called to reset a live controller first shut it down before
+	 * moving on.
+	 */
+	if (dev->ctrl.ctrl_config & NVME_CC_ENABLE)
+		nvme_dev_disable(dev, false);
 
-static const struct file_operations nvme_dev_fops = {
-	.owner		= THIS_MODULE,
-	.open		= nvme_dev_open,
-	.release	= nvme_dev_release,
-	.unlocked_ioctl	= nvme_dev_ioctl,
-	.compat_ioctl	= nvme_dev_ioctl,
-};
+	if (test_bit(NVME_CTRL_REMOVING, &dev->flags))
+		goto out;
 
-static void nvme_probe_work(struct work_struct *work)
-{
-	struct nvme_dev *dev = container_of(work, struct nvme_dev, probe_work);
-	bool start_thread = false;
-	int result;
+	set_bit(NVME_CTRL_RESETTING, &dev->flags);
 
-	result = nvme_dev_map(dev);
+	result = nvme_pci_enable(dev);
 	if (result)
 		goto out;
 
@@ -3144,35 +2088,22 @@
 	if (result)
 		goto unmap;
 
-	spin_lock(&dev_list_lock);
-	if (list_empty(&dev_list) && IS_ERR_OR_NULL(nvme_thread)) {
-		start_thread = true;
-		nvme_thread = NULL;
-	}
-	list_add(&dev->node, &dev_list);
-	spin_unlock(&dev_list_lock);
-
-	if (start_thread) {
-		nvme_thread = kthread_run(nvme_kthread, NULL, "nvme");
-		wake_up_all(&nvme_kthread_wait);
-	} else
-		wait_event_killable(nvme_kthread_wait, nvme_thread);
-
-	if (IS_ERR_OR_NULL(nvme_thread)) {
-		result = nvme_thread ? PTR_ERR(nvme_thread) : -EINTR;
-		goto disable;
-	}
-
-	nvme_init_queue(dev->queues[0], 0);
 	result = nvme_alloc_admin_tags(dev);
 	if (result)
 		goto disable;
 
+	result = nvme_init_identify(&dev->ctrl);
+	if (result)
+		goto free_tags;
+
 	result = nvme_setup_io_queues(dev);
 	if (result)
 		goto free_tags;
 
-	dev->event_limit = 1;
+	dev->ctrl.event_limit = NVME_NR_AEN_COMMANDS;
+	queue_work(nvme_workq, &dev->async_work);
+
+	mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + HZ));
 
 	/*
 	 * Keep the controller around but remove all namespaces if we don't have
@@ -3180,122 +2111,153 @@
 	 */
 	if (dev->online_queues < 2) {
 		dev_warn(dev->dev, "IO queues not created\n");
-		nvme_dev_remove(dev);
+		nvme_remove_namespaces(&dev->ctrl);
 	} else {
-		nvme_unfreeze_queues(dev);
+		nvme_start_queues(&dev->ctrl);
 		nvme_dev_add(dev);
 	}
 
+	clear_bit(NVME_CTRL_RESETTING, &dev->flags);
 	return;
 
  free_tags:
 	nvme_dev_remove_admin(dev);
-	blk_put_queue(dev->admin_q);
-	dev->admin_q = NULL;
+	blk_put_queue(dev->ctrl.admin_q);
+	dev->ctrl.admin_q = NULL;
 	dev->queues[0]->tags = NULL;
  disable:
-	nvme_disable_queue(dev, 0);
-	nvme_dev_list_remove(dev);
+	nvme_disable_admin_queue(dev, false);
  unmap:
 	nvme_dev_unmap(dev);
  out:
-	if (!work_busy(&dev->reset_work))
-		nvme_dead_ctrl(dev);
+	nvme_remove_dead_ctrl(dev);
 }
 
-static int nvme_remove_dead_ctrl(void *arg)
+static void nvme_remove_dead_ctrl_work(struct work_struct *work)
 {
-	struct nvme_dev *dev = (struct nvme_dev *)arg;
+	struct nvme_dev *dev = container_of(work, struct nvme_dev, remove_work);
 	struct pci_dev *pdev = to_pci_dev(dev->dev);
 
+	nvme_kill_queues(&dev->ctrl);
 	if (pci_get_drvdata(pdev))
 		pci_stop_and_remove_bus_device_locked(pdev);
-	kref_put(&dev->kref, nvme_free_dev);
-	return 0;
+	nvme_put_ctrl(&dev->ctrl);
 }
 
-static void nvme_dead_ctrl(struct nvme_dev *dev)
+static void nvme_remove_dead_ctrl(struct nvme_dev *dev)
 {
-	dev_warn(dev->dev, "Device failed to resume\n");
-	kref_get(&dev->kref);
-	if (IS_ERR(kthread_run(nvme_remove_dead_ctrl, dev, "nvme%d",
-						dev->instance))) {
-		dev_err(dev->dev,
-			"Failed to start controller remove task\n");
-		kref_put(&dev->kref, nvme_free_dev);
-	}
+	dev_warn(dev->dev, "Removing after probe failure\n");
+	kref_get(&dev->ctrl.kref);
+	nvme_dev_disable(dev, false);
+	if (!schedule_work(&dev->remove_work))
+		nvme_put_ctrl(&dev->ctrl);
 }
 
-static void nvme_reset_work(struct work_struct *ws)
+static int nvme_reset(struct nvme_dev *dev)
 {
-	struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work);
-	bool in_probe = work_busy(&dev->probe_work);
+	if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q))
+		return -ENODEV;
 
-	nvme_dev_shutdown(dev);
+	if (!queue_work(nvme_workq, &dev->reset_work))
+		return -EBUSY;
 
-	/* Synchronize with device probe so that work will see failure status
-	 * and exit gracefully without trying to schedule another reset */
-	flush_work(&dev->probe_work);
+	flush_work(&dev->reset_work);
+	return 0;
+}
 
-	/* Fail this device if reset occured during probe to avoid
-	 * infinite initialization loops. */
-	if (in_probe) {
-		nvme_dead_ctrl(dev);
-		return;
-	}
-	/* Schedule device resume asynchronously so the reset work is available
-	 * to cleanup errors that may occur during reinitialization */
-	schedule_work(&dev->probe_work);
+static int nvme_pci_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val)
+{
+	*val = readl(to_nvme_dev(ctrl)->bar + off);
+	return 0;
 }
 
-static int __nvme_reset(struct nvme_dev *dev)
+static int nvme_pci_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val)
 {
-	if (work_pending(&dev->reset_work))
-		return -EBUSY;
-	list_del_init(&dev->node);
-	queue_work(nvme_workq, &dev->reset_work);
+	writel(val, to_nvme_dev(ctrl)->bar + off);
 	return 0;
 }
 
-static int nvme_reset(struct nvme_dev *dev)
+static int nvme_pci_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val)
 {
-	int ret;
+	*val = readq(to_nvme_dev(ctrl)->bar + off);
+	return 0;
+}
 
-	if (!dev->admin_q || blk_queue_dying(dev->admin_q))
-		return -ENODEV;
+static bool nvme_pci_io_incapable(struct nvme_ctrl *ctrl)
+{
+	struct nvme_dev *dev = to_nvme_dev(ctrl);
 
-	spin_lock(&dev_list_lock);
-	ret = __nvme_reset(dev);
-	spin_unlock(&dev_list_lock);
-
-	if (!ret) {
-		flush_work(&dev->reset_work);
-		flush_work(&dev->probe_work);
-		return 0;
-	}
+	return !dev->bar || dev->online_queues < 2;
+}
 
-	return ret;
+static int nvme_pci_reset_ctrl(struct nvme_ctrl *ctrl)
+{
+	return nvme_reset(to_nvme_dev(ctrl));
 }
 
-static ssize_t nvme_sysfs_reset(struct device *dev,
-				struct device_attribute *attr, const char *buf,
-				size_t count)
+static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
+	.reg_read32		= nvme_pci_reg_read32,
+	.reg_write32		= nvme_pci_reg_write32,
+	.reg_read64		= nvme_pci_reg_read64,
+	.io_incapable		= nvme_pci_io_incapable,
+	.reset_ctrl		= nvme_pci_reset_ctrl,
+	.free_ctrl		= nvme_pci_free_ctrl,
+};
+
+static int nvme_dev_map(struct nvme_dev *dev)
 {
-	struct nvme_dev *ndev = dev_get_drvdata(dev);
-	int ret;
+	int bars;
+	struct pci_dev *pdev = to_pci_dev(dev->dev);
 
-	ret = nvme_reset(ndev);
-	if (ret < 0)
-		return ret;
+	bars = pci_select_bars(pdev, IORESOURCE_MEM);
+	if (!bars)
+		return -ENODEV;
+	if (pci_request_selected_regions(pdev, bars, "nvme"))
+		return -ENODEV;
+
+	dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
+	if (!dev->bar)
+		goto release;
 
-	return count;
+       return 0;
+  release:
+       pci_release_regions(pdev);
+       return -ENODEV;
+}
+
+static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
+{
+	if (pdev->vendor == 0x144d && pdev->device == 0xa802) {
+		/*
+		 * Several Samsung devices seem to drop off the PCIe bus
+		 * randomly when APST is on and uses the deepest sleep state.
+		 * This has been observed on a Samsung "SM951 NVMe SAMSUNG
+		 * 256GB", a "PM951 NVMe SAMSUNG 512GB", and a "Samsung SSD
+		 * 950 PRO 256GB", but it seems to be restricted to two Dell
+		 * laptops.
+		 */
+		if (dmi_match(DMI_SYS_VENDOR, "Dell Inc.") &&
+		    (dmi_match(DMI_PRODUCT_NAME, "XPS 15 9550") ||
+		     dmi_match(DMI_PRODUCT_NAME, "Precision 5510")))
+			return NVME_QUIRK_NO_DEEPEST_PS;
+	} else if (pdev->vendor == 0x144d && pdev->device == 0xa804) {
+		/*
+		 * Samsung SSD 960 EVO drops off the PCIe bus after system
+		 * suspend on a Ryzen board, ASUS PRIME B350M-A.
+		 */
+		if (dmi_match(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC.") &&
+		    dmi_match(DMI_BOARD_NAME, "PRIME B350M-A"))
+			return NVME_QUIRK_NO_APST;
+	}
+
+	return 0;
 }
-static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_sysfs_reset);
 
 static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	int node, result = -ENOMEM;
 	struct nvme_dev *dev;
+	unsigned long quirks = id->driver_data;
 
 	node = dev_to_node(&pdev->dev);
 	if (node == NUMA_NO_NODE)
@@ -3313,48 +2275,41 @@
 	if (!dev->queues)
 		goto free;
 
-	INIT_LIST_HEAD(&dev->namespaces);
-	INIT_WORK(&dev->reset_work, nvme_reset_work);
 	dev->dev = get_device(&pdev->dev);
 	pci_set_drvdata(pdev, dev);
-	result = nvme_set_instance(dev);
+
+	result = nvme_dev_map(dev);
 	if (result)
-		goto put_pci;
+		goto free;
+
+	INIT_WORK(&dev->scan_work, nvme_dev_scan);
+	INIT_WORK(&dev->reset_work, nvme_reset_work);
+	INIT_WORK(&dev->remove_work, nvme_remove_dead_ctrl_work);
+	INIT_WORK(&dev->async_work, nvme_async_event_work);
+	setup_timer(&dev->watchdog_timer, nvme_watchdog_timer,
+		(unsigned long)dev);
+	mutex_init(&dev->shutdown_lock);
+	init_completion(&dev->ioq_wait);
 
 	result = nvme_setup_prp_pools(dev);
 	if (result)
-		goto release;
+		goto put_pci;
 
-	kref_init(&dev->kref);
-	dev->device = device_create(nvme_class, &pdev->dev,
-				MKDEV(nvme_char_major, dev->instance),
-				dev, "nvme%d", dev->instance);
-	if (IS_ERR(dev->device)) {
-		result = PTR_ERR(dev->device);
-		goto release_pools;
-	}
-	get_device(dev->device);
-	dev_set_drvdata(dev->device, dev);
+	quirks |= check_vendor_combination_bug(pdev);
 
-	result = device_create_file(dev->device, &dev_attr_reset_controller);
+	result = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_pci_ctrl_ops,
+			quirks);
 	if (result)
-		goto put_dev;
+		goto release_pools;
 
-	INIT_LIST_HEAD(&dev->node);
-	INIT_WORK(&dev->scan_work, nvme_dev_scan);
-	INIT_WORK(&dev->probe_work, nvme_probe_work);
-	schedule_work(&dev->probe_work);
+	queue_work(nvme_workq, &dev->reset_work);
 	return 0;
 
- put_dev:
-	device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance));
-	put_device(dev->device);
  release_pools:
 	nvme_release_prp_pools(dev);
- release:
-	nvme_release_instance(dev);
  put_pci:
 	put_device(dev->dev);
+	nvme_dev_unmap(dev);
  free:
 	kfree(dev->queues);
 	kfree(dev->entry);
@@ -3367,54 +2322,44 @@
 	struct nvme_dev *dev = pci_get_drvdata(pdev);
 
 	if (prepare)
-		nvme_dev_shutdown(dev);
+		nvme_dev_disable(dev, false);
 	else
-		schedule_work(&dev->probe_work);
+		queue_work(nvme_workq, &dev->reset_work);
 }
 
 static void nvme_shutdown(struct pci_dev *pdev)
 {
 	struct nvme_dev *dev = pci_get_drvdata(pdev);
-	nvme_dev_shutdown(dev);
+	nvme_dev_disable(dev, true);
 }
 
 static void nvme_remove(struct pci_dev *pdev)
 {
 	struct nvme_dev *dev = pci_get_drvdata(pdev);
 
-	spin_lock(&dev_list_lock);
-	list_del_init(&dev->node);
-	spin_unlock(&dev_list_lock);
-
+	set_bit(NVME_CTRL_REMOVING, &dev->flags);
 	pci_set_drvdata(pdev, NULL);
-	flush_work(&dev->probe_work);
+	flush_work(&dev->async_work);
 	flush_work(&dev->reset_work);
 	flush_work(&dev->scan_work);
-	device_remove_file(dev->device, &dev_attr_reset_controller);
-	nvme_dev_remove(dev);
-	nvme_dev_shutdown(dev);
+	nvme_remove_namespaces(&dev->ctrl);
+	nvme_uninit_ctrl(&dev->ctrl);
+	nvme_dev_disable(dev, true);
 	nvme_dev_remove_admin(dev);
-	device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance));
 	nvme_free_queues(dev, 0);
 	nvme_release_cmb(dev);
 	nvme_release_prp_pools(dev);
-	kref_put(&dev->kref, nvme_free_dev);
+	nvme_dev_unmap(dev);
+	nvme_put_ctrl(&dev->ctrl);
 }
 
-/* These functions are yet to be implemented */
-#define nvme_error_detected NULL
-#define nvme_dump_registers NULL
-#define nvme_link_reset NULL
-#define nvme_slot_reset NULL
-#define nvme_error_resume NULL
-
 #ifdef CONFIG_PM_SLEEP
 static int nvme_suspend(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct nvme_dev *ndev = pci_get_drvdata(pdev);
 
-	nvme_dev_shutdown(ndev);
+	nvme_dev_disable(ndev, true);
 	return 0;
 }
 
@@ -3423,17 +2368,53 @@
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct nvme_dev *ndev = pci_get_drvdata(pdev);
 
-	schedule_work(&ndev->probe_work);
+	queue_work(nvme_workq, &ndev->reset_work);
 	return 0;
 }
 #endif
 
 static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume);
 
+static pci_ers_result_t nvme_error_detected(struct pci_dev *pdev,
+						pci_channel_state_t state)
+{
+	struct nvme_dev *dev = pci_get_drvdata(pdev);
+
+	/*
+	 * A frozen channel requires a reset. When detected, this method will
+	 * shutdown the controller to quiesce. The controller will be restarted
+	 * after the slot reset through driver's slot_reset callback.
+	 */
+	dev_warn(&pdev->dev, "error detected: state:%d\n", state);
+	switch (state) {
+	case pci_channel_io_normal:
+		return PCI_ERS_RESULT_CAN_RECOVER;
+	case pci_channel_io_frozen:
+		nvme_dev_disable(dev, false);
+		return PCI_ERS_RESULT_NEED_RESET;
+	case pci_channel_io_perm_failure:
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev)
+{
+	struct nvme_dev *dev = pci_get_drvdata(pdev);
+
+	dev_info(&pdev->dev, "restart after slot reset\n");
+	pci_restore_state(pdev);
+	queue_work(nvme_workq, &dev->reset_work);
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void nvme_error_resume(struct pci_dev *pdev)
+{
+	pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
 static const struct pci_error_handlers nvme_err_handler = {
 	.error_detected	= nvme_error_detected,
-	.mmio_enabled	= nvme_dump_registers,
-	.link_reset	= nvme_link_reset,
 	.slot_reset	= nvme_slot_reset,
 	.resume		= nvme_error_resume,
 	.reset_notify	= nvme_reset_notify,
@@ -3443,6 +2424,19 @@
 #define PCI_CLASS_STORAGE_EXPRESS	0x010802
 
 static const struct pci_device_id nvme_id_table[] = {
+	{ PCI_VDEVICE(INTEL, 0x0953),
+		.driver_data = NVME_QUIRK_STRIPE_SIZE |
+				NVME_QUIRK_DISCARD_ZEROES, },
+	{ PCI_VDEVICE(INTEL, 0xf1a5),	/* Intel 600P/P3100 */
+		.driver_data = NVME_QUIRK_NO_DEEPEST_PS },
+	{ PCI_VDEVICE(INTEL, 0x5845),	/* Qemu emulated controller */
+		.driver_data = NVME_QUIRK_IDENTIFY_CNS, },
+	{ PCI_DEVICE(0x1c58, 0x0003),	/* HGST adapter */
+		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
+	{ PCI_DEVICE(0x144d, 0xa821),   /* Samsung PM1725 */
+		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
+	{ PCI_DEVICE(0x144d, 0xa822),   /* Samsung PM1725a */
+		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
 	{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) },
 	{ 0, }
@@ -3465,42 +2459,24 @@
 {
 	int result;
 
-	init_waitqueue_head(&nvme_kthread_wait);
-
-	nvme_workq = create_singlethread_workqueue("nvme");
+	nvme_workq = alloc_workqueue("nvme", WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
 	if (!nvme_workq)
 		return -ENOMEM;
 
-	result = register_blkdev(nvme_major, "nvme");
+	result = nvme_core_init();
 	if (result < 0)
 		goto kill_workq;
-	else if (result > 0)
-		nvme_major = result;
-
-	result = __register_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme",
-							&nvme_dev_fops);
-	if (result < 0)
-		goto unregister_blkdev;
-	else if (result > 0)
-		nvme_char_major = result;
-
-	nvme_class = class_create(THIS_MODULE, "nvme");
-	if (IS_ERR(nvme_class)) {
-		result = PTR_ERR(nvme_class);
-		goto unregister_chrdev;
-	}
 
 	result = pci_register_driver(&nvme_driver);
 	if (result)
-		goto destroy_class;
+		goto core_exit;
+
+	dma_set_attr(DMA_ATTR_NO_WARN, &nvme_dma_attrs);
+
 	return 0;
 
- destroy_class:
-	class_destroy(nvme_class);
- unregister_chrdev:
-	__unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
- unregister_blkdev:
-	unregister_blkdev(nvme_major, "nvme");
+ core_exit:
+	nvme_core_exit();
  kill_workq:
 	destroy_workqueue(nvme_workq);
 	return result;
@@ -3509,11 +2485,8 @@
 static void __exit nvme_exit(void)
 {
 	pci_unregister_driver(&nvme_driver);
-	unregister_blkdev(nvme_major, "nvme");
+	nvme_core_exit();
 	destroy_workqueue(nvme_workq);
-	class_destroy(nvme_class);
-	__unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
-	BUG_ON(nvme_thread && !IS_ERR(nvme_thread));
 	_nvme_check_size();
 }
 
--- linux-4.4.0.orig/drivers/nvme/host/scsi.c
+++ linux-4.4.0/drivers/nvme/host/scsi.c
@@ -72,15 +72,6 @@
 #define ALL_LUNS_RETURNED				0x02
 #define ALL_WELL_KNOWN_LUNS_RETURNED			0x01
 #define RESTRICTED_LUNS_RETURNED			0x00
-#define NVME_POWER_STATE_START_VALID			0x00
-#define NVME_POWER_STATE_ACTIVE				0x01
-#define NVME_POWER_STATE_IDLE				0x02
-#define NVME_POWER_STATE_STANDBY			0x03
-#define NVME_POWER_STATE_LU_CONTROL			0x07
-#define POWER_STATE_0					0
-#define POWER_STATE_1					1
-#define POWER_STATE_2					2
-#define POWER_STATE_3					3
 #define DOWNLOAD_SAVE_ACTIVATE				0x05
 #define DOWNLOAD_SAVE_DEFER_ACTIVATE			0x0E
 #define ACTIVATE_DEFERRED_MICROCODE			0x0F
@@ -524,7 +515,7 @@
 					struct sg_io_hdr *hdr, u8 *inq_response,
 					int alloc_len)
 {
-	struct nvme_dev *dev = ns->dev;
+	struct nvme_ctrl *ctrl = ns->ctrl;
 	struct nvme_id_ns *id_ns;
 	int res;
 	int nvme_sc;
@@ -532,10 +523,10 @@
 	u8 resp_data_format = 0x02;
 	u8 protect;
 	u8 cmdque = 0x01 << 1;
-	u8 fw_offset = sizeof(dev->firmware_rev);
+	u8 fw_offset = sizeof(ctrl->firmware_rev);
 
 	/* nvme ns identify - use DPS value for PROTECT field */
-	nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
+	nvme_sc = nvme_identify_ns(ctrl, ns->ns_id, &id_ns);
 	res = nvme_trans_status_code(hdr, nvme_sc);
 	if (res)
 		return res;
@@ -553,12 +544,12 @@
 	inq_response[5] = protect;	/* sccs=0 | acc=0 | tpgs=0 | pc3=0 */
 	inq_response[7] = cmdque;	/* wbus16=0 | sync=0 | vs=0 */
 	strncpy(&inq_response[8], "NVMe    ", 8);
-	strncpy(&inq_response[16], dev->model, 16);
+	strncpy(&inq_response[16], ctrl->model, 16);
 
-	while (dev->firmware_rev[fw_offset - 1] == ' ' && fw_offset > 4)
+	while (ctrl->firmware_rev[fw_offset - 1] == ' ' && fw_offset > 4)
 		fw_offset--;
 	fw_offset -= 4;
-	strncpy(&inq_response[32], dev->firmware_rev + fw_offset, 4);
+	strncpy(&inq_response[32], ctrl->firmware_rev + fw_offset, 4);
 
 	xfer_len = min(alloc_len, STANDARD_INQUIRY_LENGTH);
 	return nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
@@ -588,82 +579,113 @@
 					struct sg_io_hdr *hdr, u8 *inq_response,
 					int alloc_len)
 {
-	struct nvme_dev *dev = ns->dev;
 	int xfer_len;
 
 	memset(inq_response, 0, STANDARD_INQUIRY_LENGTH);
 	inq_response[1] = INQ_UNIT_SERIAL_NUMBER_PAGE; /* Page Code */
 	inq_response[3] = INQ_SERIAL_NUMBER_LENGTH;    /* Page Length */
-	strncpy(&inq_response[4], dev->serial, INQ_SERIAL_NUMBER_LENGTH);
+	strncpy(&inq_response[4], ns->ctrl->serial, INQ_SERIAL_NUMBER_LENGTH);
 
 	xfer_len = min(alloc_len, STANDARD_INQUIRY_LENGTH);
 	return nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
 }
 
-static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
-					u8 *inq_response, int alloc_len)
+static int nvme_fill_device_id_eui64(struct nvme_ns *ns, struct sg_io_hdr *hdr,
+		u8 *inq_response, int alloc_len)
 {
-	struct nvme_dev *dev = ns->dev;
-	int res;
-	int nvme_sc;
-	int xfer_len;
-	__be32 tmp_id = cpu_to_be32(ns->ns_id);
+	struct nvme_id_ns *id_ns;
+	int nvme_sc, res;
+	size_t len;
+	void *eui;
 
-	memset(inq_response, 0, alloc_len);
-	inq_response[1] = INQ_DEVICE_IDENTIFICATION_PAGE;    /* Page Code */
-	if (readl(&dev->bar->vs) >= NVME_VS(1, 1)) {
-		struct nvme_id_ns *id_ns;
-		void *eui;
-		int len;
+	nvme_sc = nvme_identify_ns(ns->ctrl, ns->ns_id, &id_ns);
+	res = nvme_trans_status_code(hdr, nvme_sc);
+	if (res)
+		return res;
 
-		nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
-		res = nvme_trans_status_code(hdr, nvme_sc);
-		if (res)
-			return res;
+	eui = id_ns->eui64;
+	len = sizeof(id_ns->eui64);
 
-		eui = id_ns->eui64;
-		len = sizeof(id_ns->eui64);
-		if (readl(&dev->bar->vs) >= NVME_VS(1, 2)) {
-			if (bitmap_empty(eui, len * 8)) {
-				eui = id_ns->nguid;
-				len = sizeof(id_ns->nguid);
-			}
-		}
+	if (ns->ctrl->vs >= NVME_VS(1, 2)) {
 		if (bitmap_empty(eui, len * 8)) {
-			kfree(id_ns);
-			goto scsi_string;
+			eui = id_ns->nguid;
+			len = sizeof(id_ns->nguid);
 		}
+	}
 
-		inq_response[3] = 4 + len; /* Page Length */
-		/* Designation Descriptor start */
-		inq_response[4] = 0x01;    /* Proto ID=0h | Code set=1h */
-		inq_response[5] = 0x02;    /* PIV=0b | Asso=00b | Designator Type=2h */
-		inq_response[6] = 0x00;    /* Rsvd */
-		inq_response[7] = len;     /* Designator Length */
-		memcpy(&inq_response[8], eui, len);
-		kfree(id_ns);
-	} else {
- scsi_string:
-		if (alloc_len < 72) {
-			return nvme_trans_completion(hdr,
-					SAM_STAT_CHECK_CONDITION,
-					ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
-					SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
-		}
-		inq_response[3] = 0x48;    /* Page Length */
-		/* Designation Descriptor start */
-		inq_response[4] = 0x03;    /* Proto ID=0h | Code set=3h */
-		inq_response[5] = 0x08;    /* PIV=0b | Asso=00b | Designator Type=8h */
-		inq_response[6] = 0x00;    /* Rsvd */
-		inq_response[7] = 0x44;    /* Designator Length */
-
-		sprintf(&inq_response[8], "%04x", to_pci_dev(dev->dev)->vendor);
-		memcpy(&inq_response[12], dev->model, sizeof(dev->model));
-		sprintf(&inq_response[52], "%04x", tmp_id);
-		memcpy(&inq_response[56], dev->serial, sizeof(dev->serial));
+	if (bitmap_empty(eui, len * 8)) {
+		res = -EOPNOTSUPP;
+		goto out_free_id;
 	}
-	xfer_len = alloc_len;
-	return nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
+
+	memset(inq_response, 0, alloc_len);
+	inq_response[1] = INQ_DEVICE_IDENTIFICATION_PAGE;
+	inq_response[3] = 4 + len; /* Page Length */
+
+	/* Designation Descriptor start */
+	inq_response[4] = 0x01;	/* Proto ID=0h | Code set=1h */
+	inq_response[5] = 0x02;	/* PIV=0b | Asso=00b | Designator Type=2h */
+	inq_response[6] = 0x00;	/* Rsvd */
+	inq_response[7] = len;	/* Designator Length */
+	memcpy(&inq_response[8], eui, len);
+
+	res = nvme_trans_copy_to_user(hdr, inq_response, alloc_len);
+out_free_id:
+	kfree(id_ns);
+	return res;
+}
+
+static int nvme_fill_device_id_scsi_string(struct nvme_ns *ns,
+		struct sg_io_hdr *hdr, u8 *inq_response, int alloc_len)
+{
+	struct nvme_ctrl *ctrl = ns->ctrl;
+	struct nvme_id_ctrl *id_ctrl;
+	int nvme_sc, res;
+
+	if (alloc_len < 72) {
+		return nvme_trans_completion(hdr,
+				SAM_STAT_CHECK_CONDITION,
+				ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
+				SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
+	}
+
+	nvme_sc = nvme_identify_ctrl(ctrl, &id_ctrl);
+	res = nvme_trans_status_code(hdr, nvme_sc);
+	if (res)
+		return res;
+
+	memset(inq_response, 0, alloc_len);
+	inq_response[1] = INQ_DEVICE_IDENTIFICATION_PAGE;
+	inq_response[3] = 0x48;	/* Page Length */
+
+	/* Designation Descriptor start */
+	inq_response[4] = 0x03;	/* Proto ID=0h | Code set=3h */
+	inq_response[5] = 0x08;	/* PIV=0b | Asso=00b | Designator Type=8h */
+	inq_response[6] = 0x00;	/* Rsvd */
+	inq_response[7] = 0x44;	/* Designator Length */
+
+	sprintf(&inq_response[8], "%04x", le16_to_cpu(id_ctrl->vid));
+	memcpy(&inq_response[12], ctrl->model, sizeof(ctrl->model));
+	sprintf(&inq_response[52], "%04x", cpu_to_be32(ns->ns_id));
+	memcpy(&inq_response[56], ctrl->serial, sizeof(ctrl->serial));
+
+	res = nvme_trans_copy_to_user(hdr, inq_response, alloc_len);
+	kfree(id_ctrl);
+	return res;
+}
+
+static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
+					u8 *resp, int alloc_len)
+{
+	int res;
+
+	if (ns->ctrl->vs >= NVME_VS(1, 1)) {
+		res = nvme_fill_device_id_eui64(ns, hdr, resp, alloc_len);
+		if (res != -EOPNOTSUPP)
+			return res;
+	}
+
+	return nvme_fill_device_id_scsi_string(ns, hdr, resp, alloc_len);
 }
 
 static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
@@ -672,7 +694,7 @@
 	u8 *inq_response;
 	int res;
 	int nvme_sc;
-	struct nvme_dev *dev = ns->dev;
+	struct nvme_ctrl *ctrl = ns->ctrl;
 	struct nvme_id_ctrl *id_ctrl;
 	struct nvme_id_ns *id_ns;
 	int xfer_len;
@@ -688,7 +710,7 @@
 	if (inq_response == NULL)
 		return -ENOMEM;
 
-	nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
+	nvme_sc = nvme_identify_ns(ctrl, ns->ns_id, &id_ns);
 	res = nvme_trans_status_code(hdr, nvme_sc);
 	if (res)
 		goto out_free_inq;
@@ -704,7 +726,7 @@
 	app_chk = protect << 1;
 	ref_chk = protect;
 
-	nvme_sc = nvme_identify_ctrl(dev, &id_ctrl);
+	nvme_sc = nvme_identify_ctrl(ctrl, &id_ctrl);
 	res = nvme_trans_status_code(hdr, nvme_sc);
 	if (res)
 		goto out_free_inq;
@@ -815,7 +837,6 @@
 	int res;
 	int xfer_len;
 	u8 *log_response;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_smart_log *smart_log;
 	u8 temp_c;
 	u16 temp_k;
@@ -824,7 +845,7 @@
 	if (log_response == NULL)
 		return -ENOMEM;
 
-	res = nvme_get_log_page(dev, &smart_log);
+	res = nvme_get_log_page(ns->ctrl, &smart_log);
 	if (res < 0)
 		goto out_free_response;
 
@@ -862,7 +883,6 @@
 	int res;
 	int xfer_len;
 	u8 *log_response;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_smart_log *smart_log;
 	u32 feature_resp;
 	u8 temp_c_cur, temp_c_thresh;
@@ -872,7 +892,7 @@
 	if (log_response == NULL)
 		return -ENOMEM;
 
-	res = nvme_get_log_page(dev, &smart_log);
+	res = nvme_get_log_page(ns->ctrl, &smart_log);
 	if (res < 0)
 		goto out_free_response;
 
@@ -886,7 +906,7 @@
 	kfree(smart_log);
 
 	/* Get Features for Temp Threshold */
-	res = nvme_get_features(dev, NVME_FEAT_TEMP_THRESH, 0, 0,
+	res = nvme_get_features(ns->ctrl, NVME_FEAT_TEMP_THRESH, 0, NULL, 0,
 								&feature_resp);
 	if (res != NVME_SC_SUCCESS)
 		temp_c_thresh = LOG_TEMP_UNKNOWN;
@@ -948,7 +968,6 @@
 {
 	int res;
 	int nvme_sc;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_id_ns *id_ns;
 	u8 flbas;
 	u32 lba_length;
@@ -958,7 +977,7 @@
 	else if (llbaa > 0 && len < MODE_PAGE_LLBAA_BLK_DES_LEN)
 		return -EINVAL;
 
-	nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
+	nvme_sc = nvme_identify_ns(ns->ctrl, ns->ns_id, &id_ns);
 	res = nvme_trans_status_code(hdr, nvme_sc);
 	if (res)
 		return res;
@@ -1014,14 +1033,13 @@
 {
 	int res = 0;
 	int nvme_sc;
-	struct nvme_dev *dev = ns->dev;
 	u32 feature_resp;
 	u8 vwc;
 
 	if (len < MODE_PAGE_CACHING_LEN)
 		return -EINVAL;
 
-	nvme_sc = nvme_get_features(dev, NVME_FEAT_VOLATILE_WC, 0, 0,
+	nvme_sc = nvme_get_features(ns->ctrl, NVME_FEAT_VOLATILE_WC, 0, NULL, 0,
 								&feature_resp);
 	res = nvme_trans_status_code(hdr, nvme_sc);
 	if (res)
@@ -1202,65 +1220,6 @@
 
 /* Start Stop Unit Helper Functions */
 
-static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr,
-						u8 pc, u8 pcmod, u8 start)
-{
-	int res;
-	int nvme_sc;
-	struct nvme_dev *dev = ns->dev;
-	struct nvme_id_ctrl *id_ctrl;
-	int lowest_pow_st;	/* max npss = lowest power consumption */
-	unsigned ps_desired = 0;
-
-	nvme_sc = nvme_identify_ctrl(dev, &id_ctrl);
-	res = nvme_trans_status_code(hdr, nvme_sc);
-	if (res)
-		return res;
-
-	lowest_pow_st = max(POWER_STATE_0, (int)(id_ctrl->npss - 1));
-	kfree(id_ctrl);
-
-	switch (pc) {
-	case NVME_POWER_STATE_START_VALID:
-		/* Action unspecified if POWER CONDITION MODIFIER != 0 */
-		if (pcmod == 0 && start == 0x1)
-			ps_desired = POWER_STATE_0;
-		if (pcmod == 0 && start == 0x0)
-			ps_desired = lowest_pow_st;
-		break;
-	case NVME_POWER_STATE_ACTIVE:
-		/* Action unspecified if POWER CONDITION MODIFIER != 0 */
-		if (pcmod == 0)
-			ps_desired = POWER_STATE_0;
-		break;
-	case NVME_POWER_STATE_IDLE:
-		/* Action unspecified if POWER CONDITION MODIFIER != [0,1,2] */
-		if (pcmod == 0x0)
-			ps_desired = POWER_STATE_1;
-		else if (pcmod == 0x1)
-			ps_desired = POWER_STATE_2;
-		else if (pcmod == 0x2)
-			ps_desired = POWER_STATE_3;
-		break;
-	case NVME_POWER_STATE_STANDBY:
-		/* Action unspecified if POWER CONDITION MODIFIER != [0,1] */
-		if (pcmod == 0x0)
-			ps_desired = max(POWER_STATE_0, (lowest_pow_st - 2));
-		else if (pcmod == 0x1)
-			ps_desired = max(POWER_STATE_0, (lowest_pow_st - 1));
-		break;
-	case NVME_POWER_STATE_LU_CONTROL:
-	default:
-		res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
-				ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
-				SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
-		break;
-	}
-	nvme_sc = nvme_set_features(dev, NVME_FEAT_POWER_MGMT, ps_desired, 0,
-				    NULL);
-	return nvme_trans_status_code(hdr, nvme_sc);
-}
-
 static int nvme_trans_send_activate_fw_cmd(struct nvme_ns *ns, struct sg_io_hdr *hdr,
 					u8 buffer_id)
 {
@@ -1280,7 +1239,6 @@
 					u8 buffer_id)
 {
 	int nvme_sc;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_command c;
 
 	if (hdr->iovec_count > 0) {
@@ -1297,7 +1255,7 @@
 	c.dlfw.numd = cpu_to_le32((tot_len/BYTES_TO_DWORDS) - 1);
 	c.dlfw.offset = cpu_to_le32(offset/BYTES_TO_DWORDS);
 
-	nvme_sc = __nvme_submit_sync_cmd(dev->admin_q, &c, NULL,
+	nvme_sc = nvme_submit_user_cmd(ns->ctrl->admin_q, &c,
 			hdr->dxferp, tot_len, NULL, 0);
 	return nvme_trans_status_code(hdr, nvme_sc);
 }
@@ -1364,14 +1322,13 @@
 {
 	int res = 0;
 	int nvme_sc;
-	struct nvme_dev *dev = ns->dev;
 	unsigned dword11;
 
 	switch (page_code) {
 	case MODE_PAGE_CACHING:
 		dword11 = ((mode_page[2] & CACHING_MODE_PAGE_WCE_MASK) ? 1 : 0);
-		nvme_sc = nvme_set_features(dev, NVME_FEAT_VOLATILE_WC, dword11,
-					    0, NULL);
+		nvme_sc = nvme_set_features(ns->ctrl, NVME_FEAT_VOLATILE_WC,
+					    dword11, NULL, 0, NULL);
 		res = nvme_trans_status_code(hdr, nvme_sc);
 		break;
 	case MODE_PAGE_CONTROL:
@@ -1473,7 +1430,6 @@
 {
 	int res = 0;
 	int nvme_sc;
-	struct nvme_dev *dev = ns->dev;
 	u8 flbas;
 
 	/*
@@ -1486,7 +1442,7 @@
 	if (ns->mode_select_num_blocks == 0 || ns->mode_select_block_len == 0) {
 		struct nvme_id_ns *id_ns;
 
-		nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
+		nvme_sc = nvme_identify_ns(ns->ctrl, ns->ns_id, &id_ns);
 		res = nvme_trans_status_code(hdr, nvme_sc);
 		if (res)
 			return res;
@@ -1570,7 +1526,6 @@
 {
 	int res;
 	int nvme_sc;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_id_ns *id_ns;
 	u8 i;
 	u8 flbas, nlbaf;
@@ -1579,7 +1534,7 @@
 	struct nvme_command c;
 
 	/* Loop thru LBAF's in id_ns to match reqd lbaf, put in cdw10 */
-	nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
+	nvme_sc = nvme_identify_ns(ns->ctrl, ns->ns_id, &id_ns);
 	res = nvme_trans_status_code(hdr, nvme_sc);
 	if (res)
 		return res;
@@ -1611,7 +1566,7 @@
 	c.format.nsid = cpu_to_le32(ns->ns_id);
 	c.format.cdw10 = cpu_to_le32(cdw10);
 
-	nvme_sc = nvme_submit_sync_cmd(dev->admin_q, &c, NULL, 0);
+	nvme_sc = nvme_submit_sync_cmd(ns->ctrl->admin_q, &c, NULL, 0);
 	res = nvme_trans_status_code(hdr, nvme_sc);
 
 	kfree(id_ns);
@@ -1704,7 +1659,7 @@
 			nvme_sc = NVME_SC_LBA_RANGE;
 			break;
 		}
-		nvme_sc = __nvme_submit_sync_cmd(ns->queue, &c, NULL,
+		nvme_sc = nvme_submit_user_cmd(ns->queue, &c,
 				next_mapping_addr, unit_len, NULL, 0);
 		if (nvme_sc)
 			break;
@@ -2040,7 +1995,6 @@
 	u32 alloc_len;
 	u32 resp_size;
 	u32 xfer_len;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_id_ns *id_ns;
 	u8 *response;
 
@@ -2052,7 +2006,7 @@
 		resp_size = READ_CAP_10_RESP_SIZE;
 	}
 
-	nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
+	nvme_sc = nvme_identify_ns(ns->ctrl, ns->ns_id, &id_ns);
 	res = nvme_trans_status_code(hdr, nvme_sc);
 	if (res)
 		return res;	
@@ -2080,7 +2034,6 @@
 	int nvme_sc;
 	u32 alloc_len, xfer_len, resp_size;
 	u8 *response;
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_id_ctrl *id_ctrl;
 	u32 ll_length, lun_id;
 	u8 lun_id_offset = REPORT_LUNS_FIRST_LUN_OFFSET;
@@ -2094,7 +2047,7 @@
 	case ALL_LUNS_RETURNED:
 	case ALL_WELL_KNOWN_LUNS_RETURNED:
 	case RESTRICTED_LUNS_RETURNED:
-		nvme_sc = nvme_identify_ctrl(dev, &id_ctrl);
+		nvme_sc = nvme_identify_ctrl(ns->ctrl, &id_ctrl);
 		res = nvme_trans_status_code(hdr, nvme_sc);
 		if (res)
 			return res;
@@ -2215,11 +2168,10 @@
 static int nvme_trans_start_stop(struct nvme_ns *ns, struct sg_io_hdr *hdr,
 							u8 *cmd)
 {
-	u8 immed, pcmod, pc, no_flush, start;
+	u8 immed, pcmod, no_flush, start;
 
 	immed = cmd[1] & 0x01;
 	pcmod = cmd[3] & 0x0f;
-	pc = (cmd[4] & 0xf0) >> 4;
 	no_flush = cmd[4] & 0x04;
 	start = cmd[4] & 0x01;
 
@@ -2234,8 +2186,8 @@
 			if (res)
 				return res;
 		}
-		/* Setup the expected power state transition */
-		return nvme_trans_power_state(ns, hdr, pc, pcmod, start);
+
+		return 0;
 	}
 }
 
@@ -2295,9 +2247,7 @@
 					struct sg_io_hdr *hdr,
 					u8 *cmd)
 {
-	struct nvme_dev *dev = ns->dev;
-
-	if (!(readl(&dev->bar->csts) & NVME_CSTS_RDY))
+	if (nvme_ctrl_ready(ns->ctrl))
 		return nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
 					    NOT_READY, SCSI_ASC_LUN_NOT_READY,
 					    SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
--- linux-4.4.0.orig/drivers/nvmem/core.c
+++ linux-4.4.0/drivers/nvmem/core.c
@@ -457,7 +457,7 @@
 	d = bus_find_device(&nvmem_bus_type, NULL, (void *)name, nvmem_match);
 
 	if (!d)
-		return NULL;
+		return ERR_PTR(-ENOENT);
 
 	return to_nvmem_device(d);
 }
@@ -789,7 +789,7 @@
 						    void *buf)
 {
 	u8 *p, *b;
-	int i, bit_offset = cell->bit_offset;
+	int i, extra, bit_offset = cell->bit_offset;
 
 	p = b = buf;
 	if (bit_offset) {
@@ -804,11 +804,16 @@
 			p = b;
 			*b++ >>= bit_offset;
 		}
-
-		/* result fits in less bytes */
-		if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE))
-			*p-- = 0;
+	} else {
+		/* point to the msb */
+		p += cell->bytes - 1;
 	}
+
+	/* result fits in less bytes */
+	extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE);
+	while (--extra >= 0)
+		*p-- = 0;
+
 	/* clear msb bits if any leftover in the last byte */
 	*p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
 }
--- linux-4.4.0.orig/drivers/nvmem/imx-ocotp.c
+++ linux-4.4.0/drivers/nvmem/imx-ocotp.c
@@ -88,7 +88,7 @@
 
 static const struct of_device_id imx_ocotp_dt_ids[] = {
 	{ .compatible = "fsl,imx6q-ocotp",  (void *)128 },
-	{ .compatible = "fsl,imx6sl-ocotp", (void *)32 },
+	{ .compatible = "fsl,imx6sl-ocotp", (void *)64 },
 	{ .compatible = "fsl,imx6sx-ocotp", (void *)128 },
 	{ },
 };
--- linux-4.4.0.orig/drivers/nvmem/mxs-ocotp.c
+++ linux-4.4.0/drivers/nvmem/mxs-ocotp.c
@@ -94,7 +94,7 @@
 	if (ret)
 		goto close_banks;
 
-	while (val_size) {
+	while (val_size >= reg_size) {
 		if ((offset < OCOTP_DATA_OFFSET) || (offset % 16)) {
 			/* fill up non-data register */
 			*buf = 0;
@@ -103,7 +103,7 @@
 		}
 
 		buf++;
-		val_size--;
+		val_size -= reg_size;
 		offset += reg_size;
 	}
 
--- linux-4.4.0.orig/drivers/of/Kconfig
+++ linux-4.4.0/drivers/of/Kconfig
@@ -112,4 +112,12 @@
 	  While this option is selected automatically when needed, you can
 	  enable it manually to improve device tree unit test coverage.
 
+config OF_NUMA
+	bool
+
+config OF_DMA_DEFAULT_COHERENT
+	# arches should select this if DMA is coherent by default for OF devices
+	bool
+
+
 endif # OF
--- linux-4.4.0.orig/drivers/of/Makefile
+++ linux-4.4.0/drivers/of/Makefile
@@ -14,5 +14,6 @@
 obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
 obj-$(CONFIG_OF_RESOLVE)  += resolver.o
 obj-$(CONFIG_OF_OVERLAY) += overlay.o
+obj-$(CONFIG_OF_NUMA) += of_numa.o
 
 obj-$(CONFIG_OF_UNITTEST) += unittest-data/
--- linux-4.4.0.orig/drivers/of/address.c
+++ linux-4.4.0/drivers/of/address.c
@@ -4,6 +4,7 @@
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
+#include <linux/pci.h>
 #include <linux/pci_regs.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
@@ -260,7 +261,7 @@
 	if (!parser->range || parser->range + parser->np > parser->end)
 		return NULL;
 
-	range->pci_space = parser->range[0];
+	range->pci_space = be32_to_cpup(parser->range);
 	range->flags = of_bus_pci_get_flags(parser->range);
 	range->pci_addr = of_read_number(parser->range + 1, ns);
 	range->cpu_addr = of_translate_address(parser->node,
@@ -673,121 +674,6 @@
 }
 EXPORT_SYMBOL(of_get_address);
 
-#ifdef PCI_IOBASE
-struct io_range {
-	struct list_head list;
-	phys_addr_t start;
-	resource_size_t size;
-};
-
-static LIST_HEAD(io_range_list);
-static DEFINE_SPINLOCK(io_range_lock);
-#endif
-
-/*
- * Record the PCI IO range (expressed as CPU physical address + size).
- * Return a negative value if an error has occured, zero otherwise
- */
-int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size)
-{
-	int err = 0;
-
-#ifdef PCI_IOBASE
-	struct io_range *range;
-	resource_size_t allocated_size = 0;
-
-	/* check if the range hasn't been previously recorded */
-	spin_lock(&io_range_lock);
-	list_for_each_entry(range, &io_range_list, list) {
-		if (addr >= range->start && addr + size <= range->start + size) {
-			/* range already registered, bail out */
-			goto end_register;
-		}
-		allocated_size += range->size;
-	}
-
-	/* range not registed yet, check for available space */
-	if (allocated_size + size - 1 > IO_SPACE_LIMIT) {
-		/* if it's too big check if 64K space can be reserved */
-		if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) {
-			err = -E2BIG;
-			goto end_register;
-		}
-
-		size = SZ_64K;
-		pr_warn("Requested IO range too big, new size set to 64K\n");
-	}
-
-	/* add the range to the list */
-	range = kzalloc(sizeof(*range), GFP_ATOMIC);
-	if (!range) {
-		err = -ENOMEM;
-		goto end_register;
-	}
-
-	range->start = addr;
-	range->size = size;
-
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
-#endif
-
-	return err;
-}
-
-phys_addr_t pci_pio_to_address(unsigned long pio)
-{
-	phys_addr_t address = (phys_addr_t)OF_BAD_ADDR;
-
-#ifdef PCI_IOBASE
-	struct io_range *range;
-	resource_size_t allocated_size = 0;
-
-	if (pio > IO_SPACE_LIMIT)
-		return address;
-
-	spin_lock(&io_range_lock);
-	list_for_each_entry(range, &io_range_list, list) {
-		if (pio >= allocated_size && pio < allocated_size + range->size) {
-			address = range->start + pio - allocated_size;
-			break;
-		}
-		allocated_size += range->size;
-	}
-	spin_unlock(&io_range_lock);
-#endif
-
-	return address;
-}
-
-unsigned long __weak pci_address_to_pio(phys_addr_t address)
-{
-#ifdef PCI_IOBASE
-	struct io_range *res;
-	resource_size_t offset = 0;
-	unsigned long addr = -1;
-
-	spin_lock(&io_range_lock);
-	list_for_each_entry(res, &io_range_list, list) {
-		if (address >= res->start && address < res->start + res->size) {
-			addr = address - res->start + offset;
-			break;
-		}
-		offset += res->size;
-	}
-	spin_unlock(&io_range_lock);
-
-	return addr;
-#else
-	if (address > IO_SPACE_LIMIT)
-		return (unsigned long)-1;
-
-	return (unsigned long) address;
-#endif
-}
-
 static int __of_address_to_resource(struct device_node *dev,
 		const __be32 *addrp, u64 size, unsigned int flags,
 		const char *name, struct resource *r)
@@ -1009,11 +895,17 @@
  * @np:	device node
  *
  * It returns true if "dma-coherent" property was found
- * for this device in DT.
+ * for this device in the DT, or if DMA is coherent by
+ * default for OF devices on the current platform.
  */
 bool of_dma_is_coherent(struct device_node *np)
 {
-	struct device_node *node = of_node_get(np);
+	struct device_node *node;
+
+	if (IS_ENABLED(CONFIG_OF_DMA_DEFAULT_COHERENT))
+		return true;
+
+	node = of_node_get(np);
 
 	while (node) {
 		if (of_property_read_bool(node, "dma-coherent")) {
--- linux-4.4.0.orig/drivers/of/base.c
+++ linux-4.4.0/drivers/of/base.c
@@ -112,6 +112,7 @@
 	return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length);
 }
 
+/* always return newly allocated name, caller must free after use */
 static const char *safe_name(struct kobject *kobj, const char *orig_name)
 {
 	const char *name = orig_name;
@@ -126,9 +127,12 @@
 		name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i);
 	}
 
-	if (name != orig_name)
+	if (name == orig_name) {
+		name = kstrdup(orig_name, GFP_KERNEL);
+	} else {
 		pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",
 			kobject_name(kobj), name);
+	}
 	return name;
 }
 
@@ -159,27 +163,26 @@
 int __of_attach_node_sysfs(struct device_node *np)
 {
 	const char *name;
+	struct kobject *parent;
 	struct property *pp;
 	int rc;
 
-	if (!IS_ENABLED(CONFIG_SYSFS))
-		return 0;
-
 	if (!of_kset)
 		return 0;
 
 	np->kobj.kset = of_kset;
 	if (!np->parent) {
 		/* Nodes without parents are new top level trees */
-		rc = kobject_add(&np->kobj, NULL, "%s",
-				 safe_name(&of_kset->kobj, "base"));
+		name = safe_name(&of_kset->kobj, "base");
+		parent = NULL;
 	} else {
 		name = safe_name(&np->parent->kobj, kbasename(np->full_name));
-		if (!name || !name[0])
-			return -EINVAL;
-
-		rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name);
+		parent = &np->parent->kobj;
 	}
+	if (!name)
+		return -ENOMEM;
+	rc = kobject_add(&np->kobj, parent, "%s", name);
+	kfree(name);
 	if (rc)
 		return rc;
 
@@ -707,6 +710,31 @@
 EXPORT_SYMBOL(of_get_next_available_child);
 
 /**
+ * of_get_compatible_child - Find compatible child node
+ * @parent:	parent node
+ * @compatible:	compatible string
+ *
+ * Lookup child node whose compatible property contains the given compatible
+ * string.
+ *
+ * Returns a node pointer with refcount incremented, use of_node_put() on it
+ * when done; or NULL if not found.
+ */
+struct device_node *of_get_compatible_child(const struct device_node *parent,
+				const char *compatible)
+{
+	struct device_node *child;
+
+	for_each_child_of_node(parent, child) {
+		if (of_device_is_compatible(child, compatible))
+			break;
+	}
+
+	return child;
+}
+EXPORT_SYMBOL(of_get_compatible_child);
+
+/**
  *	of_get_child_by_name - Find the child node by name for a given parent
  *	@node:	parent node
  *	@name:	child name to look for.
@@ -1753,6 +1781,12 @@
 	return 0;
 }
 
+void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop)
+{
+	sysfs_remove_bin_file(&np->kobj, &prop->attr);
+	kfree(prop->attr.attr.name);
+}
+
 void __of_remove_property_sysfs(struct device_node *np, struct property *prop)
 {
 	if (!IS_ENABLED(CONFIG_SYSFS))
@@ -1760,7 +1794,7 @@
 
 	/* at early boot, bail here and defer setup to of_init() */
 	if (of_kset && of_node_is_attached(np))
-		sysfs_remove_bin_file(&np->kobj, &prop->attr);
+		__of_sysfs_remove_bin_file(np, prop);
 }
 
 /**
@@ -1830,7 +1864,7 @@
 		return;
 
 	if (oldprop)
-		sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
+		__of_sysfs_remove_bin_file(np, oldprop);
 	__of_add_property_sysfs(np, newprop);
 }
 
@@ -2088,7 +2122,7 @@
 	/* OF on pmac has nodes instead of properties named "l2-cache"
 	 * beneath CPU nodes.
 	 */
-	if (!strcmp(np->type, "cpu"))
+	if (IS_ENABLED(CONFIG_PPC_PMAC) && !strcmp(np->type, "cpu"))
 		for_each_child_of_node(np, child)
 			if (!strcmp(child->type, "cache"))
 				return child;
@@ -2241,20 +2275,13 @@
 	const struct device_node *parent, int port_reg, int reg)
 {
 	struct of_endpoint endpoint;
-	struct device_node *node, *prev_node = NULL;
-
-	while (1) {
-		node = of_graph_get_next_endpoint(parent, prev_node);
-		of_node_put(prev_node);
-		if (!node)
-			break;
+	struct device_node *node = NULL;
 
+	for_each_endpoint_of_node(parent, node) {
 		of_graph_parse_endpoint(node, &endpoint);
 		if (((port_reg == -1) || (endpoint.port == port_reg)) &&
 			((reg == -1) || (endpoint.id == reg)))
 			return node;
-
-		prev_node = node;
 	}
 
 	return NULL;
--- linux-4.4.0.orig/drivers/of/device.c
+++ linux-4.4.0/drivers/of/device.c
@@ -223,8 +223,9 @@
 			str[i] = '_';
 	}
 
-	return tsize;
+	return repend;
 }
+EXPORT_SYMBOL_GPL(of_device_get_modalias);
 
 /**
  * of_device_uevent - Display OF related uevent information
@@ -287,3 +288,4 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(of_device_uevent_modalias);
--- linux-4.4.0.orig/drivers/of/dynamic.c
+++ linux-4.4.0/drivers/of/dynamic.c
@@ -55,7 +55,7 @@
 	/* only remove properties if on sysfs */
 	if (of_node_is_attached(np)) {
 		for_each_property_of_node(np, pp)
-			sysfs_remove_bin_file(&np->kobj, &pp->attr);
+			__of_sysfs_remove_bin_file(np, pp);
 		kobject_del(&np->kobj);
 	}
 
--- linux-4.4.0.orig/drivers/of/fdt.c
+++ linux-4.4.0/drivers/of/fdt.c
@@ -632,9 +632,12 @@
 	const char *pathp;
 	int offset, rc = 0, depth = -1;
 
-        for (offset = fdt_next_node(blob, -1, &depth);
-             offset >= 0 && depth >= 0 && !rc;
-             offset = fdt_next_node(blob, offset, &depth)) {
+	if (!blob)
+		return 0;
+
+	for (offset = fdt_next_node(blob, -1, &depth);
+	     offset >= 0 && depth >= 0 && !rc;
+	     offset = fdt_next_node(blob, offset, &depth)) {
 
 		pathp = fdt_get_name(blob, offset, NULL);
 		if (*pathp == '/')
@@ -798,7 +801,7 @@
 #ifdef CONFIG_SERIAL_EARLYCON
 extern struct of_device_id __earlycon_of_table[];
 
-static int __init early_init_dt_scan_chosen_serial(void)
+int __init early_init_dt_scan_chosen_stdout(void)
 {
 	int offset;
 	const char *p;
@@ -843,15 +846,6 @@
 	}
 	return -ENODEV;
 }
-
-static int __init setup_of_earlycon(char *buf)
-{
-	if (buf)
-		return 0;
-
-	return early_init_dt_scan_chosen_serial();
-}
-early_param("earlycon", setup_of_earlycon);
 #endif
 
 /**
--- linux-4.4.0.orig/drivers/of/irq.c
+++ linux-4.4.0/drivers/of/irq.c
@@ -56,20 +56,19 @@
 struct device_node *of_irq_find_parent(struct device_node *child)
 {
 	struct device_node *p;
-	const __be32 *parp;
+	phandle parent;
 
 	if (!of_node_get(child))
 		return NULL;
 
 	do {
-		parp = of_get_property(child, "interrupt-parent", NULL);
-		if (parp == NULL)
+		if (of_property_read_u32(child, "interrupt-parent", &parent)) {
 			p = of_get_parent(child);
-		else {
+		} else	{
 			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
 				p = of_node_get(of_irq_dflt_pic);
 			else
-				p = of_find_node_by_phandle(be32_to_cpup(parp));
+				p = of_find_node_by_phandle(parent);
 		}
 		of_node_put(child);
 		child = p;
@@ -114,11 +113,8 @@
 	 * is none, we are nice and just walk up the tree
 	 */
 	do {
-		tmp = of_get_property(ipar, "#interrupt-cells", NULL);
-		if (tmp != NULL) {
-			intsize = be32_to_cpu(*tmp);
+		if (!of_property_read_u32(ipar, "#interrupt-cells", &intsize))
 			break;
-		}
 		tnode = ipar;
 		ipar = of_irq_find_parent(ipar);
 		of_node_put(tnode);
@@ -224,14 +220,14 @@
 			/* Get #interrupt-cells and #address-cells of new
 			 * parent
 			 */
-			tmp = of_get_property(newpar, "#interrupt-cells", NULL);
-			if (tmp == NULL) {
+			if (of_property_read_u32(newpar, "#interrupt-cells",
+						 &newintsize)) {
 				pr_debug(" -> parent lacks #interrupt-cells!\n");
 				goto fail;
 			}
-			newintsize = be32_to_cpu(*tmp);
-			tmp = of_get_property(newpar, "#address-cells", NULL);
-			newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);
+			if (of_property_read_u32(newpar, "#address-cells",
+						 &newaddrsize))
+				newaddrsize = 0;
 
 			pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
 			    newintsize, newaddrsize);
@@ -289,9 +285,10 @@
 int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
 {
 	struct device_node *p;
-	const __be32 *intspec, *tmp, *addr;
-	u32 intsize, intlen;
-	int i, res;
+	const __be32 *addr;
+	u32 intsize;
+	int i, res, addr_len;
+	__be32 addr_buf[3] = { 0 };
 
 	pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
 
@@ -300,22 +297,19 @@
 		return of_irq_parse_oldworld(device, index, out_irq);
 
 	/* Get the reg property (if any) */
-	addr = of_get_property(device, "reg", NULL);
+	addr = of_get_property(device, "reg", &addr_len);
+
+	/* Prevent out-of-bounds read in case of longer interrupt parent address size */
+	if (addr_len > (3 * sizeof(__be32)))
+		addr_len = 3 * sizeof(__be32);
+	if (addr)
+		memcpy(addr_buf, addr, addr_len);
 
 	/* Try the new-style interrupts-extended first */
 	res = of_parse_phandle_with_args(device, "interrupts-extended",
 					"#interrupt-cells", index, out_irq);
 	if (!res)
-		return of_irq_parse_raw(addr, out_irq);
-
-	/* Get the interrupts property */
-	intspec = of_get_property(device, "interrupts", &intlen);
-	if (intspec == NULL)
-		return -EINVAL;
-
-	intlen /= sizeof(*intspec);
-
-	pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
+		return of_irq_parse_raw(addr_buf, out_irq);
 
 	/* Look for the interrupt parent. */
 	p = of_irq_find_parent(device);
@@ -323,30 +317,29 @@
 		return -EINVAL;
 
 	/* Get size of interrupt specifier */
-	tmp = of_get_property(p, "#interrupt-cells", NULL);
-	if (tmp == NULL) {
+	if (of_property_read_u32(p, "#interrupt-cells", &intsize)) {
 		res = -EINVAL;
 		goto out;
 	}
-	intsize = be32_to_cpu(*tmp);
-
-	pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
 
-	/* Check index */
-	if ((index + 1) * intsize > intlen) {
-		res = -EINVAL;
-		goto out;
-	}
+	pr_debug(" parent=%pOF, intsize=%d\n", p, intsize);
 
 	/* Copy intspec into irq structure */
-	intspec += index * intsize;
 	out_irq->np = p;
 	out_irq->args_count = intsize;
-	for (i = 0; i < intsize; i++)
-		out_irq->args[i] = be32_to_cpup(intspec++);
+	for (i = 0; i < intsize; i++) {
+		res = of_property_read_u32_index(device, "interrupts",
+						 (index * intsize) + i,
+						 out_irq->args + i);
+		if (res)
+			goto out;
+	}
+
+	pr_debug(" intspec=%d\n", *out_irq->args);
+
 
 	/* Check if there are any interrupt-map translations to process */
-	res = of_irq_parse_raw(addr, out_irq);
+	res = of_irq_parse_raw(addr_buf, out_irq);
  out:
 	of_node_put(p);
 	return res;
@@ -386,13 +379,13 @@
 EXPORT_SYMBOL_GPL(of_irq_to_resource);
 
 /**
- * of_irq_get - Decode a node's IRQ and return it as a Linux irq number
+ * of_irq_get - Decode a node's IRQ and return it as a Linux IRQ number
  * @dev: pointer to device tree node
- * @index: zero-based index of the irq
- *
- * Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain
- * is not yet created.
+ * @index: zero-based index of the IRQ
  *
+ * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
+ * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
+ * of any other failure.
  */
 int of_irq_get(struct device_node *dev, int index)
 {
@@ -413,12 +406,13 @@
 EXPORT_SYMBOL_GPL(of_irq_get);
 
 /**
- * of_irq_get_byname - Decode a node's IRQ and return it as a Linux irq number
+ * of_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number
  * @dev: pointer to device tree node
- * @name: irq name
+ * @name: IRQ name
  *
- * Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain
- * is not yet created, or error code in case of any other failure.
+ * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
+ * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
+ * of any other failure.
  */
 int of_irq_get_byname(struct device_node *dev, const char *name)
 {
@@ -636,6 +630,13 @@
 		msi_base = be32_to_cpup(msi_map + 2);
 		rid_len = be32_to_cpup(msi_map + 3);
 
+		if (rid_base & ~map_mask) {
+			dev_err(parent_dev,
+				"Invalid msi-map translation - msi-map-mask (0x%x) ignores rid-base (0x%x)\n",
+				map_mask, rid_base);
+			return rid_out;
+		}
+
 		msi_controller_node = of_find_node_by_phandle(phandle);
 
 		matched = (masked_rid >= rid_base &&
@@ -655,7 +656,7 @@
 	if (!matched)
 		return rid_out;
 
-	rid_out = masked_rid + msi_base;
+	rid_out = masked_rid - rid_base + msi_base;
 	dev_dbg(dev,
 		"msi-map at: %s, using mask %08x, rid-base: %08x, msi-base: %08x, length: %08x, rid: %08x -> %08x\n",
 		dev_name(parent_dev), map_mask, rid_base, msi_base,
--- linux-4.4.0.orig/drivers/of/of_mdio.c
+++ linux-4.4.0/drivers/of/of_mdio.c
@@ -334,8 +334,11 @@
 		status.link = 1;
 		status.duplex = of_property_read_bool(fixed_link_node,
 						      "full-duplex");
-		if (of_property_read_u32(fixed_link_node, "speed", &status.speed))
+		if (of_property_read_u32(fixed_link_node, "speed",
+					 &status.speed)) {
+			of_node_put(fixed_link_node);
 			return -EINVAL;
+		}
 		status.pause = of_property_read_bool(fixed_link_node, "pause");
 		status.asym_pause = of_property_read_bool(fixed_link_node,
 							  "asym-pause");
--- linux-4.4.0.orig/drivers/of/of_numa.c
+++ linux-4.4.0/drivers/of/of_numa.c
@@ -0,0 +1,211 @@
+/*
+ * OF NUMA Parsing support.
+ *
+ * Copyright (C) 2015 - 2016 Cavium 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/nodemask.h>
+
+#include <asm/numa.h>
+
+/* define default numa node to 0 */
+#define DEFAULT_NODE 0
+
+/*
+ * Even though we connect cpus to numa domains later in SMP
+ * init, we need to know the node ids now for all cpus.
+*/
+static void __init of_numa_parse_cpu_nodes(void)
+{
+	u32 nid;
+	int r;
+	struct device_node *cpus;
+	struct device_node *np = NULL;
+
+	cpus = of_find_node_by_path("/cpus");
+	if (!cpus)
+		return;
+
+	for_each_child_of_node(cpus, np) {
+		/* Skip things that are not CPUs */
+		if (of_node_cmp(np->type, "cpu") != 0)
+			continue;
+
+		r = of_property_read_u32(np, "numa-node-id", &nid);
+		if (r)
+			continue;
+
+		pr_debug("NUMA: CPU on %u\n", nid);
+		if (nid >= MAX_NUMNODES)
+			pr_warn("NUMA: Node id %u exceeds maximum value\n",
+				nid);
+		else
+			node_set(nid, numa_nodes_parsed);
+	}
+}
+
+static int __init of_numa_parse_memory_nodes(void)
+{
+	struct device_node *np = NULL;
+	struct resource rsrc;
+	u32 nid;
+	int r = 0;
+
+	for (;;) {
+		np = of_find_node_by_type(np, "memory");
+		if (!np)
+			break;
+
+		r = of_property_read_u32(np, "numa-node-id", &nid);
+		if (r == -EINVAL)
+			/*
+			 * property doesn't exist if -EINVAL, continue
+			 * looking for more memory nodes with
+			 * "numa-node-id" property
+			 */
+			continue;
+		else if (r)
+			/* some other error */
+			break;
+
+		r = of_address_to_resource(np, 0, &rsrc);
+		if (r) {
+			pr_err("NUMA: bad reg property in memory node\n");
+			break;
+		}
+
+		pr_debug("NUMA:  base = %llx len = %llx, node = %u\n",
+			 rsrc.start, rsrc.end - rsrc.start + 1, nid);
+
+		r = numa_add_memblk(nid, rsrc.start,
+				    rsrc.end - rsrc.start + 1);
+		if (r)
+			break;
+	}
+	of_node_put(np);
+
+	return r;
+}
+
+static int __init of_numa_parse_distance_map_v1(struct device_node *map)
+{
+	const __be32 *matrix;
+	int entry_count;
+	int i;
+
+	pr_info("NUMA: parsing numa-distance-map-v1\n");
+
+	matrix = of_get_property(map, "distance-matrix", NULL);
+	if (!matrix) {
+		pr_err("NUMA: No distance-matrix property in distance-map\n");
+		return -EINVAL;
+	}
+
+	entry_count = of_property_count_u32_elems(map, "distance-matrix");
+	if (entry_count <= 0) {
+		pr_err("NUMA: Invalid distance-matrix\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i + 2 < entry_count; i += 3) {
+		u32 nodea, nodeb, distance;
+
+		nodea = of_read_number(matrix, 1);
+		matrix++;
+		nodeb = of_read_number(matrix, 1);
+		matrix++;
+		distance = of_read_number(matrix, 1);
+		matrix++;
+
+		numa_set_distance(nodea, nodeb, distance);
+		pr_debug("NUMA:  distance[node%d -> node%d] = %d\n",
+			 nodea, nodeb, distance);
+
+		/* Set default distance of node B->A same as A->B */
+		if (nodeb > nodea)
+			numa_set_distance(nodeb, nodea, distance);
+	}
+
+	return 0;
+}
+
+static int __init of_numa_parse_distance_map(void)
+{
+	int ret = 0;
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL,
+				     "numa-distance-map-v1");
+	if (np)
+		ret = of_numa_parse_distance_map_v1(np);
+
+	of_node_put(np);
+	return ret;
+}
+
+int of_node_to_nid(struct device_node *device)
+{
+	struct device_node *np;
+	u32 nid;
+	int r = -ENODATA;
+
+	np = of_node_get(device);
+
+	while (np) {
+		struct device_node *parent;
+
+		r = of_property_read_u32(np, "numa-node-id", &nid);
+		/*
+		 * -EINVAL indicates the property was not found, and
+		 *  we walk up the tree trying to find a parent with a
+		 *  "numa-node-id".  Any other type of error indicates
+		 *  a bad device tree and we give up.
+		 */
+		if (r != -EINVAL)
+			break;
+
+		parent = of_get_parent(np);
+		of_node_put(np);
+		np = parent;
+	}
+	if (np && r)
+		pr_warn("NUMA: Invalid \"numa-node-id\" property in node %s\n",
+			np->name);
+	of_node_put(np);
+
+	if (!r) {
+		if (nid >= MAX_NUMNODES)
+			pr_warn("NUMA: Node id %u exceeds maximum value\n",
+				nid);
+		else
+			return nid;
+	}
+
+	return NUMA_NO_NODE;
+}
+EXPORT_SYMBOL(of_node_to_nid);
+
+int __init of_numa_init(void)
+{
+	int r;
+
+	of_numa_parse_cpu_nodes();
+	r = of_numa_parse_memory_nodes();
+	if (r)
+		return r;
+	return of_numa_parse_distance_map();
+}
--- linux-4.4.0.orig/drivers/of/of_private.h
+++ linux-4.4.0/drivers/of/of_private.h
@@ -81,6 +81,9 @@
 extern void __of_detach_node(struct device_node *np);
 extern void __of_detach_node_sysfs(struct device_node *np);
 
+extern void __of_sysfs_remove_bin_file(struct device_node *np,
+				       struct property *prop);
+
 /* iterators for transactions, used for overlays */
 /* forward iterator */
 #define for_each_transaction_entry(_oft, _te) \
--- linux-4.4.0.orig/drivers/of/of_reserved_mem.c
+++ linux-4.4.0/drivers/of/of_reserved_mem.c
@@ -32,11 +32,13 @@
 	phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
 	phys_addr_t *res_base)
 {
+	phys_addr_t base;
 	/*
 	 * We use __memblock_alloc_base() because memblock_alloc_base()
 	 * panic()s on allocation failure.
 	 */
-	phys_addr_t base = __memblock_alloc_base(size, align, end);
+	end = !end ? MEMBLOCK_ALLOC_ANYWHERE : end;
+	base = __memblock_alloc_base(size, align, end);
 	if (!base)
 		return -ENOMEM;
 
@@ -125,8 +127,12 @@
 	}
 
 	/* Need adjust the alignment to satisfy the CMA requirement */
-	if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, "shared-dma-pool"))
-		align = max(align, (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
+	if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, "shared-dma-pool")) {
+		unsigned long order =
+			max_t(unsigned long, MAX_ORDER - 1, pageblock_order);
+
+		align = max(align, (phys_addr_t)PAGE_SIZE << order);
+	}
 
 	prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
 	if (prop) {
@@ -212,6 +218,16 @@
 	if (ra->base > rb->base)
 		return 1;
 
+	/*
+	 * Put the dynamic allocations (address == 0, size == 0) before static
+	 * allocations at address 0x0 so that overlap detection works
+	 * correctly.
+	 */
+	if (ra->size < rb->size)
+		return -1;
+	if (ra->size > rb->size)
+		return 1;
+
 	return 0;
 }
 
@@ -229,8 +245,7 @@
 
 		this = &reserved_mem[i];
 		next = &reserved_mem[i + 1];
-		if (!(this->base && next->base))
-			continue;
+
 		if (this->base + this->size > next->base) {
 			phys_addr_t this_end, next_end;
 
--- linux-4.4.0.orig/drivers/of/unittest.c
+++ linux-4.4.0/drivers/of/unittest.c
@@ -156,20 +156,20 @@
 	/* Add a new property - should pass*/
 	prop->name = "new-property";
 	prop->value = "new-property-data";
-	prop->length = strlen(prop->value);
+	prop->length = strlen(prop->value) + 1;
 	unittest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
 
 	/* Try to add an existing property - should fail */
 	prop++;
 	prop->name = "new-property";
 	prop->value = "new-property-data-should-fail";
-	prop->length = strlen(prop->value);
+	prop->length = strlen(prop->value) + 1;
 	unittest(of_add_property(np, prop) != 0,
 		 "Adding an existing property should have failed\n");
 
 	/* Try to modify an existing property - should pass */
 	prop->value = "modify-property-data-should-pass";
-	prop->length = strlen(prop->value);
+	prop->length = strlen(prop->value) + 1;
 	unittest(of_update_property(np, prop) == 0,
 		 "Updating an existing property should have passed\n");
 
@@ -177,7 +177,7 @@
 	prop++;
 	prop->name = "modify-property";
 	prop->value = "modify-missing-property-data-should-pass";
-	prop->length = strlen(prop->value);
+	prop->length = strlen(prop->value) + 1;
 	unittest(of_update_property(np, prop) == 0,
 		 "Updating a missing property should have passed\n");
 
@@ -553,6 +553,9 @@
 	struct of_phandle_args args;
 	int i, rc;
 
+	if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
+		return;
+
 	np = of_find_node_by_path("/testcase-data/interrupts/interrupts0");
 	if (!np) {
 		pr_err("missing testcase data\n");
@@ -627,6 +630,9 @@
 	struct of_phandle_args args;
 	int i, rc;
 
+	if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
+		return;
+
 	np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
 	if (!np) {
 		pr_err("missing testcase data\n");
@@ -778,15 +784,19 @@
 	pdev = of_find_device_by_node(np);
 	unittest(pdev, "device 1 creation failed\n");
 
-	irq = platform_get_irq(pdev, 0);
-	unittest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq);
-
-	/* Test that a parsing failure does not return -EPROBE_DEFER */
-	np = of_find_node_by_path("/testcase-data/testcase-device2");
-	pdev = of_find_device_by_node(np);
-	unittest(pdev, "device 2 creation failed\n");
-	irq = platform_get_irq(pdev, 0);
-	unittest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
+	if (!(of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)) {
+		irq = platform_get_irq(pdev, 0);
+		unittest(irq == -EPROBE_DEFER,
+			 "device deferred probe failed - %d\n", irq);
+
+		/* Test that a parsing failure does not return -EPROBE_DEFER */
+		np = of_find_node_by_path("/testcase-data/testcase-device2");
+		pdev = of_find_device_by_node(np);
+		unittest(pdev, "device 2 creation failed\n");
+		irq = platform_get_irq(pdev, 0);
+		unittest(irq < 0 && irq != -EPROBE_DEFER,
+			 "device parsing error failed - %d\n", irq);
+	}
 
 	np = of_find_node_by_path("/testcase-data/platform-tests");
 	unittest(np, "No testcase data in device tree\n");
@@ -802,10 +812,13 @@
 
 	of_platform_populate(np, match, NULL, &test_bus->dev);
 	for_each_child_of_node(np, child) {
-		for_each_child_of_node(child, grandchild)
-			unittest(of_find_device_by_node(grandchild),
+		for_each_child_of_node(child, grandchild) {
+			pdev = of_find_device_by_node(grandchild);
+			unittest(pdev,
 				 "Could not create device for node '%s'\n",
 				 grandchild->name);
+			of_dev_put(pdev);
+		}
 	}
 
 	of_platform_depopulate(&test_bus->dev);
@@ -914,6 +927,7 @@
 	of_fdt_unflatten_tree(unittest_data, &unittest_data_node);
 	if (!unittest_data_node) {
 		pr_warn("%s: No tree to attach; not running tests\n", __func__);
+		kfree(unittest_data);
 		return -ENODATA;
 	}
 	of_node_set_flag(unittest_data_node, OF_DETACHED);
--- linux-4.4.0.orig/drivers/parisc/ccio-dma.c
+++ linux-4.4.0/drivers/parisc/ccio-dma.c
@@ -563,8 +563,6 @@
 	/* We currently only support kernel addresses */
 	BUG_ON(sid != KERNEL_SPACE);
 
-	mtsp(sid,1);
-
 	/*
 	** WORD 1 - low order word
 	** "hints" parm includes the VALID bit!
@@ -595,7 +593,7 @@
 	** Grab virtual index [0:11]
 	** Deposit virt_idx bits into I/O PDIR word
 	*/
-	asm volatile ("lci %%r0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
+	asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba));
 	asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci));
 	asm volatile ("depw  %1,15,12,%0" : "+r" (pa) : "r" (ci));
 
@@ -741,6 +739,8 @@
 
 	BUG_ON(!dev);
 	ioc = GET_IOC(dev);
+	if (!ioc)
+		return DMA_ERROR_CODE;
 
 	BUG_ON(size <= 0);
 
@@ -805,6 +805,10 @@
 	
 	BUG_ON(!dev);
 	ioc = GET_IOC(dev);
+	if (!ioc) {
+		WARN_ON(!ioc);
+		return;
+	}
 
 	DBG_RUN("%s() iovp 0x%lx/%x\n",
 		__func__, (long)iova, size);
@@ -908,6 +912,8 @@
 	
 	BUG_ON(!dev);
 	ioc = GET_IOC(dev);
+	if (!ioc)
+		return 0;
 	
 	DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
 
@@ -980,6 +986,10 @@
 
 	BUG_ON(!dev);
 	ioc = GET_IOC(dev);
+	if (!ioc) {
+		WARN_ON(!ioc);
+		return;
+	}
 
 	DBG_RUN_SG("%s() START %d entries, %p,%x\n",
 		__func__, nents, sg_virt(sglist), sglist->length);
--- linux-4.4.0.orig/drivers/parisc/dino.c
+++ linux-4.4.0/drivers/parisc/dino.c
@@ -154,9 +154,21 @@
 };
 
 /* Looks nice and keeps the compiler happy */
-#define DINO_DEV(d) ((struct dino_device *) d)
+#define DINO_DEV(d) ({				\
+	void *__pdata = d;			\
+	BUG_ON(!__pdata);			\
+	(struct dino_device *)__pdata; })
 
 
+/* Check if PCI device is behind a Card-mode Dino. */
+static int pci_dev_is_behind_card_dino(struct pci_dev *dev)
+{
+	struct dino_device *dino_dev;
+
+	dino_dev = DINO_DEV(parisc_walk_tree(dev->bus->bridge));
+	return is_card_dino(&dino_dev->hba.dev->id);
+}
+
 /*
  * Dino Configuration Space Accessor Functions
  */
@@ -439,6 +451,21 @@
 }
 DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus );
 
+#ifdef CONFIG_TULIP
+static void pci_fixup_tulip(struct pci_dev *dev)
+{
+	if (!pci_dev_is_behind_card_dino(dev))
+		return;
+	if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM))
+		return;
+	pr_warn("%s: HP HSC-PCI Cards with card-mode Dino not yet supported.\n",
+		pci_name(dev));
+	/* Disable this card by zeroing the PCI resources */
+	memset(&dev->resource[0], 0, sizeof(dev->resource[0]));
+	memset(&dev->resource[1], 0, sizeof(dev->resource[1]));
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_DEC, PCI_ANY_ID, pci_fixup_tulip);
+#endif /* CONFIG_TULIP */
 
 static void __init
 dino_bios_init(void)
@@ -951,7 +978,7 @@
 
 	dino_dev->hba.dev = dev;
 	dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096);
-	dino_dev->hba.lmmio_space_offset = 0;	/* CPU addrs == bus addrs */
+	dino_dev->hba.lmmio_space_offset = PCI_F_EXTEND;
 	spin_lock_init(&dino_dev->dinosaur_pen);
 	dino_dev->hba.iommu = ccio_get_iommu(dev);
 
--- linux-4.4.0.orig/drivers/parisc/lba_pci.c
+++ linux-4.4.0/drivers/parisc/lba_pci.c
@@ -111,8 +111,10 @@
 
 
 /* Looks nice and keeps the compiler happy */
-#define LBA_DEV(d) ((struct lba_device *) (d))
-
+#define LBA_DEV(d) ({				\
+	void *__pdata = d;			\
+	BUG_ON(!__pdata);			\
+	(struct lba_device *)__pdata; })
 
 /*
 ** Only allow 8 subsidiary busses per LBA
@@ -1363,9 +1365,27 @@
 		WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG);
 	}
 
-	/* Set HF mode as the default (vs. -1 mode). */
+
+	/*
+	 * Hard Fail vs. Soft Fail on PCI "Master Abort".
+	 *
+	 * "Master Abort" means the MMIO transaction timed out - usually due to
+	 * the device not responding to an MMIO read. We would like HF to be
+	 * enabled to find driver problems, though it means the system will
+	 * crash with a HPMC.
+	 *
+	 * In SoftFail mode "~0L" is returned as a result of a timeout on the
+	 * pci bus. This is like how PCI busses on x86 and most other
+	 * architectures behave.  In order to increase compatibility with
+	 * existing (x86) PCI hardware and existing Linux drivers we enable
+	 * Soft Faul mode on PA-RISC now too.
+	 */
         stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);
+#if defined(ENABLE_HARDFAIL)
 	WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
+#else
+	WRITE_REG32(stat & ~HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
+#endif
 
 	/*
 	** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal
@@ -1652,3 +1672,36 @@
 	iounmap(base_addr);
 }
 
+
+/*
+ * The design of the Diva management card in rp34x0 machines (rp3410, rp3440)
+ * seems rushed, so that many built-in components simply don't work.
+ * The following quirks disable the serial AUX port and the built-in ATI RV100
+ * Radeon 7000 graphics card which both don't have any external connectors and
+ * thus are useless, and even worse, e.g. the AUX port occupies ttyS0 and as
+ * such makes those machines the only PARISC machines on which we can't use
+ * ttyS0 as boot console.
+ */
+static void quirk_diva_ati_card(struct pci_dev *dev)
+{
+	if (dev->subsystem_vendor != PCI_VENDOR_ID_HP ||
+	    dev->subsystem_device != 0x1292)
+		return;
+
+	dev_info(&dev->dev, "Hiding Diva built-in ATI card");
+	dev->device = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY,
+	quirk_diva_ati_card);
+
+static void quirk_diva_aux_disable(struct pci_dev *dev)
+{
+	if (dev->subsystem_vendor != PCI_VENDOR_ID_HP ||
+	    dev->subsystem_device != 0x1291)
+		return;
+
+	dev_info(&dev->dev, "Hiding Diva built-in AUX serial device");
+	dev->device = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
+	quirk_diva_aux_disable);
--- linux-4.4.0.orig/drivers/parisc/sba_iommu.c
+++ linux-4.4.0/drivers/parisc/sba_iommu.c
@@ -573,8 +573,7 @@
 	pa = virt_to_phys(vba);
 	pa &= IOVP_MASK;
 
-	mtsp(sid,1);
-	asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
+	asm("lci 0(%1), %0" : "=r" (ci) : "r" (vba));
 	pa |= (ci >> PAGE_SHIFT) & 0xff;  /* move CI (8 bits) into lowest byte */
 
 	pa |= SBA_PDIR_VALID_BIT;	/* set "valid" bit */
@@ -691,6 +690,8 @@
 		return 0;
 
 	ioc = GET_IOC(dev);
+	if (!ioc)
+		return 0;
 
 	/*
 	 * check if mask is >= than the current max IO Virt Address
@@ -722,6 +723,8 @@
 	int pide;
 
 	ioc = GET_IOC(dev);
+	if (!ioc)
+		return DMA_ERROR_CODE;
 
 	/* save offset bits */
 	offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
@@ -803,6 +806,10 @@
 	DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size);
 
 	ioc = GET_IOC(dev);
+	if (!ioc) {
+		WARN_ON(!ioc);
+		return;
+	}
 	offset = iova & ~IOVP_MASK;
 	iova ^= offset;        /* clear offset bits */
 	size += offset;
@@ -942,6 +949,8 @@
 	DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
 
 	ioc = GET_IOC(dev);
+	if (!ioc)
+		return 0;
 
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
@@ -1027,6 +1036,10 @@
 		__func__, nents, sg_virt(sglist), sglist->length);
 
 	ioc = GET_IOC(dev);
+	if (!ioc) {
+		WARN_ON(!ioc);
+		return;
+	}
 
 #ifdef SBA_COLLECT_STATS
 	ioc->usg_calls++;
@@ -1264,7 +1277,7 @@
 	** (one that doesn't overlap memory or LMMIO space) in the
 	** IBASE and IMASK registers.
 	*/
-	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE);
+	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & ~0x1fffffULL;
 	iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
 
 	if ((ioc->ibase < 0xfed00000UL) && ((ioc->ibase + iova_space_size) > 0xfee00000UL)) {
--- linux-4.4.0.orig/drivers/parport/parport_gsc.c
+++ linux-4.4.0/drivers/parport/parport_gsc.c
@@ -293,7 +293,7 @@
 		p->irq = PARPORT_IRQ_NONE;
 	}
 	if (p->irq != PARPORT_IRQ_NONE) {
-		printk(", irq %d", p->irq);
+		pr_cont(", irq %d", p->irq);
 
 		if (p->dma == PARPORT_DMA_AUTO) {
 			p->dma = PARPORT_DMA_NONE;
@@ -303,8 +303,8 @@
                                            is mandatory (see above) */
 		p->dma = PARPORT_DMA_NONE;
 
-	printk(" [");
-#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
+	pr_cont(" [");
+#define printmode(x) {if(p->modes&PARPORT_MODE_##x){pr_cont("%s%s",f?",":"",#x);f++;}}
 	{
 		int f = 0;
 		printmode(PCSPP);
@@ -315,7 +315,7 @@
 //		printmode(DMA);
 	}
 #undef printmode
-	printk("]\n");
+	pr_cont("]\n");
 
 	if (p->irq != PARPORT_IRQ_NONE) {
 		if (request_irq (p->irq, parport_irq_handler,
--- linux-4.4.0.orig/drivers/parport/parport_pc.c
+++ linux-4.4.0/drivers/parport/parport_pc.c
@@ -1377,7 +1377,7 @@
 {
 	int i;
 	for (i = 0; i < NR_SUPERIOS; i++)
-		if (superios[i].io != p->base)
+		if (superios[i].io == p->base)
 			return &superios[i];
 	return NULL;
 }
@@ -2646,6 +2646,7 @@
 	netmos_9901,
 	netmos_9865,
 	quatech_sppxp100,
+	wch_ch382l,
 };
 
 
@@ -2708,6 +2709,7 @@
 	/* netmos_9901 */               { 1, { { 0, -1 }, } },
 	/* netmos_9865 */               { 1, { { 0, -1 }, } },
 	/* quatech_sppxp100 */		{ 1, { { 0, 1 }, } },
+	/* wch_ch382l */		{ 1, { { 2, -1 }, } },
 };
 
 static const struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2797,6 +2799,8 @@
 	/* Quatech SPPXP-100 Parallel port PCI ExpressCard */
 	{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
+	/* WCH CH382L PCI-E single parallel port card */
+	{ 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l },
 	{ 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl);
@@ -3150,13 +3154,13 @@
 static char *dma[PARPORT_PC_MAX_PORTS];
 
 MODULE_PARM_DESC(io, "Base I/O address (SPP regs)");
-module_param_array(io, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
 MODULE_PARM_DESC(io_hi, "Base I/O address (ECR)");
-module_param_array(io_hi, int, NULL, 0);
+module_param_hw_array(io_hi, int, ioport, NULL, 0);
 MODULE_PARM_DESC(irq, "IRQ line");
-module_param_array(irq, charp, NULL, 0);
+module_param_hw_array(irq, charp, irq, NULL, 0);
 MODULE_PARM_DESC(dma, "DMA channel");
-module_param_array(dma, charp, NULL, 0);
+module_param_hw_array(dma, charp, dma, NULL, 0);
 #if defined(CONFIG_PARPORT_PC_SUPERIO) || \
        (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO))
 MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
--- linux-4.4.0.orig/drivers/parport/parport_sunbpp.c
+++ linux-4.4.0/drivers/parport/parport_sunbpp.c
@@ -286,12 +286,16 @@
 
 	ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations),
 		      GFP_KERNEL);
-        if (!ops)
+	if (!ops) {
+		err = -ENOMEM;
 		goto out_unmap;
+	}
 
 	dprintk(("register_port\n"));
-	if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
+	if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) {
+		err = -ENOMEM;
 		goto out_free_ops;
+	}
 
 	p->size = size;
 	p->dev = &op->dev;
--- linux-4.4.0.orig/drivers/parport/procfs.c
+++ linux-4.4.0/drivers/parport/procfs.c
@@ -50,12 +50,12 @@
 	
 	for (dev = port->devices; dev ; dev = dev->next) {
 		if(dev == port->cad) {
-			len += sprintf(buffer, "%s\n", dev->name);
+			len += scnprintf(buffer, sizeof(buffer), "%s\n", dev->name);
 		}
 	}
 
 	if(!len) {
-		len += sprintf(buffer, "%s\n", "none");
+		len += scnprintf(buffer, sizeof(buffer), "%s\n", "none");
 	}
 
 	if (len > *lenp)
@@ -86,19 +86,19 @@
 	}
 	
 	if ((str = info->class_name) != NULL)
-		len += sprintf (buffer + len, "CLASS:%s;\n", str);
+		len += scnprintf (buffer + len, sizeof(buffer) - len, "CLASS:%s;\n", str);
 
 	if ((str = info->model) != NULL)
-		len += sprintf (buffer + len, "MODEL:%s;\n", str);
+		len += scnprintf (buffer + len, sizeof(buffer) - len, "MODEL:%s;\n", str);
 
 	if ((str = info->mfr) != NULL)
-		len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
+		len += scnprintf (buffer + len, sizeof(buffer) - len, "MANUFACTURER:%s;\n", str);
 
 	if ((str = info->description) != NULL)
-		len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
+		len += scnprintf (buffer + len, sizeof(buffer) - len, "DESCRIPTION:%s;\n", str);
 
 	if ((str = info->cmdset) != NULL)
-		len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
+		len += scnprintf (buffer + len, sizeof(buffer) - len, "COMMAND SET:%s;\n", str);
 
 	if (len > *lenp)
 		len = *lenp;
@@ -116,7 +116,7 @@
 				 size_t *lenp, loff_t *ppos)
 {
 	struct parport *port = (struct parport *)table->extra1;
-	char buffer[20];
+	char buffer[64];
 	int len = 0;
 
 	if (*ppos) {
@@ -127,7 +127,7 @@
 	if (write) /* permissions prevent this anyway */
 		return -EACCES;
 
-	len += sprintf (buffer, "%lu\t%lu\n", port->base, port->base_hi);
+	len += scnprintf (buffer, sizeof(buffer), "%lu\t%lu\n", port->base, port->base_hi);
 
 	if (len > *lenp)
 		len = *lenp;
@@ -155,7 +155,7 @@
 	if (write) /* permissions prevent this anyway */
 		return -EACCES;
 
-	len += sprintf (buffer, "%d\n", port->irq);
+	len += scnprintf (buffer, sizeof(buffer), "%d\n", port->irq);
 
 	if (len > *lenp)
 		len = *lenp;
@@ -183,7 +183,7 @@
 	if (write) /* permissions prevent this anyway */
 		return -EACCES;
 
-	len += sprintf (buffer, "%d\n", port->dma);
+	len += scnprintf (buffer, sizeof(buffer), "%d\n", port->dma);
 
 	if (len > *lenp)
 		len = *lenp;
@@ -212,7 +212,11 @@
 		return -EACCES;
 
 	{
-#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
+#define printmode(x)							\
+do {									\
+	if (port->modes & PARPORT_MODE_##x)				\
+		len += scnprintf(buffer + len, sizeof(buffer) - len, "%s%s", f++ ? "," : "", #x); \
+} while (0)
 		int f = 0;
 		printmode(PCSPP);
 		printmode(TRISTATE);
--- linux-4.4.0.orig/drivers/parport/share.c
+++ linux-4.4.0/drivers/parport/share.c
@@ -228,6 +228,18 @@
 	return 0;
 }
 
+/*
+ * Iterates through all the devices connected to the bus and return 1
+ * if the device is a parallel port.
+ */
+
+static int port_detect(struct device *dev, void *dev_drv)
+{
+	if (is_parport(dev))
+		return 1;
+	return 0;
+}
+
 /**
  *	parport_register_driver - register a parallel port device driver
  *	@drv: structure describing the driver
@@ -280,6 +292,15 @@
 		if (ret)
 			return ret;
 
+		/*
+		 * check if bus has any parallel port registered, if
+		 * none is found then load the lowlevel driver.
+		 */
+		ret = bus_for_each_dev(&parport_bus_type, NULL, NULL,
+				       port_detect);
+		if (!ret)
+			get_lowlevel_driver();
+
 		mutex_lock(&registration_lock);
 		if (drv->match_port)
 			bus_for_each_dev(&parport_bus_type, NULL, drv,
@@ -892,6 +913,7 @@
 	par_dev->devmodel = true;
 	ret = device_register(&par_dev->dev);
 	if (ret) {
+		kfree(par_dev->state);
 		put_device(&par_dev->dev);
 		goto err_put_port;
 	}
@@ -909,6 +931,7 @@
 			spin_unlock(&port->physport->pardevice_lock);
 			pr_debug("%s: cannot grant exclusive access for device %s\n",
 				 port->name, name);
+			kfree(par_dev->state);
 			device_unregister(&par_dev->dev);
 			goto err_put_port;
 		}
@@ -936,8 +959,10 @@
 	 * pardevice fields. -arca
 	 */
 	port->ops->init_state(par_dev, par_dev->state);
-	port->proc_device = par_dev;
-	parport_device_proc_register(par_dev);
+	if (!test_and_set_bit(PARPORT_DEVPROC_REGISTERED, &port->devflags)) {
+		port->proc_device = par_dev;
+		parport_device_proc_register(par_dev);
+	}
 
 	return par_dev;
 
--- linux-4.4.0.orig/drivers/pci/Kconfig
+++ linux-4.4.0/drivers/pci/Kconfig
@@ -80,6 +80,9 @@
 config PCI_ATS
 	bool
 
+config PCI_ECAM
+	bool
+
 config PCI_IOV
 	bool "PCI IOV support"
 	depends on PCI
@@ -118,4 +121,11 @@
 	def_bool y if (DMI || ACPI)
 	select NLS
 
+config PCI_HYPERV
+        tristate "Hyper-V PCI Frontend"
+        depends on PCI && X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64
+        help
+          The PCI device frontend driver allows the kernel to import arbitrary
+          PCI devices from a PCI backend to support PCI driver domains.
+
 source "drivers/pci/host/Kconfig"
--- linux-4.4.0.orig/drivers/pci/Makefile
+++ linux-4.4.0/drivers/pci/Makefile
@@ -54,6 +54,8 @@
 
 obj-$(CONFIG_PCI_STUB) += pci-stub.o
 
+obj-$(CONFIG_PCI_ECAM) += ecam.o
+
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
 
 obj-$(CONFIG_OF) += of.o
--- linux-4.4.0.orig/drivers/pci/bus.c
+++ linux-4.4.0/drivers/pci/bus.c
@@ -140,6 +140,8 @@
 	type_mask |= IORESOURCE_TYPE_BITS;
 
 	pci_bus_for_each_resource(bus, r, i) {
+		resource_size_t min_used = min;
+
 		if (!r)
 			continue;
 
@@ -163,12 +165,12 @@
 		 * overrides "min".
 		 */
 		if (avail.start)
-			min = avail.start;
+			min_used = avail.start;
 
 		max = avail.end;
 
 		/* Ok, try it out.. */
-		ret = allocate_resource(r, res, size, min, max,
+		ret = allocate_resource(r, res, size, min_used, max,
 					align, alignf, alignf_data);
 		if (ret == 0)
 			return 0;
--- linux-4.4.0.orig/drivers/pci/ecam.c
+++ linux-4.4.0/drivers/pci/ecam.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci-ecam.h>
+#include <linux/slab.h>
+
+/*
+ * On 64-bit systems, we do a single ioremap for the whole config space
+ * since we have enough virtual address range available.  On 32-bit, we
+ * ioremap the config space for each bus individually.
+ */
+static const bool per_bus_mapping = !config_enabled(CONFIG_64BIT);
+
+/*
+ * Create a PCI config space window
+ *  - reserve mem region
+ *  - alloc struct pci_config_window with space for all mappings
+ *  - ioremap the config space
+ */
+struct pci_config_window *pci_ecam_create(struct device *dev,
+		struct resource *cfgres, struct resource *busr,
+		struct pci_ecam_ops *ops)
+{
+	struct pci_config_window *cfg;
+	unsigned int bus_range, bus_range_max, bsz;
+	struct resource *conflict;
+	int i, err;
+
+	if (busr->start > busr->end)
+		return ERR_PTR(-EINVAL);
+
+	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	cfg->parent = dev;
+	cfg->ops = ops;
+	cfg->busr.start = busr->start;
+	cfg->busr.end = busr->end;
+	cfg->busr.flags = IORESOURCE_BUS;
+	bus_range = resource_size(&cfg->busr);
+	bus_range_max = resource_size(cfgres) >> ops->bus_shift;
+	if (bus_range > bus_range_max) {
+		bus_range = bus_range_max;
+		cfg->busr.end = busr->start + bus_range - 1;
+		dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n",
+			 cfgres, &cfg->busr, busr);
+	}
+	bsz = 1 << ops->bus_shift;
+
+	cfg->res.start = cfgres->start;
+	cfg->res.end = cfgres->end;
+	cfg->res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+	cfg->res.name = "PCI ECAM";
+
+	conflict = request_resource_conflict(&iomem_resource, &cfg->res);
+	if (conflict) {
+		err = -EBUSY;
+		dev_err(dev, "can't claim ECAM area %pR: address conflict with %s %pR\n",
+			&cfg->res, conflict->name, conflict);
+		goto err_exit;
+	}
+
+	if (per_bus_mapping) {
+		cfg->winp = kcalloc(bus_range, sizeof(*cfg->winp), GFP_KERNEL);
+		if (!cfg->winp)
+			goto err_exit_malloc;
+		for (i = 0; i < bus_range; i++) {
+			cfg->winp[i] = ioremap(cfgres->start + i * bsz, bsz);
+			if (!cfg->winp[i])
+				goto err_exit_iomap;
+		}
+	} else {
+		cfg->win = ioremap(cfgres->start, bus_range * bsz);
+		if (!cfg->win)
+			goto err_exit_iomap;
+	}
+
+	if (ops->init) {
+		err = ops->init(cfg);
+		if (err)
+			goto err_exit;
+	}
+	dev_info(dev, "ECAM at %pR for %pR\n", &cfg->res, &cfg->busr);
+	return cfg;
+
+err_exit_iomap:
+	dev_err(dev, "ECAM ioremap failed\n");
+err_exit_malloc:
+	err = -ENOMEM;
+err_exit:
+	pci_ecam_free(cfg);
+	return ERR_PTR(err);
+}
+
+void pci_ecam_free(struct pci_config_window *cfg)
+{
+	int i;
+
+	if (per_bus_mapping) {
+		if (cfg->winp) {
+			for (i = 0; i < resource_size(&cfg->busr); i++)
+				if (cfg->winp[i])
+					iounmap(cfg->winp[i]);
+			kfree(cfg->winp);
+		}
+	} else {
+		if (cfg->win)
+			iounmap(cfg->win);
+	}
+	if (cfg->res.parent)
+		release_resource(&cfg->res);
+	kfree(cfg);
+}
+
+/*
+ * Function to implement the pci_ops ->map_bus method
+ */
+void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
+			       int where)
+{
+	struct pci_config_window *cfg = bus->sysdata;
+	unsigned int devfn_shift = cfg->ops->bus_shift - 8;
+	unsigned int busn = bus->number;
+	void __iomem *base;
+
+	if (busn < cfg->busr.start || busn > cfg->busr.end)
+		return NULL;
+
+	busn -= cfg->busr.start;
+	if (per_bus_mapping)
+		base = cfg->winp[busn];
+	else
+		base = cfg->win + (busn << cfg->ops->bus_shift);
+	return base + (devfn << devfn_shift) + where;
+}
+
+/* ECAM ops */
+struct pci_ecam_ops pci_generic_ecam_ops = {
+	.bus_shift	= 20,
+	.pci_ops	= {
+		.map_bus	= pci_ecam_map_bus,
+		.read		= pci_generic_config_read,
+		.write		= pci_generic_config_write,
+	}
+};
--- linux-4.4.0.orig/drivers/pci/host/Kconfig
+++ linux-4.4.0/drivers/pci/host/Kconfig
@@ -54,9 +54,14 @@
 	help
 	  Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
 
+config PCI_HOST_COMMON
+	bool
+	select PCI_ECAM
+
 config PCI_HOST_GENERIC
 	bool "Generic PCI host controller"
 	depends on (ARM || ARM64) && OF
+	select PCI_HOST_COMMON
 	help
 	  Say Y here if you want to support a simple generic PCI host
 	  controller, such as the one emulated by kvmtool.
@@ -173,4 +178,18 @@
 	help
 	  Say Y here if you want PCIe controller support on HiSilicon HIP05 SoC
 
+config PCI_HOST_THUNDER_PEM
+	bool "Cavium Thunder PCIe controller to off-chip devices"
+	depends on OF && ARM64
+	select PCI_HOST_COMMON
+	help
+	  Say Y here if you want PCIe support for CN88XX Cavium Thunder SoCs.
+
+config PCI_HOST_THUNDER_ECAM
+	bool "Cavium Thunder ECAM controller to on-chip devices on pass-1.x silicon"
+	depends on OF && ARM64
+	select PCI_HOST_COMMON
+	help
+	  Say Y here if you want ECAM support for CN88XX-Pass-1.x Cavium Thunder SoCs.
+
 endmenu
--- linux-4.4.0.orig/drivers/pci/host/Makefile
+++ linux-4.4.0/drivers/pci/host/Makefile
@@ -2,10 +2,12 @@
 obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
 obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
 obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
+obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
 obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
 obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
@@ -20,3 +22,5 @@
 obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
 obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
 obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
+obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
+obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
--- linux-4.4.0.orig/drivers/pci/host/pci-dra7xx.c
+++ linux-4.4.0/drivers/pci/host/pci-dra7xx.c
@@ -302,7 +302,8 @@
 	}
 
 	ret = devm_request_irq(&pdev->dev, pp->irq,
-			       dra7xx_pcie_msi_irq_handler, IRQF_SHARED,
+			       dra7xx_pcie_msi_irq_handler,
+			       IRQF_SHARED | IRQF_NO_THREAD,
 			       "dra7-pcie-msi",	pp);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request irq\n");
--- linux-4.4.0.orig/drivers/pci/host/pci-exynos.c
+++ linux-4.4.0/drivers/pci/host/pci-exynos.c
@@ -522,7 +522,8 @@
 
 		ret = devm_request_irq(&pdev->dev, pp->msi_irq,
 					exynos_pcie_msi_irq_handler,
-					IRQF_SHARED, "exynos-pcie", pp);
+					IRQF_SHARED | IRQF_NO_THREAD,
+					"exynos-pcie", pp);
 		if (ret) {
 			dev_err(&pdev->dev, "failed to request msi irq\n");
 			return ret;
--- linux-4.4.0.orig/drivers/pci/host/pci-host-common.c
+++ linux-4.4.0/drivers/pci/host/pci-host-common.c
@@ -0,0 +1,171 @@
+/*
+ * This program is free software; you can 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/>.
+ *
+ * Copyright (C) 2014 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
+#include <linux/platform_device.h>
+
+static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
+		       struct list_head *resources, struct resource **bus_range)
+{
+	int err, res_valid = 0;
+	struct device_node *np = dev->of_node;
+	resource_size_t iobase;
+	struct resource_entry *win;
+
+	err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase);
+	if (err)
+		return err;
+
+	resource_list_for_each_entry(win, resources) {
+		struct resource *parent, *res = win->res;
+
+		switch (resource_type(res)) {
+		case IORESOURCE_IO:
+			parent = &ioport_resource;
+			err = pci_remap_iospace(res, iobase);
+			if (err) {
+				dev_warn(dev, "error %d: failed to map resource %pR\n",
+					 err, res);
+				continue;
+			}
+			break;
+		case IORESOURCE_MEM:
+			parent = &iomem_resource;
+			res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+			break;
+		case IORESOURCE_BUS:
+			*bus_range = res;
+		default:
+			continue;
+		}
+
+		err = devm_request_resource(dev, parent, res);
+		if (err)
+			goto out_release_res;
+	}
+
+	if (!res_valid) {
+		dev_err(dev, "non-prefetchable memory resource required\n");
+		err = -EINVAL;
+		goto out_release_res;
+	}
+
+	return 0;
+
+out_release_res:
+	return err;
+}
+
+static void gen_pci_unmap_cfg(void *ptr)
+{
+	pci_ecam_free((struct pci_config_window *)ptr);
+}
+
+static struct pci_config_window *gen_pci_init(struct device *dev,
+		struct list_head *resources, struct pci_ecam_ops *ops)
+{
+	int err;
+	struct resource cfgres;
+	struct resource *bus_range = NULL;
+	struct pci_config_window *cfg;
+
+	/* Parse our PCI ranges and request their resources */
+	err = gen_pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
+	if (err)
+		goto err_out;
+
+	err = of_address_to_resource(dev->of_node, 0, &cfgres);
+	if (err) {
+		dev_err(dev, "missing \"reg\" property\n");
+		goto err_out;
+	}
+
+	cfg = pci_ecam_create(dev, &cfgres, bus_range, ops);
+	if (IS_ERR(cfg)) {
+		err = PTR_ERR(cfg);
+		goto err_out;
+	}
+
+	err = devm_add_action(dev, gen_pci_unmap_cfg, cfg);
+	if (err) {
+		gen_pci_unmap_cfg(cfg);
+		goto err_out;
+	}
+	return cfg;
+
+err_out:
+	pci_free_resource_list(resources);
+	return ERR_PTR(err);
+}
+
+int pci_host_common_probe(struct platform_device *pdev,
+			  struct pci_ecam_ops *ops)
+{
+	const char *type;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct pci_bus *bus, *child;
+	struct pci_config_window *cfg;
+	struct list_head resources;
+
+	type = of_get_property(np, "device_type", NULL);
+	if (!type || strcmp(type, "pci")) {
+		dev_err(dev, "invalid \"device_type\" %s\n", type);
+		return -EINVAL;
+	}
+
+	of_pci_check_probe_only();
+
+	/* Parse and map our Configuration Space windows */
+	INIT_LIST_HEAD(&resources);
+	cfg = gen_pci_init(dev, &resources, ops);
+	if (IS_ERR(cfg))
+		return PTR_ERR(cfg);
+
+	/* Do not reassign resources if probe only */
+	if (!pci_has_flag(PCI_PROBE_ONLY))
+		pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
+
+	bus = pci_scan_root_bus(dev, cfg->busr.start, &ops->pci_ops, cfg,
+				&resources);
+	if (!bus) {
+		dev_err(dev, "Scanning rootbus failed");
+		return -ENODEV;
+	}
+
+	pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
+
+	if (!pci_has_flag(PCI_PROBE_ONLY)) {
+		pci_bus_size_bridges(bus);
+		pci_bus_assign_resources(bus);
+
+		list_for_each_entry(child, &bus->children, node)
+			pcie_bus_configure_settings(child);
+	}
+
+	pci_bus_add_devices(bus);
+	return 0;
+}
+
+MODULE_DESCRIPTION("Generic PCI host driver common code");
+MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/pci/host/pci-host-generic.c
+++ linux-4.4.0/drivers/pci/host/pci-host-generic.c
@@ -23,69 +23,13 @@
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-struct gen_pci_cfg_bus_ops {
-	u32 bus_shift;
-	struct pci_ops ops;
-};
-
-struct gen_pci_cfg_windows {
-	struct resource				res;
-	struct resource				*bus_range;
-	void __iomem				**win;
-
-	struct gen_pci_cfg_bus_ops		*ops;
-};
-
-/*
- * ARM pcibios functions expect the ARM struct pci_sys_data as the PCI
- * sysdata.  Add pci_sys_data as the first element in struct gen_pci so
- * that when we use a gen_pci pointer as sysdata, it is also a pointer to
- * a struct pci_sys_data.
- */
-struct gen_pci {
-#ifdef CONFIG_ARM
-	struct pci_sys_data			sys;
-#endif
-	struct pci_host_bridge			host;
-	struct gen_pci_cfg_windows		cfg;
-	struct list_head			resources;
-};
-
-static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
-					     unsigned int devfn,
-					     int where)
-{
-	struct gen_pci *pci = bus->sysdata;
-	resource_size_t idx = bus->number - pci->cfg.bus_range->start;
-
-	return pci->cfg.win[idx] + ((devfn << 8) | where);
-}
-
-static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = {
+static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
 	.bus_shift	= 16,
-	.ops		= {
-		.map_bus	= gen_pci_map_cfg_bus_cam,
-		.read		= pci_generic_config_read,
-		.write		= pci_generic_config_write,
-	}
-};
-
-static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
-					      unsigned int devfn,
-					      int where)
-{
-	struct gen_pci *pci = bus->sysdata;
-	resource_size_t idx = bus->number - pci->cfg.bus_range->start;
-
-	return pci->cfg.win[idx] + ((devfn << 12) | where);
-}
-
-static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
-	.bus_shift	= 20,
-	.ops		= {
-		.map_bus	= gen_pci_map_cfg_bus_ecam,
+	.pci_ops	= {
+		.map_bus	= pci_ecam_map_bus,
 		.read		= pci_generic_config_read,
 		.write		= pci_generic_config_write,
 	}
@@ -96,181 +40,22 @@
 	  .data = &gen_pci_cfg_cam_bus_ops },
 
 	{ .compatible = "pci-host-ecam-generic",
-	  .data = &gen_pci_cfg_ecam_bus_ops },
+	  .data = &pci_generic_ecam_ops },
 
 	{ },
 };
-MODULE_DEVICE_TABLE(of, gen_pci_of_match);
-
-static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
-{
-	pci_free_resource_list(&pci->resources);
-}
-
-static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
-{
-	int err, res_valid = 0;
-	struct device *dev = pci->host.dev.parent;
-	struct device_node *np = dev->of_node;
-	resource_size_t iobase;
-	struct resource_entry *win;
-
-	err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
-					       &iobase);
-	if (err)
-		return err;
-
-	resource_list_for_each_entry(win, &pci->resources) {
-		struct resource *parent, *res = win->res;
-
-		switch (resource_type(res)) {
-		case IORESOURCE_IO:
-			parent = &ioport_resource;
-			err = pci_remap_iospace(res, iobase);
-			if (err) {
-				dev_warn(dev, "error %d: failed to map resource %pR\n",
-					 err, res);
-				continue;
-			}
-			break;
-		case IORESOURCE_MEM:
-			parent = &iomem_resource;
-			res_valid |= !(res->flags & IORESOURCE_PREFETCH);
-			break;
-		case IORESOURCE_BUS:
-			pci->cfg.bus_range = res;
-		default:
-			continue;
-		}
-
-		err = devm_request_resource(dev, parent, res);
-		if (err)
-			goto out_release_res;
-	}
-
-	if (!res_valid) {
-		dev_err(dev, "non-prefetchable memory resource required\n");
-		err = -EINVAL;
-		goto out_release_res;
-	}
-
-	return 0;
-
-out_release_res:
-	gen_pci_release_of_pci_ranges(pci);
-	return err;
-}
 
-static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
-{
-	int err;
-	u8 bus_max;
-	resource_size_t busn;
-	struct resource *bus_range;
-	struct device *dev = pci->host.dev.parent;
-	struct device_node *np = dev->of_node;
-	u32 sz = 1 << pci->cfg.ops->bus_shift;
-
-	err = of_address_to_resource(np, 0, &pci->cfg.res);
-	if (err) {
-		dev_err(dev, "missing \"reg\" property\n");
-		return err;
-	}
-
-	/* Limit the bus-range to fit within reg */
-	bus_max = pci->cfg.bus_range->start +
-		  (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
-	pci->cfg.bus_range->end = min_t(resource_size_t,
-					pci->cfg.bus_range->end, bus_max);
-
-	pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
-				    sizeof(*pci->cfg.win), GFP_KERNEL);
-	if (!pci->cfg.win)
-		return -ENOMEM;
-
-	/* Map our Configuration Space windows */
-	if (!devm_request_mem_region(dev, pci->cfg.res.start,
-				     resource_size(&pci->cfg.res),
-				     "Configuration Space"))
-		return -ENOMEM;
-
-	bus_range = pci->cfg.bus_range;
-	for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
-		u32 idx = busn - bus_range->start;
-
-		pci->cfg.win[idx] = devm_ioremap(dev,
-						 pci->cfg.res.start + idx * sz,
-						 sz);
-		if (!pci->cfg.win[idx])
-			return -ENOMEM;
-	}
-
-	return 0;
-}
+MODULE_DEVICE_TABLE(of, gen_pci_of_match);
 
 static int gen_pci_probe(struct platform_device *pdev)
 {
-	int err;
-	const char *type;
 	const struct of_device_id *of_id;
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
-	struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
-	struct pci_bus *bus, *child;
-
-	if (!pci)
-		return -ENOMEM;
-
-	type = of_get_property(np, "device_type", NULL);
-	if (!type || strcmp(type, "pci")) {
-		dev_err(dev, "invalid \"device_type\" %s\n", type);
-		return -EINVAL;
-	}
-
-	of_pci_check_probe_only();
-
-	of_id = of_match_node(gen_pci_of_match, np);
-	pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
-	pci->host.dev.parent = dev;
-	INIT_LIST_HEAD(&pci->host.windows);
-	INIT_LIST_HEAD(&pci->resources);
-
-	/* Parse our PCI ranges and request their resources */
-	err = gen_pci_parse_request_of_pci_ranges(pci);
-	if (err)
-		return err;
-
-	/* Parse and map our Configuration Space windows */
-	err = gen_pci_parse_map_cfg_windows(pci);
-	if (err) {
-		gen_pci_release_of_pci_ranges(pci);
-		return err;
-	}
-
-	/* Do not reassign resources if probe only */
-	if (!pci_has_flag(PCI_PROBE_ONLY))
-		pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
+	struct pci_ecam_ops *ops;
 
+	of_id = of_match_node(gen_pci_of_match, pdev->dev.of_node);
+	ops = (struct pci_ecam_ops *)of_id->data;
 
-	bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start,
-				&pci->cfg.ops->ops, pci, &pci->resources);
-	if (!bus) {
-		dev_err(dev, "Scanning rootbus failed");
-		return -ENODEV;
-	}
-
-	pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
-
-	if (!pci_has_flag(PCI_PROBE_ONLY)) {
-		pci_bus_size_bridges(bus);
-		pci_bus_assign_resources(bus);
-
-		list_for_each_entry(child, &bus->children, node)
-			pcie_bus_configure_settings(child);
-	}
-
-	pci_bus_add_devices(bus);
-	return 0;
+	return pci_host_common_probe(pdev, ops);
 }
 
 static struct platform_driver gen_pci_driver = {
--- linux-4.4.0.orig/drivers/pci/host/pci-hyperv.c
+++ linux-4.4.0/drivers/pci/host/pci-hyperv.c
@@ -0,0 +1,2426 @@
+/*
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Author:
+ *   Jake Oshins <jakeo@microsoft.com>
+ *
+ * This driver acts as a paravirtual front-end for PCI Express root buses.
+ * When a PCI Express function (either an entire device or an SR-IOV
+ * Virtual Function) is being passed through to the VM, this driver exposes
+ * a new bus to the guest VM.  This is modeled as a root PCI bus because
+ * no bridges are being exposed to the VM.  In fact, with a "Generation 2"
+ * VM within Hyper-V, there may seem to be no PCI bus at all in the VM
+ * until a device as been exposed using this driver.
+ *
+ * Each root PCI bus has its own PCI domain, which is called "Segment" in
+ * the PCI Firmware Specifications.  Thus while each device passed through
+ * to the VM using this front-end will appear at "device 0", the domain will
+ * be unique.  Typically, each bus will have one PCI function on it, though
+ * this driver does support more than one.
+ *
+ * In order to map the interrupts from the device through to the guest VM,
+ * this driver also implements an IRQ Domain, which handles interrupts (either
+ * MSI or MSI-X) associated with the functions on the bus.  As interrupts are
+ * set up, torn down, or reaffined, this driver communicates with the
+ * underlying hypervisor to adjust the mappings in the I/O MMU so that each
+ * interrupt will be delivered to the correct virtual processor at the right
+ * vector.  This driver does not support level-triggered (line-based)
+ * interrupts, and will report that the Interrupt Line register in the
+ * function's configuration space is zero.
+ *
+ * The rest of this driver mostly maps PCI concepts onto underlying Hyper-V
+ * facilities.  For instance, the configuration space of a function exposed
+ * by Hyper-V is mapped into a single page of memory space, and the
+ * read and write handlers for config space must be aware of this mechanism.
+ * Similarly, device setup and teardown involves messages sent to and from
+ * the PCI back-end driver in Hyper-V.
+ *
+ * This program is free software; you can 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/semaphore.h>
+#include <linux/irqdomain.h>
+#include <asm/irqdomain.h>
+#include <asm/apic.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+#include <linux/hyperv.h>
+#include <asm/mshyperv.h>
+
+/*
+ * Protocol versions. The low word is the minor version, the high word the
+ * major version.
+ */
+
+#define PCI_MAKE_VERSION(major, minor) ((u32)(((major) << 16) | (major)))
+#define PCI_MAJOR_VERSION(version) ((u32)(version) >> 16)
+#define PCI_MINOR_VERSION(version) ((u32)(version) & 0xff)
+
+enum {
+	PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1),
+	PCI_PROTOCOL_VERSION_CURRENT = PCI_PROTOCOL_VERSION_1_1
+};
+
+#define PCI_CONFIG_MMIO_LENGTH	0x2000
+#define CFG_PAGE_OFFSET 0x1000
+#define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET)
+
+#define MAX_SUPPORTED_MSI_MESSAGES 0x400
+
+/*
+ * Message Types
+ */
+
+enum pci_message_type {
+	/*
+	 * Version 1.1
+	 */
+	PCI_MESSAGE_BASE                = 0x42490000,
+	PCI_BUS_RELATIONS               = PCI_MESSAGE_BASE + 0,
+	PCI_QUERY_BUS_RELATIONS         = PCI_MESSAGE_BASE + 1,
+	PCI_POWER_STATE_CHANGE          = PCI_MESSAGE_BASE + 4,
+	PCI_QUERY_RESOURCE_REQUIREMENTS = PCI_MESSAGE_BASE + 5,
+	PCI_QUERY_RESOURCE_RESOURCES    = PCI_MESSAGE_BASE + 6,
+	PCI_BUS_D0ENTRY                 = PCI_MESSAGE_BASE + 7,
+	PCI_BUS_D0EXIT                  = PCI_MESSAGE_BASE + 8,
+	PCI_READ_BLOCK                  = PCI_MESSAGE_BASE + 9,
+	PCI_WRITE_BLOCK                 = PCI_MESSAGE_BASE + 0xA,
+	PCI_EJECT                       = PCI_MESSAGE_BASE + 0xB,
+	PCI_QUERY_STOP                  = PCI_MESSAGE_BASE + 0xC,
+	PCI_REENABLE                    = PCI_MESSAGE_BASE + 0xD,
+	PCI_QUERY_STOP_FAILED           = PCI_MESSAGE_BASE + 0xE,
+	PCI_EJECTION_COMPLETE           = PCI_MESSAGE_BASE + 0xF,
+	PCI_RESOURCES_ASSIGNED          = PCI_MESSAGE_BASE + 0x10,
+	PCI_RESOURCES_RELEASED          = PCI_MESSAGE_BASE + 0x11,
+	PCI_INVALIDATE_BLOCK            = PCI_MESSAGE_BASE + 0x12,
+	PCI_QUERY_PROTOCOL_VERSION      = PCI_MESSAGE_BASE + 0x13,
+	PCI_CREATE_INTERRUPT_MESSAGE    = PCI_MESSAGE_BASE + 0x14,
+	PCI_DELETE_INTERRUPT_MESSAGE    = PCI_MESSAGE_BASE + 0x15,
+	PCI_MESSAGE_MAXIMUM
+};
+
+/*
+ * Structures defining the virtual PCI Express protocol.
+ */
+
+union pci_version {
+	struct {
+		u16 minor_version;
+		u16 major_version;
+	} parts;
+	u32 version;
+} __packed;
+
+/*
+ * Function numbers are 8-bits wide on Express, as interpreted through ARI,
+ * which is all this driver does.  This representation is the one used in
+ * Windows, which is what is expected when sending this back and forth with
+ * the Hyper-V parent partition.
+ */
+union win_slot_encoding {
+	struct {
+		u32	dev:5;
+		u32	func:3;
+		u32	reserved:24;
+	} bits;
+	u32 slot;
+} __packed;
+
+/*
+ * Pretty much as defined in the PCI Specifications.
+ */
+struct pci_function_description {
+	u16	v_id;	/* vendor ID */
+	u16	d_id;	/* device ID */
+	u8	rev;
+	u8	prog_intf;
+	u8	subclass;
+	u8	base_class;
+	u32	subsystem_id;
+	union win_slot_encoding win_slot;
+	u32	ser;	/* serial number */
+} __packed;
+
+/**
+ * struct hv_msi_desc
+ * @vector:		IDT entry
+ * @delivery_mode:	As defined in Intel's Programmer's
+ *			Reference Manual, Volume 3, Chapter 8.
+ * @vector_count:	Number of contiguous entries in the
+ *			Interrupt Descriptor Table that are
+ *			occupied by this Message-Signaled
+ *			Interrupt. For "MSI", as first defined
+ *			in PCI 2.2, this can be between 1 and
+ *			32. For "MSI-X," as first defined in PCI
+ *			3.0, this must be 1, as each MSI-X table
+ *			entry would have its own descriptor.
+ * @reserved:		Empty space
+ * @cpu_mask:		All the target virtual processors.
+ */
+struct hv_msi_desc {
+	u8	vector;
+	u8	delivery_mode;
+	u16	vector_count;
+	u32	reserved;
+	u64	cpu_mask;
+} __packed;
+
+/**
+ * struct tran_int_desc
+ * @reserved:		unused, padding
+ * @vector_count:	same as in hv_msi_desc
+ * @data:		This is the "data payload" value that is
+ *			written by the device when it generates
+ *			a message-signaled interrupt, either MSI
+ *			or MSI-X.
+ * @address:		This is the address to which the data
+ *			payload is written on interrupt
+ *			generation.
+ */
+struct tran_int_desc {
+	u16	reserved;
+	u16	vector_count;
+	u32	data;
+	u64	address;
+} __packed;
+
+/*
+ * A generic message format for virtual PCI.
+ * Specific message formats are defined later in the file.
+ */
+
+struct pci_message {
+	u32 type;
+} __packed;
+
+struct pci_child_message {
+	struct pci_message message_type;
+	union win_slot_encoding wslot;
+} __packed;
+
+struct pci_incoming_message {
+	struct vmpacket_descriptor hdr;
+	struct pci_message message_type;
+} __packed;
+
+struct pci_response {
+	struct vmpacket_descriptor hdr;
+	s32 status;			/* negative values are failures */
+} __packed;
+
+struct pci_packet {
+	void (*completion_func)(void *context, struct pci_response *resp,
+				int resp_packet_size);
+	void *compl_ctxt;
+
+	struct pci_message message[0];
+};
+
+/*
+ * Specific message types supporting the PCI protocol.
+ */
+
+/*
+ * Version negotiation message. Sent from the guest to the host.
+ * The guest is free to try different versions until the host
+ * accepts the version.
+ *
+ * pci_version: The protocol version requested.
+ * is_last_attempt: If TRUE, this is the last version guest will request.
+ * reservedz: Reserved field, set to zero.
+ */
+
+struct pci_version_request {
+	struct pci_message message_type;
+	enum pci_message_type protocol_version;
+} __packed;
+
+/*
+ * Bus D0 Entry.  This is sent from the guest to the host when the virtual
+ * bus (PCI Express port) is ready for action.
+ */
+
+struct pci_bus_d0_entry {
+	struct pci_message message_type;
+	u32 reserved;
+	u64 mmio_base;
+} __packed;
+
+struct pci_bus_relations {
+	struct pci_incoming_message incoming;
+	u32 device_count;
+	struct pci_function_description func[0];
+} __packed;
+
+struct pci_q_res_req_response {
+	struct vmpacket_descriptor hdr;
+	s32 status;			/* negative values are failures */
+	u32 probed_bar[6];
+} __packed;
+
+struct pci_set_power {
+	struct pci_message message_type;
+	union win_slot_encoding wslot;
+	u32 power_state;		/* In Windows terms */
+	u32 reserved;
+} __packed;
+
+struct pci_set_power_response {
+	struct vmpacket_descriptor hdr;
+	s32 status;			/* negative values are failures */
+	union win_slot_encoding wslot;
+	u32 resultant_state;		/* In Windows terms */
+	u32 reserved;
+} __packed;
+
+struct pci_resources_assigned {
+	struct pci_message message_type;
+	union win_slot_encoding wslot;
+	u8 memory_range[0x14][6];	/* not used here */
+	u32 msi_descriptors;
+	u32 reserved[4];
+} __packed;
+
+struct pci_create_interrupt {
+	struct pci_message message_type;
+	union win_slot_encoding wslot;
+	struct hv_msi_desc int_desc;
+} __packed;
+
+struct pci_create_int_response {
+	struct pci_response response;
+	u32 reserved;
+	struct tran_int_desc int_desc;
+} __packed;
+
+struct pci_delete_interrupt {
+	struct pci_message message_type;
+	union win_slot_encoding wslot;
+	struct tran_int_desc int_desc;
+} __packed;
+
+struct pci_dev_incoming {
+	struct pci_incoming_message incoming;
+	union win_slot_encoding wslot;
+} __packed;
+
+struct pci_eject_response {
+	struct pci_message message_type;
+	union win_slot_encoding wslot;
+	u32 status;
+} __packed;
+
+static int pci_ring_size = (4 * PAGE_SIZE);
+
+/*
+ * Definitions or interrupt steering hypercall.
+ */
+#define HV_PARTITION_ID_SELF		((u64)-1)
+#define HVCALL_RETARGET_INTERRUPT	0x7e
+
+struct retarget_msi_interrupt {
+	u64	partition_id;		/* use "self" */
+	u64	device_id;
+	u32	source;			/* 1 for MSI(-X) */
+	u32	reserved1;
+	u32	address;
+	u32	data;
+	u64	reserved2;
+	u32	vector;
+	u32	flags;
+	u64	vp_mask;
+} __packed;
+
+/*
+ * Driver specific state.
+ */
+
+enum hv_pcibus_state {
+	hv_pcibus_init = 0,
+	hv_pcibus_probed,
+	hv_pcibus_installed,
+	hv_pcibus_removed,
+	hv_pcibus_maximum
+};
+
+struct hv_pcibus_device {
+	struct pci_sysdata sysdata;
+	enum hv_pcibus_state state;
+	atomic_t remove_lock;
+	struct hv_device *hdev;
+	resource_size_t low_mmio_space;
+	resource_size_t high_mmio_space;
+	struct resource *mem_config;
+	struct resource *low_mmio_res;
+	struct resource *high_mmio_res;
+	struct completion *survey_event;
+	struct completion remove_event;
+	struct pci_bus *pci_bus;
+	spinlock_t config_lock;	/* Avoid two threads writing index page */
+	spinlock_t device_list_lock;	/* Protect lists below */
+	void __iomem *cfg_addr;
+
+	struct semaphore enum_sem;
+	struct list_head resources_for_children;
+
+	struct list_head children;
+	struct list_head dr_list;
+
+	struct msi_domain_info msi_info;
+	struct msi_controller msi_chip;
+	struct irq_domain *irq_domain;
+	struct retarget_msi_interrupt retarget_msi_interrupt_params;
+	spinlock_t retarget_msi_interrupt_lock;
+};
+
+/*
+ * Tracks "Device Relations" messages from the host, which must be both
+ * processed in order and deferred so that they don't run in the context
+ * of the incoming packet callback.
+ */
+struct hv_dr_work {
+	struct work_struct wrk;
+	struct hv_pcibus_device *bus;
+};
+
+struct hv_dr_state {
+	struct list_head list_entry;
+	u32 device_count;
+	struct pci_function_description func[0];
+};
+
+enum hv_pcichild_state {
+	hv_pcichild_init = 0,
+	hv_pcichild_requirements,
+	hv_pcichild_resourced,
+	hv_pcichild_ejecting,
+	hv_pcichild_maximum
+};
+
+enum hv_pcidev_ref_reason {
+	hv_pcidev_ref_invalid = 0,
+	hv_pcidev_ref_initial,
+	hv_pcidev_ref_by_slot,
+	hv_pcidev_ref_packet,
+	hv_pcidev_ref_pnp,
+	hv_pcidev_ref_childlist,
+	hv_pcidev_irqdata,
+	hv_pcidev_ref_max
+};
+
+struct hv_pci_dev {
+	/* List protected by pci_rescan_remove_lock */
+	struct list_head list_entry;
+	atomic_t refs;
+	enum hv_pcichild_state state;
+	struct pci_function_description desc;
+	bool reported_missing;
+	struct hv_pcibus_device *hbus;
+	struct work_struct wrk;
+
+	/*
+	 * What would be observed if one wrote 0xFFFFFFFF to a BAR and then
+	 * read it back, for each of the BAR offsets within config space.
+	 */
+	u32 probed_bar[6];
+};
+
+struct hv_pci_compl {
+	struct completion host_event;
+	s32 completion_status;
+};
+
+/**
+ * hv_pci_generic_compl() - Invoked for a completion packet
+ * @context:		Set up by the sender of the packet.
+ * @resp:		The response packet
+ * @resp_packet_size:	Size in bytes of the packet
+ *
+ * This function is used to trigger an event and report status
+ * for any message for which the completion packet contains a
+ * status and nothing else.
+ */
+static void hv_pci_generic_compl(void *context, struct pci_response *resp,
+				 int resp_packet_size)
+{
+	struct hv_pci_compl *comp_pkt = context;
+
+	if (resp_packet_size >= offsetofend(struct pci_response, status))
+		comp_pkt->completion_status = resp->status;
+	else
+		comp_pkt->completion_status = -1;
+
+	complete(&comp_pkt->host_event);
+}
+
+static struct hv_pci_dev *get_pcichild_wslot(struct hv_pcibus_device *hbus,
+						u32 wslot);
+static void get_pcichild(struct hv_pci_dev *hv_pcidev,
+			 enum hv_pcidev_ref_reason reason);
+static void put_pcichild(struct hv_pci_dev *hv_pcidev,
+			 enum hv_pcidev_ref_reason reason);
+
+static void get_hvpcibus(struct hv_pcibus_device *hv_pcibus);
+static void put_hvpcibus(struct hv_pcibus_device *hv_pcibus);
+
+/**
+ * devfn_to_wslot() - Convert from Linux PCI slot to Windows
+ * @devfn:	The Linux representation of PCI slot
+ *
+ * Windows uses a slightly different representation of PCI slot.
+ *
+ * Return: The Windows representation
+ */
+static u32 devfn_to_wslot(int devfn)
+{
+	union win_slot_encoding wslot;
+
+	wslot.slot = 0;
+	wslot.bits.dev = PCI_SLOT(devfn);
+	wslot.bits.func = PCI_FUNC(devfn);
+
+	return wslot.slot;
+}
+
+/**
+ * wslot_to_devfn() - Convert from Windows PCI slot to Linux
+ * @wslot:	The Windows representation of PCI slot
+ *
+ * Windows uses a slightly different representation of PCI slot.
+ *
+ * Return: The Linux representation
+ */
+static int wslot_to_devfn(u32 wslot)
+{
+	union win_slot_encoding slot_no;
+
+	slot_no.slot = wslot;
+	return PCI_DEVFN(slot_no.bits.dev, slot_no.bits.func);
+}
+
+/*
+ * PCI Configuration Space for these root PCI buses is implemented as a pair
+ * of pages in memory-mapped I/O space.  Writing to the first page chooses
+ * the PCI function being written or read.  Once the first page has been
+ * written to, the following page maps in the entire configuration space of
+ * the function.
+ */
+
+/**
+ * _hv_pcifront_read_config() - Internal PCI config read
+ * @hpdev:	The PCI driver's representation of the device
+ * @where:	Offset within config space
+ * @size:	Size of the transfer
+ * @val:	Pointer to the buffer receiving the data
+ */
+static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where,
+				     int size, u32 *val)
+{
+	unsigned long flags;
+	void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where;
+
+	/*
+	 * If the attempt is to read the IDs or the ROM BAR, simulate that.
+	 */
+	if (where + size <= PCI_COMMAND) {
+		memcpy(val, ((u8 *)&hpdev->desc.v_id) + where, size);
+	} else if (where >= PCI_CLASS_REVISION && where + size <=
+		   PCI_CACHE_LINE_SIZE) {
+		memcpy(val, ((u8 *)&hpdev->desc.rev) + where -
+		       PCI_CLASS_REVISION, size);
+	} else if (where >= PCI_SUBSYSTEM_VENDOR_ID && where + size <=
+		   PCI_ROM_ADDRESS) {
+		memcpy(val, (u8 *)&hpdev->desc.subsystem_id + where -
+		       PCI_SUBSYSTEM_VENDOR_ID, size);
+	} else if (where >= PCI_ROM_ADDRESS && where + size <=
+		   PCI_CAPABILITY_LIST) {
+		/* ROM BARs are unimplemented */
+		*val = 0;
+	} else if (where >= PCI_INTERRUPT_LINE && where + size <=
+		   PCI_INTERRUPT_PIN) {
+		/*
+		 * Interrupt Line and Interrupt PIN are hard-wired to zero
+		 * because this front-end only supports message-signaled
+		 * interrupts.
+		 */
+		*val = 0;
+	} else if (where + size <= CFG_PAGE_SIZE) {
+		spin_lock_irqsave(&hpdev->hbus->config_lock, flags);
+		/* Choose the function to be read. (See comment above) */
+		writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr);
+		/* Make sure the function was chosen before we start reading. */
+		mb();
+		/* Read from that function's config space. */
+		switch (size) {
+		case 1:
+			*val = readb(addr);
+			break;
+		case 2:
+			*val = readw(addr);
+			break;
+		default:
+			*val = readl(addr);
+			break;
+		}
+		/*
+		 * Make sure the write was done before we release the spinlock
+		 * allowing consecutive reads/writes.
+		 */
+		mb();
+		spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags);
+	} else {
+		dev_err(&hpdev->hbus->hdev->device,
+			"Attempt to read beyond a function's config space.\n");
+	}
+}
+
+/**
+ * _hv_pcifront_write_config() - Internal PCI config write
+ * @hpdev:	The PCI driver's representation of the device
+ * @where:	Offset within config space
+ * @size:	Size of the transfer
+ * @val:	The data being transferred
+ */
+static void _hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where,
+				      int size, u32 val)
+{
+	unsigned long flags;
+	void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where;
+
+	if (where >= PCI_SUBSYSTEM_VENDOR_ID &&
+	    where + size <= PCI_CAPABILITY_LIST) {
+		/* SSIDs and ROM BARs are read-only */
+	} else if (where >= PCI_COMMAND && where + size <= CFG_PAGE_SIZE) {
+		spin_lock_irqsave(&hpdev->hbus->config_lock, flags);
+		/* Choose the function to be written. (See comment above) */
+		writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr);
+		/* Make sure the function was chosen before we start writing. */
+		wmb();
+		/* Write to that function's config space. */
+		switch (size) {
+		case 1:
+			writeb(val, addr);
+			break;
+		case 2:
+			writew(val, addr);
+			break;
+		default:
+			writel(val, addr);
+			break;
+		}
+		/*
+		 * Make sure the write was done before we release the spinlock
+		 * allowing consecutive reads/writes.
+		 */
+		mb();
+		spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags);
+	} else {
+		dev_err(&hpdev->hbus->hdev->device,
+			"Attempt to write beyond a function's config space.\n");
+	}
+}
+
+/**
+ * hv_pcifront_read_config() - Read configuration space
+ * @bus: PCI Bus structure
+ * @devfn: Device/function
+ * @where: Offset from base
+ * @size: Byte/word/dword
+ * @val: Value to be read
+ *
+ * Return: PCIBIOS_SUCCESSFUL on success
+ *	   PCIBIOS_DEVICE_NOT_FOUND on failure
+ */
+static int hv_pcifront_read_config(struct pci_bus *bus, unsigned int devfn,
+				   int where, int size, u32 *val)
+{
+	struct hv_pcibus_device *hbus =
+		container_of(bus->sysdata, struct hv_pcibus_device, sysdata);
+	struct hv_pci_dev *hpdev;
+
+	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(devfn));
+	if (!hpdev)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	_hv_pcifront_read_config(hpdev, where, size, val);
+
+	put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/**
+ * hv_pcifront_write_config() - Write configuration space
+ * @bus: PCI Bus structure
+ * @devfn: Device/function
+ * @where: Offset from base
+ * @size: Byte/word/dword
+ * @val: Value to be written to device
+ *
+ * Return: PCIBIOS_SUCCESSFUL on success
+ *	   PCIBIOS_DEVICE_NOT_FOUND on failure
+ */
+static int hv_pcifront_write_config(struct pci_bus *bus, unsigned int devfn,
+				    int where, int size, u32 val)
+{
+	struct hv_pcibus_device *hbus =
+	    container_of(bus->sysdata, struct hv_pcibus_device, sysdata);
+	struct hv_pci_dev *hpdev;
+
+	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(devfn));
+	if (!hpdev)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	_hv_pcifront_write_config(hpdev, where, size, val);
+
+	put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/* PCIe operations */
+static struct pci_ops hv_pcifront_ops = {
+	.read  = hv_pcifront_read_config,
+	.write = hv_pcifront_write_config,
+};
+
+/* Interrupt management hooks */
+static void hv_int_desc_free(struct hv_pci_dev *hpdev,
+			     struct tran_int_desc *int_desc)
+{
+	struct pci_delete_interrupt *int_pkt;
+	struct {
+		struct pci_packet pkt;
+		u8 buffer[sizeof(struct pci_delete_interrupt)];
+	} ctxt;
+
+	memset(&ctxt, 0, sizeof(ctxt));
+	int_pkt = (struct pci_delete_interrupt *)&ctxt.pkt.message;
+	int_pkt->message_type.type =
+		PCI_DELETE_INTERRUPT_MESSAGE;
+	int_pkt->wslot.slot = hpdev->desc.win_slot.slot;
+	int_pkt->int_desc = *int_desc;
+	vmbus_sendpacket(hpdev->hbus->hdev->channel, int_pkt, sizeof(*int_pkt),
+			 (unsigned long)&ctxt.pkt, VM_PKT_DATA_INBAND, 0);
+	kfree(int_desc);
+}
+
+/**
+ * hv_msi_free() - Free the MSI.
+ * @domain:	The interrupt domain pointer
+ * @info:	Extra MSI-related context
+ * @irq:	Identifies the IRQ.
+ *
+ * The Hyper-V parent partition and hypervisor are tracking the
+ * messages that are in use, keeping the interrupt redirection
+ * table up to date.  This callback sends a message that frees
+ * the IRT entry and related tracking nonsense.
+ */
+static void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info,
+			unsigned int irq)
+{
+	struct hv_pcibus_device *hbus;
+	struct hv_pci_dev *hpdev;
+	struct pci_dev *pdev;
+	struct tran_int_desc *int_desc;
+	struct irq_data *irq_data = irq_domain_get_irq_data(domain, irq);
+	struct msi_desc *msi = irq_data_get_msi_desc(irq_data);
+
+	pdev = msi_desc_to_pci_dev(msi);
+	hbus = info->data;
+	int_desc = irq_data_get_irq_chip_data(irq_data);
+	if (!int_desc)
+		return;
+
+	irq_data->chip_data = NULL;
+	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
+	if (!hpdev) {
+		kfree(int_desc);
+		return;
+	}
+
+	hv_int_desc_free(hpdev, int_desc);
+	put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+}
+
+static int hv_set_affinity(struct irq_data *data, const struct cpumask *dest,
+			   bool force)
+{
+	struct irq_data *parent = data->parent_data;
+
+	return parent->chip->irq_set_affinity(parent, dest, force);
+}
+
+static void hv_irq_mask(struct irq_data *data)
+{
+	pci_msi_mask_irq(data);
+}
+
+/**
+ * hv_irq_unmask() - "Unmask" the IRQ by setting its current
+ * affinity.
+ * @data:	Describes the IRQ
+ *
+ * Build new a destination for the MSI and make a hypercall to
+ * update the Interrupt Redirection Table. "Device Logical ID"
+ * is built out of this PCI bus's instance GUID and the function
+ * number of the device.
+ */
+static void hv_irq_unmask(struct irq_data *data)
+{
+	struct msi_desc *msi_desc = irq_data_get_msi_desc(data);
+	struct irq_cfg *cfg = irqd_cfg(data);
+	struct retarget_msi_interrupt *params;
+	struct hv_pcibus_device *hbus;
+	struct cpumask *dest;
+	struct pci_bus *pbus;
+	struct pci_dev *pdev;
+	int cpu;
+	unsigned long flags;
+
+	dest = irq_data_get_affinity_mask(data);
+	pdev = msi_desc_to_pci_dev(msi_desc);
+	pbus = pdev->bus;
+	hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
+
+	spin_lock_irqsave(&hbus->retarget_msi_interrupt_lock, flags);
+
+	params = &hbus->retarget_msi_interrupt_params;
+	memset(params, 0, sizeof(*params));
+	params->partition_id = HV_PARTITION_ID_SELF;
+	params->source = 1; /* MSI(-X) */
+	params->address = msi_desc->msg.address_lo;
+	params->data = msi_desc->msg.data;
+	params->device_id = (hbus->hdev->dev_instance.b[5] << 24) |
+			   (hbus->hdev->dev_instance.b[4] << 16) |
+			   (hbus->hdev->dev_instance.b[7] << 8) |
+			   (hbus->hdev->dev_instance.b[6] & 0xf8) |
+			   PCI_FUNC(pdev->devfn);
+	params->vector = cfg->vector;
+
+	for_each_cpu_and(cpu, dest, cpu_online_mask)
+		params->vp_mask |= (1ULL << vmbus_cpu_number_to_vp_number(cpu));
+
+	hv_do_hypercall(HVCALL_RETARGET_INTERRUPT, params, NULL);
+
+	spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags);
+
+	pci_msi_unmask_irq(data);
+}
+
+struct compose_comp_ctxt {
+	struct hv_pci_compl comp_pkt;
+	struct tran_int_desc int_desc;
+};
+
+static void hv_pci_compose_compl(void *context, struct pci_response *resp,
+				 int resp_packet_size)
+{
+	struct compose_comp_ctxt *comp_pkt = context;
+	struct pci_create_int_response *int_resp =
+		(struct pci_create_int_response *)resp;
+
+	comp_pkt->comp_pkt.completion_status = resp->status;
+	comp_pkt->int_desc = int_resp->int_desc;
+	complete(&comp_pkt->comp_pkt.host_event);
+}
+
+/**
+ * hv_compose_msi_msg() - Supplies a valid MSI address/data
+ * @data:	Everything about this MSI
+ * @msg:	Buffer that is filled in by this function
+ *
+ * This function unpacks the IRQ looking for target CPU set, IDT
+ * vector and mode and sends a message to the parent partition
+ * asking for a mapping for that tuple in this partition.  The
+ * response supplies a data value and address to which that data
+ * should be written to trigger that interrupt.
+ */
+static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_cfg *cfg = irqd_cfg(data);
+	struct hv_pcibus_device *hbus;
+	struct hv_pci_dev *hpdev;
+	struct pci_bus *pbus;
+	struct pci_dev *pdev;
+	struct pci_create_interrupt *int_pkt;
+	struct compose_comp_ctxt comp;
+	struct tran_int_desc *int_desc;
+	struct cpumask *affinity;
+	struct {
+		struct pci_packet pkt;
+		u8 buffer[sizeof(struct pci_create_interrupt)];
+	} ctxt;
+	int cpu;
+	int ret;
+
+	pdev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data));
+	pbus = pdev->bus;
+	hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
+	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
+	if (!hpdev)
+		goto return_null_message;
+
+	/* Free any previous message that might have already been composed. */
+	if (data->chip_data) {
+		int_desc = data->chip_data;
+		data->chip_data = NULL;
+		hv_int_desc_free(hpdev, int_desc);
+	}
+
+	int_desc = kzalloc(sizeof(*int_desc), GFP_KERNEL);
+	if (!int_desc)
+		goto drop_reference;
+
+	memset(&ctxt, 0, sizeof(ctxt));
+	init_completion(&comp.comp_pkt.host_event);
+	ctxt.pkt.completion_func = hv_pci_compose_compl;
+	ctxt.pkt.compl_ctxt = &comp;
+	int_pkt = (struct pci_create_interrupt *)&ctxt.pkt.message;
+	int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE;
+	int_pkt->wslot.slot = hpdev->desc.win_slot.slot;
+	int_pkt->int_desc.vector = cfg->vector;
+	int_pkt->int_desc.vector_count = 1;
+	int_pkt->int_desc.delivery_mode =
+		(apic->irq_delivery_mode == dest_LowestPrio) ? 1 : 0;
+
+	/*
+	 * This bit doesn't have to work on machines with more than 64
+	 * processors because Hyper-V only supports 64 in a guest.
+	 */
+	affinity = irq_data_get_affinity_mask(data);
+	for_each_cpu_and(cpu, affinity, cpu_online_mask) {
+		int_pkt->int_desc.cpu_mask |=
+			(1ULL << vmbus_cpu_number_to_vp_number(cpu));
+	}
+
+	ret = vmbus_sendpacket(hpdev->hbus->hdev->channel, int_pkt,
+			       sizeof(*int_pkt), (unsigned long)&ctxt.pkt,
+			       VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (ret)
+		goto free_int_desc;
+
+	/*
+	 * Since this function is called with IRQ locks held, can't
+	 * do normal wait for completion; instead poll.
+	 */
+	while (!try_wait_for_completion(&comp.comp_pkt.host_event))
+		udelay(100);
+
+	if (comp.comp_pkt.completion_status < 0) {
+		dev_err(&hbus->hdev->device,
+			"Request for interrupt failed: 0x%x",
+			comp.comp_pkt.completion_status);
+		goto free_int_desc;
+	}
+
+	/*
+	 * Record the assignment so that this can be unwound later. Using
+	 * irq_set_chip_data() here would be appropriate, but the lock it takes
+	 * is already held.
+	 */
+	*int_desc = comp.int_desc;
+	data->chip_data = int_desc;
+
+	/* Pass up the result. */
+	msg->address_hi = comp.int_desc.address >> 32;
+	msg->address_lo = comp.int_desc.address & 0xffffffff;
+	msg->data = comp.int_desc.data;
+
+	put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+	return;
+
+free_int_desc:
+	kfree(int_desc);
+drop_reference:
+	put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+return_null_message:
+	msg->address_hi = 0;
+	msg->address_lo = 0;
+	msg->data = 0;
+}
+
+/* HW Interrupt Chip Descriptor */
+static struct irq_chip hv_msi_irq_chip = {
+	.name			= "Hyper-V PCIe MSI",
+	.irq_compose_msi_msg	= hv_compose_msi_msg,
+	.irq_set_affinity	= hv_set_affinity,
+	.irq_ack		= irq_chip_ack_parent,
+	.irq_mask		= hv_irq_mask,
+	.irq_unmask		= hv_irq_unmask,
+};
+
+static irq_hw_number_t hv_msi_domain_ops_get_hwirq(struct msi_domain_info *info,
+						   msi_alloc_info_t *arg)
+{
+	return arg->msi_hwirq;
+}
+
+static struct msi_domain_ops hv_msi_ops = {
+	.get_hwirq	= hv_msi_domain_ops_get_hwirq,
+	.msi_prepare	= pci_msi_prepare,
+	.set_desc	= pci_msi_set_desc,
+	.msi_free	= hv_msi_free,
+};
+
+/**
+ * hv_pcie_init_irq_domain() - Initialize IRQ domain
+ * @hbus:	The root PCI bus
+ *
+ * This function creates an IRQ domain which will be used for
+ * interrupts from devices that have been passed through.  These
+ * devices only support MSI and MSI-X, not line-based interrupts
+ * or simulations of line-based interrupts through PCIe's
+ * fabric-layer messages.  Because interrupts are remapped, we
+ * can support multi-message MSI here.
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int hv_pcie_init_irq_domain(struct hv_pcibus_device *hbus)
+{
+	hbus->msi_info.chip = &hv_msi_irq_chip;
+	hbus->msi_info.ops = &hv_msi_ops;
+	hbus->msi_info.flags = (MSI_FLAG_USE_DEF_DOM_OPS |
+		MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI |
+		MSI_FLAG_PCI_MSIX);
+	hbus->msi_info.handler = handle_edge_irq;
+	hbus->msi_info.handler_name = "edge";
+	hbus->msi_info.data = hbus;
+	hbus->irq_domain = pci_msi_create_irq_domain(hbus->sysdata.fwnode,
+						     &hbus->msi_info,
+						     x86_vector_domain);
+	if (!hbus->irq_domain) {
+		dev_err(&hbus->hdev->device,
+			"Failed to build an MSI IRQ domain\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * get_bar_size() - Get the address space consumed by a BAR
+ * @bar_val:	Value that a BAR returned after -1 was written
+ *              to it.
+ *
+ * This function returns the size of the BAR, rounded up to 1
+ * page.  It has to be rounded up because the hypervisor's page
+ * table entry that maps the BAR into the VM can't specify an
+ * offset within a page.  The invariant is that the hypervisor
+ * must place any BARs of smaller than page length at the
+ * beginning of a page.
+ *
+ * Return:	Size in bytes of the consumed MMIO space.
+ */
+static u64 get_bar_size(u64 bar_val)
+{
+	return round_up((1 + ~(bar_val & PCI_BASE_ADDRESS_MEM_MASK)),
+			PAGE_SIZE);
+}
+
+/**
+ * survey_child_resources() - Total all MMIO requirements
+ * @hbus:	Root PCI bus, as understood by this driver
+ */
+static void survey_child_resources(struct hv_pcibus_device *hbus)
+{
+	struct list_head *iter;
+	struct hv_pci_dev *hpdev;
+	resource_size_t bar_size = 0;
+	unsigned long flags;
+	struct completion *event;
+	u64 bar_val;
+	int i;
+
+	/* If nobody is waiting on the answer, don't compute it. */
+	event = xchg(&hbus->survey_event, NULL);
+	if (!event)
+		return;
+
+	/* If the answer has already been computed, go with it. */
+	if (hbus->low_mmio_space || hbus->high_mmio_space) {
+		complete(event);
+		return;
+	}
+
+	spin_lock_irqsave(&hbus->device_list_lock, flags);
+
+	/*
+	 * Due to an interesting quirk of the PCI spec, all memory regions
+	 * for a child device are a power of 2 in size and aligned in memory,
+	 * so it's sufficient to just add them up without tracking alignment.
+	 */
+	list_for_each(iter, &hbus->children) {
+		hpdev = container_of(iter, struct hv_pci_dev, list_entry);
+		for (i = 0; i < 6; i++) {
+			if (hpdev->probed_bar[i] & PCI_BASE_ADDRESS_SPACE_IO)
+				dev_err(&hbus->hdev->device,
+					"There's an I/O BAR in this list!\n");
+
+			if (hpdev->probed_bar[i] != 0) {
+				/*
+				 * A probed BAR has all the upper bits set that
+				 * can be changed.
+				 */
+
+				bar_val = hpdev->probed_bar[i];
+				if (bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64)
+					bar_val |=
+					((u64)hpdev->probed_bar[++i] << 32);
+				else
+					bar_val |= 0xffffffff00000000ULL;
+
+				bar_size = get_bar_size(bar_val);
+
+				if (bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64)
+					hbus->high_mmio_space += bar_size;
+				else
+					hbus->low_mmio_space += bar_size;
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+	complete(event);
+}
+
+/**
+ * prepopulate_bars() - Fill in BARs with defaults
+ * @hbus:	Root PCI bus, as understood by this driver
+ *
+ * The core PCI driver code seems much, much happier if the BARs
+ * for a device have values upon first scan. So fill them in.
+ * The algorithm below works down from large sizes to small,
+ * attempting to pack the assignments optimally. The assumption,
+ * enforced in other parts of the code, is that the beginning of
+ * the memory-mapped I/O space will be aligned on the largest
+ * BAR size.
+ */
+static void prepopulate_bars(struct hv_pcibus_device *hbus)
+{
+	resource_size_t high_size = 0;
+	resource_size_t low_size = 0;
+	resource_size_t high_base = 0;
+	resource_size_t low_base = 0;
+	resource_size_t bar_size;
+	struct hv_pci_dev *hpdev;
+	struct list_head *iter;
+	unsigned long flags;
+	u64 bar_val;
+	u32 command;
+	bool high;
+	int i;
+
+	if (hbus->low_mmio_space) {
+		low_size = 1ULL << (63 - __builtin_clzll(hbus->low_mmio_space));
+		low_base = hbus->low_mmio_res->start;
+	}
+
+	if (hbus->high_mmio_space) {
+		high_size = 1ULL <<
+			(63 - __builtin_clzll(hbus->high_mmio_space));
+		high_base = hbus->high_mmio_res->start;
+	}
+
+	spin_lock_irqsave(&hbus->device_list_lock, flags);
+
+	/* Pick addresses for the BARs. */
+	do {
+		list_for_each(iter, &hbus->children) {
+			hpdev = container_of(iter, struct hv_pci_dev,
+					     list_entry);
+			for (i = 0; i < 6; i++) {
+				bar_val = hpdev->probed_bar[i];
+				if (bar_val == 0)
+					continue;
+				high = bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64;
+				if (high) {
+					bar_val |=
+						((u64)hpdev->probed_bar[i + 1]
+						 << 32);
+				} else {
+					bar_val |= 0xffffffffULL << 32;
+				}
+				bar_size = get_bar_size(bar_val);
+				if (high) {
+					if (high_size != bar_size) {
+						i++;
+						continue;
+					}
+					_hv_pcifront_write_config(hpdev,
+						PCI_BASE_ADDRESS_0 + (4 * i),
+						4,
+						(u32)(high_base & 0xffffff00));
+					i++;
+					_hv_pcifront_write_config(hpdev,
+						PCI_BASE_ADDRESS_0 + (4 * i),
+						4, (u32)(high_base >> 32));
+					high_base += bar_size;
+				} else {
+					if (low_size != bar_size)
+						continue;
+					_hv_pcifront_write_config(hpdev,
+						PCI_BASE_ADDRESS_0 + (4 * i),
+						4,
+						(u32)(low_base & 0xffffff00));
+					low_base += bar_size;
+				}
+			}
+			if (high_size <= 1 && low_size <= 1) {
+				/* Set the memory enable bit. */
+				_hv_pcifront_read_config(hpdev, PCI_COMMAND, 2,
+							 &command);
+				command |= PCI_COMMAND_MEMORY;
+				_hv_pcifront_write_config(hpdev, PCI_COMMAND, 2,
+							  command);
+				break;
+			}
+		}
+
+		high_size >>= 1;
+		low_size >>= 1;
+	}  while (high_size || low_size);
+
+	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+}
+
+/**
+ * create_root_hv_pci_bus() - Expose a new root PCI bus
+ * @hbus:	Root PCI bus, as understood by this driver
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)
+{
+	/* Register the device */
+	hbus->pci_bus = pci_create_root_bus(&hbus->hdev->device,
+					    0, /* bus number is always zero */
+					    &hv_pcifront_ops,
+					    &hbus->sysdata,
+					    &hbus->resources_for_children);
+	if (!hbus->pci_bus)
+		return -ENODEV;
+
+	hbus->pci_bus->msi = &hbus->msi_chip;
+	hbus->pci_bus->msi->dev = &hbus->hdev->device;
+
+	pci_lock_rescan_remove();
+	pci_scan_child_bus(hbus->pci_bus);
+	pci_bus_assign_resources(hbus->pci_bus);
+	pci_bus_add_devices(hbus->pci_bus);
+	pci_unlock_rescan_remove();
+	hbus->state = hv_pcibus_installed;
+	return 0;
+}
+
+struct q_res_req_compl {
+	struct completion host_event;
+	struct hv_pci_dev *hpdev;
+};
+
+/**
+ * q_resource_requirements() - Query Resource Requirements
+ * @context:		The completion context.
+ * @resp:		The response that came from the host.
+ * @resp_packet_size:	The size in bytes of resp.
+ *
+ * This function is invoked on completion of a Query Resource
+ * Requirements packet.
+ */
+static void q_resource_requirements(void *context, struct pci_response *resp,
+				    int resp_packet_size)
+{
+	struct q_res_req_compl *completion = context;
+	struct pci_q_res_req_response *q_res_req =
+		(struct pci_q_res_req_response *)resp;
+	int i;
+
+	if (resp->status < 0) {
+		dev_err(&completion->hpdev->hbus->hdev->device,
+			"query resource requirements failed: %x\n",
+			resp->status);
+	} else {
+		for (i = 0; i < 6; i++) {
+			completion->hpdev->probed_bar[i] =
+				q_res_req->probed_bar[i];
+		}
+	}
+
+	complete(&completion->host_event);
+}
+
+static void get_pcichild(struct hv_pci_dev *hpdev,
+			    enum hv_pcidev_ref_reason reason)
+{
+	atomic_inc(&hpdev->refs);
+}
+
+static void put_pcichild(struct hv_pci_dev *hpdev,
+			    enum hv_pcidev_ref_reason reason)
+{
+	if (atomic_dec_and_test(&hpdev->refs))
+		kfree(hpdev);
+}
+
+/**
+ * new_pcichild_device() - Create a new child device
+ * @hbus:	The internal struct tracking this root PCI bus.
+ * @desc:	The information supplied so far from the host
+ *              about the device.
+ *
+ * This function creates the tracking structure for a new child
+ * device and kicks off the process of figuring out what it is.
+ *
+ * Return: Pointer to the new tracking struct
+ */
+static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus,
+		struct pci_function_description *desc)
+{
+	struct hv_pci_dev *hpdev;
+	struct pci_child_message *res_req;
+	struct q_res_req_compl comp_pkt;
+	union {
+	struct pci_packet init_packet;
+		u8 buffer[0x100];
+	} pkt;
+	unsigned long flags;
+	int ret;
+
+	hpdev = kzalloc(sizeof(*hpdev), GFP_ATOMIC);
+	if (!hpdev)
+		return NULL;
+
+	hpdev->hbus = hbus;
+
+	memset(&pkt, 0, sizeof(pkt));
+	init_completion(&comp_pkt.host_event);
+	comp_pkt.hpdev = hpdev;
+	pkt.init_packet.compl_ctxt = &comp_pkt;
+	pkt.init_packet.completion_func = q_resource_requirements;
+	res_req = (struct pci_child_message *)&pkt.init_packet.message;
+	res_req->message_type.type = PCI_QUERY_RESOURCE_REQUIREMENTS;
+	res_req->wslot.slot = desc->win_slot.slot;
+
+	ret = vmbus_sendpacket(hbus->hdev->channel, res_req,
+			       sizeof(struct pci_child_message),
+			       (unsigned long)&pkt.init_packet,
+			       VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (ret)
+		goto error;
+
+	wait_for_completion(&comp_pkt.host_event);
+
+	hpdev->desc = *desc;
+	get_pcichild(hpdev, hv_pcidev_ref_initial);
+	get_pcichild(hpdev, hv_pcidev_ref_childlist);
+	spin_lock_irqsave(&hbus->device_list_lock, flags);
+
+	/*
+	 * When a device is being added to the bus, we set the PCI domain
+	 * number to be the device serial number, which is non-zero and
+	 * unique on the same VM.  The serial numbers start with 1, and
+	 * increase by 1 for each device.  So device names including this
+	 * can have shorter names than based on the bus instance UUID.
+	 * Only the first device serial number is used for domain, so the
+	 * domain number will not change after the first device is added.
+	 * The lower 16 bits of the serial number is used, otherwise some
+	 * drivers may not be able to handle it.
+	 */
+	if (list_empty(&hbus->children))
+		hbus->sysdata.domain = desc->ser & 0xFFFF;
+	list_add_tail(&hpdev->list_entry, &hbus->children);
+	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+	return hpdev;
+
+error:
+	kfree(hpdev);
+	return NULL;
+}
+
+/**
+ * get_pcichild_wslot() - Find device from slot
+ * @hbus:	Root PCI bus, as understood by this driver
+ * @wslot:	Location on the bus
+ *
+ * This function looks up a PCI device and returns the internal
+ * representation of it.  It acquires a reference on it, so that
+ * the device won't be deleted while somebody is using it.  The
+ * caller is responsible for calling put_pcichild() to release
+ * this reference.
+ *
+ * Return:	Internal representation of a PCI device
+ */
+static struct hv_pci_dev *get_pcichild_wslot(struct hv_pcibus_device *hbus,
+					     u32 wslot)
+{
+	unsigned long flags;
+	struct hv_pci_dev *iter, *hpdev = NULL;
+
+	spin_lock_irqsave(&hbus->device_list_lock, flags);
+	list_for_each_entry(iter, &hbus->children, list_entry) {
+		if (iter->desc.win_slot.slot == wslot) {
+			hpdev = iter;
+			get_pcichild(hpdev, hv_pcidev_ref_by_slot);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+	return hpdev;
+}
+
+/**
+ * pci_devices_present_work() - Handle new list of child devices
+ * @work:	Work struct embedded in struct hv_dr_work
+ *
+ * "Bus Relations" is the Windows term for "children of this
+ * bus."  The terminology is preserved here for people trying to
+ * debug the interaction between Hyper-V and Linux.  This
+ * function is called when the parent partition reports a list
+ * of functions that should be observed under this PCI Express
+ * port (bus).
+ *
+ * This function updates the list, and must tolerate being
+ * called multiple times with the same information.  The typical
+ * number of child devices is one, with very atypical cases
+ * involving three or four, so the algorithms used here can be
+ * simple and inefficient.
+ *
+ * It must also treat the omission of a previously observed device as
+ * notification that the device no longer exists.
+ *
+ * Note that this function is a work item, and it may not be
+ * invoked in the order that it was queued.  Back to back
+ * updates of the list of present devices may involve queuing
+ * multiple work items, and this one may run before ones that
+ * were sent later. As such, this function only does something
+ * if is the last one in the queue.
+ */
+static void pci_devices_present_work(struct work_struct *work)
+{
+	u32 child_no;
+	bool found;
+	struct list_head *iter;
+	struct pci_function_description *new_desc;
+	struct hv_pci_dev *hpdev;
+	struct hv_pcibus_device *hbus;
+	struct list_head removed;
+	struct hv_dr_work *dr_wrk;
+	struct hv_dr_state *dr = NULL;
+	unsigned long flags;
+
+	dr_wrk = container_of(work, struct hv_dr_work, wrk);
+	hbus = dr_wrk->bus;
+	kfree(dr_wrk);
+
+	INIT_LIST_HEAD(&removed);
+
+	if (down_interruptible(&hbus->enum_sem)) {
+		put_hvpcibus(hbus);
+		return;
+	}
+
+	/* Pull this off the queue and process it if it was the last one. */
+	spin_lock_irqsave(&hbus->device_list_lock, flags);
+	while (!list_empty(&hbus->dr_list)) {
+		dr = list_first_entry(&hbus->dr_list, struct hv_dr_state,
+				      list_entry);
+		list_del(&dr->list_entry);
+
+		/* Throw this away if the list still has stuff in it. */
+		if (!list_empty(&hbus->dr_list)) {
+			kfree(dr);
+			continue;
+		}
+	}
+	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+	if (!dr) {
+		up(&hbus->enum_sem);
+		put_hvpcibus(hbus);
+		return;
+	}
+
+	/* First, mark all existing children as reported missing. */
+	spin_lock_irqsave(&hbus->device_list_lock, flags);
+	list_for_each(iter, &hbus->children) {
+			hpdev = container_of(iter, struct hv_pci_dev,
+					     list_entry);
+			hpdev->reported_missing = true;
+	}
+	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+	/* Next, add back any reported devices. */
+	for (child_no = 0; child_no < dr->device_count; child_no++) {
+		found = false;
+		new_desc = &dr->func[child_no];
+
+		spin_lock_irqsave(&hbus->device_list_lock, flags);
+		list_for_each(iter, &hbus->children) {
+			hpdev = container_of(iter, struct hv_pci_dev,
+					     list_entry);
+			if ((hpdev->desc.win_slot.slot ==
+			     new_desc->win_slot.slot) &&
+			    (hpdev->desc.v_id == new_desc->v_id) &&
+			    (hpdev->desc.d_id == new_desc->d_id) &&
+			    (hpdev->desc.ser == new_desc->ser)) {
+				hpdev->reported_missing = false;
+				found = true;
+			}
+		}
+		spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+		if (!found) {
+			hpdev = new_pcichild_device(hbus, new_desc);
+			if (!hpdev)
+				dev_err(&hbus->hdev->device,
+					"couldn't record a child device.\n");
+		}
+	}
+
+	/* Move missing children to a list on the stack. */
+	spin_lock_irqsave(&hbus->device_list_lock, flags);
+	do {
+		found = false;
+		list_for_each(iter, &hbus->children) {
+			hpdev = container_of(iter, struct hv_pci_dev,
+					     list_entry);
+			if (hpdev->reported_missing) {
+				found = true;
+				put_pcichild(hpdev, hv_pcidev_ref_childlist);
+				list_move_tail(&hpdev->list_entry, &removed);
+				break;
+			}
+		}
+	} while (found);
+	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+	/* Delete everything that should no longer exist. */
+	while (!list_empty(&removed)) {
+		hpdev = list_first_entry(&removed, struct hv_pci_dev,
+					 list_entry);
+		list_del(&hpdev->list_entry);
+		put_pcichild(hpdev, hv_pcidev_ref_initial);
+	}
+
+	switch (hbus->state) {
+	case hv_pcibus_installed:
+		/*
+		 * Tell the core to rescan bus
+		 * because there may have been changes.
+		 */
+		pci_lock_rescan_remove();
+		pci_scan_child_bus(hbus->pci_bus);
+		pci_unlock_rescan_remove();
+		break;
+
+	case hv_pcibus_init:
+	case hv_pcibus_probed:
+		survey_child_resources(hbus);
+		break;
+
+	default:
+		break;
+	}
+
+	up(&hbus->enum_sem);
+	put_hvpcibus(hbus);
+	kfree(dr);
+}
+
+/**
+ * hv_pci_devices_present() - Handles list of new children
+ * @hbus:	Root PCI bus, as understood by this driver
+ * @relations:	Packet from host listing children
+ *
+ * This function is invoked whenever a new list of devices for
+ * this bus appears.
+ */
+static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
+				   struct pci_bus_relations *relations)
+{
+	struct hv_dr_state *dr;
+	struct hv_dr_work *dr_wrk;
+	unsigned long flags;
+
+	dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT);
+	if (!dr_wrk)
+		return;
+
+	dr = kzalloc(offsetof(struct hv_dr_state, func) +
+		     (sizeof(struct pci_function_description) *
+		      (relations->device_count)), GFP_NOWAIT);
+	if (!dr)  {
+		kfree(dr_wrk);
+		return;
+	}
+
+	INIT_WORK(&dr_wrk->wrk, pci_devices_present_work);
+	dr_wrk->bus = hbus;
+	dr->device_count = relations->device_count;
+	if (dr->device_count != 0) {
+		memcpy(dr->func, relations->func,
+		       sizeof(struct pci_function_description) *
+		       dr->device_count);
+	}
+
+	spin_lock_irqsave(&hbus->device_list_lock, flags);
+	list_add_tail(&dr->list_entry, &hbus->dr_list);
+	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+	get_hvpcibus(hbus);
+	schedule_work(&dr_wrk->wrk);
+}
+
+/**
+ * hv_eject_device_work() - Asynchronously handles ejection
+ * @work:	Work struct embedded in internal device struct
+ *
+ * This function handles ejecting a device.  Windows will
+ * attempt to gracefully eject a device, waiting 60 seconds to
+ * hear back from the guest OS that this completed successfully.
+ * If this timer expires, the device will be forcibly removed.
+ */
+static void hv_eject_device_work(struct work_struct *work)
+{
+	struct pci_eject_response *ejct_pkt;
+	struct hv_pci_dev *hpdev;
+	struct pci_dev *pdev;
+	unsigned long flags;
+	int wslot;
+	struct {
+		struct pci_packet pkt;
+		u8 buffer[sizeof(struct pci_eject_response)];
+	} ctxt;
+
+	hpdev = container_of(work, struct hv_pci_dev, wrk);
+
+	if (hpdev->state != hv_pcichild_ejecting) {
+		put_pcichild(hpdev, hv_pcidev_ref_pnp);
+		return;
+	}
+
+	/*
+	 * Ejection can come before or after the PCI bus has been set up, so
+	 * attempt to find it and tear down the bus state, if it exists.  This
+	 * must be done without constructs like pci_domain_nr(hbus->pci_bus)
+	 * because hbus->pci_bus may not exist yet.
+	 */
+	wslot = wslot_to_devfn(hpdev->desc.win_slot.slot);
+	pdev = pci_get_domain_bus_and_slot(hpdev->hbus->sysdata.domain, 0,
+					   wslot);
+	if (pdev) {
+		pci_lock_rescan_remove();
+		pci_stop_and_remove_bus_device(pdev);
+		pci_dev_put(pdev);
+		pci_unlock_rescan_remove();
+	}
+
+	spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags);
+	list_del(&hpdev->list_entry);
+	spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags);
+
+	memset(&ctxt, 0, sizeof(ctxt));
+	ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
+	ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;
+	ejct_pkt->wslot.slot = hpdev->desc.win_slot.slot;
+	vmbus_sendpacket(hpdev->hbus->hdev->channel, ejct_pkt,
+			 sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
+			 VM_PKT_DATA_INBAND, 0);
+
+	put_pcichild(hpdev, hv_pcidev_ref_childlist);
+	put_pcichild(hpdev, hv_pcidev_ref_pnp);
+	put_hvpcibus(hpdev->hbus);
+}
+
+/**
+ * hv_pci_eject_device() - Handles device ejection
+ * @hpdev:	Internal device tracking struct
+ *
+ * This function is invoked when an ejection packet arrives.  It
+ * just schedules work so that we don't re-enter the packet
+ * delivery code handling the ejection.
+ */
+static void hv_pci_eject_device(struct hv_pci_dev *hpdev)
+{
+	hpdev->state = hv_pcichild_ejecting;
+	get_pcichild(hpdev, hv_pcidev_ref_pnp);
+	INIT_WORK(&hpdev->wrk, hv_eject_device_work);
+	get_hvpcibus(hpdev->hbus);
+	schedule_work(&hpdev->wrk);
+}
+
+/**
+ * hv_pci_onchannelcallback() - Handles incoming packets
+ * @context:	Internal bus tracking struct
+ *
+ * This function is invoked whenever the host sends a packet to
+ * this channel (which is private to this root PCI bus).
+ */
+static void hv_pci_onchannelcallback(void *context)
+{
+	const int packet_size = 0x100;
+	int ret;
+	struct hv_pcibus_device *hbus = context;
+	u32 bytes_recvd;
+	u64 req_id;
+	struct vmpacket_descriptor *desc;
+	unsigned char *buffer;
+	int bufferlen = packet_size;
+	struct pci_packet *comp_packet;
+	struct pci_response *response;
+	struct pci_incoming_message *new_message;
+	struct pci_bus_relations *bus_rel;
+	struct pci_dev_incoming *dev_message;
+	struct hv_pci_dev *hpdev;
+
+	buffer = kmalloc(bufferlen, GFP_ATOMIC);
+	if (!buffer)
+		return;
+
+	while (1) {
+		ret = vmbus_recvpacket_raw(hbus->hdev->channel, buffer,
+					   bufferlen, &bytes_recvd, &req_id);
+
+		if (ret == -ENOBUFS) {
+			kfree(buffer);
+			/* Handle large packet */
+			bufferlen = bytes_recvd;
+			buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
+			if (!buffer)
+				return;
+			continue;
+		}
+
+		/* Zero length indicates there are no more packets. */
+		if (ret || !bytes_recvd)
+			break;
+
+		/*
+		 * All incoming packets must be at least as large as a
+		 * response.
+		 */
+		if (bytes_recvd <= sizeof(struct pci_response))
+			continue;
+		desc = (struct vmpacket_descriptor *)buffer;
+
+		switch (desc->type) {
+		case VM_PKT_COMP:
+
+			/*
+			 * The host is trusted, and thus it's safe to interpret
+			 * this transaction ID as a pointer.
+			 */
+			comp_packet = (struct pci_packet *)req_id;
+			response = (struct pci_response *)buffer;
+			comp_packet->completion_func(comp_packet->compl_ctxt,
+						     response,
+						     bytes_recvd);
+			break;
+
+		case VM_PKT_DATA_INBAND:
+
+			new_message = (struct pci_incoming_message *)buffer;
+			switch (new_message->message_type.type) {
+			case PCI_BUS_RELATIONS:
+
+				bus_rel = (struct pci_bus_relations *)buffer;
+				if (bytes_recvd <
+				    offsetof(struct pci_bus_relations, func) +
+				    (sizeof(struct pci_function_description) *
+				     (bus_rel->device_count))) {
+					dev_err(&hbus->hdev->device,
+						"bus relations too small\n");
+					break;
+				}
+
+				hv_pci_devices_present(hbus, bus_rel);
+				break;
+
+			case PCI_EJECT:
+
+				dev_message = (struct pci_dev_incoming *)buffer;
+				hpdev = get_pcichild_wslot(hbus,
+						      dev_message->wslot.slot);
+				if (hpdev) {
+					hv_pci_eject_device(hpdev);
+					put_pcichild(hpdev,
+							hv_pcidev_ref_by_slot);
+				}
+				break;
+
+			default:
+				dev_warn(&hbus->hdev->device,
+					"Unimplemented protocol message %x\n",
+					new_message->message_type.type);
+				break;
+			}
+			break;
+
+		default:
+			dev_err(&hbus->hdev->device,
+				"unhandled packet type %d, tid %llx len %d\n",
+				desc->type, req_id, bytes_recvd);
+			break;
+		}
+	}
+
+	kfree(buffer);
+}
+
+/**
+ * hv_pci_protocol_negotiation() - Set up protocol
+ * @hdev:	VMBus's tracking struct for this root PCI bus
+ *
+ * This driver is intended to support running on Windows 10
+ * (server) and later versions. It will not run on earlier
+ * versions, as they assume that many of the operations which
+ * Linux needs accomplished with a spinlock held were done via
+ * asynchronous messaging via VMBus.  Windows 10 increases the
+ * surface area of PCI emulation so that these actions can take
+ * place by suspending a virtual processor for their duration.
+ *
+ * This function negotiates the channel protocol version,
+ * failing if the host doesn't support the necessary protocol
+ * level.
+ */
+static int hv_pci_protocol_negotiation(struct hv_device *hdev)
+{
+	struct pci_version_request *version_req;
+	struct hv_pci_compl comp_pkt;
+	struct pci_packet *pkt;
+	int ret;
+
+	/*
+	 * Initiate the handshake with the host and negotiate
+	 * a version that the host can support. We start with the
+	 * highest version number and go down if the host cannot
+	 * support it.
+	 */
+	pkt = kzalloc(sizeof(*pkt) + sizeof(*version_req), GFP_KERNEL);
+	if (!pkt)
+		return -ENOMEM;
+
+	init_completion(&comp_pkt.host_event);
+	pkt->completion_func = hv_pci_generic_compl;
+	pkt->compl_ctxt = &comp_pkt;
+	version_req = (struct pci_version_request *)&pkt->message;
+	version_req->message_type.type = PCI_QUERY_PROTOCOL_VERSION;
+	version_req->protocol_version = PCI_PROTOCOL_VERSION_CURRENT;
+
+	ret = vmbus_sendpacket(hdev->channel, version_req,
+			       sizeof(struct pci_version_request),
+			       (unsigned long)pkt, VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (ret)
+		goto exit;
+
+	wait_for_completion(&comp_pkt.host_event);
+
+	if (comp_pkt.completion_status < 0) {
+		dev_err(&hdev->device,
+			"PCI Pass-through VSP failed version request %x\n",
+			comp_pkt.completion_status);
+		ret = -EPROTO;
+		goto exit;
+	}
+
+	ret = 0;
+
+exit:
+	kfree(pkt);
+	return ret;
+}
+
+/**
+ * hv_pci_free_bridge_windows() - Release memory regions for the
+ * bus
+ * @hbus:	Root PCI bus, as understood by this driver
+ */
+static void hv_pci_free_bridge_windows(struct hv_pcibus_device *hbus)
+{
+	/*
+	 * Set the resources back to the way they looked when they
+	 * were allocated by setting IORESOURCE_BUSY again.
+	 */
+
+	if (hbus->low_mmio_space && hbus->low_mmio_res) {
+		hbus->low_mmio_res->flags |= IORESOURCE_BUSY;
+		vmbus_free_mmio(hbus->low_mmio_res->start,
+				resource_size(hbus->low_mmio_res));
+	}
+
+	if (hbus->high_mmio_space && hbus->high_mmio_res) {
+		hbus->high_mmio_res->flags |= IORESOURCE_BUSY;
+		vmbus_free_mmio(hbus->high_mmio_res->start,
+				resource_size(hbus->high_mmio_res));
+	}
+}
+
+/**
+ * hv_pci_allocate_bridge_windows() - Allocate memory regions
+ * for the bus
+ * @hbus:	Root PCI bus, as understood by this driver
+ *
+ * This function calls vmbus_allocate_mmio(), which is itself a
+ * bit of a compromise.  Ideally, we might change the pnp layer
+ * in the kernel such that it comprehends either PCI devices
+ * which are "grandchildren of ACPI," with some intermediate bus
+ * node (in this case, VMBus) or change it such that it
+ * understands VMBus.  The pnp layer, however, has been declared
+ * deprecated, and not subject to change.
+ *
+ * The workaround, implemented here, is to ask VMBus to allocate
+ * MMIO space for this bus.  VMBus itself knows which ranges are
+ * appropriate by looking at its own ACPI objects.  Then, after
+ * these ranges are claimed, they're modified to look like they
+ * would have looked if the ACPI and pnp code had allocated
+ * bridge windows.  These descriptors have to exist in this form
+ * in order to satisfy the code which will get invoked when the
+ * endpoint PCI function driver calls request_mem_region() or
+ * request_mem_region_exclusive().
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_allocate_bridge_windows(struct hv_pcibus_device *hbus)
+{
+	resource_size_t align;
+	int ret;
+
+	if (hbus->low_mmio_space) {
+		align = 1ULL << (63 - __builtin_clzll(hbus->low_mmio_space));
+		ret = vmbus_allocate_mmio(&hbus->low_mmio_res, hbus->hdev, 0,
+					  (u64)(u32)0xffffffff,
+					  hbus->low_mmio_space,
+					  align, false);
+		if (ret) {
+			dev_err(&hbus->hdev->device,
+				"Need %#llx of low MMIO space. Consider reconfiguring the VM.\n",
+				hbus->low_mmio_space);
+			return ret;
+		}
+
+		/* Modify this resource to become a bridge window. */
+		hbus->low_mmio_res->flags |= IORESOURCE_WINDOW;
+		hbus->low_mmio_res->flags &= ~IORESOURCE_BUSY;
+		pci_add_resource(&hbus->resources_for_children,
+				 hbus->low_mmio_res);
+	}
+
+	if (hbus->high_mmio_space) {
+		align = 1ULL << (63 - __builtin_clzll(hbus->high_mmio_space));
+		ret = vmbus_allocate_mmio(&hbus->high_mmio_res, hbus->hdev,
+					  0x100000000, -1,
+					  hbus->high_mmio_space, align,
+					  false);
+		if (ret) {
+			dev_err(&hbus->hdev->device,
+				"Need %#llx of high MMIO space. Consider reconfiguring the VM.\n",
+				hbus->high_mmio_space);
+			goto release_low_mmio;
+		}
+
+		/* Modify this resource to become a bridge window. */
+		hbus->high_mmio_res->flags |= IORESOURCE_WINDOW;
+		hbus->high_mmio_res->flags &= ~IORESOURCE_BUSY;
+		pci_add_resource(&hbus->resources_for_children,
+				 hbus->high_mmio_res);
+	}
+
+	return 0;
+
+release_low_mmio:
+	if (hbus->low_mmio_res) {
+		vmbus_free_mmio(hbus->low_mmio_res->start,
+				resource_size(hbus->low_mmio_res));
+	}
+
+	return ret;
+}
+
+/**
+ * hv_allocate_config_window() - Find MMIO space for PCI Config
+ * @hbus:	Root PCI bus, as understood by this driver
+ *
+ * This function claims memory-mapped I/O space for accessing
+ * configuration space for the functions on this bus.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_allocate_config_window(struct hv_pcibus_device *hbus)
+{
+	int ret;
+
+	/*
+	 * Set up a region of MMIO space to use for accessing configuration
+	 * space.
+	 */
+	ret = vmbus_allocate_mmio(&hbus->mem_config, hbus->hdev, 0, -1,
+				  PCI_CONFIG_MMIO_LENGTH, 0x1000, false);
+	if (ret)
+		return ret;
+
+	/*
+	 * vmbus_allocate_mmio() gets used for allocating both device endpoint
+	 * resource claims (those which cannot be overlapped) and the ranges
+	 * which are valid for the children of this bus, which are intended
+	 * to be overlapped by those children.  Set the flag on this claim
+	 * meaning that this region can't be overlapped.
+	 */
+
+	hbus->mem_config->flags |= IORESOURCE_BUSY;
+
+	return 0;
+}
+
+static void hv_free_config_window(struct hv_pcibus_device *hbus)
+{
+	vmbus_free_mmio(hbus->mem_config->start, PCI_CONFIG_MMIO_LENGTH);
+}
+
+/**
+ * hv_pci_enter_d0() - Bring the "bus" into the D0 power state
+ * @hdev:	VMBus's tracking struct for this root PCI bus
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_enter_d0(struct hv_device *hdev)
+{
+	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+	struct pci_bus_d0_entry *d0_entry;
+	struct hv_pci_compl comp_pkt;
+	struct pci_packet *pkt;
+	int ret;
+
+	/*
+	 * Tell the host that the bus is ready to use, and moved into the
+	 * powered-on state.  This includes telling the host which region
+	 * of memory-mapped I/O space has been chosen for configuration space
+	 * access.
+	 */
+	pkt = kzalloc(sizeof(*pkt) + sizeof(*d0_entry), GFP_KERNEL);
+	if (!pkt)
+		return -ENOMEM;
+
+	init_completion(&comp_pkt.host_event);
+	pkt->completion_func = hv_pci_generic_compl;
+	pkt->compl_ctxt = &comp_pkt;
+	d0_entry = (struct pci_bus_d0_entry *)&pkt->message;
+	d0_entry->message_type.type = PCI_BUS_D0ENTRY;
+	d0_entry->mmio_base = hbus->mem_config->start;
+
+	ret = vmbus_sendpacket(hdev->channel, d0_entry, sizeof(*d0_entry),
+			       (unsigned long)pkt, VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (ret)
+		goto exit;
+
+	wait_for_completion(&comp_pkt.host_event);
+
+	if (comp_pkt.completion_status < 0) {
+		dev_err(&hdev->device,
+			"PCI Pass-through VSP failed D0 Entry with status %x\n",
+			comp_pkt.completion_status);
+		ret = -EPROTO;
+		goto exit;
+	}
+
+	ret = 0;
+
+exit:
+	kfree(pkt);
+	return ret;
+}
+
+/**
+ * hv_pci_query_relations() - Ask host to send list of child
+ * devices
+ * @hdev:	VMBus's tracking struct for this root PCI bus
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_query_relations(struct hv_device *hdev)
+{
+	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+	struct pci_message message;
+	struct completion comp;
+	int ret;
+
+	/* Ask the host to send along the list of child devices */
+	init_completion(&comp);
+	if (cmpxchg(&hbus->survey_event, NULL, &comp))
+		return -ENOTEMPTY;
+
+	memset(&message, 0, sizeof(message));
+	message.type = PCI_QUERY_BUS_RELATIONS;
+
+	ret = vmbus_sendpacket(hdev->channel, &message, sizeof(message),
+			       0, VM_PKT_DATA_INBAND, 0);
+	if (ret)
+		return ret;
+
+	wait_for_completion(&comp);
+	return 0;
+}
+
+/**
+ * hv_send_resources_allocated() - Report local resource choices
+ * @hdev:	VMBus's tracking struct for this root PCI bus
+ *
+ * The host OS is expecting to be sent a request as a message
+ * which contains all the resources that the device will use.
+ * The response contains those same resources, "translated"
+ * which is to say, the values which should be used by the
+ * hardware, when it delivers an interrupt.  (MMIO resources are
+ * used in local terms.)  This is nice for Windows, and lines up
+ * with the FDO/PDO split, which doesn't exist in Linux.  Linux
+ * is deeply expecting to scan an emulated PCI configuration
+ * space.  So this message is sent here only to drive the state
+ * machine on the host forward.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_send_resources_allocated(struct hv_device *hdev)
+{
+	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+	struct pci_resources_assigned *res_assigned;
+	struct hv_pci_compl comp_pkt;
+	struct hv_pci_dev *hpdev;
+	struct pci_packet *pkt;
+	u32 wslot;
+	int ret;
+
+	pkt = kmalloc(sizeof(*pkt) + sizeof(*res_assigned), GFP_KERNEL);
+	if (!pkt)
+		return -ENOMEM;
+
+	ret = 0;
+
+	for (wslot = 0; wslot < 256; wslot++) {
+		hpdev = get_pcichild_wslot(hbus, wslot);
+		if (!hpdev)
+			continue;
+
+		memset(pkt, 0, sizeof(*pkt) + sizeof(*res_assigned));
+		init_completion(&comp_pkt.host_event);
+		pkt->completion_func = hv_pci_generic_compl;
+		pkt->compl_ctxt = &comp_pkt;
+		res_assigned = (struct pci_resources_assigned *)&pkt->message;
+		res_assigned->message_type.type = PCI_RESOURCES_ASSIGNED;
+		res_assigned->wslot.slot = hpdev->desc.win_slot.slot;
+
+		put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+
+		ret = vmbus_sendpacket(
+			hdev->channel, &pkt->message,
+			sizeof(*res_assigned),
+			(unsigned long)pkt,
+			VM_PKT_DATA_INBAND,
+			VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+		if (ret)
+			break;
+
+		wait_for_completion(&comp_pkt.host_event);
+
+		if (comp_pkt.completion_status < 0) {
+			ret = -EPROTO;
+			dev_err(&hdev->device,
+				"resource allocated returned 0x%x",
+				comp_pkt.completion_status);
+			break;
+		}
+	}
+
+	kfree(pkt);
+	return ret;
+}
+
+/**
+ * hv_send_resources_released() - Report local resources
+ * released
+ * @hdev:	VMBus's tracking struct for this root PCI bus
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_send_resources_released(struct hv_device *hdev)
+{
+	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+	struct pci_child_message pkt;
+	struct hv_pci_dev *hpdev;
+	u32 wslot;
+	int ret;
+
+	for (wslot = 0; wslot < 256; wslot++) {
+		hpdev = get_pcichild_wslot(hbus, wslot);
+		if (!hpdev)
+			continue;
+
+		memset(&pkt, 0, sizeof(pkt));
+		pkt.message_type.type = PCI_RESOURCES_RELEASED;
+		pkt.wslot.slot = hpdev->desc.win_slot.slot;
+
+		put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+
+		ret = vmbus_sendpacket(hdev->channel, &pkt, sizeof(pkt), 0,
+				       VM_PKT_DATA_INBAND, 0);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void get_hvpcibus(struct hv_pcibus_device *hbus)
+{
+	atomic_inc(&hbus->remove_lock);
+}
+
+static void put_hvpcibus(struct hv_pcibus_device *hbus)
+{
+	if (atomic_dec_and_test(&hbus->remove_lock))
+		complete(&hbus->remove_event);
+}
+
+/**
+ * hv_pci_probe() - New VMBus channel probe, for a root PCI bus
+ * @hdev:	VMBus's tracking struct for this root PCI bus
+ * @dev_id:	Identifies the device itself
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_probe(struct hv_device *hdev,
+			const struct hv_vmbus_device_id *dev_id)
+{
+	struct hv_pcibus_device *hbus;
+	int ret;
+
+	hbus = kzalloc(sizeof(*hbus), GFP_KERNEL);
+	if (!hbus)
+		return -ENOMEM;
+	hbus->state = hv_pcibus_init;
+
+	/*
+	 * The PCI bus "domain" is what is called "segment" in ACPI and
+	 * other specs.  Pull it from the instance ID, to get something
+	 * unique.  Bytes 8 and 9 are what is used in Windows guests, so
+	 * do the same thing for consistency.  Note that, since this code
+	 * only runs in a Hyper-V VM, Hyper-V can (and does) guarantee
+	 * that (1) the only domain in use for something that looks like
+	 * a physical PCI bus (which is actually emulated by the
+	 * hypervisor) is domain 0 and (2) there will be no overlap
+	 * between domains derived from these instance IDs in the same
+	 * VM.
+	 */
+	hbus->sysdata.domain = hdev->dev_instance.b[9] |
+			       hdev->dev_instance.b[8] << 8;
+
+	hbus->hdev = hdev;
+	atomic_inc(&hbus->remove_lock);
+	INIT_LIST_HEAD(&hbus->children);
+	INIT_LIST_HEAD(&hbus->dr_list);
+	INIT_LIST_HEAD(&hbus->resources_for_children);
+	spin_lock_init(&hbus->config_lock);
+	spin_lock_init(&hbus->device_list_lock);
+	spin_lock_init(&hbus->retarget_msi_interrupt_lock);
+	sema_init(&hbus->enum_sem, 1);
+	init_completion(&hbus->remove_event);
+
+	ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0,
+			 hv_pci_onchannelcallback, hbus);
+	if (ret)
+		goto free_bus;
+
+	hv_set_drvdata(hdev, hbus);
+
+	ret = hv_pci_protocol_negotiation(hdev);
+	if (ret)
+		goto close;
+
+	ret = hv_allocate_config_window(hbus);
+	if (ret)
+		goto close;
+
+	hbus->cfg_addr = ioremap(hbus->mem_config->start,
+				 PCI_CONFIG_MMIO_LENGTH);
+	if (!hbus->cfg_addr) {
+		dev_err(&hdev->device,
+			"Unable to map a virtual address for config space\n");
+		ret = -ENOMEM;
+		goto free_config;
+	}
+
+	hbus->sysdata.fwnode = irq_domain_alloc_fwnode(hbus);
+	if (!hbus->sysdata.fwnode) {
+		ret = -ENOMEM;
+		goto unmap;
+	}
+
+	ret = hv_pcie_init_irq_domain(hbus);
+	if (ret)
+		goto free_fwnode;
+
+	ret = hv_pci_query_relations(hdev);
+	if (ret)
+		goto free_irq_domain;
+
+	ret = hv_pci_enter_d0(hdev);
+	if (ret)
+		goto free_irq_domain;
+
+	ret = hv_pci_allocate_bridge_windows(hbus);
+	if (ret)
+		goto free_irq_domain;
+
+	ret = hv_send_resources_allocated(hdev);
+	if (ret)
+		goto free_windows;
+
+	prepopulate_bars(hbus);
+
+	hbus->state = hv_pcibus_probed;
+
+	ret = create_root_hv_pci_bus(hbus);
+	if (ret)
+		goto free_windows;
+
+	return 0;
+
+free_windows:
+	hv_pci_free_bridge_windows(hbus);
+free_irq_domain:
+	irq_domain_remove(hbus->irq_domain);
+free_fwnode:
+	irq_domain_free_fwnode(hbus->sysdata.fwnode);
+unmap:
+	iounmap(hbus->cfg_addr);
+free_config:
+	hv_free_config_window(hbus);
+close:
+	vmbus_close(hdev->channel);
+free_bus:
+	kfree(hbus);
+	return ret;
+}
+
+static void hv_pci_bus_exit(struct hv_device *hdev)
+{
+	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+	struct {
+		struct pci_packet teardown_packet;
+		u8 buffer[sizeof(struct pci_message)];
+	} pkt;
+	struct pci_bus_relations relations;
+	struct hv_pci_compl comp_pkt;
+	int ret;
+
+	/*
+	 * After the host sends the RESCIND_CHANNEL message, it doesn't
+	 * access the per-channel ringbuffer any longer.
+	 */
+	if (hdev->channel->rescind)
+		return;
+
+	/* Delete any children which might still exist. */
+	memset(&relations, 0, sizeof(relations));
+	hv_pci_devices_present(hbus, &relations);
+
+	ret = hv_send_resources_released(hdev);
+	if (ret)
+		dev_err(&hdev->device,
+			"Couldn't send resources released packet(s)\n");
+
+	memset(&pkt.teardown_packet, 0, sizeof(pkt.teardown_packet));
+	init_completion(&comp_pkt.host_event);
+	pkt.teardown_packet.completion_func = hv_pci_generic_compl;
+	pkt.teardown_packet.compl_ctxt = &comp_pkt;
+	pkt.teardown_packet.message[0].type = PCI_BUS_D0EXIT;
+
+	ret = vmbus_sendpacket(hdev->channel, &pkt.teardown_packet.message,
+			       sizeof(struct pci_message),
+			       (unsigned long)&pkt.teardown_packet,
+			       VM_PKT_DATA_INBAND,
+			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (!ret)
+		wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ);
+}
+
+/**
+ * hv_pci_remove() - Remove routine for this VMBus channel
+ * @hdev:	VMBus's tracking struct for this root PCI bus
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_remove(struct hv_device *hdev)
+{
+	struct hv_pcibus_device *hbus;
+
+	hbus = hv_get_drvdata(hdev);
+	if (hbus->state == hv_pcibus_installed) {
+		/* Remove the bus from PCI's point of view. */
+		pci_lock_rescan_remove();
+		pci_stop_root_bus(hbus->pci_bus);
+		pci_remove_root_bus(hbus->pci_bus);
+		pci_unlock_rescan_remove();
+		hbus->state = hv_pcibus_removed;
+	}
+
+	hv_pci_bus_exit(hdev);
+
+	vmbus_close(hdev->channel);
+
+	iounmap(hbus->cfg_addr);
+	hv_free_config_window(hbus);
+	pci_free_resource_list(&hbus->resources_for_children);
+	hv_pci_free_bridge_windows(hbus);
+	irq_domain_remove(hbus->irq_domain);
+	irq_domain_free_fwnode(hbus->sysdata.fwnode);
+	put_hvpcibus(hbus);
+	wait_for_completion(&hbus->remove_event);
+	kfree(hbus);
+	return 0;
+}
+
+static const struct hv_vmbus_device_id hv_pci_id_table[] = {
+	/* PCI Pass-through Class ID */
+	/* 44C4F61D-4444-4400-9D52-802E27EDE19F */
+	{ HV_PCIE_GUID, },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(vmbus, hv_pci_id_table);
+
+static struct hv_driver hv_pci_drv = {
+	.name		= "hv_pci",
+	.id_table	= hv_pci_id_table,
+	.probe		= hv_pci_probe,
+	.remove		= hv_pci_remove,
+};
+
+static void __exit exit_hv_pci_drv(void)
+{
+	vmbus_driver_unregister(&hv_pci_drv);
+}
+
+static int __init init_hv_pci_drv(void)
+{
+	return vmbus_driver_register(&hv_pci_drv);
+}
+
+module_init(init_hv_pci_drv);
+module_exit(exit_hv_pci_drv);
+
+MODULE_DESCRIPTION("Hyper-V PCI");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/pci/host/pci-imx6.c
+++ linux-4.4.0/drivers/pci/host/pci-imx6.c
@@ -537,7 +537,8 @@
 
 		ret = devm_request_irq(&pdev->dev, pp->msi_irq,
 				       imx6_pcie_msi_handler,
-				       IRQF_SHARED, "mx6-pcie-msi", pp);
+				       IRQF_SHARED | IRQF_NO_THREAD,
+				       "mx6-pcie-msi", pp);
 		if (ret) {
 			dev_err(&pdev->dev, "failed to request MSI irq\n");
 			return ret;
--- linux-4.4.0.orig/drivers/pci/host/pci-keystone-dw.c
+++ linux-4.4.0/drivers/pci/host/pci-keystone-dw.c
@@ -58,11 +58,6 @@
 
 #define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
 
-static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
-{
-	return sys->private_data;
-}
-
 static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
 					     u32 *bit_pos)
 {
@@ -108,7 +103,7 @@
 	struct pcie_port *pp;
 
 	msi = irq_data_get_msi_desc(d);
-	pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+	pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
 	ks_pcie = to_keystone_pcie(pp);
 	offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
 	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
@@ -146,7 +141,7 @@
 	u32 offset;
 
 	msi = irq_data_get_msi_desc(d);
-	pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+	pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
 	ks_pcie = to_keystone_pcie(pp);
 	offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
 
@@ -167,7 +162,7 @@
 	u32 offset;
 
 	msi = irq_data_get_msi_desc(d);
-	pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+	pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
 	ks_pcie = to_keystone_pcie(pp);
 	offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
 
@@ -455,7 +450,7 @@
 	/* Disable Link training */
 	val = readl(ks_pcie->va_app_base + CMD_STATUS);
 	val &= ~LTSSM_EN_VAL;
-	writel(LTSSM_EN_VAL | val,  ks_pcie->va_app_base + CMD_STATUS);
+	writel(val,  ks_pcie->va_app_base + CMD_STATUS);
 
 	/* Initiate Link Training */
 	val = readl(ks_pcie->va_app_base + CMD_STATUS);
--- linux-4.4.0.orig/drivers/pci/host/pci-keystone.c
+++ linux-4.4.0/drivers/pci/host/pci-keystone.c
@@ -42,6 +42,7 @@
 #define PCIE_RC_K2HK		0xb008
 #define PCIE_RC_K2E		0xb009
 #define PCIE_RC_K2L		0xb00a
+#define PCIE_RC_K2G		0xb00b
 
 #define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
 
@@ -56,6 +57,8 @@
 		 .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
 		{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2L),
 		 .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
+		{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2G),
+		 .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
 		{ 0, },
 	};
 
@@ -179,14 +182,16 @@
 	}
 
 	/* interrupt controller is in a child node */
-	*np_temp = of_find_node_by_name(np_pcie, controller);
+	*np_temp = of_get_child_by_name(np_pcie, controller);
 	if (!(*np_temp)) {
 		dev_err(dev, "Node for %s is absent\n", controller);
 		goto out;
 	}
 	temp = of_irq_count(*np_temp);
-	if (!temp)
+	if (!temp) {
+		of_node_put(*np_temp);
 		goto out;
+	}
 	if (temp > max_host_irqs)
 		dev_warn(dev, "Too many %s interrupts defined %u\n",
 			(legacy ? "legacy" : "MSI"), temp);
@@ -200,6 +205,9 @@
 		if (!host_irqs[temp])
 			break;
 	}
+
+	of_node_put(*np_temp);
+
 	if (temp) {
 		*num_irqs = temp;
 		ret = 0;
--- linux-4.4.0.orig/drivers/pci/host/pci-layerscape.c
+++ linux-4.4.0/drivers/pci/host/pci-layerscape.c
@@ -77,6 +77,16 @@
 	iowrite16(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE);
 }
 
+/* Drop MSG TLP except for Vendor MSG */
+static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
+{
+	u32 val;
+
+	val = ioread32(pcie->dbi + PCIE_STRFMR1);
+	val &= 0xDFFFFFFF;
+	iowrite32(val, pcie->dbi + PCIE_STRFMR1);
+}
+
 static int ls1021_pcie_link_up(struct pcie_port *pp)
 {
 	u32 state;
@@ -97,7 +107,7 @@
 static void ls1021_pcie_host_init(struct pcie_port *pp)
 {
 	struct ls_pcie *pcie = to_ls_pcie(pp);
-	u32 val, index[2];
+	u32 index[2];
 
 	pcie->scfg = syscon_regmap_lookup_by_phandle(pp->dev->of_node,
 						     "fsl,pcie-scfg");
@@ -116,13 +126,7 @@
 
 	dw_pcie_setup_rc(pp);
 
-	/*
-	 * LS1021A Workaround for internal TKT228622
-	 * to fix the INTx hang issue
-	 */
-	val = ioread32(pcie->dbi + PCIE_STRFMR1);
-	val &= 0xffff;
-	iowrite32(val, pcie->dbi + PCIE_STRFMR1);
+	ls_pcie_drop_msg_tlp(pcie);
 }
 
 static int ls_pcie_link_up(struct pcie_port *pp)
@@ -147,6 +151,7 @@
 	iowrite32(1, pcie->dbi + PCIE_DBI_RO_WR_EN);
 	ls_pcie_fix_class(pcie);
 	ls_pcie_clear_multifunction(pcie);
+	ls_pcie_drop_msg_tlp(pcie);
 	iowrite32(0, pcie->dbi + PCIE_DBI_RO_WR_EN);
 }
 
@@ -203,6 +208,7 @@
 	{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
 	{ .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
 	{ .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
+	{ .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
--- linux-4.4.0.orig/drivers/pci/host/pci-mvebu.c
+++ linux-4.4.0/drivers/pci/host/pci-mvebu.c
@@ -131,6 +131,12 @@
 	int nports;
 };
 
+struct mvebu_pcie_window {
+	phys_addr_t base;
+	phys_addr_t remap;
+	size_t size;
+};
+
 /* Structure representing one PCIe interface */
 struct mvebu_pcie_port {
 	char *name;
@@ -148,10 +154,8 @@
 	struct mvebu_sw_pci_bridge bridge;
 	struct device_node *dn;
 	struct mvebu_pcie *pcie;
-	phys_addr_t memwin_base;
-	size_t memwin_size;
-	phys_addr_t iowin_base;
-	size_t iowin_size;
+	struct mvebu_pcie_window memwin;
+	struct mvebu_pcie_window iowin;
 	u32 saved_pcie_stat;
 };
 
@@ -377,23 +381,45 @@
 	}
 }
 
+static void mvebu_pcie_set_window(struct mvebu_pcie_port *port,
+				  unsigned int target, unsigned int attribute,
+				  const struct mvebu_pcie_window *desired,
+				  struct mvebu_pcie_window *cur)
+{
+	if (desired->base == cur->base && desired->remap == cur->remap &&
+	    desired->size == cur->size)
+		return;
+
+	if (cur->size != 0) {
+		mvebu_pcie_del_windows(port, cur->base, cur->size);
+		cur->size = 0;
+		cur->base = 0;
+
+		/*
+		 * If something tries to change the window while it is enabled
+		 * the change will not be done atomically. That would be
+		 * difficult to do in the general case.
+		 */
+	}
+
+	if (desired->size == 0)
+		return;
+
+	mvebu_pcie_add_windows(port, target, attribute, desired->base,
+			       desired->size, desired->remap);
+	*cur = *desired;
+}
+
 static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
 {
-	phys_addr_t iobase;
+	struct mvebu_pcie_window desired = {};
 
 	/* Are the new iobase/iolimit values invalid? */
 	if (port->bridge.iolimit < port->bridge.iobase ||
 	    port->bridge.iolimitupper < port->bridge.iobaseupper ||
 	    !(port->bridge.command & PCI_COMMAND_IO)) {
-
-		/* If a window was configured, remove it */
-		if (port->iowin_base) {
-			mvebu_pcie_del_windows(port, port->iowin_base,
-					       port->iowin_size);
-			port->iowin_base = 0;
-			port->iowin_size = 0;
-		}
-
+		mvebu_pcie_set_window(port, port->io_target, port->io_attr,
+				      &desired, &port->iowin);
 		return;
 	}
 
@@ -410,32 +436,27 @@
 	 * specifications. iobase is the bus address, port->iowin_base
 	 * is the CPU address.
 	 */
-	iobase = ((port->bridge.iobase & 0xF0) << 8) |
-		(port->bridge.iobaseupper << 16);
-	port->iowin_base = port->pcie->io.start + iobase;
-	port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
-			    (port->bridge.iolimitupper << 16)) -
-			    iobase) + 1;
-
-	mvebu_pcie_add_windows(port, port->io_target, port->io_attr,
-			       port->iowin_base, port->iowin_size,
-			       iobase);
+	desired.remap = ((port->bridge.iobase & 0xF0) << 8) |
+			(port->bridge.iobaseupper << 16);
+	desired.base = port->pcie->io.start + desired.remap;
+	desired.size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
+			 (port->bridge.iolimitupper << 16)) -
+			desired.remap) +
+		       1;
+
+	mvebu_pcie_set_window(port, port->io_target, port->io_attr, &desired,
+			      &port->iowin);
 }
 
 static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
 {
+	struct mvebu_pcie_window desired = {.remap = MVEBU_MBUS_NO_REMAP};
+
 	/* Are the new membase/memlimit values invalid? */
 	if (port->bridge.memlimit < port->bridge.membase ||
 	    !(port->bridge.command & PCI_COMMAND_MEMORY)) {
-
-		/* If a window was configured, remove it */
-		if (port->memwin_base) {
-			mvebu_pcie_del_windows(port, port->memwin_base,
-					       port->memwin_size);
-			port->memwin_base = 0;
-			port->memwin_size = 0;
-		}
-
+		mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
+				      &desired, &port->memwin);
 		return;
 	}
 
@@ -445,14 +466,12 @@
 	 * window to setup, according to the PCI-to-PCI bridge
 	 * specifications.
 	 */
-	port->memwin_base  = ((port->bridge.membase & 0xFFF0) << 16);
-	port->memwin_size  =
-		(((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
-		port->memwin_base + 1;
-
-	mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr,
-			       port->memwin_base, port->memwin_size,
-			       MVEBU_MBUS_NO_REMAP);
+	desired.base = ((port->bridge.membase & 0xFFF0) << 16);
+	desired.size = (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
+		       desired.base + 1;
+
+	mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired,
+			      &port->memwin);
 }
 
 /*
@@ -1216,7 +1235,7 @@
 		pcie->realio.start = PCIBIOS_MIN_IO;
 		pcie->realio.end = min_t(resource_size_t,
 					 IO_SPACE_LIMIT,
-					 resource_size(&pcie->io));
+					 resource_size(&pcie->io) - 1);
 	} else
 		pcie->realio = pcie->io;
 
--- linux-4.4.0.orig/drivers/pci/host/pci-tegra.c
+++ linux-4.4.0/drivers/pci/host/pci-tegra.c
@@ -586,12 +586,15 @@
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class);
 
-/* Tegra PCIE requires relaxed ordering */
+/* Tegra20 and Tegra30 PCIE requires relaxed ordering */
 static void tegra_pcie_relax_enable(struct pci_dev *dev)
 {
 	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_relax_enable);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_relax_enable);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_relax_enable);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_relax_enable);
 
 static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
 {
@@ -1288,7 +1291,7 @@
 
 	msi->irq = err;
 
-	err = request_irq(msi->irq, tegra_pcie_msi_irq, 0,
+	err = request_irq(msi->irq, tegra_pcie_msi_irq, IRQF_NO_THREAD,
 			  tegra_msi_irq_chip.name, pcie);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
--- linux-4.4.0.orig/drivers/pci/host/pci-thunder-ecam.c
+++ linux-4.4.0/drivers/pci/host/pci-thunder-ecam.c
@@ -0,0 +1,379 @@
+/*
+ * 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) 2015, 2016 Cavium, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/of_pci.h>
+#include <linux/of.h>
+#include <linux/pci-ecam.h>
+#include <linux/platform_device.h>
+
+static void set_val(u32 v, int where, int size, u32 *val)
+{
+	int shift = (where & 3) * 8;
+
+	pr_debug("set_val %04x: %08x\n", (unsigned)(where & ~3), v);
+	v >>= shift;
+	if (size == 1)
+		v &= 0xff;
+	else if (size == 2)
+		v &= 0xffff;
+	*val = v;
+}
+
+static int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus,
+			 unsigned int devfn, int where, int size, u32 *val)
+{
+	void __iomem *addr;
+	u32 v;
+
+	/* Entries are 16-byte aligned; bits[2,3] select word in entry */
+	int where_a = where & 0xc;
+
+	if (where_a == 0) {
+		set_val(e0, where, size, val);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	if (where_a == 0x4) {
+		addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
+		if (!addr) {
+			*val = ~0;
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+		v = readl(addr);
+		v &= ~0xf;
+		v |= 2; /* EA entry-1. Base-L */
+		set_val(v, where, size, val);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	if (where_a == 0x8) {
+		u32 barl_orig;
+		u32 barl_rb;
+
+		addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
+		if (!addr) {
+			*val = ~0;
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+		barl_orig = readl(addr + 0);
+		writel(0xffffffff, addr + 0);
+		barl_rb = readl(addr + 0);
+		writel(barl_orig, addr + 0);
+		/* zeros in unsettable bits */
+		v = ~barl_rb & ~3;
+		v |= 0xc; /* EA entry-2. Offset-L */
+		set_val(v, where, size, val);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	if (where_a == 0xc) {
+		addr = bus->ops->map_bus(bus, devfn, bar + 4); /* BAR 1 */
+		if (!addr) {
+			*val = ~0;
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+		v = readl(addr); /* EA entry-3. Base-H */
+		set_val(v, where, size, val);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int thunder_ecam_p2_config_read(struct pci_bus *bus, unsigned int devfn,
+				       int where, int size, u32 *val)
+{
+	struct pci_config_window *cfg = bus->sysdata;
+	int where_a = where & ~3;
+	void __iomem *addr;
+	u32 node_bits;
+	u32 v;
+
+	/* EA Base[63:32] may be missing some bits ... */
+	switch (where_a) {
+	case 0xa8:
+	case 0xbc:
+	case 0xd0:
+	case 0xe4:
+		break;
+	default:
+		return pci_generic_config_read(bus, devfn, where, size, val);
+	}
+
+	addr = bus->ops->map_bus(bus, devfn, where_a);
+	if (!addr) {
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	v = readl(addr);
+
+	/*
+	 * Bit 44 of the 64-bit Base must match the same bit in
+	 * the config space access window.  Since we are working with
+	 * the high-order 32 bits, shift everything down by 32 bits.
+	 */
+	node_bits = (cfg->res.start >> 32) & (1 << 12);
+
+	v |= node_bits;
+	set_val(v, where, size, val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,
+				    int where, int size, u32 *val)
+{
+	u32 v;
+	u32 vendor_device;
+	u32 class_rev;
+	void __iomem *addr;
+	int cfg_type;
+	int where_a = where & ~3;
+
+	addr = bus->ops->map_bus(bus, devfn, 0xc);
+	if (!addr) {
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	v = readl(addr);
+
+	/* Check for non type-00 header */
+	cfg_type = (v >> 16) & 0x7f;
+
+	addr = bus->ops->map_bus(bus, devfn, 8);
+	if (!addr) {
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	class_rev = readl(addr);
+	if (class_rev == 0xffffffff)
+		goto no_emulation;
+
+	if ((class_rev & 0xff) >= 8) {
+		/* Pass-2 handling */
+		if (cfg_type)
+			goto no_emulation;
+		return thunder_ecam_p2_config_read(bus, devfn, where,
+						   size, val);
+	}
+
+	/*
+	 * All BARs have fixed addresses specified by the EA
+	 * capability; they must return zero on read.
+	 */
+	if (cfg_type == 0 &&
+	    ((where >= 0x10 && where < 0x2c) ||
+	     (where >= 0x1a4 && where < 0x1bc))) {
+		/* BAR or SR-IOV BAR */
+		*val = 0;
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	addr = bus->ops->map_bus(bus, devfn, 0);
+	if (!addr) {
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	vendor_device = readl(addr);
+	if (vendor_device == 0xffffffff)
+		goto no_emulation;
+
+	pr_debug("%04x:%04x - Fix pass#: %08x, where: %03x, devfn: %03x\n",
+		 vendor_device & 0xffff, vendor_device >> 16, class_rev,
+		 (unsigned) where, devfn);
+
+	/* Check for non type-00 header */
+	if (cfg_type == 0) {
+		bool has_msix;
+		bool is_nic = (vendor_device == 0xa01e177d);
+		bool is_tns = (vendor_device == 0xa01f177d);
+
+		addr = bus->ops->map_bus(bus, devfn, 0x70);
+		if (!addr) {
+			*val = ~0;
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+		/* E_CAP */
+		v = readl(addr);
+		has_msix = (v & 0xff00) != 0;
+
+		if (!has_msix && where_a == 0x70) {
+			v |= 0xbc00; /* next capability is EA at 0xbc */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xb0) {
+			addr = bus->ops->map_bus(bus, devfn, where_a);
+			if (!addr) {
+				*val = ~0;
+				return PCIBIOS_DEVICE_NOT_FOUND;
+			}
+			v = readl(addr);
+			if (v & 0xff00)
+				pr_err("Bad MSIX cap header: %08x\n", v);
+			v |= 0xbc00; /* next capability is EA at 0xbc */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xbc) {
+			if (is_nic)
+				v = 0x40014; /* EA last in chain, 4 entries */
+			else if (is_tns)
+				v = 0x30014; /* EA last in chain, 3 entries */
+			else if (has_msix)
+				v = 0x20014; /* EA last in chain, 2 entries */
+			else
+				v = 0x10014; /* EA last in chain, 1 entry */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a >= 0xc0 && where_a < 0xd0)
+			/* EA entry-0. PP=0, BAR0 Size:3 */
+			return handle_ea_bar(0x80ff0003,
+					     0x10, bus, devfn, where,
+					     size, val);
+		if (where_a >= 0xd0 && where_a < 0xe0 && has_msix)
+			 /* EA entry-1. PP=0, BAR4 Size:3 */
+			return handle_ea_bar(0x80ff0043,
+					     0x20, bus, devfn, where,
+					     size, val);
+		if (where_a >= 0xe0 && where_a < 0xf0 && is_tns)
+			/* EA entry-2. PP=0, BAR2, Size:3 */
+			return handle_ea_bar(0x80ff0023,
+					     0x18, bus, devfn, where,
+					     size, val);
+		if (where_a >= 0xe0 && where_a < 0xf0 && is_nic)
+			/* EA entry-2. PP=4, VF_BAR0 (9), Size:3 */
+			return handle_ea_bar(0x80ff0493,
+					     0x1a4, bus, devfn, where,
+					     size, val);
+		if (where_a >= 0xf0 && where_a < 0x100 && is_nic)
+			/* EA entry-3. PP=4, VF_BAR4 (d), Size:3 */
+			return handle_ea_bar(0x80ff04d3,
+					     0x1b4, bus, devfn, where,
+					     size, val);
+	} else if (cfg_type == 1) {
+		bool is_rsl_bridge = devfn == 0x08;
+		bool is_rad_bridge = devfn == 0xa0;
+		bool is_zip_bridge = devfn == 0xa8;
+		bool is_dfa_bridge = devfn == 0xb0;
+		bool is_nic_bridge = devfn == 0x10;
+
+		if (where_a == 0x70) {
+			addr = bus->ops->map_bus(bus, devfn, where_a);
+			if (!addr) {
+				*val = ~0;
+				return PCIBIOS_DEVICE_NOT_FOUND;
+			}
+			v = readl(addr);
+			if (v & 0xff00)
+				pr_err("Bad PCIe cap header: %08x\n", v);
+			v |= 0xbc00; /* next capability is EA at 0xbc */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xbc) {
+			if (is_nic_bridge)
+				v = 0x10014; /* EA last in chain, 1 entry */
+			else
+				v = 0x00014; /* EA last in chain, no entries */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xc0) {
+			if (is_rsl_bridge || is_nic_bridge)
+				v = 0x0101; /* subordinate:secondary = 1:1 */
+			else if (is_rad_bridge)
+				v = 0x0202; /* subordinate:secondary = 2:2 */
+			else if (is_zip_bridge)
+				v = 0x0303; /* subordinate:secondary = 3:3 */
+			else if (is_dfa_bridge)
+				v = 0x0404; /* subordinate:secondary = 4:4 */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xc4 && is_nic_bridge) {
+			/* Enabled, not-Write, SP=ff, PP=05, BEI=6, ES=4 */
+			v = 0x80ff0564;
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xc8 && is_nic_bridge) {
+			v = 0x00000002; /* Base-L 64-bit */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xcc && is_nic_bridge) {
+			v = 0xfffffffe; /* MaxOffset-L 64-bit */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xd0 && is_nic_bridge) {
+			v = 0x00008430; /* NIC Base-H */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		if (where_a == 0xd4 && is_nic_bridge) {
+			v = 0x0000000f; /* MaxOffset-H */
+			set_val(v, where, size, val);
+			return PCIBIOS_SUCCESSFUL;
+		}
+	}
+no_emulation:
+	return pci_generic_config_read(bus, devfn, where, size, val);
+}
+
+static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
+				     int where, int size, u32 val)
+{
+	/*
+	 * All BARs have fixed addresses; ignore BAR writes so they
+	 * don't get corrupted.
+	 */
+	if ((where >= 0x10 && where < 0x2c) ||
+	    (where >= 0x1a4 && where < 0x1bc))
+		/* BAR or SR-IOV BAR */
+		return PCIBIOS_SUCCESSFUL;
+
+	return pci_generic_config_write(bus, devfn, where, size, val);
+}
+
+static struct pci_ecam_ops pci_thunder_ecam_ops = {
+	.bus_shift	= 20,
+	.pci_ops	= {
+		.map_bus        = pci_ecam_map_bus,
+		.read           = thunder_ecam_config_read,
+		.write          = thunder_ecam_config_write,
+	}
+};
+
+static const struct of_device_id thunder_ecam_of_match[] = {
+	{ .compatible = "cavium,pci-host-thunder-ecam" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, thunder_ecam_of_match);
+
+static int thunder_ecam_probe(struct platform_device *pdev)
+{
+	return pci_host_common_probe(pdev, &pci_thunder_ecam_ops);
+}
+
+static struct platform_driver thunder_ecam_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.of_match_table = thunder_ecam_of_match,
+	},
+	.probe = thunder_ecam_probe,
+};
+module_platform_driver(thunder_ecam_driver);
+
+MODULE_DESCRIPTION("Thunder ECAM PCI host driver");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/pci/host/pci-thunder-pem.c
+++ linux-4.4.0/drivers/pci/host/pci-thunder-pem.c
@@ -0,0 +1,340 @@
+/*
+ * This program is free software; you can 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/>.
+ *
+ * Copyright (C) 2015 - 2016 Cavium, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
+#include <linux/platform_device.h>
+
+#define PEM_CFG_WR 0x28
+#define PEM_CFG_RD 0x30
+
+struct thunder_pem_pci {
+	u32		ea_entry[3];
+	void __iomem	*pem_reg_base;
+};
+
+static int thunder_pem_bridge_read(struct pci_bus *bus, unsigned int devfn,
+				   int where, int size, u32 *val)
+{
+	u64 read_val;
+	struct pci_config_window *cfg = bus->sysdata;
+	struct thunder_pem_pci *pem_pci = (struct thunder_pem_pci *)cfg->priv;
+
+	if (devfn != 0 || where >= 2048) {
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	/*
+	 * 32-bit accesses only.  Write the address to the low order
+	 * bits of PEM_CFG_RD, then trigger the read by reading back.
+	 * The config data lands in the upper 32-bits of PEM_CFG_RD.
+	 */
+	read_val = where & ~3ull;
+	writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+	read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
+	read_val >>= 32;
+
+	/*
+	 * The config space contains some garbage, fix it up.  Also
+	 * synthesize an EA capability for the BAR used by MSI-X.
+	 */
+	switch (where & ~3) {
+	case 0x40:
+		read_val &= 0xffff00ff;
+		read_val |= 0x00007000; /* Skip MSI CAP */
+		break;
+	case 0x70: /* Express Cap */
+		/* PME interrupt on vector 2*/
+		read_val |= (2u << 25);
+		break;
+	case 0xb0: /* MSI-X Cap */
+		/* TableSize=4, Next Cap is EA */
+		read_val &= 0xc00000ff;
+		read_val |= 0x0003bc00;
+		break;
+	case 0xb4:
+		/* Table offset=0, BIR=0 */
+		read_val = 0x00000000;
+		break;
+	case 0xb8:
+		/* BPA offset=0xf0000, BIR=0 */
+		read_val = 0x000f0000;
+		break;
+	case 0xbc:
+		/* EA, 1 entry, no next Cap */
+		read_val = 0x00010014;
+		break;
+	case 0xc0:
+		/* DW2 for type-1 */
+		read_val = 0x00000000;
+		break;
+	case 0xc4:
+		/* Entry BEI=0, PP=0x00, SP=0xff, ES=3 */
+		read_val = 0x80ff0003;
+		break;
+	case 0xc8:
+		read_val = pem_pci->ea_entry[0];
+		break;
+	case 0xcc:
+		read_val = pem_pci->ea_entry[1];
+		break;
+	case 0xd0:
+		read_val = pem_pci->ea_entry[2];
+		break;
+	default:
+		break;
+	}
+	read_val >>= (8 * (where & 3));
+	switch (size) {
+	case 1:
+		read_val &= 0xff;
+		break;
+	case 2:
+		read_val &= 0xffff;
+		break;
+	default:
+		break;
+	}
+	*val = read_val;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int thunder_pem_config_read(struct pci_bus *bus, unsigned int devfn,
+				   int where, int size, u32 *val)
+{
+	struct pci_config_window *cfg = bus->sysdata;
+
+	if (bus->number < cfg->busr.start ||
+	    bus->number > cfg->busr.end)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/*
+	 * The first device on the bus is the PEM PCIe bridge.
+	 * Special case its config access.
+	 */
+	if (bus->number == cfg->busr.start)
+		return thunder_pem_bridge_read(bus, devfn, where, size, val);
+
+	return pci_generic_config_read(bus, devfn, where, size, val);
+}
+
+/*
+ * Some of the w1c_bits below also include read-only or non-writable
+ * reserved bits, this makes the code simpler and is OK as the bits
+ * are not affected by writing zeros to them.
+ */
+static u32 thunder_pem_bridge_w1c_bits(int where)
+{
+	u32 w1c_bits = 0;
+
+	switch (where & ~3) {
+	case 0x04: /* Command/Status */
+	case 0x1c: /* Base and I/O Limit/Secondary Status */
+		w1c_bits = 0xff000000;
+		break;
+	case 0x44: /* Power Management Control and Status */
+		w1c_bits = 0xfffffe00;
+		break;
+	case 0x78: /* Device Control/Device Status */
+	case 0x80: /* Link Control/Link Status */
+	case 0x88: /* Slot Control/Slot Status */
+	case 0x90: /* Root Status */
+	case 0xa0: /* Link Control 2 Registers/Link Status 2 */
+		w1c_bits = 0xffff0000;
+		break;
+	case 0x104: /* Uncorrectable Error Status */
+	case 0x110: /* Correctable Error Status */
+	case 0x130: /* Error Status */
+	case 0x160: /* Link Control 4 */
+		w1c_bits = 0xffffffff;
+		break;
+	default:
+		break;
+	}
+	return w1c_bits;
+}
+
+static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
+				    int where, int size, u32 val)
+{
+	struct pci_config_window *cfg = bus->sysdata;
+	struct thunder_pem_pci *pem_pci = (struct thunder_pem_pci *)cfg->priv;
+	u64 write_val, read_val;
+	u32 mask = 0;
+
+
+	if (devfn != 0 || where >= 2048)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/*
+	 * 32-bit accesses only.  If the write is for a size smaller
+	 * than 32-bits, we must first read the 32-bit value and merge
+	 * in the desired bits and then write the whole 32-bits back
+	 * out.
+	 */
+	switch (size) {
+	case 1:
+		read_val = where & ~3ull;
+		writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+		read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
+		read_val >>= 32;
+		mask = ~(0xff << (8 * (where & 3)));
+		read_val &= mask;
+		val = (val & 0xff) << (8 * (where & 3));
+		val |= (u32)read_val;
+		break;
+	case 2:
+		read_val = where & ~3ull;
+		writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+		read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
+		read_val >>= 32;
+		mask = ~(0xffff << (8 * (where & 3)));
+		read_val &= mask;
+		val = (val & 0xffff) << (8 * (where & 3));
+		val |= (u32)read_val;
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * By expanding the write width to 32 bits, we may
+	 * inadvertently hit some W1C bits that were not intended to
+	 * be written.  Calculate the mask that must be applied to the
+	 * data to be written to avoid these cases.
+	 */
+	if (mask) {
+		u32 w1c_bits = thunder_pem_bridge_w1c_bits(where);
+
+		if (w1c_bits) {
+			mask &= w1c_bits;
+			val &= ~mask;
+		}
+	}
+
+	/*
+	 * Low order bits are the config address, the high order 32
+	 * bits are the data to be written.
+	 */
+	write_val = where & ~3ull;
+	write_val |= (((u64)val) << 32);
+	writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
+				    int where, int size, u32 val)
+{
+	struct pci_config_window *cfg = bus->sysdata;
+
+	if (bus->number < cfg->busr.start ||
+	    bus->number > cfg->busr.end)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	/*
+	 * The first device on the bus is the PEM PCIe bridge.
+	 * Special case its config access.
+	 */
+	if (bus->number == cfg->busr.start)
+		return thunder_pem_bridge_write(bus, devfn, where, size, val);
+
+
+	return pci_generic_config_write(bus, devfn, where, size, val);
+}
+
+static int thunder_pem_init(struct pci_config_window *cfg)
+{
+	struct device *dev = cfg->parent;
+	resource_size_t bar4_start;
+	struct resource *res_pem;
+	struct thunder_pem_pci *pem_pci;
+	struct platform_device *pdev;
+
+	/* Only OF support for now */
+	if (!dev->of_node)
+		return -EINVAL;
+
+	pem_pci = devm_kzalloc(dev, sizeof(*pem_pci), GFP_KERNEL);
+	if (!pem_pci)
+		return -ENOMEM;
+
+	pdev = to_platform_device(dev);
+
+	/*
+	 * The second register range is the PEM bridge to the PCIe
+	 * bus.  It has a different config access method than those
+	 * devices behind the bridge.
+	 */
+	res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res_pem) {
+		dev_err(dev, "missing \"reg[1]\"property\n");
+		return -EINVAL;
+	}
+
+	pem_pci->pem_reg_base = devm_ioremap(dev, res_pem->start, 0x10000);
+	if (!pem_pci->pem_reg_base)
+		return -ENOMEM;
+
+	/*
+	 * The MSI-X BAR for the PEM and AER interrupts is located at
+	 * a fixed offset from the PEM register base.  Generate a
+	 * fragment of the synthesized Enhanced Allocation capability
+	 * structure here for the BAR.
+	 */
+	bar4_start = res_pem->start + 0xf00000;
+	pem_pci->ea_entry[0] = (u32)bar4_start | 2;
+	pem_pci->ea_entry[1] = (u32)(res_pem->end - bar4_start) & ~3u;
+	pem_pci->ea_entry[2] = (u32)(bar4_start >> 32);
+
+	cfg->priv = pem_pci;
+	return 0;
+}
+
+static struct pci_ecam_ops pci_thunder_pem_ops = {
+	.bus_shift	= 24,
+	.init		= thunder_pem_init,
+	.pci_ops	= {
+		.map_bus	= pci_ecam_map_bus,
+		.read		= thunder_pem_config_read,
+		.write		= thunder_pem_config_write,
+	}
+};
+
+static const struct of_device_id thunder_pem_of_match[] = {
+	{ .compatible = "cavium,pci-host-thunder-pem" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, thunder_pem_of_match);
+
+static int thunder_pem_probe(struct platform_device *pdev)
+{
+	return pci_host_common_probe(pdev, &pci_thunder_pem_ops);
+}
+
+static struct platform_driver thunder_pem_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.of_match_table = thunder_pem_of_match,
+	},
+	.probe = thunder_pem_probe,
+};
+module_platform_driver(thunder_pem_driver);
+
+MODULE_DESCRIPTION("Thunder PEM PCIe host driver");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/pci/host/pci-xgene-msi.c
+++ linux-4.4.0/drivers/pci/host/pci-xgene-msi.c
@@ -393,13 +393,9 @@
 		if (!msi_group->gic_irq)
 			continue;
 
-		irq_set_chained_handler(msi_group->gic_irq,
-					xgene_msi_isr);
-		err = irq_set_handler_data(msi_group->gic_irq, msi_group);
-		if (err) {
-			pr_err("failed to register GIC IRQ handler\n");
-			return -EINVAL;
-		}
+		irq_set_chained_handler_and_data(msi_group->gic_irq,
+			xgene_msi_isr, msi_group);
+
 		/*
 		 * Statically allocate MSI GIC IRQs to each CPU core.
 		 * With 8-core X-Gene v1, 2 MSI GIC IRQs are allocated
--- linux-4.4.0.orig/drivers/pci/host/pcie-altera.c
+++ linux-4.4.0/drivers/pci/host/pcie-altera.c
@@ -40,8 +40,10 @@
 #define P2A_INT_ENABLE			0x3070
 #define P2A_INT_ENA_ALL			0xf
 #define RP_LTSSM			0x3c64
+#define RP_LTSSM_MASK			0x1f
 #define LTSSM_L0			0xf
 
+#define PCIE_CAP_OFFSET			0x80
 /* TLP configuration type 0 and 1 */
 #define TLP_FMTTYPE_CFGRD0		0x04	/* Configuration Read Type 0 */
 #define TLP_FMTTYPE_CFGWR0		0x44	/* Configuration Write Type 0 */
@@ -60,6 +62,9 @@
 #define TLP_LOOP			500
 #define RP_DEVFN			0
 
+#define LINK_UP_TIMEOUT			HZ
+#define LINK_RETRAIN_TIMEOUT		HZ
+
 #define INTX_NUM			4
 
 #define DWORD_MASK			3
@@ -80,25 +85,21 @@
 	u32 reg1;
 };
 
-static void altera_pcie_retrain(struct pci_dev *dev)
+static inline void cra_writel(struct altera_pcie *pcie, const u32 value,
+			      const u32 reg)
 {
-	u16 linkcap, linkstat;
-
-	/*
-	 * Set the retrain bit if the PCIe rootport support > 2.5GB/s, but
-	 * current speed is 2.5 GB/s.
-	 */
-	pcie_capability_read_word(dev, PCI_EXP_LNKCAP, &linkcap);
+	writel_relaxed(value, pcie->cra_base + reg);
+}
 
-	if ((linkcap & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
-		return;
+static inline u32 cra_readl(struct altera_pcie *pcie, const u32 reg)
+{
+	return readl_relaxed(pcie->cra_base + reg);
+}
 
-	pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &linkstat);
-	if ((linkstat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB)
-		pcie_capability_set_word(dev, PCI_EXP_LNKCTL,
-					 PCI_EXP_LNKCTL_RL);
+static bool altera_pcie_link_is_up(struct altera_pcie *pcie)
+{
+	return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0);
 }
-DECLARE_PCI_FIXUP_EARLY(0x1172, PCI_ANY_ID, altera_pcie_retrain);
 
 /*
  * Altera PCIe port uses BAR0 of RC's configuration space as the translation
@@ -119,17 +120,6 @@
 	return false;
 }
 
-static inline void cra_writel(struct altera_pcie *pcie, const u32 value,
-			      const u32 reg)
-{
-	writel_relaxed(value, pcie->cra_base + reg);
-}
-
-static inline u32 cra_readl(struct altera_pcie *pcie, const u32 reg)
-{
-	return readl_relaxed(pcie->cra_base + reg);
-}
-
 static void tlp_write_tx(struct altera_pcie *pcie,
 			 struct tlp_rp_regpair_t *tlp_rp_regdata)
 {
@@ -138,11 +128,6 @@
 	cra_writel(pcie, tlp_rp_regdata->ctrl, RP_TX_CNTRL);
 }
 
-static bool altera_pcie_link_is_up(struct altera_pcie *pcie)
-{
-	return !!(cra_readl(pcie, RP_LTSSM) & LTSSM_L0);
-}
-
 static bool altera_pcie_valid_config(struct altera_pcie *pcie,
 				     struct pci_bus *bus, int dev)
 {
@@ -286,22 +271,14 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn,
-				int where, int size, u32 *value)
+static int _altera_pcie_cfg_read(struct altera_pcie *pcie, u8 busno,
+				 unsigned int devfn, int where, int size,
+				 u32 *value)
 {
-	struct altera_pcie *pcie = bus->sysdata;
 	int ret;
 	u32 data;
 	u8 byte_en;
 
-	if (altera_pcie_hide_rc_bar(bus, devfn, where))
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-
-	if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn))) {
-		*value = 0xffffffff;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	}
-
 	switch (size) {
 	case 1:
 		byte_en = 1 << (where & 3);
@@ -314,7 +291,7 @@
 		break;
 	}
 
-	ret = tlp_cfg_dword_read(pcie, bus->number, devfn,
+	ret = tlp_cfg_dword_read(pcie, busno, devfn,
 				 (where & ~DWORD_MASK), byte_en, &data);
 	if (ret != PCIBIOS_SUCCESSFUL)
 		return ret;
@@ -334,20 +311,14 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static int altera_pcie_cfg_write(struct pci_bus *bus, unsigned int devfn,
-				 int where, int size, u32 value)
+static int _altera_pcie_cfg_write(struct altera_pcie *pcie, u8 busno,
+				  unsigned int devfn, int where, int size,
+				  u32 value)
 {
-	struct altera_pcie *pcie = bus->sysdata;
 	u32 data32;
 	u32 shift = 8 * (where & 3);
 	u8 byte_en;
 
-	if (altera_pcie_hide_rc_bar(bus, devfn, where))
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-
-	if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn)))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
 	switch (size) {
 	case 1:
 		data32 = (value & 0xff) << shift;
@@ -363,8 +334,40 @@
 		break;
 	}
 
-	return tlp_cfg_dword_write(pcie, bus->number, devfn,
-		(where & ~DWORD_MASK), byte_en, data32);
+	return tlp_cfg_dword_write(pcie, busno, devfn, (where & ~DWORD_MASK),
+				   byte_en, data32);
+}
+
+static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn,
+				int where, int size, u32 *value)
+{
+	struct altera_pcie *pcie = bus->sysdata;
+
+	if (altera_pcie_hide_rc_bar(bus, devfn, where))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn))) {
+		*value = 0xffffffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	return _altera_pcie_cfg_read(pcie, bus->number, devfn, where, size,
+				     value);
+}
+
+static int altera_pcie_cfg_write(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 value)
+{
+	struct altera_pcie *pcie = bus->sysdata;
+
+	if (altera_pcie_hide_rc_bar(bus, devfn, where))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return _altera_pcie_cfg_write(pcie, bus->number, devfn, where, size,
+				     value);
 }
 
 static struct pci_ops altera_pcie_ops = {
@@ -372,6 +375,90 @@
 	.write = altera_pcie_cfg_write,
 };
 
+static int altera_read_cap_word(struct altera_pcie *pcie, u8 busno,
+				unsigned int devfn, int offset, u16 *value)
+{
+	u32 data;
+	int ret;
+
+	ret = _altera_pcie_cfg_read(pcie, busno, devfn,
+				    PCIE_CAP_OFFSET + offset, sizeof(*value),
+				    &data);
+	*value = data;
+	return ret;
+}
+
+static int altera_write_cap_word(struct altera_pcie *pcie, u8 busno,
+				 unsigned int devfn, int offset, u16 value)
+{
+	return _altera_pcie_cfg_write(pcie, busno, devfn,
+				      PCIE_CAP_OFFSET + offset, sizeof(value),
+				      value);
+}
+
+static void altera_wait_link_retrain(struct altera_pcie *pcie)
+{
+	u16 reg16;
+	unsigned long start_jiffies;
+
+	/* Wait for link training end. */
+	start_jiffies = jiffies;
+	for (;;) {
+		altera_read_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN,
+				     PCI_EXP_LNKSTA, &reg16);
+		if (!(reg16 & PCI_EXP_LNKSTA_LT))
+			break;
+
+		if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) {
+			dev_err(&pcie->pdev->dev, "link retrain timeout\n");
+			break;
+		}
+		udelay(100);
+	}
+
+	/* Wait for link is up */
+	start_jiffies = jiffies;
+	for (;;) {
+		if (altera_pcie_link_is_up(pcie))
+			break;
+
+		if (time_after(jiffies, start_jiffies + LINK_UP_TIMEOUT)) {
+			dev_err(&pcie->pdev->dev, "link up timeout\n");
+			break;
+		}
+		udelay(100);
+	}
+}
+
+static void altera_pcie_retrain(struct altera_pcie *pcie)
+{
+	u16 linkcap, linkstat, linkctl;
+
+	if (!altera_pcie_link_is_up(pcie))
+		return;
+
+	/*
+	 * Set the retrain bit if the PCIe rootport support > 2.5GB/s, but
+	 * current speed is 2.5 GB/s.
+	 */
+	altera_read_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN, PCI_EXP_LNKCAP,
+			     &linkcap);
+	if ((linkcap & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+		return;
+
+	altera_read_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN, PCI_EXP_LNKSTA,
+			     &linkstat);
+	if ((linkstat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+		altera_read_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN,
+				     PCI_EXP_LNKCTL, &linkctl);
+		linkctl |= PCI_EXP_LNKCTL_RL;
+		altera_write_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN,
+				      PCI_EXP_LNKCTL, linkctl);
+
+		altera_wait_link_retrain(pcie);
+	}
+}
+
 static int altera_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 				irq_hw_number_t hwirq)
 {
@@ -506,6 +593,11 @@
 	return 0;
 }
 
+static void altera_pcie_host_init(struct altera_pcie *pcie)
+{
+	altera_pcie_retrain(pcie);
+}
+
 static int altera_pcie_probe(struct platform_device *pdev)
 {
 	struct altera_pcie *pcie;
@@ -543,6 +635,7 @@
 	cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
 	/* enable all interrupts */
 	cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE);
+	altera_pcie_host_init(pcie);
 
 	bus = pci_scan_root_bus(&pdev->dev, pcie->root_bus_nr, &altera_pcie_ops,
 				pcie, &pcie->resources);
--- linux-4.4.0.orig/drivers/pci/host/pcie-rcar.c
+++ linux-4.4.0/drivers/pci/host/pcie-rcar.c
@@ -720,14 +720,16 @@
 
 	/* Two irqs are for MSI, but they are also used for non-MSI irqs */
 	err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq,
-			       IRQF_SHARED, rcar_msi_irq_chip.name, pcie);
+			       IRQF_SHARED | IRQF_NO_THREAD,
+			       rcar_msi_irq_chip.name, pcie);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
 		goto err;
 	}
 
 	err = devm_request_irq(&pdev->dev, msi->irq2, rcar_pcie_msi_irq,
-			       IRQF_SHARED, rcar_msi_irq_chip.name, pcie);
+			       IRQF_SHARED | IRQF_NO_THREAD,
+			       rcar_msi_irq_chip.name, pcie);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
 		goto err;
@@ -735,6 +737,10 @@
 
 	/* setup MSI data target */
 	msi->pages = __get_free_pages(GFP_KERNEL, 0);
+	if (!msi->pages) {
+		err = -ENOMEM;
+		goto err;
+	}
 	base = virt_to_phys((void *)msi->pages);
 
 	rcar_pci_write_reg(pcie, base | MSIFE, PCIEMSIALR);
--- linux-4.4.0.orig/drivers/pci/host/pcie-spear13xx.c
+++ linux-4.4.0/drivers/pci/host/pcie-spear13xx.c
@@ -279,7 +279,8 @@
 		return -ENODEV;
 	}
 	ret = devm_request_irq(dev, pp->irq, spear13xx_pcie_irq_handler,
-			       IRQF_SHARED, "spear1340-pcie", pp);
+			       IRQF_SHARED | IRQF_NO_THREAD,
+			       "spear1340-pcie", pp);
 	if (ret) {
 		dev_err(dev, "failed to request irq %d\n", pp->irq);
 		return ret;
--- linux-4.4.0.orig/drivers/pci/host/pcie-xilinx.c
+++ linux-4.4.0/drivers/pci/host/pcie-xilinx.c
@@ -349,14 +349,19 @@
  * xilinx_pcie_enable_msi - Enable MSI support
  * @port: PCIe port information
  */
-static void xilinx_pcie_enable_msi(struct xilinx_pcie_port *port)
+static int xilinx_pcie_enable_msi(struct xilinx_pcie_port *port)
 {
 	phys_addr_t msg_addr;
 
 	port->msi_pages = __get_free_pages(GFP_KERNEL, 0);
+	if (!port->msi_pages)
+		return -ENOMEM;
+
 	msg_addr = virt_to_phys((void *)port->msi_pages);
 	pcie_write(port, 0x0, XILINX_PCIE_REG_MSIBASE1);
 	pcie_write(port, msg_addr, XILINX_PCIE_REG_MSIBASE2);
+
+	return 0;
 }
 
 /* INTx Functions */
@@ -555,6 +560,7 @@
 	struct device *dev = port->dev;
 	struct device_node *node = dev->of_node;
 	struct device_node *pcie_intc_node;
+	int ret;
 
 	/* Setup INTx */
 	pcie_intc_node = of_get_next_child(node, NULL);
@@ -582,7 +588,9 @@
 			return PTR_ERR(port->irq_domain);
 		}
 
-		xilinx_pcie_enable_msi(port);
+		ret = xilinx_pcie_enable_msi(port);
+		if (ret)
+			return ret;
 	}
 
 	return 0;
@@ -781,7 +789,8 @@
 
 	port->irq = irq_of_parse_and_map(node, 0);
 	err = devm_request_irq(dev, port->irq, xilinx_pcie_intr_handler,
-			       IRQF_SHARED, "xilinx-pcie", port);
+			       IRQF_SHARED | IRQF_NO_THREAD,
+			       "xilinx-pcie", port);
 	if (err) {
 		dev_err(dev, "unable to request irq %d\n", port->irq);
 		return err;
--- linux-4.4.0.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-4.4.0/drivers/pci/hotplug/acpiphp_glue.c
@@ -136,13 +136,21 @@
 	struct acpiphp_context *context;
 
 	acpi_lock_hp_context();
+
 	context = acpiphp_get_context(adev);
-	if (!context || context->func.parent->is_going_away) {
-		acpi_unlock_hp_context();
-		return NULL;
+	if (!context)
+		goto unlock;
+
+	if (context->func.parent->is_going_away) {
+		acpiphp_put_context(context);
+		context = NULL;
+		goto unlock;
 	}
+
 	get_bridge(context->func.parent);
 	acpiphp_put_context(context);
+
+unlock:
 	acpi_unlock_hp_context();
 	return context;
 }
@@ -587,6 +595,7 @@
 {
 	unsigned long long sta = 0;
 	struct acpiphp_func *func;
+	u32 dvid;
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_STA) {
@@ -597,19 +606,27 @@
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
-			u32 dvid;
-
-			pci_bus_read_config_dword(slot->bus,
-						  PCI_DEVFN(slot->device,
-							    func->function),
-						  PCI_VENDOR_ID, &dvid);
-			if (dvid != 0xffffffff) {
+			if (pci_bus_read_dev_vendor_id(slot->bus,
+					PCI_DEVFN(slot->device, func->function),
+					&dvid, 0)) {
 				sta = ACPI_STA_ALL;
 				break;
 			}
 		}
 	}
 
+	if (!sta) {
+		/*
+		 * Check for the slot itself since it may be that the
+		 * ACPI slot is a device below PCIe upstream port so in
+		 * that case it may not even be reachable yet.
+		 */
+		if (pci_bus_read_dev_vendor_id(slot->bus,
+				PCI_DEVFN(slot->device, 0), &dvid, 0)) {
+			sta = ACPI_STA_ALL;
+		}
+	}
+
 	return (unsigned int)sta;
 }
 
@@ -953,8 +970,10 @@
 {
 	pci_lock_rescan_remove();
 
-	if (slot->flags & SLOT_IS_GOING_AWAY)
+	if (slot->flags & SLOT_IS_GOING_AWAY) {
+		pci_unlock_rescan_remove();
 		return -ENODEV;
+	}
 
 	/* configure all functions */
 	if (!(slot->flags & SLOT_ENABLED))
--- linux-4.4.0.orig/drivers/pci/hotplug/cpcihp_generic.c
+++ linux-4.4.0/drivers/pci/hotplug/cpcihp_generic.c
@@ -220,7 +220,7 @@
 MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number");
 module_param(last_slot, byte, 0);
 MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number");
-module_param(port, ushort, 0);
+module_param_hw(port, ushort, ioport, 0);
 MODULE_PARM_DESC(port, "#ENUM signal I/O port");
 module_param(enum_bit, uint, 0);
 MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)");
--- linux-4.4.0.orig/drivers/pci/hotplug/pci_hotplug_core.c
+++ linux-4.4.0/drivers/pci/hotplug/pci_hotplug_core.c
@@ -457,8 +457,17 @@
 	list_add(&slot->slot_list, &pci_hotplug_slot_list);
 
 	result = fs_add_slot(pci_slot);
+	if (result)
+		goto err_list_del;
+
 	kobject_uevent(&pci_slot->kobj, KOBJ_ADD);
 	dbg("Added slot %s to the list\n", name);
+	goto out;
+
+err_list_del:
+	list_del(&slot->slot_list);
+	pci_slot->hotplug = NULL;
+	pci_destroy_slot(pci_slot);
 out:
 	mutex_unlock(&pci_hp_mutex);
 	return result;
--- linux-4.4.0.orig/drivers/pci/hotplug/pciehp.h
+++ linux-4.4.0/drivers/pci/hotplug/pciehp.h
@@ -132,9 +132,10 @@
 void pciehp_queue_pushbutton_work(struct work_struct *work);
 struct controller *pcie_init(struct pcie_device *dev);
 int pcie_init_notification(struct controller *ctrl);
+void pcie_shutdown_notification(struct controller *ctrl);
 int pciehp_enable_slot(struct slot *p_slot);
 int pciehp_disable_slot(struct slot *p_slot);
-void pcie_enable_notification(struct controller *ctrl);
+void pcie_reenable_notification(struct controller *ctrl);
 int pciehp_power_on_slot(struct slot *slot);
 void pciehp_power_off_slot(struct slot *slot);
 void pciehp_get_power_status(struct slot *slot, u8 *status);
--- linux-4.4.0.orig/drivers/pci/hotplug/pciehp_core.c
+++ linux-4.4.0/drivers/pci/hotplug/pciehp_core.c
@@ -77,6 +77,12 @@
  */
 static void release_slot(struct hotplug_slot *hotplug_slot)
 {
+	struct slot *slot = hotplug_slot->private;
+
+	/* queued work needs hotplug_slot name */
+	cancel_delayed_work(&slot->work);
+	drain_workqueue(slot->wq);
+
 	kfree(hotplug_slot->ops);
 	kfree(hotplug_slot->info);
 	kfree(hotplug_slot);
@@ -276,6 +282,7 @@
 {
 	struct controller *ctrl = get_service_data(dev);
 
+	pcie_shutdown_notification(ctrl);
 	cleanup_slot(ctrl);
 	pciehp_release_ctrl(ctrl);
 }
@@ -295,7 +302,7 @@
 	ctrl = get_service_data(dev);
 
 	/* reinitialize the chipset's event detection logic */
-	pcie_enable_notification(ctrl);
+	pcie_reenable_notification(ctrl);
 
 	slot = ctrl->slot;
 
--- linux-4.4.0.orig/drivers/pci/hotplug/pciehp_hpc.c
+++ linux-4.4.0/drivers/pci/hotplug/pciehp_hpc.c
@@ -628,7 +628,7 @@
 	return IRQ_HANDLED;
 }
 
-void pcie_enable_notification(struct controller *ctrl)
+static void pcie_enable_notification(struct controller *ctrl)
 {
 	u16 cmd, mask;
 
@@ -666,6 +666,17 @@
 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
 }
 
+void pcie_reenable_notification(struct controller *ctrl)
+{
+	/*
+	 * Clear both Presence and Data Link Layer Changed to make sure
+	 * those events still fire after we have re-enabled them.
+	 */
+	pcie_capability_write_word(ctrl->pcie->port, PCI_EXP_SLTSTA,
+				   PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
+	pcie_enable_notification(ctrl);
+}
+
 static void pcie_disable_notification(struct controller *ctrl)
 {
 	u16 mask;
@@ -730,7 +741,7 @@
 	return 0;
 }
 
-static void pcie_shutdown_notification(struct controller *ctrl)
+void pcie_shutdown_notification(struct controller *ctrl)
 {
 	if (ctrl->notification_enabled) {
 		pcie_disable_notification(ctrl);
@@ -765,7 +776,7 @@
 static void pcie_cleanup_slot(struct controller *ctrl)
 {
 	struct slot *slot = ctrl->slot;
-	cancel_delayed_work(&slot->work);
+
 	destroy_workqueue(slot->wq);
 	kfree(slot);
 }
@@ -842,7 +853,6 @@
 
 void pciehp_release_ctrl(struct controller *ctrl)
 {
-	pcie_shutdown_notification(ctrl);
 	pcie_cleanup_slot(ctrl);
 	kfree(ctrl);
 }
--- linux-4.4.0.orig/drivers/pci/hotplug/rpadlpar_core.c
+++ linux-4.4.0/drivers/pci/hotplug/rpadlpar_core.c
@@ -55,6 +55,7 @@
 		if ((rc == 0) && (!strcmp(drc_name, name)))
 			break;
 	}
+	of_node_put(parent);
 
 	return dn;
 }
@@ -78,6 +79,7 @@
 	return np;
 }
 
+/* Returns a device_node with its reference count incremented */
 static struct device_node *find_dlpar_node(char *drc_name, int *node_type)
 {
 	struct device_node *dn;
@@ -258,8 +260,13 @@
 
 static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn)
 {
-	if (vio_find_node(dn))
+	struct vio_dev *vio_dev;
+
+	vio_dev = vio_find_node(dn);
+	if (vio_dev) {
+		put_device(&vio_dev->dev);
 		return -EINVAL;
+	}
 
 	if (!vio_register_device_node(dn)) {
 		printk(KERN_ERR
@@ -309,6 +316,7 @@
 			rc = dlpar_add_phb(drc_name, dn);
 			break;
 	}
+	of_node_put(dn);
 
 	printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
 exit:
@@ -335,6 +343,9 @@
 		return -EINVAL;
 
 	vio_unregister_device(vio_dev);
+
+	put_device(&vio_dev->dev);
+
 	return 0;
 }
 
@@ -439,6 +450,7 @@
 			rc = dlpar_remove_pci_slot(drc_name, dn);
 			break;
 	}
+	of_node_put(dn);
 	vm_unmap_aliases();
 
 	printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
--- linux-4.4.0.orig/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ linux-4.4.0/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -39,12 +39,11 @@
 	if (nbytes >= MAX_DRC_NAME_LEN)
 		return 0;
 
-	memcpy(drc_name, buf, nbytes);
+	strscpy(drc_name, buf, nbytes + 1);
 
 	end = strchr(drc_name, '\n');
-	if (!end)
-		end = &drc_name[nbytes];
-	*end = '\0';
+	if (end)
+		*end = '\0';
 
 	rc = dlpar_add_slot(drc_name);
 	if (rc)
@@ -70,12 +69,11 @@
 	if (nbytes >= MAX_DRC_NAME_LEN)
 		return 0;
 
-	memcpy(drc_name, buf, nbytes);
+	strscpy(drc_name, buf, nbytes + 1);
 
 	end = strchr(drc_name, '\n');
-	if (!end)
-		end = &drc_name[nbytes];
-	*end = '\0';
+	if (end)
+		*end = '\0';
 
 	rc = dlpar_remove_slot(drc_name);
 	if (rc)
--- linux-4.4.0.orig/drivers/pci/hotplug/rpaphp_slot.c
+++ linux-4.4.0/drivers/pci/hotplug/rpaphp_slot.c
@@ -117,8 +117,10 @@
 int rpaphp_register_slot(struct slot *slot)
 {
 	struct hotplug_slot *php_slot = slot->hotplug_slot;
+	struct device_node *child;
+	u32 my_index;
 	int retval;
-	int slotno;
+	int slotno = -1;
 
 	dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
 		__func__, slot->dn->full_name, slot->index, slot->name,
@@ -130,10 +132,15 @@
 		return -EAGAIN;
 	}
 
-	if (slot->dn->child)
-		slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn);
-	else
-		slotno = -1;
+	for_each_child_of_node(slot->dn, child) {
+		retval = of_property_read_u32(child, "ibm,my-drc-index", &my_index);
+		if (my_index == slot->index) {
+			slotno = PCI_SLOT(PCI_DN(child)->devfn);
+			of_node_put(child);
+			break;
+		}
+	}
+
 	retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name);
 	if (retval) {
 		err("pci_hp_register failed with error %d\n", retval);
--- linux-4.4.0.orig/drivers/pci/hotplug/s390_pci_hpc.c
+++ linux-4.4.0/drivers/pci/hotplug/s390_pci_hpc.c
@@ -93,13 +93,17 @@
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
 	struct slot *slot = hotplug_slot->private;
+	struct pci_dev *pdev;
 	int rc;
 
 	if (!zpci_fn_configured(slot->zdev->state))
 		return -EIO;
 
-	if (slot->zdev->pdev)
-		pci_stop_and_remove_bus_device_locked(slot->zdev->pdev);
+	pdev = pci_get_slot(slot->zdev->bus, ZPCI_DEVFN);
+	if (pdev) {
+		pci_stop_and_remove_bus_device_locked(pdev);
+		pci_dev_put(pdev);
+	}
 
 	rc = zpci_disable_device(slot->zdev);
 	if (rc)
--- linux-4.4.0.orig/drivers/pci/hotplug/shpchp_hpc.c
+++ linux-4.4.0/drivers/pci/hotplug/shpchp_hpc.c
@@ -1062,6 +1062,8 @@
 		if (rc) {
 			ctrl_info(ctrl, "Can't get msi for the hotplug controller\n");
 			ctrl_info(ctrl, "Use INTx for the hotplug controller\n");
+		} else {
+			pci_set_master(pdev);
 		}
 
 		rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
--- linux-4.4.0.orig/drivers/pci/iov.c
+++ linux-4.4.0/drivers/pci/iov.c
@@ -161,7 +161,6 @@
 	pci_device_add(virtfn, virtfn->bus);
 	mutex_unlock(&iov->dev->sriov->lock);
 
-	pci_bus_add_device(virtfn);
 	sprintf(buf, "virtfn%u", id);
 	rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
 	if (rc)
@@ -172,6 +171,8 @@
 
 	kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
 
+	pci_bus_add_device(virtfn);
+
 	return 0;
 
 failed2:
@@ -303,13 +304,6 @@
 			return rc;
 	}
 
-	pci_iov_set_numvfs(dev, nr_virtfn);
-	iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
-	pci_cfg_access_lock(dev);
-	pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-	msleep(100);
-	pci_cfg_access_unlock(dev);
-
 	iov->initial_VFs = initial;
 	if (nr_virtfn < initial)
 		initial = nr_virtfn;
@@ -320,6 +314,13 @@
 		goto err_pcibios;
 	}
 
+	pci_iov_set_numvfs(dev, nr_virtfn);
+	iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
+	pci_cfg_access_lock(dev);
+	pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+	msleep(100);
+	pci_cfg_access_unlock(dev);
+
 	for (i = 0; i < initial; i++) {
 		rc = virtfn_add(dev, i, 0);
 		if (rc)
@@ -555,21 +556,61 @@
 }
 
 /**
- * pci_iov_resource_bar - get position of the SR-IOV BAR
+ * pci_iov_update_resource - update a VF BAR
  * @dev: the PCI device
  * @resno: the resource number
  *
- * Returns position of the BAR encapsulated in the SR-IOV capability.
+ * Update a VF BAR in the SR-IOV capability of a PF.
  */
-int pci_iov_resource_bar(struct pci_dev *dev, int resno)
+void pci_iov_update_resource(struct pci_dev *dev, int resno)
 {
-	if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
-		return 0;
+	struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL;
+	struct resource *res = dev->resource + resno;
+	int vf_bar = resno - PCI_IOV_RESOURCES;
+	struct pci_bus_region region;
+	u16 cmd;
+	u32 new;
+	int reg;
 
-	BUG_ON(!dev->is_physfn);
+	/*
+	 * The generic pci_restore_bars() path calls this for all devices,
+	 * including VFs and non-SR-IOV devices.  If this is not a PF, we
+	 * have nothing to do.
+	 */
+	if (!iov)
+		return;
 
-	return dev->sriov->pos + PCI_SRIOV_BAR +
-		4 * (resno - PCI_IOV_RESOURCES);
+	pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd);
+	if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) {
+		dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n",
+			 vf_bar, res);
+		return;
+	}
+
+	/*
+	 * Ignore unimplemented BARs, unused resource slots for 64-bit
+	 * BARs, and non-movable resources, e.g., those described via
+	 * Enhanced Allocation.
+	 */
+	if (!res->flags)
+		return;
+
+	if (res->flags & IORESOURCE_UNSET)
+		return;
+
+	if (res->flags & IORESOURCE_PCI_FIXED)
+		return;
+
+	pcibios_resource_to_bus(dev->bus, &region, res);
+	new = region.start;
+	new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
+
+	reg = iov->pos + PCI_SRIOV_BAR + 4 * vf_bar;
+	pci_write_config_dword(dev, reg, new);
+	if (res->flags & IORESOURCE_MEM_64) {
+		new = region.start >> 16 >> 16;
+		pci_write_config_dword(dev, reg + 4, new);
+	}
 }
 
 resource_size_t __weak pcibios_iov_resource_alignment(struct pci_dev *dev,
--- linux-4.4.0.orig/drivers/pci/msi.c
+++ linux-4.4.0/drivers/pci/msi.c
@@ -224,7 +224,7 @@
 		return 0;
 
 	mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
-	if (flag)
+	if (flag & PCI_MSIX_ENTRY_CTRL_MASKBIT)
 		mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
 	writel(mask_bits, desc->mask_base + offset);
 
@@ -257,6 +257,7 @@
 {
 	msi_set_mask_bit(data, 1);
 }
+EXPORT_SYMBOL_GPL(pci_msi_mask_irq);
 
 /**
  * pci_msi_unmask_irq - Generic irq chip callback to unmask PCI/MSI interrupts
@@ -266,6 +267,7 @@
 {
 	msi_set_mask_bit(data, 0);
 }
+EXPORT_SYMBOL_GPL(pci_msi_unmask_irq);
 
 void default_restore_msi_irqs(struct pci_dev *dev)
 {
@@ -1126,6 +1128,7 @@
 {
 	return to_pci_dev(desc->dev);
 }
+EXPORT_SYMBOL(msi_desc_to_pci_dev);
 
 void *msi_desc_to_pci_sysdata(struct msi_desc *desc)
 {
@@ -1278,6 +1281,8 @@
 	if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
 		pci_msi_domain_update_chip_ops(info);
 
+	info->flags |= MSI_FLAG_ACTIVATE_EARLY;
+
 	domain = msi_create_irq_domain(fwnode, info, parent);
 	if (!domain)
 		return NULL;
@@ -1285,6 +1290,7 @@
 	domain->bus_token = DOMAIN_BUS_PCI_MSI;
 	return domain;
 }
+EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
 
 /**
  * pci_msi_domain_alloc_irqs - Allocate interrupts for @dev in @domain
--- linux-4.4.0.orig/drivers/pci/pci-acpi.c
+++ linux-4.4.0/drivers/pci/pci-acpi.c
@@ -9,7 +9,9 @@
 
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irqdomain.h>
 #include <linux/pci.h>
+#include <linux/msi.h>
 #include <linux/pci_hotplug.h>
 #include <linux/module.h>
 #include <linux/pci-aspm.h>
@@ -543,7 +545,7 @@
 	union acpi_object *obj;
 	struct pci_host_bridge *bridge;
 
-	if (acpi_pci_disabled || !bus->bridge)
+	if (acpi_pci_disabled || !bus->bridge || !ACPI_HANDLE(bus->bridge))
 		return;
 
 	acpi_pci_slot_enumerate(bus);
@@ -689,6 +691,46 @@
 	.cleanup = pci_acpi_cleanup,
 };
 
+
+static struct fwnode_handle *(*pci_msi_get_fwnode_cb)(struct device *dev);
+
+/**
+ * pci_msi_register_fwnode_provider - Register callback to retrieve fwnode
+ * @fn:       Callback matching a device to a fwnode that identifies a PCI
+ *            MSI domain.
+ *
+ * This should be called by irqchip driver, which is the parent of
+ * the MSI domain to provide callback interface to query fwnode.
+ */
+void
+pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *))
+{
+	pci_msi_get_fwnode_cb = fn;
+}
+
+/**
+ * pci_host_bridge_acpi_msi_domain - Retrieve MSI domain of a PCI host bridge
+ * @bus:      The PCI host bridge bus.
+ *
+ * This function uses the callback function registered by
+ * pci_msi_register_fwnode_provider() to retrieve the irq_domain with
+ * type DOMAIN_BUS_PCI_MSI of the specified host bridge bus.
+ * This returns NULL on error or when the domain is not found.
+ */
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
+{
+	struct fwnode_handle *fwnode;
+
+	if (!pci_msi_get_fwnode_cb)
+		return NULL;
+
+	fwnode = pci_msi_get_fwnode_cb(&bus->dev);
+	if (!fwnode)
+		return NULL;
+
+	return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
+}
+
 static int __init acpi_pci_init(void)
 {
 	int ret;
--- linux-4.4.0.orig/drivers/pci/pci-driver.c
+++ linux-4.4.0/drivers/pci/pci-driver.c
@@ -944,7 +944,13 @@
 	if (pci_has_legacy_pm_support(pci_dev))
 		return pci_legacy_resume_early(dev);
 
-	pci_update_current_state(pci_dev, PCI_D0);
+	/*
+	 * pci_restore_state() requires the device to be in D0 (because of MSI
+	 * restoration among other things), so force it into D0 in case the
+	 * driver's "freeze" callbacks put it into a low-power state directly.
+	 */
+	pci_set_power_state(pci_dev, PCI_D0);
+	pci_restore_state(pci_dev);
 
 	if (drv && drv->pm && drv->pm->thaw_noirq)
 		error = drv->pm->thaw_noirq(dev);
@@ -1134,11 +1140,14 @@
 	int error;
 
 	/*
-	 * If pci_dev->driver is not set (unbound), the device should
-	 * always remain in D0 regardless of the runtime PM status
+	 * If pci_dev->driver is not set (unbound), we leave the device in D0,
+	 * but it may go to D3cold when the bridge above it runtime suspends.
+	 * Save its config space in case that happens.
 	 */
-	if (!pci_dev->driver)
+	if (!pci_dev->driver) {
+		pci_save_state(pci_dev);
 		return 0;
+	}
 
 	if (!pm || !pm->runtime_suspend)
 		return -ENOSYS;
@@ -1189,16 +1198,18 @@
 	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
 	/*
-	 * If pci_dev->driver is not set (unbound), the device should
-	 * always remain in D0 regardless of the runtime PM status
+	 * Restoring config space is necessary even if the device is not bound
+	 * to a driver because although we left it in D0, it may have gone to
+	 * D3cold when the bridge above it runtime suspended.
 	 */
+	pci_restore_standard_config(pci_dev);
+
 	if (!pci_dev->driver)
 		return 0;
 
 	if (!pm || !pm->runtime_resume)
 		return -ENOSYS;
 
-	pci_restore_standard_config(pci_dev);
 	pci_fixup_device(pci_fixup_resume_early, pci_dev);
 	__pci_enable_wake(pci_dev, PCI_D0, true, false);
 	pci_fixup_device(pci_fixup_resume, pci_dev);
--- linux-4.4.0.orig/drivers/pci/pci-sysfs.c
+++ linux-4.4.0/drivers/pci/pci-sysfs.c
@@ -30,6 +30,7 @@
 #include <linux/vgaarb.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
+#include <linux/module.h>
 #include "pci.h"
 
 static int sysfs_initialized;	/* = 0 */
@@ -180,13 +181,16 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!val) {
-		if (pci_is_enabled(pdev))
-			pci_disable_device(pdev);
-		else
-			result = -EIO;
-	} else
+	device_lock(dev);
+	if (dev->driver)
+		result = -EBUSY;
+	else if (val)
 		result = pci_enable_device(pdev);
+	else if (pci_is_enabled(pdev))
+		pci_disable_device(pdev);
+	else
+		result = -EIO;
+	device_unlock(dev);
 
 	return result < 0 ? result : count;
 }
@@ -368,7 +372,7 @@
 		pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
 	return count;
 }
-static struct device_attribute dev_remove_attr = __ATTR(remove,
+static struct device_attribute dev_remove_attr = __ATTR_IGNORE_LOCKDEP(remove,
 							(S_IWUSR|S_IWGRP),
 							NULL, remove_store);
 
@@ -522,7 +526,7 @@
 				     const char *buf, size_t count)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
-	char *driver_override, *old = pdev->driver_override, *cp;
+	char *driver_override, *old, *cp;
 
 	/* We need to keep extra room for a newline */
 	if (count >= (PAGE_SIZE - 1))
@@ -536,12 +540,15 @@
 	if (cp)
 		*cp = '\0';
 
+	device_lock(dev);
+	old = pdev->driver_override;
 	if (strlen(driver_override)) {
 		pdev->driver_override = driver_override;
 	} else {
 		kfree(driver_override);
 		pdev->driver_override = NULL;
 	}
+	device_unlock(dev);
 
 	kfree(old);
 
@@ -552,8 +559,12 @@
 				    struct device_attribute *attr, char *buf)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
+	ssize_t len;
 
-	return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
+	device_lock(dev);
+	len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
+	device_unlock(dev);
+	return len;
 }
 static DEVICE_ATTR_RW(driver_override);
 
@@ -713,6 +724,9 @@
 	loff_t init_off = off;
 	u8 *data = (u8 *) buf;
 
+	if (secure_modules())
+		return -EPERM;
+
 	if (off > dev->cfg_size)
 		return 0;
 	if (off + count > dev->cfg_size) {
@@ -973,15 +987,19 @@
 int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
 		  enum pci_mmap_api mmap_api)
 {
-	unsigned long nr, start, size, pci_start;
+	unsigned long nr, start, size;
+	resource_size_t pci_start = 0, pci_end;
 
 	if (pci_resource_len(pdev, resno) == 0)
 		return 0;
 	nr = vma_pages(vma);
 	start = vma->vm_pgoff;
 	size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
-	pci_start = (mmap_api == PCI_MMAP_PROCFS) ?
-			pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0;
+	if (mmap_api == PCI_MMAP_PROCFS) {
+		pci_resource_to_user(pdev, resno, &pdev->resource[resno],
+				     &pci_start, &pci_end);
+		pci_start >>= PAGE_SHIFT;
+	}
 	if (start >= pci_start && start < pci_start + size &&
 			start + nr <= pci_start + size)
 		return 1;
@@ -1007,12 +1025,18 @@
 	resource_size_t start, end;
 	int i;
 
+	if (secure_modules())
+		return -EPERM;
+
 	for (i = 0; i < PCI_ROM_RESOURCE; i++)
 		if (res == &pdev->resource[i])
 			break;
 	if (i >= PCI_ROM_RESOURCE)
 		return -ENODEV;
 
+	if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
+		return -EINVAL;
+
 	if (!pci_mmap_fits(pdev, i, vma, PCI_MMAP_SYSFS)) {
 		WARN(1, "process \"%s\" tried to map 0x%08lx bytes at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n",
 			current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff,
@@ -1029,10 +1053,6 @@
 	pci_resource_to_user(pdev, i, res, &start, &end);
 	vma->vm_pgoff += start >> PAGE_SHIFT;
 	mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
-
-	if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start))
-		return -EINVAL;
-
 	return pci_mmap_page_range(pdev, vma, mmap_type, write_combine);
 }
 
@@ -1108,6 +1128,9 @@
 				     struct bin_attribute *attr, char *buf,
 				     loff_t off, size_t count)
 {
+	if (secure_modules())
+		return -EPERM;
+
 	return pci_resource_io(filp, kobj, attr, buf, off, count, true);
 }
 
@@ -1372,10 +1395,10 @@
 	if (!sysfs_initialized)
 		return -EACCES;
 
-	if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
-		retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
-	else
+	if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
 		retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+	else
+		retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
 	if (retval)
 		goto err;
 
@@ -1427,10 +1450,10 @@
 err_resource_files:
 	pci_remove_resource_files(pdev);
 err_config_file:
-	if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
-		sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
-	else
+	if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
 		sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+	else
+		sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
 err:
 	return retval;
 }
@@ -1464,10 +1487,10 @@
 
 	pci_remove_capabilities_sysfs(pdev);
 
-	if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
-		sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
-	else
+	if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
 		sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+	else
+		sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
 
 	pci_remove_resource_files(pdev);
 
--- linux-4.4.0.orig/drivers/pci/pci.c
+++ linux-4.4.0/drivers/pci/pci.c
@@ -7,6 +7,7 @@
  *	Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
  */
 
+#include <linux/acpi.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -25,6 +26,7 @@
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
 #include <linux/pci_hotplug.h>
+#include <linux/vmalloc.h>
 #include <asm-generic/pci-bridge.h>
 #include <asm/setup.h>
 #include <linux/aer.h>
@@ -519,10 +521,6 @@
 {
 	int i;
 
-	/* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */
-	if (dev->is_virtfn)
-		return;
-
 	for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
 		pci_update_resource(dev, i);
 }
@@ -708,19 +706,6 @@
 }
 
 /**
- * pci_power_up - Put the given device into D0 forcibly
- * @dev: PCI device to power up
- */
-void pci_power_up(struct pci_dev *dev)
-{
-	if (platform_pci_power_manageable(dev))
-		platform_pci_set_power_state(dev, PCI_D0);
-
-	pci_raw_set_power_state(dev, PCI_D0);
-	pci_update_current_state(dev, PCI_D0);
-}
-
-/**
  * pci_platform_power_transition - Use platform to change device power state
  * @dev: PCI device to handle.
  * @state: State to put the device into.
@@ -896,6 +881,17 @@
 EXPORT_SYMBOL(pci_set_power_state);
 
 /**
+ * pci_power_up - Put the given device into D0 forcibly
+ * @dev: PCI device to power up
+ */
+void pci_power_up(struct pci_dev *dev)
+{
+	__pci_start_power_transition(dev, PCI_D0);
+	pci_raw_set_power_state(dev, PCI_D0);
+	pci_update_current_state(dev, PCI_D0);
+}
+
+/**
  * pci_choose_state - Choose the power state of a PCI device
  * @dev: PCI device to be suspended
  * @state: target sleep state for the whole system. This is the value
@@ -1068,12 +1064,12 @@
 EXPORT_SYMBOL(pci_save_state);
 
 static void pci_restore_config_dword(struct pci_dev *pdev, int offset,
-				     u32 saved_val, int retry)
+				     u32 saved_val, int retry, bool force)
 {
 	u32 val;
 
 	pci_read_config_dword(pdev, offset, &val);
-	if (val == saved_val)
+	if (!force && val == saved_val)
 		return;
 
 	for (;;) {
@@ -1092,25 +1088,36 @@
 }
 
 static void pci_restore_config_space_range(struct pci_dev *pdev,
-					   int start, int end, int retry)
+					   int start, int end, int retry,
+					   bool force)
 {
 	int index;
 
 	for (index = end; index >= start; index--)
 		pci_restore_config_dword(pdev, 4 * index,
 					 pdev->saved_config_space[index],
-					 retry);
+					 retry, force);
 }
 
 static void pci_restore_config_space(struct pci_dev *pdev)
 {
 	if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
-		pci_restore_config_space_range(pdev, 10, 15, 0);
+		pci_restore_config_space_range(pdev, 10, 15, 0, false);
 		/* Restore BARs before the command register. */
-		pci_restore_config_space_range(pdev, 4, 9, 10);
-		pci_restore_config_space_range(pdev, 0, 3, 0);
+		pci_restore_config_space_range(pdev, 4, 9, 10, false);
+		pci_restore_config_space_range(pdev, 0, 3, 0, false);
+	} else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_restore_config_space_range(pdev, 12, 15, 0, false);
+
+		/*
+		 * Force rewriting of prefetch registers to avoid S3 resume
+		 * issues on Intel PCI bridges that occur when these
+		 * registers are not explicitly written.
+		 */
+		pci_restore_config_space_range(pdev, 9, 11, 0, true);
+		pci_restore_config_space_range(pdev, 0, 8, 0, false);
 	} else {
-		pci_restore_config_space_range(pdev, 0, 15, 0);
+		pci_restore_config_space_range(pdev, 0, 15, 0, false);
 	}
 }
 
@@ -1729,6 +1736,13 @@
 			 */
 			if (bridge && bridge->current_state != PCI_D0)
 				continue;
+			/*
+			 * If the device is in D3cold it should not be
+			 * polled either.
+			 */
+			if (pme_dev->dev->current_state == PCI_D3cold)
+				continue;
+
 			pci_pme_wakeup(pme_dev->dev, NULL);
 		} else {
 			list_del(&pme_dev->list);
@@ -1736,8 +1750,8 @@
 		}
 	}
 	if (!list_empty(&pci_pme_list))
-		schedule_delayed_work(&pci_pme_work,
-				      msecs_to_jiffies(PME_TIMEOUT));
+		queue_delayed_work(system_freezable_wq, &pci_pme_work,
+				   msecs_to_jiffies(PME_TIMEOUT));
 	mutex_unlock(&pci_pme_list_mutex);
 }
 
@@ -1802,8 +1816,9 @@
 			mutex_lock(&pci_pme_list_mutex);
 			list_add(&pme_dev->list, &pci_pme_list);
 			if (list_is_singular(&pci_pme_list))
-				schedule_delayed_work(&pci_pme_work,
-						      msecs_to_jiffies(PME_TIMEOUT));
+				queue_delayed_work(system_freezable_wq,
+						   &pci_pme_work,
+						   msecs_to_jiffies(PME_TIMEOUT));
 			mutex_unlock(&pci_pme_list_mutex);
 		} else {
 			mutex_lock(&pci_pme_list_mutex);
@@ -2043,6 +2058,10 @@
 	if (!dev->pme_support)
 		return false;
 
+	/* PME-capable in principle, but not from the intended sleep state */
+	if (!pci_pme_capable(dev, pci_target_state(dev)))
+		return false;
+
 	while (bus->parent) {
 		struct pci_dev *bridge = bus->self;
 
@@ -3022,6 +3041,121 @@
 }
 EXPORT_SYMBOL(pci_request_regions_exclusive);
 
+#ifdef PCI_IOBASE
+struct io_range {
+	struct list_head list;
+	phys_addr_t start;
+	resource_size_t size;
+};
+
+static LIST_HEAD(io_range_list);
+static DEFINE_SPINLOCK(io_range_lock);
+#endif
+
+/*
+ * Record the PCI IO range (expressed as CPU physical address + size).
+ * Return a negative value if an error has occured, zero otherwise
+ */
+int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size)
+{
+	int err = 0;
+
+#ifdef PCI_IOBASE
+	struct io_range *range;
+	resource_size_t allocated_size = 0;
+
+	/* check if the range hasn't been previously recorded */
+	spin_lock(&io_range_lock);
+	list_for_each_entry(range, &io_range_list, list) {
+		if (addr >= range->start && addr + size <= range->start + size) {
+			/* range already registered, bail out */
+			goto end_register;
+		}
+		allocated_size += range->size;
+	}
+
+	/* range not registed yet, check for available space */
+	if (allocated_size + size - 1 > IO_SPACE_LIMIT) {
+		/* if it's too big check if 64K space can be reserved */
+		if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) {
+			err = -E2BIG;
+			goto end_register;
+		}
+
+		size = SZ_64K;
+		pr_warn("Requested IO range too big, new size set to 64K\n");
+	}
+
+	/* add the range to the list */
+	range = kzalloc(sizeof(*range), GFP_ATOMIC);
+	if (!range) {
+		err = -ENOMEM;
+		goto end_register;
+	}
+
+	range->start = addr;
+	range->size = size;
+
+	list_add_tail(&range->list, &io_range_list);
+
+end_register:
+	spin_unlock(&io_range_lock);
+#endif
+
+	return err;
+}
+
+phys_addr_t pci_pio_to_address(unsigned long pio)
+{
+	phys_addr_t address = (phys_addr_t)OF_BAD_ADDR;
+
+#ifdef PCI_IOBASE
+	struct io_range *range;
+	resource_size_t allocated_size = 0;
+
+	if (pio > IO_SPACE_LIMIT)
+		return address;
+
+	spin_lock(&io_range_lock);
+	list_for_each_entry(range, &io_range_list, list) {
+		if (pio >= allocated_size && pio < allocated_size + range->size) {
+			address = range->start + pio - allocated_size;
+			break;
+		}
+		allocated_size += range->size;
+	}
+	spin_unlock(&io_range_lock);
+#endif
+
+	return address;
+}
+
+unsigned long __weak pci_address_to_pio(phys_addr_t address)
+{
+#ifdef PCI_IOBASE
+	struct io_range *res;
+	resource_size_t offset = 0;
+	unsigned long addr = -1;
+
+	spin_lock(&io_range_lock);
+	list_for_each_entry(res, &io_range_list, list) {
+		if (address >= res->start && address < res->start + res->size) {
+			addr = address - res->start + offset;
+			break;
+		}
+		offset += res->size;
+	}
+	spin_unlock(&io_range_lock);
+
+	return addr;
+#else
+	if (address > IO_SPACE_LIMIT)
+		return (unsigned long)-1;
+
+	return (unsigned long) address;
+#endif
+}
+
 /**
  *	pci_remap_iospace - Remap the memory mapped I/O space
  *	@res: Resource describing the I/O space
@@ -3053,6 +3187,23 @@
 #endif
 }
 
+/**
+ *	pci_unmap_iospace - Unmap the memory mapped I/O space
+ *	@res: resource to be unmapped
+ *
+ *	Unmap the CPU virtual address @res from virtual address space.
+ *	Only architectures that have memory mapped IO functions defined
+ *	(and the PCI_IOBASE value defined) should call this function.
+ */
+void pci_unmap_iospace(struct resource *res)
+{
+#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
+	unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
+
+	unmap_kernel_range(vaddr, resource_size(res));
+#endif
+}
+
 static void __pci_set_master(struct pci_dev *dev, bool enable)
 {
 	u16 old_cmd, cmd;
@@ -3849,6 +4000,10 @@
 {
 	struct pci_dev *dev;
 
+
+	if (bus->self && (bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
+		return false;
+
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
 		    (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
@@ -4468,36 +4623,6 @@
 }
 EXPORT_SYMBOL(pci_select_bars);
 
-/**
- * pci_resource_bar - get position of the BAR associated with a resource
- * @dev: the PCI device
- * @resno: the resource number
- * @type: the BAR type to be filled in
- *
- * Returns BAR position in config space, or 0 if the BAR is invalid.
- */
-int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
-{
-	int reg;
-
-	if (resno < PCI_ROM_RESOURCE) {
-		*type = pci_bar_unknown;
-		return PCI_BASE_ADDRESS_0 + 4 * resno;
-	} else if (resno == PCI_ROM_RESOURCE) {
-		*type = pci_bar_mem32;
-		return dev->rom_base_reg;
-	} else if (resno < PCI_BRIDGE_RESOURCES) {
-		/* device specific resource */
-		*type = pci_bar_unknown;
-		reg = pci_iov_resource_bar(dev, resno);
-		if (reg)
-			return reg;
-	}
-
-	dev_err(&dev->dev, "BAR %d: invalid resource\n", resno);
-	return 0;
-}
-
 /* Some architectures require additional programming to enable VGA */
 static arch_set_vga_state_t arch_set_vga_state;
 
@@ -4769,11 +4894,13 @@
 }
 
 #ifdef CONFIG_PCI_DOMAINS_GENERIC
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+static int of_pci_bus_find_domain_nr(struct device *parent)
 {
 	static int use_dt_domains = -1;
-	int domain = of_get_pci_domain_nr(parent->of_node);
+	int domain = -1;
 
+	if (parent)
+		domain = of_get_pci_domain_nr(parent->of_node);
 	/*
 	 * Check DT domain and use_dt_domains values.
 	 *
@@ -4811,7 +4938,13 @@
 		domain = -1;
 	}
 
-	bus->domain_nr = domain;
+	return domain;
+}
+
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
+{
+	return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
+			       acpi_pci_bus_find_domain_nr(bus);
 }
 #endif
 #endif
--- linux-4.4.0.orig/drivers/pci/pci.h
+++ linux-4.4.0/drivers/pci/pci.h
@@ -232,7 +232,6 @@
 int pci_setup_device(struct pci_dev *dev);
 int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 		    struct resource *res, unsigned int reg);
-int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type);
 void pci_configure_ari(struct pci_dev *dev);
 void __pci_bus_size_bridges(struct pci_bus *bus,
 			struct list_head *realloc_head);
@@ -276,7 +275,7 @@
 #ifdef CONFIG_PCI_IOV
 int pci_iov_init(struct pci_dev *dev);
 void pci_iov_release(struct pci_dev *dev);
-int pci_iov_resource_bar(struct pci_dev *dev, int resno);
+void pci_iov_update_resource(struct pci_dev *dev, int resno);
 resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
 void pci_restore_iov_state(struct pci_dev *dev);
 int pci_iov_bus_range(struct pci_bus *bus);
@@ -290,10 +289,6 @@
 
 {
 }
-static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno)
-{
-	return 0;
-}
 static inline void pci_restore_iov_state(struct pci_dev *dev)
 {
 }
--- linux-4.4.0.orig/drivers/pci/pcie/aer/aer_inject.c
+++ linux-4.4.0/drivers/pci/pcie/aer/aer_inject.c
@@ -283,20 +283,6 @@
 	return 0;
 }
 
-static struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
-{
-	while (1) {
-		if (!pci_is_pcie(dev))
-			break;
-		if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
-			return dev;
-		if (!dev->bus->self)
-			break;
-		dev = dev->bus->self;
-	}
-	return NULL;
-}
-
 static int find_aer_device_iter(struct device *device, void *data)
 {
 	struct pcie_device **result = data;
--- linux-4.4.0.orig/drivers/pci/pcie/aer/aerdrv.c
+++ linux-4.4.0/drivers/pci/pcie/aer/aerdrv.c
@@ -262,7 +262,6 @@
 	rpc->rpd = dev;
 	INIT_WORK(&rpc->dpc_handler, aer_isr);
 	mutex_init(&rpc->rpc_mutex);
-	init_waitqueue_head(&rpc->wait_release);
 
 	/* Use PCIe bus function to store rpc into PCIe device */
 	set_service_data(dev, rpc);
@@ -285,8 +284,7 @@
 		if (rpc->isr)
 			free_irq(dev->irq, dev);
 
-		wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
-
+		flush_work(&rpc->dpc_handler);
 		aer_disable_rootport(rpc);
 		kfree(rpc);
 		set_service_data(dev, NULL);
--- linux-4.4.0.orig/drivers/pci/pcie/aer/aerdrv.h
+++ linux-4.4.0/drivers/pci/pcie/aer/aerdrv.h
@@ -72,7 +72,6 @@
 					 * recovery on the same
 					 * root port hierarchy
 					 */
-	wait_queue_head_t wait_release;
 };
 
 struct aer_broadcast_data {
--- linux-4.4.0.orig/drivers/pci/pcie/aer/aerdrv_core.c
+++ linux-4.4.0/drivers/pci/pcie/aer/aerdrv_core.c
@@ -388,7 +388,14 @@
 		 * If the error is reported by an end point, we think this
 		 * error is related to the upstream link of the end point.
 		 */
-		pci_walk_bus(dev->bus, cb, &result_data);
+		if (state == pci_channel_io_normal)
+			/*
+			 * the error is non fatal so the bus is ok, just invoke
+			 * the callback for the function that logged the error.
+			 */
+			cb(dev, &result_data);
+		else
+			pci_walk_bus(dev->bus, cb, &result_data);
 	}
 
 	return result_data.result;
@@ -811,8 +818,6 @@
 	while (get_e_source(rpc, &e_src))
 		aer_isr_one_error(p_device, &e_src);
 	mutex_unlock(&rpc->rpc_mutex);
-
-	wake_up(&rpc->wait_release);
 }
 
 /**
--- linux-4.4.0.orig/drivers/pci/pcie/aspm.c
+++ linux-4.4.0/drivers/pci/pcie/aspm.c
@@ -388,16 +388,6 @@
 
 	/* Setup initial capable state. Will be updated later */
 	link->aspm_capable = link->aspm_support;
-	/*
-	 * If the downstream component has pci bridge function, don't
-	 * do ASPM for now.
-	 */
-	list_for_each_entry(child, &linkbus->devices, bus_list) {
-		if (pci_pcie_type(child) == PCI_EXP_TYPE_PCI_BRIDGE) {
-			link->aspm_disable = ASPM_STATE_ALL;
-			break;
-		}
-	}
 
 	/* Get and check endpoint acceptable latencies */
 	list_for_each_entry(child, &linkbus->devices, bus_list) {
@@ -518,25 +508,32 @@
 	link = kzalloc(sizeof(*link), GFP_KERNEL);
 	if (!link)
 		return NULL;
+
 	INIT_LIST_HEAD(&link->sibling);
 	INIT_LIST_HEAD(&link->children);
 	INIT_LIST_HEAD(&link->link);
 	link->pdev = pdev;
-	if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) {
+
+	/*
+	 * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe
+	 * hierarchies.
+	 */
+	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
+	    pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) {
+		link->root = link;
+	} else {
 		struct pcie_link_state *parent;
+
 		parent = pdev->bus->parent->self->link_state;
 		if (!parent) {
 			kfree(link);
 			return NULL;
 		}
+
 		link->parent = parent;
+		link->root = link->parent->root;
 		list_add(&link->link, &parent->children);
 	}
-	/* Setup a pointer to the root port link */
-	if (!link->parent)
-		link->root = link;
-	else
-		link->root = link->parent->root;
 
 	list_add(&link->sibling, &link_list);
 	pdev->link_state = link;
@@ -810,6 +807,7 @@
 			cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]);
 		else
 			cnt += sprintf(buffer + cnt, "%s ", policy_str[i]);
+	cnt += sprintf(buffer + cnt, "\n");
 	return cnt;
 }
 
--- linux-4.4.0.orig/drivers/pci/pcie/pme.c
+++ linux-4.4.0/drivers/pci/pcie/pme.c
@@ -233,6 +233,9 @@
 			break;
 
 		pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
+		if (rtsta == (u32) ~0)
+			break;
+
 		if (rtsta & PCI_EXP_RTSTA_PME) {
 			/*
 			 * Clear PME status of the port.  If there are other
@@ -280,7 +283,7 @@
 	spin_lock_irqsave(&data->lock, flags);
 	pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
 
-	if (!(rtsta & PCI_EXP_RTSTA_PME)) {
+	if (rtsta == (u32) ~0 || !(rtsta & PCI_EXP_RTSTA_PME)) {
 		spin_unlock_irqrestore(&data->lock, flags);
 		return IRQ_NONE;
 	}
--- linux-4.4.0.orig/drivers/pci/probe.c
+++ linux-4.4.0/drivers/pci/probe.c
@@ -15,6 +15,7 @@
 #include <linux/pci-aspm.h>
 #include <linux/aer.h>
 #include <linux/acpi.h>
+#include <linux/irqdomain.h>
 #include <asm-generic/pci-bridge.h>
 #include "pci.h"
 
@@ -226,10 +227,11 @@
 			mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK;
 		}
 	} else {
-		res->flags |= (l & IORESOURCE_ROM_ENABLE);
+		if (l & PCI_ROM_ADDRESS_ENABLE)
+			res->flags |= IORESOURCE_ROM_ENABLE;
 		l64 = l & PCI_ROM_ADDRESS_MASK;
 		sz64 = sz & PCI_ROM_ADDRESS_MASK;
-		mask64 = (u32)PCI_ROM_ADDRESS_MASK;
+		mask64 = PCI_ROM_ADDRESS_MASK;
 	}
 
 	if (res->flags & IORESOURCE_MEM_64) {
@@ -319,6 +321,9 @@
 {
 	unsigned int pos, reg;
 
+	if (dev->non_compliant_bars)
+		return;
+
 	for (pos = 0; pos < howmany; pos++) {
 		struct resource *res = &dev->resource[pos];
 		reg = PCI_BASE_ADDRESS_0 + (pos << 2);
@@ -672,6 +677,22 @@
 	 * should be called from here.
 	 */
 	d = pci_host_bridge_of_msi_domain(bus);
+	if (!d)
+		d = pci_host_bridge_acpi_msi_domain(bus);
+
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+	/*
+	 * If no IRQ domain was found via the OF tree, try looking it up
+	 * directly through the fwnode_handle.
+	 */
+	if (!d) {
+		struct fwnode_handle *fwnode = pci_root_bus_fwnode(bus);
+
+		if (fwnode)
+			d = irq_find_matching_fwnode(fwnode,
+						     DOMAIN_BUS_PCI_MSI);
+	}
+#endif
 
 	return d;
 }
@@ -1016,6 +1037,7 @@
 	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
 	if (!pos)
 		return;
+
 	pdev->pcie_cap = pos;
 	pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
 	pdev->pcie_flags_reg = reg16;
@@ -1023,13 +1045,14 @@
 	pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
 
 	/*
-	 * A Root Port is always the upstream end of a Link.  No PCIe
-	 * component has two Links.  Two Links are connected by a Switch
-	 * that has a Port on each Link and internal logic to connect the
-	 * two Ports.
+	 * A Root Port or a PCI-to-PCIe bridge is always the upstream end
+	 * of a Link.  No PCIe component has two Links.  Two Links are
+	 * connected by a Switch that has a Port on each Link and internal
+	 * logic to connect the two Ports.
 	 */
 	type = pci_pcie_type(pdev);
-	if (type == PCI_EXP_TYPE_ROOT_PORT)
+	if (type == PCI_EXP_TYPE_ROOT_PORT ||
+	    type == PCI_EXP_TYPE_PCIE_BRIDGE)
 		pdev->has_secondary_link = 1;
 	else if (type == PCI_EXP_TYPE_UPSTREAM ||
 		 type == PCI_EXP_TYPE_DOWNSTREAM) {
@@ -1174,6 +1197,7 @@
 int pci_setup_device(struct pci_dev *dev)
 {
 	u32 class;
+	u16 cmd;
 	u8 hdr_type;
 	int pos = 0;
 	struct pci_bus_region region;
@@ -1219,6 +1243,16 @@
 	/* device class may be changed after fixup */
 	class = dev->class >> 8;
 
+	if (dev->non_compliant_bars && !dev->mmio_always_on) {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+			dev_info(&dev->dev, "device has non-compliant BARs; disabling IO/MEM decoding\n");
+			cmd &= ~PCI_COMMAND_IO;
+			cmd &= ~PCI_COMMAND_MEMORY;
+			pci_write_config_word(dev, PCI_COMMAND, cmd);
+		}
+	}
+
 	switch (dev->hdr_type) {		    /* header type */
 	case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
 		if (class == PCI_CLASS_BRIDGE_PCI)
@@ -1318,7 +1352,31 @@
 	struct pci_dev *bridge = pci_upstream_bridge(dev);
 	int mps, p_mps, rc;
 
-	if (!pci_is_pcie(dev) || !bridge || !pci_is_pcie(bridge))
+	if (!pci_is_pcie(dev))
+		return;
+
+	/* MPS and MRRS fields are of type 'RsvdP' for VFs, short-circuit out */
+	if (dev->is_virtfn)
+		return;
+
+	/*
+	 * For Root Complex Integrated Endpoints, program the maximum
+	 * supported value unless limited by the PCIE_BUS_PEER2PEER case.
+	 */
+	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) {
+		if (pcie_bus_config == PCIE_BUS_PEER2PEER)
+			mps = 128;
+		else
+			mps = 128 << dev->pcie_mpss;
+		rc = pcie_set_mps(dev, mps);
+		if (rc) {
+			dev_warn(&dev->dev, "can't set Max Payload Size to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n",
+				 mps);
+		}
+		return;
+	}
+
+	if (!bridge || !pci_is_pcie(bridge))
 		return;
 
 	mps = pcie_get_mps(dev);
@@ -1397,8 +1455,31 @@
 
 static void program_hpp_type1(struct pci_dev *dev, struct hpp_type1 *hpp)
 {
-	if (hpp)
-		dev_warn(&dev->dev, "PCI-X settings not supported\n");
+	int pos;
+
+	if (!hpp)
+		return;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+	if (!pos)
+		return;
+
+	dev_warn(&dev->dev, "PCI-X settings not supported\n");
+}
+
+static bool pcie_root_rcb_set(struct pci_dev *dev)
+{
+	struct pci_dev *rp = pcie_find_root_port(dev);
+	u16 lnkctl;
+
+	if (!rp)
+		return false;
+
+	pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl);
+	if (lnkctl & PCI_EXP_LNKCTL_RCB)
+		return true;
+
+	return false;
 }
 
 static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
@@ -1409,6 +1490,9 @@
 	if (!hpp)
 		return;
 
+	if (!pci_is_pcie(dev))
+		return;
+
 	if (hpp->revision > 1) {
 		dev_warn(&dev->dev, "PCIe settings rev %d not supported\n",
 			 hpp->revision);
@@ -1430,9 +1514,20 @@
 			~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or);
 
 	/* Initialize Link Control Register */
-	if (pcie_cap_has_lnkctl(dev))
+	if (pcie_cap_has_lnkctl(dev)) {
+
+		/*
+		 * If the Root Port supports Read Completion Boundary of
+		 * 128, set RCB to 128.  Otherwise, clear it.
+		 */
+		hpp->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB;
+		hpp->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB;
+		if (pcie_root_rcb_set(dev))
+			hpp->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB;
+
 		pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
 			~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or);
+	}
 
 	/* Find Advanced Error Reporting Enhanced Capability */
 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
@@ -2090,7 +2185,9 @@
 	b->sysdata = sysdata;
 	b->ops = ops;
 	b->number = b->busn_res.start = bus;
-	pci_bus_assign_domain_nr(b, parent);
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+	b->domain_nr = pci_bus_find_domain_nr(b, parent);
+#endif
 	b2 = pci_find_bus(pci_domain_nr(b), bus);
 	if (b2) {
 		/* If we already got to this bus through a different bridge, ignore it */
--- linux-4.4.0.orig/drivers/pci/proc.c
+++ linux-4.4.0/drivers/pci/proc.c
@@ -116,6 +116,9 @@
 	int size = dev->cfg_size;
 	int cnt;
 
+	if (secure_modules())
+		return -EPERM;
+
 	if (pos >= size)
 		return 0;
 	if (nbytes >= size)
@@ -195,6 +198,9 @@
 #endif /* HAVE_PCI_MMAP */
 	int ret = 0;
 
+	if (secure_modules())
+		return -EPERM;
+
 	switch (cmd) {
 	case PCIIOC_CONTROLLER:
 		ret = pci_domain_nr(dev->bus);
@@ -233,7 +239,7 @@
 	struct pci_filp_private *fpriv = file->private_data;
 	int i, ret;
 
-	if (!capable(CAP_SYS_RAWIO))
+	if (!capable(CAP_SYS_RAWIO) || secure_modules())
 		return -EPERM;
 
 	/* Make sure the caller is mapping a real resource for this device */
--- linux-4.4.0.orig/drivers/pci/quirks.c
+++ linux-4.4.0/drivers/pci/quirks.c
@@ -41,6 +41,21 @@
 DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
 				PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
 
+/* The BAR0 ~ BAR4 of Marvell 9125 device can't be accessed
+*  by IO resource file, and need to skip the files
+*/
+static void quirk_marvell_mask_bar(struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < 5; i++)
+		if (dev->resource[i].start)
+			dev->resource[i].start =
+				dev->resource[i].end = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9125,
+				quirk_marvell_mask_bar);
+
 /* The Mellanox Tavor device gives false positive parity errors
  * Mark this device with a broken_parity_status, to allow
  * PCI scanning code to "skip" this now blacklisted device.
@@ -287,6 +302,18 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_CITRINE,	quirk_citrine);
 
+/*
+ * This chip can cause bus lockups if config addresses above 0x600
+ * are read or written.
+ */
+static void quirk_nfp6000(struct pci_dev *dev)
+{
+	dev->cfg_size = 0x600;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME,	PCI_DEVICE_ID_NETRONOME_NFP4000,	quirk_nfp6000);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME,	PCI_DEVICE_ID_NETRONOME_NFP6000,	quirk_nfp6000);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME,	PCI_DEVICE_ID_NETRONOME_NFP6000_VF,	quirk_nfp6000);
+
 /*  On IBM Crocodile ipr SAS adapters, expand BAR to system page size */
 static void quirk_extend_bar_to_page(struct pci_dev *dev)
 {
@@ -1612,6 +1639,7 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7320_MCH,	quirk_pcie_mch);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7525_MCH,	quirk_pcie_mch);
 
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_HUAWEI, 0x1610, PCI_CLASS_BRIDGE_PCI, 8, quirk_pcie_mch);
 
 /*
  * It's possible for the MSI to get corrupted if shpc and acpi
@@ -2260,6 +2288,19 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0xa238, quirk_disable_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x5a3f, quirk_disable_msi);
 
+static void quirk_disable_aspm_l0s_l1(struct pci_dev *dev)
+{
+	dev_info(&dev->dev, "Disabling ASPM L0s/L1\n");
+	pci_disable_link_state(dev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+}
+
+/*
+ * ASM1083/1085 PCIe-PCI bridge devices cause AER timeout errors on the
+ * upstream PCIe root port when ASPM is enabled. At least L0s mode is affected;
+ * disable both L0s and L1 for now to be safe.
+ */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASMEDIA, 0x1080, quirk_disable_aspm_l0s_l1);
+
 /*
  * The APC bridge device in AMD 780 family northbridges has some random
  * OEM subsystem ID in its vendor ID register (erratum 18), so instead
@@ -2735,6 +2776,26 @@
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HINT, 0x0020, quirk_hotplug_bridge);
 
 /*
+ * Apple: Avoid programming the memory/io aperture of 00:1c.0
+ *
+ * BIOS does not declare any resource for 00:1c.0, but with
+ * hotplug flag set, thus the OS allocates:
+ * [mem 0x7fa00000 - 0x7fbfffff]
+ * [mem 0x7fc00000-0x7fdfffff 64bit pref]
+ * which is conflict with an unreported device, which
+ * causes unpredictable result such as accessing io port.
+ * So clear the hotplug flag to work around it.
+ */
+static void quirk_apple_mbp_poweroff(struct pci_dev *dev)
+{
+	if (dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,4") ||
+	    dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,5"))
+		dev->is_hotplug_bridge = 0;
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8c10, quirk_apple_mbp_poweroff);
+
+/*
  * This is a quirk for the Ricoh MMC controller found as a part of
  * some mulifunction chips.
 
@@ -3049,7 +3110,11 @@
 
 	pci_iounmap(dev, regs);
 }
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0042, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0046, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x004a, disable_igfx_irq);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0106, disable_igfx_irq);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
 
@@ -3115,13 +3180,17 @@
 }
 
 /*
- * Atheros AR93xx chips do not behave after a bus reset.  The device will
- * throw a Link Down error on AER-capable systems and regardless of AER,
- * config space of the device is never accessible again and typically
- * causes the system to hang or reset when access is attempted.
+ * Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
+ * The device will throw a Link Down error on AER-capable systems and
+ * regardless of AER, config space of the device is never accessible again
+ * and typically causes the system to hang or reset when access is attempted.
  * http://www.spinics.net/lists/linux-pci/msg34797.html
  */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset);
 
 static void quirk_no_pm_reset(struct pci_dev *dev)
 {
@@ -3599,9 +3668,13 @@
 			 quirk_dma_func1_alias);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9123,
 			 quirk_dma_func1_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9128,
+			 quirk_dma_func1_alias);
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9130,
 			 quirk_dma_func1_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9170,
+			 quirk_dma_func1_alias);
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c47 + c57 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9172,
 			 quirk_dma_func1_alias);
@@ -3611,11 +3684,19 @@
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0,
 			 quirk_dma_func1_alias);
+/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c135 */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9215,
+			 quirk_dma_func1_alias);
+/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c127 */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9220,
+			 quirk_dma_func1_alias);
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c49 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230,
 			 quirk_dma_func1_alias);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0642,
 			 quirk_dma_func1_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0645,
+			 quirk_dma_func1_alias);
 /* https://bugs.gentoo.org/show_bug.cgi?id=497630 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON,
 			 PCI_DEVICE_ID_JMICRON_JMB388_ESD,
@@ -4009,7 +4090,7 @@
 #define INTEL_BSPR_REG_BPPD  (1 << 9)
 
 /* Upstream Peer Decode Configuration Register */
-#define INTEL_UPDCR_REG 0x1114
+#define INTEL_UPDCR_REG 0x1014
 /* 5:0 Peer Decode Enable bits */
 #define INTEL_UPDCR_REG_MASK 0x3f
 
--- linux-4.4.0.orig/drivers/pci/remove.c
+++ linux-4.4.0/drivers/pci/remove.c
@@ -20,9 +20,9 @@
 	pci_pme_active(dev, false);
 
 	if (dev->is_added) {
+		device_release_driver(&dev->dev);
 		pci_proc_detach_device(dev);
 		pci_remove_sysfs_dev_files(dev);
-		device_release_driver(&dev->dev);
 		dev->is_added = 0;
 	}
 
--- linux-4.4.0.orig/drivers/pci/rom.c
+++ linux-4.4.0/drivers/pci/rom.c
@@ -31,6 +31,11 @@
 	if (!res->flags)
 		return -1;
 
+	/*
+	 * Ideally pci_update_resource() would update the ROM BAR address,
+	 * and we would only set the enable bit here.  But apparently some
+	 * devices have buggy ROM BARs that read as zero when disabled.
+	 */
 	pcibios_resource_to_bus(pdev->bus, &region, res);
 	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
 	rom_addr &= ~PCI_ROM_ADDRESS_MASK;
--- linux-4.4.0.orig/drivers/pci/setup-bus.c
+++ linux-4.4.0/drivers/pci/setup-bus.c
@@ -1760,12 +1760,18 @@
 	/* restore size and flags */
 	list_for_each_entry(fail_res, &fail_head, list) {
 		struct resource *res = fail_res->res;
+		int idx;
 
 		res->start = fail_res->start;
 		res->end = fail_res->end;
 		res->flags = fail_res->flags;
-		if (fail_res->dev->subordinate)
-			res->flags = 0;
+
+		if (pci_is_bridge(fail_res->dev)) {
+			idx = res - &fail_res->dev->resource[0];
+			if (idx >= PCI_BRIDGE_RESOURCES &&
+			    idx <= PCI_BRIDGE_RESOURCE_END)
+				res->flags = 0;
+		}
 	}
 	free_list(&fail_head);
 
@@ -1826,12 +1832,18 @@
 	/* restore size and flags */
 	list_for_each_entry(fail_res, &fail_head, list) {
 		struct resource *res = fail_res->res;
+		int idx;
 
 		res->start = fail_res->start;
 		res->end = fail_res->end;
 		res->flags = fail_res->flags;
-		if (fail_res->dev->subordinate)
-			res->flags = 0;
+
+		if (pci_is_bridge(fail_res->dev)) {
+			idx = res - &fail_res->dev->resource[0];
+			if (idx >= PCI_BRIDGE_RESOURCES &&
+			    idx <= PCI_BRIDGE_RESOURCE_END)
+				res->flags = 0;
+		}
 	}
 	free_list(&fail_head);
 
--- linux-4.4.0.orig/drivers/pci/setup-res.c
+++ linux-4.4.0/drivers/pci/setup-res.c
@@ -25,21 +25,18 @@
 #include <linux/slab.h>
 #include "pci.h"
 
-
-void pci_update_resource(struct pci_dev *dev, int resno)
+static void pci_std_update_resource(struct pci_dev *dev, int resno)
 {
 	struct pci_bus_region region;
 	bool disable;
 	u16 cmd;
 	u32 new, check, mask;
 	int reg;
-	enum pci_bar_type type;
 	struct resource *res = dev->resource + resno;
 
-	if (dev->is_virtfn) {
-		dev_warn(&dev->dev, "can't update VF BAR%d\n", resno);
+	/* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */
+	if (dev->is_virtfn)
 		return;
-	}
 
 	/*
 	 * Ignore resources for unimplemented BARs and unused resource slots
@@ -60,21 +57,34 @@
 		return;
 
 	pcibios_resource_to_bus(dev->bus, &region, res);
+	new = region.start;
 
-	new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
-	if (res->flags & IORESOURCE_IO)
+	if (res->flags & IORESOURCE_IO) {
 		mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
-	else
+		new |= res->flags & ~PCI_BASE_ADDRESS_IO_MASK;
+	} else if (resno == PCI_ROM_RESOURCE) {
+		mask = PCI_ROM_ADDRESS_MASK;
+	} else {
 		mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
+		new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
+	}
 
-	reg = pci_resource_bar(dev, resno, &type);
-	if (!reg)
-		return;
-	if (type != pci_bar_unknown) {
+	if (resno < PCI_ROM_RESOURCE) {
+		reg = PCI_BASE_ADDRESS_0 + 4 * resno;
+	} else if (resno == PCI_ROM_RESOURCE) {
+
+		/*
+		 * Apparently some Matrox devices have ROM BARs that read
+		 * as zero when disabled, so don't update ROM BARs unless
+		 * they're enabled.  See https://lkml.org/lkml/2005/8/30/138.
+		 */
 		if (!(res->flags & IORESOURCE_ROM_ENABLE))
 			return;
+
+		reg = dev->rom_base_reg;
 		new |= PCI_ROM_ADDRESS_ENABLE;
-	}
+	} else
+		return;
 
 	/*
 	 * We can't update a 64-bit BAR atomically, so when possible,
@@ -110,6 +120,16 @@
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 }
 
+void pci_update_resource(struct pci_dev *dev, int resno)
+{
+	if (resno <= PCI_ROM_RESOURCE)
+		pci_std_update_resource(dev, resno);
+#ifdef CONFIG_PCI_IOV
+	else if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
+		pci_iov_update_resource(dev, resno);
+#endif
+}
+
 int pci_claim_resource(struct pci_dev *dev, int resource)
 {
 	struct resource *res = &dev->resource[resource];
--- linux-4.4.0.orig/drivers/pci/slot.c
+++ linux-4.4.0/drivers/pci/slot.c
@@ -303,16 +303,19 @@
 	slot_name = make_slot_name(name);
 	if (!slot_name) {
 		err = -ENOMEM;
+		kfree(slot);
 		goto err;
 	}
 
+	INIT_LIST_HEAD(&slot->list);
+	list_add(&slot->list, &parent->slots);
+
 	err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
 				   "%s", slot_name);
-	if (err)
+	if (err) {
+		kobject_put(&slot->kobj);
 		goto err;
-
-	INIT_LIST_HEAD(&slot->list);
-	list_add(&slot->list, &parent->slots);
+	}
 
 	down_read(&pci_bus_sem);
 	list_for_each_entry(dev, &parent->devices, bus_list)
@@ -328,7 +331,6 @@
 	mutex_unlock(&pci_slot_mutex);
 	return slot;
 err:
-	kfree(slot);
 	slot = ERR_PTR(err);
 	goto out;
 }
--- linux-4.4.0.orig/drivers/pci/syscall.c
+++ linux-4.4.0/drivers/pci/syscall.c
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/pci.h>
 #include <linux/syscalls.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 #include "pci.h"
 
@@ -21,7 +22,7 @@
 	u16 word;
 	u32 dword;
 	long err;
-	long cfg_ret;
+	int cfg_ret;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -47,7 +48,7 @@
 	}
 
 	err = -EIO;
-	if (cfg_ret != PCIBIOS_SUCCESSFUL)
+	if (cfg_ret)
 		goto error;
 
 	switch (len) {
@@ -92,7 +93,7 @@
 	u32 dword;
 	int err = 0;
 
-	if (!capable(CAP_SYS_ADMIN))
+	if (!capable(CAP_SYS_ADMIN) || secure_modules())
 		return -EPERM;
 
 	dev = pci_get_bus_and_slot(bus, dfn);
@@ -105,7 +106,7 @@
 		if (err)
 			break;
 		err = pci_user_write_config_byte(dev, off, byte);
-		if (err != PCIBIOS_SUCCESSFUL)
+		if (err)
 			err = -EIO;
 		break;
 
@@ -114,7 +115,7 @@
 		if (err)
 			break;
 		err = pci_user_write_config_word(dev, off, word);
-		if (err != PCIBIOS_SUCCESSFUL)
+		if (err)
 			err = -EIO;
 		break;
 
@@ -123,7 +124,7 @@
 		if (err)
 			break;
 		err = pci_user_write_config_dword(dev, off, dword);
-		if (err != PCIBIOS_SUCCESSFUL)
+		if (err)
 			err = -EIO;
 		break;
 
--- linux-4.4.0.orig/drivers/pci/xen-pcifront.c
+++ linux-4.4.0/drivers/pci/xen-pcifront.c
@@ -53,7 +53,7 @@
 };
 
 struct pcifront_sd {
-	int domain;
+	struct pci_sysdata sd;
 	struct pcifront_device *pdev;
 };
 
@@ -67,7 +67,9 @@
 				    unsigned int domain, unsigned int bus,
 				    struct pcifront_device *pdev)
 {
-	sd->domain = domain;
+	/* Because we do not expose that information via XenBus. */
+	sd->sd.node = first_online_node;
+	sd->sd.domain = domain;
 	sd->pdev = pdev;
 }
 
@@ -468,8 +470,8 @@
 	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
 		 domain, bus);
 
-	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
-	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	bus_entry = kzalloc(sizeof(*bus_entry), GFP_KERNEL);
+	sd = kzalloc(sizeof(*sd), GFP_KERNEL);
 	if (!bus_entry || !sd) {
 		err = -ENOMEM;
 		goto err_out;
--- linux-4.4.0.orig/drivers/pcmcia/cistpl.c
+++ linux-4.4.0/drivers/pcmcia/cistpl.c
@@ -1578,6 +1578,9 @@
 	struct pcmcia_socket *s;
 	int error;
 
+	if (secure_modules())
+		return -EPERM;
+
 	s = to_socket(container_of(kobj, struct device, kobj));
 
 	if (off)
--- linux-4.4.0.orig/drivers/pcmcia/db1xxx_ss.c
+++ linux-4.4.0/drivers/pcmcia/db1xxx_ss.c
@@ -56,6 +56,7 @@
 	int	stschg_irq;	/* card-status-change irq */
 	int	card_irq;	/* card irq */
 	int	eject_irq;	/* db1200/pb1200 have these */
+	int	insert_gpio;	/* db1000 carddetect gpio */
 
 #define BOARD_TYPE_DEFAULT	0	/* most boards */
 #define BOARD_TYPE_DB1200	1	/* IRQs aren't gpios */
@@ -83,7 +84,7 @@
 /* carddetect gpio: low-active */
 static int db1000_card_inserted(struct db1x_pcmcia_sock *sock)
 {
-	return !gpio_get_value(irq_to_gpio(sock->insert_irq));
+	return !gpio_get_value(sock->insert_gpio);
 }
 
 static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
@@ -457,9 +458,15 @@
 	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "card");
 	sock->card_irq = r ? r->start : 0;
 
-	/* insert: irq which triggers on card insertion/ejection */
+	/* insert: irq which triggers on card insertion/ejection
+	 * BIG FAT NOTE: on DB1000/1100/1500/1550 we pass a GPIO here!
+	 */
 	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "insert");
 	sock->insert_irq = r ? r->start : -1;
+	if (sock->board_type == BOARD_TYPE_DEFAULT) {
+		sock->insert_gpio = r ? r->start : -1;
+		sock->insert_irq = r ? gpio_to_irq(r->start) : -1;
+	}
 
 	/* stschg: irq which trigger on card status change (optional) */
 	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "stschg");
--- linux-4.4.0.orig/drivers/pcmcia/i82365.c
+++ linux-4.4.0/drivers/pcmcia/i82365.c
@@ -108,12 +108,12 @@
 static int cable_mode = -1;
 static int wakeup = 0;
 
-module_param(i365_base, ulong, 0444);
+module_param_hw(i365_base, ulong, ioport, 0444);
 module_param(ignore, int, 0444);
 module_param(extra_sockets, int, 0444);
-module_param(irq_mask, int, 0444);
-module_param_array(irq_list, int, &irq_list_count, 0444);
-module_param(cs_irq, int, 0444);
+module_param_hw(irq_mask, int, other, 0444);
+module_param_hw_array(irq_list, int, irq, &irq_list_count, 0444);
+module_param_hw(cs_irq, int, irq, 0444);
 module_param(async_clock, int, 0444);
 module_param(cable_mode, int, 0444);
 module_param(wakeup, int, 0444);
--- linux-4.4.0.orig/drivers/pcmcia/ricoh.h
+++ linux-4.4.0/drivers/pcmcia/ricoh.h
@@ -119,6 +119,10 @@
 #define  RL5C4XX_MISC_CONTROL           0x2F /* 8 bit */
 #define  RL5C4XX_ZV_ENABLE              0x08
 
+/* Misc Control 3 Register */
+#define RL5C4XX_MISC3			0x00A2 /* 16 bit */
+#define  RL5C47X_MISC3_CB_CLKRUN_DIS	BIT(1)
+
 #ifdef __YENTA_H
 
 #define rl_misc(socket)		((socket)->private[0])
@@ -156,6 +160,35 @@
         }
 }
 
+static void ricoh_set_clkrun(struct yenta_socket *socket, bool quiet)
+{
+	u16 misc3;
+
+	/*
+	 * RL5C475II likely has this setting, too, however no datasheet
+	 * is publicly available for this chip
+	 */
+	if (socket->dev->device != PCI_DEVICE_ID_RICOH_RL5C476 &&
+	    socket->dev->device != PCI_DEVICE_ID_RICOH_RL5C478)
+		return;
+
+	if (socket->dev->revision < 0x80)
+		return;
+
+	misc3 = config_readw(socket, RL5C4XX_MISC3);
+	if (misc3 & RL5C47X_MISC3_CB_CLKRUN_DIS) {
+		if (!quiet)
+			dev_dbg(&socket->dev->dev,
+				"CLKRUN feature already disabled\n");
+	} else if (disable_clkrun) {
+		if (!quiet)
+			dev_info(&socket->dev->dev,
+				 "Disabling CLKRUN feature\n");
+		misc3 |= RL5C47X_MISC3_CB_CLKRUN_DIS;
+		config_writew(socket, RL5C4XX_MISC3, misc3);
+	}
+}
+
 static void ricoh_save_state(struct yenta_socket *socket)
 {
 	rl_misc(socket) = config_readw(socket, RL5C4XX_MISC);
@@ -172,6 +205,7 @@
 	config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
 	config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
 	config_writew(socket, RL5C4XX_CONFIG, rl_config(socket));
+	ricoh_set_clkrun(socket, true);
 }
 
 
@@ -197,6 +231,7 @@
 	config_writew(socket, RL5C4XX_CONFIG, config);
 
 	ricoh_set_zv(socket);
+	ricoh_set_clkrun(socket, false);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/pcmcia/tcic.c
+++ linux-4.4.0/drivers/pcmcia/tcic.c
@@ -85,12 +85,12 @@
 /* CCLK external clock time, in nanoseconds.  70 ns = 14.31818 MHz */
 static int cycle_time = 70;
 
-module_param(tcic_base, ulong, 0444);
+module_param_hw(tcic_base, ulong, ioport, 0444);
 module_param(ignore, int, 0444);
 module_param(do_scan, int, 0444);
-module_param(irq_mask, int, 0444);
-module_param_array(irq_list, int, &irq_list_count, 0444);
-module_param(cs_irq, int, 0444);
+module_param_hw(irq_mask, int, other, 0444);
+module_param_hw_array(irq_list, int, irq, &irq_list_count, 0444);
+module_param_hw(cs_irq, int, irq, 0444);
 module_param(poll_interval, int, 0444);
 module_param(poll_quick, int, 0444);
 module_param(cycle_time, int, 0444);
--- linux-4.4.0.orig/drivers/pcmcia/yenta_socket.c
+++ linux-4.4.0/drivers/pcmcia/yenta_socket.c
@@ -26,7 +26,8 @@
 
 static bool disable_clkrun;
 module_param(disable_clkrun, bool, 0444);
-MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option");
+MODULE_PARM_DESC(disable_clkrun,
+		 "If PC card doesn't function properly, please try this option (TI and Ricoh bridges only)");
 
 static bool isa_probe = 1;
 module_param(isa_probe, bool, 0444);
--- linux-4.4.0.orig/drivers/perf/arm_pmu.c
+++ linux-4.4.0/drivers/perf/arm_pmu.c
@@ -321,10 +321,16 @@
 	return 0;
 }
 
+static struct arm_pmu_platdata *armpmu_get_platdata(struct arm_pmu *armpmu)
+{
+	struct platform_device *pdev = armpmu->plat_device;
+
+	return pdev ? dev_get_platdata(&pdev->dev) : NULL;
+}
+
 static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
 {
 	struct arm_pmu *armpmu;
-	struct platform_device *plat_device;
 	struct arm_pmu_platdata *plat;
 	int ret;
 	u64 start_clock, finish_clock;
@@ -336,8 +342,8 @@
 	 * dereference.
 	 */
 	armpmu = *(void **)dev;
-	plat_device = armpmu->plat_device;
-	plat = dev_get_platdata(&plat_device->dev);
+
+	plat = armpmu_get_platdata(armpmu);
 
 	start_clock = sched_clock();
 	if (plat && plat->handle_irq)
@@ -551,14 +557,6 @@
 	};
 }
 
-int armpmu_register(struct arm_pmu *armpmu, int type)
-{
-	armpmu_init(armpmu);
-	pr_info("enabled with %s PMU driver, %d counters available\n",
-			armpmu->name, armpmu->num_events);
-	return perf_pmu_register(&armpmu->pmu, armpmu->name, type);
-}
-
 /* Set at runtime when we know what CPU type we are. */
 static struct arm_pmu *__oprofile_cpu_pmu;
 
@@ -815,6 +813,7 @@
 			if (i > 0 && spi != using_spi) {
 				pr_err("PPI/SPI IRQ type mismatch for %s!\n",
 					dn->name);
+				of_node_put(dn);
 				kfree(irqs);
 				return -EINVAL;
 			}
@@ -887,6 +886,8 @@
 		return -ENOMEM;
 	}
 
+	armpmu_init(pmu);
+
 	if (!__oprofile_cpu_pmu)
 		__oprofile_cpu_pmu = pmu;
 
@@ -912,10 +913,13 @@
 	if (ret)
 		goto out_free;
 
-	ret = armpmu_register(pmu, -1);
+	ret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
 	if (ret)
 		goto out_destroy;
 
+	pr_info("enabled with %s PMU driver, %d counters available\n",
+			pmu->name, pmu->num_events);
+
 	return 0;
 
 out_destroy:
--- linux-4.4.0.orig/drivers/phy/Kconfig
+++ linux-4.4.0/drivers/phy/Kconfig
@@ -368,6 +368,7 @@
 config PHY_TUSB1210
 	tristate "TI TUSB1210 ULPI PHY module"
 	depends on USB_ULPI_BUS
+	depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in
 	select GENERIC_PHY
 	help
 	  Support for TI TUSB1210 USB ULPI PHY.
--- linux-4.4.0.orig/drivers/phy/phy-core.c
+++ linux-4.4.0/drivers/phy/phy-core.c
@@ -275,20 +275,21 @@
 
 int phy_power_on(struct phy *phy)
 {
-	int ret;
+	int ret = 0;
 
 	if (!phy)
-		return 0;
+		goto out;
 
 	if (phy->pwr) {
 		ret = regulator_enable(phy->pwr);
 		if (ret)
-			return ret;
+			goto out;
 	}
 
 	ret = phy_pm_runtime_get_sync(phy);
 	if (ret < 0 && ret != -ENOTSUPP)
-		return ret;
+		goto err_pm_sync;
+
 	ret = 0; /* Override possible ret == -ENOTSUPP */
 
 	mutex_lock(&phy->mutex);
@@ -296,19 +297,20 @@
 		ret = phy->ops->power_on(phy);
 		if (ret < 0) {
 			dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
-			goto out;
+			goto err_pwr_on;
 		}
 	}
 	++phy->power_count;
 	mutex_unlock(&phy->mutex);
 	return 0;
 
-out:
+err_pwr_on:
 	mutex_unlock(&phy->mutex);
 	phy_pm_runtime_put_sync(phy);
+err_pm_sync:
 	if (phy->pwr)
 		regulator_disable(phy->pwr);
-
+out:
 	return ret;
 }
 EXPORT_SYMBOL_GPL(phy_power_on);
@@ -363,6 +365,10 @@
 	if (ret)
 		return ERR_PTR(-ENODEV);
 
+	/* This phy type handled by the usb-phy subsystem for now */
+	if (of_device_is_compatible(args.np, "usb-nop-xceiv"))
+		return ERR_PTR(-ENODEV);
+
 	mutex_lock(&phy_provider_mutex);
 	phy_provider = of_phy_provider_lookup(args.np);
 	if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) {
--- linux-4.4.0.orig/drivers/phy/phy-omap-usb2.c
+++ linux-4.4.0/drivers/phy/phy-omap-usb2.c
@@ -62,7 +62,7 @@
 {
 	struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
 
-	if (!phy->comparator)
+	if (!phy->comparator || !phy->comparator->set_vbus)
 		return -ENODEV;
 
 	return phy->comparator->set_vbus(phy->comparator, enabled);
@@ -72,7 +72,7 @@
 {
 	struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
 
-	if (!phy->comparator)
+	if (!phy->comparator || !phy->comparator->start_srp)
 		return -ENODEV;
 
 	return phy->comparator->start_srp(phy->comparator);
--- linux-4.4.0.orig/drivers/phy/phy-rcar-gen2.c
+++ linux-4.4.0/drivers/phy/phy-rcar-gen2.c
@@ -287,6 +287,7 @@
 		error = of_property_read_u32(np, "reg", &channel_num);
 		if (error || channel_num > 2) {
 			dev_err(dev, "Invalid \"reg\" property\n");
+			of_node_put(np);
 			return error;
 		}
 		channel->select_mask = select_mask[channel_num];
@@ -302,6 +303,7 @@
 						   &rcar_gen2_phy_ops);
 			if (IS_ERR(phy->phy)) {
 				dev_err(dev, "Failed to create PHY\n");
+				of_node_put(np);
 				return PTR_ERR(phy->phy);
 			}
 			phy_set_drvdata(phy->phy, phy);
--- linux-4.4.0.orig/drivers/phy/phy-s5pv210-usb2.c
+++ linux-4.4.0/drivers/phy/phy-s5pv210-usb2.c
@@ -142,6 +142,10 @@
 		udelay(10);
 		rst &= ~rstbits;
 		writel(rst, drv->reg_phy + S5PV210_UPHYRST);
+		/* The following delay is necessary for the reset sequence to be
+		 * completed
+		 */
+		udelay(80);
 	} else {
 		pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
 		pwr |= phypwr;
--- linux-4.4.0.orig/drivers/phy/phy-twl4030-usb.c
+++ linux-4.4.0/drivers/phy/phy-twl4030-usb.c
@@ -715,6 +715,7 @@
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
 	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
 
 	/* Our job is to use irqs and status from the power module
 	 * to keep the transceiver disabled when nothing's connected.
@@ -750,6 +751,7 @@
 	struct twl4030_usb *twl = platform_get_drvdata(pdev);
 	int val;
 
+	usb_remove_phy(&twl->phy);
 	pm_runtime_get_sync(twl->dev);
 	cancel_delayed_work(&twl->id_workaround_work);
 	device_remove_file(twl->dev, &dev_attr_vbus);
@@ -757,6 +759,13 @@
 	/* set transceiver mode to power on defaults */
 	twl4030_usb_set_mode(twl, -1);
 
+	/* idle ulpi before powering off */
+	if (cable_present(twl->linkstat))
+		pm_runtime_put_noidle(twl->dev);
+	pm_runtime_mark_last_busy(twl->dev);
+	pm_runtime_put_sync_suspend(twl->dev);
+	pm_runtime_disable(twl->dev);
+
 	/* autogate 60MHz ULPI clock,
 	 * clear dpll clock request for i2c access,
 	 * disable 32KHz
@@ -771,11 +780,6 @@
 	/* disable complete OTG block */
 	twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
 
-	if (cable_present(twl->linkstat))
-		pm_runtime_put_noidle(twl->dev);
-	pm_runtime_mark_last_busy(twl->dev);
-	pm_runtime_put(twl->dev);
-
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/pinctrl/Kconfig
+++ linux-4.4.0/drivers/pinctrl/Kconfig
@@ -26,7 +26,8 @@
 
 config PINCTRL_ADI2
 	bool "ADI pin controller driver"
-	depends on BLACKFIN
+	depends on (BF54x || BF60x)
+	depends on !GPIO_ADI
 	select PINMUX
 	select IRQ_DOMAIN
 	help
--- linux-4.4.0.orig/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ linux-4.4.0/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -779,7 +779,7 @@
 		}
 		if (num_pulls) {
 			err = of_property_read_u32_index(np, "brcm,pull",
-					(num_funcs > 1) ? i : 0, &pull);
+					(num_pulls > 1) ? i : 0, &pull);
 			if (err)
 				goto out;
 			err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin,
@@ -795,7 +795,7 @@
 	return 0;
 
 out:
-	kfree(maps);
+	bcm2835_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin);
 	return err;
 }
 
--- linux-4.4.0.orig/drivers/pinctrl/berlin/berlin-bg4ct.c
+++ linux-4.4.0/drivers/pinctrl/berlin/berlin-bg4ct.c
@@ -217,7 +217,7 @@
 	BERLIN_PINCTRL_GROUP("SCRD0_CRD_PRES", 0xc, 0x3, 0x15,
 			BERLIN_PINCTRL_FUNCTION(0x0, "gpio"), /* GPIO20 */
 			BERLIN_PINCTRL_FUNCTION(0x1, "scrd0"), /* crd pres */
-			BERLIN_PINCTRL_FUNCTION(0x1, "sd1a")), /* DAT3 */
+			BERLIN_PINCTRL_FUNCTION(0x3, "sd1a")), /* DAT3 */
 	BERLIN_PINCTRL_GROUP("SPI1_SS0n", 0xc, 0x3, 0x18,
 			BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS0n */
 			BERLIN_PINCTRL_FUNCTION(0x1, "gpio"), /* GPIO37 */
--- linux-4.4.0.orig/drivers/pinctrl/core.c
+++ linux-4.4.0/drivers/pinctrl/core.c
@@ -840,8 +840,8 @@
 		 * an -EPROBE_DEFER later, as that is the worst case.
 		 */
 		if (ret == -EPROBE_DEFER) {
-			pinctrl_free(p, false);
 			mutex_unlock(&pinctrl_maps_mutex);
+			pinctrl_free(p, false);
 			return ERR_PTR(ret);
 		}
 	}
@@ -979,19 +979,16 @@
 EXPORT_SYMBOL_GPL(pinctrl_lookup_state);
 
 /**
- * pinctrl_select_state() - select/activate/program a pinctrl state to HW
+ * pinctrl_commit_state() - select/activate/program a pinctrl state to HW
  * @p: the pinctrl handle for the device that requests configuration
  * @state: the state handle to select/activate/program
  */
-int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
+static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
 {
 	struct pinctrl_setting *setting, *setting2;
 	struct pinctrl_state *old_state = p->state;
 	int ret;
 
-	if (p->state == state)
-		return 0;
-
 	if (p->state) {
 		/*
 		 * For each pinmux setting in the old state, forget SW's record
@@ -1055,6 +1052,19 @@
 
 	return ret;
 }
+
+/**
+ * pinctrl_select_state() - select/activate/program a pinctrl state to HW
+ * @p: the pinctrl handle for the device that requests configuration
+ * @state: the state handle to select/activate/program
+ */
+int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
+{
+	if (p->state == state)
+		return 0;
+
+	return pinctrl_commit_state(p, state);
+}
 EXPORT_SYMBOL_GPL(pinctrl_select_state);
 
 static void devm_pinctrl_release(struct device *dev, void *res)
@@ -1223,7 +1233,7 @@
 int pinctrl_force_sleep(struct pinctrl_dev *pctldev)
 {
 	if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_sleep))
-		return pinctrl_select_state(pctldev->p, pctldev->hog_sleep);
+		return pinctrl_commit_state(pctldev->p, pctldev->hog_sleep);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pinctrl_force_sleep);
@@ -1235,7 +1245,7 @@
 int pinctrl_force_default(struct pinctrl_dev *pctldev)
 {
 	if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_default))
-		return pinctrl_select_state(pctldev->p, pctldev->hog_default);
+		return pinctrl_commit_state(pctldev->p, pctldev->hog_default);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pinctrl_force_default);
@@ -1861,6 +1871,69 @@
 }
 EXPORT_SYMBOL_GPL(pinctrl_unregister);
 
+static void devm_pinctrl_dev_release(struct device *dev, void *res)
+{
+	struct pinctrl_dev *pctldev = *(struct pinctrl_dev **)res;
+
+	pinctrl_unregister(pctldev);
+}
+
+static int devm_pinctrl_dev_match(struct device *dev, void *res, void *data)
+{
+	struct pctldev **r = res;
+
+	if (WARN_ON(!r || !*r))
+		return 0;
+
+	return *r == data;
+}
+
+/**
+ * devm_pinctrl_register() - Resource managed version of pinctrl_register().
+ * @dev: parent device for this pin controller
+ * @pctldesc: descriptor for this pin controller
+ * @driver_data: private pin controller data for this pin controller
+ *
+ * Returns an error pointer if pincontrol register failed. Otherwise
+ * it returns valid pinctrl handle.
+ *
+ * The pinctrl device will be automatically released when the device is unbound.
+ */
+struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
+					  struct pinctrl_desc *pctldesc,
+					  void *driver_data)
+{
+	struct pinctrl_dev **ptr, *pctldev;
+
+	ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	pctldev = pinctrl_register(pctldesc, dev, driver_data);
+	if (IS_ERR(pctldev)) {
+		devres_free(ptr);
+		return pctldev;
+	}
+
+	*ptr = pctldev;
+	devres_add(dev, ptr);
+
+	return pctldev;
+}
+EXPORT_SYMBOL_GPL(devm_pinctrl_register);
+
+/**
+ * devm_pinctrl_unregister() - Resource managed version of pinctrl_unregister().
+ * @dev: device for which which resource was allocated
+ * @pctldev: the pinctrl device to unregister.
+ */
+void devm_pinctrl_unregister(struct device *dev, struct pinctrl_dev *pctldev)
+{
+	WARN_ON(devres_release(dev, devm_pinctrl_dev_release,
+			       devm_pinctrl_dev_match, pctldev));
+}
+EXPORT_SYMBOL_GPL(devm_pinctrl_unregister);
+
 static int __init pinctrl_init(void)
 {
 	pr_info("initialized pinctrl subsystem\n");
--- linux-4.4.0.orig/drivers/pinctrl/devicetree.c
+++ linux-4.4.0/drivers/pinctrl/devicetree.c
@@ -40,6 +40,13 @@
 static void dt_free_map(struct pinctrl_dev *pctldev,
 		     struct pinctrl_map *map, unsigned num_maps)
 {
+	int i;
+
+	for (i = 0; i < num_maps; ++i) {
+		kfree_const(map[i].dev_name);
+		map[i].dev_name = NULL;
+	}
+
 	if (pctldev) {
 		const struct pinctrl_ops *ops = pctldev->desc->pctlops;
 		ops->dt_free_map(pctldev, map, num_maps);
@@ -73,7 +80,13 @@
 
 	/* Initialize common mapping table entry fields */
 	for (i = 0; i < num_maps; i++) {
-		map[i].dev_name = dev_name(p->dev);
+		const char *devname;
+
+		devname = kstrdup_const(dev_name(p->dev), GFP_KERNEL);
+		if (!devname)
+			goto err_free_map;
+
+		map[i].dev_name = devname;
 		map[i].name = statename;
 		if (pctldev)
 			map[i].ctrl_dev_name = dev_name(pctldev->dev);
@@ -83,8 +96,7 @@
 	dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
 	if (!dt_map) {
 		dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");
-		dt_free_map(pctldev, map, num_maps);
-		return -ENOMEM;
+		goto err_free_map;
 	}
 
 	dt_map->pctldev = pctldev;
@@ -93,6 +105,10 @@
 	list_add_tail(&dt_map->node, &p->dt_maps);
 
 	return pinctrl_register_map(map, num_maps, false);
+
+err_free_map:
+	dt_free_map(pctldev, map, num_maps);
+	return -ENOMEM;
 }
 
 struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
--- linux-4.4.0.orig/drivers/pinctrl/freescale/pinctrl-imx.c
+++ linux-4.4.0/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -207,9 +207,9 @@
 		pin_reg = &info->pin_regs[pin_id];
 
 		if (pin_reg->mux_reg == -1) {
-			dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
+			dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n",
 				info->pins[pin_id].name);
-			return -EINVAL;
+			continue;
 		}
 
 		if (info->flags & SHARE_MUX_CONF_REG) {
@@ -726,19 +726,18 @@
 
 	if (of_property_read_bool(dev_np, "fsl,input-sel")) {
 		np = of_parse_phandle(dev_np, "fsl,input-sel", 0);
-		if (np) {
-			ipctl->input_sel_base = of_iomap(np, 0);
-			if (IS_ERR(ipctl->input_sel_base)) {
-				of_node_put(np);
-				dev_err(&pdev->dev,
-					"iomuxc input select base address not found\n");
-				return PTR_ERR(ipctl->input_sel_base);
-			}
-		} else {
+		if (!np) {
 			dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n");
 			return -EINVAL;
 		}
+
+		ipctl->input_sel_base = of_iomap(np, 0);
 		of_node_put(np);
+		if (!ipctl->input_sel_base) {
+			dev_err(&pdev->dev,
+				"iomuxc input select base address not found\n");
+			return -ENOMEM;
+		}
 	}
 
 	imx_pinctrl_desc.name = dev_name(&pdev->dev);
--- linux-4.4.0.orig/drivers/pinctrl/freescale/pinctrl-imx1-core.c
+++ linux-4.4.0/drivers/pinctrl/freescale/pinctrl-imx1-core.c
@@ -434,7 +434,7 @@
 	const char *name;
 	int i, ret;
 
-	if (group > info->ngroups)
+	if (group >= info->ngroups)
 		return;
 
 	seq_puts(s, "\n");
--- linux-4.4.0.orig/drivers/pinctrl/freescale/pinctrl-mxs.c
+++ linux-4.4.0/drivers/pinctrl/freescale/pinctrl-mxs.c
@@ -195,6 +195,16 @@
 	return 0;
 }
 
+static void mxs_pinctrl_rmwl(u32 value, u32 mask, u8 shift, void __iomem *reg)
+{
+	u32 tmp;
+
+	tmp = readl(reg);
+	tmp &= ~(mask << shift);
+	tmp |= value << shift;
+	writel(tmp, reg);
+}
+
 static int mxs_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
 			       unsigned group)
 {
@@ -212,8 +222,7 @@
 		reg += bank * 0x20 + pin / 16 * 0x10;
 		shift = pin % 16 * 2;
 
-		writel(0x3 << shift, reg + CLR);
-		writel(g->muxsel[i] << shift, reg + SET);
+		mxs_pinctrl_rmwl(g->muxsel[i], 0x3, shift, reg);
 	}
 
 	return 0;
@@ -280,8 +289,7 @@
 			/* mA */
 			if (config & MA_PRESENT) {
 				shift = pin % 8 * 4;
-				writel(0x3 << shift, reg + CLR);
-				writel(ma << shift, reg + SET);
+				mxs_pinctrl_rmwl(ma, 0x3, shift, reg);
 			}
 
 			/* vol */
--- linux-4.4.0.orig/drivers/pinctrl/intel/pinctrl-broxton.c
+++ linux-4.4.0/drivers/pinctrl/intel/pinctrl-broxton.c
@@ -19,7 +19,7 @@
 
 #define BXT_PAD_OWN	0x020
 #define BXT_HOSTSW_OWN	0x080
-#define BXT_PADCFGLOCK	0x090
+#define BXT_PADCFGLOCK	0x060
 #define BXT_GPI_IE	0x110
 
 #define BXT_COMMUNITY(s, e)				\
--- linux-4.4.0.orig/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ linux-4.4.0/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -134,6 +134,7 @@
  * @gpio_ranges: An array of GPIO ranges in this community
  * @ngpio_ranges: Number of GPIO ranges
  * @ngpios: Total number of GPIOs in this community
+ * @nirqs: Total number of IRQs this community can generate
  */
 struct chv_community {
 	const char *uid;
@@ -146,6 +147,7 @@
 	const struct chv_gpio_pinrange *gpio_ranges;
 	size_t ngpio_ranges;
 	size_t ngpios;
+	size_t nirqs;
 };
 
 struct chv_pin_context {
@@ -160,7 +162,6 @@
  * @pctldev: Pointer to the pin controller device
  * @chip: GPIO chip in this pin controller
  * @regs: MMIO registers
- * @lock: Lock to serialize register accesses
  * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO
  *		offset (in GPIO number space)
  * @community: Community this pinctrl instance represents
@@ -174,7 +175,6 @@
 	struct pinctrl_dev *pctldev;
 	struct gpio_chip chip;
 	void __iomem *regs;
-	raw_spinlock_t lock;
 	unsigned intr_lines[16];
 	const struct chv_community *community;
 	u32 saved_intmask;
@@ -400,6 +400,12 @@
 	.gpio_ranges = southwest_gpio_ranges,
 	.ngpio_ranges = ARRAY_SIZE(southwest_gpio_ranges),
 	.ngpios = ARRAY_SIZE(southwest_pins),
+	/*
+	 * Southwest community can benerate GPIO interrupts only for the
+	 * first 8 interrupts. The upper half (8-15) can only be used to
+	 * trigger GPEs.
+	 */
+	.nirqs = 8,
 };
 
 static const struct pinctrl_pin_desc north_pins[] = {
@@ -483,6 +489,12 @@
 	.gpio_ranges = north_gpio_ranges,
 	.ngpio_ranges = ARRAY_SIZE(north_gpio_ranges),
 	.ngpios = ARRAY_SIZE(north_pins),
+	/*
+	 * North community can benerate GPIO interrupts only for the first
+	 * 8 interrupts. The upper half (8-15) can only be used to trigger
+	 * GPEs.
+	 */
+	.nirqs = 8,
 };
 
 static const struct pinctrl_pin_desc east_pins[] = {
@@ -525,6 +537,7 @@
 	.gpio_ranges = east_gpio_ranges,
 	.ngpio_ranges = ARRAY_SIZE(east_gpio_ranges),
 	.ngpios = ARRAY_SIZE(east_pins),
+	.nirqs = 16,
 };
 
 static const struct pinctrl_pin_desc southeast_pins[] = {
@@ -650,6 +663,7 @@
 	.gpio_ranges = southeast_gpio_ranges,
 	.ngpio_ranges = ARRAY_SIZE(southeast_gpio_ranges),
 	.ngpios = ARRAY_SIZE(southeast_pins),
+	.nirqs = 16,
 };
 
 static const struct chv_community *chv_communities[] = {
@@ -659,6 +673,17 @@
 	&southeast_community,
 };
 
+/*
+ * Lock to serialize register accesses
+ *
+ * Due to a silicon issue, a shared lock must be used to prevent
+ * concurrent accesses across the 4 GPIO controllers.
+ *
+ * See Intel Atom Z8000 Processor Series Specification Update (Rev. 005),
+ * errata #CHT34, for further information.
+ */
+static DEFINE_RAW_SPINLOCK(chv_lock);
+
 static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset,
 				unsigned reg)
 {
@@ -720,13 +745,13 @@
 	u32 ctrl0, ctrl1;
 	bool locked;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 
 	ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
 	ctrl1 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL1));
 	locked = chv_pad_locked(pctrl, offset);
 
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	if (ctrl0 & CHV_PADCTRL0_GPIOEN) {
 		seq_puts(s, "GPIO ");
@@ -789,14 +814,14 @@
 
 	grp = &pctrl->community->groups[group];
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 
 	/* Check first that the pad is not locked */
 	for (i = 0; i < grp->npins; i++) {
 		if (chv_pad_locked(pctrl, grp->pins[i])) {
 			dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n",
 				 grp->pins[i]);
-			raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+			raw_spin_unlock_irqrestore(&chv_lock, flags);
 			return -EBUSY;
 		}
 	}
@@ -839,7 +864,7 @@
 			pin, altfunc->mode, altfunc->invert_oe ? "" : "not ");
 	}
 
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	return 0;
 }
@@ -853,13 +878,13 @@
 	void __iomem *reg;
 	u32 value;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 
 	if (chv_pad_locked(pctrl, offset)) {
 		value = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
 		if (!(value & CHV_PADCTRL0_GPIOEN)) {
 			/* Locked so cannot enable */
-			raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+			raw_spin_unlock_irqrestore(&chv_lock, flags);
 			return -EBUSY;
 		}
 	} else {
@@ -899,7 +924,7 @@
 		chv_writel(value, reg);
 	}
 
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	return 0;
 }
@@ -913,13 +938,13 @@
 	void __iomem *reg;
 	u32 value;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 
 	reg = chv_padreg(pctrl, offset, CHV_PADCTRL0);
 	value = readl(reg) & ~CHV_PADCTRL0_GPIOEN;
 	chv_writel(value, reg);
 
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -931,7 +956,7 @@
 	unsigned long flags;
 	u32 ctrl0;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 
 	ctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIOCFG_MASK;
 	if (input)
@@ -940,7 +965,7 @@
 		ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT;
 	chv_writel(ctrl0, reg);
 
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	return 0;
 }
@@ -965,10 +990,10 @@
 	u16 arg = 0;
 	u32 term;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 	ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
 	ctrl1 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1));
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT;
 
@@ -1042,7 +1067,7 @@
 	unsigned long flags;
 	u32 ctrl0, pull;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 	ctrl0 = readl(reg);
 
 	switch (param) {
@@ -1065,7 +1090,7 @@
 			pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
 			break;
 		default:
-			raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+			raw_spin_unlock_irqrestore(&chv_lock, flags);
 			return -EINVAL;
 		}
 
@@ -1083,7 +1108,7 @@
 			pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
 			break;
 		default:
-			raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+			raw_spin_unlock_irqrestore(&chv_lock, flags);
 			return -EINVAL;
 		}
 
@@ -1091,12 +1116,12 @@
 		break;
 
 	default:
-		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+		raw_spin_unlock_irqrestore(&chv_lock, flags);
 		return -EINVAL;
 	}
 
 	chv_writel(ctrl0, reg);
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	return 0;
 }
@@ -1162,9 +1187,9 @@
 	unsigned long flags;
 	u32 ctrl0, cfg;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 	ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
 	cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
@@ -1182,7 +1207,7 @@
 	void __iomem *reg;
 	u32 ctrl0;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 
 	reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
 	ctrl0 = readl(reg);
@@ -1194,7 +1219,7 @@
 
 	chv_writel(ctrl0, reg);
 
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -1204,9 +1229,9 @@
 	u32 ctrl0, direction;
 	unsigned long flags;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 	ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
 	direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
@@ -1244,14 +1269,14 @@
 	int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
 	u32 intr_line;
 
-	raw_spin_lock(&pctrl->lock);
+	raw_spin_lock(&chv_lock);
 
 	intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
 	intr_line &= CHV_PADCTRL0_INTSEL_MASK;
 	intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT;
 	chv_writel(BIT(intr_line), pctrl->regs + CHV_INTSTAT);
 
-	raw_spin_unlock(&pctrl->lock);
+	raw_spin_unlock(&chv_lock);
 }
 
 static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
@@ -1262,7 +1287,7 @@
 	u32 value, intr_line;
 	unsigned long flags;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 
 	intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
 	intr_line &= CHV_PADCTRL0_INTSEL_MASK;
@@ -1275,7 +1300,7 @@
 		value |= BIT(intr_line);
 	chv_writel(value, pctrl->regs + CHV_INTMASK);
 
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static void chv_gpio_irq_mask(struct irq_data *d)
@@ -1309,7 +1334,7 @@
 		unsigned long flags;
 		u32 intsel, value;
 
-		raw_spin_lock_irqsave(&pctrl->lock, flags);
+		raw_spin_lock_irqsave(&chv_lock, flags);
 		intsel = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
 		intsel &= CHV_PADCTRL0_INTSEL_MASK;
 		intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
@@ -1324,7 +1349,7 @@
 			irq_set_handler_locked(d, handler);
 			pctrl->intr_lines[intsel] = offset;
 		}
-		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+		raw_spin_unlock_irqrestore(&chv_lock, flags);
 	}
 
 	chv_gpio_irq_unmask(d);
@@ -1340,7 +1365,7 @@
 	unsigned long flags;
 	u32 value;
 
-	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	raw_spin_lock_irqsave(&chv_lock, flags);
 
 	/*
 	 * Pins which can be used as shared interrupt are configured in
@@ -1389,7 +1414,7 @@
 	else if (type & IRQ_TYPE_LEVEL_MASK)
 		irq_set_handler_locked(d, handle_level_irq);
 
-	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
 
 	return 0;
 }
@@ -1415,7 +1440,7 @@
 	chained_irq_enter(chip, desc);
 
 	pending = readl(pctrl->regs + CHV_INTSTAT);
-	for_each_set_bit(intr_line, &pending, 16) {
+	for_each_set_bit(intr_line, &pending, pctrl->community->nirqs) {
 		unsigned irq, offset;
 
 		offset = pctrl->intr_lines[intr_line];
@@ -1438,6 +1463,7 @@
 	chip->label = dev_name(pctrl->dev);
 	chip->dev = pctrl->dev;
 	chip->base = -1;
+	chip->irq_need_valid_mask = true;
 
 	ret = gpiochip_add(chip);
 	if (ret) {
@@ -1457,12 +1483,26 @@
 		offset += range->npins;
 	}
 
-	/* Mask and clear all interrupts */
-	chv_writel(0, pctrl->regs + CHV_INTMASK);
+	/* Do not add GPIOs that can only generate GPEs to the IRQ domain */
+	for (i = 0; i < pctrl->community->npins; i++) {
+		const struct pinctrl_pin_desc *desc;
+		u32 intsel;
+
+		desc = &pctrl->community->pins[i];
+
+		intsel = readl(chv_padreg(pctrl, desc->number, CHV_PADCTRL0));
+		intsel &= CHV_PADCTRL0_INTSEL_MASK;
+		intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
+
+		if (intsel >= pctrl->community->nirqs)
+			clear_bit(i, chip->irq_valid_mask);
+	}
+
+	/* Clear all interrupts */
 	chv_writel(0xffff, pctrl->regs + CHV_INTSTAT);
 
 	ret = gpiochip_irqchip_add(chip, &chv_gpio_irqchip, 0,
-				   handle_simple_irq, IRQ_TYPE_NONE);
+				   handle_bad_irq, IRQ_TYPE_NONE);
 	if (ret) {
 		dev_err(pctrl->dev, "failed to add IRQ chip\n");
 		goto fail;
@@ -1501,7 +1541,6 @@
 	if (i == ARRAY_SIZE(chv_communities))
 		return -ENODEV;
 
-	raw_spin_lock_init(&pctrl->lock);
 	pctrl->dev = &pdev->dev;
 
 #ifdef CONFIG_PM_SLEEP
@@ -1556,12 +1595,15 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int chv_pinctrl_suspend(struct device *dev)
+static int chv_pinctrl_suspend_noirq(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
+	unsigned long flags;
 	int i;
 
+	raw_spin_lock_irqsave(&chv_lock, flags);
+
 	pctrl->saved_intmask = readl(pctrl->regs + CHV_INTMASK);
 
 	for (i = 0; i < pctrl->community->npins; i++) {
@@ -1582,15 +1624,20 @@
 		ctx->padctrl1 = readl(reg);
 	}
 
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
+
 	return 0;
 }
 
-static int chv_pinctrl_resume(struct device *dev)
+static int chv_pinctrl_resume_noirq(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
+	unsigned long flags;
 	int i;
 
+	raw_spin_lock_irqsave(&chv_lock, flags);
+
 	/*
 	 * Mask all interrupts before restoring per-pin configuration
 	 * registers because we don't know in which state BIOS left them
@@ -1635,12 +1682,15 @@
 	chv_writel(0xffff, pctrl->regs + CHV_INTSTAT);
 	chv_writel(pctrl->saved_intmask, pctrl->regs + CHV_INTMASK);
 
+	raw_spin_unlock_irqrestore(&chv_lock, flags);
+
 	return 0;
 }
 #endif
 
 static const struct dev_pm_ops chv_pinctrl_pm_ops = {
-	SET_LATE_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend, chv_pinctrl_resume)
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend_noirq,
+				      chv_pinctrl_resume_noirq)
 };
 
 static const struct acpi_device_id chv_pinctrl_acpi_match[] = {
--- linux-4.4.0.orig/drivers/pinctrl/intel/pinctrl-intel.c
+++ linux-4.4.0/drivers/pinctrl/intel/pinctrl-intel.c
@@ -23,6 +23,7 @@
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
+#include "../core.h"
 #include "pinctrl-intel.h"
 
 /* Offset from regs */
@@ -1049,6 +1050,26 @@
 EXPORT_SYMBOL_GPL(intel_pinctrl_remove);
 
 #ifdef CONFIG_PM_SLEEP
+static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin)
+{
+	const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);
+
+	if (!pd || !intel_pad_usable(pctrl, pin))
+		return false;
+
+	/*
+	 * Only restore the pin if it is actually in use by the kernel (or
+	 * by userspace). It is possible that some pins are used by the
+	 * BIOS during resume and those are not always locked down so leave
+	 * them alone.
+	 */
+	if (pd->mux_owner || pd->gpio_owner ||
+	    gpiochip_line_is_irq(&pctrl->chip, pin))
+		return true;
+
+	return false;
+}
+
 int intel_pinctrl_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -1062,7 +1083,7 @@
 		const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
 		u32 val;
 
-		if (!intel_pad_usable(pctrl, desc->number))
+		if (!intel_pinctrl_should_save(pctrl, desc->number))
 			continue;
 
 		val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0));
@@ -1123,7 +1144,7 @@
 		void __iomem *padcfg;
 		u32 val;
 
-		if (!intel_pad_usable(pctrl, desc->number))
+		if (!intel_pinctrl_should_save(pctrl, desc->number))
 			continue;
 
 		padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG0);
--- linux-4.4.0.orig/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ linux-4.4.0/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -939,7 +939,8 @@
 	struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
 	int eint_num, virq, eint_offset;
 	unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc;
-	static const unsigned int dbnc_arr[] = {0 , 1, 16, 32, 64, 128, 256};
+	static const unsigned int debounce_time[] = {500, 1000, 16000, 32000, 64000,
+						128000, 256000};
 	const struct mtk_desc_pin *pin;
 	struct irq_data *d;
 
@@ -957,9 +958,9 @@
 	if (!mtk_eint_can_en_debounce(pctl, eint_num))
 		return -ENOSYS;
 
-	dbnc = ARRAY_SIZE(dbnc_arr);
-	for (i = 0; i < ARRAY_SIZE(dbnc_arr); i++) {
-		if (debounce <= dbnc_arr[i]) {
+	dbnc = ARRAY_SIZE(debounce_time);
+	for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+		if (debounce <= debounce_time[i]) {
 			dbnc = i;
 			break;
 		}
@@ -1190,9 +1191,10 @@
 	const struct mtk_desc_pin *pin;
 
 	chained_irq_enter(chip, desc);
-	for (eint_num = 0; eint_num < pctl->devdata->ap_num; eint_num += 32) {
+	for (eint_num = 0;
+	     eint_num < pctl->devdata->ap_num;
+	     eint_num += 32, reg += 4) {
 		status = readl(reg);
-		reg += 4;
 		while (status) {
 			offset = __ffs(status);
 			index = eint_num + offset;
--- linux-4.4.0.orig/drivers/pinctrl/meson/pinctrl-meson.c
+++ linux-4.4.0/drivers/pinctrl/meson/pinctrl-meson.c
@@ -246,7 +246,7 @@
 {
 	struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
 
-	meson_pmx_disable_other_groups(pc, range->pin_base + offset, -1);
+	meson_pmx_disable_other_groups(pc, offset, -1);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ linux-4.4.0/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -656,7 +656,7 @@
 
 static const char * const sdxc_a_groups[] = {
 	"sdxc_d0_0_a", "sdxc_d13_0_a", "sdxc_d47_a", "sdxc_clk_a",
-	"sdxc_cmd_a", "sdxc_d0_1_a", "sdxc_d0_13_1_a"
+	"sdxc_cmd_a", "sdxc_d0_1_a", "sdxc_d13_1_a"
 };
 
 static const char * const pcm_a_groups[] = {
@@ -732,8 +732,8 @@
 static const char * const nand_groups[] = {
 	"nand_io", "nand_io_ce0", "nand_io_ce1",
 	"nand_io_rb0", "nand_ale", "nand_cle",
-	"nand_wen_clk", "nand_ren_clk", "nand_dqs0",
-	"nand_dqs1"
+	"nand_wen_clk", "nand_ren_clk", "nand_dqs_0",
+	"nand_dqs_1"
 };
 
 static const char * const nor_groups[] = {
--- linux-4.4.0.orig/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ linux-4.4.0/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -995,7 +995,7 @@
 		int val;
 
 		if (pull)
-			pullidx = data_out ? 1 : 2;
+			pullidx = data_out ? 2 : 1;
 
 		seq_printf(s, " gpio-%-3d (%-20.20s) in  %s %s",
 			   gpio,
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-amd.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-amd.c
@@ -48,17 +48,6 @@
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + offset * 4);
-	/*
-	 * Suppose BIOS or Bootloader sets specific debounce for the
-	 * GPIO. if not, set debounce to be  2.75ms and remove glitch.
-	*/
-	if ((pin_reg & DB_TMR_OUT_MASK) == 0) {
-		pin_reg |= 0xf;
-		pin_reg |= BIT(DB_TMR_OUT_UNIT_OFF);
-		pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF;
-		pin_reg &= ~BIT(DB_TMR_LARGE_OFF);
-	}
-
 	pin_reg &= ~BIT(OUTPUT_ENABLE_OFF);
 	writel(pin_reg, gpio_dev->base + offset * 4);
 	spin_unlock_irqrestore(&gpio_dev->lock, flags);
@@ -155,7 +144,7 @@
 			pin_reg |= BIT(DB_TMR_OUT_UNIT_OFF);
 			pin_reg &= ~BIT(DB_TMR_LARGE_OFF);
 		} else if (debounce < 250000) {
-			time = debounce / 15600;
+			time = debounce / 15625;
 			pin_reg |= time & DB_TMR_OUT_MASK;
 			pin_reg &= ~BIT(DB_TMR_OUT_UNIT_OFF);
 			pin_reg |= BIT(DB_TMR_LARGE_OFF);
@@ -165,14 +154,14 @@
 			pin_reg |= BIT(DB_TMR_OUT_UNIT_OFF);
 			pin_reg |= BIT(DB_TMR_LARGE_OFF);
 		} else {
-			pin_reg &= ~DB_CNTRl_MASK;
+			pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF);
 			ret = -EINVAL;
 		}
 	} else {
 		pin_reg &= ~BIT(DB_TMR_OUT_UNIT_OFF);
 		pin_reg &= ~BIT(DB_TMR_LARGE_OFF);
 		pin_reg &= ~DB_TMR_OUT_MASK;
-		pin_reg &= ~DB_CNTRl_MASK;
+		pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF);
 	}
 	writel(pin_reg, gpio_dev->base + offset * 4);
 	spin_unlock_irqrestore(&gpio_dev->lock, flags);
@@ -331,15 +320,6 @@
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
-	/*
-		Suppose BIOS or Bootloader sets specific debounce for the
-		GPIO. if not, set debounce to be  2.75ms.
-	*/
-	if ((pin_reg & DB_TMR_OUT_MASK) == 0) {
-		pin_reg |= 0xf;
-		pin_reg |= BIT(DB_TMR_OUT_UNIT_OFF);
-		pin_reg &= ~BIT(DB_TMR_LARGE_OFF);
-	}
 	pin_reg |= BIT(INTERRUPT_ENABLE_OFF);
 	pin_reg |= BIT(INTERRUPT_MASK_OFF);
 	writel(pin_reg, gpio_dev->base + (d->hwirq)*4);
@@ -408,18 +388,31 @@
 	int ret = 0;
 	u32 pin_reg;
 	unsigned long flags;
+	bool level_trig;
+	u32 active_level;
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
 
+	/*
+	 * When level_trig is set EDGE and active_level is set HIGH in BIOS
+	 * default settings, ignore incoming settings from client and use
+	 * BIOS settings to configure GPIO register.
+	 */
+	level_trig = !(pin_reg & (LEVEL_TRIGGER << LEVEL_TRIG_OFF));
+	active_level = pin_reg & (ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF);
+
+	if(level_trig &&
+	   ((active_level >> ACTIVE_LEVEL_OFF) == ACTIVE_HIGH))
+		type = IRQ_TYPE_EDGE_FALLING;
+
 	switch (type & IRQ_TYPE_SENSE_MASK) {
 	case IRQ_TYPE_EDGE_RISING:
 		pin_reg &= ~BIT(LEVEL_TRIG_OFF);
 		pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF);
 		pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF;
-		pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF;
 		irq_set_handler_locked(d, handle_edge_irq);
 		break;
 
@@ -427,7 +420,6 @@
 		pin_reg &= ~BIT(LEVEL_TRIG_OFF);
 		pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF);
 		pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF;
-		pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF;
 		irq_set_handler_locked(d, handle_edge_irq);
 		break;
 
@@ -435,7 +427,6 @@
 		pin_reg &= ~BIT(LEVEL_TRIG_OFF);
 		pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF);
 		pin_reg |= BOTH_EADGE << ACTIVE_LEVEL_OFF;
-		pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF;
 		irq_set_handler_locked(d, handle_edge_irq);
 		break;
 
@@ -443,8 +434,6 @@
 		pin_reg |= LEVEL_TRIGGER << LEVEL_TRIG_OFF;
 		pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF);
 		pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF;
-		pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF);
-		pin_reg |= DB_TYPE_PRESERVE_LOW_GLITCH << DB_CNTRL_OFF;
 		irq_set_handler_locked(d, handle_level_irq);
 		break;
 
@@ -452,8 +441,6 @@
 		pin_reg |= LEVEL_TRIGGER << LEVEL_TRIG_OFF;
 		pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF);
 		pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF;
-		pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF);
-		pin_reg |= DB_TYPE_PRESERVE_HIGH_GLITCH << DB_CNTRL_OFF;
 		irq_set_handler_locked(d, handle_level_irq);
 		break;
 
@@ -788,8 +775,8 @@
 	gpio_dev->ngroups = ARRAY_SIZE(kerncz_groups);
 
 	amd_pinctrl_desc.name = dev_name(&pdev->dev);
-	gpio_dev->pctrl = pinctrl_register(&amd_pinctrl_desc,
-					&pdev->dev, gpio_dev);
+	gpio_dev->pctrl = devm_pinctrl_register(&pdev->dev, &amd_pinctrl_desc,
+						gpio_dev);
 	if (IS_ERR(gpio_dev->pctrl)) {
 		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
 		return PTR_ERR(gpio_dev->pctrl);
@@ -797,7 +784,7 @@
 
 	ret = gpiochip_add(&gpio_dev->gc);
 	if (ret)
-		goto out1;
+		return ret;
 
 	ret = gpiochip_add_pin_range(&gpio_dev->gc, dev_name(&pdev->dev),
 				0, 0, TOTAL_NUMBER_OF_PINS);
@@ -830,8 +817,6 @@
 out2:
 	gpiochip_remove(&gpio_dev->gc);
 
-out1:
-	pinctrl_unregister(gpio_dev->pctrl);
 	return ret;
 }
 
@@ -842,7 +827,6 @@
 	gpio_dev = platform_get_drvdata(pdev);
 
 	gpiochip_remove(&gpio_dev->gc);
-	pinctrl_unregister(gpio_dev->pctrl);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-amd.h
+++ linux-4.4.0/drivers/pinctrl/pinctrl-amd.h
@@ -249,7 +249,7 @@
 	{
 		.name = "uart0",
 		.pins = uart0_pins,
-		.npins = 9,
+		.npins = 5,
 	},
 	{
 		.name = "uart1",
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-at91-pio4.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -477,7 +477,6 @@
 	unsigned num_pins, num_configs, reserve;
 	unsigned long *configs;
 	struct property	*pins;
-	bool has_config;
 	u32 pinfunc;
 	int ret, i;
 
@@ -493,9 +492,6 @@
 		return ret;
 	}
 
-	if (num_configs)
-		has_config = true;
-
 	num_pins = pins->length / sizeof(u32);
 	if (!num_pins) {
 		dev_err(pctldev->dev, "no pins found in node %s\n",
@@ -508,7 +504,7 @@
 	 * map for each pin.
 	 */
 	reserve = 1;
-	if (has_config && num_pins >= 1)
+	if (num_configs)
 		reserve++;
 	reserve *= num_pins;
 	ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps,
@@ -531,7 +527,7 @@
 		pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps,
 					  group, func);
 
-		if (has_config) {
+		if (num_configs) {
 			ret = pinctrl_utils_add_map_configs(pctldev, map,
 					reserved_maps, num_maps, group,
 					configs, num_configs,
@@ -568,8 +564,10 @@
 		for_each_child_of_node(np_config, np) {
 			ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map,
 						    &reserved_maps, num_maps);
-			if (ret < 0)
+			if (ret < 0) {
+				of_node_put(np);
 				break;
+			}
 		}
 	}
 
@@ -717,9 +715,11 @@
 			break;
 		case PIN_CONFIG_BIAS_PULL_UP:
 			conf |= ATMEL_PIO_PUEN_MASK;
+			conf &= (~ATMEL_PIO_PDEN_MASK);
 			break;
 		case PIN_CONFIG_BIAS_PULL_DOWN:
 			conf |= ATMEL_PIO_PDEN_MASK;
+			conf &= (~ATMEL_PIO_PUEN_MASK);
 			break;
 		case PIN_CONFIG_DRIVE_OPEN_DRAIN:
 			if (arg == 0)
@@ -1000,7 +1000,7 @@
 		atmel_pioctrl->irqs[i] = res->start;
 		irq_set_chained_handler(res->start, atmel_gpio_irq_handler);
 		irq_set_handler_data(res->start, atmel_pioctrl);
-		dev_dbg(dev, "bank %i: hwirq=%u\n", i, res->start);
+		dev_dbg(dev, "bank %i: irq=%pr\n", i, res);
 	}
 
 	atmel_pioctrl->irq_domain = irq_domain_add_linear(dev->of_node,
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-at91.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-at91.c
@@ -1556,16 +1556,6 @@
 #define gpio_irq_set_wake	NULL
 #endif /* CONFIG_PM */
 
-static struct irq_chip gpio_irqchip = {
-	.name		= "GPIO",
-	.irq_ack	= gpio_irq_ack,
-	.irq_disable	= gpio_irq_mask,
-	.irq_mask	= gpio_irq_mask,
-	.irq_unmask	= gpio_irq_unmask,
-	/* .irq_set_type is set dynamically */
-	.irq_set_wake	= gpio_irq_set_wake,
-};
-
 static void gpio_irq_handler(struct irq_desc *desc)
 {
 	struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -1608,12 +1598,22 @@
 	struct gpio_chip	*gpiochip_prev = NULL;
 	struct at91_gpio_chip   *prev = NULL;
 	struct irq_data		*d = irq_get_irq_data(at91_gpio->pioc_virq);
+	struct irq_chip		*gpio_irqchip;
 	int ret, i;
 
+	gpio_irqchip = devm_kzalloc(&pdev->dev, sizeof(*gpio_irqchip), GFP_KERNEL);
+	if (!gpio_irqchip)
+		return -ENOMEM;
+
 	at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
 
-	/* Setup proper .irq_set_type function */
-	gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type;
+	gpio_irqchip->name = "GPIO";
+	gpio_irqchip->irq_ack = gpio_irq_ack;
+	gpio_irqchip->irq_disable = gpio_irq_mask;
+	gpio_irqchip->irq_mask = gpio_irq_mask;
+	gpio_irqchip->irq_unmask = gpio_irq_unmask;
+	gpio_irqchip->irq_set_wake = gpio_irq_set_wake,
+	gpio_irqchip->irq_set_type = at91_gpio->ops->irq_type;
 
 	/* Disable irqs of this PIO controller */
 	writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
@@ -1624,7 +1624,7 @@
 	 * interrupt.
 	 */
 	ret = gpiochip_irqchip_add(&at91_gpio->chip,
-				   &gpio_irqchip,
+				   gpio_irqchip,
 				   0,
 				   handle_edge_irq,
 				   IRQ_TYPE_EDGE_BOTH);
@@ -1642,7 +1642,7 @@
 	if (!gpiochip_prev) {
 		/* Then register the chain on the parent IRQ */
 		gpiochip_set_chained_irqchip(&at91_gpio->chip,
-					     &gpio_irqchip,
+					     gpio_irqchip,
 					     at91_gpio->pioc_virq,
 					     gpio_irq_handler);
 		return 0;
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-falcon.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-falcon.c
@@ -438,24 +438,28 @@
 
 	/* load and remap the pad resources of the different banks */
 	for_each_compatible_node(np, NULL, "lantiq,pad-falcon") {
-		struct platform_device *ppdev = of_find_device_by_node(np);
 		const __be32 *bank = of_get_property(np, "lantiq,bank", NULL);
 		struct resource res;
+		struct platform_device *ppdev;
 		u32 avail;
 		int pins;
 
 		if (!of_device_is_available(np))
 			continue;
 
-		if (!ppdev) {
-			dev_err(&pdev->dev, "failed to find pad pdev\n");
-			continue;
-		}
 		if (!bank || *bank >= PORTS)
 			continue;
 		if (of_address_to_resource(np, 0, &res))
 			continue;
+
+		ppdev = of_find_device_by_node(np);
+		if (!ppdev) {
+			dev_err(&pdev->dev, "failed to find pad pdev\n");
+			continue;
+		}
+
 		falcon_info.clk[*bank] = clk_get(&ppdev->dev, NULL);
+		put_device(&ppdev->dev);
 		if (IS_ERR(falcon_info.clk[*bank])) {
 			dev_err(&ppdev->dev, "failed to get clock\n");
 			return PTR_ERR(falcon_info.clk[*bank]);
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-pistachio.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-pistachio.c
@@ -469,27 +469,27 @@
 	"mfio83",
 };
 
-static const char * const pistachio_sys_pll_lock_groups[] = {
+static const char * const pistachio_audio_pll_lock_groups[] = {
 	"mfio84",
 };
 
-static const char * const pistachio_wifi_pll_lock_groups[] = {
+static const char * const pistachio_rpu_v_pll_lock_groups[] = {
 	"mfio85",
 };
 
-static const char * const pistachio_bt_pll_lock_groups[] = {
+static const char * const pistachio_rpu_l_pll_lock_groups[] = {
 	"mfio86",
 };
 
-static const char * const pistachio_rpu_v_pll_lock_groups[] = {
+static const char * const pistachio_sys_pll_lock_groups[] = {
 	"mfio87",
 };
 
-static const char * const pistachio_rpu_l_pll_lock_groups[] = {
+static const char * const pistachio_wifi_pll_lock_groups[] = {
 	"mfio88",
 };
 
-static const char * const pistachio_audio_pll_lock_groups[] = {
+static const char * const pistachio_bt_pll_lock_groups[] = {
 	"mfio89",
 };
 
@@ -559,12 +559,12 @@
 	PISTACHIO_FUNCTION_DREQ4,
 	PISTACHIO_FUNCTION_DREQ5,
 	PISTACHIO_FUNCTION_MIPS_PLL_LOCK,
+	PISTACHIO_FUNCTION_AUDIO_PLL_LOCK,
+	PISTACHIO_FUNCTION_RPU_V_PLL_LOCK,
+	PISTACHIO_FUNCTION_RPU_L_PLL_LOCK,
 	PISTACHIO_FUNCTION_SYS_PLL_LOCK,
 	PISTACHIO_FUNCTION_WIFI_PLL_LOCK,
 	PISTACHIO_FUNCTION_BT_PLL_LOCK,
-	PISTACHIO_FUNCTION_RPU_V_PLL_LOCK,
-	PISTACHIO_FUNCTION_RPU_L_PLL_LOCK,
-	PISTACHIO_FUNCTION_AUDIO_PLL_LOCK,
 	PISTACHIO_FUNCTION_DEBUG_RAW_CCA_IND,
 	PISTACHIO_FUNCTION_DEBUG_ED_SEC20_CCA_IND,
 	PISTACHIO_FUNCTION_DEBUG_ED_SEC40_CCA_IND,
@@ -620,12 +620,12 @@
 	FUNCTION(dreq4),
 	FUNCTION(dreq5),
 	FUNCTION(mips_pll_lock),
+	FUNCTION(audio_pll_lock),
+	FUNCTION(rpu_v_pll_lock),
+	FUNCTION(rpu_l_pll_lock),
 	FUNCTION(sys_pll_lock),
 	FUNCTION(wifi_pll_lock),
 	FUNCTION(bt_pll_lock),
-	FUNCTION(rpu_v_pll_lock),
-	FUNCTION(rpu_l_pll_lock),
-	FUNCTION(audio_pll_lock),
 	FUNCTION(debug_raw_cca_ind),
 	FUNCTION(debug_ed_sec20_cca_ind),
 	FUNCTION(debug_ed_sec40_cca_ind),
@@ -809,17 +809,17 @@
 			   PADS_FUNCTION_SELECT2, 12, 0x3),
 	MFIO_MUX_PIN_GROUP(83, MIPS_PLL_LOCK, MIPS_TRACE_DATA, USB_DEBUG,
 			   PADS_FUNCTION_SELECT2, 14, 0x3),
-	MFIO_MUX_PIN_GROUP(84, SYS_PLL_LOCK, MIPS_TRACE_DATA, USB_DEBUG,
+	MFIO_MUX_PIN_GROUP(84, AUDIO_PLL_LOCK, MIPS_TRACE_DATA, USB_DEBUG,
 			   PADS_FUNCTION_SELECT2, 16, 0x3),
-	MFIO_MUX_PIN_GROUP(85, WIFI_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
+	MFIO_MUX_PIN_GROUP(85, RPU_V_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
 			   PADS_FUNCTION_SELECT2, 18, 0x3),
-	MFIO_MUX_PIN_GROUP(86, BT_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
+	MFIO_MUX_PIN_GROUP(86, RPU_L_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
 			   PADS_FUNCTION_SELECT2, 20, 0x3),
-	MFIO_MUX_PIN_GROUP(87, RPU_V_PLL_LOCK, DREQ2, SOCIF_DEBUG,
+	MFIO_MUX_PIN_GROUP(87, SYS_PLL_LOCK, DREQ2, SOCIF_DEBUG,
 			   PADS_FUNCTION_SELECT2, 22, 0x3),
-	MFIO_MUX_PIN_GROUP(88, RPU_L_PLL_LOCK, DREQ3, SOCIF_DEBUG,
+	MFIO_MUX_PIN_GROUP(88, WIFI_PLL_LOCK, DREQ3, SOCIF_DEBUG,
 			   PADS_FUNCTION_SELECT2, 24, 0x3),
-	MFIO_MUX_PIN_GROUP(89, AUDIO_PLL_LOCK, DREQ4, DREQ5,
+	MFIO_MUX_PIN_GROUP(89, BT_PLL_LOCK, DREQ4, DREQ5,
 			   PADS_FUNCTION_SELECT2, 26, 0x3),
 	PIN_GROUP(TCK, "tck"),
 	PIN_GROUP(TRSTN, "trstn"),
@@ -1373,6 +1373,7 @@
 		if (!of_find_property(child, "gpio-controller", NULL)) {
 			dev_err(pctl->dev,
 				"No gpio-controller property for bank %u\n", i);
+			of_node_put(child);
 			ret = -ENODEV;
 			goto err;
 		}
@@ -1380,6 +1381,7 @@
 		irq = irq_of_parse_and_map(child, 0);
 		if (irq < 0) {
 			dev_err(pctl->dev, "No IRQ for bank %u: %d\n", i, irq);
+			of_node_put(child);
 			ret = irq;
 			goto err;
 		}
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-rockchip.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-rockchip.c
@@ -1445,7 +1445,9 @@
 	if (!bank->domain)
 		return -ENXIO;
 
+	clk_enable(bank->clk);
 	virq = irq_create_mapping(bank->domain, offset);
+	clk_disable(bank->clk);
 
 	return (virq) ? : -ENXIO;
 }
@@ -1837,6 +1839,7 @@
 						    base,
 						    &rockchip_regmap_config);
 		}
+		of_node_put(node);
 	}
 
 	bank->irq = irq_of_parse_and_map(bank->of_node, 0);
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-single.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-single.c
@@ -1071,7 +1071,7 @@
 
 	/* If pinconf isn't supported, don't parse properties in below. */
 	if (!PCS_HAS_PINCONF)
-		return 0;
+		return -ENOTSUPP;
 
 	/* cacluate how much properties are supported in current node */
 	for (i = 0; i < ARRAY_SIZE(prop2); i++) {
@@ -1083,7 +1083,7 @@
 			nconfs++;
 	}
 	if (!nconfs)
-		return 0;
+		return -ENOTSUPP;
 
 	func->conf = devm_kzalloc(pcs->dev,
 				  sizeof(struct pcs_conf_vals) * nconfs,
@@ -1196,9 +1196,12 @@
 
 	if (PCS_HAS_PINCONF) {
 		res = pcs_parse_pinconf(pcs, np, function, map);
-		if (res)
+		if (res == 0)
+			*num_maps = 2;
+		else if (res == -ENOTSUPP)
+			*num_maps = 1;
+		else
 			goto free_pingroups;
-		*num_maps = 2;
 	} else {
 		*num_maps = 1;
 	}
@@ -1273,9 +1276,9 @@
 
 		/* Parse pins in each row from LSB */
 		while (mask) {
-			bit_pos = ffs(mask);
+			bit_pos = __ffs(mask);
 			pin_num_from_lsb = bit_pos / pcs->bits_per_pin;
-			mask_pos = ((pcs->fmask) << (bit_pos - 1));
+			mask_pos = ((pcs->fmask) << bit_pos);
 			val_pos = val & mask_pos;
 			submask = mask & mask_pos;
 
@@ -1576,6 +1579,9 @@
 		else
 			mask &= ~soc_mask;
 		pcs->write(mask, pcswi->reg);
+
+		/* flush posted write */
+		mask = pcs->read(pcswi->reg);
 		raw_spin_unlock(&pcs->lock);
 	}
 
@@ -1847,7 +1853,7 @@
 	ret = of_property_read_u32(np, "pinctrl-single,function-mask",
 				   &pcs->fmask);
 	if (!ret) {
-		pcs->fshift = ffs(pcs->fmask) - 1;
+		pcs->fshift = __ffs(pcs->fmask);
 		pcs->fmax = pcs->fmask >> pcs->fshift;
 	} else {
 		/* If mask property doesn't exist, function mux is invalid. */
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-st.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-st.c
@@ -1338,6 +1338,22 @@
 	writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK);
 }
 
+static int st_gpio_irq_request_resources(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+	st_gpio_direction_input(gc, d->hwirq);
+
+	return gpiochip_lock_as_irq(gc, d->hwirq);
+}
+
+static void st_gpio_irq_release_resources(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+	gpiochip_unlock_as_irq(gc, d->hwirq);
+}
+
 static int st_gpio_irq_set_type(struct irq_data *d, unsigned type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
@@ -1493,12 +1509,14 @@
 };
 
 static struct irq_chip st_gpio_irqchip = {
-	.name		= "GPIO",
-	.irq_disable	= st_gpio_irq_mask,
-	.irq_mask	= st_gpio_irq_mask,
-	.irq_unmask	= st_gpio_irq_unmask,
-	.irq_set_type	= st_gpio_irq_set_type,
-	.flags		= IRQCHIP_SKIP_SET_WAKE,
+	.name			= "GPIO",
+	.irq_request_resources	= st_gpio_irq_request_resources,
+	.irq_release_resources	= st_gpio_irq_release_resources,
+	.irq_disable		= st_gpio_irq_mask,
+	.irq_mask		= st_gpio_irq_mask,
+	.irq_unmask		= st_gpio_irq_unmask,
+	.irq_set_type		= st_gpio_irq_set_type,
+	.flags			= IRQCHIP_SKIP_SET_WAKE,
 };
 
 static int st_gpiolib_register_bank(struct st_pinctrl *info,
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-tegra.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-tegra.c
@@ -52,7 +52,9 @@
 
 static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
 {
-	writel(val, pmx->regs[bank] + reg);
+	writel_relaxed(val, pmx->regs[bank] + reg);
+	/* make sure pinmux register write completed */
+	pmx_readl(pmx, bank, reg);
 }
 
 static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
@@ -416,7 +418,7 @@
 		return -ENOTSUPP;
 	}
 
-	if (*reg < 0 || *bit > 31) {
+	if (*reg < 0 || *bit < 0)  {
 		if (report_err) {
 			const char *prop = "unknown";
 			int i;
--- linux-4.4.0.orig/drivers/pinctrl/pinctrl-zynq.c
+++ linux-4.4.0/drivers/pinctrl/pinctrl-zynq.c
@@ -967,15 +967,12 @@
 	zynq_iostd_max
 };
 
-/**
- * enum zynq_pin_config_param - possible pin configuration parameters
- * @PIN_CONFIG_IOSTANDARD: if the pin can select an IO standard, the argument to
+/*
+ * PIN_CONFIG_IOSTANDARD: if the pin can select an IO standard, the argument to
  *	this parameter (on a custom format) tells the driver which alternative
  *	IO standard to use.
  */
-enum zynq_pin_config_param {
-	PIN_CONFIG_IOSTANDARD = PIN_CONFIG_END + 1,
-};
+#define PIN_CONFIG_IOSTANDARD		(PIN_CONFIG_END + 1)
 
 static const struct pinconf_generic_params zynq_dt_params[] = {
 	{"io-standard", PIN_CONFIG_IOSTANDARD, zynq_iostd_lvcmos18},
--- linux-4.4.0.orig/drivers/pinctrl/qcom/pinctrl-msm.c
+++ linux-4.4.0/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -597,10 +597,6 @@
 
 	spin_lock_irqsave(&pctrl->lock, flags);
 
-	val = readl(pctrl->regs + g->intr_status_reg);
-	val &= ~BIT(g->intr_status_bit);
-	writel(val, pctrl->regs + g->intr_status_reg);
-
 	val = readl(pctrl->regs + g->intr_cfg_reg);
 	val |= BIT(g->intr_enable_bit);
 	writel(val, pctrl->regs + g->intr_cfg_reg);
@@ -810,11 +806,24 @@
 		return ret;
 	}
 
-	ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
-	if (ret) {
-		dev_err(pctrl->dev, "Failed to add pin range\n");
-		gpiochip_remove(&pctrl->chip);
-		return ret;
+	/*
+	 * For DeviceTree-supported systems, the gpio core checks the
+	 * pinctrl's device node for the "gpio-ranges" property.
+	 * If it is present, it takes care of adding the pin ranges
+	 * for the driver. In this case the driver can skip ahead.
+	 *
+	 * In order to remain compatible with older, existing DeviceTree
+	 * files which don't set the "gpio-ranges" property or systems that
+	 * utilize ACPI the driver has to call gpiochip_add_pin_range().
+	 */
+	if (!of_property_read_bool(pctrl->dev->of_node, "gpio-ranges")) {
+		ret = gpiochip_add_pin_range(&pctrl->chip,
+			dev_name(pctrl->dev), 0, 0, chip->ngpio);
+		if (ret) {
+			dev_err(pctrl->dev, "Failed to add pin range\n");
+			gpiochip_remove(&pctrl->chip);
+			return ret;
+		}
 	}
 
 	ret = gpiochip_irqchip_add(chip,
--- linux-4.4.0.orig/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ linux-4.4.0/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -291,31 +291,47 @@
 
 	switch (param) {
 	case PIN_CONFIG_DRIVE_PUSH_PULL:
-		arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_CMOS;
+		if (pad->buffer_type != PMIC_GPIO_OUT_BUF_CMOS)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
-		arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS;
+		if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_DRIVE_OPEN_SOURCE:
-		arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS;
+		if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_BIAS_PULL_DOWN:
-		arg = pad->pullup == PMIC_GPIO_PULL_DOWN;
+		if (pad->pullup != PMIC_GPIO_PULL_DOWN)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_BIAS_DISABLE:
-		arg = pad->pullup = PMIC_GPIO_PULL_DISABLE;
+		if (pad->pullup != PMIC_GPIO_PULL_DISABLE)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_BIAS_PULL_UP:
-		arg = pad->pullup == PMIC_GPIO_PULL_UP_30;
+		if (pad->pullup != PMIC_GPIO_PULL_UP_30)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
-		arg = !pad->is_enabled;
+		if (pad->is_enabled)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_POWER_SOURCE:
 		arg = pad->power_source;
 		break;
 	case PIN_CONFIG_INPUT_ENABLE:
-		arg = pad->input_enabled;
+		if (!pad->input_enabled)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_OUTPUT:
 		arg = pad->out_value;
@@ -777,10 +793,23 @@
 		goto err_chip;
 	}
 
-	ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
-	if (ret) {
-		dev_err(dev, "failed to add pin range\n");
-		goto err_range;
+	/*
+	 * For DeviceTree-supported systems, the gpio core checks the
+	 * pinctrl's device node for the "gpio-ranges" property.
+	 * If it is present, it takes care of adding the pin ranges
+	 * for the driver. In this case the driver can skip ahead.
+	 *
+	 * In order to remain compatible with older, existing DeviceTree
+	 * files which don't set the "gpio-ranges" property or systems that
+	 * utilize ACPI the driver has to call gpiochip_add_pin_range().
+	 */
+	if (!of_property_read_bool(dev->of_node, "gpio-ranges")) {
+		ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0,
+					     npins);
+		if (ret) {
+			dev_err(dev, "failed to add pin range\n");
+			goto err_range;
+		}
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ linux-4.4.0/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -321,6 +321,8 @@
 	pad->function = function;
 
 	ret = pmic_mpp_write_mode_ctl(state, pad);
+	if (ret < 0)
+		return ret;
 
 	val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT;
 
@@ -345,13 +347,12 @@
 
 	switch (param) {
 	case PIN_CONFIG_BIAS_DISABLE:
-		arg = pad->pullup == PMIC_MPP_PULL_UP_OPEN;
+		if (pad->pullup != PMIC_MPP_PULL_UP_OPEN)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_BIAS_PULL_UP:
 		switch (pad->pullup) {
-		case PMIC_MPP_PULL_UP_OPEN:
-			arg = 0;
-			break;
 		case PMIC_MPP_PULL_UP_0P6KOHM:
 			arg = 600;
 			break;
@@ -366,13 +367,17 @@
 		}
 		break;
 	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
-		arg = !pad->is_enabled;
+		if (pad->is_enabled)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_POWER_SOURCE:
 		arg = pad->power_source;
 		break;
 	case PIN_CONFIG_INPUT_ENABLE:
-		arg = pad->input_enabled;
+		if (!pad->input_enabled)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_OUTPUT:
 		arg = pad->out_value;
@@ -384,7 +389,9 @@
 		arg = pad->amux_input;
 		break;
 	case PMIC_MPP_CONF_PAIRED:
-		arg = pad->paired;
+		if (!pad->paired)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_DRIVE_STRENGTH:
 		arg = pad->drive_strength;
@@ -457,7 +464,7 @@
 			pad->dtest = arg;
 			break;
 		case PIN_CONFIG_DRIVE_STRENGTH:
-			arg = pad->drive_strength;
+			pad->drive_strength = arg;
 			break;
 		case PMIC_MPP_CONF_AMUX_ROUTE:
 			if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4)
@@ -501,6 +508,10 @@
 	if (ret < 0)
 		return ret;
 
+	ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_SINK_CTL, pad->drive_strength);
+	if (ret < 0)
+		return ret;
+
 	val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT;
 
 	return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val);
--- linux-4.4.0.orig/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
+++ linux-4.4.0/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
@@ -259,22 +259,32 @@
 
 	switch (param) {
 	case PIN_CONFIG_BIAS_DISABLE:
-		arg = pin->bias == PM8XXX_GPIO_BIAS_NP;
+		if (pin->bias != PM8XXX_GPIO_BIAS_NP)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_BIAS_PULL_DOWN:
-		arg = pin->bias == PM8XXX_GPIO_BIAS_PD;
+		if (pin->bias != PM8XXX_GPIO_BIAS_PD)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_BIAS_PULL_UP:
-		arg = pin->bias <= PM8XXX_GPIO_BIAS_PU_1P5_30;
+		if (pin->bias > PM8XXX_GPIO_BIAS_PU_1P5_30)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PM8XXX_QCOM_PULL_UP_STRENGTH:
 		arg = pin->pull_up_strength;
 		break;
 	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
-		arg = pin->disable;
+		if (!pin->disable)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_INPUT_ENABLE:
-		arg = pin->mode == PM8XXX_GPIO_MODE_INPUT;
+		if (pin->mode != PM8XXX_GPIO_MODE_INPUT)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_OUTPUT:
 		if (pin->mode & PM8XXX_GPIO_MODE_OUTPUT)
@@ -289,10 +299,14 @@
 		arg = pin->output_strength;
 		break;
 	case PIN_CONFIG_DRIVE_PUSH_PULL:
-		arg = !pin->open_drain;
+		if (pin->open_drain)
+			return -EINVAL;
+		arg = 1;
 		break;
 	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
-		arg = pin->open_drain;
+		if (!pin->open_drain)
+			return -EINVAL;
+		arg = 1;
 		break;
 	default:
 		return -EINVAL;
@@ -741,12 +755,23 @@
 		goto unregister_pinctrl;
 	}
 
-	ret = gpiochip_add_pin_range(&pctrl->chip,
-				     dev_name(pctrl->dev),
-				     0, 0, pctrl->chip.ngpio);
-	if (ret) {
-		dev_err(pctrl->dev, "failed to add pin range\n");
-		goto unregister_gpiochip;
+	/*
+	 * For DeviceTree-supported systems, the gpio core checks the
+	 * pinctrl's device node for the "gpio-ranges" property.
+	 * If it is present, it takes care of adding the pin ranges
+	 * for the driver. In this case the driver can skip ahead.
+	 *
+	 * In order to remain compatible with older, existing DeviceTree
+	 * files which don't set the "gpio-ranges" property or systems that
+	 * utilize ACPI the driver has to call gpiochip_add_pin_range().
+	 */
+	if (!of_property_read_bool(pctrl->dev->of_node, "gpio-ranges")) {
+		ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev),
+					     0, 0, pctrl->chip.ngpio);
+		if (ret) {
+			dev_err(pctrl->dev, "failed to add pin range\n");
+			goto unregister_gpiochip;
+		}
 	}
 
 	platform_set_drvdata(pdev, pctrl);
--- linux-4.4.0.orig/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ linux-4.4.0/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -194,8 +194,6 @@
 
 	spin_unlock_irqrestore(&bank->slock, flags);
 
-	exynos_irq_unmask(irqd);
-
 	return 0;
 }
 
@@ -216,8 +214,6 @@
 	shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
 	mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
 
-	exynos_irq_mask(irqd);
-
 	spin_lock_irqsave(&bank->slock, flags);
 
 	con = readl(d->virt_base + reg_con);
@@ -292,6 +288,7 @@
 	u32 eint_con;
 	u32 eint_fltcon0;
 	u32 eint_fltcon1;
+	u32 eint_mask;
 };
 
 /*
@@ -592,10 +589,13 @@
 						+ 2 * bank->eint_offset);
 	save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
 						+ 2 * bank->eint_offset + 4);
+	save->eint_mask = readl(regs + bank->irq_chip->eint_mask
+						+ bank->eint_offset);
 
 	pr_debug("%s: save     con %#010x\n", bank->name, save->eint_con);
 	pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
 	pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
+	pr_debug("%s: save    mask %#010x\n", bank->name, save->eint_mask);
 }
 
 static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
@@ -624,6 +624,9 @@
 	pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name,
 			readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
 			+ 2 * bank->eint_offset + 4), save->eint_fltcon1);
+	pr_debug("%s:    mask %#010x => %#010x\n", bank->name,
+			readl(regs + bank->irq_chip->eint_mask
+			+ bank->eint_offset), save->eint_mask);
 
 	writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET
 						+ bank->eint_offset);
@@ -631,6 +634,8 @@
 						+ 2 * bank->eint_offset);
 	writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET
 						+ 2 * bank->eint_offset + 4);
+	writel(save->eint_mask, regs + bank->irq_chip->eint_mask
+						+ bank->eint_offset);
 }
 
 static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
--- linux-4.4.0.orig/drivers/pinctrl/samsung/pinctrl-exynos5440.c
+++ linux-4.4.0/drivers/pinctrl/samsung/pinctrl-exynos5440.c
@@ -107,6 +107,7 @@
  * @nr_groups: number of pin groups available.
  * @pmx_functions: list of pin functions parsed from device tree.
  * @nr_functions: number of pin functions available.
+ * @range: gpio range to register with pinctrl
  */
 struct exynos5440_pinctrl_priv_data {
 	void __iomem			*reg_base;
@@ -117,6 +118,7 @@
 	unsigned int			nr_groups;
 	const struct exynos5440_pmx_func	*pmx_functions;
 	unsigned int			nr_functions;
+	struct pinctrl_gpio_range	range;
 };
 
 /**
@@ -742,7 +744,6 @@
 	struct pinctrl_desc *ctrldesc;
 	struct pinctrl_dev *pctl_dev;
 	struct pinctrl_pin_desc *pindesc, *pdesc;
-	struct pinctrl_gpio_range grange;
 	char *pin_names;
 	int pin, ret;
 
@@ -794,12 +795,12 @@
 		return PTR_ERR(pctl_dev);
 	}
 
-	grange.name = "exynos5440-pctrl-gpio-range";
-	grange.id = 0;
-	grange.base = 0;
-	grange.npins = EXYNOS5440_MAX_PINS;
-	grange.gc = priv->gc;
-	pinctrl_add_gpio_range(pctl_dev, &grange);
+	priv->range.name = "exynos5440-pctrl-gpio-range";
+	priv->range.id = 0;
+	priv->range.base = 0;
+	priv->range.npins = EXYNOS5440_MAX_PINS;
+	priv->range.gc = priv->gc;
+	pinctrl_add_gpio_range(pctl_dev, &priv->range);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/pinctrl/samsung/pinctrl-s3c24xx.c
+++ linux-4.4.0/drivers/pinctrl/samsung/pinctrl-s3c24xx.c
@@ -495,8 +495,10 @@
 		return -ENODEV;
 
 	eint_data = devm_kzalloc(dev, sizeof(*eint_data), GFP_KERNEL);
-	if (!eint_data)
+	if (!eint_data) {
+		of_node_put(eint_np);
 		return -ENOMEM;
+	}
 
 	eint_data->drvdata = d;
 
@@ -508,12 +510,14 @@
 		irq = irq_of_parse_and_map(eint_np, i);
 		if (!irq) {
 			dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
+			of_node_put(eint_np);
 			return -ENXIO;
 		}
 
 		eint_data->parents[i] = irq;
 		irq_set_chained_handler_and_data(irq, handlers[i], eint_data);
 	}
+	of_node_put(eint_np);
 
 	bank = d->pin_banks;
 	for (i = 0; i < d->nr_banks; ++i, ++bank) {
--- linux-4.4.0.orig/drivers/pinctrl/samsung/pinctrl-s3c64xx.c
+++ linux-4.4.0/drivers/pinctrl/samsung/pinctrl-s3c64xx.c
@@ -713,6 +713,7 @@
 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		dev_err(dev, "could not allocate memory for wkup eint data\n");
+		of_node_put(eint0_np);
 		return -ENOMEM;
 	}
 	data->drvdata = d;
@@ -723,6 +724,7 @@
 		irq = irq_of_parse_and_map(eint0_np, i);
 		if (!irq) {
 			dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
+			of_node_put(eint0_np);
 			return -ENXIO;
 		}
 
@@ -730,6 +732,7 @@
 						 s3c64xx_eint0_handlers[i],
 						 data);
 	}
+	of_node_put(eint0_np);
 
 	bank = d->pin_banks;
 	for (i = 0; i < d->nr_banks; ++i, ++bank) {
--- linux-4.4.0.orig/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ linux-4.4.0/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -286,6 +286,7 @@
 						&reserved_maps, num_maps);
 		if (ret < 0) {
 			samsung_dt_free_map(pctldev, *map, *num_maps);
+			of_node_put(np);
 			return ret;
 		}
 	}
@@ -753,8 +754,10 @@
 		if (!of_get_child_count(cfg_np)) {
 			ret = samsung_pinctrl_create_function(dev, drvdata,
 							cfg_np, func);
-			if (ret < 0)
+			if (ret < 0) {
+				of_node_put(cfg_np);
 				return ERR_PTR(ret);
+			}
 			if (ret > 0) {
 				++func;
 				++func_cnt;
@@ -765,8 +768,11 @@
 		for_each_child_of_node(cfg_np, func_np) {
 			ret = samsung_pinctrl_create_function(dev, drvdata,
 						func_np, func);
-			if (ret < 0)
+			if (ret < 0) {
+				of_node_put(func_np);
+				of_node_put(cfg_np);
 				return ERR_PTR(ret);
+			}
 			if (ret > 0) {
 				++func;
 				++func_cnt;
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/core.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/core.c
@@ -543,9 +543,14 @@
 		ret = info->ops->init(pfc);
 		if (ret < 0)
 			return ret;
+
+		/* .init() may have overridden pfc->info */
+		info = pfc->info;
 	}
 
-	pinctrl_provide_dummies();
+	/* Enable dummy states for those platforms without pinctrl support */
+	if (!of_have_populated_dt())
+		pinctrl_provide_dummies();
 
 	ret = sh_pfc_init_ranges(pfc);
 	if (ret < 0)
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-emev2.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-emev2.c
@@ -1263,6 +1263,14 @@
 	"dtv_b",
 };
 
+static const char * const err_rst_reqb_groups[] = {
+	"err_rst_reqb",
+};
+
+static const char * const ext_clki_groups[] = {
+	"ext_clki",
+};
+
 static const char * const iic0_groups[] = {
 	"iic0",
 };
@@ -1285,6 +1293,10 @@
 	"yuv3",
 };
 
+static const char * const lowpwr_groups[] = {
+	"lowpwr",
+};
+
 static const char * const ntsc_groups[] = {
 	"ntsc_clk",
 	"ntsc_data",
@@ -1298,6 +1310,10 @@
 	"pwm1",
 };
 
+static const char * const ref_clko_groups[] = {
+	"ref_clko",
+};
+
 static const char * const sd_groups[] = {
 	"sd_cki",
 };
@@ -1391,13 +1407,17 @@
 	SH_PFC_FUNCTION(cam),
 	SH_PFC_FUNCTION(cf),
 	SH_PFC_FUNCTION(dtv),
+	SH_PFC_FUNCTION(err_rst_reqb),
+	SH_PFC_FUNCTION(ext_clki),
 	SH_PFC_FUNCTION(iic0),
 	SH_PFC_FUNCTION(iic1),
 	SH_PFC_FUNCTION(jtag),
 	SH_PFC_FUNCTION(lcd),
+	SH_PFC_FUNCTION(lowpwr),
 	SH_PFC_FUNCTION(ntsc),
 	SH_PFC_FUNCTION(pwm0),
 	SH_PFC_FUNCTION(pwm1),
+	SH_PFC_FUNCTION(ref_clko),
 	SH_PFC_FUNCTION(sd),
 	SH_PFC_FUNCTION(sdi0),
 	SH_PFC_FUNCTION(sdi1),
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
@@ -1983,7 +1983,7 @@
 	 */
 	185, 186, 187, 188, 189, 190, 191, 192, 174, 161, 204,
 	171, 170, 169, 168, 167, 166, 173, 172, 176, 184, 183, 203,
-	205, 163, 206, 207,
+	205, 163, 206, 207, 158,
 };
 static const unsigned int gether_gmii_mux[] = {
 	ET_ERXD0_MARK, ET_ERXD1_MARK, ET_ERXD2_MARK, ET_ERXD3_MARK,
@@ -2155,6 +2155,7 @@
 	LCD0_D0_MARK, LCD0_D1_MARK, LCD0_D2_MARK, LCD0_D3_MARK,
 	LCD0_D4_MARK, LCD0_D5_MARK, LCD0_D6_MARK, LCD0_D7_MARK,
 	LCD0_D8_MARK, LCD0_D9_MARK, LCD0_D10_MARK, LCD0_D11_MARK,
+	LCD0_D12_MARK, LCD0_D13_MARK, LCD0_D14_MARK, LCD0_D15_MARK,
 	LCD0_D16_MARK, LCD0_D17_MARK, LCD0_D18_PORT163_MARK,
 	LCD0_D19_PORT162_MARK, LCD0_D20_PORT161_MARK, LCD0_D21_PORT158_MARK,
 	LCD0_D22_PORT160_MARK, LCD0_D23_PORT159_MARK,
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
@@ -2324,7 +2324,7 @@
 		FN_ATAG0_A,	0,		FN_REMOCON_B,	0,
 		/* IP0_11_8 [4] */
 		FN_SD1_DAT2_A,	FN_MMC_D2,	0,		FN_BS,
-		FN_ATADIR0_A,	0,		FN_SDSELF_B,	0,
+		FN_ATADIR0_A,	0,		FN_SDSELF_A,	0,
 		FN_PWM4_B,	0,		0,		0,
 		0,		0,		0,		0,
 		/* IP0_7_5 [3] */
@@ -2366,7 +2366,7 @@
 		FN_TS_SDAT0_A,	0,		0,		0,
 		0,		0,		0,		0,
 		/* IP1_10_8 [3] */
-		FN_SD1_CLK_B,	FN_MMC_D6,	0,		FN_A24,
+		FN_SD1_CD_A,	FN_MMC_D6,	0,		FN_A24,
 		FN_DREQ1_A,	0,		FN_HRX0_B,	FN_TS_SPSYNC0_A,
 		/* IP1_7_5 [3] */
 		FN_A23,		FN_HTX0_B,	FN_TX2_B,	FN_DACK2_A,
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -1102,7 +1102,7 @@
 	PINMUX_IPSR_MSEL(IP6_5_3, FMIN_E, SEL_FM_4),
 	PINMUX_IPSR_DATA(IP6_7_6, AUDIO_CLKOUT),
 	PINMUX_IPSR_MSEL(IP6_7_6, MSIOF1_SS1_B, SEL_SOF1_1),
-	PINMUX_IPSR_MSEL(IP6_5_3, TX2, SEL_SCIF2_0),
+	PINMUX_IPSR_MSEL(IP6_7_6, TX2, SEL_SCIF2_0),
 	PINMUX_IPSR_MSEL(IP6_7_6, SCIFA2_TXD, SEL_SCIFA2_0),
 	PINMUX_IPSR_DATA(IP6_9_8, IRQ0),
 	PINMUX_IPSR_MSEL(IP6_9_8, SCIFB1_RXD_D, SEL_SCIFB1_3),
@@ -3059,8 +3059,7 @@
 	RCAR_GP_PIN(6, 4),
 };
 static const unsigned int qspi_data4_b_mux[] = {
-	SPCLK_B_MARK, MOSI_IO0_B_MARK, MISO_IO1_B_MARK,
-	IO2_B_MARK, IO3_B_MARK, SSL_B_MARK,
+	MOSI_IO0_B_MARK, MISO_IO1_B_MARK, IO2_B_MARK, IO3_B_MARK,
 };
 /* - SCIF0 ------------------------------------------------------------------ */
 static const unsigned int scif0_data_pins[] = {
@@ -4171,17 +4170,14 @@
 };
 static const unsigned int vin1_b_data18_mux[] = {
 	/* B */
-	VI1_DATA0_B_MARK, VI1_DATA1_B_MARK,
 	VI1_DATA2_B_MARK, VI1_DATA3_B_MARK,
 	VI1_DATA4_B_MARK, VI1_DATA5_B_MARK,
 	VI1_DATA6_B_MARK, VI1_DATA7_B_MARK,
 	/* G */
-	VI1_G0_B_MARK, VI1_G1_B_MARK,
 	VI1_G2_B_MARK, VI1_G3_B_MARK,
 	VI1_G4_B_MARK, VI1_G5_B_MARK,
 	VI1_G6_B_MARK, VI1_G7_B_MARK,
 	/* R */
-	VI1_R0_B_MARK, VI1_R1_B_MARK,
 	VI1_R2_B_MARK, VI1_R3_B_MARK,
 	VI1_R4_B_MARK, VI1_R5_B_MARK,
 	VI1_R6_B_MARK, VI1_R7_B_MARK,
@@ -4971,7 +4967,7 @@
 	"scifb2_data_b",
 	"scifb2_clk_b",
 	"scifb2_ctrl_b",
-	"scifb0_data_c",
+	"scifb2_data_c",
 	"scifb2_clk_c",
 	"scifb2_data_d",
 };
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
@@ -4046,7 +4046,7 @@
 		FN_AVB_MDC, FN_SSI_SDATA6_B, 0, 0, }
 	},
 	{ PINMUX_CFG_REG_VAR("IPSR9", 0xE6060044, 32,
-			     1, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3) {
+			     1, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3) {
 		/* IP9_31 [1] */
 		0, 0,
 		/* IP9_30_28 [3] */
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-sh7264.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-sh7264.c
@@ -500,17 +500,15 @@
 	SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK,
 	CRX0_MARK, CRX1_MARK,
 	CTX0_MARK, CTX1_MARK,
+	CRX0_CRX1_MARK, CTX0_CTX1_MARK,
 
 	PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
 	PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
 	PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
 	PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
 	IERXD_MARK, IETXD_MARK,
-	CRX0_CRX1_MARK,
 	WDTOVF_MARK,
 
-	CRX0X1_MARK,
-
 	/* DMAC */
 	TEND0_MARK, DACK0_MARK, DREQ0_MARK,
 	TEND1_MARK, DACK1_MARK, DREQ1_MARK,
@@ -998,12 +996,12 @@
 
 	PINMUX_DATA(PJ3_DATA, PJ3MD_00),
 	PINMUX_DATA(CRX1_MARK, PJ3MD_01),
-	PINMUX_DATA(CRX0X1_MARK, PJ3MD_10),
+	PINMUX_DATA(CRX0_CRX1_MARK, PJ3MD_10),
 	PINMUX_DATA(IRQ1_PJ_MARK, PJ3MD_11),
 
 	PINMUX_DATA(PJ2_DATA, PJ2MD_000),
 	PINMUX_DATA(CTX1_MARK, PJ2MD_001),
-	PINMUX_DATA(CRX0_CRX1_MARK, PJ2MD_010),
+	PINMUX_DATA(CTX0_CTX1_MARK, PJ2MD_010),
 	PINMUX_DATA(CS2_MARK, PJ2MD_011),
 	PINMUX_DATA(SCK0_MARK, PJ2MD_100),
 	PINMUX_DATA(LCD_M_DISP_MARK, PJ2MD_101),
@@ -1248,6 +1246,7 @@
 	GPIO_FN(CTX1),
 	GPIO_FN(CRX1),
 	GPIO_FN(CTX0),
+	GPIO_FN(CTX0_CTX1),
 	GPIO_FN(CRX0),
 	GPIO_FN(CRX0_CRX1),
 
@@ -1716,6 +1715,9 @@
 	},
 
 	{ PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+		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, 0, 0,
 		PF12MD_000, PF12MD_001, 0, PF12MD_011,
 		PF12MD_100, PF12MD_101, 0, 0,
 		0, 0, 0, 0, 0, 0, 0, 0 }
@@ -1759,8 +1761,10 @@
 		0, 0, 0, 0, 0, 0, 0, 0,
 		PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
 		PF1MD_100, PF1MD_101, 0, 0,
-		0, 0, 0, 0, 0, 0, 0, 0
-	 }
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+		PF0MD_100, PF0MD_101, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0 }
 	},
 
 	{ PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-sh7269.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-sh7269.c
@@ -740,13 +740,12 @@
 	CRX0_MARK, CTX0_MARK,
 	CRX1_MARK, CTX1_MARK,
 	CRX2_MARK, CTX2_MARK,
-	CRX0_CRX1_MARK,
-	CRX0_CRX1_CRX2_MARK,
-	CTX0CTX1CTX2_MARK,
+	CRX0_CRX1_MARK, CTX0_CTX1_MARK,
+	CRX0_CRX1_CRX2_MARK, CTX0_CTX1_CTX2_MARK,
 	CRX1_PJ22_MARK, CTX1_PJ23_MARK,
 	CRX2_PJ20_MARK, CTX2_PJ21_MARK,
-	CRX0CRX1_PJ22_MARK,
-	CRX0CRX1CRX2_PJ20_MARK,
+	CRX0_CRX1_PJ22_MARK, CTX0_CTX1_PJ23_MARK,
+	CRX0_CRX1_CRX2_PJ20_MARK, CTX0_CTX1_CTX2_PJ21_MARK,
 
 	/* VDC */
 	DV_CLK_MARK,
@@ -824,6 +823,7 @@
 	PINMUX_DATA(CS3_MARK, PC8MD_001),
 	PINMUX_DATA(TXD7_MARK, PC8MD_010),
 	PINMUX_DATA(CTX1_MARK, PC8MD_011),
+	PINMUX_DATA(CTX0_CTX1_MARK, PC8MD_100),
 
 	PINMUX_DATA(PC7_DATA, PC7MD_000),
 	PINMUX_DATA(CKE_MARK, PC7MD_001),
@@ -836,11 +836,12 @@
 	PINMUX_DATA(CAS_MARK, PC6MD_001),
 	PINMUX_DATA(SCK7_MARK, PC6MD_010),
 	PINMUX_DATA(CTX0_MARK, PC6MD_011),
+	PINMUX_DATA(CTX0_CTX1_CTX2_MARK, PC6MD_100),
 
 	PINMUX_DATA(PC5_DATA, PC5MD_000),
 	PINMUX_DATA(RAS_MARK, PC5MD_001),
 	PINMUX_DATA(CRX0_MARK, PC5MD_011),
-	PINMUX_DATA(CTX0CTX1CTX2_MARK, PC5MD_100),
+	PINMUX_DATA(CTX0_CTX1_CTX2_MARK, PC5MD_100),
 	PINMUX_DATA(IRQ0_PC_MARK, PC5MD_101),
 
 	PINMUX_DATA(PC4_DATA, PC4MD_00),
@@ -1292,30 +1293,32 @@
 	PINMUX_DATA(LCD_DATA23_PJ23_MARK, PJ23MD_010),
 	PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011),
 	PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100),
-	PINMUX_DATA(CTX1_MARK, PJ23MD_101),
+	PINMUX_DATA(CTX1_PJ23_MARK, PJ23MD_101),
+	PINMUX_DATA(CTX0_CTX1_PJ23_MARK, PJ23MD_110),
 
 	PINMUX_DATA(PJ22_DATA, PJ22MD_000),
 	PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001),
 	PINMUX_DATA(LCD_DATA22_PJ22_MARK, PJ22MD_010),
 	PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011),
 	PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100),
-	PINMUX_DATA(CRX1_MARK, PJ22MD_101),
-	PINMUX_DATA(CRX0_CRX1_MARK, PJ22MD_110),
+	PINMUX_DATA(CRX1_PJ22_MARK, PJ22MD_101),
+	PINMUX_DATA(CRX0_CRX1_PJ22_MARK, PJ22MD_110),
 
 	PINMUX_DATA(PJ21_DATA, PJ21MD_000),
 	PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001),
 	PINMUX_DATA(LCD_DATA21_PJ21_MARK, PJ21MD_010),
 	PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011),
 	PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100),
-	PINMUX_DATA(CTX2_MARK, PJ21MD_101),
+	PINMUX_DATA(CTX2_PJ21_MARK, PJ21MD_101),
+	PINMUX_DATA(CTX0_CTX1_CTX2_PJ21_MARK, PJ21MD_110),
 
 	PINMUX_DATA(PJ20_DATA, PJ20MD_000),
 	PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001),
 	PINMUX_DATA(LCD_DATA20_PJ20_MARK, PJ20MD_010),
 	PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011),
 	PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100),
-	PINMUX_DATA(CRX2_MARK, PJ20MD_101),
-	PINMUX_DATA(CRX0CRX1CRX2_PJ20_MARK, PJ20MD_110),
+	PINMUX_DATA(CRX2_PJ20_MARK, PJ20MD_101),
+	PINMUX_DATA(CRX0_CRX1_CRX2_PJ20_MARK, PJ20MD_110),
 
 	PINMUX_DATA(PJ19_DATA, PJ19MD_000),
 	PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001),
@@ -1666,12 +1669,24 @@
 	GPIO_FN(WDTOVF),
 
 	/* CAN */
+	GPIO_FN(CTX2),
+	GPIO_FN(CRX2),
 	GPIO_FN(CTX1),
 	GPIO_FN(CRX1),
 	GPIO_FN(CTX0),
 	GPIO_FN(CRX0),
+	GPIO_FN(CTX0_CTX1),
 	GPIO_FN(CRX0_CRX1),
+	GPIO_FN(CTX0_CTX1_CTX2),
 	GPIO_FN(CRX0_CRX1_CRX2),
+	GPIO_FN(CTX2_PJ21),
+	GPIO_FN(CRX2_PJ20),
+	GPIO_FN(CTX1_PJ23),
+	GPIO_FN(CRX1_PJ22),
+	GPIO_FN(CTX0_CTX1_PJ23),
+	GPIO_FN(CRX0_CRX1_PJ22),
+	GPIO_FN(CTX0_CTX1_CTX2_PJ21),
+	GPIO_FN(CRX0_CRX1_CRX2_PJ20),
 
 	/* DMAC */
 	GPIO_FN(TEND0),
@@ -2119,7 +2134,7 @@
 	},
 
 	{ PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
-		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,
 		PC8_IN, PC8_OUT,
 		PC7_IN, PC7_OUT,
 		PC6_IN, PC6_OUT,
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -2672,6 +2672,7 @@
 };
 static const unsigned int tpu4_to3_pins[] = {
 	/* TO */
+	PIN_NUMBER(6, 26),
 };
 static const unsigned int tpu4_to3_mux[] = {
 	TPU4TO3_MARK,
@@ -2894,7 +2895,8 @@
 	"fsic_sclk_out",
 	"fsic_data_in",
 	"fsic_data_out",
-	"fsic_spdif",
+	"fsic_spdif_0",
+	"fsic_spdif_1",
 };
 
 static const char * const fsid_groups[] = {
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pfc-sh7734.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pfc-sh7734.c
@@ -1458,7 +1458,7 @@
 	GPIO_FN(ET0_ETXD2_A),
 	GPIO_FN(EX_CS5), GPIO_FN(SD1_CMD_A), GPIO_FN(ATADIR), GPIO_FN(QSSL_B),
 	GPIO_FN(ET0_ETXD3_A),
-	GPIO_FN(RD_WR), GPIO_FN(TCLK1_B),
+	GPIO_FN(RD_WR), GPIO_FN(TCLK0), GPIO_FN(CAN_CLK_B), GPIO_FN(ET0_ETXD4),
 	GPIO_FN(EX_WAIT0), GPIO_FN(TCLK1_B),
 	GPIO_FN(EX_WAIT1), GPIO_FN(SD1_DAT0_A), GPIO_FN(DREQ2),
 		GPIO_FN(CAN1_TX_C), GPIO_FN(ET0_LINK_C), GPIO_FN(ET0_ETXD5_A),
@@ -1954,7 +1954,7 @@
 	    /* IP3_20 [1] */
 		FN_EX_WAIT0, FN_TCLK1_B,
 	    /* IP3_19_18 [2] */
-		FN_RD_WR, FN_TCLK1_B, 0, 0,
+		FN_RD_WR, FN_TCLK0, FN_CAN_CLK_B, FN_ET0_ETXD4,
 	    /* IP3_17_15 [3] */
 		FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B,
 		FN_ET0_ETXD3_A, 0, 0, 0,
@@ -2218,31 +2218,31 @@
 	    /* IP10_22 [1] */
 		FN_CAN_CLK_A, FN_RX4_D,
 	    /* IP10_21_19 [3] */
-		FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B,
-		FN_LCD_M_DISP_B, 0, 0, 0,
+		FN_AUDIO_CLKOUT, FN_TX1_E, 0, FN_HRTS0_C, FN_FSE_B,
+		FN_LCD_M_DISP_B, 0, 0,
 	    /* IP10_18_16 [3] */
-		FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B,
-		FN_LCD_VEPWC_B, 0, 0, 0,
+		FN_AUDIO_CLKC, FN_SCK1_E, 0, FN_HCTS0_C, FN_FRB_B,
+		FN_LCD_VEPWC_B, 0, 0,
 	    /* IP10_15 [1] */
 		FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
 	    /* IP10_14_12 [3] */
 		FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B,
 		FN_LCD_FLM_B, 0, 0, 0,
 	    /* IP10_11_9 [3] */
-		FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B,
-		FN_LCD_CL2_B, 0, 0, 0,
+		FN_SSI_SDATA3, FN_VI1_7_B, 0, FN_HTX0_C, FN_FWE_B,
+		FN_LCD_CL2_B, 0, 0,
 	    /* IP10_8_6 [3] */
-		FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B,
-		FN_LCD_CL1_B, 0, 0, 0,
+		FN_SSI_SDATA2, FN_VI1_6_B, 0, FN_HRX0_C, FN_FRE_B,
+		FN_LCD_CL1_B, 0, 0,
 	    /* IP10_5_3 [3] */
 		FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B,
-		FN_LCD_DON_B, 0, 0, 0,
+		FN_LCD_DON_B, 0, 0,
 	    /* IP10_2_0 [3] */
 		FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B,
 		FN_LCD_DATA15_B, 0, 0, 0 }
 	},
 	{ PINMUX_CFG_REG_VAR("IPSR11", 0xFFFC0048, 32,
-			3, 1, 2, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) {
+			3, 1, 2, 3, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) {
 	    /* IP11_31_29 [3] */
 	    0, 0, 0, 0, 0, 0, 0, 0,
 	    /* IP11_28 [1] */
--- linux-4.4.0.orig/drivers/pinctrl/sh-pfc/pinctrl.c
+++ linux-4.4.0/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -483,7 +483,8 @@
 
 	switch (param) {
 	case PIN_CONFIG_BIAS_DISABLE:
-		return true;
+		return pin->configs &
+			(SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN);
 
 	case PIN_CONFIG_BIAS_PULL_UP:
 		return pin->configs & SH_PFC_PIN_CFG_PULL_UP;
--- linux-4.4.0.orig/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
+++ linux-4.4.0/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
@@ -811,6 +811,7 @@
 		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D16 */
 		  SUNXI_FUNCTION(0x3, "pata"),		/* ATAD12 */
 		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN6 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* DET */
 		  SUNXI_FUNCTION_IRQ(0x6, 16),		/* EINT16 */
 		  SUNXI_FUNCTION(0x7, "csi1")),		/* D16 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 17),
--- linux-4.4.0.orig/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
+++ linux-4.4.0/drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
@@ -485,12 +485,12 @@
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart2"),		/* RTS */
+		  SUNXI_FUNCTION(0x2, "uart1"),		/* RTS */
 		  SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 8)),	/* PG_EINT8 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart2"),		/* CTS */
+		  SUNXI_FUNCTION(0x2, "uart1"),		/* CTS */
 		  SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 9)),	/* PG_EINT9 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
--- linux-4.4.0.orig/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
+++ linux-4.4.0/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
@@ -407,12 +407,12 @@
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart2"),		/* RTS */
+		  SUNXI_FUNCTION(0x2, "uart1"),		/* RTS */
 		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 8)),	/* PG_EINT8 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart2"),		/* CTS */
+		  SUNXI_FUNCTION(0x2, "uart1"),		/* CTS */
 		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 9)),	/* PG_EINT9 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -485,6 +485,7 @@
 	.pins = sun8i_a33_pins,
 	.npins = ARRAY_SIZE(sun8i_a33_pins),
 	.irq_banks = 2,
+	.irq_bank_base = 1,
 };
 
 static int sun8i_a33_pinctrl_probe(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
+++ linux-4.4.0/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
@@ -394,7 +394,7 @@
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 18),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x3, "owa")),		/* DOUT */
+		  SUNXI_FUNCTION(0x3, "spdif")),	/* DOUT */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 19),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out")),
@@ -568,7 +568,7 @@
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)),	/* PH_EINT11 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)),	/* PH_EINT11 */
 };
 
 static const struct sunxi_pinctrl_desc sun8i_a83t_pinctrl_data = {
--- linux-4.4.0.orig/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
+++ linux-4.4.0/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
@@ -145,19 +145,19 @@
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x3, "mcsi"),		/* MCLK */
-		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)),	/* PB_EINT14 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 14)),	/* PB_EINT14 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x3, "mcsi"),		/* SCK */
 		  SUNXI_FUNCTION(0x4, "i2c4"),		/* SCK */
-		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)),	/* PB_EINT15 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 15)),	/* PB_EINT15 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x3, "mcsi"),		/* SDA */
 		  SUNXI_FUNCTION(0x4, "i2c4"),		/* SDA */
-		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)),	/* PB_EINT16 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 16)),	/* PB_EINT16 */
 
 	/* Hole */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
--- linux-4.4.0.orig/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ linux-4.4.0/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -457,8 +457,8 @@
 	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
 	u32 reg = sunxi_data_reg(offset);
 	u8 index = sunxi_data_offset(offset);
-	u32 set_mux = pctl->desc->irq_read_needs_mux &&
-			test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
+	bool set_mux = pctl->desc->irq_read_needs_mux &&
+		gpiochip_line_is_irq(chip, offset);
 	u32 val;
 
 	if (set_mux)
@@ -578,7 +578,7 @@
 static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-	u32 reg = sunxi_irq_cfg_reg(d->hwirq);
+	u32 reg = sunxi_irq_cfg_reg(d->hwirq, pctl->desc->irq_bank_base);
 	u8 index = sunxi_irq_cfg_offset(d->hwirq);
 	unsigned long flags;
 	u32 regval;
@@ -625,7 +625,8 @@
 static void sunxi_pinctrl_irq_ack(struct irq_data *d)
 {
 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-	u32 status_reg = sunxi_irq_status_reg(d->hwirq);
+	u32 status_reg = sunxi_irq_status_reg(d->hwirq,
+					      pctl->desc->irq_bank_base);
 	u8 status_idx = sunxi_irq_status_offset(d->hwirq);
 
 	/* Clear the IRQ */
@@ -635,7 +636,7 @@
 static void sunxi_pinctrl_irq_mask(struct irq_data *d)
 {
 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-	u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
+	u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base);
 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
 	unsigned long flags;
 	u32 val;
@@ -652,7 +653,7 @@
 static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
 {
 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-	u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
+	u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base);
 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
 	unsigned long flags;
 	u32 val;
@@ -744,7 +745,7 @@
 	if (bank == pctl->desc->irq_banks)
 		return;
 
-	reg = sunxi_irq_status_reg_from_bank(bank);
+	reg = sunxi_irq_status_reg_from_bank(bank, pctl->desc->irq_bank_base);
 	val = readl(pctl->membase + reg);
 
 	if (val) {
@@ -1023,9 +1024,11 @@
 
 	for (i = 0; i < pctl->desc->irq_banks; i++) {
 		/* Mask and clear all IRQs before registering a handler */
-		writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i));
+		writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i,
+						pctl->desc->irq_bank_base));
 		writel(0xffffffff,
-			pctl->membase + sunxi_irq_status_reg_from_bank(i));
+		       pctl->membase + sunxi_irq_status_reg_from_bank(i,
+						pctl->desc->irq_bank_base));
 
 		irq_set_chained_handler_and_data(pctl->irq[i],
 						 sunxi_pinctrl_irq_handler,
--- linux-4.4.0.orig/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ linux-4.4.0/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -97,6 +97,7 @@
 	int				npins;
 	unsigned			pin_base;
 	unsigned			irq_banks;
+	unsigned			irq_bank_base;
 	bool				irq_read_needs_mux;
 };
 
@@ -233,12 +234,12 @@
 	return pin_num * PULL_PINS_BITS;
 }
 
-static inline u32 sunxi_irq_cfg_reg(u16 irq)
+static inline u32 sunxi_irq_cfg_reg(u16 irq, unsigned bank_base)
 {
 	u8 bank = irq / IRQ_PER_BANK;
 	u8 reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04;
 
-	return IRQ_CFG_REG + bank * IRQ_MEM_SIZE + reg;
+	return IRQ_CFG_REG + (bank_base + bank) * IRQ_MEM_SIZE + reg;
 }
 
 static inline u32 sunxi_irq_cfg_offset(u16 irq)
@@ -247,16 +248,16 @@
 	return irq_num * IRQ_CFG_IRQ_BITS;
 }
 
-static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank)
+static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank, unsigned bank_base)
 {
-	return IRQ_CTRL_REG + bank * IRQ_MEM_SIZE;
+	return IRQ_CTRL_REG + (bank_base + bank) * IRQ_MEM_SIZE;
 }
 
-static inline u32 sunxi_irq_ctrl_reg(u16 irq)
+static inline u32 sunxi_irq_ctrl_reg(u16 irq, unsigned bank_base)
 {
 	u8 bank = irq / IRQ_PER_BANK;
 
-	return sunxi_irq_ctrl_reg_from_bank(bank);
+	return sunxi_irq_ctrl_reg_from_bank(bank, bank_base);
 }
 
 static inline u32 sunxi_irq_ctrl_offset(u16 irq)
@@ -265,16 +266,16 @@
 	return irq_num * IRQ_CTRL_IRQ_BITS;
 }
 
-static inline u32 sunxi_irq_status_reg_from_bank(u8 bank)
+static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base)
 {
-	return IRQ_STATUS_REG + bank * IRQ_MEM_SIZE;
+	return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE;
 }
 
-static inline u32 sunxi_irq_status_reg(u16 irq)
+static inline u32 sunxi_irq_status_reg(u16 irq, unsigned bank_base)
 {
 	u8 bank = irq / IRQ_PER_BANK;
 
-	return sunxi_irq_status_reg_from_bank(bank);
+	return sunxi_irq_status_reg_from_bank(bank, bank_base);
 }
 
 static inline u32 sunxi_irq_status_offset(u16 irq)
--- linux-4.4.0.orig/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
+++ linux-4.4.0/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
@@ -73,6 +73,12 @@
 	case UNIPHIER_PIN_PULL_DOWN:
 		pull_dir = "DOWN";
 		break;
+	case UNIPHIER_PIN_PULL_UP_FIXED:
+		pull_dir = "UP(FIXED)";
+		break;
+	case UNIPHIER_PIN_PULL_DOWN_FIXED:
+		pull_dir = "DOWN(FIXED)";
+		break;
 	case UNIPHIER_PIN_PULL_NONE:
 		pull_dir = "NONE";
 		break;
--- linux-4.4.0.orig/drivers/platform/chrome/cros_ec_dev.c
+++ linux-4.4.0/drivers/platform/chrome/cros_ec_dev.c
@@ -147,13 +147,19 @@
 		goto exit;
 	}
 
+	if (u_cmd.outsize != s_cmd->outsize ||
+	    u_cmd.insize != s_cmd->insize) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
 	s_cmd->command += ec->cmd_offset;
 	ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
 	/* Only copy data to userland if data was received. */
 	if (ret < 0)
 		goto exit;
 
-	if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + u_cmd.insize))
+	if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize))
 		ret = -EFAULT;
 exit:
 	kfree(s_cmd);
--- linux-4.4.0.orig/drivers/platform/chrome/cros_ec_proto.c
+++ linux-4.4.0/drivers/platform/chrome/cros_ec_proto.c
@@ -59,12 +59,25 @@
 			struct cros_ec_command *msg)
 {
 	int ret;
+	int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg);
 
 	if (ec_dev->proto_version > 2)
-		ret = ec_dev->pkt_xfer(ec_dev, msg);
+		xfer_fxn = ec_dev->pkt_xfer;
 	else
-		ret = ec_dev->cmd_xfer(ec_dev, msg);
+		xfer_fxn = ec_dev->cmd_xfer;
 
+	if (!xfer_fxn) {
+		/*
+		 * This error can happen if a communication error happened and
+		 * the EC is trying to use protocol v2, on an underlying
+		 * communication mechanism that does not support v2.
+		 */
+		dev_err_once(ec_dev->dev,
+			     "missing EC transfer API, cannot send command\n");
+		return -EIO;
+	}
+
+	ret = (*xfer_fxn)(ec_dev, msg);
 	if (msg->result == EC_RES_IN_PROGRESS) {
 		int i;
 		struct cros_ec_command *status_msg;
@@ -87,7 +100,7 @@
 		for (i = 0; i < EC_COMMAND_RETRIES; i++) {
 			usleep_range(10000, 11000);
 
-			ret = ec_dev->cmd_xfer(ec_dev, status_msg);
+			ret = (*xfer_fxn)(ec_dev, status_msg);
 			if (ret < 0)
 				break;
 
@@ -380,3 +393,20 @@
 	return ret;
 }
 EXPORT_SYMBOL(cros_ec_cmd_xfer);
+
+int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
+			    struct cros_ec_command *msg)
+{
+	int ret;
+
+	ret = cros_ec_cmd_xfer(ec_dev, msg);
+	if (ret < 0) {
+		dev_err(ec_dev->dev, "Command xfer error (err:%d)\n", ret);
+	} else if (msg->result != EC_RES_SUCCESS) {
+		dev_dbg(ec_dev->dev, "Command result (err: %d)\n", msg->result);
+		return -EPROTO;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
--- linux-4.4.0.orig/drivers/platform/chrome/cros_ec_sysfs.c
+++ linux-4.4.0/drivers/platform/chrome/cros_ec_sysfs.c
@@ -187,7 +187,7 @@
 		count += scnprintf(buf + count, PAGE_SIZE - count,
 				   "Build info:    EC error %d\n", msg->result);
 	else {
-		msg->data[sizeof(msg->data) - 1] = '\0';
+		msg->data[EC_HOST_PARAM_SIZE - 1] = '\0';
 		count += scnprintf(buf + count, PAGE_SIZE - count,
 				   "Build info:    %s\n", msg->data);
 	}
--- linux-4.4.0.orig/drivers/platform/goldfish/pdev_bus.c
+++ linux-4.4.0/drivers/platform/goldfish/pdev_bus.c
@@ -157,23 +157,26 @@
 static irqreturn_t goldfish_pdev_bus_interrupt(int irq, void *dev_id)
 {
 	irqreturn_t ret = IRQ_NONE;
+
 	while (1) {
 		u32 op = readl(pdev_bus_base + PDEV_BUS_OP);
-		switch (op) {
-		case PDEV_BUS_OP_DONE:
-			return IRQ_NONE;
 
+		switch (op) {
 		case PDEV_BUS_OP_REMOVE_DEV:
 			goldfish_pdev_remove();
+			ret = IRQ_HANDLED;
 			break;
 
 		case PDEV_BUS_OP_ADD_DEV:
 			goldfish_new_pdev();
+			ret = IRQ_HANDLED;
 			break;
+
+		case PDEV_BUS_OP_DONE:
+		default:
+			return ret;
 		}
-		ret = IRQ_HANDLED;
 	}
-	return ret;
 }
 
 static int goldfish_pdev_bus_probe(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/platform/mips/cpu_hwmon.c
+++ linux-4.4.0/drivers/platform/mips/cpu_hwmon.c
@@ -155,7 +155,7 @@
 
 	cpu_hwmon_dev = hwmon_device_register(NULL);
 	if (IS_ERR(cpu_hwmon_dev)) {
-		ret = -ENOMEM;
+		ret = PTR_ERR(cpu_hwmon_dev);
 		pr_err("hwmon_device_register fail!\n");
 		goto fail_hwmon_device_register;
 	}
--- linux-4.4.0.orig/drivers/platform/x86/Kconfig
+++ linux-4.4.0/drivers/platform/x86/Kconfig
@@ -95,6 +95,7 @@
 	tristate "Dell Laptop Extras"
 	depends on X86
 	depends on DCDBAS
+	depends on DMI
 	depends on BACKLIGHT_CLASS_DEVICE
 	depends on ACPI_VIDEO || ACPI_VIDEO = n
 	depends on RFKILL || RFKILL = n
@@ -110,6 +111,7 @@
 config DELL_WMI
 	tristate "Dell WMI extras"
 	depends on ACPI_WMI
+	depends on DMI
 	depends on INPUT
 	depends on ACPI_VIDEO || ACPI_VIDEO = n
 	select INPUT_SPARSEKMAP
@@ -564,6 +566,7 @@
 config ASUS_NB_WMI
 	tristate "Asus Notebook WMI Driver"
 	depends on ASUS_WMI
+	depends on SERIO_I8042 || SERIO_I8042 = n
 	---help---
 	  This is a driver for newer Asus notebooks. It adds extra features
 	  like wireless radio and bluetooth control, leds, hotkeys, backlight...
@@ -731,6 +734,30 @@
 	  keys as input device, backlight device, tablet and accelerometer
 	  devices.
 
+config INTEL_HID_EVENT
+	tristate "INTEL HID Event"
+	depends on ACPI
+	depends on INPUT
+	select INPUT_SPARSEKMAP
+	help
+	  This driver provides support for the Intel HID Event hotkey interface.
+	  Some laptops require this driver for hotkey support.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called intel_hid.
+
+config INTEL_VBTN
+	tristate "INTEL VIRTUAL BUTTON"
+	depends on ACPI
+	depends on INPUT
+	select INPUT_SPARSEKMAP
+	help
+	  This driver provides support for the Intel Virtual Button interface.
+	  Some laptops require this driver for power button support.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called intel_vbtn.
+
 config INTEL_SCU_IPC
 	bool "Intel SCU IPC Support"
 	depends on X86_INTEL_MID
@@ -879,6 +906,7 @@
 config SAMSUNG_Q10
 	tristate "Samsung Q10 Extras"
 	depends on ACPI
+	depends on BACKLIGHT_LCD_SUPPORT
 	select BACKLIGHT_CLASS_DEVICE
 	---help---
 	  This driver provides support for backlight control on Samsung Q10
@@ -944,4 +972,21 @@
 	depends on ACPI && INPUT
 	---help---
 	  This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3 tablet.
+
+config INTEL_PUNIT_IPC
+	tristate "Intel P-Unit IPC Driver"
+	---help---
+	  This driver provides support for Intel P-Unit Mailbox IPC mechanism,
+	  which is used to bridge the communications between kernel and P-Unit.
+
+config INTEL_TELEMETRY
+	tristate "Intel SoC Telemetry Driver"
+	default n
+	depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64
+	---help---
+	  This driver provides interfaces to configure and use
+	  telemetry for INTEL SoC from APL onwards. It is also
+	  used to get various SoC events and parameters
+	  directly via debugfs files. Various tools may use
+	  this interface for SoC state monitoring.
 endif # X86_PLATFORM_DEVICES
--- linux-4.4.0.orig/drivers/platform/x86/Makefile
+++ linux-4.4.0/drivers/platform/x86/Makefile
@@ -41,6 +41,8 @@
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)	+= toshiba_bluetooth.o
 obj-$(CONFIG_TOSHIBA_HAPS)	+= toshiba_haps.o
 obj-$(CONFIG_TOSHIBA_WMI)	+= toshiba-wmi.o
+obj-$(CONFIG_INTEL_HID_EVENT)	+= intel-hid.o
+obj-$(CONFIG_INTEL_VBTN)	+= intel-vbtn.o
 obj-$(CONFIG_INTEL_SCU_IPC)	+= intel_scu_ipc.o
 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
 obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
@@ -62,3 +64,7 @@
 obj-$(CONFIG_ALIENWARE_WMI)	+= alienware-wmi.o
 obj-$(CONFIG_INTEL_PMC_IPC)	+= intel_pmc_ipc.o
 obj-$(CONFIG_SURFACE_PRO3_BUTTON)	+= surfacepro3_button.o
+obj-$(CONFIG_INTEL_PUNIT_IPC)  += intel_punit_ipc.o
+obj-$(CONFIG_INTEL_TELEMETRY)	+= intel_telemetry_core.o \
+				   intel_telemetry_pltdrv.o \
+				   intel_telemetry_debugfs.o
--- linux-4.4.0.orig/drivers/platform/x86/acer-wmi.c
+++ linux-4.4.0/drivers/platform/x86/acer-wmi.c
@@ -124,10 +124,12 @@
 	{KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} },	/* Display Switch */
 	{KE_IGNORE, 0x81, {KEY_SLEEP} },
 	{KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} },	/* Touch Pad Toggle */
+	{KE_IGNORE, 0x84, {KEY_KBDILLUMTOGGLE} }, /* Automatic Keyboard background light toggle */
 	{KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} },
 	{KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
 	{KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
 	{KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
+	{KE_KEY, 0x87, {KEY_POWER} },
 	{KE_END, 0}
 };
 
@@ -228,6 +230,7 @@
 static int brightness = -1;
 static int threeg = -1;
 static int force_series;
+static int force_caps = -1;
 static bool ec_raw_mode;
 static bool has_type_aa;
 static u16 commun_func_bitmap;
@@ -237,11 +240,13 @@
 module_param(brightness, int, 0444);
 module_param(threeg, int, 0444);
 module_param(force_series, int, 0444);
+module_param(force_caps, int, 0444);
 module_param(ec_raw_mode, bool, 0444);
 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
 MODULE_PARM_DESC(force_series, "Force a different laptop series");
+MODULE_PARM_DESC(force_caps, "Force the capability bitmask to this value");
 MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
 
 struct acer_data {
@@ -1816,11 +1821,24 @@
 	return status;
 }
 
+#define ACER_WMID_ACCEL_HID	"BST0001"
+
 static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
 						void *ctx, void **retval)
 {
+	struct acpi_device *dev;
+
+	if (!strcmp(ctx, "SENR")) {
+		if (acpi_bus_get_device(ah, &dev))
+			return AE_OK;
+		if (strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev)))
+			return AE_OK;
+	} else
+		return AE_OK;
+
 	*(acpi_handle *)retval = ah;
-	return AE_OK;
+
+	return AE_CTRL_TERMINATE;
 }
 
 static int __init acer_wmi_get_handle(const char *name, const char *prop,
@@ -1834,8 +1852,7 @@
 	handle = NULL;
 	status = acpi_get_devices(prop, acer_wmi_get_handle_cb,
 					(void *)name, &handle);
-
-	if (ACPI_SUCCESS(status)) {
+	if (ACPI_SUCCESS(status) && handle) {
 		*ah = handle;
 		return 0;
 	} else {
@@ -1847,7 +1864,7 @@
 {
 	int err;
 
-	err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
+	err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle);
 	if (err)
 		return err;
 
@@ -2137,7 +2154,7 @@
 		}
 		/* WMID always provides brightness methods */
 		interface->capability |= ACER_CAP_BRIGHTNESS;
-	} else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) {
+	} else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa && force_caps == -1) {
 		pr_err("No WMID device detection method found\n");
 		return -ENODEV;
 	}
@@ -2167,6 +2184,9 @@
 	if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
 		interface->capability &= ~ACER_CAP_BRIGHTNESS;
 
+	if (force_caps != -1)
+		interface->capability = force_caps;
+
 	if (wmi_has_guid(WMID_GUID3)) {
 		if (ec_raw_mode) {
 			if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
@@ -2185,10 +2205,11 @@
 		err = acer_wmi_input_setup();
 		if (err)
 			return err;
+		err = acer_wmi_accel_setup();
+		if (err && err != -ENODEV)
+			pr_warn("Cannot enable accelerometer\n");
 	}
 
-	acer_wmi_accel_setup();
-
 	err = platform_driver_register(&acer_platform_driver);
 	if (err) {
 		pr_err("Unable to register platform driver\n");
--- linux-4.4.0.orig/drivers/platform/x86/acerhdf.c
+++ linux-4.4.0/drivers/platform/x86/acerhdf.c
@@ -233,6 +233,7 @@
 	{"Gateway", "LT31",   "v1.3201",  0x55, 0x58, {0x9e, 0x00}, 0},
 	{"Gateway", "LT31",   "v1.3302",  0x55, 0x58, {0x9e, 0x00}, 0},
 	{"Gateway", "LT31",   "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0},
+	{"Gateway", "LT31",   "v1.3307",  0x55, 0x58, {0x9e, 0x00}, 0},
 	/* Packard Bell */
 	{"Packard Bell", "DOA150",  "v0.3104",  0x55, 0x58, {0x21, 0x00}, 0},
 	{"Packard Bell", "DOA150",  "v0.3105",  0x55, 0x58, {0x20, 0x00}, 0},
--- linux-4.4.0.orig/drivers/platform/x86/alienware-wmi.c
+++ linux-4.4.0/drivers/platform/x86/alienware-wmi.c
@@ -449,22 +449,22 @@
 
 	input.length = (acpi_size) sizeof(*in_args);
 	input.pointer = in_args;
-	if (out_data != NULL) {
+	if (out_data) {
 		output.length = ACPI_ALLOCATE_BUFFER;
 		output.pointer = NULL;
 		status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
 					     command, &input, &output);
-	} else
+		if (ACPI_SUCCESS(status)) {
+			obj = (union acpi_object *)output.pointer;
+			if (obj && obj->type == ACPI_TYPE_INTEGER)
+				*out_data = (u32)obj->integer.value;
+		}
+		kfree(output.pointer);
+	} else {
 		status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
 					     command, &input, NULL);
-
-	if (ACPI_SUCCESS(status) && out_data != NULL) {
-		obj = (union acpi_object *)output.pointer;
-		if (obj && obj->type == ACPI_TYPE_INTEGER)
-			*out_data = (u32) obj->integer.value;
 	}
 	return status;
-
 }
 
 static ssize_t show_hdmi_cable(struct device *dev,
@@ -510,7 +510,7 @@
 			return scnprintf(buf, PAGE_SIZE,
 					 "input [gpu] unknown\n");
 	}
-	pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data);
+	pr_err("alienware-wmi: unknown HDMI source status: %u\n", status);
 	return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
 }
 
--- linux-4.4.0.orig/drivers/platform/x86/asus-nb-wmi.c
+++ linux-4.4.0/drivers/platform/x86/asus-nb-wmi.c
@@ -27,6 +27,7 @@
 #include <linux/input/sparse-keymap.h>
 #include <linux/fb.h>
 #include <linux/dmi.h>
+#include <linux/i8042.h>
 
 #include "asus-wmi.h"
 
@@ -55,8 +56,33 @@
 
 static struct quirk_entry *quirks;
 
+static bool asus_q500a_i8042_filter(unsigned char data, unsigned char str,
+			      struct serio *port)
+{
+	static bool extended;
+	bool ret = false;
+
+	if (str & I8042_STR_AUXDATA)
+		return false;
+
+	if (unlikely(data == 0xe1)) {
+		extended = true;
+		ret = true;
+	} else if (unlikely(extended)) {
+		extended = false;
+		ret = true;
+	}
+
+	return ret;
+}
+
 static struct quirk_entry quirk_asus_unknown = {
 	.wapf = 0,
+	.wmi_backlight_set_devstate = true,
+};
+
+static struct quirk_entry quirk_asus_q500a = {
+	.i8042_filter = asus_q500a_i8042_filter,
 };
 
 /*
@@ -67,15 +93,39 @@
 static struct quirk_entry quirk_asus_x55u = {
 	.wapf = 4,
 	.wmi_backlight_power = true,
+	.wmi_backlight_set_devstate = true,
 	.no_display_toggle = true,
 };
 
 static struct quirk_entry quirk_asus_wapf4 = {
 	.wapf = 4,
+	.wmi_backlight_set_devstate = true,
 };
 
 static struct quirk_entry quirk_asus_x200ca = {
 	.wapf = 2,
+	.wmi_backlight_set_devstate = true,
+};
+
+static struct quirk_entry quirk_no_rfkill = {
+	.no_rfkill = true,
+};
+
+static struct quirk_entry quirk_no_rfkill_wapf4 = {
+	.wapf = 4,
+	.no_rfkill = true,
+};
+
+static struct quirk_entry quirk_asus_ux303ub = {
+	.wmi_backlight_native = true,
+};
+
+static struct quirk_entry quirk_asus_x550lb = {
+	.xusb2pr = 0x01D9,
+};
+
+static struct quirk_entry quirk_asus_forceals = {
+	.wmi_force_als_set = true,
 };
 
 static int dmi_matched(const struct dmi_system_id *dmi)
@@ -87,6 +137,15 @@
 static const struct dmi_system_id asus_quirks[] = {
 	{
 		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. Q500A",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Q500A"),
+		},
+		.driver_data = &quirk_asus_q500a,
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "ASUSTeK COMPUTER INC. U32U",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
@@ -101,6 +160,15 @@
 	},
 	{
 		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. X302UA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X302UA"),
+		},
+		.driver_data = &quirk_asus_wapf4,
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "ASUSTeK COMPUTER INC. X401U",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -128,6 +196,15 @@
 	},
 	{
 		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. X45U",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X45U"),
+		},
+		.driver_data = &quirk_asus_wapf4,
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "ASUSTeK COMPUTER INC. X456UA",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -142,7 +219,7 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 			DMI_MATCH(DMI_PRODUCT_NAME, "X456UF"),
 		},
-		.driver_data = &quirk_asus_wapf4,
+		.driver_data = &quirk_no_rfkill_wapf4,
 	},
 	{
 		.callback = dmi_matched,
@@ -297,11 +374,85 @@
 		},
 		.driver_data = &quirk_asus_x200ca,
 	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. X555UB",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X555UB"),
+		},
+		.driver_data = &quirk_no_rfkill,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. N552VW",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N552VW"),
+		},
+		.driver_data = &quirk_no_rfkill,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. U303LB",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "U303LB"),
+		},
+		.driver_data = &quirk_no_rfkill,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. Z550MA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Z550MA"),
+		},
+		.driver_data = &quirk_no_rfkill,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. UX303UB",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"),
+		},
+		.driver_data = &quirk_asus_ux303ub,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. UX330UAK",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"),
+		},
+		.driver_data = &quirk_asus_forceals,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. X550LB",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"),
+		},
+		.driver_data = &quirk_asus_x550lb,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. UX430UQ",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"),
+		},
+		.driver_data = &quirk_asus_forceals,
+	},
 	{},
 };
 
 static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
 {
+	int ret;
+
 	quirks = &quirk_asus_unknown;
 	dmi_check_system(asus_quirks);
 
@@ -313,6 +464,15 @@
 		quirks->wapf = wapf;
 	else
 		wapf = quirks->wapf;
+
+	if (quirks->i8042_filter) {
+		ret = i8042_install_filter(quirks->i8042_filter);
+		if (ret) {
+			pr_warn("Unable to install key filter\n");
+			return;
+		}
+		pr_info("Using i8042 filter function for receiving events\n");
+	}
 }
 
 static const struct key_entry asus_nb_wmi_keymap[] = {
@@ -321,8 +481,7 @@
 	{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
 	{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
 	{ KE_KEY, 0x32, { KEY_MUTE } },
-	{ KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
-	{ KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
+	{ KE_KEY, 0x35, { KEY_SCREENLOCK } },
 	{ KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
 	{ KE_KEY, 0x41, { KEY_NEXTSONG } },
 	{ KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
@@ -374,6 +533,7 @@
 	{ KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
 	{ KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
 	{ KE_IGNORE, 0xC6, },  /* Ambient Light Sensor notification */
+	{ KE_KEY, 0xFA, { KEY_PROG2 } },           /* Lid flip action */
 	{ KE_END, 0},
 };
 
@@ -387,9 +547,33 @@
 	.detect_quirks = asus_nb_wmi_quirks,
 };
 
+static const struct dmi_system_id asus_nb_wmi_blacklist[] __initconst = {
+	{
+		/*
+		 * asus-nb-wm adds no functionality. The T100TA has a detachable
+		 * USB kbd, so no hotkeys and it has no WMI rfkill; and loading
+		 * asus-nb-wm causes the camera LED to turn and _stay_ on.
+		 */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+		},
+	},
+	{
+		/* The Asus T200TA has the same issue as the T100TA */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T200TA"),
+		},
+	},
+	{} /* Terminating entry */
+};
 
 static int __init asus_nb_wmi_init(void)
 {
+	if (dmi_check_system(asus_nb_wmi_blacklist))
+		return -ENODEV;
+
 	return asus_wmi_register_driver(&asus_nb_wmi_driver);
 }
 
--- linux-4.4.0.orig/drivers/platform/x86/asus-wmi.c
+++ linux-4.4.0/drivers/platform/x86/asus-wmi.c
@@ -117,6 +117,7 @@
 #define ASUS_WMI_DEVID_LED6		0x00020016
 
 /* Backlight and Brightness */
+#define ASUS_WMI_DEVID_ALS_ENABLE	0x00050001 /* Ambient Light Sensor */
 #define ASUS_WMI_DEVID_BACKLIGHT	0x00050011
 #define ASUS_WMI_DEVID_BRIGHTNESS	0x00050012
 #define ASUS_WMI_DEVID_KBD_BACKLIGHT	0x00050021
@@ -158,6 +159,9 @@
 #define ASUS_FAN_CTRL_MANUAL		1
 #define ASUS_FAN_CTRL_AUTO		2
 
+#define USB_INTEL_XUSB2PR		0xD0
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI	0x9c31
+
 struct bios_args {
 	u32 arg0;
 	u32 arg1;
@@ -448,13 +452,7 @@
 
 	asus = container_of(work, struct asus_wmi, kbd_led_work);
 
-	/*
-	 * bits 0-2: level
-	 * bit 7: light on/off
-	 */
-	if (asus->kbd_led_wk > 0)
-		ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
-
+	ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
 	asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL);
 }
 
@@ -1082,6 +1080,38 @@
 	return result;
 }
 
+static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
+{
+	struct pci_dev *xhci_pdev;
+	u32 orig_ports_available;
+	u32 ports_available = asus->driver->quirks->xusb2pr;
+
+	xhci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+			PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI,
+			NULL);
+
+	if (!xhci_pdev)
+		return;
+
+	pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
+				&orig_ports_available);
+
+	pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
+				cpu_to_le32(ports_available));
+
+	pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n",
+			orig_ports_available, ports_available);
+}
+
+/*
+ * Some devices dont support or have borcken get_als method
+ * but still support set method.
+ */
+static void asus_wmi_set_als(void)
+{
+	asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL);
+}
+
 /*
  * Hwmon device
  */
@@ -1733,6 +1763,7 @@
 ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA);
 ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER);
 ASUS_WMI_CREATE_DEVICE_ATTR(lid_resume, 0644, ASUS_WMI_DEVID_LID_RESUME);
+ASUS_WMI_CREATE_DEVICE_ATTR(als_enable, 0644, ASUS_WMI_DEVID_ALS_ENABLE);
 
 static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
 			   const char *buf, size_t count)
@@ -1759,6 +1790,7 @@
 	&dev_attr_cardr.attr,
 	&dev_attr_touchpad.attr,
 	&dev_attr_lid_resume.attr,
+	&dev_attr_als_enable.attr,
 	NULL
 };
 
@@ -1779,6 +1811,8 @@
 		devid = ASUS_WMI_DEVID_TOUCHPAD;
 	else if (attr == &dev_attr_lid_resume.attr)
 		devid = ASUS_WMI_DEVID_LID_RESUME;
+	else if (attr == &dev_attr_als_enable.attr)
+		devid = ASUS_WMI_DEVID_ALS_ENABLE;
 
 	if (devid != -1)
 		ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -1870,6 +1904,9 @@
 	int err;
 	u32 retval = -1;
 
+	if (secure_modules())
+		return -EPERM;
+
 	err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);
 
 	if (err < 0)
@@ -1886,6 +1923,9 @@
 	int err;
 	u32 retval = -1;
 
+	if (secure_modules())
+		return -EPERM;
+
 	err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param,
 				    &retval);
 
@@ -1910,6 +1950,9 @@
 	union acpi_object *obj;
 	acpi_status status;
 
+	if (secure_modules())
+		return -EPERM;
+
 	status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID,
 				     1, asus->debug.method_id,
 				     &input, &output);
@@ -2067,9 +2110,14 @@
 	if (err)
 		goto fail_leds;
 
-	err = asus_wmi_rfkill_init(asus);
-	if (err)
-		goto fail_rfkill;
+	if (!asus->driver->quirks->no_rfkill) {
+		err = asus_wmi_rfkill_init(asus);
+		if (err)
+			goto fail_rfkill;
+	}
+
+	if (asus->driver->quirks->wmi_force_als_set)
+		asus_wmi_set_als();
 
 	/* Some Asus desktop boards export an acpi-video backlight interface,
 	   stop this from showing up */
@@ -2080,11 +2128,18 @@
 	if (asus->driver->quirks->wmi_backlight_power)
 		acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
 
+	if (asus->driver->quirks->wmi_backlight_native)
+		acpi_video_set_dmi_backlight_type(acpi_backlight_native);
+
+	if (asus->driver->quirks->xusb2pr)
+		asus_wmi_set_xusb2pr(asus);
+
 	if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
 		err = asus_wmi_backlight_init(asus);
 		if (err && err != -ENODEV)
 			goto fail_backlight;
-	}
+	} else if (asus->driver->quirks->wmi_backlight_set_devstate)
+		err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
 
 	status = wmi_install_notify_handler(asus->driver->event_guid,
 					    asus_wmi_notify, asus);
--- linux-4.4.0.orig/drivers/platform/x86/asus-wmi.h
+++ linux-4.4.0/drivers/platform/x86/asus-wmi.h
@@ -28,6 +28,7 @@
 #define _ASUS_WMI_H_
 
 #include <linux/platform_device.h>
+#include <linux/i8042.h>
 
 #define ASUS_WMI_KEY_IGNORE (-1)
 #define ASUS_WMI_BRN_DOWN	0x20
@@ -38,10 +39,14 @@
 struct asus_wmi;
 
 struct quirk_entry {
+	bool no_rfkill;
 	bool hotplug_wireless;
 	bool scalar_panel_brightness;
 	bool store_backlight_power;
 	bool wmi_backlight_power;
+	bool wmi_backlight_native;
+	bool wmi_force_als_set;
+	bool wmi_backlight_set_devstate;
 	int wapf;
 	/*
 	 * For machines with AMD graphic chips, it will send out WMI event
@@ -50,6 +55,10 @@
 	 * and let the ACPI interrupt to send out the key event.
 	 */
 	int no_display_toggle;
+	u32 xusb2pr;
+
+	bool (*i8042_filter)(unsigned char data, unsigned char str,
+			     struct serio *serio);
 };
 
 struct asus_wmi_driver {
--- linux-4.4.0.orig/drivers/platform/x86/dell-laptop.c
+++ linux-4.4.0/drivers/platform/x86/dell-laptop.c
@@ -43,6 +43,7 @@
 #define KBD_LED_AUTO_50_TOKEN 0x02EB
 #define KBD_LED_AUTO_75_TOKEN 0x02EC
 #define KBD_LED_AUTO_100_TOKEN 0x02F6
+#define KBD_LED_AC_TOKEN 0x0451
 
 /* This structure will be modified by the firmware when we enter
  * system management mode, hence the volatiles */
@@ -139,6 +140,12 @@
 		},
 	},
 	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/
+		},
+	},
+	{
 		.ident = "Dell Computer Corporation",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
@@ -1162,7 +1169,7 @@
  *     bit 2     Pointing stick
  *     bit 3     Any mouse
  *     bits 4-7  Reserved for future use
- *  cbRES2, byte3  Current Timeout
+ *  cbRES2, byte3  Current Timeout on battery
  *     bits 7:6  Timeout units indicator:
  *     00b       Seconds
  *     01b       Minutes
@@ -1174,6 +1181,15 @@
  *  cbRES3, byte0  Current setting of ALS value that turns the light on or off.
  *  cbRES3, byte1  Current ALS reading
  *  cbRES3, byte2  Current keyboard light level.
+ *  cbRES3, byte3  Current timeout on AC Power
+ *     bits 7:6  Timeout units indicator:
+ *     00b       Seconds
+ *     01b       Minutes
+ *     10b       Hours
+ *     11b       Days
+ *     Bits 5:0  Timeout value (0-63) in sec/min/hr/day
+ *     NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte2
+ *     are set upon return from the upon return from the [Get Feature information] call.
  *
  * cbArg1 0x2 = Set New State
  *  cbRES1         Standard return codes (0, -1, -2)
@@ -1196,7 +1212,7 @@
  *     bit 2     Pointing stick
  *     bit 3     Any mouse
  *     bits 4-7  Reserved for future use
- *  cbArg2, byte3  Desired Timeout
+ *  cbArg2, byte3  Desired Timeout on battery
  *     bits 7:6  Timeout units indicator:
  *     00b       Seconds
  *     01b       Minutes
@@ -1205,6 +1221,13 @@
  *     bits 5:0  Timeout value (0-63) in sec/min/hr/day
  *  cbArg3, byte0  Desired setting of ALS value that turns the light on or off.
  *  cbArg3, byte2  Desired keyboard light level.
+ *  cbArg3, byte3  Desired Timeout on AC power
+ *     bits 7:6  Timeout units indicator:
+ *     00b       Seconds
+ *     01b       Minutes
+ *     10b       Hours
+ *     11b       Days
+ *     bits 5:0  Timeout value (0-63) in sec/min/hr/day
  */
 
 
@@ -1250,6 +1273,8 @@
 	u8 triggers;
 	u8 timeout_value;
 	u8 timeout_unit;
+	u8 timeout_value_ac;
+	u8 timeout_unit_ac;
 	u8 als_setting;
 	u8 als_value;
 	u8 level;
@@ -1269,6 +1294,7 @@
 static struct kbd_info kbd_info;
 static bool kbd_als_supported;
 static bool kbd_triggers_supported;
+static bool kbd_timeout_ac_supported;
 
 static u8 kbd_mode_levels[16];
 static int kbd_mode_levels_count;
@@ -1405,6 +1431,8 @@
 	state->als_setting = buffer->output[2] & 0xFF;
 	state->als_value = (buffer->output[2] >> 8) & 0xFF;
 	state->level = (buffer->output[2] >> 16) & 0xFF;
+	state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F;
+	state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3;
 
  out:
 	release_buffer();
@@ -1423,6 +1451,8 @@
 	buffer->input[1] |= (state->timeout_unit & 0x3) << 30;
 	buffer->input[2] = state->als_setting & 0xFF;
 	buffer->input[2] |= (state->level & 0xFF) << 16;
+	buffer->input[2] |= (state->timeout_value_ac & 0x3F) << 24;
+	buffer->input[2] |= (state->timeout_unit_ac & 0x3) << 30;
 	dell_send_request(buffer, 4, 11);
 	ret = buffer->output[0];
 	release_buffer();
@@ -1527,6 +1557,13 @@
 	if (ret)
 		return ret;
 
+	/* NOTE: Old models without KBD_LED_AC_TOKEN token supports only one
+	 *       timeout value which is shared for both battery and AC power
+	 *       settings. So do not try to set AC values on old models.
+	 */
+	if (find_token_location(KBD_LED_AC_TOKEN))
+		kbd_timeout_ac_supported = true;
+
 	kbd_get_state(&state);
 
 	/* NOTE: timeout value is stored in 6 bits so max value is 63 */
@@ -1706,8 +1743,14 @@
 		return ret;
 
 	new_state = state;
-	new_state.timeout_value = value;
-	new_state.timeout_unit = unit;
+
+	if (kbd_timeout_ac_supported && power_supply_is_system_supplied() > 0) {
+		new_state.timeout_value_ac = value;
+		new_state.timeout_unit_ac = unit;
+	} else {
+		new_state.timeout_value = value;
+		new_state.timeout_unit = unit;
+	}
 
 	ret = kbd_set_state_safe(&new_state, &state);
 	if (ret)
@@ -1720,16 +1763,26 @@
 				    struct device_attribute *attr, char *buf)
 {
 	struct kbd_state state;
+	int value;
 	int ret;
 	int len;
+	u8 unit;
 
 	ret = kbd_get_state(&state);
 	if (ret)
 		return ret;
 
-	len = sprintf(buf, "%d", state.timeout_value);
+	if (kbd_timeout_ac_supported && power_supply_is_system_supplied() > 0) {
+		value = state.timeout_value_ac;
+		unit = state.timeout_unit_ac;
+	} else {
+		value = state.timeout_value;
+		unit = state.timeout_unit;
+	}
+
+	len = sprintf(buf, "%d", value);
 
-	switch (state.timeout_unit) {
+	switch (unit) {
 	case KBD_TIMEOUT_SECONDS:
 		return len + sprintf(buf+len, "s\n");
 	case KBD_TIMEOUT_MINUTES:
--- linux-4.4.0.orig/drivers/platform/x86/dell-rbtn.c
+++ linux-4.4.0/drivers/platform/x86/dell-rbtn.c
@@ -28,6 +28,7 @@
 	enum rbtn_type type;
 	struct rfkill *rfkill;
 	struct input_dev *input_dev;
+	bool suspended;
 };
 
 
@@ -220,9 +221,55 @@
 	{ "", 0 },
 };
 
+#ifdef CONFIG_PM_SLEEP
+static void ACPI_SYSTEM_XFACE rbtn_clear_suspended_flag(void *context)
+{
+	struct rbtn_data *rbtn_data = context;
+
+	rbtn_data->suspended = false;
+}
+
+static int rbtn_suspend(struct device *dev)
+{
+	struct acpi_device *device = to_acpi_device(dev);
+	struct rbtn_data *rbtn_data = acpi_driver_data(device);
+
+	rbtn_data->suspended = true;
+
+	return 0;
+}
+
+static int rbtn_resume(struct device *dev)
+{
+	struct acpi_device *device = to_acpi_device(dev);
+	struct rbtn_data *rbtn_data = acpi_driver_data(device);
+	acpi_status status;
+
+	/*
+	 * Upon resume, some BIOSes send an ACPI notification thet triggers
+	 * an unwanted input event. In order to ignore it, we use a flag
+	 * that we set at suspend and clear once we have received the extra
+	 * ACPI notification. Since ACPI notifications are delivered
+	 * asynchronously to drivers, we clear the flag from the workqueue
+	 * used to deliver the notifications. This should be enough
+	 * to have the flag cleared only after we received the extra
+	 * notification, if any.
+	 */
+	status = acpi_os_execute(OSL_NOTIFY_HANDLER,
+			 rbtn_clear_suspended_flag, rbtn_data);
+	if (ACPI_FAILURE(status))
+		rbtn_clear_suspended_flag(rbtn_data);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rbtn_pm_ops, rbtn_suspend, rbtn_resume);
+
 static struct acpi_driver rbtn_driver = {
 	.name = "dell-rbtn",
 	.ids = rbtn_ids,
+	.drv.pm = &rbtn_pm_ops,
 	.ops = {
 		.add = rbtn_add,
 		.remove = rbtn_remove,
@@ -384,6 +431,15 @@
 {
 	struct rbtn_data *rbtn_data = device->driver_data;
 
+	/*
+	 * Some BIOSes send a notification at resume.
+	 * Ignore it to prevent unwanted input events.
+	 */
+	if (rbtn_data->suspended) {
+		dev_dbg(&device->dev, "ACPI notification ignored\n");
+		return;
+	}
+
 	if (event != 0x80) {
 		dev_info(&device->dev, "Received unknown event (0x%x)\n",
 			 event);
--- linux-4.4.0.orig/drivers/platform/x86/dell-smo8800.c
+++ linux-4.4.0/drivers/platform/x86/dell-smo8800.c
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/acpi.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/miscdevice.h>
 
 struct smo8800_device {
--- linux-4.4.0.orig/drivers/platform/x86/dell-wmi.c
+++ linux-4.4.0/drivers/platform/x86/dell-wmi.c
@@ -90,6 +90,9 @@
 	{ KE_IGNORE, 0xe025, { KEY_RESERVED } },
 	{ KE_IGNORE, 0xe026, { KEY_RESERVED } },
 
+	/* LCD Display On/Off Control key */
+	{ KE_KEY,    0xe027, { KEY_DISPLAYTOGGLE } },
+
 	{ KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
 	{ KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
 	{ KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
--- linux-4.4.0.orig/drivers/platform/x86/hp-wmi.c
+++ linux-4.4.0/drivers/platform/x86/hp-wmi.c
@@ -90,7 +90,7 @@
 	u32 command;
 	u32 commandtype;
 	u32 datasize;
-	u32 data;
+	u8 data[128];
 };
 
 struct bios_return {
@@ -199,7 +199,7 @@
 		.command = write ? 0x2 : 0x1,
 		.commandtype = query,
 		.datasize = insize,
-		.data = 0,
+		.data = { 0 },
 	};
 	struct acpi_buffer input = { sizeof(struct bios_args), &args };
 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -207,7 +207,7 @@
 
 	if (WARN_ON(insize > sizeof(args.data)))
 		return -EINVAL;
-	memcpy(&args.data, buffer, insize);
+	memcpy(&args.data[0], buffer, insize);
 
 	wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
 
@@ -249,7 +249,7 @@
 	int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
 				       sizeof(state), sizeof(state));
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 	return state;
 }
 
@@ -259,7 +259,7 @@
 	int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
 				       sizeof(state), sizeof(state));
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 	return state;
 }
 
@@ -269,7 +269,7 @@
 	int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
 				       sizeof(state), sizeof(state));
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 	return state;
 }
 
@@ -280,7 +280,7 @@
 				       sizeof(state), sizeof(state));
 
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 
 	return state & 0x1;
 }
@@ -291,7 +291,7 @@
 	int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
 				       sizeof(state), sizeof(state));
 	if (ret)
-		return ret;
+		return ret < 0 ? ret : -EINVAL;
 
 	return (state & 0x4) ? 1 : 0;
 }
@@ -309,7 +309,7 @@
 
 static int __init hp_wmi_bios_2009_later(void)
 {
-	int state = 0;
+	u8 state[128];
 	int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, 0, &state,
 				       sizeof(state), sizeof(state));
 	if (!ret)
@@ -324,7 +324,7 @@
 	int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &value,
 				       sizeof(value), 0);
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 	return 0;
 }
 
@@ -337,7 +337,7 @@
 	ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
 				   &query, sizeof(query), 0);
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 	return 0;
 }
 
@@ -429,7 +429,7 @@
 	int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 0, &state,
 				       sizeof(state), sizeof(state));
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 	return state;
 }
 
@@ -495,7 +495,7 @@
 	int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
 				       sizeof(tmp), sizeof(tmp));
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 
 	return count;
 }
@@ -516,7 +516,7 @@
 	ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 1, &tmp,
 				       sizeof(tmp), sizeof(tmp));
 	if (ret)
-		return -EINVAL;
+		return ret < 0 ? ret : -EINVAL;
 
 	return count;
 }
@@ -573,10 +573,12 @@
 
 	switch (event_id) {
 	case HPWMI_DOCK_EVENT:
-		input_report_switch(hp_wmi_input_dev, SW_DOCK,
-				    hp_wmi_dock_state());
-		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
-				    hp_wmi_tablet_state());
+		if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
+			input_report_switch(hp_wmi_input_dev, SW_DOCK,
+					    hp_wmi_dock_state());
+		if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
+			input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+					    hp_wmi_tablet_state());
 		input_sync(hp_wmi_input_dev);
 		break;
 	case HPWMI_PARK_HDD:
@@ -649,6 +651,7 @@
 {
 	acpi_status status;
 	int err;
+	int val;
 
 	hp_wmi_input_dev = input_allocate_device();
 	if (!hp_wmi_input_dev)
@@ -659,17 +662,26 @@
 	hp_wmi_input_dev->id.bustype = BUS_HOST;
 
 	__set_bit(EV_SW, hp_wmi_input_dev->evbit);
-	__set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
-	__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+
+	/* Dock */
+	val = hp_wmi_dock_state();
+	if (!(val < 0)) {
+		__set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
+		input_report_switch(hp_wmi_input_dev, SW_DOCK, val);
+	}
+
+	/* Tablet mode */
+	val = hp_wmi_tablet_state();
+	if (!(val < 0)) {
+		__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
+	}
 
 	err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
 	if (err)
 		goto err_free_dev;
 
 	/* Set initial hardware state */
-	input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
-	input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
-			    hp_wmi_tablet_state());
 	input_sync(hp_wmi_input_dev);
 
 	if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later())
@@ -723,6 +735,11 @@
 	if (err)
 		return err;
 
+	err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &wireless,
+				   sizeof(wireless), 0);
+	if (err)
+		return err;
+
 	if (wireless & 0x1) {
 		wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
 					   RFKILL_TYPE_WLAN,
@@ -910,7 +927,7 @@
 	gps_rfkill = NULL;
 	rfkill2_count = 0;
 
-	if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device))
+	if (hp_wmi_rfkill_setup(device))
 		hp_wmi_rfkill2_setup(device);
 
 	err = device_create_file(&device->dev, &dev_attr_display);
@@ -977,10 +994,12 @@
 	 * changed.
 	 */
 	if (hp_wmi_input_dev) {
-		input_report_switch(hp_wmi_input_dev, SW_DOCK,
-				    hp_wmi_dock_state());
-		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
-				    hp_wmi_tablet_state());
+		if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
+			input_report_switch(hp_wmi_input_dev, SW_DOCK,
+					    hp_wmi_dock_state());
+		if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
+			input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+					    hp_wmi_tablet_state());
 		input_sync(hp_wmi_input_dev);
 	}
 
--- linux-4.4.0.orig/drivers/platform/x86/ideapad-laptop.c
+++ linux-4.4.0/drivers/platform/x86/ideapad-laptop.c
@@ -563,6 +563,7 @@
 static const struct key_entry ideapad_keymap[] = {
 	{ KE_KEY, 6,  { KEY_SWITCHVIDEOMODE } },
 	{ KE_KEY, 7,  { KEY_CAMERA } },
+	{ KE_KEY, 8,  { KEY_MICMUTE } },
 	{ KE_KEY, 11, { KEY_F16 } },
 	{ KE_KEY, 13, { KEY_WLAN } },
 	{ KE_KEY, 16, { KEY_PROG1 } },
@@ -805,8 +806,10 @@
 				break;
 			case 13:
 			case 11:
+			case 8:
 			case 7:
 			case 6:
+			case 1:
 				ideapad_input_report(priv, vpc_bit);
 				break;
 			case 5:
@@ -865,6 +868,97 @@
 		},
 	},
 	{
+		.ident = "Lenovo V310-14IKB",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14IKB"),
+		},
+	},
+	{
+		.ident = "Lenovo V310-14ISK",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14ISK"),
+		},
+	},
+	{
+		.ident = "Lenovo V310-15IKB",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15IKB"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad 300-15IBR",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IBR"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad 300-15IKB",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IKB"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad 300S-11IBR",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300S-11BR"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad 310-15ABR",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ABR"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad 310-15IAP",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IAP"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad 310-15ISK",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ISK"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad Y700-14ISK",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-14ISK"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad Y700-15ISK",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad Y700 Touch-15ISK",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"),
+		},
+	},
+	{
+		.ident = "Lenovo ideapad Y700-17ISK",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"),
+		},
+	},
+	{
 		.ident = "Lenovo Yoga 2 11 / 13 / Pro",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -893,6 +987,13 @@
 		},
 	},
 	{
+		.ident = "Lenovo Yoga 700",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 700"),
+		},
+	},
+	{
 		.ident = "Lenovo Yoga 900",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
--- linux-4.4.0.orig/drivers/platform/x86/intel-hid.c
+++ linux-4.4.0/drivers/platform/x86/intel-hid.c
@@ -0,0 +1,374 @@
+/*
+ *  Intel HID event & 5 button array driver
+ *
+ *  Copyright (C) 2015 Alex Hung <alex.hung@canonical.com>
+ *  Copyright (C) 2015 Andrew Lutomirski <luto@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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex Hung");
+
+static const struct acpi_device_id intel_hid_ids[] = {
+	{"INT33D5", 0},
+	{"", 0},
+};
+
+/* In theory, these are HID usages. */
+static const struct key_entry intel_hid_keymap[] = {
+	/* 1: LSuper (Page 0x07, usage 0xE3) -- unclear what to do */
+	/* 2: Toggle SW_ROTATE_LOCK -- easy to implement if seen in wild */
+	{ KE_KEY, 3, { KEY_NUMLOCK } },
+	{ KE_KEY, 4, { KEY_HOME } },
+	{ KE_KEY, 5, { KEY_END } },
+	{ KE_KEY, 6, { KEY_PAGEUP } },
+	{ KE_KEY, 7, { KEY_PAGEDOWN } },
+	{ KE_KEY, 8, { KEY_RFKILL } },
+	{ KE_KEY, 9, { KEY_POWER } },
+	{ KE_KEY, 11, { KEY_SLEEP } },
+	/* 13 has two different meanings in the spec -- ignore it. */
+	{ KE_KEY, 14, { KEY_STOPCD } },
+	{ KE_KEY, 15, { KEY_PLAYPAUSE } },
+	{ KE_KEY, 16, { KEY_MUTE } },
+	{ KE_KEY, 17, { KEY_VOLUMEUP } },
+	{ KE_KEY, 18, { KEY_VOLUMEDOWN } },
+	{ KE_KEY, 19, { KEY_BRIGHTNESSUP } },
+	{ KE_KEY, 20, { KEY_BRIGHTNESSDOWN } },
+	/* 27: wake -- needs special handling */
+	{ KE_END },
+};
+
+/* 5 button array notification value. */
+static const struct key_entry intel_array_keymap[] = {
+	{ KE_KEY,    0xC2, { KEY_LEFTMETA } },                /* Press */
+	{ KE_IGNORE, 0xC3, { KEY_LEFTMETA } },                /* Release */
+	{ KE_KEY,    0xC4, { KEY_VOLUMEUP } },                /* Press */
+	{ KE_IGNORE, 0xC5, { KEY_VOLUMEUP } },                /* Release */
+	{ KE_KEY,    0xC6, { KEY_VOLUMEDOWN } },              /* Press */
+	{ KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } },              /* Release */
+	{ KE_SW,     0xC8, { .sw = { SW_ROTATE_LOCK, 1 } } }, /* Press */
+	{ KE_SW,     0xC9, { .sw = { SW_ROTATE_LOCK, 0 } } }, /* Release */
+	{ KE_KEY,    0xCE, { KEY_POWER } },                   /* Press */
+	{ KE_IGNORE, 0xCF, { KEY_POWER } },                   /* Release */
+	{ KE_END },
+};
+
+struct intel_hid_priv {
+	struct input_dev *input_dev;
+	struct input_dev *array;
+};
+
+static int intel_hid_set_enable(struct device *device, int enable)
+{
+	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+	struct acpi_object_list args = { 1, &arg0 };
+	acpi_status status;
+
+	arg0.integer.value = enable;
+	status = acpi_evaluate_object(ACPI_HANDLE(device), "HDSM", &args, NULL);
+	if (!ACPI_SUCCESS(status)) {
+		dev_warn(device, "failed to %sable hotkeys\n",
+			 enable ? "en" : "dis");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void intel_button_array_enable(struct device *device, bool enable)
+{
+	struct intel_hid_priv *priv = dev_get_drvdata(device);
+	acpi_handle handle = ACPI_HANDLE(device);
+	unsigned long long button_cap;
+	acpi_status status;
+
+	if (!priv->array)
+		return;
+
+	/* Query supported platform features */
+	status = acpi_evaluate_integer(handle, "BTNC", NULL, &button_cap);
+	if (ACPI_FAILURE(status)) {
+		dev_warn(device, "failed to get button capability\n");
+		return;
+	}
+
+	/* Enable|disable features - power button is always enabled */
+	status = acpi_execute_simple_method(handle, "BTNE",
+					    enable ? button_cap : 1);
+	if (ACPI_FAILURE(status))
+		dev_warn(device, "failed to set button capability\n");
+}
+
+static int intel_hid_pl_suspend_handler(struct device *device)
+{
+	intel_hid_set_enable(device, 0);
+	intel_button_array_enable(device, false);
+
+	return 0;
+}
+
+static int intel_hid_pl_resume_handler(struct device *device)
+{
+	intel_hid_set_enable(device, 1);
+	intel_button_array_enable(device, true);
+
+	return 0;
+}
+
+static const struct dev_pm_ops intel_hid_pl_pm_ops = {
+	.freeze  = intel_hid_pl_suspend_handler,
+	.restore  = intel_hid_pl_resume_handler,
+	.suspend  = intel_hid_pl_suspend_handler,
+	.resume  = intel_hid_pl_resume_handler,
+};
+
+static int intel_hid_input_setup(struct platform_device *device)
+{
+	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+	int ret;
+
+	priv->input_dev = input_allocate_device();
+	if (!priv->input_dev)
+		return -ENOMEM;
+
+	ret = sparse_keymap_setup(priv->input_dev, intel_hid_keymap, NULL);
+	if (ret)
+		goto err_free_device;
+
+	priv->input_dev->dev.parent = &device->dev;
+	priv->input_dev->name = "Intel HID events";
+	priv->input_dev->id.bustype = BUS_HOST;
+	set_bit(KEY_RFKILL, priv->input_dev->keybit);
+
+	ret = input_register_device(priv->input_dev);
+	if (ret)
+		goto err_free_device;
+
+	return 0;
+
+err_free_device:
+	input_free_device(priv->input_dev);
+	return ret;
+}
+
+static int intel_button_array_input_setup(struct platform_device *device)
+{
+	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+	int ret;
+
+	/* Setup input device for 5 button array */
+	priv->array = devm_input_allocate_device(&device->dev);
+	if (!priv->array)
+		return -ENOMEM;
+
+	ret = sparse_keymap_setup(priv->array, intel_array_keymap, NULL);
+	if (ret)
+		return ret;
+
+	priv->array->dev.parent = &device->dev;
+	priv->array->name = "Intel HID 5 button array";
+	priv->array->id.bustype = BUS_HOST;
+
+	return input_register_device(priv->array);
+}
+
+static void intel_hid_input_destroy(struct platform_device *device)
+{
+	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+
+	input_unregister_device(priv->input_dev);
+}
+
+static void notify_handler(acpi_handle handle, u32 event, void *context)
+{
+	struct platform_device *device = context;
+	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+	unsigned long long ev_index;
+	acpi_status status;
+
+	/* 0xC0 is for HID events, other values are for 5 button array */
+	if (event != 0xc0) {
+		if (!priv->array ||
+		    !sparse_keymap_report_event(priv->array, event, 1, true))
+			dev_info(&device->dev, "unknown event 0x%x\n", event);
+		return;
+	}
+
+	status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index);
+	if (!ACPI_SUCCESS(status)) {
+		dev_warn(&device->dev, "failed to get event index\n");
+		return;
+	}
+
+	if (!sparse_keymap_report_event(priv->input_dev, ev_index, 1, true))
+		dev_info(&device->dev, "unknown event index 0x%llx\n",
+			 ev_index);
+}
+
+static int intel_hid_probe(struct platform_device *device)
+{
+	acpi_handle handle = ACPI_HANDLE(&device->dev);
+	unsigned long long event_cap, mode;
+	struct intel_hid_priv *priv;
+	acpi_status status;
+	int err;
+
+	status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode);
+	if (!ACPI_SUCCESS(status)) {
+		dev_warn(&device->dev, "failed to read mode\n");
+		return -ENODEV;
+	}
+
+	if (mode != 0) {
+		/*
+		 * This driver only implements "simple" mode.  There appear
+		 * to be no other modes, but we should be paranoid and check
+		 * for compatibility.
+		 */
+		dev_info(&device->dev, "platform is not in simple mode\n");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	dev_set_drvdata(&device->dev, priv);
+
+	err = intel_hid_input_setup(device);
+	if (err) {
+		pr_err("Failed to setup Intel HID hotkeys\n");
+		return err;
+	}
+
+	/* Setup 5 button array */
+	status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
+	if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) {
+		dev_info(&device->dev, "platform supports 5 button array\n");
+		err = intel_button_array_input_setup(device);
+		if (err)
+			pr_err("Failed to setup Intel 5 button array hotkeys\n");
+	}
+
+	status = acpi_install_notify_handler(handle,
+					     ACPI_DEVICE_NOTIFY,
+					     notify_handler,
+					     device);
+	if (ACPI_FAILURE(status)) {
+		err = -EBUSY;
+		goto err_remove_input;
+	}
+
+	err = intel_hid_set_enable(&device->dev, 1);
+	if (err)
+		goto err_remove_notify;
+
+	if (priv->array) {
+		intel_button_array_enable(&device->dev, true);
+
+		/* Call button load method to enable HID power button */
+		status = acpi_evaluate_object(handle, "BTNL", NULL, NULL);
+		if (ACPI_FAILURE(status))
+			dev_warn(&device->dev,
+				 "failed to enable HID power button\n");
+	}
+
+	return 0;
+
+err_remove_notify:
+	acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
+
+err_remove_input:
+	intel_hid_input_destroy(device);
+
+	return err;
+}
+
+static int intel_hid_remove(struct platform_device *device)
+{
+	acpi_handle handle = ACPI_HANDLE(&device->dev);
+
+	acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
+	intel_hid_input_destroy(device);
+	intel_hid_set_enable(&device->dev, 0);
+	intel_button_array_enable(&device->dev, false);
+
+	/*
+	 * Even if we failed to shut off the event stream, we can still
+	 * safely detach from the device.
+	 */
+	return 0;
+}
+
+static struct platform_driver intel_hid_pl_driver = {
+	.driver = {
+		.name = "intel-hid",
+		.acpi_match_table = intel_hid_ids,
+		.pm = &intel_hid_pl_pm_ops,
+	},
+	.probe = intel_hid_probe,
+	.remove = intel_hid_remove,
+};
+MODULE_DEVICE_TABLE(acpi, intel_hid_ids);
+
+/*
+ * Unfortunately, some laptops provide a _HID="INT33D5" device with
+ * _CID="PNP0C02".  This causes the pnpacpi scan driver to claim the
+ * ACPI node, so no platform device will be created.  The pnpacpi
+ * driver rejects this device in subsequent processing, so no physical
+ * node is created at all.
+ *
+ * As a workaround until the ACPI core figures out how to handle
+ * this corner case, manually ask the ACPI platform device code to
+ * claim the ACPI node.
+ */
+static acpi_status __init
+check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	const struct acpi_device_id *ids = context;
+	struct acpi_device *dev;
+
+	if (acpi_bus_get_device(handle, &dev) != 0)
+		return AE_OK;
+
+	if (acpi_match_device_ids(dev, ids) == 0)
+		if (acpi_create_platform_device(dev))
+			dev_info(&dev->dev,
+				 "intel-hid: created platform device\n");
+
+	return AE_OK;
+}
+
+static int __init intel_hid_init(void)
+{
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+			    ACPI_UINT32_MAX, check_acpi_dev, NULL,
+			    (void *)intel_hid_ids, NULL);
+
+	return platform_driver_register(&intel_hid_pl_driver);
+}
+module_init(intel_hid_init);
+
+static void __exit intel_hid_exit(void)
+{
+	platform_driver_unregister(&intel_hid_pl_driver);
+}
+module_exit(intel_hid_exit);
--- linux-4.4.0.orig/drivers/platform/x86/intel-vbtn.c
+++ linux-4.4.0/drivers/platform/x86/intel-vbtn.c
@@ -0,0 +1,188 @@
+/*
+ *  Intel Virtual Button driver for Windows 8.1+
+ *
+ *  Copyright (C) 2016 AceLan Kao <acelan.kao@canonical.com>
+ *  Copyright (C) 2016 Alex Hung <alex.hung@canonical.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("AceLan Kao");
+
+static const struct acpi_device_id intel_vbtn_ids[] = {
+	{"INT33D6", 0},
+	{"", 0},
+};
+
+/* In theory, these are HID usages. */
+static const struct key_entry intel_vbtn_keymap[] = {
+	{ KE_IGNORE, 0xC0, { KEY_POWER } },	/* power key press */
+	{ KE_KEY, 0xC1, { KEY_POWER } },	/* power key release */
+	{ KE_END },
+};
+
+struct intel_vbtn_priv {
+	struct input_dev *input_dev;
+};
+
+static int intel_vbtn_input_setup(struct platform_device *device)
+{
+	struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
+	int ret;
+
+	priv->input_dev = input_allocate_device();
+	if (!priv->input_dev)
+		return -ENOMEM;
+
+	ret = sparse_keymap_setup(priv->input_dev, intel_vbtn_keymap, NULL);
+	if (ret)
+		goto err_free_device;
+
+	priv->input_dev->dev.parent = &device->dev;
+	priv->input_dev->name = "Intel Virtual Button driver";
+	priv->input_dev->id.bustype = BUS_HOST;
+
+	ret = input_register_device(priv->input_dev);
+	if (ret)
+		goto err_free_device;
+
+	return 0;
+
+err_free_device:
+	input_free_device(priv->input_dev);
+	return ret;
+}
+
+static void intel_vbtn_input_destroy(struct platform_device *device)
+{
+	struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
+
+	input_unregister_device(priv->input_dev);
+}
+
+static void notify_handler(acpi_handle handle, u32 event, void *context)
+{
+	struct platform_device *device = context;
+	struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
+
+	if (!sparse_keymap_report_event(priv->input_dev, event, 1, true))
+		dev_info(&device->dev, "unknown event index 0x%x\n",
+			 event);
+}
+
+static int intel_vbtn_probe(struct platform_device *device)
+{
+	acpi_handle handle = ACPI_HANDLE(&device->dev);
+	struct intel_vbtn_priv *priv;
+	acpi_status status;
+	int err;
+
+	status = acpi_evaluate_object(handle, "VBDL", NULL, NULL);
+	if (!ACPI_SUCCESS(status)) {
+		dev_warn(&device->dev, "failed to read Intel Virtual Button driver\n");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	dev_set_drvdata(&device->dev, priv);
+
+	err = intel_vbtn_input_setup(device);
+	if (err) {
+		pr_err("Failed to setup Intel Virtual Button\n");
+		return err;
+	}
+
+	status = acpi_install_notify_handler(handle,
+					     ACPI_DEVICE_NOTIFY,
+					     notify_handler,
+					     device);
+	if (ACPI_FAILURE(status)) {
+		err = -EBUSY;
+		goto err_remove_input;
+	}
+
+	return 0;
+
+err_remove_input:
+	intel_vbtn_input_destroy(device);
+
+	return err;
+}
+
+static int intel_vbtn_remove(struct platform_device *device)
+{
+	acpi_handle handle = ACPI_HANDLE(&device->dev);
+
+	intel_vbtn_input_destroy(device);
+	acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
+
+	/*
+	 * Even if we failed to shut off the event stream, we can still
+	 * safely detach from the device.
+	 */
+	return 0;
+}
+
+static struct platform_driver intel_vbtn_pl_driver = {
+	.driver = {
+		.name = "intel-vbtn",
+		.acpi_match_table = intel_vbtn_ids,
+	},
+	.probe = intel_vbtn_probe,
+	.remove = intel_vbtn_remove,
+};
+MODULE_DEVICE_TABLE(acpi, intel_vbtn_ids);
+
+static acpi_status __init
+check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	const struct acpi_device_id *ids = context;
+	struct acpi_device *dev;
+
+	if (acpi_bus_get_device(handle, &dev) != 0)
+		return AE_OK;
+
+	if (acpi_match_device_ids(dev, ids) == 0)
+		if (acpi_create_platform_device(dev))
+			dev_info(&dev->dev,
+				 "intel-vbtn: created platform device\n");
+
+	return AE_OK;
+}
+
+static int __init intel_vbtn_init(void)
+{
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+			    ACPI_UINT32_MAX, check_acpi_dev, NULL,
+			    (void *)intel_vbtn_ids, NULL);
+
+	return platform_driver_register(&intel_vbtn_pl_driver);
+}
+module_init(intel_vbtn_init);
+
+static void __exit intel_vbtn_exit(void)
+{
+	platform_driver_unregister(&intel_vbtn_pl_driver);
+}
+module_exit(intel_vbtn_exit);
--- linux-4.4.0.orig/drivers/platform/x86/intel_ips.c
+++ linux-4.4.0/drivers/platform/x86/intel_ips.c
@@ -74,6 +74,7 @@
 #include <linux/timer.h>
 #include <linux/dmi.h>
 #include <drm/i915_drm.h>
+#include <drm/i915_drm_bpo.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
 #include "intel_ips.h"
@@ -251,6 +252,9 @@
 static const int IPS_ADJUST_PERIOD = 5000; /* ms */
 static bool late_i915_load = false;
 
+int i915_bpo_enabled = 0;
+EXPORT_SYMBOL(i915_bpo_enabled);
+
 /* For initial average collection */
 static const int IPS_SAMPLE_PERIOD = 200; /* ms */
 static const int IPS_SAMPLE_WINDOW = 5000; /* 5s moving window of samples */
@@ -1421,8 +1425,43 @@
  * enable graphics turbo, otherwise we must disable it to avoid exceeding
  * thermal and power limits in the MCP.
  */
+static bool ips_get_i915_bpo_syms(struct ips_driver *ips)
+{
+	ips->read_mch_val = symbol_get(i915_bpo_read_mch_val);
+	if (!ips->read_mch_val)
+		goto out_err;
+	ips->gpu_raise = symbol_get(i915_bpo_gpu_raise);
+	if (!ips->gpu_raise)
+		goto out_put_mch;
+	ips->gpu_lower = symbol_get(i915_bpo_gpu_lower);
+	if (!ips->gpu_lower)
+		goto out_put_raise;
+	ips->gpu_busy = symbol_get(i915_bpo_gpu_busy);
+	if (!ips->gpu_busy)
+		goto out_put_lower;
+	ips->gpu_turbo_disable = symbol_get(i915_bpo_gpu_turbo_disable);
+	if (!ips->gpu_turbo_disable)
+		goto out_put_busy;
+
+	return true;
+
+out_put_busy:
+	symbol_put(i915_bpo_gpu_busy);
+out_put_lower:
+	symbol_put(i915_bpo_gpu_lower);
+out_put_raise:
+	symbol_put(i915_bpo_gpu_raise);
+out_put_mch:
+	symbol_put(i915_bpo_read_mch_val);
+out_err:
+	return false;
+}
+
 static bool ips_get_i915_syms(struct ips_driver *ips)
 {
+	if (ips_get_i915_bpo_syms(ips) != false)
+		return true;
+
 	ips->read_mch_val = symbol_get(i915_read_mch_val);
 	if (!ips->read_mch_val)
 		goto out_err;
@@ -1501,6 +1540,14 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook"),
 		},
 	},
+	{
+		.callback = ips_blacklist_callback,
+		.ident = "G60JX",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "G60JX"),
+		},
+	},
 	{ }	/* terminating entry */
 };
 
--- linux-4.4.0.orig/drivers/platform/x86/intel_mid_powerbtn.c
+++ linux-4.4.0/drivers/platform/x86/intel_mid_powerbtn.c
@@ -77,7 +77,7 @@
 
 	input_set_capability(input, EV_KEY, KEY_POWER);
 
-	error = request_threaded_irq(irq, NULL, mfld_pb_isr, 0,
+	error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_ONESHOT,
 				     DRIVER_NAME, input);
 	if (error) {
 		dev_err(&pdev->dev, "Unable to request irq %d for mfld power"
--- linux-4.4.0.orig/drivers/platform/x86/intel_mid_thermal.c
+++ linux-4.4.0/drivers/platform/x86/intel_mid_thermal.c
@@ -415,6 +415,7 @@
 	return td_info;
 }
 
+#ifdef CONFIG_PM_SLEEP
 /**
  * mid_thermal_resume - resume routine
  * @dev: device structure
@@ -442,6 +443,7 @@
 	 */
 	return configure_adc(0);
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(mid_thermal_pm,
 			 mid_thermal_suspend, mid_thermal_resume);
@@ -550,6 +552,7 @@
 	{ "msic_thermal", 1 },
 	{ }
 };
+MODULE_DEVICE_TABLE(platform, therm_id_table);
 
 static struct platform_driver mid_thermal_driver = {
 	.driver = {
--- linux-4.4.0.orig/drivers/platform/x86/intel_pmc_ipc.c
+++ linux-4.4.0/drivers/platform/x86/intel_pmc_ipc.c
@@ -68,8 +68,13 @@
 #define PLAT_RESOURCE_IPC_INDEX		0
 #define PLAT_RESOURCE_IPC_SIZE		0x1000
 #define PLAT_RESOURCE_GCR_SIZE		0x1000
-#define PLAT_RESOURCE_PUNIT_DATA_INDEX	1
-#define PLAT_RESOURCE_PUNIT_INTER_INDEX	2
+#define PLAT_RESOURCE_BIOS_DATA_INDEX	1
+#define PLAT_RESOURCE_BIOS_IFACE_INDEX	2
+#define PLAT_RESOURCE_TELEM_SSRAM_INDEX	3
+#define PLAT_RESOURCE_ISP_DATA_INDEX	4
+#define PLAT_RESOURCE_ISP_IFACE_INDEX	5
+#define PLAT_RESOURCE_GTD_DATA_INDEX	6
+#define PLAT_RESOURCE_GTD_IFACE_INDEX	7
 #define PLAT_RESOURCE_ACPI_IO_INDEX	0
 
 /*
@@ -84,6 +89,10 @@
 #define TCO_BASE_OFFSET			0x60
 #define TCO_REGS_SIZE			16
 #define PUNIT_DEVICE_NAME		"intel_punit_ipc"
+#define TELEMETRY_DEVICE_NAME		"intel_telemetry"
+#define TELEM_SSRAM_SIZE		240
+#define TELEM_PMC_SSRAM_OFFSET		0x1B00
+#define TELEM_PUNIT_SSRAM_OFFSET	0x1A00
 
 static const int iTCO_version = 3;
 
@@ -105,11 +114,15 @@
 	int gcr_size;
 
 	/* punit */
-	resource_size_t punit_base;
-	int punit_size;
-	resource_size_t punit_base2;
-	int punit_size2;
 	struct platform_device *punit_dev;
+
+	/* Telemetry */
+	resource_size_t telem_pmc_ssram_base;
+	resource_size_t telem_punit_ssram_base;
+	int telem_pmc_ssram_size;
+	int telem_punit_ssram_size;
+	u8 telem_res_inval;
+	struct platform_device *telemetry_dev;
 } ipcdev;
 
 static char *ipc_err_sources[] = {
@@ -444,9 +457,22 @@
 	.attrs = intel_ipc_attrs,
 };
 
-#define PUNIT_RESOURCE_INTER		1
-static struct resource punit_res[] = {
-	/* Punit */
+static struct resource punit_res_array[] = {
+	/* Punit BIOS */
+	{
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.flags = IORESOURCE_MEM,
+	},
+	/* Punit ISP */
+	{
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.flags = IORESOURCE_MEM,
+	},
+	/* Punit GTD */
 	{
 		.flags = IORESOURCE_MEM,
 	},
@@ -478,10 +504,21 @@
 	.version = 3,
 };
 
+#define TELEMETRY_RESOURCE_PUNIT_SSRAM	0
+#define TELEMETRY_RESOURCE_PMC_SSRAM	1
+static struct resource telemetry_res[] = {
+	/*Telemetry*/
+	{
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.flags = IORESOURCE_MEM,
+	},
+};
+
 static int ipc_create_punit_device(void)
 {
 	struct platform_device *pdev;
-	struct resource *res;
 	int ret;
 
 	pdev = platform_device_alloc(PUNIT_DEVICE_NAME, -1);
@@ -491,17 +528,8 @@
 	}
 
 	pdev->dev.parent = ipcdev.dev;
-
-	res = punit_res;
-	res->start = ipcdev.punit_base;
-	res->end = res->start + ipcdev.punit_size - 1;
-
-	res = punit_res + PUNIT_RESOURCE_INTER;
-	res->start = ipcdev.punit_base2;
-	res->end = res->start + ipcdev.punit_size2 - 1;
-
-	ret = platform_device_add_resources(pdev, punit_res,
-					    ARRAY_SIZE(punit_res));
+	ret = platform_device_add_resources(pdev, punit_res_array,
+					    ARRAY_SIZE(punit_res_array));
 	if (ret) {
 		dev_err(ipcdev.dev, "Failed to add platform punit resources\n");
 		goto err;
@@ -571,6 +599,51 @@
 	return ret;
 }
 
+static int ipc_create_telemetry_device(void)
+{
+	struct platform_device *pdev;
+	struct resource *res;
+	int ret;
+
+	pdev = platform_device_alloc(TELEMETRY_DEVICE_NAME, -1);
+	if (!pdev) {
+		dev_err(ipcdev.dev,
+			"Failed to allocate telemetry platform device\n");
+		return -ENOMEM;
+	}
+
+	pdev->dev.parent = ipcdev.dev;
+
+	res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM;
+	res->start = ipcdev.telem_punit_ssram_base;
+	res->end = res->start + ipcdev.telem_punit_ssram_size - 1;
+
+	res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM;
+	res->start = ipcdev.telem_pmc_ssram_base;
+	res->end = res->start + ipcdev.telem_pmc_ssram_size - 1;
+
+	ret = platform_device_add_resources(pdev, telemetry_res,
+					    ARRAY_SIZE(telemetry_res));
+	if (ret) {
+		dev_err(ipcdev.dev,
+			"Failed to add telemetry platform resources\n");
+		goto err;
+	}
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		dev_err(ipcdev.dev,
+			"Failed to add telemetry platform device\n");
+		goto err;
+	}
+	ipcdev.telemetry_dev = pdev;
+
+	return 0;
+err:
+	platform_device_put(pdev);
+	return ret;
+}
+
 static int ipc_create_pmc_devices(void)
 {
 	int ret;
@@ -585,12 +658,20 @@
 		dev_err(ipcdev.dev, "Failed to add punit platform device\n");
 		platform_device_unregister(ipcdev.tco_dev);
 	}
+
+	if (!ipcdev.telem_res_inval) {
+		ret = ipc_create_telemetry_device();
+		if (ret)
+			dev_warn(ipcdev.dev,
+				"Failed to add telemetry platform device\n");
+	}
+
 	return ret;
 }
 
 static int ipc_plat_get_res(struct platform_device *pdev)
 {
-	struct resource *res;
+	struct resource *res, *punit_res;
 	void __iomem *addr;
 	int size;
 
@@ -603,32 +684,68 @@
 	size = resource_size(res);
 	ipcdev.acpi_io_base = res->start;
 	ipcdev.acpi_io_size = size;
-	dev_info(&pdev->dev, "io res: %llx %x\n",
-		 (long long)res->start, (int)resource_size(res));
+	dev_info(&pdev->dev, "io res: %pR\n", res);
 
+	/* This is index 0 to cover BIOS data register */
+	punit_res = punit_res_array;
 	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_PUNIT_DATA_INDEX);
+				    PLAT_RESOURCE_BIOS_DATA_INDEX);
 	if (!res) {
-		dev_err(&pdev->dev, "Failed to get punit resource\n");
+		dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
 		return -ENXIO;
 	}
-	size = resource_size(res);
-	ipcdev.punit_base = res->start;
-	ipcdev.punit_size = size;
-	dev_info(&pdev->dev, "punit data res: %llx %x\n",
-		 (long long)res->start, (int)resource_size(res));
+	*punit_res = *res;
+	dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_PUNIT_INTER_INDEX);
+				    PLAT_RESOURCE_BIOS_IFACE_INDEX);
 	if (!res) {
-		dev_err(&pdev->dev, "Failed to get punit inter resource\n");
+		dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
 		return -ENXIO;
 	}
-	size = resource_size(res);
-	ipcdev.punit_base2 = res->start;
-	ipcdev.punit_size2 = size;
-	dev_info(&pdev->dev, "punit interface res: %llx %x\n",
-		 (long long)res->start, (int)resource_size(res));
+	/* This is index 1 to cover BIOS interface register */
+	*++punit_res = *res;
+	dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM,
+				    PLAT_RESOURCE_ISP_DATA_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get res of punit ISP data\n");
+		return -ENXIO;
+	}
+	/* This is index 2 to cover ISP data register */
+	*++punit_res = *res;
+	dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM,
+				    PLAT_RESOURCE_ISP_IFACE_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get res of punit ISP iface\n");
+		return -ENXIO;
+	}
+	/* This is index 3 to cover ISP interface register */
+	*++punit_res = *res;
+	dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM,
+				    PLAT_RESOURCE_GTD_DATA_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get res of punit GTD data\n");
+		return -ENXIO;
+	}
+	/* This is index 4 to cover GTD data register */
+	*++punit_res = *res;
+	dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM,
+				    PLAT_RESOURCE_GTD_IFACE_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get res of punit GTD iface\n");
+		return -ENXIO;
+	}
+	/* This is index 5 to cover GTD interface register */
+	*++punit_res = *res;
+	dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM,
 				    PLAT_RESOURCE_IPC_INDEX);
@@ -651,8 +768,23 @@
 
 	ipcdev.gcr_base = res->start + size;
 	ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE;
-	dev_info(&pdev->dev, "ipc res: %llx %x\n",
-		 (long long)res->start, (int)resource_size(res));
+	dev_info(&pdev->dev, "ipc res: %pR\n", res);
+
+	ipcdev.telem_res_inval = 0;
+	res = platform_get_resource(pdev, IORESOURCE_MEM,
+				    PLAT_RESOURCE_TELEM_SSRAM_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n");
+		ipcdev.telem_res_inval = 1;
+	} else {
+		ipcdev.telem_punit_ssram_base = res->start +
+						TELEM_PUNIT_SSRAM_OFFSET;
+		ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE;
+		ipcdev.telem_pmc_ssram_base = res->start +
+						TELEM_PMC_SSRAM_OFFSET;
+		ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE;
+		dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res);
+	}
 
 	return 0;
 }
@@ -711,6 +843,7 @@
 err_irq:
 	platform_device_unregister(ipcdev.tco_dev);
 	platform_device_unregister(ipcdev.punit_dev);
+	platform_device_unregister(ipcdev.telemetry_dev);
 err_device:
 	iounmap(ipcdev.ipc_base);
 	res = platform_get_resource(pdev, IORESOURCE_MEM,
@@ -728,6 +861,7 @@
 	free_irq(ipcdev.irq, &ipcdev);
 	platform_device_unregister(ipcdev.tco_dev);
 	platform_device_unregister(ipcdev.punit_dev);
+	platform_device_unregister(ipcdev.telemetry_dev);
 	iounmap(ipcdev.ipc_base);
 	res = platform_get_resource(pdev, IORESOURCE_MEM,
 				    PLAT_RESOURCE_IPC_INDEX);
--- linux-4.4.0.orig/drivers/platform/x86/intel_punit_ipc.c
+++ linux-4.4.0/drivers/platform/x86/intel_punit_ipc.c
@@ -0,0 +1,342 @@
+/*
+ * Driver for the Intel P-Unit Mailbox IPC mechanism
+ *
+ * (C) Copyright 2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The heart of the P-Unit is the Foxton microcontroller and its firmware,
+ * which provide mailbox interface for power management usage.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/intel_punit_ipc.h>
+
+/* IPC Mailbox registers */
+#define OFFSET_DATA_LOW		0x0
+#define OFFSET_DATA_HIGH	0x4
+/* bit field of interface register */
+#define	CMD_RUN			BIT(31)
+#define	CMD_ERRCODE_MASK	GENMASK(7, 0)
+#define	CMD_PARA1_SHIFT		8
+#define	CMD_PARA2_SHIFT		16
+
+#define CMD_TIMEOUT_SECONDS	1
+
+enum {
+	BASE_DATA = 0,
+	BASE_IFACE,
+	BASE_MAX,
+};
+
+typedef struct {
+	struct device *dev;
+	struct mutex lock;
+	int irq;
+	struct completion cmd_complete;
+	/* base of interface and data registers */
+	void __iomem *base[RESERVED_IPC][BASE_MAX];
+	IPC_TYPE type;
+} IPC_DEV;
+
+static IPC_DEV *punit_ipcdev;
+
+static inline u32 ipc_read_status(IPC_DEV *ipcdev, IPC_TYPE type)
+{
+	return readl(ipcdev->base[type][BASE_IFACE]);
+}
+
+static inline void ipc_write_cmd(IPC_DEV *ipcdev, IPC_TYPE type, u32 cmd)
+{
+	writel(cmd, ipcdev->base[type][BASE_IFACE]);
+}
+
+static inline u32 ipc_read_data_low(IPC_DEV *ipcdev, IPC_TYPE type)
+{
+	return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
+}
+
+static inline u32 ipc_read_data_high(IPC_DEV *ipcdev, IPC_TYPE type)
+{
+	return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
+}
+
+static inline void ipc_write_data_low(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
+{
+	writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
+}
+
+static inline void ipc_write_data_high(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
+{
+	writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
+}
+
+static const char *ipc_err_string(int error)
+{
+	if (error == IPC_PUNIT_ERR_SUCCESS)
+		return "no error";
+	else if (error == IPC_PUNIT_ERR_INVALID_CMD)
+		return "invalid command";
+	else if (error == IPC_PUNIT_ERR_INVALID_PARAMETER)
+		return "invalid parameter";
+	else if (error == IPC_PUNIT_ERR_CMD_TIMEOUT)
+		return "command timeout";
+	else if (error == IPC_PUNIT_ERR_CMD_LOCKED)
+		return "command locked";
+	else if (error == IPC_PUNIT_ERR_INVALID_VR_ID)
+		return "invalid vr id";
+	else if (error == IPC_PUNIT_ERR_VR_ERR)
+		return "vr error";
+	else
+		return "unknown error";
+}
+
+static int intel_punit_ipc_check_status(IPC_DEV *ipcdev, IPC_TYPE type)
+{
+	int loops = CMD_TIMEOUT_SECONDS * USEC_PER_SEC;
+	int errcode;
+	int status;
+
+	if (ipcdev->irq) {
+		if (!wait_for_completion_timeout(&ipcdev->cmd_complete,
+						 CMD_TIMEOUT_SECONDS * HZ)) {
+			dev_err(ipcdev->dev, "IPC timed out\n");
+			return -ETIMEDOUT;
+		}
+	} else {
+		while ((ipc_read_status(ipcdev, type) & CMD_RUN) && --loops)
+			udelay(1);
+		if (!loops) {
+			dev_err(ipcdev->dev, "IPC timed out\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	status = ipc_read_status(ipcdev, type);
+	errcode = status & CMD_ERRCODE_MASK;
+	if (errcode) {
+		dev_err(ipcdev->dev, "IPC failed: %s, IPC_STS=0x%x\n",
+			ipc_err_string(errcode), status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * intel_punit_ipc_simple_command() - Simple IPC command
+ * @cmd:	IPC command code.
+ * @para1:	First 8bit parameter, set 0 if not used.
+ * @para2:	Second 8bit parameter, set 0 if not used.
+ *
+ * Send a IPC command to P-Unit when there is no data transaction
+ *
+ * Return:	IPC error code or 0 on success.
+ */
+int intel_punit_ipc_simple_command(int cmd, int para1, int para2)
+{
+	IPC_DEV *ipcdev = punit_ipcdev;
+	IPC_TYPE type;
+	u32 val;
+	int ret;
+
+	mutex_lock(&ipcdev->lock);
+
+	reinit_completion(&ipcdev->cmd_complete);
+	type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
+
+	val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
+	val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
+	ipc_write_cmd(ipcdev, type, val);
+	ret = intel_punit_ipc_check_status(ipcdev, type);
+
+	mutex_unlock(&ipcdev->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(intel_punit_ipc_simple_command);
+
+/**
+ * intel_punit_ipc_command() - IPC command with data and pointers
+ * @cmd:	IPC command code.
+ * @para1:	First 8bit parameter, set 0 if not used.
+ * @para2:	Second 8bit parameter, set 0 if not used.
+ * @in:		Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD.
+ * @out:	Output data.
+ *
+ * Send a IPC command to P-Unit with data transaction
+ *
+ * Return:	IPC error code or 0 on success.
+ */
+int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out)
+{
+	IPC_DEV *ipcdev = punit_ipcdev;
+	IPC_TYPE type;
+	u32 val;
+	int ret;
+
+	mutex_lock(&ipcdev->lock);
+
+	reinit_completion(&ipcdev->cmd_complete);
+	type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
+
+	if (in) {
+		ipc_write_data_low(ipcdev, type, *in);
+		if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
+			ipc_write_data_high(ipcdev, type, *++in);
+	}
+
+	val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
+	val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
+	ipc_write_cmd(ipcdev, type, val);
+
+	ret = intel_punit_ipc_check_status(ipcdev, type);
+	if (ret)
+		goto out;
+
+	if (out) {
+		*out = ipc_read_data_low(ipcdev, type);
+		if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
+			*++out = ipc_read_data_high(ipcdev, type);
+	}
+
+out:
+	mutex_unlock(&ipcdev->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(intel_punit_ipc_command);
+
+static irqreturn_t intel_punit_ioc(int irq, void *dev_id)
+{
+	IPC_DEV *ipcdev = dev_id;
+
+	complete(&ipcdev->cmd_complete);
+	return IRQ_HANDLED;
+}
+
+static int intel_punit_get_bars(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *addr;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(addr))
+		return PTR_ERR(addr);
+	punit_ipcdev->base[BIOS_IPC][BASE_DATA] = addr;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(addr))
+		return PTR_ERR(addr);
+	punit_ipcdev->base[BIOS_IPC][BASE_IFACE] = addr;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(addr))
+		return PTR_ERR(addr);
+	punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(addr))
+		return PTR_ERR(addr);
+	punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+	addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(addr))
+		return PTR_ERR(addr);
+	punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
+	addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(addr))
+		return PTR_ERR(addr);
+	punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
+
+	return 0;
+}
+
+static int intel_punit_ipc_probe(struct platform_device *pdev)
+{
+	int irq, ret;
+
+	punit_ipcdev = devm_kzalloc(&pdev->dev,
+				    sizeof(*punit_ipcdev), GFP_KERNEL);
+	if (!punit_ipcdev)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, punit_ipcdev);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		punit_ipcdev->irq = 0;
+		dev_warn(&pdev->dev, "Invalid IRQ, using polling mode\n");
+	} else {
+		ret = devm_request_irq(&pdev->dev, irq, intel_punit_ioc,
+				       IRQF_NO_SUSPEND, "intel_punit_ipc",
+				       &punit_ipcdev);
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request irq: %d\n", irq);
+			return ret;
+		}
+		punit_ipcdev->irq = irq;
+	}
+
+	ret = intel_punit_get_bars(pdev);
+	if (ret)
+		goto out;
+
+	punit_ipcdev->dev = &pdev->dev;
+	mutex_init(&punit_ipcdev->lock);
+	init_completion(&punit_ipcdev->cmd_complete);
+
+out:
+	return ret;
+}
+
+static int intel_punit_ipc_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct acpi_device_id punit_ipc_acpi_ids[] = {
+	{ "INT34D4", 0 },
+	{ }
+};
+
+static struct platform_driver intel_punit_ipc_driver = {
+	.probe = intel_punit_ipc_probe,
+	.remove = intel_punit_ipc_remove,
+	.driver = {
+		.name = "intel_punit_ipc",
+		.acpi_match_table = ACPI_PTR(punit_ipc_acpi_ids),
+	},
+};
+
+static int __init intel_punit_ipc_init(void)
+{
+	return platform_driver_register(&intel_punit_ipc_driver);
+}
+
+static void __exit intel_punit_ipc_exit(void)
+{
+	platform_driver_unregister(&intel_punit_ipc_driver);
+}
+
+MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>");
+MODULE_DESCRIPTION("Intel P-Unit IPC driver");
+MODULE_LICENSE("GPL v2");
+
+/* Some modules are dependent on this, so init earlier */
+fs_initcall(intel_punit_ipc_init);
+module_exit(intel_punit_ipc_exit);
--- linux-4.4.0.orig/drivers/platform/x86/intel_scu_ipcutil.c
+++ linux-4.4.0/drivers/platform/x86/intel_scu_ipcutil.c
@@ -49,7 +49,7 @@
 
 static int scu_reg_access(u32 cmd, struct scu_ipc_data  *data)
 {
-	int count = data->count;
+	unsigned int count = data->count;
 
 	if (count == 0 || count == 3 || count > 4)
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/platform/x86/intel_telemetry_core.c
+++ linux-4.4.0/drivers/platform/x86/intel_telemetry_core.c
@@ -0,0 +1,464 @@
+/*
+ * Intel SoC Core Telemetry Driver
+ * Copyright (C) 2015, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * Telemetry Framework provides platform related PM and performance statistics.
+ * This file provides the core telemetry API implementation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/intel_telemetry.h>
+
+#define DRIVER_NAME "intel_telemetry_core"
+
+struct telemetry_core_config {
+	struct telemetry_plt_config *plt_config;
+	struct telemetry_core_ops *telem_ops;
+};
+
+static struct telemetry_core_config telm_core_conf;
+
+static int telemetry_def_update_events(struct telemetry_evtconfig pss_evtconfig,
+				      struct telemetry_evtconfig ioss_evtconfig)
+{
+	return 0;
+}
+
+static int telemetry_def_set_sampling_period(u8 pss_period, u8 ioss_period)
+{
+	return 0;
+}
+
+static int telemetry_def_get_sampling_period(u8 *pss_min_period,
+					     u8 *pss_max_period,
+					     u8 *ioss_min_period,
+					     u8 *ioss_max_period)
+{
+	return 0;
+}
+
+static int telemetry_def_get_eventconfig(
+			struct telemetry_evtconfig *pss_evtconfig,
+			struct telemetry_evtconfig *ioss_evtconfig,
+			int pss_len, int ioss_len)
+{
+	return 0;
+}
+
+static int telemetry_def_get_trace_verbosity(enum telemetry_unit telem_unit,
+					     u32 *verbosity)
+{
+	return 0;
+}
+
+
+static int telemetry_def_set_trace_verbosity(enum telemetry_unit telem_unit,
+					     u32 verbosity)
+{
+	return 0;
+}
+
+static int telemetry_def_raw_read_eventlog(enum telemetry_unit telem_unit,
+					   struct telemetry_evtlog *evtlog,
+					   int len, int log_all_evts)
+{
+	return 0;
+}
+
+static int telemetry_def_read_eventlog(enum telemetry_unit telem_unit,
+				       struct telemetry_evtlog *evtlog,
+				       int len, int log_all_evts)
+{
+	return 0;
+}
+
+static int telemetry_def_add_events(u8 num_pss_evts, u8 num_ioss_evts,
+				    u32 *pss_evtmap, u32 *ioss_evtmap)
+{
+	return 0;
+}
+
+static int telemetry_def_reset_events(void)
+{
+	return 0;
+}
+
+static struct telemetry_core_ops telm_defpltops = {
+	.set_sampling_period = telemetry_def_set_sampling_period,
+	.get_sampling_period = telemetry_def_get_sampling_period,
+	.get_trace_verbosity = telemetry_def_get_trace_verbosity,
+	.set_trace_verbosity = telemetry_def_set_trace_verbosity,
+	.raw_read_eventlog = telemetry_def_raw_read_eventlog,
+	.get_eventconfig = telemetry_def_get_eventconfig,
+	.read_eventlog = telemetry_def_read_eventlog,
+	.update_events = telemetry_def_update_events,
+	.reset_events = telemetry_def_reset_events,
+	.add_events = telemetry_def_add_events,
+};
+
+/**
+ * telemetry_update_events() - Update telemetry Configuration
+ * @pss_evtconfig: PSS related config. No change if num_evts = 0.
+ * @pss_evtconfig: IOSS related config. No change if num_evts = 0.
+ *
+ * This API updates the IOSS & PSS Telemetry configuration. Old config
+ * is overwritten. Call telemetry_reset_events when logging is over
+ * All sample period values should be in the form of:
+ * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig,
+			    struct telemetry_evtconfig ioss_evtconfig)
+{
+	return telm_core_conf.telem_ops->update_events(pss_evtconfig,
+						       ioss_evtconfig);
+}
+EXPORT_SYMBOL_GPL(telemetry_update_events);
+
+
+/**
+ * telemetry_set_sampling_period() - Sets the IOSS & PSS sampling period
+ * @pss_period:  placeholder for PSS Period to be set.
+ *		 Set to 0 if not required to be updated
+ * @ioss_period: placeholder for IOSS Period to be set
+ *		 Set to 0 if not required to be updated
+ *
+ * All values should be in the form of:
+ * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period)
+{
+	return telm_core_conf.telem_ops->set_sampling_period(pss_period,
+							     ioss_period);
+}
+EXPORT_SYMBOL_GPL(telemetry_set_sampling_period);
+
+/**
+ * telemetry_get_sampling_period() - Get IOSS & PSS min & max sampling period
+ * @pss_min_period:  placeholder for PSS Min Period supported
+ * @pss_max_period:  placeholder for PSS Max Period supported
+ * @ioss_min_period: placeholder for IOSS Min Period supported
+ * @ioss_max_period: placeholder for IOSS Max Period supported
+ *
+ * All values should be in the form of:
+ * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period,
+				  u8 *ioss_min_period, u8 *ioss_max_period)
+{
+	return telm_core_conf.telem_ops->get_sampling_period(pss_min_period,
+							     pss_max_period,
+							     ioss_min_period,
+							     ioss_max_period);
+}
+EXPORT_SYMBOL_GPL(telemetry_get_sampling_period);
+
+
+/**
+ * telemetry_reset_events() - Restore the IOSS & PSS configuration to default
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_reset_events(void)
+{
+	return telm_core_conf.telem_ops->reset_events();
+}
+EXPORT_SYMBOL_GPL(telemetry_reset_events);
+
+/**
+ * telemetry_get_eventconfig() - Returns the pss and ioss events enabled
+ * @pss_evtconfig: Pointer to PSS related configuration.
+ * @pss_evtconfig: Pointer to IOSS related configuration.
+ * @pss_len:	   Number of u32 elements allocated for pss_evtconfig array
+ * @ioss_len:	   Number of u32 elements allocated for ioss_evtconfig array
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_evtconfig,
+			      struct telemetry_evtconfig *ioss_evtconfig,
+			      int pss_len, int ioss_len)
+{
+	return telm_core_conf.telem_ops->get_eventconfig(pss_evtconfig,
+							 ioss_evtconfig,
+							 pss_len, ioss_len);
+}
+EXPORT_SYMBOL_GPL(telemetry_get_eventconfig);
+
+/**
+ * telemetry_add_events() - Add IOSS & PSS configuration to existing settings.
+ * @num_pss_evts:  Number of PSS Events (<29) in pss_evtmap. Can be 0.
+ * @num_ioss_evts: Number of IOSS Events (<29) in ioss_evtmap. Can be 0.
+ * @pss_evtmap:    Array of PSS Event-IDs to Enable
+ * @ioss_evtmap:   Array of PSS Event-IDs to Enable
+ *
+ * Events are appended to Old Configuration. In case of total events > 28, it
+ * returns error. Call telemetry_reset_events to reset after eventlog done
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts,
+			 u32 *pss_evtmap, u32 *ioss_evtmap)
+{
+	return telm_core_conf.telem_ops->add_events(num_pss_evts,
+						    num_ioss_evts, pss_evtmap,
+						    ioss_evtmap);
+}
+EXPORT_SYMBOL_GPL(telemetry_add_events);
+
+/**
+ * telemetry_read_events() - Fetches samples as specified by evtlog.telem_evt_id
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @evtlog:     Array of telemetry_evtlog structs to fill data
+ *		evtlog.telem_evt_id specifies the ids to read
+ * @len:	Length of array of evtlog
+ *
+ * Return: number of eventlogs read for success, < 0 for failure
+ */
+int telemetry_read_events(enum telemetry_unit telem_unit,
+			  struct telemetry_evtlog *evtlog, int len)
+{
+	return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog,
+						       len, 0);
+}
+EXPORT_SYMBOL_GPL(telemetry_read_events);
+
+/**
+ * telemetry_raw_read_events() - Fetch samples specified by evtlog.telem_evt_id
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @evtlog:	Array of telemetry_evtlog structs to fill data
+ *		evtlog.telem_evt_id specifies the ids to read
+ * @len:	Length of array of evtlog
+ *
+ * The caller must take care of locking in this case.
+ *
+ * Return: number of eventlogs read for success, < 0 for failure
+ */
+int telemetry_raw_read_events(enum telemetry_unit telem_unit,
+			      struct telemetry_evtlog *evtlog, int len)
+{
+	return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog,
+							   len, 0);
+}
+EXPORT_SYMBOL_GPL(telemetry_raw_read_events);
+
+/**
+ * telemetry_read_eventlog() - Fetch the Telemetry log from PSS or IOSS
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @evtlog:	Array of telemetry_evtlog structs to fill data
+ * @len:	Length of array of evtlog
+ *
+ * Return: number of eventlogs read for success, < 0 for failure
+ */
+int telemetry_read_eventlog(enum telemetry_unit telem_unit,
+			    struct telemetry_evtlog *evtlog, int len)
+{
+	return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog,
+						       len, 1);
+}
+EXPORT_SYMBOL_GPL(telemetry_read_eventlog);
+
+/**
+ * telemetry_raw_read_eventlog() - Fetch the Telemetry log from PSS or IOSS
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @evtlog:	Array of telemetry_evtlog structs to fill data
+ * @len:	Length of array of evtlog
+ *
+ * The caller must take care of locking in this case.
+ *
+ * Return: number of eventlogs read for success, < 0 for failure
+ */
+int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit,
+				struct telemetry_evtlog *evtlog, int len)
+{
+	return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog,
+							   len, 1);
+}
+EXPORT_SYMBOL_GPL(telemetry_raw_read_eventlog);
+
+
+/**
+ * telemetry_get_trace_verbosity() - Get the IOSS & PSS Trace verbosity
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @verbosity:	Pointer to return Verbosity
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit,
+				  u32 *verbosity)
+{
+	return telm_core_conf.telem_ops->get_trace_verbosity(telem_unit,
+							     verbosity);
+}
+EXPORT_SYMBOL_GPL(telemetry_get_trace_verbosity);
+
+
+/**
+ * telemetry_set_trace_verbosity() - Update the IOSS & PSS Trace verbosity
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @verbosity:	Verbosity to set
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit, u32 verbosity)
+{
+	return telm_core_conf.telem_ops->set_trace_verbosity(telem_unit,
+							     verbosity);
+}
+EXPORT_SYMBOL_GPL(telemetry_set_trace_verbosity);
+
+/**
+ * telemetry_set_pltdata() - Set the platform specific Data
+ * @ops:	Pointer to ops structure
+ * @pltconfig:	Platform config data
+ *
+ * Usage by other than telemetry pltdrv module is invalid
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_set_pltdata(struct telemetry_core_ops *ops,
+			  struct telemetry_plt_config *pltconfig)
+{
+	if (ops)
+		telm_core_conf.telem_ops = ops;
+
+	if (pltconfig)
+		telm_core_conf.plt_config = pltconfig;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(telemetry_set_pltdata);
+
+/**
+ * telemetry_clear_pltdata() - Clear the platform specific Data
+ *
+ * Usage by other than telemetry pltdrv module is invalid
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_clear_pltdata(void)
+{
+	telm_core_conf.telem_ops = &telm_defpltops;
+	telm_core_conf.plt_config = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(telemetry_clear_pltdata);
+
+/**
+ * telemetry_pltconfig_valid() - Checkif platform config is valid
+ *
+ * Usage by other than telemetry module is invalid
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_pltconfig_valid(void)
+{
+	if (telm_core_conf.plt_config)
+		return 0;
+
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(telemetry_pltconfig_valid);
+
+static inline int telemetry_get_pssevtname(enum telemetry_unit telem_unit,
+					   const char **name, int len)
+{
+	struct telemetry_unit_config psscfg;
+	int i;
+
+	if (!telm_core_conf.plt_config)
+		return -EINVAL;
+
+	psscfg = telm_core_conf.plt_config->pss_config;
+
+	if (len > psscfg.ssram_evts_used)
+		len = psscfg.ssram_evts_used;
+
+	for (i = 0; i < len; i++)
+		name[i] = psscfg.telem_evts[i].name;
+
+	return 0;
+}
+
+static inline int telemetry_get_iossevtname(enum telemetry_unit telem_unit,
+					    const char **name, int len)
+{
+	struct telemetry_unit_config iosscfg;
+	int i;
+
+	if (!(telm_core_conf.plt_config))
+		return -EINVAL;
+
+	iosscfg = telm_core_conf.plt_config->ioss_config;
+
+	if (len > iosscfg.ssram_evts_used)
+		len = iosscfg.ssram_evts_used;
+
+	for (i = 0; i < len; i++)
+		name[i] = iosscfg.telem_evts[i].name;
+
+	return 0;
+
+}
+
+/**
+ * telemetry_get_evtname() - Checkif platform config is valid
+ * @telem_unit:	Telemetry Unit to check
+ * @name:	Array of character pointers to contain name
+ * @len:	length of array name provided by user
+ *
+ * Usage by other than telemetry debugfs module is invalid
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_get_evtname(enum telemetry_unit telem_unit,
+			  const char **name, int len)
+{
+	int ret = -EINVAL;
+
+	if (telem_unit == TELEM_PSS)
+		ret = telemetry_get_pssevtname(telem_unit, name, len);
+
+	else if (telem_unit == TELEM_IOSS)
+		ret = telemetry_get_iossevtname(telem_unit, name, len);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(telemetry_get_evtname);
+
+static int __init telemetry_module_init(void)
+{
+	pr_info(pr_fmt(DRIVER_NAME) " Init\n");
+
+	telm_core_conf.telem_ops = &telm_defpltops;
+	return 0;
+}
+
+static void __exit telemetry_module_exit(void)
+{
+}
+
+module_init(telemetry_module_init);
+module_exit(telemetry_module_exit);
+
+MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
+MODULE_DESCRIPTION("Intel SoC Telemetry Interface");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/platform/x86/intel_telemetry_debugfs.c
+++ linux-4.4.0/drivers/platform/x86/intel_telemetry_debugfs.c
@@ -0,0 +1,1030 @@
+/*
+ * Intel SOC Telemetry debugfs Driver: Currently supports APL
+ * Copyright (c) 2015, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * This file provides the debugfs interfaces for telemetry.
+ * /sys/kernel/debug/telemetry/pss_info: Shows Primary Control Sub-Sys Counters
+ * /sys/kernel/debug/telemetry/ioss_info: Shows IO Sub-System Counters
+ * /sys/kernel/debug/telemetry/soc_states: Shows SoC State
+ * /sys/kernel/debug/telemetry/pss_trace_verbosity: Read and Change Tracing
+ *				Verbosity via firmware
+ * /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing
+ *				Verbosity via firmware
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/pci.h>
+#include <linux/suspend.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel_pmc_ipc.h>
+#include <asm/intel_punit_ipc.h>
+#include <asm/intel_telemetry.h>
+
+#define DRIVER_NAME	"telemetry_soc_debugfs"
+#define DRIVER_VERSION	"1.0.0"
+
+/* ApolloLake SoC Event-IDs */
+#define TELEM_APL_PSS_PSTATES_ID	0x2802
+#define TELEM_APL_PSS_IDLE_ID		0x2806
+#define TELEM_APL_PCS_IDLE_BLOCKED_ID	0x2C00
+#define TELEM_APL_PCS_S0IX_BLOCKED_ID	0x2C01
+#define TELEM_APL_PSS_WAKEUP_ID		0x2C02
+#define TELEM_APL_PSS_LTR_BLOCKING_ID	0x2C03
+
+#define TELEM_APL_S0IX_TOTAL_OCC_ID	0x4000
+#define TELEM_APL_S0IX_SHLW_OCC_ID	0x4001
+#define TELEM_APL_S0IX_DEEP_OCC_ID	0x4002
+#define TELEM_APL_S0IX_TOTAL_RES_ID	0x4800
+#define TELEM_APL_S0IX_SHLW_RES_ID	0x4801
+#define TELEM_APL_S0IX_DEEP_RES_ID	0x4802
+#define TELEM_APL_D0IX_ID		0x581A
+#define TELEM_APL_D3_ID			0x5819
+#define TELEM_APL_PG_ID			0x5818
+
+#define TELEM_INFO_SRAMEVTS_MASK	0xFF00
+#define TELEM_INFO_SRAMEVTS_SHIFT	0x8
+#define TELEM_SSRAM_READ_TIMEOUT	10
+
+#define TELEM_MASK_BIT			1
+#define TELEM_MASK_BYTE			0xFF
+#define BYTES_PER_LONG			8
+#define TELEM_APL_MASK_PCS_STATE	0xF
+
+/* Max events in bitmap to check for */
+#define TELEM_PSS_IDLE_EVTS		25
+#define TELEM_PSS_IDLE_BLOCKED_EVTS	20
+#define TELEM_PSS_S0IX_BLOCKED_EVTS	20
+#define TELEM_PSS_S0IX_WAKEUP_EVTS	20
+#define TELEM_PSS_LTR_BLOCKING_EVTS	20
+#define TELEM_IOSS_DX_D0IX_EVTS		25
+#define TELEM_IOSS_PG_EVTS		30
+
+#define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0]))
+
+#define TELEM_DEBUGFS_CPU(model, data) \
+	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data}
+
+#define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \
+	if (evtlog[index].telem_evtid == (EVTID)) { \
+		for (idx = 0; idx < (EVTNUM); idx++) \
+			(BUF)[idx] = ((EVTLOG) >> (EVTDAT)[idx].bit_pos) & \
+				     (MASK); \
+	continue; \
+	} \
+}
+
+#define TELEM_CHECK_AND_PARSE_CTRS(EVTID, CTR) { \
+	if (evtlog[index].telem_evtid == (EVTID)) { \
+		(CTR) = evtlog[index].telem_evtlog; \
+		continue; \
+	} \
+}
+
+static u8 suspend_prep_ok;
+static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp;
+static u64 suspend_shlw_res_temp, suspend_deep_res_temp;
+
+struct telemetry_susp_stats {
+	u32 shlw_swake_ctr;
+	u32 deep_swake_ctr;
+	u64 shlw_swake_res;
+	u64 deep_swake_res;
+	u32 shlw_ctr;
+	u32 deep_ctr;
+	u64 shlw_res;
+	u64 deep_res;
+};
+
+/* Bitmap definitions for default counters in APL */
+struct telem_pss_idle_stateinfo {
+	const char *name;
+	u32 bit_pos;
+};
+
+static struct telem_pss_idle_stateinfo telem_apl_pss_idle_data[] = {
+	{"IA_CORE0_C1E",		0},
+	{"IA_CORE1_C1E",		1},
+	{"IA_CORE2_C1E",		2},
+	{"IA_CORE3_C1E",		3},
+	{"IA_CORE0_C6",			16},
+	{"IA_CORE1_C6",			17},
+	{"IA_CORE2_C6",			18},
+	{"IA_CORE3_C6",			19},
+	{"IA_MODULE0_C7",		32},
+	{"IA_MODULE1_C7",		33},
+	{"GT_RC6",			40},
+	{"IUNIT_PROCESSING_IDLE",	41},
+	{"FAR_MEM_IDLE",		43},
+	{"DISPLAY_IDLE",		44},
+	{"IUNIT_INPUT_SYSTEM_IDLE",	45},
+	{"PCS_STATUS",			60},
+};
+
+struct telem_pcs_blkd_info {
+	const char *name;
+	u32 bit_pos;
+};
+
+static struct telem_pcs_blkd_info telem_apl_pcs_idle_blkd_data[] = {
+	{"COMPUTE",			0},
+	{"MISC",			8},
+	{"MODULE_ACTIONS_PENDING",	16},
+	{"LTR",				24},
+	{"DISPLAY_WAKE",		32},
+	{"ISP_WAKE",			40},
+	{"PSF0_ACTIVE",			48},
+};
+
+static struct telem_pcs_blkd_info telem_apl_pcs_s0ix_blkd_data[] = {
+	{"LTR",				0},
+	{"IRTL",			8},
+	{"WAKE_DEADLINE_PENDING",	16},
+	{"DISPLAY",			24},
+	{"ISP",				32},
+	{"CORE",			40},
+	{"PMC",				48},
+	{"MISC",			56},
+};
+
+struct telem_pss_ltr_info {
+	const char *name;
+	u32 bit_pos;
+};
+
+static struct telem_pss_ltr_info telem_apl_pss_ltr_data[] = {
+	{"CORE_ACTIVE",		0},
+	{"MEM_UP",		8},
+	{"DFX",			16},
+	{"DFX_FORCE_LTR",	24},
+	{"DISPLAY",		32},
+	{"ISP",			40},
+	{"SOUTH",		48},
+};
+
+struct telem_pss_wakeup_info {
+	const char *name;
+	u32 bit_pos;
+};
+
+static struct telem_pss_wakeup_info telem_apl_pss_wakeup[] = {
+	{"IP_IDLE",			0},
+	{"DISPLAY_WAKE",		8},
+	{"VOLTAGE_REG_INT",		16},
+	{"DROWSY_TIMER (HOTPLUG)",	24},
+	{"CORE_WAKE",			32},
+	{"MISC_S0IX",			40},
+	{"MISC_ABORT",			56},
+};
+
+struct telem_ioss_d0ix_stateinfo {
+	const char *name;
+	u32 bit_pos;
+};
+
+static struct telem_ioss_d0ix_stateinfo telem_apl_ioss_d0ix_data[] = {
+	{"CSE",		0},
+	{"SCC2",	1},
+	{"GMM",		2},
+	{"XDCI",	3},
+	{"XHCI",	4},
+	{"ISH",		5},
+	{"AVS",		6},
+	{"PCIE0P1",	7},
+	{"PECI0P0",	8},
+	{"LPSS",	9},
+	{"SCC",		10},
+	{"PWM",		11},
+	{"PCIE1_P3",    12},
+	{"PCIE1_P2",    13},
+	{"PCIE1_P1",    14},
+	{"PCIE1_P0",    15},
+	{"CNV",		16},
+	{"SATA",	17},
+	{"PRTC",	18},
+};
+
+struct telem_ioss_pg_info {
+	const char *name;
+	u32 bit_pos;
+};
+
+static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = {
+	{"LPSS",	0},
+	{"SCC",		1},
+	{"P2SB",	2},
+	{"SCC2",	3},
+	{"GMM",		4},
+	{"PCIE0",	5},
+	{"XDCI",	6},
+	{"xHCI",	7},
+	{"CSE",		8},
+	{"SPI",		9},
+	{"AVSPGD4",	10},
+	{"AVSPGD3",	11},
+	{"AVSPGD2",	12},
+	{"AVSPGD1",	13},
+	{"ISH",		14},
+	{"EXI",		15},
+	{"NPKVRC",	16},
+	{"NPKVNN",	17},
+	{"CUNIT",	18},
+	{"FUSE_CTRL",	19},
+	{"PCIE1",	20},
+	{"CNV",		21},
+	{"LPC",		22},
+	{"SATA",	23},
+	{"SMB",		24},
+	{"PRTC",	25},
+};
+
+
+struct telemetry_debugfs_conf {
+	struct telemetry_susp_stats suspend_stats;
+	struct dentry *telemetry_dbg_dir;
+
+	/* Bitmap Data */
+	struct telem_ioss_d0ix_stateinfo *ioss_d0ix_data;
+	struct telem_pss_idle_stateinfo *pss_idle_data;
+	struct telem_pcs_blkd_info *pcs_idle_blkd_data;
+	struct telem_pcs_blkd_info *pcs_s0ix_blkd_data;
+	struct telem_pss_wakeup_info *pss_wakeup;
+	struct telem_pss_ltr_info *pss_ltr_data;
+	struct telem_ioss_pg_info *ioss_pg_data;
+	u8 pcs_idle_blkd_evts;
+	u8 pcs_s0ix_blkd_evts;
+	u8 pss_wakeup_evts;
+	u8 pss_idle_evts;
+	u8 pss_ltr_evts;
+	u8 ioss_d0ix_evts;
+	u8 ioss_pg_evts;
+
+	/* IDs */
+	u16  pss_ltr_blocking_id;
+	u16  pcs_idle_blkd_id;
+	u16  pcs_s0ix_blkd_id;
+	u16  s0ix_total_occ_id;
+	u16  s0ix_shlw_occ_id;
+	u16  s0ix_deep_occ_id;
+	u16  s0ix_total_res_id;
+	u16  s0ix_shlw_res_id;
+	u16  s0ix_deep_res_id;
+	u16  pss_wakeup_id;
+	u16  ioss_d0ix_id;
+	u16  pstates_id;
+	u16  pss_idle_id;
+	u16  ioss_d3_id;
+	u16  ioss_pg_id;
+};
+
+static struct telemetry_debugfs_conf *debugfs_conf;
+
+static struct telemetry_debugfs_conf telem_apl_debugfs_conf = {
+	.pss_idle_data = telem_apl_pss_idle_data,
+	.pcs_idle_blkd_data = telem_apl_pcs_idle_blkd_data,
+	.pcs_s0ix_blkd_data = telem_apl_pcs_s0ix_blkd_data,
+	.pss_ltr_data = telem_apl_pss_ltr_data,
+	.pss_wakeup = telem_apl_pss_wakeup,
+	.ioss_d0ix_data = telem_apl_ioss_d0ix_data,
+	.ioss_pg_data = telem_apl_ioss_pg_data,
+
+	.pss_idle_evts = TELEM_EVT_LEN(telem_apl_pss_idle_data),
+	.pcs_idle_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_idle_blkd_data),
+	.pcs_s0ix_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_s0ix_blkd_data),
+	.pss_ltr_evts = TELEM_EVT_LEN(telem_apl_pss_ltr_data),
+	.pss_wakeup_evts = TELEM_EVT_LEN(telem_apl_pss_wakeup),
+	.ioss_d0ix_evts = TELEM_EVT_LEN(telem_apl_ioss_d0ix_data),
+	.ioss_pg_evts = TELEM_EVT_LEN(telem_apl_ioss_pg_data),
+
+	.pstates_id = TELEM_APL_PSS_PSTATES_ID,
+	.pss_idle_id = TELEM_APL_PSS_IDLE_ID,
+	.pcs_idle_blkd_id = TELEM_APL_PCS_IDLE_BLOCKED_ID,
+	.pcs_s0ix_blkd_id = TELEM_APL_PCS_S0IX_BLOCKED_ID,
+	.pss_wakeup_id = TELEM_APL_PSS_WAKEUP_ID,
+	.pss_ltr_blocking_id = TELEM_APL_PSS_LTR_BLOCKING_ID,
+	.s0ix_total_occ_id = TELEM_APL_S0IX_TOTAL_OCC_ID,
+	.s0ix_shlw_occ_id = TELEM_APL_S0IX_SHLW_OCC_ID,
+	.s0ix_deep_occ_id = TELEM_APL_S0IX_DEEP_OCC_ID,
+	.s0ix_total_res_id = TELEM_APL_S0IX_TOTAL_RES_ID,
+	.s0ix_shlw_res_id = TELEM_APL_S0IX_SHLW_RES_ID,
+	.s0ix_deep_res_id = TELEM_APL_S0IX_DEEP_RES_ID,
+	.ioss_d0ix_id = TELEM_APL_D0IX_ID,
+	.ioss_d3_id = TELEM_APL_D3_ID,
+	.ioss_pg_id = TELEM_APL_PG_ID,
+};
+
+static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = {
+	TELEM_DEBUGFS_CPU(0x5c, telem_apl_debugfs_conf),
+	{}
+};
+
+MODULE_DEVICE_TABLE(x86cpu, telemetry_debugfs_cpu_ids);
+
+static int telemetry_debugfs_check_evts(void)
+{
+	if ((debugfs_conf->pss_idle_evts > TELEM_PSS_IDLE_EVTS) ||
+	    (debugfs_conf->pcs_idle_blkd_evts > TELEM_PSS_IDLE_BLOCKED_EVTS) ||
+	    (debugfs_conf->pcs_s0ix_blkd_evts > TELEM_PSS_S0IX_BLOCKED_EVTS) ||
+	    (debugfs_conf->pss_ltr_evts > TELEM_PSS_LTR_BLOCKING_EVTS) ||
+	    (debugfs_conf->pss_wakeup_evts > TELEM_PSS_S0IX_WAKEUP_EVTS) ||
+	    (debugfs_conf->ioss_d0ix_evts > TELEM_IOSS_DX_D0IX_EVTS) ||
+	    (debugfs_conf->ioss_pg_evts > TELEM_IOSS_PG_EVTS))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int telem_pss_states_show(struct seq_file *s, void *unused)
+{
+	struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+	struct telemetry_debugfs_conf *conf = debugfs_conf;
+	const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS];
+	u32 pcs_idle_blkd[TELEM_PSS_IDLE_BLOCKED_EVTS],
+	    pcs_s0ix_blkd[TELEM_PSS_S0IX_BLOCKED_EVTS],
+	    pss_s0ix_wakeup[TELEM_PSS_S0IX_WAKEUP_EVTS],
+	    pss_ltr_blkd[TELEM_PSS_LTR_BLOCKING_EVTS],
+	    pss_idle[TELEM_PSS_IDLE_EVTS];
+	int index, idx, ret, err = 0;
+	u64 pstates = 0;
+
+	ret = telemetry_read_eventlog(TELEM_PSS, evtlog,
+				      TELEM_MAX_OS_ALLOCATED_EVENTS);
+	if (ret < 0)
+		return ret;
+
+	err = telemetry_get_evtname(TELEM_PSS, name,
+				    TELEM_MAX_OS_ALLOCATED_EVENTS);
+	if (err < 0)
+		return err;
+
+	seq_puts(s, "\n----------------------------------------------------\n");
+	seq_puts(s, "\tPSS TELEM EVENTLOG (Residency = field/19.2 us\n");
+	seq_puts(s, "----------------------------------------------------\n");
+	for (index = 0; index < ret; index++) {
+		seq_printf(s, "%-32s %llu\n",
+			   name[index], evtlog[index].telem_evtlog);
+
+		/* Fetch PSS IDLE State */
+		if (evtlog[index].telem_evtid == conf->pss_idle_id) {
+			pss_idle[conf->pss_idle_evts - 1] =
+			(evtlog[index].telem_evtlog >>
+			conf->pss_idle_data[conf->pss_idle_evts - 1].bit_pos) &
+			TELEM_APL_MASK_PCS_STATE;
+		}
+
+
+		TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id,
+					   conf->pss_idle_evts - 1,
+					   pss_idle, evtlog[index].telem_evtlog,
+					   conf->pss_idle_data, TELEM_MASK_BIT);
+
+		TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_idle_blkd_id,
+					   conf->pcs_idle_blkd_evts,
+					   pcs_idle_blkd,
+					   evtlog[index].telem_evtlog,
+					   conf->pcs_idle_blkd_data,
+					   TELEM_MASK_BYTE);
+
+		TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_s0ix_blkd_id,
+					   conf->pcs_s0ix_blkd_evts,
+					   pcs_s0ix_blkd,
+					   evtlog[index].telem_evtlog,
+					   conf->pcs_s0ix_blkd_data,
+					   TELEM_MASK_BYTE);
+
+
+		TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id,
+					   conf->pss_wakeup_evts,
+					   pss_s0ix_wakeup,
+					   evtlog[index].telem_evtlog,
+					   conf->pss_wakeup, TELEM_MASK_BYTE);
+
+		TELEM_CHECK_AND_PARSE_EVTS(conf->pss_ltr_blocking_id,
+					   conf->pss_ltr_evts, pss_ltr_blkd,
+					   evtlog[index].telem_evtlog,
+					   conf->pss_ltr_data, TELEM_MASK_BYTE);
+
+		if (evtlog[index].telem_evtid == debugfs_conf->pstates_id)
+			pstates = evtlog[index].telem_evtlog;
+	}
+
+	seq_puts(s, "\n--------------------------------------\n");
+	seq_puts(s, "PStates\n");
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "Domain\t\t\t\tFreq(Mhz)\n");
+	seq_printf(s, " IA\t\t\t\t %llu\n GT\t\t\t\t %llu\n",
+		   (pstates & TELEM_MASK_BYTE)*100,
+		   ((pstates >> 8) & TELEM_MASK_BYTE)*50/3);
+
+	seq_printf(s, " IUNIT\t\t\t\t %llu\n SA\t\t\t\t %llu\n",
+		   ((pstates >> 16) & TELEM_MASK_BYTE)*25,
+		   ((pstates >> 24) & TELEM_MASK_BYTE)*50/3);
+
+	seq_puts(s, "\n--------------------------------------\n");
+	seq_puts(s, "PSS IDLE Status\n");
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "Device\t\t\t\t\tIDLE\n");
+	for (index = 0; index < debugfs_conf->pss_idle_evts; index++) {
+		seq_printf(s, "%-32s\t%u\n",
+			   debugfs_conf->pss_idle_data[index].name,
+			   pss_idle[index]);
+	}
+
+	seq_puts(s, "\n--------------------------------------\n");
+	seq_puts(s, "PSS Idle blkd Status (~1ms saturating bucket)\n");
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "Blocker\t\t\t\t\tCount\n");
+	for (index = 0; index < debugfs_conf->pcs_idle_blkd_evts; index++) {
+		seq_printf(s, "%-32s\t%u\n",
+			   debugfs_conf->pcs_idle_blkd_data[index].name,
+			   pcs_idle_blkd[index]);
+	}
+
+	seq_puts(s, "\n--------------------------------------\n");
+	seq_puts(s, "PSS S0ix blkd Status (~1ms saturating bucket)\n");
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "Blocker\t\t\t\t\tCount\n");
+	for (index = 0; index < debugfs_conf->pcs_s0ix_blkd_evts; index++) {
+		seq_printf(s, "%-32s\t%u\n",
+			   debugfs_conf->pcs_s0ix_blkd_data[index].name,
+			   pcs_s0ix_blkd[index]);
+	}
+
+	seq_puts(s, "\n--------------------------------------\n");
+	seq_puts(s, "LTR Blocking Status (~1ms saturating bucket)\n");
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "Blocker\t\t\t\t\tCount\n");
+	for (index = 0; index < debugfs_conf->pss_ltr_evts; index++) {
+		seq_printf(s, "%-32s\t%u\n",
+			   debugfs_conf->pss_ltr_data[index].name,
+			   pss_s0ix_wakeup[index]);
+	}
+
+	seq_puts(s, "\n--------------------------------------\n");
+	seq_puts(s, "Wakes Status (~1ms saturating bucket)\n");
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "Wakes\t\t\t\t\tCount\n");
+	for (index = 0; index < debugfs_conf->pss_wakeup_evts; index++) {
+		seq_printf(s, "%-32s\t%u\n",
+			   debugfs_conf->pss_wakeup[index].name,
+			   pss_ltr_blkd[index]);
+	}
+
+	return 0;
+}
+
+static int telem_pss_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, telem_pss_states_show, inode->i_private);
+}
+
+static const struct file_operations telem_pss_ops = {
+	.open		= telem_pss_state_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+
+static int telem_ioss_states_show(struct seq_file *s, void *unused)
+{
+	struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+	const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS];
+	int index, ret, err;
+
+	ret = telemetry_read_eventlog(TELEM_IOSS, evtlog,
+				      TELEM_MAX_OS_ALLOCATED_EVENTS);
+	if (ret < 0)
+		return ret;
+
+	err = telemetry_get_evtname(TELEM_IOSS, name,
+				    TELEM_MAX_OS_ALLOCATED_EVENTS);
+	if (err < 0)
+		return err;
+
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "\tI0SS TELEMETRY EVENTLOG\n");
+	seq_puts(s, "--------------------------------------\n");
+	for (index = 0; index < ret; index++) {
+		seq_printf(s, "%-32s 0x%llx\n",
+			   name[index], evtlog[index].telem_evtlog);
+	}
+
+	return 0;
+}
+
+static int telem_ioss_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, telem_ioss_states_show, inode->i_private);
+}
+
+static const struct file_operations telem_ioss_ops = {
+	.open		= telem_ioss_state_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int telem_soc_states_show(struct seq_file *s, void *unused)
+{
+	u32 d3_sts[TELEM_IOSS_DX_D0IX_EVTS], d0ix_sts[TELEM_IOSS_DX_D0IX_EVTS];
+	u32 pg_sts[TELEM_IOSS_PG_EVTS], pss_idle[TELEM_PSS_IDLE_EVTS];
+	struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+	u32 s0ix_total_ctr = 0, s0ix_shlw_ctr = 0, s0ix_deep_ctr = 0;
+	u64 s0ix_total_res = 0, s0ix_shlw_res = 0, s0ix_deep_res = 0;
+	struct telemetry_debugfs_conf *conf = debugfs_conf;
+	struct pci_dev *dev = NULL;
+	int index, idx, ret;
+	u32 d3_state;
+	u16 pmcsr;
+
+	ret = telemetry_read_eventlog(TELEM_IOSS, evtlog,
+				      TELEM_MAX_OS_ALLOCATED_EVENTS);
+	if (ret < 0)
+		return ret;
+
+	for (index = 0; index < ret; index++) {
+		TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d3_id,
+					   conf->ioss_d0ix_evts,
+					   d3_sts, evtlog[index].telem_evtlog,
+					   conf->ioss_d0ix_data,
+					   TELEM_MASK_BIT);
+
+		TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_pg_id, conf->ioss_pg_evts,
+					   pg_sts, evtlog[index].telem_evtlog,
+					   conf->ioss_pg_data, TELEM_MASK_BIT);
+
+		TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d0ix_id,
+					   conf->ioss_d0ix_evts,
+					   d0ix_sts, evtlog[index].telem_evtlog,
+					   conf->ioss_d0ix_data,
+					   TELEM_MASK_BIT);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_occ_id,
+					   s0ix_total_ctr);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id,
+					   s0ix_shlw_ctr);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id,
+					   s0ix_deep_ctr);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_res_id,
+					   s0ix_total_res);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id,
+					   s0ix_shlw_res);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id,
+					   s0ix_deep_res);
+	}
+
+	seq_puts(s, "\n---------------------------------------------------\n");
+	seq_puts(s, "S0IX Type\t\t\t Occurrence\t\t Residency(us)\n");
+	seq_puts(s, "---------------------------------------------------\n");
+
+	seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n",
+		   s0ix_shlw_ctr -
+		   conf->suspend_stats.shlw_ctr -
+		   conf->suspend_stats.shlw_swake_ctr,
+		   (u64)((s0ix_shlw_res -
+		   conf->suspend_stats.shlw_res -
+		   conf->suspend_stats.shlw_swake_res)*10/192));
+
+	seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n",
+		   s0ix_deep_ctr -
+		   conf->suspend_stats.deep_ctr -
+		   conf->suspend_stats.deep_swake_ctr,
+		   (u64)((s0ix_deep_res -
+		   conf->suspend_stats.deep_res -
+		   conf->suspend_stats.deep_swake_res)*10/192));
+
+	seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n",
+		   conf->suspend_stats.shlw_ctr,
+		   (u64)(conf->suspend_stats.shlw_res*10)/192);
+
+	seq_printf(s, "Suspend(With S0ixDeep)\t\t %10u\t %10llu\n",
+		   conf->suspend_stats.deep_ctr,
+		   (u64)(conf->suspend_stats.deep_res*10)/192);
+
+	seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n",
+		   conf->suspend_stats.shlw_swake_ctr +
+		   conf->suspend_stats.deep_swake_ctr,
+		   (u64)((conf->suspend_stats.shlw_swake_res +
+		   conf->suspend_stats.deep_swake_res)*10/192));
+
+	seq_printf(s, "S0IX+Suspend Total\t\t %10u\t %10llu\n", s0ix_total_ctr,
+				(u64)(s0ix_total_res*10/192));
+	seq_puts(s, "\n-------------------------------------------------\n");
+	seq_puts(s, "\t\tDEVICE STATES\n");
+	seq_puts(s, "-------------------------------------------------\n");
+
+	for_each_pci_dev(dev) {
+		pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+		d3_state = ((pmcsr & PCI_PM_CTRL_STATE_MASK) ==
+			    (__force int)PCI_D3hot) ? 1 : 0;
+
+		seq_printf(s, "pci %04x %04X %s %20.20s: ",
+			   dev->vendor, dev->device, dev_name(&dev->dev),
+			   dev_driver_string(&dev->dev));
+		seq_printf(s, " d3:%x\n", d3_state);
+	}
+
+	seq_puts(s, "\n--------------------------------------\n");
+	seq_puts(s, "D3/D0i3 Status\n");
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "Block\t\t D3\t D0i3\n");
+	for (index = 0; index < conf->ioss_d0ix_evts; index++) {
+		seq_printf(s, "%-10s\t %u\t %u\n",
+			   conf->ioss_d0ix_data[index].name,
+			   d3_sts[index], d0ix_sts[index]);
+	}
+
+	seq_puts(s, "\n--------------------------------------\n");
+	seq_puts(s, "South Complex PowerGate Status\n");
+	seq_puts(s, "--------------------------------------\n");
+	seq_puts(s, "Device\t\t PG\n");
+	for (index = 0; index < conf->ioss_pg_evts; index++) {
+		seq_printf(s, "%-10s\t %u\n",
+			   conf->ioss_pg_data[index].name,
+			   pg_sts[index]);
+	}
+
+	evtlog->telem_evtid = conf->pss_idle_id;
+	ret = telemetry_read_events(TELEM_PSS, evtlog, 1);
+	if (ret < 0)
+		return ret;
+
+	seq_puts(s, "\n-----------------------------------------\n");
+	seq_puts(s, "North Idle Status\n");
+	seq_puts(s, "-----------------------------------------\n");
+	for (idx = 0; idx < conf->pss_idle_evts - 1; idx++) {
+		pss_idle[idx] =	(evtlog->telem_evtlog >>
+				conf->pss_idle_data[idx].bit_pos) &
+				TELEM_MASK_BIT;
+	}
+
+	pss_idle[idx] = (evtlog->telem_evtlog >>
+			conf->pss_idle_data[idx].bit_pos) &
+			TELEM_APL_MASK_PCS_STATE;
+
+	for (index = 0; index < conf->pss_idle_evts; index++) {
+		seq_printf(s, "%-30s %u\n",
+			   conf->pss_idle_data[index].name,
+			   pss_idle[index]);
+	}
+
+	seq_puts(s, "\nPCS_STATUS Code\n");
+	seq_puts(s, "0:C0 1:C1 2:C1_DN_WT_DEV 3:C2 4:C2_WT_DE_MEM_UP\n");
+	seq_puts(s, "5:C2_WT_DE_MEM_DOWN 6:C2_UP_WT_DEV 7:C2_DN 8:C2_VOA\n");
+	seq_puts(s, "9:C2_VOA_UP 10:S0IX_PRE 11:S0IX\n");
+
+	return 0;
+}
+
+static int telem_soc_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, telem_soc_states_show, inode->i_private);
+}
+
+static const struct file_operations telem_socstate_ops = {
+	.open		= telem_soc_state_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int telem_pss_trc_verb_show(struct seq_file *s, void *unused)
+{
+	u32 verbosity;
+	int err;
+
+	err = telemetry_get_trace_verbosity(TELEM_PSS, &verbosity);
+	if (err) {
+		pr_err("Get PSS Trace Verbosity Failed with Error %d\n", err);
+		return -EFAULT;
+	}
+
+	seq_printf(s, "PSS Trace Verbosity %u\n", verbosity);
+	return 0;
+}
+
+static ssize_t telem_pss_trc_verb_write(struct file *file,
+					const char __user *userbuf,
+					size_t count, loff_t *ppos)
+{
+	u32 verbosity;
+	int err;
+
+	if (kstrtou32_from_user(userbuf, count, 0, &verbosity))
+		return -EFAULT;
+
+	err = telemetry_set_trace_verbosity(TELEM_PSS, verbosity);
+	if (err) {
+		pr_err("Changing PSS Trace Verbosity Failed. Error %d\n", err);
+		count = err;
+	}
+
+	return count;
+}
+
+static int telem_pss_trc_verb_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, telem_pss_trc_verb_show, inode->i_private);
+}
+
+static const struct file_operations telem_pss_trc_verb_ops = {
+	.open		= telem_pss_trc_verb_open,
+	.read		= seq_read,
+	.write		= telem_pss_trc_verb_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+
+static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused)
+{
+	u32 verbosity;
+	int err;
+
+	err = telemetry_get_trace_verbosity(TELEM_IOSS, &verbosity);
+	if (err) {
+		pr_err("Get IOSS Trace Verbosity Failed with Error %d\n", err);
+		return -EFAULT;
+	}
+
+	seq_printf(s, "IOSS Trace Verbosity %u\n", verbosity);
+	return 0;
+}
+
+static ssize_t telem_ioss_trc_verb_write(struct file *file,
+					 const char __user *userbuf,
+					 size_t count, loff_t *ppos)
+{
+	u32 verbosity;
+	int err;
+
+	if (kstrtou32_from_user(userbuf, count, 0, &verbosity))
+		return -EFAULT;
+
+	err = telemetry_set_trace_verbosity(TELEM_IOSS, verbosity);
+	if (err) {
+		pr_err("Changing IOSS Trace Verbosity Failed. Error %d\n", err);
+		count = err;
+	}
+
+	return count;
+}
+
+static int telem_ioss_trc_verb_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, telem_ioss_trc_verb_show, inode->i_private);
+}
+
+static const struct file_operations telem_ioss_trc_verb_ops = {
+	.open		= telem_ioss_trc_verb_open,
+	.read		= seq_read,
+	.write		= telem_ioss_trc_verb_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int pm_suspend_prep_cb(void)
+{
+	struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+	struct telemetry_debugfs_conf *conf = debugfs_conf;
+	int ret, index;
+
+	ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog,
+			TELEM_MAX_OS_ALLOCATED_EVENTS);
+	if (ret < 0) {
+		suspend_prep_ok = 0;
+		goto out;
+	}
+
+	for (index = 0; index < ret; index++) {
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id,
+					   suspend_shlw_ctr_temp);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id,
+					   suspend_deep_ctr_temp);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id,
+					   suspend_shlw_res_temp);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id,
+					   suspend_deep_res_temp);
+	}
+	suspend_prep_ok = 1;
+out:
+	return NOTIFY_OK;
+}
+
+static int pm_suspend_exit_cb(void)
+{
+	struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+	static u32 suspend_shlw_ctr_exit, suspend_deep_ctr_exit;
+	static u64 suspend_shlw_res_exit, suspend_deep_res_exit;
+	struct telemetry_debugfs_conf *conf = debugfs_conf;
+	int ret, index;
+
+	if (!suspend_prep_ok)
+		goto out;
+
+	ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog,
+					  TELEM_MAX_OS_ALLOCATED_EVENTS);
+	if (ret < 0)
+		goto out;
+
+	for (index = 0; index < ret; index++) {
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id,
+					   suspend_shlw_ctr_exit);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id,
+					   suspend_deep_ctr_exit);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id,
+					   suspend_shlw_res_exit);
+
+		TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id,
+					   suspend_deep_res_exit);
+	}
+
+	if ((suspend_shlw_ctr_exit < suspend_shlw_ctr_temp) ||
+	    (suspend_deep_ctr_exit < suspend_deep_ctr_temp) ||
+	    (suspend_shlw_res_exit < suspend_shlw_res_temp) ||
+	    (suspend_deep_res_exit < suspend_deep_res_temp)) {
+		pr_err("Wrong s0ix counters detected\n");
+		goto out;
+	}
+
+	suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp;
+	suspend_deep_ctr_exit -= suspend_deep_ctr_temp;
+	suspend_shlw_res_exit -= suspend_shlw_res_temp;
+	suspend_deep_res_exit -= suspend_deep_res_temp;
+
+	if (suspend_shlw_ctr_exit == 1) {
+		conf->suspend_stats.shlw_ctr +=
+		suspend_shlw_ctr_exit;
+
+		conf->suspend_stats.shlw_res +=
+		suspend_shlw_res_exit;
+	}
+	/* Shallow Wakes Case */
+	else if (suspend_shlw_ctr_exit > 1) {
+		conf->suspend_stats.shlw_swake_ctr +=
+		suspend_shlw_ctr_exit;
+
+		conf->suspend_stats.shlw_swake_res +=
+		suspend_shlw_res_exit;
+	}
+
+	if (suspend_deep_ctr_exit == 1) {
+		conf->suspend_stats.deep_ctr +=
+		suspend_deep_ctr_exit;
+
+		conf->suspend_stats.deep_res +=
+		suspend_deep_res_exit;
+	}
+
+	/* Shallow Wakes Case */
+	else if (suspend_deep_ctr_exit > 1) {
+		conf->suspend_stats.deep_swake_ctr +=
+		suspend_deep_ctr_exit;
+
+		conf->suspend_stats.deep_swake_res +=
+		suspend_deep_res_exit;
+	}
+
+out:
+	suspend_prep_ok = 0;
+	return NOTIFY_OK;
+}
+
+static int pm_notification(struct notifier_block *this,
+			   unsigned long event, void *ptr)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		return pm_suspend_prep_cb();
+	case PM_POST_SUSPEND:
+		return pm_suspend_exit_cb();
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block pm_notifier = {
+	.notifier_call = pm_notification,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static int __init telemetry_debugfs_init(void)
+{
+	const struct x86_cpu_id *id;
+	int err = -ENOMEM;
+	struct dentry *f;
+
+	/* Only APL supported for now */
+	id = x86_match_cpu(telemetry_debugfs_cpu_ids);
+	if (!id)
+		return -ENODEV;
+
+	debugfs_conf = (struct telemetry_debugfs_conf *)id->driver_data;
+
+	err = telemetry_pltconfig_valid();
+	if (err < 0)
+		return -ENODEV;
+
+	err = telemetry_debugfs_check_evts();
+	if (err < 0)
+		return -EINVAL;
+
+
+#ifdef CONFIG_PM_SLEEP
+	register_pm_notifier(&pm_notifier);
+#endif /* CONFIG_PM_SLEEP */
+
+	debugfs_conf->telemetry_dbg_dir = debugfs_create_dir("telemetry", NULL);
+	if (!debugfs_conf->telemetry_dbg_dir)
+		return -ENOMEM;
+
+	f = debugfs_create_file("pss_info", S_IFREG | S_IRUGO,
+				debugfs_conf->telemetry_dbg_dir, NULL,
+				&telem_pss_ops);
+	if (!f) {
+		pr_err("pss_sample_info debugfs register failed\n");
+		goto out;
+	}
+
+	f = debugfs_create_file("ioss_info", S_IFREG | S_IRUGO,
+				debugfs_conf->telemetry_dbg_dir, NULL,
+				&telem_ioss_ops);
+	if (!f) {
+		pr_err("ioss_sample_info debugfs register failed\n");
+		goto out;
+	}
+
+	f = debugfs_create_file("soc_states", S_IFREG | S_IRUGO,
+				debugfs_conf->telemetry_dbg_dir,
+				NULL, &telem_socstate_ops);
+	if (!f) {
+		pr_err("ioss_sample_info debugfs register failed\n");
+		goto out;
+	}
+
+	f = debugfs_create_file("pss_trace_verbosity", S_IFREG | S_IRUGO,
+				debugfs_conf->telemetry_dbg_dir, NULL,
+				&telem_pss_trc_verb_ops);
+	if (!f) {
+		pr_err("pss_trace_verbosity debugfs register failed\n");
+		goto out;
+	}
+
+	f = debugfs_create_file("ioss_trace_verbosity", S_IFREG | S_IRUGO,
+				debugfs_conf->telemetry_dbg_dir, NULL,
+				&telem_ioss_trc_verb_ops);
+	if (!f) {
+		pr_err("ioss_trace_verbosity debugfs register failed\n");
+		goto out;
+	}
+
+	return 0;
+
+out:
+	debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir);
+	debugfs_conf->telemetry_dbg_dir = NULL;
+
+	return err;
+}
+
+static void __exit telemetry_debugfs_exit(void)
+{
+	debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir);
+	debugfs_conf->telemetry_dbg_dir = NULL;
+}
+
+late_initcall(telemetry_debugfs_init);
+module_exit(telemetry_debugfs_exit);
+
+MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
+MODULE_DESCRIPTION("Intel SoC Telemetry debugfs Interface");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ linux-4.4.0/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -0,0 +1,1206 @@
+/*
+ * Intel SOC Telemetry Platform Driver: Currently supports APL
+ * Copyright (c) 2015, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * This file provides the platform specific telemetry implementation for APL.
+ * It used the PUNIT and PMC IPC interfaces for configuring the counters.
+ * The accumulated results are fetched from SRAM.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/pci.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel_pmc_ipc.h>
+#include <asm/intel_punit_ipc.h>
+#include <asm/intel_telemetry.h>
+
+#define DRIVER_NAME	"intel_telemetry"
+#define DRIVER_VERSION	"1.0.0"
+
+#define TELEM_TRC_VERBOSITY_MASK	0x3
+
+#define TELEM_MIN_PERIOD(x)		((x) & 0x7F0000)
+#define TELEM_MAX_PERIOD(x)		((x) & 0x7F000000)
+#define TELEM_SAMPLE_PERIOD_INVALID(x)	((x) & (BIT(7)))
+#define TELEM_CLEAR_SAMPLE_PERIOD(x)	((x) &= ~0x7F)
+
+#define TELEM_SAMPLING_DEFAULT_PERIOD	0xD
+
+#define TELEM_MAX_EVENTS_SRAM		28
+#define TELEM_MAX_OS_ALLOCATED_EVENTS	20
+#define TELEM_SSRAM_STARTTIME_OFFSET	8
+#define TELEM_SSRAM_EVTLOG_OFFSET	16
+
+#define IOSS_TELEM_EVENT_READ		0x0
+#define IOSS_TELEM_EVENT_WRITE		0x1
+#define IOSS_TELEM_INFO_READ		0x2
+#define IOSS_TELEM_TRACE_CTL_READ	0x5
+#define IOSS_TELEM_TRACE_CTL_WRITE	0x6
+#define IOSS_TELEM_EVENT_CTL_READ	0x7
+#define IOSS_TELEM_EVENT_CTL_WRITE	0x8
+#define IOSS_TELEM_EVT_CTRL_WRITE_SIZE	0x4
+#define IOSS_TELEM_READ_WORD		0x1
+#define IOSS_TELEM_WRITE_FOURBYTES	0x4
+#define IOSS_TELEM_EVT_WRITE_SIZE	0x3
+
+#define TELEM_INFO_SRAMEVTS_MASK	0xFF00
+#define TELEM_INFO_SRAMEVTS_SHIFT	0x8
+#define TELEM_SSRAM_READ_TIMEOUT	10
+
+#define TELEM_INFO_NENABLES_MASK	0xFF
+#define TELEM_EVENT_ENABLE		0x8000
+
+#define TELEM_MASK_BIT			1
+#define TELEM_MASK_BYTE			0xFF
+#define BYTES_PER_LONG			8
+#define TELEM_MASK_PCS_STATE		0xF
+
+#define TELEM_DISABLE(x)		((x) &= ~(BIT(31)))
+#define TELEM_CLEAR_EVENTS(x)		((x) |= (BIT(30)))
+#define TELEM_ENABLE_SRAM_EVT_TRACE(x)	((x) &= ~(BIT(30) | BIT(24)))
+#define TELEM_ENABLE_PERIODIC(x)	((x) |= (BIT(23) | BIT(31) | BIT(7)))
+#define TELEM_EXTRACT_VERBOSITY(x, y)	((y) = (((x) >> 27) & 0x3))
+#define TELEM_CLEAR_VERBOSITY_BITS(x)	((x) &= ~(BIT(27) | BIT(28)))
+#define TELEM_SET_VERBOSITY_BITS(x, y)	((x) |= ((y) << 27))
+
+#define TELEM_CPU(model, data) \
+	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data }
+
+enum telemetry_action {
+	TELEM_UPDATE = 0,
+	TELEM_ADD,
+	TELEM_RESET,
+	TELEM_ACTION_NONE
+};
+
+struct telem_ssram_region {
+	u64 timestamp;
+	u64 start_time;
+	u64 events[TELEM_MAX_EVENTS_SRAM];
+};
+
+static struct telemetry_plt_config *telm_conf;
+
+/*
+ * The following counters are programmed by default during setup.
+ * Only 20 allocated to kernel driver
+ */
+static struct telemetry_evtmap
+	telemetry_apl_ioss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = {
+	{"SOC_S0IX_TOTAL_RES",			0x4800},
+	{"SOC_S0IX_TOTAL_OCC",			0x4000},
+	{"SOC_S0IX_SHALLOW_RES",		0x4801},
+	{"SOC_S0IX_SHALLOW_OCC",		0x4001},
+	{"SOC_S0IX_DEEP_RES",			0x4802},
+	{"SOC_S0IX_DEEP_OCC",			0x4002},
+	{"PMC_POWER_GATE",			0x5818},
+	{"PMC_D3_STATES",			0x5819},
+	{"PMC_D0I3_STATES",			0x581A},
+	{"PMC_S0IX_WAKE_REASON_GPIO",		0x6000},
+	{"PMC_S0IX_WAKE_REASON_TIMER",		0x6001},
+	{"PMC_S0IX_WAKE_REASON_VNNREQ",         0x6002},
+	{"PMC_S0IX_WAKE_REASON_LOWPOWER",       0x6003},
+	{"PMC_S0IX_WAKE_REASON_EXTERNAL",       0x6004},
+	{"PMC_S0IX_WAKE_REASON_MISC",           0x6005},
+	{"PMC_S0IX_BLOCKING_IPS_D3_D0I3",       0x6006},
+	{"PMC_S0IX_BLOCKING_IPS_PG",            0x6007},
+	{"PMC_S0IX_BLOCKING_MISC_IPS_PG",       0x6008},
+	{"PMC_S0IX_BLOCK_IPS_VNN_REQ",          0x6009},
+	{"PMC_S0IX_BLOCK_IPS_CLOCKS",           0x600B},
+};
+
+
+static struct telemetry_evtmap
+	telemetry_apl_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = {
+	{"IA_CORE0_C6_RES",			0x0400},
+	{"IA_CORE0_C6_CTR",			0x0000},
+	{"IA_MODULE0_C7_RES",			0x0410},
+	{"IA_MODULE0_C7_CTR",			0x000E},
+	{"IA_C0_RES",				0x0805},
+	{"PCS_LTR",				0x2801},
+	{"PSTATES",				0x2802},
+	{"SOC_S0I3_RES",			0x0409},
+	{"SOC_S0I3_CTR",			0x000A},
+	{"PCS_S0I3_CTR",			0x0009},
+	{"PCS_C1E_RES",				0x041A},
+	{"PCS_IDLE_STATUS",			0x2806},
+	{"IA_PERF_LIMITS",			0x280B},
+	{"GT_PERF_LIMITS",			0x280C},
+	{"PCS_WAKEUP_S0IX_CTR",			0x0030},
+	{"PCS_IDLE_BLOCKED",			0x2C00},
+	{"PCS_S0IX_BLOCKED",			0x2C01},
+	{"PCS_S0IX_WAKE_REASONS",		0x2C02},
+	{"PCS_LTR_BLOCKING",			0x2C03},
+	{"PC2_AND_MEM_SHALLOW_IDLE_RES",	0x1D40},
+};
+
+/* APL specific Data */
+static struct telemetry_plt_config telem_apl_config = {
+	.pss_config = {
+		.telem_evts = telemetry_apl_pss_default_events,
+	},
+	.ioss_config = {
+		.telem_evts = telemetry_apl_ioss_default_events,
+	},
+};
+
+static const struct x86_cpu_id telemetry_cpu_ids[] = {
+	TELEM_CPU(0x5c, telem_apl_config),
+	{}
+};
+
+MODULE_DEVICE_TABLE(x86cpu, telemetry_cpu_ids);
+
+static inline int telem_get_unitconfig(enum telemetry_unit telem_unit,
+				     struct telemetry_unit_config **unit_config)
+{
+	if (telem_unit == TELEM_PSS)
+		*unit_config = &(telm_conf->pss_config);
+	else if (telem_unit == TELEM_IOSS)
+		*unit_config = &(telm_conf->ioss_config);
+	else
+		return -EINVAL;
+
+	return 0;
+
+}
+
+static int telemetry_check_evtid(enum telemetry_unit telem_unit,
+				 u32 *evtmap, u8 len,
+				 enum telemetry_action action)
+{
+	struct telemetry_unit_config *unit_config;
+	int ret;
+
+	ret = telem_get_unitconfig(telem_unit, &unit_config);
+	if (ret < 0)
+		return ret;
+
+	switch (action) {
+	case TELEM_RESET:
+		if (len > TELEM_MAX_EVENTS_SRAM)
+			return -EINVAL;
+
+		break;
+
+	case TELEM_UPDATE:
+		if (len > TELEM_MAX_EVENTS_SRAM)
+			return -EINVAL;
+
+		if ((len > 0) && (evtmap == NULL))
+			return -EINVAL;
+
+		break;
+
+	case TELEM_ADD:
+		if ((len + unit_config->ssram_evts_used) >
+		    TELEM_MAX_EVENTS_SRAM)
+			return -EINVAL;
+
+		if ((len > 0) && (evtmap == NULL))
+			return -EINVAL;
+
+		break;
+
+	default:
+		pr_err("Unknown Telemetry action Specified %d\n", action);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index)
+{
+	u32 write_buf;
+	int ret;
+
+	write_buf = evt_id | TELEM_EVENT_ENABLE;
+	write_buf <<= BITS_PER_BYTE;
+	write_buf |= index;
+
+	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_WRITE, (u8 *)&write_buf,
+				    IOSS_TELEM_EVT_WRITE_SIZE, NULL, 0);
+
+	return ret;
+}
+
+static inline int telemetry_plt_config_pss_event(u32 evt_id, int index)
+{
+	u32 write_buf;
+	int ret;
+
+	write_buf = evt_id | TELEM_EVENT_ENABLE;
+	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT,
+				      index, 0, &write_buf, NULL);
+
+	return ret;
+}
+
+static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
+					 enum telemetry_action action)
+{
+	u8 num_ioss_evts, ioss_period;
+	int ret, index, idx;
+	u32 *ioss_evtmap;
+	u32 telem_ctrl;
+
+	num_ioss_evts = evtconfig.num_evts;
+	ioss_period = evtconfig.period;
+	ioss_evtmap = evtconfig.evtmap;
+
+	/* Get telemetry EVENT CTL */
+	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_READ, NULL, 0,
+				    &telem_ctrl, IOSS_TELEM_READ_WORD);
+	if (ret) {
+		pr_err("IOSS TELEM_CTRL Read Failed\n");
+		return ret;
+	}
+
+	/* Disable Telemetry */
+	TELEM_DISABLE(telem_ctrl);
+
+	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl,
+				    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+				    NULL, 0);
+	if (ret) {
+		pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
+		return ret;
+	}
+
+
+	/* Reset Everything */
+	if (action == TELEM_RESET) {
+		/* Clear All Events */
+		TELEM_CLEAR_EVENTS(telem_ctrl);
+
+		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+					    IOSS_TELEM_EVENT_CTL_WRITE,
+					    (u8 *)&telem_ctrl,
+					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+					    NULL, 0);
+		if (ret) {
+			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
+			return ret;
+		}
+		telm_conf->ioss_config.ssram_evts_used = 0;
+
+		/* Configure Events */
+		for (idx = 0; idx < num_ioss_evts; idx++) {
+			if (telemetry_plt_config_ioss_event(
+			    telm_conf->ioss_config.telem_evts[idx].evt_id,
+			    idx)) {
+				pr_err("IOSS TELEM_RESET Fail for data: %x\n",
+				telm_conf->ioss_config.telem_evts[idx].evt_id);
+				continue;
+			}
+			telm_conf->ioss_config.ssram_evts_used++;
+		}
+	}
+
+	/* Re-Configure Everything */
+	if (action == TELEM_UPDATE) {
+		/* Clear All Events */
+		TELEM_CLEAR_EVENTS(telem_ctrl);
+
+		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+					    IOSS_TELEM_EVENT_CTL_WRITE,
+					    (u8 *)&telem_ctrl,
+					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+					    NULL, 0);
+		if (ret) {
+			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
+			return ret;
+		}
+		telm_conf->ioss_config.ssram_evts_used = 0;
+
+		/* Configure Events */
+		for (index = 0; index < num_ioss_evts; index++) {
+			telm_conf->ioss_config.telem_evts[index].evt_id =
+			ioss_evtmap[index];
+
+			if (telemetry_plt_config_ioss_event(
+			    telm_conf->ioss_config.telem_evts[index].evt_id,
+			    index)) {
+				pr_err("IOSS TELEM_UPDATE Fail for Evt%x\n",
+					ioss_evtmap[index]);
+				continue;
+			}
+			telm_conf->ioss_config.ssram_evts_used++;
+		}
+	}
+
+	/* Add some Events */
+	if (action == TELEM_ADD) {
+		/* Configure Events */
+		for (index = telm_conf->ioss_config.ssram_evts_used, idx = 0;
+		     idx < num_ioss_evts; index++, idx++) {
+			telm_conf->ioss_config.telem_evts[index].evt_id =
+			ioss_evtmap[idx];
+
+			if (telemetry_plt_config_ioss_event(
+			    telm_conf->ioss_config.telem_evts[index].evt_id,
+			    index)) {
+				pr_err("IOSS TELEM_ADD Fail for Event %x\n",
+					ioss_evtmap[idx]);
+				continue;
+			}
+			telm_conf->ioss_config.ssram_evts_used++;
+		}
+	}
+
+	/* Enable Periodic Telemetry Events and enable SRAM trace */
+	TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl);
+	TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
+	TELEM_ENABLE_PERIODIC(telem_ctrl);
+	telem_ctrl |= ioss_period;
+
+	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl,
+				    IOSS_TELEM_EVT_CTRL_WRITE_SIZE, NULL, 0);
+	if (ret) {
+		pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n");
+		return ret;
+	}
+
+	telm_conf->ioss_config.curr_period = ioss_period;
+
+	return 0;
+}
+
+
+static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
+					enum telemetry_action action)
+{
+	u8 num_pss_evts, pss_period;
+	int ret, index, idx;
+	u32 *pss_evtmap;
+	u32 telem_ctrl;
+
+	num_pss_evts = evtconfig.num_evts;
+	pss_period = evtconfig.period;
+	pss_evtmap = evtconfig.evtmap;
+
+	/* PSS Config */
+	/* Get telemetry EVENT CTL */
+	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+				      0, 0, NULL, &telem_ctrl);
+	if (ret) {
+		pr_err("PSS TELEM_CTRL Read Failed\n");
+		return ret;
+	}
+
+	/* Disable Telemetry */
+	TELEM_DISABLE(telem_ctrl);
+	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, 0, &telem_ctrl, NULL);
+	if (ret) {
+		pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
+		return ret;
+	}
+
+	/* Reset Everything */
+	if (action == TELEM_RESET) {
+		/* Clear All Events */
+		TELEM_CLEAR_EVENTS(telem_ctrl);
+
+		ret = intel_punit_ipc_command(
+				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				0, 0, &telem_ctrl, NULL);
+		if (ret) {
+			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
+			return ret;
+		}
+		telm_conf->pss_config.ssram_evts_used = 0;
+		/* Configure Events */
+		for (idx = 0; idx < num_pss_evts; idx++) {
+			if (telemetry_plt_config_pss_event(
+			    telm_conf->pss_config.telem_evts[idx].evt_id,
+			    idx)) {
+				pr_err("PSS TELEM_RESET Fail for Event %x\n",
+				telm_conf->pss_config.telem_evts[idx].evt_id);
+				continue;
+			}
+			telm_conf->pss_config.ssram_evts_used++;
+		}
+	}
+
+	/* Re-Configure Everything */
+	if (action == TELEM_UPDATE) {
+		/* Clear All Events */
+		TELEM_CLEAR_EVENTS(telem_ctrl);
+
+		ret = intel_punit_ipc_command(
+				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				0, 0, &telem_ctrl, NULL);
+		if (ret) {
+			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
+			return ret;
+		}
+		telm_conf->pss_config.ssram_evts_used = 0;
+
+		/* Configure Events */
+		for (index = 0; index < num_pss_evts; index++) {
+			telm_conf->pss_config.telem_evts[index].evt_id =
+			pss_evtmap[index];
+
+			if (telemetry_plt_config_pss_event(
+			    telm_conf->pss_config.telem_evts[index].evt_id,
+			    index)) {
+				pr_err("PSS TELEM_UPDATE Fail for Event %x\n",
+					pss_evtmap[index]);
+				continue;
+			}
+			telm_conf->pss_config.ssram_evts_used++;
+		}
+	}
+
+	/* Add some Events */
+	if (action == TELEM_ADD) {
+		/* Configure Events */
+		for (index = telm_conf->pss_config.ssram_evts_used, idx = 0;
+		     idx < num_pss_evts; index++, idx++) {
+
+			telm_conf->pss_config.telem_evts[index].evt_id =
+			pss_evtmap[idx];
+
+			if (telemetry_plt_config_pss_event(
+			    telm_conf->pss_config.telem_evts[index].evt_id,
+			    index)) {
+				pr_err("PSS TELEM_ADD Fail for Event %x\n",
+					pss_evtmap[idx]);
+				continue;
+			}
+			telm_conf->pss_config.ssram_evts_used++;
+		}
+	}
+
+	/* Enable Periodic Telemetry Events and enable SRAM trace */
+	TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl);
+	TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
+	TELEM_ENABLE_PERIODIC(telem_ctrl);
+	telem_ctrl |= pss_period;
+
+	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, 0, &telem_ctrl, NULL);
+	if (ret) {
+		pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
+		return ret;
+	}
+
+	telm_conf->pss_config.curr_period = pss_period;
+
+	return 0;
+}
+
+static int telemetry_setup_evtconfig(struct telemetry_evtconfig pss_evtconfig,
+				     struct telemetry_evtconfig ioss_evtconfig,
+				     enum telemetry_action action)
+{
+	int ret;
+
+	mutex_lock(&(telm_conf->telem_lock));
+
+	if ((action == TELEM_UPDATE) && (telm_conf->telem_in_use)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = telemetry_check_evtid(TELEM_PSS, pss_evtconfig.evtmap,
+				    pss_evtconfig.num_evts, action);
+	if (ret)
+		goto out;
+
+	ret = telemetry_check_evtid(TELEM_IOSS, ioss_evtconfig.evtmap,
+				    ioss_evtconfig.num_evts, action);
+	if (ret)
+		goto out;
+
+	if (ioss_evtconfig.num_evts) {
+		ret = telemetry_setup_iossevtconfig(ioss_evtconfig, action);
+		if (ret)
+			goto out;
+	}
+
+	if (pss_evtconfig.num_evts) {
+		ret = telemetry_setup_pssevtconfig(pss_evtconfig, action);
+		if (ret)
+			goto out;
+	}
+
+	if ((action == TELEM_UPDATE) || (action == TELEM_ADD))
+		telm_conf->telem_in_use = true;
+	else
+		telm_conf->telem_in_use = false;
+
+out:
+	mutex_unlock(&(telm_conf->telem_lock));
+	return ret;
+}
+
+static int telemetry_setup(struct platform_device *pdev)
+{
+	struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig;
+	u32 read_buf, events, event_regs;
+	int ret;
+
+	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, IOSS_TELEM_INFO_READ,
+				    NULL, 0, &read_buf, IOSS_TELEM_READ_WORD);
+	if (ret) {
+		dev_err(&pdev->dev, "IOSS TELEM_INFO Read Failed\n");
+		return ret;
+	}
+
+	/* Get telemetry Info */
+	events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >>
+		  TELEM_INFO_SRAMEVTS_SHIFT;
+	event_regs = read_buf & TELEM_INFO_NENABLES_MASK;
+	if ((events < TELEM_MAX_EVENTS_SRAM) ||
+	    (event_regs < TELEM_MAX_EVENTS_SRAM)) {
+		dev_err(&pdev->dev, "IOSS:Insufficient Space for SRAM Trace\n");
+		dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n",
+			events, event_regs);
+		return -ENOMEM;
+	}
+
+	telm_conf->ioss_config.min_period = TELEM_MIN_PERIOD(read_buf);
+	telm_conf->ioss_config.max_period = TELEM_MAX_PERIOD(read_buf);
+
+	/* PUNIT Mailbox Setup */
+	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_INFO, 0, 0,
+				      NULL, &read_buf);
+	if (ret) {
+		dev_err(&pdev->dev, "PSS TELEM_INFO Read Failed\n");
+		return ret;
+	}
+
+	/* Get telemetry Info */
+	events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >>
+		  TELEM_INFO_SRAMEVTS_SHIFT;
+	event_regs = read_buf & TELEM_INFO_SRAMEVTS_MASK;
+	if ((events < TELEM_MAX_EVENTS_SRAM) ||
+	    (event_regs < TELEM_MAX_EVENTS_SRAM)) {
+		dev_err(&pdev->dev, "PSS:Insufficient Space for SRAM Trace\n");
+		dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n",
+			events, event_regs);
+		return -ENOMEM;
+	}
+
+	telm_conf->pss_config.min_period = TELEM_MIN_PERIOD(read_buf);
+	telm_conf->pss_config.max_period = TELEM_MAX_PERIOD(read_buf);
+
+	pss_evtconfig.evtmap = NULL;
+	pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS;
+	pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD;
+
+	ioss_evtconfig.evtmap = NULL;
+	ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS;
+	ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD;
+
+	ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
+					TELEM_RESET);
+	if (ret) {
+		dev_err(&pdev->dev, "TELEMTRY Setup Failed\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int telemetry_plt_update_events(struct telemetry_evtconfig pss_evtconfig,
+				struct telemetry_evtconfig ioss_evtconfig)
+{
+	int ret;
+
+	if ((pss_evtconfig.num_evts > 0) &&
+	    (TELEM_SAMPLE_PERIOD_INVALID(pss_evtconfig.period))) {
+		pr_err("PSS Sampling Period Out of Range\n");
+		return -EINVAL;
+	}
+
+	if ((ioss_evtconfig.num_evts > 0) &&
+	    (TELEM_SAMPLE_PERIOD_INVALID(ioss_evtconfig.period))) {
+		pr_err("IOSS Sampling Period Out of Range\n");
+		return -EINVAL;
+	}
+
+	ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
+					TELEM_UPDATE);
+	if (ret)
+		pr_err("TELEMTRY Config Failed\n");
+
+	return ret;
+}
+
+
+static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
+{
+	u32 telem_ctrl = 0;
+	int ret;
+
+	mutex_lock(&(telm_conf->telem_lock));
+	if (ioss_period) {
+		if (TELEM_SAMPLE_PERIOD_INVALID(ioss_period)) {
+			pr_err("IOSS Sampling Period Out of Range\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		/* Get telemetry EVENT CTL */
+		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+					    IOSS_TELEM_EVENT_CTL_READ, NULL, 0,
+					    &telem_ctrl, IOSS_TELEM_READ_WORD);
+		if (ret) {
+			pr_err("IOSS TELEM_CTRL Read Failed\n");
+			goto out;
+		}
+
+		/* Disable Telemetry */
+		TELEM_DISABLE(telem_ctrl);
+
+		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+					    IOSS_TELEM_EVENT_CTL_WRITE,
+					    (u8 *)&telem_ctrl,
+					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+					    NULL, 0);
+		if (ret) {
+			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
+			goto out;
+		}
+
+		/* Enable Periodic Telemetry Events and enable SRAM trace */
+		TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl);
+		TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
+		TELEM_ENABLE_PERIODIC(telem_ctrl);
+		telem_ctrl |= ioss_period;
+
+		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+					    IOSS_TELEM_EVENT_CTL_WRITE,
+					    (u8 *)&telem_ctrl,
+					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+					    NULL, 0);
+		if (ret) {
+			pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n");
+			goto out;
+		}
+		telm_conf->ioss_config.curr_period = ioss_period;
+	}
+
+	if (pss_period) {
+		if (TELEM_SAMPLE_PERIOD_INVALID(pss_period)) {
+			pr_err("PSS Sampling Period Out of Range\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		/* Get telemetry EVENT CTL */
+		ret = intel_punit_ipc_command(
+				IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+				0, 0, NULL, &telem_ctrl);
+		if (ret) {
+			pr_err("PSS TELEM_CTRL Read Failed\n");
+			goto out;
+		}
+
+		/* Disable Telemetry */
+		TELEM_DISABLE(telem_ctrl);
+		ret = intel_punit_ipc_command(
+				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				0, 0, &telem_ctrl, NULL);
+		if (ret) {
+			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
+			goto out;
+		}
+
+		/* Enable Periodic Telemetry Events and enable SRAM trace */
+		TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl);
+		TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
+		TELEM_ENABLE_PERIODIC(telem_ctrl);
+		telem_ctrl |= pss_period;
+
+		ret = intel_punit_ipc_command(
+				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				0, 0, &telem_ctrl, NULL);
+		if (ret) {
+			pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
+			goto out;
+		}
+		telm_conf->pss_config.curr_period = pss_period;
+	}
+
+out:
+	mutex_unlock(&(telm_conf->telem_lock));
+	return ret;
+}
+
+
+static int telemetry_plt_get_sampling_period(u8 *pss_min_period,
+					     u8 *pss_max_period,
+					     u8 *ioss_min_period,
+					     u8 *ioss_max_period)
+{
+	*pss_min_period = telm_conf->pss_config.min_period;
+	*pss_max_period = telm_conf->pss_config.max_period;
+	*ioss_min_period = telm_conf->ioss_config.min_period;
+	*ioss_max_period = telm_conf->ioss_config.max_period;
+
+	return 0;
+}
+
+
+static int telemetry_plt_reset_events(void)
+{
+	struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig;
+	int ret;
+
+	pss_evtconfig.evtmap = NULL;
+	pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS;
+	pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD;
+
+	ioss_evtconfig.evtmap = NULL;
+	ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS;
+	ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD;
+
+	ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
+					TELEM_RESET);
+	if (ret)
+		pr_err("TELEMTRY Reset Failed\n");
+
+	return ret;
+}
+
+
+static int telemetry_plt_get_eventconfig(struct telemetry_evtconfig *pss_config,
+					struct telemetry_evtconfig *ioss_config,
+					int pss_len, int ioss_len)
+{
+	u32 *pss_evtmap, *ioss_evtmap;
+	u32 index;
+
+	pss_evtmap = pss_config->evtmap;
+	ioss_evtmap = ioss_config->evtmap;
+
+	mutex_lock(&(telm_conf->telem_lock));
+	pss_config->num_evts = telm_conf->pss_config.ssram_evts_used;
+	ioss_config->num_evts = telm_conf->ioss_config.ssram_evts_used;
+
+	pss_config->period = telm_conf->pss_config.curr_period;
+	ioss_config->period = telm_conf->ioss_config.curr_period;
+
+	if ((pss_len < telm_conf->pss_config.ssram_evts_used) ||
+	    (ioss_len < telm_conf->ioss_config.ssram_evts_used)) {
+		mutex_unlock(&(telm_conf->telem_lock));
+		return -EINVAL;
+	}
+
+	for (index = 0; index < telm_conf->pss_config.ssram_evts_used;
+	     index++) {
+		pss_evtmap[index] =
+		telm_conf->pss_config.telem_evts[index].evt_id;
+	}
+
+	for (index = 0; index < telm_conf->ioss_config.ssram_evts_used;
+	     index++) {
+		ioss_evtmap[index] =
+		telm_conf->ioss_config.telem_evts[index].evt_id;
+	}
+
+	mutex_unlock(&(telm_conf->telem_lock));
+	return 0;
+}
+
+
+static int telemetry_plt_add_events(u8 num_pss_evts, u8 num_ioss_evts,
+				    u32 *pss_evtmap, u32 *ioss_evtmap)
+{
+	struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig;
+	int ret;
+
+	pss_evtconfig.evtmap = pss_evtmap;
+	pss_evtconfig.num_evts = num_pss_evts;
+	pss_evtconfig.period = telm_conf->pss_config.curr_period;
+
+	ioss_evtconfig.evtmap = ioss_evtmap;
+	ioss_evtconfig.num_evts = num_ioss_evts;
+	ioss_evtconfig.period = telm_conf->ioss_config.curr_period;
+
+	ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
+					TELEM_ADD);
+	if (ret)
+		pr_err("TELEMTRY ADD Failed\n");
+
+	return ret;
+}
+
+static int telem_evtlog_read(enum telemetry_unit telem_unit,
+			     struct telem_ssram_region *ssram_region, u8 len)
+{
+	struct telemetry_unit_config *unit_config;
+	u64 timestamp_prev, timestamp_next;
+	int ret, index, timeout = 0;
+
+	ret = telem_get_unitconfig(telem_unit, &unit_config);
+	if (ret < 0)
+		return ret;
+
+	if (len > unit_config->ssram_evts_used)
+		len = unit_config->ssram_evts_used;
+
+	do {
+		timestamp_prev = readq(unit_config->regmap);
+		if (!timestamp_prev) {
+			pr_err("Ssram under update. Please Try Later\n");
+			return -EBUSY;
+		}
+
+		ssram_region->start_time = readq(unit_config->regmap +
+						 TELEM_SSRAM_STARTTIME_OFFSET);
+
+		for (index = 0; index < len; index++) {
+			ssram_region->events[index] =
+			readq(unit_config->regmap + TELEM_SSRAM_EVTLOG_OFFSET +
+			      BYTES_PER_LONG*index);
+		}
+
+		timestamp_next = readq(unit_config->regmap);
+		if (!timestamp_next) {
+			pr_err("Ssram under update. Please Try Later\n");
+			return -EBUSY;
+		}
+
+		if (timeout++ > TELEM_SSRAM_READ_TIMEOUT) {
+			pr_err("Timeout while reading Events\n");
+			return -EBUSY;
+		}
+
+	} while (timestamp_prev != timestamp_next);
+
+	ssram_region->timestamp = timestamp_next;
+
+	return len;
+}
+
+static int telemetry_plt_raw_read_eventlog(enum telemetry_unit telem_unit,
+					   struct telemetry_evtlog *evtlog,
+					   int len, int log_all_evts)
+{
+	int index, idx1, ret, readlen = len;
+	struct telem_ssram_region ssram_region;
+	struct telemetry_evtmap *evtmap;
+
+	switch (telem_unit)	{
+	case TELEM_PSS:
+		evtmap = telm_conf->pss_config.telem_evts;
+		break;
+
+	case TELEM_IOSS:
+		evtmap = telm_conf->ioss_config.telem_evts;
+		break;
+
+	default:
+		pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit);
+		return -EINVAL;
+	}
+
+	if (!log_all_evts)
+		readlen = TELEM_MAX_EVENTS_SRAM;
+
+	ret = telem_evtlog_read(telem_unit, &ssram_region, readlen);
+	if (ret < 0)
+		return ret;
+
+	/* Invalid evt-id array specified via length mismatch */
+	if ((!log_all_evts) && (len > ret))
+		return -EINVAL;
+
+	if (log_all_evts)
+		for (index = 0; index < ret; index++) {
+			evtlog[index].telem_evtlog = ssram_region.events[index];
+			evtlog[index].telem_evtid = evtmap[index].evt_id;
+		}
+	else
+		for (index = 0, readlen = 0; (index < ret) && (readlen < len);
+		     index++) {
+			for (idx1 = 0; idx1 < len; idx1++) {
+				/* Elements matched */
+				if (evtmap[index].evt_id ==
+				    evtlog[idx1].telem_evtid) {
+					evtlog[idx1].telem_evtlog =
+					ssram_region.events[index];
+					readlen++;
+
+					break;
+				}
+			}
+		}
+
+	return readlen;
+}
+
+static int telemetry_plt_read_eventlog(enum telemetry_unit telem_unit,
+		struct telemetry_evtlog *evtlog, int len, int log_all_evts)
+{
+	int ret;
+
+	mutex_lock(&(telm_conf->telem_lock));
+	ret = telemetry_plt_raw_read_eventlog(telem_unit, evtlog,
+					      len, log_all_evts);
+	mutex_unlock(&(telm_conf->telem_lock));
+
+	return ret;
+}
+
+static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit,
+					     u32 *verbosity)
+{
+	u32 temp = 0;
+	int ret;
+
+	if (verbosity == NULL)
+		return -EINVAL;
+
+	mutex_lock(&(telm_conf->telem_trace_lock));
+	switch (telem_unit) {
+	case TELEM_PSS:
+		ret = intel_punit_ipc_command(
+				IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
+				0, 0, NULL, &temp);
+		if (ret) {
+			pr_err("PSS TRACE_CTRL Read Failed\n");
+			goto out;
+		}
+
+		break;
+
+	case TELEM_IOSS:
+		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+				IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp,
+				IOSS_TELEM_READ_WORD);
+		if (ret) {
+			pr_err("IOSS TRACE_CTL Read Failed\n");
+			goto out;
+		}
+
+		break;
+
+	default:
+		pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit);
+		ret = -EINVAL;
+		break;
+	}
+	TELEM_EXTRACT_VERBOSITY(temp, *verbosity);
+
+out:
+	mutex_unlock(&(telm_conf->telem_trace_lock));
+	return ret;
+}
+
+static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
+					     u32 verbosity)
+{
+	u32 temp = 0;
+	int ret;
+
+	verbosity &= TELEM_TRC_VERBOSITY_MASK;
+
+	mutex_lock(&(telm_conf->telem_trace_lock));
+	switch (telem_unit) {
+	case TELEM_PSS:
+		ret = intel_punit_ipc_command(
+				IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL,
+				0, 0, &verbosity, NULL);
+		if (ret) {
+			pr_err("PSS TRACE_CTRL Verbosity Set Failed\n");
+			goto out;
+		}
+		break;
+
+	case TELEM_IOSS:
+		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+				IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp,
+				IOSS_TELEM_READ_WORD);
+		if (ret) {
+			pr_err("IOSS TRACE_CTL Read Failed\n");
+			goto out;
+		}
+
+		TELEM_CLEAR_VERBOSITY_BITS(temp);
+		TELEM_SET_VERBOSITY_BITS(temp, verbosity);
+
+		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+				IOSS_TELEM_TRACE_CTL_WRITE, (u8 *)&temp,
+				IOSS_TELEM_WRITE_FOURBYTES, NULL, 0);
+		if (ret) {
+			pr_err("IOSS TRACE_CTL Verbosity Set Failed\n");
+			goto out;
+		}
+		break;
+
+	default:
+		pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit);
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	mutex_unlock(&(telm_conf->telem_trace_lock));
+	return ret;
+}
+
+static struct telemetry_core_ops telm_pltops = {
+	.get_trace_verbosity = telemetry_plt_get_trace_verbosity,
+	.set_trace_verbosity = telemetry_plt_set_trace_verbosity,
+	.set_sampling_period = telemetry_plt_set_sampling_period,
+	.get_sampling_period = telemetry_plt_get_sampling_period,
+	.raw_read_eventlog = telemetry_plt_raw_read_eventlog,
+	.get_eventconfig = telemetry_plt_get_eventconfig,
+	.update_events = telemetry_plt_update_events,
+	.read_eventlog = telemetry_plt_read_eventlog,
+	.reset_events = telemetry_plt_reset_events,
+	.add_events = telemetry_plt_add_events,
+};
+
+static int telemetry_pltdrv_probe(struct platform_device *pdev)
+{
+	struct resource *res0 = NULL, *res1 = NULL;
+	const struct x86_cpu_id *id;
+	int size, ret = -ENOMEM;
+
+	id = x86_match_cpu(telemetry_cpu_ids);
+	if (!id)
+		return -ENODEV;
+
+	telm_conf = (struct telemetry_plt_config *)id->driver_data;
+
+	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res0) {
+		ret = -EINVAL;
+		goto out;
+	}
+	size = resource_size(res0);
+	if (!devm_request_mem_region(&pdev->dev, res0->start, size,
+				     pdev->name)) {
+		ret = -EBUSY;
+		goto out;
+	}
+	telm_conf->pss_config.ssram_base_addr = res0->start;
+	telm_conf->pss_config.ssram_size = size;
+
+	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res1) {
+		ret = -EINVAL;
+		goto out;
+	}
+	size = resource_size(res1);
+	if (!devm_request_mem_region(&pdev->dev, res1->start, size,
+				     pdev->name)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	telm_conf->ioss_config.ssram_base_addr = res1->start;
+	telm_conf->ioss_config.ssram_size = size;
+
+	telm_conf->pss_config.regmap = ioremap_nocache(
+					telm_conf->pss_config.ssram_base_addr,
+					telm_conf->pss_config.ssram_size);
+	if (!telm_conf->pss_config.regmap) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	telm_conf->ioss_config.regmap = ioremap_nocache(
+				telm_conf->ioss_config.ssram_base_addr,
+				telm_conf->ioss_config.ssram_size);
+	if (!telm_conf->ioss_config.regmap) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mutex_init(&telm_conf->telem_lock);
+	mutex_init(&telm_conf->telem_trace_lock);
+
+	ret = telemetry_setup(pdev);
+	if (ret)
+		goto out;
+
+	ret = telemetry_set_pltdata(&telm_pltops, telm_conf);
+	if (ret) {
+		dev_err(&pdev->dev, "TELEMTRY Set Pltops Failed.\n");
+		goto out;
+	}
+
+	return 0;
+
+out:
+	if (res0)
+		release_mem_region(res0->start, resource_size(res0));
+	if (res1)
+		release_mem_region(res1->start, resource_size(res1));
+	if (telm_conf->pss_config.regmap)
+		iounmap(telm_conf->pss_config.regmap);
+	if (telm_conf->ioss_config.regmap)
+		iounmap(telm_conf->ioss_config.regmap);
+	dev_err(&pdev->dev, "TELEMTRY Setup Failed.\n");
+
+	return ret;
+}
+
+static int telemetry_pltdrv_remove(struct platform_device *pdev)
+{
+	telemetry_clear_pltdata();
+	iounmap(telm_conf->pss_config.regmap);
+	iounmap(telm_conf->ioss_config.regmap);
+
+	return 0;
+}
+
+static struct platform_driver telemetry_soc_driver = {
+	.probe		= telemetry_pltdrv_probe,
+	.remove		= telemetry_pltdrv_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+static int __init telemetry_module_init(void)
+{
+	pr_info(DRIVER_NAME ": version %s loaded\n", DRIVER_VERSION);
+	return platform_driver_register(&telemetry_soc_driver);
+}
+
+static void __exit telemetry_module_exit(void)
+{
+	platform_driver_unregister(&telemetry_soc_driver);
+}
+
+device_initcall(telemetry_module_init);
+module_exit(telemetry_module_exit);
+
+MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
+MODULE_DESCRIPTION("Intel SoC Telemetry Platform Driver");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/platform/x86/sony-laptop.c
+++ linux-4.4.0/drivers/platform/x86/sony-laptop.c
@@ -4394,14 +4394,16 @@
 			}
 			return AE_OK;
 		}
+
+	case ACPI_RESOURCE_TYPE_END_TAG:
+		return AE_OK;
+
 	default:
 		dprintk("Resource %d isn't an IRQ nor an IO port\n",
 			resource->type);
+		return AE_CTRL_TERMINATE;
 
-	case ACPI_RESOURCE_TYPE_END_TAG:
-		return AE_OK;
 	}
-	return AE_CTRL_TERMINATE;
 }
 
 static int sony_pic_possible_resources(struct acpi_device *device)
--- linux-4.4.0.orig/drivers/platform/x86/tc1100-wmi.c
+++ linux-4.4.0/drivers/platform/x86/tc1100-wmi.c
@@ -52,7 +52,9 @@
 	u32 jogdial;
 };
 
+#ifdef CONFIG_PM
 static struct tc1100_data suspend_data;
+#endif
 
 /* --------------------------------------------------------------------------
 				Device Management
--- linux-4.4.0.orig/drivers/platform/x86/thinkpad_acpi.c
+++ linux-4.4.0/drivers/platform/x86/thinkpad_acpi.c
@@ -128,6 +128,7 @@
 /* ACPI HIDs */
 #define TPACPI_ACPI_IBM_HKEY_HID	"IBM0068"
 #define TPACPI_ACPI_LENOVO_HKEY_HID	"LEN0068"
+#define TPACPI_ACPI_LENOVO_HKEY_V2_HID	"LEN0268"
 #define TPACPI_ACPI_EC_HID		"PNP0C09"
 
 /* Input IDs */
@@ -303,6 +304,7 @@
 	u32 hotkey_mask:1;
 	u32 hotkey_wlsw:1;
 	u32 hotkey_tablet:1;
+	u32 kbdlight:1;
 	u32 light:1;
 	u32 light_status:1;
 	u32 bright_acpimode:1;
@@ -1913,7 +1915,9 @@
 	TP_ACPI_HOTKEYSCAN_UNK7,
 	TP_ACPI_HOTKEYSCAN_UNK8,
 
-	TP_ACPI_HOTKEYSCAN_MUTE2,
+	/* Adaptive keyboard keycodes */
+	TP_ACPI_HOTKEYSCAN_ADAPTIVE_START,
+	TP_ACPI_HOTKEYSCAN_MUTE2        = TP_ACPI_HOTKEYSCAN_ADAPTIVE_START,
 	TP_ACPI_HOTKEYSCAN_BRIGHTNESS_ZERO,
 	TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL,
 	TP_ACPI_HOTKEYSCAN_CLOUD,
@@ -1934,6 +1938,15 @@
 	TP_ACPI_HOTKEYSCAN_CAMERA_MODE,
 	TP_ACPI_HOTKEYSCAN_ROTATE_DISPLAY,
 
+	/* Lenovo extended keymap, starting at 0x1300 */
+	TP_ACPI_HOTKEYSCAN_EXTENDED_START,
+	/* first new observed key (star, favorites) is 0x1311 */
+	TP_ACPI_HOTKEYSCAN_STAR = 69,
+	TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2,
+	TP_ACPI_HOTKEYSCAN_UNK25,
+	TP_ACPI_HOTKEYSCAN_BLUETOOTH,
+	TP_ACPI_HOTKEYSCAN_KEYBOARD,
+
 	/* Hotkey keymap size */
 	TPACPI_HOTKEY_MAP_LEN
 };
@@ -2042,6 +2055,7 @@
 
 static u32 hotkey_orig_mask;		/* events the BIOS had enabled */
 static u32 hotkey_all_mask;		/* all events supported in fw */
+static u32 hotkey_adaptive_all_mask;	/* all adaptive events supported in fw */
 static u32 hotkey_reserved_mask;	/* events better left disabled */
 static u32 hotkey_driver_mask;		/* events needed by the driver */
 static u32 hotkey_user_mask;		/* events visible to userspace */
@@ -2474,7 +2488,7 @@
  */
 static int hotkey_kthread(void *data)
 {
-	struct tp_nvram_state s[2];
+	struct tp_nvram_state s[2] = { 0 };
 	u32 poll_mask, event_mask;
 	unsigned int si, so;
 	unsigned long t;
@@ -2741,6 +2755,17 @@
 
 static DEVICE_ATTR_RO(hotkey_all_mask);
 
+/* sysfs hotkey all_mask ----------------------------------------------- */
+static ssize_t hotkey_adaptive_all_mask_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n",
+			hotkey_adaptive_all_mask | hotkey_source_mask);
+}
+
+static DEVICE_ATTR_RO(hotkey_adaptive_all_mask);
+
 /* sysfs hotkey recommended_mask --------------------------------------- */
 static ssize_t hotkey_recommended_mask_show(struct device *dev,
 					    struct device_attribute *attr,
@@ -2984,6 +3009,7 @@
 	&dev_attr_wakeup_hotunplug_complete.attr,
 	&dev_attr_hotkey_mask.attr,
 	&dev_attr_hotkey_all_mask.attr,
+	&dev_attr_hotkey_adaptive_all_mask.attr,
 	&dev_attr_hotkey_recommended_mask.attr,
 #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
 	&dev_attr_hotkey_source_mask.attr,
@@ -3182,6 +3208,15 @@
 		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
 		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
 		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+
+		/* No assignment, used for newer Lenovo models */
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN
+
 		},
 
 	/* Generic keymap for Lenovo ThinkPads */
@@ -3267,6 +3302,29 @@
 		KEY_RESERVED,        /* Microphone cancellation */
 		KEY_RESERVED,        /* Camera mode */
 		KEY_RESERVED,        /* Rotate display, 0x116 */
+
+		/*
+		 * These are found in 2017 models (e.g. T470s, X270).
+		 * The lowest known value is 0x311, which according to
+		 * the manual should launch a user defined favorite
+		 * application.
+		 *
+		 * The offset for these is TP_ACPI_HOTKEYSCAN_EXTENDED_START,
+		 * corresponding to 0x34.
+		 */
+
+		/* (assignments unknown, please report if found) */
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN,
+
+		KEY_FAVORITES,       /* Favorite app, 0x311 */
+		KEY_RESERVED,        /* Clipping tool */
+		KEY_RESERVED,
+		KEY_BLUETOOTH,       /* Bluetooth */
+		KEY_KEYBOARD         /* Keyboard, 0x315 */
 		},
 	};
 
@@ -3320,20 +3378,6 @@
 	if (!tp_features.hotkey)
 		return 1;
 
-	/*
-	 * Check if we have an adaptive keyboard, like on the
-	 * Lenovo Carbon X1 2014 (2nd Gen).
-	 */
-	if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
-		if ((hkeyv >> 8) == 2) {
-			tp_features.has_adaptive_kbd = true;
-			res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
-					&adaptive_kbd_attr_group);
-			if (res)
-				goto err_exit;
-		}
-	}
-
 	quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable,
 				     ARRAY_SIZE(tpacpi_hotkey_qtable));
 
@@ -3356,30 +3400,70 @@
 	   A30, R30, R31, T20-22, X20-21, X22-24.  Detected by checking
 	   for HKEY interface version 0x100 */
 	if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
-		if ((hkeyv >> 8) != 1) {
-			pr_err("unknown version of the HKEY interface: 0x%x\n",
-			       hkeyv);
-			pr_err("please report this to %s\n", TPACPI_MAIL);
-		} else {
+		vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+			    "firmware HKEY interface version: 0x%x\n",
+			    hkeyv);
+
+		switch (hkeyv >> 8) {
+		case 1:
 			/*
 			 * MHKV 0x100 in A31, R40, R40e,
 			 * T4x, X31, and later
 			 */
-			vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-				"firmware HKEY interface version: 0x%x\n",
-				hkeyv);
 
 			/* Paranoia check AND init hotkey_all_mask */
 			if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
 					"MHKA", "qd")) {
-				pr_err("missing MHKA handler, "
-				       "please report this to %s\n",
+				pr_err("missing MHKA handler, please report this to %s\n",
+				       TPACPI_MAIL);
+				/* Fallback: pre-init for FN+F3,F4,F12 */
+				hotkey_all_mask = 0x080cU;
+			} else {
+				tp_features.hotkey_mask = 1;
+			}
+			break;
+
+		case 2:
+			/*
+			 * MHKV 0x200 in X1, T460s, X260, T560, X1 Tablet (2016)
+			 */
+
+			/* Paranoia check AND init hotkey_all_mask */
+			if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
+					"MHKA", "dd", 1)) {
+				pr_err("missing MHKA handler, please report this to %s\n",
 				       TPACPI_MAIL);
 				/* Fallback: pre-init for FN+F3,F4,F12 */
 				hotkey_all_mask = 0x080cU;
 			} else {
 				tp_features.hotkey_mask = 1;
 			}
+
+			/*
+			 * Check if we have an adaptive keyboard, like on the
+			 * Lenovo Carbon X1 2014 (2nd Gen).
+			 */
+			if (acpi_evalf(hkey_handle, &hotkey_adaptive_all_mask,
+				       "MHKA", "dd", 2)) {
+				if (hotkey_adaptive_all_mask != 0) {
+					tp_features.has_adaptive_kbd = true;
+					res = sysfs_create_group(
+						&tpacpi_pdev->dev.kobj,
+						&adaptive_kbd_attr_group);
+					if (res)
+						goto err_exit;
+				}
+			} else {
+				tp_features.has_adaptive_kbd = false;
+				hotkey_adaptive_all_mask = 0x0U;
+			}
+			break;
+
+		default:
+			pr_err("unknown version of the HKEY interface: 0x%x\n",
+			       hkeyv);
+			pr_err("please report this to %s\n", TPACPI_MAIL);
+			break;
 		}
 	}
 
@@ -3569,7 +3653,6 @@
 #define DFR_CHANGE_ROW			0x101
 #define DFR_SHOW_QUICKVIEW_ROW		0x102
 #define FIRST_ADAPTIVE_KEY		0x103
-#define ADAPTIVE_KEY_OFFSET		0x020
 
 /* press Fn key a while second, it will switch to Function Mode. Then
  * release Fn key, previous mode be restored.
@@ -3659,13 +3742,15 @@
 
 	default:
 		if (scancode < FIRST_ADAPTIVE_KEY ||
-		    scancode >= FIRST_ADAPTIVE_KEY + TPACPI_HOTKEY_MAP_LEN -
-				ADAPTIVE_KEY_OFFSET) {
+		    scancode >= FIRST_ADAPTIVE_KEY +
+		    TP_ACPI_HOTKEYSCAN_EXTENDED_START -
+		    TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) {
 			pr_info("Unhandled adaptive keyboard key: 0x%x\n",
 					scancode);
 			return false;
 		}
-		keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY + ADAPTIVE_KEY_OFFSET];
+		keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY +
+					     TP_ACPI_HOTKEYSCAN_ADAPTIVE_START];
 		if (keycode != KEY_RESERVED) {
 			mutex_lock(&tpacpi_inputdev_send_mutex);
 
@@ -3690,19 +3775,44 @@
 	*send_acpi_ev = true;
 	*ignore_acpi_ev = false;
 
-	/* HKEY event 0x1001 is scancode 0x00 */
-	if (scancode > 0 && scancode <= TPACPI_HOTKEY_MAP_LEN) {
-		scancode--;
-		if (!(hotkey_source_mask & (1 << scancode))) {
-			tpacpi_input_send_key_masked(scancode);
-			*send_acpi_ev = false;
-		} else {
-			*ignore_acpi_ev = true;
+	/*
+	 * Original events are in the 0x10XX range, the adaptive keyboard
+	 * found in 2014 X1 Carbon emits events are of 0x11XX. In 2017
+	 * models, additional keys are emitted through 0x13XX.
+	 */
+	switch ((hkey >> 8) & 0xf) {
+	case 0:
+		if (scancode > 0 &&
+		    scancode <= TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) {
+			/* HKEY event 0x1001 is scancode 0x00 */
+			scancode--;
+			if (!(hotkey_source_mask & (1 << scancode))) {
+				tpacpi_input_send_key_masked(scancode);
+				*send_acpi_ev = false;
+			} else {
+				*ignore_acpi_ev = true;
+			}
+			return true;
 		}
-		return true;
-	} else {
+		break;
+
+	case 1:
 		return adaptive_keyboard_hotkey_notify_hotkey(scancode);
+
+	case 3:
+		/* Extended keycodes start at 0x300 and our offset into the map
+		 * TP_ACPI_HOTKEYSCAN_EXTENDED_START. The calculated scancode
+		 * will be positive, but might not be in the correct range.
+		 */
+		scancode -= (0x300 - TP_ACPI_HOTKEYSCAN_EXTENDED_START);
+		if (scancode >= TP_ACPI_HOTKEYSCAN_EXTENDED_START &&
+		    scancode < TPACPI_HOTKEY_MAP_LEN) {
+			tpacpi_input_send_key(scancode);
+			return true;
+		}
+		break;
 	}
+
 	return false;
 }
 
@@ -4103,6 +4213,7 @@
 static const struct acpi_device_id ibm_htk_device_ids[] = {
 	{TPACPI_ACPI_IBM_HKEY_HID, 0},
 	{TPACPI_ACPI_LENOVO_HKEY_HID, 0},
+	{TPACPI_ACPI_LENOVO_HKEY_V2_HID, 0},
 	{"", 0},
 };
 
@@ -4986,6 +5097,207 @@
 #endif /* CONFIG_THINKPAD_ACPI_VIDEO */
 
 /*************************************************************************
+ * Keyboard backlight subdriver
+ */
+
+static int kbdlight_set_level(int level)
+{
+	if (!hkey_handle)
+		return -ENXIO;
+
+	if (!acpi_evalf(hkey_handle, NULL, "MLCS", "dd", level))
+		return -EIO;
+
+	return 0;
+}
+
+static int kbdlight_get_level(void)
+{
+	int status = 0;
+
+	if (!hkey_handle)
+		return -ENXIO;
+
+	if (!acpi_evalf(hkey_handle, &status, "MLCG", "dd", 0))
+		return -EIO;
+
+	if (status < 0)
+		return status;
+
+	return status & 0x3;
+}
+
+static bool kbdlight_is_supported(void)
+{
+	int status = 0;
+
+	if (!hkey_handle)
+		return false;
+
+	if (!acpi_has_method(hkey_handle, "MLCG")) {
+		vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG is unavailable\n");
+		return false;
+	}
+
+	if (!acpi_evalf(hkey_handle, &status, "MLCG", "qdd", 0)) {
+		vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG failed\n");
+		return false;
+	}
+
+	if (status < 0) {
+		vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG err: %d\n", status);
+		return false;
+	}
+
+	vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG returned 0x%x\n", status);
+	/*
+	 * Guessed test for keyboard backlight:
+	 *
+	 * Machines with backlight keyboard return:
+	 *   b010100000010000000XX - ThinkPad X1 Carbon 3rd
+	 *   b110100010010000000XX - ThinkPad x230
+	 *   b010100000010000000XX - ThinkPad x240
+	 *   b010100000010000000XX - ThinkPad W541
+	 * (XX is current backlight level)
+	 *
+	 * Machines without backlight keyboard return:
+	 *   b10100001000000000000 - ThinkPad x230
+	 *   b10110001000000000000 - ThinkPad E430
+	 *   b00000000000000000000 - ThinkPad E450
+	 *
+	 * Candidate BITs for detection test (XOR):
+	 *   b01000000001000000000
+	 *              ^
+	 */
+	return status & BIT(9);
+}
+
+static void kbdlight_set_worker(struct work_struct *work)
+{
+	struct tpacpi_led_classdev *data =
+			container_of(work, struct tpacpi_led_classdev, work);
+
+	if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+		kbdlight_set_level(data->new_state);
+}
+
+static void kbdlight_sysfs_set(struct led_classdev *led_cdev,
+			enum led_brightness brightness)
+{
+	struct tpacpi_led_classdev *data =
+			container_of(led_cdev,
+				     struct tpacpi_led_classdev,
+				     led_classdev);
+	data->new_state = brightness;
+	queue_work(tpacpi_wq, &data->work);
+}
+
+static enum led_brightness kbdlight_sysfs_get(struct led_classdev *led_cdev)
+{
+	int level;
+
+	level = kbdlight_get_level();
+	if (level < 0)
+		return 0;
+
+	return level;
+}
+
+static struct tpacpi_led_classdev tpacpi_led_kbdlight = {
+	.led_classdev = {
+		.name		= "tpacpi::kbd_backlight",
+		.max_brightness	= 2,
+		.brightness_set	= &kbdlight_sysfs_set,
+		.brightness_get	= &kbdlight_sysfs_get,
+		.flags		= LED_CORE_SUSPENDRESUME,
+	}
+};
+
+static int __init kbdlight_init(struct ibm_init_struct *iibm)
+{
+	int rc;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing kbdlight subdriver\n");
+
+	TPACPI_ACPIHANDLE_INIT(hkey);
+	INIT_WORK(&tpacpi_led_kbdlight.work, kbdlight_set_worker);
+
+	if (!kbdlight_is_supported()) {
+		tp_features.kbdlight = 0;
+		vdbg_printk(TPACPI_DBG_INIT, "kbdlight is unsupported\n");
+		return 1;
+	}
+
+	tp_features.kbdlight = 1;
+
+	rc = led_classdev_register(&tpacpi_pdev->dev,
+				   &tpacpi_led_kbdlight.led_classdev);
+	if (rc < 0) {
+		tp_features.kbdlight = 0;
+		return rc;
+	}
+
+	return 0;
+}
+
+static void kbdlight_exit(void)
+{
+	if (tp_features.kbdlight)
+		led_classdev_unregister(&tpacpi_led_kbdlight.led_classdev);
+	flush_workqueue(tpacpi_wq);
+}
+
+static int kbdlight_read(struct seq_file *m)
+{
+	int level;
+
+	if (!tp_features.kbdlight) {
+		seq_printf(m, "status:\t\tnot supported\n");
+	} else {
+		level = kbdlight_get_level();
+		if (level < 0)
+			seq_printf(m, "status:\t\terror %d\n", level);
+		else
+			seq_printf(m, "status:\t\t%d\n", level);
+		seq_printf(m, "commands:\t0, 1, 2\n");
+	}
+
+	return 0;
+}
+
+static int kbdlight_write(char *buf)
+{
+	char *cmd;
+	int level = -1;
+
+	if (!tp_features.kbdlight)
+		return -ENODEV;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (strlencmp(cmd, "0") == 0)
+			level = 0;
+		else if (strlencmp(cmd, "1") == 0)
+			level = 1;
+		else if (strlencmp(cmd, "2") == 0)
+			level = 2;
+		else
+			return -EINVAL;
+	}
+
+	if (level == -1)
+		return -EINVAL;
+
+	return kbdlight_set_level(level);
+}
+
+static struct ibm_struct kbdlight_driver_data = {
+	.name = "kbdlight",
+	.read = kbdlight_read,
+	.write = kbdlight_write,
+	.exit = kbdlight_exit,
+};
+
+/*************************************************************************
  * Light (thinklight) subdriver
  */
 
@@ -6362,8 +6674,10 @@
 	list_for_each_entry(child, &device->children, node) {
 		acpi_status status = acpi_evaluate_object(child->handle, "_BCL",
 							  NULL, &buffer);
-		if (ACPI_FAILURE(status))
+		if (ACPI_FAILURE(status)) {
+			buffer.length = ACPI_ALLOCATE_BUFFER;
 			continue;
+		}
 
 		obj = (union acpi_object *)buffer.pointer;
 		if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
@@ -9207,6 +9521,10 @@
 	},
 #endif
 	{
+		.init = kbdlight_init,
+		.data = &kbdlight_driver_data,
+	},
+	{
 		.init = light_init,
 		.data = &light_driver_data,
 	},
--- linux-4.4.0.orig/drivers/platform/x86/toshiba-wmi.c
+++ linux-4.4.0/drivers/platform/x86/toshiba-wmi.c
@@ -24,14 +24,15 @@
 #include <linux/acpi.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
+#include <linux/dmi.h>
 
 MODULE_AUTHOR("Azael Avalos");
 MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver");
 MODULE_LICENSE("GPL");
 
-#define TOSHIBA_WMI_EVENT_GUID	"59142400-C6A3-40FA-BADB-8A2652834100"
+#define WMI_EVENT_GUID	"59142400-C6A3-40FA-BADB-8A2652834100"
 
-MODULE_ALIAS("wmi:"TOSHIBA_WMI_EVENT_GUID);
+MODULE_ALIAS("wmi:"WMI_EVENT_GUID);
 
 static struct input_dev *toshiba_wmi_input_dev;
 
@@ -63,6 +64,16 @@
 	kfree(response.pointer);
 }
 
+static struct dmi_system_id toshiba_wmi_dmi_table[] __initdata = {
+	{
+		.ident = "Toshiba laptop",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+		},
+	},
+	{}
+};
+
 static int __init toshiba_wmi_input_setup(void)
 {
 	acpi_status status;
@@ -81,7 +92,7 @@
 	if (err)
 		goto err_free_dev;
 
-	status = wmi_install_notify_handler(TOSHIBA_WMI_EVENT_GUID,
+	status = wmi_install_notify_handler(WMI_EVENT_GUID,
 					    toshiba_wmi_notify, NULL);
 	if (ACPI_FAILURE(status)) {
 		err = -EIO;
@@ -95,7 +106,7 @@
 	return 0;
 
  err_remove_notifier:
-	wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID);
+	wmi_remove_notify_handler(WMI_EVENT_GUID);
  err_free_keymap:
 	sparse_keymap_free(toshiba_wmi_input_dev);
  err_free_dev:
@@ -105,7 +116,7 @@
 
 static void toshiba_wmi_input_destroy(void)
 {
-	wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID);
+	wmi_remove_notify_handler(WMI_EVENT_GUID);
 	sparse_keymap_free(toshiba_wmi_input_dev);
 	input_unregister_device(toshiba_wmi_input_dev);
 }
@@ -114,7 +125,8 @@
 {
 	int ret;
 
-	if (!wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+	if (!wmi_has_guid(WMI_EVENT_GUID) ||
+	    !dmi_check_system(toshiba_wmi_dmi_table))
 		return -ENODEV;
 
 	ret = toshiba_wmi_input_setup();
@@ -130,7 +142,7 @@
 
 static void __exit toshiba_wmi_exit(void)
 {
-	if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+	if (wmi_has_guid(WMI_EVENT_GUID))
 		toshiba_wmi_input_destroy();
 }
 
--- linux-4.4.0.orig/drivers/platform/x86/toshiba_acpi.c
+++ linux-4.4.0/drivers/platform/x86/toshiba_acpi.c
@@ -34,6 +34,7 @@
 #define TOSHIBA_ACPI_VERSION	"0.23"
 #define PROC_INTERFACE_VERSION	1
 
+#include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -131,7 +132,7 @@
 /* Field definitions */
 #define HCI_ACCEL_MASK			0x7fff
 #define HCI_HOTKEY_DISABLE		0x0b
-#define HCI_HOTKEY_ENABLE		0x01
+#define HCI_HOTKEY_ENABLE		0x09
 #define HCI_HOTKEY_SPECIAL_FUNCTIONS	0x10
 #define HCI_LCD_BRIGHTNESS_BITS		3
 #define HCI_LCD_BRIGHTNESS_SHIFT	(16-HCI_LCD_BRIGHTNESS_BITS)
@@ -1472,7 +1473,7 @@
 	.write		= keys_proc_write,
 };
 
-static int version_proc_show(struct seq_file *m, void *v)
+static int __maybe_unused version_proc_show(struct seq_file *m, void *v)
 {
 	seq_printf(m, "driver:                  %s\n", TOSHIBA_ACPI_VERSION);
 	seq_printf(m, "proc_interface:          %d\n", PROC_INTERFACE_VERSION);
@@ -2484,6 +2485,14 @@
 	brightness = __get_lcd_brightness(dev);
 	if (brightness < 0)
 		return 0;
+	/*
+	 * If transflective backlight is supported and the brightness is zero
+	 * (lowest brightness level), the set_lcd_brightness function will
+	 * activate the transflective backlight, making the LCD appear to be
+	 * turned off, simply increment the brightness level to avoid that.
+	 */
+	if (dev->tr_backlight_supported && brightness == 0)
+		brightness++;
 	ret = set_lcd_brightness(dev, brightness);
 	if (ret) {
 		pr_debug("Backlight method is read-only, disabling backlight support\n");
--- linux-4.4.0.orig/drivers/pnp/isapnp/core.c
+++ linux-4.4.0/drivers/pnp/isapnp/core.c
@@ -41,6 +41,7 @@
 #include <linux/init.h>
 #include <linux/isapnp.h>
 #include <linux/mutex.h>
+#include <linux/async.h>
 #include <asm/io.h>
 
 #include "../base.h"
@@ -990,7 +991,7 @@
 	.disable = isapnp_disable_resources,
 };
 
-static int __init isapnp_init(void)
+static int __init real_isapnp_init(void)
 {
 	int cards;
 	struct pnp_card *card;
@@ -1084,6 +1085,16 @@
 	return 0;
 }
 
+static void __init async_isapnp_init(void *unused, async_cookie_t cookie)
+{
+	(void)real_isapnp_init();
+}
+
+static int __init isapnp_init(void)
+{
+	async_schedule(async_isapnp_init, NULL);
+	return 0;
+}
 device_initcall(isapnp_init);
 
 /* format is: noisapnp */
--- linux-4.4.0.orig/drivers/pnp/quirks.c
+++ linux-4.4.0/drivers/pnp/quirks.c
@@ -342,7 +342,9 @@
 /* Device IDs of parts that have 32KB MCH space */
 static const unsigned int mch_quirk_devices[] = {
 	0x0154,	/* Ivy Bridge */
+	0x0a04, /* Haswell-ULT */
 	0x0c00,	/* Haswell */
+	0x1604, /* Broadwell */
 };
 
 static struct pci_dev *get_intel_host(void)
--- linux-4.4.0.orig/drivers/power/88pm860x_battery.c
+++ linux-4.4.0/drivers/power/88pm860x_battery.c
@@ -436,7 +436,7 @@
 	int ret;
 	int data;
 	int bat_remove;
-	int soc;
+	int soc = 0;
 
 	/* measure enable on GPADC1 */
 	data = MEAS1_GP1;
@@ -499,7 +499,9 @@
 	}
 	mutex_unlock(&info->lock);
 
-	calc_soc(info, OCV_MODE_ACTIVE, &soc);
+	ret = calc_soc(info, OCV_MODE_ACTIVE, &soc);
+	if (ret < 0)
+		goto out;
 
 	data = pm860x_reg_read(info->i2c, PM8607_POWER_UP_LOG);
 	bat_remove = data & BAT_WU_LOG;
--- linux-4.4.0.orig/drivers/power/Kconfig
+++ linux-4.4.0/drivers/power/Kconfig
@@ -159,6 +159,7 @@
 
 config BATTERY_BQ27XXX
 	tristate "BQ27xxx battery driver"
+	depends on I2C || I2C=n
 	help
 	  Say Y here to enable support for batteries with BQ27xxx (I2C/HDQ) chips.
 
--- linux-4.4.0.orig/drivers/power/ab8500_fg.c
+++ linux-4.4.0/drivers/power/ab8500_fg.c
@@ -2447,17 +2447,14 @@
 				 size_t count)
 {
 	unsigned long charge_full;
-	ssize_t ret;
+	int ret;
 
 	ret = kstrtoul(buf, 10, &charge_full);
+	if (ret)
+		return ret;
 
-	dev_dbg(di->dev, "Ret %zd charge_full %lu", ret, charge_full);
-
-	if (!ret) {
-		di->bat_cap.max_mah = (int) charge_full;
-		ret = count;
-	}
-	return ret;
+	di->bat_cap.max_mah = (int) charge_full;
+	return count;
 }
 
 static ssize_t charge_now_show(struct ab8500_fg *di, char *buf)
@@ -2469,20 +2466,16 @@
 				 size_t count)
 {
 	unsigned long charge_now;
-	ssize_t ret;
+	int ret;
 
 	ret = kstrtoul(buf, 10, &charge_now);
+	if (ret)
+		return ret;
 
-	dev_dbg(di->dev, "Ret %zd charge_now %lu was %d",
-		ret, charge_now, di->bat_cap.prev_mah);
-
-	if (!ret) {
-		di->bat_cap.user_mah = (int) charge_now;
-		di->flags.user_cap = true;
-		ret = count;
-		queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
-	}
-	return ret;
+	di->bat_cap.user_mah = (int) charge_now;
+	di->flags.user_cap = true;
+	queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+	return count;
 }
 
 static struct ab8500_fg_sysfs_entry charge_full_attr =
--- linux-4.4.0.orig/drivers/power/avs/smartreflex.c
+++ linux-4.4.0/drivers/power/avs/smartreflex.c
@@ -1001,8 +1001,7 @@
 
 	if (sr_info->autocomp_active)
 		sr_stop_vddautocomp(sr_info);
-	if (sr_info->dbg_dir)
-		debugfs_remove_recursive(sr_info->dbg_dir);
+	debugfs_remove_recursive(sr_info->dbg_dir);
 
 	pm_runtime_disable(&pdev->dev);
 	list_del(&sr_info->node);
--- linux-4.4.0.orig/drivers/power/axp288_charger.c
+++ linux-4.4.0/drivers/power/axp288_charger.c
@@ -883,6 +883,10 @@
 	/* Register charger interrupts */
 	for (i = 0; i < CHRG_INTR_END; i++) {
 		pirq = platform_get_irq(info->pdev, i);
+		if (pirq < 0) {
+			dev_err(&pdev->dev, "Failed to get IRQ: %d\n", pirq);
+			return pirq;
+		}
 		info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
 		if (info->irq[i] < 0) {
 			dev_warn(&info->pdev->dev,
--- linux-4.4.0.orig/drivers/power/bq24190_charger.c
+++ linux-4.4.0/drivers/power/bq24190_charger.c
@@ -144,10 +144,7 @@
  * so the first read after a fault returns the latched value and subsequent
  * reads return the current value.  In order to return the fault status
  * to the user, have the interrupt handler save the reg's value and retrieve
- * it in the appropriate health/status routine.  Each routine has its own
- * flag indicating whether it should use the value stored by the last run
- * of the interrupt handler or do an actual reg read.  That way each routine
- * can report back whatever fault may have occured.
+ * it in the appropriate health/status routine.
  */
 struct bq24190_dev_info {
 	struct i2c_client		*client;
@@ -159,10 +156,6 @@
 	unsigned int			gpio_int;
 	unsigned int			irq;
 	struct mutex			f_reg_lock;
-	bool				first_time;
-	bool				charger_health_valid;
-	bool				battery_health_valid;
-	bool				battery_status_valid;
 	u8				f_reg;
 	u8				ss_reg;
 	u8				watchdog;
@@ -636,21 +629,11 @@
 		union power_supply_propval *val)
 {
 	u8 v;
-	int health, ret;
+	int health;
 
 	mutex_lock(&bdi->f_reg_lock);
-
-	if (bdi->charger_health_valid) {
-		v = bdi->f_reg;
-		bdi->charger_health_valid = false;
-		mutex_unlock(&bdi->f_reg_lock);
-	} else {
-		mutex_unlock(&bdi->f_reg_lock);
-
-		ret = bq24190_read(bdi, BQ24190_REG_F, &v);
-		if (ret < 0)
-			return ret;
-	}
+	v = bdi->f_reg;
+	mutex_unlock(&bdi->f_reg_lock);
 
 	if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
 		/*
@@ -937,18 +920,8 @@
 	int status, ret;
 
 	mutex_lock(&bdi->f_reg_lock);
-
-	if (bdi->battery_status_valid) {
-		chrg_fault = bdi->f_reg;
-		bdi->battery_status_valid = false;
-		mutex_unlock(&bdi->f_reg_lock);
-	} else {
-		mutex_unlock(&bdi->f_reg_lock);
-
-		ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault);
-		if (ret < 0)
-			return ret;
-	}
+	chrg_fault = bdi->f_reg;
+	mutex_unlock(&bdi->f_reg_lock);
 
 	chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
 	chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
@@ -996,21 +969,11 @@
 		union power_supply_propval *val)
 {
 	u8 v;
-	int health, ret;
+	int health;
 
 	mutex_lock(&bdi->f_reg_lock);
-
-	if (bdi->battery_health_valid) {
-		v = bdi->f_reg;
-		bdi->battery_health_valid = false;
-		mutex_unlock(&bdi->f_reg_lock);
-	} else {
-		mutex_unlock(&bdi->f_reg_lock);
-
-		ret = bq24190_read(bdi, BQ24190_REG_F, &v);
-		if (ret < 0)
-			return ret;
-	}
+	v = bdi->f_reg;
+	mutex_unlock(&bdi->f_reg_lock);
 
 	if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
 		health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
@@ -1197,9 +1160,12 @@
 static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
 {
 	struct bq24190_dev_info *bdi = data;
-	bool alert_userspace = false;
+	const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK;
+	const u8 battery_mask_f = BQ24190_REG_F_BAT_FAULT_MASK
+				| BQ24190_REG_F_NTC_FAULT_MASK;
+	bool alert_charger = false, alert_battery = false;
 	u8 ss_reg = 0, f_reg = 0;
-	int ret;
+	int i, ret;
 
 	pm_runtime_get_sync(bdi->dev);
 
@@ -1209,6 +1175,32 @@
 		goto out;
 	}
 
+	i = 0;
+	do {
+		ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
+		if (ret < 0) {
+			dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
+			goto out;
+		}
+	} while (f_reg && ++i < 2);
+
+	if (f_reg != bdi->f_reg) {
+		dev_info(bdi->dev,
+			"Fault: boost %d, charge %d, battery %d, ntc %d\n",
+			!!(f_reg & BQ24190_REG_F_BOOST_FAULT_MASK),
+			!!(f_reg & BQ24190_REG_F_CHRG_FAULT_MASK),
+			!!(f_reg & BQ24190_REG_F_BAT_FAULT_MASK),
+			!!(f_reg & BQ24190_REG_F_NTC_FAULT_MASK));
+
+		mutex_lock(&bdi->f_reg_lock);
+		if ((bdi->f_reg & battery_mask_f) != (f_reg & battery_mask_f))
+			alert_battery = true;
+		if ((bdi->f_reg & ~battery_mask_f) != (f_reg & ~battery_mask_f))
+			alert_charger = true;
+		bdi->f_reg = f_reg;
+		mutex_unlock(&bdi->f_reg_lock);
+	}
+
 	if (ss_reg != bdi->ss_reg) {
 		/*
 		 * The device is in host mode so when PG_STAT goes from 1->0
@@ -1225,47 +1217,17 @@
 					ret);
 		}
 
+		if ((bdi->ss_reg & battery_mask_ss) != (ss_reg & battery_mask_ss))
+			alert_battery = true;
+		if ((bdi->ss_reg & ~battery_mask_ss) != (ss_reg & ~battery_mask_ss))
+			alert_charger = true;
 		bdi->ss_reg = ss_reg;
-		alert_userspace = true;
-	}
-
-	mutex_lock(&bdi->f_reg_lock);
-
-	ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
-	if (ret < 0) {
-		mutex_unlock(&bdi->f_reg_lock);
-		dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
-		goto out;
 	}
 
-	if (f_reg != bdi->f_reg) {
-		bdi->f_reg = f_reg;
-		bdi->charger_health_valid = true;
-		bdi->battery_health_valid = true;
-		bdi->battery_status_valid = true;
-
-		alert_userspace = true;
-	}
-
-	mutex_unlock(&bdi->f_reg_lock);
-
-	/*
-	 * Sometimes bq24190 gives a steady trickle of interrupts even
-	 * though the watchdog timer is turned off and neither the STATUS
-	 * nor FAULT registers have changed.  Weed out these sprurious
-	 * interrupts so userspace isn't alerted for no reason.
-	 * In addition, the chip always generates an interrupt after
-	 * register reset so we should ignore that one (the very first
-	 * interrupt received).
-	 */
-	if (alert_userspace) {
-		if (!bdi->first_time) {
-			power_supply_changed(bdi->charger);
-			power_supply_changed(bdi->battery);
-		} else {
-			bdi->first_time = false;
-		}
-	}
+	if (alert_charger)
+		power_supply_changed(bdi->charger);
+	if (alert_battery)
+		power_supply_changed(bdi->battery);
 
 out:
 	pm_runtime_put_sync(bdi->dev);
@@ -1300,6 +1262,10 @@
 		goto out;
 
 	ret = bq24190_set_mode_host(bdi);
+	if (ret < 0)
+		goto out;
+
+	ret = bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
 out:
 	pm_runtime_put_sync(bdi->dev);
 	return ret;
@@ -1375,10 +1341,8 @@
 	bdi->model = id->driver_data;
 	strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
 	mutex_init(&bdi->f_reg_lock);
-	bdi->first_time = true;
-	bdi->charger_health_valid = false;
-	bdi->battery_health_valid = false;
-	bdi->battery_status_valid = false;
+	bdi->f_reg = 0;
+	bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
 
 	i2c_set_clientdata(client, bdi);
 
@@ -1392,22 +1356,13 @@
 		return -EINVAL;
 	}
 
-	ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
-			bq24190_irq_handler_thread,
-			IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-			"bq24190-charger", bdi);
-	if (ret < 0) {
-		dev_err(dev, "Can't set up irq handler\n");
-		goto out1;
-	}
-
 	pm_runtime_enable(dev);
 	pm_runtime_resume(dev);
 
 	ret = bq24190_hw_init(bdi);
 	if (ret < 0) {
 		dev_err(dev, "Hardware init failed\n");
-		goto out2;
+		goto out1;
 	}
 
 	charger_cfg.drv_data = bdi;
@@ -1418,7 +1373,7 @@
 	if (IS_ERR(bdi->charger)) {
 		dev_err(dev, "Can't register charger\n");
 		ret = PTR_ERR(bdi->charger);
-		goto out2;
+		goto out1;
 	}
 
 	battery_cfg.drv_data = bdi;
@@ -1427,24 +1382,34 @@
 	if (IS_ERR(bdi->battery)) {
 		dev_err(dev, "Can't register battery\n");
 		ret = PTR_ERR(bdi->battery);
-		goto out3;
+		goto out2;
 	}
 
 	ret = bq24190_sysfs_create_group(bdi);
 	if (ret) {
 		dev_err(dev, "Can't create sysfs entries\n");
+		goto out3;
+	}
+
+	ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
+			bq24190_irq_handler_thread,
+			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+			"bq24190-charger", bdi);
+	if (ret < 0) {
+		dev_err(dev, "Can't set up irq handler\n");
 		goto out4;
 	}
 
 	return 0;
 
 out4:
-	power_supply_unregister(bdi->battery);
+	bq24190_sysfs_remove_group(bdi);
 out3:
-	power_supply_unregister(bdi->charger);
+	power_supply_unregister(bdi->battery);
 out2:
-	pm_runtime_disable(dev);
+	power_supply_unregister(bdi->charger);
 out1:
+	pm_runtime_disable(dev);
 	if (bdi->gpio_int)
 		gpio_free(bdi->gpio_int);
 
@@ -1488,12 +1453,13 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
 
-	bdi->charger_health_valid = false;
-	bdi->battery_health_valid = false;
-	bdi->battery_status_valid = false;
+	bdi->f_reg = 0;
+	bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
 
 	pm_runtime_get_sync(bdi->dev);
 	bq24190_register_reset(bdi);
+	bq24190_set_mode_host(bdi);
+	bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
 	pm_runtime_put_sync(bdi->dev);
 
 	/* Things may have changed while suspended so alert upper layer */
--- linux-4.4.0.orig/drivers/power/bq24257_charger.c
+++ linux-4.4.0/drivers/power/bq24257_charger.c
@@ -1068,6 +1068,12 @@
 		return ret;
 	}
 
+	ret = bq24257_power_supply_init(bq);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register power supply\n");
+		return ret;
+	}
+
 	ret = devm_request_threaded_irq(dev, client->irq, NULL,
 					bq24257_irq_handler_thread,
 					IRQF_TRIGGER_FALLING |
@@ -1078,12 +1084,6 @@
 		return ret;
 	}
 
-	ret = bq24257_power_supply_init(bq);
-	if (ret < 0) {
-		dev_err(dev, "Failed to register power supply\n");
-		return ret;
-	}
-
 	ret = sysfs_create_group(&bq->charger->dev.kobj, &bq24257_attr_group);
 	if (ret < 0) {
 		dev_err(dev, "Can't create sysfs entries\n");
--- linux-4.4.0.orig/drivers/power/bq27xxx_battery.c
+++ linux-4.4.0/drivers/power/bq27xxx_battery.c
@@ -198,10 +198,10 @@
 	INVALID_REG_ADDR,	/* TTECP - NA	*/
 	0x0c,	/* NAC		*/
 	0x12,	/* LMD(FCC)	*/
-	0x1e,	/* CYCT		*/
+	0x2a,	/* CYCT		*/
 	INVALID_REG_ADDR,	/* AE - NA	*/
-	0x20,	/* SOC(RSOC)	*/
-	0x2e,	/* DCAP(ILMD)	*/
+	0x2c,	/* SOC(RSOC)	*/
+	0x3c,	/* DCAP(ILMD)	*/
 	INVALID_REG_ADDR,	/* AP - NA	*/
 };
 
@@ -242,7 +242,7 @@
 	INVALID_REG_ADDR,	/* AE - NA	*/
 	0x2c,	/* SOC(RSOC)	*/
 	0x3c,	/* DCAP		*/
-	0x76,	/* AP		*/
+	0x24,	/* AP		*/
 };
 
 static u8 bq27545_regs[] = {
@@ -285,7 +285,7 @@
 	0x18,	/* AP		*/
 };
 
-static u8 *bq27xxx_regs[] = {
+static u8 *bq27xxx_regs[] __maybe_unused = {
 	[BQ27000] = bq27000_regs,
 	[BQ27010] = bq27010_regs,
 	[BQ27500] = bq27500_regs,
@@ -471,7 +471,10 @@
 {
 	int soc;
 
-	soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false);
+	if (di->chip == BQ27000 || di->chip == BQ27010)
+		soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true);
+	else
+		soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false);
 
 	if (soc < 0)
 		dev_dbg(di->dev, "error reading State-of-Charge\n");
@@ -536,7 +539,10 @@
 {
 	int dcap;
 
-	dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false);
+	if (di->chip == BQ27000 || di->chip == BQ27010)
+		dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true);
+	else
+		dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false);
 
 	if (dcap < 0) {
 		dev_dbg(di->dev, "error reading initial last measured discharge\n");
@@ -544,7 +550,7 @@
 	}
 
 	if (di->chip == BQ27000 || di->chip == BQ27010)
-		dcap *= BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
+		dcap = (dcap << 8) * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
 	else
 		dcap *= 1000;
 
@@ -991,7 +997,7 @@
 	schedule_delayed_work(&di->work, 0);
 }
 
-static int bq27xxx_powersupply_init(struct bq27xxx_device_info *di,
+static int __maybe_unused bq27xxx_powersupply_init(struct bq27xxx_device_info *di,
 				    const char *name)
 {
 	int ret;
@@ -1026,7 +1032,7 @@
 	return 0;
 }
 
-static void bq27xxx_powersupply_unregister(struct bq27xxx_device_info *di)
+static void __maybe_unused bq27xxx_powersupply_unregister(struct bq27xxx_device_info *di)
 {
 	/*
 	 * power_supply_unregister call bq27xxx_battery_get_property which
--- linux-4.4.0.orig/drivers/power/ipaq_micro_battery.c
+++ linux-4.4.0/drivers/power/ipaq_micro_battery.c
@@ -261,7 +261,7 @@
 	return 0;
 
 ac_err:
-	power_supply_unregister(micro_ac_power);
+	power_supply_unregister(micro_batt_power);
 batt_err:
 	cancel_delayed_work_sync(&mb->update);
 	destroy_workqueue(mb->wq);
--- linux-4.4.0.orig/drivers/power/ltc2941-battery-gauge.c
+++ linux-4.4.0/drivers/power/ltc2941-battery-gauge.c
@@ -364,7 +364,7 @@
 {
 	struct ltc294x_info *info = i2c_get_clientdata(client);
 
-	cancel_delayed_work(&info->work);
+	cancel_delayed_work_sync(&info->work);
 	power_supply_unregister(info->supply);
 	return 0;
 }
--- linux-4.4.0.orig/drivers/power/max17042_battery.c
+++ linux-4.4.0/drivers/power/max17042_battery.c
@@ -457,13 +457,16 @@
 }
 
 static inline void max17042_read_model_data(struct max17042_chip *chip,
-					u8 addr, u32 *data, int size)
+					u8 addr, u16 *data, int size)
 {
 	struct regmap *map = chip->regmap;
 	int i;
+	u32 tmp;
 
-	for (i = 0; i < size; i++)
-		regmap_read(map, addr + i, &data[i]);
+	for (i = 0; i < size; i++) {
+		regmap_read(map, addr + i, &tmp);
+		data[i] = (u16)tmp;
+	}
 }
 
 static inline int max17042_model_data_compare(struct max17042_chip *chip,
@@ -486,7 +489,7 @@
 {
 	int ret;
 	int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
-	u32 *temp_data;
+	u16 *temp_data;
 
 	temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
 	if (!temp_data)
@@ -501,7 +504,7 @@
 	ret = max17042_model_data_compare(
 		chip,
 		chip->pdata->config_data->cell_char_tbl,
-		(u16 *)temp_data,
+		temp_data,
 		table_size);
 
 	max10742_lock_model(chip);
@@ -514,7 +517,7 @@
 {
 	int i;
 	int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
-	u32 *temp_data;
+	u16 *temp_data;
 	int ret = 0;
 
 	temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
--- linux-4.4.0.orig/drivers/power/max8998_charger.c
+++ linux-4.4.0/drivers/power/max8998_charger.c
@@ -85,7 +85,7 @@
 static int max8998_battery_probe(struct platform_device *pdev)
 {
 	struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct max8998_platform_data *pdata = iodev->pdata;
 	struct power_supply_config psy_cfg = {};
 	struct max8998_battery_data *max8998;
 	struct i2c_client *i2c;
--- linux-4.4.0.orig/drivers/power/olpc_battery.c
+++ linux-4.4.0/drivers/power/olpc_battery.c
@@ -427,14 +427,14 @@
 		if (ret)
 			return ret;
 
-		val->intval = (s16)be16_to_cpu(ec_word) * 100 / 256;
+		val->intval = (s16)be16_to_cpu(ec_word) * 10 / 256;
 		break;
 	case POWER_SUPPLY_PROP_TEMP_AMBIENT:
 		ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
 		if (ret)
 			return ret;
 
-		val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
+		val->intval = (int)be16_to_cpu(ec_word) * 10 / 256;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
 		ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
--- linux-4.4.0.orig/drivers/power/pda_power.c
+++ linux-4.4.0/drivers/power/pda_power.c
@@ -30,9 +30,9 @@
 static struct device *dev;
 static struct pda_power_pdata *pdata;
 static struct resource *ac_irq, *usb_irq;
-static struct timer_list charger_timer;
-static struct timer_list supply_timer;
-static struct timer_list polling_timer;
+static struct delayed_work charger_work;
+static struct delayed_work polling_work;
+static struct delayed_work supply_work;
 static int polling;
 static struct power_supply *pda_psy_ac, *pda_psy_usb;
 
@@ -140,7 +140,7 @@
 	}
 }
 
-static void supply_timer_func(unsigned long unused)
+static void supply_work_func(struct work_struct *work)
 {
 	if (ac_status == PDA_PSY_TO_CHANGE) {
 		ac_status = new_ac_status;
@@ -161,11 +161,12 @@
 	 * Okay, charger set. Now wait a bit before notifying supplicants,
 	 * charge power should stabilize.
 	 */
-	mod_timer(&supply_timer,
-		  jiffies + msecs_to_jiffies(pdata->wait_for_charger));
+	cancel_delayed_work(&supply_work);
+	schedule_delayed_work(&supply_work,
+			      msecs_to_jiffies(pdata->wait_for_charger));
 }
 
-static void charger_timer_func(unsigned long unused)
+static void charger_work_func(struct work_struct *work)
 {
 	update_status();
 	psy_changed();
@@ -184,13 +185,14 @@
 	 * Wait a bit before reading ac/usb line status and setting charger,
 	 * because ac/usb status readings may lag from irq.
 	 */
-	mod_timer(&charger_timer,
-		  jiffies + msecs_to_jiffies(pdata->wait_for_status));
+	cancel_delayed_work(&charger_work);
+	schedule_delayed_work(&charger_work,
+			      msecs_to_jiffies(pdata->wait_for_status));
 
 	return IRQ_HANDLED;
 }
 
-static void polling_timer_func(unsigned long unused)
+static void polling_work_func(struct work_struct *work)
 {
 	int changed = 0;
 
@@ -211,8 +213,9 @@
 	if (changed)
 		psy_changed();
 
-	mod_timer(&polling_timer,
-		  jiffies + msecs_to_jiffies(pdata->polling_interval));
+	cancel_delayed_work(&polling_work);
+	schedule_delayed_work(&polling_work,
+			      msecs_to_jiffies(pdata->polling_interval));
 }
 
 #if IS_ENABLED(CONFIG_USB_PHY)
@@ -250,8 +253,9 @@
 	 * Wait a bit before reading ac/usb line status and setting charger,
 	 * because ac/usb status readings may lag from irq.
 	 */
-	mod_timer(&charger_timer,
-		  jiffies + msecs_to_jiffies(pdata->wait_for_status));
+	cancel_delayed_work(&charger_work);
+	schedule_delayed_work(&charger_work,
+			      msecs_to_jiffies(pdata->wait_for_status));
 
 	return NOTIFY_OK;
 }
@@ -300,8 +304,8 @@
 	if (!pdata->ac_max_uA)
 		pdata->ac_max_uA = 500000;
 
-	setup_timer(&charger_timer, charger_timer_func, 0);
-	setup_timer(&supply_timer, supply_timer_func, 0);
+	INIT_DELAYED_WORK(&charger_work, charger_work_func);
+	INIT_DELAYED_WORK(&supply_work, supply_work_func);
 
 	ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
 	usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
@@ -385,9 +389,10 @@
 
 	if (polling) {
 		dev_dbg(dev, "will poll for status\n");
-		setup_timer(&polling_timer, polling_timer_func, 0);
-		mod_timer(&polling_timer,
-			  jiffies + msecs_to_jiffies(pdata->polling_interval));
+		INIT_DELAYED_WORK(&polling_work, polling_work_func);
+		cancel_delayed_work(&polling_work);
+		schedule_delayed_work(&polling_work,
+				      msecs_to_jiffies(pdata->polling_interval));
 	}
 
 	if (ac_irq || usb_irq)
@@ -433,9 +438,9 @@
 		free_irq(ac_irq->start, pda_psy_ac);
 
 	if (polling)
-		del_timer_sync(&polling_timer);
-	del_timer_sync(&charger_timer);
-	del_timer_sync(&supply_timer);
+		cancel_delayed_work_sync(&polling_work);
+	cancel_delayed_work_sync(&charger_work);
+	cancel_delayed_work_sync(&supply_work);
 
 	if (pdata->is_usb_online)
 		power_supply_unregister(pda_psy_usb);
--- linux-4.4.0.orig/drivers/power/power_supply_core.c
+++ linux-4.4.0/drivers/power/power_supply_core.c
@@ -565,11 +565,12 @@
 
 	WARN_ON(tzd == NULL);
 	psy = tzd->devdata;
-	ret = psy->desc->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
+	ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
+	if (ret)
+		return ret;
 
 	/* Convert tenths of degree Celsius to milli degree Celsius. */
-	if (!ret)
-		*temp = val.intval * 100;
+	*temp = val.intval * 100;
 
 	return ret;
 }
@@ -612,10 +613,12 @@
 	int ret;
 
 	psy = tcd->devdata;
-	ret = psy->desc->get_property(psy,
-		POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
-	if (!ret)
-		*state = val.intval;
+	ret = power_supply_get_property(psy,
+			POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
+	if (ret)
+		return ret;
+
+	*state = val.intval;
 
 	return ret;
 }
@@ -628,10 +631,12 @@
 	int ret;
 
 	psy = tcd->devdata;
-	ret = psy->desc->get_property(psy,
-		POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
-	if (!ret)
-		*state = val.intval;
+	ret = power_supply_get_property(psy,
+			POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
+	if (ret)
+		return ret;
+
+	*state = val.intval;
 
 	return ret;
 }
@@ -750,14 +755,14 @@
 	}
 
 	spin_lock_init(&psy->changed_lock);
-	rc = device_init_wakeup(dev, ws);
-	if (rc)
-		goto wakeup_init_failed;
-
 	rc = device_add(dev);
 	if (rc)
 		goto device_add_failed;
 
+	rc = device_init_wakeup(dev, ws);
+	if (rc)
+		goto wakeup_init_failed;
+
 	rc = psy_register_thermal(psy);
 	if (rc)
 		goto register_thermal_failed;
@@ -793,8 +798,8 @@
 	psy_unregister_thermal(psy);
 register_thermal_failed:
 	device_del(dev);
-device_add_failed:
 wakeup_init_failed:
+device_add_failed:
 check_supplies_failed:
 dev_set_name_failed:
 	put_device(dev);
--- linux-4.4.0.orig/drivers/power/power_supply_sysfs.c
+++ linux-4.4.0/drivers/power/power_supply_sysfs.c
@@ -277,15 +277,11 @@
 	char *prop_buf;
 	char *attrname;
 
-	dev_dbg(dev, "uevent\n");
-
 	if (!psy || !psy->desc) {
 		dev_dbg(dev, "No power supply yet\n");
 		return ret;
 	}
 
-	dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->desc->name);
-
 	ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name);
 	if (ret)
 		return ret;
@@ -321,8 +317,6 @@
 			goto out;
 		}
 
-		dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
-
 		ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
 		kfree(attrname);
 		if (ret)
--- linux-4.4.0.orig/drivers/power/reset/at91-poweroff.c
+++ linux-4.4.0/drivers/power/reset/at91-poweroff.c
@@ -14,9 +14,12 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/printk.h>
 
+#include <soc/at91/at91sam9_ddrsdr.h>
+
 #define AT91_SHDW_CR	0x00		/* Shut Down Control Register */
 #define AT91_SHDW_SHDW		BIT(0)			/* Shut Down command */
 #define AT91_SHDW_KEY		(0xa5 << 24)		/* KEY Password */
@@ -50,6 +53,7 @@
 
 static void __iomem *at91_shdwc_base;
 static struct clk *sclk;
+static void __iomem *mpddrc_base;
 
 static void __init at91_wakeup_status(void)
 {
@@ -73,6 +77,29 @@
 	writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
 }
 
+static void at91_lpddr_poweroff(void)
+{
+	asm volatile(
+		/* Align to cache lines */
+		".balign 32\n\t"
+
+		/* Ensure AT91_SHDW_CR is in the TLB by reading it */
+		"	ldr	r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
+
+		/* Power down SDRAM0 */
+		"	str	%1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
+		/* Shutdown CPU */
+		"	str	%3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
+
+		"	b	.\n\t"
+		:
+		: "r" (mpddrc_base),
+		  "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
+		  "r" (at91_shdwc_base),
+		  "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
+		: "r0");
+}
+
 static int at91_poweroff_get_wakeup_mode(struct device_node *np)
 {
 	const char *pm;
@@ -124,6 +151,8 @@
 static int __init at91_poweroff_probe(struct platform_device *pdev)
 {
 	struct resource *res;
+	struct device_node *np;
+	u32 ddr_type;
 	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -150,12 +179,30 @@
 
 	pm_power_off = at91_poweroff;
 
+	np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
+	if (!np)
+		return 0;
+
+	mpddrc_base = of_iomap(np, 0);
+	of_node_put(np);
+
+	if (!mpddrc_base)
+		return 0;
+
+	ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
+	if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
+	    (ddr_type == AT91_DDRSDRC_MD_LPDDR3))
+		pm_power_off = at91_lpddr_poweroff;
+	else
+		iounmap(mpddrc_base);
+
 	return 0;
 }
 
 static int __exit at91_poweroff_remove(struct platform_device *pdev)
 {
-	if (pm_power_off == at91_poweroff)
+	if (pm_power_off == at91_poweroff ||
+	    pm_power_off == at91_lpddr_poweroff)
 		pm_power_off = NULL;
 
 	clk_disable_unprepare(sclk);
@@ -163,6 +210,11 @@
 	return 0;
 }
 
+static const struct of_device_id at91_ramc_of_match[] = {
+	{ .compatible = "atmel,sama5d3-ddramc", },
+	{ /* sentinel */ }
+};
+
 static const struct of_device_id at91_poweroff_of_match[] = {
 	{ .compatible = "atmel,at91sam9260-shdwc", },
 	{ .compatible = "atmel,at91sam9rl-shdwc", },
--- linux-4.4.0.orig/drivers/power/reset/hisi-reboot.c
+++ linux-4.4.0/drivers/power/reset/hisi-reboot.c
@@ -53,13 +53,16 @@
 
 	if (of_property_read_u32(np, "reboot-offset", &reboot_offset) < 0) {
 		pr_err("failed to find reboot-offset property\n");
+		iounmap(base);
 		return -EINVAL;
 	}
 
 	err = register_restart_handler(&hisi_restart_nb);
-	if (err)
+	if (err) {
 		dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n",
 			err);
+		iounmap(base);
+	}
 
 	return err;
 }
--- linux-4.4.0.orig/drivers/power/reset/vexpress-poweroff.c
+++ linux-4.4.0/drivers/power/reset/vexpress-poweroff.c
@@ -35,6 +35,7 @@
 }
 
 static struct device *vexpress_power_off_device;
+static atomic_t vexpress_restart_nb_refcnt = ATOMIC_INIT(0);
 
 static void vexpress_power_off(void)
 {
@@ -99,10 +100,13 @@
 	int err;
 
 	vexpress_restart_device = dev;
-	err = register_restart_handler(&vexpress_restart_nb);
-	if (err) {
-		dev_err(dev, "cannot register restart handler (err=%d)\n", err);
-		return err;
+	if (atomic_inc_return(&vexpress_restart_nb_refcnt) == 1) {
+		err = register_restart_handler(&vexpress_restart_nb);
+		if (err) {
+			dev_err(dev, "cannot register restart handler (err=%d)\n", err);
+			atomic_dec(&vexpress_restart_nb_refcnt);
+			return err;
+		}
 	}
 	device_create_file(dev, &dev_attr_active);
 
@@ -146,6 +150,7 @@
 	.driver = {
 		.name = "vexpress-reset",
 		.of_match_table = vexpress_reset_of_match,
+		.suppress_bind_attrs = true,
 	},
 };
 
--- linux-4.4.0.orig/drivers/power/reset/zx-reboot.c
+++ linux-4.4.0/drivers/power/reset/zx-reboot.c
@@ -78,3 +78,7 @@
 	},
 };
 module_platform_driver(zx_reboot_driver);
+
+MODULE_DESCRIPTION("ZTE SoCs reset driver");
+MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
+MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/power/smb347-charger.c
+++ linux-4.4.0/drivers/power/smb347-charger.c
@@ -1141,6 +1141,7 @@
 	switch (reg) {
 	case IRQSTAT_A:
 	case IRQSTAT_C:
+	case IRQSTAT_D:
 	case IRQSTAT_E:
 	case IRQSTAT_F:
 	case STAT_A:
--- linux-4.4.0.orig/drivers/power/test_power.c
+++ linux-4.4.0/drivers/power/test_power.c
@@ -301,6 +301,8 @@
 	buf[MAX_KEYLENGTH-1] = '\0';
 
 	cr = strnlen(buf, MAX_KEYLENGTH) - 1;
+	if (cr < 0)
+		return def_val;
 	if (buf[cr] == '\n')
 		buf[cr] = '\0';
 
@@ -342,6 +344,7 @@
 static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
 {
 	strcpy(buffer, map_get_key(map_ac_online, ac_online, "unknown"));
+	strcat(buffer, "\n");
 	return strlen(buffer);
 }
 
@@ -355,6 +358,7 @@
 static int param_get_usb_online(char *buffer, const struct kernel_param *kp)
 {
 	strcpy(buffer, map_get_key(map_ac_online, usb_online, "unknown"));
+	strcat(buffer, "\n");
 	return strlen(buffer);
 }
 
@@ -369,6 +373,7 @@
 static int param_get_battery_status(char *buffer, const struct kernel_param *kp)
 {
 	strcpy(buffer, map_get_key(map_status, battery_status, "unknown"));
+	strcat(buffer, "\n");
 	return strlen(buffer);
 }
 
@@ -383,6 +388,7 @@
 static int param_get_battery_health(char *buffer, const struct kernel_param *kp)
 {
 	strcpy(buffer, map_get_key(map_health, battery_health, "unknown"));
+	strcat(buffer, "\n");
 	return strlen(buffer);
 }
 
@@ -398,6 +404,7 @@
 					const struct kernel_param *kp)
 {
 	strcpy(buffer, map_get_key(map_present, battery_present, "unknown"));
+	strcat(buffer, "\n");
 	return strlen(buffer);
 }
 
@@ -415,6 +422,7 @@
 {
 	strcpy(buffer,
 		map_get_key(map_technology, battery_technology, "unknown"));
+	strcat(buffer, "\n");
 	return strlen(buffer);
 }
 
--- linux-4.4.0.orig/drivers/power/tps65217_charger.c
+++ linux-4.4.0/drivers/power/tps65217_charger.c
@@ -197,6 +197,7 @@
 {
 	struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
 	struct tps65217_charger *charger;
+	struct power_supply_config cfg = {};
 	int ret;
 
 	dev_dbg(&pdev->dev, "%s\n", __func__);
@@ -205,12 +206,16 @@
 	if (!charger)
 		return -ENOMEM;
 
+	platform_set_drvdata(pdev, charger);
 	charger->tps = tps;
 	charger->dev = &pdev->dev;
 
+	cfg.of_node = pdev->dev.of_node;
+	cfg.drv_data = charger;
+
 	charger->ac = devm_power_supply_register(&pdev->dev,
 						 &tps65217_charger_desc,
-						 NULL);
+						 &cfg);
 	if (IS_ERR(charger->ac)) {
 		dev_err(&pdev->dev, "failed: power supply register\n");
 		return PTR_ERR(charger->ac);
--- linux-4.4.0.orig/drivers/power/twl4030_charger.c
+++ linux-4.4.0/drivers/power/twl4030_charger.c
@@ -449,7 +449,8 @@
 
 	if (v < USB_MIN_VOLT) {
 		/* Back up and stop adjusting. */
-		bci->usb_cur -= USB_CUR_STEP;
+		if (bci->usb_cur >= USB_CUR_STEP)
+			bci->usb_cur -= USB_CUR_STEP;
 		bci->usb_cur_target = bci->usb_cur;
 	} else if (bci->usb_cur >= bci->usb_cur_target ||
 		   bci->usb_cur + USB_CUR_STEP > USB_MAX_CURRENT) {
@@ -468,6 +469,7 @@
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
 {
 	int ret;
+	u32 reg;
 
 	if (bci->usb_mode == CHARGE_OFF)
 		enable = false;
@@ -481,14 +483,38 @@
 			bci->usb_enabled = 1;
 		}
 
-		if (bci->usb_mode == CHARGE_AUTO)
+		if (bci->usb_mode == CHARGE_AUTO) {
+			/* Enable interrupts now. */
+			reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC |
+					TWL4030_TBATOR2 | TWL4030_TBATOR1 |
+					TWL4030_BATSTS);
+			ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
+				       TWL4030_INTERRUPTS_BCIIMR1A);
+			if (ret < 0) {
+				dev_err(bci->dev,
+					"failed to unmask interrupts: %d\n",
+					ret);
+				return ret;
+			}
 			/* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
 			ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
+		}
 
 		/* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
 		ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0,
 			TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
 		if (bci->usb_mode == CHARGE_LINEAR) {
+			/* Enable interrupts now. */
+			reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_TBATOR2 |
+					TWL4030_TBATOR1 | TWL4030_BATSTS);
+			ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
+				       TWL4030_INTERRUPTS_BCIIMR1A);
+			if (ret < 0) {
+				dev_err(bci->dev,
+					"failed to unmask interrupts: %d\n",
+					ret);
+				return ret;
+			}
 			twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0);
 			/* Watch dog key: WOVF acknowledge */
 			ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
--- linux-4.4.0.orig/drivers/power/wm8350_power.c
+++ linux-4.4.0/drivers/power/wm8350_power.c
@@ -458,6 +458,7 @@
 	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350);
 	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350);
 	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350);
 	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350);
 	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350);
 	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350);
--- linux-4.4.0.orig/drivers/powercap/intel_rapl.c
+++ linux-4.4.0/drivers/powercap/intel_rapl.c
@@ -1105,6 +1105,8 @@
 	RAPL_CPU(0X5C, rapl_defaults_core),/* Broxton */
 	RAPL_CPU(0x5E, rapl_defaults_core),/* Skylake-H/S */
 	RAPL_CPU(0x57, rapl_defaults_hsw_server),/* Knights Landing */
+	RAPL_CPU(0x8E, rapl_defaults_core),/* Kabylake */
+	RAPL_CPU(0x9E, rapl_defaults_core),/* Kabylake */
 	{}
 };
 MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
--- linux-4.4.0.orig/drivers/powercap/powercap_sys.c
+++ linux-4.4.0/drivers/powercap/powercap_sys.c
@@ -236,46 +236,46 @@
 
 	for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
 		ret = create_constraint_attribute(i, "power_limit_uw",
-					S_IWUSR | S_IRUGO,
+					S_IWUSR | S_IRUSR,
 					&constraint_attrs[i].power_limit_attr,
 					show_constraint_power_limit_uw,
 					store_constraint_power_limit_uw);
 		if (ret)
 			goto err_alloc;
 		ret = create_constraint_attribute(i, "time_window_us",
-					S_IWUSR | S_IRUGO,
+					S_IWUSR | S_IRUSR,
 					&constraint_attrs[i].time_window_attr,
 					show_constraint_time_window_us,
 					store_constraint_time_window_us);
 		if (ret)
 			goto err_alloc;
-		ret = create_constraint_attribute(i, "name", S_IRUGO,
+		ret = create_constraint_attribute(i, "name", S_IRUSR,
 				&constraint_attrs[i].name_attr,
 				show_constraint_name,
 				NULL);
 		if (ret)
 			goto err_alloc;
-		ret = create_constraint_attribute(i, "max_power_uw", S_IRUGO,
+		ret = create_constraint_attribute(i, "max_power_uw", S_IRUSR,
 				&constraint_attrs[i].max_power_attr,
 				show_constraint_max_power_uw,
 				NULL);
 		if (ret)
 			goto err_alloc;
-		ret = create_constraint_attribute(i, "min_power_uw", S_IRUGO,
+		ret = create_constraint_attribute(i, "min_power_uw", S_IRUSR,
 				&constraint_attrs[i].min_power_attr,
 				show_constraint_min_power_uw,
 				NULL);
 		if (ret)
 			goto err_alloc;
 		ret = create_constraint_attribute(i, "max_time_window_us",
-				S_IRUGO,
+				S_IRUSR,
 				&constraint_attrs[i].max_time_window_attr,
 				show_constraint_max_time_window_us,
 				NULL);
 		if (ret)
 			goto err_alloc;
 		ret = create_constraint_attribute(i, "min_time_window_us",
-				S_IRUGO,
+				S_IRUSR,
 				&constraint_attrs[i].min_time_window_attr,
 				show_constraint_min_time_window_us,
 				NULL);
@@ -374,23 +374,29 @@
 	int count = 0;
 
 	power_zone->zone_dev_attrs[count++] = &dev_attr_name.attr;
-	if (power_zone->ops->get_max_energy_range_uj)
+	if (power_zone->ops->get_max_energy_range_uj) {
+		dev_attr_max_energy_range_uj.attr.mode = S_IRUSR;
 		power_zone->zone_dev_attrs[count++] =
 					&dev_attr_max_energy_range_uj.attr;
+	}
 	if (power_zone->ops->get_energy_uj) {
 		if (power_zone->ops->reset_energy_uj)
-			dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUGO;
+			dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUSR;
 		else
-			dev_attr_energy_uj.attr.mode = S_IRUGO;
+			dev_attr_energy_uj.attr.mode = S_IRUSR;
 		power_zone->zone_dev_attrs[count++] =
 					&dev_attr_energy_uj.attr;
 	}
-	if (power_zone->ops->get_power_uw)
+	if (power_zone->ops->get_power_uw) {
+		dev_attr_power_uw.attr.mode = S_IRUSR;
 		power_zone->zone_dev_attrs[count++] =
 					&dev_attr_power_uw.attr;
-	if (power_zone->ops->get_max_power_range_uw)
+	}
+	if (power_zone->ops->get_max_power_range_uw) {
+		dev_attr_max_power_range_uw.attr.mode = S_IRUSR;
 		power_zone->zone_dev_attrs[count++] =
 					&dev_attr_max_power_range_uw.attr;
+	}
 	power_zone->zone_dev_attrs[count] = NULL;
 	power_zone->zone_attr_count = count;
 }
@@ -538,6 +544,7 @@
 
 	power_zone->id = result;
 	idr_init(&power_zone->idr);
+	result = -ENOMEM;
 	power_zone->name = kstrdup(name, GFP_KERNEL);
 	if (!power_zone->name)
 		goto err_name_alloc;
--- linux-4.4.0.orig/drivers/pps/clients/pps_parport.c
+++ linux-4.4.0/drivers/pps/clients/pps_parport.c
@@ -195,7 +195,7 @@
 	struct pps_client_pp *device;
 
 	/* FIXME: oooh, this is ugly! */
-	if (strcmp(pardev->name, KBUILD_MODNAME))
+	if (!pardev || strcmp(pardev->name, KBUILD_MODNAME))
 		/* not our port */
 		return;
 
--- linux-4.4.0.orig/drivers/pps/pps.c
+++ linux-4.4.0/drivers/pps/pps.c
@@ -129,6 +129,14 @@
 			pps->params.mode |= PPS_CANWAIT;
 		pps->params.api_version = PPS_API_VERS;
 
+		/*
+		 * Clear unused fields of pps_kparams to avoid leaking
+		 * uninitialized data of the PPS_SETPARAMS caller via
+		 * PPS_GETPARAMS
+		 */
+		pps->params.assert_off_tu.flags = 0;
+		pps->params.clear_off_tu.flags = 0;
+
 		spin_unlock_irq(&pps->lock);
 
 		break;
--- linux-4.4.0.orig/drivers/ps3/ps3stor_lib.c
+++ linux-4.4.0/drivers/ps3/ps3stor_lib.c
@@ -201,7 +201,7 @@
 	dev->bounce_lpar = ps3_mm_phys_to_lpar(__pa(dev->bounce_buf));
 	dev->bounce_dma = dma_map_single(&dev->sbd.core, dev->bounce_buf,
 					 dev->bounce_size, DMA_BIDIRECTIONAL);
-	if (!dev->bounce_dma) {
+	if (dma_mapping_error(&dev->sbd.core, dev->bounce_dma)) {
 		dev_err(&dev->sbd.core, "%s:%u: map DMA region failed\n",
 			__func__, __LINE__);
 		error = -ENODEV;
--- linux-4.4.0.orig/drivers/ptp/ptp_chardev.c
+++ linux-4.4.0/drivers/ptp/ptp_chardev.c
@@ -22,6 +22,9 @@
 #include <linux/poll.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/timekeeping.h>
+
+#include <linux/nospec.h>
 
 #include "ptp_private.h"
 
@@ -88,6 +91,7 @@
 	case PTP_PF_PHYSYNC:
 		if (chan != 0)
 			return -EINVAL;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -120,11 +124,13 @@
 	struct ptp_clock_caps caps;
 	struct ptp_clock_request req;
 	struct ptp_sys_offset *sysoff = NULL;
+	struct ptp_sys_offset_precise precise_offset;
 	struct ptp_pin_desc pd;
 	struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
 	struct ptp_clock_info *ops = ptp->info;
 	struct ptp_clock_time *pct;
 	struct timespec64 ts;
+	struct system_device_crosststamp xtstamp;
 	int enable, err = 0;
 	unsigned int i, pin_index;
 
@@ -138,6 +144,7 @@
 		caps.n_per_out = ptp->info->n_per_out;
 		caps.pps = ptp->info->pps;
 		caps.n_pins = ptp->info->n_pins;
+		caps.cross_timestamping = ptp->info->getcrosststamp != NULL;
 		if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
 			err = -EFAULT;
 		break;
@@ -180,6 +187,29 @@
 		err = ops->enable(ops, &req, enable);
 		break;
 
+	case PTP_SYS_OFFSET_PRECISE:
+		if (!ptp->info->getcrosststamp) {
+			err = -EOPNOTSUPP;
+			break;
+		}
+		err = ptp->info->getcrosststamp(ptp->info, &xtstamp);
+		if (err)
+			break;
+
+		ts = ktime_to_timespec64(xtstamp.device);
+		precise_offset.device.sec = ts.tv_sec;
+		precise_offset.device.nsec = ts.tv_nsec;
+		ts = ktime_to_timespec64(xtstamp.sys_realtime);
+		precise_offset.sys_realtime.sec = ts.tv_sec;
+		precise_offset.sys_realtime.nsec = ts.tv_nsec;
+		ts = ktime_to_timespec64(xtstamp.sys_monoraw);
+		precise_offset.sys_monoraw.sec = ts.tv_sec;
+		precise_offset.sys_monoraw.nsec = ts.tv_nsec;
+		if (copy_to_user((void __user *)arg, &precise_offset,
+				 sizeof(precise_offset)))
+			err = -EFAULT;
+		break;
+
 	case PTP_SYS_OFFSET:
 		sysoff = kmalloc(sizeof(*sysoff), GFP_KERNEL);
 		if (!sysoff) {
@@ -201,7 +231,9 @@
 			pct->sec = ts.tv_sec;
 			pct->nsec = ts.tv_nsec;
 			pct++;
-			ptp->info->gettime64(ptp->info, &ts);
+			err = ptp->info->gettime64(ptp->info, &ts);
+			if (err)
+				goto out;
 			pct->sec = ts.tv_sec;
 			pct->nsec = ts.tv_nsec;
 			pct++;
@@ -223,6 +255,7 @@
 			err = -EINVAL;
 			break;
 		}
+		pin_index = array_index_nospec(pin_index, ops->n_pins);
 		if (mutex_lock_interruptible(&ptp->pincfg_mux))
 			return -ERESTARTSYS;
 		pd = ops->pin_config[pin_index];
@@ -241,6 +274,7 @@
 			err = -EINVAL;
 			break;
 		}
+		pin_index = array_index_nospec(pin_index, ops->n_pins);
 		if (mutex_lock_interruptible(&ptp->pincfg_mux))
 			return -ERESTARTSYS;
 		err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan);
@@ -252,6 +286,7 @@
 		break;
 	}
 
+out:
 	kfree(sysoff);
 	return err;
 }
--- linux-4.4.0.orig/drivers/ptp/ptp_clock.c
+++ linux-4.4.0/drivers/ptp/ptp_clock.c
@@ -97,30 +97,26 @@
 
 /* posix clock implementation */
 
-static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp)
+static int ptp_clock_getres(struct posix_clock *pc, struct timespec64 *tp)
 {
 	tp->tv_sec = 0;
 	tp->tv_nsec = 1;
 	return 0;
 }
 
-static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp)
+static int ptp_clock_settime(struct posix_clock *pc, const struct timespec64 *tp)
 {
 	struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
-	struct timespec64 ts = timespec_to_timespec64(*tp);
 
-	return  ptp->info->settime64(ptp->info, &ts);
+	return  ptp->info->settime64(ptp->info, tp);
 }
 
-static int ptp_clock_gettime(struct posix_clock *pc, struct timespec *tp)
+static int ptp_clock_gettime(struct posix_clock *pc, struct timespec64 *tp)
 {
 	struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
-	struct timespec64 ts;
 	int err;
 
-	err = ptp->info->gettime64(ptp->info, &ts);
-	if (!err)
-		*tp = timespec64_to_timespec(ts);
+	err = ptp->info->gettime64(ptp->info, tp);
 	return err;
 }
 
@@ -133,7 +129,7 @@
 	ops = ptp->info;
 
 	if (tx->modes & ADJ_SETOFFSET) {
-		struct timespec ts;
+		struct timespec64 ts;
 		ktime_t kt;
 		s64 delta;
 
@@ -146,7 +142,7 @@
 		if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC)
 			return -EINVAL;
 
-		kt = timespec_to_ktime(ts);
+		kt = timespec64_to_ktime(ts);
 		delta = ktime_to_ns(kt);
 		err = ops->adjtime(ops, delta);
 	} else if (tx->modes & ADJ_FREQUENCY) {
@@ -175,10 +171,11 @@
 	.read		= ptp_read,
 };
 
-static void delete_ptp_clock(struct posix_clock *pc)
+static void ptp_clock_release(struct device *dev)
 {
-	struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+	struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev);
 
+	ptp_cleanup_pin_groups(ptp);
 	mutex_destroy(&ptp->tsevq_mux);
 	mutex_destroy(&ptp->pincfg_mux);
 	ida_simple_remove(&ptp_clocks_map, ptp->index);
@@ -209,7 +206,6 @@
 	}
 
 	ptp->clock.ops = ptp_clock_ops;
-	ptp->clock.release = delete_ptp_clock;
 	ptp->info = info;
 	ptp->devid = MKDEV(major, index);
 	ptp->index = index;
@@ -218,17 +214,9 @@
 	mutex_init(&ptp->pincfg_mux);
 	init_waitqueue_head(&ptp->tsev_wq);
 
-	/* Create a new device in our class. */
-	ptp->dev = device_create(ptp_class, parent, ptp->devid, ptp,
-				 "ptp%d", ptp->index);
-	if (IS_ERR(ptp->dev))
-		goto no_device;
-
-	dev_set_drvdata(ptp->dev, ptp);
-
-	err = ptp_populate_sysfs(ptp);
+	err = ptp_populate_pin_groups(ptp);
 	if (err)
-		goto no_sysfs;
+		goto no_pin_groups;
 
 	/* Register a new PPS source. */
 	if (info->pps) {
@@ -239,13 +227,24 @@
 		pps.owner = info->owner;
 		ptp->pps_source = pps_register_source(&pps, PTP_PPS_DEFAULTS);
 		if (!ptp->pps_source) {
+			err = -EINVAL;
 			pr_err("failed to register pps source\n");
 			goto no_pps;
 		}
 	}
 
-	/* Create a posix clock. */
-	err = posix_clock_register(&ptp->clock, ptp->devid);
+	/* Initialize a new device of our class in our clock structure. */
+	device_initialize(&ptp->dev);
+	ptp->dev.devt = ptp->devid;
+	ptp->dev.class = ptp_class;
+	ptp->dev.parent = parent;
+	ptp->dev.groups = ptp->pin_attr_groups;
+	ptp->dev.release = ptp_clock_release;
+	dev_set_drvdata(&ptp->dev, ptp);
+	dev_set_name(&ptp->dev, "ptp%d", ptp->index);
+
+	/* Create a posix clock and link it to the device. */
+	err = posix_clock_register(&ptp->clock, &ptp->dev);
 	if (err) {
 		pr_err("failed to create posix clock\n");
 		goto no_clock;
@@ -257,10 +256,8 @@
 	if (ptp->pps_source)
 		pps_unregister_source(ptp->pps_source);
 no_pps:
-	ptp_cleanup_sysfs(ptp);
-no_sysfs:
-	device_destroy(ptp_class, ptp->devid);
-no_device:
+	ptp_cleanup_pin_groups(ptp);
+no_pin_groups:
 	mutex_destroy(&ptp->tsevq_mux);
 	mutex_destroy(&ptp->pincfg_mux);
 no_slot:
@@ -278,10 +275,9 @@
 	/* Release the clock's resources. */
 	if (ptp->pps_source)
 		pps_unregister_source(ptp->pps_source);
-	ptp_cleanup_sysfs(ptp);
-	device_destroy(ptp_class, ptp->devid);
 
 	posix_clock_unregister(&ptp->clock);
+
 	return 0;
 }
 EXPORT_SYMBOL(ptp_clock_unregister);
--- linux-4.4.0.orig/drivers/ptp/ptp_private.h
+++ linux-4.4.0/drivers/ptp/ptp_private.h
@@ -40,7 +40,7 @@
 
 struct ptp_clock {
 	struct posix_clock clock;
-	struct device *dev;
+	struct device dev;
 	struct ptp_clock_info *info;
 	dev_t devid;
 	int index; /* index into clocks.map */
@@ -54,6 +54,8 @@
 	struct device_attribute *pin_dev_attr;
 	struct attribute **pin_attr;
 	struct attribute_group pin_attr_group;
+	/* 1st entry is a pointer to the real group, 2nd is NULL terminator */
+	const struct attribute_group *pin_attr_groups[2];
 };
 
 /*
@@ -94,8 +96,7 @@
 
 extern const struct attribute_group *ptp_groups[];
 
-int ptp_cleanup_sysfs(struct ptp_clock *ptp);
-
-int ptp_populate_sysfs(struct ptp_clock *ptp);
+int ptp_populate_pin_groups(struct ptp_clock *ptp);
+void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
 
 #endif
--- linux-4.4.0.orig/drivers/ptp/ptp_sysfs.c
+++ linux-4.4.0/drivers/ptp/ptp_sysfs.c
@@ -46,27 +46,6 @@
 PTP_SHOW_INT(n_programmable_pins, n_pins);
 PTP_SHOW_INT(pps_available, pps);
 
-static struct attribute *ptp_attrs[] = {
-	&dev_attr_clock_name.attr,
-	&dev_attr_max_adjustment.attr,
-	&dev_attr_n_alarms.attr,
-	&dev_attr_n_external_timestamps.attr,
-	&dev_attr_n_periodic_outputs.attr,
-	&dev_attr_n_programmable_pins.attr,
-	&dev_attr_pps_available.attr,
-	NULL,
-};
-
-static const struct attribute_group ptp_group = {
-	.attrs = ptp_attrs,
-};
-
-const struct attribute_group *ptp_groups[] = {
-	&ptp_group,
-	NULL,
-};
-
-
 static ssize_t extts_enable_store(struct device *dev,
 				  struct device_attribute *attr,
 				  const char *buf, size_t count)
@@ -91,6 +70,7 @@
 out:
 	return err;
 }
+static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
 
 static ssize_t extts_fifo_show(struct device *dev,
 			       struct device_attribute *attr, char *page)
@@ -124,6 +104,7 @@
 	mutex_unlock(&ptp->tsevq_mux);
 	return cnt;
 }
+static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
 
 static ssize_t period_store(struct device *dev,
 			    struct device_attribute *attr,
@@ -151,6 +132,7 @@
 out:
 	return err;
 }
+static DEVICE_ATTR(period, 0220, NULL, period_store);
 
 static ssize_t pps_enable_store(struct device *dev,
 				struct device_attribute *attr,
@@ -177,6 +159,57 @@
 out:
 	return err;
 }
+static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store);
+
+static struct attribute *ptp_attrs[] = {
+	&dev_attr_clock_name.attr,
+
+	&dev_attr_max_adjustment.attr,
+	&dev_attr_n_alarms.attr,
+	&dev_attr_n_external_timestamps.attr,
+	&dev_attr_n_periodic_outputs.attr,
+	&dev_attr_n_programmable_pins.attr,
+	&dev_attr_pps_available.attr,
+
+	&dev_attr_extts_enable.attr,
+	&dev_attr_fifo.attr,
+	&dev_attr_period.attr,
+	&dev_attr_pps_enable.attr,
+	NULL
+};
+
+static umode_t ptp_is_attribute_visible(struct kobject *kobj,
+					struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct ptp_clock *ptp = dev_get_drvdata(dev);
+	struct ptp_clock_info *info = ptp->info;
+	umode_t mode = attr->mode;
+
+	if (attr == &dev_attr_extts_enable.attr ||
+	    attr == &dev_attr_fifo.attr) {
+		if (!info->n_ext_ts)
+			mode = 0;
+	} else if (attr == &dev_attr_period.attr) {
+		if (!info->n_per_out)
+			mode = 0;
+	} else if (attr == &dev_attr_pps_enable.attr) {
+		if (!info->pps)
+			mode = 0;
+	}
+
+	return mode;
+}
+
+static const struct attribute_group ptp_group = {
+	.is_visible	= ptp_is_attribute_visible,
+	.attrs		= ptp_attrs,
+};
+
+const struct attribute_group *ptp_groups[] = {
+	&ptp_group,
+	NULL
+};
 
 static int ptp_pin_name2index(struct ptp_clock *ptp, const char *name)
 {
@@ -235,40 +268,14 @@
 	return count;
 }
 
-static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
-static DEVICE_ATTR(fifo,         0444, extts_fifo_show, NULL);
-static DEVICE_ATTR(period,       0220, NULL, period_store);
-static DEVICE_ATTR(pps_enable,   0220, NULL, pps_enable_store);
-
-int ptp_cleanup_sysfs(struct ptp_clock *ptp)
-{
-	struct device *dev = ptp->dev;
-	struct ptp_clock_info *info = ptp->info;
-
-	if (info->n_ext_ts) {
-		device_remove_file(dev, &dev_attr_extts_enable);
-		device_remove_file(dev, &dev_attr_fifo);
-	}
-	if (info->n_per_out)
-		device_remove_file(dev, &dev_attr_period);
-
-	if (info->pps)
-		device_remove_file(dev, &dev_attr_pps_enable);
-
-	if (info->n_pins) {
-		sysfs_remove_group(&dev->kobj, &ptp->pin_attr_group);
-		kfree(ptp->pin_attr);
-		kfree(ptp->pin_dev_attr);
-	}
-	return 0;
-}
-
-static int ptp_populate_pins(struct ptp_clock *ptp)
+int ptp_populate_pin_groups(struct ptp_clock *ptp)
 {
-	struct device *dev = ptp->dev;
 	struct ptp_clock_info *info = ptp->info;
 	int err = -ENOMEM, i, n_pins = info->n_pins;
 
+	if (!n_pins)
+		return 0;
+
 	ptp->pin_dev_attr = kzalloc(n_pins * sizeof(*ptp->pin_dev_attr),
 				    GFP_KERNEL);
 	if (!ptp->pin_dev_attr)
@@ -292,61 +299,18 @@
 	ptp->pin_attr_group.name = "pins";
 	ptp->pin_attr_group.attrs = ptp->pin_attr;
 
-	err = sysfs_create_group(&dev->kobj, &ptp->pin_attr_group);
-	if (err)
-		goto no_group;
+	ptp->pin_attr_groups[0] = &ptp->pin_attr_group;
+
 	return 0;
 
-no_group:
-	kfree(ptp->pin_attr);
 no_pin_attr:
 	kfree(ptp->pin_dev_attr);
 no_dev_attr:
 	return err;
 }
 
-int ptp_populate_sysfs(struct ptp_clock *ptp)
+void ptp_cleanup_pin_groups(struct ptp_clock *ptp)
 {
-	struct device *dev = ptp->dev;
-	struct ptp_clock_info *info = ptp->info;
-	int err;
-
-	if (info->n_ext_ts) {
-		err = device_create_file(dev, &dev_attr_extts_enable);
-		if (err)
-			goto out1;
-		err = device_create_file(dev, &dev_attr_fifo);
-		if (err)
-			goto out2;
-	}
-	if (info->n_per_out) {
-		err = device_create_file(dev, &dev_attr_period);
-		if (err)
-			goto out3;
-	}
-	if (info->pps) {
-		err = device_create_file(dev, &dev_attr_pps_enable);
-		if (err)
-			goto out4;
-	}
-	if (info->n_pins) {
-		err = ptp_populate_pins(ptp);
-		if (err)
-			goto out5;
-	}
-	return 0;
-out5:
-	if (info->pps)
-		device_remove_file(dev, &dev_attr_pps_enable);
-out4:
-	if (info->n_per_out)
-		device_remove_file(dev, &dev_attr_period);
-out3:
-	if (info->n_ext_ts)
-		device_remove_file(dev, &dev_attr_fifo);
-out2:
-	if (info->n_ext_ts)
-		device_remove_file(dev, &dev_attr_extts_enable);
-out1:
-	return err;
+	kfree(ptp->pin_attr);
+	kfree(ptp->pin_dev_attr);
 }
--- linux-4.4.0.orig/drivers/pwm/Kconfig
+++ linux-4.4.0/drivers/pwm/Kconfig
@@ -148,6 +148,7 @@
 
 config PWM_FSL_FTM
 	tristate "Freescale FlexTimer Module (FTM) PWM support"
+	depends on HAS_IOMEM
 	depends on OF
 	select REGMAP_MMIO
 	help
@@ -222,18 +223,12 @@
 	  will be called pwm-lpc32xx.
 
 config PWM_LPSS
-	tristate "Intel LPSS PWM support"
-	depends on X86
-	help
-	  Generic PWM framework driver for Intel Low Power Subsystem PWM
-	  controller.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called pwm-lpss.
+	tristate
 
 config PWM_LPSS_PCI
 	tristate "Intel LPSS PWM PCI driver"
-	depends on PWM_LPSS && PCI
+	depends on X86 && PCI
+	select PWM_LPSS
 	help
 	  The PCI driver for Intel Low Power Subsystem PWM controller.
 
@@ -242,7 +237,8 @@
 
 config PWM_LPSS_PLATFORM
 	tristate "Intel LPSS PWM platform driver"
-	depends on PWM_LPSS && ACPI
+	depends on X86 && ACPI
+	select PWM_LPSS
 	help
 	  The platform driver for Intel Low Power Subsystem PWM controller.
 
@@ -270,6 +266,15 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-mxs.
 
+config PWM_OMAP_DMTIMER
+	tristate "OMAP Dual-Mode Timer PWM support"
+	depends on OF && ARCH_OMAP && OMAP_DM_TIMER
+	help
+	  Generic PWM framework driver for OMAP Dual-Mode Timer PWM output
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-omap-dmtimer
+
 config PWM_PCA9685
 	tristate "NXP PCA9685 PWM driver"
 	depends on I2C
--- linux-4.4.0.orig/drivers/pwm/Makefile
+++ linux-4.4.0/drivers/pwm/Makefile
@@ -24,6 +24,7 @@
 obj-$(CONFIG_PWM_LPSS_PLATFORM)	+= pwm-lpss-platform.o
 obj-$(CONFIG_PWM_MTK_DISP)	+= pwm-mtk-disp.o
 obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o
+obj-$(CONFIG_PWM_OMAP_DMTIMER)	+= pwm-omap-dmtimer.o
 obj-$(CONFIG_PWM_PCA9685)	+= pwm-pca9685.o
 obj-$(CONFIG_PWM_PUV3)		+= pwm-puv3.o
 obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
--- linux-4.4.0.orig/drivers/pwm/core.c
+++ linux-4.4.0/drivers/pwm/core.c
@@ -284,10 +284,12 @@
 	if (IS_ENABLED(CONFIG_OF))
 		of_pwmchip_add(chip);
 
-	pwmchip_sysfs_export(chip);
-
 out:
 	mutex_unlock(&pwm_lock);
+
+	if (!ret)
+		pwmchip_sysfs_export(chip);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(pwmchip_add_with_polarity);
@@ -321,6 +323,8 @@
 	unsigned int i;
 	int ret = 0;
 
+	pwmchip_sysfs_unexport(chip);
+
 	mutex_lock(&pwm_lock);
 
 	for (i = 0; i < chip->npwm; i++) {
@@ -339,8 +343,6 @@
 
 	free_pwms(chip);
 
-	pwmchip_sysfs_unexport(chip);
-
 out:
 	mutex_unlock(&pwm_lock);
 	return ret;
@@ -779,6 +781,7 @@
 	if (pwm->chip->ops->free)
 		pwm->chip->ops->free(pwm->chip, pwm);
 
+	pwm_set_chip_data(pwm, NULL);
 	pwm->label = NULL;
 
 	module_put(pwm->chip->ops->owner);
@@ -889,7 +892,7 @@
   */
 bool pwm_can_sleep(struct pwm_device *pwm)
 {
-	return pwm->chip->can_sleep;
+	return true;
 }
 EXPORT_SYMBOL_GPL(pwm_can_sleep);
 
--- linux-4.4.0.orig/drivers/pwm/pwm-bcm2835.c
+++ linux-4.4.0/drivers/pwm/pwm-bcm2835.c
@@ -29,7 +29,6 @@
 struct bcm2835_pwm {
 	struct pwm_chip chip;
 	struct device *dev;
-	unsigned long scaler;
 	void __iomem *base;
 	struct clk *clk;
 };
@@ -66,6 +65,15 @@
 			      int duty_ns, int period_ns)
 {
 	struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
+	unsigned long rate = clk_get_rate(pc->clk);
+	unsigned long scaler;
+
+	if (!rate) {
+		dev_err(pc->dev, "failed to get clock rate\n");
+		return -EINVAL;
+	}
+
+	scaler = NSEC_PER_SEC / rate;
 
 	if (period_ns <= MIN_PERIOD) {
 		dev_err(pc->dev, "period %d not supported, minimum %d\n",
@@ -73,8 +81,8 @@
 		return -EINVAL;
 	}
 
-	writel(duty_ns / pc->scaler, pc->base + DUTY(pwm->hwpwm));
-	writel(period_ns / pc->scaler, pc->base + PERIOD(pwm->hwpwm));
+	writel(duty_ns / scaler, pc->base + DUTY(pwm->hwpwm));
+	writel(period_ns / scaler, pc->base + PERIOD(pwm->hwpwm));
 
 	return 0;
 }
@@ -156,10 +164,9 @@
 	if (ret)
 		return ret;
 
-	pc->scaler = NSEC_PER_SEC / clk_get_rate(pc->clk);
-
 	pc->chip.dev = &pdev->dev;
 	pc->chip.ops = &bcm2835_pwm_ops;
+	pc->chip.base = -1;
 	pc->chip.npwm = 2;
 
 	platform_set_drvdata(pdev, pc);
@@ -200,6 +207,6 @@
 };
 module_platform_driver(bcm2835_pwm_driver);
 
-MODULE_AUTHOR("Bart Tanghe <bart.tanghe@thomasmore.be");
+MODULE_AUTHOR("Bart Tanghe <bart.tanghe@thomasmore.be>");
 MODULE_DESCRIPTION("Broadcom BCM2835 PWM driver");
 MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/pwm/pwm-brcmstb.c
+++ linux-4.4.0/drivers/pwm/pwm-brcmstb.c
@@ -274,8 +274,8 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	p->base = devm_ioremap_resource(&pdev->dev, res);
-	if (!p->base) {
-		ret = -ENOMEM;
+	if (IS_ERR(p->base)) {
+		ret = PTR_ERR(p->base);
 		goto out_clk;
 	}
 
--- linux-4.4.0.orig/drivers/pwm/pwm-fsl-ftm.c
+++ linux-4.4.0/drivers/pwm/pwm-fsl-ftm.c
@@ -80,7 +80,6 @@
 
 	struct mutex lock;
 
-	unsigned int use_count;
 	unsigned int cnt_select;
 	unsigned int clk_ps;
 
@@ -300,9 +299,6 @@
 {
 	int ret;
 
-	if (fpc->use_count++ != 0)
-		return 0;
-
 	/* select counter clock source */
 	regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
 			   FTM_SC_CLK(fpc->cnt_select));
@@ -334,25 +330,6 @@
 	return ret;
 }
 
-static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc)
-{
-	/*
-	 * already disabled, do nothing
-	 */
-	if (fpc->use_count == 0)
-		return;
-
-	/* there are still users, so can't disable yet */
-	if (--fpc->use_count > 0)
-		return;
-
-	/* no users left, disable PWM counter clock */
-	regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, 0);
-
-	clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
-	clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
-}
-
 static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
@@ -362,7 +339,8 @@
 	regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm),
 			   BIT(pwm->hwpwm));
 
-	fsl_counter_clock_disable(fpc);
+	clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
+	clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
 
 	regmap_read(fpc->regmap, FTM_OUTMASK, &val);
 	if ((val & 0xFF) == 0xFF)
@@ -414,7 +392,7 @@
 
 	.max_register = FTM_PWMLOAD,
 	.volatile_reg = fsl_pwm_volatile_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static int fsl_pwm_probe(struct platform_device *pdev)
@@ -492,17 +470,24 @@
 static int fsl_pwm_suspend(struct device *dev)
 {
 	struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
-	u32 val;
+	int i;
 
 	regcache_cache_only(fpc->regmap, true);
 	regcache_mark_dirty(fpc->regmap);
 
-	/* read from cache */
-	regmap_read(fpc->regmap, FTM_OUTMASK, &val);
-	if ((val & 0xFF) != 0xFF) {
+	for (i = 0; i < fpc->chip.npwm; i++) {
+		struct pwm_device *pwm = &fpc->chip.pwms[i];
+
+		if (!test_bit(PWMF_REQUESTED, &pwm->flags))
+			continue;
+
+		clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
+
+		if (!pwm_is_enabled(pwm))
+			continue;
+
 		clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
 		clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
-		clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
 	}
 
 	return 0;
@@ -511,12 +496,19 @@
 static int fsl_pwm_resume(struct device *dev)
 {
 	struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
-	u32 val;
+	int i;
+
+	for (i = 0; i < fpc->chip.npwm; i++) {
+		struct pwm_device *pwm = &fpc->chip.pwms[i];
+
+		if (!test_bit(PWMF_REQUESTED, &pwm->flags))
+			continue;
 
-	/* read from cache */
-	regmap_read(fpc->regmap, FTM_OUTMASK, &val);
-	if ((val & 0xFF) != 0xFF) {
 		clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
+
+		if (!pwm_is_enabled(pwm))
+			continue;
+
 		clk_prepare_enable(fpc->clk[fpc->cnt_select]);
 		clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
 	}
--- linux-4.4.0.orig/drivers/pwm/pwm-lpc32xx.c
+++ linux-4.4.0/drivers/pwm/pwm-lpc32xx.c
@@ -24,9 +24,7 @@
 	void __iomem *base;
 };
 
-#define PWM_ENABLE	(1 << 31)
-#define PWM_RELOADV(x)	(((x) & 0xFF) << 8)
-#define PWM_DUTY(x)	((x) & 0xFF)
+#define PWM_ENABLE	BIT(31)
 
 #define to_lpc32xx_pwm_chip(_chip) \
 	container_of(_chip, struct lpc32xx_pwm_chip, chip)
@@ -38,40 +36,27 @@
 	unsigned long long c;
 	int period_cycles, duty_cycles;
 	u32 val;
+	c = clk_get_rate(lpc32xx->clk);
 
-	c = clk_get_rate(lpc32xx->clk) / 256;
-	c = c * period_ns;
-	do_div(c, NSEC_PER_SEC);
-
-	/* Handle high and low extremes */
-	if (c == 0)
-		c = 1;
-	if (c > 255)
-		c = 0; /* 0 set division by 256 */
-	period_cycles = c;
-
-	/* The duty-cycle value is as follows:
-	 *
-	 *  DUTY-CYCLE     HIGH LEVEL
-	 *      1            99.9%
-	 *      25           90.0%
-	 *      128          50.0%
-	 *      220          10.0%
-	 *      255           0.1%
-	 *      0             0.0%
-	 *
-	 * In other words, the register value is duty-cycle % 256 with
-	 * duty-cycle in the range 1-256.
-	 */
-	c = 256 * duty_ns;
-	do_div(c, period_ns);
-	if (c > 255)
-		c = 255;
-	duty_cycles = 256 - c;
+	/* The highest acceptable divisor is 256, which is represented by 0 */
+	period_cycles = div64_u64(c * period_ns,
+			       (unsigned long long)NSEC_PER_SEC * 256);
+	if (!period_cycles || period_cycles > 256)
+		return -ERANGE;
+	if (period_cycles == 256)
+		period_cycles = 0;
+
+	/* Compute 256 x #duty/period value and care for corner cases */
+	duty_cycles = div64_u64((unsigned long long)(period_ns - duty_ns) * 256,
+				period_ns);
+	if (!duty_cycles)
+		duty_cycles = 1;
+	if (duty_cycles > 255)
+		duty_cycles = 255;
 
 	val = readl(lpc32xx->base + (pwm->hwpwm << 2));
 	val &= ~0xFFFF;
-	val |= PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles);
+	val |= (period_cycles << 8) | duty_cycles;
 	writel(val, lpc32xx->base + (pwm->hwpwm << 2));
 
 	return 0;
@@ -83,7 +68,7 @@
 	u32 val;
 	int ret;
 
-	ret = clk_enable(lpc32xx->clk);
+	ret = clk_prepare_enable(lpc32xx->clk);
 	if (ret)
 		return ret;
 
@@ -103,7 +88,7 @@
 	val &= ~PWM_ENABLE;
 	writel(val, lpc32xx->base + (pwm->hwpwm << 2));
 
-	clk_disable(lpc32xx->clk);
+	clk_disable_unprepare(lpc32xx->clk);
 }
 
 static const struct pwm_ops lpc32xx_pwm_ops = {
@@ -134,7 +119,7 @@
 
 	lpc32xx->chip.dev = &pdev->dev;
 	lpc32xx->chip.ops = &lpc32xx_pwm_ops;
-	lpc32xx->chip.npwm = 2;
+	lpc32xx->chip.npwm = 1;
 	lpc32xx->chip.base = -1;
 
 	ret = pwmchip_add(&lpc32xx->chip);
--- linux-4.4.0.orig/drivers/pwm/pwm-lpss.c
+++ linux-4.4.0/drivers/pwm/pwm-lpss.c
@@ -13,10 +13,12 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/time.h>
 
 #include "pwm-lpss.h"
 
@@ -24,11 +26,8 @@
 #define PWM_ENABLE			BIT(31)
 #define PWM_SW_UPDATE			BIT(30)
 #define PWM_BASE_UNIT_SHIFT		8
-#define PWM_BASE_UNIT_MASK		0x00ffff00
 #define PWM_ON_TIME_DIV_MASK		0x000000ff
 #define PWM_DIVISION_CORRECTION		0x2
-#define PWM_LIMIT			(0x8000 + PWM_DIVISION_CORRECTION)
-#define NSECS_PER_SEC			1000000000UL
 
 /* Size of each PWM register space if multiple */
 #define PWM_SIZE			0x400
@@ -36,13 +35,14 @@
 struct pwm_lpss_chip {
 	struct pwm_chip chip;
 	void __iomem *regs;
-	unsigned long clk_rate;
+	const struct pwm_lpss_boardinfo *info;
 };
 
 /* BayTrail */
 const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
 	.clk_rate = 25000000,
 	.npwm = 1,
+	.base_unit_bits = 16,
 };
 EXPORT_SYMBOL_GPL(pwm_lpss_byt_info);
 
@@ -50,6 +50,7 @@
 const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
 	.clk_rate = 19200000,
 	.npwm = 1,
+	.base_unit_bits = 16,
 };
 EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info);
 
@@ -57,6 +58,7 @@
 const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
 	.clk_rate = 19200000,
 	.npwm = 4,
+	.base_unit_bits = 22,
 };
 EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info);
 
@@ -79,28 +81,37 @@
 	writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
 }
 
+static void pwm_lpss_update(struct pwm_device *pwm)
+{
+	pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
+	/* Give it some time to propagate */
+	usleep_range(10, 50);
+}
+
 static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			   int duty_ns, int period_ns)
 {
 	struct pwm_lpss_chip *lpwm = to_lpwm(chip);
 	u8 on_time_div;
-	unsigned long c;
-	unsigned long long base_unit, freq = NSECS_PER_SEC;
+	unsigned long c, base_unit_range;
+	unsigned long long base_unit, freq = NSEC_PER_SEC;
 	u32 ctrl;
 
 	do_div(freq, period_ns);
 
-	/* The equation is: base_unit = ((freq / c) * 65536) + correction */
-	base_unit = freq * 65536;
+	/*
+	 * The equation is:
+	 * base_unit = ((freq / c) * base_unit_range) + correction
+	 */
+	base_unit_range = BIT(lpwm->info->base_unit_bits);
+	base_unit = freq * base_unit_range;
 
-	c = lpwm->clk_rate;
+	c = lpwm->info->clk_rate;
 	if (!c)
 		return -EINVAL;
 
 	do_div(base_unit, c);
 	base_unit += PWM_DIVISION_CORRECTION;
-	if (base_unit > PWM_LIMIT)
-		return -EINVAL;
 
 	if (duty_ns <= 0)
 		duty_ns = 1;
@@ -109,13 +120,20 @@
 	pm_runtime_get_sync(chip->dev);
 
 	ctrl = pwm_lpss_read(pwm);
-	ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK);
-	ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT;
+	ctrl &= ~PWM_ON_TIME_DIV_MASK;
+	ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
+	base_unit &= (base_unit_range - 1);
+	ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
 	ctrl |= on_time_div;
-	/* request PWM to update on next cycle */
-	ctrl |= PWM_SW_UPDATE;
 	pwm_lpss_write(pwm, ctrl);
 
+	/*
+	 * If the PWM is already enabled we need to notify the hardware
+	 * about the change by setting PWM_SW_UPDATE.
+	 */
+	if (pwm_is_enabled(pwm))
+		pwm_lpss_update(pwm);
+
 	pm_runtime_put(chip->dev);
 
 	return 0;
@@ -124,6 +142,12 @@
 static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	pm_runtime_get_sync(chip->dev);
+
+	/*
+	 * Hardware must first see PWM_SW_UPDATE before the PWM can be
+	 * enabled.
+	 */
+	pwm_lpss_update(pwm);
 	pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
 	return 0;
 }
@@ -135,7 +159,6 @@
 }
 
 static const struct pwm_ops pwm_lpss_ops = {
-	.free = pwm_lpss_disable,
 	.config = pwm_lpss_config,
 	.enable = pwm_lpss_enable,
 	.disable = pwm_lpss_disable,
@@ -156,7 +179,7 @@
 	if (IS_ERR(lpwm->regs))
 		return ERR_CAST(lpwm->regs);
 
-	lpwm->clk_rate = info->clk_rate;
+	lpwm->info = info;
 	lpwm->chip.dev = dev;
 	lpwm->chip.ops = &pwm_lpss_ops;
 	lpwm->chip.base = -1;
--- linux-4.4.0.orig/drivers/pwm/pwm-lpss.h
+++ linux-4.4.0/drivers/pwm/pwm-lpss.h
@@ -21,6 +21,7 @@
 struct pwm_lpss_boardinfo {
 	unsigned long clk_rate;
 	unsigned int npwm;
+	unsigned long base_unit_bits;
 };
 
 extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info;
--- linux-4.4.0.orig/drivers/pwm/pwm-omap-dmtimer.c
+++ linux-4.4.0/drivers/pwm/pwm-omap-dmtimer.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015 Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (c) 2014 Joachim Eastwood <manabian@gmail.com>
+ * Copyright (c) 2012 NeilBrown <neilb@suse.de>
+ * Heavily based on earlier code which is:
+ * Copyright (c) 2010 Grant Erickson <marathon96@gmail.com>
+ *
+ * Also based on pwm-samsung.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Description:
+ *   This file is the core OMAP support for the generic, Linux
+ *   PWM driver / controller, using the OMAP's dual-mode timers.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_data/pwm_omap_dmtimer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#define DM_TIMER_LOAD_MIN 0xfffffffe
+
+struct pwm_omap_dmtimer_chip {
+	struct pwm_chip chip;
+	struct mutex mutex;
+	pwm_omap_dmtimer *dm_timer;
+	struct pwm_omap_dmtimer_pdata *pdata;
+	struct platform_device *dm_timer_pdev;
+};
+
+static inline struct pwm_omap_dmtimer_chip *
+to_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
+}
+
+static int pwm_omap_dmtimer_calc_value(unsigned long clk_rate, int ns)
+{
+	u64 c = (u64)clk_rate * ns;
+
+	do_div(c, NSEC_PER_SEC);
+
+	return DM_TIMER_LOAD_MIN - c;
+}
+
+static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
+{
+	/*
+	 * According to OMAP 4 TRM section 22.2.4.10 the counter should be
+	 * started at 0xFFFFFFFE when overflow and match is used to ensure
+	 * that the PWM line is toggled on the first event.
+	 *
+	 * Note that omap_dm_timer_enable/disable is for register access and
+	 * not the timer counter itself.
+	 */
+	omap->pdata->enable(omap->dm_timer);
+	omap->pdata->write_counter(omap->dm_timer, DM_TIMER_LOAD_MIN);
+	omap->pdata->disable(omap->dm_timer);
+
+	omap->pdata->start(omap->dm_timer);
+}
+
+static int pwm_omap_dmtimer_enable(struct pwm_chip *chip,
+				   struct pwm_device *pwm)
+{
+	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+
+	mutex_lock(&omap->mutex);
+	pwm_omap_dmtimer_start(omap);
+	mutex_unlock(&omap->mutex);
+
+	return 0;
+}
+
+static void pwm_omap_dmtimer_disable(struct pwm_chip *chip,
+				     struct pwm_device *pwm)
+{
+	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+
+	mutex_lock(&omap->mutex);
+	omap->pdata->stop(omap->dm_timer);
+	mutex_unlock(&omap->mutex);
+}
+
+static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
+				   struct pwm_device *pwm,
+				   int duty_ns, int period_ns)
+{
+	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+	int load_value, match_value;
+	struct clk *fclk;
+	unsigned long clk_rate;
+	bool timer_active;
+
+	dev_dbg(chip->dev, "duty cycle: %d, period %d\n", duty_ns, period_ns);
+
+	mutex_lock(&omap->mutex);
+	if (duty_ns == pwm_get_duty_cycle(pwm) &&
+	    period_ns == pwm_get_period(pwm)) {
+		/* No change - don't cause any transients. */
+		mutex_unlock(&omap->mutex);
+		return 0;
+	}
+
+	fclk = omap->pdata->get_fclk(omap->dm_timer);
+	if (!fclk) {
+		dev_err(chip->dev, "invalid pmtimer fclk\n");
+		mutex_unlock(&omap->mutex);
+		return -EINVAL;
+	}
+
+	clk_rate = clk_get_rate(fclk);
+	if (!clk_rate) {
+		dev_err(chip->dev, "invalid pmtimer fclk rate\n");
+		mutex_unlock(&omap->mutex);
+		return -EINVAL;
+	}
+
+	dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
+
+	/*
+	 * Calculate the appropriate load and match values based on the
+	 * specified period and duty cycle. The load value determines the
+	 * cycle time and the match value determines the duty cycle.
+	 */
+	load_value = pwm_omap_dmtimer_calc_value(clk_rate, period_ns);
+	match_value = pwm_omap_dmtimer_calc_value(clk_rate,
+						  period_ns - duty_ns);
+
+	/*
+	 * We MUST stop the associated dual-mode timer before attempting to
+	 * write its registers, but calls to omap_dm_timer_start/stop must
+	 * be balanced so check if timer is active before calling timer_stop.
+	 */
+	timer_active = pm_runtime_active(&omap->dm_timer_pdev->dev);
+	if (timer_active)
+		omap->pdata->stop(omap->dm_timer);
+
+	omap->pdata->set_load(omap->dm_timer, true, load_value);
+	omap->pdata->set_match(omap->dm_timer, true, match_value);
+
+	dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
+		load_value, load_value,	match_value, match_value);
+
+	omap->pdata->set_pwm(omap->dm_timer,
+			      pwm->polarity == PWM_POLARITY_INVERSED,
+			      true,
+			      PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+
+	/* If config was called while timer was running it must be reenabled. */
+	if (timer_active)
+		pwm_omap_dmtimer_start(omap);
+
+	mutex_unlock(&omap->mutex);
+
+	return 0;
+}
+
+static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
+					 struct pwm_device *pwm,
+					 enum pwm_polarity polarity)
+{
+	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+
+	/*
+	 * PWM core will not call set_polarity while PWM is enabled so it's
+	 * safe to reconfigure the timer here without stopping it first.
+	 */
+	mutex_lock(&omap->mutex);
+	omap->pdata->set_pwm(omap->dm_timer,
+			      polarity == PWM_POLARITY_INVERSED,
+			      true,
+			      PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+	mutex_unlock(&omap->mutex);
+
+	return 0;
+}
+
+static const struct pwm_ops pwm_omap_dmtimer_ops = {
+	.enable	= pwm_omap_dmtimer_enable,
+	.disable = pwm_omap_dmtimer_disable,
+	.config	= pwm_omap_dmtimer_config,
+	.set_polarity = pwm_omap_dmtimer_set_polarity,
+	.owner = THIS_MODULE,
+};
+
+static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *timer;
+	struct pwm_omap_dmtimer_chip *omap;
+	struct pwm_omap_dmtimer_pdata *pdata;
+	pwm_omap_dmtimer *dm_timer;
+	u32 prescaler;
+	int status;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "Missing dmtimer platform data\n");
+		return -EINVAL;
+	}
+
+	if (!pdata->request_by_node ||
+	    !pdata->free ||
+	    !pdata->enable ||
+	    !pdata->disable ||
+	    !pdata->get_fclk ||
+	    !pdata->start ||
+	    !pdata->stop ||
+	    !pdata->set_load ||
+	    !pdata->set_match ||
+	    !pdata->set_pwm ||
+	    !pdata->set_prescaler ||
+	    !pdata->write_counter) {
+		dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");
+		return -EINVAL;
+	}
+
+	timer = of_parse_phandle(np, "ti,timers", 0);
+	if (!timer)
+		return -ENODEV;
+
+	if (!of_get_property(timer, "ti,timer-pwm", NULL)) {
+		dev_err(&pdev->dev, "Missing ti,timer-pwm capability\n");
+		return -ENODEV;
+	}
+
+	dm_timer = pdata->request_by_node(timer);
+	if (!dm_timer)
+		return -EPROBE_DEFER;
+
+	omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL);
+	if (!omap) {
+		pdata->free(dm_timer);
+		return -ENOMEM;
+	}
+
+	omap->pdata = pdata;
+	omap->dm_timer = dm_timer;
+
+	omap->dm_timer_pdev = of_find_device_by_node(timer);
+	if (!omap->dm_timer_pdev) {
+		dev_err(&pdev->dev, "Unable to find timer pdev\n");
+		omap->pdata->free(dm_timer);
+		return -EINVAL;
+	}
+
+	/*
+	 * Ensure that the timer is stopped before we allow PWM core to call
+	 * pwm_enable.
+	 */
+	if (pm_runtime_active(&omap->dm_timer_pdev->dev))
+		omap->pdata->stop(omap->dm_timer);
+
+	/* setup dmtimer prescaler */
+	if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler",
+				&prescaler))
+		omap->pdata->set_prescaler(omap->dm_timer, prescaler);
+
+	omap->chip.dev = &pdev->dev;
+	omap->chip.ops = &pwm_omap_dmtimer_ops;
+	omap->chip.base = -1;
+	omap->chip.npwm = 1;
+	omap->chip.of_xlate = of_pwm_xlate_with_flags;
+	omap->chip.of_pwm_n_cells = 3;
+
+	mutex_init(&omap->mutex);
+
+	status = pwmchip_add(&omap->chip);
+	if (status < 0) {
+		dev_err(&pdev->dev, "failed to register PWM\n");
+		omap->pdata->free(omap->dm_timer);
+		return status;
+	}
+
+	platform_set_drvdata(pdev, omap);
+
+	return 0;
+}
+
+static int pwm_omap_dmtimer_remove(struct platform_device *pdev)
+{
+	struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev);
+
+	if (pm_runtime_active(&omap->dm_timer_pdev->dev))
+		omap->pdata->stop(omap->dm_timer);
+
+	omap->pdata->free(omap->dm_timer);
+
+	mutex_destroy(&omap->mutex);
+
+	return pwmchip_remove(&omap->chip);
+}
+
+static const struct of_device_id pwm_omap_dmtimer_of_match[] = {
+	{.compatible = "ti,omap-dmtimer-pwm"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, pwm_omap_dmtimer_of_match);
+
+static struct platform_driver pwm_omap_dmtimer_driver = {
+	.driver = {
+		.name = "omap-dmtimer-pwm",
+		.of_match_table = of_match_ptr(pwm_omap_dmtimer_of_match),
+	},
+	.probe = pwm_omap_dmtimer_probe,
+	.remove	= pwm_omap_dmtimer_remove,
+};
+module_platform_driver(pwm_omap_dmtimer_driver);
+
+MODULE_AUTHOR("Grant Erickson <marathon96@gmail.com>");
+MODULE_AUTHOR("NeilBrown <neilb@suse.de>");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP PWM Driver using Dual-mode Timers");
--- linux-4.4.0.orig/drivers/pwm/pwm-pca9685.c
+++ linux-4.4.0/drivers/pwm/pwm-pca9685.c
@@ -65,7 +65,6 @@
 #define PCA9685_MAXCHAN		0x10
 
 #define LED_FULL		(1 << 4)
-#define MODE1_RESTART		(1 << 7)
 #define MODE1_SLEEP		(1 << 4)
 #define MODE2_INVRT		(1 << 4)
 #define MODE2_OUTDRV		(1 << 2)
@@ -117,16 +116,6 @@
 			udelay(500);
 
 			pca->period_ns = period_ns;
-
-			/*
-			 * If the duty cycle did not change, restart PWM with
-			 * the same duty cycle to period ratio and return.
-			 */
-			if (duty_ns == pca->duty_ns) {
-				regmap_update_bits(pca->regmap, PCA9685_MODE1,
-						   MODE1_RESTART, 0x1);
-				return 0;
-			}
 		} else {
 			dev_err(chip->dev,
 				"prescaler not set: period out of bounds!\n");
--- linux-4.4.0.orig/drivers/pwm/pwm-rcar.c
+++ linux-4.4.0/drivers/pwm/pwm-rcar.c
@@ -81,7 +81,7 @@
 		max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE *
 			(1 << div);
 		do_div(max, clk_rate);
-		if (period_ns < max)
+		if (period_ns <= max)
 			break;
 	}
 
@@ -232,24 +232,28 @@
 	rcar_pwm->chip.base = -1;
 	rcar_pwm->chip.npwm = 1;
 
+	pm_runtime_enable(&pdev->dev);
+
 	ret = pwmchip_add(&rcar_pwm->chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret);
+		pm_runtime_disable(&pdev->dev);
 		return ret;
 	}
 
-	pm_runtime_enable(&pdev->dev);
-
 	return 0;
 }
 
 static int rcar_pwm_remove(struct platform_device *pdev)
 {
 	struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = pwmchip_remove(&rcar_pwm->chip);
 
 	pm_runtime_disable(&pdev->dev);
 
-	return pwmchip_remove(&rcar_pwm->chip);
+	return ret;
 }
 
 static const struct of_device_id rcar_pwm_of_table[] = {
--- linux-4.4.0.orig/drivers/pwm/pwm-renesas-tpu.c
+++ linux-4.4.0/drivers/pwm/pwm-renesas-tpu.c
@@ -423,16 +423,17 @@
 	tpu->chip.base = -1;
 	tpu->chip.npwm = TPU_CHANNEL_MAX;
 
+	pm_runtime_enable(&pdev->dev);
+
 	ret = pwmchip_add(&tpu->chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to register PWM chip\n");
+		pm_runtime_disable(&pdev->dev);
 		return ret;
 	}
 
 	dev_info(&pdev->dev, "TPU PWM %d registered\n", tpu->pdev->id);
 
-	pm_runtime_enable(&pdev->dev);
-
 	return 0;
 }
 
@@ -442,12 +443,10 @@
 	int ret;
 
 	ret = pwmchip_remove(&tpu->chip);
-	if (ret)
-		return ret;
 
 	pm_runtime_disable(&pdev->dev);
 
-	return 0;
+	return ret;
 }
 
 #ifdef CONFIG_OF
--- linux-4.4.0.orig/drivers/pwm/pwm-samsung.c
+++ linux-4.4.0/drivers/pwm/pwm-samsung.c
@@ -226,7 +226,6 @@
 static void pwm_samsung_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	devm_kfree(chip->dev, pwm_get_chip_data(pwm));
-	pwm_set_chip_data(pwm, NULL);
 }
 
 static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
--- linux-4.4.0.orig/drivers/pwm/pwm-tegra.c
+++ linux-4.4.0/drivers/pwm/pwm-tegra.c
@@ -69,6 +69,7 @@
 	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
 	unsigned long long c;
 	unsigned long rate, hz;
+	unsigned long long ns100 = NSEC_PER_SEC;
 	u32 val = 0;
 	int err;
 
@@ -87,9 +88,11 @@
 	 * cycles at the PWM clock rate will take period_ns nanoseconds.
 	 */
 	rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH;
-	hz = NSEC_PER_SEC / period_ns;
 
-	rate = (rate + (hz / 2)) / hz;
+	/* Consider precision in PWM_SCALE_WIDTH rate calculation */
+	ns100 *= 100;
+	hz = DIV_ROUND_CLOSEST_ULL(ns100, period_ns);
+	rate = DIV_ROUND_CLOSEST(rate * 100, hz);
 
 	/*
 	 * Since the actual PWM divider is the register's frequency divider
--- linux-4.4.0.orig/drivers/pwm/pwm-tiehrpwm.c
+++ linux-4.4.0/drivers/pwm/pwm-tiehrpwm.c
@@ -384,6 +384,10 @@
 		aqcsfrc_mask = AQCSFRC_CSFA_MASK;
 	}
 
+	/* Update shadow register first before modifying active register */
+	ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,
+		      AQSFRC_RLDCSF_ZRO);
+	ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
 	/*
 	 * Changes to immediate action on Action Qualifier. This puts
 	 * Action Qualifier control on PWM output from next TBCLK
--- linux-4.4.0.orig/drivers/pwm/sysfs.c
+++ linux-4.4.0/drivers/pwm/sysfs.c
@@ -340,14 +340,22 @@
 void pwmchip_sysfs_unexport(struct pwm_chip *chip)
 {
 	struct device *parent;
+	unsigned int i;
 
 	parent = class_find_device(&pwm_class, NULL, chip,
 				   pwmchip_sysfs_match);
-	if (parent) {
-		/* for class_find_device() */
-		put_device(parent);
-		device_unregister(parent);
+	if (!parent)
+		return;
+
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
+
+		if (test_bit(PWMF_EXPORTED, &pwm->flags))
+			pwm_unexport_child(parent, pwm);
 	}
+
+	put_device(parent);
+	device_unregister(parent);
 }
 
 static int __init pwm_sysfs_init(void)
--- linux-4.4.0.orig/drivers/rapidio/Kconfig
+++ linux-4.4.0/drivers/rapidio/Kconfig
@@ -25,7 +25,7 @@
 config RAPIDIO_DMA_ENGINE
 	bool "DMA Engine support for RapidIO"
 	depends on RAPIDIO
-	select DMADEVICES
+	depends on DMADEVICES
 	select DMA_ENGINE
 	help
 	  Say Y here if you want to use DMA Engine frameork for RapidIO data
--- linux-4.4.0.orig/drivers/regulator/Kconfig
+++ linux-4.4.0/drivers/regulator/Kconfig
@@ -446,6 +446,7 @@
 config REGULATOR_MT6311
 	tristate "MediaTek MT6311 PMIC"
 	depends on I2C
+	select REGMAP_I2C
 	help
 	  Say y here to select this option to enable the power regulator of
 	  MediaTek MT6311 PMIC.
--- linux-4.4.0.orig/drivers/regulator/act8865-regulator.c
+++ linux-4.4.0/drivers/regulator/act8865-regulator.c
@@ -131,7 +131,7 @@
  * ACT8865 voltage number
  */
 #define	ACT8865_VOLTAGE_NUM	64
-#define ACT8600_SUDCDC_VOLTAGE_NUM	255
+#define ACT8600_SUDCDC_VOLTAGE_NUM	256
 
 struct act8865 {
 	struct regmap *regmap;
@@ -154,7 +154,8 @@
 	REGULATOR_LINEAR_RANGE(3000000, 0, 63, 0),
 	REGULATOR_LINEAR_RANGE(3000000, 64, 159, 100000),
 	REGULATOR_LINEAR_RANGE(12600000, 160, 191, 200000),
-	REGULATOR_LINEAR_RANGE(19000000, 191, 255, 400000),
+	REGULATOR_LINEAR_RANGE(19000000, 192, 247, 400000),
+	REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0),
 };
 
 static struct regulator_ops act8865_ops = {
--- linux-4.4.0.orig/drivers/regulator/anatop-regulator.c
+++ linux-4.4.0/drivers/regulator/anatop-regulator.c
@@ -296,7 +296,12 @@
 		if (!sreg->sel && !strcmp(sreg->name, "vddpu"))
 			sreg->sel = 22;
 
-		if (!sreg->sel) {
+		/* set the default voltage of the pcie phy to be 1.100v */
+		if (!sreg->sel && rdesc->name &&
+		    !strcmp(rdesc->name, "vddpcie"))
+			sreg->sel = 0x10;
+
+		if (!sreg->bypass && !sreg->sel) {
 			dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n");
 			return -EINVAL;
 		}
--- linux-4.4.0.orig/drivers/regulator/axp20x-regulator.c
+++ linux-4.4.0/drivers/regulator/axp20x-regulator.c
@@ -27,8 +27,8 @@
 #define AXP20X_IO_ENABLED		0x03
 #define AXP20X_IO_DISABLED		0x07
 
-#define AXP22X_IO_ENABLED		0x04
-#define AXP22X_IO_DISABLED		0x03
+#define AXP22X_IO_ENABLED		0x03
+#define AXP22X_IO_DISABLED		0x04
 
 #define AXP20X_WORKMODE_DCDC2_MASK	BIT(2)
 #define AXP20X_WORKMODE_DCDC3_MASK	BIT(1)
@@ -221,10 +221,10 @@
 		 AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
 	AXP_DESC(AXP22X, ELDO3, "eldo3", "eldoin", 700, 3300, 100,
 		 AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
-	AXP_DESC_IO(AXP22X, LDO_IO0, "ldo_io0", "ips", 1800, 3300, 100,
+	AXP_DESC_IO(AXP22X, LDO_IO0, "ldo_io0", "ips", 700, 3300, 100,
 		    AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
 		    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
-	AXP_DESC_IO(AXP22X, LDO_IO1, "ldo_io1", "ips", 1800, 3300, 100,
+	AXP_DESC_IO(AXP22X, LDO_IO1, "ldo_io1", "ips", 700, 3300, 100,
 		    AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
 		    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
 	AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000),
@@ -279,7 +279,7 @@
 static int axp20x_regulator_parse_dt(struct platform_device *pdev)
 {
 	struct device_node *np, *regulators;
-	int ret;
+	int ret = 0;
 	u32 dcdcfreq = 0;
 
 	np = of_node_get(pdev->dev.parent->of_node);
@@ -294,13 +294,12 @@
 		ret = axp20x_set_dcdc_freq(pdev, dcdcfreq);
 		if (ret < 0) {
 			dev_err(&pdev->dev, "Error setting dcdc frequency: %d\n", ret);
-			return ret;
 		}
-
 		of_node_put(regulators);
 	}
 
-	return 0;
+	of_node_put(np);
+	return ret;
 }
 
 static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
--- linux-4.4.0.orig/drivers/regulator/core.c
+++ linux-4.4.0/drivers/regulator/core.c
@@ -132,24 +132,24 @@
 	return has_full_constraints || of_have_populated_dt();
 }
 
+static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
+{
+	if (rdev && rdev->supply)
+		return rdev->supply->rdev;
+
+	return NULL;
+}
+
 /**
  * regulator_lock_supply - lock a regulator and its supplies
  * @rdev:         regulator source
  */
 static void regulator_lock_supply(struct regulator_dev *rdev)
 {
-	struct regulator *supply;
-	int i = 0;
-
-	while (1) {
-		mutex_lock_nested(&rdev->mutex, i++);
-		supply = rdev->supply;
-
-		if (!rdev->supply)
-			return;
+	int i;
 
-		rdev = supply->rdev;
-	}
+	for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++)
+		mutex_lock_nested(&rdev->mutex, i);
 }
 
 /**
@@ -1057,18 +1057,18 @@
 
 	ret = machine_constraints_voltage(rdev, rdev->constraints);
 	if (ret != 0)
-		goto out;
+		return ret;
 
 	ret = machine_constraints_current(rdev, rdev->constraints);
 	if (ret != 0)
-		goto out;
+		return ret;
 
 	if (rdev->constraints->ilim_uA && ops->set_input_current_limit) {
 		ret = ops->set_input_current_limit(rdev,
 						   rdev->constraints->ilim_uA);
 		if (ret < 0) {
 			rdev_err(rdev, "failed to set input limit\n");
-			goto out;
+			return ret;
 		}
 	}
 
@@ -1077,21 +1077,20 @@
 		ret = suspend_prepare(rdev, rdev->constraints->initial_state);
 		if (ret < 0) {
 			rdev_err(rdev, "failed to set suspend state\n");
-			goto out;
+			return ret;
 		}
 	}
 
 	if (rdev->constraints->initial_mode) {
 		if (!ops->set_mode) {
 			rdev_err(rdev, "no set_mode operation\n");
-			ret = -EINVAL;
-			goto out;
+			return -EINVAL;
 		}
 
 		ret = ops->set_mode(rdev, rdev->constraints->initial_mode);
 		if (ret < 0) {
 			rdev_err(rdev, "failed to set initial mode: %d\n", ret);
-			goto out;
+			return ret;
 		}
 	}
 
@@ -1102,7 +1101,7 @@
 		ret = _regulator_do_enable(rdev);
 		if (ret < 0 && ret != -EINVAL) {
 			rdev_err(rdev, "failed to enable\n");
-			goto out;
+			return ret;
 		}
 	}
 
@@ -1111,7 +1110,7 @@
 		ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
 		if (ret < 0) {
 			rdev_err(rdev, "failed to set ramp_delay\n");
-			goto out;
+			return ret;
 		}
 	}
 
@@ -1119,7 +1118,7 @@
 		ret = ops->set_pull_down(rdev);
 		if (ret < 0) {
 			rdev_err(rdev, "failed to set pull down\n");
-			goto out;
+			return ret;
 		}
 	}
 
@@ -1127,7 +1126,7 @@
 		ret = ops->set_soft_start(rdev);
 		if (ret < 0) {
 			rdev_err(rdev, "failed to set soft start\n");
-			goto out;
+			return ret;
 		}
 	}
 
@@ -1136,16 +1135,12 @@
 		ret = ops->set_over_current_protection(rdev);
 		if (ret < 0) {
 			rdev_err(rdev, "failed to set over current protection\n");
-			goto out;
+			return ret;
 		}
 	}
 
 	print_constraints(rdev);
 	return 0;
-out:
-	kfree(rdev->constraints);
-	rdev->constraints = NULL;
-	return ret;
 }
 
 /**
@@ -1519,6 +1514,7 @@
 		ret = regulator_enable(rdev->supply);
 		if (ret < 0) {
 			_regulator_put(rdev->supply);
+			rdev->supply = NULL;
 			return ret;
 		}
 	}
@@ -3982,7 +3978,7 @@
 
 scrub:
 	regulator_ena_gpio_free(rdev);
-	kfree(rdev->constraints);
+
 wash:
 	device_unregister(&rdev->dev);
 	/* device core frees rdev */
@@ -4273,12 +4269,13 @@
 	seq_puts(s, "\n");
 
 	list_for_each_entry(consumer, &rdev->consumer_list, list) {
-		if (consumer->dev->class == &regulator_class)
+		if (consumer->dev && consumer->dev->class == &regulator_class)
 			continue;
 
 		seq_printf(s, "%*s%-*s ",
 			   (level + 1) * 3 + 1, "",
-			   30 - (level + 1) * 3, dev_name(consumer->dev));
+			   30 - (level + 1) * 3,
+			   consumer->dev ? dev_name(consumer->dev) : "deviceless");
 
 		switch (rdev->desc->type) {
 		case REGULATOR_VOLTAGE:
--- linux-4.4.0.orig/drivers/regulator/fan53555.c
+++ linux-4.4.0/drivers/regulator/fan53555.c
@@ -434,7 +434,10 @@
 		.name = "fan53555",
 		.driver_data = FAN53555_VENDOR_FAIRCHILD
 	}, {
-		.name = "syr82x",
+		.name = "syr827",
+		.driver_data = FAN53555_VENDOR_SILERGY
+	}, {
+		.name = "syr828",
 		.driver_data = FAN53555_VENDOR_SILERGY
 	},
 	{ },
--- linux-4.4.0.orig/drivers/regulator/max8907-regulator.c
+++ linux-4.4.0/drivers/regulator/max8907-regulator.c
@@ -299,7 +299,10 @@
 	memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
 
 	/* Backwards compatibility with MAX8907B; SD1 uses different voltages */
-	regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
+	ret = regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
+	if (ret)
+		return ret;
+
 	if ((val & MAX8907_II2RR_VERSION_MASK) ==
 	    MAX8907_II2RR_VERSION_REV_B) {
 		pmic->desc[MAX8907_SD1].min_uV = 637500;
@@ -336,14 +339,20 @@
 		}
 
 		if (pmic->desc[i].ops == &max8907_ldo_ops) {
-			regmap_read(config.regmap, pmic->desc[i].enable_reg,
+			ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
 				    &val);
+			if (ret)
+				return ret;
+
 			if ((val & MAX8907_MASK_LDO_SEQ) !=
 			    MAX8907_MASK_LDO_SEQ)
 				pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
 		} else if (pmic->desc[i].ops == &max8907_out5v_ops) {
-			regmap_read(config.regmap, pmic->desc[i].enable_reg,
+			ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
 				    &val);
+			if (ret)
+				return ret;
+
 			if ((val & (MAX8907_MASK_OUT5V_VINEN |
 						MAX8907_MASK_OUT5V_ENSRC)) !=
 			    MAX8907_MASK_OUT5V_ENSRC)
--- linux-4.4.0.orig/drivers/regulator/of_regulator.c
+++ linux-4.4.0/drivers/regulator/of_regulator.c
@@ -274,6 +274,7 @@
 				dev_err(dev,
 					"failed to parse DT for regulator %s\n",
 					child->name);
+				of_node_put(child);
 				return -EINVAL;
 			}
 			match->of_node = of_node_get(child);
--- linux-4.4.0.orig/drivers/regulator/palmas-regulator.c
+++ linux-4.4.0/drivers/regulator/palmas-regulator.c
@@ -435,13 +435,16 @@
 static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
 {
 	int id = rdev_get_id(dev);
+	int ret;
 	struct palmas_pmic *pmic = rdev_get_drvdata(dev);
 	struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata;
 	struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
 	unsigned int reg;
 	bool rail_enable = true;
 
-	palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, &reg);
+	ret = palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, &reg);
+	if (ret)
+		return ret;
 
 	reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
 
--- linux-4.4.0.orig/drivers/regulator/pfuze100-regulator.c
+++ linux-4.4.0/drivers/regulator/pfuze100-regulator.c
@@ -152,6 +152,7 @@
 static struct regulator_ops pfuze100_swb_regulator_ops = {
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
 	.list_voltage = regulator_list_voltage_table,
 	.map_voltage = regulator_map_voltage_ascend,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -608,7 +609,13 @@
 
 		/* SW2~SW4 high bit check and modify the voltage value table */
 		if (i >= sw_check_start && i <= sw_check_end) {
-			regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
+			ret = regmap_read(pfuze_chip->regmap,
+						desc->vsel_reg, &val);
+			if (ret) {
+				dev_err(&client->dev, "Fails to read from the register.\n");
+				return ret;
+			}
+
 			if (val & sw_hi) {
 				if (pfuze_chip->chip_id == PFUZE3000) {
 					desc->volt_table = pfuze3000_sw2hi;
--- linux-4.4.0.orig/drivers/regulator/qcom_smd-regulator.c
+++ linux-4.4.0/drivers/regulator/qcom_smd-regulator.c
@@ -166,29 +166,30 @@
 static const struct regulator_desc pm8841_ftsmps = {
 	.linear_ranges = (struct regulator_linear_range[]) {
 		REGULATOR_LINEAR_RANGE(350000,  0, 184, 5000),
-		REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
+		REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000),
 	},
 	.n_linear_ranges = 2,
-	.n_voltages = 340,
+	.n_voltages = 262,
 	.ops = &rpm_smps_ldo_ops,
 };
 
 static const struct regulator_desc pm8941_boost = {
 	.linear_ranges = (struct regulator_linear_range[]) {
-		REGULATOR_LINEAR_RANGE(4000000, 0, 15, 100000),
+		REGULATOR_LINEAR_RANGE(4000000, 0, 30, 50000),
 	},
 	.n_linear_ranges = 1,
-	.n_voltages = 16,
+	.n_voltages = 31,
 	.ops = &rpm_smps_ldo_ops,
 };
 
 static const struct regulator_desc pm8941_pldo = {
 	.linear_ranges = (struct regulator_linear_range[]) {
-		REGULATOR_LINEAR_RANGE( 750000,  0,  30, 25000),
-		REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
+		REGULATOR_LINEAR_RANGE( 750000,  0,  63, 12500),
+		REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000),
+		REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000),
 	},
-	.n_linear_ranges = 2,
-	.n_voltages = 100,
+	.n_linear_ranges = 3,
+	.n_voltages = 164,
 	.ops = &rpm_smps_ldo_ops,
 };
 
--- linux-4.4.0.orig/drivers/regulator/qcom_spmi-regulator.c
+++ linux-4.4.0/drivers/regulator/qcom_spmi-regulator.c
@@ -1050,6 +1050,8 @@
 	.set_pull_down		= spmi_regulator_common_set_pull_down,
 	.set_soft_start		= spmi_regulator_common_set_soft_start,
 	.set_over_current_protection = spmi_regulator_vs_ocp,
+	.set_mode		= spmi_regulator_common_set_mode,
+	.get_mode		= spmi_regulator_common_get_mode,
 };
 
 static struct regulator_ops spmi_boost_ops = {
@@ -1440,6 +1442,7 @@
 	{ "s1", 0x1400, "vdd_s1", },
 	{ "s2", 0x1700, "vdd_s2", },
 	{ "s3", 0x1a00, "vdd_s3", },
+	{ "s4", 0xa000, },
 	{ "l1", 0x4000, "vdd_l1_l3", },
 	{ "l2", 0x4100, "vdd_l2_lvs_1_2_3", },
 	{ "l3", 0x4200, "vdd_l1_l3", },
@@ -1467,8 +1470,8 @@
 	{ "lvs1", 0x8000, "vdd_l2_lvs_1_2_3", },
 	{ "lvs2", 0x8100, "vdd_l2_lvs_1_2_3", },
 	{ "lvs3", 0x8200, "vdd_l2_lvs_1_2_3", },
-	{ "mvs1", 0x8300, "vin_5vs", },
-	{ "mvs2", 0x8400, "vin_5vs", },
+	{ "5vs1", 0x8300, "vin_5vs", "ocp-5vs1", },
+	{ "5vs2", 0x8400, "vin_5vs", "ocp-5vs2", },
 	{ }
 };
 
--- linux-4.4.0.orig/drivers/regulator/rk808-regulator.c
+++ linux-4.4.0/drivers/regulator/rk808-regulator.c
@@ -551,7 +551,7 @@
 		}
 
 		if (!pdata->dvs_gpio[i]) {
-			dev_warn(dev, "there is no dvs%d gpio\n", i);
+			dev_info(dev, "there is no dvs%d gpio\n", i);
 			continue;
 		}
 
--- linux-4.4.0.orig/drivers/regulator/rn5t618-regulator.c
+++ linux-4.4.0/drivers/regulator/rn5t618-regulator.c
@@ -95,6 +95,7 @@
 
 module_platform_driver(rn5t618_regulator_driver);
 
+MODULE_ALIAS("platform:rn5t618-regulator");
 MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
 MODULE_DESCRIPTION("RN5T618 regulator driver");
 MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/regulator/s2mpa01.c
+++ linux-4.4.0/drivers/regulator/s2mpa01.c
@@ -303,13 +303,13 @@
 	regulator_desc_ldo(2, STEP_50_MV),
 	regulator_desc_ldo(3, STEP_50_MV),
 	regulator_desc_ldo(4, STEP_50_MV),
-	regulator_desc_ldo(5, STEP_50_MV),
+	regulator_desc_ldo(5, STEP_25_MV),
 	regulator_desc_ldo(6, STEP_25_MV),
 	regulator_desc_ldo(7, STEP_50_MV),
 	regulator_desc_ldo(8, STEP_50_MV),
 	regulator_desc_ldo(9, STEP_50_MV),
 	regulator_desc_ldo(10, STEP_50_MV),
-	regulator_desc_ldo(11, STEP_25_MV),
+	regulator_desc_ldo(11, STEP_50_MV),
 	regulator_desc_ldo(12, STEP_50_MV),
 	regulator_desc_ldo(13, STEP_50_MV),
 	regulator_desc_ldo(14, STEP_50_MV),
@@ -320,11 +320,11 @@
 	regulator_desc_ldo(19, STEP_50_MV),
 	regulator_desc_ldo(20, STEP_50_MV),
 	regulator_desc_ldo(21, STEP_50_MV),
-	regulator_desc_ldo(22, STEP_25_MV),
-	regulator_desc_ldo(23, STEP_25_MV),
+	regulator_desc_ldo(22, STEP_50_MV),
+	regulator_desc_ldo(23, STEP_50_MV),
 	regulator_desc_ldo(24, STEP_50_MV),
 	regulator_desc_ldo(25, STEP_50_MV),
-	regulator_desc_ldo(26, STEP_50_MV),
+	regulator_desc_ldo(26, STEP_25_MV),
 	regulator_desc_buck1_4(1),
 	regulator_desc_buck1_4(2),
 	regulator_desc_buck1_4(3),
--- linux-4.4.0.orig/drivers/regulator/s2mps11.c
+++ linux-4.4.0/drivers/regulator/s2mps11.c
@@ -305,7 +305,7 @@
 	.enable_mask	= S2MPS11_ENABLE_MASK			\
 }
 
-#define regulator_desc_s2mps11_buck6_10(num, min, step) {	\
+#define regulator_desc_s2mps11_buck67810(num, min, step) {	\
 	.name		= "BUCK"#num,				\
 	.id		= S2MPS11_BUCK##num,			\
 	.ops		= &s2mps11_buck_ops,			\
@@ -321,6 +321,22 @@
 	.enable_mask	= S2MPS11_ENABLE_MASK			\
 }
 
+#define regulator_desc_s2mps11_buck9 {				\
+	.name		= "BUCK9",				\
+	.id		= S2MPS11_BUCK9,			\
+	.ops		= &s2mps11_buck_ops,			\
+	.type		= REGULATOR_VOLTAGE,			\
+	.owner		= THIS_MODULE,				\
+	.min_uV		= MIN_3000_MV,				\
+	.uV_step	= STEP_25_MV,				\
+	.n_voltages	= S2MPS11_BUCK9_N_VOLTAGES,		\
+	.ramp_delay	= S2MPS11_RAMP_DELAY,			\
+	.vsel_reg	= S2MPS11_REG_B9CTRL2,			\
+	.vsel_mask	= S2MPS11_BUCK9_VSEL_MASK,		\
+	.enable_reg	= S2MPS11_REG_B9CTRL1,			\
+	.enable_mask	= S2MPS11_ENABLE_MASK			\
+}
+
 static const struct regulator_desc s2mps11_regulators[] = {
 	regulator_desc_s2mps11_ldo(1, STEP_25_MV),
 	regulator_desc_s2mps11_ldo(2, STEP_50_MV),
@@ -356,7 +372,7 @@
 	regulator_desc_s2mps11_ldo(32, STEP_50_MV),
 	regulator_desc_s2mps11_ldo(33, STEP_50_MV),
 	regulator_desc_s2mps11_ldo(34, STEP_50_MV),
-	regulator_desc_s2mps11_ldo(35, STEP_50_MV),
+	regulator_desc_s2mps11_ldo(35, STEP_25_MV),
 	regulator_desc_s2mps11_ldo(36, STEP_50_MV),
 	regulator_desc_s2mps11_ldo(37, STEP_50_MV),
 	regulator_desc_s2mps11_ldo(38, STEP_50_MV),
@@ -365,11 +381,11 @@
 	regulator_desc_s2mps11_buck1_4(3),
 	regulator_desc_s2mps11_buck1_4(4),
 	regulator_desc_s2mps11_buck5,
-	regulator_desc_s2mps11_buck6_10(6, MIN_600_MV, STEP_6_25_MV),
-	regulator_desc_s2mps11_buck6_10(7, MIN_600_MV, STEP_6_25_MV),
-	regulator_desc_s2mps11_buck6_10(8, MIN_600_MV, STEP_6_25_MV),
-	regulator_desc_s2mps11_buck6_10(9, MIN_3000_MV, STEP_25_MV),
-	regulator_desc_s2mps11_buck6_10(10, MIN_750_MV, STEP_12_5_MV),
+	regulator_desc_s2mps11_buck67810(6, MIN_600_MV, STEP_6_25_MV),
+	regulator_desc_s2mps11_buck67810(7, MIN_750_MV, STEP_12_5_MV),
+	regulator_desc_s2mps11_buck67810(8, MIN_750_MV, STEP_12_5_MV),
+	regulator_desc_s2mps11_buck9,
+	regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV),
 };
 
 static struct regulator_ops s2mps14_reg_ops;
--- linux-4.4.0.orig/drivers/regulator/s5m8767.c
+++ linux-4.4.0/drivers/regulator/s5m8767.c
@@ -202,9 +202,10 @@
 		}
 	}
 
-	if (i < s5m8767->num_regulators)
-		*enable_ctrl =
-		s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
+	if (i >= s5m8767->num_regulators)
+		return -EINVAL;
+
+	*enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
 
 	return 0;
 }
@@ -937,8 +938,12 @@
 			else
 				regulators[id].vsel_mask = 0xff;
 
-			s5m8767_get_register(s5m8767, id, &enable_reg,
+			ret = s5m8767_get_register(s5m8767, id, &enable_reg,
 					     &enable_val);
+			if (ret) {
+				dev_err(s5m8767->dev, "error reading registers\n");
+				return ret;
+			}
 			regulators[id].enable_reg = enable_reg;
 			regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
 			regulators[id].enable_val = enable_val;
--- linux-4.4.0.orig/drivers/regulator/stw481x-vmmc.c
+++ linux-4.4.0/drivers/regulator/stw481x-vmmc.c
@@ -47,7 +47,8 @@
 	.volt_table = stw481x_vmmc_voltages,
 	.enable_time = 200, /* FIXME: look this up */
 	.enable_reg = STW_CONF1,
-	.enable_mask = STW_CONF1_PDN_VMMC,
+	.enable_mask = STW_CONF1_PDN_VMMC | STW_CONF1_MMC_LS_STATUS,
+	.enable_val = STW_CONF1_PDN_VMMC,
 	.vsel_reg = STW_CONF1,
 	.vsel_mask = STW_CONF1_VMMC_MASK,
 };
--- linux-4.4.0.orig/drivers/regulator/ti-abb-regulator.c
+++ linux-4.4.0/drivers/regulator/ti-abb-regulator.c
@@ -173,19 +173,14 @@
 	while (timeout++ <= abb->settling_time) {
 		status = ti_abb_check_txdone(abb);
 		if (status)
-			break;
+			return 0;
 
 		udelay(1);
 	}
 
-	if (timeout > abb->settling_time) {
-		dev_warn_ratelimited(dev,
-				     "%s:TRANXDONE timeout(%duS) int=0x%08x\n",
-				     __func__, timeout, readl(abb->int_base));
-		return -ETIMEDOUT;
-	}
-
-	return 0;
+	dev_warn_ratelimited(dev, "%s:TRANXDONE timeout(%duS) int=0x%08x\n",
+			     __func__, timeout, readl(abb->int_base));
+	return -ETIMEDOUT;
 }
 
 /**
@@ -205,19 +200,14 @@
 
 		status = ti_abb_check_txdone(abb);
 		if (!status)
-			break;
+			return 0;
 
 		udelay(1);
 	}
 
-	if (timeout > abb->settling_time) {
-		dev_warn_ratelimited(dev,
-				     "%s:TRANXDONE timeout(%duS) int=0x%08x\n",
-				     __func__, timeout, readl(abb->int_base));
-		return -ETIMEDOUT;
-	}
-
-	return 0;
+	dev_warn_ratelimited(dev, "%s:TRANXDONE timeout(%duS) int=0x%08x\n",
+			     __func__, timeout, readl(abb->int_base));
+	return -ETIMEDOUT;
 }
 
 /**
@@ -352,8 +342,17 @@
 		return ret;
 	}
 
-	/* If data is exactly the same, then just update index, no change */
 	info = &abb->info[sel];
+	/*
+	 * When Linux kernel is starting up, we are'nt sure of the
+	 * Bias configuration that bootloader has configured.
+	 * So, we get to know the actual setting the first time
+	 * we are asked to transition.
+	 */
+	if (abb->current_info_idx == -EINVAL)
+		goto just_set_abb;
+
+	/* If data is exactly the same, then just update index, no change */
 	oinfo = &abb->info[abb->current_info_idx];
 	if (!memcmp(info, oinfo, sizeof(*info))) {
 		dev_dbg(dev, "%s: Same data new idx=%d, old idx=%d\n", __func__,
@@ -361,6 +360,7 @@
 		goto out;
 	}
 
+just_set_abb:
 	ret = ti_abb_set_opp(rdev, abb, info);
 
 out:
--- linux-4.4.0.orig/drivers/regulator/tps65023-regulator.c
+++ linux-4.4.0/drivers/regulator/tps65023-regulator.c
@@ -311,8 +311,7 @@
 
 	/* Enable setting output voltage by I2C */
 	regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
-					TPS65023_REG_CTRL2_CORE_ADJ,
-					TPS65023_REG_CTRL2_CORE_ADJ);
+			   TPS65023_REG_CTRL2_CORE_ADJ, 0);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/regulator/tps65910-regulator.c
+++ linux-4.4.0/drivers/regulator/tps65910-regulator.c
@@ -1102,8 +1102,10 @@
 	platform_set_drvdata(pdev, pmic);
 
 	/* Give control of all register to control port */
-	tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL,
+	err = tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL,
 				DEVCTRL_SR_CTL_I2C_SEL_MASK);
+	if (err < 0)
+		return err;
 
 	switch (tps65910_chip_id(tps65910)) {
 	case TPS65910:
@@ -1111,6 +1113,12 @@
 		pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
 		pmic->ext_sleep_control = tps65910_ext_sleep_control;
 		info = tps65910_regs;
+		/* Work around silicon erratum SWCZ010: output programmed
+		 * voltage level can go higher than expected or crash
+		 * Workaround: use no synchronization of DCDC clocks
+		 */
+		tps65910_reg_clear_bits(pmic->mfd, TPS65910_DCDCCTRL,
+					DCDCCTRL_DCDCCKSYNC_MASK);
 		break;
 	case TPS65911:
 		pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
--- linux-4.4.0.orig/drivers/regulator/wm831x-dcdc.c
+++ linux-4.4.0/drivers/regulator/wm831x-dcdc.c
@@ -327,8 +327,8 @@
 }
 
 /* Current limit options */
-static u16 wm831x_dcdc_ilim[] = {
-	125, 250, 375, 500, 625, 750, 875, 1000
+static const unsigned int wm831x_dcdc_ilim[] = {
+	125000, 250000, 375000, 500000, 625000, 750000, 875000, 1000000
 };
 
 static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev,
--- linux-4.4.0.orig/drivers/remoteproc/remoteproc_core.c
+++ linux-4.4.0/drivers/remoteproc/remoteproc_core.c
@@ -288,7 +288,7 @@
 {
 	int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
 	struct rproc *rproc = rvring->rvdev->rproc;
-	int idx = rvring->rvdev->vring - rvring;
+	int idx = rvring - rvring->rvdev->vring;
 	struct fw_rsc_vdev *rsc;
 
 	dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
@@ -1239,11 +1239,6 @@
 	if (ret < 0)
 		return ret;
 
-	/* expose to rproc_get_by_phandle users */
-	mutex_lock(&rproc_list_mutex);
-	list_add(&rproc->node, &rproc_list);
-	mutex_unlock(&rproc_list_mutex);
-
 	dev_info(dev, "%s is available\n", rproc->name);
 
 	dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n");
@@ -1251,8 +1246,16 @@
 
 	/* create debugfs entries */
 	rproc_create_debug_dir(rproc);
+	ret = rproc_add_virtio_devices(rproc);
+	if (ret < 0)
+		return ret;
 
-	return rproc_add_virtio_devices(rproc);
+	/* expose to rproc_get_by_phandle users */
+	mutex_lock(&rproc_list_mutex);
+	list_add(&rproc->node, &rproc_list);
+	mutex_unlock(&rproc_list_mutex);
+
+	return 0;
 }
 EXPORT_SYMBOL(rproc_add);
 
@@ -1474,7 +1477,7 @@
 
 	return 0;
 }
-module_init(remoteproc_init);
+subsys_initcall(remoteproc_init);
 
 static void __exit remoteproc_exit(void)
 {
--- linux-4.4.0.orig/drivers/rtc/Kconfig
+++ linux-4.4.0/drivers/rtc/Kconfig
@@ -278,6 +278,7 @@
 config RTC_DRV_MAX8907
 	tristate "Maxim MAX8907"
 	depends on MFD_MAX8907
+	select REGMAP_IRQ
 	help
 	  If you say yes here you will get support for the
 	  RTC of Maxim MAX8907 PMIC.
--- linux-4.4.0.orig/drivers/rtc/hctosys.c
+++ linux-4.4.0/drivers/rtc/hctosys.c
@@ -49,6 +49,13 @@
 
 	tv64.tv_sec = rtc_tm_to_time64(&tm);
 
+#if BITS_PER_LONG == 32
+	if (tv64.tv_sec > INT_MAX) {
+		err = -ERANGE;
+		goto err_read;
+	}
+#endif
+
 	err = do_settimeofday64(&tv64);
 
 	dev_info(rtc->dev.parent,
--- linux-4.4.0.orig/drivers/rtc/interface.c
+++ linux-4.4.0/drivers/rtc/interface.c
@@ -217,6 +217,13 @@
 			missing = year;
 	}
 
+	/* Can't proceed if alarm is still invalid after replacing
+	 * missing fields.
+	 */
+	err = rtc_valid_tm(&alarm->time);
+	if (err)
+		goto done;
+
 	/* with luck, no rollover is needed */
 	t_now = rtc_tm_to_time64(&now);
 	t_alm = rtc_tm_to_time64(&alarm->time);
@@ -268,9 +275,9 @@
 		dev_warn(&rtc->dev, "alarm rollover not handled\n");
 	}
 
-done:
 	err = rtc_valid_tm(&alarm->time);
 
+done:
 	if (err) {
 		dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
 			alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
@@ -342,6 +349,11 @@
 {
 	int err;
 
+	if (!rtc->ops)
+		return -ENODEV;
+	else if (!rtc->ops->set_alarm)
+		return -EINVAL;
+
 	err = rtc_valid_tm(&alarm->time);
 	if (err != 0)
 		return err;
@@ -748,9 +760,23 @@
  */
 static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
 {
+	struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
+	struct rtc_time tm;
+	ktime_t now;
+
 	timer->enabled = 1;
+	__rtc_read_time(rtc, &tm);
+	now = rtc_tm_to_ktime(tm);
+
+	/* Skip over expired timers */
+	while (next) {
+		if (next->expires.tv64 >= now.tv64)
+			break;
+		next = timerqueue_iterate_next(next);
+	}
+
 	timerqueue_add(&rtc->timerqueue, &timer->node);
-	if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
+	if (!next || ktime_before(timer->node.expires, next->expires)) {
 		struct rtc_wkalrm alarm;
 		int err;
 		alarm.time = rtc_ktime_to_tm(timer->node.expires);
--- linux-4.4.0.orig/drivers/rtc/rtc-88pm80x.c
+++ linux-4.4.0/drivers/rtc/rtc-88pm80x.c
@@ -116,12 +116,14 @@
 	unsigned char buf[4];
 	unsigned long ticks, base, data;
 	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
-	base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
 
 	/* load 32-bit read-only counter */
 	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
-	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	ticks = base + data;
 	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
 		base, data, ticks);
@@ -144,7 +146,8 @@
 
 	/* load 32-bit read-only counter */
 	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
-	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	base = ticks - data;
 	dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
 		base, data, ticks);
@@ -165,11 +168,13 @@
 	int ret;
 
 	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
-	base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
 
 	regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4);
-	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	ticks = base + data;
 	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
 		base, data, ticks);
@@ -192,12 +197,14 @@
 	regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0);
 
 	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
-	base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
 
 	/* load 32-bit read-only counter */
 	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
-	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	ticks = base + data;
 	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
 		base, data, ticks);
--- linux-4.4.0.orig/drivers/rtc/rtc-88pm860x.c
+++ linux-4.4.0/drivers/rtc/rtc-88pm860x.c
@@ -115,11 +115,13 @@
 	pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
 	dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
 		buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
-	base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+	base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) |
+		(buf[5] << 8) | buf[7];
 
 	/* load 32-bit read-only counter */
 	pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
-	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	ticks = base + data;
 	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
 		base, data, ticks);
@@ -145,7 +147,8 @@
 
 	/* load 32-bit read-only counter */
 	pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
-	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	base = ticks - data;
 	dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
 		base, data, ticks);
@@ -170,10 +173,12 @@
 	pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
 	dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
 		buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
-	base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+	base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) |
+		(buf[5] << 8) | buf[7];
 
 	pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
-	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	ticks = base + data;
 	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
 		base, data, ticks);
@@ -198,11 +203,13 @@
 	pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
 	dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
 		buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
-	base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+	base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) |
+		(buf[5] << 8) | buf[7];
 
 	/* load 32-bit read-only counter */
 	pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
-	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+		(buf[1] << 8) | buf[0];
 	ticks = base + data;
 	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
 		base, data, ticks);
@@ -414,7 +421,7 @@
 	struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
 
 #ifdef VRTC_CALIBRATION
-	flush_scheduled_work();
+	cancel_delayed_work_sync(&info->calib_work);
 	/* disable measurement */
 	pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
 #endif	/* VRTC_CALIBRATION */
--- linux-4.4.0.orig/drivers/rtc/rtc-bq4802.c
+++ linux-4.4.0/drivers/rtc/rtc-bq4802.c
@@ -164,6 +164,10 @@
 	} else if (p->r->flags & IORESOURCE_MEM) {
 		p->regs = devm_ioremap(&pdev->dev, p->r->start,
 					resource_size(p->r));
+		if (!p->regs){
+			err = -ENOMEM;
+			goto out;
+		}
 		p->read = bq4802_read_mem;
 		p->write = bq4802_write_mem;
 	} else {
--- linux-4.4.0.orig/drivers/rtc/rtc-cmos.c
+++ linux-4.4.0/drivers/rtc/rtc-cmos.c
@@ -41,6 +41,9 @@
 #include <linux/pm.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#ifdef CONFIG_X86
+#include <asm/i8259.h>
+#endif
 
 /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
 #include <asm-generic/rtc.h>
@@ -1058,17 +1061,23 @@
 {
 	cmos_wake_setup(&pnp->dev);
 
-	if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0))
+	if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) {
+		unsigned int irq = 0;
+#ifdef CONFIG_X86
 		/* Some machines contain a PNP entry for the RTC, but
 		 * don't define the IRQ. It should always be safe to
-		 * hardcode it in these cases
+		 * hardcode it on systems with a legacy PIC.
 		 */
+		if (nr_legacy_irqs())
+			irq = 8;
+#endif
 		return cmos_do_probe(&pnp->dev,
-				pnp_get_resource(pnp, IORESOURCE_IO, 0), 8);
-	else
+				pnp_get_resource(pnp, IORESOURCE_IO, 0), irq);
+	} else {
 		return cmos_do_probe(&pnp->dev,
 				pnp_get_resource(pnp, IORESOURCE_IO, 0),
 				pnp_irq(pnp, 0));
+	}
 }
 
 static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
--- linux-4.4.0.orig/drivers/rtc/rtc-da9063.c
+++ linux-4.4.0/drivers/rtc/rtc-da9063.c
@@ -491,6 +491,13 @@
 	da9063_data_to_tm(data, &rtc->alarm_time, rtc);
 	rtc->rtc_sync = false;
 
+	/*
+	 * TODO: some models have alarms on a minute boundary but still support
+	 * real hardware interrupts. Add this once the core supports it.
+	 */
+	if (config->rtc_data_start != RTC_SEC)
+		rtc->rtc_dev->uie_unsupported = 1;
+
 	irq_alarm = platform_get_irq_byname(pdev, "ALARM");
 	ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
 					da9063_alarm_event,
--- linux-4.4.0.orig/drivers/rtc/rtc-ds1374.c
+++ linux-4.4.0/drivers/rtc/rtc-ds1374.c
@@ -527,6 +527,10 @@
 		if (get_user(new_margin, (int __user *)arg))
 			return -EFAULT;
 
+		/* the hardware's tick rate is 4096 Hz, so
+		 * the counter value needs to be scaled accordingly
+		 */
+		new_margin <<= 12;
 		if (new_margin < 1 || new_margin > 16777216)
 			return -EINVAL;
 
@@ -535,7 +539,8 @@
 		ds1374_wdt_ping();
 		/* fallthrough */
 	case WDIOC_GETTIMEOUT:
-		return put_user(wdt_margin, (int __user *)arg);
+		/* when returning ... inverse is true */
+		return put_user((wdt_margin >> 12), (int __user *)arg);
 	case WDIOC_SETOPTIONS:
 		if (copy_from_user(&options, (int __user *)arg, sizeof(int)))
 			return -EFAULT;
@@ -543,14 +548,15 @@
 		if (options & WDIOS_DISABLECARD) {
 			pr_info("disable watchdog\n");
 			ds1374_wdt_disable();
+			return 0;
 		}
 
 		if (options & WDIOS_ENABLECARD) {
 			pr_info("enable watchdog\n");
 			ds1374_wdt_settimeout(wdt_margin);
 			ds1374_wdt_ping();
+			return 0;
 		}
-
 		return -EINVAL;
 	}
 	return -ENOTTY;
--- linux-4.4.0.orig/drivers/rtc/rtc-ds1672.c
+++ linux-4.4.0/drivers/rtc/rtc-ds1672.c
@@ -60,7 +60,8 @@
 		"%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
 		__func__, buf[0], buf[1], buf[2], buf[3]);
 
-	time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	time = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
+	       (buf[1] << 8) | buf[0];
 
 	rtc_time_to_tm(time, tm);
 
--- linux-4.4.0.orig/drivers/rtc/rtc-ds1685.c
+++ linux-4.4.0/drivers/rtc/rtc-ds1685.c
@@ -187,9 +187,9 @@
  * Only use this where you are certain another lock will not be held.
  */
 static inline void
-ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long flags)
+ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long *flags)
 {
-	spin_lock_irqsave(&rtc->lock, flags);
+	spin_lock_irqsave(&rtc->lock, *flags);
 	ds1685_rtc_switch_to_bank1(rtc);
 }
 
@@ -1304,7 +1304,7 @@
 {
 	struct ds1685_priv *rtc = dev_get_drvdata(dev);
 	u8 reg = 0, bit = 0, tmp;
-	unsigned long flags = 0;
+	unsigned long flags;
 	long int val = 0;
 	const struct ds1685_rtc_ctrl_regs *reg_info =
 		ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
@@ -1325,7 +1325,7 @@
 	bit = reg_info->bit;
 
 	/* Safe to spinlock during a write. */
-	ds1685_rtc_begin_ctrl_access(rtc, flags);
+	ds1685_rtc_begin_ctrl_access(rtc, &flags);
 	tmp = rtc->read(rtc, reg);
 	rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit))));
 	ds1685_rtc_end_ctrl_access(rtc, flags);
--- linux-4.4.0.orig/drivers/rtc/rtc-hym8563.c
+++ linux-4.4.0/drivers/rtc/rtc-hym8563.c
@@ -105,7 +105,7 @@
 
 	if (!hym8563->valid) {
 		dev_warn(&client->dev, "no valid clock/calendar values available\n");
-		return -EPERM;
+		return -EINVAL;
 	}
 
 	ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf);
@@ -144,7 +144,7 @@
 	 * it does not seem to carry it over a subsequent write/read.
 	 * So we'll limit ourself to 100 years, starting at 2000 for now.
 	 */
-	buf[6] = tm->tm_year - 100;
+	buf[6] = bin2bcd(tm->tm_year - 100);
 
 	/*
 	 * CTL1 only contains TEST-mode bits apart from stop,
--- linux-4.4.0.orig/drivers/rtc/rtc-lib.c
+++ linux-4.4.0/drivers/rtc/rtc-lib.c
@@ -52,13 +52,11 @@
  */
 void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
 {
-	unsigned int month, year;
-	unsigned long secs;
+	unsigned int month, year, secs;
 	int days;
 
 	/* time must be positive */
-	days = div_s64(time, 86400);
-	secs = time - (unsigned int) days * 86400;
+	days = div_s64_rem(time, 86400, &secs);
 
 	/* day of the week, 1970-01-01 was a Thursday */
 	tm->tm_wday = (days + 4) % 7;
--- linux-4.4.0.orig/drivers/rtc/rtc-max77686.c
+++ linux-4.4.0/drivers/rtc/rtc-max77686.c
@@ -465,7 +465,7 @@
 
 	info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
 					 MAX77686_RTCIRQ_RTCA1);
-	if (!info->virq) {
+	if (info->virq <= 0) {
 		ret = -ENXIO;
 		goto err_rtc;
 	}
--- linux-4.4.0.orig/drivers/rtc/rtc-max8997.c
+++ linux-4.4.0/drivers/rtc/rtc-max8997.c
@@ -221,7 +221,7 @@
 
 out:
 	mutex_unlock(&info->lock);
-	return 0;
+	return ret;
 }
 
 static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info)
--- linux-4.4.0.orig/drivers/rtc/rtc-msm6242.c
+++ linux-4.4.0/drivers/rtc/rtc-msm6242.c
@@ -132,7 +132,8 @@
 		      msm6242_read(priv, MSM6242_SECOND1);
 	tm->tm_min  = msm6242_read(priv, MSM6242_MINUTE10) * 10 +
 		      msm6242_read(priv, MSM6242_MINUTE1);
-	tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10 & 3)) * 10 +
+	tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10) &
+		       MSM6242_HOUR10_HR_MASK) * 10 +
 		      msm6242_read(priv, MSM6242_HOUR1);
 	tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 +
 		      msm6242_read(priv, MSM6242_DAY1);
--- linux-4.4.0.orig/drivers/rtc/rtc-mt6397.c
+++ linux-4.4.0/drivers/rtc/rtc-mt6397.c
@@ -55,6 +55,14 @@
 
 #define RTC_AL_SEC		0x0018
 
+#define RTC_AL_SEC_MASK		0x003f
+#define RTC_AL_MIN_MASK		0x003f
+#define RTC_AL_HOU_MASK		0x001f
+#define RTC_AL_DOM_MASK		0x001f
+#define RTC_AL_DOW_MASK		0x0007
+#define RTC_AL_MTH_MASK		0x000f
+#define RTC_AL_YEA_MASK		0x007f
+
 #define RTC_PDN2		0x002e
 #define RTC_PDN2_PWRON_ALARM	BIT(4)
 
@@ -111,7 +119,7 @@
 		irqen = irqsta & ~RTC_IRQ_EN_AL;
 		mutex_lock(&rtc->lock);
 		if (regmap_write(rtc->regmap, rtc->addr_base + RTC_IRQ_EN,
-				 irqen) < 0)
+				 irqen) == 0)
 			mtk_rtc_write_trigger(rtc);
 		mutex_unlock(&rtc->lock);
 
@@ -233,12 +241,12 @@
 	alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM);
 	mutex_unlock(&rtc->lock);
 
-	tm->tm_sec = data[RTC_OFFSET_SEC];
-	tm->tm_min = data[RTC_OFFSET_MIN];
-	tm->tm_hour = data[RTC_OFFSET_HOUR];
-	tm->tm_mday = data[RTC_OFFSET_DOM];
-	tm->tm_mon = data[RTC_OFFSET_MTH];
-	tm->tm_year = data[RTC_OFFSET_YEAR];
+	tm->tm_sec = data[RTC_OFFSET_SEC] & RTC_AL_SEC_MASK;
+	tm->tm_min = data[RTC_OFFSET_MIN] & RTC_AL_MIN_MASK;
+	tm->tm_hour = data[RTC_OFFSET_HOUR] & RTC_AL_HOU_MASK;
+	tm->tm_mday = data[RTC_OFFSET_DOM] & RTC_AL_DOM_MASK;
+	tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK;
+	tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK;
 
 	tm->tm_year += RTC_MIN_YEAR_OFFSET;
 	tm->tm_mon--;
@@ -259,14 +267,25 @@
 	tm->tm_year -= RTC_MIN_YEAR_OFFSET;
 	tm->tm_mon++;
 
-	data[RTC_OFFSET_SEC] = tm->tm_sec;
-	data[RTC_OFFSET_MIN] = tm->tm_min;
-	data[RTC_OFFSET_HOUR] = tm->tm_hour;
-	data[RTC_OFFSET_DOM] = tm->tm_mday;
-	data[RTC_OFFSET_MTH] = tm->tm_mon;
-	data[RTC_OFFSET_YEAR] = tm->tm_year;
-
 	mutex_lock(&rtc->lock);
+	ret = regmap_bulk_read(rtc->regmap, rtc->addr_base + RTC_AL_SEC,
+			       data, RTC_OFFSET_COUNT);
+	if (ret < 0)
+		goto exit;
+
+	data[RTC_OFFSET_SEC] = ((data[RTC_OFFSET_SEC] & ~(RTC_AL_SEC_MASK)) |
+				(tm->tm_sec & RTC_AL_SEC_MASK));
+	data[RTC_OFFSET_MIN] = ((data[RTC_OFFSET_MIN] & ~(RTC_AL_MIN_MASK)) |
+				(tm->tm_min & RTC_AL_MIN_MASK));
+	data[RTC_OFFSET_HOUR] = ((data[RTC_OFFSET_HOUR] & ~(RTC_AL_HOU_MASK)) |
+				(tm->tm_hour & RTC_AL_HOU_MASK));
+	data[RTC_OFFSET_DOM] = ((data[RTC_OFFSET_DOM] & ~(RTC_AL_DOM_MASK)) |
+				(tm->tm_mday & RTC_AL_DOM_MASK));
+	data[RTC_OFFSET_MTH] = ((data[RTC_OFFSET_MTH] & ~(RTC_AL_MTH_MASK)) |
+				(tm->tm_mon & RTC_AL_MTH_MASK));
+	data[RTC_OFFSET_YEAR] = ((data[RTC_OFFSET_YEAR] & ~(RTC_AL_YEA_MASK)) |
+				(tm->tm_year & RTC_AL_YEA_MASK));
+
 	if (alm->enabled) {
 		ret = regmap_bulk_write(rtc->regmap,
 					rtc->addr_base + RTC_AL_SEC,
--- linux-4.4.0.orig/drivers/rtc/rtc-omap.c
+++ linux-4.4.0/drivers/rtc/rtc-omap.c
@@ -109,6 +109,7 @@
 /* OMAP_RTC_OSC_REG bit fields: */
 #define OMAP_RTC_OSC_32KCLK_EN		BIT(6)
 #define OMAP_RTC_OSC_SEL_32KCLK_SRC	BIT(3)
+#define OMAP_RTC_OSC_OSC32K_GZ_DISABLE	BIT(4)
 
 /* OMAP_RTC_IRQWAKEEN bit fields: */
 #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN	BIT(1)
@@ -646,8 +647,9 @@
 	 */
 	if (rtc->has_ext_clk) {
 		reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
-		rtc_write(rtc, OMAP_RTC_OSC_REG,
-			  reg | OMAP_RTC_OSC_SEL_32KCLK_SRC);
+		reg &= ~OMAP_RTC_OSC_OSC32K_GZ_DISABLE;
+		reg |= OMAP_RTC_OSC_32KCLK_EN | OMAP_RTC_OSC_SEL_32KCLK_SRC;
+		rtc_writel(rtc, OMAP_RTC_OSC_REG, reg);
 	}
 
 	rtc->type->lock(rtc);
--- linux-4.4.0.orig/drivers/rtc/rtc-opal.c
+++ linux-4.4.0/drivers/rtc/rtc-opal.c
@@ -58,6 +58,7 @@
 static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
 {
 	long rc = OPAL_BUSY;
+	int retries = 10;
 	u32 y_m_d;
 	u64 h_m_s_ms;
 	__be32 __y_m_d;
@@ -67,8 +68,11 @@
 		rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms);
 		if (rc == OPAL_BUSY_EVENT)
 			opal_poll_events(NULL);
-		else
+		else if (retries-- && (rc == OPAL_HARDWARE
+				       || rc == OPAL_INTERNAL_ERROR))
 			msleep(10);
+		else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT)
+			break;
 	}
 
 	if (rc != OPAL_SUCCESS)
@@ -84,6 +88,7 @@
 static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm)
 {
 	long rc = OPAL_BUSY;
+	int retries = 10;
 	u32 y_m_d = 0;
 	u64 h_m_s_ms = 0;
 
@@ -92,8 +97,11 @@
 		rc = opal_rtc_write(y_m_d, h_m_s_ms);
 		if (rc == OPAL_BUSY_EVENT)
 			opal_poll_events(NULL);
-		else
+		else if (retries-- && (rc == OPAL_HARDWARE
+				       || rc == OPAL_INTERNAL_ERROR))
 			msleep(10);
+		else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT)
+			break;
 	}
 
 	return rc == OPAL_SUCCESS ? 0 : -EIO;
@@ -142,6 +150,16 @@
 
 	y_m_d = be32_to_cpu(__y_m_d);
 	h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32);
+
+	/* check if no alarm is set */
+	if (y_m_d == 0 && h_m_s_ms == 0) {
+		pr_debug("No alarm is set\n");
+		rc = -ENOENT;
+		goto exit;
+	} else {
+		pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
+	}
+
 	opal_to_tm(y_m_d, h_m_s_ms, &alarm->time);
 
 exit:
--- linux-4.4.0.orig/drivers/rtc/rtc-pcf8563.c
+++ linux-4.4.0/drivers/rtc/rtc-pcf8563.c
@@ -427,7 +427,7 @@
 		return 0;
 
 	buf &= PCF8563_REG_CLKO_F_MASK;
-	return clkout_rates[ret];
+	return clkout_rates[buf];
 }
 
 static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -568,7 +568,6 @@
 	struct pcf8563 *pcf8563;
 	int err;
 	unsigned char buf;
-	unsigned char alm_pending;
 
 	dev_dbg(&client->dev, "%s\n", __func__);
 
@@ -594,13 +593,13 @@
 		return err;
 	}
 
-	err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);
-	if (err) {
-		dev_err(&client->dev, "%s: read error\n", __func__);
+	/* Clear flags and disable interrupts */
+	buf = 0;
+	err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
+	if (err < 0) {
+		dev_err(&client->dev, "%s: write error\n", __func__);
 		return err;
 	}
-	if (alm_pending)
-		pcf8563_set_alarm_mode(client, 0);
 
 	pcf8563->rtc = devm_rtc_device_register(&client->dev,
 				pcf8563_driver.driver.name,
--- linux-4.4.0.orig/drivers/rtc/rtc-pl031.c
+++ linux-4.4.0/drivers/rtc/rtc-pl031.c
@@ -308,7 +308,8 @@
 
 	dev_pm_clear_wake_irq(&adev->dev);
 	device_init_wakeup(&adev->dev, false);
-	free_irq(adev->irq[0], ldata);
+	if (adev->irq[0])
+		free_irq(adev->irq[0], ldata);
 	rtc_device_unregister(ldata->rtc);
 	iounmap(ldata->base);
 	kfree(ldata);
@@ -381,12 +382,13 @@
 		goto out_no_rtc;
 	}
 
-	if (request_irq(adev->irq[0], pl031_interrupt,
-			vendor->irqflags, "rtc-pl031", ldata)) {
-		ret = -EIO;
-		goto out_no_irq;
+	if (adev->irq[0]) {
+		ret = request_irq(adev->irq[0], pl031_interrupt,
+				  vendor->irqflags, "rtc-pl031", ldata);
+		if (ret)
+			goto out_no_irq;
+		dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
 	}
-	dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
 	return 0;
 
 out_no_irq:
--- linux-4.4.0.orig/drivers/rtc/rtc-pm8xxx.c
+++ linux-4.4.0/drivers/rtc/rtc-pm8xxx.c
@@ -74,16 +74,18 @@
 /*
  * Steps to write the RTC registers.
  * 1. Disable alarm if enabled.
- * 2. Write 0x00 to LSB.
- * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
- * 4. Enable alarm if disabled in step 1.
+ * 2. Disable rtc if enabled.
+ * 3. Write 0x00 to LSB.
+ * 4. Write Byte[1], Byte[2], Byte[3] then Byte[0].
+ * 5. Enable rtc if disabled in step 2.
+ * 6. Enable alarm if disabled in step 1.
  */
 static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
 	int rc, i;
 	unsigned long secs, irq_flags;
-	u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0;
-	unsigned int ctrl_reg;
+	u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0;
+	unsigned int ctrl_reg, rtc_ctrl_reg;
 	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
 	const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
 
@@ -92,23 +94,38 @@
 
 	rtc_tm_to_time(tm, &secs);
 
+	dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
+
 	for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
 		value[i] = secs & 0xFF;
 		secs >>= 8;
 	}
 
-	dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
-
 	spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
 
-	rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg);
+	rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
 	if (rc)
 		goto rtc_rw_fail;
 
 	if (ctrl_reg & regs->alarm_en) {
 		alarm_enabled = 1;
 		ctrl_reg &= ~regs->alarm_en;
-		rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
+		rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
+		if (rc) {
+			dev_err(dev, "Write to RTC Alarm control register failed\n");
+			goto rtc_rw_fail;
+		}
+	}
+
+	/* Disable RTC H/w before writing on RTC register */
+	rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg);
+	if (rc)
+		goto rtc_rw_fail;
+
+	if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) {
+		rtc_disabled = 1;
+		rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE;
+		rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
 		if (rc) {
 			dev_err(dev, "Write to RTC control register failed\n");
 			goto rtc_rw_fail;
@@ -137,11 +154,21 @@
 		goto rtc_rw_fail;
 	}
 
+	/* Enable RTC H/w after writing on RTC register */
+	if (rtc_disabled) {
+		rtc_ctrl_reg |= PM8xxx_RTC_ENABLE;
+		rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
+		if (rc) {
+			dev_err(dev, "Write to RTC control register failed\n");
+			goto rtc_rw_fail;
+		}
+	}
+
 	if (alarm_enabled) {
 		ctrl_reg |= regs->alarm_en;
-		rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
+		rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
 		if (rc) {
-			dev_err(dev, "Write to RTC control register failed\n");
+			dev_err(dev, "Write to RTC Alarm control register failed\n");
 			goto rtc_rw_fail;
 		}
 	}
@@ -186,7 +213,8 @@
 		}
 	}
 
-	secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
+	secs = value[0] | (value[1] << 8) | (value[2] << 16) |
+	       ((unsigned long)value[3] << 24);
 
 	rtc_time_to_tm(secs, tm);
 
@@ -267,7 +295,8 @@
 		return rc;
 	}
 
-	secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
+	secs = value[0] | (value[1] << 8) | (value[2] << 16) |
+	       ((unsigned long)value[3] << 24);
 
 	rtc_time_to_tm(secs, &alarm->time);
 
--- linux-4.4.0.orig/drivers/rtc/rtc-rx8025.c
+++ linux-4.4.0/drivers/rtc/rtc-rx8025.c
@@ -65,7 +65,6 @@
 
 static const struct i2c_device_id rx8025_id[] = {
 	{ "rx8025", 0 },
-	{ "rv8803", 1 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, rx8025_id);
--- linux-4.4.0.orig/drivers/rtc/rtc-s35390a.c
+++ linux-4.4.0/drivers/rtc/rtc-s35390a.c
@@ -15,6 +15,7 @@
 #include <linux/bitrev.h>
 #include <linux/bcd.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #define S35390A_CMD_STATUS1	0
 #define S35390A_CMD_STATUS2	1
@@ -34,10 +35,14 @@
 #define S35390A_ALRM_BYTE_HOURS	1
 #define S35390A_ALRM_BYTE_MINS	2
 
+/* flags for STATUS1 */
 #define S35390A_FLAG_POC	0x01
 #define S35390A_FLAG_BLD	0x02
+#define S35390A_FLAG_INT2	0x04
 #define S35390A_FLAG_24H	0x40
 #define S35390A_FLAG_RESET	0x80
+
+/* flag for STATUS2 */
 #define S35390A_FLAG_TEST	0x01
 
 #define S35390A_INT2_MODE_MASK		0xF0
@@ -94,19 +99,63 @@
 	return 0;
 }
 
-static int s35390a_reset(struct s35390a *s35390a)
-{
-	char buf[1];
-
-	if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0)
-		return -EIO;
-
-	if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD)))
+/*
+ * Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
+ * To keep the information if an irq is pending, pass the value read from
+ * STATUS1 to the caller.
+ */
+static int s35390a_reset(struct s35390a *s35390a, char *status1)
+{
+	u8 buf;
+	int ret;
+	unsigned initcount = 0;
+
+	ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
+	if (ret < 0)
+		return ret;
+
+	if (*status1 & S35390A_FLAG_POC)
+		/*
+		 * Do not communicate for 0.5 seconds since the power-on
+		 * detection circuit is in operation.
+		 */
+		msleep(500);
+	else if (!(*status1 & S35390A_FLAG_BLD))
+		/*
+		 * If both POC and BLD are unset everything is fine.
+		 */
 		return 0;
 
-	buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H);
-	buf[0] &= 0xf0;
-	return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
+	/*
+	 * At least one of POC and BLD are set, so reinitialise chip. Keeping
+	 * this information in the hardware to know later that the time isn't
+	 * valid is unfortunately not possible because POC and BLD are cleared
+	 * on read. So the reset is best done now.
+	 *
+	 * The 24H bit is kept over reset, so set it already here.
+	 */
+initialize:
+	*status1 = S35390A_FLAG_24H;
+	buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
+	ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
+
+	if (ret < 0)
+		return ret;
+
+	ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
+	if (ret < 0)
+		return ret;
+
+	if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
+		/* Try up to five times to reset the chip */
+		if (initcount < 5) {
+			++initcount;
+			goto initialize;
+		} else
+			return -EIO;
+	}
+
+	return 1;
 }
 
 static int s35390a_disable_test_mode(struct s35390a *s35390a)
@@ -242,6 +291,8 @@
 
 	if (alm->time.tm_wday != -1)
 		buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
+	else
+		buf[S35390A_ALRM_BYTE_WDAY] = 0;
 
 	buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
 			alm->time.tm_hour) | 0x80;
@@ -265,27 +316,61 @@
 	char buf[3], sts;
 	int i, err;
 
+	/*
+	 * initialize all members to -1 to signal the core that they are not
+	 * defined by the hardware.
+	 */
+	alm->time.tm_sec = -1;
+	alm->time.tm_min = -1;
+	alm->time.tm_hour = -1;
+	alm->time.tm_mday = -1;
+	alm->time.tm_mon = -1;
+	alm->time.tm_year = -1;
+	alm->time.tm_wday = -1;
+	alm->time.tm_yday = -1;
+	alm->time.tm_isdst = -1;
+
 	err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
 	if (err < 0)
 		return err;
 
-	if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
-		return -EINVAL;
+	if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
+		/*
+		 * When the alarm isn't enabled, the register to configure
+		 * the alarm time isn't accessible.
+		 */
+		alm->enabled = 0;
+		return 0;
+	} else {
+		alm->enabled = 1;
+	}
 
 	err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
 	if (err < 0)
 		return err;
 
 	/* This chip returns the bits of each byte in reverse order */
-	for (i = 0; i < 3; ++i) {
+	for (i = 0; i < 3; ++i)
 		buf[i] = bitrev8(buf[i]);
-		buf[i] &= ~0x80;
-	}
 
-	alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]);
-	alm->time.tm_hour = s35390a_reg2hr(s35390a,
-						buf[S35390A_ALRM_BYTE_HOURS]);
-	alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]);
+	/*
+	 * B0 of the three matching registers is an enable flag. Iff it is set
+	 * the configured value is used for matching.
+	 */
+	if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80)
+		alm->time.tm_wday =
+			bcd2bin(buf[S35390A_ALRM_BYTE_WDAY] & ~0x80);
+
+	if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80)
+		alm->time.tm_hour =
+			s35390a_reg2hr(s35390a,
+				       buf[S35390A_ALRM_BYTE_HOURS] & ~0x80);
+
+	if (buf[S35390A_ALRM_BYTE_MINS] & 0x80)
+		alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80);
+
+	/* alarm triggers always at s=0 */
+	alm->time.tm_sec = 0;
 
 	dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
 			__func__, alm->time.tm_min, alm->time.tm_hour,
@@ -327,11 +412,11 @@
 static int s35390a_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
-	int err;
+	int err, err_reset;
 	unsigned int i;
 	struct s35390a *s35390a;
 	struct rtc_time tm;
-	char buf[1];
+	char buf, status1;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		err = -ENODEV;
@@ -360,29 +445,35 @@
 		}
 	}
 
-	err = s35390a_reset(s35390a);
-	if (err < 0) {
+	err_reset = s35390a_reset(s35390a, &status1);
+	if (err_reset < 0) {
+		err = err_reset;
 		dev_err(&client->dev, "error resetting chip\n");
 		goto exit_dummy;
 	}
 
-	err = s35390a_disable_test_mode(s35390a);
-	if (err < 0) {
-		dev_err(&client->dev, "error disabling test mode\n");
-		goto exit_dummy;
-	}
-
-	err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
-	if (err < 0) {
-		dev_err(&client->dev, "error checking 12/24 hour mode\n");
-		goto exit_dummy;
-	}
-	if (buf[0] & S35390A_FLAG_24H)
+	if (status1 & S35390A_FLAG_24H)
 		s35390a->twentyfourhour = 1;
 	else
 		s35390a->twentyfourhour = 0;
 
-	if (s35390a_get_datetime(client, &tm) < 0)
+	if (status1 & S35390A_FLAG_INT2) {
+		/* disable alarm (and maybe test mode) */
+		buf = 0;
+		err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
+		if (err < 0) {
+			dev_err(&client->dev, "error disabling alarm");
+			goto exit_dummy;
+		}
+	} else {
+		err = s35390a_disable_test_mode(s35390a);
+		if (err < 0) {
+			dev_err(&client->dev, "error disabling test mode\n");
+			goto exit_dummy;
+		}
+	}
+
+	if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
 		dev_warn(&client->dev, "clock needs to be set\n");
 
 	device_set_wakeup_capable(&client->dev, 1);
@@ -395,6 +486,10 @@
 		err = PTR_ERR(s35390a->rtc);
 		goto exit_dummy;
 	}
+
+	if (status1 & S35390A_FLAG_INT2)
+		rtc_update_irq(s35390a->rtc, 1, RTC_AF);
+
 	return 0;
 
 exit_dummy:
--- linux-4.4.0.orig/drivers/rtc/rtc-s3c.c
+++ linux-4.4.0/drivers/rtc/rtc-s3c.c
@@ -149,12 +149,14 @@
 	if (!is_power_of_2(freq))
 		return -EINVAL;
 
+	s3c_rtc_enable_clk(info);
 	spin_lock_irq(&info->pie_lock);
 
 	if (info->data->set_freq)
 		info->data->set_freq(info, freq);
 
 	spin_unlock_irq(&info->pie_lock);
+	s3c_rtc_disable_clk(info);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/rtc/rtc-sh.c
+++ linux-4.4.0/drivers/rtc/rtc-sh.c
@@ -455,7 +455,7 @@
 static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off)
 {
 	unsigned int byte;
-	int value = 0xff;	/* return 0xff for ignored values */
+	int value = -1;			/* return -1 for ignored values */
 
 	byte = readb(rtc->regbase + reg_off);
 	if (byte & AR_ENB) {
--- linux-4.4.0.orig/drivers/rtc/rtc-snvs.c
+++ linux-4.4.0/drivers/rtc/rtc-snvs.c
@@ -47,49 +47,83 @@
 	struct clk *clk;
 };
 
+/* Read 64 bit timer register, which could be in inconsistent state */
+static u64 rtc_read_lpsrt(struct snvs_rtc_data *data)
+{
+	u32 msb, lsb;
+
+	regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &msb);
+	regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &lsb);
+	return (u64)msb << 32 | lsb;
+}
+
+/* Read the secure real time counter, taking care to deal with the cases of the
+ * counter updating while being read.
+ */
 static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
 {
 	u64 read1, read2;
-	u32 val;
+	unsigned int timeout = 100;
 
+	/* As expected, the registers might update between the read of the LSB
+	 * reg and the MSB reg.  It's also possible that one register might be
+	 * in partially modified state as well.
+	 */
+	read1 = rtc_read_lpsrt(data);
 	do {
-		regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val);
-		read1 = val;
-		read1 <<= 32;
-		regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val);
-		read1 |= val;
-
-		regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val);
-		read2 = val;
-		read2 <<= 32;
-		regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val);
-		read2 |= val;
-	} while (read1 != read2);
+		read2 = read1;
+		read1 = rtc_read_lpsrt(data);
+	} while (read1 != read2 && --timeout);
+	if (!timeout)
+		dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n");
 
 	/* Convert 47-bit counter to 32-bit raw second count */
 	return (u32) (read1 >> CNTR_TO_SECS_SH);
 }
 
-static void rtc_write_sync_lp(struct snvs_rtc_data *data)
+/* Just read the lsb from the counter, dealing with inconsistent state */
+static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb)
 {
-	u32 count1, count2, count3;
-	int i;
+	u32 count1, count2;
+	unsigned int timeout = 100;
 
-	/* Wait for 3 CKIL cycles */
-	for (i = 0; i < 3; i++) {
-		do {
-			regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
-			regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2);
-		} while (count1 != count2);
-
-		/* Now wait until counter value changes */
-		do {
-			do {
-				regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2);
-				regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count3);
-			} while (count2 != count3);
-		} while (count3 == count1);
+	regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
+	do {
+		count2 = count1;
+		regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
+	} while (count1 != count2 && --timeout);
+	if (!timeout) {
+		dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n");
+		return -ETIMEDOUT;
 	}
+
+	*lsb = count1;
+	return 0;
+}
+
+static int rtc_write_sync_lp(struct snvs_rtc_data *data)
+{
+	u32 count1, count2;
+	u32 elapsed;
+	unsigned int timeout = 1000;
+	int ret;
+
+	ret = rtc_read_lp_counter_lsb(data, &count1);
+	if (ret)
+		return ret;
+
+	/* Wait for 3 CKIL cycles, about 61.0-91.5 µs */
+	do {
+		ret = rtc_read_lp_counter_lsb(data, &count2);
+		if (ret)
+			return ret;
+		elapsed = count2 - count1; /* wrap around _is_ handled! */
+	} while (elapsed < 3 && --timeout);
+	if (!timeout) {
+		dev_err(&data->rtc->dev, "Timeout waiting for LPSRT Counter to change\n");
+		return -ETIMEDOUT;
+	}
+	return 0;
 }
 
 static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable)
@@ -132,20 +166,23 @@
 {
 	struct snvs_rtc_data *data = dev_get_drvdata(dev);
 	unsigned long time;
+	int ret;
 
 	rtc_tm_to_time(tm, &time);
 
 	/* Disable RTC first */
-	snvs_rtc_enable(data, false);
+	ret = snvs_rtc_enable(data, false);
+	if (ret)
+		return ret;
 
 	/* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */
 	regmap_write(data->regmap, data->offset + SNVS_LPSRTCLR, time << CNTR_TO_SECS_SH);
 	regmap_write(data->regmap, data->offset + SNVS_LPSRTCMR, time >> (32 - CNTR_TO_SECS_SH));
 
 	/* Enable RTC again */
-	snvs_rtc_enable(data, true);
+	ret = snvs_rtc_enable(data, true);
 
-	return 0;
+	return ret;
 }
 
 static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -170,9 +207,7 @@
 			   (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN),
 			   enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0);
 
-	rtc_write_sync_lp(data);
-
-	return 0;
+	return rtc_write_sync_lp(data);
 }
 
 static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -180,10 +215,14 @@
 	struct snvs_rtc_data *data = dev_get_drvdata(dev);
 	struct rtc_time *alrm_tm = &alrm->time;
 	unsigned long time;
+	int ret;
 
 	rtc_tm_to_time(alrm_tm, &time);
 
 	regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0);
+	ret = rtc_write_sync_lp(data);
+	if (ret)
+		return ret;
 	regmap_write(data->regmap, data->offset + SNVS_LPTAR, time);
 
 	/* Clear alarm interrupt status bit */
@@ -257,7 +296,7 @@
 		of_property_read_u32(pdev->dev.of_node, "offset", &data->offset);
 	}
 
-	if (!data->regmap) {
+	if (IS_ERR(data->regmap)) {
 		dev_err(&pdev->dev, "Can't find snvs syscon\n");
 		return -ENODEV;
 	}
@@ -287,7 +326,11 @@
 	regmap_write(data->regmap, data->offset + SNVS_LPSR, 0xffffffff);
 
 	/* Enable RTC */
-	snvs_rtc_enable(data, true);
+	ret = snvs_rtc_enable(data, true);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable rtc %d\n", ret);
+		goto error_rtc_device_register;
+	}
 
 	device_init_wakeup(&pdev->dev, true);
 
--- linux-4.4.0.orig/drivers/rtc/rtc-sun6i.c
+++ linux-4.4.0/drivers/rtc/rtc-sun6i.c
@@ -37,9 +37,11 @@
 
 /* Control register */
 #define SUN6I_LOSC_CTRL				0x0000
+#define SUN6I_LOSC_CTRL_KEY			(0x16aa << 16)
 #define SUN6I_LOSC_CTRL_ALM_DHMS_ACC		BIT(9)
 #define SUN6I_LOSC_CTRL_RTC_HMS_ACC		BIT(8)
 #define SUN6I_LOSC_CTRL_RTC_YMD_ACC		BIT(7)
+#define SUN6I_LOSC_CTRL_EXT_OSC			BIT(0)
 #define SUN6I_LOSC_CTRL_ACC_MASK		GENMASK(9, 7)
 
 /* RTC */
@@ -114,13 +116,17 @@
 	void __iomem *base;
 	int irq;
 	unsigned long alarm;
+
+	spinlock_t lock;
 };
 
 static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
 {
 	struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
+	irqreturn_t ret = IRQ_NONE;
 	u32 val;
 
+	spin_lock(&chip->lock);
 	val = readl(chip->base + SUN6I_ALRM_IRQ_STA);
 
 	if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) {
@@ -129,10 +135,11 @@
 
 		rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
 
-		return IRQ_HANDLED;
+		ret = IRQ_HANDLED;
 	}
+	spin_unlock(&chip->lock);
 
-	return IRQ_NONE;
+	return ret;
 }
 
 static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
@@ -140,6 +147,7 @@
 	u32 alrm_val = 0;
 	u32 alrm_irq_val = 0;
 	u32 alrm_wake_val = 0;
+	unsigned long flags;
 
 	if (to) {
 		alrm_val = SUN6I_ALRM_EN_CNT_EN;
@@ -150,9 +158,11 @@
 		       chip->base + SUN6I_ALRM_IRQ_STA);
 	}
 
+	spin_lock_irqsave(&chip->lock, flags);
 	writel(alrm_val, chip->base + SUN6I_ALRM_EN);
 	writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN);
 	writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG);
+	spin_unlock_irqrestore(&chip->lock, flags);
 }
 
 static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
@@ -191,11 +201,15 @@
 static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 {
 	struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
+	unsigned long flags;
 	u32 alrm_st;
 	u32 alrm_en;
 
+	spin_lock_irqsave(&chip->lock, flags);
 	alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN);
 	alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA);
+	spin_unlock_irqrestore(&chip->lock, flags);
+
 	wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN);
 	wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN);
 	rtc_time_to_tm(chip->alarm, &wkalrm->time);
@@ -356,6 +370,7 @@
 	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
+	spin_lock_init(&chip->lock);
 
 	platform_set_drvdata(pdev, chip);
 	chip->dev = &pdev->dev;
@@ -404,6 +419,10 @@
 	/* disable alarm wakeup */
 	writel(0, chip->base + SUN6I_ALARM_CONFIG);
 
+	/* switch to the external, more precise, oscillator */
+	writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC,
+	       chip->base + SUN6I_LOSC_CTRL);
+
 	chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
 					&sun6i_rtc_ops, THIS_MODULE);
 	if (IS_ERR(chip->rtc)) {
--- linux-4.4.0.orig/drivers/rtc/rtc-tegra.c
+++ linux-4.4.0/drivers/rtc/rtc-tegra.c
@@ -18,6 +18,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 #include <linux/kernel.h>
+#include <linux/clk.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -59,6 +60,7 @@
 	struct platform_device	*pdev;
 	struct rtc_device	*rtc_dev;
 	void __iomem		*rtc_base; /* NULL if not initialized. */
+	struct clk		*clk;
 	int			tegra_rtc_irq; /* alarm and periodic irq */
 	spinlock_t		tegra_rtc_lock;
 };
@@ -332,6 +334,14 @@
 	if (info->tegra_rtc_irq <= 0)
 		return -EBUSY;
 
+	info->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(info->clk))
+		return PTR_ERR(info->clk);
+
+	ret = clk_prepare_enable(info->clk);
+	if (ret < 0)
+		return ret;
+
 	/* set context info. */
 	info->pdev = pdev;
 	spin_lock_init(&info->tegra_rtc_lock);
@@ -352,7 +362,7 @@
 		ret = PTR_ERR(info->rtc_dev);
 		dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
 			ret);
-		return ret;
+		goto disable_clk;
 	}
 
 	ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
@@ -362,12 +372,25 @@
 		dev_err(&pdev->dev,
 			"Unable to request interrupt for device (err=%d).\n",
 			ret);
-		return ret;
+		goto disable_clk;
 	}
 
 	dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
 
 	return 0;
+
+disable_clk:
+	clk_disable_unprepare(info->clk);
+	return ret;
+}
+
+static int tegra_rtc_remove(struct platform_device *pdev)
+{
+	struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(info->clk);
+
+	return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -419,6 +442,7 @@
 
 MODULE_ALIAS("platform:tegra_rtc");
 static struct platform_driver tegra_rtc_driver = {
+	.remove		= tegra_rtc_remove,
 	.shutdown	= tegra_rtc_shutdown,
 	.driver		= {
 		.name	= "tegra_rtc",
--- linux-4.4.0.orig/drivers/rtc/rtc-tx4939.c
+++ linux-4.4.0/drivers/rtc/rtc-tx4939.c
@@ -86,7 +86,8 @@
 	for (i = 2; i < 6; i++)
 		buf[i] = __raw_readl(&rtcreg->dat);
 	spin_unlock_irq(&pdata->lock);
-	sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];
+	sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) |
+		(buf[3] << 8) | buf[2];
 	rtc_time_to_tm(sec, tm);
 	return rtc_valid_tm(tm);
 }
@@ -147,7 +148,8 @@
 	alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0;
 	alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0;
 	spin_unlock_irq(&pdata->lock);
-	sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];
+	sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) |
+		(buf[3] << 8) | buf[2];
 	rtc_time_to_tm(sec, &alrm->time);
 	return rtc_valid_tm(&alrm->time);
 }
--- linux-4.4.0.orig/drivers/rtc/rtc-vr41xx.c
+++ linux-4.4.0/drivers/rtc/rtc-vr41xx.c
@@ -272,12 +272,13 @@
 }
 
 static const struct rtc_class_ops vr41xx_rtc_ops = {
-	.release	= vr41xx_rtc_release,
-	.ioctl		= vr41xx_rtc_ioctl,
-	.read_time	= vr41xx_rtc_read_time,
-	.set_time	= vr41xx_rtc_set_time,
-	.read_alarm	= vr41xx_rtc_read_alarm,
-	.set_alarm	= vr41xx_rtc_set_alarm,
+	.release		= vr41xx_rtc_release,
+	.ioctl			= vr41xx_rtc_ioctl,
+	.read_time		= vr41xx_rtc_read_time,
+	.set_time		= vr41xx_rtc_set_time,
+	.read_alarm		= vr41xx_rtc_read_alarm,
+	.set_alarm		= vr41xx_rtc_set_alarm,
+	.alarm_irq_enable	= vr41xx_rtc_alarm_irq_enable,
 };
 
 static int rtc_probe(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/s390/block/dasd.c
+++ linux-4.4.0/drivers/s390/block/dasd.c
@@ -1584,9 +1584,18 @@
 	unsigned long long now;
 	int expires;
 
+	cqr = (struct dasd_ccw_req *) intparm;
 	if (IS_ERR(irb)) {
 		switch (PTR_ERR(irb)) {
 		case -EIO:
+			if (cqr && cqr->status == DASD_CQR_CLEAR_PENDING) {
+				device = (struct dasd_device *) cqr->startdev;
+				cqr->status = DASD_CQR_CLEARED;
+				dasd_device_clear_timer(device);
+				wake_up(&dasd_flush_wq);
+				dasd_schedule_device_bh(device);
+				return;
+			}
 			break;
 		case -ETIMEDOUT:
 			DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s: "
@@ -1602,7 +1611,6 @@
 	}
 
 	now = get_tod_clock();
-	cqr = (struct dasd_ccw_req *) intparm;
 	/* check for conditions that should be handled immediately */
 	if (!cqr ||
 	    !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
@@ -1627,8 +1635,11 @@
 	/* check for for attention message */
 	if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) {
 		device = dasd_device_from_cdev_locked(cdev);
-		device->discipline->check_attention(device, irb->esw.esw1.lpum);
-		dasd_put_device(device);
+		if (!IS_ERR(device)) {
+			device->discipline->check_attention(device,
+							    irb->esw.esw1.lpum);
+			dasd_put_device(device);
+		}
 	}
 
 	if (!cqr)
@@ -1870,8 +1881,12 @@
 {
 	int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM);
 
-	if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
-		/* dasd is being set offline. */
+	if (test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
+	    !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
+		/*
+		 * dasd is being set offline
+		 * but it is no safe offline where we have to allow I/O
+		 */
 		return 1;
 	}
 	if (device->stopped) {
@@ -3031,6 +3046,7 @@
 		max = block->base->discipline->max_blocks << block->s2b_shift;
 	}
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, block->request_queue);
+	block->request_queue->limits.max_dev_sectors = max;
 	blk_queue_logical_block_size(block->request_queue,
 				     block->bp_block);
 	blk_queue_max_hw_sectors(block->request_queue, max);
@@ -3270,8 +3286,6 @@
 	struct dasd_device *device;
 	struct dasd_block *block;
 
-	cdev->handler = NULL;
-
 	device = dasd_device_from_cdev(cdev);
 	if (IS_ERR(device)) {
 		dasd_remove_sysfs_files(cdev);
@@ -3290,6 +3304,7 @@
 	 * no quite down yet.
 	 */
 	dasd_set_target_state(device, DASD_STATE_NEW);
+	cdev->handler = NULL;
 	/* dasd_delete_device destroys the device reference. */
 	block = device->block;
 	dasd_delete_device(device);
--- linux-4.4.0.orig/drivers/s390/block/dasd_3990_erp.c
+++ linux-4.4.0/drivers/s390/block/dasd_3990_erp.c
@@ -2743,6 +2743,16 @@
 		erp = dasd_3990_erp_handle_match_erp(cqr, erp);
 	}
 
+
+	/*
+	 * For path verification work we need to stick with the path that was
+	 * originally chosen so that the per path configuration data is
+	 * assigned correctly.
+	 */
+	if (test_bit(DASD_CQR_VERIFY_PATH, &erp->flags) && cqr->lpm) {
+		erp->lpm = cqr->lpm;
+	}
+
 	if (device->features & DASD_FEATURE_ERPLOG) {
 		/* print current erp_chain */
 		dev_err(&device->cdev->dev,
--- linux-4.4.0.orig/drivers/s390/block/dasd_alias.c
+++ linux-4.4.0/drivers/s390/block/dasd_alias.c
@@ -258,14 +258,15 @@
 		return;
 	device->discipline->get_uid(device, &uid);
 	spin_lock_irqsave(&lcu->lock, flags);
-	list_del_init(&device->alias_list);
 	/* make sure that the workers don't use this device */
 	if (device == lcu->suc_data.device) {
 		spin_unlock_irqrestore(&lcu->lock, flags);
 		cancel_work_sync(&lcu->suc_data.worker);
 		spin_lock_irqsave(&lcu->lock, flags);
-		if (device == lcu->suc_data.device)
+		if (device == lcu->suc_data.device) {
+			dasd_put_device(device);
 			lcu->suc_data.device = NULL;
+		}
 	}
 	was_pending = 0;
 	if (device == lcu->ruac_data.device) {
@@ -273,14 +274,17 @@
 		was_pending = 1;
 		cancel_delayed_work_sync(&lcu->ruac_data.dwork);
 		spin_lock_irqsave(&lcu->lock, flags);
-		if (device == lcu->ruac_data.device)
+		if (device == lcu->ruac_data.device) {
+			dasd_put_device(device);
 			lcu->ruac_data.device = NULL;
+		}
 	}
 	private->lcu = NULL;
 	spin_unlock_irqrestore(&lcu->lock, flags);
 
 	spin_lock_irqsave(&aliastree.lock, flags);
 	spin_lock(&lcu->lock);
+	list_del_init(&device->alias_list);
 	if (list_empty(&lcu->grouplist) &&
 	    list_empty(&lcu->active_devices) &&
 	    list_empty(&lcu->inactive_devices)) {
@@ -392,6 +396,20 @@
 	char msg_format;
 	char msg_no;
 
+	/*
+	 * intrc values ENODEV, ENOLINK and EPERM
+	 * will be optained from sleep_on to indicate that no
+	 * IO operation can be started
+	 */
+	if (cqr->intrc == -ENODEV)
+		return 1;
+
+	if (cqr->intrc == -ENOLINK)
+		return 1;
+
+	if (cqr->intrc == -EPERM)
+		return 1;
+
 	sense = dasd_get_sense(&cqr->irb);
 	if (!sense)
 		return 0;
@@ -456,16 +474,20 @@
 	lcu->flags &= ~NEED_UAC_UPDATE;
 	spin_unlock_irqrestore(&lcu->lock, flags);
 
-	do {
-		rc = dasd_sleep_on(cqr);
-		if (rc && suborder_not_supported(cqr))
-			return -EOPNOTSUPP;
-	} while (rc && (cqr->retries > 0));
-	if (rc) {
+	rc = dasd_sleep_on(cqr);
+	if (!rc)
+		goto out;
+
+	if (suborder_not_supported(cqr)) {
+		/* suborder not supported or device unusable for IO */
+		rc = -EOPNOTSUPP;
+	} else {
+		/* IO failed but should be retried */
 		spin_lock_irqsave(&lcu->lock, flags);
 		lcu->flags |= NEED_UAC_UPDATE;
 		spin_unlock_irqrestore(&lcu->lock, flags);
 	}
+out:
 	dasd_kfree_request(cqr, cqr->memdev);
 	return rc;
 }
@@ -549,8 +571,10 @@
 	if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) {
 		DBF_DEV_EVENT(DBF_WARNING, device, "could not update"
 			    " alias data in lcu (rc = %d), retry later", rc);
-		schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
+		if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ))
+			dasd_put_device(device);
 	} else {
+		dasd_put_device(device);
 		lcu->ruac_data.device = NULL;
 		lcu->flags &= ~UPDATE_PENDING;
 	}
@@ -593,8 +617,10 @@
 	 */
 	if (!usedev)
 		return -EINVAL;
+	dasd_get_device(usedev);
 	lcu->ruac_data.device = usedev;
-	schedule_delayed_work(&lcu->ruac_data.dwork, 0);
+	if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0))
+		dasd_put_device(usedev);
 	return 0;
 }
 
@@ -619,6 +645,7 @@
 	}
 	if (lcu->flags & UPDATE_PENDING) {
 		list_move(&device->alias_list, &lcu->active_devices);
+		private->pavgroup = NULL;
 		_schedule_lcu_update(lcu, device);
 	}
 	spin_unlock(&lcu->lock);
@@ -723,7 +750,7 @@
 	ASCEBC((char *) &cqr->magic, 4);
 	ccw = cqr->cpaddr;
 	ccw->cmd_code = DASD_ECKD_CCW_RSCK;
-	ccw->flags = 0 ;
+	ccw->flags = CCW_FLAG_SLI;
 	ccw->count = 16;
 	ccw->cda = (__u32)(addr_t) cqr->data;
 	((char *)cqr->data)[0] = reason;
@@ -930,6 +957,7 @@
 	/* 3. read new alias configuration */
 	_schedule_lcu_update(lcu, device);
 	lcu->suc_data.device = NULL;
+	dasd_put_device(device);
 	spin_unlock_irqrestore(&lcu->lock, flags);
 }
 
@@ -989,6 +1017,8 @@
 	}
 	lcu->suc_data.reason = reason;
 	lcu->suc_data.device = device;
+	dasd_get_device(device);
 	spin_unlock(&lcu->lock);
-	schedule_work(&lcu->suc_data.worker);
+	if (!schedule_work(&lcu->suc_data.worker))
+		dasd_put_device(device);
 };
--- linux-4.4.0.orig/drivers/s390/block/dasd_diag.c
+++ linux-4.4.0/drivers/s390/block/dasd_diag.c
@@ -67,7 +67,7 @@
  * and function code cmd.
  * In case of an exception return 3. Otherwise return result of bitwise OR of
  * resulting condition code and DIAG return code. */
-static inline int dia250(void *iob, int cmd)
+static inline int __dia250(void *iob, int cmd)
 {
 	register unsigned long reg2 asm ("2") = (unsigned long) iob;
 	typedef union {
@@ -77,7 +77,6 @@
 	int rc;
 
 	rc = 3;
-	diag_stat_inc(DIAG_STAT_X250);
 	asm volatile(
 		"	diag	2,%2,0x250\n"
 		"0:	ipm	%0\n"
@@ -91,6 +90,12 @@
 	return rc;
 }
 
+static inline int dia250(void *iob, int cmd)
+{
+	diag_stat_inc(DIAG_STAT_X250);
+	return __dia250(iob, cmd);
+}
+
 /* Initialize block I/O to DIAG device using the specified blocksize and
  * block offset. On success, return zero and set end_block to contain the
  * number of blocks on the device minus the specified offset. Return non-zero
--- linux-4.4.0.orig/drivers/s390/block/dasd_eckd.c
+++ linux-4.4.0/drivers/s390/block/dasd_eckd.c
@@ -223,7 +223,7 @@
 	data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
 	data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
 
-	rc = get_sync_clock(&data->ep_sys_time);
+	rc = get_phys_clock(&data->ep_sys_time);
 	/* Ignore return code if sync clock is switched off. */
 	if (rc == -EOPNOTSUPP || rc == -EACCES)
 		rc = 0;
@@ -334,7 +334,7 @@
 	pfxdata->define_extent.ga_extended |= 0x02; /* 'Extended Parameter' */
 	pfxdata->validity.time_stamp = 1;	    /* 'Time Stamp Valid'   */
 
-	rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time);
+	rc = get_phys_clock(&pfxdata->define_extent.ep_sys_time);
 	/* Ignore return code if sync clock is switched off. */
 	if (rc == -EOPNOTSUPP || rc == -EACCES)
 		rc = 0;
@@ -518,10 +518,12 @@
 	pfxdata->validity.define_extent = 1;
 
 	/* private uid is kept up to date, conf_data may be outdated */
-	if (startpriv->uid.type != UA_BASE_DEVICE) {
+	if (startpriv->uid.type == UA_BASE_PAV_ALIAS)
 		pfxdata->validity.verify_base = 1;
-		if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
-			pfxdata->validity.hyper_pav = 1;
+
+	if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) {
+		pfxdata->validity.verify_base = 1;
+		pfxdata->validity.hyper_pav = 1;
 	}
 
 	/* define extend data (mostly)*/
@@ -2064,14 +2066,14 @@
 	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
 
 raw:
-	block->blocks = (private->real_cyl *
+	block->blocks = ((unsigned long) private->real_cyl *
 			  private->rdc_data.trk_per_cyl *
 			  blk_per_trk);
 
 	dev_info(&device->cdev->dev,
-		 "DASD with %d KB/block, %d KB total size, %d KB/track, "
+		 "DASD with %u KB/block, %lu KB total size, %u KB/track, "
 		 "%s\n", (block->bp_block >> 10),
-		 ((private->real_cyl *
+		 (((unsigned long) private->real_cyl *
 		   private->rdc_data.trk_per_cyl *
 		   blk_per_trk * (block->bp_block >> 9)) >> 1),
 		 ((blk_per_trk * block->bp_block) >> 10),
@@ -2099,8 +2101,11 @@
 
 static int dasd_eckd_online_to_ready(struct dasd_device *device)
 {
-	cancel_work_sync(&device->reload_device);
-	cancel_work_sync(&device->kick_validate);
+	if (cancel_work_sync(&device->reload_device))
+		dasd_put_device(device);
+	if (cancel_work_sync(&device->kick_validate))
+		dasd_put_device(device);
+
 	return 0;
 };
 
@@ -3002,10 +3007,12 @@
 	pfxdata.validity.define_extent = 1;
 
 	/* private uid is kept up to date, conf_data may be outdated */
-	if (startpriv->uid.type != UA_BASE_DEVICE) {
+	if (startpriv->uid.type == UA_BASE_PAV_ALIAS)
 		pfxdata.validity.verify_base = 1;
-		if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
-			pfxdata.validity.hyper_pav = 1;
+
+	if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) {
+		pfxdata.validity.verify_base = 1;
+		pfxdata.validity.hyper_pav = 1;
 	}
 
 	switch (cmd) {
@@ -4016,6 +4023,14 @@
 		usrparm.psf_data &= 0x7fffffffULL;
 		usrparm.rssd_result &= 0x7fffffffULL;
 	}
+	/* at least 2 bytes are accessed and should be allocated */
+	if (usrparm.psf_data_len < 2) {
+		DBF_DEV_EVENT(DBF_WARNING, device,
+			      "Symmetrix ioctl invalid data length %d",
+			      usrparm.psf_data_len);
+		rc = -EINVAL;
+		goto out;
+	}
 	/* alloc I/O data area */
 	psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA);
 	rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA);
--- linux-4.4.0.orig/drivers/s390/block/dcssblk.c
+++ linux-4.4.0/drivers/s390/block/dcssblk.c
@@ -892,7 +892,7 @@
 	dev_info = bdev->bd_disk->private_data;
 	if (!dev_info)
 		return -ENODEV;
-	dev_sz = dev_info->end - dev_info->start;
+	dev_sz = dev_info->end - dev_info->start + 1;
 	offset = secnum * 512;
 	addr = (void *) (dev_info->start + offset);
 	*pfn = virt_to_phys(addr) >> PAGE_SHIFT;
--- linux-4.4.0.orig/drivers/s390/char/Makefile
+++ linux-4.4.0/drivers/s390/char/Makefile
@@ -2,6 +2,8 @@
 # S/390 character devices
 #
 
+CFLAGS_REMOVE_sclp_early_core.o	+= $(CC_FLAGS_EXPOLINE)
+
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
 	 sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
 	 sclp_early.o
--- linux-4.4.0.orig/drivers/s390/char/con3270.c
+++ linux-4.4.0/drivers/s390/char/con3270.c
@@ -124,7 +124,12 @@
 static void
 con3270_update_string(struct con3270 *cp, struct string *s, int nr)
 {
-	if (s->len >= cp->view.cols - 5)
+	if (s->len < 4) {
+		/* This indicates a bug, but printing a warning would
+		 * cause a deadlock. */
+		return;
+	}
+	if (s->string[s->len - 4] != TO_RA)
 		return;
 	raw3270_buffer_address(cp->view.dev, s->string + s->len - 3,
 			       cp->view.cols * (nr + 1));
@@ -461,11 +466,11 @@
 		cp->cline->len + 4 : cp->view.cols;
 	s = con3270_alloc_string(cp, size);
 	memcpy(s->string, cp->cline->string, cp->cline->len);
-	if (s->len < cp->view.cols - 5) {
+	if (cp->cline->len < cp->view.cols - 5) {
 		s->string[s->len - 4] = TO_RA;
 		s->string[s->len - 1] = 0;
 	} else {
-		while (--size > cp->cline->len)
+		while (--size >= cp->cline->len)
 			s->string[size] = cp->view.ascebc[' '];
 	}
 	/* Replace cline with allocated line s and reset cline. */
@@ -622,7 +627,7 @@
 		     (void (*)(unsigned long)) con3270_read_tasklet,
 		     (unsigned long) condev->read);
 
-	raw3270_add_view(&condev->view, &con3270_fn, 1);
+	raw3270_add_view(&condev->view, &con3270_fn, 1, RAW3270_VIEW_LOCK_IRQ);
 
 	INIT_LIST_HEAD(&condev->freemem);
 	for (i = 0; i < CON3270_STRING_PAGES; i++) {
--- linux-4.4.0.orig/drivers/s390/char/fs3270.c
+++ linux-4.4.0/drivers/s390/char/fs3270.c
@@ -463,7 +463,8 @@
 
 	init_waitqueue_head(&fp->wait);
 	fp->fs_pid = get_pid(task_pid(current));
-	rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
+	rc = raw3270_add_view(&fp->view, &fs3270_fn, minor,
+			      RAW3270_VIEW_LOCK_BH);
 	if (rc) {
 		fs3270_free_view(&fp->view);
 		goto out;
--- linux-4.4.0.orig/drivers/s390/char/keyboard.c
+++ linux-4.4.0/drivers/s390/char/keyboard.c
@@ -333,37 +333,41 @@
 	      int cmd, int perm)
 {
 	struct kbentry tmp;
+	unsigned long kb_index, kb_table;
 	ushort *key_map, val, ov;
 
 	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
 		return -EFAULT;
+	kb_index = (unsigned long) tmp.kb_index;
 #if NR_KEYS < 256
-	if (tmp.kb_index >= NR_KEYS)
+	if (kb_index >= NR_KEYS)
 		return -EINVAL;
 #endif
+	kb_table = (unsigned long) tmp.kb_table;
 #if MAX_NR_KEYMAPS < 256
-	if (tmp.kb_table >= MAX_NR_KEYMAPS)
+	if (kb_table >= MAX_NR_KEYMAPS)
 		return -EINVAL;	
+	kb_table = array_index_nospec(kb_table , MAX_NR_KEYMAPS);
 #endif
 
 	switch (cmd) {
 	case KDGKBENT:
-		key_map = kbd->key_maps[tmp.kb_table];
+		key_map = kbd->key_maps[kb_table];
 		if (key_map) {
-		    val = U(key_map[tmp.kb_index]);
+		    val = U(key_map[kb_index]);
 		    if (KTYP(val) >= KBD_NR_TYPES)
 			val = K_HOLE;
 		} else
-		    val = (tmp.kb_index ? K_HOLE : K_NOSUCHMAP);
+		    val = (kb_index ? K_HOLE : K_NOSUCHMAP);
 		return put_user(val, &user_kbe->kb_value);
 	case KDSKBENT:
 		if (!perm)
 			return -EPERM;
-		if (!tmp.kb_index && tmp.kb_value == K_NOSUCHMAP) {
+		if (!kb_index && tmp.kb_value == K_NOSUCHMAP) {
 			/* disallocate map */
-			key_map = kbd->key_maps[tmp.kb_table];
+			key_map = kbd->key_maps[kb_table];
 			if (key_map) {
-			    kbd->key_maps[tmp.kb_table] = NULL;
+			    kbd->key_maps[kb_table] = NULL;
 			    kfree(key_map);
 			}
 			break;
@@ -374,18 +378,18 @@
 		if (KVAL(tmp.kb_value) > kbd_max_vals[KTYP(tmp.kb_value)])
 			return -EINVAL;
 
-		if (!(key_map = kbd->key_maps[tmp.kb_table])) {
+		if (!(key_map = kbd->key_maps[kb_table])) {
 			int j;
 
 			key_map = kmalloc(sizeof(plain_map),
 						     GFP_KERNEL);
 			if (!key_map)
 				return -ENOMEM;
-			kbd->key_maps[tmp.kb_table] = key_map;
+			kbd->key_maps[kb_table] = key_map;
 			for (j = 0; j < NR_KEYS; j++)
 				key_map[j] = U(K_HOLE);
 		}
-		ov = U(key_map[tmp.kb_index]);
+		ov = U(key_map[kb_index]);
 		if (tmp.kb_value == ov)
 			break;	/* nothing to do */
 		/*
@@ -394,7 +398,7 @@
 		if (((ov == K_SAK) || (tmp.kb_value == K_SAK)) &&
 		    !capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		key_map[tmp.kb_index] = U(tmp.kb_value);
+		key_map[kb_index] = U(tmp.kb_value);
 		break;
 	}
 	return 0;
--- linux-4.4.0.orig/drivers/s390/char/raw3270.c
+++ linux-4.4.0/drivers/s390/char/raw3270.c
@@ -956,7 +956,7 @@
  * Add view to device with minor "minor".
  */
 int
-raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
+raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor, int subclass)
 {
 	unsigned long flags;
 	struct raw3270 *rp;
@@ -978,6 +978,7 @@
 		view->cols = rp->cols;
 		view->ascebc = rp->ascebc;
 		spin_lock_init(&view->lock);
+		lockdep_set_subclass(&view->lock, subclass);
 		list_add(&view->list, &rp->view_list);
 		rc = 0;
 		spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
--- linux-4.4.0.orig/drivers/s390/char/raw3270.h
+++ linux-4.4.0/drivers/s390/char/raw3270.h
@@ -155,6 +155,8 @@
 struct raw3270_view {
 	struct list_head list;
 	spinlock_t lock;
+#define RAW3270_VIEW_LOCK_IRQ	0
+#define RAW3270_VIEW_LOCK_BH	1
 	atomic_t ref_count;
 	struct raw3270 *dev;
 	struct raw3270_fn *fn;
@@ -163,7 +165,7 @@
 	unsigned char *ascebc;		/* ascii -> ebcdic table */
 };
 
-int raw3270_add_view(struct raw3270_view *, struct raw3270_fn *, int);
+int raw3270_add_view(struct raw3270_view *, struct raw3270_fn *, int, int);
 int raw3270_activate_view(struct raw3270_view *);
 void raw3270_del_view(struct raw3270_view *);
 void raw3270_deactivate_view(struct raw3270_view *);
--- linux-4.4.0.orig/drivers/s390/char/sclp_config.c
+++ linux-4.4.0/drivers/s390/char/sclp_config.c
@@ -43,7 +43,9 @@
 
 static void __ref sclp_cpu_change_notify(struct work_struct *work)
 {
+	lock_device_hotplug();
 	smp_rescan_cpus();
+	unlock_device_hotplug();
 }
 
 static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
--- linux-4.4.0.orig/drivers/s390/char/sclp_ctl.c
+++ linux-4.4.0/drivers/s390/char/sclp_ctl.c
@@ -56,6 +56,7 @@
 {
 	struct sclp_ctl_sccb ctl_sccb;
 	struct sccb_header *sccb;
+	unsigned long copied;
 	int rc;
 
 	if (copy_from_user(&ctl_sccb, user_area, sizeof(ctl_sccb)))
@@ -65,14 +66,15 @@
 	sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!sccb)
 		return -ENOMEM;
-	if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sizeof(*sccb))) {
+	copied = PAGE_SIZE -
+		copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), PAGE_SIZE);
+	if (offsetof(struct sccb_header, length) +
+	    sizeof(sccb->length) > copied || sccb->length > copied) {
 		rc = -EFAULT;
 		goto out_free;
 	}
-	if (sccb->length > PAGE_SIZE || sccb->length < 8)
-		return -EINVAL;
-	if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sccb->length)) {
-		rc = -EFAULT;
+	if (sccb->length < 8) {
+		rc = -EINVAL;
 		goto out_free;
 	}
 	rc = sclp_sync_request(ctl_sccb.cmdw, sccb);
--- linux-4.4.0.orig/drivers/s390/char/tty3270.c
+++ linux-4.4.0/drivers/s390/char/tty3270.c
@@ -937,7 +937,8 @@
 		return PTR_ERR(tp);
 
 	rc = raw3270_add_view(&tp->view, &tty3270_fn,
-			      tty->index + RAW3270_FIRSTMINOR);
+			      tty->index + RAW3270_FIRSTMINOR,
+			      RAW3270_VIEW_LOCK_BH);
 	if (rc) {
 		tty3270_free_view(tp);
 		return rc;
--- linux-4.4.0.orig/drivers/s390/char/vmlogrdr.c
+++ linux-4.4.0/drivers/s390/char/vmlogrdr.c
@@ -872,7 +872,7 @@
 		goto cleanup;
 
 	for (i=0; i < MAXMINOR; ++i ) {
-		sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL);
+		sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
 		if (!sys_ser[i].buffer) {
 			rc = -ENOMEM;
 			break;
--- linux-4.4.0.orig/drivers/s390/cio/blacklist.c
+++ linux-4.4.0/drivers/s390/cio/blacklist.c
@@ -303,8 +303,10 @@
 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
 {
 	struct ccwdev_iter *iter;
+	loff_t p = *offset;
 
-	if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
+	(*offset)++;
+	if (p >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
 		return NULL;
 	iter = it;
 	if (iter->devno == __MAX_SUBCHANNEL) {
@@ -314,7 +316,6 @@
 			return NULL;
 	} else
 		iter->devno++;
-	(*offset)++;
 	return iter;
 }
 
--- linux-4.4.0.orig/drivers/s390/cio/ccwgroup.c
+++ linux-4.4.0/drivers/s390/cio/ccwgroup.c
@@ -369,7 +369,7 @@
 		goto error;
 	}
 	/* Check for trailing stuff. */
-	if (i == num_devices && strlen(buf) > 0) {
+	if (i == num_devices && buf && strlen(buf) > 0) {
 		rc = -EINVAL;
 		goto error;
 	}
--- linux-4.4.0.orig/drivers/s390/cio/chp.c
+++ linux-4.4.0/drivers/s390/cio/chp.c
@@ -139,11 +139,11 @@
 
 	device = container_of(kobj, struct device, kobj);
 	chp = to_channelpath(device);
-	if (!chp->cmg_chars)
+	if (chp->cmg == -1)
 		return 0;
 
-	return memory_read_from_buffer(buf, count, &off,
-				chp->cmg_chars, sizeof(struct cmg_chars));
+	return memory_read_from_buffer(buf, count, &off, &chp->cmg_chars,
+				       sizeof(chp->cmg_chars));
 }
 
 static struct bin_attribute chp_measurement_chars_attr = {
@@ -416,7 +416,8 @@
  * chp_update_desc - update channel-path description
  * @chp - channel-path
  *
- * Update the channel-path description of the specified channel-path.
+ * Update the channel-path description of the specified channel-path
+ * including channel measurement related information.
  * Return zero on success, non-zero otherwise.
  */
 int chp_update_desc(struct channel_path *chp)
@@ -428,8 +429,10 @@
 		return rc;
 
 	rc = chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1);
+	if (rc)
+		return rc;
 
-	return rc;
+	return chsc_get_channel_measurement_chars(chp);
 }
 
 /**
@@ -466,14 +469,6 @@
 		ret = -ENODEV;
 		goto out_free;
 	}
-	/* Get channel-measurement characteristics. */
-	if (css_chsc_characteristics.scmc && css_chsc_characteristics.secm) {
-		ret = chsc_get_channel_measurement_chars(chp);
-		if (ret)
-			goto out_free;
-	} else {
-		chp->cmg = -1;
-	}
 	dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id);
 
 	/* make it known to the system */
--- linux-4.4.0.orig/drivers/s390/cio/chp.h
+++ linux-4.4.0/drivers/s390/cio/chp.h
@@ -48,7 +48,7 @@
 	/* Channel-measurement related stuff: */
 	int cmg;
 	int shared;
-	void *cmg_chars;
+	struct cmg_chars cmg_chars;
 };
 
 /* Return channel_path struct for given chpid. */
--- linux-4.4.0.orig/drivers/s390/cio/chsc.c
+++ linux-4.4.0/drivers/s390/cio/chsc.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 
 #include <asm/cio.h>
@@ -94,12 +95,13 @@
 int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
 {
 	struct chsc_ssd_area *ssd_area;
+	unsigned long flags;
 	int ccode;
 	int ret;
 	int i;
 	int mask;
 
-	spin_lock_irq(&chsc_page_lock);
+	spin_lock_irqsave(&chsc_page_lock, flags);
 	memset(chsc_page, 0, PAGE_SIZE);
 	ssd_area = chsc_page;
 	ssd_area->request.length = 0x0010;
@@ -143,7 +145,7 @@
 			ssd->fla[i] = ssd_area->fla[i];
 	}
 out:
-	spin_unlock_irq(&chsc_page_lock);
+	spin_unlock_irqrestore(&chsc_page_lock, flags);
 	return ret;
 }
 
@@ -224,8 +226,9 @@
 
 void chsc_chp_offline(struct chp_id chpid)
 {
-	char dbf_txt[15];
+	struct channel_path *chp = chpid_to_chp(chpid);
 	struct chp_link link;
+	char dbf_txt[15];
 
 	sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
 	CIO_TRACE_EVENT(2, dbf_txt);
@@ -236,6 +239,11 @@
 	link.chpid = chpid;
 	/* Wait until previous actions have settled. */
 	css_wait_for_slow_path();
+
+	mutex_lock(&chp->lock);
+	chp_update_desc(chp);
+	mutex_unlock(&chp->lock);
+
 	for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link);
 }
 
@@ -443,6 +451,7 @@
 
 static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
 {
+	struct channel_path *chp;
 	struct chp_link link;
 	struct chp_id chpid;
 	int status;
@@ -455,10 +464,17 @@
 	chpid.id = sei_area->rsid;
 	/* allocate a new channel path structure, if needed */
 	status = chp_get_status(chpid);
-	if (status < 0)
-		chp_new(chpid);
-	else if (!status)
+	if (!status)
 		return;
+
+	if (status < 0) {
+		chp_new(chpid);
+	} else {
+		chp = chpid_to_chp(chpid);
+		mutex_lock(&chp->lock);
+		chp_update_desc(chp);
+		mutex_unlock(&chp->lock);
+	}
 	memset(&link, 0, sizeof(struct chp_link));
 	link.chpid = chpid;
 	if ((sei_area->vf & 0xc0) != 0) {
@@ -690,8 +706,9 @@
 
 void chsc_chp_online(struct chp_id chpid)
 {
-	char dbf_txt[15];
+	struct channel_path *chp = chpid_to_chp(chpid);
 	struct chp_link link;
+	char dbf_txt[15];
 
 	sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
 	CIO_TRACE_EVENT(2, dbf_txt);
@@ -701,6 +718,11 @@
 		link.chpid = chpid;
 		/* Wait until previous actions have settled. */
 		css_wait_for_slow_path();
+
+		mutex_lock(&chp->lock);
+		chp_update_desc(chp);
+		mutex_unlock(&chp->lock);
+
 		for_each_subchannel_staged(__s390_process_res_acc, NULL,
 					   &link);
 		css_schedule_reprobe();
@@ -819,9 +841,10 @@
 		u32 fmt : 4;
 		u32 : 16;
 	} __attribute__ ((packed)) *secm_area;
+	unsigned long flags;
 	int ret, ccode;
 
-	spin_lock_irq(&chsc_page_lock);
+	spin_lock_irqsave(&chsc_page_lock, flags);
 	memset(chsc_page, 0, PAGE_SIZE);
 	secm_area = chsc_page;
 	secm_area->request.length = 0x0050;
@@ -851,7 +874,7 @@
 		CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
 			      secm_area->response.code);
 out:
-	spin_unlock_irq(&chsc_page_lock);
+	spin_unlock_irqrestore(&chsc_page_lock, flags);
 	return ret;
 }
 
@@ -967,22 +990,20 @@
 chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
 			  struct cmg_chars *chars)
 {
-	struct cmg_chars *cmg_chars;
 	int i, mask;
 
-	cmg_chars = chp->cmg_chars;
 	for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
 		mask = 0x80 >> (i + 3);
 		if (cmcv & mask)
-			cmg_chars->values[i] = chars->values[i];
+			chp->cmg_chars.values[i] = chars->values[i];
 		else
-			cmg_chars->values[i] = 0;
+			chp->cmg_chars.values[i] = 0;
 	}
 }
 
 int chsc_get_channel_measurement_chars(struct channel_path *chp)
 {
-	struct cmg_chars *cmg_chars;
+	unsigned long flags;
 	int ccode, ret;
 
 	struct {
@@ -1006,12 +1027,13 @@
 		u32 data[NR_MEASUREMENT_CHARS];
 	} __attribute__ ((packed)) *scmc_area;
 
-	chp->cmg_chars = NULL;
-	cmg_chars = kmalloc(sizeof(*cmg_chars), GFP_KERNEL);
-	if (!cmg_chars)
-		return -ENOMEM;
+	chp->shared = -1;
+	chp->cmg = -1;
 
-	spin_lock_irq(&chsc_page_lock);
+	if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
+		return 0;
+
+	spin_lock_irqsave(&chsc_page_lock, flags);
 	memset(chsc_page, 0, PAGE_SIZE);
 	scmc_area = chsc_page;
 	scmc_area->request.length = 0x0010;
@@ -1031,25 +1053,19 @@
 			      scmc_area->response.code);
 		goto out;
 	}
-	if (scmc_area->not_valid) {
-		chp->cmg = -1;
-		chp->shared = -1;
+	if (scmc_area->not_valid)
 		goto out;
-	}
+
 	chp->cmg = scmc_area->cmg;
 	chp->shared = scmc_area->shared;
 	if (chp->cmg != 2 && chp->cmg != 3) {
 		/* No cmg-dependent data. */
 		goto out;
 	}
-	chp->cmg_chars = cmg_chars;
 	chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
 				  (struct cmg_chars *) &scmc_area->data);
 out:
-	spin_unlock_irq(&chsc_page_lock);
-	if (!chp->cmg_chars)
-		kfree(cmg_chars);
-
+	spin_unlock_irqrestore(&chsc_page_lock, flags);
 	return ret;
 }
 
@@ -1130,6 +1146,7 @@
 int __init
 chsc_determine_css_characteristics(void)
 {
+	unsigned long flags;
 	int result;
 	struct {
 		struct chsc_header request;
@@ -1142,7 +1159,7 @@
 		u32 chsc_char[508];
 	} __attribute__ ((packed)) *scsc_area;
 
-	spin_lock_irq(&chsc_page_lock);
+	spin_lock_irqsave(&chsc_page_lock, flags);
 	memset(chsc_page, 0, PAGE_SIZE);
 	scsc_area = chsc_page;
 	scsc_area->request.length = 0x0010;
@@ -1164,14 +1181,14 @@
 		CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
 			      scsc_area->response.code);
 exit:
-	spin_unlock_irq(&chsc_page_lock);
+	spin_unlock_irqrestore(&chsc_page_lock, flags);
 	return result;
 }
 
 EXPORT_SYMBOL_GPL(css_general_characteristics);
 EXPORT_SYMBOL_GPL(css_chsc_characteristics);
 
-int chsc_sstpc(void *page, unsigned int op, u16 ctrl)
+int chsc_sstpc(void *page, unsigned int op, u16 ctrl, u64 *clock_delta)
 {
 	struct {
 		struct chsc_header request;
@@ -1181,7 +1198,9 @@
 		unsigned int ctrl : 16;
 		unsigned int rsvd2[5];
 		struct chsc_header response;
-		unsigned int rsvd3[7];
+		unsigned int rsvd3[3];
+		u64 clock_delta;
+		unsigned int rsvd4[2];
 	} __attribute__ ((packed)) *rr;
 	int rc;
 
@@ -1195,6 +1214,8 @@
 	if (rc)
 		return -EIO;
 	rc = (rr->response.code == 0x0001) ? 0 : -EIO;
+	if (clock_delta)
+		*clock_delta = rr->clock_delta;
 	return rc;
 }
 
--- linux-4.4.0.orig/drivers/s390/cio/cio.h
+++ linux-4.4.0/drivers/s390/cio/cio.h
@@ -102,7 +102,7 @@
 	struct schib_config config;
 } __attribute__ ((aligned(8)));
 
-DECLARE_PER_CPU(struct irb, cio_irb);
+DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb);
 
 #define to_subchannel(n) container_of(n, struct subchannel, dev)
 
--- linux-4.4.0.orig/drivers/s390/cio/cmf.c
+++ linux-4.4.0/drivers/s390/cio/cmf.c
@@ -753,6 +753,17 @@
 	cmf_generic_reset(cdev);
 }
 
+static int cmf_enabled(struct ccw_device *cdev)
+{
+	int enabled;
+
+	spin_lock_irq(cdev->ccwlock);
+	enabled = !!cdev->private->cmb;
+	spin_unlock_irq(cdev->ccwlock);
+
+	return enabled;
+}
+
 static struct attribute_group cmf_attr_group;
 
 static struct cmb_operations cmbops_basic = {
@@ -1153,13 +1164,8 @@
 			       char *buf)
 {
 	struct ccw_device *cdev = to_ccwdev(dev);
-	int enabled;
 
-	spin_lock_irq(cdev->ccwlock);
-	enabled = !!cdev->private->cmb;
-	spin_unlock_irq(cdev->ccwlock);
-
-	return sprintf(buf, "%d\n", enabled);
+	return sprintf(buf, "%d\n", cmf_enabled(cdev));
 }
 
 static ssize_t cmb_enable_store(struct device *dev,
@@ -1199,15 +1205,20 @@
  *  @cdev:	The ccw device to be enabled
  *
  *  Returns %0 for success or a negative error value.
- *
+ *  Note: If this is called on a device for which channel measurement is already
+ *	  enabled a reset of the measurement data is triggered.
  *  Context:
  *    non-atomic
  */
 int enable_cmf(struct ccw_device *cdev)
 {
-	int ret;
+	int ret = 0;
 
 	device_lock(&cdev->dev);
+	if (cmf_enabled(cdev)) {
+		cmbops->reset(cdev);
+		goto out_unlock;
+	}
 	get_device(&cdev->dev);
 	ret = cmbops->alloc(cdev);
 	if (ret)
@@ -1226,7 +1237,7 @@
 out:
 	if (ret)
 		put_device(&cdev->dev);
-
+out_unlock:
 	device_unlock(&cdev->dev);
 	return ret;
 }
--- linux-4.4.0.orig/drivers/s390/cio/css.c
+++ linux-4.4.0/drivers/s390/cio/css.c
@@ -529,6 +529,11 @@
 		rc = css_evaluate_known_subchannel(sch, 1);
 		if (rc == -EAGAIN)
 			css_schedule_eval(sch->schid);
+		/*
+		 * The loop might take long time for platforms with lots of
+		 * known devices. Allow scheduling here.
+		 */
+		cond_resched();
 	}
 	return 0;
 }
@@ -1120,6 +1125,8 @@
 
 int sch_is_pseudo_sch(struct subchannel *sch)
 {
+	if (!sch->dev.parent)
+		return 0;
 	return sch == to_css(sch->dev.parent)->pseudo_subchannel;
 }
 
--- linux-4.4.0.orig/drivers/s390/cio/device.c
+++ linux-4.4.0/drivers/s390/cio/device.c
@@ -872,8 +872,10 @@
 	 * Now we know this subchannel will stay, we can throw
 	 * our delayed uevent.
 	 */
-	dev_set_uevent_suppress(&sch->dev, 0);
-	kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+	if (dev_get_uevent_suppress(&sch->dev)) {
+		dev_set_uevent_suppress(&sch->dev, 0);
+		kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+	}
 	/* make it known to the system */
 	ret = ccw_device_add(cdev);
 	if (ret) {
@@ -1082,8 +1084,11 @@
 		 * Throw the delayed uevent for the subchannel, register
 		 * the ccw_device and exit.
 		 */
-		dev_set_uevent_suppress(&sch->dev, 0);
-		kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+		if (dev_get_uevent_suppress(&sch->dev)) {
+			/* should always be the case for the console */
+			dev_set_uevent_suppress(&sch->dev, 0);
+			kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+		}
 		cdev = sch_get_cdev(sch);
 		rc = ccw_device_add(cdev);
 		if (rc) {
--- linux-4.4.0.orig/drivers/s390/cio/device_fsm.c
+++ linux-4.4.0/drivers/s390/cio/device_fsm.c
@@ -822,6 +822,7 @@
 
 	ccw_device_set_timeout(cdev, 0);
 	cdev->private->iretry = 255;
+	cdev->private->async_kill_io_rc = -ETIMEDOUT;
 	ret = ccw_device_cancel_halt_clear(cdev);
 	if (ret == -EBUSY) {
 		ccw_device_set_timeout(cdev, 3*HZ);
@@ -898,7 +899,7 @@
 	/* OK, i/o is dead now. Call interrupt handler. */
 	if (cdev->handler)
 		cdev->handler(cdev, cdev->private->intparm,
-			      ERR_PTR(-EIO));
+			      ERR_PTR(cdev->private->async_kill_io_rc));
 }
 
 static void
@@ -915,14 +916,16 @@
 	ccw_device_online_verify(cdev, 0);
 	if (cdev->handler)
 		cdev->handler(cdev, cdev->private->intparm,
-			      ERR_PTR(-EIO));
+			      ERR_PTR(cdev->private->async_kill_io_rc));
 }
 
 void ccw_device_kill_io(struct ccw_device *cdev)
 {
 	int ret;
 
+	ccw_device_set_timeout(cdev, 0);
 	cdev->private->iretry = 255;
+	cdev->private->async_kill_io_rc = -EIO;
 	ret = ccw_device_cancel_halt_clear(cdev);
 	if (ret == -EBUSY) {
 		ccw_device_set_timeout(cdev, 3*HZ);
--- linux-4.4.0.orig/drivers/s390/cio/io_sch.h
+++ linux-4.4.0/drivers/s390/cio/io_sch.h
@@ -155,6 +155,7 @@
 	unsigned long intparm;	/* user interruption parameter */
 	struct qdio_irq *qdio_data;
 	struct irb irb;		/* device status */
+	int async_kill_io_rc;
 	struct senseid senseid;	/* SenseID info */
 	struct pgid pgid[8];	/* path group IDs per chpid*/
 	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
--- linux-4.4.0.orig/drivers/s390/cio/qdio.h
+++ linux-4.4.0/drivers/s390/cio/qdio.h
@@ -376,7 +376,6 @@
 extern u64 last_ai_time;
 
 /* prototypes for thin interrupt */
-void qdio_setup_thinint(struct qdio_irq *irq_ptr);
 int qdio_establish_thinint(struct qdio_irq *irq_ptr);
 void qdio_shutdown_thinint(struct qdio_irq *irq_ptr);
 void tiqdio_add_input_queues(struct qdio_irq *irq_ptr);
--- linux-4.4.0.orig/drivers/s390/cio/qdio_main.c
+++ linux-4.4.0/drivers/s390/cio/qdio_main.c
@@ -126,7 +126,7 @@
 static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
 			int start, int count, int auto_ack)
 {
-	int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0;
+	int rc, tmp_count = count, tmp_start = start, nr = q->nr;
 	unsigned int ccq = 0;
 
 	qperf_inc(q, eqbs);
@@ -149,14 +149,7 @@
 		qperf_inc(q, eqbs_partial);
 		DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x",
 			tmp_count);
-		/*
-		 * Retry once, if that fails bail out and process the
-		 * extracted buffers before trying again.
-		 */
-		if (!retried++)
-			goto again;
-		else
-			return count - tmp_count;
+		return count - tmp_count;
 	}
 
 	DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
@@ -212,7 +205,10 @@
 	return 0;
 }
 
-/* returns number of examined buffers and their common state in *state */
+/*
+ * Returns number of examined buffers and their common state in *state.
+ * Requested number of buffers-to-examine must be > 0.
+ */
 static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
 				 unsigned char *state, unsigned int count,
 				 int auto_ack, int merge_pending)
@@ -223,17 +219,23 @@
 	if (is_qebsm(q))
 		return qdio_do_eqbs(q, state, bufnr, count, auto_ack);
 
-	for (i = 0; i < count; i++) {
-		if (!__state) {
-			__state = q->slsb.val[bufnr];
-			if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
-				__state = SLSB_P_OUTPUT_EMPTY;
-		} else if (merge_pending) {
-			if ((q->slsb.val[bufnr] & __state) != __state)
-				break;
-		} else if (q->slsb.val[bufnr] != __state)
-			break;
+	/* get initial state: */
+	__state = q->slsb.val[bufnr];
+	if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
+		__state = SLSB_P_OUTPUT_EMPTY;
+
+	for (i = 1; i < count; i++) {
 		bufnr = next_buf(bufnr);
+
+		/* merge PENDING into EMPTY: */
+		if (merge_pending &&
+		    q->slsb.val[bufnr] == SLSB_P_OUTPUT_PENDING &&
+		    __state == SLSB_P_OUTPUT_EMPTY)
+			continue;
+
+		/* stop if next state differs from initial state: */
+		if (q->slsb.val[bufnr] != __state)
+			break;
 	}
 	*state = __state;
 	return i;
@@ -638,21 +640,20 @@
 	unsigned long phys_aob = 0;
 
 	if (!q->use_cq)
-		goto out;
+		return 0;
 
 	if (!q->aobs[bufnr]) {
 		struct qaob *aob = qdio_allocate_aob();
 		q->aobs[bufnr] = aob;
 	}
 	if (q->aobs[bufnr]) {
-		q->sbal_state[bufnr].flags = QDIO_OUTBUF_STATE_FLAG_NONE;
 		q->sbal_state[bufnr].aob = q->aobs[bufnr];
 		q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user;
 		phys_aob = virt_to_phys(q->aobs[bufnr]);
 		WARN_ON_ONCE(phys_aob & 0xFF);
 	}
 
-out:
+	q->sbal_state[bufnr].flags = 0;
 	return phys_aob;
 }
 
@@ -751,6 +752,7 @@
 
 	switch (state) {
 	case SLSB_P_OUTPUT_EMPTY:
+	case SLSB_P_OUTPUT_PENDING:
 		/* the adapter got it */
 		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr,
 			"out empty:%1d %02x", q->nr, count);
@@ -1574,13 +1576,13 @@
 		rc = qdio_kick_outbound_q(q, phys_aob);
 	} else if (need_siga_sync(q)) {
 		rc = qdio_siga_sync_q(q);
+	} else if (count < QDIO_MAX_BUFFERS_PER_Q &&
+		   get_buf_state(q, prev_buf(bufnr), &state, 0) > 0 &&
+		   state == SLSB_CU_OUTPUT_PRIMED) {
+		/* The previous buffer is not processed yet, tack on. */
+		qperf_inc(q, fast_requeue);
 	} else {
-		/* try to fast requeue buffers */
-		get_buf_state(q, prev_buf(bufnr), &state, 0);
-		if (state != SLSB_CU_OUTPUT_PRIMED)
-			rc = qdio_kick_outbound_q(q, 0);
-		else
-			qperf_inc(q, fast_requeue);
+		rc = qdio_kick_outbound_q(q, 0);
 	}
 
 	/* in case of SIGA errors we must process the error immediately */
--- linux-4.4.0.orig/drivers/s390/cio/qdio_setup.c
+++ linux-4.4.0/drivers/s390/cio/qdio_setup.c
@@ -140,7 +140,7 @@
 	int i;
 
 	for (i = 0; i < nr_queues; i++) {
-		q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
+		q = kmem_cache_zalloc(qdio_q_cache, GFP_KERNEL);
 		if (!q)
 			return -ENOMEM;
 
@@ -150,6 +150,7 @@
 			return -ENOMEM;
 		}
 		irq_ptr_qs[i] = q;
+		INIT_LIST_HEAD(&q->entry);
 	}
 	return 0;
 }
@@ -178,6 +179,7 @@
 	q->mask = 1 << (31 - i);
 	q->nr = i;
 	q->handler = handler;
+	INIT_LIST_HEAD(&q->entry);
 }
 
 static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
@@ -456,7 +458,6 @@
 {
 	struct ciw *ciw;
 	struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data;
-	int rc;
 
 	memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib));
 	memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag));
@@ -478,7 +479,6 @@
 	setup_queues(irq_ptr, init_data);
 
 	setup_qib(irq_ptr, init_data);
-	qdio_setup_thinint(irq_ptr);
 	set_impl_params(irq_ptr, init_data->qib_param_field_format,
 			init_data->qib_param_field,
 			init_data->input_slib_elements,
@@ -493,16 +493,14 @@
 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE);
 	if (!ciw) {
 		DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no);
-		rc = -EINVAL;
-		goto out_err;
+		return -EINVAL;
 	}
 	irq_ptr->equeue = *ciw;
 
 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE);
 	if (!ciw) {
 		DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no);
-		rc = -EINVAL;
-		goto out_err;
+		return -EINVAL;
 	}
 	irq_ptr->aqueue = *ciw;
 
@@ -510,9 +508,6 @@
 	irq_ptr->orig_handler = init_data->cdev->handler;
 	init_data->cdev->handler = qdio_int_handler;
 	return 0;
-out_err:
-	qdio_release_memory(irq_ptr);
-	return rc;
 }
 
 void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
--- linux-4.4.0.orig/drivers/s390/cio/qdio_thinint.c
+++ linux-4.4.0/drivers/s390/cio/qdio_thinint.c
@@ -80,7 +80,6 @@
 	mutex_lock(&tiq_list_lock);
 	list_add_rcu(&irq_ptr->input_qs[0]->entry, &tiq_list);
 	mutex_unlock(&tiq_list_lock);
-	xchg(irq_ptr->dsci, 1 << 7);
 }
 
 void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
@@ -88,14 +87,14 @@
 	struct qdio_q *q;
 
 	q = irq_ptr->input_qs[0];
-	/* if establish triggered an error */
-	if (!q || !q->entry.prev || !q->entry.next)
+	if (!q)
 		return;
 
 	mutex_lock(&tiq_list_lock);
 	list_del_rcu(&q->entry);
 	mutex_unlock(&tiq_list_lock);
 	synchronize_rcu();
+	INIT_LIST_HEAD(&q->entry);
 }
 
 static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr)
@@ -147,11 +146,11 @@
 	struct qdio_q *q;
 	int i;
 
-	for_each_input_queue(irq, q, i) {
-		if (!references_shared_dsci(irq) &&
-		    has_multiple_inq_on_dsci(irq))
-			xchg(q->irq_ptr->dsci, 0);
+	if (!references_shared_dsci(irq) &&
+	    has_multiple_inq_on_dsci(irq))
+		xchg(irq->dsci, 0);
 
+	for_each_input_queue(irq, q, i) {
 		if (q->u.in.queue_start_poll) {
 			/* skip if polling is enabled or already in work */
 			if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
@@ -269,17 +268,19 @@
 
 int qdio_establish_thinint(struct qdio_irq *irq_ptr)
 {
+	int rc;
+
 	if (!is_thinint_irq(irq_ptr))
 		return 0;
-	return set_subchannel_ind(irq_ptr, 0);
-}
 
-void qdio_setup_thinint(struct qdio_irq *irq_ptr)
-{
-	if (!is_thinint_irq(irq_ptr))
-		return;
 	irq_ptr->dsci = get_indicator();
 	DBF_HEX(&irq_ptr->dsci, sizeof(void *));
+
+	rc = set_subchannel_ind(irq_ptr, 0);
+	if (rc)
+		put_indicator(irq_ptr->dsci);
+
+	return rc;
 }
 
 void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)
--- linux-4.4.0.orig/drivers/s390/crypto/ap_bus.c
+++ linux-4.4.0/drivers/s390/crypto/ap_bus.c
@@ -1651,6 +1651,10 @@
 		ap_dev->queue_depth = queue_depth;
 		ap_dev->raw_hwtype = device_type;
 		ap_dev->device_type = device_type;
+		/* CEX6/CEX7 toleration: map to CEX5 */
+		if (device_type == AP_DEVICE_TYPE_CEX6 ||
+		    device_type == AP_DEVICE_TYPE_CEX7)
+			ap_dev->device_type = AP_DEVICE_TYPE_CEX5;
 		ap_dev->functions = device_functions;
 		spin_lock_init(&ap_dev->lock);
 		INIT_LIST_HEAD(&ap_dev->pendingq);
--- linux-4.4.0.orig/drivers/s390/crypto/ap_bus.h
+++ linux-4.4.0/drivers/s390/crypto/ap_bus.h
@@ -105,6 +105,8 @@
 #define AP_DEVICE_TYPE_CEX3C	9
 #define AP_DEVICE_TYPE_CEX4	10
 #define AP_DEVICE_TYPE_CEX5	11
+#define AP_DEVICE_TYPE_CEX6	12
+#define AP_DEVICE_TYPE_CEX7	13
 
 /*
  * Known function facilities
--- linux-4.4.0.orig/drivers/s390/net/ctcm_main.c
+++ linux-4.4.0/drivers/s390/net/ctcm_main.c
@@ -1595,6 +1595,7 @@
 		if (priv->channel[direction] == NULL) {
 			if (direction == CTCM_WRITE)
 				channel_free(priv->channel[CTCM_READ]);
+			result = -ENODEV;
 			goto out_dev;
 		}
 		priv->channel[direction]->netdev = dev;
--- linux-4.4.0.orig/drivers/s390/net/qeth_core.h
+++ linux-4.4.0/drivers/s390/net/qeth_core.h
@@ -591,6 +591,11 @@
 	void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *);
 };
 
+static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
+{
+	return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
+}
+
 /**
  * definition of a qeth channel, used for read and write
  */
@@ -717,6 +722,7 @@
 };
 
 struct qeth_discipline {
+	const struct device_type *devtype;
 	void (*start_poll)(struct ccw_device *, int, unsigned long);
 	qdio_handler_t *input_handler;
 	qdio_handler_t *output_handler;
@@ -844,6 +850,17 @@
 /*some helper functions*/
 #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
 
+static inline void qeth_scrub_qdio_buffer(struct qdio_buffer *buf,
+					  unsigned int elements)
+{
+	unsigned int i;
+
+	for (i = 0; i < elements; i++)
+		memset(&buf->element[i], 0, sizeof(struct qdio_buffer_element));
+	buf->element[14].sflags = 0;
+	buf->element[15].sflags = 0;
+}
+
 static inline int qeth_get_micros(void)
 {
 	return (int) (get_tod_clock() >> 12);
@@ -881,6 +898,9 @@
 extern struct qeth_discipline qeth_l3_discipline;
 extern const struct attribute_group *qeth_generic_attr_groups[];
 extern const struct attribute_group *qeth_osn_attr_groups[];
+extern const struct attribute_group qeth_device_attr_group;
+extern const struct attribute_group qeth_device_blkt_group;
+extern const struct device_type qeth_generic_devtype;
 extern struct workqueue_struct *qeth_wq;
 
 int qeth_card_hw_is_reachable(struct qeth_card *);
@@ -905,7 +925,6 @@
 int qeth_core_hardsetup_card(struct qeth_card *);
 void qeth_print_status_message(struct qeth_card *);
 int qeth_init_qdio_queues(struct qeth_card *);
-int qeth_send_startlan(struct qeth_card *);
 int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
 		  int (*reply_cb)
 		  (struct qeth_card *, struct qeth_reply *, unsigned long),
--- linux-4.4.0.orig/drivers/s390/net/qeth_core_main.c
+++ linux-4.4.0/drivers/s390/net/qeth_core_main.c
@@ -19,6 +19,8 @@
 #include <linux/mii.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
+
 #include <net/iucv/af_iucv.h>
 #include <net/dsfield.h>
 
@@ -65,9 +67,6 @@
 		struct qeth_qdio_out_buffer *buf,
 		enum iucv_tx_notify notification);
 static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf);
-static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
-		struct qeth_qdio_out_buffer *buf,
-		enum qeth_qdio_buffer_states newbufstate);
 static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
 
 struct workqueue_struct *qeth_wq;
@@ -478,6 +477,7 @@
 	struct qaob *aob;
 	struct qeth_qdio_out_buffer *buffer;
 	enum iucv_tx_notify notification;
+	unsigned int i;
 
 	aob = (struct qaob *) phys_to_virt(phys_aob_addr);
 	QETH_CARD_TEXT(card, 5, "haob");
@@ -502,10 +502,18 @@
 	qeth_notify_skbs(buffer->q, buffer, notification);
 
 	buffer->aob = NULL;
-	qeth_clear_output_buffer(buffer->q, buffer,
-				 QETH_QDIO_BUF_HANDLED_DELAYED);
+	/* Free dangling allocations. The attached skbs are handled by
+	 * qeth_cleanup_handled_pending().
+	 */
+	for (i = 0;
+	     i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card);
+	     i++) {
+		if (aob->sba[i] && buffer->is_header[i])
+			kmem_cache_free(qeth_core_header_cache,
+					(void *) aob->sba[i]);
+	}
+	atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED);
 
-	/* from here on: do not touch buffer anymore */
 	qdio_release_aob(aob);
 }
 
@@ -517,8 +525,7 @@
 	    queue == card->qdio.no_in_queues - 1;
 }
 
-
-static int qeth_issue_next_read(struct qeth_card *card)
+static int __qeth_issue_next_read(struct qeth_card *card)
 {
 	int rc;
 	struct qeth_cmd_buffer *iob;
@@ -549,6 +556,17 @@
 	return rc;
 }
 
+static int qeth_issue_next_read(struct qeth_card *card)
+{
+	int ret;
+
+	spin_lock_irq(get_ccwdev_lock(CARD_RDEV(card)));
+	ret = __qeth_issue_next_read(card);
+	spin_unlock_irq(get_ccwdev_lock(CARD_RDEV(card)));
+
+	return ret;
+}
+
 static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
 {
 	struct qeth_reply *reply;
@@ -578,7 +596,7 @@
 static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc,
 		struct qeth_card *card)
 {
-	char *ipa_name;
+	const char *ipa_name;
 	int com = cmd->hdr.command;
 	ipa_name = qeth_get_ipa_cmd_name(com);
 	if (rc)
@@ -952,7 +970,7 @@
 	spin_lock_irqsave(&card->thread_mask_lock, flags);
 	card->thread_running_mask &= ~thread;
 	spin_unlock_irqrestore(&card->thread_mask_lock, flags);
-	wake_up(&card->wait_q);
+	wake_up_all(&card->wait_q);
 }
 EXPORT_SYMBOL_GPL(qeth_clear_thread_running_bit);
 
@@ -1156,6 +1174,7 @@
 		}
 		rc = qeth_get_problem(cdev, irb);
 		if (rc) {
+			card->read_or_write_problem = 1;
 			qeth_clear_ipacmd_list(card);
 			qeth_schedule_recovery(card);
 			goto out;
@@ -1174,7 +1193,7 @@
 		return;
 	if (channel == &card->read &&
 	    channel->state == CH_STATE_UP)
-		qeth_issue_next_read(card);
+		__qeth_issue_next_read(card);
 
 	iob = channel->iob;
 	index = channel->buf_no;
@@ -2054,7 +2073,7 @@
 	unsigned long flags;
 	struct qeth_reply *reply = NULL;
 	unsigned long timeout, event_timeout;
-	struct qeth_ipa_cmd *cmd;
+	struct qeth_ipa_cmd *cmd = NULL;
 
 	QETH_CARD_TEXT(card, 2, "sendctl");
 
@@ -2068,23 +2087,27 @@
 	}
 	reply->callback = reply_cb;
 	reply->param = reply_param;
-	if (card->state == CARD_STATE_DOWN)
-		reply->seqno = QETH_IDX_COMMAND_SEQNO;
-	else
-		reply->seqno = card->seqno.ipa++;
+
 	init_waitqueue_head(&reply->wait_q);
-	spin_lock_irqsave(&card->lock, flags);
-	list_add_tail(&reply->list, &card->cmd_waiter_list);
-	spin_unlock_irqrestore(&card->lock, flags);
 	QETH_DBF_HEX(CTRL, 2, iob->data, QETH_DBF_CTRL_LEN);
 
 	while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
-	qeth_prepare_control_data(card, len, iob);
 
-	if (IS_IPA(iob->data))
+	if (IS_IPA(iob->data)) {
+		cmd = __ipa_cmd(iob);
+		cmd->hdr.seqno = card->seqno.ipa++;
+		reply->seqno = cmd->hdr.seqno;
 		event_timeout = QETH_IPA_TIMEOUT;
-	else
+	} else {
+		reply->seqno = QETH_IDX_COMMAND_SEQNO;
 		event_timeout = QETH_TIMEOUT;
+	}
+	qeth_prepare_control_data(card, len, iob);
+
+	spin_lock_irqsave(&card->lock, flags);
+	list_add_tail(&reply->list, &card->cmd_waiter_list);
+	spin_unlock_irqrestore(&card->lock, flags);
+
 	timeout = jiffies + event_timeout;
 
 	QETH_CARD_TEXT(card, 6, "noirqpnd");
@@ -2109,9 +2132,8 @@
 
 	/* we have only one long running ipassist, since we can ensure
 	   process context of this command we can sleep */
-	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
-	if ((cmd->hdr.command == IPA_CMD_SETIP) &&
-	    (cmd->hdr.prot_version == QETH_PROT_IPV4)) {
+	if (cmd && cmd->hdr.command == IPA_CMD_SETIP &&
+	    cmd->hdr.prot_version == QETH_PROT_IPV4) {
 		if (!wait_event_timeout(reply->wait_q,
 		    atomic_read(&reply->received), event_timeout))
 			goto time_err;
@@ -2438,11 +2460,12 @@
 	return rc;
 }
 
-static void qeth_free_qdio_out_buf(struct qeth_qdio_out_q *q)
+static void qeth_free_output_queue(struct qeth_qdio_out_q *q)
 {
 	if (!q)
 		return;
 
+	qeth_clear_outq_buffers(q, 1);
 	qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q);
 	kfree(q);
 }
@@ -2515,10 +2538,8 @@
 		card->qdio.out_qs[i]->bufs[j] = NULL;
 	}
 out_freeoutq:
-	while (i > 0) {
-		qeth_free_qdio_out_buf(card->qdio.out_qs[--i]);
-		qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
-	}
+	while (i > 0)
+		qeth_free_output_queue(card->qdio.out_qs[--i]);
 	kfree(card->qdio.out_qs);
 	card->qdio.out_qs = NULL;
 out_freepool:
@@ -2551,10 +2572,8 @@
 	qeth_free_buffer_pool(card);
 	/* free outbound qdio_qs */
 	if (card->qdio.out_qs) {
-		for (i = 0; i < card->qdio.no_out_queues; ++i) {
-			qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
-			qeth_free_qdio_out_buf(card->qdio.out_qs[i]);
-		}
+		for (i = 0; i < card->qdio.no_out_queues; i++)
+			qeth_free_output_queue(card->qdio.out_qs[i]);
 		kfree(card->qdio.out_qs);
 		card->qdio.out_qs = NULL;
 	}
@@ -2877,7 +2896,7 @@
 	memset(cmd, 0, sizeof(struct qeth_ipa_cmd));
 	cmd->hdr.command = command;
 	cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST;
-	cmd->hdr.seqno = card->seqno.ipa;
+	/* cmd->hdr.seqno is set by qeth_send_control_data() */
 	cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type);
 	cmd->hdr.rel_adapter_no = (__u8) card->info.portno;
 	if (card->options.layer2)
@@ -2955,7 +2974,7 @@
 }
 EXPORT_SYMBOL_GPL(qeth_send_ipa_cmd);
 
-int qeth_send_startlan(struct qeth_card *card)
+static int qeth_send_startlan(struct qeth_card *card)
 {
 	int rc;
 	struct qeth_cmd_buffer *iob;
@@ -2968,7 +2987,6 @@
 	rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(qeth_send_startlan);
 
 static int qeth_default_setadapterparms_cb(struct qeth_card *card,
 		struct qeth_reply *reply, unsigned long data)
@@ -3492,13 +3510,14 @@
 	qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
 	if (atomic_read(&queue->set_pci_flags_count))
 		qdio_flags |= QDIO_FLAG_PCI_OUT;
+	atomic_add(count, &queue->used_buffers);
+
 	rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags,
 		     queue->queue_no, index, count);
 	if (queue->card->options.performance_stats)
 		queue->card->perf_stats.outbound_do_qdio_time +=
 			qeth_get_micros() -
 			queue->card->perf_stats.outbound_do_qdio_start_time;
-	atomic_add(count, &queue->used_buffers);
 	if (rc) {
 		queue->card->stats.tx_errors += count;
 		/* ignore temporary SIGA errors without busy condition */
@@ -3630,7 +3649,8 @@
 		int e;
 
 		e = 0;
-		while (buffer->element[e].addr) {
+		while ((e < QDIO_MAX_ELEMENTS_PER_BUFFER) &&
+		       buffer->element[e].addr) {
 			unsigned long phys_aob_addr;
 
 			phys_aob_addr = (unsigned long) buffer->element[e].addr;
@@ -3729,6 +3749,10 @@
 			QETH_CARD_TEXT(queue->card, 5, "aob");
 			QETH_CARD_TEXT_(queue->card, 5, "%lx",
 					virt_to_phys(buffer->aob));
+
+			/* prepare the queue slot for re-use: */
+			qeth_scrub_qdio_buffer(buffer->buffer,
+					       QETH_MAX_BUFFER_ELEMENTS(card));
 			if (qeth_init_qdio_out_buf(queue, bidx)) {
 				QETH_CARD_TEXT(card, 2, "outofbuf");
 				qeth_schedule_recovery(card);
@@ -3823,7 +3847,7 @@
 		data = (char *)page_to_phys(skb_frag_page(frag)) +
 			frag->page_offset;
 		length = frag->size;
-		e = PFN_UP((unsigned long)data + length - 1) -
+		e = PFN_UP((unsigned long)data + length) -
 			PFN_DOWN((unsigned long)data);
 		elements += e;
 	}
@@ -3835,7 +3859,7 @@
 		     struct sk_buff *skb, int elems)
 {
 	int dlen = skb->len - skb->data_len;
-	int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) -
+	int elements_needed = PFN_UP((unsigned long)skb->data + dlen) -
 		PFN_DOWN((unsigned long)skb->data);
 
 	elements_needed += qeth_get_elements_for_frags(skb);
@@ -4505,8 +4529,8 @@
 {
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_arp_query_info *qinfo;
-	struct qeth_snmp_cmd *snmp;
 	unsigned char *data;
+	void *snmp_data;
 	__u16 data_len;
 
 	QETH_CARD_TEXT(card, 3, "snpcmdcb");
@@ -4514,7 +4538,6 @@
 	cmd = (struct qeth_ipa_cmd *) sdata;
 	data = (unsigned char *)((char *)cmd - reply->offset);
 	qinfo = (struct qeth_arp_query_info *) reply->param;
-	snmp = &cmd->data.setadapterparms.data.snmp;
 
 	if (cmd->hdr.return_code) {
 		QETH_CARD_TEXT_(card, 4, "scer1%x", cmd->hdr.return_code);
@@ -4527,10 +4550,15 @@
 		return 0;
 	}
 	data_len = *((__u16 *)QETH_IPA_PDU_LEN_PDU1(data));
-	if (cmd->data.setadapterparms.hdr.seq_no == 1)
-		data_len -= (__u16)((char *)&snmp->data - (char *)cmd);
-	else
-		data_len -= (__u16)((char *)&snmp->request - (char *)cmd);
+	if (cmd->data.setadapterparms.hdr.seq_no == 1) {
+		snmp_data = &cmd->data.setadapterparms.data.snmp;
+		data_len -= offsetof(struct qeth_ipa_cmd,
+				     data.setadapterparms.data.snmp);
+	} else {
+		snmp_data = &cmd->data.setadapterparms.data.snmp.request;
+		data_len -= offsetof(struct qeth_ipa_cmd,
+				     data.setadapterparms.data.snmp.request);
+	}
 
 	/* check if there is enough room in userspace */
 	if ((qinfo->udata_len - qinfo->udata_offset) < data_len) {
@@ -4543,16 +4571,9 @@
 	QETH_CARD_TEXT_(card, 4, "sseqn%i",
 		cmd->data.setadapterparms.hdr.seq_no);
 	/*copy entries to user buffer*/
-	if (cmd->data.setadapterparms.hdr.seq_no == 1) {
-		memcpy(qinfo->udata + qinfo->udata_offset,
-		       (char *)snmp,
-		       data_len + offsetof(struct qeth_snmp_cmd, data));
-		qinfo->udata_offset += offsetof(struct qeth_snmp_cmd, data);
-	} else {
-		memcpy(qinfo->udata + qinfo->udata_offset,
-		       (char *)&snmp->request, data_len);
-	}
+	memcpy(qinfo->udata + qinfo->udata_offset, snmp_data, data_len);
 	qinfo->udata_offset += data_len;
+
 	/* check if all replies received ... */
 		QETH_CARD_TEXT_(card, 4, "srtot%i",
 			       cmd->data.setadapterparms.hdr.used_total);
@@ -4681,7 +4702,7 @@
 
 	priv.buffer_len = oat_data.buffer_len;
 	priv.response_len = 0;
-	priv.buffer =  kzalloc(oat_data.buffer_len, GFP_KERNEL);
+	priv.buffer = vzalloc(oat_data.buffer_len);
 	if (!priv.buffer) {
 		rc = -ENOMEM;
 		goto out;
@@ -4722,7 +4743,7 @@
 			rc = -EFAULT;
 
 out_free:
-	kfree(priv.buffer);
+	vfree(priv.buffer);
 out:
 	return rc;
 }
@@ -4967,8 +4988,6 @@
 	QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 	qeth_clean_channel(&card->read);
 	qeth_clean_channel(&card->write);
-	if (card->dev)
-		free_netdev(card->dev);
 	kfree(card->ip_tbd_list);
 	qeth_free_qdio_buffers(card);
 	unregister_service_level(&card->qeth_service_level);
@@ -5080,6 +5099,20 @@
 		goto out;
 	}
 
+	rc = qeth_send_startlan(card);
+	if (rc) {
+		QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+		if (rc == IPA_RC_LAN_OFFLINE) {
+			dev_warn(&card->gdev->dev,
+				"The LAN is offline\n");
+			card->lan_online = 0;
+		} else {
+			rc = -ENODEV;
+			goto out;
+		}
+	} else
+		card->lan_online = 1;
+
 	card->options.ipa4.supported_funcs = 0;
 	card->options.ipa6.supported_funcs = 0;
 	card->options.adp.supported_funcs = 0;
@@ -5091,14 +5124,14 @@
 	if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) {
 		rc = qeth_query_setadapterparms(card);
 		if (rc < 0) {
-			QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+			QETH_DBF_TEXT_(SETUP, 2, "7err%d", rc);
 			goto out;
 		}
 	}
 	if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
 		rc = qeth_query_setdiagass(card);
 		if (rc < 0) {
-			QETH_DBF_TEXT_(SETUP, 2, "7err%d", rc);
+			QETH_DBF_TEXT_(SETUP, 2, "8err%d", rc);
 			goto out;
 		}
 	}
@@ -5449,10 +5482,12 @@
 	card->discipline = NULL;
 }
 
-static const struct device_type qeth_generic_devtype = {
+const struct device_type qeth_generic_devtype = {
 	.name = "qeth_generic",
 	.groups = qeth_generic_attr_groups,
 };
+EXPORT_SYMBOL_GPL(qeth_generic_devtype);
+
 static const struct device_type qeth_osn_devtype = {
 	.name = "qeth_osn",
 	.groups = qeth_osn_attr_groups,
@@ -5578,23 +5613,22 @@
 		goto err_card;
 	}
 
-	if (card->info.type == QETH_CARD_TYPE_OSN)
-		gdev->dev.type = &qeth_osn_devtype;
-	else
-		gdev->dev.type = &qeth_generic_devtype;
-
 	switch (card->info.type) {
 	case QETH_CARD_TYPE_OSN:
 	case QETH_CARD_TYPE_OSM:
 		rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
 		if (rc)
 			goto err_card;
+
+		gdev->dev.type = (card->info.type != QETH_CARD_TYPE_OSN)
+					? card->discipline->devtype
+					: &qeth_osn_devtype;
 		rc = card->discipline->setup(card->gdev);
 		if (rc)
 			goto err_disc;
-	case QETH_CARD_TYPE_OSD:
-	case QETH_CARD_TYPE_OSX:
+		break;
 	default:
+		gdev->dev.type = &qeth_generic_devtype;
 		break;
 	}
 
@@ -5650,8 +5684,10 @@
 		if (rc)
 			goto err;
 		rc = card->discipline->setup(card->gdev);
-		if (rc)
+		if (rc) {
+			qeth_core_free_discipline(card);
 			goto err;
+		}
 	}
 	rc = card->discipline->set_online(gdev);
 err:
--- linux-4.4.0.orig/drivers/s390/net/qeth_core_mpc.c
+++ linux-4.4.0/drivers/s390/net/qeth_core_mpc.c
@@ -158,10 +158,10 @@
 
 struct ipa_rc_msg {
 	enum qeth_ipa_return_codes rc;
-	char *msg;
+	const char *msg;
 };
 
-static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
+static const struct ipa_rc_msg qeth_ipa_rc_msg[] = {
 	{IPA_RC_SUCCESS,		"success"},
 	{IPA_RC_NOTSUPP,		"Command not supported"},
 	{IPA_RC_IP_TABLE_FULL,		"Add Addr IP Table Full - ipv6"},
@@ -212,23 +212,23 @@
 
 
 
-char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc)
+const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc)
 {
-	int x = 0;
-	qeth_ipa_rc_msg[sizeof(qeth_ipa_rc_msg) /
-			sizeof(struct ipa_rc_msg) - 1].rc = rc;
-	while (qeth_ipa_rc_msg[x].rc != rc)
-		x++;
+	int x;
+
+	for (x = 0; x < ARRAY_SIZE(qeth_ipa_rc_msg) - 1; x++)
+		if (qeth_ipa_rc_msg[x].rc == rc)
+			return qeth_ipa_rc_msg[x].msg;
 	return qeth_ipa_rc_msg[x].msg;
 }
 
 
 struct ipa_cmd_names {
 	enum qeth_ipa_cmds cmd;
-	char *name;
+	const char *name;
 };
 
-static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
+static const struct ipa_cmd_names qeth_ipa_cmd_names[] = {
 	{IPA_CMD_STARTLAN,	"startlan"},
 	{IPA_CMD_STOPLAN,	"stoplan"},
 	{IPA_CMD_SETVMAC,	"setvmac"},
@@ -259,13 +259,12 @@
 	{IPA_CMD_UNKNOWN,	"unknown"},
 };
 
-char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd)
+const char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd)
 {
-	int x = 0;
-	qeth_ipa_cmd_names[
-		sizeof(qeth_ipa_cmd_names) /
-			sizeof(struct ipa_cmd_names)-1].cmd = cmd;
-	while (qeth_ipa_cmd_names[x].cmd != cmd)
-		x++;
+	int x;
+
+	for (x = 0; x < ARRAY_SIZE(qeth_ipa_cmd_names) - 1; x++)
+		if (qeth_ipa_cmd_names[x].cmd == cmd)
+			return qeth_ipa_cmd_names[x].name;
 	return qeth_ipa_cmd_names[x].name;
 }
--- linux-4.4.0.orig/drivers/s390/net/qeth_core_mpc.h
+++ linux-4.4.0/drivers/s390/net/qeth_core_mpc.h
@@ -686,8 +686,8 @@
 	QETH_IPA_ARP_RC_Q_NO_DATA    = 0x0008,
 };
 
-extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
-extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
+extern const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
+extern const char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
 
 #define QETH_SETASS_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
 			       sizeof(struct qeth_ipacmd_setassparms_hdr))
--- linux-4.4.0.orig/drivers/s390/net/qeth_core_sys.c
+++ linux-4.4.0/drivers/s390/net/qeth_core_sys.c
@@ -409,12 +409,17 @@
 
 	if (card->options.layer2 == newdis)
 		goto out;
-	else {
-		card->info.mac_bits  = 0;
-		if (card->discipline) {
-			card->discipline->remove(card->gdev);
-			qeth_core_free_discipline(card);
-		}
+	if (card->info.type == QETH_CARD_TYPE_OSM) {
+		/* fixed layer, can't switch */
+		rc = -EOPNOTSUPP;
+		goto out;
+	}
+
+	card->info.mac_bits = 0;
+	if (card->discipline) {
+		card->discipline->remove(card->gdev);
+		qeth_core_free_discipline(card);
+		card->options.layer2 = -1;
 	}
 
 	rc = qeth_core_load_discipline(card, newdis);
@@ -422,6 +427,8 @@
 		goto out;
 
 	rc = card->discipline->setup(card->gdev);
+	if (rc)
+		qeth_core_free_discipline(card);
 out:
 	mutex_unlock(&card->discipline_mutex);
 	return rc ? rc : count;
@@ -699,10 +706,11 @@
 	&dev_attr_inter_jumbo.attr,
 	NULL,
 };
-static struct attribute_group qeth_device_blkt_group = {
+const struct attribute_group qeth_device_blkt_group = {
 	.name = "blkt",
 	.attrs = qeth_blkt_device_attrs,
 };
+EXPORT_SYMBOL_GPL(qeth_device_blkt_group);
 
 static struct attribute *qeth_device_attrs[] = {
 	&dev_attr_state.attr,
@@ -722,9 +730,10 @@
 	&dev_attr_switch_attrs.attr,
 	NULL,
 };
-static struct attribute_group qeth_device_attr_group = {
+const struct attribute_group qeth_device_attr_group = {
 	.attrs = qeth_device_attrs,
 };
+EXPORT_SYMBOL_GPL(qeth_device_attr_group);
 
 const struct attribute_group *qeth_generic_attr_groups[] = {
 	&qeth_device_attr_group,
--- linux-4.4.0.orig/drivers/s390/net/qeth_l2.h
+++ linux-4.4.0/drivers/s390/net/qeth_l2.h
@@ -8,6 +8,8 @@
 
 #include "qeth_core.h"
 
+extern const struct attribute_group *qeth_l2_attr_groups[];
+
 int qeth_l2_create_device_attributes(struct device *);
 void qeth_l2_remove_device_attributes(struct device *);
 void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
--- linux-4.4.0.orig/drivers/s390/net/qeth_l2_main.c
+++ linux-4.4.0/drivers/s390/net/qeth_l2_main.c
@@ -523,7 +523,7 @@
 		default:
 			dev_kfree_skb_any(skb);
 			QETH_CARD_TEXT(card, 3, "inbunkno");
-			QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
+			QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr));
 			continue;
 		}
 		work_done++;
@@ -996,7 +996,10 @@
 
 	if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
 		napi_enable(&card->napi);
+		local_bh_disable();
 		napi_schedule(&card->napi);
+		/* kick-start the NAPI softirq: */
+		local_bh_enable();
 	} else
 		rc = -EIO;
 	return rc;
@@ -1027,11 +1030,21 @@
 	return 0;
 }
 
+static const struct device_type qeth_l2_devtype = {
+	.name = "qeth_layer2",
+	.groups = qeth_l2_attr_groups,
+};
+
 static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
 {
 	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+	int rc;
 
-	qeth_l2_create_device_attributes(&gdev->dev);
+	if (gdev->dev.type == &qeth_generic_devtype) {
+		rc = qeth_l2_create_device_attributes(&gdev->dev);
+		if (rc)
+			return rc;
+	}
 	INIT_LIST_HEAD(&card->vid_list);
 	hash_init(card->mac_htable);
 	card->options.layer2 = 1;
@@ -1043,7 +1056,8 @@
 {
 	struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
 
-	qeth_l2_remove_device_attributes(&cgdev->dev);
+	if (cgdev->dev.type == &qeth_generic_devtype)
+		qeth_l2_remove_device_attributes(&cgdev->dev);
 	qeth_set_allowed_threads(card, 0, 1);
 	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
 
@@ -1052,6 +1066,7 @@
 
 	if (card->dev) {
 		unregister_netdev(card->dev);
+		free_netdev(card->dev);
 		card->dev = NULL;
 	}
 	return;
@@ -1100,7 +1115,6 @@
 	case QETH_CARD_TYPE_OSN:
 		card->dev = alloc_netdev(0, "osn%d", NET_NAME_UNKNOWN,
 					 ether_setup);
-		card->dev->flags |= IFF_NOARP;
 		break;
 	default:
 		card->dev = alloc_etherdev(0);
@@ -1113,9 +1127,12 @@
 	card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
 	card->dev->mtu = card->info.initial_mtu;
 	card->dev->netdev_ops = &qeth_l2_netdev_ops;
-	card->dev->ethtool_ops =
-		(card->info.type != QETH_CARD_TYPE_OSN) ?
-		&qeth_l2_ethtool_ops : &qeth_l2_osn_ops;
+	if (card->info.type == QETH_CARD_TYPE_OSN) {
+		card->dev->ethtool_ops = &qeth_l2_osn_ops;
+		card->dev->flags |= IFF_NOARP;
+	} else {
+		card->dev->ethtool_ops = &qeth_l2_ethtool_ops;
+	}
 	card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 	if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) {
 		card->dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
@@ -1126,6 +1143,7 @@
 	qeth_l2_request_initial_mac(card);
 	SET_NETDEV_DEV(card->dev, &card->gdev->dev);
 	netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
+	netif_carrier_off(card->dev);
 	return register_netdev(card->dev);
 }
 
@@ -1188,21 +1206,6 @@
 	/* softsetup */
 	QETH_DBF_TEXT(SETUP, 2, "softsetp");
 
-	rc = qeth_send_startlan(card);
-	if (rc) {
-		QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
-		if (rc == 0xe080) {
-			dev_warn(&card->gdev->dev,
-				"The LAN is offline\n");
-			card->lan_online = 0;
-			goto contin;
-		}
-		rc = -ENODEV;
-		goto out_remove;
-	} else
-		card->lan_online = 1;
-
-contin:
 	if ((card->info.type == QETH_CARD_TYPE_OSD) ||
 	    (card->info.type == QETH_CARD_TYPE_OSX)) {
 		if (qeth_l2_start_ipassists(card))
@@ -1427,6 +1430,7 @@
 }
 
 struct qeth_discipline qeth_l2_discipline = {
+	.devtype = &qeth_l2_devtype,
 	.start_poll = qeth_qdio_start_poll,
 	.input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
 	.output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
@@ -1665,6 +1669,10 @@
 	int extrasize;
 
 	QETH_CARD_TEXT(card, 2, "brstchng");
+	if (qports->num_entries == 0) {
+		QETH_CARD_TEXT(card, 2, "BPempty");
+		return;
+	}
 	if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
 		QETH_CARD_TEXT_(card, 2, "BPsz%04x", qports->entry_length);
 		return;
@@ -2111,7 +2119,7 @@
 
 	l2entry = (struct qdio_brinfo_entry_l2 *)entry;
 	code = IPA_ADDR_CHANGE_CODE_MACADDR;
-	if (l2entry->addr_lnid.lnid)
+	if (l2entry->addr_lnid.lnid < VLAN_N_VID)
 		code |= IPA_ADDR_CHANGE_CODE_VLANID;
 	qeth_bridge_emit_host_event(card, anev_reg_unreg, code,
 		(struct net_if_token *)&l2entry->nit,
--- linux-4.4.0.orig/drivers/s390/net/qeth_l2_sys.c
+++ linux-4.4.0/drivers/s390/net/qeth_l2_sys.c
@@ -272,3 +272,11 @@
 	} else
 		qeth_bridgeport_an_set(card, 0);
 }
+
+const struct attribute_group *qeth_l2_attr_groups[] = {
+	&qeth_device_attr_group,
+	&qeth_device_blkt_group,
+	/* l2 specific, see l2_{create,remove}_device_attributes(): */
+	&qeth_l2_bridgeport_attr_group,
+	NULL,
+};
--- linux-4.4.0.orig/drivers/s390/net/qeth_l3_main.c
+++ linux-4.4.0/drivers/s390/net/qeth_l3_main.c
@@ -1902,7 +1902,7 @@
 		default:
 			dev_kfree_skb_any(skb);
 			QETH_CARD_TEXT(card, 3, "inbunkno");
-			QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
+			QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr));
 			continue;
 		}
 		work_done++;
@@ -2680,17 +2680,13 @@
 	char daddr[16];
 	struct af_iucv_trans_hdr *iucv_hdr;
 
-	skb_pull(skb, 14);
-	card->dev->header_ops->create(skb, card->dev, 0,
-				      card->dev->dev_addr, card->dev->dev_addr,
-				      card->dev->addr_len);
-	skb_pull(skb, 14);
-	iucv_hdr = (struct af_iucv_trans_hdr *)skb->data;
 	memset(hdr, 0, sizeof(struct qeth_hdr));
 	hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
 	hdr->hdr.l3.ext_flags = 0;
-	hdr->hdr.l3.length = skb->len;
+	hdr->hdr.l3.length = skb->len - ETH_HLEN;
 	hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
+
+	iucv_hdr = (struct af_iucv_trans_hdr *) (skb->data + ETH_HLEN);
 	memset(daddr, 0, sizeof(daddr));
 	daddr[0] = 0xfe;
 	daddr[1] = 0x80;
@@ -2727,7 +2723,7 @@
 		struct rtable *rt = (struct rtable *) dst;
 		__be32 *pkey = &ip_hdr(skb)->daddr;
 
-		if (rt->rt_gateway)
+		if (rt && rt->rt_gateway)
 			pkey = &rt->rt_gateway;
 
 		/* IPv4 */
@@ -2738,7 +2734,7 @@
 		struct rt6_info *rt = (struct rt6_info *) dst;
 		struct in6_addr *pkey = &ipv6_hdr(skb)->daddr;
 
-		if (!ipv6_addr_any(&rt->rt6i_gateway))
+		if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
 			pkey = &rt->rt6i_gateway;
 
 		/* IPv6 */
@@ -2819,7 +2815,7 @@
 	unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
 		tcp_hdr(skb)->doff * 4;
 	int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);
-	int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd);
+	int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd);
 
 	elements += qeth_get_elements_for_frags(skb);
 
@@ -2873,10 +2869,7 @@
 	if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
 	    (skb_shinfo(skb)->nr_frags == 0)) {
 		new_skb = skb;
-		if (new_skb->protocol == ETH_P_AF_IUCV)
-			data_offset = 0;
-		else
-			data_offset = ETH_HLEN;
+		data_offset = ETH_HLEN;
 		hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);
 		if (!hdr)
 			goto tx_drop;
@@ -3038,7 +3031,10 @@
 
 	if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
 		napi_enable(&card->napi);
+		local_bh_disable();
 		napi_schedule(&card->napi);
+		/* kick-start the NAPI softirq: */
+		local_bh_enable();
 	} else
 		rc = -EIO;
 	return rc;
@@ -3220,14 +3216,18 @@
 
 	SET_NETDEV_DEV(card->dev, &card->gdev->dev);
 	netif_napi_add(card->dev, &card->napi, qeth_l3_poll, QETH_NAPI_WEIGHT);
+	netif_carrier_off(card->dev);
 	return register_netdev(card->dev);
 }
 
 static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
 {
 	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+	int rc;
 
-	qeth_l3_create_device_attributes(&gdev->dev);
+	rc = qeth_l3_create_device_attributes(&gdev->dev);
+	if (rc)
+		return rc;
 	card->options.layer2 = 0;
 	card->info.hwtrap = 0;
 	return 0;
@@ -3247,6 +3247,7 @@
 
 	if (card->dev) {
 		unregister_netdev(card->dev);
+		free_netdev(card->dev);
 		card->dev = NULL;
 	}
 
@@ -3293,21 +3294,6 @@
 	/* softsetup */
 	QETH_DBF_TEXT(SETUP, 2, "softsetp");
 
-	rc = qeth_send_startlan(card);
-	if (rc) {
-		QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
-		if (rc == 0xe080) {
-			dev_warn(&card->gdev->dev,
-				"The LAN is offline\n");
-			card->lan_online = 0;
-			goto contin;
-		}
-		rc = -ENODEV;
-		goto out_remove;
-	} else
-		card->lan_online = 1;
-
-contin:
 	rc = qeth_l3_setadapter_parms(card);
 	if (rc)
 		QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
@@ -3517,6 +3503,7 @@
 }
 
 struct qeth_discipline qeth_l3_discipline = {
+	.devtype = &qeth_generic_devtype,
 	.start_poll = qeth_qdio_start_poll,
 	.input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
 	.output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_aux.c
+++ linux-4.4.0/drivers/s390/scsi/zfcp_aux.c
@@ -275,16 +275,16 @@
  */
 int zfcp_status_read_refill(struct zfcp_adapter *adapter)
 {
-	while (atomic_read(&adapter->stat_miss) > 0)
+	while (atomic_add_unless(&adapter->stat_miss, -1, 0))
 		if (zfcp_fsf_status_read(adapter->qdio)) {
+			atomic_inc(&adapter->stat_miss); /* undo add -1 */
 			if (atomic_read(&adapter->stat_miss) >=
 			    adapter->stat_read_buf_num) {
 				zfcp_erp_adapter_reopen(adapter, 0, "axsref1");
 				return 1;
 			}
 			break;
-		} else
-			atomic_dec(&adapter->stat_miss);
+		}
 	return 0;
 }
 
@@ -358,6 +358,8 @@
 
 	adapter->next_port_scan = jiffies;
 
+	adapter->erp_action.adapter = adapter;
+
 	if (zfcp_qdio_setup(adapter))
 		goto failed;
 
@@ -514,6 +516,9 @@
 	port->dev.groups = zfcp_port_attr_groups;
 	port->dev.release = zfcp_port_release;
 
+	port->erp_action.adapter = adapter;
+	port->erp_action.port = port;
+
 	if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) {
 		kfree(port);
 		goto err_out;
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_dbf.c
+++ linux-4.4.0/drivers/s390/scsi/zfcp_dbf.c
@@ -3,7 +3,7 @@
  *
  * Debug traces for zfcp.
  *
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2018
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -65,7 +65,7 @@
  * @tag: tag indicating which kind of unsolicited status has been received
  * @req: request for which a response was received
  */
-void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
+void zfcp_dbf_hba_fsf_res(char *tag, int level, struct zfcp_fsf_req *req)
 {
 	struct zfcp_dbf *dbf = req->adapter->dbf;
 	struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix;
@@ -85,19 +85,19 @@
 	rec->u.res.req_issued = req->issued;
 	rec->u.res.prot_status = q_pref->prot_status;
 	rec->u.res.fsf_status = q_head->fsf_status;
+	rec->u.res.port_handle = q_head->port_handle;
+	rec->u.res.lun_handle = q_head->lun_handle;
 
 	memcpy(rec->u.res.prot_status_qual, &q_pref->prot_status_qual,
 	       FSF_PROT_STATUS_QUAL_SIZE);
 	memcpy(rec->u.res.fsf_status_qual, &q_head->fsf_status_qual,
 	       FSF_STATUS_QUALIFIER_SIZE);
 
-	if (req->fsf_command != FSF_QTCB_FCP_CMND) {
-		rec->pl_len = q_head->log_length;
-		zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start,
-				  rec->pl_len, "fsf_res", req->req_id);
-	}
+	rec->pl_len = q_head->log_length;
+	zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start,
+			  rec->pl_len, "fsf_res", req->req_id);
 
-	debug_event(dbf->hba, 1, rec, sizeof(*rec));
+	debug_event(dbf->hba, level, rec, sizeof(*rec));
 	spin_unlock_irqrestore(&dbf->hba_lock, flags);
 }
 
@@ -241,7 +241,8 @@
 	if (sdev) {
 		rec->lun_status = atomic_read(&sdev_to_zfcp(sdev)->status);
 		rec->lun = zfcp_scsi_dev_lun(sdev);
-	}
+	} else
+		rec->lun = ZFCP_DBF_INVALID_LUN;
 }
 
 /**
@@ -284,13 +285,35 @@
 	spin_unlock_irqrestore(&dbf->rec_lock, flags);
 }
 
+/**
+ * zfcp_dbf_rec_trig_lock - trace event related to triggered recovery with lock
+ * @tag: identifier for event
+ * @adapter: adapter on which the erp_action should run
+ * @port: remote port involved in the erp_action
+ * @sdev: scsi device involved in the erp_action
+ * @want: wanted erp_action
+ * @need: required erp_action
+ *
+ * The adapter->erp_lock must not be held.
+ */
+void zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter,
+			    struct zfcp_port *port, struct scsi_device *sdev,
+			    u8 want, u8 need)
+{
+	unsigned long flags;
+
+	read_lock_irqsave(&adapter->erp_lock, flags);
+	zfcp_dbf_rec_trig(tag, adapter, port, sdev, want, need);
+	read_unlock_irqrestore(&adapter->erp_lock, flags);
+}
 
 /**
- * zfcp_dbf_rec_run - trace event related to running recovery
+ * zfcp_dbf_rec_run_lvl - trace event related to running recovery
+ * @level: trace level to be used for event
  * @tag: identifier for event
  * @erp: erp_action running
  */
-void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
+void zfcp_dbf_rec_run_lvl(int level, char *tag, struct zfcp_erp_action *erp)
 {
 	struct zfcp_dbf *dbf = erp->adapter->dbf;
 	struct zfcp_dbf_rec *rec = &dbf->rec_buf;
@@ -316,17 +339,62 @@
 	else
 		rec->u.run.rec_count = atomic_read(&erp->adapter->erp_counter);
 
+	debug_event(dbf->rec, level, rec, sizeof(*rec));
+	spin_unlock_irqrestore(&dbf->rec_lock, flags);
+}
+
+/**
+ * zfcp_dbf_rec_run - trace event related to running recovery
+ * @tag: identifier for event
+ * @erp: erp_action running
+ */
+void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
+{
+	zfcp_dbf_rec_run_lvl(1, tag, erp);
+}
+
+/**
+ * zfcp_dbf_rec_run_wka - trace wka port event with info like running recovery
+ * @tag: identifier for event
+ * @wka_port: well known address port
+ * @req_id: request ID to correlate with potential HBA trace record
+ */
+void zfcp_dbf_rec_run_wka(char *tag, struct zfcp_fc_wka_port *wka_port,
+			  u64 req_id)
+{
+	struct zfcp_dbf *dbf = wka_port->adapter->dbf;
+	struct zfcp_dbf_rec *rec = &dbf->rec_buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dbf->rec_lock, flags);
+	memset(rec, 0, sizeof(*rec));
+
+	rec->id = ZFCP_DBF_REC_RUN;
+	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+	rec->port_status = wka_port->status;
+	rec->d_id = wka_port->d_id;
+	rec->lun = ZFCP_DBF_INVALID_LUN;
+
+	rec->u.run.fsf_req_id = req_id;
+	rec->u.run.rec_status = ~0;
+	rec->u.run.rec_step = ~0;
+	rec->u.run.rec_action = ~0;
+	rec->u.run.rec_count = ~0;
+
 	debug_event(dbf->rec, 1, rec, sizeof(*rec));
 	spin_unlock_irqrestore(&dbf->rec_lock, flags);
 }
 
 static inline
-void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len,
-		  u64 req_id, u32 d_id)
+void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf,
+		  char *paytag, struct scatterlist *sg, u8 id, u16 len,
+		  u64 req_id, u32 d_id, u16 cap_len)
 {
 	struct zfcp_dbf_san *rec = &dbf->san_buf;
 	u16 rec_len;
 	unsigned long flags;
+	struct zfcp_dbf_pay *payload = &dbf->pay_buf;
+	u16 pay_sum = 0;
 
 	spin_lock_irqsave(&dbf->san_lock, flags);
 	memset(rec, 0, sizeof(*rec));
@@ -334,10 +402,41 @@
 	rec->id = id;
 	rec->fsf_req_id = req_id;
 	rec->d_id = d_id;
-	rec_len = min(len, (u16)ZFCP_DBF_SAN_MAX_PAYLOAD);
-	memcpy(rec->payload, data, rec_len);
 	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+	rec->pl_len = len; /* full length even if we cap pay below */
+	if (!sg)
+		goto out;
+	rec_len = min_t(unsigned int, sg->length, ZFCP_DBF_SAN_MAX_PAYLOAD);
+	memcpy(rec->payload, sg_virt(sg), rec_len); /* part of 1st sg entry */
+	if (len <= rec_len)
+		goto out; /* skip pay record if full content in rec->payload */
+
+	/* if (len > rec_len):
+	 * dump data up to cap_len ignoring small duplicate in rec->payload
+	 */
+	spin_lock(&dbf->pay_lock);
+	memset(payload, 0, sizeof(*payload));
+	memcpy(payload->area, paytag, ZFCP_DBF_TAG_LEN);
+	payload->fsf_req_id = req_id;
+	payload->counter = 0;
+	for (; sg && pay_sum < cap_len; sg = sg_next(sg)) {
+		u16 pay_len, offset = 0;
 
+		while (offset < sg->length && pay_sum < cap_len) {
+			pay_len = min((u16)ZFCP_DBF_PAY_MAX_REC,
+				      (u16)(sg->length - offset));
+			/* cap_len <= pay_sum < cap_len+ZFCP_DBF_PAY_MAX_REC */
+			memcpy(payload->data, sg_virt(sg) + offset, pay_len);
+			debug_event(dbf->pay, 1, payload,
+				    zfcp_dbf_plen(pay_len));
+			payload->counter++;
+			offset += pay_len;
+			pay_sum += pay_len;
+		}
+	}
+	spin_unlock(&dbf->pay_lock);
+
+out:
 	debug_event(dbf->san, 1, rec, sizeof(*rec));
 	spin_unlock_irqrestore(&dbf->san_lock, flags);
 }
@@ -354,9 +453,70 @@
 	struct zfcp_fsf_ct_els *ct_els = fsf->data;
 	u16 length;
 
-	length = (u16)(ct_els->req->length + FC_CT_HDR_LEN);
-	zfcp_dbf_san(tag, dbf, sg_virt(ct_els->req), ZFCP_DBF_SAN_REQ, length,
-		     fsf->req_id, d_id);
+	length = (u16)zfcp_qdio_real_bytes(ct_els->req);
+	zfcp_dbf_san(tag, dbf, "san_req", ct_els->req, ZFCP_DBF_SAN_REQ,
+		     length, fsf->req_id, d_id, length);
+}
+
+static u16 zfcp_dbf_san_res_cap_len_if_gpn_ft(char *tag,
+					      struct zfcp_fsf_req *fsf,
+					      u16 len)
+{
+	struct zfcp_fsf_ct_els *ct_els = fsf->data;
+	struct fc_ct_hdr *reqh = sg_virt(ct_els->req);
+	struct fc_ns_gid_ft *reqn = (struct fc_ns_gid_ft *)(reqh + 1);
+	struct scatterlist *resp_entry = ct_els->resp;
+	struct fc_ct_hdr *resph;
+	struct fc_gpn_ft_resp *acc;
+	int max_entries, x, last = 0;
+
+	if (!(memcmp(tag, "fsscth2", 7) == 0
+	      && ct_els->d_id == FC_FID_DIR_SERV
+	      && reqh->ct_rev == FC_CT_REV
+	      && reqh->ct_in_id[0] == 0
+	      && reqh->ct_in_id[1] == 0
+	      && reqh->ct_in_id[2] == 0
+	      && reqh->ct_fs_type == FC_FST_DIR
+	      && reqh->ct_fs_subtype == FC_NS_SUBTYPE
+	      && reqh->ct_options == 0
+	      && reqh->_ct_resvd1 == 0
+	      && reqh->ct_cmd == FC_NS_GPN_FT
+	      /* reqh->ct_mr_size can vary so do not match but read below */
+	      && reqh->_ct_resvd2 == 0
+	      && reqh->ct_reason == 0
+	      && reqh->ct_explan == 0
+	      && reqh->ct_vendor == 0
+	      && reqn->fn_resvd == 0
+	      && reqn->fn_domain_id_scope == 0
+	      && reqn->fn_area_id_scope == 0
+	      && reqn->fn_fc4_type == FC_TYPE_FCP))
+		return len; /* not GPN_FT response so do not cap */
+
+	acc = sg_virt(resp_entry);
+
+	/* cap all but accept CT responses to at least the CT header */
+	resph = (struct fc_ct_hdr *)acc;
+	if ((ct_els->status) ||
+	    (resph->ct_cmd != cpu_to_be16(FC_FS_ACC)))
+		return max(FC_CT_HDR_LEN, ZFCP_DBF_SAN_MAX_PAYLOAD);
+
+	max_entries = (reqh->ct_mr_size * 4 / sizeof(struct fc_gpn_ft_resp))
+		+ 1 /* zfcp_fc_scan_ports: bytes correct, entries off-by-one
+		     * to account for header as 1st pseudo "entry" */;
+
+	/* the basic CT_IU preamble is the same size as one entry in the GPN_FT
+	 * response, allowing us to skip special handling for it - just skip it
+	 */
+	for (x = 1; x < max_entries && !last; x++) {
+		if (x % (ZFCP_FC_GPN_FT_ENT_PAGE + 1))
+			acc++;
+		else
+			acc = sg_virt(++resp_entry);
+
+		last = acc->fp_flags & FC_NS_FID_LAST;
+	}
+	len = min(len, (u16)(x * sizeof(struct fc_gpn_ft_resp)));
+	return len; /* cap after last entry */
 }
 
 /**
@@ -370,9 +530,10 @@
 	struct zfcp_fsf_ct_els *ct_els = fsf->data;
 	u16 length;
 
-	length = (u16)(ct_els->resp->length + FC_CT_HDR_LEN);
-	zfcp_dbf_san(tag, dbf, sg_virt(ct_els->resp), ZFCP_DBF_SAN_RES, length,
-		     fsf->req_id, 0);
+	length = (u16)zfcp_qdio_real_bytes(ct_els->resp);
+	zfcp_dbf_san(tag, dbf, "san_res", ct_els->resp, ZFCP_DBF_SAN_RES,
+		     length, fsf->req_id, ct_els->d_id,
+		     zfcp_dbf_san_res_cap_len_if_gpn_ft(tag, fsf, length));
 }
 
 /**
@@ -386,11 +547,13 @@
 	struct fsf_status_read_buffer *srb =
 		(struct fsf_status_read_buffer *) fsf->data;
 	u16 length;
+	struct scatterlist sg;
 
 	length = (u16)(srb->length -
 			offsetof(struct fsf_status_read_buffer, payload));
-	zfcp_dbf_san(tag, dbf, srb->payload.data, ZFCP_DBF_SAN_ELS, length,
-		     fsf->req_id, ntoh24(srb->d_id));
+	sg_init_one(&sg, srb->payload.data, length);
+	zfcp_dbf_san(tag, dbf, "san_els", &sg, ZFCP_DBF_SAN_ELS, length,
+		     fsf->req_id, ntoh24(srb->d_id), length);
 }
 
 /**
@@ -399,7 +562,8 @@
  * @sc: pointer to struct scsi_cmnd
  * @fsf: pointer to struct zfcp_fsf_req
  */
-void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)
+void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc,
+		   struct zfcp_fsf_req *fsf)
 {
 	struct zfcp_adapter *adapter =
 		(struct zfcp_adapter *) sc->device->host->hostdata[0];
@@ -418,8 +582,8 @@
 	rec->scsi_retries = sc->retries;
 	rec->scsi_allowed = sc->allowed;
 	rec->scsi_id = sc->device->id;
-	/* struct zfcp_dbf_scsi needs to be updated to handle 64bit LUNs */
 	rec->scsi_lun = (u32)sc->device->lun;
+	rec->scsi_lun_64_hi = (u32)(sc->device->lun >> 32);
 	rec->host_scribble = (unsigned long)sc->host_scribble;
 
 	memcpy(rec->scsi_opcode, sc->cmnd,
@@ -427,22 +591,75 @@
 
 	if (fsf) {
 		rec->fsf_req_id = fsf->req_id;
+		rec->pl_len = FCP_RESP_WITH_EXT;
 		fcp_rsp = (struct fcp_resp_with_ext *)
 				&(fsf->qtcb->bottom.io.fcp_rsp);
+		/* mandatory parts of FCP_RSP IU in this SCSI record */
 		memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT);
 		if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) {
 			fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
 			rec->fcp_rsp_info = fcp_rsp_info->rsp_code;
+			rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_rsp_len);
 		}
 		if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
-			rec->pl_len = min((u16)SCSI_SENSE_BUFFERSIZE,
-					  (u16)ZFCP_DBF_PAY_MAX_REC);
-			zfcp_dbf_pl_write(dbf, sc->sense_buffer, rec->pl_len,
-					  "fcp_sns", fsf->req_id);
+			rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_sns_len);
 		}
+		/* complete FCP_RSP IU in associated PAYload record
+		 * but only if there are optional parts
+		 */
+		if (fcp_rsp->resp.fr_flags != 0)
+			zfcp_dbf_pl_write(
+				dbf, fcp_rsp,
+				/* at least one full PAY record
+				 * but not beyond hardware response field
+				 */
+				min_t(u16, max_t(u16, rec->pl_len,
+						 ZFCP_DBF_PAY_MAX_REC),
+				      FSF_FCP_RSP_SIZE),
+				"fcp_riu", fsf->req_id);
 	}
 
-	debug_event(dbf->scsi, 1, rec, sizeof(*rec));
+	debug_event(dbf->scsi, level, rec, sizeof(*rec));
+	spin_unlock_irqrestore(&dbf->scsi_lock, flags);
+}
+
+/**
+ * zfcp_dbf_scsi_eh() - Trace event for special cases of scsi_eh callbacks.
+ * @tag: Identifier for event.
+ * @adapter: Pointer to zfcp adapter as context for this event.
+ * @scsi_id: SCSI ID/target to indicate scope of task management function (TMF).
+ * @ret: Return value of calling function.
+ *
+ * This SCSI trace variant does not depend on any of:
+ * scsi_cmnd, zfcp_fsf_req, scsi_device.
+ */
+void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter,
+		      unsigned int scsi_id, int ret)
+{
+	struct zfcp_dbf *dbf = adapter->dbf;
+	struct zfcp_dbf_scsi *rec = &dbf->scsi_buf;
+	unsigned long flags;
+	static int const level = 1;
+
+	if (unlikely(!debug_level_enabled(adapter->dbf->scsi, level)))
+		return;
+
+	spin_lock_irqsave(&dbf->scsi_lock, flags);
+	memset(rec, 0, sizeof(*rec));
+
+	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+	rec->id = ZFCP_DBF_SCSI_CMND;
+	rec->scsi_result = ret; /* re-use field, int is 4 bytes and fits */
+	rec->scsi_retries = ~0;
+	rec->scsi_allowed = ~0;
+	rec->fcp_rsp_info = ~0;
+	rec->scsi_id = scsi_id;
+	rec->scsi_lun = (u32)ZFCP_DBF_INVALID_LUN;
+	rec->scsi_lun_64_hi = (u32)(ZFCP_DBF_INVALID_LUN >> 32);
+	rec->host_scribble = ~0;
+	memset(rec->scsi_opcode, 0xff, ZFCP_DBF_SCSI_OPCODE);
+
+	debug_event(dbf->scsi, level, rec, sizeof(*rec));
 	spin_unlock_irqrestore(&dbf->scsi_lock, flags);
 }
 
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_dbf.h
+++ linux-4.4.0/drivers/s390/scsi/zfcp_dbf.h
@@ -2,7 +2,7 @@
  * zfcp device driver
  * debug feature declarations
  *
- * Copyright IBM Corp. 2008, 2010
+ * Copyright IBM Corp. 2008, 2017
  */
 
 #ifndef ZFCP_DBF_H
@@ -17,6 +17,11 @@
 
 #define ZFCP_DBF_INVALID_LUN	0xFFFFFFFFFFFFFFFFull
 
+enum zfcp_dbf_pseudo_erp_act_type {
+	ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD = 0xff,
+	ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL = 0xfe,
+};
+
 /**
  * struct zfcp_dbf_rec_trigger - trace record for triggered recovery action
  * @ready: number of ready recovery actions
@@ -110,6 +115,7 @@
 	u32 d_id;
 #define ZFCP_DBF_SAN_MAX_PAYLOAD (FC_CT_HDR_LEN + 32)
 	char payload[ZFCP_DBF_SAN_MAX_PAYLOAD];
+	u16 pl_len;
 } __packed;
 
 /**
@@ -126,6 +132,8 @@
 	u8  prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
 	u32 fsf_status;
 	u8  fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
+	u32 port_handle;
+	u32 lun_handle;
 } __packed;
 
 /**
@@ -196,7 +204,7 @@
  * @id: unique number of recovery record type
  * @tag: identifier string specifying the location of initiation
  * @scsi_id: scsi device id
- * @scsi_lun: scsi device logical unit number
+ * @scsi_lun: scsi device logical unit number, low part of 64 bit, old 32 bit
  * @scsi_result: scsi result
  * @scsi_retries: current retry number of scsi request
  * @scsi_allowed: allowed retries
@@ -206,6 +214,7 @@
  * @host_scribble: LLD specific data attached to SCSI request
  * @pl_len: length of paload stored as zfcp_dbf_pay
  * @fsf_rsp: response for fsf request
+ * @scsi_lun_64_hi: scsi device logical unit number, high part of 64 bit
  */
 struct zfcp_dbf_scsi {
 	u8 id;
@@ -222,6 +231,7 @@
 	u64 host_scribble;
 	u16 pl_len;
 	struct fcp_resp_with_ext fcp_rsp;
+	u32 scsi_lun_64_hi;
 } __packed;
 
 /**
@@ -275,11 +285,35 @@
 	struct zfcp_dbf_scsi		scsi_buf;
 };
 
+/**
+ * zfcp_dbf_hba_fsf_resp_suppress - true if we should not trace by default
+ * @req: request that has been completed
+ *
+ * Returns true if FCP response with only benign residual under count.
+ */
+static inline
+bool zfcp_dbf_hba_fsf_resp_suppress(struct zfcp_fsf_req *req)
+{
+	struct fsf_qtcb *qtcb = req->qtcb;
+	u32 fsf_stat = qtcb->header.fsf_status;
+	struct fcp_resp *fcp_rsp;
+	u8 rsp_flags, fr_status;
+
+	if (qtcb->prefix.qtcb_type != FSF_IO_COMMAND)
+		return false; /* not an FCP response */
+	fcp_rsp = (struct fcp_resp *)&qtcb->bottom.io.fcp_rsp;
+	rsp_flags = fcp_rsp->fr_flags;
+	fr_status = fcp_rsp->fr_status;
+	return (fsf_stat == FSF_FCP_RSP_AVAILABLE) &&
+		(rsp_flags == FCP_RESID_UNDER) &&
+		(fr_status == SAM_STAT_GOOD);
+}
+
 static inline
 void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req)
 {
 	if (debug_level_enabled(req->adapter->dbf->hba, level))
-		zfcp_dbf_hba_fsf_res(tag, req);
+		zfcp_dbf_hba_fsf_res(tag, level, req);
 }
 
 /**
@@ -291,12 +325,18 @@
 {
 	struct fsf_qtcb *qtcb = req->qtcb;
 
-	if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
+	if (unlikely(req->status & (ZFCP_STATUS_FSFREQ_DISMISSED |
+				    ZFCP_STATUS_FSFREQ_ERROR))) {
+		zfcp_dbf_hba_fsf_resp("fs_rerr", 3, req);
+
+	} else if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
 	    (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
 		zfcp_dbf_hba_fsf_resp("fs_perr", 1, req);
 
 	} else if (qtcb->header.fsf_status != FSF_GOOD) {
-		zfcp_dbf_hba_fsf_resp("fs_ferr", 1, req);
+		zfcp_dbf_hba_fsf_resp("fs_ferr",
+				      zfcp_dbf_hba_fsf_resp_suppress(req)
+				      ? 5 : 1, req);
 
 	} else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||
 		   (req->fsf_command == FSF_QTCB_OPEN_LUN)) {
@@ -318,7 +358,7 @@
 					scmd->device->host->hostdata[0];
 
 	if (debug_level_enabled(adapter->dbf->scsi, level))
-		zfcp_dbf_scsi(tag, scmd, req);
+		zfcp_dbf_scsi(tag, level, scmd, req);
 }
 
 /**
@@ -367,7 +407,8 @@
  * @flag: indicates type of reset (Target Reset, Logical Unit Reset)
  */
 static inline
-void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
+void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag,
+			    struct zfcp_fsf_req *fsf_req)
 {
 	char tmp_tag[ZFCP_DBF_TAG_LEN];
 
@@ -377,7 +418,18 @@
 		memcpy(tmp_tag, "lr_", 3);
 
 	memcpy(&tmp_tag[3], tag, 4);
-	_zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL);
+	_zfcp_dbf_scsi(tmp_tag, 1, scmnd, fsf_req);
+}
+
+/**
+ * zfcp_dbf_scsi_nullcmnd() - trace NULLify of SCSI command in dev/tgt-reset.
+ * @scmnd: SCSI command that was NULLified.
+ * @fsf_req: request that owned @scmnd.
+ */
+static inline void zfcp_dbf_scsi_nullcmnd(struct scsi_cmnd *scmnd,
+					  struct zfcp_fsf_req *fsf_req)
+{
+	_zfcp_dbf_scsi("scfc__1", 3, scmnd, fsf_req);
 }
 
 #endif /* ZFCP_DBF_H */
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_erp.c
+++ linux-4.4.0/drivers/s390/scsi/zfcp_erp.c
@@ -3,13 +3,14 @@
  *
  * Error Recovery Procedures (ERP).
  *
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2016
  */
 
 #define KMSG_COMPONENT "zfcp"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/kthread.h>
+#include <linux/bug.h>
 #include "zfcp_ext.h"
 #include "zfcp_reqlist.h"
 
@@ -34,11 +35,28 @@
 	ZFCP_ERP_STEP_LUN_OPENING	= 0x2000,
 };
 
+/**
+ * enum zfcp_erp_act_type - Type of ERP action object.
+ * @ZFCP_ERP_ACTION_REOPEN_LUN: LUN recovery.
+ * @ZFCP_ERP_ACTION_REOPEN_PORT: Port recovery.
+ * @ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: Forced port recovery.
+ * @ZFCP_ERP_ACTION_REOPEN_ADAPTER: Adapter recovery.
+ * @ZFCP_ERP_ACTION_NONE: Eyecatcher pseudo flag to bitwise or-combine with
+ *			  either of the first four enum values.
+ *			  Used to indicate that an ERP action could not be
+ *			  set up despite a detected need for some recovery.
+ * @ZFCP_ERP_ACTION_FAILED: Eyecatcher pseudo flag to bitwise or-combine with
+ *			    either of the first four enum values.
+ *			    Used to indicate that ERP not needed because
+ *			    the object has ZFCP_STATUS_COMMON_ERP_FAILED.
+ */
 enum zfcp_erp_act_type {
 	ZFCP_ERP_ACTION_REOPEN_LUN         = 1,
 	ZFCP_ERP_ACTION_REOPEN_PORT	   = 2,
 	ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
 	ZFCP_ERP_ACTION_REOPEN_ADAPTER     = 4,
+	ZFCP_ERP_ACTION_NONE		   = 0xc0,
+	ZFCP_ERP_ACTION_FAILED		   = 0xe0,
 };
 
 enum zfcp_erp_act_state {
@@ -125,6 +143,46 @@
 	}
 }
 
+static int zfcp_erp_handle_failed(int want, struct zfcp_adapter *adapter,
+				  struct zfcp_port *port,
+				  struct scsi_device *sdev)
+{
+	int need = want;
+	struct zfcp_scsi_dev *zsdev;
+
+	switch (want) {
+	case ZFCP_ERP_ACTION_REOPEN_LUN:
+		zsdev = sdev_to_zfcp(sdev);
+		if (atomic_read(&zsdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+			need = 0;
+		break;
+	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+			need = 0;
+		break;
+	case ZFCP_ERP_ACTION_REOPEN_PORT:
+		if (atomic_read(&port->status) &
+		    ZFCP_STATUS_COMMON_ERP_FAILED) {
+			need = 0;
+			/* ensure propagation of failed status to new devices */
+			zfcp_erp_set_port_status(
+				port, ZFCP_STATUS_COMMON_ERP_FAILED);
+		}
+		break;
+	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+		if (atomic_read(&adapter->status) &
+		    ZFCP_STATUS_COMMON_ERP_FAILED) {
+			need = 0;
+			/* ensure propagation of failed status to new devices */
+			zfcp_erp_set_adapter_status(
+				adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
+		}
+		break;
+	}
+
+	return need;
+}
+
 static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
 				 struct zfcp_port *port,
 				 struct scsi_device *sdev)
@@ -184,6 +242,12 @@
 	struct zfcp_erp_action *erp_action;
 	struct zfcp_scsi_dev *zfcp_sdev;
 
+	if (WARN_ON_ONCE(need != ZFCP_ERP_ACTION_REOPEN_LUN &&
+			 need != ZFCP_ERP_ACTION_REOPEN_PORT &&
+			 need != ZFCP_ERP_ACTION_REOPEN_PORT_FORCED &&
+			 need != ZFCP_ERP_ACTION_REOPEN_ADAPTER))
+		return NULL;
+
 	switch (need) {
 	case ZFCP_ERP_ACTION_REOPEN_LUN:
 		zfcp_sdev = sdev_to_zfcp(sdev);
@@ -193,9 +257,8 @@
 		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE,
 				&zfcp_sdev->status);
 		erp_action = &zfcp_sdev->erp_action;
-		memset(erp_action, 0, sizeof(struct zfcp_erp_action));
-		erp_action->port = port;
-		erp_action->sdev = sdev;
+		WARN_ON_ONCE(erp_action->port != port);
+		WARN_ON_ONCE(erp_action->sdev != sdev);
 		if (!(atomic_read(&zfcp_sdev->status) &
 		      ZFCP_STATUS_COMMON_RUNNING))
 			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
@@ -208,8 +271,8 @@
 		zfcp_erp_action_dismiss_port(port);
 		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
 		erp_action = &port->erp_action;
-		memset(erp_action, 0, sizeof(struct zfcp_erp_action));
-		erp_action->port = port;
+		WARN_ON_ONCE(erp_action->port != port);
+		WARN_ON_ONCE(erp_action->sdev != NULL);
 		if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
 			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
 		break;
@@ -219,7 +282,8 @@
 		zfcp_erp_action_dismiss_adapter(adapter);
 		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
 		erp_action = &adapter->erp_action;
-		memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+		WARN_ON_ONCE(erp_action->port != NULL);
+		WARN_ON_ONCE(erp_action->sdev != NULL);
 		if (!(atomic_read(&adapter->status) &
 		      ZFCP_STATUS_COMMON_RUNNING))
 			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
@@ -229,7 +293,11 @@
 		return NULL;
 	}
 
-	erp_action->adapter = adapter;
+	WARN_ON_ONCE(erp_action->adapter != adapter);
+	memset(&erp_action->list, 0, sizeof(erp_action->list));
+	memset(&erp_action->timer, 0, sizeof(erp_action->timer));
+	erp_action->step = ZFCP_ERP_STEP_UNINITIALIZED;
+	erp_action->fsf_req_id = 0;
 	erp_action->action = need;
 	erp_action->status = act_status;
 
@@ -244,16 +312,27 @@
 	int retval = 1, need;
 	struct zfcp_erp_action *act;
 
-	if (!adapter->erp_thread)
-		return -EIO;
+	need = zfcp_erp_handle_failed(want, adapter, port, sdev);
+	if (!need) {
+		need = ZFCP_ERP_ACTION_FAILED; /* marker for trace */
+		goto out;
+	}
+
+	if (!adapter->erp_thread) {
+		need = ZFCP_ERP_ACTION_NONE; /* marker for trace */
+		retval = -EIO;
+		goto out;
+	}
 
 	need = zfcp_erp_required_act(want, adapter, port, sdev);
 	if (!need)
 		goto out;
 
 	act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev);
-	if (!act)
+	if (!act) {
+		need |= ZFCP_ERP_ACTION_NONE; /* marker for trace */
 		goto out;
+	}
 	atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
 	++adapter->erp_total_count;
 	list_add_tail(&act->list, &adapter->erp_ready_head);
@@ -264,18 +343,32 @@
 	return retval;
 }
 
+void zfcp_erp_port_forced_no_port_dbf(char *id, struct zfcp_adapter *adapter,
+				      u64 port_name, u32 port_id)
+{
+	unsigned long flags;
+	static /* don't waste stack */ struct zfcp_port tmpport;
+
+	write_lock_irqsave(&adapter->erp_lock, flags);
+	/* Stand-in zfcp port with fields just good enough for
+	 * zfcp_dbf_rec_trig() and zfcp_dbf_set_common().
+	 * Under lock because tmpport is static.
+	 */
+	atomic_set(&tmpport.status, -1); /* unknown */
+	tmpport.wwpn = port_name;
+	tmpport.d_id = port_id;
+	zfcp_dbf_rec_trig(id, adapter, &tmpport, NULL,
+			  ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
+			  ZFCP_ERP_ACTION_NONE);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
+}
+
 static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
 				    int clear_mask, char *id)
 {
 	zfcp_erp_adapter_block(adapter, clear_mask);
 	zfcp_scsi_schedule_rports_block(adapter);
 
-	/* ensure propagation of failed status to new devices */
-	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
-		zfcp_erp_set_adapter_status(adapter,
-					    ZFCP_STATUS_COMMON_ERP_FAILED);
-		return -EIO;
-	}
 	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
 				       adapter, NULL, NULL, id, 0);
 }
@@ -294,12 +387,8 @@
 	zfcp_scsi_schedule_rports_block(adapter);
 
 	write_lock_irqsave(&adapter->erp_lock, flags);
-	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
-		zfcp_erp_set_adapter_status(adapter,
-					    ZFCP_STATUS_COMMON_ERP_FAILED);
-	else
-		zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
-					NULL, NULL, id, 0);
+	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
+				NULL, NULL, id, 0);
 	write_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
@@ -340,9 +429,6 @@
 	zfcp_erp_port_block(port, clear);
 	zfcp_scsi_schedule_rport_block(port);
 
-	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
-		return;
-
 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
 				port->adapter, port, NULL, id, 0);
 }
@@ -368,12 +454,6 @@
 	zfcp_erp_port_block(port, clear);
 	zfcp_scsi_schedule_rport_block(port);
 
-	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
-		/* ensure propagation of failed status to new devices */
-		zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
-		return -EIO;
-	}
-
 	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
 				       port->adapter, port, NULL, id, 0);
 }
@@ -413,9 +493,6 @@
 
 	zfcp_erp_lun_block(sdev, clear);
 
-	if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
-		return;
-
 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
 				zfcp_sdev->port, sdev, id, act_status);
 }
@@ -579,6 +656,20 @@
 	add_timer(&erp_action->timer);
 }
 
+void zfcp_erp_port_forced_reopen_all(struct zfcp_adapter *adapter,
+				     int clear, char *dbftag)
+{
+	unsigned long flags;
+	struct zfcp_port *port;
+
+	write_lock_irqsave(&adapter->erp_lock, flags);
+	read_lock(&adapter->port_list_lock);
+	list_for_each_entry(port, &adapter->port_list, list)
+		_zfcp_erp_port_forced_reopen(port, clear, dbftag);
+	read_unlock(&adapter->port_list_lock);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
+}
+
 static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
 				      int clear, char *id)
 {
@@ -656,7 +747,7 @@
 				 adapter->peer_d_id);
 	if (IS_ERR(port)) /* error or port already attached */
 		return;
-	_zfcp_erp_port_reopen(port, 0, "ereptp1");
+	zfcp_erp_port_reopen(port, 0, "ereptp1");
 }
 
 static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
@@ -1204,6 +1295,65 @@
 	}
 }
 
+/**
+ * zfcp_erp_try_rport_unblock - unblock rport if no more/new recovery
+ * @port: zfcp_port whose fc_rport we should try to unblock
+ */
+static void zfcp_erp_try_rport_unblock(struct zfcp_port *port)
+{
+	unsigned long flags;
+	struct zfcp_adapter *adapter = port->adapter;
+	int port_status;
+	struct Scsi_Host *shost = adapter->scsi_host;
+	struct scsi_device *sdev;
+
+	write_lock_irqsave(&adapter->erp_lock, flags);
+	port_status = atomic_read(&port->status);
+	if ((port_status & ZFCP_STATUS_COMMON_UNBLOCKED)    == 0 ||
+	    (port_status & (ZFCP_STATUS_COMMON_ERP_INUSE |
+			    ZFCP_STATUS_COMMON_ERP_FAILED)) != 0) {
+		/* new ERP of severity >= port triggered elsewhere meanwhile or
+		 * local link down (adapter erp_failed but not clear unblock)
+		 */
+		zfcp_dbf_rec_run_lvl(4, "ertru_p", &port->erp_action);
+		write_unlock_irqrestore(&adapter->erp_lock, flags);
+		return;
+	}
+	spin_lock(shost->host_lock);
+	__shost_for_each_device(sdev, shost) {
+		struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
+		int lun_status;
+
+		if (sdev->sdev_state == SDEV_DEL ||
+		    sdev->sdev_state == SDEV_CANCEL)
+			continue;
+		if (zsdev->port != port)
+			continue;
+		/* LUN under port of interest */
+		lun_status = atomic_read(&zsdev->status);
+		if ((lun_status & ZFCP_STATUS_COMMON_ERP_FAILED) != 0)
+			continue; /* unblock rport despite failed LUNs */
+		/* LUN recovery not given up yet [maybe follow-up pending] */
+		if ((lun_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 ||
+		    (lun_status & ZFCP_STATUS_COMMON_ERP_INUSE) != 0) {
+			/* LUN blocked:
+			 * not yet unblocked [LUN recovery pending]
+			 * or meanwhile blocked [new LUN recovery triggered]
+			 */
+			zfcp_dbf_rec_run_lvl(4, "ertru_l", &zsdev->erp_action);
+			spin_unlock(shost->host_lock);
+			write_unlock_irqrestore(&adapter->erp_lock, flags);
+			return;
+		}
+	}
+	/* now port has no child or all children have completed recovery,
+	 * and no ERP of severity >= port was meanwhile triggered elsewhere
+	 */
+	zfcp_scsi_schedule_rport_register(port);
+	spin_unlock(shost->host_lock);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
+}
+
 static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
 {
 	struct zfcp_adapter *adapter = act->adapter;
@@ -1214,11 +1364,18 @@
 	case ZFCP_ERP_ACTION_REOPEN_LUN:
 		if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
 			scsi_device_put(sdev);
+		zfcp_erp_try_rport_unblock(port);
 		break;
 
 	case ZFCP_ERP_ACTION_REOPEN_PORT:
-		if (result == ZFCP_ERP_SUCCEEDED)
-			zfcp_scsi_schedule_rport_register(port);
+		/* This switch case might also happen after a forced reopen
+		 * was successfully done and thus overwritten with a new
+		 * non-forced reopen at `ersfs_2'. In this case, we must not
+		 * do the clean-up of the non-forced version.
+		 */
+		if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
+			if (result == ZFCP_ERP_SUCCEEDED)
+				zfcp_erp_try_rport_unblock(port);
 		/* fall through */
 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
 		put_device(&port->dev);
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_ext.h
+++ linux-4.4.0/drivers/s390/scsi/zfcp_ext.h
@@ -3,7 +3,7 @@
  *
  * External function declarations.
  *
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2018
  */
 
 #ifndef ZFCP_EXT_H
@@ -34,9 +34,15 @@
 extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *);
 extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *,
 			      struct zfcp_port *, struct scsi_device *, u8, u8);
+extern void zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter,
+				   struct zfcp_port *port,
+				   struct scsi_device *sdev, u8 want, u8 need);
 extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *);
+extern void zfcp_dbf_rec_run_lvl(int level, char *tag,
+				 struct zfcp_erp_action *erp);
+extern void zfcp_dbf_rec_run_wka(char *, struct zfcp_fc_wka_port *, u64);
 extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_hba_fsf_res(char *, int, struct zfcp_fsf_req *);
 extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
 extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
 extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **);
@@ -44,11 +50,17 @@
 extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
 extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
 extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_scsi(char *, struct scsi_cmnd *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_scsi(char *, int, struct scsi_cmnd *,
+			  struct zfcp_fsf_req *);
+extern void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter,
+			     unsigned int scsi_id, int ret);
 
 /* zfcp_erp.c */
 extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32);
 extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32);
+extern void zfcp_erp_port_forced_no_port_dbf(char *id,
+					     struct zfcp_adapter *adapter,
+					     u64 port_name, u32 port_id);
 extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *);
 extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *);
 extern void zfcp_erp_set_port_status(struct zfcp_port *, u32);
@@ -56,6 +68,8 @@
 extern int  zfcp_erp_port_reopen(struct zfcp_port *, int, char *);
 extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *);
 extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *);
+extern void zfcp_erp_port_forced_reopen_all(struct zfcp_adapter *adapter,
+					    int clear, char *dbftag);
 extern void zfcp_erp_set_lun_status(struct scsi_device *, u32);
 extern void zfcp_erp_clear_lun_status(struct scsi_device *, u32);
 extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *);
@@ -147,6 +161,7 @@
 extern struct mutex zfcp_sysfs_port_units_mutex;
 extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
 extern struct device_attribute *zfcp_sysfs_shost_attrs[];
+bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port);
 
 /* zfcp_unit.c */
 extern int zfcp_unit_add(struct zfcp_port *, u64);
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_fc.c
+++ linux-4.4.0/drivers/s390/scsi/zfcp_fc.c
@@ -238,10 +238,6 @@
 	list_for_each_entry(port, &adapter->port_list, list) {
 		if ((port->d_id & range) == (ntoh24(page->rscn_fid) & range))
 			zfcp_fc_test_link(port);
-		if (!port->d_id)
-			zfcp_erp_port_reopen(port,
-					     ZFCP_STATUS_COMMON_ERP_FAILED,
-					     "fcrscn1");
 	}
 	read_unlock_irqrestore(&adapter->port_list_lock, flags);
 }
@@ -249,6 +245,7 @@
 static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
 {
 	struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data;
+	struct zfcp_adapter *adapter = fsf_req->adapter;
 	struct fc_els_rscn *head;
 	struct fc_els_rscn_page *page;
 	u16 i;
@@ -261,6 +258,22 @@
 	/* see FC-FS */
 	no_entries = head->rscn_plen / sizeof(struct fc_els_rscn_page);
 
+	if (no_entries > 1) {
+		/* handle failed ports */
+		unsigned long flags;
+		struct zfcp_port *port;
+
+		read_lock_irqsave(&adapter->port_list_lock, flags);
+		list_for_each_entry(port, &adapter->port_list, list) {
+			if (port->d_id)
+				continue;
+			zfcp_erp_port_reopen(port,
+					     ZFCP_STATUS_COMMON_ERP_FAILED,
+					     "fcrscn1");
+		}
+		read_unlock_irqrestore(&adapter->port_list_lock, flags);
+	}
+
 	for (i = 1; i < no_entries; i++) {
 		/* skip head and start with 1st element */
 		page++;
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_fc.h
+++ linux-4.4.0/drivers/s390/scsi/zfcp_fc.h
@@ -4,7 +4,7 @@
  * Fibre Channel related definitions and inline functions for the zfcp
  * device driver
  *
- * Copyright IBM Corp. 2009
+ * Copyright IBM Corp. 2009, 2017
  */
 
 #ifndef ZFCP_FC_H
@@ -279,6 +279,10 @@
 		     !(rsp_flags & FCP_SNS_LEN_VAL) &&
 		     fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
 			set_host_byte(scsi, DID_ERROR);
+	} else if (unlikely(rsp_flags & FCP_RESID_OVER)) {
+		/* FCP_DL was not sufficient for SCSI data length */
+		if (fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
+			set_host_byte(scsi, DID_ERROR);
 	}
 }
 
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_fsf.c
+++ linux-4.4.0/drivers/s390/scsi/zfcp_fsf.c
@@ -3,7 +3,7 @@
  *
  * Implementation of FSF commands.
  *
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2015
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -20,6 +20,11 @@
 
 struct kmem_cache *zfcp_fsf_qtcb_cache;
 
+static bool ber_stop = true;
+module_param(ber_stop, bool, 0600);
+MODULE_PARM_DESC(ber_stop,
+		 "Shuts down FCP devices for FCP channels that report a bit-error count in excess of its threshold (default on)");
+
 static void zfcp_fsf_request_timeout_handler(unsigned long data)
 {
 	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
@@ -231,10 +236,15 @@
 	case FSF_STATUS_READ_SENSE_DATA_AVAIL:
 		break;
 	case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
-		dev_warn(&adapter->ccw_device->dev,
-			 "The error threshold for checksum statistics "
-			 "has been exceeded\n");
 		zfcp_dbf_hba_bit_err("fssrh_3", req);
+		if (ber_stop) {
+			dev_warn(&adapter->ccw_device->dev,
+				 "All paths over this FCP device are disused because of excessive bit errors\n");
+			zfcp_erp_adapter_shutdown(adapter, 0, "fssrh_b");
+		} else {
+			dev_warn(&adapter->ccw_device->dev,
+				 "The error threshold for checksum statistics has been exceeded\n");
+		}
 		break;
 	case FSF_STATUS_READ_LINK_DOWN:
 		zfcp_fsf_status_read_link_down(req);
@@ -508,7 +518,10 @@
 		fc_host_port_type(shost) = FC_PORTTYPE_PTP;
 		break;
 	case FSF_TOPO_FABRIC:
-		fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+		if (bottom->connection_features & FSF_FEATURE_NPIV_MODE)
+			fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
+		else
+			fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
 		break;
 	case FSF_TOPO_AL:
 		fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
@@ -613,7 +626,6 @@
 
 	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
 		fc_host_permanent_port_name(shost) = bottom->wwpn;
-		fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
 	} else
 		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
 	fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
@@ -926,8 +938,8 @@
 
 	switch (header->fsf_status) {
         case FSF_GOOD:
-		zfcp_dbf_san_res("fsscth2", req);
 		ct->status = 0;
+		zfcp_dbf_san_res("fsscth2", req);
 		break;
         case FSF_SERVICE_CLASS_NOT_SUPPORTED:
 		zfcp_fsf_class_not_supp(req);
@@ -982,8 +994,12 @@
 	if (zfcp_adapter_multi_buffer_active(adapter)) {
 		if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req))
 			return -EIO;
+		qtcb->bottom.support.req_buf_length =
+			zfcp_qdio_real_bytes(sg_req);
 		if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp))
 			return -EIO;
+		qtcb->bottom.support.resp_buf_length =
+			zfcp_qdio_real_bytes(sg_resp);
 
 		zfcp_qdio_set_data_div(qdio, &req->qdio_req,
 					zfcp_qdio_sbale_count(sg_req));
@@ -1073,6 +1089,7 @@
 
 	req->handler = zfcp_fsf_send_ct_handler;
 	req->qtcb->header.port_handle = wka_port->handle;
+	ct->d_id = wka_port->d_id;
 	req->data = ct;
 
 	zfcp_dbf_san_req("fssct_1", req, wka_port->d_id);
@@ -1102,8 +1119,8 @@
 
 	switch (header->fsf_status) {
 	case FSF_GOOD:
-		zfcp_dbf_san_res("fsselh1", req);
 		send_els->status = 0;
+		zfcp_dbf_san_res("fsselh1", req);
 		break;
 	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
 		zfcp_fsf_class_not_supp(req);
@@ -1169,6 +1186,7 @@
 
 	hton24(req->qtcb->bottom.support.d_id, d_id);
 	req->handler = zfcp_fsf_send_els_handler;
+	els->d_id = d_id;
 	req->data = els;
 
 	zfcp_dbf_san_req("fssels1", req, d_id);
@@ -1576,6 +1594,7 @@
 {
 	struct zfcp_qdio *qdio = wka_port->adapter->qdio;
 	struct zfcp_fsf_req *req;
+	unsigned long req_id = 0;
 	int retval = -EIO;
 
 	spin_lock_irq(&qdio->req_q_lock);
@@ -1598,12 +1617,16 @@
 	hton24(req->qtcb->bottom.support.d_id, wka_port->d_id);
 	req->data = wka_port;
 
+	req_id = req->req_id;
+
 	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
 	retval = zfcp_fsf_req_send(req);
 	if (retval)
 		zfcp_fsf_req_free(req);
 out:
 	spin_unlock_irq(&qdio->req_q_lock);
+	if (!retval)
+		zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req_id);
 	return retval;
 }
 
@@ -1629,6 +1652,7 @@
 {
 	struct zfcp_qdio *qdio = wka_port->adapter->qdio;
 	struct zfcp_fsf_req *req;
+	unsigned long req_id = 0;
 	int retval = -EIO;
 
 	spin_lock_irq(&qdio->req_q_lock);
@@ -1651,12 +1675,16 @@
 	req->data = wka_port;
 	req->qtcb->header.port_handle = wka_port->handle;
 
+	req_id = req->req_id;
+
 	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
 	retval = zfcp_fsf_req_send(req);
 	if (retval)
 		zfcp_fsf_req_free(req);
 out:
 	spin_unlock_irq(&qdio->req_q_lock);
+	if (!retval)
+		zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req_id);
 	return retval;
 }
 
@@ -2246,7 +2274,8 @@
 	fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
 	zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0);
 
-	if (scsi_prot_sg_count(scsi_cmnd)) {
+	if ((scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) &&
+	    scsi_prot_sg_count(scsi_cmnd)) {
 		zfcp_qdio_set_data_div(qdio, &req->qdio_req,
 				       scsi_prot_sg_count(scsi_cmnd));
 		retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_fsf.h
+++ linux-4.4.0/drivers/s390/scsi/zfcp_fsf.h
@@ -3,7 +3,7 @@
  *
  * Interface to the FSF support functions.
  *
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2016
  */
 
 #ifndef FSF_H
@@ -78,6 +78,7 @@
 #define FSF_APP_TAG_CHECK_FAILURE		0x00000082
 #define FSF_REF_TAG_CHECK_FAILURE		0x00000083
 #define FSF_ADAPTER_STATUS_AVAILABLE		0x000000AD
+#define FSF_FCP_RSP_AVAILABLE			0x000000AF
 #define FSF_UNKNOWN_COMMAND			0x000000E2
 #define FSF_UNKNOWN_OP_SUBTYPE                  0x000000E3
 #define FSF_INVALID_COMMAND_OPTION              0x000000E5
@@ -436,6 +437,7 @@
  * @handler_data: data passed to handler function
  * @port: Optional pointer to port for zfcp internal ELS (only test link ADISC)
  * @status: used to pass error status to calling function
+ * @d_id: Destination ID of either open WKA port for CT or of D_ID for ELS
  */
 struct zfcp_fsf_ct_els {
 	struct scatterlist *req;
@@ -444,6 +446,7 @@
 	void *handler_data;
 	struct zfcp_port *port;
 	int status;
+	u32 d_id;
 };
 
 #endif				/* FSF_H */
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_reqlist.h
+++ linux-4.4.0/drivers/s390/scsi/zfcp_reqlist.h
@@ -4,7 +4,7 @@
  * Data structure and helper functions for tracking pending FSF
  * requests.
  *
- * Copyright IBM Corp. 2009
+ * Copyright IBM Corp. 2009, 2016
  */
 
 #ifndef ZFCP_REQLIST_H
@@ -180,4 +180,32 @@
 	spin_unlock_irqrestore(&rl->lock, flags);
 }
 
+/**
+ * zfcp_reqlist_apply_for_all() - apply a function to every request.
+ * @rl: the requestlist that contains the target requests.
+ * @f: the function to apply to each request; the first parameter of the
+ *     function will be the target-request; the second parameter is the same
+ *     pointer as given with the argument @data.
+ * @data: freely chosen argument; passed through to @f as second parameter.
+ *
+ * Uses :c:macro:`list_for_each_entry` to iterate over the lists in the hash-
+ * table (not a 'safe' variant, so don't modify the list).
+ *
+ * Holds @rl->lock over the entire request-iteration.
+ */
+static inline void
+zfcp_reqlist_apply_for_all(struct zfcp_reqlist *rl,
+			   void (*f)(struct zfcp_fsf_req *, void *), void *data)
+{
+	struct zfcp_fsf_req *req;
+	unsigned long flags;
+	unsigned int i;
+
+	spin_lock_irqsave(&rl->lock, flags);
+	for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
+		list_for_each_entry(req, &rl->buckets[i], list)
+			f(req, data);
+	spin_unlock_irqrestore(&rl->lock, flags);
+}
+
 #endif /* ZFCP_REQLIST_H */
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_scsi.c
+++ linux-4.4.0/drivers/s390/scsi/zfcp_scsi.c
@@ -3,7 +3,7 @@
  *
  * Interface to Linux SCSI midlayer.
  *
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2018
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -88,9 +88,7 @@
 	}
 
 	if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) {
-		/* This could be either
-		 * open LUN pending: this is temporary, will result in
-		 *	open LUN or ERP_FAILED, so retry command
+		/* This could be
 		 * call to rport_delete pending: mimic retry from
 		 * 	fc_remote_port_chkready until rport is BLOCKED
 		 */
@@ -117,10 +115,24 @@
 	struct zfcp_unit *unit;
 	int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE;
 
+	zfcp_sdev->erp_action.adapter = adapter;
+	zfcp_sdev->erp_action.sdev = sdev;
+
 	port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
 	if (!port)
 		return -ENXIO;
 
+	zfcp_sdev->erp_action.port = port;
+
+	mutex_lock(&zfcp_sysfs_port_units_mutex);
+	if (zfcp_sysfs_port_is_removing(port)) {
+		/* port is already gone */
+		mutex_unlock(&zfcp_sysfs_port_units_mutex);
+		put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
+		return -ENXIO;
+	}
+	mutex_unlock(&zfcp_sysfs_port_units_mutex);
+
 	unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev));
 	if (unit)
 		put_device(&unit->dev);
@@ -177,6 +189,7 @@
 		if (abrt_req)
 			break;
 
+		zfcp_dbf_scsi_abort("abrt_wt", scpnt, NULL);
 		zfcp_erp_wait(adapter);
 		ret = fc_block_scsi_eh(scpnt);
 		if (ret) {
@@ -209,6 +222,57 @@
 	return retval;
 }
 
+struct zfcp_scsi_req_filter {
+	u8 tmf_scope;
+	u32 lun_handle;
+	u32 port_handle;
+};
+
+static void zfcp_scsi_forget_cmnd(struct zfcp_fsf_req *old_req, void *data)
+{
+	struct zfcp_scsi_req_filter *filter =
+		(struct zfcp_scsi_req_filter *)data;
+
+	/* already aborted - prevent side-effects - or not a SCSI command */
+	if (old_req->data == NULL || old_req->fsf_command != FSF_QTCB_FCP_CMND)
+		return;
+
+	/* (tmf_scope == FCP_TMF_TGT_RESET || tmf_scope == FCP_TMF_LUN_RESET) */
+	if (old_req->qtcb->header.port_handle != filter->port_handle)
+		return;
+
+	if (filter->tmf_scope == FCP_TMF_LUN_RESET &&
+	    old_req->qtcb->header.lun_handle != filter->lun_handle)
+		return;
+
+	zfcp_dbf_scsi_nullcmnd((struct scsi_cmnd *)old_req->data, old_req);
+	old_req->data = NULL;
+}
+
+static void zfcp_scsi_forget_cmnds(struct zfcp_scsi_dev *zsdev, u8 tm_flags)
+{
+	struct zfcp_adapter *adapter = zsdev->port->adapter;
+	struct zfcp_scsi_req_filter filter = {
+		.tmf_scope = FCP_TMF_TGT_RESET,
+		.port_handle = zsdev->port->handle,
+	};
+	unsigned long flags;
+
+	if (tm_flags == FCP_TMF_LUN_RESET) {
+		filter.tmf_scope = FCP_TMF_LUN_RESET;
+		filter.lun_handle = zsdev->lun_handle;
+	}
+
+	/*
+	 * abort_lock secures against other processings - in the abort-function
+	 * and normal cmnd-handler - of (struct zfcp_fsf_req *)->data
+	 */
+	write_lock_irqsave(&adapter->abort_lock, flags);
+	zfcp_reqlist_apply_for_all(adapter->req_list, zfcp_scsi_forget_cmnd,
+				   &filter);
+	write_unlock_irqrestore(&adapter->abort_lock, flags);
+}
+
 static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
 {
 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
@@ -222,27 +286,34 @@
 		if (fsf_req)
 			break;
 
+		zfcp_dbf_scsi_devreset("wait", scpnt, tm_flags, NULL);
 		zfcp_erp_wait(adapter);
 		ret = fc_block_scsi_eh(scpnt);
-		if (ret)
+		if (ret) {
+			zfcp_dbf_scsi_devreset("fiof", scpnt, tm_flags, NULL);
 			return ret;
+		}
 
 		if (!(atomic_read(&adapter->status) &
 		      ZFCP_STATUS_COMMON_RUNNING)) {
-			zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags);
+			zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags, NULL);
 			return SUCCESS;
 		}
 	}
-	if (!fsf_req)
+	if (!fsf_req) {
+		zfcp_dbf_scsi_devreset("reqf", scpnt, tm_flags, NULL);
 		return FAILED;
+	}
 
 	wait_for_completion(&fsf_req->completion);
 
 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
-		zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags);
+		zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags, fsf_req);
 		retval = FAILED;
-	} else
-		zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags);
+	} else {
+		zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags, fsf_req);
+		zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags);
+	}
 
 	zfcp_fsf_req_free(fsf_req);
 	return retval;
@@ -262,15 +333,20 @@
 {
 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
 	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
-	int ret;
+	int ret = SUCCESS, fc_ret;
 
+	if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) {
+		zfcp_erp_port_forced_reopen_all(adapter, 0, "schrh_p");
+		zfcp_erp_wait(adapter);
+	}
 	zfcp_erp_adapter_reopen(adapter, 0, "schrh_1");
 	zfcp_erp_wait(adapter);
-	ret = fc_block_scsi_eh(scpnt);
-	if (ret)
-		return ret;
+	fc_ret = fc_block_scsi_eh(scpnt);
+	if (fc_ret)
+		ret = fc_ret;
 
-	return SUCCESS;
+	zfcp_dbf_scsi_eh("schrh_r", adapter, ~0, ret);
+	return ret;
 }
 
 struct scsi_transport_template *zfcp_scsi_transport_template;
@@ -540,6 +616,11 @@
 	if (port) {
 		zfcp_erp_port_forced_reopen(port, 0, "sctrpi1");
 		put_device(&port->dev);
+	} else {
+		zfcp_erp_port_forced_no_port_dbf(
+			"sctrpin", adapter,
+			rport->port_name /* zfcp_scsi_rport_register */,
+			rport->port_id /* zfcp_scsi_rport_register */);
 	}
 }
 
@@ -556,6 +637,9 @@
 	ids.port_id = port->d_id;
 	ids.roles = FC_RPORT_ROLE_FCP_TARGET;
 
+	zfcp_dbf_rec_trig_lock("scpaddy", port->adapter, port, NULL,
+			       ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD,
+			       ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD);
 	rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
 	if (!rport) {
 		dev_err(&port->adapter->ccw_device->dev,
@@ -577,6 +661,9 @@
 	struct fc_rport *rport = port->rport;
 
 	if (rport) {
+		zfcp_dbf_rec_trig_lock("scpdely", port->adapter, port, NULL,
+				       ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL,
+				       ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL);
 		fc_remote_port_delete(rport);
 		port->rport = NULL;
 	}
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_sysfs.c
+++ linux-4.4.0/drivers/s390/scsi/zfcp_sysfs.c
@@ -237,6 +237,53 @@
 
 DEFINE_MUTEX(zfcp_sysfs_port_units_mutex);
 
+static void zfcp_sysfs_port_set_removing(struct zfcp_port *const port)
+{
+	lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
+	atomic_set(&port->units, -1);
+}
+
+bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port)
+{
+	lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
+	return atomic_read(&port->units) == -1;
+}
+
+static bool zfcp_sysfs_port_in_use(struct zfcp_port *const port)
+{
+	struct zfcp_adapter *const adapter = port->adapter;
+	unsigned long flags;
+	struct scsi_device *sdev;
+	bool in_use = true;
+
+	mutex_lock(&zfcp_sysfs_port_units_mutex);
+	if (atomic_read(&port->units) > 0)
+		goto unlock_port_units_mutex; /* zfcp_unit(s) under port */
+
+	spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
+	__shost_for_each_device(sdev, adapter->scsi_host) {
+		const struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
+
+		if (sdev->sdev_state == SDEV_DEL ||
+		    sdev->sdev_state == SDEV_CANCEL)
+			continue;
+		if (zsdev->port != port)
+			continue;
+		/* alive scsi_device under port of interest */
+		goto unlock_host_lock;
+	}
+
+	/* port is about to be removed, so no more unit_add or slave_alloc */
+	zfcp_sysfs_port_set_removing(port);
+	in_use = false;
+
+unlock_host_lock:
+	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
+unlock_port_units_mutex:
+	mutex_unlock(&zfcp_sysfs_port_units_mutex);
+	return in_use;
+}
+
 static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
 					    struct device_attribute *attr,
 					    const char *buf, size_t count)
@@ -259,15 +306,11 @@
 	else
 		retval = 0;
 
-	mutex_lock(&zfcp_sysfs_port_units_mutex);
-	if (atomic_read(&port->units) > 0) {
+	if (zfcp_sysfs_port_in_use(port)) {
 		retval = -EBUSY;
-		mutex_unlock(&zfcp_sysfs_port_units_mutex);
+		put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
 		goto out;
 	}
-	/* port is about to be removed, so no more unit_add */
-	atomic_set(&port->units, -1);
-	mutex_unlock(&zfcp_sysfs_port_units_mutex);
 
 	write_lock_irq(&adapter->port_list_lock);
 	list_del(&port->list);
--- linux-4.4.0.orig/drivers/s390/scsi/zfcp_unit.c
+++ linux-4.4.0/drivers/s390/scsi/zfcp_unit.c
@@ -122,7 +122,7 @@
 	int retval = 0;
 
 	mutex_lock(&zfcp_sysfs_port_units_mutex);
-	if (atomic_read(&port->units) == -1) {
+	if (zfcp_sysfs_port_is_removing(port)) {
 		/* port is already gone */
 		retval = -ENODEV;
 		goto out;
@@ -166,8 +166,14 @@
 	write_lock_irq(&port->unit_list_lock);
 	list_add_tail(&unit->list, &port->unit_list);
 	write_unlock_irq(&port->unit_list_lock);
+	/*
+	 * lock order: shost->scan_mutex before zfcp_sysfs_port_units_mutex
+	 * due to      zfcp_unit_scsi_scan() => zfcp_scsi_slave_alloc()
+	 */
+	mutex_unlock(&zfcp_sysfs_port_units_mutex);
 
 	zfcp_unit_scsi_scan(unit);
+	return retval;
 
 out:
 	mutex_unlock(&zfcp_sysfs_port_units_mutex);
--- linux-4.4.0.orig/drivers/s390/virtio/virtio_ccw.c
+++ linux-4.4.0/drivers/s390/virtio/virtio_ccw.c
@@ -59,6 +59,7 @@
 	unsigned int revision; /* Transport revision */
 	wait_queue_head_t wait_q;
 	spinlock_t lock;
+	struct mutex io_lock; /* Serializes I/O requests */
 	struct list_head virtqueues;
 	unsigned long indicators;
 	unsigned long indicators2;
@@ -282,6 +283,8 @@
 {
 	struct virtio_ccw_vq_info *info;
 
+	if (!vcdev->airq_info)
+		return;
 	list_for_each_entry(info, &vcdev->virtqueues, node)
 		drop_airq_indicator(info->vq, vcdev->airq_info);
 }
@@ -307,6 +310,7 @@
 	unsigned long flags;
 	int flag = intparm & VIRTIO_CCW_INTPARM_MASK;
 
+	mutex_lock(&vcdev->io_lock);
 	do {
 		spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags);
 		ret = ccw_device_start(vcdev->cdev, ccw, intparm, 0, 0);
@@ -319,7 +323,9 @@
 		cpu_relax();
 	} while (ret == -EBUSY);
 	wait_event(vcdev->wait_q, doing_io(vcdev, flag) == 0);
-	return ret ? ret : vcdev->err;
+	ret = ret ? ret : vcdev->err;
+	mutex_unlock(&vcdev->io_lock);
+	return ret;
 }
 
 static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
@@ -419,7 +425,7 @@
 	ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
 	if (ret)
 		return ret;
-	return vcdev->config_block->num;
+	return vcdev->config_block->num ?: -ENOENT;
 }
 
 static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
@@ -833,6 +839,7 @@
 	int ret;
 	struct ccw1 *ccw;
 	void *config_area;
+	unsigned long flags;
 
 	ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
 	if (!ccw)
@@ -851,11 +858,13 @@
 	if (ret)
 		goto out_free;
 
+	spin_lock_irqsave(&vcdev->lock, flags);
 	memcpy(vcdev->config, config_area, offset + len);
-	if (buf)
-		memcpy(buf, &vcdev->config[offset], len);
 	if (vcdev->config_ready < offset + len)
 		vcdev->config_ready = offset + len;
+	spin_unlock_irqrestore(&vcdev->lock, flags);
+	if (buf)
+		memcpy(buf, config_area + offset, len);
 
 out_free:
 	kfree(config_area);
@@ -869,6 +878,7 @@
 	struct virtio_ccw_device *vcdev = to_vc_device(vdev);
 	struct ccw1 *ccw;
 	void *config_area;
+	unsigned long flags;
 
 	ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
 	if (!ccw)
@@ -881,9 +891,11 @@
 	/* Make sure we don't overwrite fields. */
 	if (vcdev->config_ready < offset)
 		virtio_ccw_get_config(vdev, 0, NULL, offset);
+	spin_lock_irqsave(&vcdev->lock, flags);
 	memcpy(&vcdev->config[offset], buf, len);
 	/* Write the config area to the host. */
 	memcpy(config_area, vcdev->config, sizeof(vcdev->config));
+	spin_unlock_irqrestore(&vcdev->lock, flags);
 	ccw->cmd_code = CCW_CMD_WRITE_CONF;
 	ccw->flags = 0;
 	ccw->count = offset + len;
@@ -1230,6 +1242,7 @@
 	init_waitqueue_head(&vcdev->wait_q);
 	INIT_LIST_HEAD(&vcdev->virtqueues);
 	spin_lock_init(&vcdev->lock);
+	mutex_init(&vcdev->io_lock);
 
 	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
 	dev_set_drvdata(&cdev->dev, vcdev);
--- linux-4.4.0.orig/drivers/sbus/char/display7seg.c
+++ linux-4.4.0/drivers/sbus/char/display7seg.c
@@ -221,6 +221,7 @@
 	dev_set_drvdata(&op->dev, p);
 	d7s_device = p;
 	err = 0;
+	of_node_put(opts);
 
 out:
 	return err;
--- linux-4.4.0.orig/drivers/sbus/char/envctrl.c
+++ linux-4.4.0/drivers/sbus/char/envctrl.c
@@ -910,8 +910,10 @@
 			for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
 				pchild->mon_type[len] = ENVCTRL_NOMON;
 			}
+			of_node_put(root_node);
 			return;
 		}
+		of_node_put(root_node);
 	}
 
 	/* Get the monitor channels. */
--- linux-4.4.0.orig/drivers/scsi/3w-9xxx.c
+++ linux-4.4.0/drivers/scsi/3w-9xxx.c
@@ -889,6 +889,11 @@
 	unsigned int minor_number;
 	int retval = TW_IOCTL_ERROR_OS_ENODEV;
 
+	if (!capable(CAP_SYS_ADMIN)) {
+		retval = -EACCES;
+		goto out;
+	}
+
 	minor_number = iminor(inode);
 	if (minor_number >= twa_device_extension_count)
 		goto out;
@@ -2040,6 +2045,7 @@
 
 	if (twa_initialize_device_extension(tw_dev)) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
+		retval = -ENOMEM;
 		goto out_free_device_extension;
 	}
 
@@ -2062,6 +2068,7 @@
 	tw_dev->base_addr = ioremap(mem_addr, mem_len);
 	if (!tw_dev->base_addr) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
+		retval = -ENOMEM;
 		goto out_release_mem_region;
 	}
 
@@ -2069,8 +2076,10 @@
 	TW_DISABLE_INTERRUPTS(tw_dev);
 
 	/* Initialize the card */
-	if (twa_reset_sequence(tw_dev, 0))
+	if (twa_reset_sequence(tw_dev, 0)) {
+		retval = -ENOMEM;
 		goto out_iounmap;
+	}
 
 	/* Set host specific parameters */
 	if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
--- linux-4.4.0.orig/drivers/scsi/3w-sas.c
+++ linux-4.4.0/drivers/scsi/3w-sas.c
@@ -1600,6 +1600,7 @@
 
 	if (twl_initialize_device_extension(tw_dev)) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension");
+		retval = -ENOMEM;
 		goto out_free_device_extension;
 	}
 
@@ -1614,6 +1615,7 @@
 	tw_dev->base_addr = pci_iomap(pdev, 1, 0);
 	if (!tw_dev->base_addr) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap");
+		retval = -ENOMEM;
 		goto out_release_mem_region;
 	}
 
@@ -1623,6 +1625,7 @@
 	/* Initialize the card */
 	if (twl_reset_sequence(tw_dev, 0)) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe");
+		retval = -ENOMEM;
 		goto out_iounmap;
 	}
 
--- linux-4.4.0.orig/drivers/scsi/3w-xxxx.c
+++ linux-4.4.0/drivers/scsi/3w-xxxx.c
@@ -1034,6 +1034,9 @@
 
 	dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n");
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
 	minor_number = iminor(inode);
 	if (minor_number >= tw_device_extension_count)
 		return -ENODEV;
@@ -2275,6 +2278,7 @@
 
 	if (tw_initialize_device_extension(tw_dev)) {
 		printk(KERN_WARNING "3w-xxxx: Failed to initialize device extension.");
+		retval = -ENOMEM;
 		goto out_free_device_extension;
 	}
 
@@ -2289,6 +2293,7 @@
 	tw_dev->base_addr = pci_resource_start(pdev, 0);
 	if (!tw_dev->base_addr) {
 		printk(KERN_WARNING "3w-xxxx: Failed to get io address.");
+		retval = -ENOMEM;
 		goto out_release_mem_region;
 	}
 
--- linux-4.4.0.orig/drivers/scsi/53c700.c
+++ linux-4.4.0/drivers/scsi/53c700.c
@@ -1122,7 +1122,7 @@
 		} else {
 			struct scsi_cmnd *SCp;
 
-			SCp = scsi_host_find_tag(SDp->host, SCSI_NO_TAG);
+			SCp = SDp->current_cmnd;
 			if(unlikely(SCp == NULL)) {
 				sdev_printk(KERN_ERR, SDp,
 					"no saved request for untagged cmd\n");
@@ -1826,7 +1826,7 @@
 		       slot->tag, slot);
 	} else {
 		slot->tag = SCSI_NO_TAG;
-		/* must populate current_cmnd for scsi_host_find_tag to work */
+		/* save current command for reselection */
 		SCp->device->current_cmnd = SCp;
 	}
 	/* sanity check: some of the commands generated by the mid-layer
--- linux-4.4.0.orig/drivers/scsi/Kconfig
+++ linux-4.4.0/drivers/scsi/Kconfig
@@ -194,6 +194,7 @@
 config SCSI_ENCLOSURE
 	tristate "SCSI Enclosure Support"
 	depends on SCSI && ENCLOSURE_SERVICES
+	depends on m || SCSI_SAS_ATTRS != m
 	help
 	  Enclosures are devices sitting on or in SCSI backplanes that
 	  manage devices.  If you have a disk cage, the chances are that
@@ -845,6 +846,23 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ibmvscsi.
 
+config SCSI_IBMVSCSIS
+	tristate "IBM Virtual SCSI Server support"
+	depends on PPC_PSERIES && TARGET_CORE && SCSI && PCI
+	help
+	  This is the IBM POWER Virtual SCSI Target Server
+	  This driver uses the SRP protocol for communication betwen servers
+	  guest and/or the host that run on the same server.
+	  More information on VSCSI protocol can be found at www.power.org
+
+	  The userspace configuration needed to initialize the driver can be
+	  be found here:
+
+	  https://github.com/powervm/ibmvscsis/wiki/Configuration
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ibmvscsis.
+
 config SCSI_IBMVFC
 	tristate "IBM Virtual FC support"
 	depends on PPC_PSERIES && SCSI
@@ -1013,7 +1031,7 @@
 
 config 53C700_LE_ON_BE
 	bool
-	depends on SCSI_LASI700
+	depends on SCSI_LASI700 || SCSI_SNI_53C710
 	default y
 
 config SCSI_STEX
@@ -1637,7 +1655,7 @@
 
 config MAC_SCSI
 	tristate "Macintosh NCR5380 SCSI"
-	depends on MAC && SCSI=y
+	depends on MAC && SCSI
 	select SCSI_SPI_ATTRS
 	help
 	  This is the NCR 5380 SCSI controller included on most of the 68030
--- linux-4.4.0.orig/drivers/scsi/Makefile
+++ linux-4.4.0/drivers/scsi/Makefile
@@ -128,6 +128,7 @@
 obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 obj-$(CONFIG_SCSI_IPR)		+= ipr.o
 obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsi/
+obj-$(CONFIG_SCSI_IBMVSCSIS)	+= ibmvscsi_tgt/
 obj-$(CONFIG_SCSI_IBMVFC)	+= ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)	+= hptiop.o
 obj-$(CONFIG_SCSI_STEX)		+= stex.o
--- linux-4.4.0.orig/drivers/scsi/aacraid/aachba.c
+++ linux-4.4.0/drivers/scsi/aacraid/aachba.c
@@ -1938,13 +1938,13 @@
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
 			SAM_STAT_CHECK_CONDITION;
 		set_sense(&dev->fsa_dev[cid].sense_data,
-			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+			  ILLEGAL_REQUEST, SENCODE_LBA_OUT_OF_RANGE,
 			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
 			     SCSI_SENSE_BUFFERSIZE));
 		scsicmd->scsi_done(scsicmd);
-		return 1;
+		return 0;
 	}
 
 	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
@@ -2035,13 +2035,13 @@
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
 			SAM_STAT_CHECK_CONDITION;
 		set_sense(&dev->fsa_dev[cid].sense_data,
-			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+			  ILLEGAL_REQUEST, SENCODE_LBA_OUT_OF_RANGE,
 			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
 			     SCSI_SENSE_BUFFERSIZE));
 		scsicmd->scsi_done(scsicmd);
-		return 1;
+		return 0;
 	}
 
 	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
@@ -2977,16 +2977,11 @@
 		return;
 
 	BUG_ON(fibptr == NULL);
-	dev = fibptr->dev;
-
-	scsi_dma_unmap(scsicmd);
 
-	/* expose physical device if expose_physicald flag is on */
-	if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
-	  && expose_physicals > 0)
-		aac_expose_phy_device(scsicmd);
+	dev = fibptr->dev;
 
 	srbreply = (struct aac_srb_reply *) fib_data(fibptr);
+
 	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
 
 	if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
@@ -2999,158 +2994,176 @@
 		 */
 		scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
 				   - le32_to_cpu(srbreply->data_xfer_length));
-		/*
-		 * First check the fib status
-		 */
+	}
 
-		if (le32_to_cpu(srbreply->status) != ST_OK) {
-			int len;
 
-			printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
-			len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
-				    SCSI_SENSE_BUFFERSIZE);
-			scsicmd->result = DID_ERROR << 16
-						| COMMAND_COMPLETE << 8
-						| SAM_STAT_CHECK_CONDITION;
-			memcpy(scsicmd->sense_buffer,
-					srbreply->sense_data, len);
-		}
+	scsi_dma_unmap(scsicmd);
 
-		/*
-		 * Next check the srb status
-		 */
-		switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
-		case SRB_STATUS_ERROR_RECOVERY:
-		case SRB_STATUS_PENDING:
-		case SRB_STATUS_SUCCESS:
-			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
-			break;
-		case SRB_STATUS_DATA_OVERRUN:
-			switch (scsicmd->cmnd[0]) {
-			case  READ_6:
-			case  WRITE_6:
-			case  READ_10:
-			case  WRITE_10:
-			case  READ_12:
-			case  WRITE_12:
-			case  READ_16:
-			case  WRITE_16:
-				if (le32_to_cpu(srbreply->data_xfer_length)
-							< scsicmd->underflow)
-					printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
-				else
-					printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
-				scsicmd->result = DID_ERROR << 16
-							| COMMAND_COMPLETE << 8;
-				break;
-			case INQUIRY: {
-				scsicmd->result = DID_OK << 16
-							| COMMAND_COMPLETE << 8;
-				break;
-			}
-			default:
-				scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
-				break;
-			}
-			break;
-		case SRB_STATUS_ABORTED:
-			scsicmd->result = DID_ABORT << 16 | ABORT << 8;
-			break;
-		case SRB_STATUS_ABORT_FAILED:
-			/*
-			 * Not sure about this one - but assuming the
-			 * hba was trying to abort for some reason
-			 */
-			scsicmd->result = DID_ERROR << 16 | ABORT << 8;
-			break;
-		case SRB_STATUS_PARITY_ERROR:
-			scsicmd->result = DID_PARITY << 16
-						| MSG_PARITY_ERROR << 8;
-			break;
-		case SRB_STATUS_NO_DEVICE:
-		case SRB_STATUS_INVALID_PATH_ID:
-		case SRB_STATUS_INVALID_TARGET_ID:
-		case SRB_STATUS_INVALID_LUN:
-		case SRB_STATUS_SELECTION_TIMEOUT:
-			scsicmd->result = DID_NO_CONNECT << 16
-						| COMMAND_COMPLETE << 8;
-			break;
+	/* expose physical device if expose_physicald flag is on */
+	if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
+	  && expose_physicals > 0)
+		aac_expose_phy_device(scsicmd);
 
-		case SRB_STATUS_COMMAND_TIMEOUT:
-		case SRB_STATUS_TIMEOUT:
-			scsicmd->result = DID_TIME_OUT << 16
-						| COMMAND_COMPLETE << 8;
-			break;
+	/*
+	 * First check the fib status
+	 */
 
-		case SRB_STATUS_BUSY:
-			scsicmd->result = DID_BUS_BUSY << 16
-						| COMMAND_COMPLETE << 8;
-			break;
+	if (le32_to_cpu(srbreply->status) != ST_OK) {
+		int len;
 
-		case SRB_STATUS_BUS_RESET:
-			scsicmd->result = DID_RESET << 16
-						| COMMAND_COMPLETE << 8;
-			break;
+		pr_warn("aac_srb_callback: srb failed, status = %d\n",
+				le32_to_cpu(srbreply->status));
+		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+			    SCSI_SENSE_BUFFERSIZE);
+		scsicmd->result = DID_ERROR << 16
+				| COMMAND_COMPLETE << 8
+				| SAM_STAT_CHECK_CONDITION;
+		memcpy(scsicmd->sense_buffer,
+				srbreply->sense_data, len);
+	}
 
-		case SRB_STATUS_MESSAGE_REJECTED:
+	/*
+	 * Next check the srb status
+	 */
+	switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
+	case SRB_STATUS_ERROR_RECOVERY:
+	case SRB_STATUS_PENDING:
+	case SRB_STATUS_SUCCESS:
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+		break;
+	case SRB_STATUS_DATA_OVERRUN:
+		switch (scsicmd->cmnd[0]) {
+		case  READ_6:
+		case  WRITE_6:
+		case  READ_10:
+		case  WRITE_10:
+		case  READ_12:
+		case  WRITE_12:
+		case  READ_16:
+		case  WRITE_16:
+			if (le32_to_cpu(srbreply->data_xfer_length)
+						< scsicmd->underflow)
+				pr_warn("aacraid: SCSI CMD underflow\n");
+			else
+				pr_warn("aacraid: SCSI CMD Data Overrun\n");
 			scsicmd->result = DID_ERROR << 16
-						| MESSAGE_REJECT << 8;
+					| COMMAND_COMPLETE << 8;
+			break;
+		case INQUIRY:
+			scsicmd->result = DID_OK << 16
+					| COMMAND_COMPLETE << 8;
 			break;
-		case SRB_STATUS_REQUEST_FLUSHED:
-		case SRB_STATUS_ERROR:
-		case SRB_STATUS_INVALID_REQUEST:
-		case SRB_STATUS_REQUEST_SENSE_FAILED:
-		case SRB_STATUS_NO_HBA:
-		case SRB_STATUS_UNEXPECTED_BUS_FREE:
-		case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
-		case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
-		case SRB_STATUS_DELAYED_RETRY:
-		case SRB_STATUS_BAD_FUNCTION:
-		case SRB_STATUS_NOT_STARTED:
-		case SRB_STATUS_NOT_IN_USE:
-		case SRB_STATUS_FORCE_ABORT:
-		case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
 		default:
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			break;
+		}
+		break;
+	case SRB_STATUS_ABORTED:
+		scsicmd->result = DID_ABORT << 16 | ABORT << 8;
+		break;
+	case SRB_STATUS_ABORT_FAILED:
+		/*
+		 * Not sure about this one - but assuming the
+		 * hba was trying to abort for some reason
+		 */
+		scsicmd->result = DID_ERROR << 16 | ABORT << 8;
+		break;
+	case SRB_STATUS_PARITY_ERROR:
+		scsicmd->result = DID_PARITY << 16
+				| MSG_PARITY_ERROR << 8;
+		break;
+	case SRB_STATUS_NO_DEVICE:
+	case SRB_STATUS_INVALID_PATH_ID:
+	case SRB_STATUS_INVALID_TARGET_ID:
+	case SRB_STATUS_INVALID_LUN:
+	case SRB_STATUS_SELECTION_TIMEOUT:
+		scsicmd->result = DID_NO_CONNECT << 16
+				| COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_COMMAND_TIMEOUT:
+	case SRB_STATUS_TIMEOUT:
+		scsicmd->result = DID_TIME_OUT << 16
+				| COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_BUSY:
+		scsicmd->result = DID_BUS_BUSY << 16
+				| COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_BUS_RESET:
+		scsicmd->result = DID_RESET << 16
+				| COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_MESSAGE_REJECTED:
+		scsicmd->result = DID_ERROR << 16
+				| MESSAGE_REJECT << 8;
+		break;
+	case SRB_STATUS_REQUEST_FLUSHED:
+	case SRB_STATUS_ERROR:
+	case SRB_STATUS_INVALID_REQUEST:
+	case SRB_STATUS_REQUEST_SENSE_FAILED:
+	case SRB_STATUS_NO_HBA:
+	case SRB_STATUS_UNEXPECTED_BUS_FREE:
+	case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
+	case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+	case SRB_STATUS_DELAYED_RETRY:
+	case SRB_STATUS_BAD_FUNCTION:
+	case SRB_STATUS_NOT_STARTED:
+	case SRB_STATUS_NOT_IN_USE:
+	case SRB_STATUS_FORCE_ABORT:
+	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
+	default:
 #ifdef AAC_DETAILED_STATUS_INFO
-			printk(KERN_INFO "aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
-				le32_to_cpu(srbreply->srb_status) & 0x3F,
-				aac_get_status_string(
-					le32_to_cpu(srbreply->srb_status) & 0x3F),
-				scsicmd->cmnd[0],
-				le32_to_cpu(srbreply->scsi_status));
+		pr_info("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x -scsi status 0x%x\n",
+			le32_to_cpu(srbreply->srb_status) & 0x3F,
+			aac_get_status_string(
+				le32_to_cpu(srbreply->srb_status) & 0x3F),
+			scsicmd->cmnd[0],
+			le32_to_cpu(srbreply->scsi_status));
 #endif
-			if ((scsicmd->cmnd[0] == ATA_12)
-				|| (scsicmd->cmnd[0] == ATA_16)) {
-					if (scsicmd->cmnd[2] & (0x01 << 5)) {
-						scsicmd->result = DID_OK << 16
-							| COMMAND_COMPLETE << 8;
-				break;
-				} else {
-					scsicmd->result = DID_ERROR << 16
-						| COMMAND_COMPLETE << 8;
-					break;
-				}
+		/*
+		 * When the CC bit is SET by the host in ATA pass thru CDB,
+		 *  driver is supposed to return DID_OK
+		 *
+		 * When the CC bit is RESET by the host, driver should
+		 *  return DID_ERROR
+		 */
+		if ((scsicmd->cmnd[0] == ATA_12)
+			|| (scsicmd->cmnd[0] == ATA_16)) {
+
+			if (scsicmd->cmnd[2] & (0x01 << 5)) {
+				scsicmd->result = DID_OK << 16
+					| COMMAND_COMPLETE << 8;
+			break;
 			} else {
 				scsicmd->result = DID_ERROR << 16
 					| COMMAND_COMPLETE << 8;
-				break;
+			break;
 			}
+		} else {
+			scsicmd->result = DID_ERROR << 16
+				| COMMAND_COMPLETE << 8;
+			break;
 		}
-		if (le32_to_cpu(srbreply->scsi_status)
-				== SAM_STAT_CHECK_CONDITION) {
-			int len;
-
-			scsicmd->result |= SAM_STAT_CHECK_CONDITION;
-			len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
-				    SCSI_SENSE_BUFFERSIZE);
+	}
+	if (le32_to_cpu(srbreply->scsi_status)
+			== SAM_STAT_CHECK_CONDITION) {
+		int len;
+
+		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
+		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+			    SCSI_SENSE_BUFFERSIZE);
 #ifdef AAC_DETAILED_STATUS_INFO
-			printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
-						le32_to_cpu(srbreply->status), len);
+		pr_warn("aac_srb_callback: check condition, status = %d len=%d\n",
+					le32_to_cpu(srbreply->status), len);
 #endif
-			memcpy(scsicmd->sense_buffer,
-					srbreply->sense_data, len);
-		}
+		memcpy(scsicmd->sense_buffer,
+				srbreply->sense_data, len);
 	}
+
 	/*
 	 * OR in the scsi status (already shifted up a bit)
 	 */
--- linux-4.4.0.orig/drivers/scsi/aacraid/aacraid.h
+++ linux-4.4.0/drivers/scsi/aacraid/aacraid.h
@@ -29,6 +29,7 @@
 #define AAC_INT_MODE_MSI		(1<<1)
 #define AAC_INT_MODE_AIF		(1<<2)
 #define AAC_INT_MODE_SYNC		(1<<3)
+#define AAC_INT_MODE_MSIX		(1<<16)
 
 #define AAC_INT_ENABLE_TYPE1_INTX	0xfffffffb
 #define AAC_INT_ENABLE_TYPE1_MSIX	0xfffffffa
@@ -944,6 +945,7 @@
 	 */
 	struct list_head	fiblink;
 	void			*data;
+	u32			vector_no;
 	struct hw_fib		*hw_fib_va;		/* Actual shared object */
 	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
 };
@@ -2113,6 +2115,7 @@
 int aac_acquire_irq(struct aac_dev *dev);
 void aac_free_irq(struct aac_dev *dev);
 const char *aac_driverinfo(struct Scsi_Host *);
+void aac_fib_vector_assign(struct aac_dev *dev);
 struct fib *aac_fib_alloc(struct aac_dev *dev);
 int aac_fib_setup(struct aac_dev *dev);
 void aac_fib_map_free(struct aac_dev *dev);
--- linux-4.4.0.orig/drivers/scsi/aacraid/commctrl.c
+++ linux-4.4.0/drivers/scsi/aacraid/commctrl.c
@@ -63,7 +63,7 @@
 	struct fib *fibptr;
 	struct hw_fib * hw_fib = (struct hw_fib *)0;
 	dma_addr_t hw_fib_pa = (dma_addr_t)0LL;
-	unsigned size;
+	unsigned int size, osize;
 	int retval;
 
 	if (dev->in_reset) {
@@ -87,7 +87,8 @@
 	 *	will not overrun the buffer when we copy the memory. Return
 	 *	an error if we would.
 	 */
-	size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr);
+	osize = size = le16_to_cpu(kfib->header.Size) +
+		sizeof(struct aac_fibhdr);
 	if (size < le16_to_cpu(kfib->header.SenderSize))
 		size = le16_to_cpu(kfib->header.SenderSize);
 	if (size > dev->max_fib_size) {
@@ -118,6 +119,14 @@
 		goto cleanup;
 	}
 
+	/* Sanity check the second copy */
+	if ((osize != le16_to_cpu(kfib->header.Size) +
+		sizeof(struct aac_fibhdr))
+		|| (size < le16_to_cpu(kfib->header.SenderSize))) {
+		retval = -EINVAL;
+		goto cleanup;
+	}
+
 	if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {
 		aac_adapter_interrupt(dev);
 		/*
--- linux-4.4.0.orig/drivers/scsi/aacraid/comminit.c
+++ linux-4.4.0/drivers/scsi/aacraid/comminit.c
@@ -37,6 +37,7 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
+#include <linux/delay.h>
 #include <linux/completion.h>
 #include <linux/mm.h>
 #include <scsi/scsi_host.h>
@@ -47,6 +48,24 @@
 	.irq_mod = 1
 };
 
+static inline int aac_is_msix_mode(struct aac_dev *dev)
+{
+	u32 status = 0;
+
+	if (dev->pdev->device == PMC_DEVICE_S6 ||
+		dev->pdev->device == PMC_DEVICE_S7 ||
+		dev->pdev->device == PMC_DEVICE_S8) {
+		status = src_readl(dev, MUnit.OMR);
+	}
+	return (status & AAC_INT_MODE_MSIX);
+}
+
+static inline void aac_change_to_intx(struct aac_dev *dev)
+{
+	aac_src_access_devreg(dev, AAC_DISABLE_MSIX);
+	aac_src_access_devreg(dev, AAC_ENABLE_INTX);
+}
+
 static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign)
 {
 	unsigned char *base;
@@ -425,6 +444,15 @@
 	dev->comm_interface = AAC_COMM_PRODUCER;
 	dev->raw_io_interface = dev->raw_io_64 = 0;
 
+
+	/*
+	 * Enable INTX mode, if not done already Enabled
+	 */
+	if (aac_is_msix_mode(dev)) {
+		aac_change_to_intx(dev);
+		dev_info(&dev->pdev->dev, "Changed firmware to INTX mode");
+	}
+
 	if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
 		0, 0, 0, 0, 0, 0,
 		status+0, status+1, status+2, status+3, NULL)) &&
@@ -559,6 +587,7 @@
 
 	if (aac_comm_init(dev)<0){
 		kfree(dev->queues);
+		dev->queues = NULL;
 		return NULL;
 	}
 	/*
@@ -566,6 +595,7 @@
 	 */
 	if (aac_fib_setup(dev) < 0) {
 		kfree(dev->queues);
+		dev->queues = NULL;
 		return NULL;
 	}
 		
--- linux-4.4.0.orig/drivers/scsi/aacraid/commsup.c
+++ linux-4.4.0/drivers/scsi/aacraid/commsup.c
@@ -83,13 +83,38 @@
 
 void aac_fib_map_free(struct aac_dev *dev)
 {
-	pci_free_consistent(dev->pdev,
-	  dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
-	  dev->hw_fib_va, dev->hw_fib_pa);
+	if (dev->hw_fib_va && dev->max_fib_size) {
+		pci_free_consistent(dev->pdev,
+		(dev->max_fib_size *
+		(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)),
+		dev->hw_fib_va, dev->hw_fib_pa);
+	}
 	dev->hw_fib_va = NULL;
 	dev->hw_fib_pa = 0;
 }
 
+void aac_fib_vector_assign(struct aac_dev *dev)
+{
+	u32 i = 0;
+	u32 vector = 1;
+	struct fib *fibptr = NULL;
+
+	for (i = 0, fibptr = &dev->fibs[i];
+		i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
+		i++, fibptr++) {
+		if ((dev->max_msix == 1) ||
+		  (i > ((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1)
+			- dev->vector_cap))) {
+			fibptr->vector_no = 0;
+		} else {
+			fibptr->vector_no = vector;
+			vector++;
+			if (vector == dev->max_msix)
+				vector = 1;
+		}
+	}
+}
+
 /**
  *	aac_fib_setup	-	setup the fibs
  *	@dev: Adapter to set up
@@ -151,6 +176,12 @@
 		hw_fib_pa = hw_fib_pa +
 			dev->max_fib_size + sizeof(struct aac_fib_xporthdr);
 	}
+
+	/*
+	 *Assign vector numbers to fibs
+	 */
+	aac_fib_vector_assign(dev);
+
 	/*
 	 *	Add the fib chain to the free list
 	 */
@@ -580,10 +611,10 @@
 					}
 					return -EFAULT;
 				}
-				/* We used to udelay() here but that absorbed
-				 * a CPU when a timeout occured. Not very
-				 * useful. */
-				cpu_relax();
+				/*
+				 * Allow other processes / CPUS to use core
+				 */
+				schedule();
 			}
 		} else if (down_interruptible(&fibptr->event_wait)) {
 			/* Do nothing ... satisfy
@@ -1290,9 +1321,10 @@
 	host = aac->scsi_host_ptr;
 	scsi_block_requests(host);
 	aac_adapter_disable_int(aac);
-	if (aac->thread->pid != current->pid) {
+	if (aac->thread && aac->thread->pid != current->pid) {
 		spin_unlock_irq(host->host_lock);
 		kthread_stop(aac->thread);
+		aac->thread = NULL;
 		jafo = 1;
 	}
 
@@ -1332,13 +1364,13 @@
 	 * will ensure that i/o is queisced and the card is flushed in that
 	 * case.
 	 */
+	aac_free_irq(aac);
 	aac_fib_map_free(aac);
 	pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
 	aac->comm_addr = NULL;
 	aac->comm_phys = 0;
 	kfree(aac->queues);
 	aac->queues = NULL;
-	aac_free_irq(aac);
 	kfree(aac->fsa_dev);
 	aac->fsa_dev = NULL;
 	quirks = aac_get_driver_ident(index)->quirks;
@@ -1361,6 +1393,7 @@
 					  aac->name);
 		if (IS_ERR(aac->thread)) {
 			retval = PTR_ERR(aac->thread);
+			aac->thread = NULL;
 			goto out;
 		}
 	}
@@ -1939,6 +1972,10 @@
 		if (difference <= 0)
 			difference = 1;
 		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (kthread_should_stop())
+			break;
+
 		schedule_timeout(difference);
 
 		if (kthread_should_stop())
--- linux-4.4.0.orig/drivers/scsi/aacraid/linit.c
+++ linux-4.4.0/drivers/scsi/aacraid/linit.c
@@ -1085,6 +1085,7 @@
 				up(&fib->event_wait);
 		}
 		kthread_stop(aac->thread);
+		aac->thread = NULL;
 	}
 	aac_send_shutdown(aac);
 	aac_adapter_disable_int(aac);
@@ -1189,8 +1190,10 @@
 	 *	Map in the registers from the adapter.
 	 */
 	aac->base_size = AAC_MIN_FOOTPRINT_SIZE;
-	if ((*aac_drivers[index].init)(aac))
+	if ((*aac_drivers[index].init)(aac)) {
+		error = -ENODEV;
 		goto out_unmap;
+	}
 
 	if (aac->sync_mode) {
 		if (aac_sync_mode)
@@ -1404,8 +1407,18 @@
 
 	aac_adapter_enable_int(dev);
 
-	if (!dev->sync_mode)
+	/*max msix may change  after EEH
+	 * Re-assign vectors to fibs
+	 */
+	aac_fib_vector_assign(dev);
+
+	if (!dev->sync_mode) {
+		/* After EEH recovery or suspend resume, max_msix count
+		 * may change, therfore updating in init as well.
+		 */
+		dev->init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix);
 		aac_adapter_start(dev);
+	}
 	return 0;
 
 error_iounmap:
--- linux-4.4.0.orig/drivers/scsi/aacraid/src.c
+++ linux-4.4.0/drivers/scsi/aacraid/src.c
@@ -156,8 +156,8 @@
 				break;
 			if (dev->msi_enabled && dev->max_msix > 1)
 				atomic_dec(&dev->rrq_outstanding[vector_no]);
-			aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
 			dev->host_rrq[index++] = 0;
+			aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
 			if (index == (vector_no + 1) * dev->vector_cap)
 				index = vector_no * dev->vector_cap;
 			dev->host_rrq_idx[vector_no] = index;
@@ -413,16 +413,23 @@
 	u32 status = src_readl(dev, MUnit.OMR);
 
 	/*
+	 *	Check to see if the board panic'd.
+	 */
+	if (unlikely(status & KERNEL_PANIC))
+		goto err_blink;
+
+	/*
 	 *	Check to see if the board failed any self tests.
 	 */
 	if (unlikely(status & SELF_TEST_FAILED))
-		return -1;
+		goto err_out;
 
 	/*
-	 *	Check to see if the board panic'd.
+	 *	Check to see if the board failed any self tests.
 	 */
-	if (unlikely(status & KERNEL_PANIC))
-		return (status >> 16) & 0xFF;
+	if (unlikely(status & MONITOR_PANIC))
+		goto err_out;
+
 	/*
 	 *	Wait for the adapter to be up and running.
 	 */
@@ -432,6 +439,12 @@
 	 *	Everything is OK
 	 */
 	return 0;
+
+err_out:
+	return -1;
+
+err_blink:
+	return (status >> 16) & 0xFF;
 }
 
 /**
@@ -452,36 +465,20 @@
 #endif
 
 	u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size);
+	u16 vector_no;
 
 	atomic_inc(&q->numpending);
 
 	if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest &&
 	    dev->max_msix > 1) {
-		u_int16_t vector_no, first_choice = 0xffff;
-
-		vector_no = dev->fibs_pushed_no % dev->max_msix;
-		do {
-			vector_no += 1;
-			if (vector_no == dev->max_msix)
-				vector_no = 1;
-			if (atomic_read(&dev->rrq_outstanding[vector_no]) <
-			    dev->vector_cap)
-				break;
-			if (0xffff == first_choice)
-				first_choice = vector_no;
-			else if (vector_no == first_choice)
-				break;
-		} while (1);
-		if (vector_no == first_choice)
-			vector_no = 0;
-		atomic_inc(&dev->rrq_outstanding[vector_no]);
-		if (dev->fibs_pushed_no == 0xffffffff)
-			dev->fibs_pushed_no = 0;
-		else
-			dev->fibs_pushed_no++;
+		vector_no = fib->vector_no;
 		fib->hw_fib_va->header.Handle += (vector_no << 16);
+	} else {
+		vector_no = 0;
 	}
 
+	atomic_inc(&dev->rrq_outstanding[vector_no]);
+
 	if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
 		/* Calculate the amount to the fibsize bits */
 		fibsize = (hdr_size + 127) / 128 - 1;
--- linux-4.4.0.orig/drivers/scsi/advansys.c
+++ linux-4.4.0/drivers/scsi/advansys.c
@@ -6291,18 +6291,17 @@
 static uchar
 AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
 {
-	EXT_MSG sdtr_buf;
-	uchar sdtr_period_index;
-	PortAddr iop_base;
-
-	iop_base = asc_dvc->iop_base;
-	sdtr_buf.msg_type = EXTENDED_MESSAGE;
-	sdtr_buf.msg_len = MS_SDTR_LEN;
-	sdtr_buf.msg_req = EXTENDED_SDTR;
-	sdtr_buf.xfer_period = sdtr_period;
+	PortAddr iop_base = asc_dvc->iop_base;
+	uchar sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+	EXT_MSG sdtr_buf = {
+		.msg_type = EXTENDED_MESSAGE,
+		.msg_len = MS_SDTR_LEN,
+		.msg_req = EXTENDED_SDTR,
+		.xfer_period = sdtr_period,
+		.req_ack_offset = sdtr_offset,
+	};
 	sdtr_offset &= ASC_SYN_MAX_OFFSET;
-	sdtr_buf.req_ack_offset = sdtr_offset;
-	sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+
 	if (sdtr_period_index <= asc_dvc->max_sdtr_index) {
 		AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
 					(uchar *)&sdtr_buf,
@@ -11030,6 +11029,9 @@
 		ASC_DBG(2, "AdvInitGetConfig()\n");
 
 		ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0;
+#else
+		share_irq = 0;
+		ret = -ENODEV;
 #endif /* CONFIG_PCI */
 	}
 
--- linux-4.4.0.orig/drivers/scsi/aha152x.c
+++ linux-4.4.0/drivers/scsi/aha152x.c
@@ -331,11 +331,11 @@
 #if !defined(PCMCIA)
 #if defined(MODULE)
 static int io[] = {0, 0};
-module_param_array(io, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
 MODULE_PARM_DESC(io,"base io address of controller");
 
 static int irq[] = {0, 0};
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(irq,"interrupt for controller");
 
 static int scsiid[] = {7, 7};
--- linux-4.4.0.orig/drivers/scsi/aha1542.c
+++ linux-4.4.0/drivers/scsi/aha1542.c
@@ -31,7 +31,7 @@
 MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)");
 
 static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 };
-module_param_array(io, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
 MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)");
 
 /* time AHA spends on the AT-bus during data transfer */
--- linux-4.4.0.orig/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ linux-4.4.0/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -2321,7 +2321,7 @@
 			 * At some speeds, we only support
 			 * ST transfers.
 			 */
-		 	if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
+			if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
 				*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
 			break;
 		}
--- linux-4.4.0.orig/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ linux-4.4.0/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1336,6 +1336,7 @@
 	case AHC_DEV_Q_TAGGED:
 		scsi_change_queue_depth(sdev,
 				dev->openings + dev->active);
+		break;
 	default:
 		/*
 		 * We allow the OS to queue 2 untagged transactions to
--- linux-4.4.0.orig/drivers/scsi/aic94xx/aic94xx_init.c
+++ linux-4.4.0/drivers/scsi/aic94xx/aic94xx_init.c
@@ -1031,8 +1031,10 @@
 
 	aic94xx_transport_template =
 		sas_domain_attach_transport(&aic94xx_transport_functions);
-	if (!aic94xx_transport_template)
+	if (!aic94xx_transport_template) {
+		err = -ENOMEM;
 		goto out_destroy_caches;
+	}
 
 	err = pci_register_driver(&aic94xx_pci_driver);
 	if (err)
--- linux-4.4.0.orig/drivers/scsi/arcmsr/arcmsr.h
+++ linux-4.4.0/drivers/scsi/arcmsr/arcmsr.h
@@ -52,7 +52,7 @@
 	#define ARCMSR_MAX_FREECCB_NUM	320
 #define ARCMSR_MAX_OUTSTANDING_CMD	255
 #endif
-#define ARCMSR_DRIVER_VERSION		"v1.30.00.04-20140919"
+#define ARCMSR_DRIVER_VERSION		"v1.30.00.22-20151126"
 #define ARCMSR_SCSI_INITIATOR_ID						255
 #define ARCMSR_MAX_XFER_SECTORS							512
 #define ARCMSR_MAX_XFER_SECTORS_B						4096
@@ -74,6 +74,9 @@
 #ifndef PCI_DEVICE_ID_ARECA_1214
 	#define PCI_DEVICE_ID_ARECA_1214	0x1214
 #endif
+#ifndef PCI_DEVICE_ID_ARECA_1203
+	#define PCI_DEVICE_ID_ARECA_1203	0x1203
+#endif
 /*
 **********************************************************************************
 **
@@ -245,6 +248,12 @@
 /* window of "instruction flags" from iop to driver */
 #define ARCMSR_IOP2DRV_DOORBELL                       0x00020408
 #define ARCMSR_IOP2DRV_DOORBELL_MASK                  0x0002040C
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL_1203                  0x00021870
+#define ARCMSR_IOP2DRV_DOORBELL_MASK_1203             0x00021874
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL_1203                  0x00021878
+#define ARCMSR_DRV2IOP_DOORBELL_MASK_1203             0x0002187C
 /* ARECA FLAG LANGUAGE */
 /* ioctl transfer */
 #define ARCMSR_IOP2DRV_DATA_WRITE_OK                  0x00000001
@@ -288,6 +297,9 @@
 #define ARCMSR_MESSAGE_RBUFFER			      0x0000ff00
 /* iop message_rwbuffer for message command */
 #define ARCMSR_MESSAGE_RWBUFFER			      0x0000fa00
+
+#define MEM_BASE0(x)	(u32 __iomem *)((unsigned long)acb->mem_base0 + x)
+#define MEM_BASE1(x)	(u32 __iomem *)((unsigned long)acb->mem_base1 + x)
 /* 
 ************************************************************************
 **                SPEC. for Areca HBC adapter
--- linux-4.4.0.orig/drivers/scsi/arcmsr/arcmsr_hba.c
+++ linux-4.4.0/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -114,6 +114,7 @@
 static const char *arcmsr_info(struct Scsi_Host *);
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
 static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *);
+static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb);
 static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
 {
 	if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
@@ -157,6 +158,8 @@
 		.driver_data = ACB_ADAPTER_TYPE_B},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202),
 		.driver_data = ACB_ADAPTER_TYPE_B},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1203),
+		.driver_data = ACB_ADAPTER_TYPE_B},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210),
 		.driver_data = ACB_ADAPTER_TYPE_A},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214),
@@ -495,6 +498,91 @@
 	}
 }
 
+static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb)
+{
+	bool rtn = true;
+	void *dma_coherent;
+	dma_addr_t dma_coherent_handle;
+	struct pci_dev *pdev = acb->pdev;
+
+	switch (acb->adapter_type) {
+	case ACB_ADAPTER_TYPE_B: {
+		struct MessageUnit_B *reg;
+		acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
+		dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+			&dma_coherent_handle, GFP_KERNEL);
+		if (!dma_coherent) {
+			pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+			return false;
+		}
+		acb->dma_coherent_handle2 = dma_coherent_handle;
+		acb->dma_coherent2 = dma_coherent;
+		reg = (struct MessageUnit_B *)dma_coherent;
+		acb->pmuB = reg;
+		if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) {
+			reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203);
+			reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203);
+			reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203);
+			reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203);
+		} else {
+			reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL);
+			reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK);
+			reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL);
+			reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK);
+		}
+		reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER);
+		reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER);
+		reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER);
+		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D *reg;
+
+		acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
+		dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+			&dma_coherent_handle, GFP_KERNEL);
+		if (!dma_coherent) {
+			pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+			return false;
+		}
+		acb->dma_coherent_handle2 = dma_coherent_handle;
+		acb->dma_coherent2 = dma_coherent;
+		reg = (struct MessageUnit_D *)dma_coherent;
+		acb->pmuD = reg;
+		reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID);
+		reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION);
+		reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK);
+		reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET);
+		reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST);
+		reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS);
+		reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE);
+		reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0);
+		reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1);
+		reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0);
+		reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1);
+		reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL);
+		reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL);
+		reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE);
+		reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW);
+		reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH);
+		reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER);
+		reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW);
+		reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH);
+		reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER);
+		reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER);
+		reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE);
+		reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE);
+		reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER);
+		reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER);
+		reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER);
+		}
+		break;
+	default:
+		break;
+	}
+	return rtn;
+}
+
 static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 {
 	struct pci_dev *pdev = acb->pdev;
@@ -739,9 +827,12 @@
 	if(!error){
 		goto pci_release_regs;
 	}
+	error = arcmsr_alloc_io_queue(acb);
+	if (!error)
+		goto unmap_pci_region;
 	error = arcmsr_get_firmware_spec(acb);
 	if(!error){
-		goto unmap_pci_region;
+		goto free_hbb_mu;
 	}
 	error = arcmsr_alloc_ccb_pool(acb);
 	if(error){
@@ -2297,15 +2388,23 @@
 	}
 	case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
 		unsigned char *ver_addr;
-		int32_t user_len, cnt2end;
+		uint32_t user_len;
+		int32_t cnt2end;
 		uint8_t *pQbuffer, *ptmpuserbuffer;
+
+		user_len = pcmdmessagefld->cmdmessage.Length;
+		if (user_len > ARCMSR_API_DATA_BUFLEN) {
+			retvalue = ARCMSR_MESSAGE_FAIL;
+			goto message_out;
+		}
+
 		ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC);
 		if (!ver_addr) {
 			retvalue = ARCMSR_MESSAGE_FAIL;
 			goto message_out;
 		}
 		ptmpuserbuffer = ver_addr;
-		user_len = pcmdmessagefld->cmdmessage.Length;
+
 		memcpy(ptmpuserbuffer,
 			pcmdmessagefld->messagedatabuffer, user_len);
 		spin_lock_irqsave(&acb->wqbuffer_lock, flags);
@@ -2537,18 +2636,9 @@
 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 	struct CommandControlBlock *ccb;
 	int target = cmd->device->id;
-	int lun = cmd->device->lun;
-	uint8_t scsicmd = cmd->cmnd[0];
 	cmd->scsi_done = done;
 	cmd->host_scribble = NULL;
 	cmd->result = 0;
-	if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){
-		if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
-    			cmd->result = (DID_NO_CONNECT << 16);
-		}
-		cmd->scsi_done(cmd);
-		return 0;
-	}
 	if (target == 16) {
 		/* virtual device for iop message transfer */
 		arcmsr_handle_virtual_command(acb, cmd);
@@ -2622,9 +2712,6 @@
 static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
-	struct pci_dev *pdev = acb->pdev;
-	void *dma_coherent;
-	dma_addr_t dma_coherent_handle;
 	char *acb_firm_model = acb->firm_model;
 	char *acb_firm_version = acb->firm_version;
 	char *acb_device_map = acb->device_map;
@@ -2636,30 +2723,16 @@
 	/*firm_version,21,84-99*/
 	int count;
 
-	acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
-	dma_coherent = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
-			&dma_coherent_handle, GFP_KERNEL);
-	if (!dma_coherent){
-		printk(KERN_NOTICE
-			"arcmsr%d: dma_alloc_coherent got error for hbb mu\n",
-			acb->host->host_no);
-		return false;
-	}
-	acb->dma_coherent_handle2 = dma_coherent_handle;
-	acb->dma_coherent2 = dma_coherent;
-	reg = (struct MessageUnit_B *)dma_coherent;
-	acb->pmuB = reg;
-	reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
-	reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
-	reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
-	reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
-	reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
-	reg->message_rbuffer =  (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
-	reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
 	iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);	/*firm_model,15,60-67*/
 	iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);	/*firm_version,17,68-83*/
 	iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);	/*firm_version,21,84-99*/
 
+	arcmsr_wait_firmware_ready(acb);
+	writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
+	if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+		printk(KERN_ERR "arcmsr%d: can't set driver mode.\n", acb->host->host_no);
+		return false;
+	}
 	writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
 	if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
@@ -2694,15 +2767,15 @@
 		acb->firm_model,
 		acb->firm_version);
 
-	acb->signature = readl(&reg->message_rwbuffer[1]);
+	acb->signature = readl(&reg->message_rwbuffer[0]);
 	/*firm_signature,1,00-03*/
-	acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
+	acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
 	/*firm_request_len,1,04-07*/
-	acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
+	acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
 	/*firm_numbers_queue,2,08-11*/
-	acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
+	acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
 	/*firm_sdram_size,3,12-15*/
-	acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
+	acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
 	/*firm_ide_channels,4,16-19*/
 	acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
 	/*firm_ide_channels,4,16-19*/
@@ -2777,70 +2850,8 @@
 	char __iomem *iop_firm_version;
 	char __iomem *iop_device_map;
 	u32 count;
-	struct MessageUnit_D *reg;
-	void *dma_coherent2;
-	dma_addr_t dma_coherent_handle2;
-	struct pci_dev *pdev = acb->pdev;
+	struct MessageUnit_D *reg = acb->pmuD;
 
-	acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
-	dma_coherent2 = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
-		&dma_coherent_handle2, GFP_KERNEL);
-	if (!dma_coherent2) {
-		pr_notice("DMA allocation failed...\n");
-		return false;
-	}
-	memset(dma_coherent2, 0, acb->roundup_ccbsize);
-	acb->dma_coherent_handle2 = dma_coherent_handle2;
-	acb->dma_coherent2 = dma_coherent2;
-	reg = (struct MessageUnit_D *)dma_coherent2;
-	acb->pmuD = reg;
-	reg->chip_id = acb->mem_base0 + ARCMSR_ARC1214_CHIP_ID;
-	reg->cpu_mem_config = acb->mem_base0 +
-		ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION;
-	reg->i2o_host_interrupt_mask = acb->mem_base0 +
-		ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK;
-	reg->sample_at_reset = acb->mem_base0 + ARCMSR_ARC1214_SAMPLE_RESET;
-	reg->reset_request = acb->mem_base0 + ARCMSR_ARC1214_RESET_REQUEST;
-	reg->host_int_status = acb->mem_base0 +
-		ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS;
-	reg->pcief0_int_enable = acb->mem_base0 +
-		ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE;
-	reg->inbound_msgaddr0 = acb->mem_base0 +
-		ARCMSR_ARC1214_INBOUND_MESSAGE0;
-	reg->inbound_msgaddr1 = acb->mem_base0 +
-		ARCMSR_ARC1214_INBOUND_MESSAGE1;
-	reg->outbound_msgaddr0 = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_MESSAGE0;
-	reg->outbound_msgaddr1 = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_MESSAGE1;
-	reg->inbound_doorbell = acb->mem_base0 +
-		ARCMSR_ARC1214_INBOUND_DOORBELL;
-	reg->outbound_doorbell = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_DOORBELL;
-	reg->outbound_doorbell_enable = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE;
-	reg->inboundlist_base_low = acb->mem_base0 +
-		ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW;
-	reg->inboundlist_base_high = acb->mem_base0 +
-		ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH;
-	reg->inboundlist_write_pointer = acb->mem_base0 +
-		ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER;
-	reg->outboundlist_base_low = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW;
-	reg->outboundlist_base_high = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH;
-	reg->outboundlist_copy_pointer = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER;
-	reg->outboundlist_read_pointer = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER;
-	reg->outboundlist_interrupt_cause = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE;
-	reg->outboundlist_interrupt_enable = acb->mem_base0 +
-		ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE;
-	reg->message_wbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_WBUFFER;
-	reg->message_rbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RBUFFER;
-	reg->msgcode_rwbuffer = acb->mem_base0 +
-		ARCMSR_ARC1214_MESSAGE_RWBUFFER;
 	iop_firm_model = (char __iomem *)(&reg->msgcode_rwbuffer[15]);
 	iop_firm_version = (char __iomem *)(&reg->msgcode_rwbuffer[17]);
 	iop_device_map = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
@@ -2855,8 +2866,6 @@
 	if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
 		pr_notice("arcmsr%d: wait get adapter firmware "
 			"miscellaneous data timeout\n", acb->host->host_no);
-		dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
-			acb->dma_coherent2, acb->dma_coherent_handle2);
 		return false;
 	}
 	count = 8;
@@ -2880,15 +2889,15 @@
 		iop_device_map++;
 		count--;
 	}
-	acb->signature = readl(&reg->msgcode_rwbuffer[1]);
+	acb->signature = readl(&reg->msgcode_rwbuffer[0]);
 	/*firm_signature,1,00-03*/
-	acb->firm_request_len = readl(&reg->msgcode_rwbuffer[2]);
+	acb->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);
 	/*firm_request_len,1,04-07*/
-	acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[3]);
+	acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]);
 	/*firm_numbers_queue,2,08-11*/
-	acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[4]);
+	acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);
 	/*firm_sdram_size,3,12-15*/
-	acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[5]);
+	acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);
 	/*firm_hd_channels,4,16-19*/
 	acb->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
 	pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
@@ -3998,6 +4007,7 @@
 	case PCI_DEVICE_ID_ARECA_1160:
 	case PCI_DEVICE_ID_ARECA_1170:
 	case PCI_DEVICE_ID_ARECA_1201:
+	case PCI_DEVICE_ID_ARECA_1203:
 	case PCI_DEVICE_ID_ARECA_1220:
 	case PCI_DEVICE_ID_ARECA_1230:
 	case PCI_DEVICE_ID_ARECA_1260:
--- linux-4.4.0.orig/drivers/scsi/arm/acornscsi.c
+++ linux-4.4.0/drivers/scsi/arm/acornscsi.c
@@ -2912,8 +2912,10 @@
 
 	ashost->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
 	ashost->fast = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
-	if (!ashost->base || !ashost->fast)
+	if (!ashost->base || !ashost->fast) {
+		ret = -ENOMEM;
 		goto out_put;
+	}
 
 	host->irq = ec->irq;
 	ashost->host = host;
--- linux-4.4.0.orig/drivers/scsi/arm/cumana_2.c
+++ linux-4.4.0/drivers/scsi/arm/cumana_2.c
@@ -454,7 +454,7 @@
 
 	if (info->info.scsi.dma != NO_DMA)
 		free_dma(info->info.scsi.dma);
-	free_irq(ec->irq, host);
+	free_irq(ec->irq, info);
 
  out_release:
 	fas216_release(host);
--- linux-4.4.0.orig/drivers/scsi/arm/eesox.c
+++ linux-4.4.0/drivers/scsi/arm/eesox.c
@@ -575,7 +575,7 @@
 
 	if (info->info.scsi.dma != NO_DMA)
 		free_dma(info->info.scsi.dma);
-	free_irq(ec->irq, host);
+	free_irq(ec->irq, info);
 
  out_remove:
 	fas216_remove(host);
--- linux-4.4.0.orig/drivers/scsi/arm/fas216.c
+++ linux-4.4.0/drivers/scsi/arm/fas216.c
@@ -2009,7 +2009,7 @@
 		 * have valid data in the sense buffer that could
 		 * confuse the higher levels.
 		 */
-		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+		memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 //printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id);
 //{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); }
 	/*
--- linux-4.4.0.orig/drivers/scsi/arm/powertec.c
+++ linux-4.4.0/drivers/scsi/arm/powertec.c
@@ -382,7 +382,7 @@
 
 	if (info->info.scsi.dma != NO_DMA)
 		free_dma(info->info.scsi.dma);
-	free_irq(ec->irq, host);
+	free_irq(ec->irq, info);
 
  out_release:
 	fas216_release(host);
--- linux-4.4.0.orig/drivers/scsi/be2iscsi/be_main.c
+++ linux-4.4.0/drivers/scsi/be2iscsi/be_main.c
@@ -232,20 +232,20 @@
 	cls_session = starget_to_session(scsi_target(sc->device));
 	session = cls_session->dd_data;
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (!aborted_task || !aborted_task->sc) {
 		/* we raced */
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		return SUCCESS;
 	}
 
 	aborted_io_task = aborted_task->dd_data;
 	if (!aborted_io_task->scsi_cmnd) {
 		/* raced or invalid command */
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		return SUCCESS;
 	}
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	/* Invalidate WRB Posted for this Task */
 	AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
 		      aborted_io_task->pwrb_handle->pwrb,
@@ -310,9 +310,9 @@
 	/* invalidate iocbs */
 	cls_session = starget_to_session(scsi_target(sc->device));
 	session = cls_session->dd_data;
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) {
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		return FAILED;
 	}
 	conn = session->leadconn;
@@ -341,7 +341,7 @@
 		num_invalidate++;
 		inv_tbl++;
 	}
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	inv_tbl = phba->inv_tbl;
 
 	nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
@@ -1137,9 +1137,9 @@
 		return 1;
 	}
 
-	spin_lock_bh(&session->back_lock);
+	spin_lock_bh(&session->lock);
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len);
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&session->lock);
 	return 0;
 }
 
@@ -1562,7 +1562,7 @@
 	pwrb = pwrb_handle->pwrb;
 	type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type;
 
-	spin_lock_bh(&session->back_lock);
+	spin_lock_bh(&session->lock);
 	switch (type) {
 	case HWH_TYPE_IO:
 	case HWH_TYPE_IO_RD:
@@ -1601,7 +1601,7 @@
 		break;
 	}
 
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&session->lock);
 }
 
 static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context
@@ -4470,6 +4470,7 @@
 	scsi_host_put(phba->shost);
 free_kset:
 	iscsi_boot_destroy_kset(phba->boot_kset);
+	phba->boot_kset = NULL;
 	return -ENOMEM;
 }
 
@@ -4691,9 +4692,9 @@
 	 * login/startup related tasks.
 	 */
 	beiscsi_conn->login_in_progress = 0;
-	spin_lock_bh(&session->back_lock);
+	spin_lock_bh(&session->lock);
 	beiscsi_cleanup_task(task);
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&session->lock);
 
 	pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid,
 				       &pwrb_context);
--- linux-4.4.0.orig/drivers/scsi/bfa/bfa_fcbuild.c
+++ linux-4.4.0/drivers/scsi/bfa/bfa_fcbuild.c
@@ -1249,8 +1249,8 @@
 	memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
 
 	rspnid->dap = s_id;
-	rspnid->spn_len = (u8) strlen((char *)name);
-	strncpy((char *)rspnid->spn, (char *)name, rspnid->spn_len);
+	strlcpy(rspnid->spn, name, sizeof(rspnid->spn));
+	rspnid->spn_len = (u8) strlen(rspnid->spn);
 
 	return sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s);
 }
@@ -1270,8 +1270,8 @@
 	memset(rsnn_nn, 0, sizeof(struct fcgs_rsnn_nn_req_s));
 
 	rsnn_nn->node_name = node_name;
-	rsnn_nn->snn_len = (u8) strlen((char *)name);
-	strncpy((char *)rsnn_nn->snn, (char *)name, rsnn_nn->snn_len);
+	strlcpy(rsnn_nn->snn, name, sizeof(rsnn_nn->snn));
+	rsnn_nn->snn_len = (u8) strlen(rsnn_nn->snn);
 
 	return sizeof(struct fcgs_rsnn_nn_req_s) + sizeof(struct ct_hdr_s);
 }
--- linux-4.4.0.orig/drivers/scsi/bfa/bfa_fcs.c
+++ linux-4.4.0/drivers/scsi/bfa/bfa_fcs.c
@@ -831,23 +831,23 @@
 	bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
 
 	/* Model name/number */
-	strncpy((char *)&port_cfg->sym_name, model,
-		BFA_FCS_PORT_SYMBNAME_MODEL_SZ);
-	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+	strlcpy(port_cfg->sym_name.symname, model,
+		BFA_SYMNAME_MAXLEN);
+	strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+		BFA_SYMNAME_MAXLEN);
 
 	/* Driver Version */
-	strncat((char *)&port_cfg->sym_name, (char *)driver_info->version,
-		BFA_FCS_PORT_SYMBNAME_VERSION_SZ);
-	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+	strlcat(port_cfg->sym_name.symname, driver_info->version,
+		BFA_SYMNAME_MAXLEN);
+	strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+		BFA_SYMNAME_MAXLEN);
 
 	/* Host machine name */
-	strncat((char *)&port_cfg->sym_name,
-		(char *)driver_info->host_machine_name,
-		BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ);
-	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+	strlcat(port_cfg->sym_name.symname,
+		driver_info->host_machine_name,
+		BFA_SYMNAME_MAXLEN);
+	strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+		BFA_SYMNAME_MAXLEN);
 
 	/*
 	 * Host OS Info :
@@ -855,24 +855,24 @@
 	 * OS name string and instead copy the entire OS info string (64 bytes).
 	 */
 	if (driver_info->host_os_patch[0] == '\0') {
-		strncat((char *)&port_cfg->sym_name,
-			(char *)driver_info->host_os_name,
-			BFA_FCS_OS_STR_LEN);
-		strncat((char *)&port_cfg->sym_name,
+		strlcat(port_cfg->sym_name.symname,
+			driver_info->host_os_name,
+			BFA_SYMNAME_MAXLEN);
+		strlcat(port_cfg->sym_name.symname,
 			BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+			BFA_SYMNAME_MAXLEN);
 	} else {
-		strncat((char *)&port_cfg->sym_name,
-			(char *)driver_info->host_os_name,
-			BFA_FCS_PORT_SYMBNAME_OSINFO_SZ);
-		strncat((char *)&port_cfg->sym_name,
+		strlcat(port_cfg->sym_name.symname,
+			driver_info->host_os_name,
+			BFA_SYMNAME_MAXLEN);
+		strlcat(port_cfg->sym_name.symname,
 			BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+			BFA_SYMNAME_MAXLEN);
 
 		/* Append host OS Patch Info */
-		strncat((char *)&port_cfg->sym_name,
-			(char *)driver_info->host_os_patch,
-			BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ);
+		strlcat(port_cfg->sym_name.symname,
+			driver_info->host_os_patch,
+			BFA_SYMNAME_MAXLEN);
 	}
 
 	/* null terminate */
@@ -892,26 +892,26 @@
 	bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
 
 	/* Model name/number */
-	strncpy((char *)&port_cfg->node_sym_name, model,
-		BFA_FCS_PORT_SYMBNAME_MODEL_SZ);
-	strncat((char *)&port_cfg->node_sym_name,
+	strlcpy(port_cfg->node_sym_name.symname, model,
+		BFA_SYMNAME_MAXLEN);
+	strlcat(port_cfg->node_sym_name.symname,
 			BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+			BFA_SYMNAME_MAXLEN);
 
 	/* Driver Version */
-	strncat((char *)&port_cfg->node_sym_name, (char *)driver_info->version,
-		BFA_FCS_PORT_SYMBNAME_VERSION_SZ);
-	strncat((char *)&port_cfg->node_sym_name,
+	strlcat(port_cfg->node_sym_name.symname, (char *)driver_info->version,
+		BFA_SYMNAME_MAXLEN);
+	strlcat(port_cfg->node_sym_name.symname,
 			BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+			BFA_SYMNAME_MAXLEN);
 
 	/* Host machine name */
-	strncat((char *)&port_cfg->node_sym_name,
-		(char *)driver_info->host_machine_name,
-		BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ);
-	strncat((char *)&port_cfg->node_sym_name,
+	strlcat(port_cfg->node_sym_name.symname,
+		driver_info->host_machine_name,
+		BFA_SYMNAME_MAXLEN);
+	strlcat(port_cfg->node_sym_name.symname,
 			BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+			BFA_SYMNAME_MAXLEN);
 
 	/* null terminate */
 	port_cfg->node_sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0;
--- linux-4.4.0.orig/drivers/scsi/bfa/bfa_fcs_lport.c
+++ linux-4.4.0/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -2630,10 +2630,10 @@
 	bfa_ioc_get_adapter_fw_ver(&port->fcs->bfa->ioc,
 					hba_attr->fw_version);
 
-	strncpy(hba_attr->driver_version, (char *)driver_info->version,
+	strlcpy(hba_attr->driver_version, (char *)driver_info->version,
 		sizeof(hba_attr->driver_version));
 
-	strncpy(hba_attr->os_name, driver_info->host_os_name,
+	strlcpy(hba_attr->os_name, driver_info->host_os_name,
 		sizeof(hba_attr->os_name));
 
 	/*
@@ -2641,23 +2641,23 @@
 	 * to the os name along with a separator
 	 */
 	if (driver_info->host_os_patch[0] != '\0') {
-		strncat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
-			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
-		strncat(hba_attr->os_name, driver_info->host_os_patch,
-				sizeof(driver_info->host_os_patch));
+		strlcat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+			sizeof(hba_attr->os_name));
+		strlcat(hba_attr->os_name, driver_info->host_os_patch,
+				sizeof(hba_attr->os_name));
 	}
 
 	/* Retrieve the max frame size from the port attr */
 	bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr);
 	hba_attr->max_ct_pyld = fcs_port_attr.max_frm_size;
 
-	strncpy(hba_attr->node_sym_name.symname,
+	strlcpy(hba_attr->node_sym_name.symname,
 		port->port_cfg.node_sym_name.symname, BFA_SYMNAME_MAXLEN);
 	strcpy(hba_attr->vendor_info, "BROCADE");
 	hba_attr->num_ports =
 		cpu_to_be32(bfa_ioc_get_nports(&port->fcs->bfa->ioc));
 	hba_attr->fabric_name = port->fabric->lps->pr_nwwn;
-	strncpy(hba_attr->bios_ver, hba_attr->option_rom_ver, BFA_VERSION_LEN);
+	strlcpy(hba_attr->bios_ver, hba_attr->option_rom_ver, BFA_VERSION_LEN);
 
 }
 
@@ -2724,20 +2724,20 @@
 	/*
 	 * OS device Name
 	 */
-	strncpy(port_attr->os_device_name, (char *)driver_info->os_device_name,
+	strlcpy(port_attr->os_device_name, driver_info->os_device_name,
 		sizeof(port_attr->os_device_name));
 
 	/*
 	 * Host name
 	 */
-	strncpy(port_attr->host_name, (char *)driver_info->host_machine_name,
+	strlcpy(port_attr->host_name, driver_info->host_machine_name,
 		sizeof(port_attr->host_name));
 
 	port_attr->node_name = bfa_fcs_lport_get_nwwn(port);
 	port_attr->port_name = bfa_fcs_lport_get_pwwn(port);
 
-	strncpy(port_attr->port_sym_name.symname,
-		(char *)&bfa_fcs_lport_get_psym_name(port), BFA_SYMNAME_MAXLEN);
+	strlcpy(port_attr->port_sym_name.symname,
+		bfa_fcs_lport_get_psym_name(port).symname, BFA_SYMNAME_MAXLEN);
 	bfa_fcs_lport_get_attr(port, &lport_attr);
 	port_attr->port_type = cpu_to_be32(lport_attr.port_type);
 	port_attr->scos = pport_attr.cos_supported;
@@ -3217,7 +3217,7 @@
 					rsp_str[gmal_entry->len-1] = 0;
 
 				/* copy IP Address to fabric */
-				strncpy(bfa_fcs_lport_get_fabric_ipaddr(port),
+				strlcpy(bfa_fcs_lport_get_fabric_ipaddr(port),
 					gmal_entry->ip_addr,
 					BFA_FCS_FABRIC_IPADDR_SZ);
 				break;
@@ -4655,21 +4655,13 @@
 		 * to that of the base port.
 		 */
 
-		strncpy((char *)psymbl,
-			(char *) &
-			(bfa_fcs_lport_get_psym_name
+		strlcpy(symbl,
+			(char *)&(bfa_fcs_lport_get_psym_name
 			 (bfa_fcs_get_base_port(port->fcs))),
-			strlen((char *) &
-			       bfa_fcs_lport_get_psym_name(bfa_fcs_get_base_port
-							  (port->fcs))));
-
-		/* Ensure we have a null terminating string. */
-		((char *)psymbl)[strlen((char *) &
-			bfa_fcs_lport_get_psym_name(bfa_fcs_get_base_port
-						(port->fcs)))] = 0;
-		strncat((char *)psymbl,
-			(char *) &(bfa_fcs_lport_get_psym_name(port)),
-		strlen((char *) &bfa_fcs_lport_get_psym_name(port)));
+			sizeof(symbl));
+
+		strlcat(symbl, (char *)&(bfa_fcs_lport_get_psym_name(port)),
+			sizeof(symbl));
 	} else {
 		psymbl = (u8 *) &(bfa_fcs_lport_get_psym_name(port));
 	}
@@ -5161,7 +5153,6 @@
 	struct fchs_s fchs;
 	struct bfa_fcxp_s *fcxp;
 	u8 symbl[256];
-	u8 *psymbl = &symbl[0];
 	int len;
 
 	/* Avoid sending RSPN in the following states. */
@@ -5191,22 +5182,17 @@
 		 * For Vports, we append the vport's port symbolic name
 		 * to that of the base port.
 		 */
-		strncpy((char *)psymbl, (char *)&(bfa_fcs_lport_get_psym_name
+		strlcpy(symbl, (char *)&(bfa_fcs_lport_get_psym_name
 			(bfa_fcs_get_base_port(port->fcs))),
-			strlen((char *)&bfa_fcs_lport_get_psym_name(
-			bfa_fcs_get_base_port(port->fcs))));
-
-		/* Ensure we have a null terminating string. */
-		((char *)psymbl)[strlen((char *)&bfa_fcs_lport_get_psym_name(
-		 bfa_fcs_get_base_port(port->fcs)))] = 0;
+			sizeof(symbl));
 
-		strncat((char *)psymbl,
+		strlcat(symbl,
 			(char *)&(bfa_fcs_lport_get_psym_name(port)),
-			strlen((char *)&bfa_fcs_lport_get_psym_name(port)));
+			sizeof(symbl));
 	}
 
 	len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
-			      bfa_fcs_lport_get_fcid(port), 0, psymbl);
+			      bfa_fcs_lport_get_fcid(port), 0, symbl);
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);
--- linux-4.4.0.orig/drivers/scsi/bfa/bfa_ioc.c
+++ linux-4.4.0/drivers/scsi/bfa/bfa_ioc.c
@@ -2802,7 +2802,7 @@
 bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
 {
 	memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
-	memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+	strlcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
 }
 
 void
--- linux-4.4.0.orig/drivers/scsi/bfa/bfa_svc.c
+++ linux-4.4.0/drivers/scsi/bfa/bfa_svc.c
@@ -365,8 +365,8 @@
 		lp.eid = event;
 		lp.log_type = BFA_PL_LOG_TYPE_STRING;
 		lp.misc = misc;
-		strncpy(lp.log_entry.string_log, log_str,
-			BFA_PL_STRING_LOG_SZ - 1);
+		strlcpy(lp.log_entry.string_log, log_str,
+			BFA_PL_STRING_LOG_SZ);
 		lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0';
 		bfa_plog_add(plog, &lp);
 	}
--- linux-4.4.0.orig/drivers/scsi/bfa/bfad.c
+++ linux-4.4.0/drivers/scsi/bfa/bfad.c
@@ -987,20 +987,20 @@
 
 	/* Fill the driver_info info to fcs*/
 	memset(&driver_info, 0, sizeof(driver_info));
-	strncpy(driver_info.version, BFAD_DRIVER_VERSION,
-		sizeof(driver_info.version) - 1);
+	strlcpy(driver_info.version, BFAD_DRIVER_VERSION,
+		sizeof(driver_info.version));
 	if (host_name)
-		strncpy(driver_info.host_machine_name, host_name,
-			sizeof(driver_info.host_machine_name) - 1);
+		strlcpy(driver_info.host_machine_name, host_name,
+			sizeof(driver_info.host_machine_name));
 	if (os_name)
-		strncpy(driver_info.host_os_name, os_name,
-			sizeof(driver_info.host_os_name) - 1);
+		strlcpy(driver_info.host_os_name, os_name,
+			sizeof(driver_info.host_os_name));
 	if (os_patch)
-		strncpy(driver_info.host_os_patch, os_patch,
-			sizeof(driver_info.host_os_patch) - 1);
+		strlcpy(driver_info.host_os_patch, os_patch,
+			sizeof(driver_info.host_os_patch));
 
-	strncpy(driver_info.os_device_name, bfad->pci_name,
-		sizeof(driver_info.os_device_name) - 1);
+	strlcpy(driver_info.os_device_name, bfad->pci_name,
+		sizeof(driver_info.os_device_name));
 
 	/* FCS driver info init */
 	spin_lock_irqsave(&bfad->bfad_lock, flags);
@@ -1718,9 +1718,8 @@
 
 	error = bfad_im_module_init();
 	if (error) {
-		error = -ENOMEM;
 		printk(KERN_WARNING "bfad_im_module_init failure\n");
-		goto ext;
+		return -ENOMEM;
 	}
 
 	if (strcmp(FCPI_NAME, " fcpim") == 0)
--- linux-4.4.0.orig/drivers/scsi/bfa/bfad_attr.c
+++ linux-4.4.0/drivers/scsi/bfa/bfad_attr.c
@@ -282,8 +282,10 @@
 	rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa),
 				fcstats, bfad_hcb_comp, &fcomp);
 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
-	if (rc != BFA_STATUS_OK)
+	if (rc != BFA_STATUS_OK) {
+		kfree(fcstats);
 		return NULL;
+	}
 
 	wait_for_completion(&fcomp.comp);
 
@@ -842,7 +844,7 @@
 	char symname[BFA_SYMNAME_MAXLEN];
 
 	bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr);
-	strncpy(symname, port_attr.port_cfg.sym_name.symname,
+	strlcpy(symname, port_attr.port_cfg.sym_name.symname,
 			BFA_SYMNAME_MAXLEN);
 	return snprintf(buf, PAGE_SIZE, "%s\n", symname);
 }
--- linux-4.4.0.orig/drivers/scsi/bfa/bfad_bsg.c
+++ linux-4.4.0/drivers/scsi/bfa/bfad_bsg.c
@@ -126,7 +126,7 @@
 
 	/* fill in driver attr info */
 	strcpy(iocmd->ioc_attr.driver_attr.driver, BFAD_DRIVER_NAME);
-	strncpy(iocmd->ioc_attr.driver_attr.driver_ver,
+	strlcpy(iocmd->ioc_attr.driver_attr.driver_ver,
 		BFAD_DRIVER_VERSION, BFA_VERSION_LEN);
 	strcpy(iocmd->ioc_attr.driver_attr.fw_ver,
 		iocmd->ioc_attr.adapter_attr.fw_ver);
@@ -314,9 +314,9 @@
 	iocmd->attr.port_type = port_attr.port_type;
 	iocmd->attr.loopback = port_attr.loopback;
 	iocmd->attr.authfail = port_attr.authfail;
-	strncpy(iocmd->attr.port_symname.symname,
+	strlcpy(iocmd->attr.port_symname.symname,
 		port_attr.port_cfg.sym_name.symname,
-		sizeof(port_attr.port_cfg.sym_name.symname));
+		sizeof(iocmd->attr.port_symname.symname));
 
 	iocmd->status = BFA_STATUS_OK;
 	return 0;
--- linux-4.4.0.orig/drivers/scsi/bfa/bfad_debugfs.c
+++ linux-4.4.0/drivers/scsi/bfa/bfad_debugfs.c
@@ -254,18 +254,19 @@
 	struct bfad_s *bfad = port->bfad;
 	struct bfa_s *bfa = &bfad->bfa;
 	struct bfa_ioc_s *ioc = &bfa->ioc;
-	int addr, len, rc, i;
+	int addr, rc, i;
+	u32 len;
 	u32 *regbuf;
 	void __iomem *rb, *reg_addr;
 	unsigned long flags;
 	void *kern_buf;
 
-	kern_buf = memdup_user(buf, nbytes);
+	kern_buf = memdup_user_nul(buf, nbytes);
 	if (IS_ERR(kern_buf))
 		return PTR_ERR(kern_buf);
 
 	rc = sscanf(kern_buf, "%x:%x", &addr, &len);
-	if (rc < 2) {
+	if (rc < 2 || len > (UINT_MAX >> 2)) {
 		printk(KERN_INFO
 			"bfad[%d]: %s failed to read user buf\n",
 			bfad->inst_no, __func__);
@@ -327,7 +328,7 @@
 	unsigned long flags;
 	void *kern_buf;
 
-	kern_buf = memdup_user(buf, nbytes);
+	kern_buf = memdup_user_nul(buf, nbytes);
 	if (IS_ERR(kern_buf))
 		return PTR_ERR(kern_buf);
 
--- linux-4.4.0.orig/drivers/scsi/bnx2fc/Kconfig
+++ linux-4.4.0/drivers/scsi/bnx2fc/Kconfig
@@ -4,6 +4,7 @@
 	depends on (IPV6 || IPV6=n)
 	depends on LIBFC
 	depends on LIBFCOE
+	depends on MMU
 	select NETDEVICES
 	select ETHERNET
 	select NET_VENDOR_BROADCOM
--- linux-4.4.0.orig/drivers/scsi/bnx2fc/bnx2fc.h
+++ linux-4.4.0/drivers/scsi/bnx2fc/bnx2fc.h
@@ -191,6 +191,7 @@
 	struct bnx2fc_cmd_mgr *cmd_mgr;
 	spinlock_t hba_lock;
 	struct mutex hba_mutex;
+	struct mutex hba_stats_mutex;
 	unsigned long adapter_state;
 		#define ADAPTER_STATE_UP		0
 		#define ADAPTER_STATE_GOING_DOWN	1
--- linux-4.4.0.orig/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ linux-4.4.0/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -641,15 +641,17 @@
 	if (!fw_stats)
 		return NULL;
 
+	mutex_lock(&hba->hba_stats_mutex);
+
 	bnx2fc_stats = fc_get_host_stats(shost);
 
 	init_completion(&hba->stat_req_done);
 	if (bnx2fc_send_stat_req(hba))
-		return bnx2fc_stats;
+		goto unlock_stats_mutex;
 	rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ));
 	if (!rc) {
 		BNX2FC_HBA_DBG(lport, "FW stat req timed out\n");
-		return bnx2fc_stats;
+		goto unlock_stats_mutex;
 	}
 	BNX2FC_STATS(hba, rx_stat2, fc_crc_cnt);
 	bnx2fc_stats->invalid_crc_count += hba->bfw_stats.fc_crc_cnt;
@@ -671,6 +673,9 @@
 
 	memcpy(&hba->prev_stats, hba->stats_buffer,
 	       sizeof(struct fcoe_statistics_params));
+
+unlock_stats_mutex:
+	mutex_unlock(&hba->hba_stats_mutex);
 	return bnx2fc_stats;
 }
 
@@ -1302,6 +1307,7 @@
 	}
 	spin_lock_init(&hba->hba_lock);
 	mutex_init(&hba->hba_mutex);
+	mutex_init(&hba->hba_stats_mutex);
 
 	hba->cnic = cnic;
 
@@ -2273,7 +2279,7 @@
 	if (!interface) {
 		printk(KERN_ERR PFX "bnx2fc_interface_create failed\n");
 		rc = -ENOMEM;
-		goto ifput_err;
+		goto netdev_err;
 	}
 
 	if (netdev->priv_flags & IFF_802_1Q_VLAN) {
--- linux-4.4.0.orig/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ linux-4.4.0/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -829,7 +829,7 @@
 			((u64)err_entry->data.err_warn_bitmap_hi << 32) |
 			(u64)err_entry->data.err_warn_bitmap_lo;
 		for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) {
-			if (err_warn_bit_map & (u64) (1 << i)) {
+			if (err_warn_bit_map & ((u64)1 << i)) {
 				err_warn = i;
 				break;
 			}
--- linux-4.4.0.orig/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ linux-4.4.0/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1858,6 +1858,7 @@
 		/* we will not receive ABTS response for this IO */
 		BNX2FC_IO_DBG(io_req, "Timer context finished processing "
 			   "this scsi cmd\n");
+		return;
 	}
 
 	/* Cancel the timeout_work, as we received IO completion */
--- linux-4.4.0.orig/drivers/scsi/bnx2i/Kconfig
+++ linux-4.4.0/drivers/scsi/bnx2i/Kconfig
@@ -3,6 +3,7 @@
 	depends on NET
 	depends on PCI
 	depends on (IPV6 || IPV6=n)
+	depends on MMU
 	select SCSI_ISCSI_ATTRS
 	select NETDEVICES
 	select ETHERNET
--- linux-4.4.0.orig/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ linux-4.4.0/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1363,7 +1363,7 @@
 	u32 datalen = 0;
 
 	resp_cqe = (struct bnx2i_cmd_response *)cqe;
-	spin_lock_bh(&session->back_lock);
+	spin_lock_bh(&session->lock);
 	task = iscsi_itt_to_task(conn,
 				 resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
 	if (!task)
@@ -1434,7 +1434,7 @@
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
 			     conn->data, datalen);
 fail:
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&session->lock);
 	return 0;
 }
 
@@ -1459,7 +1459,7 @@
 	int pad_len;
 
 	login = (struct bnx2i_login_response *) cqe;
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	task = iscsi_itt_to_task(conn,
 				 login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
 	if (!task)
@@ -1502,7 +1502,7 @@
 		bnx2i_conn->gen_pdu.resp_buf,
 		bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
 done:
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 	return 0;
 }
 
@@ -1527,7 +1527,7 @@
 	int pad_len;
 
 	text = (struct bnx2i_text_response *) cqe;
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX);
 	if (!task)
 		goto done;
@@ -1563,7 +1563,7 @@
 			     bnx2i_conn->gen_pdu.resp_wr_ptr -
 			     bnx2i_conn->gen_pdu.resp_buf);
 done:
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 	return 0;
 }
 
@@ -1586,7 +1586,7 @@
 	struct iscsi_tm_rsp *resp_hdr;
 
 	tmf_cqe = (struct bnx2i_tmf_response *)cqe;
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	task = iscsi_itt_to_task(conn,
 				 tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
 	if (!task)
@@ -1602,7 +1602,7 @@
 
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
 done:
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 	return 0;
 }
 
@@ -1625,7 +1625,7 @@
 	struct iscsi_logout_rsp *resp_hdr;
 
 	logout = (struct bnx2i_logout_response *) cqe;
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	task = iscsi_itt_to_task(conn,
 				 logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
 	if (!task)
@@ -1649,7 +1649,7 @@
 
 	bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
 done:
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 	return 0;
 }
 
@@ -1670,12 +1670,12 @@
 	struct iscsi_task *task;
 
 	nop_in = (struct bnx2i_nop_in_msg *)cqe;
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	task = iscsi_itt_to_task(conn,
 				 nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
 	if (task)
 		__iscsi_put_task(task);
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 }
 
 /**
@@ -1714,7 +1714,7 @@
 
 	nop_in = (struct bnx2i_nop_in_msg *)cqe;
 
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
 	memset(hdr, 0, sizeof(struct iscsi_hdr));
 	hdr->opcode = nop_in->op_code;
@@ -1740,7 +1740,7 @@
 	}
 done:
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 
 	return tgt_async_nop;
 }
@@ -1773,7 +1773,7 @@
 		return;
 	}
 
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
 	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
 	resp_hdr->opcode = async_cqe->op_code;
@@ -1792,7 +1792,7 @@
 
 	__iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
 			     (struct iscsi_hdr *)resp_hdr, NULL, 0);
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 }
 
 
@@ -1819,7 +1819,7 @@
 	} else
 		bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
 
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
 	memset(hdr, 0, sizeof(struct iscsi_hdr));
 	hdr->opcode = reject->op_code;
@@ -1830,7 +1830,7 @@
 	hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
 			     reject->data_length);
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 }
 
 /**
@@ -1850,13 +1850,13 @@
 	struct iscsi_task *task;
 
 	cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	task = iscsi_itt_to_task(conn,
 			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
 	if (!task)
 		printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
 			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 	complete(&bnx2i_conn->cmd_cleanup_cmpl);
 }
 
@@ -1923,11 +1923,11 @@
 	int rc = 0;
 	int cpu;
 
-	spin_lock(&session->back_lock);
+	spin_lock(&session->lock);
 	task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
 				 cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
 	if (!task || !task->sc) {
-		spin_unlock(&session->back_lock);
+		spin_unlock(&session->lock);
 		return -EINVAL;
 	}
 	sc = task->sc;
@@ -1937,7 +1937,7 @@
 	else
 		cpu = sc->request->cpu;
 
-	spin_unlock(&session->back_lock);
+	spin_unlock(&session->lock);
 
 	p = &per_cpu(bnx2i_percpu, cpu);
 	spin_lock(&p->p_work_lock);
@@ -2742,6 +2742,8 @@
 					      BNX2X_DOORBELL_PCI_BAR);
 		reg_off = (1 << BNX2X_DB_SHIFT) * (cid_num & 0x1FFFF);
 		ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4);
+		if (!ep->qp.ctx_base)
+			return -ENOMEM;
 		goto arm_cq;
 	}
 
--- linux-4.4.0.orig/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ linux-4.4.0/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -915,12 +915,12 @@
 	INIT_LIST_HEAD(&hba->ep_ofld_list);
 	INIT_LIST_HEAD(&hba->ep_active_list);
 	INIT_LIST_HEAD(&hba->ep_destroy_list);
-	pci_dev_put(hba->pcidev);
 
 	if (hba->regview) {
 		pci_iounmap(hba->pcidev, hba->regview);
 		hba->regview = NULL;
 	}
+	pci_dev_put(hba->pcidev);
 	bnx2i_free_mp_bdt(hba);
 	bnx2i_release_free_cid_que(hba);
 	iscsi_host_free(shost);
@@ -1172,12 +1172,10 @@
 	if (task->state == ISCSI_TASK_ABRT_TMF) {
 		bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
 
-		spin_unlock_bh(&conn->session->back_lock);
-		spin_unlock_bh(&conn->session->frwd_lock);
+		spin_unlock_bh(&conn->session->lock);
 		wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl,
 				msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT));
-		spin_lock_bh(&conn->session->frwd_lock);
-		spin_lock_bh(&conn->session->back_lock);
+		spin_lock_bh(&conn->session->lock);
 	}
 	bnx2i_iscsi_unmap_sg_list(task->dd_data);
 }
@@ -2063,7 +2061,7 @@
 		goto out;
 
 	if (session) {
-		spin_lock_bh(&session->frwd_lock);
+		spin_lock_bh(&session->lock);
 		if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
 			if (session->state == ISCSI_STATE_LOGGING_OUT) {
 				if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
@@ -2079,7 +2077,7 @@
 		} else
 			close = 1;
 
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 	}
 
 	bnx2i_ep->state = EP_STATE_DISCONN_START;
--- linux-4.4.0.orig/drivers/scsi/constants.c
+++ linux-4.4.0/drivers/scsi/constants.c
@@ -1181,8 +1181,9 @@
 
 /* Get sense key string or NULL if not available */
 const char *
-scsi_sense_key_string(unsigned char key) {
-	if (key <= 0xE)
+scsi_sense_key_string(unsigned char key)
+{
+	if (key < ARRAY_SIZE(snstext))
 		return snstext[key];
 	return NULL;
 }
--- linux-4.4.0.orig/drivers/scsi/csiostor/csio_attr.c
+++ linux-4.4.0/drivers/scsi/csiostor/csio_attr.c
@@ -582,12 +582,12 @@
 	}
 
 	fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING);
+	ln->fc_vport = fc_vport;
 
 	if (csio_fcoe_alloc_vnp(hw, ln))
 		goto error;
 
 	*(struct csio_lnode **)fc_vport->dd_data = ln;
-	ln->fc_vport = fc_vport;
 	if (!fc_vport->node_name)
 		fc_vport->node_name = wwn_to_u64(csio_ln_wwnn(ln));
 	if (!fc_vport->port_name)
--- linux-4.4.0.orig/drivers/scsi/csiostor/csio_hw.c
+++ linux-4.4.0/drivers/scsi/csiostor/csio_hw.c
@@ -1769,7 +1769,6 @@
 		goto bye;
 	}
 
-	mempool_free(mbp, hw->mb_mempool);
 	if (finicsum != cfcsum) {
 		csio_warn(hw,
 		      "Config File checksum mismatch: csum=%#x, computed=%#x\n",
@@ -1780,6 +1779,10 @@
 	rv = csio_hw_validate_caps(hw, mbp);
 	if (rv != 0)
 		goto bye;
+
+	mempool_free(mbp, hw->mb_mempool);
+	mbp = NULL;
+
 	/*
 	 * Note that we're operating with parameters
 	 * not supplied by the driver, rather than from hard-wired
@@ -1970,7 +1973,7 @@
 			FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c),
 			FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k),
 			FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k));
-		ret = EINVAL;
+		ret = -EINVAL;
 		goto bye;
 	}
 
--- linux-4.4.0.orig/drivers/scsi/csiostor/csio_init.c
+++ linux-4.4.0/drivers/scsi/csiostor/csio_init.c
@@ -648,7 +648,7 @@
 	if (csio_lnode_init(ln, hw, pln))
 		goto err_shost_put;
 
-	if (scsi_add_host(shost, dev))
+	if (scsi_add_host_with_dma(shost, dev, &hw->pdev->dev))
 		goto err_lnode_exit;
 
 	return ln;
--- linux-4.4.0.orig/drivers/scsi/csiostor/csio_lnode.c
+++ linux-4.4.0/drivers/scsi/csiostor/csio_lnode.c
@@ -238,14 +238,23 @@
 }
 
 static inline void
-csio_append_attrib(uint8_t **ptr, uint16_t type, uint8_t *val, uint16_t len)
+csio_append_attrib(uint8_t **ptr, uint16_t type, void *val, size_t val_len)
 {
+	uint16_t len;
 	struct fc_fdmi_attr_entry *ae = (struct fc_fdmi_attr_entry *)*ptr;
+
+	if (WARN_ON(val_len > U16_MAX))
+		return;
+
+	len = val_len;
+
 	ae->type = htons(type);
 	len += 4;		/* includes attribute type and length */
 	len = (len + 3) & ~3;	/* should be multiple of 4 bytes */
 	ae->len = htons(len);
-	memcpy(ae->value, val, len);
+	memcpy(ae->value, val, val_len);
+	if (len > val_len)
+		memset(ae->value + val_len, 0, len - val_len);
 	*ptr += len;
 }
 
@@ -292,6 +301,7 @@
 	struct fc_fdmi_port_name *port_name;
 	uint8_t buf[64];
 	uint8_t *fc4_type;
+	unsigned long flags;
 
 	if (fdmi_req->wr_status != FW_SUCCESS) {
 		csio_ln_dbg(ln, "WR error:%x in processing fdmi rhba cmd\n",
@@ -335,7 +345,7 @@
 	numattrs++;
 	val = htonl(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
 	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_SUPPORTEDSPEED,
-			   (uint8_t *)&val,
+			   &val,
 			   FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN);
 	numattrs++;
 
@@ -346,36 +356,35 @@
 	else
 		val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN);
 	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
-			   (uint8_t *)&val,
-			   FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
+			   &val, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
 	numattrs++;
 
 	mfs = ln->ln_sparm.csp.sp_bb_data;
 	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_MAXFRAMESIZE,
-			   (uint8_t *)&mfs, FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN);
+			   &mfs, sizeof(mfs));
 	numattrs++;
 
 	strcpy(buf, "csiostor");
 	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_OSDEVICENAME, buf,
-			   (uint16_t)strlen(buf));
+			   strlen(buf));
 	numattrs++;
 
 	if (!csio_hostname(buf, sizeof(buf))) {
 		csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_HOSTNAME,
-				   buf, (uint16_t)strlen(buf));
+				   buf, strlen(buf));
 		numattrs++;
 	}
 	attrib_blk->numattrs = htonl(numattrs);
 	len = (uint32_t)(pld - (uint8_t *)cmd);
 
 	/* Submit FDMI RPA request */
-	spin_lock_irq(&hw->lock);
+	spin_lock_irqsave(&hw->lock, flags);
 	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_done,
 				FCOE_CT, &fdmi_req->dma_buf, len)) {
 		CSIO_INC_STATS(ln, n_fdmi_err);
 		csio_ln_dbg(ln, "Failed to issue fdmi rpa req\n");
 	}
-	spin_unlock_irq(&hw->lock);
+	spin_unlock_irqrestore(&hw->lock, flags);
 }
 
 /*
@@ -396,6 +405,7 @@
 	struct fc_fdmi_rpl *reg_pl;
 	struct fs_fdmi_attrs *attrib_blk;
 	uint8_t buf[64];
+	unsigned long flags;
 
 	if (fdmi_req->wr_status != FW_SUCCESS) {
 		csio_ln_dbg(ln, "WR error:%x in processing fdmi dprt cmd\n",
@@ -444,45 +454,44 @@
 
 	strcpy(buf, "Chelsio Communications");
 	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MANUFACTURER, buf,
-			   (uint16_t)strlen(buf));
+			   strlen(buf));
 	numattrs++;
 	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_SERIALNUMBER,
-			   hw->vpd.sn, (uint16_t)sizeof(hw->vpd.sn));
+			   hw->vpd.sn, sizeof(hw->vpd.sn));
 	numattrs++;
 	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODEL, hw->vpd.id,
-			   (uint16_t)sizeof(hw->vpd.id));
+			   sizeof(hw->vpd.id));
 	numattrs++;
 	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODELDESCRIPTION,
-			   hw->model_desc, (uint16_t)strlen(hw->model_desc));
+			   hw->model_desc, strlen(hw->model_desc));
 	numattrs++;
 	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_HARDWAREVERSION,
-			   hw->hw_ver, (uint16_t)sizeof(hw->hw_ver));
+			   hw->hw_ver, sizeof(hw->hw_ver));
 	numattrs++;
 	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_FIRMWAREVERSION,
-			   hw->fwrev_str, (uint16_t)strlen(hw->fwrev_str));
+			   hw->fwrev_str, strlen(hw->fwrev_str));
 	numattrs++;
 
 	if (!csio_osname(buf, sizeof(buf))) {
 		csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_OSNAMEVERSION,
-				   buf, (uint16_t)strlen(buf));
+				   buf, strlen(buf));
 		numattrs++;
 	}
 
 	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD,
-			   (uint8_t *)&maxpayload,
-			   FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN);
+			   &maxpayload, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN);
 	len = (uint32_t)(pld - (uint8_t *)cmd);
 	numattrs++;
 	attrib_blk->numattrs = htonl(numattrs);
 
 	/* Submit FDMI RHBA request */
-	spin_lock_irq(&hw->lock);
+	spin_lock_irqsave(&hw->lock, flags);
 	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_rhba_cbfn,
 				FCOE_CT, &fdmi_req->dma_buf, len)) {
 		CSIO_INC_STATS(ln, n_fdmi_err);
 		csio_ln_dbg(ln, "Failed to issue fdmi rhba req\n");
 	}
-	spin_unlock_irq(&hw->lock);
+	spin_unlock_irqrestore(&hw->lock, flags);
 }
 
 /*
@@ -497,6 +506,7 @@
 	void *cmd;
 	struct fc_fdmi_port_name *port_name;
 	uint32_t len;
+	unsigned long flags;
 
 	if (fdmi_req->wr_status != FW_SUCCESS) {
 		csio_ln_dbg(ln, "WR error:%x in processing fdmi dhba cmd\n",
@@ -527,13 +537,13 @@
 	len += sizeof(*port_name);
 
 	/* Submit FDMI request */
-	spin_lock_irq(&hw->lock);
+	spin_lock_irqsave(&hw->lock, flags);
 	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dprt_cbfn,
 				FCOE_CT, &fdmi_req->dma_buf, len)) {
 		CSIO_INC_STATS(ln, n_fdmi_err);
 		csio_ln_dbg(ln, "Failed to issue fdmi dprt req\n");
 	}
-	spin_unlock_irq(&hw->lock);
+	spin_unlock_irqrestore(&hw->lock, flags);
 }
 
 /**
@@ -1794,6 +1804,8 @@
 	struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw);
 	int rv;
 
+	BUG_ON(pld_len > pld->len);
+
 	io_req->io_cbfn = io_cbfn;	/* Upper layer callback handler */
 	io_req->fw_handle = (uintptr_t) (io_req);
 	io_req->eq_idx = mgmtm->eq_idx;
--- linux-4.4.0.orig/drivers/scsi/csiostor/csio_scsi.c
+++ linux-4.4.0/drivers/scsi/csiostor/csio_scsi.c
@@ -1383,7 +1383,7 @@
 		return -EINVAL;
 
 	/* Delete NPIV lnodes */
-	 csio_lnodes_exit(hw, 1);
+	csio_lnodes_exit(hw, 1);
 
 	/* Block upper IOs */
 	csio_lnodes_block_request(hw);
@@ -1713,8 +1713,11 @@
 	}
 
 out:
-	if (req->nsge > 0)
+	if (req->nsge > 0) {
 		scsi_dma_unmap(cmnd);
+		if (req->dcopy && (host_status == DID_OK))
+			host_status = csio_scsi_copy_to_sgl(hw, req);
+	}
 
 	cmnd->result = (((host_status) << 16) | scsi_status);
 	cmnd->scsi_done(cmnd);
--- linux-4.4.0.orig/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ linux-4.4.0/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -1339,6 +1339,7 @@
 		csk, csk->state, csk->flags, csk->tid);
 
 	cxgbi_sock_free_cpl_skbs(csk);
+	cxgbi_sock_purge_write_queue(csk);
 	if (csk->wr_cred != csk->wr_max_cred) {
 		cxgbi_sock_purge_wr_queue(csk);
 		cxgbi_sock_reset_wr_list(csk);
--- linux-4.4.0.orig/drivers/scsi/cxgbi/libcxgbi.c
+++ linux-4.4.0/drivers/scsi/cxgbi/libcxgbi.c
@@ -634,6 +634,10 @@
 
 	if (ndev->flags & IFF_LOOPBACK) {
 		ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr);
+		if (!ndev) {
+			err = -ENETUNREACH;
+			goto rel_neigh;
+		}
 		mtu = ndev->mtu;
 		pr_info("rt dev %s, loopback -> %s, mtu %u.\n",
 			n->dev->name, ndev->name, mtu);
@@ -688,6 +692,7 @@
 {
 	struct flowi6 fl;
 
+	memset(&fl, 0, sizeof(fl));
 	if (saddr)
 		memcpy(&fl.saddr, saddr, sizeof(struct in6_addr));
 	if (daddr)
--- linux-4.4.0.orig/drivers/scsi/cxlflash/common.h
+++ linux-4.4.0/drivers/scsi/cxlflash/common.h
@@ -34,7 +34,6 @@
 								   sectors
 								*/
 
-#define NUM_RRQ_ENTRY    16     /* for master issued cmds */
 #define MAX_RHT_PER_CONTEXT (PAGE_SIZE / sizeof(struct sisl_rht_entry))
 
 /* AFU command retry limit */
@@ -48,9 +47,12 @@
 							   index derivation
 							 */
 
-#define CXLFLASH_MAX_CMDS               16
+#define CXLFLASH_MAX_CMDS               256
 #define CXLFLASH_MAX_CMDS_PER_LUN       CXLFLASH_MAX_CMDS
 
+/* RRQ for master issued cmds */
+#define NUM_RRQ_ENTRY                   CXLFLASH_MAX_CMDS
+
 
 static inline void check_sizes(void)
 {
@@ -106,7 +108,6 @@
 	atomic_t scan_host_needed;
 
 	struct cxl_afu *cxl_afu;
-	struct pci_dev *parent_dev;
 
 	atomic_t recovery_threads;
 	struct mutex ctx_recovery_mutex;
@@ -149,7 +150,7 @@
 struct afu {
 	/* Stuff requiring alignment go first. */
 
-	u64 rrq_entry[NUM_RRQ_ENTRY];	/* 128B RRQ */
+	u64 rrq_entry[NUM_RRQ_ENTRY];	/* 2K RRQ */
 	/*
 	 * Command & data for AFU commands.
 	 */
@@ -165,6 +166,8 @@
 	struct sisl_host_map __iomem *host_map;		/* MC host map */
 	struct sisl_ctrl_map __iomem *ctrl_map;		/* MC control map */
 
+	struct kref mapcount;
+
 	ctx_hndl_t ctx_hndl;	/* master's context handle */
 	u64 *hrrq_start;
 	u64 *hrrq_end;
--- linux-4.4.0.orig/drivers/scsi/cxlflash/main.c
+++ linux-4.4.0/drivers/scsi/cxlflash/main.c
@@ -289,7 +289,7 @@
 		atomic64_set(&afu->room, room);
 		if (room)
 			goto write_rrin;
-		udelay(nretry);
+		udelay(1 << nretry);
 	} while (nretry++ < MC_ROOM_RETRY_CNT);
 
 	pr_err("%s: no cmd_room to send reset\n", __func__);
@@ -303,7 +303,7 @@
 		if (rrin != 0x1)
 			break;
 		/* Double delay each time */
-		udelay(2 << nretry);
+		udelay(1 << nretry);
 	} while (nretry++ < MC_ROOM_RETRY_CNT);
 }
 
@@ -338,7 +338,7 @@
 			atomic64_set(&afu->room, room);
 			if (room)
 				goto write_ioarrin;
-			udelay(nretry);
+			udelay(1 << nretry);
 		} while (nretry++ < MC_ROOM_RETRY_CNT);
 
 		dev_err(dev, "%s: no cmd_room to send 0x%X\n",
@@ -352,7 +352,7 @@
 		 * afu->room.
 		 */
 		if (nretry++ < MC_ROOM_RETRY_CNT) {
-			udelay(nretry);
+			udelay(1 << nretry);
 			goto retry;
 		}
 
@@ -368,6 +368,7 @@
 
 no_room:
 	afu->read_room = true;
+	kref_get(&cfg->afu->mapcount);
 	schedule_work(&cfg->work_q);
 	rc = SCSI_MLQUEUE_HOST_BUSY;
 	goto out;
@@ -473,6 +474,16 @@
 	return rc;
 }
 
+static void afu_unmap(struct kref *ref)
+{
+	struct afu *afu = container_of(ref, struct afu, mapcount);
+
+	if (likely(afu->afu_map)) {
+		cxl_psa_unmap((void __iomem *)afu->afu_map);
+		afu->afu_map = NULL;
+	}
+}
+
 /**
  * cxlflash_driver_info() - information handler for this host driver
  * @host:	SCSI host associated with device.
@@ -503,6 +514,7 @@
 	ulong lock_flags;
 	short lflag = 0;
 	int rc = 0;
+	int kref_got = 0;
 
 	dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
 			    "cdb=(%08X-%08X-%08X-%08X)\n",
@@ -547,6 +559,9 @@
 		goto out;
 	}
 
+	kref_get(&cfg->afu->mapcount);
+	kref_got = 1;
+
 	cmd->rcb.ctx_id = afu->ctx_hndl;
 	cmd->rcb.port_sel = port_sel;
 	cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
@@ -587,6 +602,8 @@
 	}
 
 out:
+	if (kref_got)
+		kref_put(&afu->mapcount, afu_unmap);
 	pr_devel("%s: returning rc=%d\n", __func__, rc);
 	return rc;
 }
@@ -632,46 +649,57 @@
  * @cfg:	Internal structure associated with the host.
  *
  * Safe to call with AFU in a partially allocated/initialized state.
+ *
+ * Cleans up all state associated with the command queue, and unmaps
+ * the MMIO space.
+ *
+ *  - complete() will take care of commands we initiated (they'll be checked
+ *  in as part of the cleanup that occurs after the completion)
+ *
+ *  - cmd_checkin() will take care of entries that we did not initiate and that
+ *  have not (and will not) complete because they are sitting on a [now stale]
+ *  hardware queue
  */
 static void stop_afu(struct cxlflash_cfg *cfg)
 {
 	int i;
 	struct afu *afu = cfg->afu;
+	struct afu_cmd *cmd;
 
 	if (likely(afu)) {
-		for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
-			complete(&afu->cmd[i].cevent);
+		for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
+			cmd = &afu->cmd[i];
+			complete(&cmd->cevent);
+			if (!atomic_read(&cmd->free))
+				cmd_checkin(cmd);
+		}
 
 		if (likely(afu->afu_map)) {
 			cxl_psa_unmap((void __iomem *)afu->afu_map);
 			afu->afu_map = NULL;
 		}
+		kref_put(&afu->mapcount, afu_unmap);
 	}
 }
 
 /**
- * term_mc() - terminates the master context
+ * term_intr() - disables all AFU interrupts
  * @cfg:	Internal structure associated with the host.
  * @level:	Depth of allocation, where to begin waterfall tear down.
  *
  * Safe to call with AFU/MC in partially allocated/initialized state.
  */
-static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level)
+static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level)
 {
-	int rc = 0;
 	struct afu *afu = cfg->afu;
 	struct device *dev = &cfg->dev->dev;
 
 	if (!afu || !cfg->mcctx) {
-		dev_err(dev, "%s: returning from term_mc with NULL afu or MC\n",
-		       __func__);
+		dev_err(dev, "%s: returning with NULL afu or MC\n", __func__);
 		return;
 	}
 
 	switch (level) {
-	case UNDO_START:
-		rc = cxl_stop_context(cfg->mcctx);
-		BUG_ON(rc);
 	case UNMAP_THREE:
 		cxl_unmap_afu_irq(cfg->mcctx, 3, afu);
 	case UNMAP_TWO:
@@ -680,12 +708,37 @@
 		cxl_unmap_afu_irq(cfg->mcctx, 1, afu);
 	case FREE_IRQ:
 		cxl_free_afu_irqs(cfg->mcctx);
-	case RELEASE_CONTEXT:
-		cfg->mcctx = NULL;
+		/* fall through */
+	case UNDO_NOOP:
+		/* No action required */
+		break;
 	}
 }
 
 /**
+ * term_mc() - terminates the master context
+ * @cfg:	Internal structure associated with the host.
+ * @level:	Depth of allocation, where to begin waterfall tear down.
+ *
+ * Safe to call with AFU/MC in partially allocated/initialized state.
+ */
+static void term_mc(struct cxlflash_cfg *cfg)
+{
+	int rc = 0;
+	struct afu *afu = cfg->afu;
+	struct device *dev = &cfg->dev->dev;
+
+	if (!afu || !cfg->mcctx) {
+		dev_err(dev, "%s: returning with NULL afu or MC\n", __func__);
+		return;
+	}
+
+	rc = cxl_stop_context(cfg->mcctx);
+	WARN_ON(rc);
+	cfg->mcctx = NULL;
+}
+
+/**
  * term_afu() - terminates the AFU
  * @cfg:	Internal structure associated with the host.
  *
@@ -693,15 +746,83 @@
  */
 static void term_afu(struct cxlflash_cfg *cfg)
 {
-	term_mc(cfg, UNDO_START);
-
+	/*
+	 * Tear down is carefully orchestrated to ensure
+	 * no interrupts can come in when the problem state
+	 * area is unmapped.
+	 *
+	 * 1) Disable all AFU interrupts
+	 * 2) Unmap the problem state area
+	 * 3) Stop the master context
+	 */
+	term_intr(cfg, UNMAP_THREE);
 	if (cfg->afu)
 		stop_afu(cfg);
 
+	term_mc(cfg);
+
 	pr_debug("%s: returning\n", __func__);
 }
 
 /**
+ * notify_shutdown() - notifies device of pending shutdown
+ * @cfg:	Internal structure associated with the host.
+ * @wait:	Whether to wait for shutdown processing to complete.
+ *
+ * This function will notify the AFU that the adapter is being shutdown
+ * and will wait for shutdown processing to complete if wait is true.
+ * This notification should flush pending I/Os to the device and halt
+ * further I/Os until the next AFU reset is issued and device restarted.
+ */
+static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait)
+{
+	struct afu *afu = cfg->afu;
+	struct device *dev = &cfg->dev->dev;
+	struct sisl_global_map __iomem *global;
+	struct dev_dependent_vals *ddv;
+	u64 reg, status;
+	int i, retry_cnt = 0;
+
+	ddv = (struct dev_dependent_vals *)cfg->dev_id->driver_data;
+	if (!(ddv->flags & CXLFLASH_NOTIFY_SHUTDOWN))
+		return;
+
+	if (!afu || !afu->afu_map) {
+		dev_dbg(dev, "%s: The problem state area is not mapped\n",
+			__func__);
+		return;
+	}
+
+	global = &afu->afu_map->global;
+
+	/* Notify AFU */
+	for (i = 0; i < NUM_FC_PORTS; i++) {
+		reg = readq_be(&global->fc_regs[i][FC_CONFIG2 / 8]);
+		reg |= SISL_FC_SHUTDOWN_NORMAL;
+		writeq_be(reg, &global->fc_regs[i][FC_CONFIG2 / 8]);
+	}
+
+	if (!wait)
+		return;
+
+	/* Wait up to 1.5 seconds for shutdown processing to complete */
+	for (i = 0; i < NUM_FC_PORTS; i++) {
+		retry_cnt = 0;
+		while (true) {
+			status = readq_be(&global->fc_regs[i][FC_STATUS / 8]);
+			if (status & SISL_STATUS_SHUTDOWN_COMPLETE)
+				break;
+			if (++retry_cnt >= MC_RETRY_CNT) {
+				dev_dbg(dev, "%s: port %d shutdown processing "
+					"not yet completed\n", __func__, i);
+				break;
+			}
+			msleep(100 * retry_cnt);
+		}
+	}
+}
+
+/**
  * cxlflash_remove() - PCI entry point to tear down host
  * @pdev:	PCI device associated with the host.
  *
@@ -712,6 +833,11 @@
 	struct cxlflash_cfg *cfg = pci_get_drvdata(pdev);
 	ulong lock_flags;
 
+	if (!pci_is_enabled(pdev)) {
+		pr_debug("%s: Device is disabled\n", __func__);
+		return;
+	}
+
 	/* If a Task Management Function is active, wait for it to complete
 	 * before continuing with remove.
 	 */
@@ -722,6 +848,9 @@
 						  cfg->tmf_slock);
 	spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags);
 
+	/* Notify AFU and wait for shutdown processing to complete */
+	notify_shutdown(cfg, true);
+
 	cfg->state = STATE_FAILTERM;
 	cxlflash_stop_term_user_contexts(cfg);
 
@@ -731,10 +860,9 @@
 		scsi_remove_host(cfg->host);
 		/* fall through */
 	case INIT_STATE_AFU:
-		term_afu(cfg);
 		cancel_work_sync(&cfg->work_q);
+		term_afu(cfg);
 	case INIT_STATE_PCI:
-		pci_release_regions(cfg->dev);
 		pci_disable_device(pdev);
 	case INIT_STATE_NONE:
 		free_mem(cfg);
@@ -807,15 +935,6 @@
 	struct pci_dev *pdev = cfg->dev;
 	int rc = 0;
 
-	cfg->cxlflash_regs_pci = pci_resource_start(pdev, 0);
-	rc = pci_request_regions(pdev, CXLFLASH_NAME);
-	if (rc < 0) {
-		dev_err(&pdev->dev,
-			"%s: Couldn't register memory range of registers\n",
-			__func__);
-		goto out;
-	}
-
 	rc = pci_enable_device(pdev);
 	if (rc || pci_channel_offline(pdev)) {
 		if (pci_channel_offline(pdev)) {
@@ -827,55 +946,13 @@
 			dev_err(&pdev->dev, "%s: Cannot enable adapter\n",
 				__func__);
 			cxlflash_wait_for_pci_err_recovery(cfg);
-			goto out_release_regions;
-		}
-	}
-
-	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-	if (rc < 0) {
-		dev_dbg(&pdev->dev, "%s: Failed to set 64 bit PCI DMA mask\n",
-			__func__);
-		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-	}
-
-	if (rc < 0) {
-		dev_err(&pdev->dev, "%s: Failed to set PCI DMA mask\n",
-			__func__);
-		goto out_disable;
-	}
-
-	pci_set_master(pdev);
-
-	if (pci_channel_offline(pdev)) {
-		cxlflash_wait_for_pci_err_recovery(cfg);
-		if (pci_channel_offline(pdev)) {
-			rc = -EIO;
-			goto out_msi_disable;
+			goto out;
 		}
 	}
 
-	rc = pci_save_state(pdev);
-
-	if (rc != PCIBIOS_SUCCESSFUL) {
-		dev_err(&pdev->dev, "%s: Failed to save PCI config space\n",
-			__func__);
-		rc = -EIO;
-		goto cleanup_nolog;
-	}
-
 out:
 	pr_debug("%s: returning rc=%d\n", __func__, rc);
 	return rc;
-
-cleanup_nolog:
-out_msi_disable:
-	cxlflash_wait_for_pci_err_recovery(cfg);
-out_disable:
-	pci_disable_device(pdev);
-out_release_regions:
-	pci_release_regions(pdev);
-	goto out;
-
 }
 
 /**
@@ -963,6 +1040,8 @@
 	do {
 		msleep(delay_us / 1000);
 		status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]);
+		if (status == U64_MAX)
+			nretry /= 2;
 	} while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_ONLINE &&
 		 nretry--);
 
@@ -994,6 +1073,8 @@
 	do {
 		msleep(delay_us / 1000);
 		status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]);
+		if (status == U64_MAX)
+			nretry /= 2;
 	} while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_OFFLINE &&
 		 nretry--);
 
@@ -1104,15 +1185,15 @@
 	{SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR},
 	{SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, SCAN_HOST},
 	{SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0},
-	{SISL_ASTATUS_FC0_LINK_UP, "link up", 0, SCAN_HOST},
+	{SISL_ASTATUS_FC0_LINK_UP, "link up", 0, 0},
 	{SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET},
 	{SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0},
 	{SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET},
-	{SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0},
+	{SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET},
 	{SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR},
 	{SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST},
 	{SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0},
-	{SISL_ASTATUS_FC1_LINK_UP, "link up", 1, SCAN_HOST},
+	{SISL_ASTATUS_FC1_LINK_UP, "link up", 1, 0},
 	{0x0, "", 0, 0}		/* terminator */
 };
 
@@ -1316,6 +1397,7 @@
 				__func__, port);
 			cfg->lr_state = LINK_RESET_REQUIRED;
 			cfg->lr_port = port;
+			kref_get(&cfg->afu->mapcount);
 			schedule_work(&cfg->work_q);
 		}
 
@@ -1336,6 +1418,7 @@
 
 		if (info->action & SCAN_HOST) {
 			atomic_inc(&cfg->scan_host_needed);
+			kref_get(&cfg->afu->mapcount);
 			schedule_work(&cfg->work_q);
 		}
 	}
@@ -1372,7 +1455,7 @@
  */
 static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
 {
-	struct pci_dev *dev = cfg->parent_dev;
+	struct pci_dev *dev = cfg->dev;
 	int rc = 0;
 	int ro_start, ro_size, i, j, k;
 	ssize_t vpd_size;
@@ -1381,7 +1464,7 @@
 	char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" };
 
 	/* Get the VPD data from the device */
-	vpd_size = pci_read_vpd(dev, 0, sizeof(vpd_data), vpd_data);
+	vpd_size = cxl_read_adapter_vpd(dev, vpd_data, sizeof(vpd_data));
 	if (unlikely(vpd_size <= 0)) {
 		dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n",
 		       __func__, vpd_size);
@@ -1614,41 +1697,24 @@
 }
 
 /**
- * init_mc() - create and register as the master context
+ * init_intr() - setup interrupt handlers for the master context
  * @cfg:	Internal structure associated with the host.
  *
  * Return: 0 on success, -errno on failure
  */
-static int init_mc(struct cxlflash_cfg *cfg)
+static enum undo_level init_intr(struct cxlflash_cfg *cfg,
+				 struct cxl_context *ctx)
 {
-	struct cxl_context *ctx;
-	struct device *dev = &cfg->dev->dev;
 	struct afu *afu = cfg->afu;
+	struct device *dev = &cfg->dev->dev;
 	int rc = 0;
-	enum undo_level level;
-
-	ctx = cxl_get_context(cfg->dev);
-	if (unlikely(!ctx))
-		return -ENOMEM;
-	cfg->mcctx = ctx;
-
-	/* Set it up as a master with the CXL */
-	cxl_set_master(ctx);
-
-	/* During initialization reset the AFU to start from a clean slate */
-	rc = cxl_afu_reset(cfg->mcctx);
-	if (unlikely(rc)) {
-		dev_err(dev, "%s: initial AFU reset failed rc=%d\n",
-			__func__, rc);
-		level = RELEASE_CONTEXT;
-		goto out;
-	}
+	enum undo_level level = UNDO_NOOP;
 
 	rc = cxl_allocate_afu_irqs(ctx, 3);
 	if (unlikely(rc)) {
 		dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n",
 			__func__, rc);
-		level = RELEASE_CONTEXT;
+		level = UNDO_NOOP;
 		goto out;
 	}
 
@@ -1678,8 +1744,47 @@
 		level = UNMAP_TWO;
 		goto out;
 	}
+out:
+	return level;
+}
 
-	rc = 0;
+/**
+ * init_mc() - create and register as the master context
+ * @cfg:	Internal structure associated with the host.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int init_mc(struct cxlflash_cfg *cfg)
+{
+	struct cxl_context *ctx;
+	struct device *dev = &cfg->dev->dev;
+	int rc = 0;
+	enum undo_level level;
+
+	ctx = cxl_get_context(cfg->dev);
+	if (unlikely(!ctx)) {
+		rc = -ENOMEM;
+		goto ret;
+	}
+	cfg->mcctx = ctx;
+
+	/* Set it up as a master with the CXL */
+	cxl_set_master(ctx);
+
+	/* During initialization reset the AFU to start from a clean slate */
+	rc = cxl_afu_reset(cfg->mcctx);
+	if (unlikely(rc)) {
+		dev_err(dev, "%s: initial AFU reset failed rc=%d\n",
+			__func__, rc);
+		goto ret;
+	}
+
+	level = init_intr(cfg, ctx);
+	if (unlikely(level)) {
+		dev_err(dev, "%s: setting up interrupts failed rc=%d\n",
+			__func__, rc);
+		goto out;
+	}
 
 	/* This performs the equivalent of the CXL_IOCTL_START_WORK.
 	 * The CXL_IOCTL_GET_PROCESS_ELEMENT is implicit in the process
@@ -1695,7 +1800,7 @@
 	pr_debug("%s: returning rc=%d\n", __func__, rc);
 	return rc;
 out:
-	term_mc(cfg, level);
+	term_intr(cfg, level);
 	goto ret;
 }
 
@@ -1731,6 +1836,7 @@
 		rc = -ENOMEM;
 		goto err1;
 	}
+	kref_init(&afu->mapcount);
 
 	/* No byte reverse on reading afu_version or string will be backwards */
 	reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1765,10 +1871,10 @@
 	return rc;
 
 err2:
-	cxl_psa_unmap((void __iomem *)afu->afu_map);
-	afu->afu_map = NULL;
+	kref_put(&afu->mapcount, afu_unmap);
 err1:
-	term_mc(cfg, UNDO_START);
+	term_intr(cfg, UNMAP_THREE);
+	term_mc(cfg);
 	goto out;
 }
 
@@ -1880,6 +1986,19 @@
 }
 
 /**
+ * drain_ioctls() - wait until all currently executing ioctls have completed
+ * @cfg:	Internal structure associated with the host.
+ *
+ * Obtain write access to read/write semaphore that wraps ioctl
+ * handling to 'drain' ioctls currently executing.
+ */
+static void drain_ioctls(struct cxlflash_cfg *cfg)
+{
+	down_write(&cfg->ioctl_rwsem);
+	up_write(&cfg->ioctl_rwsem);
+}
+
+/**
  * cxlflash_eh_device_reset_handler() - reset a single LUN
  * @scp:	SCSI command to send.
  *
@@ -1927,6 +2046,11 @@
  * cxlflash_eh_host_reset_handler() - reset the host adapter
  * @scp:	SCSI command from stack identifying host.
  *
+ * Following a reset, the state is evaluated again in case an EEH occurred
+ * during the reset. In such a scenario, the host reset will either yield
+ * until the EEH recovery is complete or return success or failure based
+ * upon the current device state.
+ *
  * Return:
  *	SUCCESS as defined in scsi/scsi.h
  *	FAILED as defined in scsi/scsi.h
@@ -1950,6 +2074,7 @@
 	switch (cfg->state) {
 	case STATE_NORMAL:
 		cfg->state = STATE_RESET;
+		drain_ioctls(cfg);
 		cxlflash_mark_contexts_error(cfg);
 		rcr = afu_reset(cfg);
 		if (rcr) {
@@ -1958,7 +2083,8 @@
 		} else
 			cfg->state = STATE_NORMAL;
 		wake_up_all(&cfg->reset_waitq);
-		break;
+		ssleep(1);
+		/* fall through */
 	case STATE_RESET:
 		wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
 		if (cfg->state == STATE_NORMAL)
@@ -2114,6 +2240,16 @@
 	rc = kstrtouint(buf, 10, &lun_mode);
 	if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) {
 		afu->internal_lun = lun_mode;
+
+		/*
+		 * When configured for internal LUN, there is only one channel,
+		 * channel number 0, else there will be 2 (default).
+		 */
+		if (afu->internal_lun)
+			shost->max_channel = 0;
+		else
+			shost->max_channel = NUM_FC_PORTS - 1;
+
 		afu_reset(cfg);
 		scsi_scan_host(cfg->host);
 	}
@@ -2260,7 +2396,7 @@
 	.eh_device_reset_handler = cxlflash_eh_device_reset_handler,
 	.eh_host_reset_handler = cxlflash_eh_host_reset_handler,
 	.change_queue_depth = cxlflash_change_queue_depth,
-	.cmd_per_lun = 16,
+	.cmd_per_lun = CXLFLASH_MAX_CMDS_PER_LUN,
 	.can_queue = CXLFLASH_MAX_CMDS,
 	.this_id = -1,
 	.sg_tablesize = SG_NONE,	/* No scatter gather support */
@@ -2273,7 +2409,10 @@
 /*
  * Device dependent values
  */
-static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
+static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS,
+					0ULL };
+static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS,
+					CXLFLASH_NOTIFY_SHUTDOWN };
 
 /*
  * PCI device binding table
@@ -2281,6 +2420,8 @@
 static struct pci_device_id cxlflash_pci_table[] = {
 	{PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
+	{PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals},
 	{}
 };
 
@@ -2339,6 +2480,7 @@
 
 	if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
 		scsi_scan_host(cfg->host);
+	kref_put(&afu->mapcount, afu_unmap);
 }
 
 /**
@@ -2353,7 +2495,6 @@
 {
 	struct Scsi_Host *host;
 	struct cxlflash_cfg *cfg = NULL;
-	struct device *phys_dev;
 	struct dev_dependent_vals *ddv;
 	int rc = 0;
 
@@ -2419,19 +2560,6 @@
 
 	pci_set_drvdata(pdev, cfg);
 
-	/*
-	 * Use the special service provided to look up the physical
-	 * PCI device, since we are called on the probe of the virtual
-	 * PCI host bus (vphb)
-	 */
-	phys_dev = cxl_get_phys_dev(pdev);
-	if (!dev_is_pci(phys_dev)) {
-		dev_err(&pdev->dev, "%s: not a pci dev\n", __func__);
-		rc = -ENODEV;
-		goto out_remove;
-	}
-	cfg->parent_dev = to_pci_dev(phys_dev);
-
 	cfg->cxl_afu = cxl_pci_to_afu(pdev);
 
 	rc = init_pci(cfg);
@@ -2468,23 +2596,13 @@
 }
 
 /**
- * drain_ioctls() - wait until all currently executing ioctls have completed
- * @cfg:	Internal structure associated with the host.
- *
- * Obtain write access to read/write semaphore that wraps ioctl
- * handling to 'drain' ioctls currently executing.
- */
-static void drain_ioctls(struct cxlflash_cfg *cfg)
-{
-	down_write(&cfg->ioctl_rwsem);
-	up_write(&cfg->ioctl_rwsem);
-}
-
-/**
  * cxlflash_pci_error_detected() - called when a PCI error is detected
  * @pdev:	PCI device struct.
  * @state:	PCI channel state.
  *
+ * When an EEH occurs during an active reset, wait until the reset is
+ * complete and then take action based upon the device state.
+ *
  * Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
  */
 static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev,
@@ -2498,6 +2616,10 @@
 
 	switch (state) {
 	case pci_channel_io_frozen:
+		wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
+		if (cfg->state == STATE_FAILTERM)
+			return PCI_ERS_RESULT_DISCONNECT;
+
 		cfg->state = STATE_RESET;
 		scsi_block_requests(cfg->host);
 		drain_ioctls(cfg);
@@ -2505,8 +2627,7 @@
 		if (unlikely(rc))
 			dev_err(dev, "%s: Failed to mark user contexts!(%d)\n",
 				__func__, rc);
-		term_mc(cfg, UNDO_START);
-		stop_afu(cfg);
+		term_afu(cfg);
 		return PCI_ERS_RESULT_NEED_RESET;
 	case pci_channel_io_perm_failure:
 		cfg->state = STATE_FAILTERM;
@@ -2575,6 +2696,7 @@
 	.id_table = cxlflash_pci_table,
 	.probe = cxlflash_probe,
 	.remove = cxlflash_remove,
+	.shutdown = cxlflash_remove,
 	.err_handler = &cxlflash_err_handler,
 };
 
@@ -2585,8 +2707,7 @@
  */
 static int __init init_cxlflash(void)
 {
-	pr_info("%s: IBM Power CXL Flash Adapter: %s\n",
-		__func__, CXLFLASH_DRIVER_DATE);
+	pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME);
 
 	cxlflash_list_init();
 
--- linux-4.4.0.orig/drivers/scsi/cxlflash/main.h
+++ linux-4.4.0/drivers/scsi/cxlflash/main.h
@@ -22,10 +22,9 @@
 
 #define CXLFLASH_NAME		"cxlflash"
 #define CXLFLASH_ADAPTER_NAME	"IBM POWER CXL Flash Adapter"
-#define CXLFLASH_DRIVER_DATE	"(August 13, 2015)"
 
-#define PCI_DEVICE_ID_IBM_CORSA	0x04F0
-#define CXLFLASH_SUBS_DEV_ID	0x04F0
+#define PCI_DEVICE_ID_IBM_CORSA		0x04F0
+#define PCI_DEVICE_ID_IBM_FLASH_GT	0x0600
 
 /* Since there is only one target, make it 0 */
 #define CXLFLASH_TARGET		0
@@ -80,16 +79,17 @@
 #define WWPN_BUF_LEN	(WWPN_LEN + 1)
 
 enum undo_level {
-	RELEASE_CONTEXT = 0,
+	UNDO_NOOP = 0,
 	FREE_IRQ,
 	UNMAP_ONE,
 	UNMAP_TWO,
-	UNMAP_THREE,
-	UNDO_START
+	UNMAP_THREE
 };
 
 struct dev_dependent_vals {
 	u64 max_sectors;
+	u64 flags;
+#define CXLFLASH_NOTIFY_SHUTDOWN   0x0000000000000001ULL
 };
 
 struct asyc_intr_info {
--- linux-4.4.0.orig/drivers/scsi/cxlflash/sislite.h
+++ linux-4.4.0/drivers/scsi/cxlflash/sislite.h
@@ -311,6 +311,12 @@
 #define SISL_FC_INTERNAL_MASK	~(SISL_FC_INTERNAL_UNMASK)
 #define SISL_FC_INTERNAL_SHIFT	32
 
+#define SISL_FC_SHUTDOWN_NORMAL		0x0000000000000010ULL
+#define SISL_FC_SHUTDOWN_ABRUPT		0x0000000000000020ULL
+
+#define SISL_STATUS_SHUTDOWN_ACTIVE	0x0000000000000010ULL
+#define SISL_STATUS_SHUTDOWN_COMPLETE	0x0000000000000020ULL
+
 #define SISL_ASTATUS_UNMASK	0xFFFFULL		/* 1 means unmasked */
 #define SISL_ASTATUS_MASK	~(SISL_ASTATUS_UNMASK)	/* 1 means masked */
 
--- linux-4.4.0.orig/drivers/scsi/cxlflash/superpipe.c
+++ linux-4.4.0/drivers/scsi/cxlflash/superpipe.c
@@ -709,27 +709,32 @@
  * @cfg:	Internal structure associated with the host.
  * @ctxi:	Context to release.
  *
- * Note that the rht_lun member of the context was cut from a single
- * allocation when the context was created and therefore does not need
- * to be explicitly freed. Also note that we conditionally check for the
- * existence of the context control map before clearing the RHT registers
- * and context capabilities because it is possible to destroy a context
- * while the context is in the error state (previous mapping was removed
- * [so we don't have to worry about clearing] and context is waiting for
- * a new mapping).
+ * This routine is safe to be called with a a non-initialized context
+ * and is tolerant of being called with the context's mutex held (it
+ * will be unlocked if necessary before freeing). Also note that the
+ * routine conditionally checks for the existence of the context control
+ * map before clearing the RHT registers and context capabilities because
+ * it is possible to destroy a context while the context is in the error
+ * state (previous mapping was removed [so there is no need to worry about
+ * clearing] and context is waiting for a new mapping).
  */
 static void destroy_context(struct cxlflash_cfg *cfg,
 			    struct ctx_info *ctxi)
 {
 	struct afu *afu = cfg->afu;
 
-	WARN_ON(!list_empty(&ctxi->luns));
+	if (ctxi->initialized) {
+		WARN_ON(!list_empty(&ctxi->luns));
 
-	/* Clear RHT registers and drop all capabilities for this context */
-	if (afu->afu_map && ctxi->ctrl_map) {
-		writeq_be(0, &ctxi->ctrl_map->rht_start);
-		writeq_be(0, &ctxi->ctrl_map->rht_cnt_id);
-		writeq_be(0, &ctxi->ctrl_map->ctx_cap);
+		/* Clear RHT registers and drop all capabilities for context */
+		if (afu->afu_map && ctxi->ctrl_map) {
+			writeq_be(0, &ctxi->ctrl_map->rht_start);
+			writeq_be(0, &ctxi->ctrl_map->rht_cnt_id);
+			writeq_be(0, &ctxi->ctrl_map->ctx_cap);
+		}
+
+		if (mutex_is_locked(&ctxi->mutex))
+			mutex_unlock(&ctxi->mutex);
 	}
 
 	/* Free memory associated with context */
@@ -742,23 +747,12 @@
 /**
  * create_context() - allocates and initializes a context
  * @cfg:	Internal structure associated with the host.
- * @ctx:	Previously obtained CXL context reference.
- * @ctxid:	Previously obtained process element associated with CXL context.
- * @adap_fd:	Previously obtained adapter fd associated with CXL context.
- * @file:	Previously obtained file associated with CXL context.
- * @perms:	User-specified permissions.
- *
- * The context's mutex is locked when an allocated context is returned.
  *
  * Return: Allocated context on success, NULL on failure
  */
-static struct ctx_info *create_context(struct cxlflash_cfg *cfg,
-				       struct cxl_context *ctx, int ctxid,
-				       int adap_fd, struct file *file,
-				       u32 perms)
+static struct ctx_info *create_context(struct cxlflash_cfg *cfg)
 {
 	struct device *dev = &cfg->dev->dev;
-	struct afu *afu = cfg->afu;
 	struct ctx_info *ctxi = NULL;
 	struct llun_info **lli = NULL;
 	u8 *ws = NULL;
@@ -781,28 +775,49 @@
 	ctxi->rht_lun = lli;
 	ctxi->rht_needs_ws = ws;
 	ctxi->rht_start = rhte;
-	ctxi->rht_perms = perms;
+out:
+	return ctxi;
+
+err:
+	kfree(ws);
+	kfree(lli);
+	kfree(ctxi);
+	ctxi = NULL;
+	goto out;
+}
+
+/**
+ * init_context() - initializes a previously allocated context
+ * @ctxi:	Previously allocated context
+ * @cfg:	Internal structure associated with the host.
+ * @ctx:	Previously obtained CXL context reference.
+ * @ctxid:	Previously obtained process element associated with CXL context.
+ * @adap_fd:	Previously obtained adapter fd associated with CXL context.
+ * @file:	Previously obtained file associated with CXL context.
+ * @perms:	User-specified permissions.
+ *
+ * Upon return, the context is marked as initialized and the context's mutex
+ * is locked.
+ */
+static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg,
+			 struct cxl_context *ctx, int ctxid, int adap_fd,
+			 struct file *file, u32 perms)
+{
+	struct afu *afu = cfg->afu;
 
+	ctxi->rht_perms = perms;
 	ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl;
 	ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid);
 	ctxi->lfd = adap_fd;
 	ctxi->pid = current->tgid; /* tgid = pid */
 	ctxi->ctx = ctx;
 	ctxi->file = file;
+	ctxi->initialized = true;
 	mutex_init(&ctxi->mutex);
 	INIT_LIST_HEAD(&ctxi->luns);
 	INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */
 
 	mutex_lock(&ctxi->mutex);
-out:
-	return ctxi;
-
-err:
-	kfree(ws);
-	kfree(lli);
-	kfree(ctxi);
-	ctxi = NULL;
-	goto out;
 }
 
 /**
@@ -1300,9 +1315,9 @@
 	u32 perms;
 	int ctxid = -1;
 	u64 rctxid = 0UL;
-	struct file *file;
+	struct file *file = NULL;
 
-	struct cxl_context *ctx;
+	struct cxl_context *ctx = NULL;
 
 	int fd = -1;
 
@@ -1356,7 +1371,7 @@
 	if (unlikely(!lun_access)) {
 		dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__);
 		rc = -ENOMEM;
-		goto err0;
+		goto err;
 	}
 
 	lun_access->lli = lli;
@@ -1371,53 +1386,56 @@
 		goto out_attach;
 	}
 
+	ctxi = create_context(cfg);
+	if (unlikely(!ctxi)) {
+		dev_err(dev, "%s: Failed to create context! (%d)\n",
+			__func__, ctxid);
+		goto err;
+	}
+
 	ctx = cxl_dev_context_init(cfg->dev);
-	if (unlikely(IS_ERR_OR_NULL(ctx))) {
+	if (IS_ERR_OR_NULL(ctx)) {
 		dev_err(dev, "%s: Could not initialize context %p\n",
 			__func__, ctx);
 		rc = -ENODEV;
-		goto err1;
+		goto err;
+	}
+
+	work = &ctxi->work;
+	work->num_interrupts = attach->num_interrupts;
+	work->flags = CXL_START_WORK_NUM_IRQS;
+
+	rc = cxl_start_work(ctx, work);
+	if (unlikely(rc)) {
+		dev_dbg(dev, "%s: Could not start context rc=%d\n",
+			__func__, rc);
+		goto err;
 	}
 
 	ctxid = cxl_process_element(ctx);
-	if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+	if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
 		dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
 		rc = -EPERM;
-		goto err2;
+		goto err;
 	}
 
 	file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd);
 	if (unlikely(fd < 0)) {
 		rc = -ENODEV;
 		dev_err(dev, "%s: Could not get file descriptor\n", __func__);
-		goto err2;
+		goto err;
 	}
 
 	/* Translate read/write O_* flags from fcntl.h to AFU permission bits */
 	perms = SISL_RHT_PERM(attach->hdr.flags + 1);
 
-	ctxi = create_context(cfg, ctx, ctxid, fd, file, perms);
-	if (unlikely(!ctxi)) {
-		dev_err(dev, "%s: Failed to create context! (%d)\n",
-			__func__, ctxid);
-		goto err3;
-	}
-
-	work = &ctxi->work;
-	work->num_interrupts = attach->num_interrupts;
-	work->flags = CXL_START_WORK_NUM_IRQS;
-
-	rc = cxl_start_work(ctx, work);
-	if (unlikely(rc)) {
-		dev_dbg(dev, "%s: Could not start context rc=%d\n",
-			__func__, rc);
-		goto err4;
-	}
+	/* Context mutex is locked upon return */
+	init_context(ctxi, cfg, ctx, ctxid, fd, file, perms);
 
 	rc = afu_attach(cfg, ctxi);
 	if (unlikely(rc)) {
 		dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc);
-		goto err5;
+		goto err;
 	}
 
 	/*
@@ -1453,13 +1471,14 @@
 		__func__, ctxid, fd, attach->block_size, rc, attach->last_lba);
 	return rc;
 
-err5:
-	cxl_stop_context(ctx);
-err4:
-	put_context(ctxi);
-	destroy_context(cfg, ctxi);
-	ctxi = NULL;
-err3:
+err:
+	/* Cleanup CXL context; okay to 'stop' even if it was not started */
+	if (!IS_ERR_OR_NULL(ctx)) {
+		cxl_stop_context(ctx);
+		cxl_release_context(ctx);
+		ctx = NULL;
+	}
+
 	/*
 	 * Here, we're overriding the fops with a dummy all-NULL fops because
 	 * fput() calls the release fop, which will cause us to mistakenly
@@ -1467,15 +1486,21 @@
 	 * to that routine (cxlflash_cxl_release) we should try to fix the
 	 * issue here.
 	 */
-	file->f_op = &null_fops;
-	fput(file);
-	put_unused_fd(fd);
-	fd = -1;
-err2:
-	cxl_release_context(ctx);
-err1:
+	if (fd > 0) {
+		file->f_op = &null_fops;
+		fput(file);
+		put_unused_fd(fd);
+		fd = -1;
+		file = NULL;
+	}
+
+	/* Cleanup our context; safe to call even with mutex locked */
+	if (ctxi) {
+		destroy_context(cfg, ctxi);
+		ctxi = NULL;
+	}
+
 	kfree(lun_access);
-err0:
 	scsi_device_put(sdev);
 	goto out;
 }
@@ -1500,31 +1525,31 @@
 	struct afu *afu = cfg->afu;
 
 	ctx = cxl_dev_context_init(cfg->dev);
-	if (unlikely(IS_ERR_OR_NULL(ctx))) {
+	if (IS_ERR_OR_NULL(ctx)) {
 		dev_err(dev, "%s: Could not initialize context %p\n",
 			__func__, ctx);
 		rc = -ENODEV;
 		goto out;
 	}
 
+	rc = cxl_start_work(ctx, &ctxi->work);
+	if (unlikely(rc)) {
+		dev_dbg(dev, "%s: Could not start context rc=%d\n",
+			__func__, rc);
+		goto err1;
+	}
+
 	ctxid = cxl_process_element(ctx);
-	if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+	if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
 		dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
 		rc = -EPERM;
-		goto err1;
+		goto err2;
 	}
 
 	file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd);
 	if (unlikely(fd < 0)) {
 		rc = -ENODEV;
 		dev_err(dev, "%s: Could not get file descriptor\n", __func__);
-		goto err1;
-	}
-
-	rc = cxl_start_work(ctx, &ctxi->work);
-	if (unlikely(rc)) {
-		dev_dbg(dev, "%s: Could not start context rc=%d\n",
-			__func__, rc);
 		goto err2;
 	}
 
@@ -1569,10 +1594,10 @@
 	return rc;
 
 err3:
-	cxl_stop_context(ctx);
-err2:
 	fput(file);
 	put_unused_fd(fd);
+err2:
+	cxl_stop_context(ctx);
 err1:
 	cxl_release_context(ctx);
 	goto out;
@@ -1590,6 +1615,13 @@
  * place at the same time and the failure was due to CXL services being
  * unable to keep up.
  *
+ * As this routine is called on ioctl context, it holds the ioctl r/w
+ * semaphore that is used to drain ioctls in recovery scenarios. The
+ * implementation to achieve the pacing described above (a local mutex)
+ * requires that the ioctl r/w semaphore be dropped and reacquired to
+ * avoid a 3-way deadlock when multiple process recoveries operate in
+ * parallel.
+ *
  * Because a user can detect an error condition before the kernel, it is
  * quite possible for this routine to act as the kernel's EEH detection
  * source (MMIO read of mbox_r). Because of this, there is a window of
@@ -1617,9 +1649,17 @@
 	int rc = 0;
 
 	atomic_inc(&cfg->recovery_threads);
+	up_read(&cfg->ioctl_rwsem);
 	rc = mutex_lock_interruptible(mutex);
+	down_read(&cfg->ioctl_rwsem);
 	if (rc)
 		goto out;
+	rc = check_state(cfg);
+	if (rc) {
+		dev_err(dev, "%s: Failed state! rc=%d\n", __func__, rc);
+		rc = -ENODEV;
+		goto out;
+	}
 
 	dev_dbg(dev, "%s: reason 0x%016llX rctxid=%016llX\n",
 		__func__, recover->reason, rctxid);
--- linux-4.4.0.orig/drivers/scsi/cxlflash/superpipe.h
+++ linux-4.4.0/drivers/scsi/cxlflash/superpipe.h
@@ -102,6 +102,7 @@
 	u64 ctxid;
 	int lfd;
 	pid_t pid;
+	bool initialized;
 	bool unavail;
 	bool err_recovery_active;
 	struct mutex mutex; /* Context protection */
--- linux-4.4.0.orig/drivers/scsi/cxlflash/vlun.c
+++ linux-4.4.0/drivers/scsi/cxlflash/vlun.c
@@ -1008,6 +1008,8 @@
 	virt->last_lba = last_lba;
 	virt->rsrc_handle = rsrc_handle;
 
+	if (lli->port_sel == BOTH_PORTS)
+		virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE;
 out:
 	if (likely(ctxi))
 		put_context(ctxi);
--- linux-4.4.0.orig/drivers/scsi/dc395x.c
+++ linux-4.4.0/drivers/scsi/dc395x.c
@@ -1972,6 +1972,11 @@
 			xferred -= psge->length;
 		} else {
 			/* Partial SG entry done */
+			pci_dma_sync_single_for_cpu(srb->dcb->
+					    acb->dev,
+					    srb->sg_bus_addr,
+					    SEGMENTX_LEN,
+					    PCI_DMA_TODEVICE);
 			psge->length -= xferred;
 			psge->address += xferred;
 			srb->sg_index = idx;
@@ -3450,14 +3455,12 @@
 		}
 	}
 
-	if (dir != PCI_DMA_NONE && scsi_sg_count(cmd))
-		pci_dma_sync_sg_for_cpu(acb->dev, scsi_sglist(cmd),
-					scsi_sg_count(cmd), dir);
-
 	ckc_only = 0;
 /* Check Error Conditions */
       ckc_e:
 
+	pci_unmap_srb(acb, srb);
+
 	if (cmd->cmnd[0] == INQUIRY) {
 		unsigned char *base = NULL;
 		struct ScsiInqData *ptr;
@@ -3511,7 +3514,6 @@
 			cmd, cmd->result);
 		srb_free_insert(acb, srb);
 	}
-	pci_unmap_srb(acb, srb);
 
 	cmd->scsi_done(cmd);
 	waiting_process_next(acb);
--- linux-4.4.0.orig/drivers/scsi/device_handler/Kconfig
+++ linux-4.4.0/drivers/scsi/device_handler/Kconfig
@@ -13,13 +13,13 @@
 
 config SCSI_DH_RDAC
 	tristate "LSI RDAC Device Handler"
-	depends on SCSI_DH
+	depends on SCSI_DH && SCSI
 	help
 	If you have a LSI RDAC select y. Otherwise, say N.
 
 config SCSI_DH_HP_SW
 	tristate "HP/COMPAQ MSA Device Handler"
-	depends on SCSI_DH
+	depends on SCSI_DH && SCSI
 	help
 	If you have a HP/COMPAQ MSA device that requires START_STOP to
 	be sent to start it and cannot upgrade the firmware then select y.
@@ -27,13 +27,13 @@
 
 config SCSI_DH_EMC
 	tristate "EMC CLARiiON Device Handler"
-	depends on SCSI_DH
+	depends on SCSI_DH && SCSI
 	help
 	If you have a EMC CLARiiON select y. Otherwise, say N.
 
 config SCSI_DH_ALUA
 	tristate "SPC-3 ALUA Device Handler"
-	depends on SCSI_DH
+	depends on SCSI_DH && SCSI
 	help
 	  SCSI Device handler for generic SPC-3 Asymmetric Logical Unit
 	  Access (ALUA).
--- linux-4.4.0.orig/drivers/scsi/device_handler/scsi_dh_alua.c
+++ linux-4.4.0/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -22,7 +22,9 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <asm/unaligned.h>
 #include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_dh.h>
 
@@ -54,27 +56,60 @@
 #define TPGS_MODE_IMPLICIT		0x1
 #define TPGS_MODE_EXPLICIT		0x2
 
-#define ALUA_INQUIRY_SIZE		36
+#define ALUA_RTPG_SIZE			128
 #define ALUA_FAILOVER_TIMEOUT		60
 #define ALUA_FAILOVER_RETRIES		5
+#define ALUA_RTPG_DELAY_MSECS		5
 
-/* flags passed from user level */
-#define ALUA_OPTIMIZE_STPG		1
+/* device handler flags */
+#define ALUA_OPTIMIZE_STPG		0x01
+#define ALUA_RTPG_EXT_HDR_UNSUPP	0x02
+#define ALUA_SYNC_STPG			0x04
+/* State machine flags */
+#define ALUA_PG_RUN_RTPG		0x10
+#define ALUA_PG_RUN_STPG		0x20
+#define ALUA_PG_RUNNING			0x40
 
-struct alua_dh_data {
+static uint optimize_stpg;
+module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
+
+static LIST_HEAD(port_group_list);
+static DEFINE_SPINLOCK(port_group_lock);
+static struct workqueue_struct *kaluad_wq;
+static struct workqueue_struct *kaluad_sync_wq;
+
+struct alua_port_group {
+	struct kref		kref;
+	struct rcu_head		rcu;
+	struct list_head	node;
+	unsigned char		device_id_str[256];
+	int			device_id_len;
 	int			group_id;
-	int			rel_port;
 	int			tpgs;
 	int			state;
 	int			pref;
 	unsigned		flags; /* used for optimizing STPG */
-	unsigned char		inq[ALUA_INQUIRY_SIZE];
-	unsigned char		*buff;
-	int			bufflen;
 	unsigned char		transition_tmo;
-	unsigned char		sense[SCSI_SENSE_BUFFERSIZE];
-	int			senselen;
+	unsigned long		expiry;
+	unsigned long		interval;
+	struct delayed_work	rtpg_work;
+	spinlock_t		lock;
+	struct list_head	rtpg_list;
+	struct scsi_device	*rtpg_sdev;
+};
+
+struct alua_dh_data {
+	struct alua_port_group	*pg;
+	int			group_id;
+	spinlock_t		pg_lock;
 	struct scsi_device	*sdev;
+	int			init_error;
+	struct mutex		init_mutex;
+};
+
+struct alua_queue_data {
+	struct list_head	entry;
 	activate_complete	callback_fn;
 	void			*callback_data;
 };
@@ -82,231 +117,162 @@
 #define ALUA_POLICY_SWITCH_CURRENT	0
 #define ALUA_POLICY_SWITCH_ALL		1
 
-static char print_alua_state(int);
-static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
+static void alua_rtpg_work(struct work_struct *work);
+static void alua_rtpg_queue(struct alua_port_group *pg,
+			    struct scsi_device *sdev,
+			    struct alua_queue_data *qdata, bool force);
+static void alua_check(struct scsi_device *sdev, bool force);
 
-static int realloc_buffer(struct alua_dh_data *h, unsigned len)
+static void release_port_group(struct kref *kref)
 {
-	if (h->buff && h->buff != h->inq)
-		kfree(h->buff);
+	struct alua_port_group *pg;
 
-	h->buff = kmalloc(len, GFP_NOIO);
-	if (!h->buff) {
-		h->buff = h->inq;
-		h->bufflen = ALUA_INQUIRY_SIZE;
-		return 1;
-	}
-	h->bufflen = len;
-	return 0;
-}
-
-static struct request *get_alua_req(struct scsi_device *sdev,
-				    void *buffer, unsigned buflen, int rw)
-{
-	struct request *rq;
-	struct request_queue *q = sdev->request_queue;
-
-	rq = blk_get_request(q, rw, GFP_NOIO);
-
-	if (IS_ERR(rq)) {
-		sdev_printk(KERN_INFO, sdev,
-			    "%s: blk_get_request failed\n", __func__);
-		return NULL;
-	}
-	blk_rq_set_block_pc(rq);
-
-	if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
-		blk_put_request(rq);
-		sdev_printk(KERN_INFO, sdev,
-			    "%s: blk_rq_map_kern failed\n", __func__);
-		return NULL;
-	}
-
-	rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
-			 REQ_FAILFAST_DRIVER;
-	rq->retries = ALUA_FAILOVER_RETRIES;
-	rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ;
-
-	return rq;
+	pg = container_of(kref, struct alua_port_group, kref);
+	if (pg->rtpg_sdev)
+		flush_delayed_work(&pg->rtpg_work);
+	spin_lock(&port_group_lock);
+	list_del(&pg->node);
+	spin_unlock(&port_group_lock);
+	kfree_rcu(pg, rcu);
 }
 
 /*
- * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
+ * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
  * @sdev: sdev the command should be sent to
  */
-static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+		       int bufflen, struct scsi_sense_hdr *sshdr, int flags)
 {
-	struct request *rq;
-	int err = SCSI_DH_RES_TEMP_UNAVAIL;
-
-	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
-	if (!rq)
-		goto done;
+	u8 cdb[COMMAND_SIZE(MAINTENANCE_IN)];
+	int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+		REQ_FAILFAST_DRIVER;
 
 	/* Prepare the command. */
-	rq->cmd[0] = INQUIRY;
-	rq->cmd[1] = 1;
-	rq->cmd[2] = 0x83;
-	rq->cmd[4] = h->bufflen;
-	rq->cmd_len = COMMAND_SIZE(INQUIRY);
-
-	rq->sense = h->sense;
-	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-	rq->sense_len = h->senselen = 0;
+	memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_IN));
+	cdb[0] = MAINTENANCE_IN;
+	if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
+		cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
+	else
+		cdb[1] = MI_REPORT_TARGET_PGS;
+	put_unaligned_be32(bufflen, &cdb[6]);
 
-	err = blk_execute_rq(rq->q, NULL, rq, 1);
-	if (err == -EIO) {
-		sdev_printk(KERN_INFO, sdev,
-			    "%s: evpd inquiry failed with %x\n",
-			    ALUA_DH_NAME, rq->errors);
-		h->senselen = rq->sense_len;
-		err = SCSI_DH_IO;
-	}
-	blk_put_request(rq);
-done:
-	return err;
+	return scsi_execute_req_flags(sdev, cdb, DMA_FROM_DEVICE,
+				      buff, bufflen, sshdr,
+				      ALUA_FAILOVER_TIMEOUT * HZ,
+				      ALUA_FAILOVER_RETRIES, NULL, req_flags);
 }
 
 /*
- * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
- * @sdev: sdev the command should be sent to
+ * submit_stpg - Issue a SET TARGET PORT GROUP command
+ *
+ * Currently we're only setting the current target port group state
+ * to 'active/optimized' and let the array firmware figure out
+ * the states of the remaining groups.
  */
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
-			    bool rtpg_ext_hdr_req)
+static int submit_stpg(struct scsi_device *sdev, int group_id,
+		       struct scsi_sense_hdr *sshdr)
 {
-	struct request *rq;
-	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+	u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)];
+	unsigned char stpg_data[8];
+	int stpg_len = 8;
+	int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+		REQ_FAILFAST_DRIVER;
 
-	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
-	if (!rq)
-		goto done;
+	/* Prepare the data buffer */
+	memset(stpg_data, 0, stpg_len);
+	stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+	put_unaligned_be16(group_id, &stpg_data[6]);
 
 	/* Prepare the command. */
-	rq->cmd[0] = MAINTENANCE_IN;
-	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;
-	rq->cmd[9] = h->bufflen & 0xff;
-	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
-
-	rq->sense = h->sense;
-	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-	rq->sense_len = h->senselen = 0;
-
-	err = blk_execute_rq(rq->q, NULL, rq, 1);
-	if (err == -EIO) {
-		sdev_printk(KERN_INFO, sdev,
-			    "%s: rtpg failed with %x\n",
-			    ALUA_DH_NAME, rq->errors);
-		h->senselen = rq->sense_len;
-		err = SCSI_DH_IO;
-	}
-	blk_put_request(rq);
-done:
-	return err;
+	memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_OUT));
+	cdb[0] = MAINTENANCE_OUT;
+	cdb[1] = MO_SET_TARGET_PGS;
+	put_unaligned_be32(stpg_len, &cdb[6]);
+
+	return scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE,
+				      stpg_data, stpg_len,
+				      sshdr, ALUA_FAILOVER_TIMEOUT * HZ,
+				      ALUA_FAILOVER_RETRIES, NULL, req_flags);
 }
 
-/*
- * alua_stpg - Evaluate SET TARGET GROUP STATES
- * @sdev: the device to be evaluated
- * @state: the new target group state
- *
- * Send a SET TARGET GROUP STATES command to the device.
- * We only have to test here if we should resubmit the command;
- * any other error is assumed as a failure.
- */
-static void stpg_endio(struct request *req, int error)
+struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size,
+					 int group_id)
 {
-	struct alua_dh_data *h = req->end_io_data;
-	struct scsi_sense_hdr sense_hdr;
-	unsigned err = SCSI_DH_OK;
+	struct alua_port_group *pg;
 
-	if (host_byte(req->errors) != DID_OK ||
-	    msg_byte(req->errors) != COMMAND_COMPLETE) {
-		err = SCSI_DH_IO;
-		goto done;
-	}
+	if (!id_str || !id_size || !strlen(id_str))
+		return NULL;
 
-	if (req->sense_len > 0) {
-		err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
-					   &sense_hdr);
-		if (!err) {
-			err = SCSI_DH_IO;
-			goto done;
-		}
-		err = alua_check_sense(h->sdev, &sense_hdr);
-		if (err == ADD_TO_MLQUEUE) {
-			err = SCSI_DH_RETRY;
-			goto done;
-		}
-		sdev_printk(KERN_INFO, h->sdev,
-			    "%s: stpg sense code: %02x/%02x/%02x\n",
-			    ALUA_DH_NAME, sense_hdr.sense_key,
-			    sense_hdr.asc, sense_hdr.ascq);
-		err = SCSI_DH_IO;
-	} else if (error)
-		err = SCSI_DH_IO;
-
-	if (err == SCSI_DH_OK) {
-		h->state = TPGS_STATE_OPTIMIZED;
-		sdev_printk(KERN_INFO, h->sdev,
-			    "%s: port group %02x switched to state %c\n",
-			    ALUA_DH_NAME, h->group_id,
-			    print_alua_state(h->state));
-	}
-done:
-	req->end_io_data = NULL;
-	__blk_put_request(req->q, req);
-	if (h->callback_fn) {
-		h->callback_fn(h->callback_data, err);
-		h->callback_fn = h->callback_data = NULL;
+	list_for_each_entry(pg, &port_group_list, node) {
+		if (pg->group_id != group_id)
+			continue;
+		if (!pg->device_id_len || pg->device_id_len != id_size)
+			continue;
+		if (strncmp(pg->device_id_str, id_str, id_size))
+			continue;
+		if (!kref_get_unless_zero(&pg->kref))
+			continue;
+		return pg;
 	}
-	return;
+
+	return NULL;
 }
 
 /*
- * submit_stpg - Issue a SET TARGET GROUP STATES command
+ * alua_alloc_pg - Allocate a new port_group structure
+ * @sdev: scsi device
+ * @h: alua device_handler data
+ * @group_id: port group id
  *
- * Currently we're only setting the current target port group state
- * to 'active/optimized' and let the array firmware figure out
- * the states of the remaining groups.
+ * Allocate a new port_group structure for a given
+ * device.
  */
-static unsigned submit_stpg(struct alua_dh_data *h)
+struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
+				      int group_id, int tpgs)
 {
-	struct request *rq;
-	int stpg_len = 8;
-	struct scsi_device *sdev = h->sdev;
+	struct alua_port_group *pg, *tmp_pg;
 
-	/* Prepare the data buffer */
-	memset(h->buff, 0, stpg_len);
-	h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
-	h->buff[6] = (h->group_id >> 8) & 0xff;
-	h->buff[7] = h->group_id & 0xff;
-
-	rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
-	if (!rq)
-		return SCSI_DH_RES_TEMP_UNAVAIL;
+	pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
+	if (!pg)
+		return ERR_PTR(-ENOMEM);
+
+	pg->device_id_len = scsi_vpd_lun_id(sdev, pg->device_id_str,
+					    sizeof(pg->device_id_str));
+	if (pg->device_id_len <= 0) {
+		/*
+		 * TPGS supported but no device identification found.
+		 * Generate private device identification.
+		 */
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: No device descriptors found\n",
+			    ALUA_DH_NAME);
+		pg->device_id_str[0] = '\0';
+		pg->device_id_len = 0;
+	}
+	pg->group_id = group_id;
+	pg->tpgs = tpgs;
+	pg->state = TPGS_STATE_OPTIMIZED;
+	if (optimize_stpg)
+		pg->flags |= ALUA_OPTIMIZE_STPG;
+	kref_init(&pg->kref);
+	INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work);
+	INIT_LIST_HEAD(&pg->rtpg_list);
+	INIT_LIST_HEAD(&pg->node);
+	spin_lock_init(&pg->lock);
+
+	spin_lock(&port_group_lock);
+	tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
+				  group_id);
+	if (tmp_pg) {
+		spin_unlock(&port_group_lock);
+		kfree(pg);
+		return tmp_pg;
+	}
 
-	/* Prepare the command. */
-	rq->cmd[0] = MAINTENANCE_OUT;
-	rq->cmd[1] = MO_SET_TARGET_PGS;
-	rq->cmd[6] = (stpg_len >> 24) & 0xff;
-	rq->cmd[7] = (stpg_len >> 16) & 0xff;
-	rq->cmd[8] = (stpg_len >>  8) & 0xff;
-	rq->cmd[9] = stpg_len & 0xff;
-	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
-
-	rq->sense = h->sense;
-	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-	rq->sense_len = h->senselen = 0;
-	rq->end_io_data = h;
+	list_add(&pg->node, &port_group_list);
+	spin_unlock(&port_group_lock);
 
-	blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
-	return SCSI_DH_OK;
+	return pg;
 }
 
 /*
@@ -316,12 +282,23 @@
  * Examine the TPGS setting of the sdev to find out if ALUA
  * is supported.
  */
-static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_tpgs(struct scsi_device *sdev)
 {
-	int err = SCSI_DH_OK;
+	int tpgs = TPGS_MODE_NONE;
 
-	h->tpgs = scsi_device_tpgs(sdev);
-	switch (h->tpgs) {
+	/*
+	 * ALUA support for non-disk devices is fraught with
+	 * difficulties, so disable it for now.
+	 */
+	if (sdev->type != TYPE_DISK) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: disable for non-disk devices\n",
+			    ALUA_DH_NAME);
+		return tpgs;
+	}
+
+	tpgs = scsi_device_tpgs(sdev);
+	switch (tpgs) {
 	case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
 		sdev_printk(KERN_INFO, sdev,
 			    "%s: supports implicit and explicit TPGS\n",
@@ -335,71 +312,36 @@
 		sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
 			    ALUA_DH_NAME);
 		break;
-	default:
-		h->tpgs = TPGS_MODE_NONE;
+	case TPGS_MODE_NONE:
 		sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
 			    ALUA_DH_NAME);
-		err = SCSI_DH_DEV_UNSUPP;
+		break;
+	default:
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: unsupported TPGS setting %d\n",
+			    ALUA_DH_NAME, tpgs);
+		tpgs = TPGS_MODE_NONE;
 		break;
 	}
 
-	return err;
+	return tpgs;
 }
 
 /*
- * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
+ * alua_check_vpd - Evaluate INQUIRY vpd page 0x83
  * @sdev: device to be checked
  *
  * Extract the relative target port and the target port group
  * descriptor from the list of identificators.
  */
-static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
+			  int tpgs)
 {
-	int len;
-	unsigned err;
-	unsigned char *d;
-
- retry:
-	err = submit_vpd_inquiry(sdev, h);
-
-	if (err != SCSI_DH_OK)
-		return err;
+	int rel_port = -1, group_id;
+	struct alua_port_group *pg, *old_pg = NULL;
 
-	/* Check if vpd page exceeds initial buffer */
-	len = (h->buff[2] << 8) + h->buff[3] + 4;
-	if (len > h->bufflen) {
-		/* Resubmit with the correct length */
-		if (realloc_buffer(h, len)) {
-			sdev_printk(KERN_WARNING, sdev,
-				    "%s: kmalloc buffer failed\n",
-				    ALUA_DH_NAME);
-			/* Temporary failure, bypass */
-			return SCSI_DH_DEV_TEMP_BUSY;
-		}
-		goto retry;
-	}
-
-	/*
-	 * Now look for the correct descriptor.
-	 */
-	d = h->buff + 4;
-	while (d < h->buff + len) {
-		switch (d[1] & 0xf) {
-		case 0x4:
-			/* Relative target port */
-			h->rel_port = (d[6] << 8) + d[7];
-			break;
-		case 0x5:
-			/* Target port group */
-			h->group_id = (d[6] << 8) + d[7];
-			break;
-		default:
-			break;
-		}
-		d += d[3] + 4;
-	}
-
-	if (h->group_id == -1) {
+	group_id = scsi_vpd_tpg_id(sdev, &rel_port);
+	if (group_id < 0) {
 		/*
 		 * Internal error; TPGS supported but required
 		 * VPD identification descriptors not present.
@@ -408,16 +350,41 @@
 		sdev_printk(KERN_INFO, sdev,
 			    "%s: No target port descriptors found\n",
 			    ALUA_DH_NAME);
-		h->state = TPGS_STATE_OPTIMIZED;
-		h->tpgs = TPGS_MODE_NONE;
-		err = SCSI_DH_DEV_UNSUPP;
-	} else {
-		sdev_printk(KERN_INFO, sdev,
-			    "%s: port group %02x rel port %02x\n",
-			    ALUA_DH_NAME, h->group_id, h->rel_port);
+		return SCSI_DH_DEV_UNSUPP;
 	}
 
-	return err;
+	pg = alua_alloc_pg(sdev, group_id, tpgs);
+	if (IS_ERR(pg)) {
+		if (PTR_ERR(pg) == -ENOMEM)
+			return SCSI_DH_NOMEM;
+		return SCSI_DH_DEV_UNSUPP;
+	}
+	if (pg->device_id_len)
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: device %s port group %x rel port %x\n",
+			    ALUA_DH_NAME, pg->device_id_str,
+			    group_id, rel_port);
+	else
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: port group %x rel port %x\n",
+			    ALUA_DH_NAME, group_id, rel_port);
+
+	/* Check for existing port group references */
+	spin_lock(&h->pg_lock);
+	old_pg = h->pg;
+	if (old_pg != pg) {
+		/* port group has changed. Update to new port group */
+		rcu_assign_pointer(h->pg, pg);
+	}
+	if (sdev->synchronous_alua)
+		pg->flags |= ALUA_SYNC_STPG;
+	alua_rtpg_queue(h->pg, sdev, NULL, true);
+	spin_unlock(&h->pg_lock);
+
+	if (old_pg)
+		kref_put(&old_pg->kref, release_port_group);
+
+	return SCSI_DH_OK;
 }
 
 static char print_alua_state(int state)
@@ -447,40 +414,24 @@
 {
 	switch (sense_hdr->sense_key) {
 	case NOT_READY:
-		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
 			/*
 			 * LUN Not Accessible - ALUA state transition
 			 */
-			return ADD_TO_MLQUEUE;
-		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
-			/*
-			 * LUN Not Accessible -- Target port in standby state
-			 */
-			return SUCCESS;
-		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
-			/*
-			 * LUN Not Accessible -- Target port in unavailable state
-			 */
-			return SUCCESS;
-		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
-			/*
-			 * LUN Not Ready -- Offline
-			 */
-			return SUCCESS;
-		if (sdev->allow_restart &&
-		    sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x02)
-			/*
-			 * if the device is not started, we need to wake
-			 * the error handler to start the motor
-			 */
-			return FAILED;
+			alua_check(sdev, false);
+			return NEEDS_RETRY;
+		}
 		break;
 	case UNIT_ATTENTION:
-		if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
+		if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
 			/*
-			 * Power On, Reset, or Bus Device Reset, just retry.
+			 * Power On, Reset, or Bus Device Reset.
+			 * Might have obscured a state transition,
+			 * so schedule a recheck.
 			 */
+			alua_check(sdev, true);
 			return ADD_TO_MLQUEUE;
+		}
 		if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
 			/*
 			 * Device internal reset
@@ -491,16 +442,20 @@
 			 * Mode Parameters Changed
 			 */
 			return ADD_TO_MLQUEUE;
-		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06)
+		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
 			/*
 			 * ALUA state changed
 			 */
+			alua_check(sdev, true);
 			return ADD_TO_MLQUEUE;
-		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07)
+		}
+		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
 			/*
 			 * Implicit ALUA state transition failed
 			 */
+			alua_check(sdev, true);
 			return ADD_TO_MLQUEUE;
+		}
 		if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
 			/*
 			 * Inquiry data has changed
@@ -520,38 +475,75 @@
 }
 
 /*
+ * alua_tur - Send a TEST UNIT READY
+ * @sdev: device to which the TEST UNIT READY command should be send
+ *
+ * Send a TEST UNIT READY to @sdev to figure out the device state
+ * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING,
+ * SCSI_DH_OK if no error occurred, and SCSI_DH_IO otherwise.
+ */
+static int alua_tur(struct scsi_device *sdev)
+{
+	struct scsi_sense_hdr sense_hdr;
+	int retval;
+
+	retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
+				      ALUA_FAILOVER_RETRIES, &sense_hdr);
+	if (sense_hdr.sense_key == NOT_READY &&
+	    sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+		return SCSI_DH_RETRY;
+	else if (retval)
+		return SCSI_DH_IO;
+	else
+		return SCSI_DH_OK;
+}
+
+/*
  * alua_rtpg - Evaluate REPORT TARGET GROUP STATES
  * @sdev: the device to be evaluated.
- * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state
  *
  * Evaluate the Target Port Group State.
  * Returns SCSI_DH_DEV_OFFLINED if the path is
  * found to be unusable.
  */
-static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
 {
 	struct scsi_sense_hdr sense_hdr;
-	int len, k, off, valid_states = 0;
-	unsigned char *ucp;
-	unsigned err;
-	bool rtpg_ext_hdr_req = 1;
-	unsigned long expiry, interval = 0;
+	struct alua_port_group *tmp_pg;
+	int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
+	unsigned char *desc, *buff;
+	unsigned err, retval;
 	unsigned int tpg_desc_tbl_off;
 	unsigned char orig_transition_tmo;
+	unsigned long flags;
 
-	if (!h->transition_tmo)
-		expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
-	else
-		expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
+	if (!pg->expiry) {
+		unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ;
+
+		if (pg->transition_tmo)
+			transition_tmo = pg->transition_tmo * HZ;
+
+		pg->expiry = round_jiffies_up(jiffies + transition_tmo);
+	}
+
+	buff = kzalloc(bufflen, GFP_KERNEL);
+	if (!buff)
+		return SCSI_DH_DEV_TEMP_BUSY;
 
  retry:
-	err = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
+	err = 0;
+	retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, pg->flags);
 
-	if (err == SCSI_DH_IO && h->senselen > 0) {
-		err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
-					   &sense_hdr);
-		if (!err)
+	if (retval) {
+		if (!scsi_sense_valid(&sense_hdr)) {
+			sdev_printk(KERN_INFO, sdev,
+				    "%s: rtpg failed, result %d\n",
+				    ALUA_DH_NAME, retval);
+			kfree(buff);
+			if (driver_byte(retval) == DRIVER_ERROR)
+				return SCSI_DH_DEV_TEMP_BUSY;
 			return SCSI_DH_IO;
+		}
 
 		/*
 		 * submit_rtpg() has failed on existing arrays
@@ -561,73 +553,101 @@
 		 * The retry without rtpg_ext_hdr_req set
 		 * handles this.
 		 */
-		if (rtpg_ext_hdr_req == 1 &&
+		if (!(pg->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
 		    sense_hdr.sense_key == ILLEGAL_REQUEST &&
 		    sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
-			rtpg_ext_hdr_req = 0;
+			pg->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
 			goto retry;
 		}
-
-		err = alua_check_sense(sdev, &sense_hdr);
-		if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry))
-			goto retry;
-		sdev_printk(KERN_INFO, sdev,
-			    "%s: rtpg sense code %02x/%02x/%02x\n",
-			    ALUA_DH_NAME, sense_hdr.sense_key,
-			    sense_hdr.asc, sense_hdr.ascq);
-		err = SCSI_DH_IO;
+		/*
+		 * Retry on ALUA state transition or if any
+		 * UNIT ATTENTION occurred.
+		 */
+		if (sense_hdr.sense_key == NOT_READY &&
+		    sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+			err = SCSI_DH_RETRY;
+		else if (sense_hdr.sense_key == UNIT_ATTENTION)
+			err = SCSI_DH_RETRY;
+		if (err == SCSI_DH_RETRY &&
+		    pg->expiry != 0 && time_before(jiffies, pg->expiry)) {
+			sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
+				    ALUA_DH_NAME);
+			scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+			return err;
+		}
+		sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
+			    ALUA_DH_NAME);
+		scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+		kfree(buff);
+		pg->expiry = 0;
+		return SCSI_DH_IO;
 	}
-	if (err != SCSI_DH_OK)
-		return err;
 
-	len = (h->buff[0] << 24) + (h->buff[1] << 16) +
-		(h->buff[2] << 8) + h->buff[3] + 4;
+	len = get_unaligned_be32(&buff[0]) + 4;
 
-	if (len > h->bufflen) {
+	if (len > bufflen) {
 		/* Resubmit with the correct length */
-		if (realloc_buffer(h, len)) {
+		kfree(buff);
+		bufflen = len;
+		buff = kmalloc(bufflen, GFP_KERNEL);
+		if (!buff) {
 			sdev_printk(KERN_WARNING, sdev,
 				    "%s: kmalloc buffer failed\n",__func__);
 			/* Temporary failure, bypass */
+			pg->expiry = 0;
 			return SCSI_DH_DEV_TEMP_BUSY;
 		}
 		goto retry;
 	}
 
-	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];
+	orig_transition_tmo = pg->transition_tmo;
+	if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && buff[5] != 0)
+		pg->transition_tmo = buff[5];
 	else
-		h->transition_tmo = ALUA_FAILOVER_TIMEOUT;
+		pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
 
-	if (wait_for_transition && (orig_transition_tmo != h->transition_tmo)) {
+	if (orig_transition_tmo != pg->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;
+			    ALUA_DH_NAME, pg->transition_tmo);
+		pg->expiry = jiffies + pg->transition_tmo * HZ;
 	}
 
-	if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
+	if ((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;
+	for (k = tpg_desc_tbl_off, desc = buff + tpg_desc_tbl_off;
 	     k < len;
-	     k += off, ucp += off) {
+	     k += off, desc += off) {
+		u16 group_id = get_unaligned_be16(&desc[2]);
 
-		if (h->group_id == (ucp[2] << 8) + ucp[3]) {
-			h->state = ucp[0] & 0x0f;
-			h->pref = ucp[0] >> 7;
-			valid_states = ucp[1];
+		spin_lock_irqsave(&port_group_lock, flags);
+		tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
+					  group_id);
+		spin_unlock_irqrestore(&port_group_lock, flags);
+		if (tmp_pg) {
+			if (spin_trylock_irqsave(&tmp_pg->lock, flags)) {
+				if ((tmp_pg == pg) ||
+				    !(tmp_pg->flags & ALUA_PG_RUNNING)) {
+					tmp_pg->state = desc[0] & 0x0f;
+					tmp_pg->pref = desc[0] >> 7;
+				}
+				if (tmp_pg == pg)
+					valid_states = desc[1];
+				spin_unlock_irqrestore(&tmp_pg->lock, flags);
+			}
+			kref_put(&tmp_pg->kref, release_port_group);
 		}
-		off = 8 + (ucp[7] * 4);
+		off = 8 + (desc[7] * 4);
 	}
 
+	spin_lock_irqsave(&pg->lock, flags);
 	sdev_printk(KERN_INFO, sdev,
 		    "%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
-		    ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
-		    h->pref ? "preferred" : "non-preferred",
+		    ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state),
+		    pg->pref ? "preferred" : "non-preferred",
 		    valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
 		    valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
 		    valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
@@ -636,36 +656,224 @@
 		    valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
 		    valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
 
-	switch (h->state) {
+	switch (pg->state) {
 	case TPGS_STATE_TRANSITIONING:
-		if (wait_for_transition) {
-			if (time_before(jiffies, expiry)) {
-				/* State transition, retry */
-				interval += 2000;
-				msleep(interval);
-				goto retry;
-			}
+		if (time_before(jiffies, pg->expiry)) {
+			/* State transition, retry */
+			pg->interval = 2;
 			err = SCSI_DH_RETRY;
 		} else {
-			err = SCSI_DH_OK;
+			/* Transitioning time exceeded, set port to standby */
+			err = SCSI_DH_IO;
+			pg->state = TPGS_STATE_STANDBY;
+			pg->expiry = 0;
 		}
-
-		/* Transitioning time exceeded, set port to standby */
-		h->state = TPGS_STATE_STANDBY;
 		break;
 	case TPGS_STATE_OFFLINE:
 		/* Path unusable */
 		err = SCSI_DH_DEV_OFFLINED;
+		pg->expiry = 0;
 		break;
 	default:
 		/* Useable path if active */
 		err = SCSI_DH_OK;
+		pg->expiry = 0;
 		break;
 	}
+	spin_unlock_irqrestore(&pg->lock, flags);
+	kfree(buff);
 	return err;
 }
 
 /*
+ * alua_stpg - Issue a SET TARGET PORT GROUP command
+ *
+ * Issue a SET TARGET PORT GROUP command and evaluate the
+ * response. Returns SCSI_DH_RETRY per default to trigger
+ * a re-evaluation of the target group state or SCSI_DH_OK
+ * if no further action needs to be taken.
+ */
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
+{
+	int retval;
+	struct scsi_sense_hdr sense_hdr;
+
+	if (!(pg->tpgs & TPGS_MODE_EXPLICIT)) {
+		/* Only implicit ALUA supported, retry */
+		return SCSI_DH_RETRY;
+	}
+	switch (pg->state) {
+	case TPGS_STATE_OPTIMIZED:
+		return SCSI_DH_OK;
+	case TPGS_STATE_NONOPTIMIZED:
+		if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
+		    !pg->pref &&
+		    (pg->tpgs & TPGS_MODE_IMPLICIT))
+			return SCSI_DH_OK;
+		break;
+	case TPGS_STATE_STANDBY:
+	case TPGS_STATE_UNAVAILABLE:
+		break;
+	case TPGS_STATE_OFFLINE:
+		return SCSI_DH_IO;
+	case TPGS_STATE_TRANSITIONING:
+		break;
+	default:
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: stpg failed, unhandled TPGS state %d",
+			    ALUA_DH_NAME, pg->state);
+		return SCSI_DH_NOSYS;
+	}
+	retval = submit_stpg(sdev, pg->group_id, &sense_hdr);
+
+	if (retval) {
+		if (!scsi_sense_valid(&sense_hdr)) {
+			sdev_printk(KERN_INFO, sdev,
+				    "%s: stpg failed, result %d",
+				    ALUA_DH_NAME, retval);
+			if (driver_byte(retval) == DRIVER_ERROR)
+				return SCSI_DH_DEV_TEMP_BUSY;
+		} else {
+			sdev_printk(KERN_INFO, sdev, "%s: stpg failed\n",
+				    ALUA_DH_NAME);
+			scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+		}
+	}
+	/* Retry RTPG */
+	return SCSI_DH_RETRY;
+}
+
+static void alua_rtpg_work(struct work_struct *work)
+{
+	struct alua_port_group *pg =
+		container_of(work, struct alua_port_group, rtpg_work.work);
+	struct scsi_device *sdev;
+	LIST_HEAD(qdata_list);
+	int err = SCSI_DH_OK;
+	struct alua_queue_data *qdata, *tmp;
+	unsigned long flags;
+	struct workqueue_struct *alua_wq = kaluad_wq;
+
+	spin_lock_irqsave(&pg->lock, flags);
+	sdev = pg->rtpg_sdev;
+	if (!sdev) {
+		WARN_ON(pg->flags & ALUA_PG_RUN_RTPG);
+		WARN_ON(pg->flags & ALUA_PG_RUN_STPG);
+		spin_unlock_irqrestore(&pg->lock, flags);
+		return;
+	}
+	if (pg->flags & ALUA_SYNC_STPG)
+		alua_wq = kaluad_sync_wq;
+	pg->flags |= ALUA_PG_RUNNING;
+	if (pg->flags & ALUA_PG_RUN_RTPG) {
+		int state = pg->state;
+
+		pg->flags &= ~ALUA_PG_RUN_RTPG;
+		spin_unlock_irqrestore(&pg->lock, flags);
+		if (state == TPGS_STATE_TRANSITIONING) {
+			if (alua_tur(sdev) == SCSI_DH_RETRY) {
+				spin_lock_irqsave(&pg->lock, flags);
+				pg->flags &= ~ALUA_PG_RUNNING;
+				pg->flags |= ALUA_PG_RUN_RTPG;
+				spin_unlock_irqrestore(&pg->lock, flags);
+				queue_delayed_work(alua_wq, &pg->rtpg_work,
+						   pg->interval * HZ);
+				return;
+			}
+			/* Send RTPG on failure or if TUR indicates SUCCESS */
+		}
+		err = alua_rtpg(sdev, pg);
+		spin_lock_irqsave(&pg->lock, flags);
+		if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
+			pg->flags &= ~ALUA_PG_RUNNING;
+			pg->flags |= ALUA_PG_RUN_RTPG;
+			spin_unlock_irqrestore(&pg->lock, flags);
+			queue_delayed_work(alua_wq, &pg->rtpg_work,
+					   pg->interval * HZ);
+			return;
+		}
+		if (err != SCSI_DH_OK)
+			pg->flags &= ~ALUA_PG_RUN_STPG;
+	}
+	if (pg->flags & ALUA_PG_RUN_STPG) {
+		pg->flags &= ~ALUA_PG_RUN_STPG;
+		spin_unlock_irqrestore(&pg->lock, flags);
+		err = alua_stpg(sdev, pg);
+		spin_lock_irqsave(&pg->lock, flags);
+		if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
+			pg->flags |= ALUA_PG_RUN_RTPG;
+			pg->interval = 0;
+			pg->flags &= ~ALUA_PG_RUNNING;
+			spin_unlock_irqrestore(&pg->lock, flags);
+			queue_delayed_work(alua_wq, &pg->rtpg_work,
+					   pg->interval * HZ);
+			return;
+		}
+	}
+
+	list_splice_init(&pg->rtpg_list, &qdata_list);
+	pg->rtpg_sdev = NULL;
+	spin_unlock_irqrestore(&pg->lock, flags);
+
+	list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) {
+		list_del(&qdata->entry);
+		if (qdata->callback_fn)
+			qdata->callback_fn(qdata->callback_data, err);
+		kfree(qdata);
+	}
+	spin_lock_irqsave(&pg->lock, flags);
+	pg->flags &= ~ALUA_PG_RUNNING;
+	spin_unlock_irqrestore(&pg->lock, flags);
+	scsi_device_put(sdev);
+	kref_put(&pg->kref, release_port_group);
+}
+
+static void alua_rtpg_queue(struct alua_port_group *pg,
+			    struct scsi_device *sdev,
+			    struct alua_queue_data *qdata, bool force)
+{
+	int start_queue = 0;
+	unsigned long flags;
+	struct workqueue_struct *alua_wq = kaluad_wq;
+
+	if (!pg)
+		return;
+
+	spin_lock_irqsave(&pg->lock, flags);
+	if (qdata) {
+		list_add_tail(&qdata->entry, &pg->rtpg_list);
+		pg->flags |= ALUA_PG_RUN_STPG;
+		force = true;
+	}
+	if (pg->rtpg_sdev == NULL) {
+		pg->interval = 0;
+		pg->flags |= ALUA_PG_RUN_RTPG;
+		kref_get(&pg->kref);
+		pg->rtpg_sdev = sdev;
+		scsi_device_get(sdev);
+		start_queue = 1;
+	} else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) {
+		pg->flags |= ALUA_PG_RUN_RTPG;
+		/* Do not queue if the worker is already running */
+		if (!(pg->flags & ALUA_PG_RUNNING)) {
+			kref_get(&pg->kref);
+			start_queue = 1;
+		}
+	}
+
+	if (pg->flags & ALUA_SYNC_STPG)
+		alua_wq = kaluad_sync_wq;
+	spin_unlock_irqrestore(&pg->lock, flags);
+
+	if (start_queue &&
+	    !queue_delayed_work(alua_wq, &pg->rtpg_work,
+				msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) {
+		scsi_device_put(sdev);
+		kref_put(&pg->kref, release_port_group);
+	}
+}
+
+/*
  * alua_initialize - Initialize ALUA state
  * @sdev: the device to be initialized
  *
@@ -674,21 +882,14 @@
  */
 static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
 {
-	int err;
-
-	err = alua_check_tpgs(sdev, h);
-	if (err != SCSI_DH_OK)
-		goto out;
-
-	err = alua_vpd_inquiry(sdev, h);
-	if (err != SCSI_DH_OK)
-		goto out;
-
-	err = alua_rtpg(sdev, h, 0);
-	if (err != SCSI_DH_OK)
-		goto out;
+	int err = SCSI_DH_DEV_UNSUPP, tpgs;
 
-out:
+	mutex_lock(&h->init_mutex);
+	tpgs = alua_check_tpgs(sdev);
+	if (tpgs != TPGS_MODE_NONE)
+		err = alua_check_vpd(sdev, h, tpgs);
+	h->init_error = err;
+	mutex_unlock(&h->init_mutex);
 	return err;
 }
 /*
@@ -703,9 +904,11 @@
 static int alua_set_params(struct scsi_device *sdev, const char *params)
 {
 	struct alua_dh_data *h = sdev->handler_data;
+	struct alua_port_group __rcu *pg = NULL;
 	unsigned int optimize = 0, argc;
 	const char *p = params;
 	int result = SCSI_DH_OK;
+	unsigned long flags;
 
 	if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
 		return -EINVAL;
@@ -715,18 +918,23 @@
 	if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
 		return -EINVAL;
 
+	rcu_read_lock();
+	pg = rcu_dereference(h->pg);
+	if (!pg) {
+		rcu_read_unlock();
+		return -ENXIO;
+	}
+	spin_lock_irqsave(&pg->lock, flags);
 	if (optimize)
-		h->flags |= ALUA_OPTIMIZE_STPG;
+		pg->flags |= ALUA_OPTIMIZE_STPG;
 	else
-		h->flags &= ~ALUA_OPTIMIZE_STPG;
+		pg->flags &= ~ALUA_OPTIMIZE_STPG;
+	spin_unlock_irqrestore(&pg->lock, flags);
+	rcu_read_unlock();
 
 	return result;
 }
 
-static uint optimize_stpg;
-module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
-
 /*
  * alua_activate - activate a path
  * @sdev: device on the path to be activated
@@ -742,48 +950,33 @@
 {
 	struct alua_dh_data *h = sdev->handler_data;
 	int err = SCSI_DH_OK;
-	int stpg = 0;
+	struct alua_queue_data *qdata;
+	struct alua_port_group __rcu *pg;
 
-	err = alua_rtpg(sdev, h, 1);
-	if (err != SCSI_DH_OK)
+	qdata = kzalloc(sizeof(*qdata), GFP_KERNEL);
+	if (!qdata) {
+		err = SCSI_DH_RES_TEMP_UNAVAIL;
 		goto out;
-
-	if (optimize_stpg)
-		h->flags |= ALUA_OPTIMIZE_STPG;
-
-	if (h->tpgs & TPGS_MODE_EXPLICIT) {
-		switch (h->state) {
-		case TPGS_STATE_NONOPTIMIZED:
-			stpg = 1;
-			if ((h->flags & ALUA_OPTIMIZE_STPG) &&
-			    (!h->pref) &&
-			    (h->tpgs & TPGS_MODE_IMPLICIT))
-				stpg = 0;
-			break;
-		case TPGS_STATE_STANDBY:
-		case TPGS_STATE_UNAVAILABLE:
-			stpg = 1;
-			break;
-		case TPGS_STATE_OFFLINE:
-			err = SCSI_DH_IO;
-			break;
-		case TPGS_STATE_TRANSITIONING:
-			err = SCSI_DH_RETRY;
-			break;
-		default:
-			break;
-		}
 	}
+	qdata->callback_fn = fn;
+	qdata->callback_data = data;
 
-	if (stpg) {
-		h->callback_fn = fn;
-		h->callback_data = data;
-		err = submit_stpg(h);
-		if (err == SCSI_DH_OK)
-			return 0;
-		h->callback_fn = h->callback_data = NULL;
+	mutex_lock(&h->init_mutex);
+	rcu_read_lock();
+	pg = rcu_dereference(h->pg);
+	if (!pg || !kref_get_unless_zero(&pg->kref)) {
+		rcu_read_unlock();
+		kfree(qdata);
+		err = h->init_error;
+		mutex_unlock(&h->init_mutex);
+		goto out;
 	}
+	fn = NULL;
+	rcu_read_unlock();
+	mutex_unlock(&h->init_mutex);
 
+	alua_rtpg_queue(pg, sdev, qdata, true);
+	kref_put(&pg->kref, release_port_group);
 out:
 	if (fn)
 		fn(data, err);
@@ -791,6 +984,29 @@
 }
 
 /*
+ * alua_check - check path status
+ * @sdev: device on the path to be checked
+ *
+ * Check the device status
+ */
+static void alua_check(struct scsi_device *sdev, bool force)
+{
+	struct alua_dh_data *h = sdev->handler_data;
+	struct alua_port_group *pg;
+
+	rcu_read_lock();
+	pg = rcu_dereference(h->pg);
+	if (!pg || !kref_get_unless_zero(&pg->kref)) {
+		rcu_read_unlock();
+		return;
+	}
+	rcu_read_unlock();
+
+	alua_rtpg_queue(pg, sdev, NULL, force);
+	kref_put(&pg->kref, release_port_group);
+}
+
+/*
  * alua_prep_fn - request callback
  *
  * Fail I/O to all paths not in state
@@ -799,13 +1015,20 @@
 static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
 {
 	struct alua_dh_data *h = sdev->handler_data;
+	struct alua_port_group __rcu *pg;
+	int state = TPGS_STATE_OPTIMIZED;
 	int ret = BLKPREP_OK;
 
-	if (h->state == TPGS_STATE_TRANSITIONING)
+	rcu_read_lock();
+	pg = rcu_dereference(h->pg);
+	if (pg)
+		state = pg->state;
+	rcu_read_unlock();
+	if (state == TPGS_STATE_TRANSITIONING)
 		ret = BLKPREP_DEFER;
-	else if (h->state != TPGS_STATE_OPTIMIZED &&
-		 h->state != TPGS_STATE_NONOPTIMIZED &&
-		 h->state != TPGS_STATE_LBA_DEPENDENT) {
+	else if (state != TPGS_STATE_OPTIMIZED &&
+		 state != TPGS_STATE_NONOPTIMIZED &&
+		 state != TPGS_STATE_LBA_DEPENDENT) {
 		ret = BLKPREP_KILL;
 		req->cmd_flags |= REQ_QUIET;
 	}
@@ -820,20 +1043,20 @@
 static int alua_bus_attach(struct scsi_device *sdev)
 {
 	struct alua_dh_data *h;
-	int err;
+	int err, ret = -EINVAL;
 
 	h = kzalloc(sizeof(*h) , GFP_KERNEL);
 	if (!h)
 		return -ENOMEM;
-	h->tpgs = TPGS_MODE_UNINITIALIZED;
-	h->state = TPGS_STATE_OPTIMIZED;
-	h->group_id = -1;
-	h->rel_port = -1;
-	h->buff = h->inq;
-	h->bufflen = ALUA_INQUIRY_SIZE;
+	spin_lock_init(&h->pg_lock);
+	rcu_assign_pointer(h->pg, NULL);
+	h->init_error = SCSI_DH_OK;
 	h->sdev = sdev;
 
+	mutex_init(&h->init_mutex);
 	err = alua_initialize(sdev, h);
+	if (err == SCSI_DH_NOMEM)
+		ret = -ENOMEM;
 	if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
 		goto failed;
 
@@ -841,7 +1064,7 @@
 	return 0;
 failed:
 	kfree(h);
-	return -EINVAL;
+	return ret;
 }
 
 /*
@@ -851,9 +1074,16 @@
 static void alua_bus_detach(struct scsi_device *sdev)
 {
 	struct alua_dh_data *h = sdev->handler_data;
+	struct alua_port_group *pg;
+
+	spin_lock(&h->pg_lock);
+	pg = h->pg;
+	rcu_assign_pointer(h->pg, NULL);
+	h->sdev = NULL;
+	spin_unlock(&h->pg_lock);
+	if (pg)
+		kref_put(&pg->kref, release_port_group);
 
-	if (h->buff && h->inq != h->buff)
-		kfree(h->buff);
 	sdev->handler_data = NULL;
 	kfree(h);
 }
@@ -873,16 +1103,31 @@
 {
 	int r;
 
+	kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0);
+	if (!kaluad_wq) {
+		/* Temporary failure, bypass */
+		return SCSI_DH_DEV_TEMP_BUSY;
+	}
+	kaluad_sync_wq = create_workqueue("kaluad_sync");
+	if (!kaluad_sync_wq) {
+		destroy_workqueue(kaluad_wq);
+		return SCSI_DH_DEV_TEMP_BUSY;
+	}
 	r = scsi_register_device_handler(&alua_dh);
-	if (r != 0)
+	if (r != 0) {
 		printk(KERN_ERR "%s: Failed to register scsi device handler",
 			ALUA_DH_NAME);
+		destroy_workqueue(kaluad_sync_wq);
+		destroy_workqueue(kaluad_wq);
+	}
 	return r;
 }
 
 static void __exit alua_exit(void)
 {
 	scsi_unregister_device_handler(&alua_dh);
+	destroy_workqueue(kaluad_sync_wq);
+	destroy_workqueue(kaluad_wq);
 }
 
 module_init(alua_init);
--- linux-4.4.0.orig/drivers/scsi/device_handler/scsi_dh_emc.c
+++ linux-4.4.0/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -456,7 +456,7 @@
 static int clariion_std_inquiry(struct scsi_device *sdev,
 				struct clariion_dh_data *csdev)
 {
-	int err;
+	int err = SCSI_DH_OK;
 	char *sp_model;
 
 	err = send_inquiry_cmd(sdev, 0, csdev);
--- linux-4.4.0.orig/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ linux-4.4.0/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -562,7 +562,7 @@
 			/*
 			 * Command Lock contention
 			 */
-			err = SCSI_DH_RETRY;
+			err = SCSI_DH_IMM_RETRY;
 		break;
 	default:
 		break;
@@ -612,6 +612,8 @@
 		err = mode_select_handle_sense(sdev, h->sense);
 		if (err == SCSI_DH_RETRY && retry_cnt--)
 			goto retry;
+		if (err == SCSI_DH_IMM_RETRY)
+			goto retry;
 	}
 	if (err == SCSI_DH_OK) {
 		h->state = RDAC_STATE_ACTIVE;
--- linux-4.4.0.orig/drivers/scsi/dpt_i2o.c
+++ linux-4.4.0/drivers/scsi/dpt_i2o.c
@@ -180,11 +180,14 @@
  *============================================================================
  */
 
+#ifdef MODULE
 static struct pci_device_id dptids[] = {
 	{ PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
 	{ PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
 	{ 0, }
 };
+#endif
+
 MODULE_DEVICE_TABLE(pci,dptids);
 
 static int adpt_detect(struct scsi_host_template* sht)
--- linux-4.4.0.orig/drivers/scsi/esas2r/esas2r_flash.c
+++ linux-4.4.0/drivers/scsi/esas2r/esas2r_flash.c
@@ -1197,6 +1197,7 @@
 	if (!esas2r_read_flash_block(a, a->nvram, FLS_OFFSET_NVR,
 				     sizeof(struct esas2r_sas_nvram))) {
 		esas2r_hdebug("NVRAM read failed, using defaults");
+		up(&a->nvram_semaphore);
 		return false;
 	}
 
--- linux-4.4.0.orig/drivers/scsi/esp_scsi.c
+++ linux-4.4.0/drivers/scsi/esp_scsi.c
@@ -1349,6 +1349,7 @@
 
 	bytes_sent = esp->data_dma_len;
 	bytes_sent -= ecount;
+	bytes_sent -= esp->send_cmd_residual;
 
 	/*
 	 * The am53c974 has a DMA 'pecularity'. The doc states:
--- linux-4.4.0.orig/drivers/scsi/esp_scsi.h
+++ linux-4.4.0/drivers/scsi/esp_scsi.h
@@ -540,6 +540,8 @@
 
 	void			*dma;
 	int			dmarev;
+
+	u32			send_cmd_residual;
 };
 
 /* A front-end driver for the ESP chip should do the following in
--- linux-4.4.0.orig/drivers/scsi/fcoe/fcoe_ctlr.c
+++ linux-4.4.0/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -264,9 +264,9 @@
 		WARN_ON(!fcf_dev);
 		new->fcf_dev = NULL;
 		fcoe_fcf_device_delete(fcf_dev);
-		kfree(new);
 		mutex_unlock(&cdev->lock);
 	}
+	kfree(new);
 }
 
 /**
@@ -752,9 +752,9 @@
 	case ELS_LOGO:
 		if (fip->mode == FIP_MODE_VN2VN) {
 			if (fip->state != FIP_ST_VNMP_UP)
-				return -EINVAL;
+				goto drop;
 			if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI)
-				return -EINVAL;
+				goto drop;
 		} else {
 			if (fip->state != FIP_ST_ENABLED)
 				return 0;
@@ -1973,7 +1973,7 @@
  */
 static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata)
 {
-	return (struct fcoe_rport *)(rdata + 1);
+	return container_of(rdata, struct fcoe_rport, rdata);
 }
 
 /**
@@ -2233,7 +2233,7 @@
  */
 static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
 			      struct sk_buff *skb,
-			      struct fc_rport_priv *rdata)
+			      struct fcoe_rport *frport)
 {
 	struct fip_header *fiph;
 	struct fip_desc *desc = NULL;
@@ -2241,16 +2241,12 @@
 	struct fip_wwn_desc *wwn = NULL;
 	struct fip_vn_desc *vn = NULL;
 	struct fip_size_desc *size = NULL;
-	struct fcoe_rport *frport;
 	size_t rlen;
 	size_t dlen;
 	u32 desc_mask = 0;
 	u32 dtype;
 	u8 sub;
 
-	memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
-	frport = fcoe_ctlr_rport(rdata);
-
 	fiph = (struct fip_header *)skb->data;
 	frport->flags = ntohs(fiph->fip_flags);
 
@@ -2313,15 +2309,17 @@
 			if (dlen != sizeof(struct fip_wwn_desc))
 				goto len_err;
 			wwn = (struct fip_wwn_desc *)desc;
-			rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
+			frport->rdata.ids.node_name =
+				get_unaligned_be64(&wwn->fd_wwn);
 			break;
 		case FIP_DT_VN_ID:
 			if (dlen != sizeof(struct fip_vn_desc))
 				goto len_err;
 			vn = (struct fip_vn_desc *)desc;
 			memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN);
-			rdata->ids.port_id = ntoh24(vn->fd_fc_id);
-			rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn);
+			frport->rdata.ids.port_id = ntoh24(vn->fd_fc_id);
+			frport->rdata.ids.port_name =
+				get_unaligned_be64(&vn->fd_wwpn);
 			break;
 		case FIP_DT_FC4F:
 			if (dlen != sizeof(struct fip_fc4_feat))
@@ -2664,16 +2662,13 @@
 {
 	struct fip_header *fiph;
 	enum fip_vn2vn_subcode sub;
-	struct {
-		struct fc_rport_priv rdata;
-		struct fcoe_rport frport;
-	} buf;
+	struct fcoe_rport frport = { };
 	int rc;
 
 	fiph = (struct fip_header *)skb->data;
 	sub = fiph->fip_subcode;
 
-	rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata);
+	rc = fcoe_ctlr_vn_parse(fip, skb, &frport);
 	if (rc) {
 		LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc);
 		goto drop;
@@ -2682,19 +2677,19 @@
 	mutex_lock(&fip->ctlr_mutex);
 	switch (sub) {
 	case FIP_SC_VN_PROBE_REQ:
-		fcoe_ctlr_vn_probe_req(fip, &buf.rdata);
+		fcoe_ctlr_vn_probe_req(fip, &frport.rdata);
 		break;
 	case FIP_SC_VN_PROBE_REP:
-		fcoe_ctlr_vn_probe_reply(fip, &buf.rdata);
+		fcoe_ctlr_vn_probe_reply(fip, &frport.rdata);
 		break;
 	case FIP_SC_VN_CLAIM_NOTIFY:
-		fcoe_ctlr_vn_claim_notify(fip, &buf.rdata);
+		fcoe_ctlr_vn_claim_notify(fip, &frport.rdata);
 		break;
 	case FIP_SC_VN_CLAIM_REP:
-		fcoe_ctlr_vn_claim_resp(fip, &buf.rdata);
+		fcoe_ctlr_vn_claim_resp(fip, &frport.rdata);
 		break;
 	case FIP_SC_VN_BEACON:
-		fcoe_ctlr_vn_beacon(fip, &buf.rdata);
+		fcoe_ctlr_vn_beacon(fip, &frport.rdata);
 		break;
 	default:
 		LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub);
--- linux-4.4.0.orig/drivers/scsi/fdomain.c
+++ linux-4.4.0/drivers/scsi/fdomain.c
@@ -1768,7 +1768,7 @@
 };
 
 #ifndef PCMCIA
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && defined(MODULE)
 
 static struct pci_device_id fdomain_pci_tbl[] = {
 	{ PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
--- linux-4.4.0.orig/drivers/scsi/fnic/fnic.h
+++ linux-4.4.0/drivers/scsi/fnic/fnic.h
@@ -248,6 +248,7 @@
 	struct completion *remove_wait; /* device remove thread blocks */
 
 	atomic_t in_flight;		/* io counter */
+	bool internal_reset_inprogress;
 	u32 _reserved;			/* fill hole */
 	unsigned long state_flags;	/* protected by host lock */
 	enum fnic_state state;
--- linux-4.4.0.orig/drivers/scsi/fnic/fnic_fcs.c
+++ linux-4.4.0/drivers/scsi/fnic/fnic_fcs.c
@@ -954,8 +954,8 @@
 	skb_put(skb, len);
 	pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE);
 
-	r = pci_dma_mapping_error(fnic->pdev, pa);
-	if (r) {
+	if (pci_dma_mapping_error(fnic->pdev, pa)) {
+		r = -ENOMEM;
 		printk(KERN_ERR "PCI mapping failed with error %d\n", r);
 		goto free_skb;
 	}
@@ -1093,8 +1093,8 @@
 
 	pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE);
 
-	ret = pci_dma_mapping_error(fnic->pdev, pa);
-	if (ret) {
+	if (pci_dma_mapping_error(fnic->pdev, pa)) {
+		ret = -ENOMEM;
 		printk(KERN_ERR "DMA map failed with error %d\n", ret);
 		goto free_skb_on_err;
 	}
--- linux-4.4.0.orig/drivers/scsi/fnic/fnic_main.c
+++ linux-4.4.0/drivers/scsi/fnic/fnic_main.c
@@ -735,6 +735,7 @@
 	for (i = 0; i < FNIC_IO_LOCKS; i++)
 		spin_lock_init(&fnic->io_req_lock[i]);
 
+	err = -ENOMEM;
 	fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache);
 	if (!fnic->io_req_pool)
 		goto err_out_free_resources;
--- linux-4.4.0.orig/drivers/scsi/fnic/fnic_scsi.c
+++ linux-4.4.0/drivers/scsi/fnic/fnic_scsi.c
@@ -446,6 +446,9 @@
 	if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED)))
 		return SCSI_MLQUEUE_HOST_BUSY;
 
+	if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET)))
+		return SCSI_MLQUEUE_HOST_BUSY;
+
 	rport = starget_to_rport(scsi_target(sc->device));
 	ret = fc_remote_port_chkready(rport);
 	if (ret) {
@@ -2533,6 +2536,19 @@
 	unsigned long wait_host_tmo;
 	struct Scsi_Host *shost = sc->device->host;
 	struct fc_lport *lp = shost_priv(shost);
+	struct fnic *fnic = lport_priv(lp);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fnic->fnic_lock, flags);
+	if (fnic->internal_reset_inprogress == 0) {
+		fnic->internal_reset_inprogress = 1;
+	} else {
+		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
+		FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+			"host reset in progress skipping another host reset\n");
+		return SUCCESS;
+	}
+	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 
 	/*
 	 * If fnic_reset is successful, wait for fabric login to complete
@@ -2553,6 +2569,9 @@
 		}
 	}
 
+	spin_lock_irqsave(&fnic->fnic_lock, flags);
+	fnic->internal_reset_inprogress = 0;
+	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/scsi/fnic/vnic_dev.c
+++ linux-4.4.0/drivers/scsi/fnic/vnic_dev.c
@@ -445,26 +445,26 @@
 
 int vnic_dev_hang_notify(struct vnic_dev *vdev)
 {
-	u64 a0, a1;
+	u64 a0 = 0, a1 = 0;
 	int wait = 1000;
 	return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait);
 }
 
 int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr)
 {
-	u64 a0, a1;
+	u64 a[2] = {};
 	int wait = 1000;
 	int err, i;
 
 	for (i = 0; i < ETH_ALEN; i++)
 		mac_addr[i] = 0;
 
-	err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait);
+	err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a[0], &a[1], wait);
 	if (err)
 		return err;
 
 	for (i = 0; i < ETH_ALEN; i++)
-		mac_addr[i] = ((u8 *)&a0)[i];
+		mac_addr[i] = ((u8 *)&a)[i];
 
 	return 0;
 }
@@ -489,38 +489,32 @@
 
 void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
 {
-	u64 a0 = 0, a1 = 0;
+	u64 a[2] = {};
 	int wait = 1000;
 	int err;
 	int i;
 
 	for (i = 0; i < ETH_ALEN; i++)
-		((u8 *)&a0)[i] = addr[i];
+		((u8 *)&a)[i] = addr[i];
 
-	err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
+	err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a[0], &a[1], wait);
 	if (err)
-		printk(KERN_ERR
-			"Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
-			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
-			err);
+		pr_err("Can't add addr [%pM], %d\n", addr, err);
 }
 
 void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
 {
-	u64 a0 = 0, a1 = 0;
+	u64 a[2] = {};
 	int wait = 1000;
 	int err;
 	int i;
 
 	for (i = 0; i < ETH_ALEN; i++)
-		((u8 *)&a0)[i] = addr[i];
+		((u8 *)&a)[i] = addr[i];
 
-	err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
+	err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a[0], &a[1], wait);
 	if (err)
-		printk(KERN_ERR
-			"Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
-			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
-			err);
+		pr_err("Can't del addr [%pM], %d\n", addr, err);
 }
 
 int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
--- linux-4.4.0.orig/drivers/scsi/g_NCR5380.c
+++ linux-4.4.0/drivers/scsi/g_NCR5380.c
@@ -75,6 +75,7 @@
 #include <scsi/scsi_host.h>
 #include "g_NCR5380.h"
 #include "NCR5380.h"
+#include <linux/module.h>
 #include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -174,6 +175,9 @@
 {
 	int ints[10];
 
+	if (secure_modules())
+		return -EPERM;
+
 	get_options(str, ARRAY_SIZE(ints), ints);
 	internal_setup(BOARD_NCR5380, str, ints);
 	return 1;
@@ -192,6 +196,9 @@
 {
 	int ints[10];
 
+	if (secure_modules())
+		return -EPERM;
+
 	get_options(str, ARRAY_SIZE(ints), ints);
 	internal_setup(BOARD_NCR53C400, str, ints);
 	return 1;
@@ -210,6 +217,9 @@
 {
 	int ints[10];
 
+	if (secure_modules())
+		return -EPERM;
+
 	get_options(str, ARRAY_SIZE(ints), ints);
 	internal_setup(BOARD_NCR53C400A, str, ints);
 	return 1;
@@ -228,6 +238,9 @@
 {
 	int ints[10];
 
+	if (secure_modules())
+		return -EPERM;
+
 	get_options(str, ARRAY_SIZE(ints), ints);
 	internal_setup(BOARD_DTC3181E, str, ints);
 	return 1;
@@ -538,7 +551,10 @@
 			printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
 			return -1;
 		}
-		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY);
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+		{
+			// FIXME - no timeout
+		}
 
 #ifndef SCSI_G_NCR5380_MEM
 		{
@@ -714,9 +730,9 @@
 #include <linux/module.h>
 #include "scsi_module.c"
 
-module_param(ncr_irq, int, 0);
+module_param_hw(ncr_irq, int, irq, 0);
 module_param(ncr_dma, int, 0);
-module_param(ncr_addr, int, 0);
+module_param_hw(ncr_addr, int, ioport, 0);
 module_param(ncr_5380, int, 0);
 module_param(ncr_53c400, int, 0);
 module_param(ncr_53c400a, int, 0);
--- linux-4.4.0.orig/drivers/scsi/gdth.c
+++ linux-4.4.0/drivers/scsi/gdth.c
@@ -353,7 +353,7 @@
 static int force_dma32 = 0;
 
 /* parameters for modprobe/insmod */
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 module_param(disable, int, 0);
 module_param(reserve_mode, int, 0);
 module_param_array(reserve_list, int, NULL, 0);
--- linux-4.4.0.orig/drivers/scsi/gdth.h
+++ linux-4.4.0/drivers/scsi/gdth.h
@@ -177,9 +177,6 @@
 #define MSG_SIZE        34                      /* size of message structure */
 #define MSG_REQUEST     0                       /* async. event: message */
 
-/* cacheservice defines */
-#define SECTOR_SIZE     0x200                   /* always 512 bytes per sec. */
-
 /* DPMEM constants */
 #define DPMEM_MAGIC     0xC0FFEE11
 #define IC_HEADER_BYTES 48
--- linux-4.4.0.orig/drivers/scsi/hpsa.c
+++ linux-4.4.0/drivers/scsi/hpsa.c
@@ -906,7 +906,7 @@
 #endif
 	.sdev_attrs = hpsa_sdev_attrs,
 	.shost_attrs = hpsa_shost_attrs,
-	.max_sectors = 8192,
+	.max_sectors = 1024,
 	.no_write_same = 1,
 };
 
@@ -2153,6 +2153,8 @@
 	case IOACCEL2_SERV_RESPONSE_COMPLETE:
 		switch (c2->error_data.status) {
 		case IOACCEL2_STATUS_SR_TASK_COMP_GOOD:
+			if (cmd)
+				cmd->result = 0;
 			break;
 		case IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND:
 			cmd->result |= SAM_STAT_CHECK_CONDITION;
@@ -2320,8 +2322,10 @@
 
 	/* check for good status */
 	if (likely(c2->error_data.serv_response == 0 &&
-			c2->error_data.status == 0))
+			c2->error_data.status == 0)) {
+		cmd->result = 0;
 		return hpsa_cmd_free_and_done(h, c, cmd);
+	}
 
 	/*
 	 * Any RAID offload error results in retry which will use
@@ -3466,7 +3470,7 @@
  *  # (integer code indicating one of several NOT READY states
  *     describing why a volume is to be kept offline)
  */
-static int hpsa_volume_offline(struct ctlr_info *h,
+static unsigned char hpsa_volume_offline(struct ctlr_info *h,
 					unsigned char scsi3addr[])
 {
 	struct CommandList *c;
@@ -3486,7 +3490,7 @@
 	rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT);
 	if (rc) {
 		cmd_free(h, c);
-		return 0;
+		return HPSA_VPD_LV_STATUS_UNSUPPORTED;
 	}
 	sense = c->err_info->SenseInfo;
 	if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo))
@@ -3497,19 +3501,13 @@
 	cmd_status = c->err_info->CommandStatus;
 	scsi_status = c->err_info->ScsiStatus;
 	cmd_free(h, c);
-	/* Is the volume 'not ready'? */
-	if (cmd_status != CMD_TARGET_STATUS ||
-		scsi_status != SAM_STAT_CHECK_CONDITION ||
-		sense_key != NOT_READY ||
-		asc != ASC_LUN_NOT_READY)  {
-		return 0;
-	}
 
 	/* Determine the reason for not ready state */
 	ldstat = hpsa_get_volume_status(h, scsi3addr);
 
 	/* Keep volume offline in certain cases: */
 	switch (ldstat) {
+	case HPSA_LV_FAILED:
 	case HPSA_LV_UNDERGOING_ERASE:
 	case HPSA_LV_NOT_AVAILABLE:
 	case HPSA_LV_UNDERGOING_RPI:
@@ -3531,7 +3529,7 @@
 	default:
 		break;
 	}
-	return 0;
+	return HPSA_LV_OK;
 }
 
 /*
@@ -3615,10 +3613,10 @@
 	/* Do an inquiry to the device to see what it is. */
 	if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
 		(unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
-		/* Inquiry failed (msg printed already) */
 		dev_err(&h->pdev->dev,
-			"hpsa_update_device_info: inquiry failed\n");
-		rc = -EIO;
+			"%s: inquiry failed, device will be skipped.\n",
+			__func__);
+		rc = HPSA_INQUIRY_FAILED;
 		goto bail_out;
 	}
 
@@ -3638,15 +3636,20 @@
 
 	if (this_device->devtype == TYPE_DISK &&
 		is_logical_dev_addr_mode(scsi3addr)) {
-		int volume_offline;
+		unsigned char volume_offline;
 
 		hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
 		if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
 			hpsa_get_ioaccel_status(h, scsi3addr, this_device);
 		volume_offline = hpsa_volume_offline(h, scsi3addr);
-		if (volume_offline < 0 || volume_offline > 0xff)
-			volume_offline = HPSA_VPD_LV_STATUS_UNSUPPORTED;
-		this_device->volume_offline = volume_offline & 0xff;
+		this_device->volume_offline = volume_offline;
+		if (volume_offline == HPSA_LV_FAILED) {
+			rc = HPSA_LV_FAILED;
+			dev_err(&h->pdev->dev,
+				"%s: LV failed, device will be skipped.\n",
+				__func__);
+			goto bail_out;
+		}
 	} else {
 		this_device->raid_level = RAID_UNKNOWN;
 		this_device->offload_config = 0;
@@ -3930,6 +3933,70 @@
 	return rc;
 }
 
+static bool hpsa_is_disk_spare(struct ctlr_info *h, u8 *lunaddrbytes)
+{
+	struct bmic_identify_physical_device *id_phys;
+	bool is_spare = false;
+	int rc;
+
+	id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+	if (!id_phys)
+		return false;
+
+	rc = hpsa_bmic_id_physical_device(h,
+					lunaddrbytes,
+					GET_BMIC_DRIVE_NUMBER(lunaddrbytes),
+					id_phys, sizeof(*id_phys));
+	if (rc == 0)
+		is_spare = (id_phys->more_flags >> 6) & 0x01;
+
+	kfree(id_phys);
+	return is_spare;
+}
+
+#define RPL_DEV_FLAG_NON_DISK                           0x1
+#define RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED  0x2
+#define RPL_DEV_FLAG_UNCONFIG_DISK                      0x4
+
+#define BMIC_DEVICE_TYPE_ENCLOSURE  6
+
+static bool hpsa_skip_device(struct ctlr_info *h, u8 *lunaddrbytes,
+				struct ext_report_lun_entry *rle)
+{
+	u8 device_flags;
+	u8 device_type;
+
+	if (!MASKED_DEVICE(lunaddrbytes))
+		return false;
+
+	device_flags = rle->device_flags;
+	device_type = rle->device_type;
+
+	if (device_flags & RPL_DEV_FLAG_NON_DISK) {
+		if (device_type == BMIC_DEVICE_TYPE_ENCLOSURE)
+			return false;
+		return true;
+	}
+
+	if (!(device_flags & RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED))
+		return false;
+
+	if (device_flags & RPL_DEV_FLAG_UNCONFIG_DISK)
+		return false;
+
+	/*
+	 * Spares may be spun down, we do not want to
+	 * do an Inquiry to a RAID set spare drive as
+	 * that would have them spun up, that is a
+	 * performance hit because I/O to the RAID device
+	 * stops while the spin up occurs which can take
+	 * over 50 seconds.
+	 */
+	if (hpsa_is_disk_spare(h, lunaddrbytes))
+		return true;
+
+	return false;
+}
 
 static void hpsa_update_scsi_devices(struct ctlr_info *h)
 {
@@ -4023,6 +4090,7 @@
 		u8 *lunaddrbytes, is_OBDR = 0;
 		int rc = 0;
 		int phys_dev_index = i - (raid_ctlr_position == 0);
+		bool skip_device = false;
 
 		physical_device = i < nphysicals + (raid_ctlr_position == 0);
 
@@ -4030,10 +4098,15 @@
 		lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
 			i, nphysicals, nlogicals, physdev_list, logdev_list);
 
-		/* skip masked non-disk devices */
-		if (MASKED_DEVICE(lunaddrbytes) && physical_device &&
-			(physdev_list->LUN[phys_dev_index].device_flags & 0x01))
-			continue;
+		/*
+		 * Skip over some devices such as a spare.
+		 */
+		if (!tmpdevice->external && physical_device) {
+			skip_device = hpsa_skip_device(h, lunaddrbytes,
+					&physdev_list->LUN[phys_dev_index]);
+			if (skip_device)
+				continue;
+		}
 
 		/* Get device type, vendor, model, device id */
 		rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
@@ -4045,8 +4118,7 @@
 			goto out;
 		}
 		if (rc) {
-			dev_warn(&h->pdev->dev,
-				"Inquiry failed, skipping device.\n");
+			h->drv_req_rescan = 1;
 			continue;
 		}
 
@@ -4494,7 +4566,7 @@
 			curr_sg->reserved[0] = 0;
 			curr_sg->reserved[1] = 0;
 			curr_sg->reserved[2] = 0;
-			curr_sg->chain_indicator = 0x80;
+			curr_sg->chain_indicator = IOACCEL2_CHAIN;
 
 			curr_sg = h->ioaccel2_cmd_sg_list[c->cmdindex];
 		}
@@ -4511,6 +4583,11 @@
 			curr_sg++;
 		}
 
+		/*
+		 * Set the last s/g element bit
+		 */
+		(curr_sg - 1)->chain_indicator = IOACCEL2_LAST_SG;
+
 		switch (cmd->sc_data_direction) {
 		case DMA_TO_DEVICE:
 			cp->direction &= ~IOACCEL2_DIRECTION_MASK;
@@ -5164,6 +5241,12 @@
 	c = cmd_tagged_alloc(h, cmd);
 
 	/*
+	 * This is necessary because the SML doesn't zero out this field during
+	 * error recovery.
+	 */
+	cmd->result = 0;
+
+	/*
 	 * Call alternate submit routine for I/O accelerated commands.
 	 * Retries always go down the normal I/O path.
 	 */
@@ -5187,7 +5270,7 @@
 
 	spin_lock_irqsave(&h->scan_lock, flags);
 	h->scan_finished = 1;
-	wake_up_all(&h->scan_wait_queue);
+	wake_up(&h->scan_wait_queue);
 	spin_unlock_irqrestore(&h->scan_lock, flags);
 }
 
@@ -5205,11 +5288,23 @@
 	if (unlikely(lockup_detected(h)))
 		return hpsa_scan_complete(h);
 
+	/*
+	 * If a scan is already waiting to run, no need to add another
+	 */
+	spin_lock_irqsave(&h->scan_lock, flags);
+	if (h->scan_waiting) {
+		spin_unlock_irqrestore(&h->scan_lock, flags);
+		return;
+	}
+
+	spin_unlock_irqrestore(&h->scan_lock, flags);
+
 	/* wait until any scan already in progress is finished. */
 	while (1) {
 		spin_lock_irqsave(&h->scan_lock, flags);
 		if (h->scan_finished)
 			break;
+		h->scan_waiting = 1;
 		spin_unlock_irqrestore(&h->scan_lock, flags);
 		wait_event(h->scan_wait_queue, h->scan_finished);
 		/* Note: We don't need to worry about a race between this
@@ -5219,6 +5314,7 @@
 		 */
 	}
 	h->scan_finished = 0; /* mark scan as in progress */
+	h->scan_waiting = 0;
 	spin_unlock_irqrestore(&h->scan_lock, flags);
 
 	if (unlikely(lockup_detected(h)))
@@ -8435,6 +8531,7 @@
 	init_waitqueue_head(&h->event_sync_wait_queue);
 	mutex_init(&h->reset_mutex);
 	h->scan_finished = 1; /* no scan currently in progress */
+	h->scan_waiting = 0;
 
 	pci_set_drvdata(pdev, h);
 	h->ndevices = 0;
@@ -8727,6 +8824,8 @@
 	destroy_workqueue(h->rescan_ctlr_wq);
 	destroy_workqueue(h->resubmit_wq);
 
+	hpsa_delete_sas_host(h);
+
 	/*
 	 * Call before disabling interrupts.
 	 * scsi_remove_host can trigger I/O operations especially
@@ -8761,8 +8860,6 @@
 	h->lockup_detected = NULL;			/* init_one 2 */
 	/* (void) pci_disable_pcie_error_reporting(pdev); */	/* init_one 1 */
 
-	hpsa_delete_sas_host(h);
-
 	kfree(h);					/* init_one 1 */
 }
 
@@ -9254,9 +9351,9 @@
 	struct sas_phy *phy = hpsa_sas_phy->phy;
 
 	sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy);
-	sas_phy_free(phy);
 	if (hpsa_sas_phy->added_to_port)
 		list_del(&hpsa_sas_phy->phy_list_entry);
+	sas_phy_delete(phy);
 	kfree(hpsa_sas_phy);
 }
 
--- linux-4.4.0.orig/drivers/scsi/hpsa.h
+++ linux-4.4.0/drivers/scsi/hpsa.h
@@ -200,6 +200,7 @@
 	dma_addr_t		errinfo_pool_dhandle;
 	unsigned long  		*cmd_pool_bits;
 	int			scan_finished;
+	u8			scan_waiting : 1;
 	spinlock_t		scan_lock;
 	wait_queue_head_t	scan_wait_queue;
 
--- linux-4.4.0.orig/drivers/scsi/hpsa_cmd.h
+++ linux-4.4.0/drivers/scsi/hpsa_cmd.h
@@ -155,6 +155,7 @@
 #define CFGTBL_BusType_Fibre2G  0x00000200l
 
 /* VPD Inquiry types */
+#define HPSA_INQUIRY_FAILED		0x02
 #define HPSA_VPD_SUPPORTED_PAGES        0x00
 #define HPSA_VPD_LV_DEVICE_GEOMETRY     0xC1
 #define HPSA_VPD_LV_IOACCEL_STATUS      0xC2
@@ -164,6 +165,7 @@
 /* Logical volume states */
 #define HPSA_VPD_LV_STATUS_UNSUPPORTED			0xff
 #define HPSA_LV_OK                                      0x0
+#define HPSA_LV_FAILED					0x01
 #define HPSA_LV_NOT_AVAILABLE				0x0b
 #define HPSA_LV_UNDERGOING_ERASE			0x0F
 #define HPSA_LV_UNDERGOING_RPI				0x12
@@ -511,6 +513,7 @@
 	u8 reserved[3];
 	u8 chain_indicator;
 #define IOACCEL2_CHAIN 0x80
+#define IOACCEL2_LAST_SG 0x40
 };
 
 /*
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi/ibmvfc.c
+++ linux-4.4.0/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -717,7 +717,6 @@
 	spin_lock_irqsave(vhost->host->host_lock, flags);
 	vhost->state = IBMVFC_NO_CRQ;
 	vhost->logged_in = 0;
-	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
 
 	/* Clean out the queue */
 	memset(crq->msgs, 0, PAGE_SIZE);
@@ -2884,8 +2883,10 @@
 	unsigned long flags = 0;
 
 	spin_lock_irqsave(shost->host_lock, flags);
-	if (sdev->type == TYPE_DISK)
+	if (sdev->type == TYPE_DISK) {
 		sdev->allow_restart = 1;
+		blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
+	}
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	return 0;
 }
@@ -4791,6 +4792,7 @@
 	if (IS_ERR(vhost->work_thread)) {
 		dev_err(dev, "Couldn't create kernel thread: %ld\n",
 			PTR_ERR(vhost->work_thread));
+		rc = PTR_ERR(vhost->work_thread);
 		goto free_host_mem;
 	}
 
@@ -4870,8 +4872,8 @@
 
 	spin_lock_irqsave(vhost->host->host_lock, flags);
 	ibmvfc_purge_requests(vhost, DID_ERROR);
-	ibmvfc_free_event_pool(vhost);
 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
+	ibmvfc_free_event_pool(vhost);
 
 	ibmvfc_free_mem(vhost);
 	spin_lock(&ibmvfc_driver_lock);
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi/ibmvfc.h
+++ linux-4.4.0/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -26,7 +26,7 @@
 
 #include <linux/list.h>
 #include <linux/types.h>
-#include "viosrp.h"
+#include <scsi/viosrp.h>
 
 #define IBMVFC_NAME	"ibmvfc"
 #define IBMVFC_DRIVER_VERSION		"1.0.11"
@@ -366,7 +366,7 @@
 };
 
 struct ibmvfc_fcp_rsp_info {
-	__be16 reserved;
+	u8 reserved[3];
 	u8 rsp_code;
 	u8 reserved2[4];
 }__attribute__((packed, aligned (2)));
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ linux-4.4.0/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -93,7 +93,7 @@
 static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
 static int fast_fail = 1;
 static int client_reserve = 1;
-static char partition_name[97] = "UNKNOWN";
+static char partition_name[96] = "UNKNOWN";
 static unsigned int partition_number = -1;
 
 static struct scsi_transport_template *ibmvscsi_transport_template;
@@ -261,7 +261,7 @@
 
 	ppartition_name = of_get_property(rootdn, "ibm,partition-name", NULL);
 	if (ppartition_name)
-		strncpy(partition_name, ppartition_name,
+		strlcpy(partition_name, ppartition_name,
 				sizeof(partition_name));
 	p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL);
 	if (p_number_ptr)
@@ -427,6 +427,8 @@
 	int rc = 0;
 	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
 
+	set_adapter_info(hostdata);
+
 	/* Re-enable the CRQ */
 	do {
 		if (rc)
@@ -2041,7 +2043,7 @@
 	int len;
 
 	len = snprintf(buf, PAGE_SIZE, "%d\n",
-		       hostdata->madapter_info.partition_number);
+		       be32_to_cpu(hostdata->madapter_info.partition_number));
 	return len;
 }
 
@@ -2061,7 +2063,7 @@
 	int len;
 
 	len = snprintf(buf, PAGE_SIZE, "%d\n",
-		       hostdata->madapter_info.mad_version);
+		       be32_to_cpu(hostdata->madapter_info.mad_version));
 	return len;
 }
 
@@ -2080,7 +2082,8 @@
 	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 	int len;
 
-	len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
+	len = snprintf(buf, PAGE_SIZE, "%d\n",
+		       be32_to_cpu(hostdata->madapter_info.os_type));
 	return len;
 }
 
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ linux-4.4.0/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -33,7 +33,7 @@
 #include <linux/list.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
-#include "viosrp.h"
+#include <scsi/viosrp.h>
 
 struct scsi_cmnd;
 struct Scsi_Host;
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi_tgt/Makefile
+++ linux-4.4.0/drivers/scsi/ibmvscsi_tgt/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SCSI_IBMVSCSIS)	+= ibmvscsis.o
+
+ibmvscsis-y := libsrp.o ibmvscsi_tgt.o
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ linux-4.4.0/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -0,0 +1,3955 @@
+/*******************************************************************************
+ * IBM Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ *			   Santiago Leon (santil@us.ibm.com) IBM Corp.
+ *			   Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+ * Authors: Michael Cyr <mikecyr@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/string.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#include <asm/hvcall.h>
+#include <asm/vio.h>
+
+#include <scsi/viosrp.h>
+
+#include "ibmvscsi_tgt.h"
+
+#define IBMVSCSIS_VERSION	"v0.2"
+
+#define	INITIAL_SRP_LIMIT	800
+#define	DEFAULT_MAX_SECTORS	256
+#define MAX_TXU			1024 * 1024
+
+static uint max_vdma_size = MAX_H_COPY_RDMA;
+
+static char system_id[SYS_ID_NAME_LEN] = "";
+static char partition_name[PARTITION_NAMELEN] = "UNKNOWN";
+static uint partition_number = -1;
+
+/* Adapter list and lock to control it */
+static DEFINE_SPINLOCK(ibmvscsis_dev_lock);
+static LIST_HEAD(ibmvscsis_dev_list);
+
+static long ibmvscsis_parse_command(struct scsi_info *vscsi,
+				    struct viosrp_crq *crq);
+
+static void ibmvscsis_adapter_idle(struct scsi_info *vscsi);
+
+static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
+				      struct srp_rsp *rsp)
+{
+	u32 residual_count = se_cmd->residual_count;
+
+	if (!residual_count)
+		return;
+
+	if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+		if (se_cmd->data_direction == DMA_TO_DEVICE) {
+			/* residual data from an underflow write */
+			rsp->flags = SRP_RSP_FLAG_DOUNDER;
+			rsp->data_out_res_cnt = cpu_to_be32(residual_count);
+		} else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
+			/* residual data from an underflow read */
+			rsp->flags = SRP_RSP_FLAG_DIUNDER;
+			rsp->data_in_res_cnt = cpu_to_be32(residual_count);
+		}
+	} else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+		if (se_cmd->data_direction == DMA_TO_DEVICE) {
+			/* residual data from an overflow write */
+			rsp->flags = SRP_RSP_FLAG_DOOVER;
+			rsp->data_out_res_cnt = cpu_to_be32(residual_count);
+		} else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
+			/* residual data from an overflow read */
+			rsp->flags = SRP_RSP_FLAG_DIOVER;
+			rsp->data_in_res_cnt = cpu_to_be32(residual_count);
+		}
+	}
+}
+
+/**
+ * connection_broken() - Determine if the connection to the client is good
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * This function attempts to send a ping MAD to the client. If the call to
+ * queue the request returns H_CLOSED then the connection has been broken
+ * and the function returns TRUE.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt or Process environment
+ */
+static bool connection_broken(struct scsi_info *vscsi)
+{
+	struct viosrp_crq *crq;
+	u64 buffer[2] = { 0, 0 };
+	long h_return_code;
+	bool rc = false;
+
+	/* create a PING crq */
+	crq = (struct viosrp_crq *)&buffer;
+	crq->valid = VALID_CMD_RESP_EL;
+	crq->format = MESSAGE_IN_CRQ;
+	crq->status = PING;
+
+	h_return_code = h_send_crq(vscsi->dds.unit_id,
+				   cpu_to_be64(buffer[MSG_HI]),
+				   cpu_to_be64(buffer[MSG_LOW]));
+
+	pr_debug("connection_broken: rc %ld\n", h_return_code);
+
+	if (h_return_code == H_CLOSED)
+		rc = true;
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_unregister_command_q() - Helper Function-Unregister Command Queue
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * This function calls h_free_q then frees the interrupt bit etc.
+ * It must release the lock before doing so because of the time it can take
+ * for h_free_crq in PHYP
+ * NOTE: the caller must make sure that state and or flags will prevent
+ *	 interrupt handler from scheduling work.
+ * NOTE: anyone calling this function may need to set the CRQ_CLOSED flag
+ *	 we can't do it here, because we don't have the lock
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process level
+ */
+static long ibmvscsis_unregister_command_q(struct scsi_info *vscsi)
+{
+	long qrc;
+	long rc = ADAPT_SUCCESS;
+	int ticks = 0;
+
+	do {
+		qrc = h_free_crq(vscsi->dds.unit_id);
+		switch (qrc) {
+		case H_SUCCESS:
+			break;
+
+		case H_HARDWARE:
+		case H_PARAMETER:
+			dev_err(&vscsi->dev, "unregister_command_q: error from h_free_crq %ld\n",
+				qrc);
+			rc = ERROR;
+			break;
+
+		case H_BUSY:
+		case H_LONG_BUSY_ORDER_1_MSEC:
+			/* msleep not good for small values */
+			usleep_range(1000, 2000);
+			ticks += 1;
+			break;
+		case H_LONG_BUSY_ORDER_10_MSEC:
+			usleep_range(10000, 20000);
+			ticks += 10;
+			break;
+		case H_LONG_BUSY_ORDER_100_MSEC:
+			msleep(100);
+			ticks += 100;
+			break;
+		case H_LONG_BUSY_ORDER_1_SEC:
+			ssleep(1);
+			ticks += 1000;
+			break;
+		case H_LONG_BUSY_ORDER_10_SEC:
+			ssleep(10);
+			ticks += 10000;
+			break;
+		case H_LONG_BUSY_ORDER_100_SEC:
+			ssleep(100);
+			ticks += 100000;
+			break;
+		default:
+			dev_err(&vscsi->dev, "unregister_command_q: unknown error %ld from h_free_crq\n",
+				qrc);
+			rc = ERROR;
+			break;
+		}
+
+		/*
+		 * dont wait more then 300 seconds
+		 * ticks are in milliseconds more or less
+		 */
+		if (ticks > 300000 && qrc != H_SUCCESS) {
+			rc = ERROR;
+			dev_err(&vscsi->dev, "Excessive wait for h_free_crq\n");
+		}
+	} while (qrc != H_SUCCESS && rc == ADAPT_SUCCESS);
+
+	pr_debug("Freeing CRQ: phyp rc %ld, rc %ld\n", qrc, rc);
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_delete_client_info() - Helper function to Delete Client Info
+ * @vscsi:	Pointer to our adapter structure
+ * @client_closed:	True if client closed its queue
+ *
+ * Deletes information specific to the client when the client goes away
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt or Process
+ */
+static void ibmvscsis_delete_client_info(struct scsi_info *vscsi,
+					 bool client_closed)
+{
+	vscsi->client_cap = 0;
+
+	/*
+	 * Some things we don't want to clear if we're closing the queue,
+	 * because some clients don't resend the host handshake when they
+	 * get a transport event.
+	 */
+	if (client_closed)
+		vscsi->client_data.os_type = 0;
+}
+
+/**
+ * ibmvscsis_free_command_q() - Free Command Queue
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * This function calls unregister_command_q, then clears interrupts and
+ * any pending interrupt acknowledgments associated with the command q.
+ * It also clears memory if there is no error.
+ *
+ * PHYP did not meet the PAPR architecture so that we must give up the
+ * lock. This causes a timing hole regarding state change.  To close the
+ * hole this routine does accounting on any change that occurred during
+ * the time the lock is not held.
+ * NOTE: must give up and then acquire the interrupt lock, the caller must
+ *	 make sure that state and or flags will prevent interrupt handler from
+ *	 scheduling work.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process level, interrupt lock is held
+ */
+static long ibmvscsis_free_command_q(struct scsi_info *vscsi)
+{
+	int bytes;
+	u32 flags_under_lock;
+	u16 state_under_lock;
+	long rc = ADAPT_SUCCESS;
+
+	if (!(vscsi->flags & CRQ_CLOSED)) {
+		vio_disable_interrupts(vscsi->dma_dev);
+
+		state_under_lock = vscsi->new_state;
+		flags_under_lock = vscsi->flags;
+		vscsi->phyp_acr_state = 0;
+		vscsi->phyp_acr_flags = 0;
+
+		spin_unlock_bh(&vscsi->intr_lock);
+		rc = ibmvscsis_unregister_command_q(vscsi);
+		spin_lock_bh(&vscsi->intr_lock);
+
+		if (state_under_lock != vscsi->new_state)
+			vscsi->phyp_acr_state = vscsi->new_state;
+
+		vscsi->phyp_acr_flags = ((~flags_under_lock) & vscsi->flags);
+
+		if (rc == ADAPT_SUCCESS) {
+			bytes = vscsi->cmd_q.size * PAGE_SIZE;
+			memset(vscsi->cmd_q.base_addr, 0, bytes);
+			vscsi->cmd_q.index = 0;
+			vscsi->flags |= CRQ_CLOSED;
+
+			ibmvscsis_delete_client_info(vscsi, false);
+		}
+
+		pr_debug("free_command_q: flags 0x%x, state 0x%hx, acr_flags 0x%x, acr_state 0x%hx\n",
+			 vscsi->flags, vscsi->state, vscsi->phyp_acr_flags,
+			 vscsi->phyp_acr_state);
+	}
+	return rc;
+}
+
+/**
+ * ibmvscsis_cmd_q_dequeue() - Get valid Command element
+ * @mask:	Mask to use in case index wraps
+ * @current_index:	Current index into command queue
+ * @base_addr:	Pointer to start of command queue
+ *
+ * Returns a pointer to a valid command element or NULL, if the command
+ * queue is empty
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt environment, interrupt lock held
+ */
+static struct viosrp_crq *ibmvscsis_cmd_q_dequeue(uint mask,
+						  uint *current_index,
+						  struct viosrp_crq *base_addr)
+{
+	struct viosrp_crq *ptr;
+
+	ptr = base_addr + *current_index;
+
+	if (ptr->valid) {
+		*current_index = (*current_index + 1) & mask;
+		dma_rmb();
+	} else {
+		ptr = NULL;
+	}
+
+	return ptr;
+}
+
+/**
+ * ibmvscsis_send_init_message() - send initialize message to the client
+ * @vscsi:	Pointer to our adapter structure
+ * @format:	Which Init Message format to send
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt environment interrupt lock held
+ */
+static long ibmvscsis_send_init_message(struct scsi_info *vscsi, u8 format)
+{
+	struct viosrp_crq *crq;
+	u64 buffer[2] = { 0, 0 };
+	long rc;
+
+	crq = (struct viosrp_crq *)&buffer;
+	crq->valid = VALID_INIT_MSG;
+	crq->format = format;
+	rc = h_send_crq(vscsi->dds.unit_id, cpu_to_be64(buffer[MSG_HI]),
+			cpu_to_be64(buffer[MSG_LOW]));
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_check_init_msg() - Check init message valid
+ * @vscsi:	Pointer to our adapter structure
+ * @format:	Pointer to return format of Init Message, if any.
+ *		Set to UNUSED_FORMAT if no Init Message in queue.
+ *
+ * Checks if an initialize message was queued by the initiatior
+ * after the queue was created and before the interrupt was enabled.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process level only, interrupt lock held
+ */
+static long ibmvscsis_check_init_msg(struct scsi_info *vscsi, uint *format)
+{
+	struct viosrp_crq *crq;
+	long rc = ADAPT_SUCCESS;
+
+	crq = ibmvscsis_cmd_q_dequeue(vscsi->cmd_q.mask, &vscsi->cmd_q.index,
+				      vscsi->cmd_q.base_addr);
+	if (!crq) {
+		*format = (uint)UNUSED_FORMAT;
+	} else if (crq->valid == VALID_INIT_MSG && crq->format == INIT_MSG) {
+		*format = (uint)INIT_MSG;
+		crq->valid = INVALIDATE_CMD_RESP_EL;
+		dma_rmb();
+
+		/*
+		 * the caller has ensured no initialize message was
+		 * sent after the queue was
+		 * created so there should be no other message on the queue.
+		 */
+		crq = ibmvscsis_cmd_q_dequeue(vscsi->cmd_q.mask,
+					      &vscsi->cmd_q.index,
+					      vscsi->cmd_q.base_addr);
+		if (crq) {
+			*format = (uint)(crq->format);
+			rc = ERROR;
+			crq->valid = INVALIDATE_CMD_RESP_EL;
+			dma_rmb();
+		}
+	} else {
+		*format = (uint)(crq->format);
+		rc = ERROR;
+		crq->valid = INVALIDATE_CMD_RESP_EL;
+		dma_rmb();
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_disconnect() - Helper function to disconnect
+ * @work:	Pointer to work_struct, gives access to our adapter structure
+ *
+ * An error has occurred or the driver received a Transport event,
+ * and the driver is requesting that the command queue be de-registered
+ * in a safe manner. If there is no outstanding I/O then we can stop the
+ * queue. If we are restarting the queue it will be reflected in the
+ * the state of the adapter.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process environment
+ */
+static void ibmvscsis_disconnect(struct work_struct *work)
+{
+	struct scsi_info *vscsi = container_of(work, struct scsi_info,
+					       proc_work);
+	u16 new_state;
+	bool wait_idle = false;
+
+	spin_lock_bh(&vscsi->intr_lock);
+	new_state = vscsi->new_state;
+	vscsi->new_state = 0;
+
+	pr_debug("disconnect: flags 0x%x, state 0x%hx\n", vscsi->flags,
+		 vscsi->state);
+
+	/*
+	 * check which state we are in and see if we
+	 * should transitition to the new state
+	 */
+	switch (vscsi->state) {
+	/* Should never be called while in this state. */
+	case NO_QUEUE:
+	/*
+	 * Can never transition from this state;
+	 * igonore errors and logout.
+	 */
+	case UNCONFIGURING:
+		break;
+
+	/* can transition from this state to UNCONFIGURING */
+	case ERR_DISCONNECT:
+		if (new_state == UNCONFIGURING)
+			vscsi->state = new_state;
+		break;
+
+	/*
+	 * Can transition from this state to to unconfiguring
+	 * or err disconnect.
+	 */
+	case ERR_DISCONNECT_RECONNECT:
+		switch (new_state) {
+		case UNCONFIGURING:
+		case ERR_DISCONNECT:
+			vscsi->state = new_state;
+			break;
+
+		case WAIT_IDLE:
+			break;
+		default:
+			break;
+		}
+		break;
+
+	/* can transition from this state to UNCONFIGURING */
+	case ERR_DISCONNECTED:
+		if (new_state == UNCONFIGURING)
+			vscsi->state = new_state;
+		break;
+
+	case WAIT_ENABLED:
+		switch (new_state) {
+		case UNCONFIGURING:
+			vscsi->state = new_state;
+			vscsi->flags |= RESPONSE_Q_DOWN;
+			vscsi->flags &= ~(SCHEDULE_DISCONNECT |
+					  DISCONNECT_SCHEDULED);
+			dma_rmb();
+			if (vscsi->flags & CFG_SLEEPING) {
+				vscsi->flags &= ~CFG_SLEEPING;
+				complete(&vscsi->unconfig);
+			}
+			break;
+
+		/* should never happen */
+		case ERR_DISCONNECT:
+		case ERR_DISCONNECT_RECONNECT:
+		case WAIT_IDLE:
+			dev_err(&vscsi->dev, "disconnect: invalid state %d for WAIT_IDLE\n",
+				vscsi->state);
+			break;
+		}
+		break;
+
+	case WAIT_IDLE:
+		switch (new_state) {
+		case UNCONFIGURING:
+			vscsi->flags |= RESPONSE_Q_DOWN;
+			vscsi->state = new_state;
+			vscsi->flags &= ~(SCHEDULE_DISCONNECT |
+					  DISCONNECT_SCHEDULED);
+			ibmvscsis_free_command_q(vscsi);
+			break;
+		case ERR_DISCONNECT:
+		case ERR_DISCONNECT_RECONNECT:
+			vscsi->state = new_state;
+			break;
+		}
+		break;
+
+	/*
+	 * Initiator has not done a successful srp login
+	 * or has done a successful srp logout ( adapter was not
+	 * busy). In the first case there can be responses queued
+	 * waiting for space on the initiators response queue (MAD)
+	 * The second case the adapter is idle. Assume the worse case,
+	 * i.e. the second case.
+	 */
+	case WAIT_CONNECTION:
+	case CONNECTED:
+	case SRP_PROCESSING:
+		wait_idle = true;
+		vscsi->state = new_state;
+		break;
+
+	/* can transition from this state to UNCONFIGURING */
+	case UNDEFINED:
+		if (new_state == UNCONFIGURING)
+			vscsi->state = new_state;
+		break;
+	default:
+		break;
+	}
+
+	if (wait_idle) {
+		pr_debug("disconnect start wait, active %d, sched %d\n",
+			 (int)list_empty(&vscsi->active_q),
+			 (int)list_empty(&vscsi->schedule_q));
+		if (!list_empty(&vscsi->active_q) ||
+		    !list_empty(&vscsi->schedule_q)) {
+			vscsi->flags |= WAIT_FOR_IDLE;
+			pr_debug("disconnect flags 0x%x\n", vscsi->flags);
+			/*
+			 * This routine is can not be called with the interrupt
+			 * lock held.
+			 */
+			spin_unlock_bh(&vscsi->intr_lock);
+			wait_for_completion(&vscsi->wait_idle);
+			spin_lock_bh(&vscsi->intr_lock);
+		}
+		pr_debug("disconnect stop wait\n");
+
+		ibmvscsis_adapter_idle(vscsi);
+	}
+
+	spin_unlock_bh(&vscsi->intr_lock);
+}
+
+/**
+ * ibmvscsis_post_disconnect() - Schedule the disconnect
+ * @vscsi:	Pointer to our adapter structure
+ * @new_state:	State to move to after disconnecting
+ * @flag_bits:	Flags to turn on in adapter structure
+ *
+ * If it's already been scheduled, then see if we need to "upgrade"
+ * the new state (if the one passed in is more "severe" than the
+ * previous one).
+ *
+ * PRECONDITION:
+ *	interrupt lock is held
+ */
+static void ibmvscsis_post_disconnect(struct scsi_info *vscsi, uint new_state,
+				      uint flag_bits)
+{
+	uint state;
+
+	/* check the validity of the new state */
+	switch (new_state) {
+	case UNCONFIGURING:
+	case ERR_DISCONNECT:
+	case ERR_DISCONNECT_RECONNECT:
+	case WAIT_IDLE:
+		break;
+
+	default:
+		dev_err(&vscsi->dev, "post_disconnect: Invalid new state %d\n",
+			new_state);
+		return;
+	}
+
+	vscsi->flags |= flag_bits;
+
+	pr_debug("post_disconnect: new_state 0x%x, flag_bits 0x%x, vscsi->flags 0x%x, state %hx\n",
+		 new_state, flag_bits, vscsi->flags, vscsi->state);
+
+	if (!(vscsi->flags & (DISCONNECT_SCHEDULED | SCHEDULE_DISCONNECT))) {
+		vscsi->flags |= SCHEDULE_DISCONNECT;
+		vscsi->new_state = new_state;
+
+		INIT_WORK(&vscsi->proc_work, ibmvscsis_disconnect);
+		(void)queue_work(vscsi->work_q, &vscsi->proc_work);
+	} else {
+		if (vscsi->new_state)
+			state = vscsi->new_state;
+		else
+			state = vscsi->state;
+
+		switch (state) {
+		case NO_QUEUE:
+		case UNCONFIGURING:
+			break;
+
+		case ERR_DISCONNECTED:
+		case ERR_DISCONNECT:
+		case UNDEFINED:
+			if (new_state == UNCONFIGURING)
+				vscsi->new_state = new_state;
+			break;
+
+		case ERR_DISCONNECT_RECONNECT:
+			switch (new_state) {
+			case UNCONFIGURING:
+			case ERR_DISCONNECT:
+				vscsi->new_state = new_state;
+				break;
+			default:
+				break;
+			}
+			break;
+
+		case WAIT_ENABLED:
+		case WAIT_IDLE:
+		case WAIT_CONNECTION:
+		case CONNECTED:
+		case SRP_PROCESSING:
+			vscsi->new_state = new_state;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	pr_debug("Leaving post_disconnect: flags 0x%x, new_state 0x%x\n",
+		 vscsi->flags, vscsi->new_state);
+}
+
+/**
+ * ibmvscsis_handle_init_compl_msg() - Respond to an Init Complete Message
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_handle_init_compl_msg(struct scsi_info *vscsi)
+{
+	long rc = ADAPT_SUCCESS;
+
+	switch (vscsi->state) {
+	case NO_QUEUE:
+	case ERR_DISCONNECT:
+	case ERR_DISCONNECT_RECONNECT:
+	case ERR_DISCONNECTED:
+	case UNCONFIGURING:
+	case UNDEFINED:
+		rc = ERROR;
+		break;
+
+	case WAIT_CONNECTION:
+		vscsi->state = CONNECTED;
+		break;
+
+	case WAIT_IDLE:
+	case SRP_PROCESSING:
+	case CONNECTED:
+	case WAIT_ENABLED:
+	default:
+		rc = ERROR;
+		dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n",
+			vscsi->state);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		break;
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_handle_init_msg() - Respond to an Init Message
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_handle_init_msg(struct scsi_info *vscsi)
+{
+	long rc = ADAPT_SUCCESS;
+
+	switch (vscsi->state) {
+	case WAIT_CONNECTION:
+		rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG);
+		switch (rc) {
+		case H_SUCCESS:
+			vscsi->state = CONNECTED;
+			break;
+
+		case H_PARAMETER:
+			dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
+				rc);
+			ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
+			break;
+
+		case H_DROPPED:
+			dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
+				rc);
+			rc = ERROR;
+			ibmvscsis_post_disconnect(vscsi,
+						  ERR_DISCONNECT_RECONNECT, 0);
+			break;
+
+		case H_CLOSED:
+			pr_warn("init_msg: failed to send, rc %ld\n", rc);
+			rc = 0;
+			break;
+		}
+		break;
+
+	case UNDEFINED:
+		rc = ERROR;
+		break;
+
+	case UNCONFIGURING:
+		break;
+
+	case WAIT_ENABLED:
+	case CONNECTED:
+	case SRP_PROCESSING:
+	case WAIT_IDLE:
+	case NO_QUEUE:
+	case ERR_DISCONNECT:
+	case ERR_DISCONNECT_RECONNECT:
+	case ERR_DISCONNECTED:
+	default:
+		rc = ERROR;
+		dev_err(&vscsi->dev, "init_msg: invalid state %d to get init msg\n",
+			vscsi->state);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		break;
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_init_msg() - Respond to an init message
+ * @vscsi:	Pointer to our adapter structure
+ * @crq:	Pointer to CRQ element containing the Init Message
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, interrupt lock held
+ */
+static long ibmvscsis_init_msg(struct scsi_info *vscsi, struct viosrp_crq *crq)
+{
+	long rc = ADAPT_SUCCESS;
+
+	pr_debug("init_msg: state 0x%hx\n", vscsi->state);
+
+	rc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO,
+		      (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0,
+		      0);
+	if (rc == H_SUCCESS) {
+		vscsi->client_data.partition_number =
+			be64_to_cpu(*(u64 *)vscsi->map_buf);
+		pr_debug("init_msg, part num %d\n",
+			 vscsi->client_data.partition_number);
+	} else {
+		pr_debug("init_msg h_vioctl rc %ld\n", rc);
+		rc = ADAPT_SUCCESS;
+	}
+
+	if (crq->format == INIT_MSG) {
+		rc = ibmvscsis_handle_init_msg(vscsi);
+	} else if (crq->format == INIT_COMPLETE_MSG) {
+		rc = ibmvscsis_handle_init_compl_msg(vscsi);
+	} else {
+		rc = ERROR;
+		dev_err(&vscsi->dev, "init_msg: invalid format %d\n",
+			(uint)crq->format);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_establish_new_q() - Establish new CRQ queue
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_establish_new_q(struct scsi_info *vscsi)
+{
+	long rc = ADAPT_SUCCESS;
+	uint format;
+
+	vscsi->flags &= PRESERVE_FLAG_FIELDS;
+	vscsi->rsp_q_timer.timer_pops = 0;
+	vscsi->debit = 0;
+	vscsi->credit = 0;
+
+	rc = vio_enable_interrupts(vscsi->dma_dev);
+	if (rc) {
+		pr_warn("establish_new_q: failed to enable interrupts, rc %ld\n",
+			rc);
+		return rc;
+	}
+
+	rc = ibmvscsis_check_init_msg(vscsi, &format);
+	if (rc) {
+		dev_err(&vscsi->dev, "establish_new_q: check_init_msg failed, rc %ld\n",
+			rc);
+		return rc;
+	}
+
+	if (format == UNUSED_FORMAT) {
+		rc = ibmvscsis_send_init_message(vscsi, INIT_MSG);
+		switch (rc) {
+		case H_SUCCESS:
+		case H_DROPPED:
+		case H_CLOSED:
+			rc = ADAPT_SUCCESS;
+			break;
+
+		case H_PARAMETER:
+		case H_HARDWARE:
+			break;
+
+		default:
+			vscsi->state = UNDEFINED;
+			rc = H_HARDWARE;
+			break;
+		}
+	} else if (format == INIT_MSG) {
+		rc = ibmvscsis_handle_init_msg(vscsi);
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_reset_queue() - Reset CRQ Queue
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * This function calls h_free_q and then calls h_reg_q and does all
+ * of the bookkeeping to get us back to where we can communicate.
+ *
+ * Actually, we don't always call h_free_crq.  A problem was discovered
+ * where one partition would close and reopen his queue, which would
+ * cause his partner to get a transport event, which would cause him to
+ * close and reopen his queue, which would cause the original partition
+ * to get a transport event, etc., etc.  To prevent this, we don't
+ * actually close our queue if the client initiated the reset, (i.e.
+ * either we got a transport event or we have detected that the client's
+ * queue is gone)
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process environment, called with interrupt lock held
+ */
+static void ibmvscsis_reset_queue(struct scsi_info *vscsi)
+{
+	int bytes;
+	long rc = ADAPT_SUCCESS;
+
+	pr_debug("reset_queue: flags 0x%x\n", vscsi->flags);
+
+	/* don't reset, the client did it for us */
+	if (vscsi->flags & (CLIENT_FAILED | TRANS_EVENT)) {
+		vscsi->flags &= PRESERVE_FLAG_FIELDS;
+		vscsi->rsp_q_timer.timer_pops = 0;
+		vscsi->debit = 0;
+		vscsi->credit = 0;
+		vscsi->state = WAIT_CONNECTION;
+		vio_enable_interrupts(vscsi->dma_dev);
+	} else {
+		rc = ibmvscsis_free_command_q(vscsi);
+		if (rc == ADAPT_SUCCESS) {
+			vscsi->state = WAIT_CONNECTION;
+
+			bytes = vscsi->cmd_q.size * PAGE_SIZE;
+			rc = h_reg_crq(vscsi->dds.unit_id,
+				       vscsi->cmd_q.crq_token, bytes);
+			if (rc == H_CLOSED || rc == H_SUCCESS) {
+				rc = ibmvscsis_establish_new_q(vscsi);
+			}
+
+			if (rc != ADAPT_SUCCESS) {
+				pr_debug("reset_queue: reg_crq rc %ld\n", rc);
+
+				vscsi->state = ERR_DISCONNECTED;
+				vscsi->flags |= RESPONSE_Q_DOWN;
+				ibmvscsis_free_command_q(vscsi);
+			}
+		} else {
+			vscsi->state = ERR_DISCONNECTED;
+			vscsi->flags |= RESPONSE_Q_DOWN;
+		}
+	}
+}
+
+/**
+ * ibmvscsis_free_cmd_resources() - Free command resources
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Command which is not longer in use
+ *
+ * Must be called with interrupt lock held.
+ */
+static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi,
+					 struct ibmvscsis_cmd *cmd)
+{
+	struct iu_entry *iue = cmd->iue;
+
+	switch (cmd->type) {
+	case TASK_MANAGEMENT:
+	case SCSI_CDB:
+		/*
+		 * When the queue goes down this value is cleared, so it
+		 * cannot be cleared in this general purpose function.
+		 */
+		if (vscsi->debit)
+			vscsi->debit -= 1;
+		break;
+	case ADAPTER_MAD:
+		vscsi->flags &= ~PROCESSING_MAD;
+		break;
+	case UNSET_TYPE:
+		break;
+	default:
+		dev_err(&vscsi->dev, "free_cmd_resources unknown type %d\n",
+			cmd->type);
+		break;
+	}
+
+	cmd->iue = NULL;
+	list_add_tail(&cmd->list, &vscsi->free_cmd);
+	srp_iu_put(iue);
+
+	if (list_empty(&vscsi->active_q) && list_empty(&vscsi->schedule_q) &&
+	    list_empty(&vscsi->waiting_rsp) && (vscsi->flags & WAIT_FOR_IDLE)) {
+		vscsi->flags &= ~WAIT_FOR_IDLE;
+		complete(&vscsi->wait_idle);
+	}
+}
+
+/**
+ * ibmvscsis_trans_event() - Handle a Transport Event
+ * @vscsi:	Pointer to our adapter structure
+ * @crq:	Pointer to CRQ entry containing the Transport Event
+ *
+ * Do the logic to close the I_T nexus.  This function may not
+ * behave to specification.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, interrupt lock held
+ */
+static long ibmvscsis_trans_event(struct scsi_info *vscsi,
+				  struct viosrp_crq *crq)
+{
+	long rc = ADAPT_SUCCESS;
+
+	pr_debug("trans_event: format %d, flags 0x%x, state 0x%hx\n",
+		 (int)crq->format, vscsi->flags, vscsi->state);
+
+	switch (crq->format) {
+	case MIGRATED:
+	case PARTNER_FAILED:
+	case PARTNER_DEREGISTER:
+		ibmvscsis_delete_client_info(vscsi, true);
+		break;
+
+	default:
+		rc = ERROR;
+		dev_err(&vscsi->dev, "trans_event: invalid format %d\n",
+			(uint)crq->format);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT,
+					  RESPONSE_Q_DOWN);
+		break;
+	}
+
+	if (rc == ADAPT_SUCCESS) {
+		switch (vscsi->state) {
+		case NO_QUEUE:
+		case ERR_DISCONNECTED:
+		case UNDEFINED:
+			break;
+
+		case UNCONFIGURING:
+			vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT);
+			break;
+
+		case WAIT_ENABLED:
+			break;
+
+		case WAIT_CONNECTION:
+			break;
+
+		case CONNECTED:
+			ibmvscsis_post_disconnect(vscsi, WAIT_IDLE,
+						  (RESPONSE_Q_DOWN |
+						   TRANS_EVENT));
+			break;
+
+		case SRP_PROCESSING:
+			if ((vscsi->debit > 0) ||
+			    !list_empty(&vscsi->schedule_q) ||
+			    !list_empty(&vscsi->waiting_rsp) ||
+			    !list_empty(&vscsi->active_q)) {
+				pr_debug("debit %d, sched %d, wait %d, active %d\n",
+					 vscsi->debit,
+					 (int)list_empty(&vscsi->schedule_q),
+					 (int)list_empty(&vscsi->waiting_rsp),
+					 (int)list_empty(&vscsi->active_q));
+				pr_warn("connection lost with outstanding work\n");
+			} else {
+				pr_debug("trans_event: SRP Processing, but no outstanding work\n");
+			}
+
+			ibmvscsis_post_disconnect(vscsi, WAIT_IDLE,
+						  (RESPONSE_Q_DOWN |
+						   TRANS_EVENT));
+			break;
+
+		case ERR_DISCONNECT:
+		case ERR_DISCONNECT_RECONNECT:
+		case WAIT_IDLE:
+			vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT);
+			break;
+		}
+	}
+
+	rc = vscsi->flags & SCHEDULE_DISCONNECT;
+
+	pr_debug("Leaving trans_event: flags 0x%x, state 0x%hx, rc %ld\n",
+		 vscsi->flags, vscsi->state, rc);
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_poll_cmd_q() - Poll Command Queue
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Called to handle command elements that may have arrived while
+ * interrupts were disabled.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	intr_lock must be held
+ */
+static void ibmvscsis_poll_cmd_q(struct scsi_info *vscsi)
+{
+	struct viosrp_crq *crq;
+	long rc;
+	bool ack = true;
+	volatile u8 valid;
+
+	pr_debug("poll_cmd_q: flags 0x%x, state 0x%hx, q index %ud\n",
+		 vscsi->flags, vscsi->state, vscsi->cmd_q.index);
+
+	rc = vscsi->flags & SCHEDULE_DISCONNECT;
+	crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+	valid = crq->valid;
+	dma_rmb();
+
+	while (valid) {
+poll_work:
+		vscsi->cmd_q.index =
+			(vscsi->cmd_q.index + 1) & vscsi->cmd_q.mask;
+
+		if (!rc) {
+			rc = ibmvscsis_parse_command(vscsi, crq);
+		} else {
+			if ((uint)crq->valid == VALID_TRANS_EVENT) {
+				/*
+				 * must service the transport layer events even
+				 * in an error state, dont break out until all
+				 * the consecutive transport events have been
+				 * processed
+				 */
+				rc = ibmvscsis_trans_event(vscsi, crq);
+			} else if (vscsi->flags & TRANS_EVENT) {
+				/*
+				 * if a tranport event has occurred leave
+				 * everything but transport events on the queue
+				 */
+				pr_debug("poll_cmd_q, ignoring\n");
+
+				/*
+				 * need to decrement the queue index so we can
+				 * look at the elment again
+				 */
+				if (vscsi->cmd_q.index)
+					vscsi->cmd_q.index -= 1;
+				else
+					/*
+					 * index is at 0 it just wrapped.
+					 * have it index last element in q
+					 */
+					vscsi->cmd_q.index = vscsi->cmd_q.mask;
+				break;
+			}
+		}
+
+		crq->valid = INVALIDATE_CMD_RESP_EL;
+
+		crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+		valid = crq->valid;
+		dma_rmb();
+	}
+
+	if (!rc) {
+		if (ack) {
+			vio_enable_interrupts(vscsi->dma_dev);
+			ack = false;
+			pr_debug("poll_cmd_q, reenabling interrupts\n");
+		}
+		valid = crq->valid;
+		dma_rmb();
+		if (valid)
+			goto poll_work;
+	}
+
+	pr_debug("Leaving poll_cmd_q: rc %ld\n", rc);
+}
+
+/**
+ * ibmvscsis_free_cmd_qs() - Free elements in queue
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Free all of the elements on all queues that are waiting for
+ * whatever reason.
+ *
+ * PRECONDITION:
+ *	Called with interrupt lock held
+ */
+static void ibmvscsis_free_cmd_qs(struct scsi_info *vscsi)
+{
+	struct ibmvscsis_cmd *cmd, *nxt;
+
+	pr_debug("free_cmd_qs: waiting_rsp empty %d, timer starter %d\n",
+		 (int)list_empty(&vscsi->waiting_rsp),
+		 vscsi->rsp_q_timer.started);
+
+	list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp, list) {
+		list_del(&cmd->list);
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+	}
+}
+
+/**
+ * ibmvscsis_get_free_cmd() - Get free command from list
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Must be called with interrupt lock held.
+ */
+static struct ibmvscsis_cmd *ibmvscsis_get_free_cmd(struct scsi_info *vscsi)
+{
+	struct ibmvscsis_cmd *cmd = NULL;
+	struct iu_entry *iue;
+
+	iue = srp_iu_get(&vscsi->target);
+	if (iue) {
+		cmd = list_first_entry_or_null(&vscsi->free_cmd,
+					       struct ibmvscsis_cmd, list);
+		if (cmd) {
+			list_del(&cmd->list);
+			cmd->iue = iue;
+			cmd->type = UNSET_TYPE;
+			memset(&cmd->se_cmd, 0, sizeof(cmd->se_cmd));
+		} else {
+			srp_iu_put(iue);
+		}
+	}
+
+	return cmd;
+}
+
+/**
+ * ibmvscsis_adapter_idle() - Helper function to handle idle adapter
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * This function is called when the adapter is idle when the driver
+ * is attempting to clear an error condition.
+ * The adapter is considered busy if any of its cmd queues
+ * are non-empty. This function can be invoked
+ * from the off level disconnect function.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process environment called with interrupt lock held
+ */
+static void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
+{
+	int free_qs = false;
+
+	pr_debug("adapter_idle: flags 0x%x, state 0x%hx\n", vscsi->flags,
+		 vscsi->state);
+
+	/* Only need to free qs if we're disconnecting from client */
+	if (vscsi->state != WAIT_CONNECTION || vscsi->flags & TRANS_EVENT)
+		free_qs = true;
+
+	switch (vscsi->state) {
+	case UNCONFIGURING:
+		ibmvscsis_free_command_q(vscsi);
+		dma_rmb();
+		isync();
+		if (vscsi->flags & CFG_SLEEPING) {
+			vscsi->flags &= ~CFG_SLEEPING;
+			complete(&vscsi->unconfig);
+		}
+		break;
+	case ERR_DISCONNECT_RECONNECT:
+		ibmvscsis_reset_queue(vscsi);
+		pr_debug("adapter_idle, disc_rec: flags 0x%x\n", vscsi->flags);
+		break;
+
+	case ERR_DISCONNECT:
+		ibmvscsis_free_command_q(vscsi);
+		vscsi->flags &= ~(SCHEDULE_DISCONNECT | DISCONNECT_SCHEDULED);
+		vscsi->flags |= RESPONSE_Q_DOWN;
+		if (vscsi->tport.enabled)
+			vscsi->state = ERR_DISCONNECTED;
+		else
+			vscsi->state = WAIT_ENABLED;
+		pr_debug("adapter_idle, disc: flags 0x%x, state 0x%hx\n",
+			 vscsi->flags, vscsi->state);
+		break;
+
+	case WAIT_IDLE:
+		vscsi->rsp_q_timer.timer_pops = 0;
+		vscsi->debit = 0;
+		vscsi->credit = 0;
+		if (vscsi->flags & TRANS_EVENT) {
+			vscsi->state = WAIT_CONNECTION;
+			vscsi->flags &= PRESERVE_FLAG_FIELDS;
+		} else {
+			vscsi->state = CONNECTED;
+			vscsi->flags &= ~DISCONNECT_SCHEDULED;
+		}
+
+		pr_debug("adapter_idle, wait: flags 0x%x, state 0x%hx\n",
+			 vscsi->flags, vscsi->state);
+		ibmvscsis_poll_cmd_q(vscsi);
+		break;
+
+	case ERR_DISCONNECTED:
+		vscsi->flags &= ~DISCONNECT_SCHEDULED;
+		pr_debug("adapter_idle, disconnected: flags 0x%x, state 0x%hx\n",
+			 vscsi->flags, vscsi->state);
+		break;
+
+	default:
+		dev_err(&vscsi->dev, "adapter_idle: in invalid state %d\n",
+			vscsi->state);
+		break;
+	}
+
+	if (free_qs)
+		ibmvscsis_free_cmd_qs(vscsi);
+
+	/*
+	 * There is a timing window where we could lose a disconnect request.
+	 * The known path to this window occurs during the DISCONNECT_RECONNECT
+	 * case above: reset_queue calls free_command_q, which will release the
+	 * interrupt lock.  During that time, a new post_disconnect call can be
+	 * made with a "more severe" state (DISCONNECT or UNCONFIGURING).
+	 * Because the DISCONNECT_SCHEDULED flag is already set, post_disconnect
+	 * will only set the new_state.  Now free_command_q reacquires the intr
+	 * lock and clears the DISCONNECT_SCHEDULED flag (using PRESERVE_FLAG_
+	 * FIELDS), and the disconnect is lost.  This is particularly bad when
+	 * the new disconnect was for UNCONFIGURING, since the unconfigure hangs
+	 * forever.
+	 * Fix is that free command queue sets acr state and acr flags if there
+	 * is a change under the lock
+	 * note free command queue writes to this state it clears it
+	 * before releasing the lock, different drivers call the free command
+	 * queue different times so dont initialize above
+	 */
+	if (vscsi->phyp_acr_state != 0)	{
+		/*
+		 * set any bits in flags that may have been cleared by
+		 * a call to free command queue in switch statement
+		 * or reset queue
+		 */
+		vscsi->flags |= vscsi->phyp_acr_flags;
+		ibmvscsis_post_disconnect(vscsi, vscsi->phyp_acr_state, 0);
+		vscsi->phyp_acr_state = 0;
+		vscsi->phyp_acr_flags = 0;
+
+		pr_debug("adapter_idle: flags 0x%x, state 0x%hx, acr_flags 0x%x, acr_state 0x%hx\n",
+			 vscsi->flags, vscsi->state, vscsi->phyp_acr_flags,
+			 vscsi->phyp_acr_state);
+	}
+
+	pr_debug("Leaving adapter_idle: flags 0x%x, state 0x%hx, new_state 0x%x\n",
+		 vscsi->flags, vscsi->state, vscsi->new_state);
+}
+
+/**
+ * ibmvscsis_copy_crq_packet() - Copy CRQ Packet
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Pointer to command element to use to process the request
+ * @crq:	Pointer to CRQ entry containing the request
+ *
+ * Copy the srp information unit from the hosted
+ * partition using remote dma
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, interrupt lock held
+ */
+static long ibmvscsis_copy_crq_packet(struct scsi_info *vscsi,
+				      struct ibmvscsis_cmd *cmd,
+				      struct viosrp_crq *crq)
+{
+	struct iu_entry *iue = cmd->iue;
+	long rc = 0;
+	u16 len;
+
+	len = be16_to_cpu(crq->IU_length);
+	if ((len > SRP_MAX_IU_LEN) || (len == 0)) {
+		dev_err(&vscsi->dev, "copy_crq: Invalid len %d passed", len);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		return SRP_VIOLATION;
+	}
+
+	rc = h_copy_rdma(len, vscsi->dds.window[REMOTE].liobn,
+			 be64_to_cpu(crq->IU_data_ptr),
+			 vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma);
+
+	switch (rc) {
+	case H_SUCCESS:
+		cmd->init_time = mftb();
+		iue->remote_token = crq->IU_data_ptr;
+		iue->iu_len = len;
+		pr_debug("copy_crq: ioba 0x%llx, init_time 0x%llx\n",
+			 be64_to_cpu(crq->IU_data_ptr), cmd->init_time);
+		break;
+	case H_PERMISSION:
+		if (connection_broken(vscsi))
+			ibmvscsis_post_disconnect(vscsi,
+						  ERR_DISCONNECT_RECONNECT,
+						  (RESPONSE_Q_DOWN |
+						   CLIENT_FAILED));
+		else
+			ibmvscsis_post_disconnect(vscsi,
+						  ERR_DISCONNECT_RECONNECT, 0);
+
+		dev_err(&vscsi->dev, "copy_crq: h_copy_rdma failed, rc %ld\n",
+			rc);
+		break;
+	case H_DEST_PARM:
+	case H_SOURCE_PARM:
+	default:
+		dev_err(&vscsi->dev, "copy_crq: h_copy_rdma failed, rc %ld\n",
+			rc);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		break;
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_adapter_info - Service an Adapter Info MAnagement Data gram
+ * @vscsi:	Pointer to our adapter structure
+ * @iue:	Information Unit containing the Adapter Info MAD request
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt adapter lock is held
+ */
+static long ibmvscsis_adapter_info(struct scsi_info *vscsi,
+				   struct iu_entry *iue)
+{
+	struct viosrp_adapter_info *mad = &vio_iu(iue)->mad.adapter_info;
+	struct mad_adapter_info_data *info;
+	uint flag_bits = 0;
+	dma_addr_t token;
+	long rc;
+
+	mad->common.status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
+
+	if (be16_to_cpu(mad->common.length) > sizeof(*info)) {
+		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		return 0;
+	}
+
+	info = dma_alloc_coherent(&vscsi->dma_dev->dev, sizeof(*info), &token,
+				  GFP_ATOMIC);
+	if (!info) {
+		dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n",
+			iue->target);
+		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		return 0;
+	}
+
+	/* Get remote info */
+	rc = h_copy_rdma(be16_to_cpu(mad->common.length),
+			 vscsi->dds.window[REMOTE].liobn,
+			 be64_to_cpu(mad->buffer),
+			 vscsi->dds.window[LOCAL].liobn, token);
+
+	if (rc != H_SUCCESS) {
+		if (rc == H_PERMISSION) {
+			if (connection_broken(vscsi))
+				flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
+		}
+		pr_warn("adapter_info: h_copy_rdma from client failed, rc %ld\n",
+			rc);
+		pr_debug("adapter_info: ioba 0x%llx, flags 0x%x, flag_bits 0x%x\n",
+			 be64_to_cpu(mad->buffer), vscsi->flags, flag_bits);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+					  flag_bits);
+		goto free_dma;
+	}
+
+	/*
+	 * Copy client info, but ignore partition number, which we
+	 * already got from phyp - unless we failed to get it from
+	 * phyp (e.g. if we're running on a p5 system).
+	 */
+	if (vscsi->client_data.partition_number == 0)
+		vscsi->client_data.partition_number =
+			be32_to_cpu(info->partition_number);
+	strncpy(vscsi->client_data.srp_version, info->srp_version,
+		sizeof(vscsi->client_data.srp_version));
+	strncpy(vscsi->client_data.partition_name, info->partition_name,
+		sizeof(vscsi->client_data.partition_name));
+	vscsi->client_data.mad_version = be32_to_cpu(info->mad_version);
+	vscsi->client_data.os_type = be32_to_cpu(info->os_type);
+
+	/* Copy our info */
+	strncpy(info->srp_version, SRP_VERSION,
+		sizeof(info->srp_version));
+	strncpy(info->partition_name, vscsi->dds.partition_name,
+		sizeof(info->partition_name));
+	info->partition_number = cpu_to_be32(vscsi->dds.partition_num);
+	info->mad_version = cpu_to_be32(MAD_VERSION_1);
+	info->os_type = cpu_to_be32(LINUX);
+	memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu));
+	info->port_max_txu[0] = cpu_to_be32(MAX_TXU);
+
+	dma_wmb();
+	rc = h_copy_rdma(sizeof(*info), vscsi->dds.window[LOCAL].liobn,
+			 token, vscsi->dds.window[REMOTE].liobn,
+			 be64_to_cpu(mad->buffer));
+	switch (rc) {
+	case H_SUCCESS:
+		break;
+
+	case H_SOURCE_PARM:
+	case H_DEST_PARM:
+	case H_PERMISSION:
+		if (connection_broken(vscsi))
+			flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
+	default:
+		dev_err(&vscsi->dev, "adapter_info: h_copy_rdma to client failed, rc %ld\n",
+			rc);
+		ibmvscsis_post_disconnect(vscsi,
+					  ERR_DISCONNECT_RECONNECT,
+					  flag_bits);
+		break;
+	}
+
+free_dma:
+	dma_free_coherent(&vscsi->dma_dev->dev, sizeof(*info), info, token);
+	pr_debug("Leaving adapter_info, rc %ld\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_cap_mad() - Service a Capabilities MAnagement Data gram
+ * @vscsi:	Pointer to our adapter structure
+ * @iue:	Information Unit containing the Capabilities MAD request
+ *
+ * NOTE: if you return an error from this routine you must be
+ * disconnecting or you will cause a hang
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt called with adapter lock held
+ */
+static int ibmvscsis_cap_mad(struct scsi_info *vscsi, struct iu_entry *iue)
+{
+	struct viosrp_capabilities *mad = &vio_iu(iue)->mad.capabilities;
+	struct capabilities *cap;
+	struct mad_capability_common *common;
+	dma_addr_t token;
+	u16 olen, len, status, min_len, cap_len;
+	u32 flag;
+	uint flag_bits = 0;
+	long rc = 0;
+
+	olen = be16_to_cpu(mad->common.length);
+	/*
+	 * struct capabilities hardcodes a couple capabilities after the
+	 * header, but the capabilities can actually be in any order.
+	 */
+	min_len = offsetof(struct capabilities, migration);
+	if ((olen < min_len) || (olen > PAGE_SIZE)) {
+		pr_warn("cap_mad: invalid len %d\n", olen);
+		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		return 0;
+	}
+
+	cap = dma_alloc_coherent(&vscsi->dma_dev->dev, olen, &token,
+				 GFP_ATOMIC);
+	if (!cap) {
+		dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n",
+			iue->target);
+		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		return 0;
+	}
+	rc = h_copy_rdma(olen, vscsi->dds.window[REMOTE].liobn,
+			 be64_to_cpu(mad->buffer),
+			 vscsi->dds.window[LOCAL].liobn, token);
+	if (rc == H_SUCCESS) {
+		strncpy(cap->name, dev_name(&vscsi->dma_dev->dev),
+			SRP_MAX_LOC_LEN);
+
+		len = olen - min_len;
+		status = VIOSRP_MAD_SUCCESS;
+		common = (struct mad_capability_common *)&cap->migration;
+
+		while ((len > 0) && (status == VIOSRP_MAD_SUCCESS) && !rc) {
+			pr_debug("cap_mad: len left %hd, cap type %d, cap len %hd\n",
+				 len, be32_to_cpu(common->cap_type),
+				 be16_to_cpu(common->length));
+
+			cap_len = be16_to_cpu(common->length);
+			if (cap_len > len) {
+				dev_err(&vscsi->dev, "cap_mad: cap len mismatch with total len\n");
+				status = VIOSRP_MAD_FAILED;
+				break;
+			}
+
+			if (cap_len == 0) {
+				dev_err(&vscsi->dev, "cap_mad: cap len is 0\n");
+				status = VIOSRP_MAD_FAILED;
+				break;
+			}
+
+			switch (common->cap_type) {
+			default:
+				pr_debug("cap_mad: unsupported capability\n");
+				common->server_support = 0;
+				flag = cpu_to_be32((u32)CAP_LIST_SUPPORTED);
+				cap->flags &= ~flag;
+				break;
+			}
+
+			len = len - cap_len;
+			common = (struct mad_capability_common *)
+				((char *)common + cap_len);
+		}
+
+		mad->common.status = cpu_to_be16(status);
+
+		dma_wmb();
+		rc = h_copy_rdma(olen, vscsi->dds.window[LOCAL].liobn, token,
+				 vscsi->dds.window[REMOTE].liobn,
+				 be64_to_cpu(mad->buffer));
+
+		if (rc != H_SUCCESS) {
+			pr_debug("cap_mad: failed to copy to client, rc %ld\n",
+				 rc);
+
+			if (rc == H_PERMISSION) {
+				if (connection_broken(vscsi))
+					flag_bits = (RESPONSE_Q_DOWN |
+						     CLIENT_FAILED);
+			}
+
+			pr_warn("cap_mad: error copying data to client, rc %ld\n",
+				rc);
+			ibmvscsis_post_disconnect(vscsi,
+						  ERR_DISCONNECT_RECONNECT,
+						  flag_bits);
+		}
+	}
+
+	dma_free_coherent(&vscsi->dma_dev->dev, olen, cap, token);
+
+	pr_debug("Leaving cap_mad, rc %ld, client_cap 0x%x\n",
+		 rc, vscsi->client_cap);
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_process_mad() - Service a MAnagement Data gram
+ * @vscsi:	Pointer to our adapter structure
+ * @iue:	Information Unit containing the MAD request
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_process_mad(struct scsi_info *vscsi, struct iu_entry *iue)
+{
+	struct mad_common *mad = (struct mad_common *)&vio_iu(iue)->mad;
+	struct viosrp_empty_iu *empty;
+	long rc = ADAPT_SUCCESS;
+
+	switch (be32_to_cpu(mad->type)) {
+	case VIOSRP_EMPTY_IU_TYPE:
+		empty = &vio_iu(iue)->mad.empty_iu;
+		vscsi->empty_iu_id = be64_to_cpu(empty->buffer);
+		vscsi->empty_iu_tag = be64_to_cpu(empty->common.tag);
+		mad->status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
+		break;
+	case VIOSRP_ADAPTER_INFO_TYPE:
+		rc = ibmvscsis_adapter_info(vscsi, iue);
+		break;
+	case VIOSRP_CAPABILITIES_TYPE:
+		rc = ibmvscsis_cap_mad(vscsi, iue);
+		break;
+	case VIOSRP_ENABLE_FAST_FAIL:
+		if (vscsi->state == CONNECTED) {
+			vscsi->fast_fail = true;
+			mad->status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
+		} else {
+			pr_warn("fast fail mad sent after login\n");
+			mad->status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		}
+		break;
+	default:
+		mad->status = cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
+		break;
+	}
+
+	return rc;
+}
+
+/**
+ * srp_snd_msg_failed() - Handle an error when sending a response
+ * @vscsi:	Pointer to our adapter structure
+ * @rc:		The return code from the h_send_crq command
+ *
+ * Must be called with interrupt lock held.
+ */
+static void srp_snd_msg_failed(struct scsi_info *vscsi, long rc)
+{
+	ktime_t kt;
+
+	if (rc != H_DROPPED) {
+		ibmvscsis_free_cmd_qs(vscsi);
+
+		if (rc == H_CLOSED)
+			vscsi->flags |= CLIENT_FAILED;
+
+		/* don't flag the same problem multiple times */
+		if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
+			vscsi->flags |= RESPONSE_Q_DOWN;
+			if (!(vscsi->state & (ERR_DISCONNECT |
+					      ERR_DISCONNECT_RECONNECT |
+					      ERR_DISCONNECTED | UNDEFINED))) {
+				dev_err(&vscsi->dev, "snd_msg_failed: setting RESPONSE_Q_DOWN, state 0x%hx, flags 0x%x, rc %ld\n",
+					vscsi->state, vscsi->flags, rc);
+			}
+			ibmvscsis_post_disconnect(vscsi,
+						  ERR_DISCONNECT_RECONNECT, 0);
+		}
+		return;
+	}
+
+	/*
+	 * The response queue is full.
+	 * If the server is processing SRP requests, i.e.
+	 * the client has successfully done an
+	 * SRP_LOGIN, then it will wait forever for room in
+	 * the queue.  However if the system admin
+	 * is attempting to unconfigure the server then one
+	 * or more children will be in a state where
+	 * they are being removed. So if there is even one
+	 * child being removed then the driver assumes
+	 * the system admin is attempting to break the
+	 * connection with the client and MAX_TIMER_POPS
+	 * is honored.
+	 */
+	if ((vscsi->rsp_q_timer.timer_pops < MAX_TIMER_POPS) ||
+	    (vscsi->state == SRP_PROCESSING)) {
+		pr_debug("snd_msg_failed: response queue full, flags 0x%x, timer started %d, pops %d\n",
+			 vscsi->flags, (int)vscsi->rsp_q_timer.started,
+			 vscsi->rsp_q_timer.timer_pops);
+
+		/*
+		 * Check if the timer is running; if it
+		 * is not then start it up.
+		 */
+		if (!vscsi->rsp_q_timer.started) {
+			if (vscsi->rsp_q_timer.timer_pops <
+			    MAX_TIMER_POPS) {
+				kt = ktime_set(0, WAIT_NANO_SECONDS);
+			} else {
+				/*
+				 * slide the timeslice if the maximum
+				 * timer pops have already happened
+				 */
+				kt = ktime_set(WAIT_SECONDS, 0);
+			}
+
+			vscsi->rsp_q_timer.started = true;
+			hrtimer_start(&vscsi->rsp_q_timer.timer, kt,
+				      HRTIMER_MODE_REL);
+		}
+	} else {
+		/*
+		 * TBD: Do we need to worry about this? Need to get
+		 *      remove working.
+		 */
+		/*
+		 * waited a long time and it appears the system admin
+		 * is bring this driver down
+		 */
+		vscsi->flags |= RESPONSE_Q_DOWN;
+		ibmvscsis_free_cmd_qs(vscsi);
+		/*
+		 * if the driver is already attempting to disconnect
+		 * from the client and has already logged an error
+		 * trace this event but don't put it in the error log
+		 */
+		if (!(vscsi->state & (ERR_DISCONNECT |
+				      ERR_DISCONNECT_RECONNECT |
+				      ERR_DISCONNECTED | UNDEFINED))) {
+			dev_err(&vscsi->dev, "client crq full too long\n");
+			ibmvscsis_post_disconnect(vscsi,
+						  ERR_DISCONNECT_RECONNECT,
+						  0);
+		}
+	}
+}
+
+/**
+ * ibmvscsis_send_messages() - Send a Response
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Send a response, first checking the waiting queue. Responses are
+ * sent in order they are received. If the response cannot be sent,
+ * because the client queue is full, it stays on the waiting queue.
+ *
+ * PRECONDITION:
+ *	Called with interrupt lock held
+ */
+static void ibmvscsis_send_messages(struct scsi_info *vscsi)
+{
+	u64 msg_hi = 0;
+	/* note do not attmempt to access the IU_data_ptr with this pointer
+	 * it is not valid
+	 */
+	struct viosrp_crq *crq = (struct viosrp_crq *)&msg_hi;
+	struct ibmvscsis_cmd *cmd, *nxt;
+	struct iu_entry *iue;
+	long rc = ADAPT_SUCCESS;
+
+	if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
+		list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp, list) {
+			iue = cmd->iue;
+
+			crq->valid = VALID_CMD_RESP_EL;
+			crq->format = cmd->rsp.format;
+
+			if (cmd->flags & CMD_FAST_FAIL)
+				crq->status = VIOSRP_ADAPTER_FAIL;
+
+			crq->IU_length = cpu_to_be16(cmd->rsp.len);
+
+			rc = h_send_crq(vscsi->dma_dev->unit_address,
+					be64_to_cpu(msg_hi),
+					be64_to_cpu(cmd->rsp.tag));
+
+			pr_debug("send_messages: cmd %p, tag 0x%llx, rc %ld\n",
+				 cmd, be64_to_cpu(cmd->rsp.tag), rc);
+
+			/* if all ok free up the command element resources */
+			if (rc == H_SUCCESS) {
+				/* some movement has occurred */
+				vscsi->rsp_q_timer.timer_pops = 0;
+				list_del(&cmd->list);
+
+				ibmvscsis_free_cmd_resources(vscsi, cmd);
+			} else {
+				srp_snd_msg_failed(vscsi, rc);
+				break;
+			}
+		}
+
+		if (!rc) {
+			/*
+			 * The timer could pop with the queue empty.  If
+			 * this happens, rc will always indicate a
+			 * success; clear the pop count.
+			 */
+			vscsi->rsp_q_timer.timer_pops = 0;
+		}
+	} else {
+		ibmvscsis_free_cmd_qs(vscsi);
+	}
+}
+
+/* Called with intr lock held */
+static void ibmvscsis_send_mad_resp(struct scsi_info *vscsi,
+				    struct ibmvscsis_cmd *cmd,
+				    struct viosrp_crq *crq)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct mad_common *mad = (struct mad_common *)&vio_iu(iue)->mad;
+	uint flag_bits = 0;
+	long rc;
+
+	dma_wmb();
+	rc = h_copy_rdma(sizeof(struct mad_common),
+			 vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma,
+			 vscsi->dds.window[REMOTE].liobn,
+			 be64_to_cpu(crq->IU_data_ptr));
+	if (!rc) {
+		cmd->rsp.format = VIOSRP_MAD_FORMAT;
+		cmd->rsp.len = sizeof(struct mad_common);
+		cmd->rsp.tag = mad->tag;
+		list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+		ibmvscsis_send_messages(vscsi);
+	} else {
+		pr_debug("Error sending mad response, rc %ld\n", rc);
+		if (rc == H_PERMISSION) {
+			if (connection_broken(vscsi))
+				flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
+		}
+		dev_err(&vscsi->dev, "mad: failed to copy to client, rc %ld\n",
+			rc);
+
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+					  flag_bits);
+	}
+}
+
+/**
+ * ibmvscsis_mad() - Service a MAnagement Data gram.
+ * @vscsi:	Pointer to our adapter structure
+ * @crq:	Pointer to the CRQ entry containing the MAD request
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, called with adapter lock held
+ */
+static long ibmvscsis_mad(struct scsi_info *vscsi, struct viosrp_crq *crq)
+{
+	struct iu_entry *iue;
+	struct ibmvscsis_cmd *cmd;
+	struct mad_common *mad;
+	long rc = ADAPT_SUCCESS;
+
+	switch (vscsi->state) {
+		/*
+		 * We have not exchanged Init Msgs yet, so this MAD was sent
+		 * before the last Transport Event; client will not be
+		 * expecting a response.
+		 */
+	case WAIT_CONNECTION:
+		pr_debug("mad: in Wait Connection state, ignoring MAD, flags %d\n",
+			 vscsi->flags);
+		return ADAPT_SUCCESS;
+
+	case SRP_PROCESSING:
+	case CONNECTED:
+		break;
+
+		/*
+		 * We should never get here while we're in these states.
+		 * Just log an error and get out.
+		 */
+	case UNCONFIGURING:
+	case WAIT_IDLE:
+	case ERR_DISCONNECT:
+	case ERR_DISCONNECT_RECONNECT:
+	default:
+		dev_err(&vscsi->dev, "mad: invalid adapter state %d for mad\n",
+			vscsi->state);
+		return ADAPT_SUCCESS;
+	}
+
+	cmd = ibmvscsis_get_free_cmd(vscsi);
+	if (!cmd) {
+		dev_err(&vscsi->dev, "mad: failed to get cmd, debit %d\n",
+			vscsi->debit);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		return ERROR;
+	}
+	iue = cmd->iue;
+	cmd->type = ADAPTER_MAD;
+
+	rc = ibmvscsis_copy_crq_packet(vscsi, cmd, crq);
+	if (!rc) {
+		mad = (struct mad_common *)&vio_iu(iue)->mad;
+
+		pr_debug("mad: type %d\n", be32_to_cpu(mad->type));
+
+		rc = ibmvscsis_process_mad(vscsi, iue);
+
+		pr_debug("mad: status %hd, rc %ld\n", be16_to_cpu(mad->status),
+			 rc);
+
+		if (!rc)
+			ibmvscsis_send_mad_resp(vscsi, cmd, crq);
+	} else {
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+	}
+
+	pr_debug("Leaving mad, rc %ld\n", rc);
+	return rc;
+}
+
+/**
+ * ibmvscsis_login_rsp() - Create/copy a login response notice to the client
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Pointer to the command for the SRP Login request
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, interrupt lock held
+ */
+static long ibmvscsis_login_rsp(struct scsi_info *vscsi,
+				struct ibmvscsis_cmd *cmd)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct srp_login_rsp *rsp = &vio_iu(iue)->srp.login_rsp;
+	struct format_code *fmt;
+	uint flag_bits = 0;
+	long rc = ADAPT_SUCCESS;
+
+	memset(rsp, 0, sizeof(struct srp_login_rsp));
+
+	rsp->opcode = SRP_LOGIN_RSP;
+	rsp->req_lim_delta = cpu_to_be32(vscsi->request_limit);
+	rsp->tag = cmd->rsp.tag;
+	rsp->max_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+	rsp->max_ti_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+	fmt = (struct format_code *)&rsp->buf_fmt;
+	fmt->buffers = SUPPORTED_FORMATS;
+	vscsi->credit = 0;
+
+	cmd->rsp.len = sizeof(struct srp_login_rsp);
+
+	dma_wmb();
+	rc = h_copy_rdma(cmd->rsp.len, vscsi->dds.window[LOCAL].liobn,
+			 iue->sbuf->dma, vscsi->dds.window[REMOTE].liobn,
+			 be64_to_cpu(iue->remote_token));
+
+	switch (rc) {
+	case H_SUCCESS:
+		break;
+
+	case H_PERMISSION:
+		if (connection_broken(vscsi))
+			flag_bits = RESPONSE_Q_DOWN | CLIENT_FAILED;
+		dev_err(&vscsi->dev, "login_rsp: error copying to client, rc %ld\n",
+			rc);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+					  flag_bits);
+		break;
+	case H_SOURCE_PARM:
+	case H_DEST_PARM:
+	default:
+		dev_err(&vscsi->dev, "login_rsp: error copying to client, rc %ld\n",
+			rc);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		break;
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_srp_login_rej() - Create/copy a login rejection notice to client
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Pointer to the command for the SRP Login request
+ * @reason:	The reason the SRP Login is being rejected, per SRP protocol
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, interrupt lock held
+ */
+static long ibmvscsis_srp_login_rej(struct scsi_info *vscsi,
+				    struct ibmvscsis_cmd *cmd, u32 reason)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct srp_login_rej *rej = &vio_iu(iue)->srp.login_rej;
+	struct format_code *fmt;
+	uint flag_bits = 0;
+	long rc = ADAPT_SUCCESS;
+
+	memset(rej, 0, sizeof(*rej));
+
+	rej->opcode = SRP_LOGIN_REJ;
+	rej->reason = cpu_to_be32(reason);
+	rej->tag = cmd->rsp.tag;
+	fmt = (struct format_code *)&rej->buf_fmt;
+	fmt->buffers = SUPPORTED_FORMATS;
+
+	cmd->rsp.len = sizeof(*rej);
+
+	dma_wmb();
+	rc = h_copy_rdma(cmd->rsp.len, vscsi->dds.window[LOCAL].liobn,
+			 iue->sbuf->dma, vscsi->dds.window[REMOTE].liobn,
+			 be64_to_cpu(iue->remote_token));
+
+	switch (rc) {
+	case H_SUCCESS:
+		break;
+	case H_PERMISSION:
+		if (connection_broken(vscsi))
+			flag_bits = RESPONSE_Q_DOWN | CLIENT_FAILED;
+		dev_err(&vscsi->dev, "login_rej: error copying to client, rc %ld\n",
+			rc);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+					  flag_bits);
+		break;
+	case H_SOURCE_PARM:
+	case H_DEST_PARM:
+	default:
+		dev_err(&vscsi->dev, "login_rej: error copying to client, rc %ld\n",
+			rc);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		break;
+	}
+
+	return rc;
+}
+
+static int ibmvscsis_make_nexus(struct ibmvscsis_tport *tport)
+{
+	char *name = tport->tport_name;
+	struct ibmvscsis_nexus *nexus;
+	int rc;
+
+	if (tport->ibmv_nexus) {
+		pr_debug("tport->ibmv_nexus already exists\n");
+		return 0;
+	}
+
+	nexus = kzalloc(sizeof(*nexus), GFP_KERNEL);
+	if (!nexus) {
+		pr_err("Unable to allocate struct ibmvscsis_nexus\n");
+		return -ENOMEM;
+	}
+
+	nexus->se_sess = target_alloc_session(&tport->se_tpg, 0, 0,
+					      TARGET_PROT_NORMAL, name, nexus,
+					      NULL);
+	if (IS_ERR(nexus->se_sess)) {
+		rc = PTR_ERR(nexus->se_sess);
+		goto transport_init_fail;
+	}
+
+	tport->ibmv_nexus = nexus;
+
+	return 0;
+
+transport_init_fail:
+	kfree(nexus);
+	return rc;
+}
+
+static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport)
+{
+	struct se_session *se_sess;
+	struct ibmvscsis_nexus *nexus;
+
+	nexus = tport->ibmv_nexus;
+	if (!nexus)
+		return -ENODEV;
+
+	se_sess = nexus->se_sess;
+	if (!se_sess)
+		return -ENODEV;
+
+	/*
+	 * Release the SCSI I_T Nexus to the emulated ibmvscsis Target Port
+	 */
+	target_wait_for_sess_cmds(se_sess);
+	transport_deregister_session_configfs(se_sess);
+	transport_deregister_session(se_sess);
+	tport->ibmv_nexus = NULL;
+	kfree(nexus);
+
+	return 0;
+}
+
+/**
+ * ibmvscsis_srp_login() - Process an SRP Login Request
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Command element to use to process the SRP Login request
+ * @crq:	Pointer to CRQ entry containing the SRP Login request
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, called with interrupt lock held
+ */
+static long ibmvscsis_srp_login(struct scsi_info *vscsi,
+				struct ibmvscsis_cmd *cmd,
+				struct viosrp_crq *crq)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct srp_login_req *req = &vio_iu(iue)->srp.login_req;
+	struct port_id {
+		__be64 id_extension;
+		__be64 io_guid;
+	} *iport, *tport;
+	struct format_code *fmt;
+	u32 reason = 0x0;
+	long rc = ADAPT_SUCCESS;
+
+	iport = (struct port_id *)req->initiator_port_id;
+	tport = (struct port_id *)req->target_port_id;
+	fmt = (struct format_code *)&req->req_buf_fmt;
+	if (be32_to_cpu(req->req_it_iu_len) > SRP_MAX_IU_LEN)
+		reason = SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE;
+	else if (be32_to_cpu(req->req_it_iu_len) < 64)
+		reason = SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL;
+	else if ((be64_to_cpu(iport->id_extension) > (MAX_NUM_PORTS - 1)) ||
+		 (be64_to_cpu(tport->id_extension) > (MAX_NUM_PORTS - 1)))
+		reason = SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL;
+	else if (req->req_flags & SRP_MULTICHAN_MULTI)
+		reason = SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED;
+	else if (fmt->buffers & (~SUPPORTED_FORMATS))
+		reason = SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT;
+	else if ((fmt->buffers & SUPPORTED_FORMATS) == 0)
+		reason = SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT;
+
+	if (vscsi->state == SRP_PROCESSING)
+		reason = SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED;
+
+	rc = ibmvscsis_make_nexus(&vscsi->tport);
+	if (rc)
+		reason = SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL;
+
+	cmd->rsp.format = VIOSRP_SRP_FORMAT;
+	cmd->rsp.tag = req->tag;
+
+	pr_debug("srp_login: reason 0x%x\n", reason);
+
+	if (reason)
+		rc = ibmvscsis_srp_login_rej(vscsi, cmd, reason);
+	else
+		rc = ibmvscsis_login_rsp(vscsi, cmd);
+
+	if (!rc) {
+		if (!reason)
+			vscsi->state = SRP_PROCESSING;
+
+		list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+		ibmvscsis_send_messages(vscsi);
+	} else {
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+	}
+
+	pr_debug("Leaving srp_login, rc %ld\n", rc);
+	return rc;
+}
+
+/**
+ * ibmvscsis_srp_i_logout() - Helper Function to close I_T Nexus
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Command element to use to process the Implicit Logout request
+ * @crq:	Pointer to CRQ entry containing the Implicit Logout request
+ *
+ * Do the logic to close the I_T nexus.  This function may not
+ * behave to specification.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, interrupt lock held
+ */
+static long ibmvscsis_srp_i_logout(struct scsi_info *vscsi,
+				   struct ibmvscsis_cmd *cmd,
+				   struct viosrp_crq *crq)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct srp_i_logout *log_out = &vio_iu(iue)->srp.i_logout;
+	long rc = ADAPT_SUCCESS;
+
+	if ((vscsi->debit > 0) || !list_empty(&vscsi->schedule_q) ||
+	    !list_empty(&vscsi->waiting_rsp)) {
+		dev_err(&vscsi->dev, "i_logout: outstanding work\n");
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
+	} else {
+		cmd->rsp.format = SRP_FORMAT;
+		cmd->rsp.tag = log_out->tag;
+		cmd->rsp.len = sizeof(struct mad_common);
+		list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+		ibmvscsis_send_messages(vscsi);
+
+		ibmvscsis_post_disconnect(vscsi, WAIT_IDLE, 0);
+	}
+
+	return rc;
+}
+
+/* Called with intr lock held */
+static void ibmvscsis_srp_cmd(struct scsi_info *vscsi, struct viosrp_crq *crq)
+{
+	struct ibmvscsis_cmd *cmd;
+	struct iu_entry *iue;
+	struct srp_cmd *srp;
+	struct srp_tsk_mgmt *tsk;
+	long rc;
+
+	if (vscsi->request_limit - vscsi->debit <= 0) {
+		/* Client has exceeded request limit */
+		dev_err(&vscsi->dev, "Client exceeded the request limit (%d), debit %d\n",
+			vscsi->request_limit, vscsi->debit);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		return;
+	}
+
+	cmd = ibmvscsis_get_free_cmd(vscsi);
+	if (!cmd) {
+		dev_err(&vscsi->dev, "srp_cmd failed to get cmd, debit %d\n",
+			vscsi->debit);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		return;
+	}
+	iue = cmd->iue;
+	srp = &vio_iu(iue)->srp.cmd;
+
+	rc = ibmvscsis_copy_crq_packet(vscsi, cmd, crq);
+	if (rc) {
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+		return;
+	}
+
+	if (vscsi->state == SRP_PROCESSING) {
+		switch (srp->opcode) {
+		case SRP_LOGIN_REQ:
+			rc = ibmvscsis_srp_login(vscsi, cmd, crq);
+			break;
+
+		case SRP_TSK_MGMT:
+			tsk = &vio_iu(iue)->srp.tsk_mgmt;
+			pr_debug("tsk_mgmt tag: %llu (0x%llx)\n", tsk->tag,
+				 tsk->tag);
+			cmd->rsp.tag = tsk->tag;
+			vscsi->debit += 1;
+			cmd->type = TASK_MANAGEMENT;
+			list_add_tail(&cmd->list, &vscsi->schedule_q);
+			queue_work(vscsi->work_q, &cmd->work);
+			break;
+
+		case SRP_CMD:
+			pr_debug("srp_cmd tag: %llu (0x%llx)\n", srp->tag,
+				 srp->tag);
+			cmd->rsp.tag = srp->tag;
+			vscsi->debit += 1;
+			cmd->type = SCSI_CDB;
+			/*
+			 * We want to keep track of work waiting for
+			 * the workqueue.
+			 */
+			list_add_tail(&cmd->list, &vscsi->schedule_q);
+			queue_work(vscsi->work_q, &cmd->work);
+			break;
+
+		case SRP_I_LOGOUT:
+			rc = ibmvscsis_srp_i_logout(vscsi, cmd, crq);
+			break;
+
+		case SRP_CRED_RSP:
+		case SRP_AER_RSP:
+		default:
+			ibmvscsis_free_cmd_resources(vscsi, cmd);
+			dev_err(&vscsi->dev, "invalid srp cmd, opcode %d\n",
+				(uint)srp->opcode);
+			ibmvscsis_post_disconnect(vscsi,
+						  ERR_DISCONNECT_RECONNECT, 0);
+			break;
+		}
+	} else if (srp->opcode == SRP_LOGIN_REQ && vscsi->state == CONNECTED) {
+		rc = ibmvscsis_srp_login(vscsi, cmd, crq);
+	} else {
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+		dev_err(&vscsi->dev, "Invalid state %d to handle srp cmd\n",
+			vscsi->state);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+	}
+}
+
+/**
+ * ibmvscsis_ping_response() - Respond to a ping request
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Let the client know that the server is alive and waiting on
+ * its native I/O stack.
+ * If any type of error occurs from the call to queue a ping
+ * response then the client is either not accepting or receiving
+ * interrupts.  Disconnect with an error.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, interrupt lock held
+ */
+static long ibmvscsis_ping_response(struct scsi_info *vscsi)
+{
+	struct viosrp_crq *crq;
+	u64 buffer[2] = { 0, 0 };
+	long rc;
+
+	crq = (struct viosrp_crq *)&buffer;
+	crq->valid = VALID_CMD_RESP_EL;
+	crq->format = (u8)MESSAGE_IN_CRQ;
+	crq->status = PING_RESPONSE;
+
+	rc = h_send_crq(vscsi->dds.unit_id, cpu_to_be64(buffer[MSG_HI]),
+			cpu_to_be64(buffer[MSG_LOW]));
+
+	switch (rc) {
+	case H_SUCCESS:
+		break;
+	case H_CLOSED:
+		vscsi->flags |= CLIENT_FAILED;
+	case H_DROPPED:
+		vscsi->flags |= RESPONSE_Q_DOWN;
+	case H_REMOTE_PARM:
+		dev_err(&vscsi->dev, "ping_response: h_send_crq failed, rc %ld\n",
+			rc);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		break;
+	default:
+		dev_err(&vscsi->dev, "ping_response: h_send_crq returned unknown rc %ld\n",
+			rc);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
+		break;
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_parse_command() - Parse an element taken from the cmd rsp queue.
+ * @vscsi:	Pointer to our adapter structure
+ * @crq:	Pointer to CRQ element containing the SRP request
+ *
+ * This function will return success if the command queue element is valid
+ * and the srp iu or MAD request it pointed to was also valid.  That does
+ * not mean that an error was not returned to the client.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Interrupt, intr lock held
+ */
+static long ibmvscsis_parse_command(struct scsi_info *vscsi,
+				    struct viosrp_crq *crq)
+{
+	long rc = ADAPT_SUCCESS;
+
+	switch (crq->valid) {
+	case VALID_CMD_RESP_EL:
+		switch (crq->format) {
+		case OS400_FORMAT:
+		case AIX_FORMAT:
+		case LINUX_FORMAT:
+		case MAD_FORMAT:
+			if (vscsi->flags & PROCESSING_MAD) {
+				rc = ERROR;
+				dev_err(&vscsi->dev, "parse_command: already processing mad\n");
+				ibmvscsis_post_disconnect(vscsi,
+						       ERR_DISCONNECT_RECONNECT,
+						       0);
+			} else {
+				vscsi->flags |= PROCESSING_MAD;
+				rc = ibmvscsis_mad(vscsi, crq);
+			}
+			break;
+
+		case SRP_FORMAT:
+			ibmvscsis_srp_cmd(vscsi, crq);
+			break;
+
+		case MESSAGE_IN_CRQ:
+			if (crq->status == PING)
+				ibmvscsis_ping_response(vscsi);
+			break;
+
+		default:
+			dev_err(&vscsi->dev, "parse_command: invalid format %d\n",
+				(uint)crq->format);
+			ibmvscsis_post_disconnect(vscsi,
+						  ERR_DISCONNECT_RECONNECT, 0);
+			break;
+		}
+		break;
+
+	case VALID_TRANS_EVENT:
+		rc = ibmvscsis_trans_event(vscsi, crq);
+		break;
+
+	case VALID_INIT_MSG:
+		rc = ibmvscsis_init_msg(vscsi, crq);
+		break;
+
+	default:
+		dev_err(&vscsi->dev, "parse_command: invalid valid field %d\n",
+			(uint)crq->valid);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		break;
+	}
+
+	/*
+	 * Return only what the interrupt handler cares
+	 * about. Most errors we keep right on trucking.
+	 */
+	rc = vscsi->flags & SCHEDULE_DISCONNECT;
+
+	return rc;
+}
+
+static int read_dma_window(struct scsi_info *vscsi)
+{
+	struct vio_dev *vdev = vscsi->dma_dev;
+	const __be32 *dma_window;
+	const __be32 *prop;
+
+	/* TODO Using of_parse_dma_window would be better, but it doesn't give
+	 * a way to read multiple windows without already knowing the size of
+	 * a window or the number of windows.
+	 */
+	dma_window = (const __be32 *)vio_get_attribute(vdev,
+						       "ibm,my-dma-window",
+						       NULL);
+	if (!dma_window) {
+		pr_err("Couldn't find ibm,my-dma-window property\n");
+		return -1;
+	}
+
+	vscsi->dds.window[LOCAL].liobn = be32_to_cpu(*dma_window);
+	dma_window++;
+
+	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
+						 NULL);
+	if (!prop) {
+		pr_warn("Couldn't find ibm,#dma-address-cells property\n");
+		dma_window++;
+	} else {
+		dma_window += be32_to_cpu(*prop);
+	}
+
+	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
+						 NULL);
+	if (!prop) {
+		pr_warn("Couldn't find ibm,#dma-size-cells property\n");
+		dma_window++;
+	} else {
+		dma_window += be32_to_cpu(*prop);
+	}
+
+	/* dma_window should point to the second window now */
+	vscsi->dds.window[REMOTE].liobn = be32_to_cpu(*dma_window);
+
+	return 0;
+}
+
+static struct ibmvscsis_tport *ibmvscsis_lookup_port(const char *name)
+{
+	struct ibmvscsis_tport *tport = NULL;
+	struct vio_dev *vdev;
+	struct scsi_info *vscsi;
+
+	spin_lock_bh(&ibmvscsis_dev_lock);
+	list_for_each_entry(vscsi, &ibmvscsis_dev_list, list) {
+		vdev = vscsi->dma_dev;
+		if (!strcmp(dev_name(&vdev->dev), name)) {
+			tport = &vscsi->tport;
+			break;
+		}
+	}
+	spin_unlock_bh(&ibmvscsis_dev_lock);
+
+	return tport;
+}
+
+/**
+ * ibmvscsis_parse_cmd() - Parse SRP Command
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Pointer to command element with SRP command
+ *
+ * Parse the srp command; if it is valid then submit it to tcm.
+ * Note: The return code does not reflect the status of the SCSI CDB.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process level
+ */
+static void ibmvscsis_parse_cmd(struct scsi_info *vscsi,
+				struct ibmvscsis_cmd *cmd)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
+	struct ibmvscsis_nexus *nexus;
+	u64 data_len = 0;
+	enum dma_data_direction dir;
+	int attr = 0;
+	int rc = 0;
+
+	nexus = vscsi->tport.ibmv_nexus;
+	/*
+	 * additional length in bytes.  Note that the SRP spec says that
+	 * additional length is in 4-byte words, but technically the
+	 * additional length field is only the upper 6 bits of the byte.
+	 * The lower 2 bits are reserved.  If the lower 2 bits are 0 (as
+	 * all reserved fields should be), then interpreting the byte as
+	 * an int will yield the length in bytes.
+	 */
+	if (srp->add_cdb_len & 0x03) {
+		dev_err(&vscsi->dev, "parse_cmd: reserved bits set in IU\n");
+		spin_lock_bh(&vscsi->intr_lock);
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+		spin_unlock_bh(&vscsi->intr_lock);
+		return;
+	}
+
+	if (srp_get_desc_table(srp, &dir, &data_len)) {
+		dev_err(&vscsi->dev, "0x%llx: parsing SRP descriptor table failed.\n",
+			srp->tag);
+		goto fail;
+	}
+
+	cmd->rsp.sol_not = srp->sol_not;
+
+	switch (srp->task_attr) {
+	case SRP_SIMPLE_TASK:
+		attr = TCM_SIMPLE_TAG;
+		break;
+	case SRP_ORDERED_TASK:
+		attr = TCM_ORDERED_TAG;
+		break;
+	case SRP_HEAD_TASK:
+		attr = TCM_HEAD_TAG;
+		break;
+	case SRP_ACA_TASK:
+		attr = TCM_ACA_TAG;
+		break;
+	default:
+		dev_err(&vscsi->dev, "Invalid task attribute %d\n",
+			srp->task_attr);
+		goto fail;
+	}
+
+	cmd->se_cmd.tag = be64_to_cpu(srp->tag);
+
+	spin_lock_bh(&vscsi->intr_lock);
+	list_add_tail(&cmd->list, &vscsi->active_q);
+	spin_unlock_bh(&vscsi->intr_lock);
+
+	srp->lun.scsi_lun[0] &= 0x3f;
+
+	rc = target_submit_cmd(&cmd->se_cmd, nexus->se_sess, srp->cdb,
+			       cmd->sense_buf, scsilun_to_int(&srp->lun),
+			       data_len, attr, dir, 0);
+	if (rc) {
+		dev_err(&vscsi->dev, "target_submit_cmd failed, rc %d\n", rc);
+		spin_lock_bh(&vscsi->intr_lock);
+		list_del(&cmd->list);
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+		spin_unlock_bh(&vscsi->intr_lock);
+		goto fail;
+	}
+	return;
+
+fail:
+	spin_lock_bh(&vscsi->intr_lock);
+	ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+	spin_unlock_bh(&vscsi->intr_lock);
+}
+
+/**
+ * ibmvscsis_parse_task() - Parse SRP Task Management Request
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Pointer to command element with SRP task management request
+ *
+ * Parse the srp task management request; if it is valid then submit it to tcm.
+ * Note: The return code does not reflect the status of the task management
+ * request.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Processor level
+ */
+static void ibmvscsis_parse_task(struct scsi_info *vscsi,
+				 struct ibmvscsis_cmd *cmd)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt;
+	int tcm_type;
+	u64 tag_to_abort = 0;
+	int rc = 0;
+	struct ibmvscsis_nexus *nexus;
+
+	nexus = vscsi->tport.ibmv_nexus;
+
+	cmd->rsp.sol_not = srp_tsk->sol_not;
+
+	switch (srp_tsk->tsk_mgmt_func) {
+	case SRP_TSK_ABORT_TASK:
+		tcm_type = TMR_ABORT_TASK;
+		tag_to_abort = be64_to_cpu(srp_tsk->task_tag);
+		break;
+	case SRP_TSK_ABORT_TASK_SET:
+		tcm_type = TMR_ABORT_TASK_SET;
+		break;
+	case SRP_TSK_CLEAR_TASK_SET:
+		tcm_type = TMR_CLEAR_TASK_SET;
+		break;
+	case SRP_TSK_LUN_RESET:
+		tcm_type = TMR_LUN_RESET;
+		break;
+	case SRP_TSK_CLEAR_ACA:
+		tcm_type = TMR_CLEAR_ACA;
+		break;
+	default:
+		dev_err(&vscsi->dev, "unknown task mgmt func %d\n",
+			srp_tsk->tsk_mgmt_func);
+		cmd->se_cmd.se_tmr_req->response =
+			TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
+		rc = -1;
+		break;
+	}
+
+	if (!rc) {
+		cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag);
+
+		spin_lock_bh(&vscsi->intr_lock);
+		list_add_tail(&cmd->list, &vscsi->active_q);
+		spin_unlock_bh(&vscsi->intr_lock);
+
+		srp_tsk->lun.scsi_lun[0] &= 0x3f;
+
+		pr_debug("calling submit_tmr, func %d\n",
+			 srp_tsk->tsk_mgmt_func);
+		rc = target_submit_tmr(&cmd->se_cmd, nexus->se_sess, NULL,
+				       scsilun_to_int(&srp_tsk->lun), srp_tsk,
+				       tcm_type, GFP_KERNEL, tag_to_abort, 0);
+		if (rc) {
+			dev_err(&vscsi->dev, "target_submit_tmr failed, rc %d\n",
+				rc);
+			spin_lock_bh(&vscsi->intr_lock);
+			list_del(&cmd->list);
+			spin_unlock_bh(&vscsi->intr_lock);
+			cmd->se_cmd.se_tmr_req->response =
+				TMR_FUNCTION_REJECTED;
+		}
+	}
+
+	if (rc)
+		transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0);
+}
+
+static void ibmvscsis_scheduler(struct work_struct *work)
+{
+	struct ibmvscsis_cmd *cmd = container_of(work, struct ibmvscsis_cmd,
+						 work);
+	struct scsi_info *vscsi = cmd->adapter;
+
+	spin_lock_bh(&vscsi->intr_lock);
+
+	/* Remove from schedule_q */
+	list_del(&cmd->list);
+
+	/* Don't submit cmd if we're disconnecting */
+	if (vscsi->flags & (SCHEDULE_DISCONNECT | DISCONNECT_SCHEDULED)) {
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+
+		/* ibmvscsis_disconnect might be waiting for us */
+		if (list_empty(&vscsi->active_q) &&
+		    list_empty(&vscsi->schedule_q) &&
+		    (vscsi->flags & WAIT_FOR_IDLE)) {
+			vscsi->flags &= ~WAIT_FOR_IDLE;
+			complete(&vscsi->wait_idle);
+		}
+
+		spin_unlock_bh(&vscsi->intr_lock);
+		return;
+	}
+
+	spin_unlock_bh(&vscsi->intr_lock);
+
+	switch (cmd->type) {
+	case SCSI_CDB:
+		ibmvscsis_parse_cmd(vscsi, cmd);
+		break;
+	case TASK_MANAGEMENT:
+		ibmvscsis_parse_task(vscsi, cmd);
+		break;
+	default:
+		dev_err(&vscsi->dev, "scheduler, invalid cmd type %d\n",
+			cmd->type);
+		spin_lock_bh(&vscsi->intr_lock);
+		ibmvscsis_free_cmd_resources(vscsi, cmd);
+		spin_unlock_bh(&vscsi->intr_lock);
+		break;
+	}
+}
+
+static int ibmvscsis_alloc_cmds(struct scsi_info *vscsi, int num)
+{
+	struct ibmvscsis_cmd *cmd;
+	int i;
+
+	INIT_LIST_HEAD(&vscsi->free_cmd);
+	vscsi->cmd_pool = kcalloc(num, sizeof(struct ibmvscsis_cmd),
+				  GFP_KERNEL);
+	if (!vscsi->cmd_pool)
+		return -ENOMEM;
+
+	for (i = 0, cmd = (struct ibmvscsis_cmd *)vscsi->cmd_pool; i < num;
+	     i++, cmd++) {
+		cmd->adapter = vscsi;
+		INIT_WORK(&cmd->work, ibmvscsis_scheduler);
+		list_add_tail(&cmd->list, &vscsi->free_cmd);
+	}
+
+	return 0;
+}
+
+static void ibmvscsis_free_cmds(struct scsi_info *vscsi)
+{
+	kfree(vscsi->cmd_pool);
+	vscsi->cmd_pool = NULL;
+	INIT_LIST_HEAD(&vscsi->free_cmd);
+}
+
+/**
+ * ibmvscsis_service_wait_q() - Service Waiting Queue
+ * @timer:	Pointer to timer which has expired
+ *
+ * This routine is called when the timer pops to service the waiting
+ * queue. Elements on the queue have completed, their responses have been
+ * copied to the client, but the client's response queue was full so
+ * the queue message could not be sent. The routine grabs the proper locks
+ * and calls send messages.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	called at interrupt level
+ */
+static enum hrtimer_restart ibmvscsis_service_wait_q(struct hrtimer *timer)
+{
+	struct timer_cb *p_timer = container_of(timer, struct timer_cb, timer);
+	struct scsi_info *vscsi = container_of(p_timer, struct scsi_info,
+					       rsp_q_timer);
+
+	spin_lock_bh(&vscsi->intr_lock);
+	p_timer->timer_pops += 1;
+	p_timer->started = false;
+	ibmvscsis_send_messages(vscsi);
+	spin_unlock_bh(&vscsi->intr_lock);
+
+	return HRTIMER_NORESTART;
+}
+
+static long ibmvscsis_alloctimer(struct scsi_info *vscsi)
+{
+	struct timer_cb *p_timer;
+
+	p_timer = &vscsi->rsp_q_timer;
+	hrtimer_init(&p_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+	p_timer->timer.function = ibmvscsis_service_wait_q;
+	p_timer->started = false;
+	p_timer->timer_pops = 0;
+
+	return ADAPT_SUCCESS;
+}
+
+static void ibmvscsis_freetimer(struct scsi_info *vscsi)
+{
+	struct timer_cb *p_timer;
+
+	p_timer = &vscsi->rsp_q_timer;
+
+	(void)hrtimer_cancel(&p_timer->timer);
+
+	p_timer->started = false;
+	p_timer->timer_pops = 0;
+}
+
+static irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
+{
+	struct scsi_info *vscsi = data;
+
+	vio_disable_interrupts(vscsi->dma_dev);
+	tasklet_schedule(&vscsi->work_task);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ibmvscsis_enable_change_state() - Set new state based on enabled status
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * This function determines our new state now that we are enabled.  This
+ * may involve sending an Init Complete message to the client.
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_enable_change_state(struct scsi_info *vscsi)
+{
+	int bytes;
+	long rc = ADAPT_SUCCESS;
+
+	bytes = vscsi->cmd_q.size * PAGE_SIZE;
+	rc = h_reg_crq(vscsi->dds.unit_id, vscsi->cmd_q.crq_token, bytes);
+	if (rc == H_CLOSED || rc == H_SUCCESS) {
+		vscsi->state = WAIT_CONNECTION;
+		rc = ibmvscsis_establish_new_q(vscsi);
+	}
+
+	if (rc != ADAPT_SUCCESS) {
+		vscsi->state = ERR_DISCONNECTED;
+		vscsi->flags |= RESPONSE_Q_DOWN;
+	}
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_create_command_q() - Create Command Queue
+ * @vscsi:	Pointer to our adapter structure
+ * @num_cmds:	Currently unused.  In the future, may be used to determine
+ *		the size of the CRQ.
+ *
+ * Allocates memory for command queue maps remote memory into an ioba
+ * initializes the command response queue
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process level only
+ */
+static long ibmvscsis_create_command_q(struct scsi_info *vscsi, int num_cmds)
+{
+	int pages;
+	struct vio_dev *vdev = vscsi->dma_dev;
+
+	/* We might support multiple pages in the future, but just 1 for now */
+	pages = 1;
+
+	vscsi->cmd_q.size = pages;
+
+	vscsi->cmd_q.base_addr =
+		(struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
+	if (!vscsi->cmd_q.base_addr)
+		return -ENOMEM;
+
+	vscsi->cmd_q.mask = ((uint)pages * CRQ_PER_PAGE) - 1;
+
+	vscsi->cmd_q.crq_token = dma_map_single(&vdev->dev,
+						vscsi->cmd_q.base_addr,
+						PAGE_SIZE, DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(&vdev->dev, vscsi->cmd_q.crq_token)) {
+		free_page((unsigned long)vscsi->cmd_q.base_addr);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * ibmvscsis_destroy_command_q - Destroy Command Queue
+ * @vscsi:	Pointer to our adapter structure
+ *
+ * Releases memory for command queue and unmaps mapped remote memory.
+ *
+ * EXECUTION ENVIRONMENT:
+ *	Process level only
+ */
+static void ibmvscsis_destroy_command_q(struct scsi_info *vscsi)
+{
+	dma_unmap_single(&vscsi->dma_dev->dev, vscsi->cmd_q.crq_token,
+			 PAGE_SIZE, DMA_BIDIRECTIONAL);
+	free_page((unsigned long)vscsi->cmd_q.base_addr);
+	vscsi->cmd_q.base_addr = NULL;
+	vscsi->state = NO_QUEUE;
+}
+
+static u8 ibmvscsis_fast_fail(struct scsi_info *vscsi,
+			      struct ibmvscsis_cmd *cmd)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
+	struct scsi_sense_hdr sshdr;
+	u8 rc = se_cmd->scsi_status;
+
+	if (vscsi->fast_fail && (READ_CMD(srp->cdb) || WRITE_CMD(srp->cdb)))
+		if (scsi_normalize_sense(se_cmd->sense_buffer,
+					 se_cmd->scsi_sense_length, &sshdr))
+			if (sshdr.sense_key == HARDWARE_ERROR &&
+			    (se_cmd->residual_count == 0 ||
+			     se_cmd->residual_count == se_cmd->data_length)) {
+				rc = NO_SENSE;
+				cmd->flags |= CMD_FAST_FAIL;
+			}
+
+	return rc;
+}
+
+/**
+ * srp_build_response() - Build an SRP response buffer
+ * @vscsi:	Pointer to our adapter structure
+ * @cmd:	Pointer to command for which to send the response
+ * @len_p:	Where to return the length of the IU response sent.  This
+ *		is needed to construct the CRQ response.
+ *
+ * Build the SRP response buffer and copy it to the client's memory space.
+ */
+static long srp_build_response(struct scsi_info *vscsi,
+			       struct ibmvscsis_cmd *cmd, uint *len_p)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct srp_rsp *rsp;
+	uint len;
+	u32 rsp_code;
+	char *data;
+	u32 *tsk_status;
+	long rc = ADAPT_SUCCESS;
+
+	spin_lock_bh(&vscsi->intr_lock);
+
+	rsp = &vio_iu(iue)->srp.rsp;
+	len = sizeof(*rsp);
+	memset(rsp, 0, len);
+	data = rsp->data;
+
+	rsp->opcode = SRP_RSP;
+
+	if (vscsi->credit > 0 && vscsi->state == SRP_PROCESSING)
+		rsp->req_lim_delta = cpu_to_be32(vscsi->credit);
+	else
+		rsp->req_lim_delta = cpu_to_be32(1 + vscsi->credit);
+	rsp->tag = cmd->rsp.tag;
+	rsp->flags = 0;
+
+	if (cmd->type == SCSI_CDB) {
+		rsp->status = ibmvscsis_fast_fail(vscsi, cmd);
+		if (rsp->status) {
+			pr_debug("build_resp: cmd %p, scsi status %d\n", cmd,
+				 (int)rsp->status);
+			ibmvscsis_determine_resid(se_cmd, rsp);
+			if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
+				rsp->sense_data_len =
+					cpu_to_be32(se_cmd->scsi_sense_length);
+				rsp->flags |= SRP_RSP_FLAG_SNSVALID;
+				len += se_cmd->scsi_sense_length;
+				memcpy(data, se_cmd->sense_buffer,
+				       se_cmd->scsi_sense_length);
+			}
+			rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
+				UCSOLNT_RESP_SHIFT;
+		} else if (cmd->flags & CMD_FAST_FAIL) {
+			pr_debug("build_resp: cmd %p, fast fail\n", cmd);
+			rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
+				UCSOLNT_RESP_SHIFT;
+		} else {
+			rsp->sol_not = (cmd->rsp.sol_not & SCSOLNT) >>
+				SCSOLNT_RESP_SHIFT;
+		}
+	} else {
+		/* this is task management */
+		rsp->status = 0;
+		rsp->resp_data_len = cpu_to_be32(4);
+		rsp->flags |= SRP_RSP_FLAG_RSPVALID;
+
+		switch (se_cmd->se_tmr_req->response) {
+		case TMR_FUNCTION_COMPLETE:
+		case TMR_TASK_DOES_NOT_EXIST:
+			rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE;
+			rsp->sol_not = (cmd->rsp.sol_not & SCSOLNT) >>
+				SCSOLNT_RESP_SHIFT;
+			break;
+		case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
+		case TMR_LUN_DOES_NOT_EXIST:
+			rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED;
+			rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
+				UCSOLNT_RESP_SHIFT;
+			break;
+		case TMR_FUNCTION_FAILED:
+		case TMR_FUNCTION_REJECTED:
+		default:
+			rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_FAILED;
+			rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
+				UCSOLNT_RESP_SHIFT;
+			break;
+		}
+
+		tsk_status = (u32 *)data;
+		*tsk_status = cpu_to_be32(rsp_code);
+		data = (char *)(tsk_status + 1);
+		len += 4;
+	}
+
+	dma_wmb();
+	rc = h_copy_rdma(len, vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma,
+			 vscsi->dds.window[REMOTE].liobn,
+			 be64_to_cpu(iue->remote_token));
+
+	switch (rc) {
+	case H_SUCCESS:
+		vscsi->credit = 0;
+		*len_p = len;
+		break;
+	case H_PERMISSION:
+		if (connection_broken(vscsi))
+			vscsi->flags |= RESPONSE_Q_DOWN | CLIENT_FAILED;
+
+		dev_err(&vscsi->dev, "build_response: error copying to client, rc %ld, flags 0x%x, state 0x%hx\n",
+			rc, vscsi->flags, vscsi->state);
+		break;
+	case H_SOURCE_PARM:
+	case H_DEST_PARM:
+	default:
+		dev_err(&vscsi->dev, "build_response: error copying to client, rc %ld\n",
+			rc);
+		break;
+	}
+
+	spin_unlock_bh(&vscsi->intr_lock);
+
+	return rc;
+}
+
+static int ibmvscsis_rdma(struct ibmvscsis_cmd *cmd, struct scatterlist *sg,
+			  int nsg, struct srp_direct_buf *md, int nmd,
+			  enum dma_data_direction dir, unsigned int bytes)
+{
+	struct iu_entry *iue = cmd->iue;
+	struct srp_target *target = iue->target;
+	struct scsi_info *vscsi = target->ldata;
+	struct scatterlist *sgp;
+	dma_addr_t client_ioba, server_ioba;
+	ulong buf_len;
+	ulong client_len, server_len;
+	int md_idx;
+	long tx_len;
+	long rc = 0;
+
+	if (bytes == 0)
+		return 0;
+
+	sgp = sg;
+	client_len = 0;
+	server_len = 0;
+	md_idx = 0;
+	tx_len = bytes;
+
+	do {
+		if (client_len == 0) {
+			if (md_idx >= nmd) {
+				dev_err(&vscsi->dev, "rdma: ran out of client memory descriptors\n");
+				rc = -EIO;
+				break;
+			}
+			client_ioba = be64_to_cpu(md[md_idx].va);
+			client_len = be32_to_cpu(md[md_idx].len);
+		}
+		if (server_len == 0) {
+			if (!sgp) {
+				dev_err(&vscsi->dev, "rdma: ran out of scatter/gather list\n");
+				rc = -EIO;
+				break;
+			}
+			server_ioba = sg_dma_address(sgp);
+			server_len = sg_dma_len(sgp);
+		}
+
+		buf_len = tx_len;
+
+		if (buf_len > client_len)
+			buf_len = client_len;
+
+		if (buf_len > server_len)
+			buf_len = server_len;
+
+		if (buf_len > max_vdma_size)
+			buf_len = max_vdma_size;
+
+		if (dir == DMA_TO_DEVICE) {
+			/* read from client */
+			rc = h_copy_rdma(buf_len,
+					 vscsi->dds.window[REMOTE].liobn,
+					 client_ioba,
+					 vscsi->dds.window[LOCAL].liobn,
+					 server_ioba);
+		} else {
+			/* write to client */
+			struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
+
+			/* The h_copy_rdma will cause phyp, running in another
+			 * partition, to read memory, so we need to make sure
+			 * the data has been written out, hence these syncs.
+			 */
+			/* ensure that everything is in memory */
+			isync();
+			/* ensure that memory has been made visible */
+			dma_wmb();
+			rc = h_copy_rdma(buf_len,
+					 vscsi->dds.window[LOCAL].liobn,
+					 server_ioba,
+					 vscsi->dds.window[REMOTE].liobn,
+					 client_ioba);
+		}
+		switch (rc) {
+		case H_SUCCESS:
+			break;
+		case H_PERMISSION:
+		case H_SOURCE_PARM:
+		case H_DEST_PARM:
+			if (connection_broken(vscsi)) {
+				spin_lock_bh(&vscsi->intr_lock);
+				vscsi->flags |=
+					(RESPONSE_Q_DOWN | CLIENT_FAILED);
+				spin_unlock_bh(&vscsi->intr_lock);
+			}
+			dev_err(&vscsi->dev, "rdma: h_copy_rdma failed, rc %ld\n",
+				rc);
+			break;
+
+		default:
+			dev_err(&vscsi->dev, "rdma: unknown error %ld from h_copy_rdma\n",
+				rc);
+			break;
+		}
+
+		if (!rc) {
+			tx_len -= buf_len;
+			if (tx_len) {
+				client_len -= buf_len;
+				if (client_len == 0)
+					md_idx++;
+				else
+					client_ioba += buf_len;
+
+				server_len -= buf_len;
+				if (server_len == 0)
+					sgp = sg_next(sgp);
+				else
+					server_ioba += buf_len;
+			} else {
+				break;
+			}
+		}
+	} while (!rc);
+
+	return rc;
+}
+
+/**
+ * ibmvscsis_handle_crq() - Handle CRQ
+ * @data:	Pointer to our adapter structure
+ *
+ * Read the command elements from the command queue and copy the payloads
+ * associated with the command elements to local memory and execute the
+ * SRP requests.
+ *
+ * Note: this is an edge triggered interrupt. It can not be shared.
+ */
+static void ibmvscsis_handle_crq(unsigned long data)
+{
+	struct scsi_info *vscsi = (struct scsi_info *)data;
+	struct viosrp_crq *crq;
+	long rc;
+	bool ack = true;
+	volatile u8 valid;
+
+	spin_lock_bh(&vscsi->intr_lock);
+
+	pr_debug("got interrupt\n");
+
+	/*
+	 * if we are in a path where we are waiting for all pending commands
+	 * to complete because we received a transport event and anything in
+	 * the command queue is for a new connection, do nothing
+	 */
+	if (TARGET_STOP(vscsi)) {
+		vio_enable_interrupts(vscsi->dma_dev);
+
+		pr_debug("handle_crq, don't process: flags 0x%x, state 0x%hx\n",
+			 vscsi->flags, vscsi->state);
+		spin_unlock_bh(&vscsi->intr_lock);
+		return;
+	}
+
+	rc = vscsi->flags & SCHEDULE_DISCONNECT;
+	crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+	valid = crq->valid;
+	dma_rmb();
+
+	while (valid) {
+		/*
+		 * These are edege triggered interrupts. After dropping out of
+		 * the while loop, the code must check for work since an
+		 * interrupt could be lost, and an elment be left on the queue,
+		 * hence the label.
+		 */
+cmd_work:
+		vscsi->cmd_q.index =
+			(vscsi->cmd_q.index + 1) & vscsi->cmd_q.mask;
+
+		if (!rc) {
+			rc = ibmvscsis_parse_command(vscsi, crq);
+		} else {
+			if ((uint)crq->valid == VALID_TRANS_EVENT) {
+				/*
+				 * must service the transport layer events even
+				 * in an error state, dont break out until all
+				 * the consecutive transport events have been
+				 * processed
+				 */
+				rc = ibmvscsis_trans_event(vscsi, crq);
+			} else if (vscsi->flags & TRANS_EVENT) {
+				/*
+				 * if a transport event has occurred leave
+				 * everything but transport events on the queue
+				 *
+				 * need to decrement the queue index so we can
+				 * look at the element again
+				 */
+				if (vscsi->cmd_q.index)
+					vscsi->cmd_q.index -= 1;
+				else
+					/*
+					 * index is at 0 it just wrapped.
+					 * have it index last element in q
+					 */
+					vscsi->cmd_q.index = vscsi->cmd_q.mask;
+				break;
+			}
+		}
+
+		crq->valid = INVALIDATE_CMD_RESP_EL;
+
+		crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+		valid = crq->valid;
+		dma_rmb();
+	}
+
+	if (!rc) {
+		if (ack) {
+			vio_enable_interrupts(vscsi->dma_dev);
+			ack = false;
+			pr_debug("handle_crq, reenabling interrupts\n");
+		}
+		valid = crq->valid;
+		dma_rmb();
+		if (valid)
+			goto cmd_work;
+	} else {
+		pr_debug("handle_crq, error: flags 0x%x, state 0x%hx, crq index 0x%x\n",
+			 vscsi->flags, vscsi->state, vscsi->cmd_q.index);
+	}
+
+	pr_debug("Leaving handle_crq: schedule_q empty %d, flags 0x%x, state 0x%hx\n",
+		 (int)list_empty(&vscsi->schedule_q), vscsi->flags,
+		 vscsi->state);
+
+	spin_unlock_bh(&vscsi->intr_lock);
+}
+
+static int ibmvscsis_probe(struct vio_dev *vdev,
+			   const struct vio_device_id *id)
+{
+	struct scsi_info *vscsi;
+	int rc = 0;
+	long hrc = 0;
+	char wq_name[24];
+
+	vscsi = kzalloc(sizeof(*vscsi), GFP_KERNEL);
+	if (!vscsi) {
+		rc = -ENOMEM;
+		pr_err("probe: allocation of adapter failed\n");
+		return rc;
+	}
+
+	vscsi->dma_dev = vdev;
+	vscsi->dev = vdev->dev;
+	INIT_LIST_HEAD(&vscsi->schedule_q);
+	INIT_LIST_HEAD(&vscsi->waiting_rsp);
+	INIT_LIST_HEAD(&vscsi->active_q);
+
+	snprintf(vscsi->tport.tport_name, IBMVSCSIS_NAMELEN, "%s",
+		 dev_name(&vdev->dev));
+
+	pr_debug("probe tport_name: %s\n", vscsi->tport.tport_name);
+
+	rc = read_dma_window(vscsi);
+	if (rc)
+		goto free_adapter;
+	pr_debug("Probe: liobn 0x%x, riobn 0x%x\n",
+		 vscsi->dds.window[LOCAL].liobn,
+		 vscsi->dds.window[REMOTE].liobn);
+
+	strcpy(vscsi->eye, "VSCSI ");
+	strncat(vscsi->eye, vdev->name, MAX_EYE);
+
+	vscsi->dds.unit_id = vdev->unit_address;
+	strncpy(vscsi->dds.partition_name, partition_name,
+		sizeof(vscsi->dds.partition_name));
+	vscsi->dds.partition_num = partition_number;
+
+	spin_lock_bh(&ibmvscsis_dev_lock);
+	list_add_tail(&vscsi->list, &ibmvscsis_dev_list);
+	spin_unlock_bh(&ibmvscsis_dev_lock);
+
+	/*
+	 * TBD: How do we determine # of cmds to request?  Do we know how
+	 * many "children" we have?
+	 */
+	vscsi->request_limit = INITIAL_SRP_LIMIT;
+	rc = srp_target_alloc(&vscsi->target, &vdev->dev, vscsi->request_limit,
+			      SRP_MAX_IU_LEN);
+	if (rc)
+		goto rem_list;
+
+	vscsi->target.ldata = vscsi;
+
+	rc = ibmvscsis_alloc_cmds(vscsi, vscsi->request_limit);
+	if (rc) {
+		dev_err(&vscsi->dev, "alloc_cmds failed, rc %d, num %d\n",
+			rc, vscsi->request_limit);
+		goto free_target;
+	}
+
+	/*
+	 * Note: the lock is used in freeing timers, so must initialize
+	 * first so that ordering in case of error is correct.
+	 */
+	spin_lock_init(&vscsi->intr_lock);
+
+	rc = ibmvscsis_alloctimer(vscsi);
+	if (rc) {
+		dev_err(&vscsi->dev, "probe: alloctimer failed, rc %d\n", rc);
+		goto free_cmds;
+	}
+
+	rc = ibmvscsis_create_command_q(vscsi, 256);
+	if (rc) {
+		dev_err(&vscsi->dev, "probe: create_command_q failed, rc %d\n",
+			rc);
+		goto free_timer;
+	}
+
+	vscsi->map_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!vscsi->map_buf) {
+		rc = -ENOMEM;
+		dev_err(&vscsi->dev, "probe: allocating cmd buffer failed\n");
+		goto destroy_queue;
+	}
+
+	vscsi->map_ioba = dma_map_single(&vdev->dev, vscsi->map_buf, PAGE_SIZE,
+					 DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(&vdev->dev, vscsi->map_ioba)) {
+		dev_err(&vscsi->dev, "probe: error mapping command buffer\n");
+		goto free_buf;
+	}
+
+	hrc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO,
+		       (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0,
+		       0);
+	if (hrc == H_SUCCESS)
+		vscsi->client_data.partition_number =
+			be64_to_cpu(*(u64 *)vscsi->map_buf);
+	/*
+	 * We expect the VIOCTL to fail if we're configured as "any
+	 * client can connect" and the client isn't activated yet.
+	 * We'll make the call again when he sends an init msg.
+	 */
+	pr_debug("probe hrc %ld, client partition num %d\n",
+		 hrc, vscsi->client_data.partition_number);
+
+	tasklet_init(&vscsi->work_task, ibmvscsis_handle_crq,
+		     (unsigned long)vscsi);
+
+	init_completion(&vscsi->wait_idle);
+	init_completion(&vscsi->unconfig);
+
+	snprintf(wq_name, 24, "ibmvscsis%s", dev_name(&vdev->dev));
+	vscsi->work_q = create_workqueue(wq_name);
+	if (!vscsi->work_q) {
+		rc = -ENOMEM;
+		dev_err(&vscsi->dev, "create_workqueue failed\n");
+		goto unmap_buf;
+	}
+
+	rc = request_irq(vdev->irq, ibmvscsis_interrupt, 0, "ibmvscsis", vscsi);
+	if (rc) {
+		rc = -EPERM;
+		dev_err(&vscsi->dev, "probe: request_irq failed, rc %d\n", rc);
+		goto destroy_WQ;
+	}
+
+	vscsi->state = WAIT_ENABLED;
+
+	dev_set_drvdata(&vdev->dev, vscsi);
+
+	return 0;
+
+destroy_WQ:
+	destroy_workqueue(vscsi->work_q);
+unmap_buf:
+	dma_unmap_single(&vdev->dev, vscsi->map_ioba, PAGE_SIZE,
+			 DMA_BIDIRECTIONAL);
+free_buf:
+	kfree(vscsi->map_buf);
+destroy_queue:
+	tasklet_kill(&vscsi->work_task);
+	ibmvscsis_unregister_command_q(vscsi);
+	ibmvscsis_destroy_command_q(vscsi);
+free_timer:
+	ibmvscsis_freetimer(vscsi);
+free_cmds:
+	ibmvscsis_free_cmds(vscsi);
+free_target:
+	srp_target_free(&vscsi->target);
+rem_list:
+	spin_lock_bh(&ibmvscsis_dev_lock);
+	list_del(&vscsi->list);
+	spin_unlock_bh(&ibmvscsis_dev_lock);
+free_adapter:
+	kfree(vscsi);
+
+	return rc;
+}
+
+static int ibmvscsis_remove(struct vio_dev *vdev)
+{
+	struct scsi_info *vscsi = dev_get_drvdata(&vdev->dev);
+
+	pr_debug("remove (%s)\n", dev_name(&vscsi->dma_dev->dev));
+
+	spin_lock_bh(&vscsi->intr_lock);
+	ibmvscsis_post_disconnect(vscsi, UNCONFIGURING, 0);
+	vscsi->flags |= CFG_SLEEPING;
+	spin_unlock_bh(&vscsi->intr_lock);
+	wait_for_completion(&vscsi->unconfig);
+
+	vio_disable_interrupts(vdev);
+	free_irq(vdev->irq, vscsi);
+	destroy_workqueue(vscsi->work_q);
+	dma_unmap_single(&vdev->dev, vscsi->map_ioba, PAGE_SIZE,
+			 DMA_BIDIRECTIONAL);
+	kfree(vscsi->map_buf);
+	tasklet_kill(&vscsi->work_task);
+	ibmvscsis_destroy_command_q(vscsi);
+	ibmvscsis_freetimer(vscsi);
+	ibmvscsis_free_cmds(vscsi);
+	srp_target_free(&vscsi->target);
+	spin_lock_bh(&ibmvscsis_dev_lock);
+	list_del(&vscsi->list);
+	spin_unlock_bh(&ibmvscsis_dev_lock);
+	kfree(vscsi);
+
+	return 0;
+}
+
+static ssize_t system_id_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
+}
+
+static ssize_t partition_number_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
+}
+
+static ssize_t unit_address_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct scsi_info *vscsi = container_of(dev, struct scsi_info, dev);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", vscsi->dma_dev->unit_address);
+}
+
+static int ibmvscsis_get_system_info(void)
+{
+	struct device_node *rootdn, *vdevdn;
+	const char *id, *model, *name;
+	const uint *num;
+
+	rootdn = of_find_node_by_path("/");
+	if (!rootdn)
+		return -ENOENT;
+
+	model = of_get_property(rootdn, "model", NULL);
+	id = of_get_property(rootdn, "system-id", NULL);
+	if (model && id)
+		snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
+
+	name = of_get_property(rootdn, "ibm,partition-name", NULL);
+	if (name)
+		strncpy(partition_name, name, sizeof(partition_name));
+
+	num = of_get_property(rootdn, "ibm,partition-no", NULL);
+	if (num)
+		partition_number = of_read_number(num, 1);
+
+	of_node_put(rootdn);
+
+	vdevdn = of_find_node_by_path("/vdevice");
+	if (vdevdn) {
+		const uint *mvds;
+
+		mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size",
+				       NULL);
+		if (mvds)
+			max_vdma_size = *mvds;
+		of_node_put(vdevdn);
+	}
+
+	return 0;
+}
+
+static char *ibmvscsis_get_fabric_name(void)
+{
+	return "ibmvscsis";
+}
+
+static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct ibmvscsis_tport *tport =
+		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
+
+	return tport->tport_name;
+}
+
+static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg)
+{
+	struct ibmvscsis_tport *tport =
+		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
+
+	return tport->tport_tpgt;
+}
+
+static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int ibmvscsis_check_true(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int ibmvscsis_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
+
+static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
+{
+	return target_put_sess_cmd(se_cmd);
+}
+
+static void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+						 se_cmd);
+	struct scsi_info *vscsi = cmd->adapter;
+
+	spin_lock_bh(&vscsi->intr_lock);
+	/* Remove from active_q */
+	list_del(&cmd->list);
+	list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+	ibmvscsis_send_messages(vscsi);
+	spin_unlock_bh(&vscsi->intr_lock);
+}
+
+static u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
+
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+						 se_cmd);
+	struct iu_entry *iue = cmd->iue;
+	int rc;
+
+	rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma,
+			       1, 1);
+	if (rc) {
+		pr_err("srp_transfer_data() failed: %d\n", rc);
+		return -EIO;
+	}
+	/*
+	 * We now tell TCM to add this WRITE CDB directly into the TCM storage
+	 * object execution queue.
+	 */
+	target_execute_cmd(se_cmd);
+	return 0;
+}
+
+static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl)
+{
+}
+
+static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+						 se_cmd);
+	struct iu_entry *iue = cmd->iue;
+	struct scsi_info *vscsi = cmd->adapter;
+	char *sd;
+	uint len = 0;
+	int rc;
+
+	rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma, 1,
+			       1);
+	if (rc) {
+		pr_err("srp_transfer_data failed: %d\n", rc);
+		sd = se_cmd->sense_buffer;
+		se_cmd->scsi_sense_length = 18;
+		memset(se_cmd->sense_buffer, 0, se_cmd->scsi_sense_length);
+		/* Logical Unit Communication Time-out asc/ascq = 0x0801 */
+		scsi_build_sense_buffer(0, se_cmd->sense_buffer, MEDIUM_ERROR,
+					0x08, 0x01);
+	}
+
+	srp_build_response(vscsi, cmd, &len);
+	cmd->rsp.format = SRP_FORMAT;
+	cmd->rsp.len = len;
+
+	return 0;
+}
+
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+						 se_cmd);
+	struct scsi_info *vscsi = cmd->adapter;
+	uint len;
+
+	pr_debug("queue_status %p\n", se_cmd);
+
+	srp_build_response(vscsi, cmd, &len);
+	cmd->rsp.format = SRP_FORMAT;
+	cmd->rsp.len = len;
+
+	return 0;
+}
+
+static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+						 se_cmd);
+	struct scsi_info *vscsi = cmd->adapter;
+	uint len;
+
+	pr_debug("queue_tm_rsp %p, status %d\n",
+		 se_cmd, (int)se_cmd->se_tmr_req->response);
+
+	srp_build_response(vscsi, cmd, &len);
+	cmd->rsp.format = SRP_FORMAT;
+	cmd->rsp.len = len;
+}
+
+static void ibmvscsis_aborted_task(struct se_cmd *se_cmd)
+{
+	/* TBD: What (if anything) should we do here? */
+	pr_debug("ibmvscsis_aborted_task %p\n", se_cmd);
+}
+
+static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
+					   struct config_group *group,
+					   const char *name)
+{
+	struct ibmvscsis_tport *tport;
+
+	tport = ibmvscsis_lookup_port(name);
+	if (tport) {
+		tport->tport_proto_id = SCSI_PROTOCOL_SRP;
+		pr_debug("make_tport(%s), pointer:%p, tport_id:%x\n",
+			 name, tport, tport->tport_proto_id);
+		return &tport->tport_wwn;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static void ibmvscsis_drop_tport(struct se_wwn *wwn)
+{
+	struct ibmvscsis_tport *tport = container_of(wwn,
+						     struct ibmvscsis_tport,
+						     tport_wwn);
+
+	pr_debug("drop_tport(%s)\n",
+		 config_item_name(&tport->tport_wwn.wwn_group.cg_item));
+}
+
+static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
+						  struct config_group *group,
+						  const char *name)
+{
+	struct ibmvscsis_tport *tport =
+		container_of(wwn, struct ibmvscsis_tport, tport_wwn);
+	int rc;
+
+	tport->releasing = false;
+
+	rc = core_tpg_register(&tport->tport_wwn, &tport->se_tpg,
+			       tport->tport_proto_id);
+	if (rc)
+		return ERR_PTR(rc);
+
+	return &tport->se_tpg;
+}
+
+static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+						     struct ibmvscsis_tport,
+						     se_tpg);
+
+	tport->releasing = true;
+	tport->enabled = false;
+
+	/*
+	 * Release the virtual I_T Nexus for this ibmvscsis TPG
+	 */
+	ibmvscsis_drop_nexus(tport);
+	/*
+	 * Deregister the se_tpg from TCM..
+	 */
+	core_tpg_deregister(se_tpg);
+}
+
+static ssize_t ibmvscsis_wwn_version_show(struct config_item *item,
+					  char *page)
+{
+	return scnprintf(page, PAGE_SIZE, "%s\n", IBMVSCSIS_VERSION);
+}
+CONFIGFS_ATTR_RO(ibmvscsis_wwn_, version);
+
+static struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
+	&ibmvscsis_wwn_attr_version,
+	NULL,
+};
+
+static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
+					 char *page)
+{
+	struct se_portal_group *se_tpg = to_tpg(item);
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+						     struct ibmvscsis_tport,
+						     se_tpg);
+
+	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
+}
+
+static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
+					  const char *page, size_t count)
+{
+	struct se_portal_group *se_tpg = to_tpg(item);
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+						     struct ibmvscsis_tport,
+						     se_tpg);
+	struct scsi_info *vscsi = container_of(tport, struct scsi_info, tport);
+	unsigned long tmp;
+	int rc;
+	long lrc;
+
+	rc = kstrtoul(page, 0, &tmp);
+	if (rc < 0) {
+		pr_err("Unable to extract srpt_tpg_store_enable\n");
+		return -EINVAL;
+	}
+
+	if ((tmp != 0) && (tmp != 1)) {
+		pr_err("Illegal value for srpt_tpg_store_enable\n");
+		return -EINVAL;
+	}
+
+	if (tmp) {
+		spin_lock_bh(&vscsi->intr_lock);
+		tport->enabled = true;
+		lrc = ibmvscsis_enable_change_state(vscsi);
+		if (lrc)
+			pr_err("enable_change_state failed, rc %ld state %d\n",
+			       lrc, vscsi->state);
+		spin_unlock_bh(&vscsi->intr_lock);
+	} else {
+		spin_lock_bh(&vscsi->intr_lock);
+		tport->enabled = false;
+		/* This simulates the server going down */
+		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
+		spin_unlock_bh(&vscsi->intr_lock);
+	}
+
+	pr_debug("tpg_enable_store, tmp %ld, state %d\n", tmp, vscsi->state);
+
+	return count;
+}
+CONFIGFS_ATTR(ibmvscsis_tpg_, enable);
+
+static struct configfs_attribute *ibmvscsis_tpg_attrs[] = {
+	&ibmvscsis_tpg_attr_enable,
+	NULL,
+};
+
+static const struct target_core_fabric_ops ibmvscsis_ops = {
+	.module				= THIS_MODULE,
+	.name				= "ibmvscsis",
+	.max_data_sg_nents		= MAX_TXU / PAGE_SIZE,
+	.get_fabric_name		= ibmvscsis_get_fabric_name,
+	.tpg_get_wwn			= ibmvscsis_get_fabric_wwn,
+	.tpg_get_tag			= ibmvscsis_get_tag,
+	.tpg_get_default_depth		= ibmvscsis_get_default_depth,
+	.tpg_check_demo_mode		= ibmvscsis_check_true,
+	.tpg_check_demo_mode_cache	= ibmvscsis_check_true,
+	.tpg_check_demo_mode_write_protect = ibmvscsis_check_false,
+	.tpg_check_prod_mode_write_protect = ibmvscsis_check_false,
+	.tpg_get_inst_index		= ibmvscsis_tpg_get_inst_index,
+	.check_stop_free		= ibmvscsis_check_stop_free,
+	.release_cmd			= ibmvscsis_release_cmd,
+	.sess_get_index			= ibmvscsis_sess_get_index,
+	.write_pending			= ibmvscsis_write_pending,
+	.write_pending_status		= ibmvscsis_write_pending_status,
+	.set_default_node_attributes	= ibmvscsis_set_default_node_attrs,
+	.get_cmd_state			= ibmvscsis_get_cmd_state,
+	.queue_data_in			= ibmvscsis_queue_data_in,
+	.queue_status			= ibmvscsis_queue_status,
+	.queue_tm_rsp			= ibmvscsis_queue_tm_rsp,
+	.aborted_task			= ibmvscsis_aborted_task,
+	/*
+	 * Setup function pointers for logic in target_core_fabric_configfs.c
+	 */
+	.fabric_make_wwn		= ibmvscsis_make_tport,
+	.fabric_drop_wwn		= ibmvscsis_drop_tport,
+	.fabric_make_tpg		= ibmvscsis_make_tpg,
+	.fabric_drop_tpg		= ibmvscsis_drop_tpg,
+
+	.tfc_wwn_attrs			= ibmvscsis_wwn_attrs,
+	.tfc_tpg_base_attrs		= ibmvscsis_tpg_attrs,
+};
+
+static void ibmvscsis_dev_release(struct device *dev) {};
+
+static struct class_attribute ibmvscsis_class_attrs[] = {
+	__ATTR_NULL,
+};
+
+static struct device_attribute dev_attr_system_id =
+	__ATTR(system_id, S_IRUGO, system_id_show, NULL);
+
+static struct device_attribute dev_attr_partition_number =
+	__ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
+
+static struct device_attribute dev_attr_unit_address =
+	__ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
+
+static struct attribute *ibmvscsis_dev_attrs[] = {
+	&dev_attr_system_id.attr,
+	&dev_attr_partition_number.attr,
+	&dev_attr_unit_address.attr,
+};
+ATTRIBUTE_GROUPS(ibmvscsis_dev);
+
+static struct class ibmvscsis_class = {
+	.name		= "ibmvscsis",
+	.dev_release	= ibmvscsis_dev_release,
+	.class_attrs	= ibmvscsis_class_attrs,
+	.dev_groups	= ibmvscsis_dev_groups,
+};
+
+static struct vio_device_id ibmvscsis_device_table[] = {
+	{ "v-scsi-host", "IBM,v-scsi-host" },
+	{ "", "" }
+};
+MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
+
+static struct vio_driver ibmvscsis_driver = {
+	.name = "ibmvscsis",
+	.id_table = ibmvscsis_device_table,
+	.probe = ibmvscsis_probe,
+	.remove = ibmvscsis_remove,
+};
+
+/*
+ * ibmvscsis_init() - Kernel Module initialization
+ *
+ * Note: vio_register_driver() registers callback functions, and at least one
+ * of those callback functions calls TCM - Linux IO Target Subsystem, thus
+ * the SCSI Target template must be registered before vio_register_driver()
+ * is called.
+ */
+static int __init ibmvscsis_init(void)
+{
+	int rc = 0;
+
+	rc = ibmvscsis_get_system_info();
+	if (rc) {
+		pr_err("rc %d from get_system_info\n", rc);
+		goto out;
+	}
+
+	rc = class_register(&ibmvscsis_class);
+	if (rc) {
+		pr_err("failed class register\n");
+		goto out;
+	}
+
+	rc = target_register_template(&ibmvscsis_ops);
+	if (rc) {
+		pr_err("rc %d from target_register_template\n", rc);
+		goto unregister_class;
+	}
+
+	rc = vio_register_driver(&ibmvscsis_driver);
+	if (rc) {
+		pr_err("rc %d from vio_register_driver\n", rc);
+		goto unregister_target;
+	}
+
+	return 0;
+
+unregister_target:
+	target_unregister_template(&ibmvscsis_ops);
+unregister_class:
+	class_unregister(&ibmvscsis_class);
+out:
+	return rc;
+}
+
+static void __exit ibmvscsis_exit(void)
+{
+	pr_info("Unregister IBM virtual SCSI host driver\n");
+	vio_unregister_driver(&ibmvscsis_driver);
+	target_unregister_template(&ibmvscsis_ops);
+	class_unregister(&ibmvscsis_class);
+}
+
+MODULE_DESCRIPTION("IBMVSCSIS fabric driver");
+MODULE_AUTHOR("Bryant G. Ly and Michael Cyr");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(IBMVSCSIS_VERSION);
+module_init(ibmvscsis_init);
+module_exit(ibmvscsis_exit);
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
+++ linux-4.4.0/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
@@ -0,0 +1,347 @@
+/*******************************************************************************
+ * IBM Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ *			   Santiago Leon (santil@us.ibm.com) IBM Corp.
+ *			   Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.org>
+ * Copyright (C) 2016 Bryant G. Ly <bryantly@linux.vnet.ibm.com> IBM Corp.
+ *
+ * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+ * Authors: Michael Cyr <mikecyr@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __H_IBMVSCSI_TGT
+#define __H_IBMVSCSI_TGT
+
+#include "libsrp.h"
+
+#define SYS_ID_NAME_LEN		64
+#define PARTITION_NAMELEN	96
+#define IBMVSCSIS_NAMELEN       32
+
+#define MSG_HI  0
+#define MSG_LOW 1
+
+#define MAX_CMD_Q_PAGES       4
+#define CRQ_PER_PAGE          (PAGE_SIZE / sizeof(struct viosrp_crq))
+/* in terms of number of elements */
+#define DEFAULT_CMD_Q_SIZE    CRQ_PER_PAGE
+#define MAX_CMD_Q_SIZE        (DEFAULT_CMD_Q_SIZE * MAX_CMD_Q_PAGES)
+
+#define SRP_VIOLATION           0x102  /* general error code */
+
+/*
+ * SRP buffer formats defined as of 16.a supported by this driver.
+ */
+#define SUPPORTED_FORMATS  ((SRP_DATA_DESC_DIRECT << 1) | \
+			    (SRP_DATA_DESC_INDIRECT << 1))
+
+#define SCSI_LUN_ADDR_METHOD_FLAT	1
+
+struct dma_window {
+	u32 liobn;	/* Unique per vdevice */
+	u64 tce_base;	/* Physical location of the TCE table */
+	u64 tce_size;	/* Size of the TCE table in bytes */
+};
+
+struct target_dds {
+	u64 unit_id;                /* 64 bit will force alignment */
+#define NUM_DMA_WINDOWS 2
+#define LOCAL  0
+#define REMOTE 1
+	struct dma_window  window[NUM_DMA_WINDOWS];
+
+	/* root node property "ibm,partition-no" */
+	uint partition_num;
+	char partition_name[PARTITION_NAMELEN];
+};
+
+#define MAX_NUM_PORTS        1
+#define MAX_H_COPY_RDMA      (128 * 1024)
+
+#define MAX_EYE   64
+
+/* Return codes */
+#define ADAPT_SUCCESS            0L
+/* choose error codes that do not conflict with PHYP */
+#define ERROR                   -40L
+
+struct format_code {
+	u8 reserved;
+	u8 buffers;
+};
+
+struct client_info {
+#define SRP_VERSION "16.a"
+	char srp_version[8];
+	/* root node property ibm,partition-name */
+	char partition_name[PARTITION_NAMELEN];
+	/* root node property ibm,partition-no */
+	u32 partition_number;
+	/* initially 1 */
+	u32 mad_version;
+	u32 os_type;
+};
+
+/*
+ * Changing this constant changes the number of seconds to wait before
+ * considering the client will never service its queue again.
+ */
+#define SECONDS_TO_CONSIDER_FAILED 30
+/*
+ * These constants set the polling period used to determine if the client
+ * has freed at least one element in the response queue.
+ */
+#define WAIT_SECONDS 1
+#define WAIT_NANO_SECONDS 5000
+#define MAX_TIMER_POPS ((1000000 / WAIT_NANO_SECONDS) * \
+			SECONDS_TO_CONSIDER_FAILED)
+/*
+ * general purpose timer control block
+ * which can be used for multiple functions
+ */
+struct timer_cb {
+	struct hrtimer timer;
+	/*
+	 * how long has it been since the client
+	 * serviced the queue. The variable is incrmented
+	 * in the service_wait_q routine and cleared
+	 * in send messages
+	 */
+	int timer_pops;
+	/* the timer is started */
+	bool started;
+};
+
+struct cmd_queue {
+	/* kva */
+	struct viosrp_crq *base_addr;
+	dma_addr_t crq_token;
+	/* used to maintain index */
+	uint mask;
+	/* current element */
+	uint index;
+	int size;
+};
+
+#define SCSOLNT_RESP_SHIFT	1
+#define UCSOLNT_RESP_SHIFT	2
+
+#define SCSOLNT         BIT(SCSOLNT_RESP_SHIFT)
+#define UCSOLNT         BIT(UCSOLNT_RESP_SHIFT)
+
+enum cmd_type {
+	SCSI_CDB	= 0x01,
+	TASK_MANAGEMENT	= 0x02,
+	/* MAD or addressed to port 0 */
+	ADAPTER_MAD	= 0x04,
+	UNSET_TYPE	= 0x08,
+};
+
+struct iu_rsp {
+	u8 format;
+	u8 sol_not;
+	u16 len;
+	/* tag is just to help client identify cmd, so don't translate be/le */
+	u64 tag;
+};
+
+struct ibmvscsis_cmd {
+	struct list_head list;
+	/* Used for TCM Core operations */
+	struct se_cmd se_cmd;
+	struct iu_entry *iue;
+	struct iu_rsp rsp;
+	struct work_struct work;
+	struct scsi_info *adapter;
+	/* Sense buffer that will be mapped into outgoing status */
+	unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+	u64 init_time;
+#define CMD_FAST_FAIL	BIT(0)
+	u32 flags;
+	char type;
+};
+
+struct ibmvscsis_nexus {
+	struct se_session *se_sess;
+};
+
+struct ibmvscsis_tport {
+	/* SCSI protocol the tport is providing */
+	u8 tport_proto_id;
+	/* ASCII formatted WWPN for SRP Target port */
+	char tport_name[IBMVSCSIS_NAMELEN];
+	/* Returned by ibmvscsis_make_tport() */
+	struct se_wwn tport_wwn;
+	/* Returned by ibmvscsis_make_tpg() */
+	struct se_portal_group se_tpg;
+	/* ibmvscsis port target portal group tag for TCM */
+	u16 tport_tpgt;
+	/* Pointer to TCM session for I_T Nexus */
+	struct ibmvscsis_nexus *ibmv_nexus;
+	bool enabled;
+	bool releasing;
+};
+
+struct scsi_info {
+	struct list_head list;
+	char eye[MAX_EYE];
+
+	/* commands waiting for space on repsonse queue */
+	struct list_head waiting_rsp;
+#define NO_QUEUE                    0x00
+#define WAIT_ENABLED                0X01
+#define WAIT_CONNECTION             0x04
+	/* have established a connection */
+#define CONNECTED                   0x08
+	/* at least one port is processing SRP IU */
+#define SRP_PROCESSING              0x10
+	/* remove request received */
+#define UNCONFIGURING               0x20
+	/* disconnect by letting adapter go idle, no error */
+#define WAIT_IDLE                   0x40
+	/* disconnecting to clear an error */
+#define ERR_DISCONNECT              0x80
+	/* disconnect to clear error state, then come back up */
+#define ERR_DISCONNECT_RECONNECT    0x100
+	/* disconnected after clearing an error */
+#define ERR_DISCONNECTED            0x200
+	/* A series of errors caused unexpected errors */
+#define UNDEFINED                   0x400
+	u16  state;
+	int fast_fail;
+	struct target_dds dds;
+	char *cmd_pool;
+	/* list of free commands */
+	struct list_head free_cmd;
+	/* command elements ready for scheduler */
+	struct list_head schedule_q;
+	/* commands sent to TCM */
+	struct list_head active_q;
+	caddr_t *map_buf;
+	/* ioba of map buffer */
+	dma_addr_t map_ioba;
+	/* allowable number of outstanding SRP requests */
+	int request_limit;
+	/* extra credit */
+	int credit;
+	/* outstanding transactions against credit limit */
+	int debit;
+
+	/* allow only one outstanding mad request */
+#define PROCESSING_MAD                0x00002
+	/* Waiting to go idle */
+#define WAIT_FOR_IDLE		      0x00004
+	/* H_REG_CRQ called */
+#define CRQ_CLOSED                    0x00010
+	/* detected that client has failed */
+#define CLIENT_FAILED                 0x00040
+	/* detected that transport event occurred */
+#define TRANS_EVENT                   0x00080
+	/* don't attempt to send anything to the client */
+#define RESPONSE_Q_DOWN               0x00100
+	/* request made to schedule disconnect handler */
+#define SCHEDULE_DISCONNECT           0x00400
+	/* disconnect handler is scheduled */
+#define DISCONNECT_SCHEDULED          0x00800
+	/* remove function is sleeping */
+#define CFG_SLEEPING                  0x01000
+	u32 flags;
+	/* adapter lock */
+	spinlock_t intr_lock;
+	/* information needed to manage command queue */
+	struct cmd_queue cmd_q;
+	/* used in hcall to copy response back into srp buffer */
+	u64  empty_iu_id;
+	/* used in crq, to tag what iu the response is for */
+	u64  empty_iu_tag;
+	uint new_state;
+	/* control block for the response queue timer */
+	struct timer_cb rsp_q_timer;
+	/* keep last client to enable proper accounting */
+	struct client_info client_data;
+	/* what can this client do */
+	u32 client_cap;
+	/*
+	 * The following two fields capture state and flag changes that
+	 * can occur when the lock is given up.  In the orginal design,
+	 * the lock was held during calls into phyp;
+	 * however, phyp did not meet PAPR architecture.  This is
+	 * a work around.
+	 */
+	u16  phyp_acr_state;
+	u32 phyp_acr_flags;
+
+	struct workqueue_struct *work_q;
+	struct completion wait_idle;
+	struct completion unconfig;
+	struct device dev;
+	struct vio_dev *dma_dev;
+	struct srp_target target;
+	struct ibmvscsis_tport tport;
+	struct tasklet_struct work_task;
+	struct work_struct proc_work;
+};
+
+/*
+ * Provide a constant that allows software to detect the adapter is
+ * disconnecting from the client from one of several states.
+ */
+#define IS_DISCONNECTING (UNCONFIGURING | ERR_DISCONNECT_RECONNECT | \
+			  ERR_DISCONNECT)
+
+/*
+ * Provide a constant that can be used with interrupt handling that
+ * essentially lets the interrupt handler know that all requests should
+ * be thrown out,
+ */
+#define DONT_PROCESS_STATE (IS_DISCONNECTING | UNDEFINED | \
+			    ERR_DISCONNECTED  | WAIT_IDLE)
+
+/*
+ * If any of these flag bits are set then do not allow the interrupt
+ * handler to schedule the off level handler.
+ */
+#define BLOCK (DISCONNECT_SCHEDULED)
+
+/* State and transition events that stop the interrupt handler */
+#define TARGET_STOP(VSCSI) (long)(((VSCSI)->state & DONT_PROCESS_STATE) | \
+				  ((VSCSI)->flags & BLOCK))
+
+/* flag bit that are not reset during disconnect */
+#define PRESERVE_FLAG_FIELDS 0
+
+#define vio_iu(IUE) ((union viosrp_iu *)((IUE)->sbuf->buf))
+
+#define READ_CMD(cdb)	(((cdb)[0] & 0x1F) == 8)
+#define WRITE_CMD(cdb)	(((cdb)[0] & 0x1F) == 0xA)
+
+#ifndef H_GET_PARTNER_INFO
+#define H_GET_PARTNER_INFO      0x0000000000000008LL
+#endif
+
+#define h_copy_rdma(l, sa, sb, da, db) \
+		plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
+#define h_vioctl(u, o, a, u1, u2, u3, u4) \
+		plpar_hcall_norets(H_VIOCTL, u, o, a, u1, u2)
+#define h_reg_crq(ua, tok, sz) \
+		plpar_hcall_norets(H_REG_CRQ, ua, tok, sz)
+#define h_free_crq(ua) \
+		plpar_hcall_norets(H_FREE_CRQ, ua)
+#define h_send_crq(ua, d1, d2) \
+		plpar_hcall_norets(H_SEND_CRQ, ua, d1, d2)
+
+#endif
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi_tgt/libsrp.c
+++ linux-4.4.0/drivers/scsi/ibmvscsi_tgt/libsrp.c
@@ -0,0 +1,427 @@
+/*******************************************************************************
+ * SCSI RDMA Protocol lib functions
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2016 Bryant G. Ly <bryantly@linux.vnet.ibm.com> IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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)	"libsrp: " fmt
+
+#include <linux/printk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <scsi/srp.h>
+#include <target/target_core_base.h>
+#include "libsrp.h"
+#include "ibmvscsi_tgt.h"
+
+static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
+			     struct srp_buf **ring)
+{
+	struct iu_entry *iue;
+	int i;
+
+	q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
+	if (!q->pool)
+		return -ENOMEM;
+	q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
+	if (!q->items)
+		goto free_pool;
+
+	spin_lock_init(&q->lock);
+	kfifo_init(&q->queue, (void *)q->pool, max * sizeof(void *));
+
+	for (i = 0, iue = q->items; i < max; i++) {
+		kfifo_in(&q->queue, (void *)&iue, sizeof(void *));
+		iue->sbuf = ring[i];
+		iue++;
+	}
+	return 0;
+
+free_pool:
+	kfree(q->pool);
+	return -ENOMEM;
+}
+
+static void srp_iu_pool_free(struct srp_queue *q)
+{
+	kfree(q->items);
+	kfree(q->pool);
+}
+
+static struct srp_buf **srp_ring_alloc(struct device *dev,
+				       size_t max, size_t size)
+{
+	struct srp_buf **ring;
+	int i;
+
+	ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
+	if (!ring)
+		return NULL;
+
+	for (i = 0; i < max; i++) {
+		ring[i] = kzalloc(sizeof(*ring[i]), GFP_KERNEL);
+		if (!ring[i])
+			goto out;
+		ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
+						  GFP_KERNEL);
+		if (!ring[i]->buf)
+			goto out;
+	}
+	return ring;
+
+out:
+	for (i = 0; i < max && ring[i]; i++) {
+		if (ring[i]->buf) {
+			dma_free_coherent(dev, size, ring[i]->buf,
+					  ring[i]->dma);
+		}
+		kfree(ring[i]);
+	}
+	kfree(ring);
+
+	return NULL;
+}
+
+static void srp_ring_free(struct device *dev, struct srp_buf **ring,
+			  size_t max, size_t size)
+{
+	int i;
+
+	for (i = 0; i < max; i++) {
+		dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
+		kfree(ring[i]);
+	}
+	kfree(ring);
+}
+
+int srp_target_alloc(struct srp_target *target, struct device *dev,
+		     size_t nr, size_t iu_size)
+{
+	int err;
+
+	spin_lock_init(&target->lock);
+
+	target->dev = dev;
+
+	target->srp_iu_size = iu_size;
+	target->rx_ring_size = nr;
+	target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
+	if (!target->rx_ring)
+		return -ENOMEM;
+	err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
+	if (err)
+		goto free_ring;
+
+	dev_set_drvdata(target->dev, target);
+	return 0;
+
+free_ring:
+	srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
+	return -ENOMEM;
+}
+
+void srp_target_free(struct srp_target *target)
+{
+	dev_set_drvdata(target->dev, NULL);
+	srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
+		      target->srp_iu_size);
+	srp_iu_pool_free(&target->iu_queue);
+}
+
+struct iu_entry *srp_iu_get(struct srp_target *target)
+{
+	struct iu_entry *iue = NULL;
+
+	if (kfifo_out_locked(&target->iu_queue.queue, (void *)&iue,
+			     sizeof(void *),
+			     &target->iu_queue.lock) != sizeof(void *)) {
+		WARN_ONCE(1, "unexpected fifo state");
+		return NULL;
+	}
+	if (!iue)
+		return iue;
+	iue->target = target;
+	iue->flags = 0;
+	return iue;
+}
+
+void srp_iu_put(struct iu_entry *iue)
+{
+	kfifo_in_locked(&iue->target->iu_queue.queue, (void *)&iue,
+			sizeof(void *), &iue->target->iu_queue.lock);
+}
+
+static int srp_direct_data(struct ibmvscsis_cmd *cmd, struct srp_direct_buf *md,
+			   enum dma_data_direction dir, srp_rdma_t rdma_io,
+			   int dma_map, int ext_desc)
+{
+	struct iu_entry *iue = NULL;
+	struct scatterlist *sg = NULL;
+	int err, nsg = 0, len;
+
+	if (dma_map) {
+		iue = cmd->iue;
+		sg = cmd->se_cmd.t_data_sg;
+		nsg = dma_map_sg(iue->target->dev, sg, cmd->se_cmd.t_data_nents,
+				 DMA_BIDIRECTIONAL);
+		if (!nsg) {
+			pr_err("fail to map %p %d\n", iue,
+			       cmd->se_cmd.t_data_nents);
+			return 0;
+		}
+		len = min(cmd->se_cmd.data_length, be32_to_cpu(md->len));
+	} else {
+		len = be32_to_cpu(md->len);
+	}
+
+	err = rdma_io(cmd, sg, nsg, md, 1, dir, len);
+
+	if (dma_map)
+		dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+	return err;
+}
+
+static int srp_indirect_data(struct ibmvscsis_cmd *cmd, struct srp_cmd *srp_cmd,
+			     struct srp_indirect_buf *id,
+			     enum dma_data_direction dir, srp_rdma_t rdma_io,
+			     int dma_map, int ext_desc)
+{
+	struct iu_entry *iue = NULL;
+	struct srp_direct_buf *md = NULL;
+	struct scatterlist dummy, *sg = NULL;
+	dma_addr_t token = 0;
+	int err = 0;
+	int nmd, nsg = 0, len;
+
+	if (dma_map || ext_desc) {
+		iue = cmd->iue;
+		sg = cmd->se_cmd.t_data_sg;
+	}
+
+	nmd = be32_to_cpu(id->table_desc.len) / sizeof(struct srp_direct_buf);
+
+	if ((dir == DMA_FROM_DEVICE && nmd == srp_cmd->data_in_desc_cnt) ||
+	    (dir == DMA_TO_DEVICE && nmd == srp_cmd->data_out_desc_cnt)) {
+		md = &id->desc_list[0];
+		goto rdma;
+	}
+
+	if (ext_desc && dma_map) {
+		md = dma_alloc_coherent(iue->target->dev,
+					be32_to_cpu(id->table_desc.len),
+					&token, GFP_KERNEL);
+		if (!md) {
+			pr_err("Can't get dma memory %u\n",
+			       be32_to_cpu(id->table_desc.len));
+			return -ENOMEM;
+		}
+
+		sg_init_one(&dummy, md, be32_to_cpu(id->table_desc.len));
+		sg_dma_address(&dummy) = token;
+		sg_dma_len(&dummy) = be32_to_cpu(id->table_desc.len);
+		err = rdma_io(cmd, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
+			      be32_to_cpu(id->table_desc.len));
+		if (err) {
+			pr_err("Error copying indirect table %d\n", err);
+			goto free_mem;
+		}
+	} else {
+		pr_err("This command uses external indirect buffer\n");
+		return -EINVAL;
+	}
+
+rdma:
+	if (dma_map) {
+		nsg = dma_map_sg(iue->target->dev, sg, cmd->se_cmd.t_data_nents,
+				 DMA_BIDIRECTIONAL);
+		if (!nsg) {
+			pr_err("fail to map %p %d\n", iue,
+			       cmd->se_cmd.t_data_nents);
+			err = -EIO;
+			goto free_mem;
+		}
+		len = min(cmd->se_cmd.data_length, be32_to_cpu(id->len));
+	} else {
+		len = be32_to_cpu(id->len);
+	}
+
+	err = rdma_io(cmd, sg, nsg, md, nmd, dir, len);
+
+	if (dma_map)
+		dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+free_mem:
+	if (token && dma_map) {
+		dma_free_coherent(iue->target->dev,
+				  be32_to_cpu(id->table_desc.len), md, token);
+	}
+	return err;
+}
+
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+	int size = 0;
+	u8 fmt = cmd->buf_fmt >> 4;
+
+	switch (fmt) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		size = sizeof(struct srp_direct_buf);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		size = sizeof(struct srp_indirect_buf) +
+			sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
+		break;
+	default:
+		pr_err("client error. Invalid data_out_format %x\n", fmt);
+		break;
+	}
+	return size;
+}
+
+/*
+ * TODO: this can be called multiple times for a single command if it
+ * has very long data.
+ */
+int srp_transfer_data(struct ibmvscsis_cmd *cmd, struct srp_cmd *srp_cmd,
+		      srp_rdma_t rdma_io, int dma_map, int ext_desc)
+{
+	struct srp_direct_buf *md;
+	struct srp_indirect_buf *id;
+	enum dma_data_direction dir;
+	int offset, err = 0;
+	u8 format;
+
+	if (!cmd->se_cmd.t_data_nents)
+		return 0;
+
+	offset = srp_cmd->add_cdb_len & ~3;
+
+	dir = srp_cmd_direction(srp_cmd);
+	if (dir == DMA_FROM_DEVICE)
+		offset += data_out_desc_size(srp_cmd);
+
+	if (dir == DMA_TO_DEVICE)
+		format = srp_cmd->buf_fmt >> 4;
+	else
+		format = srp_cmd->buf_fmt & ((1U << 4) - 1);
+
+	switch (format) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		md = (struct srp_direct_buf *)(srp_cmd->add_data + offset);
+		err = srp_direct_data(cmd, md, dir, rdma_io, dma_map, ext_desc);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		id = (struct srp_indirect_buf *)(srp_cmd->add_data + offset);
+		err = srp_indirect_data(cmd, srp_cmd, id, dir, rdma_io, dma_map,
+					ext_desc);
+		break;
+	default:
+		pr_err("Unknown format %d %x\n", dir, format);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
+{
+	struct srp_direct_buf *md;
+	struct srp_indirect_buf *id;
+	u64 len = 0;
+	uint offset = cmd->add_cdb_len & ~3;
+	u8 fmt;
+
+	if (dir == DMA_TO_DEVICE) {
+		fmt = cmd->buf_fmt >> 4;
+	} else {
+		fmt = cmd->buf_fmt & ((1U << 4) - 1);
+		offset += data_out_desc_size(cmd);
+	}
+
+	switch (fmt) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		md = (struct srp_direct_buf *)(cmd->add_data + offset);
+		len = be32_to_cpu(md->len);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		id = (struct srp_indirect_buf *)(cmd->add_data + offset);
+		len = be32_to_cpu(id->len);
+		break;
+	default:
+		pr_err("invalid data format %x\n", fmt);
+		break;
+	}
+	return len;
+}
+
+int srp_get_desc_table(struct srp_cmd *srp_cmd, enum dma_data_direction *dir,
+		       u64 *data_len)
+{
+	struct srp_indirect_buf *idb;
+	struct srp_direct_buf *db;
+	uint add_cdb_offset;
+	int rc;
+
+	/*
+	 * The pointer computations below will only be compiled correctly
+	 * if srp_cmd::add_data is declared as s8*, u8*, s8[] or u8[], so check
+	 * whether srp_cmd::add_data has been declared as a byte pointer.
+	 */
+	BUILD_BUG_ON(!__same_type(srp_cmd->add_data[0], (s8)0)
+		     && !__same_type(srp_cmd->add_data[0], (u8)0));
+
+	BUG_ON(!dir);
+	BUG_ON(!data_len);
+
+	rc = 0;
+	*data_len = 0;
+
+	*dir = DMA_NONE;
+
+	if (srp_cmd->buf_fmt & 0xf)
+		*dir = DMA_FROM_DEVICE;
+	else if (srp_cmd->buf_fmt >> 4)
+		*dir = DMA_TO_DEVICE;
+
+	add_cdb_offset = srp_cmd->add_cdb_len & ~3;
+	if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_DIRECT) ||
+	    ((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_DIRECT)) {
+		db = (struct srp_direct_buf *)(srp_cmd->add_data
+					       + add_cdb_offset);
+		*data_len = be32_to_cpu(db->len);
+	} else if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_INDIRECT) ||
+		   ((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_INDIRECT)) {
+		idb = (struct srp_indirect_buf *)(srp_cmd->add_data
+						  + add_cdb_offset);
+
+		*data_len = be32_to_cpu(idb->len);
+	}
+	return rc;
+}
+
+MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/scsi/ibmvscsi_tgt/libsrp.h
+++ linux-4.4.0/drivers/scsi/ibmvscsi_tgt/libsrp.h
@@ -0,0 +1,123 @@
+#ifndef __LIBSRP_H__
+#define __LIBSRP_H__
+
+#include <linux/list.h>
+#include <linux/kfifo.h>
+#include <scsi/srp.h>
+
+enum srp_valid {
+	INVALIDATE_CMD_RESP_EL = 0,
+	VALID_CMD_RESP_EL = 0x80,
+	VALID_INIT_MSG = 0xC0,
+	VALID_TRANS_EVENT = 0xFF
+};
+
+enum srp_format {
+	SRP_FORMAT = 1,
+	MAD_FORMAT = 2,
+	OS400_FORMAT = 3,
+	AIX_FORMAT = 4,
+	LINUX_FORMAT = 5,
+	MESSAGE_IN_CRQ = 6
+};
+
+enum srp_init_msg {
+	INIT_MSG = 1,
+	INIT_COMPLETE_MSG = 2
+};
+
+enum srp_trans_event {
+	UNUSED_FORMAT = 0,
+	PARTNER_FAILED = 1,
+	PARTNER_DEREGISTER = 2,
+	MIGRATED = 6
+};
+
+enum srp_status {
+	HEADER_DESCRIPTOR = 0xF1,
+	PING = 0xF5,
+	PING_RESPONSE = 0xF6
+};
+
+enum srp_mad_version {
+	MAD_VERSION_1 = 1
+};
+
+enum srp_os_type {
+	OS400 = 1,
+	LINUX = 2,
+	AIX = 3,
+	OFW = 4
+};
+
+enum srp_task_attributes {
+	SRP_SIMPLE_TASK = 0,
+	SRP_HEAD_TASK = 1,
+	SRP_ORDERED_TASK = 2,
+	SRP_ACA_TASK = 4
+};
+
+enum {
+	SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE           = 0,
+	SRP_REQUEST_FIELDS_INVALID                      = 2,
+	SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED      = 4,
+	SRP_TASK_MANAGEMENT_FUNCTION_FAILED             = 5
+};
+
+struct srp_buf {
+	dma_addr_t dma;
+	void *buf;
+};
+
+struct srp_queue {
+	void *pool;
+	void *items;
+	struct kfifo queue;
+	spinlock_t lock;
+};
+
+struct srp_target {
+	struct device *dev;
+
+	spinlock_t lock;
+	struct list_head cmd_queue;
+
+	size_t srp_iu_size;
+	struct srp_queue iu_queue;
+	size_t rx_ring_size;
+	struct srp_buf **rx_ring;
+
+	void *ldata;
+};
+
+struct iu_entry {
+	struct srp_target *target;
+
+	struct list_head ilist;
+	dma_addr_t remote_token;
+	unsigned long flags;
+
+	struct srp_buf *sbuf;
+	u16 iu_len;
+};
+
+struct ibmvscsis_cmd;
+
+typedef int (srp_rdma_t)(struct ibmvscsis_cmd *, struct scatterlist *, int,
+			 struct srp_direct_buf *, int,
+			 enum dma_data_direction, unsigned int);
+int srp_target_alloc(struct srp_target *, struct device *, size_t, size_t);
+void srp_target_free(struct srp_target *);
+struct iu_entry *srp_iu_get(struct srp_target *);
+void srp_iu_put(struct iu_entry *);
+int srp_transfer_data(struct ibmvscsis_cmd *, struct srp_cmd *,
+		      srp_rdma_t, int, int);
+u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir);
+int srp_get_desc_table(struct srp_cmd *srp_cmd, enum dma_data_direction *dir,
+		       u64 *data_len);
+static inline int srp_cmd_direction(struct srp_cmd *cmd)
+{
+	return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+}
+
+#endif
--- linux-4.4.0.orig/drivers/scsi/initio.c
+++ linux-4.4.0/drivers/scsi/initio.c
@@ -110,11 +110,6 @@
 #define i91u_MAXQUEUE		2
 #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
 
-#define I950_DEVICE_ID	0x9500	/* Initio's inic-950 product ID   */
-#define I940_DEVICE_ID	0x9400	/* Initio's inic-940 product ID   */
-#define I935_DEVICE_ID	0x9401	/* Initio's inic-935 product ID   */
-#define I920_DEVICE_ID	0x0002	/* Initio's other product ID      */
-
 #ifdef DEBUG_i91u
 static unsigned int i91u_debug = DEBUG_DEFAULT;
 #endif
@@ -127,17 +122,6 @@
 
 static void i91uSCBPost(u8 * pHcb, u8 * pScb);
 
-/* PCI Devices supported by this driver */
-static struct pci_device_id i91u_pci_devices[] = {
-	{ PCI_VENDOR_ID_INIT,  I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_INIT,  I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_INIT,  I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_INIT,  I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ }
-};
-MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
-
 #define DEBUG_INTERRUPT 0
 #define DEBUG_QUEUE     0
 #define DEBUG_STATE     0
--- linux-4.4.0.orig/drivers/scsi/ipr.c
+++ linux-4.4.0/drivers/scsi/ipr.c
@@ -835,8 +835,10 @@
 
 	qc->err_mask |= AC_ERR_OTHER;
 	sata_port->ioasa.status |= ATA_BUSY;
-	list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 	ata_qc_complete(qc);
+	if (ipr_cmd->eh_comp)
+		complete(ipr_cmd->eh_comp);
+	list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 }
 
 /**
@@ -4003,13 +4005,17 @@
 	struct ipr_sglist *sglist;
 	char fname[100];
 	char *src;
-	int len, result, dnld_size;
+	char *endline;
+	int result, dnld_size;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	len = snprintf(fname, 99, "%s", buf);
-	fname[len-1] = '\0';
+	snprintf(fname, sizeof(fname), "%s", buf);
+
+	endline = strchr(fname, '\n');
+	if (endline)
+		*endline = '\0';
 
 	if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
 		dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
@@ -5860,8 +5866,10 @@
 		res->in_erp = 0;
 	}
 	scsi_dma_unmap(ipr_cmd->scsi_cmd);
-	list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 	scsi_cmd->scsi_done(scsi_cmd);
+	if (ipr_cmd->eh_comp)
+		complete(ipr_cmd->eh_comp);
+	list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 }
 
 /**
@@ -6206,7 +6214,12 @@
 		break;
 	case IPR_IOASC_MED_DO_NOT_REALLOC: /* prevent retries */
 	case IPR_IOASA_IR_DUAL_IOA_DISABLED:
-		scsi_cmd->result |= (DID_PASSTHROUGH << 16);
+		/*
+		 * exception: do not set DID_PASSTHROUGH on CHECK CONDITION
+		 * so SCSI mid-layer and upper layers handle it accordingly.
+		 */
+		if (scsi_cmd->result != SAM_STAT_CHECK_CONDITION)
+			scsi_cmd->result |= (DID_PASSTHROUGH << 16);
 		break;
 	case IPR_IOASC_BUS_WAS_RESET:
 	case IPR_IOASC_BUS_WAS_RESET_BY_OTHER:
@@ -6251,8 +6264,10 @@
 	}
 
 	scsi_dma_unmap(ipr_cmd->scsi_cmd);
-	list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 	scsi_cmd->scsi_done(scsi_cmd);
+	if (ipr_cmd->eh_comp)
+		complete(ipr_cmd->eh_comp);
+	list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 }
 
 /**
@@ -6278,8 +6293,10 @@
 		scsi_dma_unmap(scsi_cmd);
 
 		spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags);
-		list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 		scsi_cmd->scsi_done(scsi_cmd);
+		if (ipr_cmd->eh_comp)
+			complete(ipr_cmd->eh_comp);
+		list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 		spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags);
 	} else {
 		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -9718,6 +9735,7 @@
 	ioa_cfg->max_devs_supported = ipr_max_devs;
 
 	if (ioa_cfg->sis64) {
+		host->max_channel = IPR_MAX_SIS64_BUSES;
 		host->max_id = IPR_MAX_SIS64_TARGETS_PER_BUS;
 		host->max_lun = IPR_MAX_SIS64_LUNS_PER_TARGET;
 		if (ipr_max_devs > IPR_MAX_SIS64_DEVS)
@@ -9726,6 +9744,7 @@
 					   + ((sizeof(struct ipr_config_table_entry64)
 					       * ioa_cfg->max_devs_supported)));
 	} else {
+		host->max_channel = IPR_VSET_BUS;
 		host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS;
 		host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET;
 		if (ipr_max_devs > IPR_MAX_PHYSICAL_DEVS)
@@ -9735,7 +9754,6 @@
 					       * ioa_cfg->max_devs_supported)));
 	}
 
-	host->max_channel = IPR_VSET_BUS;
 	host->unique_id = host->host_no;
 	host->max_cmd_len = IPR_MAX_CDB_LEN;
 	host->can_queue = ioa_cfg->max_cmds;
@@ -10091,6 +10109,7 @@
 		ioa_cfg->intr_flag = IPR_USE_MSI;
 	else {
 		ioa_cfg->intr_flag = IPR_USE_LSI;
+		ioa_cfg->clear_isr = 1;
 		ioa_cfg->nvectors = 1;
 		dev_info(&pdev->dev, "Cannot enable MSI.\n");
 	}
--- linux-4.4.0.orig/drivers/scsi/ipr.h
+++ linux-4.4.0/drivers/scsi/ipr.h
@@ -1301,6 +1301,7 @@
 #define IPR_ARRAY_VIRTUAL_BUS			0x1
 #define IPR_VSET_VIRTUAL_BUS			0x2
 #define IPR_IOAFP_VIRTUAL_BUS			0x3
+#define IPR_MAX_SIS64_BUSES			0x4
 
 #define IPR_GET_RES_PHYS_LOC(res) \
 	(((res)->bus << 24) | ((res)->target << 8) | (res)->lun)
--- linux-4.4.0.orig/drivers/scsi/ips.c
+++ linux-4.4.0/drivers/scsi/ips.c
@@ -3500,6 +3500,7 @@
 
 		case START_STOP:
 			scb->scsi_cmd->result = DID_OK << 16;
+			break;
 
 		case TEST_UNIT_READY:
 		case INQUIRY:
--- linux-4.4.0.orig/drivers/scsi/isci/host.c
+++ linux-4.4.0/drivers/scsi/isci/host.c
@@ -2717,9 +2717,9 @@
  *    the task management request.
  * @task_request: the handle to the task request object to start.
  */
-enum sci_task_status sci_controller_start_task(struct isci_host *ihost,
-					       struct isci_remote_device *idev,
-					       struct isci_request *ireq)
+enum sci_status sci_controller_start_task(struct isci_host *ihost,
+					  struct isci_remote_device *idev,
+					  struct isci_request *ireq)
 {
 	enum sci_status status;
 
@@ -2728,7 +2728,7 @@
 			 "%s: SCIC Controller starting task from invalid "
 			 "state\n",
 			 __func__);
-		return SCI_TASK_FAILURE_INVALID_STATE;
+		return SCI_FAILURE_INVALID_STATE;
 	}
 
 	status = sci_remote_device_start_task(ihost, idev, ireq);
--- linux-4.4.0.orig/drivers/scsi/isci/host.h
+++ linux-4.4.0/drivers/scsi/isci/host.h
@@ -490,7 +490,7 @@
 	struct isci_remote_device *idev,
 	struct isci_request *ireq);
 
-enum sci_task_status sci_controller_start_task(
+enum sci_status sci_controller_start_task(
 	struct isci_host *ihost,
 	struct isci_remote_device *idev,
 	struct isci_request *ireq);
--- linux-4.4.0.orig/drivers/scsi/isci/init.c
+++ linux-4.4.0/drivers/scsi/isci/init.c
@@ -595,6 +595,13 @@
 	shost->max_lun = ~0;
 	shost->max_cmd_len = MAX_COMMAND_SIZE;
 
+	/* turn on DIF support */
+	scsi_host_set_prot(shost,
+			   SHOST_DIF_TYPE1_PROTECTION |
+			   SHOST_DIF_TYPE2_PROTECTION |
+			   SHOST_DIF_TYPE3_PROTECTION);
+	scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
+
 	err = scsi_add_host(shost, &pdev->dev);
 	if (err)
 		goto err_shost;
@@ -682,13 +689,6 @@
 			goto err_host_alloc;
 		}
 		pci_info->hosts[i] = h;
-
-		/* turn on DIF support */
-		scsi_host_set_prot(to_shost(h),
-				   SHOST_DIF_TYPE1_PROTECTION |
-				   SHOST_DIF_TYPE2_PROTECTION |
-				   SHOST_DIF_TYPE3_PROTECTION);
-		scsi_host_set_guard(to_shost(h), SHOST_DIX_GUARD_CRC);
 	}
 
 	err = isci_setup_interrupts(pdev);
--- linux-4.4.0.orig/drivers/scsi/isci/remote_node_context.c
+++ linux-4.4.0/drivers/scsi/isci/remote_node_context.c
@@ -66,6 +66,9 @@
 {
 	static const char * const strings[] = RNC_STATES;
 
+	if (state >= ARRAY_SIZE(strings))
+		return "UNKNOWN";
+
 	return strings[state];
 }
 #undef C
--- linux-4.4.0.orig/drivers/scsi/isci/request.c
+++ linux-4.4.0/drivers/scsi/isci/request.c
@@ -1626,9 +1626,9 @@
 
 	if (status == SCI_SUCCESS) {
 		if (ireq->stp.rsp.status & ATA_ERR)
-			status = SCI_IO_FAILURE_RESPONSE_VALID;
+			status = SCI_FAILURE_IO_RESPONSE_VALID;
 	} else {
-		status = SCI_IO_FAILURE_RESPONSE_VALID;
+		status = SCI_FAILURE_IO_RESPONSE_VALID;
 	}
 
 	if (status != SCI_SUCCESS) {
--- linux-4.4.0.orig/drivers/scsi/isci/task.c
+++ linux-4.4.0/drivers/scsi/isci/task.c
@@ -258,7 +258,7 @@
 				 struct isci_tmf *tmf, unsigned long timeout_ms)
 {
 	DECLARE_COMPLETION_ONSTACK(completion);
-	enum sci_task_status status = SCI_TASK_FAILURE;
+	enum sci_status status = SCI_FAILURE;
 	struct isci_request *ireq;
 	int ret = TMF_RESP_FUNC_FAILED;
 	unsigned long flags;
@@ -301,7 +301,7 @@
 	/* start the TMF io. */
 	status = sci_controller_start_task(ihost, idev, ireq);
 
-	if (status != SCI_TASK_SUCCESS) {
+	if (status != SCI_SUCCESS) {
 		dev_dbg(&ihost->pdev->dev,
 			 "%s: start_io failed - status = 0x%x, request = %p\n",
 			 __func__,
--- linux-4.4.0.orig/drivers/scsi/iscsi_boot_sysfs.c
+++ linux-4.4.0/drivers/scsi/iscsi_boot_sysfs.c
@@ -319,7 +319,7 @@
 	boot_kobj->kobj.kset = boot_kset->kset;
 	if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype,
 				 NULL, name, index)) {
-		kfree(boot_kobj);
+		kobject_put(&boot_kobj->kobj);
 		return NULL;
 	}
 	boot_kobj->data = data;
--- linux-4.4.0.orig/drivers/scsi/iscsi_tcp.c
+++ linux-4.4.0/drivers/scsi/iscsi_tcp.c
@@ -593,9 +593,9 @@
 	iscsi_sw_tcp_conn_restore_callbacks(conn);
 	sock_put(sock->sk);
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	tcp_sw_conn->sock = NULL;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	sockfd_put(sock);
 }
 
@@ -663,10 +663,10 @@
 	if (err)
 		goto free_socket;
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	/* bind iSCSI connection and socket */
 	tcp_sw_conn->sock = sock;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	/* setup Socket parameters */
 	sk = sock->sk;
@@ -727,9 +727,9 @@
 	case ISCSI_PARAM_CONN_PORT:
 	case ISCSI_PARAM_CONN_ADDRESS:
 	case ISCSI_PARAM_LOCAL_PORT:
-		spin_lock_bh(&conn->session->frwd_lock);
+		spin_lock_bh(&conn->session->lock);
 		if (!tcp_sw_conn || !tcp_sw_conn->sock) {
-			spin_unlock_bh(&conn->session->frwd_lock);
+			spin_unlock_bh(&conn->session->lock);
 			return -ENOTCONN;
 		}
 		if (param == ISCSI_PARAM_LOCAL_PORT)
@@ -738,7 +738,7 @@
 		else
 			rc = kernel_getpeername(tcp_sw_conn->sock,
 						(struct sockaddr *)&addr, &len);
-		spin_unlock_bh(&conn->session->frwd_lock);
+		spin_unlock_bh(&conn->session->lock);
 		if (rc)
 			return rc;
 
@@ -755,7 +755,7 @@
 				       enum iscsi_host_param param, char *buf)
 {
 	struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost);
-	struct iscsi_session *session = tcp_sw_host->session;
+	struct iscsi_session *session;
 	struct iscsi_conn *conn;
 	struct iscsi_tcp_conn *tcp_conn;
 	struct iscsi_sw_tcp_conn *tcp_sw_conn;
@@ -764,31 +764,33 @@
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_IPADDRESS:
+		session = tcp_sw_host->session;
 		if (!session)
 			return -ENOTCONN;
 
-		spin_lock_bh(&session->frwd_lock);
+		spin_lock_bh(&session->lock);
 		conn = session->leadconn;
 		if (!conn) {
-			spin_unlock_bh(&session->frwd_lock);
+			spin_unlock_bh(&session->lock);
 			return -ENOTCONN;
 		}
 		tcp_conn = conn->dd_data;
 
 		tcp_sw_conn = tcp_conn->dd_data;
 		if (!tcp_sw_conn->sock) {
-			spin_unlock_bh(&session->frwd_lock);
+			spin_unlock_bh(&session->lock);
 			return -ENOTCONN;
 		}
 
 		rc = kernel_getsockname(tcp_sw_conn->sock,
 					(struct sockaddr *)&addr, &len);
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		if (rc)
 			return rc;
 
 		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
-						 &addr, param, buf);
+						 &addr,
+						 (enum iscsi_param)param, buf);
 	default:
 		return iscsi_host_get_param(shost, param, buf);
 	}
@@ -851,12 +853,14 @@
 	if (!cls_session)
 		goto remove_host;
 	session = cls_session->dd_data;
-	tcp_sw_host = iscsi_host_priv(shost);
-	tcp_sw_host->session = session;
 
 	shost->can_queue = session->scsi_cmds_max;
 	if (iscsi_tcp_r2tpool_alloc(session))
 		goto remove_session;
+
+	/* We are now fully setup so expose the session to sysfs. */
+	tcp_sw_host = iscsi_host_priv(shost);
+	tcp_sw_host->session = session;
 	return cls_session;
 
 remove_session:
@@ -871,11 +875,22 @@
 static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
 {
 	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	struct iscsi_session *session = cls_session->dd_data;
 
-	iscsi_tcp_r2tpool_free(cls_session->dd_data);
-	iscsi_session_teardown(cls_session);
+	if (WARN_ON_ONCE(session->leadconn))
+		return;
 
+	iscsi_session_remove(cls_session);
+	/*
+	 * Our get_host_param needs to access the session, so remove the
+	 * host from sysfs before freeing the session to make sure userspace
+	 * is no longer accessing the callout.
+	 */
 	iscsi_host_remove(shost);
+
+	iscsi_tcp_r2tpool_free(cls_session->dd_data);
+
+	iscsi_session_free(cls_session);
 	iscsi_host_free(shost);
 }
 
--- linux-4.4.0.orig/drivers/scsi/libfc/fc_disc.c
+++ linux-4.4.0/drivers/scsi/libfc/fc_disc.c
@@ -595,8 +595,12 @@
 	mutex_lock(&disc->disc_mutex);
 	if (PTR_ERR(fp) == -FC_EX_CLOSED)
 		goto out;
-	if (IS_ERR(fp))
-		goto redisc;
+	if (IS_ERR(fp)) {
+		mutex_lock(&disc->disc_mutex);
+		fc_disc_restart(disc);
+		mutex_unlock(&disc->disc_mutex);
+		goto out;
+	}
 
 	cp = fc_frame_payload_get(fp, sizeof(*cp));
 	if (!cp)
@@ -621,7 +625,7 @@
 				new_rdata->disc_id = disc->disc_id;
 				lport->tt.rport_login(new_rdata);
 			}
-			goto out;
+			goto free_fp;
 		}
 		rdata->disc_id = disc->disc_id;
 		lport->tt.rport_login(rdata);
@@ -635,6 +639,8 @@
 redisc:
 		fc_disc_restart(disc);
 	}
+free_fp:
+	fc_frame_free(fp);
 out:
 	mutex_unlock(&disc->disc_mutex);
 	kref_put(&rdata->kref, lport->tt.rport_destroy);
--- linux-4.4.0.orig/drivers/scsi/libfc/fc_exch.c
+++ linux-4.4.0/drivers/scsi/libfc/fc_exch.c
@@ -1577,8 +1577,13 @@
 		rc = fc_exch_done_locked(ep);
 		WARN_ON(fc_seq_exch(sp) != ep);
 		spin_unlock_bh(&ep->ex_lock);
-		if (!rc)
+		if (!rc) {
 			fc_exch_delete(ep);
+		} else {
+			FC_EXCH_DBG(ep, "ep is completed already,"
+					"hence skip calling the resp\n");
+			goto skip_resp;
+		}
 	}
 
 	/*
@@ -1597,6 +1602,7 @@
 	if (!fc_invoke_resp(ep, sp, fp))
 		fc_frame_free(fp);
 
+skip_resp:
 	fc_exch_release(ep);
 	return;
 rel:
@@ -1841,10 +1847,16 @@
 
 	fc_exch_hold(ep);
 
-	if (!rc)
+	if (!rc) {
 		fc_exch_delete(ep);
+	} else {
+		FC_EXCH_DBG(ep, "ep is completed already,"
+				"hence skip calling the resp\n");
+		goto skip_resp;
+	}
 
 	fc_invoke_resp(ep, sp, ERR_PTR(-FC_EX_CLOSED));
+skip_resp:
 	fc_seq_set_resp(sp, NULL, ep->arg);
 	fc_exch_release(ep);
 }
@@ -2499,7 +2511,7 @@
 
 	/* lport lock ? */
 	if (!lport || lport->state == LPORT_ST_DISABLED) {
-		FC_LPORT_DBG(lport, "Receiving frames for an lport that "
+		FC_LIBFC_DBG("Receiving frames for an lport that "
 			     "has not been initialized correctly\n");
 		fc_frame_free(fp);
 		return;
--- linux-4.4.0.orig/drivers/scsi/libfc/fc_lport.c
+++ linux-4.4.0/drivers/scsi/libfc/fc_lport.c
@@ -248,6 +248,12 @@
 		kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
 	}
 	lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid);
+	if (!lport->ptp_rdata) {
+		printk(KERN_WARNING "libfc: Failed to setup lport 0x%x\n",
+			lport->port_id);
+		mutex_unlock(&lport->disc.disc_mutex);
+		return;
+	}
 	kref_get(&lport->ptp_rdata->kref);
 	lport->ptp_rdata->ids.port_name = remote_wwpn;
 	lport->ptp_rdata->ids.node_name = remote_wwnn;
@@ -1739,14 +1745,14 @@
 	    fc_frame_payload_op(fp) != ELS_LS_ACC) {
 		FC_LPORT_DBG(lport, "FLOGI not accepted or bad response\n");
 		fc_lport_error(lport, fp);
-		goto err;
+		goto out;
 	}
 
 	flp = fc_frame_payload_get(fp, sizeof(*flp));
 	if (!flp) {
 		FC_LPORT_DBG(lport, "FLOGI bad response\n");
 		fc_lport_error(lport, fp);
-		goto err;
+		goto out;
 	}
 
 	mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1756,7 +1762,7 @@
 		FC_LPORT_DBG(lport, "FLOGI bad mfs:%hu response, "
 			     "lport->mfs:%hu\n", mfs, lport->mfs);
 		fc_lport_error(lport, fp);
-		goto err;
+		goto out;
 	}
 
 	if (mfs <= lport->mfs) {
--- linux-4.4.0.orig/drivers/scsi/libfc/fc_rport.c
+++ linux-4.4.0/drivers/scsi/libfc/fc_rport.c
@@ -121,12 +121,15 @@
 					     u32 port_id)
 {
 	struct fc_rport_priv *rdata;
+	size_t rport_priv_size = sizeof(*rdata);
 
 	rdata = lport->tt.rport_lookup(lport, port_id);
 	if (rdata)
 		return rdata;
 
-	rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL);
+	if (lport->rport_priv_size > 0)
+		rport_priv_size = lport->rport_priv_size;
+	rdata = kzalloc(rport_priv_size, GFP_KERNEL);
 	if (!rdata)
 		return NULL;
 
--- linux-4.4.0.orig/drivers/scsi/libiscsi.c
+++ linux-4.4.0/drivers/scsi/libiscsi.c
@@ -283,11 +283,11 @@
 		 */
 		if (opcode != ISCSI_OP_SCSI_DATA_OUT) {
 			iscsi_conn_printk(KERN_INFO, conn,
-					  "task [op %x/%x itt "
+					  "task [op %x itt "
 					  "0x%x/0x%x] "
 					  "rejected.\n",
-					  task->hdr->opcode, opcode,
-					  task->itt, task->hdr_itt);
+					  opcode, task->itt,
+					  task->hdr_itt);
 			return -EACCES;
 		}
 		/*
@@ -296,10 +296,10 @@
 		 */
 		if (conn->session->fast_abort) {
 			iscsi_conn_printk(KERN_INFO, conn,
-					  "task [op %x/%x itt "
+					  "task [op %x itt "
 					  "0x%x/0x%x] fast abort.\n",
-					  task->hdr->opcode, opcode,
-					  task->itt, task->hdr_itt);
+					  opcode, task->itt,
+					  task->hdr_itt);
 			return -EACCES;
 		}
 		break;
@@ -477,7 +477,7 @@
  * iscsi_free_task - free a task
  * @task: iscsi cmd task
  *
- * Must be called with session back_lock.
+ * Must be called with session lock.
  * This function returns the scsi command to scsi-ml or cleans
  * up mgmt tasks then returns the task to the pool.
  */
@@ -531,10 +531,9 @@
 {
 	struct iscsi_session *session = task->conn->session;
 
-	/* regular RX path uses back_lock */
-	spin_lock_bh(&session->back_lock);
+	spin_lock_bh(&session->lock);
 	__iscsi_put_task(task);
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&session->lock);
 }
 EXPORT_SYMBOL_GPL(iscsi_put_task);
 
@@ -543,7 +542,7 @@
  * @task: iscsi cmd task
  * @state: state to complete task with
  *
- * Must be called with session back_lock.
+ * Must be called with session lock.
  */
 static void iscsi_complete_task(struct iscsi_task *task, int state)
 {
@@ -560,14 +559,18 @@
 	WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
 	task->state = state;
 
-	if (!list_empty(&task->running))
+	spin_lock_bh(&conn->taskqueuelock);
+	if (!list_empty(&task->running)) {
+		pr_debug_once("%s while task on list", __func__);
 		list_del_init(&task->running);
+	}
+	spin_unlock_bh(&conn->taskqueuelock);
 
 	if (conn->task == task)
 		conn->task = NULL;
 
-	if (conn->ping_task == task)
-		conn->ping_task = NULL;
+	if (READ_ONCE(conn->ping_task) == task)
+		WRITE_ONCE(conn->ping_task, NULL);
 
 	/* release get from queueing */
 	__iscsi_put_task(task);
@@ -582,7 +585,7 @@
  * This is used when drivers do not need or cannot perform
  * lower level pdu processing.
  *
- * Called with session back_lock
+ * Called with session lock
  */
 void iscsi_complete_scsi_task(struct iscsi_task *task,
 			      uint32_t exp_cmdsn, uint32_t max_cmdsn)
@@ -599,7 +602,7 @@
 
 
 /*
- * session back_lock must be held and if not called for a task that is
+ * session lock must be held and if not called for a task that is
  * still pending or from the xmit thread, then xmit thread must
  * be suspended.
  */
@@ -639,10 +642,7 @@
 		scsi_in(sc)->resid = scsi_in(sc)->length;
 	}
 
-	/* regular RX path uses back_lock */
-	spin_lock_bh(&conn->session->back_lock);
 	iscsi_complete_task(task, state);
-	spin_unlock_bh(&conn->session->back_lock);
 }
 
 static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -776,6 +776,9 @@
 						   task->conn->session->age);
 	}
 
+	if (unlikely(READ_ONCE(conn->ping_task) == INVALID_SCSI_TASK))
+		WRITE_ONCE(conn->ping_task, task);
+
 	if (!ihost->workq) {
 		if (iscsi_prep_mgmt_task(conn, task))
 			goto free_task;
@@ -783,17 +786,16 @@
 		if (session->tt->xmit_task(task))
 			goto free_task;
 	} else {
+		spin_lock_bh(&conn->taskqueuelock);
 		list_add_tail(&task->running, &conn->mgmtqueue);
+		spin_unlock_bh(&conn->taskqueuelock);
 		iscsi_conn_queue_work(conn);
 	}
 
 	return task;
 
 free_task:
-	/* regular RX path uses back_lock */
-	spin_lock_bh(&session->back_lock);
 	__iscsi_put_task(task);
-	spin_unlock_bh(&session->back_lock);
 	return NULL;
 }
 
@@ -804,10 +806,10 @@
 	struct iscsi_session *session = conn->session;
 	int err = 0;
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
 		err = -EPERM;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	return err;
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
@@ -981,8 +983,11 @@
         struct iscsi_nopout hdr;
 	struct iscsi_task *task;
 
-	if (!rhdr && conn->ping_task)
-		return -EINVAL;
+	if (!rhdr) {
+		if (READ_ONCE(conn->ping_task))
+			return -EINVAL;
+		WRITE_ONCE(conn->ping_task, INVALID_SCSI_TASK);
+	}
 
 	memset(&hdr, 0, sizeof(struct iscsi_nopout));
 	hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
@@ -997,11 +1002,12 @@
 
 	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
 	if (!task) {
+		if (!rhdr)
+			WRITE_ONCE(conn->ping_task, NULL);
 		iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
 		return -EIO;
 	} else if (!rhdr) {
 		/* only track our nops */
-		conn->ping_task = task;
 		conn->last_ping = jiffies;
 	}
 
@@ -1014,7 +1020,7 @@
 	struct iscsi_conn *conn = task->conn;
 	int rc = 0;
 
-	if (conn->ping_task != task) {
+	if (READ_ONCE(conn->ping_task) != task) {
 		/*
 		 * If this is not in response to one of our
 		 * nops then it must be from userspace.
@@ -1071,19 +1077,14 @@
 		if (opcode != ISCSI_OP_NOOP_OUT)
 			return 0;
 
-		 if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+		 if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG))
 			/*
 			 * nop-out in response to target's nop-out rejected.
 			 * Just resend.
 			 */
-			/* In RX path we are under back lock */
-			spin_unlock(&conn->session->back_lock);
-			spin_lock(&conn->session->frwd_lock);
 			iscsi_send_nopout(conn,
 					  (struct iscsi_nopin*)&rejected_pdu);
-			spin_unlock(&conn->session->frwd_lock);
-			spin_lock(&conn->session->back_lock);
-		} else {
+		else {
 			struct iscsi_task *task;
 			/*
 			 * Our nop as ping got dropped. We know the target
@@ -1119,7 +1120,7 @@
  * This should be used for mgmt tasks like login and nops, or if
  * the LDD's itt space does not include the session age.
  *
- * The session back_lock must be held.
+ * The session lock must be held.
  */
 struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 {
@@ -1148,7 +1149,7 @@
  * @datalen: len of data buffer
  *
  * Completes pdu processing by freeing any resources allocated at
- * queuecommand or send generic. session back_lock must be held and verify
+ * queuecommand or send generic. session lock must be held and verify
  * itt must have been called.
  */
 int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
@@ -1185,12 +1186,7 @@
 			if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
 				break;
 
-			/* In RX path we are under back lock */
-			spin_unlock(&session->back_lock);
-			spin_lock(&session->frwd_lock);
 			iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
-			spin_unlock(&session->frwd_lock);
-			spin_lock(&session->back_lock);
 			break;
 		case ISCSI_OP_REJECT:
 			rc = iscsi_handle_reject(conn, hdr, data, datalen);
@@ -1297,9 +1293,9 @@
 {
 	int rc;
 
-	spin_lock(&conn->session->back_lock);
+	spin_lock(&conn->session->lock);
 	rc = __iscsi_complete_pdu(conn, hdr, data, datalen);
-	spin_unlock(&conn->session->back_lock);
+	spin_unlock(&conn->session->lock);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
@@ -1343,7 +1339,7 @@
  *
  * This should be used for cmd tasks.
  *
- * The session back_lock must be held.
+ * The session lock must be held.
  */
 struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
 {
@@ -1373,15 +1369,15 @@
 	struct iscsi_conn *conn;
 	struct device *dev;
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	conn = session->leadconn;
 	if (session->state == ISCSI_STATE_TERMINATE || !conn) {
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		return;
 	}
 
 	dev = get_device(&conn->cls_conn->dev);
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	if (!dev)
 	        return;
 	/*
@@ -1401,15 +1397,15 @@
 {
 	struct iscsi_session *session = conn->session;
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (session->state == ISCSI_STATE_FAILED) {
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		return;
 	}
 
 	if (conn->stop_stage == 0)
 		session->state = ISCSI_STATE_FAILED;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
@@ -1443,18 +1439,15 @@
 		return -ENODATA;
 
 	__iscsi_get_task(task);
-	spin_unlock_bh(&conn->session->frwd_lock);
+	spin_unlock_bh(&conn->session->lock);
 	rc = conn->session->tt->xmit_task(task);
-	spin_lock_bh(&conn->session->frwd_lock);
+	spin_lock_bh(&conn->session->lock);
 	if (!rc) {
 		/* done with this task */
 		task->last_xfer = jiffies;
 		conn->task = NULL;
 	}
-	/* regular RX path uses back_lock */
-	spin_lock(&conn->session->back_lock);
 	__iscsi_put_task(task);
-	spin_unlock(&conn->session->back_lock);
 	return rc;
 }
 
@@ -1463,7 +1456,7 @@
  * @task: task to requeue
  *
  * LLDs that need to run a task from the session workqueue should call
- * this. The session frwd_lock must be held. This should only be called
+ * this. The session lock must be held. This should only be called
  * by software drivers.
  */
 void iscsi_requeue_task(struct iscsi_task *task)
@@ -1474,8 +1467,10 @@
 	 * this may be on the requeue list already if the xmit_task callout
 	 * is handling the r2ts while we are adding new ones
 	 */
+	spin_lock_bh(&conn->taskqueuelock);
 	if (list_empty(&task->running))
 		list_add_tail(&task->running, &conn->requeue);
+	spin_unlock_bh(&conn->taskqueuelock);
 	iscsi_conn_queue_work(conn);
 }
 EXPORT_SYMBOL_GPL(iscsi_requeue_task);
@@ -1494,10 +1489,10 @@
 	struct iscsi_task *task;
 	int rc = 0;
 
-	spin_lock_bh(&conn->session->frwd_lock);
+	spin_lock_bh(&conn->session->lock);
 	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
 		ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
-		spin_unlock_bh(&conn->session->frwd_lock);
+		spin_unlock_bh(&conn->session->lock);
 		return -ENODATA;
 	}
 
@@ -1512,22 +1507,23 @@
 	 * only have one nop-out as a ping from us and targets should not
 	 * overflow us with nop-ins
 	 */
+	spin_lock_bh(&conn->taskqueuelock);
 check_mgmt:
 	while (!list_empty(&conn->mgmtqueue)) {
 		conn->task = list_entry(conn->mgmtqueue.next,
 					 struct iscsi_task, running);
 		list_del_init(&conn->task->running);
+		spin_unlock_bh(&conn->taskqueuelock);
 		if (iscsi_prep_mgmt_task(conn, conn->task)) {
-			/* regular RX path uses back_lock */
-			spin_lock_bh(&conn->session->back_lock);
 			__iscsi_put_task(conn->task);
-			spin_unlock_bh(&conn->session->back_lock);
 			conn->task = NULL;
+			spin_lock_bh(&conn->taskqueuelock);
 			continue;
 		}
 		rc = iscsi_xmit_task(conn);
 		if (rc)
 			goto done;
+		spin_lock_bh(&conn->taskqueuelock);
 	}
 
 	/* process pending command queue */
@@ -1535,19 +1531,19 @@
 		conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task,
 					running);
 		list_del_init(&conn->task->running);
+		spin_unlock_bh(&conn->taskqueuelock);
 		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
 			fail_scsi_task(conn->task, DID_IMM_RETRY);
+			spin_lock_bh(&conn->taskqueuelock);
 			continue;
 		}
 		rc = iscsi_prep_scsi_cmd_pdu(conn->task);
 		if (rc) {
-			if (rc == -ENOMEM || rc == -EACCES) {
-				list_add_tail(&conn->task->running,
-					      &conn->cmdqueue);
-				conn->task = NULL;
-				goto done;
-			} else
+			if (rc == -ENOMEM || rc == -EACCES)
+				fail_scsi_task(conn->task, DID_IMM_RETRY);
+			else
 				fail_scsi_task(conn->task, DID_ABORT);
+			spin_lock_bh(&conn->taskqueuelock);
 			continue;
 		}
 		rc = iscsi_xmit_task(conn);
@@ -1558,6 +1554,7 @@
 		 * we need to check the mgmt queue for nops that need to
 		 * be sent to aviod starvation
 		 */
+		spin_lock_bh(&conn->taskqueuelock);
 		if (!list_empty(&conn->mgmtqueue))
 			goto check_mgmt;
 	}
@@ -1577,17 +1574,20 @@
 		conn->task = task;
 		list_del_init(&conn->task->running);
 		conn->task->state = ISCSI_TASK_RUNNING;
+		spin_unlock_bh(&conn->taskqueuelock);
 		rc = iscsi_xmit_task(conn);
 		if (rc)
 			goto done;
+		spin_lock_bh(&conn->taskqueuelock);
 		if (!list_empty(&conn->mgmtqueue))
 			goto check_mgmt;
 	}
-	spin_unlock_bh(&conn->session->frwd_lock);
+	spin_unlock_bh(&conn->taskqueuelock);
+	spin_unlock_bh(&conn->session->lock);
 	return -ENODATA;
 
 done:
-	spin_unlock_bh(&conn->session->frwd_lock);
+	spin_unlock_bh(&conn->session->lock);
 	return rc;
 }
 
@@ -1657,7 +1657,7 @@
 
 	cls_session = starget_to_session(scsi_target(sc->device));
 	session = cls_session->dd_data;
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 
 	reason = iscsi_session_chkready(cls_session);
 	if (reason) {
@@ -1674,6 +1674,15 @@
 		 */
 		switch (session->state) {
 		case ISCSI_STATE_FAILED:
+			/*
+			 * cmds should fail during shutdown, if the session
+			 * state is bad, allowing completion to happen
+			 */
+			if (unlikely(system_state != SYSTEM_RUNNING)) {
+				reason = FAILURE_SESSION_FAILED;
+				sc->result = DID_NO_CONNECT << 16;
+				break;
+			}
 		case ISCSI_STATE_IN_RECOVERY:
 			reason = FAILURE_SESSION_IN_RECOVERY;
 			sc->result = DID_IMM_RETRY << 16;
@@ -1706,7 +1715,7 @@
 
 	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
 		reason = FAILURE_SESSION_IN_RECOVERY;
-		sc->result = DID_REQUEUE;
+		sc->result = DID_REQUEUE << 16;
 		goto fault;
 	}
 
@@ -1738,18 +1747,20 @@
 			goto prepd_reject;
 		}
 	} else {
+		spin_lock_bh(&conn->taskqueuelock);
 		list_add_tail(&task->running, &conn->cmdqueue);
+		spin_unlock_bh(&conn->taskqueuelock);
 		iscsi_conn_queue_work(conn);
 	}
 
 	session->queued_cmdsn++;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	return 0;
 
 prepd_reject:
 	iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
 reject:
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
 			  sc->cmnd[0], reason);
 	return SCSI_MLQUEUE_TARGET_BUSY;
@@ -1757,7 +1768,7 @@
 prepd_fault:
 	iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
 fault:
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
 			  sc->cmnd[0], reason);
 	if (!scsi_bidi_cmnd(sc))
@@ -1786,14 +1797,14 @@
 	struct iscsi_conn *conn = (struct iscsi_conn *)data;
 	struct iscsi_session *session = conn->session;
 
-	spin_lock(&session->frwd_lock);
+	spin_lock(&session->lock);
 	if (conn->tmf_state == TMF_QUEUED) {
 		conn->tmf_state = TMF_TIMEDOUT;
 		ISCSI_DBG_EH(session, "tmf timedout\n");
 		/* unblock eh_abort() */
 		wake_up(&conn->ehwait);
 	}
-	spin_unlock(&session->frwd_lock);
+	spin_unlock(&session->lock);
 }
 
 static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
@@ -1806,10 +1817,10 @@
 	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
 				      NULL, 0);
 	if (!task) {
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		iscsi_conn_printk(KERN_ERR, conn, "Could not send TMF.\n");
 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-		spin_lock_bh(&session->frwd_lock);
+		spin_lock_bh(&session->lock);
 		return -EPERM;
 	}
 	conn->tmfcmd_pdus_cnt++;
@@ -1819,7 +1830,7 @@
 	add_timer(&conn->tmf_timer);
 	ISCSI_DBG_EH(session, "tmf set timeout\n");
 
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
 
 	/*
@@ -1838,7 +1849,7 @@
 	del_timer_sync(&conn->tmf_timer);
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	/* if the session drops it will clean up the task */
 	if (age != session->age ||
 	    session->state != ISCSI_STATE_LOGGED_IN)
@@ -1874,7 +1885,7 @@
  * iscsi_suspend_queue - suspend iscsi_queuecommand
  * @conn: iscsi conn to stop queueing IO on
  *
- * This grabs the session frwd_lock to make sure no one is in
+ * This grabs the session lock to make sure no one is in
  * xmit_task/queuecommand, and then sets suspend to prevent
  * new commands from being queued. This only needs to be called
  * by offload drivers that need to sync a path like ep disconnect
@@ -1883,9 +1894,9 @@
  */
 void iscsi_suspend_queue(struct iscsi_conn *conn)
 {
-	spin_lock_bh(&conn->session->frwd_lock);
+	spin_lock_bh(&conn->session->lock);
 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-	spin_unlock_bh(&conn->session->frwd_lock);
+	spin_unlock_bh(&conn->session->lock);
 }
 EXPORT_SYMBOL_GPL(iscsi_suspend_queue);
 
@@ -1922,7 +1933,7 @@
  */
 static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
 {
-	if (conn->ping_task &&
+	if (READ_ONCE(conn->ping_task) &&
 	    time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
 			   (conn->ping_timeout * HZ), jiffies))
 		return 1;
@@ -1944,7 +1955,7 @@
 
 	ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
 
-	spin_lock(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	task = (struct iscsi_task *)sc->SCp.ptr;
 	if (!task) {
 		/*
@@ -1957,6 +1968,19 @@
 
 	if (session->state != ISCSI_STATE_LOGGED_IN) {
 		/*
+		 * During shutdown, if session is prematurely disconnected,
+		 * recovery won't happen and there will be hung cmds. Not
+		 * handling cmds would trigger EH, also bad in this case.
+		 * Instead, handle cmd, allow completion to happen and let
+		 * upper layer to deal with the result.
+		 */
+		if (unlikely(system_state != SYSTEM_RUNNING)) {
+			sc->result = DID_NO_CONNECT << 16;
+			ISCSI_DBG_EH(session, "sc on shutdown, handled\n");
+			rc = BLK_EH_HANDLED;
+			goto done;
+		}
+		/*
 		 * We are probably in the middle of iscsi recovery so let
 		 * that complete and handle the error.
 		 */
@@ -2044,7 +2068,7 @@
 	 * Checking the transport already or nop from a cmd timeout still
 	 * running
 	 */
-	if (conn->ping_task) {
+	if (READ_ONCE(conn->ping_task)) {
 		task->have_checked_conn = true;
 		rc = BLK_EH_RESET_TIMER;
 		goto done;
@@ -2058,9 +2082,9 @@
 done:
 	if (task)
 		task->last_timeout = jiffies;
-	spin_unlock(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
-		     "timer reset" : "nh");
+		     "timer reset" : "shutdown or nh");
 	return rc;
 }
 
@@ -2070,7 +2094,7 @@
 	struct iscsi_session *session = conn->session;
 	unsigned long recv_timeout, next_timeout = 0, last_recv;
 
-	spin_lock(&session->frwd_lock);
+	spin_lock(&session->lock);
 	if (session->state != ISCSI_STATE_LOGGED_IN)
 		goto done;
 
@@ -2087,7 +2111,7 @@
 				  "last ping %lu, now %lu\n",
 				  conn->ping_timeout, conn->recv_timeout,
 				  last_recv, conn->last_ping, jiffies);
-		spin_unlock(&session->frwd_lock);
+		spin_unlock(&session->lock);
 		iscsi_conn_failure(conn, ISCSI_ERR_NOP_TIMEDOUT);
 		return;
 	}
@@ -2105,7 +2129,7 @@
 	ISCSI_DBG_CONN(conn, "Setting next tmo %lu\n", next_timeout);
 	mod_timer(&conn->transport_timer, next_timeout);
 done:
-	spin_unlock(&session->frwd_lock);
+	spin_unlock(&session->lock);
 }
 
 static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
@@ -2135,7 +2159,7 @@
 	ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	/*
 	 * if session was ISCSI_STATE_IN_RECOVERY then we may not have
 	 * got the command.
@@ -2143,7 +2167,7 @@
 	if (!sc->SCp.ptr) {
 		ISCSI_DBG_EH(session, "sc never reached iscsi layer or "
 				      "it completed.\n");
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		mutex_unlock(&session->eh_mutex);
 		return SUCCESS;
 	}
@@ -2154,7 +2178,7 @@
 	 */
 	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
 	    sc->SCp.phase != session->age) {
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		mutex_unlock(&session->eh_mutex);
 		ISCSI_DBG_EH(session, "failing abort due to dropped "
 				  "session.\n");
@@ -2195,7 +2219,7 @@
 
 	switch (conn->tmf_state) {
 	case TMF_SUCCESS:
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		/*
 		 * stop tx side incase the target had sent a abort rsp but
 		 * the initiator was still writing out data.
@@ -2206,15 +2230,15 @@
 		 * good and have never sent us a successful tmf response
 		 * then sent more data for the cmd.
 		 */
-		spin_lock_bh(&session->frwd_lock);
+		spin_lock_bh(&session->lock);
 		fail_scsi_task(task, DID_ABORT);
 		conn->tmf_state = TMF_INITIAL;
 		memset(hdr, 0, sizeof(*hdr));
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		iscsi_start_tx(conn);
 		goto success_unlocked;
 	case TMF_TIMEDOUT:
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
 		goto failed_unlocked;
 	case TMF_NOT_FOUND:
@@ -2233,7 +2257,7 @@
 	}
 
 success:
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 success_unlocked:
 	ISCSI_DBG_EH(session, "abort success [sc %p itt 0x%x]\n",
 		     sc, task->itt);
@@ -2241,7 +2265,7 @@
 	return SUCCESS;
 
 failed:
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 failed_unlocked:
 	ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc,
 		     task ? task->itt : 0);
@@ -2275,7 +2299,7 @@
 		     sc->device->lun);
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	/*
 	 * Just check if we are not logged in. We cannot check for
 	 * the phase because the reset could come from a ioctl.
@@ -2302,7 +2326,7 @@
 	case TMF_SUCCESS:
 		break;
 	case TMF_TIMEDOUT:
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
 		goto done;
 	default:
@@ -2311,21 +2335,21 @@
 	}
 
 	rc = SUCCESS;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	iscsi_suspend_tx(conn);
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	memset(hdr, 0, sizeof(*hdr));
 	fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
 	conn->tmf_state = TMF_INITIAL;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	iscsi_start_tx(conn);
 	goto done;
 
 unlock:
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 done:
 	ISCSI_DBG_EH(session, "dev reset result = %s\n",
 		     rc == SUCCESS ? "SUCCESS" : "FAILED");
@@ -2338,13 +2362,13 @@
 {
 	struct iscsi_session *session = cls_session->dd_data;
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (session->state != ISCSI_STATE_LOGGED_IN) {
 		session->state = ISCSI_STATE_RECOVERY_FAILED;
 		if (session->leadconn)
 			wake_up(&session->leadconn->ehwait);
 	}
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 }
 EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
 
@@ -2366,19 +2390,19 @@
 	conn = session->leadconn;
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (session->state == ISCSI_STATE_TERMINATE) {
 failed:
 		ISCSI_DBG_EH(session,
 			     "failing session reset: Could not log back into "
-			     "%s, %s [age %d]\n", session->targetname,
-			     conn->persistent_address, session->age);
-		spin_unlock_bh(&session->frwd_lock);
+			     "%s [age %d]\n", session->targetname,
+			     session->age);
+		spin_unlock_bh(&session->lock);
 		mutex_unlock(&session->eh_mutex);
 		return FAILED;
 	}
 
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
 	/*
 	 * we drop the lock here but the leadconn cannot be destoyed while
@@ -2395,14 +2419,14 @@
 		flush_signals(current);
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (session->state == ISCSI_STATE_LOGGED_IN) {
 		ISCSI_DBG_EH(session,
 			     "session reset succeeded for %s,%s\n",
 			     session->targetname, conn->persistent_address);
 	} else
 		goto failed;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
 	return SUCCESS;
 }
@@ -2438,7 +2462,7 @@
 		     session->targetname);
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	/*
 	 * Just check if we are not logged in. We cannot check for
 	 * the phase because the reset could come from a ioctl.
@@ -2465,7 +2489,7 @@
 	case TMF_SUCCESS:
 		break;
 	case TMF_TIMEDOUT:
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
 		goto done;
 	default:
@@ -2474,21 +2498,21 @@
 	}
 
 	rc = SUCCESS;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	iscsi_suspend_tx(conn);
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	memset(hdr, 0, sizeof(*hdr));
 	fail_scsi_tasks(conn, -1, DID_ERROR);
 	conn->tmf_state = TMF_INITIAL;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	iscsi_start_tx(conn);
 	goto done;
 
 unlock:
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 done:
 	ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname,
 		     rc == SUCCESS ? "SUCCESS" : "FAILED");
@@ -2786,10 +2810,8 @@
 	session->max_r2t = 1;
 	session->tt = iscsit;
 	session->dd_data = cls_session->dd_data + sizeof(*session);
-
 	mutex_init(&session->eh_mutex);
-	spin_lock_init(&session->frwd_lock);
-	spin_lock_init(&session->back_lock);
+	spin_lock_init(&session->lock);
 
 	/* initialize SCSI PDU commands pool */
 	if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
@@ -2828,21 +2850,34 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_session_setup);
 
+/*
+ * issi_session_remove - Remove session from iSCSI class.
+ */
+void iscsi_session_remove(struct iscsi_cls_session *cls_session)
+{
+	struct iscsi_session *session = cls_session->dd_data;
+	struct Scsi_Host *shost = session->host;
+
+	iscsi_remove_session(cls_session);
+	/*
+	 * host removal only has to wait for its children to be removed from
+	 * sysfs, and iscsi_tcp needs to do iscsi_host_remove before freeing
+	 * the session, so drop the session count here.
+	 */
+	iscsi_host_dec_session_cnt(shost);
+}
+EXPORT_SYMBOL_GPL(iscsi_session_remove);
+
 /**
- * iscsi_session_teardown - destroy session, host, and cls_session
+ * iscsi_session_free - Free iscsi session and it's resources
  * @cls_session: iscsi session
- *
- * The driver must have called iscsi_remove_session before
- * calling this.
  */
-void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
+void iscsi_session_free(struct iscsi_cls_session *cls_session)
 {
 	struct iscsi_session *session = cls_session->dd_data;
 	struct module *owner = cls_session->transport->owner;
-	struct Scsi_Host *shost = session->host;
 
 	iscsi_pool_free(&session->cmdpool);
-
 	kfree(session->password);
 	kfree(session->password_in);
 	kfree(session->username);
@@ -2857,10 +2892,20 @@
 	kfree(session->portal_type);
 	kfree(session->discovery_parent_type);
 
-	iscsi_destroy_session(cls_session);
-	iscsi_host_dec_session_cnt(shost);
+	iscsi_free_session(cls_session);
 	module_put(owner);
 }
+EXPORT_SYMBOL_GPL(iscsi_session_free);
+
+/**
+ * iscsi_session_teardown - destroy session and cls_session
+ * @cls_session: iscsi session
+ */
+void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
+{
+	iscsi_session_remove(cls_session);
+	iscsi_session_free(cls_session);
+}
 EXPORT_SYMBOL_GPL(iscsi_session_teardown);
 
 /**
@@ -2900,17 +2945,18 @@
 	INIT_LIST_HEAD(&conn->mgmtqueue);
 	INIT_LIST_HEAD(&conn->cmdqueue);
 	INIT_LIST_HEAD(&conn->requeue);
+	spin_lock_init(&conn->taskqueuelock);
 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
 	/* allocate login_task used for the login/text sequences */
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (!kfifo_out(&session->cmdpool.queue,
                          (void*)&conn->login_task,
 			 sizeof(void*))) {
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		goto login_task_alloc_fail;
 	}
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	data = (char *) __get_free_pages(GFP_KERNEL,
 					 get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
@@ -2947,7 +2993,7 @@
 	del_timer_sync(&conn->transport_timer);
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
 	if (session->leadconn == conn) {
 		/*
@@ -2956,24 +3002,21 @@
 		session->state = ISCSI_STATE_TERMINATE;
 		wake_up(&conn->ehwait);
 	}
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	/* flush queued up work because we free the connection below */
 	iscsi_suspend_tx(conn);
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	free_pages((unsigned long) conn->data,
 		   get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
 	kfree(conn->persistent_address);
 	kfree(conn->local_ipaddr);
-	/* regular RX path uses back_lock */
-	spin_lock_bh(&session->back_lock);
 	kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
 		    sizeof(void*));
-	spin_unlock_bh(&session->back_lock);
 	if (session->leadconn == conn)
 		session->leadconn = NULL;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
 
 	iscsi_destroy_conn(cls_conn);
@@ -3011,7 +3054,7 @@
 		conn->ping_timeout = 5;
 	}
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	conn->c_stage = ISCSI_CONN_STARTED;
 	session->state = ISCSI_STATE_LOGGED_IN;
 	session->queued_cmdsn = session->cmdsn;
@@ -3040,7 +3083,7 @@
 	default:
 		break;
 	}
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	iscsi_unblock_session(session->cls_session);
 	wake_up(&conn->ehwait);
@@ -3079,9 +3122,9 @@
 	int old_stop_stage;
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (conn->stop_stage == STOP_CONN_TERM) {
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->lock);
 		mutex_unlock(&session->eh_mutex);
 		return;
 	}
@@ -3098,14 +3141,14 @@
 
 	old_stop_stage = conn->stop_stage;
 	conn->stop_stage = flag;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	del_timer_sync(&conn->transport_timer);
 	iscsi_suspend_tx(conn);
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	conn->c_stage = ISCSI_CONN_STOPPED;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	/*
 	 * for connection level recovery we should not calculate
@@ -3126,11 +3169,11 @@
 	/*
 	 * flush queues.
 	 */
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
 	fail_mgmt_tasks(session, conn);
 	memset(&conn->tmhdr, 0, sizeof(conn->tmhdr));
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
 }
 
@@ -3157,10 +3200,10 @@
 	struct iscsi_session *session = cls_session->dd_data;
 	struct iscsi_conn *conn = cls_conn->dd_data;
 
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->lock);
 	if (is_leading)
 		session->leadconn = conn;
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->lock);
 
 	/*
 	 * Unblock xmitworker(), Login Phase will pass through.
@@ -3312,125 +3355,125 @@
 
 	switch(param) {
 	case ISCSI_PARAM_FAST_ABORT:
-		len = sprintf(buf, "%d\n", session->fast_abort);
+		len = sysfs_emit(buf, "%d\n", session->fast_abort);
 		break;
 	case ISCSI_PARAM_ABORT_TMO:
-		len = sprintf(buf, "%d\n", session->abort_timeout);
+		len = sysfs_emit(buf, "%d\n", session->abort_timeout);
 		break;
 	case ISCSI_PARAM_LU_RESET_TMO:
-		len = sprintf(buf, "%d\n", session->lu_reset_timeout);
+		len = sysfs_emit(buf, "%d\n", session->lu_reset_timeout);
 		break;
 	case ISCSI_PARAM_TGT_RESET_TMO:
-		len = sprintf(buf, "%d\n", session->tgt_reset_timeout);
+		len = sysfs_emit(buf, "%d\n", session->tgt_reset_timeout);
 		break;
 	case ISCSI_PARAM_INITIAL_R2T_EN:
-		len = sprintf(buf, "%d\n", session->initial_r2t_en);
+		len = sysfs_emit(buf, "%d\n", session->initial_r2t_en);
 		break;
 	case ISCSI_PARAM_MAX_R2T:
-		len = sprintf(buf, "%hu\n", session->max_r2t);
+		len = sysfs_emit(buf, "%hu\n", session->max_r2t);
 		break;
 	case ISCSI_PARAM_IMM_DATA_EN:
-		len = sprintf(buf, "%d\n", session->imm_data_en);
+		len = sysfs_emit(buf, "%d\n", session->imm_data_en);
 		break;
 	case ISCSI_PARAM_FIRST_BURST:
-		len = sprintf(buf, "%u\n", session->first_burst);
+		len = sysfs_emit(buf, "%u\n", session->first_burst);
 		break;
 	case ISCSI_PARAM_MAX_BURST:
-		len = sprintf(buf, "%u\n", session->max_burst);
+		len = sysfs_emit(buf, "%u\n", session->max_burst);
 		break;
 	case ISCSI_PARAM_PDU_INORDER_EN:
-		len = sprintf(buf, "%d\n", session->pdu_inorder_en);
+		len = sysfs_emit(buf, "%d\n", session->pdu_inorder_en);
 		break;
 	case ISCSI_PARAM_DATASEQ_INORDER_EN:
-		len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
+		len = sysfs_emit(buf, "%d\n", session->dataseq_inorder_en);
 		break;
 	case ISCSI_PARAM_DEF_TASKMGMT_TMO:
-		len = sprintf(buf, "%d\n", session->def_taskmgmt_tmo);
+		len = sysfs_emit(buf, "%d\n", session->def_taskmgmt_tmo);
 		break;
 	case ISCSI_PARAM_ERL:
-		len = sprintf(buf, "%d\n", session->erl);
+		len = sysfs_emit(buf, "%d\n", session->erl);
 		break;
 	case ISCSI_PARAM_TARGET_NAME:
-		len = sprintf(buf, "%s\n", session->targetname);
+		len = sysfs_emit(buf, "%s\n", session->targetname);
 		break;
 	case ISCSI_PARAM_TARGET_ALIAS:
-		len = sprintf(buf, "%s\n", session->targetalias);
+		len = sysfs_emit(buf, "%s\n", session->targetalias);
 		break;
 	case ISCSI_PARAM_TPGT:
-		len = sprintf(buf, "%d\n", session->tpgt);
+		len = sysfs_emit(buf, "%d\n", session->tpgt);
 		break;
 	case ISCSI_PARAM_USERNAME:
-		len = sprintf(buf, "%s\n", session->username);
+		len = sysfs_emit(buf, "%s\n", session->username);
 		break;
 	case ISCSI_PARAM_USERNAME_IN:
-		len = sprintf(buf, "%s\n", session->username_in);
+		len = sysfs_emit(buf, "%s\n", session->username_in);
 		break;
 	case ISCSI_PARAM_PASSWORD:
-		len = sprintf(buf, "%s\n", session->password);
+		len = sysfs_emit(buf, "%s\n", session->password);
 		break;
 	case ISCSI_PARAM_PASSWORD_IN:
-		len = sprintf(buf, "%s\n", session->password_in);
+		len = sysfs_emit(buf, "%s\n", session->password_in);
 		break;
 	case ISCSI_PARAM_IFACE_NAME:
-		len = sprintf(buf, "%s\n", session->ifacename);
+		len = sysfs_emit(buf, "%s\n", session->ifacename);
 		break;
 	case ISCSI_PARAM_INITIATOR_NAME:
-		len = sprintf(buf, "%s\n", session->initiatorname);
+		len = sysfs_emit(buf, "%s\n", session->initiatorname);
 		break;
 	case ISCSI_PARAM_BOOT_ROOT:
-		len = sprintf(buf, "%s\n", session->boot_root);
+		len = sysfs_emit(buf, "%s\n", session->boot_root);
 		break;
 	case ISCSI_PARAM_BOOT_NIC:
-		len = sprintf(buf, "%s\n", session->boot_nic);
+		len = sysfs_emit(buf, "%s\n", session->boot_nic);
 		break;
 	case ISCSI_PARAM_BOOT_TARGET:
-		len = sprintf(buf, "%s\n", session->boot_target);
+		len = sysfs_emit(buf, "%s\n", session->boot_target);
 		break;
 	case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
-		len = sprintf(buf, "%u\n", session->auto_snd_tgt_disable);
+		len = sysfs_emit(buf, "%u\n", session->auto_snd_tgt_disable);
 		break;
 	case ISCSI_PARAM_DISCOVERY_SESS:
-		len = sprintf(buf, "%u\n", session->discovery_sess);
+		len = sysfs_emit(buf, "%u\n", session->discovery_sess);
 		break;
 	case ISCSI_PARAM_PORTAL_TYPE:
-		len = sprintf(buf, "%s\n", session->portal_type);
+		len = sysfs_emit(buf, "%s\n", session->portal_type);
 		break;
 	case ISCSI_PARAM_CHAP_AUTH_EN:
-		len = sprintf(buf, "%u\n", session->chap_auth_en);
+		len = sysfs_emit(buf, "%u\n", session->chap_auth_en);
 		break;
 	case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
-		len = sprintf(buf, "%u\n", session->discovery_logout_en);
+		len = sysfs_emit(buf, "%u\n", session->discovery_logout_en);
 		break;
 	case ISCSI_PARAM_BIDI_CHAP_EN:
-		len = sprintf(buf, "%u\n", session->bidi_chap_en);
+		len = sysfs_emit(buf, "%u\n", session->bidi_chap_en);
 		break;
 	case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
-		len = sprintf(buf, "%u\n", session->discovery_auth_optional);
+		len = sysfs_emit(buf, "%u\n", session->discovery_auth_optional);
 		break;
 	case ISCSI_PARAM_DEF_TIME2WAIT:
-		len = sprintf(buf, "%d\n", session->time2wait);
+		len = sysfs_emit(buf, "%d\n", session->time2wait);
 		break;
 	case ISCSI_PARAM_DEF_TIME2RETAIN:
-		len = sprintf(buf, "%d\n", session->time2retain);
+		len = sysfs_emit(buf, "%d\n", session->time2retain);
 		break;
 	case ISCSI_PARAM_TSID:
-		len = sprintf(buf, "%u\n", session->tsid);
+		len = sysfs_emit(buf, "%u\n", session->tsid);
 		break;
 	case ISCSI_PARAM_ISID:
-		len = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
+		len = sysfs_emit(buf, "%02x%02x%02x%02x%02x%02x\n",
 			      session->isid[0], session->isid[1],
 			      session->isid[2], session->isid[3],
 			      session->isid[4], session->isid[5]);
 		break;
 	case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
-		len = sprintf(buf, "%u\n", session->discovery_parent_idx);
+		len = sysfs_emit(buf, "%u\n", session->discovery_parent_idx);
 		break;
 	case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
 		if (session->discovery_parent_type)
-			len = sprintf(buf, "%s\n",
+			len = sysfs_emit(buf, "%s\n",
 				      session->discovery_parent_type);
 		else
-			len = sprintf(buf, "\n");
+			len = sysfs_emit(buf, "\n");
 		break;
 	default:
 		return -ENOSYS;
@@ -3462,16 +3505,16 @@
 	case ISCSI_PARAM_CONN_ADDRESS:
 	case ISCSI_HOST_PARAM_IPADDRESS:
 		if (sin)
-			len = sprintf(buf, "%pI4\n", &sin->sin_addr.s_addr);
+			len = sysfs_emit(buf, "%pI4\n", &sin->sin_addr.s_addr);
 		else
-			len = sprintf(buf, "%pI6\n", &sin6->sin6_addr);
+			len = sysfs_emit(buf, "%pI6\n", &sin6->sin6_addr);
 		break;
 	case ISCSI_PARAM_CONN_PORT:
 	case ISCSI_PARAM_LOCAL_PORT:
 		if (sin)
-			len = sprintf(buf, "%hu\n", be16_to_cpu(sin->sin_port));
+			len = sysfs_emit(buf, "%hu\n", be16_to_cpu(sin->sin_port));
 		else
-			len = sprintf(buf, "%hu\n",
+			len = sysfs_emit(buf, "%hu\n",
 				      be16_to_cpu(sin6->sin6_port));
 		break;
 	default:
@@ -3490,88 +3533,88 @@
 
 	switch(param) {
 	case ISCSI_PARAM_PING_TMO:
-		len = sprintf(buf, "%u\n", conn->ping_timeout);
+		len = sysfs_emit(buf, "%u\n", conn->ping_timeout);
 		break;
 	case ISCSI_PARAM_RECV_TMO:
-		len = sprintf(buf, "%u\n", conn->recv_timeout);
+		len = sysfs_emit(buf, "%u\n", conn->recv_timeout);
 		break;
 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
-		len = sprintf(buf, "%u\n", conn->max_recv_dlength);
+		len = sysfs_emit(buf, "%u\n", conn->max_recv_dlength);
 		break;
 	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
-		len = sprintf(buf, "%u\n", conn->max_xmit_dlength);
+		len = sysfs_emit(buf, "%u\n", conn->max_xmit_dlength);
 		break;
 	case ISCSI_PARAM_HDRDGST_EN:
-		len = sprintf(buf, "%d\n", conn->hdrdgst_en);
+		len = sysfs_emit(buf, "%d\n", conn->hdrdgst_en);
 		break;
 	case ISCSI_PARAM_DATADGST_EN:
-		len = sprintf(buf, "%d\n", conn->datadgst_en);
+		len = sysfs_emit(buf, "%d\n", conn->datadgst_en);
 		break;
 	case ISCSI_PARAM_IFMARKER_EN:
-		len = sprintf(buf, "%d\n", conn->ifmarker_en);
+		len = sysfs_emit(buf, "%d\n", conn->ifmarker_en);
 		break;
 	case ISCSI_PARAM_OFMARKER_EN:
-		len = sprintf(buf, "%d\n", conn->ofmarker_en);
+		len = sysfs_emit(buf, "%d\n", conn->ofmarker_en);
 		break;
 	case ISCSI_PARAM_EXP_STATSN:
-		len = sprintf(buf, "%u\n", conn->exp_statsn);
+		len = sysfs_emit(buf, "%u\n", conn->exp_statsn);
 		break;
 	case ISCSI_PARAM_PERSISTENT_PORT:
-		len = sprintf(buf, "%d\n", conn->persistent_port);
+		len = sysfs_emit(buf, "%d\n", conn->persistent_port);
 		break;
 	case ISCSI_PARAM_PERSISTENT_ADDRESS:
-		len = sprintf(buf, "%s\n", conn->persistent_address);
+		len = sysfs_emit(buf, "%s\n", conn->persistent_address);
 		break;
 	case ISCSI_PARAM_STATSN:
-		len = sprintf(buf, "%u\n", conn->statsn);
+		len = sysfs_emit(buf, "%u\n", conn->statsn);
 		break;
 	case ISCSI_PARAM_MAX_SEGMENT_SIZE:
-		len = sprintf(buf, "%u\n", conn->max_segment_size);
+		len = sysfs_emit(buf, "%u\n", conn->max_segment_size);
 		break;
 	case ISCSI_PARAM_KEEPALIVE_TMO:
-		len = sprintf(buf, "%u\n", conn->keepalive_tmo);
+		len = sysfs_emit(buf, "%u\n", conn->keepalive_tmo);
 		break;
 	case ISCSI_PARAM_LOCAL_PORT:
-		len = sprintf(buf, "%u\n", conn->local_port);
+		len = sysfs_emit(buf, "%u\n", conn->local_port);
 		break;
 	case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
-		len = sprintf(buf, "%u\n", conn->tcp_timestamp_stat);
+		len = sysfs_emit(buf, "%u\n", conn->tcp_timestamp_stat);
 		break;
 	case ISCSI_PARAM_TCP_NAGLE_DISABLE:
-		len = sprintf(buf, "%u\n", conn->tcp_nagle_disable);
+		len = sysfs_emit(buf, "%u\n", conn->tcp_nagle_disable);
 		break;
 	case ISCSI_PARAM_TCP_WSF_DISABLE:
-		len = sprintf(buf, "%u\n", conn->tcp_wsf_disable);
+		len = sysfs_emit(buf, "%u\n", conn->tcp_wsf_disable);
 		break;
 	case ISCSI_PARAM_TCP_TIMER_SCALE:
-		len = sprintf(buf, "%u\n", conn->tcp_timer_scale);
+		len = sysfs_emit(buf, "%u\n", conn->tcp_timer_scale);
 		break;
 	case ISCSI_PARAM_TCP_TIMESTAMP_EN:
-		len = sprintf(buf, "%u\n", conn->tcp_timestamp_en);
+		len = sysfs_emit(buf, "%u\n", conn->tcp_timestamp_en);
 		break;
 	case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
-		len = sprintf(buf, "%u\n", conn->fragment_disable);
+		len = sysfs_emit(buf, "%u\n", conn->fragment_disable);
 		break;
 	case ISCSI_PARAM_IPV4_TOS:
-		len = sprintf(buf, "%u\n", conn->ipv4_tos);
+		len = sysfs_emit(buf, "%u\n", conn->ipv4_tos);
 		break;
 	case ISCSI_PARAM_IPV6_TC:
-		len = sprintf(buf, "%u\n", conn->ipv6_traffic_class);
+		len = sysfs_emit(buf, "%u\n", conn->ipv6_traffic_class);
 		break;
 	case ISCSI_PARAM_IPV6_FLOW_LABEL:
-		len = sprintf(buf, "%u\n", conn->ipv6_flow_label);
+		len = sysfs_emit(buf, "%u\n", conn->ipv6_flow_label);
 		break;
 	case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
-		len = sprintf(buf, "%u\n", conn->is_fw_assigned_ipv6);
+		len = sysfs_emit(buf, "%u\n", conn->is_fw_assigned_ipv6);
 		break;
 	case ISCSI_PARAM_TCP_XMIT_WSF:
-		len = sprintf(buf, "%u\n", conn->tcp_xmit_wsf);
+		len = sysfs_emit(buf, "%u\n", conn->tcp_xmit_wsf);
 		break;
 	case ISCSI_PARAM_TCP_RECV_WSF:
-		len = sprintf(buf, "%u\n", conn->tcp_recv_wsf);
+		len = sysfs_emit(buf, "%u\n", conn->tcp_recv_wsf);
 		break;
 	case ISCSI_PARAM_LOCAL_IPADDR:
-		len = sprintf(buf, "%s\n", conn->local_ipaddr);
+		len = sysfs_emit(buf, "%s\n", conn->local_ipaddr);
 		break;
 	default:
 		return -ENOSYS;
@@ -3589,13 +3632,13 @@
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_NETDEV_NAME:
-		len = sprintf(buf, "%s\n", ihost->netdev);
+		len = sysfs_emit(buf, "%s\n", ihost->netdev);
 		break;
 	case ISCSI_HOST_PARAM_HWADDRESS:
-		len = sprintf(buf, "%s\n", ihost->hwaddress);
+		len = sysfs_emit(buf, "%s\n", ihost->hwaddress);
 		break;
 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
-		len = sprintf(buf, "%s\n", ihost->initiatorname);
+		len = sysfs_emit(buf, "%s\n", ihost->initiatorname);
 		break;
 	default:
 		return -ENOSYS;
--- linux-4.4.0.orig/drivers/scsi/libiscsi_tcp.c
+++ linux-4.4.0/drivers/scsi/libiscsi_tcp.c
@@ -446,7 +446,7 @@
  * iscsi_tcp_cleanup_task - free tcp_task resources
  * @task: iscsi task
  *
- * must be called with session back_lock
+ * must be called with session lock
  */
 void iscsi_tcp_cleanup_task(struct iscsi_task *task)
 {
@@ -457,7 +457,6 @@
 	if (!task->sc)
 		return;
 
-	spin_lock_bh(&tcp_task->queue2pool);
 	/* flush task's r2t queues */
 	while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
 		kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
@@ -471,7 +470,6 @@
 			    sizeof(void*));
 		tcp_task->r2t = NULL;
 	}
-	spin_unlock_bh(&tcp_task->queue2pool);
 }
 EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task);
 
@@ -579,13 +577,11 @@
 		return ISCSI_ERR_DATALEN;
 	}
 
-	spin_lock(&tcp_task->pool2queue);
 	rc = kfifo_out(&tcp_task->r2tpool.queue, (void *)&r2t, sizeof(void *));
 	if (!rc) {
 		iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
 				  "Target has sent more R2Ts than it "
 				  "negotiated for or driver has leaked.\n");
-		spin_unlock(&tcp_task->pool2queue);
 		return ISCSI_ERR_PROTO;
 	}
 
@@ -600,7 +596,6 @@
 	tcp_task->exp_datasn = r2tsn + 1;
 	kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
 	conn->r2t_pdus_cnt++;
-	spin_unlock(&tcp_task->pool2queue);
 
 	iscsi_requeue_task(task);
 	return 0;
@@ -673,14 +668,14 @@
 
 	switch(opcode) {
 	case ISCSI_OP_SCSI_DATA_IN:
-		spin_lock(&conn->session->back_lock);
+		spin_lock(&conn->session->lock);
 		task = iscsi_itt_to_ctask(conn, hdr->itt);
 		if (!task)
 			rc = ISCSI_ERR_BAD_ITT;
 		else
 			rc = iscsi_tcp_data_in(conn, task);
 		if (rc) {
-			spin_unlock(&conn->session->back_lock);
+			spin_unlock(&conn->session->lock);
 			break;
 		}
 
@@ -713,11 +708,11 @@
 						   tcp_conn->in.datalen,
 						   iscsi_tcp_process_data_in,
 						   rx_hash);
-			spin_unlock(&conn->session->back_lock);
+			spin_unlock(&conn->session->lock);
 			return rc;
 		}
 		rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
-		spin_unlock(&conn->session->back_lock);
+		spin_unlock(&conn->session->lock);
 		break;
 	case ISCSI_OP_SCSI_CMD_RSP:
 		if (tcp_conn->in.datalen) {
@@ -727,20 +722,18 @@
 		rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
 		break;
 	case ISCSI_OP_R2T:
-		spin_lock(&conn->session->back_lock);
+		spin_lock(&conn->session->lock);
 		task = iscsi_itt_to_ctask(conn, hdr->itt);
-		spin_unlock(&conn->session->back_lock);
 		if (!task)
 			rc = ISCSI_ERR_BAD_ITT;
 		else if (ahslen)
 			rc = ISCSI_ERR_AHSLEN;
 		else if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
 			task->last_xfer = jiffies;
-			spin_lock(&conn->session->frwd_lock);
 			rc = iscsi_tcp_r2t_rsp(conn, task);
-			spin_unlock(&conn->session->frwd_lock);
 		} else
 			rc = ISCSI_ERR_PROTO;
+		spin_unlock(&conn->session->lock);
 		break;
 	case ISCSI_OP_LOGIN_RSP:
 	case ISCSI_OP_TEXT_RSP:
@@ -988,13 +981,14 @@
 
 static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
 {
+	struct iscsi_session *session = task->conn->session;
 	struct iscsi_tcp_task *tcp_task = task->dd_data;
 	struct iscsi_r2t_info *r2t = NULL;
 
 	if (iscsi_task_has_unsol_data(task))
 		r2t = &task->unsol_r2t;
 	else {
-		spin_lock_bh(&tcp_task->queue2pool);
+		spin_lock_bh(&session->lock);
 		if (tcp_task->r2t) {
 			r2t = tcp_task->r2t;
 			/* Continue with this R2T? */
@@ -1016,7 +1010,7 @@
 			else
 				r2t = tcp_task->r2t;
 		}
-		spin_unlock_bh(&tcp_task->queue2pool);
+		spin_unlock_bh(&session->lock);
 	}
 
 	return r2t;
@@ -1146,8 +1140,6 @@
 			iscsi_pool_free(&tcp_task->r2tpool);
 			goto r2t_alloc_fail;
 		}
-		spin_lock_init(&tcp_task->pool2queue);
-		spin_lock_init(&tcp_task->queue2pool);
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/scsi/libsas/sas_ata.c
+++ linux-4.4.0/drivers/scsi/libsas/sas_ata.c
@@ -218,13 +218,16 @@
 		task->num_scatter = qc->n_elem;
 	} else {
 		for_each_sg(qc->sg, sg, qc->n_elem, si)
-			xfer += sg->length;
+			xfer += sg_dma_len(sg);
 
 		task->total_xfer_len = xfer;
 		task->num_scatter = si;
 	}
 
-	task->data_dir = qc->dma_dir;
+	if (qc->tf.protocol == ATA_PROT_NODATA)
+		task->data_dir = DMA_NONE;
+	else
+		task->data_dir = qc->dma_dir;
 	task->scatter = qc->sg;
 	task->ata_task.retry_count = 1;
 	task->task_state_flags = SAS_TASK_STATE_PENDING;
@@ -732,7 +735,6 @@
 	if (res)
 		return res;
 
-	sas_discover_event(dev->port, DISCE_PROBE);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/scsi/libsas/sas_discover.c
+++ linux-4.4.0/drivers/scsi/libsas/sas_discover.c
@@ -97,12 +97,21 @@
 		else
 			dev->dev_type = SAS_SATA_DEV;
 		dev->tproto = SAS_PROTOCOL_SATA;
-	} else {
+	} else if (port->oob_mode == SAS_OOB_MODE) {
 		struct sas_identify_frame *id =
 			(struct sas_identify_frame *) dev->frame_rcvd;
 		dev->dev_type = id->dev_type;
 		dev->iproto = id->initiator_bits;
 		dev->tproto = id->target_bits;
+	} else {
+		/* If the oob mode is OOB_NOT_CONNECTED, the port is
+		 * disconnected due to race with PHY down. We cannot
+		 * continue to discover this port
+		 */
+		sas_put_device(dev);
+		pr_warn("Port %016llx is disconnected when discovering\n",
+			SAS_ADDR(port->attached_sas_addr));
+		return -ENODEV;
 	}
 
 	sas_init_dev(dev);
@@ -212,13 +221,9 @@
 	}
 }
 
-static void sas_probe_devices(struct work_struct *work)
+static void sas_probe_devices(struct asd_sas_port *port)
 {
 	struct domain_device *dev, *n;
-	struct sas_discovery_event *ev = to_sas_discovery_event(work);
-	struct asd_sas_port *port = ev->port;
-
-	clear_bit(DISCE_PROBE, &port->disc.pending);
 
 	/* devices must be domain members before link recovery and probe */
 	list_for_each_entry(dev, &port->disco_list, disco_list_node) {
@@ -294,7 +299,6 @@
 	res = sas_notify_lldd_dev_found(dev);
 	if (res)
 		return res;
-	sas_discover_event(dev->port, DISCE_PROBE);
 
 	return 0;
 }
@@ -353,13 +357,9 @@
 	sas_put_device(dev);
 }
 
-static void sas_destruct_devices(struct work_struct *work)
+void sas_destruct_devices(struct asd_sas_port *port)
 {
 	struct domain_device *dev, *n;
-	struct sas_discovery_event *ev = to_sas_discovery_event(work);
-	struct asd_sas_port *port = ev->port;
-
-	clear_bit(DISCE_DESTRUCT, &port->disc.pending);
 
 	list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) {
 		list_del_init(&dev->disco_list_node);
@@ -370,6 +370,16 @@
 	}
 }
 
+static void sas_destruct_ports(struct asd_sas_port *port)
+{
+	struct sas_port *sas_port, *p;
+
+	list_for_each_entry_safe(sas_port, p, &port->sas_port_del_list, del_list) {
+		list_del_init(&sas_port->del_list);
+		sas_port_delete(sas_port);
+	}
+}
+
 void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
 {
 	if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
@@ -384,7 +394,6 @@
 	if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
 		sas_rphy_unlink(dev->rphy);
 		list_move_tail(&dev->disco_list_node, &port->destroy_list);
-		sas_discover_event(dev->port, DISCE_DESTRUCT);
 	}
 }
 
@@ -490,6 +499,8 @@
 		port->port_dev = NULL;
 	}
 
+	sas_probe_devices(port);
+
 	SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
 		    task_pid_nr(current), error);
 }
@@ -523,6 +534,10 @@
 		    port->id, task_pid_nr(current), res);
  out:
 	mutex_unlock(&ha->disco_mutex);
+
+	sas_destruct_devices(port);
+	sas_destruct_ports(port);
+	sas_probe_devices(port);
 }
 
 /* ---------- Events ---------- */
@@ -578,10 +593,8 @@
 	static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
 		[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
 		[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
-		[DISCE_PROBE] = sas_probe_devices,
 		[DISCE_SUSPEND] = sas_suspend_devices,
 		[DISCE_RESUME] = sas_resume_devices,
-		[DISCE_DESTRUCT] = sas_destruct_devices,
 	};
 
 	disc->pending = 0;
--- linux-4.4.0.orig/drivers/scsi/libsas/sas_expander.c
+++ linux-4.4.0/drivers/scsi/libsas/sas_expander.c
@@ -47,17 +47,16 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&task->task_state_lock, flags);
-	if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+	if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
 		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+		complete(&task->slow_task->completion);
+	}
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	complete(&task->slow_task->completion);
 }
 
 static void smp_task_done(struct sas_task *task)
 {
-	if (!del_timer(&task->slow_task->timer))
-		return;
+	del_timer(&task->slow_task->timer);
 	complete(&task->slow_task->completion);
 }
 
@@ -282,6 +281,7 @@
 	phy->phy->minimum_linkrate = dr->pmin_linkrate;
 	phy->phy->maximum_linkrate = dr->pmax_linkrate;
 	phy->phy->negotiated_linkrate = phy->linkrate;
+	phy->phy->enabled = (phy->linkrate != SAS_PHY_DISABLED);
 
  skip:
 	if (new_phy)
@@ -603,7 +603,14 @@
 	}
 
 	res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE);
-
+	if (res) {
+		pr_err("ex %016llx phy%02d PHY control failed: %d\n",
+		       SAS_ADDR(dev->sas_addr), phy_id, res);
+	} else if (pc_resp[2] != SMP_RESP_FUNC_ACC) {
+		pr_err("ex %016llx phy%02d PHY control failed: function result 0x%x\n",
+		       SAS_ADDR(dev->sas_addr), phy_id, pc_resp[2]);
+		res = pc_resp[2];
+	}
 	kfree(pc_resp);
 	kfree(pc_req);
 	return res;
@@ -675,7 +682,7 @@
 	res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
 			            resp, RPEL_RESP_SIZE);
 
-	if (!res)
+	if (res)
 		goto out;
 
 	phy->invalid_dword_count = scsi_to_u32(&resp[12]);
@@ -684,6 +691,7 @@
 	phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
 
  out:
+	kfree(req);
 	kfree(resp);
 	return res;
 
@@ -805,6 +813,26 @@
 
 #ifdef CONFIG_SCSI_SAS_ATA
 	if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
+		if (child->linkrate > parent->min_linkrate) {
+			struct sas_phy_linkrates rates = {
+				.maximum_linkrate = parent->min_linkrate,
+				.minimum_linkrate = parent->min_linkrate,
+			};
+			int ret;
+
+			pr_notice("ex %016llx phy%02d SATA device linkrate > min pathway connection rate, attempting to lower device linkrate\n",
+				   SAS_ADDR(child->sas_addr), phy_id);
+			ret = sas_smp_phy_control(parent, phy_id,
+						  PHY_FUNC_LINK_RESET, &rates);
+			if (ret) {
+				pr_err("ex %016llx phy%02d SATA device could not set linkrate (%d)\n",
+				       SAS_ADDR(child->sas_addr), phy_id, ret);
+				goto out_free;
+			}
+			pr_notice("ex %016llx phy%02d SATA device set linkrate successfully\n",
+				  SAS_ADDR(child->sas_addr), phy_id);
+			child->linkrate = child->min_linkrate;
+		}
 		res = sas_get_ata_info(child, phy);
 		if (res)
 			goto out_free;
@@ -816,6 +844,7 @@
 		rphy = sas_end_device_alloc(phy->port);
 		if (!rphy)
 			goto out_free;
+		rphy->identify.phy_identifier = phy_id;
 
 		child->rphy = rphy;
 		get_device(&rphy->dev);
@@ -843,6 +872,7 @@
 
 		child->rphy = rphy;
 		get_device(&rphy->dev);
+		rphy->identify.phy_identifier = phy_id;
 		sas_fill_in_rphy(child, rphy);
 
 		list_add_tail(&child->disco_list_node, &parent->port->disco_list);
@@ -975,6 +1005,8 @@
 		list_del(&child->dev_list_node);
 		spin_unlock_irq(&parent->port->dev_list_lock);
 		sas_put_device(child);
+		sas_port_delete(phy->port);
+		phy->port = NULL;
 		return NULL;
 	}
 	list_add_tail(&child->siblings, &parent->ex_dev.children);
@@ -1903,7 +1935,8 @@
 		sas_port_delete_phy(phy->port, phy->phy);
 		sas_device_set_phy(found, phy->port);
 		if (phy->port->num_phys == 0)
-			sas_port_delete(phy->port);
+			list_add_tail(&phy->port->del_list,
+				&parent->port->sas_port_del_list);
 		phy->port = NULL;
 	}
 }
@@ -2024,6 +2057,11 @@
 	if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) {
 		phy->phy_state = PHY_EMPTY;
 		sas_unregister_devs_sas_addr(dev, phy_id, last);
+		/*
+		 * Even though the PHY is empty, for convenience we discover
+		 * the PHY to update the PHY info, like negotiated linkrate.
+		 */
+		sas_ex_phy_discover(dev, phy_id);
 		return res;
 	} else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) &&
 		   dev_type_flutter(type, phy->attached_dev_type)) {
@@ -2039,14 +2077,11 @@
 		return res;
 	}
 
-	/* delete the old link */
-	if (SAS_ADDR(phy->attached_sas_addr) &&
-	    SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr)) {
-		SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n",
-			    SAS_ADDR(dev->sas_addr), phy_id,
-			    SAS_ADDR(phy->attached_sas_addr));
-		sas_unregister_devs_sas_addr(dev, phy_id, last);
-	}
+	/* we always have to delete the old device when we went here */
+	SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n",
+		    SAS_ADDR(dev->sas_addr), phy_id,
+		    SAS_ADDR(phy->attached_sas_addr));
+	sas_unregister_devs_sas_addr(dev, phy_id, last);
 
 	return sas_discover_new(dev, phy_id);
 }
@@ -2111,7 +2146,7 @@
 	struct domain_device *dev = NULL;
 
 	res = sas_find_bcast_dev(port_dev, &dev);
-	while (res == 0 && dev) {
+	if (res == 0 && dev) {
 		struct expander_device *ex = &dev->ex_dev;
 		int i = 0, phy_id;
 
@@ -2123,9 +2158,6 @@
 			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);
 	}
 	return res;
 }
--- linux-4.4.0.orig/drivers/scsi/libsas/sas_internal.h
+++ linux-4.4.0/drivers/scsi/libsas/sas_internal.h
@@ -98,6 +98,7 @@
 void sas_hae_reset(struct work_struct *work);
 
 void sas_free_device(struct kref *kref);
+void sas_destruct_devices(struct asd_sas_port *port);
 
 #ifdef CONFIG_SCSI_SAS_HOST_SMP
 extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
--- linux-4.4.0.orig/drivers/scsi/libsas/sas_port.c
+++ linux-4.4.0/drivers/scsi/libsas/sas_port.c
@@ -66,6 +66,7 @@
 		rc = sas_notify_lldd_dev_found(dev);
 		if (rc) {
 			sas_unregister_dev(port, dev);
+			sas_destruct_devices(port);
 			continue;
 		}
 
@@ -219,6 +220,7 @@
 
 	if (port->num_phys == 1) {
 		sas_unregister_domain_devices(port, gone);
+		sas_destruct_devices(port);
 		sas_port_delete(port->port);
 		port->port = NULL;
 	} else {
@@ -323,6 +325,7 @@
 	INIT_LIST_HEAD(&port->dev_list);
 	INIT_LIST_HEAD(&port->disco_list);
 	INIT_LIST_HEAD(&port->destroy_list);
+	INIT_LIST_HEAD(&port->sas_port_del_list);
 	spin_lock_init(&port->phy_list_lock);
 	INIT_LIST_HEAD(&port->phy_list);
 	port->ha = sas_ha;
--- linux-4.4.0.orig/drivers/scsi/libsas/sas_scsi_host.c
+++ linux-4.4.0/drivers/scsi/libsas/sas_scsi_host.c
@@ -222,6 +222,7 @@
 static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
 {
 	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host);
+	struct domain_device *dev = cmd_to_domain_dev(cmd);
 	struct sas_task *task = TO_SAS_TASK(cmd);
 
 	/* At this point, we only get called following an actual abort
@@ -230,6 +231,14 @@
 	 */
 	sas_end_task(cmd, task);
 
+	if (dev_is_sata(dev)) {
+		/* defer commands to libata so that libata EH can
+		 * handle ata qcs correctly
+		 */
+		list_move_tail(&cmd->eh_entry, &sas_ha->eh_ata_q);
+		return;
+	}
+
 	/* now finish the command and move it on to the error
 	 * handler done list, this also takes it off the
 	 * error handler pending list.
@@ -237,22 +246,6 @@
 	scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q);
 }
 
-static void sas_eh_defer_cmd(struct scsi_cmnd *cmd)
-{
-	struct domain_device *dev = cmd_to_domain_dev(cmd);
-	struct sas_ha_struct *ha = dev->port->ha;
-	struct sas_task *task = TO_SAS_TASK(cmd);
-
-	if (!dev_is_sata(dev)) {
-		sas_eh_finish_cmd(cmd);
-		return;
-	}
-
-	/* report the timeout to libata */
-	sas_end_task(cmd, task);
-	list_move_tail(&cmd->eh_entry, &ha->eh_ata_q);
-}
-
 static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
 {
 	struct scsi_cmnd *cmd, *n;
@@ -260,7 +253,7 @@
 	list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
 		if (cmd->device->sdev_target == my_cmd->device->sdev_target &&
 		    cmd->device->lun == my_cmd->device->lun)
-			sas_eh_defer_cmd(cmd);
+			sas_eh_finish_cmd(cmd);
 	}
 }
 
@@ -622,12 +615,12 @@
 		case TASK_IS_DONE:
 			SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
 				    task);
-			sas_eh_defer_cmd(cmd);
+			sas_eh_finish_cmd(cmd);
 			continue;
 		case TASK_IS_ABORTED:
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
 				    __func__, task);
-			sas_eh_defer_cmd(cmd);
+			sas_eh_finish_cmd(cmd);
 			continue;
 		case TASK_IS_AT_LU:
 			SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
@@ -638,7 +631,7 @@
 					    "recovered\n",
 					    SAS_ADDR(task->dev),
 					    cmd->device->lun);
-				sas_eh_defer_cmd(cmd);
+				sas_eh_finish_cmd(cmd);
 				sas_scsi_clear_queue_lu(work_q, cmd);
 				goto Again;
 			}
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc.h
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc.h
@@ -386,7 +386,6 @@
 	uint32_t work_port_events; /* Timeout to be handled  */
 #define WORKER_DISC_TMO                0x1	/* vport: Discovery timeout */
 #define WORKER_ELS_TMO                 0x2	/* vport: ELS timeout */
-#define WORKER_FDMI_TMO                0x4	/* vport: FDMI timeout */
 #define WORKER_DELAYED_DISC_TMO        0x8	/* vport: delayed discovery */
 
 #define WORKER_MBOX_TMO                0x100	/* hba: MBOX timeout */
@@ -396,7 +395,6 @@
 #define WORKER_RAMP_UP_QUEUE           0x1000	/* hba: Increase Q depth */
 #define WORKER_SERVICE_TXQ             0x2000	/* hba: IOCBs on the txq */
 
-	struct timer_list fc_fdmitmo;
 	struct timer_list els_tmofunc;
 	struct timer_list delayed_disc_tmo;
 
@@ -405,6 +403,7 @@
 	uint8_t load_flag;
 #define FC_LOADING		0x1	/* HBA in process of loading drvr */
 #define FC_UNLOADING		0x2	/* HBA in process of unloading drvr */
+#define FC_ALLOW_FDMI		0x4	/* port is ready for FDMI requests */
 	/* Vport Config Parameters */
 	uint32_t cfg_scan_down;
 	uint32_t cfg_lun_queue_depth;
@@ -414,10 +413,6 @@
 	uint32_t cfg_peer_port_login;
 	uint32_t cfg_fcp_class;
 	uint32_t cfg_use_adisc;
-	uint32_t cfg_fdmi_on;
-#define LPFC_FDMI_SUPPORT	1	/* bit 0 - FDMI supported? */
-#define LPFC_FDMI_REG_DELAY	2	/* bit 1 - 60 sec registration delay */
-#define LPFC_FDMI_ALL_ATTRIB	4	/* bit 2 - register ALL attributes? */
 	uint32_t cfg_discovery_threads;
 	uint32_t cfg_log_verbose;
 	uint32_t cfg_max_luns;
@@ -443,6 +438,10 @@
 	unsigned long rcv_buffer_time_stamp;
 	uint32_t vport_flag;
 #define STATIC_VPORT	1
+
+	uint16_t fdmi_num_disc;
+	uint32_t fdmi_hba_mask;
+	uint32_t fdmi_port_mask;
 };
 
 struct hbq_s {
@@ -755,6 +754,11 @@
 #define LPFC_DELAY_INIT_LINK              1	/* layered driver hold off */
 #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2	/* wait, manual intervention */
 	uint32_t cfg_enable_dss;
+	uint32_t cfg_fdmi_on;
+#define LPFC_FDMI_NO_SUPPORT	0	/* FDMI not supported */
+#define LPFC_FDMI_SUPPORT	1	/* FDMI supported? */
+#define LPFC_FDMI_SMART_SAN	2	/* SmartSAN supported */
+	uint32_t cfg_enable_SmartSAN;
 	lpfc_vpd_t vpd;		/* vital product data */
 
 	struct pci_dev *pcidev;
@@ -775,9 +779,9 @@
 
 	atomic_t fcp_qidx;		/* next work queue to post work to */
 
-	unsigned long pci_bar0_map;     /* Physical address for PCI BAR0 */
-	unsigned long pci_bar1_map;     /* Physical address for PCI BAR1 */
-	unsigned long pci_bar2_map;     /* Physical address for PCI BAR2 */
+	phys_addr_t pci_bar0_map;     /* Physical address for PCI BAR0 */
+	phys_addr_t pci_bar1_map;     /* Physical address for PCI BAR1 */
+	phys_addr_t pci_bar2_map;     /* Physical address for PCI BAR2 */
 	void __iomem *slim_memmap_p;	/* Kernel memory mapped address for
 					   PCI BAR0 */
 	void __iomem *ctrl_regs_memmap_p;/* Kernel memory mapped address for
@@ -867,7 +871,8 @@
 	struct list_head port_list;
 	struct lpfc_vport *pport;	/* physical lpfc_vport pointer */
 	uint16_t max_vpi;		/* Maximum virtual nports */
-#define LPFC_MAX_VPI 0xFFFF		/* Max number of VPI supported */
+#define LPFC_MAX_VPI	0xFF		/* Max number VPI supported 0 - 0xff */
+#define LPFC_MAX_VPORTS	0x100		/* Max vports per port, with pport */
 	uint16_t max_vports;            /*
 					 * For IOV HBAs max_vpi can change
 					 * after a reset. max_vports is max
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_attr.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_attr.c
@@ -634,7 +634,12 @@
 	LPFC_MBOXQ_t *pmboxq;
 	int mbxstatus = MBXERR_ERROR;
 
+	/*
+	 * If the link is offline, disabled or BLOCK_MGMT_IO
+	 * it doesn't make any sense to allow issue_lip
+	 */
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+	    (phba->hba_flag & LINK_DISABLED) ||
 	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
 		return -EPERM;
 
@@ -1208,6 +1213,9 @@
 		max_vpi = (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) > 0) ?
 			(bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - 1) : 0;
 
+		/* Limit the max we support */
+		if (max_vpi > LPFC_MAX_VPI)
+			max_vpi = LPFC_MAX_VPI;
 		if (mvpi)
 			*mvpi = max_vpi;
 		if (avpi)
@@ -1223,8 +1231,13 @@
 			*axri = pmb->un.varRdConfig.avail_xri;
 		if (mvpi)
 			*mvpi = pmb->un.varRdConfig.max_vpi;
-		if (avpi)
-			*avpi = pmb->un.varRdConfig.avail_vpi;
+		if (avpi) {
+			/* avail_vpi is only valid if link is up and ready */
+			if (phba->link_state == LPFC_HBA_READY)
+				*avpi = pmb->un.varRdConfig.avail_vpi;
+			else
+				*avpi = pmb->un.varRdConfig.max_vpi;
+		}
 	}
 
 	mempool_free(pmboxq, phba->mbox_mem_pool);
@@ -4572,19 +4585,27 @@
 	     255, "Identifies TYPE for additional ring configuration");
 
 /*
-# lpfc_fdmi_on: controls FDMI support.
-#               Set                NOT Set
-#       bit 0 = FDMI support       no FDMI support
-#           LPFC_FDMI_SUPPORT just turns basic support on/off
-#       bit 1 = Register delay     no register delay  (60 seconds)
-#           LPFC_FDMI_REG_DELAY	60 sec registration delay after FDMI login
-#       bit 2 = All attributes     Use a attribute subset
-#           LPFC_FDMI_ALL_ATTRIB applies to both port and HBA attributes
-#           Port attrutes subset: 1 thru 6 OR all: 1 thru 0xd 0x101 0x102 0x103
-#           HBA attributes subset: 1 thru 0xb OR all: 1 thru 0xc
-# Value range [0,7]. Default value is 0.
+# lpfc_enable_SmartSAN: Sets up FDMI support for SmartSAN
+#       0  = SmartSAN functionality disabled (default)
+#       1  = SmartSAN functionality enabled
+# This parameter will override the value of lpfc_fdmi_on module parameter.
+# Value range is [0,1]. Default value is 0.
 */
-LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 7, "Enable FDMI support");
+LPFC_ATTR_R(enable_SmartSAN, 0, 0, 1, "Enable SmartSAN functionality");
+
+/*
+# lpfc_fdmi_on: Controls FDMI support.
+#       0       No FDMI support (default)
+#       1       Traditional FDMI support
+#       2       Smart SAN support
+# If lpfc_enable_SmartSAN is set 1, the driver sets lpfc_fdmi_on to value 2
+# overwriting the current value.  If lpfc_enable_SmartSAN is set 0, the
+# driver uses the current value of lpfc_fdmi_on provided it has value 0 or 1.
+# A value of 2 with lpfc_enable_SmartSAN set to 0 causes the driver to
+# set lpfc_fdmi_on back to 1.
+# Value range [0,2]. Default value is 0.
+*/
+LPFC_ATTR_R(fdmi_on, 0, 0, 2, "Enable FDMI support");
 
 /*
 # Specifies the maximum number of ELS cmds we can have outstanding (for
@@ -4815,6 +4836,7 @@
 	&dev_attr_lpfc_multi_ring_rctl,
 	&dev_attr_lpfc_multi_ring_type,
 	&dev_attr_lpfc_fdmi_on,
+	&dev_attr_lpfc_enable_SmartSAN,
 	&dev_attr_lpfc_max_luns,
 	&dev_attr_lpfc_enable_npiv,
 	&dev_attr_lpfc_fcf_failover_policy,
@@ -4887,7 +4909,6 @@
 	&dev_attr_lpfc_fcp_class,
 	&dev_attr_lpfc_use_adisc,
 	&dev_attr_lpfc_first_burst_size,
-	&dev_attr_lpfc_fdmi_on,
 	&dev_attr_lpfc_max_luns,
 	&dev_attr_nport_evt_cnt,
 	&dev_attr_npiv_info,
@@ -5148,6 +5169,19 @@
  */
 
 /**
+ * lpfc_get_host_symbolic_name - Copy symbolic name into the scsi host
+ * @shost: kernel scsi host pointer.
+ **/
+static void
+lpfc_get_host_symbolic_name(struct Scsi_Host *shost)
+{
+	struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+
+	lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost),
+				      sizeof fc_host_symbolic_name(shost));
+}
+
+/**
  * lpfc_get_host_port_id - Copy the vport DID into the scsi host port id
  * @shost: kernel scsi host pointer.
  **/
@@ -5247,7 +5281,7 @@
 
 	spin_lock_irq(shost->host_lock);
 
-	if (lpfc_is_link_up(phba)) {
+	if ((lpfc_is_link_up(phba)) && (!(phba->hba_flag & HBA_FCOE_MODE))) {
 		switch(phba->fc_linkspeed) {
 		case LPFC_LINK_SPEED_1GHZ:
 			fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
@@ -5684,6 +5718,8 @@
 	.show_host_supported_fc4s = 1,
 	.show_host_supported_speeds = 1,
 	.show_host_maxframe_size = 1,
+
+	.get_host_symbolic_name = lpfc_get_host_symbolic_name,
 	.show_host_symbolic_name = 1,
 
 	/* dynamic attributes the driver supports */
@@ -5751,6 +5787,8 @@
 	.show_host_supported_fc4s = 1,
 	.show_host_supported_speeds = 1,
 	.show_host_maxframe_size = 1,
+
+	.get_host_symbolic_name = lpfc_get_host_symbolic_name,
 	.show_host_symbolic_name = 1,
 
 	/* dynamic attributes the driver supports */
@@ -5826,6 +5864,8 @@
 	lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
 	lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
 	lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
+	lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
+	lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
 	lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
 	lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
@@ -5846,6 +5886,15 @@
 		phba->cfg_poll = 0;
 	else
 		phba->cfg_poll = lpfc_poll;
+
+	/* Ensure fdmi_on and enable_SmartSAN don't conflict */
+	if (phba->cfg_enable_SmartSAN) {
+		phba->cfg_fdmi_on = LPFC_FDMI_SMART_SAN;
+	} else {
+		if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+			phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT;
+	}
+
 	phba->cfg_soft_wwnn = 0L;
 	phba->cfg_soft_wwpn = 0L;
 	lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
@@ -5879,7 +5928,6 @@
 	lpfc_use_adisc_init(vport, lpfc_use_adisc);
 	lpfc_first_burst_size_init(vport, lpfc_first_burst_size);
 	lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
-	lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
 	lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
 	lpfc_max_luns_init(vport, lpfc_max_luns);
 	lpfc_scan_down_init(vport, lpfc_scan_down);
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_bsg.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_bsg.c
@@ -4352,12 +4352,6 @@
 	phba->mbox_ext_buf_ctx.seqNum++;
 	nemb_tp = phba->mbox_ext_buf_ctx.nembType;
 
-	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
-	if (!dd_data) {
-		rc = -ENOMEM;
-		goto job_error;
-	}
-
 	pbuf = (uint8_t *)dmabuf->virt;
 	size = job->request_payload.payload_len;
 	sg_copy_to_buffer(job->request_payload.sg_list,
@@ -4394,6 +4388,13 @@
 				"2968 SLI_CONFIG ext-buffer wr all %d "
 				"ebuffers received\n",
 				phba->mbox_ext_buf_ctx.numBuf);
+
+		dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+		if (!dd_data) {
+			rc = -ENOMEM;
+			goto job_error;
+		}
+
 		/* mailbox command structure for base driver */
 		pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 		if (!pmboxq) {
@@ -4441,6 +4442,8 @@
 	return SLI_CONFIG_HANDLED;
 
 job_error:
+	if (pmboxq)
+		mempool_free(pmboxq, phba->mbox_mem_pool);
 	lpfc_bsg_dma_page_free(phba, dmabuf);
 	kfree(dd_data);
 
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_crtn.h
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_crtn.h
@@ -72,6 +72,7 @@
 void lpfc_retry_pport_discovery(struct lpfc_hba *);
 void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
 
+void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -167,9 +168,8 @@
 			 struct lpfc_iocbq *);
 int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
 int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
-int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
-void lpfc_fdmi_tmo(unsigned long);
-void lpfc_fdmi_timeout_handler(struct lpfc_vport *);
+int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t);
+void lpfc_fdmi_num_disc_check(struct lpfc_vport *);
 void lpfc_delayed_disc_tmo(unsigned long);
 void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
 
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_ct.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_ct.c
@@ -48,15 +48,26 @@
 #include "lpfc_vport.h"
 #include "lpfc_debugfs.h"
 
-/* FDMI Port Speed definitions */
-#define HBA_PORTSPEED_1GBIT		0x0001	/* 1 GBit/sec */
-#define HBA_PORTSPEED_2GBIT		0x0002	/* 2 GBit/sec */
-#define HBA_PORTSPEED_4GBIT		0x0008	/* 4 GBit/sec */
-#define HBA_PORTSPEED_10GBIT		0x0004	/* 10 GBit/sec */
-#define HBA_PORTSPEED_8GBIT		0x0010	/* 8 GBit/sec */
-#define HBA_PORTSPEED_16GBIT		0x0020	/* 16 GBit/sec */
-#define HBA_PORTSPEED_32GBIT		0x0040  /* 32 GBit/sec */
-#define HBA_PORTSPEED_UNKNOWN		0x0800	/* Unknown */
+/* FDMI Port Speed definitions - FC-GS-7 */
+#define HBA_PORTSPEED_1GFC		0x00000001	/* 1G FC */
+#define HBA_PORTSPEED_2GFC		0x00000002	/* 2G FC */
+#define HBA_PORTSPEED_4GFC		0x00000008	/* 4G FC */
+#define HBA_PORTSPEED_10GFC		0x00000004	/* 10G FC */
+#define HBA_PORTSPEED_8GFC		0x00000010	/* 8G FC */
+#define HBA_PORTSPEED_16GFC		0x00000020	/* 16G FC */
+#define HBA_PORTSPEED_32GFC		0x00000040	/* 32G FC */
+#define HBA_PORTSPEED_20GFC		0x00000080	/* 20G FC */
+#define HBA_PORTSPEED_40GFC		0x00000100	/* 40G FC */
+#define HBA_PORTSPEED_128GFC		0x00000200	/* 128G FC */
+#define HBA_PORTSPEED_64GFC		0x00000400	/* 64G FC */
+#define HBA_PORTSPEED_256GFC		0x00000800	/* 256G FC */
+#define HBA_PORTSPEED_UNKNOWN		0x00008000	/* Unknown */
+#define HBA_PORTSPEED_10GE		0x00010000	/* 10G E */
+#define HBA_PORTSPEED_40GE		0x00020000	/* 40G E */
+#define HBA_PORTSPEED_100GE		0x00040000	/* 100G E */
+#define HBA_PORTSPEED_25GE		0x00080000	/* 25G E */
+#define HBA_PORTSPEED_50GE		0x00100000	/* 50G E */
+#define HBA_PORTSPEED_400GE		0x00200000	/* 400G E */
 
 #define FOURBYTES	4
 
@@ -287,6 +298,17 @@
 	return 0;
 }
 
+/**
+ * lpfc_gen_req - Build and issue a GEN_REQUEST command  to the SLI Layer
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @bmp: Pointer to BPL for SLI command
+ * @inp: Pointer to data buffer for response data.
+ * @outp: Pointer to data buffer that hold the CT command.
+ * @cmpl: completion routine to call when command completes
+ * @ndlp: Destination NPort nodelist entry
+ *
+ * This function as the final part for issuing a CT command.
+ */
 static int
 lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
 	     struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
@@ -311,7 +333,7 @@
 	icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
 	icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
 	icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
-	icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64));
+	icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
 
 	if (usr_flg)
 		geniocb->context3 = NULL;
@@ -370,6 +392,16 @@
 	return 0;
 }
 
+/**
+ * lpfc_ct_cmd - Build and issue a CT command
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @inmp: Pointer to data buffer for response data.
+ * @bmp: Pointer to BPL for SLI command
+ * @ndlp: Destination NPort nodelist entry
+ * @cmpl: completion routine to call when command completes
+ *
+ * This function is called for issuing a CT command.
+ */
 static int
 lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
 	    struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
@@ -453,7 +485,7 @@
 			Cnt -= 16;	/* subtract length of CT header */
 
 		/* Loop through entire NameServer list of DIDs */
-		while (Cnt >= sizeof (uint32_t)) {
+		while (Cnt >= sizeof(uint32_t)) {
 			/* Get next DID from NameServer List */
 			CTentry = *ctptr++;
 			Did = ((be32_to_cpu(CTentry)) & Mask_DID);
@@ -558,7 +590,7 @@
 			}
 			if (CTentry & (cpu_to_be32(SLI_CT_LAST_ENTRY)))
 				goto nsout1;
-			Cnt -= sizeof (uint32_t);
+			Cnt -= sizeof(uint32_t);
 		}
 		ctptr = NULL;
 
@@ -1146,7 +1178,7 @@
 
 	/* fill in BDEs for command */
 	/* Allocate buffer for command payload */
-	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
 	if (!mp) {
 		rc=2;
 		goto ns_cmd_exit;
@@ -1160,7 +1192,7 @@
 	}
 
 	/* Allocate buffer for Buffer ptr list */
-	bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
 	if (!bmp) {
 		rc=4;
 		goto ns_cmd_free_mpvirt;
@@ -1204,7 +1236,7 @@
 	bpl->tus.w = le32_to_cpu(bpl->tus.w);
 
 	CtReq = (struct lpfc_sli_ct_request *) mp->virt;
-	memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request));
+	memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
 	CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
 	CtReq->RevisionId.bits.InId = 0;
 	CtReq->FsType = SLI_CT_DIRECTORY_SERVICE;
@@ -1244,7 +1276,7 @@
 		    cpu_to_be16(SLI_CTNS_RNN_ID);
 		CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
 		memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
-		       sizeof (struct lpfc_name));
+		       sizeof(struct lpfc_name));
 		cmpl = lpfc_cmpl_ct_cmd_rnn_id;
 		break;
 
@@ -1264,7 +1296,7 @@
 		CtReq->CommandResponse.bits.CmdRsp =
 		    cpu_to_be16(SLI_CTNS_RSNN_NN);
 		memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
-		       sizeof (struct lpfc_name));
+		       sizeof(struct lpfc_name));
 		size = sizeof(CtReq->un.rsnn.symbname);
 		CtReq->un.rsnn.len =
 			lpfc_vport_symbolic_node_name(vport,
@@ -1319,20 +1351,29 @@
 	return 1;
 }
 
+/**
+ * lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion
+ * @phba: Pointer to HBA context object.
+ * @cmdiocb: Pointer to the command IOCBQ.
+ * @rspiocb: Pointer to the response IOCBQ.
+ *
+ * This function to handle the completion of a driver initiated FDMI
+ * CT command issued during discovery.
+ */
 static void
-lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-		      struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+		       struct lpfc_iocbq *rspiocb)
 {
+	struct lpfc_vport *vport = cmdiocb->vport;
 	struct lpfc_dmabuf *inp = cmdiocb->context1;
 	struct lpfc_dmabuf *outp = cmdiocb->context2;
-	struct lpfc_sli_ct_request *CTrsp = outp->virt;
 	struct lpfc_sli_ct_request *CTcmd = inp->virt;
-	struct lpfc_nodelist *ndlp;
+	struct lpfc_sli_ct_request *CTrsp = outp->virt;
 	uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
 	uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
-	struct lpfc_vport *vport = cmdiocb->vport;
 	IOCB_t *irsp = &rspiocb->iocb;
-	uint32_t latt;
+	struct lpfc_nodelist *ndlp;
+	uint32_t latt, cmd, err;
 
 	latt = lpfc_els_chk_latt(vport);
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
@@ -1340,91 +1381,1115 @@
 		irsp->ulpStatus, irsp->un.ulpWord[4], latt);
 
 	if (latt || irsp->ulpStatus) {
+
+		/* Look for a retryable error */
+		if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+			switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) {
+			case IOERR_SLI_ABORTED:
+			case IOERR_ABORT_IN_PROGRESS:
+			case IOERR_SEQUENCE_TIMEOUT:
+			case IOERR_ILLEGAL_FRAME:
+			case IOERR_NO_RESOURCES:
+			case IOERR_ILLEGAL_COMMAND:
+				cmdiocb->retry++;
+				if (cmdiocb->retry >= LPFC_FDMI_MAX_RETRY)
+					break;
+
+				/* Retry the same FDMI command */
+				err = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING,
+							  cmdiocb, 0);
+				if (err == IOCB_ERROR)
+					break;
+				return;
+			default:
+				break;
+			}
+		}
+
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
 				 "0229 FDMI cmd %04x failed, latt = %d "
 				 "ulpStatus: x%x, rid x%x\n",
 				 be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
 				 irsp->un.ulpWord[4]);
-		goto fail_out;
 	}
+	lpfc_ct_free_iocb(phba, cmdiocb);
 
 	ndlp = lpfc_findnode_did(vport, FDMI_DID);
 	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
-		goto fail_out;
+		return;
 
+	/* Check for a CT LS_RJT response */
+	cmd =  be16_to_cpu(fdmi_cmd);
 	if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) {
 		/* FDMI rsp failed */
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-				 "0220 FDMI rsp failed Data: x%x\n",
-				 be16_to_cpu(fdmi_cmd));
-	}
+				 "0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
 
-fail_out:
-	lpfc_ct_free_iocb(phba, cmdiocb);
-}
-
-static void
-lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-		       struct lpfc_iocbq *rspiocb)
-{
-	struct lpfc_vport *vport = cmdiocb->vport;
-	struct lpfc_dmabuf *inp = cmdiocb->context1;
-	struct lpfc_sli_ct_request *CTcmd = inp->virt;
-	uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
-	struct lpfc_nodelist *ndlp;
+		/* Should we fallback to FDMI-2 / FDMI-1 ? */
+		switch (cmd) {
+		case SLI_MGMT_RHBA:
+			if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) {
+				/* Fallback to FDMI-1 */
+				vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+				vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+				/* Start over */
+				lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+			}
+			return;
 
-	lpfc_cmpl_ct_cmd_fdmi(phba, cmdiocb, rspiocb);
+		case SLI_MGMT_RPRT:
+			if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+				/* Fallback to FDMI-1 */
+				vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+				/* Start over */
+				lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+			}
+			if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+				vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+				/* Retry the same command */
+				lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+			}
+			return;
 
-	ndlp = lpfc_findnode_did(vport, FDMI_DID);
-	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
-		return;
+		case SLI_MGMT_RPA:
+			if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+				/* Fallback to FDMI-1 */
+				vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+				vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+				/* Start over */
+				lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+			}
+			if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+				vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+				/* Retry the same command */
+				lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+			}
+			return;
+		}
+	}
 
 	/*
-	 * Need to cycle thru FDMI registration for discovery
-	 * DHBA -> DPRT -> RHBA -> RPA
+	 * On success, need to cycle thru FDMI registration for discovery
+	 * DHBA -> DPRT -> RHBA -> RPA  (physical port)
+	 * DPRT -> RPRT (vports)
 	 */
-	switch (be16_to_cpu(fdmi_cmd)) {
+	switch (cmd) {
 	case SLI_MGMT_RHBA:
-		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA);
+		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0);
 		break;
 
 	case SLI_MGMT_DHBA:
-		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT);
+		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
 		break;
 
 	case SLI_MGMT_DPRT:
-		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
+		if (vport->port_type == LPFC_PHYSICAL_PORT)
+			lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0);
+		else
+			lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
 		break;
 	}
+	return;
+}
+
+
+/**
+ * lpfc_fdmi_num_disc_check - Check how many mapped NPorts we are connected to
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * Called from hbeat timeout routine to check if the number of discovered
+ * ports has changed. If so, re-register thar port Attribute.
+ */
+void
+lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_nodelist *ndlp;
+	uint16_t cnt;
+
+	if (!lpfc_is_link_up(phba))
+		return;
+
+	if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
+		return;
+
+	cnt = lpfc_find_map_node(vport);
+	if (cnt == vport->fdmi_num_disc)
+		return;
+
+	ndlp = lpfc_findnode_did(vport, FDMI_DID);
+	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+		return;
+
+	if (vport->port_type == LPFC_PHYSICAL_PORT) {
+		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
+			      LPFC_FDMI_PORT_ATTR_num_disc);
+	} else {
+		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT,
+			      LPFC_FDMI_PORT_ATTR_num_disc);
+	}
+}
+
+/* Routines for all individual HBA attributes */
+int
+lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, sizeof(struct lpfc_name));
+
+	memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+	       sizeof(struct lpfc_name));
+	size = FOURBYTES + sizeof(struct lpfc_name);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_NODENAME);
+	return size;
+}
+int
+lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
+				struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString,
+		"Emulex Corporation",
+		       sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString, phba->SerialNumber,
+		sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport,
+			 struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString, phba->ModelName,
+		sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_MODEL);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport,
+			       struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString, phba->ModelDesc,
+		sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString,
+				  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
+	return size;
 }
 
+int
+lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport,
+			   struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	lpfc_vpd_t *vp = &phba->vpd;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t i, j, incr, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	/* Convert JEDEC ID to ascii for hardware version */
+	incr = vp->rev.biuRev;
+	for (i = 0; i < 8; i++) {
+		j = (incr & 0xf);
+		if (j <= 9)
+			ae->un.AttrString[7 - i] =
+			    (char)((uint8_t) 0x30 +
+				   (uint8_t) j);
+		else
+			ae->un.AttrString[7 - i] =
+			    (char)((uint8_t) 0x61 +
+				   (uint8_t) (j - 10));
+		incr = (incr >> 4);
+	}
+	size = FOURBYTES + 8;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
+	return size;
+}
 
 int
-lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
+lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport,
+			    struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString, lpfc_release_version,
+		sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport,
+			   struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	if (phba->sli_rev == LPFC_SLI_REV4)
+		lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+	else
+		strncpy(ae->un.AttrString, phba->OptionROMVersion,
+			sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport,
+			   struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport,
+			  struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s %s %s",
+		 init_utsname()->sysname,
+		 init_utsname()->release,
+		 init_utsname()->version);
+
+	len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport,
+			  struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+	ae->un.AttrInt =  cpu_to_be32(LPFC_MAX_CT_SIZE);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport,
+				 struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	len = lpfc_vport_symbolic_node_name(vport,
+				ae->un.AttrString, 256);
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport,
+			       struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+	/* Nothing is defined for this currently */
+	ae->un.AttrInt =  cpu_to_be32(0);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_VENDOR_INFO);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport,
+			     struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+	/* Each driver instance corresponds to a single port */
+	ae->un.AttrInt =  cpu_to_be32(1);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_NUM_PORTS);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport,
+			       struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, sizeof(struct lpfc_name));
+
+	memcpy(&ae->un.AttrWWN, &vport->fabric_nodename,
+	       sizeof(struct lpfc_name));
+	size = FOURBYTES + sizeof(struct lpfc_name);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_FABRIC_WWNN);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
+			    struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_BIOS_VERSION);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport,
+			      struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+	/* Driver doesn't have access to this information */
+	ae->un.AttrInt =  cpu_to_be32(0);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_BIOS_STATE);
+	return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport,
+			     struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString, "EMULEX",
+		sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RHBA_VENDOR_ID);
+	return size;
+}
+
+/* Routines for all individual PORT attributes */
+int
+lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
+			    struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 32);
+
+	ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+	ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+	ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+	size = FOURBYTES + 32;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
+				  struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba   *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+	ae->un.AttrInt = 0;
+	if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+		if (phba->lmt & LMT_32Gb)
+			ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
+		if (phba->lmt & LMT_16Gb)
+			ae->un.AttrInt |= HBA_PORTSPEED_16GFC;
+		if (phba->lmt & LMT_10Gb)
+			ae->un.AttrInt |= HBA_PORTSPEED_10GFC;
+		if (phba->lmt & LMT_8Gb)
+			ae->un.AttrInt |= HBA_PORTSPEED_8GFC;
+		if (phba->lmt & LMT_4Gb)
+			ae->un.AttrInt |= HBA_PORTSPEED_4GFC;
+		if (phba->lmt & LMT_2Gb)
+			ae->un.AttrInt |= HBA_PORTSPEED_2GFC;
+		if (phba->lmt & LMT_1Gb)
+			ae->un.AttrInt |= HBA_PORTSPEED_1GFC;
+	} else {
+		/* FCoE links support only one speed */
+		switch (phba->fc_linkspeed) {
+		case LPFC_ASYNC_LINK_SPEED_10GBPS:
+			ae->un.AttrInt = HBA_PORTSPEED_10GE;
+			break;
+		case LPFC_ASYNC_LINK_SPEED_25GBPS:
+			ae->un.AttrInt = HBA_PORTSPEED_25GE;
+			break;
+		case LPFC_ASYNC_LINK_SPEED_40GBPS:
+			ae->un.AttrInt = HBA_PORTSPEED_40GE;
+			break;
+		case LPFC_ASYNC_LINK_SPEED_100GBPS:
+			ae->un.AttrInt = HBA_PORTSPEED_100GE;
+			break;
+		}
+	}
+	ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
+			  struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba   *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+	if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+		switch (phba->fc_linkspeed) {
+		case LPFC_LINK_SPEED_1GHZ:
+			ae->un.AttrInt = HBA_PORTSPEED_1GFC;
+			break;
+		case LPFC_LINK_SPEED_2GHZ:
+			ae->un.AttrInt = HBA_PORTSPEED_2GFC;
+			break;
+		case LPFC_LINK_SPEED_4GHZ:
+			ae->un.AttrInt = HBA_PORTSPEED_4GFC;
+			break;
+		case LPFC_LINK_SPEED_8GHZ:
+			ae->un.AttrInt = HBA_PORTSPEED_8GFC;
+			break;
+		case LPFC_LINK_SPEED_10GHZ:
+			ae->un.AttrInt = HBA_PORTSPEED_10GFC;
+			break;
+		case LPFC_LINK_SPEED_16GHZ:
+			ae->un.AttrInt = HBA_PORTSPEED_16GFC;
+			break;
+		case LPFC_LINK_SPEED_32GHZ:
+			ae->un.AttrInt = HBA_PORTSPEED_32GFC;
+			break;
+		default:
+			ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+			break;
+		}
+	} else {
+		switch (phba->fc_linkspeed) {
+		case LPFC_ASYNC_LINK_SPEED_10GBPS:
+			ae->un.AttrInt = HBA_PORTSPEED_10GE;
+			break;
+		case LPFC_ASYNC_LINK_SPEED_25GBPS:
+			ae->un.AttrInt = HBA_PORTSPEED_25GE;
+			break;
+		case LPFC_ASYNC_LINK_SPEED_40GBPS:
+			ae->un.AttrInt = HBA_PORTSPEED_40GE;
+			break;
+		case LPFC_ASYNC_LINK_SPEED_100GBPS:
+			ae->un.AttrInt = HBA_PORTSPEED_100GE;
+			break;
+		default:
+			ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+			break;
+		}
+	}
+
+	ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport,
+			      struct lpfc_fdmi_attr_def *ad)
+{
+	struct serv_parm *hsp;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+	hsp = (struct serv_parm *)&vport->fc_sparam;
+	ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb) << 8) |
+			  (uint32_t) hsp->cmn.bbRcvSizeLsb;
+	ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport,
+			       struct lpfc_fdmi_attr_def *ad)
+{
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	snprintf(ae->un.AttrString, sizeof(ae->un.AttrString),
+		 "/sys/class/scsi_host/host%d", shost->host_no);
+	len = strnlen((char *)ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
+			      struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
+		 init_utsname()->nodename);
+
+	len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport,
+			 struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0,  sizeof(struct lpfc_name));
+
+	memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+	       sizeof(struct lpfc_name));
+	size = FOURBYTES + sizeof(struct lpfc_name);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_NODENAME);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport,
+			 struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0,  sizeof(struct lpfc_name));
+
+	memcpy(&ae->un.AttrWWN, &vport->fc_sparam.portName,
+	       sizeof(struct lpfc_name));
+	size = FOURBYTES + sizeof(struct lpfc_name);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport,
+				  struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	len = lpfc_vport_symbolic_port_name(vport, ae->un.AttrString, 256);
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport,
+			      struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	if (phba->fc_topology == LPFC_TOPOLOGY_LOOP)
+		ae->un.AttrInt =  cpu_to_be32(LPFC_FDMI_PORTTYPE_NLPORT);
+	else
+		ae->un.AttrInt =  cpu_to_be32(LPFC_FDMI_PORTTYPE_NPORT);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_class(struct lpfc_vport *vport,
+			  struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	ae->un.AttrInt = cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport,
+				struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0,  sizeof(struct lpfc_name));
+
+	memcpy(&ae->un.AttrWWN, &vport->fabric_portname,
+	       sizeof(struct lpfc_name));
+	size = FOURBYTES + sizeof(struct lpfc_name);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
+				   struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 32);
+
+	ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+	ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+	ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+	size = FOURBYTES + 32;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport,
+			       struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	/* Link Up - operational */
+	ae->un.AttrInt =  cpu_to_be32(LPFC_FDMI_PORTSTATE_ONLINE);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport,
+			     struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	vport->fdmi_num_disc = lpfc_find_map_node(vport);
+	ae->un.AttrInt = cpu_to_be32(vport->fdmi_num_disc);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
+	return size;
+}
+
+int
+lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport,
+			    struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	ae->un.AttrInt =  cpu_to_be32(vport->fc_myDID);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
+	return size;
+}
+
+int
+lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport,
+			     struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString, "Smart SAN Initiator",
+		sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SMART_SERVICE);
+	return size;
+}
+
+int
+lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport,
+			  struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	memcpy(&ae->un.AttrString, &vport->fc_sparam.nodeName,
+	       sizeof(struct lpfc_name));
+	memcpy((((uint8_t *)&ae->un.AttrString) +
+		sizeof(struct lpfc_name)),
+		&vport->fc_sparam.portName, sizeof(struct lpfc_name));
+	size = FOURBYTES + (2 * sizeof(struct lpfc_name));
+	ad->AttrLen =  cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SMART_GUID);
+	return size;
+}
+
+int
+lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport,
+			     struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString, "Smart SAN Version 1.0",
+		sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString,
+			  sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen =  cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SMART_VERSION);
+	return size;
+}
+
+int
+lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport,
+			   struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t len, size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	memset(ae, 0, 256);
+
+	strncpy(ae->un.AttrString, phba->ModelName,
+		sizeof(ae->un.AttrString));
+	len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+	len += (len & 3) ? (4 - (len & 3)) : 4;
+	size = FOURBYTES + len;
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SMART_MODEL);
+	return size;
+}
+
+int
+lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport,
+			       struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+	/* SRIOV (type 3) is not supported */
+	if (vport->vpi)
+		ae->un.AttrInt =  cpu_to_be32(2);  /* NPIV */
+	else
+		ae->un.AttrInt =  cpu_to_be32(1);  /* Physical */
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SMART_PORT_INFO);
+	return size;
+}
+
+int
+lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport,
+			 struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	ae->un.AttrInt =  cpu_to_be32(0);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SMART_QOS);
+	return size;
+}
+
+int
+lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport,
+			      struct lpfc_fdmi_attr_def *ad)
+{
+	struct lpfc_fdmi_attr_entry *ae;
+	uint32_t size;
+
+	ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+	ae->un.AttrInt =  cpu_to_be32(0);
+	size = FOURBYTES + sizeof(uint32_t);
+	ad->AttrLen = cpu_to_be16(size);
+	ad->AttrType = cpu_to_be16(RPRT_SMART_SECURITY);
+	return size;
+}
+
+/* RHBA attribute jump table */
+int (*lpfc_fdmi_hba_action[])
+	(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+	/* Action routine                 Mask bit     Attribute type */
+	lpfc_fdmi_hba_attr_wwnn,	  /* bit0     RHBA_NODENAME           */
+	lpfc_fdmi_hba_attr_manufacturer,  /* bit1     RHBA_MANUFACTURER       */
+	lpfc_fdmi_hba_attr_sn,		  /* bit2     RHBA_SERIAL_NUMBER      */
+	lpfc_fdmi_hba_attr_model,	  /* bit3     RHBA_MODEL              */
+	lpfc_fdmi_hba_attr_description,	  /* bit4     RHBA_MODEL_DESCRIPTION  */
+	lpfc_fdmi_hba_attr_hdw_ver,	  /* bit5     RHBA_HARDWARE_VERSION   */
+	lpfc_fdmi_hba_attr_drvr_ver,	  /* bit6     RHBA_DRIVER_VERSION     */
+	lpfc_fdmi_hba_attr_rom_ver,	  /* bit7     RHBA_OPTION_ROM_VERSION */
+	lpfc_fdmi_hba_attr_fmw_ver,	  /* bit8     RHBA_FIRMWARE_VERSION   */
+	lpfc_fdmi_hba_attr_os_ver,	  /* bit9     RHBA_OS_NAME_VERSION    */
+	lpfc_fdmi_hba_attr_ct_len,	  /* bit10    RHBA_MAX_CT_PAYLOAD_LEN */
+	lpfc_fdmi_hba_attr_symbolic_name, /* bit11    RHBA_SYM_NODENAME       */
+	lpfc_fdmi_hba_attr_vendor_info,	  /* bit12    RHBA_VENDOR_INFO        */
+	lpfc_fdmi_hba_attr_num_ports,	  /* bit13    RHBA_NUM_PORTS          */
+	lpfc_fdmi_hba_attr_fabric_wwnn,	  /* bit14    RHBA_FABRIC_WWNN        */
+	lpfc_fdmi_hba_attr_bios_ver,	  /* bit15    RHBA_BIOS_VERSION       */
+	lpfc_fdmi_hba_attr_bios_state,	  /* bit16    RHBA_BIOS_STATE         */
+	lpfc_fdmi_hba_attr_vendor_id,	  /* bit17    RHBA_VENDOR_ID          */
+};
+
+/* RPA / RPRT attribute jump table */
+int (*lpfc_fdmi_port_action[])
+	(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+	/* Action routine                   Mask bit   Attribute type */
+	lpfc_fdmi_port_attr_fc4type,        /* bit0   RPRT_SUPPORT_FC4_TYPES  */
+	lpfc_fdmi_port_attr_support_speed,  /* bit1   RPRT_SUPPORTED_SPEED    */
+	lpfc_fdmi_port_attr_speed,          /* bit2   RPRT_PORT_SPEED         */
+	lpfc_fdmi_port_attr_max_frame,      /* bit3   RPRT_MAX_FRAME_SIZE     */
+	lpfc_fdmi_port_attr_os_devname,     /* bit4   RPRT_OS_DEVICE_NAME     */
+	lpfc_fdmi_port_attr_host_name,      /* bit5   RPRT_HOST_NAME          */
+	lpfc_fdmi_port_attr_wwnn,           /* bit6   RPRT_NODENAME           */
+	lpfc_fdmi_port_attr_wwpn,           /* bit7   RPRT_PORTNAME           */
+	lpfc_fdmi_port_attr_symbolic_name,  /* bit8   RPRT_SYM_PORTNAME       */
+	lpfc_fdmi_port_attr_port_type,      /* bit9   RPRT_PORT_TYPE          */
+	lpfc_fdmi_port_attr_class,          /* bit10  RPRT_SUPPORTED_CLASS    */
+	lpfc_fdmi_port_attr_fabric_wwpn,    /* bit11  RPRT_FABRICNAME         */
+	lpfc_fdmi_port_attr_active_fc4type, /* bit12  RPRT_ACTIVE_FC4_TYPES   */
+	lpfc_fdmi_port_attr_port_state,     /* bit13  RPRT_PORT_STATE         */
+	lpfc_fdmi_port_attr_num_disc,       /* bit14  RPRT_DISC_PORT          */
+	lpfc_fdmi_port_attr_nportid,        /* bit15  RPRT_PORT_ID            */
+	lpfc_fdmi_smart_attr_service,       /* bit16  RPRT_SMART_SERVICE      */
+	lpfc_fdmi_smart_attr_guid,          /* bit17  RPRT_SMART_GUID         */
+	lpfc_fdmi_smart_attr_version,       /* bit18  RPRT_SMART_VERSION      */
+	lpfc_fdmi_smart_attr_model,         /* bit19  RPRT_SMART_MODEL        */
+	lpfc_fdmi_smart_attr_port_info,     /* bit20  RPRT_SMART_PORT_INFO    */
+	lpfc_fdmi_smart_attr_qos,           /* bit21  RPRT_SMART_QOS          */
+	lpfc_fdmi_smart_attr_security,      /* bit22  RPRT_SMART_SECURITY     */
+};
+
+/**
+ * lpfc_fdmi_cmd - Build and send a FDMI cmd to the specified NPort
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
+ * cmdcode: FDMI command to send
+ * mask: Mask of HBA or PORT Attributes to send
+ *
+ * Builds and sends a FDMI command using the CT subsystem.
+ */
+int
+lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+	      int cmdcode, uint32_t new_mask)
 {
 	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_dmabuf *mp, *bmp;
 	struct lpfc_sli_ct_request *CtReq;
 	struct ulp_bde64 *bpl;
+	uint32_t bit_pos;
 	uint32_t size;
 	uint32_t rsp_size;
+	uint32_t mask;
 	struct lpfc_fdmi_reg_hba *rh;
 	struct lpfc_fdmi_port_entry *pe;
 	struct lpfc_fdmi_reg_portattr *pab = NULL;
 	struct lpfc_fdmi_attr_block *ab = NULL;
-	struct lpfc_fdmi_attr_entry *ae;
-	struct lpfc_fdmi_attr_def *ad;
-	void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
-		      struct lpfc_iocbq *);
+	int  (*func)(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad);
+	void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
+		     struct lpfc_iocbq *);
 
-	if (ndlp == NULL) {
-		ndlp = lpfc_findnode_did(vport, FDMI_DID);
-		if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
-			return 0;
-		cmpl = lpfc_cmpl_ct_cmd_fdmi; /* cmd interface */
-	} else {
-		cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
-	}
+	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+		return 0;
+
+	cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
 
 	/* fill in BDEs for command */
 	/* Allocate buffer for command payload */
@@ -1470,573 +2535,99 @@
 	switch (cmdcode) {
 	case SLI_MGMT_RHAT:
 	case SLI_MGMT_RHBA:
-		{
-			lpfc_vpd_t *vp = &phba->vpd;
-			uint32_t i, j, incr;
-			int len = 0;
+		rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
+		/* HBA Identifier */
+		memcpy(&rh->hi.PortName, &phba->pport->fc_sparam.portName,
+		       sizeof(struct lpfc_name));
 
-			rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
-			/* HBA Identifier */
-			memcpy(&rh->hi.PortName, &vport->fc_sparam.portName,
+		if (cmdcode == SLI_MGMT_RHBA) {
+			/* Registered Port List */
+			/* One entry (port) per adapter */
+			rh->rpl.EntryCnt = cpu_to_be32(1);
+			memcpy(&rh->rpl.pe, &phba->pport->fc_sparam.portName,
 			       sizeof(struct lpfc_name));
 
-			if (cmdcode == SLI_MGMT_RHBA) {
-				/* Registered Port List */
-				/* One entry (port) per adapter */
-				rh->rpl.EntryCnt = cpu_to_be32(1);
-				memcpy(&rh->rpl.pe, &vport->fc_sparam.portName,
-				       sizeof(struct lpfc_name));
-
-				/* point to the HBA attribute block */
-				size = 2 * sizeof(struct lpfc_name) +
-					FOURBYTES;
-			} else {
-				size = sizeof(struct lpfc_name);
-			}
-			ab = (struct lpfc_fdmi_attr_block *)
-				((uint8_t *)rh + size);
-			ab->EntryCnt = 0;
-			size += FOURBYTES;
+			/* point to the HBA attribute block */
+			size = 2 * sizeof(struct lpfc_name) +
+				FOURBYTES;
+		} else {
+			size = sizeof(struct lpfc_name);
+		}
+		ab = (struct lpfc_fdmi_attr_block *)((uint8_t *)rh + size);
+		ab->EntryCnt = 0;
+		size += FOURBYTES;
+		bit_pos = 0;
+		if (new_mask)
+			mask = new_mask;
+		else
+			mask = vport->fdmi_hba_mask;
 
-			/*
-			 * Point to beginning of first HBA attribute entry
-			 */
-			/* #1 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(struct lpfc_name));
-			ad->AttrType = cpu_to_be16(RHBA_NODENAME);
-			ad->AttrLen =  cpu_to_be16(FOURBYTES
-						+ sizeof(struct lpfc_name));
-			memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
-			       sizeof(struct lpfc_name));
-			ab->EntryCnt++;
-			size += FOURBYTES + sizeof(struct lpfc_name);
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #2 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.Manufacturer));
-			ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
-			strncpy(ae->un.Manufacturer, "Emulex Corporation",
-				sizeof(ae->un.Manufacturer));
-			len = strnlen(ae->un.Manufacturer,
-					  sizeof(ae->un.Manufacturer));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #3 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.SerialNumber));
-			ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
-			strncpy(ae->un.SerialNumber, phba->SerialNumber,
-				sizeof(ae->un.SerialNumber));
-			len = strnlen(ae->un.SerialNumber,
-					  sizeof(ae->un.SerialNumber));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #4 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.Model));
-			ad->AttrType = cpu_to_be16(RHBA_MODEL);
-			strncpy(ae->un.Model, phba->ModelName,
-				sizeof(ae->un.Model));
-			len = strnlen(ae->un.Model, sizeof(ae->un.Model));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #5 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.ModelDescription));
-			ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
-			strncpy(ae->un.ModelDescription, phba->ModelDesc,
-				sizeof(ae->un.ModelDescription));
-			len = strnlen(ae->un.ModelDescription,
-					  sizeof(ae->un.ModelDescription));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + 8) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #6 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, 8);
-			ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 8);
-			/* Convert JEDEC ID to ascii for hardware version */
-			incr = vp->rev.biuRev;
-			for (i = 0; i < 8; i++) {
-				j = (incr & 0xf);
-				if (j <= 9)
-					ae->un.HardwareVersion[7 - i] =
-					    (char)((uint8_t)0x30 +
-						   (uint8_t)j);
-				else
-					ae->un.HardwareVersion[7 - i] =
-					    (char)((uint8_t)0x61 +
-						   (uint8_t)(j - 10));
-				incr = (incr >> 4);
+		/* Mask will dictate what attributes to build in the request */
+		while (mask) {
+			if (mask & 0x1) {
+				func = lpfc_fdmi_hba_action[bit_pos];
+				size += func(vport,
+					     (struct lpfc_fdmi_attr_def *)
+					     ((uint8_t *)rh + size));
+				ab->EntryCnt++;
+				if ((size + 256) >
+				    (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+					goto hba_out;
 			}
-			ab->EntryCnt++;
-			size += FOURBYTES + 8;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #7 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.DriverVersion));
-			ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
-			strncpy(ae->un.DriverVersion, lpfc_release_version,
-				sizeof(ae->un.DriverVersion));
-			len = strnlen(ae->un.DriverVersion,
-					sizeof(ae->un.DriverVersion));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #8 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.OptionROMVersion));
-			ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
-			strncpy(ae->un.OptionROMVersion, phba->OptionROMVersion,
-				sizeof(ae->un.OptionROMVersion));
-			len = strnlen(ae->un.OptionROMVersion,
-				      sizeof(ae->un.OptionROMVersion));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #9 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.FirmwareVersion));
-			ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
-			lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion,
-				1);
-			len = strnlen(ae->un.FirmwareVersion,
-					sizeof(ae->un.FirmwareVersion));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #10 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.OsNameVersion));
-			ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
-			snprintf(ae->un.OsNameVersion,
-				 sizeof(ae->un.OsNameVersion),
-				 "%s %s %s",
-				 init_utsname()->sysname,
-				 init_utsname()->release,
-				 init_utsname()->version);
-			len = strnlen(ae->un.OsNameVersion,
-				      sizeof(ae->un.OsNameVersion));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/* #11 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType =
-				cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			ae->un.MaxCTPayloadLen = cpu_to_be32(LPFC_MAX_CT_SIZE);
-			ab->EntryCnt++;
-			size += FOURBYTES + 4;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto hba_out;
-
-			/*
-			 * Currently switches don't seem to support the
-			 * following extended HBA attributes.
-			 */
-			if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
-				goto hba_out;
-
-			/* #12 HBA attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)rh + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.NodeSymName));
-			ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
-			len = lpfc_vport_symbolic_node_name(vport,
-				ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			ab->EntryCnt++;
-			size += FOURBYTES + len;
-hba_out:
-			ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
-			/* Total size */
-			size = GID_REQUEST_SZ - 4 + size;
+			mask = mask >> 1;
+			bit_pos++;
 		}
+hba_out:
+		ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
+		/* Total size */
+		size = GID_REQUEST_SZ - 4 + size;
 		break;
 
 	case SLI_MGMT_RPRT:
 	case SLI_MGMT_RPA:
-		{
-			struct serv_parm *hsp;
-			int len = 0;
-
-			if (cmdcode == SLI_MGMT_RPRT) {
-				rh = (struct lpfc_fdmi_reg_hba *)
-					&CtReq->un.PortID;
-				/* HBA Identifier */
-				memcpy(&rh->hi.PortName,
-				       &vport->fc_sparam.portName,
-				       sizeof(struct lpfc_name));
-				pab = (struct lpfc_fdmi_reg_portattr *)
-					&rh->rpl.EntryCnt;
-			} else
-				pab = (struct lpfc_fdmi_reg_portattr *)
-					&CtReq->un.PortID;
-			size = sizeof(struct lpfc_name) + FOURBYTES;
-			memcpy((uint8_t *)&pab->PortName,
-			       (uint8_t *)&vport->fc_sparam.portName,
+		pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID;
+		if (cmdcode == SLI_MGMT_RPRT) {
+			rh = (struct lpfc_fdmi_reg_hba *)pab;
+			/* HBA Identifier */
+			memcpy(&rh->hi.PortName,
+			       &phba->pport->fc_sparam.portName,
 			       sizeof(struct lpfc_name));
-			pab->ab.EntryCnt = 0;
-
-			/* #1 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.FC4Types));
-			ad->AttrType =
-				cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
-			ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
-			ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
-			ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 32;
-
-			/* #2 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			ae->un.SupportSpeed = 0;
-			if (phba->lmt & LMT_32Gb)
-				ae->un.SupportSpeed |= HBA_PORTSPEED_32GBIT;
-			if (phba->lmt & LMT_16Gb)
-				ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT;
-			if (phba->lmt & LMT_10Gb)
-				ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT;
-			if (phba->lmt & LMT_8Gb)
-				ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
-			if (phba->lmt & LMT_4Gb)
-				ae->un.SupportSpeed |= HBA_PORTSPEED_4GBIT;
-			if (phba->lmt & LMT_2Gb)
-				ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT;
-			if (phba->lmt & LMT_1Gb)
-				ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT;
-			ae->un.SupportSpeed =
-				cpu_to_be32(ae->un.SupportSpeed);
-
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 4;
-
-			/* #3 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			switch (phba->fc_linkspeed) {
-			case LPFC_LINK_SPEED_1GHZ:
-				ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
-				break;
-			case LPFC_LINK_SPEED_2GHZ:
-				ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
-				break;
-			case LPFC_LINK_SPEED_4GHZ:
-				ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
-				break;
-			case LPFC_LINK_SPEED_8GHZ:
-				ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
-				break;
-			case LPFC_LINK_SPEED_10GHZ:
-				ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
-				break;
-			case LPFC_LINK_SPEED_16GHZ:
-				ae->un.PortSpeed = HBA_PORTSPEED_16GBIT;
-				break;
-			case LPFC_LINK_SPEED_32GHZ:
-				ae->un.PortSpeed = HBA_PORTSPEED_32GBIT;
-				break;
-			default:
-				ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN;
-				break;
-			}
-			ae->un.PortSpeed = cpu_to_be32(ae->un.PortSpeed);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 4;
-
-			/* #4 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			hsp = (struct serv_parm *)&vport->fc_sparam;
-			ae->un.MaxFrameSize =
-			    (((uint32_t)hsp->cmn.
-			      bbRcvSizeMsb) << 8) | (uint32_t)hsp->cmn.
-			    bbRcvSizeLsb;
-			ae->un.MaxFrameSize =
-				cpu_to_be32(ae->un.MaxFrameSize);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 4;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #5 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.OsDeviceName));
-			ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
-			strncpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME,
-				sizeof(ae->un.OsDeviceName));
-			len = strnlen((char *)ae->un.OsDeviceName,
-					  sizeof(ae->un.OsDeviceName));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #6 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.HostName));
-			snprintf(ae->un.HostName, sizeof(ae->un.HostName), "%s",
-				 init_utsname()->nodename);
-			ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
-			len = strnlen(ae->un.HostName,
-					sizeof(ae->un.HostName));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen =
-				cpu_to_be16(FOURBYTES + len);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + sizeof(struct lpfc_name)) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
+			pab = (struct lpfc_fdmi_reg_portattr *)
+				((uint8_t *)pab +  sizeof(struct lpfc_name));
+		}
 
-			/*
-			 * Currently switches don't seem to support the
-			 * following extended Port attributes.
-			 */
-			if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
-				goto port_out;
+		memcpy((uint8_t *)&pab->PortName,
+		       (uint8_t *)&vport->fc_sparam.portName,
+		       sizeof(struct lpfc_name));
+		size += sizeof(struct lpfc_name) + FOURBYTES;
+		pab->ab.EntryCnt = 0;
+		bit_pos = 0;
+		if (new_mask)
+			mask = new_mask;
+		else
+			mask = vport->fdmi_port_mask;
 
-			/* #7 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0,  sizeof(struct lpfc_name));
-			ad->AttrType = cpu_to_be16(RPRT_NODENAME);
-			ad->AttrLen =  cpu_to_be16(FOURBYTES
-						+ sizeof(struct lpfc_name));
-			memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
-			       sizeof(struct lpfc_name));
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + sizeof(struct lpfc_name);
-			if ((size + sizeof(struct lpfc_name)) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #8 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0,  sizeof(struct lpfc_name));
-			ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
-			ad->AttrLen =  cpu_to_be16(FOURBYTES
-						+ sizeof(struct lpfc_name));
-			memcpy(&ae->un.PortName, &vport->fc_sparam.portName,
-			       sizeof(struct lpfc_name));
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + sizeof(struct lpfc_name);
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #9 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.NodeSymName));
-			ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
-			len = lpfc_vport_symbolic_port_name(vport,
-				ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
-			len += (len & 3) ? (4 - (len & 3)) : 4;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + len;
-			if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #10 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
-			ae->un.PortState = 0;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 4;
-			if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #11 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
-			ae->un.SupportClass =
-				cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 4;
-			if ((size + sizeof(struct lpfc_name)) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #12 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(struct lpfc_name));
-			ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
-			ad->AttrLen =  cpu_to_be16(FOURBYTES
-						+ sizeof(struct lpfc_name));
-			memcpy(&ae->un.FabricName, &vport->fabric_nodename,
-			       sizeof(struct lpfc_name));
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + sizeof(struct lpfc_name);
-			if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-					(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #13 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			memset(ae, 0, sizeof(ae->un.FC4Types));
-			ad->AttrType =
-				cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
-			ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
-			ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
-			ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 32;
-			if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #257 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
-			ae->un.PortState = 0;
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 4;
-			if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #258 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
-			ae->un.PortState = lpfc_find_map_node(vport);
-			ae->un.PortState = cpu_to_be32(ae->un.PortState);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 4;
-			if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-				goto port_out;
-
-			/* #259 Port attribute entry */
-			ad = (struct lpfc_fdmi_attr_def *)
-				((uint8_t *)pab + size);
-			ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-			ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
-			ae->un.PortId =  cpu_to_be32(vport->fc_myDID);
-			ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-			pab->ab.EntryCnt++;
-			size += FOURBYTES + 4;
-port_out:
-			pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
-			/* Total size */
-			size = GID_REQUEST_SZ - 4 + size;
+		/* Mask will dictate what attributes to build in the request */
+		while (mask) {
+			if (mask & 0x1) {
+				func = lpfc_fdmi_port_action[bit_pos];
+				size += func(vport,
+					     (struct lpfc_fdmi_attr_def *)
+					     ((uint8_t *)pab + size));
+				pab->ab.EntryCnt++;
+				if ((size + 256) >
+				    (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+					goto port_out;
+			}
+			mask = mask >> 1;
+			bit_pos++;
 		}
+port_out:
+		pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
+		/* Total size */
+		if (cmdcode == SLI_MGMT_RPRT)
+			size += sizeof(struct lpfc_name);
+		size = GID_REQUEST_SZ - 4 + size;
 		break;
 
 	case SLI_MGMT_GHAT:
@@ -2158,41 +2749,6 @@
 }
 
 void
-lpfc_fdmi_tmo(unsigned long ptr)
-{
-	struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
-	struct lpfc_hba   *phba = vport->phba;
-	uint32_t tmo_posted;
-	unsigned long iflag;
-
-	spin_lock_irqsave(&vport->work_port_lock, iflag);
-	tmo_posted = vport->work_port_events & WORKER_FDMI_TMO;
-	if (!tmo_posted)
-		vport->work_port_events |= WORKER_FDMI_TMO;
-	spin_unlock_irqrestore(&vport->work_port_lock, iflag);
-
-	if (!tmo_posted)
-		lpfc_worker_wake_up(phba);
-	return;
-}
-
-void
-lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
-{
-	struct lpfc_nodelist *ndlp;
-
-	ndlp = lpfc_findnode_did(vport, FDMI_DID);
-	if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
-		if (init_utsname()->nodename[0] != '\0')
-			lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
-		else
-			mod_timer(&vport->fc_fdmitmo, jiffies +
-				  msecs_to_jiffies(1000 * 60));
-	}
-	return;
-}
-
-void
 lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
 {
 	struct lpfc_sli *psli = &phba->sli;
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_els.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_els.c
@@ -455,9 +455,9 @@
 lpfc_issue_reg_vfi(struct lpfc_vport *vport)
 {
 	struct lpfc_hba  *phba = vport->phba;
-	LPFC_MBOXQ_t *mboxq;
+	LPFC_MBOXQ_t *mboxq = NULL;
 	struct lpfc_nodelist *ndlp;
-	struct lpfc_dmabuf *dmabuf;
+	struct lpfc_dmabuf *dmabuf = NULL;
 	int rc = 0;
 
 	/* move forward in case of SLI4 FC port loopback test and pt2pt mode */
@@ -471,25 +471,33 @@
 		}
 	}
 
-	dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-	if (!dmabuf) {
+	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
 		rc = -ENOMEM;
 		goto fail;
 	}
-	dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
-	if (!dmabuf->virt) {
-		rc = -ENOMEM;
-		goto fail_free_dmabuf;
-	}
 
-	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	if (!mboxq) {
-		rc = -ENOMEM;
-		goto fail_free_coherent;
+	/* Supply CSP's only if we are fabric connect or pt-to-pt connect */
+	if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) {
+		dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+		if (!dmabuf) {
+			rc = -ENOMEM;
+			goto fail;
+		}
+		dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+		if (!dmabuf->virt) {
+			rc = -ENOMEM;
+			goto fail;
+		}
+		memcpy(dmabuf->virt, &phba->fc_fabparam,
+		       sizeof(struct serv_parm));
 	}
+
 	vport->port_state = LPFC_FABRIC_CFG_LINK;
-	memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
-	lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+	if (dmabuf)
+		lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+	else
+		lpfc_reg_vfi(mboxq, vport, 0);
 
 	mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
 	mboxq->vport = vport;
@@ -497,17 +505,19 @@
 	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
 	if (rc == MBX_NOT_FINISHED) {
 		rc = -ENXIO;
-		goto fail_free_mbox;
+		goto fail;
 	}
 	return 0;
 
-fail_free_mbox:
-	mempool_free(mboxq, phba->mbox_mem_pool);
-fail_free_coherent:
-	lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-fail_free_dmabuf:
-	kfree(dmabuf);
 fail:
+	if (mboxq)
+		mempool_free(mboxq, phba->mbox_mem_pool);
+	if (dmabuf) {
+		if (dmabuf->virt)
+			lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+		kfree(dmabuf);
+	}
+
 	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
 		"0289 Issue Register VFI failed: Err %d\n", rc);
@@ -678,6 +688,21 @@
 				sp->cmn.bbRcvSizeLsb;
 
 	fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+	if (fabric_param_changed) {
+		/* Reset FDMI attribute masks based on config parameter */
+		if (phba->cfg_fdmi_on == LPFC_FDMI_NO_SUPPORT) {
+			vport->fdmi_hba_mask = 0;
+			vport->fdmi_port_mask = 0;
+		} else {
+			/* Setup appropriate attribute masks */
+			vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+			if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+				vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+			else
+				vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+		}
+
+	}
 	memcpy(&vport->fabric_portname, &sp->portName,
 			sizeof(struct lpfc_name));
 	memcpy(&vport->fabric_nodename, &sp->nodeName,
@@ -711,9 +736,10 @@
 	 * For FC we need to do some special processing because of the SLI
 	 * Port's default settings of the Common Service Parameters.
 	 */
-	if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) {
+	if ((phba->sli_rev == LPFC_SLI_REV4) &&
+	    (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)) {
 		/* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
-		if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed)
+		if (fabric_param_changed)
 			lpfc_unregister_fcf_prep(phba);
 
 		/* This should just update the VFI CSPs*/
@@ -824,13 +850,21 @@
 
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+	vport->fc_flag |= FC_PT2PT;
 	spin_unlock_irq(shost->host_lock);
 
-	phba->fc_edtov = FF_DEF_EDTOV;
-	phba->fc_ratov = FF_DEF_RATOV;
+	/* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
+	if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
+		lpfc_unregister_fcf_prep(phba);
+
+		spin_lock_irq(shost->host_lock);
+		vport->fc_flag &= ~FC_VFI_REGISTERED;
+		spin_unlock_irq(shost->host_lock);
+		phba->fc_topology_changed = 0;
+	}
+
 	rc = memcmp(&vport->fc_portname, &sp->portName,
 		    sizeof(vport->fc_portname));
-	memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
 
 	if (rc >= 0) {
 		/* This side will initiate the PLOGI */
@@ -839,38 +873,14 @@
 		spin_unlock_irq(shost->host_lock);
 
 		/*
-		 * N_Port ID cannot be 0, set our to LocalID the other
-		 * side will be RemoteID.
+		 * N_Port ID cannot be 0, set our Id to LocalID
+		 * the other side will be RemoteID.
 		 */
 
 		/* not equal */
 		if (rc)
 			vport->fc_myDID = PT2PT_LocalID;
 
-		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-		if (!mbox)
-			goto fail;
-
-		lpfc_config_link(phba, mbox);
-
-		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		mbox->vport = vport;
-		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-		if (rc == MBX_NOT_FINISHED) {
-			mempool_free(mbox, phba->mbox_mem_pool);
-			goto fail;
-		}
-
-		/*
-		 * For SLI4, the VFI/VPI are registered AFTER the
-		 * Nport with the higher WWPN sends the PLOGI with
-		 * an assigned NPortId.
-		 */
-
-		/* not equal */
-		if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
-			lpfc_issue_reg_vfi(vport);
-
 		/* Decrement ndlp reference count indicating that ndlp can be
 		 * safely released when other references to it are done.
 		 */
@@ -912,29 +922,20 @@
 	/* If we are pt2pt with another NPort, force NPIV off! */
 	phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
 
-	spin_lock_irq(shost->host_lock);
-	vport->fc_flag |= FC_PT2PT;
-	spin_unlock_irq(shost->host_lock);
-	/* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
-	if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
-		lpfc_unregister_fcf_prep(phba);
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		goto fail;
 
-		/* The FC_VFI_REGISTERED flag will get clear in the cmpl
-		 * handler for unreg_vfi, but if we don't force the
-		 * FC_VFI_REGISTERED flag then the reg_vfi mailbox could be
-		 * built with the update bit set instead of just the vp bit to
-		 * change the Nport ID.  We need to have the vp set and the
-		 * Upd cleared on topology changes.
-		 */
-		spin_lock_irq(shost->host_lock);
-		vport->fc_flag &= ~FC_VFI_REGISTERED;
-		spin_unlock_irq(shost->host_lock);
-		phba->fc_topology_changed = 0;
-		lpfc_issue_reg_vfi(vport);
+	lpfc_config_link(phba, mbox);
+
+	mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
+	mbox->vport = vport;
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		mempool_free(mbox, phba->mbox_mem_pool);
+		goto fail;
 	}
 
-	/* Start discovery - this should just do CLEAR_LA */
-	lpfc_disc_start(vport);
 	return 0;
 fail:
 	return -ENXIO;
@@ -1068,7 +1069,10 @@
 					lpfc_sli4_unreg_all_rpis(vport);
 				}
 			}
-			lpfc_issue_reg_vfi(vport);
+
+			/* Do not register VFI if the driver aborted FLOGI */
+			if (!lpfc_error_lost_link(irsp))
+				lpfc_issue_reg_vfi(vport);
 			lpfc_nlp_put(ndlp);
 			goto out;
 		}
@@ -1135,6 +1139,7 @@
 			phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
 			phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO);
 			spin_unlock_irq(&phba->hbalock);
+			phba->fcf.fcf_redisc_attempted = 0; /* reset */
 			goto out;
 		}
 		if (!rc) {
@@ -1149,6 +1154,7 @@
 			phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
 			phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO);
 			spin_unlock_irq(&phba->hbalock);
+			phba->fcf.fcf_redisc_attempted = 0; /* reset */
 			goto out;
 		}
 	}
@@ -1157,6 +1163,7 @@
 	spin_lock_irq(&phba->hbalock);
 	phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
 	spin_unlock_irq(&phba->hbalock);
+
 	lpfc_nlp_put(ndlp);
 
 	if (!lpfc_error_lost_link(irsp)) {
@@ -1992,6 +1999,9 @@
 	if (sp->cmn.fcphHigh < FC_PH3)
 		sp->cmn.fcphHigh = FC_PH3;
 
+	sp->cmn.valid_vendor_ver_level = 0;
+	memset(sp->vendorVersion, 0, sizeof(sp->vendorVersion));
+
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
 		"Issue PLOGI:     did:x%x",
 		did, 0, 0);
@@ -3576,12 +3586,14 @@
 		} else {
 			buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
 			lpfc_els_free_data(phba, buf_ptr1);
+			elsiocb->context2 = NULL;
 		}
 	}
 
 	if (elsiocb->context3) {
 		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
 		lpfc_els_free_bpl(phba, buf_ptr);
+		elsiocb->context3 = NULL;
 	}
 	lpfc_sli_release_iocbq(phba, elsiocb);
 	return 0;
@@ -3792,14 +3804,17 @@
 				lpfc_nlp_set_state(vport, ndlp,
 					   NLP_STE_REG_LOGIN_ISSUE);
 			}
+
+			ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
 			if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
 			    != MBX_NOT_FINISHED)
 				goto out;
-			else
-				/* Decrement the ndlp reference count we
-				 * set for this failed mailbox command.
-				 */
-				lpfc_nlp_put(ndlp);
+
+			/* Decrement the ndlp reference count we
+			 * set for this failed mailbox command.
+			 */
+			lpfc_nlp_put(ndlp);
+			ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
 
 			/* ELS rsp: Cannot issue reg_login for <NPortid> */
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -3839,9 +3854,11 @@
 		mempool_free(mbox, phba->mbox_mem_pool);
 	}
 out:
-	if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
+	if (ndlp && NLP_CHK_NODE_ACT(ndlp) && shost) {
 		spin_lock_irq(shost->host_lock);
-		ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
+		if (mbox)
+			ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
+		ndlp->nlp_flag &= ~NLP_RM_DFLT_RPI;
 		spin_unlock_irq(shost->host_lock);
 
 		/* If the node is not being used by another discovery thread,
@@ -3856,6 +3873,7 @@
 				 * the routine lpfc_els_free_iocb.
 				 */
 				cmdiocb->context1 = NULL;
+
 	}
 
 	lpfc_els_free_iocb(phba, cmdiocb);
@@ -3898,6 +3916,7 @@
 	IOCB_t *oldcmd;
 	struct lpfc_iocbq *elsiocb;
 	uint8_t *pcmd;
+	struct serv_parm *sp;
 	uint16_t cmdsize;
 	int rc;
 	ELS_PKT *els_pkt_ptr;
@@ -3927,6 +3946,7 @@
 			"Issue ACC:       did:x%x flg:x%x",
 			ndlp->nlp_DID, ndlp->nlp_flag, 0);
 		break;
+	case ELS_CMD_FLOGI:
 	case ELS_CMD_PLOGI:
 		cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
 		elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
@@ -3944,10 +3964,37 @@
 
 		*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
 		pcmd += sizeof(uint32_t);
-		memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+		sp = (struct serv_parm *)pcmd;
+
+		if (flag == ELS_CMD_FLOGI) {
+			/* Copy the received service parameters back */
+			memcpy(sp, &phba->fc_fabparam,
+			       sizeof(struct serv_parm));
+
+			/* Clear the F_Port bit */
+			sp->cmn.fPort = 0;
+
+			/* Mark all class service parameters as invalid */
+			sp->cls1.classValid = 0;
+			sp->cls2.classValid = 0;
+			sp->cls3.classValid = 0;
+			sp->cls4.classValid = 0;
+
+			/* Copy our worldwide names */
+			memcpy(&sp->portName, &vport->fc_sparam.portName,
+			       sizeof(struct lpfc_name));
+			memcpy(&sp->nodeName, &vport->fc_sparam.nodeName,
+			       sizeof(struct lpfc_name));
+		} else {
+			memcpy(pcmd, &vport->fc_sparam,
+			       sizeof(struct serv_parm));
+
+			sp->cmn.valid_vendor_ver_level = 0;
+			memset(sp->vendorVersion, 0, sizeof(sp->vendorVersion));
+		}
 
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
-			"Issue ACC PLOGI: did:x%x flg:x%x",
+			"Issue ACC FLOGI/PLOGI: did:x%x flg:x%x",
 			ndlp->nlp_DID, ndlp->nlp_flag, 0);
 		break;
 	case ELS_CMD_PRLO:
@@ -4673,6 +4720,23 @@
 	desc->length = cpu_to_be32(sizeof(desc->info));
 }
 
+int
+lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat)
+{
+	if (bf_get(lpfc_read_link_stat_gec2, stat) == 0)
+		return 0;
+	desc->tag = cpu_to_be32(RDP_FEC_DESC_TAG);
+
+	desc->info.CorrectedBlocks =
+		cpu_to_be32(stat->fecCorrBlkCount);
+	desc->info.UncorrectableBlocks =
+		cpu_to_be32(stat->fecUncorrBlkCount);
+
+	desc->length = cpu_to_be32(sizeof(desc->info));
+
+	return sizeof(struct fc_fec_rdp_desc);
+}
+
 void
 lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
 {
@@ -4681,26 +4745,26 @@
 
 	desc->tag = cpu_to_be32(RDP_PORT_SPEED_DESC_TAG);
 
-	switch (phba->sli4_hba.link_state.speed) {
-	case LPFC_FC_LA_SPEED_1G:
+	switch (phba->fc_linkspeed) {
+	case LPFC_LINK_SPEED_1GHZ:
 		rdp_speed = RDP_PS_1GB;
 		break;
-	case LPFC_FC_LA_SPEED_2G:
+	case LPFC_LINK_SPEED_2GHZ:
 		rdp_speed = RDP_PS_2GB;
 		break;
-	case LPFC_FC_LA_SPEED_4G:
+	case LPFC_LINK_SPEED_4GHZ:
 		rdp_speed = RDP_PS_4GB;
 		break;
-	case LPFC_FC_LA_SPEED_8G:
+	case LPFC_LINK_SPEED_8GHZ:
 		rdp_speed = RDP_PS_8GB;
 		break;
-	case LPFC_FC_LA_SPEED_10G:
+	case LPFC_LINK_SPEED_10GHZ:
 		rdp_speed = RDP_PS_10GB;
 		break;
-	case LPFC_FC_LA_SPEED_16G:
+	case LPFC_LINK_SPEED_16GHZ:
 		rdp_speed = RDP_PS_16GB;
 		break;
-	case LPFC_FC_LA_SPEED_32G:
+	case LPFC_LINK_SPEED_32GHZ:
 		rdp_speed = RDP_PS_32GB;
 		break;
 	default:
@@ -4778,15 +4842,18 @@
 	struct lpfc_nodelist *ndlp = rdp_context->ndlp;
 	struct lpfc_vport *vport = ndlp->vport;
 	struct lpfc_iocbq *elsiocb;
+	struct ulp_bde64 *bpl;
 	IOCB_t *icmd;
 	uint8_t *pcmd;
 	struct ls_rjt *stat;
 	struct fc_rdp_res_frame *rdp_res;
 	uint32_t cmdsize;
-	int rc;
+	int rc, fec_size;
 
 	if (status != SUCCESS)
 		goto error;
+
+	/* This will change once we know the true size of the RDP payload */
 	cmdsize = sizeof(struct fc_rdp_res_frame);
 
 	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize,
@@ -4823,10 +4890,18 @@
 	lpfc_rdp_res_diag_port_names(&rdp_res->diag_port_names_desc, phba);
 	lpfc_rdp_res_attach_port_names(&rdp_res->attached_port_names_desc,
 			vport, ndlp);
-	rdp_res->length = cpu_to_be32(RDP_DESC_PAYLOAD_SIZE);
-
+	fec_size = lpfc_rdp_res_fec_desc(&rdp_res->fec_desc,
+			&rdp_context->link_stat);
+	rdp_res->length = cpu_to_be32(fec_size + RDP_DESC_PAYLOAD_SIZE);
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 
+	/* Now that we know the true size of the payload, update the BPL */
+	bpl = (struct ulp_bde64 *)
+		(((struct lpfc_dmabuf *)(elsiocb->context3))->virt);
+	bpl->tus.f.bdeSize = (fec_size + RDP_DESC_PAYLOAD_SIZE + 8);
+	bpl->tus.f.bdeFlags = 0;
+	bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
 	phba->fc_stat.elsXmitACC++;
 	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 	if (rc == IOCB_ERROR)
@@ -4956,13 +5031,12 @@
 	if (RDP_NPORT_ID_SIZE !=
 			be32_to_cpu(rdp_req->nport_id_desc.length))
 		goto rjt_logerr;
-	rdp_context = kmalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
+	rdp_context = kzalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
 	if (!rdp_context) {
 		rjt_err = LSRJT_UNABLE_TPC;
 		goto error;
 	}
 
-	memset(rdp_context, 0, sizeof(struct lpfc_rdp_context));
 	cmd = &cmdiocb->iocb;
 	rdp_context->ndlp = lpfc_nlp_get(ndlp);
 	rdp_context->ox_id = cmd->unsli3.rcvsli3.ox_id;
@@ -5080,6 +5154,9 @@
 	stat = (struct ls_rjt *)(pcmd + sizeof(uint32_t));
 	stat->un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 
+	if (shdr_add_status == ADD_STATUS_OPERATION_ALREADY_ACTIVE)
+		stat->un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
+
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	phba->fc_stat.elsXmitLSRJT++;
 	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
@@ -5739,7 +5816,6 @@
 	IOCB_t *icmd = &cmdiocb->iocb;
 	struct serv_parm *sp;
 	LPFC_MBOXQ_t *mbox;
-	struct ls_rjt stat;
 	uint32_t cmd, did;
 	int rc;
 	uint32_t fc_flag = 0;
@@ -5765,135 +5841,92 @@
 		return 1;
 	}
 
-	if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
-		/* For a FLOGI we accept, then if our portname is greater
-		 * then the remote portname we initiate Nport login.
-		 */
+	(void) lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1);
 
-		rc = memcmp(&vport->fc_portname, &sp->portName,
-			    sizeof(struct lpfc_name));
 
-		if (!rc) {
-			if (phba->sli_rev < LPFC_SLI_REV4) {
-				mbox = mempool_alloc(phba->mbox_mem_pool,
-						     GFP_KERNEL);
-				if (!mbox)
-					return 1;
-				lpfc_linkdown(phba);
-				lpfc_init_link(phba, mbox,
-					       phba->cfg_topology,
-					       phba->cfg_link_speed);
-				mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
-				mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-				mbox->vport = vport;
-				rc = lpfc_sli_issue_mbox(phba, mbox,
-							 MBX_NOWAIT);
-				lpfc_set_loopback_flag(phba);
-				if (rc == MBX_NOT_FINISHED)
-					mempool_free(mbox, phba->mbox_mem_pool);
-				return 1;
-			} else {
-				/* abort the flogi coming back to ourselves
-				 * due to external loopback on the port.
-				 */
-				lpfc_els_abort_flogi(phba);
-				return 0;
-			}
-		} else if (rc > 0) {	/* greater than */
-			spin_lock_irq(shost->host_lock);
-			vport->fc_flag |= FC_PT2PT_PLOGI;
-			spin_unlock_irq(shost->host_lock);
+	/*
+	 * If our portname is greater than the remote portname,
+	 * then we initiate Nport login.
+	 */
 
-			/* If we have the high WWPN we can assign our own
-			 * myDID; otherwise, we have to WAIT for a PLOGI
-			 * from the remote NPort to find out what it
-			 * will be.
-			 */
-			vport->fc_myDID = PT2PT_LocalID;
-		} else
-			vport->fc_myDID = PT2PT_RemoteID;
+	rc = memcmp(&vport->fc_portname, &sp->portName,
+		    sizeof(struct lpfc_name));
 
-		/*
-		 * The vport state should go to LPFC_FLOGI only
-		 * AFTER we issue a FLOGI, not receive one.
+	if (!rc) {
+		if (phba->sli_rev < LPFC_SLI_REV4) {
+			mbox = mempool_alloc(phba->mbox_mem_pool,
+					     GFP_KERNEL);
+			if (!mbox)
+				return 1;
+			lpfc_linkdown(phba);
+			lpfc_init_link(phba, mbox,
+				       phba->cfg_topology,
+				       phba->cfg_link_speed);
+			mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
+			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+			mbox->vport = vport;
+			rc = lpfc_sli_issue_mbox(phba, mbox,
+						 MBX_NOWAIT);
+			lpfc_set_loopback_flag(phba);
+			if (rc == MBX_NOT_FINISHED)
+				mempool_free(mbox, phba->mbox_mem_pool);
+			return 1;
+		}
+
+		/* abort the flogi coming back to ourselves
+		 * due to external loopback on the port.
 		 */
+		lpfc_els_abort_flogi(phba);
+		return 0;
+
+	} else if (rc > 0) {	/* greater than */
 		spin_lock_irq(shost->host_lock);
-		fc_flag = vport->fc_flag;
-		port_state = vport->port_state;
-		vport->fc_flag |= FC_PT2PT;
-		vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+		vport->fc_flag |= FC_PT2PT_PLOGI;
 		spin_unlock_irq(shost->host_lock);
-		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
-				 "3311 Rcv Flogi PS x%x new PS x%x "
-				 "fc_flag x%x new fc_flag x%x\n",
-				 port_state, vport->port_state,
-				 fc_flag, vport->fc_flag);
 
-		/*
-		 * We temporarily set fc_myDID to make it look like we are
-		 * a Fabric. This is done just so we end up with the right
-		 * did / sid on the FLOGI ACC rsp.
+		/* If we have the high WWPN we can assign our own
+		 * myDID; otherwise, we have to WAIT for a PLOGI
+		 * from the remote NPort to find out what it
+		 * will be.
 		 */
-		did = vport->fc_myDID;
-		vport->fc_myDID = Fabric_DID;
-
+		vport->fc_myDID = PT2PT_LocalID;
 	} else {
-		/* Reject this request because invalid parameters */
-		stat.un.b.lsRjtRsvd0 = 0;
-		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
-		stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
-		stat.un.b.vendorUnique = 0;
-
-		/*
-		 * We temporarily set fc_myDID to make it look like we are
-		 * a Fabric. This is done just so we end up with the right
-		 * did / sid on the FLOGI LS_RJT rsp.
-		 */
-		did = vport->fc_myDID;
-		vport->fc_myDID = Fabric_DID;
-
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
-			NULL);
+		vport->fc_myDID = PT2PT_RemoteID;
+	}
 
-		/* Now lets put fc_myDID back to what its supposed to be */
-		vport->fc_myDID = did;
+	/*
+	 * The vport state should go to LPFC_FLOGI only
+	 * AFTER we issue a FLOGI, not receive one.
+	 */
+	spin_lock_irq(shost->host_lock);
+	fc_flag = vport->fc_flag;
+	port_state = vport->port_state;
+	vport->fc_flag |= FC_PT2PT;
+	vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+	spin_unlock_irq(shost->host_lock);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "3311 Rcv Flogi PS x%x new PS x%x "
+			 "fc_flag x%x new fc_flag x%x\n",
+			 port_state, vport->port_state,
+			 fc_flag, vport->fc_flag);
 
-		return 1;
-	}
+	/*
+	 * We temporarily set fc_myDID to make it look like we are
+	 * a Fabric. This is done just so we end up with the right
+	 * did / sid on the FLOGI ACC rsp.
+	 */
+	did = vport->fc_myDID;
+	vport->fc_myDID = Fabric_DID;
 
-	/* send our FLOGI first */
-	if (vport->port_state < LPFC_FLOGI) {
-		vport->fc_myDID = 0;
-		lpfc_initial_flogi(vport);
-		vport->fc_myDID = Fabric_DID;
-	}
+	memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
 
 	/* Send back ACC */
-	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+	lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, cmdiocb, ndlp, NULL);
 
 	/* Now lets put fc_myDID back to what its supposed to be */
 	vport->fc_myDID = did;
 
-	if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
-		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-		if (!mbox)
-			goto fail;
-
-		lpfc_config_link(phba, mbox);
-
-		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		mbox->vport = vport;
-		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-		if (rc == MBX_NOT_FINISHED) {
-			mempool_free(mbox, phba->mbox_mem_pool);
-			goto fail;
-		}
-	}
-
 	return 0;
-fail:
-	return 1;
 }
 
 /**
@@ -6514,7 +6547,10 @@
 lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq)
 {
 	struct lpfc_nodelist *ndlp = lpfc_findnode_did(rrq->vport,
-							rrq->nlp_DID);
+						       rrq->nlp_DID);
+	if (!ndlp)
+		return 1;
+
 	if (lpfc_test_rrq_active(phba, ndlp, rrq->xritag))
 		return lpfc_issue_els_rrq(rrq->vport, ndlp,
 					 rrq->nlp_DID, rrq);
@@ -7326,6 +7362,8 @@
 	spin_lock_irq(shost->host_lock);
 	if (ndlp->nlp_flag & NLP_IN_DEV_LOSS) {
 		spin_unlock_irq(shost->host_lock);
+		if (newnode)
+			lpfc_nlp_put(ndlp);
 		goto dropit;
 	}
 	spin_unlock_irq(shost->host_lock);
@@ -7345,7 +7383,7 @@
 
 	/* reject till our FLOGI completes */
 	if ((vport->port_state < LPFC_FABRIC_CFG_LINK) &&
-		(cmd != ELS_CMD_FLOGI)) {
+	    (cmd != ELS_CMD_FLOGI)) {
 		rjt_err = LSRJT_UNABLE_TPC;
 		rjt_exp = LSEXP_NOTHING_MORE;
 		goto lsrjt;
@@ -7381,6 +7419,7 @@
 			rjt_exp = LSEXP_NOTHING_MORE;
 			break;
 		}
+
 		if (vport->port_state < LPFC_DISC_AUTH) {
 			if (!(phba->pport->fc_flag & FC_PT2PT) ||
 				(phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -7509,7 +7548,8 @@
 			did, vport->port_state, ndlp->nlp_flag);
 
 		phba->fc_stat.elsRcvPRLI++;
-		if (vport->port_state < LPFC_DISC_AUTH) {
+		if ((vport->port_state < LPFC_DISC_AUTH) &&
+		    (vport->fc_flag & FC_FABRIC)) {
 			rjt_err = LSRJT_UNABLE_TPC;
 			rjt_exp = LSEXP_NOTHING_MORE;
 			break;
@@ -7730,6 +7770,35 @@
 	}
 }
 
+void
+lpfc_start_fdmi(struct lpfc_vport *vport)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_nodelist *ndlp;
+
+	/* If this is the first time, allocate an ndlp and initialize
+	 * it. Otherwise, make sure the node is enabled and then do the
+	 * login.
+	 */
+	ndlp = lpfc_findnode_did(vport, FDMI_DID);
+	if (!ndlp) {
+		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+		if (ndlp) {
+			lpfc_nlp_init(vport, ndlp, FDMI_DID);
+			ndlp->nlp_type |= NLP_FABRIC;
+		} else {
+			return;
+		}
+	}
+	if (!NLP_CHK_NODE_ACT(ndlp))
+		ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE);
+
+	if (ndlp) {
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+		lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+	}
+}
+
 /**
  * lpfc_do_scr_ns_plogi - Issue a plogi to the name server for scr
  * @phba: pointer to lpfc hba data structure.
@@ -7746,7 +7815,7 @@
 void
 lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
 {
-	struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+	struct lpfc_nodelist *ndlp;
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
 	/*
@@ -7804,32 +7873,9 @@
 		return;
 	}
 
-	if (vport->cfg_fdmi_on & LPFC_FDMI_SUPPORT) {
-		/* If this is the first time, allocate an ndlp and initialize
-		 * it. Otherwise, make sure the node is enabled and then do the
-		 * login.
-		 */
-		ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
-		if (!ndlp_fdmi) {
-			ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
-						  GFP_KERNEL);
-			if (ndlp_fdmi) {
-				lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
-				ndlp_fdmi->nlp_type |= NLP_FABRIC;
-			} else
-				return;
-		}
-		if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
-			ndlp_fdmi = lpfc_enable_node(vport,
-						     ndlp_fdmi,
-						     NLP_STE_NPR_NODE);
-
-		if (ndlp_fdmi) {
-			lpfc_nlp_set_state(vport, ndlp_fdmi,
-					   NLP_STE_PLOGI_ISSUE);
-			lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
-		}
-	}
+	if ((phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) &&
+	    (vport->load_flag & FC_ALLOW_FDMI))
+		lpfc_start_fdmi(vport);
 }
 
 /**
@@ -7905,11 +7951,17 @@
 			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
 			spin_unlock_irq(shost->host_lock);
-			if (vport->port_type == LPFC_PHYSICAL_PORT
-				&& !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
-				lpfc_issue_init_vfi(vport);
-			else
+			if (mb->mbxStatus == MBX_NOT_FINISHED)
+				break;
+			if ((vport->port_type == LPFC_PHYSICAL_PORT) &&
+			    !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) {
+				if (phba->sli_rev == LPFC_SLI_REV4)
+					lpfc_issue_init_vfi(vport);
+				else
+					lpfc_initial_flogi(vport);
+			} else {
 				lpfc_initial_fdisc(vport);
+			}
 			break;
 		}
 	} else {
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -674,8 +674,6 @@
 				lpfc_mbox_timeout_handler(phba);
 			if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
 				lpfc_unblock_fabric_iocbs(phba);
-			if (work_port_events & WORKER_FDMI_TMO)
-				lpfc_fdmi_timeout_handler(vport);
 			if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
 				lpfc_ramp_down_queue_handler(phba);
 			if (work_port_events & WORKER_DELAYED_DISC_TMO)
@@ -691,8 +689,9 @@
 	    (phba->hba_flag & HBA_SP_QUEUE_EVT)) {
 		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
 			pring->flag |= LPFC_DEFERRED_RING_EVENT;
-			/* Set the lpfc data pending flag */
-			set_bit(LPFC_DATA_READY, &phba->data_flags);
+			/* Preserve legacy behavior. */
+			if (!(phba->hba_flag & HBA_SP_QUEUE_EVT))
+				set_bit(LPFC_DATA_READY, &phba->data_flags);
 		} else {
 			if (phba->link_state >= LPFC_LINK_UP) {
 				pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
@@ -901,7 +900,11 @@
 			lpfc_linkdown_port(vports[i]);
 		}
 	lpfc_destroy_vport_work_array(phba, vports);
-	/* Clean up any firmware default rpi's */
+
+	/* Clean up any SLI3 firmware default rpi's */
+	if (phba->sli_rev > LPFC_SLI_REV3)
+		goto skip_unreg_did;
+
 	mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (mb) {
 		lpfc_unreg_did(phba, 0xffff, LPFC_UNREG_ALL_DFLT_RPIS, mb);
@@ -913,6 +916,7 @@
 		}
 	}
 
+ skip_unreg_did:
 	/* Setup myDID for link up if we are in pt2pt mode */
 	if (phba->pport->fc_flag & FC_PT2PT) {
 		phba->pport->fc_myDID = 0;
@@ -1083,7 +1087,7 @@
 }
 
 
-static void
+void
 lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
 	struct lpfc_vport *vport = pmb->vport;
@@ -1113,8 +1117,10 @@
 	/* Start discovery by sending a FLOGI. port_state is identically
 	 * LPFC_FLOGI while waiting for FLOGI cmpl
 	 */
-	if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI)
+	if (vport->port_state != LPFC_FLOGI)
 		lpfc_initial_flogi(vport);
+	else if (vport->fc_flag & FC_PT2PT)
+		lpfc_disc_start(vport);
 	return;
 
 out:
@@ -1958,6 +1964,26 @@
 				"failover and change port state:x%x/x%x\n",
 				phba->pport->port_state, LPFC_VPORT_UNKNOWN);
 		phba->pport->port_state = LPFC_VPORT_UNKNOWN;
+
+		if (!phba->fcf.fcf_redisc_attempted) {
+			lpfc_unregister_fcf(phba);
+
+			rc = lpfc_sli4_redisc_fcf_table(phba);
+			if (!rc) {
+				lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+						"3195 Rediscover FCF table\n");
+				phba->fcf.fcf_redisc_attempted = 1;
+				lpfc_sli4_clear_fcf_rr_bmask(phba);
+			} else {
+				lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+						"3196 Rediscover FCF table "
+						"failed. Status:x%x\n", rc);
+			}
+		} else {
+			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+					"3197 Already rediscover FCF table "
+					"attempted. No more retry\n");
+		}
 		goto stop_flogi_current_fcf;
 	} else {
 		lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_ELS,
@@ -2963,8 +2989,10 @@
 
 out_free_mem:
 	mempool_free(mboxq, phba->mbox_mem_pool);
-	lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-	kfree(dmabuf);
+	if (dmabuf) {
+		lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+		kfree(dmabuf);
+	}
 	return;
 }
 
@@ -3035,19 +3063,22 @@
 	uint32_t fc_flags = 0;
 
 	spin_lock_irq(&phba->hbalock);
-	switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
-	case LPFC_LINK_SPEED_1GHZ:
-	case LPFC_LINK_SPEED_2GHZ:
-	case LPFC_LINK_SPEED_4GHZ:
-	case LPFC_LINK_SPEED_8GHZ:
-	case LPFC_LINK_SPEED_10GHZ:
-	case LPFC_LINK_SPEED_16GHZ:
-	case LPFC_LINK_SPEED_32GHZ:
-		phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
-		break;
-	default:
-		phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
-		break;
+	phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
+
+	if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+		switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
+		case LPFC_LINK_SPEED_1GHZ:
+		case LPFC_LINK_SPEED_2GHZ:
+		case LPFC_LINK_SPEED_4GHZ:
+		case LPFC_LINK_SPEED_8GHZ:
+		case LPFC_LINK_SPEED_10GHZ:
+		case LPFC_LINK_SPEED_16GHZ:
+		case LPFC_LINK_SPEED_32GHZ:
+			break;
+		default:
+			phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
+			break;
+		}
 	}
 
 	if (phba->fc_topology &&
@@ -3448,10 +3479,10 @@
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
 		spin_unlock_irq(shost->host_lock);
-	} else
-		/* Good status, call state machine */
-		lpfc_disc_state_machine(vport, ndlp, pmb,
-				NLP_EVT_CMPL_REG_LOGIN);
+	}
+
+	/* Call state machine */
+	lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
 
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
@@ -4642,6 +4673,10 @@
 	LPFC_MBOXQ_t     *mbox;
 	int rc;
 
+	/* Unreg DID is an SLI3 operation. */
+	if (phba->sli_rev > LPFC_SLI_REV3)
+		return;
+
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (mbox) {
 		lpfc_unreg_did(phba, vport->vpi, LPFC_UNREG_ALL_DFLT_RPIS,
@@ -4773,7 +4808,8 @@
 	lpfc_cancel_retry_delay_tmo(vport, ndlp);
 	if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
 	    !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
-	    !(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
+	    !(ndlp->nlp_flag & NLP_RPI_REGISTERED) &&
+	    phba->sli_rev != LPFC_SLI_REV4) {
 		/* For this case we need to cleanup the default rpi
 		 * allocated by the firmware.
 		 */
@@ -5550,15 +5586,15 @@
 			 ndlp->nlp_usg_map, ndlp);
 	/*
 	 * Start issuing Fabric-Device Management Interface (FDMI) command to
-	 * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if
-	 * fdmi-on=2 (supporting RPA/hostnmae)
+	 * 0xfffffa (FDMI well known port).
+	 * DHBA -> DPRT -> RHBA -> RPA  (physical port)
+	 * DPRT -> RPRT (vports)
 	 */
-
-	if (vport->cfg_fdmi_on & LPFC_FDMI_REG_DELAY)
-		mod_timer(&vport->fc_fdmitmo,
-			  jiffies + msecs_to_jiffies(1000 * 60));
+	if (vport->port_type == LPFC_PHYSICAL_PORT)
+		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
 	else
-		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+
 
 	/* decrement the node reference count held for this callback
 	 * function.
@@ -6139,7 +6175,9 @@
 	if (rc)
 		return;
 	/* Reset HBA FCF states after successful unregister FCF */
+	spin_lock_irq(&phba->hbalock);
 	phba->fcf.fcf_flag = 0;
+	spin_unlock_irq(&phba->hbalock);
 	phba->fcf.current_rec.flag = 0;
 
 	/*
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_hw.h
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_hw.h
@@ -360,6 +360,12 @@
  * Word 1 Bit 30 in PLOGI request is random offset
  */
 #define virtual_fabric_support randomOffset /* Word 1, bit 30 */
+/*
+ * Word 1 Bit 29 in common service parameter is overloaded.
+ * Word 1 Bit 29 in FLOGI response is multiple NPort assignment
+ * Word 1 Bit 29 in FLOGI/PLOGI request is Valid Vendor Version Level
+ */
+#define valid_vendor_ver_level response_multiple_NPort /* Word 1, bit 29 */
 #ifdef __BIG_ENDIAN_BITFIELD
 	uint16_t request_multiple_Nport:1;	/* FC Word 1, bit 31 */
 	uint16_t randomOffset:1;	/* FC Word 1, bit 30 */
@@ -1097,6 +1103,18 @@
 };
 
 
+struct fc_rdp_fec_info {
+	uint32_t CorrectedBlocks;
+	uint32_t UncorrectableBlocks;
+};
+
+#define RDP_FEC_DESC_TAG  0x00010005
+struct fc_fec_rdp_desc {
+	uint32_t tag;
+	uint32_t length;
+	struct fc_rdp_fec_info info;
+};
+
 struct fc_rdp_link_error_status_payload_info {
 	struct fc_link_status link_status; /* 24 bytes */
 	uint32_t  port_type;             /* bits 31-30 only */
@@ -1196,14 +1214,15 @@
 	struct fc_rdp_link_error_status_desc link_error_desc; /* Word 13-21 */
 	struct fc_rdp_port_name_desc diag_port_names_desc;    /* Word 22-27 */
 	struct fc_rdp_port_name_desc attached_port_names_desc;/* Word 28-33 */
+	struct fc_fec_rdp_desc fec_desc;	      /* FC Word 34 - 37 */
 };
 
 
 #define RDP_DESC_PAYLOAD_SIZE (sizeof(struct fc_rdp_link_service_desc) \
-			+ sizeof(struct fc_rdp_sfp_desc) \
-			+ sizeof(struct fc_rdp_port_speed_desc) \
-			+ sizeof(struct fc_rdp_link_error_status_desc) \
-			+ (sizeof(struct fc_rdp_port_name_desc) * 2))
+				+ sizeof(struct fc_rdp_sfp_desc) \
+				+ sizeof(struct fc_rdp_port_speed_desc) \
+				+ sizeof(struct fc_rdp_link_error_status_desc) \
+				+ (sizeof(struct fc_rdp_port_name_desc) * 2))
 
 
 /******** FDMI ********/
@@ -1233,31 +1252,10 @@
 /* Attribute Entry */
 struct lpfc_fdmi_attr_entry {
 	union {
-		uint32_t VendorSpecific;
-		uint32_t SupportClass;
-		uint32_t SupportSpeed;
-		uint32_t PortSpeed;
-		uint32_t MaxFrameSize;
-		uint32_t MaxCTPayloadLen;
-		uint32_t PortState;
-		uint32_t PortId;
-		struct lpfc_name NodeName;
-		struct lpfc_name PortName;
-		struct lpfc_name FabricName;
-		uint8_t FC4Types[32];
-		uint8_t Manufacturer[64];
-		uint8_t SerialNumber[64];
-		uint8_t Model[256];
-		uint8_t ModelDescription[256];
-		uint8_t HardwareVersion[256];
-		uint8_t DriverVersion[256];
-		uint8_t OptionROMVersion[256];
-		uint8_t FirmwareVersion[256];
-		uint8_t OsHostName[256];
-		uint8_t NodeSymName[256];
-		uint8_t OsDeviceName[256];
-		uint8_t OsNameVersion[256];
-		uint8_t HostName[256];
+		uint32_t AttrInt;
+		uint8_t  AttrTypes[32];
+		uint8_t  AttrString[256];
+		struct lpfc_name AttrWWN;
 	} un;
 };
 
@@ -1327,6 +1325,8 @@
 #define  SLI_MGMT_DPRT     0x310	/* De-register Port */
 #define  SLI_MGMT_DPA      0x311	/* De-register Port attributes */
 
+#define LPFC_FDMI_MAX_RETRY     3  /* Max retries for a FDMI command */
+
 /*
  * HBA Attribute Types
  */
@@ -1342,6 +1342,39 @@
 #define  RHBA_OS_NAME_VERSION	 0xa /* 4 to 256 byte ASCII string */
 #define  RHBA_MAX_CT_PAYLOAD_LEN 0xb /* 32-bit unsigned int */
 #define  RHBA_SYM_NODENAME       0xc /* 4 to 256 byte ASCII string */
+#define  RHBA_VENDOR_INFO        0xd  /* 32-bit unsigned int */
+#define  RHBA_NUM_PORTS          0xe  /* 32-bit unsigned int */
+#define  RHBA_FABRIC_WWNN        0xf  /* 8 byte WWNN */
+#define  RHBA_BIOS_VERSION       0x10 /* 4 to 256 byte ASCII string */
+#define  RHBA_BIOS_STATE         0x11 /* 32-bit unsigned int */
+#define  RHBA_VENDOR_ID          0xe0 /* 8 byte ASCII string */
+
+/* Bit mask for all individual HBA attributes */
+#define LPFC_FDMI_HBA_ATTR_wwnn			0x00000001
+#define LPFC_FDMI_HBA_ATTR_manufacturer		0x00000002
+#define LPFC_FDMI_HBA_ATTR_sn			0x00000004
+#define LPFC_FDMI_HBA_ATTR_model		0x00000008
+#define LPFC_FDMI_HBA_ATTR_description		0x00000010
+#define LPFC_FDMI_HBA_ATTR_hdw_ver		0x00000020
+#define LPFC_FDMI_HBA_ATTR_drvr_ver		0x00000040
+#define LPFC_FDMI_HBA_ATTR_rom_ver		0x00000080
+#define LPFC_FDMI_HBA_ATTR_fmw_ver		0x00000100
+#define LPFC_FDMI_HBA_ATTR_os_ver		0x00000200
+#define LPFC_FDMI_HBA_ATTR_ct_len		0x00000400
+#define LPFC_FDMI_HBA_ATTR_symbolic_name	0x00000800
+#define LPFC_FDMI_HBA_ATTR_vendor_info		0x00001000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_num_ports		0x00002000
+#define LPFC_FDMI_HBA_ATTR_fabric_wwnn		0x00004000
+#define LPFC_FDMI_HBA_ATTR_bios_ver		0x00008000
+#define LPFC_FDMI_HBA_ATTR_bios_state		0x00010000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_vendor_id		0x00020000
+
+/* Bit mask for FDMI-1 defined HBA attributes */
+#define LPFC_FDMI1_HBA_ATTR			0x000007ff
+
+/* Bit mask for FDMI-2 defined HBA attributes */
+/* Skip vendor_info and bios_state */
+#define LPFC_FDMI2_HBA_ATTR			0x0002efff
 
 /*
  * Port Attrubute Types
@@ -1353,15 +1386,65 @@
 #define  RPRT_OS_DEVICE_NAME          0x5 /* 4 to 256 byte ASCII string */
 #define  RPRT_HOST_NAME               0x6 /* 4 to 256 byte ASCII string */
 #define  RPRT_NODENAME                0x7 /* 8 byte WWNN */
-#define  RPRT_PORTNAME                0x8 /* 8 byte WWNN */
+#define  RPRT_PORTNAME                0x8 /* 8 byte WWPN */
 #define  RPRT_SYM_PORTNAME            0x9 /* 4 to 256 byte ASCII string */
 #define  RPRT_PORT_TYPE               0xa /* 32-bit unsigned int */
 #define  RPRT_SUPPORTED_CLASS         0xb /* 32-bit unsigned int */
-#define  RPRT_FABRICNAME              0xc /* 8 byte Fabric WWNN */
+#define  RPRT_FABRICNAME              0xc /* 8 byte Fabric WWPN */
 #define  RPRT_ACTIVE_FC4_TYPES        0xd /* 32 byte binary array */
 #define  RPRT_PORT_STATE              0x101 /* 32-bit unsigned int */
 #define  RPRT_DISC_PORT               0x102 /* 32-bit unsigned int */
 #define  RPRT_PORT_ID                 0x103 /* 32-bit unsigned int */
+#define  RPRT_SMART_SERVICE           0xf100 /* 4 to 256 byte ASCII string */
+#define  RPRT_SMART_GUID              0xf101 /* 8 byte WWNN + 8 byte WWPN */
+#define  RPRT_SMART_VERSION           0xf102 /* 4 to 256 byte ASCII string */
+#define  RPRT_SMART_MODEL             0xf103 /* 4 to 256 byte ASCII string */
+#define  RPRT_SMART_PORT_INFO         0xf104 /* 32-bit unsigned int */
+#define  RPRT_SMART_QOS               0xf105 /* 32-bit unsigned int */
+#define  RPRT_SMART_SECURITY          0xf106 /* 32-bit unsigned int */
+
+/* Bit mask for all individual PORT attributes */
+#define LPFC_FDMI_PORT_ATTR_fc4type		0x00000001
+#define LPFC_FDMI_PORT_ATTR_support_speed	0x00000002
+#define LPFC_FDMI_PORT_ATTR_speed		0x00000004
+#define LPFC_FDMI_PORT_ATTR_max_frame		0x00000008
+#define LPFC_FDMI_PORT_ATTR_os_devname		0x00000010
+#define LPFC_FDMI_PORT_ATTR_host_name		0x00000020
+#define LPFC_FDMI_PORT_ATTR_wwnn		0x00000040
+#define LPFC_FDMI_PORT_ATTR_wwpn		0x00000080
+#define LPFC_FDMI_PORT_ATTR_symbolic_name	0x00000100
+#define LPFC_FDMI_PORT_ATTR_port_type		0x00000200
+#define LPFC_FDMI_PORT_ATTR_class		0x00000400
+#define LPFC_FDMI_PORT_ATTR_fabric_wwpn		0x00000800
+#define LPFC_FDMI_PORT_ATTR_port_state		0x00001000
+#define LPFC_FDMI_PORT_ATTR_active_fc4type	0x00002000
+#define LPFC_FDMI_PORT_ATTR_num_disc		0x00004000
+#define LPFC_FDMI_PORT_ATTR_nportid		0x00008000
+#define LPFC_FDMI_SMART_ATTR_service		0x00010000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_guid		0x00020000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_version		0x00040000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_model		0x00080000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_port_info		0x00100000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_qos		0x00200000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_security		0x00400000 /* Vendor specific */
+
+/* Bit mask for FDMI-1 defined PORT attributes */
+#define LPFC_FDMI1_PORT_ATTR			0x0000003f
+
+/* Bit mask for FDMI-2 defined PORT attributes */
+#define LPFC_FDMI2_PORT_ATTR			0x0000ffff
+
+/* Bit mask for Smart SAN defined PORT attributes */
+#define LPFC_FDMI2_SMART_ATTR			0x007fffff
+
+/* Defines for PORT port state attribute */
+#define LPFC_FDMI_PORTSTATE_UNKNOWN	1
+#define LPFC_FDMI_PORTSTATE_ONLINE	2
+
+/* Defines for PORT port type attribute */
+#define LPFC_FDMI_PORTTYPE_UNKNOWN	0
+#define LPFC_FDMI_PORTTYPE_NPORT	1
+#define LPFC_FDMI_PORTTYPE_NLPORT	2
 
 /*
  *  Begin HBA configuration parameters.
@@ -2498,10 +2581,38 @@
 /* Structure for MB Command READ_LINK_STAT (18) */
 
 typedef struct {
-	uint32_t rsvd1;
+	uint32_t word0;
+
+#define lpfc_read_link_stat_rec_SHIFT   0
+#define lpfc_read_link_stat_rec_MASK   0x1
+#define lpfc_read_link_stat_rec_WORD   word0
+
+#define lpfc_read_link_stat_gec_SHIFT	1
+#define lpfc_read_link_stat_gec_MASK   0x1
+#define lpfc_read_link_stat_gec_WORD   word0
+
+#define lpfc_read_link_stat_w02oftow23of_SHIFT	2
+#define lpfc_read_link_stat_w02oftow23of_MASK   0x3FFFFF
+#define lpfc_read_link_stat_w02oftow23of_WORD   word0
+
+#define lpfc_read_link_stat_rsvd_SHIFT	24
+#define lpfc_read_link_stat_rsvd_MASK   0x1F
+#define lpfc_read_link_stat_rsvd_WORD   word0
+
+#define lpfc_read_link_stat_gec2_SHIFT  29
+#define lpfc_read_link_stat_gec2_MASK   0x1
+#define lpfc_read_link_stat_gec2_WORD   word0
+
+#define lpfc_read_link_stat_clrc_SHIFT  30
+#define lpfc_read_link_stat_clrc_MASK   0x1
+#define lpfc_read_link_stat_clrc_WORD   word0
+
+#define lpfc_read_link_stat_clof_SHIFT  31
+#define lpfc_read_link_stat_clof_MASK   0x1
+#define lpfc_read_link_stat_clof_WORD   word0
+
 	uint32_t linkFailureCnt;
 	uint32_t lossSyncCnt;
-
 	uint32_t lossSignalCnt;
 	uint32_t primSeqErrCnt;
 	uint32_t invalidXmitWord;
@@ -2509,6 +2620,19 @@
 	uint32_t primSeqTimeout;
 	uint32_t elasticOverrun;
 	uint32_t arbTimeout;
+	uint32_t advRecBufCredit;
+	uint32_t curRecBufCredit;
+	uint32_t advTransBufCredit;
+	uint32_t curTransBufCredit;
+	uint32_t recEofCount;
+	uint32_t recEofdtiCount;
+	uint32_t recEofniCount;
+	uint32_t recSofcount;
+	uint32_t rsvd1;
+	uint32_t rsvd2;
+	uint32_t recDrpXriCount;
+	uint32_t fecCorrBlkCount;
+	uint32_t fecUncorrBlkCount;
 } READ_LNK_VAR;
 
 /* Structure for MB Command REG_LOGIN (19) */
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_hw4.h
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1182,6 +1182,7 @@
 #define lpfc_mbx_wq_create_page_size_SHIFT	0
 #define lpfc_mbx_wq_create_page_size_MASK	0x000000FF
 #define lpfc_mbx_wq_create_page_size_WORD	word1
+#define LPFC_WQ_PAGE_SIZE_4096	0x1
 #define lpfc_mbx_wq_create_wqe_size_SHIFT	8
 #define lpfc_mbx_wq_create_wqe_size_MASK	0x0000000F
 #define lpfc_mbx_wq_create_wqe_size_WORD	word1
@@ -1253,6 +1254,7 @@
 #define lpfc_rq_context_page_size_SHIFT	0		/* Version 1 Only */
 #define lpfc_rq_context_page_size_MASK	0x000000FF
 #define lpfc_rq_context_page_size_WORD	word0
+#define	LPFC_RQ_PAGE_SIZE_4096	0x1
 	uint32_t reserved1;
 	uint32_t word2;
 #define lpfc_rq_context_cq_id_SHIFT	16
@@ -3178,7 +3180,7 @@
 #define MB_CEQ_STATUS_QUEUE_FLUSHING		0x4
 #define MB_CQE_STATUS_DMA_FAILED		0x5
 
-#define LPFC_MBX_WR_CONFIG_MAX_BDE		8
+#define LPFC_MBX_WR_CONFIG_MAX_BDE		1
 struct lpfc_mbx_wr_object {
 	struct mbox_header header;
 	union {
@@ -3317,6 +3319,7 @@
 #define LPFC_ASYNC_LINK_SPEED_20GBPS		0x5
 #define LPFC_ASYNC_LINK_SPEED_25GBPS		0x6
 #define LPFC_ASYNC_LINK_SPEED_40GBPS		0x7
+#define LPFC_ASYNC_LINK_SPEED_100GBPS		0x8
 #define lpfc_acqe_link_duplex_SHIFT		16
 #define lpfc_acqe_link_duplex_MASK		0x000000FF
 #define lpfc_acqe_link_duplex_WORD		word0
@@ -3447,23 +3450,50 @@
 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
+#define lpfc_sli_misconfigured_port0_state_SHIFT	0
+#define lpfc_sli_misconfigured_port0_state_MASK		0x000000FF
+#define lpfc_sli_misconfigured_port0_state_WORD		word0
+#define lpfc_sli_misconfigured_port1_state_SHIFT	8
+#define lpfc_sli_misconfigured_port1_state_MASK		0x000000FF
+#define lpfc_sli_misconfigured_port1_state_WORD		word0
+#define lpfc_sli_misconfigured_port2_state_SHIFT	16
+#define lpfc_sli_misconfigured_port2_state_MASK		0x000000FF
+#define lpfc_sli_misconfigured_port2_state_WORD		word0
+#define lpfc_sli_misconfigured_port3_state_SHIFT	24
+#define lpfc_sli_misconfigured_port3_state_MASK		0x000000FF
+#define lpfc_sli_misconfigured_port3_state_WORD		word0
+	uint32_t word1;
+#define lpfc_sli_misconfigured_port0_op_SHIFT		0
+#define lpfc_sli_misconfigured_port0_op_MASK		0x00000001
+#define lpfc_sli_misconfigured_port0_op_WORD		word1
+#define lpfc_sli_misconfigured_port0_severity_SHIFT	1
+#define lpfc_sli_misconfigured_port0_severity_MASK	0x00000003
+#define lpfc_sli_misconfigured_port0_severity_WORD	word1
+#define lpfc_sli_misconfigured_port1_op_SHIFT		8
+#define lpfc_sli_misconfigured_port1_op_MASK		0x00000001
+#define lpfc_sli_misconfigured_port1_op_WORD		word1
+#define lpfc_sli_misconfigured_port1_severity_SHIFT	9
+#define lpfc_sli_misconfigured_port1_severity_MASK	0x00000003
+#define lpfc_sli_misconfigured_port1_severity_WORD	word1
+#define lpfc_sli_misconfigured_port2_op_SHIFT		16
+#define lpfc_sli_misconfigured_port2_op_MASK		0x00000001
+#define lpfc_sli_misconfigured_port2_op_WORD		word1
+#define lpfc_sli_misconfigured_port2_severity_SHIFT	17
+#define lpfc_sli_misconfigured_port2_severity_MASK	0x00000003
+#define lpfc_sli_misconfigured_port2_severity_WORD	word1
+#define lpfc_sli_misconfigured_port3_op_SHIFT		24
+#define lpfc_sli_misconfigured_port3_op_MASK		0x00000001
+#define lpfc_sli_misconfigured_port3_op_WORD		word1
+#define lpfc_sli_misconfigured_port3_severity_SHIFT	25
+#define lpfc_sli_misconfigured_port3_severity_MASK	0x00000003
+#define lpfc_sli_misconfigured_port3_severity_WORD	word1
 	} 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
+#define LPFC_SLI_EVENT_STATUS_UNQUALIFIED	0x04
+#define LPFC_SLI_EVENT_STATUS_UNCERTIFIED	0x05
 };
 
 struct lpfc_acqe_sli {
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_init.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_init.c
@@ -1184,8 +1184,10 @@
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			lpfc_rcv_seq_check_edtov(vports[i]);
+			lpfc_fdmi_num_disc_check(vports[i]);
+		}
 	lpfc_destroy_vport_work_array(phba, vports);
 
 	if ((phba->link_state == LPFC_HBA_ERROR) ||
@@ -1290,6 +1292,10 @@
 				jiffies +
 				msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT));
 		}
+	} else {
+			mod_timer(&phba->hb_tmofunc,
+				jiffies +
+				msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
 	}
 }
 
@@ -2621,7 +2627,6 @@
 lpfc_stop_vport_timers(struct lpfc_vport *vport)
 {
 	del_timer_sync(&vport->els_tmofunc);
-	del_timer_sync(&vport->fc_fdmitmo);
 	del_timer_sync(&vport->delayed_disc_tmo);
 	lpfc_can_disctmo(vport);
 	return;
@@ -2855,7 +2860,7 @@
 	}
 
 	vports = lpfc_create_vport_work_array(phba);
-	if (vports != NULL)
+	if (vports != NULL) {
 		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			struct Scsi_Host *shost;
 			shost = lpfc_shost_from_vport(vports[i]);
@@ -2872,7 +2877,8 @@
 			}
 			spin_unlock_irq(shost->host_lock);
 		}
-		lpfc_destroy_vport_work_array(phba, vports);
+	}
+	lpfc_destroy_vport_work_array(phba, vports);
 
 	lpfc_unblock_mgmt_io(phba);
 	return 0;
@@ -3340,10 +3346,6 @@
 	vport->fc_disctmo.function = lpfc_disc_timeout;
 	vport->fc_disctmo.data = (unsigned long)vport;
 
-	init_timer(&vport->fc_fdmitmo);
-	vport->fc_fdmitmo.function = lpfc_fdmi_tmo;
-	vport->fc_fdmitmo.data = (unsigned long)vport;
-
 	init_timer(&vport->els_tmofunc);
 	vport->els_tmofunc.function = lpfc_els_timeout;
 	vport->els_tmofunc.data = (unsigned long)vport;
@@ -3709,49 +3711,6 @@
 }
 
 /**
- * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed
- * @phba: pointer to lpfc hba data structure.
- * @acqe_link: pointer to the async link completion queue entry.
- *
- * This routine is to parse the SLI4 link-attention link speed and translate
- * it into the base driver's link-attention link speed coding.
- *
- * Return: Link-attention link speed in terms of base driver's coding.
- **/
-static uint8_t
-lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba,
-				struct lpfc_acqe_link *acqe_link)
-{
-	uint8_t link_speed;
-
-	switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
-	case LPFC_ASYNC_LINK_SPEED_ZERO:
-	case LPFC_ASYNC_LINK_SPEED_10MBPS:
-	case LPFC_ASYNC_LINK_SPEED_100MBPS:
-		link_speed = LPFC_LINK_SPEED_UNKNOWN;
-		break;
-	case LPFC_ASYNC_LINK_SPEED_1GBPS:
-		link_speed = LPFC_LINK_SPEED_1GHZ;
-		break;
-	case LPFC_ASYNC_LINK_SPEED_10GBPS:
-		link_speed = LPFC_LINK_SPEED_10GHZ;
-		break;
-	case LPFC_ASYNC_LINK_SPEED_20GBPS:
-	case LPFC_ASYNC_LINK_SPEED_25GBPS:
-	case LPFC_ASYNC_LINK_SPEED_40GBPS:
-		link_speed = LPFC_LINK_SPEED_UNKNOWN;
-		break;
-	default:
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"0483 Invalid link-attention link speed: x%x\n",
-				bf_get(lpfc_acqe_link_speed, acqe_link));
-		link_speed = LPFC_LINK_SPEED_UNKNOWN;
-		break;
-	}
-	return link_speed;
-}
-
-/**
  * lpfc_sli_port_speed_get - Get sli3 link speed code to link speed
  * @phba: pointer to lpfc hba data structure.
  *
@@ -3767,27 +3726,35 @@
 	if (!lpfc_is_link_up(phba))
 		return 0;
 
-	switch (phba->fc_linkspeed) {
-	case LPFC_LINK_SPEED_1GHZ:
-		link_speed = 1000;
-		break;
-	case LPFC_LINK_SPEED_2GHZ:
-		link_speed = 2000;
-		break;
-	case LPFC_LINK_SPEED_4GHZ:
-		link_speed = 4000;
-		break;
-	case LPFC_LINK_SPEED_8GHZ:
-		link_speed = 8000;
-		break;
-	case LPFC_LINK_SPEED_10GHZ:
-		link_speed = 10000;
-		break;
-	case LPFC_LINK_SPEED_16GHZ:
-		link_speed = 16000;
-		break;
-	default:
-		link_speed = 0;
+	if (phba->sli_rev <= LPFC_SLI_REV3) {
+		switch (phba->fc_linkspeed) {
+		case LPFC_LINK_SPEED_1GHZ:
+			link_speed = 1000;
+			break;
+		case LPFC_LINK_SPEED_2GHZ:
+			link_speed = 2000;
+			break;
+		case LPFC_LINK_SPEED_4GHZ:
+			link_speed = 4000;
+			break;
+		case LPFC_LINK_SPEED_8GHZ:
+			link_speed = 8000;
+			break;
+		case LPFC_LINK_SPEED_10GHZ:
+			link_speed = 10000;
+			break;
+		case LPFC_LINK_SPEED_16GHZ:
+			link_speed = 16000;
+			break;
+		default:
+			link_speed = 0;
+		}
+	} else {
+		if (phba->sli4_hba.link_state.logical_speed)
+			link_speed =
+			      phba->sli4_hba.link_state.logical_speed;
+		else
+			link_speed = phba->sli4_hba.link_state.speed;
 	}
 	return link_speed;
 }
@@ -3983,7 +3950,7 @@
 	la->eventTag = acqe_link->event_tag;
 	bf_set(lpfc_mbx_read_top_att_type, la, att_type);
 	bf_set(lpfc_mbx_read_top_link_spd, la,
-	       lpfc_sli4_parse_latt_link_speed(phba, acqe_link));
+	       (bf_get(lpfc_acqe_link_speed, acqe_link)));
 
 	/* Fake the the following irrelvant fields */
 	bf_set(lpfc_mbx_read_top_topology, la, LPFC_TOPOLOGY_PT_PT);
@@ -4113,22 +4080,18 @@
 	char message[128];
 	uint8_t status;
 	uint8_t evt_type;
+	uint8_t operational = 0;
 	struct temp_event temp_event_data;
 	struct lpfc_acqe_misconfigured_event *misconfigured;
 	struct Scsi_Host  *shost;
 
 	evt_type = bf_get(lpfc_trailer_type, acqe_sli);
 
-	/* Special case Lancer */
-	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
-		 LPFC_SLI_INTF_IF_TYPE_2) {
-		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,
-				evt_type);
-		return;
-	}
+	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,
+			evt_type);
 
 	port_name = phba->Port[0];
 	if (port_name == 0x00)
@@ -4174,29 +4137,46 @@
 		/* 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,
+			status = bf_get(lpfc_sli_misconfigured_port0_state,
+					&misconfigured->theEvent);
+			operational = bf_get(lpfc_sli_misconfigured_port0_op,
 					&misconfigured->theEvent);
 			break;
 		case LPFC_LINK_NUMBER_1:
-			status = bf_get(lpfc_sli_misconfigured_port1,
+			status = bf_get(lpfc_sli_misconfigured_port1_state,
+					&misconfigured->theEvent);
+			operational = bf_get(lpfc_sli_misconfigured_port1_op,
 					&misconfigured->theEvent);
 			break;
 		case LPFC_LINK_NUMBER_2:
-			status = bf_get(lpfc_sli_misconfigured_port2,
+			status = bf_get(lpfc_sli_misconfigured_port2_state,
+					&misconfigured->theEvent);
+			operational = bf_get(lpfc_sli_misconfigured_port2_op,
 					&misconfigured->theEvent);
 			break;
 		case LPFC_LINK_NUMBER_3:
-			status = bf_get(lpfc_sli_misconfigured_port3,
+			status = bf_get(lpfc_sli_misconfigured_port3_state,
+					&misconfigured->theEvent);
+			operational = bf_get(lpfc_sli_misconfigured_port3_op,
 					&misconfigured->theEvent);
 			break;
 		default:
-			status = ~LPFC_SLI_EVENT_STATUS_VALID;
-			break;
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"3296 "
+					"LPFC_SLI_EVENT_TYPE_MISCONFIGURED "
+					"event: Invalid link %d",
+					phba->sli4_hba.lnk_info.lnk_no);
+			return;
 		}
 
+		/* Skip if optic state unchanged */
+		if (phba->sli4_hba.lnk_info.optic_state == status)
+			return;
+
 		switch (status) {
 		case LPFC_SLI_EVENT_STATUS_VALID:
-			return; /* no message if the sfp is okay */
+			sprintf(message, "Physical Link is functional");
+			break;
 		case LPFC_SLI_EVENT_STATUS_NOT_PRESENT:
 			sprintf(message, "Optics faulted/incorrectly "
 				"installed/not installed - Reseat optics, "
@@ -4211,15 +4191,26 @@
 			sprintf(message, "Incompatible optics - Replace with "
 				"compatible optics for card to function.");
 			break;
+		case LPFC_SLI_EVENT_STATUS_UNQUALIFIED:
+			sprintf(message, "Unqualified optics - Replace with "
+				"Avago optics for Warranty and Technical "
+				"Support - Link is%s operational",
+				(operational) ? "" : " not");
+			break;
+		case LPFC_SLI_EVENT_STATUS_UNCERTIFIED:
+			sprintf(message, "Uncertified optics - Replace with "
+				"Avago-certified optics to enable link "
+				"operation - Link is%s operational",
+				(operational) ? "" : " not");
+			break;
 		default:
 			/* firmware is reporting a status we don't know about */
 			sprintf(message, "Unknown event status x%02x", status);
 			break;
 		}
-
+		phba->sli4_hba.lnk_info.optic_state = status;
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-				"3176 Misconfigured Physical Port - "
-				"Port Name %c %s\n", port_name, message);
+				"3176 Port Name %c %s\n", port_name, message);
 		break;
 	case LPFC_SLI_EVENT_TYPE_REMOTE_DPORT:
 		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -4375,7 +4366,7 @@
 			break;
 		}
 		/* If fast FCF failover rescan event is pending, do nothing */
-		if (phba->fcf.fcf_flag & FCF_REDISC_EVT) {
+		if (phba->fcf.fcf_flag & (FCF_REDISC_EVT | FCF_REDISC_PEND)) {
 			spin_unlock_irq(&phba->hbalock);
 			break;
 		}
@@ -5293,6 +5284,9 @@
 	INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list);
 	INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list);
 
+	/* initialize optic_state to 0xFF */
+	phba->sli4_hba.lnk_info.optic_state = 0xff;
+
 	/* Initialize the driver internal SLI layer lists. */
 	lpfc_sli_setup(phba);
 	lpfc_sli_queue_setup(phba);
@@ -6159,6 +6153,20 @@
 	/* Put reference to SCSI host to driver's device private data */
 	pci_set_drvdata(phba->pcidev, shost);
 
+	/*
+	 * At this point we are fully registered with PSA. In addition,
+	 * any initial discovery should be completed.
+	 */
+	vport->load_flag |= FC_ALLOW_FDMI;
+	if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+
+		/* Setup appropriate attribute masks */
+		vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+		if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+			vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+		else
+			vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+	}
 	return 0;
 }
 
@@ -6889,6 +6897,9 @@
 			bf_get(lpfc_mbx_rd_conf_xri_base, rd_config);
 		phba->sli4_hba.max_cfg_param.max_vpi =
 			bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config);
+		/* Limit the max we support */
+		if (phba->sli4_hba.max_cfg_param.max_vpi > LPFC_MAX_VPORTS)
+			phba->sli4_hba.max_cfg_param.max_vpi = LPFC_MAX_VPORTS;
 		phba->sli4_hba.max_cfg_param.vpi_base =
 			bf_get(lpfc_mbx_rd_conf_vpi_base, rd_config);
 		phba->sli4_hba.max_cfg_param.max_rpi =
@@ -8833,9 +8844,12 @@
 				 * already mapped to this phys_id.
 				 */
 				if (cpup->irq != LPFC_VECTOR_MAP_EMPTY) {
-					chann[saved_chann] =
-						cpup->channel_id;
-					saved_chann++;
+					if (saved_chann <=
+					    LPFC_FCP_IO_CHAN_MAX) {
+						chann[saved_chann] =
+							cpup->channel_id;
+						saved_chann++;
+					}
 					goto out;
 				}
 
@@ -11383,6 +11397,7 @@
 	.id_table	= lpfc_id_table,
 	.probe		= lpfc_pci_probe_one,
 	.remove		= lpfc_pci_remove_one,
+	.shutdown	= lpfc_pci_remove_one,
 	.suspend        = lpfc_pci_suspend_one,
 	.resume		= lpfc_pci_resume_one,
 	.err_handler    = &lpfc_err_handler,
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_mbox.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_mbox.c
@@ -2145,10 +2145,12 @@
 	reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
 	reg_vfi->e_d_tov = phba->fc_edtov;
 	reg_vfi->r_a_tov = phba->fc_ratov;
-	reg_vfi->bde.addrHigh = putPaddrHigh(phys);
-	reg_vfi->bde.addrLow = putPaddrLow(phys);
-	reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
-	reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+	if (phys) {
+		reg_vfi->bde.addrHigh = putPaddrHigh(phys);
+		reg_vfi->bde.addrLow = putPaddrLow(phys);
+		reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
+		reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+	}
 	bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID);
 
 	/* Only FC supports upd bit */
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_mem.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_mem.c
@@ -231,15 +231,13 @@
 	if (phba->lpfc_hbq_pool)
 		pci_pool_destroy(phba->lpfc_hbq_pool);
 	phba->lpfc_hbq_pool = NULL;
-
-	if (phba->rrq_pool)
-		mempool_destroy(phba->rrq_pool);
+	mempool_destroy(phba->rrq_pool);
 	phba->rrq_pool = NULL;
 
 	/* Free NLP memory pool */
 	mempool_destroy(phba->nlp_mem_pool);
 	phba->nlp_mem_pool = NULL;
-	if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) {
+	if (phba->sli_rev == LPFC_SLI_REV4) {
 		mempool_destroy(phba->active_rrq_pool);
 		phba->active_rrq_pool = NULL;
 	}
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -280,38 +280,12 @@
 	uint32_t *lp;
 	IOCB_t *icmd;
 	struct serv_parm *sp;
+	uint32_t ed_tov;
 	LPFC_MBOXQ_t *mbox;
 	struct ls_rjt stat;
 	int rc;
 
 	memset(&stat, 0, sizeof (struct ls_rjt));
-	if (vport->port_state <= LPFC_FDISC) {
-		/* Before responding to PLOGI, check for pt2pt mode.
-		 * If we are pt2pt, with an outstanding FLOGI, abort
-		 * the FLOGI and resend it first.
-		 */
-		if (vport->fc_flag & FC_PT2PT) {
-			 lpfc_els_abort_flogi(phba);
-		        if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-				/* If the other side is supposed to initiate
-				 * the PLOGI anyway, just ACC it now and
-				 * move on with discovery.
-				 */
-				phba->fc_edtov = FF_DEF_EDTOV;
-				phba->fc_ratov = FF_DEF_RATOV;
-				/* Start discovery - this should just do
-				   CLEAR_LA */
-				lpfc_disc_start(vport);
-			} else
-				lpfc_initial_flogi(vport);
-		} else {
-			stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
-			stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
-			lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
-					    ndlp, NULL);
-			return 0;
-		}
-	}
 	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
 	lp = (uint32_t *) pcmd->virt;
 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
@@ -404,30 +378,46 @@
 	/* Check for Nport to NPort pt2pt protocol */
 	if ((vport->fc_flag & FC_PT2PT) &&
 	    !(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
 		/* rcv'ed PLOGI decides what our NPortId will be */
 		vport->fc_myDID = icmd->un.rcvels.parmRo;
-		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-		if (mbox == NULL)
-			goto out;
-		lpfc_config_link(phba, mbox);
-		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		mbox->vport = vport;
-		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-		if (rc == MBX_NOT_FINISHED) {
-			mempool_free(mbox, phba->mbox_mem_pool);
-			goto out;
+
+		ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+		if (sp->cmn.edtovResolution) {
+			/* E_D_TOV ticks are in nanoseconds */
+			ed_tov = (phba->fc_edtov + 999999) / 1000000;
 		}
+
 		/*
-		 * For SLI4, the VFI/VPI are registered AFTER the
-		 * Nport with the higher WWPN sends us a PLOGI with
-		 * our assigned NPortId.
+		 * For pt-to-pt, use the larger EDTOV
+		 * RATOV = 2 * EDTOV
 		 */
+		if (ed_tov > phba->fc_edtov)
+			phba->fc_edtov = ed_tov;
+		phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+		memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+		/* Issue config_link / reg_vfi to account for updated TOV's */
+
 		if (phba->sli_rev == LPFC_SLI_REV4)
 			lpfc_issue_reg_vfi(vport);
+		else {
+			mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+			if (mbox == NULL)
+				goto out;
+			lpfc_config_link(phba, mbox);
+			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+			mbox->vport = vport;
+			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+			if (rc == MBX_NOT_FINISHED) {
+				mempool_free(mbox, phba->mbox_mem_pool);
+				goto out;
+			}
+		}
 
 		lpfc_can_disctmo(vport);
 	}
+
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mbox)
 		goto out;
@@ -464,8 +454,10 @@
 	 * single discovery thread, this will cause a huge delay in
 	 * discovery. Also this will cause multiple state machines
 	 * running in parallel for this node.
+	 * This only applies to a fabric environment.
 	 */
-	if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
+	if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) &&
+	    (vport->fc_flag & FC_FABRIC)) {
 		/* software abort outstanding PLOGI */
 		lpfc_els_abort(phba, ndlp);
 	}
@@ -769,9 +761,9 @@
 
 	if (!(vport->fc_flag & FC_PT2PT)) {
 		/* Check config parameter use-adisc or FCP-2 */
-		if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
+		if (vport->cfg_use_adisc && ((vport->fc_flag & FC_RSCN_MODE) ||
 		    ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
-		     (ndlp->nlp_type & NLP_FCP_TARGET))) {
+		     (ndlp->nlp_type & NLP_FCP_TARGET)))) {
 			spin_lock_irq(shost->host_lock);
 			ndlp->nlp_flag |= NLP_NPR_ADISC;
 			spin_unlock_irq(shost->host_lock);
@@ -1038,7 +1030,9 @@
 	uint32_t *lp;
 	IOCB_t *irsp;
 	struct serv_parm *sp;
+	uint32_t ed_tov;
 	LPFC_MBOXQ_t *mbox;
+	int rc;
 
 	cmdiocb = (struct lpfc_iocbq *) arg;
 	rspiocb = cmdiocb->context_un.rsp_iocb;
@@ -1094,18 +1088,63 @@
 	ndlp->nlp_maxframe =
 		((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
 
+	if ((vport->fc_flag & FC_PT2PT) &&
+	    (vport->fc_flag & FC_PT2PT_PLOGI)) {
+		ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+		if (sp->cmn.edtovResolution) {
+			/* E_D_TOV ticks are in nanoseconds */
+			ed_tov = (phba->fc_edtov + 999999) / 1000000;
+		}
+
+		/*
+		 * Use the larger EDTOV
+		 * RATOV = 2 * EDTOV for pt-to-pt
+		 */
+		if (ed_tov > phba->fc_edtov)
+			phba->fc_edtov = ed_tov;
+		phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+		memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+		/* Issue config_link / reg_vfi to account for updated TOV's */
+		if (phba->sli_rev == LPFC_SLI_REV4) {
+			lpfc_issue_reg_vfi(vport);
+		} else {
+			mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+			if (!mbox) {
+				lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+						 "0133 PLOGI: no memory "
+						 "for config_link "
+						 "Data: x%x x%x x%x x%x\n",
+						 ndlp->nlp_DID, ndlp->nlp_state,
+						 ndlp->nlp_flag, ndlp->nlp_rpi);
+				goto out;
+			}
+
+			lpfc_config_link(phba, mbox);
+
+			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+			mbox->vport = vport;
+			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+			if (rc == MBX_NOT_FINISHED) {
+				mempool_free(mbox, phba->mbox_mem_pool);
+				goto out;
+			}
+		}
+	}
+
+	lpfc_unreg_rpi(vport, ndlp);
+
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mbox) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-			"0133 PLOGI: no memory for reg_login "
-			"Data: x%x x%x x%x x%x\n",
-			ndlp->nlp_DID, ndlp->nlp_state,
-			ndlp->nlp_flag, ndlp->nlp_rpi);
+				 "0018 PLOGI: no memory for reg_login "
+				 "Data: x%x x%x x%x x%x\n",
+				 ndlp->nlp_DID, ndlp->nlp_state,
+				 ndlp->nlp_flag, ndlp->nlp_rpi);
 		goto out;
 	}
 
-	lpfc_unreg_rpi(vport, ndlp);
-
 	if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
 			 (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
 		switch (ndlp->nlp_DID) {
@@ -2299,6 +2338,9 @@
 		if (vport->phba->sli_rev < LPFC_SLI_REV4)
 			ndlp->nlp_rpi = mb->un.varWords[0];
 		ndlp->nlp_flag |= NLP_RPI_REGISTERED;
+		if (ndlp->nlp_flag & NLP_LOGO_ACC) {
+			lpfc_unreg_rpi(vport, ndlp);
+		}
 	} else {
 		if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
 			lpfc_drop_node(vport, ndlp);
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_scsi.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_scsi.c
@@ -2707,6 +2707,7 @@
 	int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction;
 	int prot_group_type = 0;
 	int fcpdl;
+	struct lpfc_vport *vport = phba->pport;
 
 	/*
 	 * Start the lpfc command prep by bumping the bpl beyond fcp_cmnd
@@ -2812,6 +2813,14 @@
 	 */
 	iocb_cmd->un.fcpi.fcpi_parm = fcpdl;
 
+	/*
+	 * For First burst, we may need to adjust the initial transfer
+	 * length for DIF
+	 */
+	if (iocb_cmd->un.fcpi.fcpi_XRdy &&
+	    (fcpdl < vport->cfg_first_burst_size))
+		iocb_cmd->un.fcpi.fcpi_XRdy = fcpdl;
+
 	return 0;
 err:
 	if (lpfc_cmd->seg_cnt)
@@ -3361,6 +3370,7 @@
 	int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction;
 	int prot_group_type = 0;
 	int fcpdl;
+	struct lpfc_vport *vport = phba->pport;
 
 	/*
 	 * Start the lpfc command prep by bumping the sgl beyond fcp_cmnd
@@ -3477,6 +3487,14 @@
 	iocb_cmd->un.fcpi.fcpi_parm = fcpdl;
 
 	/*
+	 * For First burst, we may need to adjust the initial transfer
+	 * length for DIF
+	 */
+	if (iocb_cmd->un.fcpi.fcpi_XRdy &&
+	    (fcpdl < vport->cfg_first_burst_size))
+		iocb_cmd->un.fcpi.fcpi_XRdy = fcpdl;
+
+	/*
 	 * If the OAS driver feature is enabled and the lun is enabled for
 	 * OAS, set the oas iocb related flags.
 	 */
@@ -3676,6 +3694,7 @@
 lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		    struct lpfc_iocbq *rsp_iocb)
 {
+	struct lpfc_hba *phba = vport->phba;
 	struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
 	struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
 	struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
@@ -3685,6 +3704,7 @@
 	uint32_t *lp;
 	uint32_t host_status = DID_OK;
 	uint32_t rsplen = 0;
+	uint32_t fcpDl;
 	uint32_t logit = LOG_FCP | LOG_FCP_ERROR;
 
 
@@ -3755,13 +3775,14 @@
 			 fcprsp->rspInfo3);
 
 	scsi_set_resid(cmnd, 0);
+	fcpDl = be32_to_cpu(fcpcmd->fcpDl);
 	if (resp_info & RESID_UNDER) {
 		scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
 
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
 				 "9025 FCP Read Underrun, expected %d, "
 				 "residual %d Data: x%x x%x x%x\n",
-				 be32_to_cpu(fcpcmd->fcpDl),
+				 fcpDl,
 				 scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
 				 cmnd->underflow);
 
@@ -3777,7 +3798,7 @@
 					 LOG_FCP | LOG_FCP_ERROR,
 					 "9026 FCP Read Check Error "
 					 "and Underrun Data: x%x x%x x%x x%x\n",
-					 be32_to_cpu(fcpcmd->fcpDl),
+					 fcpDl,
 					 scsi_get_resid(cmnd), fcpi_parm,
 					 cmnd->cmnd[0]);
 			scsi_set_resid(cmnd, scsi_bufflen(cmnd));
@@ -3812,13 +3833,25 @@
 	 * Check SLI validation that all the transfer was actually done
 	 * (fcpi_parm should be zero). Apply check only to reads.
 	 */
-	} else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
+	} else if (fcpi_parm) {
 		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
-				 "9029 FCP Read Check Error Data: "
+				 "9029 FCP %s Check Error xri x%x  Data: "
 				 "x%x x%x x%x x%x x%x\n",
-				 be32_to_cpu(fcpcmd->fcpDl),
-				 be32_to_cpu(fcprsp->rspResId),
+				 ((cmnd->sc_data_direction == DMA_FROM_DEVICE) ?
+				 "Read" : "Write"),
+				 ((phba->sli_rev == LPFC_SLI_REV4) ?
+				 lpfc_cmd->cur_iocbq.sli4_xritag :
+				 rsp_iocb->iocb.ulpContext),
+				 fcpDl, be32_to_cpu(fcprsp->rspResId),
 				 fcpi_parm, cmnd->cmnd[0], scsi_status);
+
+		/* There is some issue with the LPe12000 that causes it
+		 * to miscalculate the fcpi_parm and falsely trip this
+		 * recovery logic.  Detect this case and don't error when true.
+		 */
+		if (fcpi_parm > fcpDl)
+			goto out;
+
 		switch (scsi_status) {
 		case SAM_STAT_GOOD:
 		case SAM_STAT_CHECK_CONDITION:
@@ -3859,7 +3892,7 @@
 	uint32_t tag;
 	uint16_t hwq;
 
-	if (shost_use_blk_mq(cmnd->device->host)) {
+	if (cmnd && shost_use_blk_mq(cmnd->device->host)) {
 		tag = blk_mq_unique_tag(cmnd->request);
 		hwq = blk_mq_unique_tag_to_hwq(tag);
 
@@ -3908,9 +3941,9 @@
 	uint32_t logit = LOG_FCP;
 
 	/* Sanity check on return of outstanding command */
-	if (!(lpfc_cmd->pCmd))
-		return;
 	cmd = lpfc_cmd->pCmd;
+	if (!cmd)
+		return;
 	shost = cmd->device->host;
 
 	lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
@@ -4446,15 +4479,7 @@
 				 phba->Port);
 		}
 		len = strlen(lpfcinfobuf);
-		if (phba->sli_rev <= LPFC_SLI_REV3) {
-			link_speed = lpfc_sli_port_speed_get(phba);
-		} else {
-			if (phba->sli4_hba.link_state.logical_speed)
-				link_speed =
-				      phba->sli4_hba.link_state.logical_speed;
-			else
-				link_speed = phba->sli4_hba.link_state.speed;
-		}
+		link_speed = lpfc_sli_port_speed_get(phba);
 		if (link_speed != 0)
 			snprintf(lpfcinfobuf + len, 384-len,
 				 " Logical Link Speed: %d Mbps", link_speed);
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_sli.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_sli.c
@@ -115,9 +115,13 @@
 	/* set consumption flag every once in a while */
 	if (!((q->host_index + 1) % q->entry_repost))
 		bf_set(wqe_wqec, &wqe->generic.wqe_com, 1);
+	else
+		bf_set(wqe_wqec, &wqe->generic.wqe_com, 0);
 	if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED)
 		bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id);
 	lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
+	/* ensure WQE bcopy flushed before doorbell write */
+	wmb();
 
 	/* Update the host index before invoking device */
 	host_index = q->host_index;
@@ -2182,6 +2186,8 @@
 	    !pmb->u.mb.mbxStatus) {
 		rpi = pmb->u.mb.un.varWords[0];
 		vpi = pmb->u.mb.un.varRegLogin.vpi;
+		if (phba->sli_rev == LPFC_SLI_REV4)
+			vpi -= phba->sli4_hba.max_cfg_param.vpi_base;
 		lpfc_unreg_login(phba, vpi, rpi, pmb);
 		pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
@@ -3481,6 +3487,7 @@
 	struct hbq_dmabuf *dmabuf;
 	struct lpfc_cq_event *cq_event;
 	unsigned long iflag;
+	int count = 0;
 
 	spin_lock_irqsave(&phba->hbalock, iflag);
 	phba->hba_flag &= ~HBA_SP_QUEUE_EVT;
@@ -3502,16 +3509,22 @@
 			if (irspiocbq)
 				lpfc_sli_sp_handle_rspiocb(phba, pring,
 							   irspiocbq);
+			count++;
 			break;
 		case CQE_CODE_RECEIVE:
 		case CQE_CODE_RECEIVE_V1:
 			dmabuf = container_of(cq_event, struct hbq_dmabuf,
 					      cq_event);
 			lpfc_sli4_handle_received_buffer(phba, dmabuf);
+			count++;
 			break;
 		default:
 			break;
 		}
+
+		/* Limit the number of events to 64 to avoid soft lockups */
+		if (count == 64)
+			break;
 	}
 }
 
@@ -5887,18 +5900,25 @@
 
  free_vfi_bmask:
 	kfree(phba->sli4_hba.vfi_bmask);
+	phba->sli4_hba.vfi_bmask = NULL;
  free_xri_ids:
 	kfree(phba->sli4_hba.xri_ids);
+	phba->sli4_hba.xri_ids = NULL;
  free_xri_bmask:
 	kfree(phba->sli4_hba.xri_bmask);
+	phba->sli4_hba.xri_bmask = NULL;
  free_vpi_ids:
 	kfree(phba->vpi_ids);
+	phba->vpi_ids = NULL;
  free_vpi_bmask:
 	kfree(phba->vpi_bmask);
+	phba->vpi_bmask = NULL;
  free_rpi_ids:
 	kfree(phba->sli4_hba.rpi_ids);
+	phba->sli4_hba.rpi_ids = NULL;
  free_rpi_bmask:
 	kfree(phba->sli4_hba.rpi_bmask);
+	phba->sli4_hba.rpi_bmask = NULL;
  err_exit:
 	return rc;
 }
@@ -9798,6 +9818,7 @@
 		iabt->ulpCommand = CMD_CLOSE_XRI_CN;
 
 	abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
+	abtsiocbp->vport = vport;
 
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
 			 "0339 Abort xri x%x, original iotag x%x, "
@@ -11740,13 +11761,19 @@
 	phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
 	/* Setting active mailbox pointer need to be in sync to flag clear */
 	phba->sli.mbox_active = NULL;
+	if (bf_get(lpfc_trailer_consumed, mcqe))
+		lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
 	spin_unlock_irqrestore(&phba->hbalock, iflags);
 	/* Wake up worker thread to post the next pending mailbox command */
 	lpfc_worker_wake_up(phba);
+	return workposted;
+
 out_no_mqe_complete:
+	spin_lock_irqsave(&phba->hbalock, iflags);
 	if (bf_get(lpfc_trailer_consumed, mcqe))
 		lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
-	return workposted;
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	return false;
 }
 
 /**
@@ -13475,7 +13502,7 @@
 			       LPFC_WQ_WQE_SIZE_128);
 			bf_set(lpfc_mbx_wq_create_page_size,
 			       &wq_create->u.request_1,
-			       (PAGE_SIZE/SLI4_PAGE_SIZE));
+			       LPFC_WQ_PAGE_SIZE_4096);
 			page = wq_create->u.request_1.page;
 			break;
 		}
@@ -13483,6 +13510,9 @@
 	case LPFC_Q_CREATE_VERSION_1:
 		bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
 		       wq->entry_count);
+		bf_set(lpfc_mbox_hdr_version, &shdr->request,
+		       LPFC_Q_CREATE_VERSION_1);
+
 		switch (wq->entry_size) {
 		default:
 		case 64:
@@ -13501,8 +13531,9 @@
 			       LPFC_WQ_WQE_SIZE_128);
 			break;
 		}
-		bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1,
-		       (PAGE_SIZE/SLI4_PAGE_SIZE));
+		bf_set(lpfc_mbx_wq_create_page_size,
+		       &wq_create->u.request_1,
+		       LPFC_WQ_PAGE_SIZE_4096);
 		page = wq_create->u.request_1.page;
 		break;
 	default:
@@ -13688,7 +13719,7 @@
 		       LPFC_RQE_SIZE_8);
 		bf_set(lpfc_rq_context_page_size,
 		       &rq_create->u.request.context,
-		       (PAGE_SIZE/SLI4_PAGE_SIZE));
+		       LPFC_RQ_PAGE_SIZE_4096);
 	} else {
 		switch (hrq->entry_count) {
 		default:
@@ -14842,10 +14873,12 @@
 	struct lpfc_dmabuf *h_buf;
 	struct hbq_dmabuf *seq_dmabuf = NULL;
 	struct hbq_dmabuf *temp_dmabuf = NULL;
+	uint8_t	found = 0;
 
 	INIT_LIST_HEAD(&dmabuf->dbuf.list);
 	dmabuf->time_stamp = jiffies;
 	new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+
 	/* Use the hdr_buf to find the sequence that this frame belongs to */
 	list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
 		temp_hdr = (struct fc_frame_header *)h_buf->virt;
@@ -14885,7 +14918,8 @@
 		return seq_dmabuf;
 	}
 	/* find the correct place in the sequence to insert this frame */
-	list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
+	d_buf = list_entry(seq_dmabuf->dbuf.list.prev, typeof(*d_buf), list);
+	while (!found) {
 		temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
 		temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
 		/*
@@ -14895,9 +14929,17 @@
 		if (be16_to_cpu(new_hdr->fh_seq_cnt) >
 			be16_to_cpu(temp_hdr->fh_seq_cnt)) {
 			list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
-			return seq_dmabuf;
+			found = 1;
+			break;
 		}
+
+		if (&d_buf->list == &seq_dmabuf->dbuf.list)
+			break;
+		d_buf = list_entry(d_buf->list.prev, typeof(*d_buf), list);
 	}
+
+	if (found)
+		return seq_dmabuf;
 	return NULL;
 }
 
@@ -15403,6 +15445,10 @@
 			list_add_tail(&iocbq->list, &first_iocbq->list);
 		}
 	}
+	/* Free the sequence's header buffer */
+	if (!first_iocbq)
+		lpfc_in_buf_free(vport->phba, &seq_dmabuf->dbuf);
+
 	return first_iocbq;
 }
 
@@ -15752,6 +15798,13 @@
 static void
 __lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
 {
+	/*
+	 * if the rpi value indicates a prior unreg has already
+	 * been done, skip the unreg.
+	 */
+	if (rpi == LPFC_RPI_ALLOC_ERROR)
+		return;
+
 	if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) {
 		phba->sli4_hba.rpi_count--;
 		phba->sli4_hba.max_cfg_param.rpi_used--;
@@ -16173,7 +16226,7 @@
 }
 
 /**
- * lpfc_check_next_fcf_pri
+ * lpfc_check_next_fcf_pri_level
  * phba pointer to the lpfc_hba struct for this port.
  * This routine is called from the lpfc_sli4_fcf_rr_next_index_get
  * routine when the rr_bmask is empty. The FCF indecies are put into the
@@ -16316,21 +16369,18 @@
 			goto initial_priority;
 		lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
 				"2844 No roundrobin failover FCF available\n");
-		if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
-			return LPFC_FCOE_FCF_NEXT_NONE;
-		else {
-			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
-				"3063 Only FCF available idx %d, flag %x\n",
-				next_fcf_index,
-			phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag);
-			return next_fcf_index;
-		}
+
+		return LPFC_FCOE_FCF_NEXT_NONE;
 	}
 
 	if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
 		phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
-		LPFC_FCF_FLOGI_FAILED)
+		LPFC_FCF_FLOGI_FAILED) {
+		if (list_is_singular(&phba->fcf.fcf_pri_list))
+			return LPFC_FCOE_FCF_NEXT_NONE;
+
 		goto next_priority;
+	}
 
 	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
 			"2845 Get next roundrobin failover FCF (x%x)\n",
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_sli4.h
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_sli4.h
@@ -237,6 +237,7 @@
 #define FCF_REDISC_EVT	0x100 /* FCF rediscovery event to worker thread */
 #define FCF_REDISC_FOV	0x200 /* Post FCF rediscovery fast failover */
 #define FCF_REDISC_PROG (FCF_REDISC_PEND | FCF_REDISC_EVT)
+	uint16_t fcf_redisc_attempted;
 	uint32_t addr_mode;
 	uint32_t eligible_fcf_cnt;
 	struct lpfc_fcf_rec current_rec;
@@ -442,6 +443,7 @@
 #define LPFC_LNK_GE	0x0 /* FCoE */
 #define LPFC_LNK_FC	0x1 /* FC   */
 	uint8_t lnk_no;
+	uint8_t optic_state;
 };
 
 #define LPFC_SLI4_HANDLER_CNT		(LPFC_FCP_IO_CHAN_MAX+ \
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_version.h
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "11.0.0.0."
+#define LPFC_DRIVER_VERSION "11.0.0.10."
 #define LPFC_DRIVER_NAME		"lpfc"
 
 /* Used for SLI 2/3 */
--- linux-4.4.0.orig/drivers/scsi/lpfc/lpfc_vport.c
+++ linux-4.4.0/drivers/scsi/lpfc/lpfc_vport.c
@@ -393,6 +393,14 @@
 	*(struct lpfc_vport **)fc_vport->dd_data = vport;
 	vport->fc_vport = fc_vport;
 
+	/* At this point we are fully registered with SCSI Layer.  */
+	vport->load_flag |= FC_ALLOW_FDMI;
+	if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+		/* Setup appropriate attribute masks */
+		vport->fdmi_hba_mask = phba->pport->fdmi_hba_mask;
+		vport->fdmi_port_mask = phba->pport->fdmi_port_mask;
+	}
+
 	/*
 	 * In SLI4, the vpi must be activated before it can be used
 	 * by the port.
@@ -528,6 +536,12 @@
 
 	spin_lock_irq(shost->host_lock);
 	vport->load_flag |= FC_LOADING;
+	if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) {
+		spin_unlock_irq(shost->host_lock);
+		lpfc_issue_init_vpi(vport);
+		goto out;
+	}
+
 	vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
 	spin_unlock_irq(shost->host_lock);
 
@@ -548,6 +562,8 @@
 	} else {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 	}
+
+out:
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
 			 "1827 Vport Enabled.\n");
 	return VPORT_OK;
@@ -607,27 +623,16 @@
 		    vport->port_state < LPFC_VPORT_READY)
 			return -EAGAIN;
 	}
+
 	/*
-	 * This is a bit of a mess.  We want to ensure the shost doesn't get
-	 * torn down until we're done with the embedded lpfc_vport structure.
-	 *
-	 * Beyond holding a reference for this function, we also need a
-	 * reference for outstanding I/O requests we schedule during delete
-	 * processing.  But once we scsi_remove_host() we can no longer obtain
-	 * a reference through scsi_host_get().
-	 *
-	 * So we take two references here.  We release one reference at the
-	 * bottom of the function -- after delinking the vport.  And we
-	 * release the other at the completion of the unreg_vpi that get's
-	 * initiated after we've disposed of all other resources associated
-	 * with the port.
+	 * Take early refcount for outstanding I/O requests we schedule during
+	 * delete processing for unreg_vpi.  Always keep this before
+	 * scsi_remove_host() as we can no longer obtain a reference through
+	 * scsi_host_get() after scsi_host_remove as shost is set to SHOST_DEL.
 	 */
 	if (!scsi_host_get(shost))
 		return VPORT_INVAL;
-	if (!scsi_host_get(shost)) {
-		scsi_host_put(shost);
-		return VPORT_INVAL;
-	}
+
 	lpfc_free_sysfs_attr(vport);
 
 	lpfc_debugfs_terminate(vport);
@@ -644,10 +649,6 @@
 		ns_ndlp_referenced = true;
 	}
 
-	/* Remove FC host and then SCSI host with the vport */
-	fc_remove_host(shost);
-	scsi_remove_host(shost);
-
 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
 
 	/* In case of driver unload, we shall not perform fabric logo as the
@@ -760,6 +761,10 @@
 		lpfc_nlp_put(ndlp);
 	}
 
+	/* Remove FC host to break driver binding. */
+	fc_remove_host(shost);
+	scsi_remove_host(shost);
+
 	lpfc_cleanup(vport);
 	lpfc_sli_host_down(vport);
 
@@ -775,8 +780,9 @@
 		if (!(vport->vpi_state & LPFC_VPI_REGISTERED) ||
 				lpfc_mbx_unreg_vpi(vport))
 			scsi_host_put(shost);
-	} else
+	} else {
 		scsi_host_put(shost);
+	}
 
 	lpfc_free_vpi(phba, vport->vpi);
 	vport->work_port_events = 0;
--- linux-4.4.0.orig/drivers/scsi/mac_esp.c
+++ linux-4.4.0/drivers/scsi/mac_esp.c
@@ -55,6 +55,7 @@
 	int error;
 };
 static struct esp *esp_chips[2];
+static DEFINE_SPINLOCK(esp_chips_lock);
 
 #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
 			       platform_get_drvdata((struct platform_device *) \
@@ -425,6 +426,8 @@
 			scsi_esp_cmd(esp, ESP_CMD_TI);
 		}
 	}
+
+	esp->send_cmd_residual = esp_count;
 }
 
 static int mac_esp_irq_pending(struct esp *esp)
@@ -562,15 +565,18 @@
 	}
 
 	host->irq = IRQ_MAC_SCSI;
-	esp_chips[dev->id] = esp;
-	mb();
-	if (esp_chips[!dev->id] == NULL) {
-		err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL);
-		if (err < 0) {
-			esp_chips[dev->id] = NULL;
-			goto fail_free_priv;
-		}
+
+	/* The request_irq() call is intended to succeed for the first device
+	 * and fail for the second device.
+	 */
+	err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL);
+	spin_lock(&esp_chips_lock);
+	if (err < 0 && esp_chips[!dev->id] == NULL) {
+		spin_unlock(&esp_chips_lock);
+		goto fail_free_priv;
 	}
+	esp_chips[dev->id] = esp;
+	spin_unlock(&esp_chips_lock);
 
 	err = scsi_esp_register(esp, &dev->dev);
 	if (err)
@@ -579,8 +585,13 @@
 	return 0;
 
 fail_free_irq:
-	if (esp_chips[!dev->id] == NULL)
+	spin_lock(&esp_chips_lock);
+	esp_chips[dev->id] = NULL;
+	if (esp_chips[!dev->id] == NULL) {
+		spin_unlock(&esp_chips_lock);
 		free_irq(host->irq, esp);
+	} else
+		spin_unlock(&esp_chips_lock);
 fail_free_priv:
 	kfree(mep);
 fail_free_command_block:
@@ -599,9 +610,13 @@
 
 	scsi_esp_unregister(esp);
 
+	spin_lock(&esp_chips_lock);
 	esp_chips[dev->id] = NULL;
-	if (!(esp_chips[0] || esp_chips[1]))
+	if (esp_chips[!dev->id] == NULL) {
+		spin_unlock(&esp_chips_lock);
 		free_irq(irq, NULL);
+	} else
+		spin_unlock(&esp_chips_lock);
 
 	kfree(mep);
 
--- linux-4.4.0.orig/drivers/scsi/megaraid.c
+++ linux-4.4.0/drivers/scsi/megaraid.c
@@ -4197,6 +4197,9 @@
 	int irq, i, j;
 	int error = -ENODEV;
 
+	if (hba_count >= MAX_CONTROLLERS)
+		goto out;
+
 	if (pci_enable_device(pdev))
 		goto out;
 	pci_set_master(pdev);
@@ -4216,11 +4219,11 @@
 		 */
 		if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ &&
 		    pdev->subsystem_device == 0xC000)
-		   	return -ENODEV;
+			goto out_disable_device;
 		/* Now check the magic signature byte */
 		pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
 		if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE)
-			return -ENODEV;
+			goto out_disable_device;
 		/* Ok it is probably a megaraid */
 	}
 
--- linux-4.4.0.orig/drivers/scsi/megaraid/megaraid_mm.c
+++ linux-4.4.0/drivers/scsi/megaraid/megaraid_mm.c
@@ -179,8 +179,12 @@
 
 	/*
 	 * The following call will block till a kioc is available
+	 * or return NULL if the list head is empty for the pointer
+	 * of type mraid_mmapt passed to mraid_mm_alloc_kioc
 	 */
 	kioc = mraid_mm_alloc_kioc(adp);
+	if (!kioc)
+		return -ENXIO;
 
 	/*
 	 * User sent the old mimd_t ioctl packet. Convert it to uioc_t.
--- linux-4.4.0.orig/drivers/scsi/megaraid/megaraid_sas.h
+++ linux-4.4.0/drivers/scsi/megaraid/megaraid_sas.h
@@ -35,8 +35,8 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION				"06.808.16.00-rc1"
-#define MEGASAS_RELDATE				"Oct. 8, 2015"
+#define MEGASAS_VERSION				"06.810.09.00-rc1"
+#define MEGASAS_RELDATE				"Jan. 28, 2016"
 
 /*
  * Device IDs
@@ -152,6 +152,7 @@
 #define MFI_RESET_FLAGS				MFI_INIT_READY| \
 						MFI_INIT_MFIMODE| \
 						MFI_INIT_ABORT
+#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE    (0x01)
 
 /*
  * MFI frame flags
@@ -170,6 +171,7 @@
 
 /* Driver internal */
 #define DRV_DCMD_POLLED_MODE		0x1
+#define DRV_DCMD_SKIP_REFIRE		0x2
 
 /*
  * Definition for cmd_status
@@ -214,6 +216,7 @@
 
 #define MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS	0x01190100
 #define MR_DRIVER_SET_APP_CRASHDUMP_MODE	(0xF0010000 | 0x0600)
+#define MR_DCMD_PD_GET_INFO			0x02020000
 
 /*
  * Global functions
@@ -390,6 +393,7 @@
 
 
 #define SGE_BUFFER_SIZE	4096
+#define MEGASAS_CLUSTER_ID_SIZE	16
 /*
  * define constants for device list query options
  */
@@ -434,6 +438,257 @@
 	MR_PD_STATE_SYSTEM              = 0x40,
  };
 
+union MR_PD_REF {
+	struct {
+		u16	 deviceId;
+		u16	 seqNum;
+	} mrPdRef;
+	u32	 ref;
+};
+
+/*
+ * define the DDF Type bit structure
+ */
+union MR_PD_DDF_TYPE {
+	 struct {
+		union {
+			struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+				 u16	 forcedPDGUID:1;
+				 u16	 inVD:1;
+				 u16	 isGlobalSpare:1;
+				 u16	 isSpare:1;
+				 u16	 isForeign:1;
+				 u16	 reserved:7;
+				 u16	 intf:4;
+#else
+				 u16	 intf:4;
+				 u16	 reserved:7;
+				 u16	 isForeign:1;
+				 u16	 isSpare:1;
+				 u16	 isGlobalSpare:1;
+				 u16	 inVD:1;
+				 u16	 forcedPDGUID:1;
+#endif
+			 } pdType;
+			 u16	 type;
+		 };
+		 u16	 reserved;
+	 } ddf;
+	 struct {
+		 u32	reserved;
+	 } nonDisk;
+	 u32	 type;
+} __packed;
+
+/*
+ * defines the progress structure
+ */
+union MR_PROGRESS {
+	struct  {
+		u16 progress;
+		union {
+			u16 elapsedSecs;
+			u16 elapsedSecsForLastPercent;
+		};
+	} mrProgress;
+	u32 w;
+} __packed;
+
+/*
+ * defines the physical drive progress structure
+ */
+struct MR_PD_PROGRESS {
+	struct {
+#ifndef MFI_BIG_ENDIAN
+		u32     rbld:1;
+		u32     patrol:1;
+		u32     clear:1;
+		u32     copyBack:1;
+		u32     erase:1;
+		u32     locate:1;
+		u32     reserved:26;
+#else
+		u32     reserved:26;
+		u32     locate:1;
+		u32     erase:1;
+		u32     copyBack:1;
+		u32     clear:1;
+		u32     patrol:1;
+		u32     rbld:1;
+#endif
+	} active;
+	union MR_PROGRESS     rbld;
+	union MR_PROGRESS     patrol;
+	union {
+		union MR_PROGRESS     clear;
+		union MR_PROGRESS     erase;
+	};
+
+	struct {
+#ifndef MFI_BIG_ENDIAN
+		u32     rbld:1;
+		u32     patrol:1;
+		u32     clear:1;
+		u32     copyBack:1;
+		u32     erase:1;
+		u32     reserved:27;
+#else
+		u32     reserved:27;
+		u32     erase:1;
+		u32     copyBack:1;
+		u32     clear:1;
+		u32     patrol:1;
+		u32     rbld:1;
+#endif
+	} pause;
+
+	union MR_PROGRESS     reserved[3];
+} __packed;
+
+struct  MR_PD_INFO {
+	union MR_PD_REF	ref;
+	u8 inquiryData[96];
+	u8 vpdPage83[64];
+	u8 notSupported;
+	u8 scsiDevType;
+
+	union {
+		u8 connectedPortBitmap;
+		u8 connectedPortNumbers;
+	};
+
+	u8 deviceSpeed;
+	u32 mediaErrCount;
+	u32 otherErrCount;
+	u32 predFailCount;
+	u32 lastPredFailEventSeqNum;
+
+	u16 fwState;
+	u8 disabledForRemoval;
+	u8 linkSpeed;
+	union MR_PD_DDF_TYPE state;
+
+	struct {
+		u8 count;
+#ifndef __BIG_ENDIAN_BITFIELD
+		u8 isPathBroken:4;
+		u8 reserved3:3;
+		u8 widePortCapable:1;
+#else
+		u8 widePortCapable:1;
+		u8 reserved3:3;
+		u8 isPathBroken:4;
+#endif
+
+		u8 connectorIndex[2];
+		u8 reserved[4];
+		u64 sasAddr[2];
+		u8 reserved2[16];
+	} pathInfo;
+
+	u64 rawSize;
+	u64 nonCoercedSize;
+	u64 coercedSize;
+	u16 enclDeviceId;
+	u8 enclIndex;
+
+	union {
+		u8 slotNumber;
+		u8 enclConnectorIndex;
+	};
+
+	struct MR_PD_PROGRESS progInfo;
+	u8 badBlockTableFull;
+	u8 unusableInCurrentConfig;
+	u8 vpdPage83Ext[64];
+	u8 powerState;
+	u8 enclPosition;
+	u32 allowedOps;
+	u16 copyBackPartnerId;
+	u16 enclPartnerDeviceId;
+	struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+		u16 fdeCapable:1;
+		u16 fdeEnabled:1;
+		u16 secured:1;
+		u16 locked:1;
+		u16 foreign:1;
+		u16 needsEKM:1;
+		u16 reserved:10;
+#else
+		u16 reserved:10;
+		u16 needsEKM:1;
+		u16 foreign:1;
+		u16 locked:1;
+		u16 secured:1;
+		u16 fdeEnabled:1;
+		u16 fdeCapable:1;
+#endif
+	} security;
+	u8 mediaType;
+	u8 notCertified;
+	u8 bridgeVendor[8];
+	u8 bridgeProductIdentification[16];
+	u8 bridgeProductRevisionLevel[4];
+	u8 satBridgeExists;
+
+	u8 interfaceType;
+	u8 temperature;
+	u8 emulatedBlockSize;
+	u16 userDataBlockSize;
+	u16 reserved2;
+
+	struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+		u32 piType:3;
+		u32 piFormatted:1;
+		u32 piEligible:1;
+		u32 NCQ:1;
+		u32 WCE:1;
+		u32 commissionedSpare:1;
+		u32 emergencySpare:1;
+		u32 ineligibleForSSCD:1;
+		u32 ineligibleForLd:1;
+		u32 useSSEraseType:1;
+		u32 wceUnchanged:1;
+		u32 supportScsiUnmap:1;
+		u32 reserved:18;
+#else
+		u32 reserved:18;
+		u32 supportScsiUnmap:1;
+		u32 wceUnchanged:1;
+		u32 useSSEraseType:1;
+		u32 ineligibleForLd:1;
+		u32 ineligibleForSSCD:1;
+		u32 emergencySpare:1;
+		u32 commissionedSpare:1;
+		u32 WCE:1;
+		u32 NCQ:1;
+		u32 piEligible:1;
+		u32 piFormatted:1;
+		u32 piType:3;
+#endif
+	} properties;
+
+	u64 shieldDiagCompletionTime;
+	u8 shieldCounter;
+
+	u8 linkSpeedOther;
+	u8 reserved4[2];
+
+	struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+		u32 bbmErrCountSupported:1;
+		u32 bbmErrCount:31;
+#else
+		u32 bbmErrCount:31;
+		u32 bbmErrCountSupported:1;
+#endif
+	} bbmErr;
+
+	u8 reserved1[512-428];
+} __packed;
 
  /*
  * defines the physical drive address structure
@@ -473,6 +728,7 @@
 	u16             tid;
 	u8             driveType;
 	u8             driveState;
+	u8             interface;
 } __packed;
 
  /*
@@ -972,7 +1228,8 @@
 	*/
 	struct {
 #if defined(__BIG_ENDIAN_BITFIELD)
-		u32     reserved:26;
+		u32     reserved:25;
+		u32     passive:1;
 		u32     premiumFeatureMismatch:1;
 		u32     ctrlPropIncompatible:1;
 		u32     fwVersionMismatch:1;
@@ -986,11 +1243,12 @@
 		u32     fwVersionMismatch:1;
 		u32     ctrlPropIncompatible:1;
 		u32     premiumFeatureMismatch:1;
-		u32     reserved:26;
+		u32     passive:1;
+		u32     reserved:25;
 #endif
 	} cluster;
 
-	char clusterId[16];                     /*7D4h */
+	char clusterId[MEGASAS_CLUSTER_ID_SIZE]; /*0x7D4 */
 	struct {
 		u8  maxVFsSupported;            /*0x7E4*/
 		u8  numVFsEnabled;              /*0x7E5*/
@@ -1083,6 +1341,8 @@
 
 #define VD_EXT_DEBUG 0
 
+#define SCAN_PD_CHANNEL	0x1
+#define SCAN_VD_CHANNEL	0x2
 
 enum MR_SCSI_CMD_TYPE {
 	READ_WRITE_LDIO = 0,
@@ -1091,6 +1351,17 @@
 	NON_READ_WRITE_SYSPDIO = 3,
 };
 
+enum DCMD_TIMEOUT_ACTION {
+	INITIATE_OCR = 0,
+	KILL_ADAPTER = 1,
+	IGNORE_TIMEOUT = 2,
+};
+
+enum FW_BOOT_CONTEXT {
+	PROBE_CONTEXT = 0,
+	OCR_CONTEXT = 1,
+};
+
 /* Frame Type */
 #define IO_FRAME				0
 #define PTHRU_FRAME				1
@@ -1137,6 +1408,7 @@
 
 #define MFI_OB_INTR_STATUS_MASK			0x00000002
 #define MFI_POLL_TIMEOUT_SECS			60
+#define MFI_IO_TIMEOUT_SECS			180
 #define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF	(5 * HZ)
 #define MEGASAS_OCR_SETTLE_TIME_VF		(1000 * 30)
 #define MEGASAS_ROUTINE_WAIT_TIME_VF		300
@@ -1154,6 +1426,7 @@
 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET          0X003FC000
 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT    14
 #define MR_MAX_MSIX_REG_ARRAY                   16
+#define MR_RDPQ_MODE_OFFSET			0X00800000
 /*
 * register set for both 1068 and 1078 controllers
 * structure extended for 1078 registers
@@ -1193,8 +1466,9 @@
 
 	u32 	outbound_scratch_pad ;		/*00B0h*/
 	u32	outbound_scratch_pad_2;         /*00B4h*/
+	u32	outbound_scratch_pad_3;         /*00B8h*/
 
-	u32	reserved_4[2];			/*00B8h*/
+	u32	reserved_4;			/*00BCh*/
 
 	u32 	inbound_low_queue_port ;	/*00C0h*/
 
@@ -1266,7 +1540,10 @@
 typedef union _MFI_CAPABILITIES {
 	struct {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-		u32     reserved:23;
+		u32     reserved:20;
+		u32     support_qd_throttling:1;
+		u32     support_fp_rlbypass:1;
+		u32     support_vfid_in_ioframe:1;
 		u32     support_ext_io_size:1;
 		u32	support_ext_queue_depth:1;
 		u32     security_protocol_cmds_fw:1;
@@ -1286,7 +1563,10 @@
 		u32     security_protocol_cmds_fw:1;
 		u32	support_ext_queue_depth:1;
 		u32     support_ext_io_size:1;
-		u32     reserved:23;
+		u32     support_vfid_in_ioframe:1;
+		u32     support_fp_rlbypass:1;
+		u32     support_qd_throttling:1;
+		u32     reserved:20;
 #endif
 	} mfi_capabilities;
 	__le32		reg;
@@ -1511,6 +1791,15 @@
 	u8 raw_bytes[64];
 };
 
+/**
+ * struct MR_PRIV_DEVICE - sdev private hostdata
+ * @is_tm_capable: firmware managed tm_capable flag
+ * @tm_busy: TM request is in progress
+ */
+struct MR_PRIV_DEVICE {
+	bool is_tm_capable;
+	bool tm_busy;
+};
 struct megasas_cmd;
 
 union megasas_evt_class_locale {
@@ -1700,6 +1989,19 @@
 	u8	reserved[1980];
 };
 
+enum MR_PD_TYPE {
+		 UNKNOWN_DRIVE = 0,
+		 PARALLEL_SCSI = 1,
+		 SAS_PD = 2,
+		 SATA_PD = 3,
+		 FC_PD = 4,
+};
+
+/* JBOD Queue depth definitions */
+#define MEGASAS_SATA_QD	32
+#define MEGASAS_SAS_QD	64
+#define MEGASAS_DEFAULT_PD_QD	64
+
 struct megasas_instance {
 
 	__le32 *producer;
@@ -1714,6 +2016,8 @@
 	dma_addr_t vf_affiliation_111_h;
 	struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
 	dma_addr_t hb_host_mem_h;
+	struct MR_PD_INFO *pd_info;
+	dma_addr_t pd_info_h;
 
 	__le32 *reply_queue;
 	dma_addr_t reply_queue_h;
@@ -1745,6 +2049,8 @@
 	u16 max_fw_cmds;
 	u16 max_mfi_cmds;
 	u16 max_scsi_cmds;
+	u16 ldio_threshold;
+	u16 cur_can_queue;
 	u32 max_sectors_per_req;
 	struct megasas_aen_event *ev;
 
@@ -1762,7 +2068,7 @@
 	struct megasas_evt_detail *evt_detail;
 	dma_addr_t evt_detail_h;
 	struct megasas_cmd *aen_cmd;
-	struct mutex aen_mutex;
+	struct mutex hba_mutex;
 	struct semaphore ioctl_sem;
 
 	struct Scsi_Host *host;
@@ -1775,6 +2081,7 @@
 	u32 fw_support_ieee;
 
 	atomic_t fw_outstanding;
+	atomic_t ldio_outstanding;
 	atomic_t fw_reset_no_pci_access;
 
 	struct megasas_instance_template *instancet;
@@ -1790,14 +2097,14 @@
 	u8 UnevenSpanSupport;
 
 	u8 supportmax256vd;
-	u8 allow_fw_scan;
+	u8 pd_list_not_supported;
 	u16 fw_supported_vd_count;
 	u16 fw_supported_pd_count;
 
 	u16 drv_supported_vd_count;
 	u16 drv_supported_pd_count;
 
-	u8 adprecovery;
+	atomic_t adprecovery;
 	unsigned long last_time;
 	u32 mfiStatus;
 	u32 last_seq_num;
@@ -1822,11 +2129,14 @@
 	char skip_heartbeat_timer_del;
 	u8 requestorId;
 	char PlasmaFW111;
-	char mpio;
+	char clusterId[MEGASAS_CLUSTER_ID_SIZE];
+	u8 peerIsPresent;
+	u8 passive;
 	u16 throttlequeuedepth;
 	u8 mask_interrupts;
 	u16 max_chain_frame_sz;
 	u8 is_imr;
+	u8 is_rdpq;
 	bool dev_handle;
 };
 struct MR_LD_VF_MAP {
@@ -1916,12 +2226,12 @@
 	u32 (*init_adapter)(struct megasas_instance *);
 	u32 (*build_and_issue_cmd) (struct megasas_instance *,
 				    struct scsi_cmnd *);
-	void (*issue_dcmd) (struct megasas_instance *instance,
+	int (*issue_dcmd)(struct megasas_instance *instance,
 			    struct megasas_cmd *cmd);
 };
 
 #define MEGASAS_IS_LOGICAL(scp)						\
-	(scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
+	((scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
 
 #define MEGASAS_DEV_INDEX(scp)						\
 	(((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +	\
@@ -2014,6 +2324,19 @@
 	int max_index;
 };
 
+enum MEGASAS_OCR_CAUSE {
+	FW_FAULT_OCR			= 0,
+	SCSIIO_TIMEOUT_OCR		= 1,
+	MFI_IO_TIMEOUT_OCR		= 2,
+};
+
+enum DCMD_RETURN_STATUS {
+	DCMD_SUCCESS		= 0,
+	DCMD_TIMEOUT		= 1,
+	DCMD_FAILED		= 2,
+	DCMD_NOT_FIRED		= 3,
+};
+
 u8
 MR_BuildRaidContext(struct megasas_instance *instance,
 		    struct IO_REQUEST_INFO *io_info,
@@ -2051,4 +2374,8 @@
 int megasas_cmd_type(struct scsi_cmnd *cmd);
 void megasas_setup_jbod_map(struct megasas_instance *instance);
 
+void megasas_update_sdev_properties(struct scsi_device *sdev);
+int megasas_reset_fusion(struct Scsi_Host *shost, int reason);
+int megasas_task_abort_fusion(struct scsi_cmnd *scmd);
+int megasas_reset_target_fusion(struct scsi_cmnd *scmd);
 #endif				/*LSI_MEGARAID_SAS_H */
--- linux-4.4.0.orig/drivers/scsi/megaraid/megaraid_sas_base.c
+++ linux-4.4.0/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -83,7 +83,7 @@
 MODULE_PARM_DESC(throttlequeuedepth,
 	"Adapter queue depth when throttled due to I/O timeout. Default: 16");
 
-int resetwaittime = MEGASAS_RESET_WAIT_TIME;
+unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
 module_param(resetwaittime, int, S_IRUGO);
 MODULE_PARM_DESC(resetwaittime, "Wait time in seconds after I/O timeout "
 		 "before resetting adapter. Default: 180");
@@ -92,6 +92,18 @@
 module_param(smp_affinity_enable, int, S_IRUGO);
 MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
 
+int rdpq_enable = 1;
+module_param(rdpq_enable, int, S_IRUGO);
+MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disable Default: disable(0)");
+
+unsigned int dual_qdepth_disable;
+module_param(dual_qdepth_disable, int, S_IRUGO);
+MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
+
+unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
+module_param(scmd_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
@@ -104,6 +116,8 @@
 static int megasas_issue_init_mfi(struct megasas_instance *instance);
 static int megasas_register_aen(struct megasas_instance *instance,
 				u32 seq_num, u32 class_locale_word);
+static int
+megasas_get_pd_info(struct megasas_instance *instance, u16 device_id);
 /*
  * PCI ID table for all supported controllers
  */
@@ -189,18 +203,18 @@
 wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
 	int seconds);
 void megasas_reset_reply_desc(struct megasas_instance *instance);
-int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
 void megasas_fusion_ocr_wq(struct work_struct *work);
 static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
 					 int initial);
 int megasas_check_mpio_paths(struct megasas_instance *instance,
 			     struct scsi_cmnd *scmd);
 
-void
+int
 megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
 	instance->instancet->fire_cmd(instance,
 		cmd->frame_phys_addr, 0, instance->reg_set);
+	return 0;
 }
 
 /**
@@ -473,7 +487,7 @@
 megasas_check_reset_xscale(struct megasas_instance *instance,
 		struct megasas_register_set __iomem *regs)
 {
-	if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+	if ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
 	    (le32_to_cpu(*instance->consumer) ==
 		MEGASAS_ADPRESET_INPROG_SIGN))
 		return 1;
@@ -609,7 +623,7 @@
 megasas_check_reset_ppc(struct megasas_instance *instance,
 			struct megasas_register_set __iomem *regs)
 {
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
 		return 1;
 
 	return 0;
@@ -735,6 +749,7 @@
 	       &(regs)->inbound_high_queue_port);
 	writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1,
 	       &(regs)->inbound_low_queue_port);
+	mmiowb();
 	spin_unlock_irqrestore(&instance->hba_lock, flags);
 }
 
@@ -746,7 +761,7 @@
 megasas_check_reset_skinny(struct megasas_instance *instance,
 				struct megasas_register_set __iomem *regs)
 {
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
 		return 1;
 
 	return 0;
@@ -940,9 +955,8 @@
 megasas_check_reset_gen2(struct megasas_instance *instance,
 		struct megasas_register_set __iomem *regs)
 {
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
 		return 1;
-	}
 
 	return 0;
 }
@@ -983,25 +997,20 @@
 int
 megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
-	int seconds;
 	struct megasas_header *frame_hdr = &cmd->frame->hdr;
 
-	frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
+	frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
 	frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
 
-	/*
-	 * Issue the frame using inbound queue port
-	 */
-	instance->instancet->issue_dcmd(instance, cmd);
+	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+		(instance->instancet->issue_dcmd(instance, cmd))) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return DCMD_NOT_FIRED;
+	}
 
-	/*
-	 * Wait for cmd_status to change
-	 */
-	if (instance->requestorId)
-		seconds = MEGASAS_ROUTINE_WAIT_TIME_VF;
-	else
-		seconds = MFI_POLL_TIMEOUT_SECS;
-	return wait_and_poll(instance, cmd, seconds);
+	return wait_and_poll(instance, cmd, instance->requestorId ?
+			MEGASAS_ROUTINE_WAIT_TIME_VF : MFI_IO_TIMEOUT_SECS);
 }
 
 /**
@@ -1019,21 +1028,29 @@
 			  struct megasas_cmd *cmd, int timeout)
 {
 	int ret = 0;
-
 	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
 
-	instance->instancet->issue_dcmd(instance, cmd);
+	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+		(instance->instancet->issue_dcmd(instance, cmd))) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return DCMD_NOT_FIRED;
+	}
+
 	if (timeout) {
 		ret = wait_event_timeout(instance->int_cmd_wait_q,
 				cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
-		if (!ret)
-			return 1;
+		if (!ret) {
+			dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n",
+				__func__, __LINE__);
+			return DCMD_TIMEOUT;
+		}
 	} else
 		wait_event(instance->int_cmd_wait_q,
 				cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS);
 
 	return (cmd->cmd_status_drv == MFI_STAT_OK) ?
-		0 : 1;
+		DCMD_SUCCESS : DCMD_FAILED;
 }
 
 /**
@@ -1077,15 +1094,20 @@
 	cmd->sync_cmd = 1;
 	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
 
-	instance->instancet->issue_dcmd(instance, cmd);
+	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+		(instance->instancet->issue_dcmd(instance, cmd))) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return DCMD_NOT_FIRED;
+	}
 
 	if (timeout) {
 		ret = wait_event_timeout(instance->abort_cmd_wait_q,
 				cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
 		if (!ret) {
-			dev_err(&instance->pdev->dev, "Command timedout"
-				"from %s\n", __func__);
-			return 1;
+			dev_err(&instance->pdev->dev, "Failed from %s %d Abort Timed out\n",
+				__func__, __LINE__);
+			return DCMD_TIMEOUT;
 		}
 	} else
 		wait_event(instance->abort_cmd_wait_q,
@@ -1094,7 +1116,8 @@
 	cmd->sync_cmd = 0;
 
 	megasas_return_cmd(instance, cmd);
-	return 0;
+	return (cmd->cmd_status_drv == MFI_STAT_OK) ?
+		DCMD_SUCCESS : DCMD_FAILED;
 }
 
 /**
@@ -1621,7 +1644,7 @@
 	return 0;
 out_return_cmd:
 	megasas_return_cmd(instance, cmd);
-	return 1;
+	return SCSI_MLQUEUE_HOST_BUSY;
 }
 
 
@@ -1634,7 +1657,7 @@
 megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 {
 	struct megasas_instance *instance;
-	unsigned long flags;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
 
 	instance = (struct megasas_instance *)
 	    scmd->device->host->hostdata;
@@ -1648,35 +1671,38 @@
 	if (instance->issuepend_done == 0)
 		return SCSI_MLQUEUE_HOST_BUSY;
 
-	spin_lock_irqsave(&instance->hba_lock, flags);
 
 	/* Check for an mpio path and adjust behavior */
-	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
 		if (megasas_check_mpio_paths(instance, scmd) ==
 		    (DID_RESET << 16)) {
-			spin_unlock_irqrestore(&instance->hba_lock, flags);
 			return SCSI_MLQUEUE_HOST_BUSY;
 		} else {
-			spin_unlock_irqrestore(&instance->hba_lock, flags);
 			scmd->result = DID_NO_CONNECT << 16;
 			scmd->scsi_done(scmd);
 			return 0;
 		}
 	}
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
-		spin_unlock_irqrestore(&instance->hba_lock, flags);
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		scmd->result = DID_NO_CONNECT << 16;
 		scmd->scsi_done(scmd);
 		return 0;
 	}
 
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
-		spin_unlock_irqrestore(&instance->hba_lock, flags);
-		return SCSI_MLQUEUE_HOST_BUSY;
+	mr_device_priv_data = scmd->device->hostdata;
+	if (!mr_device_priv_data) {
+		scmd->result = DID_NO_CONNECT << 16;
+		scmd->scsi_done(scmd);
+		return 0;
 	}
 
-	spin_unlock_irqrestore(&instance->hba_lock, flags);
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	if (mr_device_priv_data->tm_busy)
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+
 
 	scmd->result = 0;
 
@@ -1687,24 +1713,16 @@
 		goto out_done;
 	}
 
-	switch (scmd->cmnd[0]) {
-	case SYNCHRONIZE_CACHE:
-		/*
-		 * FW takes care of flush cache on its own
-		 * No need to send it down
-		 */
+	/*
+	 * FW takes care of flush cache on its own for Virtual Disk.
+	 * No need to send it down for VD. For JBOD send SYNCHRONIZE_CACHE to FW.
+	 */
+	if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) && MEGASAS_IS_LOGICAL(scmd)) {
 		scmd->result = DID_OK << 16;
 		goto out_done;
-	default:
-		break;
 	}
 
-	if (instance->instancet->build_and_issue_cmd(instance, scmd)) {
-		dev_err(&instance->pdev->dev, "Err returned from build_and_issue_cmd\n");
-		return SCSI_MLQUEUE_HOST_BUSY;
-	}
-
-	return 0;
+	return instance->instancet->build_and_issue_cmd(instance, scmd);
 
  out_done:
 	scmd->scsi_done(scmd);
@@ -1726,27 +1744,39 @@
 }
 
 /*
-* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD
+* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities
 *
 * @sdev: OS provided scsi device
 *
 * Returns void
 */
-static void megasas_set_dma_alignment(struct scsi_device *sdev)
+void megasas_update_sdev_properties(struct scsi_device *sdev)
 {
+	u16 pd_index = 0;
 	u32 device_id, ld;
 	struct megasas_instance *instance;
 	struct fusion_context *fusion;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
+	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
 	struct MR_LD_RAID *raid;
 	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
 
 	instance = megasas_lookup_instance(sdev->host->host_no);
 	fusion = instance->ctrl_context;
+	mr_device_priv_data = sdev->hostdata;
 
 	if (!fusion)
 		return;
 
-	if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) {
+	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+		instance->use_seqnum_jbod_fp) {
+		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+			sdev->id;
+		pd_sync = (void *)fusion->pd_seq_sync
+				[(instance->pd_seq_map_id - 1) & 1];
+		mr_device_priv_data->is_tm_capable =
+			pd_sync->seq[pd_index].capability.tmCapable;
+	} else {
 		device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
 					+ sdev->id;
 		local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
@@ -1754,17 +1784,58 @@
 		raid = MR_LdRaidGet(ld, local_map_ptr);
 
 		if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
-			blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+		blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+		mr_device_priv_data->is_tm_capable =
+			raid->capability.tmCapable;
+	}
+}
+
+static void megasas_set_device_queue_depth(struct scsi_device *sdev)
+{
+	u16				pd_index = 0;
+	int		ret = DCMD_FAILED;
+	struct megasas_instance *instance;
+
+	instance = megasas_lookup_instance(sdev->host->host_no);
+
+	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+
+		if (instance->pd_info) {
+			mutex_lock(&instance->hba_mutex);
+			ret = megasas_get_pd_info(instance, pd_index);
+			mutex_unlock(&instance->hba_mutex);
+		}
+
+		if (ret != DCMD_SUCCESS)
+			return;
+
+		if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
+
+			switch (instance->pd_list[pd_index].interface) {
+			case SAS_PD:
+				scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
+				break;
+
+			case SATA_PD:
+				scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
+				break;
+
+			default:
+				scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
+			}
+		}
 	}
 }
 
+
 static int megasas_slave_configure(struct scsi_device *sdev)
 {
 	u16 pd_index = 0;
 	struct megasas_instance *instance;
 
 	instance = megasas_lookup_instance(sdev->host->host_no);
-	if (instance->allow_fw_scan) {
+	if (instance->pd_list_not_supported) {
 		if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
 			sdev->type == TYPE_DISK) {
 			pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
@@ -1774,12 +1845,14 @@
 				return -ENXIO;
 		}
 	}
-	megasas_set_dma_alignment(sdev);
+	megasas_set_device_queue_depth(sdev);
+	megasas_update_sdev_properties(sdev);
+
 	/*
 	 * The RAID firmware may require extended timeouts.
 	 */
 	blk_queue_rq_timeout(sdev->request_queue,
-		MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+		scmd_timeout * HZ);
 
 	return 0;
 }
@@ -1788,6 +1861,7 @@
 {
 	u16 pd_index = 0;
 	struct megasas_instance *instance ;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
 
 	instance = megasas_lookup_instance(sdev->host->host_no);
 	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
@@ -1797,15 +1871,29 @@
 		pd_index =
 			(sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
 			sdev->id;
-		if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState ==
+		if ((instance->pd_list_not_supported ||
+			instance->pd_list[pd_index].driveState ==
 			MR_PD_STATE_SYSTEM)) {
-			return 0;
+			goto scan_target;
 		}
 		return -ENXIO;
 	}
+
+scan_target:
+	mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
+					GFP_KERNEL);
+	if (!mr_device_priv_data)
+		return -ENOMEM;
+	sdev->hostdata = mr_device_priv_data;
 	return 0;
 }
 
+static void megasas_slave_destroy(struct scsi_device *sdev)
+{
+	kfree(sdev->hostdata);
+	sdev->hostdata = NULL;
+}
+
 /*
 * megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
 *                                       kill adapter
@@ -1826,9 +1914,12 @@
 			if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) {
 				cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
 				if (cmd_mfi->sync_cmd &&
-					cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)
+				    (cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)) {
+					cmd_mfi->frame->hdr.cmd_status =
+							MFI_STAT_WRONG_STATE;
 					megasas_complete_cmd(instance,
 							     cmd_mfi, DID_OK);
+				}
 			}
 		}
 	} else {
@@ -1845,7 +1936,7 @@
 void megaraid_sas_kill_hba(struct megasas_instance *instance)
 {
 	/* Set critical error to block I/O & ioctls in case caller didn't */
-	instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+	atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
 	/* Wait 1 second to ensure IO or ioctls in build have posted */
 	msleep(1000);
 	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
@@ -1854,7 +1945,7 @@
 		writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
 		/* Flush */
 		readl(&instance->reg_set->doorbell);
-		if (instance->mpio && instance->requestorId)
+		if (instance->requestorId && instance->peerIsPresent)
 			memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
 	} else {
 		writel(MFI_STOP_ADP,
@@ -1883,7 +1974,7 @@
 		spin_lock_irqsave(instance->host->host_lock, flags);
 		instance->flag &= ~MEGASAS_FW_BUSY;
 
-		instance->host->can_queue = instance->max_scsi_cmds;
+		instance->host->can_queue = instance->cur_can_queue;
 		spin_unlock_irqrestore(instance->host->host_lock, flags);
 	}
 }
@@ -1905,7 +1996,7 @@
 	unsigned long flags;
 
 	/* If we have already declared adapter dead, donot complete cmds */
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return;
 
 	spin_lock_irqsave(&instance->completion_lock, flags);
@@ -1974,7 +2065,7 @@
 		*instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
 	}
 	instance->instancet->disable_intr(instance);
-	instance->adprecovery   = MEGASAS_ADPRESET_SM_INFAULT;
+	atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
 	instance->issuepend_done = 0;
 
 	atomic_set(&instance->fw_outstanding, 0);
@@ -2054,9 +2145,7 @@
 	dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
 	       "scsi%d\n", instance->host->host_no);
 
-	megasas_issue_blocked_cmd(instance, cmd, 0);
-
-	if (dcmd->cmd_status) {
+	if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
 		dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
 		       " failed with status 0x%x for scsi%d\n",
 		       dcmd->cmd_status, instance->host->host_no);
@@ -2166,9 +2255,8 @@
 	dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
 	       "scsi%d\n", instance->host->host_no);
 
-	megasas_issue_blocked_cmd(instance, cmd, 0);
 
-	if (dcmd->cmd_status) {
+	if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
 		dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
 		       " failed with status 0x%x for scsi%d\n",
 		       dcmd->cmd_status, instance->host->host_no);
@@ -2373,21 +2461,21 @@
  */
 static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 {
-	int i;
+	int i, sl, outstanding;
 	u32 reset_index;
 	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
-	u8 adprecovery;
 	unsigned long flags;
 	struct list_head clist_local;
 	struct megasas_cmd *reset_cmd;
 	u32 fw_state;
-	u8 kill_adapter_flag;
 
-	spin_lock_irqsave(&instance->hba_lock, flags);
-	adprecovery = instance->adprecovery;
-	spin_unlock_irqrestore(&instance->hba_lock, flags);
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+		dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
+		__func__, __LINE__);
+		return FAILED;
+	}
 
-	if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 
 		INIT_LIST_HEAD(&clist_local);
 		spin_lock_irqsave(&instance->hba_lock, flags);
@@ -2398,18 +2486,13 @@
 		dev_notice(&instance->pdev->dev, "HBA reset wait ...\n");
 		for (i = 0; i < wait_time; i++) {
 			msleep(1000);
-			spin_lock_irqsave(&instance->hba_lock, flags);
-			adprecovery = instance->adprecovery;
-			spin_unlock_irqrestore(&instance->hba_lock, flags);
-			if (adprecovery == MEGASAS_HBA_OPERATIONAL)
+			if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL)
 				break;
 		}
 
-		if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+		if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 			dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n");
-			spin_lock_irqsave(&instance->hba_lock, flags);
-			instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
-			spin_unlock_irqrestore(&instance->hba_lock, flags);
+			atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
 			return FAILED;
 		}
 
@@ -2447,7 +2530,7 @@
 	}
 
 	for (i = 0; i < resetwaittime; i++) {
-		int outstanding = atomic_read(&instance->fw_outstanding);
+		outstanding = atomic_read(&instance->fw_outstanding);
 
 		if (!outstanding)
 			break;
@@ -2466,67 +2549,60 @@
 	}
 
 	i = 0;
-	kill_adapter_flag = 0;
+	outstanding = atomic_read(&instance->fw_outstanding);
+	fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+
+	if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
+		goto no_outstanding;
+
+	if (instance->disableOnlineCtrlReset)
+		goto kill_hba_and_failed;
 	do {
-		fw_state = instance->instancet->read_fw_status_reg(
-					instance->reg_set) & MFI_STATE_MASK;
-		if ((fw_state == MFI_STATE_FAULT) &&
-			(instance->disableOnlineCtrlReset == 0)) {
-			if (i == 3) {
-				kill_adapter_flag = 2;
-				break;
-			}
+		if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) {
+			dev_info(&instance->pdev->dev,
+				"%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, oustanding 0x%x\n",
+				__func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding));
+			if (i == 3)
+				goto kill_hba_and_failed;
 			megasas_do_ocr(instance);
-			kill_adapter_flag = 1;
 
-			/* wait for 1 secs to let FW finish the pending cmds */
-			msleep(1000);
+			if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+				dev_info(&instance->pdev->dev, "%s:%d OCR failed and HBA is killed.\n",
+				__func__, __LINE__);
+				return FAILED;
+			}
+			dev_info(&instance->pdev->dev, "%s:%d waiting_for_outstanding: after issue OCR.\n",
+				__func__, __LINE__);
+
+			for (sl = 0; sl < 10; sl++)
+				msleep(500);
+
+			outstanding = atomic_read(&instance->fw_outstanding);
+
+			fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+			if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
+				goto no_outstanding;
 		}
 		i++;
 	} while (i <= 3);
 
-	if (atomic_read(&instance->fw_outstanding) && !kill_adapter_flag) {
-		if (instance->disableOnlineCtrlReset == 0) {
-			megasas_do_ocr(instance);
+no_outstanding:
 
-			/* wait for 5 secs to let FW finish the pending cmds */
-			for (i = 0; i < wait_time; i++) {
-				int outstanding =
-					atomic_read(&instance->fw_outstanding);
-				if (!outstanding)
-					return SUCCESS;
-				msleep(1000);
-			}
-		}
-	}
+	dev_info(&instance->pdev->dev, "%s:%d no more pending commands remain after reset handling.\n",
+		__func__, __LINE__);
+	return SUCCESS;
 
-	if (atomic_read(&instance->fw_outstanding) ||
-					(kill_adapter_flag == 2)) {
-		dev_notice(&instance->pdev->dev, "pending cmds after reset\n");
-		/*
-		 * Send signal to FW to stop processing any pending cmds.
-		 * The controller will be taken offline by the OS now.
-		 */
-		if ((instance->pdev->device ==
-			PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-			(instance->pdev->device ==
-			PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
-			writel(MFI_STOP_ADP,
-				&instance->reg_set->doorbell);
-		} else {
-			writel(MFI_STOP_ADP,
-				&instance->reg_set->inbound_doorbell);
-		}
-		megasas_dump_pending_frames(instance);
-		spin_lock_irqsave(&instance->hba_lock, flags);
-		instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
-		spin_unlock_irqrestore(&instance->hba_lock, flags);
-		return FAILED;
-	}
+kill_hba_and_failed:
 
-	dev_notice(&instance->pdev->dev, "no pending cmds after reset\n");
+	/* Reset not supported, kill adapter */
+	dev_info(&instance->pdev->dev, "%s:%d killing adapter scsi%d"
+		" disableOnlineCtrlReset %d fw_outstanding %d \n",
+		__func__, __LINE__, instance->host->host_no, instance->disableOnlineCtrlReset,
+		atomic_read(&instance->fw_outstanding));
+	megasas_dump_pending_frames(instance);
+	megaraid_sas_kill_hba(instance);
 
-	return SUCCESS;
+	return FAILED;
 }
 
 /**
@@ -2547,7 +2623,7 @@
 	scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n",
 		 scmd->cmnd[0], scmd->retries);
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n");
 		return FAILED;
 	}
@@ -2575,7 +2651,7 @@
 	unsigned long flags;
 
 	if (time_after(jiffies, scmd->jiffies_at_alloc +
-				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
+				(scmd_timeout * 2) * HZ)) {
 		return BLK_EH_NOT_HANDLED;
 	}
 
@@ -2751,6 +2827,7 @@
 	u32 size;
 	unsigned long buff_addr;
 	unsigned long dmachunk = CRASH_DMA_BUF_SIZE;
+	unsigned long chunk_left_bytes;
 	unsigned long src_addr;
 	unsigned long flags;
 	u32 buff_offset;
@@ -2776,6 +2853,8 @@
 	}
 
 	size = (instance->fw_crash_buffer_size * dmachunk) - buff_offset;
+	chunk_left_bytes = dmachunk - (buff_offset % dmachunk);
+	size = (size > chunk_left_bytes) ? chunk_left_bytes : size;
 	size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size;
 
 	src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] +
@@ -2851,6 +2930,16 @@
 	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
 }
 
+static ssize_t
+megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
+	char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding));
+}
+
 static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
 	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
 static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO,
@@ -2859,12 +2948,15 @@
 	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
 static DEVICE_ATTR(page_size, S_IRUGO,
 	megasas_page_size_show, NULL);
+static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
+	megasas_ldio_outstanding_show, NULL);
 
 struct device_attribute *megaraid_host_attrs[] = {
 	&dev_attr_fw_crash_buffer_size,
 	&dev_attr_fw_crash_buffer,
 	&dev_attr_fw_crash_state,
 	&dev_attr_page_size,
+	&dev_attr_ldio_outstanding,
 	NULL,
 };
 
@@ -2878,6 +2970,7 @@
 	.proc_name = "megaraid_sas",
 	.slave_configure = megasas_slave_configure,
 	.slave_alloc = megasas_slave_alloc,
+	.slave_destroy = megasas_slave_destroy,
 	.queuecommand = megasas_queue_command,
 	.eh_device_reset_handler = megasas_reset_device,
 	.eh_bus_reset_handler = megasas_reset_bus_host,
@@ -3277,13 +3370,13 @@
 	u32 wait;
 	unsigned long flags;
 
-	if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
+    if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
 		dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
-				instance->adprecovery);
+				atomic_read(&instance->adprecovery));
 		return ;
 	}
 
-	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
 		dev_notice(&instance->pdev->dev, "FW detected to be in fault"
 					"state, restarting it...\n");
 
@@ -3326,7 +3419,7 @@
 		megasas_issue_init_mfi(instance);
 
 		spin_lock_irqsave(&instance->hba_lock, flags);
-		instance->adprecovery	= MEGASAS_HBA_OPERATIONAL;
+		atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		instance->instancet->enable_intr(instance);
 
@@ -3391,14 +3484,14 @@
 
 
 			instance->instancet->disable_intr(instance);
-			instance->adprecovery	= MEGASAS_ADPRESET_SM_INFAULT;
+			atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
 			instance->issuepend_done = 0;
 
 			atomic_set(&instance->fw_outstanding, 0);
 			megasas_internal_reset_defer_cmds(instance);
 
 			dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n",
-					fw_state, instance->adprecovery);
+					fw_state, atomic_read(&instance->adprecovery));
 
 			schedule_work(&instance->work_init);
 			return IRQ_HANDLED;
@@ -3581,12 +3674,12 @@
 		/*
 		 * The cur_state should not last for more than max_wait secs
 		 */
-		for (i = 0; i < (max_wait * 1000); i++) {
+		for (i = 0; i < max_wait * 50; i++) {
 			curr_abs_state = instance->instancet->
 				read_fw_status_reg(instance->reg_set);
 
 			if (abs_state == curr_abs_state) {
-				msleep(1);
+				msleep(20);
 			} else
 				break;
 		}
@@ -3846,12 +3939,99 @@
 	if (megasas_create_frame_pool(instance)) {
 		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
 		megasas_free_cmds(instance);
+		return -ENOMEM;
 	}
 
 	return 0;
 }
 
 /*
+ * dcmd_timeout_ocr_possible -	Check if OCR is possible based on Driver/FW state.
+ * @instance:				Adapter soft state
+ *
+ * Return 0 for only Fusion adapter, if driver load/unload is not in progress
+ * or FW is not under OCR.
+ */
+inline int
+dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
+
+	if (!instance->ctrl_context)
+		return KILL_ADAPTER;
+	else if (instance->unload ||
+			test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
+		return IGNORE_TIMEOUT;
+	else
+		return INITIATE_OCR;
+}
+
+static int
+megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
+{
+	int ret;
+	struct megasas_cmd *cmd;
+	struct megasas_dcmd_frame *dcmd;
+
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd) {
+		dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
+		return -ENOMEM;
+	}
+
+	dcmd = &cmd->frame->dcmd;
+
+	memset(instance->pd_info, 0, sizeof(*instance->pd_info));
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+	dcmd->mbox.s[0] = cpu_to_le16(device_id);
+	dcmd->cmd = MFI_CMD_DCMD;
+	dcmd->cmd_status = 0xFF;
+	dcmd->sge_count = 1;
+	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+	dcmd->timeout = 0;
+	dcmd->pad_0 = 0;
+	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO));
+	dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO);
+	dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->pd_info_h);
+	dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_PD_INFO));
+
+	if (instance->ctrl_context && !instance->mask_interrupts)
+		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
+	else
+		ret = megasas_issue_polled(instance, cmd);
+
+	switch (ret) {
+	case DCMD_SUCCESS:
+		instance->pd_list[device_id].interface =
+				instance->pd_info->state.ddf.pdType.intf;
+		break;
+
+	case DCMD_TIMEOUT:
+
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			megasas_reset_fusion(instance->host,
+				MFI_IO_TIMEOUT_OCR);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+
+		break;
+	}
+
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
+
+	return ret;
+}
+/*
  * megasas_get_pd_list_info -	Returns FW's pd_list structure
  * @instance:				Adapter soft state
  * @pd_list:				pd_list structure
@@ -3906,42 +4086,78 @@
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
 		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+			MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-	/*
-	 * the following function will get the instance PD LIST.
-	 */
+	switch (ret) {
+	case DCMD_FAILED:
+		dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
+			"failed/not supported by firmware\n");
 
-	pd_addr = ci->addr;
+		if (instance->ctrl_context)
+			megaraid_sas_kill_hba(instance);
+		else
+			instance->pd_list_not_supported = 1;
+		break;
+	case DCMD_TIMEOUT:
 
-	if (ret == 0 &&
-	     (le32_to_cpu(ci->count) <
-		  (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			/*
+			 * DCMD failed from AEN path.
+			 * AEN path already hold reset_mutex to avoid PCI access
+			 * while OCR is in progress.
+			 */
+			mutex_unlock(&instance->reset_mutex);
+			megasas_reset_fusion(instance->host,
+						MFI_IO_TIMEOUT_OCR);
+			mutex_lock(&instance->reset_mutex);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d \n",
+				__func__, __LINE__);
+			break;
+		}
+
+		break;
+
+	case DCMD_SUCCESS:
+		pd_addr = ci->addr;
+
+		if ((le32_to_cpu(ci->count) >
+			(MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
+			break;
 
 		memset(instance->local_pd_list, 0,
-			MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
+				MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
 
 		for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) {
-
 			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].tid	=
-				le16_to_cpu(pd_addr->deviceId);
+					le16_to_cpu(pd_addr->deviceId);
 			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveType	=
-							pd_addr->scsiDevType;
+					pd_addr->scsiDevType;
 			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState	=
-							MR_PD_STATE_SYSTEM;
+					MR_PD_STATE_SYSTEM;
 			pd_addr++;
 		}
+
 		memcpy(instance->pd_list, instance->local_pd_list,
 			sizeof(instance->pd_list));
+		break;
+
 	}
 
 	pci_free_consistent(instance->pdev,
 				MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
 				ci, ci_h);
 
-	megasas_return_cmd(instance, cmd);
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
 
 	return ret;
 }
@@ -4002,33 +4218,63 @@
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
 		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+			MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-
 	ld_count = le32_to_cpu(ci->ldCount);
 
-	/* the following function will get the instance PD LIST */
+	switch (ret) {
+	case DCMD_FAILED:
+		megaraid_sas_kill_hba(instance);
+		break;
+	case DCMD_TIMEOUT:
+
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			/*
+			 * DCMD failed from AEN path.
+			 * AEN path already hold reset_mutex to avoid PCI access
+			 * while OCR is in progress.
+			 */
+			mutex_unlock(&instance->reset_mutex);
+			megasas_reset_fusion(instance->host,
+						MFI_IO_TIMEOUT_OCR);
+			mutex_lock(&instance->reset_mutex);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+
+		break;
+
+	case DCMD_SUCCESS:
+		if (ld_count > instance->fw_supported_vd_count)
+			break;
 
-	if ((ret == 0) && (ld_count <= instance->fw_supported_vd_count)) {
 		memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
 
 		for (ld_index = 0; ld_index < ld_count; ld_index++) {
 			if (ci->ldList[ld_index].state != 0) {
 				ids = ci->ldList[ld_index].ref.targetId;
-				instance->ld_ids[ids] =
-					ci->ldList[ld_index].ref.targetId;
+				instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
 			}
 		}
+
+		break;
 	}
 
-	pci_free_consistent(instance->pdev,
-				sizeof(struct MR_LD_LIST),
-				ci,
-				ci_h);
+	pci_free_consistent(instance->pdev, sizeof(struct MR_LD_LIST), ci, ci_h);
+
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
 
-	megasas_return_cmd(instance, cmd);
 	return ret;
 }
 
@@ -4090,26 +4336,61 @@
 	dcmd->pad_0  = 0;
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
-		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-	tgtid_count = le32_to_cpu(ci->count);
+	switch (ret) {
+	case DCMD_FAILED:
+		dev_info(&instance->pdev->dev,
+			"DCMD not supported by firmware - %s %d\n",
+				__func__, __LINE__);
+		ret = megasas_get_ld_list(instance);
+		break;
+	case DCMD_TIMEOUT:
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			/*
+			 * DCMD failed from AEN path.
+			 * AEN path already hold reset_mutex to avoid PCI access
+			 * while OCR is in progress.
+			 */
+			mutex_unlock(&instance->reset_mutex);
+			megasas_reset_fusion(instance->host,
+						MFI_IO_TIMEOUT_OCR);
+			mutex_lock(&instance->reset_mutex);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+
+		break;
+	case DCMD_SUCCESS:
+		tgtid_count = le32_to_cpu(ci->count);
+
+		if ((tgtid_count > (instance->fw_supported_vd_count)))
+			break;
 
-	if ((ret == 0) && (tgtid_count <= (instance->fw_supported_vd_count))) {
 		memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
 		for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
 			ids = ci->targetId[ld_index];
 			instance->ld_ids[ids] = ci->targetId[ld_index];
 		}
 
+		break;
 	}
 
 	pci_free_consistent(instance->pdev, sizeof(struct MR_LD_TARGETID_LIST),
-			    ci, ci_h);
+		    ci, ci_h);
 
-	megasas_return_cmd(instance, cmd);
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
 
 	return ret;
 }
@@ -4223,38 +4504,73 @@
 	dcmd->mbox.b[0] = 1;
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
-		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-	if (!ret) {
+	switch (ret) {
+	case DCMD_SUCCESS:
 		memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
+		/* Save required controller information in
+		 * CPU endianness format.
+		 */
 		le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties);
 		le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
 		le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
+
+		/* Update the latest Ext VD info.
+		 * From Init path, store current firmware details.
+		 * From OCR path, detect any firmware properties changes.
+		 * in case of Firmware upgrade without system reboot.
+		 */
 		megasas_update_ext_vd_details(instance);
 		instance->use_seqnum_jbod_fp =
 			ctrl_info->adapterOperations3.useSeqNumJbodFP;
+
+		/*Check whether controller is iMR or MR */
 		instance->is_imr = (ctrl_info->memory_size ? 0 : 1);
 		dev_info(&instance->pdev->dev,
-				"controller type\t: %s(%dMB)\n",
-				instance->is_imr ? "iMR" : "MR",
-				le16_to_cpu(ctrl_info->memory_size));
+			"controller type\t: %s(%dMB)\n",
+			instance->is_imr ? "iMR" : "MR",
+			le16_to_cpu(ctrl_info->memory_size));
+
 		instance->disableOnlineCtrlReset =
 			ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
-		dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
-			instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
 		instance->secure_jbod_support =
 			ctrl_info->adapterOperations3.supportSecurityonJBOD;
+		dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
+			instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
 		dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n",
 			instance->secure_jbod_support ? "Yes" : "No");
+		break;
+
+	case DCMD_TIMEOUT:
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			megasas_reset_fusion(instance->host,
+				MFI_IO_TIMEOUT_OCR);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+	case DCMD_FAILED:
+		megaraid_sas_kill_hba(instance);
+		break;
+
 	}
 
 	pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
 			    ci, ci_h);
 
 	megasas_return_cmd(instance, cmd);
+
+
 	return ret;
 }
 
@@ -4304,12 +4620,28 @@
 	dcmd->sgl.sge32[0].length = cpu_to_le32(CRASH_DMA_BUF_SIZE);
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
-		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-	megasas_return_cmd(instance, cmd);
+	if (ret == DCMD_TIMEOUT) {
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			megasas_reset_fusion(instance->host,
+					MFI_IO_TIMEOUT_OCR);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+	} else
+		megasas_return_cmd(instance, cmd);
+
 	return ret;
 }
 
@@ -4426,6 +4758,7 @@
 		sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS));
 	}
 
+	instance->cur_can_queue = instance->max_scsi_cmds;
 	/*
 	 * Create a pool of commands
 	 */
@@ -4669,7 +5002,7 @@
 	/* Find first memory bar */
 	bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
 	instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
-	if (pci_request_selected_regions(instance->pdev, instance->bar,
+	if (pci_request_selected_regions(instance->pdev, 1<<instance->bar,
 					 "megasas: LSI")) {
 		dev_printk(KERN_DEBUG, &instance->pdev->dev, "IO memory region busy!\n");
 		return -EBUSY;
@@ -4712,7 +5045,6 @@
 	case PCI_DEVICE_ID_DELL_PERC5:
 	default:
 		instance->instancet = &megasas_instance_template_xscale;
-		instance->allow_fw_scan = 1;
 		break;
 	}
 
@@ -4756,6 +5088,9 @@
 				instance->msix_vectors = ((scratch_pad_2
 					& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
 					>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
+				if (rdpq_enable)
+					instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
+								1 : 0;
 				fw_msix_count = instance->msix_vectors;
 				/* Save 1-15 reply post index address to local memory
 				 * Index 0 is already saved from reg offset
@@ -4792,6 +5127,8 @@
 	dev_info(&instance->pdev->dev,
 		"current msix/online cpus\t: (%d/%d)\n",
 		instance->msix_vectors, (unsigned int)num_online_cpus());
+	dev_info(&instance->pdev->dev,
+		"RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled");
 
 	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
 		(unsigned long)instance);
@@ -4856,7 +5193,9 @@
 
 	tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2);
 
-	instance->mpio = ctrl_info->adapterOperations2.mpio;
+	instance->peerIsPresent = ctrl_info->cluster.peerIsPresent;
+	instance->passive = ctrl_info->cluster.passive;
+	memcpy(instance->clusterId, ctrl_info->clusterId, sizeof(instance->clusterId));
 	instance->UnevenSpanSupport =
 		ctrl_info->adapterOperations2.supportUnevenSpans;
 	if (instance->UnevenSpanSupport) {
@@ -4932,6 +5271,11 @@
 		instance->throttlequeuedepth =
 				MEGASAS_THROTTLE_QUEUE_DEPTH;
 
+	if (resetwaittime > MEGASAS_RESET_WAIT_TIME)
+		resetwaittime = MEGASAS_RESET_WAIT_TIME;
+
+	if ((scmd_timeout < 10) || (scmd_timeout > MEGASAS_DEFAULT_CMD_TIMEOUT))
+		scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
 
 	/* Launch SR-IOV heartbeat timer */
 	if (instance->requestorId) {
@@ -4960,7 +5304,7 @@
 	iounmap(instance->reg_set);
 
       fail_ioremap:
-	pci_release_selected_regions(instance->pdev, instance->bar);
+	pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 
 	return -EINVAL;
 }
@@ -4981,7 +5325,7 @@
 
 	iounmap(instance->reg_set);
 
-	pci_release_selected_regions(instance->pdev, instance->bar);
+	pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 }
 
 /**
@@ -5035,10 +5379,8 @@
 	dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(el_info_h);
 	dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_log_info));
 
-	if (megasas_issue_blocked_cmd(instance, cmd, 30))
-		dev_err(&instance->pdev->dev, "Command timedout"
-			"from %s\n", __func__);
-	else {
+	if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS) ==
+		DCMD_SUCCESS) {
 		/*
 		 * Copy the data back into callers buffer
 		 */
@@ -5047,7 +5389,9 @@
 		eli->clear_seq_num = el_info->clear_seq_num;
 		eli->shutdown_seq_num = el_info->shutdown_seq_num;
 		eli->boot_seq_num = el_info->boot_seq_num;
-	}
+	} else
+		dev_err(&instance->pdev->dev, "DCMD failed "
+			"from %s\n", __func__);
 
 	pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
 			    el_info, el_info_h);
@@ -5096,6 +5440,14 @@
 		prev_aen.word =
 			le32_to_cpu(instance->aen_cmd->frame->dcmd.mbox.w[1]);
 
+		if ((curr_aen.members.class < MFI_EVT_CLASS_DEBUG) ||
+		    (curr_aen.members.class > MFI_EVT_CLASS_DEAD)) {
+			dev_info(&instance->pdev->dev,
+				 "%s %d out of range class %d send by application\n",
+				 __func__, __LINE__, curr_aen.members.class);
+			return 0;
+		}
+
 		/*
 		 * A class whose enum value is smaller is inclusive of all
 		 * higher values. If a PROGRESS (= -1) was previously
@@ -5262,6 +5614,8 @@
 	if (instance->ctrl_context) {
 		host->hostt->eh_device_reset_handler = NULL;
 		host->hostt->eh_bus_reset_handler = NULL;
+		host->hostt->eh_target_reset_handler = megasas_reset_target_fusion;
+		host->hostt->eh_abort_handler = megasas_task_abort_fusion;
 	}
 
 	/*
@@ -5447,7 +5801,7 @@
 	instance->flag_ieee = 0;
 	instance->ev = NULL;
 	instance->issuepend_done = 1;
-	instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+	atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 	instance->is_imr = 0;
 
 	instance->evt_detail = pci_alloc_consistent(pdev,
@@ -5461,6 +5815,12 @@
 		goto fail_alloc_dma_buf;
 	}
 
+	instance->pd_info = pci_alloc_consistent(pdev,
+		sizeof(struct MR_PD_INFO), &instance->pd_info_h);
+
+	if (!instance->pd_info)
+		dev_err(&instance->pdev->dev, "Failed to alloc mem for pd_info\n");
+
 	/*
 	 * Initialize locks and queues
 	 */
@@ -5476,8 +5836,8 @@
 	spin_lock_init(&instance->hba_lock);
 	spin_lock_init(&instance->completion_lock);
 
-	mutex_init(&instance->aen_mutex);
 	mutex_init(&instance->reset_mutex);
+	mutex_init(&instance->hba_mutex);
 
 	/*
 	 * Initialize PCI related and misc parameters
@@ -5592,6 +5952,10 @@
 				    instance->evt_detail,
 				    instance->evt_detail_h);
 
+	if (instance->pd_info)
+		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+					instance->pd_info,
+					instance->pd_info_h);
 	if (instance->producer)
 		pci_free_consistent(pdev, sizeof(u32), instance->producer,
 				    instance->producer_h);
@@ -5616,7 +5980,7 @@
 	struct megasas_cmd *cmd;
 	struct megasas_dcmd_frame *dcmd;
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return;
 
 	cmd = megasas_get_cmd(instance);
@@ -5638,9 +6002,12 @@
 	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
 	dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
 
-	if (megasas_issue_blocked_cmd(instance, cmd, 30))
-		dev_err(&instance->pdev->dev, "Command timedout"
-			" from %s\n", __func__);
+	if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
+			!= DCMD_SUCCESS) {
+		dev_err(&instance->pdev->dev,
+			"return from %s %d\n", __func__, __LINE__);
+		return;
+	}
 
 	megasas_return_cmd(instance, cmd);
 }
@@ -5656,7 +6023,7 @@
 	struct megasas_cmd *cmd;
 	struct megasas_dcmd_frame *dcmd;
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return;
 
 	cmd = megasas_get_cmd(instance);
@@ -5666,13 +6033,13 @@
 
 	if (instance->aen_cmd)
 		megasas_issue_blocked_abort_cmd(instance,
-			instance->aen_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+			instance->aen_cmd, MFI_IO_TIMEOUT_SECS);
 	if (instance->map_update_cmd)
 		megasas_issue_blocked_abort_cmd(instance,
-			instance->map_update_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+			instance->map_update_cmd, MFI_IO_TIMEOUT_SECS);
 	if (instance->jbod_seq_cmd)
 		megasas_issue_blocked_abort_cmd(instance,
-			instance->jbod_seq_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+			instance->jbod_seq_cmd, MFI_IO_TIMEOUT_SECS);
 
 	dcmd = &cmd->frame->dcmd;
 
@@ -5687,9 +6054,12 @@
 	dcmd->data_xfer_len = 0;
 	dcmd->opcode = cpu_to_le32(opcode);
 
-	if (megasas_issue_blocked_cmd(instance, cmd, 30))
-		dev_err(&instance->pdev->dev, "Command timedout"
-			"from %s\n", __func__);
+	if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
+			!= DCMD_SUCCESS) {
+		dev_err(&instance->pdev->dev,
+			"return from %s %d\n", __func__, __LINE__);
+		return;
+	}
 
 	megasas_return_cmd(instance, cmd);
 }
@@ -5847,6 +6217,10 @@
 				instance->evt_detail,
 				instance->evt_detail_h);
 
+	if (instance->pd_info)
+		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+					instance->pd_info,
+					instance->pd_info_h);
 	if (instance->producer)
 		pci_free_consistent(pdev, sizeof(u32), instance->producer,
 				instance->producer_h);
@@ -5941,11 +6315,11 @@
 			if (fusion->ld_drv_map[i])
 				free_pages((ulong)fusion->ld_drv_map[i],
 					fusion->drv_map_pages);
-				if (fusion->pd_seq_sync)
-					dma_free_coherent(&instance->pdev->dev,
-						pd_seq_map_sz,
-						fusion->pd_seq_sync[i],
-						fusion->pd_seq_phys[i]);
+			if (fusion->pd_seq_sync[i])
+				dma_free_coherent(&instance->pdev->dev,
+					pd_seq_map_sz,
+					fusion->pd_seq_sync[i],
+					fusion->pd_seq_phys[i]);
 		}
 		free_pages((ulong)instance->ctrl_context,
 			instance->ctrl_context_pages);
@@ -5965,6 +6339,10 @@
 		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
 				instance->evt_detail, instance->evt_detail_h);
 
+	if (instance->pd_info)
+		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+					instance->pd_info,
+					instance->pd_info_h);
 	if (instance->vf_affiliation)
 		pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
 				    sizeof(struct MR_LD_VF_AFFILIATION),
@@ -6090,7 +6468,7 @@
 	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
 		local_instance = megasas_mgmt_info.instance[i];
 		if (local_instance && local_instance->crash_dump_drv_support) {
-			if ((local_instance->adprecovery ==
+			if ((atomic_read(&local_instance->adprecovery) ==
 				MEGASAS_HBA_OPERATIONAL) &&
 				!megasas_set_crash_dump_params(local_instance,
 					crash_support)) {
@@ -6227,7 +6605,15 @@
 	 * cmd to the SCSI mid-layer
 	 */
 	cmd->sync_cmd = 1;
-	megasas_issue_blocked_cmd(instance, cmd, 0);
+	if (megasas_issue_blocked_cmd(instance, cmd, 0) == DCMD_NOT_FIRED) {
+		cmd->sync_cmd = 0;
+		dev_err(&instance->pdev->dev,
+			"return -EBUSY from %s %d opcode 0x%x cmd->cmd_status_drv 0x%x\n",
+			__func__, __LINE__, cmd->frame->dcmd.opcode,
+			cmd->cmd_status_drv);
+		return -EBUSY;
+	}
+
 	cmd->sync_cmd = 0;
 
 	if (instance->unload == 1) {
@@ -6282,12 +6668,13 @@
 	}
 
 	for (i = 0; i < ioc->sge_count; i++) {
-		if (kbuff_arr[i])
+		if (kbuff_arr[i]) {
 			dma_free_coherent(&instance->pdev->dev,
 					  le32_to_cpu(kern_sge32[i].length),
 					  kbuff_arr[i],
 					  le32_to_cpu(kern_sge32[i].phys_addr));
 			kbuff_arr[i] = NULL;
+		}
 	}
 
 	megasas_return_cmd(instance, cmd);
@@ -6330,7 +6717,7 @@
 		goto out_kfree_ioc;
 	}
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		dev_err(&instance->pdev->dev, "Controller in crit error\n");
 		error = -ENODEV;
 		goto out_kfree_ioc;
@@ -6349,7 +6736,7 @@
 	for (i = 0; i < wait_time; i++) {
 
 		spin_lock_irqsave(&instance->hba_lock, flags);
-		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
 			spin_unlock_irqrestore(&instance->hba_lock, flags);
 			break;
 		}
@@ -6364,7 +6751,7 @@
 	}
 
 	spin_lock_irqsave(&instance->hba_lock, flags);
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 
 		dev_err(&instance->pdev->dev, "timed out while"
@@ -6406,7 +6793,7 @@
 	if (!instance)
 		return -ENODEV;
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		return -ENODEV;
 	}
 
@@ -6417,7 +6804,7 @@
 	for (i = 0; i < wait_time; i++) {
 
 		spin_lock_irqsave(&instance->hba_lock, flags);
-		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
 			spin_unlock_irqrestore(&instance->hba_lock,
 						flags);
 			break;
@@ -6434,7 +6821,7 @@
 	}
 
 	spin_lock_irqsave(&instance->hba_lock, flags);
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		dev_err(&instance->pdev->dev, "timed out while waiting"
 				"for HBA to recover\n");
@@ -6442,10 +6829,10 @@
 	}
 	spin_unlock_irqrestore(&instance->hba_lock, flags);
 
-	mutex_lock(&instance->aen_mutex);
+	mutex_lock(&instance->reset_mutex);
 	error = megasas_register_aen(instance, aen.seq_num,
 				     aen.class_locale_word);
-	mutex_unlock(&instance->aen_mutex);
+	mutex_unlock(&instance->reset_mutex);
 	return error;
 }
 
@@ -6476,9 +6863,9 @@
 	int i;
 	int error = 0;
 	compat_uptr_t ptr;
-	unsigned long local_raw_ptr;
 	u32 local_sense_off;
 	u32 local_sense_len;
+	u32 user_sense_off;
 
 	if (clear_user(ioc, sizeof(*ioc)))
 		return -EFAULT;
@@ -6496,17 +6883,19 @@
 	 * sense_len is not null, so prepare the 64bit value under
 	 * the same condition.
 	 */
-	if (get_user(local_raw_ptr, ioc->frame.raw) ||
-		get_user(local_sense_off, &ioc->sense_off) ||
-		get_user(local_sense_len, &ioc->sense_len))
+	if (get_user(local_sense_off, &ioc->sense_off) ||
+		get_user(local_sense_len, &ioc->sense_len) ||
+		get_user(user_sense_off, &cioc->sense_off))
 		return -EFAULT;
 
+	if (local_sense_off != user_sense_off)
+		return -EINVAL;
 
 	if (local_sense_len) {
 		void __user **sense_ioc_ptr =
-			(void __user **)((u8*)local_raw_ptr + local_sense_off);
+			(void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off);
 		compat_uptr_t *sense_cioc_ptr =
-			(compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
+			(compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off);
 		if (get_user(ptr, sense_cioc_ptr) ||
 		    put_user(compat_ptr(ptr), sense_ioc_ptr))
 			return -EFAULT;
@@ -6647,6 +7036,7 @@
 	int     i, j, doscan = 0;
 	u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
 	int error;
+	u8  dcmd_ret = DCMD_SUCCESS;
 
 	if (!instance) {
 		printk(KERN_ERR "invalid instance!\n");
@@ -6659,16 +7049,7 @@
 		wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
 
 	/* Don't run the event workqueue thread if OCR is running */
-	for (i = 0; i < wait_time; i++) {
-		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
-			break;
-		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
-			dev_notice(&instance->pdev->dev, "%s waiting for "
-			       "controller reset to finish for scsi%d\n",
-			       __func__, instance->host->host_no);
-		}
-		msleep(1000);
-	}
+	mutex_lock(&instance->reset_mutex);
 
 	instance->ev = NULL;
 	host = instance->host;
@@ -6676,212 +7057,127 @@
 		megasas_decode_evt(instance);
 
 		switch (le32_to_cpu(instance->evt_detail->code)) {
-		case MR_EVT_PD_INSERTED:
-			if (megasas_get_pd_list(instance) == 0) {
-			for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-				for (j = 0;
-				j < MEGASAS_MAX_DEV_PER_CHANNEL;
-				j++) {
-
-				pd_index =
-				(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-				sdev1 = scsi_device_lookup(host, i, j, 0);
-
-				if (instance->pd_list[pd_index].driveState
-						== MR_PD_STATE_SYSTEM) {
-					if (!sdev1)
-						scsi_add_device(host, i, j, 0);
-
-					if (sdev1)
-						scsi_device_put(sdev1);
-					}
-				}
-			}
-			}
-			doscan = 0;
-			break;
 
+		case MR_EVT_PD_INSERTED:
 		case MR_EVT_PD_REMOVED:
-			if (megasas_get_pd_list(instance) == 0) {
-			for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-				for (j = 0;
-				j < MEGASAS_MAX_DEV_PER_CHANNEL;
-				j++) {
-
-				pd_index =
-				(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-				sdev1 = scsi_device_lookup(host, i, j, 0);
-
-				if (instance->pd_list[pd_index].driveState
-					== MR_PD_STATE_SYSTEM) {
-					if (sdev1)
-						scsi_device_put(sdev1);
-				} else {
-					if (sdev1) {
-						scsi_remove_device(sdev1);
-						scsi_device_put(sdev1);
-					}
-				}
-				}
-			}
-			}
-			doscan = 0;
+			dcmd_ret = megasas_get_pd_list(instance);
+			if (dcmd_ret == DCMD_SUCCESS)
+				doscan = SCAN_PD_CHANNEL;
 			break;
 
 		case MR_EVT_LD_OFFLINE:
 		case MR_EVT_CFG_CLEARED:
 		case MR_EVT_LD_DELETED:
-			if (!instance->requestorId ||
-			    megasas_get_ld_vf_affiliation(instance, 0)) {
-				if (megasas_ld_list_query(instance,
-							  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-					megasas_get_ld_list(instance);
-				for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-					for (j = 0;
-					     j < MEGASAS_MAX_DEV_PER_CHANNEL;
-					     j++) {
-
-						ld_index =
-							(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-						sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
-						if (instance->ld_ids[ld_index]
-						    != 0xff) {
-							if (sdev1)
-								scsi_device_put(sdev1);
-						} else {
-							if (sdev1) {
-								scsi_remove_device(sdev1);
-								scsi_device_put(sdev1);
-							}
-						}
-					}
-				}
-				doscan = 0;
-			}
-			break;
 		case MR_EVT_LD_CREATED:
 			if (!instance->requestorId ||
-			    megasas_get_ld_vf_affiliation(instance, 0)) {
-				if (megasas_ld_list_query(instance,
-							  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-					megasas_get_ld_list(instance);
-				for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-					for (j = 0;
-					     j < MEGASAS_MAX_DEV_PER_CHANNEL;
-					     j++) {
-						ld_index =
-							(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-						sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
-						if (instance->ld_ids[ld_index]
-						    != 0xff) {
-							if (!sdev1)
-								scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-						}
-						if (sdev1)
-							scsi_device_put(sdev1);
-					}
-				}
-				doscan = 0;
-			}
+				(instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+				dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+			if (dcmd_ret == DCMD_SUCCESS)
+				doscan = SCAN_VD_CHANNEL;
+
 			break;
+
 		case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
 		case MR_EVT_FOREIGN_CFG_IMPORTED:
 		case MR_EVT_LD_STATE_CHANGE:
-			doscan = 1;
+			dcmd_ret = megasas_get_pd_list(instance);
+
+			if (dcmd_ret != DCMD_SUCCESS)
+				break;
+
+			if (!instance->requestorId ||
+				(instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+				dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+			if (dcmd_ret != DCMD_SUCCESS)
+				break;
+
+			doscan = SCAN_VD_CHANNEL | SCAN_PD_CHANNEL;
+			dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
+				instance->host->host_no);
 			break;
+
 		case MR_EVT_CTRL_PROP_CHANGED:
-			megasas_get_ctrl_info(instance);
-			break;
+				dcmd_ret = megasas_get_ctrl_info(instance);
+				break;
 		default:
 			doscan = 0;
 			break;
 		}
 	} else {
 		dev_err(&instance->pdev->dev, "invalid evt_detail!\n");
+		mutex_unlock(&instance->reset_mutex);
 		kfree(ev);
 		return;
 	}
 
-	if (doscan) {
-		dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
-		       instance->host->host_no);
-		if (megasas_get_pd_list(instance) == 0) {
-			for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-				for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
-					pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
-					sdev1 = scsi_device_lookup(host, i, j, 0);
-					if (instance->pd_list[pd_index].driveState ==
-					    MR_PD_STATE_SYSTEM) {
-						if (!sdev1) {
-							scsi_add_device(host, i, j, 0);
-						}
-						if (sdev1)
-							scsi_device_put(sdev1);
-					} else {
-						if (sdev1) {
-							scsi_remove_device(sdev1);
-							scsi_device_put(sdev1);
-						}
+	mutex_unlock(&instance->reset_mutex);
+
+	if (doscan & SCAN_PD_CHANNEL) {
+		for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+				pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+				sdev1 = scsi_device_lookup(host, i, j, 0);
+				if (instance->pd_list[pd_index].driveState ==
+							MR_PD_STATE_SYSTEM) {
+					if (!sdev1)
+						scsi_add_device(host, i, j, 0);
+					else
+						scsi_device_put(sdev1);
+				} else {
+					if (sdev1) {
+						scsi_remove_device(sdev1);
+						scsi_device_put(sdev1);
 					}
 				}
 			}
 		}
+	}
 
-		if (!instance->requestorId ||
-		    megasas_get_ld_vf_affiliation(instance, 0)) {
-			if (megasas_ld_list_query(instance,
-						  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-				megasas_get_ld_list(instance);
-			for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-				for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
-				     j++) {
-					ld_index =
-						(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-					sdev1 = scsi_device_lookup(host,
-								   MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-					if (instance->ld_ids[ld_index]
-					    != 0xff) {
-						if (!sdev1)
-							scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-						else
-							scsi_device_put(sdev1);
-					} else {
-						if (sdev1) {
-							scsi_remove_device(sdev1);
-							scsi_device_put(sdev1);
-						}
+	if (doscan & SCAN_VD_CHANNEL) {
+		for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+				ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+				sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+				if (instance->ld_ids[ld_index] != 0xff) {
+					if (!sdev1)
+						scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+					else
+						scsi_device_put(sdev1);
+				} else {
+					if (sdev1) {
+						scsi_remove_device(sdev1);
+						scsi_device_put(sdev1);
 					}
 				}
 			}
 		}
 	}
 
-	if (instance->aen_cmd != NULL) {
-		kfree(ev);
-		return ;
-	}
-
-	seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+	if (dcmd_ret == DCMD_SUCCESS)
+		seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+	else
+		seq_num = instance->last_seq_num;
 
 	/* Register AEN with FW for latest sequence number plus 1 */
 	class_locale.members.reserved = 0;
 	class_locale.members.locale = MR_EVT_LOCALE_ALL;
 	class_locale.members.class = MR_EVT_CLASS_DEBUG;
-	mutex_lock(&instance->aen_mutex);
+
+	if (instance->aen_cmd != NULL) {
+		kfree(ev);
+		return;
+	}
+
+	mutex_lock(&instance->reset_mutex);
 	error = megasas_register_aen(instance, seq_num,
 					class_locale.word);
-	mutex_unlock(&instance->aen_mutex);
-
 	if (error)
-		dev_err(&instance->pdev->dev, "register aen failed error %x\n", error);
+		dev_err(&instance->pdev->dev,
+			"register aen failed error %x\n", error);
 
+	mutex_unlock(&instance->reset_mutex);
 	kfree(ev);
 }
 
--- linux-4.4.0.orig/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ linux-4.4.0/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -1020,6 +1020,8 @@
 	/* assume this IO needs the full row - we'll adjust if not true */
 	regSize             = stripSize;
 
+	io_info->do_fp_rlbypass = raid->capability.fpBypassRegionLock;
+
 	/* Check if we can send this I/O via FastPath */
 	if (raid->capability.fpCapable) {
 		if (isRead)
@@ -1273,7 +1275,7 @@
 
 	for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) {
 		ld = MR_TargetIdToLdGet(ldCount, drv_map);
-		if (ld >= MAX_LOGICAL_DRIVES_EXT) {
+		if (ld >= MAX_LOGICAL_DRIVES_EXT - 1) {
 			lbInfo[ldCount].loadBalanceFlag = 0;
 			continue;
 		}
--- linux-4.4.0.orig/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ linux-4.4.0/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -91,7 +91,10 @@
 			struct timer_list *timer,
 			 void *fn, unsigned long interval);
 extern struct megasas_mgmt_info megasas_mgmt_info;
-extern int resetwaittime;
+extern unsigned int resetwaittime;
+extern unsigned int dual_qdepth_disable;
+static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
+static void megasas_free_reply_fusion(struct megasas_instance *instance);
 
 
 
@@ -201,58 +204,72 @@
 		&instance->reg_set->inbound_low_queue_port);
 	writel(le32_to_cpu(req_desc->u.high),
 		&instance->reg_set->inbound_high_queue_port);
+	mmiowb();
 	spin_unlock_irqrestore(&instance->hba_lock, flags);
 #endif
 }
 
-
 /**
- * megasas_teardown_frame_pool_fusion -	Destroy the cmd frame DMA pool
- * @instance:				Adapter soft state
+ * megasas_fusion_update_can_queue -	Do all Adapter Queue depth related calculations here
+ * @instance:							Adapter soft state
+ * fw_boot_context:						Whether this function called during probe or after OCR
+ *
+ * This function is only for fusion controllers.
+ * Update host can queue, if firmware downgrade max supported firmware commands.
+ * Firmware upgrade case will be skiped because underlying firmware has
+ * more resource than exposed to the OS.
+ *
  */
-static void megasas_teardown_frame_pool_fusion(
-	struct megasas_instance *instance)
+static void
+megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_context)
 {
-	int i;
-	struct fusion_context *fusion = instance->ctrl_context;
+	u16 cur_max_fw_cmds = 0;
+	u16 ldio_threshold = 0;
+	struct megasas_register_set __iomem *reg_set;
 
-	u16 max_cmd = instance->max_fw_cmds;
+	reg_set = instance->reg_set;
 
-	struct megasas_cmd_fusion *cmd;
+	cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF;
 
-	if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
-		dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, "
-		       "sense pool : %p\n", fusion->sg_dma_pool,
-		       fusion->sense_dma_pool);
-		return;
-	}
+	if (dual_qdepth_disable || !cur_max_fw_cmds)
+		cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+	else
+		ldio_threshold =
+			(instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF) - MEGASAS_FUSION_IOCTL_CMDS;
 
-	/*
-	 * Return all frames to pool
-	 */
-	for (i = 0; i < max_cmd; i++) {
+	dev_info(&instance->pdev->dev,
+			"Current firmware maximum commands: %d\t LDIO threshold: %d\n",
+			cur_max_fw_cmds, ldio_threshold);
+
+	if (fw_boot_context == OCR_CONTEXT) {
+		cur_max_fw_cmds = cur_max_fw_cmds - 1;
+		if (cur_max_fw_cmds <= instance->max_fw_cmds) {
+			instance->cur_can_queue =
+				cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS +
+						MEGASAS_FUSION_IOCTL_CMDS);
+			instance->host->can_queue = instance->cur_can_queue;
+			instance->ldio_threshold = ldio_threshold;
+		}
+	} else {
+		instance->max_fw_cmds = cur_max_fw_cmds;
+		instance->ldio_threshold = ldio_threshold;
 
-		cmd = fusion->cmd_list[i];
+		if (!instance->is_rdpq)
+			instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
 
-		if (cmd->sg_frame)
-			pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
-				      cmd->sg_frame_phys_addr);
+		/*
+		* Reduce the max supported cmds by 1. This is to ensure that the
+		* reply_q_sz (1 more than the max cmd that driver may send)
+		* does not exceed max cmds that the FW can support
+		*/
+		instance->max_fw_cmds = instance->max_fw_cmds-1;
 
-		if (cmd->sense)
-			pci_pool_free(fusion->sense_dma_pool, cmd->sense,
-				      cmd->sense_phys_addr);
+		instance->max_scsi_cmds = instance->max_fw_cmds -
+				(MEGASAS_FUSION_INTERNAL_CMDS +
+				MEGASAS_FUSION_IOCTL_CMDS);
+		instance->cur_can_queue = instance->max_scsi_cmds;
 	}
-
-	/*
-	 * Now destroy the pool itself
-	 */
-	pci_pool_destroy(fusion->sg_dma_pool);
-	pci_pool_destroy(fusion->sense_dma_pool);
-
-	fusion->sg_dma_pool = NULL;
-	fusion->sense_dma_pool = NULL;
 }
-
 /**
  * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
  * @instance:		Adapter soft state
@@ -262,55 +279,65 @@
 {
 	int i;
 	struct fusion_context *fusion = instance->ctrl_context;
+	struct megasas_cmd_fusion *cmd;
 
-	u32 max_cmds, req_sz, reply_sz, io_frames_sz;
+	/* SG, Sense */
+	for (i = 0; i < instance->max_fw_cmds; i++) {
+		cmd = fusion->cmd_list[i];
+		if (cmd) {
+			if (cmd->sg_frame)
+				pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
+				      cmd->sg_frame_phys_addr);
+			if (cmd->sense)
+				pci_pool_free(fusion->sense_dma_pool, cmd->sense,
+				      cmd->sense_phys_addr);
+		}
+	}
 
+	if (fusion->sg_dma_pool) {
+		pci_pool_destroy(fusion->sg_dma_pool);
+		fusion->sg_dma_pool = NULL;
+	}
+	if (fusion->sense_dma_pool) {
+		pci_pool_destroy(fusion->sense_dma_pool);
+		fusion->sense_dma_pool = NULL;
+	}
 
-	req_sz = fusion->request_alloc_sz;
-	reply_sz = fusion->reply_alloc_sz;
-	io_frames_sz = fusion->io_frames_alloc_sz;
 
-	max_cmds = instance->max_fw_cmds;
+	/* Reply Frame, Desc*/
+	if (instance->is_rdpq)
+		megasas_free_rdpq_fusion(instance);
+	else
+		megasas_free_reply_fusion(instance);
 
-	/* Free descriptors and request Frames memory */
+	/* Request Frame, Desc*/
 	if (fusion->req_frames_desc)
-		dma_free_coherent(&instance->pdev->dev, req_sz,
-				  fusion->req_frames_desc,
-				  fusion->req_frames_desc_phys);
-
-	if (fusion->reply_frames_desc) {
-		pci_pool_free(fusion->reply_frames_desc_pool,
-			      fusion->reply_frames_desc,
-			      fusion->reply_frames_desc_phys);
-		pci_pool_destroy(fusion->reply_frames_desc_pool);
-	}
-
-	if (fusion->io_request_frames) {
+		dma_free_coherent(&instance->pdev->dev,
+			fusion->request_alloc_sz, fusion->req_frames_desc,
+			fusion->req_frames_desc_phys);
+	if (fusion->io_request_frames)
 		pci_pool_free(fusion->io_request_frames_pool,
-			      fusion->io_request_frames,
-			      fusion->io_request_frames_phys);
+			fusion->io_request_frames,
+			fusion->io_request_frames_phys);
+	if (fusion->io_request_frames_pool) {
 		pci_pool_destroy(fusion->io_request_frames_pool);
+		fusion->io_request_frames_pool = NULL;
 	}
 
-	/* Free the Fusion frame pool */
-	megasas_teardown_frame_pool_fusion(instance);
 
-	/* Free all the commands in the cmd_list */
-	for (i = 0; i < max_cmds; i++)
+	/* cmd_list */
+	for (i = 0; i < instance->max_fw_cmds; i++)
 		kfree(fusion->cmd_list[i]);
 
-	/* Free the cmd_list buffer itself */
 	kfree(fusion->cmd_list);
-	fusion->cmd_list = NULL;
-
 }
 
 /**
- * megasas_create_frame_pool_fusion -	Creates DMA pool for cmd frames
+ * megasas_create_sg_sense_fusion -	Creates DMA pool for cmd frames
  * @instance:			Adapter soft state
  *
  */
-static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
+static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
 {
 	int i;
 	u32 max_cmd;
@@ -321,25 +348,17 @@
 	max_cmd = instance->max_fw_cmds;
 
 
-	/*
-	 * Use DMA pool facility provided by PCI layer
-	 */
+	fusion->sg_dma_pool =
+			pci_pool_create("mr_sg", instance->pdev,
+				instance->max_chain_frame_sz, 4, 0);
+	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
+	fusion->sense_dma_pool =
+			pci_pool_create("mr_sense", instance->pdev,
+				SCSI_SENSE_BUFFERSIZE, 64, 0);
 
-	fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev,
-						instance->max_chain_frame_sz,
-						4, 0);
-	if (!fusion->sg_dma_pool) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
-		return -ENOMEM;
-	}
-	fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
-						 instance->pdev,
-						 SCSI_SENSE_BUFFERSIZE, 64, 0);
-
-	if (!fusion->sense_dma_pool) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n");
-		pci_pool_destroy(fusion->sg_dma_pool);
-		fusion->sg_dma_pool = NULL;
+	if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
 		return -ENOMEM;
 	}
 
@@ -347,160 +366,280 @@
 	 * Allocate and attach a frame to each of the commands in cmd_list
 	 */
 	for (i = 0; i < max_cmd; i++) {
-
 		cmd = fusion->cmd_list[i];
-
 		cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
-					       GFP_KERNEL,
-					       &cmd->sg_frame_phys_addr);
+					GFP_KERNEL, &cmd->sg_frame_phys_addr);
 
 		cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
-					    GFP_KERNEL, &cmd->sense_phys_addr);
-		/*
-		 * megasas_teardown_frame_pool_fusion() takes care of freeing
-		 * whatever has been allocated
-		 */
+					GFP_KERNEL, &cmd->sense_phys_addr);
 		if (!cmd->sg_frame || !cmd->sense) {
-			dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n");
-			megasas_teardown_frame_pool_fusion(instance);
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
 			return -ENOMEM;
 		}
 	}
 	return 0;
 }
 
-/**
- * megasas_alloc_cmds_fusion -	Allocates the command packets
- * @instance:		Adapter soft state
- *
- *
- * Each frame has a 32-bit field called context. This context is used to get
- * back the megasas_cmd_fusion from the frame when a frame gets completed
- * In this driver, the 32 bit values are the indices into an array cmd_list.
- * This array is used only to look up the megasas_cmd_fusion given the context.
- * The free commands themselves are maintained in a linked list called cmd_pool.
- *
- * cmds are formed in the io_request and sg_frame members of the
- * megasas_cmd_fusion. The context field is used to get a request descriptor
- * and is used as SMID of the cmd.
- * SMID value range is from 1 to max_fw_cmds.
- */
 int
-megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
 {
-	int i, j, count;
-	u32 max_cmd, io_frames_sz;
+	u32 max_cmd, i;
 	struct fusion_context *fusion;
-	struct megasas_cmd_fusion *cmd;
-	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
-	u32 offset;
-	dma_addr_t io_req_base_phys;
-	u8 *io_req_base;
 
 	fusion = instance->ctrl_context;
 
 	max_cmd = instance->max_fw_cmds;
 
+	/*
+	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
+	 * Allocate the dynamic array first and then allocate individual
+	 * commands.
+	 */
+	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
+						GFP_KERNEL);
+	if (!fusion->cmd_list) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < max_cmd; i++) {
+		fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
+					      GFP_KERNEL);
+		if (!fusion->cmd_list[i]) {
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+int
+megasas_alloc_request_fusion(struct megasas_instance *instance)
+{
+	struct fusion_context *fusion;
+
+	fusion = instance->ctrl_context;
+
 	fusion->req_frames_desc =
 		dma_alloc_coherent(&instance->pdev->dev,
-				   fusion->request_alloc_sz,
-				   &fusion->req_frames_desc_phys, GFP_KERNEL);
-
+			fusion->request_alloc_sz,
+			&fusion->req_frames_desc_phys, GFP_KERNEL);
 	if (!fusion->req_frames_desc) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "request_frames\n");
-		goto fail_req_desc;
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
+	fusion->io_request_frames_pool =
+			pci_pool_create("mr_ioreq", instance->pdev,
+				fusion->io_frames_alloc_sz, 16, 0);
+
+	if (!fusion->io_request_frames_pool) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	fusion->io_request_frames =
+			pci_pool_alloc(fusion->io_request_frames_pool,
+				GFP_KERNEL, &fusion->io_request_frames_phys);
+	if (!fusion->io_request_frames) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+int
+megasas_alloc_reply_fusion(struct megasas_instance *instance)
+{
+	int i, count;
+	struct fusion_context *fusion;
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+	fusion = instance->ctrl_context;
+
 	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
 	fusion->reply_frames_desc_pool =
-		pci_pool_create("reply_frames pool", instance->pdev,
+			pci_pool_create("mr_reply", instance->pdev,
 				fusion->reply_alloc_sz * count, 16, 0);
 
 	if (!fusion->reply_frames_desc_pool) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "reply_frame pool\n");
-		goto fail_reply_desc;
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	fusion->reply_frames_desc =
-		pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
-			       &fusion->reply_frames_desc_phys);
-	if (!fusion->reply_frames_desc) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "reply_frame pool\n");
-		pci_pool_destroy(fusion->reply_frames_desc_pool);
-		goto fail_reply_desc;
+	fusion->reply_frames_desc[0] =
+		pci_pool_alloc(fusion->reply_frames_desc_pool,
+			GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
+	if (!fusion->reply_frames_desc[0]) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
-
-	reply_desc = fusion->reply_frames_desc;
+	reply_desc = fusion->reply_frames_desc[0];
 	for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
 		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
 
-	io_frames_sz = fusion->io_frames_alloc_sz;
+	/* This is not a rdpq mode, but driver still populate
+	 * reply_frame_desc array to use same msix index in ISR path.
+	 */
+	for (i = 0; i < (count - 1); i++)
+		fusion->reply_frames_desc[i + 1] =
+			fusion->reply_frames_desc[i] +
+			(fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
 
-	fusion->io_request_frames_pool =
-		pci_pool_create("io_request_frames pool", instance->pdev,
-				fusion->io_frames_alloc_sz, 16, 0);
+	return 0;
+}
 
-	if (!fusion->io_request_frames_pool) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "io_request_frame pool\n");
-		goto fail_io_frames;
+int
+megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
+{
+	int i, j, count;
+	struct fusion_context *fusion;
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+
+	fusion = instance->ctrl_context;
+
+	fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
+				sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+				&fusion->rdpq_phys);
+	if (!fusion->rdpq_virt) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	fusion->io_request_frames =
-		pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
-			       &fusion->io_request_frames_phys);
-	if (!fusion->io_request_frames) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "io_request_frames frames\n");
-		pci_pool_destroy(fusion->io_request_frames_pool);
-		goto fail_io_frames;
+	memset(fusion->rdpq_virt, 0,
+			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION);
+	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+	fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
+							 instance->pdev, fusion->reply_alloc_sz, 16, 0);
+
+	if (!fusion->reply_frames_desc_pool) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	/*
-	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
-	 * Allocate the dynamic array first and then allocate individual
-	 * commands.
-	 */
-	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
-				   * max_cmd, GFP_KERNEL);
+	for (i = 0; i < count; i++) {
+		fusion->reply_frames_desc[i] =
+				pci_pool_alloc(fusion->reply_frames_desc_pool,
+					GFP_KERNEL, &fusion->reply_frames_desc_phys[i]);
+		if (!fusion->reply_frames_desc[i]) {
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
+			return -ENOMEM;
+		}
 
-	if (!fusion->cmd_list) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc "
-		       "memory for cmd_list_fusion\n");
-		goto fail_cmd_list;
+		fusion->rdpq_virt[i].RDPQBaseAddress =
+			fusion->reply_frames_desc_phys[i];
+
+		reply_desc = fusion->reply_frames_desc[i];
+		for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
+			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
 	}
+	return 0;
+}
 
-	max_cmd = instance->max_fw_cmds;
-	for (i = 0; i < max_cmd; i++) {
-		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
-					      GFP_KERNEL);
-		if (!fusion->cmd_list[i]) {
-			dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n");
+static void
+megasas_free_rdpq_fusion(struct megasas_instance *instance) {
 
-			for (j = 0; j < i; j++)
-				kfree(fusion->cmd_list[j]);
+	int i;
+	struct fusion_context *fusion;
 
-			kfree(fusion->cmd_list);
-			fusion->cmd_list = NULL;
-			goto fail_cmd_list;
-		}
+	fusion = instance->ctrl_context;
+
+	for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
+		if (fusion->reply_frames_desc[i])
+			pci_pool_free(fusion->reply_frames_desc_pool,
+				fusion->reply_frames_desc[i],
+				fusion->reply_frames_desc_phys[i]);
 	}
 
-	/* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
-	io_req_base = fusion->io_request_frames +
-		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
-	io_req_base_phys = fusion->io_request_frames_phys +
-		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+	if (fusion->reply_frames_desc_pool)
+		pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+	if (fusion->rdpq_virt)
+		pci_free_consistent(instance->pdev,
+			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+			fusion->rdpq_virt, fusion->rdpq_phys);
+}
+
+static void
+megasas_free_reply_fusion(struct megasas_instance *instance) {
+
+	struct fusion_context *fusion;
+
+	fusion = instance->ctrl_context;
+
+	if (fusion->reply_frames_desc[0])
+		pci_pool_free(fusion->reply_frames_desc_pool,
+			fusion->reply_frames_desc[0],
+			fusion->reply_frames_desc_phys[0]);
+
+	if (fusion->reply_frames_desc_pool)
+		pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+}
+
+
+/**
+ * megasas_alloc_cmds_fusion -	Allocates the command packets
+ * @instance:		Adapter soft state
+ *
+ *
+ * Each frame has a 32-bit field called context. This context is used to get
+ * back the megasas_cmd_fusion from the frame when a frame gets completed
+ * In this driver, the 32 bit values are the indices into an array cmd_list.
+ * This array is used only to look up the megasas_cmd_fusion given the context.
+ * The free commands themselves are maintained in a linked list called cmd_pool.
+ *
+ * cmds are formed in the io_request and sg_frame members of the
+ * megasas_cmd_fusion. The context field is used to get a request descriptor
+ * and is used as SMID of the cmd.
+ * SMID value range is from 1 to max_fw_cmds.
+ */
+int
+megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+{
+	int i;
+	struct fusion_context *fusion;
+	struct megasas_cmd_fusion *cmd;
+	u32 offset;
+	dma_addr_t io_req_base_phys;
+	u8 *io_req_base;
+
+
+	fusion = instance->ctrl_context;
+
+	if (megasas_alloc_cmdlist_fusion(instance))
+		goto fail_exit;
+
+	if (megasas_alloc_request_fusion(instance))
+		goto fail_exit;
+
+	if (instance->is_rdpq) {
+		if (megasas_alloc_rdpq_fusion(instance))
+			goto fail_exit;
+	} else
+		if (megasas_alloc_reply_fusion(instance))
+			goto fail_exit;
+
+
+	/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
+	io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+	io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
 
 	/*
 	 * Add all the commands to command pool (fusion->cmd_pool)
 	 */
 
 	/* SMID 0 is reserved. Set SMID/index from 1 */
-	for (i = 0; i < max_cmd; i++) {
+	for (i = 0; i < instance->max_fw_cmds; i++) {
 		cmd = fusion->cmd_list[i];
 		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
 		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
@@ -518,35 +657,13 @@
 		cmd->io_request_phys_addr = io_req_base_phys + offset;
 	}
 
-	/*
-	 * Create a frame pool and assign one frame to each cmd
-	 */
-	if (megasas_create_frame_pool_fusion(instance)) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
-		megasas_free_cmds_fusion(instance);
-		goto fail_req_desc;
-	}
+	if (megasas_create_sg_sense_fusion(instance))
+		goto fail_exit;
 
 	return 0;
 
-fail_cmd_list:
-	pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
-		      fusion->io_request_frames_phys);
-	pci_pool_destroy(fusion->io_request_frames_pool);
-fail_io_frames:
-	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
-			  fusion->reply_frames_desc,
-			  fusion->reply_frames_desc_phys);
-	pci_pool_free(fusion->reply_frames_desc_pool,
-		      fusion->reply_frames_desc,
-		      fusion->reply_frames_desc_phys);
-	pci_pool_destroy(fusion->reply_frames_desc_pool);
-
-fail_reply_desc:
-	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
-			  fusion->req_frames_desc,
-			  fusion->req_frames_desc_phys);
-fail_req_desc:
+fail_exit:
+	megasas_free_cmds_fusion(instance);
 	return -ENOMEM;
 }
 
@@ -576,11 +693,12 @@
 		msleep(20);
 	}
 
-	if (frame_hdr->cmd_status == 0xff)
-		return -ETIME;
-
-	return (frame_hdr->cmd_status == MFI_STAT_OK) ?
-		0 : 1;
+	if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
+		return DCMD_TIMEOUT;
+	else if (frame_hdr->cmd_status == MFI_STAT_OK)
+		return DCMD_SUCCESS;
+	else
+		return DCMD_FAILED;
 }
 
 /**
@@ -593,16 +711,17 @@
 megasas_ioc_init_fusion(struct megasas_instance *instance)
 {
 	struct megasas_init_frame *init_frame;
-	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
+	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
 	dma_addr_t	ioc_init_handle;
 	struct megasas_cmd *cmd;
-	u8 ret;
+	u8 ret, cur_rdpq_mode;
 	struct fusion_context *fusion;
 	union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
 	int i;
 	struct megasas_header *frame_hdr;
 	const char *sys_info;
 	MFI_CAPABILITIES *drv_ops;
+	u32 scratch_pad_2;
 
 	fusion = instance->ctrl_context;
 
@@ -614,6 +733,18 @@
 		goto fail_get_cmd;
 	}
 
+	scratch_pad_2 = readl
+		(&instance->reg_set->outbound_scratch_pad_2);
+
+	cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
+
+	if (instance->is_rdpq && !cur_rdpq_mode) {
+		dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
+			" from RDPQ mode to non RDPQ mode\n");
+		ret = 1;
+		goto fail_fw_init;
+	}
+
 	IOCInitMessage =
 	  dma_alloc_coherent(&instance->pdev->dev,
 			     sizeof(struct MPI2_IOC_INIT_REQUEST),
@@ -635,7 +766,11 @@
 	IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
 
 	IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
-	IOCInitMessage->ReplyDescriptorPostQueueAddress	= cpu_to_le64(fusion->reply_frames_desc_phys);
+	IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
+			cpu_to_le64(fusion->rdpq_phys) :
+			cpu_to_le64(fusion->reply_frames_desc_phys[0]);
+	IOCInitMessage->MsgFlags = instance->is_rdpq ?
+			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
 	IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
 	IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
 	init_frame = (struct megasas_init_frame *)cmd->frame;
@@ -665,6 +800,11 @@
 	if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN)
 		drv_ops->mfi_capabilities.support_ext_io_size = 1;
 
+	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
+	if (!dual_qdepth_disable)
+		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
+
+	drv_ops->mfi_capabilities.support_qd_throttling = 1;
 	/* Convert capability to LE32 */
 	cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
 
@@ -784,7 +924,8 @@
 
 	/* Below code is only for non pended DCMD */
 	if (instance->ctrl_context && !instance->mask_interrupts)
-		ret = megasas_issue_blocked_cmd(instance, cmd, 60);
+		ret = megasas_issue_blocked_cmd(instance, cmd,
+			MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
@@ -795,7 +936,10 @@
 		ret = -EINVAL;
 	}
 
-	if (!ret)
+	if (ret == DCMD_TIMEOUT && instance->ctrl_context)
+		megaraid_sas_kill_hba(instance);
+
+	if (ret == DCMD_SUCCESS)
 		instance->pd_seq_map_id++;
 
 	megasas_return_cmd(instance, cmd);
@@ -875,10 +1019,13 @@
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
 		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+			MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
+	if (ret == DCMD_TIMEOUT && instance->ctrl_context)
+		megaraid_sas_kill_hba(instance);
+
 	megasas_return_cmd(instance, cmd);
 
 	return ret;
@@ -1072,12 +1219,7 @@
 
 	reg_set = instance->reg_set;
 
-	/*
-	 * Get various operational parameters from status register
-	 */
-	instance->max_fw_cmds =
-		instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
-	instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
+	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
 
 	/*
 	 * Reduce the max supported cmds by 1. This is to ensure that the
@@ -1658,7 +1800,7 @@
 				   local_map_ptr, start_lba_lo);
 		io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
 		cmd->request_desc->SCSIIO.RequestFlags =
-			(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
+			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO
 			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 		if (fusion->adapter_type == INVADER_SERIES) {
 			if (io_request->RaidContext.regLockFlags ==
@@ -1702,8 +1844,8 @@
 			(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
 			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 		if (fusion->adapter_type == INVADER_SERIES) {
-			if (io_request->RaidContext.regLockFlags ==
-			    REGION_TYPE_UNUSED)
+			if (io_info.do_fp_rlbypass ||
+				(io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED))
 				cmd->request_desc->SCSIIO.RequestFlags =
 					(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
 					MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
@@ -1757,7 +1899,7 @@
 		device_id < instance->fw_supported_vd_count)) {
 
 		ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
-		if (ld >= instance->fw_supported_vd_count)
+		if (ld >= instance->fw_supported_vd_count - 1)
 			fp_possible = 0;
 
 		raid = MR_LdRaidGet(ld, local_map_ptr);
@@ -1791,7 +1933,7 @@
 
 		/* build request descriptor */
 		cmd->request_desc->SCSIIO.RequestFlags =
-			(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
 			MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 		cmd->request_desc->SCSIIO.DevHandle = devHandle;
 
@@ -1855,6 +1997,8 @@
 		io_request->DevHandle = pd_sync->seq[pd_index].devHandle;
 		pRAID_Context->regLockFlags |=
 			(MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+		pRAID_Context->Type = MPI2_TYPE_CUDA;
+		pRAID_Context->nseg = 0x1;
 	} else if (fusion->fast_path_io) {
 		pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
 		pRAID_Context->configSeqNum = 0;
@@ -1883,6 +2027,9 @@
 		pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value);
 		pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
 	} else {
+		if (os_timeout_value)
+			os_timeout_value++;
+
 		/* system pd Fast Path */
 		io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
 		timeout_limit = (scmd->device->type == TYPE_DISK) ?
@@ -1890,14 +2037,12 @@
 		pRAID_Context->timeoutValue =
 			cpu_to_le16((os_timeout_value > timeout_limit) ?
 			timeout_limit : os_timeout_value);
-		if (fusion->adapter_type == INVADER_SERIES) {
-			pRAID_Context->Type = MPI2_TYPE_CUDA;
-			pRAID_Context->nseg = 0x1;
+		if (fusion->adapter_type == INVADER_SERIES)
 			io_request->IoFlags |=
 				cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
-		}
+
 		cmd->request_desc->SCSIIO.RequestFlags =
-			(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
 				MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 	}
 }
@@ -2035,13 +2180,21 @@
 
 	fusion = instance->ctrl_context;
 
+	if ((megasas_cmd_type(scmd) == READ_WRITE_LDIO) &&
+		instance->ldio_threshold &&
+		(atomic_inc_return(&instance->ldio_outstanding) >
+		instance->ldio_threshold)) {
+		atomic_dec(&instance->ldio_outstanding);
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+	}
+
 	cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
 
 	index = cmd->index;
 
 	req_desc = megasas_get_request_descriptor(instance, index-1);
 	if (!req_desc)
-		return 1;
+		return SCSI_MLQUEUE_HOST_BUSY;
 
 	req_desc->Words = 0;
 	cmd->request_desc = req_desc;
@@ -2050,7 +2203,7 @@
 		megasas_return_cmd_fusion(instance, cmd);
 		dev_err(&instance->pdev->dev, "Error building command\n");
 		cmd->request_desc = NULL;
-		return 1;
+		return SCSI_MLQUEUE_HOST_BUSY;
 	}
 
 	req_desc = cmd->request_desc;
@@ -2092,16 +2245,16 @@
 	struct LD_LOAD_BALANCE_INFO *lbinfo;
 	int threshold_reply_count = 0;
 	struct scsi_cmnd *scmd_local = NULL;
+	struct MR_TASK_MANAGE_REQUEST *mr_tm_req;
+	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req;
 
 	fusion = instance->ctrl_context;
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return IRQ_HANDLED;
 
-	desc = fusion->reply_frames_desc;
-	desc += ((MSIxIndex * fusion->reply_alloc_sz)/
-		 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
-		fusion->last_reply_idx[MSIxIndex];
+	desc = fusion->reply_frames_desc[MSIxIndex] +
+				fusion->last_reply_idx[MSIxIndex];
 
 	reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
 
@@ -2133,6 +2286,16 @@
 		extStatus = scsi_io_req->RaidContext.exStatus;
 
 		switch (scsi_io_req->Function) {
+		case MPI2_FUNCTION_SCSI_TASK_MGMT:
+			mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *)
+						cmd_fusion->io_request;
+			mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *)
+						&mr_tm_req->TmRequest;
+			dev_dbg(&instance->pdev->dev, "TM completion:"
+				"type: 0x%x TaskMID: 0x%x\n",
+				mpi_tm_req->TaskType, mpi_tm_req->TaskMID);
+			complete(&cmd_fusion->done);
+			break;
 		case MPI2_FUNCTION_SCSI_IO_REQUEST:  /*Fast Path IO.*/
 			/* Update load balancing info */
 			device_id = MEGASAS_DEV_INDEX(scmd_local);
@@ -2155,6 +2318,8 @@
 			map_cmd_status(cmd_fusion, status, extStatus);
 			scsi_io_req->RaidContext.status = 0;
 			scsi_io_req->RaidContext.exStatus = 0;
+			if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+				atomic_dec(&instance->ldio_outstanding);
 			megasas_return_cmd_fusion(instance, cmd_fusion);
 			scsi_dma_unmap(scmd_local);
 			scmd_local->scsi_done(scmd_local);
@@ -2186,9 +2351,7 @@
 
 		/* Get the next reply descriptor */
 		if (!fusion->last_reply_idx[MSIxIndex])
-			desc = fusion->reply_frames_desc +
-				((MSIxIndex * fusion->reply_alloc_sz)/
-				 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
+			desc = fusion->reply_frames_desc[MSIxIndex];
 		else
 			desc++;
 
@@ -2254,7 +2417,7 @@
 
 	/* If we have already declared adapter dead, donot complete cmds */
 	spin_lock_irqsave(&instance->hba_lock, flags);
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		return;
 	}
@@ -2411,7 +2574,7 @@
  * @cmd:			mfi cmd pointer
  *
  */
-void
+int
 megasas_issue_dcmd_fusion(struct megasas_instance *instance,
 			  struct megasas_cmd *cmd)
 {
@@ -2419,10 +2582,13 @@
 
 	req_desc = build_mpt_cmd(instance, cmd);
 	if (!req_desc) {
-		dev_err(&instance->pdev->dev, "Couldn't issue MFI pass thru cmd\n");
-		return;
+		dev_info(&instance->pdev->dev, "Failed from %s %d\n",
+					__func__, __LINE__);
+		return DCMD_NOT_FIRED;
 	}
+
 	megasas_fire_cmd_fusion(instance, req_desc);
+	return DCMD_SUCCESS;
 }
 
 /**
@@ -2437,7 +2603,7 @@
 
 	iounmap(instance->reg_set);
 
-	pci_release_selected_regions(instance->pdev, instance->bar);
+	pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 }
 
 /**
@@ -2583,7 +2749,7 @@
 
 /* This function waits for outstanding commands on fusion to complete */
 int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
-					int iotimeout, int *convert)
+					int reason, int *convert)
 {
 	int i, outstanding, retval = 0, hb_seconds_missed = 0;
 	u32 fw_state;
@@ -2599,14 +2765,22 @@
 			retval = 1;
 			goto out;
 		}
+
+		if (reason == MFI_IO_TIMEOUT_OCR) {
+			dev_info(&instance->pdev->dev,
+				"MFI IO is timed out, initiating OCR\n");
+			retval = 1;
+			goto out;
+		}
+
 		/* If SR-IOV VF mode & heartbeat timeout, don't wait */
-		if (instance->requestorId && !iotimeout) {
+		if (instance->requestorId && !reason) {
 			retval = 1;
 			goto out;
 		}
 
 		/* If SR-IOV VF mode & I/O timeout, check for HB timeout */
-		if (instance->requestorId && iotimeout) {
+		if (instance->requestorId && reason) {
 			if (instance->hb_host_mem->HB.fwCounter !=
 			    instance->hb_host_mem->HB.driverCounter) {
 				instance->hb_host_mem->HB.driverCounter =
@@ -2647,6 +2821,7 @@
 		dev_err(&instance->pdev->dev, "pending commands remain after waiting, "
 		       "will reset adapter scsi%d.\n",
 		       instance->host->host_no);
+		*convert = 1;
 		retval = 1;
 	}
 out:
@@ -2655,17 +2830,18 @@
 
 void  megasas_reset_reply_desc(struct megasas_instance *instance)
 {
-	int i, count;
+	int i, j, count;
 	struct fusion_context *fusion;
 	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
 
 	fusion = instance->ctrl_context;
 	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
-	for (i = 0 ; i < count ; i++)
+	for (i = 0 ; i < count ; i++) {
 		fusion->last_reply_idx[i] = 0;
-	reply_desc = fusion->reply_frames_desc;
-	for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++)
-		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+		reply_desc = fusion->reply_frames_desc[i];
+		for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
+			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+	}
 }
 
 /*
@@ -2680,6 +2856,7 @@
 	struct megasas_cmd *cmd_mfi;
 	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
 	u16 smid;
+	bool refire_cmd = 0;
 
 	fusion = instance->ctrl_context;
 
@@ -2695,42 +2872,500 @@
 			continue;
 		req_desc = megasas_get_request_descriptor
 					(instance, smid - 1);
-		if (req_desc && ((cmd_mfi->frame->dcmd.opcode !=
+		refire_cmd = req_desc && ((cmd_mfi->frame->dcmd.opcode !=
 				cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) &&
 				 (cmd_mfi->frame->dcmd.opcode !=
-				cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO))))
+				cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO)))
+				&& !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE);
+		if (refire_cmd)
 			megasas_fire_cmd_fusion(instance, req_desc);
 		else
 			megasas_return_cmd(instance, cmd_mfi);
 	}
 }
 
+/*
+ * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
+ * @instance: per adapter struct
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
+ *
+ * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED
+ */
+
+static int megasas_track_scsiio(struct megasas_instance *instance,
+		int id, int channel)
+{
+	int i, found = 0;
+	struct megasas_cmd_fusion *cmd_fusion;
+	struct fusion_context *fusion;
+	fusion = instance->ctrl_context;
+
+	for (i = 0 ; i < instance->max_scsi_cmds; i++) {
+		cmd_fusion = fusion->cmd_list[i];
+		if (cmd_fusion->scmd &&
+			(cmd_fusion->scmd->device->id == id &&
+			cmd_fusion->scmd->device->channel == channel)) {
+			dev_info(&instance->pdev->dev,
+				"SCSI commands pending to target"
+				"channel %d id %d \tSMID: 0x%x\n",
+				channel, id, cmd_fusion->index);
+			scsi_print_command(cmd_fusion->scmd);
+			found = 1;
+			break;
+		}
+	}
+
+	return found ? FAILED : SUCCESS;
+}
+
+/**
+ * megasas_tm_response_code - translation of device response code
+ * @ioc: per adapter object
+ * @mpi_reply: MPI reply returned by firmware
+ *
+ * Return nothing.
+ */
+static void
+megasas_tm_response_code(struct megasas_instance *instance,
+		struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply)
+{
+	char *desc;
+
+	switch (mpi_reply->ResponseCode) {
+	case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
+		desc = "task management request completed";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
+		desc = "invalid frame";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+		desc = "task management request not supported";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
+		desc = "task management request failed";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+		desc = "task management request succeeded";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+		desc = "invalid lun";
+		break;
+	case 0xA:
+		desc = "overlapped tag attempted";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+		desc = "task queued, however not sent to target";
+		break;
+	default:
+		desc = "unknown";
+		break;
+	}
+	dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n",
+		mpi_reply->ResponseCode, desc);
+	dev_dbg(&instance->pdev->dev,
+		"TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo"
+		" 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
+		mpi_reply->TerminationCount, mpi_reply->DevHandle,
+		mpi_reply->Function, mpi_reply->TaskType,
+		mpi_reply->IOCStatus, mpi_reply->IOCLogInfo);
+}
+
+/**
+ * megasas_issue_tm - main routine for sending tm requests
+ * @instance: per adapter struct
+ * @device_handle: device handle
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
+ * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c)
+ * @smid_task: smid assigned to the task
+ * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
+ * Context: user
+ *
+ * MegaRaid use MPT interface for Task Magement request.
+ * A generic API for sending task management requests to firmware.
+ *
+ * Return SUCCESS or FAILED.
+ */
+static int
+megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
+	uint channel, uint id, u16 smid_task, u8 type)
+{
+	struct MR_TASK_MANAGE_REQUEST *mr_request;
+	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request;
+	unsigned long timeleft;
+	struct megasas_cmd_fusion *cmd_fusion;
+	struct megasas_cmd *cmd_mfi;
+	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+	struct fusion_context *fusion;
+	struct megasas_cmd_fusion *scsi_lookup;
+	int rc;
+	struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply;
+
+	fusion = instance->ctrl_context;
+
+	cmd_mfi = megasas_get_cmd(instance);
+
+	if (!cmd_mfi) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	cmd_fusion = megasas_get_cmd_fusion(instance,
+			instance->max_scsi_cmds + cmd_mfi->index);
+
+	/*  Save the smid. To be used for returning the cmd */
+	cmd_mfi->context.smid = cmd_fusion->index;
+
+	req_desc = megasas_get_request_descriptor(instance,
+			(cmd_fusion->index - 1));
+	if (!req_desc) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		megasas_return_cmd(instance, cmd_mfi);
+		return -ENOMEM;
+	}
+
+	cmd_fusion->request_desc = req_desc;
+	req_desc->Words = 0;
+
+	scsi_lookup = fusion->cmd_list[smid_task - 1];
+
+	mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request;
+	memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST));
+	mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest;
+	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+	mpi_request->DevHandle = cpu_to_le16(device_handle);
+	mpi_request->TaskType = type;
+	mpi_request->TaskMID = cpu_to_le16(smid_task);
+	mpi_request->LUN[1] = 0;
+
+
+	req_desc = cmd_fusion->request_desc;
+	req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index);
+	req_desc->HighPriority.RequestFlags =
+		(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+		MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+	req_desc->HighPriority.MSIxIndex =  0;
+	req_desc->HighPriority.LMID = 0;
+	req_desc->HighPriority.Reserved1 = 0;
+
+	if (channel < MEGASAS_MAX_PD_CHANNELS)
+		mr_request->tmReqFlags.isTMForPD = 1;
+	else
+		mr_request->tmReqFlags.isTMForLD = 1;
+
+	init_completion(&cmd_fusion->done);
+	megasas_fire_cmd_fusion(instance, req_desc);
+
+	timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ);
+
+	if (!timeleft) {
+		dev_err(&instance->pdev->dev,
+			"task mgmt type 0x%x timed out\n", type);
+		cmd_mfi->flags |= DRV_DCMD_SKIP_REFIRE;
+		mutex_unlock(&instance->reset_mutex);
+		rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR);
+		mutex_lock(&instance->reset_mutex);
+		return rc;
+	}
+
+	mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply;
+	megasas_tm_response_code(instance, mpi_reply);
+
+	megasas_return_cmd(instance, cmd_mfi);
+	rc = SUCCESS;
+	switch (type) {
+	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+		if (scsi_lookup->scmd == NULL)
+			break;
+		else {
+			instance->instancet->disable_intr(instance);
+			msleep(1000);
+			megasas_complete_cmd_dpc_fusion
+					((unsigned long)instance);
+			instance->instancet->enable_intr(instance);
+			if (scsi_lookup->scmd == NULL)
+				break;
+		}
+		rc = FAILED;
+		break;
+
+	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+		if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF))
+			break;
+		instance->instancet->disable_intr(instance);
+		msleep(1000);
+		megasas_complete_cmd_dpc_fusion
+				((unsigned long)instance);
+		rc = megasas_track_scsiio(instance, id, channel);
+		instance->instancet->enable_intr(instance);
+
+		break;
+	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+	case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
+		break;
+	default:
+		rc = FAILED;
+		break;
+	}
+
+	return rc;
+
+}
+
+/*
+ * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI
+ * @instance: per adapter struct
+ *
+ * Return Non Zero index, if SMID found in outstanding commands
+ */
+static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd)
+{
+	int i, ret = 0;
+	struct megasas_instance *instance;
+	struct megasas_cmd_fusion *cmd_fusion;
+	struct fusion_context *fusion;
+
+	instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+	fusion = instance->ctrl_context;
+
+	for (i = 0; i < instance->max_scsi_cmds; i++) {
+		cmd_fusion = fusion->cmd_list[i];
+		if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) {
+			scmd_printk(KERN_NOTICE, scmd, "Abort request is for"
+				" SMID: %d\n", cmd_fusion->index);
+			ret = cmd_fusion->index;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+* megasas_get_tm_devhandle - Get devhandle for TM request
+* @sdev-		     OS provided scsi device
+*
+* Returns-		     devhandle/targetID of SCSI device
+*/
+static u16 megasas_get_tm_devhandle(struct scsi_device *sdev)
+{
+	u16 pd_index = 0;
+	u32 device_id;
+	struct megasas_instance *instance;
+	struct fusion_context *fusion;
+	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
+	u16 devhandle = (u16)ULONG_MAX;
+
+	instance = (struct megasas_instance *)sdev->host->hostdata;
+	fusion = instance->ctrl_context;
+
+	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+		if (instance->use_seqnum_jbod_fp) {
+				pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+						sdev->id;
+				pd_sync = (void *)fusion->pd_seq_sync
+						[(instance->pd_seq_map_id - 1) & 1];
+				devhandle = pd_sync->seq[pd_index].devHandle;
+		} else
+			sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable"
+				" without JBOD MAP support from %s %d\n", __func__, __LINE__);
+	} else {
+		device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
+				+ sdev->id;
+		devhandle = device_id;
+	}
+
+	return devhandle;
+}
+
+/*
+ * megasas_task_abort_fusion : SCSI task abort function for fusion adapters
+ * @scmd : pointer to scsi command object
+ *
+ * Return SUCCESS, if command aborted else FAILED
+ */
+
+int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
+{
+	struct megasas_instance *instance;
+	u16 smid, devhandle;
+	struct fusion_context *fusion;
+	int ret;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
+	mr_device_priv_data = scmd->device->hostdata;
+
+
+	instance = (struct megasas_instance *)scmd->device->host->hostdata;
+	fusion = instance->ctrl_context;
+
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
+		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
+		"SCSI host:%d\n", instance->host->host_no);
+		ret = FAILED;
+		return ret;
+	}
+
+	if (!mr_device_priv_data) {
+		sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+			"scmd(%p)\n", scmd);
+		scmd->result = DID_NO_CONNECT << 16;
+		ret = SUCCESS;
+		goto out;
+	}
+
+
+	if (!mr_device_priv_data->is_tm_capable) {
+		ret = FAILED;
+		goto out;
+	}
+
+	mutex_lock(&instance->reset_mutex);
+
+	smid = megasas_fusion_smid_lookup(scmd);
+
+	if (!smid) {
+		ret = SUCCESS;
+		scmd_printk(KERN_NOTICE, scmd, "Command for which abort is"
+			" issued is not found in oustanding commands\n");
+		mutex_unlock(&instance->reset_mutex);
+		goto out;
+	}
+
+	devhandle = megasas_get_tm_devhandle(scmd->device);
+
+	if (devhandle == (u16)ULONG_MAX) {
+		ret = SUCCESS;
+		sdev_printk(KERN_INFO, scmd->device,
+			"task abort issued for invalid devhandle\n");
+		mutex_unlock(&instance->reset_mutex);
+		goto out;
+	}
+	sdev_printk(KERN_INFO, scmd->device,
+		"attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
+		scmd, devhandle);
+
+	mr_device_priv_data->tm_busy = 1;
+	ret = megasas_issue_tm(instance, devhandle,
+			scmd->device->channel, scmd->device->id, smid,
+			MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+	mr_device_priv_data->tm_busy = 0;
+
+	mutex_unlock(&instance->reset_mutex);
+out:
+	sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
+			((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+	return ret;
+}
+
+/*
+ * megasas_reset_target_fusion : target reset function for fusion adapters
+ * scmd: SCSI command pointer
+ *
+ * Returns SUCCESS if all commands associated with target aborted else FAILED
+ */
+
+int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
+{
+
+	struct megasas_instance *instance;
+	int ret = FAILED;
+	u16 devhandle;
+	struct fusion_context *fusion;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
+	mr_device_priv_data = scmd->device->hostdata;
+
+	instance = (struct megasas_instance *)scmd->device->host->hostdata;
+	fusion = instance->ctrl_context;
+
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
+		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
+		"SCSI host:%d\n", instance->host->host_no);
+		ret = FAILED;
+		return ret;
+	}
+
+	if (!mr_device_priv_data) {
+		sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+			"scmd(%p)\n", scmd);
+		scmd->result = DID_NO_CONNECT << 16;
+		ret = SUCCESS;
+		goto out;
+	}
+
+
+	if (!mr_device_priv_data->is_tm_capable) {
+		ret = FAILED;
+		goto out;
+	}
+
+	mutex_lock(&instance->reset_mutex);
+	devhandle = megasas_get_tm_devhandle(scmd->device);
+
+	if (devhandle == (u16)ULONG_MAX) {
+		ret = SUCCESS;
+		sdev_printk(KERN_INFO, scmd->device,
+			"target reset issued for invalid devhandle\n");
+		mutex_unlock(&instance->reset_mutex);
+		goto out;
+	}
+
+	sdev_printk(KERN_INFO, scmd->device,
+		"attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
+		scmd, devhandle);
+	mr_device_priv_data->tm_busy = 1;
+	ret = megasas_issue_tm(instance, devhandle,
+			scmd->device->channel, scmd->device->id, 0,
+			MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
+	mr_device_priv_data->tm_busy = 0;
+	mutex_unlock(&instance->reset_mutex);
+out:
+	scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
+		(ret == SUCCESS) ? "SUCCESS" : "FAILED");
+
+	return ret;
+}
+
+/*SRIOV get other instance in cluster if any*/
+struct megasas_instance *megasas_get_peer_instance(struct megasas_instance *instance)
+{
+	int i;
+
+	for (i = 0; i < MAX_MGMT_ADAPTERS; i++) {
+		if (megasas_mgmt_info.instance[i] &&
+			(megasas_mgmt_info.instance[i] != instance) &&
+			 megasas_mgmt_info.instance[i]->requestorId &&
+			 megasas_mgmt_info.instance[i]->peerIsPresent &&
+			(memcmp((megasas_mgmt_info.instance[i]->clusterId),
+			instance->clusterId, MEGASAS_CLUSTER_ID_SIZE) == 0))
+			return megasas_mgmt_info.instance[i];
+	}
+	return NULL;
+}
+
 /* Check for a second path that is currently UP */
 int megasas_check_mpio_paths(struct megasas_instance *instance,
 	struct scsi_cmnd *scmd)
 {
-	int i, j, retval = (DID_RESET << 16);
+	struct megasas_instance *peer_instance = NULL;
+	int retval = (DID_RESET << 16);
 
-	if (instance->mpio && instance->requestorId) {
-		for (i = 0 ; i < MAX_MGMT_ADAPTERS ; i++)
-			for (j = 0 ; j < MAX_LOGICAL_DRIVES; j++)
-				if (megasas_mgmt_info.instance[i] &&
-				    (megasas_mgmt_info.instance[i] != instance) &&
-				    megasas_mgmt_info.instance[i]->mpio &&
-				    megasas_mgmt_info.instance[i]->requestorId
-				    &&
-				    (megasas_mgmt_info.instance[i]->ld_ids[j]
-				     == scmd->device->id)) {
-					    retval = (DID_NO_CONNECT << 16);
-					    goto out;
-				}
+	if (instance->peerIsPresent) {
+		peer_instance = megasas_get_peer_instance(instance);
+		if ((peer_instance) &&
+			(atomic_read(&peer_instance->adprecovery) ==
+			MEGASAS_HBA_OPERATIONAL))
+			retval = (DID_NO_CONNECT << 16);
 	}
-out:
 	return retval;
 }
 
 /* Core fusion reset function */
-int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
+int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 {
 	int retval = SUCCESS, i, convert = 0;
 	struct megasas_instance *instance;
@@ -2739,13 +3374,14 @@
 	u32 abs_state, status_reg, reset_adapter;
 	u32 io_timeout_in_crash_mode = 0;
 	struct scsi_cmnd *scmd_local = NULL;
+	struct scsi_device *sdev;
 
 	instance = (struct megasas_instance *)shost->hostdata;
 	fusion = instance->ctrl_context;
 
 	mutex_lock(&instance->reset_mutex);
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		dev_warn(&instance->pdev->dev, "Hardware critical error, "
 		       "returning FAILED for scsi%d.\n",
 			instance->host->host_no);
@@ -2757,10 +3393,10 @@
 
 	/* IO timeout detected, forcibly put FW in FAULT state */
 	if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf &&
-		instance->crash_dump_app_support && iotimeout) {
-		dev_info(&instance->pdev->dev, "IO timeout is detected, "
+		instance->crash_dump_app_support && reason) {
+		dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
 			"forcibly FAULT Firmware\n");
-		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+		atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
 		status_reg = readl(&instance->reg_set->doorbell);
 		writel(status_reg | MFI_STATE_FORCE_OCR,
 			&instance->reg_set->doorbell);
@@ -2772,10 +3408,10 @@
 			dev_dbg(&instance->pdev->dev, "waiting for [%d] "
 				"seconds for crash dump collection and OCR "
 				"to be done\n", (io_timeout_in_crash_mode * 3));
-		} while ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+		} while ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
 			(io_timeout_in_crash_mode < 80));
 
-		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
 			dev_info(&instance->pdev->dev, "OCR done for IO "
 				"timeout case\n");
 			retval = SUCCESS;
@@ -2792,18 +3428,18 @@
 	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
 		del_timer_sync(&instance->sriov_heartbeat_timer);
 	set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
-	instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
+	atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
 	instance->instancet->disable_intr(instance);
 	msleep(1000);
 
 	/* First try waiting for commands to complete */
-	if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
+	if (megasas_wait_for_outstanding_fusion(instance, reason,
 						&convert)) {
-		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+		atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
 		dev_warn(&instance->pdev->dev, "resetting fusion "
 		       "adapter scsi%d.\n", instance->host->host_no);
 		if (convert)
-			iotimeout = 0;
+			reason = 0;
 
 		/* Now return commands back to the OS */
 		for (i = 0 ; i < instance->max_scsi_cmds; i++) {
@@ -2813,6 +3449,8 @@
 				scmd_local->result =
 					megasas_check_mpio_paths(instance,
 							scmd_local);
+				if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+					atomic_dec(&instance->ldio_outstanding);
 				megasas_return_cmd_fusion(instance, cmd_fusion);
 				scsi_dma_unmap(scmd_local);
 				scmd_local->scsi_done(scmd_local);
@@ -2837,55 +3475,9 @@
 		}
 
 		/* Let SR-IOV VF & PF sync up if there was a HB failure */
-		if (instance->requestorId && !iotimeout) {
+		if (instance->requestorId && !reason) {
 			msleep(MEGASAS_OCR_SETTLE_TIME_VF);
-			/* Look for a late HB update after VF settle time */
-			if (abs_state == MFI_STATE_OPERATIONAL &&
-			    (instance->hb_host_mem->HB.fwCounter !=
-			     instance->hb_host_mem->HB.driverCounter)) {
-					instance->hb_host_mem->HB.driverCounter =
-						instance->hb_host_mem->HB.fwCounter;
-					dev_warn(&instance->pdev->dev, "SR-IOV:"
-					       "Late FW heartbeat update for "
-					       "scsi%d.\n",
-					       instance->host->host_no);
-			} else {
-				/* In VF mode, first poll for FW ready */
-				for (i = 0;
-				     i < (MEGASAS_RESET_WAIT_TIME * 1000);
-				     i += 20) {
-					status_reg =
-						instance->instancet->
-						read_fw_status_reg(
-							instance->reg_set);
-					abs_state = status_reg &
-						MFI_STATE_MASK;
-					if (abs_state == MFI_STATE_READY) {
-						dev_warn(&instance->pdev->dev,
-						       "SR-IOV: FW was found"
-						       "to be in ready state "
-						       "for scsi%d.\n",
-						       instance->host->host_no);
-						break;
-					}
-					msleep(20);
-				}
-				if (abs_state != MFI_STATE_READY) {
-					dev_warn(&instance->pdev->dev, "SR-IOV: "
-					       "FW not in ready state after %d"
-					       " seconds for scsi%d, status_reg = "
-					       "0x%x.\n",
-					       MEGASAS_RESET_WAIT_TIME,
-					       instance->host->host_no,
-					       status_reg);
-					megaraid_sas_kill_hba(instance);
-					instance->skip_heartbeat_timer_del = 1;
-					instance->adprecovery =
-						MEGASAS_HW_CRITICAL_ERROR;
-					retval = FAILED;
-					goto out;
-				}
-			}
+			goto transition_to_ready;
 		}
 
 		/* Now try to reset the chip */
@@ -2894,23 +3486,28 @@
 			if (instance->instancet->adp_reset
 				(instance, instance->reg_set))
 				continue;
-
+transition_to_ready:
 			/* Wait for FW to become ready */
 			if (megasas_transition_to_ready(instance, 1)) {
-				dev_warn(&instance->pdev->dev, "Failed to "
-				       "transition controller to ready "
-				       "for scsi%d.\n",
-				       instance->host->host_no);
-				continue;
+				dev_warn(&instance->pdev->dev,
+					"Failed to transition controller to ready for "
+					"scsi%d.\n", instance->host->host_no);
+				if (instance->requestorId && !reason)
+					goto fail_kill_adapter;
+				else
+					continue;
 			}
-
 			megasas_reset_reply_desc(instance);
+			megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
+
 			if (megasas_ioc_init_fusion(instance)) {
 				dev_warn(&instance->pdev->dev,
-				       "megasas_ioc_init_fusion() failed!"
-				       " for scsi%d\n",
-				       instance->host->host_no);
-				continue;
+				       "megasas_ioc_init_fusion() failed! for "
+				       "scsi%d\n", instance->host->host_no);
+				if (instance->requestorId && !reason)
+					goto fail_kill_adapter;
+				else
+					continue;
 			}
 
 			megasas_refire_mgmt_cmd(instance);
@@ -2932,10 +3529,13 @@
 
 			megasas_setup_jbod_map(instance);
 
+			shost_for_each_device(sdev, shost)
+				megasas_update_sdev_properties(sdev);
+
 			clear_bit(MEGASAS_FUSION_IN_RESET,
 				  &instance->reset_flags);
 			instance->instancet->enable_intr(instance);
-			instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+			atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 
 			/* Restart SR-IOV heartbeat */
 			if (instance->requestorId) {
@@ -2964,6 +3564,7 @@
 			retval = SUCCESS;
 			goto out;
 		}
+fail_kill_adapter:
 		/* Reset failed, kill the adapter */
 		dev_warn(&instance->pdev->dev, "Reset failed, killing "
 		       "adapter scsi%d.\n", instance->host->host_no);
@@ -2980,7 +3581,7 @@
 		}
 		clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
 		instance->instancet->enable_intr(instance);
-		instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+		atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 	}
 out:
 	clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
--- linux-4.4.0.orig/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ linux-4.4.0/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -176,7 +176,9 @@
 #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD           (0x0100)
 #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP             (0x0004)
 #define MPI2_FUNCTION_SCSI_IO_REQUEST               (0x00) /* SCSI IO */
-#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY           (0x06)
+#define MPI2_FUNCTION_SCSI_TASK_MGMT                (0x01)
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY       (0x03)
+#define MPI2_REQ_DESCRIPT_FLAGS_FP_IO               (0x06)
 #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO                 (0x00)
 #define MPI2_SGE_FLAGS_64_BIT_ADDRESSING        (0x02)
 #define MPI2_SCSIIO_CONTROL_WRITE               (0x01000000)
@@ -277,6 +279,100 @@
 	struct MPI2_SGE_SIMPLE_UNION SGE;
 };
 
+/****************************************************************************
+*  SCSI Task Management messages
+****************************************************************************/
+
+/*SCSI Task Management Request Message */
+struct MPI2_SCSI_TASK_MANAGE_REQUEST {
+	u16 DevHandle;		/*0x00 */
+	u8 ChainOffset;		/*0x02 */
+	u8 Function;		/*0x03 */
+	u8 Reserved1;		/*0x04 */
+	u8 TaskType;		/*0x05 */
+	u8 Reserved2;		/*0x06 */
+	u8 MsgFlags;		/*0x07 */
+	u8 VP_ID;		/*0x08 */
+	u8 VF_ID;		/*0x09 */
+	u16 Reserved3;		/*0x0A */
+	u8 LUN[8];		/*0x0C */
+	u32 Reserved4[7];	/*0x14 */
+	u16 TaskMID;		/*0x30 */
+	u16 Reserved5;		/*0x32 */
+};
+
+
+/*SCSI Task Management Reply Message */
+struct MPI2_SCSI_TASK_MANAGE_REPLY {
+	u16 DevHandle;		/*0x00 */
+	u8 MsgLength;		/*0x02 */
+	u8 Function;		/*0x03 */
+	u8 ResponseCode;	/*0x04 */
+	u8 TaskType;		/*0x05 */
+	u8 Reserved1;		/*0x06 */
+	u8 MsgFlags;		/*0x07 */
+	u8 VP_ID;		/*0x08 */
+	u8 VF_ID;		/*0x09 */
+	u16 Reserved2;		/*0x0A */
+	u16 Reserved3;		/*0x0C */
+	u16 IOCStatus;		/*0x0E */
+	u32 IOCLogInfo;		/*0x10 */
+	u32 TerminationCount;	/*0x14 */
+	u32 ResponseInfo;	/*0x18 */
+};
+
+struct MR_TM_REQUEST {
+	char request[128];
+};
+
+struct MR_TM_REPLY {
+	char reply[128];
+};
+
+/* SCSI Task Management Request Message */
+struct MR_TASK_MANAGE_REQUEST {
+	/*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */
+	struct MR_TM_REQUEST         TmRequest;
+	union {
+		struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+			u32 reserved1:30;
+			u32 isTMForPD:1;
+			u32 isTMForLD:1;
+#else
+			u32 isTMForLD:1;
+			u32 isTMForPD:1;
+			u32 reserved1:30;
+#endif
+			u32 reserved2;
+		} tmReqFlags;
+		struct MR_TM_REPLY   TMReply;
+	};
+};
+
+/* TaskType values */
+
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK           (0x01)
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET        (0x02)
+#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET         (0x03)
+#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET   (0x05)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET       (0x06)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK           (0x07)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA              (0x08)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET         (0x09)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT      (0x0A)
+
+/* ResponseCode values */
+
+#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE               (0x00)
+#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME             (0x02)
+#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED          (0x04)
+#define MPI2_SCSITASKMGMT_RSP_TM_FAILED                 (0x05)
+#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED              (0x08)
+#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN            (0x09)
+#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG         (0x0A)
+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC          (0x80)
+
 /*
  * RAID SCSI IO Request Message
  * Total SGE count will be one less than  _MPI2_SCSI_IO_REQUEST
@@ -547,7 +643,9 @@
 struct MR_LD_RAID {
 	struct {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-		u32     reserved4:7;
+		u32     reserved4:5;
+		u32     fpBypassRegionLock:1;
+		u32     tmCapable:1;
 		u32	fpNonRWCapable:1;
 		u32     fpReadAcrossStripe:1;
 		u32     fpWriteAcrossStripe:1;
@@ -569,7 +667,9 @@
 		u32     fpWriteAcrossStripe:1;
 		u32     fpReadAcrossStripe:1;
 		u32	fpNonRWCapable:1;
-		u32     reserved4:7;
+		u32     tmCapable:1;
+		u32     fpBypassRegionLock:1;
+		u32     reserved4:5;
 #endif
 	} capability;
 	__le32     reserved6;
@@ -639,7 +739,7 @@
 	u8 fpOkForIo;
 	u8 IoforUnevenSpan;
 	u8 start_span;
-	u8 reserved;
+	u8 do_fp_rlbypass;
 	u64 start_row;
 	u8  span_arm;	/* span[7:5], arm[4:0] */
 	u8  pd_after_lb;
@@ -694,6 +794,7 @@
 	u32 sync_cmd_idx;
 	u32 index;
 	u8 pd_r1_lb;
+	struct completion done;
 };
 
 struct LD_LOAD_BALANCE_INFO {
@@ -807,9 +908,18 @@
  *  * define MR_PD_CFG_SEQ structure for system PDs
  *   */
 struct MR_PD_CFG_SEQ {
-	__le16 seqNum;
-	__le16 devHandle;
-	u8  reserved[4];
+	u16 seqNum;
+	u16 devHandle;
+	struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+		u8     reserved:7;
+		u8     tmCapable:1;
+#else
+		u8     tmCapable:1;
+		u8     reserved:7;
+#endif
+	} capability;
+	u8  reserved[3];
 } __packed;
 
 struct MR_PD_CFG_SEQ_NUM_SYNC {
@@ -818,6 +928,12 @@
 	struct MR_PD_CFG_SEQ seq[1];
 } __packed;
 
+struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
+	u64 RDPQBaseAddress;
+	u32 Reserved1;
+	u32 Reserved2;
+};
+
 struct fusion_context {
 	struct megasas_cmd_fusion **cmd_list;
 	dma_addr_t req_frames_desc_phys;
@@ -830,8 +946,8 @@
 	struct dma_pool *sg_dma_pool;
 	struct dma_pool *sense_dma_pool;
 
-	dma_addr_t reply_frames_desc_phys;
-	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
+	dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
 	struct dma_pool *reply_frames_desc_pool;
 
 	u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
@@ -841,6 +957,8 @@
 	u32 reply_alloc_sz;
 	u32 io_frames_alloc_sz;
 
+	struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
+	dma_addr_t rdpq_phys;
 	u16	max_sge_in_main_msg;
 	u16	max_sge_in_chain;
 
--- linux-4.4.0.orig/drivers/scsi/mesh.c
+++ linux-4.4.0/drivers/scsi/mesh.c
@@ -1044,6 +1044,8 @@
 		while ((in_8(&mr->bus_status1) & BS1_RST) != 0)
 			udelay(1);
 		printk("done\n");
+		if (ms->dma_started)
+			halt_dma(ms);
 		handle_reset(ms);
 		/* request_q is empty, no point in mesh_start() */
 		return;
@@ -1356,7 +1358,8 @@
 		       ms->conn_tgt, ms->data_ptr, scsi_bufflen(cmd),
 		       ms->tgts[ms->conn_tgt].data_goes_out);
 	}
-	scsi_dma_unmap(cmd);
+	if (cmd)
+		scsi_dma_unmap(cmd);
 	ms->dma_started = 0;
 }
 
@@ -1711,6 +1714,9 @@
 
 	spin_lock_irqsave(ms->host->host_lock, flags);
 
+	if (ms->dma_started)
+		halt_dma(ms);
+
 	/* Reset the controller & dbdma channel */
 	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */
 	out_8(&mr->exception, 0xff);	/* clear all exception bits */
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpi/mpi2.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpi/mpi2.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies.  All rights reserved.
  *
  *
  *          Name:  mpi2.h
@@ -8,7 +8,7 @@
  *                 scatter/gather formats.
  * Creation Date:  June 21, 2006
  *
- * mpi2.h Version:  02.00.35
+ * mpi2.h Version:  02.00.39
  *
  * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
  *       prefix are for use only on MPI v2.5 products, and must not be used
@@ -92,6 +92,14 @@
  * 12-05-13  02.00.33  Bumped MPI2_HEADER_VERSION_UNIT.
  * 01-08-14  02.00.34  Bumped MPI2_HEADER_VERSION_UNIT
  * 06-13-14  02.00.35  Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-18-14  02.00.36  Updated copyright information.
+ *                     Bumped MPI2_HEADER_VERSION_UNIT.
+ * 03-16-15  02.00.37  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                     Added Scratchpad registers to
+ *                     MPI2_SYSTEM_INTERFACE_REGS.
+ *                     Added MPI2_DIAG_SBR_RELOAD.
+ * 03-19-15  02.00.38  Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-25-15  02.00.39  Bumped MPI2_HEADER_VERSION_UNIT.
  * --------------------------------------------------------------------------
  */
 
@@ -124,8 +132,14 @@
 					MPI25_VERSION_MINOR)
 #define MPI2_VERSION_02_05                  (0x0205)
 
+/*minor version for MPI v2.6 compatible products */
+#define MPI26_VERSION_MINOR		    (0x06)
+#define MPI26_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
+					MPI26_VERSION_MINOR)
+#define MPI2_VERSION_02_06		    (0x0206)
+
 /*Unit and Dev versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT            (0x23)
+#define MPI2_HEADER_VERSION_UNIT            (0x27)
 #define MPI2_HEADER_VERSION_DEV             (0x00)
 #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
 #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
@@ -179,10 +193,12 @@
 	U32 HCBSize;		/*0x74 */
 	U32 HCBAddressLow;	/*0x78 */
 	U32 HCBAddressHigh;	/*0x7C */
-	U32 Reserved6[16];	/*0x80 */
+	U32 Reserved6[12];	/*0x80 */
+	U32 Scratchpad[4];	/*0xB0 */
 	U32 RequestDescriptorPostLow;	/*0xC0 */
 	U32 RequestDescriptorPostHigh;	/*0xC4 */
-	U32 Reserved7[14];	/*0xC8 */
+	U32 AtomicRequestDescriptorPost;/*0xC8 */
+	U32 Reserved7[13];	/*0xCC */
 } MPI2_SYSTEM_INTERFACE_REGS,
 	*PTR_MPI2_SYSTEM_INTERFACE_REGS,
 	Mpi2SystemInterfaceRegs_t,
@@ -224,6 +240,8 @@
  */
 #define MPI2_HOST_DIAGNOSTIC_OFFSET             (0x00000008)
 
+#define MPI2_DIAG_SBR_RELOAD                    (0x00002000)
+
 #define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK       (0x00001800)
 #define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT    (0x00000000)
 #define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW       (0x00000800)
@@ -298,10 +316,19 @@
 #define MPI2_HCB_ADDRESS_HIGH_OFFSET            (0x0000007C)
 
 /*
- *Offsets for the Request Queue
+ *Offsets for the Scratchpad registers
+ */
+#define MPI26_SCRATCHPAD0_OFFSET                (0x000000B0)
+#define MPI26_SCRATCHPAD1_OFFSET                (0x000000B4)
+#define MPI26_SCRATCHPAD2_OFFSET                (0x000000B8)
+#define MPI26_SCRATCHPAD3_OFFSET                (0x000000BC)
+
+/*
+ *Offsets for the Request Descriptor Post Queue
  */
 #define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET     (0x000000C0)
 #define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET    (0x000000C4)
+#define MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET (0x000000C8)
 
 /*Hard Reset delay timings */
 #define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC     (50000)
@@ -329,7 +356,8 @@
 	*pMpi2DefaultRequestDescriptor_t;
 
 /*defines for the RequestFlags field */
-#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK               (0x0E)
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK               (0x1E)
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_RSHIFT             (1)
 #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO                 (0x00)
 #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET             (0x02)
 #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY           (0x06)
@@ -337,7 +365,7 @@
 #define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR        (0x0A)
 #define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO      (0x0C)
 
-#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER         (0x01)
 
 /*High Priority Request Descriptor */
 typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR {
@@ -408,6 +436,33 @@
 	Mpi2RequestDescriptorUnion_t,
 	*pMpi2RequestDescriptorUnion_t;
 
+/*Atomic Request Descriptors */
+
+/*
+ * All Atomic Request Descriptors have the same format, so the following
+ * structure is used for all Atomic Request Descriptors:
+ *      Atomic Default Request Descriptor
+ *      Atomic High Priority Request Descriptor
+ *      Atomic SCSI IO Request Descriptor
+ *      Atomic SCSI Target Request Descriptor
+ *      Atomic RAID Accelerator Request Descriptor
+ *      Atomic Fast Path SCSI IO Request Descriptor
+ */
+
+/*Atomic Request Descriptor */
+typedef struct _MPI26_ATOMIC_REQUEST_DESCRIPTOR {
+	U8 RequestFlags;	/* 0x00 */
+	U8 MSIxIndex;		/* 0x01 */
+	U16 SMID;		/* 0x02 */
+} MPI26_ATOMIC_REQUEST_DESCRIPTOR,
+	*PTR_MPI26_ATOMIC_REQUEST_DESCRIPTOR,
+	Mpi26AtomicRequestDescriptor_t,
+	*pMpi26AtomicRequestDescriptor_t;
+
+/*for the RequestFlags field, use the same
+ *defines as MPI2_DEFAULT_REQUEST_DESCRIPTOR
+ */
+
 /*Reply Descriptors */
 
 /*Default Reply Descriptor */
@@ -548,6 +603,7 @@
 #define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR      (0x18)
 #define MPI2_FUNCTION_SMP_PASSTHROUGH               (0x1A)
 #define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL           (0x1B)
+#define MPI2_FUNCTION_IO_UNIT_CONTROL               (0x1B)
 #define MPI2_FUNCTION_SATA_PASSTHROUGH              (0x1C)
 #define MPI2_FUNCTION_DIAG_BUFFER_POST              (0x1D)
 #define MPI2_FUNCTION_DIAG_RELEASE                  (0x1E)
@@ -587,6 +643,7 @@
 #define MPI2_IOCSTATUS_INVALID_FIELD                (0x0007)
 #define MPI2_IOCSTATUS_INVALID_STATE                (0x0008)
 #define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED       (0x0009)
+#define MPI2_IOCSTATUS_INSUFFICIENT_POWER           (0x000A)
 
 /****************************************************************************
 * Config IOCStatus values
@@ -1045,7 +1102,7 @@
 	Mpi2IeeeSgeChainUnion_t,
 	*pMpi2IeeeSgeChainUnion_t;
 
-/*MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 products only */
+/*MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 and later */
 typedef struct _MPI25_IEEE_SGE_CHAIN64 {
 	U64 Address;
 	U32 Length;
@@ -1098,6 +1155,11 @@
 #define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT      (0x00)
 #define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT       (0x80)
 
+/*Next Segment Format */
+
+#define MPI26_IEEE_SGE_FLAGS_NSF_MASK           (0x1C)
+#define MPI26_IEEE_SGE_FLAGS_NSF_MPI_IEEE       (0x00)
+
 /*Data Location Address Space */
 
 #define MPI2_IEEE_SGE_FLAGS_ADDR_MASK           (0x03)
@@ -1108,6 +1170,7 @@
 #define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR   (0x03)
 #define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \
 	 (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR)
+#define MPI26_IEEE_SGE_FLAGS_IOCCTL_ADDR        (0x02)
 
 /****************************************************************************
 * IEEE SGE operation Macros
@@ -1166,6 +1229,7 @@
 #define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE          (0x00)
 #define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE          (0x04)
 #define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE          (0x08)
+#define MPI26_SGLFLAGS_IOCPLB_ADDRESS_SPACE         (0x08)
 #define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE       (0x0C)
 /*values for SGL Type subfield */
 #define MPI2_SGLFLAGS_SGL_TYPE_MASK                 (0x03)
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies.  All rights reserved.
  *
  *
  *          Name:  mpi2_cnfg.h
  *         Title:  MPI Configuration messages and pages
  * Creation Date:  November 10, 2006
  *
- *   mpi2_cnfg.h Version:  02.00.29
+ *   mpi2_cnfg.h Version:  02.00.33
  *
  * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
  *       prefix are for use only on MPI v2.5 products, and must not be used
@@ -178,7 +178,14 @@
  * 01-08-14  02.00.28  Added more defines for the BiosOptions field of
  *		       MPI2_CONFIG_PAGE_BIOS_1.
  * 06-13-14  02.00.29  Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and
- *		       more defines for the BiosOptions field..
+ *                     more defines for the BiosOptions field.
+ * 11-18-14  02.00.30  Updated copyright information.
+ *                     Added MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG.
+ *                     Added AdapterOrderAux fields to BIOS Page 3.
+ * 03-16-15  02.00.31  Updated for MPI v2.6.
+ *                     Added new SAS Phy Event codes
+ * 05-25-15  02.00.33  Added more defines for the BiosOptions field of
+ *                     MPI2_CONFIG_PAGE_BIOS_1.
  * --------------------------------------------------------------------------
  */
 
@@ -355,7 +362,6 @@
 #define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK           (0x000000FF)
 
 
-
 /****************************************************************************
 *  Configuration messages
 ****************************************************************************/
@@ -457,8 +463,17 @@
 #define MPI25_MFGPAGE_DEVID_SAS3108_5               (0x0094)
 #define MPI25_MFGPAGE_DEVID_SAS3108_6               (0x0095)
 
-
-
+/* MPI v2.6 SAS Products */
+#define MPI26_MFGPAGE_DEVID_SAS3216                 (0x00C9)
+#define MPI26_MFGPAGE_DEVID_SAS3224                 (0x00C4)
+#define MPI26_MFGPAGE_DEVID_SAS3316_1               (0x00C5)
+#define MPI26_MFGPAGE_DEVID_SAS3316_2               (0x00C6)
+#define MPI26_MFGPAGE_DEVID_SAS3316_3               (0x00C7)
+#define MPI26_MFGPAGE_DEVID_SAS3316_4               (0x00C8)
+#define MPI26_MFGPAGE_DEVID_SAS3324_1               (0x00C0)
+#define MPI26_MFGPAGE_DEVID_SAS3324_2               (0x00C1)
+#define MPI26_MFGPAGE_DEVID_SAS3324_3               (0x00C2)
+#define MPI26_MFGPAGE_DEVID_SAS3324_4               (0x00C3)
 
 /*Manufacturing Page 0 */
 
@@ -941,8 +956,8 @@
 	U8
 		BoardTemperatureUnits;                  /*0x16 */
 	U8                      Reserved3;              /*0x17 */
-	U32			Reserved4;		/* 0x18 */
-	U32			Reserved5;		/* 0x1C */
+	U32			BoardPowerRequirement;	/*0x18 */
+	U32			PCISlotPowerAllocation;	/*0x1C */
 	U32			Reserved6;		/* 0x20 */
 	U32			Reserved7;		/* 0x24 */
 } MPI2_CONFIG_PAGE_IO_UNIT_7,
@@ -1151,6 +1166,62 @@
 #define MPI2_IOUNITPAGE10_PAGEVERSION                   (0x01)
 
 
+/* IO Unit Page 11 (for MPI v2.6 and later) */
+
+typedef struct _MPI26_IOUNIT11_SPINUP_GROUP {
+	U8          MaxTargetSpinup;            /* 0x00 */
+	U8          SpinupDelay;                /* 0x01 */
+	U8          SpinupFlags;                /* 0x02 */
+	U8          Reserved1;                  /* 0x03 */
+} MPI26_IOUNIT11_SPINUP_GROUP,
+	*PTR_MPI26_IOUNIT11_SPINUP_GROUP,
+	Mpi26IOUnit11SpinupGroup_t,
+	*pMpi26IOUnit11SpinupGroup_t;
+
+/* defines for IO Unit Page 11 SpinupFlags */
+#define MPI26_IOUNITPAGE11_SPINUP_DISABLE_FLAG          (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * four and check the value returned for NumPhys at runtime.
+ */
+#ifndef MPI26_IOUNITPAGE11_PHY_MAX
+#define MPI26_IOUNITPAGE11_PHY_MAX        (4)
+#endif
+
+typedef struct _MPI26_CONFIG_PAGE_IO_UNIT_11 {
+	MPI2_CONFIG_PAGE_HEADER       Header;			       /*0x00 */
+	U32                           Reserved1;                      /*0x04 */
+	MPI26_IOUNIT11_SPINUP_GROUP   SpinupGroupParameters[4];       /*0x08 */
+	U32                           Reserved2;                      /*0x18 */
+	U32                           Reserved3;                      /*0x1C */
+	U32                           Reserved4;                      /*0x20 */
+	U8                            BootDeviceWaitTime;             /*0x24 */
+	U8                            Reserved5;                      /*0x25 */
+	U16                           Reserved6;                      /*0x26 */
+	U8                            NumPhys;                        /*0x28 */
+	U8                            PEInitialSpinupDelay;           /*0x29 */
+	U8                            PEReplyDelay;                   /*0x2A */
+	U8                            Flags;                          /*0x2B */
+	U8			      PHY[MPI26_IOUNITPAGE11_PHY_MAX];/*0x2C */
+} MPI26_CONFIG_PAGE_IO_UNIT_11,
+	*PTR_MPI26_CONFIG_PAGE_IO_UNIT_11,
+	Mpi26IOUnitPage11_t,
+	*pMpi26IOUnitPage11_t;
+
+#define MPI26_IOUNITPAGE11_PAGEVERSION                  (0x00)
+
+/* defines for Flags field */
+#define MPI26_IOUNITPAGE11_FLAGS_AUTO_PORTENABLE        (0x01)
+
+/* defines for PHY field */
+#define MPI26_IOUNITPAGE11_PHY_SPINUP_GROUP_MASK        (0x03)
+
+
+
+
+
 
 /****************************************************************************
 *  IOC Config Pages
@@ -1343,6 +1414,10 @@
 #define MPI2_BIOSPAGE1_PAGEVERSION                      (0x07)
 
 /*values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_BOOT_LIST_ADD_ALT_BOOT_DEVICE    (0x00008000)
+#define MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG                  (0x00004000)
+
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK                         (0x00003800)
 #define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK                         (0x00003800)
 #define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL                        (0x00000000)
 #define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE                   (0x00000800)
@@ -1492,6 +1567,8 @@
 
 /*BIOS Page 3 */
 
+#define MPI2_BIOSPAGE3_NUM_ADAPTER      (4)
+
 typedef struct _MPI2_ADAPTER_INFO {
 	U8      PciBusNumber;                        /*0x00 */
 	U8      PciDeviceAndFunctionNumber;          /*0x01 */
@@ -1502,17 +1579,26 @@
 #define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED                (0x0001)
 #define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS             (0x0002)
 
+typedef struct _MPI2_ADAPTER_ORDER_AUX {
+	U64     WWID;					/* 0x00 */
+	U32     Reserved1;				/* 0x08 */
+	U32     Reserved2;				/* 0x0C */
+} MPI2_ADAPTER_ORDER_AUX, *PTR_MPI2_ADAPTER_ORDER_AUX,
+	Mpi2AdapterOrderAux_t, *pMpi2AdapterOrderAux_t;
+
+
 typedef struct _MPI2_CONFIG_PAGE_BIOS_3 {
 	MPI2_CONFIG_PAGE_HEADER Header;              /*0x00 */
 	U32                     GlobalFlags;         /*0x04 */
 	U32                     BiosVersion;         /*0x08 */
-	MPI2_ADAPTER_INFO       AdapterOrder[4];     /*0x0C */
+	MPI2_ADAPTER_INFO       AdapterOrder[MPI2_BIOSPAGE3_NUM_ADAPTER];
 	U32                     Reserved1;           /*0x1C */
+	MPI2_ADAPTER_ORDER_AUX  AdapterOrderAux[MPI2_BIOSPAGE3_NUM_ADAPTER];
 } MPI2_CONFIG_PAGE_BIOS_3,
 	*PTR_MPI2_CONFIG_PAGE_BIOS_3,
 	Mpi2BiosPage3_t, *pMpi2BiosPage3_t;
 
-#define MPI2_BIOSPAGE3_PAGEVERSION                      (0x00)
+#define MPI2_BIOSPAGE3_PAGEVERSION                      (0x01)
 
 /*values for BIOS Page 3 GlobalFlags */
 #define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR             (0x00000002)
@@ -2006,6 +2092,8 @@
 #define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG          (0x01)
 
 /*values for SAS IO Unit Page 0 PhyFlags */
+#define MPI2_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT       (0x40)
+#define MPI2_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT       (0x20)
 #define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED             (0x10)
 #define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED               (0x08)
 
@@ -2108,6 +2196,7 @@
 #define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION                   (0x0001)
 
 /*values for SAS IO Unit Page 1 AdditionalControlFlags */
+#define MPI2_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT                 (0x0100)
 #define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL          (0x0080)
 #define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION    (0x0040)
 #define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION        (0x0020)
@@ -2125,6 +2214,8 @@
 #define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG                 (0x01)
 
 /*values for SAS IO Unit Page 1 PhyFlags */
+#define MPI2_SASIOUNIT1_PHYFLAGS_INIT_PERSIST_CONNECT               (0x40)
+#define MPI2_SASIOUNIT1_PHYFLAGS_TARG_PERSIST_CONNECT               (0x20)
 #define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE                      (0x10)
 #define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE                        (0x08)
 
@@ -2144,7 +2235,7 @@
  *SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
 
 
-/*SAS IO Unit Page 4 */
+/*SAS IO Unit Page 4 (for MPI v2.5 and earlier) */
 
 typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP {
 	U8          MaxTargetSpinup;            /*0x00 */
@@ -2715,6 +2806,7 @@
 #define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED           (0x0020)
 #define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED           (0x0010)
 #define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH         (0x0008)
+#define MPI2_SAS_DEVICE0_FLAGS_PERSIST_CAPABLE              (0x0004)
 #define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID             (0x0002)
 #define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT               (0x0001)
 
@@ -2922,6 +3014,19 @@
 #define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE    (0xD1)
 #define MPI2_SASPHY3_EVENT_CODE_RX_AIP                      (0xD2)
 
+/*Following codes are product specific and in MPI v2.6 and later */
+#define MPI2_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME		    (0xD3)
+#define MPI2_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME    (0xD4)
+#define MPI2_SASPHY3_EVENT_CODE_LCCONN_TIME	            (0xD5)
+#define MPI2_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT	    (0xD6)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_TX_START	            (0xD7)
+#define MPI2_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT	    (0xD8)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN	    (0xD9)
+#define MPI2_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE	    (0xDA)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE	    (0xDB)
+#define MPI2_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE	    (0xDC)
+
+
 /*values for the CounterType field */
 #define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING                  (0x00)
 #define MPI2_SASPHY3_COUNTER_TYPE_SATURATING                (0x01)
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpi/mpi2_init.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpi/mpi2_init.h
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies.  All rights reserved.
  *
  *
  *          Name:  mpi2_init.h
  *         Title:  MPI SCSI initiator mode messages and structures
  * Creation Date:  June 23, 2006
  *
- * mpi2_init.h Version:  02.00.15
+ * mpi2_init.h Version:  02.00.17
  *
  * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
  *       prefix are for use only on MPI v2.5 products, and must not be used
@@ -46,6 +46,11 @@
  * 07-10-12  02.00.14  Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION.
  * 04-09-13  02.00.15  Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY,
  *                     replacing the Reserved4 field.
+ * 11-18-14  02.00.16  Updated copyright information.
+ * 03-16-15  02.00.17  Updated for MPI v2.6.
+ *                     Added MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH.
+ *                     Added MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF and
+ *                     MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF.
  * --------------------------------------------------------------------------
  */
 
@@ -128,6 +133,7 @@
 #define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR      (0x04)
 #define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR      (0x08)
 #define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR   (0x0C)
+#define MPI26_SCSIIO_MSGFLAGS_IOCCTL_SENSE_ADDR     (0x08)
 
 /*SCSI IO SGLFlags bits */
 
@@ -228,7 +234,7 @@
 } MPI25_SCSI_IO_CDB_UNION, *PTR_MPI25_SCSI_IO_CDB_UNION,
 	Mpi25ScsiIoCdb_t, *pMpi25ScsiIoCdb_t;
 
-/*MPI v2.5 SCSI IO Request Message */
+/*MPI v2.5/2.6 SCSI IO Request Message */
 typedef struct _MPI25_SCSI_IO_REQUEST {
 	U16 DevHandle;		/*0x00 */
 	U8 ChainOffset;		/*0x02 */
@@ -302,12 +308,14 @@
 #define MPI25_SCSIIO_NUM_SGLOFFSETS                 (4)
 
 /*defines for the IoFlags field */
-#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK           (0xC000)
-#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH            (0x0000)
-#define MPI25_SCSIIO_IOFLAGS_FAST_PATH              (0x4000)
+#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK               (0xC000)
+#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH                (0x0000)
+#define MPI25_SCSIIO_IOFLAGS_FAST_PATH                  (0x4000)
 
+#define MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH         (0x2000)
 #define MPI25_SCSIIO_IOFLAGS_LARGE_CDB                  (0x1000)
 #define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL              (0x0800)
+#define MPI26_SCSIIO_IOFLAGS_PORT_REQUEST               (0x0400)
 #define MPI25_SCSIIO_IOFLAGS_CDBLENGTH_MASK             (0x01FF)
 
 /*MPI v2.5 defines for the EEDPFlags bits */
@@ -512,6 +520,7 @@
 #define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS       (0x01)
 
 /*SlotStatus defines */
+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF                 (0x00080000)
 #define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE          (0x00040000)
 #define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST        (0x00020000)
 #define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED         (0x00000200)
@@ -547,6 +556,7 @@
 	Mpi2SepReply_t, *pMpi2SepReply_t;
 
 /*SlotStatus defines */
+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF               (0x00080000)
 #define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY          (0x00040000)
 #define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST      (0x00020000)
 #define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED       (0x00000200)
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies.  All rights reserved.
  *
  *
  *          Name:  mpi2_ioc.h
  *         Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  * Creation Date:  October 11, 2006
  *
- * mpi2_ioc.h Version:  02.00.24
+ * mpi2_ioc.h Version:  02.00.26
  *
  * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
  *       prefix are for use only on MPI v2.5 products, and must not be used
@@ -133,6 +133,10 @@
  *			Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
  *			Added Encrypted Hash Extended Image.
  * 12-05-13  02.00.24  Added MPI25_HASH_IMAGE_TYPE_BIOS.
+ * 11-18-14  02.00.25  Updated copyright information.
+ * 03-16-15  02.00.26  Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and
+ *                     MPI26_FW_HEADER_PID_FAMILY_3516_SAS.
+ *                     Added MPI26_CTRL_OP_SHUTDOWN.
  * --------------------------------------------------------------------------
  */
 
@@ -165,7 +169,7 @@
 	U16 HeaderVersion;	/*0x0E */
 	U32 Reserved5;		/*0x10 */
 	U16 Reserved6;		/*0x14 */
-	U8 Reserved7;		/*0x16 */
+	U8 HostPageSize;	/*0x16 */
 	U8 HostMSIxVectors;	/*0x17 */
 	U16 Reserved8;		/*0x18 */
 	U16 SystemRequestFrameSize;	/*0x1A */
@@ -289,7 +293,8 @@
 	U16 MaxDevHandle;	/*0x38 */
 	U16 MaxPersistentEntries;	/*0x3A */
 	U16 MinDevHandle;	/*0x3C */
-	U16 Reserved4;		/*0x3E */
+	U8 CurrentHostPageSize;	/* 0x3E */
+	U8 Reserved4;		/* 0x3F */
 } MPI2_IOC_FACTS_REPLY, *PTR_MPI2_IOC_FACTS_REPLY,
 	Mpi2IOCFactsReply_t, *pMpi2IOCFactsReply_t;
 
@@ -326,6 +331,7 @@
 /*ProductID field uses MPI2_FW_HEADER_PID_ */
 
 /*IOCCapabilities */
+#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ            (0x00080000)
 #define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE     (0x00040000)
 #define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE     (0x00020000)
 #define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY   (0x00010000)
@@ -343,8 +349,8 @@
 #define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
 
 /*ProtocolFlags */
-#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET              (0x0001)
 #define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR           (0x0002)
+#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET              (0x0001)
 
 /****************************************************************************
 * PortFacts message
@@ -1247,6 +1253,7 @@
 #define MPI2_FW_UPLOAD_ITYPE_MEGARAID           (0x09)
 #define MPI2_FW_UPLOAD_ITYPE_COMPLETE           (0x0A)
 #define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK  (0x0B)
+#define MPI2_FW_UPLOAD_ITYPE_CBB_BACKUP         (0x0D)
 
 /*MPI v2.0 FWUpload TransactionContext Element */
 typedef struct _MPI2_FW_UPLOAD_TCSGE {
@@ -1328,7 +1335,7 @@
 	U32 Reserved54;		/*0x54 */
 	U32 Reserved58;		/*0x58 */
 	U32 Reserved5C;		/*0x5C */
-	U32 Reserved60;		/*0x60 */
+	U32 BootFlags;		/*0x60 */
 	U32 FirmwareVersionNameWhat;	/*0x64 */
 	U8 FirmwareVersionName[32];	/*0x68 */
 	U32 VendorNameWhat;	/*0x88 */
@@ -1354,18 +1361,22 @@
 #define MPI2_FW_HEADER_SIGNATURE_OFFSET         (0x00)
 #define MPI2_FW_HEADER_SIGNATURE_MASK           (0xFF000000)
 #define MPI2_FW_HEADER_SIGNATURE                (0xEA000000)
+#define MPI26_FW_HEADER_SIGNATURE               (0xEB000000)
 
 /*Signature0 field */
 #define MPI2_FW_HEADER_SIGNATURE0_OFFSET        (0x04)
 #define MPI2_FW_HEADER_SIGNATURE0               (0x5AFAA55A)
+#define MPI26_FW_HEADER_SIGNATURE0              (0x5AEAA55A)
 
 /*Signature1 field */
 #define MPI2_FW_HEADER_SIGNATURE1_OFFSET        (0x08)
 #define MPI2_FW_HEADER_SIGNATURE1               (0xA55AFAA5)
+#define MPI26_FW_HEADER_SIGNATURE1              (0xA55AEAA5)
 
 /*Signature2 field */
 #define MPI2_FW_HEADER_SIGNATURE2_OFFSET        (0x0C)
 #define MPI2_FW_HEADER_SIGNATURE2               (0x5AA55AFA)
+#define MPI26_FW_HEADER_SIGNATURE2              (0x5AA55AEA)
 
 /*defines for using the ProductID field */
 #define MPI2_FW_HEADER_PID_TYPE_MASK            (0xF000)
@@ -1381,6 +1392,8 @@
 #define MPI2_FW_HEADER_PID_FAMILY_2108_SAS      (0x0013)
 #define MPI2_FW_HEADER_PID_FAMILY_2208_SAS      (0x0014)
 #define MPI25_FW_HEADER_PID_FAMILY_3108_SAS     (0x0021)
+#define MPI26_FW_HEADER_PID_FAMILY_3324_SAS     (0x0028)
+#define MPI26_FW_HEADER_PID_FAMILY_3516_SAS     (0x0031)
 
 /*use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
 
@@ -1388,6 +1401,7 @@
 
 #define MPI2_FW_HEADER_IMAGESIZE_OFFSET         (0x2C)
 #define MPI2_FW_HEADER_NEXTIMAGE_OFFSET         (0x30)
+#define MPI26_FW_HEADER_BOOTFLAGS_OFFSET        (0x60)
 #define MPI2_FW_HEADER_VERNMHWAT_OFFSET         (0x64)
 
 #define MPI2_FW_HEADER_WHAT_SIGNATURE           (0x29232840)
@@ -1493,7 +1507,9 @@
 #define MPI2_FLASH_REGION_CONFIG_1              (0x07)
 #define MPI2_FLASH_REGION_CONFIG_2              (0x08)
 #define MPI2_FLASH_REGION_MEGARAID              (0x09)
-#define MPI2_FLASH_REGION_INIT                  (0x0A)
+#define MPI2_FLASH_REGION_COMMON_BOOT_BLOCK     (0x0A)
+#define MPI2_FLASH_REGION_INIT (MPI2_FLASH_REGION_COMMON_BOOT_BLOCK)
+#define MPI2_FLASH_REGION_CBB_BACKUP            (0x0D)
 
 /*ImageRevision */
 #define MPI2_FLASH_LAYOUT_IMAGE_REVISION        (0x00)
@@ -1619,7 +1635,6 @@
 Mpi25EncryptedHashData_t, *pMpi25EncryptedHashData_t;
 
 
-
 /****************************************************************************
 * PowerManagementControl message
 ****************************************************************************/
@@ -1726,4 +1741,90 @@
 } MPI2_PWR_MGMT_CONTROL_REPLY, *PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
 	Mpi2PwrMgmtControlReply_t, *pMpi2PwrMgmtControlReply_t;
 
+/****************************************************************************
+*  IO Unit Control messages (MPI v2.6 and later only.)
+****************************************************************************/
+
+/* IO Unit Control Request Message */
+typedef struct _MPI26_IOUNIT_CONTROL_REQUEST {
+	U8                      Operation;          /* 0x00 */
+	U8                      Reserved1;          /* 0x01 */
+	U8                      ChainOffset;        /* 0x02 */
+	U8                      Function;           /* 0x03 */
+	U16                     DevHandle;          /* 0x04 */
+	U8                      IOCParameter;       /* 0x06 */
+	U8                      MsgFlags;           /* 0x07 */
+	U8                      VP_ID;              /* 0x08 */
+	U8                      VF_ID;              /* 0x09 */
+	U16                     Reserved3;          /* 0x0A */
+	U16                     Reserved4;          /* 0x0C */
+	U8                      PhyNum;             /* 0x0E */
+	U8                      PrimFlags;          /* 0x0F */
+	U32                     Primitive;          /* 0x10 */
+	U8                      LookupMethod;       /* 0x14 */
+	U8                      Reserved5;          /* 0x15 */
+	U16                     SlotNumber;         /* 0x16 */
+	U64                     LookupAddress;      /* 0x18 */
+	U32                     IOCParameterValue;  /* 0x20 */
+	U32                     Reserved7;          /* 0x24 */
+	U32                     Reserved8;          /* 0x28 */
+} MPI26_IOUNIT_CONTROL_REQUEST,
+	*PTR_MPI26_IOUNIT_CONTROL_REQUEST,
+	Mpi26IoUnitControlRequest_t,
+	*pMpi26IoUnitControlRequest_t;
+
+/* values for the Operation field */
+#define MPI26_CTRL_OP_CLEAR_ALL_PERSISTENT              (0x02)
+#define MPI26_CTRL_OP_SAS_PHY_LINK_RESET                (0x06)
+#define MPI26_CTRL_OP_SAS_PHY_HARD_RESET                (0x07)
+#define MPI26_CTRL_OP_PHY_CLEAR_ERROR_LOG               (0x08)
+#define MPI26_CTRL_OP_SAS_SEND_PRIMITIVE                (0x0A)
+#define MPI26_CTRL_OP_FORCE_FULL_DISCOVERY              (0x0B)
+#define MPI26_CTRL_OP_REMOVE_DEVICE                     (0x0D)
+#define MPI26_CTRL_OP_LOOKUP_MAPPING                    (0x0E)
+#define MPI26_CTRL_OP_SET_IOC_PARAMETER                 (0x0F)
+#define MPI26_CTRL_OP_ENABLE_FP_DEVICE                  (0x10)
+#define MPI26_CTRL_OP_DISABLE_FP_DEVICE                 (0x11)
+#define MPI26_CTRL_OP_ENABLE_FP_ALL                     (0x12)
+#define MPI26_CTRL_OP_DISABLE_FP_ALL                    (0x13)
+#define MPI26_CTRL_OP_DEV_ENABLE_NCQ                    (0x14)
+#define MPI26_CTRL_OP_DEV_DISABLE_NCQ                   (0x15)
+#define MPI26_CTRL_OP_SHUTDOWN                          (0x16)
+#define MPI26_CTRL_OP_DEV_ENABLE_PERSIST_CONNECTION     (0x17)
+#define MPI26_CTRL_OP_DEV_DISABLE_PERSIST_CONNECTION    (0x18)
+#define MPI26_CTRL_OP_DEV_CLOSE_PERSIST_CONNECTION      (0x19)
+#define MPI26_CTRL_OP_PRODUCT_SPECIFIC_MIN              (0x80)
+
+/* values for the PrimFlags field */
+#define MPI26_CTRL_PRIMFLAGS_SINGLE                     (0x08)
+#define MPI26_CTRL_PRIMFLAGS_TRIPLE                     (0x02)
+#define MPI26_CTRL_PRIMFLAGS_REDUNDANT                  (0x01)
+
+/* values for the LookupMethod field */
+#define MPI26_CTRL_LOOKUP_METHOD_WWID_ADDRESS           (0x01)
+#define MPI26_CTRL_LOOKUP_METHOD_ENCLOSURE_SLOT         (0x02)
+#define MPI26_CTRL_LOOKUP_METHOD_SAS_DEVICE_NAME        (0x03)
+
+
+/* IO Unit Control Reply Message */
+typedef struct _MPI26_IOUNIT_CONTROL_REPLY {
+	U8                      Operation;          /* 0x00 */
+	U8                      Reserved1;          /* 0x01 */
+	U8                      MsgLength;          /* 0x02 */
+	U8                      Function;           /* 0x03 */
+	U16                     DevHandle;          /* 0x04 */
+	U8                      IOCParameter;       /* 0x06 */
+	U8                      MsgFlags;           /* 0x07 */
+	U8                      VP_ID;              /* 0x08 */
+	U8                      VF_ID;              /* 0x09 */
+	U16                     Reserved3;          /* 0x0A */
+	U16                     Reserved4;          /* 0x0C */
+	U16                     IOCStatus;          /* 0x0E */
+	U32                     IOCLogInfo;         /* 0x10 */
+} MPI26_IOUNIT_CONTROL_REPLY,
+	*PTR_MPI26_IOUNIT_CONTROL_REPLY,
+	Mpi26IoUnitControlReply_t,
+	*pMpi26IoUnitControlReply_t;
+
+
 #endif
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2014 Avago Technologies.  All rights reserved.
  *
  *
  *          Name:  mpi2_raid.h
  *         Title:  MPI Integrated RAID messages and structures
  * Creation Date:  April 26, 2007
  *
- *   mpi2_raid.h Version:  02.00.10
+ *   mpi2_raid.h Version:  02.00.11
  *
  * Version History
  * ---------------
@@ -31,6 +31,7 @@
  * 07-26-12  02.00.09  Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
  *                     Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
  * 04-17-13  02.00.10  Added MPI25_RAID_ACTION_ADATA_ALLOW_PI.
+ * 11-18-14  02.00.11  Updated copyright information.
  * --------------------------------------------------------------------------
  */
 
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies.  All rights reserved.
  *
  *
  *          Name:  mpi2_sas.h
  *         Title:  MPI Serial Attached SCSI structures and definitions
  * Creation Date:  February 9, 2007
  *
- * mpi2_sas.h Version:  02.00.08
+ * mpi2_sas.h Version:  02.00.10
  *
  * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
  *       prefix are for use only on MPI v2.5 products, and must not be used
@@ -32,6 +32,9 @@
  *                     Passthrough Request message.
  * 08-19-13  02.00.08  Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete
  *			for anything newer than MPI v2.0.
+ * 11-18-14  02.00.09  Updated copyright information.
+ * 03-16-15  02.00.10  Updated for MPI v2.6.
+ *                     Added MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA.
  * --------------------------------------------------------------------------
  */
 
@@ -183,6 +186,7 @@
 
 /*values for PassthroughFlags field */
 #define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG      (0x0100)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA             (0x0040)
 #define MPI2_SATA_PT_REQ_PT_FLAGS_DMA               (0x0020)
 #define MPI2_SATA_PT_REQ_PT_FLAGS_PIO               (0x0010)
 #define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU    (0x0004)
@@ -216,6 +220,8 @@
 
 /****************************************************************************
 * SAS IO Unit Control messages
+* (MPI v2.5 and earlier only.
+* Replaced by IO Unit Control messages in MPI v2.6 and later.)
 ****************************************************************************/
 
 /*SAS IO Unit Control Request Message */
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2014 Avago Technologies.  All rights reserved.
  *
  *
  *          Name:  mpi2_tool.h
  *         Title:  MPI diagnostic tool structures and definitions
  * Creation Date:  March 26, 2007
  *
- *   mpi2_tool.h Version:  02.00.12
+ *   mpi2_tool.h Version:  02.00.13
  *
  * Version History
  * ---------------
@@ -34,6 +34,7 @@
  *                     it uses MPI Chain SGE as well as MPI Simple SGE.
  * 08-19-13  02.00.11  Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
  * 01-08-14  02.00.12  Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
+ * 11-18-14  02.00.13  Updated copyright information.
  * --------------------------------------------------------------------------
  */
 
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpi/mpi2_type.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpi/mpi2_type.h
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2014 LSI Corporation.
+ *  Copyright 2000-2014 Avago Technologies.  All rights reserved.
  *
  *
  *           Name:  mpi2_type.h
  *          Title:  MPI basic type definitions
  *  Creation Date:  August 16, 2006
  *
- *    mpi2_type.h Version:  02.00.00
+ *    mpi2_type.h Version:  02.00.01
  *
  *  Version History
  *  ---------------
@@ -14,6 +14,7 @@
  *  Date      Version   Description
  *  --------  --------  ------------------------------------------------------
  *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  11-18-14  02.00.01  Updated copyright information.
  *  --------------------------------------------------------------------------
  */
 
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -83,6 +83,10 @@
 module_param(msix_disable, int, 0);
 MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
 
+static int smp_affinity_enable = 1;
+module_param(smp_affinity_enable, int, S_IRUGO);
+MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
+
 static int max_msix_vectors = -1;
 module_param(max_msix_vectors, int, 0);
 MODULE_PARM_DESC(max_msix_vectors,
@@ -395,6 +399,9 @@
 	case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
 		desc = "insufficient resources";
 		break;
+	case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
+		desc = "insufficient power";
+		break;
 	case MPI2_IOCSTATUS_INVALID_FIELD:
 		desc = "invalid field";
 		break;
@@ -772,7 +779,7 @@
 
 	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
 	if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
-		return 1;
+		return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
 
 	if (ioc->base_cmds.status == MPT3_CMD_NOT_USED)
 		return 1;
@@ -803,6 +810,7 @@
 	Mpi2EventNotificationReply_t *mpi_reply;
 	Mpi2EventAckRequest_t *ack_request;
 	u16 smid;
+	struct _event_ack_list *delayed_event_ack;
 
 	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
 	if (!mpi_reply)
@@ -816,8 +824,18 @@
 		goto out;
 	smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
 	if (!smid) {
-		pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
-		    ioc->name, __func__);
+		delayed_event_ack = kzalloc(sizeof(*delayed_event_ack),
+					GFP_ATOMIC);
+		if (!delayed_event_ack)
+			goto out;
+		INIT_LIST_HEAD(&delayed_event_ack->list);
+		delayed_event_ack->Event = mpi_reply->Event;
+		delayed_event_ack->EventContext = mpi_reply->EventContext;
+		list_add_tail(&delayed_event_ack->list,
+				&ioc->delayed_event_ack_list);
+		dewtprintk(ioc, pr_info(MPT3SAS_FMT
+				"DELAYED: EVENT ACK: event (0x%04x)\n",
+				ioc->name, le16_to_cpu(mpi_reply->Event)));
 		goto out;
 	}
 
@@ -1348,6 +1366,7 @@
 	u8 sgl_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
 		MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
 		MPI25_IEEE_SGE_FLAGS_END_OF_LIST);
+
 	_base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1);
 }
 
@@ -1686,9 +1705,11 @@
 {
 	struct sysinfo s;
 	u64 consistent_dma_mask;
+	/* Set 63 bit DMA mask for all SAS3 and SAS35 controllers */
+	int dma_mask = (ioc->hba_mpi_version_belonged > MPI2_VERSION) ? 63 : 64;
 
 	if (ioc->dma_mask)
-		consistent_dma_mask = DMA_BIT_MASK(64);
+		consistent_dma_mask = DMA_BIT_MASK(dma_mask);
 	else
 		consistent_dma_mask = DMA_BIT_MASK(32);
 
@@ -1696,11 +1717,11 @@
 		const uint64_t required_mask =
 		    dma_get_required_mask(&pdev->dev);
 		if ((required_mask > DMA_BIT_MASK(32)) &&
-		    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+		    !pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_mask)) &&
 		    !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) {
 			ioc->base_add_sg_single = &_base_add_sg_single_64;
 			ioc->sge_size = sizeof(Mpi2SGESimple64_t);
-			ioc->dma_mask = 64;
+			ioc->dma_mask = dma_mask;
 			goto out;
 		}
 	}
@@ -1726,7 +1747,7 @@
 _base_change_consistent_dma_mask(struct MPT3SAS_ADAPTER *ioc,
 				      struct pci_dev *pdev)
 {
-	if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+	if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ioc->dma_mask))) {
 		if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
 			return -ENODEV;
 	}
@@ -1797,8 +1818,10 @@
 
 	list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
 		list_del(&reply_q->list);
-		irq_set_affinity_hint(reply_q->vector, NULL);
-		free_cpumask_var(reply_q->affinity_hint);
+		if (smp_affinity_enable) {
+			irq_set_affinity_hint(reply_q->vector, NULL);
+			free_cpumask_var(reply_q->affinity_hint);
+		}
 		synchronize_irq(reply_q->vector);
 		free_irq(reply_q->vector, reply_q);
 		kfree(reply_q);
@@ -1829,9 +1852,12 @@
 	reply_q->msix_index = index;
 	reply_q->vector = vector;
 
-	if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL))
-		return -ENOMEM;
-	cpumask_clear(reply_q->affinity_hint);
+	if (smp_affinity_enable) {
+		if (!zalloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) {
+			kfree(reply_q);
+			return -ENOMEM;
+		}
+	}
 
 	atomic_set(&reply_q->busy, 0);
 	if (ioc->msix_enable)
@@ -1845,6 +1871,7 @@
 	if (r) {
 		pr_err(MPT3SAS_FMT "unable to allocate interrupt %d!\n",
 		    reply_q->name, vector);
+		free_cpumask_var(reply_q->affinity_hint);
 		kfree(reply_q);
 		return -EBUSY;
 	}
@@ -1894,16 +1921,17 @@
 
 		for (i = 0 ; i < group ; i++) {
 			ioc->cpu_msix_table[cpu] = index;
-			cpumask_or(reply_q->affinity_hint,
+			if (smp_affinity_enable)
+				cpumask_or(reply_q->affinity_hint,
 				   reply_q->affinity_hint, get_cpu_mask(cpu));
 			cpu = cpumask_next(cpu, cpu_online_mask);
 		}
-
-		if (irq_set_affinity_hint(reply_q->vector,
+		if (smp_affinity_enable)
+			if (irq_set_affinity_hint(reply_q->vector,
 					   reply_q->affinity_hint))
-			dinitprintk(ioc, pr_info(MPT3SAS_FMT
-			    "error setting affinity hint for irq vector %d\n",
-			    ioc->name, reply_q->vector));
+				dinitprintk(ioc, pr_info(MPT3SAS_FMT
+				 "Err setting affinity hint to irq vector %d\n",
+				 ioc->name, reply_q->vector));
 		index++;
 	}
 }
@@ -1961,6 +1989,9 @@
 	} else if (max_msix_vectors == 0)
 		goto try_ioapic;
 
+	if (ioc->msix_vector_count < ioc->cpu_count)
+		smp_affinity_enable = 0;
+
 	entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
 	    GFP_KERNEL);
 	if (!entries) {
@@ -2020,8 +2051,10 @@
 	_base_free_irq(ioc);
 	_base_disable_msix(ioc);
 
-	if (ioc->msix96_vector)
+	if (ioc->msix96_vector) {
 		kfree(ioc->replyPostRegisterIndex);
+		ioc->replyPostRegisterIndex = NULL;
+	}
 
 	if (ioc->chip_phys) {
 		iounmap(ioc->chip);
@@ -2155,6 +2188,17 @@
 	} else
 		ioc->msix96_vector = 0;
 
+	if (ioc->is_warpdrive) {
+		ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
+		    &ioc->chip->ReplyPostHostIndex;
+
+		for (i = 1; i < ioc->cpu_msix_table_sz; i++)
+			ioc->reply_post_host_index[i] =
+			(resource_size_t __iomem *)
+			((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
+			* 4)));
+	}
+
 	list_for_each_entry(reply_q, &ioc->reply_queue_list, list)
 		pr_info(MPT3SAS_FMT "%s: IRQ %d\n",
 		    reply_q->name,  ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
@@ -2229,6 +2273,12 @@
 	return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
 }
 
+static inline u8
+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
+{
+	return ioc->cpu_msix_table[raw_smp_processor_id()];
+}
+
 /**
  * mpt3sas_base_get_smid - obtain a free smid from internal queue
  * @ioc: per adapter object
@@ -2289,6 +2339,7 @@
 	request->scmd = scmd;
 	request->cb_idx = cb_idx;
 	smid = request->smid;
+	request->msix_io = _base_get_msix_index(ioc);
 	list_del(&request->tracker_list);
 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 	return smid;
@@ -2411,12 +2462,6 @@
 }
 #endif
 
-static inline u8
-_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
-{
-	return ioc->cpu_msix_table[raw_smp_processor_id()];
-}
-
 /**
  * mpt3sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
  * @ioc: per adapter object
@@ -2470,18 +2515,19 @@
  * mpt3sas_base_put_smid_hi_priority - send Task Managment request to firmware
  * @ioc: per adapter object
  * @smid: system request message index
- *
+ * @msix_task: msix_task will be same as msix of IO incase of task abort else 0.
  * Return nothing.
  */
 void
-mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+	u16 msix_task)
 {
 	Mpi2RequestDescriptorUnion_t descriptor;
 	u64 *request = (u64 *)&descriptor;
 
 	descriptor.HighPriority.RequestFlags =
 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
-	descriptor.HighPriority.MSIxIndex =  0;
+	descriptor.HighPriority.MSIxIndex =  msix_task;
 	descriptor.HighPriority.SMID = cpu_to_le16(smid);
 	descriptor.HighPriority.LMID = 0;
 	descriptor.HighPriority.Reserved1 = 0;
@@ -3119,7 +3165,9 @@
 		ioc->scsi_lookup = NULL;
 	}
 	kfree(ioc->hpr_lookup);
+	ioc->hpr_lookup = NULL;
 	kfree(ioc->internal_lookup);
+	ioc->internal_lookup = NULL;
 	if (ioc->chain_lookup) {
 		for (i = 0; i < ioc->chain_depth; i++) {
 			if (ioc->chain_lookup[i].chain_buffer)
@@ -3183,20 +3231,35 @@
 	}
 	ioc->shost->sg_tablesize = sg_tablesize;
 
-	ioc->hi_priority_depth = facts->HighPriorityCredit;
-	ioc->internal_depth = ioc->hi_priority_depth + (5);
+	ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)),
+		(facts->RequestCredit / 4));
+	if (ioc->internal_depth < INTERNAL_CMDS_COUNT) {
+		if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT +
+				INTERNAL_SCSIIO_CMDS_COUNT)) {
+			pr_err(MPT3SAS_FMT "IOC doesn't have enough Request \
+			    Credits, it has just %d number of credits\n",
+			    ioc->name, facts->RequestCredit);
+			return -ENOMEM;
+		}
+		ioc->internal_depth = 10;
+	}
+
+	ioc->hi_priority_depth = ioc->internal_depth - (5);
 	/* command line tunables  for max controller queue depth */
 	if (max_queue_depth != -1 && max_queue_depth != 0) {
 		max_request_credit = min_t(u16, max_queue_depth +
-		    ioc->hi_priority_depth + ioc->internal_depth,
-		    facts->RequestCredit);
+			ioc->internal_depth, facts->RequestCredit);
 		if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
 			max_request_credit =  MAX_HBA_QUEUE_DEPTH;
 	} else
 		max_request_credit = min_t(u16, facts->RequestCredit,
 		    MAX_HBA_QUEUE_DEPTH);
 
-	ioc->hba_queue_depth = max_request_credit;
+	/* Firmware maintains additional facts->HighPriorityCredit number of
+	 * credits for HiPriprity Request messages, so hba queue depth will be
+	 * sum of max_request_credit and high priority queue depth.
+	 */
+	ioc->hba_queue_depth = max_request_credit + ioc->hi_priority_depth;
 
 	/* request frame size */
 	ioc->request_sz = facts->IOCRequestFrameSize * 4;
@@ -3204,6 +3267,19 @@
 	/* reply frame size */
 	ioc->reply_sz = facts->ReplyFrameSize * 4;
 
+	/* chain segment size */
+	if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+		if (facts->IOCMaxChainSegmentSize)
+			ioc->chain_segment_sz =
+					facts->IOCMaxChainSegmentSize *
+					MAX_CHAIN_ELEMT_SZ;
+		else
+		/* set to 128 bytes size if IOCMaxChainSegmentSize is zero */
+			ioc->chain_segment_sz = DEFAULT_NUM_FWCHAIN_ELEMTS *
+						    MAX_CHAIN_ELEMT_SZ;
+	} else
+		ioc->chain_segment_sz = ioc->request_sz;
+
 	/* calculate the max scatter element size */
 	sge_size = max_t(u16, ioc->sge_size, ioc->sge_size_ieee);
 
@@ -3215,7 +3291,7 @@
 	ioc->max_sges_in_main_message = max_sge_elements/sge_size;
 
 	/* now do the same for a chain buffer */
-	max_sge_elements = ioc->request_sz - sge_size;
+	max_sge_elements = ioc->chain_segment_sz - sge_size;
 	ioc->max_sges_in_chain_message = max_sge_elements/sge_size;
 
 	/*
@@ -3243,7 +3319,6 @@
 		ioc->reply_post_queue_depth += 16 -
 		(ioc->reply_post_queue_depth % 16);
 
-
 	if (ioc->reply_post_queue_depth >
 	    facts->MaxReplyDescriptorPostQueueDepth) {
 		ioc->reply_post_queue_depth =
@@ -3310,7 +3385,7 @@
 		total_sz += sz;
 	} while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
 
-	if (ioc->dma_mask == 64) {
+	if (ioc->dma_mask > 32) {
 		if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
 			pr_warn(MPT3SAS_FMT
 			    "no suitable consistent DMA mask for %s\n",
@@ -3325,7 +3400,7 @@
 	/* set the scsi host can_queue depth
 	 * with some internal commands that could be outstanding
 	 */
-	ioc->shost->can_queue = ioc->scsiio_depth;
+	ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT;
 	dinitprintk(ioc, pr_info(MPT3SAS_FMT
 		"scsi host: can_queue depth (%d)\n",
 		ioc->name, ioc->shost->can_queue));
@@ -3352,8 +3427,8 @@
 		    ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
 		if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH)
 			goto out;
-		retry_sz += 64;
-		ioc->hba_queue_depth = max_request_credit - retry_sz;
+		retry_sz = 64;
+		ioc->hba_queue_depth -= retry_sz;
 		goto retry_allocation;
 	}
 
@@ -3408,7 +3483,7 @@
 		goto out;
 	}
 	ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
-	    ioc->request_sz, 16, 0);
+	    ioc->chain_segment_sz, 16, 0);
 	if (!ioc->chain_dma_pool) {
 		pr_err(MPT3SAS_FMT "chain_dma_pool: pci_pool_create failed\n",
 			ioc->name);
@@ -3422,13 +3497,13 @@
 			ioc->chain_depth = i;
 			goto chain_done;
 		}
-		total_sz += ioc->request_sz;
+		total_sz += ioc->chain_segment_sz;
 	}
  chain_done:
 	dinitprintk(ioc, pr_info(MPT3SAS_FMT
 		"chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n",
-		ioc->name, ioc->chain_depth, ioc->request_sz,
-		((ioc->chain_depth *  ioc->request_sz))/1024));
+		ioc->name, ioc->chain_depth, ioc->chain_segment_sz,
+		((ioc->chain_depth *  ioc->chain_segment_sz))/1024));
 
 	/* initialize hi-priority queue smid's */
 	ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
@@ -4289,6 +4364,10 @@
 	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
 	facts->IOCRequestFrameSize =
 	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+	if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+		facts->IOCMaxChainSegmentSize =
+			le16_to_cpu(mpi_reply.IOCMaxChainSegmentSize);
+	}
 	facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
 	facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
 	ioc->shost->max_id = -1;
@@ -4966,15 +5045,16 @@
 static int
 _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 {
-	int r, i;
+	int r, i, index;
 	unsigned long	flags;
 	u32 reply_address;
 	u16 smid;
 	struct _tr_list *delayed_tr, *delayed_tr_next;
+	struct _sc_list *delayed_sc, *delayed_sc_next;
+	struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next;
 	u8 hide_flag;
 	struct adapter_reply_queue *reply_q;
-	long reply_post_free;
-	u32 reply_post_free_sz, index = 0;
+	Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig;
 
 	dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
 	    __func__));
@@ -4993,6 +5073,18 @@
 		kfree(delayed_tr);
 	}
 
+	list_for_each_entry_safe(delayed_sc, delayed_sc_next,
+	    &ioc->delayed_sc_list, list) {
+		list_del(&delayed_sc->list);
+		kfree(delayed_sc);
+	}
+
+	list_for_each_entry_safe(delayed_event_ack, delayed_event_ack_next,
+	    &ioc->delayed_event_ack_list, list) {
+		list_del(&delayed_event_ack->list);
+		kfree(delayed_event_ack);
+	}
+
 	/* initialize the scsi lookup free list */
 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
 	INIT_LIST_HEAD(&ioc->free_list);
@@ -5046,27 +5138,26 @@
 		_base_assign_reply_queues(ioc);
 
 	/* initialize Reply Post Free Queue */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	reply_post_free = (long)ioc->reply_post[index].reply_post_free;
+	index = 0;
+	reply_post_free_contig = ioc->reply_post[0].reply_post_free;
 	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+		/*
+		 * If RDPQ is enabled, switch to the next allocation.
+		 * Otherwise advance within the contiguous region.
+		 */
+		if (ioc->rdpq_array_enable) {
+			reply_q->reply_post_free =
+				ioc->reply_post[index++].reply_post_free;
+		} else {
+			reply_q->reply_post_free = reply_post_free_contig;
+			reply_post_free_contig += ioc->reply_post_queue_depth;
+		}
 		reply_q->reply_post_host_index = 0;
-		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
-		    reply_post_free;
 		for (i = 0; i < ioc->reply_post_queue_depth; i++)
 			reply_q->reply_post_free[i].Words =
 			    cpu_to_le64(ULLONG_MAX);
 		if (!_base_is_controller_msix_enabled(ioc))
 			goto skip_init_reply_post_free_queue;
-		/*
-		 * If RDPQ is enabled, switch to the next allocation.
-		 * Otherwise advance within the contiguous region.
-		 */
-		if (ioc->rdpq_array_enable)
-			reply_post_free = (long)
-			    ioc->reply_post[++index].reply_post_free;
-		else
-			reply_post_free += reply_post_free_sz;
 	}
  skip_init_reply_post_free_queue:
 
@@ -5201,17 +5292,6 @@
 	if (r)
 		goto out_free_resources;
 
-	if (ioc->is_warpdrive) {
-		ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
-		    &ioc->chip->ReplyPostHostIndex;
-
-		for (i = 1; i < ioc->cpu_msix_table_sz; i++)
-			ioc->reply_post_host_index[i] =
-			(resource_size_t __iomem *)
-			((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
-			* 4)));
-	}
-
 	pci_set_drvdata(ioc->pdev, ioc->shost);
 	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
 	if (r)
@@ -5224,6 +5304,7 @@
 		ioc->build_zero_len_sge = &_base_build_zero_len_sge;
 		break;
 	case MPI25_VERSION:
+	case MPI26_VERSION:
 		/*
 		 * In SAS3.0,
 		 * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -73,9 +73,9 @@
 #define MPT3SAS_DRIVER_NAME		"mpt3sas"
 #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
 #define MPT3SAS_DESCRIPTION	"LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION		"09.102.00.00"
-#define MPT3SAS_MAJOR_VERSION		9
-#define MPT3SAS_MINOR_VERSION		102
+#define MPT3SAS_DRIVER_VERSION		"12.100.00.00"
+#define MPT3SAS_MAJOR_VERSION		12
+#define MPT3SAS_MINOR_VERSION		100
 #define MPT3SAS_BUILD_VERSION		0
 #define MPT3SAS_RELEASE_VERSION	00
 
@@ -122,11 +122,16 @@
 #define  NO_SLEEP			0
 
 #define INTERNAL_CMDS_COUNT		10	/* reserved cmds */
+/* reserved for issuing internally framed scsi io cmds */
+#define INTERNAL_SCSIIO_CMDS_COUNT	3
 
 #define MPI3_HIM_MASK			0xFFFFFFFF /* mask every bit*/
 
 #define MPT3SAS_INVALID_DEVICE_HANDLE	0xFFFF
 
+#define MAX_CHAIN_ELEMT_SZ		16
+#define DEFAULT_NUM_FWCHAIN_ELEMTS	8
+
 /*
  * reset phases
  */
@@ -390,6 +395,7 @@
  * @eedp_enable: eedp support enable bit
  * @eedp_type: 0(type_1), 1(type_2), 2(type_3)
  * @eedp_block_length: block size
+ * @ata_command_pending: SATL passthrough outstanding for device
  */
 struct MPT3SAS_DEVICE {
 	struct MPT3SAS_TARGET *sas_target;
@@ -398,6 +404,18 @@
 	u8	configured_lun;
 	u8	block;
 	u8	tlr_snoop_check;
+	u8	ignore_delay_remove;
+	/*
+	 * Bug workaround for SATL handling: the mpt2/3sas firmware
+	 * doesn't return BUSY or TASK_SET_FULL for subsequent
+	 * commands while a SATL pass through is in operation as the
+	 * spec requires, it simply does nothing with them until the
+	 * pass through completes, causing them possibly to timeout if
+	 * the passthrough is a long executing command (like format or
+	 * secure erase).  This variable allows us to do the right
+	 * thing while a SATL command is pending.
+	 */
+	unsigned long ata_command_pending;
 };
 
 #define MPT3_CMD_NOT_USED	0x8000	/* free */
@@ -643,6 +661,7 @@
  * @cb_idx: callback index
  * @direct_io: To indicate whether I/O is direct (WARPDRIVE)
  * @tracker_list: list of free request (ioc->free_list)
+ * @msix_io: IO's msix
  */
 struct scsiio_tracker {
 	u16	smid;
@@ -651,6 +670,7 @@
 	u8	direct_io;
 	struct list_head chain_list;
 	struct list_head tracker_list;
+	u16     msix_io;
 };
 
 /**
@@ -676,6 +696,25 @@
 	u16	state;
 };
 
+/**
+ * struct _sc_list - delayed SAS_IO_UNIT_CONTROL message list
+ * @handle: device handle
+ */
+struct _sc_list {
+	struct list_head list;
+	u16     handle;
+};
+
+/**
+ * struct _event_ack_list - delayed event acknowledgment list
+ * @Event: Event ID
+ * @EventContext: used to track the event uniquely
+ */
+struct _event_ack_list {
+	struct list_head list;
+	u16     Event;
+	u32     EventContext;
+};
 
 /**
  * struct adapter_reply_queue - the reply queue struct
@@ -737,7 +776,7 @@
 	u32			IOCCapabilities;
 	union mpi3_version_union	FWVersion;
 	u16			IOCRequestFrameSize;
-	u16			Reserved3;
+	u16			IOCMaxChainSegmentSize;
 	u16			MaxInitiators;
 	u16			MaxTargets;
 	u16			MaxSasExpanders;
@@ -884,6 +923,8 @@
  * @max_sges_in_chain_message: number sg elements per chain
  * @chains_needed_per_io: max chains per io
  * @chain_depth: total chains allocated
+ * @chain_segment_sz: gives the max number of
+ *			SGEs accommodate on single chain buffer
  * @hi_priority_smid:
  * @hi_priority:
  * @hi_priority_dma:
@@ -921,6 +962,8 @@
  * @replyPostRegisterIndex: index of next position in Reply Desc Post Queue
  * @delayed_tr_list: target reset link list
  * @delayed_tr_volume_list: volume target reset link list
+ * @delayed_sc_list:
+ * @delayed_event_ack_list:
  * @temp_sensors_count: flag to carry the number of temperature sensors
  * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and
  *	pci resource handling. PCI resource freeing will lead to free
@@ -1089,6 +1132,7 @@
 	u16		max_sges_in_chain_message;
 	u16		chains_needed_per_io;
 	u32		chain_depth;
+	u16		chain_segment_sz;
 
 	/* hi-priority queue */
 	u16		hi_priority_smid;
@@ -1142,6 +1186,8 @@
 
 	struct list_head delayed_tr_list;
 	struct list_head delayed_tr_volume_list;
+	struct list_head delayed_sc_list;
+	struct list_head delayed_event_ack_list;
 	u8		temp_sensors_count;
 	struct mutex pci_access_mutex;
 
@@ -1213,7 +1259,8 @@
 	u16 handle);
 void mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
 	u16 handle);
-void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc,
+	u16 smid, u16 msix_task);
 void mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid);
 void mpt3sas_base_initialize_callback_handler(void);
 u8 mpt3sas_base_register_callback_handler(MPT_CALLBACK cb_func);
@@ -1259,6 +1306,8 @@
 void mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
 void mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
 	u64 sas_address);
+u8 mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc,
+	u16 smid);
 
 struct _sas_node *mpt3sas_scsih_expander_find_by_handle(
 	struct MPT3SAS_ADAPTER *ioc, u16 handle);
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -677,10 +677,6 @@
 	r = _config_request(ioc, &mpi_request, mpi_reply,
 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
 	    sizeof(*config_page));
-	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
-	r = _config_request(ioc, &mpi_request, mpi_reply,
-	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
-	    sizeof(*config_page));
  out:
 	return r;
 }
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -401,7 +401,8 @@
 	Mpi2EventNotificationReply_t *mpi_reply;
 
 	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
-	mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
+	if (mpi_reply)
+		mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
 	return 1;
 }
 
@@ -410,7 +411,7 @@
  * @ioc: per adapter object
  * @iocpp: The ioc pointer is returned in this.
  * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
- *		MPI25_VERSION for mpt3ctl ioctl device.
+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device.
  *
  * Return (-1) means error, else ioc_number.
  */
@@ -419,6 +420,7 @@
 							int mpi_version)
 {
 	struct MPT3SAS_ADAPTER *ioc;
+	int version = 0;
 	/* global ioc lock to protect controller on list operations */
 	spin_lock(&gioc_lock);
 	list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
@@ -427,8 +429,21 @@
 		/* Check whether this ioctl command is from right
 		 * ioctl device or not, if not continue the search.
 		 */
-		if (ioc->hba_mpi_version_belonged != mpi_version)
-			continue;
+		version = ioc->hba_mpi_version_belonged;
+		/* MPI25_VERSION and MPI26_VERSION uses same ioctl
+		 * device.
+		 */
+		if (mpi_version == (MPI25_VERSION | MPI26_VERSION)) {
+			if ((version == MPI25_VERSION) ||
+				(version == MPI26_VERSION))
+				goto out;
+			else
+				continue;
+		} else {
+			if (version != mpi_version)
+				continue;
+		}
+out:
 		spin_unlock(&gioc_lock);
 		*iocpp = ioc;
 		return ioc_number;
@@ -817,7 +832,7 @@
 		    tm_request->DevHandle));
 		ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
 		    data_in_dma, data_in_sz);
-		mpt3sas_base_put_smid_hi_priority(ioc, smid);
+		mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
 		break;
 	}
 	case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -1053,6 +1068,7 @@
 		strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);
 		break;
 	case MPI25_VERSION:
+	case MPI26_VERSION:
 		karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3;
 		strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
 		break;
@@ -1456,7 +1472,8 @@
 			    " for diag buffers, requested size(%d)\n",
 			    ioc->name, __func__, request_data_sz);
 			mpt3sas_base_free_smid(ioc, smid);
-			return -ENOMEM;
+			rc = -ENOMEM;
+			goto out;
 		}
 		ioc->diag_buffer[buffer_type] = request_data;
 		ioc->diag_buffer_sz[buffer_type] = request_data_sz;
@@ -2203,7 +2220,7 @@
  * @arg - user space data buffer
  * @compat - handles 32 bit applications in 64bit os
  * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
- *		MPI25_VERSION for mpt3ctl ioctl device.
+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device.
  */
 static long
 _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
@@ -2341,10 +2358,12 @@
 {
 	long ret;
 
-	/* pass MPI25_VERSION value, to indicate that this ioctl cmd
+	/* pass MPI25_VERSION | MPI26_VERSION value,
+	 * to indicate that this ioctl cmd
 	 * came from mpt3ctl ioctl device.
 	 */
-	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI25_VERSION);
+	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0,
+		MPI25_VERSION | MPI26_VERSION);
 	return ret;
 }
 
@@ -2379,7 +2398,8 @@
 {
 	long ret;
 
-	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI25_VERSION);
+	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1,
+		MPI25_VERSION | MPI26_VERSION);
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -51,6 +51,7 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/interrupt.h>
 #include <linux/aer.h>
 #include <linux/raid_class.h>
@@ -1275,9 +1276,9 @@
 			sas_target_priv_data->handle = raid_device->handle;
 			sas_target_priv_data->sas_address = raid_device->wwid;
 			sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
-			sas_target_priv_data->raid_device = raid_device;
 			if (ioc->is_warpdrive)
-				raid_device->starget = starget;
+				sas_target_priv_data->raid_device = raid_device;
+			raid_device->starget = starget;
 		}
 		spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
 		return 0;
@@ -1589,10 +1590,16 @@
 		percent_complete = 0;
 
  out:
-	if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+
+	switch (ioc->hba_mpi_version_belonged) {
+	case MPI2_VERSION:
 		raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
-	if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+		break;
+	case MPI25_VERSION:
+	case MPI26_VERSION:
 		raid_set_resync(mpt3sas_raid_template, dev, percent_complete);
+		break;
+	}
 }
 
 /**
@@ -1650,10 +1657,15 @@
 		break;
 	}
  out:
-	if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+	switch (ioc->hba_mpi_version_belonged) {
+	case MPI2_VERSION:
 		raid_set_state(mpt2sas_raid_template, dev, state);
-	if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+		break;
+	case MPI25_VERSION:
+	case MPI26_VERSION:
 		raid_set_state(mpt3sas_raid_template, dev, state);
+		break;
+	}
 }
 
 /**
@@ -1682,12 +1694,17 @@
 		break;
 	}
 
-	if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+	switch (ioc->hba_mpi_version_belonged) {
+	case MPI2_VERSION:
 		raid_set_level(mpt2sas_raid_template,
-			       &sdev->sdev_gendev, level);
-	if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+			&sdev->sdev_gendev, level);
+		break;
+	case MPI25_VERSION:
+	case MPI26_VERSION:
 		raid_set_level(mpt3sas_raid_template,
-			       &sdev->sdev_gendev, level);
+			&sdev->sdev_gendev, level);
+		break;
+	}
 }
 
 
@@ -1937,7 +1954,15 @@
 	if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
 		qdepth = MPT3SAS_SAS_QUEUE_DEPTH;
 		ssp_target = 1;
-		ds = "SSP";
+		if (sas_device->device_info &
+				MPI2_SAS_DEVICE_INFO_SEP) {
+			sdev_printk(KERN_WARNING, sdev,
+			"set ignore_delay_remove for handle(0x%04x)\n",
+			sas_device_priv_data->sas_target->handle);
+			sas_device_priv_data->ignore_delay_remove = 1;
+			ds = "SES";
+		} else
+			ds = "SSP";
 	} else {
 		qdepth = MPT3SAS_SATA_QUEUE_DEPTH;
 		if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
@@ -2193,6 +2218,7 @@
 	unsigned long timeleft;
 	struct scsiio_tracker *scsi_lookup = NULL;
 	int rc;
+	u16 msix_task = 0;
 
 	if (m_type == TM_MUTEX_ON)
 		mutex_lock(&ioc->tm_cmds.mutex);
@@ -2256,7 +2282,12 @@
 	int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
 	mpt3sas_scsih_set_tm_flag(ioc, handle);
 	init_completion(&ioc->tm_cmds.done);
-	mpt3sas_base_put_smid_hi_priority(ioc, smid);
+	if ((type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) &&
+			(scsi_lookup->msix_io < ioc->reply_queue_count))
+		msix_task = scsi_lookup->msix_io;
+	else
+		msix_task = 0;
+	mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task);
 	timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
 	if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
 		pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -2383,7 +2414,7 @@
 				 (unsigned long long)
 				 sas_device->enclosure_logical_id,
 				 sas_device->slot);
-			if (sas_device->connector_name)
+			if (sas_device->connector_name[0] != '\0')
 				starget_printk(KERN_INFO, starget,
 				"enclosure level(0x%04x),connector name(%s)\n",
 				 sas_device->enclosure_level,
@@ -2927,6 +2958,12 @@
 			continue;
 		if (sas_device_priv_data->block)
 			continue;
+		if (sas_device_priv_data->ignore_delay_remove) {
+			sdev_printk(KERN_INFO, sdev,
+			"%s skip device_block for SES handle(0x%04x)\n",
+			__func__, sas_device_priv_data->sas_target->handle);
+			continue;
+		}
 		_scsih_internal_device_block(sdev, sas_device_priv_data);
 	}
 }
@@ -2959,6 +2996,12 @@
 			continue;
 		if (sas_device->pend_sas_rphy_add)
 			continue;
+		if (sas_device_priv_data->ignore_delay_remove) {
+			sdev_printk(KERN_INFO, sdev,
+			"%s skip device_block for SES handle(0x%04x)\n",
+			__func__, sas_device_priv_data->sas_target->handle);
+			continue;
+		}
 		_scsih_internal_device_block(sdev, sas_device_priv_data);
 	}
 
@@ -3118,7 +3161,7 @@
 			 " slot(%d)\n", ioc->name, (unsigned long long)
 			  sas_device->enclosure_logical_id,
 			  sas_device->slot));
-		if (sas_device->connector_name)
+		if (sas_device->connector_name[0] != '\0')
 			dewtprintk(ioc, pr_info(MPT3SAS_FMT
 			 "setting delete flag: enclosure level(0x%04x),"
 			 " connector name( %s)\n", ioc->name,
@@ -3151,7 +3194,7 @@
 	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
 	mpi_request->DevHandle = cpu_to_le16(handle);
 	mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-	mpt3sas_base_put_smid_hi_priority(ioc, smid);
+	mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
 	mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
 
 out:
@@ -3186,6 +3229,7 @@
 	Mpi2SasIoUnitControlRequest_t *mpi_request;
 	u16 smid_sas_ctrl;
 	u32 ioc_state;
+	struct _sc_list *delayed_sc;
 
 	if (ioc->remove_host) {
 		dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -3228,9 +3272,16 @@
 
 	smid_sas_ctrl = mpt3sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
 	if (!smid_sas_ctrl) {
-		pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
-		    ioc->name, __func__);
-		return 1;
+		delayed_sc = kzalloc(sizeof(*delayed_sc), GFP_ATOMIC);
+		if (!delayed_sc)
+			return _scsih_check_for_pending_tm(ioc, smid);
+		INIT_LIST_HEAD(&delayed_sc->list);
+		delayed_sc->handle = mpi_request_tm->DevHandle;
+		list_add_tail(&delayed_sc->list, &ioc->delayed_sc_list);
+		dewtprintk(ioc, pr_info(MPT3SAS_FMT
+		    "DELAYED:sc:handle(0x%04x), (open)\n",
+		    ioc->name, handle));
+		return _scsih_check_for_pending_tm(ioc, smid);
 	}
 
 	dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -3247,6 +3298,40 @@
 	return _scsih_check_for_pending_tm(ioc, smid);
 }
 
+/** _scsih_allow_scmd_to_device - check whether scmd needs to
+ *				 issue to IOC or not.
+ * @ioc: per adapter object
+ * @scmd: pointer to scsi command object
+ *
+ * Returns true if scmd can be issued to IOC otherwise returns false.
+ */
+inline bool _scsih_allow_scmd_to_device(struct MPT3SAS_ADAPTER *ioc,
+	struct scsi_cmnd *scmd)
+{
+
+	if (ioc->pci_error_recovery)
+		return false;
+
+	if (ioc->hba_mpi_version_belonged == MPI2_VERSION) {
+		if (ioc->remove_host)
+			return false;
+
+		return true;
+	}
+
+	if (ioc->remove_host) {
+
+		switch (scmd->cmnd[0]) {
+		case SYNCHRONIZE_CACHE:
+		case START_STOP:
+			return true;
+		default:
+			return false;
+		}
+	}
+
+	return true;
+}
 
 /**
  * _scsih_sas_control_complete - completion routine
@@ -3281,7 +3366,7 @@
 		pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
 		    ioc->name, __FILE__, __LINE__, __func__);
 	}
-	return 1;
+	return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
 }
 
 /**
@@ -3332,7 +3417,7 @@
 	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
 	mpi_request->DevHandle = cpu_to_le16(handle);
 	mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-	mpt3sas_base_put_smid_hi_priority(ioc, smid);
+	mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
 }
 
 /**
@@ -3388,6 +3473,142 @@
 	return _scsih_check_for_pending_tm(ioc, smid);
 }
 
+/**
+ * _scsih_issue_delayed_event_ack - issue delayed Event ACK messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @event: Event ID
+ * @event_context: used to track events uniquely
+ *
+ * Context - processed in interrupt context.
+ */
+void
+_scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event,
+				u32 event_context)
+{
+	Mpi2EventAckRequest_t *ack_request;
+	int i = smid - ioc->internal_smid;
+	unsigned long flags;
+
+	/* Without releasing the smid just update the
+	 * call back index and reuse the same smid for
+	 * processing this delayed request
+	 */
+	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+	ioc->internal_lookup[i].cb_idx = ioc->base_cb_idx;
+	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+	dewtprintk(ioc, pr_info(MPT3SAS_FMT
+		"EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n",
+		ioc->name, le16_to_cpu(event), smid,
+		ioc->base_cb_idx));
+	ack_request = mpt3sas_base_get_msg_frame(ioc, smid);
+	memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
+	ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
+	ack_request->Event = event;
+	ack_request->EventContext = event_context;
+	ack_request->VF_ID = 0;  /* TODO */
+	ack_request->VP_ID = 0;
+	mpt3sas_base_put_smid_default(ioc, smid);
+}
+
+/**
+ * _scsih_issue_delayed_sas_io_unit_ctrl - issue delayed
+ *				sas_io_unit_ctrl messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle
+ *
+ * Context - processed in interrupt context.
+ */
+void
+_scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
+					u16 smid, u16 handle)
+	{
+		Mpi2SasIoUnitControlRequest_t *mpi_request;
+		u32 ioc_state;
+		int i = smid - ioc->internal_smid;
+		unsigned long flags;
+
+		if (ioc->remove_host) {
+			dewtprintk(ioc, pr_info(MPT3SAS_FMT
+			    "%s: host has been removed\n",
+			     __func__, ioc->name));
+			return;
+		} else if (ioc->pci_error_recovery) {
+			dewtprintk(ioc, pr_info(MPT3SAS_FMT
+			    "%s: host in pci error recovery\n",
+			    __func__, ioc->name));
+		return;
+	}
+	ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
+	if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+		dewtprintk(ioc, pr_info(MPT3SAS_FMT
+		    "%s: host is not operational\n",
+		    __func__, ioc->name));
+		return;
+	}
+
+	/* Without releasing the smid just update the
+	 * call back index and reuse the same smid for
+	 * processing this delayed request
+	 */
+	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+	ioc->internal_lookup[i].cb_idx = ioc->tm_sas_control_cb_idx;
+	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+	dewtprintk(ioc, pr_info(MPT3SAS_FMT
+	    "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
+	    ioc->name, le16_to_cpu(handle), smid,
+	    ioc->tm_sas_control_cb_idx));
+	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
+	memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
+	mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
+	mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
+	mpi_request->DevHandle = handle;
+	mpt3sas_base_put_smid_default(ioc, smid);
+}
+
+/**
+ * _scsih_check_for_pending_internal_cmds - check for pending internal messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Context: Executed in interrupt context
+ *
+ * This will check delayed internal messages list, and process the
+ * next request.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ *        0 means the mf is freed from this function.
+ */
+u8
+mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+	struct _sc_list *delayed_sc;
+	struct _event_ack_list *delayed_event_ack;
+
+	if (!list_empty(&ioc->delayed_event_ack_list)) {
+		delayed_event_ack = list_entry(ioc->delayed_event_ack_list.next,
+						struct _event_ack_list, list);
+		_scsih_issue_delayed_event_ack(ioc, smid,
+		  delayed_event_ack->Event, delayed_event_ack->EventContext);
+		list_del(&delayed_event_ack->list);
+		kfree(delayed_event_ack);
+		return 0;
+	}
+
+	if (!list_empty(&ioc->delayed_sc_list)) {
+		delayed_sc = list_entry(ioc->delayed_sc_list.next,
+						struct _sc_list, list);
+		_scsih_issue_delayed_sas_io_unit_ctrl(ioc, smid,
+						 delayed_sc->handle);
+		list_del(&delayed_sc->list);
+		kfree(delayed_sc);
+		return 0;
+	}
+	return 1;
+}
 
 /**
  * _scsih_check_for_pending_tm - check for pending task management
@@ -3700,6 +3921,20 @@
 	}
 }
 
+static int _scsih_set_satl_pending(struct scsi_cmnd *scmd, bool pending)
+{
+	struct MPT3SAS_DEVICE *priv = scmd->device->hostdata;
+
+	if (scmd->cmnd[0] != ATA_12 && scmd->cmnd[0] != ATA_16)
+		return 0;
+
+	if (pending)
+		return test_and_set_bit(0, &priv->ata_command_pending);
+
+	clear_bit(0, &priv->ata_command_pending);
+	return 0;
+}
+
 /**
  * _scsih_flush_running_cmds - completing outstanding commands.
  * @ioc: per adapter object
@@ -3721,6 +3956,7 @@
 		if (!scmd)
 			continue;
 		count++;
+		_scsih_set_satl_pending(scmd, false);
 		mpt3sas_base_free_smid(ioc, smid);
 		scsi_dma_unmap(scmd);
 		if (ioc->pci_error_recovery)
@@ -3825,8 +4061,6 @@
 	    SAM_STAT_CHECK_CONDITION;
 }
 
-
-
 /**
  * scsih_qcmd - main scsi request entry point
  * @scmd: pointer to scsi command object
@@ -3860,7 +4094,7 @@
 		return 0;
 	}
 
-	if (ioc->pci_error_recovery || ioc->remove_host) {
+	if (!(_scsih_allow_scmd_to_device(ioc, scmd))) {
 		scmd->result = DID_NO_CONNECT << 16;
 		scmd->scsi_done(scmd);
 		return 0;
@@ -3891,6 +4125,19 @@
 	    sas_device_priv_data->block)
 		return SCSI_MLQUEUE_DEVICE_BUSY;
 
+	/*
+	 * Bug work around for firmware SATL handling.  The loop
+	 * is based on atomic operations and ensures consistency
+	 * since we're lockless at this point
+	 */
+	do {
+		if (test_bit(0, &sas_device_priv_data->ata_command_pending)) {
+			scmd->result = SAM_STAT_BUSY;
+			scmd->scsi_done(scmd);
+			return 0;
+		}
+	} while (_scsih_set_satl_pending(scmd, true));
+
 	if (scmd->sc_data_direction == DMA_FROM_DEVICE)
 		mpi_control = MPI2_SCSIIO_CONTROL_READ;
 	else if (scmd->sc_data_direction == DMA_TO_DEVICE)
@@ -3912,6 +4159,7 @@
 	if (!smid) {
 		pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
 		    ioc->name, __func__);
+		_scsih_set_satl_pending(scmd, false);
 		goto out;
 	}
 	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
@@ -3942,6 +4190,7 @@
 	if (mpi_request->DataLength) {
 		if (ioc->build_sg_scmd(ioc, scmd, smid)) {
 			mpt3sas_base_free_smid(ioc, smid);
+			_scsih_set_satl_pending(scmd, false);
 			goto out;
 		}
 	} else
@@ -4084,6 +4333,9 @@
 	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
 		desc_ioc_state = "eedp app tag error";
 		break;
+	case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
+		desc_ioc_state = "insufficient power";
+		break;
 	default:
 		desc_ioc_state = "unknown";
 		break;
@@ -4419,12 +4671,15 @@
 	struct MPT3SAS_DEVICE *sas_device_priv_data;
 	u32 response_code = 0;
 	unsigned long flags;
+	unsigned int sector_sz;
 
 	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
 	scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
 	if (scmd == NULL)
 		return 1;
 
+	_scsih_set_satl_pending(scmd, false);
+
 	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
 
 	if (mpi_reply == NULL) {
@@ -4475,6 +4730,20 @@
 	}
 
 	xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
+
+	/* In case of bogus fw or device, we could end up having
+	 * unaligned partial completion. We can force alignment here,
+	 * then scsi-ml does not need to handle this misbehavior.
+	 */
+	sector_sz = scmd->device->sector_size;
+	if (unlikely(scmd->request->cmd_type == REQ_TYPE_FS && sector_sz &&
+		     xfer_cnt % sector_sz)) {
+		sdev_printk(KERN_INFO, scmd->device,
+		    "unaligned partial completion avoided (xfer_cnt=%u, sector_sz=%u)\n",
+			    xfer_cnt, sector_sz);
+		xfer_cnt = round_down(xfer_cnt, sector_sz);
+	}
+
 	scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
 	if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
 		log_info =  le32_to_cpu(mpi_reply->IOCLogInfo);
@@ -4504,7 +4773,7 @@
 			    le16_to_cpu(mpi_reply->DevHandle));
 		mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq);
 
-		if (!(ioc->logging_level & MPT_DEBUG_REPLY) &&
+		if ((ioc->logging_level & MPT_DEBUG_REPLY) &&
 		     ((scmd->sense_buffer[2] == UNIT_ATTENTION) ||
 		     (scmd->sense_buffer[2] == MEDIUM_ERROR) ||
 		     (scmd->sense_buffer[2] == HARDWARE_ERROR)))
@@ -4538,6 +4807,11 @@
 		} else if (log_info == VIRTUAL_IO_FAILED_RETRY) {
 			scmd->result = DID_RESET << 16;
 			break;
+		} else if ((scmd->device->channel == RAID_CHANNEL) &&
+		   (scsi_state == (MPI2_SCSI_STATE_TERMINATED |
+		   MPI2_SCSI_STATE_NO_SCSI_STATUS))) {
+			scmd->result = DID_RESET << 16;
+			break;
 		}
 		scmd->result = DID_SOFT_ERROR << 16;
 		break;
@@ -4609,6 +4883,7 @@
 	case MPI2_IOCSTATUS_INVALID_STATE:
 	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
 	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+	case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
 	default:
 		scmd->result = DID_SOFT_ERROR << 16;
 		break;
@@ -8391,7 +8666,8 @@
  * @pdev: PCI device struct
  *
  * return MPI2_VERSION for SAS 2.0 HBA devices,
- *	MPI25_VERSION for SAS 3.0 HBA devices.
+ *	MPI25_VERSION for SAS 3.0 HBA devices, and
+ *	MPI26 VERSION for Cutlass & Invader SAS 3.0 HBA devices
  */
 u16
 _scsih_determine_hba_mpi_version(struct pci_dev *pdev)
@@ -8423,6 +8699,17 @@
 	case MPI25_MFGPAGE_DEVID_SAS3108_5:
 	case MPI25_MFGPAGE_DEVID_SAS3108_6:
 		return MPI25_VERSION;
+	case MPI26_MFGPAGE_DEVID_SAS3216:
+	case MPI26_MFGPAGE_DEVID_SAS3224:
+	case MPI26_MFGPAGE_DEVID_SAS3316_1:
+	case MPI26_MFGPAGE_DEVID_SAS3316_2:
+	case MPI26_MFGPAGE_DEVID_SAS3316_3:
+	case MPI26_MFGPAGE_DEVID_SAS3316_4:
+	case MPI26_MFGPAGE_DEVID_SAS3324_1:
+	case MPI26_MFGPAGE_DEVID_SAS3324_2:
+	case MPI26_MFGPAGE_DEVID_SAS3324_3:
+	case MPI26_MFGPAGE_DEVID_SAS3324_4:
+		return MPI26_VERSION;
 	}
 	return 0;
 }
@@ -8456,11 +8743,14 @@
 	/* Enumerate only SAS 3.0 HBA's if hbas_to_enumerate is two,
 	 * for other generation HBA's return with -ENODEV
 	 */
-	if ((hbas_to_enumerate == 2) && (hba_mpi_version !=  MPI25_VERSION))
+	if ((hbas_to_enumerate == 2) && (!(hba_mpi_version ==  MPI25_VERSION
+		|| hba_mpi_version ==  MPI26_VERSION)))
 		return -ENODEV;
 
 	switch (hba_mpi_version) {
 	case MPI2_VERSION:
+		pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
+			PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
 		/* Use mpt2sas driver host template for SAS 2.0 HBA's */
 		shost = scsi_host_alloc(&mpt2sas_driver_template,
 		  sizeof(struct MPT3SAS_ADAPTER));
@@ -8478,6 +8768,7 @@
 			ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
 		break;
 	case MPI25_VERSION:
+	case MPI26_VERSION:
 		/* Use mpt3sas driver host template for SAS 3.0 HBA's */
 		shost = scsi_host_alloc(&mpt3sas_driver_template,
 		  sizeof(struct MPT3SAS_ADAPTER));
@@ -8488,7 +8779,9 @@
 		ioc->hba_mpi_version_belonged = hba_mpi_version;
 		ioc->id = mpt3_ids++;
 		sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME);
-		if (pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION)
+		if ((ioc->hba_mpi_version_belonged == MPI25_VERSION &&
+			pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION) ||
+			(ioc->hba_mpi_version_belonged == MPI26_VERSION))
 			ioc->msix96_vector = 1;
 		break;
 	default:
@@ -8533,6 +8826,8 @@
 	INIT_LIST_HEAD(&ioc->raid_device_list);
 	INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
 	INIT_LIST_HEAD(&ioc->delayed_tr_list);
+	INIT_LIST_HEAD(&ioc->delayed_sc_list);
+	INIT_LIST_HEAD(&ioc->delayed_event_ack_list);
 	INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
 	INIT_LIST_HEAD(&ioc->reply_queue_list);
 
@@ -8578,7 +8873,7 @@
 	snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
 	    "fw_event_%s%d", ioc->driver_name, ioc->id);
 	ioc->firmware_event_thread = alloc_ordered_workqueue(
-	    ioc->firmware_event_name, WQ_MEM_RECLAIM);
+	    ioc->firmware_event_name, 0);
 	if (!ioc->firmware_event_thread) {
 		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
 		    ioc->name, __FILE__, __LINE__, __func__);
@@ -8866,6 +9161,28 @@
 		PCI_ANY_ID, PCI_ANY_ID },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
 		PCI_ANY_ID, PCI_ANY_ID },
+	/* Cutlass ~ 3216 and 3224 */
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224,
+		PCI_ANY_ID, PCI_ANY_ID },
+	/* Intruder ~ 3316 and 3324 */
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_1,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_2,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_3,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_4,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_1,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_2,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_3,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_4,
+		PCI_ANY_ID, PCI_ANY_ID },
 	{0}     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table);
--- linux-4.4.0.orig/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ linux-4.4.0/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -1418,7 +1418,6 @@
 	u32 ioc_state;
 	unsigned long timeleft;
 	void *psge;
-	u32 sgl_flags;
 	u8 issue_reset = 0;
 	void *data_out = NULL;
 	dma_addr_t data_out_dma;
@@ -1507,24 +1506,10 @@
 	    cpu_to_le16(sizeof(struct phy_error_log_request));
 	psge = &mpi_request->SGL;
 
-	/* WRITE sgel first */
-	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
-	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
-	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
-	ioc->base_add_sg_single(psge, sgl_flags |
-	    sizeof(struct phy_control_request), data_out_dma);
-
-	/* incr sgel */
-	psge += ioc->sge_size;
-
-	/* READ sgel last */
-	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
-	    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
-	    MPI2_SGE_FLAGS_END_OF_LIST);
-	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
-	ioc->base_add_sg_single(psge, sgl_flags |
-	    sizeof(struct phy_control_reply), data_out_dma +
-	    sizeof(struct phy_control_request));
+	ioc->build_sg(ioc, psge, data_out_dma,
+			    sizeof(struct phy_control_request),
+	    data_out_dma + sizeof(struct phy_control_request),
+	    sizeof(struct phy_control_reply));
 
 	dtransportprintk(ioc, pr_info(MPT3SAS_FMT
 		"phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n",
@@ -1615,7 +1600,7 @@
 		    SMP_PHY_CONTROL_LINK_RESET);
 
 	/* handle hba phys */
-	memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
+	memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
 	mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
 	mpi_request.Operation = hard_reset ?
 	    MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
--- linux-4.4.0.orig/drivers/scsi/mvsas/mv_94xx.c
+++ linux-4.4.0/drivers/scsi/mvsas/mv_94xx.c
@@ -621,7 +621,7 @@
 {
 	u32 tmp;
 	tmp = mvs_cr32(mvi, MVS_COMMAND_ACTIVE+(slot_idx >> 3));
-	if (tmp && 1 << (slot_idx % 32)) {
+	if (tmp & 1 << (slot_idx % 32)) {
 		mv_printk("command active %08X,  slot [%x].\n", tmp, slot_idx);
 		mvs_cw32(mvi, MVS_COMMAND_ACTIVE + (slot_idx >> 3),
 			1 << (slot_idx % 32));
--- linux-4.4.0.orig/drivers/scsi/mvsas/mv_sas.c
+++ linux-4.4.0/drivers/scsi/mvsas/mv_sas.c
@@ -737,8 +737,8 @@
 			mv_dprintk("device %016llx not ready.\n",
 				SAS_ADDR(dev->sas_addr));
 
-			rc = SAS_PHY_DOWN;
-			return rc;
+		rc = SAS_PHY_DOWN;
+		return rc;
 	}
 	tei.port = dev->port->lldd_port;
 	if (tei.port && !tei.port->port_attached && !tmf) {
--- linux-4.4.0.orig/drivers/scsi/mvumi.c
+++ linux-4.4.0/drivers/scsi/mvumi.c
@@ -2476,6 +2476,7 @@
 	if (IS_ERR(mhba->dm_thread)) {
 		dev_err(&mhba->pdev->dev,
 			"failed to create device scan thread\n");
+		ret = PTR_ERR(mhba->dm_thread);
 		mutex_unlock(&mhba->sas_discovery_mutex);
 		goto fail_create_thread;
 	}
@@ -2629,7 +2630,7 @@
 	mvumi_flush_cache(mhba);
 }
 
-static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct mvumi_hba *mhba = NULL;
 
@@ -2648,7 +2649,7 @@
 	return 0;
 }
 
-static int mvumi_resume(struct pci_dev *pdev)
+static int __maybe_unused mvumi_resume(struct pci_dev *pdev)
 {
 	int ret;
 	struct mvumi_hba *mhba = NULL;
--- linux-4.4.0.orig/drivers/scsi/pm8001/pm8001_hwi.c
+++ linux-4.4.0/drivers/scsi/pm8001/pm8001_hwi.c
@@ -1479,6 +1479,12 @@
 		} else {
 			u32 producer_index;
 			void *pi_virt = circularQ->pi_virt;
+			/* spurious interrupt during setup if
+			 * kexec-ing and driver doing a doorbell access
+			 * with the pre-kexec oq interrupt setup
+			 */
+			if (!pi_virt)
+				break;
 			/* Update the producer index from SPC */
 			producer_index = pm8001_read_32(pi_virt);
 			circularQ->producer_index = cpu_to_le32(producer_index);
--- linux-4.4.0.orig/drivers/scsi/pm8001/pm8001_init.c
+++ linux-4.4.0/drivers/scsi/pm8001/pm8001_init.c
@@ -1063,7 +1063,8 @@
 
 	pm8001_init_sas_add(pm8001_ha);
 	/* phy setting support for motherboard controller */
-	if (pm8001_configure_phy_settings(pm8001_ha))
+	rc = pm8001_configure_phy_settings(pm8001_ha);
+	if (rc)
 		goto err_out_shost;
 
 	pm8001_post_sas_ha_init(shost, chip);
--- linux-4.4.0.orig/drivers/scsi/pm8001/pm8001_sas.c
+++ linux-4.4.0/drivers/scsi/pm8001/pm8001_sas.c
@@ -371,6 +371,13 @@
 		return 0;
 	}
 	pm8001_ha = pm8001_find_ha_by_dev(task->dev);
+	if (pm8001_ha->controller_fatal_error) {
+		struct task_status_struct *ts = &t->task_status;
+
+		ts->resp = SAS_TASK_UNDELIVERED;
+		t->task_done(t);
+		return 0;
+	}
 	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
 	spin_lock_irqsave(&pm8001_ha->lock, flags);
 	do {
@@ -463,7 +470,7 @@
 	dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc);
 	if (!sas_protocol_ata(t->task_proto))
 		if (n_elem)
-			dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
+			dma_unmap_sg(pm8001_ha->dev, t->scatter, t->num_scatter,
 				t->data_dir);
 out_done:
 	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
@@ -648,17 +655,21 @@
 
 void pm8001_task_done(struct sas_task *task)
 {
-	if (!del_timer(&task->slow_task->timer))
-		return;
+	del_timer(&task->slow_task->timer);
 	complete(&task->slow_task->completion);
 }
 
 static void pm8001_tmf_timedout(unsigned long data)
 {
 	struct sas_task *task = (struct sas_task *)data;
+	unsigned long flags;
 
-	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	complete(&task->slow_task->completion);
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+		complete(&task->slow_task->completion);
+	}
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
 }
 
 #define PM8001_TASK_TIMEOUT 20
@@ -714,13 +725,16 @@
 		}
 		res = -TMF_RESP_FUNC_FAILED;
 		/* Even TMF timed out, return direct. */
-		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-				PM8001_FAIL_DBG(pm8001_ha,
-					pm8001_printk("TMF task[%x]timeout.\n",
-					tmf->tmf));
-				goto ex_err;
-			}
+		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+			struct pm8001_ccb_info *ccb = task->lldd_task;
+
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("TMF task[%x]timeout.\n",
+				tmf->tmf));
+
+			if (ccb)
+				ccb->task = NULL;
+			goto ex_err;
 		}
 
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
@@ -785,7 +799,7 @@
 
 		res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
 		if (res)
-			return res;
+			goto ex_err;
 		ccb = &pm8001_ha->ccb_info[ccb_tag];
 		ccb->device = pm8001_dev;
 		ccb->ccb_tag = ccb_tag;
@@ -805,12 +819,10 @@
 		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)) {
-			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-				PM8001_FAIL_DBG(pm8001_ha,
-					pm8001_printk("TMF task timeout.\n"));
-				goto ex_err;
-			}
+		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("TMF task timeout.\n"));
+			goto ex_err;
 		}
 
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
--- linux-4.4.0.orig/drivers/scsi/pm8001/pm8001_sas.h
+++ linux-4.4.0/drivers/scsi/pm8001/pm8001_sas.h
@@ -531,6 +531,7 @@
 	u32			logging_level;
 	u32			fw_status;
 	u32			smp_exp_mode;
+	bool			controller_fatal_error;
 	const struct firmware 	*fw_image;
 	struct isr_param irq_vector[PM8001_MAX_MSIX_VEC];
 };
--- linux-4.4.0.orig/drivers/scsi/pm8001/pm80xx_hwi.c
+++ linux-4.4.0/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -572,6 +572,9 @@
 		pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size);
 	pm8001_mw32(address, MAIN_PCS_EVENT_LOG_OPTION,
 		pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity);
+	/* Update Fatal error interrupt vector */
+	pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |=
+					((pm8001_ha->number_of_intr - 1) << 8);
 	pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT,
 		pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt);
 	pm8001_mw32(address, MAIN_EVENT_CRC_CHECK,
@@ -1099,6 +1102,9 @@
 		return -EBUSY;
 	}
 
+	/* Initialize the controller fatal error flag */
+	pm8001_ha->controller_fatal_error = false;
+
 	/* Initialize pci space address eg: mpi offset */
 	init_pci_device_addresses(pm8001_ha);
 	init_default_table_values(pm8001_ha);
@@ -1207,13 +1213,17 @@
 	u32 bootloader_state;
 	u32 ibutton0, ibutton1;
 
-	/* Check if MPI is in ready state to reset */
-	if (mpi_uninit_check(pm8001_ha) != 0) {
-		PM8001_FAIL_DBG(pm8001_ha,
-			pm8001_printk("MPI state is not ready\n"));
-		return -1;
+	/* Process MPI table uninitialization only if FW is ready */
+	if (!pm8001_ha->controller_fatal_error) {
+		/* Check if MPI is in ready state to reset */
+		if (mpi_uninit_check(pm8001_ha) != 0) {
+			regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+				"MPI state is not ready scratch1 :0x%x\n",
+				regval));
+			return -1;
+		}
 	}
-
 	/* checked for reset register normal state; 0x0 */
 	regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET);
 	PM8001_INIT_DBG(pm8001_ha,
@@ -2358,6 +2368,8 @@
 			pm8001_printk("task 0x%p done with io_status 0x%x"
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, status, ts->resp, ts->stat));
+		if (t->slow_task)
+			complete(&t->slow_task->completion);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
@@ -3717,6 +3729,46 @@
 	}
 }
 
+static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha)
+{
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_SCRATCH_PAD_0: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_SCRATCH_PAD_1:0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_SCRATCH_PAD_2: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_SCRATCH_PAD_3: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_HOST_SCRATCH_PAD_0: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_HOST_SCRATCH_PAD_1: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_HOST_SCRATCH_PAD_2: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_HOST_SCRATCH_PAD_3: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_HOST_SCRATCH_PAD_4: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_HOST_SCRATCH_PAD_5: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6)));
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n",
+			pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7)));
+}
+
 static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
 {
 	struct outbound_queue_table *circularQ;
@@ -3724,10 +3776,28 @@
 	u8 uninitialized_var(bc);
 	u32 ret = MPI_IO_STATUS_FAIL;
 	unsigned long flags;
+	u32 regval;
 
+	if (vec == (pm8001_ha->number_of_intr - 1)) {
+		regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+		if ((regval & SCRATCH_PAD_MIPSALL_READY) !=
+					SCRATCH_PAD_MIPSALL_READY) {
+			pm8001_ha->controller_fatal_error = true;
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+				"Firmware Fatal error! Regval:0x%x\n", regval));
+			print_scratchpad_registers(pm8001_ha);
+			return ret;
+		}
+	}
 	spin_lock_irqsave(&pm8001_ha->lock, flags);
 	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
 	do {
+		/* spurious interrupt during setup if kexec-ing and
+		 * driver doing a doorbell access w/ the pre-kexec oq
+		 * interrupt setup.
+		 */
+		if (!circularQ->pi_virt)
+			break;
 		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
 		if (MPI_IO_STATUS_SUCCESS == ret) {
 			/* process the outbound message */
--- linux-4.4.0.orig/drivers/scsi/pm8001/pm80xx_hwi.h
+++ linux-4.4.0/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -1288,6 +1288,9 @@
 #define SCRATCH_PAD_BOOT_LOAD_SUCCESS	0x0
 #define SCRATCH_PAD_IOP0_READY		0xC00
 #define SCRATCH_PAD_IOP1_READY		0x3000
+#define SCRATCH_PAD_MIPSALL_READY	(SCRATCH_PAD_IOP1_READY | \
+					SCRATCH_PAD_IOP0_READY | \
+					SCRATCH_PAD_RAAE_READY)
 
 /* boot loader state */
 #define SCRATCH_PAD1_BOOTSTATE_MASK		0x70	/* Bit 4-6 */
--- linux-4.4.0.orig/drivers/scsi/qla1280.c
+++ linux-4.4.0/drivers/scsi/qla1280.c
@@ -4214,7 +4214,7 @@
 	.eh_bus_reset_handler	= qla1280_eh_bus_reset,
 	.eh_host_reset_handler	= qla1280_eh_adapter_reset,
 	.bios_param		= qla1280_biosparam,
-	.can_queue		= 0xfffff,
+	.can_queue		= MAX_OUTSTANDING_COMMANDS,
 	.this_id		= -1,
 	.sg_tablesize		= SG_ALL,
 	.use_clustering		= ENABLE_CLUSTERING,
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/Kconfig
+++ linux-4.4.0/drivers/scsi/qla2xxx/Kconfig
@@ -18,9 +18,6 @@
 	2322, 6322        ql2322_fw.bin
 	24xx, 54xx        ql2400_fw.bin
 	25xx              ql2500_fw.bin
-	2031              ql2600_fw.bin
-	8031              ql8300_fw.bin
-	27xx              ql2700_fw.bin
 
 	Upon request, the driver caches the firmware image until
 	the driver is unloaded.
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_attr.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_attr.c
@@ -329,12 +329,15 @@
 	struct qla_hw_data *ha = vha->hw;
 	ssize_t rval = 0;
 
+	mutex_lock(&ha->optrom_mutex);
+
 	if (ha->optrom_state != QLA_SREADING)
-		return 0;
+		goto out;
 
-	mutex_lock(&ha->optrom_mutex);
 	rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
 	    ha->optrom_region_size);
+
+out:
 	mutex_unlock(&ha->optrom_mutex);
 
 	return rval;
@@ -349,14 +352,19 @@
 	    struct device, kobj)));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (ha->optrom_state != QLA_SWRITING)
+	mutex_lock(&ha->optrom_mutex);
+
+	if (ha->optrom_state != QLA_SWRITING) {
+		mutex_unlock(&ha->optrom_mutex);
 		return -EINVAL;
-	if (off > ha->optrom_region_size)
+	}
+	if (off > ha->optrom_region_size) {
+		mutex_unlock(&ha->optrom_mutex);
 		return -ERANGE;
+	}
 	if (off + count > ha->optrom_region_size)
 		count = ha->optrom_region_size - off;
 
-	mutex_lock(&ha->optrom_mutex);
 	memcpy(&ha->optrom_buffer[off], buf, count);
 	mutex_unlock(&ha->optrom_mutex);
 
@@ -396,6 +404,8 @@
 		return -EINVAL;
 	if (start > ha->optrom_size)
 		return -EINVAL;
+	if (size > ha->optrom_size - start)
+		size = ha->optrom_size - start;
 
 	mutex_lock(&ha->optrom_mutex);
 	switch (val) {
@@ -421,8 +431,7 @@
 		}
 
 		ha->optrom_region_start = start;
-		ha->optrom_region_size = start + size > ha->optrom_size ?
-		    ha->optrom_size - start : size;
+		ha->optrom_region_size = size;
 
 		ha->optrom_state = QLA_SREADING;
 		ha->optrom_buffer = vmalloc(ha->optrom_region_size);
@@ -495,8 +504,7 @@
 		}
 
 		ha->optrom_region_start = start;
-		ha->optrom_region_size = start + size > ha->optrom_size ?
-		    ha->optrom_size - start : size;
+		ha->optrom_region_size = size;
 
 		ha->optrom_state = QLA_SWRITING;
 		ha->optrom_buffer = vmalloc(ha->optrom_region_size);
@@ -752,7 +760,8 @@
 			break;
 		} else {
 			/* Make sure FC side is not in reset */
-			qla2x00_wait_for_hba_online(vha);
+			WARN_ON_ONCE(qla2x00_wait_for_hba_online(vha) !=
+				     QLA_SUCCESS);
 
 			/* Issue MPI reset */
 			scsi_block_requests(vha->host);
@@ -824,6 +833,41 @@
 };
 
 static ssize_t
+qla2x00_issue_logo(struct file *filp, struct kobject *kobj,
+			struct bin_attribute *bin_attr,
+			char *buf, loff_t off, size_t count)
+{
+	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	int type;
+	int rval = 0;
+	port_id_t did;
+
+	type = simple_strtol(buf, NULL, 10);
+
+	did.b.domain = (type & 0x00ff0000) >> 16;
+	did.b.area = (type & 0x0000ff00) >> 8;
+	did.b.al_pa = (type & 0x000000ff);
+
+	ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n",
+	    did.b.domain, did.b.area, did.b.al_pa);
+
+	ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
+
+	rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
+	return count;
+}
+
+static struct bin_attribute sysfs_issue_logo_attr = {
+	.attr = {
+		.name = "issue_logo",
+		.mode = S_IWUSR,
+	},
+	.size = 0,
+	.write = qla2x00_issue_logo,
+};
+
+static ssize_t
 qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
 		       struct bin_attribute *bin_attr,
 		       char *buf, loff_t off, size_t count)
@@ -937,6 +981,7 @@
 	{ "vpd", &sysfs_vpd_attr, 1 },
 	{ "sfp", &sysfs_sfp_attr, 1 },
 	{ "reset", &sysfs_reset_attr, },
+	{ "issue_logo", &sysfs_issue_logo_attr, },
 	{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
 	{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
 	{ NULL },
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_bsg.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_bsg.c
@@ -252,7 +252,7 @@
 	srb_t *sp;
 	const char *type;
 	int req_sg_cnt, rsp_sg_cnt;
-	int rval =  (DRIVER_ERROR << 16);
+	int rval =  (DID_ERROR << 16);
 	uint16_t nextlid = 0;
 
 	if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
@@ -336,6 +336,8 @@
 		dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
 		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
 	if (!req_sg_cnt) {
+		dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+		    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
 		rval = -ENOMEM;
 		goto done_free_fcport;
 	}
@@ -343,6 +345,8 @@
 	rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
 		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
         if (!rsp_sg_cnt) {
+		dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+		    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
 		rval = -ENOMEM;
 		goto done_free_fcport;
 	}
@@ -426,7 +430,7 @@
 	struct Scsi_Host *host = bsg_job->shost;
 	scsi_qla_host_t *vha = shost_priv(host);
 	struct qla_hw_data *ha = vha->hw;
-	int rval = (DRIVER_ERROR << 16);
+	int rval = (DID_ERROR << 16);
 	int req_sg_cnt, rsp_sg_cnt;
 	uint16_t loop_id;
 	struct fc_port *fcport;
@@ -1739,8 +1743,8 @@
 	uint16_t nextlid = 0;
 	uint32_t tot_dsds;
 	srb_t *sp = NULL;
-	uint32_t req_data_len = 0;
-	uint32_t rsp_data_len = 0;
+	uint32_t req_data_len;
+	uint32_t rsp_data_len;
 
 	/* Check the type of the adapter */
 	if (!IS_BIDI_CAPABLE(ha)) {
@@ -1845,6 +1849,9 @@
 		goto done_unmap_sg;
 	}
 
+	req_data_len = bsg_job->request_payload.payload_len;
+	rsp_data_len = bsg_job->reply_payload.payload_len;
+
 	if (req_data_len != rsp_data_len) {
 		rval = EXT_STATUS_BUSY;
 		ql_log(ql_log_warn, vha, 0x70aa,
@@ -1852,10 +1859,6 @@
 		goto done_unmap_sg;
 	}
 
-	req_data_len = bsg_job->request_payload.payload_len;
-	rsp_data_len = bsg_job->reply_payload.payload_len;
-
-
 	/* Alloc SRB structure */
 	sp = qla2x00_get_sp(vha, &(vha->bidir_fcport), GFP_KERNEL);
 	if (!sp) {
@@ -1910,7 +1913,7 @@
 	struct Scsi_Host *host = bsg_job->shost;
 	scsi_qla_host_t *vha = shost_priv(host);
 	struct qla_hw_data *ha = vha->hw;
-	int rval = (DRIVER_ERROR << 16);
+	int rval = (DID_ERROR << 16);
 	struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
 	srb_t *sp;
 	int req_sg_cnt = 0, rsp_sg_cnt = 0;
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_dbg.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,25 +14,24 @@
  * | Module Init and Probe        |       0x017f       | 0x0146         |
  * |                              |                    | 0x015b-0x0160	|
  * |                              |                    | 0x016e-0x0170  |
- * | Mailbox commands             |       0x118d       | 0x1115-0x1116	|
- * |                              |                    | 0x111a-0x111b  |
+ * | Mailbox commands             |       0x1192       |		|
+ * |                              |                    |		|
  * | Device Discovery             |       0x2016       | 0x2020-0x2022, |
  * |                              |                    | 0x2011-0x2012, |
  * |                              |                    | 0x2099-0x20a4  |
- * | Queue Command and IO tracing |       0x3075       | 0x300b         |
+ * | Queue Command and IO tracing |       0x3074       | 0x300b         |
  * |                              |                    | 0x3027-0x3028  |
  * |                              |                    | 0x303d-0x3041  |
  * |                              |                    | 0x302d,0x3033  |
  * |                              |                    | 0x3036,0x3038  |
  * |                              |                    | 0x303a		|
  * | DPC Thread                   |       0x4023       | 0x4002,0x4013  |
- * | Async Events                 |       0x508a       | 0x502b-0x502f  |
- * |                              |                    | 0x5047		|
+ * | Async Events                 |       0x5089       | 0x502b-0x502f  |
  * |                              |                    | 0x5084,0x5075	|
  * |                              |                    | 0x503d,0x5044  |
  * |                              |                    | 0x507b,0x505f	|
  * | Timer Routines               |       0x6012       |                |
- * | User Space Interactions      |       0x70e2       | 0x7018,0x702e  |
+ * | User Space Interactions      |       0x70e65      | 0x7018,0x702e  |
  * |				  |		       | 0x7020,0x7024  |
  * |                              |                    | 0x7039,0x7045  |
  * |                              |                    | 0x7073-0x7075  |
@@ -60,15 +59,11 @@
  * |                              |                    | 0xb13c-0xb140  |
  * |                              |                    | 0xb149		|
  * | MultiQ                       |       0xc00c       |		|
- * | Misc                         |       0xd300       | 0xd016-0xd017	|
- * |                              |                    | 0xd021,0xd024	|
- * |                              |                    | 0xd025,0xd029	|
- * |                              |                    | 0xd02a,0xd02e	|
- * |                              |                    | 0xd031-0xd0ff	|
+ * | Misc                         |       0xd301       | 0xd031-0xd0ff	|
  * |                              |                    | 0xd101-0xd1fe	|
  * |                              |                    | 0xd214-0xd2fe	|
  * | Target Mode		  |	  0xe080       |		|
- * | Target Mode Management	  |	  0xf096       | 0xf002		|
+ * | Target Mode Management	  |	  0xf09b       | 0xf002		|
  * |                              |                    | 0xf046-0xf049  |
  * | Target Mode Task Management  |	  0x1000d      |		|
  * ----------------------------------------------------------------------
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_def.h
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_def.h
@@ -259,7 +259,7 @@
 #define LOOP_DOWN_TIME			255	/* 240 */
 #define	LOOP_DOWN_RESET			(LOOP_DOWN_TIME - 30)
 
-#define DEFAULT_OUTSTANDING_COMMANDS	1024
+#define DEFAULT_OUTSTANDING_COMMANDS	4096
 #define MIN_OUTSTANDING_COMMANDS	128
 
 /* ISP request and response entry counts (37-65535) */
@@ -267,11 +267,13 @@
 #define REQUEST_ENTRY_CNT_2200		2048	/* Number of request entries. */
 #define REQUEST_ENTRY_CNT_24XX		2048	/* Number of request entries. */
 #define REQUEST_ENTRY_CNT_83XX		8192	/* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_83XX		4096	/* Number of response entries.*/
 #define RESPONSE_ENTRY_CNT_2100		64	/* Number of response entries.*/
 #define RESPONSE_ENTRY_CNT_2300		512	/* Number of response entries.*/
 #define RESPONSE_ENTRY_CNT_MQ		128	/* Number of response entries.*/
 #define ATIO_ENTRY_CNT_24XX		4096	/* Number of ATIO entries. */
 #define RESPONSE_ENTRY_CNT_FX00		256     /* Number of response entries.*/
+#define EXTENDED_EXCH_ENTRY_CNT		32768   /* Entries for offload case */
 
 struct req_que;
 struct qla_tgt_sess;
@@ -309,6 +311,14 @@
 /* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
 #define IS_PROT_IO(sp)	(sp->flags & SRB_CRC_CTX_DSD_VALID)
 
+struct els_logo_payload {
+	uint8_t opcode;
+	uint8_t rsvd[3];
+	uint8_t s_id[3];
+	uint8_t rsvd1[1];
+	uint8_t wwpn[WWN_SIZE];
+};
+
 /*
  * SRB extensions.
  */
@@ -322,6 +332,15 @@
 			uint16_t data[2];
 		} logio;
 		struct {
+#define ELS_DCMD_TIMEOUT 20
+#define ELS_DCMD_LOGO 0x5
+			uint32_t flags;
+			uint32_t els_cmd;
+			struct completion comp;
+			struct els_logo_payload *els_logo_pyld;
+			dma_addr_t els_logo_pyld_dma;
+		} els_logo;
+		struct {
 			/*
 			 * Values for flags field below are as
 			 * defined in tsk_mgmt_entry struct
@@ -382,7 +401,7 @@
 #define SRB_FXIOCB_DCMD	10
 #define SRB_FXIOCB_BCMD	11
 #define SRB_ABT_CMD	12
-
+#define SRB_ELS_DCMD	13
 
 typedef struct srb {
 	atomic_t ref_count;
@@ -891,6 +910,7 @@
 #define MBC_DISABLE_VI			0x24	/* Disable VI operation. */
 #define MBC_ENABLE_VI			0x25	/* Enable VI operation. */
 #define MBC_GET_FIRMWARE_OPTION		0x28	/* Get Firmware Options. */
+#define MBC_GET_MEM_OFFLOAD_CNTRL_STAT	0x34	/* Memory Offload ctrl/Stat*/
 #define MBC_SET_FIRMWARE_OPTION		0x38	/* Set Firmware Options. */
 #define MBC_LOOP_PORT_BYPASS		0x40	/* Loop Port Bypass. */
 #define MBC_LOOP_PORT_ENABLE		0x41	/* Loop Port Enable. */
@@ -2695,11 +2715,16 @@
 
 struct scsi_qla_host;
 
+
+#define QLA83XX_RSPQ_MSIX_ENTRY_NUMBER 1 /* refer to qla83xx_msix_entries */
+
 struct qla_msix_entry {
 	int have_irq;
 	uint32_t vector;
 	uint16_t entry;
 	struct rsp_que *rsp;
+	struct irq_affinity_notify irq_notify;
+	int cpuid;
 };
 
 #define	WATCH_INTERVAL		1       /* number of seconds */
@@ -2910,12 +2935,15 @@
 	uint32_t num_qfull_cmds_dropped;
 	spinlock_t q_full_lock;
 	uint32_t leak_exchg_thresh_hold;
+	spinlock_t sess_lock;
+	int rspq_vector_cpuid;
+	spinlock_t atio_lock ____cacheline_aligned;
 };
 
 #define MAX_QFULL_CMDS_ALLOC	8192
 #define Q_FULL_THRESH_HOLD_PERCENT 90
 #define Q_FULL_THRESH_HOLD(ha) \
-	((ha->fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
+	((ha->cur_fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
 
 #define LEAK_EXCHG_THRESH_HOLD_PERCENT 75	/* 75 percent */
 
@@ -2962,10 +2990,12 @@
 		uint32_t	isp82xx_no_md_cap:1;
 		uint32_t	host_shutting_down:1;
 		uint32_t	idc_compl_status:1;
-
 		uint32_t        mr_reset_hdlr_active:1;
 		uint32_t        mr_intr_valid:1;
+
 		uint32_t	fawwpn_enabled:1;
+		uint32_t	exlogins_enabled:1;
+		uint32_t	exchoffld_enabled:1;
 		/* 35 bits */
 	} flags;
 
@@ -3237,6 +3267,21 @@
 	void		*async_pd;
 	dma_addr_t	async_pd_dma;
 
+#define ENABLE_EXTENDED_LOGIN	BIT_7
+
+	/* Extended Logins  */
+	void		*exlogin_buf;
+	dma_addr_t	exlogin_buf_dma;
+	int		exlogin_size;
+
+#define ENABLE_EXCHANGE_OFFLD	BIT_2
+
+	/* Exchange Offload */
+	void		*exchoffld_buf;
+	dma_addr_t	exchoffld_buf_dma;
+	int		exchoffld_size;
+	int 		exchoffld_count;
+
 	void		*swl;
 
 	/* These are used by mailbox operations. */
@@ -3279,8 +3324,14 @@
 #define RISC_START_ADDRESS_2100 0x1000
 #define RISC_START_ADDRESS_2300 0x800
 #define RISC_START_ADDRESS_2400 0x100000
-	uint16_t	fw_xcb_count;
-	uint16_t	fw_iocb_count;
+
+	uint16_t	orig_fw_tgt_xcb_count;
+	uint16_t	cur_fw_tgt_xcb_count;
+	uint16_t	orig_fw_xcb_count;
+	uint16_t	cur_fw_xcb_count;
+	uint16_t	orig_fw_iocb_count;
+	uint16_t	cur_fw_iocb_count;
+	uint16_t	fw_max_fcf_count;
 
 	uint32_t	fw_shared_ram_start;
 	uint32_t	fw_shared_ram_end;
@@ -3323,6 +3374,9 @@
 	uint32_t	chain_offset;
 	struct dentry *dfs_dir;
 	struct dentry *dfs_fce;
+	struct dentry *dfs_tgt_counters;
+	struct dentry *dfs_fw_resource_cnt;
+
 	dma_addr_t	fce_dma;
 	void		*fce;
 	uint32_t	fce_bufs;
@@ -3480,6 +3534,18 @@
 	int	allow_cna_fw_dump;
 };
 
+struct qla_tgt_counters {
+	uint64_t qla_core_sbt_cmd;
+	uint64_t core_qla_que_buf;
+	uint64_t qla_core_ret_ctio;
+	uint64_t core_qla_snd_status;
+	uint64_t qla_core_ret_sta_ctio;
+	uint64_t core_qla_free_cmd;
+	uint64_t num_q_full_sent;
+	uint64_t num_alloc_iocb_failed;
+	uint64_t num_term_xchg_sent;
+};
+
 /*
  * Qlogic scsi host structure
  */
@@ -3595,6 +3661,10 @@
 	atomic_t		generation_tick;
 	/* Time when global fcport update has been scheduled */
 	int			total_fcport_update_gen;
+	/* List of pending LOGOs, protected by tgt_mutex */
+	struct list_head	logo_list;
+	/* List of pending PLOGI acks, protected by hw lock */
+	struct list_head	plogi_ack_list;
 
 	uint32_t	vp_abort_cnt;
 
@@ -3632,6 +3702,7 @@
 
 	atomic_t	vref_count;
 	struct qla8044_reset_template reset_tmplt;
+	struct qla_tgt_counters tgt_counters;
 } scsi_qla_host_t;
 
 #define SET_VP_IDX	1
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_dfs.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,85 @@
 static atomic_t qla2x00_dfs_root_count;
 
 static int
+qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
+{
+	struct scsi_qla_host *vha = s->private;
+	struct qla_hw_data *ha = vha->hw;
+
+	seq_puts(s, "FW Resource count\n\n");
+	seq_printf(s, "Original TGT exchg count[%d]\n",
+	    ha->orig_fw_tgt_xcb_count);
+	seq_printf(s, "current TGT exchg count[%d]\n",
+	    ha->cur_fw_tgt_xcb_count);
+	seq_printf(s, "original Initiator Exchange count[%d]\n",
+	    ha->orig_fw_xcb_count);
+	seq_printf(s, "Current Initiator Exchange count[%d]\n",
+	    ha->cur_fw_xcb_count);
+	seq_printf(s, "Original IOCB count[%d]\n", ha->orig_fw_iocb_count);
+	seq_printf(s, "Current IOCB count[%d]\n", ha->cur_fw_iocb_count);
+	seq_printf(s, "MAX VP count[%d]\n", ha->max_npiv_vports);
+	seq_printf(s, "MAX FCF count[%d]\n", ha->fw_max_fcf_count);
+
+	return 0;
+}
+
+static int
+qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
+{
+	struct scsi_qla_host *vha = inode->i_private;
+	return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
+}
+
+static const struct file_operations dfs_fw_resource_cnt_ops = {
+	.open           = qla_dfs_fw_resource_cnt_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release        = single_release,
+};
+
+static int
+qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
+{
+	struct scsi_qla_host *vha = s->private;
+
+	seq_puts(s, "Target Counters\n");
+	seq_printf(s, "qla_core_sbt_cmd = %lld\n",
+		vha->tgt_counters.qla_core_sbt_cmd);
+	seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
+		vha->tgt_counters.qla_core_ret_sta_ctio);
+	seq_printf(s, "qla_core_ret_ctio = %lld\n",
+		vha->tgt_counters.qla_core_ret_ctio);
+	seq_printf(s, "core_qla_que_buf = %lld\n",
+		vha->tgt_counters.core_qla_que_buf);
+	seq_printf(s, "core_qla_snd_status = %lld\n",
+		vha->tgt_counters.core_qla_snd_status);
+	seq_printf(s, "core_qla_free_cmd = %lld\n",
+		vha->tgt_counters.core_qla_free_cmd);
+	seq_printf(s, "num alloc iocb failed = %lld\n",
+		vha->tgt_counters.num_alloc_iocb_failed);
+	seq_printf(s, "num term exchange sent = %lld\n",
+		vha->tgt_counters.num_term_xchg_sent);
+	seq_printf(s, "num Q full sent = %lld\n",
+		vha->tgt_counters.num_q_full_sent);
+
+	return 0;
+}
+
+static int
+qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
+{
+	struct scsi_qla_host *vha = inode->i_private;
+	return single_open(file, qla_dfs_tgt_counters_show, vha);
+}
+
+static const struct file_operations dfs_tgt_counters_ops = {
+	.open           = qla_dfs_tgt_counters_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release        = single_release,
+};
+
+static int
 qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
 {
 	scsi_qla_host_t *vha = s->private;
@@ -146,6 +225,22 @@
 	atomic_inc(&qla2x00_dfs_root_count);
 
 create_nodes:
+	ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
+	    S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops);
+	if (!ha->dfs_fw_resource_cnt) {
+		ql_log(ql_log_warn, vha, 0x00fd,
+		    "Unable to create debugFS fw_resource_count node.\n");
+		goto out;
+	}
+
+	ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
+	    ha->dfs_dir, vha, &dfs_tgt_counters_ops);
+	if (!ha->dfs_tgt_counters) {
+		ql_log(ql_log_warn, vha, 0xd301,
+		    "Unable to create debugFS tgt_counters node.\n");
+		goto out;
+	}
+
 	ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
 	    &dfs_fce_ops);
 	if (!ha->dfs_fce) {
@@ -161,6 +256,17 @@
 qla2x00_dfs_remove(scsi_qla_host_t *vha)
 {
 	struct qla_hw_data *ha = vha->hw;
+
+	if (ha->dfs_fw_resource_cnt) {
+		debugfs_remove(ha->dfs_fw_resource_cnt);
+		ha->dfs_fw_resource_cnt = NULL;
+	}
+
+	if (ha->dfs_tgt_counters) {
+		debugfs_remove(ha->dfs_tgt_counters);
+		ha->dfs_tgt_counters = NULL;
+	}
+
 	if (ha->dfs_fce) {
 		debugfs_remove(ha->dfs_fce);
 		ha->dfs_fce = NULL;
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_gbl.h
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_gbl.h
@@ -44,6 +44,8 @@
 extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
 extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
 
+extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t);
+
 extern void qla2x00_update_fcports(scsi_qla_host_t *);
 
 extern int qla2x00_abort_isp(scsi_qla_host_t *);
@@ -117,6 +119,8 @@
 extern uint64_t ql2xmaxlun;
 extern int ql2xmdcapmask;
 extern int ql2xmdenable;
+extern int ql2xexlogins;
+extern int ql2xexchoffld;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -135,6 +139,10 @@
     uint16_t *);
 extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
     fc_port_t *, uint16_t *);
+extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
+extern int qla2x00_set_exchoffld_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exchoffld_buffer(struct qla_hw_data *);
 
 extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
 
@@ -323,8 +331,7 @@
 qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
 
 extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
-    uint16_t *, uint16_t *, uint16_t *, uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *);
 
 extern int
 qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
@@ -766,4 +773,11 @@
 extern int qla8044_check_fw_alive(struct scsi_qla_host *);
 
 extern void qlt_host_reset_handler(struct qla_hw_data *ha);
+extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *,
+	uint16_t *);
+extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
+extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
+extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *, dma_addr_t);
+extern void qlt_handle_abts_recv(struct scsi_qla_host *, response_t *);
+
 #endif /* _QLA_GBL_H */
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_init.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_init.c
@@ -325,11 +325,10 @@
 
 	wait_for_completion(&tm_iocb->u.tmf.comp);
 
-	rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
-	    QLA_SUCCESS : QLA_FUNCTION_FAILED;
+	rval = tm_iocb->u.tmf.data;
 
-	if ((rval != QLA_SUCCESS) || tm_iocb->u.tmf.data) {
-		ql_dbg(ql_dbg_taskm, vha, 0x8030,
+	if (rval != QLA_SUCCESS) {
+		ql_log(ql_log_warn, vha, 0x8030,
 		    "TM IOCB failed (%x).\n", rval);
 	}
 
@@ -365,7 +364,8 @@
 	srb_t *sp = (srb_t *)ptr;
 	struct srb_iocb *abt = &sp->u.iocb_cmd;
 
-	complete(&abt->u.abt.comp);
+	if (del_timer(&sp->u.iocb_cmd.timer))
+		complete(&abt->u.abt.comp);
 }
 
 static int
@@ -1766,10 +1766,10 @@
 	    (ql2xmultique_tag || ql2xmaxqueues > 1)))
 		req->num_outstanding_cmds = DEFAULT_OUTSTANDING_COMMANDS;
 	else {
-		if (ha->fw_xcb_count <= ha->fw_iocb_count)
-			req->num_outstanding_cmds = ha->fw_xcb_count;
+		if (ha->cur_fw_xcb_count <= ha->cur_fw_iocb_count)
+			req->num_outstanding_cmds = ha->cur_fw_xcb_count;
 		else
-			req->num_outstanding_cmds = ha->fw_iocb_count;
+			req->num_outstanding_cmds = ha->cur_fw_iocb_count;
 	}
 
 	req->outstanding_cmds = kzalloc(sizeof(srb_t *) *
@@ -1843,9 +1843,23 @@
 			ql_dbg(ql_dbg_init, vha, 0x00ca,
 			    "Starting firmware.\n");
 
+			if (ql2xexlogins)
+				ha->flags.exlogins_enabled = 1;
+
+			if (ql2xexchoffld)
+				ha->flags.exchoffld_enabled = 1;
+
 			rval = qla2x00_execute_fw(vha, srisc_address);
 			/* Retrieve firmware information. */
 			if (rval == QLA_SUCCESS) {
+				rval = qla2x00_set_exlogins_buffer(vha);
+				if (rval != QLA_SUCCESS)
+					goto failed;
+
+				rval = qla2x00_set_exchoffld_buffer(vha);
+				if (rval != QLA_SUCCESS)
+					goto failed;
+
 enable_82xx_npiv:
 				fw_major_version = ha->fw_major_version;
 				if (IS_P3P_TYPE(ha))
@@ -1864,9 +1878,7 @@
 						ha->max_npiv_vports =
 						    MIN_MULTI_ID_FABRIC - 1;
 				}
-				qla2x00_get_resource_cnts(vha, NULL,
-				    &ha->fw_xcb_count, NULL, &ha->fw_iocb_count,
-				    &ha->max_npiv_vports, NULL);
+				qla2x00_get_resource_cnts(vha);
 
 				/*
 				 * Allocate the array of outstanding commands
@@ -2192,7 +2204,7 @@
 	/* Clear outstanding commands array. */
 	for (que = 0; que < ha->max_req_queues; que++) {
 		req = ha->req_q_map[que];
-		if (!req)
+		if (!req || !test_bit(que, ha->req_qid_map))
 			continue;
 		req->out_ptr = (void *)(req->ring + req->length);
 		*req->out_ptr = 0;
@@ -2209,7 +2221,7 @@
 
 	for (que = 0; que < ha->max_rsp_queues; que++) {
 		rsp = ha->rsp_q_map[que];
-		if (!rsp)
+		if (!rsp || !test_bit(que, ha->rsp_qid_map))
 			continue;
 		rsp->in_ptr = (void *)(rsp->ring + rsp->length);
 		*rsp->in_ptr = 0;
@@ -2248,7 +2260,7 @@
 	if (IS_FWI2_CAPABLE(ha)) {
 		mid_init_cb->options = cpu_to_le16(BIT_1);
 		mid_init_cb->init_cb.execution_throttle =
-		    cpu_to_le16(ha->fw_xcb_count);
+		    cpu_to_le16(ha->cur_fw_xcb_count);
 		/* D-Port Status */
 		if (IS_DPORT_CAPABLE(ha))
 			mid_init_cb->init_cb.firmware_options_1 |=
@@ -3053,6 +3065,26 @@
 			atomic_set(&vha->loop_state, LOOP_READY);
 			ql_dbg(ql_dbg_disc, vha, 0x2069,
 			    "LOOP READY.\n");
+
+			/*
+			 * Process any ATIO queue entries that came in
+			 * while we weren't online.
+			 */
+			if (qla_tgt_mode_enabled(vha)) {
+				if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
+					spin_lock_irqsave(&ha->tgt.atio_lock,
+					    flags);
+					qlt_24xx_process_atio_queue(vha, 0);
+					spin_unlock_irqrestore(
+					    &ha->tgt.atio_lock, flags);
+				} else {
+					spin_lock_irqsave(&ha->hardware_lock,
+					    flags);
+					qlt_24xx_process_atio_queue(vha, 1);
+					spin_unlock_irqrestore(
+					    &ha->hardware_lock, flags);
+				}
+			}
 		}
 	}
 
@@ -3260,7 +3292,8 @@
 		return;
 
 	if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
-	    fcport->fp_speed > ha->link_data_rate)
+	    fcport->fp_speed > ha->link_data_rate ||
+	    !ha->flags.gpsc_supported)
 		return;
 
 	rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
@@ -4907,7 +4940,6 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = ha->req_q_map[0];
 	struct rsp_que *rsp = ha->rsp_q_map[0];
-	unsigned long flags;
 
 	/* If firmware needs to be loaded */
 	if (qla2x00_isp_firmware(vha)) {
@@ -4929,17 +4961,6 @@
 			/* Issue a marker after FW becomes ready. */
 			qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
 
-			vha->flags.online = 1;
-
-			/*
-			 * Process any ATIO queue entries that came in
-			 * while we weren't online.
-			 */
-			spin_lock_irqsave(&ha->hardware_lock, flags);
-			if (qla_tgt_mode_enabled(vha))
-				qlt_24xx_process_atio_queue(vha);
-			spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
 			set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
 		}
 
@@ -4961,7 +4982,7 @@
 
 	for (i = 1; i < ha->max_rsp_queues; i++) {
 		rsp = ha->rsp_q_map[i];
-		if (rsp) {
+		if (rsp && test_bit(i, ha->rsp_qid_map)) {
 			rsp->options &= ~BIT_0;
 			ret = qla25xx_init_rsp_que(base_vha, rsp);
 			if (ret != QLA_SUCCESS)
@@ -4976,8 +4997,8 @@
 	}
 	for (i = 1; i < ha->max_req_queues; i++) {
 		req = ha->req_q_map[i];
-		if (req) {
-		/* Clear outstanding commands array. */
+		if (req && test_bit(i, ha->req_qid_map)) {
+			/* Clear outstanding commands array. */
 			req->options &= ~BIT_0;
 			ret = qla25xx_init_req_que(base_vha, req);
 			if (ret != QLA_SUCCESS)
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_inline.h
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_inline.h
@@ -258,6 +258,8 @@
 	if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
 	    (sp->type == SRB_FXIOCB_DCMD))
 		init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
+	if (sp->type == SRB_ELS_DCMD)
+		init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
 }
 
 static inline int
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_iocb.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1868,6 +1868,7 @@
 	}
 
 queuing_error:
+	vha->tgt_counters.num_alloc_iocb_failed++;
 	return pkt;
 }
 
@@ -2010,6 +2011,192 @@
 }
 
 static void
+qla2x00_els_dcmd_sp_free(void *ptr, void *data)
+{
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)ptr;
+	struct qla_hw_data *ha = vha->hw;
+	srb_t *sp = (srb_t *)data;
+	struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+	if (sp->fcport)
+		kfree(sp->fcport);
+
+	if (elsio->u.els_logo.els_logo_pyld)
+		dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+		    elsio->u.els_logo.els_logo_pyld,
+		    elsio->u.els_logo.els_logo_pyld_dma);
+
+	del_timer(&elsio->timer);
+	qla2x00_rel_sp(vha, sp);
+}
+
+static void
+qla2x00_els_dcmd_iocb_timeout(void *data)
+{
+	srb_t *sp = (srb_t *)data;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
+	fc_port_t *fcport = sp->fcport;
+	struct scsi_qla_host *vha = fcport->vha;
+	struct qla_hw_data *ha = vha->hw;
+	unsigned long flags = 0;
+
+	ql_dbg(ql_dbg_io, vha, 0x3069,
+	    "%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
+	    sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
+	    fcport->d_id.b.al_pa);
+
+	/* Abort the exchange */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	if (ha->isp_ops->abort_command(sp)) {
+		ql_dbg(ql_dbg_io, vha, 0x3070,
+		    "mbx abort_command failed.\n");
+	} else {
+		ql_dbg(ql_dbg_io, vha, 0x3071,
+		    "mbx abort_command success.\n");
+	}
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	complete(&lio->u.els_logo.comp);
+}
+
+static void
+qla2x00_els_dcmd_sp_done(void *data, void *ptr, int res)
+{
+	srb_t *sp = (srb_t *)ptr;
+	fc_port_t *fcport = sp->fcport;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
+	struct scsi_qla_host *vha = fcport->vha;
+
+	ql_dbg(ql_dbg_io, vha, 0x3072,
+	    "%s hdl=%x, portid=%02x%02x%02x done\n",
+	    sp->name, sp->handle, fcport->d_id.b.domain,
+	    fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+	complete(&lio->u.els_logo.comp);
+}
+
+int
+qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
+    port_id_t remote_did)
+{
+	srb_t *sp;
+	fc_port_t *fcport = NULL;
+	struct srb_iocb *elsio = NULL;
+	struct qla_hw_data *ha = vha->hw;
+	struct els_logo_payload logo_pyld;
+	int rval = QLA_SUCCESS;
+
+	fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+	if (!fcport) {
+	       ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n");
+	       return -ENOMEM;
+	}
+
+	/* Alloc SRB structure */
+	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+	if (!sp) {
+		kfree(fcport);
+		ql_log(ql_log_info, vha, 0x70e6,
+		 "SRB allocation failed\n");
+		return -ENOMEM;
+	}
+
+	elsio = &sp->u.iocb_cmd;
+	fcport->loop_id = 0xFFFF;
+	fcport->d_id.b.domain = remote_did.b.domain;
+	fcport->d_id.b.area = remote_did.b.area;
+	fcport->d_id.b.al_pa = remote_did.b.al_pa;
+
+	ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n",
+	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+	sp->type = SRB_ELS_DCMD;
+	sp->name = "ELS_DCMD";
+	sp->fcport = fcport;
+	qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
+	elsio->timeout = qla2x00_els_dcmd_iocb_timeout;
+	sp->done = qla2x00_els_dcmd_sp_done;
+	sp->free = qla2x00_els_dcmd_sp_free;
+
+	elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev,
+			    DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma,
+			    GFP_KERNEL);
+
+	if (!elsio->u.els_logo.els_logo_pyld) {
+		sp->free(vha, sp);
+		kfree(sp->fcport);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	memset(&logo_pyld, 0, sizeof(struct els_logo_payload));
+
+	elsio->u.els_logo.els_cmd = els_opcode;
+	logo_pyld.opcode = els_opcode;
+	logo_pyld.s_id[0] = vha->d_id.b.al_pa;
+	logo_pyld.s_id[1] = vha->d_id.b.area;
+	logo_pyld.s_id[2] = vha->d_id.b.domain;
+	host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t));
+	memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE);
+
+	memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld,
+	    sizeof(struct els_logo_payload));
+
+	rval = qla2x00_start_sp(sp);
+	if (rval != QLA_SUCCESS) {
+		sp->free(vha, sp);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	ql_dbg(ql_dbg_io, vha, 0x3074,
+	    "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n",
+	    sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+	    fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+	wait_for_completion(&elsio->u.els_logo.comp);
+
+	sp->free(vha, sp);
+	return rval;
+}
+
+static void
+qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+{
+	scsi_qla_host_t *vha = sp->fcport->vha;
+	struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+	els_iocb->entry_type = ELS_IOCB_TYPE;
+	els_iocb->entry_count = 1;
+	els_iocb->sys_define = 0;
+	els_iocb->entry_status = 0;
+	els_iocb->handle = sp->handle;
+	els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+	els_iocb->tx_dsd_count = 1;
+	els_iocb->vp_index = vha->vp_idx;
+	els_iocb->sof_type = EST_SOFI3;
+	els_iocb->rx_dsd_count = 0;
+	els_iocb->opcode = elsio->u.els_logo.els_cmd;
+
+	els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+	els_iocb->port_id[1] = sp->fcport->d_id.b.area;
+	els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+	els_iocb->control_flags = 0;
+
+	els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
+	els_iocb->tx_address[0] =
+	    cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
+	els_iocb->tx_address[1] =
+	    cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
+	els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
+
+	els_iocb->rx_byte_count = 0;
+	els_iocb->rx_address[0] = 0;
+	els_iocb->rx_address[1] = 0;
+	els_iocb->rx_len = 0;
+
+	sp->fcport->vha->qla_stats.control_requests++;
+}
+
+static void
 qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 {
 	struct fc_bsg_job *bsg_job = sp->u.bsg_job;
@@ -2623,6 +2810,9 @@
 			qlafx00_abort_iocb(sp, pkt) :
 			qla24xx_abort_iocb(sp, pkt);
 		break;
+	case SRB_ELS_DCMD:
+		qla24xx_els_logo_iocb(sp, pkt);
+		break;
 	default:
 		break;
 	}
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_isr.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_isr.c
@@ -18,6 +18,10 @@
 static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
 static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
 	sts_entry_t *);
+static void qla_irq_affinity_notify(struct irq_affinity_notify *,
+    const cpumask_t *);
+static void qla_irq_affinity_release(struct kref *);
+
 
 /**
  * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -268,7 +272,8 @@
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
 	/* Read all mbox registers? */
-	mboxes = (1 << ha->mbx_count) - 1;
+	WARN_ON_ONCE(ha->mbx_count > 32);
+	mboxes = (1ULL << ha->mbx_count) - 1;
 	if (!ha->mcp)
 		ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n");
 	else
@@ -965,8 +970,6 @@
 			ql_dbg(ql_dbg_async, vha, 0x5011,
 			    "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
 			    mb[1], mb[2], mb[3]);
-
-			qlt_async_event(mb[0], vha, mb);
 			break;
 		}
 
@@ -987,8 +990,6 @@
 		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
 		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
 		set_bit(VP_CONFIG_OK, &vha->vp_flags);
-
-		qlt_async_event(mb[0], vha, mb);
 		break;
 
 	case MBA_RSCN_UPDATE:		/* State Change Registration */
@@ -1418,6 +1419,12 @@
 	case SRB_CT_CMD:
 		type = "ct pass-through";
 		break;
+	case SRB_ELS_DCMD:
+		type = "Driver ELS logo";
+		ql_dbg(ql_dbg_user, vha, 0x5047,
+		    "Completing %s: (%p) type=%d.\n", type, sp, sp->type);
+		sp->done(vha, sp, 0);
+		return;
 	default:
 		ql_dbg(ql_dbg_user, vha, 0x503e,
 		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
@@ -2466,6 +2473,10 @@
 	if (pkt->entry_status & RF_BUSY)
 		res = DID_BUS_BUSY << 16;
 
+	if (pkt->entry_type == NOTIFY_ACK_TYPE &&
+	    pkt->handle == QLA_TGT_SKIP_HANDLE)
+		return;
+
 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
 	if (sp) {
 		sp->done(ha, sp, res);
@@ -2491,7 +2502,8 @@
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
 	/* Read all mbox registers? */
-	mboxes = (1 << ha->mbx_count) - 1;
+	WARN_ON_ONCE(ha->mbx_count > 32);
+	mboxes = (1ULL << ha->mbx_count) - 1;
 	if (!ha->mcp)
 		ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n");
 	else
@@ -2542,6 +2554,14 @@
 	if (!vha->flags.online)
 		return;
 
+	if (rsp->msix && (rsp->msix->cpuid != smp_processor_id())) {
+		/* if kernel does not notify qla of IRQ's CPU change,
+		 * then set it here.
+		 */
+		rsp->msix->cpuid = smp_processor_id();
+		ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid;
+	}
+
 	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
 		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
 
@@ -2587,8 +2607,14 @@
 			qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
 			break;
 		case ABTS_RECV_24XX:
-			/* ensure that the ATIO queue is empty */
-			qlt_24xx_process_atio_queue(vha);
+			if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+				/* ensure that the ATIO queue is empty */
+				qlt_handle_abts_recv(vha, (response_t *)pkt);
+				break;
+			} else {
+				/* drop through */
+				qlt_24xx_process_atio_queue(vha, 1);
+			}
 		case ABTS_RESP_24XX:
 		case CTIO_TYPE7:
 		case NOTIFY_ACK_TYPE:
@@ -2755,13 +2781,22 @@
 		case INTR_RSP_QUE_UPDATE_83XX:
 			qla24xx_process_response_queue(vha, rsp);
 			break;
-		case INTR_ATIO_QUE_UPDATE:
-			qlt_24xx_process_atio_queue(vha);
+		case INTR_ATIO_QUE_UPDATE:{
+			unsigned long flags2;
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+			qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
 			break;
-		case INTR_ATIO_RSP_QUE_UPDATE:
-			qlt_24xx_process_atio_queue(vha);
+		}
+		case INTR_ATIO_RSP_QUE_UPDATE: {
+			unsigned long flags2;
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+			qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
 			qla24xx_process_response_queue(vha, rsp);
 			break;
+		}
 		default:
 			ql_dbg(ql_dbg_async, vha, 0x504f,
 			    "Unrecognized interrupt type (%d).\n", stat * 0xff);
@@ -2920,13 +2955,22 @@
 		case INTR_RSP_QUE_UPDATE_83XX:
 			qla24xx_process_response_queue(vha, rsp);
 			break;
-		case INTR_ATIO_QUE_UPDATE:
-			qlt_24xx_process_atio_queue(vha);
+		case INTR_ATIO_QUE_UPDATE:{
+			unsigned long flags2;
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+			qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
 			break;
-		case INTR_ATIO_RSP_QUE_UPDATE:
-			qlt_24xx_process_atio_queue(vha);
+		}
+		case INTR_ATIO_RSP_QUE_UPDATE: {
+			unsigned long flags2;
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+			qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
 			qla24xx_process_response_queue(vha, rsp);
 			break;
+		}
 		default:
 			ql_dbg(ql_dbg_async, vha, 0x5051,
 			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
@@ -2973,8 +3017,11 @@
 
 	for (i = 0; i < ha->msix_count; i++) {
 		qentry = &ha->msix_entries[i];
-		if (qentry->have_irq)
+		if (qentry->have_irq) {
+			/* un-register irq cpu affinity notification */
+			irq_set_affinity_notifier(qentry->vector, NULL);
 			free_irq(qentry->vector, qentry->rsp);
+		}
 	}
 	pci_disable_msix(ha->pdev);
 	kfree(ha->msix_entries);
@@ -3018,9 +3065,9 @@
 		    "MSI-X: Failed to enable support "
 		    "-- %d/%d\n Retry with %d vectors.\n",
 		    ha->msix_count, ret, ret);
+		ha->msix_count = ret;
+		ha->max_rsp_queues = ha->msix_count - 1;
 	}
-	ha->msix_count = ret;
-	ha->max_rsp_queues = ha->msix_count - 1;
 	ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
 				ha->msix_count, GFP_KERNEL);
 	if (!ha->msix_entries) {
@@ -3037,6 +3084,9 @@
 		qentry->entry = entries[i].entry;
 		qentry->have_irq = 0;
 		qentry->rsp = NULL;
+		qentry->irq_notify.notify  = qla_irq_affinity_notify;
+		qentry->irq_notify.release = qla_irq_affinity_release;
+		qentry->cpuid = -1;
 	}
 
 	/* Enable MSI-X vectors for the base queue */
@@ -3055,6 +3105,18 @@
 		qentry->have_irq = 1;
 		qentry->rsp = rsp;
 		rsp->msix = qentry;
+
+		/* Register for CPU affinity notification. */
+		irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);
+
+		/* Schedule work (ie. trigger a notification) to read cpu
+		 * mask for this specific irq.
+		 * kref_get is required because
+		* irq_affinity_notify() will do
+		* kref_put().
+		*/
+		kref_get(&qentry->irq_notify.kref);
+		schedule_work(&qentry->irq_notify.work);
 	}
 
 	/*
@@ -3234,3 +3296,47 @@
 	msix->rsp = rsp;
 	return ret;
 }
+
+
+/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */
+static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
+	const cpumask_t *mask)
+{
+	struct qla_msix_entry *e =
+		container_of(notify, struct qla_msix_entry, irq_notify);
+	struct qla_hw_data *ha;
+	struct scsi_qla_host *base_vha;
+
+	/* user is recommended to set mask to just 1 cpu */
+	e->cpuid = cpumask_first(mask);
+
+	ha = e->rsp->hw;
+	base_vha = pci_get_drvdata(ha->pdev);
+
+	ql_dbg(ql_dbg_init, base_vha, 0xffff,
+	    "%s: host %ld : vector %d cpu %d \n", __func__,
+	    base_vha->host_no, e->vector, e->cpuid);
+
+	if (e->have_irq) {
+		if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
+		    (e->entry == QLA83XX_RSPQ_MSIX_ENTRY_NUMBER)) {
+			ha->tgt.rspq_vector_cpuid = e->cpuid;
+			ql_dbg(ql_dbg_init, base_vha, 0xffff,
+			    "%s: host%ld: rspq vector %d cpu %d  runtime change\n",
+			    __func__, base_vha->host_no, e->vector, e->cpuid);
+		}
+	}
+}
+
+static void qla_irq_affinity_release(struct kref *ref)
+{
+	struct irq_affinity_notify *notify =
+		container_of(ref, struct irq_affinity_notify, kref);
+	struct qla_msix_entry *e =
+		container_of(notify, struct qla_msix_entry, irq_notify);
+	struct scsi_qla_host *base_vha = pci_get_drvdata(e->rsp->hw->pdev);
+
+	ql_dbg(ql_dbg_init, base_vha, 0xffff,
+	    "%s: host%ld: vector %d cpu %d \n", __func__,
+	    base_vha->host_no, e->vector, e->cpuid);
+}
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_mbx.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_mbx.c
@@ -489,6 +489,13 @@
 			    EXTENDED_BB_CREDITS);
 		} else
 			mcp->mb[4] = 0;
+
+		if (ha->flags.exlogins_enabled)
+			mcp->mb[4] |= ENABLE_EXTENDED_LOGIN;
+
+		if (ha->flags.exchoffld_enabled)
+			mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD;
+
 		mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
 		mcp->in_mb |= MBX_1;
 	} else {
@@ -521,6 +528,226 @@
 }
 
 /*
+ * qla_get_exlogin_status
+ *	Get extended login status
+ *	uses the memory offload control/status Mailbox
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fwopt:		firmware options
+ *
+ * Returns:
+ *	qla2x00 local function status
+ *
+ * Context:
+ *	Kernel context.
+ */
+#define	FETCH_XLOGINS_STAT	0x8
+int
+qla_get_exlogin_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+	uint16_t *ex_logins_cnt)
+{
+	int rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118f,
+	    "Entered %s\n", __func__);
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+	mcp->mb[1] = FETCH_XLOGINS_STAT;
+	mcp->out_mb = MBX_1|MBX_0;
+	mcp->in_mb = MBX_10|MBX_4|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x1115, "Failed=%x.\n", rval);
+	} else {
+		*buf_sz = mcp->mb[4];
+		*ex_logins_cnt = mcp->mb[10];
+
+		ql_log(ql_log_info, vha, 0x1190,
+		    "buffer size 0x%x, exchange login count=%d\n",
+		    mcp->mb[4], mcp->mb[10]);
+
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1116,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+/*
+ * qla_set_exlogin_mem_cfg
+ *	set extended login memory configuration
+ *	Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	buffer:		buffer pointer
+ *	phys_addr:	physical address of buffer
+ *	size:		size of buffer
+ *	TARGET_QUEUE_LOCK must be released
+ *	ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ *	qla2x00 local funxtion status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+#define CONFIG_XLOGINS_MEM	0x3
+int
+qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+	int		rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+	struct qla_hw_data *ha = vha->hw;
+	int configured_count;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111a,
+	    "Entered %s.\n", __func__);
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+	mcp->mb[1] = CONFIG_XLOGINS_MEM;
+	mcp->mb[2] = MSW(phys_addr);
+	mcp->mb[3] = LSW(phys_addr);
+	mcp->mb[6] = MSW(MSD(phys_addr));
+	mcp->mb[7] = LSW(MSD(phys_addr));
+	mcp->mb[8] = MSW(ha->exlogin_size);
+	mcp->mb[9] = LSW(ha->exlogin_size);
+	mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_11|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		ql_dbg(ql_dbg_mbx, vha, 0x111b, "Failed=%x.\n", rval);
+	} else {
+		configured_count = mcp->mb[11];
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+/*
+ * qla_get_exchoffld_status
+ *	Get exchange offload status
+ *	uses the memory offload control/status Mailbox
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fwopt:		firmware options
+ *
+ * Returns:
+ *	qla2x00 local function status
+ *
+ * Context:
+ *	Kernel context.
+ */
+#define	FETCH_XCHOFFLD_STAT	0x2
+int
+qla_get_exchoffld_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+	uint16_t *ex_logins_cnt)
+{
+	int rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1019,
+	    "Entered %s\n", __func__);
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+	mcp->mb[1] = FETCH_XCHOFFLD_STAT;
+	mcp->out_mb = MBX_1|MBX_0;
+	mcp->in_mb = MBX_10|MBX_4|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x1155, "Failed=%x.\n", rval);
+	} else {
+		*buf_sz = mcp->mb[4];
+		*ex_logins_cnt = mcp->mb[10];
+
+		ql_log(ql_log_info, vha, 0x118e,
+		    "buffer size 0x%x, exchange offload count=%d\n",
+		    mcp->mb[4], mcp->mb[10]);
+
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1156,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+/*
+ * qla_set_exchoffld_mem_cfg
+ *	Set exchange offload memory configuration
+ *	Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	buffer:		buffer pointer
+ *	phys_addr:	physical address of buffer
+ *	size:		size of buffer
+ *	TARGET_QUEUE_LOCK must be released
+ *	ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ *	qla2x00 local funxtion status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+#define CONFIG_XCHOFFLD_MEM	0x3
+int
+qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+	int		rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+	struct qla_hw_data *ha = vha->hw;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1157,
+	    "Entered %s.\n", __func__);
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+	mcp->mb[1] = CONFIG_XCHOFFLD_MEM;
+	mcp->mb[2] = MSW(phys_addr);
+	mcp->mb[3] = LSW(phys_addr);
+	mcp->mb[6] = MSW(MSD(phys_addr));
+	mcp->mb[7] = LSW(MSD(phys_addr));
+	mcp->mb[8] = MSW(ha->exlogin_size);
+	mcp->mb[9] = LSW(ha->exlogin_size);
+	mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_11|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		ql_dbg(ql_dbg_mbx, vha, 0x1158, "Failed=%x.\n", rval);
+	} else {
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+/*
  * qla2x00_get_fw_version
  *	Get firmware version.
  *
@@ -594,6 +821,16 @@
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x112f,
 		    "%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n",
 		    __func__, mcp->mb[17], mcp->mb[16]);
+
+		if (ha->fw_attributes_h & 0x4)
+			ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118d,
+			    "%s: Firmware supports Extended Login 0x%x\n",
+			    __func__, ha->fw_attributes_h);
+
+		if (ha->fw_attributes_h & 0x8)
+			ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1191,
+			    "%s: Firmware supports Exchange Offload 0x%x\n",
+			    __func__, ha->fw_attributes_h);
 	}
 
 	if (IS_QLA27XX(ha)) {
@@ -2383,10 +2620,9 @@
  *	Kernel context.
  */
 int
-qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
-    uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
-    uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports, uint16_t *max_fcfs)
+qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
 {
+	struct qla_hw_data *ha = vha->hw;
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
@@ -2414,19 +2650,16 @@
 		    mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10],
 		    mcp->mb[11], mcp->mb[12]);
 
-		if (cur_xchg_cnt)
-			*cur_xchg_cnt = mcp->mb[3];
-		if (orig_xchg_cnt)
-			*orig_xchg_cnt = mcp->mb[6];
-		if (cur_iocb_cnt)
-			*cur_iocb_cnt = mcp->mb[7];
-		if (orig_iocb_cnt)
-			*orig_iocb_cnt = mcp->mb[10];
-		if (vha->hw->flags.npiv_supported && max_npiv_vports)
-			*max_npiv_vports = mcp->mb[11];
-		if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) ||
-		    IS_QLA27XX(vha->hw)) && max_fcfs)
-			*max_fcfs = mcp->mb[12];
+		ha->orig_fw_tgt_xcb_count =  mcp->mb[1];
+		ha->cur_fw_tgt_xcb_count = mcp->mb[2];
+		ha->cur_fw_xcb_count = mcp->mb[3];
+		ha->orig_fw_xcb_count = mcp->mb[6];
+		ha->cur_fw_iocb_count = mcp->mb[7];
+		ha->orig_fw_iocb_count = mcp->mb[10];
+		if (ha->flags.npiv_supported)
+			ha->max_npiv_vports = mcp->mb[11];
+		if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+			ha->fw_max_fcf_count = mcp->mb[12];
 	}
 
 	return (rval);
@@ -3315,10 +3548,7 @@
 	mcp->mb[0] = MBC_PORT_PARAMS;
 	mcp->mb[1] = loop_id;
 	mcp->mb[2] = BIT_0;
-	if (IS_CNA_CAPABLE(vha->hw))
-		mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
-	else
-		mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
+	mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
 	mcp->mb[9] = vha->vp_idx;
 	mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_3|MBX_1|MBX_0;
@@ -5458,9 +5688,8 @@
 	mcp->mb[7] = LSW(MSD(req_dma));
 	mcp->mb[8] = MSW(addr);
 	/* Setting RAM ID to valid */
-	mcp->mb[10] |= BIT_7;
 	/* For MCTP RAM ID is 0x40 */
-	mcp->mb[10] |= 0x40;
+	mcp->mb[10] = BIT_7 | 0x40;
 
 	mcp->out_mb |= MBX_10|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|
 	    MBX_0;
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_mid.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_mid.c
@@ -600,7 +600,7 @@
 	/* Delete request queues */
 	for (cnt = 1; cnt < ha->max_req_queues; cnt++) {
 		req = ha->req_q_map[cnt];
-		if (req) {
+		if (req && test_bit(cnt, ha->req_qid_map)) {
 			ret = qla25xx_delete_req_que(vha, req);
 			if (ret != QLA_SUCCESS) {
 				ql_log(ql_log_warn, vha, 0x00ea,
@@ -614,7 +614,7 @@
 	/* Delete response queues */
 	for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) {
 		rsp = ha->rsp_q_map[cnt];
-		if (rsp) {
+		if (rsp && test_bit(cnt, ha->rsp_qid_map)) {
 			ret = qla25xx_delete_rsp_que(vha, rsp);
 			if (ret != QLA_SUCCESS) {
 				ql_log(ql_log_warn, vha, 0x00eb,
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_mr.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_mr.c
@@ -11,6 +11,7 @@
 #include <linux/vmalloc.h>
 #include <scsi/scsi_tcq.h>
 #include <linux/utsname.h>
+#include <linux/nospec.h>
 
 
 /* QLAFX00 specific Mailbox implementation functions */
@@ -2302,10 +2303,12 @@
 	req = ha->req_q_map[que];
 
 	/* Validate handle. */
-	if (handle < req->num_outstanding_cmds)
+	if (handle < req->num_outstanding_cmds) {
+		handle = array_index_nospec(handle, req->num_outstanding_cmds); /* needed? */
 		sp = req->outstanding_cmds[handle];
-	else
+	} else {
 		sp = NULL;
+	}
 
 	if (sp == NULL) {
 		ql_dbg(ql_dbg_io, vha, 0x3034,
@@ -2653,10 +2656,12 @@
 		req = ha->req_q_map[que];
 
 		/* Validate handle. */
-		if (handle < req->num_outstanding_cmds)
+		if (handle < req->num_outstanding_cmds) {
+			handle = array_index_nospec(handle, req->num_outstanding_cmds); /* needed? */
 			sp = req->outstanding_cmds[handle];
-		else
+		} else {
 			sp = NULL;
+		}
 
 		if (sp == NULL) {
 			ql_dbg(ql_dbg_io, vha, 0x3044,
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_nx.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_nx.c
@@ -10,6 +10,7 @@
 #include <linux/ratelimit.h>
 #include <linux/vmalloc.h>
 #include <scsi/scsi_tcq.h>
+#include <asm/unaligned.h>
 
 #define MASK(n)			((1ULL<<(n))-1)
 #define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \
@@ -1600,8 +1601,7 @@
 	return (u8 *)&ha->hablob->fw->data[offset];
 }
 
-static __le32
-qla82xx_get_fw_size(struct qla_hw_data *ha)
+static u32 qla82xx_get_fw_size(struct qla_hw_data *ha)
 {
 	struct qla82xx_uri_data_desc *uri_desc = NULL;
 
@@ -1612,7 +1612,7 @@
 			return cpu_to_le32(uri_desc->size);
 	}
 
-	return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]);
+	return get_unaligned_le32(&ha->hablob->fw->data[FW_SIZE_OFFSET]);
 }
 
 static u8 *
@@ -1803,7 +1803,7 @@
 	}
 
 	flashaddr = FLASH_ADDR_START;
-	size = (__force u32)qla82xx_get_fw_size(ha) / 8;
+	size = qla82xx_get_fw_size(ha) / 8;
 	ptr64 = (u64 *)qla82xx_get_fw_offs(ha);
 
 	for (i = 0; i < size; i++) {
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_os.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_os.c
@@ -221,6 +221,18 @@
 		"0 - MiniDump disabled. "
 		"1 (Default) - MiniDump enabled.");
 
+int ql2xexlogins = 0;
+module_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexlogins,
+		 "Number of extended Logins. "
+		 "0 (Default)- Disabled.");
+
+int ql2xexchoffld = 0;
+module_param(ql2xexchoffld, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexchoffld,
+		 "Number of exchanges to offload. "
+		 "0 (Default)- Disabled.");
+
 /*
  * SCSI host template entry points
  */
@@ -397,6 +409,9 @@
 	int cnt;
 
 	for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
+		if (!test_bit(cnt, ha->req_qid_map))
+			continue;
+
 		req = ha->req_q_map[cnt];
 		qla2x00_free_req_que(ha, req);
 	}
@@ -404,6 +419,9 @@
 	ha->req_q_map = NULL;
 
 	for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
+		if (!test_bit(cnt, ha->rsp_qid_map))
+			continue;
+
 		rsp = ha->rsp_q_map[cnt];
 		qla2x00_free_rsp_que(ha, rsp);
 	}
@@ -423,6 +441,12 @@
 		goto fail;
 	}
 	if (ql2xmultique_tag) {
+		ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1);
+		if (unlikely(!ha->wq)) {
+			ql_log(ql_log_warn, vha, 0x01e0,
+			    "Failed to alloc workqueue.\n");
+			goto fail;
+		}
 		/* create a request queue for IO */
 		options |= BIT_7;
 		req = qla25xx_create_req_que(ha, options, 0, 0, -1,
@@ -430,9 +454,8 @@
 		if (!req) {
 			ql_log(ql_log_warn, vha, 0x00e0,
 			    "Failed to create request queue.\n");
-			goto fail;
+			goto fail2;
 		}
-		ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1);
 		vha->req = ha->req_q_map[req];
 		options |= BIT_1;
 		for (ques = 1; ques < ha->max_rsp_queues; ques++) {
@@ -440,7 +463,7 @@
 			if (!ret) {
 				ql_log(ql_log_warn, vha, 0x00e8,
 				    "Failed to create response queue.\n");
-				goto fail2;
+				goto fail3;
 			}
 		}
 		ha->flags.cpu_affinity_enabled = 1;
@@ -454,11 +477,13 @@
 		    ha->max_rsp_queues, ha->max_req_queues);
 	}
 	return 0;
-fail2:
+
+fail3:
 	qla25xx_delete_queues(vha);
-	destroy_workqueue(ha->wq);
-	ha->wq = NULL;
 	vha->req = ha->req_q_map[0];
+fail2:
+        destroy_workqueue(ha->wq);
+        ha->wq = NULL;
 fail:
 	ha->mqenable = 0;
 	kfree(ha->req_q_map);
@@ -679,6 +704,11 @@
 	srb_t *sp;
 	int rval;
 
+	if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags))) {
+		cmd->result = DID_NO_CONNECT << 16;
+		goto qc24_fail_command;
+	}
+
 	if (ha->flags.eeh_busy) {
 		if (ha->flags.pci_channel_io_perm_failure) {
 			ql_dbg(ql_dbg_aer, vha, 0x9010,
@@ -2251,6 +2281,8 @@
 {
 	scsi_qla_host_t *vha = shost_priv(shost);
 
+	if (test_bit(UNLOADING, &vha->dpc_flags))
+		return 1;
 	if (!vha->host)
 		return 1;
 	if (time > vha->hw->loop_reset_delay * HZ)
@@ -2303,10 +2335,10 @@
 
 	if (mem_only) {
 		if (pci_enable_device_mem(pdev))
-			goto probe_out;
+			return ret;
 	} else {
 		if (pci_enable_device(pdev))
-			goto probe_out;
+			return ret;
 	}
 
 	/* This may fail but that's ok */
@@ -2316,7 +2348,7 @@
 	if (!ha) {
 		ql_log_pci(ql_log_fatal, pdev, 0x0009,
 		    "Unable to allocate memory for ha.\n");
-		goto probe_out;
+		goto disable_device;
 	}
 	ql_dbg_pci(ql_dbg_init, pdev, 0x000a,
 	    "Memory allocated for ha=%p.\n", ha);
@@ -2324,6 +2356,9 @@
 	ha->tgt.enable_class_2 = ql2xenableclass2;
 	INIT_LIST_HEAD(&ha->tgt.q_full_list);
 	spin_lock_init(&ha->tgt.q_full_lock);
+	spin_lock_init(&ha->tgt.sess_lock);
+	spin_lock_init(&ha->tgt.atio_lock);
+
 
 	/* Clear our data area */
 	ha->bars = bars;
@@ -2468,7 +2503,7 @@
 		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
 		req_length = REQUEST_ENTRY_CNT_83XX;
-		rsp_length = RESPONSE_ENTRY_CNT_2300;
+		rsp_length = RESPONSE_ENTRY_CNT_83XX;
 		ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
 		ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
 		ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -2498,8 +2533,8 @@
 		ha->portnum = PCI_FUNC(ha->pdev->devfn);
 		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
-		req_length = REQUEST_ENTRY_CNT_24XX;
-		rsp_length = RESPONSE_ENTRY_CNT_2300;
+		req_length = REQUEST_ENTRY_CNT_83XX;
+		rsp_length = RESPONSE_ENTRY_CNT_83XX;
 		ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
 		ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
 		ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -2915,7 +2950,7 @@
 	kfree(ha);
 	ha = NULL;
 
-probe_out:
+disable_device:
 	pci_disable_device(pdev);
 	return ret;
 }
@@ -2949,6 +2984,10 @@
 	/* Stop currently executing firmware. */
 	qla2x00_try_to_stop_firmware(vha);
 
+	/* Disable timer */
+	if (vha->timer_active)
+		qla2x00_stop_timer(vha);
+
 	/* Turn adapter off line */
 	vha->flags.online = 0;
 
@@ -3128,6 +3167,14 @@
 
 	base_vha->flags.online = 0;
 
+	/* free DMA memory */
+	if (ha->exlogin_buf)
+		qla2x00_free_exlogin_buffer(ha);
+
+	/* free DMA memory */
+	if (ha->exchoffld_buf)
+		qla2x00_free_exchoffld_buffer(ha);
+
 	qla2x00_destroy_deferred_work(ha);
 
 	qlt_remove_target(ha, base_vha);
@@ -3357,7 +3404,7 @@
 				sizeof(struct ct6_dsd), 0,
 				SLAB_HWCACHE_ALIGN, NULL);
 			if (!ctx_cachep)
-				goto fail_free_gid_list;
+				goto fail_free_srb_mempool;
 		}
 		ha->ctx_mempool = mempool_create_slab_pool(SRB_MIN_REQ,
 			ctx_cachep);
@@ -3510,7 +3557,7 @@
 	ha->loop_id_map = kzalloc(BITS_TO_LONGS(LOOPID_MAP_SIZE) * sizeof(long),
 	    GFP_KERNEL);
 	if (!ha->loop_id_map)
-		goto fail_async_pd;
+		goto fail_loop_id_map;
 	else {
 		qla2x00_set_reserved_loop_ids(ha);
 		ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0123,
@@ -3519,6 +3566,8 @@
 
 	return 0;
 
+fail_loop_id_map:
+	dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
 fail_async_pd:
 	dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
 fail_ex_init_cb:
@@ -3546,6 +3595,10 @@
 	dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
 	ha->ms_iocb = NULL;
 	ha->ms_iocb_dma = 0;
+
+	if (ha->sns_cmd)
+		dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
+		    ha->sns_cmd, ha->sns_cmd_dma);
 fail_dma_pool:
 	if (IS_QLA82XX(ha) || ql2xenabledif) {
 		dma_pool_destroy(ha->fcp_cmnd_dma_pool);
@@ -3563,10 +3616,12 @@
 	kfree(ha->nvram);
 	ha->nvram = NULL;
 fail_free_ctx_mempool:
-	mempool_destroy(ha->ctx_mempool);
+	if (ha->ctx_mempool)
+		mempool_destroy(ha->ctx_mempool);
 	ha->ctx_mempool = NULL;
 fail_free_srb_mempool:
-	mempool_destroy(ha->srb_mempool);
+	if (ha->srb_mempool)
+		mempool_destroy(ha->srb_mempool);
 	ha->srb_mempool = NULL;
 fail_free_gid_list:
 	dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
@@ -3587,6 +3642,140 @@
 	return -ENOMEM;
 }
 
+int
+qla2x00_set_exlogins_buffer(scsi_qla_host_t *vha)
+{
+	int rval;
+	uint16_t	size, max_cnt, temp;
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Return if we don't need to alloacate any extended logins */
+	if (!ql2xexlogins)
+		return QLA_SUCCESS;
+
+	ql_log(ql_log_info, vha, 0xd021, "EXLOGIN count: %d.\n", ql2xexlogins);
+	max_cnt = 0;
+	rval = qla_get_exlogin_status(vha, &size, &max_cnt);
+	if (rval != QLA_SUCCESS) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0xd029,
+		    "Failed to get exlogin status.\n");
+		return rval;
+	}
+
+	temp = (ql2xexlogins > max_cnt) ? max_cnt : ql2xexlogins;
+	ha->exlogin_size = (size * temp);
+	ql_log(ql_log_info, vha, 0xd024,
+		"EXLOGIN: max_logins=%d, portdb=0x%x, total=%d.\n",
+		max_cnt, size, temp);
+
+	ql_log(ql_log_info, vha, 0xd025, "EXLOGIN: requested size=0x%x\n",
+		ha->exlogin_size);
+
+	/* Get consistent memory for extended logins */
+	ha->exlogin_buf = dma_alloc_coherent(&ha->pdev->dev,
+	    ha->exlogin_size, &ha->exlogin_buf_dma, GFP_KERNEL);
+	if (!ha->exlogin_buf) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0xd02a,
+		    "Failed to allocate memory for exlogin_buf_dma.\n");
+		return -ENOMEM;
+	}
+
+	/* Now configure the dma buffer */
+	rval = qla_set_exlogin_mem_cfg(vha, ha->exlogin_buf_dma);
+	if (rval) {
+		ql_log(ql_log_fatal, vha, 0x00cf,
+		    "Setup extended login buffer  ****FAILED****.\n");
+		qla2x00_free_exlogin_buffer(ha);
+	}
+
+	return rval;
+}
+
+/*
+* qla2x00_free_exlogin_buffer
+*
+* Input:
+*	ha = adapter block pointer
+*/
+void
+qla2x00_free_exlogin_buffer(struct qla_hw_data *ha)
+{
+	if (ha->exlogin_buf) {
+		dma_free_coherent(&ha->pdev->dev, ha->exlogin_size,
+		    ha->exlogin_buf, ha->exlogin_buf_dma);
+		ha->exlogin_buf = NULL;
+		ha->exlogin_size = 0;
+	}
+}
+
+int
+qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha)
+{
+	int rval;
+	uint16_t	size, max_cnt, temp;
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Return if we don't need to alloacate any extended logins */
+	if (!ql2xexchoffld)
+		return QLA_SUCCESS;
+
+	ql_log(ql_log_info, vha, 0xd014,
+	    "Exchange offload count: %d.\n", ql2xexlogins);
+
+	max_cnt = 0;
+	rval = qla_get_exchoffld_status(vha, &size, &max_cnt);
+	if (rval != QLA_SUCCESS) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0xd012,
+		    "Failed to get exlogin status.\n");
+		return rval;
+	}
+
+	temp = (ql2xexchoffld > max_cnt) ? max_cnt : ql2xexchoffld;
+	ha->exchoffld_size = (size * temp);
+	ql_log(ql_log_info, vha, 0xd016,
+		"Exchange offload: max_count=%d, buffers=0x%x, total=%d.\n",
+		max_cnt, size, temp);
+
+	ql_log(ql_log_info, vha, 0xd017,
+	    "Exchange Buffers requested size = 0x%x\n", ha->exchoffld_size);
+
+	/* Get consistent memory for extended logins */
+	ha->exchoffld_buf = dma_alloc_coherent(&ha->pdev->dev,
+	    ha->exchoffld_size, &ha->exchoffld_buf_dma, GFP_KERNEL);
+	if (!ha->exchoffld_buf) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0xd013,
+		    "Failed to allocate memory for exchoffld_buf_dma.\n");
+		return -ENOMEM;
+	}
+
+	/* Now configure the dma buffer */
+	rval = qla_set_exchoffld_mem_cfg(vha, ha->exchoffld_buf_dma);
+	if (rval) {
+		ql_log(ql_log_fatal, vha, 0xd02e,
+		    "Setup exchange offload buffer ****FAILED****.\n");
+		qla2x00_free_exchoffld_buffer(ha);
+	}
+
+	return rval;
+}
+
+/*
+* qla2x00_free_exchoffld_buffer
+*
+* Input:
+*	ha = adapter block pointer
+*/
+void
+qla2x00_free_exchoffld_buffer(struct qla_hw_data *ha)
+{
+	if (ha->exchoffld_buf) {
+		dma_free_coherent(&ha->pdev->dev, ha->exchoffld_size,
+		    ha->exchoffld_buf, ha->exchoffld_buf_dma);
+		ha->exchoffld_buf = NULL;
+		ha->exchoffld_size = 0;
+	}
+}
+
 /*
 * qla2x00_free_fw_dump
 *	Frees fw dump stuff.
@@ -3766,6 +3955,8 @@
 	INIT_LIST_HEAD(&vha->list);
 	INIT_LIST_HEAD(&vha->qla_cmd_list);
 	INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
+	INIT_LIST_HEAD(&vha->logo_list);
+	INIT_LIST_HEAD(&vha->plogi_ack_list);
 
 	spin_lock_init(&vha->work_lock);
 	spin_lock_init(&vha->cmd_list_lock);
@@ -4922,8 +5113,9 @@
 			}
 		}
 
-		if (test_and_clear_bit(ISP_ABORT_NEEDED,
-						&base_vha->dpc_flags)) {
+		if (test_and_clear_bit
+		    (ISP_ABORT_NEEDED, &base_vha->dpc_flags) &&
+		    !test_bit(UNLOADING, &base_vha->dpc_flags)) {
 
 			ql_dbg(ql_dbg_dpc, base_vha, 0x4007,
 			    "ISP abort scheduled.\n");
@@ -5754,8 +5946,7 @@
 	/* Initialize target kmem_cache and mem_pools */
 	ret = qlt_init();
 	if (ret < 0) {
-		kmem_cache_destroy(srb_cachep);
-		return ret;
+		goto destroy_cache;
 	} else if (ret > 0) {
 		/*
 		 * If initiator mode is explictly disabled by qlt_init(),
@@ -5774,11 +5965,10 @@
 	qla2xxx_transport_template =
 	    fc_attach_transport(&qla2xxx_transport_functions);
 	if (!qla2xxx_transport_template) {
-		kmem_cache_destroy(srb_cachep);
 		ql_log(ql_log_fatal, NULL, 0x0002,
 		    "fc_attach_transport failed...Failing load!.\n");
-		qlt_exit();
-		return -ENODEV;
+		ret = -ENODEV;
+		goto qlt_exit;
 	}
 
 	apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops);
@@ -5790,27 +5980,37 @@
 	qla2xxx_transport_vport_template =
 	    fc_attach_transport(&qla2xxx_transport_vport_functions);
 	if (!qla2xxx_transport_vport_template) {
-		kmem_cache_destroy(srb_cachep);
-		qlt_exit();
-		fc_release_transport(qla2xxx_transport_template);
 		ql_log(ql_log_fatal, NULL, 0x0004,
 		    "fc_attach_transport vport failed...Failing load!.\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto unreg_chrdev;
 	}
 	ql_log(ql_log_info, NULL, 0x0005,
 	    "QLogic Fibre Channel HBA Driver: %s.\n",
 	    qla2x00_version_str);
 	ret = pci_register_driver(&qla2xxx_pci_driver);
 	if (ret) {
-		kmem_cache_destroy(srb_cachep);
-		qlt_exit();
-		fc_release_transport(qla2xxx_transport_template);
-		fc_release_transport(qla2xxx_transport_vport_template);
 		ql_log(ql_log_fatal, NULL, 0x0006,
 		    "pci_register_driver failed...ret=%d Failing load!.\n",
 		    ret);
+		goto release_vport_transport;
 	}
 	return ret;
+
+release_vport_transport:
+	fc_release_transport(qla2xxx_transport_vport_template);
+
+unreg_chrdev:
+	if (apidev_major >= 0)
+		unregister_chrdev(apidev_major, QLA2XXX_APIDEV);
+	fc_release_transport(qla2xxx_transport_template);
+
+qlt_exit:
+	qlt_exit();
+
+destroy_cache:
+	kmem_cache_destroy(srb_cachep);
+	return ret;
 }
 
 /**
@@ -5843,6 +6043,3 @@
 MODULE_FIRMWARE(FW_FILE_ISP2322);
 MODULE_FIRMWARE(FW_FILE_ISP24XX);
 MODULE_FIRMWARE(FW_FILE_ISP25XX);
-MODULE_FIRMWARE(FW_FILE_ISP2031);
-MODULE_FIRMWARE(FW_FILE_ISP8031);
-MODULE_FIRMWARE(FW_FILE_ISP27XX);
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_target.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_target.c
@@ -100,12 +100,12 @@
  */
 /* Predefs for callbacks handed to qla2xxx LLD */
 static void qlt_24xx_atio_pkt(struct scsi_qla_host *ha,
-	struct atio_from_isp *pkt);
+	struct atio_from_isp *pkt, uint8_t);
 static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt);
 static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
 	int fn, void *iocb, int flags);
 static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd
-	*cmd, struct atio_from_isp *atio, int ha_locked);
+	*cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort);
 static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
 	struct qla_tgt_srr_imm *imm, int ha_lock);
 static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
@@ -118,10 +118,13 @@
 	struct imm_ntfy_from_isp *ntfy,
 	uint32_t add_flags, uint16_t resp_code, int resp_code_valid,
 	uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan);
+static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+	struct imm_ntfy_from_isp *imm, int ha_locked);
 /*
  * Global Variables
  */
 static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
+static struct kmem_cache *qla_tgt_plogi_cachep;
 static mempool_t *qla_tgt_mgmt_cmd_mempool;
 static struct workqueue_struct *qla_tgt_wq;
 static DEFINE_MUTEX(qla_tgt_mutex);
@@ -226,8 +229,8 @@
 	spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags);
 }
 
-static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
-	struct atio_from_isp *atio)
+static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
+	struct atio_from_isp *atio, uint8_t ha_locked)
 {
 	ql_dbg(ql_dbg_tgt, vha, 0xe072,
 		"%s: qla_target(%d): type %x ox_id %04x\n",
@@ -248,7 +251,7 @@
 			    atio->u.isp24.fcp_hdr.d_id[2]);
 			break;
 		}
-		qlt_24xx_atio_pkt(host, atio);
+		qlt_24xx_atio_pkt(host, atio, ha_locked);
 		break;
 	}
 
@@ -271,7 +274,7 @@
 				break;
 			}
 		}
-		qlt_24xx_atio_pkt(host, atio);
+		qlt_24xx_atio_pkt(host, atio, ha_locked);
 		break;
 	}
 
@@ -282,7 +285,7 @@
 		break;
 	}
 
-	return;
+	return false;
 }
 
 void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
@@ -389,6 +392,131 @@
 
 }
 
+/*
+ * All qlt_plogi_ack_t operations are protected by hardware_lock
+ */
+
+/*
+ * This is a zero-base ref-counting solution, since hardware_lock
+ * guarantees that ref_count is not modified concurrently.
+ * Upon successful return content of iocb is undefined
+ */
+static qlt_plogi_ack_t *
+qlt_plogi_ack_find_add(struct scsi_qla_host *vha, port_id_t *id,
+		       struct imm_ntfy_from_isp *iocb)
+{
+	qlt_plogi_ack_t *pla;
+
+	list_for_each_entry(pla, &vha->plogi_ack_list, list) {
+		if (pla->id.b24 == id->b24) {
+			qlt_send_term_imm_notif(vha, &pla->iocb, 1);
+			pla->iocb = *iocb;
+			return pla;
+		}
+	}
+
+	pla = kmem_cache_zalloc(qla_tgt_plogi_cachep, GFP_ATOMIC);
+	if (!pla) {
+		ql_dbg(ql_dbg_async, vha, 0x5088,
+		       "qla_target(%d): Allocation of plogi_ack failed\n",
+		       vha->vp_idx);
+		return NULL;
+	}
+
+	pla->iocb = *iocb;
+	pla->id = *id;
+	list_add_tail(&pla->list, &vha->plogi_ack_list);
+
+	return pla;
+}
+
+static void qlt_plogi_ack_unref(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla)
+{
+	BUG_ON(!pla->ref_count);
+	pla->ref_count--;
+
+	if (pla->ref_count)
+		return;
+
+	ql_dbg(ql_dbg_async, vha, 0x5089,
+	    "Sending PLOGI ACK to wwn %8phC s_id %02x:%02x:%02x loop_id %#04x"
+	    " exch %#x ox_id %#x\n", pla->iocb.u.isp24.port_name,
+	    pla->iocb.u.isp24.port_id[2], pla->iocb.u.isp24.port_id[1],
+	    pla->iocb.u.isp24.port_id[0],
+	    le16_to_cpu(pla->iocb.u.isp24.nport_handle),
+	    pla->iocb.u.isp24.exchange_address, pla->iocb.ox_id);
+	qlt_send_notify_ack(vha, &pla->iocb, 0, 0, 0, 0, 0, 0);
+
+	list_del(&pla->list);
+	kmem_cache_free(qla_tgt_plogi_cachep, pla);
+}
+
+static void
+qlt_plogi_ack_link(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla,
+    struct qla_tgt_sess *sess, qlt_plogi_link_t link)
+{
+	/* Inc ref_count first because link might already be pointing at pla */
+	pla->ref_count++;
+
+	if (sess->plogi_link[link])
+		qlt_plogi_ack_unref(vha, sess->plogi_link[link]);
+
+	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf097,
+	    "Linking sess %p [%d] wwn %8phC with PLOGI ACK to wwn %8phC"
+	    " s_id %02x:%02x:%02x, ref=%d\n", sess, link, sess->port_name,
+	    pla->iocb.u.isp24.port_name, pla->iocb.u.isp24.port_id[2],
+	    pla->iocb.u.isp24.port_id[1], pla->iocb.u.isp24.port_id[0],
+	    pla->ref_count);
+
+	sess->plogi_link[link] = pla;
+}
+
+typedef struct {
+	/* These fields must be initialized by the caller */
+	port_id_t id;
+	/*
+	 * number of cmds dropped while we were waiting for
+	 * initiator to ack LOGO initialize to 1 if LOGO is
+	 * triggered by a command, otherwise, to 0
+	 */
+	int cmd_count;
+
+	/* These fields are used by callee */
+	struct list_head list;
+} qlt_port_logo_t;
+
+static void
+qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
+{
+	qlt_port_logo_t *tmp;
+	int res;
+
+	mutex_lock(&vha->vha_tgt.tgt_mutex);
+
+	list_for_each_entry(tmp, &vha->logo_list, list) {
+		if (tmp->id.b24 == logo->id.b24) {
+			tmp->cmd_count += logo->cmd_count;
+			mutex_unlock(&vha->vha_tgt.tgt_mutex);
+			return;
+		}
+	}
+
+	list_add_tail(&logo->list, &vha->logo_list);
+
+	mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+	res = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, logo->id);
+
+	mutex_lock(&vha->vha_tgt.tgt_mutex);
+	list_del(&logo->list);
+	mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf098,
+	    "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n",
+	    logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
+	    logo->cmd_count, res);
+}
+
 static void qlt_free_session_done(struct work_struct *work)
 {
 	struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess,
@@ -402,14 +530,21 @@
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
 		"%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
-		" s_id %02x:%02x:%02x logout %d keep %d plogi %d\n",
+		" s_id %02x:%02x:%02x logout %d keep %d els_logo %d\n",
 		__func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
 		sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
 		sess->logout_on_delete, sess->keep_nport_handle,
-		sess->plogi_ack_needed);
+		sess->send_els_logo);
 
 	BUG_ON(!tgt);
 
+	if (sess->send_els_logo) {
+		qlt_port_logo_t logo;
+		logo.id = sess->s_id;
+		logo.cmd_count = 0;
+		qlt_send_first_logo(vha, &logo);
+	}
+
 	if (sess->logout_on_delete) {
 		int rc;
 
@@ -437,6 +572,7 @@
 
 	if (logout_started) {
 		bool traced = false;
+		u16 cnt = 0;
 
 		while (!ACCESS_ONCE(sess->logout_completed)) {
 			if (!traced) {
@@ -446,6 +582,9 @@
 				traced = true;
 			}
 			msleep(100);
+			cnt++;
+			if (cnt > 200)
+				break;
 		}
 
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf087,
@@ -455,9 +594,34 @@
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
-	if (sess->plogi_ack_needed)
-		qlt_send_notify_ack(vha, &sess->tm_iocb,
-				    0, 0, 0, 0, 0, 0);
+	{
+		qlt_plogi_ack_t *own =
+		    sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
+		qlt_plogi_ack_t *con =
+		    sess->plogi_link[QLT_PLOGI_LINK_CONFLICT];
+
+		if (con) {
+			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf099,
+			    "se_sess %p / sess %p port %8phC is gone,"
+			    " %s (ref=%d), releasing PLOGI for %8phC (ref=%d)\n",
+			    sess->se_sess, sess, sess->port_name,
+			    own ? "releasing own PLOGI" :
+			    "no own PLOGI pending",
+			    own ? own->ref_count : -1,
+			    con->iocb.u.isp24.port_name, con->ref_count);
+			qlt_plogi_ack_unref(vha, con);
+		} else {
+			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09a,
+			    "se_sess %p / sess %p port %8phC is gone, %s (ref=%d)\n",
+			    sess->se_sess, sess, sess->port_name,
+			    own ? "releasing own PLOGI" :
+			    "no own PLOGI pending",
+			    own ? own->ref_count : -1);
+		}
+
+		if (own)
+			qlt_plogi_ack_unref(vha, own);
+	}
 
 	list_del(&sess->sess_list_entry);
 
@@ -476,7 +640,7 @@
 		wake_up_all(&tgt->waitQ);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 void qlt_unreg_sess(struct qla_tgt_sess *sess)
 {
 	struct scsi_qla_host *vha = sess->vha;
@@ -492,7 +656,7 @@
 }
 EXPORT_SYMBOL(qlt_unreg_sess);
 
-/* ha->hardware_lock supposed to be held on entry */
+
 static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
 {
 	struct qla_hw_data *ha = vha->hw;
@@ -502,12 +666,15 @@
 	int res = 0;
 	struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb;
 	struct atio_from_isp *a = (struct atio_from_isp *)iocb;
+	unsigned long flags;
 
 	loop_id = le16_to_cpu(n->u.isp24.nport_handle);
 	if (loop_id == 0xFFFF) {
 		/* Global event */
 		atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 		qlt_clear_tgt_db(vha->vha_tgt.qla_tgt);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 #if 0 /* FIXME: do we need to choose a session here? */
 		if (!list_empty(&ha->tgt.qla_tgt->sess_list)) {
 			sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
@@ -534,7 +701,9 @@
 			sess = NULL;
 #endif
 	} else {
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 		sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	}
 
 	ql_dbg(ql_dbg_tgt, vha, 0xe000,
@@ -556,7 +725,7 @@
 	    iocb, QLA24XX_MGMT_SEND_NACK);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
 	bool immediate)
 {
@@ -600,7 +769,7 @@
 		    sess->expires - jiffies);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_clear_tgt_db(struct qla_tgt *tgt)
 {
 	struct qla_tgt_sess *sess;
@@ -636,12 +805,12 @@
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045,
 		    "qla_target(%d): get_id_list() failed: %x\n",
 		    vha->vp_idx, rc);
-		res = -1;
+		res = -EBUSY;
 		goto out_free_id_list;
 	}
 
 	id_iter = (char *)gid_list;
-	res = -1;
+	res = -ENOENT;
 	for (i = 0; i < entries; i++) {
 		struct gid_list_info *gid = (struct gid_list_info *)id_iter;
 		if ((gid->al_pa == s_id[2]) &&
@@ -660,7 +829,7 @@
 	return res;
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_undelete_sess(struct qla_tgt_sess *sess)
 {
 	BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING);
@@ -678,7 +847,7 @@
 	struct qla_tgt_sess *sess;
 	unsigned long flags, elapsed;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	while (!list_empty(&tgt->del_sess_list)) {
 		sess = list_entry(tgt->del_sess_list.next, typeof(*sess),
 		    del_list_entry);
@@ -699,7 +868,7 @@
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 /*
@@ -717,7 +886,7 @@
 	unsigned char be_sid[3];
 
 	/* Check to avoid double sessions */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	list_for_each_entry(sess, &vha->vha_tgt.qla_tgt->sess_list,
 				sess_list_entry) {
 		if (!memcmp(sess->port_name, fcport->port_name, WWN_SIZE)) {
@@ -732,7 +901,7 @@
 
 			/* Cannot undelete at this point */
 			if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
-				spin_unlock_irqrestore(&ha->hardware_lock,
+				spin_unlock_irqrestore(&ha->tgt.sess_lock,
 				    flags);
 				return NULL;
 			}
@@ -749,12 +918,12 @@
 
 			qlt_do_generation_tick(vha, &sess->generation);
 
-			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+			spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 			return sess;
 		}
 	}
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 	sess = kzalloc(sizeof(*sess), GFP_KERNEL);
 	if (!sess) {
@@ -799,7 +968,7 @@
 	}
 	/*
 	 * Take an extra reference to ->sess_kref here to handle qla_tgt_sess
-	 * access across ->hardware_lock reaquire.
+	 * access across ->tgt.sess_lock reaquire.
 	 */
 	kref_get(&sess->se_sess->sess_kref);
 
@@ -807,11 +976,11 @@
 	BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name));
 	memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name));
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list);
 	vha->vha_tgt.qla_tgt->sess_count++;
 	qlt_do_generation_tick(vha, &sess->generation);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
 	    "qla_target(%d): %ssession for wwn %8phC (loop_id %d, "
@@ -842,23 +1011,23 @@
 	if (qla_ini_mode_enabled(vha))
 		return;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	if (tgt->tgt_stop) {
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 		return;
 	}
 	sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
 	if (!sess) {
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 		mutex_lock(&vha->vha_tgt.tgt_mutex);
 		sess = qlt_create_sess(vha, fcport, false);
 		mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	} else if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
 		/* Point of no return */
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 		return;
 	} else {
 		kref_get(&sess->se_sess->sess_kref);
@@ -887,7 +1056,7 @@
 		sess->local = 0;
 	}
 	ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 /*
@@ -899,6 +1068,7 @@
 {
 	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 	struct qla_tgt_sess *sess;
+	unsigned long flags;
 
 	if (!vha->hw->tgt.tgt_ops)
 		return;
@@ -906,15 +1076,19 @@
 	if (!tgt)
 		return;
 
+	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
 	if (tgt->tgt_stop) {
+		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 		return;
 	}
 	sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
 	if (!sess) {
+		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 		return;
 	}
 
 	if (max_gen - sess->generation < 0) {
+		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092,
 		    "Ignoring stale deletion request for se_sess %p / sess %p"
 		    " for port %8phC, req_gen %d, sess_gen %d\n",
@@ -927,6 +1101,7 @@
 
 	sess->local = 1;
 	qlt_schedule_sess_for_deletion(sess, false);
+	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 }
 
 static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -984,10 +1159,10 @@
 	 * Lock is needed, because we still can get an incoming packet.
 	 */
 	mutex_lock(&vha->vha_tgt.tgt_mutex);
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	tgt->tgt_stop = 1;
 	qlt_clear_tgt_db(tgt);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	mutex_unlock(&vha->vha_tgt.tgt_mutex);
 	mutex_unlock(&qla_tgt_mutex);
 
@@ -1040,7 +1215,7 @@
 
 	mutex_lock(&vha->vha_tgt.tgt_mutex);
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	while (tgt->irq_cmd_count != 0) {
+	while ((tgt->irq_cmd_count != 0) || (tgt->atio_irq_cmd_count != 0)) {
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		udelay(2);
 		spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1309,7 +1484,7 @@
 
 	list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
 		if (tag == cmd->atio.u.isp24.exchange_addr) {
-			cmd->state = QLA_TGT_STATE_ABORTED;
+			cmd->aborted = 1;
 			spin_unlock(&vha->cmd_list_lock);
 			return 1;
 		}
@@ -1351,7 +1526,7 @@
 		cmd_lun = scsilun_to_int(
 			(struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun);
 		if (cmd_key == key && cmd_lun == lun)
-			cmd->state = QLA_TGT_STATE_ABORTED;
+			cmd->aborted = 1;
 	}
 	spin_unlock(&vha->cmd_list_lock);
 }
@@ -1435,6 +1610,7 @@
 	uint32_t tag = abts->exchange_addr_to_abort;
 	uint8_t s_id[3];
 	int rc;
+	unsigned long flags;
 
 	if (le32_to_cpu(abts->fcp_hdr_le.parameter) & ABTS_PARAM_ABORT_SEQ) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf053,
@@ -1462,6 +1638,7 @@
 	s_id[1] = abts->fcp_hdr_le.s_id[1];
 	s_id[2] = abts->fcp_hdr_le.s_id[0];
 
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
 	if (!sess) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012,
@@ -1469,12 +1646,17 @@
 		    vha->vp_idx);
 		rc = qlt_sched_sess_work(vha->vha_tgt.qla_tgt,
 		    QLA_TGT_SESS_WORK_ABORT, abts, sizeof(*abts));
+
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
 		if (rc != 0) {
 			qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED,
 			    false);
 		}
 		return;
 	}
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
 
 	if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
 		qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false);
@@ -1560,15 +1742,15 @@
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
-	if (qla2x00_reset_active(vha) || mcmd->reset_count != ha->chip_reset) {
+	if (!vha->flags.online || mcmd->reset_count != ha->chip_reset) {
 		/*
-		 * Either a chip reset is active or this request was from
+		 * Either the port is not online or this request was from
 		 * previous life, just abort the processing.
 		 */
 		ql_dbg(ql_dbg_async, vha, 0xe100,
-			"RESET-TMR active/old-count/new-count = %d/%d/%d.\n",
-			qla2x00_reset_active(vha), mcmd->reset_count,
-			ha->chip_reset);
+			"RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+			vha->flags.online, qla2x00_reset_active(vha),
+			mcmd->reset_count, ha->chip_reset);
 		ha->tgt.tgt_ops->free_mcmd(mcmd);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		return;
@@ -1578,7 +1760,7 @@
 		qlt_send_notify_ack(vha, &mcmd->orig_iocb.imm_ntfy,
 		    0, 0, 0, 0, 0, 0);
 	else {
-		if (mcmd->se_cmd.se_tmr_req->function == TMR_ABORT_TASK)
+		if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX)
 			qlt_24xx_send_abts_resp(vha, &mcmd->orig_iocb.abts,
 			    mcmd->fc_tm_rsp, false);
 		else
@@ -2487,7 +2669,7 @@
 			/* no need to terminate. FW already freed exchange. */
 			qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
 		else
-			qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+			qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		return 0;
 	}
@@ -2510,17 +2692,22 @@
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
-	if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
+	if (xmit_type == QLA_TGT_XMIT_STATUS)
+		vha->tgt_counters.core_qla_snd_status++;
+	else
+		vha->tgt_counters.core_qla_que_buf++;
+
+	if (!vha->flags.online || cmd->reset_count != ha->chip_reset) {
 		/*
-		 * Either a chip reset is active or this request was from
+		 * Either the port is not online or this request was from
 		 * previous life, just abort the processing.
 		 */
 		cmd->state = QLA_TGT_STATE_PROCESSED;
 		qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
 		ql_dbg(ql_dbg_async, vha, 0xe101,
-			"RESET-RSP active/old-count/new-count = %d/%d/%d.\n",
-			qla2x00_reset_active(vha), cmd->reset_count,
-			ha->chip_reset);
+			"RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
+			vha->flags.online, qla2x00_reset_active(vha),
+			cmd->reset_count, ha->chip_reset);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		return 0;
 	}
@@ -2651,18 +2838,18 @@
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
-	if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) ||
+	if (!vha->flags.online || (cmd->reset_count != ha->chip_reset) ||
 	    (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) {
 		/*
-		 * Either a chip reset is active or this request was from
+		 * Either the port is not online or this request was from
 		 * previous life, just abort the processing.
 		 */
 		cmd->state = QLA_TGT_STATE_NEED_DATA;
 		qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
 		ql_dbg(ql_dbg_async, vha, 0xe102,
-			"RESET-XFR active/old-count/new-count = %d/%d/%d.\n",
-			qla2x00_reset_active(vha), cmd->reset_count,
-			ha->chip_reset);
+			"RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+			vha->flags.online, qla2x00_reset_active(vha),
+			cmd->reset_count, ha->chip_reset);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		return 0;
 	}
@@ -2865,7 +3052,7 @@
 
 	pkt->entry_type = NOTIFY_ACK_TYPE;
 	pkt->entry_count = 1;
-	pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
+	pkt->handle = QLA_TGT_SKIP_HANDLE;
 
 	nack = (struct nack_to_isp *)pkt;
 	nack->ox_id = ntfy->ox_id;
@@ -2957,12 +3144,13 @@
 			ret = 1;
 	}
 
+	vha->tgt_counters.num_term_xchg_sent++;
 	pkt->entry_count = 1;
 	pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
 
 	ctio24 = (struct ctio7_to_24xx *)pkt;
 	ctio24->entry_type = CTIO_TYPE7;
-	ctio24->nport_handle = cmd ? cmd->loop_id : CTIO7_NHANDLE_UNRECOGNIZED;
+	ctio24->nport_handle = CTIO7_NHANDLE_UNRECOGNIZED;
 	ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
 	ctio24->vp_index = vha->vp_idx;
 	ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
@@ -2989,7 +3177,8 @@
 }
 
 static void qlt_send_term_exchange(struct scsi_qla_host *vha,
-	struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
+	struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked,
+	int ul_abort)
 {
 	unsigned long flags = 0;
 	int rc;
@@ -3009,8 +3198,7 @@
 		qlt_alloc_qfull_cmd(vha, atio, 0, 0);
 
 done:
-	if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) ||
-	    !cmd->cmd_sent_to_fw)) {
+	if (cmd && !ul_abort && !cmd->aborted) {
 		if (cmd->sg_mapped)
 			qlt_unmap_sg(vha, cmd);
 		vha->hw->tgt.tgt_ops->free_cmd(cmd);
@@ -3028,7 +3216,7 @@
 	struct qla_tgt_cmd *cmd, *tcmd;
 
 	vha->hw->tgt.leak_exchg_thresh_hold =
-	    (vha->hw->fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
+	    (vha->hw->cur_fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
 
 	cmd = tcmd = NULL;
 	if (!list_empty(&vha->hw->tgt.q_full_list)) {
@@ -3058,7 +3246,7 @@
 
 		ql_dbg(ql_dbg_tgt, vha, 0xe079,
 		    "Chip reset due to exchange starvation: %d/%d.\n",
-		    total_leaked, vha->hw->fw_xcb_count);
+		    total_leaked, vha->hw->cur_fw_xcb_count);
 
 		if (IS_P3P_TYPE(vha->hw))
 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -3069,21 +3257,38 @@
 
 }
 
-void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
+int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
 {
 	struct qla_tgt *tgt = cmd->tgt;
 	struct scsi_qla_host *vha = tgt->vha;
 	struct se_cmd *se_cmd = &cmd->se_cmd;
+	unsigned long flags;
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
 	    "qla_target(%d): terminating exchange for aborted cmd=%p "
 	    "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
 	    se_cmd->tag);
 
-	cmd->state = QLA_TGT_STATE_ABORTED;
+	spin_lock_irqsave(&cmd->cmd_lock, flags);
+	if (cmd->aborted) {
+		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+		/*
+		 * It's normal to see 2 calls in this path:
+		 *  1) XFER Rdy completion + CMD_T_ABORT
+		 *  2) TCM TMR - drain_state_list
+		 */
+	        ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
+			"multiple abort. %p transport_state %x, t_state %x,"
+			" se_cmd_flags %x \n", cmd, cmd->se_cmd.transport_state,
+			cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
+		return EIO;
+	}
+	cmd->aborted = 1;
 	cmd->cmd_flags |= BIT_6;
+	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
 
-	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
+	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1);
+	return 0;
 }
 EXPORT_SYMBOL(qlt_abort_cmd);
 
@@ -3098,6 +3303,9 @@
 
 	BUG_ON(cmd->cmd_in_wq);
 
+	if (cmd->sg_mapped)
+		qlt_unmap_sg(cmd->vha, cmd);
+
 	if (!cmd->q_full)
 		qlt_decr_num_pend_cmds(cmd->vha);
 
@@ -3215,7 +3423,7 @@
 		term = 1;
 
 	if (term)
-		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
 
 	return term;
 }
@@ -3300,9 +3508,6 @@
 
 		ha->tgt.tgt_ops->handle_data(cmd);
 		return;
-	} else if (cmd->state == QLA_TGT_STATE_ABORTED) {
-		ql_dbg(ql_dbg_io, vha, 0xff02,
-		    "HOST-ABORT: handle=%d, state=ABORTED.\n", handle);
 	} else {
 		ql_dbg(ql_dbg_io, vha, 0xff03,
 		    "HOST-ABORT: handle=%d, state=BAD(%d).\n", handle,
@@ -3398,13 +3603,27 @@
 
 		case CTIO_PORT_LOGGED_OUT:
 		case CTIO_PORT_UNAVAILABLE:
+		{
+			int logged_out =
+				(status & 0xFFFF) == CTIO_PORT_LOGGED_OUT;
+
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
-			    "qla_target(%d): CTIO with PORT LOGGED "
-			    "OUT (29) or PORT UNAVAILABLE (28) status %x "
+			    "qla_target(%d): CTIO with %s status %x "
 			    "received (state %x, se_cmd %p)\n", vha->vp_idx,
+			    logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE",
 			    status, cmd->state, se_cmd);
-			break;
 
+			if (logged_out && cmd->sess) {
+				/*
+				 * Session is already logged out, but we need
+				 * to notify initiator, who's not aware of this
+				 */
+				cmd->sess->logout_on_delete = 0;
+				cmd->sess->send_els_logo = 1;
+				qlt_schedule_sess_for_deletion(cmd->sess, true);
+			}
+			break;
+		}
 		case CTIO_SRR_RECEIVED:
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05a,
 			    "qla_target(%d): CTIO with SRR_RECEIVED"
@@ -3454,14 +3673,14 @@
 		}
 
 
-		/* "cmd->state == QLA_TGT_STATE_ABORTED" means
+		/* "cmd->aborted" means
 		 * cmd is already aborted/terminated, we don't
 		 * need to terminate again.  The exchange is already
 		 * cleaned up/freed at FW level.  Just cleanup at driver
 		 * level.
 		 */
 		if ((cmd->state != QLA_TGT_STATE_NEED_DATA) &&
-		    (cmd->state != QLA_TGT_STATE_ABORTED)) {
+		    (!cmd->aborted)) {
 			cmd->cmd_flags |= BIT_13;
 			if (qlt_term_ctio_exchange(vha, ctio, cmd, status))
 				return;
@@ -3479,7 +3698,7 @@
 
 		ha->tgt.tgt_ops->handle_data(cmd);
 		return;
-	} else if (cmd->state == QLA_TGT_STATE_ABORTED) {
+	} else if (cmd->aborted) {
 		cmd->cmd_flags |= BIT_18;
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e,
 		  "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag);
@@ -3491,7 +3710,7 @@
 	}
 
 	if (unlikely(status != CTIO_SUCCESS) &&
-		(cmd->state != QLA_TGT_STATE_ABORTED)) {
+		!cmd->aborted) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01f, "Finishing failed CTIO\n");
 		dump_stack();
 	}
@@ -3553,13 +3772,14 @@
 	if (tgt->tgt_stop)
 		goto out_term;
 
-	if (cmd->state == QLA_TGT_STATE_ABORTED) {
+	if (cmd->aborted) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
 		    "cmd with tag %u is aborted\n",
 		    cmd->atio.u.isp24.exchange_addr);
 		goto out_term;
 	}
 
+	spin_lock_init(&cmd->cmd_lock);
 	cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
 	cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
 	cmd->unpacked_lun = scsilun_to_int(
@@ -3589,9 +3809,9 @@
 	/*
 	 * Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
 	 */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	return;
 
 out_term:
@@ -3602,12 +3822,15 @@
 	 */
 	cmd->cmd_flags |= BIT_2;
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
+	qlt_send_term_exchange(vha, NULL, &cmd->atio, 1, 0);
 
 	qlt_decr_num_pend_cmds(vha);
 	percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
-	ha->tgt.tgt_ops->put_sess(sess);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+	ha->tgt.tgt_ops->put_sess(sess);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 static void qlt_do_work(struct work_struct *work)
@@ -3692,10 +3915,8 @@
 		goto out_term;
 	}
 
-	mutex_lock(&vha->vha_tgt.tgt_mutex);
 	sess = qlt_make_local_sess(vha, s_id);
 	/* sess has an extra creation ref. */
-	mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
 	if (!sess)
 		goto out_term;
@@ -3723,7 +3944,7 @@
 
 out_term:
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	qlt_send_term_exchange(vha, NULL, &op->atio, 1);
+	qlt_send_term_exchange(vha, NULL, &op->atio, 1, 0);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	kfree(op);
 
@@ -3787,13 +4008,24 @@
 
 	cmd->cmd_in_wq = 1;
 	cmd->cmd_flags |= BIT_0;
+	cmd->se_cmd.cpuid = ha->msix_count ?
+		ha->tgt.rspq_vector_cpuid : WORK_CPU_UNBOUND;
 
 	spin_lock(&vha->cmd_list_lock);
 	list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
 	spin_unlock(&vha->cmd_list_lock);
 
 	INIT_WORK(&cmd->work, qlt_do_work);
-	queue_work(qla_tgt_wq, &cmd->work);
+	if (ha->msix_count) {
+		if (cmd->atio.u.isp24.fcp_cmnd.rddata)
+			queue_work_on(smp_processor_id(), qla_tgt_wq,
+			    &cmd->work);
+		else
+			queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq,
+			    &cmd->work);
+	} else {
+		queue_work(qla_tgt_wq, &cmd->work);
+	}
 	return 0;
 
 }
@@ -3917,13 +4149,18 @@
 	struct qla_tgt_sess *sess;
 	uint32_t lun, unpacked_lun;
 	int fn;
+	unsigned long flags;
 
 	tgt = vha->vha_tgt.qla_tgt;
 
 	lun = a->u.isp24.fcp_cmnd.lun;
 	fn = a->u.isp24.fcp_cmnd.task_mgmt_flags;
+
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
 	    a->u.isp24.fcp_hdr.s_id);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
 	unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
 
 	if (!sess) {
@@ -3987,10 +4224,14 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct qla_tgt_sess *sess;
 	int loop_id;
+	unsigned long flags;
 
 	loop_id = GET_TARGET_ID(ha, (struct atio_from_isp *)iocb);
 
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
 	if (sess == NULL) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf025,
 		    "qla_target(%d): task abort for unexisting "
@@ -4022,15 +4263,6 @@
 	}
 }
 
-static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
-    struct imm_ntfy_from_isp *b)
-{
-	struct imm_ntfy_from_isp tmp;
-	memcpy(&tmp, a, sizeof(struct imm_ntfy_from_isp));
-	memcpy(a, b, sizeof(struct imm_ntfy_from_isp));
-	memcpy(b, &tmp, sizeof(struct imm_ntfy_from_isp));
-}
-
 /*
 * ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list)
 *
@@ -4040,11 +4272,13 @@
 */
 static struct qla_tgt_sess *
 qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
-    port_id_t port_id, uint16_t loop_id)
+    port_id_t port_id, uint16_t loop_id, struct qla_tgt_sess **conflict_sess)
 {
 	struct qla_tgt_sess *sess = NULL, *other_sess;
 	uint64_t other_wwn;
 
+	*conflict_sess = NULL;
+
 	list_for_each_entry(other_sess, &tgt->sess_list, sess_list_entry) {
 
 		other_wwn = wwn_to_u64(other_sess->port_name);
@@ -4072,9 +4306,10 @@
 			} else {
 				/*
 				 * Another wwn used to have our s_id/loop_id
-				 * combo - kill the session, but don't log out
+				 * kill the session, but don't free the loop_id
 				 */
-				sess->logout_on_delete = 0;
+				other_sess->keep_nport_handle = 1;
+				*conflict_sess = other_sess;
 				qlt_schedule_sess_for_deletion(other_sess,
 				    true);
 			}
@@ -4119,7 +4354,7 @@
 	list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
 		uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
 		if (cmd_key == key) {
-			cmd->state = QLA_TGT_STATE_ABORTED;
+			cmd->aborted = 1;
 			count++;
 		}
 	}
@@ -4136,12 +4371,14 @@
 {
 	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 	struct qla_hw_data *ha = vha->hw;
-	struct qla_tgt_sess *sess = NULL;
+	struct qla_tgt_sess *sess = NULL, *conflict_sess = NULL;
 	uint64_t wwn;
 	port_id_t port_id;
 	uint16_t loop_id;
 	uint16_t wd3_lo;
 	int res = 0;
+	qlt_plogi_ack_t *pla;
+	unsigned long flags;
 
 	wwn = wwn_to_u64(iocb->u.isp24.port_name);
 
@@ -4165,27 +4402,20 @@
 		/* Mark all stale commands in qla_tgt_wq for deletion */
 		abort_cmds_for_s_id(vha, &port_id);
 
-		if (wwn)
+		if (wwn) {
+			spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
 			sess = qlt_find_sess_invalidate_other(tgt, wwn,
-			    port_id, loop_id);
+			    port_id, loop_id, &conflict_sess);
+			spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+		}
 
-		if (!sess || IS_SW_RESV_ADDR(sess->s_id)) {
+		if (IS_SW_RESV_ADDR(port_id) || (!sess && !conflict_sess)) {
 			res = 1;
 			break;
 		}
 
-		if (sess->plogi_ack_needed) {
-			/*
-			 * Initiator sent another PLOGI before last PLOGI could
-			 * finish. Swap plogi iocbs and terminate old one
-			 * without acking, new one will get acked when session
-			 * deletion completes.
-			 */
-			ql_log(ql_log_warn, sess->vha, 0xf094,
-			    "sess %p received double plogi.\n", sess);
-
-			qlt_swap_imm_ntfy_iocb(iocb, &sess->tm_iocb);
-
+		pla = qlt_plogi_ack_find_add(vha, &port_id, iocb);
+		if (!pla) {
 			qlt_send_term_imm_notif(vha, iocb, 1);
 
 			res = 0;
@@ -4194,13 +4424,14 @@
 
 		res = 0;
 
-		/*
-		 * Save immediate Notif IOCB for Ack when sess is done
-		 * and being deleted.
-		 */
-		memcpy(&sess->tm_iocb, iocb, sizeof(sess->tm_iocb));
-		sess->plogi_ack_needed  = 1;
+		if (conflict_sess)
+			qlt_plogi_ack_link(vha, pla, conflict_sess,
+			    QLT_PLOGI_LINK_CONFLICT);
+
+		if (!sess)
+			break;
 
+		qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN);
 		 /*
 		  * Under normal circumstances we want to release nport handle
 		  * during LOGO process to avoid nport handle leaks inside FW.
@@ -4227,9 +4458,21 @@
 	case ELS_PRLI:
 		wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo);
 
-		if (wwn)
+		if (wwn) {
+			spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
 			sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id,
-			    loop_id);
+			    loop_id, &conflict_sess);
+			spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+		}
+
+		if (conflict_sess) {
+			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09b,
+			    "PRLI with conflicting sess %p port %8phC\n",
+			    conflict_sess, conflict_sess->port_name);
+			qlt_send_term_imm_notif(vha, iocb, 1);
+			res = 0;
+			break;
+		}
 
 		if (sess != NULL) {
 			if (sess->deleted) {
@@ -4554,7 +4797,7 @@
 		dump_stack();
 	} else {
 		cmd->cmd_flags |= BIT_9;
-		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
@@ -4733,7 +4976,7 @@
 				    sctio, sctio->srr_id);
 				list_del(&sctio->srr_list_entry);
 				qlt_send_term_exchange(vha, sctio->cmd,
-				    &sctio->cmd->atio, 1);
+				    &sctio->cmd->atio, 1, 0);
 				kfree(sctio);
 			}
 		}
@@ -4899,11 +5142,14 @@
 	struct qla_hw_data *ha = vha->hw;
 	request_t *pkt;
 	struct qla_tgt_sess *sess = NULL;
+	unsigned long flags;
 
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
 	    atio->u.isp24.fcp_hdr.s_id);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	if (!sess) {
-		qlt_send_term_exchange(vha, NULL, atio, 1);
+		qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 		return 0;
 	}
 	/* Sending marker isn't necessary, since we called from ISR */
@@ -4916,6 +5162,7 @@
 		return -ENOMEM;
 	}
 
+	vha->tgt_counters.num_q_full_sent++;
 	pkt->entry_count = 1;
 	pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
 
@@ -5129,11 +5376,12 @@
 /* ha->hardware_lock supposed to be held on entry */
 /* called via callback from qla2xxx */
 static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
-	struct atio_from_isp *atio)
+	struct atio_from_isp *atio, uint8_t ha_locked)
 {
 	struct qla_hw_data *ha = vha->hw;
 	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 	int rc;
+	unsigned long flags;
 
 	if (unlikely(tgt == NULL)) {
 		ql_dbg(ql_dbg_io, vha, 0x3064,
@@ -5145,7 +5393,7 @@
 	 * Otherwise, some commands can stuck.
 	 */
 
-	tgt->irq_cmd_count++;
+	tgt->atio_irq_cmd_count++;
 
 	switch (atio->u.raw.entry_type) {
 	case ATIO_TYPE7:
@@ -5155,7 +5403,11 @@
 			    "qla_target(%d): ATIO_TYPE7 "
 			    "received with UNKNOWN exchange address, "
 			    "sending QUEUE_FULL\n", vha->vp_idx);
+			if (!ha_locked)
+				spin_lock_irqsave(&ha->hardware_lock, flags);
 			qlt_send_busy(vha, atio, SAM_STAT_TASK_SET_FULL);
+			if (!ha_locked)
+				spin_unlock_irqrestore(&ha->hardware_lock, flags);
 			break;
 		}
 
@@ -5164,7 +5416,7 @@
 		if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) {
 			rc = qlt_chk_qfull_thresh_hold(vha, atio);
 			if (rc != 0) {
-				tgt->irq_cmd_count--;
+				tgt->atio_irq_cmd_count--;
 				return;
 			}
 			rc = qlt_handle_cmd_for_atio(vha, atio);
@@ -5173,11 +5425,20 @@
 		}
 		if (unlikely(rc != 0)) {
 			if (rc == -ESRCH) {
+				if (!ha_locked)
+					spin_lock_irqsave
+						(&ha->hardware_lock, flags);
+
 #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
 				qlt_send_busy(vha, atio, SAM_STAT_BUSY);
 #else
-				qlt_send_term_exchange(vha, NULL, atio, 1);
+				qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 #endif
+
+				if (!ha_locked)
+					spin_unlock_irqrestore
+						(&ha->hardware_lock, flags);
+
 			} else {
 				if (tgt->tgt_stop) {
 					ql_dbg(ql_dbg_tgt, vha, 0xe059,
@@ -5189,7 +5450,13 @@
 					    "qla_target(%d): Unable to send "
 					    "command to target, sending BUSY "
 					    "status.\n", vha->vp_idx);
+					if (!ha_locked)
+						spin_lock_irqsave(
+						    &ha->hardware_lock, flags);
 					qlt_send_busy(vha, atio, SAM_STAT_BUSY);
+					if (!ha_locked)
+						spin_unlock_irqrestore(
+						    &ha->hardware_lock, flags);
 				}
 			}
 		}
@@ -5206,7 +5473,12 @@
 			break;
 		}
 		ql_dbg(ql_dbg_tgt, vha, 0xe02e, "%s", "IMMED_NOTIFY ATIO");
+
+		if (!ha_locked)
+			spin_lock_irqsave(&ha->hardware_lock, flags);
 		qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)atio);
+		if (!ha_locked)
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		break;
 	}
 
@@ -5217,7 +5489,7 @@
 		break;
 	}
 
-	tgt->irq_cmd_count--;
+	tgt->atio_irq_cmd_count--;
 }
 
 /* ha->hardware_lock supposed to be held on entry */
@@ -5277,7 +5549,7 @@
 #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
 				qlt_send_busy(vha, atio, 0);
 #else
-				qlt_send_term_exchange(vha, NULL, atio, 1);
+				qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 #endif
 			} else {
 				if (tgt->tgt_stop) {
@@ -5286,7 +5558,7 @@
 					    "command to target, sending TERM "
 					    "EXCHANGE for rsp\n");
 					qlt_send_term_exchange(vha, NULL,
-					    atio, 1);
+					    atio, 1, 0);
 				} else {
 					ql_dbg(ql_dbg_tgt, vha, 0xe060,
 					    "qla_target(%d): Unable to send "
@@ -5502,7 +5774,7 @@
 	fc_port_t *fcport;
 	int rc;
 
-	fcport = kzalloc(sizeof(*fcport), GFP_KERNEL);
+	fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
 	if (!fcport) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06f,
 		    "qla_target(%d): Allocation of tmp FC port failed",
@@ -5534,12 +5806,16 @@
 	int rc, global_resets;
 	uint16_t loop_id = 0;
 
+	mutex_lock(&vha->vha_tgt.tgt_mutex);
+
 retry:
 	global_resets =
 	    atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
 
 	rc = qla24xx_get_loop_id(vha, s_id, &loop_id);
 	if (rc != 0) {
+		mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
 		if ((s_id[0] == 0xFF) &&
 		    (s_id[1] == 0xFC)) {
 			/*
@@ -5550,17 +5826,27 @@
 			    "Unable to find initiator with S_ID %x:%x:%x",
 			    s_id[0], s_id[1], s_id[2]);
 		} else
-			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf071,
+			ql_log(ql_log_info, vha, 0xf071,
 			    "qla_target(%d): Unable to find "
 			    "initiator with S_ID %x:%x:%x",
 			    vha->vp_idx, s_id[0], s_id[1],
 			    s_id[2]);
+
+		if (rc == -ENOENT) {
+			qlt_port_logo_t logo;
+			sid_to_portid(s_id, &logo.id);
+			logo.cmd_count = 1;
+			qlt_send_first_logo(vha, &logo);
+		}
+
 		return NULL;
 	}
 
 	fcport = qlt_get_port_database(vha, loop_id);
-	if (!fcport)
+	if (!fcport) {
+		mutex_unlock(&vha->vha_tgt.tgt_mutex);
 		return NULL;
+	}
 
 	if (global_resets !=
 	    atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) {
@@ -5575,6 +5861,8 @@
 
 	sess = qlt_create_sess(vha, fcport, true);
 
+	mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
 	kfree(fcport);
 	return sess;
 }
@@ -5585,15 +5873,15 @@
 	struct scsi_qla_host *vha = tgt->vha;
 	struct qla_hw_data *ha = vha->hw;
 	struct qla_tgt_sess *sess = NULL;
-	unsigned long flags;
+	unsigned long flags = 0, flags2 = 0;
 	uint32_t be_s_id;
 	uint8_t s_id[3];
 	int rc;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
 
 	if (tgt->tgt_stop)
-		goto out_term;
+		goto out_term2;
 
 	s_id[0] = prm->abts.fcp_hdr_le.s_id[2];
 	s_id[1] = prm->abts.fcp_hdr_le.s_id[1];
@@ -5602,41 +5890,47 @@
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
 	    (unsigned char *)&be_s_id);
 	if (!sess) {
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
 
-		mutex_lock(&vha->vha_tgt.tgt_mutex);
 		sess = qlt_make_local_sess(vha, s_id);
 		/* sess has got an extra creation ref */
-		mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
 		if (!sess)
-			goto out_term;
+			goto out_term2;
 	} else {
 		if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
 			sess = NULL;
-			goto out_term;
+			goto out_term2;
 		}
 
 		kref_get(&sess->se_sess->sess_kref);
 	}
 
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
 	if (tgt->tgt_stop)
 		goto out_term;
 
 	rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
 	if (rc != 0)
 		goto out_term;
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
 	return;
 
+out_term2:
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
 out_term:
 	qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
 	if (sess)
 		ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
 }
 
 static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -5653,7 +5947,7 @@
 	int fn;
 	void *iocb;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 
 	if (tgt->tgt_stop)
 		goto out_term;
@@ -5661,14 +5955,12 @@
 	s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id;
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
 	if (!sess) {
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
-		mutex_lock(&vha->vha_tgt.tgt_mutex);
 		sess = qlt_make_local_sess(vha, s_id);
 		/* sess has got an extra creation ref */
-		mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 		if (!sess)
 			goto out_term;
 	} else {
@@ -5690,14 +5982,14 @@
 		goto out_term;
 
 	ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	return;
 
 out_term:
-	qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
+	qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
 	if (sess)
 		ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 static void qlt_sess_work_fn(struct work_struct *work)
@@ -6002,6 +6294,7 @@
 	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 	unsigned long flags;
 	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+	int rspq_ent = QLA83XX_RSPQ_MSIX_ENTRY_NUMBER;
 
 	if (!tgt) {
 		ql_dbg(ql_dbg_tgt, vha, 0xe069,
@@ -6020,9 +6313,21 @@
 		qla24xx_disable_vp(vha);
 		qla24xx_enable_vp(vha);
 	} else {
+		if (ha->msix_entries) {
+			ql_dbg(ql_dbg_tgt, vha, 0xffff,
+			    "%s: host%ld : vector %d cpu %d\n",
+			    __func__, vha->host_no,
+			    ha->msix_entries[rspq_ent].vector,
+			    ha->msix_entries[rspq_ent].cpuid);
+
+			ha->tgt.rspq_vector_cpuid =
+			    ha->msix_entries[rspq_ent].cpuid;
+		}
+
 		set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
 		qla2xxx_wake_dpc(base_vha);
-		qla2x00_wait_for_hba_online(base_vha);
+		WARN_ON_ONCE(qla2x00_wait_for_hba_online(base_vha) !=
+			     QLA_SUCCESS);
 	}
 }
 EXPORT_SYMBOL(qlt_enable_vha);
@@ -6052,7 +6357,9 @@
 
 	set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 	qla2xxx_wake_dpc(vha);
-	qla2x00_wait_for_hba_online(vha);
+	if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS)
+		ql_dbg(ql_dbg_tgt, vha, 0xe081,
+		       "qla2x00_wait_for_hba_online() failed\n");
 }
 
 /*
@@ -6131,7 +6438,7 @@
  * @ha: SCSI driver HA context
  */
 void
-qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
+qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked)
 {
 	struct qla_hw_data *ha = vha->hw;
 	struct atio_from_isp *pkt;
@@ -6144,7 +6451,8 @@
 		pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr;
 		cnt = pkt->u.raw.entry_count;
 
-		qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt);
+		qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt,
+		    ha_locked);
 
 		for (i = 0; i < cnt; i++) {
 			ha->tgt.atio_ring_index++;
@@ -6265,10 +6573,21 @@
 {
 	struct qla_hw_data *ha = vha->hw;
 
+	if (!QLA_TGT_MODE_ENABLED())
+		return;
+
 	if (ha->tgt.node_name_set) {
 		memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
 		icb->firmware_options_1 |= cpu_to_le32(BIT_14);
 	}
+
+	/* disable ZIO at start time. */
+	if (!vha->flags.init_done) {
+		uint32_t tmp;
+		tmp = le32_to_cpu(icb->firmware_options_2);
+		tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+		icb->firmware_options_2 = cpu_to_le32(tmp);
+	}
 }
 
 void
@@ -6359,6 +6678,15 @@
 		memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
 		icb->firmware_options_1 |= cpu_to_le32(BIT_14);
 	}
+
+	/* disable ZIO at start time. */
+	if (!vha->flags.init_done) {
+		uint32_t tmp;
+		tmp = le32_to_cpu(icb->firmware_options_2);
+		tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+		icb->firmware_options_2 = cpu_to_le32(tmp);
+	}
+
 }
 
 void
@@ -6428,16 +6756,59 @@
 	ha = rsp->hw;
 	vha = pci_get_drvdata(ha->pdev);
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.atio_lock, flags);
 
-	qlt_24xx_process_atio_queue(vha);
-	qla24xx_process_response_queue(vha, rsp);
+	qlt_24xx_process_atio_queue(vha, 0);
 
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
 
 	return IRQ_HANDLED;
 }
 
+static void
+qlt_handle_abts_recv_work(struct work_struct *work)
+{
+	struct qla_tgt_sess_op *op = container_of(work,
+		struct qla_tgt_sess_op, work);
+	scsi_qla_host_t *vha = op->vha;
+	struct qla_hw_data *ha = vha->hw;
+	unsigned long flags;
+
+	if (qla2x00_reset_active(vha) || (op->chip_reset != ha->chip_reset))
+		return;
+
+	spin_lock_irqsave(&ha->tgt.atio_lock, flags);
+	qlt_24xx_process_atio_queue(vha, 0);
+	spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	qlt_response_pkt_all_vps(vha, (response_t *)&op->atio);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void
+qlt_handle_abts_recv(struct scsi_qla_host *vha, response_t *pkt)
+{
+	struct qla_tgt_sess_op *op;
+
+	op = kzalloc(sizeof(*op), GFP_ATOMIC);
+
+	if (!op) {
+		/* do not reach for ATIO queue here.  This is best effort err
+		 * recovery at this point.
+		 */
+		qlt_response_pkt_all_vps(vha, pkt);
+		return;
+	}
+
+	memcpy(&op->atio, pkt, sizeof(*pkt));
+	op->vha = vha;
+	op->chip_reset = vha->hw->chip_reset;
+	INIT_WORK(&op->work, qlt_handle_abts_recv_work);
+	queue_work(qla_tgt_wq, &op->work);
+	return;
+}
+
 int
 qlt_mem_alloc(struct qla_hw_data *ha)
 {
@@ -6532,13 +6903,25 @@
 		return -ENOMEM;
 	}
 
+	qla_tgt_plogi_cachep = kmem_cache_create("qla_tgt_plogi_cachep",
+						 sizeof(qlt_plogi_ack_t),
+						 __alignof__(qlt_plogi_ack_t),
+						 0, NULL);
+
+	if (!qla_tgt_plogi_cachep) {
+		ql_log(ql_log_fatal, NULL, 0xe06d,
+		    "kmem_cache_create for qla_tgt_plogi_cachep failed\n");
+		ret = -ENOMEM;
+		goto out_mgmt_cmd_cachep;
+	}
+
 	qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab,
 	    mempool_free_slab, qla_tgt_mgmt_cmd_cachep);
 	if (!qla_tgt_mgmt_cmd_mempool) {
 		ql_log(ql_log_fatal, NULL, 0xe06e,
 		    "mempool_create for qla_tgt_mgmt_cmd_mempool failed\n");
 		ret = -ENOMEM;
-		goto out_mgmt_cmd_cachep;
+		goto out_plogi_cachep;
 	}
 
 	qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0);
@@ -6555,6 +6938,8 @@
 
 out_cmd_mempool:
 	mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+out_plogi_cachep:
+	kmem_cache_destroy(qla_tgt_plogi_cachep);
 out_mgmt_cmd_cachep:
 	kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
 	return ret;
@@ -6567,5 +6952,6 @@
 
 	destroy_workqueue(qla_tgt_wq);
 	mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+	kmem_cache_destroy(qla_tgt_plogi_cachep);
 	kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
 }
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_target.h
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_target.h
@@ -787,7 +787,7 @@
 #define QLA_TGT_STATE_NEED_DATA		1 /* target needs data to continue */
 #define QLA_TGT_STATE_DATA_IN		2 /* Data arrived + target processing */
 #define QLA_TGT_STATE_PROCESSED		3 /* target done processing */
-#define QLA_TGT_STATE_ABORTED		4 /* Command aborted */
+
 
 /* Special handles */
 #define QLA_TGT_NULL_HANDLE	0
@@ -835,6 +835,7 @@
 	 * HW lock.
 	 */
 	int irq_cmd_count;
+	int atio_irq_cmd_count;
 
 	int datasegs_per_cmd, datasegs_per_cont, sg_tablesize;
 
@@ -883,6 +884,7 @@
 
 struct qla_tgt_sess_op {
 	struct scsi_qla_host *vha;
+	uint32_t chip_reset;
 	struct atio_from_isp atio;
 	struct work_struct work;
 	struct list_head cmd_list;
@@ -896,6 +898,19 @@
 	QLA_SESS_DELETION_IN_PROGRESS	= 2,
 };
 
+typedef enum {
+	QLT_PLOGI_LINK_SAME_WWN,
+	QLT_PLOGI_LINK_CONFLICT,
+	QLT_PLOGI_LINK_MAX
+} qlt_plogi_link_t;
+
+typedef struct {
+	struct list_head		list;
+	struct imm_ntfy_from_isp	iocb;
+	port_id_t			id;
+	int				ref_count;
+} qlt_plogi_ack_t;
+
 /*
  * Equivilant to IT Nexus (Initiator-Target)
  */
@@ -907,8 +922,8 @@
 	unsigned int deleted:2;
 	unsigned int local:1;
 	unsigned int logout_on_delete:1;
-	unsigned int plogi_ack_needed:1;
 	unsigned int keep_nport_handle:1;
+	unsigned int send_els_logo:1;
 
 	unsigned char logout_completed;
 
@@ -925,11 +940,39 @@
 	uint8_t port_name[WWN_SIZE];
 	struct work_struct free_work;
 
-	union {
-		struct imm_ntfy_from_isp tm_iocb;
-	};
+	qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
 };
 
+typedef enum {
+	/*
+	 * BIT_0 - Atio Arrival / schedule to work
+	 * BIT_1 - qlt_do_work
+	 * BIT_2 - qlt_do work failed
+	 * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
+	 * BIT_4 - read respond/tcm_qla2xx_queue_data_in
+	 * BIT_5 - status respond / tcm_qla2xx_queue_status
+	 * BIT_6 - tcm request to abort/Term exchange.
+	 *	pre_xmit_response->qlt_send_term_exchange
+	 * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
+	 * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
+	 * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
+	 * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
+
+	 * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
+	 * BIT_13 - Bad completion -
+	 *	qlt_ctio_do_completion --> qlt_term_ctio_exchange
+	 * BIT_14 - Back end data received/sent.
+	 * BIT_15 - SRR prepare ctio
+	 * BIT_16 - complete free
+	 * BIT_17 - flush - qlt_abort_cmd_on_host_reset
+	 * BIT_18 - completion w/abort status
+	 * BIT_19 - completion w/unknown status
+	 * BIT_20 - tcm_qla2xxx_free_cmd
+	 */
+	CMD_FLAG_DATA_WORK = BIT_11,
+	CMD_FLAG_DATA_WORK_FREE = BIT_21,
+} cmd_flags_t;
+
 struct qla_tgt_cmd {
 	struct se_cmd se_cmd;
 	struct qla_tgt_sess *sess;
@@ -939,6 +982,7 @@
 	/* Sense buffer that will be mapped into outgoing status */
 	unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
 
+	spinlock_t cmd_lock;
 	/* to save extra sess dereferences */
 	unsigned int conf_compl_supported:1;
 	unsigned int sg_mapped:1;
@@ -949,6 +993,7 @@
 	unsigned int term_exchg:1;
 	unsigned int cmd_sent_to_fw:1;
 	unsigned int cmd_in_wq:1;
+	unsigned int aborted:1;
 
 	struct scatterlist *sg;	/* cmd data buffer SG vector */
 	int sg_cnt;		/* SG segments count */
@@ -972,30 +1017,8 @@
 
 	uint64_t jiffies_at_alloc;
 	uint64_t jiffies_at_free;
-	/* BIT_0 - Atio Arrival / schedule to work
-	 * BIT_1 - qlt_do_work
-	 * BIT_2 - qlt_do work failed
-	 * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
-	 * BIT_4 - read respond/tcm_qla2xx_queue_data_in
-	 * BIT_5 - status respond / tcm_qla2xx_queue_status
-	 * BIT_6 - tcm request to abort/Term exchange.
-	 *	pre_xmit_response->qlt_send_term_exchange
-	 * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
-	 * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
-	 * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
-	 * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
-	 * BIT_11 - Data actually going to TCM : tcm_qla2xx_handle_data_work
-	 * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
-	 * BIT_13 - Bad completion -
-	 *	qlt_ctio_do_completion --> qlt_term_ctio_exchange
-	 * BIT_14 - Back end data received/sent.
-	 * BIT_15 - SRR prepare ctio
-	 * BIT_16 - complete free
-	 * BIT_17 - flush - qlt_abort_cmd_on_host_reset
-	 * BIT_18 - completion w/abort status
-	 * BIT_19 - completion w/unknown status
-	 */
-	uint32_t cmd_flags;
+
+	cmd_flags_t cmd_flags;
 };
 
 struct qla_tgt_sess_work_param {
@@ -1120,13 +1143,21 @@
 	return key;
 }
 
+static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
+{
+	memset(p, 0, sizeof(*p));
+	p->b.domain = s_id[0];
+	p->b.area = s_id[1];
+	p->b.al_pa = s_id[2];
+}
+
 /*
  * Exported symbols from qla_target.c LLD logic used by qla2xxx code..
  */
 extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
 extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
 extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
-extern void qlt_abort_cmd(struct qla_tgt_cmd *);
+extern int qlt_abort_cmd(struct qla_tgt_cmd *);
 extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
@@ -1135,7 +1166,7 @@
 extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
 extern void qlt_rff_id(struct scsi_qla_host *, struct ct_sns_req *);
 extern void qlt_init_atio_q_entries(struct scsi_qla_host *);
-extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *);
+extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *, uint8_t);
 extern void qlt_24xx_config_rings(struct scsi_qla_host *);
 extern void qlt_24xx_config_nvram_stage1(struct scsi_qla_host *,
 	struct nvram_24xx *);
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_tmpl.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_tmpl.c
@@ -395,6 +395,10 @@
 	if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
 		for (i = 0; i < vha->hw->max_req_queues; i++) {
 			struct req_que *req = vha->hw->req_q_map[i];
+
+			if (!test_bit(i, vha->hw->req_qid_map))
+				continue;
+
 			if (req || !buf) {
 				length = req ?
 				    req->length : REQUEST_ENTRY_CNT_24XX;
@@ -408,6 +412,10 @@
 	} else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
 		for (i = 0; i < vha->hw->max_rsp_queues; i++) {
 			struct rsp_que *rsp = vha->hw->rsp_q_map[i];
+
+			if (!test_bit(i, vha->hw->rsp_qid_map))
+				continue;
+
 			if (rsp || !buf) {
 				length = rsp ?
 				    rsp->length : RESPONSE_ENTRY_CNT_MQ;
@@ -634,6 +642,10 @@
 	if (ent->t274.queue_type == T274_QUEUE_TYPE_REQ_SHAD) {
 		for (i = 0; i < vha->hw->max_req_queues; i++) {
 			struct req_que *req = vha->hw->req_q_map[i];
+
+			if (!test_bit(i, vha->hw->req_qid_map))
+				continue;
+
 			if (req || !buf) {
 				qla27xx_insert16(i, buf, len);
 				qla27xx_insert16(1, buf, len);
@@ -645,6 +657,10 @@
 	} else if (ent->t274.queue_type == T274_QUEUE_TYPE_RSP_SHAD) {
 		for (i = 0; i < vha->hw->max_rsp_queues; i++) {
 			struct rsp_que *rsp = vha->hw->rsp_q_map[i];
+
+			if (!test_bit(i, vha->hw->rsp_qid_map))
+				continue;
+
 			if (rsp || !buf) {
 				qla27xx_insert16(i, buf, len);
 				qla27xx_insert16(1, buf, len);
@@ -855,7 +871,8 @@
 static inline int
 qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp)
 {
-	return qla27xx_template_checksum(tmp, tmp->template_size) == 0;
+	return qla27xx_template_checksum(tmp,
+		le32_to_cpu(tmp->template_size)) == 0;
 }
 
 static inline int
@@ -871,7 +888,7 @@
 	ulong len;
 
 	if (qla27xx_fwdt_template_valid(tmp)) {
-		len = tmp->template_size;
+		len = le32_to_cpu(tmp->template_size);
 		tmp = memcpy(vha->hw->fw_dump, tmp, len);
 		ql27xx_edit_template(vha, tmp);
 		qla27xx_walk_template(vha, tmp, tmp, &len);
@@ -887,7 +904,7 @@
 	ulong len = 0;
 
 	if (qla27xx_fwdt_template_valid(tmp)) {
-		len = tmp->template_size;
+		len = le32_to_cpu(tmp->template_size);
 		qla27xx_walk_template(vha, tmp, NULL, &len);
 	}
 
@@ -899,7 +916,7 @@
 {
 	struct qla27xx_fwdt_template *tmp = p;
 
-	return tmp->template_size;
+	return le32_to_cpu(tmp->template_size);
 }
 
 ulong
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/qla_tmpl.h
+++ linux-4.4.0/drivers/scsi/qla2xxx/qla_tmpl.h
@@ -13,7 +13,7 @@
 struct __packed qla27xx_fwdt_template {
 	uint32_t template_type;
 	uint32_t entry_offset;
-	uint32_t template_size;
+	__le32 template_size;
 	uint32_t reserved_1;
 
 	uint32_t entry_count;
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ linux-4.4.0/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -284,6 +284,7 @@
 
 	WARN_ON(cmd->cmd_flags &  BIT_16);
 
+	cmd->vha->tgt_counters.qla_core_ret_sta_ctio++;
 	cmd->cmd_flags |= BIT_16;
 	transport_generic_free_cmd(&cmd->se_cmd, 0);
 }
@@ -295,9 +296,14 @@
  */
 static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
 {
+	cmd->vha->tgt_counters.core_qla_free_cmd++;
 	cmd->cmd_in_wq = 1;
+
+	BUG_ON(cmd->cmd_flags & BIT_20);
+	cmd->cmd_flags |= BIT_20;
+
 	INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
-	queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+	queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
 }
 
 /*
@@ -342,9 +348,9 @@
 	BUG_ON(!sess);
 	vha = sess->vha;
 
-	spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
 	target_sess_cmd_list_set_waiting(se_sess);
-	spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 
 	return 1;
 }
@@ -358,9 +364,9 @@
 	BUG_ON(!sess);
 	vha = sess->vha;
 
-	spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
 	qlt_unreg_sess(sess);
-	spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 }
 
 static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess)
@@ -372,6 +378,20 @@
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
+
+	if (cmd->aborted) {
+		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
+		 * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+		 * already kick start the free.
+		 */
+		pr_debug("write_pending aborted cmd[%p] refcount %d "
+			"transport_state %x, t_state %x, se_cmd_flags %x\n",
+			cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+			cmd->se_cmd.transport_state,
+			cmd->se_cmd.t_state,
+			cmd->se_cmd.se_cmd_flags);
+		return 0;
+	}
 	cmd->cmd_flags |= BIT_3;
 	cmd->bufflen = se_cmd->data_length;
 	cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -403,7 +423,7 @@
 	    se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
 		spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
 		wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
-					    3 * HZ);
+						50);
 		return 0;
 	}
 	spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
@@ -442,6 +462,9 @@
 	if (bidi)
 		flags |= TARGET_SCF_BIDI_OP;
 
+	if (se_cmd->cpuid != WORK_CPU_UNBOUND)
+		flags |= TARGET_SCF_USE_CPUID;
+
 	sess = cmd->sess;
 	if (!sess) {
 		pr_err("Unable to locate struct qla_tgt_sess from qla_tgt_cmd\n");
@@ -454,6 +477,7 @@
 		return -EINVAL;
 	}
 
+	cmd->vha->tgt_counters.qla_core_sbt_cmd++;
 	return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0],
 				cmd->unpacked_lun, data_length, fcp_task_attr,
 				data_dir, flags);
@@ -462,13 +486,26 @@
 static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 {
 	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+	unsigned long flags;
 
 	/*
 	 * Ensure that the complete FCP WRITE payload has been received.
 	 * Otherwise return an exception via CHECK_CONDITION status.
 	 */
 	cmd->cmd_in_wq = 0;
-	cmd->cmd_flags |= BIT_11;
+
+	spin_lock_irqsave(&cmd->cmd_lock, flags);
+	cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
+	if (cmd->aborted) {
+		cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+		tcm_qla2xxx_free_cmd(cmd);
+		return;
+	}
+	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+	cmd->vha->tgt_counters.qla_core_ret_ctio++;
 	if (!cmd->write_data_transferred) {
 		/*
 		 * Check if se_cmd has already been aborted via LUN_RESET, and
@@ -500,7 +537,7 @@
 	cmd->cmd_flags |= BIT_10;
 	cmd->cmd_in_wq = 1;
 	INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work);
-	queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+	queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
 }
 
 static void tcm_qla2xxx_handle_dif_work(struct work_struct *work)
@@ -542,6 +579,20 @@
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
 
+	if (cmd->aborted) {
+		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
+		 * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+		 * already kick start the free.
+		 */
+		pr_debug("queue_data_in aborted cmd[%p] refcount %d "
+			"transport_state %x, t_state %x, se_cmd_flags %x\n",
+			cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+			cmd->se_cmd.transport_state,
+			cmd->se_cmd.t_state,
+			cmd->se_cmd.se_cmd_flags);
+		return 0;
+	}
+
 	cmd->cmd_flags |= BIT_4;
 	cmd->bufflen = se_cmd->data_length;
 	cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -633,17 +684,40 @@
 	qlt_xmit_tm_rsp(mcmd);
 }
 
+
+#define DATA_WORK_NOT_FREE(_flags) \
+	(( _flags & (CMD_FLAG_DATA_WORK|CMD_FLAG_DATA_WORK_FREE)) == \
+	 CMD_FLAG_DATA_WORK)
 static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
-	qlt_abort_cmd(cmd);
+	unsigned long flags;
+
+	if (qlt_abort_cmd(cmd))
+		return;
+
+	spin_lock_irqsave(&cmd->cmd_lock, flags);
+	if ((cmd->state == QLA_TGT_STATE_NEW)||
+		((cmd->state == QLA_TGT_STATE_DATA_IN) &&
+		 DATA_WORK_NOT_FREE(cmd->cmd_flags)) ) {
+
+		cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+		/* Cmd have not reached firmware.
+		 * Use this trigger to free it. */
+		tcm_qla2xxx_free_cmd(cmd);
+		return;
+	}
+	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+	return;
+
 }
 
 static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
 			struct tcm_qla2xxx_nacl *, struct qla_tgt_sess *);
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess)
 {
@@ -697,13 +771,13 @@
 	if (!sess)
 		return;
 
-	assert_spin_locked(&sess->vha->hw->hardware_lock);
+	assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
 	kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
 }
 
 static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess)
 {
-	assert_spin_locked(&sess->vha->hw->hardware_lock);
+	assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
 	target_sess_cmd_list_set_waiting(sess->se_sess);
 }
 
@@ -793,38 +867,14 @@
 			atomic_read(&tpg->lport_tpg_enabled));
 }
 
-static void tcm_qla2xxx_depend_tpg(struct work_struct *work)
-{
-	struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
-				struct tcm_qla2xxx_tpg, tpg_base_work);
-	struct se_portal_group *se_tpg = &base_tpg->se_tpg;
-	struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
-
-	if (!target_depend_item(&se_tpg->tpg_group.cg_item)) {
-		atomic_set(&base_tpg->lport_tpg_enabled, 1);
-		qlt_enable_vha(base_vha);
-	}
-	complete(&base_tpg->tpg_base_comp);
-}
-
-static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
-{
-	struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
-				struct tcm_qla2xxx_tpg, tpg_base_work);
-	struct se_portal_group *se_tpg = &base_tpg->se_tpg;
-	struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
-
-	if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) {
-		atomic_set(&base_tpg->lport_tpg_enabled, 0);
-		target_undepend_item(&se_tpg->tpg_group.cg_item);
-	}
-	complete(&base_tpg->tpg_base_comp);
-}
-
 static ssize_t tcm_qla2xxx_tpg_enable_store(struct config_item *item,
 		const char *page, size_t count)
 {
 	struct se_portal_group *se_tpg = to_tpg(item);
+	struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
+	struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
+			struct tcm_qla2xxx_lport, lport_wwn);
+	struct scsi_qla_host *vha = lport->qla_vha;
 	struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
 			struct tcm_qla2xxx_tpg, se_tpg);
 	unsigned long op;
@@ -843,24 +893,17 @@
 		if (atomic_read(&tpg->lport_tpg_enabled))
 			return -EEXIST;
 
-		INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_depend_tpg);
+		atomic_set(&tpg->lport_tpg_enabled, 1);
+		qlt_enable_vha(vha);
 	} else {
 		if (!atomic_read(&tpg->lport_tpg_enabled))
 			return count;
 
-		INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_undepend_tpg);
+		atomic_set(&tpg->lport_tpg_enabled, 0);
+		qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+		qlt_stop_phase2(vha->vha_tgt.qla_tgt);
 	}
-	init_completion(&tpg->tpg_base_comp);
-	schedule_work(&tpg->tpg_base_work);
-	wait_for_completion(&tpg->tpg_base_comp);
 
-	if (op) {
-		if (!atomic_read(&tpg->lport_tpg_enabled))
-			return -ENODEV;
-	} else {
-		if (atomic_read(&tpg->lport_tpg_enabled))
-			return -EPERM;
-	}
 	return count;
 }
 
@@ -1022,6 +1065,7 @@
 
 		atomic_set(&tpg->lport_tpg_enabled, 0);
 		qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+		qlt_stop_phase2(vha->vha_tgt.qla_tgt);
 	}
 
 	return count;
@@ -1077,7 +1121,7 @@
 }
 
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
 	scsi_qla_host_t *vha,
@@ -1116,7 +1160,7 @@
 }
 
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static void tcm_qla2xxx_set_sess_by_s_id(
 	struct tcm_qla2xxx_lport *lport,
@@ -1182,7 +1226,7 @@
 }
 
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
 	scsi_qla_host_t *vha,
@@ -1221,7 +1265,7 @@
 }
 
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static void tcm_qla2xxx_set_sess_by_loop_id(
 	struct tcm_qla2xxx_lport *lport,
@@ -1285,7 +1329,7 @@
 }
 
 /*
- * Should always be called with qla_hw_data->hardware_lock held.
+ * Should always be called with qla_hw_data->tgt.sess_lock held.
  */
 static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *lport,
 		struct tcm_qla2xxx_nacl *nacl, struct qla_tgt_sess *sess)
@@ -1353,7 +1397,7 @@
 	struct qla_tgt_sess *sess = qla_tgt_sess;
 	unsigned char port_name[36];
 	unsigned long flags;
-	int num_tags = (ha->fw_xcb_count) ? ha->fw_xcb_count :
+	int num_tags = (ha->cur_fw_xcb_count) ? ha->cur_fw_xcb_count :
 		       TCM_QLA2XXX_DEFAULT_TAGS;
 
 	lport = vha->vha_tgt.target_lport_ptr;
@@ -1401,12 +1445,12 @@
 	 * And now setup the new se_nacl and session pointers into our HW lport
 	 * mappings for fabric S_ID and LOOP_ID.
 	 */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, se_sess,
 			qla_tgt_sess, s_id);
 	tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl, se_sess,
 			qla_tgt_sess, loop_id);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	/*
 	 * Finally register the new FC Nexus with TCM
 	 */
--- linux-4.4.0.orig/drivers/scsi/qla2xxx/tcm_qla2xxx.h
+++ linux-4.4.0/drivers/scsi/qla2xxx/tcm_qla2xxx.h
@@ -47,9 +47,6 @@
 	struct tcm_qla2xxx_tpg_attrib tpg_attrib;
 	/* Returned by tcm_qla2xxx_make_tpg() */
 	struct se_portal_group se_tpg;
-	/* Items for dealing with configfs_depend_item */
-	struct completion tpg_base_comp;
-	struct work_struct tpg_base_work;
 };
 
 struct tcm_qla2xxx_fc_loopid {
--- linux-4.4.0.orig/drivers/scsi/qla4xxx/ql4_def.h
+++ linux-4.4.0/drivers/scsi/qla4xxx/ql4_def.h
@@ -168,6 +168,8 @@
 #define DEV_DB_NON_PERSISTENT	0
 #define DEV_DB_PERSISTENT	1
 
+#define QL4_ISP_REG_DISCONNECT 0xffffffffU
+
 #define COPY_ISID(dst_isid, src_isid) {			\
 	int i, j;					\
 	for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;)	\
--- linux-4.4.0.orig/drivers/scsi/qla4xxx/ql4_isr.c
+++ linux-4.4.0/drivers/scsi/qla4xxx/ql4_isr.c
@@ -385,9 +385,9 @@
 
 	cls_conn = ddb_entry->conn;
 	conn = cls_conn->dd_data;
-	spin_lock(&conn->session->back_lock);
+	spin_lock(&conn->session->lock);
 	task = iscsi_itt_to_task(conn, itt);
-	spin_unlock(&conn->session->back_lock);
+	spin_unlock(&conn->session->lock);
 
 	if (task == NULL) {
 		ql4_printk(KERN_ERR, ha, "%s: Task is NULL\n", __func__);
--- linux-4.4.0.orig/drivers/scsi/qla4xxx/ql4_mbx.c
+++ linux-4.4.0/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -641,9 +641,6 @@
 
 	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) !=
 	    QLA_SUCCESS) {
-		dma_free_coherent(&ha->pdev->dev,
-				  sizeof(struct addr_ctrl_blk),
-				  init_fw_cb, init_fw_cb_dma);
 		goto exit_init_fw_cb;
 	}
 
--- linux-4.4.0.orig/drivers/scsi/qla4xxx/ql4_os.c
+++ linux-4.4.0/drivers/scsi/qla4xxx/ql4_os.c
@@ -262,6 +262,24 @@
 
 static struct scsi_transport_template *qla4xxx_scsi_transport;
 
+static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha)
+{
+	u32 reg_val = 0;
+	int rval = QLA_SUCCESS;
+
+	if (is_qla8022(ha))
+		reg_val = readl(&ha->qla4_82xx_reg->host_status);
+	else if (is_qla8032(ha) || is_qla8042(ha))
+		reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
+	else
+		reg_val = readw(&ha->reg->ctrl_status);
+
+	if (reg_val == QL4_ISP_REG_DISCONNECT)
+		rval = QLA_ERROR;
+
+	return rval;
+}
+
 static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
 			     uint32_t iface_type, uint32_t payload_size,
 			     uint32_t pid, struct sockaddr *dst_addr)
@@ -1205,7 +1223,7 @@
 			le64_to_cpu(ql_iscsi_stats->iscsi_sequence_error);
 exit_host_stats:
 	if (ql_iscsi_stats)
-		dma_free_coherent(&ha->pdev->dev, host_stats_size,
+		dma_free_coherent(&ha->pdev->dev, stats_size,
 				  ql_iscsi_stats, iscsi_stats_dma);
 
 	ql4_printk(KERN_INFO, ha, "%s: Get host stats done\n",
@@ -3189,6 +3207,8 @@
 	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
 		return -EINVAL;
 	ep = iscsi_lookup_endpoint(transport_fd);
+	if (!ep)
+		return -EINVAL;
 	conn = cls_conn->dd_data;
 	qla_conn = conn->dd_data;
 	qla_conn->qla_ep = ep->dd_data;
@@ -4130,7 +4150,7 @@
 		dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
 				  ha->queues_dma);
 
-	 if (ha->fw_dump)
+	if (ha->fw_dump)
 		vfree(ha->fw_dump);
 
 	ha->queues_len = 0;
@@ -4265,7 +4285,6 @@
 	return QLA_SUCCESS;
 
 mem_alloc_error_exit:
-	qla4xxx_mem_free(ha);
 	return QLA_ERROR;
 }
 
@@ -5919,7 +5938,7 @@
 		val = rd_nvram_byte(ha, sec_addr);
 		if (val & BIT_7)
 			ddb_index[1] = (val & 0x7f);
-
+		goto exit_boot_info;
 	} else if (is_qla80XX(ha)) {
 		buf = dma_alloc_coherent(&ha->pdev->dev, size,
 					 &buf_dma, GFP_KERNEL);
@@ -7227,6 +7246,8 @@
 
 	rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
 					   fw_ddb_entry);
+	if (rc)
+		goto free_sess;
 
 	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
 		   __func__, fnode_sess->dev.kobj.name);
@@ -9196,10 +9217,17 @@
 	struct srb *srb = NULL;
 	int ret = SUCCESS;
 	int wait = 0;
+	int rval;
 
 	ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n",
 		   ha->host_no, id, lun, cmd, cmd->cmnd[0]);
 
+	rval = qla4xxx_isp_check_reg(ha);
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+		return FAILED;
+	}
+
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	srb = (struct srb *) CMD_SP(cmd);
 	if (!srb) {
@@ -9251,6 +9279,7 @@
 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
 	int ret = FAILED, stat;
+	int rval;
 
 	if (!ddb_entry)
 		return ret;
@@ -9270,6 +9299,12 @@
 		      cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
+	rval = qla4xxx_isp_check_reg(ha);
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+		return FAILED;
+	}
+
 	/* FIXME: wait for hba to go online */
 	stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
 	if (stat != QLA_SUCCESS) {
@@ -9313,6 +9348,7 @@
 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
 	int stat, ret;
+	int rval;
 
 	if (!ddb_entry)
 		return FAILED;
@@ -9330,6 +9366,12 @@
 		      ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
+	rval = qla4xxx_isp_check_reg(ha);
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+		return FAILED;
+	}
+
 	stat = qla4xxx_reset_target(ha, ddb_entry);
 	if (stat != QLA_SUCCESS) {
 		starget_printk(KERN_INFO, scsi_target(cmd->device),
@@ -9384,9 +9426,16 @@
 {
 	int return_status = FAILED;
 	struct scsi_qla_host *ha;
+	int rval;
 
 	ha = to_qla_host(cmd->device->host);
 
+	rval = qla4xxx_isp_check_reg(ha);
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+		return FAILED;
+	}
+
 	if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
 		qla4_83xx_set_idc_dontreset(ha);
 
--- linux-4.4.0.orig/drivers/scsi/qlogicfas.c
+++ linux-4.4.0/drivers/scsi/qlogicfas.c
@@ -137,8 +137,8 @@
 static struct qlogicfas408_priv *cards;
 static int iobase[MAX_QLOGICFAS];
 static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 };
-module_param_array(iobase, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(iobase, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 MODULE_PARM_DESC(iobase, "I/O address");
 MODULE_PARM_DESC(irq, "IRQ");
 
--- linux-4.4.0.orig/drivers/scsi/scsi_common.c
+++ linux-4.4.0/drivers/scsi/scsi_common.c
@@ -278,8 +278,16 @@
 		ucp[3] = 0;
 		put_unaligned_be64(info, &ucp[4]);
 	} else if ((buf[0] & 0x7f) == 0x70) {
-		buf[0] |= 0x80;
-		put_unaligned_be64(info, &buf[3]);
+		/*
+		 * Only set the 'VALID' bit if we can represent the value
+		 * correctly; otherwise just fill out the lower bytes and
+		 * clear the 'VALID' flag.
+		 */
+		if (info <= 0xffffffffUL)
+			buf[0] |= 0x80;
+		else
+			buf[0] &= 0x7f;
+		put_unaligned_be32((u32)info, &buf[3]);
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/scsi/scsi_debug.c
+++ linux-4.4.0/drivers/scsi/scsi_debug.c
@@ -1545,7 +1545,8 @@
 	unsigned char *cmd = scp->cmnd;
 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
 	unsigned long long capac;
-	int k, alloc_len;
+	int k;
+	u32 alloc_len;
 
 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
 		     + cmd[13]);
@@ -1576,7 +1577,7 @@
 	}
 
 	return fill_from_dev_buffer(scp, arr,
-				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
+			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
 }
 
 #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
@@ -1587,8 +1588,9 @@
 	unsigned char *cmd = scp->cmnd;
 	unsigned char * arr;
 	int host_no = devip->sdbg_host->shost->host_no;
-	int n, ret, alen, rlen;
 	int port_group_a, port_group_b, port_a, port_b;
+	u32 alen, n, rlen;
+	int ret;
 
 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
 		+ cmd[9]);
@@ -1655,9 +1657,9 @@
 	 * - The constructed command length
 	 * - The maximum array size
 	 */
-	rlen = min(alen,n);
+	rlen = min(alen, n);
 	ret = fill_from_dev_buffer(scp, arr,
-				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
+			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
 	kfree(arr);
 	return ret;
 }
@@ -2185,11 +2187,11 @@
 			    __func__, param_len, res);
 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
-	if (md_len > 2) {
+	off = bd_len + (mselect6 ? 4 : 8);
+	if (md_len > 2 || off >= res) {
 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
 		return check_condition_result;
 	}
-	off = bd_len + (mselect6 ? 4 : 8);
 	mpage = arr[off] & 0x3f;
 	ps = !!(arr[off] & 0x80);
 	if (ps) {
@@ -4981,6 +4983,7 @@
 	bus_unregister(&pseudo_lld_bus);
 	root_device_unregister(pseudo_primary);
 
+	vfree(map_storep);
 	vfree(dif_storep);
 	vfree(fake_storep);
 }
--- linux-4.4.0.orig/drivers/scsi/scsi_devinfo.c
+++ linux-4.4.0/drivers/scsi/scsi_devinfo.c
@@ -33,7 +33,6 @@
 };
 
 
-static const char spaces[] = "                "; /* 16 of them */
 static unsigned scsi_default_dev_flags;
 static LIST_HEAD(scsi_dev_info_list);
 static char scsi_dev_flags[256];
@@ -160,7 +159,7 @@
 	{"DGC", "RAID", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, storage on LUN 0 */
 	{"DGC", "DISK", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, no storage on LUN 0 */
 	{"EMC",  "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_REPORTLUN2},
 	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
 	{"easyRAID", "16P", NULL, BLIST_NOREPORTLUN},
 	{"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN},
@@ -180,7 +179,7 @@
 	{"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 	{"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 	{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP VA7400 */
-	{"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */
+	{"HP", "OPEN-", "*", BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES}, /* HP XP Arrays */
 	{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
 	{"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
 	{"HP", "C1557A", NULL, BLIST_FORCELUN},
@@ -205,6 +204,7 @@
 	{"Intel", "Multi-Flex", NULL, BLIST_NO_RSOC},
 	{"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
 	{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"Marvell", "Console", NULL, BLIST_SKIP_VPD_PAGES},
 	{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
 	{"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
@@ -218,6 +218,8 @@
 	{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"NEC", "iStorage", NULL, BLIST_REPORTLUN2},
+	{"NETAPP", "LUN C-Mode", NULL, BLIST_SYNC_ALUA},
+	{"NETAPP", "INF-01-00", NULL, BLIST_SYNC_ALUA},
 	{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -226,7 +228,9 @@
 	{"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC},
 	{"Promise", "", NULL, BLIST_SPARSELUN},
+	{"QEMU", "QEMU CD-ROM", NULL, BLIST_SKIP_VPD_PAGES},
 	{"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024},
+	{"SYNOLOGY", "iSCSI Storage", NULL, BLIST_MAX_1024},
 	{"QUANTUM", "XP34301", "1071", BLIST_NOTQ},
 	{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
 	{"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
@@ -288,20 +292,13 @@
 	size_t from_length;
 
 	from_length = strlen(from);
-	strncpy(to, from, min(to_length, from_length));
-	if (from_length < to_length) {
-		if (compatible) {
-			/*
-			 * NUL terminate the string if it is short.
-			 */
-			to[from_length] = '\0';
-		} else {
-			/* 
-			 * space pad the string if it is short. 
-			 */
-			strncpy(&to[from_length], spaces,
-				to_length - from_length);
-		}
+	/* this zero-pads the destination */
+	strncpy(to, from, to_length);
+	if (from_length < to_length && !compatible) {
+		/*
+		 * space pad the string if it is short.
+		 */
+		memset(&to[from_length], ' ', to_length - from_length);
 	}
 	if (from_length > to_length)
 		 printk(KERN_WARNING "%s: %s string '%s' is too long\n",
@@ -391,8 +388,8 @@
 
 /**
  * scsi_dev_info_list_find - find a matching dev_info list entry.
- * @vendor:	vendor string
- * @model:	model (product) string
+ * @vendor:	full vendor string
+ * @model:	full model (product) string
  * @key:	specify list to use
  *
  * Description:
@@ -407,7 +404,7 @@
 	struct scsi_dev_info_list *devinfo;
 	struct scsi_dev_info_list_table *devinfo_table =
 		scsi_devinfo_lookup_by_key(key);
-	size_t vmax, mmax;
+	size_t vmax, mmax, mlen;
 	const char *vskip, *mskip;
 
 	if (IS_ERR(devinfo_table))
@@ -423,7 +420,7 @@
 	 * here, and we don't know what device it is
 	 * trying to work with, leave it as-is.
 	 */
-	vmax = 8;	/* max length of vendor */
+	vmax = sizeof(devinfo->vendor);
 	vskip = vendor;
 	while (vmax > 0 && *vskip == ' ') {
 		vmax--;
@@ -433,7 +430,7 @@
 	while (vmax > 0 && vskip[vmax - 1] == ' ')
 		--vmax;
 
-	mmax = 16;	/* max length of model */
+	mmax = sizeof(devinfo->model);
 	mskip = model;
 	while (mmax > 0 && *mskip == ' ') {
 		mmax--;
@@ -446,13 +443,19 @@
 			    dev_info_list) {
 		if (devinfo->compatible) {
 			/*
-			 * Behave like the older version of get_device_flags.
+			 * vendor strings must be an exact match
 			 */
-			if (memcmp(devinfo->vendor, vskip, vmax) ||
-					devinfo->vendor[vmax])
+			if (vmax != strnlen(devinfo->vendor,
+					    sizeof(devinfo->vendor)) ||
+			    memcmp(devinfo->vendor, vskip, vmax))
 				continue;
-			if (memcmp(devinfo->model, mskip, mmax) ||
-					devinfo->model[mmax])
+
+			/*
+			 * @model specifies the full string, and
+			 * must be larger or equal to devinfo->model
+			 */
+			mlen = strnlen(devinfo->model, sizeof(devinfo->model));
+			if (mmax < mlen || memcmp(devinfo->model, mskip, mlen))
 				continue;
 			return devinfo;
 		} else {
@@ -584,17 +587,12 @@
 				int key)
 {
 	struct scsi_dev_info_list *devinfo;
-	int err;
 
 	devinfo = scsi_dev_info_list_find(vendor, model, key);
 	if (!IS_ERR(devinfo))
 		return devinfo->flags;
 
-	err = PTR_ERR(devinfo);
-	if (err != -ENOENT)
-		return err;
-
-	/* nothing found, return nothing */
+	/* key or device not found: return nothing */
 	if (key != SCSI_DEVINFO_GLOBAL)
 		return 0;
 
--- linux-4.4.0.orig/drivers/scsi/scsi_dh.c
+++ linux-4.4.0/drivers/scsi/scsi_dh.c
@@ -56,10 +56,16 @@
 	{"IBM", "1815",			"rdac", },
 	{"IBM", "1818",			"rdac", },
 	{"IBM", "3526",			"rdac", },
-	{"SGI", "TP9",			"rdac", },
+	{"IBM", "3542",			"rdac", },
+	{"IBM", "3552",			"rdac", },
+	{"SGI", "TP9300",		"rdac", },
+	{"SGI", "TP9400",		"rdac", },
+	{"SGI", "TP9500",		"rdac", },
+	{"SGI", "TP9700",		"rdac", },
 	{"SGI", "IS",			"rdac", },
-	{"STK", "OPENstorage D280",	"rdac", },
+	{"STK", "OPENstorage",		"rdac", },
 	{"STK", "FLEXLINE 380",		"rdac", },
+	{"STK", "BladeCtlr",		"rdac", },
 	{"SUN", "CSM",			"rdac", },
 	{"SUN", "LCSM100",		"rdac", },
 	{"SUN", "STK6580_6780",		"rdac", },
@@ -289,20 +295,6 @@
 }
 EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
 
-static struct scsi_device *get_sdev_from_queue(struct request_queue *q)
-{
-	struct scsi_device *sdev;
-	unsigned long flags;
-
-	spin_lock_irqsave(q->queue_lock, flags);
-	sdev = q->queuedata;
-	if (!sdev || !get_device(&sdev->sdev_gendev))
-		sdev = NULL;
-	spin_unlock_irqrestore(q->queue_lock, flags);
-
-	return sdev;
-}
-
 /*
  * scsi_dh_activate - activate the path associated with the scsi_device
  *      corresponding to the given request queue.
@@ -321,7 +313,7 @@
 	struct scsi_device *sdev;
 	int err = SCSI_DH_NOSYS;
 
-	sdev = get_sdev_from_queue(q);
+	sdev = scsi_device_from_queue(q);
 	if (!sdev) {
 		if (fn)
 			fn(data, err);
@@ -368,7 +360,7 @@
 	struct scsi_device *sdev;
 	int err = -SCSI_DH_NOSYS;
 
-	sdev = get_sdev_from_queue(q);
+	sdev = scsi_device_from_queue(q);
 	if (!sdev)
 		return err;
 
@@ -391,7 +383,7 @@
 	struct scsi_device_handler *scsi_dh;
 	int err = 0;
 
-	sdev = get_sdev_from_queue(q);
+	sdev = scsi_device_from_queue(q);
 	if (!sdev)
 		return -ENODEV;
 
@@ -429,7 +421,7 @@
 	struct scsi_device *sdev;
 	const char *handler_name = NULL;
 
-	sdev = get_sdev_from_queue(q);
+	sdev = scsi_device_from_queue(q);
 	if (!sdev)
 		return NULL;
 
--- linux-4.4.0.orig/drivers/scsi/scsi_error.c
+++ linux-4.4.0/drivers/scsi/scsi_error.c
@@ -1127,7 +1127,6 @@
  */
 void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
 {
-	scmd->device->host->host_failed--;
 	scmd->eh_eflags = 0;
 	list_move_tail(&scmd->eh_entry, done_q);
 }
@@ -2226,6 +2225,9 @@
 		else
 			scsi_unjam_host(shost);
 
+		/* All scmds have been handled */
+		shost->host_failed = 0;
+
 		/*
 		 * Note - if the above fails completely, the action is to take
 		 * individual devices offline and flush the queue of any
--- linux-4.4.0.orig/drivers/scsi/scsi_lib.c
+++ linux-4.4.0/drivers/scsi/scsi_lib.c
@@ -23,6 +23,7 @@
 #include <linux/scatterlist.h>
 #include <linux/blk-mq.h>
 #include <linux/ratelimit.h>
+#include <asm/unaligned.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -910,9 +911,12 @@
 	}
 
 	/*
-	 * If we finished all bytes in the request we are done now.
+	 * special case: failed zero length commands always need to
+	 * drop down into the retry code. Otherwise, if we finished
+	 * all bytes in the request we are done now.
 	 */
-	if (!scsi_end_request(req, error, good_bytes, 0))
+	if (!(blk_rq_bytes(req) == 0 && error) &&
+	    !scsi_end_request(req, error, good_bytes, 0))
 		return;
 
 	/*
@@ -1115,9 +1119,10 @@
 	struct scsi_device *sdev = cmd->device;
 	struct request *rq = cmd->request;
 	bool is_mq = (rq->mq_ctx != NULL);
-	int error;
+	int error = BLKPREP_KILL;
 
-	BUG_ON(!rq->nr_phys_segments);
+	if (WARN_ON_ONCE(!rq->nr_phys_segments))
+		goto err_exit;
 
 	error = scsi_init_sgtable(rq, &cmd->sdb);
 	if (error)
@@ -2211,6 +2216,29 @@
 	blk_mq_free_tag_set(&shost->tag_set);
 }
 
+/**
+ * scsi_device_from_queue - return sdev associated with a request_queue
+ * @q: The request queue to return the sdev from
+ *
+ * Return the sdev associated with a request queue or NULL if the
+ * request_queue does not reference a SCSI device.
+ */
+struct scsi_device *scsi_device_from_queue(struct request_queue *q)
+{
+	struct scsi_device *sdev = NULL;
+
+	if (q->mq_ops) {
+		if (q->mq_ops == &scsi_mq_ops)
+			sdev = q->queuedata;
+	} else if (q->request_fn == scsi_request_fn)
+		sdev = q->queuedata;
+	if (!sdev || !get_device(&sdev->sdev_gendev))
+		sdev = NULL;
+
+	return sdev;
+}
+EXPORT_SYMBOL_GPL(scsi_device_from_queue);
+
 /*
  * Function:    scsi_block_requests()
  *
@@ -3154,3 +3182,190 @@
 	atomic_dec(&sdev->disk_events_disable_depth);
 }
 EXPORT_SYMBOL(sdev_enable_disk_events);
+
+/**
+ * scsi_vpd_lun_id - return a unique device identification
+ * @sdev: SCSI device
+ * @id:   buffer for the identification
+ * @id_len:  length of the buffer
+ *
+ * Copies a unique device identification into @id based
+ * on the information in the VPD page 0x83 of the device.
+ * The string will be formatted as a SCSI name string.
+ *
+ * Returns the length of the identification or error on failure.
+ * If the identifier is longer than the supplied buffer the actual
+ * identifier length is returned and the buffer is not zero-padded.
+ */
+int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
+{
+	u8 cur_id_type = 0xff;
+	u8 cur_id_size = 0;
+	unsigned char *d, *cur_id_str;
+	unsigned char __rcu *vpd_pg83;
+	int id_size = -EINVAL;
+
+	rcu_read_lock();
+	vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+	if (!vpd_pg83) {
+		rcu_read_unlock();
+		return -ENXIO;
+	}
+
+	/*
+	 * Look for the correct descriptor.
+	 * Order of preference for lun descriptor:
+	 * - SCSI name string
+	 * - NAA IEEE Registered Extended
+	 * - EUI-64 based 16-byte
+	 * - EUI-64 based 12-byte
+	 * - NAA IEEE Registered
+	 * - NAA IEEE Extended
+	 * as longer descriptors reduce the likelyhood
+	 * of identification clashes.
+	 */
+
+	/* The id string must be at least 20 bytes + terminating NULL byte */
+	if (id_len < 21) {
+		rcu_read_unlock();
+		return -EINVAL;
+	}
+
+	memset(id, 0, id_len);
+	d = vpd_pg83 + 4;
+	while (d < vpd_pg83 + sdev->vpd_pg83_len) {
+		/* Skip designators not referring to the LUN */
+		if ((d[1] & 0x30) != 0x00)
+			goto next_desig;
+
+		switch (d[1] & 0xf) {
+		case 0x2:
+			/* EUI-64 */
+			if (cur_id_size > d[3])
+				break;
+			/* Prefer NAA IEEE Registered Extended */
+			if (cur_id_type == 0x3 &&
+			    cur_id_size == d[3])
+				break;
+			cur_id_size = d[3];
+			cur_id_str = d + 4;
+			cur_id_type = d[1] & 0xf;
+			switch (cur_id_size) {
+			case 8:
+				id_size = snprintf(id, id_len,
+						   "eui.%8phN",
+						   cur_id_str);
+				break;
+			case 12:
+				id_size = snprintf(id, id_len,
+						   "eui.%12phN",
+						   cur_id_str);
+				break;
+			case 16:
+				id_size = snprintf(id, id_len,
+						   "eui.%16phN",
+						   cur_id_str);
+				break;
+			default:
+				cur_id_size = 0;
+				break;
+			}
+			break;
+		case 0x3:
+			/* NAA */
+			if (cur_id_size > d[3])
+				break;
+			cur_id_size = d[3];
+			cur_id_str = d + 4;
+			cur_id_type = d[1] & 0xf;
+			switch (cur_id_size) {
+			case 8:
+				id_size = snprintf(id, id_len,
+						   "naa.%8phN",
+						   cur_id_str);
+				break;
+			case 16:
+				id_size = snprintf(id, id_len,
+						   "naa.%16phN",
+						   cur_id_str);
+				break;
+			default:
+				cur_id_size = 0;
+				break;
+			}
+			break;
+		case 0x8:
+			/* SCSI name string */
+			if (cur_id_size + 4 > d[3])
+				break;
+			/* Prefer others for truncated descriptor */
+			if (cur_id_size && d[3] > id_len)
+				break;
+			cur_id_size = id_size = d[3];
+			cur_id_str = d + 4;
+			cur_id_type = d[1] & 0xf;
+			if (cur_id_size >= id_len)
+				cur_id_size = id_len - 1;
+			memcpy(id, cur_id_str, cur_id_size);
+			/* Decrease priority for truncated descriptor */
+			if (cur_id_size != id_size)
+				cur_id_size = 6;
+			break;
+		default:
+			break;
+		}
+next_desig:
+		d += d[3] + 4;
+	}
+	rcu_read_unlock();
+
+	return id_size;
+}
+EXPORT_SYMBOL(scsi_vpd_lun_id);
+
+/*
+ * scsi_vpd_tpg_id - return a target port group identifier
+ * @sdev: SCSI device
+ *
+ * Returns the Target Port Group identifier from the information
+ * froom VPD page 0x83 of the device.
+ *
+ * Returns the identifier or error on failure.
+ */
+int scsi_vpd_tpg_id(struct scsi_device *sdev, int *rel_id)
+{
+	unsigned char *d;
+	unsigned char __rcu *vpd_pg83;
+	int group_id = -EAGAIN, rel_port = -1;
+
+	rcu_read_lock();
+	vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+	if (!vpd_pg83) {
+		rcu_read_unlock();
+		return -ENXIO;
+	}
+
+	d = sdev->vpd_pg83 + 4;
+	while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
+		switch (d[1] & 0xf) {
+		case 0x4:
+			/* Relative target port */
+			rel_port = get_unaligned_be16(&d[6]);
+			break;
+		case 0x5:
+			/* Target port group */
+			group_id = get_unaligned_be16(&d[6]);
+			break;
+		default:
+			break;
+		}
+		d += d[3] + 4;
+	}
+	rcu_read_unlock();
+
+	if (group_id >= 0 && rel_id && rel_port != -1)
+		*rel_id = rel_port;
+
+	return group_id;
+}
+EXPORT_SYMBOL(scsi_vpd_tpg_id);
--- linux-4.4.0.orig/drivers/scsi/scsi_logging.c
+++ linux-4.4.0/drivers/scsi/scsi_logging.c
@@ -16,57 +16,15 @@
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_dbg.h>
 
-#define SCSI_LOG_SPOOLSIZE 4096
-
-#if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG
-#warning SCSI logging bitmask too large
-#endif
-
-struct scsi_log_buf {
-	char buffer[SCSI_LOG_SPOOLSIZE];
-	unsigned long map;
-};
-
-static DEFINE_PER_CPU(struct scsi_log_buf, scsi_format_log);
-
 static char *scsi_log_reserve_buffer(size_t *len)
 {
-	struct scsi_log_buf *buf;
-	unsigned long map_bits = sizeof(buf->buffer) / SCSI_LOG_BUFSIZE;
-	unsigned long idx = 0;
-
-	preempt_disable();
-	buf = this_cpu_ptr(&scsi_format_log);
-	idx = find_first_zero_bit(&buf->map, map_bits);
-	if (likely(idx < map_bits)) {
-		while (test_and_set_bit(idx, &buf->map)) {
-			idx = find_next_zero_bit(&buf->map, map_bits, idx);
-			if (idx >= map_bits)
-				break;
-		}
-	}
-	if (WARN_ON(idx >= map_bits)) {
-		preempt_enable();
-		return NULL;
-	}
-	*len = SCSI_LOG_BUFSIZE;
-	return buf->buffer + idx * SCSI_LOG_BUFSIZE;
+	*len = 128;
+	return kmalloc(*len, GFP_ATOMIC);
 }
 
 static void scsi_log_release_buffer(char *bufptr)
 {
-	struct scsi_log_buf *buf;
-	unsigned long idx;
-	int ret;
-
-	buf = this_cpu_ptr(&scsi_format_log);
-	if (bufptr >= buf->buffer &&
-	    bufptr < buf->buffer + SCSI_LOG_SPOOLSIZE) {
-		idx = (bufptr - buf->buffer) / SCSI_LOG_BUFSIZE;
-		ret = test_and_clear_bit(idx, &buf->map);
-		WARN_ON(!ret);
-	}
-	preempt_enable();
+	kfree(bufptr);
 }
 
 static inline const char *scmd_name(const struct scsi_cmnd *scmd)
--- linux-4.4.0.orig/drivers/scsi/scsi_scan.c
+++ linux-4.4.0/drivers/scsi/scsi_scan.c
@@ -217,7 +217,7 @@
 	extern void scsi_requeue_run_queue(struct work_struct *work);
 
 	sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
-		       GFP_ATOMIC);
+		       GFP_KERNEL);
 	if (!sdev)
 		goto out;
 
@@ -314,6 +314,7 @@
 	struct Scsi_Host *shost = dev_to_shost(dev->parent);
 	unsigned long flags;
 
+	BUG_ON(starget->state == STARGET_DEL);
 	starget->state = STARGET_DEL;
 	transport_destroy_device(dev);
 	spin_lock_irqsave(shost->host_lock, flags);
@@ -380,11 +381,12 @@
 		= container_of(kref, struct scsi_target, reap_ref);
 
 	/*
-	 * if we get here and the target is still in the CREATED state that
+	 * if we get here and the target is still in a CREATED state that
 	 * means it was allocated but never made visible (because a scan
 	 * turned up no LUNs), so don't call device_del() on it.
 	 */
-	if (starget->state != STARGET_CREATED) {
+	if ((starget->state != STARGET_CREATED) &&
+	    (starget->state != STARGET_CREATED_REMOVE)) {
 		transport_remove_device(&starget->dev);
 		device_del(&starget->dev);
 	}
@@ -789,7 +791,7 @@
 	 */
 	sdev->inquiry = kmemdup(inq_result,
 				max_t(size_t, sdev->inquiry_len, 36),
-				GFP_ATOMIC);
+				GFP_KERNEL);
 	if (sdev->inquiry == NULL)
 		return SCSI_SCAN_NO_RESPONSE;
 
@@ -961,6 +963,9 @@
 	if (*bflags & BLIST_NO_DIF)
 		sdev->no_dif = 1;
 
+	if (*bflags & BLIST_SYNC_ALUA)
+		sdev->synchronous_alua = 1;
+
 	sdev->eh_timeout = SCSI_DEFAULT_EH_TIMEOUT;
 
 	if (*bflags & BLIST_TRY_VPD_PAGES)
@@ -1083,7 +1088,7 @@
 	if (!sdev)
 		goto out;
 
-	result = kmalloc(result_len, GFP_ATOMIC |
+	result = kmalloc(result_len, GFP_KERNEL |
 			((shost->unchecked_isa_dma) ? __GFP_DMA : 0));
 	if (!result)
 		goto out_free_sdev;
@@ -1458,12 +1463,12 @@
  out_err:
 	kfree(lun_data);
  out:
-	scsi_device_put(sdev);
 	if (scsi_device_created(sdev))
 		/*
 		 * the sdev we used didn't appear in the report luns scan
 		 */
 		__scsi_remove_device(sdev);
+	scsi_device_put(sdev);
 	return ret;
 }
 
@@ -1708,15 +1713,16 @@
  */
 static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
 {
-	struct async_scan_data *data;
+	struct async_scan_data *data = NULL;
 	unsigned long flags;
 
 	if (strncmp(scsi_scan_type, "sync", 4) == 0)
 		return NULL;
 
+	mutex_lock(&shost->scan_mutex);
 	if (shost->async_scan) {
 		shost_printk(KERN_DEBUG, shost, "%s called twice\n", __func__);
-		return NULL;
+		goto err;
 	}
 
 	data = kmalloc(sizeof(*data), GFP_KERNEL);
@@ -1727,7 +1733,6 @@
 		goto err;
 	init_completion(&data->prev_finished);
 
-	mutex_lock(&shost->scan_mutex);
 	spin_lock_irqsave(shost->host_lock, flags);
 	shost->async_scan = 1;
 	spin_unlock_irqrestore(shost->host_lock, flags);
@@ -1742,6 +1747,7 @@
 	return data;
 
  err:
+	mutex_unlock(&shost->scan_mutex);
 	kfree(data);
 	return NULL;
 }
--- linux-4.4.0.orig/drivers/scsi/scsi_sysfs.c
+++ linux-4.4.0/drivers/scsi/scsi_sysfs.c
@@ -678,8 +678,33 @@
 sdev_store_delete(struct device *dev, struct device_attribute *attr,
 		  const char *buf, size_t count)
 {
-	if (device_remove_file_self(dev, attr))
-		scsi_remove_device(to_scsi_device(dev));
+	struct kernfs_node *kn;
+	struct scsi_device *sdev = to_scsi_device(dev);
+
+	/*
+	 * We need to try to get module, avoiding the module been removed
+	 * during delete.
+	 */
+	if (scsi_device_get(sdev))
+		return -ENODEV;
+
+	kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
+	WARN_ON_ONCE(!kn);
+	/*
+	 * Concurrent writes into the "delete" sysfs attribute may trigger
+	 * concurrent calls to device_remove_file() and scsi_remove_device().
+	 * device_remove_file() handles concurrent removal calls by
+	 * serializing these and by ignoring the second and later removal
+	 * attempts.  Concurrent calls of scsi_remove_device() are
+	 * serialized. The second and later calls of scsi_remove_device() are
+	 * ignored because the first call of that function changes the device
+	 * state into SDEV_DEL.
+	 */
+	device_remove_file(dev, attr);
+	scsi_remove_device(sdev);
+	if (kn)
+		sysfs_unbreak_active_protection(kn);
+	scsi_device_put(sdev);
 	return count;
 };
 static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
@@ -1031,10 +1056,6 @@
 	struct request_queue *rq = sdev->request_queue;
 	struct scsi_target *starget = sdev->sdev_target;
 
-	error = scsi_device_set_state(sdev, SDEV_RUNNING);
-	if (error)
-		return error;
-
 	error = scsi_target_add(starget);
 	if (error)
 		return error;
@@ -1058,11 +1079,12 @@
 	}
 
 	error = scsi_dh_add_device(sdev);
-	if (error) {
+	if (error)
+		/*
+		 * device_handler is optional, so any error can be ignored
+		 */
 		sdev_printk(KERN_INFO, sdev,
 				"failed to add device handler: %d\n", error);
-		return error;
-	}
 
 	device_enable_async_suspend(&sdev->sdev_dev);
 	error = device_add(&sdev->sdev_dev);
@@ -1198,10 +1220,16 @@
 restart:
 	spin_lock_irqsave(shost->host_lock, flags);
 	list_for_each_entry(starget, &shost->__targets, siblings) {
-		if (starget->state == STARGET_DEL)
+		if (starget->state == STARGET_DEL ||
+		    starget->state == STARGET_REMOVE ||
+		    starget->state == STARGET_CREATED_REMOVE)
 			continue;
 		if (starget->dev.parent == dev || &starget->dev == dev) {
 			kref_get(&starget->reap_ref);
+			if (starget->state == STARGET_CREATED)
+				starget->state = STARGET_CREATED_REMOVE;
+			else
+				starget->state = STARGET_REMOVE;
 			spin_unlock_irqrestore(shost->host_lock, flags);
 			__scsi_remove_target(starget);
 			scsi_target_reap(starget);
--- linux-4.4.0.orig/drivers/scsi/scsi_trace.c
+++ linux-4.4.0/drivers/scsi/scsi_trace.c
@@ -17,10 +17,11 @@
  */
 #include <linux/kernel.h>
 #include <linux/trace_seq.h>
+#include <asm/unaligned.h>
 #include <trace/events/scsi.h>
 
 #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
-#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
+#define SERVICE_ACTION32(cdb) (get_unaligned_be16(&cdb[8]))
 
 static const char *
 scsi_trace_misc(struct trace_seq *, unsigned char *, int);
@@ -29,15 +30,18 @@
 scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
-	sector_t lba = 0, txlen = 0;
+	u32 lba = 0, txlen;
 
 	lba |= ((cdb[1] & 0x1F) << 16);
 	lba |=  (cdb[2] << 8);
 	lba |=   cdb[3];
-	txlen = cdb[4];
+	/*
+	 * From SBC-2: a TRANSFER LENGTH field set to zero specifies that 256
+	 * logical blocks shall be read (READ(6)) or written (WRITE(6)).
+	 */
+	txlen = cdb[4] ? cdb[4] : 256;
 
-	trace_seq_printf(p, "lba=%llu txlen=%llu",
-			 (unsigned long long)lba, (unsigned long long)txlen);
+	trace_seq_printf(p, "lba=%u txlen=%u", lba, txlen);
 	trace_seq_putc(p, 0);
 
 	return ret;
@@ -47,17 +51,12 @@
 scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
-	sector_t lba = 0, txlen = 0;
+	u32 lba, txlen;
 
-	lba |= (cdb[2] << 24);
-	lba |= (cdb[3] << 16);
-	lba |= (cdb[4] << 8);
-	lba |=  cdb[5];
-	txlen |= (cdb[7] << 8);
-	txlen |=  cdb[8];
+	lba = get_unaligned_be32(&cdb[2]);
+	txlen = get_unaligned_be16(&cdb[7]);
 
-	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
-			 (unsigned long long)lba, (unsigned long long)txlen,
+	trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen,
 			 cdb[1] >> 5);
 
 	if (cdb[0] == WRITE_SAME)
@@ -72,19 +71,12 @@
 scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
-	sector_t lba = 0, txlen = 0;
+	u32 lba, txlen;
 
-	lba |= (cdb[2] << 24);
-	lba |= (cdb[3] << 16);
-	lba |= (cdb[4] << 8);
-	lba |=  cdb[5];
-	txlen |= (cdb[6] << 24);
-	txlen |= (cdb[7] << 16);
-	txlen |= (cdb[8] << 8);
-	txlen |=  cdb[9];
+	lba = get_unaligned_be32(&cdb[2]);
+	txlen = get_unaligned_be32(&cdb[6]);
 
-	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
-			 (unsigned long long)lba, (unsigned long long)txlen,
+	trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen,
 			 cdb[1] >> 5);
 	trace_seq_putc(p, 0);
 
@@ -95,23 +87,13 @@
 scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
-	sector_t lba = 0, txlen = 0;
+	u64 lba;
+	u32 txlen;
 
-	lba |= ((u64)cdb[2] << 56);
-	lba |= ((u64)cdb[3] << 48);
-	lba |= ((u64)cdb[4] << 40);
-	lba |= ((u64)cdb[5] << 32);
-	lba |= (cdb[6] << 24);
-	lba |= (cdb[7] << 16);
-	lba |= (cdb[8] << 8);
-	lba |=  cdb[9];
-	txlen |= (cdb[10] << 24);
-	txlen |= (cdb[11] << 16);
-	txlen |= (cdb[12] << 8);
-	txlen |=  cdb[13];
+	lba = get_unaligned_be64(&cdb[2]);
+	txlen = get_unaligned_be32(&cdb[10]);
 
-	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
-			 (unsigned long long)lba, (unsigned long long)txlen,
+	trace_seq_printf(p, "lba=%llu txlen=%u protect=%u", lba, txlen,
 			 cdb[1] >> 5);
 
 	if (cdb[0] == WRITE_SAME_16)
@@ -126,8 +108,8 @@
 scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
 {
 	const char *ret = trace_seq_buffer_ptr(p), *cmd;
-	sector_t lba = 0, txlen = 0;
-	u32 ei_lbrt = 0;
+	u64 lba;
+	u32 ei_lbrt, txlen;
 
 	switch (SERVICE_ACTION32(cdb)) {
 	case READ_32:
@@ -147,26 +129,12 @@
 		goto out;
 	}
 
-	lba |= ((u64)cdb[12] << 56);
-	lba |= ((u64)cdb[13] << 48);
-	lba |= ((u64)cdb[14] << 40);
-	lba |= ((u64)cdb[15] << 32);
-	lba |= (cdb[16] << 24);
-	lba |= (cdb[17] << 16);
-	lba |= (cdb[18] << 8);
-	lba |=  cdb[19];
-	ei_lbrt |= (cdb[20] << 24);
-	ei_lbrt |= (cdb[21] << 16);
-	ei_lbrt |= (cdb[22] << 8);
-	ei_lbrt |=  cdb[23];
-	txlen |= (cdb[28] << 24);
-	txlen |= (cdb[29] << 16);
-	txlen |= (cdb[30] << 8);
-	txlen |=  cdb[31];
-
-	trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
-			 cmd, (unsigned long long)lba,
-			 (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
+	lba = get_unaligned_be64(&cdb[12]);
+	ei_lbrt = get_unaligned_be32(&cdb[20]);
+	txlen = get_unaligned_be32(&cdb[28]);
+
+	trace_seq_printf(p, "%s_32 lba=%llu txlen=%u protect=%u ei_lbrt=%u",
+			 cmd, lba, txlen, cdb[10] >> 5, ei_lbrt);
 
 	if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
 		trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
@@ -181,7 +149,7 @@
 scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
-	unsigned int regions = cdb[7] << 8 | cdb[8];
+	unsigned int regions = get_unaligned_be16(&cdb[7]);
 
 	trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
 	trace_seq_putc(p, 0);
@@ -193,8 +161,8 @@
 scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
 {
 	const char *ret = trace_seq_buffer_ptr(p), *cmd;
-	sector_t lba = 0;
-	u32 alloc_len = 0;
+	u64 lba;
+	u32 alloc_len;
 
 	switch (SERVICE_ACTION16(cdb)) {
 	case SAI_READ_CAPACITY_16:
@@ -208,21 +176,10 @@
 		goto out;
 	}
 
-	lba |= ((u64)cdb[2] << 56);
-	lba |= ((u64)cdb[3] << 48);
-	lba |= ((u64)cdb[4] << 40);
-	lba |= ((u64)cdb[5] << 32);
-	lba |= (cdb[6] << 24);
-	lba |= (cdb[7] << 16);
-	lba |= (cdb[8] << 8);
-	lba |=  cdb[9];
-	alloc_len |= (cdb[10] << 24);
-	alloc_len |= (cdb[11] << 16);
-	alloc_len |= (cdb[12] << 8);
-	alloc_len |=  cdb[13];
+	lba = get_unaligned_be64(&cdb[2]);
+	alloc_len = get_unaligned_be32(&cdb[10]);
 
-	trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
-			 (unsigned long long)lba, alloc_len);
+	trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, lba, alloc_len);
 
 out:
 	trace_seq_putc(p, 0);
--- linux-4.4.0.orig/drivers/scsi/scsi_transport_iscsi.c
+++ linux-4.4.0/drivers/scsi/scsi_transport_iscsi.c
@@ -37,6 +37,8 @@
 
 #define ISCSI_TRANSPORT_VERSION "2.0-870"
 
+#define ISCSI_SEND_MAX_ALLOWED  10
+
 static int dbg_session;
 module_param_named(debug_session, dbg_session, int,
 		   S_IRUGO | S_IWUSR);
@@ -117,7 +119,11 @@
 		      char *buf)
 {
 	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-	return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	return sysfs_emit(buf, "%llu\n",
+		  (unsigned long long)iscsi_handle(priv->iscsi_transport));
 }
 static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
 
@@ -127,7 +133,7 @@
 		      struct device_attribute *attr,char *buf)		\
 {									\
 	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);	\
-	return sprintf(buf, format"\n", priv->iscsi_transport->name);	\
+	return sysfs_emit(buf, format"\n", priv->iscsi_transport->name);\
 }									\
 static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
 
@@ -168,7 +174,7 @@
 show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
-	return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
+	return sysfs_emit(buf, "%llu\n", (unsigned long long) ep->id);
 }
 static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
 
@@ -2012,7 +2018,7 @@
 	if (session->target_id == ISCSI_MAX_TARGET) {
 		spin_unlock_irqrestore(&session->lock, flags);
 		mutex_unlock(&ihost->mutex);
-		return;
+		goto unbind_session_exit;
 	}
 
 	target_id = session->target_id;
@@ -2024,6 +2030,8 @@
 		ida_simple_remove(&iscsi_sess_ida, target_id);
 
 	scsi_remove_target(&session->dev);
+
+unbind_session_exit:
 	iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
 	ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
 }
@@ -2779,6 +2787,9 @@
 	struct iscsi_cls_session *session;
 	int err = 0, value = 0;
 
+	if (ev->u.set_param.len > PAGE_SIZE)
+		return -EINVAL;
+
 	session = iscsi_session_lookup(ev->u.set_param.sid);
 	conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
 	if (!conn || !session)
@@ -2926,6 +2937,9 @@
 	if (!transport->set_host_param)
 		return -ENOSYS;
 
+	if (ev->u.set_host_param.len > PAGE_SIZE)
+		return -EINVAL;
+
 	shost = scsi_host_lookup(ev->u.set_host_param.host_no);
 	if (!shost) {
 		printk(KERN_ERR "set_host_param could not find host no %u\n",
@@ -2963,6 +2977,24 @@
 	return err;
 }
 
+static int iscsi_session_has_conns(int sid)
+{
+	struct iscsi_cls_conn *conn;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&connlock, flags);
+	list_for_each_entry(conn, &connlist, conn_list) {
+		if (iscsi_conn_get_sid(conn) == sid) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&connlock, flags);
+
+	return found;
+}
+
 static int
 iscsi_set_iface_params(struct iscsi_transport *transport,
 		       struct iscsi_uevent *ev, uint32_t len)
@@ -3170,7 +3202,7 @@
 		pr_err("%s could not find host no %u\n",
 		       __func__, ev->u.set_flashnode.host_no);
 		err = -ENODEV;
-		goto put_host;
+		goto exit_set_fnode;
 	}
 
 	idx = ev->u.set_flashnode.flashnode_idx;
@@ -3494,6 +3526,7 @@
 iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 {
 	int err = 0;
+	u32 pdu_len;
 	struct iscsi_uevent *ev = nlmsg_data(nlh);
 	struct iscsi_transport *transport = NULL;
 	struct iscsi_internal *priv;
@@ -3501,6 +3534,9 @@
 	struct iscsi_cls_conn *conn;
 	struct iscsi_endpoint *ep = NULL;
 
+	if (!netlink_capable(skb, CAP_SYS_ADMIN))
+		return -EPERM;
+
 	if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
 		*group = ISCSI_NL_GRP_UIP;
 	else
@@ -3537,10 +3573,12 @@
 		break;
 	case ISCSI_UEVENT_DESTROY_SESSION:
 		session = iscsi_session_lookup(ev->u.d_session.sid);
-		if (session)
-			transport->destroy_session(session);
-		else
+		if (!session)
 			err = -EINVAL;
+		else if (iscsi_session_has_conns(ev->u.d_session.sid))
+			err = -EBUSY;
+		else
+			transport->destroy_session(session);
 		break;
 	case ISCSI_UEVENT_UNBIND_SESSION:
 		session = iscsi_session_lookup(ev->u.d_session.sid);
@@ -3604,6 +3642,14 @@
 			err = -EINVAL;
 		break;
 	case ISCSI_UEVENT_SEND_PDU:
+		pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev);
+
+		if ((ev->u.send_pdu.hdr_size > pdu_len) ||
+		    (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) {
+			err = -EINVAL;
+			break;
+		}
+
 		conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
 		if (conn)
 			ev->r.retcode =	transport->send_pdu(conn,
@@ -3695,9 +3741,10 @@
 		struct nlmsghdr	*nlh;
 		struct iscsi_uevent *ev;
 		uint32_t group;
+		int retries = ISCSI_SEND_MAX_ALLOWED;
 
 		nlh = nlmsg_hdr(skb);
-		if (nlh->nlmsg_len < sizeof(*nlh) ||
+		if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) ||
 		    skb->len < nlh->nlmsg_len) {
 			break;
 		}
@@ -3725,6 +3772,10 @@
 				break;
 			err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
 				nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
+			if (err == -EAGAIN && --retries < 0) {
+				printk(KERN_WARNING "Send reply failed, error %d\n", err);
+				break;
+			}
 		} while (err < 0 && err != -ECONNREFUSED && err != -ESRCH);
 		skb_pull(skb, rlen);
 	}
@@ -4003,7 +4054,7 @@
 			char *buf)
 {
 	struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-	return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
+	return sysfs_emit(buf, "%s\n", iscsi_session_state_name(session->state));
 }
 static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
 			NULL);
@@ -4012,7 +4063,7 @@
 			char *buf)
 {
 	struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-	return sprintf(buf, "%d\n", session->creator);
+	return sysfs_emit(buf, "%d\n", session->creator);
 }
 static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator,
 			NULL);
@@ -4021,7 +4072,7 @@
 			    char *buf)
 {
 	struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-	return sprintf(buf, "%d\n", session->target_id);
+	return sysfs_emit(buf, "%d\n", session->target_id);
 }
 static ISCSI_CLASS_ATTR(priv_sess, target_id, S_IRUGO,
 			show_priv_session_target_id, NULL);
@@ -4034,8 +4085,8 @@
 	struct iscsi_cls_session *session = 				\
 			iscsi_dev_to_session(dev->parent);		\
 	if (session->field == -1)					\
-		return sprintf(buf, "off\n");				\
-	return sprintf(buf, format"\n", session->field);		\
+		return sysfs_emit(buf, "off\n");			\
+	return sysfs_emit(buf, format"\n", session->field);		\
 }
 
 #define iscsi_priv_session_attr_store(field)				\
--- linux-4.4.0.orig/drivers/scsi/scsi_transport_sas.c
+++ linux-4.4.0/drivers/scsi/scsi_transport_sas.c
@@ -367,6 +367,20 @@
 EXPORT_SYMBOL(sas_remove_host);
 
 /**
+ * sas_get_address - return the SAS address of the device
+ * @sdev: scsi device
+ *
+ * Returns the SAS address of the scsi device
+ */
+u64 sas_get_address(struct scsi_device *sdev)
+{
+	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
+
+	return rdev->rphy.identify.sas_address;
+}
+EXPORT_SYMBOL(sas_get_address);
+
+/**
  * sas_tlr_supported - checking TLR bit in vpd 0x90
  * @sdev: scsi device struct
  *
--- linux-4.4.0.orig/drivers/scsi/scsi_transport_spi.c
+++ linux-4.4.0/drivers/scsi/scsi_transport_spi.c
@@ -353,7 +353,7 @@
 	struct spi_transport_attrs *tp					\
 		= (struct spi_transport_attrs *)&starget->starget_data;	\
 									\
-	if (i->f->set_##field)						\
+	if (!i->f->set_##field)						\
 		return -EINVAL;						\
 	val = simple_strtoul(buf, NULL, 0);				\
 	if (val > tp->max_##field)					\
--- linux-4.4.0.orig/drivers/scsi/scsi_transport_srp.c
+++ linux-4.4.0/drivers/scsi/scsi_transport_srp.c
@@ -52,6 +52,8 @@
 	struct transport_container rport_attr_cont;
 };
 
+static int scsi_is_srp_rport(const struct device *dev);
+
 #define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t)
 
 #define	dev_to_rport(d)	container_of(d, struct srp_rport, dev)
@@ -61,9 +63,24 @@
 	return dev_to_shost(r->dev.parent);
 }
 
+static int find_child_rport(struct device *dev, void *data)
+{
+	struct device **child = data;
+
+	if (scsi_is_srp_rport(dev)) {
+		WARN_ON_ONCE(*child);
+		*child = dev;
+	}
+	return 0;
+}
+
 static inline struct srp_rport *shost_to_rport(struct Scsi_Host *shost)
 {
-	return transport_class_to_srp_rport(&shost->shost_gendev);
+	struct device *child = NULL;
+
+	WARN_ON_ONCE(device_for_each_child(&shost->shost_gendev, &child,
+					   find_child_rport) < 0);
+	return child ? dev_to_rport(child) : NULL;
 }
 
 /**
@@ -637,7 +654,8 @@
 	struct srp_rport *rport = shost_to_rport(shost);
 
 	pr_debug("timeout for sdev %s\n", dev_name(&sdev->sdev_gendev));
-	return rport->fast_io_fail_tmo < 0 && rport->dev_loss_tmo < 0 &&
+	return rport && rport->fast_io_fail_tmo < 0 &&
+		rport->dev_loss_tmo < 0 &&
 		i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ?
 		BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED;
 }
--- linux-4.4.0.orig/drivers/scsi/sd.c
+++ linux-4.4.0/drivers/scsi/sd.c
@@ -207,6 +207,12 @@
 	sp = buffer_data[0] & 0x80 ? 1 : 0;
 	buffer_data[0] &= ~0x80;
 
+	/*
+	 * Ensure WP, DPOFUA, and RESERVED fields are cleared in
+	 * received mode parameter buffer before doing MODE SELECT.
+	 */
+	data.device_specific = 0;
+
 	if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
 			     SD_MAX_RETRIES, &data, &sshdr)) {
 		if (scsi_sense_valid(&sshdr))
@@ -233,11 +239,15 @@
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct scsi_device *sdp = sdkp->device;
+	bool v;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	sdp->manage_start_stop = simple_strtoul(buf, NULL, 10);
+	if (kstrtobool(buf, &v))
+		return -EINVAL;
+
+	sdp->manage_start_stop = v;
 
 	return count;
 }
@@ -255,6 +265,7 @@
 allow_restart_store(struct device *dev, struct device_attribute *attr,
 		    const char *buf, size_t count)
 {
+	bool v;
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct scsi_device *sdp = sdkp->device;
 
@@ -264,7 +275,10 @@
 	if (sdp->type != TYPE_DISK)
 		return -EINVAL;
 
-	sdp->allow_restart = simple_strtoul(buf, NULL, 10);
+	if (kstrtobool(buf, &v))
+		return -EINVAL;
+
+	sdp->allow_restart = v;
 
 	return count;
 }
@@ -648,7 +662,7 @@
 	 */
 	if (sdkp->lbprz) {
 		q->limits.discard_alignment = 0;
-		q->limits.discard_granularity = 1;
+		q->limits.discard_granularity = logical_block_size;
 	} else {
 		q->limits.discard_alignment = sdkp->unmap_alignment *
 			logical_block_size;
@@ -1262,11 +1276,6 @@
 			scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
 	}
 
-	/*
-	 * XXX and what if there are packets in flight and this close()
-	 * XXX is followed by a "rmmod sd_mod"?
-	 */
-
 	scsi_disk_put(sdkp);
 }
 
@@ -1275,18 +1284,19 @@
 	struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
 	struct scsi_device *sdp = sdkp->device;
 	struct Scsi_Host *host = sdp->host;
+	sector_t capacity = logical_to_sectors(sdp, sdkp->capacity);
 	int diskinfo[4];
 
 	/* default to most commonly used values */
-        diskinfo[0] = 0x40;	/* 1 << 6 */
-       	diskinfo[1] = 0x20;	/* 1 << 5 */
-       	diskinfo[2] = sdkp->capacity >> 11;
-	
+	diskinfo[0] = 0x40;	/* 1 << 6 */
+	diskinfo[1] = 0x20;	/* 1 << 5 */
+	diskinfo[2] = capacity >> 11;
+
 	/* override with calculated, extended default, or driver values */
 	if (host->hostt->bios_param)
-		host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo);
+		host->hostt->bios_param(sdp, bdev, capacity, diskinfo);
 	else
-		scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
+		scsicam_bios_param(bdev, capacity, diskinfo);
 
 	geo->heads = diskinfo[0];
 	geo->sectors = diskinfo[1];
@@ -1397,11 +1407,15 @@
  **/
 static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
 {
-	struct scsi_disk *sdkp = scsi_disk(disk);
-	struct scsi_device *sdp = sdkp->device;
+	struct scsi_disk *sdkp = scsi_disk_get(disk);
+	struct scsi_device *sdp;
 	struct scsi_sense_hdr *sshdr = NULL;
 	int retval;
 
+	if (!sdkp)
+		return 0;
+
+	sdp = sdkp->device;
 	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n"));
 
 	/*
@@ -1458,6 +1472,7 @@
 	kfree(sshdr);
 	retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
 	sdp->changed = 0;
+	scsi_disk_put(sdkp);
 	return retval;
 }
 
@@ -1915,6 +1930,8 @@
 				break;	/* standby */
 			if (sshdr.asc == 4 && sshdr.ascq == 0xc)
 				break;	/* unavailable */
+			if (sshdr.asc == 4 && sshdr.ascq == 0x1b)
+				break;	/* sanitize in progress */
 			/*
 			 * Issue command to spin up drive when not ready
 			 */
@@ -1981,8 +1998,10 @@
 	u8 type;
 	int ret = 0;
 
-	if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0)
+	if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) {
+		sdkp->protection_type = 0;
 		return ret;
+	}
 
 	type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
 
@@ -2045,6 +2064,22 @@
 
 #define READ_CAPACITY_RETRIES_ON_RESET	10
 
+/*
+ * Ensure that we don't overflow sector_t when CONFIG_LBDAF is not set
+ * and the reported logical block size is bigger than 512 bytes. Note
+ * that last_sector is a u64 and therefore logical_to_sectors() is not
+ * applicable.
+ */
+static bool sd_addressable_capacity(u64 lba, unsigned int sector_size)
+{
+	u64 last_sector = (lba + 1ULL) << (ilog2(sector_size) - 9);
+
+	if (sizeof(sector_t) == 4 && last_sector > U32_MAX)
+		return false;
+
+	return true;
+}
+
 static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
 						unsigned char *buffer)
 {
@@ -2110,7 +2145,7 @@
 		return -ENODEV;
 	}
 
-	if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) {
+	if (!sd_addressable_capacity(lba, sector_size)) {
 		sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
 			"kernel compiled with support for large block "
 			"devices.\n");
@@ -2196,7 +2231,7 @@
 		return sector_size;
 	}
 
-	if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) {
+	if (!sd_addressable_capacity(lba, sector_size)) {
 		sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
 			"kernel compiled with support for large block "
 			"devices.\n");
@@ -2337,14 +2372,6 @@
 	if (sdkp->capacity > 0xffffffff)
 		sdp->use_16_for_rw = 1;
 
-	/* Rescale capacity to 512-byte units */
-	if (sector_size == 4096)
-		sdkp->capacity <<= 3;
-	else if (sector_size == 2048)
-		sdkp->capacity <<= 2;
-	else if (sector_size == 1024)
-		sdkp->capacity <<= 1;
-
 	blk_queue_physical_block_size(sdp->request_queue,
 				      sdkp->physical_block_size);
 	sdkp->device->sector_size = sector_size;
@@ -2552,7 +2579,8 @@
 		if (sdp->broken_fua) {
 			sd_first_printk(KERN_NOTICE, sdkp, "Disabling FUA\n");
 			sdkp->DPOFUA = 0;
-		} else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
+		} else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw &&
+			   !sdkp->device->use_16_for_rw) {
 			sd_first_printk(KERN_NOTICE, sdkp,
 				  "Uses READ/WRITE(6), disabling FUA\n");
 			sdkp->DPOFUA = 0;
@@ -2812,11 +2840,6 @@
 	return 0;
 }
 
-static inline u32 logical_to_sectors(struct scsi_device *sdev, u32 blocks)
-{
-	return blocks << (ilog2(sdev->sector_size) - 9);
-}
-
 /**
  *	sd_revalidate_disk - called the first time a new disk is seen,
  *	performs disk spin up, read_capacity, etc.
@@ -2868,8 +2891,6 @@
 		sd_read_write_same(sdkp, buffer);
 	}
 
-	sdkp->first_scan = 0;
-
 	/*
 	 * We now have all cache related info, determine how we deal
 	 * with flush requests.
@@ -2884,23 +2905,37 @@
 	q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max);
 
 	/*
-	 * Use the device's preferred I/O size for reads and writes
+	 * Determine the device's preferred I/O size for reads and writes
 	 * unless the reported value is unreasonably small, large, or
 	 * garbage.
 	 */
 	if (sdkp->opt_xfer_blocks &&
 	    sdkp->opt_xfer_blocks <= dev_max &&
 	    sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS &&
-	    sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE)
-		rw_max = q->limits.io_opt =
-			logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
-	else
-		rw_max = BLK_DEF_MAX_SECTORS;
+	    logical_to_bytes(sdp, sdkp->opt_xfer_blocks) >= PAGE_CACHE_SIZE) {
+		q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks);
+		rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
+	} else {
+		q->limits.io_opt = 0;
+		rw_max = min_not_zero(logical_to_sectors(sdp, dev_max),
+				      (sector_t)BLK_DEF_MAX_SECTORS);
+	}
+
+	/* Do not exceed controller limit */
+	rw_max = min(rw_max, queue_max_hw_sectors(q));
 
-	/* Combine with controller limits */
-	q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q));
+	/*
+	 * Only update max_sectors if previously unset or if the current value
+	 * exceeds the capabilities of the hardware.
+	 */
+	if (sdkp->first_scan ||
+	    q->limits.max_sectors > q->limits.max_dev_sectors ||
+	    q->limits.max_sectors > q->limits.max_hw_sectors)
+		q->limits.max_sectors = rw_max;
+
+	sdkp->first_scan = 0;
 
-	set_capacity(disk, sdkp->capacity);
+	set_capacity(disk, logical_to_sectors(sdp, sdkp->capacity));
 	sd_config_write_same(sdkp);
 	kfree(buffer);
 
@@ -3190,11 +3225,23 @@
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct gendisk *disk = sdkp->disk;
-	
+	struct request_queue *q = disk->queue;
+
 	spin_lock(&sd_index_lock);
 	ida_remove(&sd_index_ida, sdkp->index);
 	spin_unlock(&sd_index_lock);
 
+	/*
+	 * Wait until all requests that are in progress have completed.
+	 * This is necessary to avoid that e.g. scsi_end_request() crashes
+	 * due to clearing the disk->private_data pointer. Wait from inside
+	 * scsi_disk_release() instead of from sd_release() to avoid that
+	 * freezing and unfreezing the request queue affects user space I/O
+	 * in case multiple processes open a /dev/sd... node concurrently.
+	 */
+	blk_mq_freeze_queue(q);
+	blk_mq_unfreeze_queue(q);
+
 	disk->private_data = NULL;
 	put_disk(disk);
 	put_device(&sdkp->device->sdev_gendev);
@@ -3268,8 +3315,8 @@
 	struct scsi_disk *sdkp = dev_get_drvdata(dev);
 	int ret = 0;
 
-	if (!sdkp)
-		return 0;	/* this can happen */
+	if (!sdkp)	/* E.g.: runtime suspend following sd_remove() */
+		return 0;
 
 	if (sdkp->WCE && sdkp->media_present) {
 		sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
@@ -3308,6 +3355,9 @@
 {
 	struct scsi_disk *sdkp = dev_get_drvdata(dev);
 
+	if (!sdkp)	/* E.g.: runtime resume at the start of sd_probe() */
+		return 0;
+
 	if (!sdkp->device->manage_start_stop)
 		return 0;
 
--- linux-4.4.0.orig/drivers/scsi/sd.h
+++ linux-4.4.0/drivers/scsi/sd.h
@@ -65,7 +65,7 @@
 	struct device	dev;
 	struct gendisk	*disk;
 	atomic_t	openers;
-	sector_t	capacity;	/* size in 512-byte sectors */
+	sector_t	capacity;	/* size in logical blocks */
 	u32		max_xfer_blocks;
 	u32		opt_xfer_blocks;
 	u32		max_ws_blocks;
@@ -146,6 +146,16 @@
 	return 0;
 }
 
+static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blocks)
+{
+	return blocks << (ilog2(sdev->sector_size) - 9);
+}
+
+static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t blocks)
+{
+	return blocks * sdev->sector_size;
+}
+
 /*
  * A DIF-capable target device can be formatted with different
  * protection schemes.  Currently 0 through 3 are defined:
--- linux-4.4.0.orig/drivers/scsi/ses.c
+++ linux-4.4.0/drivers/scsi/ses.c
@@ -34,6 +34,8 @@
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_host.h>
 
+#include <scsi/scsi_transport_sas.h>
+
 struct ses_device {
 	unsigned char *page1;
 	unsigned char *page1_types;
@@ -546,7 +548,6 @@
 					ecomp = &edev->component[components++];
 
 				if (!IS_ERR(ecomp)) {
-					ses_get_power_status(edev, ecomp);
 					if (addl_desc_ptr)
 						ses_process_descriptor(
 							ecomp,
@@ -579,31 +580,15 @@
 static void ses_match_to_enclosure(struct enclosure_device *edev,
 				   struct scsi_device *sdev)
 {
-	unsigned char *desc;
 	struct efd efd = {
 		.addr = 0,
 	};
 
 	ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
 
-	if (!sdev->vpd_pg83_len)
-		return;
+	if (scsi_is_sas_rphy(sdev->sdev_target->dev.parent))
+		efd.addr = sas_get_address(sdev);
 
-	desc = sdev->vpd_pg83 + 4;
-	while (desc < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
-		enum scsi_protocol proto = desc[0] >> 4;
-		u8 code_set = desc[0] & 0x0f;
-		u8 piv = desc[1] & 0x80;
-		u8 assoc = (desc[1] & 0x30) >> 4;
-		u8 type = desc[1] & 0x0f;
-		u8 len = desc[3];
-
-		if (piv && code_set == 1 && assoc == 1
-		    && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8)
-			efd.addr = get_unaligned_be64(&desc[4]);
-
-		desc += len + 4;
-	}
 	if (efd.addr) {
 		efd.dev = &sdev->sdev_gendev;
 
--- linux-4.4.0.orig/drivers/scsi/sg.c
+++ linux-4.4.0/drivers/scsi/sg.c
@@ -51,6 +51,7 @@
 #include <linux/atomic.h>
 #include <linux/ratelimit.h>
 #include <linux/uio.h>
+#include <linux/cred.h> /* for sg_check_file_access() */
 
 #include "scsi.h"
 #include <scsi/scsi_dbg.h>
@@ -133,7 +134,7 @@
 struct sg_fd;
 
 typedef struct sg_request {	/* SG_MAX_QUEUE requests outstanding per file */
-	struct sg_request *nextrp;	/* NULL -> tail request (slist) */
+	struct list_head entry;	/* list entry */
 	struct sg_fd *parentfp;	/* NULL -> not in use */
 	Sg_scatter_hold data;	/* hold buffer, perhaps scatter list */
 	sg_io_hdr_t header;	/* scsi command+info, see <scsi/sg.h> */
@@ -153,19 +154,19 @@
 	struct sg_device *parentdp;	/* owning device */
 	wait_queue_head_t read_wait;	/* queue read until command done */
 	rwlock_t rq_list_lock;	/* protect access to list in req_arr */
+	struct mutex f_mutex;	/* protect against changes in this fd */
 	int timeout;		/* defaults to SG_DEFAULT_TIMEOUT      */
 	int timeout_user;	/* defaults to SG_DEFAULT_TIMEOUT_USER */
 	Sg_scatter_hold reserve;	/* buffer held for this file descriptor */
-	unsigned save_scat_len;	/* original length of trunc. scat. element */
-	Sg_request *headrp;	/* head of request slist, NULL->empty */
+	struct list_head rq_list; /* head of request list */
 	struct fasync_struct *async_qp;	/* used by asynchronous notification */
 	Sg_request req_arr[SG_MAX_QUEUE];	/* used as singly-linked list */
-	char low_dma;		/* as in parent but possibly overridden to 1 */
 	char force_packid;	/* 1 -> pack_id input to read(), 0 -> ignored */
 	char cmd_q;		/* 1 -> allow command queuing, 0 -> don't */
 	unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
 	char keep_orphan;	/* 0 -> drop orphan (def), 1 -> keep for read() */
 	char mmap_called;	/* 0 -> mmap() never called on this fd */
+	char res_in_use;	/* 1 -> 'reserve' array in use */
 	struct kref f_ref;
 	struct execute_work ew;
 } Sg_fd;
@@ -209,7 +210,6 @@
 static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
 static Sg_request *sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
-static int sg_res_in_use(Sg_fd * sfp);
 static Sg_device *sg_get_dev(int dev);
 static void sg_device_destroy(struct kref *kref);
 
@@ -222,6 +222,33 @@
 	sdev_prefix_printk(prefix, (sdp)->device,		\
 			   (sdp)->disk->disk_name, fmt, ##a)
 
+/*
+ * The SCSI interfaces that use read() and write() as an asynchronous variant of
+ * ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways
+ * to trigger read() and write() calls from various contexts with elevated
+ * privileges. This can lead to kernel memory corruption (e.g. if these
+ * interfaces are called through splice()) and privilege escalation inside
+ * userspace (e.g. if a process with access to such a device passes a file
+ * descriptor to a SUID binary as stdin/stdout/stderr).
+ *
+ * This function provides protection for the legacy API by restricting the
+ * calling context.
+ */
+static int sg_check_file_access(struct file *filp, const char *caller)
+{
+	if (filp->f_cred != current_real_cred()) {
+		pr_err_once("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n",
+			caller, task_tgid_vnr(current), current->comm);
+		return -EPERM;
+	}
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		pr_err_once("%s: process %d (%s) called from kernel context, this is not allowed.\n",
+			caller, task_tgid_vnr(current), current->comm);
+		return -EACCES;
+	}
+	return 0;
+}
+
 static int sg_allow_access(struct file *filp, unsigned char *cmd)
 {
 	struct sg_fd *sfp = filp->private_data;
@@ -380,7 +407,6 @@
 
 	mutex_lock(&sdp->open_rel_lock);
 	scsi_autopm_put_device(sdp->device);
-	kref_put(&sfp->f_ref, sg_remove_sfp);
 	sdp->open_cnt--;
 
 	/* possibly many open()s waiting on exlude clearing, start many;
@@ -392,6 +418,7 @@
 		wake_up_interruptible(&sdp->open_wait);
 	}
 	mutex_unlock(&sdp->open_rel_lock);
+	kref_put(&sfp->f_ref, sg_remove_sfp);
 	return 0;
 }
 
@@ -406,6 +433,14 @@
 	struct sg_header *old_hdr = NULL;
 	int retval = 0;
 
+	/*
+	 * This could cause a response to be stranded. Close the associated
+	 * file descriptor to free up any resources being held.
+	 */
+	retval = sg_check_file_access(filp, __func__);
+	if (retval)
+		return retval;
+
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
@@ -536,6 +571,7 @@
 	} else
 		count = (old_hdr->result == 0) ? 0 : -EIO;
 	sg_finish_rem_req(srp);
+	sg_remove_request(sfp, srp);
 	retval = count;
 free_old_hdr:
 	kfree(old_hdr);
@@ -576,6 +612,7 @@
 	}
 err_out:
 	err2 = sg_finish_rem_req(srp);
+	sg_remove_request(sfp, srp);
 	return err ? : err2 ? : count;
 }
 
@@ -591,6 +628,11 @@
 	struct sg_header old_hdr;
 	sg_io_hdr_t *hp;
 	unsigned char cmnd[SG_MAX_CDB_SIZE];
+	int retval;
+
+	retval = sg_check_file_access(filp, __func__);
+	if (retval)
+		return retval;
 
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
@@ -622,6 +664,7 @@
 	}
 	buf += SZ_SG_HEADER;
 	__get_user(opcode, buf);
+	mutex_lock(&sfp->f_mutex);
 	if (sfp->next_cmd_len > 0) {
 		cmd_size = sfp->next_cmd_len;
 		sfp->next_cmd_len = 0;	/* reset so only this write() effected */
@@ -630,6 +673,7 @@
 		if ((opcode >= 0xc0) && old_hdr.twelve_byte)
 			cmd_size = 12;
 	}
+	mutex_unlock(&sfp->f_mutex);
 	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
 		"sg_write:   scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size));
 /* Determine buffer size.  */
@@ -652,7 +696,8 @@
 	else
 		hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
 	hp->dxfer_len = mxsize;
-	if (hp->dxfer_direction == SG_DXFER_TO_DEV)
+	if ((hp->dxfer_direction == SG_DXFER_TO_DEV) ||
+	    (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV))
 		hp->dxferp = (char __user *)buf + cmd_size;
 	else
 		hp->dxferp = NULL;
@@ -661,26 +706,24 @@
 	hp->flags = input_size;	/* structure abuse ... */
 	hp->pack_id = old_hdr.pack_id;
 	hp->usr_ptr = NULL;
-	if (__copy_from_user(cmnd, buf, cmd_size))
+	if (__copy_from_user(cmnd, buf, cmd_size)) {
+		sg_remove_request(sfp, srp);
 		return -EFAULT;
+	}
 	/*
 	 * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV,
 	 * but is is possible that the app intended SG_DXFER_TO_DEV, because there
 	 * is a non-zero input_size, so emit a warning.
 	 */
 	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
-		static char cmd[TASK_COMM_LEN];
-		if (strcmp(current->comm, cmd)) {
-			printk_ratelimited(KERN_WARNING
-					   "sg_write: data in/out %d/%d bytes "
-					   "for SCSI command 0x%x-- guessing "
-					   "data in;\n   program %s not setting "
-					   "count and/or reply_len properly\n",
-					   old_hdr.reply_len - (int)SZ_SG_HEADER,
-					   input_size, (unsigned int) cmnd[0],
-					   current->comm);
-			strcpy(cmd, current->comm);
-		}
+		printk_ratelimited(KERN_WARNING
+				   "sg_write: data in/out %d/%d bytes "
+				   "for SCSI command 0x%x-- guessing "
+				   "data in;\n   program %s not setting "
+				   "count and/or reply_len properly\n",
+				   old_hdr.reply_len - (int)SZ_SG_HEADER,
+				   input_size, (unsigned int) cmnd[0],
+				   current->comm);
 	}
 	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
 	return (k < 0) ? k : count;
@@ -728,7 +771,7 @@
 			sg_remove_request(sfp, srp);
 			return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
 		}
-		if (sg_res_in_use(sfp)) {
+		if (sfp->res_in_use) {
 			sg_remove_request(sfp, srp);
 			return -EBUSY;	/* reserve buffer already being used */
 		}
@@ -779,11 +822,17 @@
 			"sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
 			(int) cmnd[0], (int) hp->cmd_len));
 
+	if (hp->dxfer_len >= SZ_256M) {
+		sg_remove_request(sfp, srp);
+		return -EINVAL;
+	}
+
 	k = sg_start_req(srp, cmnd);
 	if (k) {
 		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
 			"sg_common_write: start_req err=%d\n", k));
 		sg_finish_rem_req(srp);
+		sg_remove_request(sfp, srp);
 		return k;	/* probably out of space --> ENOMEM */
 	}
 	if (atomic_read(&sdp->detaching)) {
@@ -796,6 +845,7 @@
 		}
 
 		sg_finish_rem_req(srp);
+		sg_remove_request(sfp, srp);
 		return -ENODEV;
 	}
 
@@ -833,6 +883,39 @@
 	return max_sectors << 9;
 }
 
+static void
+sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
+{
+	Sg_request *srp;
+	int val;
+	unsigned int ms;
+
+	val = 0;
+	list_for_each_entry(srp, &sfp->rq_list, entry) {
+		if (val >= SG_MAX_QUEUE)
+			break;
+		rinfo[val].req_state = srp->done + 1;
+		rinfo[val].problem =
+			srp->header.masked_status &
+			srp->header.host_status &
+			srp->header.driver_status;
+		if (srp->done)
+			rinfo[val].duration =
+				srp->header.duration;
+		else {
+			ms = jiffies_to_msecs(jiffies);
+			rinfo[val].duration =
+				(ms > srp->header.duration) ?
+				(ms - srp->header.duration) : 0;
+		}
+		rinfo[val].orphan = srp->orphan;
+		rinfo[val].sg_io_owned = srp->sg_io_owned;
+		rinfo[val].pack_id = srp->header.pack_id;
+		rinfo[val].usr_ptr = srp->header.usr_ptr;
+		val++;
+	}
+}
+
 static long
 sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 {
@@ -893,24 +976,14 @@
 				/* strange ..., for backward compatibility */
 		return sfp->timeout_user;
 	case SG_SET_FORCE_LOW_DMA:
-		result = get_user(val, ip);
-		if (result)
-			return result;
-		if (val) {
-			sfp->low_dma = 1;
-			if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
-				val = (int) sfp->reserve.bufflen;
-				sg_remove_scat(sfp, &sfp->reserve);
-				sg_build_reserve(sfp, val);
-			}
-		} else {
-			if (atomic_read(&sdp->detaching))
-				return -ENODEV;
-			sfp->low_dma = sdp->device->host->unchecked_isa_dma;
-		}
+		/*
+		 * N.B. This ioctl never worked properly, but failed to
+		 * return an error value. So returning '0' to keep compability
+		 * with legacy applications.
+		 */
 		return 0;
 	case SG_GET_LOW_DMA:
-		return put_user((int) sfp->low_dma, ip);
+		return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
 	case SG_GET_SCSI_ID:
 		if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
 			return -EFAULT;
@@ -944,7 +1017,7 @@
 		if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
 			return -EFAULT;
 		read_lock_irqsave(&sfp->rq_list_lock, iflags);
-		for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+		list_for_each_entry(srp, &sfp->rq_list, entry) {
 			if ((1 == srp->done) && (!srp->sg_io_owned)) {
 				read_unlock_irqrestore(&sfp->rq_list_lock,
 						       iflags);
@@ -957,7 +1030,8 @@
 		return 0;
 	case SG_GET_NUM_WAITING:
 		read_lock_irqsave(&sfp->rq_list_lock, iflags);
-		for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
+		val = 0;
+		list_for_each_entry(srp, &sfp->rq_list, entry) {
 			if ((1 == srp->done) && (!srp->sg_io_owned))
 				++val;
 		}
@@ -973,12 +1047,18 @@
                         return -EINVAL;
 		val = min_t(int, val,
 			    max_sectors_bytes(sdp->device->request_queue));
+		mutex_lock(&sfp->f_mutex);
 		if (val != sfp->reserve.bufflen) {
-			if (sg_res_in_use(sfp) || sfp->mmap_called)
+			if (sfp->mmap_called ||
+			    sfp->res_in_use) {
+				mutex_unlock(&sfp->f_mutex);
 				return -EBUSY;
+			}
+
 			sg_remove_scat(sfp, &sfp->reserve);
 			sg_build_reserve(sfp, val);
 		}
+		mutex_unlock(&sfp->f_mutex);
 		return 0;
 	case SG_GET_RESERVED_SIZE:
 		val = min_t(int, sfp->reserve.bufflen,
@@ -1004,6 +1084,8 @@
 		result = get_user(val, ip);
 		if (result)
 			return result;
+		if (val > SG_MAX_CDB_SIZE)
+			return -ENOMEM;
 		sfp->next_cmd_len = (val > 0) ? val : 0;
 		return 0;
 	case SG_GET_VERSION_NUM:
@@ -1017,42 +1099,15 @@
 			return -EFAULT;
 		else {
 			sg_req_info_t *rinfo;
-			unsigned int ms;
 
-			rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
-								GFP_KERNEL);
+			rinfo = kzalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
+					GFP_KERNEL);
 			if (!rinfo)
 				return -ENOMEM;
 			read_lock_irqsave(&sfp->rq_list_lock, iflags);
-			for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
-			     ++val, srp = srp ? srp->nextrp : srp) {
-				memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
-				if (srp) {
-					rinfo[val].req_state = srp->done + 1;
-					rinfo[val].problem =
-					    srp->header.masked_status & 
-					    srp->header.host_status & 
-					    srp->header.driver_status;
-					if (srp->done)
-						rinfo[val].duration =
-							srp->header.duration;
-					else {
-						ms = jiffies_to_msecs(jiffies);
-						rinfo[val].duration =
-						    (ms > srp->header.duration) ?
-						    (ms - srp->header.duration) : 0;
-					}
-					rinfo[val].orphan = srp->orphan;
-					rinfo[val].sg_io_owned =
-							srp->sg_io_owned;
-					rinfo[val].pack_id =
-							srp->header.pack_id;
-					rinfo[val].usr_ptr =
-							srp->header.usr_ptr;
-				}
-			}
+			sg_fill_request_table(sfp, rinfo);
 			read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-			result = __copy_to_user(p, rinfo, 
+			result = __copy_to_user(p, rinfo,
 						SZ_SG_REQ_INFO * SG_MAX_QUEUE);
 			result = result ? -EFAULT : 0;
 			kfree(rinfo);
@@ -1158,7 +1213,7 @@
 		return POLLERR;
 	poll_wait(filp, &sfp->read_wait, wait);
 	read_lock_irqsave(&sfp->rq_list_lock, iflags);
-	for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+	list_for_each_entry(srp, &sfp->rq_list, entry) {
 		/* if any read waiting, flag it */
 		if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned))
 			res = POLLIN | POLLRDNORM;
@@ -1239,6 +1294,7 @@
 	unsigned long req_sz, len, sa;
 	Sg_scatter_hold *rsv_schp;
 	int k, length;
+	int ret = 0;
 
 	if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
 		return -ENXIO;
@@ -1249,8 +1305,11 @@
 	if (vma->vm_pgoff)
 		return -EINVAL;	/* want no offset */
 	rsv_schp = &sfp->reserve;
-	if (req_sz > rsv_schp->bufflen)
-		return -ENOMEM;	/* cannot map more than reserved buffer */
+	mutex_lock(&sfp->f_mutex);
+	if (req_sz > rsv_schp->bufflen) {
+		ret = -ENOMEM;	/* cannot map more than reserved buffer */
+		goto out;
+	}
 
 	sa = vma->vm_start;
 	length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
@@ -1261,10 +1320,12 @@
 	}
 
 	sfp->mmap_called = 1;
-	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
 	vma->vm_private_data = sfp;
 	vma->vm_ops = &sg_mmap_vm_ops;
-	return 0;
+out:
+	mutex_unlock(&sfp->f_mutex);
+	return ret;
 }
 
 static void
@@ -1274,6 +1335,7 @@
 	struct sg_fd *sfp = srp->parentfp;
 
 	sg_finish_rem_req(srp);
+	sg_remove_request(sfp, srp);
 	kref_put(&sfp->f_ref, sg_remove_sfp);
 }
 
@@ -1731,13 +1793,25 @@
 		md = &map_data;
 
 	if (md) {
-		if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
+		mutex_lock(&sfp->f_mutex);
+		if (dxfer_len <= rsv_schp->bufflen &&
+		    !sfp->res_in_use) {
+			sfp->res_in_use = 1;
 			sg_link_reserve(sfp, srp, dxfer_len);
-		else {
+		} else if (hp->flags & SG_FLAG_MMAP_IO) {
+			res = -EBUSY; /* sfp->res_in_use == 1 */
+			if (dxfer_len > rsv_schp->bufflen)
+				res = -ENOMEM;
+			mutex_unlock(&sfp->f_mutex);
+			return res;
+		} else {
 			res = sg_build_indirect(req_schp, sfp, dxfer_len);
-			if (res)
+			if (res) {
+				mutex_unlock(&sfp->f_mutex);
 				return res;
+			}
 		}
+		mutex_unlock(&sfp->f_mutex);
 
 		md->pages = req_schp->pages;
 		md->page_order = req_schp->page_order;
@@ -1759,6 +1833,10 @@
 			return res;
 
 		iov_iter_truncate(&i, hp->dxfer_len);
+		if (!iov_iter_count(&i)) {
+			kfree(iov);
+			return -EINVAL;
+		}
 
 		res = blk_rq_map_user_iov(q, rq, md, &i, GFP_ATOMIC);
 		kfree(iov);
@@ -1802,8 +1880,6 @@
 	else
 		sg_remove_scat(sfp, req_schp);
 
-	sg_remove_request(sfp, srp);
-
 	return ret;
 }
 
@@ -1827,6 +1903,7 @@
 	int sg_tablesize = sfp->parentdp->sg_tablesize;
 	int blk_size = buff_size, order;
 	gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
+	struct sg_device *sdp = sfp->parentdp;
 
 	if (blk_size < 0)
 		return -EFAULT;
@@ -1852,7 +1929,7 @@
 			scatter_elem_sz_prev = num;
 	}
 
-	if (sfp->low_dma)
+	if (sdp->device->host->unchecked_isa_dma)
 		gfp_mask |= GFP_DMA;
 
 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -1868,7 +1945,7 @@
 		num = (rem_sz > scatter_elem_sz_prev) ?
 			scatter_elem_sz_prev : rem_sz;
 
-		schp->pages[k] = alloc_pages(gfp_mask, order);
+		schp->pages[k] = alloc_pages(gfp_mask | __GFP_ZERO, order);
 		if (!schp->pages[k])
 			goto out;
 
@@ -2022,8 +2099,9 @@
 	req_schp->pages = NULL;
 	req_schp->page_order = 0;
 	req_schp->sglist_len = 0;
-	sfp->save_scat_len = 0;
 	srp->res_used = 0;
+	/* Called without mutex lock to avoid deadlock */
+	sfp->res_in_use = 0;
 }
 
 static Sg_request *
@@ -2033,16 +2111,17 @@
 	unsigned long iflags;
 
 	write_lock_irqsave(&sfp->rq_list_lock, iflags);
-	for (resp = sfp->headrp; resp; resp = resp->nextrp) {
+	list_for_each_entry(resp, &sfp->rq_list, entry) {
 		/* look for requests that are ready + not SG_IO owned */
 		if ((1 == resp->done) && (!resp->sg_io_owned) &&
 		    ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
 			resp->done = 2;	/* guard against other readers */
-			break;
+			write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+			return resp;
 		}
 	}
 	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-	return resp;
+	return NULL;
 }
 
 /* always adds to end of list */
@@ -2051,70 +2130,45 @@
 {
 	int k;
 	unsigned long iflags;
-	Sg_request *resp;
 	Sg_request *rp = sfp->req_arr;
 
 	write_lock_irqsave(&sfp->rq_list_lock, iflags);
-	resp = sfp->headrp;
-	if (!resp) {
-		memset(rp, 0, sizeof (Sg_request));
-		rp->parentfp = sfp;
-		resp = rp;
-		sfp->headrp = resp;
-	} else {
-		if (0 == sfp->cmd_q)
-			resp = NULL;	/* command queuing disallowed */
-		else {
-			for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
-				if (!rp->parentfp)
-					break;
-			}
-			if (k < SG_MAX_QUEUE) {
-				memset(rp, 0, sizeof (Sg_request));
-				rp->parentfp = sfp;
-				while (resp->nextrp)
-					resp = resp->nextrp;
-				resp->nextrp = rp;
-				resp = rp;
-			} else
-				resp = NULL;
+	if (!list_empty(&sfp->rq_list)) {
+		if (!sfp->cmd_q)
+			goto out_unlock;
+
+		for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
+			if (!rp->parentfp)
+				break;
 		}
+		if (k >= SG_MAX_QUEUE)
+			goto out_unlock;
 	}
-	if (resp) {
-		resp->nextrp = NULL;
-		resp->header.duration = jiffies_to_msecs(jiffies);
-	}
+	memset(rp, 0, sizeof (Sg_request));
+	rp->parentfp = sfp;
+	rp->header.duration = jiffies_to_msecs(jiffies);
+	list_add_tail(&rp->entry, &sfp->rq_list);
 	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-	return resp;
+	return rp;
+out_unlock:
+	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return NULL;
 }
 
 /* Return of 1 for found; 0 for not found */
 static int
 sg_remove_request(Sg_fd * sfp, Sg_request * srp)
 {
-	Sg_request *prev_rp;
-	Sg_request *rp;
 	unsigned long iflags;
 	int res = 0;
 
-	if ((!sfp) || (!srp) || (!sfp->headrp))
+	if (!sfp || !srp || list_empty(&sfp->rq_list))
 		return res;
 	write_lock_irqsave(&sfp->rq_list_lock, iflags);
-	prev_rp = sfp->headrp;
-	if (srp == prev_rp) {
-		sfp->headrp = prev_rp->nextrp;
-		prev_rp->parentfp = NULL;
+	if (!list_empty(&srp->entry)) {
+		list_del(&srp->entry);
+		srp->parentfp = NULL;
 		res = 1;
-	} else {
-		while ((rp = prev_rp->nextrp)) {
-			if (srp == rp) {
-				prev_rp->nextrp = rp->nextrp;
-				rp->parentfp = NULL;
-				res = 1;
-				break;
-			}
-			prev_rp = rp;
-		}
 	}
 	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
 	return res;
@@ -2133,19 +2187,19 @@
 
 	init_waitqueue_head(&sfp->read_wait);
 	rwlock_init(&sfp->rq_list_lock);
-
+	INIT_LIST_HEAD(&sfp->rq_list);
 	kref_init(&sfp->f_ref);
+	mutex_init(&sfp->f_mutex);
 	sfp->timeout = SG_DEFAULT_TIMEOUT;
 	sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
 	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
-	sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
-	    sdp->device->host->unchecked_isa_dma : 1;
 	sfp->cmd_q = SG_DEF_COMMAND_Q;
 	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
 	sfp->parentdp = sdp;
 	write_lock_irqsave(&sdp->sfd_lock, iflags);
 	if (atomic_read(&sdp->detaching)) {
 		write_unlock_irqrestore(&sdp->sfd_lock, iflags);
+		kfree(sfp);
 		return ERR_PTR(-ENODEV);
 	}
 	list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
@@ -2173,10 +2227,18 @@
 {
 	struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
 	struct sg_device *sdp = sfp->parentdp;
+	Sg_request *srp;
+	unsigned long iflags;
 
 	/* Cleanup any responses which were never read(). */
-	while (sfp->headrp)
-		sg_finish_rem_req(sfp->headrp);
+	write_lock_irqsave(&sfp->rq_list_lock, iflags);
+	while (!list_empty(&sfp->rq_list)) {
+		srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
+		sg_finish_rem_req(srp);
+		list_del(&srp->entry);
+		srp->parentfp = NULL;
+	}
+	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
 
 	if (sfp->reserve.bufflen > 0) {
 		SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
@@ -2210,20 +2272,6 @@
 	schedule_work(&sfp->ew.work);
 }
 
-static int
-sg_res_in_use(Sg_fd * sfp)
-{
-	const Sg_request *srp;
-	unsigned long iflags;
-
-	read_lock_irqsave(&sfp->rq_list_lock, iflags);
-	for (srp = sfp->headrp; srp; srp = srp->nextrp)
-		if (srp->res_used)
-			break;
-	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-	return srp ? 1 : 0;
-}
-
 #ifdef CONFIG_SCSI_PROC_FS
 static int
 sg_idr_max_id(int id, void *p, void *data)
@@ -2593,7 +2641,7 @@
 /* must be called while holding sg_index_lock */
 static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
 {
-	int k, m, new_interface, blen, usg;
+	int k, new_interface, blen, usg;
 	Sg_request *srp;
 	Sg_fd *fp;
 	const sg_io_hdr_t *hp;
@@ -2609,17 +2657,15 @@
 			   jiffies_to_msecs(fp->timeout),
 			   fp->reserve.bufflen,
 			   (int) fp->reserve.k_use_sg,
-			   (int) fp->low_dma);
+			   (int) sdp->device->host->unchecked_isa_dma);
 		seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
 			   (int) fp->cmd_q, (int) fp->force_packid,
 			   (int) fp->keep_orphan);
-		for (m = 0, srp = fp->headrp;
-				srp != NULL;
-				++m, srp = srp->nextrp) {
+		list_for_each_entry(srp, &fp->rq_list, entry) {
 			hp = &srp->header;
 			new_interface = (hp->interface_id == '\0') ? 0 : 1;
 			if (srp->res_used) {
-				if (new_interface && 
+				if (new_interface &&
 				    (SG_FLAG_MMAP_IO & hp->flags))
 					cp = "     mmap>> ";
 				else
@@ -2650,7 +2696,7 @@
 			seq_printf(s, "ms sgat=%d op=0x%02x\n", usg,
 				   (int) srp->data.cmd_opcode);
 		}
-		if (0 == m)
+		if (list_empty(&fp->rq_list))
 			seq_puts(s, "     No requests active\n");
 		read_unlock(&fp->rq_list_lock);
 	}
--- linux-4.4.0.orig/drivers/scsi/sim710.c
+++ linux-4.4.0/drivers/scsi/sim710.c
@@ -176,8 +176,7 @@
 };
 MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
 
-static __init int
-sim710_eisa_probe(struct device *dev)
+static int sim710_eisa_probe(struct device *dev)
 {
 	struct eisa_device *edev = to_eisa_device(dev);
 	unsigned long io_addr = edev->base_addr;
--- linux-4.4.0.orig/drivers/scsi/sni_53c710.c
+++ linux-4.4.0/drivers/scsi/sni_53c710.c
@@ -78,10 +78,8 @@
 
 	base = res->start;
 	hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
-	if (!hostdata) {
-		dev_printk(KERN_ERR, dev, "Failed to allocate host data\n");
+	if (!hostdata)
 		return -ENOMEM;
-	}
 
 	hostdata->dev = &dev->dev;
 	dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
--- linux-4.4.0.orig/drivers/scsi/snic/snic_main.c
+++ linux-4.4.0/drivers/scsi/snic/snic_main.c
@@ -584,6 +584,7 @@
 	if (!pool) {
 		SNIC_HOST_ERR(shost, "dflt sgl pool creation failed\n");
 
+		ret = -ENOMEM;
 		goto err_free_res;
 	}
 
@@ -594,6 +595,7 @@
 	if (!pool) {
 		SNIC_HOST_ERR(shost, "max sgl pool creation failed\n");
 
+		ret = -ENOMEM;
 		goto err_free_dflt_sgl_pool;
 	}
 
@@ -604,6 +606,7 @@
 	if (!pool) {
 		SNIC_HOST_ERR(shost, "snic tmreq info pool creation failed.\n");
 
+		ret = -ENOMEM;
 		goto err_free_max_sgl_pool;
 	}
 
--- linux-4.4.0.orig/drivers/scsi/sr.c
+++ linux-4.4.0/drivers/scsi/sr.c
@@ -144,6 +144,9 @@
 {
 	struct scsi_cd *cd = dev_get_drvdata(dev);
 
+	if (!cd)	/* E.g.: runtime suspend following sr_remove() */
+		return 0;
+
 	if (cd->media_present)
 		return -EBUSY;
 	else
@@ -517,16 +520,26 @@
 static int sr_block_open(struct block_device *bdev, fmode_t mode)
 {
 	struct scsi_cd *cd;
+	struct scsi_device *sdev;
 	int ret = -ENXIO;
 
-	mutex_lock(&sr_mutex);
 	cd = scsi_cd_get(bdev->bd_disk);
-	if (cd) {
-		ret = cdrom_open(&cd->cdi, bdev, mode);
-		if (ret)
-			scsi_cd_put(cd);
-	}
+	if (!cd)
+		goto out;
+
+	sdev = cd->device;
+	scsi_autopm_get_device(sdev);
+	check_disk_change(bdev);
+
+	mutex_lock(&sr_mutex);
+	ret = cdrom_open(&cd->cdi, bdev, mode);
 	mutex_unlock(&sr_mutex);
+
+	scsi_autopm_put_device(sdev);
+	if (ret)
+		scsi_cd_put(cd);
+
+out:
 	return ret;
 }
 
@@ -554,6 +567,8 @@
 	if (ret)
 		goto out;
 
+	scsi_autopm_get_device(sdev);
+
 	/*
 	 * Send SCSI addressing ioctls directly to mid level, send other
 	 * ioctls to cdrom/block level.
@@ -562,15 +577,18 @@
 	case SCSI_IOCTL_GET_IDLUN:
 	case SCSI_IOCTL_GET_BUS_NUMBER:
 		ret = scsi_ioctl(sdev, cmd, argp);
-		goto out;
+		goto put;
 	}
 
 	ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg);
 	if (ret != -ENOSYS)
-		goto out;
+		goto put;
 
 	ret = scsi_ioctl(sdev, cmd, argp);
 
+put:
+	scsi_autopm_put_device(sdev);
+
 out:
 	mutex_unlock(&sr_mutex);
 	return ret;
@@ -579,18 +597,28 @@
 static unsigned int sr_block_check_events(struct gendisk *disk,
 					  unsigned int clearing)
 {
-	struct scsi_cd *cd = scsi_cd(disk);
+	unsigned int ret = 0;
+	struct scsi_cd *cd;
 
-	if (atomic_read(&cd->device->disk_events_disable_depth))
+	cd = scsi_cd_get(disk);
+	if (!cd)
 		return 0;
 
-	return cdrom_check_events(&cd->cdi, clearing);
+	if (!atomic_read(&cd->device->disk_events_disable_depth))
+		ret = cdrom_check_events(&cd->cdi, clearing);
+
+	scsi_cd_put(cd);
+	return ret;
 }
 
 static int sr_block_revalidate_disk(struct gendisk *disk)
 {
-	struct scsi_cd *cd = scsi_cd(disk);
 	struct scsi_sense_hdr sshdr;
+	struct scsi_cd *cd;
+
+	cd = scsi_cd_get(disk);
+	if (!cd)
+		return -ENXIO;
 
 	/* if the unit is not ready, nothing more to do */
 	if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
@@ -599,6 +627,7 @@
 	sr_cd_check(&cd->cdi);
 	get_sectorsize(cd);
 out:
+	scsi_cd_put(cd);
 	return 0;
 }
 
@@ -717,7 +746,7 @@
 	cd->cdi.disk = disk;
 
 	if (register_cdrom(&cd->cdi))
-		goto fail_put;
+		goto fail_minor;
 
 	/*
 	 * Initialize block layer runtime PM stuffs before the
@@ -735,6 +764,10 @@
 
 	return 0;
 
+fail_minor:
+	spin_lock(&sr_index_lock);
+	clear_bit(minor, sr_index_bits);
+	spin_unlock(&sr_index_lock);
 fail_put:
 	put_disk(disk);
 fail_free:
@@ -831,6 +864,7 @@
 	unsigned char *buffer;
 	struct scsi_mode_data data;
 	struct scsi_sense_hdr sshdr;
+	unsigned int ms_len = 128;
 	int rc, n;
 
 	static const char *loadmech[] =
@@ -857,10 +891,11 @@
 	scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
 
 	/* ask for mode page 0x2a */
-	rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
+	rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, ms_len,
 			     SR_TIMEOUT, 3, &data, NULL);
 
-	if (!scsi_status_is_good(rc)) {
+	if (!scsi_status_is_good(rc) || data.length > ms_len ||
+	    data.header_length + data.block_descriptor_length > data.length) {
 		/* failed, drive doesn't have capabilities mode page */
 		cd->cdi.speed = 1;
 		cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
@@ -985,6 +1020,7 @@
 	scsi_autopm_get_device(cd->device);
 
 	del_gendisk(cd->disk);
+	dev_set_drvdata(dev, NULL);
 
 	mutex_lock(&sr_ref_mutex);
 	kref_put(&cd->kref, sr_kref_release);
--- linux-4.4.0.orig/drivers/scsi/sr_ioctl.c
+++ linux-4.4.0/drivers/scsi/sr_ioctl.c
@@ -187,30 +187,25 @@
 	struct scsi_device *SDev;
 	struct scsi_sense_hdr sshdr;
 	int result, err = 0, retries = 0;
-	struct request_sense *sense = cgc->sense;
+	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
 
 	SDev = cd->device;
 
-	if (!sense) {
-		sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
-		if (!sense) {
-			err = -ENOMEM;
-			goto out;
-		}
-	}
-
       retry:
 	if (!scsi_block_when_processing_errors(SDev)) {
 		err = -ENODEV;
 		goto out;
 	}
 
-	memset(sense, 0, sizeof(*sense));
+	memset(sense_buffer, 0, sizeof(sense_buffer));
 	result = scsi_execute(SDev, cgc->cmd, cgc->data_direction,
-			      cgc->buffer, cgc->buflen, (char *)sense,
+			      cgc->buffer, cgc->buflen, sense_buffer,
 			      cgc->timeout, IOCTL_RETRIES, 0, NULL);
 
-	scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr);
+	scsi_normalize_sense(sense_buffer, sizeof(sense_buffer), &sshdr);
+
+	if (cgc->sense)
+		memcpy(cgc->sense, sense_buffer, sizeof(*cgc->sense));
 
 	/* Minimal error checking.  Ignore cases we know about, and report the rest. */
 	if (driver_byte(result) != 0) {
@@ -261,8 +256,6 @@
 
 	/* Wake up a process waiting for device */
       out:
-	if (!cgc->sense)
-		kfree(sense);
 	cgc->stat = err;
 	return err;
 }
--- linux-4.4.0.orig/drivers/scsi/st.c
+++ linux-4.4.0/drivers/scsi/st.c
@@ -4821,9 +4821,8 @@
 		current->mm,
 		uaddr,
 		nr_pages,
-		rw == READ,
-		0, /* don't force */
-		pages);
+		pages,
+		rw == READ ? FOLL_WRITE : 0); /* don't force */
 
 	/* Errors and no page mapped should return here */
 	if (res < nr_pages)
--- linux-4.4.0.orig/drivers/scsi/stex.c
+++ linux-4.4.0/drivers/scsi/stex.c
@@ -617,16 +617,17 @@
 		return 0;
 	case PASSTHRU_CMD:
 		if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) {
-			struct st_drvver ver;
+			const struct st_drvver ver = {
+				.major = ST_VER_MAJOR,
+				.minor = ST_VER_MINOR,
+				.oem = ST_OEM,
+				.build = ST_BUILD_VER,
+				.signature[0] = PASSTHRU_SIGNATURE,
+				.console_id = host->max_id - 1,
+				.host_no = hba->host->host_no,
+			};
 			size_t cp_len = sizeof(ver);
 
-			ver.major = ST_VER_MAJOR;
-			ver.minor = ST_VER_MINOR;
-			ver.oem = ST_OEM;
-			ver.build = ST_BUILD_VER;
-			ver.signature[0] = PASSTHRU_SIGNATURE;
-			ver.console_id = host->max_id - 1;
-			ver.host_no = hba->host->host_no;
 			cp_len = scsi_sg_copy_from_buffer(cmd, &ver, cp_len);
 			cmd->result = sizeof(ver) == cp_len ?
 				DID_OK << 16 | COMMAND_COMPLETE << 8 :
--- linux-4.4.0.orig/drivers/scsi/storvsc_drv.c
+++ linux-4.4.0/drivers/scsi/storvsc_drv.c
@@ -41,6 +41,8 @@
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_devinfo.h>
 #include <scsi/scsi_dbg.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_transport.h>
 
 /*
  * All wire protocol details (storage protocol between the guest and the host)
@@ -92,9 +94,8 @@
  */
 
 struct hv_fc_wwn_packet {
-	bool	primary_active;
-	u8	reserved1;
-	u8	reserved2;
+	u8	primary_active;
+	u8	reserved1[3];
 	u8	primary_port_wwn[8];
 	u8	primary_node_wwn[8];
 	u8	secondary_port_wwn[8];
@@ -135,6 +136,8 @@
 #define SRB_FLAGS_PORT_DRIVER_RESERVED		0x0F000000
 #define SRB_FLAGS_CLASS_DRIVER_RESERVED		0xF0000000
 
+#define SP_UNTAGGED			((unsigned char) ~0)
+#define SRB_SIMPLE_TAG_REQUEST		0x20
 
 /*
  * Platform neutral description of a scsi request -
@@ -164,6 +167,26 @@
 */
 static int vmstor_proto_version;
 
+#define STORVSC_LOGGING_NONE	0
+#define STORVSC_LOGGING_ERROR	1
+#define STORVSC_LOGGING_WARN	2
+
+static int logging_level = STORVSC_LOGGING_ERROR;
+module_param(logging_level, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(logging_level,
+	"Logging level, 0 - None, 1 - Error (default), 2 - Warning.");
+
+static inline bool do_logging(int level)
+{
+	return logging_level >= level;
+}
+
+#define storvsc_log(dev, level, fmt, ...)			\
+do {								\
+	if (do_logging(level))					\
+		dev_warn(&(dev)->device, fmt, ##__VA_ARGS__);	\
+} while (0)
+
 struct vmscsi_win8_extension {
 	/*
 	 * The following were added in Windows 8
@@ -354,6 +377,7 @@
 #define SRB_STATUS_SUCCESS	0x01
 #define SRB_STATUS_ABORTED	0x02
 #define SRB_STATUS_ERROR	0x04
+#define SRB_STATUS_DATA_OVERRUN	0x12
 
 #define SRB_STATUS(status) \
 	(status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
@@ -370,14 +394,15 @@
 MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
 
 module_param(storvsc_vcpus_per_sub_channel, int, S_IRUGO);
-MODULE_PARM_DESC(vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
+MODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
 /*
  * Timeout in seconds for all devices managed by this driver.
  */
 static int storvsc_timeout = 180;
 
-static int msft_blist_flags = BLIST_TRY_VPD_PAGES;
-
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct scsi_transport_template *fc_transport_template;
+#endif
 
 static void storvsc_on_channel_callback(void *context);
 
@@ -434,9 +459,23 @@
 	 * Max I/O, the device can support.
 	 */
 	u32   max_transfer_bytes;
+	/*
+	 * Number of sub-channels we will open.
+	 */
+	u16 num_sc;
+	struct vmbus_channel **stor_chns;
+	/*
+	 * Mask of CPUs bound to subchannels.
+	 */
+	struct cpumask alloced_cpus;
 	/* Used for vsc/vsp channel reset process */
 	struct storvsc_cmd_request init_request;
 	struct storvsc_cmd_request reset_request;
+	/*
+	 * Currently active port and node names for FC devices.
+	 */
+	u64 node_name;
+	u64 port_name;
 };
 
 struct hv_host_device {
@@ -449,19 +488,18 @@
 struct storvsc_scan_work {
 	struct work_struct work;
 	struct Scsi_Host *host;
-	uint lun;
+	u8 lun;
+	u8 tgt_id;
 };
 
 static void storvsc_device_scan(struct work_struct *work)
 {
 	struct storvsc_scan_work *wrk;
-	uint lun;
 	struct scsi_device *sdev;
 
 	wrk = container_of(work, struct storvsc_scan_work, work);
-	lun = wrk->lun;
 
-	sdev = scsi_device_lookup(wrk->host, 0, 0, lun);
+	sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
 	if (!sdev)
 		goto done;
 	scsi_rescan_device(&sdev->sdev_gendev);
@@ -512,7 +550,7 @@
 	if (!scsi_host_get(wrk->host))
 		goto done;
 
-	sdev = scsi_device_lookup(wrk->host, 0, 0, wrk->lun);
+	sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
 
 	if (sdev) {
 		scsi_remove_device(sdev);
@@ -607,22 +645,37 @@
 		   (void *)&props,
 		   sizeof(struct vmstorage_channel_properties),
 		   storvsc_on_channel_callback, new_sc);
+
+	if (new_sc->state == CHANNEL_OPENED_STATE) {
+		stor_device->stor_chns[new_sc->target_cpu] = new_sc;
+		cpumask_set_cpu(new_sc->target_cpu, &stor_device->alloced_cpus);
+	}
 }
 
 static void  handle_multichannel_storage(struct hv_device *device, int max_chns)
 {
 	struct storvsc_device *stor_device;
-	int num_cpus = num_online_cpus();
 	int num_sc;
 	struct storvsc_cmd_request *request;
 	struct vstor_packet *vstor_packet;
 	int ret, t;
 
-	num_sc = ((max_chns > num_cpus) ? num_cpus : max_chns);
+	/*
+	 * If the number of CPUs is artificially restricted, such as
+	 * with maxcpus=1 on the kernel boot line, Hyper-V could offer
+	 * sub-channels >= the number of CPUs. These sub-channels
+	 * should not be created. The primary channel is already created
+	 * and assigned to one CPU, so check against # CPUs - 1.
+	 */
+	num_sc = min((int)(num_online_cpus() - 1), max_chns);
+	if (!num_sc)
+		return;
+
 	stor_device = get_out_stor_device(device);
 	if (!stor_device)
 		return;
 
+	stor_device->num_sc = num_sc;
 	request = &stor_device->init_request;
 	vstor_packet = &request->vstor_packet;
 
@@ -676,29 +729,36 @@
 	vmbus_are_subchannels_present(device->channel);
 }
 
-static int storvsc_channel_init(struct hv_device *device)
+static void cache_wwn(struct storvsc_device *stor_device,
+		      struct vstor_packet *vstor_packet)
 {
-	struct storvsc_device *stor_device;
-	struct storvsc_cmd_request *request;
-	struct vstor_packet *vstor_packet;
-	int ret, t, i;
-	int max_chns;
-	bool process_sub_channels = false;
+	/*
+	 * Cache the currently active port and node ww names.
+	 */
+	if (vstor_packet->wwn_packet.primary_active) {
+		stor_device->node_name =
+			wwn_to_u64(vstor_packet->wwn_packet.primary_node_wwn);
+		stor_device->port_name =
+			wwn_to_u64(vstor_packet->wwn_packet.primary_port_wwn);
+	} else {
+		stor_device->node_name =
+			wwn_to_u64(vstor_packet->wwn_packet.secondary_node_wwn);
+		stor_device->port_name =
+			wwn_to_u64(vstor_packet->wwn_packet.secondary_port_wwn);
+	}
+}
 
-	stor_device = get_out_stor_device(device);
-	if (!stor_device)
-		return -ENODEV;
 
-	request = &stor_device->init_request;
+static int storvsc_execute_vstor_op(struct hv_device *device,
+				    struct storvsc_cmd_request *request,
+				    bool status_check)
+{
+	struct vstor_packet *vstor_packet;
+	int ret, t;
+
 	vstor_packet = &request->vstor_packet;
 
-	/*
-	 * Now, initiate the vsc/vsp initialization protocol on the open
-	 * channel
-	 */
-	memset(request, 0, sizeof(struct storvsc_cmd_request));
 	init_completion(&request->wait_event);
-	vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
 	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
 
 	ret = vmbus_sendpacket(device->channel, vstor_packet,
@@ -708,27 +768,56 @@
 			       VM_PKT_DATA_INBAND,
 			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 	if (ret != 0)
-		goto cleanup;
+		return ret;
 
 	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
+	if (t == 0)
+		return -ETIMEDOUT;
+
+	if (!status_check)
+		return ret;
 
 	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-	    vstor_packet->status != 0) {
-		ret = -EINVAL;
-		goto cleanup;
-	}
+	    vstor_packet->status != 0)
+		return -EINVAL;
 
+	return ret;
+}
+
+static int storvsc_channel_init(struct hv_device *device, bool is_fc)
+{
+	struct storvsc_device *stor_device;
+	struct storvsc_cmd_request *request;
+	struct vstor_packet *vstor_packet;
+	int ret, i;
+	int max_chns;
+	bool process_sub_channels = false;
+
+	stor_device = get_out_stor_device(device);
+	if (!stor_device)
+		return -ENODEV;
+
+	request = &stor_device->init_request;
+	vstor_packet = &request->vstor_packet;
+
+	/*
+	 * Now, initiate the vsc/vsp initialization protocol on the open
+	 * channel
+	 */
+	memset(request, 0, sizeof(struct storvsc_cmd_request));
+	vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
+	ret = storvsc_execute_vstor_op(device, request, true);
+	if (ret)
+		return ret;
+	/*
+	 * Query host supported protocol version.
+	 */
 
 	for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) {
 		/* reuse the packet for version range supported */
 		memset(vstor_packet, 0, sizeof(struct vstor_packet));
 		vstor_packet->operation =
 			VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
-		vstor_packet->flags = REQUEST_COMPLETION_FLAG;
 
 		vstor_packet->version.major_minor =
 			vmstor_protocols[i].protocol_version;
@@ -737,26 +826,12 @@
 		 * The revision number is only used in Windows; set it to 0.
 		 */
 		vstor_packet->version.revision = 0;
-
-		ret = vmbus_sendpacket(device->channel, vstor_packet,
-			       (sizeof(struct vstor_packet) -
-				vmscsi_size_delta),
-			       (unsigned long)request,
-			       VM_PKT_DATA_INBAND,
-			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+		ret = storvsc_execute_vstor_op(device, request, false);
 		if (ret != 0)
-			goto cleanup;
+			return ret;
 
-		t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-		if (t == 0) {
-			ret = -ETIMEDOUT;
-			goto cleanup;
-		}
-
-		if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO) {
-			ret = -EINVAL;
-			goto cleanup;
-		}
+		if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO)
+			return -EINVAL;
 
 		if (vstor_packet->status == 0) {
 			vmstor_proto_version =
@@ -772,37 +847,15 @@
 		}
 	}
 
-	if (vstor_packet->status != 0) {
-		ret = -EINVAL;
-		goto cleanup;
-	}
+	if (vstor_packet->status != 0)
+		return -EINVAL;
 
 
 	memset(vstor_packet, 0, sizeof(struct vstor_packet));
 	vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
-	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
-	ret = vmbus_sendpacket(device->channel, vstor_packet,
-			       (sizeof(struct vstor_packet) -
-				vmscsi_size_delta),
-			       (unsigned long)request,
-			       VM_PKT_DATA_INBAND,
-			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
+	ret = storvsc_execute_vstor_op(device, request, true);
 	if (ret != 0)
-		goto cleanup;
-
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
-
-	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-	    vstor_packet->status != 0) {
-		ret = -EINVAL;
-		goto cleanup;
-	}
+		return ret;
 
 	/*
 	 * Check to see if multi-channel support is there.
@@ -810,6 +863,25 @@
 	 * support multi-channel.
 	 */
 	max_chns = vstor_packet->storage_channel_properties.max_channel_cnt;
+
+	/*
+	 * Allocate state to manage the sub-channels.
+	 * We allocate an array based on the numbers of possible CPUs
+	 * (Hyper-V does not support cpu online/offline).
+	 * This Array will be sparseley populated with unique
+	 * channels - primary + sub-channels.
+	 * We will however populate all the slots to evenly distribute
+	 * the load.
+	 */
+	stor_device->stor_chns = kzalloc(sizeof(void *) * num_possible_cpus(),
+					 GFP_KERNEL);
+	if (stor_device->stor_chns == NULL)
+		return -ENOMEM;
+
+	stor_device->stor_chns[device->channel->target_cpu] = device->channel;
+	cpumask_set_cpu(device->channel->target_cpu,
+			&stor_device->alloced_cpus);
+
 	if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN8) {
 		if (vstor_packet->storage_channel_properties.flags &
 		    STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
@@ -818,37 +890,34 @@
 	stor_device->max_transfer_bytes =
 		vstor_packet->storage_channel_properties.max_transfer_bytes;
 
-	memset(vstor_packet, 0, sizeof(struct vstor_packet));
-	vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
-	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
-	ret = vmbus_sendpacket(device->channel, vstor_packet,
-			       (sizeof(struct vstor_packet) -
-				vmscsi_size_delta),
-			       (unsigned long)request,
-			       VM_PKT_DATA_INBAND,
-			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (!is_fc)
+		goto done;
 
+	/*
+	 * For FC devices retrieve FC HBA data.
+	 */
+	memset(vstor_packet, 0, sizeof(struct vstor_packet));
+	vstor_packet->operation = VSTOR_OPERATION_FCHBA_DATA;
+	ret = storvsc_execute_vstor_op(device, request, true);
 	if (ret != 0)
-		goto cleanup;
+		return ret;
 
-	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
+	/*
+	 * Cache the currently active port and node ww names.
+	 */
+	cache_wwn(stor_device, vstor_packet);
 
-	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-	    vstor_packet->status != 0) {
-		ret = -EINVAL;
-		goto cleanup;
-	}
+done:
+
+	memset(vstor_packet, 0, sizeof(struct vstor_packet));
+	vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
+	ret = storvsc_execute_vstor_op(device, request, true);
+	if (ret != 0)
+		return ret;
 
 	if (process_sub_channels)
 		handle_multichannel_storage(device, max_chns);
 
-
-cleanup:
 	return ret;
 }
 
@@ -864,6 +933,13 @@
 	switch (SRB_STATUS(vm_srb->srb_status)) {
 	case SRB_STATUS_ERROR:
 		/*
+		 * Let upper layer deal with error when
+		 * sense message is present.
+		 */
+
+		if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)
+			break;
+		/*
 		 * If there is an error; offline the device since all
 		 * error recovery strategies would have already been
 		 * deployed on the host side. However, if the command
@@ -882,15 +958,17 @@
 		case TEST_UNIT_READY:
 			break;
 		default:
-			set_host_byte(scmnd, DID_TARGET_FAILURE);
+			set_host_byte(scmnd, DID_ERROR);
 		}
 		break;
 	case SRB_STATUS_INVALID_LUN:
+		set_host_byte(scmnd, DID_NO_CONNECT);
 		do_work = true;
 		process_err_fn = storvsc_remove_lun;
 		break;
-	case (SRB_STATUS_ABORTED | SRB_STATUS_AUTOSENSE_VALID):
-		if ((asc == 0x2a) && (ascq == 0x9)) {
+	case SRB_STATUS_ABORTED:
+		if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
+		    (asc == 0x2a) && (ascq == 0x9)) {
 			do_work = true;
 			process_err_fn = storvsc_device_scan;
 			/*
@@ -915,44 +993,54 @@
 
 	wrk->host = host;
 	wrk->lun = vm_srb->lun;
+	wrk->tgt_id = vm_srb->target_id;
 	INIT_WORK(&wrk->work, process_err_fn);
 	schedule_work(&wrk->work);
 }
 
 
-static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
+				       struct storvsc_device *stor_dev)
 {
 	struct scsi_cmnd *scmnd = cmd_request->cmd;
-	struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
 	struct scsi_sense_hdr sense_hdr;
 	struct vmscsi_request *vm_srb;
+	u32 data_transfer_length;
 	struct Scsi_Host *host;
-	struct storvsc_device *stor_dev;
-	struct hv_device *dev = host_dev->dev;
 	u32 payload_sz = cmd_request->payload_sz;
 	void *payload = cmd_request->payload;
 
-	stor_dev = get_in_stor_device(dev);
 	host = stor_dev->host;
 
 	vm_srb = &cmd_request->vstor_packet.vm_srb;
+	data_transfer_length = vm_srb->data_transfer_length;
 
 	scmnd->result = vm_srb->scsi_status;
 
 	if (scmnd->result) {
 		if (scsi_normalize_sense(scmnd->sense_buffer,
-				SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+				SCSI_SENSE_BUFFERSIZE, &sense_hdr) &&
+		    !(sense_hdr.sense_key == NOT_READY &&
+				 sense_hdr.asc == 0x03A) &&
+		    do_logging(STORVSC_LOGGING_ERROR))
 			scsi_print_sense_hdr(scmnd->device, "storvsc",
 					     &sense_hdr);
 	}
 
-	if (vm_srb->srb_status != SRB_STATUS_SUCCESS)
+	if (vm_srb->srb_status != SRB_STATUS_SUCCESS) {
 		storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc,
 					 sense_hdr.ascq);
+		/*
+		 * The Windows driver set data_transfer_length on
+		 * SRB_STATUS_DATA_OVERRUN. On other errors, this value
+		 * is untouched.  In these cases we set it to 0.
+		 */
+		if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN)
+			data_transfer_length = 0;
+	}
 
 	scsi_set_resid(scmnd,
-		cmd_request->payload->range.len -
-		vm_srb->data_transfer_length);
+		cmd_request->payload->range.len - data_transfer_length);
 
 	scmnd->scsi_done(scmnd);
 
@@ -961,14 +1049,13 @@
 		kfree(payload);
 }
 
-static void storvsc_on_io_completion(struct hv_device *device,
+static void storvsc_on_io_completion(struct storvsc_device *stor_device,
 				  struct vstor_packet *vstor_packet,
 				  struct storvsc_cmd_request *request)
 {
-	struct storvsc_device *stor_device;
 	struct vstor_packet *stor_pkt;
+	struct hv_device *device = stor_device->device;
 
-	stor_device = hv_get_drvdata(device);
 	stor_pkt = &request->vstor_packet;
 
 	/*
@@ -995,6 +1082,13 @@
 	stor_pkt->vm_srb.sense_info_length =
 	vstor_packet->vm_srb.sense_info_length;
 
+	if (vstor_packet->vm_srb.scsi_status != 0 ||
+	    vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS)
+		storvsc_log(device, STORVSC_LOGGING_WARN,
+			"cmd 0x%x scsi status 0x%x srb status 0x%x\n",
+			stor_pkt->vm_srb.cdb[0],
+			vstor_packet->vm_srb.scsi_status,
+			vstor_packet->vm_srb.srb_status);
 
 	if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
 		/* CHECK_CONDITION */
@@ -1002,6 +1096,10 @@
 			SRB_STATUS_AUTOSENSE_VALID) {
 			/* autosense data available */
 
+			storvsc_log(device, STORVSC_LOGGING_WARN,
+				"stor pkt %p autosense data valid - len %d\n",
+				request, vstor_packet->vm_srb.sense_info_length);
+
 			memcpy(request->cmd->sense_buffer,
 			       vstor_packet->vm_srb.sense_data,
 			       vstor_packet->vm_srb.sense_info_length);
@@ -1012,7 +1110,7 @@
 	stor_pkt->vm_srb.data_transfer_length =
 	vstor_packet->vm_srb.data_transfer_length;
 
-	storvsc_command_completion(request);
+	storvsc_command_completion(request, stor_device);
 
 	if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
 		stor_device->drain_notify)
@@ -1021,21 +1119,19 @@
 
 }
 
-static void storvsc_on_receive(struct hv_device *device,
+static void storvsc_on_receive(struct storvsc_device *stor_device,
 			     struct vstor_packet *vstor_packet,
 			     struct storvsc_cmd_request *request)
 {
 	struct storvsc_scan_work *work;
-	struct storvsc_device *stor_device;
 
 	switch (vstor_packet->operation) {
 	case VSTOR_OPERATION_COMPLETE_IO:
-		storvsc_on_io_completion(device, vstor_packet, request);
+		storvsc_on_io_completion(stor_device, vstor_packet, request);
 		break;
 
 	case VSTOR_OPERATION_REMOVE_DEVICE:
 	case VSTOR_OPERATION_ENUMERATE_BUS:
-		stor_device = get_in_stor_device(device);
 		work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
 		if (!work)
 			return;
@@ -1045,6 +1141,13 @@
 		schedule_work(&work->work);
 		break;
 
+	case VSTOR_OPERATION_FCHBA_DATA:
+		cache_wwn(stor_device, vstor_packet);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+		fc_host_node_name(stor_device->host) = stor_device->node_name;
+		fc_host_port_name(stor_device->host) = stor_device->port_name;
+#endif
+		break;
 	default:
 		break;
 	}
@@ -1088,7 +1191,7 @@
 					vmscsi_size_delta));
 				complete(&request->wait_event);
 			} else {
-				storvsc_on_receive(device,
+				storvsc_on_receive(stor_device,
 						(struct vstor_packet *)packet,
 						request);
 			}
@@ -1100,7 +1203,8 @@
 	return;
 }
 
-static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
+static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
+				  bool is_fc)
 {
 	struct vmstorage_channel_properties props;
 	int ret;
@@ -1117,7 +1221,7 @@
 	if (ret != 0)
 		return ret;
 
-	ret = storvsc_channel_init(device);
+	ret = storvsc_channel_init(device, is_fc);
 
 	return ret;
 }
@@ -1155,17 +1259,64 @@
 	/* Close the channel */
 	vmbus_close(device->channel);
 
+	kfree(stor_device->stor_chns);
 	kfree(stor_device);
 	return 0;
 }
 
+static struct vmbus_channel *get_og_chn(struct storvsc_device *stor_device,
+					u16 q_num)
+{
+	u16 slot = 0;
+	u16 hash_qnum;
+	struct cpumask alloced_mask;
+	int num_channels, tgt_cpu;
+
+	if (stor_device->num_sc == 0)
+		return stor_device->device->channel;
+
+	/*
+	 * Our channel array is sparsley populated and we
+	 * initiated I/O on a processor/hw-q that does not
+	 * currently have a designated channel. Fix this.
+	 * The strategy is simple:
+	 * I. Ensure NUMA locality
+	 * II. Distribute evenly (best effort)
+	 * III. Mapping is persistent.
+	 */
+
+	cpumask_and(&alloced_mask, &stor_device->alloced_cpus,
+		    cpumask_of_node(cpu_to_node(q_num)));
+
+	num_channels = cpumask_weight(&alloced_mask);
+	if (num_channels == 0)
+		return stor_device->device->channel;
+
+	hash_qnum = q_num;
+	while (hash_qnum >= num_channels)
+		hash_qnum -= num_channels;
+
+	for_each_cpu(tgt_cpu, &alloced_mask) {
+		if (slot == hash_qnum)
+			break;
+		slot++;
+	}
+
+	stor_device->stor_chns[q_num] = stor_device->stor_chns[tgt_cpu];
+
+	return stor_device->stor_chns[q_num];
+}
+
+
 static int storvsc_do_io(struct hv_device *device,
-			 struct storvsc_cmd_request *request)
+			 struct storvsc_cmd_request *request, u16 q_num)
 {
 	struct storvsc_device *stor_device;
 	struct vstor_packet *vstor_packet;
 	struct vmbus_channel *outgoing_channel;
 	int ret = 0;
+	struct cpumask alloced_mask;
+	int tgt_cpu;
 
 	vstor_packet = &request->vstor_packet;
 	stor_device = get_out_stor_device(device);
@@ -1179,7 +1330,26 @@
 	 * Select an an appropriate channel to send the request out.
 	 */
 
-	outgoing_channel = vmbus_get_outgoing_channel(device->channel);
+	if (stor_device->stor_chns[q_num] != NULL) {
+		outgoing_channel = stor_device->stor_chns[q_num];
+		if (outgoing_channel->target_cpu == smp_processor_id()) {
+			/*
+			 * Ideally, we want to pick a different channel if
+			 * available on the same NUMA node.
+			 */
+			cpumask_and(&alloced_mask, &stor_device->alloced_cpus,
+				    cpumask_of_node(cpu_to_node(q_num)));
+			for_each_cpu(tgt_cpu, &alloced_mask) {
+				if (tgt_cpu != outgoing_channel->target_cpu) {
+					outgoing_channel =
+					stor_device->stor_chns[tgt_cpu];
+					break;
+				}
+			}
+		}
+	} else {
+		outgoing_channel = get_og_chn(stor_device, q_num);
+	}
 
 
 	vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
@@ -1221,10 +1391,24 @@
 	return ret;
 }
 
-static int storvsc_device_configure(struct scsi_device *sdevice)
+static int storvsc_device_alloc(struct scsi_device *sdevice)
 {
+	/*
+	 * Set blist flag to permit the reading of the VPD pages even when
+	 * the target may claim SPC-2 compliance. MSFT targets currently
+	 * claim SPC-2 compliance while they implement post SPC-2 features.
+	 * With this flag we can correctly handle WRITE_SAME_16 issues.
+	 *
+	 * Hypervisor reports SCSI_UNKNOWN type for DVD ROM device but
+	 * still supports REPORT LUN.
+	 */
+	sdevice->sdev_bflags = BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES;
+
+	return 0;
+}
 
-	blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
+static int storvsc_device_configure(struct scsi_device *sdevice)
+{
 
 	blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
 
@@ -1236,14 +1420,6 @@
 	sdevice->no_write_same = 1;
 
 	/*
-	 * Add blist flags to permit the reading of the VPD pages even when
-	 * the target may claim SPC-2 compliance. MSFT targets currently
-	 * claim SPC-2 compliance while they implement post SPC-2 features.
-	 * With this patch we can correctly handle WRITE_SAME_16 issues.
-	 */
-	sdevice->sdev_bflags |= msft_blist_flags;
-
-	/*
 	 * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3
 	 * if the device is a MSFT virtual device.  If the host is
 	 * WIN10 or newer, allow write_same.
@@ -1408,6 +1584,13 @@
 	vm_srb->win8_extension.srb_flags |=
 		SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
 
+	if (scmnd->device->tagged_supported) {
+		vm_srb->win8_extension.srb_flags |=
+		(SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE);
+		vm_srb->win8_extension.queue_tag = SP_UNTAGGED;
+		vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST;
+	}
+
 	/* Build the SRB */
 	switch (scmnd->sc_data_direction) {
 	case DMA_TO_DEVICE:
@@ -1481,9 +1664,12 @@
 	cmd_request->payload_sz = payload_sz;
 
 	/* Invokes the vsc to start an IO */
-	ret = storvsc_do_io(dev, cmd_request);
+	ret = storvsc_do_io(dev, cmd_request, get_cpu());
+	put_cpu();
 
 	if (ret == -EAGAIN) {
+		if (payload_sz > sizeof(cmd_request->mpb))
+			kfree(payload);
 		/* no more space */
 		return SCSI_MLQUEUE_DEVICE_BUSY;
 	}
@@ -1500,13 +1686,15 @@
 	.eh_host_reset_handler =	storvsc_host_reset_handler,
 	.proc_name =		"storvsc_host",
 	.eh_timed_out =		storvsc_eh_timed_out,
+	.slave_alloc =		storvsc_device_alloc,
 	.slave_configure =	storvsc_device_configure,
-	.cmd_per_lun =		255,
+	.cmd_per_lun =		2048,
 	.this_id =		-1,
 	.use_clustering =	ENABLE_CLUSTERING,
 	/* Make sure we dont get a sg segment crosses a page boundary */
 	.dma_boundary =		PAGE_SIZE-1,
 	.no_write_same =	1,
+	.track_queue_depth =	1,
 };
 
 enum {
@@ -1542,6 +1730,7 @@
 	struct Scsi_Host *host;
 	struct hv_host_device *host_dev;
 	bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
+	bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false);
 	int target = 0;
 	struct storvsc_device *stor_device;
 	int max_luns_per_target;
@@ -1599,7 +1788,7 @@
 	hv_set_drvdata(device, stor_device);
 
 	stor_device->port_number = host->host_no;
-	ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
+	ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc);
 	if (ret)
 		goto err_out1;
 
@@ -1611,6 +1800,9 @@
 		host->max_lun = STORVSC_FC_MAX_LUNS_PER_TARGET;
 		host->max_id = STORVSC_FC_MAX_TARGETS;
 		host->max_channel = STORVSC_FC_MAX_CHANNELS - 1;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+		host->transportt = fc_transport_template;
+#endif
 		break;
 
 	case SCSI_GUID:
@@ -1633,6 +1825,16 @@
 	 * from the host.
 	 */
 	host->sg_tablesize = (stor_device->max_transfer_bytes >> PAGE_SHIFT);
+#if defined(CONFIG_X86_32)
+	dev_warn(&device->device, "adjusting sg_tablesize 0x%x -> 0x%x",
+			host->sg_tablesize, MAX_MULTIPAGE_BUFFER_COUNT);
+	host->sg_tablesize = MAX_MULTIPAGE_BUFFER_COUNT;
+#endif
+	/*
+	 * Set the number of HW queues we are supporting.
+	 */
+	if (stor_device->num_sc != 0)
+		host->nr_hw_queues = stor_device->num_sc + 1;
 
 	/* Register the HBA and start the scsi bus scan */
 	ret = scsi_add_host(host, &device->device);
@@ -1650,6 +1852,12 @@
 			goto err_out2;
 		}
 	}
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+	if (host->transportt == fc_transport_template) {
+		fc_host_node_name(host) = stor_device->node_name;
+		fc_host_port_name(host) = stor_device->port_name;
+	}
+#endif
 	return 0;
 
 err_out2:
@@ -1663,6 +1871,7 @@
 	goto err_out0;
 
 err_out1:
+	kfree(stor_device->stor_chns);
 	kfree(stor_device);
 
 err_out0:
@@ -1675,6 +1884,10 @@
 	struct storvsc_device *stor_device = hv_get_drvdata(dev);
 	struct Scsi_Host *host = stor_device->host;
 
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+	if (host->transportt == fc_transport_template)
+		fc_remove_host(host);
+#endif
 	scsi_remove_host(host);
 	storvsc_dev_remove(dev);
 	scsi_host_put(host);
@@ -1689,8 +1902,16 @@
 	.remove = storvsc_remove,
 };
 
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct fc_function_template fc_transport_functions = {
+	.show_host_node_name = 1,
+	.show_host_port_name = 1,
+};
+#endif
+
 static int __init storvsc_drv_init(void)
 {
+	int ret;
 
 	/*
 	 * Divide the ring buffer data size (which is 1 page less
@@ -1705,12 +1926,33 @@
 		vmscsi_size_delta,
 		sizeof(u64)));
 
-	return vmbus_driver_register(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+	fc_transport_template = fc_attach_transport(&fc_transport_functions);
+	if (!fc_transport_template)
+		return -ENODEV;
+
+	/*
+	 * Install Hyper-V specific timeout handler.
+	 */
+	fc_transport_template->eh_timed_out = storvsc_eh_timed_out;
+#endif
+
+	ret = vmbus_driver_register(&storvsc_drv);
+
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+	if (ret)
+		fc_release_transport(fc_transport_template);
+#endif
+
+	return ret;
 }
 
 static void __exit storvsc_drv_exit(void)
 {
 	vmbus_driver_unregister(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+	fc_release_transport(fc_transport_template);
+#endif
 }
 
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ linux-4.4.0/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -536,7 +536,7 @@
 	 *  Look for the greatest clock divisor that allows an 
 	 *  input speed faster than the period.
 	 */
-	while (div-- > 0)
+	while (--div > 0)
 		if (kpc >= (div_10M[div] << 2)) break;
 
 	/*
@@ -4371,6 +4371,13 @@
 	OUTB(np, HS_PRT, HS_BUSY);
 }
 
+#define sym_printk(lvl, tp, cp, fmt, v...) do { \
+	if (cp)							\
+		scmd_printk(lvl, cp->cmd, fmt, ##v);		\
+	else							\
+		starget_printk(lvl, tp->starget, fmt, ##v);	\
+} while (0)
+
 /*
  *  chip exception handler for programmed interrupts.
  */
@@ -4416,7 +4423,7 @@
 	 *  been selected with ATN.  We do not want to handle that.
 	 */
 	case SIR_SEL_ATN_NO_MSG_OUT:
-		scmd_printk(KERN_WARNING, cp->cmd,
+		sym_printk(KERN_WARNING, tp, cp,
 				"No MSG OUT phase after selection with ATN\n");
 		goto out_stuck;
 	/*
@@ -4424,7 +4431,7 @@
 	 *  having reselected the initiator.
 	 */
 	case SIR_RESEL_NO_MSG_IN:
-		scmd_printk(KERN_WARNING, cp->cmd,
+		sym_printk(KERN_WARNING, tp, cp,
 				"No MSG IN phase after reselection\n");
 		goto out_stuck;
 	/*
@@ -4432,7 +4439,7 @@
 	 *  an IDENTIFY.
 	 */
 	case SIR_RESEL_NO_IDENTIFY:
-		scmd_printk(KERN_WARNING, cp->cmd,
+		sym_printk(KERN_WARNING, tp, cp,
 				"No IDENTIFY after reselection\n");
 		goto out_stuck;
 	/*
@@ -4461,7 +4468,7 @@
 	case SIR_RESEL_ABORTED:
 		np->lastmsg = np->msgout[0];
 		np->msgout[0] = M_NOOP;
-		scmd_printk(KERN_WARNING, cp->cmd,
+		sym_printk(KERN_WARNING, tp, cp,
 			"message %x sent on bad reselection\n", np->lastmsg);
 		goto out;
 	/*
--- linux-4.4.0.orig/drivers/scsi/ufs/ufs-qcom.c
+++ linux-4.4.0/drivers/scsi/ufs/ufs-qcom.c
@@ -1032,7 +1032,7 @@
 		hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
 	}
 
-	if (host->hw_ver.major >= 0x2) {
+	if (host->hw_ver.major == 0x2) {
 		hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
 
 		if (!ufs_qcom_cap_qunipro(host))
@@ -1552,6 +1552,7 @@
 	{ .compatible = "qcom,ufshc"},
 	{},
 };
+MODULE_DEVICE_TABLE(of, ufs_qcom_of_match);
 
 static const struct dev_pm_ops ufs_qcom_pm_ops = {
 	.suspend	= ufshcd_pltfrm_suspend,
--- linux-4.4.0.orig/drivers/scsi/ufs/ufs.h
+++ linux-4.4.0/drivers/scsi/ufs/ufs.h
@@ -45,6 +45,7 @@
 #define QUERY_DESC_MIN_SIZE       2
 #define QUERY_OSF_SIZE            (GENERAL_UPIU_REQUEST_SIZE - \
 					(sizeof(struct utp_upiu_header)))
+#define RESPONSE_UPIU_SENSE_DATA_LENGTH	18
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
 			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
@@ -383,7 +384,7 @@
 	__be32 residual_transfer_count;
 	__be32 reserved[4];
 	__be16 sense_data_len;
-	u8 sense_data[18];
+	u8 sense_data[RESPONSE_UPIU_SENSE_DATA_LENGTH];
 };
 
 /**
--- linux-4.4.0.orig/drivers/scsi/ufs/ufshcd-pci.c
+++ linux-4.4.0/drivers/scsi/ufs/ufshcd-pci.c
@@ -104,6 +104,7 @@
 	pm_runtime_forbid(&pdev->dev);
 	pm_runtime_get_noresume(&pdev->dev);
 	ufshcd_remove(hba);
+	ufshcd_dealloc_host(hba);
 }
 
 /**
@@ -147,6 +148,7 @@
 	err = ufshcd_init(hba, mmio_base, pdev->irq);
 	if (err) {
 		dev_err(&pdev->dev, "Initialization failed\n");
+		ufshcd_dealloc_host(hba);
 		return err;
 	}
 
--- linux-4.4.0.orig/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ linux-4.4.0/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -161,7 +161,7 @@
 	if (ret) {
 		dev_err(dev, "%s: unable to find %s err %d\n",
 				__func__, prop_name, ret);
-		goto out_free;
+		goto out;
 	}
 
 	vreg->min_uA = 0;
@@ -183,9 +183,6 @@
 
 	goto out;
 
-out_free:
-	devm_kfree(dev, vreg);
-	vreg = NULL;
 out:
 	if (!ret)
 		*out_vreg = vreg;
--- linux-4.4.0.orig/drivers/scsi/ufs/ufshcd.c
+++ linux-4.4.0/drivers/scsi/ufs/ufshcd.c
@@ -575,6 +575,7 @@
 int ufshcd_hold(struct ufs_hba *hba, bool async)
 {
 	int rc = 0;
+	bool flush_result;
 	unsigned long flags;
 
 	if (!ufshcd_is_clkgating_allowed(hba))
@@ -585,6 +586,28 @@
 start:
 	switch (hba->clk_gating.state) {
 	case CLKS_ON:
+		/*
+		 * Wait for the ungate work to complete if in progress.
+		 * Though the clocks may be in ON state, the link could
+		 * still be in hibner8 state if hibern8 is allowed
+		 * during clock gating.
+		 * Make sure we exit hibern8 state also in addition to
+		 * clocks being ON.
+		 */
+		if (ufshcd_can_hibern8_during_gating(hba) &&
+		    ufshcd_is_link_hibern8(hba)) {
+			if (async) {
+				rc = -EAGAIN;
+				hba->clk_gating.active_reqs--;
+				break;
+			}
+			spin_unlock_irqrestore(hba->host->host_lock, flags);
+			flush_result = flush_work(&hba->clk_gating.ungate_work);
+			if (hba->clk_gating.is_suspended && !flush_result)
+				goto out;
+			spin_lock_irqsave(hba->host->host_lock, flags);
+			goto start;
+		}
 		break;
 	case REQ_CLKS_OFF:
 		if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
@@ -813,10 +836,14 @@
 	int len;
 	if (lrbp->sense_buffer &&
 	    ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
+		int len_to_copy;
+
 		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
+		len_to_copy = min_t(int, RESPONSE_UPIU_SENSE_DATA_LENGTH, len);
+
 		memcpy(lrbp->sense_buffer,
 			lrbp->ucd_rsp_ptr->sr.sense_data,
-			min_t(int, len, SCSI_SENSE_BUFFERSIZE));
+			min_t(int, len_to_copy, SCSI_SENSE_BUFFERSIZE));
 	}
 }
 
@@ -834,7 +861,8 @@
 	memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, QUERY_OSF_SIZE);
 
 	/* Get the descriptor */
-	if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
+	if (hba->dev_cmd.query.descriptor &&
+	    lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
 		u8 *descp = (u8 *)lrbp->ucd_rsp_ptr +
 				GENERAL_UPIU_REQUEST_SIZE;
 		u16 resp_len;
@@ -1349,6 +1377,7 @@
 	ufshcd_compose_upiu(hba, lrbp);
 	err = ufshcd_map_sg(lrbp);
 	if (err) {
+		ufshcd_release(hba);
 		lrbp->cmd = NULL;
 		clear_bit_unlock(tag, &hba->lrb_in_use);
 		goto out;
@@ -1789,10 +1818,10 @@
 		goto out_unlock;
 	}
 
-	hba->dev_cmd.query.descriptor = NULL;
 	*buf_len = be16_to_cpu(response->upiu_res.length);
 
 out_unlock:
+	hba->dev_cmd.query.descriptor = NULL;
 	mutex_unlock(&hba->dev_cmd.lock);
 out:
 	ufshcd_release(hba);
@@ -2923,6 +2952,8 @@
 	/* REPORT SUPPORTED OPERATION CODES is not supported */
 	sdev->no_report_opcodes = 1;
 
+	/* WRITE_SAME command is not supported */
+	sdev->no_write_same = 1;
 
 	ufshcd_set_queue_depth(sdev);
 
@@ -3340,18 +3371,25 @@
 }
 
 /**
- * ufshcd_force_reset_auto_bkops - force enable of auto bkops
+ * ufshcd_force_reset_auto_bkops - force reset auto bkops state
  * @hba: per adapter instance
  *
  * After a device reset the device may toggle the BKOPS_EN flag
  * to default value. The s/w tracking variables should be updated
- * as well. Do this by forcing enable of auto bkops.
+ * as well. This function would change the auto-bkops state based on
+ * UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND.
  */
-static void  ufshcd_force_reset_auto_bkops(struct ufs_hba *hba)
+static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba)
 {
-	hba->auto_bkops_enabled = false;
-	hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS;
-	ufshcd_enable_auto_bkops(hba);
+	if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) {
+		hba->auto_bkops_enabled = false;
+		hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS;
+		ufshcd_enable_auto_bkops(hba);
+	} else {
+		hba->auto_bkops_enabled = true;
+		hba->ee_ctrl_mask &= ~MASK_EE_URGENT_BKOPS;
+		ufshcd_disable_auto_bkops(hba);
+	}
 }
 
 static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status)
@@ -3438,6 +3476,7 @@
 	hba = container_of(work, struct ufs_hba, eeh_work);
 
 	pm_runtime_get_sync(hba->dev);
+	scsi_block_requests(hba->host);
 	err = ufshcd_get_ee_status(hba, &status);
 	if (err) {
 		dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -3453,6 +3492,7 @@
 					__func__, err);
 	}
 out:
+	scsi_unblock_requests(hba->host);
 	pm_runtime_put_sync(hba->dev);
 	return;
 }
@@ -3778,19 +3818,16 @@
 {
 	struct Scsi_Host *host;
 	struct ufs_hba *hba;
-	unsigned int tag;
 	u32 pos;
 	int err;
-	u8 resp = 0xF;
-	struct ufshcd_lrb *lrbp;
+	u8 resp = 0xF, lun;
 	unsigned long flags;
 
 	host = cmd->device->host;
 	hba = shost_priv(host);
-	tag = cmd->request->tag;
 
-	lrbp = &hba->lrb[tag];
-	err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0, UFS_LOGICAL_RESET, &resp);
+	lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
+	err = ufshcd_issue_tm_cmd(hba, lun, 0, UFS_LOGICAL_RESET, &resp);
 	if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
 		if (!err)
 			err = resp;
@@ -3799,7 +3836,7 @@
 
 	/* clear the commands that were pending for corresponding LUN */
 	for_each_set_bit(pos, &hba->outstanding_reqs, hba->nutrs) {
-		if (hba->lrb[pos].lun == lrbp->lun) {
+		if (hba->lrb[pos].lun == lun) {
 			err = ufshcd_clear_cmd(hba, pos);
 			if (err)
 				break;
@@ -3912,6 +3949,8 @@
 	clear_bit_unlock(tag, &hba->lrb_in_use);
 	wake_up(&hba->dev_cmd.tag_wq);
 
+	lrbp->cmd = NULL;
+
 out:
 	if (!err) {
 		err = SUCCESS;
@@ -4114,19 +4153,19 @@
 		goto out;
 	}
 
-	if (hba->vreg_info.vcc)
+	if (hba->vreg_info.vcc && hba->vreg_info.vcc->max_uA)
 		icc_level = ufshcd_get_max_icc_level(
 				hba->vreg_info.vcc->max_uA,
 				POWER_DESC_MAX_ACTV_ICC_LVLS - 1,
 				&desc_buf[PWR_DESC_ACTIVE_LVLS_VCC_0]);
 
-	if (hba->vreg_info.vccq)
+	if (hba->vreg_info.vccq && hba->vreg_info.vccq->max_uA)
 		icc_level = ufshcd_get_max_icc_level(
 				hba->vreg_info.vccq->max_uA,
 				icc_level,
 				&desc_buf[PWR_DESC_ACTIVE_LVLS_VCCQ_0]);
 
-	if (hba->vreg_info.vccq2)
+	if (hba->vreg_info.vccq2 && hba->vreg_info.vccq2->max_uA)
 		icc_level = ufshcd_get_max_icc_level(
 				hba->vreg_info.vccq2->max_uA,
 				icc_level,
@@ -4293,7 +4332,8 @@
 			ufshcd_init_icc_levels(hba);
 
 		/* Add required well known logical units to scsi mid layer */
-		if (ufshcd_scsi_add_wlus(hba))
+		ret = ufshcd_scsi_add_wlus(hba);
+		if (ret)
 			goto out;
 
 		scsi_scan_host(hba->host);
@@ -4360,6 +4400,15 @@
 	if (!vreg)
 		return 0;
 
+	/*
+	 * "set_load" operation shall be required on those regulators
+	 * which specifically configured current limitation. Otherwise
+	 * zero max_uA may cause unexpected behavior when regulator is
+	 * enabled or set as high power mode.
+	 */
+	if (!vreg->max_uA)
+		return 0;
+
 	ret = regulator_set_load(vreg->reg, ua);
 	if (ret < 0) {
 		dev_err(dev, "%s: %s set load (ua=%d) failed, err=%d\n",
@@ -4378,6 +4427,9 @@
 static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
 					 struct ufs_vreg *vreg)
 {
+	if (!vreg)
+		return 0;
+
 	return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
 }
 
@@ -4385,19 +4437,25 @@
 		struct ufs_vreg *vreg, bool on)
 {
 	int ret = 0;
-	struct regulator *reg = vreg->reg;
-	const char *name = vreg->name;
+	struct regulator *reg;
+	const char *name;
 	int min_uV, uA_load;
 
 	BUG_ON(!vreg);
 
+	reg = vreg->reg;
+	name = vreg->name;
+
 	if (regulator_count_voltages(reg) > 0) {
-		min_uV = on ? vreg->min_uV : 0;
-		ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
-		if (ret) {
-			dev_err(dev, "%s: %s set voltage failed, err=%d\n",
+		if (vreg->min_uV && vreg->max_uV) {
+			min_uV = on ? vreg->min_uV : 0;
+			ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
+			if (ret) {
+				dev_err(dev,
+					"%s: %s set voltage failed, err=%d\n",
 					__func__, name, ret);
-			goto out;
+				goto out;
+			}
 		}
 
 		uA_load = on ? vreg->max_uA : 0;
@@ -5149,11 +5207,15 @@
 			goto set_old_link_state;
 	}
 
-	/*
-	 * If BKOPs operations are urgently needed at this moment then
-	 * keep auto-bkops enabled or else disable it.
-	 */
-	ufshcd_urgent_bkops(hba);
+	if (ufshcd_keep_autobkops_enabled_except_suspend(hba))
+		ufshcd_enable_auto_bkops(hba);
+	else
+		/*
+		 * If BKOPs operations are urgently needed at this moment then
+		 * keep auto-bkops enabled or else disable it.
+		 */
+		ufshcd_urgent_bkops(hba);
+
 	hba->clk_gating.is_suspended = false;
 
 	if (ufshcd_is_clkscaling_enabled(hba))
@@ -5233,7 +5295,10 @@
 
 int ufshcd_system_resume(struct ufs_hba *hba)
 {
-	if (!hba || !hba->is_powered || pm_runtime_suspended(hba->dev))
+	if (!hba)
+		return -EINVAL;
+
+	if (!hba->is_powered || pm_runtime_suspended(hba->dev))
 		/*
 		 * Let the runtime resume take care of resuming
 		 * if runtime suspended.
@@ -5254,7 +5319,10 @@
  */
 int ufshcd_runtime_suspend(struct ufs_hba *hba)
 {
-	if (!hba || !hba->is_powered)
+	if (!hba)
+		return -EINVAL;
+
+	if (!hba->is_powered)
 		return 0;
 
 	return ufshcd_suspend(hba, UFS_RUNTIME_PM);
@@ -5284,10 +5352,13 @@
  */
 int ufshcd_runtime_resume(struct ufs_hba *hba)
 {
-	if (!hba || !hba->is_powered)
+	if (!hba)
+		return -EINVAL;
+
+	if (!hba->is_powered)
 		return 0;
-	else
-		return ufshcd_resume(hba, UFS_RUNTIME_PM);
+
+	return ufshcd_resume(hba, UFS_RUNTIME_PM);
 }
 EXPORT_SYMBOL(ufshcd_runtime_resume);
 
@@ -5309,14 +5380,13 @@
 {
 	int ret = 0;
 
+	if (!hba->is_powered)
+		goto out;
+
 	if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba))
 		goto out;
 
-	if (pm_runtime_suspended(hba->dev)) {
-		ret = ufshcd_runtime_resume(hba);
-		if (ret)
-			goto out;
-	}
+	pm_runtime_get_sync(hba->dev);
 
 	ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM);
 out:
@@ -5339,8 +5409,6 @@
 	ufshcd_disable_intr(hba, hba->intr_mask);
 	ufshcd_hba_stop(hba);
 
-	scsi_host_put(hba->host);
-
 	ufshcd_exit_clk_gating(hba);
 	if (ufshcd_is_clkscaling_enabled(hba))
 		devfreq_remove_device(hba->devfreq);
@@ -5465,15 +5533,47 @@
 {
 	int err = 0;
 	struct ufs_hba *hba = dev_get_drvdata(dev);
+	bool release_clk_hold = false;
+	unsigned long irq_flags;
 
 	if (!ufshcd_is_clkscaling_enabled(hba))
 		return -EINVAL;
 
+	spin_lock_irqsave(hba->host->host_lock, irq_flags);
+	if (ufshcd_eh_in_progress(hba)) {
+		spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+		return 0;
+	}
+
+	if (ufshcd_is_clkgating_allowed(hba) &&
+	    (hba->clk_gating.state != CLKS_ON)) {
+		if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
+			/* hold the vote until the scaling work is completed */
+			hba->clk_gating.active_reqs++;
+			release_clk_hold = true;
+			hba->clk_gating.state = CLKS_ON;
+		} else {
+			/*
+			 * Clock gating work seems to be running in parallel
+			 * hence skip scaling work to avoid deadlock between
+			 * current scaling work and gating work.
+			 */
+			spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+			return 0;
+		}
+	}
+	spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
 	if (*freq == UINT_MAX)
 		err = ufshcd_scale_clks(hba, true);
 	else if (*freq == 0)
 		err = ufshcd_scale_clks(hba, false);
 
+	spin_lock_irqsave(hba->host->host_lock, irq_flags);
+	if (release_clk_hold)
+		__ufshcd_release(hba);
+	spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
 	return err;
 }
 
@@ -5655,7 +5755,6 @@
 	ufshcd_exit_clk_gating(hba);
 out_disable:
 	hba->is_irq_enabled = false;
-	scsi_host_put(host);
 	ufshcd_hba_exit(hba);
 out_error:
 	return err;
--- linux-4.4.0.orig/drivers/scsi/ufs/ufshcd.h
+++ linux-4.4.0/drivers/scsi/ufs/ufshcd.h
@@ -528,6 +528,14 @@
 	 * CAUTION: Enabling this might reduce overall UFS throughput.
 	 */
 #define UFSHCD_CAP_INTR_AGGR (1 << 4)
+	/*
+	 * This capability allows the device auto-bkops to be always enabled
+	 * except during suspend (both runtime and suspend).
+	 * Enabling this capability means that device will always be allowed
+	 * to do background operation when it's active but it might degrade
+	 * the performance of ongoing read/write operations.
+	 */
+#define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5)
 
 	struct devfreq *devfreq;
 	struct ufs_clk_scaling clk_scaling;
@@ -623,6 +631,11 @@
 	BUG_ON(!hba);
 	return hba->priv;
 }
+static inline bool ufshcd_keep_autobkops_enabled_except_suspend(
+							struct ufs_hba *hba)
+{
+	return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND;
+}
 
 extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
 extern int ufshcd_runtime_resume(struct ufs_hba *hba);
--- linux-4.4.0.orig/drivers/scsi/virtio_scsi.c
+++ linux-4.4.0/drivers/scsi/virtio_scsi.c
@@ -28,6 +28,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_devinfo.h>
 #include <linux/seqlock.h>
 
 #define VIRTIO_SCSI_MEMPOOL_SZ 64
@@ -533,7 +534,9 @@
 {
 	struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
 	struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc);
+	unsigned long flags;
 	int req_size;
+	int ret;
 
 	BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
 
@@ -561,8 +564,19 @@
 		req_size = sizeof(cmd->req.cmd);
 	}
 
-	if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 0)
+	ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd));
+	if (ret == -EIO) {
+		cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
+		spin_lock_irqsave(&req_vq->vq_lock, flags);
+		virtscsi_complete_cmd(vscsi, cmd);
+		spin_unlock_irqrestore(&req_vq->vq_lock, flags);
+	} else if (ret != 0) {
+		/* The SCSI command requeue will increment 'tgt->reqs' again. */
+		struct virtio_scsi_target_state *tgt =
+				scsi_target(sc->device)->hostdata;
+		atomic_dec(&tgt->reqs);
 		return SCSI_MLQUEUE_HOST_BUSY;
+	}
 	return 0;
 }
 
@@ -578,11 +592,12 @@
 }
 
 static struct virtio_scsi_vq *virtscsi_pick_vq_mq(struct virtio_scsi *vscsi,
-						  struct scsi_cmnd *sc)
+						  struct virtio_scsi_target_state *tgt, struct scsi_cmnd *sc)
 {
 	u32 tag = blk_mq_unique_tag(sc->request);
 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
 
+	atomic_inc(&tgt->reqs);
 	return &vscsi->req_vqs[hwq];
 }
 
@@ -632,7 +647,7 @@
 	struct virtio_scsi_vq *req_vq;
 
 	if (shost_use_blk_mq(sh))
-		req_vq = virtscsi_pick_vq_mq(vscsi, sc);
+		req_vq = virtscsi_pick_vq_mq(vscsi, tgt, sc);
 	else
 		req_vq = virtscsi_pick_vq(vscsi, tgt);
 
@@ -682,7 +697,6 @@
 		return FAILED;
 
 	memset(cmd, 0, sizeof(*cmd));
-	cmd->sc = sc;
 	cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
 		.type = VIRTIO_SCSI_T_TMF,
 		.subtype = cpu_to_virtio32(vscsi->vdev,
@@ -695,6 +709,28 @@
 	return virtscsi_tmf(vscsi, cmd);
 }
 
+static int virtscsi_device_alloc(struct scsi_device *sdevice)
+{
+	/*
+	 * Passed through SCSI targets (e.g. with qemu's 'scsi-block')
+	 * may have transfer limits which come from the host SCSI
+	 * controller or something on the host side other than the
+	 * target itself.
+	 *
+	 * To make this work properly, the hypervisor can adjust the
+	 * target's VPD information to advertise these limits.  But
+	 * for that to work, the guest has to look at the VPD pages,
+	 * which we won't do by default if it is an SPC-2 device, even
+	 * if it does actually support it.
+	 *
+	 * So, set the blist to always try to read the VPD pages.
+	 */
+	sdevice->sdev_bflags = BLIST_TRY_VPD_PAGES;
+
+	return 0;
+}
+
+
 /**
  * virtscsi_change_queue_depth() - Change a virtscsi target's queue depth
  * @sdev:	Virtscsi target whose queue depth to change
@@ -719,7 +755,6 @@
 		return FAILED;
 
 	memset(cmd, 0, sizeof(*cmd));
-	cmd->sc = sc;
 	cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
 		.type = VIRTIO_SCSI_T_TMF,
 		.subtype = VIRTIO_SCSI_T_TMF_ABORT_TASK,
@@ -753,6 +788,10 @@
 static void virtscsi_target_destroy(struct scsi_target *starget)
 {
 	struct virtio_scsi_target_state *tgt = starget->hostdata;
+
+	/* we can race with concurrent virtscsi_complete_cmd */
+	while (atomic_read(&tgt->reqs))
+		cpu_relax();
 	kfree(tgt);
 }
 
@@ -766,6 +805,7 @@
 	.change_queue_depth = virtscsi_change_queue_depth,
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
+	.slave_alloc = virtscsi_device_alloc,
 
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,
@@ -786,6 +826,7 @@
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
 
+	.slave_alloc = virtscsi_device_alloc,
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,
 	.use_clustering = ENABLE_CLUSTERING,
--- linux-4.4.0.orig/drivers/scsi/vmw_pvscsi.c
+++ linux-4.4.0/drivers/scsi/vmw_pvscsi.c
@@ -545,9 +545,14 @@
 	    (btstat == BTSTAT_SUCCESS ||
 	     btstat == BTSTAT_LINKED_COMMAND_COMPLETED ||
 	     btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) {
-		cmd->result = (DID_OK << 16) | sdstat;
-		if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer)
-			cmd->result |= (DRIVER_SENSE << 24);
+		if (sdstat == SAM_STAT_COMMAND_TERMINATED) {
+			cmd->result = (DID_RESET << 16);
+		} else {
+			cmd->result = (DID_OK << 16) | sdstat;
+			if (sdstat == SAM_STAT_CHECK_CONDITION &&
+			    cmd->sense_buffer)
+				cmd->result |= (DRIVER_SENSE << 24);
+		}
 	} else
 		switch (btstat) {
 		case BTSTAT_SUCCESS:
@@ -728,6 +733,7 @@
 	struct pvscsi_adapter *adapter = shost_priv(host);
 	struct pvscsi_ctx *ctx;
 	unsigned long flags;
+	unsigned char op;
 
 	spin_lock_irqsave(&adapter->hw_lock, flags);
 
@@ -740,13 +746,14 @@
 	}
 
 	cmd->scsi_done = done;
+	op = cmd->cmnd[0];
 
 	dev_dbg(&cmd->device->sdev_gendev,
-		"queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]);
+		"queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op);
 
 	spin_unlock_irqrestore(&adapter->hw_lock, flags);
 
-	pvscsi_kick_io(adapter, cmd->cmnd[0]);
+	pvscsi_kick_io(adapter, op);
 
 	return 0;
 }
@@ -1194,8 +1201,6 @@
 
 static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
 {
-	pvscsi_shutdown_intr(adapter);
-
 	if (adapter->workqueue)
 		destroy_workqueue(adapter->workqueue);
 
@@ -1524,6 +1529,7 @@
 out_reset_adapter:
 	ll_adapter_reset(adapter);
 out_release_resources:
+	pvscsi_shutdown_intr(adapter);
 	pvscsi_release_resources(adapter);
 	scsi_host_put(host);
 out_disable_device:
@@ -1532,6 +1538,7 @@
 	return error;
 
 out_release_resources_and_disable:
+	pvscsi_shutdown_intr(adapter);
 	pvscsi_release_resources(adapter);
 	goto out_disable_device;
 }
--- linux-4.4.0.orig/drivers/scsi/xen-scsifront.c
+++ linux-4.4.0/drivers/scsi/xen-scsifront.c
@@ -676,10 +676,17 @@
 static int scsifront_sdev_configure(struct scsi_device *sdev)
 {
 	struct vscsifrnt_info *info = shost_priv(sdev->host);
+	int err;
 
-	if (info && current == info->curr)
-		xenbus_printf(XBT_NIL, info->dev->nodename,
+	if (info && current == info->curr) {
+		err = xenbus_printf(XBT_NIL, info->dev->nodename,
 			      info->dev_state_path, "%d", XenbusStateConnected);
+		if (err) {
+			xenbus_dev_error(info->dev, err,
+				"%s: writing dev_state_path", __func__);
+			return err;
+		}
+	}
 
 	return 0;
 }
@@ -687,10 +694,15 @@
 static void scsifront_sdev_destroy(struct scsi_device *sdev)
 {
 	struct vscsifrnt_info *info = shost_priv(sdev->host);
+	int err;
 
-	if (info && current == info->curr)
-		xenbus_printf(XBT_NIL, info->dev->nodename,
+	if (info && current == info->curr) {
+		err = xenbus_printf(XBT_NIL, info->dev->nodename,
 			      info->dev_state_path, "%d", XenbusStateClosed);
+		if (err)
+			xenbus_dev_error(info->dev, err,
+				"%s: writing dev_state_path", __func__);
+	}
 }
 
 static struct scsi_host_template scsifront_sht = {
@@ -1025,9 +1037,12 @@
 
 			if (scsi_add_device(info->host, chn, tgt, lun)) {
 				dev_err(&dev->dev, "scsi_add_device\n");
-				xenbus_printf(XBT_NIL, dev->nodename,
+				err = xenbus_printf(XBT_NIL, dev->nodename,
 					      info->dev_state_path,
 					      "%d", XenbusStateClosed);
+				if (err)
+					xenbus_dev_error(dev, err,
+						"%s: writing dev_state_path", __func__);
 			}
 			break;
 		case VSCSIFRONT_OP_DEL_LUN:
@@ -1041,10 +1056,14 @@
 			}
 			break;
 		case VSCSIFRONT_OP_READD_LUN:
-			if (device_state == XenbusStateConnected)
-				xenbus_printf(XBT_NIL, dev->nodename,
+			if (device_state == XenbusStateConnected) {
+				err = xenbus_printf(XBT_NIL, dev->nodename,
 					      info->dev_state_path,
 					      "%d", XenbusStateConnected);
+				if (err)
+					xenbus_dev_error(dev, err,
+						"%s: writing dev_state_path", __func__);
+			}
 			break;
 		default:
 			break;
--- linux-4.4.0.orig/drivers/sh/intc/core.c
+++ linux-4.4.0/drivers/sh/intc/core.c
@@ -194,7 +194,6 @@
 		goto err0;
 
 	INIT_LIST_HEAD(&d->list);
-	list_add_tail(&d->list, &intc_list);
 
 	raw_spin_lock_init(&d->lock);
 	INIT_RADIX_TREE(&d->tree, GFP_ATOMIC);
@@ -380,6 +379,7 @@
 
 	d->skip_suspend = desc->skip_syscore_suspend;
 
+	list_add_tail(&d->list, &intc_list);
 	nr_intc_controllers++;
 
 	return 0;
--- linux-4.4.0.orig/drivers/sh/pm_runtime.c
+++ linux-4.4.0/drivers/sh/pm_runtime.c
@@ -34,7 +34,7 @@
 
 static int __init sh_pm_runtime_init(void)
 {
-	if (IS_ENABLED(CONFIG_ARCH_SHMOBILE)) {
+	if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_ARCH_SHMOBILE)) {
 		if (!of_find_compatible_node(NULL, NULL,
 					     "renesas,cpg-mstp-clocks"))
 			return 0;
--- linux-4.4.0.orig/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ linux-4.4.0/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -591,7 +591,7 @@
 static int pwrap_init_cipher(struct pmic_wrapper *wrp)
 {
 	int ret;
-	u32 rdata;
+	u32 rdata = 0;
 
 	pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
 	pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST);
--- linux-4.4.0.orig/drivers/soc/qcom/qcom_gsbi.c
+++ linux-4.4.0/drivers/soc/qcom/qcom_gsbi.c
@@ -138,7 +138,7 @@
 	struct resource *res;
 	void __iomem *base;
 	struct gsbi_info *gsbi;
-	int i;
+	int i, ret;
 	u32 mask, gsbi_num;
 	const struct crci_config *config = NULL;
 
@@ -221,7 +221,10 @@
 
 	platform_set_drvdata(pdev, gsbi);
 
-	return of_platform_populate(node, NULL, NULL, &pdev->dev);
+	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+	if (ret)
+		clk_disable_unprepare(gsbi->hclk);
+	return ret;
 }
 
 static int gsbi_remove(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/soc/qcom/smem.c
+++ linux-4.4.0/drivers/soc/qcom/smem.c
@@ -646,7 +646,7 @@
 			return -EINVAL;
 		}
 
-		if (header->size != entry->size) {
+		if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
 			dev_err(smem->dev,
 				"Partition %d has invalid size\n", i);
 			return -EINVAL;
--- linux-4.4.0.orig/drivers/soc/qcom/spm.c
+++ linux-4.4.0/drivers/soc/qcom/spm.c
@@ -288,7 +288,7 @@
 	struct spm_driver_data *drv = NULL;
 	struct device_node *cpu_node, *saw_node;
 	int cpu;
-	bool found;
+	bool found = 0;
 
 	for_each_possible_cpu(cpu) {
 		cpu_node = of_cpu_device_node_get(cpu);
--- linux-4.4.0.orig/drivers/soc/rockchip/pm_domains.c
+++ linux-4.4.0/drivers/soc/rockchip/pm_domains.c
@@ -419,6 +419,7 @@
 		if (error) {
 			dev_err(dev, "failed to handle node %s: %d\n",
 				node->name, error);
+			of_node_put(node);
 			goto err_out;
 		}
 	}
--- linux-4.4.0.orig/drivers/soc/tegra/common.c
+++ linux-4.4.0/drivers/soc/tegra/common.c
@@ -22,11 +22,15 @@
 
 bool soc_is_tegra(void)
 {
+	const struct of_device_id *match;
 	struct device_node *root;
 
 	root = of_find_node_by_path("/");
 	if (!root)
 		return false;
 
-	return of_match_node(tegra_machine_match, root) != NULL;
+	match = of_match_node(tegra_machine_match, root);
+	of_node_put(root);
+
+	return match != NULL;
 }
--- linux-4.4.0.orig/drivers/soc/tegra/fuse/fuse-tegra.c
+++ linux-4.4.0/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -131,13 +131,17 @@
 	/* take over the memory region from the early initialization */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	fuse->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(fuse->base))
-		return PTR_ERR(fuse->base);
+	if (IS_ERR(fuse->base)) {
+		err = PTR_ERR(fuse->base);
+		fuse->base = base;
+		return err;
+	}
 
 	fuse->clk = devm_clk_get(&pdev->dev, "fuse");
 	if (IS_ERR(fuse->clk)) {
 		dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
 			PTR_ERR(fuse->clk));
+		fuse->base = base;
 		return PTR_ERR(fuse->clk);
 	}
 
@@ -146,8 +150,10 @@
 
 	if (fuse->soc->probe) {
 		err = fuse->soc->probe(fuse);
-		if (err < 0)
+		if (err < 0) {
+			fuse->base = base;
 			return err;
+		}
 	}
 
 	if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,
--- linux-4.4.0.orig/drivers/soc/tegra/fuse/speedo-tegra210.c
+++ linux-4.4.0/drivers/soc/tegra/fuse/speedo-tegra210.c
@@ -105,7 +105,7 @@
 	unsigned int i;
 
 	for (i = 0; i < num; i++)
-		if (value < speedos[num])
+		if (value < speedos[i])
 			return i;
 
 	return -EINVAL;
--- linux-4.4.0.orig/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ linux-4.4.0/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -134,7 +134,7 @@
 			apbmisc.flags = IORESOURCE_MEM;
 
 			/* strapping options */
-			if (tegra_get_chip_id() == TEGRA124) {
+			if (of_machine_is_compatible("nvidia,tegra124")) {
 				straps.start = 0x7000e864;
 				straps.end = 0x7000e867;
 			} else {
--- linux-4.4.0.orig/drivers/soc/tegra/pmc.c
+++ linux-4.4.0/drivers/soc/tegra/pmc.c
@@ -738,7 +738,7 @@
 	if (!pmc->soc->has_tsense_reset)
 		return;
 
-	np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip");
+	np = of_get_child_by_name(pmc->dev->of_node, "i2c-thermtrip");
 	if (!np) {
 		dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
 		return;
--- linux-4.4.0.orig/drivers/soc/ti/knav_dma.c
+++ linux-4.4.0/drivers/soc/ti/knav_dma.c
@@ -752,8 +752,9 @@
 	pm_runtime_enable(kdev->dev);
 	ret = pm_runtime_get_sync(kdev->dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(kdev->dev);
 		dev_err(kdev->dev, "unable to enable pktdma, err %d\n", ret);
-		return ret;
+		goto err_pm_disable;
 	}
 
 	/* Initialise all packet dmas */
@@ -767,13 +768,21 @@
 
 	if (list_empty(&kdev->list)) {
 		dev_err(dev, "no valid dma instance\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_put_sync;
 	}
 
 	debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL,
 			    &knav_dma_debug_ops);
 
 	return ret;
+
+err_put_sync:
+	pm_runtime_put_sync(kdev->dev);
+err_pm_disable:
+	pm_runtime_disable(kdev->dev);
+
+	return ret;
 }
 
 static int knav_dma_remove(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/soc/ti/knav_qmss_queue.c
+++ linux-4.4.0/drivers/soc/ti/knav_qmss_queue.c
@@ -1717,6 +1717,7 @@
 	pm_runtime_enable(&pdev->dev);
 	ret = pm_runtime_get_sync(&pdev->dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(&pdev->dev);
 		dev_err(dev, "Failed to enable QMSS\n");
 		return ret;
 	}
@@ -1784,9 +1785,10 @@
 	if (ret)
 		goto err;
 
-	regions =  of_get_child_by_name(node, "descriptor-regions");
+	regions = of_get_child_by_name(node, "descriptor-regions");
 	if (!regions) {
 		dev_err(dev, "descriptor-regions not specified\n");
+		ret = -ENODEV;
 		goto err;
 	}
 	ret = knav_queue_setup_regions(kdev, regions);
--- linux-4.4.0.orig/drivers/spi/Kconfig
+++ linux-4.4.0/drivers/spi/Kconfig
@@ -706,4 +706,7 @@
 
 # (slave support would go here)
 
+config SPI_DYNAMIC
+	def_bool ACPI || OF_DYNAMIC || SPI_SLAVE
+
 endif # SPI
--- linux-4.4.0.orig/drivers/spi/spi-atmel.c
+++ linux-4.4.0/drivers/spi/spi-atmel.c
@@ -315,7 +315,6 @@
 	struct atmel_spi_dma	dma;
 
 	bool			keep_cs;
-	bool			cs_active;
 
 	u32			fifo_size;
 };
@@ -1209,10 +1208,8 @@
 	as = spi_master_get_devdata(spi->master);
 
 	/* see notes above re chipselect */
-	if (!atmel_spi_is_v2(as)
-			&& spi->chip_select == 0
-			&& (spi->mode & SPI_CS_HIGH)) {
-		dev_dbg(&spi->dev, "setup: can't be active-high\n");
+	if (!as->use_cs_gpios && (spi->mode & SPI_CS_HIGH)) {
+		dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n");
 		return -EINVAL;
 	}
 
@@ -1406,11 +1403,9 @@
 				 &msg->transfers)) {
 			as->keep_cs = true;
 		} else {
-			as->cs_active = !as->cs_active;
-			if (as->cs_active)
-				cs_activate(as, msg->spi);
-			else
-				cs_deactivate(as, msg->spi);
+			cs_deactivate(as, msg->spi);
+			udelay(10);
+			cs_activate(as, msg->spi);
 		}
 	}
 
@@ -1433,7 +1428,6 @@
 	atmel_spi_lock(as);
 	cs_activate(as, spi);
 
-	as->cs_active = true;
 	as->keep_cs = false;
 
 	msg->status = 0;
@@ -1571,6 +1565,7 @@
 
 	as->use_cs_gpios = true;
 	if (atmel_spi_is_v2(as) &&
+	    pdev->dev.of_node &&
 	    !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) {
 		as->use_cs_gpios = false;
 		master->num_chipselect = 4;
@@ -1668,12 +1663,12 @@
 	pm_runtime_get_sync(&pdev->dev);
 
 	/* reset the hardware and block queue progress */
-	spin_lock_irq(&as->lock);
 	if (as->use_dma) {
 		atmel_spi_stop_dma(as);
 		atmel_spi_release_dma(as);
 	}
 
+	spin_lock_irq(&as->lock);
 	spi_writel(as, CR, SPI_BIT(SWRST));
 	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
 	spi_readl(as, SR);
--- linux-4.4.0.orig/drivers/spi/spi-bcm2835.c
+++ linux-4.4.0/drivers/spi/spi-bcm2835.c
@@ -88,7 +88,7 @@
 	u8 *rx_buf;
 	int tx_len;
 	int rx_len;
-	bool dma_pending;
+	unsigned int dma_pending;
 };
 
 static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg)
@@ -155,8 +155,7 @@
 	/* Write as many bytes as possible to FIFO */
 	bcm2835_wr_fifo(bs);
 
-	/* based on flags decide if we can finish the transfer */
-	if (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE) {
+	if (!bs->rx_len) {
 		/* Transfer complete - reset SPI HW */
 		bcm2835_spi_reset_hw(master);
 		/* wake up the framework */
@@ -233,10 +232,9 @@
 	 * is called the tx-dma must have finished - can't get to this
 	 * situation otherwise...
 	 */
-	dmaengine_terminate_all(master->dma_tx);
-
-	/* mark as no longer pending */
-	bs->dma_pending = 0;
+	if (cmpxchg(&bs->dma_pending, true, false)) {
+		dmaengine_terminate_all(master->dma_tx);
+	}
 
 	/* and mark as completed */;
 	complete(&master->xfer_completion);
@@ -342,6 +340,7 @@
 	if (ret) {
 		/* need to reset on errors */
 		dmaengine_terminate_all(master->dma_tx);
+		bs->dma_pending = false;
 		bcm2835_spi_reset_hw(master);
 		return ret;
 	}
@@ -555,7 +554,8 @@
 	bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
 
 	/* handle all the 3-wire mode */
-	if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
+	if (spi->mode & SPI_3WIRE && tfr->rx_buf &&
+	    tfr->rx_buf != master->dummy_rx)
 		cs |= BCM2835_SPI_CS_REN;
 	else
 		cs &= ~BCM2835_SPI_CS_REN;
@@ -617,10 +617,9 @@
 	struct bcm2835_spi *bs = spi_master_get_devdata(master);
 
 	/* if an error occurred and we have an active dma, then terminate */
-	if (bs->dma_pending) {
+	if (cmpxchg(&bs->dma_pending, true, false)) {
 		dmaengine_terminate_all(master->dma_tx);
 		dmaengine_terminate_all(master->dma_rx);
-		bs->dma_pending = 0;
 	}
 	/* and reset */
 	bcm2835_spi_reset_hw(master);
@@ -743,7 +742,7 @@
 	struct resource *res;
 	int err;
 
-	master = spi_alloc_master(&pdev->dev, sizeof(*bs));
+	master = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
 	if (!master) {
 		dev_err(&pdev->dev, "spi_alloc_master() failed\n");
 		return -ENOMEM;
@@ -765,23 +764,20 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	bs->regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(bs->regs)) {
-		err = PTR_ERR(bs->regs);
-		goto out_master_put;
-	}
+	if (IS_ERR(bs->regs))
+		return PTR_ERR(bs->regs);
 
 	bs->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(bs->clk)) {
 		err = PTR_ERR(bs->clk);
 		dev_err(&pdev->dev, "could not get clk: %d\n", err);
-		goto out_master_put;
+		return err;
 	}
 
 	bs->irq = platform_get_irq(pdev, 0);
 	if (bs->irq <= 0) {
 		dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
-		err = bs->irq ? bs->irq : -ENODEV;
-		goto out_master_put;
+		return bs->irq ? bs->irq : -ENODEV;
 	}
 
 	clk_prepare_enable(bs->clk);
@@ -796,21 +792,20 @@
 			       dev_name(&pdev->dev), master);
 	if (err) {
 		dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
-		goto out_clk_disable;
+		goto out_dma_release;
 	}
 
-	err = devm_spi_register_master(&pdev->dev, master);
+	err = spi_register_master(master);
 	if (err) {
 		dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
-		goto out_clk_disable;
+		goto out_dma_release;
 	}
 
 	return 0;
 
-out_clk_disable:
+out_dma_release:
+	bcm2835_dma_release(master);
 	clk_disable_unprepare(bs->clk);
-out_master_put:
-	spi_master_put(master);
 	return err;
 }
 
@@ -819,6 +814,8 @@
 	struct spi_master *master = platform_get_drvdata(pdev);
 	struct bcm2835_spi *bs = spi_master_get_devdata(master);
 
+	spi_unregister_master(master);
+
 	/* Clear FIFOs, and disable the HW block */
 	bcm2835_wr(bs, BCM2835_SPI_CS,
 		   BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
--- linux-4.4.0.orig/drivers/spi/spi-bcm2835aux.c
+++ linux-4.4.0/drivers/spi/spi-bcm2835aux.c
@@ -181,19 +181,14 @@
 		      BCM2835_AUX_SPI_CNTL0_CLEARFIFO);
 }
 
-static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
+static void bcm2835aux_spi_transfer_helper(struct bcm2835aux_spi *bs)
 {
-	struct spi_master *master = dev_id;
-	struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
-	irqreturn_t ret = IRQ_NONE;
+	u32 stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT);
 
 	/* check if we have data to read */
-	while (bs->rx_len &&
-	       (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
-		  BCM2835_AUX_SPI_STAT_RX_EMPTY))) {
+	for (; bs->rx_len && (stat & BCM2835_AUX_SPI_STAT_RX_LVL);
+	     stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT))
 		bcm2835aux_rd_fifo(bs);
-		ret = IRQ_HANDLED;
-	}
 
 	/* check if we have data to write */
 	while (bs->tx_len &&
@@ -201,16 +196,21 @@
 	       (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
 		  BCM2835_AUX_SPI_STAT_TX_FULL))) {
 		bcm2835aux_wr_fifo(bs);
-		ret = IRQ_HANDLED;
 	}
+}
 
-	/* and check if we have reached "done" */
-	while (bs->rx_len &&
-	       (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
-		  BCM2835_AUX_SPI_STAT_BUSY))) {
-		bcm2835aux_rd_fifo(bs);
-		ret = IRQ_HANDLED;
-	}
+static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
+{
+	struct spi_master *master = dev_id;
+	struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+
+	/* IRQ may be shared, so return if our interrupts are disabled */
+	if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) &
+	      (BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE)))
+		return IRQ_NONE;
+
+	/* do common fifo handling */
+	bcm2835aux_spi_transfer_helper(bs);
 
 	/* and if rx_len is 0 then wake up completion and disable spi */
 	if (!bs->rx_len) {
@@ -218,8 +218,7 @@
 		complete(&master->xfer_completion);
 	}
 
-	/* and return */
-	return ret;
+	return IRQ_HANDLED;
 }
 
 static int __bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
@@ -265,7 +264,6 @@
 {
 	struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
 	unsigned long timeout;
-	u32 stat;
 
 	/* configure spi */
 	bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
@@ -276,24 +274,9 @@
 
 	/* loop until finished the transfer */
 	while (bs->rx_len) {
-		/* read status */
-		stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT);
 
-		/* fill in tx fifo with remaining data */
-		if ((bs->tx_len) && (!(stat & BCM2835_AUX_SPI_STAT_TX_FULL))) {
-			bcm2835aux_wr_fifo(bs);
-			continue;
-		}
-
-		/* read data from fifo for both cases */
-		if (!(stat & BCM2835_AUX_SPI_STAT_RX_EMPTY)) {
-			bcm2835aux_rd_fifo(bs);
-			continue;
-		}
-		if (!(stat & BCM2835_AUX_SPI_STAT_BUSY)) {
-			bcm2835aux_rd_fifo(bs);
-			continue;
-		}
+		/* do common fifo handling */
+		bcm2835aux_spi_transfer_helper(bs);
 
 		/* there is still data pending to read check the timeout */
 		if (bs->rx_len && time_after(jiffies, timeout)) {
@@ -398,7 +381,7 @@
 	unsigned long clk_hz;
 	int err;
 
-	master = spi_alloc_master(&pdev->dev, sizeof(*bs));
+	master = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
 	if (!master) {
 		dev_err(&pdev->dev, "spi_alloc_master() failed\n");
 		return -ENOMEM;
@@ -407,7 +390,18 @@
 	platform_set_drvdata(pdev, master);
 	master->mode_bits = BCM2835_AUX_SPI_MODE_BITS;
 	master->bits_per_word_mask = SPI_BPW_MASK(8);
-	master->num_chipselect = -1;
+	/* even though the driver never officially supported native CS
+	 * allow a single native CS for legacy DT support purposes when
+	 * no cs-gpio is configured.
+	 * Known limitations for native cs are:
+	 * * multiple chip-selects: cs0-cs2 are all simultaniously asserted
+	 *     whenever there is a transfer -  this even includes SPI_NO_CS
+	 * * SPI_CS_HIGH: is ignores - cs are always asserted low
+	 * * cs_change: cs is deasserted after each spi_transfer
+	 * * cs_delay_usec: cs is always deasserted one SCK cycle after
+	 *     a spi_transfer
+	 */
+	master->num_chipselect = 1;
 	master->transfer_one = bcm2835aux_spi_transfer_one;
 	master->handle_err = bcm2835aux_spi_handle_err;
 	master->dev.of_node = pdev->dev.of_node;
@@ -417,30 +411,27 @@
 	/* the main area */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	bs->regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(bs->regs)) {
-		err = PTR_ERR(bs->regs);
-		goto out_master_put;
-	}
+	if (IS_ERR(bs->regs))
+		return PTR_ERR(bs->regs);
 
 	bs->clk = devm_clk_get(&pdev->dev, NULL);
 	if ((!bs->clk) || (IS_ERR(bs->clk))) {
 		err = PTR_ERR(bs->clk);
 		dev_err(&pdev->dev, "could not get clk: %d\n", err);
-		goto out_master_put;
+		return err;
 	}
 
 	bs->irq = platform_get_irq(pdev, 0);
 	if (bs->irq <= 0) {
 		dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
-		err = bs->irq ? bs->irq : -ENODEV;
-		goto out_master_put;
+		return bs->irq ? bs->irq : -ENODEV;
 	}
 
 	/* this also enables the HW block */
 	err = clk_prepare_enable(bs->clk);
 	if (err) {
 		dev_err(&pdev->dev, "could not prepare clock: %d\n", err);
-		goto out_master_put;
+		return err;
 	}
 
 	/* just checking if the clock returns a sane value */
@@ -463,7 +454,7 @@
 		goto out_clk_disable;
 	}
 
-	err = devm_spi_register_master(&pdev->dev, master);
+	err = spi_register_master(master);
 	if (err) {
 		dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
 		goto out_clk_disable;
@@ -473,8 +464,6 @@
 
 out_clk_disable:
 	clk_disable_unprepare(bs->clk);
-out_master_put:
-	spi_master_put(master);
 	return err;
 }
 
@@ -483,6 +472,8 @@
 	struct spi_master *master = platform_get_drvdata(pdev);
 	struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
 
+	spi_unregister_master(master);
+
 	bcm2835aux_spi_reset_hw(bs);
 
 	/* disable the HW block by releasing the clock */
--- linux-4.4.0.orig/drivers/spi/spi-bcm63xx-hsspi.c
+++ linux-4.4.0/drivers/spi/spi-bcm63xx-hsspi.c
@@ -336,8 +336,8 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(dev, "no irq\n");
-		return -ENXIO;
+		dev_err(dev, "no irq: %d\n", irq);
+		return irq;
 	}
 
 	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
--- linux-4.4.0.orig/drivers/spi/spi-bcm63xx.c
+++ linux-4.4.0/drivers/spi/spi-bcm63xx.c
@@ -496,8 +496,8 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(dev, "no irq\n");
-		return -ENXIO;
+		dev_err(dev, "no irq: %d\n", irq);
+		return irq;
 	}
 
 	clk = devm_clk_get(dev, "spi");
--- linux-4.4.0.orig/drivers/spi/spi-bitbang.c
+++ linux-4.4.0/drivers/spi/spi-bitbang.c
@@ -392,7 +392,7 @@
 	if (ret)
 		spi_master_put(master);
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(spi_bitbang_start);
 
--- linux-4.4.0.orig/drivers/spi/spi-cadence.c
+++ linux-4.4.0/drivers/spi/spi-cadence.c
@@ -116,6 +116,7 @@
 	void __iomem *regs;
 	struct clk *ref_clk;
 	struct clk *pclk;
+	unsigned int clk_rate;
 	u32 speed_hz;
 	const u8 *txbuf;
 	u8 *rxbuf;
@@ -257,7 +258,7 @@
 	u32 ctrl_reg, baud_rate_val;
 	unsigned long frequency;
 
-	frequency = clk_get_rate(xspi->ref_clk);
+	frequency = xspi->clk_rate;
 
 	ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR_OFFSET);
 
@@ -557,8 +558,9 @@
 	master->set_cs = cdns_spi_chipselect;
 	master->mode_bits = SPI_CPOL | SPI_CPHA;
 
+	xspi->clk_rate = clk_get_rate(xspi->ref_clk);
 	/* Set to default valid value */
-	master->max_speed_hz = clk_get_rate(xspi->ref_clk) / 4;
+	master->max_speed_hz = xspi->clk_rate / 4;
 	xspi->speed_hz = master->max_speed_hz;
 
 	master->bits_per_word_mask = SPI_BPW_MASK(8);
--- linux-4.4.0.orig/drivers/spi/spi-davinci.c
+++ linux-4.4.0/drivers/spi/spi-davinci.c
@@ -220,7 +220,7 @@
 	pdata = &dspi->pdata;
 
 	/* program delay transfers if tx_delay is non zero */
-	if (spicfg->wdelay)
+	if (spicfg && spicfg->wdelay)
 		spidat1 |= SPIDAT1_WDEL;
 
 	/*
@@ -651,7 +651,7 @@
 			buf = t->rx_buf;
 		t->rx_dma = dma_map_single(&spi->dev, buf,
 				t->len, DMA_FROM_DEVICE);
-		if (!t->rx_dma) {
+		if (dma_mapping_error(&spi->dev, t->rx_dma)) {
 			ret = -EFAULT;
 			goto err_rx_map;
 		}
@@ -665,7 +665,7 @@
 			buf = (void *)t->tx_buf;
 		t->tx_dma = dma_map_single(&spi->dev, buf,
 				t->len, DMA_TO_DEVICE);
-		if (!t->tx_dma) {
+		if (dma_mapping_error(&spi->dev, t->tx_dma)) {
 			ret = -EFAULT;
 			goto err_tx_map;
 		}
--- linux-4.4.0.orig/drivers/spi/spi-dw-mid.c
+++ linux-4.4.0/drivers/spi/spi-dw-mid.c
@@ -155,6 +155,7 @@
 	if (!xfer->tx_buf)
 		return NULL;
 
+	memset(&txconf, 0, sizeof(txconf));
 	txconf.direction = DMA_MEM_TO_DEV;
 	txconf.dst_addr = dws->dma_addr;
 	txconf.dst_maxburst = 16;
@@ -201,6 +202,7 @@
 	if (!xfer->rx_buf)
 		return NULL;
 
+	memset(&rxconf, 0, sizeof(rxconf));
 	rxconf.direction = DMA_DEV_TO_MEM;
 	rxconf.src_addr = dws->dma_addr;
 	rxconf.src_maxburst = 16;
@@ -226,19 +228,23 @@
 
 static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
 {
-	u16 dma_ctrl = 0;
+	u16 imr = 0, dma_ctrl = 0;
 
 	dw_writel(dws, DW_SPI_DMARDLR, 0xf);
 	dw_writel(dws, DW_SPI_DMATDLR, 0x10);
 
-	if (xfer->tx_buf)
+	if (xfer->tx_buf) {
 		dma_ctrl |= SPI_DMA_TDMAE;
-	if (xfer->rx_buf)
+		imr |= SPI_INT_TXOI;
+	}
+	if (xfer->rx_buf) {
 		dma_ctrl |= SPI_DMA_RDMAE;
+		imr |= SPI_INT_RXUI | SPI_INT_RXOI;
+	}
 	dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
 
 	/* Set the interrupt mask */
-	spi_umask_intr(dws, SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI);
+	spi_umask_intr(dws, imr);
 
 	dws->transfer_handler = dma_transfer;
 
@@ -268,7 +274,7 @@
 		dma_async_issue_pending(dws->txchan);
 	}
 
-	return 0;
+	return 1;
 }
 
 static void mid_spi_dma_stop(struct dw_spi *dws)
--- linux-4.4.0.orig/drivers/spi/spi-dw-mmio.c
+++ linux-4.4.0/drivers/spi/spi-dw-mmio.c
@@ -120,8 +120,8 @@
 {
 	struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
 
-	clk_disable_unprepare(dwsmmio->clk);
 	dw_spi_remove_host(&dwsmmio->dws);
+	clk_disable_unprepare(dwsmmio->clk);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/spi/spi-dw.c
+++ linux-4.4.0/drivers/spi/spi-dw.c
@@ -107,7 +107,10 @@
 
 static int dw_spi_debugfs_init(struct dw_spi *dws)
 {
-	dws->debugfs = debugfs_create_dir("dw_spi", NULL);
+	char name[128];
+
+	snprintf(name, 128, "dw_spi-%s", dev_name(&dws->master->dev));
+	dws->debugfs = debugfs_create_dir(name, NULL);
 	if (!dws->debugfs)
 		return -ENOMEM;
 
@@ -177,9 +180,11 @@
 
 static void dw_writer(struct dw_spi *dws)
 {
-	u32 max = tx_max(dws);
+	u32 max;
 	u16 txw = 0;
 
+	spin_lock(&dws->buf_lock);
+	max = tx_max(dws);
 	while (max--) {
 		/* Set the tx word if the transfer's original "tx" is not null */
 		if (dws->tx_end - dws->len) {
@@ -191,13 +196,16 @@
 		dw_write_io_reg(dws, DW_SPI_DR, txw);
 		dws->tx += dws->n_bytes;
 	}
+	spin_unlock(&dws->buf_lock);
 }
 
 static void dw_reader(struct dw_spi *dws)
 {
-	u32 max = rx_max(dws);
+	u32 max;
 	u16 rxw;
 
+	spin_lock(&dws->buf_lock);
+	max = rx_max(dws);
 	while (max--) {
 		rxw = dw_read_io_reg(dws, DW_SPI_DR);
 		/* Care rx only if the transfer's original "rx" is not null */
@@ -209,6 +217,7 @@
 		}
 		dws->rx += dws->n_bytes;
 	}
+	spin_unlock(&dws->buf_lock);
 }
 
 static void int_error_stop(struct dw_spi *dws, const char *msg)
@@ -281,6 +290,7 @@
 {
 	struct dw_spi *dws = spi_master_get_devdata(master);
 	struct chip_data *chip = spi_get_ctldata(spi);
+	unsigned long flags;
 	u8 imask = 0;
 	u16 txlevel = 0;
 	u16 clk_div;
@@ -288,12 +298,16 @@
 	int ret;
 
 	dws->dma_mapped = 0;
-
+	spin_lock_irqsave(&dws->buf_lock, flags);
 	dws->tx = (void *)transfer->tx_buf;
 	dws->tx_end = dws->tx + transfer->len;
 	dws->rx = transfer->rx_buf;
 	dws->rx_end = dws->rx + transfer->len;
 	dws->len = transfer->len;
+	spin_unlock_irqrestore(&dws->buf_lock, flags);
+
+	/* Ensure dw->rx and dw->rx_end are visible */
+	smp_mb();
 
 	spi_enable_chip(dws, 0);
 
@@ -371,11 +385,8 @@
 
 	spi_enable_chip(dws, 1);
 
-	if (dws->dma_mapped) {
-		ret = dws->dma_ops->dma_transfer(dws, transfer);
-		if (ret < 0)
-			return ret;
-	}
+	if (dws->dma_mapped)
+		return dws->dma_ops->dma_transfer(dws, transfer);
 
 	if (chip->poll_mode)
 		return poll_transfer(dws);
@@ -485,6 +496,9 @@
 	dws->dma_inited = 0;
 	dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
 	snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num);
+	spin_lock_init(&dws->buf_lock);
+
+	spi_master_set_devdata(master, dws);
 
 	ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master);
 	if (ret < 0) {
@@ -517,8 +531,7 @@
 		}
 	}
 
-	spi_master_set_devdata(master, dws);
-	ret = devm_spi_register_master(dev, master);
+	ret = spi_register_master(master);
 	if (ret) {
 		dev_err(&master->dev, "problem registering spi master\n");
 		goto err_dma_exit;
@@ -542,6 +555,8 @@
 {
 	dw_spi_debugfs_remove(dws);
 
+	spi_unregister_master(dws->master);
+
 	if (dws->dma_ops && dws->dma_ops->dma_exit)
 		dws->dma_ops->dma_exit(dws);
 
--- linux-4.4.0.orig/drivers/spi/spi-dw.h
+++ linux-4.4.0/drivers/spi/spi-dw.h
@@ -117,6 +117,7 @@
 	size_t			len;
 	void			*tx;
 	void			*tx_end;
+	spinlock_t		buf_lock;
 	void			*rx;
 	void			*rx_end;
 	int			dma_mapped;
--- linux-4.4.0.orig/drivers/spi/spi-fsl-dspi.c
+++ linux-4.4.0/drivers/spi/spi-fsl-dspi.c
@@ -753,7 +753,6 @@
 	/* Disconnect from the SPI framework */
 	clk_disable_unprepare(dspi->clk);
 	spi_unregister_master(dspi->master);
-	spi_master_put(dspi->master);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/spi/spi-fsl-spi.c
+++ linux-4.4.0/drivers/spi/spi-fsl-spi.c
@@ -408,7 +408,6 @@
 	}
 
 	m->status = status;
-	spi_finalize_current_message(master);
 
 	if (status || !cs_change) {
 		ndelay(nsecs);
@@ -416,6 +415,7 @@
 	}
 
 	fsl_spi_setup_transfer(spi, NULL);
+	spi_finalize_current_message(master);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/spi/spi-img-spfi.c
+++ linux-4.4.0/drivers/spi/spi-img-spfi.c
@@ -673,6 +673,8 @@
 			dma_release_channel(spfi->tx_ch);
 		if (spfi->rx_ch)
 			dma_release_channel(spfi->rx_ch);
+		spfi->tx_ch = NULL;
+		spfi->rx_ch = NULL;
 		dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n");
 	} else {
 		master->dma_tx = spfi->tx_ch;
@@ -771,8 +773,10 @@
 	int ret;
 
 	ret = pm_runtime_get_sync(dev);
-	if (ret)
+	if (ret) {
+		pm_runtime_put_noidle(dev);
 		return ret;
+	}
 	spfi_reset(spfi);
 	pm_runtime_put(dev);
 
--- linux-4.4.0.orig/drivers/spi/spi-imx.c
+++ linux-4.4.0/drivers/spi/spi-imx.c
@@ -1228,12 +1228,23 @@
 {
 	struct spi_master *master = platform_get_drvdata(pdev);
 	struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+	int ret;
 
 	spi_bitbang_stop(&spi_imx->bitbang);
 
+	ret = clk_enable(spi_imx->clk_per);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(spi_imx->clk_ipg);
+	if (ret) {
+		clk_disable(spi_imx->clk_per);
+		return ret;
+	}
+
 	writel(0, spi_imx->base + MXC_CSPICTRL);
-	clk_unprepare(spi_imx->clk_ipg);
-	clk_unprepare(spi_imx->clk_per);
+	clk_disable_unprepare(spi_imx->clk_ipg);
+	clk_disable_unprepare(spi_imx->clk_per);
 	spi_imx_sdma_exit(spi_imx);
 	spi_master_put(master);
 
--- linux-4.4.0.orig/drivers/spi/spi-mpc52xx.c
+++ linux-4.4.0/drivers/spi/spi-mpc52xx.c
@@ -520,6 +520,7 @@
 	struct mpc52xx_spi *ms = spi_master_get_devdata(master);
 	int i;
 
+	cancel_work_sync(&ms->work);
 	free_irq(ms->irq0, ms);
 	free_irq(ms->irq1, ms);
 
--- linux-4.4.0.orig/drivers/spi/spi-omap2-mcspi.c
+++ linux-4.4.0/drivers/spi/spi-omap2-mcspi.c
@@ -301,7 +301,7 @@
 	struct omap2_mcspi_cs *cs = spi->controller_state;
 	struct omap2_mcspi *mcspi;
 	unsigned int wcnt;
-	int max_fifo_depth, fifo_depth, bytes_per_word;
+	int max_fifo_depth, bytes_per_word;
 	u32 chconf, xferlevel;
 
 	mcspi = spi_master_get_devdata(master);
@@ -317,10 +317,6 @@
 		else
 			max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH;
 
-		fifo_depth = gcd(t->len, max_fifo_depth);
-		if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0)
-			goto disable_fifo;
-
 		wcnt = t->len / bytes_per_word;
 		if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
 			goto disable_fifo;
@@ -328,16 +324,17 @@
 		xferlevel = wcnt << 16;
 		if (t->rx_buf != NULL) {
 			chconf |= OMAP2_MCSPI_CHCONF_FFER;
-			xferlevel |= (fifo_depth - 1) << 8;
+			xferlevel |= (bytes_per_word - 1) << 8;
 		}
+
 		if (t->tx_buf != NULL) {
 			chconf |= OMAP2_MCSPI_CHCONF_FFET;
-			xferlevel |= fifo_depth - 1;
+			xferlevel |= bytes_per_word - 1;
 		}
 
 		mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
 		mcspi_write_chconf0(spi, chconf);
-		mcspi->fifo_depth = fifo_depth;
+		mcspi->fifo_depth = max_fifo_depth;
 
 		return;
 	}
@@ -457,6 +454,8 @@
 	int			elements = 0;
 	int			word_len, element_count;
 	struct omap2_mcspi_cs	*cs = spi->controller_state;
+	void __iomem		*chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
+
 	mcspi = spi_master_get_devdata(spi->master);
 	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 	count = xfer->len;
@@ -517,8 +516,8 @@
 	if (l & OMAP2_MCSPI_CHCONF_TURBO) {
 		elements--;
 
-		if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
-				   & OMAP2_MCSPI_CHSTAT_RXS)) {
+		if (!mcspi_wait_for_reg_bit(chstat_reg,
+					    OMAP2_MCSPI_CHSTAT_RXS)) {
 			u32 w;
 
 			w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
@@ -536,8 +535,7 @@
 			return count;
 		}
 	}
-	if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
-				& OMAP2_MCSPI_CHSTAT_RXS)) {
+	if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) {
 		u32 w;
 
 		w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
@@ -568,7 +566,6 @@
 	struct dma_slave_config	cfg;
 	enum dma_slave_buswidth width;
 	unsigned es;
-	u32			burst;
 	void __iomem		*chstat_reg;
 	void __iomem            *irqstat_reg;
 	int			wait_res;
@@ -590,22 +587,14 @@
 	}
 
 	count = xfer->len;
-	burst = 1;
-
-	if (mcspi->fifo_depth > 0) {
-		if (count > mcspi->fifo_depth)
-			burst = mcspi->fifo_depth / es;
-		else
-			burst = count / es;
-	}
 
 	memset(&cfg, 0, sizeof(cfg));
 	cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
 	cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
 	cfg.src_addr_width = width;
 	cfg.dst_addr_width = width;
-	cfg.src_maxburst = burst;
-	cfg.dst_maxburst = burst;
+	cfg.src_maxburst = 1;
+	cfg.dst_maxburst = 1;
 
 	rx = xfer->rx_buf;
 	tx = xfer->tx_buf;
@@ -1024,6 +1013,16 @@
 		spi->controller_state = cs;
 		/* Link this to context save list */
 		list_add_tail(&cs->node, &ctx->cs);
+
+		if (gpio_is_valid(spi->cs_gpio)) {
+			ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev));
+			if (ret) {
+				dev_err(&spi->dev, "failed to request gpio\n");
+				return ret;
+			}
+			gpio_direction_output(spi->cs_gpio,
+					 !(spi->mode & SPI_CS_HIGH));
+		}
 	}
 
 	if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
@@ -1032,15 +1031,6 @@
 			return ret;
 	}
 
-	if (gpio_is_valid(spi->cs_gpio)) {
-		ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev));
-		if (ret) {
-			dev_err(&spi->dev, "failed to request gpio\n");
-			return ret;
-		}
-		gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
-	}
-
 	ret = pm_runtime_get_sync(mcspi->dev);
 	if (ret < 0)
 		return ret;
--- linux-4.4.0.orig/drivers/spi/spi-orion.c
+++ linux-4.4.0/drivers/spi/spi-orion.c
@@ -127,37 +127,62 @@
 	tclk_hz = clk_get_rate(orion_spi->clk);
 
 	if (devdata->typ == ARMADA_SPI) {
-		unsigned int clk, spr, sppr, sppr2, err;
-		unsigned int best_spr, best_sppr, best_err;
-
-		best_err = speed;
-		best_spr = 0;
-		best_sppr = 0;
-
-		/* Iterate over the valid range looking for best fit */
-		for (sppr = 0; sppr < 8; sppr++) {
-			sppr2 = 0x1 << sppr;
-
-			spr = tclk_hz / sppr2;
-			spr = DIV_ROUND_UP(spr, speed);
-			if ((spr == 0) || (spr > 15))
-				continue;
-
-			clk = tclk_hz / (spr * sppr2);
-			err = speed - clk;
-
-			if (err < best_err) {
-				best_spr = spr;
-				best_sppr = sppr;
-				best_err = err;
-			}
+		/*
+		 * Given the core_clk (tclk_hz) and the target rate (speed) we
+		 * determine the best values for SPR (in [0 .. 15]) and SPPR (in
+		 * [0..7]) such that
+		 *
+		 * 	core_clk / (SPR * 2 ** SPPR)
+		 *
+		 * is as big as possible but not bigger than speed.
+		 */
+
+		/* best integer divider: */
+		unsigned divider = DIV_ROUND_UP(tclk_hz, speed);
+		unsigned spr, sppr;
+
+		if (divider < 16) {
+			/* This is the easy case, divider is less than 16 */
+			spr = divider;
+			sppr = 0;
+
+		} else {
+			unsigned two_pow_sppr;
+			/*
+			 * Find the highest bit set in divider. This and the
+			 * three next bits define SPR (apart from rounding).
+			 * SPPR is then the number of zero bits that must be
+			 * appended:
+			 */
+			sppr = fls(divider) - 4;
+
+			/*
+			 * As SPR only has 4 bits, we have to round divider up
+			 * to the next multiple of 2 ** sppr.
+			 */
+			two_pow_sppr = 1 << sppr;
+			divider = (divider + two_pow_sppr - 1) & -two_pow_sppr;
+
+			/*
+			 * recalculate sppr as rounding up divider might have
+			 * increased it enough to change the position of the
+			 * highest set bit. In this case the bit that now
+			 * doesn't make it into SPR is 0, so there is no need to
+			 * round again.
+			 */
+			sppr = fls(divider) - 4;
+			spr = divider >> sppr;
+
+			/*
+			 * Now do range checking. SPR is constructed to have a
+			 * width of 4 bits, so this is fine for sure. So we
+			 * still need to check for sppr to fit into 3 bits:
+			 */
+			if (sppr > 7)
+				return -EINVAL;
 		}
 
-		if ((best_sppr == 0) && (best_spr == 0))
-			return -EINVAL;
-
-		prescale = ((best_sppr & 0x6) << 5) |
-			((best_sppr & 0x1) << 4) | best_spr;
+		prescale = ((sppr & 0x6) << 5) | ((sppr & 0x1) << 4) | spr;
 	} else {
 		/*
 		 * the supported rates are: 4,6,8...30
--- linux-4.4.0.orig/drivers/spi/spi-pxa2xx.c
+++ linux-4.4.0/drivers/spi/spi-pxa2xx.c
@@ -111,7 +111,7 @@
 		.reg_general = -1,
 		.reg_ssp = 0x20,
 		.reg_cs_ctrl = 0x24,
-		.reg_capabilities = 0xfc,
+		.reg_capabilities = -1,
 		.rx_threshold = 1,
 		.tx_threshold_lo = 32,
 		.tx_threshold_hi = 56,
@@ -548,7 +548,14 @@
 	u32 sccr1_reg;
 
 	sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1;
-	sccr1_reg &= ~SSCR1_RFT;
+	switch (drv_data->ssp_type) {
+	case QUARK_X1000_SSP:
+		sccr1_reg &= ~QUARK_X1000_SSCR1_RFT;
+		break;
+	default:
+		sccr1_reg &= ~SSCR1_RFT;
+		break;
+	}
 	sccr1_reg |= chip->threshold;
 	pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
 }
@@ -852,10 +859,14 @@
 
 	rate = min_t(int, ssp_clk, rate);
 
+	/*
+	 * Calculate the divisor for the SCR (Serial Clock Rate), avoiding
+	 * that the SSP transmission rate can be greater than the device rate
+	 */
 	if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
-		return (ssp_clk / (2 * rate) - 1) & 0xff;
+		return (DIV_ROUND_UP(ssp_clk, 2 * rate) - 1) & 0xff;
 	else
-		return (ssp_clk / rate - 1) & 0xfff;
+		return (DIV_ROUND_UP(ssp_clk, rate) - 1)  & 0xfff;
 }
 
 static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
@@ -1360,12 +1371,7 @@
 
 static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
 {
-	struct device *dev = param;
-
-	if (dev != chan->device->dev->parent)
-		return false;
-
-	return true;
+	return param == chan->device->dev;
 }
 
 static struct pxa2xx_spi_master *
@@ -1419,7 +1425,13 @@
 	}
 
 	ssp->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(ssp->clk))
+		return NULL;
+
 	ssp->irq = platform_get_irq(pdev, 0);
+	if (ssp->irq < 0)
+		return NULL;
+
 	ssp->type = type;
 	ssp->pdev = pdev;
 	ssp->port_id = pxa2xx_spi_get_port_id(adev);
@@ -1467,7 +1479,7 @@
 		return -ENODEV;
 	}
 
-	master = spi_alloc_master(dev, sizeof(struct driver_data));
+	master = devm_spi_alloc_master(dev, sizeof(*drv_data));
 	if (!master) {
 		dev_err(&pdev->dev, "cannot alloc spi_master\n");
 		pxa_ssp_free(ssp);
@@ -1593,7 +1605,7 @@
 
 	/* Register with the SPI framework */
 	platform_set_drvdata(pdev, drv_data);
-	status = devm_spi_register_master(&pdev->dev, master);
+	status = spi_register_master(master);
 	if (status != 0) {
 		dev_err(&pdev->dev, "problem registering spi master\n");
 		goto out_error_clock_enabled;
@@ -1607,7 +1619,6 @@
 	free_irq(ssp->irq, drv_data);
 
 out_error_master_alloc:
-	spi_master_put(master);
 	pxa_ssp_free(ssp);
 	return status;
 }
@@ -1623,6 +1634,8 @@
 
 	pm_runtime_get_sync(&pdev->dev);
 
+	spi_unregister_master(drv_data->master);
+
 	/* Disable the SSP at the peripheral and SOC level */
 	pxa2xx_spi_write(drv_data, SSCR0, 0);
 	clk_disable_unprepare(ssp->clk);
--- linux-4.4.0.orig/drivers/spi/spi-pxa2xx.h
+++ linux-4.4.0/drivers/spi/spi-pxa2xx.h
@@ -38,7 +38,7 @@
 
 	/* SSP register addresses */
 	void __iomem *ioaddr;
-	u32 ssdr_physical;
+	phys_addr_t ssdr_physical;
 
 	/* SSP masks*/
 	u32 dma_cr1;
--- linux-4.4.0.orig/drivers/spi/spi-qup.c
+++ linux-4.4.0/drivers/spi/spi-qup.c
@@ -961,6 +961,11 @@
 	struct spi_qup *controller = spi_master_get_devdata(master);
 	int ret;
 
+	if (pm_runtime_suspended(device)) {
+		ret = spi_qup_pm_resume_runtime(device);
+		if (ret)
+			return ret;
+	}
 	ret = spi_master_suspend(master);
 	if (ret)
 		return ret;
--- linux-4.4.0.orig/drivers/spi/spi-rb4xx.c
+++ linux-4.4.0/drivers/spi/spi-rb4xx.c
@@ -148,7 +148,7 @@
 	if (IS_ERR(spi_base))
 		return PTR_ERR(spi_base);
 
-	master = spi_alloc_master(&pdev->dev, sizeof(*rbspi));
+	master = devm_spi_alloc_master(&pdev->dev, sizeof(*rbspi));
 	if (!master)
 		return -ENOMEM;
 
--- linux-4.4.0.orig/drivers/spi/spi-rockchip.c
+++ linux-4.4.0/drivers/spi/spi-rockchip.c
@@ -265,7 +265,10 @@
 static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
 {
 	u32 ser;
-	struct rockchip_spi *rs = spi_master_get_devdata(spi->master);
+	struct spi_master *master = spi->master;
+	struct rockchip_spi *rs = spi_master_get_devdata(master);
+
+	pm_runtime_get_sync(rs->dev);
 
 	ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK;
 
@@ -290,6 +293,8 @@
 		ser &= ~(1 << spi->chip_select);
 
 	writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER);
+
+	pm_runtime_put_sync(rs->dev);
 }
 
 static int rockchip_spi_prepare_message(struct spi_master *master,
@@ -439,6 +444,9 @@
 	struct dma_slave_config rxconf, txconf;
 	struct dma_async_tx_descriptor *rxdesc, *txdesc;
 
+	memset(&rxconf, 0, sizeof(rxconf));
+	memset(&txconf, 0, sizeof(txconf));
+
 	spin_lock_irqsave(&rs->lock, flags);
 	rs->state &= ~RXBUSY;
 	rs->state &= ~TXBUSY;
--- linux-4.4.0.orig/drivers/spi/spi-rspi.c
+++ linux-4.4.0/drivers/spi/spi-rspi.c
@@ -279,7 +279,8 @@
 	/* Sets parity, interrupt mask */
 	rspi_write8(rspi, 0x00, RSPI_SPCR2);
 
-	/* Sets SPCMD */
+	/* Resets sequencer */
+	rspi_write8(rspi, 0, RSPI_SPSCR);
 	rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
 	rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
 
@@ -313,7 +314,8 @@
 	rspi_write8(rspi, 0x00, RSPI_SSLND);
 	rspi_write8(rspi, 0x00, RSPI_SPND);
 
-	/* Sets SPCMD */
+	/* Resets sequencer */
+	rspi_write8(rspi, 0, RSPI_SPSCR);
 	rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
 	rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
 
@@ -364,7 +366,8 @@
 	/* Sets buffer to allow normal operation */
 	rspi_write8(rspi, 0x00, QSPI_SPBFCR);
 
-	/* Sets SPCMD */
+	/* Resets sequencer */
+	rspi_write8(rspi, 0, RSPI_SPSCR);
 	rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
 
 	/* Enables SPI function in master mode */
@@ -587,11 +590,13 @@
 
 	ret = wait_event_interruptible_timeout(rspi->wait,
 					       rspi->dma_callbacked, HZ);
-	if (ret > 0 && rspi->dma_callbacked)
+	if (ret > 0 && rspi->dma_callbacked) {
 		ret = 0;
-	else if (!ret) {
-		dev_err(&rspi->master->dev, "DMA timeout\n");
-		ret = -ETIMEDOUT;
+	} else {
+		if (!ret) {
+			dev_err(&rspi->master->dev, "DMA timeout\n");
+			ret = -ETIMEDOUT;
+		}
 		if (tx)
 			dmaengine_terminate_all(rspi->master->dma_tx);
 		if (rx)
@@ -1303,12 +1308,36 @@
 
 MODULE_DEVICE_TABLE(platform, spi_driver_ids);
 
+#ifdef CONFIG_PM_SLEEP
+static int rspi_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rspi_data *rspi = platform_get_drvdata(pdev);
+
+	return spi_master_suspend(rspi->master);
+}
+
+static int rspi_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rspi_data *rspi = platform_get_drvdata(pdev);
+
+	return spi_master_resume(rspi->master);
+}
+
+static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume);
+#define DEV_PM_OPS	&rspi_pm_ops
+#else
+#define DEV_PM_OPS	NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver rspi_driver = {
 	.probe =	rspi_probe,
 	.remove =	rspi_remove,
 	.id_table =	spi_driver_ids,
 	.driver		= {
 		.name = "renesas_spi",
+		.pm = DEV_PM_OPS,
 		.of_match_table = of_match_ptr(rspi_of_match),
 	},
 };
--- linux-4.4.0.orig/drivers/spi/spi-s3c24xx-fiq.S
+++ linux-4.4.0/drivers/spi/spi-s3c24xx-fiq.S
@@ -36,7 +36,6 @@
 	@ and an offset to the irq acknowledgment word
 
 ENTRY(s3c24xx_spi_fiq_rx)
-s3c24xx_spi_fix_rx:
 	.word	fiq_rx_end - fiq_rx_start
 	.word	fiq_rx_irq_ack - fiq_rx_start
 fiq_rx_start:
@@ -50,7 +49,7 @@
 	strb	fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
 
 	subs	fiq_rcount, fiq_rcount, #1
-	subnes	pc, lr, #4		@@ return, still have work to do
+	subsne	pc, lr, #4		@@ return, still have work to do
 
 	@@ set IRQ controller so that next op will trigger IRQ
 	mov	fiq_rtmp, #0
@@ -62,7 +61,6 @@
 fiq_rx_end:
 
 ENTRY(s3c24xx_spi_fiq_txrx)
-s3c24xx_spi_fiq_txrx:
 	.word	fiq_txrx_end - fiq_txrx_start
 	.word	fiq_txrx_irq_ack - fiq_txrx_start
 fiq_txrx_start:
@@ -77,7 +75,7 @@
 	strb	fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
 
 	subs	fiq_rcount, fiq_rcount, #1
-	subnes	pc, lr, #4		@@ return, still have work to do
+	subsne	pc, lr, #4		@@ return, still have work to do
 
 	mov	fiq_rtmp, #0
 	str	fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD  - S3C24XX_VA_IRQ ]
@@ -89,7 +87,6 @@
 fiq_txrx_end:
 
 ENTRY(s3c24xx_spi_fiq_tx)
-s3c24xx_spi_fix_tx:
 	.word	fiq_tx_end - fiq_tx_start
 	.word	fiq_tx_irq_ack - fiq_tx_start
 fiq_tx_start:
@@ -102,7 +99,7 @@
 	strb	fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
 
 	subs	fiq_rcount, fiq_rcount, #1
-	subnes	pc, lr, #4		@@ return, still have work to do
+	subsne	pc, lr, #4		@@ return, still have work to do
 
 	mov	fiq_rtmp, #0
 	str	fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD  - S3C24XX_VA_IRQ ]
--- linux-4.4.0.orig/drivers/spi/spi-sh-msiof.c
+++ linux-4.4.0/drivers/spi/spi-sh-msiof.c
@@ -263,6 +263,9 @@
 
 	for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) {
 		brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div);
+		/* SCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */
+		if (sh_msiof_spi_div_table[k].div == 1 && brps > 2)
+			continue;
 		if (brps <= 32) /* max of brdv is 32 */
 			break;
 	}
@@ -371,7 +374,8 @@
 
 static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p)
 {
-	sh_msiof_write(p, STR, sh_msiof_read(p, STR));
+	sh_msiof_write(p, STR,
+		       sh_msiof_read(p, STR) & ~(STR_TDREQ | STR_RDREQ));
 }
 
 static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p,
@@ -860,7 +864,7 @@
 				break;
 			copy32 = copy_bswap32;
 		} else if (bits <= 16) {
-			if (l & 1)
+			if (l & 3)
 				break;
 			copy32 = copy_wswap32;
 		} else {
@@ -1194,8 +1198,8 @@
 
 	i = platform_get_irq(pdev, 0);
 	if (i < 0) {
-		dev_err(&pdev->dev, "cannot get platform IRQ\n");
-		ret = -ENOENT;
+		dev_err(&pdev->dev, "cannot get IRQ\n");
+		ret = i;
 		goto err1;
 	}
 
@@ -1272,12 +1276,37 @@
 };
 MODULE_DEVICE_TABLE(platform, spi_driver_ids);
 
+#ifdef CONFIG_PM_SLEEP
+static int sh_msiof_spi_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
+
+	return spi_master_suspend(p->master);
+}
+
+static int sh_msiof_spi_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
+
+	return spi_master_resume(p->master);
+}
+
+static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend,
+			 sh_msiof_spi_resume);
+#define DEV_PM_OPS	&sh_msiof_spi_pm_ops
+#else
+#define DEV_PM_OPS	NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver sh_msiof_spi_drv = {
 	.probe		= sh_msiof_spi_probe,
 	.remove		= sh_msiof_spi_remove,
 	.id_table	= spi_driver_ids,
 	.driver		= {
 		.name		= "spi_sh_msiof",
+		.pm		= DEV_PM_OPS,
 		.of_match_table = of_match_ptr(sh_msiof_match),
 	},
 };
--- linux-4.4.0.orig/drivers/spi/spi-sun4i.c
+++ linux-4.4.0/drivers/spi/spi-sun4i.c
@@ -170,13 +170,17 @@
 {
 	struct sun4i_spi *sspi = spi_master_get_devdata(master);
 	unsigned int mclk_rate, div, timeout;
+	unsigned int start, end, tx_time;
 	unsigned int tx_len = 0;
 	int ret = 0;
 	u32 reg;
 
 	/* We don't support transfer larger than the FIFO */
 	if (tfr->len > SUN4I_FIFO_DEPTH)
-		return -EINVAL;
+		return -EMSGSIZE;
+
+	if (tfr->tx_buf && tfr->len >= SUN4I_FIFO_DEPTH)
+		return -EMSGSIZE;
 
 	reinit_completion(&sspi->done);
 	sspi->tx_buf = tfr->tx_buf;
@@ -269,8 +273,12 @@
 	sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
 	sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
 
-	/* Fill the TX FIFO */
-	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
+	/*
+	 * Fill the TX FIFO
+	 * Filling the FIFO fully causes timeout for some reason
+	 * at least on spi2 on A10s
+	 */
+	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
 
 	/* Enable the interrupts */
 	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
@@ -279,9 +287,16 @@
 	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
 	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
 
+	tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+	start = jiffies;
 	timeout = wait_for_completion_timeout(&sspi->done,
-					      msecs_to_jiffies(1000));
+					      msecs_to_jiffies(tx_time));
+	end = jiffies;
 	if (!timeout) {
+		dev_warn(&master->dev,
+			 "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+			 dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+			 jiffies_to_msecs(end - start), tx_time);
 		ret = -ETIMEDOUT;
 		goto out;
 	}
@@ -443,7 +458,7 @@
 
 static int sun4i_spi_remove(struct platform_device *pdev)
 {
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_force_suspend(&pdev->dev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/spi/spi-sun6i.c
+++ linux-4.4.0/drivers/spi/spi-sun6i.c
@@ -160,6 +160,7 @@
 {
 	struct sun6i_spi *sspi = spi_master_get_devdata(master);
 	unsigned int mclk_rate, div, timeout;
+	unsigned int start, end, tx_time;
 	unsigned int tx_len = 0;
 	int ret = 0;
 	u32 reg;
@@ -269,9 +270,16 @@
 	reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
 	sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
 
+	tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+	start = jiffies;
 	timeout = wait_for_completion_timeout(&sspi->done,
-					      msecs_to_jiffies(1000));
+					      msecs_to_jiffies(tx_time));
+	end = jiffies;
 	if (!timeout) {
+		dev_warn(&master->dev,
+			 "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+			 dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+			 jiffies_to_msecs(end - start), tx_time);
 		ret = -ETIMEDOUT;
 		goto out;
 	}
@@ -449,7 +457,7 @@
 
 static int sun6i_spi_remove(struct platform_device *pdev)
 {
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_force_suspend(&pdev->dev);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/spi/spi-tegra114.c
+++ linux-4.4.0/drivers/spi/spi-tegra114.c
@@ -307,10 +307,16 @@
 				x |= (u32)(*tx_buf++) << (i * 8);
 			tegra_spi_writel(tspi, x, SPI_TX_FIFO);
 		}
+
+		tspi->cur_tx_pos += written_words * tspi->bytes_per_word;
 	} else {
+		unsigned int write_bytes;
 		max_n_32bit = min(tspi->curr_dma_words,  tx_empty_count);
 		written_words = max_n_32bit;
 		nbytes = written_words * tspi->bytes_per_word;
+		if (nbytes > t->len - tspi->cur_pos)
+			nbytes = t->len - tspi->cur_pos;
+		write_bytes = nbytes;
 		for (count = 0; count < max_n_32bit; count++) {
 			u32 x = 0;
 
@@ -319,8 +325,10 @@
 				x |= (u32)(*tx_buf++) << (i * 8);
 			tegra_spi_writel(tspi, x, SPI_TX_FIFO);
 		}
+
+		tspi->cur_tx_pos += write_bytes;
 	}
-	tspi->cur_tx_pos += written_words * tspi->bytes_per_word;
+
 	return written_words;
 }
 
@@ -344,20 +352,27 @@
 			for (i = 0; len && (i < 4); i++, len--)
 				*rx_buf++ = (x >> i*8) & 0xFF;
 		}
-		tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
 		read_words += tspi->curr_dma_words;
+		tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
 	} else {
 		u32 rx_mask = ((u32)1 << t->bits_per_word) - 1;
+		u8 bytes_per_word = tspi->bytes_per_word;
+		unsigned int read_bytes;
 
+		len = rx_full_count * bytes_per_word;
+		if (len > t->len - tspi->cur_pos)
+			len = t->len - tspi->cur_pos;
+		read_bytes = len;
 		for (count = 0; count < rx_full_count; count++) {
 			u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask;
 
-			for (i = 0; (i < tspi->bytes_per_word); i++)
+			for (i = 0; len && (i < bytes_per_word); i++, len--)
 				*rx_buf++ = (x >> (i*8)) & 0xFF;
 		}
-		tspi->cur_rx_pos += rx_full_count * tspi->bytes_per_word;
 		read_words += rx_full_count;
+		tspi->cur_rx_pos += read_bytes;
 	}
+
 	return read_words;
 }
 
@@ -372,12 +387,17 @@
 		unsigned len = tspi->curr_dma_words * tspi->bytes_per_word;
 
 		memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len);
+		tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
 	} else {
 		unsigned int i;
 		unsigned int count;
 		u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos;
 		unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word;
+		unsigned int write_bytes;
 
+		if (consume > t->len - tspi->cur_pos)
+			consume = t->len - tspi->cur_pos;
+		write_bytes = consume;
 		for (count = 0; count < tspi->curr_dma_words; count++) {
 			u32 x = 0;
 
@@ -386,8 +406,9 @@
 				x |= (u32)(*tx_buf++) << (i * 8);
 			tspi->tx_dma_buf[count] = x;
 		}
+
+		tspi->cur_tx_pos += write_bytes;
 	}
-	tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
 
 	/* Make the dma buffer to read by dma */
 	dma_sync_single_for_device(tspi->dev, tspi->tx_dma_phys,
@@ -405,20 +426,28 @@
 		unsigned len = tspi->curr_dma_words * tspi->bytes_per_word;
 
 		memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len);
+		tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
 	} else {
 		unsigned int i;
 		unsigned int count;
 		unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos;
 		u32 rx_mask = ((u32)1 << t->bits_per_word) - 1;
+		unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word;
+		unsigned int read_bytes;
 
+		if (consume > t->len - tspi->cur_pos)
+			consume = t->len - tspi->cur_pos;
+		read_bytes = consume;
 		for (count = 0; count < tspi->curr_dma_words; count++) {
 			u32 x = tspi->rx_dma_buf[count] & rx_mask;
 
-			for (i = 0; (i < tspi->bytes_per_word); i++)
+			for (i = 0; consume && (i < tspi->bytes_per_word);
+							i++, consume--)
 				*rx_buf++ = (x >> (i*8)) & 0xFF;
 		}
+
+		tspi->cur_rx_pos += read_bytes;
 	}
-	tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
 
 	/* Make the dma buffer to read by dma */
 	dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys,
@@ -730,6 +759,8 @@
 
 	if (tspi->is_packed)
 		command1 |= SPI_PACKED;
+	else
+		command1 &= ~SPI_PACKED;
 
 	command1 &= ~(SPI_CS_SEL_MASK | SPI_TX_EN | SPI_RX_EN);
 	tspi->cur_direction = 0;
@@ -770,6 +801,7 @@
 
 	ret = pm_runtime_get_sync(tspi->dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(tspi->dev);
 		dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
 		return ret;
 	}
@@ -1067,27 +1099,19 @@
 
 	spi_irq = platform_get_irq(pdev, 0);
 	tspi->irq = spi_irq;
-	ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
-			tegra_spi_isr_thread, IRQF_ONESHOT,
-			dev_name(&pdev->dev), tspi);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
-					tspi->irq);
-		goto exit_free_master;
-	}
 
 	tspi->clk = devm_clk_get(&pdev->dev, "spi");
 	if (IS_ERR(tspi->clk)) {
 		dev_err(&pdev->dev, "can not get clock\n");
 		ret = PTR_ERR(tspi->clk);
-		goto exit_free_irq;
+		goto exit_free_master;
 	}
 
 	tspi->rst = devm_reset_control_get(&pdev->dev, "spi");
 	if (IS_ERR(tspi->rst)) {
 		dev_err(&pdev->dev, "can not get reset\n");
 		ret = PTR_ERR(tspi->rst);
-		goto exit_free_irq;
+		goto exit_free_master;
 	}
 
 	tspi->max_buf_size = SPI_FIFO_DEPTH << 2;
@@ -1095,7 +1119,7 @@
 
 	ret = tegra_spi_init_dma_param(tspi, true);
 	if (ret < 0)
-		goto exit_free_irq;
+		goto exit_free_master;
 	ret = tegra_spi_init_dma_param(tspi, false);
 	if (ret < 0)
 		goto exit_rx_dma_free;
@@ -1117,18 +1141,32 @@
 		dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
 		goto exit_pm_disable;
 	}
+
+	reset_control_assert(tspi->rst);
+	udelay(2);
+	reset_control_deassert(tspi->rst);
 	tspi->def_command1_reg  = SPI_M_S;
 	tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
 	pm_runtime_put(&pdev->dev);
+	ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
+				   tegra_spi_isr_thread, IRQF_ONESHOT,
+				   dev_name(&pdev->dev), tspi);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
+			tspi->irq);
+		goto exit_pm_disable;
+	}
 
 	master->dev.of_node = pdev->dev.of_node;
 	ret = devm_spi_register_master(&pdev->dev, master);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "can not register to master err %d\n", ret);
-		goto exit_pm_disable;
+		goto exit_free_irq;
 	}
 	return ret;
 
+exit_free_irq:
+	free_irq(spi_irq, tspi);
 exit_pm_disable:
 	pm_runtime_disable(&pdev->dev);
 	if (!pm_runtime_status_suspended(&pdev->dev))
@@ -1136,8 +1174,6 @@
 	tegra_spi_deinit_dma_param(tspi, false);
 exit_rx_dma_free:
 	tegra_spi_deinit_dma_param(tspi, true);
-exit_free_irq:
-	free_irq(spi_irq, tspi);
 exit_free_master:
 	spi_master_put(master);
 	return ret;
@@ -1179,6 +1215,7 @@
 
 	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(dev);
 		dev_err(dev, "pm runtime failed, e = %d\n", ret);
 		return ret;
 	}
--- linux-4.4.0.orig/drivers/spi/spi-tegra20-sflash.c
+++ linux-4.4.0/drivers/spi/spi-tegra20-sflash.c
@@ -564,6 +564,7 @@
 
 	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(dev);
 		dev_err(dev, "pm runtime failed, e = %d\n", ret);
 		return ret;
 	}
--- linux-4.4.0.orig/drivers/spi/spi-tegra20-slink.c
+++ linux-4.4.0/drivers/spi/spi-tegra20-slink.c
@@ -761,6 +761,7 @@
 
 	ret = pm_runtime_get_sync(tspi->dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(tspi->dev);
 		dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
 		return ret;
 	}
@@ -1063,6 +1064,24 @@
 		goto exit_free_master;
 	}
 
+	/* disabled clock may cause interrupt storm upon request */
+	tspi->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(tspi->clk)) {
+		ret = PTR_ERR(tspi->clk);
+		dev_err(&pdev->dev, "Can not get clock %d\n", ret);
+		goto exit_free_master;
+	}
+	ret = clk_prepare(tspi->clk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Clock prepare failed %d\n", ret);
+		goto exit_free_master;
+	}
+	ret = clk_enable(tspi->clk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Clock enable failed %d\n", ret);
+		goto exit_clk_unprepare;
+	}
+
 	spi_irq = platform_get_irq(pdev, 0);
 	tspi->irq = spi_irq;
 	ret = request_threaded_irq(tspi->irq, tegra_slink_isr,
@@ -1071,14 +1090,7 @@
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
 					tspi->irq);
-		goto exit_free_master;
-	}
-
-	tspi->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(tspi->clk)) {
-		dev_err(&pdev->dev, "can not get clock\n");
-		ret = PTR_ERR(tspi->clk);
-		goto exit_free_irq;
+		goto exit_clk_disable;
 	}
 
 	tspi->rst = devm_reset_control_get(&pdev->dev, "spi");
@@ -1138,6 +1150,10 @@
 	tegra_slink_deinit_dma_param(tspi, true);
 exit_free_irq:
 	free_irq(spi_irq, tspi);
+exit_clk_disable:
+	clk_disable(tspi->clk);
+exit_clk_unprepare:
+	clk_unprepare(tspi->clk);
 exit_free_master:
 	spi_master_put(master);
 	return ret;
@@ -1150,6 +1166,9 @@
 
 	free_irq(tspi->irq, tspi);
 
+	clk_disable(tspi->clk);
+	clk_unprepare(tspi->clk);
+
 	if (tspi->tx_dma_chan)
 		tegra_slink_deinit_dma_param(tspi, false);
 
@@ -1179,6 +1198,7 @@
 
 	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(dev);
 		dev_err(dev, "pm runtime failed, e = %d\n", ret);
 		return ret;
 	}
--- linux-4.4.0.orig/drivers/spi/spi-ti-qspi.c
+++ linux-4.4.0/drivers/spi/spi-ti-qspi.c
@@ -94,6 +94,7 @@
 #define QSPI_FLEN(n)			((n - 1) << 0)
 #define QSPI_WLEN_MAX_BITS		128
 #define QSPI_WLEN_MAX_BYTES		16
+#define QSPI_WLEN_MASK			QSPI_WLEN(QSPI_WLEN_MAX_BITS)
 
 /* STATUS REGISTER */
 #define BUSY				0x01
@@ -158,6 +159,7 @@
 
 	ret = pm_runtime_get_sync(qspi->dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(qspi->dev);
 		dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
 		return ret;
 	}
@@ -224,16 +226,16 @@
 	return  -ETIMEDOUT;
 }
 
-static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t,
+			  int count)
 {
-	int wlen, count, xfer_len;
+	int wlen, xfer_len;
 	unsigned int cmd;
 	const u8 *txbuf;
 	u32 data;
 
 	txbuf = t->tx_buf;
 	cmd = qspi->cmd | QSPI_WR_SNGL;
-	count = t->len;
 	wlen = t->bits_per_word >> 3;	/* in bytes */
 	xfer_len = wlen;
 
@@ -293,9 +295,10 @@
 	return 0;
 }
 
-static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t,
+			 int count)
 {
-	int wlen, count;
+	int wlen;
 	unsigned int cmd;
 	u8 *rxbuf;
 
@@ -312,7 +315,6 @@
 		cmd |= QSPI_RD_SNGL;
 		break;
 	}
-	count = t->len;
 	wlen = t->bits_per_word >> 3;	/* in bytes */
 
 	while (count) {
@@ -343,12 +345,13 @@
 	return 0;
 }
 
-static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t,
+			     int count)
 {
 	int ret;
 
 	if (t->tx_buf) {
-		ret = qspi_write_msg(qspi, t);
+		ret = qspi_write_msg(qspi, t, count);
 		if (ret) {
 			dev_dbg(qspi->dev, "Error while writing\n");
 			return ret;
@@ -356,7 +359,7 @@
 	}
 
 	if (t->rx_buf) {
-		ret = qspi_read_msg(qspi, t);
+		ret = qspi_read_msg(qspi, t, count);
 		if (ret) {
 			dev_dbg(qspi->dev, "Error while reading\n");
 			return ret;
@@ -373,7 +376,8 @@
 	struct spi_device *spi = m->spi;
 	struct spi_transfer *t;
 	int status = 0, ret;
-	int frame_length;
+	unsigned int frame_len_words, transfer_len_words;
+	int wlen;
 
 	/* setup device control reg */
 	qspi->dc = 0;
@@ -385,30 +389,38 @@
 	if (spi->mode & SPI_CS_HIGH)
 		qspi->dc |= QSPI_CSPOL(spi->chip_select);
 
-	frame_length = (m->frame_length << 3) / spi->bits_per_word;
-
-	frame_length = clamp(frame_length, 0, QSPI_FRAME);
+	frame_len_words = 0;
+	list_for_each_entry(t, &m->transfers, transfer_list)
+		frame_len_words += t->len / (t->bits_per_word >> 3);
+	frame_len_words = min_t(unsigned int, frame_len_words, QSPI_FRAME);
 
 	/* setup command reg */
 	qspi->cmd = 0;
 	qspi->cmd |= QSPI_EN_CS(spi->chip_select);
-	qspi->cmd |= QSPI_FLEN(frame_length);
+	qspi->cmd |= QSPI_FLEN(frame_len_words);
 
 	ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG);
 
 	mutex_lock(&qspi->list_lock);
 
 	list_for_each_entry(t, &m->transfers, transfer_list) {
-		qspi->cmd |= QSPI_WLEN(t->bits_per_word);
+		qspi->cmd = ((qspi->cmd & ~QSPI_WLEN_MASK) |
+			     QSPI_WLEN(t->bits_per_word));
+
+		wlen = t->bits_per_word >> 3;
+		transfer_len_words = min(t->len / wlen, frame_len_words);
 
-		ret = qspi_transfer_msg(qspi, t);
+		ret = qspi_transfer_msg(qspi, t, transfer_len_words * wlen);
 		if (ret) {
 			dev_dbg(qspi->dev, "transfer message failed\n");
 			mutex_unlock(&qspi->list_lock);
 			return -EINVAL;
 		}
 
-		m->actual_length += t->len;
+		m->actual_length += transfer_len_words * wlen;
+		frame_len_words -= transfer_len_words;
+		if (frame_len_words == 0)
+			break;
 	}
 
 	mutex_unlock(&qspi->list_lock);
--- linux-4.4.0.orig/drivers/spi/spi-topcliff-pch.c
+++ linux-4.4.0/drivers/spi/spi-topcliff-pch.c
@@ -1326,18 +1326,27 @@
 	return;
 }
 
-static void pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
+static int pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
 			      struct pch_spi_data *data)
 {
 	struct pch_spi_dma_ctrl *dma;
+	int ret;
 
 	dma = &data->dma;
+	ret = 0;
 	/* Get Consistent memory for Tx DMA */
 	dma->tx_buf_virt = dma_alloc_coherent(&board_dat->pdev->dev,
 				PCH_BUF_SIZE, &dma->tx_buf_dma, GFP_KERNEL);
+	if (!dma->tx_buf_virt)
+		ret = -ENOMEM;
+
 	/* Get Consistent memory for Rx DMA */
 	dma->rx_buf_virt = dma_alloc_coherent(&board_dat->pdev->dev,
 				PCH_BUF_SIZE, &dma->rx_buf_dma, GFP_KERNEL);
+	if (!dma->rx_buf_virt)
+		ret = -ENOMEM;
+
+	return ret;
 }
 
 static int pch_spi_pd_probe(struct platform_device *plat_dev)
@@ -1414,7 +1423,9 @@
 
 	if (use_dma) {
 		dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
-		pch_alloc_dma_buf(board_dat, data);
+		ret = pch_alloc_dma_buf(board_dat, data);
+		if (ret)
+			goto err_spi_register_master;
 	}
 
 	ret = spi_register_master(master);
--- linux-4.4.0.orig/drivers/spi/spi-xilinx.c
+++ linux-4.4.0/drivers/spi/spi-xilinx.c
@@ -271,6 +271,7 @@
 	while (remaining_words) {
 		int n_words, tx_words, rx_words;
 		u32 sr;
+		int stalled;
 
 		n_words = min(remaining_words, xspi->buffer_size);
 
@@ -299,7 +300,17 @@
 
 		/* Read out all the data from the Rx FIFO */
 		rx_words = n_words;
+		stalled = 10;
 		while (rx_words) {
+			if (rx_words == n_words && !(stalled--) &&
+			    !(sr & XSPI_SR_TX_EMPTY_MASK) &&
+			    (sr & XSPI_SR_RX_EMPTY_MASK)) {
+				dev_err(&spi->dev,
+					"Detected stall. Check C_SPI_MODE and C_SPI_MEMORY\n");
+				xspi_init_hw(xspi);
+				return -EIO;
+			}
+
 			if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) {
 				xilinx_spi_rx(xspi);
 				rx_words--;
--- linux-4.4.0.orig/drivers/spi/spi-xlp.c
+++ linux-4.4.0/drivers/spi/spi-xlp.c
@@ -392,8 +392,8 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(&pdev->dev, "no IRQ resource found\n");
-		return -EINVAL;
+		dev_err(&pdev->dev, "no IRQ resource found: %d\n", irq);
+		return irq;
 	}
 	err = devm_request_irq(&pdev->dev, irq, xlp_spi_interrupt, 0,
 			pdev->name, xspi);
--- linux-4.4.0.orig/drivers/spi/spi-zynqmp-gqspi.c
+++ linux-4.4.0/drivers/spi/spi-zynqmp-gqspi.c
@@ -414,9 +414,6 @@
 
 	zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry);
 
-	/* Dummy generic FIFO entry */
-	zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0);
-
 	/* Manually start the generic FIFO command */
 	zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
 			zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
--- linux-4.4.0.orig/drivers/spi/spi.c
+++ linux-4.4.0/drivers/spi/spi.c
@@ -496,7 +496,6 @@
  */
 int spi_add_device(struct spi_device *spi)
 {
-	static DEFINE_MUTEX(spi_add_lock);
 	struct spi_master *master = spi->master;
 	struct device *dev = master->dev.parent;
 	int status;
@@ -516,7 +515,7 @@
 	 * chipselect **BEFORE** we call setup(), else we'll trash
 	 * its configuration.  Lock against concurrent add() calls.
 	 */
-	mutex_lock(&spi_add_lock);
+	mutex_lock(&master->add_lock);
 
 	status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
 	if (status) {
@@ -525,6 +524,13 @@
 		goto done;
 	}
 
+	/* Controller may unregister concurrently */
+	if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
+	    !device_is_registered(&master->dev)) {
+		status = -ENODEV;
+		goto done;
+	}
+
 	if (master->cs_gpios)
 		spi->cs_gpio = master->cs_gpios[spi->chip_select];
 
@@ -548,7 +554,7 @@
 		dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
 
 done:
-	mutex_unlock(&spi_add_lock);
+	mutex_unlock(&master->add_lock);
 	return status;
 }
 EXPORT_SYMBOL_GPL(spi_add_device);
@@ -707,8 +713,14 @@
 	for (i = 0; i < sgs; i++) {
 
 		if (vmalloced_buf) {
-			min = min_t(size_t,
-				    len, desc_len - offset_in_page(buf));
+			/*
+			 * Next scatterlist entry size is the minimum between
+			 * the desc_len and the remaining buffer length that
+			 * fits in a page.
+			 */
+			min = min_t(size_t, desc_len,
+				    min_t(size_t, len,
+					  PAGE_SIZE - offset_in_page(buf)));
 			vm_page = vmalloc_to_page(buf);
 			if (!vm_page) {
 				sg_free_table(sgt);
@@ -897,6 +909,8 @@
 		if (max_tx || max_rx) {
 			list_for_each_entry(xfer, &msg->transfers,
 					    transfer_list) {
+				if (!xfer->len)
+					continue;
 				if (!xfer->tx_buf)
 					xfer->tx_buf = master->dummy_tx;
 				if (!xfer->rx_buf)
@@ -1712,6 +1726,47 @@
 }
 EXPORT_SYMBOL_GPL(spi_alloc_master);
 
+static void devm_spi_release_master(struct device *dev, void *master)
+{
+	spi_master_put(*(struct spi_master **)master);
+}
+
+/**
+ * devm_spi_alloc_master - resource-managed spi_alloc_master()
+ * @dev: physical device of SPI master
+ * @size: how much zeroed driver-private data to allocate
+ * Context: can sleep
+ *
+ * Allocate an SPI master and automatically release a reference on it
+ * when @dev is unbound from its driver.  Drivers are thus relieved from
+ * having to call spi_master_put().
+ *
+ * The arguments to this function are identical to spi_alloc_master().
+ *
+ * Return: the SPI master structure on success, else NULL.
+ */
+struct spi_master *devm_spi_alloc_master(struct device *dev, unsigned int size)
+{
+	struct spi_master **ptr, *master;
+
+	ptr = devres_alloc(devm_spi_release_master, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return NULL;
+
+	master = spi_alloc_master(dev, size);
+	if (master) {
+		master->devm_allocated = true;
+		*ptr = master;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return master;
+}
+EXPORT_SYMBOL_GPL(devm_spi_alloc_master);
+
 #ifdef CONFIG_OF
 static int of_spi_register_master(struct spi_master *master)
 {
@@ -1812,6 +1867,7 @@
 	spin_lock_init(&master->queue_lock);
 	spin_lock_init(&master->bus_lock_spinlock);
 	mutex_init(&master->bus_lock_mutex);
+	mutex_init(&master->add_lock);
 	master->bus_lock_flag = 0;
 	init_completion(&master->xfer_completion);
 	if (!master->max_dma_len)
@@ -1909,7 +1965,11 @@
  */
 void spi_unregister_master(struct spi_master *master)
 {
-	int dummy;
+	/* Prevent addition of new devices, unregister existing ones */
+	if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
+		mutex_lock(&master->add_lock);
+
+	device_for_each_child(&master->dev, NULL, __unregister);
 
 	if (master->queued) {
 		if (spi_destroy_queue(master))
@@ -1920,8 +1980,16 @@
 	list_del(&master->list);
 	mutex_unlock(&board_lock);
 
-	dummy = device_for_each_child(&master->dev, NULL, __unregister);
-	device_unregister(&master->dev);
+	device_del(&master->dev);
+
+	if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
+		mutex_unlock(&master->add_lock);
+
+	/* Release the last reference on the master if its driver
+	 * has not yet been converted to devm_spi_alloc_master().
+	 */
+	if (!master->devm_allocated)
+		put_device(&master->dev);
 }
 EXPORT_SYMBOL_GPL(spi_unregister_master);
 
--- linux-4.4.0.orig/drivers/spi/spidev.c
+++ linux-4.4.0/drivers/spi/spidev.c
@@ -635,15 +635,20 @@
 static int spidev_release(struct inode *inode, struct file *filp)
 {
 	struct spidev_data	*spidev;
+	int			dofree;
 
 	mutex_lock(&device_list_lock);
 	spidev = filp->private_data;
 	filp->private_data = NULL;
 
+	spin_lock_irq(&spidev->spi_lock);
+	/* ... after we unbound from the underlying device? */
+	dofree = (spidev->spi == NULL);
+	spin_unlock_irq(&spidev->spi_lock);
+
 	/* last close? */
 	spidev->users--;
 	if (!spidev->users) {
-		int		dofree;
 
 		kfree(spidev->tx_buffer);
 		spidev->tx_buffer = NULL;
@@ -651,17 +656,15 @@
 		kfree(spidev->rx_buffer);
 		spidev->rx_buffer = NULL;
 
-		spin_lock_irq(&spidev->spi_lock);
-		if (spidev->spi)
-			spidev->speed_hz = spidev->spi->max_speed_hz;
-
-		/* ... after we unbound from the underlying device? */
-		dofree = (spidev->spi == NULL);
-		spin_unlock_irq(&spidev->spi_lock);
-
 		if (dofree)
 			kfree(spidev);
+		else
+			spidev->speed_hz = spidev->spi->max_speed_hz;
 	}
+#ifdef CONFIG_SPI_SLAVE
+	if (!dofree)
+		spi_slave_abort(spidev->spi);
+#endif
 	mutex_unlock(&device_list_lock);
 
 	return 0;
@@ -713,11 +716,9 @@
 	 * compatible string, it is a Linux implementation thing
 	 * rather than a description of the hardware.
 	 */
-	if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
-		dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
-		WARN_ON(spi->dev.of_node &&
-			!of_match_device(spidev_dt_ids, &spi->dev));
-	}
+	WARN(spi->dev.of_node &&
+	     of_device_is_compatible(spi->dev.of_node, "spidev"),
+	     "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
 
 	/* Allocate driver data */
 	spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
@@ -768,13 +769,13 @@
 {
 	struct spidev_data	*spidev = spi_get_drvdata(spi);
 
+	/* prevent new opens */
+	mutex_lock(&device_list_lock);
 	/* make sure ops on existing fds can abort cleanly */
 	spin_lock_irq(&spidev->spi_lock);
 	spidev->spi = NULL;
 	spin_unlock_irq(&spidev->spi_lock);
 
-	/* prevent new opens */
-	mutex_lock(&device_list_lock);
 	list_del(&spidev->device_entry);
 	device_destroy(spidev_class, spidev->devt);
 	clear_bit(MINOR(spidev->devt), minors);
--- linux-4.4.0.orig/drivers/spmi/spmi.c
+++ linux-4.4.0/drivers/spmi/spmi.c
@@ -364,11 +364,23 @@
 	return 0;
 }
 
+static int spmi_drv_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	int ret;
+
+	ret = of_device_uevent_modalias(dev, env);
+	if (ret != -ENODEV)
+		return ret;
+
+	return 0;
+}
+
 static struct bus_type spmi_bus_type = {
 	.name		= "spmi",
 	.match		= spmi_device_match,
 	.probe		= spmi_drv_probe,
 	.remove		= spmi_drv_remove,
+	.uevent		= spmi_drv_uevent,
 };
 
 /**
--- linux-4.4.0.orig/drivers/ssb/bridge_pcmcia_80211.c
+++ linux-4.4.0/drivers/ssb/bridge_pcmcia_80211.c
@@ -113,16 +113,21 @@
 	.resume		= ssb_host_pcmcia_resume,
 };
 
+static int pcmcia_init_failed;
+
 /*
  * These are not module init/exit functions!
  * The module_pcmcia_driver() helper cannot be used here.
  */
 int ssb_host_pcmcia_init(void)
 {
-	return pcmcia_register_driver(&ssb_host_pcmcia_driver);
+	pcmcia_init_failed = pcmcia_register_driver(&ssb_host_pcmcia_driver);
+
+	return pcmcia_init_failed;
 }
 
 void ssb_host_pcmcia_exit(void)
 {
-	pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
+	if (!pcmcia_init_failed)
+		pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
 }
--- linux-4.4.0.orig/drivers/ssb/main.c
+++ linux-4.4.0/drivers/ssb/main.c
@@ -339,11 +339,13 @@
 
 static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	struct ssb_device *ssb_dev;
 
 	if (!dev)
 		return -ENODEV;
 
+	ssb_dev = dev_to_ssb_dev(dev);
+
 	return add_uevent_var(env,
 			     "MODALIAS=ssb:v%04Xid%04Xrev%02X",
 			     ssb_dev->id.vendor, ssb_dev->id.coreid,
@@ -613,9 +615,10 @@
 	return err;
 }
 
-static int ssb_bus_register(struct ssb_bus *bus,
-			    ssb_invariants_func_t get_invariants,
-			    unsigned long baseaddr)
+static int __maybe_unused
+ssb_bus_register(struct ssb_bus *bus,
+		 ssb_invariants_func_t get_invariants,
+		 unsigned long baseaddr)
 {
 	int err;
 
--- linux-4.4.0.orig/drivers/ssb/pci.c
+++ linux-4.4.0/drivers/ssb/pci.c
@@ -909,6 +909,7 @@
 			if (err) {
 				ssb_warn("WARNING: Using fallback SPROM failed (err %d)\n",
 					 err);
+				goto out_free;
 			} else {
 				ssb_dbg("Using SPROM revision %d provided by platform\n",
 					sprom->revision);
--- linux-4.4.0.orig/drivers/staging/android/ashmem.c
+++ linux-4.4.0/drivers/staging/android/ashmem.c
@@ -330,24 +330,23 @@
 	mutex_lock(&ashmem_mutex);
 
 	if (asma->size == 0) {
-		ret = -EINVAL;
-		goto out;
+		mutex_unlock(&ashmem_mutex);
+		return -EINVAL;
 	}
 
 	if (!asma->file) {
-		ret = -EBADF;
-		goto out;
+		mutex_unlock(&ashmem_mutex);
+		return -EBADF;
 	}
 
+	mutex_unlock(&ashmem_mutex);
+
 	ret = vfs_llseek(asma->file, offset, origin);
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	/** Copy f_pos from backing file, since f_ops->llseek() sets it */
 	file->f_pos = asma->file->f_pos;
-
-out:
-	mutex_unlock(&ashmem_mutex);
 	return ret;
 }
 
@@ -358,8 +357,23 @@
 	       _calc_vm_trans(prot, PROT_EXEC,  VM_MAYEXEC);
 }
 
+static int ashmem_vmfile_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	/* do not allow to mmap ashmem backing shmem file directly */
+	return -EPERM;
+}
+
+static unsigned long
+ashmem_vmfile_get_unmapped_area(struct file *file, unsigned long addr,
+				unsigned long len, unsigned long pgoff,
+				unsigned long flags)
+{
+	return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
+}
+
 static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
 {
+	static struct file_operations vmfile_fops;
 	struct ashmem_area *asma = file->private_data;
 	int ret = 0;
 
@@ -371,6 +385,12 @@
 		goto out;
 	}
 
+	/* requested mapping size larger than object size */
+	if (vma->vm_end - vma->vm_start > PAGE_ALIGN(asma->size)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* requested protection bits must match our allowed protection mask */
 	if (unlikely((vma->vm_flags & ~calc_vm_prot_bits(asma->prot_mask)) &
 		     calc_vm_prot_bits(PROT_MASK))) {
@@ -392,7 +412,21 @@
 			ret = PTR_ERR(vmfile);
 			goto out;
 		}
+		vmfile->f_mode |= FMODE_LSEEK;
 		asma->file = vmfile;
+		/*
+		 * override mmap operation of the vmfile so that it can't be
+		 * remapped which would lead to creation of a new vma with no
+		 * asma permission checks. Have to override get_unmapped_area
+		 * as well to prevent VM_BUG_ON check for f_ops modification.
+		 */
+		if (!vmfile_fops.mmap) {
+			vmfile_fops = *vmfile->f_op;
+			vmfile_fops.mmap = ashmem_vmfile_mmap;
+			vmfile_fops.get_unmapped_area =
+					ashmem_vmfile_get_unmapped_area;
+		}
+		vmfile->f_op = &vmfile_fops;
 	}
 	get_file(asma->file);
 
@@ -441,7 +475,9 @@
 	if (!(sc->gfp_mask & __GFP_FS))
 		return SHRINK_STOP;
 
-	mutex_lock(&ashmem_mutex);
+	if (!mutex_trylock(&ashmem_mutex))
+		return -1;
+
 	list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
 		loff_t start = range->pgstart * PAGE_SIZE;
 		loff_t end = (range->pgend + 1) * PAGE_SIZE;
@@ -703,30 +739,30 @@
 	size_t pgstart, pgend;
 	int ret = -EINVAL;
 
-	if (unlikely(!asma->file))
-		return -EINVAL;
-
 	if (unlikely(copy_from_user(&pin, p, sizeof(pin))))
 		return -EFAULT;
 
+	mutex_lock(&ashmem_mutex);
+
+	if (unlikely(!asma->file))
+		goto out_unlock;
+
 	/* per custom, you can pass zero for len to mean "everything onward" */
 	if (!pin.len)
 		pin.len = PAGE_ALIGN(asma->size) - pin.offset;
 
 	if (unlikely((pin.offset | pin.len) & ~PAGE_MASK))
-		return -EINVAL;
+		goto out_unlock;
 
 	if (unlikely(((__u32)-1) - pin.offset < pin.len))
-		return -EINVAL;
+		goto out_unlock;
 
 	if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len))
-		return -EINVAL;
+		goto out_unlock;
 
 	pgstart = pin.offset / PAGE_SIZE;
 	pgend = pgstart + (pin.len / PAGE_SIZE) - 1;
 
-	mutex_lock(&ashmem_mutex);
-
 	switch (cmd) {
 	case ASHMEM_PIN:
 		ret = ashmem_pin(asma, pgstart, pgend);
@@ -739,6 +775,7 @@
 		break;
 	}
 
+out_unlock:
 	mutex_unlock(&ashmem_mutex);
 
 	return ret;
@@ -758,10 +795,12 @@
 		break;
 	case ASHMEM_SET_SIZE:
 		ret = -EINVAL;
+		mutex_lock(&ashmem_mutex);
 		if (!asma->file) {
 			ret = 0;
 			asma->size = (size_t)arg;
 		}
+		mutex_unlock(&ashmem_mutex);
 		break;
 	case ASHMEM_GET_SIZE:
 		ret = asma->size;
--- linux-4.4.0.orig/drivers/staging/android/ion/ion.c
+++ linux-4.4.0/drivers/staging/android/ion/ion.c
@@ -15,6 +15,7 @@
  *
  */
 
+#include <linux/atomic.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/file.h>
@@ -251,8 +252,10 @@
 	 * memory coming from the heaps is ready for dma, ie if it has a
 	 * cached mapping that mapping has been invalidated
 	 */
-	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
+	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
 		sg_dma_address(sg) = sg_phys(sg);
+		sg_dma_len(sg) = sg->length;
+	}
 	mutex_lock(&dev->buffer_lock);
 	ion_buffer_add(dev, buffer);
 	mutex_unlock(&dev->buffer_lock);
@@ -385,13 +388,32 @@
 	kref_get(&handle->ref);
 }
 
-static int ion_handle_put(struct ion_handle *handle)
+/* Must hold the client lock */
+static struct ion_handle *ion_handle_get_check_overflow(
+					struct ion_handle *handle)
+{
+	if (atomic_read(&handle->ref.refcount) + 1 == 0)
+		return ERR_PTR(-EOVERFLOW);
+	ion_handle_get(handle);
+	return handle;
+}
+
+static int ion_handle_put_nolock(struct ion_handle *handle)
+{
+	int ret;
+
+	ret = kref_put(&handle->ref, ion_handle_destroy);
+
+	return ret;
+}
+
+int ion_handle_put(struct ion_handle *handle)
 {
 	struct ion_client *client = handle->client;
 	int ret;
 
 	mutex_lock(&client->lock);
-	ret = kref_put(&handle->ref, ion_handle_destroy);
+	ret = ion_handle_put_nolock(handle);
 	mutex_unlock(&client->lock);
 
 	return ret;
@@ -415,18 +437,16 @@
 	return ERR_PTR(-EINVAL);
 }
 
-static struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client,
 						int id)
 {
 	struct ion_handle *handle;
 
-	mutex_lock(&client->lock);
 	handle = idr_find(&client->idr, id);
 	if (handle)
-		ion_handle_get(handle);
-	mutex_unlock(&client->lock);
+		return ion_handle_get_check_overflow(handle);
 
-	return handle ? handle : ERR_PTR(-EINVAL);
+	return ERR_PTR(-EINVAL);
 }
 
 static bool ion_handle_validate(struct ion_client *client,
@@ -530,22 +550,28 @@
 }
 EXPORT_SYMBOL(ion_alloc);
 
-void ion_free(struct ion_client *client, struct ion_handle *handle)
+static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle)
 {
 	bool valid_handle;
 
 	BUG_ON(client != handle->client);
 
-	mutex_lock(&client->lock);
 	valid_handle = ion_handle_validate(client, handle);
 
 	if (!valid_handle) {
 		WARN(1, "%s: invalid handle passed to free.\n", __func__);
-		mutex_unlock(&client->lock);
 		return;
 	}
+	ion_handle_put_nolock(handle);
+}
+
+void ion_free(struct ion_client *client, struct ion_handle *handle)
+{
+	BUG_ON(client != handle->client);
+
+	mutex_lock(&client->lock);
+	ion_free_nolock(client, handle);
 	mutex_unlock(&client->lock);
-	ion_handle_put(handle);
 }
 EXPORT_SYMBOL(ion_free);
 
@@ -580,6 +606,9 @@
 	void *vaddr;
 
 	if (buffer->kmap_cnt) {
+		if (buffer->kmap_cnt == INT_MAX)
+			return ERR_PTR(-EOVERFLOW);
+
 		buffer->kmap_cnt++;
 		return buffer->vaddr;
 	}
@@ -600,6 +629,9 @@
 	void *vaddr;
 
 	if (handle->kmap_cnt) {
+		if (handle->kmap_cnt == INT_MAX)
+			return ERR_PTR(-EOVERFLOW);
+
 		handle->kmap_cnt++;
 		return buffer->vaddr;
 	}
@@ -1100,24 +1132,28 @@
 	.kunmap = ion_dma_buf_kunmap,
 };
 
-struct dma_buf *ion_share_dma_buf(struct ion_client *client,
-						struct ion_handle *handle)
+static struct dma_buf *__ion_share_dma_buf(struct ion_client *client,
+					   struct ion_handle *handle,
+					   bool lock_client)
 {
 	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
 	struct ion_buffer *buffer;
 	struct dma_buf *dmabuf;
 	bool valid_handle;
 
-	mutex_lock(&client->lock);
+	if (lock_client)
+		mutex_lock(&client->lock);
 	valid_handle = ion_handle_validate(client, handle);
 	if (!valid_handle) {
 		WARN(1, "%s: invalid handle passed to share.\n", __func__);
-		mutex_unlock(&client->lock);
+		if (lock_client)
+			mutex_unlock(&client->lock);
 		return ERR_PTR(-EINVAL);
 	}
 	buffer = handle->buffer;
 	ion_buffer_get(buffer);
-	mutex_unlock(&client->lock);
+	if (lock_client)
+		mutex_unlock(&client->lock);
 
 	exp_info.ops = &dma_buf_ops;
 	exp_info.size = buffer->size;
@@ -1132,14 +1168,21 @@
 
 	return dmabuf;
 }
+
+struct dma_buf *ion_share_dma_buf(struct ion_client *client,
+				  struct ion_handle *handle)
+{
+	return __ion_share_dma_buf(client, handle, true);
+}
 EXPORT_SYMBOL(ion_share_dma_buf);
 
-int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle)
+static int __ion_share_dma_buf_fd(struct ion_client *client,
+				  struct ion_handle *handle, bool lock_client)
 {
 	struct dma_buf *dmabuf;
 	int fd;
 
-	dmabuf = ion_share_dma_buf(client, handle);
+	dmabuf = __ion_share_dma_buf(client, handle, lock_client);
 	if (IS_ERR(dmabuf))
 		return PTR_ERR(dmabuf);
 
@@ -1149,8 +1192,19 @@
 
 	return fd;
 }
+
+int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle)
+{
+	return __ion_share_dma_buf_fd(client, handle, true);
+}
 EXPORT_SYMBOL(ion_share_dma_buf_fd);
 
+static int ion_share_dma_buf_fd_nolock(struct ion_client *client,
+				       struct ion_handle *handle)
+{
+	return __ion_share_dma_buf_fd(client, handle, false);
+}
+
 struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
 {
 	struct dma_buf *dmabuf;
@@ -1175,7 +1229,7 @@
 	/* if a handle exists for this buffer just take a reference to it */
 	handle = ion_handle_lookup(client, buffer);
 	if (!IS_ERR(handle)) {
-		ion_handle_get(handle);
+		handle = ion_handle_get_check_overflow(handle);
 		mutex_unlock(&client->lock);
 		goto end;
 	}
@@ -1281,11 +1335,15 @@
 	{
 		struct ion_handle *handle;
 
-		handle = ion_handle_get_by_id(client, data.handle.handle);
-		if (IS_ERR(handle))
+		mutex_lock(&client->lock);
+		handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
+		if (IS_ERR(handle)) {
+			mutex_unlock(&client->lock);
 			return PTR_ERR(handle);
-		ion_free(client, handle);
-		ion_handle_put(handle);
+		}
+		ion_free_nolock(client, handle);
+		ion_handle_put_nolock(handle);
+		mutex_unlock(&client->lock);
 		break;
 	}
 	case ION_IOC_SHARE:
@@ -1293,11 +1351,15 @@
 	{
 		struct ion_handle *handle;
 
-		handle = ion_handle_get_by_id(client, data.handle.handle);
-		if (IS_ERR(handle))
+		mutex_lock(&client->lock);
+		handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
+		if (IS_ERR(handle)) {
+			mutex_unlock(&client->lock);
 			return PTR_ERR(handle);
-		data.fd.fd = ion_share_dma_buf_fd(client, handle);
-		ion_handle_put(handle);
+		}
+		data.fd.fd = ion_share_dma_buf_fd_nolock(client, handle);
+		ion_handle_put_nolock(handle);
+		mutex_unlock(&client->lock);
 		if (data.fd.fd < 0)
 			ret = data.fd.fd;
 		break;
--- linux-4.4.0.orig/drivers/staging/android/ion/ion_carveout_heap.c
+++ linux-4.4.0/drivers/staging/android/ion/ion_carveout_heap.c
@@ -167,7 +167,7 @@
 	if (!carveout_heap)
 		return ERR_PTR(-ENOMEM);
 
-	carveout_heap->pool = gen_pool_create(12, -1);
+	carveout_heap->pool = gen_pool_create(PAGE_SHIFT, -1);
 	if (!carveout_heap->pool) {
 		kfree(carveout_heap);
 		return ERR_PTR(-ENOMEM);
--- linux-4.4.0.orig/drivers/staging/android/ion/ion_heap.c
+++ linux-4.4.0/drivers/staging/android/ion/ion_heap.c
@@ -38,7 +38,7 @@
 	struct page **tmp = pages;
 
 	if (!pages)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	if (buffer->flags & ION_FLAG_CACHED)
 		pgprot = PAGE_KERNEL;
@@ -105,12 +105,12 @@
 
 static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot)
 {
-	void *addr = vm_map_ram(pages, num, -1, pgprot);
+	void *addr = vmap(pages, num, VM_MAP, pgprot);
 
 	if (!addr)
 		return -ENOMEM;
 	memset(addr, 0, PAGE_SIZE * num);
-	vm_unmap_ram(addr, num);
+	vunmap(addr);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/staging/android/ion/ion_system_heap.c
+++ linux-4.4.0/drivers/staging/android/ion/ion_system_heap.c
@@ -27,7 +27,7 @@
 #include "ion_priv.h"
 
 static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN |
-				     __GFP_NORETRY) & ~__GFP_DIRECT_RECLAIM;
+				     __GFP_NORETRY) & ~__GFP_RECLAIM;
 static gfp_t low_order_gfp_flags  = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN);
 static const unsigned int orders[] = {8, 4, 0};
 static const int num_orders = ARRAY_SIZE(orders);
--- linux-4.4.0.orig/drivers/staging/android/ion/ion_test.c
+++ linux-4.4.0/drivers/staging/android/ion/ion_test.c
@@ -285,8 +285,8 @@
 {
 	ion_test_pdev = platform_device_register_simple("ion-test",
 							-1, NULL, 0);
-	if (!ion_test_pdev)
-		return -ENODEV;
+	if (IS_ERR(ion_test_pdev))
+		return PTR_ERR(ion_test_pdev);
 
 	return platform_driver_probe(&ion_test_platform_driver, ion_test_probe);
 }
--- linux-4.4.0.orig/drivers/staging/android/sync.c
+++ linux-4.4.0/drivers/staging/android/sync.c
@@ -519,12 +519,10 @@
 static void sync_fence_free(struct kref *kref)
 {
 	struct sync_fence *fence = container_of(kref, struct sync_fence, kref);
-	int i, status = atomic_read(&fence->status);
+	int i;
 
 	for (i = 0; i < fence->num_fences; ++i) {
-		if (status)
-			fence_remove_callback(fence->cbs[i].sync_pt,
-					      &fence->cbs[i].cb);
+		fence_remove_callback(fence->cbs[i].sync_pt, &fence->cbs[i].cb);
 		fence_put(fence->cbs[i].sync_pt);
 	}
 
--- linux-4.4.0.orig/drivers/staging/android/uapi/ashmem.h
+++ linux-4.4.0/drivers/staging/android/uapi/ashmem.h
@@ -13,6 +13,7 @@
 #define _UAPI_LINUX_ASHMEM_H
 
 #include <linux/ioctl.h>
+#include <linux/types.h>
 
 #define ASHMEM_NAME_LEN		256
 
--- linux-4.4.0.orig/drivers/staging/comedi/comedi_fops.c
+++ linux-4.4.0/drivers/staging/comedi/comedi_fops.c
@@ -2592,8 +2592,10 @@
 	}
 
 	cfp = kzalloc(sizeof(*cfp), GFP_KERNEL);
-	if (!cfp)
+	if (!cfp) {
+		comedi_dev_put(dev);
 		return -ENOMEM;
+	}
 
 	cfp->dev = dev;
 
@@ -2901,9 +2903,6 @@
 
 	comedi_class->dev_groups = comedi_dev_groups;
 
-	/* XXX requires /proc interface */
-	comedi_proc_init();
-
 	/* create devices files for legacy/manual use */
 	for (i = 0; i < comedi_num_legacy_minors; i++) {
 		struct comedi_device *dev;
@@ -2911,6 +2910,7 @@
 		dev = comedi_alloc_board_minor(NULL);
 		if (IS_ERR(dev)) {
 			comedi_cleanup_board_minors();
+			class_destroy(comedi_class);
 			cdev_del(&comedi_cdev);
 			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
 						 COMEDI_NUM_MINORS);
@@ -2920,6 +2920,9 @@
 		mutex_unlock(&dev->mutex);
 	}
 
+	/* XXX requires /proc interface */
+	comedi_proc_init();
+
 	return 0;
 }
 module_init(comedi_init);
--- linux-4.4.0.orig/drivers/staging/comedi/drivers.c
+++ linux-4.4.0/drivers/staging/comedi/drivers.c
@@ -484,8 +484,7 @@
 	struct comedi_cmd *cmd = &async->cmd;
 
 	if (cmd->stop_src == TRIG_COUNT) {
-		unsigned int nscans = nsamples / cmd->scan_end_arg;
-		unsigned int scans_left = __comedi_nscans_left(s, nscans);
+		unsigned int scans_left = __comedi_nscans_left(s, cmd->stop_arg);
 		unsigned int scan_pos =
 		    comedi_bytes_to_samples(s, async->scan_progress);
 		unsigned long long samples_left = 0;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -115,14 +115,22 @@
 				    unsigned int *data)
 {
 	struct apci1032_private *devpriv = dev->private;
-	unsigned int shift, oldmask;
+	unsigned int shift, oldmask, himask, lomask;
 
 	switch (data[0]) {
 	case INSN_CONFIG_DIGITAL_TRIG:
 		if (data[1] != 0)
 			return -EINVAL;
 		shift = data[3];
-		oldmask = (1U << shift) - 1;
+		if (shift < 32) {
+			oldmask = (1U << shift) - 1;
+			himask = data[4] << shift;
+			lomask = data[5] << shift;
+		} else {
+			oldmask = 0xffffffffu;
+			himask = 0;
+			lomask = 0;
+		}
 		switch (data[2]) {
 		case COMEDI_DIGITAL_TRIG_DISABLE:
 			devpriv->ctrl = 0;
@@ -145,8 +153,8 @@
 				devpriv->mode2 &= oldmask;
 			}
 			/* configure specified channels */
-			devpriv->mode1 |= data[4] << shift;
-			devpriv->mode2 |= data[5] << shift;
+			devpriv->mode1 |= himask;
+			devpriv->mode2 |= lomask;
 			break;
 		case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS:
 			if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA |
@@ -163,8 +171,8 @@
 				devpriv->mode2 &= oldmask;
 			}
 			/* configure specified channels */
-			devpriv->mode1 |= data[4] << shift;
-			devpriv->mode2 |= data[5] << shift;
+			devpriv->mode1 |= himask;
+			devpriv->mode2 |= lomask;
 			break;
 		default:
 			return -EINVAL;
@@ -261,6 +269,7 @@
 	struct apci1032_private *devpriv = dev->private;
 	struct comedi_subdevice *s = dev->read_subdev;
 	unsigned int ctrl;
+	unsigned short val;
 
 	/* check interrupt is from this device */
 	if ((inl(devpriv->amcc_iobase + AMCC_OP_REG_INTCSR) &
@@ -276,7 +285,8 @@
 	outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG);
 
 	s->state = inl(dev->iobase + APCI1032_STATUS_REG) & 0xffff;
-	comedi_buf_write_samples(s, &s->state, 1);
+	val = s->state;
+	comedi_buf_write_samples(s, &val, 1);
 	comedi_handle_events(dev, s);
 
 	/* enable the interrupt */
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -217,7 +217,7 @@
 	struct comedi_device *dev = d;
 	struct apci1500_private *devpriv = dev->private;
 	struct comedi_subdevice *s = dev->read_subdev;
-	unsigned int status = 0;
+	unsigned short status = 0;
 	unsigned int val;
 
 	val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
@@ -247,14 +247,14 @@
 	 *
 	 *    Mask     Meaning
 	 * ----------  ------------------------------------------
-	 * 0x00000001  Event 1 has occurred
-	 * 0x00000010  Event 2 has occurred
-	 * 0x00000100  Counter/timer 1 has run down (not implemented)
-	 * 0x00001000  Counter/timer 2 has run down (not implemented)
-	 * 0x00010000  Counter 3 has run down (not implemented)
-	 * 0x00100000  Watchdog has run down (not implemented)
-	 * 0x01000000  Voltage error
-	 * 0x10000000  Short-circuit error
+	 * 0b00000001  Event 1 has occurred
+	 * 0b00000010  Event 2 has occurred
+	 * 0b00000100  Counter/timer 1 has run down (not implemented)
+	 * 0b00001000  Counter/timer 2 has run down (not implemented)
+	 * 0b00010000  Counter 3 has run down (not implemented)
+	 * 0b00100000  Watchdog has run down (not implemented)
+	 * 0b01000000  Voltage error
+	 * 0b10000000  Short-circuit error
 	 */
 	comedi_buf_write_samples(s, &status, 1);
 	comedi_handle_events(dev, s);
@@ -461,13 +461,14 @@
 	struct apci1500_private *devpriv = dev->private;
 	unsigned int trig = data[1];
 	unsigned int shift = data[3];
-	unsigned int hi_mask = data[4] << shift;
-	unsigned int lo_mask = data[5] << shift;
-	unsigned int chan_mask = hi_mask | lo_mask;
-	unsigned int old_mask = (1 << shift) - 1;
-	unsigned int pm = devpriv->pm[trig] & old_mask;
-	unsigned int pt = devpriv->pt[trig] & old_mask;
-	unsigned int pp = devpriv->pp[trig] & old_mask;
+	unsigned int hi_mask;
+	unsigned int lo_mask;
+	unsigned int chan_mask;
+	unsigned int old_mask;
+	unsigned int pm;
+	unsigned int pt;
+	unsigned int pp;
+	unsigned int invalid_chan;
 
 	if (trig > 1) {
 		dev_dbg(dev->class_dev,
@@ -475,11 +476,28 @@
 		return -EINVAL;
 	}
 
-	if (chan_mask > 0xffff) {
+	if (shift <= 16) {
+		hi_mask = data[4] << shift;
+		lo_mask = data[5] << shift;
+		old_mask = (1U << shift) - 1;
+		invalid_chan = (data[4] | data[5]) >> (16 - shift);
+	} else {
+		hi_mask = 0;
+		lo_mask = 0;
+		old_mask = 0xffff;
+		invalid_chan = data[4] | data[5];
+	}
+	chan_mask = hi_mask | lo_mask;
+
+	if (invalid_chan) {
 		dev_dbg(dev->class_dev, "invalid digital trigger channel\n");
 		return -EINVAL;
 	}
 
+	pm = devpriv->pm[trig] & old_mask;
+	pt = devpriv->pt[trig] & old_mask;
+	pp = devpriv->pp[trig] & old_mask;
+
 	switch (data[2]) {
 	case COMEDI_DIGITAL_TRIG_DISABLE:
 		/* clear trigger configuration */
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -288,14 +288,22 @@
 				    unsigned int *data)
 {
 	struct apci1564_private *devpriv = dev->private;
-	unsigned int shift, oldmask;
+	unsigned int shift, oldmask, himask, lomask;
 
 	switch (data[0]) {
 	case INSN_CONFIG_DIGITAL_TRIG:
 		if (data[1] != 0)
 			return -EINVAL;
 		shift = data[3];
-		oldmask = (1U << shift) - 1;
+		if (shift < 32) {
+			oldmask = (1U << shift) - 1;
+			himask = data[4] << shift;
+			lomask = data[5] << shift;
+		} else {
+			oldmask = 0xffffffffu;
+			himask = 0;
+			lomask = 0;
+		}
 		switch (data[2]) {
 		case COMEDI_DIGITAL_TRIG_DISABLE:
 			devpriv->ctrl = 0;
@@ -319,8 +327,8 @@
 				devpriv->mode2 &= oldmask;
 			}
 			/* configure specified channels */
-			devpriv->mode1 |= data[4] << shift;
-			devpriv->mode2 |= data[5] << shift;
+			devpriv->mode1 |= himask;
+			devpriv->mode2 |= lomask;
 			break;
 		case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS:
 			if (devpriv->ctrl != (APCI1564_DI_IRQ_ENA |
@@ -337,8 +345,8 @@
 				devpriv->mode2 &= oldmask;
 			}
 			/* configure specified channels */
-			devpriv->mode1 |= data[4] << shift;
-			devpriv->mode2 |= data[5] << shift;
+			devpriv->mode1 |= himask;
+			devpriv->mode2 |= lomask;
 			break;
 		default:
 			return -EINVAL;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/adv_pci1710.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -351,11 +351,11 @@
 static int pci171x_ai_read_sample(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  unsigned int cur_chan,
-				  unsigned int *val)
+				  unsigned short *val)
 {
 	const struct boardtype *board = dev->board_ptr;
 	struct pci1710_private *devpriv = dev->private;
-	unsigned int sample;
+	unsigned short sample;
 	unsigned int chan;
 
 	sample = inw(dev->iobase + PCI171X_AD_DATA_REG);
@@ -395,7 +395,7 @@
 	pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
 
 	for (i = 0; i < insn->n; i++) {
-		unsigned int val;
+		unsigned short val;
 
 		/* start conversion */
 		outw(0, dev->iobase + PCI171X_SOFTTRG_REG);
@@ -516,7 +516,7 @@
 {
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int status;
-	unsigned int val;
+	unsigned short val;
 	int ret;
 
 	status = inw(dev->iobase + PCI171X_STATUS_REG);
@@ -576,7 +576,7 @@
 	}
 
 	for (i = 0; i < devpriv->max_samples; i++) {
-		unsigned int val;
+		unsigned short val;
 		int ret;
 
 		ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/amplc_pci230.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -2324,7 +2324,8 @@
 	devpriv->intr_running = false;
 	spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
 
-	comedi_handle_events(dev, s_ao);
+	if (s_ao)
+		comedi_handle_events(dev, s_ao);
 	comedi_handle_events(dev, s_ai);
 
 	return IRQ_HANDLED;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/cb_pcidas.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -1351,6 +1351,7 @@
 		if (dev->irq && board->has_ao_fifo) {
 			dev->write_subdev = s;
 			s->subdev_flags	|= SDF_CMD_WRITE;
+			s->len_chanlist	= s->n_chan;
 			s->do_cmdtest	= cb_pcidas_ao_cmdtest;
 			s->do_cmd	= cb_pcidas_ao_cmd;
 			s->cancel	= cb_pcidas_ao_cancel;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/comedi_test.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/comedi_test.c
@@ -56,11 +56,6 @@
 
 #define N_CHANS 8
 
-enum waveform_state_bits {
-	WAVEFORM_AI_RUNNING,
-	WAVEFORM_AO_RUNNING
-};
-
 /* Data unique to this driver */
 struct waveform_private {
 	struct timer_list ai_timer;	/* timer for AI commands */
@@ -68,7 +63,6 @@
 	unsigned int wf_amplitude;	/* waveform amplitude in microvolts */
 	unsigned int wf_period;		/* waveform period in microseconds */
 	unsigned int wf_current;	/* current time in waveform period */
-	unsigned long state_bits;
 	unsigned int ai_scan_period;	/* AI scan period in usec */
 	unsigned int ai_convert_period;	/* AI conversion period in usec */
 	struct timer_list ao_timer;	/* timer for AO commands */
@@ -191,10 +185,6 @@
 	unsigned int nsamples;
 	unsigned int time_increment;
 
-	/* check command is still active */
-	if (!test_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits))
-		return;
-
 	now = ktime_to_us(ktime_get());
 	nsamples = comedi_nsamples_left(s, UINT_MAX);
 
@@ -386,11 +376,6 @@
 	 */
 	devpriv->ai_timer.expires =
 		jiffies + usecs_to_jiffies(devpriv->ai_convert_period) + 1;
-
-	/* mark command as active */
-	smp_mb__before_atomic();
-	set_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits);
-	smp_mb__after_atomic();
 	add_timer(&devpriv->ai_timer);
 	return 0;
 }
@@ -400,11 +385,12 @@
 {
 	struct waveform_private *devpriv = dev->private;
 
-	/* mark command as no longer active */
-	clear_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits);
-	smp_mb__after_atomic();
-	/* cannot call del_timer_sync() as may be called from timer routine */
-	del_timer(&devpriv->ai_timer);
+	if (in_softirq()) {
+		/* Assume we were called from the timer routine itself. */
+		del_timer(&devpriv->ai_timer);
+	} else {
+		del_timer_sync(&devpriv->ai_timer);
+	}
 	return 0;
 }
 
@@ -436,10 +422,6 @@
 	u64 scans_since;
 	unsigned int scans_avail = 0;
 
-	/* check command is still active */
-	if (!test_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits))
-		return;
-
 	/* determine number of scan periods since last time */
 	now = ktime_to_us(ktime_get());
 	scans_since = now - devpriv->ao_last_scan_time;
@@ -518,11 +500,6 @@
 	devpriv->ao_last_scan_time = ktime_to_us(ktime_get());
 	devpriv->ao_timer.expires =
 		jiffies + usecs_to_jiffies(devpriv->ao_scan_period);
-
-	/* mark command as active */
-	smp_mb__before_atomic();
-	set_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits);
-	smp_mb__after_atomic();
 	add_timer(&devpriv->ao_timer);
 
 	return 1;
@@ -608,11 +585,12 @@
 	struct waveform_private *devpriv = dev->private;
 
 	s->async->inttrig = NULL;
-	/* mark command as no longer active */
-	clear_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits);
-	smp_mb__after_atomic();
-	/* cannot call del_timer_sync() as may be called from timer routine */
-	del_timer(&devpriv->ao_timer);
+	if (in_softirq()) {
+		/* Assume we were called from the timer routine itself. */
+		del_timer(&devpriv->ao_timer);
+	} else {
+		del_timer_sync(&devpriv->ao_timer);
+	}
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/daqboard2000.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/daqboard2000.c
@@ -636,7 +636,7 @@
 	const struct daq200_boardtype *board;
 	int i;
 
-	if (pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
+	if (pcidev->subsystem_vendor != PCI_VENDOR_ID_IOTECH)
 		return NULL;
 
 	for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/das1800.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/das1800.c
@@ -567,14 +567,17 @@
 	struct comedi_isadma_desc *desc;
 	int i;
 
-	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 */
-
-	for (i = 0; i < 2; i++) {
-		desc = &dma->desc[i];
-		if (desc->chan)
-			comedi_isadma_disable(desc->chan);
+	/* disable and stop conversions */
+	outb(0x0, dev->iobase + DAS1800_STATUS);
+	outb(0x0, dev->iobase + DAS1800_CONTROL_B);
+	outb(0x0, dev->iobase + DAS1800_CONTROL_A);
+
+	if (dma) {
+		for (i = 0; i < 2; i++) {
+			desc = &dma->desc[i];
+			if (desc->chan)
+				comedi_isadma_disable(desc->chan);
+		}
 	}
 
 	return 0;
@@ -934,13 +937,14 @@
 {
 	struct das1800_private *devpriv = dev->private;
 	struct comedi_isadma *dma = devpriv->dma;
-	struct comedi_isadma_desc *desc = &dma->desc[0];
+	struct comedi_isadma_desc *desc;
 	unsigned int bytes;
 
 	if ((devpriv->irq_dma_bits & DMA_ENABLED) == 0)
 		return;
 
 	dma->cur_dma = 0;
+	desc = &dma->desc[0];
 
 	/* determine a dma transfer size to fill buffer in 0.3 sec */
 	bytes = das1800_ai_transfer_size(dev, s, desc->maxsize, 300000000);
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/das6402.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/das6402.c
@@ -193,7 +193,7 @@
 	if (status & DAS6402_STATUS_FFULL) {
 		async->events |= COMEDI_CB_OVERFLOW;
 	} else if (status & DAS6402_STATUS_FFNE) {
-		unsigned int val;
+		unsigned short val;
 
 		val = das6402_ai_read_sample(dev, s);
 		comedi_buf_write_samples(s, &val, 1);
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/das800.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/das800.c
@@ -436,7 +436,7 @@
 	struct comedi_cmd *cmd;
 	unsigned long irq_flags;
 	unsigned int status;
-	unsigned int val;
+	unsigned short val;
 	bool fifo_empty;
 	bool fifo_overflow;
 	int i;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/dmm32at.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/dmm32at.c
@@ -411,7 +411,7 @@
 {
 	struct comedi_device *dev = d;
 	unsigned char intstat;
-	unsigned int val;
+	unsigned short val;
 	int i;
 
 	if (!dev->attached) {
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/dt2815.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/dt2815.c
@@ -101,6 +101,7 @@
 	int ret;
 
 	for (i = 0; i < insn->n; i++) {
+		/* FIXME: lo bit 0 chooses voltage output or current output */
 		lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01;
 		hi = (data[i] & 0xff0) >> 4;
 
@@ -114,6 +115,8 @@
 		if (ret)
 			return ret;
 
+		outb(hi, dev->iobase + DT2815_DATA);
+
 		devpriv->ao_readback[chan] = data[i];
 	}
 	return i;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/dt282x.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/dt282x.c
@@ -69,48 +69,49 @@
  * Register map
  */
 #define DT2821_ADCSR_REG		0x00
-#define DT2821_ADCSR_ADERR		(1 << 15)
-#define DT2821_ADCSR_ADCLK		(1 << 9)
-#define DT2821_ADCSR_MUXBUSY		(1 << 8)
-#define DT2821_ADCSR_ADDONE		(1 << 7)
-#define DT2821_ADCSR_IADDONE		(1 << 6)
+#define DT2821_ADCSR_ADERR		BIT(15)
+#define DT2821_ADCSR_ADCLK		BIT(9)
+#define DT2821_ADCSR_MUXBUSY		BIT(8)
+#define DT2821_ADCSR_ADDONE		BIT(7)
+#define DT2821_ADCSR_IADDONE		BIT(6)
 #define DT2821_ADCSR_GS(x)		(((x) & 0x3) << 4)
 #define DT2821_ADCSR_CHAN(x)		(((x) & 0xf) << 0)
 #define DT2821_CHANCSR_REG		0x02
-#define DT2821_CHANCSR_LLE		(1 << 15)
-#define DT2821_CHANCSR_PRESLA(x)	(((x) & 0xf) >> 8)
+#define DT2821_CHANCSR_LLE		BIT(15)
+#define DT2821_CHANCSR_TO_PRESLA(x)	(((x) >> 8) & 0xf)
 #define DT2821_CHANCSR_NUMB(x)		((((x) - 1) & 0xf) << 0)
 #define DT2821_ADDAT_REG		0x04
 #define DT2821_DACSR_REG		0x06
-#define DT2821_DACSR_DAERR		(1 << 15)
+#define DT2821_DACSR_DAERR		BIT(15)
 #define DT2821_DACSR_YSEL(x)		((x) << 9)
-#define DT2821_DACSR_SSEL		(1 << 8)
-#define DT2821_DACSR_DACRDY		(1 << 7)
-#define DT2821_DACSR_IDARDY		(1 << 6)
-#define DT2821_DACSR_DACLK		(1 << 5)
-#define DT2821_DACSR_HBOE		(1 << 1)
-#define DT2821_DACSR_LBOE		(1 << 0)
+#define DT2821_DACSR_SSEL		BIT(8)
+#define DT2821_DACSR_DACRDY		BIT(7)
+#define DT2821_DACSR_IDARDY		BIT(6)
+#define DT2821_DACSR_DACLK		BIT(5)
+#define DT2821_DACSR_HBOE		BIT(1)
+#define DT2821_DACSR_LBOE		BIT(0)
 #define DT2821_DADAT_REG		0x08
 #define DT2821_DIODAT_REG		0x0a
 #define DT2821_SUPCSR_REG		0x0c
-#define DT2821_SUPCSR_DMAD		(1 << 15)
-#define DT2821_SUPCSR_ERRINTEN		(1 << 14)
-#define DT2821_SUPCSR_CLRDMADNE		(1 << 13)
-#define DT2821_SUPCSR_DDMA		(1 << 12)
-#define DT2821_SUPCSR_DS_PIO		(0 << 10)
-#define DT2821_SUPCSR_DS_AD_CLK		(1 << 10)
-#define DT2821_SUPCSR_DS_DA_CLK		(2 << 10)
-#define DT2821_SUPCSR_DS_AD_TRIG	(3 << 10)
-#define DT2821_SUPCSR_BUFFB		(1 << 9)
-#define DT2821_SUPCSR_SCDN		(1 << 8)
-#define DT2821_SUPCSR_DACON		(1 << 7)
-#define DT2821_SUPCSR_ADCINIT		(1 << 6)
-#define DT2821_SUPCSR_DACINIT		(1 << 5)
-#define DT2821_SUPCSR_PRLD		(1 << 4)
-#define DT2821_SUPCSR_STRIG		(1 << 3)
-#define DT2821_SUPCSR_XTRIG		(1 << 2)
-#define DT2821_SUPCSR_XCLK		(1 << 1)
-#define DT2821_SUPCSR_BDINIT		(1 << 0)
+#define DT2821_SUPCSR_DMAD		BIT(15)
+#define DT2821_SUPCSR_ERRINTEN		BIT(14)
+#define DT2821_SUPCSR_CLRDMADNE		BIT(13)
+#define DT2821_SUPCSR_DDMA		BIT(12)
+#define DT2821_SUPCSR_DS(x)		(((x) & 0x3) << 10)
+#define DT2821_SUPCSR_DS_PIO		DT2821_SUPCSR_DS(0)
+#define DT2821_SUPCSR_DS_AD_CLK		DT2821_SUPCSR_DS(1)
+#define DT2821_SUPCSR_DS_DA_CLK		DT2821_SUPCSR_DS(2)
+#define DT2821_SUPCSR_DS_AD_TRIG	DT2821_SUPCSR_DS(3)
+#define DT2821_SUPCSR_BUFFB		BIT(9)
+#define DT2821_SUPCSR_SCDN		BIT(8)
+#define DT2821_SUPCSR_DACON		BIT(7)
+#define DT2821_SUPCSR_ADCINIT		BIT(6)
+#define DT2821_SUPCSR_DACINIT		BIT(5)
+#define DT2821_SUPCSR_PRLD		BIT(4)
+#define DT2821_SUPCSR_STRIG		BIT(3)
+#define DT2821_SUPCSR_XTRIG		BIT(2)
+#define DT2821_SUPCSR_XCLK		BIT(1)
+#define DT2821_SUPCSR_BDINIT		BIT(0)
 #define DT2821_TMRCTR_REG		0x0e
 
 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
@@ -552,7 +553,8 @@
 	}
 #endif
 	comedi_handle_events(dev, s);
-	comedi_handle_events(dev, s_ao);
+	if (s_ao)
+		comedi_handle_events(dev, s_ao);
 
 	return IRQ_RETVAL(handled);
 }
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/dt3000.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/dt3000.c
@@ -351,9 +351,9 @@
 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
 			    unsigned int flags)
 {
-	int divider, base, prescale;
+	unsigned int divider, base, prescale;
 
-	/* This function needs improvment */
+	/* This function needs improvement */
 	/* Don't know if divider==0 works. */
 
 	for (prescale = 0; prescale < 16; prescale++) {
@@ -367,7 +367,7 @@
 			divider = (*nanosec) / base;
 			break;
 		case CMDF_ROUND_UP:
-			divider = (*nanosec) / base;
+			divider = DIV_ROUND_UP(*nanosec, base);
 			break;
 		}
 		if (divider < 65536) {
@@ -377,7 +377,7 @@
 	}
 
 	prescale = 15;
-	base = timer_base * (1 << prescale);
+	base = timer_base * (prescale + 1);
 	divider = 65535;
 	*nanosec = divider * base;
 	return (prescale << 16) | (divider);
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -632,12 +632,22 @@
 		devpriv->dio_buffer[i] =
 		    pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
 					 &devpriv->dio_buffer_phys_addr[i]);
+		if (!devpriv->dio_buffer[i]) {
+			dev_warn(dev->class_dev,
+				 "failed to allocate DMA buffer\n");
+			return -ENOMEM;
+		}
 	}
 	/* allocate dma descriptors */
 	devpriv->dma_desc = pci_alloc_consistent(pcidev,
 						 sizeof(struct plx_dma_desc) *
 						 NUM_DMA_DESCRIPTORS,
 						 &devpriv->dma_desc_phys_addr);
+	if (!devpriv->dma_desc) {
+		dev_warn(dev->class_dev,
+			 "failed to allocate DMA descriptors\n");
+		return -ENOMEM;
+	}
 	if (devpriv->dma_desc_phys_addr & 0xf) {
 		dev_warn(dev->class_dev,
 			 " dma descriptors not quad-word aligned (bug)\n");
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/jr3_pci.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/jr3_pci.c
@@ -610,7 +610,7 @@
 		s = &dev->subdevices[i];
 		spriv = s->private;
 
-		if (now > spriv->next_time_min) {
+		if (time_after_eq(now, spriv->next_time_min)) {
 			struct jr3_pci_poll_delay sub_delay;
 
 			sub_delay = jr3_pci_poll_subdevice(s);
@@ -726,11 +726,12 @@
 		s->insn_read	= jr3_pci_ai_insn_read;
 
 		spriv = jr3_pci_alloc_spriv(dev, s);
-		if (spriv) {
-			/* Channel specific range and maxdata */
-			s->range_table_list	= spriv->range_table_list;
-			s->maxdata_list		= spriv->maxdata_list;
-		}
+		if (!spriv)
+			return -ENOMEM;
+
+		/* Channel specific range and maxdata */
+		s->range_table_list	= spriv->range_table_list;
+		s->maxdata_list		= spriv->maxdata_list;
 	}
 
 	/*  Reset DSP card */
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/me4000.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/me4000.c
@@ -933,7 +933,7 @@
 	struct comedi_subdevice *s = dev->read_subdev;
 	int i;
 	int c = 0;
-	unsigned int lval;
+	unsigned short lval;
 
 	if (!dev->attached)
 		return IRQ_NONE;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/mf6x4.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/mf6x4.c
@@ -121,8 +121,9 @@
 	struct mf6x4_private *devpriv = dev->private;
 	unsigned int status;
 
+	/* EOLC goes low at end of conversion. */
 	status = ioread32(devpriv->gpioc_reg);
-	if (status & MF6X4_GPIOC_EOLC)
+	if ((status & MF6X4_GPIOC_EOLC) == 0)
 		return 0;
 	return -EBUSY;
 }
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/ni_6527.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/ni_6527.c
@@ -341,7 +341,7 @@
 		case COMEDI_DIGITAL_TRIG_ENABLE_EDGES:
 			/* check shift amount */
 			shift = data[3];
-			if (shift >= s->n_chan) {
+			if (shift >= 32) {
 				mask = 0;
 				rising = 0;
 				falling = 0;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/ni_mio_common.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -246,24 +246,24 @@
 {
 	if (dev->mmio)
 		writel(data, dev->mmio + reg);
-
-	outl(data, dev->iobase + reg);
+	else
+		outl(data, dev->iobase + reg);
 }
 
 static void ni_writew(struct comedi_device *dev, uint16_t data, int reg)
 {
 	if (dev->mmio)
 		writew(data, dev->mmio + reg);
-
-	outw(data, dev->iobase + reg);
+	else
+		outw(data, dev->iobase + reg);
 }
 
 static void ni_writeb(struct comedi_device *dev, uint8_t data, int reg)
 {
 	if (dev->mmio)
 		writeb(data, dev->mmio + reg);
-
-	outb(data, dev->iobase + reg);
+	else
+		outb(data, dev->iobase + reg);
 }
 
 static uint32_t ni_readl(struct comedi_device *dev, int reg)
@@ -1348,6 +1348,8 @@
 		ack |= NISTC_INTA_ACK_AI_START;
 	if (a_status & NISTC_AI_STATUS1_STOP)
 		ack |= NISTC_INTA_ACK_AI_STOP;
+	if (a_status & NISTC_AI_STATUS1_OVER)
+		ack |= NISTC_INTA_ACK_AI_ERR;
 	if (ack)
 		ni_stc_writew(dev, ack, NISTC_INTA_ACK_REG);
 }
@@ -1929,7 +1931,7 @@
 			   unsigned int *data)
 {
 	struct ni_private *devpriv = dev->private;
-	unsigned int mask = (s->maxdata + 1) >> 1;
+	unsigned int mask = s->maxdata;
 	int i, n;
 	unsigned signbits;
 	unsigned int d;
@@ -1972,7 +1974,7 @@
 				return -ETIME;
 			}
 			d += signbits;
-			data[n] = d;
+			data[n] = d & 0xffff;
 		}
 	} else if (devpriv->is_6143) {
 		for (n = 0; n < insn->n; n++) {
@@ -2017,8 +2019,8 @@
 				data[n] = dl;
 			} else {
 				d = ni_readw(dev, NI_E_AI_FIFO_DATA_REG);
-				d += signbits;	/* subtle: needs to be short addition */
-				data[n] = d;
+				d += signbits;
+				data[n] = d & 0xffff;
 			}
 		}
 	}
@@ -2823,7 +2825,15 @@
 	int i;
 	static const int timeout = 1000;
 
-	if (trig_num != cmd->start_arg)
+	/*
+	 * Require trig_num == cmd->start_arg when cmd->start_src == TRIG_INT.
+	 * For backwards compatibility, also allow trig_num == 0 when
+	 * cmd->start_src != TRIG_INT (i.e. when cmd->start_src == TRIG_EXT);
+	 * in that case, the internal trigger is being used as a pre-trigger
+	 * before the external trigger.
+	 */
+	if (!(trig_num == cmd->start_arg ||
+	      (trig_num == 0 && cmd->start_src != TRIG_INT)))
 		return -EINVAL;
 
 	/* Null trig at beginning prevent ao start trigger from executing more than
@@ -4799,7 +4809,10 @@
 	case NI_RTSI_OUTPUT_G_SRC0:
 	case NI_RTSI_OUTPUT_G_GATE0:
 	case NI_RTSI_OUTPUT_RGOUT0:
-	case NI_RTSI_OUTPUT_RTSI_BRD_0:
+	case NI_RTSI_OUTPUT_RTSI_BRD(0):
+	case NI_RTSI_OUTPUT_RTSI_BRD(1):
+	case NI_RTSI_OUTPUT_RTSI_BRD(2):
+	case NI_RTSI_OUTPUT_RTSI_BRD(3):
 		return 1;
 	case NI_RTSI_OUTPUT_RTSI_OSC:
 		return (devpriv->is_m_series) ? 1 : 0;
@@ -4820,11 +4833,18 @@
 		devpriv->rtsi_trig_a_output_reg |= NISTC_RTSI_TRIG(chan, src);
 		ni_stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
 			      NISTC_RTSI_TRIGA_OUT_REG);
-	} else if (chan < 8) {
+	} else if (chan < NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) {
 		devpriv->rtsi_trig_b_output_reg &= ~NISTC_RTSI_TRIG_MASK(chan);
 		devpriv->rtsi_trig_b_output_reg |= NISTC_RTSI_TRIG(chan, src);
 		ni_stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
 			      NISTC_RTSI_TRIGB_OUT_REG);
+	} else if (chan != NISTC_RTSI_TRIG_OLD_CLK_CHAN) {
+		/* probably should never reach this, since the
+		 * ni_valid_rtsi_output_source above errors out if chan is too
+		 * high
+		 */
+		dev_err(dev->class_dev, "%s: unknown rtsi channel\n", __func__);
+		return -EINVAL;
 	}
 	return 2;
 }
@@ -4839,12 +4859,12 @@
 	} else if (chan < NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) {
 		return NISTC_RTSI_TRIG_TO_SRC(chan,
 					      devpriv->rtsi_trig_b_output_reg);
-	} else {
-		if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN)
-			return NI_RTSI_OUTPUT_RTSI_OSC;
-		dev_err(dev->class_dev, "bug! should never get here?\n");
-		return 0;
+	} else if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) {
+		return NI_RTSI_OUTPUT_RTSI_OSC;
 	}
+
+	dev_err(dev->class_dev, "%s: unknown rtsi channel\n", __func__);
+	return -EINVAL;
 }
 
 static int ni_rtsi_insn_config(struct comedi_device *dev,
@@ -5265,11 +5285,11 @@
 	/* Digital I/O (PFI) subdevice */
 	s = &dev->subdevices[NI_PFI_DIO_SUBDEV];
 	s->type		= COMEDI_SUBD_DIO;
-	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 	s->maxdata	= 1;
 	if (devpriv->is_m_series) {
 		s->n_chan	= 16;
 		s->insn_bits	= ni_pfi_insn_bits;
+		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 
 		ni_writew(dev, s->state, NI_M_PFI_DO_REG);
 		for (i = 0; i < NUM_PFI_OUTPUT_SELECT_REGS; ++i) {
@@ -5278,6 +5298,7 @@
 		}
 	} else {
 		s->n_chan	= 10;
+		s->subdev_flags	= SDF_INTERNAL;
 	}
 	s->insn_config	= ni_pfi_insn_config;
 
@@ -5346,7 +5367,7 @@
 		s->maxdata	= (devpriv->is_m_series) ? 0xffffffff
 							 : 0x00ffffff;
 		s->insn_read	= ni_tio_insn_read;
-		s->insn_write	= ni_tio_insn_read;
+		s->insn_write	= ni_tio_insn_write;
 		s->insn_config	= ni_tio_insn_config;
 #ifdef PCIDMA
 		if (dev->irq && devpriv->mite) {
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -92,7 +92,7 @@
 	unsigned long flags;
 	int ret = 0;
 
-	if (trig_num != cmd->start_src)
+	if (trig_num != cmd->start_arg)
 		return -EINVAL;
 
 	spin_lock_irqsave(&counter->lock, flags);
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/ni_usb6501.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/ni_usb6501.c
@@ -472,10 +472,8 @@
 
 	size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
 	devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
-	if (!devpriv->usb_tx_buf) {
-		kfree(devpriv->usb_rx_buf);
+	if (!devpriv->usb_tx_buf)
 		return -ENOMEM;
-	}
 
 	return 0;
 }
@@ -527,6 +525,9 @@
 	if (!devpriv)
 		return -ENOMEM;
 
+	mutex_init(&devpriv->mut);
+	usb_set_intfdata(intf, devpriv);
+
 	ret = ni6501_find_endpoints(dev);
 	if (ret)
 		return ret;
@@ -535,9 +536,6 @@
 	if (ret)
 		return ret;
 
-	mutex_init(&devpriv->mut);
-	usb_set_intfdata(intf, devpriv);
-
 	ret = comedi_alloc_subdevices(dev, 2);
 	if (ret)
 		return ret;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/pcl711.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/pcl711.c
@@ -193,7 +193,7 @@
 	struct comedi_device *dev = d;
 	struct comedi_subdevice *s = dev->read_subdev;
 	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned int data;
+	unsigned short data;
 
 	if (!dev->attached) {
 		dev_err(dev->class_dev, "spurious interrupt\n");
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/pcl818.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/pcl818.c
@@ -422,7 +422,7 @@
 
 static bool pcl818_ai_write_sample(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
-				   unsigned int chan, unsigned int val)
+				   unsigned int chan, unsigned short val)
 {
 	struct pcl818_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -642,7 +642,7 @@
 	/* Make sure D/A update mode is direct update */
 	outb(0, dev->iobase + DAQP_AUX_REG);
 
-	for (i = 0; i > insn->n; i++) {
+	for (i = 0; i < insn->n; i++) {
 		unsigned val = data[i];
 		int ret;
 
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/usbduxfast.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/usbduxfast.c
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2004-2014 Bernd Porr, mail@berndporr.me.uk
+ *  Copyright (C) 2004-2019 Bernd Porr, mail@berndporr.me.uk
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
  * Description: University of Stirling USB DAQ & INCITE Technology Limited
  * Devices: [ITL] USB-DUX-FAST (usbduxfast)
  * Author: Bernd Porr <mail@berndporr.me.uk>
- * Updated: 10 Oct 2014
+ * Updated: 16 Nov 2019
  * Status: stable
  */
 
@@ -31,6 +31,7 @@
  *
  *
  * Revision history:
+ * 1.0: Fixed a rounding error in usbduxfast_ai_cmdtest
  * 0.9: Dropping the first data packet which seems to be from the last transfer.
  *      Buffer overflows in the FX2 are handed over to comedi.
  * 0.92: Dropping now 4 packets. The quad buffer has to be emptied.
@@ -359,6 +360,7 @@
 				 struct comedi_cmd *cmd)
 {
 	int err = 0;
+	int err2 = 0;
 	unsigned int steps;
 	unsigned int arg;
 
@@ -408,11 +410,16 @@
 	 */
 	steps = (cmd->convert_arg * 30) / 1000;
 	if (cmd->chanlist_len !=  1)
-		err |= comedi_check_trigger_arg_min(&steps,
-						    MIN_SAMPLING_PERIOD);
-	err |= comedi_check_trigger_arg_max(&steps, MAX_SAMPLING_PERIOD);
-	arg = (steps * 1000) / 30;
-	err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
+		err2 |= comedi_check_trigger_arg_min(&steps,
+						     MIN_SAMPLING_PERIOD);
+	else
+		err2 |= comedi_check_trigger_arg_min(&steps, 1);
+	err2 |= comedi_check_trigger_arg_max(&steps, MAX_SAMPLING_PERIOD);
+	if (err2) {
+		err |= err2;
+		arg = (steps * 1000) / 30;
+		err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
+	}
 
 	if (cmd->stop_src == TRIG_COUNT)
 		err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
--- linux-4.4.0.orig/drivers/staging/comedi/drivers/vmk80xx.c
+++ linux-4.4.0/drivers/staging/comedi/drivers/vmk80xx.c
@@ -676,6 +676,9 @@
 	if (!devpriv->ep_rx || !devpriv->ep_tx)
 		return -ENODEV;
 
+	if (!usb_endpoint_maxp(devpriv->ep_rx) || !usb_endpoint_maxp(devpriv->ep_tx))
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -691,10 +694,8 @@
 
 	size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
 	devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
-	if (!devpriv->usb_tx_buf) {
-		kfree(devpriv->usb_rx_buf);
+	if (!devpriv->usb_tx_buf)
 		return -ENOMEM;
-	}
 
 	return 0;
 }
@@ -809,6 +810,8 @@
 
 	devpriv->model = board->model;
 
+	sema_init(&devpriv->limit_sem, 8);
+
 	ret = vmk80xx_find_usb_endpoints(dev);
 	if (ret)
 		return ret;
@@ -817,8 +820,6 @@
 	if (ret)
 		return ret;
 
-	sema_init(&devpriv->limit_sem, 8);
-
 	usb_set_intfdata(intf, devpriv);
 
 	if (devpriv->model == VMK8055_MODEL)
--- linux-4.4.0.orig/drivers/staging/emxx_udc/emxx_udc.c
+++ linux-4.4.0/drivers/staging/emxx_udc/emxx_udc.c
@@ -3181,7 +3181,7 @@
 };
 
 /*-------------------------------------------------------------------------*/
-static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
+static void nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
 {
 	int	i;
 
@@ -3211,7 +3211,7 @@
 
 /*-------------------------------------------------------------------------*/
 /* platform_driver */
-static int __init nbu2ss_drv_contest_init(
+static int nbu2ss_drv_contest_init(
 	struct platform_device *pdev,
 	struct nbu2ss_udc *udc)
 {
--- linux-4.4.0.orig/drivers/staging/fbtft/fbtft-core.c
+++ linux-4.4.0/drivers/staging/fbtft/fbtft-core.c
@@ -392,11 +392,11 @@
 
 	if (unlikely(timeit)) {
 		ts_end = ktime_get();
-		if (ktime_to_ns(par->update_time))
+		if (!ktime_to_ns(par->update_time))
 			par->update_time = ts_start;
 
-		par->update_time = ts_start;
 		fps = ktime_us_delta(ts_start, par->update_time);
+		par->update_time = ts_start;
 		fps = fps ? 1000000 / fps : 0;
 
 		throughput = ktime_us_delta(ts_end, ts_start);
@@ -765,7 +765,7 @@
 	fbdefio->deferred_io =     fbtft_deferred_io;
 	fb_deferred_io_init(info);
 
-	strncpy(info->fix.id, dev->driver->name, 16);
+	snprintf(info->fix.id, sizeof(info->fix.id), "%s", dev->driver->name);
 	info->fix.type =           FB_TYPE_PACKED_PIXELS;
 	info->fix.visual =         FB_VISUAL_TRUECOLOR;
 	info->fix.xpanstep =	   0;
@@ -813,7 +813,7 @@
 	if (par->gamma.curves && gamma) {
 		if (fbtft_gamma_parse_str(par,
 			par->gamma.curves, gamma, strlen(gamma)))
-			goto alloc_fail;
+			goto release_framebuf;
 	}
 
 	/* Transmit buffer */
@@ -836,7 +836,7 @@
 			txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL);
 		}
 		if (!txbuf)
-			goto alloc_fail;
+			goto release_framebuf;
 		par->txbuf.buf = txbuf;
 		par->txbuf.len = txbuflen;
 	}
@@ -872,6 +872,9 @@
 
 	return info;
 
+release_framebuf:
+	framebuffer_release(info);
+
 alloc_fail:
 	vfree(vmem);
 
--- linux-4.4.0.orig/drivers/staging/fwserial/fwserial.c
+++ linux-4.4.0/drivers/staging/fwserial/fwserial.c
@@ -2255,6 +2255,7 @@
 		err = fw_core_add_address_handler(&port->rx_handler,
 						  &fw_high_memory_region);
 		if (err) {
+			tty_port_destroy(&port->port);
 			kfree(port);
 			goto free_ports;
 		}
@@ -2337,6 +2338,7 @@
 
 free_ports:
 	for (--i; i >= 0; --i) {
+		fw_core_remove_address_handler(&serial->ports[i]->rx_handler);
 		tty_port_destroy(&serial->ports[i]->port);
 		kfree(serial->ports[i]);
 	}
--- linux-4.4.0.orig/drivers/staging/gdm724x/gdm_lte.c
+++ linux-4.4.0/drivers/staging/gdm724x/gdm_lte.c
@@ -85,14 +85,15 @@
 
 static int gdm_lte_rx(struct sk_buff *skb, struct nic *nic, int nic_type)
 {
-	int ret;
+	int ret, len;
 
+	len = skb->len + ETH_HLEN;
 	ret = netif_rx_ni(skb);
 	if (ret == NET_RX_DROP) {
 		nic->stats.rx_dropped++;
 	} else {
 		nic->stats.rx_packets++;
-		nic->stats.rx_bytes += skb->len + ETH_HLEN;
+		nic->stats.rx_bytes += len;
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/staging/gdm724x/gdm_mux.c
+++ linux-4.4.0/drivers/staging/gdm724x/gdm_mux.c
@@ -670,14 +670,14 @@
 
 static void __exit gdm_usb_mux_exit(void)
 {
-	unregister_lte_tty_driver();
-
 	if (mux_rx_wq) {
 		flush_workqueue(mux_rx_wq);
 		destroy_workqueue(mux_rx_wq);
 	}
 
 	usb_deregister(&gdm_mux_driver);
+	unregister_lte_tty_driver();
+
 }
 
 module_init(gdm_usb_mux_init);
--- linux-4.4.0.orig/drivers/staging/goldfish/goldfish_audio.c
+++ linux-4.4.0/drivers/staging/goldfish/goldfish_audio.c
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/dma-mapping.h>
 #include <linux/uaccess.h>
+#include <linux/slab.h>
 #include <linux/goldfish.h>
 
 MODULE_AUTHOR("Google, Inc.");
--- linux-4.4.0.orig/drivers/staging/iio/accel/sca3000_core.c
+++ linux-4.4.0/drivers/staging/iio/accel/sca3000_core.c
@@ -595,7 +595,7 @@
 		goto error_ret_mut;
 	ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL);
 	mutex_unlock(&st->lock);
-	if (ret)
+	if (ret < 0)
 		goto error_ret;
 	val = ret;
 	if (base_freq > 0)
--- linux-4.4.0.orig/drivers/staging/iio/accel/sca3000_ring.c
+++ linux-4.4.0/drivers/staging/iio/accel/sca3000_ring.c
@@ -56,7 +56,7 @@
 	st->tx[0] = SCA3000_READ_REG(reg_address_high);
 	ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer));
 	if (ret) {
-		dev_err(get_device(&st->us->dev), "problem reading register");
+		dev_err(&st->us->dev, "problem reading register");
 		goto error_free_rx;
 	}
 
--- linux-4.4.0.orig/drivers/staging/iio/adc/ad7192.c
+++ linux-4.4.0/drivers/staging/iio/adc/ad7192.c
@@ -124,6 +124,8 @@
 #define AD7192_GPOCON_P1DAT	BIT(1) /* P1 state */
 #define AD7192_GPOCON_P0DAT	BIT(0) /* P0 state */
 
+#define AD7192_EXT_FREQ_MHZ_MIN	2457600
+#define AD7192_EXT_FREQ_MHZ_MAX	5120000
 #define AD7192_INT_FREQ_MHZ	4915200
 
 /* NOTE:
@@ -199,17 +201,21 @@
 				ARRAY_SIZE(ad7192_calib_arr));
 }
 
+static inline bool ad7192_valid_external_frequency(u32 freq)
+{
+	return (freq >= AD7192_EXT_FREQ_MHZ_MIN &&
+		freq <= AD7192_EXT_FREQ_MHZ_MAX);
+}
+
 static int ad7192_setup(struct ad7192_state *st,
 			const struct ad7192_platform_data *pdata)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi);
 	unsigned long long scale_uv;
 	int i, ret, id;
-	u8 ones[6];
 
 	/* reset the serial interface */
-	memset(&ones, 0xFF, 6);
-	ret = spi_write(st->sd.spi, &ones, 6);
+	ret = ad_sd_reset(&st->sd, 48);
 	if (ret < 0)
 		goto out;
 	usleep_range(500, 1000); /* Wait for at least 500us */
@@ -226,17 +232,20 @@
 			 id);
 
 	switch (pdata->clock_source_sel) {
-	case AD7192_CLK_EXT_MCLK1_2:
-	case AD7192_CLK_EXT_MCLK2:
-		st->mclk = AD7192_INT_FREQ_MHZ;
-		break;
 	case AD7192_CLK_INT:
 	case AD7192_CLK_INT_CO:
-		if (pdata->ext_clk_hz)
+		st->mclk = AD7192_INT_FREQ_MHZ;
+		break;
+	case AD7192_CLK_EXT_MCLK1_2:
+	case AD7192_CLK_EXT_MCLK2:
+		if (ad7192_valid_external_frequency(pdata->ext_clk_hz)) {
 			st->mclk = pdata->ext_clk_hz;
-		else
-			st->mclk = AD7192_INT_FREQ_MHZ;
 			break;
+		}
+		dev_err(&st->sd.spi->dev, "Invalid frequency setting %u\n",
+			pdata->ext_clk_hz);
+		ret = -EINVAL;
+		goto out;
 	default:
 		ret = -EINVAL;
 		goto out;
--- linux-4.4.0.orig/drivers/staging/iio/adc/ad7280a.c
+++ linux-4.4.0/drivers/staging/iio/adc/ad7280a.c
@@ -250,7 +250,9 @@
 	if (ret)
 		return ret;
 
-	__ad7280_read32(st, &tmp);
+	ret = __ad7280_read32(st, &tmp);
+	if (ret)
+		return ret;
 
 	if (ad7280_check_crc(st, tmp))
 		return -EIO;
@@ -288,7 +290,9 @@
 
 	ad7280_delay(st);
 
-	__ad7280_read32(st, &tmp);
+	ret = __ad7280_read32(st, &tmp);
+	if (ret)
+		return ret;
 
 	if (ad7280_check_crc(st, tmp))
 		return -EIO;
@@ -321,7 +325,9 @@
 	ad7280_delay(st);
 
 	for (i = 0; i < cnt; i++) {
-		__ad7280_read32(st, &tmp);
+		ret = __ad7280_read32(st, &tmp);
+		if (ret)
+			return ret;
 
 		if (ad7280_check_crc(st, tmp))
 			return -EIO;
@@ -364,7 +370,10 @@
 		return ret;
 
 	for (n = 0; n <= AD7280A_MAX_CHAIN; n++) {
-		__ad7280_read32(st, &val);
+		ret = __ad7280_read32(st, &val);
+		if (ret)
+			return ret;
+
 		if (val == 0)
 			return n - 1;
 
--- linux-4.4.0.orig/drivers/staging/iio/adc/ad7606_core.c
+++ linux-4.4.0/drivers/staging/iio/adc/ad7606_core.c
@@ -189,7 +189,7 @@
 	mutex_lock(&indio_dev->mlock);
 	gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1);
 	gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1);
-	gpio_set_value(st->pdata->gpio_os1, (ret >> 2) & 1);
+	gpio_set_value(st->pdata->gpio_os2, (ret >> 2) & 1);
 	st->oversampling = lval;
 	mutex_unlock(&indio_dev->mlock);
 
--- linux-4.4.0.orig/drivers/staging/iio/adc/ad7780.c
+++ linux-4.4.0/drivers/staging/iio/adc/ad7780.c
@@ -90,12 +90,16 @@
 			   long m)
 {
 	struct ad7780_state *st = iio_priv(indio_dev);
+	int voltage_uv;
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
 		return ad_sigma_delta_single_conversion(indio_dev, chan, val);
 	case IIO_CHAN_INFO_SCALE:
-		*val = st->int_vref_mv * st->gain;
+		voltage_uv = regulator_get_voltage(st->reg);
+		if (voltage_uv < 0)
+			return voltage_uv;
+		*val = (voltage_uv / 1000) * st->gain;
 		*val2 = chan->scan_type.realbits - 1;
 		return IIO_VAL_FRACTIONAL_LOG2;
 	case IIO_CHAN_INFO_OFFSET:
--- linux-4.4.0.orig/drivers/staging/iio/addac/adt7316-i2c.c
+++ linux-4.4.0/drivers/staging/iio/addac/adt7316-i2c.c
@@ -35,6 +35,8 @@
 		return ret;
 	}
 
+	*data = ret;
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/staging/iio/addac/adt7316.c
+++ linux-4.4.0/drivers/staging/iio/addac/adt7316.c
@@ -47,6 +47,8 @@
 #define ADT7516_MSB_AIN3		0xA
 #define ADT7516_MSB_AIN4		0xB
 #define ADT7316_DA_DATA_BASE		0x10
+#define ADT7316_DA_10_BIT_LSB_SHIFT	6
+#define ADT7316_DA_12_BIT_LSB_SHIFT	4
 #define ADT7316_DA_MSB_DATA_REGS	4
 #define ADT7316_LSB_DAC_A		0x10
 #define ADT7316_MSB_DAC_A		0x11
@@ -1092,7 +1094,7 @@
 		ldac_config = chip->ldac_config & (~ADT7516_DAC_IN_VREF_MASK);
 		if (data & 0x1)
 			ldac_config |= ADT7516_DAC_AB_IN_VREF;
-		else if (data & 0x2)
+		if (data & 0x2)
 			ldac_config |= ADT7516_DAC_CD_IN_VREF;
 	} else {
 		ret = kstrtou8(buf, 16, &data);
@@ -1414,7 +1416,7 @@
 static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
 		int channel, char *buf)
 {
-	u16 data;
+	u16 data = 0;
 	u8 msb, lsb, offset;
 	int ret;
 
@@ -1439,7 +1441,11 @@
 	if (ret)
 		return -EIO;
 
-	data = (msb << offset) + (lsb & ((1 << offset) - 1));
+	if (chip->dac_bits == 12)
+		data = lsb >> ADT7316_DA_12_BIT_LSB_SHIFT;
+	else if (chip->dac_bits == 10)
+		data = lsb >> ADT7316_DA_10_BIT_LSB_SHIFT;
+	data |= msb << offset;
 
 	return sprintf(buf, "%d\n", data);
 }
@@ -1447,7 +1453,7 @@
 static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip,
 		int channel, const char *buf, size_t len)
 {
-	u8 msb, lsb, offset;
+	u8 msb, lsb, lsb_reg, offset;
 	u16 data;
 	int ret;
 
@@ -1465,9 +1471,13 @@
 		return -EINVAL;
 
 	if (chip->dac_bits > 8) {
-		lsb = data & (1 << offset);
+		lsb = data & ((1 << offset) - 1);
+		if (chip->dac_bits == 12)
+			lsb_reg = lsb << ADT7316_DA_12_BIT_LSB_SHIFT;
+		else
+			lsb_reg = lsb << ADT7316_DA_10_BIT_LSB_SHIFT;
 		ret = chip->bus.write(chip->bus.client,
-			ADT7316_DA_DATA_BASE + channel * 2, lsb);
+			ADT7316_DA_DATA_BASE + channel * 2, lsb_reg);
 		if (ret)
 			return -EIO;
 	}
--- linux-4.4.0.orig/drivers/staging/iio/cdc/ad7150.c
+++ linux-4.4.0/drivers/staging/iio/cdc/ad7150.c
@@ -272,7 +272,7 @@
 error_ret:
 	mutex_unlock(&chip->state_lock);
 
-	return 0;
+	return ret;
 }
 
 static int ad7150_read_event_value(struct iio_dev *indio_dev,
--- linux-4.4.0.orig/drivers/staging/iio/frequency/ad9832.c
+++ linux-4.4.0/drivers/staging/iio/frequency/ad9832.c
@@ -33,12 +33,15 @@
 static int ad9832_write_frequency(struct ad9832_state *st,
 				  unsigned addr, unsigned long fout)
 {
+	unsigned long clk_freq;
 	unsigned long regval;
 
-	if (fout > (st->mclk / 2))
+	clk_freq = st->mclk;
+
+	if (!clk_freq || fout > (clk_freq / 2))
 		return -EINVAL;
 
-	regval = ad9832_calc_freqreg(st->mclk, fout);
+	regval = ad9832_calc_freqreg(clk_freq, fout);
 
 	st->freq_data[0] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
 					(addr << ADD_SHIFT) |
--- linux-4.4.0.orig/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ linux-4.4.0/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -647,6 +647,7 @@
 	__be16 buf[2];
 	int val[2];
 	unsigned char status;
+	int ret;
 
 	mutex_lock(&indio_dev->mlock);
 	if (st->state == AD5933_CTRL_INIT_START_FREQ) {
@@ -654,19 +655,22 @@
 		ad5933_cmd(st, AD5933_CTRL_START_SWEEP);
 		st->state = AD5933_CTRL_START_SWEEP;
 		schedule_delayed_work(&st->work, st->poll_time_jiffies);
-		mutex_unlock(&indio_dev->mlock);
-		return;
+		goto out;
 	}
 
-	ad5933_i2c_read(st->client, AD5933_REG_STATUS, 1, &status);
+	ret = ad5933_i2c_read(st->client, AD5933_REG_STATUS, 1, &status);
+	if (ret)
+		goto out;
 
 	if (status & AD5933_STAT_DATA_VALID) {
 		int scan_count = bitmap_weight(indio_dev->active_scan_mask,
 					       indio_dev->masklength);
-		ad5933_i2c_read(st->client,
+		ret = ad5933_i2c_read(st->client,
 				test_bit(1, indio_dev->active_scan_mask) ?
 				AD5933_REG_REAL_DATA : AD5933_REG_IMAG_DATA,
 				scan_count * 2, (u8 *)buf);
+		if (ret)
+			goto out;
 
 		if (scan_count == 2) {
 			val[0] = be16_to_cpu(buf[0]);
@@ -678,8 +682,7 @@
 	} else {
 		/* no data available - try again later */
 		schedule_delayed_work(&st->work, st->poll_time_jiffies);
-		mutex_unlock(&indio_dev->mlock);
-		return;
+		goto out;
 	}
 
 	if (status & AD5933_STAT_SWEEP_DONE) {
@@ -691,7 +694,7 @@
 		ad5933_cmd(st, AD5933_CTRL_INC_FREQ);
 		schedule_delayed_work(&st->work, st->poll_time_jiffies);
 	}
-
+out:
 	mutex_unlock(&indio_dev->mlock);
 }
 
--- linux-4.4.0.orig/drivers/staging/iio/magnetometer/hmc5843_i2c.c
+++ linux-4.4.0/drivers/staging/iio/magnetometer/hmc5843_i2c.c
@@ -59,8 +59,13 @@
 static int hmc5843_i2c_probe(struct i2c_client *cli,
 			     const struct i2c_device_id *id)
 {
+	struct regmap *regmap = devm_regmap_init_i2c(cli,
+			&hmc5843_i2c_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
 	return hmc5843_common_probe(&cli->dev,
-			devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config),
+			regmap,
 			id->driver_data, id->name);
 }
 
--- linux-4.4.0.orig/drivers/staging/iio/magnetometer/hmc5843_spi.c
+++ linux-4.4.0/drivers/staging/iio/magnetometer/hmc5843_spi.c
@@ -59,6 +59,7 @@
 static int hmc5843_spi_probe(struct spi_device *spi)
 {
 	int ret;
+	struct regmap *regmap;
 	const struct spi_device_id *id = spi_get_device_id(spi);
 
 	spi->mode = SPI_MODE_3;
@@ -68,8 +69,12 @@
 	if (ret)
 		return ret;
 
+	regmap = devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
 	return hmc5843_common_probe(&spi->dev,
-			devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config),
+			regmap,
 			id->driver_data, id->name);
 }
 
--- linux-4.4.0.orig/drivers/staging/iio/resolver/ad2s1210.c
+++ linux-4.4.0/drivers/staging/iio/resolver/ad2s1210.c
@@ -125,17 +125,24 @@
 static int ad2s1210_config_read(struct ad2s1210_state *st,
 		       unsigned char address)
 {
-	struct spi_transfer xfer = {
-		.len = 2,
-		.rx_buf = st->rx,
-		.tx_buf = st->tx,
+	struct spi_transfer xfers[] = {
+		{
+			.len = 1,
+			.rx_buf = &st->rx[0],
+			.tx_buf = &st->tx[0],
+			.cs_change = 1,
+		}, {
+			.len = 1,
+			.rx_buf = &st->rx[1],
+			.tx_buf = &st->tx[1],
+		},
 	};
 	int ret = 0;
 
 	ad2s1210_set_mode(MOD_CONFIG, st);
 	st->tx[0] = address | AD2S1210_MSB_IS_HIGH;
 	st->tx[1] = AD2S1210_REG_FAULT;
-	ret = spi_sync_transfer(st->sdev, &xfer, 1);
+	ret = spi_sync_transfer(st->sdev, xfers, 2);
 	if (ret < 0)
 		return ret;
 	st->old_data = true;
@@ -468,7 +475,7 @@
 			     long m)
 {
 	struct ad2s1210_state *st = iio_priv(indio_dev);
-	bool negative;
+	u16 negative;
 	int ret = 0;
 	u16 pos;
 	s16 vel;
--- linux-4.4.0.orig/drivers/staging/iio/resolver/ad2s90.c
+++ linux-4.4.0/drivers/staging/iio/resolver/ad2s90.c
@@ -86,7 +86,12 @@
 	/* need 600ns between CS and the first falling edge of SCLK */
 	spi->max_speed_hz = 830000;
 	spi->mode = SPI_MODE_3;
-	spi_setup(spi);
+	ret = spi_setup(spi);
+
+	if (ret < 0) {
+		dev_err(&spi->dev, "spi_setup failed!\n");
+		return ret;
+	}
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ linux-4.4.0/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -259,7 +259,7 @@
 out1:
 	iio_trigger_unregister(st->trig);
 out:
-	iio_trigger_put(st->trig);
+	iio_trigger_free(st->trig);
 	return ret;
 }
 
@@ -272,7 +272,7 @@
 		peripheral_free(st->t->pin);
 	free_irq(st->irq, st);
 	iio_trigger_unregister(st->trig);
-	iio_trigger_put(st->trig);
+	iio_trigger_free(st->trig);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ linux-4.4.0/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -2621,8 +2621,8 @@
 
 		net->ksnn_interfaces[j].ksni_ipaddr = ip;
 		net->ksnn_interfaces[j].ksni_netmask = mask;
-		strncpy(&net->ksnn_interfaces[j].ksni_name[0],
-			names[i], IFNAMSIZ);
+		strlcpy(net->ksnn_interfaces[j].ksni_name,
+			names[i], sizeof(net->ksnn_interfaces[j].ksni_name));
 		j++;
 	}
 
@@ -2805,8 +2805,9 @@
 				goto fail_1;
 			}
 
-			strncpy(&net->ksnn_interfaces[i].ksni_name[0],
-				ni->ni_interfaces[i], IFNAMSIZ);
+			strlcpy(net->ksnn_interfaces[i].ksni_name,
+				ni->ni_interfaces[i],
+				sizeof(net->ksnn_interfaces[i].ksni_name));
 		}
 		net->ksnn_ninterfaces = i;
 	}
--- linux-4.4.0.orig/drivers/staging/lustre/lnet/lnet/config.c
+++ linux-4.4.0/drivers/staging/lustre/lnet/lnet/config.c
@@ -650,8 +650,8 @@
 	INIT_LIST_HEAD(&nets);
 
 	/* save a copy of the string for error messages */
-	strncpy(cmd, str, sizeof(cmd) - 1);
-	cmd[sizeof(cmd) - 1] = 0;
+	strncpy(cmd, str, sizeof(cmd));
+	cmd[sizeof(cmd) - 1] = '\0';
 
 	sep = str;
 	for (;;) {
@@ -972,11 +972,13 @@
 			return 0;
 
 		offset += (int)(sep - tb->ltb_text);
-		tb2 = lnet_new_text_buf(strlen(sep));
+		len = strlen(sep);
+		tb2 = lnet_new_text_buf(len);
 		if (tb2 == NULL)
 			return -ENOMEM;
 
-		strcpy(tb2->ltb_text, sep);
+		strncpy(tb2->ltb_text, sep, len);
+		tb2->ltb_text[len] = '\0';
 		list_add_tail(&tb2->ltb_list, nets);
 
 		tb = tb2;
@@ -1021,8 +1023,8 @@
 		tb = list_entry(raw_entries.next, struct lnet_text_buf_t,
 				    ltb_list);
 
-		strncpy(source, tb->ltb_text, sizeof(source)-1);
-		source[sizeof(source)-1] = 0;
+		strncpy(source, tb->ltb_text, sizeof(source));
+		source[sizeof(source)-1] = '\0';
 
 		/* replace ltb_text with the network(s) add on match */
 		rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
--- linux-4.4.0.orig/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ linux-4.4.0/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -612,8 +612,8 @@
 		msrq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.mksn_reqst;
 		msrq->mksn_sid     = console_session.ses_id;
 		msrq->mksn_force   = console_session.ses_force;
-		strncpy(msrq->mksn_name, console_session.ses_name,
-			strlen(console_session.ses_name));
+		strlcpy(msrq->mksn_name, console_session.ses_name,
+			sizeof(msrq->mksn_name));
 		break;
 
 	case LST_TRANS_SESEND:
--- linux-4.4.0.orig/drivers/staging/lustre/lnet/selftest/console.c
+++ linux-4.4.0/drivers/staging/lustre/lnet/selftest/console.c
@@ -1739,7 +1739,8 @@
 	console_session.ses_feats_updated = 0;
 	console_session.ses_timeout = (timeout <= 0) ?
 				      LST_CONSOLE_TIMEOUT : timeout;
-	strcpy(console_session.ses_name, name);
+	strlcpy(console_session.ses_name, name,
+		sizeof(console_session.ses_name));
 
 	rc = lstcon_batch_add(LST_DEFAULT_BATCH);
 	if (rc != 0)
@@ -1959,7 +1960,8 @@
 	if (grp->grp_userland == 0)
 		grp->grp_userland = 1;
 
-	strcpy(jrep->join_session, console_session.ses_name);
+	strlcpy(jrep->join_session, console_session.ses_name,
+		sizeof(jrep->join_session));
 	jrep->join_timeout = console_session.ses_timeout;
 	jrep->join_status  = 0;
 
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
+++ linux-4.4.0/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
@@ -1063,23 +1063,21 @@
  * \retval buffer
  */
 static inline char *hai_dump_data_field(struct hsm_action_item *hai,
-					char *buffer, int len)
+					char *buffer, size_t len)
 {
-	int i, sz, data_len;
+	int i, data_len;
 	char *ptr;
 
 	ptr = buffer;
-	sz = len;
 	data_len = hai->hai_len - sizeof(*hai);
-	for (i = 0 ; (i < data_len) && (sz > 0) ; i++) {
-		int cnt;
-
-		cnt = snprintf(ptr, sz, "%.2X",
-			       (unsigned char)hai->hai_data[i]);
-		ptr += cnt;
-		sz -= cnt;
+	for (i = 0; (i < data_len) && (len > 2); i++) {
+		snprintf(ptr, 3, "%02X", (unsigned char)hai->hai_data[i]);
+		ptr += 2;
+		len -= 2;
 	}
+
 	*ptr = '\0';
+
 	return buffer;
 }
 
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/include/lustre_disk.h
+++ linux-4.4.0/drivers/staging/lustre/lustre/include/lustre_disk.h
@@ -68,6 +68,7 @@
    everything as string options */
 
 #define LMD_MAGIC    0xbdacbd03
+#define LMD_PARAMS_MAXLEN	4096
 
 /* gleaned from the mount command - no persistent info here */
 struct lustre_mount_data {
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
@@ -550,6 +550,13 @@
 	if (lock == NULL)
 		return NULL;
 
+	if (lock->l_export && lock->l_export->exp_failed) {
+		CDEBUG(D_INFO, "lock export failed: lock %p, exp %p\n",
+		       lock, lock->l_export);
+		LDLM_LOCK_PUT(lock);
+		return NULL;
+	}
+
 	/* It's unlikely but possible that someone marked the lock as
 	 * destroyed after we did handle2object on it */
 	if (flags == 0 && ((lock->l_flags & LDLM_FL_DESTROYED) == 0)) {
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/libcfs/debug.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/libcfs/debug.c
@@ -512,9 +512,9 @@
 	}
 
 	if (libcfs_debug_file_path != NULL) {
-		strncpy(libcfs_debug_file_path_arr,
-			libcfs_debug_file_path, PATH_MAX-1);
-		libcfs_debug_file_path_arr[PATH_MAX - 1] = '\0';
+		strlcpy(libcfs_debug_file_path_arr,
+			libcfs_debug_file_path,
+			sizeof(libcfs_debug_file_path_arr));
 	}
 
 	/* If libcfs_debug_mb is set to an invalid value or uninitialized
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/libcfs/hash.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/libcfs/hash.c
@@ -1062,8 +1062,7 @@
 	if (hs == NULL)
 		return NULL;
 
-	strncpy(hs->hs_name, name, len);
-	hs->hs_name[len - 1] = '\0';
+	strlcpy(hs->hs_name, name, len);
 	hs->hs_flags = flags;
 
 	atomic_set(&hs->hs_refcount, 1);
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/libcfs/workitem.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/libcfs/workitem.c
@@ -360,8 +360,8 @@
 	if (sched == NULL)
 		return -ENOMEM;
 
-	strncpy(sched->ws_name, name, CFS_WS_NAME_LEN);
-	sched->ws_name[CFS_WS_NAME_LEN - 1] = '\0';
+	strlcpy(sched->ws_name, name, CFS_WS_NAME_LEN);
+
 	sched->ws_cptab = cptab;
 	sched->ws_cpt = cpt;
 
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/llite/dir.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/llite/dir.c
@@ -641,7 +641,7 @@
 	if (!msp)
 		return -ENOMEM;
 
-	strncpy(msp->mgs_param, string, MGS_PARAM_MAXLEN);
+	strlcpy(msp->mgs_param, string, sizeof(msp->mgs_param));
 	rc = obd_set_info_async(NULL, mgc, sizeof(KEY_SET_INFO), KEY_SET_INFO,
 				sizeof(struct mgs_send_param), msp, NULL);
 	if (rc)
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ linux-4.4.0/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -631,8 +631,6 @@
 
 struct lov_stripe_md;
 
-extern spinlock_t inode_lock;
-
 extern struct dentry *llite_root;
 extern struct kset *llite_kset;
 
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -1233,7 +1233,7 @@
 		attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
 	}
 
-	/* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
+	/* POSIX: check before ATTR_*TIME_SET set (from setattr_prepare) */
 	if (attr->ia_valid & TIMES_SET_FLAGS) {
 		if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
 		    !capable(CFS_CAP_FOWNER))
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/llite/llite_mmap.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/llite/llite_mmap.c
@@ -402,15 +402,13 @@
 		result = VM_FAULT_LOCKED;
 		break;
 	case -ENODATA:
+	case -EAGAIN:
 	case -EFAULT:
 		result = VM_FAULT_NOPAGE;
 		break;
 	case -ENOMEM:
 		result = VM_FAULT_OOM;
 		break;
-	case -EAGAIN:
-		result = VM_FAULT_RETRY;
-		break;
 	default:
 		result = VM_FAULT_SIGBUS;
 		break;
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/llite/rw26.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/llite/rw26.c
@@ -376,6 +376,10 @@
 	if (!lli->lli_has_smd)
 		return -EBADF;
 
+	/* Check EOF by ourselves */
+	if (iov_iter_rw(iter) == READ && file_offset >= i_size_read(inode))
+		return 0;
+
 	/* FIXME: io smaller than PAGE_SIZE is broken on ia64 ??? */
 	if ((file_offset & ~CFS_PAGE_MASK) || (count & ~CFS_PAGE_MASK))
 		return -EINVAL;
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/lmv/lmv_obd.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/lmv/lmv_obd.c
@@ -700,7 +700,7 @@
 		memmove(ptr + strlen(gf->gf_path) + 1, ptr,
 			strlen(ori_gf->gf_path));
 
-		strncpy(ptr, gf->gf_path, strlen(gf->gf_path));
+		strcpy(ptr, gf->gf_path);
 		ptr += strlen(gf->gf_path);
 		*ptr = '/';
 	}
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/lov/lov_pack.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/lov/lov_pack.c
@@ -399,18 +399,10 @@
 	struct lov_mds_md *lmmk = NULL;
 	int rc, lmm_size;
 	int lum_size;
-	mm_segment_t seg;
 
 	if (!lsm)
 		return -ENODATA;
 
-	/*
-	 * "Switch to kernel segment" to allow copying from kernel space by
-	 * copy_{to,from}_user().
-	 */
-	seg = get_fs();
-	set_fs(KERNEL_DS);
-
 	/* we only need the header part from user space to get lmm_magic and
 	 * lmm_stripe_count, (the header part is common to v1 and v3) */
 	lum_size = sizeof(struct lov_user_md_v1);
@@ -485,6 +477,5 @@
 
 	obd_free_diskmd(exp, &lmmk);
 out_set:
-	set_fs(seg);
 	return rc;
 }
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/lov/lov_pool.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/lov/lov_pool.c
@@ -412,8 +412,7 @@
 	if (!new_pool)
 		return -ENOMEM;
 
-	strncpy(new_pool->pool_name, poolname, LOV_MAXPOOLNAME);
-	new_pool->pool_name[LOV_MAXPOOLNAME] = '\0';
+	strlcpy(new_pool->pool_name, poolname, sizeof(new_pool->pool_name));
 	new_pool->pool_lobd = obd;
 	/* ref count init to 1 because when created a pool is always used
 	 * up to deletion
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -433,7 +433,7 @@
 		return rc;
 	}
 
-	rc = posix_acl_valid(acl);
+	rc = posix_acl_valid(&init_user_ns, acl);
 	if (rc) {
 		CERROR("validate acl: %d\n", rc);
 		posix_acl_release(acl);
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -892,7 +892,7 @@
 	}
 	lmd->lmd_magic = LMD_MAGIC;
 
-	lmd->lmd_params = kzalloc(4096, GFP_NOFS);
+	lmd->lmd_params = kzalloc(LMD_PARAMS_MAXLEN, GFP_NOFS);
 	if (!lmd->lmd_params)
 		return -ENOMEM;
 	lmd->lmd_params[0] = '\0';
@@ -978,7 +978,7 @@
 				goto invalid;
 			clear++;
 		} else if (strncmp(s1, "param=", 6) == 0) {
-			int length;
+			size_t length, params_length;
 			char *tail = strchr(s1 + 6, ',');
 
 			if (tail == NULL)
@@ -986,8 +986,12 @@
 			else
 				length = tail - s1;
 			length -= 6;
+			params_length = strlen(lmd->lmd_params);
+			if (params_length + length + 1 >= LMD_PARAMS_MAXLEN)
+				return -E2BIG;
 			strncat(lmd->lmd_params, s1 + 6, length);
-			strcat(lmd->lmd_params, " ");
+			lmd->lmd_params[params_length + length] = '\0';
+			strlcat(lmd->lmd_params, " ", LMD_PARAMS_MAXLEN);
 			clear++;
 		} else if (strncmp(s1, "osd=", 4) == 0) {
 			rc = lmd_parse_string(&lmd->lmd_osd_type, s1 + 4);
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -422,6 +422,7 @@
 	complete(&pc->pc_starting);
 
 	/*
+
 	 * This mainloop strongly resembles ptlrpc_set_wait() except that our
 	 * set never completes.  ptlrpcd_check() calls ptlrpc_check_set() when
 	 * there are requests in the set. New requests come in on the set's
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/ptlrpc/sec.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/ptlrpc/sec.c
@@ -824,7 +824,7 @@
 	if (req->rq_pool || !req->rq_reqbuf)
 		return;
 
-	kfree(req->rq_reqbuf);
+	kvfree(req->rq_reqbuf);
 	req->rq_reqbuf = NULL;
 	req->rq_reqbuf_len = 0;
 }
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
@@ -83,8 +83,7 @@
 		return 0;
 	}
 
-	strncpy(buf, str, sizeof(buf));
-	buf[sizeof(buf) - 1] = '\0';
+	strlcpy(buf, str, sizeof(buf));
 
 	bulk = strchr(buf, '-');
 	if (bulk)
--- linux-4.4.0.orig/drivers/staging/lustre/lustre/ptlrpc/service.c
+++ linux-4.4.0/drivers/staging/lustre/lustre/ptlrpc/service.c
@@ -1240,20 +1240,15 @@
 		 * it may hit swab race at LU-1044. */
 		if (req->rq_ops->hpreq_check) {
 			rc = req->rq_ops->hpreq_check(req);
-			/**
-			 * XXX: Out of all current
-			 * ptlrpc_hpreq_ops::hpreq_check(), only
-			 * ldlm_cancel_hpreq_check() can return an error code;
-			 * other functions assert in similar places, which seems
-			 * odd. What also does not seem right is that handlers
-			 * for those RPCs do not assert on the same checks, but
-			 * rather handle the error cases. e.g. see
-			 * ost_rw_hpreq_check(), and ost_brw_read(),
-			 * ost_brw_write().
+			if (rc == -ESTALE) {
+				req->rq_status = rc;
+				ptlrpc_error(req);
+			}
+			/** can only return error,
+			 * 0 for normal request,
+			 *  or 1 for high priority request
 			 */
-			if (rc < 0)
-				return rc;
-			LASSERT(rc == 0 || rc == 1);
+			LASSERT(rc <= 1);
 		}
 
 		spin_lock_bh(&req->rq_export->exp_rpc_lock);
--- linux-4.4.0.orig/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ linux-4.4.0/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -406,6 +406,9 @@
 	/* If decoder is not initialized. initialize it */
 	if (!video->initialized && vpfe_update_pipe_state(video)) {
 		mutex_unlock(&video->lock);
+		v4l2_fh_del(&handle->vfh);
+		v4l2_fh_exit(&handle->vfh);
+		kfree(handle);
 		return -ENODEV;
 	}
 	/* Increment device users counter */
--- linux-4.4.0.orig/drivers/staging/media/lirc/lirc_imon.c
+++ linux-4.4.0/drivers/staging/media/lirc/lirc_imon.c
@@ -885,12 +885,14 @@
 		vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum);
 
 	/* Everything went fine. Just unlock and return retval (with is 0) */
+	mutex_unlock(&context->ctx_lock);
 	goto driver_unlock;
 
 unregister_lirc:
 	lirc_unregister_driver(driver->minor);
 
 free_tx_urb:
+	mutex_unlock(&context->ctx_lock);
 	usb_free_urb(tx_urb);
 
 free_rx_urb:
--- linux-4.4.0.orig/drivers/staging/media/lirc/lirc_sir.c
+++ linux-4.4.0/drivers/staging/media/lirc/lirc_sir.c
@@ -986,10 +986,10 @@
 #endif
 MODULE_LICENSE("GPL");
 
-module_param(io, int, S_IRUGO);
+module_param_hw(io, int, ioport, S_IRUGO);
 MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
 
-module_param(irq, int, S_IRUGO);
+module_param_hw(irq, int, irq, S_IRUGO);
 MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
 
 module_param(threshold, int, S_IRUGO);
--- linux-4.4.0.orig/drivers/staging/media/omap4iss/iss_video.c
+++ linux-4.4.0/drivers/staging/media/omap4iss/iss_video.c
@@ -11,7 +11,6 @@
  * (at your option) any later version.
  */
 
-#include <asm/cacheflush.h>
 #include <linux/clk.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
@@ -22,6 +21,8 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
 
+#include <asm/cacheflush.h>
+
 #include "iss_video.h"
 #include "iss.h"
 
--- linux-4.4.0.orig/drivers/staging/most/aim-network/networking.c
+++ linux-4.4.0/drivers/staging/most/aim-network/networking.c
@@ -87,6 +87,11 @@
 	unsigned int payload_len = skb->len - ETH_HLEN;
 	unsigned int mdp_len = payload_len + MDP_HDR_LEN;
 
+	if (mdp_len < skb->len) {
+		pr_err("drop: too large packet! (%u)\n", skb->len);
+		return -EINVAL;
+	}
+
 	if (mbo->buffer_length < mdp_len) {
 		pr_err("drop: too small buffer! (%d for %d)\n",
 		       mbo->buffer_length, mdp_len);
@@ -134,6 +139,11 @@
 	u8 *buff = mbo->virt_address;
 	unsigned int mep_len = skb->len + MEP_HDR_LEN;
 
+	if (mep_len < skb->len) {
+		pr_err("drop: too large packet! (%u)\n", skb->len);
+		return -EINVAL;
+	}
+
 	if (mbo->buffer_length < mep_len) {
 		pr_err("drop: too small buffer! (%d for %d)\n",
 		       mbo->buffer_length, mep_len);
--- linux-4.4.0.orig/drivers/staging/most/aim-sound/sound.c
+++ linux-4.4.0/drivers/staging/most/aim-sound/sound.c
@@ -92,6 +92,8 @@
 {
 	unsigned int i = 0;
 
+	if (bytes < 2)
+		return;
 	while (i < bytes - 2) {
 		dest[i] = source[i + 2];
 		dest[i + 1] = source[i + 1];
--- linux-4.4.0.orig/drivers/staging/nvec/nvec_ps2.c
+++ linux-4.4.0/drivers/staging/nvec/nvec_ps2.c
@@ -106,13 +106,12 @@
 {
 	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
 	struct serio *ser_dev;
-	char mouse_reset[] = { NVEC_PS2, SEND_COMMAND, PSMOUSE_RST, 3 };
 
-	ser_dev = devm_kzalloc(&pdev->dev, sizeof(struct serio), GFP_KERNEL);
+	ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL);
 	if (!ser_dev)
 		return -ENOMEM;
 
-	ser_dev->id.type = SERIO_PS_PSTHRU;
+	ser_dev->id.type = SERIO_8042;
 	ser_dev->write = ps2_sendcommand;
 	ser_dev->start = ps2_startstreaming;
 	ser_dev->stop = ps2_stopstreaming;
@@ -127,9 +126,6 @@
 
 	serio_register_port(ser_dev);
 
-	/* mouse reset */
-	nvec_write_async(nvec, mouse_reset, sizeof(mouse_reset));
-
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/staging/panel/panel.c
+++ linux-4.4.0/drivers/staging/panel/panel.c
@@ -825,8 +825,7 @@
 	lcd_send_serial(0x1F);	/* R/W=W, RS=0 */
 	lcd_send_serial(cmd & 0x0F);
 	lcd_send_serial((cmd >> 4) & 0x0F);
-	/* the shortest command takes at least 40 us */
-	usleep_range(40, 100);
+	udelay(40);		/* the shortest command takes at least 40 us */
 	spin_unlock_irq(&pprt_lock);
 }
 
@@ -837,8 +836,7 @@
 	lcd_send_serial(0x5F);	/* R/W=W, RS=1 */
 	lcd_send_serial(data & 0x0F);
 	lcd_send_serial((data >> 4) & 0x0F);
-	/* the shortest data takes at least 40 us */
-	usleep_range(40, 100);
+	udelay(40);		/* the shortest data takes at least 40 us */
 	spin_unlock_irq(&pprt_lock);
 }
 
@@ -848,20 +846,19 @@
 	spin_lock_irq(&pprt_lock);
 	/* present the data to the data port */
 	w_dtr(pprt, cmd);
-	/* maintain the data during 20 us before the strobe */
-	usleep_range(20, 100);
+	udelay(20);	/* maintain the data during 20 us before the strobe */
 
 	bits.e = BIT_SET;
 	bits.rs = BIT_CLR;
 	bits.rw = BIT_CLR;
 	set_ctrl_bits();
 
-	usleep_range(40, 100);	/* maintain the strobe during 40 us */
+	udelay(40);	/* maintain the strobe during 40 us */
 
 	bits.e = BIT_CLR;
 	set_ctrl_bits();
 
-	usleep_range(120, 500);	/* the shortest command takes at least 120 us */
+	udelay(120);	/* the shortest command takes at least 120 us */
 	spin_unlock_irq(&pprt_lock);
 }
 
@@ -871,20 +868,19 @@
 	spin_lock_irq(&pprt_lock);
 	/* present the data to the data port */
 	w_dtr(pprt, data);
-	/* maintain the data during 20 us before the strobe */
-	usleep_range(20, 100);
+	udelay(20);	/* maintain the data during 20 us before the strobe */
 
 	bits.e = BIT_SET;
 	bits.rs = BIT_SET;
 	bits.rw = BIT_CLR;
 	set_ctrl_bits();
 
-	usleep_range(40, 100);	/* maintain the strobe during 40 us */
+	udelay(40);	/* maintain the strobe during 40 us */
 
 	bits.e = BIT_CLR;
 	set_ctrl_bits();
 
-	usleep_range(45, 100);	/* the shortest data takes at least 45 us */
+	udelay(45);	/* the shortest data takes at least 45 us */
 	spin_unlock_irq(&pprt_lock);
 }
 
@@ -894,7 +890,7 @@
 	spin_lock_irq(&pprt_lock);
 	/* present the data to the control port */
 	w_ctr(pprt, cmd);
-	usleep_range(60, 120);
+	udelay(60);
 	spin_unlock_irq(&pprt_lock);
 }
 
@@ -904,7 +900,7 @@
 	spin_lock_irq(&pprt_lock);
 	/* present the data to the data port */
 	w_dtr(pprt, data);
-	usleep_range(60, 120);
+	udelay(60);
 	spin_unlock_irq(&pprt_lock);
 }
 
@@ -947,7 +943,7 @@
 		lcd_send_serial(0x5F);	/* R/W=W, RS=1 */
 		lcd_send_serial(' ' & 0x0F);
 		lcd_send_serial((' ' >> 4) & 0x0F);
-		usleep_range(40, 100);	/* the shortest data takes at least 40 us */
+		udelay(40);	/* the shortest data takes at least 40 us */
 	}
 	spin_unlock_irq(&pprt_lock);
 
@@ -971,7 +967,7 @@
 		w_dtr(pprt, ' ');
 
 		/* maintain the data during 20 us before the strobe */
-		usleep_range(20, 100);
+		udelay(20);
 
 		bits.e = BIT_SET;
 		bits.rs = BIT_SET;
@@ -979,13 +975,13 @@
 		set_ctrl_bits();
 
 		/* maintain the strobe during 40 us */
-		usleep_range(40, 100);
+		udelay(40);
 
 		bits.e = BIT_CLR;
 		set_ctrl_bits();
 
 		/* the shortest data takes at least 45 us */
-		usleep_range(45, 100);
+		udelay(45);
 	}
 	spin_unlock_irq(&pprt_lock);
 
@@ -1007,7 +1003,7 @@
 	for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
 		/* present the data to the data port */
 		w_dtr(pprt, ' ');
-		usleep_range(60, 120);
+		udelay(60);
 	}
 
 	spin_unlock_irq(&pprt_lock);
@@ -1435,17 +1431,25 @@
 
 static int lcd_open(struct inode *inode, struct file *file)
 {
+	int ret;
+
+	ret = -EBUSY;
 	if (!atomic_dec_and_test(&lcd_available))
-		return -EBUSY;	/* open only once at a time */
+		goto fail; /* open only once at a time */
 
+	ret = -EPERM;
 	if (file->f_mode & FMODE_READ)	/* device is write-only */
-		return -EPERM;
+		goto fail;
 
 	if (lcd.must_clear) {
 		lcd_clear_display();
 		lcd.must_clear = false;
 	}
 	return nonseekable_open(inode, file);
+
+ fail:
+	atomic_inc(&lcd_available);
+	return ret;
 }
 
 static int lcd_release(struct inode *inode, struct file *file)
@@ -1708,14 +1712,21 @@
 
 static int keypad_open(struct inode *inode, struct file *file)
 {
+	int ret;
+
+	ret = -EBUSY;
 	if (!atomic_dec_and_test(&keypad_available))
-		return -EBUSY;	/* open only once at a time */
+		goto fail;	/* open only once at a time */
 
+	ret = -EPERM;
 	if (file->f_mode & FMODE_WRITE)	/* device is read-only */
-		return -EPERM;
+		goto fail;
 
 	keypad_buflen = 0;	/* flush the buffer on opening */
 	return 0;
+ fail:
+	atomic_inc(&keypad_available);
+	return ret;
 }
 
 static int keypad_release(struct inode *inode, struct file *file)
--- linux-4.4.0.orig/drivers/staging/rdma/ehca/ehca_mrmw.c
+++ linux-4.4.0/drivers/staging/rdma/ehca/ehca_mrmw.c
@@ -1921,7 +1921,7 @@
 				  u64 *kpage)
 {
 	int ret = 0;
-	u64 pgaddr, prev_pgaddr;
+	u64 pgaddr, prev_pgaddr = 0;
 	u32 j = 0;
 	int kpages_per_hwpage = pginfo->hwpage_size / PAGE_SIZE;
 	int nr_kpages = kpages_per_hwpage;
@@ -2417,6 +2417,7 @@
 		ehca_err(&shca->ib_device, "kpage alloc failed");
 		return -ENOMEM;
 	}
+	hret = H_SUCCESS;
 	for (top = 0; top < EHCA_MAP_ENTRIES; top++) {
 		if (!ehca_bmap_valid(ehca_bmap->top[top]))
 			continue;
--- linux-4.4.0.orig/drivers/staging/rdma/hfi1/TODO
+++ linux-4.4.0/drivers/staging/rdma/hfi1/TODO
@@ -3,4 +3,4 @@
 - Remove unneeded file entries in sysfs
 - Remove software processing of IB protocol and place in library for use
   by qib, ipath (if still present), hfi1, and eventually soft-roce
-
+- Replace incorrect uAPI
--- linux-4.4.0.orig/drivers/staging/rdma/hfi1/chip.c
+++ linux-4.4.0/drivers/staging/rdma/hfi1/chip.c
@@ -5906,6 +5906,7 @@
 
 	/* disable the port */
 	clear_rcvctrl(dd, RCV_CTRL_RCV_PORT_ENABLE_SMASK);
+	cancel_work_sync(&ppd->freeze_work);
 }
 
 static inline int init_cpu_counters(struct hfi1_devdata *dd)
--- linux-4.4.0.orig/drivers/staging/rdma/hfi1/file_ops.c
+++ linux-4.4.0/drivers/staging/rdma/hfi1/file_ops.c
@@ -62,6 +62,8 @@
 #include <linux/cred.h>
 #include <linux/uio.h>
 
+#include <rdma/ib.h>
+
 #include "hfi.h"
 #include "pio.h"
 #include "device.h"
@@ -214,6 +216,10 @@
 	int uctxt_required = 1;
 	int must_be_root = 0;
 
+	/* FIXME: This interface cannot continue out of staging */
+	if (WARN_ON_ONCE(!ib_safe_file_access(fp)))
+		return -EACCES;
+
 	if (count < sizeof(cmd)) {
 		ret = -EINVAL;
 		goto bail;
--- linux-4.4.0.orig/drivers/staging/rdma/hfi1/pcie.c
+++ linux-4.4.0/drivers/staging/rdma/hfi1/pcie.c
@@ -389,7 +389,8 @@
 	/*
 	 * bus->max_bus_speed is set from the bridge's linkcap Max Link Speed
 	 */
-	if (dd->pcidev->bus->max_bus_speed != PCIE_SPEED_8_0GT) {
+	if (dd->pcidev->bus->max_bus_speed == PCIE_SPEED_2_5GT ||
+	     dd->pcidev->bus->max_bus_speed == PCIE_SPEED_5_0GT) {
 		dd_dev_info(dd, "Parent PCIe bridge does not support Gen3\n");
 		dd->link_gen3_capable = 0;
 	}
--- linux-4.4.0.orig/drivers/staging/rdma/hfi1/sysfs.c
+++ linux-4.4.0/drivers/staging/rdma/hfi1/sysfs.c
@@ -620,7 +620,11 @@
 		dd_dev_err(dd,
 			   "Skipping sc2vl sysfs info, (err %d) port %u\n",
 			   ret, port_num);
-		goto bail;
+		/*
+		 * Based on the documentation for kobject_init_and_add(), the
+		 * caller should call kobject_put even if this call fails.
+		 */
+		goto bail_sc2vl;
 	}
 	kobject_uevent(&ppd->sc2vl_kobj, KOBJ_ADD);
 
@@ -630,7 +634,7 @@
 		dd_dev_err(dd,
 			   "Skipping sl2sc sysfs info, (err %d) port %u\n",
 			   ret, port_num);
-		goto bail_sc2vl;
+		goto bail_sl2sc;
 	}
 	kobject_uevent(&ppd->sl2sc_kobj, KOBJ_ADD);
 
@@ -640,7 +644,7 @@
 		dd_dev_err(dd,
 			   "Skipping vl2mtu sysfs info, (err %d) port %u\n",
 			   ret, port_num);
-		goto bail_sl2sc;
+		goto bail_vl2mtu;
 	}
 	kobject_uevent(&ppd->vl2mtu_kobj, KOBJ_ADD);
 
@@ -651,7 +655,7 @@
 		dd_dev_err(dd,
 		 "Skipping Congestion Control sysfs info, (err %d) port %u\n",
 		 ret, port_num);
-		goto bail_vl2mtu;
+		goto bail_cc;
 	}
 
 	kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD);
@@ -691,7 +695,6 @@
 	kobject_put(&ppd->sl2sc_kobj);
 bail_sc2vl:
 	kobject_put(&ppd->sc2vl_kobj);
-bail:
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/staging/rdma/hfi1/ud.c
+++ linux-4.4.0/drivers/staging/rdma/hfi1/ud.c
@@ -793,7 +793,6 @@
 	    opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
 		wc.ex.imm_data = ohdr->u.ud.imm_data;
 		wc.wc_flags = IB_WC_WITH_IMM;
-		tlen -= sizeof(u32);
 	} else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
 		wc.ex.imm_data = 0;
 		wc.wc_flags = 0;
--- linux-4.4.0.orig/drivers/staging/rdma/hfi1/user_pages.c
+++ linux-4.4.0/drivers/staging/rdma/hfi1/user_pages.c
@@ -85,7 +85,7 @@
 	for (got = 0; got < num_pages; got += ret) {
 		ret = get_user_pages(current, current->mm,
 				     start_page + got * PAGE_SIZE,
-				     num_pages - got, 1, 1,
+				     num_pages - got, FOLL_WRITE | FOLL_FORCE,
 				     p + got, NULL);
 		if (ret < 0)
 			goto bail_release;
--- linux-4.4.0.orig/drivers/staging/rdma/ipath/ipath_file_ops.c
+++ linux-4.4.0/drivers/staging/rdma/ipath/ipath_file_ops.c
@@ -45,6 +45,8 @@
 #include <linux/uio.h>
 #include <asm/pgtable.h>
 
+#include <rdma/ib.h>
+
 #include "ipath_kernel.h"
 #include "ipath_common.h"
 #include "ipath_user_sdma.h"
@@ -2243,6 +2245,9 @@
 	ssize_t ret = 0;
 	void *dest;
 
+	if (WARN_ON_ONCE(!ib_safe_file_access(fp)))
+		return -EACCES;
+
 	if (count < sizeof(cmd.type)) {
 		ret = -EINVAL;
 		goto bail;
--- linux-4.4.0.orig/drivers/staging/rdma/ipath/ipath_user_pages.c
+++ linux-4.4.0/drivers/staging/rdma/ipath/ipath_user_pages.c
@@ -72,7 +72,7 @@
 	for (got = 0; got < num_pages; got += ret) {
 		ret = get_user_pages(current, current->mm,
 				     start_page + got * PAGE_SIZE,
-				     num_pages - got, 1, 1,
+				     num_pages - got, FOLL_WRITE | FOLL_FORCE,
 				     p + got, NULL);
 		if (ret < 0)
 			goto bail_release;
--- linux-4.4.0.orig/drivers/staging/rtl8188eu/core/rtw_ap.c
+++ linux-4.4.0/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -894,7 +894,7 @@
 		return _FAIL;
 
 
-	if (len > MAX_IE_SZ)
+	if (len < 0 || len > MAX_IE_SZ)
 		return _FAIL;
 
 	pbss_network->IELength = len;
@@ -921,6 +921,7 @@
 	/* SSID */
 	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
 	if (p && ie_len > 0) {
+		ie_len = min_t(int, ie_len, sizeof(pbss_network->Ssid.Ssid));
 		memset(&pbss_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
 		memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len);
 		pbss_network->Ssid.SsidLength = ie_len;
@@ -939,6 +940,7 @@
 	/*  get supported rates */
 	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
 	if (p !=  NULL) {
+		ie_len = min_t(int, ie_len, NDIS_802_11_LENGTH_RATES_EX);
 		memcpy(supportRate, p+2, ie_len);
 		supportRateNum = ie_len;
 	}
@@ -946,6 +948,8 @@
 	/* get ext_supported rates */
 	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_);
 	if (p !=  NULL) {
+		ie_len = min_t(int, ie_len,
+			       NDIS_802_11_LENGTH_RATES_EX - supportRateNum);
 		memcpy(supportRate+supportRateNum, p+2, ie_len);
 		supportRateNum += ie_len;
 	}
@@ -1061,6 +1065,7 @@
 			pht_cap->supp_mcs_set[0] = 0xff;
 			pht_cap->supp_mcs_set[1] = 0x0;
 		}
+		ie_len = min_t(int, ie_len, sizeof(pmlmepriv->htpriv.ht_cap));
 		memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len);
 	}
 
--- linux-4.4.0.orig/drivers/staging/rtl8188eu/core/rtw_cmd.c
+++ linux-4.4.0/drivers/staging/rtl8188eu/core/rtw_cmd.c
@@ -718,13 +718,13 @@
 	u8	res = _SUCCESS;
 
 
-	ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+	ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
 	if (ph2c == NULL) {
 		res = _FAIL;
 		goto exit;
 	}
 
-	paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_KERNEL);
+	paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_ATOMIC);
 	if (paddbareq_parm == NULL) {
 		kfree(ph2c);
 		res = _FAIL;
--- linux-4.4.0.orig/drivers/staging/rtl8188eu/core/rtw_recv.c
+++ linux-4.4.0/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -1405,6 +1405,9 @@
 		ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
 	}
 
+	if (!ptr)
+		return _FAIL;
+
 	memcpy(ptr, pattrib->dst, ETH_ALEN);
 	memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN);
 
--- linux-4.4.0.orig/drivers/staging/rtl8188eu/core/rtw_xmit.c
+++ linux-4.4.0/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -822,7 +822,7 @@
 			memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN);
 			memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN);
 
-			if (psta->qos_option)
+			if (psta && psta->qos_option)
 				qos_option = true;
 		} else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
 			   check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
@@ -830,7 +830,7 @@
 			memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
 			memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN);
 
-			if (psta->qos_option)
+			if (psta && psta->qos_option)
 				qos_option = true;
 		} else {
 			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv)));
--- linux-4.4.0.orig/drivers/staging/rtl8188eu/include/rtw_debug.h
+++ linux-4.4.0/drivers/staging/rtl8188eu/include/rtw_debug.h
@@ -75,7 +75,7 @@
 #define DBG_88E_LEVEL(_level, fmt, arg...)				\
 	do {								\
 		if (_level <= GlobalDebugLevel)				\
-			pr_info(DRIVER_PREFIX"ERROR " fmt, ##arg);	\
+			pr_info(DRIVER_PREFIX fmt, ##arg);	\
 	} while (0)
 
 #define DBG_88E(...)							\
--- linux-4.4.0.orig/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
+++ linux-4.4.0/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -1174,9 +1174,11 @@
 						break;
 					}
 					sec_len = *(pos++); len -= 1;
-					if (sec_len > 0 && sec_len <= len) {
+					if (sec_len > 0 &&
+					    sec_len <= len &&
+					    sec_len <= 32) {
 						ssid[ssid_index].SsidLength = sec_len;
-						memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength);
+						memcpy(ssid[ssid_index].Ssid, pos, sec_len);
 						ssid_index++;
 					}
 					pos += sec_len;
@@ -1399,19 +1401,13 @@
 	if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
 	    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) {
 		len = pcur_bss->Ssid.SsidLength;
-
-		wrqu->essid.length = len;
-
 		memcpy(extra, pcur_bss->Ssid.Ssid, len);
-
-		wrqu->essid.flags = 1;
 	} else {
-		ret = -1;
-		goto exit;
+		len = 0;
+		*extra = 0;
 	}
-
-exit:
-
+	wrqu->essid.length = len;
+	wrqu->essid.flags = 1;
 
 	return ret;
 }
@@ -2060,7 +2056,7 @@
 	struct ieee_param *param;
 	uint ret = 0;
 
-	if (p->length < sizeof(struct ieee_param) || !p->pointer) {
+	if (!p->pointer || p->length != sizeof(struct ieee_param)) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -2865,7 +2861,7 @@
 		goto out;
 	}
 
-	if (!p->pointer) {
+	if (!p->pointer || p->length != sizeof(struct ieee_param)) {
 		ret = -EINVAL;
 		goto out;
 	}
--- linux-4.4.0.orig/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ linux-4.4.0/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -44,10 +44,17 @@
 	/****** 8188EUS ********/
 	{USB_DEVICE(0x056e, 0x4008)}, /* Elecom WDC-150SU2M */
 	{USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
+	{USB_DEVICE(0x0B05, 0x18F0)}, /* ASUS USB-N10 Nano B1 */
 	{USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
 	{USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
 	{USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */
+	{USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */
+	{USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */
+	{USB_DEVICE(0x2357, 0x0111)}, /* TP-Link TL-WN727N v5.21 */
+	{USB_DEVICE(0x2C4E, 0x0102)}, /* MERCUSYS MW150US v2 */
 	{USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
+	{USB_DEVICE(0x7392, 0xb811)}, /* Edimax EW-7811UN V2 */
+	{USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */
 	{}	/* Terminating entry */
 };
 
@@ -79,7 +86,7 @@
 	phost_conf = pusbd->actconfig;
 	pconf_desc = &phost_conf->desc;
 
-	phost_iface = &usb_intf->altsetting[0];
+	phost_iface = usb_intf->cur_altsetting;
 	piface_desc = &phost_iface->desc;
 
 	pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces;
--- linux-4.4.0.orig/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
+++ linux-4.4.0/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
@@ -97,8 +97,9 @@
 
 	switch (variable) {
 	case HW_VAR_BSSID:
-		rtl92e_writel(dev, BSSIDR, ((u32 *)(val))[0]);
-		rtl92e_writew(dev, BSSIDR+2, ((u16 *)(val+2))[0]);
+		/* BSSIDR 2 byte alignment */
+		rtl92e_writew(dev, BSSIDR, *(u16 *)val);
+		rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(val + 2));
 		break;
 
 	case HW_VAR_MEDIA_STATUS:
@@ -626,7 +627,7 @@
 	struct r8192_priv *priv = rtllib_priv(dev);
 
 	RT_TRACE(COMP_INIT, "===========>%s()\n", __func__);
-	curCR = rtl92e_readl(dev, EPROM_CMD);
+	curCR = rtl92e_readw(dev, EPROM_CMD);
 	RT_TRACE(COMP_INIT, "read from Reg Cmd9346CR(%x):%x\n", EPROM_CMD,
 		 curCR);
 	priv->epromtype = (curCR & EPROM_CMD_9356SEL) ? EEPROM_93C56 :
@@ -963,8 +964,8 @@
 	rtl92e_config_rate(dev, &rate_config);
 	priv->dot11CurrentPreambleMode = PREAMBLE_AUTO;
 	 priv->basic_rate = rate_config &= 0x15f;
-	rtl92e_writel(dev, BSSIDR, ((u32 *)net->bssid)[0]);
-	rtl92e_writew(dev, BSSIDR+4, ((u16 *)net->bssid)[2]);
+	rtl92e_writew(dev, BSSIDR, *(u16 *)net->bssid);
+	rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(net->bssid + 2));
 
 	if (priv->rtllib->iw_mode == IW_MODE_ADHOC) {
 		rtl92e_writew(dev, ATIMWND, 2);
@@ -1184,8 +1185,7 @@
 			  struct cb_desc *cb_desc, struct sk_buff *skb)
 {
 	struct r8192_priv *priv = rtllib_priv(dev);
-	dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len,
-			 PCI_DMA_TODEVICE);
+	dma_addr_t mapping;
 	struct tx_fwinfo_8190pci *pTxFwInfo = NULL;
 
 	pTxFwInfo = (struct tx_fwinfo_8190pci *)skb->data;
@@ -1196,8 +1196,6 @@
 	pTxFwInfo->Short = _rtl92e_query_is_short(pTxFwInfo->TxHT,
 						  pTxFwInfo->TxRate, cb_desc);
 
-	if (pci_dma_mapping_error(priv->pdev, mapping))
-		netdev_err(dev, "%s(): DMA Mapping error\n", __func__);
 	if (cb_desc->bAMPDUEnable) {
 		pTxFwInfo->AllowAggregation = 1;
 		pTxFwInfo->RxMF = cb_desc->ampdu_factor;
@@ -1232,6 +1230,14 @@
 	}
 
 	memset((u8 *)pdesc, 0, 12);
+
+	mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+				 PCI_DMA_TODEVICE);
+	if (pci_dma_mapping_error(priv->pdev, mapping)) {
+		netdev_err(dev, "%s(): DMA Mapping error\n", __func__);
+		return;
+	}
+
 	pdesc->LINIP = 0;
 	pdesc->CmdInit = 1;
 	pdesc->Offset = sizeof(struct tx_fwinfo_8190pci) + 8;
--- linux-4.4.0.orig/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ linux-4.4.0/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -1631,14 +1631,15 @@
 	memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
 	skb_push(skb, priv->rtllib->tx_headroom);
 	ret = _rtl92e_tx(dev, skb);
-	if (ret != 0)
-		kfree_skb(skb);
 
 	if (queue_index != MGNT_QUEUE) {
 		priv->rtllib->stats.tx_bytes += (skb->len -
 						 priv->rtllib->tx_headroom);
 		priv->rtllib->stats.tx_packets++;
 	}
+
+	if (ret != 0)
+		kfree_skb(skb);
 }
 
 static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -2711,13 +2712,14 @@
 			free_irq(dev->irq, dev);
 			priv->irq = 0;
 		}
-		free_rtllib(dev);
 
 		if (dev->mem_start != 0) {
 			iounmap((void __iomem *)dev->mem_start);
 			release_mem_region(pci_resource_start(pdev, 1),
 					pci_resource_len(pdev, 1));
 		}
+
+		free_rtllib(dev);
 	} else {
 		priv = rtllib_priv(dev);
 	}
--- linux-4.4.0.orig/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ linux-4.4.0/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
@@ -419,9 +419,10 @@
 		struct iw_scan_req *req = (struct iw_scan_req *)b;
 
 		if (req->essid_len) {
-			ieee->current_network.ssid_len = req->essid_len;
-			memcpy(ieee->current_network.ssid, req->essid,
-			       req->essid_len);
+			int len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE);
+
+			ieee->current_network.ssid_len = len;
+			memcpy(ieee->current_network.ssid, req->essid, len);
 		}
 	}
 
--- linux-4.4.0.orig/drivers/staging/rtl8192u/r8192U_core.c
+++ linux-4.4.0/drivers/staging/rtl8192u/r8192U_core.c
@@ -1050,7 +1050,7 @@
 
 	spin_lock_irqsave(&priv->tx_lock, flags);
 
-	memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
+	*(struct net_device **)(skb->cb) = dev;
 	tcb_desc->bTxEnableFwCalcDur = 1;
 	skb_push(skb, priv->ieee80211->tx_headroom);
 	ret = rtl8192_tx(dev, skb);
@@ -1092,7 +1092,7 @@
 static void rtl8192_tx_isr(struct urb *tx_urb)
 {
 	struct sk_buff *skb = (struct sk_buff *)tx_urb->context;
-	struct net_device *dev = (struct net_device *)(skb->cb);
+	struct net_device *dev = *(struct net_device **)(skb->cb);
 	struct r8192_priv *priv = NULL;
 	cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
 	u8  queue_index = tcb_desc->queue_index;
@@ -1749,6 +1749,8 @@
 
 		priv->rx_urb[16] = usb_alloc_urb(0, GFP_KERNEL);
 		priv->oldaddr = kmalloc(16, GFP_KERNEL);
+		if (!priv->oldaddr)
+			return -ENOMEM;
 		oldaddr = priv->oldaddr;
 		align = ((long)oldaddr) & 3;
 		if (align) {
--- linux-4.4.0.orig/drivers/staging/rtl8192u/r8192U_wx.c
+++ linux-4.4.0/drivers/staging/rtl8192u/r8192U_wx.c
@@ -341,8 +341,10 @@
 		struct iw_scan_req *req = (struct iw_scan_req *)b;
 
 		if (req->essid_len) {
-			ieee->current_network.ssid_len = req->essid_len;
-			memcpy(ieee->current_network.ssid, req->essid, req->essid_len);
+			int len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE);
+
+			ieee->current_network.ssid_len = len;
+			memcpy(ieee->current_network.ssid, req->essid, len);
 		}
 	}
 
--- linux-4.4.0.orig/drivers/staging/rtl8712/ieee80211.h
+++ linux-4.4.0/drivers/staging/rtl8712/ieee80211.h
@@ -143,52 +143,52 @@
 };
 
 struct ieee80211_hdr {
-	u16 frame_ctl;
-	u16 duration_id;
+	__le16 frame_ctl;
+	__le16 duration_id;
 	u8 addr1[ETH_ALEN];
 	u8 addr2[ETH_ALEN];
 	u8 addr3[ETH_ALEN];
-	u16 seq_ctl;
+	__le16 seq_ctl;
 	u8 addr4[ETH_ALEN];
-} __packed;
+}  __packed __aligned(2);
 
 struct ieee80211_hdr_3addr {
-	u16 frame_ctl;
-	u16 duration_id;
+	__le16 frame_ctl;
+	__le16 duration_id;
 	u8 addr1[ETH_ALEN];
 	u8 addr2[ETH_ALEN];
 	u8 addr3[ETH_ALEN];
-	u16 seq_ctl;
-} __packed;
+	__le16 seq_ctl;
+}  __packed __aligned(2);
 
 
 struct	ieee80211_hdr_qos {
-	u16 frame_ctl;
-	u16 duration_id;
+	__le16 frame_ctl;
+	__le16 duration_id;
 	u8 addr1[ETH_ALEN];
 	u8 addr2[ETH_ALEN];
 	u8 addr3[ETH_ALEN];
-	u16 seq_ctl;
+	__le16 seq_ctl;
 	u8 addr4[ETH_ALEN];
-	u16	qc;
-}  __packed;
+	__le16	qc;
+}   __packed __aligned(2);
 
 struct  ieee80211_hdr_3addr_qos {
-	u16 frame_ctl;
-	u16 duration_id;
+	__le16 frame_ctl;
+	__le16 duration_id;
 	u8  addr1[ETH_ALEN];
 	u8  addr2[ETH_ALEN];
 	u8  addr3[ETH_ALEN];
-	u16 seq_ctl;
-	u16 qc;
+	__le16 seq_ctl;
+	__le16 qc;
 }  __packed;
 
 struct eapol {
 	u8 snap[6];
-	u16 ethertype;
+	__be16 ethertype;
 	u8 version;
 	u8 type;
-	u16 length;
+	__le16 length;
 } __packed;
 
 
@@ -528,13 +528,13 @@
  */
 
 struct ieee80211_header_data {
-	u16 frame_ctl;
-	u16 duration_id;
+	__le16 frame_ctl;
+	__le16 duration_id;
 	u8 addr1[6];
 	u8 addr2[6];
 	u8 addr3[6];
-	u16 seq_ctrl;
-};
+	__le16 seq_ctrl;
+} __packed __aligned(2);
 
 #define BEACON_PROBE_SSID_ID_POSITION 12
 
@@ -566,18 +566,18 @@
 /*
  * These are the data types that can make up management packets
  *
-	u16 auth_algorithm;
-	u16 auth_sequence;
-	u16 beacon_interval;
-	u16 capability;
+	__le16 auth_algorithm;
+	__le16 auth_sequence;
+	__le16 beacon_interval;
+	__le16 capability;
 	u8 current_ap[ETH_ALEN];
-	u16 listen_interval;
+	__le16 listen_interval;
 	struct {
 		u16 association_id:14, reserved:2;
 	} __packed;
-	u32 time_stamp[2];
-	u16 reason;
-	u16 status;
+	__le32 time_stamp[2];
+	__le16 reason;
+	__le16 status;
 */
 
 #define IEEE80211_DEFAULT_TX_ESSID "Penguin"
@@ -585,16 +585,16 @@
 
 struct ieee80211_authentication {
 	struct ieee80211_header_data header;
-	u16 algorithm;
-	u16 transaction;
-	u16 status;
+	__le16 algorithm;
+	__le16 transaction;
+	__le16 status;
 } __packed;
 
 struct ieee80211_probe_response {
 	struct ieee80211_header_data header;
-	u32 time_stamp[2];
-	u16 beacon_interval;
-	u16 capability;
+	__le32 time_stamp[2];
+	__le16 beacon_interval;
+	__le16 capability;
 	struct ieee80211_info_element info_element;
 } __packed;
 
@@ -604,16 +604,16 @@
 
 struct ieee80211_assoc_request_frame {
 	struct ieee80211_hdr_3addr header;
-	u16 capability;
-	u16 listen_interval;
+	__le16 capability;
+	__le16 listen_interval;
 	struct ieee80211_info_element_hdr info_element;
 } __packed;
 
 struct ieee80211_assoc_response_frame {
 	struct ieee80211_hdr_3addr header;
-	u16 capability;
-	u16 status;
-	u16 aid;
+	__le16 capability;
+	__le16 status;
+	__le16 aid;
 } __packed;
 
 struct ieee80211_txb {
--- linux-4.4.0.orig/drivers/staging/rtl8712/rtl8712_cmd.c
+++ linux-4.4.0/drivers/staging/rtl8712/rtl8712_cmd.c
@@ -128,34 +128,6 @@
 	kfree(pdrvcmd->pbuf);
 }
 
-static u8 read_macreg_hdl(struct _adapter *padapter, u8 *pbuf)
-{
-	void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj	*pcmd);
-	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
-
-	/*  invoke cmd->callback function */
-	pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
-	if (pcmd_callback == NULL)
-		r8712_free_cmd_obj(pcmd);
-	else
-		pcmd_callback(padapter, pcmd);
-	return H2C_SUCCESS;
-}
-
-static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf)
-{
-	void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj	*pcmd);
-	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
-
-	/*  invoke cmd->callback function */
-	pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
-	if (pcmd_callback == NULL)
-		r8712_free_cmd_obj(pcmd);
-	else
-		pcmd_callback(padapter, pcmd);
-	return H2C_SUCCESS;
-}
-
 static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf)
 {
 	u32 val;
@@ -232,14 +204,6 @@
 	pcmd_r = NULL;
 
 	switch (pcmd->cmdcode) {
-	case GEN_CMD_CODE(_Read_MACREG):
-		read_macreg_hdl(padapter, (u8 *)pcmd);
-		pcmd_r = pcmd;
-		break;
-	case GEN_CMD_CODE(_Write_MACREG):
-		write_macreg_hdl(padapter, (u8 *)pcmd);
-		pcmd_r = pcmd;
-		break;
 	case GEN_CMD_CODE(_Read_BBREG):
 		read_bbreg_hdl(padapter, (u8 *)pcmd);
 		break;
--- linux-4.4.0.orig/drivers/staging/rtl8712/rtl871x_cmd.c
+++ linux-4.4.0/drivers/staging/rtl8712/rtl871x_cmd.c
@@ -242,8 +242,10 @@
 	psurveyPara->ss_ssidlen = 0;
 	memset(psurveyPara->ss_ssid, 0, IW_ESSID_MAX_SIZE + 1);
 	if ((pssid != NULL) && (pssid->SsidLength)) {
-		memcpy(psurveyPara->ss_ssid, pssid->Ssid, pssid->SsidLength);
-		psurveyPara->ss_ssidlen = cpu_to_le32(pssid->SsidLength);
+		int len = min_t(int, pssid->SsidLength, IW_ESSID_MAX_SIZE);
+
+		memcpy(psurveyPara->ss_ssid, pssid->Ssid, len);
+		psurveyPara->ss_ssidlen = cpu_to_le32(len);
 	}
 	set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
 	r8712_enqueue_cmd(pcmdpriv, ph2c);
--- linux-4.4.0.orig/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ linux-4.4.0/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -199,7 +199,7 @@
 	iwe.cmd = SIOCGIWMODE;
 	memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs),
 		2);
-	cap = le16_to_cpu(cap);
+	le16_to_cpus(&cap);
 	if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) {
 		if (cap & WLAN_CAPABILITY_BSS)
 			iwe.u.mode = (u32)IW_MODE_MASTER;
@@ -935,7 +935,7 @@
 	struct iw_point *dwrq = (struct iw_point *)awrq;
 
 	len = dwrq->length;
-	ext = memdup_user(dwrq->pointer, len);
+	ext = strndup_user(dwrq->pointer, len);
 	if (IS_ERR(ext))
 		return PTR_ERR(ext);
 
--- linux-4.4.0.orig/drivers/staging/rtl8712/rtl871x_recv.c
+++ linux-4.4.0/drivers/staging/rtl8712/rtl871x_recv.c
@@ -641,11 +641,16 @@
 		/* append rx status for mp test packets */
 		ptr = recvframe_pull(precvframe, (rmv_len -
 		      sizeof(struct ethhdr) + 2) - 24);
+		if (!ptr)
+			return _FAIL;
 		memcpy(ptr, get_rxmem(precvframe), 24);
 		ptr += 24;
-	} else
+	} else {
 		ptr = recvframe_pull(precvframe, (rmv_len -
 		      sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
+		if (!ptr)
+			return _FAIL;
+	}
 
 	memcpy(ptr, pattrib->dst, ETH_ALEN);
 	memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN);
--- linux-4.4.0.orig/drivers/staging/rtl8712/rtl871x_xmit.c
+++ linux-4.4.0/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -339,7 +339,8 @@
 	/* if in MP_STATE, update pkt_attrib from mp_txcmd, and overwrite
 	 * some settings above.*/
 	if (check_fwstate(pmlmepriv, WIFI_MP_STATE))
-		pattrib->priority = (txdesc.txdw1 >> QSEL_SHT) & 0x1f;
+		pattrib->priority =
+		    (le32_to_cpu(txdesc.txdw1) >> QSEL_SHT) & 0x1f;
 	return _SUCCESS;
 }
 
@@ -479,7 +480,7 @@
 	struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr;
 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 	struct qos_priv *pqospriv = &pmlmepriv->qospriv;
-	u16 *fctrl = &pwlanhdr->frame_ctl;
+	__le16 *fctrl = &pwlanhdr->frame_ctl;
 
 	memset(hdr, 0, WLANHDR_OFFSET);
 	SetFrameSubType(fctrl, pattrib->subtype);
@@ -568,7 +569,7 @@
 	snap->oui[0] = oui[0];
 	snap->oui[1] = oui[1];
 	snap->oui[2] = oui[2];
-	*(u16 *)(data + SNAP_SIZE) = htons(h_proto);
+	*(__be16 *)(data + SNAP_SIZE) = htons(h_proto);
 	return SNAP_SIZE + sizeof(u16);
 }
 
--- linux-4.4.0.orig/drivers/staging/rtl8712/usb_intf.c
+++ linux-4.4.0/drivers/staging/rtl8712/usb_intf.c
@@ -263,7 +263,7 @@
 
 	pdvobjpriv->padapter = padapter;
 	padapter->EepromAddressSize = 6;
-	phost_iface = &pintf->altsetting[0];
+	phost_iface = pintf->cur_altsetting;
 	piface_desc = &phost_iface->desc;
 	pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
 	if (pusbd->speed == USB_SPEED_HIGH) {
--- linux-4.4.0.orig/drivers/staging/rtl8712/wifi.h
+++ linux-4.4.0/drivers/staging/rtl8712/wifi.h
@@ -466,7 +466,7 @@
 /* block-ack parameters */
 #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
 #define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
-#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
 #define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
 #define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
 
@@ -560,13 +560,6 @@
 #define IEEE80211_HT_IE_NON_GF_STA_PRSNT	0x0004
 #define IEEE80211_HT_IE_NON_HT_STA_PRSNT	0x0010
 
-/* block-ack parameters */
-#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
-#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
-#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
-#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
-#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
-
 /*
  * A-PMDU buffer sizes
  * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
--- linux-4.4.0.orig/drivers/staging/rts5208/rtsx_scsi.c
+++ linux-4.4.0/drivers/staging/rts5208/rtsx_scsi.c
@@ -414,7 +414,7 @@
 	sense->ascq = ascq;
 	if (sns_key_info0 != 0) {
 		sense->sns_key_info[0] = SKSV | sns_key_info0;
-		sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 8;
+		sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 4;
 		sense->sns_key_info[2] = sns_key_info1 & 0x0f;
 	}
 }
@@ -536,7 +536,7 @@
 
 	if (sendbytes > 8) {
 		memcpy(buf, inquiry_buf, 8);
-		memcpy(buf + 8, inquiry_string,	sendbytes - 8);
+		strncpy(buf + 8, inquiry_string, sendbytes - 8);
 		if (pro_formatter_flag) {
 			/* Additional Length */
 			buf[4] = 0x33;
--- linux-4.4.0.orig/drivers/staging/rts5208/sd.c
+++ linux-4.4.0/drivers/staging/rts5208/sd.c
@@ -4165,12 +4165,6 @@
 					rtsx_trace(chip);
 					return STATUS_FAIL;
 				}
-
-			} else if (rsp_type == SD_RSP_TYPE_R0) {
-				if ((ptr[3] & 0x1E) != 0x03) {
-					rtsx_trace(chip);
-					return STATUS_FAIL;
-				}
 			}
 		}
 	}
@@ -5031,7 +5025,7 @@
 			goto SD_Execute_Write_Cmd_Failed;
 		}
 
-		rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00);
+		retval = rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00);
 		if (retval != STATUS_SUCCESS) {
 			rtsx_trace(chip);
 			goto SD_Execute_Write_Cmd_Failed;
--- linux-4.4.0.orig/drivers/staging/rts5208/xd.c
+++ linux-4.4.0/drivers/staging/rts5208/xd.c
@@ -1252,7 +1252,7 @@
 			reg = 0;
 			rtsx_read_register(chip, XD_CTL, &reg);
 			if (reg & (XD_ECC1_ERROR | XD_ECC2_ERROR)) {
-				wait_timeout(100);
+				mdelay(100);
 
 				if (detect_card_cd(chip,
 					XD_CARD) != STATUS_SUCCESS) {
--- linux-4.4.0.orig/drivers/staging/signature-inclusion
+++ linux-4.4.0/drivers/staging/signature-inclusion
@@ -0,0 +1,18 @@
+#
+# This file lists the staging drivers that are safe for signing
+# and loading in a secure boot environment with signed module enforcement.
+#
+rtl8192c-common.ko
+rtl8192ce.ko
+rtl8192cu.ko
+rtl8192de.ko
+rtl8192ee.ko
+rtl8192se.ko
+r8188eu.ko
+r8192e_pci.ko
+r8192u_usb.ko
+r8712u.ko
+rtllib_crypt_ccmp.ko
+rtllib_crypt_tkip.ko
+rtllib_crypt_wep.ko
+rtllib.ko
--- linux-4.4.0.orig/drivers/staging/sm750fb/sm750.c
+++ linux-4.4.0/drivers/staging/sm750fb/sm750.c
@@ -894,6 +894,7 @@
 		fix->visual = FB_VISUAL_PSEUDOCOLOR;
 		break;
 	case 16:
+	case 24:
 	case 32:
 		fix->visual = FB_VISUAL_TRUECOLOR;
 		break;
--- linux-4.4.0.orig/drivers/staging/speakup/kobjects.c
+++ linux-4.4.0/drivers/staging/speakup/kobjects.c
@@ -387,7 +387,7 @@
 	len = strlen(buf);
 	if (len < 2 || len > 9)
 		return -EINVAL;
-	strncpy(new_synth_name, buf, len);
+	memcpy(new_synth_name, buf, len);
 	if (new_synth_name[len - 1] == '\n')
 		len--;
 	new_synth_name[len] = '\0';
@@ -514,7 +514,7 @@
 		return -EINVAL;
 	}
 
-	strncpy(punc_buf, buf, x);
+	memcpy(punc_buf, buf, x);
 
 	while (x && punc_buf[x - 1] == '\n')
 		x--;
@@ -831,7 +831,9 @@
 	struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
 	unsigned long flags;
 
-	BUG_ON(!group);
+	if (WARN_ON(!group))
+		return -EINVAL;
+
 	spin_lock_irqsave(&speakup_info.spinlock, flags);
 	retval = message_show_helper(buf, group->start, group->end);
 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
@@ -843,7 +845,9 @@
 {
 	struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
 
-	BUG_ON(!group);
+	if (WARN_ON(!group))
+		return -EINVAL;
+
 	return message_store_helper(buf, count, group);
 }
 
--- linux-4.4.0.orig/drivers/staging/speakup/main.c
+++ linux-4.4.0/drivers/staging/speakup/main.c
@@ -562,8 +562,7 @@
 		return 0;
 	} else if ((tmpx < vc->vc_cols - 2)
 		   && (ch == SPACE || ch == 0 || IS_WDLM(ch))
-		   && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
-		       SPACE)) {
+		   && ((char)get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE)) {
 		tmp_pos += 2;
 		tmpx++;
 	} else
--- linux-4.4.0.orig/drivers/staging/speakup/selection.c
+++ linux-4.4.0/drivers/staging/speakup/selection.c
@@ -142,7 +142,9 @@
 	struct tty_ldisc *ld;
 	DECLARE_WAITQUEUE(wait, current);
 
-	ld = tty_ldisc_ref_wait(tty);
+	ld = tty_ldisc_ref(tty);
+	if (!ld)
+		goto tty_unref;
 	tty_buffer_lock_exclusive(&vc->port);
 
 	add_wait_queue(&vc->paste_wait, &wait);
@@ -162,6 +164,7 @@
 
 	tty_buffer_unlock_exclusive(&vc->port);
 	tty_ldisc_deref(ld);
+tty_unref:
 	tty_kref_put(tty);
 }
 
--- linux-4.4.0.orig/drivers/staging/speakup/serialio.c
+++ linux-4.4.0/drivers/staging/speakup/serialio.c
@@ -6,6 +6,11 @@
 #include "spk_priv.h"
 #include "serialio.h"
 
+#include <linux/serial_core.h>
+/* WARNING:  Do not change this to <linux/serial.h> without testing that
+ * SERIAL_PORT_DFNS does get defined to the appropriate value. */
+#include <asm/serial.h>
+
 #ifndef SERIAL_PORT_DFNS
 #define SERIAL_PORT_DFNS
 #endif
@@ -23,9 +28,15 @@
 	int baud = 9600, quot = 0;
 	unsigned int cval = 0;
 	int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
-	const struct old_serial_port *ser = rs_table + index;
+	const struct old_serial_port *ser;
 	int err;
 
+	if (index >= ARRAY_SIZE(rs_table)) {
+		pr_info("no port info for ttyS%d\n", index);
+		return NULL;
+	}
+	ser = rs_table + index;
+
 	/*	Divisor, bytesize and parity */
 	quot = ser->baud_base / baud;
 	cval = cflag & (CSIZE | CSTOPB);
--- linux-4.4.0.orig/drivers/staging/speakup/speakup_acntpc.c
+++ linux-4.4.0/drivers/staging/speakup/speakup_acntpc.c
@@ -312,7 +312,7 @@
 	speakup_info.port_tts = 0;
 }
 
-module_param_named(port, port_forced, int, S_IRUGO);
+module_param_hw_named(port, port_forced, int, ioport, S_IRUGO);
 module_param_named(start, synth_acntpc.startup, short, S_IRUGO);
 
 MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
--- linux-4.4.0.orig/drivers/staging/speakup/speakup_dectlk.c
+++ linux-4.4.0/drivers/staging/speakup/speakup_dectlk.c
@@ -51,7 +51,7 @@
 static int in_escape;
 static int is_flushing;
 
-static spinlock_t flush_lock;
+static DEFINE_SPINLOCK(flush_lock);
 static DECLARE_WAIT_QUEUE_HEAD(flush);
 
 static struct var_t vars[] = {
--- linux-4.4.0.orig/drivers/staging/speakup/speakup_dtlk.c
+++ linux-4.4.0/drivers/staging/speakup/speakup_dtlk.c
@@ -382,7 +382,7 @@
 	speakup_info.port_tts = 0;
 }
 
-module_param_named(port, port_forced, int, S_IRUGO);
+module_param_hw_named(port, port_forced, int, ioport, S_IRUGO);
 module_param_named(start, synth_dtlk.startup, short, S_IRUGO);
 
 MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
--- linux-4.4.0.orig/drivers/staging/speakup/speakup_keypc.c
+++ linux-4.4.0/drivers/staging/speakup/speakup_keypc.c
@@ -313,7 +313,7 @@
 	synth_port = 0;
 }
 
-module_param_named(port, port_forced, int, S_IRUGO);
+module_param_hw_named(port, port_forced, int, ioport, S_IRUGO);
 module_param_named(start, synth_keypc.startup, short, S_IRUGO);
 
 MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
--- linux-4.4.0.orig/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
+++ linux-4.4.0/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
@@ -1039,7 +1039,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
 /**
  * synaptics_rmi4_suspend() - suspend the touch screen controller
  * @dev: pointer to device structure
@@ -1047,7 +1046,7 @@
  * This function is used to suspend the
  * touch panel controller and returns integer
  */
-static int synaptics_rmi4_suspend(struct device *dev)
+static int __maybe_unused synaptics_rmi4_suspend(struct device *dev)
 {
 	/* Touch sleep mode */
 	int retval;
@@ -1081,7 +1080,7 @@
  * This function is used to resume the touch panel
  * controller and returns integer.
  */
-static int synaptics_rmi4_resume(struct device *dev)
+static int __maybe_unused synaptics_rmi4_resume(struct device *dev)
 {
 	int retval;
 	unsigned char intr_status;
@@ -1112,8 +1111,6 @@
 	return 0;
 }
 
-#endif
-
 static SIMPLE_DEV_PM_OPS(synaptics_rmi4_dev_pm_ops, synaptics_rmi4_suspend,
 			 synaptics_rmi4_resume);
 
--- linux-4.4.0.orig/drivers/staging/unisys/visorhba/visorhba_main.c
+++ linux-4.4.0/drivers/staging/unisys/visorhba/visorhba_main.c
@@ -792,7 +792,7 @@
 do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
 {
 	struct scsi_device *scsidev;
-	unsigned char buf[36];
+	unsigned char *buf;
 	struct scatterlist *sg;
 	unsigned int i;
 	char *this_page;
@@ -807,6 +807,10 @@
 		if (cmdrsp->scsi.no_disk_result == 0)
 			return;
 
+		buf = kzalloc(sizeof(char) * 36, GFP_KERNEL);
+		if (!buf)
+			return;
+
 		/* Linux scsi code wants a device at Lun 0
 		 * to issue report luns, but we don't want
 		 * a disk there so we'll present a processor
@@ -820,6 +824,7 @@
 		if (scsi_sg_count(scsicmd) == 0) {
 			memcpy(scsi_sglist(scsicmd), buf,
 			       cmdrsp->scsi.bufflen);
+			kfree(buf);
 			return;
 		}
 
@@ -831,6 +836,7 @@
 			memcpy(this_page, buf + bufind, sg[i].length);
 			kunmap_atomic(this_page_orig);
 		}
+		kfree(buf);
 	} else {
 		devdata = (struct visorhba_devdata *)scsidev->host->hostdata;
 		for_each_vdisk_match(vdisk, devdata, scsidev) {
--- linux-4.4.0.orig/drivers/staging/unisys/visorinput/Kconfig
+++ linux-4.4.0/drivers/staging/unisys/visorinput/Kconfig
@@ -4,7 +4,7 @@
 
 config UNISYS_VISORINPUT
 	tristate "Unisys visorinput driver"
-	depends on UNISYSSPAR && UNISYS_VISORBUS && FB
+	depends on UNISYSSPAR && UNISYS_VISORBUS && FB && INPUT
 	---help---
 	If you say Y here, you will enable the Unisys visorinput driver.
 
--- linux-4.4.0.orig/drivers/staging/vme/devices/vme_pio2_core.c
+++ linux-4.4.0/drivers/staging/vme/devices/vme_pio2_core.c
@@ -478,16 +478,16 @@
 
 /* These are required for each board */
 MODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the board is connected");
-module_param_array(bus, int, &bus_num, S_IRUGO);
+module_param_hw_array(bus, int, other, &bus_num, S_IRUGO);
 
 MODULE_PARM_DESC(base, "Base VME address for PIO2 Registers");
-module_param_array(base, long, &base_num, S_IRUGO);
+module_param_hw_array(base, long, other, &base_num, S_IRUGO);
 
 MODULE_PARM_DESC(vector, "VME IRQ Vector (Lower 4 bits masked)");
-module_param_array(vector, int, &vector_num, S_IRUGO);
+module_param_hw_array(vector, int, other, &vector_num, S_IRUGO);
 
 MODULE_PARM_DESC(level, "VME IRQ Level");
-module_param_array(level, int, &level_num, S_IRUGO);
+module_param_hw_array(level, int, other, &level_num, S_IRUGO);
 
 MODULE_PARM_DESC(variant, "Last 4 characters of PIO2 board variant");
 module_param_array(variant, charp, &variant_num, S_IRUGO);
--- linux-4.4.0.orig/drivers/staging/vt6655/device_main.c
+++ linux-4.4.0/drivers/staging/vt6655/device_main.c
@@ -972,8 +972,6 @@
 		return;
 	}
 
-	MACvIntDisable(priv->PortOffset);
-
 	spin_lock_irqsave(&priv->lock, flags);
 
 	/* Read low level stats */
@@ -1062,8 +1060,6 @@
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
-
-	MACvIntEnable(priv->PortOffset, IMR_MASK_VALUE);
 }
 
 static void vnt_interrupt_work(struct work_struct *work)
@@ -1073,14 +1069,17 @@
 
 	if (priv->vif)
 		vnt_interrupt_process(priv);
+
+	MACvIntEnable(priv->PortOffset, IMR_MASK_VALUE);
 }
 
 static irqreturn_t vnt_interrupt(int irq,  void *arg)
 {
 	struct vnt_private *priv = arg;
 
-	if (priv->vif)
-		schedule_work(&priv->interrupt_work);
+	schedule_work(&priv->interrupt_work);
+
+	MACvIntDisable(priv->PortOffset);
 
 	return IRQ_HANDLED;
 }
@@ -1669,8 +1668,10 @@
 
 	priv->hw->max_signal = 100;
 
-	if (vnt_init(priv))
+	if (vnt_init(priv)) {
+		device_free_info(priv);
 		return -ENODEV;
+	}
 
 	device_print_info(priv);
 	pci_set_drvdata(pcid, priv);
@@ -1693,10 +1694,11 @@
 	MACbShutdown(priv->PortOffset);
 
 	pci_disable_device(pcid);
-	pci_set_power_state(pcid, pci_choose_state(pcid, state));
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
+	pci_set_power_state(pcid, pci_choose_state(pcid, state));
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/staging/vt6656/device.h
+++ linux-4.4.0/drivers/staging/vt6656/device.h
@@ -65,6 +65,8 @@
 #define RATE_AUTO	12
 
 #define MAX_RATE			12
+#define VNT_B_RATES	(BIT(RATE_1M) | BIT(RATE_2M) |\
+			BIT(RATE_5M) | BIT(RATE_11M))
 
 /*
  * device specific
@@ -272,6 +274,7 @@
 	u8 mac_hw;
 	/* netdev */
 	struct usb_device *usb;
+	struct usb_interface *intf;
 
 	u64 tsf_time;
 	u8 rx_rate;
--- linux-4.4.0.orig/drivers/staging/vt6656/dpc.c
+++ linux-4.4.0/drivers/staging/vt6656/dpc.c
@@ -144,7 +144,7 @@
 
 	vnt_rf_rssi_to_dbm(priv, *rssi, &rx_dbm);
 
-	priv->bb_pre_ed_rssi = (u8)rx_dbm + 1;
+	priv->bb_pre_ed_rssi = (u8)-rx_dbm + 1;
 	priv->current_rssi = priv->bb_pre_ed_rssi;
 
 	frame = skb_data + 8;
--- linux-4.4.0.orig/drivers/staging/vt6656/int.c
+++ linux-4.4.0/drivers/staging/vt6656/int.c
@@ -111,9 +111,11 @@
 
 	info->status.rates[0].count = tx_retry;
 
-	if (!(tsr & (TSR_TMO | TSR_RETRYTMO))) {
+	if (!(tsr & TSR_TMO)) {
 		info->status.rates[0].idx = idx;
-		info->flags |= IEEE80211_TX_STAT_ACK;
+
+		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+			info->flags |= IEEE80211_TX_STAT_ACK;
 	}
 
 	ieee80211_tx_status_irqsafe(priv->hw, context->skb);
@@ -155,7 +157,8 @@
 				priv->wake_up_count =
 					priv->hw->conf.listen_interval;
 
-			--priv->wake_up_count;
+			if (priv->wake_up_count)
+				--priv->wake_up_count;
 
 			/* Turn on wake up to listen next beacon */
 			if (priv->wake_up_count == 1)
--- linux-4.4.0.orig/drivers/staging/vt6656/main_usb.c
+++ linux-4.4.0/drivers/staging/vt6656/main_usb.c
@@ -529,6 +529,9 @@
 		goto free_all;
 	}
 
+	if (vnt_key_init_table(priv))
+		goto free_all;
+
 	priv->int_interval = 1;  /* bInterval is set to 1 */
 
 	vnt_int_start_interrupt(priv);
@@ -759,12 +762,15 @@
 			vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL,
 					    TFTCTL_TSFCNTREN);
 
-			vnt_adjust_tsf(priv, conf->beacon_rate->hw_value,
-				       conf->sync_tsf, priv->current_tsf);
-
 			vnt_mac_set_beacon_interval(priv, conf->beacon_int);
 
 			vnt_reset_next_tbtt(priv, conf->beacon_int);
+
+			vnt_adjust_tsf(priv, conf->beacon_rate->hw_value,
+				       conf->sync_tsf, priv->current_tsf);
+
+			vnt_update_next_tbtt(priv,
+					     conf->sync_tsf, conf->beacon_int);
 		} else {
 			vnt_clear_current_tsf(priv);
 
@@ -976,6 +982,7 @@
 	priv = hw->priv;
 	priv->hw = hw;
 	priv->usb = udev;
+	priv->intf = intf;
 
 	vnt_set_options(priv);
 
@@ -998,6 +1005,7 @@
 	ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
 	ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS);
 	ieee80211_hw_set(priv->hw, SUPPORTS_PS);
+	ieee80211_hw_set(priv->hw, PS_NULLFUNC_STACK);
 
 	priv->hw->max_signal = 100;
 
--- linux-4.4.0.orig/drivers/staging/vt6656/rxtx.c
+++ linux-4.4.0/drivers/staging/vt6656/rxtx.c
@@ -280,11 +280,9 @@
 							PK_TYPE_11B, &buf->b);
 
 	/* Get Duration and TimeStamp */
-	if (ieee80211_is_pspoll(hdr->frame_control)) {
-		__le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15));
-
-		buf->duration_a = dur;
-		buf->duration_b = dur;
+	if (ieee80211_is_nullfunc(hdr->frame_control)) {
+		buf->duration_a = hdr->duration_id;
+		buf->duration_b = hdr->duration_id;
 	} else {
 		buf->duration_a = vnt_get_duration_le(priv,
 						tx_context->pkt_type, need_ack);
@@ -373,10 +371,8 @@
 			  tx_context->pkt_type, &buf->ab);
 
 	/* Get Duration and TimeStampOff */
-	if (ieee80211_is_pspoll(hdr->frame_control)) {
-		__le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15));
-
-		buf->duration = dur;
+	if (ieee80211_is_nullfunc(hdr->frame_control)) {
+		buf->duration = hdr->duration_id;
 	} else {
 		buf->duration = vnt_get_duration_le(priv, tx_context->pkt_type,
 						    need_ack);
@@ -815,10 +811,14 @@
 		if (info->band == IEEE80211_BAND_5GHZ) {
 			pkt_type = PK_TYPE_11A;
 		} else {
-			if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
-				pkt_type = PK_TYPE_11GB;
-			else
-				pkt_type = PK_TYPE_11GA;
+			if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+				if (priv->basic_rates & VNT_B_RATES)
+					pkt_type = PK_TYPE_11GB;
+				else
+					pkt_type = PK_TYPE_11GA;
+			} else {
+				pkt_type = PK_TYPE_11A;
+			}
 		}
 	} else {
 		pkt_type = PK_TYPE_11B;
--- linux-4.4.0.orig/drivers/staging/vt6656/usbpipe.c
+++ linux-4.4.0/drivers/staging/vt6656/usbpipe.c
@@ -50,15 +50,25 @@
 		u16 index, u16 length, u8 *buffer)
 {
 	int status = 0;
+	u8 *usb_buffer;
 
 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
 		return STATUS_FAILURE;
 
 	mutex_lock(&priv->usb_lock);
 
+	usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
+	if (!usb_buffer) {
+		mutex_unlock(&priv->usb_lock);
+		return -ENOMEM;
+	}
+
 	status = usb_control_msg(priv->usb,
-		usb_sndctrlpipe(priv->usb, 0), request, 0x40, value,
-			index, buffer, length, USB_CTL_WAIT);
+				 usb_sndctrlpipe(priv->usb, 0),
+				 request, 0x40, value,
+				 index, usb_buffer, length, USB_CTL_WAIT);
+
+	kfree(usb_buffer);
 
 	mutex_unlock(&priv->usb_lock);
 
@@ -78,15 +88,28 @@
 		u16 index, u16 length, u8 *buffer)
 {
 	int status;
+	u8 *usb_buffer;
 
 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
 		return STATUS_FAILURE;
 
 	mutex_lock(&priv->usb_lock);
 
+	usb_buffer = kmalloc(length, GFP_KERNEL);
+	if (!usb_buffer) {
+		mutex_unlock(&priv->usb_lock);
+		return -ENOMEM;
+	}
+
 	status = usb_control_msg(priv->usb,
-		usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value,
-			index, buffer, length, USB_CTL_WAIT);
+				 usb_rcvctrlpipe(priv->usb, 0),
+				 request, 0xc0, value,
+				 index, usb_buffer, length, USB_CTL_WAIT);
+
+	if (status == length)
+		memcpy(buffer, usb_buffer, length);
+
+	kfree(usb_buffer);
 
 	mutex_unlock(&priv->usb_lock);
 
--- linux-4.4.0.orig/drivers/staging/vt6656/wcmd.c
+++ linux-4.4.0/drivers/staging/vt6656/wcmd.c
@@ -113,6 +113,7 @@
 		if (vnt_init(priv)) {
 			/* If fail all ends TODO retry */
 			dev_err(&priv->usb->dev, "failed to start\n");
+			usb_set_intfdata(priv->intf, NULL);
 			ieee80211_free_hw(priv->hw);
 			return;
 		}
--- linux-4.4.0.orig/drivers/staging/wilc1000/host_interface.c
+++ linux-4.4.0/drivers/staging/wilc1000/host_interface.c
@@ -2179,6 +2179,8 @@
 	wid.type = WID_STR;
 	wid.size = ETH_ALEN;
 	wid.val = kmalloc(wid.size, GFP_KERNEL);
+	if (!wid.val)
+		return -ENOMEM;
 
 	stamac = wid.val;
 	memcpy(stamac, strHostIfStaInactiveT->mac, ETH_ALEN);
--- linux-4.4.0.orig/drivers/staging/wilc1000/linux_mon.c
+++ linux-4.4.0/drivers/staging/wilc1000/linux_mon.c
@@ -251,6 +251,8 @@
 
 	if (skb->data[0] == 0xc0 && (!(memcmp(broadcast, &skb->data[4], 6)))) {
 		skb2 = dev_alloc_skb(skb->len + sizeof(struct wilc_wfi_radiotap_cb_hdr));
+		if (!skb2)
+			return -ENOMEM;
 
 		memcpy(skb_put(skb2, skb->len), skb->data, skb->len);
 
--- linux-4.4.0.orig/drivers/staging/wilc1000/wilc_wlan_if.h
+++ linux-4.4.0/drivers/staging/wilc1000/wilc_wlan_if.h
@@ -12,6 +12,7 @@
 
 #include <linux/semaphore.h>
 #include "linux_wlan_common.h"
+#include <linux/netdevice.h>
 
 /********************************************
  *
--- linux-4.4.0.orig/drivers/staging/wlan-ng/hfa384x_usb.c
+++ linux-4.4.0/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -530,13 +530,8 @@
 ----------------------------------------------------------------*/
 void hfa384x_create(hfa384x_t *hw, struct usb_device *usb)
 {
-	memset(hw, 0, sizeof(hfa384x_t));
 	hw->usb = usb;
 
-	/* set up the endpoints */
-	hw->endp_in = usb_rcvbulkpipe(usb, 1);
-	hw->endp_out = usb_sndbulkpipe(usb, 2);
-
 	/* Set up the waitq */
 	init_waitqueue_head(&hw->cmdq);
 
@@ -3574,6 +3569,8 @@
 	     WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)) {
 		pr_debug("overlen frm: len=%zd\n",
 			 skblen - sizeof(struct p80211_caphdr));
+
+		return;
 	}
 
 	skb = dev_alloc_skb(skblen);
--- linux-4.4.0.orig/drivers/staging/wlan-ng/p80211netdev.c
+++ linux-4.4.0/drivers/staging/wlan-ng/p80211netdev.c
@@ -232,7 +232,7 @@
 	struct p80211_hdr_a3 *hdr;
 
 	hdr = (struct p80211_hdr_a3 *) skb->data;
-	if (p80211_rx_typedrop(wlandev, hdr->fc))
+	if (p80211_rx_typedrop(wlandev, le16_to_cpu(hdr->fc)))
 		return CONV_TO_ETHER_SKIPPED;
 
 	/* perform mcast filtering: allow my local address through but reject
--- linux-4.4.0.orig/drivers/staging/wlan-ng/prism2mgmt.c
+++ linux-4.4.0/drivers/staging/wlan-ng/prism2mgmt.c
@@ -169,7 +169,7 @@
 				     hw->ident_sta_fw.variant) >
 	    HFA384x_FIRMWARE_VERSION(1, 5, 0)) {
 		if (msg->scantype.data != P80211ENUM_scantype_active)
-			word = cpu_to_le16(msg->maxchanneltime.data);
+			word = msg->maxchanneltime.data;
 		else
 			word = 0;
 
@@ -940,7 +940,7 @@
 		}
 	}
 
-	return 0;
+	return result;
 }
 
 /*----------------------------------------------------------------
--- linux-4.4.0.orig/drivers/staging/wlan-ng/prism2usb.c
+++ linux-4.4.0/drivers/staging/wlan-ng/prism2usb.c
@@ -60,11 +60,16 @@
 			       const struct usb_device_id *id)
 {
 	struct usb_device *dev;
-
+	struct usb_endpoint_descriptor *bulk_in, *bulk_out;
+	struct usb_host_interface *iface_desc = interface->cur_altsetting;
 	wlandevice_t *wlandev = NULL;
 	hfa384x_t *hw = NULL;
 	int result = 0;
 
+	result = usb_find_common_endpoints(iface_desc, &bulk_in, &bulk_out, NULL, NULL);
+	if (result)
+		goto failed;
+
 	dev = interface_to_usbdev(interface);
 	wlandev = create_wlan();
 	if (wlandev == NULL) {
@@ -81,6 +86,8 @@
 	}
 
 	/* Initialize the hw data */
+	hw->endp_in = usb_rcvbulkpipe(dev, bulk_in->bEndpointAddress);
+	hw->endp_out = usb_sndbulkpipe(dev, bulk_out->bEndpointAddress);
 	hfa384x_create(hw, dev);
 	hw->wlandev = wlandev;
 
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target.c
@@ -418,6 +418,7 @@
 		return 0;
 	}
 	np->np_thread_state = ISCSI_NP_THREAD_RESET;
+	atomic_inc(&np->np_reset_count);
 
 	if (np->np_thread) {
 		spin_unlock_bh(&np->np_thread_lock);
@@ -672,6 +673,7 @@
 	unsigned char *buf)
 {
 	struct iscsi_conn *conn;
+	const bool do_put = cmd->se_cmd.se_tfo != NULL;
 
 	if (!cmd->conn) {
 		pr_err("cmd->conn is NULL for ITT: 0x%08x\n",
@@ -702,7 +704,7 @@
 	 * Perform the kref_put now if se_cmd has already been setup by
 	 * scsit_setup_scsi_cmd()
 	 */
-	if (cmd->se_cmd.se_tfo != NULL) {
+	if (do_put) {
 		pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
 		target_put_sess_cmd(&cmd->se_cmd);
 	}
@@ -1111,6 +1113,18 @@
 	 */
 	if (dump_payload)
 		goto after_immediate_data;
+	/*
+	 * Check for underflow case where both EDTL and immediate data payload
+	 * exceeds what is presented by CDB's TRANSFER LENGTH, and what has
+	 * already been set in target_cmd_size_check() as se_cmd->data_length.
+	 *
+	 * For this special case, fail the command and dump the immediate data
+	 * payload.
+	 */
+	if (cmd->first_burst_len > cmd->se_cmd.data_length) {
+		cmd->sense_reason = TCM_INVALID_CDB_FIELD;
+		goto after_immediate_data;
+	}
 
 	immed_ret = iscsit_handle_immediate_data(cmd, hdr,
 					cmd->first_burst_len);
@@ -1744,8 +1758,7 @@
 	struct iscsi_tmr_req *tmr_req;
 	struct iscsi_tm *hdr;
 	int out_of_order_cmdsn = 0, ret;
-	bool sess_ref = false;
-	u8 function;
+	u8 function, tcm_function = TMR_UNKNOWN;
 
 	hdr			= (struct iscsi_tm *) buf;
 	hdr->flags &= ~ISCSI_FLAG_CMD_FINAL;
@@ -1786,22 +1799,17 @@
 					     buf);
 	}
 
+	transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
+			      conn->sess->se_sess, 0, DMA_NONE,
+			      TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
+
+	target_get_sess_cmd(&cmd->se_cmd, true);
+
 	/*
 	 * TASK_REASSIGN for ERL=2 / connection stays inside of
 	 * LIO-Target $FABRIC_MOD
 	 */
 	if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
-
-		u8 tcm_function;
-		int ret;
-
-		transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
-				      conn->sess->se_sess, 0, DMA_NONE,
-				      TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
-
-		target_get_sess_cmd(&cmd->se_cmd, true);
-		sess_ref = true;
-
 		switch (function) {
 		case ISCSI_TM_FUNC_ABORT_TASK:
 			tcm_function = TMR_ABORT_TASK;
@@ -1830,15 +1838,14 @@
 			return iscsit_add_reject_cmd(cmd,
 				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
 		}
-
-		ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req,
-					 tcm_function, GFP_KERNEL);
-		if (ret < 0)
-			return iscsit_add_reject_cmd(cmd,
+	}
+	ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req, tcm_function,
+				 GFP_KERNEL);
+	if (ret < 0)
+		return iscsit_add_reject_cmd(cmd,
 				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
 
-		cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
-	}
+	cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
 
 	cmd->iscsi_opcode	= ISCSI_OP_SCSI_TMFUNC;
 	cmd->i_state		= ISTATE_SEND_TASKMGTRSP;
@@ -1914,12 +1921,14 @@
 
 	if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
 		int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
-		if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
+		if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) {
 			out_of_order_cmdsn = 1;
-		else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+		} else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+			target_put_sess_cmd(&cmd->se_cmd);
 			return 0;
-		else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+		} else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
 			return -1;
+		}
 	}
 	iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
 
@@ -1939,12 +1948,8 @@
 	 * For connection recovery, this is also the default action for
 	 * TMR TASK_REASSIGN.
 	 */
-	if (sess_ref) {
-		pr_debug("Handle TMR, using sess_ref=true check\n");
-		target_put_sess_cmd(&cmd->se_cmd);
-	}
-
 	iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+	target_put_sess_cmd(&cmd->se_cmd);
 	return 0;
 }
 EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
@@ -1983,6 +1988,7 @@
 	cmd->cmd_sn		= be32_to_cpu(hdr->cmdsn);
 	cmd->exp_stat_sn	= be32_to_cpu(hdr->exp_statsn);
 	cmd->data_direction	= DMA_NONE;
+	kfree(cmd->text_in_ptr);
 	cmd->text_in_ptr	= NULL;
 
 	return 0;
@@ -3435,7 +3441,7 @@
 
 			if ((tpg->tpg_attrib.generate_node_acls == 0) &&
 			    (tpg->tpg_attrib.demo_mode_discovery == 0) &&
-			    (!core_tpg_get_initiator_node_acl(&tpg->tpg_se_tpg,
+			    (!target_tpg_has_node_acl(&tpg->tpg_se_tpg,
 				cmd->conn->sess->sess_ops->InitiatorName))) {
 				continue;
 			}
@@ -3952,6 +3958,8 @@
 {
 	int ret = 0;
 	struct iscsi_conn *conn = arg;
+	bool conn_freed = false;
+
 	/*
 	 * Allow ourselves to be interrupted by SIGINT so that a
 	 * connection recovery / failure event can be triggered externally.
@@ -3977,12 +3985,14 @@
 			goto transport_err;
 
 		ret = iscsit_handle_response_queue(conn);
-		if (ret == 1)
+		if (ret == 1) {
 			goto get_immediate;
-		else if (ret == -ECONNRESET)
+		} else if (ret == -ECONNRESET) {
+			conn_freed = true;
 			goto out;
-		else if (ret < 0)
+		} else if (ret < 0) {
 			goto transport_err;
+		}
 	}
 
 transport_err:
@@ -3992,8 +4002,13 @@
 	 * responsible for cleaning up the early connection failure.
 	 */
 	if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN)
-		iscsit_take_action_for_connection_exit(conn);
+		iscsit_take_action_for_connection_exit(conn, &conn_freed);
 out:
+	if (!conn_freed) {
+		while (!kthread_should_stop()) {
+			msleep(100);
+		}
+	}
 	return 0;
 }
 
@@ -4092,6 +4107,7 @@
 	u32 checksum = 0, digest = 0;
 	struct iscsi_conn *conn = arg;
 	struct kvec iov;
+	bool conn_freed = false;
 	/*
 	 * Allow ourselves to be interrupted by SIGINT so that a
 	 * connection recovery / failure event can be triggered externally.
@@ -4103,7 +4119,7 @@
 	 */
 	rc = wait_for_completion_interruptible(&conn->rx_login_comp);
 	if (rc < 0 || iscsi_target_check_conn_state(conn))
-		return 0;
+		goto out;
 
 	if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
 		struct completion comp;
@@ -4188,12 +4204,19 @@
 transport_err:
 	if (!signal_pending(current))
 		atomic_set(&conn->transport_failed, 1);
-	iscsit_take_action_for_connection_exit(conn);
+	iscsit_take_action_for_connection_exit(conn, &conn_freed);
+out:
+	if (!conn_freed) {
+		while (!kthread_should_stop()) {
+			msleep(100);
+		}
+	}
 	return 0;
 }
 
 static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
 {
+	LIST_HEAD(tmp_list);
 	struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
 	struct iscsi_session *sess = conn->sess;
 	/*
@@ -4202,18 +4225,36 @@
 	 * has been reset -> returned sleeping pre-handler state.
 	 */
 	spin_lock_bh(&conn->cmd_lock);
-	list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
+	list_splice_init(&conn->conn_cmd_list, &tmp_list);
+
+	list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
+		struct se_cmd *se_cmd = &cmd->se_cmd;
+
+		if (se_cmd->se_tfo != NULL) {
+			spin_lock_irq(&se_cmd->t_state_lock);
+			if (se_cmd->transport_state & CMD_T_ABORTED) {
+				/*
+				 * LIO's abort path owns the cleanup for this,
+				 * so put it back on the list and let
+				 * aborted_task handle it.
+				 */
+				list_move_tail(&cmd->i_conn_node,
+					       &conn->conn_cmd_list);
+			} else {
+				se_cmd->transport_state |= CMD_T_FABRIC_STOP;
+			}
+			spin_unlock_irq(&se_cmd->t_state_lock);
+		}
+	}
+	spin_unlock_bh(&conn->cmd_lock);
 
+	list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
 		list_del_init(&cmd->i_conn_node);
-		spin_unlock_bh(&conn->cmd_lock);
 
 		iscsit_increment_maxcmdsn(cmd, sess);
-
 		iscsit_free_cmd(cmd, true);
 
-		spin_lock_bh(&conn->cmd_lock);
 	}
-	spin_unlock_bh(&conn->cmd_lock);
 }
 
 static void iscsit_stop_timers_for_cmds(
@@ -4553,8 +4594,11 @@
 	 * always sleep waiting for RX/TX thread shutdown to complete
 	 * within iscsit_close_connection().
 	 */
-	if (conn->conn_transport->transport_type == ISCSI_TCP)
+	if (conn->conn_transport->transport_type == ISCSI_TCP) {
 		sleep = cmpxchg(&conn->tx_thread_active, true, false);
+		if (!sleep)
+			return;
+	}
 
 	atomic_set(&conn->conn_logout_remove, 0);
 	complete(&conn->conn_logout_comp);
@@ -4570,8 +4614,11 @@
 {
 	int sleep = 1;
 
-	if (conn->conn_transport->transport_type == ISCSI_TCP)
+	if (conn->conn_transport->transport_type == ISCSI_TCP) {
 		sleep = cmpxchg(&conn->tx_thread_active, true, false);
+		if (!sleep)
+			return;
+	}
 
 	atomic_set(&conn->conn_logout_remove, 0);
 	complete(&conn->conn_logout_comp);
@@ -4811,6 +4858,7 @@
 			continue;
 		}
 		atomic_set(&sess->session_reinstatement, 1);
+		atomic_set(&sess->session_fall_back_to_erl0, 1);
 		spin_unlock(&sess->conn_lock);
 
 		list_move_tail(&se_sess->sess_list, &free_list);
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_auth.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_auth.c
@@ -26,27 +26,6 @@
 #include "iscsi_target_nego.h"
 #include "iscsi_target_auth.h"
 
-static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len)
-{
-	int j = DIV_ROUND_UP(len, 2), rc;
-
-	rc = hex2bin(dst, src, j);
-	if (rc < 0)
-		pr_debug("CHAP string contains non hex digit symbols\n");
-
-	dst[j] = '\0';
-	return j;
-}
-
-static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len)
-{
-	int i;
-
-	for (i = 0; i < src_len; i++) {
-		sprintf(&dst[i*2], "%02x", (int) src[i] & 0xff);
-	}
-}
-
 static void chap_gen_challenge(
 	struct iscsi_conn *conn,
 	int caller,
@@ -59,7 +38,7 @@
 	memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);
 
 	get_random_bytes(chap->challenge, CHAP_CHALLENGE_LENGTH);
-	chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge,
+	bin2hex(challenge_asciihex, chap->challenge,
 				CHAP_CHALLENGE_LENGTH);
 	/*
 	 * Set CHAP_C, and copy the generated challenge into c_str.
@@ -95,7 +74,7 @@
 		if (!token)
 			goto out;
 
-		if (!strncmp(token, "5", 1)) {
+		if (!strcmp(token, "5")) {
 			pr_debug("Selected MD5 Algorithm\n");
 			kfree(orig);
 			return CHAP_DIGEST_MD5;
@@ -241,9 +220,16 @@
 		pr_err("Could not find CHAP_R.\n");
 		goto out;
 	}
+	if (strlen(chap_r) != MD5_SIGNATURE_SIZE * 2) {
+		pr_err("Malformed CHAP_R\n");
+		goto out;
+	}
+	if (hex2bin(client_digest, chap_r, MD5_SIGNATURE_SIZE) < 0) {
+		pr_err("Malformed CHAP_R\n");
+		goto out;
+	}
 
 	pr_debug("[server] Got CHAP_R=%s\n", chap_r);
-	chap_string_to_hex(client_digest, chap_r, strlen(chap_r));
 
 	tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(tfm)) {
@@ -292,7 +278,7 @@
 	}
 	crypto_free_hash(tfm);
 
-	chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE);
+	bin2hex(response, server_digest, MD5_SIGNATURE_SIZE);
 	pr_debug("[server] MD5 Server Digest: %s\n", response);
 
 	if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) {
@@ -348,9 +334,7 @@
 		pr_err("Could not find CHAP_C.\n");
 		goto out;
 	}
-	pr_debug("[server] Got CHAP_C=%s\n", challenge);
-	challenge_len = chap_string_to_hex(challenge_binhex, challenge,
-				strlen(challenge));
+	challenge_len = DIV_ROUND_UP(strlen(challenge), 2);
 	if (!challenge_len) {
 		pr_err("Unable to convert incoming challenge\n");
 		goto out;
@@ -359,6 +343,11 @@
 		pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
 		goto out;
 	}
+	if (hex2bin(challenge_binhex, challenge, challenge_len) < 0) {
+		pr_err("Malformed CHAP_C\n");
+		goto out;
+	}
+	pr_debug("[server] Got CHAP_C=%s\n", challenge);
 	/*
 	 * During mutual authentication, the CHAP_C generated by the
 	 * initiator must not match the original CHAP_C generated by
@@ -433,7 +422,7 @@
 	/*
 	 * Convert response from binary hex to ascii hext.
 	 */
-	chap_binaryhex_to_asciihex(response, digest, MD5_SIGNATURE_SIZE);
+	bin2hex(response, digest, MD5_SIGNATURE_SIZE);
 	*nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
 			response);
 	*nr_out_len += 1;
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_configfs.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_configfs.c
@@ -725,11 +725,8 @@
 
 	if (iscsit_get_tpg(tpg) < 0)
 		return -EINVAL;
-	/*
-	 * iscsit_tpg_set_initiator_node_queue_depth() assumes force=1
-	 */
-	ret = iscsit_tpg_set_initiator_node_queue_depth(tpg,
-				config_item_name(acl_ci), cmdsn_depth, 1);
+
+	ret = core_tpg_set_initiator_node_queue_depth(se_nacl, cmdsn_depth);
 
 	pr_debug("LIO_Target_ConfigFS: %s/%s Set CmdSN Window: %u for"
 		"InitiatorName: %s\n", config_item_name(wwn_ci),
@@ -871,6 +868,7 @@
 DEF_TPG_ATTRIB(t10_pi);
 DEF_TPG_ATTRIB(fabric_prot_type);
 DEF_TPG_ATTRIB(tpg_enabled_sendtargets);
+DEF_TPG_ATTRIB(login_keys_workaround);
 
 static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
 	&iscsi_tpg_attrib_attr_authentication,
@@ -886,6 +884,7 @@
 	&iscsi_tpg_attrib_attr_t10_pi,
 	&iscsi_tpg_attrib_attr_fabric_prot_type,
 	&iscsi_tpg_attrib_attr_tpg_enabled_sendtargets,
+	&iscsi_tpg_attrib_attr_login_keys_workaround,
 	NULL,
 };
 
@@ -1211,7 +1210,7 @@
 
 	ret = core_tpg_register(wwn, &tpg->tpg_se_tpg, SCSI_PROTOCOL_ISCSI);
 	if (ret < 0)
-		return NULL;
+		goto free_out;
 
 	ret = iscsit_tpg_add_portal_group(tiqn, tpg);
 	if (ret != 0)
@@ -1223,6 +1222,7 @@
 	return &tpg->tpg_se_tpg;
 out:
 	core_tpg_deregister(&tpg->tpg_se_tpg);
+free_out:
 	kfree(tpg);
 	return NULL;
 }
@@ -1593,28 +1593,31 @@
 }
 
 /*
- * Called with spin_lock_bh(struct se_portal_group->session_lock) held..
- *
- * Also, this function calls iscsit_inc_session_usage_count() on the
+ * This function calls iscsit_inc_session_usage_count() on the
  * struct iscsi_session in question.
  */
 static int lio_tpg_shutdown_session(struct se_session *se_sess)
 {
 	struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+	struct se_portal_group *se_tpg = &sess->tpg->tpg_se_tpg;
 
+	spin_lock_bh(&se_tpg->session_lock);
 	spin_lock(&sess->conn_lock);
 	if (atomic_read(&sess->session_fall_back_to_erl0) ||
 	    atomic_read(&sess->session_logout) ||
 	    (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
 		spin_unlock(&sess->conn_lock);
+		spin_unlock_bh(&se_tpg->session_lock);
 		return 0;
 	}
 	atomic_set(&sess->session_reinstatement, 1);
+	atomic_set(&sess->session_fall_back_to_erl0, 1);
 	spin_unlock(&sess->conn_lock);
 
 	iscsit_stop_time2retain_timer(sess);
-	iscsit_stop_session(sess, 1, 1);
+	spin_unlock_bh(&se_tpg->session_lock);
 
+	iscsit_stop_session(sess, 1, 1);
 	return 1;
 }
 
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_erl0.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_erl0.c
@@ -44,10 +44,8 @@
 	 */
 	if (cmd->unsolicited_data) {
 		cmd->seq_start_offset = cmd->write_data_done;
-		cmd->seq_end_offset = (cmd->write_data_done +
-			((cmd->se_cmd.data_length >
-			  conn->sess->sess_ops->FirstBurstLength) ?
-			 conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length));
+		cmd->seq_end_offset = min(cmd->se_cmd.data_length,
+					conn->sess->sess_ops->FirstBurstLength);
 		return;
 	}
 
@@ -930,8 +928,10 @@
 	}
 }
 
-void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
+void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn, bool *conn_freed)
 {
+	*conn_freed = false;
+
 	spin_lock_bh(&conn->state_lock);
 	if (atomic_read(&conn->connection_exit)) {
 		spin_unlock_bh(&conn->state_lock);
@@ -942,6 +942,7 @@
 	if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
 		spin_unlock_bh(&conn->state_lock);
 		iscsit_close_connection(conn);
+		*conn_freed = true;
 		return;
 	}
 
@@ -955,4 +956,5 @@
 	spin_unlock_bh(&conn->state_lock);
 
 	iscsit_handle_connection_cleanup(conn);
+	*conn_freed = true;
 }
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_erl0.h
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_erl0.h
@@ -9,6 +9,6 @@
 extern void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *);
 extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int);
 extern void iscsit_fall_back_to_erl0(struct iscsi_session *);
-extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *);
+extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *, bool *);
 
 #endif   /*** ISCSI_TARGET_ERL0_H ***/
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_login.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_login.c
@@ -195,6 +195,7 @@
 			    initiatorname_param->value) &&
 		   (sess_p->sess_ops->SessionType == sessiontype))) {
 			atomic_set(&sess_p->session_reinstatement, 1);
+			atomic_set(&sess_p->session_fall_back_to_erl0, 1);
 			spin_unlock(&sess_p->conn_lock);
 			iscsit_inc_session_usage_count(sess_p);
 			iscsit_stop_time2retain_timer(sess_p);
@@ -322,8 +323,7 @@
 		pr_err("idr_alloc() for sess_idr failed\n");
 		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
 				ISCSI_LOGIN_STATUS_NO_RESOURCES);
-		kfree(sess);
-		return -ENOMEM;
+		goto free_sess;
 	}
 
 	sess->creation_time = get_jiffies_64();
@@ -339,20 +339,28 @@
 				ISCSI_LOGIN_STATUS_NO_RESOURCES);
 		pr_err("Unable to allocate memory for"
 				" struct iscsi_sess_ops.\n");
-		kfree(sess);
-		return -ENOMEM;
+		goto remove_idr;
 	}
 
 	sess->se_sess = transport_init_session(TARGET_PROT_NORMAL);
 	if (IS_ERR(sess->se_sess)) {
 		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
 				ISCSI_LOGIN_STATUS_NO_RESOURCES);
-		kfree(sess->sess_ops);
-		kfree(sess);
-		return -ENOMEM;
+		goto free_ops;
 	}
 
 	return 0;
+
+free_ops:
+	kfree(sess->sess_ops);
+remove_idr:
+	spin_lock_bh(&sess_idr_lock);
+	idr_remove(&sess_idr, sess->session_index);
+	spin_unlock_bh(&sess_idr_lock);
+free_sess:
+	kfree(sess);
+	conn->sess = NULL;
+	return -ENOMEM;
 }
 
 static int iscsi_login_zero_tsih_s2(
@@ -1131,7 +1139,7 @@
 }
 
 void iscsi_target_login_sess_out(struct iscsi_conn *conn,
-		struct iscsi_np *np, bool zero_tsih, bool new_sess)
+				 bool zero_tsih, bool new_sess)
 {
 	if (!new_sess)
 		goto old_sess_out;
@@ -1141,19 +1149,18 @@
 				   ISCSI_LOGIN_STATUS_INIT_ERR);
 	if (!zero_tsih || !conn->sess)
 		goto old_sess_out;
-	if (conn->sess->se_sess)
-		transport_free_session(conn->sess->se_sess);
-	if (conn->sess->session_index != 0) {
-		spin_lock_bh(&sess_idr_lock);
-		idr_remove(&sess_idr, conn->sess->session_index);
-		spin_unlock_bh(&sess_idr_lock);
-	}
+
+	transport_free_session(conn->sess->se_sess);
+
+	spin_lock_bh(&sess_idr_lock);
+	idr_remove(&sess_idr, conn->sess->session_index);
+	spin_unlock_bh(&sess_idr_lock);
+
 	kfree(conn->sess->sess_ops);
 	kfree(conn->sess);
 	conn->sess = NULL;
 
 old_sess_out:
-	iscsi_stop_login_thread_timer(np);
 	/*
 	 * If login negotiation fails check if the Time2Retain timer
 	 * needs to be restarted.
@@ -1218,9 +1225,11 @@
 	flush_signals(current);
 
 	spin_lock_bh(&np->np_thread_lock);
-	if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+	if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
 		np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
+		spin_unlock_bh(&np->np_thread_lock);
 		complete(&np->np_restart_comp);
+		return 1;
 	} else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) {
 		spin_unlock_bh(&np->np_thread_lock);
 		goto exit;
@@ -1253,7 +1262,8 @@
 		goto exit;
 	} else if (rc < 0) {
 		spin_lock_bh(&np->np_thread_lock);
-		if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+		if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
+			np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
 			spin_unlock_bh(&np->np_thread_lock);
 			complete(&np->np_restart_comp);
 			iscsit_put_transport(conn->conn_transport);
@@ -1357,8 +1367,9 @@
 	}
 	login->zero_tsih = zero_tsih;
 
-	conn->sess->se_sess->sup_prot_ops =
-		conn->conn_transport->iscsit_get_sup_prot_ops(conn);
+	if (conn->sess)
+		conn->sess->se_sess->sup_prot_ops =
+			conn->conn_transport->iscsit_get_sup_prot_ops(conn);
 
 	tpg = conn->tpg;
 	if (!tpg) {
@@ -1395,8 +1406,9 @@
 new_sess_out:
 	new_sess = true;
 old_sess_out:
+	iscsi_stop_login_thread_timer(np);
 	tpg_np = conn->tpg_np;
-	iscsi_target_login_sess_out(conn, np, zero_tsih, new_sess);
+	iscsi_target_login_sess_out(conn, zero_tsih, new_sess);
 	new_sess = false;
 
 	if (tpg) {
@@ -1434,5 +1446,9 @@
 			break;
 	}
 
+	while (!kthread_should_stop()) {
+		msleep(100);
+	}
+
 	return 0;
 }
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_login.h
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_login.h
@@ -14,8 +14,7 @@
 extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
 extern int iscsit_start_kthreads(struct iscsi_conn *);
 extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
-extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
-				bool, bool);
+extern void iscsi_target_login_sess_out(struct iscsi_conn *, bool, bool);
 extern int iscsi_target_login_thread(void *);
 
 #endif   /*** ISCSI_TARGET_LOGIN_H ***/
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_nego.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_nego.c
@@ -489,24 +489,69 @@
 
 static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *);
 
-static bool iscsi_target_sk_state_check(struct sock *sk)
+static bool __iscsi_target_sk_check_close(struct sock *sk)
 {
 	if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) {
-		pr_debug("iscsi_target_sk_state_check: TCP_CLOSE_WAIT|TCP_CLOSE,"
+		pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE,"
 			"returning FALSE\n");
-		return false;
+		return true;
 	}
-	return true;
+	return false;
+}
+
+static bool iscsi_target_sk_check_close(struct iscsi_conn *conn)
+{
+	bool state = false;
+
+	if (conn->sock) {
+		struct sock *sk = conn->sock->sk;
+
+		read_lock_bh(&sk->sk_callback_lock);
+		state = (__iscsi_target_sk_check_close(sk) ||
+			 test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags));
+		read_unlock_bh(&sk->sk_callback_lock);
+	}
+	return state;
+}
+
+static bool iscsi_target_sk_check_flag(struct iscsi_conn *conn, unsigned int flag)
+{
+	bool state = false;
+
+	if (conn->sock) {
+		struct sock *sk = conn->sock->sk;
+
+		read_lock_bh(&sk->sk_callback_lock);
+		state = test_bit(flag, &conn->login_flags);
+		read_unlock_bh(&sk->sk_callback_lock);
+	}
+	return state;
+}
+
+static bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned int flag)
+{
+	bool state = false;
+
+	if (conn->sock) {
+		struct sock *sk = conn->sock->sk;
+
+		write_lock_bh(&sk->sk_callback_lock);
+		state = (__iscsi_target_sk_check_close(sk) ||
+			 test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags));
+		if (!state)
+			clear_bit(flag, &conn->login_flags);
+		write_unlock_bh(&sk->sk_callback_lock);
+	}
+	return state;
 }
 
 static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login)
 {
-	struct iscsi_np *np = login->np;
 	bool zero_tsih = login->zero_tsih;
 
 	iscsi_remove_failed_auth_entry(conn);
 	iscsi_target_nego_release(conn);
-	iscsi_target_login_sess_out(conn, np, zero_tsih, true);
+	iscsi_target_login_sess_out(conn, zero_tsih, true);
 }
 
 static void iscsi_target_login_timeout(unsigned long data)
@@ -536,6 +581,20 @@
 
 	pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n",
 			conn, current->comm, current->pid);
+	/*
+	 * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready()
+	 * before initial PDU processing in iscsi_target_start_negotiation()
+	 * has completed, go ahead and retry until it's cleared.
+	 *
+	 * Otherwise if the TCP connection drops while this is occuring,
+	 * iscsi_target_start_negotiation() will detect the failure, call
+	 * cancel_delayed_work_sync(&conn->login_work), and cleanup the
+	 * remaining iscsi connection resources from iscsi_np process context.
+	 */
+	if (iscsi_target_sk_check_flag(conn, LOGIN_FLAGS_INITIAL_PDU)) {
+		schedule_delayed_work(&conn->login_work, msecs_to_jiffies(10));
+		return;
+	}
 
 	spin_lock(&tpg->tpg_state_lock);
 	state = (tpg->tpg_state == TPG_STATE_ACTIVE);
@@ -543,26 +602,12 @@
 
 	if (!state) {
 		pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n");
-		iscsi_target_restore_sock_callbacks(conn);
-		iscsi_target_login_drop(conn, login);
-		iscsit_deaccess_np(np, tpg, tpg_np);
-		return;
+		goto err;
 	}
 
-	if (conn->sock) {
-		struct sock *sk = conn->sock->sk;
-
-		read_lock_bh(&sk->sk_callback_lock);
-		state = iscsi_target_sk_state_check(sk);
-		read_unlock_bh(&sk->sk_callback_lock);
-
-		if (!state) {
-			pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n");
-			iscsi_target_restore_sock_callbacks(conn);
-			iscsi_target_login_drop(conn, login);
-			iscsit_deaccess_np(np, tpg, tpg_np);
-			return;
-		}
+	if (iscsi_target_sk_check_close(conn)) {
+		pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n");
+		goto err;
 	}
 
 	conn->login_kworker = current;
@@ -580,34 +625,29 @@
 	flush_signals(current);
 	conn->login_kworker = NULL;
 
-	if (rc < 0) {
-		iscsi_target_restore_sock_callbacks(conn);
-		iscsi_target_login_drop(conn, login);
-		iscsit_deaccess_np(np, tpg, tpg_np);
-		return;
-	}
+	if (rc < 0)
+		goto err;
 
 	pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n",
 			conn, current->comm, current->pid);
 
 	rc = iscsi_target_do_login(conn, login);
 	if (rc < 0) {
-		iscsi_target_restore_sock_callbacks(conn);
-		iscsi_target_login_drop(conn, login);
-		iscsit_deaccess_np(np, tpg, tpg_np);
+		goto err;
 	} else if (!rc) {
-		if (conn->sock) {
-			struct sock *sk = conn->sock->sk;
-
-			write_lock_bh(&sk->sk_callback_lock);
-			clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags);
-			write_unlock_bh(&sk->sk_callback_lock);
-		}
+		if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_READ_ACTIVE))
+			goto err;
 	} else if (rc == 1) {
 		iscsi_target_nego_release(conn);
 		iscsi_post_login_handler(np, conn, zero_tsih);
 		iscsit_deaccess_np(np, tpg, tpg_np);
 	}
+	return;
+
+err:
+	iscsi_target_restore_sock_callbacks(conn);
+	iscsi_target_login_drop(conn, login);
+	iscsit_deaccess_np(np, tpg, tpg_np);
 }
 
 static void iscsi_target_do_cleanup(struct work_struct *work)
@@ -655,31 +695,54 @@
 		orig_state_change(sk);
 		return;
 	}
+	state = __iscsi_target_sk_check_close(sk);
+	pr_debug("__iscsi_target_sk_close_change: state: %d\n", state);
+
 	if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) {
 		pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change"
 			 " conn: %p\n", conn);
+		if (state)
+			set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags);
 		write_unlock_bh(&sk->sk_callback_lock);
 		orig_state_change(sk);
 		return;
 	}
-	if (test_and_set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) {
+	if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) {
 		pr_debug("Got LOGIN_FLAGS_CLOSED=1 sk_state_change conn: %p\n",
 			 conn);
 		write_unlock_bh(&sk->sk_callback_lock);
 		orig_state_change(sk);
 		return;
 	}
+	/*
+	 * If the TCP connection has dropped, go ahead and set LOGIN_FLAGS_CLOSED,
+	 * but only queue conn->login_work -> iscsi_target_do_login_rx()
+	 * processing if LOGIN_FLAGS_INITIAL_PDU has already been cleared.
+	 *
+	 * When iscsi_target_do_login_rx() runs, iscsi_target_sk_check_close()
+	 * will detect the dropped TCP connection from delayed workqueue context.
+	 *
+	 * If LOGIN_FLAGS_INITIAL_PDU is still set, which means the initial
+	 * iscsi_target_start_negotiation() is running, iscsi_target_do_login()
+	 * via iscsi_target_sk_check_close() or iscsi_target_start_negotiation()
+	 * via iscsi_target_sk_check_and_clear() is responsible for detecting the
+	 * dropped TCP connection in iscsi_np process context, and cleaning up
+	 * the remaining iscsi connection resources.
+	 */
+	if (state) {
+		pr_debug("iscsi_target_sk_state_change got failed state\n");
+		set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags);
+		state = test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags);
+		write_unlock_bh(&sk->sk_callback_lock);
 
-	state = iscsi_target_sk_state_check(sk);
-	write_unlock_bh(&sk->sk_callback_lock);
-
-	pr_debug("iscsi_target_sk_state_change: state: %d\n", state);
+		orig_state_change(sk);
 
-	if (!state) {
-		pr_debug("iscsi_target_sk_state_change got failed state\n");
-		schedule_delayed_work(&conn->login_cleanup_work, 0);
+		if (!state)
+			schedule_delayed_work(&conn->login_work, 0);
 		return;
 	}
+	write_unlock_bh(&sk->sk_callback_lock);
+
 	orig_state_change(sk);
 }
 
@@ -818,7 +881,8 @@
 			SENDER_TARGET,
 			login->rsp_buf,
 			&login->rsp_length,
-			conn->param_list);
+			conn->param_list,
+			conn->tpg->tpg_attrib.login_keys_workaround);
 	if (ret < 0)
 		return -1;
 
@@ -888,7 +952,8 @@
 			SENDER_TARGET,
 			login->rsp_buf,
 			&login->rsp_length,
-			conn->param_list);
+			conn->param_list,
+			conn->tpg->tpg_attrib.login_keys_workaround);
 	if (ret < 0) {
 		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
 				ISCSI_LOGIN_STATUS_INIT_ERR);
@@ -942,6 +1007,15 @@
 			if (iscsi_target_handle_csg_one(conn, login) < 0)
 				return -1;
 			if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
+				/*
+				 * Check to make sure the TCP connection has not
+				 * dropped asynchronously while session reinstatement
+				 * was occuring in this kthread context, before
+				 * transitioning to full feature phase operation.
+				 */
+				if (iscsi_target_sk_check_close(conn))
+					return -1;
+
 				login->tsih = conn->sess->tsih;
 				login->login_complete = 1;
 				iscsi_target_restore_sock_callbacks(conn);
@@ -968,21 +1042,6 @@
 		break;
 	}
 
-	if (conn->sock) {
-		struct sock *sk = conn->sock->sk;
-		bool state;
-
-		read_lock_bh(&sk->sk_callback_lock);
-		state = iscsi_target_sk_state_check(sk);
-		read_unlock_bh(&sk->sk_callback_lock);
-
-		if (!state) {
-			pr_debug("iscsi_target_do_login() failed state for"
-				 " conn: %p\n", conn);
-			return -1;
-		}
-	}
-
 	return 0;
 }
 
@@ -1246,16 +1305,28 @@
 {
 	int ret;
 
+       if (conn->sock) {
+               struct sock *sk = conn->sock->sk;
+
+		write_lock_bh(&sk->sk_callback_lock);
+		set_bit(LOGIN_FLAGS_READY, &conn->login_flags);
+		set_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags);
+		write_unlock_bh(&sk->sk_callback_lock);
+	}
+	/*
+	 * If iscsi_target_do_login returns zero to signal more PDU
+	 * exchanges are required to complete the login, go ahead and
+	 * clear LOGIN_FLAGS_INITIAL_PDU but only if the TCP connection
+	 * is still active.
+	 *
+	 * Otherwise if TCP connection dropped asynchronously, go ahead
+	 * and perform connection cleanup now.
+	 */
 	ret = iscsi_target_do_login(conn, login);
-	if (!ret) {
-		if (conn->sock) {
-			struct sock *sk = conn->sock->sk;
-
-			write_lock_bh(&sk->sk_callback_lock);
-			set_bit(LOGIN_FLAGS_READY, &conn->login_flags);
-			write_unlock_bh(&sk->sk_callback_lock);
-		}
-	} else if (ret < 0) {
+	if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU))
+		ret = -1;
+
+	if (ret < 0) {
 		cancel_delayed_work_sync(&conn->login_work);
 		cancel_delayed_work_sync(&conn->login_cleanup_work);
 		iscsi_target_restore_sock_callbacks(conn);
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_parameters.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_parameters.c
@@ -764,7 +764,8 @@
 	return 0;
 }
 
-static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param)
+static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param,
+						    bool keys_workaround)
 {
 	if (IS_TYPE_BOOL_AND(param)) {
 		if (!strcmp(param->value, NO))
@@ -772,35 +773,31 @@
 	} else if (IS_TYPE_BOOL_OR(param)) {
 		if (!strcmp(param->value, YES))
 			SET_PSTATE_REPLY_OPTIONAL(param);
-		 /*
-		  * Required for gPXE iSCSI boot client
-		  */
-		if (!strcmp(param->name, IMMEDIATEDATA))
-			SET_PSTATE_REPLY_OPTIONAL(param);
+
+		if (keys_workaround) {
+			/*
+			 * Required for gPXE iSCSI boot client
+			 */
+			if (!strcmp(param->name, IMMEDIATEDATA))
+				SET_PSTATE_REPLY_OPTIONAL(param);
+		}
 	} else if (IS_TYPE_NUMBER(param)) {
 		if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
 			SET_PSTATE_REPLY_OPTIONAL(param);
-		/*
-		 * The GlobalSAN iSCSI Initiator for MacOSX does
-		 * not respond to MaxBurstLength, FirstBurstLength,
-		 * DefaultTime2Wait or DefaultTime2Retain parameter keys.
-		 * So, we set them to 'reply optional' here, and assume the
-		 * the defaults from iscsi_parameters.h if the initiator
-		 * is not RFC compliant and the keys are not negotiated.
-		 */
-		if (!strcmp(param->name, MAXBURSTLENGTH))
-			SET_PSTATE_REPLY_OPTIONAL(param);
-		if (!strcmp(param->name, FIRSTBURSTLENGTH))
-			SET_PSTATE_REPLY_OPTIONAL(param);
-		if (!strcmp(param->name, DEFAULTTIME2WAIT))
-			SET_PSTATE_REPLY_OPTIONAL(param);
-		if (!strcmp(param->name, DEFAULTTIME2RETAIN))
-			SET_PSTATE_REPLY_OPTIONAL(param);
-		/*
-		 * Required for gPXE iSCSI boot client
-		 */
-		if (!strcmp(param->name, MAXCONNECTIONS))
-			SET_PSTATE_REPLY_OPTIONAL(param);
+
+		if (keys_workaround) {
+			/*
+			 * Required for Mellanox Flexboot PXE boot ROM
+			 */
+			if (!strcmp(param->name, FIRSTBURSTLENGTH))
+				SET_PSTATE_REPLY_OPTIONAL(param);
+
+			/*
+			 * Required for gPXE iSCSI boot client
+			 */
+			if (!strcmp(param->name, MAXCONNECTIONS))
+				SET_PSTATE_REPLY_OPTIONAL(param);
+		}
 	} else if (IS_PHASE_DECLARATIVE(param))
 		SET_PSTATE_REPLY_OPTIONAL(param);
 }
@@ -1437,7 +1434,8 @@
 	u8 sender,
 	char *textbuf,
 	u32 *length,
-	struct iscsi_param_list *param_list)
+	struct iscsi_param_list *param_list,
+	bool keys_workaround)
 {
 	char *output_buf = NULL;
 	struct iscsi_extra_response *er;
@@ -1473,7 +1471,8 @@
 			*length += 1;
 			output_buf = textbuf + *length;
 			SET_PSTATE_PROPOSER(param);
-			iscsi_check_proposer_for_optional_reply(param);
+			iscsi_check_proposer_for_optional_reply(param,
+							        keys_workaround);
 			pr_debug("Sending key: %s=%s\n",
 				param->name, param->value);
 		}
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_parameters.h
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_parameters.h
@@ -40,7 +40,7 @@
 extern int iscsi_update_param_value(struct iscsi_param *, char *);
 extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *);
 extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
-			struct iscsi_param_list *);
+			struct iscsi_param_list *, bool);
 extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
 extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
 			struct iscsi_param_list *);
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_tpg.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_tpg.c
@@ -227,6 +227,7 @@
 	a->t10_pi = TA_DEFAULT_T10_PI;
 	a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE;
 	a->tpg_enabled_sendtargets = TA_DEFAULT_TPG_ENABLED_SENDTARGETS;
+	a->login_keys_workaround = TA_DEFAULT_LOGIN_KEYS_WORKAROUND;
 }
 
 int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg)
@@ -260,7 +261,6 @@
 		iscsi_release_param_list(tpg->param_list);
 		tpg->param_list = NULL;
 	}
-	kfree(tpg);
 	return -ENOMEM;
 }
 
@@ -590,16 +590,6 @@
 	return iscsit_tpg_release_np(tpg_np, tpg, np);
 }
 
-int iscsit_tpg_set_initiator_node_queue_depth(
-	struct iscsi_portal_group *tpg,
-	unsigned char *initiatorname,
-	u32 queue_depth,
-	int force)
-{
-	return core_tpg_set_initiator_node_queue_depth(&tpg->tpg_se_tpg,
-		initiatorname, queue_depth, force);
-}
-
 int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication)
 {
 	unsigned char buf1[256], buf2[256], *none = NULL;
@@ -647,8 +637,7 @@
 		none = strstr(buf1, NONE);
 		if (none)
 			goto out;
-		strncat(buf1, ",", strlen(","));
-		strncat(buf1, NONE, strlen(NONE));
+		strlcat(buf1, "," NONE, sizeof(buf1));
 		if (iscsi_update_param_value(param, buf1) < 0)
 			return -EINVAL;
 	}
@@ -910,3 +899,21 @@
 
 	return 0;
 }
+
+int iscsit_ta_login_keys_workaround(
+	struct iscsi_portal_group *tpg,
+	u32 flag)
+{
+	struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+	if ((flag != 0) && (flag != 1)) {
+		pr_err("Illegal value %d\n", flag);
+		return -EINVAL;
+	}
+
+	a->login_keys_workaround = flag;
+	pr_debug("iSCSI_TPG[%hu] - TPG enabled bit for login keys workaround: %s ",
+		tpg->tpgt, (a->login_keys_workaround) ? "ON" : "OFF");
+
+	return 0;
+}
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_tpg.h
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_tpg.h
@@ -26,8 +26,6 @@
 			int);
 extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *,
 			struct iscsi_tpg_np *);
-extern int iscsit_tpg_set_initiator_node_queue_depth(struct iscsi_portal_group *,
-			unsigned char *, u32, int);
 extern int iscsit_ta_authentication(struct iscsi_portal_group *, u32);
 extern int iscsit_ta_login_timeout(struct iscsi_portal_group *, u32);
 extern int iscsit_ta_netif_timeout(struct iscsi_portal_group *, u32);
@@ -41,5 +39,6 @@
 extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32);
 extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32);
 extern int iscsit_ta_tpg_enabled_sendtargets(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_login_keys_workaround(struct iscsi_portal_group *, u32);
 
 #endif /* ISCSI_TARGET_TPG_H */
--- linux-4.4.0.orig/drivers/target/iscsi/iscsi_target_util.c
+++ linux-4.4.0/drivers/target/iscsi/iscsi_target_util.c
@@ -731,21 +731,23 @@
 {
 	struct se_cmd *se_cmd = NULL;
 	int rc;
+	bool op_scsi = false;
 	/*
 	 * Determine if a struct se_cmd is associated with
 	 * this struct iscsi_cmd.
 	 */
 	switch (cmd->iscsi_opcode) {
 	case ISCSI_OP_SCSI_CMD:
-		se_cmd = &cmd->se_cmd;
-		__iscsit_free_cmd(cmd, true, shutdown);
+		op_scsi = true;
 		/*
 		 * Fallthrough
 		 */
 	case ISCSI_OP_SCSI_TMFUNC:
-		rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
-		if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
-			__iscsit_free_cmd(cmd, true, shutdown);
+		se_cmd = &cmd->se_cmd;
+		__iscsit_free_cmd(cmd, op_scsi, shutdown);
+		rc = transport_generic_free_cmd(se_cmd, shutdown);
+		if (!rc && shutdown && se_cmd->se_sess) {
+			__iscsit_free_cmd(cmd, op_scsi, shutdown);
 			target_put_sess_cmd(se_cmd);
 		}
 		break;
@@ -1283,9 +1285,8 @@
 	iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC,
 		      count->iov, count->iov_count, data);
 
-	while (total_rx < data) {
-		rx_loop = sock_recvmsg(conn->sock, &msg,
-				      (data - total_rx), MSG_WAITALL);
+	while (msg_data_left(&msg)) {
+		rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL);
 		if (rx_loop <= 0) {
 			pr_debug("rx_loop: %d total_rx: %d\n",
 				rx_loop, total_rx);
--- linux-4.4.0.orig/drivers/target/target_core_alua.c
+++ linux-4.4.0/drivers/target/target_core_alua.c
@@ -1010,7 +1010,7 @@
 static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
 {
 	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work,
-		struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work);
+		struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work);
 	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
 	bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status ==
 			 ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG);
@@ -1073,17 +1073,8 @@
 	/*
 	 * Flush any pending transitions
 	 */
-	if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs &&
-	    atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) ==
-	    ALUA_ACCESS_STATE_TRANSITION) {
-		/* Just in case */
-		tg_pt_gp->tg_pt_gp_alua_pending_state = new_state;
-		tg_pt_gp->tg_pt_gp_transition_complete = &wait;
-		flush_delayed_work(&tg_pt_gp->tg_pt_gp_transition_work);
-		wait_for_completion(&wait);
-		tg_pt_gp->tg_pt_gp_transition_complete = NULL;
-		return 0;
-	}
+	if (!explicit)
+		flush_work(&tg_pt_gp->tg_pt_gp_transition_work);
 
 	/*
 	 * Save the old primary ALUA access state, and set the current state
@@ -1114,17 +1105,9 @@
 	atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
 
-	if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs) {
-		unsigned long transition_tmo;
-
-		transition_tmo = tg_pt_gp->tg_pt_gp_implicit_trans_secs * HZ;
-		queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq,
-				   &tg_pt_gp->tg_pt_gp_transition_work,
-				   transition_tmo);
-	} else {
+	schedule_work(&tg_pt_gp->tg_pt_gp_transition_work);
+	if (explicit) {
 		tg_pt_gp->tg_pt_gp_transition_complete = &wait;
-		queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq,
-				   &tg_pt_gp->tg_pt_gp_transition_work, 0);
 		wait_for_completion(&wait);
 		tg_pt_gp->tg_pt_gp_transition_complete = NULL;
 	}
@@ -1692,8 +1675,8 @@
 	mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex);
 	spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);
 	atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0);
-	INIT_DELAYED_WORK(&tg_pt_gp->tg_pt_gp_transition_work,
-			  core_alua_do_transition_tg_pt_work);
+	INIT_WORK(&tg_pt_gp->tg_pt_gp_transition_work,
+		  core_alua_do_transition_tg_pt_work);
 	tg_pt_gp->tg_pt_gp_dev = dev;
 	atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
 		ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED);
@@ -1801,7 +1784,7 @@
 	dev->t10_alua.alua_tg_pt_gps_counter--;
 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
 
-	flush_delayed_work(&tg_pt_gp->tg_pt_gp_transition_work);
+	flush_work(&tg_pt_gp->tg_pt_gp_transition_work);
 
 	/*
 	 * Allow a struct t10_alua_tg_pt_gp_member * referenced by
--- linux-4.4.0.orig/drivers/target/target_core_configfs.c
+++ linux-4.4.0/drivers/target/target_core_configfs.c
@@ -1980,14 +1980,14 @@
 	struct se_device *dev = to_device(item);
 	struct t10_alua_lba_map *lba_map = NULL;
 	struct list_head lba_list;
-	char *map_entries, *ptr;
+	char *map_entries, *orig, *ptr;
 	char state;
 	int pg_num = -1, pg;
 	int ret = 0, num = 0, pg_id, alua_state;
 	unsigned long start_lba = -1, end_lba = -1;
 	unsigned long segment_size = -1, segment_mult = -1;
 
-	map_entries = kstrdup(page, GFP_KERNEL);
+	orig = map_entries = kstrdup(page, GFP_KERNEL);
 	if (!map_entries)
 		return -ENOMEM;
 
@@ -2085,7 +2085,7 @@
 	} else
 		core_alua_set_lba_map(dev, &lba_list,
 				      segment_size, segment_mult);
-	kfree(map_entries);
+	kfree(orig);
 	return count;
 }
 
--- linux-4.4.0.orig/drivers/target/target_core_device.c
+++ linux-4.4.0/drivers/target/target_core_device.c
@@ -77,12 +77,16 @@
 					&deve->read_bytes);
 
 		se_lun = rcu_dereference(deve->se_lun);
+
+		if (!percpu_ref_tryget_live(&se_lun->lun_ref)) {
+			se_lun = NULL;
+			goto out_unlock;
+		}
+
 		se_cmd->se_lun = rcu_dereference(deve->se_lun);
 		se_cmd->pr_res_key = deve->pr_res_key;
 		se_cmd->orig_fe_lun = unpacked_lun;
 		se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
-
-		percpu_ref_get(&se_lun->lun_ref);
 		se_cmd->lun_ref_active = true;
 
 		if ((se_cmd->data_direction == DMA_TO_DEVICE) &&
@@ -96,6 +100,7 @@
 			goto ref_dev;
 		}
 	}
+out_unlock:
 	rcu_read_unlock();
 
 	if (!se_lun) {
@@ -362,7 +367,15 @@
 			kfree(new);
 			return -EINVAL;
 		}
-		BUG_ON(orig->se_lun_acl != NULL);
+		if (orig->se_lun_acl != NULL) {
+			pr_warn_ratelimited("Detected existing explicit"
+				" se_lun_acl->se_lun_group reference for %s"
+				" mapped_lun: %llu, failing\n",
+				 nacl->initiatorname, mapped_lun);
+			mutex_unlock(&nacl->lun_entry_mutex);
+			kfree(new);
+			return -EINVAL;
+		}
 
 		rcu_assign_pointer(new->se_lun, lun);
 		rcu_assign_pointer(new->se_lun_acl, lun_acl);
@@ -818,6 +831,7 @@
 	xcopy_lun = &dev->xcopy_lun;
 	rcu_assign_pointer(xcopy_lun->lun_se_dev, dev);
 	init_completion(&xcopy_lun->lun_ref_comp);
+	init_completion(&xcopy_lun->lun_shutdown_comp);
 	INIT_LIST_HEAD(&xcopy_lun->lun_deve_list);
 	INIT_LIST_HEAD(&xcopy_lun->lun_dev_link);
 	mutex_init(&xcopy_lun->lun_tg_pt_md_mutex);
@@ -826,6 +840,51 @@
 	return dev;
 }
 
+/*
+ * Check if the underlying struct block_device request_queue supports
+ * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
+ * in ATA and we need to set TPE=1
+ */
+bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
+				       struct request_queue *q)
+{
+	int block_size = queue_logical_block_size(q);
+
+	if (!blk_queue_discard(q))
+		return false;
+
+	attrib->max_unmap_lba_count =
+		q->limits.max_discard_sectors >> (ilog2(block_size) - 9);
+	/*
+	 * Currently hardcoded to 1 in Linux/SCSI code..
+	 */
+	attrib->max_unmap_block_desc_count = 1;
+	attrib->unmap_granularity = q->limits.discard_granularity / block_size;
+	attrib->unmap_granularity_alignment = q->limits.discard_alignment /
+								block_size;
+	return true;
+}
+EXPORT_SYMBOL(target_configure_unmap_from_queue);
+
+/*
+ * Convert from blocksize advertised to the initiator to the 512 byte
+ * units unconditionally used by the Linux block layer.
+ */
+sector_t target_to_linux_sector(struct se_device *dev, sector_t lb)
+{
+	switch (dev->dev_attrib.block_size) {
+	case 4096:
+		return lb << 3;
+	case 2048:
+		return lb << 2;
+	case 1024:
+		return lb << 1;
+	default:
+		return lb;
+	}
+}
+EXPORT_SYMBOL(target_to_linux_sector);
+
 int target_configure_device(struct se_device *dev)
 {
 	struct se_hba *hba = dev->se_hba;
@@ -998,27 +1057,6 @@
 	unsigned char *cdb = cmd->t_task_cdb;
 
 	/*
-	 * 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.
-	 */
-	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;
-	}
-
-	/*
 	 * For REPORT LUNS we always need to emulate the response, for everything
 	 * else, pass it up.
 	 */
--- linux-4.4.0.orig/drivers/target/target_core_fabric_configfs.c
+++ linux-4.4.0/drivers/target/target_core_fabric_configfs.c
@@ -92,6 +92,11 @@
 		pr_err("Source se_lun->lun_se_dev does not exist\n");
 		return -EINVAL;
 	}
+	if (lun->lun_shutdown) {
+		pr_err("Unable to create mappedlun symlink because"
+			" lun->lun_shutdown=true\n");
+		return -EINVAL;
+	}
 	se_tpg = lun->lun_tpg;
 
 	nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item;
--- linux-4.4.0.orig/drivers/target/target_core_fabric_lib.c
+++ linux-4.4.0/drivers/target/target_core_fabric_lib.c
@@ -75,7 +75,7 @@
 	 * encoded TransportID.
 	 */
 	ptr = &se_nacl->initiatorname[0];
-	for (i = 0; i < 24; ) {
+	for (i = 0; i < 23; ) {
 		if (!strncmp(&ptr[i], ":", 1)) {
 			i++;
 			continue;
@@ -130,7 +130,7 @@
 	memset(buf + 8, 0, leading_zero_bytes);
 	rc = hex2bin(buf + 8 + leading_zero_bytes, p, count);
 	if (rc < 0) {
-		pr_debug("hex2bin failed for %s: %d\n", __func__, rc);
+		pr_debug("hex2bin failed for %s: %d\n", p, rc);
 		return rc;
 	}
 
--- linux-4.4.0.orig/drivers/target/target_core_file.c
+++ linux-4.4.0/drivers/target/target_core_file.c
@@ -160,25 +160,10 @@
 			" block_device blocks: %llu logical_block_size: %d\n",
 			dev_size, div_u64(dev_size, fd_dev->fd_block_size),
 			fd_dev->fd_block_size);
-		/*
-		 * Check if the underlying struct block_device request_queue supports
-		 * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
-		 * in ATA and we need to set TPE=1
-		 */
-		if (blk_queue_discard(q)) {
-			dev->dev_attrib.max_unmap_lba_count =
-				q->limits.max_discard_sectors;
-			/*
-			 * Currently hardcoded to 1 in Linux/SCSI code..
-			 */
-			dev->dev_attrib.max_unmap_block_desc_count = 1;
-			dev->dev_attrib.unmap_granularity =
-				q->limits.discard_granularity >> 9;
-			dev->dev_attrib.unmap_granularity_alignment =
-				q->limits.discard_alignment;
+
+		if (target_configure_unmap_from_queue(&dev->dev_attrib, q))
 			pr_debug("IFILE: BLOCK Discard support available,"
-					" disabled by default\n");
-		}
+				 " disabled by default\n");
 		/*
 		 * Enable write same emulation for IBLOCK and use 0xFFFF as
 		 * the smaller WRITE_SAME(10) only has a two-byte block count.
@@ -291,12 +276,11 @@
 	else
 		ret = vfs_iter_read(fd, &iter, &pos);
 
-	kfree(bvec);
-
 	if (is_write) {
 		if (ret < 0 || ret != data_length) {
 			pr_err("%s() write returned %d\n", __func__, ret);
-			return (ret < 0 ? ret : -EINVAL);
+			if (ret >= 0)
+				ret = -EINVAL;
 		}
 	} else {
 		/*
@@ -309,17 +293,29 @@
 				pr_err("%s() returned %d, expecting %u for "
 						"S_ISBLK\n", __func__, ret,
 						data_length);
-				return (ret < 0 ? ret : -EINVAL);
+				if (ret >= 0)
+					ret = -EINVAL;
 			}
 		} else {
 			if (ret < 0) {
 				pr_err("%s() returned %d for non S_ISBLK\n",
 						__func__, ret);
-				return ret;
+			} else if (ret != data_length) {
+				/*
+				 * Short read case:
+				 * Probably some one truncate file under us.
+				 * We must explicitly zero sg-pages to prevent
+				 * expose uninizialized pages to userspace.
+				 */
+				if (ret < data_length)
+					ret += iov_iter_zero(data_length - ret, &iter);
+				else
+					ret = -EINVAL;
 			}
 		}
 	}
-	return 1;
+	kfree(bvec);
+	return ret;
 }
 
 static sense_reason_t
@@ -481,6 +477,10 @@
 	struct inode *inode = file->f_mapping->host;
 	int ret;
 
+	if (!nolb) {
+		return 0;
+	}
+
 	if (cmd->se_dev->dev_attrib.pi_prot_type) {
 		ret = fd_do_prot_unmap(cmd, lba, nolb);
 		if (ret)
@@ -490,9 +490,12 @@
 	if (S_ISBLK(inode->i_mode)) {
 		/* The backend is block device, use discard */
 		struct block_device *bdev = inode->i_bdev;
+		struct se_device *dev = cmd->se_dev;
 
-		ret = blkdev_issue_discard(bdev, lba,
-				nolb, GFP_KERNEL, 0);
+		ret = blkdev_issue_discard(bdev,
+					   target_to_linux_sector(dev, lba),
+					   target_to_linux_sector(dev,  nolb),
+					   GFP_KERNEL, 0);
 		if (ret < 0) {
 			pr_warn("FILEIO: blkdev_issue_discard() failed: %d\n",
 				ret);
@@ -606,8 +609,7 @@
 	if (ret < 0)
 		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
-	if (ret)
-		target_complete_cmd(cmd, SAM_STAT_GOOD);
+	target_complete_cmd(cmd, SAM_STAT_GOOD);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/target/target_core_iblock.c
+++ linux-4.4.0/drivers/target/target_core_iblock.c
@@ -121,27 +121,10 @@
 	dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q);
 	dev->dev_attrib.hw_queue_depth = q->nr_requests;
 
-	/*
-	 * Check if the underlying struct block_device request_queue supports
-	 * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
-	 * in ATA and we need to set TPE=1
-	 */
-	if (blk_queue_discard(q)) {
-		dev->dev_attrib.max_unmap_lba_count =
-				q->limits.max_discard_sectors;
-
-		/*
-		 * Currently hardcoded to 1 in Linux/SCSI code..
-		 */
-		dev->dev_attrib.max_unmap_block_desc_count = 1;
-		dev->dev_attrib.unmap_granularity =
-				q->limits.discard_granularity >> 9;
-		dev->dev_attrib.unmap_granularity_alignment =
-				q->limits.discard_alignment;
-
+	if (target_configure_unmap_from_queue(&dev->dev_attrib, q))
 		pr_debug("IBLOCK: BLOCK Discard support available,"
-				" disabled by default\n");
-	}
+			 " disabled by default\n");
+
 	/*
 	 * Enable write same emulation for IBLOCK and use 0xFFFF as
 	 * the smaller WRITE_SAME(10) only has a two-byte block count.
@@ -413,9 +396,13 @@
 iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
 {
 	struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
+	struct se_device *dev = cmd->se_dev;
 	int ret;
 
-	ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0);
+	ret = blkdev_issue_discard(bdev,
+				   target_to_linux_sector(dev, lba),
+				   target_to_linux_sector(dev,  nolb),
+				   GFP_KERNEL, 0);
 	if (ret < 0) {
 		pr_err("blkdev_issue_discard() failed: %d\n", ret);
 		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -431,8 +418,10 @@
 	struct scatterlist *sg;
 	struct bio *bio;
 	struct bio_list list;
-	sector_t block_lba = cmd->t_task_lba;
-	sector_t sectors = sbc_get_write_same_sectors(cmd);
+	struct se_device *dev = cmd->se_dev;
+	sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba);
+	sector_t sectors = target_to_linux_sector(dev,
+					sbc_get_write_same_sectors(cmd));
 
 	if (cmd->prot_op) {
 		pr_err("WRITE_SAME: Protection information with IBLOCK"
@@ -613,9 +602,9 @@
 	}
 
 	bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents);
-	if (!bip) {
+	if (IS_ERR(bip)) {
 		pr_err("Unable to allocate bio_integrity_payload\n");
-		return -ENOMEM;
+		return PTR_ERR(bip);
 	}
 
 	bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) *
@@ -646,12 +635,12 @@
 		  enum dma_data_direction data_direction)
 {
 	struct se_device *dev = cmd->se_dev;
+	sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba);
 	struct iblock_req *ibr;
 	struct bio *bio, *bio_start;
 	struct bio_list list;
 	struct scatterlist *sg;
 	u32 sg_num = sgl_nents;
-	sector_t block_lba;
 	unsigned bio_cnt;
 	int rw = 0;
 	int i;
@@ -677,24 +666,6 @@
 		rw = READ;
 	}
 
-	/*
-	 * Convert the blocksize advertised to the initiator to the 512 byte
-	 * units unconditionally used by the Linux block layer.
-	 */
-	if (dev->dev_attrib.block_size == 4096)
-		block_lba = (cmd->t_task_lba << 3);
-	else if (dev->dev_attrib.block_size == 2048)
-		block_lba = (cmd->t_task_lba << 2);
-	else if (dev->dev_attrib.block_size == 1024)
-		block_lba = (cmd->t_task_lba << 1);
-	else if (dev->dev_attrib.block_size == 512)
-		block_lba = cmd->t_task_lba;
-	else {
-		pr_err("Unsupported SCSI -> BLOCK LBA conversion:"
-				" %u\n", dev->dev_attrib.block_size);
-		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-	}
-
 	ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
 	if (!ibr)
 		goto fail;
--- linux-4.4.0.orig/drivers/target/target_core_internal.h
+++ linux-4.4.0/drivers/target/target_core_internal.h
@@ -132,7 +132,7 @@
 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);
+int	transport_cmd_finish_abort(struct se_cmd *, int);
 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 *,
@@ -148,6 +148,7 @@
 void	target_qf_do_work(struct work_struct *work);
 bool	target_check_wce(struct se_device *dev);
 bool	target_check_fua(struct se_device *dev);
+void	__target_execute_cmd(struct se_cmd *, bool);
 
 /* target_core_stat.c */
 void	target_stat_setup_dev_default_groups(struct se_device *);
--- linux-4.4.0.orig/drivers/target/target_core_pr.c
+++ linux-4.4.0/drivers/target/target_core_pr.c
@@ -56,8 +56,10 @@
 	char *buf,
 	u32 size)
 {
-	if (!pr_reg->isid_present_at_reg)
+	if (!pr_reg->isid_present_at_reg) {
 		buf[0] = '\0';
+		return;
+	}
 
 	snprintf(buf, size, ",i,0x%s", pr_reg->pr_reg_isid);
 }
--- linux-4.4.0.orig/drivers/target/target_core_pscsi.c
+++ linux-4.4.0/drivers/target/target_core_pscsi.c
@@ -154,7 +154,7 @@
 
 	buf = kzalloc(12, GFP_KERNEL);
 	if (!buf)
-		return;
+		goto out_free;
 
 	memset(cdb, 0, MAX_COMMAND_SIZE);
 	cdb[0] = MODE_SENSE;
@@ -169,9 +169,10 @@
 	 * If MODE_SENSE still returns zero, set the default value to 1024.
 	 */
 	sdev->sector_size = (buf[9] << 16) | (buf[10] << 8) | (buf[11]);
+out_free:
 	if (!sdev->sector_size)
 		sdev->sector_size = 1024;
-out_free:
+
 	kfree(buf);
 }
 
@@ -314,9 +315,10 @@
 				sd->lun, sd->queue_depth);
 	}
 
-	dev->dev_attrib.hw_block_size = sd->sector_size;
+	dev->dev_attrib.hw_block_size =
+		min_not_zero((int)sd->sector_size, 512);
 	dev->dev_attrib.hw_max_sectors =
-		min_t(int, sd->host->max_sectors, queue_max_hw_sectors(q));
+		min_not_zero(sd->host->max_sectors, queue_max_hw_sectors(q));
 	dev->dev_attrib.hw_queue_depth = sd->queue_depth;
 
 	/*
@@ -339,8 +341,10 @@
 	/*
 	 * For TYPE_TAPE, attempt to determine blocksize with MODE_SENSE.
 	 */
-	if (sd->type == TYPE_TAPE)
+	if (sd->type == TYPE_TAPE) {
 		pscsi_tape_read_blocksize(dev, sd);
+		dev->dev_attrib.hw_block_size = sd->sector_size;
+	}
 	return 0;
 }
 
@@ -406,7 +410,7 @@
 /*
  * Called with struct Scsi_Host->host_lock called.
  */
-static int pscsi_create_type_rom(struct se_device *dev, struct scsi_device *sd)
+static int pscsi_create_type_nondisk(struct se_device *dev, struct scsi_device *sd)
 	__releases(sh->host_lock)
 {
 	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;
@@ -433,28 +437,6 @@
 	return 0;
 }
 
-/*
- * Called with struct Scsi_Host->host_lock called.
- */
-static int pscsi_create_type_other(struct se_device *dev,
-		struct scsi_device *sd)
-	__releases(sh->host_lock)
-{
-	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;
-	struct Scsi_Host *sh = sd->host;
-	int ret;
-
-	spin_unlock_irq(sh->host_lock);
-	ret = pscsi_add_device_to_list(dev, sd);
-	if (ret)
-		return ret;
-
-	pr_debug("CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%llu\n",
-		phv->phv_host_id, scsi_device_type(sd->type), sh->host_no,
-		sd->channel, sd->id, sd->lun);
-	return 0;
-}
-
 static int pscsi_configure_device(struct se_device *dev)
 {
 	struct se_hba *hba = dev->se_hba;
@@ -542,11 +524,8 @@
 		case TYPE_DISK:
 			ret = pscsi_create_type_disk(dev, sd);
 			break;
-		case TYPE_ROM:
-			ret = pscsi_create_type_rom(dev, sd);
-			break;
 		default:
-			ret = pscsi_create_type_other(dev, sd);
+			ret = pscsi_create_type_nondisk(dev, sd);
 			break;
 		}
 
@@ -611,8 +590,7 @@
 		else if (pdv->pdv_lld_host)
 			scsi_host_put(pdv->pdv_lld_host);
 
-		if ((sd->type == TYPE_DISK) || (sd->type == TYPE_ROM))
-			scsi_device_put(sd);
+		scsi_device_put(sd);
 
 		pdv->pdv_sd = NULL;
 	}
@@ -1088,7 +1066,6 @@
 	if (pdv->pdv_bd && pdv->pdv_bd->bd_part)
 		return pdv->pdv_bd->bd_part->nr_sects;
 
-	dump_stack();
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/target/target_core_sbc.c
+++ linux-4.4.0/drivers/target/target_core_sbc.c
@@ -442,6 +442,7 @@
 					     int *post_ret)
 {
 	struct se_device *dev = cmd->se_dev;
+	sense_reason_t ret = TCM_NO_SENSE;
 
 	/*
 	 * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through
@@ -449,9 +450,12 @@
 	 * sent to the backend driver.
 	 */
 	spin_lock_irq(&cmd->t_state_lock);
-	if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) {
+	if (cmd->transport_state & CMD_T_SENT) {
 		cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
 		*post_ret = 1;
+
+		if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION)
+			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 	}
 	spin_unlock_irq(&cmd->t_state_lock);
 
@@ -461,7 +465,7 @@
 	 */
 	up(&dev->caw_sem);
 
-	return TCM_NO_SENSE;
+	return ret;
 }
 
 static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success,
@@ -494,8 +498,11 @@
 	 * been failed with a non-zero SCSI status.
 	 */
 	if (cmd->scsi_status) {
-		pr_err("compare_and_write_callback: non zero scsi_status:"
+		pr_debug("compare_and_write_callback: non zero scsi_status:"
 			" 0x%02x\n", cmd->scsi_status);
+		*post_ret = 1;
+		if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION)
+			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 		goto out;
 	}
 
@@ -594,7 +601,7 @@
 	cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
 	spin_unlock_irq(&cmd->t_state_lock);
 
-	__target_execute_cmd(cmd);
+	__target_execute_cmd(cmd, false);
 
 	kfree(buf);
 	return ret;
@@ -1092,9 +1099,15 @@
 			return ret;
 		break;
 	case VERIFY:
+	case VERIFY_16:
 		size = 0;
-		sectors = transport_get_sectors_10(cdb);
-		cmd->t_task_lba = transport_lba_32(cdb);
+		if (cdb[0] == VERIFY) {
+			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);
+		}
 		cmd->execute_cmd = sbc_emulate_noop;
 		goto check_lba;
 	case REZERO_UNIT:
--- linux-4.4.0.orig/drivers/target/target_core_spc.c
+++ linux-4.4.0/drivers/target/target_core_spc.c
@@ -108,12 +108,17 @@
 
 	buf[7] = 0x2; /* CmdQue=1 */
 
-	memcpy(&buf[8], "LIO-ORG ", 8);
-	memset(&buf[16], 0x20, 16);
+	/*
+	 * ASCII data fields described as being left-aligned shall have any
+	 * unused bytes at the end of the field (i.e., highest offset) and the
+	 * unused bytes shall be filled with ASCII space characters (20h).
+	 */
+	memset(&buf[8], 0x20, 8 + 16 + 4);
+	memcpy(&buf[8], "LIO-ORG", sizeof("LIO-ORG") - 1);
 	memcpy(&buf[16], dev->t10_wwn.model,
-	       min_t(size_t, strlen(dev->t10_wwn.model), 16));
+	       strnlen(dev->t10_wwn.model, 16));
 	memcpy(&buf[32], dev->t10_wwn.revision,
-	       min_t(size_t, strlen(dev->t10_wwn.revision), 4));
+	       strnlen(dev->t10_wwn.revision, 4));
 	buf[4] = 31; /* Set additional length to 31 */
 
 	return 0;
@@ -251,7 +256,9 @@
 	buf[off] = 0x2; /* ASCII */
 	buf[off+1] = 0x1; /* T10 Vendor ID */
 	buf[off+2] = 0x0;
-	memcpy(&buf[off+4], "LIO-ORG", 8);
+	/* left align Vendor ID and pad with spaces */
+	memset(&buf[off+4], 0x20, 8);
+	memcpy(&buf[off+4], "LIO-ORG", sizeof("LIO-ORG") - 1);
 	/* Extra Byte for NULL Terminator */
 	id_len++;
 	/* Identifier Length */
--- linux-4.4.0.orig/drivers/target/target_core_tmr.c
+++ linux-4.4.0/drivers/target/target_core_tmr.c
@@ -68,28 +68,30 @@
 
 	if (dev) {
 		spin_lock_irqsave(&dev->se_tmr_lock, flags);
-		list_del(&tmr->tmr_list);
+		list_del_init(&tmr->tmr_list);
 		spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
 	}
 
 	kfree(tmr);
 }
 
-static void core_tmr_handle_tas_abort(
-	struct se_node_acl *tmr_nacl,
-	struct se_cmd *cmd,
-	int tas)
+static int core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas)
 {
-	bool remove = true;
+	unsigned long flags;
+	bool remove = true, send_tas;
 	/*
 	 * TASK ABORTED status (TAS) bit support
 	 */
-	if ((tmr_nacl && (tmr_nacl != cmd->se_sess->se_node_acl)) && tas) {
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	send_tas = (cmd->transport_state & CMD_T_TAS);
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
+	if (send_tas) {
 		remove = false;
 		transport_send_task_abort(cmd);
 	}
 
-	transport_cmd_finish_abort(cmd, remove);
+	return transport_cmd_finish_abort(cmd, remove);
 }
 
 static int target_check_cdb_and_preempt(struct list_head *list,
@@ -107,6 +109,55 @@
 	return 1;
 }
 
+static bool __target_check_io_state(struct se_cmd *se_cmd,
+				    struct se_session *tmr_sess, int tas)
+{
+	struct se_session *sess = se_cmd->se_sess;
+
+	assert_spin_locked(&sess->sess_cmd_lock);
+	WARN_ON_ONCE(!irqs_disabled());
+	/*
+	 * If command already reached CMD_T_COMPLETE state within
+	 * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown,
+	 * this se_cmd has been passed to fabric driver and will
+	 * not be aborted.
+	 *
+	 * Otherwise, obtain a local se_cmd->cmd_kref now for TMR
+	 * ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as
+	 * long as se_cmd->cmd_kref is still active unless zero.
+	 */
+	spin_lock(&se_cmd->t_state_lock);
+	if (se_cmd->transport_state & (CMD_T_COMPLETE | CMD_T_FABRIC_STOP)) {
+		pr_debug("Attempted to abort io tag: %llu already complete or"
+			" fabric stop, skipping\n", se_cmd->tag);
+		spin_unlock(&se_cmd->t_state_lock);
+		return false;
+	}
+	if (se_cmd->transport_state & CMD_T_PRE_EXECUTE) {
+		if (se_cmd->scsi_status) {
+			pr_debug("Attempted to abort io tag: %llu early failure"
+				 " status: 0x%02x\n", se_cmd->tag,
+				 se_cmd->scsi_status);
+			spin_unlock(&se_cmd->t_state_lock);
+			return false;
+		}
+	}
+	if (sess->sess_tearing_down || se_cmd->cmd_wait_set) {
+		pr_debug("Attempted to abort io tag: %llu already shutdown,"
+			" skipping\n", se_cmd->tag);
+		spin_unlock(&se_cmd->t_state_lock);
+		return false;
+	}
+	se_cmd->transport_state |= CMD_T_ABORTED;
+
+	if ((tmr_sess != se_cmd->se_sess) && tas)
+		se_cmd->transport_state |= CMD_T_TAS;
+
+	spin_unlock(&se_cmd->t_state_lock);
+
+	return kref_get_unless_zero(&se_cmd->cmd_kref);
+}
+
 void core_tmr_abort_task(
 	struct se_device *dev,
 	struct se_tmr_req *tmr,
@@ -130,34 +181,21 @@
 		if (tmr->ref_task_tag != ref_tag)
 			continue;
 
-		if (!kref_get_unless_zero(&se_cmd->cmd_kref))
-			continue;
-
 		printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
 			se_cmd->se_tfo->get_fabric_name(), ref_tag);
 
-		spin_lock(&se_cmd->t_state_lock);
-		if (se_cmd->transport_state & CMD_T_COMPLETE) {
-			printk("ABORT_TASK: ref_tag: %llu already complete,"
-			       " skipping\n", ref_tag);
-			spin_unlock(&se_cmd->t_state_lock);
+		if (!__target_check_io_state(se_cmd, se_sess, 0)) {
 			spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-
-			target_put_sess_cmd(se_cmd);
-
 			goto out;
 		}
-		se_cmd->transport_state |= CMD_T_ABORTED;
-		spin_unlock(&se_cmd->t_state_lock);
-
 		list_del_init(&se_cmd->se_cmd_list);
 		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
 		cancel_work_sync(&se_cmd->work);
 		transport_wait_for_tasks(se_cmd);
 
-		target_put_sess_cmd(se_cmd);
-		transport_cmd_finish_abort(se_cmd, true);
+		if (!transport_cmd_finish_abort(se_cmd, true))
+			target_put_sess_cmd(se_cmd);
 
 		printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
 				" ref_tag: %llu\n", ref_tag);
@@ -178,9 +216,11 @@
 	struct list_head *preempt_and_abort_list)
 {
 	LIST_HEAD(drain_tmr_list);
+	struct se_session *sess;
 	struct se_tmr_req *tmr_p, *tmr_pp;
 	struct se_cmd *cmd;
 	unsigned long flags;
+	bool rc;
 	/*
 	 * Release all pending and outgoing TMRs aside from the received
 	 * LUN_RESET tmr..
@@ -206,17 +246,39 @@
 		if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
 			continue;
 
+		sess = cmd->se_sess;
+		if (WARN_ON_ONCE(!sess))
+			continue;
+
+		spin_lock(&sess->sess_cmd_lock);
 		spin_lock(&cmd->t_state_lock);
-		if (!(cmd->transport_state & CMD_T_ACTIVE)) {
+		if (!(cmd->transport_state & CMD_T_ACTIVE) ||
+		     (cmd->transport_state & CMD_T_FABRIC_STOP)) {
 			spin_unlock(&cmd->t_state_lock);
+			spin_unlock(&sess->sess_cmd_lock);
 			continue;
 		}
 		if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
 			spin_unlock(&cmd->t_state_lock);
+			spin_unlock(&sess->sess_cmd_lock);
 			continue;
 		}
+		if (sess->sess_tearing_down || cmd->cmd_wait_set) {
+			spin_unlock(&cmd->t_state_lock);
+			spin_unlock(&sess->sess_cmd_lock);
+			continue;
+		}
+		cmd->transport_state |= CMD_T_ABORTED;
 		spin_unlock(&cmd->t_state_lock);
 
+		rc = kref_get_unless_zero(&cmd->cmd_kref);
+		if (!rc) {
+			printk("LUN_RESET TMR: non-zero kref_get_unless_zero\n");
+			spin_unlock(&sess->sess_cmd_lock);
+			continue;
+		}
+		spin_unlock(&sess->sess_cmd_lock);
+
 		list_move_tail(&tmr_p->tmr_list, &drain_tmr_list);
 	}
 	spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
@@ -230,20 +292,26 @@
 			(preempt_and_abort_list) ? "Preempt" : "", tmr_p,
 			tmr_p->function, tmr_p->response, cmd->t_state);
 
-		transport_cmd_finish_abort(cmd, 1);
+		cancel_work_sync(&cmd->work);
+		transport_wait_for_tasks(cmd);
+
+		if (!transport_cmd_finish_abort(cmd, 1))
+			target_put_sess_cmd(cmd);
 	}
 }
 
 static void core_tmr_drain_state_list(
 	struct se_device *dev,
 	struct se_cmd *prout_cmd,
-	struct se_node_acl *tmr_nacl,
+	struct se_session *tmr_sess,
 	int tas,
 	struct list_head *preempt_and_abort_list)
 {
 	LIST_HEAD(drain_task_list);
+	struct se_session *sess;
 	struct se_cmd *cmd, *next;
 	unsigned long flags;
+	int rc;
 
 	/*
 	 * Complete outstanding commands with TASK_ABORTED SAM status.
@@ -282,6 +350,16 @@
 		if (prout_cmd == cmd)
 			continue;
 
+		sess = cmd->se_sess;
+		if (WARN_ON_ONCE(!sess))
+			continue;
+
+		spin_lock(&sess->sess_cmd_lock);
+		rc = __target_check_io_state(cmd, tmr_sess, tas);
+		spin_unlock(&sess->sess_cmd_lock);
+		if (!rc)
+			continue;
+
 		list_move_tail(&cmd->state_list, &drain_task_list);
 		cmd->state_active = false;
 	}
@@ -289,7 +367,7 @@
 
 	while (!list_empty(&drain_task_list)) {
 		cmd = list_entry(drain_task_list.next, struct se_cmd, state_list);
-		list_del(&cmd->state_list);
+		list_del_init(&cmd->state_list);
 
 		pr_debug("LUN_RESET: %s cmd: %p"
 			" ITT/CmdSN: 0x%08llx/0x%08x, i_state: %d, t_state: %d"
@@ -313,16 +391,11 @@
 		 * loop above, but we do it down here given that
 		 * cancel_work_sync may block.
 		 */
-		if (cmd->t_state == TRANSPORT_COMPLETE)
-			cancel_work_sync(&cmd->work);
-
-		spin_lock_irqsave(&cmd->t_state_lock, flags);
-		target_stop_cmd(cmd, &flags);
-
-		cmd->transport_state |= CMD_T_ABORTED;
-		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+		cancel_work_sync(&cmd->work);
+		transport_wait_for_tasks(cmd);
 
-		core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
+		if (!core_tmr_handle_tas_abort(cmd, tas))
+			target_put_sess_cmd(cmd);
 	}
 }
 
@@ -334,6 +407,7 @@
 {
 	struct se_node_acl *tmr_nacl = NULL;
 	struct se_portal_group *tmr_tpg = NULL;
+	struct se_session *tmr_sess = NULL;
 	int tas;
         /*
 	 * TASK_ABORTED status bit, this is configurable via ConfigFS
@@ -352,8 +426,9 @@
 	 * or struct se_device passthrough..
 	 */
 	if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
-		tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
-		tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
+		tmr_sess = tmr->task_cmd->se_sess;
+		tmr_nacl = tmr_sess->se_node_acl;
+		tmr_tpg = tmr_sess->se_tpg;
 		if (tmr_nacl && tmr_tpg) {
 			pr_debug("LUN_RESET: TMR caller fabric: %s"
 				" initiator port %s\n",
@@ -366,7 +441,7 @@
 		dev->transport->name, tas);
 
 	core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list);
-	core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas,
+	core_tmr_drain_state_list(dev, prout_cmd, tmr_sess, tas,
 				preempt_and_abort_list);
 
 	/*
--- linux-4.4.0.orig/drivers/target/target_core_tpg.c
+++ linux-4.4.0/drivers/target/target_core_tpg.c
@@ -75,9 +75,21 @@
 	unsigned char *initiatorname)
 {
 	struct se_node_acl *acl;
-
+	/*
+	 * Obtain se_node_acl->acl_kref using fabric driver provided
+	 * initiatorname[] during node acl endpoint lookup driven by
+	 * new se_session login.
+	 *
+	 * The reference is held until se_session shutdown -> release
+	 * occurs via fabric driver invoked transport_deregister_session()
+	 * or transport_free_session() code.
+	 */
 	mutex_lock(&tpg->acl_node_mutex);
 	acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
+	if (acl) {
+		if (!kref_get_unless_zero(&acl->acl_kref))
+			acl = NULL;
+	}
 	mutex_unlock(&tpg->acl_node_mutex);
 
 	return acl;
@@ -157,28 +169,25 @@
 	mutex_unlock(&tpg->tpg_lun_mutex);
 }
 
-/*      core_set_queue_depth_for_node():
- *
- *
- */
-static int core_set_queue_depth_for_node(
-	struct se_portal_group *tpg,
-	struct se_node_acl *acl)
+static void
+target_set_nacl_queue_depth(struct se_portal_group *tpg,
+			    struct se_node_acl *acl, u32 queue_depth)
 {
+	acl->queue_depth = queue_depth;
+
 	if (!acl->queue_depth) {
-		pr_err("Queue depth for %s Initiator Node: %s is 0,"
+		pr_warn("Queue depth for %s Initiator Node: %s is 0,"
 			"defaulting to 1.\n", tpg->se_tpg_tfo->get_fabric_name(),
 			acl->initiatorname);
 		acl->queue_depth = 1;
 	}
-
-	return 0;
 }
 
 static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg,
 		const unsigned char *initiatorname)
 {
 	struct se_node_acl *acl;
+	u32 queue_depth;
 
 	acl = kzalloc(max(sizeof(*acl), tpg->se_tpg_tfo->node_acl_size),
 			GFP_KERNEL);
@@ -193,24 +202,20 @@
 	spin_lock_init(&acl->nacl_sess_lock);
 	mutex_init(&acl->lun_entry_mutex);
 	atomic_set(&acl->acl_pr_ref_count, 0);
+
 	if (tpg->se_tpg_tfo->tpg_get_default_depth)
-		acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg);
+		queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg);
 	else
-		acl->queue_depth = 1;
+		queue_depth = 1;
+	target_set_nacl_queue_depth(tpg, acl, queue_depth);
+
 	snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
 	acl->se_tpg = tpg;
 	acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX);
 
 	tpg->se_tpg_tfo->set_default_node_attributes(acl);
 
-	if (core_set_queue_depth_for_node(tpg, acl) < 0)
-		goto out_free_acl;
-
 	return acl;
-
-out_free_acl:
-	kfree(acl);
-	return NULL;
 }
 
 static void target_add_node_acl(struct se_node_acl *acl)
@@ -232,6 +237,25 @@
 		acl->initiatorname);
 }
 
+bool target_tpg_has_node_acl(struct se_portal_group *tpg,
+			     const char *initiatorname)
+{
+	struct se_node_acl *acl;
+	bool found = false;
+
+	mutex_lock(&tpg->acl_node_mutex);
+	list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+		if (!strcmp(acl->initiatorname, initiatorname)) {
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&tpg->acl_node_mutex);
+
+	return found;
+}
+EXPORT_SYMBOL(target_tpg_has_node_acl);
+
 struct se_node_acl *core_tpg_check_initiator_node_acl(
 	struct se_portal_group *tpg,
 	unsigned char *initiatorname)
@@ -248,6 +272,15 @@
 	acl = target_alloc_node_acl(tpg, initiatorname);
 	if (!acl)
 		return NULL;
+	/*
+	 * When allocating a dynamically generated node_acl, go ahead
+	 * and take the extra kref now before returning to the fabric
+	 * driver caller.
+	 *
+	 * Note this reference will be released at session shutdown
+	 * time within transport_free_session() code.
+	 */
+	kref_get(&acl->acl_kref);
 	acl->dynamic_node_acl = 1;
 
 	/*
@@ -317,7 +350,7 @@
 	if (acl->dynamic_node_acl) {
 		acl->dynamic_node_acl = 0;
 	}
-	list_del(&acl->acl_list);
+	list_del_init(&acl->acl_list);
 	tpg->num_node_acls--;
 	mutex_unlock(&tpg->acl_node_mutex);
 
@@ -329,7 +362,8 @@
 		if (sess->sess_tearing_down != 0)
 			continue;
 
-		target_get_session(sess);
+		if (!target_get_session(sess))
+			continue;
 		list_move(&sess->sess_acl_list, &sess_list);
 	}
 	spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
@@ -366,108 +400,52 @@
  *
  */
 int core_tpg_set_initiator_node_queue_depth(
-	struct se_portal_group *tpg,
-	unsigned char *initiatorname,
-	u32 queue_depth,
-	int force)
+	struct se_node_acl *acl,
+	u32 queue_depth)
 {
-	struct se_session *sess, *init_sess = NULL;
-	struct se_node_acl *acl;
+	LIST_HEAD(sess_list);
+	struct se_portal_group *tpg = acl->se_tpg;
+	struct se_session *sess, *sess_tmp;
 	unsigned long flags;
-	int dynamic_acl = 0;
-
-	mutex_lock(&tpg->acl_node_mutex);
-	acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
-	if (!acl) {
-		pr_err("Access Control List entry for %s Initiator"
-			" Node %s does not exists for TPG %hu, ignoring"
-			" request.\n", tpg->se_tpg_tfo->get_fabric_name(),
-			initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg));
-		mutex_unlock(&tpg->acl_node_mutex);
-		return -ENODEV;
-	}
-	if (acl->dynamic_node_acl) {
-		acl->dynamic_node_acl = 0;
-		dynamic_acl = 1;
-	}
-	mutex_unlock(&tpg->acl_node_mutex);
-
-	spin_lock_irqsave(&tpg->session_lock, flags);
-	list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) {
-		if (sess->se_node_acl != acl)
-			continue;
-
-		if (!force) {
-			pr_err("Unable to change queue depth for %s"
-				" Initiator Node: %s while session is"
-				" operational.  To forcefully change the queue"
-				" depth and force session reinstatement"
-				" use the \"force=1\" parameter.\n",
-				tpg->se_tpg_tfo->get_fabric_name(), initiatorname);
-			spin_unlock_irqrestore(&tpg->session_lock, flags);
-
-			mutex_lock(&tpg->acl_node_mutex);
-			if (dynamic_acl)
-				acl->dynamic_node_acl = 1;
-			mutex_unlock(&tpg->acl_node_mutex);
-			return -EEXIST;
-		}
-		/*
-		 * Determine if the session needs to be closed by our context.
-		 */
-		if (!tpg->se_tpg_tfo->shutdown_session(sess))
-			continue;
-
-		init_sess = sess;
-		break;
-	}
+	int rc;
 
 	/*
 	 * User has requested to change the queue depth for a Initiator Node.
 	 * Change the value in the Node's struct se_node_acl, and call
-	 * core_set_queue_depth_for_node() to add the requested queue depth.
-	 *
-	 * Finally call  tpg->se_tpg_tfo->close_session() to force session
-	 * reinstatement to occur if there is an active session for the
-	 * $FABRIC_MOD Initiator Node in question.
+	 * target_set_nacl_queue_depth() to set the new queue depth.
 	 */
-	acl->queue_depth = queue_depth;
+	target_set_nacl_queue_depth(tpg, acl, queue_depth);
+
+	spin_lock_irqsave(&acl->nacl_sess_lock, flags);
+	list_for_each_entry_safe(sess, sess_tmp, &acl->acl_sess_list,
+				 sess_acl_list) {
+		if (sess->sess_tearing_down != 0)
+			continue;
+		if (!target_get_session(sess))
+			continue;
+		spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
 
-	if (core_set_queue_depth_for_node(tpg, acl) < 0) {
-		spin_unlock_irqrestore(&tpg->session_lock, flags);
 		/*
-		 * Force session reinstatement if
-		 * core_set_queue_depth_for_node() failed, because we assume
-		 * the $FABRIC_MOD has already the set session reinstatement
-		 * bit from tpg->se_tpg_tfo->shutdown_session() called above.
+		 * Finally call tpg->se_tpg_tfo->close_session() to force session
+		 * reinstatement to occur if there is an active session for the
+		 * $FABRIC_MOD Initiator Node in question.
 		 */
-		if (init_sess)
-			tpg->se_tpg_tfo->close_session(init_sess);
-
-		mutex_lock(&tpg->acl_node_mutex);
-		if (dynamic_acl)
-			acl->dynamic_node_acl = 1;
-		mutex_unlock(&tpg->acl_node_mutex);
-		return -EINVAL;
+		rc = tpg->se_tpg_tfo->shutdown_session(sess);
+		target_put_session(sess);
+		if (!rc) {
+			spin_lock_irqsave(&acl->nacl_sess_lock, flags);
+			continue;
+		}
+		target_put_session(sess);
+		spin_lock_irqsave(&acl->nacl_sess_lock, flags);
 	}
-	spin_unlock_irqrestore(&tpg->session_lock, flags);
-	/*
-	 * If the $FABRIC_MOD session for the Initiator Node ACL exists,
-	 * forcefully shutdown the $FABRIC_MOD session/nexus.
-	 */
-	if (init_sess)
-		tpg->se_tpg_tfo->close_session(init_sess);
+	spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
 
 	pr_debug("Successfully changed queue depth to: %d for Initiator"
-		" Node: %s on %s Target Portal Group: %u\n", queue_depth,
-		initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
+		" Node: %s on %s Target Portal Group: %u\n", acl->queue_depth,
+		acl->initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
 		tpg->se_tpg_tfo->tpg_get_tag(tpg));
 
-	mutex_lock(&tpg->acl_node_mutex);
-	if (dynamic_acl)
-		acl->dynamic_node_acl = 1;
-	mutex_unlock(&tpg->acl_node_mutex);
-
 	return 0;
 }
 EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth);
@@ -499,7 +477,7 @@
 {
 	struct se_lun *lun = container_of(ref, struct se_lun, lun_ref);
 
-	complete(&lun->lun_ref_comp);
+	complete(&lun->lun_shutdown_comp);
 }
 
 int core_tpg_register(
@@ -594,7 +572,7 @@
 	 * in transport_deregister_session().
 	 */
 	list_for_each_entry_safe(nacl, nacl_tmp, &node_list, acl_list) {
-		list_del(&nacl->acl_list);
+		list_del_init(&nacl->acl_list);
 		se_tpg->num_node_acls--;
 
 		core_tpg_wait_for_nacl_pr_ref(nacl);
@@ -626,6 +604,7 @@
 	lun->lun_link_magic = SE_LUN_LINK_MAGIC;
 	atomic_set(&lun->lun_acl_count, 0);
 	init_completion(&lun->lun_ref_comp);
+	init_completion(&lun->lun_shutdown_comp);
 	INIT_LIST_HEAD(&lun->lun_deve_list);
 	INIT_LIST_HEAD(&lun->lun_dev_link);
 	atomic_set(&lun->lun_tg_pt_secondary_offline, 0);
@@ -694,6 +673,8 @@
 	 */
 	struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev);
 
+	lun->lun_shutdown = true;
+
 	core_clear_lun_from_tpg(lun, tpg);
 	/*
 	 * Wait for any active I/O references to percpu se_lun->lun_ref to
@@ -715,6 +696,8 @@
 	}
 	if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
 		hlist_del_rcu(&lun->link);
+
+	lun->lun_shutdown = false;
 	mutex_unlock(&tpg->tpg_lun_mutex);
 
 	percpu_ref_exit(&lun->lun_ref);
--- linux-4.4.0.orig/drivers/target/target_core_transport.c
+++ linux-4.4.0/drivers/target/target_core_transport.c
@@ -281,6 +281,17 @@
 	struct se_session *se_sess;
 	int rc;
 
+	if (tag_num != 0 && !tag_size) {
+		pr_err("init_session_tags called with percpu-ida tag_num:"
+		       " %u, but zero tag_size\n", tag_num);
+		return ERR_PTR(-EINVAL);
+	}
+	if (!tag_num && tag_size) {
+		pr_err("init_session_tags called with percpu-ida tag_size:"
+		       " %u, but zero tag_num\n", tag_size);
+		return ERR_PTR(-EINVAL);
+	}
+
 	se_sess = transport_init_session(sup_prot_ops);
 	if (IS_ERR(se_sess))
 		return se_sess;
@@ -306,6 +317,7 @@
 {
 	const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo;
 	unsigned char buf[PR_REG_ISID_LEN];
+	unsigned long flags;
 
 	se_sess->se_tpg = se_tpg;
 	se_sess->fabric_sess_ptr = fabric_sess_ptr;
@@ -341,9 +353,8 @@
 					&buf[0], PR_REG_ISID_LEN);
 			se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]);
 		}
-		kref_get(&se_nacl->acl_kref);
 
-		spin_lock_irq(&se_nacl->nacl_sess_lock);
+		spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags);
 		/*
 		 * The se_nacl->nacl_sess pointer will be set to the
 		 * last active I_T Nexus for each struct se_node_acl.
@@ -352,7 +363,7 @@
 
 		list_add_tail(&se_sess->sess_acl_list,
 			      &se_nacl->acl_sess_list);
-		spin_unlock_irq(&se_nacl->nacl_sess_lock);
+		spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags);
 	}
 	list_add_tail(&se_sess->sess_list, &se_tpg->tpg_sess_list);
 
@@ -375,6 +386,51 @@
 }
 EXPORT_SYMBOL(transport_register_session);
 
+struct se_session *
+target_alloc_session(struct se_portal_group *tpg,
+		     unsigned int tag_num, unsigned int tag_size,
+		     enum target_prot_op prot_op,
+		     const char *initiatorname, void *private,
+		     int (*callback)(struct se_portal_group *,
+				     struct se_session *, void *))
+{
+	struct se_session *sess;
+
+	/*
+	 * If the fabric driver is using percpu-ida based pre allocation
+	 * of I/O descriptor tags, go ahead and perform that setup now..
+	 */
+	if (tag_num != 0)
+		sess = transport_init_session_tags(tag_num, tag_size, prot_op);
+	else
+		sess = transport_init_session(prot_op);
+
+	if (IS_ERR(sess))
+		return sess;
+
+	sess->se_node_acl = core_tpg_check_initiator_node_acl(tpg,
+					(unsigned char *)initiatorname);
+	if (!sess->se_node_acl) {
+		transport_free_session(sess);
+		return ERR_PTR(-EACCES);
+	}
+	/*
+	 * Go ahead and perform any remaining fabric setup that is
+	 * required before transport_register_session().
+	 */
+	if (callback != NULL) {
+		int rc = callback(tpg, sess, private);
+		if (rc) {
+			transport_free_session(sess);
+			return ERR_PTR(rc);
+		}
+	}
+
+	transport_register_session(tpg, sess->se_node_acl, sess, private);
+	return sess;
+}
+EXPORT_SYMBOL(target_alloc_session);
+
 static void target_release_session(struct kref *kref)
 {
 	struct se_session *se_sess = container_of(kref,
@@ -384,9 +440,9 @@
 	se_tpg->se_tpg_tfo->close_session(se_sess);
 }
 
-void target_get_session(struct se_session *se_sess)
+int target_get_session(struct se_session *se_sess)
 {
-	kref_get(&se_sess->sess_kref);
+	return kref_get_unless_zero(&se_sess->sess_kref);
 }
 EXPORT_SYMBOL(target_get_session);
 
@@ -424,14 +480,27 @@
 {
 	struct se_node_acl *nacl = container_of(kref,
 				struct se_node_acl, acl_kref);
+	struct se_portal_group *se_tpg = nacl->se_tpg;
+
+	if (!nacl->dynamic_stop) {
+		complete(&nacl->acl_free_comp);
+		return;
+	}
 
-	complete(&nacl->acl_free_comp);
+	mutex_lock(&se_tpg->acl_node_mutex);
+	list_del_init(&nacl->acl_list);
+	mutex_unlock(&se_tpg->acl_node_mutex);
+
+	core_tpg_wait_for_nacl_pr_ref(nacl);
+	core_free_device_list_for_node(nacl, se_tpg);
+	kfree(nacl);
 }
 
 void target_put_nacl(struct se_node_acl *nacl)
 {
 	kref_put(&nacl->acl_kref, target_complete_nacl);
 }
+EXPORT_SYMBOL(target_put_nacl);
 
 void transport_deregister_session_configfs(struct se_session *se_sess)
 {
@@ -464,6 +533,42 @@
 
 void transport_free_session(struct se_session *se_sess)
 {
+	struct se_node_acl *se_nacl = se_sess->se_node_acl;
+
+	/*
+	 * Drop the se_node_acl->nacl_kref obtained from within
+	 * core_tpg_get_initiator_node_acl().
+	 */
+	if (se_nacl) {
+		struct se_portal_group *se_tpg = se_nacl->se_tpg;
+		const struct target_core_fabric_ops *se_tfo = se_tpg->se_tpg_tfo;
+		unsigned long flags;
+
+		se_sess->se_node_acl = NULL;
+
+		/*
+		 * Also determine if we need to drop the extra ->cmd_kref if
+		 * it had been previously dynamically generated, and
+		 * the endpoint is not caching dynamic ACLs.
+		 */
+		mutex_lock(&se_tpg->acl_node_mutex);
+		if (se_nacl->dynamic_node_acl &&
+		    !se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
+			spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags);
+			if (list_empty(&se_nacl->acl_sess_list))
+				se_nacl->dynamic_stop = true;
+			spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags);
+
+			if (se_nacl->dynamic_stop)
+				list_del_init(&se_nacl->acl_list);
+		}
+		mutex_unlock(&se_tpg->acl_node_mutex);
+
+		if (se_nacl->dynamic_stop)
+			target_put_nacl(se_nacl);
+
+		target_put_nacl(se_nacl);
+	}
 	if (se_sess->sess_cmd_map) {
 		percpu_ida_destroy(&se_sess->sess_tag_pool);
 		kvfree(se_sess->sess_cmd_map);
@@ -475,16 +580,12 @@
 void transport_deregister_session(struct se_session *se_sess)
 {
 	struct se_portal_group *se_tpg = se_sess->se_tpg;
-	const struct target_core_fabric_ops *se_tfo;
-	struct se_node_acl *se_nacl;
 	unsigned long flags;
-	bool comp_nacl = true, drop_nacl = false;
 
 	if (!se_tpg) {
 		transport_free_session(se_sess);
 		return;
 	}
-	se_tfo = se_tpg->se_tpg_tfo;
 
 	spin_lock_irqsave(&se_tpg->session_lock, flags);
 	list_del(&se_sess->sess_list);
@@ -492,45 +593,21 @@
 	se_sess->fabric_sess_ptr = NULL;
 	spin_unlock_irqrestore(&se_tpg->session_lock, flags);
 
-	/*
-	 * Determine if we need to do extra work for this initiator node's
-	 * struct se_node_acl if it had been previously dynamically generated.
-	 */
-	se_nacl = se_sess->se_node_acl;
-
-	mutex_lock(&se_tpg->acl_node_mutex);
-	if (se_nacl && se_nacl->dynamic_node_acl) {
-		if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
-			list_del(&se_nacl->acl_list);
-			se_tpg->num_node_acls--;
-			drop_nacl = true;
-		}
-	}
-	mutex_unlock(&se_tpg->acl_node_mutex);
-
-	if (drop_nacl) {
-		core_tpg_wait_for_nacl_pr_ref(se_nacl);
-		core_free_device_list_for_node(se_nacl, se_tpg);
-		kfree(se_nacl);
-		comp_nacl = false;
-	}
 	pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n",
 		se_tpg->se_tpg_tfo->get_fabric_name());
 	/*
 	 * If last kref is dropping now for an explicit NodeACL, awake sleeping
 	 * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group
-	 * removal context.
+	 * removal context from within transport_free_session() code.
+	 *
+	 * For dynamic ACL, target_put_nacl() uses target_complete_nacl()
+	 * to release all remaining generate_node_acl=1 created ACL resources.
 	 */
-	if (se_nacl && comp_nacl)
-		target_put_nacl(se_nacl);
 
 	transport_free_session(se_sess);
 }
 EXPORT_SYMBOL(transport_deregister_session);
 
-/*
- * Called with cmd->t_state_lock held.
- */
 static void target_remove_from_state_list(struct se_cmd *cmd)
 {
 	struct se_device *dev = cmd->se_dev;
@@ -555,10 +632,6 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	if (write_pending)
-		cmd->t_state = TRANSPORT_WRITE_PENDING;
-
 	if (remove_from_lists) {
 		target_remove_from_state_list(cmd);
 
@@ -568,6 +641,10 @@
 		cmd->se_lun = NULL;
 	}
 
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	if (write_pending)
+		cmd->t_state = TRANSPORT_WRITE_PENDING;
+
 	/*
 	 * Determine if frontend context caller is requesting the stopping of
 	 * this command for frontend exceptions.
@@ -619,8 +696,11 @@
 		percpu_ref_put(&lun->lun_ref);
 }
 
-void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
+int transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 {
+	bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF);
+	int ret = 0;
+
 	if (cmd->se_cmd_flags & SCF_SE_LUN_CMD)
 		transport_lun_remove_cmd(cmd);
 	/*
@@ -631,9 +711,11 @@
 		cmd->se_tfo->aborted_task(cmd);
 
 	if (transport_cmd_check_stop_to_fabric(cmd))
-		return;
-	if (remove)
-		transport_put_cmd(cmd);
+		return 1;
+	if (remove && ack_kref)
+		ret = transport_put_cmd(cmd);
+
+	return ret;
 }
 
 static void target_complete_failure_work(struct work_struct *work)
@@ -700,9 +782,18 @@
 	 * Check for case where an explicit ABORT_TASK has been received
 	 * and transport_wait_for_tasks() will be waiting for completion..
 	 */
-	if (cmd->transport_state & CMD_T_ABORTED &&
+	if (cmd->transport_state & CMD_T_ABORTED ||
 	    cmd->transport_state & CMD_T_STOP) {
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+		/*
+		 * If COMPARE_AND_WRITE was stopped by __transport_wait_for_tasks(),
+		 * release se_device->caw_sem obtained by sbc_compare_and_write()
+		 * since target_complete_ok_work() or target_complete_failure_work()
+		 * won't be called to invoke the normal CAW completion callbacks.
+		 */
+		if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) {
+			up(&dev->caw_sem);
+		}
 		complete_all(&cmd->t_transport_stop_comp);
 		return;
 	} else if (!success) {
@@ -715,7 +806,10 @@
 	cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-	queue_work(target_completion_wq, &cmd->work);
+	if (cmd->se_cmd_flags & SCF_USE_CPUID)
+		queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work);
+	else
+		queue_work(target_completion_wq, &cmd->work);
 }
 EXPORT_SYMBOL(target_complete_cmd);
 
@@ -1132,15 +1226,28 @@
 	if (cmd->unknown_data_length) {
 		cmd->data_length = size;
 	} else if (size != cmd->data_length) {
-		pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
+		pr_warn_ratelimited("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]);
 
-		if (cmd->data_direction == DMA_TO_DEVICE &&
-		    cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
-			pr_err("Rejecting underflow/overflow WRITE data\n");
-			return TCM_INVALID_CDB_FIELD;
+		if (cmd->data_direction == DMA_TO_DEVICE) {
+			if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
+				pr_err_ratelimited("Rejecting underflow/overflow"
+						   " for WRITE data CDB\n");
+				return TCM_INVALID_CDB_FIELD;
+			}
+			/*
+			 * Some fabric drivers like iscsi-target still expect to
+			 * always reject overflow writes.  Reject this case until
+			 * full fabric driver level support for overflow writes
+			 * is introduced tree-wide.
+			 */
+			if (size > cmd->data_length) {
+				pr_err_ratelimited("Rejecting overflow for"
+						   " WRITE control CDB\n");
+				return TCM_INVALID_CDB_FIELD;
+			}
 		}
 		/*
 		 * Reject READ_* or WRITE_* with overflow/underflow for
@@ -1271,23 +1378,6 @@
 
 	trace_target_sequencer_start(cmd);
 
-	/*
-	 * Check for an existing UNIT ATTENTION condition
-	 */
-	ret = target_scsi3_ua_check(cmd);
-	if (ret)
-		return ret;
-
-	ret = target_alua_state_check(cmd);
-	if (ret)
-		return ret;
-
-	ret = target_check_reservation(cmd);
-	if (ret) {
-		cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
-		return ret;
-	}
-
 	ret = dev->transport->parse_cdb(cmd);
 	if (ret == TCM_UNSUPPORTED_SCSI_OPCODE)
 		pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n",
@@ -1428,6 +1518,12 @@
 	 */
 	transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
 				data_length, data_dir, task_attr, sense);
+
+	if (flags & TARGET_SCF_USE_CPUID)
+		se_cmd->se_cmd_flags |= SCF_USE_CPUID;
+	else
+		se_cmd->cpuid = WORK_CPU_UNBOUND;
+
 	if (flags & TARGET_SCF_UNKNOWN_SIZE)
 		se_cmd->unknown_data_length = 1;
 	/*
@@ -1698,6 +1794,11 @@
 	case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
 	case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
 	case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
+	case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
+	case TCM_TOO_MANY_TARGET_DESCS:
+	case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE:
+	case TCM_TOO_MANY_SEGMENT_DESCS:
+	case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE:
 		break;
 	case TCM_OUT_OF_RESOURCES:
 		sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -1750,20 +1851,45 @@
 }
 EXPORT_SYMBOL(transport_generic_request_failure);
 
-void __target_execute_cmd(struct se_cmd *cmd)
+void __target_execute_cmd(struct se_cmd *cmd, bool do_checks)
 {
 	sense_reason_t ret;
 
-	if (cmd->execute_cmd) {
-		ret = cmd->execute_cmd(cmd);
-		if (ret) {
-			spin_lock_irq(&cmd->t_state_lock);
-			cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
-			spin_unlock_irq(&cmd->t_state_lock);
+	if (!cmd->execute_cmd) {
+		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+		goto err;
+	}
+	if (do_checks) {
+		/*
+		 * Check for an existing UNIT ATTENTION condition after
+		 * target_handle_task_attr() has done SAM task attr
+		 * checking, and possibly have already defered execution
+		 * out to target_restart_delayed_cmds() context.
+		 */
+		ret = target_scsi3_ua_check(cmd);
+		if (ret)
+			goto err;
+
+		ret = target_alua_state_check(cmd);
+		if (ret)
+			goto err;
 
-			transport_generic_request_failure(cmd, ret);
+		ret = target_check_reservation(cmd);
+		if (ret) {
+			cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+			goto err;
 		}
 	}
+
+	ret = cmd->execute_cmd(cmd);
+	if (!ret)
+		return;
+err:
+	spin_lock_irq(&cmd->t_state_lock);
+	cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
+	spin_unlock_irq(&cmd->t_state_lock);
+
+	transport_generic_request_failure(cmd, ret);
 }
 
 static int target_write_prot_action(struct se_cmd *cmd)
@@ -1808,6 +1934,8 @@
 	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
 		return false;
 
+	cmd->se_cmd_flags |= SCF_TASK_ATTR_SET;
+
 	/*
 	 * 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.
@@ -1850,19 +1978,21 @@
 	return true;
 }
 
+static int __transport_check_aborted_status(struct se_cmd *, int);
+
 void target_execute_cmd(struct se_cmd *cmd)
 {
 	/*
-	 * If the received CDB has aleady been aborted stop processing it here.
-	 */
-	if (transport_check_aborted_status(cmd, 1))
-		return;
-
-	/*
 	 * Determine if frontend context caller is requesting the stopping of
 	 * this command for frontend exceptions.
+	 *
+	 * If the received CDB has aleady been aborted stop processing it here.
 	 */
 	spin_lock_irq(&cmd->t_state_lock);
+	if (__transport_check_aborted_status(cmd, 1)) {
+		spin_unlock_irq(&cmd->t_state_lock);
+		return;
+	}
 	if (cmd->transport_state & CMD_T_STOP) {
 		pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n",
 			__func__, __LINE__, cmd->tag);
@@ -1873,6 +2003,7 @@
 	}
 
 	cmd->t_state = TRANSPORT_PROCESSING;
+	cmd->transport_state &= ~CMD_T_PRE_EXECUTE;
 	cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
 	spin_unlock_irq(&cmd->t_state_lock);
 
@@ -1886,7 +2017,7 @@
 		return;
 	}
 
-	__target_execute_cmd(cmd);
+	__target_execute_cmd(cmd, true);
 }
 EXPORT_SYMBOL(target_execute_cmd);
 
@@ -1910,7 +2041,9 @@
 		list_del(&cmd->se_delayed_node);
 		spin_unlock(&dev->delayed_cmd_lock);
 
-		__target_execute_cmd(cmd);
+		cmd->transport_state |= CMD_T_SENT;
+
+		__target_execute_cmd(cmd, true);
 
 		if (cmd->sam_task_attr == TCM_ORDERED_TAG)
 			break;
@@ -1928,6 +2061,9 @@
 	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
 		return;
 
+	if (!(cmd->se_cmd_flags & SCF_TASK_ATTR_SET))
+		goto restart;
+
 	if (cmd->sam_task_attr == TCM_SIMPLE_TAG) {
 		atomic_dec_mb(&dev->simple_cmds);
 		dev->dev_cur_ordered_id++;
@@ -1944,7 +2080,9 @@
 		pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n",
 			 dev->dev_cur_ordered_id);
 	}
+	cmd->se_cmd_flags &= ~SCF_TASK_ATTR_SET;
 
+restart:
 	target_restart_delayed_cmds(dev);
 }
 
@@ -2213,20 +2351,14 @@
 }
 
 /**
- * transport_release_cmd - free a command
- * @cmd:       command to free
+ * transport_put_cmd - release a reference to a command
+ * @cmd:       command to release
  *
- * This routine unconditionally frees a command, and reference counting
- * or list removal must be done in the caller.
+ * This routine releases our reference to the command and frees it if possible.
  */
-static int transport_release_cmd(struct se_cmd *cmd)
+static int transport_put_cmd(struct se_cmd *cmd)
 {
 	BUG_ON(!cmd->se_tfo);
-
-	if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
-		core_tmr_release_req(cmd->se_tmr_req);
-	if (cmd->t_task_cdb != cmd->__t_task_cdb)
-		kfree(cmd->t_task_cdb);
 	/*
 	 * If this cmd has been setup with target_get_sess_cmd(), drop
 	 * the kref and call ->release_cmd() in kref callback.
@@ -2234,18 +2366,6 @@
 	return target_put_sess_cmd(cmd);
 }
 
-/**
- * transport_put_cmd - release a reference to a command
- * @cmd:       command to release
- *
- * This routine releases our reference to the command and frees it if possible.
- */
-static int transport_put_cmd(struct se_cmd *cmd)
-{
-	transport_free_pages(cmd);
-	return transport_release_cmd(cmd);
-}
-
 void *transport_kmap_data_sg(struct se_cmd *cmd)
 {
 	struct scatterlist *sg = cmd->t_data_sg;
@@ -2441,34 +2561,58 @@
 	}
 }
 
-int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
+static bool
+__transport_wait_for_tasks(struct se_cmd *, bool, bool *, bool *,
+			   unsigned long *flags);
+
+static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas)
 {
 	unsigned long flags;
+
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	__transport_wait_for_tasks(cmd, true, aborted, tas, &flags);
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+}
+
+int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
+{
 	int ret = 0;
+	bool aborted = false, tas = false;
 
 	if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
 		if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
-			 transport_wait_for_tasks(cmd);
+			target_wait_free_cmd(cmd, &aborted, &tas);
 
-		ret = transport_release_cmd(cmd);
+		if (!aborted || tas)
+			ret = transport_put_cmd(cmd);
 	} else {
 		if (wait_for_tasks)
-			transport_wait_for_tasks(cmd);
+			target_wait_free_cmd(cmd, &aborted, &tas);
 		/*
 		 * Handle WRITE failure case where transport_generic_new_cmd()
 		 * has already added se_cmd to state_list, but fabric has
 		 * failed command before I/O submission.
 		 */
-		if (cmd->state_active) {
-			spin_lock_irqsave(&cmd->t_state_lock, flags);
+		if (cmd->state_active)
 			target_remove_from_state_list(cmd);
-			spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-		}
 
 		if (cmd->se_lun)
 			transport_lun_remove_cmd(cmd);
 
-		ret = transport_put_cmd(cmd);
+		if (!aborted || tas)
+			ret = transport_put_cmd(cmd);
+	}
+	/*
+	 * If the task has been internally aborted due to TMR ABORT_TASK
+	 * or LUN_RESET, target_core_tmr.c is responsible for performing
+	 * the remaining calls to target_put_sess_cmd(), and not the
+	 * callers of this function.
+	 */
+	if (aborted) {
+		pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag);
+		wait_for_completion(&cmd->cmd_wait_comp);
+		cmd->se_tfo->release_cmd(cmd);
+		ret = 1;
 	}
 	return ret;
 }
@@ -2489,14 +2633,17 @@
 	 * fabric acknowledgement that requires two target_put_sess_cmd()
 	 * invocations before se_cmd descriptor release.
 	 */
-	if (ack_kref)
+	if (ack_kref) {
 		kref_get(&se_cmd->cmd_kref);
+		se_cmd->se_cmd_flags |= SCF_ACK_KREF;
+	}
 
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
 	if (se_sess->sess_tearing_down) {
 		ret = -ESHUTDOWN;
 		goto out;
 	}
+	se_cmd->transport_state |= CMD_T_PRE_EXECUTE;
 	list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
 out:
 	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
@@ -2508,26 +2655,41 @@
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
 
+static void target_free_cmd_mem(struct se_cmd *cmd)
+{
+	transport_free_pages(cmd);
+
+	if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
+		core_tmr_release_req(cmd->se_tmr_req);
+	if (cmd->t_task_cdb != cmd->__t_task_cdb)
+		kfree(cmd->t_task_cdb);
+}
+
 static void target_release_cmd_kref(struct kref *kref)
 {
 	struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
 	struct se_session *se_sess = se_cmd->se_sess;
 	unsigned long flags;
+	bool fabric_stop;
 
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-	if (list_empty(&se_cmd->se_cmd_list)) {
-		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-		se_cmd->se_tfo->release_cmd(se_cmd);
-		return;
-	}
-	if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
+
+	spin_lock(&se_cmd->t_state_lock);
+	fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP) &&
+		      (se_cmd->transport_state & CMD_T_ABORTED);
+	spin_unlock(&se_cmd->t_state_lock);
+
+	if (se_cmd->cmd_wait_set || fabric_stop) {
+		list_del_init(&se_cmd->se_cmd_list);
 		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+		target_free_cmd_mem(se_cmd);
 		complete(&se_cmd->cmd_wait_comp);
 		return;
 	}
-	list_del(&se_cmd->se_cmd_list);
+	list_del_init(&se_cmd->se_cmd_list);
 	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
+	target_free_cmd_mem(se_cmd);
 	se_cmd->se_tfo->release_cmd(se_cmd);
 }
 
@@ -2539,6 +2701,7 @@
 	struct se_session *se_sess = se_cmd->se_sess;
 
 	if (!se_sess) {
+		target_free_cmd_mem(se_cmd);
 		se_cmd->se_tfo->release_cmd(se_cmd);
 		return 1;
 	}
@@ -2555,6 +2718,7 @@
 {
 	struct se_cmd *se_cmd;
 	unsigned long flags;
+	int rc;
 
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
 	if (se_sess->sess_tearing_down) {
@@ -2564,8 +2728,15 @@
 	se_sess->sess_tearing_down = 1;
 	list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
 
-	list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
-		se_cmd->cmd_wait_set = 1;
+	list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) {
+		rc = kref_get_unless_zero(&se_cmd->cmd_kref);
+		if (rc) {
+			se_cmd->cmd_wait_set = 1;
+			spin_lock(&se_cmd->t_state_lock);
+			se_cmd->transport_state |= CMD_T_FABRIC_STOP;
+			spin_unlock(&se_cmd->t_state_lock);
+		}
+	}
 
 	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 }
@@ -2578,15 +2749,23 @@
 {
 	struct se_cmd *se_cmd, *tmp_cmd;
 	unsigned long flags;
+	bool tas;
 
 	list_for_each_entry_safe(se_cmd, tmp_cmd,
 				&se_sess->sess_wait_list, se_cmd_list) {
-		list_del(&se_cmd->se_cmd_list);
-
 		pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
 			" %d\n", se_cmd, se_cmd->t_state,
 			se_cmd->se_tfo->get_cmd_state(se_cmd));
 
+		spin_lock_irqsave(&se_cmd->t_state_lock, flags);
+		tas = (se_cmd->transport_state & CMD_T_TAS);
+		spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
+
+		if (!target_put_sess_cmd(se_cmd)) {
+			if (tas)
+				target_put_sess_cmd(se_cmd);
+		}
+
 		wait_for_completion(&se_cmd->cmd_wait_comp);
 		pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
 			" fabric state: %d\n", se_cmd, se_cmd->t_state,
@@ -2602,59 +2781,110 @@
 }
 EXPORT_SYMBOL(target_wait_for_sess_cmds);
 
+static void target_lun_confirm(struct percpu_ref *ref)
+{
+	struct se_lun *lun = container_of(ref, struct se_lun, lun_ref);
+
+	complete(&lun->lun_ref_comp);
+}
+
 void transport_clear_lun_ref(struct se_lun *lun)
 {
-	percpu_ref_kill(&lun->lun_ref);
+	/*
+	 * Mark the percpu-ref as DEAD, switch to atomic_t mode, drop
+	 * the initial reference and schedule confirm kill to be
+	 * executed after one full RCU grace period has completed.
+	 */
+	percpu_ref_kill_and_confirm(&lun->lun_ref, target_lun_confirm);
+	/*
+	 * The first completion waits for percpu_ref_switch_to_atomic_rcu()
+	 * to call target_lun_confirm after lun->lun_ref has been marked
+	 * as __PERCPU_REF_DEAD on all CPUs, and switches to atomic_t
+	 * mode so that percpu_ref_tryget_live() lookup of lun->lun_ref
+	 * fails for all new incoming I/O.
+	 */
 	wait_for_completion(&lun->lun_ref_comp);
+	/*
+	 * The second completion waits for percpu_ref_put_many() to
+	 * invoke ->release() after lun->lun_ref has switched to
+	 * atomic_t mode, and lun->lun_ref.count has reached zero.
+	 *
+	 * At this point all target-core lun->lun_ref references have
+	 * been dropped via transport_lun_remove_cmd(), and it's safe
+	 * to proceed with the remaining LUN shutdown.
+	 */
+	wait_for_completion(&lun->lun_shutdown_comp);
 }
 
-/**
- * transport_wait_for_tasks - wait for completion to occur
- * @cmd:	command to wait
- *
- * Called from frontend fabric context to wait for storage engine
- * to pause and/or release frontend generated struct se_cmd.
- */
-bool transport_wait_for_tasks(struct se_cmd *cmd)
+static bool
+__transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop,
+			   bool *aborted, bool *tas, unsigned long *flags)
+	__releases(&cmd->t_state_lock)
+	__acquires(&cmd->t_state_lock)
 {
-	unsigned long flags;
 
-	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	assert_spin_locked(&cmd->t_state_lock);
+	WARN_ON_ONCE(!irqs_disabled());
+
+	if (fabric_stop)
+		cmd->transport_state |= CMD_T_FABRIC_STOP;
+
+	if (cmd->transport_state & CMD_T_ABORTED)
+		*aborted = true;
+
+	if (cmd->transport_state & CMD_T_TAS)
+		*tas = true;
+
 	if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) &&
-	    !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
-		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+	    !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
 		return false;
-	}
 
 	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);
+	    !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
 		return false;
-	}
 
-	if (!(cmd->transport_state & CMD_T_ACTIVE)) {
-		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+	if (!(cmd->transport_state & CMD_T_ACTIVE))
+		return false;
+
+	if (fabric_stop && *aborted)
 		return false;
-	}
 
 	cmd->transport_state |= CMD_T_STOP;
 
-	pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n",
-		cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
+	pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d,"
+		 " t_state: %d, CMD_T_STOP\n", cmd, cmd->tag,
+		 cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
 
-	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+	spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
 
 	wait_for_completion(&cmd->t_transport_stop_comp);
 
-	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	spin_lock_irqsave(&cmd->t_state_lock, *flags);
 	cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP);
 
-	pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->t_transport_stop_comp) for ITT: 0x%08llx\n",
-		cmd->tag);
+	pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->"
+		 "t_transport_stop_comp) for ITT: 0x%08llx\n", cmd->tag);
+
+	return true;
+}
+
+/**
+ * transport_wait_for_tasks - wait for completion to occur
+ * @cmd:	command to wait
+ *
+ * Called from frontend fabric context to wait for storage engine
+ * to pause and/or release frontend generated struct se_cmd.
+ */
+bool transport_wait_for_tasks(struct se_cmd *cmd)
+{
+	unsigned long flags;
+	bool ret, aborted = false, tas = false;
 
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	ret = __transport_wait_for_tasks(cmd, false, &aborted, &tas, &flags);
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-	return true;
+	return ret;
 }
 EXPORT_SYMBOL(transport_wait_for_tasks);
 
@@ -2703,6 +2933,26 @@
 		.key = ILLEGAL_REQUEST,
 		.asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */
 	},
+	[TCM_TOO_MANY_TARGET_DESCS] = {
+		.key = ILLEGAL_REQUEST,
+		.asc = 0x26,
+		.ascq = 0x06, /* TOO MANY TARGET DESCRIPTORS */
+	},
+	[TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE] = {
+		.key = ILLEGAL_REQUEST,
+		.asc = 0x26,
+		.ascq = 0x07, /* UNSUPPORTED TARGET DESCRIPTOR TYPE CODE */
+	},
+	[TCM_TOO_MANY_SEGMENT_DESCS] = {
+		.key = ILLEGAL_REQUEST,
+		.asc = 0x26,
+		.ascq = 0x08, /* TOO MANY SEGMENT DESCRIPTORS */
+	},
+	[TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE] = {
+		.key = ILLEGAL_REQUEST,
+		.asc = 0x26,
+		.ascq = 0x09, /* UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE */
+	},
 	[TCM_PARAMETER_LIST_LENGTH_ERROR] = {
 		.key = ILLEGAL_REQUEST,
 		.asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */
@@ -2759,6 +3009,12 @@
 		.ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
 		.add_sector_info = true,
 	},
+	[TCM_COPY_TARGET_DEVICE_NOT_REACHABLE] = {
+		.key = COPY_ABORTED,
+		.asc = 0x0d,
+		.ascq = 0x02, /* COPY TARGET DEVICE NOT REACHABLE */
+
+	},
 	[TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = {
 		/*
 		 * Returning ILLEGAL REQUEST would cause immediate IO errors on
@@ -2836,28 +3092,49 @@
 }
 EXPORT_SYMBOL(transport_send_check_condition_and_sense);
 
-int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
+static int __transport_check_aborted_status(struct se_cmd *cmd, int send_status)
+	__releases(&cmd->t_state_lock)
+	__acquires(&cmd->t_state_lock)
 {
+	assert_spin_locked(&cmd->t_state_lock);
+	WARN_ON_ONCE(!irqs_disabled());
+
 	if (!(cmd->transport_state & CMD_T_ABORTED))
 		return 0;
-
 	/*
 	 * If cmd has been aborted but either no status is to be sent or it has
 	 * already been sent, just return
 	 */
-	if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS))
+	if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) {
+		if (send_status)
+			cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
 		return 1;
+	}
 
-	pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08llx\n",
-		 cmd->t_task_cdb[0], cmd->tag);
+	pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB:"
+		" 0x%02x ITT: 0x%08llx\n", cmd->t_task_cdb[0], cmd->tag);
 
 	cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS;
 	cmd->scsi_status = SAM_STAT_TASK_ABORTED;
 	trace_target_cmd_complete(cmd);
+
+	spin_unlock_irq(&cmd->t_state_lock);
 	cmd->se_tfo->queue_status(cmd);
+	spin_lock_irq(&cmd->t_state_lock);
 
 	return 1;
 }
+
+int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
+{
+	int ret;
+
+	spin_lock_irq(&cmd->t_state_lock);
+	ret = __transport_check_aborted_status(cmd, send_status);
+	spin_unlock_irq(&cmd->t_state_lock);
+
+	return ret;
+}
 EXPORT_SYMBOL(transport_check_aborted_status);
 
 void transport_send_task_abort(struct se_cmd *cmd)
@@ -2879,11 +3156,17 @@
 	 */
 	if (cmd->data_direction == DMA_TO_DEVICE) {
 		if (cmd->se_tfo->write_pending_status(cmd) != 0) {
-			cmd->transport_state |= CMD_T_ABORTED;
+			spin_lock_irqsave(&cmd->t_state_lock, flags);
+			if (cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS) {
+				spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+				goto send_abort;
+			}
 			cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
+			spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 			return;
 		}
 	}
+send_abort:
 	cmd->scsi_status = SAM_STAT_TASK_ABORTED;
 
 	transport_lun_remove_cmd(cmd);
@@ -2900,8 +3183,17 @@
 	struct se_cmd *cmd = container_of(work, struct se_cmd, work);
 	struct se_device *dev = cmd->se_dev;
 	struct se_tmr_req *tmr = cmd->se_tmr_req;
+	unsigned long flags;
 	int ret;
 
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	if (cmd->transport_state & CMD_T_ABORTED) {
+		tmr->response = TMR_FUNCTION_REJECTED;
+		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+		goto check_stop;
+	}
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
 	switch (tmr->function) {
 	case TMR_ABORT_TASK:
 		core_tmr_abort_task(dev, tmr, cmd->se_sess);
@@ -2934,9 +3226,16 @@
 		break;
 	}
 
-	cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	if (cmd->transport_state & CMD_T_ABORTED) {
+		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+		goto check_stop;
+	}
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
 	cmd->se_tfo->queue_tm_rsp(cmd);
 
+check_stop:
 	transport_cmd_check_stop_to_fabric(cmd);
 }
 
@@ -2944,11 +3243,25 @@
 	struct se_cmd *cmd)
 {
 	unsigned long flags;
+	bool aborted = false;
 
 	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	cmd->transport_state |= CMD_T_ACTIVE;
+	if (cmd->transport_state & CMD_T_ABORTED) {
+		aborted = true;
+	} else {
+		cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
+		cmd->transport_state |= CMD_T_ACTIVE;
+	}
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
+	if (aborted) {
+		pr_warn_ratelimited("handle_tmr caught CMD_T_ABORTED TMR %d"
+			"ref_tag: %llu tag: %llu\n", cmd->se_tmr_req->function,
+			cmd->se_tmr_req->ref_task_tag, cmd->tag);
+		transport_cmd_check_stop_to_fabric(cmd);
+		return 0;
+	}
+
 	INIT_WORK(&cmd->work, target_tmr_work);
 	queue_work(cmd->se_dev->tmr_wq, &cmd->work);
 	return 0;
--- linux-4.4.0.orig/drivers/target/target_core_user.c
+++ linux-4.4.0/drivers/target/target_core_user.c
@@ -92,7 +92,7 @@
 	size_t dev_size;
 	u32 cmdr_size;
 	u32 cmdr_last_cleaned;
-	/* Offset of data ring from start of mb */
+	/* Offset of data area from start of mb */
 	size_t data_off;
 	size_t data_size;
 	/* Ring head + tail values. */
@@ -154,6 +154,14 @@
 	.n_mcgrps = ARRAY_SIZE(tcmu_mcgrps),
 };
 
+/* Sense Key = 2 (Not Ready)
+ * ASC/ASCQ = 0x0800 (Logical Unit Communication Failure)
+ */
+static const char lu_comm_failure_sense[18] = {
+	0x70, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0a,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00 };
+
 static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
 {
 	struct se_device *se_dev = se_cmd->se_dev;
@@ -331,7 +339,7 @@
 
 /*
  * We can't queue a command until we have space available on the cmd ring *and*
- * space available on the data ring.
+ * space available on the data area.
  *
  * Called with ring lock held.
  */
@@ -372,7 +380,8 @@
 	return true;
 }
 
-static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
+static sense_reason_t
+tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
 {
 	struct tcmu_dev *udev = tcmu_cmd->tcmu_dev;
 	struct se_cmd *se_cmd = tcmu_cmd->se_cmd;
@@ -386,7 +395,7 @@
 	bool copy_to_data_area;
 
 	if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags))
-		return -EINVAL;
+		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
 	/*
 	 * Must be a certain minimum size for response sense info, but
@@ -409,10 +418,13 @@
 	mb = udev->mb_addr;
 	cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */
 	if ((command_size > (udev->cmdr_size / 2))
-	    || tcmu_cmd->data_length > (udev->data_size - 1))
+	    || tcmu_cmd->data_length > (udev->data_size - 1)) {
 		pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu "
 			"cmd/data ring buffers\n", command_size, tcmu_cmd->data_length,
 			udev->cmdr_size, udev->data_size);
+		spin_unlock_irq(&udev->cmdr_lock);
+		return TCM_INVALID_CDB_FIELD;
+	}
 
 	while (!is_ring_space_avail(udev, command_size, tcmu_cmd->data_length)) {
 		int ret;
@@ -426,7 +438,7 @@
 		finish_wait(&udev->wait_cmdr, &__wait);
 		if (!ret) {
 			pr_warn("tcmu: command timed out\n");
-			return -ETIMEDOUT;
+			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 		}
 
 		spin_lock_irq(&udev->cmdr_lock);
@@ -461,9 +473,7 @@
 	entry->hdr.kflags = 0;
 	entry->hdr.uflags = 0;
 
-	/*
-	 * Fix up iovecs, and handle if allocation in data ring wrapped.
-	 */
+	/* Handle allocating space from the data area */
 	iov = &entry->req.iov[0];
 	iov_cnt = 0;
 	copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE
@@ -496,10 +506,11 @@
 	mod_timer(&udev->timeout,
 		round_jiffies_up(jiffies + msecs_to_jiffies(TCMU_TIME_OUT)));
 
-	return 0;
+	return TCM_NO_SENSE;
 }
 
-static int tcmu_queue_cmd(struct se_cmd *se_cmd)
+static sense_reason_t
+tcmu_queue_cmd(struct se_cmd *se_cmd)
 {
 	struct se_device *se_dev = se_cmd->se_dev;
 	struct tcmu_dev *udev = TCMU_DEV(se_dev);
@@ -508,10 +519,10 @@
 
 	tcmu_cmd = tcmu_alloc_cmd(se_cmd);
 	if (!tcmu_cmd)
-		return -ENOMEM;
+		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
 	ret = tcmu_queue_cmd_ring(tcmu_cmd);
-	if (ret < 0) {
+	if (ret != TCM_NO_SENSE) {
 		pr_err("TCMU: Could not queue command\n");
 		spin_lock_irq(&udev->commands_lock);
 		idr_remove(&udev->commands, tcmu_cmd->cmd_id);
@@ -529,8 +540,10 @@
 	struct tcmu_dev *udev = cmd->tcmu_dev;
 
 	if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
-		/* cmd has been completed already from timeout, just reclaim data
-		   ring space */
+		/*
+		 * cmd has been completed already from timeout, just reclaim
+		 * data area space and free cmd
+		 */
 		UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size);
 		return;
 	}
@@ -540,9 +553,11 @@
 		pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n",
 			cmd->se_cmd);
 		entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION;
+		memcpy(se_cmd->sense_buffer, lu_comm_failure_sense,
+		       sizeof(lu_comm_failure_sense));
 	} else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) {
 		memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer,
-			       se_cmd->scsi_sense_length);
+			       TRANSPORT_SENSE_BUFFER);
 
 		UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size);
 	} else if (se_cmd->se_cmd_flags & SCF_BIDI) {
@@ -590,7 +605,14 @@
 		struct tcmu_cmd_entry *entry = (void *) mb + CMDR_OFF + udev->cmdr_last_cleaned;
 		struct tcmu_cmd *cmd;
 
-		tcmu_flush_dcache_range(entry, sizeof(*entry));
+		/*
+		 * Flush max. up to end of cmd ring since current entry might
+		 * be a padding that is shorter than sizeof(*entry)
+		 */
+		size_t ring_left = head_to_end(udev->cmdr_last_cleaned,
+					       udev->cmdr_size);
+		tcmu_flush_dcache_range(entry, ring_left < sizeof(*entry) ?
+					ring_left : sizeof(*entry));
 
 		if (tcmu_hdr_get_op(entry->hdr.len_op) == TCMU_OP_PAD) {
 			UPDATE_HEAD(udev->cmdr_last_cleaned,
@@ -642,11 +664,11 @@
 		return 0;
 
 	set_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags);
+	memcpy(cmd->se_cmd->sense_buffer, lu_comm_failure_sense,
+	       sizeof(lu_comm_failure_sense));
 	target_complete_cmd(cmd->se_cmd, SAM_STAT_CHECK_CONDITION);
 	cmd->se_cmd = NULL;
 
-	kmem_cache_free(tcmu_cmd_cache, cmd);
-
 	return 0;
 }
 
@@ -902,7 +924,7 @@
 	info->version = __stringify(TCMU_MAILBOX_VERSION);
 
 	info->mem[0].name = "tcm-user command & data buffer";
-	info->mem[0].addr = (phys_addr_t) udev->mb_addr;
+	info->mem[0].addr = (phys_addr_t)(uintptr_t)udev->mb_addr;
 	info->mem[0].size = TCMU_RING_SIZE;
 	info->mem[0].memtype = UIO_MEM_VIRTUAL;
 
@@ -1083,20 +1105,20 @@
 }
 
 static sense_reason_t
-tcmu_pass_op(struct se_cmd *se_cmd)
+tcmu_parse_cdb(struct se_cmd *cmd)
 {
-	int ret = tcmu_queue_cmd(se_cmd);
-
-	if (ret != 0)
-		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-	else
-		return TCM_NO_SENSE;
+	return passthrough_parse_cdb(cmd, tcmu_queue_cmd);
 }
 
-static sense_reason_t
-tcmu_parse_cdb(struct se_cmd *cmd)
+static void tcmu_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,
+				    unsigned char *sense_buffer)
 {
-	return passthrough_parse_cdb(cmd, tcmu_pass_op);
+	if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION)
+		/* Setting this flag will prevent target_complete_cmd from
+		 * calling target_complete_failure_work, which would overwrite
+		 * the sense data we already set.
+		 */
+		cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
 }
 
 static const struct target_backend_ops tcmu_ops = {
@@ -1109,6 +1131,7 @@
 	.configure_device	= tcmu_configure_device,
 	.free_device		= tcmu_free_device,
 	.parse_cdb		= tcmu_parse_cdb,
+	.transport_complete	= tcmu_transport_complete,
 	.set_configfs_dev_params = tcmu_set_configfs_dev_params,
 	.show_configfs_dev_params = tcmu_show_configfs_dev_params,
 	.get_device_type	= sbc_get_device_type,
--- linux-4.4.0.orig/drivers/target/target_core_xcopy.c
+++ linux-4.4.0/drivers/target/target_core_xcopy.c
@@ -52,64 +52,87 @@
 	return 0;
 }
 
-static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
-					bool src)
+/**
+ * target_xcopy_locate_se_dev_e4_iter - compare XCOPY NAA device identifiers
+ *
+ * @se_dev: device being considered for match
+ * @dev_wwn: XCOPY requested NAA dev_wwn
+ * @return: 1 on match, 0 on no-match
+ */
+static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
+					      const unsigned char *dev_wwn)
 {
-	struct se_device *se_dev;
-	unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
+	unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
 	int rc;
 
-	if (src)
-		dev_wwn = &xop->dst_tid_wwn[0];
-	else
-		dev_wwn = &xop->src_tid_wwn[0];
+	if (!se_dev->dev_attrib.emulate_3pc) {
+		pr_debug("XCOPY: emulate_3pc disabled on se_dev %p\n", se_dev);
+		return 0;
+	}
 
-	mutex_lock(&g_device_mutex);
-	list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
+	memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
+	target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
 
-		if (!se_dev->dev_attrib.emulate_3pc)
-			continue;
+	rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
+	if (rc != 0) {
+		pr_debug("XCOPY: skip non-matching: %*ph\n",
+			 XCOPY_NAA_IEEE_REGEX_LEN, tmp_dev_wwn);
+		return 0;
+	}
+	pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
 
-		memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
-		target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
+	return 1;
+}
 
-		rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
-		if (rc != 0)
-			continue;
+static int target_xcopy_locate_se_dev_e4(struct se_session *sess,
+					const unsigned char *dev_wwn,
+					struct se_device **_found_dev,
+					struct percpu_ref **_found_lun_ref)
+{
+	struct se_dev_entry *deve;
+	struct se_node_acl *nacl;
+	struct se_lun *this_lun = NULL;
+	struct se_device *found_dev = NULL;
 
-		if (src) {
-			xop->dst_dev = se_dev;
-			pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located"
-				" se_dev\n", xop->dst_dev);
-		} else {
-			xop->src_dev = se_dev;
-			pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located"
-				" se_dev\n", xop->src_dev);
-		}
+	/* cmd with NULL sess indicates no associated $FABRIC_MOD */
+	if (!sess)
+		goto err_out;
 
-		rc = target_depend_item(&se_dev->dev_group.cg_item);
-		if (rc != 0) {
-			pr_err("configfs_depend_item attempt failed:"
-				" %d for se_dev: %p\n", rc, se_dev);
-			mutex_unlock(&g_device_mutex);
-			return rc;
-		}
+	pr_debug("XCOPY 0xe4: searching for: %*ph\n",
+		 XCOPY_NAA_IEEE_REGEX_LEN, dev_wwn);
 
-		pr_debug("Called configfs_depend_item for se_dev: %p"
-			" se_dev->se_dev_group: %p\n", se_dev,
-			&se_dev->dev_group);
+	nacl = sess->se_node_acl;
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) {
+		struct se_device *this_dev;
+		int rc;
 
-		mutex_unlock(&g_device_mutex);
-		return 0;
-	}
-	mutex_unlock(&g_device_mutex);
+		this_lun = rcu_dereference(deve->se_lun);
+		this_dev = rcu_dereference_raw(this_lun->lun_se_dev);
 
-	pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
+		rc = target_xcopy_locate_se_dev_e4_iter(this_dev, dev_wwn);
+		if (rc) {
+			if (percpu_ref_tryget_live(&this_lun->lun_ref))
+				found_dev = this_dev;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	if (found_dev == NULL)
+		goto err_out;
+
+	pr_debug("lun_ref held for se_dev: %p se_dev->se_dev_group: %p\n",
+		 found_dev, &found_dev->dev_group);
+	*_found_dev = found_dev;
+	*_found_lun_ref = &this_lun->lun_ref;
+	return 0;
+err_out:
+	pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
 	return -EINVAL;
 }
 
 static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
-				unsigned char *p, bool src)
+				unsigned char *p, unsigned short cscd_index)
 {
 	unsigned char *desc = p;
 	unsigned short ript;
@@ -154,7 +177,13 @@
 		return -EINVAL;
 	}
 
-	if (src) {
+	if (cscd_index != xop->stdi && cscd_index != xop->dtdi) {
+		pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor "
+			 "dest\n", cscd_index);
+		return 0;
+	}
+
+	if (cscd_index == xop->stdi) {
 		memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
 		/*
 		 * Determine if the source designator matches the local device
@@ -166,10 +195,15 @@
 			pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
 					" received xop\n", xop->src_dev);
 		}
-	} else {
+	}
+
+	if (cscd_index == xop->dtdi) {
 		memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
 		/*
-		 * Determine if the destination designator matches the local device
+		 * Determine if the destination designator matches the local
+		 * device. If @cscd_index corresponds to both source (stdi) and
+		 * destination (dtdi), or dtdi comes after stdi, then
+		 * XCOL_DEST_RECV_OP wins.
 		 */
 		if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
 				XCOPY_NAA_IEEE_REGEX_LEN)) {
@@ -185,13 +219,15 @@
 
 static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
 				struct xcopy_op *xop, unsigned char *p,
-				unsigned short tdll)
+				unsigned short tdll, sense_reason_t *sense_ret)
 {
 	struct se_device *local_dev = se_cmd->se_dev;
 	unsigned char *desc = p;
-	int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0;
+	int offset = tdll % XCOPY_TARGET_DESC_LEN, rc;
+	unsigned short cscd_index = 0;
 	unsigned short start = 0;
-	bool src = true;
+
+	*sense_ret = TCM_INVALID_PARAMETER_LIST;
 
 	if (offset != 0) {
 		pr_err("XCOPY target descriptor list length is not"
@@ -212,25 +248,19 @@
 
 	while (start < tdll) {
 		/*
-		 * Check target descriptor identification with 0xE4 type with
-		 * use VPD 0x83 WWPN matching ..
+		 * Check target descriptor identification with 0xE4 type, and
+		 * compare the current index with the CSCD descriptor IDs in
+		 * the segment descriptor. Use VPD 0x83 WWPN matching ..
 		 */
 		switch (desc[0]) {
 		case 0xe4:
 			rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
-							&desc[0], src);
+							&desc[0], cscd_index);
 			if (rc != 0)
 				goto out;
-			/*
-			 * Assume target descriptors are in source -> destination order..
-			 */
-			if (src)
-				src = false;
-			else
-				src = true;
 			start += XCOPY_TARGET_DESC_LEN;
 			desc += XCOPY_TARGET_DESC_LEN;
-			ret++;
+			cscd_index++;
 			break;
 		default:
 			pr_err("XCOPY unsupported descriptor type code:"
@@ -239,20 +269,42 @@
 		}
 	}
 
-	if (xop->op_origin == XCOL_SOURCE_RECV_OP)
-		rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
-	else
-		rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
-
-	if (rc < 0)
+	switch (xop->op_origin) {
+	case XCOL_SOURCE_RECV_OP:
+		rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
+						xop->dst_tid_wwn,
+						&xop->dst_dev,
+						&xop->remote_lun_ref);
+		break;
+	case XCOL_DEST_RECV_OP:
+		rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
+						xop->src_tid_wwn,
+						&xop->src_dev,
+						&xop->remote_lun_ref);
+		break;
+	default:
+		pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
+			"stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi);
+		rc = -EINVAL;
+		break;
+	}
+	/*
+	 * If a matching IEEE NAA 0x83 descriptor for the requested device
+	 * is not located on this node, return COPY_ABORTED with ASQ/ASQC
+	 * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the
+	 * initiator to fall back to normal copy method.
+	 */
+	if (rc < 0) {
+		*sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
 		goto out;
+	}
 
 	pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n",
 		 xop->src_dev, &xop->src_tid_wwn[0]);
 	pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
 		 xop->dst_dev, &xop->dst_tid_wwn[0]);
 
-	return ret;
+	return cscd_index;
 
 out:
 	return -EINVAL;
@@ -296,17 +348,26 @@
 
 static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
 				struct xcopy_op *xop, unsigned char *p,
-				unsigned int sdll)
+				unsigned int sdll, sense_reason_t *sense_ret)
 {
 	unsigned char *desc = p;
 	unsigned int start = 0;
 	int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;
 
+	*sense_ret = TCM_INVALID_PARAMETER_LIST;
+
 	if (offset != 0) {
 		pr_err("XCOPY segment descriptor list length is not"
 			" multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
 		return -EINVAL;
 	}
+	if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) {
+		pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too"
+			" large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll);
+		/* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */
+		*sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
+		return -EINVAL;
+	}
 
 	while (start < sdll) {
 		/*
@@ -363,18 +424,12 @@
 
 static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop)
 {
-	struct se_device *remote_dev;
-
 	if (xop->op_origin == XCOL_SOURCE_RECV_OP)
-		remote_dev = xop->dst_dev;
+		pr_debug("putting dst lun_ref for %p\n", xop->dst_dev);
 	else
-		remote_dev = xop->src_dev;
-
-	pr_debug("Calling configfs_undepend_item for"
-		  " remote_dev: %p remote_dev->dev_group: %p\n",
-		  remote_dev, &remote_dev->dev_group.cg_item);
+		pr_debug("putting src lun_ref for %p\n", xop->src_dev);
 
-	target_undepend_item(&remote_dev->dev_group.cg_item);
+	percpu_ref_put(xop->remote_lun_ref);
 }
 
 static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
@@ -653,6 +708,7 @@
 	rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0],
 				remote_port, true);
 	if (rc < 0) {
+		ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
 		transport_generic_free_cmd(se_cmd, 0);
 		return rc;
 	}
@@ -664,6 +720,7 @@
 
 	rc = target_xcopy_issue_pt_cmd(xpt_cmd);
 	if (rc < 0) {
+		ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
 		transport_generic_free_cmd(se_cmd, 0);
 		return rc;
 	}
@@ -714,6 +771,7 @@
 				remote_port, false);
 	if (rc < 0) {
 		struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd;
+		ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
 		/*
 		 * If the failure happened before the t_mem_list hand-off in
 		 * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that
@@ -729,6 +787,7 @@
 
 	rc = target_xcopy_issue_pt_cmd(xpt_cmd);
 	if (rc < 0) {
+		ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
 		se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
 		transport_generic_free_cmd(se_cmd, 0);
 		return rc;
@@ -815,10 +874,15 @@
 out:
 	xcopy_pt_undepend_remotedev(xop);
 	kfree(xop);
-
-	pr_warn("target_xcopy_do_work: Setting X-COPY CHECK_CONDITION -> sending response\n");
-	ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
-	target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION);
+	/*
+	 * Don't override an error scsi status if it has already been set
+	 */
+	if (ec_cmd->scsi_status == SAM_STAT_GOOD) {
+		pr_warn_ratelimited("target_xcopy_do_work: rc: %d, Setting X-COPY"
+			" CHECK_CONDITION -> sending response\n", rc);
+		ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+	}
+	target_complete_cmd(ec_cmd, ec_cmd->scsi_status);
 }
 
 sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
@@ -875,7 +939,21 @@
 		" tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
 		tdll, sdll, inline_dl);
 
-	rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll);
+	/*
+	 * skip over the target descriptors until segment descriptors
+	 * have been passed - CSCD ids are needed to determine src and dest.
+	 */
+	seg_desc = &p[16] + tdll;
+
+	rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc,
+						    sdll, &ret);
+	if (rc <= 0)
+		goto out;
+
+	pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
+				rc * XCOPY_SEGMENT_DESC_LEN);
+
+	rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
 	if (rc <= 0)
 		goto out;
 
@@ -892,18 +970,8 @@
 
 	pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
 				rc * XCOPY_TARGET_DESC_LEN);
-	seg_desc = &p[16];
-	seg_desc += (rc * XCOPY_TARGET_DESC_LEN);
-
-	rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll);
-	if (rc <= 0) {
-		xcopy_pt_undepend_remotedev(xop);
-		goto out;
-	}
 	transport_kunmap_data_sg(se_cmd);
 
-	pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
-				rc * XCOPY_SEGMENT_DESC_LEN);
 	INIT_WORK(&xop->xop_work, target_xcopy_do_work);
 	queue_work(xcopy_wq, &xop->xop_work);
 	return TCM_NO_SENSE;
--- linux-4.4.0.orig/drivers/target/target_core_xcopy.h
+++ linux-4.4.0/drivers/target/target_core_xcopy.h
@@ -19,6 +19,7 @@
 	struct se_device *dst_dev;
 	unsigned char dst_tid_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
 	unsigned char local_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
+	struct percpu_ref *remote_lun_ref;
 
 	sector_t src_lba;
 	sector_t dst_lba;
--- linux-4.4.0.orig/drivers/tc/tc.c
+++ linux-4.4.0/drivers/tc/tc.c
@@ -2,7 +2,7 @@
  *	TURBOchannel bus services.
  *
  *	Copyright (c) Harald Koerfgen, 1998
- *	Copyright (c) 2001, 2003, 2005, 2006  Maciej W. Rozycki
+ *	Copyright (c) 2001, 2003, 2005, 2006, 2018  Maciej W. Rozycki
  *	Copyright (c) 2005  James Simmons
  *
  *	This file is subject to the terms and conditions of the GNU
@@ -10,6 +10,7 @@
  *	directory of this archive for more details.
  */
 #include <linux/compiler.h>
+#include <linux/dma-mapping.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -92,6 +93,11 @@
 		tdev->dev.bus = &tc_bus_type;
 		tdev->slot = slot;
 
+		/* TURBOchannel has 34-bit DMA addressing (16GiB space). */
+		tdev->dma_mask = DMA_BIT_MASK(34);
+		tdev->dev.dma_mask = &tdev->dma_mask;
+		tdev->dev.coherent_dma_mask = DMA_BIT_MASK(34);
+
 		for (i = 0; i < 8; i++) {
 			tdev->firmware[i] =
 				readb(module + offset + TC_FIRM_VER + 4 * i);
--- linux-4.4.0.orig/drivers/thermal/Kconfig
+++ linux-4.4.0/drivers/thermal/Kconfig
@@ -195,7 +195,7 @@
 	  passive trip is crossed.
 
 config SPEAR_THERMAL
-	bool "SPEAr thermal sensor driver"
+	tristate "SPEAr thermal sensor driver"
 	depends on PLAT_SPEAR || COMPILE_TEST
 	depends on OF
 	help
@@ -237,8 +237,8 @@
 	  framework.
 
 config DB8500_THERMAL
-	bool "DB8500 thermal management"
-	depends on ARCH_U8500
+	tristate "DB8500 thermal management"
+	depends on MFD_DB8500_PRCMU
 	default y
 	help
 	  Adds DB8500 thermal management implementation according to the thermal
@@ -299,7 +299,7 @@
 
 config INTEL_SOC_DTS_IOSF_CORE
 	tristate
-	depends on X86
+	depends on X86 && PCI
 	select IOSF_MBI
 	help
 	  This is becoming a common feature for Intel SoCs to expose the additional
@@ -309,7 +309,7 @@
 
 config INTEL_SOC_DTS_THERMAL
 	tristate "Intel SoCs DTS thermal driver"
-	depends on X86
+	depends on X86 && PCI
 	select INTEL_SOC_DTS_IOSF_CORE
 	select THERMAL_WRITABLE_TRIPS
 	help
--- linux-4.4.0.orig/drivers/thermal/cpu_cooling.c
+++ linux-4.4.0/drivers/thermal/cpu_cooling.c
@@ -191,8 +191,10 @@
 	mutex_lock(&cooling_list_lock);
 	list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
 		if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) {
+			unsigned long level = get_level(cpufreq_dev, freq);
+
 			mutex_unlock(&cooling_list_lock);
-			return get_level(cpufreq_dev, freq);
+			return level;
 		}
 	}
 	mutex_unlock(&cooling_list_lock);
@@ -377,26 +379,28 @@
  * get_load() - get load for a cpu since last updated
  * @cpufreq_device:	&struct cpufreq_cooling_device for this cpu
  * @cpu:	cpu number
+ * @cpu_idx:	index of the cpu in cpufreq_device->allowed_cpus
  *
  * Return: The average load of cpu @cpu in percentage since this
  * function was last called.
  */
-static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu)
+static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu,
+		    int cpu_idx)
 {
 	u32 load;
 	u64 now, now_idle, delta_time, delta_idle;
 
 	now_idle = get_cpu_idle_time(cpu, &now, 0);
-	delta_idle = now_idle - cpufreq_device->time_in_idle[cpu];
-	delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu];
+	delta_idle = now_idle - cpufreq_device->time_in_idle[cpu_idx];
+	delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu_idx];
 
 	if (delta_time <= delta_idle)
 		load = 0;
 	else
 		load = div64_u64(100 * (delta_time - delta_idle), delta_time);
 
-	cpufreq_device->time_in_idle[cpu] = now_idle;
-	cpufreq_device->time_in_idle_timestamp[cpu] = now;
+	cpufreq_device->time_in_idle[cpu_idx] = now_idle;
+	cpufreq_device->time_in_idle_timestamp[cpu_idx] = now;
 
 	return load;
 }
@@ -598,12 +602,12 @@
 		u32 load;
 
 		if (cpu_online(cpu))
-			load = get_load(cpufreq_device, cpu);
+			load = get_load(cpufreq_device, cpu, i);
 		else
 			load = 0;
 
 		total_load += load;
-		if (trace_thermal_power_cpu_limit_enabled() && load_cpu)
+		if (load_cpu)
 			load_cpu[i] = load;
 
 		i++;
@@ -855,14 +859,6 @@
 		goto free_power_table;
 	}
 
-	snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
-		 cpufreq_dev->id);
-
-	cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
-						      &cpufreq_cooling_ops);
-	if (IS_ERR(cool_dev))
-		goto remove_idr;
-
 	/* Fill freq-table in descending order of frequencies */
 	for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
 		freq = find_next_max(table, freq);
@@ -875,6 +871,14 @@
 			pr_debug("%s: freq:%u KHz\n", __func__, freq);
 	}
 
+	snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
+		 cpufreq_dev->id);
+
+	cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
+						      &cpufreq_cooling_ops);
+	if (IS_ERR(cool_dev))
+		goto remove_idr;
+
 	cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
 	cpufreq_dev->cool_dev = cool_dev;
 
--- linux-4.4.0.orig/drivers/thermal/hisi_thermal.c
+++ linux-4.4.0/drivers/thermal/hisi_thermal.c
@@ -389,8 +389,11 @@
 static int hisi_thermal_resume(struct device *dev)
 {
 	struct hisi_thermal_data *data = dev_get_drvdata(dev);
+	int ret;
 
-	clk_prepare_enable(data->clk);
+	ret = clk_prepare_enable(data->clk);
+	if (ret)
+		return ret;
 
 	data->irq_enabled = true;
 	hisi_thermal_enable_bind_irq_sensor(data);
--- linux-4.4.0.orig/drivers/thermal/imx_thermal.c
+++ linux-4.4.0/drivers/thermal/imx_thermal.c
@@ -589,6 +589,9 @@
 	regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
 	regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
 
+	data->irq_enabled = true;
+	data->mode = THERMAL_DEVICE_ENABLED;
+
 	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
 			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
 			0, "imx_thermal", data);
@@ -600,9 +603,6 @@
 		return ret;
 	}
 
-	data->irq_enabled = true;
-	data->mode = THERMAL_DEVICE_ENABLED;
-
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/thermal/int340x_thermal/int3400_thermal.c
+++ linux-4.4.0/drivers/thermal/int340x_thermal/int3400_thermal.c
@@ -20,6 +20,13 @@
 	INT3400_THERMAL_PASSIVE_1,
 	INT3400_THERMAL_ACTIVE,
 	INT3400_THERMAL_CRITICAL,
+	INT3400_THERMAL_ADAPTIVE_PERFORMANCE,
+	INT3400_THERMAL_EMERGENCY_CALL_MODE,
+	INT3400_THERMAL_PASSIVE_2,
+	INT3400_THERMAL_POWER_BOSS,
+	INT3400_THERMAL_VIRTUAL_SENSOR,
+	INT3400_THERMAL_COOLING_MODE,
+	INT3400_THERMAL_HARDWARE_DUTY_CYCLING,
 	INT3400_THERMAL_MAXIMUM_UUID,
 };
 
@@ -27,6 +34,13 @@
 	"42A441D6-AE6A-462b-A84B-4A8CE79027D3",
 	"3A95C389-E4B8-4629-A526-C52C88626BAE",
 	"97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
+	"63BE270F-1C11-48FD-A6F7-3AF253FF3E2D",
+	"5349962F-71E6-431D-9AE8-0A635B710AEE",
+	"9E04115A-AE87-4D1C-9500-0F3E340BFE75",
+	"F5A35014-C209-46A4-993A-EB56DE7530A1",
+	"6ED722A7-9240-48A5-B479-31EEF723D7CF",
+	"16CAF1B7-DD38-40ED-B1C1-1B8A1913D531",
+	"BE84BABF-C4D4-403D-B495-3128FD44dAC1",
 };
 
 struct int3400_thermal_priv {
@@ -271,10 +285,9 @@
 
 	platform_set_drvdata(pdev, priv);
 
-	if (priv->uuid_bitmap & 1 << INT3400_THERMAL_PASSIVE_1) {
-		int3400_thermal_ops.get_mode = int3400_thermal_get_mode;
-		int3400_thermal_ops.set_mode = int3400_thermal_set_mode;
-	}
+	int3400_thermal_ops.get_mode = int3400_thermal_get_mode;
+	int3400_thermal_ops.set_mode = int3400_thermal_set_mode;
+
 	priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
 						priv, &int3400_thermal_ops,
 						&int3400_thermal_params, 0, 0);
--- linux-4.4.0.orig/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
+++ linux-4.4.0/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/thermal.h>
+#include <linux/nospec.h>
 #include "int340x_thermal_zone.h"
 
 static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
@@ -57,15 +58,16 @@
 	if (d->override_ops && d->override_ops->get_trip_temp)
 		return d->override_ops->get_trip_temp(zone, trip, temp);
 
-	if (trip < d->aux_trip_nr)
+	if (trip < d->aux_trip_nr) {
+		trip = array_index_nospec(trip, d->aux_trip_nr); /* needed? */
 		*temp = d->aux_trips[trip];
-	else if (trip == d->crt_trip_id)
+	} else if (trip == d->crt_trip_id) {
 		*temp = d->crt_temp;
-	else if (trip == d->psv_trip_id)
+	} else if (trip == d->psv_trip_id) {
 		*temp = d->psv_temp;
-	else if (trip == d->hot_trip_id)
+	} else if (trip == d->hot_trip_id) {
 		*temp = d->hot_temp;
-	else {
+	} else {
 		for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
 			if (d->act_trips[i].valid &&
 			    d->act_trips[i].id == trip) {
--- linux-4.4.0.orig/drivers/thermal/int340x_thermal/processor_thermal_device.c
+++ linux-4.4.0/drivers/thermal/int340x_thermal/processor_thermal_device.c
@@ -363,7 +363,7 @@
 		proc_priv->soc_dts = intel_soc_dts_iosf_init(
 					INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0);
 
-		if (proc_priv->soc_dts && pdev->irq) {
+		if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
 			ret = pci_enable_msi(pdev);
 			if (!ret) {
 				ret = request_threaded_irq(pdev->irq, NULL,
--- linux-4.4.0.orig/drivers/thermal/intel_powerclamp.c
+++ linux-4.4.0/drivers/thermal/intel_powerclamp.c
@@ -510,12 +510,6 @@
 	unsigned long cpu;
 	struct task_struct *thread;
 
-	/* check if pkg cstate counter is completely 0, abort in this case */
-	if (!has_pkg_state_counter()) {
-		pr_err("pkg cstate counter not functional, abort\n");
-		return -EINVAL;
-	}
-
 	set_target_ratio = clamp(set_target_ratio, 0U, MAX_TARGET_RATIO - 1);
 	/* prevent cpu hotplug */
 	get_online_cpus();
@@ -672,51 +666,25 @@
 	.set_cur_state = powerclamp_set_cur_state,
 };
 
-/* runs on Nehalem and later */
-static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = {
-	{ X86_VENDOR_INTEL, 6, 0x1a},
-	{ X86_VENDOR_INTEL, 6, 0x1c},
-	{ X86_VENDOR_INTEL, 6, 0x1e},
-	{ X86_VENDOR_INTEL, 6, 0x1f},
-	{ X86_VENDOR_INTEL, 6, 0x25},
-	{ X86_VENDOR_INTEL, 6, 0x26},
-	{ X86_VENDOR_INTEL, 6, 0x2a},
-	{ X86_VENDOR_INTEL, 6, 0x2c},
-	{ X86_VENDOR_INTEL, 6, 0x2d},
-	{ X86_VENDOR_INTEL, 6, 0x2e},
-	{ X86_VENDOR_INTEL, 6, 0x2f},
-	{ X86_VENDOR_INTEL, 6, 0x37},
-	{ X86_VENDOR_INTEL, 6, 0x3a},
-	{ X86_VENDOR_INTEL, 6, 0x3c},
-	{ X86_VENDOR_INTEL, 6, 0x3d},
-	{ X86_VENDOR_INTEL, 6, 0x3e},
-	{ X86_VENDOR_INTEL, 6, 0x3f},
-	{ X86_VENDOR_INTEL, 6, 0x45},
-	{ X86_VENDOR_INTEL, 6, 0x46},
-	{ X86_VENDOR_INTEL, 6, 0x47},
-	{ X86_VENDOR_INTEL, 6, 0x4c},
-	{ X86_VENDOR_INTEL, 6, 0x4d},
-	{ X86_VENDOR_INTEL, 6, 0x4e},
-	{ X86_VENDOR_INTEL, 6, 0x4f},
-	{ X86_VENDOR_INTEL, 6, 0x56},
-	{ X86_VENDOR_INTEL, 6, 0x57},
-	{ X86_VENDOR_INTEL, 6, 0x5e},
+static const struct x86_cpu_id __initconst intel_powerclamp_ids[] = {
+	{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_MWAIT },
 	{}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids);
 
 static int __init powerclamp_probe(void)
 {
+
 	if (!x86_match_cpu(intel_powerclamp_ids)) {
-		pr_err("Intel powerclamp does not run on family %d model %d\n",
-				boot_cpu_data.x86, boot_cpu_data.x86_model);
+		pr_err("CPU does not support MWAIT");
 		return -ENODEV;
 	}
-	if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ||
-		!boot_cpu_has(X86_FEATURE_CONSTANT_TSC) ||
-		!boot_cpu_has(X86_FEATURE_MWAIT) ||
-		!boot_cpu_has(X86_FEATURE_ARAT))
+
+	/* The goal for idle time alignment is to achieve package cstate. */
+	if (!has_pkg_state_counter()) {
+		pr_info("No package C-state available");
 		return -ENODEV;
+	}
 
 	/* find the deepest mwait value */
 	find_target_mwait();
--- linux-4.4.0.orig/drivers/thermal/of-thermal.c
+++ linux-4.4.0/drivers/thermal/of-thermal.c
@@ -284,10 +284,13 @@
 
 	mutex_lock(&tz->lock);
 
-	if (mode == THERMAL_DEVICE_ENABLED)
+	if (mode == THERMAL_DEVICE_ENABLED) {
 		tz->polling_delay = data->polling_delay;
-	else
+		tz->passive_delay = data->passive_delay;
+	} else {
 		tz->polling_delay = 0;
+		tz->passive_delay = 0;
+	}
 
 	mutex_unlock(&tz->lock);
 
--- linux-4.4.0.orig/drivers/thermal/power_allocator.c
+++ linux-4.4.0/drivers/thermal/power_allocator.c
@@ -523,6 +523,7 @@
 	struct thermal_instance *instance;
 	struct power_allocator_params *params = tz->governor_data;
 
+	mutex_lock(&tz->lock);
 	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
 		if ((instance->trip != params->trip_max_desired_temperature) ||
 		    (!cdev_is_power_actor(instance->cdev)))
@@ -532,6 +533,7 @@
 		instance->cdev->updated = false;
 		thermal_cdev_update(instance->cdev);
 	}
+	mutex_unlock(&tz->lock);
 }
 
 /**
--- linux-4.4.0.orig/drivers/thermal/rcar_thermal.c
+++ linux-4.4.0/drivers/thermal/rcar_thermal.c
@@ -350,8 +350,8 @@
 	rcar_thermal_for_each_priv(priv, common) {
 		if (rcar_thermal_had_changed(priv, status)) {
 			rcar_thermal_irq_disable(priv);
-			schedule_delayed_work(&priv->work,
-					      msecs_to_jiffies(300));
+			queue_delayed_work(system_freezable_wq, &priv->work,
+					   msecs_to_jiffies(300));
 		}
 	}
 
--- linux-4.4.0.orig/drivers/thermal/rockchip_thermal.c
+++ linux-4.4.0/drivers/thermal/rockchip_thermal.c
@@ -545,15 +545,14 @@
 			 thermal->chip->tshut_temp);
 		thermal->tshut_temp = thermal->chip->tshut_temp;
 	} else {
+		if (shut_temp > INT_MAX) {
+			dev_err(dev, "Invalid tshut temperature specified: %d\n",
+				shut_temp);
+			return -ERANGE;
+		}
 		thermal->tshut_temp = shut_temp;
 	}
 
-	if (thermal->tshut_temp > INT_MAX) {
-		dev_err(dev, "Invalid tshut temperature specified: %d\n",
-			thermal->tshut_temp);
-		return -ERANGE;
-	}
-
 	if (of_property_read_u32(np, "rockchip,hw-tshut-mode", &tshut_mode)) {
 		dev_warn(dev,
 			 "Missing tshut mode property, using default (%s)\n",
--- linux-4.4.0.orig/drivers/thermal/samsung/exynos_tmu.c
+++ linux-4.4.0/drivers/thermal/samsung/exynos_tmu.c
@@ -585,6 +585,7 @@
 		threshold_code = temp_to_code(data, temp);
 
 		rising_threshold = readl(data->base + rising_reg_offset);
+		rising_threshold &= ~(0xff << j * 8);
 		rising_threshold |= (threshold_code << j * 8);
 		writel(rising_threshold, data->base + rising_reg_offset);
 
--- linux-4.4.0.orig/drivers/thermal/spear_thermal.c
+++ linux-4.4.0/drivers/thermal/spear_thermal.c
@@ -54,8 +54,7 @@
 	.get_temp = thermal_get_temp,
 };
 
-#ifdef CONFIG_PM
-static int spear_thermal_suspend(struct device *dev)
+static int __maybe_unused spear_thermal_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
@@ -72,7 +71,7 @@
 	return 0;
 }
 
-static int spear_thermal_resume(struct device *dev)
+static int __maybe_unused spear_thermal_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
@@ -94,7 +93,6 @@
 
 	return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(spear_thermal_pm_ops, spear_thermal_suspend,
 		spear_thermal_resume);
--- linux-4.4.0.orig/drivers/thermal/step_wise.c
+++ linux-4.4.0/drivers/thermal/step_wise.c
@@ -31,8 +31,7 @@
  * If the temperature is higher than a trip point,
  *    a. if the trend is THERMAL_TREND_RAISING, use higher cooling
  *       state for this trip point
- *    b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
- *       state for this trip point
+ *    b. if the trend is THERMAL_TREND_DROPPING, do nothing
  *    c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit
  *       for this trip point
  *    d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit
@@ -63,6 +62,19 @@
 	next_target = instance->target;
 	dev_dbg(&cdev->device, "cur_state=%ld\n", cur_state);
 
+	if (!instance->initialized) {
+		if (throttle) {
+			next_target = (cur_state + 1) >= instance->upper ?
+					instance->upper :
+					((cur_state + 1) < instance->lower ?
+					instance->lower : (cur_state + 1));
+		} else {
+			next_target = THERMAL_NO_TARGET;
+		}
+
+		return next_target;
+	}
+
 	switch (trend) {
 	case THERMAL_TREND_RAISING:
 		if (throttle) {
@@ -81,9 +93,11 @@
 			if (!throttle)
 				next_target = THERMAL_NO_TARGET;
 		} else {
-			next_target = cur_state - 1;
-			if (next_target > instance->upper)
-				next_target = instance->upper;
+			if (!throttle) {
+				next_target = cur_state - 1;
+				if (next_target > instance->upper)
+					next_target = instance->upper;
+			}
 		}
 		break;
 	case THERMAL_TREND_DROP_FULL:
@@ -149,7 +163,7 @@
 		dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
 					old_target, (int)instance->target);
 
-		if (old_target == instance->target)
+		if (instance->initialized && old_target == instance->target)
 			continue;
 
 		/* Activate a passive thermal instance */
@@ -161,7 +175,7 @@
 			instance->target == THERMAL_NO_TARGET)
 			update_passive_instance(tz, trip_type, -1);
 
-
+		instance->initialized = true;
 		instance->cdev->updated = false; /* cdev needs update */
 	}
 
--- linux-4.4.0.orig/drivers/thermal/thermal_core.c
+++ linux-4.4.0/drivers/thermal/thermal_core.c
@@ -37,6 +37,7 @@
 #include <linux/of.h>
 #include <net/netlink.h>
 #include <net/genetlink.h>
+#include <linux/suspend.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/thermal.h>
@@ -59,6 +60,8 @@
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
+static atomic_t in_suspend;
+
 static struct thermal_governor *def_governor;
 
 static struct thermal_governor *__find_governor(const char *name)
@@ -451,6 +454,10 @@
 {
 	enum thermal_trip_type type;
 
+	/* Ignore disabled trip points */
+	if (test_bit(trip, &tz->trips_disabled))
+		return;
+
 	tz->ops->get_trip_type(tz, trip, &type);
 
 	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
@@ -532,14 +539,31 @@
 	mutex_unlock(&tz->lock);
 
 	trace_thermal_temperature(tz);
-	dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
-				tz->last_temperature, tz->temperature);
+	if (tz->last_temperature == THERMAL_TEMP_INVALID)
+		dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n",
+			tz->temperature);
+	else
+		dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
+			tz->last_temperature, tz->temperature);
+}
+
+static void thermal_zone_device_reset(struct thermal_zone_device *tz)
+{
+	struct thermal_instance *pos;
+
+	tz->temperature = THERMAL_TEMP_INVALID;
+	tz->passive = 0;
+	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
+		pos->initialized = false;
 }
 
 void thermal_zone_device_update(struct thermal_zone_device *tz)
 {
 	int count;
 
+	if (atomic_read(&in_suspend))
+		return;
+
 	if (!tz->ops->get_temp)
 		return;
 
@@ -1321,6 +1345,7 @@
 	if (!result) {
 		list_add_tail(&dev->tz_node, &tz->thermal_instances);
 		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
+		atomic_set(&tz->need_update, 1);
 	}
 	mutex_unlock(&cdev->lock);
 	mutex_unlock(&tz->lock);
@@ -1430,6 +1455,7 @@
 				  const struct thermal_cooling_device_ops *ops)
 {
 	struct thermal_cooling_device *cdev;
+	struct thermal_zone_device *pos = NULL;
 	int result;
 
 	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
@@ -1474,6 +1500,12 @@
 	/* Update binding information for 'this' new cdev */
 	bind_cdev(cdev);
 
+	mutex_lock(&thermal_list_lock);
+	list_for_each_entry(pos, &thermal_tz_list, node)
+		if (atomic_cmpxchg(&pos->need_update, 1, 0))
+			thermal_zone_device_update(pos);
+	mutex_unlock(&thermal_list_lock);
+
 	return cdev;
 }
 
@@ -1768,6 +1800,7 @@
 {
 	struct thermal_zone_device *tz;
 	enum thermal_trip_type trip_type;
+	int trip_temp;
 	int result;
 	int count;
 	int passive = 0;
@@ -1806,6 +1839,8 @@
 	tz->trips = trips;
 	tz->passive_delay = passive_delay;
 	tz->polling_delay = polling_delay;
+	/* A new thermal zone needs to be updated anyway. */
+	atomic_set(&tz->need_update, 1);
 
 	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
 	result = device_register(&tz->device);
@@ -1837,9 +1872,15 @@
 		goto unregister;
 
 	for (count = 0; count < trips; count++) {
-		tz->ops->get_trip_type(tz, count, &trip_type);
+		if (tz->ops->get_trip_type(tz, count, &trip_type))
+			set_bit(count, &tz->trips_disabled);
 		if (trip_type == THERMAL_TRIP_PASSIVE)
 			passive = 1;
+		if (tz->ops->get_trip_temp(tz, count, &trip_temp))
+			set_bit(count, &tz->trips_disabled);
+		/* Check for bogus trip points */
+		if (trip_temp == 0)
+			set_bit(count, &tz->trips_disabled);
 	}
 
 	if (!passive) {
@@ -1900,7 +1941,10 @@
 
 	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
 
-	thermal_zone_device_update(tz);
+	thermal_zone_device_reset(tz);
+	/* Update the new thermal zone and mark it as already updated. */
+	if (atomic_cmpxchg(&tz->need_update, 1, 0))
+		thermal_zone_device_update(tz);
 
 	return tz;
 
@@ -1958,7 +2002,7 @@
 
 	mutex_unlock(&thermal_list_lock);
 
-	thermal_zone_device_set_polling(tz, 0);
+	cancel_delayed_work_sync(&tz->poll_queue);
 
 	if (tz->type[0])
 		device_remove_file(&tz->device, &dev_attr_type);
@@ -2140,6 +2184,36 @@
 	thermal_gov_power_allocator_unregister();
 }
 
+static int thermal_pm_notify(struct notifier_block *nb,
+				unsigned long mode, void *_unused)
+{
+	struct thermal_zone_device *tz;
+
+	switch (mode) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_RESTORE_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		atomic_set(&in_suspend, 1);
+		break;
+	case PM_POST_HIBERNATION:
+	case PM_POST_RESTORE:
+	case PM_POST_SUSPEND:
+		atomic_set(&in_suspend, 0);
+		list_for_each_entry(tz, &thermal_tz_list, node) {
+			thermal_zone_device_reset(tz);
+			thermal_zone_device_update(tz);
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static struct notifier_block thermal_pm_nb = {
+	.notifier_call = thermal_pm_notify,
+};
+
 static int __init thermal_init(void)
 {
 	int result;
@@ -2160,6 +2234,11 @@
 	if (result)
 		goto exit_netlink;
 
+	result = register_pm_notifier(&thermal_pm_nb);
+	if (result)
+		pr_warn("Thermal: Can not register suspend notifier, return %d\n",
+			result);
+
 	return 0;
 
 exit_netlink:
@@ -2179,6 +2258,7 @@
 
 static void __exit thermal_exit(void)
 {
+	unregister_pm_notifier(&thermal_pm_nb);
 	of_thermal_destroy_zones();
 	genetlink_exit();
 	class_unregister(&thermal_class);
--- linux-4.4.0.orig/drivers/thermal/thermal_core.h
+++ linux-4.4.0/drivers/thermal/thermal_core.h
@@ -41,6 +41,7 @@
 	struct thermal_zone_device *tz;
 	struct thermal_cooling_device *cdev;
 	int trip;
+	bool initialized;
 	unsigned long upper;	/* Highest cooling state for this trip point */
 	unsigned long lower;	/* Lowest cooling state for this trip point */
 	unsigned long target;	/* expected cooling state */
--- linux-4.4.0.orig/drivers/thermal/thermal_hwmon.c
+++ linux-4.4.0/drivers/thermal/thermal_hwmon.c
@@ -98,7 +98,7 @@
 	int temperature;
 	int ret;
 
-	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
+	ret = tz->ops->get_crit_temp(tz, &temperature);
 	if (ret)
 		return ret;
 
--- linux-4.4.0.orig/drivers/thermal/thermal_hwmon.h
+++ linux-4.4.0/drivers/thermal/thermal_hwmon.h
@@ -34,13 +34,13 @@
 int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz);
 void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz);
 #else
-static int
+static inline int
 thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 {
 	return 0;
 }
 
-static void
+static inline void
 thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
 {
 }
--- linux-4.4.0.orig/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
+++ linux-4.4.0/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
@@ -49,20 +49,21 @@
 
 /*
  * Temperature values in milli degree celsius
- * ADC code values from 530 to 923
+ * ADC code values from 13 to 107, see TRM
+ * "18.4.10.2.3 ADC Codes Versus Temperature".
  */
 static const int
 omap4430_adc_to_temp[OMAP4430_ADC_END_VALUE - OMAP4430_ADC_START_VALUE + 1] = {
-	-38000, -35000, -34000, -32000, -30000, -28000, -26000, -24000, -22000,
-	-20000, -18000, -17000, -15000, -13000, -12000, -10000, -8000, -6000,
-	-5000, -3000, -1000, 0, 2000, 3000, 5000, 6000, 8000, 10000, 12000,
-	13000, 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28000, 30000,
-	32000, 33000, 35000, 37000, 38000, 40000, 42000, 43000, 45000, 47000,
-	48000, 50000, 52000, 53000, 55000, 57000, 58000, 60000, 62000, 64000,
-	66000, 68000, 70000, 71000, 73000, 75000, 77000, 78000, 80000, 82000,
-	83000, 85000, 87000, 88000, 90000, 92000, 93000, 95000, 97000, 98000,
-	100000, 102000, 103000, 105000, 107000, 109000, 111000, 113000, 115000,
-	117000, 118000, 120000, 122000, 123000,
+	-40000, -38000, -35000, -34000, -32000, -30000, -28000, -26000, -24000,
+	-22000,	-20000, -18500, -17000, -15000, -13500, -12000, -10000, -8000,
+	-6500, -5000, -3500, -1500, 0, 2000, 3500, 5000, 6500, 8500, 10000,
+	12000, 13500, 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28500,
+	30000, 32000, 33500, 35000, 37000, 38500, 40000, 42000, 43500, 45000,
+	47000, 48500, 50000, 52000, 53500, 55000, 57000, 58500, 60000, 62000,
+	64000, 66000, 68000, 70000, 71500, 73500, 75000, 77000, 78500, 80000,
+	82000, 83500, 85000, 87000, 88500, 90000, 92000, 93500, 95000, 97000,
+	98500, 100000, 102000, 103500, 105000, 107000, 109000, 111000, 113000,
+	115000, 117000, 118500, 120000, 122000, 123500, 125000,
 };
 
 /* OMAP4430 data */
--- linux-4.4.0.orig/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
+++ linux-4.4.0/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
@@ -67,9 +67,13 @@
  * and thresholds for OMAP4430.
  */
 
-/* ADC conversion table limits */
-#define OMAP4430_ADC_START_VALUE			0
-#define OMAP4430_ADC_END_VALUE				127
+/*
+ * ADC conversion table limits. Ignore values outside the TRM listed
+ * range to avoid bogus thermal shutdowns. See omap4430 TRM chapter
+ * "18.4.10.2.3 ADC Codes Versus Temperature".
+ */
+#define OMAP4430_ADC_START_VALUE			13
+#define OMAP4430_ADC_END_VALUE				107
 /* bandgap clock limits (no control on 4430) */
 #define OMAP4430_MAX_FREQ				32768
 #define OMAP4430_MIN_FREQ				32768
--- linux-4.4.0.orig/drivers/thunderbolt/eeprom.c
+++ linux-4.4.0/drivers/thunderbolt/eeprom.c
@@ -444,6 +444,7 @@
 	return tb_drom_parse_entries(sw);
 err:
 	kfree(sw->drom);
+	sw->drom = NULL;
 	return -EIO;
 
 }
--- linux-4.4.0.orig/drivers/thunderbolt/nhi.c
+++ linux-4.4.0/drivers/thunderbolt/nhi.c
@@ -94,9 +94,20 @@
 	return io;
 }
 
-static void ring_iowrite16desc(struct tb_ring *ring, u32 value, u32 offset)
+static void ring_iowrite_cons(struct tb_ring *ring, u16 cons)
 {
-	iowrite16(value, ring_desc_base(ring) + offset);
+	/*
+	 * The other 16-bits in the register is read-only and writes to it
+	 * are ignored by the hardware so we can save one ioread32() by
+	 * filling the read-only bits with zeroes.
+	 */
+	iowrite32(cons, ring_desc_base(ring) + 8);
+}
+
+static void ring_iowrite_prod(struct tb_ring *ring, u16 prod)
+{
+	/* See ring_iowrite_cons() above for explanation */
+	iowrite32(prod << 16, ring_desc_base(ring) + 8);
 }
 
 static void ring_iowrite32desc(struct tb_ring *ring, u32 value, u32 offset)
@@ -148,7 +159,10 @@
 			descriptor->sof = frame->sof;
 		}
 		ring->head = (ring->head + 1) % ring->size;
-		ring_iowrite16desc(ring, ring->head, ring->is_tx ? 10 : 8);
+		if (ring->is_tx)
+			ring_iowrite_prod(ring, ring->head);
+		else
+			ring_iowrite_cons(ring, ring->head);
 	}
 }
 
@@ -368,7 +382,7 @@
 
 	ring_iowrite32options(ring, 0, 0);
 	ring_iowrite64desc(ring, 0, 0);
-	ring_iowrite16desc(ring, 0, ring->is_tx ? 10 : 8);
+	ring_iowrite32desc(ring, 0, 8);
 	ring_iowrite32desc(ring, 0, 12);
 	ring->head = 0;
 	ring->tail = 0;
@@ -627,6 +641,7 @@
 					    * we just disable hotplug, the
 					    * pci-tunnels stay alive.
 					    */
+	.thaw_noirq = nhi_resume_noirq,
 	.restore_noirq = nhi_resume_noirq,
 };
 
--- linux-4.4.0.orig/drivers/tty/Kconfig
+++ linux-4.4.0/drivers/tty/Kconfig
@@ -226,7 +226,7 @@
 
 config CYZ_INTR
 	bool "Cyclades-Z interrupt mode operation"
-	depends on CYCLADES
+	depends on CYCLADES && PCI
 	help
 	  The Cyclades-Z family of multiport cards allows 2 (two) driver op
 	  modes: polling and interrupt. In polling mode, the driver will check
@@ -466,4 +466,27 @@
 	help
 	  FDC channel number to use for KGDB.
 
+config LDISC_AUTOLOAD
+	bool "Automatically load TTY Line Disciplines"
+	default y
+	help
+	  Historically the kernel has always automatically loaded any
+	  line discipline that is in a kernel module when a user asks
+	  for it to be loaded with the TIOCSETD ioctl, or through other
+	  means.  This is not always the best thing to do on systems
+	  where you know you will not be using some of the more
+	  "ancient" line disciplines, so prevent the kernel from doing
+	  this unless the request is coming from a process with the
+	  CAP_SYS_MODULE permissions.
+
+	  Say 'Y' here if you trust your userspace users to do the right
+	  thing, or if you have only provided the line disciplines that
+	  you know you will be using, or if you wish to continue to use
+	  the traditional method of on-demand loading of these modules
+	  by any user.
+
+	  This functionality can be changed at runtime with the
+	  dev.tty.ldisc_autoload sysctl, this configuration option will
+	  only set the default value of this functionality.
+
 endif # TTY
--- linux-4.4.0.orig/drivers/tty/cyclades.c
+++ linux-4.4.0/drivers/tty/cyclades.c
@@ -158,8 +158,8 @@
 static long maddr[NR_CARDS];
 static int irq[NR_CARDS];
 
-module_param_array(maddr, long, NULL, 0);
-module_param_array(irq, int, NULL, 0);
+module_param_hw_array(maddr, long, iomem, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
 
 #endif				/* CONFIG_ISA */
 
--- linux-4.4.0.orig/drivers/tty/ehv_bytechan.c
+++ linux-4.4.0/drivers/tty/ehv_bytechan.c
@@ -140,6 +140,21 @@
 	return 1;
 }
 
+static unsigned int local_ev_byte_channel_send(unsigned int handle,
+					       unsigned int *count,
+					       const char *p)
+{
+	char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
+	unsigned int c = *count;
+
+	if (c < sizeof(buffer)) {
+		memcpy(buffer, p, c);
+		memset(&buffer[c], 0, sizeof(buffer) - c);
+		p = buffer;
+	}
+	return ev_byte_channel_send(handle, count, p);
+}
+
 /*************************** EARLY CONSOLE DRIVER ***************************/
 
 #ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC
@@ -158,7 +173,7 @@
 
 	do {
 		count = 1;
-		ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
+		ret = local_ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
 					   &count, &data);
 	} while (ret == EV_EAGAIN);
 }
@@ -225,7 +240,7 @@
 	while (count) {
 		len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES);
 		do {
-			ret = ev_byte_channel_send(handle, &len, s);
+			ret = local_ev_byte_channel_send(handle, &len, s);
 		} while (ret == EV_EAGAIN);
 		count -= len;
 		s += len;
@@ -405,7 +420,7 @@
 			    CIRC_CNT_TO_END(bc->head, bc->tail, BUF_SIZE),
 			    EV_BYTE_CHANNEL_MAX_BYTES);
 
-		ret = ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail);
+		ret = local_ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail);
 
 		/* 'len' is valid only if the return code is 0 or EV_EAGAIN */
 		if (!ret || (ret == EV_EAGAIN))
--- linux-4.4.0.orig/drivers/tty/hvc/hvc_console.c
+++ linux-4.4.0/drivers/tty/hvc/hvc_console.c
@@ -89,6 +89,8 @@
  */
 static DEFINE_SPINLOCK(hvc_structs_lock);
 
+/* Mutex to serialize hvc_open */
+static DEFINE_MUTEX(hvc_open_mutex);
 /*
  * This value is used to assign a tty->index value to a hvc_struct based
  * upon order of exposure via hvc_probe(), when we can not match it to
@@ -289,10 +291,6 @@
 	vtermnos[index] = vtermno;
 	cons_ops[index] = ops;
 
-	/* reserve all indices up to and including this index */
-	if (last_hvc < index)
-		last_hvc = index;
-
 	/* check if we need to re-register the kernel console */
 	hvc_check_console(index);
 
@@ -337,16 +335,24 @@
  */
 static int hvc_open(struct tty_struct *tty, struct file * filp)
 {
-	struct hvc_struct *hp = tty->driver_data;
+	struct hvc_struct *hp;
 	unsigned long flags;
 	int rc = 0;
 
+	mutex_lock(&hvc_open_mutex);
+
+	hp = tty->driver_data;
+	if (!hp) {
+		rc = -EIO;
+		goto out;
+	}
+
 	spin_lock_irqsave(&hp->port.lock, flags);
 	/* Check and then increment for fast path open. */
 	if (hp->port.count++ > 0) {
 		spin_unlock_irqrestore(&hp->port.lock, flags);
 		hvc_kick();
-		return 0;
+		goto out;
 	} /* else count == 0 */
 	spin_unlock_irqrestore(&hp->port.lock, flags);
 
@@ -375,6 +381,8 @@
 	/* Force wakeup of the polling thread */
 	hvc_kick();
 
+out:
+	mutex_unlock(&hvc_open_mutex);
 	return rc;
 }
 
@@ -896,13 +904,22 @@
 		    cons_ops[i] == hp->ops)
 			break;
 
-	/* no matching slot, just use a counter */
-	if (i >= MAX_NR_HVC_CONSOLES)
-		i = ++last_hvc;
+	if (i >= MAX_NR_HVC_CONSOLES) {
+
+		/* find 'empty' slot for console */
+		for (i = 0; i < MAX_NR_HVC_CONSOLES && vtermnos[i] != -1; i++) {
+		}
+
+		/* no matching slot, just use a counter */
+		if (i == MAX_NR_HVC_CONSOLES)
+			i = ++last_hvc + MAX_NR_HVC_CONSOLES;
+	}
 
 	hp->index = i;
-	cons_ops[i] = ops;
-	vtermnos[i] = vtermno;
+	if (i < MAX_NR_HVC_CONSOLES) {
+		cons_ops[i] = ops;
+		vtermnos[i] = vtermno;
+	}
 
 	list_add_tail(&(hp->next), &hvc_structs);
 	spin_unlock(&hvc_structs_lock);
--- linux-4.4.0.orig/drivers/tty/hvc/hvc_console.h
+++ linux-4.4.0/drivers/tty/hvc/hvc_console.h
@@ -60,6 +60,7 @@
 	struct winsize ws;
 	struct work_struct tty_resize;
 	struct list_head next;
+	unsigned long flags;
 };
 
 /* implemented by a low level driver */
--- linux-4.4.0.orig/drivers/tty/hvc/hvc_irq.c
+++ linux-4.4.0/drivers/tty/hvc/hvc_irq.c
@@ -14,6 +14,11 @@
 	/* if hvc_poll request a repoll, then kick the hvcd thread */
 	if (hvc_poll(dev_instance))
 		hvc_kick();
+
+	/*
+	 * We're safe to always return IRQ_HANDLED as the hvcd thread will
+	 * iterate through each hvc_struct.
+	 */
 	return IRQ_HANDLED;
 }
 
@@ -28,8 +33,8 @@
 		hp->irq_requested = 0;
 		return 0;
 	}
-	rc = request_irq(irq, hvc_handle_interrupt, 0,
-			   "hvc_console", hp);
+	rc = request_irq(irq, hvc_handle_interrupt, hp->flags,
+			"hvc_console", hp);
 	if (!rc)
 		hp->irq_requested = 1;
 	return rc;
--- linux-4.4.0.orig/drivers/tty/hvc/hvc_opal.c
+++ linux-4.4.0/drivers/tty/hvc/hvc_opal.c
@@ -214,7 +214,13 @@
 		dev->dev.of_node->full_name,
 		boot ? " (boot console)" : "");
 
-	irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT));
+	irq = irq_of_parse_and_map(dev->dev.of_node, 0);
+	if (!irq) {
+		pr_info("hvc%d: No interrupts property, using OPAL event\n",
+				termno);
+		irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT));
+	}
+
 	if (!irq) {
 		pr_err("hvc_opal: Unable to map interrupt for device %s\n",
 			dev->dev.of_node->full_name);
@@ -224,6 +230,9 @@
 	hp = hvc_alloc(termno, irq, ops, MAX_VIO_PUT_CHARS);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
+
+	/* hvc consoles on powernv may need to share a single irq */
+	hp->flags = IRQF_SHARED;
 	dev_set_drvdata(&dev->dev, hp);
 
 	return 0;
@@ -323,7 +332,6 @@
 	udbg_putc = udbg_opal_putc;
 	udbg_getc = udbg_opal_getc;
 	udbg_getc_poll = udbg_opal_getc_poll;
-	tb_ticks_per_usec = 0x200; /* Make udelay not suck */
 }
 
 void __init hvc_opal_init_early(void)
--- linux-4.4.0.orig/drivers/tty/hvc/hvc_vio.c
+++ linux-4.4.0/drivers/tty/hvc/hvc_vio.c
@@ -122,6 +122,14 @@
 	return got;
 }
 
+/**
+ * hvterm_raw_put_chars: send characters to firmware for given vterm adapter
+ * @vtermno: The virtual terminal number.
+ * @buf: The characters to send. Because of the underlying hypercall in
+ *       hvc_put_chars(), this buffer must be at least 16 bytes long, even if
+ *       you are sending fewer chars.
+ * @count: number of chars to send.
+ */
 static int hvterm_raw_put_chars(uint32_t vtermno, const char *buf, int count)
 {
 	struct hvterm_priv *pv = hvterm_privs[vtermno];
@@ -234,6 +242,7 @@
 static void udbg_hvc_putc(char c)
 {
 	int count = -1;
+	unsigned char bounce_buffer[16];
 
 	if (!hvterm_privs[0])
 		return;
@@ -244,7 +253,12 @@
 	do {
 		switch(hvterm_privs[0]->proto) {
 		case HV_PROTOCOL_RAW:
-			count = hvterm_raw_put_chars(0, &c, 1);
+			/*
+			 * hvterm_raw_put_chars requires at least a 16-byte
+			 * buffer, so go via the bounce buffer
+			 */
+			bounce_buffer[0] = c;
+			count = hvterm_raw_put_chars(0, bounce_buffer, 1);
 			break;
 		case HV_PROTOCOL_HVSI:
 			count = hvterm_hvsi_put_chars(0, &c, 1);
--- linux-4.4.0.orig/drivers/tty/hvc/hvc_xen.c
+++ linux-4.4.0/drivers/tty/hvc/hvc_xen.c
@@ -49,6 +49,8 @@
 	struct xenbus_device *xbdev;
 	struct xencons_interface *intf;
 	unsigned int evtchn;
+	XENCONS_RING_IDX out_cons;
+	unsigned int out_cons_same;
 	struct hvc_struct *hvc;
 	int irq;
 	int vtermno;
@@ -143,6 +145,8 @@
 	XENCONS_RING_IDX cons, prod;
 	int recv = 0;
 	struct xencons_info *xencons = vtermno_to_xencons(vtermno);
+	unsigned int eoiflag = 0;
+
 	if (xencons == NULL)
 		return -EINVAL;
 	intf = xencons->intf;
@@ -158,7 +162,27 @@
 	mb();			/* read ring before consuming */
 	intf->in_cons = cons;
 
-	notify_daemon(xencons);
+	/*
+	 * When to mark interrupt having been spurious:
+	 * - there was no new data to be read, and
+	 * - the backend did not consume some output bytes, and
+	 * - the previous round with no read data didn't see consumed bytes
+	 *   (we might have a race with an interrupt being in flight while
+	 *   updating xencons->out_cons, so account for that by allowing one
+	 *   round without any visible reason)
+	 */
+	if (intf->out_cons != xencons->out_cons) {
+		xencons->out_cons = intf->out_cons;
+		xencons->out_cons_same = 0;
+	}
+	if (recv) {
+		notify_daemon(xencons);
+	} else if (xencons->out_cons_same++ > 1) {
+		eoiflag = XEN_EOI_FLAG_SPURIOUS;
+	}
+
+	xen_irq_lateeoi(xencons->irq, eoiflag);
+
 	return recv;
 }
 
@@ -323,6 +347,7 @@
 	}
 }
 
+#ifdef CONFIG_HVC_XEN_FRONTEND
 static void xencons_disconnect_backend(struct xencons_info *info)
 {
 	if (info->irq > 0)
@@ -363,7 +388,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_HVC_XEN_FRONTEND
 static int xencons_remove(struct xenbus_device *dev)
 {
 	return xen_console_remove(dev_get_drvdata(&dev->dev));
@@ -380,7 +404,7 @@
 	if (ret)
 		return ret;
 	info->evtchn = evtchn;
-	irq = bind_evtchn_to_irq(evtchn);
+	irq = bind_interdomain_evtchn_to_irq_lateeoi(dev->otherend_id, evtchn);
 	if (irq < 0)
 		return irq;
 	info->irq = irq;
@@ -544,7 +568,7 @@
 			return r;
 
 		info = vtermno_to_xencons(HVC_COOKIE);
-		info->irq = bind_evtchn_to_irq(info->evtchn);
+		info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn);
 	}
 	if (info->irq < 0)
 		info->irq = 0; /* NO_IRQ */
--- linux-4.4.0.orig/drivers/tty/hvc/hvcs.c
+++ linux-4.4.0/drivers/tty/hvc/hvcs.c
@@ -1232,13 +1232,6 @@
 
 		tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
 
-		/*
-		 * This line is important because it tells hvcs_open that this
-		 * device needs to be re-configured the next time hvcs_open is
-		 * called.
-		 */
-		tty->driver_data = NULL;
-
 		free_irq(irq, hvcsd);
 		return;
 	} else if (hvcsd->port.count < 0) {
@@ -1254,6 +1247,13 @@
 {
 	struct hvcs_struct *hvcsd = tty->driver_data;
 
+	/*
+	 * This line is important because it tells hvcs_open that this
+	 * device needs to be re-configured the next time hvcs_open is
+	 * called.
+	 */
+	tty->driver_data = NULL;
+
 	tty_port_put(&hvcsd->port);
 }
 
--- linux-4.4.0.orig/drivers/tty/ipwireless/hardware.c
+++ linux-4.4.0/drivers/tty/ipwireless/hardware.c
@@ -1515,6 +1515,8 @@
 			sizeof(struct ipw_setup_get_version_query_packet),
 			ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
 			TL_SETUP_SIGNO_GET_VERSION_QRY);
+	if (!ver_packet)
+		return;
 	ver_packet->header.length = sizeof(struct tl_setup_get_version_qry);
 
 	/*
--- linux-4.4.0.orig/drivers/tty/ipwireless/main.c
+++ linux-4.4.0/drivers/tty/ipwireless/main.c
@@ -113,6 +113,10 @@
 
 	ipw->common_memory = ioremap(p_dev->resource[2]->start,
 				resource_size(p_dev->resource[2]));
+	if (!ipw->common_memory) {
+		ret = -ENOMEM;
+		goto exit1;
+	}
 	if (!request_mem_region(p_dev->resource[2]->start,
 				resource_size(p_dev->resource[2]),
 				IPWIRELESS_PCCARD_NAME)) {
@@ -133,6 +137,10 @@
 
 	ipw->attr_memory = ioremap(p_dev->resource[3]->start,
 				resource_size(p_dev->resource[3]));
+	if (!ipw->attr_memory) {
+		ret = -ENOMEM;
+		goto exit3;
+	}
 	if (!request_mem_region(p_dev->resource[3]->start,
 				resource_size(p_dev->resource[3]),
 				IPWIRELESS_PCCARD_NAME)) {
--- linux-4.4.0.orig/drivers/tty/ipwireless/network.c
+++ linux-4.4.0/drivers/tty/ipwireless/network.c
@@ -116,7 +116,7 @@
 					       skb->len,
 					       notify_packet_sent,
 					       network);
-			if (ret == -1) {
+			if (ret < 0) {
 				skb_pull(skb, 2);
 				return 0;
 			}
@@ -133,7 +133,7 @@
 					       notify_packet_sent,
 					       network);
 			kfree(buf);
-			if (ret == -1)
+			if (ret < 0)
 				return 0;
 		}
 		kfree_skb(skb);
--- linux-4.4.0.orig/drivers/tty/ipwireless/tty.c
+++ linux-4.4.0/drivers/tty/ipwireless/tty.c
@@ -217,7 +217,7 @@
 	ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS,
 			       buf, count,
 			       ipw_write_packet_sent_callback, tty);
-	if (ret == -1) {
+	if (ret < 0) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return 0;
 	}
--- linux-4.4.0.orig/drivers/tty/moxa.c
+++ linux-4.4.0/drivers/tty/moxa.c
@@ -180,7 +180,7 @@
 
 module_param_array(type, uint, NULL, 0);
 MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
-module_param_array(baseaddr, ulong, NULL, 0);
+module_param_hw_array(baseaddr, ulong, ioport, NULL, 0);
 MODULE_PARM_DESC(baseaddr, "base address");
 module_param_array(numports, uint, NULL, 0);
 MODULE_PARM_DESC(numports, "numports (ignored for C218)");
--- linux-4.4.0.orig/drivers/tty/mxser.c
+++ linux-4.4.0/drivers/tty/mxser.c
@@ -183,7 +183,7 @@
 
 MODULE_AUTHOR("Casper Yang");
 MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
-module_param_array(ioaddr, ulong, NULL, 0);
+module_param_hw_array(ioaddr, ulong, ioport, NULL, 0);
 MODULE_PARM_DESC(ioaddr, "ISA io addresses to look for a moxa board");
 module_param(ttymajor, int, 0);
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/tty/n_gsm.c
+++ linux-4.4.0/drivers/tty/n_gsm.c
@@ -137,6 +137,9 @@
 	struct mutex mutex;
 
 	/* Link layer */
+	int mode;
+#define DLCI_MODE_ABM		0	/* Normal Asynchronous Balanced Mode */
+#define DLCI_MODE_ADM		1	/* Asynchronous Disconnected Mode */
 	spinlock_t lock;	/* Protects the internal state */
 	struct timer_list t1;	/* Retransmit timer for SABM and UA */
 	int retries;
@@ -678,11 +681,10 @@
  *	FIXME: lock against link layer control transmissions
  */
 
-static void gsm_data_kick(struct gsm_mux *gsm)
+static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci)
 {
 	struct gsm_msg *msg, *nmsg;
 	int len;
-	int skip_sof = 0;
 
 	list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
 		if (gsm->constipated && msg->addr)
@@ -704,18 +706,23 @@
 			print_hex_dump_bytes("gsm_data_kick: ",
 					     DUMP_PREFIX_OFFSET,
 					     gsm->txframe, len);
-
-		if (gsm->output(gsm, gsm->txframe + skip_sof,
-						len - skip_sof) < 0)
+		if (gsm->output(gsm, gsm->txframe, len) < 0)
 			break;
 		/* FIXME: Can eliminate one SOF in many more cases */
 		gsm->tx_bytes -= msg->len;
-		/* For a burst of frames skip the extra SOF within the
-		   burst */
-		skip_sof = 1;
 
 		list_del(&msg->list);
 		kfree(msg);
+
+		if (dlci) {
+			tty_port_tty_wakeup(&dlci->port);
+		} else {
+			int i = 0;
+
+			for (i = 0; i < NUM_DLCI; i++)
+				if (gsm->dlci[i])
+					tty_port_tty_wakeup(&gsm->dlci[i]->port);
+		}
 	}
 }
 
@@ -767,7 +774,7 @@
 	/* Add to the actual output queue */
 	list_add_tail(&msg->list, &gsm->tx_list);
 	gsm->tx_bytes += msg->len;
-	gsm_data_kick(gsm);
+	gsm_data_kick(gsm, dlci);
 }
 
 /**
@@ -1228,7 +1235,7 @@
 		gsm_control_reply(gsm, CMD_FCON, NULL, 0);
 		/* Kick the link in case it is idling */
 		spin_lock_irqsave(&gsm->tx_lock, flags);
-		gsm_data_kick(gsm);
+		gsm_data_kick(gsm, NULL);
 		spin_unlock_irqrestore(&gsm->tx_lock, flags);
 		break;
 	case CMD_FCOFF:
@@ -1380,7 +1387,13 @@
 	ctrl->data = data;
 	ctrl->len = clen;
 	gsm->pending_cmd = ctrl;
-	gsm->cretries = gsm->n2;
+
+	/* If DLCI0 is in ADM mode skip retries, it won't respond */
+	if (gsm->dlci[0]->mode == DLCI_MODE_ADM)
+		gsm->cretries = 1;
+	else
+		gsm->cretries = gsm->n2;
+
 	mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
 	gsm_control_transmit(gsm, ctrl);
 	spin_unlock_irqrestore(&gsm->control_lock, flags);
@@ -1467,6 +1480,10 @@
  *	in which case an opening port goes back to closed and a closing port
  *	is simply put into closed state (any further frames from the other
  *	end will get a DM response)
+ *
+ *	Some control dlci can stay in ADM mode with other dlci working just
+ *	fine. In that case we can just keep the control dlci open after the
+ *	DLCI_OPENING retries time out.
  */
 
 static void gsm_dlci_t1(unsigned long data)
@@ -1480,8 +1497,16 @@
 		if (dlci->retries) {
 			gsm_command(dlci->gsm, dlci->addr, SABM|PF);
 			mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-		} else
+		} else if (!dlci->addr && gsm->control == (DM | PF)) {
+			if (debug & 8)
+				pr_info("DLCI %d opening in ADM mode.\n",
+					dlci->addr);
+			dlci->mode = DLCI_MODE_ADM;
+			gsm_dlci_open(dlci);
+		} else {
 			gsm_dlci_close(dlci);
+		}
+
 		break;
 	case DLCI_CLOSING:
 		dlci->retries--;
@@ -1499,8 +1524,8 @@
  *	@dlci: DLCI to open
  *
  *	Commence opening a DLCI from the Linux side. We issue SABM messages
- *	to the modem which should then reply with a UA, at which point we
- *	will move into open state. Opening is done asynchronously with retry
+ *	to the modem which should then reply with a UA or ADM, at which point
+ *	we will move into open state. Opening is done asynchronously with retry
  *	running off timers and the responses.
  */
 
@@ -1909,8 +1934,12 @@
 		break;
 	case GSM_DATA:		/* Data */
 		gsm->buf[gsm->count++] = c;
-		if (gsm->count == gsm->len)
+		if (gsm->count >= MAX_MRU) {
+			gsm->bad_size++;
+			gsm->state = GSM_SEARCH;
+		} else if (gsm->count >= gsm->len) {
 			gsm->state = GSM_FCS;
+		}
 		break;
 	case GSM_FCS:		/* FCS follows the packet */
 		gsm->received_fcs = c;
@@ -1989,7 +2018,7 @@
 		gsm->state = GSM_DATA;
 		break;
 	case GSM_DATA:		/* Data */
-		if (gsm->count > gsm->mru) {	/* Allow one for the FCS */
+		if (gsm->count > gsm->mru || gsm->count > MAX_MRU) {	/* Allow one for the FCS */
 			gsm->state = GSM_OVERRUN;
 			gsm->bad_size++;
 		} else
@@ -2034,6 +2063,7 @@
 	struct gsm_dlci *dlci = gsm->dlci[0];
 	struct gsm_msg *txq, *ntxq;
 	struct gsm_control *gc;
+	unsigned long flags;
 
 	gsm->dead = 1;
 
@@ -2045,7 +2075,9 @@
 		}
 	}
 	spin_unlock(&gsm_mux_lock);
-	WARN_ON(i == MAX_MUX);
+	/* open failed before registering => nothing to do */
+	if (i == MAX_MUX)
+		return;
 
 	/* In theory disconnecting DLCI 0 is sufficient but for some
 	   modems this is apparently not the case. */
@@ -2069,9 +2101,12 @@
 			gsm_dlci_release(gsm->dlci[i]);
 	mutex_unlock(&gsm->mutex);
 	/* Now wipe the queues */
+
+	spin_lock_irqsave(&gsm->tx_lock, flags);
 	list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
 		kfree(txq);
 	INIT_LIST_HEAD(&gsm->tx_list);
+	spin_unlock_irqrestore(&gsm->tx_lock, flags);
 }
 
 /**
@@ -2367,6 +2402,9 @@
 	struct gsm_mux *gsm;
 	int ret;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (tty->ops->write == NULL)
 		return -EINVAL;
 
@@ -2406,7 +2444,7 @@
 	/* Queue poll */
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	spin_lock_irqsave(&gsm->tx_lock, flags);
-	gsm_data_kick(gsm);
+	gsm_data_kick(gsm, NULL);
 	if (gsm->tx_bytes < TX_THRESH_LO) {
 		gsm_dlci_data_sweep(gsm);
 	}
@@ -2868,11 +2906,22 @@
 static int gsm_carrier_raised(struct tty_port *port)
 {
 	struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+	struct gsm_mux *gsm = dlci->gsm;
+
 	/* Not yet open so no carrier info */
 	if (dlci->state != DLCI_OPEN)
 		return 0;
 	if (debug & 2)
 		return 1;
+
+	/*
+	 * Basic mode with control channel in ADM mode may not respond
+	 * to CMD_MSC at all and modem_rx is empty.
+	 */
+	if (gsm->encoding == 0 && gsm->dlci[0]->mode == DLCI_MODE_ADM &&
+	    !dlci->modem_rx)
+		return 1;
+
 	return dlci->modem_rx & TIOCM_CD;
 }
 
--- linux-4.4.0.orig/drivers/tty/n_hdlc.c
+++ linux-4.4.0/drivers/tty/n_hdlc.c
@@ -114,7 +114,7 @@
 #define DEFAULT_TX_BUF_COUNT 3
 
 struct n_hdlc_buf {
-	struct n_hdlc_buf *link;
+	struct list_head  list_item;
 	int		  count;
 	char		  buf[1];
 };
@@ -122,8 +122,7 @@
 #define	N_HDLC_BUF_SIZE	(sizeof(struct n_hdlc_buf) + maxframe)
 
 struct n_hdlc_buf_list {
-	struct n_hdlc_buf *head;
-	struct n_hdlc_buf *tail;
+	struct list_head  list;
 	int		  count;
 	spinlock_t	  spinlock;
 };
@@ -136,7 +135,6 @@
  * @backup_tty - TTY to use if tty gets closed
  * @tbusy - reentrancy flag for tx wakeup code
  * @woke_up - FIXME: describe this field
- * @tbuf - currently transmitting tx buffer
  * @tx_buf_list - list of pending transmit frame buffers
  * @rx_buf_list - list of received frame buffers
  * @tx_free_buf_list - list unused transmit frame buffers
@@ -149,7 +147,6 @@
 	struct tty_struct	*backup_tty;
 	int			tbusy;
 	int			woke_up;
-	struct n_hdlc_buf	*tbuf;
 	struct n_hdlc_buf_list	tx_buf_list;
 	struct n_hdlc_buf_list	rx_buf_list;
 	struct n_hdlc_buf_list	tx_free_buf_list;
@@ -159,7 +156,8 @@
 /*
  * HDLC buffer list manipulation functions
  */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
+static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
+						struct n_hdlc_buf *buf);
 static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
 			   struct n_hdlc_buf *buf);
 static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
@@ -209,16 +207,9 @@
 {
 	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
 	struct n_hdlc_buf *buf;
-	unsigned long flags;
 
 	while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
 		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
- 	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-	if (n_hdlc->tbuf) {
-		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
-		n_hdlc->tbuf = NULL;
-	}
-	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
 }
 
 static struct tty_ldisc_ops n_hdlc_ldisc = {
@@ -284,7 +275,6 @@
 		} else
 			break;
 	}
-	kfree(n_hdlc->tbuf);
 	kfree(n_hdlc);
 	
 }	/* end of n_hdlc_release() */
@@ -403,13 +393,7 @@
 	n_hdlc->woke_up = 0;
 	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
 
-	/* get current transmit buffer or get new transmit */
-	/* buffer from list of pending transmit buffers */
-		
-	tbuf = n_hdlc->tbuf;
-	if (!tbuf)
-		tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-		
+	tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
 	while (tbuf) {
 		if (debuglevel >= DEBUG_LEVEL_INFO)	
 			printk("%s(%d)sending frame %p, count=%d\n",
@@ -421,7 +405,7 @@
 
 		/* rollback was possible and has been done */
 		if (actual == -ERESTARTSYS) {
-			n_hdlc->tbuf = tbuf;
+			n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
 			break;
 		}
 		/* if transmit error, throw frame away by */
@@ -436,10 +420,7 @@
 					
 			/* free current transmit buffer */
 			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
-			
-			/* this tx buffer is done */
-			n_hdlc->tbuf = NULL;
-			
+
 			/* wait up sleeping writers */
 			wake_up_interruptible(&tty->write_wait);
 	
@@ -449,10 +430,12 @@
 			if (debuglevel >= DEBUG_LEVEL_INFO)	
 				printk("%s(%d)frame %p pending\n",
 					__FILE__,__LINE__,tbuf);
-					
-			/* buffer not accepted by driver */
-			/* set this buffer as pending buffer */
-			n_hdlc->tbuf = tbuf;
+
+			/*
+			 * the buffer was not accepted by driver,
+			 * return it back into tx queue
+			 */
+			n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
 			break;
 		}
 	}
@@ -600,7 +583,7 @@
 	add_wait_queue(&tty->read_wait, &wait);
 
 	for (;;) {
-		if (test_bit(TTY_OTHER_DONE, &tty->flags)) {
+		if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
 			ret = -EIO;
 			break;
 		}
@@ -615,6 +598,7 @@
 				/* too large for caller's buffer */
 				ret = -EOVERFLOW;
 			} else {
+				__set_current_state(TASK_RUNNING);
 				if (copy_to_user(buf, rbuf->buf, rbuf->count))
 					ret = -EFAULT;
 				else
@@ -630,7 +614,7 @@
 		}
 			
 		/* no data */
-		if (file->f_flags & O_NONBLOCK) {
+		if (tty_io_nonblock(tty, file)) {
 			ret = -EAGAIN;
 			break;
 		}
@@ -697,7 +681,7 @@
 		if (tbuf)
 			break;
 
-		if (file->f_flags & O_NONBLOCK) {
+		if (tty_io_nonblock(tty, file)) {
 			error = -EAGAIN;
 			break;
 		}
@@ -750,7 +734,8 @@
 	int error = 0;
 	int count;
 	unsigned long flags;
-	
+	struct n_hdlc_buf *buf = NULL;
+
 	if (debuglevel >= DEBUG_LEVEL_INFO)	
 		printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
 			__FILE__,__LINE__,cmd);
@@ -764,8 +749,10 @@
 		/* report count of read data available */
 		/* in next available frame (if any) */
 		spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
-		if (n_hdlc->rx_buf_list.head)
-			count = n_hdlc->rx_buf_list.head->count;
+		buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
+						struct n_hdlc_buf, list_item);
+		if (buf)
+			count = buf->count;
 		else
 			count = 0;
 		spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
@@ -777,8 +764,10 @@
 		count = tty_chars_in_buffer(tty);
 		/* add size of next output frame in queue */
 		spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
-		if (n_hdlc->tx_buf_list.head)
-			count += n_hdlc->tx_buf_list.head->count;
+		buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
+						struct n_hdlc_buf, list_item);
+		if (buf)
+			count += buf->count;
 		spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
 		error = put_user(count, (int __user *)arg);
 		break;
@@ -826,14 +815,14 @@
 		poll_wait(filp, &tty->write_wait, wait);
 
 		/* set bits for operations that won't block */
-		if (n_hdlc->rx_buf_list.head)
+		if (!list_empty(&n_hdlc->rx_buf_list.list))
 			mask |= POLLIN | POLLRDNORM;	/* readable */
-		if (test_bit(TTY_OTHER_DONE, &tty->flags))
+		if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
 			mask |= POLLHUP;
 		if (tty_hung_up_p(filp))
 			mask |= POLLHUP;
 		if (!tty_is_writelocked(tty) &&
-				n_hdlc->tx_free_buf_list.head)
+				!list_empty(&n_hdlc->tx_free_buf_list.list))
 			mask |= POLLOUT | POLLWRNORM;	/* writable */
 	}
 	return mask;
@@ -853,11 +842,16 @@
 	if (!n_hdlc)
 		return NULL;
 
-	n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
-	n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
-	n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
-	n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
-	
+	spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
+	spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
+	spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
+	spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
+
+	INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list);
+	INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list);
+	INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
+	INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);
+
 	/* allocate free rx buffer list */
 	for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
 		buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
@@ -885,63 +879,65 @@
 }	/* end of n_hdlc_alloc() */
 
 /**
- * n_hdlc_buf_list_init - initialize specified HDLC buffer list
- * @list - pointer to buffer list
+ * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list
+ * @buf_list - pointer to the buffer list
+ * @buf - pointer to the buffer
  */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
+static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
+						struct n_hdlc_buf *buf)
 {
-	memset(list, 0, sizeof(*list));
-	spin_lock_init(&list->spinlock);
-}	/* end of n_hdlc_buf_list_init() */
+	unsigned long flags;
+
+	spin_lock_irqsave(&buf_list->spinlock, flags);
+
+	list_add(&buf->list_item, &buf_list->list);
+	buf_list->count++;
+
+	spin_unlock_irqrestore(&buf_list->spinlock, flags);
+}
 
 /**
  * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
- * @list - pointer to buffer list
+ * @buf_list - pointer to buffer list
  * @buf	- pointer to buffer
  */
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
 			   struct n_hdlc_buf *buf)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&list->spinlock,flags);
-	
-	buf->link=NULL;
-	if (list->tail)
-		list->tail->link = buf;
-	else
-		list->head = buf;
-	list->tail = buf;
-	(list->count)++;
-	
-	spin_unlock_irqrestore(&list->spinlock,flags);
-	
+
+	spin_lock_irqsave(&buf_list->spinlock, flags);
+
+	list_add_tail(&buf->list_item, &buf_list->list);
+	buf_list->count++;
+
+	spin_unlock_irqrestore(&buf_list->spinlock, flags);
 }	/* end of n_hdlc_buf_put() */
 
 /**
  * n_hdlc_buf_get - remove and return an HDLC buffer from list
- * @list - pointer to HDLC buffer list
+ * @buf_list - pointer to HDLC buffer list
  * 
  * Remove and return an HDLC buffer from the head of the specified HDLC buffer
  * list.
  * Returns a pointer to HDLC buffer if available, otherwise %NULL.
  */
-static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
+static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
 {
 	unsigned long flags;
 	struct n_hdlc_buf *buf;
-	spin_lock_irqsave(&list->spinlock,flags);
-	
-	buf = list->head;
+
+	spin_lock_irqsave(&buf_list->spinlock, flags);
+
+	buf = list_first_entry_or_null(&buf_list->list,
+						struct n_hdlc_buf, list_item);
 	if (buf) {
-		list->head = buf->link;
-		(list->count)--;
+		list_del(&buf->list_item);
+		buf_list->count--;
 	}
-	if (!list->head)
-		list->tail = NULL;
-	
-	spin_unlock_irqrestore(&list->spinlock,flags);
+
+	spin_unlock_irqrestore(&buf_list->spinlock, flags);
 	return buf;
-	
 }	/* end of n_hdlc_buf_get() */
 
 static char hdlc_banner[] __initdata =
--- linux-4.4.0.orig/drivers/tty/n_r3964.c
+++ linux-4.4.0/drivers/tty/n_r3964.c
@@ -1080,7 +1080,7 @@
 		pMsg = remove_msg(pInfo, pClient);
 		if (pMsg == NULL) {
 			/* no messages available. */
-			if (file->f_flags & O_NONBLOCK) {
+			if (tty_io_nonblock(tty, file)) {
 				ret = -EAGAIN;
 				goto unlock;
 			}
--- linux-4.4.0.orig/drivers/tty/n_tty.c
+++ linux-4.4.0/drivers/tty/n_tty.c
@@ -128,6 +128,8 @@
 	struct mutex output_lock;
 };
 
+#define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1))
+
 static inline size_t read_cnt(struct n_tty_data *ldata)
 {
 	return ldata->read_head - ldata->read_tail;
@@ -145,6 +147,7 @@
 
 static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
 {
+	smp_rmb(); /* Matches smp_wmb() in add_echo_byte(). */
 	return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
 }
 
@@ -162,15 +165,29 @@
 	return put_user(x, ptr);
 }
 
+/* If we are not echoing the data, perhaps this is a secret so erase it */
+static inline void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
+{
+	bool icanon = !!L_ICANON(tty);
+	bool no_echo = !L_ECHO(tty);
+
+	if (icanon && no_echo)
+		memset(buffer, 0x00, size);
+}
+
 static inline int tty_copy_to_user(struct tty_struct *tty,
 					void __user *to,
-					const void *from,
+					void *from,
 					unsigned long n)
 {
 	struct n_tty_data *ldata = tty->disc_data;
+	int retval;
 
 	tty_audit_add_data(tty, from, n, ldata->icanon);
-	return copy_to_user(to, from, n);
+	retval = copy_to_user(to, from, n);
+	if (!retval)
+		zero_buffer(tty, from, n);
+	return retval;
 }
 
 /**
@@ -258,16 +275,13 @@
 
 static void n_tty_check_unthrottle(struct tty_struct *tty)
 {
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) {
+	if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
 		if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
 			return;
 		if (!tty->count)
 			return;
 		n_tty_kick_worker(tty);
-		n_tty_write_wakeup(tty->link);
-		if (waitqueue_active(&tty->link->write_wait))
-			wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
+		tty_wakeup(tty->link);
 		return;
 	}
 
@@ -325,9 +339,7 @@
 static void reset_buffer_flags(struct n_tty_data *ldata)
 {
 	ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
-	ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
 	ldata->commit_head = 0;
-	ldata->echo_mark = 0;
 	ldata->line_start = 0;
 
 	ldata->erasing = 0;
@@ -648,13 +660,20 @@
 	old_space = space = tty_write_room(tty);
 
 	tail = ldata->echo_tail;
-	while (ldata->echo_commit != tail) {
+	while (MASK(ldata->echo_commit) != MASK(tail)) {
 		c = echo_buf(ldata, tail);
 		if (c == ECHO_OP_START) {
 			unsigned char op;
 			int no_space_left = 0;
 
 			/*
+			 * Since add_echo_byte() is called without holding
+			 * output_lock, we might see only portion of multi-byte
+			 * operation.
+			 */
+			if (MASK(ldata->echo_commit) == MASK(tail + 1))
+				goto not_yet_stored;
+			/*
 			 * If the buffer byte is the start of a multi-byte
 			 * operation, get the next byte, which is either the
 			 * op code or a control character value.
@@ -665,6 +684,8 @@
 				unsigned int num_chars, num_bs;
 
 			case ECHO_OP_ERASE_TAB:
+				if (MASK(ldata->echo_commit) == MASK(tail + 2))
+					goto not_yet_stored;
 				num_chars = echo_buf(ldata, tail + 2);
 
 				/*
@@ -759,7 +780,8 @@
 	/* If the echo buffer is nearly full (so that the possibility exists
 	 * of echo overrun before the next commit), then discard enough
 	 * data at the tail to prevent a subsequent overrun */
-	while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
+	while (ldata->echo_commit > tail &&
+	       ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
 		if (echo_buf(ldata, tail) == ECHO_OP_START) {
 			if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB)
 				tail += 3;
@@ -769,6 +791,7 @@
 			tail++;
 	}
 
+ not_yet_stored:
 	ldata->echo_tail = tail;
 	return old_space - space;
 }
@@ -779,6 +802,7 @@
 	size_t nr, old, echoed;
 	size_t head;
 
+	mutex_lock(&ldata->output_lock);
 	head = ldata->echo_head;
 	ldata->echo_mark = head;
 	old = ldata->echo_commit - ldata->echo_tail;
@@ -787,10 +811,12 @@
 	 * is over the threshold (and try again each time another
 	 * block is accumulated) */
 	nr = head - ldata->echo_tail;
-	if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
+	if (nr < ECHO_COMMIT_WATERMARK ||
+	    (nr % ECHO_BLOCK > old % ECHO_BLOCK)) {
+		mutex_unlock(&ldata->output_lock);
 		return;
+	}
 
-	mutex_lock(&ldata->output_lock);
 	ldata->echo_commit = head;
 	echoed = __process_echoes(tty);
 	mutex_unlock(&ldata->output_lock);
@@ -841,7 +867,9 @@
 
 static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
 {
-	*echo_buf_addr(ldata, ldata->echo_head++) = c;
+	*echo_buf_addr(ldata, ldata->echo_head) = c;
+	smp_wmb(); /* Matches smp_rmb() in echo_buf(). */
+	ldata->echo_head++;
 }
 
 /**
@@ -1009,14 +1037,15 @@
 	}
 
 	seen_alnums = 0;
-	while (ldata->read_head != ldata->canon_head) {
+	while (MASK(ldata->read_head) != MASK(ldata->canon_head)) {
 		head = ldata->read_head;
 
 		/* erase a single possibly multibyte character */
 		do {
 			head--;
 			c = read_buf(ldata, head);
-		} while (is_continuation(c, tty) && head != ldata->canon_head);
+		} while (is_continuation(c, tty) &&
+			 MASK(head) != MASK(ldata->canon_head));
 
 		/* do not partially erase */
 		if (is_continuation(c, tty))
@@ -1058,7 +1087,7 @@
 				 * This info is used to go back the correct
 				 * number of columns.
 				 */
-				while (tail != ldata->canon_head) {
+				while (MASK(tail) != MASK(ldata->canon_head)) {
 					tail--;
 					c = read_buf(ldata, tail);
 					if (c == '\t') {
@@ -1335,7 +1364,7 @@
 			finish_erasing(ldata);
 			echo_char(c, tty);
 			echo_char_raw('\n', ldata);
-			while (tail != ldata->read_head) {
+			while (MASK(tail) != MASK(ldata->read_head)) {
 				echo_char(read_buf(ldata, tail), tty);
 				tail++;
 			}
@@ -1707,7 +1736,7 @@
 
 	down_read(&tty->termios_rwsem);
 
-	while (1) {
+	do {
 		/*
 		 * When PARMRK is set, each input char may take up to 3 chars
 		 * in the read buf; reduce the buffer space avail by 3x
@@ -1749,7 +1778,7 @@
 			fp += n;
 		count -= n;
 		rcvd += n;
-	}
+	} while (!test_bit(TTY_LDISC_CHANGING, &tty->flags));
 
 	tty->receive_room = room;
 
@@ -1804,7 +1833,7 @@
 {
 	struct n_tty_data *ldata = tty->disc_data;
 
-	if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) {
+	if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) {
 		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
 		ldata->line_start = ldata->read_tail;
 		if (!L_ICANON(tty) || !read_cnt(ldata)) {
@@ -1920,31 +1949,22 @@
 	struct n_tty_data *ldata;
 
 	/* Currently a malloc failure here can panic */
-	ldata = vmalloc(sizeof(*ldata));
+	ldata = vzalloc(sizeof(*ldata));
 	if (!ldata)
-		goto err;
+		return -ENOMEM;
 
 	ldata->overrun_time = jiffies;
 	mutex_init(&ldata->atomic_read_lock);
 	mutex_init(&ldata->output_lock);
 
 	tty->disc_data = ldata;
-	reset_buffer_flags(tty->disc_data);
-	ldata->column = 0;
-	ldata->canon_column = 0;
 	ldata->minimum_to_wake = 1;
-	ldata->num_overrun = 0;
-	ldata->no_room = 0;
-	ldata->lnext = 0;
 	tty->closing = 0;
 	/* indicate buffer work may resume */
 	clear_bit(TTY_LDISC_HALTED, &tty->flags);
 	n_tty_set_termios(tty, NULL);
 	tty_unthrottle(tty);
-
 	return 0;
-err:
-	return -ENOMEM;
 }
 
 static inline int input_available_p(struct tty_struct *tty, int poll)
@@ -1958,18 +1978,6 @@
 		return ldata->commit_head - ldata->read_tail >= amt;
 }
 
-static inline int check_other_done(struct tty_struct *tty)
-{
-	int done = test_bit(TTY_OTHER_DONE, &tty->flags);
-	if (done) {
-		/* paired with cmpxchg() in check_other_closed(); ensures
-		 * read buffer head index is not stale
-		 */
-		smp_mb__after_atomic();
-	}
-	return done;
-}
-
 /**
  *	copy_from_read_buf	-	copy read data directly
  *	@tty: terminal device
@@ -2011,6 +2019,7 @@
 		is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
 		tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
 				ldata->icanon);
+		zero_buffer(tty, read_buf_addr(ldata, tail), n);
 		smp_store_release(&ldata->read_tail, ldata->read_tail + n);
 		/* Turn single EOF into zero-length read */
 		if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
@@ -2174,7 +2183,7 @@
 	struct n_tty_data *ldata = tty->disc_data;
 	unsigned char __user *b = buf;
 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
-	int c, done;
+	int c;
 	int minimum, time;
 	ssize_t retval = 0;
 	long timeout;
@@ -2242,32 +2251,41 @@
 		    ((minimum - (b - buf)) >= 1))
 			ldata->minimum_to_wake = (minimum - (b - buf));
 
-		done = check_other_done(tty);
-
 		if (!input_available_p(tty, 0)) {
-			if (done) {
-				retval = -EIO;
-				break;
-			}
-			if (tty_hung_up_p(file))
-				break;
-			if (!timeout)
-				break;
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				retval = -ERESTARTSYS;
-				break;
-			}
 			up_read(&tty->termios_rwsem);
+			tty_buffer_flush_work(tty->port);
+			down_read(&tty->termios_rwsem);
+			if (!input_available_p(tty, 0)) {
+				if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+					retval = -EIO;
+					break;
+				}
+				if (tty_hung_up_p(file))
+					break;
+				/*
+				 * Abort readers for ttys which never actually
+				 * get hung up.  See __tty_hangup().
+				 */
+				if (test_bit(TTY_HUPPING, &tty->flags))
+					break;
+				if (!timeout)
+					break;
+				if (tty_io_nonblock(tty, file)) {
+					retval = -EAGAIN;
+					break;
+				}
+				if (signal_pending(current)) {
+					retval = -ERESTARTSYS;
+					break;
+				}
+				up_read(&tty->termios_rwsem);
 
-			timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
-					     timeout);
+				timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
+						timeout);
 
-			down_read(&tty->termios_rwsem);
-			continue;
+				down_read(&tty->termios_rwsem);
+				continue;
+			}
 		}
 
 		if (ldata->icanon && !L_EXTPROC(tty)) {
@@ -2409,7 +2427,7 @@
 		}
 		if (!nr)
 			break;
-		if (file->f_flags & O_NONBLOCK) {
+		if (tty_io_nonblock(tty, file)) {
 			retval = -EAGAIN;
 			break;
 		}
@@ -2449,12 +2467,17 @@
 
 	poll_wait(file, &tty->read_wait, wait);
 	poll_wait(file, &tty->write_wait, wait);
-	if (check_other_done(tty))
-		mask |= POLLHUP;
 	if (input_available_p(tty, 1))
 		mask |= POLLIN | POLLRDNORM;
+	else {
+		tty_buffer_flush_work(tty->port);
+		if (input_available_p(tty, 1))
+			mask |= POLLIN | POLLRDNORM;
+	}
 	if (tty->packet && tty->link->ctrl_status)
 		mask |= POLLPRI | POLLIN | POLLRDNORM;
+	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+		mask |= POLLHUP;
 	if (tty_hung_up_p(file))
 		mask |= POLLHUP;
 	if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
@@ -2480,7 +2503,7 @@
 	tail = ldata->read_tail;
 	nr = head - tail;
 	/* Skip EOF-chars.. */
-	while (head != tail) {
+	while (MASK(head) != MASK(tail)) {
 		if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) &&
 		    read_buf(ldata, tail) == __DISABLED_CHAR)
 			nr--;
@@ -2500,7 +2523,7 @@
 		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
 	case TIOCINQ:
 		down_write(&tty->termios_rwsem);
-		if (L_ICANON(tty))
+		if (L_ICANON(tty) && !L_EXTPROC(tty))
 			retval = inq_canon(ldata);
 		else
 			retval = read_cnt(ldata);
--- linux-4.4.0.orig/drivers/tty/nozomi.c
+++ linux-4.4.0/drivers/tty/nozomi.c
@@ -823,7 +823,7 @@
 	struct tty_struct *tty = tty_port_tty_get(&port->port);
 	int i, ret;
 
-	read_mem32((u32 *) &size, addr, 4);
+	size = __le32_to_cpu(readl(addr));
 	/*  DBG1( "%d bytes port: %d", size, index); */
 
 	if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
--- linux-4.4.0.orig/drivers/tty/pty.c
+++ linux-4.4.0/drivers/tty/pty.c
@@ -59,7 +59,7 @@
 	if (!tty->link)
 		return;
 	set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-	tty_flip_buffer_push(tty->link->port);
+	wake_up_interruptible(&tty->link->read_wait);
 	wake_up_interruptible(&tty->link->write_wait);
 	if (tty->driver->subtype == PTY_TYPE_MASTER) {
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
@@ -107,17 +107,10 @@
 {
 	struct tty_struct *to = tty->link;
 
-	if (tty->stopped)
+	if (tty->stopped || !c)
 		return 0;
 
-	if (c > 0) {
-		/* Stuff the data into the input queue of the other end */
-		c = tty_insert_flip_string(to->port, buf, c);
-		/* And shovel */
-		if (c)
-			tty_flip_buffer_push(to->port);
-	}
-	return c;
+	return tty_insert_flip_string_and_push_buffer(to->port, buf, c);
 }
 
 /**
@@ -216,16 +209,11 @@
 static void pty_flush_buffer(struct tty_struct *tty)
 {
 	struct tty_struct *to = tty->link;
-	struct tty_ldisc *ld;
 
 	if (!to)
 		return;
 
-	ld = tty_ldisc_ref(to);
-	tty_buffer_flush(to, ld);
-	if (ld)
-		tty_ldisc_deref(ld);
-
+	tty_buffer_flush(to, NULL);
 	if (to->packet) {
 		spin_lock_irq(&tty->ctrl_lock);
 		tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -247,9 +235,7 @@
 		goto out;
 
 	clear_bit(TTY_IO_ERROR, &tty->flags);
-	/* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */
 	clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-	clear_bit(TTY_OTHER_DONE, &tty->link->flags);
 	set_bit(TTY_THROTTLED, &tty->flags);
 	return 0;
 
@@ -681,7 +667,17 @@
 /* this is called once with whichever end is closed last */
 static void pty_unix98_shutdown(struct tty_struct *tty)
 {
-	devpts_kill_index(tty->driver_data, tty->index);
+	struct pts_fs_info *fsi;
+
+	if (tty->driver->subtype == PTY_TYPE_MASTER)
+		fsi = tty->driver_data;
+	else
+		fsi = tty->link->driver_data;
+
+	if (fsi) {
+		devpts_kill_index(fsi, tty->index);
+		devpts_put_ref(fsi);
+	}
 }
 
 static const struct tty_operations ptm_unix98_ops = {
@@ -733,6 +729,7 @@
 
 static int ptmx_open(struct inode *inode, struct file *filp)
 {
+	struct pts_fs_info *fsi;
 	struct tty_struct *tty;
 	struct inode *slave_inode;
 	int retval;
@@ -747,35 +744,41 @@
 	if (retval)
 		return retval;
 
+	fsi = devpts_get_ref(inode, filp);
+	retval = -ENODEV;
+	if (!fsi)
+		goto out_free_file;
+
 	/* find a device that is not in use. */
 	mutex_lock(&devpts_mutex);
-	index = devpts_new_index(inode);
-	if (index < 0) {
-		retval = index;
-		mutex_unlock(&devpts_mutex);
-		goto err_file;
-	}
-
+	index = devpts_new_index(fsi);
 	mutex_unlock(&devpts_mutex);
 
-	mutex_lock(&tty_mutex);
-	tty = tty_init_dev(ptm_driver, index);
+	retval = index;
+	if (index < 0)
+		goto out_put_ref;
 
-	if (IS_ERR(tty)) {
-		retval = PTR_ERR(tty);
-		goto out;
-	}
 
+	mutex_lock(&tty_mutex);
+	tty = tty_init_dev(ptm_driver, index);
 	/* The tty returned here is locked so we can safely
 	   drop the mutex */
 	mutex_unlock(&tty_mutex);
 
+	retval = PTR_ERR(tty);
+	if (IS_ERR(tty))
+		goto out;
+
+	/*
+	 * From here on out, the tty is "live", and the index and
+	 * fsi will be killed/put by the tty_release()
+	 */
 	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-	tty->driver_data = inode;
+	tty->driver_data = fsi;
 
 	tty_add_file(tty, filp);
 
-	slave_inode = devpts_pty_new(inode,
+	slave_inode = devpts_pty_new(fsi,
 			MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
 			tty->link);
 	if (IS_ERR(slave_inode)) {
@@ -794,12 +797,14 @@
 	return 0;
 err_release:
 	tty_unlock(tty);
+	// This will also put-ref the fsi
 	tty_release(inode, filp);
 	return retval;
 out:
-	mutex_unlock(&tty_mutex);
-	devpts_kill_index(inode, index);
-err_file:
+	devpts_kill_index(fsi, index);
+out_put_ref:
+	devpts_put_ref(fsi);
+out_free_file:
 	tty_free_file(filp);
 	return retval;
 }
--- linux-4.4.0.orig/drivers/tty/rocket.c
+++ linux-4.4.0/drivers/tty/rocket.c
@@ -250,15 +250,15 @@
 
 MODULE_AUTHOR("Theodore Ts'o");
 MODULE_DESCRIPTION("Comtrol RocketPort driver");
-module_param(board1, ulong, 0);
+module_param_hw(board1, ulong, ioport, 0);
 MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
-module_param(board2, ulong, 0);
+module_param_hw(board2, ulong, ioport, 0);
 MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
-module_param(board3, ulong, 0);
+module_param_hw(board3, ulong, ioport, 0);
 MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
-module_param(board4, ulong, 0);
+module_param_hw(board4, ulong, ioport, 0);
 MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
-module_param(controller, ulong, 0);
+module_param_hw(controller, ulong, ioport, 0);
 MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
 module_param(support_low_speed, bool, 0);
 MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud");
@@ -279,7 +279,7 @@
 module_param_array(pc104_4, ulong, NULL, 0);
 MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,...");
 
-static int rp_init(void);
+static int __init rp_init(void);
 static void rp_cleanup_module(void);
 
 module_init(rp_init);
@@ -645,18 +645,21 @@
 	info->port.ops = &rocket_port_ops;
 	init_completion(&info->close_wait);
 	info->flags &= ~ROCKET_MODE_MASK;
-	switch (pc104[board][line]) {
-	case 422:
-		info->flags |= ROCKET_MODE_RS422;
-		break;
-	case 485:
-		info->flags |= ROCKET_MODE_RS485;
-		break;
-	case 232:
-	default:
+	if (board < ARRAY_SIZE(pc104) && line < ARRAY_SIZE(pc104_1))
+		switch (pc104[board][line]) {
+		case 422:
+			info->flags |= ROCKET_MODE_RS422;
+			break;
+		case 485:
+			info->flags |= ROCKET_MODE_RS485;
+			break;
+		case 232:
+		default:
+			info->flags |= ROCKET_MODE_RS232;
+			break;
+		}
+	else
 		info->flags |= ROCKET_MODE_RS232;
-		break;
-	}
 
 	info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
 	if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
@@ -1915,7 +1918,7 @@
 	ByteIO_t UPCIRingInd = 0;
 
 	if (!dev || !pci_match_id(rocket_pci_ids, dev) ||
-	    pci_enable_device(dev))
+	    pci_enable_device(dev) || i >= NUM_BOARDS)
 		return 0;
 
 	rcktpt_io_addr[i] = pci_resource_start(dev, 0);
--- linux-4.4.0.orig/drivers/tty/serial/8250/8250_core.c
+++ linux-4.4.0/drivers/tty/serial/8250/8250_core.c
@@ -530,6 +530,7 @@
 		 */
 		up->mcr_mask = ~ALPHA_KLUDGE_MCR;
 		up->mcr_force = ALPHA_KLUDGE_MCR;
+		serial8250_set_defaults(up);
 	}
 
 	/* chain base port ops to support Remote Supervisor Adapter */
@@ -553,7 +554,6 @@
 		port->membase  = old_serial_port[i].iomem_base;
 		port->iotype   = old_serial_port[i].io_type;
 		port->regshift = old_serial_port[i].iomem_reg_shift;
-		serial8250_set_defaults(up);
 
 		port->irqflags |= irqflag;
 		if (serial8250_isa_config != NULL)
@@ -1037,8 +1037,10 @@
 
 			ret = uart_add_one_port(&serial8250_reg,
 						&uart->port);
-			if (ret == 0)
-				ret = uart->port.line;
+			if (ret)
+				goto err;
+
+			ret = uart->port.line;
 		} else {
 			dev_info(uart->port.dev,
 				"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
@@ -1052,6 +1054,11 @@
 	mutex_unlock(&serial_mutex);
 
 	return ret;
+
+err:
+	uart->port.dev = NULL;
+	mutex_unlock(&serial_mutex);
+	return ret;
 }
 EXPORT_SYMBOL(serial8250_register_8250_port);
 
@@ -1173,7 +1180,7 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
 
-module_param(share_irqs, uint, 0644);
+module_param_hw(share_irqs, uint, other, 0644);
 MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
 	" (unsafe)");
 
@@ -1184,7 +1191,7 @@
 MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
 
 #ifdef CONFIG_SERIAL_8250_RSA
-module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
+module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444);
 MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
 #endif
 MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
--- linux-4.4.0.orig/drivers/tty/serial/8250/8250_dw.c
+++ linux-4.4.0/drivers/tty/serial/8250/8250_dw.c
@@ -224,7 +224,7 @@
 	unsigned int rate;
 	int ret;
 
-	if (IS_ERR(d->clk) || !old)
+	if (IS_ERR(d->clk))
 		goto out;
 
 	clk_disable_unprepare(d->clk);
@@ -258,7 +258,7 @@
 
 static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
 {
-	return param == chan->device->dev->parent;
+	return param == chan->device->dev;
 }
 
 static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
@@ -290,7 +290,7 @@
 		data->uart_16550_compatible = true;
 	}
 
-	/* Platforms with iDMA */
+	/* Platforms with iDMA 64-bit */
 	if (platform_get_resource_byname(to_platform_device(p->dev),
 					 IORESOURCE_MEM, "lpss_priv")) {
 		p->set_termios = dw8250_set_termios;
@@ -440,7 +440,7 @@
 	}
 
 	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
-	if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
+	if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) {
 		err = -EPROBE_DEFER;
 		goto err_clk;
 	}
--- linux-4.4.0.orig/drivers/tty/serial/8250/8250_fintek.c
+++ linux-4.4.0/drivers/tty/serial/8250/8250_fintek.c
@@ -117,7 +117,7 @@
 
 	if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) ==
 			(!!(rs485->flags & SER_RS485_RTS_AFTER_SEND)))
-		rs485->flags &= SER_RS485_ENABLED;
+		rs485->flags &= ~SER_RS485_ENABLED;
 	else
 		config |= RS485_URA;
 
--- linux-4.4.0.orig/drivers/tty/serial/8250/8250_mid.c
+++ linux-4.4.0/drivers/tty/serial/8250/8250_mid.c
@@ -14,6 +14,7 @@
 #include <linux/pci.h>
 
 #include <linux/dma/hsu.h>
+#include <linux/8250_pci.h>
 
 #include "8250.h"
 
@@ -24,6 +25,7 @@
 #define PCI_DEVICE_ID_INTEL_DNV_UART	0x19d8
 
 /* Intel MID Specific registers */
+#define INTEL_MID_UART_DNV_FISR		0x08
 #define INTEL_MID_UART_PS		0x30
 #define INTEL_MID_UART_MUL		0x34
 #define INTEL_MID_UART_DIV		0x38
@@ -31,6 +33,7 @@
 struct mid8250;
 
 struct mid8250_board {
+	unsigned int flags;
 	unsigned long freq;
 	unsigned int base_baud;
 	int (*setup)(struct mid8250 *, struct uart_port *p);
@@ -88,16 +91,16 @@
 static int dnv_handle_irq(struct uart_port *p)
 {
 	struct mid8250 *mid = p->private_data;
-	int ret;
-
-	ret = hsu_dma_irq(&mid->dma_chip, 0);
-	ret |= hsu_dma_irq(&mid->dma_chip, 1);
+	unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
+	int ret = IRQ_NONE;
 
-	/* For now, letting the HW generate separate interrupt for the UART */
-	if (ret)
-		return ret;
-
-	return serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+	if (fisr & BIT(2))
+		ret |= hsu_dma_irq(&mid->dma_chip, 1);
+	if (fisr & BIT(1))
+		ret |= hsu_dma_irq(&mid->dma_chip, 0);
+	if (fisr & BIT(0))
+		ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+	return ret;
 }
 
 #define DNV_DMA_CHAN_OFFSET 0x80
@@ -106,12 +109,13 @@
 {
 	struct hsu_dma_chip *chip = &mid->dma_chip;
 	struct pci_dev *pdev = to_pci_dev(p->dev);
+	unsigned int bar = FL_GET_BASE(mid->board->flags);
 	int ret;
 
 	chip->dev = &pdev->dev;
 	chip->irq = pdev->irq;
 	chip->regs = p->membase;
-	chip->length = pci_resource_len(pdev, 0);
+	chip->length = pci_resource_len(pdev, bar);
 	chip->offset = DNV_DMA_CHAN_OFFSET;
 
 	/* Falling back to PIO mode if DMA probing fails */
@@ -145,6 +149,9 @@
 	unsigned long w = BIT(24) - 1;
 	unsigned long mul, div;
 
+	/* Gracefully handle the B0 case: fall back to B9600 */
+	fuart = fuart ? fuart : 9600 * 16;
+
 	if (mid->board->freq < fuart) {
 		/* Find prescaler value that satisfies Fuart < Fref */
 		if (mid->board->freq > baud)
@@ -217,6 +224,7 @@
 {
 	struct uart_8250_port uart;
 	struct mid8250 *mid;
+	unsigned int bar;
 	int ret;
 
 	ret = pcim_enable_device(pdev);
@@ -230,6 +238,7 @@
 		return -ENOMEM;
 
 	mid->board = (struct mid8250_board *)id->driver_data;
+	bar = FL_GET_BASE(mid->board->flags);
 
 	memset(&uart, 0, sizeof(struct uart_8250_port));
 
@@ -242,8 +251,8 @@
 	uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
 	uart.port.set_termios = mid8250_set_termios;
 
-	uart.port.mapbase = pci_resource_start(pdev, 0);
-	uart.port.membase = pcim_iomap(pdev, 0, 0);
+	uart.port.mapbase = pci_resource_start(pdev, bar);
+	uart.port.membase = pcim_iomap(pdev, bar, 0);
 	if (!uart.port.membase)
 		return -ENOMEM;
 
@@ -282,18 +291,21 @@
 }
 
 static const struct mid8250_board pnw_board = {
+	.flags = FL_BASE0,
 	.freq = 50000000,
 	.base_baud = 115200,
 	.setup = pnw_setup,
 };
 
 static const struct mid8250_board tng_board = {
+	.flags = FL_BASE0,
 	.freq = 38400000,
 	.base_baud = 1843200,
 	.setup = tng_setup,
 };
 
 static const struct mid8250_board dnv_board = {
+	.flags = FL_BASE1,
 	.freq = 133333333,
 	.base_baud = 115200,
 	.setup = dnv_setup,
--- linux-4.4.0.orig/drivers/tty/serial/8250/8250_mtk.c
+++ linux-4.4.0/drivers/tty/serial/8250/8250_mtk.c
@@ -47,7 +47,20 @@
 	struct uart_8250_port *up =
 		container_of(port, struct uart_8250_port, port);
 
-	serial8250_do_set_termios(port, termios, old);
+	/*
+	 * Store the requested baud rate before calling the generic 8250
+	 * set_termios method. Standard 8250 port expects bauds to be
+	 * no higher than (uartclk / 16) so the baud will be clamped if it
+	 * gets out of that bound. Mediatek 8250 port supports speed
+	 * higher than that, therefore we'll get original baud rate back
+	 * after calling the generic set_termios method and recalculate
+	 * the speed later in this method.
+	 */
+	baud = tty_termios_baud_rate(termios);
+
+	serial8250_do_set_termios(port, termios, NULL);
+
+	tty_termios_encode_baud_rate(termios, baud, baud);
 
 	/*
 	 * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS)
@@ -91,6 +104,11 @@
 	 */
 	spin_lock_irqsave(&port->lock, flags);
 
+	/*
+	 * Update the per-port timeout.
+	 */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
 	/* set DLAB we have cval saved in up->lcr from the call to the core */
 	serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
 	serial_dl_write(up, quot);
@@ -231,17 +249,17 @@
 
 	platform_set_drvdata(pdev, data);
 
-	pm_runtime_enable(&pdev->dev);
-	if (!pm_runtime_enabled(&pdev->dev)) {
-		err = mtk8250_runtime_resume(&pdev->dev);
-		if (err)
-			return err;
-	}
+	err = mtk8250_runtime_resume(&pdev->dev);
+	if (err)
+		return err;
 
 	data->line = serial8250_register_8250_port(&uart);
 	if (data->line < 0)
 		return data->line;
 
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	return 0;
 }
 
@@ -252,13 +270,11 @@
 	pm_runtime_get_sync(&pdev->dev);
 
 	serial8250_unregister_port(data->line);
+	mtk8250_runtime_suspend(&pdev->dev);
 
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_put_noidle(&pdev->dev);
 
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		mtk8250_runtime_suspend(&pdev->dev);
-
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/tty/serial/8250/8250_omap.c
+++ linux-4.4.0/drivers/tty/serial/8250/8250_omap.c
@@ -155,11 +155,6 @@
 				     struct omap8250_priv *priv)
 {
 	u8 timeout = 255;
-	u8 old_mdr1;
-
-	old_mdr1 = serial_in(up, UART_OMAP_MDR1);
-	if (old_mdr1 == priv->mdr1)
-		return;
 
 	serial_out(up, UART_OMAP_MDR1, priv->mdr1);
 	udelay(2);
@@ -608,6 +603,10 @@
 	up->lsr_saved_flags = 0;
 	up->msr_saved_flags = 0;
 
+	/* Disable DMA for console UART */
+	if (uart_console(port))
+		up->dma = NULL;
+
 	if (up->dma) {
 		ret = serial8250_request_dma(up);
 		if (ret) {
@@ -1184,11 +1183,11 @@
 	spin_lock_init(&priv->rx_dma_lock);
 
 	device_init_wakeup(&pdev->dev, true);
+	pm_runtime_enable(&pdev->dev);
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_set_autosuspend_delay(&pdev->dev, -1);
 
 	pm_runtime_irq_safe(&pdev->dev);
-	pm_runtime_enable(&pdev->dev);
 
 	pm_runtime_get_sync(&pdev->dev);
 
@@ -1235,7 +1234,8 @@
 	pm_runtime_put_autosuspend(&pdev->dev);
 	return 0;
 err:
-	pm_runtime_put(&pdev->dev);
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	return ret;
 }
@@ -1244,6 +1244,7 @@
 {
 	struct omap8250_priv *priv = platform_get_drvdata(pdev);
 
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	serial8250_unregister_port(priv->line);
@@ -1343,6 +1344,10 @@
 	struct omap8250_priv *priv = dev_get_drvdata(dev);
 	struct uart_8250_port *up;
 
+	/* In case runtime-pm tries this before we are setup */
+	if (!priv)
+		return 0;
+
 	up = serial8250_get_port(priv->line);
 	/*
 	 * When using 'no_console_suspend', the console UART must not be
--- linux-4.4.0.orig/drivers/tty/serial/8250/8250_pci.c
+++ linux-4.4.0/drivers/tty/serial/8250/8250_pci.c
@@ -57,6 +57,7 @@
 	unsigned int		nr;
 	void __iomem		*remapped_bar[PCI_NUM_BAR_RESOURCES];
 	struct pci_serial_quirk	*quirk;
+	const struct pciserial_board *board;
 	int			line[0];
 };
 
@@ -1379,6 +1380,9 @@
 #define PCI_DEVICE_ID_INTEL_BSW_UART1	0x228a
 #define PCI_DEVICE_ID_INTEL_BSW_UART2	0x228c
 
+#define PCI_DEVICE_ID_INTEL_BDW_UART1	0x9ce3
+#define PCI_DEVICE_ID_INTEL_BDW_UART2	0x9ce4
+
 #define BYT_PRV_CLK			0x800
 #define BYT_PRV_CLK_EN			(1 << 0)
 #define BYT_PRV_CLK_M_VAL_SHIFT		1
@@ -1398,6 +1402,9 @@
 	unsigned long m, n;
 	u32 reg;
 
+	/* Gracefully handle the B0 case: fall back to B9600 */
+	fuart = fuart ? fuart : 9600 * 16;
+
 	/* Get Fuart closer to Fref */
 	fuart *= rounddown_pow_of_two(fref / fuart);
 
@@ -1461,11 +1468,13 @@
 	switch (pdev->device) {
 	case PCI_DEVICE_ID_INTEL_BYT_UART1:
 	case PCI_DEVICE_ID_INTEL_BSW_UART1:
+	case PCI_DEVICE_ID_INTEL_BDW_UART1:
 		rx_param->src_id = 3;
 		tx_param->dst_id = 2;
 		break;
 	case PCI_DEVICE_ID_INTEL_BYT_UART2:
 	case PCI_DEVICE_ID_INTEL_BSW_UART2:
+	case PCI_DEVICE_ID_INTEL_BDW_UART2:
 		rx_param->src_id = 5;
 		tx_param->dst_id = 4;
 		break;
@@ -1936,6 +1945,7 @@
 #define PCIE_VENDOR_ID_WCH		0x1c00
 #define PCIE_DEVICE_ID_WCH_CH382_2S1P	0x3250
 #define PCIE_DEVICE_ID_WCH_CH384_4S	0x3470
+#define PCIE_DEVICE_ID_WCH_CH382_2S	0x3253
 
 #define PCI_VENDOR_ID_PERICOM			0x12D8
 #define PCI_DEVICE_ID_PERICOM_PI7C9X7951	0x7951
@@ -1943,6 +1953,43 @@
 #define PCI_DEVICE_ID_PERICOM_PI7C9X7954	0x7954
 #define PCI_DEVICE_ID_PERICOM_PI7C9X7958	0x7958
 
+#define PCI_VENDOR_ID_ACCESIO			0x494f
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB	0x1051
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S	0x1053
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB	0x105C
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S	0x105E
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB	0x1091
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2	0x1093
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB	0x1099
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4	0x109B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB	0x10D1
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM	0x10D3
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB	0x10DA
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM	0x10DC
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1	0x1108
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2	0x1110
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2	0x1111
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4	0x1118
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4	0x1119
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S	0x1152
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S	0x115A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2	0x1190
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2	0x1191
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4	0x1198
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4	0x1199
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM	0x11D0
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4	0x105A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4	0x105B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8	0x106A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8	0x106B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4	0x1098
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8	0x10A9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM	0x10D9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM	0x10E9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM	0x11D8
+
+
+
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584	0x1584
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1588	0x1588
@@ -2062,6 +2109,20 @@
 		.subdevice	= PCI_ANY_ID,
 		.setup		= byt_serial_setup,
 	},
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_BDW_UART1,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= byt_serial_setup,
+	},
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_BDW_UART2,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= byt_serial_setup,
+	},
 	/*
 	 * ITE
 	 */
@@ -2265,6 +2326,111 @@
 		.setup		= pci_default_setup,
 		.exit		= pci_plx9050_exit,
 	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
+	{
+		.vendor     = PCI_VENDOR_ID_ACCESIO,
+		.device     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
+		.subvendor  = PCI_ANY_ID,
+		.subdevice  = PCI_ANY_ID,
+		.setup      = pci_pericom_setup,
+	},
 	/*
 	 * SBS Technologies, Inc., PMC-OCTALPRO 232
 	 */
@@ -2618,6 +2784,14 @@
 		.subdevice	= PCI_ANY_ID,
 		.setup		= pci_wch_ch353_setup,
 	},
+	/* WCH CH382 2S card (16850 clone) */
+	{
+		.vendor         = PCIE_VENDOR_ID_WCH,
+		.device         = PCIE_DEVICE_ID_WCH_CH382_2S,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.setup          = pci_wch_ch38x_setup,
+	},
 	/* WCH CH382 2S1P card (16850 clone) */
 	{
 		.vendor         = PCIE_VENDOR_ID_WCH,
@@ -2812,6 +2986,8 @@
 	pbn_b0_4_1152000_200,
 	pbn_b0_8_1152000_200,
 
+	pbn_b0_4_1250000,
+
 	pbn_b0_2_1843200,
 	pbn_b0_4_1843200,
 
@@ -2936,6 +3112,7 @@
 	pbn_fintek_4,
 	pbn_fintek_8,
 	pbn_fintek_12,
+	pbn_wch382_2,
 	pbn_wch384_4,
 	pbn_pericom_PI7C9X7951,
 	pbn_pericom_PI7C9X7952,
@@ -3044,6 +3221,13 @@
 		.uart_offset	= 0x200,
 	},
 
+	[pbn_b0_4_1250000] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 4,
+		.base_baud	= 1250000,
+		.uart_offset	= 8,
+	},
+
 	[pbn_b0_2_1843200] = {
 		.flags		= FL_BASE0,
 		.num_ports	= 2,
@@ -3756,6 +3940,13 @@
 		.base_baud	= 115200,
 		.first_offset	= 0x40,
 	},
+	[pbn_wch382_2] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 2,
+		.base_baud	= 115200,
+		.uart_offset	= 8,
+		.first_offset	= 0xC0,
+	},
 	[pbn_wch384_4] = {
 		.flags		= FL_BASE0,
 		.num_ports	= 4,
@@ -3973,6 +4164,7 @@
 		}
 	}
 	priv->nr = i;
+	priv->board = board;
 	return priv;
 
 err_deinit:
@@ -3983,7 +4175,7 @@
 }
 EXPORT_SYMBOL_GPL(pciserial_init_ports);
 
-void pciserial_remove_ports(struct serial_private *priv)
+void pciserial_detach_ports(struct serial_private *priv)
 {
 	struct pci_serial_quirk *quirk;
 	int i;
@@ -4003,7 +4195,11 @@
 	quirk = find_quirk(priv->dev);
 	if (quirk->exit)
 		quirk->exit(priv->dev);
+}
 
+void pciserial_remove_ports(struct serial_private *priv)
+{
+	pciserial_detach_ports(priv);
 	kfree(priv);
 }
 EXPORT_SYMBOL_GPL(pciserial_remove_ports);
@@ -5081,6 +5277,108 @@
 		0,
 		0, pbn_pericom_PI7C9X7958 },
 	/*
+	 * ACCES I/O Products quad
+	 */
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7951 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7952 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7958 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7958 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7958 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7958 },
+	{	PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pericom_PI7C9X7954 },
+	/*
 	 * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
 	 */
 	{	PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
@@ -5107,6 +5405,17 @@
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
 		pbn_b2_4_115200 },
 	/*
+	 * BrainBoxes UC-260
+	 */
+	{	PCI_VENDOR_ID_INTASHIELD, 0x0D21,
+		PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+		pbn_b2_4_115200 },
+	{	PCI_VENDOR_ID_INTASHIELD, 0x0E34,
+		PCI_ANY_ID, PCI_ANY_ID,
+		 PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+		pbn_b2_4_115200 },
+	/*
 	 * Perle PCI-RAS cards
 	 */
 	{       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
@@ -5506,6 +5815,16 @@
 		PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
 		pbn_byt },
 
+	/* Intel Broadwell */
+	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART1,
+		PCI_ANY_ID,  PCI_ANY_ID,
+		PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
+		pbn_byt },
+	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART2,
+		PCI_ANY_ID,  PCI_ANY_ID,
+		PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
+		pbn_byt },
+
 	/*
 	 * Intel Quark x1000
 	 */
@@ -5545,6 +5864,10 @@
 		PCI_ANY_ID, PCI_ANY_ID,
 		0, 0, pbn_b0_bt_2_115200 },
 
+	{	PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0, pbn_wch382_2 },
+
 	{	PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
 		PCI_ANY_ID, PCI_ANY_ID,
 		0, 0, pbn_wch384_4 },
@@ -5581,11 +5904,29 @@
 		0,
 		0, pbn_exar_XR17V358 },
 
+	/*
+	 * Realtek RealManage
+	 */
+	{	PCI_VENDOR_ID_REALTEK, 0x816a,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0, pbn_b0_1_115200 },
+
+	{	PCI_VENDOR_ID_REALTEK, 0x816b,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0, pbn_b0_1_115200 },
+
 	/* Fintek PCI serial cards */
 	{ PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
 	{ PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
 	{ PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 },
 
+	/* MKS Tenta SCOM-080x serial cards */
+	{ PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },
+	{ PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 },
+
+	/* Amazon PCI serial device */
+	{ PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 },
+
 	/*
 	 * These entries match devices with class COMMUNICATION_SERIAL,
 	 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
@@ -5614,7 +5955,7 @@
 		return PCI_ERS_RESULT_DISCONNECT;
 
 	if (priv)
-		pciserial_suspend_ports(priv);
+		pciserial_detach_ports(priv);
 
 	pci_disable_device(dev);
 
@@ -5639,9 +5980,16 @@
 static void serial8250_io_resume(struct pci_dev *dev)
 {
 	struct serial_private *priv = pci_get_drvdata(dev);
+	struct serial_private *new;
 
-	if (priv)
-		pciserial_resume_ports(priv);
+	if (!priv)
+		return;
+
+	new = pciserial_init_ports(dev, priv->board);
+	if (!IS_ERR(new)) {
+		pci_set_drvdata(dev, new);
+		kfree(priv);
+	}
 }
 
 static const struct pci_error_handlers serial8250_err_handler = {
--- linux-4.4.0.orig/drivers/tty/serial/8250/8250_port.c
+++ linux-4.4.0/drivers/tty/serial/8250/8250_port.c
@@ -713,22 +713,16 @@
  */
 static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
 {
-	unsigned char old_dll, old_dlm, old_lcr;
-	unsigned int id;
+	unsigned char old_lcr;
+	unsigned int id, old_dl;
 
 	old_lcr = serial_in(p, UART_LCR);
 	serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A);
+	old_dl = serial_dl_read(p);
+	serial_dl_write(p, 0);
+	id = serial_dl_read(p);
+	serial_dl_write(p, old_dl);
 
-	old_dll = serial_in(p, UART_DLL);
-	old_dlm = serial_in(p, UART_DLM);
-
-	serial_out(p, UART_DLL, 0);
-	serial_out(p, UART_DLM, 0);
-
-	id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8;
-
-	serial_out(p, UART_DLL, old_dll);
-	serial_out(p, UART_DLM, old_dlm);
 	serial_out(p, UART_LCR, old_lcr);
 
 	return id;
@@ -1908,6 +1902,10 @@
 
 	if (port->irq) {
 		unsigned char iir1;
+
+		if (port->irqflags & IRQF_SHARED)
+			disable_irq_nosync(port->irq);
+
 		/*
 		 * Test for UARTs that do not reassert THRE when the
 		 * transmitter is idle and the interrupt has already
@@ -1917,8 +1915,6 @@
 		 * allow register changes to become visible.
 		 */
 		spin_lock_irqsave(&port->lock, flags);
-		if (up->port.irqflags & IRQF_SHARED)
-			disable_irq_nosync(port->irq);
 
 		wait_for_xmitr(up, UART_LSR_THRE);
 		serial_port_out_sync(port, UART_IER, UART_IER_THRI);
@@ -1930,9 +1926,10 @@
 		iir = serial_port_in(port, UART_IIR);
 		serial_port_out(port, UART_IER, 0);
 
+		spin_unlock_irqrestore(&port->lock, flags);
+
 		if (port->irqflags & IRQF_SHARED)
 			enable_irq(port->irq);
-		spin_unlock_irqrestore(&port->lock, flags);
 
 		/*
 		 * If the interrupt is not reasserted, or we otherwise
@@ -2229,8 +2226,11 @@
 	serial_dl_write(up, quot);
 
 	/* XR17V35x UARTs have an extra fractional divisor register (DLD) */
-	if (up->port.type == PORT_XR17V35X)
+	if (up->port.type == PORT_XR17V35X) {
+		/* Preserve bits not related to baudrate; DLD[7:4]. */
+		quot_frac |= serial_port_in(port, 0x2) & 0xf0;
 		serial_port_out(port, 0x2, quot_frac);
+	}
 }
 
 static unsigned int
--- linux-4.4.0.orig/drivers/tty/serial/8250/Kconfig
+++ linux-4.4.0/drivers/tty/serial/8250/Kconfig
@@ -372,7 +372,7 @@
 	tristate "Support for serial ports on Intel MID platforms"
 	depends on SERIAL_8250 && PCI
 	select HSU_DMA if SERIAL_8250_DMA
-	select HSU_DMA_PCI if X86_INTEL_MID
+	select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
 	select RATIONAL
 	help
 	  Selecting this option will enable handling of the extra features
--- linux-4.4.0.orig/drivers/tty/serial/8250/serial_cs.c
+++ linux-4.4.0/drivers/tty/serial/8250/serial_cs.c
@@ -305,6 +305,7 @@
 static int serial_probe(struct pcmcia_device *link)
 {
 	struct serial_info *info;
+	int ret;
 
 	dev_dbg(&link->dev, "serial_attach()\n");
 
@@ -319,7 +320,15 @@
 	if (do_sound)
 		link->config_flags |= CONF_ENABLE_SPKR;
 
-	return serial_config(link);
+	ret = serial_config(link);
+	if (ret)
+		goto free_info;
+
+	return 0;
+
+free_info:
+	kfree(info);
+	return ret;
 }
 
 static void serial_detach(struct pcmcia_device *link)
@@ -629,8 +638,10 @@
 	    (link->has_func_id) &&
 	    (link->socket->pcmcia_pfc == 0) &&
 	    ((link->func_id == CISTPL_FUNCID_MULTI) ||
-	     (link->func_id == CISTPL_FUNCID_SERIAL)))
-		pcmcia_loop_config(link, serial_check_for_multi, info);
+	     (link->func_id == CISTPL_FUNCID_SERIAL))) {
+		if (pcmcia_loop_config(link, serial_check_for_multi, info))
+			goto failed;
+	}
 
 	/*
 	 * Apply any multi-port quirk.
--- linux-4.4.0.orig/drivers/tty/serial/Kconfig
+++ linux-4.4.0/drivers/tty/serial/Kconfig
@@ -9,6 +9,7 @@
 
 config SERIAL_EARLYCON
 	bool
+	depends on SERIAL_CORE
 	help
 	  Support for early consoles with the earlycon parameter. This enables
 	  the console before standard serial driver is probed. The console is
--- linux-4.4.0.orig/drivers/tty/serial/amba-pl011.c
+++ linux-4.4.0/drivers/tty/serial/amba-pl011.c
@@ -2189,12 +2189,67 @@
 	return uart_set_options(&uap->port, co, baud, parity, bits, flow);
 }
 
+/**
+ *	pl011_console_match - non-standard console matching
+ *	@co:	  registering console
+ *	@name:	  name from console command line
+ *	@idx:	  index from console command line
+ *	@options: ptr to option string from console command line
+ *
+ *	Only attempts to match console command lines of the form:
+ *	    console=pl011,mmio|mmio32,<addr>[,<options>]
+ *	    console=pl011,0x<addr>[,<options>]
+ *	This form is used to register an initial earlycon boot console and
+ *	replace it with the amba_console at pl011 driver init.
+ *
+ *	Performs console setup for a match (as required by interface)
+ *	If no <options> are specified, then assume the h/w is already setup.
+ *
+ *	Returns 0 if console matches; otherwise non-zero to use default matching
+ */
+static int __init pl011_console_match(struct console *co, char *name, int idx,
+				      char *options)
+{
+	unsigned char iotype;
+	unsigned long addr;
+	int i;
+
+	if (strcmp(name, "pl011") != 0)
+		return -ENODEV;
+
+	if (uart_parse_earlycon(options, &iotype, &addr, &options))
+		return -ENODEV;
+
+	if (iotype != UPIO_MEM && iotype != UPIO_MEM32)
+		return -ENODEV;
+
+	/* try to match the port specified on the command line */
+	for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
+		struct uart_port *port;
+
+		if (!amba_ports[i])
+			continue;
+
+		port = &amba_ports[i]->port;
+
+		if (port->mapbase != addr)
+			continue;
+
+		co->index = i;
+		port->cons = co;
+		return pl011_console_setup(co, options);
+	}
+
+	return -ENODEV;
+}
+
 static struct uart_driver amba_reg;
 static struct console amba_console = {
 	.name		= "ttyAMA",
 	.write		= pl011_console_write,
 	.device		= uart_console_device,
 	.setup		= pl011_console_setup,
+	.match		= pl011_console_match,
 	.flags		= CON_PRINTBUFFER,
 	.index		= -1,
 	.data		= &amba_reg,
@@ -2323,6 +2378,7 @@
 	uap->port.fifosize = uap->fifosize;
 	uap->port.flags = UPF_BOOT_AUTOCONF;
 	uap->port.line = index;
+	spin_lock_init(&uap->port.lock);
 
 	amba_ports[index] = uap;
 
@@ -2331,7 +2387,7 @@
 
 static int pl011_register_port(struct uart_amba_port *uap)
 {
-	int ret;
+	int ret, i;
 
 	/* Ensure interrupts from this UART are masked and cleared */
 	writew(0, uap->port.membase + UART011_IMSC);
@@ -2342,6 +2398,9 @@
 		if (ret < 0) {
 			dev_err(uap->port.dev,
 				"Failed to register AMBA-PL011 driver\n");
+			for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+				if (amba_ports[i] == uap)
+					amba_ports[i] = NULL;
 			return ret;
 		}
 	}
--- linux-4.4.0.orig/drivers/tty/serial/ar933x_uart.c
+++ linux-4.4.0/drivers/tty/serial/ar933x_uart.c
@@ -294,6 +294,10 @@
 	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
 			    AR933X_UART_CS_HOST_INT_EN);
 
+	/* enable RX and TX ready overide */
+	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
+		AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
+
 	/* reenable the UART */
 	ar933x_uart_rmw(up, AR933X_UART_CS_REG,
 			AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
@@ -426,6 +430,10 @@
 	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
 			    AR933X_UART_CS_HOST_INT_EN);
 
+	/* enable RX and TX ready overide */
+	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
+		AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
+
 	/* Enable RX interrupts */
 	up->ier = AR933X_UART_INT_RX_VALID;
 	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
--- linux-4.4.0.orig/drivers/tty/serial/arc_uart.c
+++ linux-4.4.0/drivers/tty/serial/arc_uart.c
@@ -597,6 +597,11 @@
 	if (dev_id < 0)
 		dev_id = 0;
 
+	if (dev_id >= ARRAY_SIZE(arc_uart_ports)) {
+		dev_err(&pdev->dev, "serial%d out of range\n", dev_id);
+		return -EINVAL;
+	}
+
 	uart = &arc_uart_ports[dev_id];
 	port = &uart->port;
 
--- linux-4.4.0.orig/drivers/tty/serial/atmel_serial.c
+++ linux-4.4.0/drivers/tty/serial/atmel_serial.c
@@ -169,6 +169,8 @@
 	unsigned int		pending_status;
 	spinlock_t		lock_suspended;
 
+	bool			hd_start_rx;	/* can start RX during half-duplex operation */
+
 	int (*prepare_rx)(struct uart_port *port);
 	int (*prepare_tx)(struct uart_port *port);
 	void (*schedule_rx)(struct uart_port *port);
@@ -237,6 +239,12 @@
 
 #endif
 
+static inline int atmel_uart_is_half_duplex(struct uart_port *port)
+{
+	return (port->rs485.flags & SER_RS485_ENABLED) &&
+		!(port->rs485.flags & SER_RS485_RX_DURING_TX);
+}
+
 #ifdef CONFIG_SERIAL_ATMEL_PDC
 static bool atmel_use_pdc_rx(struct uart_port *port)
 {
@@ -277,6 +285,13 @@
 	return atmel_port->use_dma_rx;
 }
 
+static bool atmel_use_fifo(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	return atmel_port->fifo_size;
+}
+
 static unsigned int atmel_get_lines_status(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -463,12 +478,20 @@
 		/* disable PDC transmit */
 		atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
 	}
+
+	/*
+	 * Disable the transmitter.
+	 * This is mandatory when DMA is used, otherwise the DMA buffer
+	 * is fully transmitted.
+	 */
+	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
+
 	/* Disable interrupts */
 	atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
 
-	if ((port->rs485.flags & SER_RS485_ENABLED) &&
-	    !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+	if (atmel_uart_is_half_duplex(port))
 		atmel_start_rx(port);
+
 }
 
 /*
@@ -478,21 +501,25 @@
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_pdc_tx(port)) {
-		if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN)
-			/* The transmitter is already running.  Yes, we
-			   really need this.*/
-			return;
+	if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
+				       & ATMEL_PDC_TXTEN))
+		/* The transmitter is already running.  Yes, we
+		   really need this.*/
+		return;
 
-		if ((port->rs485.flags & SER_RS485_ENABLED) &&
-		    !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+	if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
+		if (atmel_uart_is_half_duplex(port))
 			atmel_stop_rx(port);
 
+	if (atmel_use_pdc_tx(port))
 		/* re-enable PDC transmit */
 		atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
-	}
+
 	/* Enable interrupts */
 	atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
+
+	/* re-enable the transmitter */
+	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
 }
 
 /*
@@ -790,6 +817,15 @@
 	 */
 	if (!uart_circ_empty(xmit))
 		tasklet_schedule(&atmel_port->tasklet);
+	else if (atmel_uart_is_half_duplex(port)) {
+		/*
+		 * DMA done, re-enable TXEMPTY and signal that we can stop
+		 * TX and start RX for RS485
+		 */
+		atmel_port->hd_start_rx = true;
+		atmel_uart_writel(port, ATMEL_US_IER,
+				  atmel_port->tx_done_mask);
+	}
 
 	spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -892,12 +928,6 @@
 		desc->callback = atmel_complete_tx_dma;
 		desc->callback_param = atmel_port;
 		atmel_port->cookie_tx = dmaengine_submit(desc);
-
-	} else {
-		if (port->rs485.flags & SER_RS485_ENABLED) {
-			/* DMA done, stop TX, start RX for RS485 */
-			atmel_start_rx(port);
-		}
 	}
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -1148,6 +1178,10 @@
 					 sg_dma_len(&atmel_port->sg_rx)/2,
 					 DMA_DEV_TO_MEM,
 					 DMA_PREP_INTERRUPT);
+	if (!desc) {
+		dev_err(port->dev, "Preparing DMA cyclic failed\n");
+		goto chan_err;
+	}
 	desc->callback = atmel_complete_rx_dma;
 	desc->callback_param = port;
 	atmel_port->desc_rx = desc;
@@ -1230,9 +1264,19 @@
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
 	if (pending & atmel_port->tx_done_mask) {
-		/* Either PDC or interrupt transmission */
 		atmel_uart_writel(port, ATMEL_US_IDR,
 				  atmel_port->tx_done_mask);
+
+		/* Start RX if flag was set and FIFO is empty */
+		if (atmel_port->hd_start_rx) {
+			if (!(atmel_uart_readl(port, ATMEL_US_CSR)
+					& ATMEL_US_TXEMPTY))
+				dev_warn(port->dev, "Should start RX, but TX fifo is not empty\n");
+
+			atmel_port->hd_start_rx = false;
+			atmel_start_rx(port);
+		}
+
 		tasklet_schedule(&atmel_port->tasklet);
 	}
 }
@@ -1365,8 +1409,7 @@
 		atmel_uart_writel(port, ATMEL_US_IER,
 				  atmel_port->tx_done_mask);
 	} else {
-		if ((port->rs485.flags & SER_RS485_ENABLED) &&
-		    !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+		if (atmel_uart_is_half_duplex(port)) {
 			/* DMA done, stop TX, start RX for RS485 */
 			atmel_start_rx(port);
 		}
@@ -1764,6 +1807,7 @@
 		switch (version) {
 		case 0x302:
 		case 0x10213:
+		case 0x10302:
 			dev_dbg(port->dev, "This version is usart\n");
 			atmel_port->is_usart = true;
 			break;
@@ -1967,6 +2011,11 @@
 		atmel_uart_writel(port, ATMEL_PDC_TCR, 0);
 		atmel_port->pdc_tx.ofs = 0;
 	}
+	/*
+	 * in uart_flush_buffer(), the xmit circular buffer has just
+	 * been cleared, so we have to reset tx_len accordingly.
+	 */
+	atmel_port->tx_len = 0;
 }
 
 /*
@@ -2066,6 +2115,7 @@
 static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
 			      struct ktermios *old)
 {
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	unsigned long flags;
 	unsigned int old_mode, mode, imr, quot, baud;
 
@@ -2169,7 +2219,30 @@
 		mode |= ATMEL_US_USMODE_RS485;
 	} else if (termios->c_cflag & CRTSCTS) {
 		/* RS232 with hardware handshake (RTS/CTS) */
-		mode |= ATMEL_US_USMODE_HWHS;
+		if (atmel_use_fifo(port) &&
+		    !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
+			/*
+			 * with ATMEL_US_USMODE_HWHS set, the controller will
+			 * be able to drive the RTS pin high/low when the RX
+			 * FIFO is above RXFTHRES/below RXFTHRES2.
+			 * It will also disable the transmitter when the CTS
+			 * pin is high.
+			 * This mode is not activated if CTS pin is a GPIO
+			 * because in this case, the transmitter is always
+			 * disabled (there must be an internal pull-up
+			 * responsible for this behaviour).
+			 * If the RTS pin is a GPIO, the controller won't be
+			 * able to drive it according to the FIFO thresholds,
+			 * but it will be handled by the driver.
+			 */
+			mode |= ATMEL_US_USMODE_HWHS;
+		} else {
+			/*
+			 * For platforms without FIFO, the flow control is
+			 * handled by the driver.
+			 */
+			mode |= ATMEL_US_USMODE_NORMAL;
+		}
 	} else {
 		/* RS232 without hadware handshake */
 		mode |= ATMEL_US_USMODE_NORMAL;
@@ -2455,6 +2528,9 @@
 	pdc_tx = atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN;
 	atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
 
+	/* Make sure that tx path is actually able to send characters */
+	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
+
 	uart_console_write(port, s, count, atmel_console_putchar);
 
 	/*
--- linux-4.4.0.orig/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ linux-4.4.0/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -421,7 +421,16 @@
 			clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
 		}
 		cpm_uart_initbd(pinfo);
-		cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+		if (IS_SMC(pinfo)) {
+			out_be32(&pinfo->smcup->smc_rstate, 0);
+			out_be32(&pinfo->smcup->smc_tstate, 0);
+			out_be16(&pinfo->smcup->smc_rbptr,
+				 in_be16(&pinfo->smcup->smc_rbase));
+			out_be16(&pinfo->smcup->smc_tbptr,
+				 in_be16(&pinfo->smcup->smc_tbase));
+		} else {
+			cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+		}
 	}
 	/* Install interrupt handler. */
 	retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
@@ -875,16 +884,14 @@
 	         (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
 
 /*
- *  In case SMC1 is being relocated...
+ *  In case SMC is being relocated...
  */
-#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
 	out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
 	out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
 	out_be32(&up->smc_rstate, 0);
 	out_be32(&up->smc_tstate, 0);
 	out_be16(&up->smc_brkcr, 1);              /* number of break chars */
 	out_be16(&up->smc_brkec, 0);
-#endif
 
 	/* Set up the uart parameters in the
 	 * parameter ram.
@@ -898,8 +905,6 @@
 	out_be16(&up->smc_brkec, 0);
 	out_be16(&up->smc_brkcr, 1);
 
-	cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-
 	/* Set UART mode, 8 bit, no parity, one stop.
 	 * Enable receive and transmit.
 	 */
@@ -1068,8 +1073,8 @@
 	/* Get the address of the host memory buffer.
 	 */
 	bdp = pinfo->rx_cur;
-	while (bdp->cbd_sc & BD_SC_EMPTY)
-		;
+	if (bdp->cbd_sc & BD_SC_EMPTY)
+		return NO_POLL_CHAR;
 
 	/* If the buffer address is in the CPM DPRAM, don't
 	 * convert it.
@@ -1104,7 +1109,11 @@
 		poll_chars = 0;
 	}
 	if (poll_chars <= 0) {
-		poll_chars = poll_wait_key(poll_buf, pinfo);
+		int ret = poll_wait_key(poll_buf, pinfo);
+
+		if (ret == NO_POLL_CHAR)
+			return ret;
+		poll_chars = ret;
 		pollp = poll_buf;
 	}
 	poll_chars--;
--- linux-4.4.0.orig/drivers/tty/serial/digicolor-usart.c
+++ linux-4.4.0/drivers/tty/serial/digicolor-usart.c
@@ -544,7 +544,11 @@
 	if (ret)
 		return ret;
 
-	return platform_driver_register(&digicolor_uart_platform);
+	ret = platform_driver_register(&digicolor_uart_platform);
+	if (ret)
+		uart_unregister_driver(&digicolor_uart);
+
+	return ret;
 }
 module_init(digicolor_uart_init);
 
--- linux-4.4.0.orig/drivers/tty/serial/earlycon.c
+++ linux-4.4.0/drivers/tty/serial/earlycon.c
@@ -20,6 +20,8 @@
 #include <linux/serial_core.h>
 #include <linux/sizes.h>
 #include <linux/mod_devicetable.h>
+#include <linux/of_fdt.h>
+#include <linux/acpi.h>
 
 #ifdef CONFIG_FIX_EARLYCON_MEM
 #include <asm/fixmap.h>
@@ -178,6 +180,14 @@
 	return -ENOENT;
 }
 
+/*
+ * When CONFIG_ACPI_SPCR_TABLE is defined, "earlycon" without parameters in
+ * command line does not start DT earlycon immediately, instead it defers
+ * starting it until DT/ACPI decision is made.  At that time if ACPI is enabled
+ * call parse_spcr(), else call early_init_dt_scan_chosen_stdout()
+ */
+bool earlycon_init_is_deferred __initdata;
+
 /* early_param wrapper for setup_earlycon() */
 static int __init param_setup_earlycon(char *buf)
 {
@@ -187,8 +197,14 @@
 	 * Just 'earlycon' is a valid param for devicetree earlycons;
 	 * don't generate a warning from parse_early_params() in that case
 	 */
-	if (!buf || !buf[0])
-		return 0;
+	if (!buf || !buf[0]) {
+		if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {
+			earlycon_init_is_deferred = true;
+			return 0;
+		} else {
+			return early_init_dt_scan_chosen_stdout();
+		}
+	}
 
 	err = setup_earlycon(buf);
 	if (err == -ENOENT || err == -EALREADY)
--- linux-4.4.0.orig/drivers/tty/serial/efm32-uart.c
+++ linux-4.4.0/drivers/tty/serial/efm32-uart.c
@@ -27,6 +27,7 @@
 #define UARTn_FRAME		0x04
 #define UARTn_FRAME_DATABITS__MASK	0x000f
 #define UARTn_FRAME_DATABITS(n)		((n) - 3)
+#define UARTn_FRAME_PARITY__MASK	0x0300
 #define UARTn_FRAME_PARITY_NONE		0x0000
 #define UARTn_FRAME_PARITY_EVEN		0x0200
 #define UARTn_FRAME_PARITY_ODD		0x0300
@@ -572,12 +573,16 @@
 			16 * (4 + (clkdiv >> 6)));
 
 	frame = efm32_uart_read32(efm_port, UARTn_FRAME);
-	if (frame & UARTn_FRAME_PARITY_ODD)
+	switch (frame & UARTn_FRAME_PARITY__MASK) {
+	case UARTn_FRAME_PARITY_ODD:
 		*parity = 'o';
-	else if (frame & UARTn_FRAME_PARITY_EVEN)
+		break;
+	case UARTn_FRAME_PARITY_EVEN:
 		*parity = 'e';
-	else
+		break;
+	default:
 		*parity = 'n';
+	}
 
 	*bits = (frame & UARTn_FRAME_DATABITS__MASK) -
 			UARTn_FRAME_DATABITS(4) + 4;
--- linux-4.4.0.orig/drivers/tty/serial/fsl_lpuart.c
+++ linux-4.4.0/drivers/tty/serial/fsl_lpuart.c
@@ -1267,6 +1267,8 @@
 			else
 				cr1 &= ~UARTCR1_PT;
 		}
+	} else {
+		cr1 &= ~UARTCR1_PE;
 	}
 
 	/* ask the core to calculate the divisor */
@@ -1402,10 +1404,12 @@
 			else
 				ctrl &= ~UARTCTRL_PT;
 		}
+	} else {
+		ctrl &= ~UARTCTRL_PE;
 	}
 
 	/* ask the core to calculate the divisor */
-	baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+	baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 4);
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -1818,6 +1822,10 @@
 		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
 		return ret;
 	}
+	if (ret >= ARRAY_SIZE(lpuart_ports)) {
+		dev_err(&pdev->dev, "serial%d out of range\n", ret);
+		return -EINVAL;
+	}
 	sport->port.line = ret;
 	sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
 
--- linux-4.4.0.orig/drivers/tty/serial/ifx6x60.c
+++ linux-4.4.0/drivers/tty/serial/ifx6x60.c
@@ -1241,6 +1241,9 @@
 	struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
 	/* stop activity */
 	tasklet_kill(&ifx_dev->io_work_tasklet);
+
+	pm_runtime_disable(&spi->dev);
+
 	/* free irq */
 	free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
 	free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev);
@@ -1378,9 +1381,9 @@
 static void __exit ifx_spi_exit(void)
 {
 	/* unregister */
+	spi_unregister_driver(&ifx_spi_driver);
 	tty_unregister_driver(tty_drv);
 	put_tty_driver(tty_drv);
-	spi_unregister_driver(&ifx_spi_driver);
 	unregister_reboot_notifier(&ifx_modem_reboot_notifier_block);
 }
 
--- linux-4.4.0.orig/drivers/tty/serial/imx.c
+++ linux-4.4.0/drivers/tty/serial/imx.c
@@ -529,7 +529,7 @@
 
 	sport->tx_bytes = uart_circ_chars_pending(xmit);
 
-	if (xmit->tail < xmit->head) {
+	if (xmit->tail < xmit->head || xmit->head == 0) {
 		sport->dma_tx_nents = 1;
 		sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
 	} else {
@@ -545,7 +545,7 @@
 		dev_err(dev, "DMA mapping error for TX.\n");
 		return;
 	}
-	desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
+	desc = dmaengine_prep_slave_sg(chan, sgl, ret,
 					DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
 	if (!desc) {
 		dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
@@ -1628,16 +1628,6 @@
 	unsigned int ucr1;
 	unsigned long flags = 0;
 	int locked = 1;
-	int retval;
-
-	retval = clk_enable(sport->clk_per);
-	if (retval)
-		return;
-	retval = clk_enable(sport->clk_ipg);
-	if (retval) {
-		clk_disable(sport->clk_per);
-		return;
-	}
 
 	if (sport->port.sysrq)
 		locked = 0;
@@ -1673,9 +1663,6 @@
 
 	if (locked)
 		spin_unlock_irqrestore(&sport->port.lock, flags);
-
-	clk_disable(sport->clk_ipg);
-	clk_disable(sport->clk_per);
 }
 
 /*
@@ -1776,13 +1763,12 @@
 
 	retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
 
-	clk_disable(sport->clk_ipg);
 	if (retval) {
-		clk_unprepare(sport->clk_ipg);
+		clk_disable_unprepare(sport->clk_ipg);
 		goto error_console;
 	}
 
-	retval = clk_prepare(sport->clk_per);
+	retval = clk_prepare_enable(sport->clk_per);
 	if (retval)
 		clk_disable_unprepare(sport->clk_ipg);
 
@@ -1923,6 +1909,12 @@
 	else if (ret < 0)
 		return ret;
 
+	if (sport->port.line >= ARRAY_SIZE(imx_ports)) {
+		dev_err(&pdev->dev, "serial%d out of range\n",
+			sport->port.line);
+		return -EINVAL;
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(base))
@@ -1991,6 +1983,14 @@
 				       dev_name(&pdev->dev), sport);
 		if (ret)
 			return ret;
+
+		ret = devm_request_irq(&pdev->dev, rtsirq, imx_rtsint, 0,
+				       dev_name(&pdev->dev), sport);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to request rts irq: %d\n",
+				ret);
+			return ret;
+		}
 	} else {
 		ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,
 				       dev_name(&pdev->dev), sport);
@@ -2057,12 +2057,14 @@
 		val &= ~UCR3_AWAKEN;
 	writel(val, sport->port.membase + UCR3);
 
-	val = readl(sport->port.membase + UCR1);
-	if (on)
-		val |= UCR1_RTSDEN;
-	else
-		val &= ~UCR1_RTSDEN;
-	writel(val, sport->port.membase + UCR1);
+	if (sport->have_rtscts) {
+		val = readl(sport->port.membase + UCR1);
+		if (on)
+			val |= UCR1_RTSDEN;
+		else
+			val &= ~UCR1_RTSDEN;
+		writel(val, sport->port.membase + UCR1);
+	}
 }
 
 static int imx_serial_port_suspend_noirq(struct device *dev)
--- linux-4.4.0.orig/drivers/tty/serial/kgdboc.c
+++ linux-4.4.0/drivers/tty/serial/kgdboc.c
@@ -131,19 +131,6 @@
 #define kgdboc_restore_input()
 #endif /* ! CONFIG_KDB_KEYBOARD */
 
-static int kgdboc_option_setup(char *opt)
-{
-	if (strlen(opt) >= MAX_CONFIG_LEN) {
-		printk(KERN_ERR "kgdboc: config string too long\n");
-		return -ENOSPC;
-	}
-	strcpy(config, opt);
-
-	return 0;
-}
-
-__setup("kgdboc=", kgdboc_option_setup);
-
 static void cleanup_kgdboc(void)
 {
 	if (kgdb_unregister_nmi_console())
@@ -157,15 +144,15 @@
 {
 	struct tty_driver *p;
 	int tty_line = 0;
-	int err;
+	int err = -ENODEV;
 	char *cptr = config;
 	struct console *cons;
 
-	err = kgdboc_option_setup(config);
-	if (err || !strlen(config) || isspace(config[0]))
+	if (!strlen(config) || isspace(config[0])) {
+		err = 0;
 		goto noconfig;
+	}
 
-	err = -ENODEV;
 	kgdboc_io_ops.is_console = 0;
 	kgdb_tty_driver = NULL;
 
@@ -247,7 +234,7 @@
 
 static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
 {
-	int len = strlen(kmessage);
+	size_t len = strlen(kmessage);
 
 	if (len >= MAX_CONFIG_LEN) {
 		printk(KERN_ERR "kgdboc: config string too long\n");
@@ -269,7 +256,7 @@
 
 	strcpy(config, kmessage);
 	/* Chop out \n char as a result of echo */
-	if (config[len - 1] == '\n')
+	if (len && config[len - 1] == '\n')
 		config[len - 1] = '\0';
 
 	if (configured == 1)
@@ -313,6 +300,25 @@
 };
 
 #ifdef CONFIG_KGDB_SERIAL_CONSOLE
+static int kgdboc_option_setup(char *opt)
+{
+	if (!opt) {
+		pr_err("config string not provided\n");
+		return -EINVAL;
+	}
+
+	if (strlen(opt) >= MAX_CONFIG_LEN) {
+		pr_err("config string too long\n");
+		return -ENOSPC;
+	}
+	strcpy(config, opt);
+
+	return 0;
+}
+
+__setup("kgdboc=", kgdboc_option_setup);
+
+
 /* This is only available if kgdboc is a built in for early debugging */
 static int __init kgdboc_early_init(char *opt)
 {
--- linux-4.4.0.orig/drivers/tty/serial/max3100.c
+++ linux-4.4.0/drivers/tty/serial/max3100.c
@@ -750,13 +750,14 @@
 	mutex_lock(&max3100s_lock);
 
 	if (!uart_driver_registered) {
-		uart_driver_registered = 1;
 		retval = uart_register_driver(&max3100_uart_driver);
 		if (retval) {
 			printk(KERN_ERR "Couldn't register max3100 uart driver\n");
 			mutex_unlock(&max3100s_lock);
 			return retval;
 		}
+
+		uart_driver_registered = 1;
 	}
 
 	for (i = 0; i < MAX_MAX3100; i++)
@@ -844,6 +845,7 @@
 		}
 	pr_debug("removing max3100 driver\n");
 	uart_unregister_driver(&max3100_uart_driver);
+	uart_driver_registered = 0;
 
 	mutex_unlock(&max3100s_lock);
 	return 0;
--- linux-4.4.0.orig/drivers/tty/serial/max310x.c
+++ linux-4.4.0/drivers/tty/serial/max310x.c
@@ -486,37 +486,48 @@
 
 static int max310x_set_baud(struct uart_port *port, int baud)
 {
-	unsigned int mode = 0, clk = port->uartclk, div = clk / baud;
+	unsigned int mode = 0, div = 0, frac = 0, c = 0, F = 0;
 
-	/* Check for minimal value for divider */
-	if (div < 16)
-		div = 16;
-
-	if (clk % baud && (div / 16) < 0x8000) {
+	/*
+	 * Calculate the integer divisor first. Select a proper mode
+	 * in case if the requested baud is too high for the pre-defined
+	 * clocks frequency.
+	 */
+	div = port->uartclk / baud;
+	if (div < 8) {
+		/* Mode x4 */
+		c = 4;
+		mode = MAX310X_BRGCFG_4XMODE_BIT;
+	} else if (div < 16) {
 		/* Mode x2 */
+		c = 8;
 		mode = MAX310X_BRGCFG_2XMODE_BIT;
-		clk = port->uartclk * 2;
-		div = clk / baud;
-
-		if (clk % baud && (div / 16) < 0x8000) {
-			/* Mode x4 */
-			mode = MAX310X_BRGCFG_4XMODE_BIT;
-			clk = port->uartclk * 4;
-			div = clk / baud;
-		}
+	} else {
+		c = 16;
 	}
 
-	max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
-	max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
-	max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
+	/* Calculate the divisor in accordance with the fraction coefficient */
+	div /= c;
+	F = c*baud;
+
+	/* Calculate the baud rate fraction */
+	if (div > 0)
+		frac = (16*(port->uartclk % F)) / F;
+	else
+		div = 1;
 
-	return DIV_ROUND_CLOSEST(clk, div);
+	max310x_port_write(port, MAX310X_BRGDIVMSB_REG, div >> 8);
+	max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div);
+	max310x_port_write(port, MAX310X_BRGCFG_REG, frac | mode);
+
+	/* Return the actual baud rate we just programmed */
+	return (16*port->uartclk) / (c*(16*div + frac));
 }
 
 static int max310x_update_best_err(unsigned long f, long *besterr)
 {
 	/* Use baudrate 115200 for calculate error */
-	long err = f % (115200 * 16);
+	long err = f % (460800 * 16);
 
 	if ((*besterr < 0) || (*besterr > err)) {
 		*besterr = err;
@@ -571,7 +582,7 @@
 	}
 
 	/* Configure clock source */
-	clksrc = xtal ? MAX310X_CLKSRC_CRYST_BIT : MAX310X_CLKSRC_EXTCLK_BIT;
+	clksrc = MAX310X_CLKSRC_EXTCLK_BIT | (xtal ? MAX310X_CLKSRC_CRYST_BIT : 0);
 
 	/* Configure PLL */
 	if (pllcfg) {
@@ -752,12 +763,9 @@
 
 static unsigned int max310x_tx_empty(struct uart_port *port)
 {
-	unsigned int lvl, sts;
-
-	lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
-	sts = max310x_port_read(port, MAX310X_IRQSTS_REG);
+	u8 lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
 
-	return ((sts & MAX310X_IRQ_TXEMPTY_BIT) && !lvl) ? TIOCSER_TEMT : 0;
+	return lvl ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int max310x_get_mctrl(struct uart_port *port)
@@ -1306,6 +1314,8 @@
 	if (spi->dev.of_node) {
 		const struct of_device_id *of_id =
 			of_match_device(max310x_dt_ids, &spi->dev);
+		if (!of_id)
+			return -ENODEV;
 
 		devtype = (struct max310x_devtype *)of_id->data;
 	} else {
--- linux-4.4.0.orig/drivers/tty/serial/msm_serial.c
+++ linux-4.4.0/drivers/tty/serial/msm_serial.c
@@ -222,10 +222,14 @@
 
 static inline void msm_wait_for_xmitr(struct uart_port *port)
 {
+	unsigned int timeout = 500000;
+
 	while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
 		if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
 			break;
 		udelay(1);
+		if (!timeout--)
+			break;
 	}
 	msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR);
 }
@@ -703,6 +707,7 @@
 	struct circ_buf *xmit = &msm_port->uart.state->xmit;
 	struct msm_dma *dma = &msm_port->tx_dma;
 	unsigned int pio_count, dma_count, dma_min;
+	char buf[4] = { 0 };
 	void __iomem *tf;
 	int err = 0;
 
@@ -712,10 +717,12 @@
 		else
 			tf = port->membase + UART_TF;
 
+		buf[0] = port->x_char;
+
 		if (msm_port->is_uartdm)
 			msm_reset_dm_count(port, 1);
 
-		iowrite8_rep(tf, &port->x_char, 1);
+		iowrite32_rep(tf, buf, 1);
 		port->icount.tx++;
 		port->x_char = 0;
 		return;
@@ -726,7 +733,7 @@
 		return;
 	}
 
-	pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+	pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
 	dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
 
 	dma_min = 1;	/* Always DMA */
@@ -816,6 +823,7 @@
 static void msm_reset(struct uart_port *port)
 {
 	struct msm_port *msm_port = UART_TO_MSM(port);
+	unsigned int mr;
 
 	/* reset everything */
 	msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
@@ -823,7 +831,10 @@
 	msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
 	msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
 	msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
-	msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+	msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
+	mr = msm_read(port, UART_MR1);
+	mr &= ~UART_MR1_RX_RDY_CTL;
+	msm_write(port, mr, UART_MR1);
 
 	/* Disable DM modes */
 	if (msm_port->is_uartdm)
@@ -861,37 +872,72 @@
 };
 
 static const struct msm_baud_map *
-msm_find_best_baud(struct uart_port *port, unsigned int baud)
+msm_find_best_baud(struct uart_port *port, unsigned int baud,
+		   unsigned long *rate)
 {
-	unsigned int i, divisor;
-	const struct msm_baud_map *entry;
+	struct msm_port *msm_port = UART_TO_MSM(port);
+	unsigned int divisor, result;
+	unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX;
+	const struct msm_baud_map *entry, *end, *best;
 	static const struct msm_baud_map table[] = {
-		{ 1536, 0x00,  1 },
-		{  768, 0x11,  1 },
-		{  384, 0x22,  1 },
-		{  192, 0x33,  1 },
-		{   96, 0x44,  1 },
-		{   48, 0x55,  1 },
-		{   32, 0x66,  1 },
-		{   24, 0x77,  1 },
-		{   16, 0x88,  1 },
-		{   12, 0x99,  6 },
-		{    8, 0xaa,  6 },
-		{    6, 0xbb,  6 },
-		{    4, 0xcc,  6 },
-		{    3, 0xdd,  8 },
-		{    2, 0xee, 16 },
 		{    1, 0xff, 31 },
-		{    0, 0xff, 31 },
+		{    2, 0xee, 16 },
+		{    3, 0xdd,  8 },
+		{    4, 0xcc,  6 },
+		{    6, 0xbb,  6 },
+		{    8, 0xaa,  6 },
+		{   12, 0x99,  6 },
+		{   16, 0x88,  1 },
+		{   24, 0x77,  1 },
+		{   32, 0x66,  1 },
+		{   48, 0x55,  1 },
+		{   96, 0x44,  1 },
+		{  192, 0x33,  1 },
+		{  384, 0x22,  1 },
+		{  768, 0x11,  1 },
+		{ 1536, 0x00,  1 },
 	};
 
-	divisor = uart_get_divisor(port, baud);
+	best = table; /* Default to smallest divider */
+	target = clk_round_rate(msm_port->clk, 16 * baud);
+	divisor = DIV_ROUND_CLOSEST(target, 16 * baud);
+
+	end = table + ARRAY_SIZE(table);
+	entry = table;
+	while (entry < end) {
+		if (entry->divisor <= divisor) {
+			result = target / entry->divisor / 16;
+			diff = abs(result - baud);
+
+			/* Keep track of best entry */
+			if (diff < best_diff) {
+				best_diff = diff;
+				best = entry;
+				best_rate = target;
+			}
 
-	for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++)
-		if (entry->divisor <= divisor)
-			break;
+			if (result == baud)
+				break;
+		} else if (entry->divisor > divisor) {
+			old = target;
+			target = clk_round_rate(msm_port->clk, old + 1);
+			/*
+			 * The rate didn't get any faster so we can't do
+			 * better at dividing it down
+			 */
+			if (target == old)
+				break;
+
+			/* Start the divisor search over at this new rate */
+			entry = table;
+			divisor = DIV_ROUND_CLOSEST(target, 16 * baud);
+			continue;
+		}
+		entry++;
+	}
 
-	return entry; /* Default to smallest divider */
+	*rate = best_rate;
+	return best;
 }
 
 static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
@@ -900,22 +946,20 @@
 	unsigned int rxstale, watermark, mask;
 	struct msm_port *msm_port = UART_TO_MSM(port);
 	const struct msm_baud_map *entry;
-	unsigned long flags;
-
-	entry = msm_find_best_baud(port, baud);
-
-	msm_write(port, entry->code, UART_CSR);
-
-	if (baud > 460800)
-		port->uartclk = baud * 16;
+	unsigned long flags, rate;
 
 	flags = *saved_flags;
 	spin_unlock_irqrestore(&port->lock, flags);
 
-	clk_set_rate(msm_port->clk, port->uartclk);
+	entry = msm_find_best_baud(port, baud, &rate);
+	clk_set_rate(msm_port->clk, rate);
+	baud = rate / 16 / entry->divisor;
 
 	spin_lock_irqsave(&port->lock, flags);
 	*saved_flags = flags;
+	port->uartclk = rate;
+
+	msm_write(port, entry->code, UART_CSR);
 
 	/* RX stale watermark */
 	rxstale = entry->rxstale;
@@ -1370,6 +1414,7 @@
 	int num_newlines = 0;
 	bool replaced = false;
 	void __iomem *tf;
+	int locked = 1;
 
 	if (is_uartdm)
 		tf = port->membase + UARTDM_TF;
@@ -1382,7 +1427,13 @@
 			num_newlines++;
 	count += num_newlines;
 
-	spin_lock(&port->lock);
+	if (port->sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&port->lock);
+	else
+		spin_lock(&port->lock);
+
 	if (is_uartdm)
 		msm_reset_dm_count(port, count);
 
@@ -1418,7 +1469,9 @@
 		iowrite32_rep(tf, buf, 1);
 		i += num_chars;
 	}
-	spin_unlock(&port->lock);
+
+	if (locked)
+		spin_unlock(&port->lock);
 }
 
 static void msm_console_write(struct console *co, const char *s,
@@ -1615,6 +1668,7 @@
 	{ .compatible = "qcom,msm-uartdm" },
 	{}
 };
+MODULE_DEVICE_TABLE(of, msm_match_table);
 
 static struct platform_driver msm_platform_driver = {
 	.remove = msm_serial_remove,
--- linux-4.4.0.orig/drivers/tty/serial/mxs-auart.c
+++ linux-4.4.0/drivers/tty/serial/mxs-auart.c
@@ -1248,8 +1248,9 @@
 
 	/*
 	 * If something went wrong, rollback.
+	 * Be careful: i may be unsigned.
 	 */
-	while (err && (--i >= 0))
+	while (err && (i-- > 0))
 		if (irq[i] >= 0)
 			free_irq(irq[i], s);
 
@@ -1274,6 +1275,10 @@
 		s->port.line = pdev->id < 0 ? 0 : pdev->id;
 	else if (ret < 0)
 		return ret;
+	if (s->port.line >= ARRAY_SIZE(auart_port)) {
+		dev_err(&pdev->dev, "serial%d out of range\n", s->port.line);
+		return -EINVAL;
+	}
 
 	if (of_id) {
 		pdev->id_entry = of_id->data;
--- linux-4.4.0.orig/drivers/tty/serial/omap-serial.c
+++ linux-4.4.0/drivers/tty/serial/omap-serial.c
@@ -693,7 +693,7 @@
 	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
 		up->efr |= UART_EFR_RTS;
 	else
-		up->efr &= UART_EFR_RTS;
+		up->efr &= ~UART_EFR_RTS;
 	serial_out(up, UART_EFR, up->efr);
 	serial_out(up, UART_LCR, lcr);
 
@@ -1343,7 +1343,7 @@
 
 /* Enable or disable the rs485 support */
 static int
-serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
 {
 	struct uart_omap_port *up = to_uart_omap_port(port);
 	unsigned int mode;
@@ -1356,8 +1356,12 @@
 	up->ier = 0;
 	serial_out(up, UART_IER, 0);
 
+	/* Clamp the delays to [0, 100ms] */
+	rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+	rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
+
 	/* store new config */
-	port->rs485 = *rs485conf;
+	port->rs485 = *rs485;
 
 	/*
 	 * Just as a precaution, only allow rs485
@@ -1708,7 +1712,8 @@
 	return 0;
 
 err_add_port:
-	pm_runtime_put(&pdev->dev);
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	pm_qos_remove_request(&up->pm_qos_request);
 	device_init_wakeup(up->dev, false);
@@ -1721,9 +1726,13 @@
 {
 	struct uart_omap_port *up = platform_get_drvdata(dev);
 
+	pm_runtime_get_sync(up->dev);
+
+	uart_remove_one_port(&serial_omap_reg, &up->port);
+
+	pm_runtime_dont_use_autosuspend(up->dev);
 	pm_runtime_put_sync(up->dev);
 	pm_runtime_disable(up->dev);
-	uart_remove_one_port(&serial_omap_reg, &up->port);
 	pm_qos_remove_request(&up->pm_qos_request);
 	device_init_wakeup(&dev->dev, false);
 
--- linux-4.4.0.orig/drivers/tty/serial/pch_uart.c
+++ linux-4.4.0/drivers/tty/serial/pch_uart.c
@@ -251,6 +251,7 @@
 	struct dma_chan			*chan_rx;
 	struct scatterlist		*sg_tx_p;
 	int				nent;
+	int				orig_nent;
 	struct scatterlist		sg_rx;
 	int				tx_dma_use;
 	void				*rx_buf_virt;
@@ -804,9 +805,10 @@
 	}
 	xmit->tail &= UART_XMIT_SIZE - 1;
 	async_tx_ack(priv->desc_tx);
-	dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE);
+	dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE);
 	priv->tx_dma_use = 0;
 	priv->nent = 0;
+	priv->orig_nent = 0;
 	kfree(priv->sg_tx_p);
 	pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
 }
@@ -1031,6 +1033,7 @@
 		dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__);
 		return 0;
 	}
+	priv->orig_nent = num;
 	priv->nent = nent;
 
 	for (i = 0; i < nent; i++, sg++) {
--- linux-4.4.0.orig/drivers/tty/serial/samsung.c
+++ linux-4.4.0/drivers/tty/serial/samsung.c
@@ -860,15 +860,12 @@
 	dma->rx_conf.direction		= DMA_DEV_TO_MEM;
 	dma->rx_conf.src_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE;
 	dma->rx_conf.src_addr		= p->port.mapbase + S3C2410_URXH;
-	dma->rx_conf.src_maxburst	= 16;
+	dma->rx_conf.src_maxburst	= 1;
 
 	dma->tx_conf.direction		= DMA_MEM_TO_DEV;
 	dma->tx_conf.dst_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE;
 	dma->tx_conf.dst_addr		= p->port.mapbase + S3C2410_UTXH;
-	if (dma_get_cache_alignment() >= 16)
-		dma->tx_conf.dst_maxburst = 16;
-	else
-		dma->tx_conf.dst_maxburst = 1;
+	dma->tx_conf.dst_maxburst	= 1;
 
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
@@ -900,14 +897,13 @@
 		return -ENOMEM;
 	}
 
-	dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+	dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
 				dma->rx_size, DMA_FROM_DEVICE);
 
 	spin_lock_irqsave(&p->port.lock, flags);
 
 	/* TX buffer */
-	dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
-				p->port.state->xmit.buf,
+	dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
 				UART_XMIT_SIZE, DMA_TO_DEVICE);
 
 	spin_unlock_irqrestore(&p->port.lock, flags);
@@ -921,7 +917,7 @@
 
 	if (dma->rx_chan) {
 		dmaengine_terminate_all(dma->rx_chan);
-		dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+		dma_unmap_single(p->port.dev, dma->rx_addr,
 				dma->rx_size, DMA_FROM_DEVICE);
 		kfree(dma->rx_buf);
 		dma_release_channel(dma->rx_chan);
@@ -930,7 +926,7 @@
 
 	if (dma->tx_chan) {
 		dmaengine_terminate_all(dma->tx_chan);
-		dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+		dma_unmap_single(p->port.dev, dma->tx_addr,
 				UART_XMIT_SIZE, DMA_TO_DEVICE);
 		dma_release_channel(dma->tx_chan);
 		dma->tx_chan = NULL;
@@ -1030,8 +1026,10 @@
 	if (ourport->dma) {
 		ret = s3c24xx_serial_request_dma(ourport);
 		if (ret < 0) {
-			dev_warn(port->dev, "DMA request failed\n");
-			return ret;
+			dev_warn(port->dev,
+				 "DMA request failed, DMA will not be used\n");
+			devm_kfree(port->dev, ourport->dma);
+			ourport->dma = NULL;
 		}
 	}
 
@@ -1153,14 +1151,14 @@
 	struct s3c24xx_uart_info *info = ourport->info;
 	struct clk *clk;
 	unsigned long rate;
-	unsigned int cnt, baud, quot, clk_sel, best_quot = 0;
+	unsigned int cnt, baud, quot, best_quot = 0;
 	char clkname[MAX_CLK_NAME_LENGTH];
 	int calc_deviation, deviation = (1 << 30) - 1;
 
-	clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
-			ourport->info->def_clk_sel;
 	for (cnt = 0; cnt < info->num_clks; cnt++) {
-		if (!(clk_sel & (1 << cnt)))
+		/* Keep selected clock if provided */
+		if (ourport->cfg->clk_sel &&
+			!(ourport->cfg->clk_sel & (1 << cnt)))
 			continue;
 
 		sprintf(clkname, "clk_uart_baud%d", cnt);
@@ -1263,6 +1261,8 @@
 	/* check to see if we need  to change clock source */
 
 	if (ourport->baudclk != clk) {
+		clk_prepare_enable(clk);
+
 		s3c24xx_serial_setsource(port, clk_sel);
 
 		if (!IS_ERR(ourport->baudclk)) {
@@ -1270,8 +1270,6 @@
 			ourport->baudclk = ERR_PTR(-EINVAL);
 		}
 
-		clk_prepare_enable(clk);
-
 		ourport->baudclk = clk;
 		ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
 	}
@@ -1331,11 +1329,14 @@
 	wr_regl(port, S3C2410_ULCON, ulcon);
 	wr_regl(port, S3C2410_UBRDIV, quot);
 
+	port->status &= ~UPSTAT_AUTOCTS;
+
 	umcon = rd_regl(port, S3C2410_UMCON);
 	if (termios->c_cflag & CRTSCTS) {
 		umcon |= S3C2410_UMCOM_AFC;
 		/* Disable RTS when RX FIFO contains 63 bytes */
 		umcon &= ~S3C2412_UMCON_AFC_8;
+		port->status = UPSTAT_AUTOCTS;
 	} else {
 		umcon &= ~S3C2410_UMCOM_AFC;
 	}
@@ -1676,7 +1677,7 @@
 		return -ENODEV;
 
 	if (port->mapbase != 0)
-		return 0;
+		return -EINVAL;
 
 	/* setup info for port */
 	port->dev	= &platdev->dev;
@@ -1718,9 +1719,11 @@
 		ourport->tx_irq = ret + 1;
 	}
 
-	ret = platform_get_irq(platdev, 1);
-	if (ret > 0)
-		ourport->tx_irq = ret;
+	if (!s3c24xx_serial_has_interrupt_mask(port)) {
+		ret = platform_get_irq(platdev, 1);
+		if (ret > 0)
+			ourport->tx_irq = ret;
+	}
 	/*
 	 * DMA is currently supported only on DT platforms, if DMA properties
 	 * are specified.
@@ -1730,22 +1733,25 @@
 		ourport->dma = devm_kzalloc(port->dev,
 					    sizeof(*ourport->dma),
 					    GFP_KERNEL);
-		if (!ourport->dma)
-			return -ENOMEM;
+		if (!ourport->dma) {
+			ret = -ENOMEM;
+			goto err;
+		}
 	}
 
 	ourport->clk	= clk_get(&platdev->dev, "uart");
 	if (IS_ERR(ourport->clk)) {
 		pr_err("%s: Controller clock not found\n",
 				dev_name(&platdev->dev));
-		return PTR_ERR(ourport->clk);
+		ret = PTR_ERR(ourport->clk);
+		goto err;
 	}
 
 	ret = clk_prepare_enable(ourport->clk);
 	if (ret) {
 		pr_err("uart: clock failed to prepare+enable: %d\n", ret);
 		clk_put(ourport->clk);
-		return ret;
+		goto err;
 	}
 
 	/* Keep all interrupts masked and cleared */
@@ -1761,7 +1767,12 @@
 
 	/* reset the fifos (and setup the uart) */
 	s3c24xx_serial_resetport(port, cfg);
+
 	return 0;
+
+err:
+	port->mapbase = 0;
+	return ret;
 }
 
 /* Device driver serial port probe */
@@ -1798,6 +1809,10 @@
 
 	dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index);
 
+	if (index >= ARRAY_SIZE(s3c24xx_serial_ports)) {
+		dev_err(&pdev->dev, "serial%d out of range\n", index);
+		return -EINVAL;
+	}
 	ourport = &s3c24xx_serial_ports[index];
 
 	ourport->drv_data = s3c24xx_get_driver_data(pdev);
@@ -1828,8 +1843,6 @@
 	ourport->min_dma_size = max_t(int, ourport->port.fifosize,
 				    dma_get_cache_alignment());
 
-	probe_index++;
-
 	dbg("%s: initialising port %p...\n", __func__, ourport);
 
 	ret = s3c24xx_serial_init_port(ourport, pdev);
@@ -1859,6 +1872,8 @@
 	if (ret < 0)
 		dev_err(&pdev->dev, "failed to add cpufreq notifier\n");
 
+	probe_index++;
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/tty/serial/sc16is7xx.c
+++ linux-4.4.0/drivers/tty/serial/sc16is7xx.c
@@ -332,6 +332,7 @@
 	struct kthread_worker		kworker;
 	struct task_struct		*kworker_task;
 	struct kthread_work		irq_work;
+	struct mutex			efr_lock;
 	struct sc16is7xx_one		p[0];
 };
 
@@ -378,9 +379,7 @@
 	const u8 line = sc16is7xx_line(port);
 	u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | line;
 
-	regcache_cache_bypass(s->regmap, true);
-	regmap_raw_read(s->regmap, addr, s->buf, rxlen);
-	regcache_cache_bypass(s->regmap, false);
+	regmap_noinc_read(s->regmap, addr, s->buf, rxlen);
 }
 
 static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send)
@@ -389,9 +388,7 @@
 	const u8 line = sc16is7xx_line(port);
 	u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line;
 
-	regcache_cache_bypass(s->regmap, true);
-	regmap_raw_write(s->regmap, addr, s->buf, to_send);
-	regcache_cache_bypass(s->regmap, false);
+	regmap_noinc_write(s->regmap, addr, s->buf, to_send);
 }
 
 static void sc16is7xx_port_update(struct uart_port *port, u8 reg,
@@ -484,6 +481,11 @@
 	return false;
 }
 
+static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg)
+{
+	return reg == SC16IS7XX_RHR_REG;
+}
+
 static int sc16is7xx_set_baud(struct uart_port *port, int baud)
 {
 	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
@@ -496,6 +498,21 @@
 		div /= 4;
 	}
 
+	/* In an amazing feat of design, the Enhanced Features Register shares
+	 * the address of the Interrupt Identification Register, and is
+	 * switched in by writing a magic value (0xbf) to the Line Control
+	 * Register. Any interrupt firing during this time will see the EFR
+	 * where it expects the IIR to be, leading to "Unexpected interrupt"
+	 * messages.
+	 *
+	 * Prevent this possibility by claiming a mutex while accessing the
+	 * EFR, and claiming the same mutex from within the interrupt handler.
+	 * This is similar to disabling the interrupt, but that doesn't work
+	 * because the bulk of the interrupt processing is run as a workqueue
+	 * job in thread context.
+	 */
+	mutex_lock(&s->efr_lock);
+
 	lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
 
 	/* Open the LCR divisors for configuration */
@@ -511,6 +528,8 @@
 	/* Put LCR back to the normal mode */
 	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
 
+	mutex_unlock(&s->efr_lock);
+
 	sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
 			      SC16IS7XX_MCR_CLKSEL_BIT,
 			      prescaler);
@@ -648,7 +667,7 @@
 		uart_write_wakeup(port);
 }
 
-static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
+static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
 {
 	struct uart_port *port = &s->p[portno].port;
 
@@ -657,7 +676,7 @@
 
 		iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
 		if (iir & SC16IS7XX_IIR_NO_INT_BIT)
-			break;
+			return false;
 
 		iir &= SC16IS7XX_IIR_ID_MASK;
 
@@ -685,16 +704,27 @@
 					    port->line, iir);
 			break;
 		}
-	} while (1);
+	} while (0);
+	return true;
 }
 
 static void sc16is7xx_ist(struct kthread_work *ws)
 {
 	struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
-	int i;
 
-	for (i = 0; i < s->devtype->nr_uart; ++i)
-		sc16is7xx_port_irq(s, i);
+	mutex_lock(&s->efr_lock);
+
+	while (1) {
+		bool keep_polling = false;
+		int i;
+
+		for (i = 0; i < s->devtype->nr_uart; ++i)
+			keep_polling |= sc16is7xx_port_irq(s, i);
+		if (!keep_polling)
+			break;
+	}
+
+	mutex_unlock(&s->efr_lock);
 }
 
 static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
@@ -881,6 +911,9 @@
 	if (!(termios->c_cflag & CREAD))
 		port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;
 
+	/* As above, claim the mutex while accessing the EFR. */
+	mutex_lock(&s->efr_lock);
+
 	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
 			     SC16IS7XX_LCR_CONF_MODE_B);
 
@@ -902,6 +935,8 @@
 	/* Update LCR register */
 	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
 
+	mutex_unlock(&s->efr_lock);
+
 	/* Get baud rate generator configuration */
 	baud = uart_get_baud_rate(port, termios, old,
 				  port->uartclk / 16 / 4 / 0xffff,
@@ -1165,6 +1200,7 @@
 	s->regmap = regmap;
 	s->devtype = devtype;
 	dev_set_drvdata(dev, s);
+	mutex_init(&s->efr_lock);
 
 	init_kthread_worker(&s->kworker);
 	init_kthread_work(&s->irq_work, sc16is7xx_ist);
@@ -1230,7 +1266,7 @@
 
 	/* Setup interrupt */
 	ret = devm_request_irq(dev, irq, sc16is7xx_irq,
-			       IRQF_ONESHOT | flags, dev_name(dev), s);
+			       flags, dev_name(dev), s);
 	if (!ret)
 		return 0;
 
@@ -1298,6 +1334,8 @@
 	.cache_type = REGCACHE_RBTREE,
 	.volatile_reg = sc16is7xx_regmap_volatile,
 	.precious_reg = sc16is7xx_regmap_precious,
+	.writeable_noinc_reg = sc16is7xx_regmap_noinc,
+	.readable_noinc_reg = sc16is7xx_regmap_noinc,
 };
 
 #ifdef CONFIG_SERIAL_SC16IS7XX_SPI
@@ -1441,7 +1479,7 @@
 	ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver);
 	if (ret < 0) {
 		pr_err("failed to init sc16is7xx i2c --> %d\n", ret);
-		return ret;
+		goto err_i2c;
 	}
 #endif
 
@@ -1449,10 +1487,20 @@
 	ret = spi_register_driver(&sc16is7xx_spi_uart_driver);
 	if (ret < 0) {
 		pr_err("failed to init sc16is7xx spi --> %d\n", ret);
-		return ret;
+		goto err_spi;
 	}
 #endif
 	return ret;
+
+#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
+err_spi:
+#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
+	i2c_del_driver(&sc16is7xx_i2c_uart_driver);
+#endif
+#endif
+err_i2c:
+	uart_unregister_driver(&sc16is7xx_uart);
+	return ret;
 }
 module_init(sc16is7xx_init);
 
--- linux-4.4.0.orig/drivers/tty/serial/sccnxp.c
+++ linux-4.4.0/drivers/tty/serial/sccnxp.c
@@ -884,14 +884,19 @@
 
 	clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(clk)) {
-		if (PTR_ERR(clk) == -EPROBE_DEFER) {
-			ret = -EPROBE_DEFER;
+		ret = PTR_ERR(clk);
+		if (ret == -EPROBE_DEFER)
 			goto err_out;
-		}
+		uartclk = 0;
+	} else {
+		clk_prepare_enable(clk);
+		uartclk = clk_get_rate(clk);
+	}
+
+	if (!uartclk) {
 		dev_notice(&pdev->dev, "Using default clock frequency\n");
 		uartclk = s->chip->freq_std;
-	} else
-		uartclk = clk_get_rate(clk);
+	}
 
 	/* Check input frequency */
 	if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
--- linux-4.4.0.orig/drivers/tty/serial/serial_core.c
+++ linux-4.4.0/drivers/tty/serial/serial_core.c
@@ -768,6 +768,19 @@
 	new_flags = new_info->flags;
 	old_custom_divisor = uport->custom_divisor;
 
+	if ((change_port || change_irq) && secure_modules()) {
+		retval = -EPERM;
+		goto exit;
+	}
+
+	if (!(uport->flags & UPF_FIXED_PORT)) {
+		unsigned int uartclk = new_info->baud_base * 16;
+		/* check needs to be done here before other settings made */
+		if (uartclk == 0) {
+			retval = -EINVAL;
+			goto exit;
+		}
+	}
 	if (!capable(CAP_SYS_ADMIN)) {
 		retval = -EPERM;
 		if (change_irq || change_port ||
@@ -1015,7 +1028,7 @@
 
 	mutex_lock(&port->mutex);
 
-	if (uport->type != PORT_UNKNOWN)
+	if (uport->type != PORT_UNKNOWN && uport->ops->break_ctl)
 		uport->ops->break_ctl(uport, break_state);
 
 	mutex_unlock(&port->mutex);
@@ -2702,6 +2715,7 @@
 	if (uport->cons && uport->dev)
 		of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
 
+	tty_port_link_device(port, drv->tty_driver, uport->line);
 	uart_configure_port(drv, state, uport);
 
 	num_groups = 2;
--- linux-4.4.0.orig/drivers/tty/serial/serial_mctrl_gpio.c
+++ linux-4.4.0/drivers/tty/serial/serial_mctrl_gpio.c
@@ -20,6 +20,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/termios.h>
 #include <linux/serial_core.h>
+#include <linux/module.h>
 
 #include "serial_mctrl_gpio.h"
 
@@ -66,6 +67,9 @@
 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
 				      enum mctrl_gpio_idx gidx)
 {
+	if (gpios == NULL)
+		return NULL;
+
 	return gpios->gpio[gidx];
 }
 EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
@@ -193,6 +197,7 @@
 
 	return gpios;
 }
+EXPORT_SYMBOL_GPL(mctrl_gpio_init);
 
 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
 {
@@ -247,3 +252,6 @@
 		disable_irq(gpios->irq[i]);
 	}
 }
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
+
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/tty/serial/serial_txx9.c
+++ linux-4.4.0/drivers/tty/serial/serial_txx9.c
@@ -1287,6 +1287,9 @@
 
 #ifdef ENABLE_SERIAL_TXX9_PCI
 	ret = pci_register_driver(&serial_txx9_pci_driver);
+	if (ret) {
+		platform_driver_unregister(&serial_txx9_plat_driver);
+	}
 #endif
 	if (ret == 0)
 		goto out;
--- linux-4.4.0.orig/drivers/tty/serial/sh-sci.c
+++ linux-4.4.0/drivers/tty/serial/sh-sci.c
@@ -38,7 +38,6 @@
 #include <linux/major.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -116,8 +115,6 @@
 	struct timer_list		rx_timer;
 	unsigned int			rx_timeout;
 #endif
-
-	struct notifier_block		freq_transition;
 };
 
 #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
@@ -166,18 +163,17 @@
 	},
 
 	/*
-	 * Common definitions for legacy IrDA ports, dependent on
-	 * regshift value.
+	 * Common definitions for legacy IrDA ports.
 	 */
 	[SCIx_IRDA_REGTYPE] = {
 		[SCSMR]		= { 0x00,  8 },
-		[SCBRR]		= { 0x01,  8 },
-		[SCSCR]		= { 0x02,  8 },
-		[SCxTDR]	= { 0x03,  8 },
-		[SCxSR]		= { 0x04,  8 },
-		[SCxRDR]	= { 0x05,  8 },
-		[SCFCR]		= { 0x06,  8 },
-		[SCFDR]		= { 0x07, 16 },
+		[SCBRR]		= { 0x02,  8 },
+		[SCSCR]		= { 0x04,  8 },
+		[SCxTDR]	= { 0x06,  8 },
+		[SCxSR]		= { 0x08, 16 },
+		[SCxRDR]	= { 0x0a,  8 },
+		[SCFCR]		= { 0x0c,  8 },
+		[SCFDR]		= { 0x0e, 16 },
 		[SCTFDR]	= sci_reg_invalid,
 		[SCRFDR]	= sci_reg_invalid,
 		[SCSPTR]	= sci_reg_invalid,
@@ -750,19 +746,9 @@
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(port);
-	if (uart_circ_empty(xmit)) {
+	if (uart_circ_empty(xmit))
 		sci_stop_tx(port);
-	} else {
-		ctrl = serial_port_in(port, SCSCR);
-
-		if (port->type != PORT_SCI) {
-			serial_port_in(port, SCxSR); /* Dummy read */
-			sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
-		}
 
-		ctrl |= SCSCR_TIE;
-		serial_port_out(port, SCSCR, ctrl);
-	}
 }
 
 /* On SH3, SCIF may read end-of-break as a space->mark char */
@@ -851,6 +837,8 @@
 		/* Tell the rest of the system the news. New characters! */
 		tty_flip_buffer_push(tport);
 	} else {
+		/* TTY buffers full; read from RX reg to prevent lockup */
+		serial_port_in(port, SCxRDR);
 		serial_port_in(port, SCxSR); /* dummy read */
 		sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
 	}
@@ -1215,6 +1203,7 @@
 	struct uart_port *port = &s->port;
 	struct circ_buf *xmit = &port->state->xmit;
 	dma_addr_t buf;
+	int head, tail;
 
 	/*
 	 * DMA is idle now.
@@ -1224,16 +1213,23 @@
 	 * consistent xmit buffer state.
 	 */
 	spin_lock_irq(&port->lock);
-	buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1));
+	head = xmit->head;
+	tail = xmit->tail;
+	buf = s->tx_dma_addr + (tail & (UART_XMIT_SIZE - 1));
 	s->tx_dma_len = min_t(unsigned int,
-		CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
-		CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
-	spin_unlock_irq(&port->lock);
+		CIRC_CNT(head, tail, UART_XMIT_SIZE),
+		CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE));
+	if (!s->tx_dma_len) {
+		/* Transmit buffer has been flushed */
+		spin_unlock_irq(&port->lock);
+		return;
+	}
 
 	desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len,
 					   DMA_MEM_TO_DEV,
 					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
+		spin_unlock_irq(&port->lock);
 		dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
 		/* switch to PIO */
 		sci_tx_dma_release(s, true);
@@ -1243,20 +1239,20 @@
 	dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
 				   DMA_TO_DEVICE);
 
-	spin_lock_irq(&port->lock);
 	desc->callback = sci_dma_tx_complete;
 	desc->callback_param = s;
-	spin_unlock_irq(&port->lock);
 	s->cookie_tx = dmaengine_submit(desc);
 	if (dma_submit_error(s->cookie_tx)) {
+		spin_unlock_irq(&port->lock);
 		dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
 		/* switch to PIO */
 		sci_tx_dma_release(s, true);
 		return;
 	}
 
+	spin_unlock_irq(&port->lock);
 	dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
-		__func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+		__func__, xmit->buf, tail, head, s->cookie_tx);
 
 	dma_async_issue_pending(chan);
 }
@@ -1459,7 +1455,16 @@
 	if (s->chan_rx)
 		sci_rx_dma_release(s, false);
 }
-#else
+
+static void sci_flush_buffer(struct uart_port *port)
+{
+	/*
+	 * In uart_flush_buffer(), the xmit circular buffer has just been
+	 * cleared, so we have to reset tx_dma_len accordingly.
+	 */
+	to_sci_port(port)->tx_dma_len = 0;
+}
+#else /* !CONFIG_SERIAL_SH_SCI_DMA */
 static inline void sci_request_dma(struct uart_port *port)
 {
 }
@@ -1467,7 +1472,9 @@
 static inline void sci_free_dma(struct uart_port *port)
 {
 }
-#endif
+
+#define sci_flush_buffer	NULL
+#endif /* !CONFIG_SERIAL_SH_SCI_DMA */
 
 static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
 {
@@ -1606,29 +1613,6 @@
 	return ret;
 }
 
-/*
- * Here we define a transition notifier so that we can update all of our
- * ports' baud rate when the peripheral clock changes.
- */
-static int sci_notifier(struct notifier_block *self,
-			unsigned long phase, void *p)
-{
-	struct sci_port *sci_port;
-	unsigned long flags;
-
-	sci_port = container_of(self, struct sci_port, freq_transition);
-
-	if (phase == CPUFREQ_POSTCHANGE) {
-		struct uart_port *port = &sci_port->port;
-
-		spin_lock_irqsave(&port->lock, flags);
-		port->uartclk = clk_get_rate(sci_port->iclk);
-		spin_unlock_irqrestore(&port->lock, flags);
-	}
-
-	return NOTIFY_OK;
-}
-
 static const struct sci_irq_desc {
 	const char	*desc;
 	irq_handler_t	handler;
@@ -1826,11 +1810,13 @@
 
 	dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
 
+	sci_request_dma(port);
+
 	ret = sci_request_irq(s);
-	if (unlikely(ret < 0))
+	if (unlikely(ret < 0)) {
+		sci_free_dma(port);
 		return ret;
-
-	sci_request_dma(port);
+	}
 
 	spin_lock_irqsave(&port->lock, flags);
 	sci_start_tx(port);
@@ -1860,8 +1846,8 @@
 	}
 #endif
 
-	sci_free_dma(port);
 	sci_free_irq(s);
+	sci_free_dma(port);
 }
 
 static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
@@ -2228,6 +2214,7 @@
 	.break_ctl	= sci_break_ctl,
 	.startup	= sci_startup,
 	.shutdown	= sci_shutdown,
+	.flush_buffer	= sci_flush_buffer,
 	.set_termios	= sci_set_termios,
 	.pm		= sci_pm,
 	.type		= sci_type,
@@ -2430,13 +2417,12 @@
 	unsigned long flags;
 	int locked = 1;
 
-	local_irq_save(flags);
 	if (port->sysrq)
 		locked = 0;
 	else if (oops_in_progress)
-		locked = spin_trylock(&port->lock);
+		locked = spin_trylock_irqsave(&port->lock, flags);
 	else
-		spin_lock(&port->lock);
+		spin_lock_irqsave(&port->lock, flags);
 
 	/* first save the SCSCR then disable the interrupts */
 	ctrl = serial_port_in(port, SCSCR);
@@ -2453,8 +2439,7 @@
 	serial_port_out(port, SCSCR, ctrl);
 
 	if (locked)
-		spin_unlock(&port->lock);
-	local_irq_restore(flags);
+		spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static int serial_console_setup(struct console *co, char *options)
@@ -2559,9 +2544,6 @@
 {
 	struct sci_port *port = platform_get_drvdata(dev);
 
-	cpufreq_unregister_notifier(&port->freq_transition,
-				    CPUFREQ_TRANSITION_NOTIFIER);
-
 	uart_remove_one_port(&sci_uart_driver, &port->port);
 
 	sci_cleanup_single(port);
@@ -2714,16 +2696,6 @@
 	if (ret)
 		return ret;
 
-	sp->freq_transition.notifier_call = sci_notifier;
-
-	ret = cpufreq_register_notifier(&sp->freq_transition,
-					CPUFREQ_TRANSITION_NOTIFIER);
-	if (unlikely(ret < 0)) {
-		uart_remove_one_port(&sci_uart_driver, &sp->port);
-		sci_cleanup_single(sp);
-		return ret;
-	}
-
 #ifdef CONFIG_SH_STANDARD_BIOS
 	sh_bios_gdb_detach();
 #endif
--- linux-4.4.0.orig/drivers/tty/serial/sprd_serial.c
+++ linux-4.4.0/drivers/tty/serial/sprd_serial.c
@@ -36,7 +36,7 @@
 #define SPRD_FIFO_SIZE		128
 #define SPRD_DEF_RATE		26000000
 #define SPRD_BAUD_IO_LIMIT	3000000
-#define SPRD_TIMEOUT		256
+#define SPRD_TIMEOUT		256000
 
 /* the offset of serial registers and BITs for them */
 /* data registers */
@@ -63,6 +63,7 @@
 
 /* interrupt clear register */
 #define SPRD_ICLR		0x0014
+#define SPRD_ICLR_TIMEOUT	BIT(13)
 
 /* line control register */
 #define SPRD_LCR		0x0018
@@ -239,7 +240,7 @@
 
 		if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
 			SPRD_LSR_FE | SPRD_LSR_OE))
-			if (handle_lsr_errors(port, &lsr, &flag))
+			if (handle_lsr_errors(port, &flag, &lsr))
 				continue;
 		if (uart_handle_sysrq_char(port, ch))
 			continue;
@@ -298,7 +299,8 @@
 		return IRQ_NONE;
 	}
 
-	serial_out(port, SPRD_ICLR, ~0);
+	if (ims & SPRD_IMSR_TIMEOUT)
+		serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT);
 
 	if (ims & (SPRD_IMSR_RX_FIFO_FULL |
 		SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
@@ -731,8 +733,8 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(&pdev->dev, "not provide irq resource\n");
-		return -ENODEV;
+		dev_err(&pdev->dev, "not provide irq resource: %d\n", irq);
+		return irq;
 	}
 	up->irq = irq;
 
--- linux-4.4.0.orig/drivers/tty/serial/suncore.c
+++ linux-4.4.0/drivers/tty/serial/suncore.c
@@ -111,6 +111,7 @@
 		mode = of_get_property(dp, mode_prop, NULL);
 		if (!mode)
 			mode = "9600,8,n,1,-";
+		of_node_put(dp);
 	}
 
 	cflag = CREAD | HUPCL | CLOCAL;
--- linux-4.4.0.orig/drivers/tty/serial/sunhv.c
+++ linux-4.4.0/drivers/tty/serial/sunhv.c
@@ -392,12 +392,18 @@
 static struct uart_driver sunhv_reg = {
 	.owner			= THIS_MODULE,
 	.driver_name		= "sunhv",
-	.dev_name		= "ttyS",
+	.dev_name		= "ttyHV",
 	.major			= TTY_MAJOR,
 };
 
 static struct uart_port *sunhv_port;
 
+void sunhv_migrate_hvcons_irq(int cpu)
+{
+	/* Migrate hvcons irq to param cpu */
+	irq_force_affinity(sunhv_port->irq, cpumask_of(cpu));
+}
+
 /* Copy 's' into the con_write_page, decoding "\n" into
  * "\r\n" along the way.  We have to return two lengths
  * because the caller needs to know how much to advance
@@ -490,12 +496,6 @@
 		locked = spin_trylock_irqsave(&port->lock, flags);
 	else
 		spin_lock_irqsave(&port->lock, flags);
-	if (port->sysrq) {
-		locked = 0;
-	} else if (oops_in_progress) {
-		locked = spin_trylock(&port->lock);
-	} else
-		spin_lock(&port->lock);
 
 	for (i = 0; i < n; i++) {
 		if (*s == '\n')
--- linux-4.4.0.orig/drivers/tty/serial/uartlite.c
+++ linux-4.4.0/drivers/tty/serial/uartlite.c
@@ -701,7 +701,8 @@
 static void __exit ulite_exit(void)
 {
 	platform_driver_unregister(&ulite_platform_driver);
-	uart_unregister_driver(&ulite_uart_driver);
+	if (ulite_uart_driver.state)
+		uart_unregister_driver(&ulite_uart_driver);
 }
 
 module_init(ulite_init);
--- linux-4.4.0.orig/drivers/tty/serial/ucc_uart.c
+++ linux-4.4.0/drivers/tty/serial/ucc_uart.c
@@ -1478,6 +1478,9 @@
 		.type = "serial",
 		.compatible = "ucc_uart",
 	},
+	{
+		.compatible = "fsl,t1040-ucc-uart",
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, ucc_uart_match);
--- linux-4.4.0.orig/drivers/tty/serial/xilinx_uartps.c
+++ linux-4.4.0/drivers/tty/serial/xilinx_uartps.c
@@ -1026,7 +1026,7 @@
 	struct uart_port *port;
 
 	/* Try the given port id if failed use default method */
-	if (cdns_uart_port[id].mapbase != 0) {
+	if (id < CDNS_UART_NR_PORTS && cdns_uart_port[id].mapbase != 0) {
 		/* Find the next unused port */
 		for (id = 0; id < CDNS_UART_NR_PORTS; id++)
 			if (cdns_uart_port[id].mapbase == 0)
@@ -1145,7 +1145,7 @@
  *
  * Return: 0 on success, negative errno otherwise.
  */
-static int __init cdns_uart_console_setup(struct console *co, char *options)
+static int cdns_uart_console_setup(struct console *co, char *options)
 {
 	struct uart_port *port = &cdns_uart_port[co->index];
 	int baud = 9600;
--- linux-4.4.0.orig/drivers/tty/synclink.c
+++ linux-4.4.0/drivers/tty/synclink.c
@@ -869,9 +869,9 @@
 	
 module_param(break_on_load, bool, 0);
 module_param(ttymajor, int, 0);
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(dma, int, NULL, 0);
+module_param_hw_array(io, int, ioport, NULL, 0);
+module_param_hw_array(irq, int, irq, NULL, 0);
+module_param_hw_array(dma, int, dma, NULL, 0);
 module_param(debug_level, int, 0);
 module_param_array(maxframe, int, NULL, 0);
 module_param_array(txdmabufs, int, NULL, 0);
--- linux-4.4.0.orig/drivers/tty/synclink_gt.c
+++ linux-4.4.0/drivers/tty/synclink_gt.c
@@ -1192,14 +1192,13 @@
 			 unsigned int cmd, unsigned long arg)
 {
 	struct slgt_info *info = tty->driver_data;
-	int rc = -ENOIOCTLCMD;
+	int rc;
 
 	if (sanity_check(info, tty->name, "compat_ioctl"))
 		return -ENODEV;
 	DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
 
 	switch (cmd) {
-
 	case MGSL_IOCSPARAMS32:
 		rc = set_params32(info, compat_ptr(arg));
 		break;
@@ -1219,18 +1218,11 @@
 	case MGSL_IOCWAITGPIO:
 	case MGSL_IOCGXSYNC:
 	case MGSL_IOCGXCTRL:
-	case MGSL_IOCSTXIDLE:
-	case MGSL_IOCTXENABLE:
-	case MGSL_IOCRXENABLE:
-	case MGSL_IOCTXABORT:
-	case TIOCMIWAIT:
-	case MGSL_IOCSIF:
-	case MGSL_IOCSXSYNC:
-	case MGSL_IOCSXCTRL:
-		rc = ioctl(tty, cmd, arg);
+		rc = ioctl(tty, cmd, (unsigned long)compat_ptr(arg));
 		break;
+	default:
+		rc = ioctl(tty, cmd, arg);
 	}
-
 	DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
 	return rc;
 }
--- linux-4.4.0.orig/drivers/tty/sysrq.c
+++ linux-4.4.0/drivers/tty/sysrq.c
@@ -133,6 +133,12 @@
 {
 	char *killer = NULL;
 
+	/* we need to release the RCU read lock here,
+	 * otherwise we get an annoying
+	 * 'BUG: sleeping function called from invalid context'
+	 * complaint from the kernel before the panic.
+	 */
+	rcu_read_unlock();
 	panic_on_oops = 1;	/* force panic */
 	wmb();
 	*killer = 1;
@@ -237,8 +243,10 @@
 	 * architecture has no support for it:
 	 */
 	if (!trigger_all_cpu_backtrace()) {
-		struct pt_regs *regs = get_irq_regs();
+		struct pt_regs *regs = NULL;
 
+		if (in_irq())
+			regs = get_irq_regs();
 		if (regs) {
 			pr_info("CPU%d:\n", smp_processor_id());
 			show_regs(regs);
@@ -257,7 +265,10 @@
 
 static void sysrq_handle_showregs(int key)
 {
-	struct pt_regs *regs = get_irq_regs();
+	struct pt_regs *regs = NULL;
+
+	if (in_irq())
+		regs = get_irq_regs();
 	if (regs)
 		show_regs(regs);
 	perf_event_print_debug();
@@ -531,7 +542,6 @@
 	 */
 	orig_log_level = console_loglevel;
 	console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
-	pr_info("SysRq : ");
 
         op_p = __sysrq_get_key_op(key);
         if (op_p) {
@@ -540,14 +550,15 @@
 		 * should not) and is the invoked operation enabled?
 		 */
 		if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
-			pr_cont("%s\n", op_p->action_msg);
+			pr_info("%s\n", op_p->action_msg);
 			console_loglevel = orig_log_level;
 			op_p->handler(key);
 		} else {
-			pr_cont("This sysrq operation is disabled.\n");
+			pr_info("This sysrq operation is disabled.\n");
+			console_loglevel = orig_log_level;
 		}
 	} else {
-		pr_cont("HELP : ");
+		pr_info("HELP : ");
 		/* Only print the help msg once per handler */
 		for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
 			if (sysrq_key_table[i]) {
@@ -939,8 +950,8 @@
 	{
 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
 				INPUT_DEVICE_ID_MATCH_KEYBIT,
-		.evbit = { BIT_MASK(EV_KEY) },
-		.keybit = { BIT_MASK(KEY_LEFTALT) },
+		.evbit = { [BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY) },
+		.keybit = { [BIT_WORD(KEY_LEFTALT)] = BIT_MASK(KEY_LEFTALT) },
 	},
 	{ },
 };
--- linux-4.4.0.orig/drivers/tty/tty_buffer.c
+++ linux-4.4.0/drivers/tty/tty_buffer.c
@@ -25,7 +25,7 @@
  * Byte threshold to limit memory consumption for flip buffers.
  * The actual memory limit is > 2x this amount.
  */
-#define TTYB_DEFAULT_MEM_LIMIT	65536
+#define TTYB_DEFAULT_MEM_LIMIT	(640 * 1024UL)
 
 /*
  * We default to dicing tty buffer allocations to this many characters
@@ -37,29 +37,6 @@
 
 #define TTY_BUFFER_PAGE	(((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
 
-/*
- * If all tty flip buffers have been processed by flush_to_ldisc() or
- * dropped by tty_buffer_flush(), check if the linked pty has been closed.
- * If so, wake the reader/poll to process
- */
-static inline void check_other_closed(struct tty_struct *tty)
-{
-	unsigned long flags, old;
-
-	/* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */
-	for (flags = ACCESS_ONCE(tty->flags);
-	     test_bit(TTY_OTHER_CLOSED, &flags);
-	     ) {
-		old = flags;
-		__set_bit(TTY_OTHER_DONE, &flags);
-		flags = cmpxchg(&tty->flags, old, flags);
-		if (old == flags) {
-			wake_up_interruptible(&tty->read_wait);
-			break;
-		}
-	}
-}
-
 /**
  *	tty_buffer_lock_exclusive	-	gain exclusive access to buffer
  *	tty_buffer_unlock_exclusive	-	release exclusive access
@@ -189,7 +166,8 @@
 	   have queued and recycle that ? */
 	if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)
 		return NULL;
-	p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+	p = kmalloc(sizeof(struct tty_buffer) + 2 * size,
+		    GFP_ATOMIC | __GFP_NOWARN);
 	if (p == NULL)
 		return NULL;
 
@@ -254,8 +232,6 @@
 	if (ld && ld->ops->flush_buffer)
 		ld->ops->flush_buffer(tty);
 
-	check_other_closed(tty);
-
 	atomic_dec(&buf->priority);
 	mutex_unlock(&buf->lock);
 }
@@ -387,6 +363,41 @@
 EXPORT_SYMBOL(tty_insert_flip_string_flags);
 
 /**
+ *	__tty_insert_flip_char   -	Add one character to the tty buffer
+ *	@port: tty port
+ *	@ch: character
+ *	@flag: flag byte
+ *
+ *	Queue a single byte to the tty buffering, with an optional flag.
+ *	This is the slow path of tty_insert_flip_char.
+ */
+int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag)
+{
+	struct tty_buffer *tb;
+	int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
+
+	if (!__tty_buffer_request_room(port, 1, flags))
+		return 0;
+
+	tb = port->buf.tail;
+	if (~tb->flags & TTYB_NORMAL)
+		*flag_buf_ptr(tb, tb->used) = flag;
+	*char_buf_ptr(tb, tb->used++) = ch;
+
+	return 1;
+}
+EXPORT_SYMBOL(__tty_insert_flip_char);
+
+static inline void tty_flip_buffer_commit(struct tty_buffer *tail)
+{
+	/*
+	 * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
+	 * buffer data.
+	 */
+	smp_store_release(&tail->commit, tail->used);
+}
+
+/**
  *	tty_schedule_flip	-	push characters to ldisc
  *	@port: tty port to push from
  *
@@ -399,10 +410,7 @@
 {
 	struct tty_bufhead *buf = &port->buf;
 
-	/* paired w/ acquire in flush_to_ldisc(); ensures
-	 * flush_to_ldisc() sees buffer data.
-	 */
-	smp_store_release(&buf->tail->commit, buf->tail->used);
+	tty_flip_buffer_commit(buf->tail);
 	queue_work(system_unbound_wq, &buf->work);
 }
 EXPORT_SYMBOL(tty_schedule_flip);
@@ -453,6 +461,8 @@
 		if (count && disc->ops->receive_buf)
 			disc->ops->receive_buf(tty, p, f, count);
 	}
+	if (count > 0)
+		memset(p, 0, count);
 	return count;
 }
 
@@ -505,10 +515,8 @@
 		 */
 		count = smp_load_acquire(&head->commit) - head->read;
 		if (!count) {
-			if (next == NULL) {
-				check_other_closed(tty);
+			if (next == NULL)
 				break;
-			}
 			buf->head = next;
 			tty_buffer_free(port, head);
 			continue;
@@ -543,6 +551,37 @@
 EXPORT_SYMBOL(tty_flip_buffer_push);
 
 /**
+ * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and
+ *	push
+ * @port: tty port
+ * @chars: characters
+ * @size: size
+ *
+ * The function combines tty_insert_flip_string() and tty_flip_buffer_push()
+ * with the exception of properly holding the @port->lock.
+ *
+ * To be used only internally (by pty currently).
+ *
+ * Returns: the number added.
+ */
+int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
+		const unsigned char *chars, size_t size)
+{
+	struct tty_bufhead *buf = &port->buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	size = tty_insert_flip_string(port, chars, size);
+	if (size)
+		tty_flip_buffer_commit(buf->tail);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	queue_work(system_unbound_wq, &buf->work);
+
+	return size;
+}
+
+/**
  *	tty_buffer_init		-	prepare a tty buffer structure
  *	@tty: tty to initialise
  *
@@ -597,3 +636,8 @@
 {
 	return cancel_work_sync(&port->buf.work);
 }
+
+void tty_buffer_flush_work(struct tty_port *port)
+{
+	flush_work(&port->buf.work);
+}
--- linux-4.4.0.orig/drivers/tty/tty_io.c
+++ linux-4.4.0/drivers/tty/tty_io.c
@@ -357,7 +357,7 @@
 	mutex_lock(&tty_mutex);
 	/* Search through the tty devices to look for a match */
 	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		if (strncmp(name, p->name, len) != 0)
+		if (!len || strncmp(name, p->name, len) != 0)
 			continue;
 		stp = str;
 		if (*stp == ',')
@@ -513,6 +513,8 @@
 	tty_kref_put(tty);
 }
 
+extern void tty_sysctl_init(void);
+
 /**
  * proc_set_tty -  set the controlling terminal
  *
@@ -535,8 +537,8 @@
 	put_pid(tty->session);
 	put_pid(tty->pgrp);
 	tty->pgrp = get_pid(task_pgrp(current));
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 	tty->session = get_pid(task_session(current));
+	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 	if (current->signal->tty) {
 		tty_debug(tty, "current tty %s not NULL!!\n",
 			  current->signal->tty->name);
@@ -702,6 +704,14 @@
 		return;
 	}
 
+	/*
+	 * Some console devices aren't actually hung up for technical and
+	 * historical reasons, which can lead to indefinite interruptible
+	 * sleep in n_tty_read().  The following explicitly tells
+	 * n_tty_read() to abort readers.
+	 */
+	set_bit(TTY_HUPPING, &tty->flags);
+
 	/* inuse_filps is protected by the single tty lock,
 	   this really needs to change if we want to flush the
 	   workqueue with the lock held */
@@ -726,7 +736,7 @@
 	while (refs--)
 		tty_kref_put(tty);
 
-	tty_ldisc_hangup(tty);
+	tty_ldisc_hangup(tty, cons_filp != NULL);
 
 	spin_lock_irq(&tty->ctrl_lock);
 	clear_bit(TTY_THROTTLED, &tty->flags);
@@ -751,12 +761,12 @@
 	} else if (tty->ops->hangup)
 		tty->ops->hangup(tty);
 	/*
-	 * We don't want to have driver/ldisc interactions beyond
-	 * the ones we did here. The driver layer expects no
-	 * calls after ->hangup() from the ldisc side. However we
-	 * can't yet guarantee all that.
+	 * We don't want to have driver/ldisc interactions beyond the ones
+	 * we did here. The driver layer expects no calls after ->hangup()
+	 * from the ldisc side, which is now guaranteed.
 	 */
 	set_bit(TTY_HUPPED, &tty->flags);
+	clear_bit(TTY_HUPPING, &tty->flags);
 	tty_unlock(tty);
 
 	if (f)
@@ -918,21 +928,24 @@
 	spin_lock_irq(&current->sighand->siglock);
 	put_pid(current->signal->tty_old_pgrp);
 	current->signal->tty_old_pgrp = NULL;
-
 	tty = tty_kref_get(current->signal->tty);
+	spin_unlock_irq(&current->sighand->siglock);
+
 	if (tty) {
 		unsigned long flags;
+
+		tty_lock(tty);
 		spin_lock_irqsave(&tty->ctrl_lock, flags);
 		put_pid(tty->session);
 		put_pid(tty->pgrp);
 		tty->session = NULL;
 		tty->pgrp = NULL;
 		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+		tty_unlock(tty);
 		tty_kref_put(tty);
 	} else
 		tty_debug_hangup(tty, "no current tty\n");
 
-	spin_unlock_irq(&current->sighand->siglock);
 	/* Now clear signal->tty under the lock */
 	read_lock(&tasklist_lock);
 	session_clear_tty(task_session(current));
@@ -1067,6 +1080,8 @@
 	/* We want to wait for the line discipline to sort out in this
 	   situation */
 	ld = tty_ldisc_ref_wait(tty);
+	if (!ld)
+		return hung_up_tty_read(file, buf, count, ppos);
 	if (ld->ops->read)
 		i = ld->ops->read(tty, file, buf, count);
 	else
@@ -1242,6 +1257,8 @@
 		printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
 			tty->driver->name);
 	ld = tty_ldisc_ref_wait(tty);
+	if (!ld)
+		return hung_up_tty_write(file, buf, count, ppos);
 	if (!ld->ops->write)
 		ret = -EIO;
 	else
@@ -1387,9 +1404,10 @@
 	else {
 		/* Check for lazy saved data */
 		tp = tty->driver->termios[idx];
-		if (tp != NULL)
+		if (tp != NULL) {
 			tty->termios = *tp;
-		else
+			tty->termios.c_line  = tty->driver->init_termios.c_line;
+		} else
 			tty->termios = tty->driver->init_termios;
 	}
 	/* Compatibility until drivers always set this */
@@ -1461,22 +1479,36 @@
 static int tty_reopen(struct tty_struct *tty)
 {
 	struct tty_driver *driver = tty->driver;
-
-	if (!tty->count)
-		return -EIO;
+	struct tty_ldisc *ld;
+	int retval = 0;
 
 	if (driver->type == TTY_DRIVER_TYPE_PTY &&
 	    driver->subtype == PTY_TYPE_MASTER)
 		return -EIO;
 
+	if (!tty->count)
+		return -EAGAIN;
+
 	if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
 		return -EBUSY;
 
-	tty->count++;
+	ld = tty_ldisc_ref_wait(tty);
+	if (ld) {
+		tty_ldisc_deref(ld);
+	} else {
+		retval = tty_ldisc_lock(tty, 5 * HZ);
+		if (retval)
+			return retval;
 
-	WARN_ON(!tty->ldisc);
+		if (!tty->ldisc)
+			retval = tty_ldisc_reinit(tty, tty->termios.c_line);
+		tty_ldisc_unlock(tty);
+	}
 
-	return 0;
+	if (retval == 0)
+		tty->count++;
+
+	return retval;
 }
 
 /**
@@ -1537,6 +1569,9 @@
 			"%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
 			__func__, tty->driver->name);
 
+	retval = tty_ldisc_lock(tty, 5 * HZ);
+	if (retval)
+		goto err_release_lock;
 	tty->port->itty = tty;
 
 	/*
@@ -1547,6 +1582,7 @@
 	retval = tty_ldisc_setup(tty, tty->link);
 	if (retval)
 		goto err_release_tty;
+	tty_ldisc_unlock(tty);
 	/* Return the tty locked so that it cannot vanish under the caller */
 	return tty;
 
@@ -1561,8 +1597,11 @@
 	/* call the tty release_tty routine to clean out this slot */
 err_release_tty:
 	tty_unlock(tty);
+	tty_ldisc_unlock(tty);
 	printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
 				 "clearing slot %d\n", idx);
+err_release_lock:
+	tty_unlock(tty);
 	release_tty(tty, idx);
 	return ERR_PTR(retval);
 }
@@ -1694,6 +1733,8 @@
 	if (tty->link)
 		tty->link->port->itty = NULL;
 	tty_buffer_cancel_work(tty->port);
+	if (tty->link)
+		tty_buffer_cancel_work(tty->link->port);
 
 	tty_kref_put(tty->link);
 	tty_kref_put(tty);
@@ -2069,9 +2110,13 @@
 
 		if (tty) {
 			mutex_unlock(&tty_mutex);
-			tty_lock(tty);
-			/* safe to drop the kref from tty_driver_lookup_tty() */
-			tty_kref_put(tty);
+			retval = tty_lock_interruptible(tty);
+			tty_kref_put(tty);  /* drop kref from tty_driver_lookup_tty() */
+			if (retval) {
+				if (retval == -EINTR)
+					retval = -ERESTARTSYS;
+				goto err_unref;
+			}
 			retval = tty_reopen(tty);
 			if (retval < 0) {
 				tty_unlock(tty);
@@ -2087,7 +2132,11 @@
 
 	if (IS_ERR(tty)) {
 		retval = PTR_ERR(tty);
-		goto err_file;
+		if (retval != -EAGAIN || signal_pending(current))
+			goto err_file;
+		tty_free_file(filp);
+		schedule();
+		goto retry_open;
 	}
 
 	tty_add_file(tty, filp);
@@ -2156,6 +2205,7 @@
 	return 0;
 err_unlock:
 	mutex_unlock(&tty_mutex);
+err_unref:
 	/* after locks to avoid deadlock */
 	if (!IS_ERR_OR_NULL(driver))
 		tty_driver_kref_put(driver);
@@ -2188,6 +2238,8 @@
 		return 0;
 
 	ld = tty_ldisc_ref_wait(tty);
+	if (!ld)
+		return hung_up_tty_poll(filp, wait);
 	if (ld->ops->poll)
 		ret = ld->ops->poll(tty, filp, wait);
 	tty_ldisc_deref(ld);
@@ -2277,7 +2329,10 @@
 		return -EFAULT;
 	tty_audit_tiocsti(tty, ch);
 	ld = tty_ldisc_ref_wait(tty);
-	ld->ops->receive_buf(tty, &ch, &mbz, 1);
+	if (!ld)
+		return -EIO;
+	if (ld->ops->receive_buf)
+		ld->ops->receive_buf(tty, &ch, &mbz, 1);
 	tty_ldisc_deref(ld);
 	return 0;
 }
@@ -2578,14 +2633,19 @@
 		return -ENOTTY;
 	if (retval)
 		return retval;
-	if (!current->signal->tty ||
-	    (current->signal->tty != real_tty) ||
-	    (real_tty->session != task_session(current)))
-		return -ENOTTY;
+
 	if (get_user(pgrp_nr, p))
 		return -EFAULT;
 	if (pgrp_nr < 0)
 		return -EINVAL;
+
+	spin_lock_irq(&real_tty->ctrl_lock);
+	if (!current->signal->tty ||
+	    (current->signal->tty != real_tty) ||
+	    (real_tty->session != task_session(current))) {
+		retval = -ENOTTY;
+		goto out_unlock_ctrl;
+	}
 	rcu_read_lock();
 	pgrp = find_vpid(pgrp_nr);
 	retval = -ESRCH;
@@ -2595,12 +2655,12 @@
 	if (session_of_pgrp(pgrp) != task_session(current))
 		goto out_unlock;
 	retval = 0;
-	spin_lock_irq(&tty->ctrl_lock);
 	put_pid(real_tty->pgrp);
 	real_tty->pgrp = get_pid(pgrp);
-	spin_unlock_irq(&tty->ctrl_lock);
 out_unlock:
 	rcu_read_unlock();
+out_unlock_ctrl:
+	spin_unlock_irq(&real_tty->ctrl_lock);
 	return retval;
 }
 
@@ -2612,21 +2672,31 @@
  *
  *	Obtain the session id of the tty. If there is no session
  *	return an error.
- *
- *	Locking: none. Reference to current->signal->tty is safe.
  */
 
 static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
 {
+	unsigned long flags;
+	pid_t sid;
+
 	/*
 	 * (tty == real_tty) is a cheap way of
 	 * testing if the tty is NOT a master pty.
 	*/
 	if (tty == real_tty && current->signal->tty != real_tty)
 		return -ENOTTY;
+
+	spin_lock_irqsave(&real_tty->ctrl_lock, flags);
 	if (!real_tty->session)
-		return -ENOTTY;
-	return put_user(pid_vnr(real_tty->session), p);
+		goto err;
+	sid = pid_vnr(real_tty->session);
+	spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
+
+	return put_user(sid, p);
+
+err:
+	spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
+	return -ENOTTY;
 }
 
 /**
@@ -2641,14 +2711,38 @@
 
 static int tiocsetd(struct tty_struct *tty, int __user *p)
 {
-	int ldisc;
+	int disc;
 	int ret;
 
-	if (get_user(ldisc, p))
+	if (get_user(disc, p))
 		return -EFAULT;
 
-	ret = tty_set_ldisc(tty, ldisc);
+	ret = tty_set_ldisc(tty, disc);
+
+	return ret;
+}
+
+/**
+ *	tiocgetd	-	get line discipline
+ *	@tty: tty device
+ *	@p: pointer to user data
+ *
+ *	Retrieves the line discipline id directly from the ldisc.
+ *
+ *	Locking: waits for ldisc reference (in case the line discipline
+ *		is changing or the tty is being hungup)
+ */
+
+static int tiocgetd(struct tty_struct *tty, int __user *p)
+{
+	struct tty_ldisc *ld;
+	int ret;
 
+	ld = tty_ldisc_ref_wait(tty);
+	if (!ld)
+		return -EIO;
+	ret = put_user(ld->ops->num, p);
+	tty_ldisc_deref(ld);
 	return ret;
 }
 
@@ -2878,7 +2972,7 @@
 	case TIOCGSID:
 		return tiocgsid(tty, real_tty, p);
 	case TIOCGETD:
-		return put_user(tty->ldisc->ops->num, (int __user *)p);
+		return tiocgetd(tty, p);
 	case TIOCSETD:
 		return tiocsetd(tty, p);
 	case TIOCVHANGUP:
@@ -2944,6 +3038,8 @@
 			return retval;
 	}
 	ld = tty_ldisc_ref_wait(tty);
+	if (!ld)
+		return hung_up_tty_ioctl(file, cmd, arg);
 	retval = -EINVAL;
 	if (ld->ops->ioctl) {
 		retval = ld->ops->ioctl(tty, file, cmd, arg);
@@ -2972,6 +3068,8 @@
 	}
 
 	ld = tty_ldisc_ref_wait(tty);
+	if (!ld)
+		return hung_up_tty_compat_ioctl(file, cmd, arg);
 	if (ld->ops->compat_ioctl)
 		retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
 	else
@@ -3016,10 +3114,14 @@
 	struct task_struct *g, *p;
 	struct pid *session;
 	int		i;
+	unsigned long flags;
 
 	if (!tty)
 		return;
-	session = tty->session;
+
+	spin_lock_irqsave(&tty->ctrl_lock, flags);
+	session = get_pid(tty->session);
+	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
 	tty_ldisc_flush(tty);
 
@@ -3055,6 +3157,7 @@
 		task_unlock(p);
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
+	put_pid(session);
 #endif
 }
 
@@ -3112,7 +3215,10 @@
 
 	kref_init(&tty->kref);
 	tty->magic = TTY_MAGIC;
-	tty_ldisc_init(tty);
+	if (tty_ldisc_init(tty)) {
+		kfree(tty);
+		return NULL;
+	}
 	tty->session = NULL;
 	tty->pgrp = NULL;
 	mutex_init(&tty->legacy_mutex);
@@ -3643,6 +3749,7 @@
  */
 int __init tty_init(void)
 {
+	tty_sysctl_init();
 	cdev_init(&tty_cdev, &tty_fops);
 	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
--- linux-4.4.0.orig/drivers/tty/tty_ioctl.c
+++ linux-4.4.0/drivers/tty/tty_ioctl.c
@@ -330,7 +330,7 @@
 		else
 			cbaud += 15;
 	}
-	return baud_table[cbaud];
+	return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
 }
 EXPORT_SYMBOL(tty_termios_baud_rate);
 
@@ -366,7 +366,7 @@
 		else
 			cbaud += 15;
 	}
-	return baud_table[cbaud];
+	return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
 #else
 	return tty_termios_baud_rate(termios);
 #endif
--- linux-4.4.0.orig/drivers/tty/tty_ldisc.c
+++ linux-4.4.0/drivers/tty/tty_ldisc.c
@@ -148,6 +148,13 @@
  *		takes tty_ldiscs_lock to guard against ldisc races
  */
 
+#if defined(CONFIG_LDISC_AUTOLOAD)
+	#define INITIAL_AUTOLOAD_STATE	1
+#else
+	#define INITIAL_AUTOLOAD_STATE	0
+#endif
+static int tty_ldisc_autoload = INITIAL_AUTOLOAD_STATE;
+
 static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
 {
 	struct tty_ldisc *ld;
@@ -162,18 +169,19 @@
 	 */
 	ldops = get_ldops(disc);
 	if (IS_ERR(ldops)) {
+		if (!capable(CAP_SYS_MODULE) && !tty_ldisc_autoload)
+			return ERR_PTR(-EPERM);
 		request_module("tty-ldisc-%d", disc);
 		ldops = get_ldops(disc);
 		if (IS_ERR(ldops))
 			return ERR_CAST(ldops);
 	}
 
-	ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
-	if (ld == NULL) {
-		put_ldops(ldops);
-		return ERR_PTR(-ENOMEM);
-	}
-
+	/*
+	 * There is no way to handle allocation failure of only 16 bytes.
+	 * Let's simplify error handling and save more memory.
+	 */
+	ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL | __GFP_NOFAIL);
 	ld->ops = ldops;
 	ld->tty = tty;
 
@@ -250,19 +258,23 @@
  *	reference to it. If the line discipline is in flux then
  *	wait patiently until it changes.
  *
+ *	Returns: NULL if the tty has been hungup and not re-opened with
+ *		 a new file descriptor, otherwise valid ldisc reference
+ *
  *	Note: Must not be called from an IRQ/timer context. The caller
  *	must also be careful not to hold other locks that will deadlock
  *	against a discipline change, such as an existing ldisc reference
  *	(which we check for)
  *
- *	Note: only callable from a file_operations routine (which
- *	guarantees tty->ldisc != NULL when the lock is acquired).
+ *	Note: a file_operations routine (read/poll/write) should use this
+ *	function to wait for any ldisc lifetime events to finish.
  */
 
 struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
 {
 	ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
-	WARN_ON(!tty->ldisc);
+	if (!tty->ldisc)
+		ldsem_up_read(&tty->ldisc_sem);
 	return tty->ldisc;
 }
 EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
@@ -322,11 +334,16 @@
 	ldsem_up_write(&tty->ldisc_sem);
 }
 
-static int __lockfunc
+int __lockfunc
 tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
 {
 	int ret;
 
+	/* Kindly asking blocked readers to release the read side */
+	set_bit(TTY_LDISC_CHANGING, &tty->flags);
+	wake_up_interruptible_all(&tty->read_wait);
+	wake_up_interruptible_all(&tty->write_wait);
+
 	ret = __tty_ldisc_lock(tty, timeout);
 	if (!ret)
 		return -EBUSY;
@@ -334,9 +351,11 @@
 	return 0;
 }
 
-static void tty_ldisc_unlock(struct tty_struct *tty)
+void tty_ldisc_unlock(struct tty_struct *tty)
 {
 	clear_bit(TTY_LDISC_HALTED, &tty->flags);
+	/* Can be cleared here - ldisc_unlock will wake up writers firstly */
+	clear_bit(TTY_LDISC_CHANGING, &tty->flags);
 	__tty_ldisc_unlock(tty);
 }
 
@@ -411,20 +430,27 @@
 /**
  *	tty_set_termios_ldisc		-	set ldisc field
  *	@tty: tty structure
- *	@num: line discipline number
+ *	@disc: line discipline number
  *
  *	This is probably overkill for real world processors but
  *	they are not on hot paths so a little discipline won't do
  *	any harm.
  *
+ *	The line discipline-related tty_struct fields are reset to
+ *	prevent the ldisc driver from re-using stale information for
+ *	the new ldisc instance.
+ *
  *	Locking: takes termios_rwsem
  */
 
-static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+static void tty_set_termios_ldisc(struct tty_struct *tty, int disc)
 {
 	down_write(&tty->termios_rwsem);
-	tty->termios.c_line = num;
+	tty->termios.c_line = disc;
 	up_write(&tty->termios_rwsem);
+
+	tty->disc_data = NULL;
+	tty->receive_room = 0;
 }
 
 /**
@@ -448,7 +474,7 @@
 		if (ret)
 			clear_bit(TTY_LDISC_OPEN, &tty->flags);
 
-		tty_ldisc_debug(tty, "%p: opened\n", tty->ldisc);
+		tty_ldisc_debug(tty, "%p: opened\n", ld);
 		return ret;
 	}
 	return 0;
@@ -469,7 +495,7 @@
 	clear_bit(TTY_LDISC_OPEN, &tty->flags);
 	if (ld->ops->close)
 		ld->ops->close(tty);
-	tty_ldisc_debug(tty, "%p: closed\n", tty->ldisc);
+	tty_ldisc_debug(tty, "%p: closed\n", ld);
 }
 
 /**
@@ -518,51 +544,43 @@
  *	the close of one side of a tty/pty pair, and eventually hangup.
  */
 
-int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+int tty_set_ldisc(struct tty_struct *tty, int disc)
 {
 	int retval;
 	struct tty_ldisc *old_ldisc, *new_ldisc;
 
-	new_ldisc = tty_ldisc_get(tty, ldisc);
+	new_ldisc = tty_ldisc_get(tty, disc);
 	if (IS_ERR(new_ldisc))
 		return PTR_ERR(new_ldisc);
 
 	tty_lock(tty);
 	retval = tty_ldisc_lock(tty, 5 * HZ);
-	if (retval) {
-		tty_ldisc_put(new_ldisc);
-		tty_unlock(tty);
-		return retval;
-	}
-
-	/*
-	 *	Check the no-op case
-	 */
+	if (retval)
+		goto err;
 
-	if (tty->ldisc->ops->num == ldisc) {
-		tty_ldisc_unlock(tty);
-		tty_ldisc_put(new_ldisc);
-		tty_unlock(tty);
-		return 0;
+	if (!tty->ldisc) {
+		retval = -EIO;
+		goto out;
 	}
 
-	old_ldisc = tty->ldisc;
+	/* Check the no-op case */
+	if (tty->ldisc->ops->num == disc)
+		goto out;
 
 	if (test_bit(TTY_HUPPED, &tty->flags)) {
-		/* We were raced by the hangup method. It will have stomped
-		   the ldisc data and closed the ldisc down */
-		tty_ldisc_unlock(tty);
-		tty_ldisc_put(new_ldisc);
-		tty_unlock(tty);
-		return -EIO;
+		/* We were raced by hangup */
+		retval = -EIO;
+		goto out;
 	}
 
+	old_ldisc = tty->ldisc;
+
 	/* Shutdown the old discipline. */
 	tty_ldisc_close(tty, old_ldisc);
 
 	/* Now set up the new line discipline. */
 	tty->ldisc = new_ldisc;
-	tty_set_termios_ldisc(tty, ldisc);
+	tty_set_termios_ldisc(tty, disc);
 
 	retval = tty_ldisc_open(tty, new_ldisc);
 	if (retval < 0) {
@@ -582,23 +600,39 @@
 	   the old ldisc (if it was restored as part of error cleanup
 	   above). In either case, releasing a single reference from
 	   the old ldisc is correct. */
-
-	tty_ldisc_put(old_ldisc);
-
-	/*
-	 *	Allow ldisc referencing to occur again
-	 */
+	new_ldisc = old_ldisc;
+out:
 	tty_ldisc_unlock(tty);
 
 	/* Restart the work queue in case no characters kick it off. Safe if
 	   already running */
 	tty_buffer_restart_work(tty->port);
-
+err:
+	tty_ldisc_put(new_ldisc);	/* drop the extra reference */
 	tty_unlock(tty);
 	return retval;
 }
 
 /**
+ *	tty_ldisc_kill	-	teardown ldisc
+ *	@tty: tty being released
+ *
+ *	Perform final close of the ldisc and reset tty->ldisc
+ */
+static void tty_ldisc_kill(struct tty_struct *tty)
+{
+	if (!tty->ldisc)
+		return;
+	/*
+	 * Now kill off the ldisc
+	 */
+	tty_ldisc_close(tty, tty->ldisc);
+	tty_ldisc_put(tty->ldisc);
+	/* Force an oops if we mess this up */
+	tty->ldisc = NULL;
+}
+
+/**
  *	tty_reset_termios	-	reset terminal state
  *	@tty: tty to reset
  *
@@ -618,28 +652,44 @@
 /**
  *	tty_ldisc_reinit	-	reinitialise the tty ldisc
  *	@tty: tty to reinit
- *	@ldisc: line discipline to reinitialize
+ *	@disc: line discipline to reinitialize
  *
- *	Switch the tty to a line discipline and leave the ldisc
- *	state closed
+ *	Completely reinitialize the line discipline state, by closing the
+ *	current instance, if there is one, and opening a new instance. If
+ *	an error occurs opening the new non-N_TTY instance, the instance
+ *	is dropped and tty->ldisc reset to NULL. The caller can then retry
+ *	with N_TTY instead.
+ *
+ *	Returns 0 if successful, otherwise error code < 0
  */
 
-static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
+int tty_ldisc_reinit(struct tty_struct *tty, int disc)
 {
-	struct tty_ldisc *ld = tty_ldisc_get(tty, ldisc);
+	struct tty_ldisc *ld;
+	int retval;
 
-	if (IS_ERR(ld))
-		return -1;
+	ld = tty_ldisc_get(tty, disc);
+	if (IS_ERR(ld)) {
+		BUG_ON(disc == N_TTY);
+		return PTR_ERR(ld);
+	}
 
-	tty_ldisc_close(tty, tty->ldisc);
-	tty_ldisc_put(tty->ldisc);
-	/*
-	 *	Switch the line discipline back
-	 */
-	tty->ldisc = ld;
-	tty_set_termios_ldisc(tty, ldisc);
+	if (tty->ldisc) {
+		tty_ldisc_close(tty, tty->ldisc);
+		tty_ldisc_put(tty->ldisc);
+	}
 
-	return 0;
+	/* switch the line discipline */
+	tty->ldisc = ld;
+	tty_set_termios_ldisc(tty, disc);
+	retval = tty_ldisc_open(tty, tty->ldisc);
+	if (retval) {
+		if (!WARN_ON(disc == N_TTY)) {
+			tty_ldisc_put(tty->ldisc);
+			tty->ldisc = NULL;
+		}
+	}
+	return retval;
 }
 
 /**
@@ -657,13 +707,11 @@
  *	tty itself so we must be careful about locking rules.
  */
 
-void tty_ldisc_hangup(struct tty_struct *tty)
+void tty_ldisc_hangup(struct tty_struct *tty, bool reinit)
 {
 	struct tty_ldisc *ld;
-	int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
-	int err = 0;
 
-	tty_ldisc_debug(tty, "%p: closing\n", tty->ldisc);
+	tty_ldisc_debug(tty, "%p: hangup\n", tty->ldisc);
 
 	ld = tty_ldisc_ref(tty);
 	if (ld != NULL) {
@@ -689,31 +737,17 @@
 	 */
 	tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT);
 
-	if (tty->ldisc) {
+	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+		tty_reset_termios(tty);
 
-		/* At this point we have a halted ldisc; we want to close it and
-		   reopen a new ldisc. We could defer the reopen to the next
-		   open but it means auditing a lot of other paths so this is
-		   a FIXME */
-		if (reset == 0) {
-
-			if (!tty_ldisc_reinit(tty, tty->termios.c_line))
-				err = tty_ldisc_open(tty, tty->ldisc);
-			else
-				err = 1;
-		}
-		/* If the re-open fails or we reset then go to N_TTY. The
-		   N_TTY open cannot fail */
-		if (reset || err) {
-			BUG_ON(tty_ldisc_reinit(tty, N_TTY));
-			WARN_ON(tty_ldisc_open(tty, tty->ldisc));
-		}
+	if (tty->ldisc) {
+		if (reinit) {
+			if (tty_ldisc_reinit(tty, tty->termios.c_line) < 0)
+				tty_ldisc_reinit(tty, N_TTY);
+		} else
+			tty_ldisc_kill(tty);
 	}
 	tty_ldisc_unlock(tty);
-	if (reset)
-		tty_reset_termios(tty);
-
-	tty_ldisc_debug(tty, "%p: re-opened\n", tty->ldisc);
 }
 
 /**
@@ -745,20 +779,6 @@
 	return 0;
 }
 
-static void tty_ldisc_kill(struct tty_struct *tty)
-{
-	/*
-	 * Now kill off the ldisc
-	 */
-	tty_ldisc_close(tty, tty->ldisc);
-	tty_ldisc_put(tty->ldisc);
-	/* Force an oops if we mess this up */
-	tty->ldisc = NULL;
-
-	/* Ensure the next open requests the N_TTY ldisc */
-	tty_set_termios_ldisc(tty, N_TTY);
-}
-
 /**
  *	tty_ldisc_release		-	release line discipline
  *	@tty: tty being shut down (or one end of pty pair)
@@ -797,12 +817,13 @@
  *	the tty structure is not completely set up when this call is made.
  */
 
-void tty_ldisc_init(struct tty_struct *tty)
+int tty_ldisc_init(struct tty_struct *tty)
 {
 	struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
 	if (IS_ERR(ld))
-		panic("n_tty: init_tty");
+		return PTR_ERR(ld);
 	tty->ldisc = ld;
+	return 0;
 }
 
 /**
@@ -823,3 +844,41 @@
 	/* Setup the default TTY line discipline. */
 	(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
 }
+
+static int zero;
+static int one = 1;
+static struct ctl_table tty_table[] = {
+	{
+		.procname	= "ldisc_autoload",
+		.data		= &tty_ldisc_autoload,
+		.maxlen		= sizeof(tty_ldisc_autoload),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+		.extra1		= &zero,
+		.extra2		= &one,
+	},
+	{ }
+};
+
+static struct ctl_table tty_dir_table[] = {
+	{
+		.procname	= "tty",
+		.mode		= 0555,
+		.child		= tty_table,
+	},
+	{ }
+};
+
+static struct ctl_table tty_root_table[] = {
+	{
+		.procname	= "dev",
+		.mode		= 0555,
+		.child		= tty_dir_table,
+	},
+	{ }
+};
+
+void tty_sysctl_init(void)
+{
+	register_sysctl_table(tty_root_table);
+}
--- linux-4.4.0.orig/drivers/tty/tty_ldsem.c
+++ linux-4.4.0/drivers/tty/tty_ldsem.c
@@ -137,8 +137,7 @@
 
 	list_for_each_entry_safe(waiter, next, &sem->read_wait, list) {
 		tsk = waiter->task;
-		smp_mb();
-		waiter->task = NULL;
+		smp_store_release(&waiter->task, NULL);
 		wake_up_process(tsk);
 		put_task_struct(tsk);
 	}
@@ -234,7 +233,7 @@
 	for (;;) {
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 
-		if (!waiter.task)
+		if (!smp_load_acquire(&waiter.task))
 			break;
 		if (!timeout)
 			break;
@@ -307,6 +306,16 @@
 	if (!locked)
 		ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem);
 	list_del(&waiter.list);
+
+	/*
+	 * In case of timeout, wake up every reader who gave the right of way
+	 * to writer. Prevent separation readers into two groups:
+	 * one that helds semaphore and another that sleeps.
+	 * (in case of no contention with a writer)
+	 */
+	if (!locked && list_empty(&sem->write_wait))
+		__ldsem_wake_readers(sem);
+
 	raw_spin_unlock_irq(&sem->wait_lock);
 
 	__set_task_state(tsk, TASK_RUNNING);
--- linux-4.4.0.orig/drivers/tty/tty_mutex.c
+++ linux-4.4.0/drivers/tty/tty_mutex.c
@@ -22,6 +22,19 @@
 }
 EXPORT_SYMBOL(tty_lock);
 
+int tty_lock_interruptible(struct tty_struct *tty)
+{
+	int ret;
+
+	if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
+		return -EIO;
+	tty_kref_get(tty);
+	ret = mutex_lock_interruptible(&tty->legacy_mutex);
+	if (ret)
+		tty_kref_put(tty);
+	return ret;
+}
+
 void __lockfunc tty_unlock(struct tty_struct *tty)
 {
 	if (tty->magic != TTY_MAGIC) {
--- linux-4.4.0.orig/drivers/tty/vt/consolemap.c
+++ linux-4.4.0/drivers/tty/vt/consolemap.c
@@ -494,7 +494,7 @@
 
 	p2[unicode & 0x3f] = fontpos;
 	
-	p->sum += (fontpos << 20) + unicode;
+	p->sum += (fontpos << 20U) + unicode;
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/tty/vt/keyboard.c
+++ linux-4.4.0/drivers/tty/vt/keyboard.c
@@ -121,10 +121,15 @@
 static struct input_handler kbd_handler;
 static DEFINE_SPINLOCK(kbd_event_lock);
 static DEFINE_SPINLOCK(led_lock);
+static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf'  and friends */
 static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];	/* keyboard key bitmap */
 static unsigned char shift_down[NR_SHIFT];		/* shift state counters.. */
 static bool dead_key_next;
-static int npadch = -1;					/* -1 or number assembled on pad */
+
+/* Handles a number being assembled on the number pad */
+static bool npadch_active;
+static unsigned int npadch_value;
+
 static unsigned int diacr;
 static char rep;					/* flag telling character repeat */
 
@@ -366,34 +371,22 @@
 
 static void do_compute_shiftstate(void)
 {
-	unsigned int i, j, k, sym, val;
+	unsigned int k, sym, val;
 
 	shift_state = 0;
 	memset(shift_down, 0, sizeof(shift_down));
 
-	for (i = 0; i < ARRAY_SIZE(key_down); i++) {
-
-		if (!key_down[i])
+	for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) {
+		sym = U(key_maps[0][k]);
+		if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
 			continue;
 
-		k = i * BITS_PER_LONG;
-
-		for (j = 0; j < BITS_PER_LONG; j++, k++) {
-
-			if (!test_bit(k, key_down))
-				continue;
-
-			sym = U(key_maps[0][k]);
-			if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
-				continue;
-
-			val = KVAL(sym);
-			if (val == KVAL(K_CAPSSHIFT))
-				val = KVAL(K_SHIFT);
+		val = KVAL(sym);
+		if (val == KVAL(K_CAPSSHIFT))
+			val = KVAL(K_SHIFT);
 
-			shift_down[val]++;
-			shift_state |= (1 << val);
-		}
+		shift_down[val]++;
+		shift_state |= BIT(val);
 	}
 }
 
@@ -719,8 +712,13 @@
 		return;
 
 	if ((unsigned)value < ARRAY_SIZE(func_table)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&func_buf_lock, flags);
 		if (func_table[value])
 			puts_queue(vc, func_table[value]);
+		spin_unlock_irqrestore(&func_buf_lock, flags);
+
 	} else
 		pr_err("k_fn called with value=%d\n", value);
 }
@@ -826,12 +824,12 @@
 		shift_state &= ~(1 << value);
 
 	/* kludge */
-	if (up_flag && shift_state != old_state && npadch != -1) {
+	if (up_flag && shift_state != old_state && npadch_active) {
 		if (kbd->kbdmode == VC_UNICODE)
-			to_utf8(vc, npadch);
+			to_utf8(vc, npadch_value);
 		else
-			put_queue(vc, npadch & 0xff);
-		npadch = -1;
+			put_queue(vc, npadch_value & 0xff);
+		npadch_active = false;
 	}
 }
 
@@ -849,7 +847,7 @@
 
 static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
 {
-	int base;
+	unsigned int base;
 
 	if (up_flag)
 		return;
@@ -863,10 +861,12 @@
 		base = 16;
 	}
 
-	if (npadch == -1)
-		npadch = value;
-	else
-		npadch = npadch * base + value;
+	if (!npadch_active) {
+		npadch_value = 0;
+		npadch_active = true;
+	}
+
+	npadch_value = npadch_value * base + value;
 }
 
 static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
@@ -994,7 +994,7 @@
 	KBD_LED_TRIGGER((_led_bit) + 8, _name)
 
 static struct kbd_led_trigger kbd_led_triggers[] = {
-	KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"),
+	KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrolllock"),
 	KBD_LED_TRIGGER(VC_NUMLOCK,   "kbd-numlock"),
 	KBD_LED_TRIGGER(VC_CAPSLOCK,  "kbd-capslock"),
 	KBD_LED_TRIGGER(VC_KANALOCK,  "kbd-kanalock"),
@@ -1471,7 +1471,7 @@
 
 	if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
 		kbd_rawcode(value);
-	if (event_type == EV_KEY)
+	if (event_type == EV_KEY && event_code <= KEY_MAX)
 		kbd_keycode(event_code, value, HW_RAW(handle->dev));
 
 	spin_unlock(&kbd_event_lock);
@@ -1974,18 +1974,17 @@
 #undef s
 #undef v
 
-/* FIXME: This one needs untangling and locking */
+/* FIXME: This one needs untangling */
 int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 {
 	struct kbsentry *kbs;
-	char *p;
 	u_char *q;
-	u_char __user *up;
-	int sz;
+	int sz, fnw_sz;
 	int delta;
 	char *first_free, *fj, *fnw;
 	int i, j, k;
 	int ret;
+	unsigned long flags;
 
 	if (!capable(CAP_SYS_TTY_CONFIG))
 		perm = 0;
@@ -2005,30 +2004,33 @@
 	i = kbs->kb_func;
 
 	switch (cmd) {
-	case KDGKBSENT:
-		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-						  a struct member */
-		up = user_kdgkb->kb_string;
-		p = func_table[i];
-		if(p)
-			for ( ; *p && sz; p++, sz--)
-				if (put_user(*p, up++)) {
-					ret = -EFAULT;
-					goto reterr;
-				}
-		if (put_user('\0', up)) {
-			ret = -EFAULT;
-			goto reterr;
-		}
-		kfree(kbs);
-		return ((p && *p) ? -EOVERFLOW : 0);
+	case KDGKBSENT: {
+		/* size should have been a struct member */
+		ssize_t len = sizeof(user_kdgkb->kb_string);
+
+		spin_lock_irqsave(&func_buf_lock, flags);
+		len = strlcpy(kbs->kb_string, func_table[i] ? : "", len);
+		spin_unlock_irqrestore(&func_buf_lock, flags);
+
+		ret = copy_to_user(user_kdgkb->kb_string, kbs->kb_string,
+				len + 1) ? -EFAULT : 0;
+
+		goto reterr;
+	}
 	case KDSKBSENT:
 		if (!perm) {
 			ret = -EPERM;
 			goto reterr;
 		}
 
+		fnw = NULL;
+		fnw_sz = 0;
+		/* race aginst other writers */
+		again:
+		spin_lock_irqsave(&func_buf_lock, flags);
 		q = func_table[i];
+
+		/* fj pointer to next entry after 'q' */
 		first_free = funcbufptr + (funcbufsize - funcbufleft);
 		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
 			;
@@ -2036,10 +2038,12 @@
 			fj = func_table[j];
 		else
 			fj = first_free;
-
+		/* buffer usage increase by new entry */
 		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
+
 		if (delta <= funcbufleft) { 	/* it fits in current buf */
 		    if (j < MAX_NR_FUNC) {
+			/* make enough space for new entry at 'fj' */
 			memmove(fj + delta, fj, first_free - fj);
 			for (k = j; k < MAX_NR_FUNC; k++)
 			    if (func_table[k])
@@ -2052,20 +2056,28 @@
 		    sz = 256;
 		    while (sz < funcbufsize - funcbufleft + delta)
 		      sz <<= 1;
-		    fnw = kmalloc(sz, GFP_KERNEL);
-		    if(!fnw) {
-		      ret = -ENOMEM;
-		      goto reterr;
+		    if (fnw_sz != sz) {
+		      spin_unlock_irqrestore(&func_buf_lock, flags);
+		      kfree(fnw);
+		      fnw = kmalloc(sz, GFP_KERNEL);
+		      fnw_sz = sz;
+		      if (!fnw) {
+			ret = -ENOMEM;
+			goto reterr;
+		      }
+		      goto again;
 		    }
 
 		    if (!q)
 		      func_table[i] = fj;
+		    /* copy data before insertion point to new location */
 		    if (fj > funcbufptr)
 			memmove(fnw, funcbufptr, fj - funcbufptr);
 		    for (k = 0; k < j; k++)
 		      if (func_table[k])
 			func_table[k] = fnw + (func_table[k] - funcbufptr);
 
+		    /* copy data after insertion point to new location */
 		    if (first_free > fj) {
 			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
 			for (k = j; k < MAX_NR_FUNC; k++)
@@ -2078,7 +2090,9 @@
 		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
 		    funcbufsize = sz;
 		}
+		/* finally insert item itself */
 		strcpy(func_table[i], kbs->kb_string);
+		spin_unlock_irqrestore(&func_buf_lock, flags);
 		break;
 	}
 	ret = 0;
--- linux-4.4.0.orig/drivers/tty/vt/selection.c
+++ linux-4.4.0/drivers/tty/vt/selection.c
@@ -13,6 +13,7 @@
 #include <linux/tty.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 
@@ -40,6 +41,7 @@
 static int sel_end;
 static int sel_buffer_lth;
 static char *sel_buffer;
+static DEFINE_MUTEX(sel_lock);
 
 /* clear_selection, highlight and highlight_pointer can be called
    from interrupt (via scrollback/front) */
@@ -78,6 +80,11 @@
 	}
 }
 
+bool vc_is_sel(struct vc_data *vc)
+{
+	return vc == sel_cons;
+}
+
 /*
  * User settable table: what characters are to be considered alphabetic?
  * 256 bits. Locked by the console lock.
@@ -156,14 +163,14 @@
  *	The entire selection process is managed under the console_lock. It's
  *	 a lot under the lock but its hardly a performance path
  */
-int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
+static int __set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
 {
 	struct vc_data *vc = vc_cons[fg_console].d;
 	int sel_mode, new_sel_start, new_sel_end, spc;
 	char *bp, *obp;
 	int i, ps, pe, multiplier;
 	u16 c;
-	int mode;
+	int mode, ret = 0;
 
 	poke_blanked_console();
 
@@ -324,7 +331,21 @@
 		}
 	}
 	sel_buffer_lth = bp - sel_buffer;
-	return 0;
+
+	return ret;
+}
+
+int set_selection(const struct tiocl_selection __user *v, struct tty_struct *tty)
+{
+	int ret;
+
+	mutex_lock(&sel_lock);
+	console_lock();
+	ret = __set_selection(v, tty);
+	console_unlock();
+	mutex_unlock(&sel_lock);
+
+	return ret;
 }
 
 /* Insert the contents of the selection buffer into the
@@ -347,9 +368,12 @@
 	console_unlock();
 
 	ld = tty_ldisc_ref_wait(tty);
+	if (!ld)
+		return -EIO;	/* ldisc was hung up */
 	tty_buffer_lock_exclusive(&vc->port);
 
 	add_wait_queue(&vc->paste_wait, &wait);
+	mutex_lock(&sel_lock);
 	while (sel_buffer && sel_buffer_lth > pasted) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (test_bit(TTY_THROTTLED, &tty->flags)) {
@@ -362,6 +386,7 @@
 					      count);
 		pasted += count;
 	}
+	mutex_unlock(&sel_lock);
 	remove_wait_queue(&vc->paste_wait, &wait);
 	__set_current_state(TASK_RUNNING);
 
--- linux-4.4.0.orig/drivers/tty/vt/vc_screen.c
+++ linux-4.4.0/drivers/tty/vt/vc_screen.c
@@ -218,10 +218,6 @@
 	console_lock();
 
 	attr = (currcons & 128);
-	ret = -ENXIO;
-	vc = vcs_vc(inode, &viewed);
-	if (!vc)
-		goto unlock_out;
 
 	ret = -EINVAL;
 	if (pos < 0)
@@ -237,6 +233,11 @@
 		ssize_t orig_count;
 		long p = pos;
 
+		ret = -ENXIO;
+		vc = vcs_vc(inode, &viewed);
+		if (!vc)
+			goto unlock_out;
+
 		/* Check whether we are above size each round,
 		 * as copy_to_user at the end of this loop
 		 * could sleep.
--- linux-4.4.0.orig/drivers/tty/vt/vt.c
+++ linux-4.4.0/drivers/tty/vt/vt.c
@@ -102,6 +102,7 @@
 #include <linux/uaccess.h>
 #include <linux/kdb.h>
 #include <linux/ctype.h>
+#include <linux/screen_info.h>
 
 #define MAX_NR_CON_DRIVER 16
 
@@ -146,7 +147,7 @@
 
 static int con_open(struct tty_struct *, struct file *);
 static void vc_init(struct vc_data *vc, unsigned int rows,
-		    unsigned int cols, int do_clear);
+		    unsigned int cols, int do_clear, int mode);
 static void gotoxy(struct vc_data *vc, int new_x, int new_y);
 static void save_cur(struct vc_data *vc);
 static void reset_terminal(struct vc_data *vc, int do_clear);
@@ -170,6 +171,9 @@
 static int cur_default = CUR_DEFAULT;
 module_param(cur_default, int, S_IRUGO | S_IWUSR);
 
+int vt_handoff = 0;
+module_param_named(handoff, vt_handoff, int, S_IRUGO | S_IWUSR);
+
 /*
  * ignore_poke: don't unblank the screen when things are typed.  This is
  * mainly for the privacy of braille terminal users.
@@ -600,8 +604,9 @@
 
 static void hide_cursor(struct vc_data *vc)
 {
-	if (vc == sel_cons)
+	if (vc_is_sel(vc))
 		clear_selection();
+
 	vc->vc_sw->con_cursor(vc, CM_ERASE);
 	hide_softcursor(vc);
 }
@@ -612,7 +617,7 @@
 	    vc->vc_mode == KD_GRAPHICS)
 		return;
 	if (vc->vc_deccm) {
-		if (vc == sel_cons)
+		if (vc_is_sel(vc))
 			clear_selection();
 		add_softcursor(vc);
 		if ((vc->vc_cursor_type & 0x0f) != 1)
@@ -684,6 +689,13 @@
 		}
 		if (tty0dev)
 			sysfs_notify(&tty0dev->kobj, NULL, "active");
+		/*
+		 * If we are switching away from a transparent VT the contents
+		 * will be lost, convert it into a blank text console then
+		 * it will be repainted blank if we ever switch back.
+		 */
+		if (old_vc->vc_mode == KD_TRANSPARENT)
+			old_vc->vc_mode = KD_TEXT;
 	} else {
 		hide_cursor(vc);
 		redraw = 1;
@@ -750,6 +762,7 @@
 	vc->vc_complement_mask = 0;
 	vc->vc_can_do_color = 0;
 	vc->vc_panic_force_write = false;
+	vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
 	vc->vc_sw->con_init(vc, init);
 	if (!vc->vc_complement_mask)
 		vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
@@ -758,6 +771,17 @@
 	vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
 }
 
+static void vc_port_destruct(struct tty_port *port)
+{
+	struct vc_data *vc = container_of(port, struct vc_data, port);
+
+	kfree(vc);
+}
+
+static const struct tty_port_operations vc_port_ops = {
+	.destruct = vc_port_destruct,
+};
+
 int vc_allocate(unsigned int currcons)	/* return 0 on success */
 {
 	WARN_CONSOLE_UNLOCKED();
@@ -783,6 +807,7 @@
 		return -ENOMEM;
 	    vc_cons[currcons].d = vc;
 	    tty_port_init(&vc->port);
+	    vc->port.ops = &vc_port_ops;
 	    INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
 	    visual_init(vc, currcons, 1);
 	    if (!*vc->vc_uni_pagedir_loc)
@@ -799,7 +824,7 @@
 	    if (global_cursor_default == -1)
 		    global_cursor_default = 1;
 
-	    vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+	    vc_init(vc, vc->vc_rows, vc->vc_cols, 1, KD_TEXT);
 	    vcs_make_sysfs(currcons);
 	    atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
 	}
@@ -850,7 +875,7 @@
 	unsigned int old_rows, old_row_size;
 	unsigned int new_cols, new_rows, new_row_size, new_screen_size;
 	unsigned int user;
-	unsigned short *newscreen;
+	unsigned short *oldscreen, *newscreen;
 
 	WARN_CONSOLE_UNLOCKED();
 
@@ -871,10 +896,15 @@
 	if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
 		return 0;
 
+	if (new_screen_size > (4 << 20))
+		return -EINVAL;
 	newscreen = kmalloc(new_screen_size, GFP_USER);
 	if (!newscreen)
 		return -ENOMEM;
 
+	if (vc_is_sel(vc))
+		clear_selection();
+
 	old_rows = vc->vc_rows;
 	old_row_size = vc->vc_size_row;
 
@@ -927,10 +957,11 @@
 	if (new_scr_end > new_origin)
 		scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
 			    new_scr_end - new_origin);
-	kfree(vc->vc_screenbuf);
+	oldscreen = vc->vc_screenbuf;
 	vc->vc_screenbuf = newscreen;
 	vc->vc_screenbuf_size = new_screen_size;
 	set_origin(vc);
+	kfree(oldscreen);
 
 	/* do part of a reset_terminal() */
 	vc->vc_top = 0;
@@ -952,6 +983,7 @@
 	if (CON_IS_VISIBLE(vc))
 		update_screen(vc);
 	vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
+	notify_update(vc);
 	return err;
 }
 
@@ -1172,7 +1204,7 @@
 			break;
 		case 3: /* erase scroll-back buffer (and whole display) */
 			scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
-				    vc->vc_screenbuf_size >> 1);
+				    vc->vc_screenbuf_size);
 			set_origin(vc);
 			if (CON_IS_VISIBLE(vc))
 				update_screen(vc);
@@ -1306,6 +1338,11 @@
 			case 3:
 				vc->vc_italic = 1;
 				break;
+			case 21:
+				/*
+				 * No console drivers support double underline, so
+				 * convert it to a single underline.
+				 */
 			case 4:
 				vc->vc_underline = 1;
 				break;
@@ -1342,7 +1379,6 @@
 				vc->vc_disp_ctrl = 1;
 				vc->vc_toggle_meta = 1;
 				break;
-			case 21:
 			case 22:
 				vc->vc_intensity = 1;
 				break;
@@ -1719,7 +1755,7 @@
 	default_attr(vc);
 	update_attr(vc);
 
-	vc->vc_tab_stop[0]	= 0x01010100;
+	vc->vc_tab_stop[0]	=
 	vc->vc_tab_stop[1]	=
 	vc->vc_tab_stop[2]	=
 	vc->vc_tab_stop[3]	=
@@ -1763,7 +1799,7 @@
 		vc->vc_pos -= (vc->vc_x << 1);
 		while (vc->vc_x < vc->vc_cols - 1) {
 			vc->vc_x++;
-			if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
+			if (vc->vc_tab_stop[7 & (vc->vc_x >> 5)] & (1 << (vc->vc_x & 31)))
 				break;
 		}
 		vc->vc_pos += (vc->vc_x << 1);
@@ -1823,7 +1859,7 @@
 			lf(vc);
 			return;
 		case 'H':
-			vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
+			vc->vc_tab_stop[7 & (vc->vc_x >> 5)] |= (1 << (vc->vc_x & 31));
 			return;
 		case 'Z':
 			respond_ID(tty);
@@ -2016,7 +2052,7 @@
 			return;
 		case 'g':
 			if (!vc->vc_par[0])
-				vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
+				vc->vc_tab_stop[7 & (vc->vc_x >> 5)] &= ~(1 << (vc->vc_x & 31));
 			else if (vc->vc_par[0] == 3) {
 				vc->vc_tab_stop[0] =
 					vc->vc_tab_stop[1] =
@@ -2459,7 +2495,7 @@
 	if (scrollback_delta) {
 		struct vc_data *vc = vc_cons[fg_console].d;
 		clear_selection();
-		if (vc->vc_mode == KD_TEXT)
+		if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta)
 			vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
 		scrollback_delta = 0;
 	}
@@ -2676,9 +2712,7 @@
 	switch (type)
 	{
 		case TIOCL_SETSEL:
-			console_lock();
 			ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
-			console_unlock();
 			break;
 		case TIOCL_PASTESEL:
 			ret = paste_selection(tty);
@@ -2702,13 +2736,13 @@
 	 * related to the kernel should not use this.
 	 */
 			data = vt_get_shift_state();
-			ret = __put_user(data, p);
+			ret = put_user(data, p);
 			break;
 		case TIOCL_GETMOUSEREPORTING:
 			console_lock();	/* May be overkill */
 			data = mouse_reporting();
 			console_unlock();
-			ret = __put_user(data, p);
+			ret = put_user(data, p);
 			break;
 		case TIOCL_SETVESABLANK:
 			console_lock();
@@ -2717,7 +2751,7 @@
 			break;
 		case TIOCL_GETKMSGREDIRECT:
 			data = vt_get_kmsg_redirect();
-			ret = __put_user(data, p);
+			ret = put_user(data, p);
 			break;
 		case TIOCL_SETKMSGREDIRECT:
 			if (!capable(CAP_SYS_ADMIN)) {
@@ -2884,6 +2918,7 @@
 
 	tty->driver_data = vc;
 	vc->port.tty = tty;
+	tty_port_get(&vc->port);
 
 	if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 		tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
@@ -2919,6 +2954,13 @@
 	console_unlock();
 }
 
+static void con_cleanup(struct tty_struct *tty)
+{
+	struct vc_data *vc = tty->driver_data;
+
+	tty_port_put(&vc->port);
+}
+
 static int default_color           = 7; /* white */
 static int default_italic_color    = 2; // green (ASCII)
 static int default_underline_color = 3; // cyan (ASCII)
@@ -2927,7 +2969,7 @@
 module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
 
 static void vc_init(struct vc_data *vc, unsigned int rows,
-		    unsigned int cols, int do_clear)
+		    unsigned int cols, int do_clear, int mode)
 {
 	int j, k ;
 
@@ -2938,7 +2980,7 @@
 
 	set_origin(vc);
 	vc->vc_pos = vc->vc_origin;
-	reset_vc(vc);
+	reset_vc(vc, mode);
 	for (j=k=0; j<16; j++) {
 		vc->vc_palette[k++] = default_red[j] ;
 		vc->vc_palette[k++] = default_grn[j] ;
@@ -2995,16 +3037,32 @@
 		mod_timer(&console_timer, jiffies + (blankinterval * HZ));
 	}
 
+	if (vt_handoff > 0 && vt_handoff <= MAX_NR_CONSOLES) {
+		currcons = vt_handoff - 1;
+		vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
+		INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+		tty_port_init(&vc->port);
+		visual_init(vc, currcons, 1);
+		vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
+		vc_init(vc, vc->vc_rows, vc->vc_cols, 0, KD_TRANSPARENT);
+	}
 	for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
+		if (currcons == vt_handoff - 1)
+			continue;
 		vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
 		INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
 		tty_port_init(&vc->port);
 		visual_init(vc, currcons, 1);
 		vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
 		vc_init(vc, vc->vc_rows, vc->vc_cols,
-			currcons || !vc->vc_sw->con_save_screen);
+			currcons || !vc->vc_sw->con_save_screen, KD_TEXT);
 	}
 	currcons = fg_console = 0;
+	if (vt_handoff > 0) {
+		printk(KERN_INFO "vt handoff: transparent VT on vt#%d\n",
+								vt_handoff);
+		currcons = fg_console = vt_handoff - 1;
+	}
 	master_display_fg = vc = vc_cons[currcons].d;
 	set_origin(vc);
 	save_screen(vc);
@@ -3043,7 +3101,8 @@
 	.throttle = con_throttle,
 	.unthrottle = con_unthrottle,
 	.resize = vt_resize,
-	.shutdown = con_shutdown
+	.shutdown = con_shutdown,
+	.cleanup = con_cleanup,
 };
 
 static struct cdev vc0_cdev;
@@ -3583,9 +3642,10 @@
 		goto err;
 
 	desc = csw->con_startup();
-
-	if (!desc)
+	if (!desc) {
+		retval = -ENODEV;
 		goto err;
+	}
 
 	retval = -EINVAL;
 
@@ -4081,16 +4141,8 @@
 
 	if (op->data && font.charcount > op->charcount)
 		rc = -ENOSPC;
-	if (!(op->flags & KD_FONT_FLAG_OLD)) {
-		if (font.width > op->width || font.height > op->height) 
-			rc = -ENOSPC;
-	} else {
-		if (font.width != 8)
-			rc = -EIO;
-		else if ((op->height && font.height > op->height) ||
-			 font.height > 32)
-			rc = -ENOSPC;
-	}
+	if (font.width > op->width || font.height > op->height)
+		rc = -ENOSPC;
 	if (rc)
 		goto out;
 
@@ -4118,27 +4170,7 @@
 		return -EINVAL;
 	if (op->charcount > 512)
 		return -EINVAL;
-	if (!op->height) {		/* Need to guess font height [compat] */
-		int h, i;
-		u8 __user *charmap = op->data;
-		u8 tmp;
-		
-		/* If from KDFONTOP ioctl, don't allow things which can be done in userland,
-		   so that we can get rid of this soon */
-		if (!(op->flags & KD_FONT_FLAG_OLD))
-			return -EINVAL;
-		for (h = 32; h > 0; h--)
-			for (i = 0; i < op->charcount; i++) {
-				if (get_user(tmp, &charmap[32*i+h-1]))
-					return -EFAULT;
-				if (tmp)
-					goto nonzero;
-			}
-		return -EINVAL;
-	nonzero:
-		op->height = h;
-	}
-	if (op->width <= 0 || op->width > 32 || op->height > 32)
+	if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32)
 		return -EINVAL;
 	size = (op->width+7)/8 * 32 * op->charcount;
 	if (size > max_font_size)
@@ -4193,27 +4225,6 @@
 	return rc;
 }
 
-static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
-{
-	int con = op->height;
-	int rc;
-
-
-	console_lock();
-	if (vc->vc_mode != KD_TEXT)
-		rc = -EINVAL;
-	else if (!vc->vc_sw->con_font_copy)
-		rc = -ENOSYS;
-	else if (con < 0 || !vc_cons_allocated(con))
-		rc = -ENOTTY;
-	else if (con == vc->vc_num)	/* nothing to do */
-		rc = 0;
-	else
-		rc = vc->vc_sw->con_font_copy(vc, con);
-	console_unlock();
-	return rc;
-}
-
 int con_font_op(struct vc_data *vc, struct console_font_op *op)
 {
 	switch (op->op) {
@@ -4224,7 +4235,8 @@
 	case KD_FONT_OP_SET_DEFAULT:
 		return con_font_default(vc, op);
 	case KD_FONT_OP_COPY:
-		return con_font_copy(vc, op);
+		/* was buggy and never really used */
+		return -EINVAL;
 	}
 	return -ENOSYS;
 }
--- linux-4.4.0.orig/drivers/tty/vt/vt_ioctl.c
+++ linux-4.4.0/drivers/tty/vt/vt_ioctl.c
@@ -31,16 +31,39 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+#include <linux/nospec.h>
+
 #include <linux/kbd_kern.h>
 #include <linux/vt_kern.h>
 #include <linux/kbd_diacr.h>
 #include <linux/selection.h>
 
-char vt_dont_switch;
-extern struct tty_driver *console_driver;
+bool vt_dont_switch;
+
+static inline bool vt_in_use(unsigned int i)
+{
+	const struct vc_data *vc = vc_cons[i].d;
+
+	/*
+	 * console_lock must be held to prevent the vc from being deallocated
+	 * while we're checking whether it's in-use.
+	 */
+	WARN_CONSOLE_UNLOCKED();
+
+	return vc && kref_read(&vc->port.kref) > 1;
+}
+
+static inline bool vt_busy(int i)
+{
+	if (vt_in_use(i))
+		return true;
+	if (i == fg_console)
+		return true;
+	if (vc_is_sel(vc_cons[i].d))
+		return true;
 
-#define VT_IS_IN_USE(i)	(console_driver->ttys[i] && console_driver->ttys[i]->count)
-#define VT_BUSY(i)	(VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
+	return false;
+}
 
 /*
  * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
@@ -217,48 +240,6 @@
 #define GPLAST 0x3df
 #define GPNUM (GPLAST - GPFIRST + 1)
 
-
-
-static inline int 
-do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
-{
-	struct consolefontdesc cfdarg;
-	int i;
-
-	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
-		return -EFAULT;
- 	
-	switch (cmd) {
-	case PIO_FONTX:
-		if (!perm)
-			return -EPERM;
-		op->op = KD_FONT_OP_SET;
-		op->flags = KD_FONT_FLAG_OLD;
-		op->width = 8;
-		op->height = cfdarg.charheight;
-		op->charcount = cfdarg.charcount;
-		op->data = cfdarg.chardata;
-		return con_font_op(vc_cons[fg_console].d, op);
-	case GIO_FONTX: {
-		op->op = KD_FONT_OP_GET;
-		op->flags = KD_FONT_FLAG_OLD;
-		op->width = 8;
-		op->height = cfdarg.charheight;
-		op->charcount = cfdarg.charcount;
-		op->data = cfdarg.chardata;
-		i = con_font_op(vc_cons[fg_console].d, op);
-		if (i)
-			return i;
-		cfdarg.charheight = op->height;
-		cfdarg.charcount = op->charcount;
-		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
-			return -EFAULT;
-		return 0;
-		}
-	}
-	return -EINVAL;
-}
-
 static inline int 
 do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
 {
@@ -290,16 +271,14 @@
 	int ret = 0;
 
 	console_lock();
-	if (VT_BUSY(vc_num))
+	if (vt_busy(vc_num))
 		ret = -EBUSY;
 	else if (vc_num)
 		vc = vc_deallocate(vc_num);
 	console_unlock();
 
-	if (vc && vc_num >= MIN_NR_CONSOLES) {
-		tty_port_destroy(&vc->port);
-		kfree(vc);
-	}
+	if (vc && vc_num >= MIN_NR_CONSOLES)
+		tty_port_put(&vc->port);
 
 	return ret;
 }
@@ -312,17 +291,15 @@
 
 	console_lock();
 	for (i = 1; i < MAX_NR_CONSOLES; i++)
-		if (!VT_BUSY(i))
+		if (!vt_busy(i))
 			vc[i] = vc_deallocate(i);
 		else
 			vc[i] = NULL;
 	console_unlock();
 
 	for (i = 1; i < MAX_NR_CONSOLES; i++) {
-		if (vc[i] && i >= MIN_NR_CONSOLES) {
-			tty_port_destroy(&vc[i]->port);
-			kfree(vc[i]);
-		}
+		if (vc[i] && i >= MIN_NR_CONSOLES)
+			tty_port_put(&vc[i]->port);
 	}
 }
 
@@ -336,22 +313,13 @@
 {
 	struct vc_data *vc = tty->driver_data;
 	struct console_font_op op;	/* used in multiple places here */
-	unsigned int console;
+	unsigned int console = vc->vc_num;
 	unsigned char ucval;
 	unsigned int uival;
 	void __user *up = (void __user *)arg;
 	int i, perm;
 	int ret = 0;
 
-	console = vc->vc_num;
-
-
-	if (!vc_cons_allocated(console)) { 	/* impossible? */
-		ret = -ENOIOCTLCMD;
-		goto out;
-	}
-
-
 	/*
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
@@ -477,16 +445,19 @@
 			ret = -EINVAL;
 			goto out;
 		}
-		/* FIXME: this needs the console lock extending */
-		if (vc->vc_mode == (unsigned char) arg)
+		console_lock();
+		if (vc->vc_mode == (unsigned char) arg) {
+			console_unlock();
 			break;
+		}
 		vc->vc_mode = (unsigned char) arg;
-		if (console != fg_console)
+		if (console != fg_console) {
+			console_unlock();
 			break;
+		}
 		/*
 		 * explicitly blank/unblank the screen if switching modes
 		 */
-		console_lock();
 		if (arg == KD_TEXT)
 			do_unblank_screen(1);
 		else
@@ -642,15 +613,16 @@
 		struct vt_stat __user *vtstat = up;
 		unsigned short state, mask;
 
-		/* Review: FIXME: Console lock ? */
 		if (put_user(fg_console + 1, &vtstat->v_active))
 			ret = -EFAULT;
 		else {
 			state = 1;	/* /dev/tty0 is always open */
+			console_lock(); /* required by vt_in_use() */
 			for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
 							++i, mask <<= 1)
-				if (VT_IS_IN_USE(i))
+				if (vt_in_use(i))
 					state |= mask;
+			console_unlock();
 			ret = put_user(state, &vtstat->v_state);
 		}
 		break;
@@ -660,10 +632,11 @@
 	 * Returns the first available (non-opened) console.
 	 */
 	case VT_OPENQRY:
-		/* FIXME: locking ? - but then this is a stupid API */
+		console_lock(); /* required by vt_in_use() */
 		for (i = 0; i < MAX_NR_CONSOLES; ++i)
-			if (! VT_IS_IN_USE(i))
+			if (!vt_in_use(i))
 				break;
+		console_unlock();
 		uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
 		goto setint;		 
 
@@ -703,6 +676,8 @@
 		if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
 			ret = -ENXIO;
 		else {
+			vsa.console = array_index_nospec(vsa.console,
+							 MAX_NR_CONSOLES + 1);
 			vsa.console--;
 			console_lock();
 			ret = vc_allocate(vsa.console);
@@ -846,87 +821,64 @@
 
 	case VT_RESIZEX:
 	{
-		struct vt_consize __user *vtconsize = up;
-		ushort ll,cc,vlin,clin,vcol,ccol;
+		struct vt_consize v;
 		if (!perm)
 			return -EPERM;
-		if (!access_ok(VERIFY_READ, vtconsize,
-				sizeof(struct vt_consize))) {
-			ret = -EFAULT;
-			break;
-		}
+		if (copy_from_user(&v, up, sizeof(struct vt_consize)))
+			return -EFAULT;
 		/* FIXME: Should check the copies properly */
-		__get_user(ll, &vtconsize->v_rows);
-		__get_user(cc, &vtconsize->v_cols);
-		__get_user(vlin, &vtconsize->v_vlin);
-		__get_user(clin, &vtconsize->v_clin);
-		__get_user(vcol, &vtconsize->v_vcol);
-		__get_user(ccol, &vtconsize->v_ccol);
-		vlin = vlin ? vlin : vc->vc_scan_lines;
-		if (clin) {
-			if (ll) {
-				if (ll != vlin/clin) {
-					/* Parameters don't add up */
-					ret = -EINVAL;
-					break;
-				}
-			} else 
-				ll = vlin/clin;
+		if (!v.v_vlin)
+			v.v_vlin = vc->vc_scan_lines;
+		if (v.v_clin) {
+			int rows = v.v_vlin/v.v_clin;
+			if (v.v_rows != rows) {
+				if (v.v_rows) /* Parameters don't add up */
+					return -EINVAL;
+				v.v_rows = rows;
+			}
 		}
-		if (vcol && ccol) {
-			if (cc) {
-				if (cc != vcol/ccol) {
-					ret = -EINVAL;
-					break;
-				}
-			} else
-				cc = vcol/ccol;
+		if (v.v_vcol && v.v_ccol) {
+			int cols = v.v_vcol/v.v_ccol;
+			if (v.v_cols != cols) {
+				if (v.v_cols)
+					return -EINVAL;
+				v.v_cols = cols;
+			}
 		}
 
-		if (clin > 32) {
-			ret =  -EINVAL;
-			break;
-		}
-		    
+		if (v.v_clin > 32)
+			return -EINVAL;
+
 		for (i = 0; i < MAX_NR_CONSOLES; i++) {
+			struct vc_data *vcp;
+
 			if (!vc_cons[i].d)
 				continue;
 			console_lock();
-			if (vlin)
-				vc_cons[i].d->vc_scan_lines = vlin;
-			if (clin)
-				vc_cons[i].d->vc_font.height = clin;
-			vc_cons[i].d->vc_resize_user = 1;
-			vc_resize(vc_cons[i].d, cc, ll);
+			vcp = vc_cons[i].d;
+			if (vcp) {
+				int ret;
+				int save_scan_lines = vcp->vc_scan_lines;
+				int save_font_height = vcp->vc_font.height;
+
+				if (v.v_vlin)
+					vcp->vc_scan_lines = v.v_vlin;
+				if (v.v_clin)
+					vcp->vc_font.height = v.v_clin;
+				vcp->vc_resize_user = 1;
+				ret = vc_resize(vcp, v.v_cols, v.v_rows);
+				if (ret) {
+					vcp->vc_scan_lines = save_scan_lines;
+					vcp->vc_font.height = save_font_height;
+					console_unlock();
+					return ret;
+				}
+			}
 			console_unlock();
 		}
 		break;
 	}
 
-	case PIO_FONT: {
-		if (!perm)
-			return -EPERM;
-		op.op = KD_FONT_OP_SET;
-		op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC;	/* Compatibility */
-		op.width = 8;
-		op.height = 0;
-		op.charcount = 256;
-		op.data = up;
-		ret = con_font_op(vc_cons[fg_console].d, &op);
-		break;
-	}
-
-	case GIO_FONT: {
-		op.op = KD_FONT_OP_GET;
-		op.flags = KD_FONT_FLAG_OLD;
-		op.width = 8;
-		op.height = 32;
-		op.charcount = 256;
-		op.data = up;
-		ret = con_font_op(vc_cons[fg_console].d, &op);
-		break;
-	}
-
 	case PIO_CMAP:
                 if (!perm)
 			ret = -EPERM;
@@ -938,36 +890,6 @@
                 ret = con_get_cmap(up);
 		break;
 
-	case PIO_FONTX:
-	case GIO_FONTX:
-		ret = do_fontx_ioctl(cmd, up, perm, &op);
-		break;
-
-	case PIO_FONTRESET:
-	{
-		if (!perm)
-			return -EPERM;
-
-#ifdef BROKEN_GRAPHICS_PROGRAMS
-		/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
-		   font is not saved. */
-		ret = -ENOSYS;
-		break;
-#else
-		{
-		op.op = KD_FONT_OP_SET_DEFAULT;
-		op.data = NULL;
-		ret = con_font_op(vc_cons[fg_console].d, &op);
-		if (ret)
-			break;
-		console_lock();
-		con_set_default_unimap(vc_cons[fg_console].d);
-		console_unlock();
-		break;
-		}
-#endif
-	}
-
 	case KDFONTOP: {
 		if (copy_from_user(&op, up, sizeof(op))) {
 			ret = -EFAULT;
@@ -1025,12 +947,12 @@
 	case VT_LOCKSWITCH:
 		if (!capable(CAP_SYS_TTY_CONFIG))
 			return -EPERM;
-		vt_dont_switch = 1;
+		vt_dont_switch = true;
 		break;
 	case VT_UNLOCKSWITCH:
 		if (!capable(CAP_SYS_TTY_CONFIG))
 			return -EPERM;
-		vt_dont_switch = 0;
+		vt_dont_switch = false;
 		break;
 	case VT_GETHIFONTMASK:
 		ret = put_user(vc->vc_hi_font_mask,
@@ -1046,9 +968,9 @@
 	return ret;
 }
 
-void reset_vc(struct vc_data *vc)
+void reset_vc(struct vc_data *vc, int mode)
 {
-	vc->vc_mode = KD_TEXT;
+	vc->vc_mode = mode;
 	vt_reset_unicode(vc->vc_num);
 	vc->vt_mode.mode = VT_AUTO;
 	vc->vt_mode.waitv = 0;
@@ -1080,59 +1002,13 @@
 		 */
 		if (tty)
 			__do_SAK(tty);
-		reset_vc(vc);
+		reset_vc(vc, KD_TEXT);
 	}
 	console_unlock();
 }
 
 #ifdef CONFIG_COMPAT
 
-struct compat_consolefontdesc {
-	unsigned short charcount;       /* characters in font (256 or 512) */
-	unsigned short charheight;      /* scan lines per character (1-32) */
-	compat_caddr_t chardata;	/* font data in expanded form */
-};
-
-static inline int
-compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
-			 int perm, struct console_font_op *op)
-{
-	struct compat_consolefontdesc cfdarg;
-	int i;
-
-	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
-		return -EFAULT;
-
-	switch (cmd) {
-	case PIO_FONTX:
-		if (!perm)
-			return -EPERM;
-		op->op = KD_FONT_OP_SET;
-		op->flags = KD_FONT_FLAG_OLD;
-		op->width = 8;
-		op->height = cfdarg.charheight;
-		op->charcount = cfdarg.charcount;
-		op->data = compat_ptr(cfdarg.chardata);
-		return con_font_op(vc_cons[fg_console].d, op);
-	case GIO_FONTX:
-		op->op = KD_FONT_OP_GET;
-		op->flags = KD_FONT_FLAG_OLD;
-		op->width = 8;
-		op->height = cfdarg.charheight;
-		op->charcount = cfdarg.charcount;
-		op->data = compat_ptr(cfdarg.chardata);
-		i = con_font_op(vc_cons[fg_console].d, op);
-		if (i)
-			return i;
-		cfdarg.charheight = op->height;
-		cfdarg.charcount = op->charcount;
-		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
-			return -EFAULT;
-		return 0;
-	}
-	return -EINVAL;
-}
-
 struct compat_console_font_op {
 	compat_uint_t op;        /* operation code KD_FONT_OP_* */
 	compat_uint_t flags;     /* KD_FONT_FLAG_* */
@@ -1198,18 +1074,10 @@
 {
 	struct vc_data *vc = tty->driver_data;
 	struct console_font_op op;	/* used in multiple places here */
-	unsigned int console;
 	void __user *up = (void __user *)arg;
 	int perm;
 	int ret = 0;
 
-	console = vc->vc_num;
-
-	if (!vc_cons_allocated(console)) { 	/* impossible? */
-		ret = -ENOIOCTLCMD;
-		goto out;
-	}
-
 	/*
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
@@ -1222,11 +1090,6 @@
 	/*
 	 * these need special handlers for incompatible data structures
 	 */
-	case PIO_FONTX:
-	case GIO_FONTX:
-		ret = compat_fontx_ioctl(cmd, up, perm, &op);
-		break;
-
 	case KDFONTOP:
 		ret = compat_kdfontop_ioctl(up, perm, &op, vc);
 		break;
@@ -1269,7 +1132,7 @@
 		arg = (unsigned long)compat_ptr(arg);
 		goto fallback;
 	}
-out:
+
 	return ret;
 
 fallback:
@@ -1337,7 +1200,7 @@
 		 * this outside of VT_PROCESS but there is no single process
 		 * to account for and tracking tty count may be undesirable.
 		 */
-			reset_vc(vc);
+			reset_vc(vc, KD_TEXT);
 
 			if (old_vc_mode != vc->vc_mode) {
 				if (vc->vc_mode == KD_TEXT)
@@ -1409,7 +1272,7 @@
 		 * this outside of VT_PROCESS but there is no single process
 		 * to account for and tracking tty count may be undesirable.
 		 */
-		reset_vc(vc);
+		reset_vc(vc, KD_TEXT);
 
 		/*
 		 * Fall through to normal (VT_AUTO) handling of the switch...
--- linux-4.4.0.orig/drivers/uio/uio.c
+++ linux-4.4.0/drivers/uio/uio.c
@@ -249,6 +249,8 @@
 	.dev_groups = uio_groups,
 };
 
+bool uio_class_registered;
+
 /*
  * device functions
  */
@@ -772,6 +774,9 @@
 		printk(KERN_ERR "class_register failed for uio\n");
 		goto err_class_register;
 	}
+
+	uio_class_registered = true;
+
 	return 0;
 
 err_class_register:
@@ -782,6 +787,7 @@
 
 static void release_uio_class(void)
 {
+	uio_class_registered = false;
 	class_unregister(&uio_class);
 	uio_major_cleanup();
 }
@@ -801,6 +807,9 @@
 	struct uio_device *idev;
 	int ret = 0;
 
+	if (!uio_class_registered)
+		return -EPROBE_DEFER;
+
 	if (!parent || !info || !info->name || !info->version)
 		return -EINVAL;
 
@@ -846,8 +855,10 @@
 		 */
 		ret = request_irq(info->irq, uio_interrupt,
 				  info->irq_flags, info->name, idev);
-		if (ret)
+		if (ret) {
+			info->uio_dev = NULL;
 			goto err_request_irq;
+		}
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/uio/uio_dmem_genirq.c
+++ linux-4.4.0/drivers/uio/uio_dmem_genirq.c
@@ -135,11 +135,13 @@
 	if (irq_on) {
 		if (test_and_clear_bit(0, &priv->flags))
 			enable_irq(dev_info->irq);
+		spin_unlock_irqrestore(&priv->lock, flags);
 	} else {
-		if (!test_and_set_bit(0, &priv->flags))
+		if (!test_and_set_bit(0, &priv->flags)) {
+			spin_unlock_irqrestore(&priv->lock, flags);
 			disable_irq(dev_info->irq);
+		}
 	}
-	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
@@ -229,7 +231,7 @@
 		++uiomem;
 	}
 
-	priv->dmem_region_start = i;
+	priv->dmem_region_start = uiomem - &uioinfo->mem[0];
 	priv->num_dmem_regions = pdata->num_dynamic_regions;
 
 	for (i = 0; i < pdata->num_dynamic_regions; ++i) {
--- linux-4.4.0.orig/drivers/uio/uio_pdrv_genirq.c
+++ linux-4.4.0/drivers/uio/uio_pdrv_genirq.c
@@ -148,7 +148,7 @@
 	if (!uioinfo->irq) {
 		ret = platform_get_irq(pdev, 0);
 		uioinfo->irq = ret;
-		if (ret == -ENXIO && pdev->dev.of_node)
+		if (ret == -ENXIO)
 			uioinfo->irq = UIO_IRQ_NONE;
 		else if (ret < 0) {
 			dev_err(&pdev->dev, "failed to get IRQ\n");
--- linux-4.4.0.orig/drivers/usb/atm/cxacru.c
+++ linux-4.4.0/drivers/usb/atm/cxacru.c
@@ -1133,6 +1133,7 @@
 	struct cxacru_data *instance;
 	struct usb_device *usb_dev = interface_to_usbdev(intf);
 	struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD];
+	struct usb_endpoint_descriptor *in, *out;
 	int ret;
 
 	/* instance init */
@@ -1182,6 +1183,19 @@
 		ret = -ENODEV;
 		goto fail;
 	}
+
+	if (usb_endpoint_xfer_int(&cmd_ep->desc))
+		ret = usb_find_common_endpoints(intf->cur_altsetting,
+						NULL, NULL, &in, &out);
+	else
+		ret = usb_find_common_endpoints(intf->cur_altsetting,
+						&in, &out, NULL, NULL);
+
+	if (ret) {
+		usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n");
+		ret = -ENODEV;
+		goto fail;
+	}
 
 	if ((cmd_ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 			== USB_ENDPOINT_XFER_INT) {
--- linux-4.4.0.orig/drivers/usb/atm/ueagle-atm.c
+++ linux-4.4.0/drivers/usb/atm/ueagle-atm.c
@@ -2167,10 +2167,11 @@
 /*
  * Start the modem : init the data and start kernel thread
  */
-static int uea_boot(struct uea_softc *sc)
+static int uea_boot(struct uea_softc *sc, struct usb_interface *intf)
 {
-	int ret, size;
 	struct intr_pkt *intr;
+	int ret = -ENOMEM;
+	int size;
 
 	uea_enters(INS_TO_USBDEV(sc));
 
@@ -2195,6 +2196,11 @@
 	if (UEA_CHIP_VERSION(sc) == ADI930)
 		load_XILINX_firmware(sc);
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 1) {
+		ret = -ENODEV;
+		goto err0;
+	}
+
 	intr = kmalloc(size, GFP_KERNEL);
 	if (!intr) {
 		uea_err(INS_TO_USBDEV(sc),
@@ -2211,8 +2217,7 @@
 	usb_fill_int_urb(sc->urb_int, sc->usb_dev,
 			 usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
 			 intr, size, uea_intr, sc,
-			 sc->usb_dev->actconfig->interface[0]->altsetting[0].
-			 endpoint[0].desc.bInterval);
+			 intf->cur_altsetting->endpoint[0].desc.bInterval);
 
 	ret = usb_submit_urb(sc->urb_int, GFP_KERNEL);
 	if (ret < 0) {
@@ -2227,6 +2232,7 @@
 	sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm");
 	if (IS_ERR(sc->kthread)) {
 		uea_err(INS_TO_USBDEV(sc), "failed to create thread\n");
+		ret = PTR_ERR(sc->kthread);
 		goto err2;
 	}
 
@@ -2241,7 +2247,7 @@
 	kfree(intr);
 err0:
 	uea_leaves(INS_TO_USBDEV(sc));
-	return -ENOMEM;
+	return ret;
 }
 
 /*
@@ -2604,7 +2610,7 @@
 	if (ret < 0)
 		goto error;
 
-	ret = uea_boot(sc);
+	ret = uea_boot(sc, intf);
 	if (ret < 0)
 		goto error_rm_grp;
 
--- linux-4.4.0.orig/drivers/usb/c67x00/c67x00-sched.c
+++ linux-4.4.0/drivers/usb/c67x00/c67x00-sched.c
@@ -500,7 +500,7 @@
 	c67x00_release_urb(c67x00, urb);
 	usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00), urb);
 	spin_unlock(&c67x00->lock);
-	usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, urbp->status);
+	usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, status);
 	spin_lock(&c67x00->lock);
 }
 
--- linux-4.4.0.orig/drivers/usb/chipidea/ci.h
+++ linux-4.4.0/drivers/usb/chipidea/ci.h
@@ -428,9 +428,6 @@
 
 u8 hw_port_test_get(struct ci_hdrc *ci);
 
-int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
-				u32 value, unsigned int timeout_ms);
-
 void ci_platform_configure(struct ci_hdrc *ci);
 
 #endif	/* __DRIVERS_USB_CHIPIDEA_CI_H */
--- linux-4.4.0.orig/drivers/usb/chipidea/ci_hdrc_imx.c
+++ linux-4.4.0/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -58,7 +58,8 @@
 
 static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = {
 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
-		CI_HDRC_TURN_VBUS_EARLY_ON,
+		CI_HDRC_TURN_VBUS_EARLY_ON |
+		CI_HDRC_DISABLE_DEVICE_STREAMING,
 };
 
 static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
@@ -126,9 +127,13 @@
 	misc_pdev = of_find_device_by_node(args.np);
 	of_node_put(args.np);
 
-	if (!misc_pdev || !platform_get_drvdata(misc_pdev))
+	if (!misc_pdev)
 		return ERR_PTR(-EPROBE_DEFER);
 
+	if (!platform_get_drvdata(misc_pdev)) {
+		put_device(&misc_pdev->dev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
 	data->dev = &misc_pdev->dev;
 
 	if (of_find_property(np, "disable-over-current", NULL))
@@ -244,7 +249,6 @@
 	struct ci_hdrc_platform_data pdata = {
 		.name		= dev_name(&pdev->dev),
 		.capoffset	= DEF_CAPOFFSET,
-		.flags		= CI_HDRC_SET_NON_ZERO_TTHA,
 	};
 	int ret;
 	const struct of_device_id *of_id;
--- linux-4.4.0.orig/drivers/usb/chipidea/core.c
+++ linux-4.4.0/drivers/usb/chipidea/core.c
@@ -518,38 +518,6 @@
 	return 0;
 }
 
-/**
- * hw_wait_reg: wait the register value
- *
- * Sometimes, it needs to wait register value before going on.
- * Eg, when switch to device mode, the vbus value should be lower
- * than OTGSC_BSV before connects to host.
- *
- * @ci: the controller
- * @reg: register index
- * @mask: mast bit
- * @value: the bit value to wait
- * @timeout_ms: timeout in millisecond
- *
- * This function returns an error code if timeout
- */
-int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
-				u32 value, unsigned int timeout_ms)
-{
-	unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms);
-
-	while (hw_read(ci, reg, mask) != value) {
-		if (time_after(jiffies, elapse)) {
-			dev_err(ci->dev, "timeout waiting for %08x in %d\n",
-					mask, reg);
-			return -ETIMEDOUT;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
 static irqreturn_t ci_irq(int irq, void *data)
 {
 	struct ci_hdrc *ci = data;
@@ -883,7 +851,7 @@
 {
 	ci_hdrc_gadget_destroy(ci);
 	ci_hdrc_host_destroy(ci);
-	if (ci->is_otg)
+	if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
 		ci_hdrc_otg_destroy(ci);
 }
 
@@ -926,6 +894,7 @@
 	if (!ci)
 		return -ENOMEM;
 
+	spin_lock_init(&ci->lock);
 	ci->dev = dev;
 	ci->platdata = dev_get_platdata(dev);
 	ci->imx28_write_fix = !!(ci->platdata->flags &
@@ -944,8 +913,15 @@
 	} else if (ci->platdata->usb_phy) {
 		ci->usb_phy = ci->platdata->usb_phy;
 	} else {
+		ci->usb_phy = devm_usb_get_phy_by_phandle(dev->parent, "phys",
+							  0);
 		ci->phy = devm_phy_get(dev->parent, "usb-phy");
-		ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2);
+
+		/* Fallback to grabbing any registered USB2 PHY */
+		if (IS_ERR(ci->usb_phy) &&
+		    PTR_ERR(ci->usb_phy) != -EPROBE_DEFER)
+			ci->usb_phy = devm_usb_get_phy(dev->parent,
+						       USB_PHY_TYPE_USB2);
 
 		/* if both generic PHY and USB PHY layers aren't enabled */
 		if (PTR_ERR(ci->phy) == -ENOSYS &&
@@ -982,27 +958,35 @@
 	/* initialize role(s) before the interrupt is requested */
 	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
 		ret = ci_hdrc_host_init(ci);
-		if (ret)
-			dev_info(dev, "doesn't support host\n");
+		if (ret) {
+			if (ret == -ENXIO)
+				dev_info(dev, "doesn't support host\n");
+			else
+				goto deinit_phy;
+		}
 	}
 
 	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
 		ret = ci_hdrc_gadget_init(ci);
-		if (ret)
-			dev_info(dev, "doesn't support gadget\n");
+		if (ret) {
+			if (ret == -ENXIO)
+				dev_info(dev, "doesn't support gadget\n");
+			else
+				goto deinit_host;
+		}
 	}
 
 	if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
 		dev_err(dev, "no supported roles\n");
 		ret = -ENODEV;
-		goto deinit_phy;
+		goto deinit_gadget;
 	}
 
 	if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) {
 		ret = ci_hdrc_otg_init(ci);
 		if (ret) {
 			dev_err(dev, "init otg fails, ret = %d\n", ret);
-			goto stop;
+			goto deinit_gadget;
 		}
 	}
 
@@ -1067,7 +1051,12 @@
 
 	ci_extcon_unregister(ci);
 stop:
-	ci_role_destroy(ci);
+	if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
+		ci_hdrc_otg_destroy(ci);
+deinit_gadget:
+	ci_hdrc_gadget_destroy(ci);
+deinit_host:
+	ci_hdrc_host_destroy(ci);
 deinit_phy:
 	ci_usb_phy_exit(ci);
 
@@ -1133,6 +1122,29 @@
 	enable_irq(ci->irq);
 }
 
+/*
+ * Handle the wakeup interrupt triggered by extcon connector
+ * We need to call ci_irq again for extcon since the first
+ * interrupt (wakeup int) only let the controller be out of
+ * low power mode, but not handle any interrupts.
+ */
+static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
+{
+	struct ci_hdrc_cable *cable_id, *cable_vbus;
+	u32 otgsc = hw_read_otgsc(ci, ~0);
+
+	cable_id = &ci->platdata->id_extcon;
+	cable_vbus = &ci->platdata->vbus_extcon;
+
+	if (!IS_ERR(cable_id->edev) && ci->is_otg &&
+		(otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
+		ci_irq(ci->irq, ci);
+
+	if (!IS_ERR(cable_vbus->edev) && ci->is_otg &&
+		(otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
+		ci_irq(ci->irq, ci);
+}
+
 static int ci_controller_resume(struct device *dev)
 {
 	struct ci_hdrc *ci = dev_get_drvdata(dev);
@@ -1159,6 +1171,7 @@
 		enable_irq(ci->irq);
 		if (ci_otg_is_fsm_mode(ci))
 			ci_otg_fsm_wakeup_by_srp(ci);
+		ci_extcon_wakeup_int(ci);
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/usb/chipidea/debug.c
+++ linux-4.4.0/drivers/usb/chipidea/debug.c
@@ -295,7 +295,8 @@
 {
 	struct ci_hdrc *ci = s->private;
 
-	seq_printf(s, "%s\n", ci_role(ci)->name);
+	if (ci->role != CI_ROLE_END)
+		seq_printf(s, "%s\n", ci_role(ci)->name);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/usb/chipidea/host.c
+++ linux-4.4.0/drivers/usb/chipidea/host.c
@@ -37,6 +37,7 @@
 
 struct ehci_ci_priv {
 	struct regulator *reg_vbus;
+	bool enabled;
 };
 
 static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
@@ -48,7 +49,7 @@
 	int ret = 0;
 	int port = HCS_N_PORTS(ehci->hcs_params);
 
-	if (priv->reg_vbus) {
+	if (priv->reg_vbus && enable != priv->enabled) {
 		if (port > 1) {
 			dev_warn(dev,
 				"Not support multi-port regulator control\n");
@@ -64,6 +65,7 @@
 				enable ? "enable" : "disable", ret);
 			return ret;
 		}
+		priv->enabled = enable;
 	}
 
 	if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) {
--- linux-4.4.0.orig/drivers/usb/chipidea/otg.c
+++ linux-4.4.0/drivers/usb/chipidea/otg.c
@@ -44,12 +44,15 @@
 		else
 			val &= ~OTGSC_BSVIS;
 
-		cable->changed = false;
-
 		if (cable->state)
 			val |= OTGSC_BSV;
 		else
 			val &= ~OTGSC_BSV;
+
+		if (cable->enabled)
+			val |= OTGSC_BSVIE;
+		else
+			val &= ~OTGSC_BSVIE;
 	}
 
 	cable = &ci->platdata->id_extcon;
@@ -59,15 +62,18 @@
 		else
 			val &= ~OTGSC_IDIS;
 
-		cable->changed = false;
-
 		if (cable->state)
 			val |= OTGSC_ID;
 		else
 			val &= ~OTGSC_ID;
+
+		if (cable->enabled)
+			val |= OTGSC_IDIE;
+		else
+			val &= ~OTGSC_IDIE;
 	}
 
-	return val;
+	return val & mask;
 }
 
 /**
@@ -77,6 +83,36 @@
  */
 void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data)
 {
+	struct ci_hdrc_cable *cable;
+
+	cable = &ci->platdata->vbus_extcon;
+	if (!IS_ERR(cable->edev)) {
+		if (data & mask & OTGSC_BSVIS)
+			cable->changed = false;
+
+		/* Don't enable vbus interrupt if using external notifier */
+		if (data & mask & OTGSC_BSVIE) {
+			cable->enabled = true;
+			data &= ~OTGSC_BSVIE;
+		} else if (mask & OTGSC_BSVIE) {
+			cable->enabled = false;
+		}
+	}
+
+	cable = &ci->platdata->id_extcon;
+	if (!IS_ERR(cable->edev)) {
+		if (data & mask & OTGSC_IDIS)
+			cable->changed = false;
+
+		/* Don't enable id interrupt if using external notifier */
+		if (data & mask & OTGSC_IDIE) {
+			cable->enabled = true;
+			data &= ~OTGSC_IDIE;
+		} else if (mask & OTGSC_IDIE) {
+			cable->enabled = false;
+		}
+	}
+
 	hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data);
 }
 
@@ -98,13 +134,37 @@
 	if (!ci->is_otg)
 		return;
 
-	if (hw_read_otgsc(ci, OTGSC_BSV))
+	if (hw_read_otgsc(ci, OTGSC_BSV) && !ci->vbus_active)
 		usb_gadget_vbus_connect(&ci->gadget);
-	else
+	else if (!hw_read_otgsc(ci, OTGSC_BSV) && ci->vbus_active)
 		usb_gadget_vbus_disconnect(&ci->gadget);
 }
 
-#define CI_VBUS_STABLE_TIMEOUT_MS 5000
+/**
+ * When we switch to device mode, the vbus value should be lower
+ * than OTGSC_BSV before connecting to host.
+ *
+ * @ci: the controller
+ *
+ * This function returns an error code if timeout
+ */
+static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
+{
+	unsigned long elapse = jiffies + msecs_to_jiffies(5000);
+	u32 mask = OTGSC_BSV;
+
+	while (hw_read_otgsc(ci, mask)) {
+		if (time_after(jiffies, elapse)) {
+			dev_err(ci->dev, "timeout waiting for %08x in OTGSC\n",
+					mask);
+			return -ETIMEDOUT;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
 static void ci_handle_id_switch(struct ci_hdrc *ci)
 {
 	enum ci_role role = ci_otg_role(ci);
@@ -115,12 +175,21 @@
 
 		ci_role_stop(ci);
 
-		if (role == CI_ROLE_GADGET)
-			/* wait vbus lower than OTGSC_BSV */
-			hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
-					CI_VBUS_STABLE_TIMEOUT_MS);
+		if (role == CI_ROLE_GADGET &&
+				IS_ERR(ci->platdata->vbus_extcon.edev))
+			/*
+			 * Wait vbus lower than OTGSC_BSV before connecting
+			 * to host. If connecting status is from an external
+			 * connector instead of register, we don't need to
+			 * care vbus on the board, since it will not affect
+			 * external connector status.
+			 */
+			hw_wait_vbus_lower_bsv(ci);
 
 		ci_role_start(ci, role);
+		/* vbus change may have already occurred */
+		if (role == CI_ROLE_GADGET)
+			ci_handle_vbus_change(ci);
 	}
 }
 /**
@@ -137,14 +206,17 @@
 	}
 
 	pm_runtime_get_sync(ci->dev);
+
 	if (ci->id_event) {
 		ci->id_event = false;
 		ci_handle_id_switch(ci);
-	} else if (ci->b_sess_valid_event) {
+	}
+
+	if (ci->b_sess_valid_event) {
 		ci->b_sess_valid_event = false;
 		ci_handle_vbus_change(ci);
-	} else
-		dev_err(ci->dev, "unexpected event occurs at %s\n", __func__);
+	}
+
 	pm_runtime_put_sync(ci->dev);
 
 	enable_irq(ci->irq);
@@ -158,7 +230,7 @@
 int ci_hdrc_otg_init(struct ci_hdrc *ci)
 {
 	INIT_WORK(&ci->work, ci_otg_work);
-	ci->wq = create_singlethread_workqueue("ci_otg");
+	ci->wq = create_freezable_workqueue("ci_otg");
 	if (!ci->wq) {
 		dev_err(ci->dev, "can't create workqueue\n");
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/usb/chipidea/otg.h
+++ linux-4.4.0/drivers/usb/chipidea/otg.h
@@ -20,7 +20,8 @@
 static inline void ci_otg_queue_work(struct ci_hdrc *ci)
 {
 	disable_irq_nosync(ci->irq);
-	queue_work(ci->wq, &ci->work);
+	if (queue_work(ci->wq, &ci->work) == false)
+		enable_irq(ci->irq);
 }
 
 #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
--- linux-4.4.0.orig/drivers/usb/chipidea/udc.c
+++ linux-4.4.0/drivers/usb/chipidea/udc.c
@@ -939,6 +939,15 @@
 	int retval;
 	struct ci_hw_ep *hwep;
 
+	/*
+	 * Unexpected USB controller behavior, caused by bad signal integrity
+	 * or ground reference problems, can lead to isr_setup_status_phase
+	 * being called with ci->status equal to NULL.
+	 * If this situation occurs, you should review your USB hardware design.
+	 */
+	if (WARN_ON_ONCE(!ci->status))
+		return -EPIPE;
+
 	hwep = (ci->ep0_dir == TX) ? ci->ep0out : ci->ep0in;
 	ci->status->context = ci;
 	ci->status->complete = isr_setup_status_complete;
@@ -1585,8 +1594,11 @@
 {
 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
 
-	/* Data+ pullup controlled by OTG state machine in OTG fsm mode */
-	if (ci_otg_is_fsm_mode(ci))
+	/*
+	 * Data+ pullup controlled by OTG state machine in OTG fsm mode;
+	 * and don't touch Data+ in host mode for dual role config.
+	 */
+	if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST)
 		return 0;
 
 	pm_runtime_get_sync(&ci->gadget.dev);
@@ -1602,6 +1614,25 @@
 static int ci_udc_start(struct usb_gadget *gadget,
 			 struct usb_gadget_driver *driver);
 static int ci_udc_stop(struct usb_gadget *gadget);
+
+/* Match ISOC IN from the highest endpoint */
+static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget,
+			      struct usb_endpoint_descriptor *desc,
+			      struct usb_ss_ep_comp_descriptor *comp_desc)
+{
+	struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
+	struct usb_ep *ep;
+
+	if (usb_endpoint_xfer_isoc(desc) && usb_endpoint_dir_in(desc)) {
+		list_for_each_entry_reverse(ep, &ci->gadget.ep_list, ep_list) {
+			if (ep->caps.dir_in && !ep->claimed)
+				return ep;
+		}
+	}
+
+	return NULL;
+}
+
 /**
  * Device operations part of the API to the USB controller hardware,
  * which don't involve endpoints (or i/o)
@@ -1615,6 +1646,7 @@
 	.vbus_draw	= ci_udc_vbus_draw,
 	.udc_start	= ci_udc_start,
 	.udc_stop	= ci_udc_stop,
+	.match_ep 	= ci_udc_match_ep,
 };
 
 static int init_eps(struct ci_hdrc *ci)
@@ -1872,8 +1904,6 @@
 	struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
 	int retval = 0;
 
-	spin_lock_init(&ci->lock);
-
 	ci->gadget.ops          = &usb_gadget_ops;
 	ci->gadget.speed        = USB_SPEED_UNKNOWN;
 	ci->gadget.max_speed    = USB_SPEED_HIGH;
@@ -1972,6 +2002,7 @@
 int ci_hdrc_gadget_init(struct ci_hdrc *ci)
 {
 	struct ci_role_driver *rdrv;
+	int ret;
 
 	if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
 		return -ENXIO;
@@ -1984,7 +2015,10 @@
 	rdrv->stop	= udc_id_switch_for_host;
 	rdrv->irq	= udc_irq;
 	rdrv->name	= "gadget";
-	ci->roles[CI_ROLE_GADGET] = rdrv;
 
-	return udc_start(ci);
+	ret = udc_start(ci);
+	if (!ret)
+		ci->roles[CI_ROLE_GADGET] = rdrv;
+
+	return ret;
 }
--- linux-4.4.0.orig/drivers/usb/class/cdc-acm.c
+++ linux-4.4.0/drivers/usb/class/cdc-acm.c
@@ -35,6 +35,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/log2.h>
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/tty_driver.h>
@@ -271,39 +272,13 @@
  * Interrupt handlers for various ACM device responses
  */
 
-/* control interface reports status changes with "interrupt" transfers */
-static void acm_ctrl_irq(struct urb *urb)
+static void acm_process_notification(struct acm *acm, unsigned char *buf)
 {
-	struct acm *acm = urb->context;
-	struct usb_cdc_notification *dr = urb->transfer_buffer;
-	unsigned char *data;
 	int newctrl;
 	int difference;
-	int retval;
-	int status = urb->status;
+	struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
+	unsigned char *data = buf + sizeof(struct usb_cdc_notification);
 
-	switch (status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dev_dbg(&acm->control->dev,
-				"%s - urb shutting down with status: %d\n",
-				__func__, status);
-		return;
-	default:
-		dev_dbg(&acm->control->dev,
-				"%s - nonzero urb status received: %d\n",
-				__func__, status);
-		goto exit;
-	}
-
-	usb_mark_last_busy(acm->dev);
-
-	data = (unsigned char *)(dr + 1);
 	switch (dr->bNotificationType) {
 	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
 		dev_dbg(&acm->control->dev, "%s - network connection: %d\n",
@@ -311,6 +286,12 @@
 		break;
 
 	case USB_CDC_NOTIFY_SERIAL_STATE:
+		if (le16_to_cpu(dr->wLength) != 2) {
+			dev_dbg(&acm->control->dev,
+				"%s - malformed serial state\n", __func__);
+			break;
+		}
+
 		newctrl = get_unaligned_le16(data);
 
 		if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
@@ -326,17 +307,17 @@
 
 		if (difference & ACM_CTRL_DSR)
 			acm->iocount.dsr++;
-		if (difference & ACM_CTRL_BRK)
-			acm->iocount.brk++;
-		if (difference & ACM_CTRL_RI)
-			acm->iocount.rng++;
 		if (difference & ACM_CTRL_DCD)
 			acm->iocount.dcd++;
-		if (difference & ACM_CTRL_FRAMING)
+		if (newctrl & ACM_CTRL_BRK)
+			acm->iocount.brk++;
+		if (newctrl & ACM_CTRL_RI)
+			acm->iocount.rng++;
+		if (newctrl & ACM_CTRL_FRAMING)
 			acm->iocount.frame++;
-		if (difference & ACM_CTRL_PARITY)
+		if (newctrl & ACM_CTRL_PARITY)
 			acm->iocount.parity++;
-		if (difference & ACM_CTRL_OVERRUN)
+		if (newctrl & ACM_CTRL_OVERRUN)
 			acm->iocount.overrun++;
 		spin_unlock(&acm->read_lock);
 
@@ -347,13 +328,95 @@
 
 	default:
 		dev_dbg(&acm->control->dev,
-			"%s - unknown notification %d received: index %d "
-			"len %d data0 %d data1 %d\n",
+			"%s - unknown notification %d received: index %d len %d\n",
 			__func__,
-			dr->bNotificationType, dr->wIndex,
-			dr->wLength, data[0], data[1]);
+			dr->bNotificationType, dr->wIndex, dr->wLength);
+	}
+}
+
+/* control interface reports status changes with "interrupt" transfers */
+static void acm_ctrl_irq(struct urb *urb)
+{
+	struct acm *acm = urb->context;
+	struct usb_cdc_notification *dr;
+	unsigned int current_size = urb->actual_length;
+	unsigned int expected_size, copy_size, alloc_size;
+	int retval;
+	int status = urb->status;
+
+	switch (status) {
+	case 0:
+		/* success */
 		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		acm->nb_index = 0;
+		dev_dbg(&acm->control->dev,
+			"%s - urb shutting down with status: %d\n",
+			__func__, status);
+		return;
+	default:
+		dev_dbg(&acm->control->dev,
+			"%s - nonzero urb status received: %d\n",
+			__func__, status);
+		goto exit;
+	}
+
+	usb_mark_last_busy(acm->dev);
+
+	if (acm->nb_index == 0) {
+		/*
+		 * The first chunk of a message must contain at least the
+		 * notification header with the length field, otherwise we
+		 * can't get an expected_size.
+		 */
+		if (current_size < sizeof(struct usb_cdc_notification)) {
+			dev_dbg(&acm->control->dev, "urb too short\n");
+			goto exit;
+		}
+		dr = urb->transfer_buffer;
+	} else {
+		dr = (struct usb_cdc_notification *)acm->notification_buffer;
+	}
+	/* size = notification-header + (optional) data */
+	expected_size = sizeof(struct usb_cdc_notification) +
+					le16_to_cpu(dr->wLength);
+
+	if (acm->nb_index != 0 || current_size < expected_size) {
+		/* notification is transmitted fragmented, reassemble */
+		if (acm->nb_size < expected_size) {
+			u8 *new_buffer;
+			alloc_size = roundup_pow_of_two(expected_size);
+			/* Final freeing is done on disconnect. */
+			new_buffer = krealloc(acm->notification_buffer,
+					      alloc_size, GFP_ATOMIC);
+			if (!new_buffer) {
+				acm->nb_index = 0;
+				goto exit;
+			}
+
+			acm->notification_buffer = new_buffer;
+			acm->nb_size = alloc_size;
+			dr = (struct usb_cdc_notification *)acm->notification_buffer;
+		}
+
+		copy_size = min(current_size,
+				expected_size - acm->nb_index);
+
+		memcpy(&acm->notification_buffer[acm->nb_index],
+		       urb->transfer_buffer, copy_size);
+		acm->nb_index += copy_size;
+		current_size = acm->nb_index;
 	}
+
+	if (current_size >= expected_size) {
+		/* notification complete */
+		acm_process_notification(acm, (unsigned char *)dr);
+		acm->nb_index = 0;
+	}
+
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval && retval != -EPERM)
@@ -372,7 +435,7 @@
 
 	res = usb_submit_urb(acm->read_urbs[index], mem_flags);
 	if (res) {
-		if (res != -EPERM) {
+		if (res != -EPERM && res != -ENODEV) {
 			dev_err(&acm->data->dev,
 					"%s - usb_submit_urb failed: %d\n",
 					__func__, res);
@@ -428,7 +491,8 @@
 		set_bit(rb->index, &acm->read_urbs_free);
 		dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
 							__func__, status);
-		return;
+		if ((status != -ENOENT) || (urb->actual_length == 0))
+			return;
 	}
 
 	usb_mark_last_busy(acm->dev);
@@ -501,6 +565,13 @@
 	if (retval)
 		goto error_init_termios;
 
+	/*
+	 * Suppress initial echoing for some devices which might send data
+	 * immediately after acm driver has been installed.
+	 */
+	if (acm->quirks & DISABLE_ECHO)
+		tty->termios.c_lflag &= ~ECHO;
+
 	tty->driver_data = acm;
 
 	return 0;
@@ -828,10 +899,10 @@
 	tmp.flags = ASYNC_LOW_LATENCY;
 	tmp.xmit_fifo_size = acm->writesize;
 	tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
-	tmp.close_delay	= acm->port.close_delay / 10;
+	tmp.close_delay	= jiffies_to_msecs(acm->port.close_delay) / 10;
 	tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
 				ASYNC_CLOSING_WAIT_NONE :
-				acm->port.closing_wait / 10;
+				jiffies_to_msecs(acm->port.closing_wait) / 10;
 
 	if (copy_to_user(info, &tmp, sizeof(tmp)))
 		return -EFAULT;
@@ -844,20 +915,28 @@
 {
 	struct serial_struct new_serial;
 	unsigned int closing_wait, close_delay;
+	unsigned int old_closing_wait, old_close_delay;
 	int retval = 0;
 
 	if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
 		return -EFAULT;
 
-	close_delay = new_serial.close_delay * 10;
+	close_delay = msecs_to_jiffies(new_serial.close_delay * 10);
 	closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-			ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+			ASYNC_CLOSING_WAIT_NONE :
+			msecs_to_jiffies(new_serial.closing_wait * 10);
+
+	/* we must redo the rounding here, so that the values match */
+	old_close_delay	= jiffies_to_msecs(acm->port.close_delay) / 10;
+	old_closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+				ASYNC_CLOSING_WAIT_NONE :
+				jiffies_to_msecs(acm->port.closing_wait) / 10;
 
 	mutex_lock(&acm->port.mutex);
 
 	if (!capable(CAP_SYS_ADMIN)) {
-		if ((close_delay != acm->port.close_delay) ||
-		    (closing_wait != acm->port.closing_wait))
+		if ((new_serial.close_delay != old_close_delay) ||
+	            (new_serial.closing_wait != old_closing_wait))
 			retval = -EPERM;
 		else
 			retval = -EOPNOTSUPP;
@@ -876,8 +955,6 @@
 	DECLARE_WAITQUEUE(wait, current);
 	struct async_icount old, new;
 
-	if (arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD ))
-		return -EINVAL;
 	do {
 		spin_lock_irq(&acm->read_lock);
 		old = acm->oldcount;
@@ -1113,6 +1190,9 @@
 	if (quirks == NO_UNION_NORMAL) {
 		data_interface = usb_ifnum_to_if(usb_dev, 1);
 		control_interface = usb_ifnum_to_if(usb_dev, 0);
+		/* we would crash */
+		if (!data_interface || !control_interface)
+			return -ENODEV;
 		goto skip_normal_probe;
 	}
 
@@ -1305,13 +1385,6 @@
 	if (acm == NULL)
 		goto alloc_fail;
 
-	minor = acm_alloc_minor(acm);
-	if (minor < 0) {
-		dev_err(&intf->dev, "no more free acm devices\n");
-		kfree(acm);
-		return -ENODEV;
-	}
-
 	ctrlsize = usb_endpoint_maxp(epctrl);
 	readsize = usb_endpoint_maxp(epread) *
 				(quirks == SINGLE_RX_URB ? 1 : 2);
@@ -1319,6 +1392,16 @@
 	acm->writesize = usb_endpoint_maxp(epwrite) * 20;
 	acm->control = control_interface;
 	acm->data = data_interface;
+
+	usb_get_intf(acm->control); /* undone in destruct() */
+
+	minor = acm_alloc_minor(acm);
+	if (minor < 0) {
+		dev_err(&intf->dev, "no more free acm devices\n");
+		kfree(acm);
+		return -ENODEV;
+	}
+
 	acm->minor = minor;
 	acm->dev = usb_dev;
 	acm->ctrl_caps = ac_management_function;
@@ -1332,7 +1415,6 @@
 	spin_lock_init(&acm->write_lock);
 	spin_lock_init(&acm->read_lock);
 	mutex_init(&acm->mutex);
-	acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
 	acm->is_int_ep = usb_endpoint_xfer_int(epread);
 	if (acm->is_int_ep)
 		acm->bInterval = epread->bInterval;
@@ -1372,14 +1454,14 @@
 		urb->transfer_dma = rb->dma;
 		if (acm->is_int_ep) {
 			usb_fill_int_urb(urb, acm->dev,
-					 acm->rx_endpoint,
+					 usb_rcvintpipe(usb_dev, epread->bEndpointAddress),
 					 rb->base,
 					 acm->readsize,
 					 acm_read_bulk_callback, rb,
 					 acm->bInterval);
 		} else {
 			usb_fill_bulk_urb(urb, acm->dev,
-					  acm->rx_endpoint,
+					  usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress),
 					  rb->base,
 					  acm->readsize,
 					  acm_read_bulk_callback, rb);
@@ -1404,6 +1486,8 @@
 				usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
 				NULL, acm->writesize, acm_write_bulk, snd);
 		snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+		if (quirks & SEND_ZERO_PACKET)
+			snd->urb->transfer_flags |= URB_ZERO_PACKET;
 		snd->instance = acm;
 	}
 
@@ -1449,6 +1533,9 @@
 			 epctrl->bInterval ? epctrl->bInterval : 16);
 	acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	acm->ctrlurb->transfer_dma = acm->ctrl_dma;
+	acm->notification_buffer = NULL;
+	acm->nb_index = 0;
+	acm->nb_size = 0;
 
 	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
 
@@ -1459,7 +1546,6 @@
 	usb_driver_claim_interface(&acm_driver, data_interface, acm);
 	usb_set_intfdata(data_interface, acm);
 
-	usb_get_intf(control_interface);
 	tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,
 			&control_interface->dev);
 	if (IS_ERR(tty_dev)) {
@@ -1563,6 +1649,8 @@
 	usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 	acm_read_buffers_free(acm);
 
+	kfree(acm->notification_buffer);
+
 	if (!acm->combined_interfaces)
 		usb_driver_release_interface(&acm_driver, intf == acm->control ?
 					acm->data : acm->control);
@@ -1659,6 +1747,8 @@
 
 static const struct usb_device_id acm_ids[] = {
 	/* quirky and broken devices */
+	{ USB_DEVICE(0x0424, 0x274e), /* Microchip Technology, Inc. (formerly SMSC) */
+	  .driver_info = DISABLE_ECHO, }, /* DISABLE ECHO in termios flag */
 	{ USB_DEVICE(0x076d, 0x0006), /* Denso Cradle CU-321 */
 	.driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
 	{ USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
@@ -1666,9 +1756,21 @@
 	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
+	{ USB_DEVICE(0x045b, 0x023c),	/* Renesas USB Download mode */
+	.driver_info = DISABLE_ECHO,	/* Don't echo banner */
+	},
+	{ USB_DEVICE(0x045b, 0x0248),	/* Renesas USB Download mode */
+	.driver_info = DISABLE_ECHO,	/* Don't echo banner */
+	},
+	{ USB_DEVICE(0x045b, 0x024D),	/* Renesas USB Download mode */
+	.driver_info = DISABLE_ECHO,	/* Don't echo banner */
+	},
 	{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
+	{ USB_DEVICE(0x0e8d, 0x2000), /* MediaTek Inc Preloader */
+	.driver_info = DISABLE_ECHO, /* DISABLE ECHO in termios flag */
+	},
 	{ USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
@@ -1687,6 +1789,12 @@
 	{ USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
 	.driver_info = SINGLE_RX_URB, /* firmware bug */
 	},
+	{ USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */
+	.driver_info = SINGLE_RX_URB,
+	},
+	{ USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */
+	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+	},
 	{ USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
@@ -1702,9 +1810,13 @@
 	{ USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
+	{ USB_DEVICE(0x0572, 0x1349), /* Hiro (Conexant) USB MODEM H50228 */
+	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+	},
 	{ USB_DEVICE(0x20df, 0x0001), /* Simtec Electronics Entropy Key */
 	.driver_info = QUIRK_CONTROL_LINE_STATE, },
 	{ USB_DEVICE(0x2184, 0x001c) },	/* GW Instek AFG-2225 */
+	{ USB_DEVICE(0x2184, 0x0036) },	/* GW Instek AFG-125 */
 	{ USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
 	},
 	/* Motorola H24 HSPA module: */
@@ -1750,6 +1862,15 @@
 	{ USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
 	.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
 	},
+	{ USB_DEVICE(0xfff0, 0x0100), /* DATECS FP-2000 */
+	.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
+	},
+	{ USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */
+	.driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */
+	},
+	{ USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */
+	.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
+	},
 
 	{ USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */
 	.driver_info = CLEAR_HALT_CONDITIONS,
@@ -1836,13 +1957,59 @@
 	{ USB_DEVICE(0x04d8, 0x0083),	/* Bootloader mode */
 	.driver_info = IGNORE_DEVICE,
 	},
+
+	{ USB_DEVICE(0x04d8, 0xf58b),
+	.driver_info = IGNORE_DEVICE,
+	},
 #endif
 
+	/*Samsung phone in firmware update mode */
+	{ USB_DEVICE(0x04e8, 0x685d),
+	.driver_info = IGNORE_DEVICE,
+	},
+
 	/* Exclude Infineon Flash Loader utility */
 	{ USB_DEVICE(0x058b, 0x0041),
 	.driver_info = IGNORE_DEVICE,
 	},
 
+	/* Exclude ETAS ES58x */
+	{ USB_DEVICE(0x108c, 0x0159), /* ES581.4 */
+	.driver_info = IGNORE_DEVICE,
+	},
+	{ USB_DEVICE(0x108c, 0x0168), /* ES582.1 */
+	.driver_info = IGNORE_DEVICE,
+	},
+	{ USB_DEVICE(0x108c, 0x0169), /* ES584.1 */
+	.driver_info = IGNORE_DEVICE,
+	},
+
+	{ USB_DEVICE(0x1bc7, 0x0021), /* Telit 3G ACM only composition */
+	.driver_info = SEND_ZERO_PACKET,
+	},
+	{ USB_DEVICE(0x1bc7, 0x0023), /* Telit 3G ACM + ECM composition */
+	.driver_info = SEND_ZERO_PACKET,
+	},
+
+	/* Exclude Exar USB serial ports */
+	{ USB_DEVICE(0x04e2, 0x1400), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1401), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1402), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1403), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1410), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1411), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1412), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1414), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1420), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1421), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1422), .driver_info = IGNORE_DEVICE, },
+	{ USB_DEVICE(0x04e2, 0x1424), .driver_info = IGNORE_DEVICE, },
+
+	/* Exclude Goodix Fingerprint Reader */
+	{ USB_DEVICE(0x27c6, 0x5395),
+	.driver_info = IGNORE_DEVICE,
+	},
+
 	/* control interfaces without any protocol set */
 	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
 		USB_CDC_PROTO_NONE) },
@@ -1861,6 +2028,10 @@
 	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
 		USB_CDC_ACM_PROTO_AT_CDMA) },
 
+	{ USB_DEVICE(0x1519, 0x0452), /* Intel 7260 modem */
+	.driver_info = SEND_ZERO_PACKET,
+	},
+
 	{ }
 };
 
--- linux-4.4.0.orig/drivers/usb/class/cdc-acm.h
+++ linux-4.4.0/drivers/usb/class/cdc-acm.h
@@ -95,8 +95,10 @@
 	struct urb *read_urbs[ACM_NR];
 	struct acm_rb read_buffers[ACM_NR];
 	int rx_buflimit;
-	int rx_endpoint;
 	spinlock_t read_lock;
+	u8 *notification_buffer;			/* to reassemble fragmented notifications */
+	unsigned int nb_index;
+	unsigned int nb_size;
 	int write_used;					/* number of non-empty write buffers */
 	int transmitting;
 	spinlock_t write_lock;
@@ -134,3 +136,5 @@
 #define IGNORE_DEVICE			BIT(5)
 #define QUIRK_CONTROL_LINE_STATE	BIT(6)
 #define CLEAR_HALT_CONDITIONS		BIT(7)
+#define SEND_ZERO_PACKET		BIT(8)
+#define DISABLE_ECHO			BIT(9)
--- linux-4.4.0.orig/drivers/usb/class/cdc-wdm.c
+++ linux-4.4.0/drivers/usb/class/cdc-wdm.c
@@ -61,6 +61,9 @@
 
 #define WDM_MAX			16
 
+/* we cannot wait forever at flush() */
+#define WDM_FLUSH_TIMEOUT	(30 * HZ)
+
 /* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */
 #define WDM_DEFAULT_BUFSIZE	256
 
@@ -151,7 +154,7 @@
 	kfree(desc->outbuf);
 	desc->outbuf = NULL;
 	clear_bit(WDM_IN_USE, &desc->flags);
-	wake_up(&desc->wait);
+	wake_up_all(&desc->wait);
 }
 
 static void wdm_in_callback(struct urb *urb)
@@ -188,7 +191,12 @@
 		}
 	}
 
-	desc->rerr = status;
+	/*
+	 * Avoid propagating -EPIPE (stall) to userspace since it is
+	 * better handled as an empty read
+	 */
+	desc->rerr = (status != -EPIPE) ? status : 0;
+
 	if (length + desc->length > desc->wMaxCommand) {
 		/* The buffer would overflow */
 		set_bit(WDM_OVERFLOW, &desc->flags);
@@ -382,6 +390,9 @@
 	if (test_bit(WDM_RESETTING, &desc->flags))
 		r = -EIO;
 
+	if (test_bit(WDM_DISCONNECTING, &desc->flags))
+		r = -ENODEV;
+
 	if (r < 0) {
 		rv = r;
 		goto out_free_mem_pm;
@@ -413,6 +424,7 @@
 	if (rv < 0) {
 		desc->outbuf = NULL;
 		clear_bit(WDM_IN_USE, &desc->flags);
+		wake_up_all(&desc->wait); /* for wdm_wait_for_response() */
 		dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv);
 		rv = usb_translate_errors(rv);
 		goto out_free_mem_pm;
@@ -573,18 +585,58 @@
 	return rv;
 }
 
-static int wdm_flush(struct file *file, fl_owner_t id)
+static int wdm_wait_for_response(struct file *file, long timeout)
 {
 	struct wdm_device *desc = file->private_data;
+	long rv; /* Use long here because (int) MAX_SCHEDULE_TIMEOUT < 0. */
 
-	wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
+	/*
+	 * Needs both flags. We cannot do with one because resetting it would
+	 * cause a race with write() yet we need to signal a disconnect.
+	 */
+	rv = wait_event_interruptible_timeout(desc->wait,
+			      !test_bit(WDM_IN_USE, &desc->flags) ||
+			      test_bit(WDM_DISCONNECTING, &desc->flags),
+			      timeout);
 
-	/* cannot dereference desc->intf if WDM_DISCONNECTING */
-	if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags))
-		dev_err(&desc->intf->dev, "Error in flush path: %d\n",
-			desc->werr);
+	/*
+	 * To report the correct error. This is best effort.
+	 * We are inevitably racing with the hardware.
+	 */
+	if (test_bit(WDM_DISCONNECTING, &desc->flags))
+		return -ENODEV;
+	if (!rv)
+		return -EIO;
+	if (rv < 0)
+		return -EINTR;
+
+	spin_lock_irq(&desc->iuspin);
+	rv = desc->werr;
+	desc->werr = 0;
+	spin_unlock_irq(&desc->iuspin);
+
+	return usb_translate_errors(rv);
 
-	return usb_translate_errors(desc->werr);
+}
+
+/*
+ * You need to send a signal when you react to malicious or defective hardware.
+ * Also, don't abort when fsync() returned -EINVAL, for older kernels which do
+ * not implement wdm_flush() will return -EINVAL.
+ */
+static int wdm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+	return wdm_wait_for_response(file, MAX_SCHEDULE_TIMEOUT);
+}
+
+/*
+ * Same with wdm_fsync(), except it uses finite timeout in order to react to
+ * malicious or defective hardware which ceased communication after close() was
+ * implicitly called due to process termination.
+ */
+static int wdm_flush(struct file *file, fl_owner_t id)
+{
+	return wdm_wait_for_response(file, WDM_FLUSH_TIMEOUT);
 }
 
 static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait)
@@ -709,6 +761,7 @@
 	.owner =	THIS_MODULE,
 	.read =		wdm_read,
 	.write =	wdm_write,
+	.fsync =	wdm_fsync,
 	.open =		wdm_open,
 	.flush =	wdm_flush,
 	.release =	wdm_release,
@@ -968,8 +1021,6 @@
 	spin_lock_irqsave(&desc->iuspin, flags);
 	set_bit(WDM_DISCONNECTING, &desc->flags);
 	set_bit(WDM_READ, &desc->flags);
-	/* to terminate pending flushes */
-	clear_bit(WDM_IN_USE, &desc->flags);
 	spin_unlock_irqrestore(&desc->iuspin, flags);
 	wake_up_all(&desc->wait);
 	mutex_lock(&desc->rlock);
@@ -1090,7 +1141,7 @@
 	rv = recover_from_urb_loss(desc);
 	mutex_unlock(&desc->wlock);
 	mutex_unlock(&desc->rlock);
-	return 0;
+	return rv;
 }
 
 static struct usb_driver wdm_driver = {
--- linux-4.4.0.orig/drivers/usb/class/usblp.c
+++ linux-4.4.0/drivers/usb/class/usblp.c
@@ -289,8 +289,25 @@
 #define usblp_reset(usblp)\
 	usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
 
-#define usblp_hp_channel_change_request(usblp, channel, buffer) \
-	usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1)
+static int usblp_hp_channel_change_request(struct usblp *usblp, int channel, u8 *new_channel)
+{
+	u8 *buf;
+	int ret;
+
+	buf = kzalloc(1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST,
+			USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE,
+			channel, buf, 1);
+	if (ret == 0)
+		*new_channel = buf[0];
+
+	kfree(buf);
+
+	return ret;
+}
 
 /*
  * See the description for usblp_select_alts() below for the usage
@@ -458,6 +475,7 @@
 	kfree(usblp->readbuf);
 	kfree(usblp->device_id_string);
 	kfree(usblp->statusbuf);
+	usb_put_intf(usblp->intf);
 	kfree(usblp);
 }
 
@@ -474,11 +492,14 @@
 
 	mutex_lock(&usblp_mutex);
 	usblp->used = 0;
-	if (usblp->present) {
+	if (usblp->present)
 		usblp_unlink_urbs(usblp);
-		usb_autopm_put_interface(usblp->intf);
-	} else		/* finish cleanup from disconnect */
-		usblp_cleanup(usblp);
+
+	usb_autopm_put_interface(usblp->intf);
+
+	if (!usblp->present)		/* finish cleanup from disconnect */
+		usblp_cleanup(usblp);	/* any URBs must be dead */
+
 	mutex_unlock(&usblp_mutex);
 	return 0;
 }
@@ -836,6 +857,11 @@
 	if (rv < 0)
 		return rv;
 
+	if (!usblp->present) {
+		count = -ENODEV;
+		goto done;
+	}
+
 	if ((avail = usblp->rstatus) < 0) {
 		printk(KERN_ERR "usblp%d: error %d reading from printer\n",
 		    usblp->minor, (int)avail);
@@ -1118,7 +1144,7 @@
 	init_waitqueue_head(&usblp->wwait);
 	init_usb_anchor(&usblp->urbs);
 	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-	usblp->intf = intf;
+	usblp->intf = usb_get_intf(intf);
 
 	/* Malloc device ID string buffer to the largest expected length,
 	 * since we can re-query it on an ioctl and a dynamic string
@@ -1207,6 +1233,7 @@
 	kfree(usblp->readbuf);
 	kfree(usblp->statusbuf);
 	kfree(usblp->device_id_string);
+	usb_put_intf(usblp->intf);
 	kfree(usblp);
 abort_ret:
 	return retval;
@@ -1322,14 +1349,17 @@
 	if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
 		return -EINVAL;
 
-	alts = usblp->protocol[protocol].alt_setting;
-	if (alts < 0)
-		return -EINVAL;
-	r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
-	if (r < 0) {
-		printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
-			alts, usblp->ifnum);
-		return r;
+	/* Don't unnecessarily set the interface if there's a single alt. */
+	if (usblp->intf->num_altsetting > 1) {
+		alts = usblp->protocol[protocol].alt_setting;
+		if (alts < 0)
+			return -EINVAL;
+		r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
+		if (r < 0) {
+			printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
+				alts, usblp->ifnum);
+			return r;
+		}
 	}
 
 	usblp->bidir = (usblp->protocol[protocol].epread != NULL);
@@ -1393,9 +1423,11 @@
 
 	usblp_unlink_urbs(usblp);
 	mutex_unlock(&usblp->mut);
+	usb_poison_anchored_urbs(&usblp->urbs);
 
 	if (!usblp->used)
 		usblp_cleanup(usblp);
+
 	mutex_unlock(&usblp_mutex);
 }
 
--- linux-4.4.0.orig/drivers/usb/class/usbtmc.c
+++ linux-4.4.0/drivers/usb/class/usbtmc.c
@@ -121,6 +121,7 @@
 	struct usbtmc_device_data *data = to_usbtmc_data(kref);
 
 	usb_put_dev(data->usb_dev);
+	kfree(data);
 }
 
 static int usbtmc_open(struct inode *inode, struct file *filp)
@@ -1104,7 +1105,7 @@
 
 	dev_dbg(&intf->dev, "%s called\n", __func__);
 
-	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -1162,6 +1163,12 @@
 		}
 	}
 
+	if (!data->bulk_out || !data->bulk_in) {
+		dev_err(&intf->dev, "bulk endpoints not found\n");
+		retcode = -ENODEV;
+		goto err_put;
+	}
+
 	retcode = get_capabilities(data);
 	if (retcode)
 		dev_err(&intf->dev, "can't read capabilities\n");
@@ -1185,6 +1192,7 @@
 error_register:
 	sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
 	sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
+err_put:
 	kref_put(&data->kref, usbtmc_delete);
 	return retcode;
 }
--- linux-4.4.0.orig/drivers/usb/common/common.c
+++ linux-4.4.0/drivers/usb/common/common.c
@@ -50,6 +50,7 @@
 	[USB_SPEED_HIGH] = "high-speed",
 	[USB_SPEED_WIRELESS] = "wireless",
 	[USB_SPEED_SUPER] = "super-speed",
+	[USB_SPEED_SUPER_PLUS] = "super-speed-plus",
 };
 
 const char *usb_speed_string(enum usb_device_speed speed)
--- linux-4.4.0.orig/drivers/usb/common/usb-otg-fsm.c
+++ linux-4.4.0/drivers/usb/common/usb-otg-fsm.c
@@ -21,6 +21,7 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/mutex.h>
@@ -365,3 +366,4 @@
 	return state_changed;
 }
 EXPORT_SYMBOL_GPL(otg_statemachine);
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/usb/core/config.c
+++ linux-4.4.0/drivers/usb/core/config.c
@@ -43,6 +43,27 @@
 	return buffer - buffer0;
 }
 
+static void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev,
+		int cfgno, int inum, int asnum, struct usb_host_endpoint *ep,
+		unsigned char *buffer, int size)
+{
+	struct usb_ssp_isoc_ep_comp_descriptor *desc;
+
+	/*
+	 * The SuperSpeedPlus Isoc endpoint companion descriptor immediately
+	 * follows the SuperSpeed Endpoint Companion descriptor
+	 */
+	desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer;
+	if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP ||
+	    size < USB_DT_SSP_ISOC_EP_COMP_SIZE) {
+		dev_warn(ddev, "Invalid SuperSpeedPlus isoc endpoint companion"
+			 "for config %d interface %d altsetting %d ep %d.\n",
+			 cfgno, inum, asnum, ep->desc.bEndpointAddress);
+		return;
+	}
+	memcpy(&ep->ssp_isoc_ep_comp, desc, USB_DT_SSP_ISOC_EP_COMP_SIZE);
+}
+
 static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
 		int inum, int asnum, struct usb_host_endpoint *ep,
 		unsigned char *buffer, int size)
@@ -54,6 +75,7 @@
 	 * be the first thing immediately following the endpoint descriptor.
 	 */
 	desc = (struct usb_ss_ep_comp_descriptor *) buffer;
+
 	if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
 			size < USB_DT_SS_EP_COMP_SIZE) {
 		dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
@@ -76,7 +98,8 @@
 					ep->desc.wMaxPacketSize;
 		return;
 	}
-
+	buffer += desc->bLength;
+	size -= desc->bLength;
 	memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE);
 
 	/* Check the various values */
@@ -112,6 +135,7 @@
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
 		ep->ss_ep_comp.bmAttributes = 16;
 	} else if (usb_endpoint_xfer_isoc(&ep->desc) &&
+		   !USB_SS_SSP_ISOC_COMP(desc->bmAttributes) &&
 		   USB_SS_MULT(desc->bmAttributes) > 3) {
 		dev_warn(ddev, "Isoc endpoint has Mult of %d in "
 				"config %d interface %d altsetting %d ep %d: "
@@ -140,16 +164,100 @@
 				max_tx);
 		ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx);
 	}
+	/* Parse a possible SuperSpeedPlus isoc ep companion descriptor */
+	if (usb_endpoint_xfer_isoc(&ep->desc) &&
+	    USB_SS_SSP_ISOC_COMP(desc->bmAttributes))
+		usb_parse_ssp_isoc_endpoint_companion(ddev, cfgno, inum, asnum,
+							ep, buffer, size);
 }
 
-static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
-    int asnum, struct usb_host_interface *ifp, int num_ep,
-    unsigned char *buffer, int size)
+static const unsigned short low_speed_maxpacket_maxes[4] = {
+	[USB_ENDPOINT_XFER_CONTROL] = 8,
+	[USB_ENDPOINT_XFER_ISOC] = 0,
+	[USB_ENDPOINT_XFER_BULK] = 0,
+	[USB_ENDPOINT_XFER_INT] = 8,
+};
+static const unsigned short full_speed_maxpacket_maxes[4] = {
+	[USB_ENDPOINT_XFER_CONTROL] = 64,
+	[USB_ENDPOINT_XFER_ISOC] = 1023,
+	[USB_ENDPOINT_XFER_BULK] = 64,
+	[USB_ENDPOINT_XFER_INT] = 64,
+};
+static const unsigned short high_speed_maxpacket_maxes[4] = {
+	[USB_ENDPOINT_XFER_CONTROL] = 64,
+	[USB_ENDPOINT_XFER_ISOC] = 1024,
+
+	/* Bulk should be 512, but some devices use 1024: we will warn below */
+	[USB_ENDPOINT_XFER_BULK] = 1024,
+	[USB_ENDPOINT_XFER_INT] = 1024,
+};
+static const unsigned short super_speed_maxpacket_maxes[4] = {
+	[USB_ENDPOINT_XFER_CONTROL] = 512,
+	[USB_ENDPOINT_XFER_ISOC] = 1024,
+	[USB_ENDPOINT_XFER_BULK] = 1024,
+	[USB_ENDPOINT_XFER_INT] = 1024,
+};
+
+static bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1,
+		struct usb_endpoint_descriptor *e2)
 {
+	if (e1->bEndpointAddress == e2->bEndpointAddress)
+		return true;
+
+	if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) {
+		if (usb_endpoint_num(e1) == usb_endpoint_num(e2))
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * Check for duplicate endpoint addresses in other interfaces and in the
+ * altsetting currently being parsed.
+ */
+static bool config_endpoint_is_duplicate(struct usb_host_config *config,
+		int inum, int asnum, struct usb_endpoint_descriptor *d)
+{
+	struct usb_endpoint_descriptor *epd;
+	struct usb_interface_cache *intfc;
+	struct usb_host_interface *alt;
+	int i, j, k;
+
+	for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+		intfc = config->intf_cache[i];
+
+		for (j = 0; j < intfc->num_altsetting; ++j) {
+			alt = &intfc->altsetting[j];
+
+			if (alt->desc.bInterfaceNumber == inum &&
+					alt->desc.bAlternateSetting != asnum)
+				continue;
+
+			for (k = 0; k < alt->desc.bNumEndpoints; ++k) {
+				epd = &alt->endpoint[k].desc;
+
+				if (endpoint_is_duplicate(epd, d))
+					return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+static int usb_parse_endpoint(struct device *ddev, int cfgno,
+		struct usb_host_config *config, int inum, int asnum,
+		struct usb_host_interface *ifp, int num_ep,
+		unsigned char *buffer, int size)
+{
+	struct usb_device *udev = to_usb_device(ddev);
 	unsigned char *buffer0 = buffer;
 	struct usb_endpoint_descriptor *d;
 	struct usb_host_endpoint *endpoint;
 	int n, i, j, retval;
+	unsigned int maxp;
+	const unsigned short *maxpacket_maxes;
 
 	d = (struct usb_endpoint_descriptor *) buffer;
 	buffer += d->bLength;
@@ -178,32 +286,64 @@
 	if (ifp->desc.bNumEndpoints >= num_ep)
 		goto skip_to_next_endpoint_or_interface_descriptor;
 
+	/* Check for duplicate endpoint addresses */
+	if (config_endpoint_is_duplicate(config, inum, asnum, d)) {
+		dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
+				cfgno, inum, asnum, d->bEndpointAddress);
+		goto skip_to_next_endpoint_or_interface_descriptor;
+	}
+
+	/* Ignore blacklisted endpoints */
+	if (udev->quirks & USB_QUIRK_ENDPOINT_BLACKLIST) {
+		if (usb_endpoint_is_blacklisted(udev, ifp, d)) {
+			dev_warn(ddev, "config %d interface %d altsetting %d has a blacklisted endpoint with address 0x%X, skipping\n",
+					cfgno, inum, asnum,
+					d->bEndpointAddress);
+			goto skip_to_next_endpoint_or_interface_descriptor;
+		}
+	}
+
 	endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
 	++ifp->desc.bNumEndpoints;
 
 	memcpy(&endpoint->desc, d, n);
 	INIT_LIST_HEAD(&endpoint->urb_list);
 
-	/* Fix up bInterval values outside the legal range. Use 32 ms if no
-	 * proper value can be guessed. */
+	/*
+	 * Fix up bInterval values outside the legal range.
+	 * Use 10 or 8 ms if no proper value can be guessed.
+	 */
 	i = 0;		/* i = min, j = max, n = default */
 	j = 255;
 	if (usb_endpoint_xfer_int(d)) {
 		i = 1;
 		switch (to_usb_device(ddev)->speed) {
+		case USB_SPEED_SUPER_PLUS:
 		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
-			/* Many device manufacturers are using full-speed
+			/*
+			 * Many device manufacturers are using full-speed
 			 * bInterval values in high-speed interrupt endpoint
-			 * descriptors. Try to fix those and fall back to a
-			 * 32 ms default value otherwise. */
+			 * descriptors. Try to fix those and fall back to an
+			 * 8-ms default value otherwise.
+			 */
 			n = fls(d->bInterval*8);
 			if (n == 0)
-				n = 9;	/* 32 ms = 2^(9-1) uframes */
+				n = 7;	/* 8 ms = 2^(7-1) uframes */
 			j = 16;
 
 			/*
 			 * Adjust bInterval for quirked devices.
+			 */
+			/*
+			 * This quirk fixes bIntervals reported in ms.
+			 */
+			if (to_usb_device(ddev)->quirks &
+				USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
+				n = clamp(fls(d->bInterval) + 3, i, j);
+				i = j = n;
+			}
+			/*
 			 * This quirk fixes bIntervals reported in
 			 * linear microframes.
 			 */
@@ -214,10 +354,12 @@
 			}
 			break;
 		default:		/* USB_SPEED_FULL or _LOW */
-			/* For low-speed, 10 ms is the official minimum.
+			/*
+			 * For low-speed, 10 ms is the official minimum.
 			 * But some "overclocked" devices might want faster
-			 * polling so we'll allow it. */
-			n = 32;
+			 * polling so we'll allow it.
+			 */
+			n = 10;
 			break;
 		}
 	} else if (usb_endpoint_xfer_isoc(d)) {
@@ -225,10 +367,10 @@
 		j = 16;
 		switch (to_usb_device(ddev)->speed) {
 		case USB_SPEED_HIGH:
-			n = 9;		/* 32 ms = 2^(9-1) uframes */
+			n = 7;		/* 8 ms = 2^(7-1) uframes */
 			break;
 		default:		/* USB_SPEED_FULL */
-			n = 6;		/* 32 ms = 2^(6-1) frames */
+			n = 4;		/* 8 ms = 2^(4-1) frames */
 			break;
 		}
 	}
@@ -257,15 +399,57 @@
 	}
 
 	/*
+	 * Validate the wMaxPacketSize field.
+	 * Some devices have isochronous endpoints in altsetting 0;
+	 * the USB-2 spec requires such endpoints to have wMaxPacketSize = 0
+	 * (see the end of section 5.6.3), so don't warn about them.
+	 */
+	maxp = usb_endpoint_maxp(&endpoint->desc);
+	if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) {
+		dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
+		    cfgno, inum, asnum, d->bEndpointAddress);
+	}
+
+	/* Find the highest legal maxpacket size for this endpoint */
+	i = 0;		/* additional transactions per microframe */
+	switch (to_usb_device(ddev)->speed) {
+	case USB_SPEED_LOW:
+		maxpacket_maxes = low_speed_maxpacket_maxes;
+		break;
+	case USB_SPEED_FULL:
+		maxpacket_maxes = full_speed_maxpacket_maxes;
+		break;
+	case USB_SPEED_HIGH:
+		/* Bits 12..11 are allowed only for HS periodic endpoints */
+		if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) {
+			i = maxp & (BIT(12) | BIT(11));
+			maxp &= ~i;
+		}
+		/* fallthrough */
+	default:
+		maxpacket_maxes = high_speed_maxpacket_maxes;
+		break;
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+		maxpacket_maxes = super_speed_maxpacket_maxes;
+		break;
+	}
+	j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)];
+
+	if (maxp > j) {
+		dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
+		    cfgno, inum, asnum, d->bEndpointAddress, maxp, j);
+		maxp = j;
+		endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp);
+	}
+
+	/*
 	 * Some buggy high speed devices have bulk endpoints using
 	 * maxpacket sizes other than 512.  High speed HCDs may not
 	 * be able to handle that particular bug, so let's warn...
 	 */
 	if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
 			&& usb_endpoint_xfer_bulk(d)) {
-		unsigned maxp;
-
-		maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
 		if (maxp != 512)
 			dev_warn(ddev, "config %d interface %d altsetting %d "
 				"bulk endpoint 0x%X has invalid maxpacket %d\n",
@@ -274,7 +458,7 @@
 	}
 
 	/* Parse a possible SuperSpeed endpoint companion descriptor */
-	if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
+	if (to_usb_device(ddev)->speed >= USB_SPEED_SUPER)
 		usb_parse_ss_endpoint_companion(ddev, cfgno,
 				inum, asnum, endpoint, buffer, size);
 
@@ -394,8 +578,8 @@
 		if (((struct usb_descriptor_header *) buffer)->bDescriptorType
 		     == USB_DT_INTERFACE)
 			break;
-		retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,
-		    num_ep, buffer, size);
+		retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum,
+				alt, num_ep, buffer, size);
 		if (retval < 0)
 			return retval;
 		++n;
@@ -434,6 +618,9 @@
 	unsigned iad_num = 0;
 
 	memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
+	nintf = nintf_orig = config->desc.bNumInterfaces;
+	config->desc.bNumInterfaces = 0;	// Adjusted later
+
 	if (config->desc.bDescriptorType != USB_DT_CONFIG ||
 	    config->desc.bLength < USB_DT_CONFIG_SIZE ||
 	    config->desc.bLength > size) {
@@ -447,7 +634,6 @@
 	buffer += config->desc.bLength;
 	size -= config->desc.bLength;
 
-	nintf = nintf_orig = config->desc.bNumInterfaces;
 	if (nintf > USB_MAXINTERFACES) {
 		dev_warn(ddev, "config %d has too many interfaces: %d, "
 		    "using maximum allowed: %d\n",
@@ -522,15 +708,23 @@
 
 		} else if (header->bDescriptorType ==
 				USB_DT_INTERFACE_ASSOCIATION) {
+			struct usb_interface_assoc_descriptor *d;
+
+			d = (struct usb_interface_assoc_descriptor *)header;
+			if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
+				dev_warn(ddev,
+					 "config %d has an invalid interface association descriptor of length %d, skipping\n",
+					 cfgno, d->bLength);
+				continue;
+			}
+
 			if (iad_num == USB_MAXIADS) {
 				dev_warn(ddev, "found more Interface "
 					       "Association Descriptors "
 					       "than allocated for in "
 					       "configuration %d\n", cfgno);
 			} else {
-				config->intf_assoc[iad_num] =
-					(struct usb_interface_assoc_descriptor
-					*)header;
+				config->intf_assoc[iad_num] = d;
 				iad_num++;
 			}
 
@@ -731,7 +925,7 @@
 		}
 
 		if (dev->quirks & USB_QUIRK_DELAY_INIT)
-			msleep(100);
+			msleep(200);
 
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
 		    bigbuffer, length);
@@ -776,14 +970,25 @@
 	}
 }
 
+static const __u8 bos_desc_len[256] = {
+	[USB_CAP_TYPE_WIRELESS_USB] = USB_DT_USB_WIRELESS_CAP_SIZE,
+	[USB_CAP_TYPE_EXT]          = USB_DT_USB_EXT_CAP_SIZE,
+	[USB_SS_CAP_TYPE]           = USB_DT_USB_SS_CAP_SIZE,
+	[USB_SSP_CAP_TYPE]          = USB_DT_USB_SSP_CAP_SIZE(1),
+	[CONTAINER_ID_TYPE]         = USB_DT_USB_SS_CONTN_ID_SIZE,
+	[USB_PTM_CAP_TYPE]          = USB_DT_USB_PTM_ID_SIZE,
+};
+
 /* Get BOS descriptor set */
 int usb_get_bos_descriptor(struct usb_device *dev)
 {
 	struct device *ddev = &dev->dev;
 	struct usb_bos_descriptor *bos;
 	struct usb_dev_cap_header *cap;
-	unsigned char *buffer;
-	int length, total_len, num, i;
+	struct usb_ssp_cap_descriptor *ssp_cap;
+	unsigned char *buffer, *buffer0;
+	int length, total_len, num, i, ssac;
+	__u8 cap_type;
 	int ret;
 
 	bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
@@ -792,8 +997,8 @@
 
 	/* Get BOS descriptor */
 	ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
-	if (ret < USB_DT_BOS_SIZE) {
-		dev_err(ddev, "unable to get BOS descriptor\n");
+	if (ret < USB_DT_BOS_SIZE || bos->bLength < USB_DT_BOS_SIZE) {
+		dev_err(ddev, "unable to get BOS descriptor or descriptor too short\n");
 		if (ret >= 0)
 			ret = -ENOMSG;
 		kfree(bos);
@@ -826,23 +1031,31 @@
 			ret = -ENOMSG;
 		goto err;
 	}
+
+	buffer0 = buffer;
 	total_len -= length;
+	buffer += length;
 
 	for (i = 0; i < num; i++) {
-		buffer += length;
 		cap = (struct usb_dev_cap_header *)buffer;
-		length = cap->bLength;
 
-		if (total_len < length)
+		if (total_len < sizeof(*cap) || total_len < cap->bLength) {
+			dev->bos->desc->bNumDeviceCaps = i;
 			break;
-		total_len -= length;
+		}
+		cap_type = cap->bDevCapabilityType;
+		length = cap->bLength;
+		if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) {
+			dev->bos->desc->bNumDeviceCaps = i;
+			break;
+		}
 
 		if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
 			dev_warn(ddev, "descriptor type invalid, skip\n");
 			continue;
 		}
 
-		switch (cap->bDevCapabilityType) {
+		switch (cap_type) {
 		case USB_CAP_TYPE_WIRELESS_USB:
 			/* Wireless USB cap descriptor is handled by wusb */
 			break;
@@ -855,17 +1068,27 @@
 				(struct usb_ss_cap_descriptor *)buffer;
 			break;
 		case USB_SSP_CAP_TYPE:
-			dev->bos->ssp_cap =
-				(struct usb_ssp_cap_descriptor *)buffer;
+			ssp_cap = (struct usb_ssp_cap_descriptor *)buffer;
+			ssac = (le32_to_cpu(ssp_cap->bmAttributes) &
+				USB_SSP_SUBLINK_SPEED_ATTRIBS);
+			if (length >= USB_DT_USB_SSP_CAP_SIZE(ssac))
+				dev->bos->ssp_cap = ssp_cap;
 			break;
 		case CONTAINER_ID_TYPE:
 			dev->bos->ss_id =
 				(struct usb_ss_container_id_descriptor *)buffer;
 			break;
+		case USB_PTM_CAP_TYPE:
+			dev->bos->ptm_cap =
+				(struct usb_ptm_cap_descriptor *)buffer;
 		default:
 			break;
 		}
+
+		total_len -= length;
+		buffer += length;
 	}
+	dev->bos->desc->wTotalLength = cpu_to_le16(buffer - buffer0);
 
 	return 0;
 
--- linux-4.4.0.orig/drivers/usb/core/devices.c
+++ linux-4.4.0/drivers/usb/core/devices.c
@@ -221,7 +221,7 @@
 		break;
 	case USB_ENDPOINT_XFER_INT:
 		type = "Int.";
-		if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER)
+		if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER)
 			interval = 1 << (desc->bInterval - 1);
 		else
 			interval = desc->bInterval;
@@ -230,7 +230,7 @@
 		return start;
 	}
 	interval *= (speed == USB_SPEED_HIGH ||
-		     speed == USB_SPEED_SUPER) ? 125 : 1000;
+		     speed >= USB_SPEED_SUPER) ? 125 : 1000;
 	if (interval % 1000)
 		unit = 'u';
 	else {
@@ -322,7 +322,7 @@
 
 	if (start > end)
 		return start;
-	if (speed == USB_SPEED_SUPER)
+	if (speed >= USB_SPEED_SUPER)
 		mul = 8;
 	else
 		mul = 2;
@@ -534,6 +534,8 @@
 		speed = "480"; break;
 	case USB_SPEED_SUPER:
 		speed = "5000"; break;
+	case USB_SPEED_SUPER_PLUS:
+		speed = "10000"; break;
 	default:
 		speed = "??";
 	}
@@ -553,7 +555,7 @@
 
 		/* super/high speed reserves 80%, full/low reserves 90% */
 		if (usbdev->speed == USB_SPEED_HIGH ||
-		    usbdev->speed == USB_SPEED_SUPER)
+		    usbdev->speed >= USB_SPEED_SUPER)
 			max = 800;
 		else
 			max = FRAME_TIME_MAX_USECS_ALLOC;
--- linux-4.4.0.orig/drivers/usb/core/devio.c
+++ linux-4.4.0/drivers/usb/core/devio.c
@@ -113,42 +113,38 @@
 #define USB_DEVICE_DEV		MKDEV(USB_DEVICE_MAJOR, 0)
 
 /* Limit on the total amount of memory we can allocate for transfers */
-static unsigned usbfs_memory_mb = 16;
+static u32 usbfs_memory_mb = 16;
 module_param(usbfs_memory_mb, uint, 0644);
 MODULE_PARM_DESC(usbfs_memory_mb,
 		"maximum MB allowed for usbfs buffers (0 = no limit)");
 
 /* Hard limit, necessary to avoid arithmetic overflow */
-#define USBFS_XFER_MAX		(UINT_MAX / 2 - 1000000)
+#define USBFS_XFER_MAX         (UINT_MAX / 2 - 1000000)
 
-static atomic_t usbfs_memory_usage;	/* Total memory currently allocated */
+static atomic64_t usbfs_memory_usage;	/* Total memory currently allocated */
 
 /* Check whether it's okay to allocate more memory for a transfer */
-static int usbfs_increase_memory_usage(unsigned amount)
+static int usbfs_increase_memory_usage(u64 amount)
 {
-	unsigned lim;
+	u64 lim;
 
-	/*
-	 * Convert usbfs_memory_mb to bytes, avoiding overflows.
-	 * 0 means use the hard limit (effectively unlimited).
-	 */
 	lim = ACCESS_ONCE(usbfs_memory_mb);
-	if (lim == 0 || lim > (USBFS_XFER_MAX >> 20))
-		lim = USBFS_XFER_MAX;
-	else
-		lim <<= 20;
+	lim <<= 20;
 
-	atomic_add(amount, &usbfs_memory_usage);
-	if (atomic_read(&usbfs_memory_usage) <= lim)
-		return 0;
-	atomic_sub(amount, &usbfs_memory_usage);
-	return -ENOMEM;
+	atomic64_add(amount, &usbfs_memory_usage);
+
+	if (lim > 0 && atomic64_read(&usbfs_memory_usage) > lim) {
+		atomic64_sub(amount, &usbfs_memory_usage);
+		return -ENOMEM;
+	}
+
+	return 0;
 }
 
 /* Memory for a transfer is being deallocated */
-static void usbfs_decrease_memory_usage(unsigned amount)
+static void usbfs_decrease_memory_usage(u64 amount)
 {
-	atomic_sub(amount, &usbfs_memory_usage);
+	atomic64_sub(amount, &usbfs_memory_usage);
 }
 
 static int connected(struct usb_dev_state *ps)
@@ -373,11 +369,11 @@
 
 	if (userurb) {		/* Async */
 		if (when == SUBMIT)
-			dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
+			dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
 					"length %u\n",
 					userurb, ep, t, d, length);
 		else
-			dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
+			dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
 					"actual_length %u status %d\n",
 					userurb, ep, t, d, length,
 					timeout_or_status);
@@ -519,6 +515,8 @@
 	if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
 			as->status != -ENOENT)
 		cancel_bulk_urbs(ps, as->bulk_addr);
+
+	wake_up(&ps->wait);
 	spin_unlock(&ps->lock);
 
 	if (signr) {
@@ -526,8 +524,6 @@
 		put_pid(pid);
 		put_cred(cred);
 	}
-
-	wake_up(&ps->wait);
 }
 
 static void destroy_async(struct usb_dev_state *ps, struct list_head *list)
@@ -1077,7 +1073,7 @@
 	if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
 		return -EINVAL;
 	len1 = bulk.len;
-	if (len1 >= USBFS_XFER_MAX)
+	if (len1 >= (INT_MAX - sizeof(struct urb)))
 		return -EINVAL;
 	ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
 	if (ret)
@@ -1203,10 +1199,11 @@
 
 static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
 {
-	struct usbdevfs_connectinfo ci = {
-		.devnum = ps->dev->devnum,
-		.slow = ps->dev->speed == USB_SPEED_LOW
-	};
+	struct usbdevfs_connectinfo ci;
+
+	memset(&ci, 0, sizeof(ci));
+	ci.devnum = ps->dev->devnum;
+	ci.slow = ps->dev->speed == USB_SPEED_LOW;
 
 	if (copy_to_user(arg, &ci, sizeof(ci)))
 		return -EFAULT;
@@ -1292,17 +1289,26 @@
 	struct async *as = NULL;
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
-	int i, ret, is_in, num_sgs = 0, ifnum = -1;
+	int i, ret, num_sgs = 0, ifnum = -1;
 	int number_of_packets = 0;
 	unsigned int stream_id = 0;
 	void *buf;
-
-	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
-				USBDEVFS_URB_SHORT_NOT_OK |
+	bool is_in;
+	bool allow_short = false;
+	bool allow_zero = false;
+	unsigned long mask =	USBDEVFS_URB_SHORT_NOT_OK |
 				USBDEVFS_URB_BULK_CONTINUATION |
 				USBDEVFS_URB_NO_FSBR |
 				USBDEVFS_URB_ZERO_PACKET |
-				USBDEVFS_URB_NO_INTERRUPT))
+				USBDEVFS_URB_NO_INTERRUPT;
+	/* USBDEVFS_URB_ISO_ASAP is a special case */
+	if (uurb->type == USBDEVFS_URB_TYPE_ISO)
+		mask |= USBDEVFS_URB_ISO_ASAP;
+
+	if (uurb->flags & ~mask)
+			return -EINVAL;
+
+	if ((unsigned int)uurb->buffer_length >= USBFS_XFER_MAX)
 		return -EINVAL;
 	if (uurb->buffer_length > 0 && !uurb->buffer)
 		return -EINVAL;
@@ -1352,6 +1358,8 @@
 			is_in = 0;
 			uurb->endpoint &= ~USB_DIR_IN;
 		}
+		if (is_in)
+			allow_short = true;
 		snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
 			"bRequest=%02x wValue=%04x "
 			"wIndex=%04x wLength=%04x\n",
@@ -1363,6 +1371,10 @@
 		break;
 
 	case USBDEVFS_URB_TYPE_BULK:
+		if (!is_in)
+			allow_zero = true;
+		else
+			allow_short = true;
 		switch (usb_endpoint_type(&ep->desc)) {
 		case USB_ENDPOINT_XFER_CONTROL:
 		case USB_ENDPOINT_XFER_ISOC:
@@ -1383,6 +1395,10 @@
 		if (!usb_endpoint_xfer_int(&ep->desc))
 			return -EINVAL;
  interrupt_urb:
+		if (!is_in)
+			allow_zero = true;
+		else
+			allow_short = true;
 		break;
 
 	case USBDEVFS_URB_TYPE_ISO:
@@ -1423,10 +1439,6 @@
 		return -EINVAL;
 	}
 
-	if (uurb->buffer_length >= USBFS_XFER_MAX) {
-		ret = -EINVAL;
-		goto error;
-	}
 	if (uurb->buffer_length > 0 &&
 			!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
 				uurb->buffer, uurb->buffer_length)) {
@@ -1513,27 +1525,38 @@
 	u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
 	if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
 		u |= URB_ISO_ASAP;
-	if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in)
+	if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
 		u |= URB_SHORT_NOT_OK;
 	if (uurb->flags & USBDEVFS_URB_NO_FSBR)
 		u |= URB_NO_FSBR;
-	if (uurb->flags & USBDEVFS_URB_ZERO_PACKET)
+	if (allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
 		u |= URB_ZERO_PACKET;
 	if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
 		u |= URB_NO_INTERRUPT;
 	as->urb->transfer_flags = u;
 
+	if (!allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
+		dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_SHORT_NOT_OK.\n");
+	if (!allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
+		dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_ZERO_PACKET.\n");
+
 	as->urb->transfer_buffer_length = uurb->buffer_length;
 	as->urb->setup_packet = (unsigned char *)dr;
 	dr = NULL;
 	as->urb->start_frame = uurb->start_frame;
 	as->urb->number_of_packets = number_of_packets;
 	as->urb->stream_id = stream_id;
-	if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
-			ps->dev->speed == USB_SPEED_HIGH)
-		as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
-	else
-		as->urb->interval = ep->desc.bInterval;
+
+	if (ep->desc.bInterval) {
+		if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
+				ps->dev->speed == USB_SPEED_HIGH ||
+				ps->dev->speed >= USB_SPEED_SUPER)
+			as->urb->interval = 1 <<
+					min(15, ep->desc.bInterval - 1);
+		else
+			as->urb->interval = ep->desc.bInterval;
+	}
+
 	as->urb->context = as;
 	as->urb->complete = async_completed;
 	for (totlen = u = 0; u < number_of_packets; u++) {
@@ -1646,6 +1669,18 @@
 	return 0;
 }
 
+static void compute_isochronous_actual_length(struct urb *urb)
+{
+	unsigned int i;
+
+	if (urb->number_of_packets > 0) {
+		urb->actual_length = 0;
+		for (i = 0; i < urb->number_of_packets; i++)
+			urb->actual_length +=
+					urb->iso_frame_desc[i].actual_length;
+	}
+}
+
 static int processcompl(struct async *as, void __user * __user *arg)
 {
 	struct urb *urb = as->urb;
@@ -1653,6 +1688,7 @@
 	void __user *addr = as->userurb;
 	unsigned int i;
 
+	compute_isochronous_actual_length(urb);
 	if (as->userbuffer && urb->actual_length) {
 		if (copy_urb_data_to_user(as->userbuffer, urb))
 			goto err_out;
@@ -1822,6 +1858,7 @@
 	void __user *addr = as->userurb;
 	unsigned int i;
 
+	compute_isochronous_actual_length(urb);
 	if (as->userbuffer && urb->actual_length) {
 		if (copy_urb_data_to_user(as->userbuffer, urb))
 			return -EFAULT;
--- linux-4.4.0.orig/drivers/usb/core/driver.c
+++ linux-4.4.0/drivers/usb/core/driver.c
@@ -284,7 +284,7 @@
 	struct usb_device *udev = interface_to_usbdev(intf);
 	const struct usb_device_id *id;
 	int error = -ENODEV;
-	int lpm_disable_error;
+	int lpm_disable_error = -ENODEV;
 
 	dev_dbg(dev, "%s\n", __func__);
 
@@ -336,12 +336,14 @@
 	 * setting during probe, that should also be fine.  usb_set_interface()
 	 * will attempt to disable LPM, and fail if it can't disable it.
 	 */
-	lpm_disable_error = usb_unlocked_disable_lpm(udev);
-	if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
-		dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
-				__func__, driver->name);
-		error = lpm_disable_error;
-		goto err;
+	if (driver->disable_hub_initiated_lpm) {
+		lpm_disable_error = usb_unlocked_disable_lpm(udev);
+		if (lpm_disable_error) {
+			dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
+					__func__, driver->name);
+			error = lpm_disable_error;
+			goto err;
+		}
 	}
 
 	/* Carry out a deferred switch to altsetting 0 */
@@ -391,7 +393,8 @@
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_host_endpoint *ep, **eps = NULL;
 	struct usb_device *udev;
-	int i, j, error, r, lpm_disable_error;
+	int i, j, error, r;
+	int lpm_disable_error = -ENODEV;
 
 	intf->condition = USB_INTERFACE_UNBINDING;
 
@@ -399,12 +402,13 @@
 	udev = interface_to_usbdev(intf);
 	error = usb_autoresume_device(udev);
 
-	/* Hub-initiated LPM policy may change, so attempt to disable LPM until
+	/* If hub-initiated LPM policy may change, attempt to disable LPM until
 	 * the driver is unbound.  If LPM isn't disabled, that's fine because it
 	 * wouldn't be enabled unless all the bound interfaces supported
 	 * hub-initiated LPM.
 	 */
-	lpm_disable_error = usb_unlocked_disable_lpm(udev);
+	if (driver->disable_hub_initiated_lpm)
+		lpm_disable_error = usb_unlocked_disable_lpm(udev);
 
 	/*
 	 * Terminate all URBs for this interface unless the driver
@@ -466,11 +470,6 @@
 		pm_runtime_disable(dev);
 	pm_runtime_set_suspended(dev);
 
-	/* Undo any residual pm_autopm_get_interface_* calls */
-	for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r)
-		usb_autopm_put_interface_no_suspend(intf);
-	atomic_set(&intf->pm_usage_cnt, 0);
-
 	if (!error)
 		usb_autosuspend_device(udev);
 
@@ -502,11 +501,14 @@
 int usb_driver_claim_interface(struct usb_driver *driver,
 				struct usb_interface *iface, void *priv)
 {
-	struct device *dev = &iface->dev;
+	struct device *dev;
 	struct usb_device *udev;
 	int retval = 0;
-	int lpm_disable_error;
 
+	if (!iface)
+		return -ENODEV;
+
+	dev = &iface->dev;
 	if (dev->driver)
 		return -EBUSY;
 
@@ -522,14 +524,6 @@
 
 	iface->condition = USB_INTERFACE_BOUND;
 
-	/* Disable LPM until this driver is bound. */
-	lpm_disable_error = usb_unlocked_disable_lpm(udev);
-	if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
-		dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
-				__func__, driver->name);
-		return -ENOMEM;
-	}
-
 	/* Claimed interfaces are initially inactive (suspended) and
 	 * runtime-PM-enabled, but only if the driver has autosuspend
 	 * support.  Otherwise they are marked active, to prevent the
@@ -548,9 +542,20 @@
 	if (device_is_registered(dev))
 		retval = device_bind_driver(dev);
 
-	/* Attempt to re-enable USB3 LPM, if the disable was successful. */
-	if (!lpm_disable_error)
-		usb_unlocked_enable_lpm(udev);
+	if (retval) {
+		dev->driver = NULL;
+		usb_set_intfdata(iface, NULL);
+		iface->needs_remote_wakeup = 0;
+		iface->condition = USB_INTERFACE_UNBOUND;
+
+		/*
+		 * Unbound interfaces are always runtime-PM-disabled
+		 * and runtime-PM-suspended
+		 */
+		if (driver->supports_autosuspend)
+			pm_runtime_disable(dev);
+		pm_runtime_set_suspended(dev);
+	}
 
 	return retval;
 }
@@ -1318,6 +1323,24 @@
 		 */
 		if (udev->parent && !PMSG_IS_AUTO(msg))
 			status = 0;
+
+		/*
+		 * If the device is inaccessible, don't try to resume
+		 * suspended interfaces and just return the error.
+		 */
+		if (status && status != -EBUSY) {
+			int err;
+			u16 devstat;
+
+			err = usb_get_status(udev, USB_RECIP_DEVICE, 0,
+					     &devstat);
+			if (err) {
+				dev_err(&udev->dev,
+					"Failed to suspend device, error %d\n",
+					status);
+				goto done;
+			}
+		}
 	}
 
 	/* If the suspend failed, resume interfaces that did get suspended */
@@ -1597,7 +1620,6 @@
 	int			status;
 
 	usb_mark_last_busy(udev);
-	atomic_dec(&intf->pm_usage_cnt);
 	status = pm_runtime_put_sync(&intf->dev);
 	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
 			__func__, atomic_read(&intf->dev.power.usage_count),
@@ -1626,7 +1648,6 @@
 	int			status;
 
 	usb_mark_last_busy(udev);
-	atomic_dec(&intf->pm_usage_cnt);
 	status = pm_runtime_put(&intf->dev);
 	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
 			__func__, atomic_read(&intf->dev.power.usage_count),
@@ -1648,7 +1669,6 @@
 	struct usb_device	*udev = interface_to_usbdev(intf);
 
 	usb_mark_last_busy(udev);
-	atomic_dec(&intf->pm_usage_cnt);
 	pm_runtime_put_noidle(&intf->dev);
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
@@ -1679,8 +1699,6 @@
 	status = pm_runtime_get_sync(&intf->dev);
 	if (status < 0)
 		pm_runtime_put_sync(&intf->dev);
-	else
-		atomic_inc(&intf->pm_usage_cnt);
 	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
 			__func__, atomic_read(&intf->dev.power.usage_count),
 			status);
@@ -1714,8 +1732,6 @@
 	status = pm_runtime_get(&intf->dev);
 	if (status < 0 && status != -EINPROGRESS)
 		pm_runtime_put_noidle(&intf->dev);
-	else
-		atomic_inc(&intf->pm_usage_cnt);
 	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
 			__func__, atomic_read(&intf->dev.power.usage_count),
 			status);
@@ -1739,7 +1755,6 @@
 	struct usb_device	*udev = interface_to_usbdev(intf);
 
 	usb_mark_last_busy(udev);
-	atomic_inc(&intf->pm_usage_cnt);
 	pm_runtime_get_noresume(&intf->dev);
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
@@ -1750,6 +1765,9 @@
 	int			w, i;
 	struct usb_interface	*intf;
 
+	if (udev->state == USB_STATE_NOTATTACHED)
+		return -ENODEV;
+
 	/* Fail if autosuspend is disabled, or any interfaces are in use, or
 	 * any interface drivers require remote wakeup but it isn't available.
 	 */
@@ -1857,14 +1875,11 @@
 	return -EBUSY;
 }
 
-int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
 {
 	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
 	int ret = -EPERM;
 
-	if (enable && !udev->usb2_hw_lpm_allowed)
-		return 0;
-
 	if (hcd->driver->set_usb2_hw_lpm) {
 		ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
 		if (!ret)
@@ -1874,6 +1889,24 @@
 	return ret;
 }
 
+int usb_enable_usb2_hardware_lpm(struct usb_device *udev)
+{
+	if (!udev->usb2_hw_lpm_capable ||
+	    !udev->usb2_hw_lpm_allowed ||
+	    udev->usb2_hw_lpm_enabled)
+		return 0;
+
+	return usb_set_usb2_hardware_lpm(udev, 1);
+}
+
+int usb_disable_usb2_hardware_lpm(struct usb_device *udev)
+{
+	if (!udev->usb2_hw_lpm_enabled)
+		return 0;
+
+	return usb_set_usb2_hardware_lpm(udev, 0);
+}
+
 #endif /* CONFIG_PM */
 
 struct bus_type usb_bus_type = {
--- linux-4.4.0.orig/drivers/usb/core/file.c
+++ linux-4.4.0/drivers/usb/core/file.c
@@ -26,6 +26,7 @@
 #define MAX_USB_MINORS	256
 static const struct file_operations *usb_minors[MAX_USB_MINORS];
 static DECLARE_RWSEM(minor_rwsem);
+static DEFINE_MUTEX(init_usb_class_mutex);
 
 static int usb_open(struct inode *inode, struct file *file)
 {
@@ -108,8 +109,9 @@
 
 static void destroy_usb_class(void)
 {
-	if (usb_class)
-		kref_put(&usb_class->kref, release_usb_class);
+	mutex_lock(&init_usb_class_mutex);
+	kref_put(&usb_class->kref, release_usb_class);
+	mutex_unlock(&init_usb_class_mutex);
 }
 
 int usb_major_init(void)
@@ -171,7 +173,10 @@
 	if (intf->minor >= 0)
 		return -EADDRINUSE;
 
+	mutex_lock(&init_usb_class_mutex);
 	retval = init_usb_class();
+	mutex_unlock(&init_usb_class_mutex);
+
 	if (retval)
 		return retval;
 
@@ -186,9 +191,10 @@
 		intf->minor = minor;
 		break;
 	}
-	up_write(&minor_rwsem);
-	if (intf->minor < 0)
+	if (intf->minor < 0) {
+		up_write(&minor_rwsem);
 		return -EXFULL;
+	}
 
 	/* create a usb class device for this usb interface */
 	snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
@@ -201,12 +207,11 @@
 				      MKDEV(USB_MAJOR, minor), class_driver,
 				      "%s", temp);
 	if (IS_ERR(intf->usb_dev)) {
-		down_write(&minor_rwsem);
 		usb_minors[minor] = NULL;
 		intf->minor = -1;
-		up_write(&minor_rwsem);
 		retval = PTR_ERR(intf->usb_dev);
 	}
+	up_write(&minor_rwsem);
 	return retval;
 }
 EXPORT_SYMBOL_GPL(usb_register_dev);
@@ -232,12 +237,12 @@
 		return;
 
 	dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
+	device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
 
 	down_write(&minor_rwsem);
 	usb_minors[intf->minor] = NULL;
 	up_write(&minor_rwsem);
 
-	device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
 	intf->usb_dev = NULL;
 	intf->minor = -1;
 	destroy_usb_class();
--- linux-4.4.0.orig/drivers/usb/core/generic.c
+++ linux-4.4.0/drivers/usb/core/generic.c
@@ -208,8 +208,13 @@
 	if (!udev->parent)
 		rc = hcd_bus_suspend(udev, msg);
 
-	/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
-	else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+	/*
+	 * Non-root USB2 devices don't need to do anything for FREEZE
+	 * or PRETHAW. USB3 devices don't support global suspend and
+	 * needs to be selectively suspended.
+	 */
+	else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+		 && (udev->speed < USB_SPEED_SUPER))
 		rc = 0;
 	else
 		rc = usb_port_suspend(udev, msg);
--- linux-4.4.0.orig/drivers/usb/core/hcd-pci.c
+++ linux-4.4.0/drivers/usb/core/hcd-pci.c
@@ -74,6 +74,15 @@
 		if (companion->bus != pdev->bus ||
 				PCI_SLOT(companion->devfn) != slot)
 			continue;
+
+		/*
+		 * Companion device should be either UHCI,OHCI or EHCI host
+		 * controller, otherwise skip.
+		 */
+		if (companion->class != CL_UHCI && companion->class != CL_OHCI &&
+				companion->class != CL_EHCI)
+			continue;
+
 		companion_hcd = pci_get_drvdata(companion);
 		if (!companion_hcd || !companion_hcd->self.root_hub)
 			continue;
@@ -197,7 +206,7 @@
 	 * The xHCI driver has its own irq management
 	 * make sure irq setup is not touched for xhci in generic hcd code
 	 */
-	if ((driver->flags & HCD_MASK) != HCD_USB3) {
+	if ((driver->flags & HCD_MASK) < HCD_USB3) {
 		if (!dev->irq) {
 			dev_err(&dev->dev,
 			"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
@@ -520,8 +529,6 @@
 				event == PM_EVENT_RESTORE);
 		if (retval) {
 			dev_err(dev, "PCI post-resume error %d!\n", retval);
-			if (hcd->shared_hcd)
-				usb_hc_died(hcd->shared_hcd);
 			usb_hc_died(hcd);
 		}
 	}
--- linux-4.4.0.orig/drivers/usb/core/hcd.c
+++ linux-4.4.0/drivers/usb/core/hcd.c
@@ -128,6 +128,27 @@
 #define KERNEL_REL	bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff))
 #define KERNEL_VER	bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff))
 
+/* usb 3.1 root hub device descriptor */
+static const u8 usb31_rh_dev_descriptor[18] = {
+	0x12,       /*  __u8  bLength; */
+	USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
+	0x10, 0x03, /*  __le16 bcdUSB; v3.1 */
+
+	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*  __u8  bDeviceSubClass; */
+	0x03,       /*  __u8  bDeviceProtocol; USB 3 hub */
+	0x09,       /*  __u8  bMaxPacketSize0; 2^9 = 512 Bytes */
+
+	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */
+	0x03, 0x00, /*  __le16 idProduct; device 0x0003 */
+	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
+
+	0x03,       /*  __u8  iManufacturer; */
+	0x02,       /*  __u8  iProduct; */
+	0x01,       /*  __u8  iSerialNumber; */
+	0x01        /*  __u8  bNumConfigurations; */
+};
+
 /* usb 3.0 root hub device descriptor */
 static const u8 usb3_rh_dev_descriptor[18] = {
 	0x12,       /*  __u8  bLength; */
@@ -499,8 +520,10 @@
 	 */
 	tbuf_size =  max_t(u16, sizeof(struct usb_hub_descriptor), wLength);
 	tbuf = kzalloc(tbuf_size, GFP_KERNEL);
-	if (!tbuf)
-		return -ENOMEM;
+	if (!tbuf) {
+		status = -ENOMEM;
+		goto err_alloc;
+	}
 
 	bufp = tbuf;
 
@@ -557,6 +580,8 @@
 		case USB_DT_DEVICE << 8:
 			switch (hcd->speed) {
 			case HCD_USB31:
+				bufp = usb31_rh_dev_descriptor;
+				break;
 			case HCD_USB3:
 				bufp = usb3_rh_dev_descriptor;
 				break;
@@ -645,9 +670,15 @@
 		/* non-generic request */
 		switch (typeReq) {
 		case GetHubStatus:
-		case GetPortStatus:
 			len = 4;
 			break;
+		case GetPortStatus:
+			if (wValue == HUB_PORT_STATUS)
+				len = 4;
+			else
+				/* other port status types return 8 bytes */
+				len = 8;
+			break;
 		case GetHubDescriptor:
 			len = sizeof (struct usb_hub_descriptor);
 			break;
@@ -705,6 +736,7 @@
 	}
 
 	kfree(tbuf);
+ err_alloc:
 
 	/* any errors get returned through the urb completion */
 	spin_lock_irq(&hcd_root_hub_lock);
@@ -966,9 +998,9 @@
 	bus->bandwidth_allocated = 0;
 	bus->bandwidth_int_reqs  = 0;
 	bus->bandwidth_isoc_reqs = 0;
-	mutex_init(&bus->usb_address0_mutex);
 
 	INIT_LIST_HEAD (&bus->bus_list);
+	mutex_init(&bus->devnum_next_mutex);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1078,7 +1110,7 @@
 		retval = usb_get_bos_descriptor(usb_dev);
 		if (!retval) {
 			usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
-		} else if (usb_dev->speed == USB_SPEED_SUPER) {
+		} else if (usb_dev->speed >= USB_SPEED_SUPER) {
 			mutex_unlock(&usb_bus_list_lock);
 			dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
 					dev_name(&usb_dev->dev), retval);
@@ -1693,7 +1725,7 @@
 		if (retval == 0)
 			retval = -EINPROGRESS;
 		else if (retval != -EIDRM && retval != -EBUSY)
-			dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n",
+			dev_dbg(&udev->dev, "hcd_unlink_urb %pK fail %d\n",
 					urb, retval);
 		usb_put_dev(udev);
 	}
@@ -1848,7 +1880,7 @@
 	/* No more submits can occur */
 	spin_lock_irq(&hcd_urb_list_lock);
 rescan:
-	list_for_each_entry (urb, &ep->urb_list, urb_list) {
+	list_for_each_entry_reverse(urb, &ep->urb_list, urb_list) {
 		int	is_in;
 
 		if (urb->unlinked)
@@ -1860,7 +1892,7 @@
 		/* kick hcd */
 		unlink1(hcd, urb, -ESHUTDOWN);
 		dev_dbg (hcd->self.controller,
-			"shutdown urb %p ep%d%s%s\n",
+			"shutdown urb %pK ep%d%s%s\n",
 			urb, usb_endpoint_num(&ep->desc),
 			is_in ? "in" : "out",
 			({	char *s;
@@ -2112,7 +2144,7 @@
 	hcd = bus_to_hcd(dev->bus);
 	if (!hcd->driver->alloc_streams || !hcd->driver->free_streams)
 		return -EINVAL;
-	if (dev->speed != USB_SPEED_SUPER)
+	if (dev->speed < USB_SPEED_SUPER)
 		return -EINVAL;
 	if (dev->state < USB_STATE_CONFIGURED)
 		return -ENODEV;
@@ -2160,7 +2192,7 @@
 
 	dev = interface_to_usbdev(interface);
 	hcd = bus_to_hcd(dev->bus);
-	if (dev->speed != USB_SPEED_SUPER)
+	if (dev->speed < USB_SPEED_SUPER)
 		return -EINVAL;
 
 	/* Double-free is not allowed */
@@ -2336,6 +2368,7 @@
 
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
 	if (hcd->rh_registered) {
+		pm_wakeup_event(&hcd->self.root_hub->dev, 0);
 		set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
 		queue_work(pm_wq, &hcd->wakeup_work);
 	}
@@ -2445,6 +2478,8 @@
 	}
 	if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) {
 		hcd = hcd->shared_hcd;
+		clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+		set_bit(HCD_FLAG_DEAD, &hcd->flags);
 		if (hcd->rh_registered) {
 			clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
 
@@ -2497,9 +2532,18 @@
 		return NULL;
 	}
 	if (primary_hcd == NULL) {
+		hcd->address0_mutex = kmalloc(sizeof(*hcd->address0_mutex),
+				GFP_KERNEL);
+		if (!hcd->address0_mutex) {
+			kfree(hcd);
+			dev_dbg(dev, "hcd address0 mutex alloc failed\n");
+			return NULL;
+		}
+		mutex_init(hcd->address0_mutex);
 		hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
 				GFP_KERNEL);
 		if (!hcd->bandwidth_mutex) {
+			kfree(hcd->address0_mutex);
 			kfree(hcd);
 			dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
 			return NULL;
@@ -2508,6 +2552,7 @@
 		dev_set_drvdata(dev, hcd);
 	} else {
 		mutex_lock(&usb_port_peer_mutex);
+		hcd->address0_mutex = primary_hcd->address0_mutex;
 		hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
 		hcd->primary_hcd = primary_hcd;
 		primary_hcd->primary_hcd = primary_hcd;
@@ -2564,24 +2609,23 @@
  * Don't deallocate the bandwidth_mutex until the last shared usb_hcd is
  * deallocated.
  *
- * Make sure to only deallocate the bandwidth_mutex when the primary HCD is
- * freed.  When hcd_release() is called for either hcd in a peer set
- * invalidate the peer's ->shared_hcd and ->primary_hcd pointers to
- * block new peering attempts
+ * Make sure to deallocate the bandwidth_mutex only when the last HCD is
+ * freed.  When hcd_release() is called for either hcd in a peer set,
+ * invalidate the peer's ->shared_hcd and ->primary_hcd pointers.
  */
 static void hcd_release(struct kref *kref)
 {
 	struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
 
 	mutex_lock(&usb_port_peer_mutex);
-	if (usb_hcd_is_primary_hcd(hcd))
-		kfree(hcd->bandwidth_mutex);
 	if (hcd->shared_hcd) {
 		struct usb_hcd *peer = hcd->shared_hcd;
 
 		peer->shared_hcd = NULL;
-		if (peer->primary_hcd == hcd)
-			peer->primary_hcd = NULL;
+		peer->primary_hcd = NULL;
+	} else {
+		kfree(hcd->address0_mutex);
+		kfree(hcd->bandwidth_mutex);
 	}
 	mutex_unlock(&usb_port_peer_mutex);
 	kfree(hcd);
@@ -2778,9 +2822,11 @@
 		rhdev->speed = USB_SPEED_WIRELESS;
 		break;
 	case HCD_USB3:
-	case HCD_USB31:
 		rhdev->speed = USB_SPEED_SUPER;
 		break;
+	case HCD_USB31:
+		rhdev->speed = USB_SPEED_SUPER_PLUS;
+		break;
 	default:
 		retval = -EINVAL;
 		goto err_set_rh_speed;
@@ -2983,6 +3029,7 @@
 	}
 
 	usb_put_invalidate_rhdev(hcd);
+	hcd->flags = 0;
 }
 EXPORT_SYMBOL_GPL(usb_remove_hcd);
 
@@ -2991,6 +3038,9 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 
+	/* No need for pm_runtime_put(), we're shutting down */
+	pm_runtime_get_sync(&dev->dev);
+
 	if (hcd->driver->shutdown)
 		hcd->driver->shutdown(hcd);
 }
--- linux-4.4.0.orig/drivers/usb/core/hub.c
+++ linux-4.4.0/drivers/usb/core/hub.c
@@ -101,6 +101,9 @@
 
 static void hub_release(struct kref *kref);
 static int usb_reset_and_verify_device(struct usb_device *udev);
+static int hub_port_disable(struct usb_hub *hub, int port1, int set_state);
+static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
+		u16 portstatus);
 
 static inline char *portspeed(struct usb_hub *hub, int portstatus)
 {
@@ -128,6 +131,10 @@
 	if (udev->quirks & USB_QUIRK_NO_LPM)
 		return 0;
 
+	/* Skip if the device BOS descriptor couldn't be read */
+	if (!udev->bos)
+		return 0;
+
 	/* USB 2.1 (and greater) devices indicate LPM support through
 	 * their USB 2.0 Extended Capabilities BOS descriptor.
 	 */
@@ -298,7 +305,11 @@
 	unsigned int hub_u1_del;
 	unsigned int hub_u2_del;
 
-	if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
+	if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
+		return;
+
+	/* Skip if the device BOS descriptor couldn't be read */
+	if (!udev->bos)
 		return;
 
 	hub = usb_hub_to_struct_hub(udev->parent);
@@ -357,7 +368,8 @@
 }
 
 /* USB 2.0 spec Section 11.24.4.5 */
-static int get_hub_descriptor(struct usb_device *hdev, void *data)
+static int get_hub_descriptor(struct usb_device *hdev,
+		struct usb_hub_descriptor *desc)
 {
 	int i, ret, size;
 	unsigned dtype;
@@ -373,10 +385,18 @@
 	for (i = 0; i < 3; i++) {
 		ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
-			dtype << 8, 0, data, size,
+			dtype << 8, 0, desc, size,
 			USB_CTRL_GET_TIMEOUT);
-		if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
+		if (hub_is_superspeed(hdev)) {
+			if (ret == size)
+				return ret;
+		} else if (ret >= USB_DT_HUB_NONVAR_SIZE + 2) {
+			/* Make sure we have the DeviceRemovable field. */
+			size = USB_DT_HUB_NONVAR_SIZE + desc->bNbrPorts / 8 + 1;
+			if (ret < size)
+				return -EMSGSIZE;
 			return ret;
+		}
 	}
 	return -EINVAL;
 }
@@ -537,29 +557,34 @@
 
 /*
  * USB 2.0 spec Section 11.24.2.7
+ * USB 3.1 takes into use the wValue and wLength fields, spec Section 10.16.2.6
  */
 static int get_port_status(struct usb_device *hdev, int port1,
-		struct usb_port_status *data)
+			   void *data, u16 value, u16 length)
 {
 	int i, status = -ETIMEDOUT;
 
 	for (i = 0; i < USB_STS_RETRIES &&
 			(status == -ETIMEDOUT || status == -EPIPE); i++) {
 		status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
-			USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1,
-			data, sizeof(*data), USB_STS_TIMEOUT);
+			USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, value,
+			port1, data, length, USB_STS_TIMEOUT);
 	}
 	return status;
 }
 
-static int hub_port_status(struct usb_hub *hub, int port1,
-		u16 *status, u16 *change)
+static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
+			       u16 *status, u16 *change, u32 *ext_status)
 {
 	int ret;
+	int len = 4;
+
+	if (type != HUB_PORT_STATUS)
+		len = 8;
 
 	mutex_lock(&hub->status_mutex);
-	ret = get_port_status(hub->hdev, port1, &hub->status->port);
-	if (ret < 4) {
+	ret = get_port_status(hub->hdev, port1, &hub->status->port, type, len);
+	if (ret < len) {
 		if (ret != -ENODEV)
 			dev_err(hub->intfdev,
 				"%s failed (err = %d)\n", __func__, ret);
@@ -568,13 +593,22 @@
 	} else {
 		*status = le16_to_cpu(hub->status->port.wPortStatus);
 		*change = le16_to_cpu(hub->status->port.wPortChange);
-
+		if (type != HUB_PORT_STATUS && ext_status)
+			*ext_status = le32_to_cpu(
+				hub->status->port.dwExtPortStatus);
 		ret = 0;
 	}
 	mutex_unlock(&hub->status_mutex);
 	return ret;
 }
 
+static int hub_port_status(struct usb_hub *hub, int port1,
+		u16 *status, u16 *change)
+{
+	return hub_ext_port_status(hub, port1, HUB_PORT_STATUS,
+				   status, change, NULL);
+}
+
 static void kick_hub_wq(struct usb_hub *hub)
 {
 	struct usb_interface *intf;
@@ -622,12 +656,17 @@
 		unsigned int portnum)
 {
 	struct usb_hub *hub;
+	struct usb_port *port_dev;
 
 	if (!hdev)
 		return;
 
 	hub = usb_hub_to_struct_hub(hdev);
 	if (hub) {
+		port_dev = hub->ports[portnum - 1];
+		if (port_dev && port_dev->child)
+			pm_wakeup_event(&port_dev->child->dev, 0);
+
 		set_bit(portnum, hub->wakeup_bits);
 		kick_hub_wq(hub);
 	}
@@ -883,88 +922,6 @@
 }
 
 /*
- * If USB 3.0 ports are placed into the Disabled state, they will no longer
- * detect any device connects or disconnects.  This is generally not what the
- * USB core wants, since it expects a disabled port to produce a port status
- * change event when a new device connects.
- *
- * Instead, set the link state to Disabled, wait for the link to settle into
- * that state, clear any change bits, and then put the port into the RxDetect
- * state.
- */
-static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
-{
-	int ret;
-	int total_time;
-	u16 portchange, portstatus;
-
-	if (!hub_is_superspeed(hub->hdev))
-		return -EINVAL;
-
-	ret = hub_port_status(hub, port1, &portstatus, &portchange);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * USB controller Advanced Micro Devices, Inc. [AMD] FCH USB XHCI
-	 * Controller [1022:7814] will have spurious result making the following
-	 * usb 3.0 device hotplugging route to the 2.0 root hub and recognized
-	 * as high-speed device if we set the usb 3.0 port link state to
-	 * Disabled. Since it's already in USB_SS_PORT_LS_RX_DETECT state, we
-	 * check the state here to avoid the bug.
-	 */
-	if ((portstatus & USB_PORT_STAT_LINK_STATE) ==
-				USB_SS_PORT_LS_RX_DETECT) {
-		dev_dbg(&hub->ports[port1 - 1]->dev,
-			 "Not disabling port; link state is RxDetect\n");
-		return ret;
-	}
-
-	ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
-	if (ret)
-		return ret;
-
-	/* Wait for the link to enter the disabled state. */
-	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
-		ret = hub_port_status(hub, port1, &portstatus, &portchange);
-		if (ret < 0)
-			return ret;
-
-		if ((portstatus & USB_PORT_STAT_LINK_STATE) ==
-				USB_SS_PORT_LS_SS_DISABLED)
-			break;
-		if (total_time >= HUB_DEBOUNCE_TIMEOUT)
-			break;
-		msleep(HUB_DEBOUNCE_STEP);
-	}
-	if (total_time >= HUB_DEBOUNCE_TIMEOUT)
-		dev_warn(&hub->ports[port1 - 1]->dev,
-				"Could not disable after %d ms\n", total_time);
-
-	return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT);
-}
-
-static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
-{
-	struct usb_port *port_dev = hub->ports[port1 - 1];
-	struct usb_device *hdev = hub->hdev;
-	int ret = 0;
-
-	if (port_dev->child && set_state)
-		usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);
-	if (!hub->error) {
-		if (hub_is_superspeed(hub->hdev))
-			ret = hub_usb3_port_disable(hub, port1);
-		else
-			ret = usb_clear_port_feature(hdev, port1,
-					USB_PORT_FEAT_ENABLE);
-	}
-	if (ret && ret != -ENODEV)
-		dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);
-	return ret;
-}
-
-/*
  * Disable a port and mark a logical connect-change event, so that some
  * time later hub_wq will disconnect() any existing usb_device on the port
  * and will re-enumerate if there actually is a device attached.
@@ -1003,13 +960,17 @@
 {
 	struct usb_hub *hub;
 	struct usb_interface *intf;
+	int ret;
 
 	if (!udev->parent)	/* Can't remove a root hub */
 		return -EINVAL;
 	hub = usb_hub_to_struct_hub(udev->parent);
 	intf = to_usb_interface(hub->intfdev);
 
-	usb_autopm_get_interface(intf);
+	ret = usb_autopm_get_interface(intf);
+	if (ret < 0)
+		return ret;
+
 	set_bit(udev->portnum, hub->removed_bits);
 	hub_port_logical_disconnect(hub, udev->portnum);
 	usb_autopm_put_interface(intf);
@@ -1036,14 +997,11 @@
 
 	/* Continue a partial initialization */
 	if (type == HUB_INIT2 || type == HUB_INIT3) {
-		device_lock(hub->intfdev);
+		device_lock(&hdev->dev);
 
 		/* Was the hub disconnected while we were waiting? */
-		if (hub->disconnected) {
-			device_unlock(hub->intfdev);
-			kref_put(&hub->kref, hub_release);
-			return;
-		}
+		if (hub->disconnected)
+			goto disconnected;
 		if (type == HUB_INIT2)
 			goto init2;
 		goto init3;
@@ -1132,6 +1090,9 @@
 
 		portstatus = portchange = 0;
 		status = hub_port_status(hub, port1, &portstatus, &portchange);
+		if (status)
+			goto abort;
+
 		if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
 			dev_dbg(&port_dev->dev, "status %04x change %04x\n",
 					portstatus, portchange);
@@ -1159,6 +1120,21 @@
 						   USB_PORT_FEAT_ENABLE);
 		}
 
+		/* Make sure a warm-reset request is handled by port_event */
+		if (type == HUB_RESUME &&
+		    hub_port_warm_reset_required(hub, port1, portstatus))
+			set_bit(port1, hub->event_bits);
+
+		/*
+		 * Add debounce if USB3 link is in polling/link training state.
+		 * Link will automatically transition to Enabled state after
+		 * link training completes.
+		 */
+		if (hub_is_superspeed(hdev) &&
+		    ((portstatus & USB_PORT_STAT_LINK_STATE) ==
+						USB_SS_PORT_LS_POLLING))
+			need_debounce_delay = true;
+
 		/* Clear status-change flags; we'll debounce later */
 		if (portchange & USB_PORT_STAT_C_CONNECTION) {
 			need_debounce_delay = true;
@@ -1190,10 +1166,15 @@
 
 		if (!udev || udev->state == USB_STATE_NOTATTACHED) {
 			/* Tell hub_wq to disconnect the device or
-			 * check for a new connection
+			 * check for a new connection or over current condition.
+			 * Based on USB2.0 Spec Section 11.12.5,
+			 * C_PORT_OVER_CURRENT could be set while
+			 * PORT_OVER_CURRENT is not. So check for any of them.
 			 */
 			if (udev || (portstatus & USB_PORT_STAT_CONNECTION) ||
-			    (portstatus & USB_PORT_STAT_OVERCURRENT))
+			    (portchange & USB_PORT_STAT_C_CONNECTION) ||
+			    (portstatus & USB_PORT_STAT_OVERCURRENT) ||
+			    (portchange & USB_PORT_STAT_C_OVERCURRENT))
 				set_bit(port1, hub->change_bits);
 
 		} else if (portstatus & USB_PORT_STAT_ENABLE) {
@@ -1246,7 +1227,7 @@
 			queue_delayed_work(system_power_efficient_wq,
 					&hub->init_work,
 					msecs_to_jiffies(delay));
-			device_unlock(hub->intfdev);
+			device_unlock(&hdev->dev);
 			return;		/* Continues at init3: below */
 		} else {
 			msleep(delay);
@@ -1264,13 +1245,13 @@
 
 	/* Scan all ports that need attention */
 	kick_hub_wq(hub);
-
-	/* Allow autosuspend if it was suppressed */
-	if (type <= HUB_INIT3)
+ abort:
+	if (type == HUB_INIT2 || type == HUB_INIT3) {
+		/* Allow autosuspend if it was suppressed */
+ disconnected:
 		usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
-
-	if (type == HUB_INIT2 || type == HUB_INIT3)
-		device_unlock(hub->intfdev);
+		device_unlock(&hdev->dev);
+	}
 
 	kref_put(&hub->kref, hub_release);
 }
@@ -1299,8 +1280,6 @@
 	struct usb_device *hdev = hub->hdev;
 	int i;
 
-	cancel_delayed_work_sync(&hub->init_work);
-
 	/* hub_wq and related activity won't re-trigger */
 	hub->quiescing = 1;
 
@@ -1378,7 +1357,7 @@
 	}
 	mutex_init(&hub->status_mutex);
 
-	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
+	hub->descriptor = kzalloc(sizeof(*hub->descriptor), GFP_KERNEL);
 	if (!hub->descriptor) {
 		ret = -ENOMEM;
 		goto fail;
@@ -1386,13 +1365,19 @@
 
 	/* Request the entire hub descriptor.
 	 * hub->descriptor can handle USB_MAXCHILDREN ports,
-	 * but the hub can/will return fewer bytes here.
+	 * but a (non-SS) hub can/will return fewer bytes here.
 	 */
 	ret = get_hub_descriptor(hdev, hub->descriptor);
 	if (ret < 0) {
 		message = "can't read hub descriptor";
 		goto fail;
-	} else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
+	}
+
+	maxchild = USB_MAXCHILDREN;
+	if (hub_is_superspeed(hdev))
+		maxchild = min_t(unsigned, maxchild, USB_SS_MAXPORTS);
+
+	if (hub->descriptor->bNbrPorts > maxchild) {
 		message = "hub has too many ports!";
 		ret = -ENODEV;
 		goto fail;
@@ -2066,7 +2051,7 @@
 	struct usb_bus	*bus = udev->bus;
 
 	/* be safe when more hub events are proceed in parallel */
-	mutex_lock(&bus->usb_address0_mutex);
+	mutex_lock(&bus->devnum_next_mutex);
 	if (udev->wusb) {
 		devnum = udev->portnum + 1;
 		BUG_ON(test_bit(devnum, bus->devmap.devicemap));
@@ -2084,7 +2069,7 @@
 		set_bit(devnum, bus->devmap.devicemap);
 		udev->devnum = devnum;
 	}
-	mutex_unlock(&bus->usb_address0_mutex);
+	mutex_unlock(&bus->devnum_next_mutex);
 }
 
 static void release_devnum(struct usb_device *udev)
@@ -2154,6 +2139,12 @@
 	dev_info(&udev->dev, "USB disconnect, device number %d\n",
 			udev->devnum);
 
+	/*
+	 * Ensure that the pm runtime code knows that the USB device
+	 * is in the process of being disconnected.
+	 */
+	pm_runtime_barrier(&udev->dev);
+
 	usb_lock_device(udev);
 
 	hub_disconnect_children(udev);
@@ -2264,7 +2255,7 @@
 		/* descriptor may appear anywhere in config */
 		err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
 				le16_to_cpu(udev->config[0].desc.wTotalLength),
-				USB_DT_OTG, (void **) &desc);
+				USB_DT_OTG, (void **) &desc, sizeof(*desc));
 		if (err || !(desc->bmAttributes & USB_OTG_HNP))
 			return 0;
 
@@ -2612,6 +2603,36 @@
 	return result;
 }
 
+/*
+ * Return 1 if port speed is SuperSpeedPlus, 0 otherwise
+ * check it from the link protocol field of the current speed ID attribute.
+ * current speed ID is got from ext port status request. Sublink speed attribute
+ * table is returned with the hub BOS SSP device capability descriptor
+ */
+static int port_speed_is_ssp(struct usb_device *hdev, int speed_id)
+{
+	int ssa_count;
+	u32 ss_attr;
+	int i;
+	struct usb_ssp_cap_descriptor *ssp_cap;
+
+	if (!hdev->bos)
+		return 0;
+
+	ssp_cap = hdev->bos->ssp_cap;
+	if (!ssp_cap)
+		return 0;
+
+	ssa_count = le32_to_cpu(ssp_cap->bmAttributes) &
+		USB_SSP_SUBLINK_SPEED_ATTRIBS;
+
+	for (i = 0; i <= ssa_count; i++) {
+		ss_attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]);
+		if (speed_id == (ss_attr & USB_SSP_SUBLINK_SPEED_SSID))
+			return !!(ss_attr & USB_SSP_SUBLINK_SPEED_LP);
+	}
+	return 0;
+}
 
 /* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
 static unsigned hub_is_wusb(struct usb_hub *hub)
@@ -2645,7 +2666,7 @@
  */
 static bool use_new_scheme(struct usb_device *udev, int retry)
 {
-	if (udev->speed == USB_SPEED_SUPER)
+	if (udev->speed >= USB_SPEED_SUPER)
 		return false;
 
 	return USE_NEW_SCHEME(retry);
@@ -2676,6 +2697,7 @@
 	int delay_time, ret;
 	u16 portstatus;
 	u16 portchange;
+	u32 ext_portstatus = 0;
 
 	for (delay_time = 0;
 			delay_time < HUB_RESET_TIMEOUT;
@@ -2684,12 +2706,26 @@
 		msleep(delay);
 
 		/* read and decode port status */
-		ret = hub_port_status(hub, port1, &portstatus, &portchange);
+		if (hub_is_superspeedplus(hub->hdev))
+			ret = hub_ext_port_status(hub, port1,
+						  HUB_EXT_PORT_STATUS,
+						  &portstatus, &portchange,
+						  &ext_portstatus);
+		else
+			ret = hub_port_status(hub, port1, &portstatus,
+					      &portchange);
 		if (ret < 0)
 			return ret;
 
-		/* The port state is unknown until the reset completes. */
-		if (!(portstatus & USB_PORT_STAT_RESET))
+		/*
+		 * The port state is unknown until the reset completes.
+		 *
+		 * On top of that, some chips may require additional time
+		 * to re-establish a connection after the reset is complete,
+		 * so also wait for the connection to be re-established.
+		 */
+		if (!(portstatus & USB_PORT_STAT_RESET) &&
+		    (portstatus & USB_PORT_STAT_CONNECTION))
 			break;
 
 		/* switch to the long delay after two short delay failures */
@@ -2711,13 +2747,16 @@
 	if (!(portstatus & USB_PORT_STAT_CONNECTION))
 		return -ENOTCONN;
 
-	/* bomb out completely if the connection bounced.  A USB 3.0
-	 * connection may bounce if multiple warm resets were issued,
+	/* Retry if connect change is set but status is still connected.
+	 * A USB 3.0 connection may bounce if multiple warm resets were issued,
 	 * but the device may have successfully re-connected. Ignore it.
 	 */
 	if (!hub_is_superspeed(hub->hdev) &&
-			(portchange & USB_PORT_STAT_C_CONNECTION))
-		return -ENOTCONN;
+	    (portchange & USB_PORT_STAT_C_CONNECTION)) {
+		usb_clear_port_feature(hub->hdev, port1,
+				       USB_PORT_FEAT_C_CONNECTION);
+		return -EAGAIN;
+	}
 
 	if (!(portstatus & USB_PORT_STAT_ENABLE))
 		return -EBUSY;
@@ -2727,6 +2766,10 @@
 
 	if (hub_is_wusb(hub))
 		udev->speed = USB_SPEED_WIRELESS;
+	else if (hub_is_superspeedplus(hub->hdev) &&
+		 port_speed_is_ssp(hub->hdev, ext_portstatus &
+				   USB_EXT_PORT_STAT_RX_SPEED_ID))
+		udev->speed = USB_SPEED_SUPER_PLUS;
 	else if (hub_is_superspeed(hub->hdev))
 		udev->speed = USB_SPEED_SUPER;
 	else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
@@ -2800,7 +2843,9 @@
 					USB_PORT_FEAT_C_BH_PORT_RESET);
 			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_PORT_LINK_STATE);
-			usb_clear_port_feature(hub->hdev, port1,
+
+			if (udev)
+				usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_CONNECTION);
 
 			/*
@@ -2963,6 +3008,15 @@
 		if (portchange & USB_PORT_STAT_C_ENABLE)
 			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_ENABLE);
+
+		/*
+		 * Whatever made this reset-resume necessary may have
+		 * turned on the port1 bit in hub->change_bits.  But after
+		 * a successful reset-resume we want the bit to be clear;
+		 * if it was on it would indicate that something happened
+		 * following the reset-resume.
+		 */
+		clear_bit(port1, hub->change_bits);
 	}
 
 	return status;
@@ -3147,8 +3201,7 @@
 	}
 
 	/* disable USB2 hardware LPM */
-	if (udev->usb2_hw_lpm_enabled == 1)
-		usb_set_usb2_hardware_lpm(udev, 0);
+	usb_disable_usb2_hardware_lpm(udev);
 
 	if (usb_disable_ltm(udev)) {
 		dev_err(&udev->dev, "Failed to disable LTM before suspend\n.");
@@ -3194,8 +3247,7 @@
 		usb_enable_ltm(udev);
  err_ltm:
 		/* Try to enable USB2 hardware LPM again */
-		if (udev->usb2_hw_lpm_capable == 1)
-			usb_set_usb2_hardware_lpm(udev, 1);
+		usb_enable_usb2_hardware_lpm(udev);
 
 		if (udev->do_remote_wakeup)
 			(void) usb_disable_remote_wakeup(udev);
@@ -3351,6 +3403,10 @@
 	while (delay_ms < 2000) {
 		if (status || *portstatus & USB_PORT_STAT_CONNECTION)
 			break;
+		if (!port_is_power_on(hub, *portstatus)) {
+			status = -ENODEV;
+			break;
+		}
 		msleep(20);
 		delay_ms += 20;
 		status = hub_port_status(hub, *port1, portstatus, portchange);
@@ -3413,8 +3469,11 @@
 
 	/* Skip the initial Clear-Suspend step for a remote wakeup */
 	status = hub_port_status(hub, port1, &portstatus, &portchange);
-	if (status == 0 && !port_is_suspended(hub, portstatus))
+	if (status == 0 && !port_is_suspended(hub, portstatus)) {
+		if (portchange & USB_PORT_STAT_C_SUSPEND)
+			pm_wakeup_event(&udev->dev, 0);
 		goto SuspendCleared;
+	}
 
 	/* see 7.1.7.7; affects power usage, but not budgeting */
 	if (hub_is_superspeed(hub->hdev))
@@ -3467,8 +3526,7 @@
 		hub_port_logical_disconnect(hub, port1);
 	} else  {
 		/* Try to enable USB2 hardware LPM */
-		if (udev->usb2_hw_lpm_capable == 1)
-			usb_set_usb2_hardware_lpm(udev, 1);
+		usb_enable_usb2_hardware_lpm(udev);
 
 		/* Try to enable USB3 LTM and LPM */
 		usb_enable_ltm(udev);
@@ -3506,6 +3564,7 @@
 	struct usb_device *hdev;
 	struct usb_device *udev;
 	int connect_change = 0;
+	u16 link_state;
 	int ret;
 
 	hdev = hub->hdev;
@@ -3515,9 +3574,11 @@
 			return 0;
 		usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
 	} else {
+		link_state = portstatus & USB_PORT_STAT_LINK_STATE;
 		if (!udev || udev->state != USB_STATE_SUSPENDED ||
-				 (portstatus & USB_PORT_STAT_LINK_STATE) !=
-				 USB_SS_PORT_LS_U0)
+				(link_state != USB_SS_PORT_LS_U0 &&
+				 link_state != USB_SS_PORT_LS_U1 &&
+				 link_state != USB_SS_PORT_LS_U2))
 			return 0;
 	}
 
@@ -3847,6 +3908,9 @@
  * control transfers to set the hub timeout or enable device-initiated U1/U2
  * will be successful.
  *
+ * If the control transfer to enable device-initiated U1/U2 entry fails, then
+ * hub-initiated U1/U2 will be disabled.
+ *
  * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
  * driver know about it.  If that call fails, it should be harmless, and just
  * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
@@ -3855,8 +3919,15 @@
 		enum usb3_link_state state)
 {
 	int timeout, ret;
-	__u8 u1_mel = udev->bos->ss_cap->bU1devExitLat;
-	__le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat;
+	__u8 u1_mel;
+	__le16 u2_mel;
+
+	/* Skip if the device BOS descriptor couldn't be read */
+	if (!udev->bos)
+		return;
+
+	u1_mel = udev->bos->ss_cap->bU1devExitLat;
+	u2_mel = udev->bos->ss_cap->bU2DevExitLat;
 
 	/* If the device says it doesn't have *any* exit latency to come out of
 	 * U1 or U2, it's probably lying.  Assume it doesn't implement that link
@@ -3895,17 +3966,31 @@
 		return;
 	}
 
-	if (usb_set_lpm_timeout(udev, state, timeout))
+	if (usb_set_lpm_timeout(udev, state, timeout)) {
 		/* If we can't set the parent hub U1/U2 timeout,
 		 * device-initiated LPM won't be allowed either, so let the xHCI
 		 * host know that this link state won't be enabled.
 		 */
 		hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
+		return;
+	}
 
-	/* Only a configured device will accept the Set Feature U1/U2_ENABLE */
-	else if (udev->actconfig)
-		usb_set_device_initiated_lpm(udev, state, true);
-
+	/* Only a configured device will accept the Set Feature
+	 * U1/U2_ENABLE
+	 */
+	if (udev->actconfig &&
+	    usb_set_device_initiated_lpm(udev, state, true) == 0) {
+		if (state == USB3_LPM_U1)
+			udev->usb3_lpm_u1_enabled = 1;
+		else if (state == USB3_LPM_U2)
+			udev->usb3_lpm_u2_enabled = 1;
+	} else {
+		/* Don't request U1/U2 entry if the device
+		 * cannot transition to U1/U2.
+		 */
+		usb_set_lpm_timeout(udev, state, 0);
+		hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
+	}
 }
 
 /*
@@ -3945,6 +4030,18 @@
 		dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
 				"bus schedule bandwidth may be impacted.\n",
 				usb3_lpm_names[state]);
+
+	/* As soon as usb_set_lpm_timeout(0) return 0, hub initiated LPM
+	 * is disabled. Hub will disallows link to enter U1/U2 as well,
+	 * even device is initiating LPM. Hence LPM is disabled if hub LPM
+	 * timeout set to 0, no matter device-initiated LPM is disabled or
+	 * not.
+	 */
+	if (state == USB3_LPM_U1)
+		udev->usb3_lpm_u1_enabled = 0;
+	else if (state == USB3_LPM_U2)
+		udev->usb3_lpm_u2_enabled = 0;
+
 	return 0;
 }
 
@@ -3960,7 +4057,7 @@
 	struct usb_hcd *hcd;
 
 	if (!udev || !udev->parent ||
-			udev->speed != USB_SPEED_SUPER ||
+			udev->speed < USB_SPEED_SUPER ||
 			!udev->lpm_capable ||
 			udev->state < USB_STATE_DEFAULT)
 		return 0;
@@ -3979,8 +4076,6 @@
 	if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
 		goto enable_lpm;
 
-	udev->usb3_lpm_enabled = 0;
-
 	return 0;
 
 enable_lpm:
@@ -4019,7 +4114,7 @@
 	struct usb_hcd *hcd;
 
 	if (!udev || !udev->parent ||
-			udev->speed != USB_SPEED_SUPER ||
+			udev->speed < USB_SPEED_SUPER ||
 			!udev->lpm_capable ||
 			udev->state < USB_STATE_DEFAULT)
 		return;
@@ -4038,8 +4133,6 @@
 
 	usb_enable_link_state(hcd, udev, USB3_LPM_U1);
 	usb_enable_link_state(hcd, udev, USB3_LPM_U2);
-
-	udev->usb3_lpm_enabled = 1;
 }
 EXPORT_SYMBOL_GPL(usb_enable_lpm);
 
@@ -4057,6 +4150,26 @@
 }
 EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
 
+/* usb3 devices use U3 for disabled, make sure remote wakeup is disabled */
+static void hub_usb3_port_prepare_disable(struct usb_hub *hub,
+					  struct usb_port *port_dev)
+{
+	struct usb_device *udev = port_dev->child;
+	int ret;
+
+	if (udev && udev->port_is_suspended && udev->do_remote_wakeup) {
+		ret = hub_set_port_link_state(hub, port_dev->portnum,
+					      USB_SS_PORT_LS_U0);
+		if (!ret) {
+			msleep(USB_RESUME_TIMEOUT);
+			ret = usb_disable_remote_wakeup(udev);
+		}
+		if (ret)
+			dev_warn(&udev->dev,
+				 "Port disable: can't disable remote wake\n");
+		udev->do_remote_wakeup = 0;
+	}
+}
 
 #else	/* CONFIG_PM */
 
@@ -4064,6 +4177,9 @@
 #define hub_resume		NULL
 #define hub_reset_resume	NULL
 
+static inline void hub_usb3_port_prepare_disable(struct usb_hub *hub,
+						 struct usb_port *port_dev) { }
+
 int usb_disable_lpm(struct usb_device *udev)
 {
 	return 0;
@@ -4099,6 +4215,34 @@
 
 #endif	/* CONFIG_PM */
 
+/*
+ * USB-3 does not have a similar link state as USB-2 that will avoid negotiating
+ * a connection with a plugged-in cable but will signal the host when the cable
+ * is unplugged. Disable remote wake and set link state to U3 for USB-3 devices
+ */
+static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
+{
+	struct usb_port *port_dev = hub->ports[port1 - 1];
+	struct usb_device *hdev = hub->hdev;
+	int ret = 0;
+
+	if (!hub->error) {
+		if (hub_is_superspeed(hub->hdev)) {
+			hub_usb3_port_prepare_disable(hub, port_dev);
+			ret = hub_set_port_link_state(hub, port_dev->portnum,
+						      USB_SS_PORT_LS_U3);
+		} else {
+			ret = usb_clear_port_feature(hdev, port1,
+					USB_PORT_FEAT_ENABLE);
+		}
+	}
+	if (port_dev->child && set_state)
+		usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);
+	if (ret && ret != -ENODEV)
+		dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);
+	return ret;
+}
+
 
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
  *
@@ -4213,7 +4357,7 @@
 	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
 	int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
 
-	if (!udev->usb2_hw_lpm_capable)
+	if (!udev->usb2_hw_lpm_capable || !udev->bos)
 		return;
 
 	if (hub)
@@ -4222,7 +4366,7 @@
 	if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) ||
 			connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
 		udev->usb2_hw_lpm_allowed = 1;
-		usb_set_usb2_hardware_lpm(udev, 1);
+		usb_enable_usb2_hardware_lpm(udev);
 	}
 }
 
@@ -4256,7 +4400,7 @@
 {
 	struct usb_device	*hdev = hub->hdev;
 	struct usb_hcd		*hcd = bus_to_hcd(hdev->bus);
-	int			i, j, retval;
+	int			retries, operations, retval, i;
 	unsigned		delay = HUB_SHORT_RESET_TIME;
 	enum usb_device_speed	oldspeed = udev->speed;
 	const char		*speed;
@@ -4276,7 +4420,7 @@
 	if (oldspeed == USB_SPEED_LOW)
 		delay = HUB_LONG_RESET_TIME;
 
-	mutex_lock(&hdev->bus->usb_address0_mutex);
+	mutex_lock(hcd->address0_mutex);
 
 	/* Reset the device; full speed may morph to high speed */
 	/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
@@ -4287,7 +4431,9 @@
 
 	retval = -ENODEV;
 
-	if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
+	/* Don't allow speed changes at reset, except usb 3.0 to faster */
+	if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
+	    !(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
 		dev_dbg(&udev->dev, "device reset changed speed!\n");
 		goto fail;
 	}
@@ -4299,6 +4445,7 @@
 	 * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
 	 */
 	switch (udev->speed) {
+	case USB_SPEED_SUPER_PLUS:
 	case USB_SPEED_SUPER:
 	case USB_SPEED_WIRELESS:	/* fixed at 512 */
 		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
@@ -4325,7 +4472,7 @@
 	else
 		speed = usb_speed_string(udev->speed);
 
-	if (udev->speed != USB_SPEED_SUPER)
+	if (udev->speed < USB_SPEED_SUPER)
 		dev_info(&udev->dev,
 				"%s %s USB device number %d using %s\n",
 				(udev->config) ? "reset" : "new", speed,
@@ -4358,7 +4505,7 @@
 	 * first 8 bytes of the device descriptor to get the ep0 maxpacket
 	 * value.
 	 */
-	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
+	for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
 		bool did_new_scheme = false;
 
 		if (use_new_scheme(udev, retry_counter)) {
@@ -4385,7 +4532,7 @@
 			 * 255 is for WUSB devices, we actually need to use
 			 * 512 (WUSB1.0[4.8.1]).
 			 */
-			for (j = 0; j < 3; ++j) {
+			for (operations = 0; operations < 3; ++operations) {
 				buf->bMaxPacketSize0 = 0;
 				r = usb_control_msg(udev, usb_rcvaddr0pipe(),
 					USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
@@ -4405,7 +4552,15 @@
 						r = -EPROTO;
 					break;
 				}
-				if (r == 0)
+				/*
+				 * Some devices time out if they are powered on
+				 * when already connected. They need a second
+				 * reset. But only on the first attempt,
+				 * lest we get into a time out/reset loop
+				 */
+				if (r == 0 || (r == -ETIMEDOUT &&
+						retries == 0 &&
+						udev->speed > USB_SPEED_FULL))
 					break;
 			}
 			udev->descriptor.bMaxPacketSize0 =
@@ -4437,7 +4592,7 @@
 		 * authorization will assign the final address.
 		 */
 		if (udev->wusb == 0) {
-			for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
+			for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
 				retval = hub_set_address(udev, devnum);
 				if (retval >= 0)
 					break;
@@ -4449,11 +4604,12 @@
 							devnum, retval);
 				goto fail;
 			}
-			if (udev->speed == USB_SPEED_SUPER) {
+			if (udev->speed >= USB_SPEED_SUPER) {
 				devnum = udev->devnum;
 				dev_info(&udev->dev,
-						"%s SuperSpeed USB device number %d using %s\n",
+						"%s SuperSpeed%s USB device number %d using %s\n",
 						(udev->config) ? "reset" : "new",
+					 (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
 						devnum, udev->bus->controller->driver->name);
 			}
 
@@ -4492,7 +4648,7 @@
 	 * got from those devices show they aren't superspeed devices. Warm
 	 * reset the port attached by the devices can fix them.
 	 */
-	if ((udev->speed == USB_SPEED_SUPER) &&
+	if ((udev->speed >= USB_SPEED_SUPER) &&
 			(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
 		dev_err(&udev->dev, "got a wrong device descriptor, "
 				"warm reset device\n");
@@ -4503,7 +4659,7 @@
 	}
 
 	if (udev->descriptor.bMaxPacketSize0 == 0xff ||
-			udev->speed == USB_SPEED_SUPER)
+			udev->speed >= USB_SPEED_SUPER)
 		i = 512;
 	else
 		i = udev->descriptor.bMaxPacketSize0;
@@ -4552,7 +4708,7 @@
 		hub_port_disable(hub, port1, 0);
 		update_devnum(udev, devnum);	/* for disconnect processing */
 	}
-	mutex_unlock(&hdev->bus->usb_address0_mutex);
+	mutex_unlock(hcd->address0_mutex);
 	return retval;
 }
 
@@ -4634,7 +4790,8 @@
 static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
 		u16 portchange)
 {
-	int status, i;
+	int status = -ENODEV;
+	int i;
 	unsigned unit_load;
 	struct usb_device *hdev = hub->hdev;
 	struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
@@ -4713,7 +4870,7 @@
 		udev->level = hdev->level + 1;
 		udev->wusb = hub_is_wusb(hub);
 
-		/* Only USB 3.0 devices are connected to SuperSpeed hubs. */
+		/* Devices connected to SuperSpeed hubs are USB 3.0 or later */
 		if (hub_is_superspeed(hub->hdev))
 			udev->speed = USB_SPEED_SUPER;
 		else
@@ -4733,7 +4890,7 @@
 			goto loop;
 
 		if (udev->quirks & USB_QUIRK_DELAY_INIT)
-			msleep(1000);
+			msleep(2000);
 
 		/* consecutive bus-powered hubs aren't reliable; they can
 		 * violate the voltage drop budget.  if the new child has
@@ -4827,6 +4984,15 @@
 		usb_put_dev(udev);
 		if ((status == -ENOTCONN) || (status == -ENOTSUPP))
 			break;
+
+		/* When halfway through our retry count, power-cycle the port */
+		if (i == (SET_CONFIG_TRIES / 2) - 1) {
+			dev_info(&port_dev->dev, "attempt power cycle\n");
+			usb_hub_set_port_power(hdev, hub, port1, false);
+			msleep(2 * hub_power_on_good_delay(hub));
+			usb_hub_set_port_power(hdev, hub, port1, true);
+			msleep(hub_power_on_good_delay(hub));
+		}
 	}
 	if (hub->hdev->parent ||
 			!hcd->driver->port_handed_over ||
@@ -4838,9 +5004,10 @@
 
 done:
 	hub_port_disable(hub, port1, 1);
-	if (hcd->driver->relinquish_port && !hub->hdev->parent)
-		hcd->driver->relinquish_port(hcd, port1);
-
+	if (hcd->driver->relinquish_port && !hub->hdev->parent) {
+		if (status != -ENOTCONN && status != -ENODEV)
+			hcd->driver->relinquish_port(hcd, port1);
+	}
 }
 
 /* Handle physical or logical connection change events.
@@ -5344,8 +5511,7 @@
 	/* Disable USB2 hardware LPM.
 	 * It will be re-enabled by the enumeration process.
 	 */
-	if (udev->usb2_hw_lpm_enabled == 1)
-		usb_set_usb2_hardware_lpm(udev, 0);
+	usb_disable_usb2_hardware_lpm(udev);
 
 	/* Disable LPM and LTM while we reset the device and reinstall the alt
 	 * settings.  Device-initiated LPM settings, and system exit latency
@@ -5455,7 +5621,7 @@
 
 done:
 	/* Now that the alt settings are re-installed, enable LTM and LPM. */
-	usb_set_usb2_hardware_lpm(udev, 1);
+	usb_enable_usb2_hardware_lpm(udev);
 	usb_unlocked_enable_lpm(udev);
 	usb_enable_ltm(udev);
 	usb_release_bos_descriptor(udev);
@@ -5473,13 +5639,18 @@
 
 /**
  * usb_reset_device - warn interface drivers and perform a USB port reset
- * @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
+ * @udev: device to reset (not in NOTATTACHED state)
  *
  * Warns all drivers bound to registered interfaces (using their pre_reset
  * method), performs the port reset, and then lets the drivers know that
  * the reset is over (using their post_reset method).
  *
  * Return: The same as for usb_reset_and_verify_device().
+ * However, if a reset is already in progress (for instance, if a
+ * driver doesn't have pre_ or post_reset() callbacks, and while
+ * being unbound or re-bound during the ongoing reset its disconnect()
+ * or probe() routine tries to perform a second, nested reset), the
+ * routine returns -EINPROGRESS.
  *
  * Note:
  * The caller must own the device lock.  For example, it's safe to use
@@ -5501,8 +5672,7 @@
 	struct usb_host_config *config = udev->actconfig;
 	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
 
-	if (udev->state == USB_STATE_NOTATTACHED ||
-			udev->state == USB_STATE_SUSPENDED) {
+	if (udev->state == USB_STATE_NOTATTACHED) {
 		dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
 				udev->state);
 		return -EINVAL;
@@ -5514,6 +5684,10 @@
 		return -EISDIR;
 	}
 
+	if (udev->reset_in_progress)
+		return -EINPROGRESS;
+	udev->reset_in_progress = 1;
+
 	port_dev = hub->ports[udev->portnum - 1];
 
 	/*
@@ -5570,11 +5744,15 @@
 					cintf->needs_binding = 1;
 			}
 		}
-		usb_unbind_and_rebind_marked_interfaces(udev);
+
+		/* If the reset failed, hub_wq will unbind drivers later */
+		if (ret == 0)
+			usb_unbind_and_rebind_marked_interfaces(udev);
 	}
 
 	usb_autosuspend_device(udev);
 	memalloc_noio_restore(noio_flag);
+	udev->reset_in_progress = 0;
 	return ret;
 }
 EXPORT_SYMBOL_GPL(usb_reset_device);
--- linux-4.4.0.orig/drivers/usb/core/hub.h
+++ linux-4.4.0/drivers/usb/core/hub.h
@@ -136,6 +136,13 @@
 	return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS;
 }
 
+static inline int hub_is_superspeedplus(struct usb_device *hdev)
+{
+	return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS &&
+		le16_to_cpu(hdev->descriptor.bcdUSB) >= 0x0310 &&
+		hdev->bos && hdev->bos->ssp_cap);
+}
+
 static inline unsigned hub_power_on_good_delay(struct usb_hub *hub)
 {
 	unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2;
--- linux-4.4.0.orig/drivers/usb/core/message.c
+++ linux-4.4.0/drivers/usb/core/message.c
@@ -147,6 +147,10 @@
 
 	ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
 
+	/* Linger a bit, prior to the next control message. */
+	if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
+		msleep(200);
+
 	kfree(dr);
 
 	return ret;
@@ -154,6 +158,143 @@
 EXPORT_SYMBOL_GPL(usb_control_msg);
 
 /**
+ * usb_control_msg_send - Builds a control "send" message, sends it off and waits for completion
+ * @dev: pointer to the usb device to send the message to
+ * @endpoint: endpoint to send the message to
+ * @request: USB message request value
+ * @requesttype: USB message request type value
+ * @value: USB message value
+ * @index: USB message index value
+ * @driver_data: pointer to the data to send
+ * @size: length in bytes of the data to send
+ * @timeout: time in msecs to wait for the message to complete before timing
+ *	out (if 0 the wait is forever)
+ * @memflags: the flags for memory allocation for buffers
+ *
+ * Context: !in_interrupt ()
+ *
+ * This function sends a control message to a specified endpoint that is not
+ * expected to fill in a response (i.e. a "send message") and waits for the
+ * message to complete, or timeout.
+ *
+ * Do not use this function from within an interrupt context. If you need
+ * an asynchronous message, or need to send a message from within interrupt
+ * context, use usb_submit_urb(). If a thread in your driver uses this call,
+ * make sure your disconnect() method can wait for it to complete. Since you
+ * don't have a handle on the URB used, you can't cancel the request.
+ *
+ * The data pointer can be made to a reference on the stack, or anywhere else,
+ * as it will not be modified at all.  This does not have the restriction that
+ * usb_control_msg() has where the data pointer must be to dynamically allocated
+ * memory (i.e. memory that can be successfully DMAed to a device).
+ *
+ * Return: If successful, 0 is returned, Otherwise, a negative error number.
+ */
+int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request,
+			 __u8 requesttype, __u16 value, __u16 index,
+			 const void *driver_data, __u16 size, int timeout,
+			 gfp_t memflags)
+{
+	unsigned int pipe = usb_sndctrlpipe(dev, endpoint);
+	int ret;
+	u8 *data = NULL;
+
+	if (usb_pipe_type_check(dev, pipe))
+		return -EINVAL;
+
+	if (size) {
+		data = kmemdup(driver_data, size, memflags);
+		if (!data)
+			return -ENOMEM;
+	}
+
+	ret = usb_control_msg(dev, pipe, request, requesttype, value, index,
+			      data, size, timeout);
+	kfree(data);
+
+	if (ret < 0)
+		return ret;
+	if (ret == size)
+		return 0;
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_control_msg_send);
+
+/**
+ * usb_control_msg_recv - Builds a control "receive" message, sends it off and waits for completion
+ * @dev: pointer to the usb device to send the message to
+ * @endpoint: endpoint to send the message to
+ * @request: USB message request value
+ * @requesttype: USB message request type value
+ * @value: USB message value
+ * @index: USB message index value
+ * @driver_data: pointer to the data to be filled in by the message
+ * @size: length in bytes of the data to be received
+ * @timeout: time in msecs to wait for the message to complete before timing
+ *	out (if 0 the wait is forever)
+ * @memflags: the flags for memory allocation for buffers
+ *
+ * Context: !in_interrupt ()
+ *
+ * This function sends a control message to a specified endpoint that is
+ * expected to fill in a response (i.e. a "receive message") and waits for the
+ * message to complete, or timeout.
+ *
+ * Do not use this function from within an interrupt context. If you need
+ * an asynchronous message, or need to send a message from within interrupt
+ * context, use usb_submit_urb(). If a thread in your driver uses this call,
+ * make sure your disconnect() method can wait for it to complete. Since you
+ * don't have a handle on the URB used, you can't cancel the request.
+ *
+ * The data pointer can be made to a reference on the stack, or anywhere else
+ * that can be successfully written to.  This function does not have the
+ * restriction that usb_control_msg() has where the data pointer must be to
+ * dynamically allocated memory (i.e. memory that can be successfully DMAed to a
+ * device).
+ *
+ * The "whole" message must be properly received from the device in order for
+ * this function to be successful.  If a device returns less than the expected
+ * amount of data, then the function will fail.  Do not use this for messages
+ * where a variable amount of data might be returned.
+ *
+ * Return: If successful, 0 is returned, Otherwise, a negative error number.
+ */
+int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request,
+			 __u8 requesttype, __u16 value, __u16 index,
+			 void *driver_data, __u16 size, int timeout,
+			 gfp_t memflags)
+{
+	unsigned int pipe = usb_rcvctrlpipe(dev, endpoint);
+	int ret;
+	u8 *data;
+
+	if (!size || !driver_data || usb_pipe_type_check(dev, pipe))
+		return -EINVAL;
+
+	data = kmalloc(size, memflags);
+	if (!data)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev, pipe, request, requesttype, value, index,
+			      data, size, timeout);
+
+	if (ret < 0)
+		goto exit;
+
+	if (ret == size) {
+		memcpy(driver_data, data, size);
+		ret = 0;
+	} else {
+		ret = -EINVAL;
+	}
+
+exit:
+	kfree(data);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_control_msg_recv);
+
+/**
  * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion
  * @usb_dev: pointer to the usb device to send the message to
  * @pipe: endpoint "pipe" to send the message to
@@ -302,9 +443,10 @@
 		 */
 		spin_unlock(&io->lock);
 		for (i = 0, found = 0; i < io->entries; i++) {
-			if (!io->urbs[i] || !io->urbs[i]->dev)
+			if (!io->urbs[i])
 				continue;
 			if (found) {
+				usb_block_urb(io->urbs[i]);
 				retval = usb_unlink_urb(io->urbs[i]);
 				if (retval != -EINPROGRESS &&
 				    retval != -ENODEV &&
@@ -515,12 +657,10 @@
 		int retval;
 
 		io->urbs[i]->dev = io->dev;
-		retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
-
-		/* after we submit, let completions or cancellations fire;
-		 * we handshake using io->status.
-		 */
 		spin_unlock_irq(&io->lock);
+
+		retval = usb_submit_urb(io->urbs[i], GFP_NOIO);
+
 		switch (retval) {
 			/* maybe we retrying will recover */
 		case -ENXIO:	/* hc didn't queue this one */
@@ -578,30 +718,34 @@
 void usb_sg_cancel(struct usb_sg_request *io)
 {
 	unsigned long flags;
+	int i, retval;
 
 	spin_lock_irqsave(&io->lock, flags);
+	if (io->status || io->count == 0) {
+		spin_unlock_irqrestore(&io->lock, flags);
+		return;
+	}
+	/* shut everything down */
+	io->status = -ECONNRESET;
+	io->count++;		/* Keep the request alive until we're done */
+	spin_unlock_irqrestore(&io->lock, flags);
 
-	/* shut everything down, if it didn't already */
-	if (!io->status) {
-		int i;
-
-		io->status = -ECONNRESET;
-		spin_unlock(&io->lock);
-		for (i = 0; i < io->entries; i++) {
-			int retval;
+	for (i = io->entries - 1; i >= 0; --i) {
+		usb_block_urb(io->urbs[i]);
 
-			if (!io->urbs[i]->dev)
-				continue;
-			retval = usb_unlink_urb(io->urbs[i]);
-			if (retval != -EINPROGRESS
-					&& retval != -ENODEV
-					&& retval != -EBUSY
-					&& retval != -EIDRM)
-				dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
-					__func__, retval);
-		}
-		spin_lock(&io->lock);
+		retval = usb_unlink_urb(io->urbs[i]);
+		if (retval != -EINPROGRESS
+		    && retval != -ENODEV
+		    && retval != -EBUSY
+		    && retval != -EIDRM)
+			dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
+				 __func__, retval);
 	}
+
+	spin_lock_irqsave(&io->lock, flags);
+	io->count--;
+	if (!io->count)
+		complete(&io->complete);
 	spin_unlock_irqrestore(&io->lock, flags);
 }
 EXPORT_SYMBOL_GPL(usb_sg_cancel);
@@ -816,9 +960,11 @@
 
 	if (dev->state == USB_STATE_SUSPENDED)
 		return -EHOSTUNREACH;
-	if (size <= 0 || !buf || !index)
+	if (size <= 0 || !buf)
 		return -EINVAL;
 	buf[0] = 0;
+	if (index <= 0 || index >= 256)
+		return -EINVAL;
 	tbuf = kmalloc(256, GFP_NOIO);
 	if (!tbuf)
 		return -ENOMEM;
@@ -1071,11 +1217,11 @@
 
 	if (usb_endpoint_out(epaddr)) {
 		ep = dev->ep_out[epnum];
-		if (reset_hardware)
+		if (reset_hardware && epnum != 0)
 			dev->ep_out[epnum] = NULL;
 	} else {
 		ep = dev->ep_in[epnum];
-		if (reset_hardware)
+		if (reset_hardware && epnum != 0)
 			dev->ep_in[epnum] = NULL;
 	}
 	if (ep) {
@@ -1132,6 +1278,34 @@
 	}
 }
 
+/*
+ * usb_disable_device_endpoints -- Disable all endpoints for a device
+ * @dev: the device whose endpoints are being disabled
+ * @skip_ep0: 0 to disable endpoint 0, 1 to skip it.
+ */
+static void usb_disable_device_endpoints(struct usb_device *dev, int skip_ep0)
+{
+	struct usb_hcd *hcd = bus_to_hcd(dev->bus);
+	int i;
+
+	if (hcd->driver->check_bandwidth) {
+		/* First pass: Cancel URBs, leave endpoint pointers intact. */
+		for (i = skip_ep0; i < 16; ++i) {
+			usb_disable_endpoint(dev, i, false);
+			usb_disable_endpoint(dev, i + USB_DIR_IN, false);
+		}
+		/* Remove endpoints from the host controller internal state */
+		mutex_lock(hcd->bandwidth_mutex);
+		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+		mutex_unlock(hcd->bandwidth_mutex);
+	}
+	/* Second pass: remove endpoint pointers */
+	for (i = skip_ep0; i < 16; ++i) {
+		usb_disable_endpoint(dev, i, true);
+		usb_disable_endpoint(dev, i + USB_DIR_IN, true);
+	}
+}
+
 /**
  * usb_disable_device - Disable all the endpoints for a USB device
  * @dev: the device whose endpoints are being disabled
@@ -1145,7 +1319,6 @@
 void usb_disable_device(struct usb_device *dev, int skip_ep0)
 {
 	int i;
-	struct usb_hcd *hcd = bus_to_hcd(dev->bus);
 
 	/* getting rid of interfaces will disconnect
 	 * any drivers bound to them (a key side effect)
@@ -1180,8 +1353,7 @@
 			dev->actconfig->interface[i] = NULL;
 		}
 
-		if (dev->usb2_hw_lpm_enabled == 1)
-			usb_set_usb2_hardware_lpm(dev, 0);
+		usb_disable_usb2_hardware_lpm(dev);
 		usb_unlocked_disable_lpm(dev);
 		usb_disable_ltm(dev);
 
@@ -1192,22 +1364,8 @@
 
 	dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
 		skip_ep0 ? "non-ep0" : "all");
-	if (hcd->driver->check_bandwidth) {
-		/* First pass: Cancel URBs, leave endpoint pointers intact. */
-		for (i = skip_ep0; i < 16; ++i) {
-			usb_disable_endpoint(dev, i, false);
-			usb_disable_endpoint(dev, i + USB_DIR_IN, false);
-		}
-		/* Remove endpoints from the host controller internal state */
-		mutex_lock(hcd->bandwidth_mutex);
-		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
-		mutex_unlock(hcd->bandwidth_mutex);
-		/* Second pass: remove endpoint pointers */
-	}
-	for (i = skip_ep0; i < 16; ++i) {
-		usb_disable_endpoint(dev, i, true);
-		usb_disable_endpoint(dev, i + USB_DIR_IN, true);
-	}
+
+	usb_disable_device_endpoints(dev, skip_ep0);
 }
 
 /**
@@ -1278,6 +1436,11 @@
  * is submitted that needs that bandwidth.  Some other operating systems
  * allocate bandwidth early, when a configuration is chosen.
  *
+ * xHCI reserves bandwidth and configures the alternate setting in
+ * usb_hcd_alloc_bandwidth(). If it fails the original interface altsetting
+ * may be disabled. Drivers cannot rely on any particular alternate
+ * setting being in effect after a failure.
+ *
  * This call is synchronous, and may not be used in an interrupt context.
  * Also, drivers must not change altsettings while urbs are scheduled for
  * endpoints in that interface; all such urbs must first be completed
@@ -1313,6 +1476,12 @@
 			 alternate);
 		return -EINVAL;
 	}
+	/*
+	 * usb3 hosts configure the interface in usb_hcd_alloc_bandwidth,
+	 * including freeing dropped endpoint ring buffers.
+	 * Make sure the interface endpoints are flushed before that
+	 */
+	usb_disable_interface(dev, iface, false);
 
 	/* Make sure we have enough bandwidth for this alternate interface.
 	 * Remove the current alt setting and add the new alt setting.
@@ -1439,6 +1608,9 @@
  * The caller must own the device lock.
  *
  * Return: Zero on success, else a negative error code.
+ *
+ * If this routine fails the device will probably be in an unusable state
+ * with endpoints disabled, and interfaces only partially enabled.
  */
 int usb_reset_configuration(struct usb_device *dev)
 {
@@ -1454,10 +1626,7 @@
 	 * calls during probe() are fine
 	 */
 
-	for (i = 1; i < 16; ++i) {
-		usb_disable_endpoint(dev, i, true);
-		usb_disable_endpoint(dev, i + USB_DIR_IN, true);
-	}
+	usb_disable_device_endpoints(dev, 1); /* skip ep0*/
 
 	config = dev->actconfig;
 	retval = 0;
@@ -1470,34 +1639,10 @@
 		mutex_unlock(hcd->bandwidth_mutex);
 		return -ENOMEM;
 	}
-	/* Make sure we have enough bandwidth for each alternate setting 0 */
-	for (i = 0; i < config->desc.bNumInterfaces; i++) {
-		struct usb_interface *intf = config->interface[i];
-		struct usb_host_interface *alt;
-
-		alt = usb_altnum_to_altsetting(intf, 0);
-		if (!alt)
-			alt = &intf->altsetting[0];
-		if (alt != intf->cur_altsetting)
-			retval = usb_hcd_alloc_bandwidth(dev, NULL,
-					intf->cur_altsetting, alt);
-		if (retval < 0)
-			break;
-	}
-	/* If not, reinstate the old alternate settings */
+
+	/* xHCI adds all endpoints in usb_hcd_alloc_bandwidth */
+	retval = usb_hcd_alloc_bandwidth(dev, config, NULL, NULL);
 	if (retval < 0) {
-reset_old_alts:
-		for (i--; i >= 0; i--) {
-			struct usb_interface *intf = config->interface[i];
-			struct usb_host_interface *alt;
-
-			alt = usb_altnum_to_altsetting(intf, 0);
-			if (!alt)
-				alt = &intf->altsetting[0];
-			if (alt != intf->cur_altsetting)
-				usb_hcd_alloc_bandwidth(dev, NULL,
-						alt, intf->cur_altsetting);
-		}
 		usb_enable_lpm(dev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		return retval;
@@ -1506,8 +1651,12 @@
 			USB_REQ_SET_CONFIGURATION, 0,
 			config->desc.bConfigurationValue, 0,
 			NULL, 0, USB_CTRL_SET_TIMEOUT);
-	if (retval < 0)
-		goto reset_old_alts;
+	if (retval < 0) {
+		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+		usb_enable_lpm(dev);
+		mutex_unlock(hcd->bandwidth_mutex);
+		return retval;
+	}
 	mutex_unlock(hcd->bandwidth_mutex);
 
 	/* re-init hc/hcd interface/endpoint state */
--- linux-4.4.0.orig/drivers/usb/core/port.c
+++ linux-4.4.0/drivers/usb/core/port.c
@@ -98,7 +98,10 @@
 	if (!port_dev->is_superspeed && peer)
 		pm_runtime_get_sync(&peer->dev);
 
-	usb_autopm_get_interface(intf);
+	retval = usb_autopm_get_interface(intf);
+	if (retval < 0)
+		return retval;
+
 	retval = usb_hub_set_port_power(hdev, hub, port1, true);
 	msleep(hub_power_on_good_delay(hub));
 	if (udev && !retval) {
@@ -151,7 +154,10 @@
 	if (usb_port_block_power_off)
 		return -EBUSY;
 
-	usb_autopm_get_interface(intf);
+	retval = usb_autopm_get_interface(intf);
+	if (retval < 0)
+		return retval;
+
 	retval = usb_hub_set_port_power(hdev, hub, port1, false);
 	usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
 	if (!port_dev->is_superspeed)
--- linux-4.4.0.orig/drivers/usb/core/quirks.c
+++ linux-4.4.0/drivers/usb/core/quirks.c
@@ -37,22 +37,48 @@
 	/* CBM - Flash disk */
 	{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* WORLDE Controller KS49 or Prodipe MIDI 49C USB controller */
+	{ USB_DEVICE(0x0218, 0x0201), .driver_info =
+			USB_QUIRK_CONFIG_INTF_STRINGS },
+
+	/* WORLDE easy key (easykey.25) MIDI controller  */
+	{ USB_DEVICE(0x0218, 0x0401), .driver_info =
+			USB_QUIRK_CONFIG_INTF_STRINGS },
+
 	/* HP 5300/5370C scanner */
 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info =
 			USB_QUIRK_STRING_FETCH_255 },
 
+	/* HP v222w 16GB Mini USB Drive */
+	{ USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT },
+
 	/* Creative SB Audigy 2 NX */
 	{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* USB3503 */
+	{ USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	/* Microsoft Wireless Laser Mouse 6000 Receiver */
 	{ USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME },
 
 	/* Microsoft LifeCam-VX700 v2.0 */
 	{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
 
-	/* Logitech HD Pro Webcams C920 and C930e */
+	/* Microsoft Surface Dock Ethernet (RTL8153 GigE) */
+	{ USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM },
+
+	/* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */
+	{ USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech HD Webcam C270 */
+	{ USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech HD Pro Webcams C920, C920-C, C922, C925e and C930e */
 	{ USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
+	{ USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT },
 	{ USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
+	{ USB_DEVICE(0x046d, 0x085b), .driver_info = USB_QUIRK_DELAY_INIT },
+	{ USB_DEVICE(0x046d, 0x085c), .driver_info = USB_QUIRK_DELAY_INIT },
 
 	/* Logitech ConferenceCam CC3000e */
 	{ USB_DEVICE(0x046d, 0x0847), .driver_info = USB_QUIRK_DELAY_INIT },
@@ -61,6 +87,9 @@
 	/* Logitech PTZ Pro Camera */
 	{ USB_DEVICE(0x046d, 0x0853), .driver_info = USB_QUIRK_DELAY_INIT },
 
+	/* Logitech Screen Share */
+	{ USB_DEVICE(0x046d, 0x086c), .driver_info = USB_QUIRK_NO_LPM },
+
 	/* Logitech Quickcam Fusion */
 	{ USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -125,6 +154,9 @@
 	{ USB_DEVICE(0x04f3, 0x016f), .driver_info =
 			USB_QUIRK_DEVICE_QUALIFIER },
 
+	{ USB_DEVICE(0x04f3, 0x0381), .driver_info =
+			USB_QUIRK_NO_LPM },
+
 	{ USB_DEVICE(0x04f3, 0x21b8), .driver_info =
 			USB_QUIRK_DEVICE_QUALIFIER },
 
@@ -140,6 +172,15 @@
 	/* appletouch */
 	{ USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Genesys Logic hub, internally used by KY-688 USB 3.1 Type-C Hub */
+	{ USB_DEVICE(0x05e3, 0x0612), .driver_info = USB_QUIRK_NO_LPM },
+
+	/* ELSA MicroLink 56K */
+	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Genesys Logic hub, internally used by Moshi USB to Ethernet Adapter */
+	{ USB_DEVICE(0x05e3, 0x0616), .driver_info = USB_QUIRK_NO_LPM },
+
 	/* Avision AV600U */
 	{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
 	  USB_QUIRK_STRING_FETCH_255 },
@@ -148,31 +189,70 @@
 	{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
 			USB_QUIRK_CONFIG_INTF_STRINGS },
 
+	/* Agfa SNAPSCAN 1212U */
+	{ USB_DEVICE(0x06bd, 0x0001), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	/* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */
 	{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
 
 	/* Guillemot Webcam Hercules Dualpix Exchange*/
 	{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Guillemot Hercules DJ Console audio card (BZ 208357) */
+	{ USB_DEVICE(0x06f8, 0xb000), .driver_info =
+			USB_QUIRK_ENDPOINT_BLACKLIST },
+
 	/* Midiman M-Audio Keystation 88es */
 	{ USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* SanDisk Ultra Fit and Ultra Flair */
+	{ USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM },
+	{ USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM },
+
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Baum Vario Ultra */
+	{ USB_DEVICE(0x0904, 0x6101), .driver_info =
+			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+	{ USB_DEVICE(0x0904, 0x6102), .driver_info =
+			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+	{ USB_DEVICE(0x0904, 0x6103), .driver_info =
+			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+
 	/* Keytouch QWERTY Panel keyboard */
 	{ USB_DEVICE(0x0926, 0x3333), .driver_info =
 			USB_QUIRK_CONFIG_INTF_STRINGS },
 
+	/* Kingston DataTraveler 3.0 */
+	{ USB_DEVICE(0x0951, 0x1666), .driver_info = USB_QUIRK_NO_LPM },
+
 	/* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
 	{ USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
 
+	/* ELMO L-12F document camera */
+	{ USB_DEVICE(0x09a1, 0x0028), .driver_info = USB_QUIRK_DELAY_CTRL_MSG },
+
 	/* Broadcom BCM92035DGROM BT dongle */
 	{ USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME },
 
 	/* MAYA44USB sound device */
 	{ USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* ASUS Base Station(T100) */
+	{ USB_DEVICE(0x0b05, 0x17e0), .driver_info =
+			USB_QUIRK_IGNORE_REMOTE_WAKEUP },
+
+	/* Realtek hub in Dell WD19 (Type-C) */
+	{ USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM },
+
+	/* Generic RTL8153 based ethernet adapters */
+	{ USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM },
+
+	/* SONiX USB DEVICE Touchpad */
+	{ USB_DEVICE(0x0c45, 0x7056), .driver_info =
+			USB_QUIRK_IGNORE_REMOTE_WAKEUP },
+
 	/* Action Semiconductor flash disk */
 	{ USB_DEVICE(0x10d6, 0x2200), .driver_info =
 			USB_QUIRK_STRING_FETCH_255 },
@@ -188,26 +268,65 @@
 	{ USB_DEVICE(0x1908, 0x1315), .driver_info =
 			USB_QUIRK_HONOR_BNUMINTERFACES },
 
-	/* INTEL VALUE SSD */
-	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* USB3503 */
-	{ USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* ASUS Base Station(T100) */
-	{ USB_DEVICE(0x0b05, 0x17e0), .driver_info =
-			USB_QUIRK_IGNORE_REMOTE_WAKEUP },
-
 	/* Protocol and OTG Electrical Test Device */
 	{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
 			USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
 
+	/* Corsair K70 RGB */
+	{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT |
+	  USB_QUIRK_DELAY_CTRL_MSG },
+
+	/* Corsair Strafe */
+	{ USB_DEVICE(0x1b1c, 0x1b15), .driver_info = USB_QUIRK_DELAY_INIT |
+	  USB_QUIRK_DELAY_CTRL_MSG },
+
+	/* Corsair Strafe RGB */
+	{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT |
+	  USB_QUIRK_DELAY_CTRL_MSG },
+
+	/* Corsair K70 LUX RGB */
+	{ USB_DEVICE(0x1b1c, 0x1b33), .driver_info = USB_QUIRK_DELAY_INIT },
+
+	/* Corsair K70 LUX */
+	{ USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
+
+	/* Corsair K70 RGB RAPDIFIRE */
+	{ USB_DEVICE(0x1b1c, 0x1b38), .driver_info = USB_QUIRK_DELAY_INIT |
+	  USB_QUIRK_DELAY_CTRL_MSG },
+
+	/* MIDI keyboard WORLDE MINI */
+	{ USB_DEVICE(0x1c75, 0x0204), .driver_info =
+			USB_QUIRK_CONFIG_INTF_STRINGS },
+
+	/* Acer C120 LED Projector */
+	{ USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM },
+
 	/* Blackmagic Design Intensity Shuttle */
 	{ USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM },
 
 	/* Blackmagic Design UltraStudio SDI */
 	{ USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },
 
+	/* Hauppauge HVR-950q */
+	{ USB_DEVICE(0x2040, 0x7200), .driver_info =
+			USB_QUIRK_CONFIG_INTF_STRINGS },
+
+	/* Raydium Touchscreen */
+	{ USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM },
+
+	{ USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM },
+
+	{ USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
+
+	/* DJI CineSSD */
+	{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
+
+	/* INTEL VALUE SSD */
+	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* novation SoundControl XL */
+	{ USB_DEVICE(0x1235, 0x0061), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	{ }  /* terminating entry must be last */
 };
 
@@ -227,6 +346,7 @@
 	{ USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME },
 	{ USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME },
 	{ USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME },
+	{ USB_DEVICE(0x03f0, 0x2b4a), .driver_info = USB_QUIRK_RESET_RESUME },
 
 	/* Logitech Optical Mouse M90/M100 */
 	{ USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -234,6 +354,40 @@
 	{ }  /* terminating entry must be last */
 };
 
+/*
+ * Entries for blacklisted endpoints that should be ignored when parsing
+ * configuration descriptors.
+ *
+ * Matched for devices with USB_QUIRK_ENDPOINT_BLACKLIST.
+ */
+static const struct usb_device_id usb_endpoint_blacklist[] = {
+	{ USB_DEVICE_INTERFACE_NUMBER(0x06f8, 0xb000, 5), .driver_info = 0x01 },
+	{ USB_DEVICE_INTERFACE_NUMBER(0x06f8, 0xb000, 5), .driver_info = 0x81 },
+	{ }
+};
+
+bool usb_endpoint_is_blacklisted(struct usb_device *udev,
+		struct usb_host_interface *intf,
+		struct usb_endpoint_descriptor *epd)
+{
+	const struct usb_device_id *id;
+	unsigned int address;
+
+	for (id = usb_endpoint_blacklist; id->match_flags; ++id) {
+		if (!usb_match_device(udev, id))
+			continue;
+
+		if (!usb_match_one_id_intf(udev, intf, id))
+			continue;
+
+		address = id->driver_info;
+		if (address == epd->bEndpointAddress)
+			return true;
+	}
+
+	return false;
+}
+
 static bool usb_match_any_interface(struct usb_device *udev,
 				    const struct usb_device_id *id)
 {
--- linux-4.4.0.orig/drivers/usb/core/sysfs.c
+++ linux-4.4.0/drivers/usb/core/sysfs.c
@@ -141,6 +141,9 @@
 	case USB_SPEED_SUPER:
 		speed = "5000";
 		break;
+	case USB_SPEED_SUPER_PLUS:
+		speed = "10000";
+		break;
 	default:
 		speed = "unknown";
 	}
@@ -472,7 +475,10 @@
 
 	if (!ret) {
 		udev->usb2_hw_lpm_allowed = value;
-		ret = usb_set_usb2_hardware_lpm(udev, value);
+		if (value)
+			ret = usb_enable_usb2_hardware_lpm(udev);
+		else
+			ret = usb_disable_usb2_hardware_lpm(udev);
 	}
 
 	usb_unlock_device(udev);
@@ -531,7 +537,26 @@
 }
 static DEVICE_ATTR_RW(usb2_lpm_besl);
 
-static ssize_t usb3_hardware_lpm_show(struct device *dev,
+static ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	const char *p;
+
+	usb_lock_device(udev);
+
+	if (udev->usb3_lpm_u1_enabled)
+		p = "enabled";
+	else
+		p = "disabled";
+
+	usb_unlock_device(udev);
+
+	return sprintf(buf, "%s\n", p);
+}
+static DEVICE_ATTR_RO(usb3_hardware_lpm_u1);
+
+static ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
@@ -539,7 +564,7 @@
 
 	usb_lock_device(udev);
 
-	if (udev->usb3_lpm_enabled)
+	if (udev->usb3_lpm_u2_enabled)
 		p = "enabled";
 	else
 		p = "disabled";
@@ -548,7 +573,7 @@
 
 	return sprintf(buf, "%s\n", p);
 }
-static DEVICE_ATTR_RO(usb3_hardware_lpm);
+static DEVICE_ATTR_RO(usb3_hardware_lpm_u2);
 
 static struct attribute *usb2_hardware_lpm_attr[] = {
 	&dev_attr_usb2_hardware_lpm.attr,
@@ -562,7 +587,8 @@
 };
 
 static struct attribute *usb3_hardware_lpm_attr[] = {
-	&dev_attr_usb3_hardware_lpm.attr,
+	&dev_attr_usb3_hardware_lpm_u1.attr,
+	&dev_attr_usb3_hardware_lpm_u2.attr,
 	NULL,
 };
 static struct attribute_group usb3_hardware_lpm_attr_group = {
@@ -592,7 +618,8 @@
 		if (udev->usb2_hw_lpm_capable == 1)
 			rc = sysfs_merge_group(&dev->kobj,
 					&usb2_hardware_lpm_attr_group);
-		if (udev->lpm_capable == 1)
+		if (udev->speed == USB_SPEED_SUPER &&
+				udev->lpm_capable == 1)
 			rc = sysfs_merge_group(&dev->kobj,
 					&usb3_hardware_lpm_attr_group);
 	}
@@ -977,14 +1004,24 @@
 {
 	struct usb_interface *intf = to_usb_interface(dev);
 	bool val;
+	struct kernfs_node *kn;
 
 	if (strtobool(buf, &val) != 0)
 		return -EINVAL;
 
-	if (val)
+	if (val) {
 		usb_authorize_interface(intf);
-	else
-		usb_deauthorize_interface(intf);
+	} else {
+		/*
+		 * Prevent deadlock if another process is concurrently
+		 * trying to unregister intf.
+		 */
+		kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
+		if (kn) {
+			usb_deauthorize_interface(intf);
+			sysfs_unbreak_active_protection(kn);
+		}
+	}
 
 	return count;
 }
--- linux-4.4.0.orig/drivers/usb/core/urb.c
+++ linux-4.4.0/drivers/usb/core/urb.c
@@ -40,6 +40,7 @@
 	if (urb) {
 		memset(urb, 0, sizeof(*urb));
 		kref_init(&urb->kref);
+		INIT_LIST_HEAD(&urb->urb_list);
 		INIT_LIST_HEAD(&urb->anchor_list);
 	}
 }
@@ -184,6 +185,46 @@
 
 /*-------------------------------------------------------------------*/
 
+static const int pipetypes[4] = {
+	PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
+/**
+ * usb_pipe_type_check - sanity check of a specific pipe for a usb device
+ * @dev: struct usb_device to be checked
+ * @pipe: pipe to check
+ *
+ * This performs a light-weight sanity check for the endpoint in the
+ * given usb device.  It returns 0 if the pipe is valid for the specific usb
+ * device, otherwise a negative error code.
+ */
+int usb_pipe_type_check(struct usb_device *dev, unsigned int pipe)
+{
+	const struct usb_host_endpoint *ep;
+
+	ep = usb_pipe_endpoint(dev, pipe);
+	if (!ep)
+		return -EINVAL;
+	if (usb_pipetype(pipe) != pipetypes[usb_endpoint_type(&ep->desc)])
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_pipe_type_check);
+
+/**
+ * usb_urb_ep_type_check - sanity check of endpoint in the given urb
+ * @urb: urb to be checked
+ *
+ * This performs a light-weight sanity check for the endpoint in the
+ * given urb.  It returns 0 if the urb contains a valid endpoint, otherwise
+ * a negative error code.
+ */
+int usb_urb_ep_type_check(const struct urb *urb)
+{
+	return usb_pipe_type_check(urb->dev, urb->pipe);
+}
+EXPORT_SYMBOL_GPL(usb_urb_ep_type_check);
+
 /**
  * usb_submit_urb - issue an asynchronous transfer request for an endpoint
  * @urb: pointer to the urb describing the request
@@ -323,9 +364,6 @@
  */
 int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 {
-	static int			pipetypes[4] = {
-		PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
-	};
 	int				xfertype, max;
 	struct usb_device		*dev;
 	struct usb_host_endpoint	*ep;
@@ -335,7 +373,7 @@
 	if (!urb || !urb->complete)
 		return -EINVAL;
 	if (urb->hcpriv) {
-		WARN_ONCE(1, "URB %p submitted while active\n", urb);
+		WARN_ONCE(1, "URB %pK submitted while active\n", urb);
 		return -EBUSY;
 	}
 
@@ -401,7 +439,7 @@
 		/* SuperSpeed isoc endpoints have up to 16 bursts of up to
 		 * 3 packets each
 		 */
-		if (dev->speed == USB_SPEED_SUPER) {
+		if (dev->speed >= USB_SPEED_SUPER) {
 			int     burst = 1 + ep->ss_ep_comp.bMaxBurst;
 			int     mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
 			max *= burst;
@@ -444,7 +482,7 @@
 	 */
 
 	/* Check that the pipe's type matches the endpoint's type */
-	if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+	if (usb_pipe_type_check(urb->dev, urb->pipe))
 		dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
 			usb_pipetype(urb->pipe), pipetypes[xfertype]);
 
@@ -499,6 +537,7 @@
 		}
 		/* too big? */
 		switch (dev->speed) {
+		case USB_SPEED_SUPER_PLUS:
 		case USB_SPEED_SUPER:	/* units are 125us */
 			/* Handle up to 2^(16-1) microframes */
 			if (urb->interval > (1 << 15))
@@ -743,11 +782,12 @@
 EXPORT_SYMBOL_GPL(usb_block_urb);
 
 /**
- * usb_kill_anchored_urbs - cancel transfer requests en masse
+ * usb_kill_anchored_urbs - kill all URBs associated with an anchor
  * @anchor: anchor the requests are bound to
  *
- * this allows all outstanding URBs to be killed starting
- * from the back of the queue
+ * This kills all outstanding URBs starting from the back of the queue,
+ * with guarantee that no completer callbacks will take place from the
+ * anchor after this function returns.
  *
  * This routine should not be called by a driver after its disconnect
  * method has returned.
@@ -755,20 +795,26 @@
 void usb_kill_anchored_urbs(struct usb_anchor *anchor)
 {
 	struct urb *victim;
+	int surely_empty;
 
-	spin_lock_irq(&anchor->lock);
-	while (!list_empty(&anchor->urb_list)) {
-		victim = list_entry(anchor->urb_list.prev, struct urb,
-				    anchor_list);
-		/* we must make sure the URB isn't freed before we kill it*/
-		usb_get_urb(victim);
-		spin_unlock_irq(&anchor->lock);
-		/* this will unanchor the URB */
-		usb_kill_urb(victim);
-		usb_put_urb(victim);
+	do {
 		spin_lock_irq(&anchor->lock);
-	}
-	spin_unlock_irq(&anchor->lock);
+		while (!list_empty(&anchor->urb_list)) {
+			victim = list_entry(anchor->urb_list.prev,
+					    struct urb, anchor_list);
+			/* make sure the URB isn't freed before we kill it */
+			usb_get_urb(victim);
+			spin_unlock_irq(&anchor->lock);
+			/* this will unanchor the URB */
+			usb_kill_urb(victim);
+			usb_put_urb(victim);
+			spin_lock_irq(&anchor->lock);
+		}
+		surely_empty = usb_anchor_check_wakeup(anchor);
+
+		spin_unlock_irq(&anchor->lock);
+		cpu_relax();
+	} while (!surely_empty);
 }
 EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
 
@@ -787,21 +833,27 @@
 void usb_poison_anchored_urbs(struct usb_anchor *anchor)
 {
 	struct urb *victim;
+	int surely_empty;
 
-	spin_lock_irq(&anchor->lock);
-	anchor->poisoned = 1;
-	while (!list_empty(&anchor->urb_list)) {
-		victim = list_entry(anchor->urb_list.prev, struct urb,
-				    anchor_list);
-		/* we must make sure the URB isn't freed before we kill it*/
-		usb_get_urb(victim);
-		spin_unlock_irq(&anchor->lock);
-		/* this will unanchor the URB */
-		usb_poison_urb(victim);
-		usb_put_urb(victim);
+	do {
 		spin_lock_irq(&anchor->lock);
-	}
-	spin_unlock_irq(&anchor->lock);
+		anchor->poisoned = 1;
+		while (!list_empty(&anchor->urb_list)) {
+			victim = list_entry(anchor->urb_list.prev,
+					    struct urb, anchor_list);
+			/* make sure the URB isn't freed before we kill it */
+			usb_get_urb(victim);
+			spin_unlock_irq(&anchor->lock);
+			/* this will unanchor the URB */
+			usb_poison_urb(victim);
+			usb_put_urb(victim);
+			spin_lock_irq(&anchor->lock);
+		}
+		surely_empty = usb_anchor_check_wakeup(anchor);
+
+		spin_unlock_irq(&anchor->lock);
+		cpu_relax();
+	} while (!surely_empty);
 }
 EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
 
@@ -941,14 +993,20 @@
 {
 	struct urb *victim;
 	unsigned long flags;
+	int surely_empty;
 
-	spin_lock_irqsave(&anchor->lock, flags);
-	while (!list_empty(&anchor->urb_list)) {
-		victim = list_entry(anchor->urb_list.prev, struct urb,
-				    anchor_list);
-		__usb_unanchor_urb(victim, anchor);
-	}
-	spin_unlock_irqrestore(&anchor->lock, flags);
+	do {
+		spin_lock_irqsave(&anchor->lock, flags);
+		while (!list_empty(&anchor->urb_list)) {
+			victim = list_entry(anchor->urb_list.prev,
+					    struct urb, anchor_list);
+			__usb_unanchor_urb(victim, anchor);
+		}
+		surely_empty = usb_anchor_check_wakeup(anchor);
+
+		spin_unlock_irqrestore(&anchor->lock, flags);
+		cpu_relax();
+	} while (!surely_empty);
 }
 
 EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
--- linux-4.4.0.orig/drivers/usb/core/usb-acpi.c
+++ linux-4.4.0/drivers/usb/core/usb-acpi.c
@@ -127,6 +127,22 @@
  */
 #define USB_ACPI_LOCATION_VALID (1 << 31)
 
+static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
+					      int raw)
+{
+	struct acpi_device *adev;
+
+	if (!parent)
+		return NULL;
+
+	list_for_each_entry(adev, &parent->children, node) {
+		if (acpi_device_adr(adev) == raw)
+			return adev;
+	}
+
+	return acpi_find_child_device(parent, raw, false);
+}
+
 static struct acpi_device *usb_acpi_find_companion(struct device *dev)
 {
 	struct usb_device *udev;
@@ -174,8 +190,10 @@
 			int raw;
 
 			raw = usb_hcd_find_raw_port_number(hcd, port1);
-			adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev),
-					raw, false);
+
+			adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
+						  raw);
+
 			if (!adev)
 				return NULL;
 		} else {
@@ -186,7 +204,9 @@
 				return NULL;
 
 			acpi_bus_get_device(parent_handle, &adev);
-			adev = acpi_find_child_device(adev, port1, false);
+
+			adev = usb_acpi_find_port(adev, port1);
+
 			if (!adev)
 				return NULL;
 		}
--- linux-4.4.0.orig/drivers/usb/core/usb.c
+++ linux-4.4.0/drivers/usb/core/usb.c
@@ -75,6 +75,205 @@
 #define usb_autosuspend_delay		0
 #endif
 
+static bool match_endpoint(struct usb_endpoint_descriptor *epd,
+		struct usb_endpoint_descriptor **bulk_in,
+		struct usb_endpoint_descriptor **bulk_out,
+		struct usb_endpoint_descriptor **int_in,
+		struct usb_endpoint_descriptor **int_out)
+{
+	switch (usb_endpoint_type(epd)) {
+	case USB_ENDPOINT_XFER_BULK:
+		if (usb_endpoint_dir_in(epd)) {
+			if (bulk_in && !*bulk_in) {
+				*bulk_in = epd;
+				break;
+			}
+		} else {
+			if (bulk_out && !*bulk_out) {
+				*bulk_out = epd;
+				break;
+			}
+		}
+
+		return false;
+	case USB_ENDPOINT_XFER_INT:
+		if (usb_endpoint_dir_in(epd)) {
+			if (int_in && !*int_in) {
+				*int_in = epd;
+				break;
+			}
+		} else {
+			if (int_out && !*int_out) {
+				*int_out = epd;
+				break;
+			}
+		}
+
+		return false;
+	default:
+		return false;
+	}
+
+	return (!bulk_in || *bulk_in) && (!bulk_out || *bulk_out) &&
+			(!int_in || *int_in) && (!int_out || *int_out);
+}
+
+/**
+ * usb_find_common_endpoints() -- look up common endpoint descriptors
+ * @alt:	alternate setting to search
+ * @bulk_in:	pointer to descriptor pointer, or NULL
+ * @bulk_out:	pointer to descriptor pointer, or NULL
+ * @int_in:	pointer to descriptor pointer, or NULL
+ * @int_out:	pointer to descriptor pointer, or NULL
+ *
+ * Search the alternate setting's endpoint descriptors for the first bulk-in,
+ * bulk-out, interrupt-in and interrupt-out endpoints and return them in the
+ * provided pointers (unless they are NULL).
+ *
+ * If a requested endpoint is not found, the corresponding pointer is set to
+ * NULL.
+ *
+ * Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
+ */
+int usb_find_common_endpoints(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **bulk_in,
+		struct usb_endpoint_descriptor **bulk_out,
+		struct usb_endpoint_descriptor **int_in,
+		struct usb_endpoint_descriptor **int_out)
+{
+	struct usb_endpoint_descriptor *epd;
+	int i;
+
+	if (bulk_in)
+		*bulk_in = NULL;
+	if (bulk_out)
+		*bulk_out = NULL;
+	if (int_in)
+		*int_in = NULL;
+	if (int_out)
+		*int_out = NULL;
+
+	for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
+		epd = &alt->endpoint[i].desc;
+
+		if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
+			return 0;
+	}
+
+	return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints);
+
+/**
+ * usb_find_common_endpoints_reverse() -- look up common endpoint descriptors
+ *
+ * Same as usb_find_common_endpoints(), but the endpoint descriptors are
+ * searched in reverse order (see usb_find_common_endpoints() for details).
+ */
+int usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **bulk_in,
+		struct usb_endpoint_descriptor **bulk_out,
+		struct usb_endpoint_descriptor **int_in,
+		struct usb_endpoint_descriptor **int_out)
+{
+	struct usb_endpoint_descriptor *epd;
+	int i;
+
+	if (bulk_in)
+		*bulk_in = NULL;
+	if (bulk_out)
+		*bulk_out = NULL;
+	if (int_in)
+		*int_in = NULL;
+	if (int_out)
+		*int_out = NULL;
+
+	for (i = alt->desc.bNumEndpoints - 1; i >= 0; --i) {
+		epd = &alt->endpoint[i].desc;
+
+		if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
+			return 0;
+	}
+
+	return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse);
+
+/**
+ * usb_find_endpoint() - Given an endpoint address, search for the endpoint's
+ * usb_host_endpoint structure in an interface's current altsetting.
+ * @intf: the interface whose current altsetting should be searched
+ * @ep_addr: the endpoint address (number and direction) to find
+ *
+ * Search the altsetting's list of endpoints for one with the specified address.
+ *
+ * Return: Pointer to the usb_host_endpoint if found, %NULL otherwise.
+ */
+static const struct usb_host_endpoint *usb_find_endpoint(
+		const struct usb_interface *intf, unsigned int ep_addr)
+{
+	int n;
+	const struct usb_host_endpoint *ep;
+
+	n = intf->cur_altsetting->desc.bNumEndpoints;
+	ep = intf->cur_altsetting->endpoint;
+	for (; n > 0; (--n, ++ep)) {
+		if (ep->desc.bEndpointAddress == ep_addr)
+			return ep;
+	}
+	return NULL;
+}
+
+/**
+ * usb_check_bulk_endpoints - Check whether an interface's current altsetting
+ * contains a set of bulk endpoints with the given addresses.
+ * @intf: the interface whose current altsetting should be searched
+ * @ep_addrs: 0-terminated array of the endpoint addresses (number and
+ * direction) to look for
+ *
+ * Search for endpoints with the specified addresses and check their types.
+ *
+ * Return: %true if all the endpoints are found and are bulk, %false otherwise.
+ */
+bool usb_check_bulk_endpoints(
+		const struct usb_interface *intf, const u8 *ep_addrs)
+{
+	const struct usb_host_endpoint *ep;
+
+	for (; *ep_addrs; ++ep_addrs) {
+		ep = usb_find_endpoint(intf, *ep_addrs);
+		if (!ep || !usb_endpoint_xfer_bulk(&ep->desc))
+			return false;
+	}
+	return true;
+}
+EXPORT_SYMBOL_GPL(usb_check_bulk_endpoints);
+
+/**
+ * usb_check_int_endpoints - Check whether an interface's current altsetting
+ * contains a set of interrupt endpoints with the given addresses.
+ * @intf: the interface whose current altsetting should be searched
+ * @ep_addrs: 0-terminated array of the endpoint addresses (number and
+ * direction) to look for
+ *
+ * Search for endpoints with the specified addresses and check their types.
+ *
+ * Return: %true if all the endpoints are found and are interrupt,
+ * %false otherwise.
+ */
+bool usb_check_int_endpoints(
+		const struct usb_interface *intf, const u8 *ep_addrs)
+{
+	const struct usb_host_endpoint *ep;
+
+	for (; *ep_addrs; ++ep_addrs) {
+		ep = usb_find_endpoint(intf, *ep_addrs);
+		if (!ep || !usb_endpoint_xfer_int(&ep->desc))
+			return false;
+	}
+	return true;
+}
+EXPORT_SYMBOL_GPL(usb_check_int_endpoints);
 
 /**
  * usb_find_alt_setting() - Given a configuration, find the alternate setting
@@ -95,6 +294,8 @@
 	struct usb_interface_cache *intf_cache = NULL;
 	int i;
 
+	if (!config)
+		return NULL;
 	for (i = 0; i < config->desc.bNumInterfaces; i++) {
 		if (config->intf_cache[i]->altsetting[0].desc.bInterfaceNumber
 				== iface_num) {
@@ -676,14 +877,14 @@
  */
 
 int __usb_get_extra_descriptor(char *buffer, unsigned size,
-			       unsigned char type, void **ptr)
+			       unsigned char type, void **ptr, size_t minsize)
 {
 	struct usb_descriptor_header *header;
 
 	while (size >= sizeof(struct usb_descriptor_header)) {
 		header = (struct usb_descriptor_header *)buffer;
 
-		if (header->bLength < 2) {
+		if (header->bLength < 2 || header->bLength > size) {
 			printk(KERN_ERR
 				"%s: bogus descriptor, type %d length %d\n",
 				usbcore_name,
@@ -692,7 +893,7 @@
 			return -1;
 		}
 
-		if (header->bDescriptorType == type) {
+		if (header->bDescriptorType == type && header->bLength >= minsize) {
 			*ptr = header;
 			return 0;
 		}
--- linux-4.4.0.orig/drivers/usb/core/usb.h
+++ linux-4.4.0/drivers/usb/core/usb.h
@@ -31,6 +31,9 @@
 extern void usb_authorize_interface(struct usb_interface *);
 extern void usb_detect_quirks(struct usb_device *udev);
 extern void usb_detect_interface_quirks(struct usb_device *udev);
+extern bool usb_endpoint_is_blacklisted(struct usb_device *udev,
+		struct usb_host_interface *intf,
+		struct usb_endpoint_descriptor *epd);
 extern int usb_remove_device(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
@@ -45,7 +48,7 @@
 		struct usb_host_config *c)
 {
 	/* SuperSpeed power is in 8 mA units; others are in 2 mA units */
-	unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2);
+	unsigned mul = (udev->speed >= USB_SPEED_SUPER ? 8 : 2);
 
 	return c->desc.bMaxPower * mul;
 }
@@ -84,7 +87,8 @@
 extern int usb_runtime_suspend(struct device *dev);
 extern int usb_runtime_resume(struct device *dev);
 extern int usb_runtime_idle(struct device *dev);
-extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
+extern int usb_enable_usb2_hardware_lpm(struct usb_device *udev);
+extern int usb_disable_usb2_hardware_lpm(struct usb_device *udev);
 
 #else
 
@@ -104,7 +108,12 @@
 	return 0;
 }
 
-static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+static inline int usb_enable_usb2_hardware_lpm(struct usb_device *udev)
+{
+	return 0;
+}
+
+static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev)
 {
 	return 0;
 }
--- linux-4.4.0.orig/drivers/usb/dwc2/core.h
+++ linux-4.4.0/drivers/usb/dwc2/core.h
@@ -44,6 +44,17 @@
 #include <linux/usb/phy.h>
 #include "hw.h"
 
+#ifdef CONFIG_MIPS
+/*
+ * There are some MIPS machines that can run in either big-endian
+ * or little-endian mode and that use the dwc2 register without
+ * a byteswap in both ways.
+ * Unlike other architectures, MIPS apparently does not require a
+ * barrier before the __raw_writel() to synchronize with DMA but does
+ * require the barrier after the __raw_writel() to serialize a set of
+ * writes. This set of operations was added specifically for MIPS and
+ * should only be used there.
+ */
 static inline u32 dwc2_readl(const void __iomem *addr)
 {
 	u32 value = __raw_readl(addr);
@@ -70,6 +81,22 @@
 	pr_info("INFO:: wrote %08x to %p\n", value, addr);
 #endif
 }
+#else
+/* Normal architectures just use readl/write */
+static inline u32 dwc2_readl(const void __iomem *addr)
+{
+	return readl(addr);
+}
+
+static inline void dwc2_writel(u32 value, void __iomem *addr)
+{
+	writel(value, addr);
+
+#ifdef DWC2_LOG_WRITES
+	pr_info("info:: wrote %08x to %p\n", value, addr);
+#endif
+}
+#endif
 
 /* Maximum number of Endpoints/HostChannels */
 #define MAX_EPS_CHANNELS	16
@@ -160,7 +187,7 @@
 	unsigned char           dir_in;
 	unsigned char           index;
 	unsigned char           mc;
-	unsigned char           interval;
+	u16                     interval;
 
 	unsigned int            halted:1;
 	unsigned int            periodic:1;
--- linux-4.4.0.orig/drivers/usb/dwc2/core_intr.c
+++ linux-4.4.0/drivers/usb/dwc2/core_intr.c
@@ -363,10 +363,13 @@
 			if (ret && (ret != -ENOTSUPP))
 				dev_err(hsotg->dev, "exit hibernation failed\n");
 
+			/* Change to L0 state */
+			hsotg->lx_state = DWC2_L0;
 			call_gadget(hsotg, resume);
+		} else {
+			/* Change to L0 state */
+			hsotg->lx_state = DWC2_L0;
 		}
-		/* Change to L0 state */
-		hsotg->lx_state = DWC2_L0;
 	} else {
 		if (hsotg->core_params->hibernation) {
 			dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
--- linux-4.4.0.orig/drivers/usb/dwc2/gadget.c
+++ linux-4.4.0/drivers/usb/dwc2/gadget.c
@@ -871,7 +871,6 @@
 static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
 					   u32 windex)
 {
-	struct dwc2_hsotg_ep *ep;
 	int dir = (windex & USB_DIR_IN) ? 1 : 0;
 	int idx = windex & 0x7F;
 
@@ -881,12 +880,7 @@
 	if (idx > hsotg->num_of_eps)
 		return NULL;
 
-	ep = index_to_ep(hsotg, idx, dir);
-
-	if (idx && ep->dir_in != dir)
-		return NULL;
-
-	return ep;
+	return index_to_ep(hsotg, idx, dir);
 }
 
 /**
@@ -2424,12 +2418,6 @@
 	dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
 	       DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0);
 
-	dwc2_hsotg_enqueue_setup(hsotg);
-
-	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-		dwc2_readl(hsotg->regs + DIEPCTL0),
-		dwc2_readl(hsotg->regs + DOEPCTL0));
-
 	/* clear global NAKs */
 	val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
 	if (!is_usb_reset)
@@ -2440,6 +2428,12 @@
 	mdelay(3);
 
 	hsotg->lx_state = DWC2_L0;
+
+	dwc2_hsotg_enqueue_setup(hsotg);
+
+	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+		dwc2_readl(hsotg->regs + DIEPCTL0),
+		dwc2_readl(hsotg->regs + DOEPCTL0));
 }
 
 static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
@@ -3656,10 +3650,6 @@
 								epnum, 0);
 	}
 
-	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
-	if (ret)
-		return ret;
-
 	dwc2_hsotg_dump(hsotg);
 
 	return 0;
@@ -3672,6 +3662,7 @@
 int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg)
 {
 	usb_del_gadget_udc(&hsotg->gadget);
+	dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep, hsotg->ctrl_req);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/usb/dwc2/hcd.c
+++ linux-4.4.0/drivers/usb/dwc2/hcd.c
@@ -1402,8 +1402,12 @@
 		if (count > 250)
 			dev_err(hsotg->dev,
 				"Connection id status change timed out\n");
-		hsotg->op_state = OTG_STATE_A_HOST;
 
+		spin_lock_irqsave(&hsotg->lock, flags);
+		dwc2_hsotg_disconnect(hsotg);
+		spin_unlock_irqrestore(&hsotg->lock, flags);
+
+		hsotg->op_state = OTG_STATE_A_HOST;
 		/* Initialize the Core for Host mode */
 		dwc2_core_init(hsotg, false, -1);
 		dwc2_enable_global_interrupts(hsotg);
@@ -3160,7 +3164,6 @@
 error2:
 	usb_put_hcd(hcd);
 error1:
-	kfree(hsotg->core_params);
 
 #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
 	kfree(hsotg->last_frame_num_array);
--- linux-4.4.0.orig/drivers/usb/dwc2/hcd_intr.c
+++ linux-4.4.0/drivers/usb/dwc2/hcd_intr.c
@@ -461,7 +461,7 @@
 						      &short_read);
 
 	if (urb->actual_length + xfer_length > urb->length) {
-		dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__);
+		dev_dbg(hsotg->dev, "%s(): trimming xfer length\n", __func__);
 		xfer_length = urb->length - urb->actual_length;
 	}
 
@@ -931,9 +931,8 @@
 	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
 	len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd,
 					  DWC2_HC_XFER_COMPLETE, NULL);
-	if (!len) {
+	if (!len && !qtd->isoc_split_offset) {
 		qtd->complete_split = 0;
-		qtd->isoc_split_offset = 0;
 		return 0;
 	}
 
@@ -1916,6 +1915,18 @@
 		qtd->error_count++;
 		dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb,
 					  qtd, DWC2_HC_XFER_XACT_ERR);
+		/*
+		 * We can get here after a completed transaction
+		 * (urb->actual_length >= urb->length) which was not reported
+		 * as completed. If that is the case, and we do not abort
+		 * the transfer, a transfer of size 0 will be enqueued
+		 * subsequently. If urb->actual_length is not DMA-aligned,
+		 * the buffer will then point to an unaligned address, and
+		 * the resulting behavior is undefined. Bail out in that
+		 * situation.
+		 */
+		if (qtd->urb->actual_length >= qtd->urb->length)
+			qtd->error_count = 3;
 		dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
 		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR);
 	}
--- linux-4.4.0.orig/drivers/usb/dwc2/platform.c
+++ linux-4.4.0/drivers/usb/dwc2/platform.c
@@ -452,10 +452,23 @@
 	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
 		dwc2_lowlevel_hw_disable(hsotg);
 
+#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
+	IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
+	/* Postponed adding a new gadget to the udc class driver list */
+	if (hsotg->gadget_enabled) {
+		retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget);
+		if (retval) {
+			hsotg->gadget.udc = NULL;
+			dwc2_hsotg_remove(hsotg);
+			goto error;
+		}
+	}
+#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
 	return 0;
 
 error:
-	dwc2_lowlevel_hw_disable(hsotg);
+	if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL)
+		dwc2_lowlevel_hw_disable(hsotg);
 	return retval;
 }
 
--- linux-4.4.0.orig/drivers/usb/dwc3/core.c
+++ linux-4.4.0/drivers/usb/dwc3/core.c
@@ -801,6 +801,9 @@
 		/* do nothing */
 		break;
 	}
+
+	/* de-assert DRVVBUS for HOST and OTG mode */
+	dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 }
 
 #define DWC3_ALIGN_MASK		(16 - 1)
@@ -867,7 +870,7 @@
 	dwc->regs_size	= resource_size(res);
 
 	/* default to highest possible threshold */
-	lpm_nyet_threshold = 0xff;
+	lpm_nyet_threshold = 0xf;
 
 	/* default to -3.5dB de-emphasis */
 	tx_de_emphasis = 1;
--- linux-4.4.0.orig/drivers/usb/dwc3/core.h
+++ linux-4.4.0/drivers/usb/dwc3/core.h
@@ -42,9 +42,7 @@
 #define DWC3_XHCI_RESOURCES_NUM	2
 
 #define DWC3_SCRATCHBUF_SIZE	4096	/* each buffer is assumed to be 4KiB */
-#define DWC3_EVENT_SIZE		4	/* bytes */
-#define DWC3_EVENT_MAX_NUM	64	/* 2 events/endpoint */
-#define DWC3_EVENT_BUFFERS_SIZE	(DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
+#define DWC3_EVENT_BUFFERS_SIZE	4096
 #define DWC3_EVENT_TYPE_MASK	0xfe
 
 #define DWC3_EVENT_TYPE_DEV	0
@@ -204,6 +202,8 @@
 #define DWC3_GUSB3PIPECTL_TX_DEEPH(n)	((n) << 1)
 
 /* Global TX Fifo Size Register */
+#define DWC31_GTXFIFOSIZ_TXFRAMNUM	BIT(15)		/* DWC_usb31 only */
+#define DWC31_GTXFIFOSIZ_TXFDEF(n)	((n) & 0x7fff)	/* DWC_usb31 only */
 #define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
 #define DWC3_GTXFIFOSIZ_TXFSTADDR(n)	((n) & 0xffff0000)
 
@@ -853,7 +853,6 @@
 	unsigned		pullups_connected:1;
 	unsigned		resize_fifos:1;
 	unsigned		setup_packet_pending:1;
-	unsigned		start_config_issued:1;
 	unsigned		three_stage_setup:1;
 	unsigned		usb3_lpm_capable:1;
 
--- linux-4.4.0.orig/drivers/usb/dwc3/dwc3-exynos.c
+++ linux-4.4.0/drivers/usb/dwc3/dwc3-exynos.c
@@ -128,12 +128,6 @@
 
 	platform_set_drvdata(pdev, exynos);
 
-	ret = dwc3_exynos_register_phys(exynos);
-	if (ret) {
-		dev_err(dev, "couldn't register PHYs\n");
-		return ret;
-	}
-
 	exynos->dev	= dev;
 
 	exynos->clk = devm_clk_get(dev, "usbdrd30");
@@ -154,7 +148,8 @@
 		exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk");
 		if (IS_ERR(exynos->axius_clk)) {
 			dev_err(dev, "no AXI UpScaler clk specified\n");
-			return -ENODEV;
+			ret = -ENODEV;
+			goto axius_clk_err;
 		}
 		clk_prepare_enable(exynos->axius_clk);
 	} else {
@@ -183,26 +178,36 @@
 		goto err3;
 	}
 
+	ret = dwc3_exynos_register_phys(exynos);
+	if (ret) {
+		dev_err(dev, "couldn't register PHYs\n");
+		goto err4;
+	}
+
 	if (node) {
 		ret = of_platform_populate(node, NULL, NULL, dev);
 		if (ret) {
 			dev_err(dev, "failed to add dwc3 core\n");
-			goto err4;
+			goto err5;
 		}
 	} else {
 		dev_err(dev, "no device node, failed to add dwc3 core\n");
 		ret = -ENODEV;
-		goto err4;
+		goto err5;
 	}
 
 	return 0;
 
+err5:
+	platform_device_unregister(exynos->usb2_phy);
+	platform_device_unregister(exynos->usb3_phy);
 err4:
 	regulator_disable(exynos->vdd10);
 err3:
 	regulator_disable(exynos->vdd33);
 err2:
 	clk_disable_unprepare(exynos->axius_clk);
+axius_clk_err:
 	clk_disable_unprepare(exynos->susp_clk);
 	clk_disable_unprepare(exynos->clk);
 	return ret;
--- linux-4.4.0.orig/drivers/usb/dwc3/dwc3-keystone.c
+++ linux-4.4.0/drivers/usb/dwc3/dwc3-keystone.c
@@ -112,6 +112,10 @@
 	dev->dma_mask = &kdwc3_dma_mask;
 
 	kdwc->clk = devm_clk_get(kdwc->dev, "usb");
+	if (IS_ERR(kdwc->clk)) {
+		dev_err(kdwc->dev, "unable to get usb clock\n");
+		return PTR_ERR(kdwc->clk);
+	}
 
 	error = clk_prepare_enable(kdwc->clk);
 	if (error < 0) {
--- linux-4.4.0.orig/drivers/usb/dwc3/dwc3-omap.c
+++ linux-4.4.0/drivers/usb/dwc3/dwc3-omap.c
@@ -469,8 +469,8 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(dev, "missing IRQ resource\n");
-		return -EINVAL;
+		dev_err(dev, "missing IRQ resource: %d\n", irq);
+		return irq;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
--- linux-4.4.0.orig/drivers/usb/dwc3/dwc3-pci.c
+++ linux-4.4.0/drivers/usb/dwc3/dwc3-pci.c
@@ -36,6 +36,8 @@
 #define PCI_DEVICE_ID_INTEL_SPTH		0xa130
 #define PCI_DEVICE_ID_INTEL_BXT			0x0aaa
 #define PCI_DEVICE_ID_INTEL_APL			0x5aaa
+#define PCI_DEVICE_ID_INTEL_KBP			0xa2b0
+#define PCI_DEVICE_ID_INTEL_GLK			0x31aa
 
 static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
 static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
@@ -165,7 +167,7 @@
 	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
 	if (ret) {
 		dev_err(dev, "couldn't add resources to dwc3 device\n");
-		return ret;
+		goto err;
 	}
 
 	pci_set_drvdata(pci, dwc3);
@@ -214,6 +216,8 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
 	{  }	/* Terminating Entry */
 };
--- linux-4.4.0.orig/drivers/usb/dwc3/dwc3-st.c
+++ linux-4.4.0/drivers/usb/dwc3/dwc3-st.c
@@ -224,7 +224,7 @@
 
 	dwc3_data->syscfg_reg_off = res->start;
 
-	dev_vdbg(&pdev->dev, "glue-logic addr 0x%p, syscfg-reg offset 0x%x\n",
+	dev_vdbg(&pdev->dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n",
 		 dwc3_data->glue_base, dwc3_data->syscfg_reg_off);
 
 	dwc3_data->rstc_pwrdn = devm_reset_control_get(dev, "powerdown");
--- linux-4.4.0.orig/drivers/usb/dwc3/ep0.c
+++ linux-4.4.0/drivers/usb/dwc3/ep0.c
@@ -55,20 +55,13 @@
 	}
 }
 
-static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
-		u32 len, u32 type, bool chain)
+static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
+		dma_addr_t buf_dma, u32 len, u32 type, bool chain)
 {
-	struct dwc3_gadget_ep_cmd_params params;
 	struct dwc3_trb			*trb;
 	struct dwc3_ep			*dep;
 
-	int				ret;
-
 	dep = dwc->eps[epnum];
-	if (dep->flags & DWC3_EP_BUSY) {
-		dwc3_trace(trace_dwc3_ep0, "%s still busy", dep->name);
-		return 0;
-	}
 
 	trb = &dwc->ep0_trb[dep->free_slot];
 
@@ -89,15 +82,25 @@
 		trb->ctrl |= (DWC3_TRB_CTRL_IOC
 				| DWC3_TRB_CTRL_LST);
 
-	if (chain)
+	trace_dwc3_prepare_trb(dep, trb);
+}
+
+static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_ep			*dep;
+	int				ret;
+
+	dep = dwc->eps[epnum];
+	if (dep->flags & DWC3_EP_BUSY) {
+		dwc3_trace(trace_dwc3_ep0, "%s still busy", dep->name);
 		return 0;
+	}
 
 	memset(&params, 0, sizeof(params));
 	params.param0 = upper_32_bits(dwc->ep0_trb_addr);
 	params.param1 = lower_32_bits(dwc->ep0_trb_addr);
 
-	trace_dwc3_prepare_trb(dep, trb);
-
 	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
 			DWC3_DEPCMD_STARTTRANSFER, &params);
 	if (ret < 0) {
@@ -311,8 +314,9 @@
 {
 	int				ret;
 
-	ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
+	dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8,
 			DWC3_TRBCTL_CONTROL_SETUP, false);
+	ret = dwc3_ep0_start_trans(dwc, 0);
 	WARN_ON(ret < 0);
 }
 
@@ -327,6 +331,9 @@
 		epnum |= 1;
 
 	dep = dwc->eps[epnum];
+	if (dep == NULL)
+		return NULL;
+
 	if (dep->flags & DWC3_EP_ENABLED)
 		return dep;
 
@@ -555,7 +562,6 @@
 	int ret;
 	u32 reg;
 
-	dwc->start_config_issued = false;
 	cfg = le16_to_cpu(ctrl->wValue);
 
 	switch (state) {
@@ -737,10 +743,6 @@
 		dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
 		ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
 		break;
-	case USB_REQ_SET_INTERFACE:
-		dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE");
-		dwc->start_config_issued = false;
-		/* Fall through */
 	default:
 		dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
@@ -876,9 +878,9 @@
 
 			dwc->ep0_next_event = DWC3_EP0_COMPLETE;
 
-			ret = dwc3_ep0_start_trans(dwc, epnum,
-					dwc->ctrl_req_addr, 0,
-					DWC3_TRBCTL_CONTROL_DATA, false);
+			dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr,
+					0, DWC3_TRBCTL_CONTROL_DATA, false);
+			ret = dwc3_ep0_start_trans(dwc, epnum);
 			WARN_ON(ret < 0);
 		}
 	}
@@ -960,9 +962,10 @@
 	req->direction = !!dep->number;
 
 	if (req->request.length == 0) {
-		ret = dwc3_ep0_start_trans(dwc, dep->number,
+		dwc3_ep0_prepare_one_trb(dwc, dep->number,
 				dwc->ctrl_req_addr, 0,
 				DWC3_TRBCTL_CONTROL_DATA, false);
+		ret = dwc3_ep0_start_trans(dwc, dep->number);
 	} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
 			&& (dep->number == 0)) {
 		u32	transfer_size = 0;
@@ -980,7 +983,7 @@
 		if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
 			transfer_size = ALIGN(req->request.length - maxpacket,
 					      maxpacket);
-			ret = dwc3_ep0_start_trans(dwc, dep->number,
+			dwc3_ep0_prepare_one_trb(dwc, dep->number,
 						   req->request.dma,
 						   transfer_size,
 						   DWC3_TRBCTL_CONTROL_DATA,
@@ -992,9 +995,10 @@
 
 		dwc->ep0_bounced = true;
 
-		ret = dwc3_ep0_start_trans(dwc, dep->number,
+		dwc3_ep0_prepare_one_trb(dwc, dep->number,
 				dwc->ep0_bounce_addr, transfer_size,
 				DWC3_TRBCTL_CONTROL_DATA, false);
+		ret = dwc3_ep0_start_trans(dwc, dep->number);
 	} else {
 		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
 				dep->number);
@@ -1003,9 +1007,10 @@
 			return;
 		}
 
-		ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
+		dwc3_ep0_prepare_one_trb(dwc, dep->number, req->request.dma,
 				req->request.length, DWC3_TRBCTL_CONTROL_DATA,
 				false);
+		ret = dwc3_ep0_start_trans(dwc, dep->number);
 	}
 
 	WARN_ON(ret < 0);
@@ -1019,8 +1024,9 @@
 	type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
 		: DWC3_TRBCTL_CONTROL_STATUS2;
 
-	return dwc3_ep0_start_trans(dwc, dep->number,
+	dwc3_ep0_prepare_one_trb(dwc, dep->number,
 			dwc->ctrl_req_addr, 0, type, false);
+	return dwc3_ep0_start_trans(dwc, dep->number);
 }
 
 static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
--- linux-4.4.0.orig/drivers/usb/dwc3/gadget.c
+++ linux-4.4.0/drivers/usb/dwc3/gadget.c
@@ -235,6 +235,7 @@
 		int status)
 {
 	struct dwc3			*dwc = dep->dwc;
+	unsigned int			unmap_after_complete = false;
 	int				i;
 
 	if (req->queued) {
@@ -259,11 +260,19 @@
 	if (req->request.status == -EINPROGRESS)
 		req->request.status = status;
 
-	if (dwc->ep0_bounced && dep->number == 0)
+	/*
+	 * NOTICE we don't want to unmap before calling ->complete() if we're
+	 * dealing with a bounced ep0 request. If we unmap it here, we would end
+	 * up overwritting the contents of req->buf and this could confuse the
+	 * gadget driver.
+	 */
+	if (dwc->ep0_bounced && dep->number <= 1) {
 		dwc->ep0_bounced = false;
-	else
-		usb_gadget_unmap_request(&dwc->gadget, &req->request,
-				req->direction);
+		unmap_after_complete = true;
+	} else {
+		usb_gadget_unmap_request(&dwc->gadget,
+				&req->request, req->direction);
+	}
 
 	dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
 			req, dep->name, req->request.actual,
@@ -273,6 +282,10 @@
 	spin_unlock(&dwc->lock);
 	usb_gadget_giveback_request(&dep->endpoint, &req->request);
 	spin_lock(&dwc->lock);
+
+	if (unmap_after_complete)
+		usb_gadget_unmap_request(&dwc->gadget,
+				&req->request, req->direction);
 }
 
 int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
@@ -388,24 +401,66 @@
 	dep->trb_pool_dma = 0;
 }
 
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep);
+
+/**
+ * dwc3_gadget_start_config - Configure EP resources
+ * @dwc: pointer to our controller context structure
+ * @dep: endpoint that is being enabled
+ *
+ * The assignment of transfer resources cannot perfectly follow the
+ * data book due to the fact that the controller driver does not have
+ * all knowledge of the configuration in advance. It is given this
+ * information piecemeal by the composite gadget framework after every
+ * SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook
+ * programming model in this scenario can cause errors. For two
+ * reasons:
+ *
+ * 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION
+ * and SET_INTERFACE (8.1.5). This is incorrect in the scenario of
+ * multiple interfaces.
+ *
+ * 2) The databook does not mention doing more DEPXFERCFG for new
+ * endpoint on alt setting (8.1.6).
+ *
+ * The following simplified method is used instead:
+ *
+ * All hardware endpoints can be assigned a transfer resource and this
+ * setting will stay persistent until either a core reset or
+ * hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and
+ * do DEPXFERCFG for every hardware endpoint as well. We are
+ * guaranteed that there are as many transfer resources as endpoints.
+ *
+ * This function is called for each endpoint when it is being enabled
+ * but is triggered only when called for EP0-out, which always happens
+ * first, and which should only happen in one of the above conditions.
+ */
 static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
 	struct dwc3_gadget_ep_cmd_params params;
 	u32			cmd;
+	int			i;
+	int			ret;
+
+	if (dep->number)
+		return 0;
 
 	memset(&params, 0x00, sizeof(params));
+	cmd = DWC3_DEPCMD_DEPSTARTCFG;
 
-	if (dep->number != 1) {
-		cmd = DWC3_DEPCMD_DEPSTARTCFG;
-		/* XferRscIdx == 0 for ep0 and 2 for the remaining */
-		if (dep->number > 1) {
-			if (dwc->start_config_issued)
-				return 0;
-			dwc->start_config_issued = true;
-			cmd |= DWC3_DEPCMD_PARAM(2);
-		}
+	ret = dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+		struct dwc3_ep *dep = dwc->eps[i];
+
+		if (!dep)
+			continue;
 
-		return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+		ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+		if (ret)
+			return ret;
 	}
 
 	return 0;
@@ -466,8 +521,23 @@
 		params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
 
 	if (desc->bInterval) {
-		params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
-		dep->interval = 1 << (desc->bInterval - 1);
+		u8 bInterval_m1;
+
+		/*
+		 * Valid range for DEPCFG.bInterval_m1 is from 0 to 13, and it
+		 * must be set to 0 when the controller operates in full-speed.
+		 */
+		bInterval_m1 = min_t(u8, desc->bInterval - 1, 13);
+		if (dwc->gadget.speed == USB_SPEED_FULL)
+			bInterval_m1 = 0;
+
+		if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&
+		    dwc->gadget.speed == USB_SPEED_FULL)
+			dep->interval = desc->bInterval;
+		else
+			dep->interval = 1 << (desc->bInterval - 1);
+
+		params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1);
 	}
 
 	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
@@ -519,10 +589,6 @@
 		struct dwc3_trb	*trb_st_hw;
 		struct dwc3_trb	*trb_link;
 
-		ret = dwc3_gadget_set_xfer_resource(dwc, dep);
-		if (ret)
-			return ret;
-
 		dep->endpoint.desc = desc;
 		dep->comp_desc = comp_desc;
 		dep->type = usb_endpoint_type(desc);
@@ -1168,7 +1234,7 @@
 		goto out;
 	}
 
-	if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
+	if (WARN(req->dep != dep, "request %pK belongs to '%s'\n",
 				request, req->dep->name)) {
 		ret = -EINVAL;
 		goto out;
@@ -1213,7 +1279,7 @@
 			dwc3_stop_active_transfer(dwc, dep->number, true);
 			goto out1;
 		}
-		dev_err(dwc->dev, "request %p was not queued to %s\n",
+		dev_err(dwc->dev, "request %pK was not queued to %s\n",
 				request, ep->name);
 		ret = -EINVAL;
 		goto out0;
@@ -1604,8 +1670,6 @@
 	}
 	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
-	dwc->start_config_issued = false;
-
 	/* Start with SuperSpeed Default */
 	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
@@ -1627,6 +1691,7 @@
 
 	/* begin to receive SETUP packets */
 	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc->link_state = DWC3_LINK_STATE_SS_DIS;
 	dwc3_ep0_out_start(dwc);
 
 	dwc3_gadget_enable_irq(dwc);
@@ -1817,7 +1882,7 @@
 		 * would help. Lets hope that if this occurs, someone
 		 * fixes the root cause instead of looking away :)
 		 */
-		dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
+		dev_err(dwc->dev, "%s's TRB (%pK) still owned by HW\n",
 				dep->name, trb);
 	count = trb->size & DWC3_TRB_SIZE_MASK;
 
@@ -1856,14 +1921,6 @@
 			s_pkt = 1;
 	}
 
-	/*
-	 * We assume here we will always receive the entire data block
-	 * which we should receive. Meaning, if we program RX to
-	 * receive 4K but we receive only 2K, we assume that's all we
-	 * should receive and we simply bounce the request back to the
-	 * gadget driver for further processing.
-	 */
-	req->request.actual += req->request.length - count;
 	if (s_pkt)
 		return 1;
 	if ((event->status & DEPEVT_STATUS_LST) &&
@@ -1883,6 +1940,7 @@
 	struct dwc3_trb		*trb;
 	unsigned int		slot;
 	unsigned int		i;
+	int			count = 0;
 	int			ret;
 
 	do {
@@ -1899,6 +1957,8 @@
 				slot++;
 			slot %= DWC3_TRB_NUM;
 			trb = &dep->trb_pool[slot];
+			count += trb->size & DWC3_TRB_SIZE_MASK;
+
 
 			ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
 					event, status);
@@ -1906,6 +1966,14 @@
 				break;
 		} while (++i < req->request.num_mapped_sgs);
 
+		/*
+		 * We assume here we will always receive the entire data block
+		 * which we should receive. Meaning, if we program RX to
+		 * receive 4K but we receive only 2K, we assume that's all we
+		 * should receive and we simply bounce the request back to the
+		 * gadget driver for further processing.
+		 */
+		req->request.actual += req->request.length - count;
 		dwc3_gadget_giveback(dep, req, status);
 
 		if (ret)
@@ -1929,6 +1997,10 @@
 		return 1;
 	}
 
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
+		if ((event->status & DEPEVT_STATUS_IOC) &&
+				(trb->ctrl & DWC3_TRB_CTRL_IOC))
+			return 0;
 	return 1;
 }
 
@@ -2202,7 +2274,6 @@
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
 	dwc3_disconnect_gadget(dwc);
-	dwc->start_config_issued = false;
 
 	dwc->gadget.speed = USB_SPEED_UNKNOWN;
 	dwc->setup_packet_pending = false;
@@ -2253,7 +2324,6 @@
 
 	dwc3_stop_active_transfers(dwc);
 	dwc3_clear_stall_all_ep(dwc);
-	dwc->start_config_issued = false;
 
 	/* Reset device address to zero */
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
@@ -2339,6 +2409,8 @@
 		break;
 	}
 
+	dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket;
+
 	/* Enable USB2 LPM Capability */
 
 	if ((dwc->revision > DWC3_REVISION_194A)
@@ -2804,7 +2876,7 @@
 	kfree(dwc->setup_buf);
 
 err2:
-	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
 			dwc->ep0_trb, dwc->ep0_trb_addr);
 
 err1:
@@ -2828,7 +2900,7 @@
 
 	kfree(dwc->setup_buf);
 
-	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
 			dwc->ep0_trb, dwc->ep0_trb_addr);
 
 	dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
@@ -2837,6 +2909,9 @@
 
 int dwc3_gadget_suspend(struct dwc3 *dwc)
 {
+	if (!dwc->gadget_driver)
+		return 0;
+
 	if (dwc->pullups_connected) {
 		dwc3_gadget_disable_irq(dwc);
 		dwc3_gadget_run_stop(dwc, true, true);
@@ -2855,6 +2930,9 @@
 	struct dwc3_ep		*dep;
 	int			ret;
 
+	if (!dwc->gadget_driver)
+		return 0;
+
 	/* Start with SuperSpeed Default */
 	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
--- linux-4.4.0.orig/drivers/usb/dwc3/gadget.h
+++ linux-4.4.0/drivers/usb/dwc3/gadget.h
@@ -28,23 +28,23 @@
 #define gadget_to_dwc(g)	(container_of(g, struct dwc3, gadget))
 
 /* DEPCFG parameter 1 */
-#define DWC3_DEPCFG_INT_NUM(n)		((n) << 0)
+#define DWC3_DEPCFG_INT_NUM(n)		(((n) & 0x1f) << 0)
 #define DWC3_DEPCFG_XFER_COMPLETE_EN	(1 << 8)
 #define DWC3_DEPCFG_XFER_IN_PROGRESS_EN	(1 << 9)
 #define DWC3_DEPCFG_XFER_NOT_READY_EN	(1 << 10)
 #define DWC3_DEPCFG_FIFO_ERROR_EN	(1 << 11)
 #define DWC3_DEPCFG_STREAM_EVENT_EN	(1 << 13)
-#define DWC3_DEPCFG_BINTERVAL_M1(n)	((n) << 16)
+#define DWC3_DEPCFG_BINTERVAL_M1(n)	(((n) & 0xff) << 16)
 #define DWC3_DEPCFG_STREAM_CAPABLE	(1 << 24)
-#define DWC3_DEPCFG_EP_NUMBER(n)	((n) << 25)
+#define DWC3_DEPCFG_EP_NUMBER(n)	(((n) & 0x1f) << 25)
 #define DWC3_DEPCFG_BULK_BASED		(1 << 30)
 #define DWC3_DEPCFG_FIFO_BASED		(1 << 31)
 
 /* DEPCFG parameter 0 */
-#define DWC3_DEPCFG_EP_TYPE(n)		((n) << 1)
-#define DWC3_DEPCFG_MAX_PACKET_SIZE(n)	((n) << 3)
-#define DWC3_DEPCFG_FIFO_NUMBER(n)	((n) << 17)
-#define DWC3_DEPCFG_BURST_SIZE(n)	((n) << 22)
+#define DWC3_DEPCFG_EP_TYPE(n)		(((n) & 0x3) << 1)
+#define DWC3_DEPCFG_MAX_PACKET_SIZE(n)	(((n) & 0x7ff) << 3)
+#define DWC3_DEPCFG_FIFO_NUMBER(n)	(((n) & 0x1f) << 17)
+#define DWC3_DEPCFG_BURST_SIZE(n)	(((n) & 0xf) << 22)
 #define DWC3_DEPCFG_DATA_SEQ_NUM(n)	((n) << 26)
 /* This applies for core versions earlier than 1.94a */
 #define DWC3_DEPCFG_IGN_SEQ_NUM		(1 << 31)
--- linux-4.4.0.orig/drivers/usb/dwc3/ulpi.c
+++ linux-4.4.0/drivers/usb/dwc3/ulpi.c
@@ -10,6 +10,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
+#include <linux/time64.h>
 #include <linux/ulpi/regs.h>
 
 #include "core.h"
@@ -20,12 +22,22 @@
 		DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
 		DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
 
-static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
+#define DWC3_ULPI_BASE_DELAY	DIV_ROUND_UP(NSEC_PER_SEC, 60000000L)
+
+static int dwc3_ulpi_busyloop(struct dwc3 *dwc, u8 addr, bool read)
 {
-	unsigned count = 1000;
+	unsigned long ns = 5L * DWC3_ULPI_BASE_DELAY;
+	unsigned int count = 1000;
 	u32 reg;
 
+	if (addr >= ULPI_EXT_VENDOR_SPECIFIC)
+		ns += DWC3_ULPI_BASE_DELAY;
+
+	if (read)
+		ns += DWC3_ULPI_BASE_DELAY;
+
 	while (count--) {
+		ndelay(ns);
 		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
 		if (!(reg & DWC3_GUSB2PHYACC_BUSY))
 			return 0;
@@ -44,7 +56,7 @@
 	reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
 
-	ret = dwc3_ulpi_busyloop(dwc);
+	ret = dwc3_ulpi_busyloop(dwc, addr, true);
 	if (ret)
 		return ret;
 
@@ -62,7 +74,7 @@
 	reg |= DWC3_GUSB2PHYACC_WRITE | val;
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
 
-	return dwc3_ulpi_busyloop(dwc);
+	return dwc3_ulpi_busyloop(dwc, addr, false);
 }
 
 static struct ulpi_ops dwc3_ulpi_ops = {
--- linux-4.4.0.orig/drivers/usb/gadget/Kconfig
+++ linux-4.4.0/drivers/usb/gadget/Kconfig
@@ -267,6 +267,7 @@
 	depends on NET
 	select USB_U_ETHER
 	select USB_F_NCM
+	select CRC32
 	help
 	  NCM is an advanced protocol for Ethernet encapsulation, allows
 	  grouping of several ethernet frames into one USB transfer and
@@ -316,6 +317,7 @@
 	depends on NET
 	select USB_U_ETHER
 	select USB_F_EEM
+	select CRC32
 	help
 	  CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
 	  and therefore can be supported by more hardware.  Technically ECM and
--- linux-4.4.0.orig/drivers/usb/gadget/composite.c
+++ linux-4.4.0/drivers/usb/gadget/composite.c
@@ -104,7 +104,6 @@
 			struct usb_function *f,
 			struct usb_ep *_ep)
 {
-	struct usb_composite_dev	*cdev = get_gadget_data(g);
 	struct usb_endpoint_descriptor *chosen_desc = NULL;
 	struct usb_descriptor_header **speed_desc = NULL;
 
@@ -144,11 +143,16 @@
 
 ep_found:
 	/* commit results */
-	_ep->maxpacket = usb_endpoint_maxp(chosen_desc);
+	_ep->maxpacket = usb_endpoint_maxp(chosen_desc) & 0x7ff;
 	_ep->desc = chosen_desc;
 	_ep->comp_desc = NULL;
 	_ep->maxburst = 0;
-	_ep->mult = 0;
+	_ep->mult = 1;
+
+	if (g->speed == USB_SPEED_HIGH && (usb_endpoint_xfer_isoc(_ep->desc) ||
+				usb_endpoint_xfer_int(_ep->desc)))
+		_ep->mult = ((usb_endpoint_maxp(_ep->desc) & 0x1800) >> 11) + 1;
+
 	if (!want_comp_desc)
 		return 0;
 
@@ -165,14 +169,18 @@
 		switch (usb_endpoint_type(_ep->desc)) {
 		case USB_ENDPOINT_XFER_ISOC:
 			/* mult: bits 1:0 of bmAttributes */
-			_ep->mult = comp_desc->bmAttributes & 0x3;
+			_ep->mult = (comp_desc->bmAttributes & 0x3) + 1;
 		case USB_ENDPOINT_XFER_BULK:
 		case USB_ENDPOINT_XFER_INT:
 			_ep->maxburst = comp_desc->bMaxBurst + 1;
 			break;
 		default:
-			if (comp_desc->bMaxBurst != 0)
+			if (comp_desc->bMaxBurst != 0) {
+				struct usb_composite_dev *cdev;
+
+				cdev = get_gadget_data(g);
 				ERROR(cdev, "ep0 bMaxBurst must be 0\n");
+			}
 			_ep->maxburst = 1;
 			break;
 		}
@@ -285,8 +293,11 @@
 
 	spin_lock_irqsave(&cdev->lock, flags);
 
-	if (cdev->deactivations == 0)
+	if (cdev->deactivations == 0) {
+		spin_unlock_irqrestore(&cdev->lock, flags);
 		status = usb_gadget_deactivate(cdev->gadget);
+		spin_lock_irqsave(&cdev->lock, flags);
+	}
 	if (status == 0)
 		cdev->deactivations++;
 
@@ -317,8 +328,11 @@
 		status = -EINVAL;
 	else {
 		cdev->deactivations--;
-		if (cdev->deactivations == 0)
+		if (cdev->deactivations == 0) {
+			spin_unlock_irqrestore(&cdev->lock, flags);
 			status = usb_gadget_activate(cdev->gadget);
+			spin_lock_irqsave(&cdev->lock, flags);
+		}
 	}
 
 	spin_unlock_irqrestore(&cdev->lock, flags);
@@ -736,6 +750,11 @@
 	/* when we return, be sure our power usage is valid */
 	power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
 done:
+	if (power <= USB_SELF_POWER_VBUS_MAX_DRAW)
+		usb_gadget_set_selfpowered(gadget);
+	else
+		usb_gadget_clear_selfpowered(gadget);
+
 	usb_gadget_vbus_draw(gadget, power);
 	if (result >= 0 && cdev->delayed_status)
 		result = USB_GADGET_DELAYED_STATUS;
@@ -1320,7 +1339,7 @@
 	return res;
 }
 
-static void fill_ext_compat(struct usb_configuration *c, u8 *buf)
+static int fill_ext_compat(struct usb_configuration *c, u8 *buf)
 {
 	int i, count;
 
@@ -1347,10 +1366,12 @@
 				buf += 23;
 			}
 			count += 24;
-			if (count >= 4096)
-				return;
+			if (count + 24 >= USB_COMP_EP0_OS_DESC_BUFSIZ)
+				return count;
 		}
 	}
+
+	return count;
 }
 
 static int count_ext_prop(struct usb_configuration *c, int interface)
@@ -1395,25 +1416,20 @@
 	struct usb_os_desc *d;
 	struct usb_os_desc_ext_prop *ext_prop;
 	int j, count, n, ret;
-	u8 *start = buf;
 
 	f = c->interface[interface];
+	count = 10; /* header length */
 	for (j = 0; j < f->os_desc_n; ++j) {
 		if (interface != f->os_desc_table[j].if_id)
 			continue;
 		d = f->os_desc_table[j].os_desc;
 		if (d)
 			list_for_each_entry(ext_prop, &d->ext_prop, entry) {
-				/* 4kB minus header length */
-				n = buf - start;
-				if (n >= 4086)
-					return 0;
-
-				count = ext_prop->data_len +
+				n = ext_prop->data_len +
 					ext_prop->name_len + 14;
-				if (count > 4086 - n)
-					return -EINVAL;
-				usb_ext_prop_put_size(buf, count);
+				if (count + n >= USB_COMP_EP0_OS_DESC_BUFSIZ)
+					return count;
+				usb_ext_prop_put_size(buf, n);
 				usb_ext_prop_put_type(buf, ext_prop->type);
 				ret = usb_ext_prop_put_name(buf, ext_prop->name,
 							    ext_prop->name_len);
@@ -1439,11 +1455,12 @@
 				default:
 					return -EINVAL;
 				}
-				buf += count;
+				buf += n;
+				count += n;
 			}
 	}
 
-	return 0;
+	return count;
 }
 
 /*
@@ -1467,6 +1484,18 @@
 	struct usb_function		*f = NULL;
 	u8				endp;
 
+	if (w_length > USB_COMP_EP0_BUFSIZ) {
+		if (ctrl->bRequestType & USB_DIR_IN) {
+			/* Cast away the const, we are going to overwrite on purpose. */
+			__le16 *temp = (__le16 *)&ctrl->wLength;
+
+			*temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ);
+			w_length = USB_COMP_EP0_BUFSIZ;
+		} else {
+			goto done;
+		}
+	}
+
 	/* partial re-init of the response message; the function or the
 	 * gadget might need to intercept e.g. a control-OUT completion
 	 * when we delegate to it.
@@ -1596,9 +1625,7 @@
 		value = min(w_length, (u16) 1);
 		break;
 
-	/* function drivers must handle get/set altsetting; if there's
-	 * no get() method, we know only altsetting zero works.
-	 */
+	/* function drivers must handle get/set altsetting */
 	case USB_REQ_SET_INTERFACE:
 		if (ctrl->bRequestType != USB_RECIP_INTERFACE)
 			goto unknown;
@@ -1607,8 +1634,16 @@
 		f = cdev->config->interface[intf];
 		if (!f)
 			break;
-		if (w_value && !f->set_alt)
+
+		/*
+		 * If there's no get_alt() method, we know only altsetting zero
+		 * works. There is no need to check if set_alt() is not NULL
+		 * as we check this in usb_add_function().
+		 */
+		if (w_value && !f->get_alt)
 			break;
+
+		spin_lock(&cdev->lock);
 		value = f->set_alt(f, w_index, w_value);
 		if (value == USB_GADGET_DELAYED_STATUS) {
 			DBG(cdev,
@@ -1618,6 +1653,7 @@
 			DBG(cdev, "delayed_status count %d\n",
 					cdev->delayed_status);
 		}
+		spin_unlock(&cdev->lock);
 		break;
 	case USB_REQ_GET_INTERFACE:
 		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
@@ -1708,6 +1744,7 @@
 			req->complete = composite_setup_complete;
 			buf = req->buf;
 			os_desc_cfg = cdev->os_desc_config;
+			w_length = min_t(u16, w_length, USB_COMP_EP0_OS_DESC_BUFSIZ);
 			memset(buf, 0, w_length);
 			buf[5] = 0x01;
 			switch (ctrl->bRequestType & USB_RECIP_MASK) {
@@ -1731,14 +1768,17 @@
 					count += 16; /* header */
 					put_unaligned_le32(count, buf);
 					buf += 16;
-					fill_ext_compat(os_desc_cfg, buf);
-					value = w_length;
+					value = fill_ext_compat(os_desc_cfg, buf);
+					value = min_t(u16, w_length, value);
 				}
 				break;
 			case USB_RECIP_INTERFACE:
 				if (w_index != 0x5 || (w_value >> 8))
 					break;
 				interface = w_value & 0xFF;
+				if (interface >= MAX_CONFIG_INTERFACES ||
+				    !os_desc_cfg->interface[interface])
+					break;
 				buf[6] = w_index;
 				if (w_length == 0x0A) {
 					count = count_ext_prop(os_desc_cfg,
@@ -1761,8 +1801,7 @@
 							      interface, buf);
 					if (value < 0)
 						return value;
-
-					value = w_length;
+					value = min_t(u16, w_length, value);
 				}
 				break;
 			}
@@ -1806,6 +1845,8 @@
 			break;
 
 		case USB_RECIP_ENDPOINT:
+			if (!cdev->config)
+				break;
 			endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
 			list_for_each_entry(f, &cdev->config->functions, list) {
 				if (test_bit(endp, f->endpoints))
@@ -1874,6 +1915,7 @@
 	 * disconnect callbacks?
 	 */
 	spin_lock_irqsave(&cdev->lock, flags);
+	cdev->suspended = 0;
 	if (cdev->config)
 		reset_config(cdev);
 	if (cdev->driver->disconnect)
@@ -1896,6 +1938,8 @@
 static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
 {
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	struct usb_gadget_strings	*gstr = cdev->driver->strings[0];
+	struct usb_string		*dev_str = gstr->strings;
 
 	/* composite_disconnect() must already have been called
 	 * by the underlying peripheral controller driver!
@@ -1915,6 +1959,9 @@
 
 	composite_dev_cleanup(cdev);
 
+	if (dev_str[USB_GADGET_MANUFACTURER_IDX].s == cdev->def_manufacturer)
+		dev_str[USB_GADGET_MANUFACTURER_IDX].s = "";
+
 	kfree(cdev->def_manufacturer);
 	kfree(cdev);
 	set_gadget_data(gadget, NULL);
@@ -1974,7 +2021,7 @@
 	if (!cdev->req)
 		return -ENOMEM;
 
-	cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
+	cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
 	if (!cdev->req->buf)
 		goto fail;
 
@@ -2021,8 +2068,8 @@
 		goto end;
 	}
 
-	/* OS feature descriptor length <= 4kB */
-	cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL);
+	cdev->os_desc_req->buf = kmalloc(USB_COMP_EP0_OS_DESC_BUFSIZ,
+					 GFP_KERNEL);
 	if (!cdev->os_desc_req->buf) {
 		ret = PTR_ERR(cdev->os_desc_req->buf);
 		kfree(cdev->os_desc_req);
@@ -2047,14 +2094,18 @@
 			usb_ep_dequeue(cdev->gadget->ep0, cdev->os_desc_req);
 
 		kfree(cdev->os_desc_req->buf);
+		cdev->os_desc_req->buf = NULL;
 		usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req);
+		cdev->os_desc_req = NULL;
 	}
 	if (cdev->req) {
 		if (cdev->setup_pending)
 			usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
 
 		kfree(cdev->req->buf);
+		cdev->req->buf = NULL;
 		usb_ep_free_request(cdev->gadget->ep0, cdev->req);
+		cdev->req = NULL;
 	}
 	cdev->next_string_id = 0;
 	device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
@@ -2131,6 +2182,7 @@
 
 	cdev->suspended = 1;
 
+	usb_gadget_set_selfpowered(gadget);
 	usb_gadget_vbus_draw(gadget, 2);
 }
 
@@ -2154,6 +2206,9 @@
 
 		maxpower = cdev->config->MaxPower;
 
+		if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW)
+			usb_gadget_clear_selfpowered(gadget);
+
 		usb_gadget_vbus_draw(gadget, maxpower ?
 			maxpower : CONFIG_USB_GADGET_VBUS_DRAW);
 	}
--- linux-4.4.0.orig/drivers/usb/gadget/configfs.c
+++ linux-4.4.0/drivers/usb/gadget/configfs.c
@@ -62,6 +62,8 @@
 	bool use_os_desc;
 	char b_vendor_code;
 	char qw_sign[OS_STRING_QW_SIGN_LEN];
+	spinlock_t spinlock;
+	bool unbind;
 };
 
 static inline struct gadget_info *to_gadget_info(struct config_item *item)
@@ -233,7 +235,16 @@
 
 static ssize_t gadget_dev_desc_UDC_show(struct config_item *item, char *page)
 {
-	return sprintf(page, "%s\n", to_gadget_info(item)->udc_name ?: "");
+	struct gadget_info *gi = to_gadget_info(item);
+	char *udc_name;
+	int ret;
+
+	mutex_lock(&gi->lock);
+	udc_name = gi->udc_name;
+	ret = sprintf(page, "%s\n", udc_name ?: "");
+	mutex_unlock(&gi->lock);
+
+	return ret;
 }
 
 static int unregister_gadget(struct gadget_info *gi)
@@ -258,6 +269,9 @@
 	char *name;
 	int ret;
 
+	if (strlen(page) < len)
+		return -EOVERFLOW;
+
 	name = kstrdup(page, GFP_KERNEL);
 	if (!name)
 		return -ENOMEM;
@@ -270,6 +284,7 @@
 		ret = unregister_gadget(gi);
 		if (ret)
 			goto err;
+		kfree(name);
 	} else {
 		if (gi->udc_name) {
 			ret = -EBUSY;
@@ -1215,9 +1230,9 @@
 
 		cfg = container_of(c, struct config_usb_cfg, c);
 
-		list_for_each_entry_safe(f, tmp, &c->functions, list) {
+		list_for_each_entry_safe_reverse(f, tmp, &c->functions, list) {
 
-			list_move_tail(&f->list, &cfg->func_list);
+			list_move(&f->list, &cfg->func_list);
 			if (f->unbind) {
 				dev_err(&gi->cdev.gadget->dev, "unbind function"
 						" '%s'/%p\n", f->name, f);
@@ -1245,6 +1260,7 @@
 	int				ret;
 
 	/* the gi->lock is hold by the caller */
+	gi->unbind = 0;
 	cdev->gadget = gadget;
 	set_gadget_data(gadget, cdev);
 	ret = composite_dev_prepare(composite, cdev);
@@ -1377,33 +1393,130 @@
 {
 	struct usb_composite_dev	*cdev;
 	struct gadget_info		*gi;
+	unsigned long flags;
 
 	/* the gi->lock is hold by the caller */
 
 	cdev = get_gadget_data(gadget);
 	gi = container_of(cdev, struct gadget_info, cdev);
+	spin_lock_irqsave(&gi->spinlock, flags);
+	gi->unbind = 1;
+	spin_unlock_irqrestore(&gi->spinlock, flags);
 
 	kfree(otg_desc[0]);
 	otg_desc[0] = NULL;
 	purge_configs_funcs(gi);
 	composite_dev_cleanup(cdev);
 	usb_ep_autoconfig_reset(cdev->gadget);
+	spin_lock_irqsave(&gi->spinlock, flags);
 	cdev->gadget = NULL;
 	set_gadget_data(gadget, NULL);
+	spin_unlock_irqrestore(&gi->spinlock, flags);
+}
+
+static int configfs_composite_setup(struct usb_gadget *gadget,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_composite_dev *cdev;
+	struct gadget_info *gi;
+	unsigned long flags;
+	int ret;
+
+	cdev = get_gadget_data(gadget);
+	if (!cdev)
+		return 0;
+
+	gi = container_of(cdev, struct gadget_info, cdev);
+	spin_lock_irqsave(&gi->spinlock, flags);
+	cdev = get_gadget_data(gadget);
+	if (!cdev || gi->unbind) {
+		spin_unlock_irqrestore(&gi->spinlock, flags);
+		return 0;
+	}
+
+	ret = composite_setup(gadget, ctrl);
+	spin_unlock_irqrestore(&gi->spinlock, flags);
+	return ret;
+}
+
+static void configfs_composite_disconnect(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev *cdev;
+	struct gadget_info *gi;
+	unsigned long flags;
+
+	cdev = get_gadget_data(gadget);
+	if (!cdev)
+		return;
+
+	gi = container_of(cdev, struct gadget_info, cdev);
+	spin_lock_irqsave(&gi->spinlock, flags);
+	cdev = get_gadget_data(gadget);
+	if (!cdev || gi->unbind) {
+		spin_unlock_irqrestore(&gi->spinlock, flags);
+		return;
+	}
+
+	composite_disconnect(gadget);
+	spin_unlock_irqrestore(&gi->spinlock, flags);
+}
+
+static void configfs_composite_suspend(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev *cdev;
+	struct gadget_info *gi;
+	unsigned long flags;
+
+	cdev = get_gadget_data(gadget);
+	if (!cdev)
+		return;
+
+	gi = container_of(cdev, struct gadget_info, cdev);
+	spin_lock_irqsave(&gi->spinlock, flags);
+	cdev = get_gadget_data(gadget);
+	if (!cdev || gi->unbind) {
+		spin_unlock_irqrestore(&gi->spinlock, flags);
+		return;
+	}
+
+	composite_suspend(gadget);
+	spin_unlock_irqrestore(&gi->spinlock, flags);
+}
+
+static void configfs_composite_resume(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev *cdev;
+	struct gadget_info *gi;
+	unsigned long flags;
+
+	cdev = get_gadget_data(gadget);
+	if (!cdev)
+		return;
+
+	gi = container_of(cdev, struct gadget_info, cdev);
+	spin_lock_irqsave(&gi->spinlock, flags);
+	cdev = get_gadget_data(gadget);
+	if (!cdev || gi->unbind) {
+		spin_unlock_irqrestore(&gi->spinlock, flags);
+		return;
+	}
+
+	composite_resume(gadget);
+	spin_unlock_irqrestore(&gi->spinlock, flags);
 }
 
 static const struct usb_gadget_driver configfs_driver_template = {
 	.bind           = configfs_composite_bind,
 	.unbind         = configfs_composite_unbind,
 
-	.setup          = composite_setup,
-	.reset          = composite_disconnect,
-	.disconnect     = composite_disconnect,
+	.setup          = configfs_composite_setup,
+	.reset          = configfs_composite_disconnect,
+	.disconnect     = configfs_composite_disconnect,
 
-	.suspend	= composite_suspend,
-	.resume		= composite_resume,
+	.suspend	= configfs_composite_suspend,
+	.resume		= configfs_composite_resume,
 
-	.max_speed	= USB_SPEED_SUPER,
+	.max_speed	= USB_SPEED_SUPER_PLUS,
 	.driver = {
 		.owner          = THIS_MODULE,
 		.name		= "configfs-gadget",
@@ -1439,8 +1552,9 @@
 	gi->composite.unbind = configfs_do_nothing;
 	gi->composite.suspend = NULL;
 	gi->composite.resume = NULL;
-	gi->composite.max_speed = USB_SPEED_SUPER;
+	gi->composite.max_speed = USB_SPEED_SUPER_PLUS;
 
+	spin_lock_init(&gi->spinlock);
 	mutex_init(&gi->lock);
 	INIT_LIST_HEAD(&gi->string_list);
 	INIT_LIST_HEAD(&gi->available_func);
@@ -1495,7 +1609,9 @@
 {
 	struct gadget_info *gi = to_gadget_info(item);
 
+	mutex_lock(&gi->lock);
 	unregister_gadget(gi);
+	mutex_unlock(&gi->lock);
 }
 EXPORT_SYMBOL_GPL(unregister_gadget_item);
 
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_acm.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_acm.c
@@ -535,13 +535,15 @@
 {
 	struct usb_composite_dev *cdev = acm->port.func.config->cdev;
 	int			status;
+	__le16			serial_state;
 
 	spin_lock(&acm->lock);
 	if (acm->notify_req) {
 		dev_dbg(&cdev->gadget->dev, "acm ttyGS%d serial state %04x\n",
 			acm->port_num, acm->serial_state);
+		serial_state = cpu_to_le16(acm->serial_state);
 		status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
-				0, &acm->serial_state, sizeof(acm->serial_state));
+				0, &serial_state, sizeof(acm->serial_state));
 	} else {
 		acm->pending = true;
 		status = 0;
@@ -777,10 +779,10 @@
 	return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
 }
 
-CONFIGFS_ATTR_RO(f_acm_port_, num);
+CONFIGFS_ATTR_RO(f_acm_, port_num);
 
 static struct configfs_attribute *acm_attrs[] = {
-	&f_acm_port_attr_num,
+	&f_acm_attr_port_num,
 	NULL,
 };
 
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_ecm.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_ecm.c
@@ -56,6 +56,7 @@
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	u8				notify_state;
+	atomic_t			notify_count;
 	bool				is_open;
 
 	/* FIXME is_open needs some irq-ish locking
@@ -384,7 +385,7 @@
 	int				status;
 
 	/* notification already in flight? */
-	if (!req)
+	if (atomic_read(&ecm->notify_count))
 		return;
 
 	event = req->buf;
@@ -424,10 +425,10 @@
 	event->bmRequestType = 0xA1;
 	event->wIndex = cpu_to_le16(ecm->ctrl_id);
 
-	ecm->notify_req = NULL;
+	atomic_inc(&ecm->notify_count);
 	status = usb_ep_queue(ecm->notify, req, GFP_ATOMIC);
 	if (status < 0) {
-		ecm->notify_req = req;
+		atomic_dec(&ecm->notify_count);
 		DBG(cdev, "notify --> %d\n", status);
 	}
 }
@@ -452,17 +453,19 @@
 	switch (req->status) {
 	case 0:
 		/* no fault */
+		atomic_dec(&ecm->notify_count);
 		break;
 	case -ECONNRESET:
 	case -ESHUTDOWN:
+		atomic_set(&ecm->notify_count, 0);
 		ecm->notify_state = ECM_NOTIFY_NONE;
 		break;
 	default:
 		DBG(cdev, "event %02x --> %d\n",
 			event->bNotificationType, req->status);
+		atomic_dec(&ecm->notify_count);
 		break;
 	}
-	ecm->notify_req = req;
 	ecm_do_notify(ecm);
 }
 
@@ -625,8 +628,12 @@
 
 	DBG(cdev, "ecm deactivated\n");
 
-	if (ecm->port.in_ep->enabled)
+	if (ecm->port.in_ep->enabled) {
 		gether_disconnect(&ecm->port);
+	} else {
+		ecm->port.in_ep->desc = NULL;
+		ecm->port.out_ep->desc = NULL;
+	}
 
 	usb_ep_disable(ecm->notify);
 	ecm->notify->desc = NULL;
@@ -905,6 +912,11 @@
 
 	usb_free_all_descriptors(f);
 
+	if (atomic_read(&ecm->notify_count)) {
+		usb_ep_dequeue(ecm->notify, ecm->notify_req);
+		atomic_set(&ecm->notify_count, 0);
+	}
+
 	kfree(ecm->notify_req->buf);
 	usb_ep_free_request(ecm->notify, ecm->notify_req);
 }
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_fs.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_fs.c
@@ -646,24 +646,27 @@
 						   work);
 	int ret = io_data->req->status ? io_data->req->status :
 					 io_data->req->actual;
+	bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
 
 	if (io_data->read && ret > 0) {
+		mm_segment_t oldfs = get_fs();
+
+		set_fs(USER_DS);
 		use_mm(io_data->mm);
 		ret = copy_to_iter(io_data->buf, ret, &io_data->data);
-		if (iov_iter_count(&io_data->data))
+		if (ret != io_data->req->actual && iov_iter_count(&io_data->data))
 			ret = -EFAULT;
 		unuse_mm(io_data->mm);
+		set_fs(oldfs);
 	}
 
 	io_data->kiocb->ki_complete(io_data->kiocb, ret, ret);
 
-	if (io_data->ffs->ffs_eventfd &&
-	    !(io_data->kiocb->ki_flags & IOCB_EVENTFD))
+	if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
 		eventfd_signal(io_data->ffs->ffs_eventfd, 1);
 
 	usb_ep_free_request(io_data->ep, io_data->req);
 
-	io_data->kiocb->private = NULL;
 	if (io_data->read)
 		kfree(io_data->to_free);
 	kfree(io_data->buf);
@@ -792,7 +795,7 @@
 		}
 
 		if (io_data->aio) {
-			req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
+			req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
 			if (unlikely(!req))
 				goto error_lock;
 
@@ -809,6 +812,7 @@
 
 			ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
 			if (unlikely(ret)) {
+				io_data->req = NULL;
 				usb_ep_free_request(ep->ep, req);
 				goto error_lock;
 			}
@@ -885,18 +889,19 @@
 {
 	struct ffs_io_data *io_data = kiocb->private;
 	struct ffs_epfile *epfile = kiocb->ki_filp->private_data;
+	unsigned long flags;
 	int value;
 
 	ENTER();
 
-	spin_lock_irq(&epfile->ffs->eps_lock);
+	spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
 
 	if (likely(io_data && io_data->ep && io_data->req))
 		value = usb_ep_dequeue(io_data->ep, io_data->req);
 	else
 		value = -EINVAL;
 
-	spin_unlock_irq(&epfile->ffs->eps_lock);
+	spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
 
 	return value;
 }
@@ -909,11 +914,12 @@
 	ENTER();
 
 	if (!is_sync_kiocb(kiocb)) {
-		p = kmalloc(sizeof(io_data), GFP_KERNEL);
+		p = kzalloc(sizeof(io_data), GFP_KERNEL);
 		if (unlikely(!p))
 			return -ENOMEM;
 		p->aio = true;
 	} else {
+		memset(p, 0, sizeof(*p));
 		p->aio = false;
 	}
 
@@ -945,11 +951,12 @@
 	ENTER();
 
 	if (!is_sync_kiocb(kiocb)) {
-		p = kmalloc(sizeof(io_data), GFP_KERNEL);
+		p = kzalloc(sizeof(io_data), GFP_KERNEL);
 		if (unlikely(!p))
 			return -ENOMEM;
 		p->aio = true;
 	} else {
+		memset(p, 0, sizeof(*p));
 		p->aio = false;
 	}
 
@@ -1027,7 +1034,7 @@
 		case FUNCTIONFS_ENDPOINT_DESC:
 		{
 			int desc_idx;
-			struct usb_endpoint_descriptor *desc;
+			struct usb_endpoint_descriptor desc1, *desc;
 
 			switch (epfile->ffs->gadget->speed) {
 			case USB_SPEED_SUPER:
@@ -1039,10 +1046,12 @@
 			default:
 				desc_idx = 0;
 			}
+
 			desc = epfile->ep->descs[desc_idx];
+			memcpy(&desc1, desc, desc->bLength);
 
 			spin_unlock_irq(&epfile->ffs->eps_lock);
-			ret = copy_to_user((void *)value, desc, sizeof(*desc));
+			ret = copy_to_user((void *)value, &desc1, desc1.bLength);
 			if (ret)
 				ret = -EFAULT;
 			return ret;
@@ -1334,7 +1343,6 @@
 	if (sb->s_fs_info) {
 		ffs_release_dev(sb->s_fs_info);
 		ffs_data_closed(sb->s_fs_info);
-		ffs_data_put(sb->s_fs_info);
 	}
 }
 
@@ -1468,11 +1476,15 @@
 
 	BUG_ON(ffs->gadget);
 
-	if (ffs->epfiles)
+	if (ffs->epfiles) {
 		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+		ffs->epfiles = NULL;
+	}
 
-	if (ffs->ffs_eventfd)
+	if (ffs->ffs_eventfd) {
 		eventfd_ctx_put(ffs->ffs_eventfd);
+		ffs->ffs_eventfd = NULL;
+	}
 
 	kfree(ffs->raw_descs_data);
 	kfree(ffs->raw_strings);
@@ -1485,7 +1497,6 @@
 
 	ffs_data_clear(ffs);
 
-	ffs->epfiles = NULL;
 	ffs->raw_descs_data = NULL;
 	ffs->raw_descs = NULL;
 	ffs->raw_strings = NULL;
@@ -1505,6 +1516,10 @@
 	ffs->state = FFS_READ_DESCRIPTORS;
 	ffs->setup_state = FFS_NO_SETUP;
 	ffs->flags = 0;
+
+	ffs->ms_os_descs_ext_prop_count = 0;
+	ffs->ms_os_descs_ext_prop_name_len = 0;
+	ffs->ms_os_descs_ext_prop_data_len = 0;
 }
 
 
@@ -1644,11 +1659,14 @@
 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
 	do {
 		struct usb_endpoint_descriptor *ds;
+		struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
+		int needs_comp_desc = false;
 		int desc_idx;
 
-		if (ffs->gadget->speed == USB_SPEED_SUPER)
+		if (ffs->gadget->speed == USB_SPEED_SUPER) {
 			desc_idx = 2;
-		else if (ffs->gadget->speed == USB_SPEED_HIGH)
+			needs_comp_desc = true;
+		} else if (ffs->gadget->speed == USB_SPEED_HIGH)
 			desc_idx = 1;
 		else
 			desc_idx = 0;
@@ -1665,6 +1683,14 @@
 
 		ep->ep->driver_data = ep;
 		ep->ep->desc = ds;
+
+		if (needs_comp_desc) {
+			comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds +
+					USB_DT_ENDPOINT_SIZE);
+			ep->ep->maxburst = comp_desc->bMaxBurst + 1;
+			ep->ep->comp_desc = comp_desc;
+		}
+
 		ret = usb_ep_enable(ep->ep);
 		if (likely(!ret)) {
 			epfile->ep = ep;
@@ -2080,6 +2106,8 @@
 		if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
 			return -EINVAL;
 		length = le32_to_cpu(d->dwSize);
+		if (len < length)
+			return -EINVAL;
 		type = le32_to_cpu(d->dwPropertyDataType);
 		if (type < USB_EXT_PROP_UNICODE ||
 		    type > USB_EXT_PROP_UNICODE_MULTI) {
@@ -2088,6 +2116,11 @@
 			return -EINVAL;
 		}
 		pnl = le16_to_cpu(d->wPropertyNameLength);
+		if (length < 14 + pnl) {
+			pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n",
+				  length, pnl, type);
+			return -EINVAL;
+		}
 		pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl));
 		if (length != 14 + pnl + pdl) {
 			pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
@@ -2172,6 +2205,9 @@
 		}
 	}
 	if (flags & (1 << i)) {
+		if (len < 4) {
+			goto error;
+		}
 		os_descs_count = get_unaligned_le32(data);
 		data += 4;
 		len -= 4;
@@ -2244,7 +2280,8 @@
 
 	ENTER();
 
-	if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
+	if (unlikely(len < 16 ||
+		     get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
 		     get_unaligned_le32(data + 4) != len))
 		goto error;
 	str_count  = get_unaligned_le32(data + 8);
@@ -2735,12 +2772,11 @@
 	struct ffs_data *ffs = func->ffs;
 
 	const int full = !!func->ffs->fs_descs_count;
-	const int high = gadget_is_dualspeed(func->gadget) &&
-		func->ffs->hs_descs_count;
-	const int super = gadget_is_superspeed(func->gadget) &&
-		func->ffs->ss_descs_count;
+	const int high = !!func->ffs->hs_descs_count;
+	const int super = !!func->ffs->ss_descs_count;
 
 	int fs_len, hs_len, ss_len, ret, i;
+	struct ffs_ep *eps_ptr;
 
 	/* Make it a single chunk, less management later on */
 	vla_group(d);
@@ -2789,12 +2825,9 @@
 	       ffs->raw_descs_length);
 
 	memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
-	for (ret = ffs->eps_count; ret; --ret) {
-		struct ffs_ep *ptr;
-
-		ptr = vla_ptr(vlabuf, d, eps);
-		ptr[ret].num = -1;
-	}
+	eps_ptr = vla_ptr(vlabuf, d, eps);
+	for (i = 0; i < ffs->eps_count; i++)
+		eps_ptr[i].num = -1;
 
 	/* Save pointers
 	 * d_eps == vlabuf, func->eps used to kfree vlabuf later
@@ -3017,7 +3050,7 @@
 	__ffs_event_add(ffs, FUNCTIONFS_SETUP);
 	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
 
-	return 0;
+	return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
 }
 
 static void ffs_func_suspend(struct usb_function *f)
@@ -3444,6 +3477,7 @@
 {
 	struct ffs_dev *ffs_obj;
 	struct f_fs_opts *opts;
+	struct config_item *ci;
 
 	ENTER();
 	ffs_dev_lock();
@@ -3467,8 +3501,12 @@
 	    || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount))
 		goto done;
 
-	unregister_gadget_item(ffs_obj->opts->
-			       func_inst.group.cg_item.ci_parent->ci_parent);
+	ci = opts->func_inst.group.cg_item.ci_parent->ci_parent;
+	ffs_dev_unlock();
+
+	if (test_bit(FFS_FL_BOUND, &ffs->flags))
+		unregister_gadget_item(ci);
+	return;
 done:
 	ffs_dev_unlock();
 }
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_hid.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_hid.c
@@ -223,6 +223,13 @@
 	/* pick the first one */
 	list = list_first_entry(&hidg->completed_out_req,
 				struct f_hidg_req_list, list);
+
+	/*
+	 * Remove this from list to protect it from beign free()
+	 * while host disables our function
+	 */
+	list_del(&list->list);
+
 	req = list->req;
 	count = min_t(unsigned int, count, req->actual - list->pos);
 	spin_unlock_irqrestore(&hidg->spinlock, flags);
@@ -238,15 +245,20 @@
 	 * call, taking into account its current read position.
 	 */
 	if (list->pos == req->actual) {
-		spin_lock_irqsave(&hidg->spinlock, flags);
-		list_del(&list->list);
 		kfree(list);
-		spin_unlock_irqrestore(&hidg->spinlock, flags);
 
 		req->length = hidg->report_length;
 		ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL);
-		if (ret < 0)
+		if (ret < 0) {
+			free_ep_req(hidg->out_ep, req);
 			return ret;
+		}
+	} else {
+		spin_lock_irqsave(&hidg->spinlock, flags);
+		list_add(&list->list, &hidg->completed_out_req);
+		spin_unlock_irqrestore(&hidg->spinlock, flags);
+
+		wake_up(&hidg->read_queue);
 	}
 
 	return count;
@@ -490,14 +502,18 @@
 {
 	struct f_hidg *hidg = func_to_hidg(f);
 	struct f_hidg_req_list *list, *next;
+	unsigned long flags;
 
 	usb_ep_disable(hidg->in_ep);
 	usb_ep_disable(hidg->out_ep);
 
+	spin_lock_irqsave(&hidg->spinlock, flags);
 	list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
+		free_ep_req(hidg->out_ep, list->req);
 		list_del(&list->list);
 		kfree(list);
 	}
+	spin_unlock_irqrestore(&hidg->spinlock, flags);
 }
 
 static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
@@ -539,7 +555,7 @@
 		}
 		status = usb_ep_enable(hidg->out_ep);
 		if (status < 0) {
-			ERROR(cdev, "Enable IN endpoint FAILED!\n");
+			ERROR(cdev, "Enable OUT endpoint FAILED!\n");
 			goto fail;
 		}
 		hidg->out_ep->driver_data = hidg;
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_mass_storage.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_mass_storage.c
@@ -220,6 +220,8 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/composite.h>
 
+#include <linux/nospec.h>
+
 #include "configfs.h"
 
 
@@ -306,8 +308,6 @@
 	struct completion	thread_notifier;
 	struct task_struct	*thread_task;
 
-	/* Callback functions. */
-	const struct fsg_operations	*ops;
 	/* Gadget's private data. */
 	void			*private_data;
 
@@ -399,7 +399,11 @@
 /* Caller must hold fsg->lock */
 static void wakeup_thread(struct fsg_common *common)
 {
-	smp_wmb();	/* ensure the write of bh->state is complete */
+	/*
+	 * Ensure the reading of thread_wakeup_needed
+	 * and the writing of bh->state are completed
+	 */
+	smp_mb();
 	/* Tell the main thread that something has happened */
 	common->thread_wakeup_needed = 1;
 	if (common->thread_task)
@@ -630,7 +634,12 @@
 	}
 	__set_current_state(TASK_RUNNING);
 	common->thread_wakeup_needed = 0;
-	smp_rmb();	/* ensure the latest bh->state is visible */
+
+	/*
+	 * Ensure the writing of thread_wakeup_needed
+	 * and the reading of bh->state are completed
+	 */
+	smp_mb();
 	return rc;
 }
 
@@ -2495,6 +2504,7 @@
 static int fsg_main_thread(void *common_)
 {
 	struct fsg_common	*common = common_;
+	int			i;
 
 	/*
 	 * Allow the thread to be killed by a signal, but set the signal mask
@@ -2556,21 +2566,16 @@
 	common->thread_task = NULL;
 	spin_unlock_irq(&common->lock);
 
-	if (!common->ops || !common->ops->thread_exits
-	 || common->ops->thread_exits(common) < 0) {
-		int i;
-
-		down_write(&common->filesem);
-		for (i = 0; i < ARRAY_SIZE(common->luns); --i) {
-			struct fsg_lun *curlun = common->luns[i];
-			if (!curlun || !fsg_lun_is_open(curlun))
-				continue;
+	/* Eject media from all LUNs */
 
+	down_write(&common->filesem);
+	for (i = 0; i < ARRAY_SIZE(common->luns); i++) {
+		struct fsg_lun *curlun = common->luns[i];
+
+		if (curlun && fsg_lun_is_open(curlun))
 			fsg_lun_close(curlun);
-			curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
-		}
-		up_write(&common->filesem);
 	}
+	up_write(&common->filesem);
 
 	/* Let fsg_unbind() know the thread has exited */
 	complete_and_exit(&common->thread_notifier, 0);
@@ -2776,13 +2781,6 @@
 }
 EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
 
-void fsg_common_set_ops(struct fsg_common *common,
-			const struct fsg_operations *ops)
-{
-	common->ops = ops;
-}
-EXPORT_SYMBOL_GPL(fsg_common_set_ops);
-
 void fsg_common_free_buffers(struct fsg_common *common)
 {
 	_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);
@@ -2977,25 +2975,6 @@
 }
 EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string);
 
-int fsg_common_run_thread(struct fsg_common *common)
-{
-	common->state = FSG_STATE_IDLE;
-	/* Tell the thread to start working */
-	common->thread_task =
-		kthread_create(fsg_main_thread, common, "file-storage");
-	if (IS_ERR(common->thread_task)) {
-		common->state = FSG_STATE_TERMINATED;
-		return PTR_ERR(common->thread_task);
-	}
-
-	DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
-
-	wake_up_process(common->thread_task);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(fsg_common_run_thread);
-
 static void fsg_common_release(struct kref *ref)
 {
 	struct fsg_common *common = container_of(ref, struct fsg_common, ref);
@@ -3005,6 +2984,7 @@
 	if (common->state != FSG_STATE_TERMINATED) {
 		raise_exception(common, FSG_STATE_EXIT);
 		wait_for_completion(&common->thread_notifier);
+		common->thread_task = NULL;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
@@ -3050,9 +3030,21 @@
 		if (ret)
 			return ret;
 		fsg_common_set_inquiry_string(fsg->common, NULL, NULL);
-		ret = fsg_common_run_thread(fsg->common);
-		if (ret)
+	}
+
+	if (!common->thread_task) {
+		common->state = FSG_STATE_IDLE;
+		common->thread_task =
+			kthread_create(fsg_main_thread, common, "file-storage");
+		if (IS_ERR(common->thread_task)) {
+			int ret = PTR_ERR(common->thread_task);
+			common->thread_task = NULL;
+			common->state = FSG_STATE_TERMINATED;
 			return ret;
+		}
+		DBG(common, "I/O thread pid: %d\n",
+		    task_pid_nr(common->thread_task));
+		wake_up_process(common->thread_task);
 	}
 
 	fsg->gadget = gadget;
@@ -3270,6 +3262,7 @@
 	fsg_opts = to_fsg_opts(&group->cg_item);
 	if (num >= FSG_MAX_LUNS)
 		return ERR_PTR(-ERANGE);
+	num = array_index_nospec(num, FSG_MAX_LUNS);
 
 	mutex_lock(&fsg_opts->lock);
 	if (fsg_opts->refcnt || fsg_opts->common->luns[num]) {
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_mass_storage.h
+++ linux-4.4.0/drivers/usb/gadget/function/f_mass_storage.h
@@ -60,17 +60,6 @@
 struct fsg_common;
 
 /* FSF callback functions */
-struct fsg_operations {
-	/*
-	 * Callback function to call when thread exits.  If no
-	 * callback is set or it returns value lower then zero MSF
-	 * will force eject all LUNs it operates on (including those
-	 * marked as non-removable or with prevent_medium_removal flag
-	 * set).
-	 */
-	int (*thread_exits)(struct fsg_common *common);
-};
-
 struct fsg_lun_opts {
 	struct config_group group;
 	struct fsg_lun *lun;
@@ -141,9 +130,6 @@
 
 void fsg_common_remove_luns(struct fsg_common *common);
 
-void fsg_common_set_ops(struct fsg_common *common,
-			const struct fsg_operations *ops);
-
 int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
 			  unsigned int id, const char *name,
 			  const char **name_pfx);
@@ -153,8 +139,6 @@
 void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
 				   const char *pn);
 
-int fsg_common_run_thread(struct fsg_common *common);
-
 void fsg_config_from_params(struct fsg_config *cfg,
 			    const struct fsg_module_parameters *params,
 			    unsigned int fsg_num_buffers);
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_midi.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_midi.c
@@ -201,12 +201,6 @@
 	return alloc_ep_req(ep, length, length);
 }
 
-static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
-{
-	kfree(req->buf);
-	usb_ep_free_request(ep, req);
-}
-
 static const uint8_t f_midi_cin_length[] = {
 	0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
 };
@@ -361,16 +355,20 @@
 	/* allocate a bunch of read buffers and queue them all at once. */
 	for (i = 0; i < midi->qlen && err == 0; i++) {
 		struct usb_request *req =
-			midi_alloc_ep_req(midi->out_ep, midi->buflen);
+			midi_alloc_ep_req(midi->out_ep,
+				max_t(unsigned, midi->buflen,
+					bulk_out_desc.wMaxPacketSize));
 		if (req == NULL)
 			return -ENOMEM;
 
 		req->complete = f_midi_complete;
 		err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC);
 		if (err) {
-			ERROR(midi, "%s queue req: %d\n",
+			ERROR(midi, "%s: couldn't enqueue request: %d\n",
 				    midi->out_ep->name, err);
-			free_ep_req(midi->out_ep, req);
+			if (req->buf != NULL)
+				free_ep_req(midi->out_ep, req);
+			return err;
 		}
 	}
 
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_ncm.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_ncm.c
@@ -57,6 +57,7 @@
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	u8				notify_state;
+	atomic_t			notify_count;
 	bool				is_open;
 
 	const struct ndp_parser_opts	*parser_opts;
@@ -480,7 +481,7 @@
 	int				status;
 
 	/* notification already in flight? */
-	if (!req)
+	if (atomic_read(&ncm->notify_count))
 		return;
 
 	event = req->buf;
@@ -520,7 +521,8 @@
 	event->bmRequestType = 0xA1;
 	event->wIndex = cpu_to_le16(ncm->ctrl_id);
 
-	ncm->notify_req = NULL;
+	atomic_inc(&ncm->notify_count);
+
 	/*
 	 * In double buffering if there is a space in FIFO,
 	 * completion callback can be called right after the call,
@@ -530,7 +532,7 @@
 	status = usb_ep_queue(ncm->notify, req, GFP_ATOMIC);
 	spin_lock(&ncm->lock);
 	if (status < 0) {
-		ncm->notify_req = req;
+		atomic_dec(&ncm->notify_count);
 		DBG(cdev, "notify --> %d\n", status);
 	}
 }
@@ -565,17 +567,19 @@
 	case 0:
 		VDBG(cdev, "Notification %02x sent\n",
 		     event->bNotificationType);
+		atomic_dec(&ncm->notify_count);
 		break;
 	case -ECONNRESET:
 	case -ESHUTDOWN:
+		atomic_set(&ncm->notify_count, 0);
 		ncm->notify_state = NCM_NOTIFY_NONE;
 		break;
 	default:
 		DBG(cdev, "event %02x --> %d\n",
 			event->bNotificationType, req->status);
+		atomic_dec(&ncm->notify_count);
 		break;
 	}
-	ncm->notify_req = req;
 	ncm_do_notify(ncm);
 	spin_unlock(&ncm->lock);
 }
@@ -818,7 +822,7 @@
 		if (alt > 1)
 			goto fail;
 
-		if (ncm->port.in_ep->enabled) {
+		if (ncm->netdev) {
 			DBG(cdev, "reset ncm\n");
 			ncm->timer_stopping = true;
 			ncm->netdev = NULL;
@@ -1273,7 +1277,7 @@
 
 	DBG(cdev, "ncm deactivated\n");
 
-	if (ncm->port.in_ep->enabled) {
+	if (ncm->netdev) {
 		ncm->timer_stopping = true;
 		ncm->netdev = NULL;
 		gether_disconnect(&ncm->port);
@@ -1559,6 +1563,11 @@
 	ncm_string_defs[0].id = 0;
 	usb_free_all_descriptors(f);
 
+	if (atomic_read(&ncm->notify_count)) {
+		usb_ep_dequeue(ncm->notify, ncm->notify_req);
+		atomic_set(&ncm->notify_count, 0);
+	}
+
 	kfree(ncm->notify_req->buf);
 	usb_ep_free_request(ncm->notify, ncm->notify_req);
 }
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_printer.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_printer.c
@@ -35,6 +35,7 @@
 #include <linux/types.h>
 #include <linux/ctype.h>
 #include <linux/cdev.h>
+#include <linux/kref.h>
 
 #include <asm/byteorder.h>
 #include <linux/io.h>
@@ -69,7 +70,7 @@
 	struct usb_gadget	*gadget;
 	s8			interface;
 	struct usb_ep		*in_ep, *out_ep;
-
+	struct kref             kref;
 	struct list_head	rx_reqs;	/* List of free RX structs */
 	struct list_head	rx_reqs_active;	/* List of Active RX xfers */
 	struct list_head	rx_buffers;	/* List of completed xfers */
@@ -161,14 +162,6 @@
 	.wMaxPacketSize =	cpu_to_le16(512)
 };
 
-static struct usb_qualifier_descriptor dev_qualifier = {
-	.bLength =		sizeof(dev_qualifier),
-	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
-	.bcdUSB =		cpu_to_le16(0x0200),
-	.bDeviceClass =		USB_CLASS_PRINTER,
-	.bNumConfigurations =	1
-};
-
 static struct usb_descriptor_header *hs_printer_function[] = {
 	(struct usb_descriptor_header *) &intf_desc,
 	(struct usb_descriptor_header *) &hs_ep_in_desc,
@@ -231,6 +224,13 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void printer_dev_free(struct kref *kref)
+{
+	struct printer_dev *dev = container_of(kref, struct printer_dev, kref);
+
+	kfree(dev);
+}
+
 static struct usb_request *
 printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
 {
@@ -361,6 +361,7 @@
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
+	kref_get(&dev->kref);
 	DBG(dev, "printer_open returned %x\n", ret);
 	return ret;
 }
@@ -378,6 +379,7 @@
 	dev->printer_status &= ~PRINTER_SELECTED;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
+	kref_put(&dev->kref, printer_dev_free);
 	DBG(dev, "printer_close\n");
 
 	return 0;
@@ -1114,6 +1116,7 @@
 		printer_req_free(dev->in_ep, req);
 	}
 
+	usb_free_all_descriptors(f);
 	return ret;
 
 }
@@ -1324,7 +1327,8 @@
 	struct f_printer_opts *opts;
 
 	opts = container_of(f->fi, struct f_printer_opts, func_inst);
-	kfree(dev);
+
+	kref_put(&dev->kref, printer_dev_free);
 	mutex_lock(&opts->lock);
 	--opts->refcnt;
 	mutex_unlock(&opts->lock);
@@ -1393,6 +1397,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	kref_init(&dev->kref);
 	++opts->refcnt;
 	dev->minor = opts->minor;
 	dev->pnp_string = opts->pnp_string;
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_rndis.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_rndis.c
@@ -91,8 +91,10 @@
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static unsigned int bitrate(struct usb_gadget *g)
 {
+	if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
+		return 4250000000U;
 	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
-		return 13 * 1024 * 8 * 1000 * 8;
+		return 3750000000U;
 	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
 		return 13 * 512 * 8 * 1000 * 8;
 	else
@@ -619,6 +621,7 @@
 	gether_disconnect(&rndis->port);
 
 	usb_ep_disable(rndis->notify);
+	rndis->notify->desc = NULL;
 }
 
 /*-------------------------------------------------------------------------*/
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_sourcesink.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_sourcesink.c
@@ -303,12 +303,6 @@
 	return alloc_ep_req(ep, len, ss->buflen);
 }
 
-void free_ep_req(struct usb_ep *ep, struct usb_request *req)
-{
-	kfree(req->buf);
-	usb_ep_free_request(ep, req);
-}
-
 static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
 {
 	int			value;
@@ -855,7 +849,7 @@
 
 	ss = kzalloc(sizeof(*ss), GFP_KERNEL);
 	if (!ss)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	ss_opts =  container_of(fi, struct f_ss_opts, func_inst);
 
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_uac1.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_uac1.c
@@ -336,7 +336,9 @@
 
 	/* Copy buffer is full, add it to the play_queue */
 	if (audio_buf_size - copy_buf->actual < req->actual) {
+		spin_lock_irq(&audio->lock);
 		list_add_tail(&copy_buf->list, &audio->play_queue);
+		spin_unlock_irq(&audio->lock);
 		schedule_work(&audio->playback_work);
 		copy_buf = f_audio_buffer_alloc(audio_buf_size);
 		if (IS_ERR(copy_buf))
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_uac2.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_uac2.c
@@ -598,18 +598,6 @@
 	NULL,
 };
 
-static struct usb_qualifier_descriptor devqual_desc = {
-	.bLength = sizeof devqual_desc,
-	.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
-
-	.bcdUSB = cpu_to_le16(0x200),
-	.bDeviceClass = USB_CLASS_MISC,
-	.bDeviceSubClass = 0x02,
-	.bDeviceProtocol = 0x01,
-	.bNumConfigurations = 1,
-	.bRESERVED = 0,
-};
-
 static struct usb_interface_assoc_descriptor iad_desc = {
 	.bLength = sizeof iad_desc,
 	.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
@@ -778,7 +766,7 @@
 
 	.bEndpointAddress = USB_DIR_OUT,
 	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
-	.wMaxPacketSize = cpu_to_le16(1023),
+	/* .wMaxPacketSize = DYNAMIC */
 	.bInterval = 1,
 };
 
@@ -787,7 +775,7 @@
 	.bDescriptorType = USB_DT_ENDPOINT,
 
 	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
-	.wMaxPacketSize = cpu_to_le16(1024),
+	/* .wMaxPacketSize = DYNAMIC */
 	.bInterval = 4,
 };
 
@@ -855,7 +843,7 @@
 
 	.bEndpointAddress = USB_DIR_IN,
 	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
-	.wMaxPacketSize = cpu_to_le16(1023),
+	/* .wMaxPacketSize = DYNAMIC */
 	.bInterval = 1,
 };
 
@@ -864,7 +852,7 @@
 	.bDescriptorType = USB_DT_ENDPOINT,
 
 	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
-	.wMaxPacketSize = cpu_to_le16(1024),
+	/* .wMaxPacketSize = DYNAMIC */
 	.bInterval = 4,
 };
 
@@ -941,14 +929,14 @@
 };
 
 struct cntrl_cur_lay3 {
-	__u32	dCUR;
+	__le32	dCUR;
 };
 
 struct cntrl_range_lay3 {
-	__u16	wNumSubRanges;
-	__u32	dMIN;
-	__u32	dMAX;
-	__u32	dRES;
+	__le16	wNumSubRanges;
+	__le32	dMIN;
+	__le32	dMAX;
+	__le32	dRES;
 } __packed;
 
 static inline void
@@ -975,12 +963,28 @@
 			"%s:%d Error!\n", __func__, __LINE__);
 }
 
-static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
+static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
 	struct usb_endpoint_descriptor *ep_desc,
-	unsigned int factor, bool is_playback)
+	enum usb_device_speed speed, bool is_playback)
 {
 	int chmask, srate, ssize;
-	u16 max_packet_size;
+	u16 max_size_bw, max_size_ep;
+	unsigned int factor;
+
+	switch (speed) {
+	case USB_SPEED_FULL:
+		max_size_ep = 1023;
+		factor = 1000;
+		break;
+
+	case USB_SPEED_HIGH:
+		max_size_ep = 1024;
+		factor = 8000;
+		break;
+
+	default:
+		return -EINVAL;
+	}
 
 	if (is_playback) {
 		chmask = uac2_opts->p_chmask;
@@ -992,10 +996,12 @@
 		ssize = uac2_opts->c_ssize;
 	}
 
-	max_packet_size = num_channels(chmask) * ssize *
-		DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
-	ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_packet_size,
-				le16_to_cpu(ep_desc->wMaxPacketSize)));
+	max_size_bw = num_channels(chmask) * ssize *
+		((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1);
+	ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
+						    max_size_ep));
+
+	return 0;
 }
 
 static int
@@ -1052,6 +1058,8 @@
 		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
 		return ret;
 	}
+	iad_desc.bFirstInterface = ret;
+
 	std_ac_if_desc.bInterfaceNumber = ret;
 	agdev->ac_intf = ret;
 	agdev->ac_alt = 0;
@@ -1079,30 +1087,53 @@
 	agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
 	if (!agdev->out_ep) {
 		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		goto err;
+		return -ENODEV;
 	}
 
 	agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
 	if (!agdev->in_ep) {
 		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		goto err;
+		return -ENODEV;
 	}
 
 	uac2->p_prm.uac2 = uac2;
 	uac2->c_prm.uac2 = uac2;
 
 	/* Calculate wMaxPacketSize according to audio bandwidth */
-	set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
-	set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
-	set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
-	set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
+	ret = set_ep_max_packet_size(uac2_opts, &fs_epin_desc, USB_SPEED_FULL,
+				     true);
+	if (ret < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		return ret;
+	}
+
+	ret = set_ep_max_packet_size(uac2_opts, &fs_epout_desc, USB_SPEED_FULL,
+				     false);
+	if (ret < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		return ret;
+	}
+
+	ret = set_ep_max_packet_size(uac2_opts, &hs_epin_desc, USB_SPEED_HIGH,
+				     true);
+	if (ret < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		return ret;
+	}
+
+	ret = set_ep_max_packet_size(uac2_opts, &hs_epout_desc, USB_SPEED_HIGH,
+				     false);
+	if (ret < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		return ret;
+	}
 
 	hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
 	hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
 
 	ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
 	if (ret)
-		goto err;
+		return ret;
 
 	prm = &agdev->uac2.c_prm;
 	prm->max_psize = hs_epout_desc.wMaxPacketSize;
@@ -1117,19 +1148,19 @@
 	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
 	if (!prm->rbuf) {
 		prm->max_psize = 0;
-		goto err_free_descs;
+		goto err;
 	}
 
 	ret = alsa_uac2_init(agdev);
 	if (ret)
-		goto err_free_descs;
+		goto err;
 	return 0;
 
-err_free_descs:
-	usb_free_all_descriptors(fn);
 err:
 	kfree(agdev->uac2.p_prm.rbuf);
 	kfree(agdev->uac2.c_prm.rbuf);
+err_free_descs:
+	usb_free_all_descriptors(fn);
 	return -EINVAL;
 }
 
@@ -1291,11 +1322,12 @@
 
 	if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
 		struct cntrl_cur_lay3 c;
+		memset(&c, 0, sizeof(struct cntrl_cur_lay3));
 
 		if (entity_id == USB_IN_CLK_ID)
-			c.dCUR = p_srate;
+			c.dCUR = cpu_to_le32(p_srate);
 		else if (entity_id == USB_OUT_CLK_ID)
-			c.dCUR = c_srate;
+			c.dCUR = cpu_to_le32(c_srate);
 
 		value = min_t(unsigned, w_length, sizeof c);
 		memcpy(req->buf, &c, value);
@@ -1333,15 +1365,15 @@
 
 	if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
 		if (entity_id == USB_IN_CLK_ID)
-			r.dMIN = p_srate;
+			r.dMIN = cpu_to_le32(p_srate);
 		else if (entity_id == USB_OUT_CLK_ID)
-			r.dMIN = c_srate;
+			r.dMIN = cpu_to_le32(c_srate);
 		else
 			return -EOPNOTSUPP;
 
 		r.dMAX = r.dMIN;
 		r.dRES = 0;
-		r.wNumSubRanges = 1;
+		r.wNumSubRanges = cpu_to_le16(1);
 
 		value = min_t(unsigned, w_length, sizeof r);
 		memcpy(req->buf, &r, value);
--- linux-4.4.0.orig/drivers/usb/gadget/function/f_uvc.c
+++ linux-4.4.0/drivers/usb/gadget/function/f_uvc.c
@@ -594,6 +594,14 @@
 	opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
 	opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
 
+	/* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */
+	if (opts->streaming_maxburst &&
+	    (opts->streaming_maxpacket % 1024) != 0) {
+		opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024);
+		INFO(cdev, "overriding streaming_maxpacket to %d\n",
+		     opts->streaming_maxpacket);
+	}
+
 	/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
 	 * module parameters.
 	 *
@@ -625,7 +633,7 @@
 	uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
 	uvc_ss_streaming_comp.wBytesPerInterval =
 		cpu_to_le16(max_packet_size * max_packet_mult *
-			    opts->streaming_maxburst);
+			    (opts->streaming_maxburst + 1));
 
 	/* Allocate endpoints. */
 	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
--- linux-4.4.0.orig/drivers/usb/gadget/function/g_zero.h
+++ linux-4.4.0/drivers/usb/gadget/function/g_zero.h
@@ -59,7 +59,6 @@
 int lb_modinit(void);
 
 /* common utilities */
-void free_ep_req(struct usb_ep *ep, struct usb_request *req);
 void disable_endpoints(struct usb_composite_dev *cdev,
 		struct usb_ep *in, struct usb_ep *out,
 		struct usb_ep *iso_in, struct usb_ep *iso_out);
--- linux-4.4.0.orig/drivers/usb/gadget/function/rndis.c
+++ linux-4.4.0/drivers/usb/gadget/function/rndis.c
@@ -642,14 +642,18 @@
 	rndis_set_cmplt_type *resp;
 	rndis_resp_t *r;
 
+	BufLength = le32_to_cpu(buf->InformationBufferLength);
+	BufOffset = le32_to_cpu(buf->InformationBufferOffset);
+	if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
+	    (BufOffset > RNDIS_MAX_TOTAL_SIZE) ||
+	    (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
+		    return -EINVAL;
+
 	r = rndis_add_response(params, sizeof(rndis_set_cmplt_type));
 	if (!r)
 		return -ENOMEM;
 	resp = (rndis_set_cmplt_type *)r->buf;
 
-	BufLength = le32_to_cpu(buf->InformationBufferLength);
-	BufOffset = le32_to_cpu(buf->InformationBufferOffset);
-
 #ifdef	VERBOSE_DEBUG
 	pr_debug("%s: Length: %d\n", __func__, BufLength);
 	pr_debug("%s: Offset: %d\n", __func__, BufOffset);
@@ -680,6 +684,12 @@
 {
 	rndis_reset_cmplt_type *resp;
 	rndis_resp_t *r;
+	u8 *xbuf;
+	u32 length;
+
+	/* drain the response queue */
+	while ((xbuf = rndis_get_next_response(params, &length)))
+		rndis_free_response(params, xbuf);
 
 	r = rndis_add_response(params, sizeof(rndis_reset_cmplt_type));
 	if (!r)
--- linux-4.4.0.orig/drivers/usb/gadget/function/u_ether.c
+++ linux-4.4.0/drivers/usb/gadget/function/u_ether.c
@@ -96,7 +96,7 @@
 static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
 {
 	if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
-					    gadget->speed == USB_SPEED_SUPER))
+					    gadget->speed >= USB_SPEED_SUPER))
 		return qmult * DEFAULT_QLEN;
 	else
 		return DEFAULT_QLEN;
@@ -207,11 +207,12 @@
 		out = dev->port_usb->out_ep;
 	else
 		out = NULL;
-	spin_unlock_irqrestore(&dev->lock, flags);
 
 	if (!out)
+	{
+		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENOTCONN;
-
+	}
 
 	/* Padding up to RX_EXTRA handles minor disagreements with host.
 	 * Normally we use the USB "terminate on short read" convention;
@@ -232,6 +233,7 @@
 
 	if (dev->port_usb->is_fixed)
 		size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+	spin_unlock_irqrestore(&dev->lock, flags);
 
 	skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
 	if (skb == NULL) {
@@ -594,13 +596,6 @@
 
 	req->length = length;
 
-	/* throttle high/super speed IRQ rate back slightly */
-	if (gadget_is_dualspeed(dev->gadget))
-		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
-				     dev->gadget->speed == USB_SPEED_SUPER)
-			? ((atomic_read(&dev->tx_qlen) % dev->qmult) != 0)
-			: 0;
-
 	retval = usb_ep_queue(in, req, GFP_ATOMIC);
 	switch (retval) {
 	default:
--- linux-4.4.0.orig/drivers/usb/gadget/function/u_serial.c
+++ linux-4.4.0/drivers/usb/gadget/function/u_serial.c
@@ -361,10 +361,15 @@
 */
 {
 	struct list_head	*pool = &port->write_pool;
-	struct usb_ep		*in = port->port_usb->in;
+	struct usb_ep		*in;
 	int			status = 0;
 	bool			do_tty_wake = false;
 
+	if (!port->port_usb)
+		return status;
+
+	in = port->port_usb->in;
+
 	while (!port->write_busy && !list_empty(pool)) {
 		struct usb_request	*req;
 		int			len;
@@ -518,7 +523,7 @@
 		}
 
 		/* push data to (open) tty */
-		if (req->actual) {
+		if (req->actual && tty) {
 			char		*packet = req->buf;
 			unsigned	size = req->actual;
 			unsigned	n;
@@ -696,8 +701,10 @@
 	port->n_read = 0;
 	started = gs_start_rx(port);
 
-	/* unblock any pending writes into our circular buffer */
 	if (started) {
+		gs_start_tx(port);
+		/* Unblock any pending writes into our circular buffer, in case
+		 * we didn't in gs_start_tx() */
 		tty_wakeup(port->port.tty);
 	} else {
 		gs_free_requests(ep, head, &port->read_allocated);
@@ -1132,8 +1139,10 @@
 				__func__, port_num, PTR_ERR(tty_dev));
 
 		ret = PTR_ERR(tty_dev);
+		mutex_lock(&ports[port_num].lock);
 		port = ports[port_num].port;
 		ports[port_num].port = NULL;
+		mutex_unlock(&ports[port_num].lock);
 		gserial_free_port(port);
 		goto err;
 	}
--- linux-4.4.0.orig/drivers/usb/gadget/function/uvc_configfs.c
+++ linux-4.4.0/drivers/usb/gadget/function/uvc_configfs.c
@@ -564,6 +564,7 @@
 unlock:
 	mutex_unlock(&opts->lock);
 out:
+	config_item_put(header);
 	mutex_unlock(su_mutex);
 	return ret;
 }
@@ -605,6 +606,7 @@
 unlock:
 	mutex_unlock(&opts->lock);
 out:
+	config_item_put(header);
 	mutex_unlock(su_mutex);
 	return ret;
 }
@@ -805,6 +807,7 @@
 	format_ptr->fmt = target_fmt;
 	list_add_tail(&format_ptr->entry, &src_hdr->formats);
 	++src_hdr->num_fmt;
+	++target_fmt->linked;
 
 out:
 	mutex_unlock(&opts->lock);
@@ -843,6 +846,8 @@
 			break;
 		}
 
+	--target_fmt->linked;
+
 out:
 	mutex_unlock(&opts->lock);
 	mutex_unlock(su_mutex);
@@ -2087,6 +2092,7 @@
 unlock:
 	mutex_unlock(&opts->lock);
 out:
+	config_item_put(header);
 	mutex_unlock(su_mutex);
 	return ret;
 }
@@ -2131,6 +2137,7 @@
 unlock:
 	mutex_unlock(&opts->lock);
 out:
+	config_item_put(header);
 	mutex_unlock(su_mutex);
 	return ret;
 }
@@ -2202,7 +2209,7 @@
 	.release		= uvc_attr_release,
 };
 
-#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit)		\
+#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit)	\
 static ssize_t f_uvc_opts_##cname##_show(				\
 	struct config_item *item, char *page)				\
 {									\
@@ -2245,16 +2252,16 @@
 	return ret;							\
 }									\
 									\
-UVC_ATTR(f_uvc_opts_, cname, aname)
+UVC_ATTR(f_uvc_opts_, cname, cname)
 
 #define identity_conv(x) (x)
 
-UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
-	       16);
-UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
-	       3072);
-UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
-	       15);
+UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
+	       kstrtou8, u8, identity_conv, 16);
+UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
+	       kstrtou16, u16, le16_to_cpu, 3072);
+UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
+	       kstrtou8, u8, identity_conv, 15);
 
 #undef identity_conv
 
--- linux-4.4.0.orig/drivers/usb/gadget/function/uvc_video.c
+++ linux-4.4.0/drivers/usb/gadget/function/uvc_video.c
@@ -129,6 +129,21 @@
  * Request handling
  */
 
+static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
+{
+	int ret;
+
+	ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
+	if (ret < 0) {
+		printk(KERN_INFO "Failed to queue request (%d).\n", ret);
+		/* Isochronous endpoints can't be halted. */
+		if (usb_endpoint_xfer_bulk(video->ep->desc))
+			usb_ep_set_halt(video->ep);
+	}
+
+	return ret;
+}
+
 /*
  * I somehow feel that synchronisation won't be easy to achieve here. We have
  * three events that control USB requests submission:
@@ -193,14 +208,13 @@
 
 	video->encode(req, video, buf);
 
-	if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) {
-		printk(KERN_INFO "Failed to queue request (%d).\n", ret);
-		usb_ep_set_halt(ep);
-		spin_unlock_irqrestore(&video->queue.irqlock, flags);
+	ret = uvcg_video_ep_queue(video, req);
+	spin_unlock_irqrestore(&video->queue.irqlock, flags);
+
+	if (ret < 0) {
 		uvcg_queue_cancel(queue, 0);
 		goto requeue;
 	}
-	spin_unlock_irqrestore(&video->queue.irqlock, flags);
 
 	return;
 
@@ -243,7 +257,7 @@
 
 	req_size = video->ep->maxpacket
 		 * max_t(unsigned int, video->ep->maxburst, 1)
-		 * (video->ep->mult + 1);
+		 * (video->ep->mult);
 
 	for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
 		video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);
@@ -320,15 +334,13 @@
 		video->encode(req, video, buf);
 
 		/* Queue the USB request */
-		ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
+		ret = uvcg_video_ep_queue(video, req);
+		spin_unlock_irqrestore(&queue->irqlock, flags);
+
 		if (ret < 0) {
-			printk(KERN_INFO "Failed to queue request (%d)\n", ret);
-			usb_ep_set_halt(video->ep);
-			spin_unlock_irqrestore(&queue->irqlock, flags);
 			uvcg_queue_cancel(queue, 0);
 			break;
 		}
-		spin_unlock_irqrestore(&queue->irqlock, flags);
 	}
 
 	spin_lock_irqsave(&video->req_lock, flags);
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/acm_ms.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/acm_ms.c
@@ -133,10 +133,6 @@
 	if (status < 0)
 		goto put_msg;
 
-	status = fsg_common_run_thread(opts->common);
-	if (status)
-		goto remove_acm;
-
 	status = usb_add_function(c, f_msg);
 	if (status)
 		goto remove_acm;
@@ -211,8 +207,10 @@
 		struct usb_descriptor_header *usb_desc;
 
 		usb_desc = usb_otg_descriptor_alloc(gadget);
-		if (!usb_desc)
+		if (!usb_desc) {
+			status = -ENOMEM;
 			goto fail_string_ids;
+		}
 		usb_otg_descriptor_init(gadget, usb_desc);
 		otg_desc[0] = usb_desc;
 		otg_desc[1] = NULL;
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/audio.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/audio.c
@@ -249,8 +249,10 @@
 		struct usb_descriptor_header *usb_desc;
 
 		usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
-		if (!usb_desc)
+		if (!usb_desc) {
+			status = -ENOMEM;
 			goto fail;
+		}
 		usb_otg_descriptor_init(cdev->gadget, usb_desc);
 		otg_desc[0] = usb_desc;
 		otg_desc[1] = NULL;
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/cdc2.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/cdc2.c
@@ -183,8 +183,10 @@
 		struct usb_descriptor_header *usb_desc;
 
 		usb_desc = usb_otg_descriptor_alloc(gadget);
-		if (!usb_desc)
+		if (!usb_desc) {
+			status = -ENOMEM;
 			goto fail1;
+		}
 		usb_otg_descriptor_init(gadget, usb_desc);
 		otg_desc[0] = usb_desc;
 		otg_desc[1] = NULL;
@@ -229,7 +231,7 @@
 	.name		= "g_cdc",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
-	.max_speed	= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_SUPER,
 	.bind		= cdc_bind,
 	.unbind		= cdc_unbind,
 };
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/dbgp.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/dbgp.c
@@ -136,7 +136,7 @@
 		goto fail_1;
 	}
 
-	req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL);
+	req->buf = kzalloc(DBGP_REQ_LEN, GFP_KERNEL);
 	if (!req->buf) {
 		err = -ENOMEM;
 		stp = 2;
@@ -344,6 +344,19 @@
 	void *data = NULL;
 	u16 len = 0;
 
+	if (length > DBGP_REQ_LEN) {
+		if (ctrl->bRequestType & USB_DIR_IN) {
+			/* Cast away the const, we are going to overwrite on purpose. */
+			__le16 *temp = (__le16 *)&ctrl->wLength;
+
+			*temp = cpu_to_le16(DBGP_REQ_LEN);
+			length = DBGP_REQ_LEN;
+		} else {
+			return err;
+		}
+	}
+
+
 	if (request == USB_REQ_GET_DESCRIPTOR) {
 		switch (value>>8) {
 		case USB_DT_DEVICE:
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/ether.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/ether.c
@@ -407,8 +407,10 @@
 		struct usb_descriptor_header *usb_desc;
 
 		usb_desc = usb_otg_descriptor_alloc(gadget);
-		if (!usb_desc)
+		if (!usb_desc) {
+			status = -ENOMEM;
 			goto fail1;
+		}
 		usb_otg_descriptor_init(gadget, usb_desc);
 		otg_desc[0] = usb_desc;
 		otg_desc[1] = NULL;
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/g_ffs.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/g_ffs.c
@@ -153,7 +153,7 @@
 	.name		= DRIVER_NAME,
 	.dev		= &gfs_dev_desc,
 	.strings	= gfs_dev_strings,
-	.max_speed	= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_SUPER,
 	.bind		= gfs_bind,
 	.unbind		= gfs_unbind,
 };
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/inode.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/inode.c
@@ -27,7 +27,7 @@
 #include <linux/mmu_context.h>
 #include <linux/aio.h>
 #include <linux/uio.h>
-
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
 
@@ -113,9 +113,12 @@
 /* enough for the whole queue: most events invalidate others */
 #define	N_EVENT			5
 
+#define RBUF_SIZE		256
+
 struct dev_data {
 	spinlock_t			lock;
 	atomic_t			count;
+	int				udc_usage;
 	enum ep0_state			state;		/* P: lock */
 	struct usb_gadgetfs_event	event [N_EVENT];
 	unsigned			ev_next;
@@ -145,7 +148,7 @@
 	struct dentry			*dentry;
 
 	/* except this scratch i/o buffer for ep0 */
-	u8				rbuf [256];
+	u8				rbuf[RBUF_SIZE];
 };
 
 static inline void get_dev (struct dev_data *data)
@@ -512,9 +515,9 @@
 		INIT_WORK(&priv->work, ep_user_copy_worker);
 		schedule_work(&priv->work);
 	}
-	spin_unlock(&epdata->dev->lock);
 
 	usb_ep_free_request(ep, req);
+	spin_unlock(&epdata->dev->lock);
 	put_ep(epdata);
 }
 
@@ -541,7 +544,7 @@
 	 */
 	spin_lock_irq(&epdata->dev->lock);
 	value = -ENODEV;
-	if (unlikely(epdata->ep))
+	if (unlikely(epdata->ep == NULL))
 		goto fail;
 
 	req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
@@ -937,8 +940,13 @@
 			struct usb_ep		*ep = dev->gadget->ep0;
 			struct usb_request	*req = dev->req;
 
-			if ((retval = setup_req (ep, req, 0)) == 0)
-				retval = usb_ep_queue (ep, req, GFP_ATOMIC);
+			if ((retval = setup_req (ep, req, 0)) == 0) {
+				++dev->udc_usage;
+				spin_unlock_irq (&dev->lock);
+				retval = usb_ep_queue (ep, req, GFP_KERNEL);
+				spin_lock_irq (&dev->lock);
+				--dev->udc_usage;
+			}
 			dev->state = STATE_DEV_CONNECTED;
 
 			/* assume that was SET_CONFIGURATION */
@@ -979,11 +987,14 @@
 				retval = -EIO;
 			else {
 				len = min (len, (size_t)dev->req->actual);
-// FIXME don't call this with the spinlock held ...
+				++dev->udc_usage;
+				spin_unlock_irq(&dev->lock);
 				if (copy_to_user (buf, dev->req->buf, len))
 					retval = -EFAULT;
 				else
 					retval = len;
+				spin_lock_irq(&dev->lock);
+				--dev->udc_usage;
 				clean_req (dev->gadget->ep0, dev->req);
 				/* NOTE userspace can't yet choose to stall */
 			}
@@ -1122,11 +1133,12 @@
 	/* data and/or status stage for control request */
 	} else if (dev->state == STATE_DEV_SETUP) {
 
-		/* IN DATA+STATUS caller makes len <= wLength */
+		len = min_t(size_t, len, dev->setup_wLength);
 		if (dev->setup_in) {
 			retval = setup_req (dev->gadget->ep0, dev->req, len);
 			if (retval == 0) {
 				dev->state = STATE_DEV_CONNECTED;
+				++dev->udc_usage;
 				spin_unlock_irq (&dev->lock);
 				if (copy_from_user (dev->req->buf, buf, len))
 					retval = -EFAULT;
@@ -1137,10 +1149,10 @@
 						dev->gadget->ep0, dev->req,
 						GFP_KERNEL);
 				}
+				spin_lock_irq(&dev->lock);
+				--dev->udc_usage;
 				if (retval < 0) {
-					spin_lock_irq (&dev->lock);
 					clean_req (dev->gadget->ep0, dev->req);
-					spin_unlock_irq (&dev->lock);
 				} else
 					retval = len;
 
@@ -1237,9 +1249,21 @@
 	struct usb_gadget	*gadget = dev->gadget;
 	long ret = -ENOTTY;
 
-	if (gadget->ops->ioctl)
+	spin_lock_irq(&dev->lock);
+	if (dev->state == STATE_DEV_OPENED ||
+			dev->state == STATE_DEV_UNBOUND) {
+		/* Not bound to a UDC */
+	} else if (gadget->ops->ioctl) {
+		++dev->udc_usage;
+		spin_unlock_irq(&dev->lock);
+
 		ret = gadget->ops->ioctl (gadget, code, value);
 
+		spin_lock_irq(&dev->lock);
+		--dev->udc_usage;
+	}
+	spin_unlock_irq(&dev->lock);
+
 	return ret;
 }
 
@@ -1310,6 +1334,18 @@
 	u16				w_value = le16_to_cpu(ctrl->wValue);
 	u16				w_length = le16_to_cpu(ctrl->wLength);
 
+	if (w_length > RBUF_SIZE) {
+		if (ctrl->bRequestType & USB_DIR_IN) {
+			/* Cast away the const, we are going to overwrite on purpose. */
+			__le16 *temp = (__le16 *)&ctrl->wLength;
+
+			*temp = cpu_to_le16(RBUF_SIZE);
+			w_length = RBUF_SIZE;
+		} else {
+			return value;
+		}
+	}
+
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
 	if (dev->state == STATE_DEV_UNCONNECTED) {
@@ -1338,7 +1374,6 @@
 
 	req->buf = dev->rbuf;
 	req->context = NULL;
-	value = -EOPNOTSUPP;
 	switch (ctrl->bRequest) {
 
 	case USB_REQ_GET_DESCRIPTOR:
@@ -1456,8 +1491,13 @@
 							w_length);
 				if (value < 0)
 					break;
+
+				++dev->udc_usage;
+				spin_unlock (&dev->lock);
 				value = usb_ep_queue (gadget->ep0, dev->req,
-							GFP_ATOMIC);
+							GFP_KERNEL);
+				spin_lock (&dev->lock);
+				--dev->udc_usage;
 				if (value < 0) {
 					clean_req (gadget->ep0, dev->req);
 					break;
@@ -1480,11 +1520,18 @@
 	if (value >= 0 && dev->state != STATE_DEV_SETUP) {
 		req->length = value;
 		req->zero = value < w_length;
-		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+
+		++dev->udc_usage;
+		spin_unlock (&dev->lock);
+		value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL);
+		spin_lock(&dev->lock);
+		--dev->udc_usage;
+		spin_unlock(&dev->lock);
 		if (value < 0) {
 			DBG (dev, "ep_queue --> %d\n", value);
 			req->status = 0;
 		}
+		return value;
 	}
 
 	/* device stalls when value < 0 */
@@ -1506,21 +1553,24 @@
 		/* break link to FS */
 		ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
 		list_del_init (&ep->epfiles);
+		spin_unlock_irq (&dev->lock);
+
 		dentry = ep->dentry;
 		ep->dentry = NULL;
 		parent = d_inode(dentry->d_parent);
 
 		/* break link to controller */
+		mutex_lock(&ep->lock);
 		if (ep->state == STATE_EP_ENABLED)
 			(void) usb_ep_disable (ep->ep);
 		ep->state = STATE_EP_UNBOUND;
 		usb_ep_free_request (ep->ep, ep->req);
 		ep->ep = NULL;
+		mutex_unlock(&ep->lock);
+
 		wake_up (&ep->wait);
 		put_ep (ep);
 
-		spin_unlock_irq (&dev->lock);
-
 		/* break link to dcache */
 		mutex_lock (&parent->i_mutex);
 		d_delete (dentry);
@@ -1591,6 +1641,11 @@
 
 	spin_lock_irq (&dev->lock);
 	dev->state = STATE_DEV_UNBOUND;
+	while (dev->udc_usage > 0) {
+		spin_unlock_irq(&dev->lock);
+		usleep_range(1000, 2000);
+		spin_lock_irq(&dev->lock);
+	}
 	spin_unlock_irq (&dev->lock);
 
 	destroy_ep_files (dev);
@@ -1667,9 +1722,10 @@
 gadgetfs_suspend (struct usb_gadget *gadget)
 {
 	struct dev_data		*dev = get_gadget_data (gadget);
+	unsigned long		flags;
 
 	INFO (dev, "suspended from state %d\n", dev->state);
-	spin_lock (&dev->lock);
+	spin_lock_irqsave(&dev->lock, flags);
 	switch (dev->state) {
 	case STATE_DEV_SETUP:		// VERY odd... host died??
 	case STATE_DEV_CONNECTED:
@@ -1680,7 +1736,7 @@
 	default:
 		break;
 	}
-	spin_unlock (&dev->lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static struct usb_gadget_driver gadgetfs_driver = {
@@ -1746,10 +1802,12 @@
  * such as configuration notifications.
  */
 
-static int is_valid_config (struct usb_config_descriptor *config)
+static int is_valid_config(struct usb_config_descriptor *config,
+		unsigned int total)
 {
 	return config->bDescriptorType == USB_DT_CONFIG
 		&& config->bLength == USB_DT_CONFIG_SIZE
+		&& total >= USB_DT_CONFIG_SIZE
 		&& config->bConfigurationValue != 0
 		&& (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0
 		&& (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0;
@@ -1761,7 +1819,7 @@
 dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 {
 	struct dev_data		*dev = fd->private_data;
-	ssize_t			value = len, length = len;
+	ssize_t			value, length = len;
 	unsigned		total;
 	u32			tag;
 	char			*kbuf;
@@ -1774,7 +1832,8 @@
 	}
 	spin_unlock_irq(&dev->lock);
 
-	if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
+	if ((len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) ||
+	    (len > PAGE_SIZE * 4))
 		return -EINVAL;
 
 	/* we might need to change message format someday */
@@ -1791,14 +1850,18 @@
 
 	spin_lock_irq (&dev->lock);
 	value = -EINVAL;
-	if (dev->buf)
-		goto fail;
+	if (dev->buf) {
+		spin_unlock_irq(&dev->lock);
+		kfree(kbuf);
+		return value;
+	}
 	dev->buf = kbuf;
 
 	/* full or low speed config */
 	dev->config = (void *) kbuf;
 	total = le16_to_cpu(dev->config->wTotalLength);
-	if (!is_valid_config (dev->config) || total >= length)
+	if (!is_valid_config(dev->config, total) ||
+			total > length - USB_DT_DEVICE_SIZE)
 		goto fail;
 	kbuf += total;
 	length -= total;
@@ -1807,10 +1870,13 @@
 	if (kbuf [1] == USB_DT_CONFIG) {
 		dev->hs_config = (void *) kbuf;
 		total = le16_to_cpu(dev->hs_config->wTotalLength);
-		if (!is_valid_config (dev->hs_config) || total >= length)
+		if (!is_valid_config(dev->hs_config, total) ||
+				total > length - USB_DT_DEVICE_SIZE)
 			goto fail;
 		kbuf += total;
 		length -= total;
+	} else {
+		dev->hs_config = NULL;
 	}
 
 	/* could support multiple configs, using another encoding! */
@@ -1835,8 +1901,8 @@
 
 	value = usb_gadget_probe_driver(&gadgetfs_driver);
 	if (value != 0) {
-		kfree (dev->buf);
-		dev->buf = NULL;
+		spin_lock_irq(&dev->lock);
+		goto fail;
 	} else {
 		/* at this point "good" hardware has for the first time
 		 * let the USB the host see us.  alternatively, if users
@@ -1852,6 +1918,9 @@
 	return value;
 
 fail:
+	dev->config = NULL;
+	dev->hs_config = NULL;
+	dev->dev = NULL;
 	spin_unlock_irq (&dev->lock);
 	pr_debug ("%s: %s fail %Zd, %p\n", shortname, __func__, value, dev);
 	kfree (dev->buf);
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/mass_storage.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/mass_storage.c
@@ -107,15 +107,6 @@
 
 FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
 
-static unsigned long msg_registered;
-static void msg_cleanup(void);
-
-static int msg_thread_exits(struct fsg_common *common)
-{
-	msg_cleanup();
-	return 0;
-}
-
 static int msg_do_config(struct usb_configuration *c)
 {
 	struct fsg_opts *opts;
@@ -132,10 +123,6 @@
 	if (IS_ERR(f_msg))
 		return PTR_ERR(f_msg);
 
-	ret = fsg_common_run_thread(opts->common);
-	if (ret)
-		goto put_func;
-
 	ret = usb_add_function(c, f_msg);
 	if (ret)
 		goto put_func;
@@ -158,9 +145,6 @@
 
 static int msg_bind(struct usb_composite_dev *cdev)
 {
-	static const struct fsg_operations ops = {
-		.thread_exits = msg_thread_exits,
-	};
 	struct fsg_opts *opts;
 	struct fsg_config config;
 	int status;
@@ -177,8 +161,6 @@
 	if (status)
 		goto fail;
 
-	fsg_common_set_ops(opts->common, &ops);
-
 	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
 	if (status)
 		goto fail_set_cdev;
@@ -214,7 +196,6 @@
 	usb_composite_overwrite_options(cdev, &coverwrite);
 	dev_info(&cdev->gadget->dev,
 		 DRIVER_DESC ", version: " DRIVER_VERSION "\n");
-	set_bit(0, &msg_registered);
 	return 0;
 
 fail_otg_desc:
@@ -265,9 +246,8 @@
 }
 module_init(msg_init);
 
-static void msg_cleanup(void)
+static void __exit msg_cleanup(void)
 {
-	if (test_and_clear_bit(0, &msg_registered))
-		usb_composite_unregister(&msg_driver);
+	usb_composite_unregister(&msg_driver);
 }
 module_exit(msg_cleanup);
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/multi.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/multi.c
@@ -137,7 +137,6 @@
 
 static int rndis_do_config(struct usb_configuration *c)
 {
-	struct fsg_opts *fsg_opts;
 	int ret;
 
 	if (gadget_is_otg(c->cdev->gadget)) {
@@ -169,11 +168,6 @@
 		goto err_fsg;
 	}
 
-	fsg_opts = fsg_opts_from_func_inst(fi_msg);
-	ret = fsg_common_run_thread(fsg_opts->common);
-	if (ret)
-		goto err_run;
-
 	ret = usb_add_function(c, f_msg_rndis);
 	if (ret)
 		goto err_run;
@@ -225,7 +219,6 @@
 
 static int cdc_do_config(struct usb_configuration *c)
 {
-	struct fsg_opts *fsg_opts;
 	int ret;
 
 	if (gadget_is_otg(c->cdev->gadget)) {
@@ -258,11 +251,6 @@
 		goto err_fsg;
 	}
 
-	fsg_opts = fsg_opts_from_func_inst(fi_msg);
-	ret = fsg_common_run_thread(fsg_opts->common);
-	if (ret)
-		goto err_run;
-
 	ret = usb_add_function(c, f_msg_multi);
 	if (ret)
 		goto err_run;
@@ -498,7 +486,7 @@
 	.name		= "g_multi",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
-	.max_speed	= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_SUPER,
 	.bind		= multi_bind,
 	.unbind		= multi_unbind,
 	.needs_serial	= 1,
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/ncm.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/ncm.c
@@ -162,8 +162,10 @@
 		struct usb_descriptor_header *usb_desc;
 
 		usb_desc = usb_otg_descriptor_alloc(gadget);
-		if (!usb_desc)
+		if (!usb_desc) {
+			status = -ENOMEM;
 			goto fail;
+		}
 		usb_otg_descriptor_init(gadget, usb_desc);
 		otg_desc[0] = usb_desc;
 		otg_desc[1] = NULL;
@@ -203,7 +205,7 @@
 	.name		= "g_ncm",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
-	.max_speed	= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_SUPER,
 	.bind		= gncm_bind,
 	.unbind		= gncm_unbind,
 };
--- linux-4.4.0.orig/drivers/usb/gadget/legacy/nokia.c
+++ linux-4.4.0/drivers/usb/gadget/legacy/nokia.c
@@ -152,7 +152,6 @@
 	struct usb_function *f_ecm;
 	struct usb_function *f_obex2 = NULL;
 	struct usb_function *f_msg;
-	struct fsg_opts *fsg_opts;
 	int status = 0;
 	int obex1_stat = -1;
 	int obex2_stat = -1;
@@ -222,12 +221,6 @@
 		goto err_ecm;
 	}
 
-	fsg_opts = fsg_opts_from_func_inst(fi_msg);
-
-	status = fsg_common_run_thread(fsg_opts->common);
-	if (status)
-		goto err_msg;
-
 	status = usb_add_function(c, f_msg);
 	if (status)
 		goto err_msg;
--- linux-4.4.0.orig/drivers/usb/gadget/u_f.c
+++ linux-4.4.0/drivers/usb/gadget/u_f.c
@@ -11,16 +11,18 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/usb/gadget.h>
 #include "u_f.h"
+#include <linux/usb/ch9.h>
 
-struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len)
+struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len)
 {
 	struct usb_request      *req;
 
 	req = usb_ep_alloc_request(ep, GFP_ATOMIC);
 	if (req) {
 		req->length = len ?: default_len;
+		if (usb_endpoint_dir_out(ep->desc))
+			req->length = usb_ep_align(ep, req->length);
 		req->buf = kmalloc(req->length, GFP_ATOMIC);
 		if (!req->buf) {
 			usb_ep_free_request(ep, req);
--- linux-4.4.0.orig/drivers/usb/gadget/u_f.h
+++ linux-4.4.0/drivers/usb/gadget/u_f.h
@@ -16,6 +16,8 @@
 #ifndef __U_F_H__
 #define __U_F_H__
 
+#include <linux/usb/gadget.h>
+
 /* Variable Length Array Macros **********************************************/
 #define vla_group(groupname) size_t groupname##__next = 0
 #define vla_group_size(groupname) groupname##__next
@@ -45,8 +47,28 @@
 struct usb_ep;
 struct usb_request;
 
-struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len);
+/**
+ * alloc_ep_req - returns a usb_request allocated by the gadget driver and
+ * allocates the request's buffer.
+ *
+ * @ep: the endpoint to allocate a usb_request
+ * @len: usb_requests's buffer suggested size
+ * @default_len: used if @len is not provided, ie, is 0
+ *
+ * In case @ep direction is OUT, the @len will be aligned to ep's
+ * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use
+ * usb_requests's length (req->length) to refer to the allocated buffer size.
+ * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req().
+ */
+struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len);
+
+/* Frees a usb_request previously allocated by alloc_ep_req() */
+static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+	WARN_ON(req->buf == NULL);
+	kfree(req->buf);
+	req->buf = NULL;
+	usb_ep_free_request(ep, req);
+}
 
 #endif /* __U_F_H__ */
-
-
--- linux-4.4.0.orig/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -28,6 +28,8 @@
 #include <asm/gpio.h>
 
 #include "atmel_usba_udc.h"
+#define USBA_VBUS_IRQFLAGS (IRQF_ONESHOT \
+			   | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)
 
 #ifdef CONFIG_USB_GADGET_DEBUG_FS
 #include <linux/debugfs.h>
@@ -401,9 +403,11 @@
 		next_fifo_transaction(ep, req);
 		if (req->last_transaction) {
 			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
-			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+			if (ep_is_control(ep))
+				usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
 		} else {
-			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			if (ep_is_control(ep))
+				usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
 			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
 		}
 	}
@@ -839,7 +843,7 @@
 	u32 status;
 
 	DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
-			ep->ep.name, req);
+			ep->ep.name, _req);
 
 	spin_lock_irqsave(&udc->lock, flags);
 
@@ -2185,7 +2189,7 @@
 					IRQ_NOAUTOEN);
 			ret = devm_request_threaded_irq(&pdev->dev,
 					gpio_to_irq(udc->vbus_pin), NULL,
-					usba_vbus_irq_thread, IRQF_ONESHOT,
+					usba_vbus_irq_thread, USBA_VBUS_IRQFLAGS,
 					"atmel_usba_udc", udc);
 			if (ret) {
 				udc->vbus_pin = -ENODEV;
--- linux-4.4.0.orig/drivers/usb/gadget/udc/bdc/Kconfig
+++ linux-4.4.0/drivers/usb/gadget/udc/bdc/Kconfig
@@ -14,7 +14,7 @@
 comment "Platform Support"
 config	USB_BDC_PCI
 	tristate "BDC support for PCIe based platforms"
-	depends on PCI
+	depends on PCI && BROKEN
 	default USB_BDC_UDC
 	help
 		Enable support for platforms which have BDC connected through PCIe, such as Lego3 FPGA platform.
--- linux-4.4.0.orig/drivers/usb/gadget/udc/bdc/bdc_core.c
+++ linux-4.4.0/drivers/usb/gadget/udc/bdc/bdc_core.c
@@ -286,6 +286,7 @@
 	 * in that case reinit is passed as 1
 	 */
 	if (reinit) {
+		int i;
 		/* Enable interrupts */
 		temp = bdc_readl(bdc->regs, BDC_BDCSC);
 		temp |= BDC_GIE;
@@ -295,6 +296,9 @@
 		/* Initialize SRR to 0 */
 		memset(bdc->srr.sr_bds, 0,
 					NUM_SR_ENTRIES * sizeof(struct bdc_bd));
+		/* clear ep flags to avoid post disconnect stops/deconfigs */
+		for (i = 1; i < bdc->num_eps; ++i)
+			bdc->bdc_ep_array[i]->flags = 0;
 	} else {
 		/* One time initiaization only */
 		/* Enable status report function pointers */
@@ -475,7 +479,7 @@
 	bdc->dev = dev;
 	dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq);
 
-	temp = bdc_readl(bdc->regs, BDC_BDCSC);
+	temp = bdc_readl(bdc->regs, BDC_BDCCAP1);
 	if ((temp & BDC_P64) &&
 			!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
 		dev_dbg(bdc->dev, "Using 64-bit address\n");
--- linux-4.4.0.orig/drivers/usb/gadget/udc/bdc/bdc_ep.c
+++ linux-4.4.0/drivers/usb/gadget/udc/bdc/bdc_ep.c
@@ -546,7 +546,7 @@
 {
 	struct bdc *bdc = ep->bdc;
 
-	if (req == NULL  || &req->queue == NULL || &req->usb_req == NULL)
+	if (req == NULL)
 		return;
 
 	dev_dbg(bdc->dev, "%s ep:%s status:%d\n", __func__, ep->name, status);
@@ -621,7 +621,6 @@
 	}
 	bdc_dbg_bd_list(bdc, ep);
 	/* only for ep0: config ep is called for ep0 from connect event */
-	ep->flags |= BDC_EP_ENABLED;
 	if (ep->ep_num == 1)
 		return ret;
 
@@ -767,10 +766,13 @@
 					__func__, ep->name, start_bdi, end_bdi);
 	dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n",
 						ep, (void *)ep->usb_ep.desc);
-	/* Stop the ep to see where the HW is ? */
-	ret = bdc_stop_ep(bdc, ep->ep_num);
-	/* if there is an issue with stopping ep, then no need to go further */
-	if (ret)
+	/* if still connected, stop the ep to see where the HW is ? */
+	if (!(bdc_readl(bdc->regs, BDC_USPC) & BDC_PST_MASK)) {
+		ret = bdc_stop_ep(bdc, ep->ep_num);
+		/* if there is an issue, then no need to go further */
+		if (ret)
+			return 0;
+	} else
 		return 0;
 
 	/*
@@ -1921,7 +1923,9 @@
 		__func__, ep->name, ep->flags);
 
 	if (!(ep->flags & BDC_EP_ENABLED)) {
-		dev_warn(bdc->dev, "%s is already disabled\n", ep->name);
+		if (bdc->gadget.speed != USB_SPEED_UNKNOWN)
+			dev_warn(bdc->dev, "%s is already disabled\n",
+				 ep->name);
 		return 0;
 	}
 	spin_lock_irqsave(&bdc->lock, flags);
--- linux-4.4.0.orig/drivers/usb/gadget/udc/bdc/bdc_pci.c
+++ linux-4.4.0/drivers/usb/gadget/udc/bdc/bdc_pci.c
@@ -82,6 +82,7 @@
 	if (ret) {
 		dev_err(&pci->dev,
 			"couldn't add resources to bdc device\n");
+		platform_device_put(bdc);
 		return ret;
 	}
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/dummy_hcd.c
+++ linux-4.4.0/drivers/usb/gadget/udc/dummy_hcd.c
@@ -50,6 +50,7 @@
 #define DRIVER_VERSION	"02 May 2005"
 
 #define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
+#define POWER_BUDGET_3	900	/* in mA */
 
 static const char	driver_name[] = "dummy_hcd";
 static const char	driver_desc[] = "USB Host+Gadget Emulator";
@@ -237,6 +238,8 @@
 
 	struct usb_device		*udev;
 	struct list_head		urbp_list;
+	struct urbp			*next_frame_urbp;
+
 	u32				stream_en_ep;
 	u8				num_stream[30 / 2];
 
@@ -253,11 +256,13 @@
 	 */
 	struct dummy_ep			ep[DUMMY_ENDPOINTS];
 	int				address;
+	int				callback_usage;
 	struct usb_gadget		gadget;
 	struct usb_gadget_driver	*driver;
 	struct dummy_request		fifo_req;
 	u8				fifo_buf[FIFO_SIZE];
 	u16				devstatus;
+	unsigned			ints_enabled:1;
 	unsigned			udc_suspended:1;
 	unsigned			pullup:1;
 
@@ -330,7 +335,7 @@
 /* caller must hold lock */
 static void stop_activity(struct dummy *dum)
 {
-	struct dummy_ep	*ep;
+	int i;
 
 	/* prevent any more requests */
 	dum->address = 0;
@@ -338,8 +343,8 @@
 	/* The timer is left running so that outstanding URBs can fail */
 
 	/* nuke any pending requests first, so driver i/o is quiesced */
-	list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list)
-		nuke(dum, ep);
+	for (i = 0; i < DUMMY_ENDPOINTS; ++i)
+		nuke(dum, &dum->ep[i]);
 
 	/* driver now does any non-usb quiescing necessary */
 }
@@ -375,11 +380,10 @@
 			     USB_PORT_STAT_CONNECTION) == 0)
 				dum_hcd->port_status |=
 					(USB_PORT_STAT_C_CONNECTION << 16);
-			if ((dum_hcd->port_status &
-			     USB_PORT_STAT_ENABLE) == 1 &&
-				(dum_hcd->port_status &
-				 USB_SS_PORT_LS_U0) == 1 &&
-				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) &&
+			    (dum_hcd->port_status &
+			     USB_PORT_STAT_LINK_STATE) == USB_SS_PORT_LS_U0 &&
+			    dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
 				dum_hcd->active = 1;
 		}
 	} else {
@@ -416,6 +420,7 @@
 static void set_link_state(struct dummy_hcd *dum_hcd)
 {
 	struct dummy *dum = dum_hcd->dum;
+	unsigned int power_bit;
 
 	dum_hcd->active = 0;
 	if (dum->pullup)
@@ -426,39 +431,43 @@
 			return;
 
 	set_link_state_by_speed(dum_hcd);
+	power_bit = (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 ?
+			USB_SS_PORT_STAT_POWER : USB_PORT_STAT_POWER);
 
 	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
 	     dum_hcd->active)
 		dum_hcd->resuming = 0;
 
 	/* Currently !connected or in reset */
-	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+	if ((dum_hcd->port_status & power_bit) == 0 ||
 			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
-		unsigned disconnect = USB_PORT_STAT_CONNECTION &
+		unsigned int disconnect = power_bit &
 				dum_hcd->old_status & (~dum_hcd->port_status);
-		unsigned reset = USB_PORT_STAT_RESET &
+		unsigned int reset = USB_PORT_STAT_RESET &
 				(~dum_hcd->old_status) & dum_hcd->port_status;
 
 		/* Report reset and disconnect events to the driver */
-		if (dum->driver && (disconnect || reset)) {
+		if (dum->ints_enabled && (disconnect || reset)) {
 			stop_activity(dum);
+			++dum->callback_usage;
 			spin_unlock(&dum->lock);
 			if (reset)
 				usb_gadget_udc_reset(&dum->gadget, dum->driver);
 			else
 				dum->driver->disconnect(&dum->gadget);
 			spin_lock(&dum->lock);
+			--dum->callback_usage;
 		}
-	} else if (dum_hcd->active != dum_hcd->old_active) {
-		if (dum_hcd->old_active && dum->driver->suspend) {
-			spin_unlock(&dum->lock);
+	} else if (dum_hcd->active != dum_hcd->old_active &&
+			dum->ints_enabled) {
+		++dum->callback_usage;
+		spin_unlock(&dum->lock);
+		if (dum_hcd->old_active && dum->driver->suspend)
 			dum->driver->suspend(&dum->gadget);
-			spin_lock(&dum->lock);
-		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
-			spin_unlock(&dum->lock);
+		else if (!dum_hcd->old_active &&  dum->driver->resume)
 			dum->driver->resume(&dum->gadget);
-			spin_lock(&dum->lock);
-		}
+		spin_lock(&dum->lock);
+		--dum->callback_usage;
 	}
 
 	dum_hcd->old_status = dum_hcd->port_status;
@@ -974,8 +983,11 @@
 	 * can't enumerate without help from the driver we're binding.
 	 */
 
+	spin_lock_irq(&dum->lock);
 	dum->devstatus = 0;
 	dum->driver = driver;
+	dum->ints_enabled = 1;
+	spin_unlock_irq(&dum->lock);
 
 	return 0;
 }
@@ -985,7 +997,19 @@
 	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
 	struct dummy		*dum = dum_hcd->dum;
 
+	spin_lock_irq(&dum->lock);
+	dum->ints_enabled = 0;
+	stop_activity(dum);
+
+	/* emulate synchronize_irq(): wait for callbacks to finish */
+	while (dum->callback_usage > 0) {
+		spin_unlock_irq(&dum->lock);
+		usleep_range(1000, 2000);
+		spin_lock_irq(&dum->lock);
+	}
+
 	dum->driver = NULL;
+	spin_unlock_irq(&dum->lock);
 
 	return 0;
 }
@@ -1033,9 +1057,16 @@
 	int		rc;
 
 	dum = *((void **)dev_get_platdata(&pdev->dev));
+	/* Clear usb_gadget region for new registration to udc-core */
+	memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));
 	dum->gadget.name = gadget_name;
 	dum->gadget.ops = &dummy_ops;
-	dum->gadget.max_speed = USB_SPEED_SUPER;
+	if (mod_data.is_super_speed)
+		dum->gadget.max_speed = USB_SPEED_SUPER;
+	else if (mod_data.is_high_speed)
+		dum->gadget.max_speed = USB_SPEED_HIGH;
+	else
+		dum->gadget.max_speed = USB_SPEED_FULL;
 
 	dum->gadget.dev.parent = &pdev->dev;
 	init_dummy_udc_hw(dum);
@@ -1244,6 +1275,8 @@
 
 	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
 	urb->hcpriv = urbp;
+	if (!dum_hcd->next_frame_urbp)
+		dum_hcd->next_frame_urbp = urbp;
 	if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
 		urb->error_count = 1;		/* mark as a new urb */
 
@@ -1520,6 +1553,8 @@
 	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
 			dum->ss_hcd : dum->hs_hcd)))
 		return NULL;
+	if (!dum->ints_enabled)
+		return NULL;
 	if ((address & ~USB_DIR_IN) == 0)
 		return &dum->ep[0];
 	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
@@ -1761,6 +1796,7 @@
 		spin_unlock_irqrestore(&dum->lock, flags);
 		return;
 	}
+	dum_hcd->next_frame_urbp = NULL;
 
 	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
 		if (!ep_info[i].name)
@@ -1777,6 +1813,10 @@
 		int			type;
 		int			status = -EINPROGRESS;
 
+		/* stop when we reach URBs queued after the timer interrupt */
+		if (urbp == dum_hcd->next_frame_urbp)
+			break;
+
 		urb = urbp->urb;
 		if (urb->unlinked)
 			goto return_urb;
@@ -1856,10 +1896,12 @@
 			 * until setup() returns; no reentrancy issues etc.
 			 */
 			if (value > 0) {
+				++dum->callback_usage;
 				spin_unlock(&dum->lock);
 				value = dum->driver->setup(&dum->gadget,
 						&setup);
 				spin_lock(&dum->lock);
+				--dum->callback_usage;
 
 				if (value >= 0) {
 					/* no delays (max 64KB data stage) */
@@ -2009,7 +2051,7 @@
 			HUB_CHAR_COMMON_OCPM);
 	desc->bNbrPorts = 1;
 	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
-	desc->u.ss.DeviceRemovable = 0xffff;
+	desc->u.ss.DeviceRemovable = 0;
 }
 
 static inline void hub_descriptor(struct usb_hub_descriptor *desc)
@@ -2021,8 +2063,8 @@
 			HUB_CHAR_INDV_PORT_LPSM |
 			HUB_CHAR_COMMON_OCPM);
 	desc->bNbrPorts = 1;
-	desc->u.hs.DeviceRemovable[0] = 0xff;
-	desc->u.hs.DeviceRemovable[1] = 0xff;
+	desc->u.hs.DeviceRemovable[0] = 0;
+	desc->u.hs.DeviceRemovable[1] = 0xff;	/* PortPwrCtrlMask */
 }
 
 static int dummy_hub_control(
@@ -2063,16 +2105,13 @@
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (hcd->speed == HCD_USB3) {
-				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
-					dev_dbg(dummy_dev(dum_hcd),
-						"power-off\n");
-			} else
-				if (dum_hcd->port_status &
-							USB_SS_PORT_STAT_POWER)
-					dev_dbg(dummy_dev(dum_hcd),
-						"power-off\n");
-			/* FALLS THROUGH */
+			dev_dbg(dummy_dev(dum_hcd), "power-off\n");
+			if (hcd->speed == HCD_USB3)
+				dum_hcd->port_status &= ~USB_SS_PORT_STAT_POWER;
+			else
+				dum_hcd->port_status &= ~USB_PORT_STAT_POWER;
+			set_link_state(dum_hcd);
+			break;
 		default:
 			dum_hcd->port_status &= ~(1 << wValue);
 			set_link_state(dum_hcd);
@@ -2243,14 +2282,13 @@
 				if ((dum_hcd->port_status &
 				     USB_SS_PORT_STAT_POWER) != 0) {
 					dum_hcd->port_status |= (1 << wValue);
-					set_link_state(dum_hcd);
 				}
 			} else
 				if ((dum_hcd->port_status &
 				     USB_PORT_STAT_POWER) != 0) {
 					dum_hcd->port_status |= (1 << wValue);
-					set_link_state(dum_hcd);
 				}
+			set_link_state(dum_hcd);
 		}
 		break;
 	case GetPortErrorCount:
@@ -2398,7 +2436,7 @@
 	dum_hcd->rh_state = DUMMY_RH_RUNNING;
 	dum_hcd->stream_en_ep = 0;
 	INIT_LIST_HEAD(&dum_hcd->urbp_list);
-	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
+	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET_3;
 	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
 	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
 #ifdef CONFIG_USB_OTG
@@ -2567,8 +2605,6 @@
 	.product_desc =		"Dummy host controller",
 	.hcd_priv_size =	sizeof(struct dummy_hcd),
 
-	.flags =		HCD_USB3 | HCD_SHARED,
-
 	.reset =		dummy_setup,
 	.start =		dummy_start,
 	.stop =			dummy_stop,
@@ -2597,8 +2633,12 @@
 	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 	dum = *((void **)dev_get_platdata(&pdev->dev));
 
-	if (!mod_data.is_super_speed)
+	if (mod_data.is_super_speed)
+		dummy_hcd.flags = HCD_USB3 | HCD_SHARED;
+	else if (mod_data.is_high_speed)
 		dummy_hcd.flags = HCD_USB2;
+	else
+		dummy_hcd.flags = HCD_USB11;
 	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
 	if (!hs_hcd)
 		return -ENOMEM;
@@ -2701,7 +2741,7 @@
 {
 	int	retval = -ENOMEM;
 	int	i;
-	struct	dummy *dum[MAX_NUM_UDC];
+	struct	dummy *dum[MAX_NUM_UDC] = {};
 
 	if (usb_disabled())
 		return -ENODEV;
--- linux-4.4.0.orig/drivers/usb/gadget/udc/fotg210-udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/fotg210-udc.c
@@ -744,7 +744,7 @@
 	fotg210->ep0_req->length = 2;
 
 	spin_unlock(&fotg210->lock);
-	fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_KERNEL);
+	fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC);
 	spin_lock(&fotg210->lock);
 }
 
@@ -1066,12 +1066,15 @@
 static int fotg210_udc_remove(struct platform_device *pdev)
 {
 	struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
+	int i;
 
 	usb_del_gadget_udc(&fotg210->gadget);
 	iounmap(fotg210->reg);
 	free_irq(platform_get_irq(pdev, 0), fotg210);
 
 	fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
+	for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
+		kfree(fotg210->ep[i]);
 	kfree(fotg210);
 
 	return 0;
@@ -1102,7 +1105,7 @@
 	/* initialize udc */
 	fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL);
 	if (fotg210 == NULL)
-		goto err_alloc;
+		goto err;
 
 	for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
 		_ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
@@ -1114,7 +1117,7 @@
 	fotg210->reg = ioremap(res->start, resource_size(res));
 	if (fotg210->reg == NULL) {
 		pr_err("ioremap error.\n");
-		goto err_map;
+		goto err_alloc;
 	}
 
 	spin_lock_init(&fotg210->lock);
@@ -1162,7 +1165,7 @@
 	fotg210->ep0_req = fotg210_ep_alloc_request(&fotg210->ep[0]->ep,
 				GFP_KERNEL);
 	if (fotg210->ep0_req == NULL)
-		goto err_req;
+		goto err_map;
 
 	fotg210_init(fotg210);
 
@@ -1190,12 +1193,14 @@
 	fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
 
 err_map:
-	if (fotg210->reg)
-		iounmap(fotg210->reg);
+	iounmap(fotg210->reg);
 
 err_alloc:
+	for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
+		kfree(fotg210->ep[i]);
 	kfree(fotg210);
 
+err:
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -1878,11 +1878,8 @@
 
 	tmp = in_be16(&udc->usb_param->frame_n);
 	if (tmp & 0x8000)
-		tmp = tmp & 0x07ff;
-	else
-		tmp = -EINVAL;
-
-	return (int)tmp;
+		return tmp & 0x07ff;
+	return -EINVAL;
 }
 
 static int fsl_qe_start(struct usb_gadget *gadget,
@@ -2053,7 +2050,7 @@
 			struct qe_ep *ep;
 
 			if (wValue != 0 || wLength != 0
-				|| pipe > USB_MAX_ENDPOINTS)
+				|| pipe >= USB_MAX_ENDPOINTS)
 				break;
 			ep = &udc->eps[pipe];
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/fsl_udc_core.c
+++ linux-4.4.0/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1249,6 +1249,12 @@
 	.udc_stop = fsl_udc_stop,
 };
 
+/*
+ * Empty complete function used by this driver to fill in the req->complete
+ * field when creating a request since the complete field is mandatory.
+ */
+static void fsl_noop_complete(struct usb_ep *ep, struct usb_request *req) { }
+
 /* Set protocol stall on ep0, protocol stall will automatically be cleared
    on new transaction */
 static void ep0stall(struct fsl_udc *udc)
@@ -1283,7 +1289,7 @@
 	req->req.length = 0;
 	req->req.status = -EINPROGRESS;
 	req->req.actual = 0;
-	req->req.complete = NULL;
+	req->req.complete = fsl_noop_complete;
 	req->dtd_count = 0;
 
 	ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
@@ -1304,7 +1310,7 @@
 {
 	struct fsl_ep *ep = get_ep_by_pipe(udc, pipe);
 
-	if (ep->name)
+	if (ep->ep.name)
 		nuke(ep, -ESHUTDOWN);
 }
 
@@ -1366,7 +1372,7 @@
 	req->req.length = 2;
 	req->req.status = -EINPROGRESS;
 	req->req.actual = 0;
-	req->req.complete = NULL;
+	req->req.complete = fsl_noop_complete;
 	req->dtd_count = 0;
 
 	ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
@@ -1692,7 +1698,7 @@
 		curr_ep = get_ep_by_pipe(udc, i);
 
 		/* If the ep is configured */
-		if (curr_ep->name == NULL) {
+		if (!curr_ep->ep.name) {
 			WARNING("Invalid EP?");
 			continue;
 		}
@@ -2564,7 +2570,7 @@
 	dma_pool_destroy(udc_controller->td_pool);
 	free_irq(udc_controller->irq, udc_controller);
 	iounmap(dr_regs);
-	if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
+	if (res && (pdata->operating_mode == FSL_USB2_DR_DEVICE))
 		release_mem_region(res->start, resource_size(res));
 
 	/* free udc --wait for the release() finished */
--- linux-4.4.0.orig/drivers/usb/gadget/udc/fusb300_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/fusb300_udc.c
@@ -1345,12 +1345,15 @@
 static int fusb300_remove(struct platform_device *pdev)
 {
 	struct fusb300 *fusb300 = platform_get_drvdata(pdev);
+	int i;
 
 	usb_del_gadget_udc(&fusb300->gadget);
 	iounmap(fusb300->reg);
 	free_irq(platform_get_irq(pdev, 0), fusb300);
 
 	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
+	for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
+		kfree(fusb300->ep[i]);
 	kfree(fusb300);
 
 	return 0;
@@ -1494,6 +1497,8 @@
 		if (fusb300->ep0_req)
 			fusb300_free_request(&fusb300->ep[0]->ep,
 				fusb300->ep0_req);
+		for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
+			kfree(fusb300->ep[i]);
 		kfree(fusb300);
 	}
 	if (reg)
--- linux-4.4.0.orig/drivers/usb/gadget/udc/goku_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/goku_udc.c
@@ -1773,6 +1773,7 @@
 		goto err;
 	}
 
+	pci_set_drvdata(pdev, dev);
 	spin_lock_init(&dev->lock);
 	dev->pdev = pdev;
 	dev->gadget.ops = &goku_ops;
@@ -1806,7 +1807,6 @@
 	}
 	dev->regs = (struct goku_udc_regs __iomem *) base;
 
-	pci_set_drvdata(pdev, dev);
 	INFO(dev, "%s\n", driver_desc);
 	INFO(dev, "version: " DRIVER_VERSION " %s\n", dmastr());
 	INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base);
--- linux-4.4.0.orig/drivers/usb/gadget/udc/goku_udc.h
+++ linux-4.4.0/drivers/usb/gadget/udc/goku_udc.h
@@ -28,7 +28,7 @@
 #	define INT_EP1DATASET		0x00040
 #	define INT_EP2DATASET		0x00080
 #	define INT_EP3DATASET		0x00100
-#define INT_EPnNAK(n)		(0x00100 < (n))		/* 0 < n < 4 */
+#define INT_EPnNAK(n)		(0x00100 << (n))	/* 0 < n < 4 */
 #	define INT_EP1NAK		0x00200
 #	define INT_EP2NAK		0x00400
 #	define INT_EP3NAK		0x00800
--- linux-4.4.0.orig/drivers/usb/gadget/udc/gr_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/gr_udc.c
@@ -2001,9 +2001,12 @@
 
 	if (num == 0) {
 		_req = gr_alloc_request(&ep->ep, GFP_ATOMIC);
+		if (!_req)
+			return -ENOMEM;
+
 		buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_ATOMIC);
-		if (!_req || !buf) {
-			/* possible _req freed by gr_probe via gr_remove */
+		if (!buf) {
+			gr_free_request(&ep->ep, _req);
 			return -ENOMEM;
 		}
 
@@ -2201,8 +2204,6 @@
 		return -ENOMEM;
 	}
 
-	spin_lock(&dev->lock);
-
 	/* Inside lock so that no gadget can use this udc until probe is done */
 	retval = usb_add_gadget_udc(dev->dev, &dev->gadget);
 	if (retval) {
@@ -2211,15 +2212,21 @@
 	}
 	dev->added = 1;
 
+	spin_lock(&dev->lock);
+
 	retval = gr_udc_init(dev);
-	if (retval)
+	if (retval) {
+		spin_unlock(&dev->lock);
 		goto out;
-
-	gr_dfs_create(dev);
+	}
 
 	/* Clear all interrupt enables that might be left on since last boot */
 	gr_disable_interrupts_and_pullup(dev);
 
+	spin_unlock(&dev->lock);
+
+	gr_dfs_create(dev);
+
 	retval = gr_request_irq(dev, dev->irq);
 	if (retval) {
 		dev_err(dev->dev, "Failed to request irq %d\n", dev->irq);
@@ -2248,8 +2255,6 @@
 		dev_info(dev->dev, "regs: %p, irq %d\n", dev->regs, dev->irq);
 
 out:
-	spin_unlock(&dev->lock);
-
 	if (retval)
 		gr_remove(pdev);
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -964,8 +964,7 @@
 	dma_addr_t			dma;
 	struct lpc32xx_usbd_dd_gad	*dd;
 
-	dd = (struct lpc32xx_usbd_dd_gad *) dma_pool_alloc(
-			udc->dd_cache, (GFP_KERNEL | GFP_DMA), &dma);
+	dd = dma_pool_alloc(udc->dd_cache, GFP_ATOMIC | GFP_DMA, &dma);
 	if (dd)
 		dd->this_dma = dma;
 
@@ -1226,11 +1225,11 @@
 			tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
 
 			bl = bytes - n;
-			if (bl > 3)
-				bl = 3;
+			if (bl > 4)
+				bl = 4;
 
 			for (i = 0; i < bl; i++)
-				data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF);
+				data[n + i] = (u8) ((tmp >> (i * 8)) & 0xFF);
 		}
 		break;
 
@@ -1663,17 +1662,17 @@
 			     const struct usb_endpoint_descriptor *desc)
 {
 	struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
-	struct lpc32xx_udc *udc = ep->udc;
+	struct lpc32xx_udc *udc;
 	u16 maxpacket;
 	u32 tmp;
 	unsigned long flags;
 
 	/* Verify EP data */
 	if ((!_ep) || (!ep) || (!desc) ||
-	    (desc->bDescriptorType != USB_DT_ENDPOINT)) {
-		dev_dbg(udc->dev, "bad ep or descriptor\n");
+	    (desc->bDescriptorType != USB_DT_ENDPOINT))
 		return -EINVAL;
-	}
+
+	udc = ep->udc;
 	maxpacket = usb_endpoint_maxp(desc);
 	if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) {
 		dev_dbg(udc->dev, "bad ep descriptor's packet size\n");
@@ -1921,7 +1920,7 @@
 static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value)
 {
 	struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
-	struct lpc32xx_udc *udc = ep->udc;
+	struct lpc32xx_udc *udc;
 	unsigned long flags;
 
 	if ((!ep) || (ep->hwep_num <= 1))
@@ -1931,6 +1930,7 @@
 	if (ep->is_in)
 		return -EAGAIN;
 
+	udc = ep->udc;
 	spin_lock_irqsave(&udc->lock, flags);
 
 	if (value == 1) {
--- linux-4.4.0.orig/drivers/usb/gadget/udc/m66592-udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/m66592-udc.c
@@ -1684,7 +1684,7 @@
 
 err_add_udc:
 	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
-
+	m66592->ep0_req = NULL;
 clean_up3:
 	if (m66592->pdata->on_chip) {
 		clk_disable(m66592->clk);
--- linux-4.4.0.orig/drivers/usb/gadget/udc/mv_udc_core.c
+++ linux-4.4.0/drivers/usb/gadget/udc/mv_udc_core.c
@@ -2322,7 +2322,8 @@
 	return 0;
 
 err_create_workqueue:
-	destroy_workqueue(udc->qwork);
+	if (udc->qwork)
+		destroy_workqueue(udc->qwork);
 err_destroy_dma:
 	dma_pool_destroy(udc->dtd_pool);
 err_free_dma:
--- linux-4.4.0.orig/drivers/usb/gadget/udc/net2272.c
+++ linux-4.4.0/drivers/usb/gadget/udc/net2272.c
@@ -962,6 +962,7 @@
 			break;
 	}
 	if (&req->req != _req) {
+		ep->stopped = stopped;
 		spin_unlock_irqrestore(&ep->dev->lock, flags);
 		return -EINVAL;
 	}
@@ -2100,7 +2101,7 @@
 #if defined(PLX_PCI_RDK2)
 	/* see if PCI int for us by checking irqstat */
 	intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT);
-	if (!intcsr & (1 << NET2272_PCI_IRQ)) {
+	if (!(intcsr & (1 << NET2272_PCI_IRQ))) {
 		spin_unlock(&dev->lock);
 		return IRQ_NONE;
 	}
@@ -2669,6 +2670,8 @@
  err_req:
 	release_mem_region(base, len);
  err:
+	kfree(dev);
+
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/net2280.c
+++ linux-4.4.0/drivers/usb/gadget/udc/net2280.c
@@ -870,9 +870,6 @@
 	(void) readl(&ep->dev->pci->pcimstctl);
 
 	writel(BIT(DMA_START), &dma->dmastat);
-
-	if (!ep->is_in)
-		stop_out_naking(ep);
 }
 
 static void start_dma(struct net2280_ep *ep, struct net2280_request *req)
@@ -911,6 +908,7 @@
 			writel(BIT(DMA_START), &dma->dmastat);
 			return;
 		}
+		stop_out_naking(ep);
 	}
 
 	tmp = dmactl_default;
@@ -1272,9 +1270,9 @@
 			break;
 	}
 	if (&req->req != _req) {
+		ep->stopped = stopped;
 		spin_unlock_irqrestore(&ep->dev->lock, flags);
-		dev_err(&ep->dev->pdev->dev, "%s: Request mismatch\n",
-								__func__);
+		ep_dbg(ep->dev, "%s: Request mismatch\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1542,11 +1540,14 @@
 		writel(tmp | BIT(USB_DETECT_ENABLE), &dev->usb->usbctl);
 	} else {
 		writel(tmp & ~BIT(USB_DETECT_ENABLE), &dev->usb->usbctl);
-		stop_activity(dev, dev->driver);
+		stop_activity(dev, NULL);
 	}
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
+	if (!is_on && dev->driver)
+		dev->driver->disconnect(&dev->gadget);
+
 	return 0;
 }
 
@@ -3343,6 +3344,7 @@
 	tmp = BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT);
 	if (stat & tmp) {
 		writel(tmp, &dev->regs->irqstat1);
+		spin_unlock(&dev->lock);
 		if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) {
 			if (dev->driver->suspend)
 				dev->driver->suspend(&dev->gadget);
@@ -3353,6 +3355,7 @@
 				dev->driver->resume(&dev->gadget);
 			/* at high speed, note erratum 0133 */
 		}
+		spin_lock(&dev->lock);
 		stat &= ~tmp;
 	}
 
@@ -3709,8 +3712,10 @@
 	return 0;
 
 done:
-	if (dev)
+	if (dev) {
 		net2280_remove(pdev);
+		kfree(dev);
+	}
 	return retval;
 }
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/omap_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/omap_udc.c
@@ -2037,6 +2037,7 @@
 {
 	return machine_is_omap_innovator()
 		|| machine_is_omap_osk()
+		|| machine_is_omap_palmte()
 		|| machine_is_sx1()
 		/* No known omap7xx boards with vbus sense */
 		|| cpu_is_omap7xx();
@@ -2045,7 +2046,7 @@
 static int omap_udc_start(struct usb_gadget *g,
 		struct usb_gadget_driver *driver)
 {
-	int		status = -ENODEV;
+	int		status;
 	struct omap_ep	*ep;
 	unsigned long	flags;
 
@@ -2083,6 +2084,7 @@
 			goto done;
 		}
 	} else {
+		status = 0;
 		if (can_pullup(udc))
 			pullup_enable(udc);
 		else
@@ -2612,9 +2614,22 @@
 
 static void omap_udc_release(struct device *dev)
 {
-	complete(udc->done);
+	pullup_disable(udc);
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
+		usb_put_phy(udc->transceiver);
+		udc->transceiver = NULL;
+	}
+	omap_writew(0, UDC_SYSCON1);
+	remove_proc_file();
+	if (udc->dc_clk) {
+		if (udc->clk_requested)
+			omap_udc_enable_clock(0);
+		clk_put(udc->hhc_clk);
+		clk_put(udc->dc_clk);
+	}
+	if (udc->done)
+		complete(udc->done);
 	kfree(udc);
-	udc = NULL;
 }
 
 static int
@@ -2886,8 +2901,8 @@
 		udc->clr_halt = UDC_RESET_EP;
 
 	/* USB general purpose IRQ:  ep0, state changes, dma, etc */
-	status = request_irq(pdev->resource[1].start, omap_udc_irq,
-			0, driver_name, udc);
+	status = devm_request_irq(&pdev->dev, pdev->resource[1].start,
+				  omap_udc_irq, 0, driver_name, udc);
 	if (status != 0) {
 		ERR("can't get irq %d, err %d\n",
 			(int) pdev->resource[1].start, status);
@@ -2895,20 +2910,20 @@
 	}
 
 	/* USB "non-iso" IRQ (PIO for all but ep0) */
-	status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,
-			0, "omap_udc pio", udc);
+	status = devm_request_irq(&pdev->dev, pdev->resource[2].start,
+				  omap_udc_pio_irq, 0, "omap_udc pio", udc);
 	if (status != 0) {
 		ERR("can't get irq %d, err %d\n",
 			(int) pdev->resource[2].start, status);
-		goto cleanup2;
+		goto cleanup1;
 	}
 #ifdef	USE_ISO
-	status = request_irq(pdev->resource[3].start, omap_udc_iso_irq,
-			0, "omap_udc iso", udc);
+	status = devm_request_irq(&pdev->dev, pdev->resource[3].start,
+				  omap_udc_iso_irq, 0, "omap_udc iso", udc);
 	if (status != 0) {
 		ERR("can't get irq %d, err %d\n",
 			(int) pdev->resource[3].start, status);
-		goto cleanup3;
+		goto cleanup1;
 	}
 #endif
 	if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
@@ -2919,23 +2934,8 @@
 	}
 
 	create_proc_file();
-	status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
-			omap_udc_release);
-	if (status)
-		goto cleanup4;
-
-	return 0;
-
-cleanup4:
-	remove_proc_file();
-
-#ifdef	USE_ISO
-cleanup3:
-	free_irq(pdev->resource[2].start, udc);
-#endif
-
-cleanup2:
-	free_irq(pdev->resource[1].start, udc);
+	return usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
+					  omap_udc_release);
 
 cleanup1:
 	kfree(udc);
@@ -2962,42 +2962,15 @@
 {
 	DECLARE_COMPLETION_ONSTACK(done);
 
-	if (!udc)
-		return -ENODEV;
-
-	usb_del_gadget_udc(&udc->gadget);
-	if (udc->driver)
-		return -EBUSY;
-
 	udc->done = &done;
 
-	pullup_disable(udc);
-	if (!IS_ERR_OR_NULL(udc->transceiver)) {
-		usb_put_phy(udc->transceiver);
-		udc->transceiver = NULL;
-	}
-	omap_writew(0, UDC_SYSCON1);
-
-	remove_proc_file();
-
-#ifdef	USE_ISO
-	free_irq(pdev->resource[3].start, udc);
-#endif
-	free_irq(pdev->resource[2].start, udc);
-	free_irq(pdev->resource[1].start, udc);
+	usb_del_gadget_udc(&udc->gadget);
 
-	if (udc->dc_clk) {
-		if (udc->clk_requested)
-			omap_udc_enable_clock(0);
-		clk_put(udc->hhc_clk);
-		clk_put(udc->dc_clk);
-	}
+	wait_for_completion(&done);
 
 	release_mem_region(pdev->resource[0].start,
 			pdev->resource[0].end - pdev->resource[0].start + 1);
 
-	wait_for_completion(&done);
-
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/pch_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/pch_udc.c
@@ -1488,11 +1488,11 @@
 		req->dma_mapped = 0;
 	}
 	ep->halted = 1;
-	spin_lock(&dev->lock);
+	spin_unlock(&dev->lock);
 	if (!ep->in)
 		pch_udc_ep_clear_rrdy(ep);
 	usb_gadget_giveback_request(&ep->ep, &req->req);
-	spin_unlock(&dev->lock);
+	spin_lock(&dev->lock);
 	ep->halted = halted;
 }
 
@@ -1534,7 +1534,6 @@
 		td = phys_to_virt(addr);
 		addr2 = (dma_addr_t)td->next;
 		pci_pool_free(dev->data_requests, td, addr);
-		td->next = 0x00;
 		addr = addr2;
 	}
 	req->chain_len = 1;
@@ -1732,14 +1731,12 @@
 static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
 {
 	struct pch_udc_ep	*ep;
-	struct pch_udc_dev	*dev;
 	unsigned long	iflags;
 
 	if (!usbep)
 		return -EINVAL;
 
 	ep = container_of(usbep, struct pch_udc_ep, ep);
-	dev = ep->dev;
 	if ((usbep->name == ep0_string) || !ep->ep.desc)
 		return -EINVAL;
 
@@ -1770,12 +1767,10 @@
 	struct pch_udc_request		*req;
 	struct pch_udc_ep		*ep;
 	struct pch_udc_data_dma_desc	*dma_desc;
-	struct pch_udc_dev		*dev;
 
 	if (!usbep)
 		return NULL;
 	ep = container_of(usbep, struct pch_udc_ep, ep);
-	dev = ep->dev;
 	req = kzalloc(sizeof *req, gfp);
 	if (!req)
 		return NULL;
@@ -1948,12 +1943,10 @@
 {
 	struct pch_udc_ep	*ep;
 	struct pch_udc_request	*req;
-	struct pch_udc_dev	*dev;
 	unsigned long		flags;
 	int ret = -EINVAL;
 
 	ep = container_of(usbep, struct pch_udc_ep, ep);
-	dev = ep->dev;
 	if (!usbep || !usbreq || (!ep->ep.desc && ep->num))
 		return ret;
 	req = container_of(usbreq, struct pch_udc_request, req);
@@ -1985,14 +1978,12 @@
 static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
 {
 	struct pch_udc_ep	*ep;
-	struct pch_udc_dev	*dev;
 	unsigned long iflags;
 	int ret;
 
 	if (!usbep)
 		return -EINVAL;
 	ep = container_of(usbep, struct pch_udc_ep, ep);
-	dev = ep->dev;
 	if (!ep->ep.desc && !ep->num)
 		return -EINVAL;
 	if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
@@ -2030,14 +2021,12 @@
 static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
 {
 	struct pch_udc_ep	*ep;
-	struct pch_udc_dev	*dev;
 	unsigned long iflags;
 	int ret;
 
 	if (!usbep)
 		return -EINVAL;
 	ep = container_of(usbep, struct pch_udc_ep, ep);
-	dev = ep->dev;
 	if (!ep->ep.desc && !ep->num)
 		return -EINVAL;
 	if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
@@ -2594,9 +2583,9 @@
 		empty_req_queue(ep);
 	}
 	if (dev->driver) {
-		spin_lock(&dev->lock);
-		usb_gadget_udc_reset(&dev->gadget, dev->driver);
 		spin_unlock(&dev->lock);
+		usb_gadget_udc_reset(&dev->gadget, dev->driver);
+		spin_lock(&dev->lock);
 	}
 }
 
@@ -2647,7 +2636,7 @@
 static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
 {
 	u32 reg, dev_stat = 0;
-	int i, ret;
+	int i;
 
 	dev_stat = pch_udc_read_device_status(dev);
 	dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
@@ -2675,9 +2664,9 @@
 		dev->ep[i].halted = 0;
 	}
 	dev->stall = 0;
-	spin_lock(&dev->lock);
-	ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
 	spin_unlock(&dev->lock);
+	dev->driver->setup(&dev->gadget, &dev->setup_data);
+	spin_lock(&dev->lock);
 }
 
 /**
@@ -2687,7 +2676,7 @@
  */
 static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
 {
-	int i, ret;
+	int i;
 	u32 reg, dev_stat = 0;
 
 	dev_stat = pch_udc_read_device_status(dev);
@@ -2712,9 +2701,9 @@
 	dev->stall = 0;
 
 	/* call gadget zero with setup data received */
-	spin_lock(&dev->lock);
-	ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
 	spin_unlock(&dev->lock);
+	dev->driver->setup(&dev->gadget, &dev->setup_data);
+	spin_lock(&dev->lock);
 }
 
 /**
--- linux-4.4.0.orig/drivers/usb/gadget/udc/r8a66597-udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/r8a66597-udc.c
@@ -835,11 +835,11 @@
 
 		r8a66597_bset(r8a66597, XCKE, SYSCFG0);
 
-		msleep(3);
+		mdelay(3);
 
 		r8a66597_bset(r8a66597, PLLC, SYSCFG0);
 
-		msleep(1);
+		mdelay(1);
 
 		r8a66597_bset(r8a66597, SCKE, SYSCFG0);
 
@@ -1193,7 +1193,7 @@
 	r8a66597->ep0_req->length = 2;
 	/* AV: what happens if we get called again before that gets through? */
 	spin_unlock(&r8a66597->lock);
-	r8a66597_queue(r8a66597->gadget.ep0, r8a66597->ep0_req, GFP_KERNEL);
+	r8a66597_queue(r8a66597->gadget.ep0, r8a66597->ep0_req, GFP_ATOMIC);
 	spin_lock(&r8a66597->lock);
 }
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/s3c2410_udc.c
+++ linux-4.4.0/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -269,10 +269,6 @@
 static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
 		struct s3c2410_ep *ep, int status)
 {
-	/* Sanity check */
-	if (&ep->queue == NULL)
-		return;
-
 	while (!list_empty(&ep->queue)) {
 		struct s3c2410_request *req;
 		req = list_entry(ep->queue.next, struct s3c2410_request,
--- linux-4.4.0.orig/drivers/usb/gadget/udc/udc-core.c
+++ linux-4.4.0/drivers/usb/gadget/udc/udc-core.c
@@ -71,7 +71,7 @@
 		mapped = dma_map_sg(dev, req->sg, req->num_sgs,
 				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 		if (mapped == 0) {
-			dev_err(&gadget->dev, "failed to map SGs\n");
+			dev_err(dev, "failed to map SGs\n");
 			return -EFAULT;
 		}
 
@@ -97,7 +97,7 @@
 		return;
 
 	if (req->num_mapped_sgs) {
-		dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs,
+		dma_unmap_sg(gadget->dev.parent, req->sg, req->num_sgs,
 				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 
 		req->num_mapped_sgs = 0;
@@ -451,7 +451,6 @@
 	usb_gadget_udc_stop(udc);
 
 	udc->driver = NULL;
-	udc->dev.driver = NULL;
 	udc->gadget->dev.driver = NULL;
 }
 
@@ -495,7 +494,6 @@
 			driver->function);
 
 	udc->driver = driver;
-	udc->dev.driver = &driver->driver;
 	udc->gadget->dev.driver = &driver->driver;
 
 	ret = driver->bind(udc->gadget, driver);
@@ -515,7 +513,6 @@
 		dev_err(&udc->dev, "failed to start %s: %d\n",
 			udc->driver->function, ret);
 	udc->driver = NULL;
-	udc->dev.driver = NULL;
 	udc->gadget->dev.driver = NULL;
 	return ret;
 }
@@ -612,10 +609,13 @@
 		struct device_attribute *attr, const char *buf, size_t n)
 {
 	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev);
+	ssize_t			ret;
 
+	mutex_lock(&udc_lock);
 	if (!udc->driver) {
 		dev_err(dev, "soft-connect without a gadget driver\n");
-		return -EOPNOTSUPP;
+		ret = -EOPNOTSUPP;
+		goto out;
 	}
 
 	if (sysfs_streq(buf, "connect")) {
@@ -627,10 +627,14 @@
 		usb_gadget_udc_stop(udc);
 	} else {
 		dev_err(dev, "unsupported command '%s'\n", buf);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
-	return n;
+	ret = n;
+out:
+	mutex_unlock(&udc_lock);
+	return ret;
 }
 static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
 
--- linux-4.4.0.orig/drivers/usb/gadget/udc/udc-xilinx.c
+++ linux-4.4.0/drivers/usb/gadget/udc/udc-xilinx.c
@@ -1622,6 +1622,8 @@
 		break;
 	case USB_RECIP_ENDPOINT:
 		epnum = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
+		if (epnum >= XUSB_MAX_ENDPOINTS)
+			goto stall;
 		target_ep = &udc->ep[epnum];
 		epcfgreg = udc->read_fn(udc->addr + target_ep->offset);
 		halt = epcfgreg & XUSB_EP_CFG_STALL_MASK;
@@ -1689,6 +1691,10 @@
 	case USB_RECIP_ENDPOINT:
 		if (!udc->setup.wValue) {
 			endpoint = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
+			if (endpoint >= XUSB_MAX_ENDPOINTS) {
+				xudc_ep0_stall(udc);
+				return;
+			}
 			target_ep = &udc->ep[endpoint];
 			outinbit = udc->setup.wIndex & USB_ENDPOINT_DIR_MASK;
 			outinbit = outinbit >> 7;
--- linux-4.4.0.orig/drivers/usb/host/Kconfig
+++ linux-4.4.0/drivers/usb/host/Kconfig
@@ -220,6 +220,8 @@
        depends on ARCH_TEGRA
        select USB_EHCI_ROOT_HUB_TT
        select USB_PHY
+	select USB_ULPI
+	select USB_ULPI_VIEWPORT
        help
          This driver enables support for the internal USB Host Controllers
          found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
--- linux-4.4.0.orig/drivers/usb/host/ehci-dbg.c
+++ linux-4.4.0/drivers/usb/host/ehci-dbg.c
@@ -851,7 +851,7 @@
 			default:		/* unknown */
 				break;
 			}
-			temp = (cap >> 8) & 0xff;
+			offset = (cap >> 8) & 0xff;
 		}
 	}
 #endif
--- linux-4.4.0.orig/drivers/usb/host/ehci-exynos.c
+++ linux-4.4.0/drivers/usb/host/ehci-exynos.c
@@ -77,10 +77,12 @@
 		if (IS_ERR(phy)) {
 			ret = PTR_ERR(phy);
 			if (ret == -EPROBE_DEFER) {
+				of_node_put(child);
 				return ret;
 			} else if (ret != -ENOSYS && ret != -ENODEV) {
 				dev_err(dev,
 					"Error retrieving usb2 phy: %d\n", ret);
+				of_node_put(child);
 				return ret;
 			}
 		}
@@ -197,9 +199,8 @@
 	hcd->rsrc_len = resource_size(res);
 
 	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		dev_err(&pdev->dev, "Failed to get IRQ\n");
-		err = -ENODEV;
+	if (irq < 0) {
+		err = irq;
 		goto fail_io;
 	}
 
--- linux-4.4.0.orig/drivers/usb/host/ehci-hcd.c
+++ linux-4.4.0/drivers/usb/host/ehci-hcd.c
@@ -35,6 +35,7 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/debugfs.h>
@@ -332,11 +333,11 @@
 	int	port = HCS_N_PORTS(ehci->hcs_params);
 
 	while (port--) {
-		ehci_writel(ehci, PORT_RWC_BITS,
-				&ehci->regs->port_status[port]);
 		spin_unlock_irq(&ehci->lock);
 		ehci_port_power(ehci, port, false);
 		spin_lock_irq(&ehci->lock);
+		ehci_writel(ehci, PORT_RWC_BITS,
+				&ehci->regs->port_status[port]);
 	}
 }
 
@@ -574,6 +575,7 @@
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
 	u32			hcc_params;
+	int			rc;
 
 	hcd->uses_new_polling = 1;
 
@@ -629,9 +631,20 @@
 	down_write(&ehci_cf_port_reset_rwsem);
 	ehci->rh_state = EHCI_RH_RUNNING;
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+
+	/* Wait until HC become operational */
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 	msleep(5);
+	rc = ehci_handshake(ehci, &ehci->regs->status, STS_HALT, 0, 100 * 1000);
+
 	up_write(&ehci_cf_port_reset_rwsem);
+
+	if (rc) {
+		ehci_err(ehci, "USB %x.%x, controller refused to start: %d\n",
+			 ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), rc);
+		return rc;
+	}
+
 	ehci->last_periodic_enable = ktime_get_real();
 
 	temp = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
--- linux-4.4.0.orig/drivers/usb/host/ehci-hub.c
+++ linux-4.4.0/drivers/usb/host/ehci-hub.c
@@ -27,7 +27,6 @@
  */
 
 /*-------------------------------------------------------------------------*/
-#include <linux/usb/otg.h>
 
 #define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
 
--- linux-4.4.0.orig/drivers/usb/host/ehci-mv.c
+++ linux-4.4.0/drivers/usb/host/ehci-mv.c
@@ -196,12 +196,10 @@
 	hcd->rsrc_len = resource_size(r);
 	hcd->regs = ehci_mv->op_regs;
 
-	hcd->irq = platform_get_irq(pdev, 0);
-	if (!hcd->irq) {
-		dev_err(&pdev->dev, "Cannot get irq.");
-		retval = -ENODEV;
+	retval = platform_get_irq(pdev, 0);
+	if (retval < 0)
 		goto err_disable_clk;
-	}
+	hcd->irq = retval;
 
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
--- linux-4.4.0.orig/drivers/usb/host/ehci-mxc.c
+++ linux-4.4.0/drivers/usb/host/ehci-mxc.c
@@ -63,6 +63,8 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
 
 	hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev));
 	if (!hcd)
--- linux-4.4.0.orig/drivers/usb/host/ehci-omap.c
+++ linux-4.4.0/drivers/usb/host/ehci-omap.c
@@ -130,8 +130,8 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(dev, "EHCI irq failed\n");
-		return -ENODEV;
+		dev_err(dev, "EHCI irq failed: %d\n", irq);
+		return irq;
 	}
 
 	res =  platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -237,6 +237,7 @@
 
 err_pm_runtime:
 	pm_runtime_put_sync(dev);
+	pm_runtime_disable(dev);
 
 err_phy:
 	for (i = 0; i < omap->nports; i++) {
--- linux-4.4.0.orig/drivers/usb/host/ehci-pci.c
+++ linux-4.4.0/drivers/usb/host/ehci-pci.c
@@ -229,6 +229,13 @@
 		ehci_info(ehci, "applying MosChip frame-index workaround\n");
 		ehci->frame_index_bug = 1;
 		break;
+	case PCI_VENDOR_ID_HUAWEI:
+		/* Synopsys HC bug */
+		if (pdev->device == 0xa239) {
+			ehci_info(ehci, "applying Synopsys HC workaround\n");
+			ehci->has_synopsys_hc_bug = 1;
+		}
+		break;
 	}
 
 	/* optional debug port, normally in the first BAR */
--- linux-4.4.0.orig/drivers/usb/host/ehci-q.c
+++ linux-4.4.0/drivers/usb/host/ehci-q.c
@@ -40,6 +40,10 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* PID Codes that are used here, from EHCI specification, Table 3-16. */
+#define PID_CODE_IN    1
+#define PID_CODE_SETUP 2
+
 /* fill a qtd, returning how much of the buffer we were able to queue up */
 
 static int
@@ -199,7 +203,7 @@
 	int	status = -EINPROGRESS;
 
 	/* count IN/OUT bytes, not SETUP (even short packets) */
-	if (likely (QTD_PID (token) != 2))
+	if (likely(QTD_PID(token) != PID_CODE_SETUP))
 		urb->actual_length += length - QTD_LENGTH (token);
 
 	/* don't modify error codes */
@@ -215,6 +219,13 @@
 		if (token & QTD_STS_BABBLE) {
 			/* FIXME "must" disable babbling device's port too */
 			status = -EOVERFLOW;
+		/*
+		 * When MMF is active and PID Code is IN, queue is halted.
+		 * EHCI Specification, Table 4-13.
+		 */
+		} else if ((token & QTD_STS_MMF) &&
+					(QTD_PID(token) == PID_CODE_IN)) {
+			status = -EPROTO;
 		/* CERR nonzero + halt --> stall */
 		} else if (QTD_CERR(token)) {
 			status = -EPIPE;
--- linux-4.4.0.orig/drivers/usb/host/ehci-tegra.c
+++ linux-4.4.0/drivers/usb/host/ehci-tegra.c
@@ -89,7 +89,7 @@
 	if (!usb1_reset_attempted) {
 		struct reset_control *usb1_reset;
 
-		usb1_reset = of_reset_control_get(phy_np, "usb");
+		usb1_reset = of_reset_control_get(phy_np, "utmi-pads");
 		if (IS_ERR(usb1_reset)) {
 			dev_warn(&pdev->dev,
 				 "can't get utmi-pads reset from the PHY\n");
--- linux-4.4.0.orig/drivers/usb/host/fotg210-hcd.c
+++ linux-4.4.0/drivers/usb/host/fotg210-hcd.c
@@ -1653,6 +1653,10 @@
 			/* see what we found out */
 			temp = check_reset_complete(fotg210, wIndex, status_reg,
 					fotg210_readl(fotg210, status_reg));
+
+			/* restart schedule */
+			fotg210->command |= CMD_RUN;
+			fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
 		}
 
 		if (!(temp & (PORT_RESUME|PORT_RESET))) {
--- linux-4.4.0.orig/drivers/usb/host/hwa-hc.c
+++ linux-4.4.0/drivers/usb/host/hwa-hc.c
@@ -173,7 +173,7 @@
 	return result;
 
 error_set_cluster_id:
-	wusb_cluster_id_put(wusbhc->cluster_id);
+	wusb_cluster_id_put(addr);
 error_cluster_id_get:
 	goto out;
 
@@ -654,7 +654,7 @@
 	top = itr + itr_size;
 	result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
 			le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
-			USB_DT_SECURITY, (void **) &secd);
+			USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
 	if (result == -1) {
 		dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
 		return 0;
--- linux-4.4.0.orig/drivers/usb/host/imx21-hcd.c
+++ linux-4.4.0/drivers/usb/host/imx21-hcd.c
@@ -1849,8 +1849,10 @@
 	if (!res)
 		return -ENODEV;
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return -ENXIO;
+	if (irq < 0) {
+		dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
+		return irq;
+	}
 
 	hcd = usb_create_hcd(&imx21_hc_driver,
 		&pdev->dev, dev_name(&pdev->dev));
--- linux-4.4.0.orig/drivers/usb/host/max3421-hcd.c
+++ linux-4.4.0/drivers/usb/host/max3421-hcd.c
@@ -149,8 +149,6 @@
 	 */
 	struct urb *curr_urb;
 	enum scheduling_pass sched_pass;
-	struct usb_device *loaded_dev;	/* dev that's loaded into the chip */
-	int loaded_epnum;		/* epnum whose toggles are loaded */
 	int urb_done;			/* > 0 -> no errors, < 0: errno */
 	size_t curr_len;
 	u8 hien;
@@ -488,39 +486,17 @@
  * Caller must NOT hold HCD spinlock.
  */
 static void
-max3421_set_address(struct usb_hcd *hcd, struct usb_device *dev, int epnum,
-		    int force_toggles)
+max3421_set_address(struct usb_hcd *hcd, struct usb_device *dev, int epnum)
 {
-	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
-	int old_epnum, same_ep, rcvtog, sndtog;
-	struct usb_device *old_dev;
+	int rcvtog, sndtog;
 	u8 hctl;
 
-	old_dev = max3421_hcd->loaded_dev;
-	old_epnum = max3421_hcd->loaded_epnum;
-
-	same_ep = (dev == old_dev && epnum == old_epnum);
-	if (same_ep && !force_toggles)
-		return;
-
-	if (old_dev && !same_ep) {
-		/* save the old end-points toggles: */
-		u8 hrsl = spi_rd8(hcd, MAX3421_REG_HRSL);
-
-		rcvtog = (hrsl >> MAX3421_HRSL_RCVTOGRD_BIT) & 1;
-		sndtog = (hrsl >> MAX3421_HRSL_SNDTOGRD_BIT) & 1;
-
-		/* no locking: HCD (i.e., we) own toggles, don't we? */
-		usb_settoggle(old_dev, old_epnum, 0, rcvtog);
-		usb_settoggle(old_dev, old_epnum, 1, sndtog);
-	}
 	/* setup new endpoint's toggle bits: */
 	rcvtog = usb_gettoggle(dev, epnum, 0);
 	sndtog = usb_gettoggle(dev, epnum, 1);
 	hctl = (BIT(rcvtog + MAX3421_HCTL_RCVTOG0_BIT) |
 		BIT(sndtog + MAX3421_HCTL_SNDTOG0_BIT));
 
-	max3421_hcd->loaded_epnum = epnum;
 	spi_wr8(hcd, MAX3421_REG_HCTL, hctl);
 
 	/*
@@ -528,7 +504,6 @@
 	 * address-assignment so it's best to just always load the
 	 * address whenever the end-point changed/was forced.
 	 */
-	max3421_hcd->loaded_dev = dev;
 	spi_wr8(hcd, MAX3421_REG_PERADDR, dev->devnum);
 }
 
@@ -663,7 +638,7 @@
 	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
 	struct urb *urb, *curr_urb = NULL;
 	struct max3421_ep *max3421_ep;
-	int epnum, force_toggles = 0;
+	int epnum;
 	struct usb_host_endpoint *ep;
 	struct list_head *pos;
 	unsigned long flags;
@@ -773,7 +748,6 @@
 			usb_settoggle(urb->dev, epnum, 0, 1);
 			usb_settoggle(urb->dev, epnum, 1, 1);
 			max3421_ep->pkt_state = PKT_STATE_SETUP;
-			force_toggles = 1;
 		} else
 			max3421_ep->pkt_state = PKT_STATE_TRANSFER;
 	}
@@ -781,7 +755,7 @@
 	spin_unlock_irqrestore(&max3421_hcd->lock, flags);
 
 	max3421_ep->last_active = max3421_hcd->frame_number;
-	max3421_set_address(hcd, urb->dev, epnum, force_toggles);
+	max3421_set_address(hcd, urb->dev, epnum);
 	max3421_set_speed(hcd, urb->dev);
 	max3421_next_transfer(hcd, 0);
 	return 1;
@@ -1382,6 +1356,16 @@
 		status = 0;
 	urb = max3421_hcd->curr_urb;
 	if (urb) {
+		/* save the old end-points toggles: */
+		u8 hrsl = spi_rd8(hcd, MAX3421_REG_HRSL);
+		int rcvtog = (hrsl >> MAX3421_HRSL_RCVTOGRD_BIT) & 1;
+		int sndtog = (hrsl >> MAX3421_HRSL_SNDTOGRD_BIT) & 1;
+		int epnum = usb_endpoint_num(&urb->ep->desc);
+
+		/* no locking: HCD (i.e., we) own toggles, don't we? */
+		usb_settoggle(urb->dev, epnum, 0, rcvtog);
+		usb_settoggle(urb->dev, epnum, 1, sndtog);
+
 		max3421_hcd->curr_urb = NULL;
 		spin_lock_irqsave(&max3421_hcd->lock, flags);
 		usb_hcd_unlink_urb_from_ep(hcd, urb);
--- linux-4.4.0.orig/drivers/usb/host/ohci-exynos.c
+++ linux-4.4.0/drivers/usb/host/ohci-exynos.c
@@ -66,10 +66,12 @@
 		if (IS_ERR(phy)) {
 			ret = PTR_ERR(phy);
 			if (ret == -EPROBE_DEFER) {
+				of_node_put(child);
 				return ret;
 			} else if (ret != -ENOSYS && ret != -ENODEV) {
 				dev_err(dev,
 					"Error retrieving usb2 phy: %d\n", ret);
+				of_node_put(child);
 				return ret;
 			}
 		}
@@ -164,9 +166,8 @@
 	hcd->rsrc_len = resource_size(res);
 
 	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		dev_err(&pdev->dev, "Failed to get IRQ\n");
-		err = -ENODEV;
+	if (irq < 0) {
+		err = irq;
 		goto fail_io;
 	}
 
--- linux-4.4.0.orig/drivers/usb/host/ohci-hcd.c
+++ linux-4.4.0/drivers/usb/host/ohci-hcd.c
@@ -72,7 +72,7 @@
 static const char	hcd_name [] = "ohci_hcd";
 
 #define	STATECHANGE_DELAY	msecs_to_jiffies(300)
-#define	IO_WATCHDOG_DELAY	msecs_to_jiffies(250)
+#define	IO_WATCHDOG_DELAY	msecs_to_jiffies(275)
 
 #include "ohci.h"
 #include "pci-quirks.h"
@@ -99,7 +99,7 @@
 
 
 /* Some boards misreport power switching/overcurrent */
-static bool distrust_firmware = 1;
+static bool distrust_firmware;
 module_param (distrust_firmware, bool, 0);
 MODULE_PARM_DESC (distrust_firmware,
 	"true to distrust firmware power/overcurrent setup");
@@ -415,8 +415,7 @@
  * other cases where the next software may expect clean state from the
  * "firmware".  this is bus-neutral, unlike shutdown() methods.
  */
-static void
-ohci_shutdown (struct usb_hcd *hcd)
+static void _ohci_shutdown(struct usb_hcd *hcd)
 {
 	struct ohci_hcd *ohci;
 
@@ -432,6 +431,16 @@
 	ohci->rh_state = OHCI_RH_HALTED;
 }
 
+static void ohci_shutdown(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ohci->lock, flags);
+	_ohci_shutdown(hcd);
+	spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -444,7 +453,8 @@
 	struct usb_hcd *hcd = ohci_to_hcd(ohci);
 
 	/* Accept arbitrarily long scatter-gather lists */
-	hcd->self.sg_tablesize = ~0;
+	if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+		hcd->self.sg_tablesize = ~0;
 
 	if (distrust_firmware)
 		ohci->flags |= OHCI_QUIRK_HUB_POWER;
@@ -653,20 +663,24 @@
 
 	/* handle root hub init quirks ... */
 	val = roothub_a (ohci);
-	val &= ~(RH_A_PSM | RH_A_OCPM);
+	/* Configure for per-port over-current protection by default */
+	val &= ~RH_A_NOCP;
+	val |= RH_A_OCPM;
 	if (ohci->flags & OHCI_QUIRK_SUPERIO) {
-		/* NSC 87560 and maybe others */
+		/* NSC 87560 and maybe others.
+		 * Ganged power switching, no over-current protection.
+		 */
 		val |= RH_A_NOCP;
-		val &= ~(RH_A_POTPGT | RH_A_NPS);
-		ohci_writel (ohci, val, &ohci->regs->roothub.a);
+		val &= ~(RH_A_POTPGT | RH_A_NPS | RH_A_PSM | RH_A_OCPM);
 	} else if ((ohci->flags & OHCI_QUIRK_AMD756) ||
 			(ohci->flags & OHCI_QUIRK_HUB_POWER)) {
 		/* hub power always on; required for AMD-756 and some
-		 * Mac platforms.  ganged overcurrent reporting, if any.
+		 * Mac platforms.
 		 */
 		val |= RH_A_NPS;
-		ohci_writel (ohci, val, &ohci->regs->roothub.a);
 	}
+	ohci_writel(ohci, val, &ohci->regs->roothub.a);
+
 	ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
 	ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM,
 						&ohci->regs->roothub.b);
@@ -749,7 +763,7 @@
  died:
 			usb_hc_died(ohci_to_hcd(ohci));
 			ohci_dump(ohci);
-			ohci_shutdown(ohci_to_hcd(ohci));
+			_ohci_shutdown(ohci_to_hcd(ohci));
 			goto done;
 		} else {
 			/* No write back because the done queue was empty */
--- linux-4.4.0.orig/drivers/usb/host/ohci-q.c
+++ linux-4.4.0/drivers/usb/host/ohci-q.c
@@ -183,7 +183,6 @@
 {
 	int	branch;
 
-	ed->state = ED_OPER;
 	ed->ed_prev = NULL;
 	ed->ed_next = NULL;
 	ed->hwNextED = 0;
@@ -259,6 +258,8 @@
 	/* the HC may not see the schedule updates yet, but if it does
 	 * then they'll be properly ordered.
 	 */
+
+	ed->state = ED_OPER;
 	return 0;
 }
 
@@ -1017,6 +1018,8 @@
 		 * have modified this list.  normally it's just prepending
 		 * entries (which we'd ignore), but paranoia won't hurt.
 		 */
+		*last = ed->ed_next;
+		ed->ed_next = NULL;
 		modified = 0;
 
 		/* unlink urbs as requested, but rescan the list after
@@ -1075,21 +1078,22 @@
 			goto rescan_this;
 
 		/*
-		 * If no TDs are queued, take ED off the ed_rm_list.
+		 * If no TDs are queued, ED is now idle.
 		 * Otherwise, if the HC is running, reschedule.
-		 * If not, leave it on the list for further dequeues.
+		 * If the HC isn't running, add ED back to the
+		 * start of the list for later processing.
 		 */
 		if (list_empty(&ed->td_list)) {
-			*last = ed->ed_next;
-			ed->ed_next = NULL;
 			ed->state = ED_IDLE;
 			list_del(&ed->in_use_list);
 		} else if (ohci->rh_state == OHCI_RH_RUNNING) {
-			*last = ed->ed_next;
-			ed->ed_next = NULL;
 			ed_schedule(ohci, ed);
 		} else {
-			last = &ed->ed_next;
+			ed->ed_next = ohci->ed_rm_list;
+			ohci->ed_rm_list = ed;
+			/* Don't loop on the same ED */
+			if (last == &ohci->ed_rm_list)
+				last = &ed->ed_next;
 		}
 
 		if (modified)
--- linux-4.4.0.orig/drivers/usb/host/ohci-sm501.c
+++ linux-4.4.0/drivers/usb/host/ohci-sm501.c
@@ -196,6 +196,7 @@
 	struct resource	*mem;
 
 	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	dma_release_declared_memory(&pdev->dev);
--- linux-4.4.0.orig/drivers/usb/host/oxu210hp-hcd.c
+++ linux-4.4.0/drivers/usb/host/oxu210hp-hcd.c
@@ -3741,8 +3741,10 @@
 	oxu->is_otg = otg;
 
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
-	if (ret < 0)
+	if (ret < 0) {
+		usb_put_hcd(hcd);
 		return ERR_PTR(ret);
+	}
 
 	device_wakeup_enable(hcd->self.controller);
 	return hcd;
--- linux-4.4.0.orig/drivers/usb/host/pci-quirks.c
+++ linux-4.4.0/drivers/usb/host/pci-quirks.c
@@ -78,6 +78,16 @@
 #define USB_INTEL_USB3_PSSEN   0xD8
 #define USB_INTEL_USB3PRM      0xDC
 
+/* ASMEDIA quirk use */
+#define ASMT_DATA_WRITE0_REG	0xF8
+#define ASMT_DATA_WRITE1_REG	0xFC
+#define ASMT_CONTROL_REG	0xE0
+#define ASMT_CONTROL_WRITE_BIT	0x02
+#define ASMT_WRITEREG_CMD	0x10423
+#define ASMT_FLOWCTL_ADDR	0xFA30
+#define ASMT_FLOWCTL_DATA	0xBA
+#define ASMT_PSEUDO_DATA	0
+
 /*
  * amd_chipset_gen values represent AMD different chipset generations
  */
@@ -89,6 +99,7 @@
 	AMD_CHIPSET_HUDSON2,
 	AMD_CHIPSET_BOLTON,
 	AMD_CHIPSET_YANGTZE,
+	AMD_CHIPSET_TAISHAN,
 	AMD_CHIPSET_UNKNOWN,
 };
 
@@ -136,20 +147,26 @@
 		pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
 				PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL);
 
-		if (!pinfo->smbus_dev) {
-			pinfo->sb_type.gen = NOT_AMD_CHIPSET;
-			return 0;
+		if (pinfo->smbus_dev) {
+			rev = pinfo->smbus_dev->revision;
+			if (rev >= 0x11 && rev <= 0x14)
+				pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2;
+			else if (rev >= 0x15 && rev <= 0x18)
+				pinfo->sb_type.gen = AMD_CHIPSET_BOLTON;
+			else if (rev >= 0x39 && rev <= 0x3a)
+				pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE;
+		} else {
+			pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+							  0x145c, NULL);
+			if (pinfo->smbus_dev) {
+				rev = pinfo->smbus_dev->revision;
+				pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN;
+			} else {
+				pinfo->sb_type.gen = NOT_AMD_CHIPSET;
+				return 0;
+			}
 		}
-
-		rev = pinfo->smbus_dev->revision;
-		if (rev >= 0x11 && rev <= 0x14)
-			pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2;
-		else if (rev >= 0x15 && rev <= 0x18)
-			pinfo->sb_type.gen = AMD_CHIPSET_BOLTON;
-		else if (rev >= 0x39 && rev <= 0x3a)
-			pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE;
 	}
-
 	pinfo->sb_type.rev = rev;
 	return 1;
 }
@@ -171,7 +188,7 @@
 {
 	unsigned long flags;
 	struct amd_chipset_info info;
-	int ret;
+	int need_pll_quirk = 0;
 
 	spin_lock_irqsave(&amd_lock, flags);
 
@@ -185,21 +202,28 @@
 	spin_unlock_irqrestore(&amd_lock, flags);
 
 	if (!amd_chipset_sb_type_init(&info)) {
-		ret = 0;
 		goto commit;
 	}
 
-	/* Below chipset generations needn't enable AMD PLL quirk */
-	if (info.sb_type.gen == AMD_CHIPSET_UNKNOWN ||
-			info.sb_type.gen == AMD_CHIPSET_SB600 ||
-			info.sb_type.gen == AMD_CHIPSET_YANGTZE ||
-			(info.sb_type.gen == AMD_CHIPSET_SB700 &&
-			info.sb_type.rev > 0x3b)) {
+	switch (info.sb_type.gen) {
+	case AMD_CHIPSET_SB700:
+		need_pll_quirk = info.sb_type.rev <= 0x3B;
+		break;
+	case AMD_CHIPSET_SB800:
+	case AMD_CHIPSET_HUDSON2:
+	case AMD_CHIPSET_BOLTON:
+		need_pll_quirk = 1;
+		break;
+	default:
+		need_pll_quirk = 0;
+		break;
+	}
+
+	if (!need_pll_quirk) {
 		if (info.smbus_dev) {
 			pci_dev_put(info.smbus_dev);
 			info.smbus_dev = NULL;
 		}
-		ret = 0;
 		goto commit;
 	}
 
@@ -218,7 +242,7 @@
 		}
 	}
 
-	ret = info.probe_result = 1;
+	need_pll_quirk = info.probe_result = 1;
 	printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
 
 commit:
@@ -229,7 +253,7 @@
 
 		/* Mark that we where here */
 		amd_chipset.probe_count++;
-		ret = amd_chipset.probe_result;
+		need_pll_quirk = amd_chipset.probe_result;
 
 		spin_unlock_irqrestore(&amd_lock, flags);
 
@@ -243,7 +267,7 @@
 		spin_unlock_irqrestore(&amd_lock, flags);
 	}
 
-	return ret;
+	return need_pll_quirk;
 }
 EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
 
@@ -251,11 +275,12 @@
 {
 	/* Make sure amd chipset type has already been initialized */
 	usb_amd_find_chipset_info();
-	if (amd_chipset.sb_type.gen != AMD_CHIPSET_YANGTZE)
-		return 0;
-
-	dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n");
-	return 1;
+	if (amd_chipset.sb_type.gen == AMD_CHIPSET_YANGTZE ||
+	    amd_chipset.sb_type.gen == AMD_CHIPSET_TAISHAN) {
+		dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n");
+		return 1;
+	}
+	return 0;
 }
 EXPORT_SYMBOL_GPL(usb_hcd_amd_remote_wakeup_quirk);
 
@@ -413,6 +438,50 @@
 }
 EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable);
 
+static int usb_asmedia_wait_write(struct pci_dev *pdev)
+{
+	unsigned long retry_count;
+	unsigned char value;
+
+	for (retry_count = 1000; retry_count > 0; --retry_count) {
+
+		pci_read_config_byte(pdev, ASMT_CONTROL_REG, &value);
+
+		if (value == 0xff) {
+			dev_err(&pdev->dev, "%s: check_ready ERROR", __func__);
+			return -EIO;
+		}
+
+		if ((value & ASMT_CONTROL_WRITE_BIT) == 0)
+			return 0;
+
+		usleep_range(40, 60);
+	}
+
+	dev_warn(&pdev->dev, "%s: check_write_ready timeout", __func__);
+	return -ETIMEDOUT;
+}
+
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev)
+{
+	if (usb_asmedia_wait_write(pdev) != 0)
+		return;
+
+	/* send command and address to device */
+	pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_WRITEREG_CMD);
+	pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_FLOWCTL_ADDR);
+	pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+
+	if (usb_asmedia_wait_write(pdev) != 0)
+		return;
+
+	/* send data to device */
+	pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_FLOWCTL_DATA);
+	pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_PSEUDO_DATA);
+	pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+}
+EXPORT_SYMBOL_GPL(usb_asmedia_modifyflowcontrol);
+
 void usb_amd_quirk_pll_enable(void)
 {
 	usb_amd_quirk_pll(0);
@@ -961,7 +1030,7 @@
  *
  * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
  * It signals to the BIOS that the OS wants control of the host controller,
- * and then waits 5 seconds for the BIOS to hand over control.
+ * and then waits 1 second for the BIOS to hand over control.
  * If we timeout, assume the BIOS is broken and take control anyway.
  */
 static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
@@ -1007,9 +1076,9 @@
 	if (val & XHCI_HC_BIOS_OWNED) {
 		writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
 
-		/* Wait for 5 seconds with 10 microsecond polling interval */
+		/* Wait for 1 second with 10 microsecond polling interval */
 		timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
-				0, 5000, 10);
+				0, 1000000, 10);
 
 		/* Assume a buggy BIOS and take HC ownership anyway */
 		if (timeout) {
@@ -1038,7 +1107,7 @@
 	 * operational or runtime registers.  Wait 5 seconds and no more.
 	 */
 	timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
-			5000, 10);
+			5000000, 10);
 	/* Assume a buggy HC and start HC initialization anyway */
 	if (timeout) {
 		val = readl(op_reg_base + XHCI_STS_OFFSET);
--- linux-4.4.0.orig/drivers/usb/host/pci-quirks.h
+++ linux-4.4.0/drivers/usb/host/pci-quirks.h
@@ -11,6 +11,7 @@
 void usb_amd_dev_put(void);
 void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev);
 void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
--- linux-4.4.0.orig/drivers/usb/host/r8a66597-hcd.c
+++ linux-4.4.0/drivers/usb/host/r8a66597-hcd.c
@@ -1269,7 +1269,7 @@
 			time = 30;
 			break;
 		default:
-			time = 300;
+			time = 50;
 			break;
 		}
 
@@ -1785,6 +1785,7 @@
 		pipe = td->pipe;
 		pipe_stop(r8a66597, pipe);
 
+		/* Select a different address or endpoint */
 		new_td = td;
 		do {
 			list_move_tail(&new_td->queue,
@@ -1794,7 +1795,8 @@
 				new_td = td;
 				break;
 			}
-		} while (td != new_td && td->address == new_td->address);
+		} while (td != new_td && td->address == new_td->address &&
+			td->pipe->info.epnum == new_td->pipe->info.epnum);
 
 		start_transfer(r8a66597, new_td);
 
@@ -1988,6 +1990,8 @@
 
 static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
 				      struct usb_host_endpoint *hep)
+__acquires(r8a66597->lock)
+__releases(r8a66597->lock)
 {
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv;
@@ -2000,13 +2004,14 @@
 		return;
 	pipenum = pipe->info.pipenum;
 
+	spin_lock_irqsave(&r8a66597->lock, flags);
 	if (pipenum == 0) {
 		kfree(hep->hcpriv);
 		hep->hcpriv = NULL;
+		spin_unlock_irqrestore(&r8a66597->lock, flags);
 		return;
 	}
 
-	spin_lock_irqsave(&r8a66597->lock, flags);
 	pipe_stop(r8a66597, pipe);
 	pipe_irq_disable(r8a66597, pipenum);
 	disable_irq_empty(r8a66597, pipenum);
--- linux-4.4.0.orig/drivers/usb/host/u132-hcd.c
+++ linux-4.4.0/drivers/usb/host/u132-hcd.c
@@ -2565,7 +2565,7 @@
 	} else {
 		int frame = 0;
 		dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
-		msleep(100);
+		mdelay(100);
 		return frame;
 	}
 }
@@ -3214,6 +3214,9 @@
 	printk(KERN_INFO "driver %s\n", hcd_name);
 	workqueue = create_singlethread_workqueue("u132");
 	retval = platform_driver_register(&u132_platform_driver);
+	if (retval)
+		destroy_workqueue(workqueue);
+
 	return retval;
 }
 
--- linux-4.4.0.orig/drivers/usb/host/uhci-pci.c
+++ linux-4.4.0/drivers/usb/host/uhci-pci.c
@@ -129,6 +129,10 @@
 	if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP)
 		uhci->wait_for_hp = 1;
 
+	/* Intel controllers use non-PME wakeup signalling */
+	if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_INTEL)
+		device_set_run_wake(uhci_dev(uhci), 1);
+
 	/* Set up pointers to PCI-specific functions */
 	uhci->reset_hc = uhci_pci_reset_hc;
 	uhci->check_and_reset_hc = uhci_pci_check_and_reset_hc;
--- linux-4.4.0.orig/drivers/usb/host/xhci-dbg.c
+++ linux-4.4.0/drivers/usb/host/xhci-dbg.c
@@ -111,7 +111,7 @@
 	xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK);
 
 	/* xhci 1.1 controllers have the HCCPARAMS2 register */
-	if (hci_version > 100) {
+	if (hci_version > 0x100) {
 		temp = readl(&xhci->cap_regs->hcc_params2);
 		xhci_dbg(xhci, "HCC PARAMS2 0x%x:\n", (unsigned int) temp);
 		xhci_dbg(xhci, "  HC %s Force save context capability",
--- linux-4.4.0.orig/drivers/usb/host/xhci-hub.c
+++ linux-4.4.0/drivers/usb/host/xhci-hub.c
@@ -50,14 +50,18 @@
 	0x00,				/* bU1DevExitLat, set later. */
 	0x00, 0x00,			/* __le16 bU2DevExitLat, set later. */
 	/* Second device capability, SuperSpeedPlus */
-	0x0c,				/* bLength 12, will be adjusted later */
+	0x1c,				/* bLength 28, will be adjusted later */
 	USB_DT_DEVICE_CAPABILITY,	/* Device Capability */
 	USB_SSP_CAP_TYPE,		/* bDevCapabilityType SUPERSPEED_PLUS */
 	0x00,				/* bReserved 0 */
-	0x00, 0x00, 0x00, 0x00,		/* bmAttributes, get from xhci psic */
-	0x00, 0x00,			/* wFunctionalitySupport */
+	0x23, 0x00, 0x00, 0x00,		/* bmAttributes, SSAC=3 SSIC=1 */
+	0x01, 0x00,			/* wFunctionalitySupport */
 	0x00, 0x00,			/* wReserved 0 */
-	/* Sublink Speed Attributes are added in xhci_create_usb3_bos_desc() */
+	/* Default Sublink Speed Attributes, overwrite if custom PSI exists */
+	0x34, 0x00, 0x05, 0x00,		/* 5Gbps, symmetric, rx, ID = 4 */
+	0xb4, 0x00, 0x05, 0x00,		/* 5Gbps, symmetric, tx, ID = 4 */
+	0x35, 0x40, 0x0a, 0x00,		/* 10Gbps, SSP, symmetric, rx, ID = 5 */
+	0xb5, 0x40, 0x0a, 0x00,		/* 10Gbps, SSP, symmetric, tx, ID = 5 */
 };
 
 static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
@@ -72,10 +76,14 @@
 	ssp_cap_size = sizeof(usb_bos_descriptor) - desc_size;
 
 	/* does xhci support USB 3.1 Enhanced SuperSpeed */
-	if (xhci->usb3_rhub.min_rev >= 0x01 && xhci->usb3_rhub.psi_uid_count) {
-		/* two SSA entries for each unique PSI ID, one RX and one TX */
-		ssa_count = xhci->usb3_rhub.psi_uid_count * 2;
-		ssa_size = ssa_count * sizeof(u32);
+	if (xhci->usb3_rhub.min_rev >= 0x01) {
+		/* does xhci provide a PSI table for SSA speed attributes? */
+		if (xhci->usb3_rhub.psi_count) {
+			/* two SSA entries for each unique PSI ID, RX and TX */
+			ssa_count = xhci->usb3_rhub.psi_uid_count * 2;
+			ssa_size = ssa_count * sizeof(u32);
+			ssp_cap_size -= 16; /* skip copying the default SSA */
+		}
 		desc_size += ssp_cap_size;
 		usb3_1 = true;
 	}
@@ -102,7 +110,8 @@
 		put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
 	}
 
-	if (usb3_1) {
+	/* If PSI table exists, add the custom speed attributes from it */
+	if (usb3_1 && xhci->usb3_rhub.psi_count) {
 		u32 ssp_cap_base, bm_attrib, psi;
 		int offset;
 
@@ -348,7 +357,7 @@
 
 	slot_id = 0;
 	for (i = 0; i < MAX_HC_SLOTS; i++) {
-		if (!xhci->devs[i])
+		if (!xhci->devs[i] || !xhci->devs[i]->udev)
 			continue;
 		speed = xhci->devs[i]->udev->speed;
 		if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3))
@@ -377,6 +386,9 @@
 
 	ret = 0;
 	virt_dev = xhci->devs[slot_id];
+	if (!virt_dev)
+		return -ENODEV;
+
 	cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
 	if (!cmd) {
 		xhci_dbg(xhci, "Couldn't allocate command structure.\n");
@@ -391,15 +403,25 @@
 						     GFP_NOWAIT);
 			if (!command) {
 				spin_unlock_irqrestore(&xhci->lock, flags);
-				xhci_free_command(xhci, cmd);
-				return -ENOMEM;
+				ret = -ENOMEM;
+				goto cmd_cleanup;
+			}
 
+			ret = xhci_queue_stop_endpoint(xhci, command, slot_id,
+						       i, suspend);
+			if (ret) {
+				spin_unlock_irqrestore(&xhci->lock, flags);
+				xhci_free_command(xhci, command);
+				goto cmd_cleanup;
 			}
-			xhci_queue_stop_endpoint(xhci, command, slot_id, i,
-						 suspend);
 		}
 	}
-	xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
+	ret = xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
+	if (ret) {
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		goto cmd_cleanup;
+	}
+
 	xhci_ring_cmd_db(xhci);
 	spin_unlock_irqrestore(&xhci->lock, flags);
 
@@ -410,6 +432,8 @@
 		xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");
 		ret = -ETIME;
 	}
+
+cmd_cleanup:
 	xhci_free_command(xhci, cmd);
 	return ret;
 }
@@ -584,15 +608,6 @@
 {
 	u32 pls = status_reg & PORT_PLS_MASK;
 
-	/* resume state is a xHCI internal state.
-	 * Do not report it to usb core, instead, pretend to be U3,
-	 * thus usb core knows it's not ready for transfer
-	 */
-	if (pls == XDEV_RESUME) {
-		*status |= USB_SS_PORT_LS_U3;
-		return;
-	}
-
 	/* When the CAS bit is set then warm reset
 	 * should be performed on port
 	 */
@@ -615,6 +630,16 @@
 		pls |= USB_PORT_STAT_CONNECTION;
 	} else {
 		/*
+		 * Resume state is an xHCI internal state.  Do not report it to
+		 * usb core, instead, pretend to be U3, thus usb core knows
+		 * it's not ready for transfer.
+		 */
+		if (pls == XDEV_RESUME) {
+			*status |= USB_SS_PORT_LS_U3;
+			return;
+		}
+
+		/*
 		 * If CAS bit isn't set but the Port is already at
 		 * Compliance Mode, fake a connection so the USB core
 		 * notices the Compliance state and resets the port.
@@ -689,7 +714,7 @@
 		struct xhci_bus_state *bus_state,
 		__le32 __iomem **port_array,
 		u16 wIndex, u32 raw_port_status,
-		unsigned long flags)
+		unsigned long *flags)
 	__releases(&xhci->lock)
 	__acquires(&xhci->lock)
 {
@@ -721,6 +746,14 @@
 			status |= USB_PORT_STAT_C_BH_RESET << 16;
 		if ((raw_port_status & PORT_CEC))
 			status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
+
+		/* USB3 remote wake resume signaling completed */
+		if (bus_state->port_remote_wakeup & (1 << wIndex) &&
+		    (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME &&
+		    (raw_port_status & PORT_PLS_MASK) != XDEV_RECOVERY) {
+			bus_state->port_remote_wakeup &= ~(1 << wIndex);
+			usb_hcd_end_port_resume(&hcd->self, wIndex);
+		}
 	}
 
 	if (hcd->speed < HCD_USB3) {
@@ -729,7 +762,7 @@
 			status |= USB_PORT_STAT_SUSPEND;
 	}
 	if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
-		!DEV_SUPERSPEED_ANY(raw_port_status)) {
+		!DEV_SUPERSPEED_ANY(raw_port_status) && hcd->speed < HCD_USB3) {
 		if ((raw_port_status & PORT_RESET) ||
 				!(raw_port_status & PORT_PE))
 			return 0xffffffff;
@@ -765,15 +798,18 @@
 			clear_bit(wIndex, &bus_state->resuming_ports);
 
 			set_bit(wIndex, &bus_state->rexit_ports);
+
+			xhci_test_and_clear_bit(xhci, port_array, wIndex,
+						PORT_PLC);
 			xhci_set_link_state(xhci, port_array, wIndex,
 					XDEV_U0);
 
-			spin_unlock_irqrestore(&xhci->lock, flags);
+			spin_unlock_irqrestore(&xhci->lock, *flags);
 			time_left = wait_for_completion_timeout(
 					&bus_state->rexit_done[wIndex],
 					msecs_to_jiffies(
-						XHCI_MAX_REXIT_TIMEOUT));
-			spin_lock_irqsave(&xhci->lock, flags);
+						XHCI_MAX_REXIT_TIMEOUT_MS));
+			spin_lock_irqsave(&xhci->lock, *flags);
 
 			if (time_left) {
 				slot_id = xhci_find_slot_id_by_port(hcd,
@@ -786,7 +822,7 @@
 			} else {
 				int port_status = readl(port_array[wIndex]);
 				xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
-						XHCI_MAX_REXIT_TIMEOUT,
+						XHCI_MAX_REXIT_TIMEOUT_MS,
 						port_status);
 				status |= USB_PORT_STAT_SUSPEND;
 				clear_bit(wIndex, &bus_state->rexit_ports);
@@ -919,7 +955,7 @@
 			break;
 		}
 		status = xhci_get_port_status(hcd, bus_state, port_array,
-				wIndex, temp, flags);
+				wIndex, temp, &flags);
 		if (status == 0xffffffff)
 			goto error;
 
@@ -939,7 +975,7 @@
 			}
 			port_li = readl(port_array[wIndex] + PORTLI);
 			status = xhci_get_ext_port_status(temp, port_li);
-			put_unaligned_le32(cpu_to_le32(status), &buf[4]);
+			put_unaligned_le32(status, &buf[4]);
 		}
 		break;
 	case SetPortFeature:
@@ -1030,17 +1066,17 @@
 				temp = readl(port_array[wIndex]);
 				break;
 			}
-
-			/* Software should not attempt to set
-			 * port link state above '3' (U3) and the port
-			 * must be enabled.
-			 */
-			if ((temp & PORT_PE) == 0 ||
-				(link_state > USB_SS_PORT_LS_U3)) {
-				xhci_warn(xhci, "Cannot set link state.\n");
+			/* Port must be enabled */
+			if (!(temp & PORT_PE)) {
+				retval = -ENODEV;
+				break;
+			}
+			/* Can't set port link state above '3' (U3) */
+			if (link_state > USB_SS_PORT_LS_U3) {
+				xhci_warn(xhci, "Cannot set port %d link state %d\n",
+					 wIndex, link_state);
 				goto error;
 			}
-
 			if (link_state == USB_SS_PORT_LS_U3) {
 				slot_id = xhci_find_slot_id_by_port(hcd, xhci,
 						wIndex + 1);
@@ -1154,7 +1190,7 @@
 				xhci_set_link_state(xhci, port_array, wIndex,
 							XDEV_RESUME);
 				spin_unlock_irqrestore(&xhci->lock, flags);
-				msleep(20);
+				msleep(USB_RESUME_TIMEOUT);
 				spin_lock_irqsave(&xhci->lock, flags);
 				xhci_set_link_state(xhci, port_array, wIndex,
 							XDEV_U0);
@@ -1280,13 +1316,16 @@
 	__le32 __iomem **port_array;
 	struct xhci_bus_state *bus_state;
 	unsigned long flags;
+	u32 portsc_buf[USB_MAXCHILDREN];
+	bool wake_enabled;
 
 	max_ports = xhci_get_ports(hcd, &port_array);
 	bus_state = &xhci->bus_state[hcd_index(hcd)];
+	wake_enabled = hcd->self.root_hub->do_remote_wakeup;
 
 	spin_lock_irqsave(&xhci->lock, flags);
 
-	if (hcd->self.root_hub->do_remote_wakeup) {
+	if (wake_enabled) {
 		if (bus_state->resuming_ports ||	/* USB2 */
 		    bus_state->port_remote_wakeup) {	/* USB3 */
 			spin_unlock_irqrestore(&xhci->lock, flags);
@@ -1294,26 +1333,37 @@
 			return -EBUSY;
 		}
 	}
-
-	port_index = max_ports;
+	/*
+	 * Prepare ports for suspend, but don't write anything before all ports
+	 * are checked and we know bus suspend can proceed
+	 */
 	bus_state->bus_suspended = 0;
+	port_index = max_ports;
 	while (port_index--) {
-		/* suspend the port if the port is not suspended */
 		u32 t1, t2;
-		int slot_id;
 
 		t1 = readl(port_array[port_index]);
 		t2 = xhci_port_state_to_neutral(t1);
+		portsc_buf[port_index] = 0;
 
-		if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
-			xhci_dbg(xhci, "port %d not suspended\n", port_index);
-			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-					port_index + 1);
-			if (slot_id) {
+		/* Bail out if a USB3 port has a new device in link training */
+		if ((hcd->speed >= HCD_USB3) &&
+		    (t1 & PORT_PLS_MASK) == XDEV_POLLING) {
+			bus_state->bus_suspended = 0;
+			spin_unlock_irqrestore(&xhci->lock, flags);
+			xhci_dbg(xhci, "Bus suspend bailout, port in polling\n");
+			return -EBUSY;
+		}
+
+		/* suspend ports in U0, or bail out for new connect changes */
+		if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) {
+			if ((t1 & PORT_CSC) && wake_enabled) {
+				bus_state->bus_suspended = 0;
 				spin_unlock_irqrestore(&xhci->lock, flags);
-				xhci_stop_device(xhci, slot_id, 1);
-				spin_lock_irqsave(&xhci->lock, flags);
+				xhci_dbg(xhci, "Bus suspend bailout, port connect change\n");
+				return -EBUSY;
 			}
+			xhci_dbg(xhci, "port %d not suspended\n", port_index);
 			t2 &= ~PORT_PLS_MASK;
 			t2 |= PORT_LINK_STROBE | XDEV_U3;
 			set_bit(port_index, &bus_state->bus_suspended);
@@ -1322,7 +1372,7 @@
 		 * including the USB 3.0 roothub, but only if CONFIG_PM
 		 * is enabled, so also enable remote wake here.
 		 */
-		if (hcd->self.root_hub->do_remote_wakeup) {
+		if (wake_enabled) {
 			if (t1 & PORT_CONNECT) {
 				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
 				t2 &= ~PORT_WKCONN_E;
@@ -1330,19 +1380,73 @@
 				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
 				t2 &= ~PORT_WKDISC_E;
 			}
+			if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) && (hcd->speed < HCD_USB3))
+				t2 &= ~PORT_WAKE_BITS;
 		} else
 			t2 &= ~PORT_WAKE_BITS;
 
 		t1 = xhci_port_state_to_neutral(t1);
 		if (t1 != t2)
-			writel(t2, port_array[port_index]);
+			portsc_buf[port_index] = t2;
+	}
+
+	/* write port settings, stopping and suspending ports if needed */
+	port_index = max_ports;
+	while (port_index--) {
+		if (!portsc_buf[port_index])
+			continue;
+		if (test_bit(port_index, &bus_state->bus_suspended)) {
+			int slot_id;
+
+			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+							    port_index + 1);
+			if (slot_id) {
+				spin_unlock_irqrestore(&xhci->lock, flags);
+				xhci_stop_device(xhci, slot_id, 1);
+				spin_lock_irqsave(&xhci->lock, flags);
+			}
+		}
+		writel(portsc_buf[port_index], port_array[port_index]);
 	}
 	hcd->state = HC_STATE_SUSPENDED;
 	bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
 	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	if (bus_state->bus_suspended)
+		usleep_range(5000, 10000);
+
 	return 0;
 }
 
+/*
+ * Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3.
+ * warm reset a USB3 device stuck in polling or compliance mode after resume.
+ * See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8
+ */
+static bool xhci_port_missing_cas_quirk(int port_index,
+					     __le32 __iomem **port_array)
+{
+	u32 portsc;
+
+	portsc = readl(port_array[port_index]);
+
+	/* if any of these are set we are not stuck */
+	if (portsc & (PORT_CONNECT | PORT_CAS))
+		return false;
+
+	if (((portsc & PORT_PLS_MASK) != XDEV_POLLING) &&
+	    ((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE))
+		return false;
+
+	/* clear wakeup/change bits, and do a warm port reset */
+	portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
+	portsc |= PORT_WR;
+	writel(portsc, port_array[port_index]);
+	/* flush write */
+	readl(port_array[port_index]);
+	return true;
+}
+
 int xhci_bus_resume(struct usb_hcd *hcd)
 {
 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
@@ -1380,6 +1484,14 @@
 		u32 temp;
 
 		temp = readl(port_array[port_index]);
+
+		/* warm reset CAS limited ports stuck in polling/compliance */
+		if ((xhci->quirks & XHCI_MISSING_CAS) &&
+		    (hcd->speed >= HCD_USB3) &&
+		    xhci_port_missing_cas_quirk(port_index, port_array)) {
+			xhci_dbg(xhci, "reset stuck port %d\n", port_index);
+			continue;
+		}
 		if (DEV_SUPERSPEED_ANY(temp))
 			temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
 		else
@@ -1398,7 +1510,7 @@
 
 	if (need_usb2_u3_exit) {
 		spin_unlock_irqrestore(&xhci->lock, flags);
-		msleep(20);
+		msleep(USB_RESUME_TIMEOUT);
 		spin_lock_irqsave(&xhci->lock, flags);
 	}
 
--- linux-4.4.0.orig/drivers/usb/host/xhci-mem.c
+++ linux-4.4.0/drivers/usb/host/xhci-mem.c
@@ -638,7 +638,7 @@
 	if (!ep->stream_info)
 		return NULL;
 
-	if (stream_id > ep->stream_info->num_streams)
+	if (stream_id >= ep->stream_info->num_streams)
 		return NULL;
 	return ep->stream_info->stream_rings[stream_id];
 }
@@ -960,10 +960,53 @@
 	if (dev->out_ctx)
 		xhci_free_container_ctx(xhci, dev->out_ctx);
 
+	if (dev->udev && dev->udev->slot_id)
+		dev->udev->slot_id = 0;
 	kfree(xhci->devs[slot_id]);
 	xhci->devs[slot_id] = NULL;
 }
 
+/*
+ * Free a virt_device structure.
+ * If the virt_device added a tt_info (a hub) and has children pointing to
+ * that tt_info, then free the child first. Recursive.
+ * We can't rely on udev at this point to find child-parent relationships.
+ */
+void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id)
+{
+	struct xhci_virt_device *vdev;
+	struct list_head *tt_list_head;
+	struct xhci_tt_bw_info *tt_info, *next;
+	int i;
+
+	vdev = xhci->devs[slot_id];
+	if (!vdev)
+		return;
+
+	if (vdev->real_port == 0 ||
+			vdev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) {
+		xhci_dbg(xhci, "Bad vdev->real_port.\n");
+		goto out;
+	}
+
+	tt_list_head = &(xhci->rh_bw[vdev->real_port - 1].tts);
+	list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) {
+		/* is this a hub device that added a tt_info to the tts list */
+		if (tt_info->slot_id == slot_id) {
+			/* are any devices using this tt_info? */
+			for (i = 1; i < HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
+				vdev = xhci->devs[i];
+				if (vdev && (vdev->tt_info == tt_info))
+					xhci_free_virt_devices_depth_first(
+						xhci, i);
+			}
+		}
+	}
+out:
+	/* we are now at a leaf device */
+	xhci_free_virt_device(xhci, slot_id);
+}
+
 int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
 		struct usb_device *udev, gfp_t flags)
 {
@@ -976,10 +1019,9 @@
 		return 0;
 	}
 
-	xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags);
-	if (!xhci->devs[slot_id])
+	dev = kzalloc(sizeof(*dev), flags);
+	if (!dev)
 		return 0;
-	dev = xhci->devs[slot_id];
 
 	/* Allocate the (output) device context that will be used in the HC. */
 	dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags);
@@ -1027,9 +1069,18 @@
 		 &xhci->dcbaa->dev_context_ptrs[slot_id],
 		 le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
 
+	xhci->devs[slot_id] = dev;
+
 	return 1;
 fail:
-	xhci_free_virt_device(xhci, slot_id);
+	if (dev->eps[0].ring)
+		xhci_ring_free(xhci, dev->eps[0].ring);
+	if (dev->in_ctx)
+		xhci_free_container_ctx(xhci, dev->in_ctx);
+	if (dev->out_ctx)
+		xhci_free_container_ctx(xhci, dev->out_ctx);
+	kfree(dev);
+
 	return 0;
 }
 
@@ -1072,7 +1123,7 @@
 	struct usb_device *top_dev;
 	struct usb_hcd *hcd;
 
-	if (udev->speed == USB_SPEED_SUPER)
+	if (udev->speed >= USB_SPEED_SUPER)
 		hcd = xhci->shared_hcd;
 	else
 		hcd = xhci->main_hcd;
@@ -1107,6 +1158,10 @@
 	/* 3) Only the control endpoint is valid - one endpoint context */
 	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route);
 	switch (udev->speed) {
+	case USB_SPEED_SUPER_PLUS:
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SSP);
+		max_packets = MAX_PACKET(512);
+		break;
 	case USB_SPEED_SUPER:
 		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
 		max_packets = MAX_PACKET(512);
@@ -1294,6 +1349,7 @@
 		}
 		/* Fall through - SS and HS isoc/int have same decoding */
 
+	case USB_SPEED_SUPER_PLUS:
 	case USB_SPEED_SUPER:
 		if (usb_endpoint_xfer_int(&ep->desc) ||
 		    usb_endpoint_xfer_isoc(&ep->desc)) {
@@ -1323,7 +1379,7 @@
 	default:
 		BUG();
 	}
-	return EP_INTERVAL(interval);
+	return interval;
 }
 
 /* The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps.
@@ -1334,39 +1390,42 @@
 static u32 xhci_get_endpoint_mult(struct usb_device *udev,
 		struct usb_host_endpoint *ep)
 {
-	if (udev->speed != USB_SPEED_SUPER ||
+	if (udev->speed < USB_SPEED_SUPER ||
 			!usb_endpoint_xfer_isoc(&ep->desc))
 		return 0;
 	return ep->ss_ep_comp.bmAttributes;
 }
 
+static u32 xhci_get_endpoint_max_burst(struct usb_device *udev,
+				       struct usb_host_endpoint *ep)
+{
+	/* Super speed and Plus have max burst in ep companion desc */
+	if (udev->speed >= USB_SPEED_SUPER)
+		return ep->ss_ep_comp.bMaxBurst;
+
+	if (udev->speed == USB_SPEED_HIGH &&
+	    (usb_endpoint_xfer_isoc(&ep->desc) ||
+	     usb_endpoint_xfer_int(&ep->desc)))
+		return (usb_endpoint_maxp(&ep->desc) & 0x1800) >> 11;
+
+	return 0;
+}
+
 static u32 xhci_get_endpoint_type(struct usb_host_endpoint *ep)
 {
 	int in;
-	u32 type;
 
 	in = usb_endpoint_dir_in(&ep->desc);
-	if (usb_endpoint_xfer_control(&ep->desc)) {
-		type = EP_TYPE(CTRL_EP);
-	} else if (usb_endpoint_xfer_bulk(&ep->desc)) {
-		if (in)
-			type = EP_TYPE(BULK_IN_EP);
-		else
-			type = EP_TYPE(BULK_OUT_EP);
-	} else if (usb_endpoint_xfer_isoc(&ep->desc)) {
-		if (in)
-			type = EP_TYPE(ISOC_IN_EP);
-		else
-			type = EP_TYPE(ISOC_OUT_EP);
-	} else if (usb_endpoint_xfer_int(&ep->desc)) {
-		if (in)
-			type = EP_TYPE(INT_IN_EP);
-		else
-			type = EP_TYPE(INT_OUT_EP);
-	} else {
-		type = 0;
-	}
-	return type;
+
+	if (usb_endpoint_xfer_control(&ep->desc))
+		return CTRL_EP;
+	if (usb_endpoint_xfer_bulk(&ep->desc))
+		return in ? BULK_IN_EP : BULK_OUT_EP;
+	if (usb_endpoint_xfer_isoc(&ep->desc))
+		return in ? ISOC_IN_EP : ISOC_OUT_EP;
+	if (usb_endpoint_xfer_int(&ep->desc))
+		return in ? INT_IN_EP : INT_OUT_EP;
+	return 0;
 }
 
 /* Return the maximum endpoint service interval time (ESIT) payload.
@@ -1384,7 +1443,12 @@
 			usb_endpoint_xfer_bulk(&ep->desc))
 		return 0;
 
-	if (udev->speed == USB_SPEED_SUPER)
+	/* SuperSpeedPlus Isoc ep sending over 48k per esit */
+	if ((udev->speed >= USB_SPEED_SUPER_PLUS) &&
+	    USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes))
+		return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval);
+	/* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */
+	else if (udev->speed >= USB_SPEED_SUPER)
 		return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
 
 	max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
@@ -1406,10 +1470,14 @@
 	struct xhci_ep_ctx *ep_ctx;
 	struct xhci_ring *ep_ring;
 	unsigned int max_packet;
-	unsigned int max_burst;
-	enum xhci_ring_type type;
+	enum xhci_ring_type ring_type;
 	u32 max_esit_payload;
 	u32 endpoint_type;
+	unsigned int max_burst;
+	unsigned int interval;
+	unsigned int mult;
+	unsigned int avg_trb_len;
+	unsigned int err_count = 0;
 
 	ep_index = xhci_get_endpoint_index(&ep->desc);
 	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
@@ -1417,12 +1485,11 @@
 	endpoint_type = xhci_get_endpoint_type(ep);
 	if (!endpoint_type)
 		return -EINVAL;
-	ep_ctx->ep_info2 = cpu_to_le32(endpoint_type);
 
-	type = usb_endpoint_type(&ep->desc);
+	ring_type = usb_endpoint_type(&ep->desc);
 	/* Set up the endpoint ring */
 	virt_dev->eps[ep_index].new_ring =
-		xhci_ring_alloc(xhci, 2, 1, type, mem_flags);
+		xhci_ring_alloc(xhci, 2, 1, ring_type, mem_flags);
 	if (!virt_dev->eps[ep_index].new_ring) {
 		/* Attempt to use the ring cache */
 		if (virt_dev->num_rings_cached == 0)
@@ -1432,80 +1499,52 @@
 			virt_dev->ring_cache[virt_dev->num_rings_cached];
 		virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
 		xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
-					1, type);
+					1, ring_type);
 	}
 	virt_dev->eps[ep_index].skip = false;
 	ep_ring = virt_dev->eps[ep_index].new_ring;
-	ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma | ep_ring->cycle_state);
 
-	ep_ctx->ep_info = cpu_to_le32(xhci_get_endpoint_interval(udev, ep)
-				      | EP_MULT(xhci_get_endpoint_mult(udev, ep)));
+	/*
+	 * Get values to fill the endpoint context, mostly from ep descriptor.
+	 * The average TRB buffer lengt for bulk endpoints is unclear as we
+	 * have no clue on scatter gather list entry size. For Isoc and Int,
+	 * set it to max available. See xHCI 1.1 spec 4.14.1.1 for details.
+	 */
+	max_esit_payload = xhci_get_max_esit_payload(udev, ep);
+	interval = xhci_get_endpoint_interval(udev, ep);
+	mult = xhci_get_endpoint_mult(udev, ep);
+	max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
+	max_burst = xhci_get_endpoint_max_burst(udev, ep);
+	avg_trb_len = max_esit_payload;
 
 	/* FIXME dig Mult and streams info out of ep companion desc */
 
-	/* Allow 3 retries for everything but isoc;
-	 * CErr shall be set to 0 for Isoch endpoints.
-	 */
+	/* Allow 3 retries for everything but isoc, set CErr = 3 */
 	if (!usb_endpoint_xfer_isoc(&ep->desc))
-		ep_ctx->ep_info2 |= cpu_to_le32(ERROR_COUNT(3));
-	else
-		ep_ctx->ep_info2 |= cpu_to_le32(ERROR_COUNT(0));
-
-	/* Set the max packet size and max burst */
-	max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
-	max_burst = 0;
-	switch (udev->speed) {
-	case USB_SPEED_SUPER:
-		/* dig out max burst from ep companion desc */
-		max_burst = ep->ss_ep_comp.bMaxBurst;
-		break;
-	case USB_SPEED_HIGH:
-		/* Some devices get this wrong */
-		if (usb_endpoint_xfer_bulk(&ep->desc))
-			max_packet = 512;
-		/* bits 11:12 specify the number of additional transaction
-		 * opportunities per microframe (USB 2.0, section 9.6.6)
-		 */
-		if (usb_endpoint_xfer_isoc(&ep->desc) ||
-				usb_endpoint_xfer_int(&ep->desc)) {
-			max_burst = (usb_endpoint_maxp(&ep->desc)
-				     & 0x1800) >> 11;
-		}
-		break;
-	case USB_SPEED_FULL:
-	case USB_SPEED_LOW:
-		break;
-	default:
-		BUG();
-	}
-	ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet) |
-			MAX_BURST(max_burst));
-	max_esit_payload = xhci_get_max_esit_payload(udev, ep);
-	ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload));
-
-	/*
-	 * XXX no idea how to calculate the average TRB buffer length for bulk
-	 * endpoints, as the driver gives us no clue how big each scatter gather
-	 * list entry (or buffer) is going to be.
-	 *
-	 * For isochronous and interrupt endpoints, we set it to the max
-	 * available, until we have new API in the USB core to allow drivers to
-	 * declare how much bandwidth they actually need.
-	 *
-	 * Normally, it would be calculated by taking the total of the buffer
-	 * lengths in the TD and then dividing by the number of TRBs in a TD,
-	 * including link TRBs, No-op TRBs, and Event data TRBs.  Since we don't
-	 * use Event Data TRBs, and we don't chain in a link TRB on short
-	 * transfers, we're basically dividing by 1.
-	 *
-	 * xHCI 1.0 and 1.1 specification indicates that the Average TRB Length
-	 * should be set to 8 for control endpoints.
-	 */
+		err_count = 3;
+	/* Some devices get this wrong */
+	if (usb_endpoint_xfer_bulk(&ep->desc) && udev->speed == USB_SPEED_HIGH)
+		max_packet = 512;
+	/* xHCI 1.0 and 1.1 indicates that ctrl ep avg TRB Length should be 8 */
 	if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100)
-		ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8));
-	else
-		ep_ctx->tx_info |=
-			 cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(max_esit_payload));
+		avg_trb_len = 8;
+	/* xhci 1.1 with LEC support doesn't use mult field, use RsvdZ */
+	if ((xhci->hci_version > 0x100) && HCC2_LEC(xhci->hcc_params2))
+		mult = 0;
+
+	/* Fill the endpoint context */
+	ep_ctx->ep_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
+				      EP_INTERVAL(interval) |
+				      EP_MULT(mult));
+	ep_ctx->ep_info2 = cpu_to_le32(EP_TYPE(endpoint_type) |
+				       MAX_PACKET(max_packet) |
+				       MAX_BURST(max_burst) |
+				       ERROR_COUNT(err_count));
+	ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma |
+				  ep_ring->cycle_state);
+
+	ep_ctx->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
+				      EP_AVG_TRB_LENGTH(avg_trb_len));
 
 	/* FIXME Debug endpoint context */
 	return 0;
@@ -1672,7 +1711,7 @@
 	xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma);
 	for (i = 0; i < num_sp; i++) {
 		dma_addr_t dma;
-		void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma,
+		void *buf = dma_zalloc_coherent(dev, xhci->page_size, &dma,
 				flags);
 		if (!buf)
 			goto fail_sp5;
@@ -1792,7 +1831,7 @@
 	int size;
 	int i, j, num_ports;
 
-	del_timer_sync(&xhci->cmd_timer);
+	cancel_delayed_work_sync(&xhci->cmd_timer);
 
 	/* Free the Event Ring Segment Table and the actual Event Ring */
 	size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
@@ -1825,8 +1864,8 @@
 		}
 	}
 
-	for (i = 1; i < MAX_HC_SLOTS; ++i)
-		xhci_free_virt_device(xhci, i);
+	for (i = HCS_MAX_SLOTS(xhci->hcs_params1); i > 0; i--)
+		xhci_free_virt_devices_depth_first(xhci, i);
 
 	dma_pool_destroy(xhci->segment_pool);
 	xhci->segment_pool = NULL;
@@ -1874,6 +1913,16 @@
 	kfree(xhci->port_array);
 	kfree(xhci->rh_bw);
 	kfree(xhci->ext_caps);
+	kfree(xhci->usb2_rhub.psi);
+	kfree(xhci->usb3_rhub.psi);
+
+	xhci->usb2_ports = NULL;
+	xhci->usb3_ports = NULL;
+	xhci->port_array = NULL;
+	xhci->usb2_rhub.psi = NULL;
+	xhci->usb3_rhub.psi = NULL;
+	xhci->rh_bw = NULL;
+	xhci->ext_caps = NULL;
 
 	xhci->page_size = 0;
 	xhci->page_shift = 0;
@@ -2352,9 +2401,9 @@
 
 	INIT_LIST_HEAD(&xhci->cmd_list);
 
-	/* init command timeout timer */
-	setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
-		    (unsigned long)xhci);
+	/* init command timeout work */
+	INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout);
+	init_completion(&xhci->cmd_ring_stop_completion);
 
 	page_size = readl(&xhci->op_regs->page_size);
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@@ -2393,7 +2442,7 @@
 	 * "physically contiguous and 64-byte (cache line) aligned".
 	 */
 	xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
-			GFP_KERNEL);
+			flags);
 	if (!xhci->dcbaa)
 		goto fail;
 	memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
@@ -2450,7 +2499,7 @@
 		(xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
 		xhci->cmd_ring->cycle_state;
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
-			"// Setting command ring address to 0x%x", val);
+			"// Setting command ring address to 0x%016llx", val_64);
 	xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
 	xhci_dbg_cmd_ptrs(xhci);
 
@@ -2489,7 +2538,7 @@
 
 	xhci->erst.entries = dma_alloc_coherent(dev,
 			sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma,
-			GFP_KERNEL);
+			flags);
 	if (!xhci->erst.entries)
 		goto fail;
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
--- linux-4.4.0.orig/drivers/usb/host/xhci-pci.c
+++ linux-4.4.0/drivers/usb/host/xhci-pci.c
@@ -28,13 +28,16 @@
 #include "xhci.h"
 #include "xhci-trace.h"
 
-#define PORT2_SSIC_CONFIG_REG2	0x883c
+#define SSIC_PORT_NUM		2
+#define SSIC_PORT_CFG2		0x880c
+#define SSIC_PORT_CFG2_OFFSET	0x30
 #define PROG_DONE		(1 << 30)
 #define SSIC_PORT_UNUSED	(1 << 31)
 
 /* Device for a quirk */
 #define PCI_VENDOR_ID_FRESCO_LOGIC	0x1b73
 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK	0x1000
+#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1009	0x1009
 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400	0x1400
 
 #define PCI_VENDOR_ID_ETRON		0x1b6f
@@ -42,9 +45,22 @@
 
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI	0x8c31
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI	0x9c31
+#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI	0x9cb1
 #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI		0x22b5
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI		0xa12f
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI	0x9d2f
+#define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI		0x0aa8
+#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI		0x1aa8
+#define PCI_DEVICE_ID_INTEL_APL_XHCI			0x5aa8
+#define PCI_DEVICE_ID_INTEL_DNV_XHCI			0x19d0
+#define PCI_DEVICE_ID_INTEL_CML_XHCI			0xa3af
+
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_4			0x43b9
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_3			0x43ba
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_2			0x43bb
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_1			0x43bc
+
+#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI		0x1142
 
 static const char hcd_name[] = "xhci_hcd";
 
@@ -111,6 +127,10 @@
 		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 	}
 
+	if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
+			pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009)
+		xhci->quirks |= XHCI_BROKEN_STREAMS;
+
 	if (pdev->vendor == PCI_VENDOR_ID_NEC)
 		xhci->quirks |= XHCI_NEC_HOST;
 
@@ -124,6 +144,14 @@
 	if (pdev->vendor == PCI_VENDOR_ID_AMD)
 		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 
+	if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
+		((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
+		(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
+		(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
+		(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
+		xhci->quirks |= XHCI_U2_DISABLE_WAKE;
+
+
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
 		xhci->quirks |= XHCI_LPM_SUPPORT;
 		xhci->quirks |= XHCI_INTEL_HOST;
@@ -145,16 +173,30 @@
 		xhci->quirks |= XHCI_SPURIOUS_REBOOT;
 	}
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
-		pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
+		(pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI ||
+		 pdev->device == PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI)) {
 		xhci->quirks |= XHCI_SPURIOUS_REBOOT;
 		xhci->quirks |= XHCI_SPURIOUS_WAKEUP;
 	}
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
 		(pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
 		 pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
-		 pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) {
+		 pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+		 pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI ||
+		 pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI ||
+		 pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI ||
+		 pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI ||
+		 pdev->device == PCI_DEVICE_ID_INTEL_CML_XHCI)) {
 		xhci->quirks |= XHCI_PME_STUCK_QUIRK;
 	}
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+	    (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+	     pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
+	     pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
+	     pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI ||
+	     pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI))
+		xhci->quirks |= XHCI_MISSING_CAS;
+
 	if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
 			pdev->device == PCI_DEVICE_ID_EJ168) {
 		xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -162,6 +204,9 @@
 		xhci->quirks |= XHCI_BROKEN_STREAMS;
 	}
 	if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
+			pdev->device == 0x0014)
+		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+	if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
 			pdev->device == 0x0015)
 		xhci->quirks |= XHCI_RESET_ON_RESUME;
 	if (pdev->vendor == PCI_VENDOR_ID_VIA)
@@ -175,6 +220,13 @@
 	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
 			pdev->device == 0x1042)
 		xhci->quirks |= XHCI_BROKEN_STREAMS;
+	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+			pdev->device == 0x1142)
+		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+
+	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+		pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI)
+		xhci->quirks |= XHCI_ASMEDIA_MODIFY_FLOWCONTROL;
 
 	if (xhci->quirks & XHCI_RESET_ON_RESUME)
 		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
@@ -295,15 +347,17 @@
 	struct xhci_hcd *xhci;
 
 	xhci = hcd_to_xhci(pci_get_drvdata(dev));
+	xhci->xhc_state |= XHCI_STATE_REMOVING;
 	if (xhci->shared_hcd) {
 		usb_remove_hcd(xhci->shared_hcd);
 		usb_put_hcd(xhci->shared_hcd);
 	}
-	usb_hcd_pci_remove(dev);
 
 	/* Workaround for spurious wakeups at shutdown with HSW */
 	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
 		pci_set_power_state(dev, PCI_D3hot);
+
+	usb_hcd_pci_remove(dev);
 }
 
 #ifdef CONFIG_PM
@@ -322,28 +376,36 @@
 	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller);
 	u32 val;
 	void __iomem *reg;
+	int i;
 
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
 		 pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
 
-		reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
-
-		/* Notify SSIC that SSIC profile programming is not done */
-		val = readl(reg) & ~PROG_DONE;
-		writel(val, reg);
-
-		/* Mark SSIC port as unused(suspend) or used(resume) */
-		val = readl(reg);
-		if (suspend)
-			val |= SSIC_PORT_UNUSED;
-		else
-			val &= ~SSIC_PORT_UNUSED;
-		writel(val, reg);
-
-		/* Notify SSIC that SSIC profile programming is done */
-		val = readl(reg) | PROG_DONE;
-		writel(val, reg);
-		readl(reg);
+		for (i = 0; i < SSIC_PORT_NUM; i++) {
+			reg = (void __iomem *) xhci->cap_regs +
+					SSIC_PORT_CFG2 +
+					i * SSIC_PORT_CFG2_OFFSET;
+
+			/*
+			 * Notify SSIC that SSIC profile programming
+			 * is not done.
+			 */
+			val = readl(reg) & ~PROG_DONE;
+			writel(val, reg);
+
+			/* Mark SSIC port as unused(suspend) or used(resume) */
+			val = readl(reg);
+			if (suspend)
+				val |= SSIC_PORT_UNUSED;
+			else
+				val &= ~SSIC_PORT_UNUSED;
+			writel(val, reg);
+
+			/* Notify SSIC that SSIC profile programming is done */
+			val = readl(reg) | PROG_DONE;
+			writel(val, reg);
+			readl(reg);
+		}
 	}
 
 	reg = (void __iomem *) xhci->cap_regs + 0x80a4;
@@ -403,6 +465,18 @@
 	retval = xhci_resume(xhci, hibernated);
 	return retval;
 }
+
+static void xhci_pci_shutdown(struct usb_hcd *hcd)
+{
+	struct xhci_hcd		*xhci = hcd_to_xhci(hcd);
+	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller);
+
+	xhci_shutdown(hcd);
+
+	/* Yet another workaround for spurious wakeups at shutdown with HSW */
+	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
+		pci_set_power_state(pdev, PCI_D3hot);
+}
 #endif /* CONFIG_PM */
 
 /*-------------------------------------------------------------------------*/
@@ -440,6 +514,7 @@
 #ifdef CONFIG_PM
 	xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
 	xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
+	xhci_pci_hc_driver.shutdown = xhci_pci_shutdown;
 #endif
 	return pci_register_driver(&xhci_pci_driver);
 }
--- linux-4.4.0.orig/drivers/usb/host/xhci-plat.c
+++ linux-4.4.0/drivers/usb/host/xhci-plat.c
@@ -92,7 +92,7 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
-		return -ENODEV;
+		return irq;
 
 	/* Try to set 64-bit DMA first */
 	if (WARN_ON(!pdev->dev.dma_mask))
@@ -132,6 +132,9 @@
 		ret = clk_prepare_enable(clk);
 		if (ret)
 			goto put_hcd;
+	} else if (PTR_ERR(clk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto put_hcd;
 	}
 
 	if (of_device_is_compatible(pdev->dev.of_node,
@@ -159,9 +162,6 @@
 			(pdata && pdata->usb3_lpm_capable))
 		xhci->quirks |= XHCI_LPM_SUPPORT;
 
-	if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
-		xhci->shared_hcd->can_do_streams = 1;
-
 	hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
 	if (IS_ERR(hcd->usb_phy)) {
 		ret = PTR_ERR(hcd->usb_phy);
@@ -178,6 +178,9 @@
 	if (ret)
 		goto disable_usb_phy;
 
+	if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+		xhci->shared_hcd->can_do_streams = 1;
+
 	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
 	if (ret)
 		goto dealloc_usb2_hcd;
@@ -210,6 +213,8 @@
 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
 	struct clk *clk = xhci->clk;
 
+	xhci->xhc_state |= XHCI_STATE_REMOVING;
+
 	usb_remove_hcd(xhci->shared_hcd);
 	usb_phy_shutdown(hcd->usb_phy);
 
@@ -279,6 +284,7 @@
 static struct platform_driver usb_xhci_driver = {
 	.probe	= xhci_plat_probe,
 	.remove	= xhci_plat_remove,
+	.shutdown = usb_hcd_platform_shutdown,
 	.driver	= {
 		.name = "xhci-hcd",
 		.pm = DEV_PM_OPS,
--- linux-4.4.0.orig/drivers/usb/host/xhci-ring.c
+++ linux-4.4.0/drivers/usb/host/xhci-ring.c
@@ -280,15 +280,76 @@
 	readl(&xhci->dba->doorbell[0]);
 }
 
-static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
+static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci, unsigned long delay)
+{
+	return mod_delayed_work(system_wq, &xhci->cmd_timer, delay);
+}
+
+static struct xhci_command *xhci_next_queued_cmd(struct xhci_hcd *xhci)
+{
+	return list_first_entry_or_null(&xhci->cmd_list, struct xhci_command,
+					cmd_list);
+}
+
+/*
+ * Turn all commands on command ring with status set to "aborted" to no-op trbs.
+ * If there are other commands waiting then restart the ring and kick the timer.
+ * This must be called with command ring stopped and xhci->lock held.
+ */
+static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
+					 struct xhci_command *cur_cmd)
+{
+	struct xhci_command *i_cmd;
+	u32 cycle_state;
+
+	/* Turn all aborted commands in list to no-ops, then restart */
+	list_for_each_entry(i_cmd, &xhci->cmd_list, cmd_list) {
+
+		if (i_cmd->status != COMP_CMD_ABORT)
+			continue;
+
+		i_cmd->status = COMP_CMD_STOP;
+
+		xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
+			 i_cmd->command_trb);
+		/* get cycle state from the original cmd trb */
+		cycle_state = le32_to_cpu(
+			i_cmd->command_trb->generic.field[3]) &	TRB_CYCLE;
+		/* modify the command trb to no-op command */
+		i_cmd->command_trb->generic.field[0] = 0;
+		i_cmd->command_trb->generic.field[1] = 0;
+		i_cmd->command_trb->generic.field[2] = 0;
+		i_cmd->command_trb->generic.field[3] = cpu_to_le32(
+			TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
+
+		/*
+		 * caller waiting for completion is called when command
+		 *  completion event is received for these no-op commands
+		 */
+	}
+
+	xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
+
+	/* ring command ring doorbell to restart the command ring */
+	if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
+	    !(xhci->xhc_state & XHCI_STATE_DYING)) {
+		xhci->current_cmd = cur_cmd;
+		xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
+		xhci_ring_cmd_db(xhci);
+	}
+}
+
+/* Must be called with xhci->lock held, releases and aquires lock back */
+static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
 {
 	u64 temp_64;
 	int ret;
 
 	xhci_dbg(xhci, "Abort command ring\n");
 
+	reinit_completion(&xhci->cmd_ring_stop_completion);
+
 	temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
-	xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
 	xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
 			&xhci->op_regs->cmd_ring);
 
@@ -308,15 +369,30 @@
 		udelay(1000);
 		ret = xhci_handshake(&xhci->op_regs->cmd_ring,
 				     CMD_RING_RUNNING, 0, 3 * 1000 * 1000);
-		if (ret == 0)
-			return 0;
-
-		xhci_err(xhci, "Stopped the command ring failed, "
-				"maybe the host is dead\n");
-		xhci->xhc_state |= XHCI_STATE_DYING;
-		xhci_quiesce(xhci);
-		xhci_halt(xhci);
-		return -ESHUTDOWN;
+		if (ret < 0) {
+			xhci_err(xhci, "Stopped the command ring failed, "
+				 "maybe the host is dead\n");
+			xhci->xhc_state |= XHCI_STATE_DYING;
+			xhci_quiesce(xhci);
+			xhci_halt(xhci);
+			return -ESHUTDOWN;
+		}
+	}
+	/*
+	 * Writing the CMD_RING_ABORT bit should cause a cmd completion event,
+	 * however on some host hw the CMD_RING_RUNNING bit is correctly cleared
+	 * but the completion event in never sent. Wait 2 secs (arbitrary
+	 * number) to handle those cases after negation of CMD_RING_RUNNING.
+	 */
+	spin_unlock_irqrestore(&xhci->lock, flags);
+	ret = wait_for_completion_timeout(&xhci->cmd_ring_stop_completion,
+					  msecs_to_jiffies(2000));
+	spin_lock_irqsave(&xhci->lock, flags);
+	if (!ret) {
+		xhci_dbg(xhci, "No stop event for abort, ring start fail?\n");
+		xhci_cleanup_command_queue(xhci);
+	} else {
+		xhci_handle_stopped_cmd_ring(xhci, xhci_next_queued_cmd(xhci));
 	}
 
 	return 0;
@@ -780,13 +856,16 @@
 			(ep->ep_state & EP_GETTING_NO_STREAMS)) {
 		int stream_id;
 
-		for (stream_id = 0; stream_id < ep->stream_info->num_streams;
+		for (stream_id = 1; stream_id < ep->stream_info->num_streams;
 				stream_id++) {
+			ring = ep->stream_info->stream_rings[stream_id];
+			if (!ring)
+				continue;
+
 			xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
 					"Killing URBs for slot ID %u, ep index %u, stream %u",
-					slot_id, ep_index, stream_id + 1);
-			xhci_kill_ring_urbs(xhci,
-					ep->stream_info->stream_rings[stream_id]);
+					slot_id, ep_index, stream_id);
+			xhci_kill_ring_urbs(xhci, ring);
 		}
 	} else {
 		ring = ep->ring;
@@ -837,13 +916,6 @@
 	spin_lock_irqsave(&xhci->lock, flags);
 
 	ep->stop_cmds_pending--;
-	if (xhci->xhc_state & XHCI_STATE_DYING) {
-		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
-				"Stop EP timer ran, but another timer marked "
-				"xHCI as DYING, exiting.");
-		spin_unlock_irqrestore(&xhci->lock, flags);
-		return;
-	}
 	if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
 		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
 				"Stop EP timer ran, but no command pending, "
@@ -890,7 +962,7 @@
 	spin_unlock_irqrestore(&xhci->lock, flags);
 	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
 			"Calling usb_hc_died()");
-	usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
+	usb_hc_died(xhci_to_hcd(xhci));
 	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
 			"xHCI host controller is dead.");
 }
@@ -1195,93 +1267,62 @@
 		xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT);
 }
 
-/*
- * Turn all commands on command ring with status set to "aborted" to no-op trbs.
- * If there are other commands waiting then restart the ring and kick the timer.
- * This must be called with command ring stopped and xhci->lock held.
- */
-static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
-					 struct xhci_command *cur_cmd)
-{
-	struct xhci_command *i_cmd, *tmp_cmd;
-	u32 cycle_state;
-
-	/* Turn all aborted commands in list to no-ops, then restart */
-	list_for_each_entry_safe(i_cmd, tmp_cmd, &xhci->cmd_list,
-				 cmd_list) {
-
-		if (i_cmd->status != COMP_CMD_ABORT)
-			continue;
-
-		i_cmd->status = COMP_CMD_STOP;
-
-		xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
-			 i_cmd->command_trb);
-		/* get cycle state from the original cmd trb */
-		cycle_state = le32_to_cpu(
-			i_cmd->command_trb->generic.field[3]) &	TRB_CYCLE;
-		/* modify the command trb to no-op command */
-		i_cmd->command_trb->generic.field[0] = 0;
-		i_cmd->command_trb->generic.field[1] = 0;
-		i_cmd->command_trb->generic.field[2] = 0;
-		i_cmd->command_trb->generic.field[3] = cpu_to_le32(
-			TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
-
-		/*
-		 * caller waiting for completion is called when command
-		 *  completion event is received for these no-op commands
-		 */
-	}
-
-	xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
-
-	/* ring command ring doorbell to restart the command ring */
-	if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
-	    !(xhci->xhc_state & XHCI_STATE_DYING)) {
-		xhci->current_cmd = cur_cmd;
-		mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
-		xhci_ring_cmd_db(xhci);
-	}
-	return;
-}
-
-
-void xhci_handle_command_timeout(unsigned long data)
+void xhci_handle_command_timeout(struct work_struct *work)
 {
 	struct xhci_hcd *xhci;
 	int ret;
 	unsigned long flags;
 	u64 hw_ring_state;
-	struct xhci_command *cur_cmd = NULL;
-	xhci = (struct xhci_hcd *) data;
 
-	/* mark this command to be cancelled */
+	xhci = container_of(to_delayed_work(work), struct xhci_hcd, cmd_timer);
+
 	spin_lock_irqsave(&xhci->lock, flags);
-	if (xhci->current_cmd) {
-		cur_cmd = xhci->current_cmd;
-		cur_cmd->status = COMP_CMD_ABORT;
-	}
 
+	/*
+	 * If timeout work is pending, or current_cmd is NULL, it means we
+	 * raced with command completion. Command is handled so just return.
+	 */
+	if (!xhci->current_cmd || delayed_work_pending(&xhci->cmd_timer)) {
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		return;
+	}
+	/* mark this command to be cancelled */
+	xhci->current_cmd->status = COMP_CMD_ABORT;
 
 	/* Make sure command ring is running before aborting it */
 	hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
 	if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) &&
 	    (hw_ring_state & CMD_RING_RUNNING))  {
-
-		spin_unlock_irqrestore(&xhci->lock, flags);
+		/* Prevent new doorbell, and start command abort */
+		xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
 		xhci_dbg(xhci, "Command timeout\n");
-		ret = xhci_abort_cmd_ring(xhci);
+		ret = xhci_abort_cmd_ring(xhci, flags);
 		if (unlikely(ret == -ESHUTDOWN)) {
 			xhci_err(xhci, "Abort command ring failed\n");
 			xhci_cleanup_command_queue(xhci);
+			spin_unlock_irqrestore(&xhci->lock, flags);
 			usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
 			xhci_dbg(xhci, "xHCI host controller is dead.\n");
+
+			return;
 		}
-		return;
+
+		goto time_out_completed;
 	}
+
+	/* host removed. Bail out */
+	if (xhci->xhc_state & XHCI_STATE_REMOVING) {
+		xhci_dbg(xhci, "host removed, ring start fail?\n");
+		xhci_cleanup_command_queue(xhci);
+
+		goto time_out_completed;
+	}
+
 	/* command timeout on stopped ring, ring can't be aborted */
 	xhci_dbg(xhci, "Command timeout on stopped ring\n");
 	xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd);
+
+time_out_completed:
 	spin_unlock_irqrestore(&xhci->lock, flags);
 	return;
 }
@@ -1314,13 +1355,7 @@
 
 	cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list);
 
-	if (cmd->command_trb != xhci->cmd_ring->dequeue) {
-		xhci_err(xhci,
-			 "Command completion event does not match command\n");
-		return;
-	}
-
-	del_timer(&xhci->cmd_timer);
+	cancel_delayed_work(&xhci->cmd_timer);
 
 	trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event);
 
@@ -1328,9 +1363,16 @@
 
 	/* If CMD ring stopped we own the trbs between enqueue and dequeue */
 	if (cmd_comp_code == COMP_CMD_STOP) {
-		xhci_handle_stopped_cmd_ring(xhci, cmd);
+		complete_all(&xhci->cmd_ring_stop_completion);
 		return;
 	}
+
+	if (cmd->command_trb != xhci->cmd_ring->dequeue) {
+		xhci_err(xhci,
+			 "Command completion event does not match command\n");
+		return;
+	}
+
 	/*
 	 * Host aborted the command ring, check if the current command was
 	 * supposed to be aborted, otherwise continue normally.
@@ -1339,8 +1381,11 @@
 	 */
 	if (cmd_comp_code == COMP_CMD_ABORT) {
 		xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
-		if (cmd->status == COMP_CMD_ABORT)
+		if (cmd->status == COMP_CMD_ABORT) {
+			if (xhci->current_cmd == cmd)
+				xhci->current_cmd = NULL;
 			goto event_handled;
+		}
 	}
 
 	cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3]));
@@ -1401,7 +1446,9 @@
 	if (cmd->cmd_list.next != &xhci->cmd_list) {
 		xhci->current_cmd = list_entry(cmd->cmd_list.next,
 					       struct xhci_command, cmd_list);
-		mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
+		xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
+	} else if (xhci->current_cmd == cmd) {
+		xhci->current_cmd = NULL;
 	}
 
 event_handled:
@@ -1555,9 +1602,6 @@
 		usb_hcd_resume_root_hub(hcd);
 	}
 
-	if (hcd->speed >= HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
-		bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
-
 	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
 		xhci_dbg(xhci, "port resume event for port %d\n", port_id);
 
@@ -1576,6 +1620,7 @@
 			bus_state->port_remote_wakeup |= 1 << faked_port_index;
 			xhci_test_and_clear_bit(xhci, port_array,
 					faked_port_index, PORT_PLC);
+			usb_hcd_start_port_resume(&hcd->self, faked_port_index);
 			xhci_set_link_state(xhci, port_array, faked_port_index,
 						XDEV_U0);
 			/* Need to wait until the next link state change
@@ -1595,10 +1640,13 @@
 		}
 	}
 
-	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 &&
-			DEV_SUPERSPEED_ANY(temp)) {
+	if ((temp & PORT_PLC) &&
+	    DEV_SUPERSPEED_ANY(temp) &&
+	    ((temp & PORT_PLS_MASK) == XDEV_U0 ||
+	     (temp & PORT_PLS_MASK) == XDEV_U1 ||
+	     (temp & PORT_PLS_MASK) == XDEV_U2)) {
 		xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
-		/* We've just brought the device into U0 through either the
+		/* We've just brought the device into U0/1/2 through either the
 		 * Resume state after a device remote wakeup, or through the
 		 * U3Exit state after a host-initiated resume.  If it's a device
 		 * initiated remote wake, don't pass up the link state change,
@@ -1610,8 +1658,6 @@
 		if (slot_id && xhci->devs[slot_id])
 			xhci_ring_device(xhci, slot_id);
 		if (bus_state->port_remote_wakeup & (1 << faked_port_index)) {
-			bus_state->port_remote_wakeup &=
-				~(1 << faked_port_index);
 			xhci_test_and_clear_bit(xhci, port_array,
 					faked_port_index, PORT_PLC);
 			usb_wakeup_notification(hcd->self.root_hub,
@@ -1626,7 +1672,7 @@
 	 * RExit to a disconnect state).  If so, let the the driver know it's
 	 * out of the RExit state.
 	 */
-	if (!DEV_SUPERSPEED_ANY(temp) &&
+	if (!DEV_SUPERSPEED_ANY(temp) && hcd->speed < HCD_USB3 &&
 			test_and_clear_bit(faked_port_index,
 				&bus_state->rexit_ports)) {
 		complete(&bus_state->rexit_done[faked_port_index]);
@@ -2192,10 +2238,6 @@
 		}
 	/* Fast path - was this the last TRB in the TD for this URB? */
 	} else if (event_trb == td->last_trb) {
-		if (td->urb_length_set && trb_comp_code == COMP_SHORT_TX)
-			return finish_td(xhci, td, event_trb, event, ep,
-					 status, false);
-
 		if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
 			td->urb->actual_length =
 				td->urb->transfer_buffer_length -
@@ -2247,12 +2289,6 @@
 			td->urb->actual_length +=
 				TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
 				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
-
-		if (trb_comp_code == COMP_SHORT_TX) {
-			xhci_dbg(xhci, "mid bulk/intr SP, wait for last TRB event\n");
-			td->urb_length_set = true;
-			return 0;
-		}
 	}
 
 	return finish_td(xhci, td, event_trb, event, ep, status, false);
@@ -2749,6 +2785,8 @@
 		spin_unlock(&xhci->lock);
 
 		return IRQ_HANDLED;
+	} else if (xhci->xhc_state & XHCI_STATE_HALTED) {
+		xhci_dbg(xhci, "xHCI halted, handling interrupt.\n");
 	}
 
 	event_ring_deq = xhci->event_ring->dequeue;
@@ -2803,6 +2841,8 @@
 	trb->field[0] = cpu_to_le32(field1);
 	trb->field[1] = cpu_to_le32(field2);
 	trb->field[2] = cpu_to_le32(field3);
+	/* make sure TRB is fully written before giving it to the controller */
+	wmb();
 	trb->field[3] = cpu_to_le32(field4);
 	inc_enq(xhci, ring, more_trbs_coming);
 }
@@ -3562,12 +3602,11 @@
  * zero.  Only xHCI 1.0 host controllers support this field.
  */
 static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
-		struct usb_device *udev,
 		struct urb *urb, unsigned int total_packet_count)
 {
 	unsigned int max_burst;
 
-	if (xhci->hci_version < 0x100 || udev->speed != USB_SPEED_SUPER)
+	if (xhci->hci_version < 0x100 || urb->dev->speed < USB_SPEED_SUPER)
 		return 0;
 
 	max_burst = urb->ep->ss_ep_comp.bMaxBurst;
@@ -3583,7 +3622,6 @@
  * contain 1 to (bMaxBurst + 1) packets.
  */
 static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
-		struct usb_device *udev,
 		struct urb *urb, unsigned int total_packet_count)
 {
 	unsigned int max_burst;
@@ -3592,8 +3630,7 @@
 	if (xhci->hci_version < 0x100)
 		return 0;
 
-	switch (udev->speed) {
-	case USB_SPEED_SUPER:
+	if (urb->dev->speed >= USB_SPEED_SUPER) {
 		/* bMaxBurst is zero based: 0 means 1 packet per burst */
 		max_burst = urb->ep->ss_ep_comp.bMaxBurst;
 		residue = total_packet_count % (max_burst + 1);
@@ -3603,11 +3640,10 @@
 		if (residue == 0)
 			return max_burst;
 		return residue - 1;
-	default:
-		if (total_packet_count == 0)
-			return 0;
-		return total_packet_count - 1;
 	}
+	if (total_packet_count == 0)
+		return 0;
+	return total_packet_count - 1;
 }
 
 /*
@@ -3718,6 +3754,7 @@
 	int i, j;
 	bool more_trbs_coming;
 	struct xhci_virt_ep *xep;
+	int frame_id;
 
 	xep = &xhci->devs[slot_id]->eps[ep_index];
 	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
@@ -3727,33 +3764,31 @@
 		xhci_dbg(xhci, "Isoc URB with zero packets?\n");
 		return -EINVAL;
 	}
-
 	start_addr = (u64) urb->transfer_dma;
 	start_trb = &ep_ring->enqueue->generic;
 	start_cycle = ep_ring->cycle_state;
 
 	urb_priv = urb->hcpriv;
-	/* Queue the first TRB, even if it's zero-length */
+	/* Queue the TRBs for each TD, even if they are zero-length */
 	for (i = 0; i < num_tds; i++) {
-		unsigned int total_packet_count;
-		unsigned int burst_count;
-		unsigned int residue;
+		unsigned int total_pkt_count, max_pkt;
+		unsigned int burst_count, last_burst_pkt_count;
+		u32 sia_frame_id;
 
 		first_trb = true;
 		running_total = 0;
 		addr = start_addr + urb->iso_frame_desc[i].offset;
 		td_len = urb->iso_frame_desc[i].length;
 		td_remain_len = td_len;
-		total_packet_count = DIV_ROUND_UP(td_len,
-				GET_MAX_PACKET(
-					usb_endpoint_maxp(&urb->ep->desc)));
+		max_pkt = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
+		total_pkt_count = DIV_ROUND_UP(td_len, max_pkt);
+
 		/* A zero-length transfer still involves at least one packet. */
-		if (total_packet_count == 0)
-			total_packet_count++;
-		burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
-				total_packet_count);
-		residue = xhci_get_last_burst_packet_count(xhci,
-				urb->dev, urb, total_packet_count);
+		if (total_pkt_count == 0)
+			total_pkt_count++;
+		burst_count = xhci_get_burst_count(xhci, urb, total_pkt_count);
+		last_burst_pkt_count = xhci_get_last_burst_packet_count(xhci,
+							urb, total_pkt_count);
 
 		trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
 
@@ -3764,68 +3799,57 @@
 				return ret;
 			goto cleanup;
 		}
-
 		td = urb_priv->td[i];
+
+		/* use SIA as default, if frame id is used overwrite it */
+		sia_frame_id = TRB_SIA;
+		if (!(urb->transfer_flags & URB_ISO_ASAP) &&
+		    HCC_CFC(xhci->hcc_params)) {
+			frame_id = xhci_get_isoc_frame_id(xhci, urb, i);
+			if (frame_id >= 0)
+				sia_frame_id = TRB_FRAME_ID(frame_id);
+		}
+		/*
+		 * Set isoc specific data for the first TRB in a TD.
+		 * Prevent HW from getting the TRBs by keeping the cycle state
+		 * inverted in the first TDs isoc TRB.
+		 */
+		field = TRB_TYPE(TRB_ISOC) |
+			TRB_TLBPC(last_burst_pkt_count) |
+			sia_frame_id |
+			(i ? ep_ring->cycle_state : !start_cycle);
+
+		/* xhci 1.1 with ETE uses TD_Size field for TBC, old is Rsvdz */
+		if (!xep->use_extended_tbc)
+			field |= TRB_TBC(burst_count);
+
+		/* fill the rest of the TRB fields, and remaining normal TRBs */
 		for (j = 0; j < trbs_per_td; j++) {
-			int frame_id = 0;
 			u32 remainder = 0;
-			field = 0;
 
-			if (first_trb) {
-				field = TRB_TBC(burst_count) |
-					TRB_TLBPC(residue);
-				/* Queue the isoc TRB */
-				field |= TRB_TYPE(TRB_ISOC);
-
-				/* Calculate Frame ID and SIA fields */
-				if (!(urb->transfer_flags & URB_ISO_ASAP) &&
-						HCC_CFC(xhci->hcc_params)) {
-					frame_id = xhci_get_isoc_frame_id(xhci,
-									  urb,
-									  i);
-					if (frame_id >= 0)
-						field |= TRB_FRAME_ID(frame_id);
-					else
-						field |= TRB_SIA;
-				} else
-					field |= TRB_SIA;
-
-				if (i == 0) {
-					if (start_cycle == 0)
-						field |= 0x1;
-				} else
-					field |= ep_ring->cycle_state;
-				first_trb = false;
-			} else {
-				/* Queue other normal TRBs */
-				field |= TRB_TYPE(TRB_NORMAL);
-				field |= ep_ring->cycle_state;
-			}
+			/* only first TRB is isoc, overwrite otherwise */
+			if (!first_trb)
+				field = TRB_TYPE(TRB_NORMAL) |
+					ep_ring->cycle_state;
 
 			/* Only set interrupt on short packet for IN EPs */
 			if (usb_urb_dir_in(urb))
 				field |= TRB_ISP;
 
-			/* Chain all the TRBs together; clear the chain bit in
-			 * the last TRB to indicate it's the last TRB in the
-			 * chain.
-			 */
+			/* Set the chain bit for all except the last TRB  */
 			if (j < trbs_per_td - 1) {
-				field |= TRB_CHAIN;
 				more_trbs_coming = true;
+				field |= TRB_CHAIN;
 			} else {
+				more_trbs_coming = false;
 				td->last_trb = ep_ring->enqueue;
 				field |= TRB_IOC;
-				if (xhci->hci_version == 0x100 &&
-						!(xhci->quirks &
-							XHCI_AVOID_BEI)) {
-					/* Set BEI bit except for the last td */
-					if (i < num_tds - 1)
-						field |= TRB_BEI;
-				}
-				more_trbs_coming = false;
+				/* set BEI, except for the last TD */
+				if (xhci->hci_version >= 0x100 &&
+				    !(xhci->quirks & XHCI_AVOID_BEI) &&
+				    i < num_tds - 1)
+					field |= TRB_BEI;
 			}
-
 			/* Calculate TRB length */
 			trb_buff_len = TRB_MAX_BUFF_SIZE -
 				(addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
@@ -3838,9 +3862,15 @@
 						   urb, trbs_per_td - j - 1);
 
 			length_field = TRB_LEN(trb_buff_len) |
-				TRB_TD_SIZE(remainder) |
 				TRB_INTR_TARGET(0);
 
+			/* xhci 1.1 with ETE uses TD Size field for TBC */
+			if (first_trb && xep->use_extended_tbc)
+				length_field |= TRB_TD_SIZE_TBC(burst_count);
+			else
+				length_field |= TRB_TD_SIZE(remainder);
+			first_trb = false;
+
 			queue_trb(xhci, ep_ring, more_trbs_coming,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
@@ -4018,7 +4048,8 @@
 	int reserved_trbs = xhci->cmd_ring_reserved_trbs;
 	int ret;
 
-	if (xhci->xhc_state) {
+	if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+		(xhci->xhc_state & XHCI_STATE_HALTED)) {
 		xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n");
 		return -ESHUTDOWN;
 	}
@@ -4041,9 +4072,9 @@
 
 	/* if there are no other commands queued we start the timeout timer */
 	if (xhci->cmd_list.next == &cmd->cmd_list &&
-	    !timer_pending(&xhci->cmd_timer)) {
+	    !delayed_work_pending(&xhci->cmd_timer)) {
 		xhci->current_cmd = cmd;
-		mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
+		xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
 	}
 
 	queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
--- linux-4.4.0.orig/drivers/usb/host/xhci.c
+++ linux-4.4.0/drivers/usb/host/xhci.c
@@ -21,6 +21,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/iopoll.h>
 #include <linux/irq.h>
 #include <linux/log2.h>
 #include <linux/module.h>
@@ -46,7 +47,6 @@
 module_param(quirks, uint, S_IRUGO);
 MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
 
-/* TODO: copied from ehci-hcd.c - can this be refactored? */
 /*
  * xhci_handshake - spin reading hc until handshake completes or fails
  * @ptr: address of hc register to be read
@@ -63,18 +63,16 @@
 int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
 {
 	u32	result;
+	int	ret;
 
-	do {
-		result = readl(ptr);
-		if (result == ~(u32)0)		/* card removed */
-			return -ENODEV;
-		result &= mask;
-		if (result == done)
-			return 0;
-		udelay(1);
-		usec--;
-	} while (usec > 0);
-	return -ETIMEDOUT;
+	ret = readl_poll_timeout_atomic(ptr, result,
+					(result & mask) == done ||
+					result == U32_MAX,
+					1, usec);
+	if (result == U32_MAX)		/* card removed */
+		return -ENODEV;
+
+	return ret;
 }
 
 /*
@@ -146,7 +144,8 @@
 				"waited %u microseconds.\n",
 				XHCI_MAX_HALT_USEC);
 	if (!ret)
-		xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING);
+		/* clear state flags. Including dying, halted or removing */
+		xhci->xhc_state = 0;
 
 	return ret;
 }
@@ -190,6 +189,9 @@
 	if (ret)
 		return ret;
 
+	if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+		usb_asmedia_modifyflowcontrol(to_pci_dev(xhci_to_hcd(xhci)->self.controller));
+
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 			 "Wait for controller to be ready for doorbell rings");
 	/*
@@ -679,20 +681,23 @@
 	u32 temp;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
-	if (xhci->xhc_state & XHCI_STATE_HALTED)
-		return;
-
 	mutex_lock(&xhci->mutex);
-	spin_lock_irq(&xhci->lock);
-	xhci->xhc_state |= XHCI_STATE_HALTED;
-	xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
 
-	/* Make sure the xHC is halted for a USB3 roothub
-	 * (xhci_stop() could be called as part of failed init).
-	 */
-	xhci_halt(xhci);
-	xhci_reset(xhci);
-	spin_unlock_irq(&xhci->lock);
+	if (!(xhci->xhc_state & XHCI_STATE_HALTED)) {
+		spin_lock_irq(&xhci->lock);
+
+		xhci->xhc_state |= XHCI_STATE_HALTED;
+		xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
+		xhci_halt(xhci);
+		xhci_reset(xhci);
+
+		spin_unlock_irq(&xhci->lock);
+	}
+
+	if (!usb_hcd_is_primary_hcd(hcd)) {
+		mutex_unlock(&xhci->mutex);
+		return;
+	}
 
 	xhci_cleanup_msix(xhci);
 
@@ -752,11 +757,8 @@
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 			"xhci_shutdown completed - status = %x",
 			readl(&xhci->op_regs->status));
-
-	/* Yet another workaround for spurious wakeups at shutdown with HSW */
-	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
-		pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot);
 }
+EXPORT_SYMBOL_GPL(xhci_shutdown);
 
 #ifdef CONFIG_PM
 static void xhci_save_registers(struct xhci_hcd *xhci)
@@ -883,6 +885,41 @@
 	spin_unlock_irqrestore(&xhci->lock, flags);
 }
 
+static bool xhci_pending_portevent(struct xhci_hcd *xhci)
+{
+	__le32 __iomem		**port_array;
+	int			port_index;
+	u32			status;
+	u32			portsc;
+
+	status = readl(&xhci->op_regs->status);
+	if (status & STS_EINT)
+		return true;
+	/*
+	 * Checking STS_EINT is not enough as there is a lag between a change
+	 * bit being set and the Port Status Change Event that it generated
+	 * being written to the Event Ring. See note in xhci 1.1 section 4.19.2.
+	 */
+
+	port_index = xhci->num_usb2_ports;
+	port_array = xhci->usb2_ports;
+	while (port_index--) {
+		portsc = readl(port_array[port_index]);
+		if (portsc & PORT_CHANGE_MASK ||
+		    (portsc & PORT_PLS_MASK) == XDEV_RESUME)
+			return true;
+	}
+	port_index = xhci->num_usb3_ports;
+	port_array = xhci->usb3_ports;
+	while (port_index--) {
+		portsc = readl(port_array[port_index]);
+		if (portsc & PORT_CHANGE_MASK ||
+		    (portsc & PORT_PLS_MASK) == XDEV_RESUME)
+			return true;
+	}
+	return false;
+}
+
 /*
  * Stop HC (not bus-specific)
  *
@@ -892,7 +929,7 @@
 int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
 {
 	int			rc = 0;
-	unsigned int		delay = XHCI_MAX_HALT_USEC;
+	unsigned int		delay = XHCI_MAX_HALT_USEC * 2;
 	struct usb_hcd		*hcd = xhci_to_hcd(xhci);
 	u32			command;
 
@@ -944,7 +981,7 @@
 	command |= CMD_CSS;
 	writel(command, &xhci->op_regs->command);
 	if (xhci_handshake(&xhci->op_regs->status,
-				STS_SAVE, 0, 10 * 1000)) {
+				STS_SAVE, 0, 20 * 1000)) {
 		xhci_warn(xhci, "WARN: xHC save state timeout\n");
 		spin_unlock_irq(&xhci->lock);
 		return -ETIMEDOUT;
@@ -979,11 +1016,12 @@
  */
 int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 {
-	u32			command, temp = 0, status;
+	u32			command, temp = 0;
 	struct usb_hcd		*hcd = xhci_to_hcd(xhci);
 	struct usb_hcd		*secondary_hcd;
 	int			retval = 0;
 	bool			comp_timer_running = false;
+	bool			pending_portevent = false;
 
 	if (!hcd->state)
 		return 0;
@@ -1004,6 +1042,18 @@
 		hibernated = true;
 
 	if (!hibernated) {
+		/*
+		 * Some controllers might lose power during suspend, so wait
+		 * for controller not ready bit to clear, just as in xHC init.
+		 */
+		retval = xhci_handshake(&xhci->op_regs->status,
+					STS_CNR, 0, 10 * 1000 * 1000);
+		if (retval) {
+			xhci_warn(xhci, "Controller not ready at resume %d\n",
+				  retval);
+			spin_unlock_irq(&xhci->lock);
+			return retval;
+		}
 		/* step 1: restore register */
 		xhci_restore_registers(xhci);
 		/* step 2: initialize command ring buffer */
@@ -1013,8 +1063,13 @@
 		command = readl(&xhci->op_regs->command);
 		command |= CMD_CRS;
 		writel(command, &xhci->op_regs->command);
+		/*
+		 * Some controllers take up to 55+ ms to complete the controller
+		 * restore so setting the timeout to 100ms. Xhci specification
+		 * doesn't mention any timeout value.
+		 */
 		if (xhci_handshake(&xhci->op_regs->status,
-			      STS_RESTORE, 0, 10 * 1000)) {
+			      STS_RESTORE, 0, 100 * 1000)) {
 			xhci_warn(xhci, "WARN: xHC restore state timeout\n");
 			spin_unlock_irq(&xhci->lock);
 			return -ETIMEDOUT;
@@ -1100,14 +1155,22 @@
 
  done:
 	if (retval == 0) {
-		/* Resume root hubs only when have pending events. */
-		status = readl(&xhci->op_regs->status);
-		if (status & STS_EINT) {
-			usb_hcd_resume_root_hub(hcd);
+		/*
+		 * Resume roothubs only if there are pending events.
+		 * USB 3 devices resend U3 LFPS wake after a 100ms delay if
+		 * the first wake signalling failed, give it that chance.
+		 */
+		pending_portevent = xhci_pending_portevent(xhci);
+		if (!pending_portevent) {
+			msleep(120);
+			pending_portevent = xhci_pending_portevent(xhci);
+		}
+
+		if (pending_portevent) {
 			usb_hcd_resume_root_hub(xhci->shared_hcd);
+			usb_hcd_resume_root_hub(hcd);
 		}
 	}
-
 	/*
 	 * If system is subject to the Quirk, Compliance Mode Timer needs to
 	 * be re-initialized Always after a system resume. Ports are subject
@@ -1117,12 +1180,15 @@
 	if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running)
 		compliance_mode_recovery_timer_init(xhci);
 
+	if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+		usb_asmedia_modifyflowcontrol(to_pci_dev(hcd->self.controller));
+
 	/* Re-enable port polling. */
 	xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
-	set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
-	usb_hcd_poll_rh_status(hcd);
 	set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
 	usb_hcd_poll_rh_status(xhci->shared_hcd);
+	set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+	usb_hcd_poll_rh_status(hcd);
 
 	return retval;
 }
@@ -1290,6 +1356,7 @@
 				xhci->devs[slot_id]->out_ctx, ep_index);
 
 		ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index);
+		ep_ctx->ep_info &= cpu_to_le32(~EP_STATE_MASK);/* must clear */
 		ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK);
 		ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size));
 
@@ -1549,7 +1616,9 @@
 		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
 				"HW died, freeing TD.");
 		urb_priv = urb->hcpriv;
-		for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
+		for (i = urb_priv->td_cnt;
+		     i < urb_priv->length && xhci->devs[urb->dev->slot_id];
+		     i++) {
 			td = urb_priv->td[i];
 			if (!list_empty(&td->td_list))
 				list_del_init(&td->td_list);
@@ -1563,19 +1632,6 @@
 		xhci_urb_free_priv(urb_priv);
 		return ret;
 	}
-	if ((xhci->xhc_state & XHCI_STATE_DYING) ||
-			(xhci->xhc_state & XHCI_STATE_HALTED)) {
-		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
-				"Ep 0x%x: URB %p to be canceled on "
-				"non-responsive xHCI host.",
-				urb->ep->desc.bEndpointAddress, urb);
-		/* Let the stop endpoint command watchdog timer (which set this
-		 * state) finish cleaning up the endpoint TD lists.  We must
-		 * have caught it in the middle of dropping a lock and giving
-		 * back an URB.
-		 */
-		goto done;
-	}
 
 	ep_index = xhci_get_endpoint_index(&urb->ep->desc);
 	ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
@@ -2067,6 +2123,7 @@
 	case USB_SPEED_HIGH:
 		return HS_BLOCK;
 	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
 		return SS_BLOCK;
 	case USB_SPEED_UNKNOWN:
 	case USB_SPEED_WIRELESS:
@@ -2192,7 +2249,7 @@
 	unsigned int packets_remaining = 0;
 	unsigned int i;
 
-	if (virt_dev->udev->speed == USB_SPEED_SUPER)
+	if (virt_dev->udev->speed >= USB_SPEED_SUPER)
 		return xhci_check_ss_bw(xhci, virt_dev);
 
 	if (virt_dev->udev->speed == USB_SPEED_HIGH) {
@@ -2393,7 +2450,7 @@
 	if (xhci_is_async_ep(ep_bw->type))
 		return;
 
-	if (udev->speed == USB_SPEED_SUPER) {
+	if (udev->speed >= USB_SPEED_SUPER) {
 		if (xhci_is_sync_in_ep(ep_bw->type))
 			xhci->devs[udev->slot_id]->bw_table->ss_bw_in -=
 				xhci_get_ss_bw_consumed(ep_bw);
@@ -2431,6 +2488,7 @@
 		interval_bw->overhead[HS_OVERHEAD_TYPE] -= 1;
 		break;
 	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
 	case USB_SPEED_UNKNOWN:
 	case USB_SPEED_WIRELESS:
 		/* Should never happen because only LS/FS/HS endpoints will get
@@ -2490,6 +2548,7 @@
 		interval_bw->overhead[HS_OVERHEAD_TYPE] += 1;
 		break;
 	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
 	case USB_SPEED_UNKNOWN:
 	case USB_SPEED_WIRELESS:
 		/* Should never happen because only LS/FS/HS endpoints will get
@@ -2751,7 +2810,8 @@
 	if (ret <= 0)
 		return ret;
 	xhci = hcd_to_xhci(hcd);
-	if (xhci->xhc_state & XHCI_STATE_DYING)
+	if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+		(xhci->xhc_state & XHCI_STATE_REMOVING))
 		return -ENODEV;
 
 	xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
@@ -3639,6 +3699,9 @@
 	}
 
 	spin_lock_irqsave(&xhci->lock, flags);
+
+	virt_dev->udev = NULL;
+
 	/* Don't disable the slot if the host controller is dead. */
 	state = readl(&xhci->op_regs->status);
 	if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
@@ -3798,8 +3861,10 @@
 
 	mutex_lock(&xhci->mutex);
 
-	if (xhci->xhc_state)	/* dying or halted */
+	if (xhci->xhc_state) {	/* dying, removing or halted */
+		ret = -ESHUTDOWN;
 		goto out;
+	}
 
 	if (!udev->slot_id) {
 		xhci_dbg_trace(xhci, trace_xhci_dbg_address,
@@ -4152,7 +4217,6 @@
 	pm_addr = port_array[port_num] + PORTPMSC;
 	pm_val = readl(pm_addr);
 	hlpm_addr = port_array[port_num] + PORTHLPMC;
-	field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
 
 	xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
 			enable ? "enable" : "disable", port_num + 1);
@@ -4164,6 +4228,7 @@
 			 * default one which works with mixed HIRD and BESL
 			 * systems. See XHCI_DEFAULT_BESL definition in xhci.h
 			 */
+			field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
 			if ((field & USB_BESL_SUPPORT) &&
 			    (field & USB_BESL_BASELINE_VALID))
 				hird = USB_GET_BESL_BASELINE(field);
@@ -4215,6 +4280,9 @@
 			mutex_lock(hcd->bandwidth_mutex);
 			xhci_change_max_exit_latency(xhci, udev, 0);
 			mutex_unlock(hcd->bandwidth_mutex);
+			readl_poll_timeout(port_array[port_num], pm_val,
+					   (pm_val & PORT_PLS_MASK) == XDEV_U0,
+					   100, 10000);
 			return 0;
 		}
 	}
@@ -4381,6 +4449,14 @@
 	else
 		timeout_ns = udev->u1_params.sel;
 
+	/* Prevent U1 if service interval is shorter than U1 exit latency */
+	if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) {
+		if (xhci_service_interval_to_ns(desc) <= timeout_ns) {
+			dev_dbg(&udev->dev, "Disable U1, ESIT shorter than exit latency\n");
+			return USB3_LPM_DISABLED;
+		}
+	}
+
 	/* The U1 timeout is encoded in 1us intervals.
 	 * Don't return a timeout of zero, because that's USB3_LPM_DISABLED.
 	 */
@@ -4437,6 +4513,14 @@
 	else
 		timeout_ns = udev->u2_params.sel;
 
+	/* Prevent U2 if service interval is shorter than U2 exit latency */
+	if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) {
+		if (xhci_service_interval_to_ns(desc) <= timeout_ns) {
+			dev_dbg(&udev->dev, "Disable U2, ESIT shorter than exit latency\n");
+			return USB3_LPM_DISABLED;
+		}
+	}
+
 	/* The U2 timeout is encoded in 256us intervals */
 	timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000);
 	/* If the necessary timeout value is bigger than what we can set in the
@@ -4474,12 +4558,12 @@
 	alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
 		desc, state, timeout);
 
-	/* If we found we can't enable hub-initiated LPM, or
+	/* If we found we can't enable hub-initiated LPM, and
 	 * the U1 or U2 exit latency was too high to allow
-	 * device-initiated LPM as well, just stop searching.
+	 * device-initiated LPM as well, then we will disable LPM
+	 * for this device, so stop searching any further.
 	 */
-	if (alt_timeout == USB3_LPM_DISABLED ||
-			alt_timeout == USB3_LPM_DEVICE_INITIATED) {
+	if (alt_timeout == USB3_LPM_DISABLED) {
 		*timeout = alt_timeout;
 		return -E2BIG;
 	}
@@ -4590,10 +4674,12 @@
 		if (intf->dev.driver) {
 			driver = to_usb_driver(intf->dev.driver);
 			if (driver && driver->disable_hub_initiated_lpm) {
-				dev_dbg(&udev->dev, "Hub-initiated %s disabled "
-						"at request of driver %s\n",
-						state_name, driver->name);
-				return xhci_get_timeout_no_hub_lpm(udev, state);
+				dev_dbg(&udev->dev, "Hub-initiated %s disabled at request of driver %s\n",
+					state_name, driver->name);
+				timeout = xhci_get_timeout_no_hub_lpm(udev,
+								      state);
+				if (timeout == USB3_LPM_DISABLED)
+					return timeout;
 			}
 		}
 
@@ -4878,6 +4964,7 @@
 		if (xhci->sbrn == 0x31) {
 			xhci_info(xhci, "Host supports USB 3.1 Enhanced SuperSpeed\n");
 			hcd->speed = HCD_USB31;
+			hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
 		}
 		/* xHCI private pointer was set in xhci_pci_probe for the second
 		 * registered roothub.
@@ -5059,6 +5146,10 @@
 	BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
 	/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
 	BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
+
+	if (usb_disabled())
+		return -ENODEV;
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/usb/host/xhci.h
+++ linux-4.4.0/drivers/usb/host/xhci.h
@@ -232,7 +232,9 @@
  * disabled, or powered-off state.
  */
 #define CMD_PM_INDEX	(1 << 11)
-/* bits 12:31 are reserved (and should be preserved on writes). */
+/* bit 14 Extended TBC Enable, changes Isoc TRB fields to support larger TBC */
+#define CMD_ETE		(1 << 14)
+/* bits 15:31 are reserved (and should be preserved on writes). */
 
 /* IMAN - Interrupt Management Register */
 #define IMAN_IE		(1 << 1)
@@ -309,9 +311,13 @@
  */
 #define PORT_PLS_MASK	(0xf << 5)
 #define XDEV_U0		(0x0 << 5)
+#define XDEV_U1		(0x1 << 5)
 #define XDEV_U2		(0x2 << 5)
 #define XDEV_U3		(0x3 << 5)
 #define XDEV_INACTIVE	(0x6 << 5)
+#define XDEV_POLLING	(0x7 << 5)
+#define XDEV_RECOVERY	(0x8 << 5)
+#define XDEV_COMP_MODE  (0xa << 5)
 #define XDEV_RESUME	(0xf << 5)
 /* true: port has power (see HCC_PPC) */
 #define PORT_POWER	(1 << 9)
@@ -343,6 +349,7 @@
 #define	SLOT_SPEED_LS		(XDEV_LS << 10)
 #define	SLOT_SPEED_HS		(XDEV_HS << 10)
 #define	SLOT_SPEED_SS		(XDEV_SS << 10)
+#define	SLOT_SPEED_SSP		(XDEV_SSP << 10)
 /* Port Indicator Control */
 #define PORT_LED_OFF	(0 << 14)
 #define PORT_LED_AMBER	(1 << 14)
@@ -380,6 +387,10 @@
 #define PORT_PLC	(1 << 22)
 /* port configure error change - port failed to configure its link partner */
 #define PORT_CEC	(1 << 23)
+#define PORT_CHANGE_MASK	(PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
+				 PORT_RC | PORT_PLC | PORT_CEC)
+
+
 /* Cold Attach Status - xHC can set this bit to report device attached during
  * Sx state. Warm port reset should be perfomed to clear this bit and move port
  * to connected state.
@@ -698,7 +709,7 @@
  * 4 - TRB error
  * 5-7 - reserved
  */
-#define EP_STATE_MASK		(0xf)
+#define EP_STATE_MASK		(0x7)
 #define EP_STATE_DISABLED	0
 #define EP_STATE_RUNNING	1
 #define EP_STATE_HALTED		2
@@ -748,8 +759,9 @@
 #define GET_MAX_PACKET(p)	((p) & 0x7ff)
 
 /* tx_info bitmasks */
-#define AVG_TRB_LENGTH_FOR_EP(p)	((p) & 0xffff)
-#define MAX_ESIT_PAYLOAD_FOR_EP(p)	(((p) & 0xffff) << 16)
+#define EP_AVG_TRB_LENGTH(p)		((p) & 0xffff)
+#define EP_MAX_ESIT_PAYLOAD_LO(p)	(((p) & 0xffff) << 16)
+#define EP_MAX_ESIT_PAYLOAD_HI(p)	((((p) >> 16) & 0xff) << 24)
 #define CTX_TO_MAX_ESIT_PAYLOAD(p)	(((p) >> 16) & 0xffff)
 
 /* deq bitmasks */
@@ -941,6 +953,8 @@
 	struct list_head	bw_endpoint_list;
 	/* Isoch Frame ID checking storage */
 	int			next_frame_id;
+	/* Use new Isoch TRB layout needed for extended TBC support */
+	bool			use_extended_tbc;
 };
 
 enum xhci_overhead_type {
@@ -1182,9 +1196,12 @@
 #define	TRB_LEN(p)		((p) & 0x1ffff)
 /* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */
 #define TRB_TD_SIZE(p)          (min((p), (u32)31) << 17)
+/* xhci 1.1 uses the TD_SIZE field for TBC if Extended TBC is enabled (ETE) */
+#define TRB_TD_SIZE_TBC(p)      (min((p), (u32)31) << 17)
 /* Interrupter Target - which MSI-X vector to target the completion event at */
 #define TRB_INTR_TARGET(p)	(((p) & 0x3ff) << 22)
 #define GET_INTR_TARGET(p)	(((p) >> 22) & 0x3ff)
+/* Total burst count field, Rsvdz on xhci 1.1 with Extended TBC enabled (ETE) */
 #define TRB_TBC(p)		(((p) & 0x3) << 7)
 #define TRB_TLBPC(p)		(((p) & 0xf) << 16)
 
@@ -1484,11 +1501,11 @@
  * It can take up to 20 ms to transition from RExit to U0 on the
  * Intel Lynx Point LP xHCI host.
  */
-#define	XHCI_MAX_REXIT_TIMEOUT	(20 * 1000)
+#define	XHCI_MAX_REXIT_TIMEOUT_MS	20
 
 static inline unsigned int hcd_index(struct usb_hcd *hcd)
 {
-	if (hcd->speed == HCD_USB3)
+	if (hcd->speed >= HCD_USB3)
 		return 0;
 	else
 		return 1;
@@ -1550,7 +1567,8 @@
 #define CMD_RING_STATE_STOPPED         (1 << 2)
 	struct list_head        cmd_list;
 	unsigned int		cmd_ring_reserved_trbs;
-	struct timer_list	cmd_timer;
+	struct delayed_work	cmd_timer;
+	struct completion	cmd_ring_stop_completion;
 	struct xhci_command	*current_cmd;
 	struct xhci_ring	*event_ring;
 	struct xhci_erst	erst;
@@ -1596,6 +1614,7 @@
  */
 #define XHCI_STATE_DYING	(1 << 0)
 #define XHCI_STATE_HALTED	(1 << 1)
+#define XHCI_STATE_REMOVING	(1 << 2)
 	/* Statistics */
 	int			error_bitmask;
 	unsigned int		quirks;
@@ -1630,6 +1649,10 @@
 /* For controllers with a broken beyond repair streams implementation */
 #define XHCI_BROKEN_STREAMS	(1 << 19)
 #define XHCI_PME_STUCK_QUIRK	(1 << 20)
+#define XHCI_MISSING_CAS	(1 << 24)
+#define XHCI_U2_DISABLE_WAKE    (1 << 27)
+#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL	(1 << 28)
+
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
@@ -1823,6 +1846,7 @@
 void xhci_stop(struct usb_hcd *hcd);
 void xhci_shutdown(struct usb_hcd *hcd);
 int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
+void xhci_shutdown(struct usb_hcd *hcd);
 void xhci_init_driver(struct hc_driver *drv,
 		      const struct xhci_driver_overrides *over);
 
@@ -1911,7 +1935,7 @@
 		unsigned int slot_id, unsigned int ep_index,
 		struct xhci_dequeue_state *deq_state);
 void xhci_stop_endpoint_command_watchdog(unsigned long arg);
-void xhci_handle_command_timeout(unsigned long data);
+void xhci_handle_command_timeout(struct work_struct *work);
 
 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
 		unsigned int ep_index, unsigned int stream_id);
--- linux-4.4.0.orig/drivers/usb/image/microtek.c
+++ linux-4.4.0/drivers/usb/image/microtek.c
@@ -724,6 +724,10 @@
 
 	}
 
+	if (ep_in_current != &ep_in_set[2]) {
+		MTS_WARNING("couldn't find two input bulk endpoints. Bailing out.\n");
+		return -ENODEV;
+	}
 
 	if ( ep_out == -1 ) {
 		MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
--- linux-4.4.0.orig/drivers/usb/misc/Kconfig
+++ linux-4.4.0/drivers/usb/misc/Kconfig
@@ -46,16 +46,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called usbsevseg.
 
-config USB_RIO500
-	tristate "USB Diamond Rio500 support"
-	help
-	  Say Y here if you want to connect a USB Rio500 mp3 player to your
-	  computer's USB port. Please read <file:Documentation/usb/rio.txt>
-	  for more information.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called rio500.
-
 config USB_LEGOTOWER
 	tristate "USB Lego Infrared Tower support"
 	help
--- linux-4.4.0.orig/drivers/usb/misc/Makefile
+++ linux-4.4.0/drivers/usb/misc/Makefile
@@ -17,7 +17,6 @@
 obj-$(CONFIG_USB_LD)			+= ldusb.o
 obj-$(CONFIG_USB_LED)			+= usbled.o
 obj-$(CONFIG_USB_LEGOTOWER)		+= legousbtower.o
-obj-$(CONFIG_USB_RIO500)		+= rio500.o
 obj-$(CONFIG_USB_TEST)			+= usbtest.o
 obj-$(CONFIG_USB_EHSET_TEST_FIXTURE)    += ehset.o
 obj-$(CONFIG_USB_TRANCEVIBRATOR)	+= trancevibrator.o
--- linux-4.4.0.orig/drivers/usb/misc/adutux.c
+++ linux-4.4.0/drivers/usb/misc/adutux.c
@@ -80,6 +80,7 @@
 	char			serial_number[8];
 
 	int			open_count; /* number of times this port has been opened */
+	unsigned long		disconnected:1;
 
 	char		*read_buffer_primary;
 	int			read_buffer_length;
@@ -121,7 +122,7 @@
 {
 	unsigned long flags;
 
-	if (dev->udev == NULL)
+	if (dev->disconnected)
 		return;
 
 	/* shutdown transfer */
@@ -151,6 +152,7 @@
 	kfree(dev->read_buffer_secondary);
 	kfree(dev->interrupt_in_buffer);
 	kfree(dev->interrupt_out_buffer);
+	usb_put_dev(dev->udev);
 	kfree(dev);
 }
 
@@ -208,6 +210,7 @@
 
 	if (status != 0) {
 		if ((status != -ENOENT) &&
+		    (status != -ESHUTDOWN) &&
 		    (status != -ECONNRESET)) {
 			dev_dbg(&dev->udev->dev,
 				"%s :nonzero status received: %d\n", __func__,
@@ -244,7 +247,7 @@
 	}
 
 	dev = usb_get_intfdata(interface);
-	if (!dev || !dev->udev) {
+	if (!dev) {
 		retval = -ENODEV;
 		goto exit_no_device;
 	}
@@ -327,7 +330,7 @@
 	}
 
 	adu_release_internal(dev);
-	if (dev->udev == NULL) {
+	if (dev->disconnected) {
 		/* the device was unplugged before the file was released */
 		if (!dev->open_count)	/* ... and we're the last user */
 			adu_delete(dev);
@@ -356,7 +359,7 @@
 		return -ERESTARTSYS;
 
 	/* verify that the device wasn't unplugged */
-	if (dev->udev == NULL) {
+	if (dev->disconnected) {
 		retval = -ENODEV;
 		pr_err("No device or device unplugged %d\n", retval);
 		goto exit;
@@ -525,7 +528,7 @@
 		goto exit_nolock;
 
 	/* verify that the device wasn't unplugged */
-	if (dev->udev == NULL) {
+	if (dev->disconnected) {
 		retval = -ENODEV;
 		pr_err("No device or device unplugged %d\n", retval);
 		goto exit;
@@ -680,11 +683,11 @@
 
 	mutex_init(&dev->mtx);
 	spin_lock_init(&dev->buflock);
-	dev->udev = udev;
+	dev->udev = usb_get_dev(udev);
 	init_waitqueue_head(&dev->read_wait);
 	init_waitqueue_head(&dev->write_wait);
 
-	iface_desc = &interface->altsetting[0];
+	iface_desc = &interface->cur_altsetting[0];
 
 	/* set up the endpoint information */
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
@@ -800,19 +803,21 @@
 static void adu_disconnect(struct usb_interface *interface)
 {
 	struct adu_device *dev;
-	int minor;
 
 	dev = usb_get_intfdata(interface);
 
-	mutex_lock(&dev->mtx);	/* not interruptible */
-	dev->udev = NULL;	/* poison */
-	minor = dev->minor;
 	usb_deregister_dev(interface, &adu_class);
-	mutex_unlock(&dev->mtx);
+
+	usb_poison_urb(dev->interrupt_in_urb);
+	usb_poison_urb(dev->interrupt_out_urb);
 
 	mutex_lock(&adutux_mutex);
 	usb_set_intfdata(interface, NULL);
 
+	mutex_lock(&dev->mtx);	/* not interruptible */
+	dev->disconnected = 1;
+	mutex_unlock(&dev->mtx);
+
 	/* if the device is not opened, then we clean up right now */
 	if (!dev->open_count)
 		adu_delete(dev);
--- linux-4.4.0.orig/drivers/usb/misc/appledisplay.c
+++ linux-4.4.0/drivers/usb/misc/appledisplay.c
@@ -63,6 +63,8 @@
 	{ APPLEDISPLAY_DEVICE(0x9219) },
 	{ APPLEDISPLAY_DEVICE(0x921c) },
 	{ APPLEDISPLAY_DEVICE(0x921d) },
+	{ APPLEDISPLAY_DEVICE(0x9222) },
+	{ APPLEDISPLAY_DEVICE(0x9226) },
 	{ APPLEDISPLAY_DEVICE(0x9236) },
 
 	/* Terminating entry */
@@ -159,8 +161,11 @@
 		pdata->msgdata, 2,
 		ACD_USB_TIMEOUT);
 	mutex_unlock(&pdata->sysfslock);
-	
-	return retval;
+
+	if (retval < 0)
+		return retval;
+	else
+		return 0;
 }
 
 static int appledisplay_bl_get_brightness(struct backlight_device *bd)
@@ -178,7 +183,12 @@
 		0,
 		pdata->msgdata, 2,
 		ACD_USB_TIMEOUT);
-	brightness = pdata->msgdata[1];
+	if (retval < 2) {
+		if (retval >= 0)
+			retval = -EMSGSIZE;
+	} else {
+		brightness = pdata->msgdata[1];
+	}
 	mutex_unlock(&pdata->sysfslock);
 
 	if (retval < 0)
@@ -324,6 +334,7 @@
 	if (pdata) {
 		if (pdata->urb) {
 			usb_kill_urb(pdata->urb);
+			cancel_delayed_work_sync(&pdata->work);
 			if (pdata->urbdata)
 				usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
 					pdata->urbdata, pdata->urb->transfer_dma);
--- linux-4.4.0.orig/drivers/usb/misc/chaoskey.c
+++ linux-4.4.0/drivers/usb/misc/chaoskey.c
@@ -96,6 +96,7 @@
 	usb_dbg(dev->interface, "free");
 	kfree(dev->name);
 	kfree(dev->buf);
+	usb_put_intf(dev->interface);
 	kfree(dev);
 }
 
@@ -144,6 +145,8 @@
 	if (dev == NULL)
 		return -ENOMEM;
 
+	dev->interface = usb_get_intf(interface);
+
 	dev->buf = kmalloc(size, GFP_KERNEL);
 
 	if (dev->buf == NULL) {
@@ -169,8 +172,6 @@
 		strcat(dev->name, udev->serial);
 	}
 
-	dev->interface = interface;
-
 	dev->in_ep = in_ep;
 
 	dev->size = size;
--- linux-4.4.0.orig/drivers/usb/misc/idmouse.c
+++ linux-4.4.0/drivers/usb/misc/idmouse.c
@@ -342,10 +342,13 @@
 	int result;
 
 	/* check if we have gotten the data or the hid interface */
-	iface_desc = &interface->altsetting[0];
+	iface_desc = interface->cur_altsetting;
 	if (iface_desc->desc.bInterfaceClass != 0x0A)
 		return -ENODEV;
 
+	if (iface_desc->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	/* allocate memory for our device state and initialize it */
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL)
--- linux-4.4.0.orig/drivers/usb/misc/iowarrior.c
+++ linux-4.4.0/drivers/usb/misc/iowarrior.c
@@ -89,6 +89,7 @@
 	char chip_serial[9];		/* the serial number string of the chip connected */
 	int report_size;		/* number of bytes in a report */
 	u16 product_id;
+	struct usb_anchor submitted;
 };
 
 /*--------------*/
@@ -248,6 +249,7 @@
 	kfree(dev->int_in_buffer);
 	usb_free_urb(dev->int_in_urb);
 	kfree(dev->read_queue);
+	usb_put_intf(dev->interface);
 	kfree(dev);
 }
 
@@ -436,11 +438,13 @@
 			retval = -EFAULT;
 			goto error;
 		}
+		usb_anchor_urb(int_out_urb, &dev->submitted);
 		retval = usb_submit_urb(int_out_urb, GFP_KERNEL);
 		if (retval) {
 			dev_dbg(&dev->interface->dev,
 				"submit error %d for urb nr.%d\n",
 				retval, atomic_read(&dev->write_busy));
+			usb_unanchor_urb(int_out_urb);
 			goto error;
 		}
 		/* submit was ok */
@@ -557,7 +561,7 @@
 			info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice);
 
 			/* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */
-			info.speed = le16_to_cpu(dev->udev->speed);
+			info.speed = dev->udev->speed;
 			info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber;
 			info.report_size = dev->report_size;
 
@@ -782,11 +786,13 @@
 	init_waitqueue_head(&dev->write_wait);
 
 	dev->udev = udev;
-	dev->interface = interface;
+	dev->interface = usb_get_intf(interface);
 
 	iface_desc = interface->cur_altsetting;
 	dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
 
+	init_usb_anchor(&dev->submitted);
+
 	/* set up the endpoint information */
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		endpoint = &iface_desc->endpoint[i].desc;
@@ -797,6 +803,21 @@
 			/* this one will match for the IOWarrior56 only */
 			dev->int_out_endpoint = endpoint;
 	}
+
+	if (!dev->int_in_endpoint) {
+		dev_err(&interface->dev, "no interrupt-in endpoint found\n");
+		retval = -ENODEV;
+		goto error;
+	}
+
+	if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) {
+		if (!dev->int_out_endpoint) {
+			dev_err(&interface->dev, "no interrupt-out endpoint found\n");
+			retval = -ENODEV;
+			goto error;
+		}
+	}
+
 	/* we have to check the report_size often, so remember it in the endianness suitable for our machine */
 	dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
 	if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
@@ -885,8 +906,9 @@
 	usb_set_intfdata(interface, NULL);
 
 	minor = dev->minor;
+	mutex_unlock(&iowarrior_open_disc_lock);
+	/* give back our minor - this will call close() locks need to be dropped at this point*/
 
-	/* give back our minor */
 	usb_deregister_dev(interface, &iowarrior_class);
 
 	mutex_lock(&dev->mutex);
@@ -894,19 +916,19 @@
 	/* prevent device read, write and ioctl */
 	dev->present = 0;
 
-	mutex_unlock(&dev->mutex);
-	mutex_unlock(&iowarrior_open_disc_lock);
-
 	if (dev->opened) {
 		/* There is a process that holds a filedescriptor to the device ,
 		   so we only shutdown read-/write-ops going on.
 		   Deleting the device is postponed until close() was called.
 		 */
 		usb_kill_urb(dev->int_in_urb);
+		usb_kill_anchored_urbs(&dev->submitted);
 		wake_up_interruptible(&dev->read_wait);
 		wake_up_interruptible(&dev->write_wait);
+		mutex_unlock(&dev->mutex);
 	} else {
 		/* no process is using the device, cleanup now */
+		mutex_unlock(&dev->mutex);
 		iowarrior_delete(dev);
 	}
 
--- linux-4.4.0.orig/drivers/usb/misc/ldusb.c
+++ linux-4.4.0/drivers/usb/misc/ldusb.c
@@ -46,6 +46,9 @@
 #define USB_DEVICE_ID_LD_MICROCASSYTIME		0x1033	/* USB Product ID of Micro-CASSY Time (reserved) */
 #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE	0x1035	/* USB Product ID of Micro-CASSY Temperature */
 #define USB_DEVICE_ID_LD_MICROCASSYPH		0x1038	/* USB Product ID of Micro-CASSY pH */
+#define USB_DEVICE_ID_LD_POWERANALYSERCASSY	0x1040	/* USB Product ID of Power Analyser CASSY */
+#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY	0x1042	/* USB Product ID of Converter Controller CASSY */
+#define USB_DEVICE_ID_LD_MACHINETESTCASSY	0x1043	/* USB Product ID of Machine Test CASSY */
 #define USB_DEVICE_ID_LD_JWM		0x1080	/* USB Product ID of Joule and Wattmeter */
 #define USB_DEVICE_ID_LD_DMMP		0x1081	/* USB Product ID of Digital Multimeter P (reserved) */
 #define USB_DEVICE_ID_LD_UMIP		0x1090	/* USB Product ID of UMI P */
@@ -88,6 +91,9 @@
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
+	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) },
+	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) },
+	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
@@ -152,6 +158,7 @@
 struct ld_usb {
 	struct mutex		mutex;		/* locks this structure */
 	struct usb_interface*	intf;		/* save off the usb interface pointer */
+	unsigned long		disconnected:1;
 
 	int			open_count;	/* number of times this port has been opened */
 
@@ -191,12 +198,10 @@
 	/* shutdown transfer */
 	if (dev->interrupt_in_running) {
 		dev->interrupt_in_running = 0;
-		if (dev->intf)
-			usb_kill_urb(dev->interrupt_in_urb);
+		usb_kill_urb(dev->interrupt_in_urb);
 	}
 	if (dev->interrupt_out_busy)
-		if (dev->intf)
-			usb_kill_urb(dev->interrupt_out_urb);
+		usb_kill_urb(dev->interrupt_out_urb);
 }
 
 /**
@@ -204,8 +209,6 @@
  */
 static void ld_usb_delete(struct ld_usb *dev)
 {
-	ld_usb_abort_transfers(dev);
-
 	/* free data structures */
 	usb_free_urb(dev->interrupt_in_urb);
 	usb_free_urb(dev->interrupt_out_urb);
@@ -261,7 +264,7 @@
 
 resubmit:
 	/* resubmit if we're still running */
-	if (dev->interrupt_in_running && !dev->buffer_overflow && dev->intf) {
+	if (dev->interrupt_in_running && !dev->buffer_overflow) {
 		retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
 		if (retval) {
 			dev_err(&dev->intf->dev,
@@ -381,16 +384,13 @@
 		goto exit;
 	}
 
-	if (mutex_lock_interruptible(&dev->mutex)) {
-		retval = -ERESTARTSYS;
-		goto exit;
-	}
+	mutex_lock(&dev->mutex);
 
 	if (dev->open_count != 1) {
 		retval = -ENODEV;
 		goto unlock_exit;
 	}
-	if (dev->intf == NULL) {
+	if (dev->disconnected) {
 		/* the device was unplugged before the file was released */
 		mutex_unlock(&dev->mutex);
 		/* unlock here as ld_usb_delete frees dev */
@@ -421,7 +421,7 @@
 
 	dev = file->private_data;
 
-	if (!dev->intf)
+	if (dev->disconnected)
 		return POLLERR | POLLHUP;
 
 	poll_wait(file, &dev->read_wait, wait);
@@ -460,7 +460,7 @@
 	}
 
 	/* verify that the device wasn't unplugged */
-	if (dev->intf == NULL) {
+	if (dev->disconnected) {
 		retval = -ENODEV;
 		printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
 		goto unlock_exit;
@@ -468,7 +468,7 @@
 
 	/* wait for data */
 	spin_lock_irq(&dev->rbsl);
-	if (dev->ring_head == dev->ring_tail) {
+	while (dev->ring_head == dev->ring_tail) {
 		dev->interrupt_in_done = 0;
 		spin_unlock_irq(&dev->rbsl);
 		if (file->f_flags & O_NONBLOCK) {
@@ -478,12 +478,17 @@
 		retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
 		if (retval < 0)
 			goto unlock_exit;
-	} else {
-		spin_unlock_irq(&dev->rbsl);
+
+		spin_lock_irq(&dev->rbsl);
 	}
+	spin_unlock_irq(&dev->rbsl);
 
 	/* actual_buffer contains actual_length + interrupt_in_buffer */
 	actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size));
+	if (*actual_buffer > dev->interrupt_in_endpoint_size) {
+		retval = -EIO;
+		goto unlock_exit;
+	}
 	bytes_to_read = min(count, *actual_buffer);
 	if (bytes_to_read < *actual_buffer)
 		dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
@@ -494,11 +499,11 @@
 		retval = -EFAULT;
 		goto unlock_exit;
 	}
-	dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
-
 	retval = bytes_to_read;
 
 	spin_lock_irq(&dev->rbsl);
+	dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size;
+
 	if (dev->buffer_overflow) {
 		dev->buffer_overflow = 0;
 		spin_unlock_irq(&dev->rbsl);
@@ -540,7 +545,7 @@
 	}
 
 	/* verify that the device wasn't unplugged */
-	if (dev->intf == NULL) {
+	if (dev->disconnected) {
 		retval = -ENODEV;
 		printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
 		goto unlock_exit;
@@ -579,7 +584,7 @@
 					 1 << 8, 0,
 					 dev->interrupt_out_buffer,
 					 bytes_to_write,
-					 USB_CTRL_SET_TIMEOUT * HZ);
+					 USB_CTRL_SET_TIMEOUT);
 		if (retval < 0)
 			dev_err(&dev->intf->dev,
 				"Couldn't submit HID_REQ_SET_REPORT %d\n",
@@ -703,7 +708,9 @@
 		dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
 
 	dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
-	dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL);
+	dev->ring_buffer = kcalloc(ring_buffer_size,
+			sizeof(size_t) + dev->interrupt_in_endpoint_size,
+			GFP_KERNEL);
 	if (!dev->ring_buffer) {
 		dev_err(&intf->dev, "Couldn't allocate ring_buffer\n");
 		goto error;
@@ -776,6 +783,9 @@
 	/* give back our minor */
 	usb_deregister_dev(intf, &ld_usb_class);
 
+	usb_poison_urb(dev->interrupt_in_urb);
+	usb_poison_urb(dev->interrupt_out_urb);
+
 	mutex_lock(&dev->mutex);
 
 	/* if the device is not opened, then we clean up right now */
@@ -783,7 +793,7 @@
 		mutex_unlock(&dev->mutex);
 		ld_usb_delete(dev);
 	} else {
-		dev->intf = NULL;
+		dev->disconnected = 1;
 		/* wake up pollers */
 		wake_up_interruptible_all(&dev->read_wait);
 		wake_up_interruptible_all(&dev->write_wait);
--- linux-4.4.0.orig/drivers/usb/misc/legousbtower.c
+++ linux-4.4.0/drivers/usb/misc/legousbtower.c
@@ -185,7 +185,6 @@
 };
 
 MODULE_DEVICE_TABLE (usb, tower_table);
-static DEFINE_MUTEX(open_disc_mutex);
 
 #define LEGO_USB_TOWER_MINOR_BASE	160
 
@@ -197,6 +196,7 @@
 	unsigned char		minor;		/* the starting minor number for this device */
 
 	int			open_count;	/* number of times this port has been opened */
+	unsigned long		disconnected:1;
 
 	char*			read_buffer;
 	size_t			read_buffer_length; /* this much came in */
@@ -296,14 +296,13 @@
  */
 static inline void tower_delete (struct lego_usb_tower *dev)
 {
-	tower_abort_transfers (dev);
-
 	/* free data structures */
 	usb_free_urb(dev->interrupt_in_urb);
 	usb_free_urb(dev->interrupt_out_urb);
 	kfree (dev->read_buffer);
 	kfree (dev->interrupt_in_buffer);
 	kfree (dev->interrupt_out_buffer);
+	usb_put_dev(dev->udev);
 	kfree (dev);
 }
 
@@ -317,9 +316,16 @@
 	int subminor;
 	int retval = 0;
 	struct usb_interface *interface;
-	struct tower_reset_reply reset_reply;
+	struct tower_reset_reply *reset_reply;
 	int result;
 
+	reset_reply = kmalloc(sizeof(*reset_reply), GFP_KERNEL);
+
+	if (!reset_reply) {
+		retval = -ENOMEM;
+		goto exit;
+	}
+
 	nonseekable_open(inode, file);
 	subminor = iminor(inode);
 
@@ -331,18 +337,14 @@
 		goto exit;
 	}
 
-	mutex_lock(&open_disc_mutex);
 	dev = usb_get_intfdata(interface);
-
 	if (!dev) {
-		mutex_unlock(&open_disc_mutex);
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	/* lock this device */
 	if (mutex_lock_interruptible(&dev->lock)) {
-		mutex_unlock(&open_disc_mutex);
 	        retval = -ERESTARTSYS;
 		goto exit;
 	}
@@ -350,12 +352,9 @@
 
 	/* allow opening only once */
 	if (dev->open_count) {
-		mutex_unlock(&open_disc_mutex);
 		retval = -EBUSY;
 		goto unlock_exit;
 	}
-	dev->open_count = 1;
-	mutex_unlock(&open_disc_mutex);
 
 	/* reset the tower */
 	result = usb_control_msg (dev->udev,
@@ -364,8 +363,8 @@
 				  USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
 				  0,
 				  0,
-				  &reset_reply,
-				  sizeof(reset_reply),
+				  reset_reply,
+				  sizeof(*reset_reply),
 				  1000);
 	if (result < 0) {
 		dev_err(&dev->udev->dev,
@@ -395,17 +394,19 @@
 		dev_err(&dev->udev->dev,
 			"Couldn't submit interrupt_in_urb %d\n", retval);
 		dev->interrupt_in_running = 0;
-		dev->open_count = 0;
 		goto unlock_exit;
 	}
 
 	/* save device in the file's private structure */
 	file->private_data = dev;
 
+	dev->open_count = 1;
+
 unlock_exit:
 	mutex_unlock(&dev->lock);
 
 exit:
+	kfree(reset_reply);
 	return retval;
 }
 
@@ -421,22 +422,19 @@
 
 	if (dev == NULL) {
 		retval = -ENODEV;
-		goto exit_nolock;
-	}
-
-	mutex_lock(&open_disc_mutex);
-	if (mutex_lock_interruptible(&dev->lock)) {
-	        retval = -ERESTARTSYS;
 		goto exit;
 	}
 
+	mutex_lock(&dev->lock);
+
 	if (dev->open_count != 1) {
 		dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n",
 			__func__);
 		retval = -ENODEV;
 		goto unlock_exit;
 	}
-	if (dev->udev == NULL) {
+
+	if (dev->disconnected) {
 		/* the device was unplugged before the file was released */
 
 		/* unlock here as tower_delete frees dev */
@@ -454,10 +452,7 @@
 
 unlock_exit:
 	mutex_unlock(&dev->lock);
-
 exit:
-	mutex_unlock(&open_disc_mutex);
-exit_nolock:
 	return retval;
 }
 
@@ -475,10 +470,9 @@
 	if (dev->interrupt_in_running) {
 		dev->interrupt_in_running = 0;
 		mb();
-		if (dev->udev)
-			usb_kill_urb (dev->interrupt_in_urb);
+		usb_kill_urb(dev->interrupt_in_urb);
 	}
-	if (dev->interrupt_out_busy && dev->udev)
+	if (dev->interrupt_out_busy)
 		usb_kill_urb(dev->interrupt_out_urb);
 }
 
@@ -514,7 +508,7 @@
 
 	dev = file->private_data;
 
-	if (!dev->udev)
+	if (dev->disconnected)
 		return POLLERR | POLLHUP;
 
 	poll_wait(file, &dev->read_wait, wait);
@@ -561,7 +555,7 @@
 	}
 
 	/* verify that the device wasn't unplugged */
-	if (dev->udev == NULL) {
+	if (dev->disconnected) {
 		retval = -ENODEV;
 		pr_err("No device or device unplugged %d\n", retval);
 		goto unlock_exit;
@@ -647,7 +641,7 @@
 	}
 
 	/* verify that the device wasn't unplugged */
-	if (dev->udev == NULL) {
+	if (dev->disconnected) {
 		retval = -ENODEV;
 		pr_err("No device or device unplugged %d\n", retval);
 		goto unlock_exit;
@@ -756,7 +750,7 @@
 
 resubmit:
 	/* resubmit if we're still running */
-	if (dev->interrupt_in_running && dev->udev) {
+	if (dev->interrupt_in_running) {
 		retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
 		if (retval)
 			dev_err(&dev->udev->dev,
@@ -808,7 +802,7 @@
 	struct lego_usb_tower *dev = NULL;
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor* endpoint;
-	struct tower_get_version_reply get_version_reply;
+	struct tower_get_version_reply *get_version_reply = NULL;
 	int i;
 	int retval = -ENOMEM;
 	int result;
@@ -824,8 +818,9 @@
 
 	mutex_init(&dev->lock);
 
-	dev->udev = udev;
+	dev->udev = usb_get_dev(udev);
 	dev->open_count = 0;
+	dev->disconnected = 0;
 
 	dev->read_buffer = NULL;
 	dev->read_buffer_length = 0;
@@ -898,23 +893,12 @@
 	dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
 	dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
 
-	/* we can register the device now, as it is ready */
-	usb_set_intfdata (interface, dev);
-
-	retval = usb_register_dev (interface, &tower_class);
+	get_version_reply = kmalloc(sizeof(*get_version_reply), GFP_KERNEL);
 
-	if (retval) {
-		/* something prevented us from registering this driver */
-		dev_err(idev, "Not able to get a minor for this device.\n");
-		usb_set_intfdata (interface, NULL);
+	if (!get_version_reply) {
+		retval = -ENOMEM;
 		goto error;
 	}
-	dev->minor = interface->minor;
-
-	/* let the user know what node this device is now attached to */
-	dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major "
-		 "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE),
-		 USB_MAJOR, dev->minor);
 
 	/* get the firmware version and log it */
 	result = usb_control_msg (udev,
@@ -923,24 +907,45 @@
 				  USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
 				  0,
 				  0,
-				  &get_version_reply,
-				  sizeof(get_version_reply),
+				  get_version_reply,
+				  sizeof(*get_version_reply),
 				  1000);
-	if (result < 0) {
-		dev_err(idev, "LEGO USB Tower get version control request failed\n");
+	if (result != sizeof(*get_version_reply)) {
+		if (result >= 0)
+			result = -EIO;
+		dev_err(idev, "get version request failed: %d\n", result);
 		retval = result;
 		goto error;
 	}
-	dev_info(&interface->dev, "LEGO USB Tower firmware version is %d.%d "
-		 "build %d\n", get_version_reply.major,
-		 get_version_reply.minor,
-		 le16_to_cpu(get_version_reply.build_no));
+	dev_info(&interface->dev,
+		 "LEGO USB Tower firmware version is %d.%d build %d\n",
+		 get_version_reply->major,
+		 get_version_reply->minor,
+		 le16_to_cpu(get_version_reply->build_no));
+
+	/* we can register the device now, as it is ready */
+	usb_set_intfdata (interface, dev);
 
+	retval = usb_register_dev (interface, &tower_class);
+
+	if (retval) {
+		/* something prevented us from registering this driver */
+		dev_err(idev, "Not able to get a minor for this device.\n");
+		goto error;
+	}
+	dev->minor = interface->minor;
+
+	/* let the user know what node this device is now attached to */
+	dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major "
+		 "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE),
+		 USB_MAJOR, dev->minor);
 
 exit:
+	kfree(get_version_reply);
 	return retval;
 
 error:
+	kfree(get_version_reply);
 	tower_delete(dev);
 	return retval;
 }
@@ -957,23 +962,24 @@
 	int minor;
 
 	dev = usb_get_intfdata (interface);
-	mutex_lock(&open_disc_mutex);
-	usb_set_intfdata (interface, NULL);
 
 	minor = dev->minor;
 
-	/* give back our minor */
+	/* give back our minor and prevent further open() */
 	usb_deregister_dev (interface, &tower_class);
 
+	/* stop I/O */
+	usb_poison_urb(dev->interrupt_in_urb);
+	usb_poison_urb(dev->interrupt_out_urb);
+
 	mutex_lock(&dev->lock);
-	mutex_unlock(&open_disc_mutex);
 
 	/* if the device is not opened, then we clean up right now */
 	if (!dev->open_count) {
 		mutex_unlock(&dev->lock);
 		tower_delete (dev);
 	} else {
-		dev->udev = NULL;
+		dev->disconnected = 1;
 		/* wake up pollers */
 		wake_up_interruptible_all(&dev->read_wait);
 		wake_up_interruptible_all(&dev->write_wait);
--- linux-4.4.0.orig/drivers/usb/misc/lvstest.c
+++ linux-4.4.0/drivers/usb/misc/lvstest.c
@@ -370,6 +370,10 @@
 
 	hdev = interface_to_usbdev(intf);
 	desc = intf->cur_altsetting;
+
+	if (desc->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	endpoint = &desc->endpoint[0].desc;
 
 	/* valid only for SS root hub */
@@ -392,7 +396,7 @@
 			USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT);
 	if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) {
 		dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret);
-		return ret;
+		return ret < 0 ? ret : -EINVAL;
 	}
 
 	/* submit urb to poll interrupt endpoint */
--- linux-4.4.0.orig/drivers/usb/misc/sisusbvga/Kconfig
+++ linux-4.4.0/drivers/usb/misc/sisusbvga/Kconfig
@@ -15,7 +15,7 @@
 
 config USB_SISUSBVGA_CON
 	bool "Text console and mode switching support" if USB_SISUSBVGA
-	depends on VT
+	depends on VT && BROKEN
 	select FONT_8x16
 	---help---
 	  Say Y here if you want a VGA text console via the USB dongle or
--- linux-4.4.0.orig/drivers/usb/misc/sisusbvga/sisusb.c
+++ linux-4.4.0/drivers/usb/misc/sisusbvga/sisusb.c
@@ -790,7 +790,7 @@
 	u8   swap8, fromkern = kernbuffer ? 1 : 0;
 	u16  swap16;
 	u32  swap32, flag = (length >> 28) & 1;
-	char buf[4];
+	u8 buf[4];
 
 	/* if neither kernbuffer not userbuffer are given, assume
 	 * data in obuf
@@ -1243,20 +1243,20 @@
 
 #ifdef INCL_SISUSB_CON
 int
-sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
+sisusb_setreg(struct sisusb_usb_data *sisusb, u32 port, u8 data)
 {
 	return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
 }
 
 int
-sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
+sisusb_getreg(struct sisusb_usb_data *sisusb, u32 port, u8 *data)
 {
 	return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
 }
 #endif
 
 int
-sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
+sisusb_setidxreg(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 data)
 {
 	int ret;
 	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
@@ -1265,7 +1265,7 @@
 }
 
 int
-sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
+sisusb_getidxreg(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 *data)
 {
 	int ret;
 	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
@@ -1274,7 +1274,7 @@
 }
 
 int
-sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
+sisusb_setidxregandor(struct sisusb_usb_data *sisusb, u32 port, u8 idx,
 							u8 myand, u8 myor)
 {
 	int ret;
@@ -1289,7 +1289,7 @@
 }
 
 static int
-sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
+sisusb_setidxregmask(struct sisusb_usb_data *sisusb, u32 port, u8 idx,
 							u8 data, u8 mask)
 {
 	int ret;
@@ -1303,13 +1303,13 @@
 }
 
 int
-sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
+sisusb_setidxregor(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 myor)
 {
 	return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
 }
 
 int
-sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
+sisusb_setidxregand(struct sisusb_usb_data *sisusb, u32 port, u8 idx, u8 myand)
 {
 	return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
 }
@@ -2849,8 +2849,8 @@
 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 							unsigned long arg)
 {
-	int	retval, port, length;
-	u32	address;
+	int	retval, length;
+	u32	port, address;
 
 	/* All our commands require the device
 	 * to be initialized.
@@ -3103,6 +3103,13 @@
 
 	mutex_init(&(sisusb->lock));
 
+	sisusb->sisusb_dev = dev;
+	sisusb->vrambase   = SISUSB_PCI_MEMBASE;
+	sisusb->mmiobase   = SISUSB_PCI_MMIOBASE;
+	sisusb->mmiosize   = SISUSB_PCI_MMIOSIZE;
+	sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
+	/* Everything else is zero */
+
 	/* Register device */
 	retval = usb_register_dev(intf, &usb_sisusb_class);
 	if (retval) {
@@ -3112,13 +3119,7 @@
 		goto error_1;
 	}
 
-	sisusb->sisusb_dev = dev;
-	sisusb->minor      = intf->minor;
-	sisusb->vrambase   = SISUSB_PCI_MEMBASE;
-	sisusb->mmiobase   = SISUSB_PCI_MMIOBASE;
-	sisusb->mmiosize   = SISUSB_PCI_MMIOSIZE;
-	sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
-	/* Everything else is zero */
+	sisusb->minor = intf->minor;
 
 	/* Allocate buffers */
 	sisusb->ibufsize = SISUSB_IBUF_SIZE;
--- linux-4.4.0.orig/drivers/usb/misc/sisusbvga/sisusb_init.h
+++ linux-4.4.0/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -811,17 +811,17 @@
 int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
 int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
 
-extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
-extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, u32 port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, u32 port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, u32 port,
 			    u8 index, u8 data);
-extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, u32 port,
 			    u8 index, u8 * data);
-extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, u32 port,
 				 u8 idx, u8 myand, u8 myor);
-extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, u32 port,
 			      u8 index, u8 myor);
-extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, u32 port,
 			       u8 idx, u8 myand);
 
 void sisusb_delete(struct kref *kref);
--- linux-4.4.0.orig/drivers/usb/misc/usb3503.c
+++ linux-4.4.0/drivers/usb/misc/usb3503.c
@@ -292,6 +292,8 @@
 	if (gpio_is_valid(hub->gpio_reset)) {
 		err = devm_gpio_request_one(dev, hub->gpio_reset,
 				GPIOF_OUT_INIT_LOW, "usb3503 reset");
+		/* Datasheet defines a hardware reset to be at least 100us */
+		usleep_range(100, 10000);
 		if (err) {
 			dev_err(dev,
 				"unable to request GPIO %d as reset pin (%d)\n",
--- linux-4.4.0.orig/drivers/usb/misc/usblcd.c
+++ linux-4.4.0/drivers/usb/misc/usblcd.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/mutex.h>
+#include <linux/rwsem.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 
@@ -56,6 +57,8 @@
 							   using up all RAM */
 	struct usb_anchor	submitted;		/* URBs to wait for
 							   before suspend */
+	struct rw_semaphore	io_rwsem;
+	unsigned long		disconnected:1;
 };
 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
 
@@ -141,6 +144,13 @@
 
 	dev = file->private_data;
 
+	down_read(&dev->io_rwsem);
+
+	if (dev->disconnected) {
+		retval = -ENODEV;
+		goto out_up_io;
+	}
+
 	/* do a blocking bulk read to get data from the device */
 	retval = usb_bulk_msg(dev->udev,
 			      usb_rcvbulkpipe(dev->udev,
@@ -157,6 +167,9 @@
 			retval = bytes_read;
 	}
 
+out_up_io:
+	up_read(&dev->io_rwsem);
+
 	return retval;
 }
 
@@ -236,11 +249,18 @@
 	if (r < 0)
 		return -EINTR;
 
+	down_read(&dev->io_rwsem);
+
+	if (dev->disconnected) {
+		retval = -ENODEV;
+		goto err_up_io;
+	}
+
 	/* create a urb, and a buffer for it, and copy the data to the urb */
 	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb) {
 		retval = -ENOMEM;
-		goto err_no_buf;
+		goto err_up_io;
 	}
 
 	buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL,
@@ -277,6 +297,7 @@
 	   the USB core will eventually free it entirely */
 	usb_free_urb(urb);
 
+	up_read(&dev->io_rwsem);
 exit:
 	return count;
 error_unanchor:
@@ -284,7 +305,8 @@
 error:
 	usb_free_coherent(dev->udev, count, buf, urb->transfer_dma);
 	usb_free_urb(urb);
-err_no_buf:
+err_up_io:
+	up_read(&dev->io_rwsem);
 	up(&dev->limit_sem);
 	return retval;
 }
@@ -327,6 +349,7 @@
 	}
 	kref_init(&dev->kref);
 	sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
+	init_rwsem(&dev->io_rwsem);
 	init_usb_anchor(&dev->submitted);
 
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -437,6 +460,12 @@
 	/* give back our minor */
 	usb_deregister_dev(interface, &lcd_class);
 
+	down_write(&dev->io_rwsem);
+	dev->disconnected = 1;
+	up_write(&dev->io_rwsem);
+
+	usb_kill_anchored_urbs(&dev->submitted);
+
 	/* decrement our usage count */
 	kref_put(&dev->kref, lcd_delete);
 
--- linux-4.4.0.orig/drivers/usb/misc/usbtest.c
+++ linux-4.4.0/drivers/usb/misc/usbtest.c
@@ -135,6 +135,7 @@
 			case USB_ENDPOINT_XFER_INT:
 				if (dev->info->intr)
 					goto try_intr;
+				continue;
 			case USB_ENDPOINT_XFER_ISOC:
 				if (dev->info->iso)
 					goto try_iso;
@@ -184,12 +185,13 @@
 			return tmp;
 	}
 
-	if (in) {
+	if (in)
 		dev->in_pipe = usb_rcvbulkpipe(udev,
 			in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	if (out)
 		dev->out_pipe = usb_sndbulkpipe(udev,
 			out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-	}
+
 	if (iso_in) {
 		dev->iso_in = &iso_in->desc;
 		dev->in_iso_pipe = usb_rcvisocpipe(udev,
@@ -505,6 +507,7 @@
 alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe)
 {
 	struct scatterlist	*sg;
+	unsigned int		n_size = 0;
 	unsigned		i;
 	unsigned		size = max;
 	unsigned		maxpacket =
@@ -537,7 +540,8 @@
 			break;
 		case 1:
 			for (j = 0; j < size; j++)
-				*buf++ = (u8) ((j % maxpacket) % 63);
+				*buf++ = (u8) (((j + n_size) % maxpacket) % 63);
+			n_size += size;
 			break;
 		}
 
@@ -556,7 +560,6 @@
 {
 	struct usb_sg_request	*req = (struct usb_sg_request *) _req;
 
-	req->status = -ETIMEDOUT;
 	usb_sg_cancel(req);
 }
 
@@ -587,8 +590,10 @@
 		mod_timer(&sg_timer, jiffies +
 				msecs_to_jiffies(SIMPLE_IO_TIMEOUT));
 		usb_sg_wait(req);
-		del_timer_sync(&sg_timer);
-		retval = req->status;
+		if (!del_timer_sync(&sg_timer))
+			retval = -ETIMEDOUT;
+		else
+			retval = req->status;
 
 		/* FIXME check resulting data pattern */
 
@@ -2698,6 +2703,7 @@
 
 	usb_set_intfdata(intf, NULL);
 	dev_dbg(&intf->dev, "disconnect\n");
+	kfree(dev->buf);
 	kfree(dev);
 }
 
--- linux-4.4.0.orig/drivers/usb/misc/uss720.c
+++ linux-4.4.0/drivers/usb/misc/uss720.c
@@ -87,6 +87,7 @@
 
 	dev_dbg(&priv->usbdev->dev, "destroying priv datastructure\n");
 	usb_put_dev(priv->usbdev);
+	priv->usbdev = NULL;
 	kfree(priv);
 }
 
@@ -388,7 +389,7 @@
 	mask &= 0x0f;
 	val &= 0x0f;
 	d = (priv->reg[1] & (~mask)) ^ val;
-	if (set_1284_register(pp, 2, d, GFP_KERNEL))
+	if (set_1284_register(pp, 2, d, GFP_ATOMIC))
 		return 0;
 	priv->reg[1] = d;
 	return d & 0xf;
@@ -398,7 +399,7 @@
 {
 	unsigned char ret;
 
-	if (get_1284_register(pp, 1, &ret, GFP_KERNEL))
+	if (get_1284_register(pp, 1, &ret, GFP_ATOMIC))
 		return 0;
 	return ret & 0xf8;
 }
@@ -711,6 +712,11 @@
 
 	interface = intf->cur_altsetting;
 
+	if (interface->desc.bNumEndpoints < 3) {
+		usb_put_dev(usbdev);
+		return -ENODEV;
+	}
+
 	/*
 	 * Allocate parport interface 
 	 */
@@ -760,14 +766,11 @@
 {
 	struct parport *pp = usb_get_intfdata(intf);
 	struct parport_uss720_private *priv;
-	struct usb_device *usbdev;
 
 	dev_dbg(&intf->dev, "disconnect\n");
 	usb_set_intfdata(intf, NULL);
 	if (pp) {
 		priv = pp->private_data;
-		usbdev = priv->usbdev;
-		priv->usbdev = NULL;
 		priv->pp = NULL;
 		dev_dbg(&intf->dev, "parport_remove_port\n");
 		parport_remove_port(pp);
--- linux-4.4.0.orig/drivers/usb/misc/yurex.c
+++ linux-4.4.0/drivers/usb/misc/yurex.c
@@ -64,6 +64,7 @@
 
 	struct kref		kref;
 	struct mutex		io_mutex;
+	unsigned long		disconnected:1;
 	struct fasync_struct	*async_queue;
 	wait_queue_head_t	waitq;
 
@@ -96,7 +97,6 @@
 
 	dev_dbg(&dev->interface->dev, "%s\n", __func__);
 
-	usb_put_dev(dev->udev);
 	if (dev->cntl_urb) {
 		usb_kill_urb(dev->cntl_urb);
 		kfree(dev->cntl_req);
@@ -112,6 +112,8 @@
 				dev->int_buffer, dev->urb->transfer_dma);
 		usb_free_urb(dev->urb);
 	}
+	usb_put_intf(dev->interface);
+	usb_put_dev(dev->udev);
 	kfree(dev);
 }
 
@@ -136,6 +138,7 @@
 	switch (status) {
 	case 0: /*success*/
 		break;
+	/* The device is terminated or messed up, give up */
 	case -EOVERFLOW:
 		dev_err(&dev->interface->dev,
 			"%s - overflow with length %d, actual length is %d\n",
@@ -144,12 +147,13 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 	case -EILSEQ:
-		/* The device is terminated, clean up */
+	case -EPROTO:
+	case -ETIME:
 		return;
 	default:
 		dev_err(&dev->interface->dev,
 			"%s - unknown status received: %d\n", __func__, status);
-		goto exit;
+		return;
 	}
 
 	/* handle received message */
@@ -181,7 +185,6 @@
 		break;
 	}
 
-exit:
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
 	if (retval) {
 		dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n",
@@ -210,7 +213,7 @@
 	init_waitqueue_head(&dev->waitq);
 
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
-	dev->interface = interface;
+	dev->interface = usb_get_intf(interface);
 
 	/* set up the endpoint information */
 	iface_desc = interface->cur_altsetting;
@@ -332,8 +335,10 @@
 	usb_deregister_dev(interface, &yurex_class);
 
 	/* prevent more I/O from starting */
+	usb_poison_urb(dev->urb);
+	usb_poison_urb(dev->cntl_urb);
 	mutex_lock(&dev->io_mutex);
-	dev->interface = NULL;
+	dev->disconnected = 1;
 	mutex_unlock(&dev->io_mutex);
 
 	/* wakeup waiters */
@@ -414,35 +419,27 @@
 			  loff_t *ppos)
 {
 	struct usb_yurex *dev;
-	int retval = 0;
-	int bytes_read = 0;
+	int len = 0;
 	char in_buffer[20];
 	unsigned long flags;
 
 	dev = file->private_data;
 
 	mutex_lock(&dev->io_mutex);
-	if (!dev->interface) {		/* already disconnected */
-		retval = -ENODEV;
-		goto exit;
+	if (dev->disconnected) {		/* already disconnected */
+		mutex_unlock(&dev->io_mutex);
+		return -ENODEV;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
-	bytes_read = snprintf(in_buffer, 20, "%lld\n", dev->bbu);
+	len = snprintf(in_buffer, 20, "%lld\n", dev->bbu);
 	spin_unlock_irqrestore(&dev->lock, flags);
+	mutex_unlock(&dev->io_mutex);
 
-	if (*ppos < bytes_read) {
-		if (copy_to_user(buffer, in_buffer + *ppos, bytes_read - *ppos))
-			retval = -EFAULT;
-		else {
-			retval = bytes_read - *ppos;
-			*ppos += bytes_read;
-		}
-	}
+	if (WARN_ON_ONCE(len >= sizeof(in_buffer)))
+		return -EIO;
 
-exit:
-	mutex_unlock(&dev->io_mutex);
-	return retval;
+	return simple_read_from_buffer(buffer, count, ppos, in_buffer, len);
 }
 
 static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
@@ -450,13 +447,13 @@
 {
 	struct usb_yurex *dev;
 	int i, set = 0, retval = 0;
-	char buffer[16];
+	char buffer[16 + 1];
 	char *data = buffer;
 	unsigned long long c, c2 = 0;
 	signed long timeout = 0;
 	DEFINE_WAIT(wait);
 
-	count = min(sizeof(buffer), count);
+	count = min(sizeof(buffer) - 1, count);
 	dev = file->private_data;
 
 	/* verify that we actually have some data to write */
@@ -464,7 +461,7 @@
 		goto error;
 
 	mutex_lock(&dev->io_mutex);
-	if (!dev->interface) {		/* already disconnected */
+	if (dev->disconnected) {		/* already disconnected */
 		mutex_unlock(&dev->io_mutex);
 		retval = -ENODEV;
 		goto error;
@@ -475,6 +472,7 @@
 		retval = -EFAULT;
 		goto error;
 	}
+	buffer[count] = 0;
 	memset(dev->cntl_buffer, CMD_PADDING, YUREX_BUF_SIZE);
 
 	switch (buffer[0]) {
@@ -512,11 +510,14 @@
 	prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE);
 	dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__,
 		dev->cntl_buffer[0]);
-	retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL);
+	retval = usb_submit_urb(dev->cntl_urb, GFP_ATOMIC);
 	if (retval >= 0)
 		timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
 	finish_wait(&dev->waitq, &wait);
 
+	/* make sure URB is idle after timeout or (spurious) CMD_ACK */
+	usb_kill_urb(dev->cntl_urb);
+
 	mutex_unlock(&dev->io_mutex);
 
 	if (retval < 0) {
--- linux-4.4.0.orig/drivers/usb/mon/mon_bin.c
+++ linux-4.4.0/drivers/usb/mon/mon_bin.c
@@ -1001,7 +1001,9 @@
 		break;
 
 	case MON_IOCQ_RING_SIZE:
+		mutex_lock(&rp->fetch_lock);
 		ret = rp->b_size;
+		mutex_unlock(&rp->fetch_lock);
 		break;
 
 	case MON_IOCT_RING_SIZE:
@@ -1033,12 +1035,18 @@
 
 		mutex_lock(&rp->fetch_lock);
 		spin_lock_irqsave(&rp->b_lock, flags);
-		mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
-		kfree(rp->b_vec);
-		rp->b_vec  = vec;
-		rp->b_size = size;
-		rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
-		rp->cnt_lost = 0;
+		if (rp->mmap_active) {
+			mon_free_buff(vec, size/CHUNK_SIZE);
+			kfree(vec);
+			ret = -EBUSY;
+		} else {
+			mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+			kfree(rp->b_vec);
+			rp->b_vec  = vec;
+			rp->b_size = size;
+			rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+			rp->cnt_lost = 0;
+		}
 		spin_unlock_irqrestore(&rp->b_lock, flags);
 		mutex_unlock(&rp->fetch_lock);
 		}
@@ -1210,13 +1218,21 @@
 static void mon_bin_vma_open(struct vm_area_struct *vma)
 {
 	struct mon_reader_bin *rp = vma->vm_private_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rp->b_lock, flags);
 	rp->mmap_active++;
+	spin_unlock_irqrestore(&rp->b_lock, flags);
 }
 
 static void mon_bin_vma_close(struct vm_area_struct *vma)
 {
+	unsigned long flags;
+
 	struct mon_reader_bin *rp = vma->vm_private_data;
+	spin_lock_irqsave(&rp->b_lock, flags);
 	rp->mmap_active--;
+	spin_unlock_irqrestore(&rp->b_lock, flags);
 }
 
 /*
@@ -1248,6 +1264,11 @@
 {
 	/* don't do anything here: "fault" will set up page table entries */
 	vma->vm_ops = &mon_bin_vm_ops;
+
+	if (vma->vm_flags & VM_WRITE)
+		return -EPERM;
+
+	vma->vm_flags &= ~VM_MAYWRITE;
 	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 	vma->vm_private_data = filp->private_data;
 	mon_bin_vma_open(vma);
--- linux-4.4.0.orig/drivers/usb/mon/mon_text.c
+++ linux-4.4.0/drivers/usb/mon/mon_text.c
@@ -82,6 +82,8 @@
 
 	wait_queue_head_t wait;
 	int printf_size;
+	size_t printf_offset;
+	size_t printf_togo;
 	char *printf_buf;
 	struct mutex printf_lock;
 
@@ -373,73 +375,103 @@
 	return rc;
 }
 
-/*
- * For simplicity, we read one record in one system call and throw out
- * what does not fit. This means that the following does not work:
- *   dd if=/dbg/usbmon/0t bs=10
- * Also, we do not allow seeks and do not bother advancing the offset.
- */
+static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp,
+    char __user * const buf, const size_t nbytes)
+{
+	const size_t togo = min(nbytes, rp->printf_togo);
+
+	if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo))
+		return -EFAULT;
+	rp->printf_togo -= togo;
+	rp->printf_offset += togo;
+	return togo;
+}
+
+/* ppos is not advanced since the llseek operation is not permitted. */
 static ssize_t mon_text_read_t(struct file *file, char __user *buf,
-				size_t nbytes, loff_t *ppos)
+    size_t nbytes, loff_t *ppos)
 {
 	struct mon_reader_text *rp = file->private_data;
 	struct mon_event_text *ep;
 	struct mon_text_ptr ptr;
+	ssize_t ret;
 
-	if (IS_ERR(ep = mon_text_read_wait(rp, file)))
-		return PTR_ERR(ep);
 	mutex_lock(&rp->printf_lock);
-	ptr.cnt = 0;
-	ptr.pbuf = rp->printf_buf;
-	ptr.limit = rp->printf_size;
-
-	mon_text_read_head_t(rp, &ptr, ep);
-	mon_text_read_statset(rp, &ptr, ep);
-	ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
-	    " %d", ep->length);
-	mon_text_read_data(rp, &ptr, ep);
 
-	if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
-		ptr.cnt = -EFAULT;
+	if (rp->printf_togo == 0) {
+
+		ep = mon_text_read_wait(rp, file);
+		if (IS_ERR(ep)) {
+			mutex_unlock(&rp->printf_lock);
+			return PTR_ERR(ep);
+		}
+		ptr.cnt = 0;
+		ptr.pbuf = rp->printf_buf;
+		ptr.limit = rp->printf_size;
+
+		mon_text_read_head_t(rp, &ptr, ep);
+		mon_text_read_statset(rp, &ptr, ep);
+		ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+		    " %d", ep->length);
+		mon_text_read_data(rp, &ptr, ep);
+
+		rp->printf_togo = ptr.cnt;
+		rp->printf_offset = 0;
+
+		kmem_cache_free(rp->e_slab, ep);
+	}
+
+	ret = mon_text_copy_to_user(rp, buf, nbytes);
 	mutex_unlock(&rp->printf_lock);
-	kmem_cache_free(rp->e_slab, ep);
-	return ptr.cnt;
+	return ret;
 }
 
+/* ppos is not advanced since the llseek operation is not permitted. */
 static ssize_t mon_text_read_u(struct file *file, char __user *buf,
-				size_t nbytes, loff_t *ppos)
+    size_t nbytes, loff_t *ppos)
 {
 	struct mon_reader_text *rp = file->private_data;
 	struct mon_event_text *ep;
 	struct mon_text_ptr ptr;
+	ssize_t ret;
 
-	if (IS_ERR(ep = mon_text_read_wait(rp, file)))
-		return PTR_ERR(ep);
 	mutex_lock(&rp->printf_lock);
-	ptr.cnt = 0;
-	ptr.pbuf = rp->printf_buf;
-	ptr.limit = rp->printf_size;
 
-	mon_text_read_head_u(rp, &ptr, ep);
-	if (ep->type == 'E') {
-		mon_text_read_statset(rp, &ptr, ep);
-	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
-		mon_text_read_isostat(rp, &ptr, ep);
-		mon_text_read_isodesc(rp, &ptr, ep);
-	} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
-		mon_text_read_intstat(rp, &ptr, ep);
-	} else {
-		mon_text_read_statset(rp, &ptr, ep);
+	if (rp->printf_togo == 0) {
+
+		ep = mon_text_read_wait(rp, file);
+		if (IS_ERR(ep)) {
+			mutex_unlock(&rp->printf_lock);
+			return PTR_ERR(ep);
+		}
+		ptr.cnt = 0;
+		ptr.pbuf = rp->printf_buf;
+		ptr.limit = rp->printf_size;
+
+		mon_text_read_head_u(rp, &ptr, ep);
+		if (ep->type == 'E') {
+			mon_text_read_statset(rp, &ptr, ep);
+		} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
+			mon_text_read_isostat(rp, &ptr, ep);
+			mon_text_read_isodesc(rp, &ptr, ep);
+		} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
+			mon_text_read_intstat(rp, &ptr, ep);
+		} else {
+			mon_text_read_statset(rp, &ptr, ep);
+		}
+		ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+		    " %d", ep->length);
+		mon_text_read_data(rp, &ptr, ep);
+
+		rp->printf_togo = ptr.cnt;
+		rp->printf_offset = 0;
+
+		kmem_cache_free(rp->e_slab, ep);
 	}
-	ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
-	    " %d", ep->length);
-	mon_text_read_data(rp, &ptr, ep);
 
-	if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
-		ptr.cnt = -EFAULT;
+	ret = mon_text_copy_to_user(rp, buf, nbytes);
 	mutex_unlock(&rp->printf_lock);
-	kmem_cache_free(rp->e_slab, ep);
-	return ptr.cnt;
+	return ret;
 }
 
 static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
--- linux-4.4.0.orig/drivers/usb/musb/blackfin.c
+++ linux-4.4.0/drivers/usb/musb/blackfin.c
@@ -469,6 +469,7 @@
 	.init		= bfin_musb_init,
 	.exit		= bfin_musb_exit,
 
+	.fifo_offset	= bfin_fifo_offset,
 	.readb		= bfin_readb,
 	.writeb		= bfin_writeb,
 	.readw		= bfin_readw,
--- linux-4.4.0.orig/drivers/usb/musb/da8xx.c
+++ linux-4.4.0/drivers/usb/musb/da8xx.c
@@ -350,7 +350,15 @@
 			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
 			portstate(musb->port1_status |= USB_PORT_STAT_POWER);
 			del_timer(&otg_workaround);
-		} else {
+		} else if (!(musb->int_usb & MUSB_INTR_BABBLE)){
+			/*
+			 * When babble condition happens, drvvbus interrupt
+			 * is also generated. Ignore this drvvbus interrupt
+			 * and let babble interrupt handler recovers the
+			 * controller; otherwise, the host-mode flag is lost
+			 * due to the MUSB_DEV_MODE() call below and babble
+			 * recovery logic will not called.
+			 */
 			musb->is_active = 0;
 			MUSB_DEV_MODE(musb);
 			otg->default_a = 0;
@@ -458,15 +466,11 @@
 }
 
 static const struct musb_platform_ops da8xx_ops = {
-	.quirks		= MUSB_DMA_CPPI | MUSB_INDEXED_EP,
+	.quirks		= MUSB_INDEXED_EP,
 	.init		= da8xx_musb_init,
 	.exit		= da8xx_musb_exit,
 
 	.fifo_mode	= 2,
-#ifdef CONFIG_USB_TI_CPPI_DMA
-	.dma_init	= cppi_dma_controller_create,
-	.dma_exit	= cppi_dma_controller_destroy,
-#endif
 	.enable		= da8xx_musb_enable,
 	.disable	= da8xx_musb_disable,
 
--- linux-4.4.0.orig/drivers/usb/musb/musb_core.c
+++ linux-4.4.0/drivers/usb/musb/musb_core.c
@@ -877,7 +877,7 @@
 	 */
 	if (int_usb & MUSB_INTR_RESET) {
 		handled = IRQ_HANDLED;
-		if (devctl & MUSB_DEVCTL_HM) {
+		if (is_host_active(musb)) {
 			/*
 			 * When BABBLE happens what we can depends on which
 			 * platform MUSB is running, because some platforms
@@ -887,9 +887,7 @@
 			 * drop the session.
 			 */
 			dev_err(musb->controller, "Babble\n");
-
-			if (is_host_active(musb))
-				musb_recover_from_babble(musb);
+			musb_recover_from_babble(musb);
 		} else {
 			dev_dbg(musb->controller, "BUS RESET as %s\n",
 				usb_otg_state_string(musb->xceiv->otg->state));
@@ -1777,6 +1775,7 @@
 	int		vbus;
 	u8		devctl;
 
+	pm_runtime_get_sync(dev);
 	spin_lock_irqsave(&musb->lock, flags);
 	val = musb->a_wait_bcon;
 	vbus = musb_platform_get_vbus_status(musb);
@@ -1790,6 +1789,7 @@
 			vbus = 0;
 	}
 	spin_unlock_irqrestore(&musb->lock, flags);
+	pm_runtime_put_sync(dev);
 
 	return sprintf(buf, "Vbus %s, timeout %lu msec\n",
 			vbus ? "on" : "off", val);
@@ -2132,6 +2132,9 @@
 	musb_platform_disable(musb);
 	musb_generic_disable(musb);
 
+	/* MUSB_POWER_SOFTCONN might be already set, JZ4740 does this. */
+	musb_writeb(musb->mregs, MUSB_POWER, 0);
+
 	/* Init IRQ workqueue before request_irq */
 	INIT_WORK(&musb->irq_work, musb_irq_work);
 	INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset);
@@ -2401,7 +2404,8 @@
 	musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);
 	musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);
 	musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
-	musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
+	if (musb->context.devctl & MUSB_DEVCTL_SESSION)
+		musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
 
 	for (i = 0; i < musb->config->num_eps; ++i) {
 		struct musb_hw_ep	*hw_ep;
@@ -2523,7 +2527,8 @@
 	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
 
-	musb_start(musb);
+	musb_enable_interrupts(musb);
+	musb_platform_enable(musb);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/usb/musb/musb_core.h
+++ linux-4.4.0/drivers/usb/musb/musb_core.h
@@ -214,6 +214,7 @@
 				dma_addr_t *dma_addr, u32 *len);
 	void	(*pre_root_reset_end)(struct musb *musb);
 	void	(*post_root_reset_end)(struct musb *musb);
+	void	(*clear_ep_rxintr)(struct musb *musb, int epnum);
 };
 
 /*
@@ -612,4 +613,10 @@
 		musb->ops->post_root_reset_end(musb);
 }
 
+static inline void musb_platform_clear_ep_rxintr(struct musb *musb, int epnum)
+{
+	if (musb->ops->clear_ep_rxintr)
+		musb->ops->clear_ep_rxintr(musb, epnum);
+}
+
 #endif	/* __MUSB_CORE_H__ */
--- linux-4.4.0.orig/drivers/usb/musb/musb_cppi41.c
+++ linux-4.4.0/drivers/usb/musb/musb_cppi41.c
@@ -250,8 +250,27 @@
 			transferred < cppi41_channel->packet_sz)
 		cppi41_channel->prog_len = 0;
 
-	if (cppi41_channel->is_tx)
-		empty = musb_is_tx_fifo_empty(hw_ep);
+	if (cppi41_channel->is_tx) {
+		u8 type;
+
+		if (is_host_active(musb))
+			type = hw_ep->out_qh->type;
+		else
+			type = hw_ep->ep_in.type;
+
+		if (type == USB_ENDPOINT_XFER_ISOC)
+			/*
+			 * Don't use the early-TX-interrupt workaround below
+			 * for Isoch transfter. Since Isoch are periodic
+			 * transfer, by the time the next transfer is
+			 * scheduled, the current one should be done already.
+			 *
+			 * This avoids audio playback underrun issue.
+			 */
+			empty = true;
+		else
+			empty = musb_is_tx_fifo_empty(hw_ep);
+	}
 
 	if (!cppi41_channel->is_tx || empty) {
 		cppi41_trans_done(cppi41_channel);
--- linux-4.4.0.orig/drivers/usb/musb/musb_dsps.c
+++ linux-4.4.0/drivers/usb/musb/musb_dsps.c
@@ -301,6 +301,17 @@
 	spin_unlock_irqrestore(&musb->lock, flags);
 }
 
+void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum)
+{
+	u32 epintr;
+	struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+
+	/* musb->lock might already been held */
+	epintr = (1 << epnum) << wrp->rxep_shift;
+	musb_writel(musb->ctrl_base, wrp->epintr_status, epintr);
+}
+
 static irqreturn_t dsps_interrupt(int irq, void *hci)
 {
 	struct musb  *musb = hci;
@@ -647,6 +658,7 @@
 	.try_idle	= dsps_musb_try_idle,
 	.set_mode	= dsps_musb_set_mode,
 	.recover	= dsps_musb_recover,
+	.clear_ep_rxintr = dsps_musb_clear_ep_rxintr,
 };
 
 static u64 musb_dmamask = DMA_BIT_MASK(32);
--- linux-4.4.0.orig/drivers/usb/musb/musb_gadget_ep0.c
+++ linux-4.4.0/drivers/usb/musb/musb_gadget_ep0.c
@@ -114,15 +114,19 @@
 		}
 
 		is_in = epnum & USB_DIR_IN;
-		if (is_in) {
-			epnum &= 0x0f;
+		epnum &= 0x0f;
+		if (epnum >= MUSB_C_NUM_EPS) {
+			handled = -EINVAL;
+			break;
+		}
+
+		if (is_in)
 			ep = &musb->endpoints[epnum].ep_in;
-		} else {
+		else
 			ep = &musb->endpoints[epnum].ep_out;
-		}
 		regs = musb->endpoints[epnum].regs;
 
-		if (epnum >= MUSB_C_NUM_EPS || !ep->desc) {
+		if (!ep->desc) {
 			handled = -EINVAL;
 			break;
 		}
--- linux-4.4.0.orig/drivers/usb/musb/musb_host.c
+++ linux-4.4.0/drivers/usb/musb/musb_host.c
@@ -138,6 +138,7 @@
 				"Could not flush host TX%d fifo: csr: %04x\n",
 				ep->epnum, csr))
 			return;
+		mdelay(1);
 	}
 }
 
@@ -594,14 +595,13 @@
 		musb_writew(ep->regs, MUSB_TXCSR, 0);
 
 	/* scrub all previous state, clearing toggle */
-	} else {
-		csr = musb_readw(ep->regs, MUSB_RXCSR);
-		if (csr & MUSB_RXCSR_RXPKTRDY)
-			WARNING("rx%d, packet/%d ready?\n", ep->epnum,
-				musb_readw(ep->regs, MUSB_RXCOUNT));
-
-		musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
 	}
+	csr = musb_readw(ep->regs, MUSB_RXCSR);
+	if (csr & MUSB_RXCSR_RXPKTRDY)
+		WARNING("rx%d, packet/%d ready?\n", ep->epnum,
+			musb_readw(ep->regs, MUSB_RXCOUNT));
+
+	musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
 
 	/* target addr and (for multipoint) hub addr/port */
 	if (musb->is_multipoint) {
@@ -662,7 +662,7 @@
 		csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
 		csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */
 	}
-	channel->desired_mode = mode;
+	channel->desired_mode = *mode;
 	musb_writew(epio, MUSB_TXCSR, csr);
 
 	return 0;
@@ -995,9 +995,15 @@
 	if (is_in) {
 		dma = is_dma_capable() ? ep->rx_channel : NULL;
 
-		/* clear nak timeout bit */
+		/*
+		 * Need to stop the transaction by clearing REQPKT first
+		 * then the NAK Timeout bit ref MUSBMHDRC USB 2.0 HIGH-SPEED
+		 * DUAL-ROLE CONTROLLER Programmer's Guide, section 9.2.2
+		 */
 		rx_csr = musb_readw(epio, MUSB_RXCSR);
 		rx_csr |= MUSB_RXCSR_H_WZC_BITS;
+		rx_csr &= ~MUSB_RXCSR_H_REQPKT;
+		musb_writew(epio, MUSB_RXCSR, rx_csr);
 		rx_csr &= ~MUSB_RXCSR_DATAERROR;
 		musb_writew(epio, MUSB_RXCSR, rx_csr);
 
@@ -1042,7 +1048,9 @@
 			/* set tx_reinit and schedule the next qh */
 			ep->tx_reinit = 1;
 		}
-		musb_start_urb(musb, is_in, next_qh);
+
+		if (next_qh)
+			musb_start_urb(musb, is_in, next_qh);
 	}
 }
 
@@ -1511,10 +1519,7 @@
 	 * We need to map sg if the transfer_buffer is
 	 * NULL.
 	 */
-	if (!urb->transfer_buffer)
-		qh->use_sg = true;
-
-	if (qh->use_sg) {
+	if (!urb->transfer_buffer) {
 		/* sg_miter_start is already done in musb_ep_program */
 		if (!sg_miter_next(&qh->sg_miter)) {
 			dev_err(musb->controller, "error: sg list empty\n");
@@ -1522,9 +1527,8 @@
 			status = -EINVAL;
 			goto done;
 		}
-		urb->transfer_buffer = qh->sg_miter.addr;
 		length = min_t(u32, length, qh->sg_miter.length);
-		musb_write_fifo(hw_ep, length, urb->transfer_buffer);
+		musb_write_fifo(hw_ep, length, qh->sg_miter.addr);
 		qh->sg_miter.consumed = length;
 		sg_miter_stop(&qh->sg_miter);
 	} else {
@@ -1533,11 +1537,6 @@
 
 	qh->segsize = length;
 
-	if (qh->use_sg) {
-		if (offset + length >= urb->transfer_buffer_length)
-			qh->use_sg = false;
-	}
-
 	musb_ep_select(mbase, epnum);
 	musb_writew(epio, MUSB_TXCSR,
 			MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1551,7 +1550,7 @@
 				  struct urb *urb,
 				  size_t len)
 {
-	struct dma_channel *channel = hw_ep->tx_channel;
+	struct dma_channel *channel = hw_ep->rx_channel;
 	void __iomem *epio = hw_ep->regs;
 	dma_addr_t *buf;
 	u32 length, res;
@@ -2003,10 +2002,8 @@
 				qh->offset,
 				urb->transfer_buffer_length);
 
-			done = musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh,
-							      urb, xfer_len,
-							      iso_err);
-			if (done)
+			if (musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh, urb,
+							   xfer_len, iso_err))
 				goto finish;
 			else
 				dev_err(musb->controller, "error: rx_dma failed\n");
@@ -2058,8 +2055,10 @@
 	urb->actual_length += xfer_len;
 	qh->offset += xfer_len;
 	if (done) {
-		if (qh->use_sg)
+		if (qh->use_sg) {
 			qh->use_sg = false;
+			urb->transfer_buffer = NULL;
+		}
 
 		if (urb->status == -EINPROGRESS)
 			urb->status = status;
@@ -2387,12 +2386,11 @@
 	int			is_in = usb_pipein(urb->pipe);
 	int			status = 0;
 	u16			csr;
+	struct dma_channel	*dma = NULL;
 
 	musb_ep_select(regs, hw_end);
 
 	if (is_dma_capable()) {
-		struct dma_channel	*dma;
-
 		dma = is_in ? ep->rx_channel : ep->tx_channel;
 		if (dma) {
 			status = ep->musb->dma_controller->channel_abort(dma);
@@ -2409,10 +2407,9 @@
 		/* giveback saves bulk toggle */
 		csr = musb_h_flush_rxfifo(ep, 0);
 
-		/* REVISIT we still get an irq; should likely clear the
-		 * endpoint's irq status here to avoid bogus irqs.
-		 * clearing that status is platform-specific...
-		 */
+		/* clear the endpoint's irq status here to avoid bogus irqs */
+		if (is_dma_capable() && dma)
+			musb_platform_clear_ep_rxintr(musb, ep->epnum);
 	} else if (ep->epnum) {
 		musb_h_tx_flush_fifo(ep);
 		csr = musb_readw(epio, MUSB_TXCSR);
@@ -2576,8 +2573,11 @@
 {
 	struct musb	*musb = hcd_to_musb(hcd);
 	u8		devctl;
+	int		ret;
 
-	musb_port_suspend(musb, true);
+	ret = musb_port_suspend(musb, true);
+	if (ret)
+		return ret;
 
 	if (!is_host_active(musb))
 		return 0;
--- linux-4.4.0.orig/drivers/usb/musb/musb_host.h
+++ linux-4.4.0/drivers/usb/musb/musb_host.h
@@ -92,7 +92,7 @@
 extern void musb_root_disconnect(struct musb *musb);
 extern void musb_host_resume_root_hub(struct musb *musb);
 extern void musb_host_poke_root_hub(struct musb *musb);
-extern void musb_port_suspend(struct musb *musb, bool do_suspend);
+extern int musb_port_suspend(struct musb *musb, bool do_suspend);
 extern void musb_port_reset(struct musb *musb, bool do_reset);
 extern void musb_host_finish_resume(struct work_struct *work);
 #else
@@ -124,7 +124,10 @@
 static inline void musb_host_resume_root_hub(struct musb *musb)	{}
 static inline void musb_host_poll_rh_status(struct musb *musb)	{}
 static inline void musb_host_poke_root_hub(struct musb *musb)	{}
-static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {}
+static inline int musb_port_suspend(struct musb *musb, bool do_suspend)
+{
+	return 0;
+}
 static inline void musb_port_reset(struct musb *musb, bool do_reset) {}
 static inline void musb_host_finish_resume(struct work_struct *work) {}
 #endif
--- linux-4.4.0.orig/drivers/usb/musb/musb_virthub.c
+++ linux-4.4.0/drivers/usb/musb/musb_virthub.c
@@ -74,14 +74,14 @@
 	spin_unlock_irqrestore(&musb->lock, flags);
 }
 
-void musb_port_suspend(struct musb *musb, bool do_suspend)
+int musb_port_suspend(struct musb *musb, bool do_suspend)
 {
 	struct usb_otg	*otg = musb->xceiv->otg;
 	u8		power;
 	void __iomem	*mbase = musb->mregs;
 
 	if (!is_host_active(musb))
-		return;
+		return 0;
 
 	/* NOTE:  this doesn't necessarily put PHY into low power mode,
 	 * turning off its clock; that's a function of PHY integration and
@@ -92,16 +92,20 @@
 	if (do_suspend) {
 		int retries = 10000;
 
-		power &= ~MUSB_POWER_RESUME;
-		power |= MUSB_POWER_SUSPENDM;
-		musb_writeb(mbase, MUSB_POWER, power);
+		if (power & MUSB_POWER_RESUME)
+			return -EBUSY;
+
+		if (!(power & MUSB_POWER_SUSPENDM)) {
+			power |= MUSB_POWER_SUSPENDM;
+			musb_writeb(mbase, MUSB_POWER, power);
 
-		/* Needed for OPT A tests */
-		power = musb_readb(mbase, MUSB_POWER);
-		while (power & MUSB_POWER_SUSPENDM) {
+			/* Needed for OPT A tests */
 			power = musb_readb(mbase, MUSB_POWER);
-			if (retries-- < 1)
-				break;
+			while (power & MUSB_POWER_SUSPENDM) {
+				power = musb_readb(mbase, MUSB_POWER);
+				if (retries-- < 1)
+					break;
+			}
 		}
 
 		dev_dbg(musb->controller, "Root port suspended, power %02x\n", power);
@@ -138,6 +142,7 @@
 		schedule_delayed_work(&musb->finish_resume_work,
 				      msecs_to_jiffies(USB_RESUME_TIMEOUT));
 	}
+	return 0;
 }
 
 void musb_port_reset(struct musb *musb, bool do_reset)
--- linux-4.4.0.orig/drivers/usb/musb/musbhsdma.c
+++ linux-4.4.0/drivers/usb/musb/musbhsdma.c
@@ -398,7 +398,7 @@
 	controller->controller.channel_abort = dma_channel_abort;
 
 	if (request_irq(irq, dma_controller_irq, 0,
-			dev_name(musb->controller), &controller->controller)) {
+			dev_name(musb->controller), controller)) {
 		dev_err(dev, "request_irq %d failed!\n", irq);
 		musb_dma_controller_destroy(&controller->controller);
 
--- linux-4.4.0.orig/drivers/usb/musb/musbhsdma.h
+++ linux-4.4.0/drivers/usb/musb/musbhsdma.h
@@ -157,5 +157,5 @@
 	void __iomem			*base;
 	u8				channel_count;
 	u8				used_channels;
-	u8				irq;
+	int				irq;
 };
--- linux-4.4.0.orig/drivers/usb/musb/sunxi.c
+++ linux-4.4.0/drivers/usb/musb/sunxi.c
@@ -320,6 +320,8 @@
 	if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
 		sunxi_sram_release(musb->controller->parent);
 
+	devm_usb_put_phy(glue->dev, glue->xceiv);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/usb/musb/tusb6010.c
+++ linux-4.4.0/drivers/usb/musb/tusb6010.c
@@ -1119,6 +1119,11 @@
 
 	/* dma address for async dma */
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		pr_debug("no async dma resource?\n");
+		ret = -ENODEV;
+		goto done;
+	}
 	musb->async = mem->start;
 
 	/* dma address for sync dma */
--- linux-4.4.0.orig/drivers/usb/musb/tusb6010_omap.c
+++ linux-4.4.0/drivers/usb/musb/tusb6010_omap.c
@@ -220,6 +220,7 @@
 	u32				dma_remaining;
 	int				src_burst, dst_burst;
 	u16				csr;
+	u32				psize;
 	int				ch;
 	s8				dmareq;
 	s8				sync_dev;
@@ -391,15 +392,19 @@
 
 	if (chdat->tx) {
 		/* Send transfer_packet_sz packets at a time */
-		musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
-			chdat->transfer_packet_sz);
+		psize = musb_readl(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET);
+		psize &= ~0x7ff;
+		psize |= chdat->transfer_packet_sz;
+		musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET, psize);
 
 		musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
 			TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
 	} else {
 		/* Receive transfer_packet_sz packets at a time */
-		musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
-			chdat->transfer_packet_sz << 16);
+		psize = musb_readl(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET);
+		psize &= ~(0x7ff << 16);
+		psize |= (chdat->transfer_packet_sz << 16);
+		musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET, psize);
 
 		musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
 			TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
--- linux-4.4.0.orig/drivers/usb/musb/ux500.c
+++ linux-4.4.0/drivers/usb/musb/ux500.c
@@ -348,7 +348,9 @@
 	struct ux500_glue	*glue = dev_get_drvdata(dev);
 	struct musb		*musb = glue_to_musb(glue);
 
-	usb_phy_set_suspend(musb->xceiv, 1);
+	if (musb)
+		usb_phy_set_suspend(musb->xceiv, 1);
+
 	clk_disable_unprepare(glue->clk);
 
 	return 0;
@@ -366,7 +368,8 @@
 		return ret;
 	}
 
-	usb_phy_set_suspend(musb->xceiv, 0);
+	if (musb)
+		usb_phy_set_suspend(musb->xceiv, 0);
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/usb/musb/ux500_dma.c
+++ linux-4.4.0/drivers/usb/musb/ux500_dma.c
@@ -207,9 +207,6 @@
 	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
 		channel->status == MUSB_DMA_STATUS_BUSY);
 
-	if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len))
-		return false;
-
 	channel->status = MUSB_DMA_STATUS_BUSY;
 	channel->actual_len = 0;
 	ret = ux500_configure_channel(channel, packet_sz, mode, dma_addr, len);
--- linux-4.4.0.orig/drivers/usb/phy/Kconfig
+++ linux-4.4.0/drivers/usb/phy/Kconfig
@@ -140,6 +140,7 @@
 	tristate "Qualcomm on-chip USB OTG controller support"
 	depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
 	depends on RESET_CONTROLLER
+	depends on REGULATOR
 	depends on EXTCON
 	select USB_PHY
 	help
--- linux-4.4.0.orig/drivers/usb/phy/phy-am335x-control.c
+++ linux-4.4.0/drivers/usb/phy/phy-am335x-control.c
@@ -126,10 +126,12 @@
 		return NULL;
 
 	dev = bus_find_device(&platform_bus_type, NULL, node, match);
+	of_node_put(node);
 	if (!dev)
 		return NULL;
 
 	ctrl_usb = dev_get_drvdata(dev);
+	put_device(dev);
 	if (!ctrl_usb)
 		return NULL;
 	return &ctrl_usb->phy_ctrl;
--- linux-4.4.0.orig/drivers/usb/phy/phy-am335x.c
+++ linux-4.4.0/drivers/usb/phy/phy-am335x.c
@@ -56,9 +56,6 @@
 	if (ret)
 		return ret;
 
-	ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
-	if (ret)
-		return ret;
 	am_phy->usb_phy_gen.phy.init = am335x_init;
 	am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;
 
@@ -77,7 +74,7 @@
 	device_set_wakeup_enable(dev, false);
 	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
 
-	return 0;
+	return usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
 }
 
 static int am335x_phy_remove(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/usb/phy/phy-fsl-usb.c
+++ linux-4.4.0/drivers/usb/phy/phy-fsl-usb.c
@@ -75,7 +75,7 @@
 	.otg_port = 1,
 };
 
-#ifdef CONFIG_PPC32
+#ifdef CONFIG_PPC
 static u32 _fsl_readl_be(const unsigned __iomem *p)
 {
 	return in_be32(p);
@@ -105,7 +105,7 @@
 #else
 #define fsl_readl(addr)		readl(addr)
 #define fsl_writel(val, addr)	writel(val, addr)
-#endif /* CONFIG_PPC32 */
+#endif /* CONFIG_PPC */
 
 int write_ulpi(u8 addr, u8 data)
 {
@@ -879,6 +879,7 @@
 	if (pdata->init && pdata->init(pdev) != 0)
 		return -EINVAL;
 
+#ifdef CONFIG_PPC32
 	if (pdata->big_endian_mmio) {
 		_fsl_readl = _fsl_readl_be;
 		_fsl_writel = _fsl_writel_be;
@@ -886,6 +887,7 @@
 		_fsl_readl = _fsl_readl_le;
 		_fsl_writel = _fsl_writel_le;
 	}
+#endif
 
 	/* request irq */
 	p_otg->irq = platform_get_irq(pdev, 0);
@@ -976,7 +978,7 @@
 /*
  * state file in sysfs
  */
-static int show_fsl_usb2_otg_state(struct device *dev,
+static ssize_t show_fsl_usb2_otg_state(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
 	struct otg_fsm *fsm = &fsl_otg_dev->fsm;
--- linux-4.4.0.orig/drivers/usb/phy/phy-isp1301.c
+++ linux-4.4.0/drivers/usb/phy/phy-isp1301.c
@@ -33,6 +33,12 @@
 };
 MODULE_DEVICE_TABLE(i2c, isp1301_id);
 
+static const struct of_device_id isp1301_of_match[] = {
+	{.compatible = "nxp,isp1301" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, isp1301_of_match);
+
 static struct i2c_client *isp1301_i2c_client;
 
 static int __isp1301_write(struct isp1301 *isp, u8 reg, u8 value, u8 clear)
@@ -130,6 +136,7 @@
 static struct i2c_driver isp1301_driver = {
 	.driver = {
 		.name = DRV_NAME,
+		.of_match_table = of_match_ptr(isp1301_of_match),
 	},
 	.probe = isp1301_probe,
 	.remove = isp1301_remove,
--- linux-4.4.0.orig/drivers/usb/phy/phy-msm-usb.c
+++ linux-4.4.0/drivers/usb/phy/phy-msm-usb.c
@@ -1599,6 +1599,8 @@
 						&motg->id.nb);
 		if (ret < 0) {
 			dev_err(&pdev->dev, "register ID notifier failed\n");
+			extcon_unregister_notifier(motg->vbus.extcon,
+						   EXTCON_USB, &motg->vbus.nb);
 			return ret;
 		}
 
@@ -1660,15 +1662,6 @@
 	if (!motg)
 		return -ENOMEM;
 
-	pdata = dev_get_platdata(&pdev->dev);
-	if (!pdata) {
-		if (!np)
-			return -ENXIO;
-		ret = msm_otg_read_dt(pdev, motg);
-		if (ret)
-			return ret;
-	}
-
 	motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
 				     GFP_KERNEL);
 	if (!motg->phy.otg)
@@ -1710,6 +1703,15 @@
 	if (!motg->regs)
 		return -ENOMEM;
 
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		if (!np)
+			return -ENXIO;
+		ret = msm_otg_read_dt(pdev, motg);
+		if (ret)
+			return ret;
+	}
+
 	/*
 	 * NOTE: The PHYs can be multiplexed between the chipidea controller
 	 * and the dwc3 controller, using a single bit. It is important that
@@ -1717,8 +1719,10 @@
 	 */
 	if (motg->phy_number) {
 		phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4);
-		if (!phy_select)
-			return -ENOMEM;
+		if (!phy_select) {
+			ret = -ENOMEM;
+			goto unregister_extcon;
+		}
 		/* Enable second PHY with the OTG port */
 		writel(0x1, phy_select);
 	}
@@ -1728,7 +1732,8 @@
 	motg->irq = platform_get_irq(pdev, 0);
 	if (motg->irq < 0) {
 		dev_err(&pdev->dev, "platform_get_irq failed\n");
-		return motg->irq;
+		ret = motg->irq;
+		goto unregister_extcon;
 	}
 
 	regs[0].supply = "vddcx";
@@ -1737,7 +1742,7 @@
 
 	ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs);
 	if (ret)
-		return ret;
+		goto unregister_extcon;
 
 	motg->vddcx = regs[0].consumer;
 	motg->v3p3  = regs[1].consumer;
@@ -1834,6 +1839,12 @@
 	clk_disable_unprepare(motg->clk);
 	if (!IS_ERR(motg->core_clk))
 		clk_disable_unprepare(motg->core_clk);
+unregister_extcon:
+	extcon_unregister_notifier(motg->id.extcon,
+				   EXTCON_USB_HOST, &motg->id.nb);
+	extcon_unregister_notifier(motg->vbus.extcon,
+				   EXTCON_USB, &motg->vbus.nb);
+
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/usb/phy/phy-tahvo.c
+++ linux-4.4.0/drivers/usb/phy/phy-tahvo.c
@@ -368,7 +368,8 @@
 	tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable);
 	if (IS_ERR(tu->extcon)) {
 		dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
-		return -ENOMEM;
+		ret = PTR_ERR(tu->extcon);
+		goto err_disable_clk;
 	}
 
 	ret = devm_extcon_dev_register(&pdev->dev, tu->extcon);
--- linux-4.4.0.orig/drivers/usb/renesas_usbhs/common.c
+++ linux-4.4.0/drivers/usb/renesas_usbhs/common.c
@@ -733,8 +733,10 @@
 	struct usbhs_priv *priv = dev_get_drvdata(dev);
 	struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-	if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+	if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
 		usbhsc_power_ctrl(priv, 1);
+		usbhs_mod_autonomy_mode(priv);
+	}
 
 	usbhs_platform_call(priv, phy_reset, pdev);
 
--- linux-4.4.0.orig/drivers/usb/renesas_usbhs/common.h
+++ linux-4.4.0/drivers/usb/renesas_usbhs/common.h
@@ -163,11 +163,12 @@
 #define VBSTS	(1 << 7)	/* VBUS_0 and VBUSIN_0 Input Status */
 #define VALID	(1 << 3)	/* USB Request Receive */
 
-#define DVSQ_MASK		(0x3 << 4)	/* Device State */
+#define DVSQ_MASK		(0x7 << 4)	/* Device State */
 #define  POWER_STATE		(0 << 4)
 #define  DEFAULT_STATE		(1 << 4)
 #define  ADDRESS_STATE		(2 << 4)
 #define  CONFIGURATION_STATE	(3 << 4)
+#define  SUSPENDED_STATE	(4 << 4)
 
 #define CTSQ_MASK		(0x7)	/* Control Transfer Stage */
 #define  IDLE_SETUP_STAGE	0	/* Idle stage or setup stage */
@@ -213,6 +214,7 @@
 /* DCPCTR */
 #define BSTS		(1 << 15)	/* Buffer Status */
 #define SUREQ		(1 << 14)	/* Sending SETUP Token */
+#define INBUFM		(1 << 14)	/* (PIPEnCTR) Transfer Buffer Monitor */
 #define CSSTS		(1 << 12)	/* CSSTS Status */
 #define	ACLRM		(1 << 9)	/* Buffer Auto-Clear Mode */
 #define SQCLR		(1 << 8)	/* Toggle Bit Clear */
--- linux-4.4.0.orig/drivers/usb/renesas_usbhs/fifo.c
+++ linux-4.4.0/drivers/usb/renesas_usbhs/fifo.c
@@ -98,7 +98,7 @@
 	list_del_init(&pkt->node);
 }
 
-static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
+struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
 {
 	if (list_empty(&pipe->list))
 		return NULL;
@@ -140,6 +140,8 @@
 			usbhsf_dma_unmap(pkt);
 		}
 
+		usbhs_pipe_running(pipe, 0);
+
 		__usbhsf_pkt_del(pkt);
 	}
 
@@ -190,7 +192,8 @@
 		goto __usbhs_pkt_handler_end;
 	}
 
-	ret = func(pkt, &is_done);
+	if (likely(func))
+		ret = func(pkt, &is_done);
 
 	if (is_done)
 		__usbhsf_pkt_del(pkt);
@@ -284,11 +287,26 @@
 			      struct usbhs_fifo *fifo)
 {
 	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+	int ret = 0;
 
-	if (!usbhs_pipe_is_dcp(pipe))
-		usbhsf_fifo_barrier(priv, fifo);
+	if (!usbhs_pipe_is_dcp(pipe)) {
+		/*
+		 * This driver checks the pipe condition first to avoid -EBUSY
+		 * from usbhsf_fifo_barrier() with about 10 msec delay in
+		 * the interrupt handler if the pipe is RX direction and empty.
+		 */
+		if (usbhs_pipe_is_dir_in(pipe))
+			ret = usbhs_pipe_is_accessible(pipe);
+		if (!ret)
+			ret = usbhsf_fifo_barrier(priv, fifo);
+	}
 
-	usbhs_write(priv, fifo->ctr, BCLR);
+	/*
+	 * if non-DCP pipe, this driver should set BCLR when
+	 * usbhsf_fifo_barrier() returns 0.
+	 */
+	if (!ret)
+		usbhs_write(priv, fifo->ctr, BCLR);
 }
 
 static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv,
@@ -803,17 +821,21 @@
 }
 
 static void usbhsf_dma_complete(void *arg);
-static void xfer_work(struct work_struct *work)
+static void usbhsf_dma_xfer_preparing(struct usbhs_pkt *pkt)
 {
-	struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
 	struct usbhs_pipe *pipe = pkt->pipe;
-	struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
+	struct usbhs_fifo *fifo;
 	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
 	struct dma_async_tx_descriptor *desc;
-	struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
+	struct dma_chan *chan;
 	struct device *dev = usbhs_priv_to_dev(priv);
 	enum dma_transfer_direction dir;
 
+	fifo = usbhs_pipe_to_fifo(pipe);
+	if (!fifo)
+		return;
+
+	chan = usbhsf_dma_chan_get(fifo, pkt);
 	dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
 
 	desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual,
@@ -835,12 +857,24 @@
 		fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero);
 
 	usbhs_pipe_running(pipe, 1);
-	usbhsf_dma_start(pipe, fifo);
 	usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
 	dma_async_issue_pending(chan);
+	usbhsf_dma_start(pipe, fifo);
 	usbhs_pipe_enable(pipe);
 }
 
+static void xfer_work(struct work_struct *work)
+{
+	struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
+	struct usbhs_pipe *pipe = pkt->pipe;
+	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+	unsigned long flags;
+
+	usbhs_lock(priv, flags);
+	usbhsf_dma_xfer_preparing(pkt);
+	usbhs_unlock(priv, flags);
+}
+
 /*
  *		DMA push handler
  */
@@ -858,7 +892,7 @@
 
 	/* use PIO if packet is less than pio_dma_border or pipe is DCP */
 	if ((len < usbhs_get_dparam(priv, pio_dma_border)) ||
-	    usbhs_pipe_is_dcp(pipe))
+	    usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC))
 		goto usbhsf_pio_prepare_push;
 
 	/* check data length if this driver don't use USB-DMAC */
@@ -889,8 +923,14 @@
 
 	pkt->trans = len;
 
-	INIT_WORK(&pkt->work, xfer_work);
-	schedule_work(&pkt->work);
+	usbhsf_tx_irq_ctrl(pipe, 0);
+	/* FIXME: Workaound for usb dmac that driver can be used in atomic */
+	if (usbhs_get_dparam(priv, has_usb_dmac)) {
+		usbhsf_dma_xfer_preparing(pkt);
+	} else {
+		INIT_WORK(&pkt->work, xfer_work);
+		schedule_work(&pkt->work);
+	}
 
 	return 0;
 
@@ -962,7 +1002,7 @@
 
 	/* use PIO if packet is less than pio_dma_border or pipe is DCP */
 	if ((pkt->length < usbhs_get_dparam(priv, pio_dma_border)) ||
-	    usbhs_pipe_is_dcp(pipe))
+	    usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC))
 		goto usbhsf_pio_prepare_pop;
 
 	fifo = usbhsf_get_dma_fifo(priv, pkt);
@@ -972,6 +1012,10 @@
 	if ((uintptr_t)pkt->buf & (USBHS_USB_DMAC_XFER_SIZE - 1))
 		goto usbhsf_pio_prepare_pop;
 
+	/* return at this time if the pipe is running */
+	if (usbhs_pipe_is_running(pipe))
+		return 0;
+
 	usbhs_pipe_config_change_bfre(pipe, 1);
 
 	ret = usbhsf_fifo_select(pipe, fifo, 0);
@@ -992,8 +1036,7 @@
 
 	pkt->trans = pkt->length;
 
-	INIT_WORK(&pkt->work, xfer_work);
-	schedule_work(&pkt->work);
+	usbhsf_dma_xfer_preparing(pkt);
 
 	return 0;
 
@@ -1162,6 +1205,7 @@
 	usbhsf_fifo_clear(pipe, fifo);
 	pkt->actual = usbhs_dma_calc_received_size(pkt, chan, rcv_len);
 
+	usbhs_pipe_running(pipe, 0);
 	usbhsf_dma_stop(pipe, fifo);
 	usbhsf_dma_unmap(pkt);
 	usbhsf_fifo_unselect(pipe, pipe->fifo);
--- linux-4.4.0.orig/drivers/usb/renesas_usbhs/fifo.h
+++ linux-4.4.0/drivers/usb/renesas_usbhs/fifo.h
@@ -106,5 +106,6 @@
 		    void *buf, int len, int zero, int sequence);
 struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
 void usbhs_pkt_start(struct usbhs_pipe *pipe);
+struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe);
 
 #endif /* RENESAS_USB_FIFO_H */
--- linux-4.4.0.orig/drivers/usb/renesas_usbhs/mod.c
+++ linux-4.4.0/drivers/usb/renesas_usbhs/mod.c
@@ -282,9 +282,16 @@
 	if (usbhs_mod_is_host(priv))
 		usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
 
-	usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
+	/*
+	 * The driver should not clear the xxxSTS after the line of
+	 * "call irq callback functions" because each "if" statement is
+	 * possible to call the callback function for avoiding any side effects.
+	 */
+	if (irq_state.intsts0 & BRDY)
+		usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
 	usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts);
-	usbhs_write(priv, BEMPSTS, ~irq_state.bempsts);
+	if (irq_state.intsts0 & BEMP)
+		usbhs_write(priv, BEMPSTS, ~irq_state.bempsts);
 
 	/*
 	 * call irq callback functions
--- linux-4.4.0.orig/drivers/usb/renesas_usbhs/mod_gadget.c
+++ linux-4.4.0/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -37,6 +37,7 @@
 struct usbhsg_uep {
 	struct usb_ep		 ep;
 	struct usbhs_pipe	*pipe;
+	spinlock_t		lock;	/* protect the pipe */
 
 	char ep_name[EP_NAME_SIZE];
 
@@ -158,10 +159,14 @@
 	struct usbhs_pipe *pipe = pkt->pipe;
 	struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
 	struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
+	unsigned long flags;
 
 	ureq->req.actual = pkt->actual;
 
-	usbhsg_queue_pop(uep, ureq, 0);
+	usbhs_lock(priv, flags);
+	if (uep)
+		__usbhsg_queue_pop(uep, ureq, 0);
+	usbhs_unlock(priv, flags);
 }
 
 static void usbhsg_queue_push(struct usbhsg_uep *uep,
@@ -462,12 +467,18 @@
 {
 	struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
 	struct device *dev = usbhsg_gpriv_to_dev(gpriv);
+	int state = usbhs_status_get_device_state(irq_state);
 
 	gpriv->gadget.speed = usbhs_bus_get_speed(priv);
 
-	dev_dbg(dev, "state = %x : speed : %d\n",
-		usbhs_status_get_device_state(irq_state),
-		gpriv->gadget.speed);
+	dev_dbg(dev, "state = %x : speed : %d\n", state, gpriv->gadget.speed);
+
+	if (gpriv->gadget.speed != USB_SPEED_UNKNOWN &&
+	    (state & SUSPENDED_STATE)) {
+		if (gpriv->driver && gpriv->driver->suspend)
+			gpriv->driver->suspend(&gpriv->gadget);
+		usb_gadget_set_state(&gpriv->gadget, USB_STATE_SUSPENDED);
+	}
 
 	return 0;
 }
@@ -582,6 +593,9 @@
 	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
 	struct usbhs_pipe *pipe;
 	int ret = -EIO;
+	unsigned long flags;
+
+	usbhs_lock(priv, flags);
 
 	/*
 	 * if it already have pipe,
@@ -590,7 +604,8 @@
 	if (uep->pipe) {
 		usbhs_pipe_clear(uep->pipe);
 		usbhs_pipe_sequence_data0(uep->pipe);
-		return 0;
+		ret = 0;
+		goto usbhsg_ep_enable_end;
 	}
 
 	pipe = usbhs_pipe_malloc(priv,
@@ -610,24 +625,33 @@
 		 * use dmaengine if possible.
 		 * It will use pio handler if impossible.
 		 */
-		if (usb_endpoint_dir_in(desc))
+		if (usb_endpoint_dir_in(desc)) {
 			pipe->handler = &usbhs_fifo_dma_push_handler;
-		else
+		} else {
 			pipe->handler = &usbhs_fifo_dma_pop_handler;
+			usbhs_xxxsts_clear(priv, BRDYSTS,
+					   usbhs_pipe_number(pipe));
+		}
 
 		ret = 0;
 	}
 
+usbhsg_ep_enable_end:
+	usbhs_unlock(priv, flags);
+
 	return ret;
 }
 
 static int usbhsg_ep_disable(struct usb_ep *ep)
 {
 	struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
-	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+	struct usbhs_pipe *pipe;
+	unsigned long flags;
 
+	spin_lock_irqsave(&uep->lock, flags);
+	pipe = usbhsg_uep_to_pipe(uep);
 	if (!pipe)
-		return -EINVAL;
+		goto out;
 
 	usbhsg_pipe_disable(uep);
 	usbhs_pipe_free(pipe);
@@ -635,6 +659,9 @@
 	uep->pipe->mod_private	= NULL;
 	uep->pipe		= NULL;
 
+out:
+	spin_unlock_irqrestore(&uep->lock, flags);
+
 	return 0;
 }
 
@@ -684,8 +711,11 @@
 {
 	struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
 	struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
-	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+	struct usbhs_pipe *pipe;
+	unsigned long flags;
 
+	spin_lock_irqsave(&uep->lock, flags);
+	pipe = usbhsg_uep_to_pipe(uep);
 	if (pipe)
 		usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
 
@@ -694,6 +724,7 @@
 	 * even if the pipe is NULL.
 	 */
 	usbhsg_queue_pop(uep, ureq, -ECONNRESET);
+	spin_unlock_irqrestore(&uep->lock, flags);
 
 	return 0;
 }
@@ -706,8 +737,7 @@
 	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
 	struct device *dev = usbhsg_gpriv_to_dev(gpriv);
 	unsigned long flags;
-
-	usbhsg_pipe_disable(uep);
+	int ret = 0;
 
 	dev_dbg(dev, "set halt %d (pipe %d)\n",
 		halt, usbhs_pipe_number(pipe));
@@ -715,6 +745,18 @@
 	/********************  spin lock ********************/
 	usbhs_lock(priv, flags);
 
+	/*
+	 * According to usb_ep_set_halt()'s description, this function should
+	 * return -EAGAIN if the IN endpoint has any queue or data. Note
+	 * that the usbhs_pipe_is_dir_in() returns false if the pipe is an
+	 * IN endpoint in the gadget mode.
+	 */
+	if (!usbhs_pipe_is_dir_in(pipe) && (__usbhsf_pkt_get(pipe) ||
+	    usbhs_pipe_contains_transmittable_data(pipe))) {
+		ret = -EAGAIN;
+		goto out;
+	}
+
 	if (halt)
 		usbhs_pipe_stall(pipe);
 	else
@@ -725,10 +767,11 @@
 	else
 		usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE);
 
+out:
 	usbhs_unlock(priv, flags);
 	/********************  spin unlock ******************/
 
-	return 0;
+	return ret;
 }
 
 static int usbhsg_ep_set_halt(struct usb_ep *ep, int value)
@@ -840,10 +883,10 @@
 {
 	struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
 	struct usbhs_mod *mod = usbhs_mod_get_current(priv);
-	struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv);
+	struct usbhsg_uep *uep;
 	struct device *dev = usbhs_priv_to_dev(priv);
 	unsigned long flags;
-	int ret = 0;
+	int ret = 0, i;
 
 	/********************  spin lock ********************/
 	usbhs_lock(priv, flags);
@@ -875,7 +918,9 @@
 	usbhs_sys_set_test_mode(priv, 0);
 	usbhs_sys_function_ctrl(priv, 0);
 
-	usbhsg_ep_disable(&dcp->ep);
+	/* disable all eps */
+	usbhsg_for_each_uep_with_dcp(uep, gpriv, i)
+		usbhsg_ep_disable(&uep->ep);
 
 	dev_dbg(dev, "stop gadget\n");
 
@@ -1061,7 +1106,7 @@
 
 	gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
 	dev_info(dev, "%stransceiver found\n",
-		 gpriv->transceiver ? "" : "no ");
+		 !IS_ERR(gpriv->transceiver) ? "" : "no ");
 
 	/*
 	 * CAUTION
@@ -1105,6 +1150,7 @@
 		uep->ep.name		= uep->ep_name;
 		uep->ep.ops		= &usbhsg_ep_ops;
 		INIT_LIST_HEAD(&uep->ep.ep_list);
+		spin_lock_init(&uep->lock);
 
 		/* init DCP */
 		if (usbhsg_is_dcp(uep)) {
--- linux-4.4.0.orig/drivers/usb/renesas_usbhs/pipe.c
+++ linux-4.4.0/drivers/usb/renesas_usbhs/pipe.c
@@ -279,6 +279,21 @@
 	return -EBUSY;
 }
 
+bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe)
+{
+	u16 val;
+
+	/* Do not support for DCP pipe */
+	if (usbhs_pipe_is_dcp(pipe))
+		return false;
+
+	val = usbhsp_pipectrl_get(pipe);
+	if (val & INBUFM)
+		return true;
+
+	return false;
+}
+
 /*
  *		PID ctrl
  */
@@ -790,6 +805,8 @@
 
 void usbhs_pipe_free(struct usbhs_pipe *pipe)
 {
+	usbhsp_pipe_select(pipe);
+	usbhsp_pipe_cfg_set(pipe, 0xFFFF, 0);
 	usbhsp_put_pipe(pipe);
 }
 
--- linux-4.4.0.orig/drivers/usb/renesas_usbhs/pipe.h
+++ linux-4.4.0/drivers/usb/renesas_usbhs/pipe.h
@@ -89,6 +89,7 @@
 int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
 void usbhs_pipe_clear(struct usbhs_pipe *pipe);
 int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
+bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe);
 void usbhs_pipe_enable(struct usbhs_pipe *pipe);
 void usbhs_pipe_disable(struct usbhs_pipe *pipe);
 void usbhs_pipe_stall(struct usbhs_pipe *pipe);
--- linux-4.4.0.orig/drivers/usb/serial/Kconfig
+++ linux-4.4.0/drivers/usb/serial/Kconfig
@@ -62,7 +62,9 @@
 		- Fundamental Software dongle.
 		- Google USB serial devices
 		- HP4x calculators
+		- Libtransistor USB console
 		- a number of Motorola phones
+		- Motorola Tetra devices
 		- Novatel Wireless GPS receivers
 		- Siemens USB/MPI adapter.
 		- ViVOtech ViVOpay USB device.
--- linux-4.4.0.orig/drivers/usb/serial/ark3116.c
+++ linux-4.4.0/drivers/usb/serial/ark3116.c
@@ -99,10 +99,17 @@
 				 usb_rcvctrlpipe(serial->dev, 0),
 				 0xfe, 0xc0, 0, reg,
 				 buf, 1, ARK_TIMEOUT);
-	if (result < 0)
+	if (result < 1) {
+		dev_err(&serial->interface->dev,
+				"failed to read register %u: %d\n",
+				reg, result);
+		if (result >= 0)
+			result = -EIO;
+
 		return result;
-	else
-		return buf[0];
+	}
+
+	return buf[0];
 }
 
 static inline int calc_divisor(int bps)
@@ -366,23 +373,29 @@
 		dev_dbg(&port->dev,
 			"%s - usb_serial_generic_open failed: %d\n",
 			__func__, result);
-		goto err_out;
+		goto err_free;
 	}
 
 	/* remove any data still left: also clears error state */
 	ark3116_read_reg(serial, UART_RX, buf);
 
 	/* read modem status */
-	priv->msr = ark3116_read_reg(serial, UART_MSR, buf);
+	result = ark3116_read_reg(serial, UART_MSR, buf);
+	if (result < 0)
+		goto err_close;
+	priv->msr = *buf;
+
 	/* read line status */
-	priv->lsr = ark3116_read_reg(serial, UART_LSR, buf);
+	result = ark3116_read_reg(serial, UART_LSR, buf);
+	if (result < 0)
+		goto err_close;
+	priv->lsr = *buf;
 
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result) {
 		dev_err(&port->dev, "submit irq_in urb failed %d\n",
 			result);
-		ark3116_close(port);
-		goto err_out;
+		goto err_close;
 	}
 
 	/* activate interrupts */
@@ -395,8 +408,15 @@
 	if (tty)
 		ark3116_set_termios(tty, port, NULL);
 
-err_out:
 	kfree(buf);
+
+	return 0;
+
+err_close:
+	usb_serial_generic_close(port);
+err_free:
+	kfree(buf);
+
 	return result;
 }
 
--- linux-4.4.0.orig/drivers/usb/serial/ch341.c
+++ linux-4.4.0/drivers/usb/serial/ch341.c
@@ -70,9 +70,12 @@
 
 
 static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(0x4348, 0x5523) },
-	{ USB_DEVICE(0x1a86, 0x7523) },
+	{ USB_DEVICE(0x1a86, 0x5512) },
 	{ USB_DEVICE(0x1a86, 0x5523) },
+	{ USB_DEVICE(0x1a86, 0x7522) },
+	{ USB_DEVICE(0x1a86, 0x7523) },
+	{ USB_DEVICE(0x4348, 0x5523) },
+	{ USB_DEVICE(0x9986, 0x7523) },
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -99,6 +102,8 @@
 	r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
 			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
 			    value, index, NULL, 0, DEFAULT_TIMEOUT);
+	if (r < 0)
+		dev_err(&dev->dev, "failed to send control message: %d\n", r);
 
 	return r;
 }
@@ -116,7 +121,20 @@
 	r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
 			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
 			    value, index, buf, bufsize, DEFAULT_TIMEOUT);
-	return r;
+	if (r < (int)bufsize) {
+		if (r >= 0) {
+			dev_err(&dev->dev,
+				"short control message received (%d < %u)\n",
+				r, bufsize);
+			r = -EIO;
+		}
+
+		dev_err(&dev->dev, "failed to receive control message: %d\n",
+			r);
+		return r;
+	}
+
+	return 0;
 }
 
 static int ch341_set_baudrate(struct usb_device *dev,
@@ -158,9 +176,9 @@
 
 static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
 {
+	const unsigned int size = 2;
 	char *buffer;
 	int r;
-	const unsigned size = 8;
 	unsigned long flags;
 
 	buffer = kmalloc(size, GFP_KERNEL);
@@ -171,14 +189,9 @@
 	if (r < 0)
 		goto out;
 
-	/* setup the private status if available */
-	if (r == 2) {
-		r = 0;
-		spin_lock_irqsave(&priv->lock, flags);
-		priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
-		spin_unlock_irqrestore(&priv->lock, flags);
-	} else
-		r = -EPROTO;
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 out:	kfree(buffer);
 	return r;
@@ -188,9 +201,9 @@
 
 static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
 {
+	const unsigned int size = 2;
 	char *buffer;
 	int r;
-	const unsigned size = 8;
 
 	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer)
@@ -253,7 +266,6 @@
 
 	spin_lock_init(&priv->lock);
 	priv->baud_rate = DEFAULT_BAUD_RATE;
-	priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
 
 	r = ch341_configure(port->serial->dev, priv);
 	if (r < 0)
@@ -315,7 +327,7 @@
 
 	r = ch341_configure(serial->dev, priv);
 	if (r)
-		goto out;
+		return r;
 
 	if (tty)
 		ch341_set_termios(tty, port, NULL);
@@ -325,12 +337,19 @@
 	if (r) {
 		dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n",
 			__func__, r);
-		goto out;
+		return r;
 	}
 
 	r = usb_serial_generic_open(tty, port);
+	if (r)
+		goto err_kill_interrupt_urb;
+
+	return 0;
+
+err_kill_interrupt_urb:
+	usb_kill_urb(port->interrupt_in_urb);
 
-out:	return r;
+	return r;
 }
 
 /* Old_termios contains the original termios settings and
@@ -345,26 +364,25 @@
 
 	baud_rate = tty_get_baud_rate(tty);
 
-	priv->baud_rate = baud_rate;
-
 	if (baud_rate) {
-		spin_lock_irqsave(&priv->lock, flags);
-		priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
-		spin_unlock_irqrestore(&priv->lock, flags);
+		priv->baud_rate = baud_rate;
 		ch341_set_baudrate(port->serial->dev, priv);
-	} else {
-		spin_lock_irqsave(&priv->lock, flags);
-		priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
-		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
-	ch341_set_handshake(port->serial->dev, priv->line_control);
-
 	/* Unimplemented:
 	 * (cflag & CSIZE) : data bits [5, 8]
 	 * (cflag & PARENB) : parity {NONE, EVEN, ODD}
 	 * (cflag & CSTOPB) : stop bits [1, 2]
 	 */
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (C_BAUD(tty) == B0)
+		priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
+	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+		priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	ch341_set_handshake(port->serial->dev, priv->line_control);
 }
 
 static void ch341_break_ctl(struct tty_struct *tty, int break_state)
@@ -539,14 +557,27 @@
 
 static int ch341_reset_resume(struct usb_serial *serial)
 {
+	struct usb_serial_port *port = serial->port[0];
 	struct ch341_private *priv;
+	int ret;
 
-	priv = usb_get_serial_port_data(serial->port[0]);
+	priv = usb_get_serial_port_data(port);
+	if (!priv)
+		return 0;
 
 	/* reconfigure ch341 serial port after bus-reset */
 	ch341_configure(serial->dev, priv);
 
-	return 0;
+	if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
+		ret = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+		if (ret) {
+			dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return usb_serial_generic_resume(serial);
 }
 
 static struct usb_serial_driver ch341_device = {
--- linux-4.4.0.orig/drivers/usb/serial/console.c
+++ linux-4.4.0/drivers/usb/serial/console.c
@@ -189,6 +189,7 @@
 	tty_kref_put(tty);
  reset_open_count:
 	port->port.count = 0;
+	info->port = NULL;
 	usb_autopm_put_interface(serial->interface);
  error_get_interface:
 	usb_serial_put(serial);
--- linux-4.4.0.orig/drivers/usb/serial/cp210x.c
+++ linux-4.4.0/drivers/usb/serial/cp210x.c
@@ -33,7 +33,7 @@
 static void cp210x_close(struct usb_serial_port *);
 static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
 static void cp210x_get_termios_port(struct usb_serial_port *port,
-	unsigned int *cflagp, unsigned int *baudp);
+	tcflag_t *cflagp, unsigned int *baudp);
 static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
 							struct ktermios *);
 static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
@@ -57,6 +57,8 @@
 	{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
 	{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
 	{ USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
+	{ USB_DEVICE(0x0988, 0x0578) }, /* Teraoka AD2000 */
+	{ USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */
 	{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
 	{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
 	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
@@ -75,6 +77,7 @@
 	{ USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */
 	{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
 	{ USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
+	{ USB_DEVICE(0x10C4, 0x8056) }, /* Lorenz Messtechnik devices */
 	{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
 	{ USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */
 	{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
@@ -91,6 +94,9 @@
 	{ 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, 0x817C) }, /* CESINEL MEDCAL N Power Quality Monitor */
+	{ USB_DEVICE(0x10C4, 0x817D) }, /* CESINEL MEDCAL NT Power Quality Monitor */
+	{ USB_DEVICE(0x10C4, 0x817E) }, /* CESINEL MEDCAL S Power Quality Monitor */
 	{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
 	{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
 	{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
@@ -98,6 +104,7 @@
 	{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
 	{ USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
 	{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
+	{ USB_DEVICE(0x10C4, 0x81D7) }, /* IAI Corp. RCB-CV-USB USB to RS485 Adaptor */
 	{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
 	{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
 	{ USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
@@ -107,15 +114,25 @@
 	{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
 	{ USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */
 	{ USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
+	{ USB_DEVICE(0x10C4, 0x82EF) }, /* CESINEL FALCO 6105 AC Power Supply */
+	{ USB_DEVICE(0x10C4, 0x82F1) }, /* CESINEL MEDCAL EFD Earth Fault Detector */
+	{ USB_DEVICE(0x10C4, 0x82F2) }, /* CESINEL MEDCAL ST Network Analyzer */
+	{ USB_DEVICE(0x10C4, 0x82F4) }, /* Starizona MicroTouch */
 	{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
 	{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
 	{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
 	{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
+	{ USB_DEVICE(0x10C4, 0x83AA) }, /* Mark-10 Digital Force Gauge */
 	{ USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
 	{ USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
 	{ USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
 	{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
+	{ USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */
 	{ USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
+	{ USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */
+	{ USB_DEVICE(0x10C4, 0x851E) }, /* CESINEL MEDCAL PT Network Analyzer */
+	{ USB_DEVICE(0x10C4, 0x85A7) }, /* LifeScan OneTouch Verio IQ */
+	{ USB_DEVICE(0x10C4, 0x85B8) }, /* CESINEL ReCon T Energy Logger */
 	{ USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
 	{ USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
 	{ USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
@@ -125,22 +142,36 @@
 	{ USB_DEVICE(0x10C4, 0x8857) },	/* CEL EM357 ZigBee USB Stick */
 	{ USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
 	{ USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
+	{ USB_DEVICE(0x10C4, 0x88D8) }, /* Acuity Brands nLight Air Adapter */
+	{ USB_DEVICE(0x10C4, 0x88FB) }, /* CESINEL MEDCAL STII Network Analyzer */
+	{ USB_DEVICE(0x10C4, 0x8938) }, /* CESINEL MEDCAL S II Network Analyzer */
 	{ USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */
+	{ USB_DEVICE(0x10C4, 0x8962) }, /* Brim Brothers charging dock */
 	{ USB_DEVICE(0x10C4, 0x8977) },	/* CEL MeshWorks DevKit Device */
 	{ USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */
+	{ USB_DEVICE(0x10C4, 0x89A4) }, /* CESINEL FTBC Flexible Thyristor Bridge Controller */
+	{ USB_DEVICE(0x10C4, 0x89FB) }, /* Qivicon ZigBee USB Radio Stick */
 	{ USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */
+	{ USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */
+	{ USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */
 	{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
 	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+	{ USB_DEVICE(0x10C4, 0xEA63) }, /* Silicon Labs Windows Update (CP2101-4/CP2102N) */
 	{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
 	{ USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
+	{ USB_DEVICE(0x10C4, 0xEA7A) }, /* Silicon Labs Windows Update (CP2105) */
+	{ USB_DEVICE(0x10C4, 0xEA7B) }, /* Silicon Labs Windows Update (CP2108) */
 	{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
 	{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
 	{ USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
 	{ USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
 	{ USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
 	{ USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
+	{ USB_DEVICE(0x12B8, 0xEC60) }, /* Link G4 ECU */
+	{ USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */
 	{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
 	{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
+	{ USB_DEVICE(0x155A, 0x1006) },	/* ELDAT Easywave RX09 */
 	{ 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 */
@@ -160,6 +191,18 @@
 	{ USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
 	{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
 	{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
+	{ USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */
+	{ USB_DEVICE(0x18EF, 0xE030) }, /* ELV ALC 8xxx Battery Charger */
+	{ USB_DEVICE(0x18EF, 0xE032) }, /* ELV TFD500 Data Logger */
+	{ USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
+	{ USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */
+	{ USB_DEVICE(0x1901, 0x0194) },	/* GE Healthcare Remote Alarm Box */
+	{ USB_DEVICE(0x1901, 0x0195) },	/* GE B850/B650/B450 CP2104 DP UART interface */
+	{ USB_DEVICE(0x1901, 0x0196) },	/* GE B850 CP2105 DP UART interface */
+	{ USB_DEVICE(0x1901, 0x0197) }, /* GE CS1000 Display serial interface */
+	{ USB_DEVICE(0x1901, 0x0198) }, /* GE CS1000 M.2 Key E serial interface */
+	{ USB_DEVICE(0x199B, 0xBA30) }, /* LORD WSDA-200-USB */
+	{ USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
 	{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
 	{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
 	{ USB_DEVICE(0x1BA4, 0x0002) },	/* Silicon Labs 358x factory default */
@@ -190,6 +233,7 @@
 	{ 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(0x3923, 0x7A0B) }, /* National Instruments USB Serial Console */
 	{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
 	{ } /* Terminating Entry */
 };
@@ -213,6 +257,8 @@
 	.close			= cp210x_close,
 	.break_ctl		= cp210x_break_ctl,
 	.set_termios		= cp210x_set_termios,
+	.throttle		= usb_serial_generic_throttle,
+	.unthrottle		= usb_serial_generic_unthrottle,
 	.tiocmget		= cp210x_tiocmget,
 	.tiocmset		= cp210x_tiocmset,
 	.attach			= cp210x_startup,
@@ -494,7 +540,7 @@
 			&tty->termios.c_cflag, &baud);
 		tty_encode_baud_rate(tty, baud, baud);
 	} else {
-		unsigned int cflag;
+		tcflag_t cflag;
 		cflag = 0;
 		cp210x_get_termios_port(port, &cflag, &baud);
 	}
@@ -505,10 +551,11 @@
  * This is the heart of cp210x_get_termios which always uses a &usb_serial_port.
  */
 static void cp210x_get_termios_port(struct usb_serial_port *port,
-	unsigned int *cflagp, unsigned int *baudp)
+	tcflag_t *cflagp, unsigned int *baudp)
 {
 	struct device *dev = &port->dev;
-	unsigned int cflag, modem_ctl[4];
+	tcflag_t cflag;
+	unsigned int modem_ctl[4];
 	unsigned int baud;
 	unsigned int bits;
 
@@ -774,7 +821,7 @@
 		} else {
 			modem_ctl[0] &= ~0x7B;
 			modem_ctl[0] |= 0x01;
-			modem_ctl[1] |= 0x40;
+			modem_ctl[1] = 0x40;
 			dev_dbg(dev, "%s - flow control = NONE\n", __func__);
 		}
 
@@ -834,7 +881,9 @@
 	unsigned int control;
 	int result;
 
-	cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
+	result = cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
+	if (result)
+		return result;
 
 	result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
 		|((control & CONTROL_RTS) ? TIOCM_RTS : 0)
--- linux-4.4.0.orig/drivers/usb/serial/cyberjack.c
+++ linux-4.4.0/drivers/usb/serial/cyberjack.c
@@ -50,6 +50,7 @@
 #define CYBERJACK_PRODUCT_ID	0x0100
 
 /* Function prototypes */
+static int cyberjack_attach(struct usb_serial *serial);
 static int cyberjack_port_probe(struct usb_serial_port *port);
 static int cyberjack_port_remove(struct usb_serial_port *port);
 static int  cyberjack_open(struct tty_struct *tty,
@@ -77,6 +78,7 @@
 	.description =		"Reiner SCT Cyberjack USB card reader",
 	.id_table =		id_table,
 	.num_ports =		1,
+	.attach =		cyberjack_attach,
 	.port_probe =		cyberjack_port_probe,
 	.port_remove =		cyberjack_port_remove,
 	.open =			cyberjack_open,
@@ -100,6 +102,14 @@
 	short		wrsent;		/* Data already sent */
 };
 
+static int cyberjack_attach(struct usb_serial *serial)
+{
+	if (serial->num_bulk_out < serial->num_ports)
+		return -ENODEV;
+
+	return 0;
+}
+
 static int cyberjack_port_probe(struct usb_serial_port *port)
 {
 	struct cyberjack_private *priv;
@@ -358,11 +368,12 @@
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
 	struct device *dev = &port->dev;
 	int status = urb->status;
+	bool resubmitted = false;
 
-	set_bit(0, &port->write_urbs_free);
 	if (status) {
 		dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
 			__func__, status);
+		set_bit(0, &port->write_urbs_free);
 		return;
 	}
 
@@ -395,6 +406,8 @@
 			goto exit;
 		}
 
+		resubmitted = true;
+
 		dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent);
 		dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled);
 
@@ -411,6 +424,8 @@
 
 exit:
 	spin_unlock(&priv->lock);
+	if (!resubmitted)
+		set_bit(0, &port->write_urbs_free);
 	usb_serial_port_softint(port);
 }
 
--- linux-4.4.0.orig/drivers/usb/serial/cypress_m8.c
+++ linux-4.4.0/drivers/usb/serial/cypress_m8.c
@@ -63,6 +63,7 @@
 
 static const struct usb_device_id id_table_cyphidcomrs232[] = {
 	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+	{ USB_DEVICE(VENDOR_ID_SAI, PRODUCT_ID_CYPHIDCOM) },
 	{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
 	{ USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) },
 	{ }						/* Terminating entry */
@@ -77,6 +78,7 @@
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
 	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+	{ USB_DEVICE(VENDOR_ID_SAI, PRODUCT_ID_CYPHIDCOM) },
 	{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
 	{ USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) },
 	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
@@ -447,6 +449,11 @@
 	struct usb_serial *serial = port->serial;
 	struct cypress_private *priv;
 
+	if (!port->interrupt_out_urb || !port->interrupt_in_urb) {
+		dev_err(&port->dev, "required endpoint is missing\n");
+		return -ENODEV;
+	}
+
 	priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
@@ -606,12 +613,6 @@
 		cypress_set_termios(tty, port, &priv->tmp_termios);
 
 	/* setup the port and start reading from the device */
-	if (!port->interrupt_in_urb) {
-		dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n",
-			__func__);
-		return -1;
-	}
-
 	usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
 		usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
 		port->interrupt_in_urb->transfer_buffer,
@@ -774,7 +775,7 @@
 
 	usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
 		usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
-		port->interrupt_out_buffer, port->interrupt_out_size,
+		port->interrupt_out_buffer, actual_size,
 		cypress_write_int_callback, port, priv->write_urb_interval);
 	result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
 	if (result) {
--- linux-4.4.0.orig/drivers/usb/serial/cypress_m8.h
+++ linux-4.4.0/drivers/usb/serial/cypress_m8.h
@@ -24,6 +24,9 @@
 #define VENDOR_ID_CYPRESS		0x04b4
 #define PRODUCT_ID_CYPHIDCOM		0x5500
 
+/* Simply Automated HID->COM UPB PIM (using Cypress PID 0x5500) */
+#define VENDOR_ID_SAI			0x17dd
+
 /* FRWD Dongle - a GPS sports watch */
 #define VENDOR_ID_FRWD			0x6737
 #define PRODUCT_ID_CYPHIDCOM_FRWD	0x0001
--- linux-4.4.0.orig/drivers/usb/serial/digi_acceleport.c
+++ linux-4.4.0/drivers/usb/serial/digi_acceleport.c
@@ -23,7 +23,6 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/workqueue.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
@@ -201,14 +200,12 @@
 	int dp_throttle_restart;
 	wait_queue_head_t dp_flush_wait;
 	wait_queue_head_t dp_close_wait;	/* wait queue for close */
-	struct work_struct dp_wakeup_work;
 	struct usb_serial_port *dp_port;
 };
 
 
 /* Local Function Declarations */
 
-static void digi_wakeup_write_lock(struct work_struct *work);
 static int digi_write_oob_command(struct usb_serial_port *port,
 	unsigned char *buf, int count, int interruptible);
 static int digi_write_inb_command(struct usb_serial_port *port,
@@ -355,26 +352,6 @@
 	return timeout;
 }
 
-
-/*
- *  Digi Wakeup Write
- *
- *  Wake up port, line discipline, and tty processes sleeping
- *  on writes.
- */
-
-static void digi_wakeup_write_lock(struct work_struct *work)
-{
-	struct digi_port *priv =
-			container_of(work, struct digi_port, dp_wakeup_work);
-	struct usb_serial_port *port = priv->dp_port;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->dp_port_lock, flags);
-	tty_port_tty_wakeup(&port->port);
-	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
-}
-
 /*
  *  Digi Write OOB Command
  *
@@ -986,6 +963,7 @@
 	struct digi_serial *serial_priv;
 	int ret = 0;
 	int status = urb->status;
+	bool wakeup;
 
 	/* port and serial sanity check */
 	if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
@@ -1012,6 +990,7 @@
 	}
 
 	/* try to send any buffered data on this port */
+	wakeup = true;
 	spin_lock(&priv->dp_port_lock);
 	priv->dp_write_urb_in_use = 0;
 	if (priv->dp_out_buf_len > 0) {
@@ -1027,19 +1006,18 @@
 		if (ret == 0) {
 			priv->dp_write_urb_in_use = 1;
 			priv->dp_out_buf_len = 0;
+			wakeup = false;
 		}
 	}
-	/* wake up processes sleeping on writes immediately */
-	tty_port_tty_wakeup(&port->port);
-	/* also queue up a wakeup at scheduler time, in case we */
-	/* lost the race in write_chan(). */
-	schedule_work(&priv->dp_wakeup_work);
-
 	spin_unlock(&priv->dp_port_lock);
+
 	if (ret && ret != -EPERM)
 		dev_err_console(port,
 			"%s: usb_submit_urb failed, ret=%d, port=%d\n",
 			__func__, ret, priv->dp_port_num);
+
+	if (wakeup)
+		tty_port_tty_wakeup(&port->port);
 }
 
 static int digi_write_room(struct tty_struct *tty)
@@ -1239,7 +1217,6 @@
 	init_waitqueue_head(&priv->dp_transmit_idle_wait);
 	init_waitqueue_head(&priv->dp_flush_wait);
 	init_waitqueue_head(&priv->dp_close_wait);
-	INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
 	priv->dp_port = port;
 
 	init_waitqueue_head(&port->write_wait);
@@ -1251,8 +1228,27 @@
 
 static int digi_startup(struct usb_serial *serial)
 {
+	struct device *dev = &serial->interface->dev;
 	struct digi_serial *serial_priv;
 	int ret;
+	int i;
+
+	/* check whether the device has the expected number of endpoints */
+	if (serial->num_port_pointers < serial->type->num_ports + 1) {
+		dev_err(dev, "OOB endpoints missing\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < serial->type->num_ports + 1 ; i++) {
+		if (!serial->port[i]->read_urb) {
+			dev_err(dev, "bulk-in endpoint missing\n");
+			return -ENODEV;
+		}
+		if (!serial->port[i]->write_urb) {
+			dev_err(dev, "bulk-out endpoint missing\n");
+			return -ENODEV;
+		}
+	}
 
 	serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
 	if (!serial_priv)
@@ -1380,25 +1376,30 @@
 {
 	struct usb_serial_port *port = urb->context;
 	struct digi_port *priv = usb_get_serial_port_data(port);
-	int opcode = ((unsigned char *)urb->transfer_buffer)[0];
-	int len = ((unsigned char *)urb->transfer_buffer)[1];
-	int port_status = ((unsigned char *)urb->transfer_buffer)[2];
-	unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3;
+	unsigned char *buf = urb->transfer_buffer;
+	int opcode;
+	int len;
+	int port_status;
+	unsigned char *data;
 	int flag, throttled;
-	int status = urb->status;
-
-	/* do not process callbacks on closed ports */
-	/* but do continue the read chain */
-	if (urb->status == -ENOENT)
-		return 0;
 
 	/* short/multiple packet check */
+	if (urb->actual_length < 2) {
+		dev_warn(&port->dev, "short packet received\n");
+		return -1;
+	}
+
+	opcode = buf[0];
+	len = buf[1];
+
 	if (urb->actual_length != len + 2) {
-		dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, "
-			"status=%d, port=%d, opcode=%d, len=%d, "
-			"actual_length=%d, status=%d\n", __func__, status,
-			priv->dp_port_num, opcode, len, urb->actual_length,
-			port_status);
+		dev_err(&port->dev, "malformed packet received: port=%d, opcode=%d, len=%d, actual_length=%u\n",
+			priv->dp_port_num, opcode, len, urb->actual_length);
+		return -1;
+	}
+
+	if (opcode == DIGI_CMD_RECEIVE_DATA && len < 1) {
+		dev_err(&port->dev, "malformed data packet received\n");
 		return -1;
 	}
 
@@ -1412,6 +1413,9 @@
 
 	/* receive data */
 	if (opcode == DIGI_CMD_RECEIVE_DATA) {
+		port_status = buf[2];
+		data = &buf[3];
+
 		/* get flag from port_status */
 		flag = 0;
 
@@ -1464,16 +1468,20 @@
 	struct usb_serial *serial = port->serial;
 	struct tty_struct *tty;
 	struct digi_port *priv = usb_get_serial_port_data(port);
+	unsigned char *buf = urb->transfer_buffer;
 	int opcode, line, status, val;
 	int i;
 	unsigned int rts;
 
+	if (urb->actual_length < 4)
+		return -1;
+
 	/* handle each oob command */
-	for (i = 0; i < urb->actual_length - 3;) {
-		opcode = ((unsigned char *)urb->transfer_buffer)[i++];
-		line = ((unsigned char *)urb->transfer_buffer)[i++];
-		status = ((unsigned char *)urb->transfer_buffer)[i++];
-		val = ((unsigned char *)urb->transfer_buffer)[i++];
+	for (i = 0; i < urb->actual_length - 3; i += 4) {
+		opcode = buf[i];
+		line = buf[i + 1];
+		status = buf[i + 2];
+		val = buf[i + 3];
 
 		dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
 			opcode, line, status, val);
@@ -1494,13 +1502,14 @@
 			rts = tty->termios.c_cflag & CRTSCTS;
 		
 		if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
+			bool wakeup = false;
+
 			spin_lock(&priv->dp_port_lock);
 			/* convert from digi flags to termiox flags */
 			if (val & DIGI_READ_INPUT_SIGNALS_CTS) {
 				priv->dp_modem_signals |= TIOCM_CTS;
-				/* port must be open to use tty struct */
 				if (rts)
-					tty_port_tty_wakeup(&port->port);
+					wakeup = true;
 			} else {
 				priv->dp_modem_signals &= ~TIOCM_CTS;
 				/* port must be open to use tty struct */
@@ -1519,6 +1528,9 @@
 				priv->dp_modem_signals &= ~TIOCM_CD;
 
 			spin_unlock(&priv->dp_port_lock);
+
+			if (wakeup)
+				tty_port_tty_wakeup(&port->port);
 		} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
 			spin_lock(&priv->dp_port_lock);
 			priv->dp_transmit_idle = 1;
--- linux-4.4.0.orig/drivers/usb/serial/ftdi_sio.c
+++ linux-4.4.0/drivers/usb/serial/ftdi_sio.c
@@ -604,6 +604,8 @@
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+	{ USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLX_PLUS_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_NT_ORION_IO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2_PID) },
@@ -648,6 +650,8 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_PALMSENS_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_IVIUM_XSTAT_PID) },
 	{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
 	{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
 	{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -704,6 +708,7 @@
 	{ USB_DEVICE(XSENS_VID, XSENS_AWINDA_STATION_PID) },
 	{ USB_DEVICE(XSENS_VID, XSENS_CONVERTER_PID) },
 	{ USB_DEVICE(XSENS_VID, XSENS_MTDEVBOARD_PID) },
+	{ USB_DEVICE(XSENS_VID, XSENS_MTIUSBCONVERTER_PID) },
 	{ USB_DEVICE(XSENS_VID, XSENS_MTW_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
 	{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
@@ -771,6 +776,7 @@
 		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
 	{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
 	{ USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) },
+	{ USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) },
 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
@@ -807,10 +813,10 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
 	{ USB_DEVICE(FTDI_VID, CYBER_CORTEX_AV_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
-	{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
-		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
-	{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID),
-		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+	{ USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID, 1) },
+	{ USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID, 1) },
+	{ USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_TINY_PID, 1) },
+	{ USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_TINY_H_PID, 1) },
 	{ USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
@@ -824,6 +830,7 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
+	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) },
 	{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
 
 	/* Papouch devices based on FTDI chip */
@@ -870,6 +877,7 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID,
 					USB_CLASS_VENDOR_SPEC,
 					USB_SUBCLASS_VENDOR_SPEC, 0x00) },
+	{ USB_DEVICE_INTERFACE_NUMBER(ACTEL_VID, MICROSEMI_ARROW_SF2PLUS_BOARD_PID, 2) },
 	{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
 	{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -931,6 +939,7 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_FHE_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
 	{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -983,7 +992,8 @@
 	/* ekey Devices */
 	{ USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) },
 	/* Infineon Devices */
-	{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) },
+	{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC1798_PID, 1) },
+	{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC2X7_PID, 1) },
 	/* GE Healthcare devices */
 	{ USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) },
 	/* Active Research (Actisense) devices */
@@ -1003,6 +1013,30 @@
 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
+	/* ICP DAS I-756xU devices */
+	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7560U_PID) },
+	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
+	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7563U_PID) },
+	{ USB_DEVICE(WICED_VID, WICED_USB20706V2_PID) },
+	{ USB_DEVICE(TI_VID, TI_CC3200_LAUNCHPAD_PID),
+		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+	{ USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) },
+	{ USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) },
+	{ USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) },
+	/* EZPrototypes devices */
+	{ USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
+	{ USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) },
+	/* Sienna devices */
+	{ USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) },
+	{ USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) },
+	/* U-Blox devices */
+	{ USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) },
+	{ USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) },
+	/* FreeCalypso USB adapters */
+	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_BUF_PID),
+		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID),
+		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ }					/* Terminating entry */
 };
 
@@ -1428,10 +1462,13 @@
 			     FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
 			     0, priv->interface,
 			     buf, 1, WDR_TIMEOUT);
-	if (rv < 0)
+	if (rv < 1) {
 		dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
-	else
+		if (rv >= 0)
+			rv = -EIO;
+	} else {
 		priv->latency = buf[0];
+	}
 
 	kfree(buf);
 
@@ -1493,9 +1530,9 @@
 					(new_serial.flags & ASYNC_FLAGS));
 	priv->custom_divisor = new_serial.custom_divisor;
 
+check_and_exit:
 	write_latency_timer(port);
 
-check_and_exit:
 	if ((old_priv.flags & ASYNC_SPD_MASK) !=
 	     (priv->flags & ASYNC_SPD_MASK)) {
 		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
@@ -1796,8 +1833,6 @@
 
 	mutex_init(&priv->cfg_lock);
 
-	priv->flags = ASYNC_LOW_LATENCY;
-
 	if (quirk && quirk->port_probe)
 		quirk->port_probe(priv);
 
@@ -1893,7 +1928,8 @@
 		return ftdi_jtag_probe(serial);
 
 	if (udev->product &&
-		(!strcmp(udev->product, "BeagleBone/XDS100V2") ||
+		(!strcmp(udev->product, "Arrow USB Blaster") ||
+		 !strcmp(udev->product, "BeagleBone/XDS100V2") ||
 		 !strcmp(udev->product, "SNAP Connect E10")))
 		return ftdi_jtag_probe(serial);
 
@@ -2021,12 +2057,11 @@
 #define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE)
 
 static int ftdi_process_packet(struct usb_serial_port *port,
-		struct ftdi_private *priv, char *packet, int len)
+		struct ftdi_private *priv, unsigned char *buf, int len)
 {
+	unsigned char status;
 	int i;
-	char status;
 	char flag;
-	char *ch;
 
 	if (len < 2) {
 		dev_dbg(&port->dev, "malformed packet\n");
@@ -2036,7 +2071,7 @@
 	/* Compare new line status to the old one, signal if different/
 	   N.B. packet may be processed more than once, but differences
 	   are only processed once.  */
-	status = packet[0] & FTDI_STATUS_B0_MASK;
+	status = buf[0] & FTDI_STATUS_B0_MASK;
 	if (status != priv->prev_status) {
 		char diff_status = status ^ priv->prev_status;
 
@@ -2061,50 +2096,55 @@
 		priv->prev_status = status;
 	}
 
+	/* save if the transmitter is empty or not */
+	if (buf[1] & FTDI_RS_TEMT)
+		priv->transmit_empty = 1;
+	else
+		priv->transmit_empty = 0;
+
+	if (len == 2)
+		return 0;	/* status only */
+
+	/*
+	 * Break and error status must only be processed for packets with
+	 * data payload to avoid over-reporting.
+	 */
 	flag = TTY_NORMAL;
-	if (packet[1] & FTDI_RS_ERR_MASK) {
+	if (buf[1] & FTDI_RS_ERR_MASK) {
 		/* Break takes precedence over parity, which takes precedence
 		 * over framing errors */
-		if (packet[1] & FTDI_RS_BI) {
+		if (buf[1] & FTDI_RS_BI) {
 			flag = TTY_BREAK;
 			port->icount.brk++;
 			usb_serial_handle_break(port);
-		} else if (packet[1] & FTDI_RS_PE) {
+		} else if (buf[1] & FTDI_RS_PE) {
 			flag = TTY_PARITY;
 			port->icount.parity++;
-		} else if (packet[1] & FTDI_RS_FE) {
+		} else if (buf[1] & FTDI_RS_FE) {
 			flag = TTY_FRAME;
 			port->icount.frame++;
 		}
 		/* Overrun is special, not associated with a char */
-		if (packet[1] & FTDI_RS_OE) {
+		if (buf[1] & FTDI_RS_OE) {
 			port->icount.overrun++;
 			tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
 		}
 	}
 
-	/* save if the transmitter is empty or not */
-	if (packet[1] & FTDI_RS_TEMT)
-		priv->transmit_empty = 1;
-	else
-		priv->transmit_empty = 0;
-
-	len -= 2;
-	if (!len)
-		return 0;	/* status only */
-	port->icount.rx += len;
-	ch = packet + 2;
+	port->icount.rx += len - 2;
 
 	if (port->port.console && port->sysrq) {
-		for (i = 0; i < len; i++, ch++) {
-			if (!usb_serial_handle_sysrq_char(port, *ch))
-				tty_insert_flip_char(&port->port, *ch, flag);
+		for (i = 2; i < len; i++) {
+			if (usb_serial_handle_sysrq_char(port, buf[i]))
+				continue;
+			tty_insert_flip_char(&port->port, buf[i], flag);
 		}
 	} else {
-		tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len);
+		tty_insert_flip_string_fixed_flag(&port->port, buf + 2, flag,
+				len - 2);
 	}
 
-	return len;
+	return len - 2;
 }
 
 static void ftdi_process_read_urb(struct urb *urb)
@@ -2422,8 +2462,12 @@
 			FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
 			0, priv->interface,
 			buf, len, WDR_TIMEOUT);
-	if (ret < 0) {
+
+	/* NOTE: We allow short responses and handle that below. */
+	if (ret < 1) {
 		dev_err(&port->dev, "failed to get modem status: %d\n", ret);
+		if (ret >= 0)
+			ret = -EIO;
 		ret = usb_translate_errors(ret);
 		goto out;
 	}
--- linux-4.4.0.orig/drivers/usb/serial/ftdi_sio_ids.h
+++ linux-4.4.0/drivers/usb/serial/ftdi_sio_ids.h
@@ -38,6 +38,16 @@
 
 #define FTDI_LUMEL_PD12_PID	0x6002
 
+/*
+ * Custom USB adapters made by Falconia Partners LLC
+ * for FreeCalypso project, ID codes allocated to Falconia by FTDI.
+ */
+#define FTDI_FALCONIA_JTAG_BUF_PID	0x7150
+#define FTDI_FALCONIA_JTAG_UNBUF_PID	0x7151
+
+/* Sienna Serial Interface by Secyourit GmbH */
+#define FTDI_SIENNA_PID		0x8348
+
 /* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
 #define CYBER_CORTEX_AV_PID	0x8698
 
@@ -156,6 +166,7 @@
 #define XSENS_AWINDA_DONGLE_PID 0x0102
 #define XSENS_MTW_PID		0x0200	/* Xsens MTw */
 #define XSENS_MTDEVBOARD_PID	0x0300	/* Motion Tracker Development Board */
+#define XSENS_MTIUSBCONVERTER_PID	0x0301	/* MTi USB converter */
 #define XSENS_CONVERTER_PID	0xD00D	/* Xsens USB-serial converter */
 
 /* Xsens devices using FTDI VID */
@@ -406,6 +417,12 @@
 #define FTDI_4N_GALAXY_DE_3_PID	0xF3C2
 
 /*
+ * Ivium Technologies product IDs
+ */
+#define FTDI_PALMSENS_PID	0xf440
+#define FTDI_IVIUM_XSTAT_PID	0xf441
+
+/*
  * Linx Technologies product ids
  */
 #define LINX_SDMUSBQSS_PID	0xF448	/* Linx SDM-USB-QS-S */
@@ -560,7 +577,9 @@
 /*
  * NovaTech product ids (FTDI_VID)
  */
-#define FTDI_NT_ORIONLXM_PID	0x7c90	/* OrionLXm Substation Automation Platform */
+#define FTDI_NT_ORIONLXM_PID		0x7c90	/* OrionLXm Substation Automation Platform */
+#define FTDI_NT_ORIONLX_PLUS_PID	0x7c91	/* OrionLX+ Substation Automation Platform */
+#define FTDI_NT_ORION_IO_PID		0x7c92	/* Orion I/O */
 
 /*
  * Synapse Wireless product ids (FTDI_VID)
@@ -590,6 +609,12 @@
 #define STK541_PID		0x2109 /* Zigbee Controller */
 
 /*
+ * Texas Instruments
+ */
+#define TI_VID			0x0451
+#define TI_CC3200_LAUNCHPAD_PID	0xC32A /* SimpleLink Wi-Fi CC3200 LaunchPad */
+
+/*
  * Blackfin gnICE JTAG
  * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice
  */
@@ -598,6 +623,13 @@
 #define ADI_GNICEPLUS_PID	0xF001
 
 /*
+ * Cypress WICED USB UART
+ */
+#define CYPRESS_VID			0x04B4
+#define CYPRESS_WICED_BT_USB_PID	0x009B
+#define CYPRESS_WICED_WL_USB_PID	0xF900
+
+/*
  * Microchip Technology, Inc.
  *
  * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are
@@ -615,12 +647,14 @@
  */
 #define RATOC_VENDOR_ID		0x0584
 #define RATOC_PRODUCT_ID_USB60F	0xb020
+#define RATOC_PRODUCT_ID_SCU18	0xb03a
 
 /*
  * Infineon Technologies
  */
-#define INFINEON_VID		0x058b
-#define INFINEON_TRIBOARD_PID	0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */
+#define INFINEON_VID		        0x058b
+#define INFINEON_TRIBOARD_TC1798_PID	0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */
+#define INFINEON_TRIBOARD_TC2X7_PID	0x0043 /* DAS JTAG TriBoard TC2X7 V1.0 */
 
 /*
  * Acton Research Corp.
@@ -665,6 +699,12 @@
 #define BANDB_ZZ_PROG1_USB_PID	0xBA02
 
 /*
+ * Echelon USB Serial Interface
+ */
+#define ECHELON_VID		0x0920
+#define ECHELON_U20_PID		0x7500
+
+/*
  * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
  */
 #define INTREPID_VID		0x093C
@@ -672,6 +712,12 @@
 #define INTREPID_NEOVI_PID	0x0701
 
 /*
+ * WICED USB UART
+ */
+#define WICED_VID		0x0A5C
+#define WICED_USB20706V2_PID	0x6422
+
+/*
  * Definitions for ID TECH (www.idt-net.com) devices
  */
 #define IDTECH_VID		0x0ACD	/* ID TECH Vendor ID */
@@ -853,9 +899,17 @@
 #define	FIC_VID			0x1457
 #define	FIC_NEO1973_DEBUG_PID	0x5118
 
+/*
+ * Actel / Microsemi
+ */
+#define ACTEL_VID				0x1514
+#define MICROSEMI_ARROW_SF2PLUS_BOARD_PID	0x2008
+
 /* Olimex */
 #define OLIMEX_VID			0x15BA
 #define OLIMEX_ARM_USB_OCD_PID		0x0003
+#define OLIMEX_ARM_USB_TINY_PID	0x0004
+#define OLIMEX_ARM_USB_TINY_H_PID	0x002a
 #define OLIMEX_ARM_USB_OCD_H_PID	0x002b
 
 /*
@@ -871,8 +925,25 @@
 #define NOVITUS_BONO_E_PID		0x6010
 
 /*
+ * ICPDAS I-756*U devices
+ */
+#define ICPDAS_VID			0x1b5c
+#define ICPDAS_I7560U_PID		0x0103
+#define ICPDAS_I7561U_PID		0x0104
+#define ICPDAS_I7563U_PID		0x0105
+
+/*
+ * Airbus Defence and Space
+ */
+#define AIRBUS_DS_VID			0x1e8e  /* Vendor ID */
+#define AIRBUS_DS_P8GR			0x6001  /* Tetra P8GR */
+
+/*
  * RT Systems programming cables for various ham radios
  */
+/* This device uses the VID of FTDI */
+#define RTSYSTEMS_USB_VX8_PID   0x9e50  /* USB-VX8 USB to 7 pin modular plug for Yaesu VX-8 radio */
+
 #define RTSYSTEMS_VID		0x2100	/* Vendor ID */
 #define RTSYSTEMS_USB_S03_PID	0x9001	/* RTS-03 USB to Serial Adapter */
 #define RTSYSTEMS_USB_59_PID	0x9e50	/* USB-59 USB to 8 pin plug */
@@ -1256,6 +1327,12 @@
 #define IONICS_PLUGCOMPUTER_PID		0x0102
 
 /*
+ * EZPrototypes (PID reseller)
+ */
+#define EZPROTOTYPES_VID		0x1c40
+#define HJELMSLUND_USB485_ISO_PID	0x0477
+
+/*
  * Dresden Elektronik Sensor Terminal Board
  */
 #define DE_VID			0x1cf1 /* Vendor ID */
@@ -1392,6 +1469,12 @@
 #define FTDI_CINTERION_MC55I_PID	0xA951
 
 /*
+ * Product: FirmwareHubEmulator
+ * Manufacturer: Harman Becker Automotive Systems
+ */
+#define FTDI_FHE_PID		0xA9A0
+
+/*
  * Product: Comet Caller ID decoder
  * Manufacturer: Crucible Technologies
  */
@@ -1476,3 +1559,16 @@
 #define CHETCO_SEASMART_DISPLAY_PID	0xA5AD /* SeaSmart NMEA2000 Display */
 #define CHETCO_SEASMART_LITE_PID	0xA5AE /* SeaSmart Lite USB Adapter */
 #define CHETCO_SEASMART_ANALOG_PID	0xA5AF /* SeaSmart Analog Adapter */
+
+/*
+ * Unjo AB
+ */
+#define UNJO_VID			0x22B7
+#define UNJO_ISODEBUG_V1_PID		0x150D
+
+/*
+ * U-Blox products (http://www.u-blox.com).
+ */
+#define UBLOX_VID			0x1546
+#define UBLOX_C099F9P_ZED_PID		0x0502
+#define UBLOX_C099F9P_ODIN_PID		0x0503
--- linux-4.4.0.orig/drivers/usb/serial/garmin_gps.c
+++ linux-4.4.0/drivers/usb/serial/garmin_gps.c
@@ -138,6 +138,7 @@
 	__u8   privpkt[4*6];
 	spinlock_t lock;
 	struct list_head pktlist;
+	struct usb_anchor write_urbs;
 };
 
 
@@ -906,7 +907,7 @@
 					sizeof(GARMIN_START_SESSION_REQ), 0);
 
 			if (status < 0)
-				break;
+				goto err_kill_urbs;
 		}
 
 		if (status > 0)
@@ -914,6 +915,12 @@
 	}
 
 	return status;
+
+err_kill_urbs:
+	usb_kill_anchored_urbs(&garmin_data_p->write_urbs);
+	usb_kill_urb(port->interrupt_in_urb);
+
+	return status;
 }
 
 
@@ -931,7 +938,6 @@
 	spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
 	/* shutdown any bulk reads that might be going on */
-	usb_kill_urb(port->write_urb);
 	usb_kill_urb(port->read_urb);
 
 	if (garmin_data_p->state == STATE_RESET)
@@ -954,7 +960,7 @@
 
 	/* shutdown our urbs */
 	usb_kill_urb(port->read_urb);
-	usb_kill_urb(port->write_urb);
+	usb_kill_anchored_urbs(&garmin_data_p->write_urbs);
 
 	/* keep reset state so we know that we must start a new session */
 	if (garmin_data_p->state != STATE_RESET)
@@ -1038,12 +1044,15 @@
 	}
 
 	/* send it down the pipe */
+	usb_anchor_urb(urb, &garmin_data_p->write_urbs);
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status) {
 		dev_err(&port->dev,
 		   "%s - usb_submit_urb(write bulk) failed with status = %d\n",
 				__func__, status);
 		count = status;
+		usb_unanchor_urb(urb);
+		kfree(buffer);
 	}
 
 	/* we are done with this urb, so let the host driver
@@ -1153,8 +1162,8 @@
 		   send it directly to the tty port */
 		if (garmin_data_p->flags & FLAGS_QUEUING) {
 			pkt_add(garmin_data_p, data, data_length);
-		} else if (bulk_data ||
-			   getLayerId(data) == GARMIN_LAYERID_APPL) {
+		} else if (bulk_data || (data_length >= sizeof(u32) &&
+				getLayerId(data) == GARMIN_LAYERID_APPL)) {
 
 			spin_lock_irqsave(&garmin_data_p->lock, flags);
 			garmin_data_p->flags |= APP_RESP_SEEN;
@@ -1401,9 +1410,16 @@
 	garmin_data_p->state = 0;
 	garmin_data_p->flags = 0;
 	garmin_data_p->count = 0;
+	init_usb_anchor(&garmin_data_p->write_urbs);
 	usb_set_serial_port_data(port, garmin_data_p);
 
 	status = garmin_init_session(port);
+	if (status)
+		goto err_free;
+
+	return 0;
+err_free:
+	kfree(garmin_data_p);
 
 	return status;
 }
@@ -1413,6 +1429,7 @@
 {
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 
+	usb_kill_anchored_urbs(&garmin_data_p->write_urbs);
 	usb_kill_urb(port->interrupt_in_urb);
 	del_timer_sync(&garmin_data_p->timer);
 	kfree(garmin_data_p);
--- linux-4.4.0.orig/drivers/usb/serial/generic.c
+++ linux-4.4.0/drivers/usb/serial/generic.c
@@ -350,39 +350,59 @@
 	struct usb_serial_port *port = urb->context;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned long flags;
+	bool stopped = false;
+	int status = urb->status;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
 		if (urb == port->read_urbs[i])
 			break;
 	}
-	set_bit(i, &port->read_urbs_free);
 
 	dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
 							urb->actual_length);
-	switch (urb->status) {
+	switch (status) {
 	case 0:
+		usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
+							data);
+		port->serial->type->process_read_urb(urb);
 		break;
 	case -ENOENT:
 	case -ECONNRESET:
 	case -ESHUTDOWN:
 		dev_dbg(&port->dev, "%s - urb stopped: %d\n",
-							__func__, urb->status);
-		return;
+							__func__, status);
+		stopped = true;
+		break;
 	case -EPIPE:
 		dev_err(&port->dev, "%s - urb stopped: %d\n",
-							__func__, urb->status);
-		return;
+							__func__, status);
+		stopped = true;
+		break;
 	default:
 		dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
-							__func__, urb->status);
-		goto resubmit;
+							__func__, status);
+		break;
 	}
 
-	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
-	port->serial->type->process_read_urb(urb);
+	/*
+	 * Make sure URB processing is done before marking as free to avoid
+	 * racing with unthrottle() on another CPU. Matches the barriers
+	 * implied by the test_and_clear_bit() in
+	 * usb_serial_generic_submit_read_urb().
+	 */
+	smp_mb__before_atomic();
+	set_bit(i, &port->read_urbs_free);
+	/*
+	 * Make sure URB is marked as free before checking the throttled flag
+	 * to avoid racing with unthrottle() on another CPU. Matches the
+	 * smp_mb() in unthrottle().
+	 */
+	smp_mb__after_atomic();
+
+	if (stopped)
+		return;
 
-resubmit:
 	/* Throttle the device if requested by tty */
 	spin_lock_irqsave(&port->lock, flags);
 	port->throttled = port->throttle_req;
@@ -399,6 +419,7 @@
 {
 	unsigned long flags;
 	struct usb_serial_port *port = urb->context;
+	int status = urb->status;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
@@ -410,22 +431,22 @@
 	set_bit(i, &port->write_urbs_free);
 	spin_unlock_irqrestore(&port->lock, flags);
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		break;
 	case -ENOENT:
 	case -ECONNRESET:
 	case -ESHUTDOWN:
 		dev_dbg(&port->dev, "%s - urb stopped: %d\n",
-							__func__, urb->status);
+							__func__, status);
 		return;
 	case -EPIPE:
 		dev_err_console(port, "%s - urb stopped: %d\n",
-							__func__, urb->status);
+							__func__, status);
 		return;
 	default:
 		dev_err_console(port, "%s - nonzero urb status: %d\n",
-							__func__, urb->status);
+							__func__, status);
 		goto resubmit;
 	}
 
@@ -456,6 +477,12 @@
 	port->throttled = port->throttle_req = 0;
 	spin_unlock_irq(&port->lock);
 
+	/*
+	 * Matches the smp_mb__after_atomic() in
+	 * usb_serial_generic_read_bulk_callback().
+	 */
+	smp_mb();
+
 	if (was_throttled)
 		usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
 }
--- linux-4.4.0.orig/drivers/usb/serial/io_edgeport.c
+++ linux-4.4.0/drivers/usb/serial/io_edgeport.c
@@ -492,20 +492,24 @@
 	int result;
 	struct usb_serial *serial = ep->serial;
 	struct edgeport_product_info *product_info = &ep->product_info;
-	struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+	struct edge_compatibility_descriptor *epic;
 	struct edge_compatibility_bits *bits;
 	struct device *dev = &serial->dev->dev;
 
 	ep->is_epic = 0;
+
+	epic = kmalloc(sizeof(*epic), GFP_KERNEL);
+	if (!epic)
+		return -ENOMEM;
+
 	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 				 USB_REQUEST_ION_GET_EPIC_DESC,
 				 0xC0, 0x00, 0x00,
-				 &ep->epic_descriptor,
-				 sizeof(struct edge_compatibility_descriptor),
+				 epic, sizeof(*epic),
 				 300);
-
-	if (result > 0) {
+	if (result == sizeof(*epic)) {
 		ep->is_epic = 1;
+		memcpy(&ep->epic_descriptor, epic, sizeof(*epic));
 		memset(product_info, 0, sizeof(struct edgeport_product_info));
 
 		product_info->NumPorts = epic->NumPorts;
@@ -534,8 +538,16 @@
 		dev_dbg(dev, "  IOSPWriteLCR     : %s\n", bits->IOSPWriteLCR	? "TRUE": "FALSE");
 		dev_dbg(dev, "  IOSPSetBaudRate  : %s\n", bits->IOSPSetBaudRate	? "TRUE": "FALSE");
 		dev_dbg(dev, "  TrueEdgeport     : %s\n", bits->TrueEdgeport	? "TRUE": "FALSE");
+
+		result = 0;
+	} else if (result >= 0) {
+		dev_warn(&serial->interface->dev, "short epic descriptor received: %d\n",
+			 result);
+		result = -EIO;
 	}
 
+	kfree(epic);
+
 	return result;
 }
 
@@ -560,6 +572,7 @@
 	struct usb_serial_port *port;
 	unsigned char *data = urb->transfer_buffer;
 	int length = urb->actual_length;
+	unsigned long flags;
 	int bytes_avail;
 	int position;
 	int txCredits;
@@ -591,7 +604,7 @@
 		if (length > 1) {
 			bytes_avail = data[0] | (data[1] << 8);
 			if (bytes_avail) {
-				spin_lock(&edge_serial->es_lock);
+				spin_lock_irqsave(&edge_serial->es_lock, flags);
 				edge_serial->rxBytesAvail += bytes_avail;
 				dev_dbg(dev,
 					"%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n",
@@ -614,22 +627,25 @@
 						edge_serial->read_in_progress = false;
 					}
 				}
-				spin_unlock(&edge_serial->es_lock);
+				spin_unlock_irqrestore(&edge_serial->es_lock,
+						       flags);
 			}
 		}
 		/* grab the txcredits for the ports if available */
 		position = 2;
 		portNumber = 0;
-		while ((position < length) &&
+		while ((position < length - 1) &&
 				(portNumber < edge_serial->serial->num_ports)) {
 			txCredits = data[position] | (data[position+1] << 8);
 			if (txCredits) {
 				port = edge_serial->serial->port[portNumber];
 				edge_port = usb_get_serial_port_data(port);
-				if (edge_port->open) {
-					spin_lock(&edge_port->ep_lock);
+				if (edge_port && edge_port->open) {
+					spin_lock_irqsave(&edge_port->ep_lock,
+							  flags);
 					edge_port->txCredits += txCredits;
-					spin_unlock(&edge_port->ep_lock);
+					spin_unlock_irqrestore(&edge_port->ep_lock,
+							       flags);
 					dev_dbg(dev, "%s - txcredits for port%d = %d\n",
 						__func__, portNumber,
 						edge_port->txCredits);
@@ -670,6 +686,7 @@
 	int			retval;
 	__u16			raw_data_length;
 	int status = urb->status;
+	unsigned long flags;
 
 	if (status) {
 		dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
@@ -689,7 +706,7 @@
 
 	usb_serial_debug_data(dev, __func__, raw_data_length, data);
 
-	spin_lock(&edge_serial->es_lock);
+	spin_lock_irqsave(&edge_serial->es_lock, flags);
 
 	/* decrement our rxBytes available by the number that we just got */
 	edge_serial->rxBytesAvail -= raw_data_length;
@@ -713,7 +730,7 @@
 		edge_serial->read_in_progress = false;
 	}
 
-	spin_unlock(&edge_serial->es_lock);
+	spin_unlock_irqrestore(&edge_serial->es_lock, flags);
 }
 
 
@@ -1654,7 +1671,8 @@
 static void process_rcvd_data(struct edgeport_serial *edge_serial,
 				unsigned char *buffer, __u16 bufferLength)
 {
-	struct device *dev = &edge_serial->serial->dev->dev;
+	struct usb_serial *serial = edge_serial->serial;
+	struct device *dev = &serial->dev->dev;
 	struct usb_serial_port *port;
 	struct edgeport_port *edge_port;
 	__u16 lastBufferLength;
@@ -1759,11 +1777,10 @@
 
 			/* spit this data back into the tty driver if this
 			   port is open */
-			if (rxLen) {
-				port = edge_serial->serial->port[
-							edge_serial->rxPort];
+			if (rxLen && edge_serial->rxPort < serial->num_ports) {
+				port = serial->port[edge_serial->rxPort];
 				edge_port = usb_get_serial_port_data(port);
-				if (edge_port->open) {
+				if (edge_port && edge_port->open) {
 					dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n",
 						__func__, rxLen,
 						edge_serial->rxPort);
@@ -1771,8 +1788,8 @@
 							rxLen);
 					edge_port->port->icount.rx += rxLen;
 				}
-				buffer += rxLen;
 			}
+			buffer += rxLen;
 			break;
 
 		case EXPECT_HDR3:	/* Expect 3rd byte of status header */
@@ -1807,6 +1824,8 @@
 	__u8 code = edge_serial->rxStatusCode;
 
 	/* switch the port pointer to the one being currently talked about */
+	if (edge_serial->rxPort >= edge_serial->serial->num_ports)
+		return;
 	port = edge_serial->serial->port[edge_serial->rxPort];
 	edge_port = usb_get_serial_port_data(port);
 	if (edge_port == NULL) {
@@ -2097,8 +2116,7 @@
  * rom_read
  *	reads a number of bytes from the Edgeport device starting at the given
  *	address.
- *	If successful returns the number of bytes read, otherwise it returns
- *	a negative error number of the problem.
+ *	Returns zero on success or a negative error number.
  ****************************************************************************/
 static int rom_read(struct usb_serial *serial, __u16 extAddr,
 					__u16 addr, __u16 length, __u8 *data)
@@ -2123,12 +2141,17 @@
 					USB_REQUEST_ION_READ_ROM,
 					0xC0, addr, extAddr, transfer_buffer,
 					current_length, 300);
-		if (result < 0)
+		if (result < current_length) {
+			if (result >= 0)
+				result = -EIO;
 			break;
+		}
 		memcpy(data, transfer_buffer, current_length);
 		length -= current_length;
 		addr += current_length;
 		data += current_length;
+
+		result = 0;
 	}
 
 	kfree(transfer_buffer);
@@ -2203,7 +2226,6 @@
 		/* something went wrong */
 		dev_err(dev, "%s - usb_submit_urb(write command) failed, status = %d\n",
 			__func__, status);
-		usb_kill_urb(urb);
 		usb_free_urb(urb);
 		atomic_dec(&CmdUrbs);
 		return status;
@@ -2585,9 +2607,10 @@
 				EDGE_MANUF_DESC_LEN,
 				(__u8 *)(&edge_serial->manuf_descriptor));
 
-	if (response < 1)
-		dev_err(dev, "error in getting manufacturer descriptor\n");
-	else {
+	if (response < 0) {
+		dev_err(dev, "error in getting manufacturer descriptor: %d\n",
+				response);
+	} else {
 		char string[30];
 		dev_dbg(dev, "**Manufacturer Descriptor\n");
 		dev_dbg(dev, "  RomSize:        %dK\n",
@@ -2644,9 +2667,10 @@
 				EDGE_BOOT_DESC_LEN,
 				(__u8 *)(&edge_serial->boot_descriptor));
 
-	if (response < 1)
-		dev_err(dev, "error in getting boot descriptor\n");
-	else {
+	if (response < 0) {
+		dev_err(dev, "error in getting boot descriptor: %d\n",
+				response);
+	} else {
 		dev_dbg(dev, "**Boot Descriptor:\n");
 		dev_dbg(dev, "  BootCodeLength: %d\n",
 			le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength));
@@ -2761,6 +2785,11 @@
 					EDGE_COMPATIBILITY_MASK1,
 					EDGE_COMPATIBILITY_MASK2 };
 
+	if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
 	dev = serial->dev;
 
 	/* create our private serial structure */
@@ -2784,7 +2813,7 @@
 	dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
 	/* Read the epic descriptor */
-	if (get_epic_descriptor(edge_serial) <= 0) {
+	if (get_epic_descriptor(edge_serial) < 0) {
 		/* memcpy descriptor to Supports structures */
 		memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
 		       sizeof(struct edge_compatibility_bits));
@@ -2837,16 +2866,18 @@
 	response = 0;
 
 	if (edge_serial->is_epic) {
+		struct usb_host_interface *alt;
+
+		alt = serial->interface->cur_altsetting;
+
 		/* EPIC thing, set up our interrupt polling now and our read
 		 * urb, so that the device knows it really is connected. */
 		interrupt_in_found = bulk_in_found = bulk_out_found = false;
-		for (i = 0; i < serial->interface->altsetting[0]
-						.desc.bNumEndpoints; ++i) {
+		for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
 			struct usb_endpoint_descriptor *endpoint;
 			int buffer_size;
 
-			endpoint = &serial->interface->altsetting[0].
-							endpoint[i].desc;
+			endpoint = &alt->endpoint[i].desc;
 			buffer_size = usb_endpoint_maxp(endpoint);
 			if (!interrupt_in_found &&
 			    (usb_endpoint_is_int_in(endpoint))) {
@@ -2856,14 +2887,16 @@
 				/* not set up yet, so do it now */
 				edge_serial->interrupt_read_urb =
 						usb_alloc_urb(0, GFP_KERNEL);
-				if (!edge_serial->interrupt_read_urb)
-					return -ENOMEM;
+				if (!edge_serial->interrupt_read_urb) {
+					response = -ENOMEM;
+					break;
+				}
 
 				edge_serial->interrupt_in_buffer =
 					kmalloc(buffer_size, GFP_KERNEL);
 				if (!edge_serial->interrupt_in_buffer) {
-					usb_free_urb(edge_serial->interrupt_read_urb);
-					return -ENOMEM;
+					response = -ENOMEM;
+					break;
 				}
 				edge_serial->interrupt_in_endpoint =
 						endpoint->bEndpointAddress;
@@ -2891,14 +2924,16 @@
 				/* not set up yet, so do it now */
 				edge_serial->read_urb =
 						usb_alloc_urb(0, GFP_KERNEL);
-				if (!edge_serial->read_urb)
-					return -ENOMEM;
+				if (!edge_serial->read_urb) {
+					response = -ENOMEM;
+					break;
+				}
 
 				edge_serial->bulk_in_buffer =
 					kmalloc(buffer_size, GFP_KERNEL);
 				if (!edge_serial->bulk_in_buffer) {
-					usb_free_urb(edge_serial->read_urb);
-					return -ENOMEM;
+					response = -ENOMEM;
+					break;
 				}
 				edge_serial->bulk_in_endpoint =
 						endpoint->bEndpointAddress;
@@ -2924,20 +2959,39 @@
 			}
 		}
 
-		if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) {
-			dev_err(ddev, "Error - the proper endpoints were not found!\n");
-			return -ENODEV;
+		if (response || !interrupt_in_found || !bulk_in_found ||
+							!bulk_out_found) {
+			if (!response) {
+				dev_err(ddev, "expected endpoints not found\n");
+				response = -ENODEV;
+			}
+
+			goto error;
 		}
 
 		/* start interrupt read for this edgeport this interrupt will
 		 * continue as long as the edgeport is connected */
 		response = usb_submit_urb(edge_serial->interrupt_read_urb,
 								GFP_KERNEL);
-		if (response)
+		if (response) {
 			dev_err(ddev, "%s - Error %d submitting control urb\n",
 				__func__, response);
+
+			goto error;
+		}
 	}
 	return response;
+
+error:
+	usb_free_urb(edge_serial->interrupt_read_urb);
+	kfree(edge_serial->interrupt_in_buffer);
+
+	usb_free_urb(edge_serial->read_urb);
+	kfree(edge_serial->bulk_in_buffer);
+
+	kfree(edge_serial);
+
+	return response;
 }
 
 
@@ -2949,16 +3003,9 @@
 {
 	struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
 
-	/* stop reads and writes on all ports */
-	/* free up our endpoint stuff */
 	if (edge_serial->is_epic) {
 		usb_kill_urb(edge_serial->interrupt_read_urb);
-		usb_free_urb(edge_serial->interrupt_read_urb);
-		kfree(edge_serial->interrupt_in_buffer);
-
 		usb_kill_urb(edge_serial->read_urb);
-		usb_free_urb(edge_serial->read_urb);
-		kfree(edge_serial->bulk_in_buffer);
 	}
 }
 
@@ -2971,6 +3018,16 @@
 {
 	struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
 
+	if (edge_serial->is_epic) {
+		usb_kill_urb(edge_serial->interrupt_read_urb);
+		usb_free_urb(edge_serial->interrupt_read_urb);
+		kfree(edge_serial->interrupt_in_buffer);
+
+		usb_kill_urb(edge_serial->read_urb);
+		usb_free_urb(edge_serial->read_urb);
+		kfree(edge_serial->bulk_in_buffer);
+	}
+
 	kfree(edge_serial);
 }
 
--- linux-4.4.0.orig/drivers/usb/serial/io_ti.c
+++ linux-4.4.0/drivers/usb/serial/io_ti.c
@@ -1499,8 +1499,7 @@
 
 		dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__);
 
-		/* return an error on purpose */
-		return -ENODEV;
+		return 1;
 	}
 
 stayinbootmode:
@@ -1508,7 +1507,7 @@
 	dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__);
 	serial->product_info.TiMode = TI_MODE_BOOT;
 
-	return 0;
+	return 1;
 }
 
 static int ti_do_config(struct edgeport_port *port, int feature, int on)
@@ -1675,6 +1674,12 @@
 	function    = TIUMP_GET_FUNC_FROM_CODE(data[0]);
 	dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__,
 		port_number, function, data[1]);
+
+	if (port_number >= edge_serial->serial->num_ports) {
+		dev_err(dev, "bad port number %d\n", port_number);
+		goto exit;
+	}
+
 	port = edge_serial->serial->port[port_number];
 	edge_port = usb_get_serial_port_data(port);
 	if (!edge_port) {
@@ -1756,7 +1761,7 @@
 
 	port_number = edge_port->port->port_number;
 
-	if (edge_port->lsr_event) {
+	if (urb->actual_length > 0 && edge_port->lsr_event) {
 		edge_port->lsr_event = 0;
 		dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n",
 			__func__, port_number, edge_port->lsr_mask, *data);
@@ -2344,8 +2349,11 @@
 	if (!baud) {
 		/* pick a default, any default... */
 		baud = 9600;
-	} else
+	} else {
+		/* Avoid a zero divisor. */
+		baud = min(baud, 461550);
 		tty_encode_baud_rate(tty, baud, baud);
+	}
 
 	edge_port->baud_rate = baud;
 	config->wBaudRate = (__u16)((461550L + baud/2) / baud);
@@ -2549,6 +2557,13 @@
 	int status;
 	u16 product_id;
 
+	/* Make sure we have the required endpoints when in download mode. */
+	if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) {
+		if (serial->num_bulk_in < serial->num_ports ||
+				serial->num_bulk_out < serial->num_ports)
+			return -ENODEV;
+	}
+
 	/* create our private serial structure */
 	edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
 	if (!edge_serial)
@@ -2556,14 +2571,18 @@
 
 	mutex_init(&edge_serial->es_lock);
 	edge_serial->serial = serial;
+	INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
 	usb_set_serial_data(serial, edge_serial);
 
 	status = download_fw(edge_serial);
-	if (status) {
+	if (status < 0) {
 		kfree(edge_serial);
 		return status;
 	}
 
+	if (status > 0)
+		return 1;	/* bind but do not register any ports */
+
 	product_id = le16_to_cpu(
 			edge_serial->serial->dev->descriptor.idProduct);
 
@@ -2575,7 +2594,6 @@
 		}
 	}
 
-	INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
 	edge_heartbeat_schedule(edge_serial);
 
 	return 0;
@@ -2583,6 +2601,9 @@
 
 static void edge_disconnect(struct usb_serial *serial)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
+
+	cancel_delayed_work_sync(&edge_serial->heartbeat_work);
 }
 
 static void edge_release(struct usb_serial *serial)
--- linux-4.4.0.orig/drivers/usb/serial/io_ti.h
+++ linux-4.4.0/drivers/usb/serial/io_ti.h
@@ -178,7 +178,7 @@
 }  __attribute__((packed));
 
 
-#define TIUMP_GET_PORT_FROM_CODE(c)	(((c) >> 4) - 3)
+#define TIUMP_GET_PORT_FROM_CODE(c)	(((c) >> 6) & 0x01)
 #define TIUMP_GET_FUNC_FROM_CODE(c)	((c) & 0x0f)
 #define TIUMP_INTERRUPT_CODE_LSR	0x03
 #define TIUMP_INTERRUPT_CODE_MSR	0x04
--- linux-4.4.0.orig/drivers/usb/serial/ir-usb.c
+++ linux-4.4.0/drivers/usb/serial/ir-usb.c
@@ -49,9 +49,10 @@
 static int xbof = -1;
 
 static int  ir_startup (struct usb_serial *serial);
-static int  ir_open(struct tty_struct *tty, struct usb_serial_port *port);
-static int ir_prepare_write_buffer(struct usb_serial_port *port,
-						void *dest, size_t size);
+static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
+		const unsigned char *buf, int count);
+static int ir_write_room(struct tty_struct *tty);
+static void ir_write_bulk_callback(struct urb *urb);
 static void ir_process_read_urb(struct urb *urb);
 static void ir_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios);
@@ -81,8 +82,9 @@
 	.num_ports		= 1,
 	.set_termios		= ir_set_termios,
 	.attach			= ir_startup,
-	.open			= ir_open,
-	.prepare_write_buffer	= ir_prepare_write_buffer,
+	.write			= ir_write,
+	.write_room		= ir_write_room,
+	.write_bulk_callback	= ir_write_bulk_callback,
 	.process_read_urb	= ir_process_read_urb,
 };
 
@@ -198,6 +200,9 @@
 {
 	struct usb_irda_cs_descriptor *irda_desc;
 
+	if (serial->num_bulk_in < 1 || serial->num_bulk_out < 1)
+		return -ENODEV;
+
 	irda_desc = irda_usb_find_class_desc(serial, 0);
 	if (!irda_desc) {
 		dev_err(&serial->dev->dev,
@@ -252,35 +257,102 @@
 	return 0;
 }
 
-static int ir_open(struct tty_struct *tty, struct usb_serial_port *port)
+static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
+		const unsigned char *buf, int count)
 {
-	int i;
+	struct urb *urb = NULL;
+	unsigned long flags;
+	int ret;
 
-	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
-		port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET;
+	if (port->bulk_out_size == 0)
+		return -EINVAL;
 
-	/* Start reading from the device */
-	return usb_serial_generic_open(tty, port);
-}
+	if (count == 0)
+		return 0;
 
-static int ir_prepare_write_buffer(struct usb_serial_port *port,
-						void *dest, size_t size)
-{
-	unsigned char *buf = dest;
-	int count;
+	count = min(count, port->bulk_out_size - 1);
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (__test_and_clear_bit(0, &port->write_urbs_free)) {
+		urb = port->write_urbs[0];
+		port->tx_bytes += count;
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (!urb)
+		return 0;
 
 	/*
 	 * The first byte of the packet we send to the device contains an
-	 * inbound header which indicates an additional number of BOFs and
+	 * outbound header which indicates an additional number of BOFs and
 	 * a baud rate change.
 	 *
 	 * See section 5.4.2.2 of the USB IrDA spec.
 	 */
-	*buf = ir_xbof | ir_baud;
+	*(u8 *)urb->transfer_buffer = ir_xbof | ir_baud;
+
+	memcpy(urb->transfer_buffer + 1, buf, count);
+
+	urb->transfer_buffer_length = count + 1;
+	urb->transfer_flags = URB_ZERO_PACKET;
+
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret) {
+		dev_err(&port->dev, "failed to submit write urb: %d\n", ret);
+
+		spin_lock_irqsave(&port->lock, flags);
+		__set_bit(0, &port->write_urbs_free);
+		port->tx_bytes -= count;
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		return ret;
+	}
+
+	return count;
+}
+
+static void ir_write_bulk_callback(struct urb *urb)
+{
+	struct usb_serial_port *port = urb->context;
+	int status = urb->status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	__set_bit(0, &port->write_urbs_free);
+	port->tx_bytes -= urb->transfer_buffer_length - 1;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	switch (status) {
+	case 0:
+		break;
+	case -ENOENT:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		dev_dbg(&port->dev, "write urb stopped: %d\n", status);
+		return;
+	case -EPIPE:
+		dev_err(&port->dev, "write urb stopped: %d\n", status);
+		return;
+	default:
+		dev_err(&port->dev, "nonzero write-urb status: %d\n", status);
+		break;
+	}
+
+	usb_serial_port_softint(port);
+}
+
+static int ir_write_room(struct tty_struct *tty)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	int count = 0;
+
+	if (port->bulk_out_size == 0)
+		return 0;
+
+	if (test_bit(0, &port->write_urbs_free))
+		count = port->bulk_out_size - 1;
 
-	count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1,
-								&port->lock);
-	return count + 1;
+	return count;
 }
 
 static void ir_process_read_urb(struct urb *urb)
@@ -333,34 +405,34 @@
 
 	switch (baud) {
 	case 2400:
-		ir_baud = USB_IRDA_BR_2400;
+		ir_baud = USB_IRDA_LS_2400;
 		break;
 	case 9600:
-		ir_baud = USB_IRDA_BR_9600;
+		ir_baud = USB_IRDA_LS_9600;
 		break;
 	case 19200:
-		ir_baud = USB_IRDA_BR_19200;
+		ir_baud = USB_IRDA_LS_19200;
 		break;
 	case 38400:
-		ir_baud = USB_IRDA_BR_38400;
+		ir_baud = USB_IRDA_LS_38400;
 		break;
 	case 57600:
-		ir_baud = USB_IRDA_BR_57600;
+		ir_baud = USB_IRDA_LS_57600;
 		break;
 	case 115200:
-		ir_baud = USB_IRDA_BR_115200;
+		ir_baud = USB_IRDA_LS_115200;
 		break;
 	case 576000:
-		ir_baud = USB_IRDA_BR_576000;
+		ir_baud = USB_IRDA_LS_576000;
 		break;
 	case 1152000:
-		ir_baud = USB_IRDA_BR_1152000;
+		ir_baud = USB_IRDA_LS_1152000;
 		break;
 	case 4000000:
-		ir_baud = USB_IRDA_BR_4000000;
+		ir_baud = USB_IRDA_LS_4000000;
 		break;
 	default:
-		ir_baud = USB_IRDA_BR_9600;
+		ir_baud = USB_IRDA_LS_9600;
 		baud = 9600;
 	}
 
--- linux-4.4.0.orig/drivers/usb/serial/iuu_phoenix.c
+++ linux-4.4.0/drivers/usb/serial/iuu_phoenix.c
@@ -68,6 +68,16 @@
 	u32 clk;
 };
 
+static int iuu_attach(struct usb_serial *serial)
+{
+	unsigned char num_ports = serial->num_ports;
+
+	if (serial->num_bulk_in < num_ports || serial->num_bulk_out < num_ports)
+		return -ENODEV;
+
+	return 0;
+}
+
 static int iuu_port_probe(struct usb_serial_port *port)
 {
 	struct iuu_private *priv;
@@ -541,23 +551,29 @@
 	struct device *dev = &port->dev;
 	int i;
 	int status;
-	u8 rxcmd = IUU_UART_RX;
+	u8 *rxcmd;
 	struct iuu_private *priv = usb_get_serial_port_data(port);
 
 	if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
 		return -EIO;
 
+	rxcmd = kmalloc(1, GFP_KERNEL);
+	if (!rxcmd)
+		return -ENOMEM;
+
+	rxcmd[0] = IUU_UART_RX;
+
 	for (i = 0; i < 2; i++) {
-		status = bulk_immediate(port, &rxcmd, 1);
+		status = bulk_immediate(port, rxcmd, 1);
 		if (status != IUU_OPERATION_OK) {
 			dev_dbg(dev, "%s - uart_flush_write error\n", __func__);
-			return status;
+			goto out_free;
 		}
 
 		status = read_immediate(port, &priv->len, 1);
 		if (status != IUU_OPERATION_OK) {
 			dev_dbg(dev, "%s - uart_flush_read error\n", __func__);
-			return status;
+			goto out_free;
 		}
 
 		if (priv->len > 0) {
@@ -565,12 +581,16 @@
 			status = read_immediate(port, priv->buf, priv->len);
 			if (status != IUU_OPERATION_OK) {
 				dev_dbg(dev, "%s - uart_flush_read error\n", __func__);
-				return status;
+				goto out_free;
 			}
 		}
 	}
 	dev_dbg(dev, "%s - uart_flush_read OK!\n", __func__);
 	iuu_led(port, 0, 0xF000, 0, 0xFF);
+
+out_free:
+	kfree(rxcmd);
+
 	return status;
 }
 
@@ -707,14 +727,16 @@
 	struct iuu_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 
-	if (count > 256)
-		return -ENOMEM;
-
 	spin_lock_irqsave(&priv->lock, flags);
 
+	count = min(count, 256 - priv->writelen);
+	if (count == 0)
+		goto out;
+
 	/* fill the buffer */
 	memcpy(priv->writebuf + priv->writelen, buf, count);
 	priv->writelen += count;
+out:
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return count;
@@ -1196,6 +1218,7 @@
 	.tiocmset = iuu_tiocmset,
 	.set_termios = iuu_set_termios,
 	.init_termios = iuu_init_termios,
+	.attach = iuu_attach,
 	.port_probe = iuu_port_probe,
 	.port_remove = iuu_port_remove,
 };
--- linux-4.4.0.orig/drivers/usb/serial/keyspan.c
+++ linux-4.4.0/drivers/usb/serial/keyspan.c
@@ -565,6 +565,8 @@
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
 		p_priv = usb_get_serial_port_data(port);
+		if (!p_priv)
+			continue;
 
 		if (p_priv->resend_cont) {
 			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
@@ -962,6 +964,8 @@
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
 		p_priv = usb_get_serial_port_data(port);
+		if (!p_priv)
+			continue;
 
 		if (p_priv->resend_cont) {
 			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
@@ -1249,8 +1253,8 @@
 
 	ep_desc = find_ep(serial, endpoint);
 	if (!ep_desc) {
-		/* leak the urb, something's wrong and the callers don't care */
-		return urb;
+		usb_free_urb(urb);
+		return NULL;
 	}
 	if (usb_endpoint_xfer_int(ep_desc)) {
 		ep_type_name = "INT";
@@ -2376,6 +2380,10 @@
 
 	s_priv = usb_get_serial_data(serial);
 
+	/* Make sure to unlink the URBs submitted in attach. */
+	usb_kill_urb(s_priv->instat_urb);
+	usb_kill_urb(s_priv->indat_urb);
+
 	usb_free_urb(s_priv->instat_urb);
 	usb_free_urb(s_priv->indat_urb);
 	usb_free_urb(s_priv->glocont_urb);
--- linux-4.4.0.orig/drivers/usb/serial/keyspan_pda.c
+++ linux-4.4.0/drivers/usb/serial/keyspan_pda.c
@@ -44,11 +44,12 @@
 #define DRIVER_AUTHOR "Brian Warner <warner@lothar.com>"
 #define DRIVER_DESC "USB Keyspan PDA Converter driver"
 
+#define KEYSPAN_TX_THRESHOLD	16
+
 struct keyspan_pda_private {
 	int			tx_room;
 	int			tx_throttled;
-	struct work_struct			wakeup_work;
-	struct work_struct			unthrottle_work;
+	struct work_struct	unthrottle_work;
 	struct usb_serial	*serial;
 	struct usb_serial_port	*port;
 };
@@ -101,15 +102,6 @@
 };
 #endif
 
-static void keyspan_pda_wakeup_write(struct work_struct *work)
-{
-	struct keyspan_pda_private *priv =
-		container_of(work, struct keyspan_pda_private, wakeup_work);
-	struct usb_serial_port *port = priv->port;
-
-	tty_port_tty_wakeup(&port->port);
-}
-
 static void keyspan_pda_request_unthrottle(struct work_struct *work)
 {
 	struct keyspan_pda_private *priv =
@@ -124,7 +116,7 @@
 				 7, /* request_unthrottle */
 				 USB_TYPE_VENDOR | USB_RECIP_INTERFACE
 				 | USB_DIR_OUT,
-				 16, /* value: threshold */
+				 KEYSPAN_TX_THRESHOLD,
 				 0, /* index */
 				 NULL,
 				 0,
@@ -139,9 +131,12 @@
 {
 	struct usb_serial_port *port = urb->context;
 	unsigned char *data = urb->transfer_buffer;
+	unsigned int len = urb->actual_length;
 	int retval;
 	int status = urb->status;
 	struct keyspan_pda_private *priv;
+	unsigned long flags;
+
 	priv = usb_get_serial_port_data(port);
 
 	switch (status) {
@@ -159,26 +154,37 @@
 		goto exit;
 	}
 
+	if (len < 1) {
+		dev_warn(&port->dev, "short message received\n");
+		goto exit;
+	}
+
 	/* see if the message is data or a status interrupt */
 	switch (data[0]) {
 	case 0:
 		 /* rest of message is rx data */
-		if (urb->actual_length) {
-			tty_insert_flip_string(&port->port, data + 1,
-						urb->actual_length - 1);
-			tty_flip_buffer_push(&port->port);
-		}
+		if (len < 2)
+			break;
+		tty_insert_flip_string(&port->port, data + 1, len - 1);
+		tty_flip_buffer_push(&port->port);
 		break;
 	case 1:
 		/* status interrupt */
-		dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]);
+		if (len < 2) {
+			dev_warn(&port->dev, "short interrupt message received\n");
+			break;
+		}
+		dev_dbg(&port->dev, "rx int, d1=%d\n", data[1]);
 		switch (data[1]) {
 		case 1: /* modemline change */
 			break;
 		case 2: /* tx unthrottle interrupt */
+			spin_lock_irqsave(&port->lock, flags);
 			priv->tx_throttled = 0;
+			priv->tx_room = max(priv->tx_room, KEYSPAN_TX_THRESHOLD);
+			spin_unlock_irqrestore(&port->lock, flags);
 			/* queue up a wakeup at scheduler time */
-			schedule_work(&priv->wakeup_work);
+			usb_serial_port_softint(port);
 			break;
 		default:
 			break;
@@ -364,8 +370,10 @@
 			     3, /* get pins */
 			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
 			     0, 0, data, 1, 2000);
-	if (rc >= 0)
+	if (rc == 1)
 		*value = *data;
+	else if (rc >= 0)
+		rc = -EIO;
 
 	kfree(data);
 	return rc;
@@ -436,6 +444,7 @@
 	int request_unthrottle = 0;
 	int rc = 0;
 	struct keyspan_pda_private *priv;
+	unsigned long flags;
 
 	priv = usb_get_serial_port_data(port);
 	/* guess how much room is left in the device's ring buffer, and if we
@@ -455,13 +464,13 @@
 	   the TX urb is in-flight (wait until it completes)
 	   the device is full (wait until it says there is room)
 	*/
-	spin_lock_bh(&port->lock);
+	spin_lock_irqsave(&port->lock, flags);
 	if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) {
-		spin_unlock_bh(&port->lock);
+		spin_unlock_irqrestore(&port->lock, flags);
 		return 0;
 	}
 	clear_bit(0, &port->write_urbs_free);
-	spin_unlock_bh(&port->lock);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	/* At this point the URB is in our control, nobody else can submit it
 	   again (the only sudden transition was the one from EINPROGRESS to
@@ -507,7 +516,8 @@
 			goto exit;
 		}
 	}
-	if (count > priv->tx_room) {
+
+	if (count >= priv->tx_room) {
 		/* we're about to completely fill the Tx buffer, so
 		   we'll be throttled afterwards. */
 		count = priv->tx_room;
@@ -540,7 +550,7 @@
 
 	rc = count;
 exit:
-	if (rc < 0)
+	if (rc <= 0)
 		set_bit(0, &port->write_urbs_free);
 	return rc;
 }
@@ -549,27 +559,28 @@
 static void keyspan_pda_write_bulk_callback(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
-	struct keyspan_pda_private *priv;
 
 	set_bit(0, &port->write_urbs_free);
-	priv = usb_get_serial_port_data(port);
 
 	/* queue up a wakeup at scheduler time */
-	schedule_work(&priv->wakeup_work);
+	usb_serial_port_softint(port);
 }
 
 
 static int keyspan_pda_write_room(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	struct keyspan_pda_private *priv;
-	priv = usb_get_serial_port_data(port);
-	/* used by n_tty.c for processing of tabs and such. Giving it our
-	   conservative guess is probably good enough, but needs testing by
-	   running a console through the device. */
-	return priv->tx_room;
-}
+	struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+	int room = 0;
 
+	spin_lock_irqsave(&port->lock, flags);
+	if (test_bit(0, &port->write_urbs_free) && !priv->tx_throttled)
+		room = priv->tx_room;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return room;
+}
 
 static int keyspan_pda_chars_in_buffer(struct tty_struct *tty)
 {
@@ -649,8 +660,12 @@
 }
 static void keyspan_pda_close(struct usb_serial_port *port)
 {
+	struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
+
 	usb_kill_urb(port->write_urb);
 	usb_kill_urb(port->interrupt_in_urb);
+
+	cancel_work_sync(&priv->unthrottle_work);
 }
 
 
@@ -699,6 +714,19 @@
 MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
 #endif
 
+static int keyspan_pda_attach(struct usb_serial *serial)
+{
+	unsigned char num_ports = serial->num_ports;
+
+	if (serial->num_bulk_out < num_ports ||
+			serial->num_interrupt_in < num_ports) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int keyspan_pda_port_probe(struct usb_serial_port *port)
 {
 
@@ -708,7 +736,6 @@
 	if (!priv)
 		return -ENOMEM;
 
-	INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write);
 	INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle);
 	priv->serial = port->serial;
 	priv->port = port;
@@ -776,6 +803,7 @@
 	.break_ctl =		keyspan_pda_break_ctl,
 	.tiocmget =		keyspan_pda_tiocmget,
 	.tiocmset =		keyspan_pda_tiocmset,
+	.attach =		keyspan_pda_attach,
 	.port_probe =		keyspan_pda_port_probe,
 	.port_remove =		keyspan_pda_port_remove,
 };
--- linux-4.4.0.orig/drivers/usb/serial/kl5kusb105.c
+++ linux-4.4.0/drivers/usb/serial/kl5kusb105.c
@@ -192,10 +192,11 @@
 			     status_buf, KLSI_STATUSBUF_LEN,
 			     10000
 			     );
-	if (rc < 0)
-		dev_err(&port->dev, "Reading line status failed (error = %d)\n",
-			rc);
-	else {
+	if (rc != KLSI_STATUSBUF_LEN) {
+		dev_err(&port->dev, "reading line status failed: %d\n", rc);
+		if (rc >= 0)
+			rc = -EIO;
+	} else {
 		status = get_unaligned_le16(status_buf);
 
 		dev_info(&port->serial->dev->dev, "read status %x %x\n",
@@ -292,12 +293,12 @@
 	priv->cfg.unknown2 = cfg->unknown2;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
+	kfree(cfg);
+
 	/* READ_ON and urb submission */
 	rc = usb_serial_generic_open(tty, port);
-	if (rc) {
-		retval = rc;
-		goto exit;
-	}
+	if (rc)
+		return rc;
 
 	rc = usb_control_msg(port->serial->dev,
 			     usb_sndctrlpipe(port->serial->dev, 0),
@@ -311,21 +312,36 @@
 	if (rc < 0) {
 		dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
 		retval = rc;
+		goto err_generic_close;
 	} else
 		dev_dbg(&port->dev, "%s - enabled reading\n", __func__);
 
 	rc = klsi_105_get_line_state(port, &line_state);
-	if (rc >= 0) {
-		spin_lock_irqsave(&priv->lock, flags);
-		priv->line_state = line_state;
-		spin_unlock_irqrestore(&priv->lock, flags);
-		dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
-		retval = 0;
-	} else
+	if (rc < 0) {
 		retval = rc;
+		goto err_disable_read;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->line_state = line_state;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__,
+			line_state);
+
+	return 0;
+
+err_disable_read:
+	usb_control_msg(port->serial->dev,
+			     usb_sndctrlpipe(port->serial->dev, 0),
+			     KL5KUSB105A_SIO_CONFIGURE,
+			     USB_TYPE_VENDOR | USB_DIR_OUT,
+			     KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+			     0, /* index */
+			     NULL, 0,
+			     KLSI_TIMEOUT);
+err_generic_close:
+	usb_serial_generic_close(port);
 
-exit:
-	kfree(cfg);
 	return retval;
 }
 
--- linux-4.4.0.orig/drivers/usb/serial/kobil_sct.c
+++ linux-4.4.0/drivers/usb/serial/kobil_sct.c
@@ -51,6 +51,7 @@
 
 
 /* Function prototypes */
+static int kobil_attach(struct usb_serial *serial);
 static int kobil_port_probe(struct usb_serial_port *probe);
 static int kobil_port_remove(struct usb_serial_port *probe);
 static int  kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
@@ -86,6 +87,7 @@
 	.description =		"KOBIL USB smart card terminal",
 	.id_table =		id_table,
 	.num_ports =		1,
+	.attach =		kobil_attach,
 	.port_probe =		kobil_port_probe,
 	.port_remove =		kobil_port_remove,
 	.ioctl =		kobil_ioctl,
@@ -113,6 +115,16 @@
 };
 
 
+static int kobil_attach(struct usb_serial *serial)
+{
+	if (serial->num_interrupt_out < serial->num_ports) {
+		dev_err(&serial->interface->dev, "missing interrupt-out endpoint\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int kobil_port_probe(struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
@@ -396,12 +408,20 @@
 			  transfer_buffer_length,
 			  KOBIL_TIMEOUT);
 
-	dev_dbg(&port->dev, "%s - Send get_status_line_state URB returns: %i. Statusline: %02x\n",
-		__func__, result, transfer_buffer[0]);
+	dev_dbg(&port->dev, "Send get_status_line_state URB returns: %i\n",
+			result);
+	if (result < 1) {
+		if (result >= 0)
+			result = -EIO;
+		goto out_free;
+	}
+
+	dev_dbg(&port->dev, "Statusline: %02x\n", transfer_buffer[0]);
 
 	result = 0;
 	if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0)
 		result = TIOCM_DSR;
+out_free:
 	kfree(transfer_buffer);
 	return result;
 }
--- linux-4.4.0.orig/drivers/usb/serial/mct_u232.c
+++ linux-4.4.0/drivers/usb/serial/mct_u232.c
@@ -189,7 +189,7 @@
 		return -ENOMEM;
 
 	divisor = mct_u232_calculate_baud_rate(serial, value, &speed);
-	put_unaligned_le32(cpu_to_le32(divisor), buf);
+	put_unaligned_le32(divisor, buf);
 	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 				MCT_U232_SET_BAUD_RATE_REQUEST,
 				MCT_U232_SET_REQUEST_TYPE,
@@ -322,8 +322,12 @@
 			MCT_U232_GET_REQUEST_TYPE,
 			0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
 			WDR_TIMEOUT);
-	if (rc < 0) {
+	if (rc < MCT_U232_GET_MODEM_STAT_SIZE) {
 		dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc);
+
+		if (rc >= 0)
+			rc = -EIO;
+
 		*msr = 0;
 	} else {
 		*msr = buf[0];
@@ -376,14 +380,21 @@
 
 static int mct_u232_port_probe(struct usb_serial_port *port)
 {
+	struct usb_serial *serial = port->serial;
 	struct mct_u232_private *priv;
 
+	/* check first to simplify error handling */
+	if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) {
+		dev_err(&port->dev, "expected endpoint missing\n");
+		return -ENODEV;
+	}
+
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
 	/* Use second interrupt-in endpoint for reading. */
-	priv->read_urb = port->serial->port[1]->interrupt_in_urb;
+	priv->read_urb = serial->port[1]->interrupt_in_urb;
 	priv->read_urb->context = port;
 
 	spin_lock_init(&priv->lock);
--- linux-4.4.0.orig/drivers/usb/serial/metro-usb.c
+++ linux-4.4.0/drivers/usb/serial/metro-usb.c
@@ -45,6 +45,7 @@
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },
 	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x0c2e, 0x0730, 0xff) },	/* MS7820 */
 	{ }, /* Terminating entry. */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
--- linux-4.4.0.orig/drivers/usb/serial/mos7720.c
+++ linux-4.4.0/drivers/usb/serial/mos7720.c
@@ -65,8 +65,6 @@
 	struct urb		*write_urb_pool[NUM_URBS];
 };
 
-static struct usb_serial_driver moschip7720_2port_driver;
-
 #define USB_VENDOR_ID_MOSCHIP		0x9710
 #define MOSCHIP_DEVICE_ID_7720		0x7720
 #define MOSCHIP_DEVICE_ID_7715		0x7715
@@ -236,11 +234,16 @@
 
 	status = usb_control_msg(usbdev, pipe, request, requesttype, value,
 				     index, buf, 1, MOS_WDR_TIMEOUT);
-	if (status == 1)
+	if (status == 1) {
 		*data = *buf;
-	else if (status < 0)
+	} else {
 		dev_err(&usbdev->dev,
 			"mos7720: usb_control_msg() failed: %d\n", status);
+		if (status >= 0)
+			status = -EIO;
+		*data = 0;
+	}
+
 	kfree(buf);
 
 	return status;
@@ -365,8 +368,6 @@
 	if (!urbtrack)
 		return -ENOMEM;
 
-	kref_get(&mos_parport->ref_count);
-	urbtrack->mos_parport = mos_parport;
 	urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urbtrack->urb) {
 		kfree(urbtrack);
@@ -387,6 +388,8 @@
 			     usb_sndctrlpipe(usbdev, 0),
 			     (unsigned char *)urbtrack->setup,
 			     NULL, 0, async_complete, urbtrack);
+	kref_get(&mos_parport->ref_count);
+	urbtrack->mos_parport = mos_parport;
 	kref_init(&urbtrack->ref_count);
 	INIT_LIST_HEAD(&urbtrack->urblist_entry);
 
@@ -637,6 +640,8 @@
 		spin_unlock(&release_lock);
 		return;
 	}
+	mos_parport->shadowDCR = s->u.pc.ctr;
+	mos_parport->shadowECR = s->u.pc.ecr;
 	write_parport_reg_nonblock(mos_parport, MOS7720_DCR,
 				   mos_parport->shadowDCR);
 	write_parport_reg_nonblock(mos_parport, MOS7720_ECR,
@@ -970,25 +975,6 @@
 		tty_port_tty_wakeup(&mos7720_port->port->port);
 }
 
-/*
- * mos77xx_probe
- *	this function installs the appropriate read interrupt endpoint callback
- *	depending on whether the device is a 7720 or 7715, thus avoiding costly
- *	run-time checks in the high-frequency callback routine itself.
- */
-static int mos77xx_probe(struct usb_serial *serial,
-			 const struct usb_device_id *id)
-{
-	if (id->idProduct == MOSCHIP_DEVICE_ID_7715)
-		moschip7720_2port_driver.read_int_callback =
-			mos7715_interrupt_callback;
-	else
-		moschip7720_2port_driver.read_int_callback =
-			mos7720_interrupt_callback;
-
-	return 0;
-}
-
 static int mos77xx_calc_num_ports(struct usb_serial *serial)
 {
 	u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
@@ -1252,9 +1238,11 @@
 
 	if (urb->transfer_buffer == NULL) {
 		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
-					       GFP_KERNEL);
-		if (!urb->transfer_buffer)
+					       GFP_ATOMIC);
+		if (!urb->transfer_buffer) {
+			bytes_sent = -ENOMEM;
 			goto exit;
+		}
 	}
 	transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
 
@@ -1920,6 +1908,11 @@
 	u16 product;
 	int ret_val;
 
+	if (serial->num_bulk_in < 2 || serial->num_bulk_out < 2) {
+		dev_err(&serial->interface->dev, "missing bulk endpoints\n");
+		return -ENODEV;
+	}
+
 	product = le16_to_cpu(serial->dev->descriptor.idProduct);
 	dev = serial->dev;
 
@@ -1944,18 +1937,13 @@
 			tmp->interrupt_in_endpointAddress;
 		serial->port[1]->interrupt_in_urb = NULL;
 		serial->port[1]->interrupt_in_buffer = NULL;
-	}
 
-	/* setting configuration feature to one */
-	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
+		if (serial->port[0]->interrupt_in_urb) {
+			struct urb *urb = serial->port[0]->interrupt_in_urb;
 
-	/* start the interrupt urb */
-	ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
-	if (ret_val)
-		dev_err(&dev->dev,
-			"%s - Error %d submitting control urb\n",
-			__func__, ret_val);
+			urb->complete = mos7715_interrupt_callback;
+		}
+	}
 
 #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
 	if (product == MOSCHIP_DEVICE_ID_7715) {
@@ -1964,6 +1952,13 @@
 			return ret_val;
 	}
 #endif
+	/* start the interrupt urb */
+	ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
+	if (ret_val) {
+		dev_err(&dev->dev, "failed to submit interrupt urb: %d\n",
+			ret_val);
+	}
+
 	/* LSR For Port 1 */
 	read_mos_reg(serial, 0, MOS7720_LSR, &data);
 	dev_dbg(&dev->dev, "LSR:%x\n", data);
@@ -1973,6 +1968,8 @@
 
 static void mos7720_release(struct usb_serial *serial)
 {
+	usb_kill_urb(serial->port[0]->interrupt_in_urb);
+
 #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
 	/* close the parallel port */
 
@@ -2007,6 +2004,7 @@
 				    urblist_entry)
 			usb_unlink_urb(urbtrack->urb);
 		spin_unlock_irqrestore(&mos_parport->listlock, flags);
+		parport_del_port(mos_parport->pp);
 
 		kref_put(&mos_parport->ref_count, destroy_mos_parport);
 	}
@@ -2055,7 +2053,6 @@
 	.close			= mos7720_close,
 	.throttle		= mos7720_throttle,
 	.unthrottle		= mos7720_unthrottle,
-	.probe			= mos77xx_probe,
 	.attach			= mos7720_startup,
 	.release		= mos7720_release,
 	.port_probe		= mos7720_port_probe,
@@ -2069,7 +2066,7 @@
 	.chars_in_buffer	= mos7720_chars_in_buffer,
 	.break_ctl		= mos7720_break,
 	.read_bulk_callback	= mos7720_bulk_in_callback,
-	.read_int_callback	= NULL  /* dynamically assigned in probe() */
+	.read_int_callback	= mos7720_interrupt_callback,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
--- linux-4.4.0.orig/drivers/usb/serial/mos7840.c
+++ linux-4.4.0/drivers/usb/serial/mos7840.c
@@ -131,11 +131,15 @@
 /* This driver also supports
  * ATEN UC2324 device using Moschip MCS7840
  * ATEN UC2322 device using Moschip MCS7820
+ * MOXA UPort 2210 device using Moschip MCS7820
  */
 #define USB_VENDOR_ID_ATENINTL		0x0557
 #define ATENINTL_DEVICE_ID_UC2324	0x2011
 #define ATENINTL_DEVICE_ID_UC2322	0x7820
 
+#define USB_VENDOR_ID_MOXA		0x110a
+#define MOXA_DEVICE_ID_2210		0x2210
+
 /* Interrupt Routine Defines    */
 
 #define SERIAL_IIR_RLS      0x06
@@ -206,6 +210,7 @@
 	{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
 	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
 	{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
+	{USB_DEVICE(USB_VENDOR_ID_MOXA, MOXA_DEVICE_ID_2210)},
 	{}			/* terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -285,9 +290,15 @@
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
 			      MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH,
 			      MOS_WDR_TIMEOUT);
+	if (ret < VENDOR_READ_LENGTH) {
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
+
 	*val = buf[0];
 	dev_dbg(&port->dev, "%s offset is %x, return val %x\n", __func__, reg, *val);
-
+out:
 	kfree(buf);
 	return ret;
 }
@@ -353,8 +364,13 @@
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
 			      MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH,
 			      MOS_WDR_TIMEOUT);
+	if (ret < VENDOR_READ_LENGTH) {
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
 	*val = buf[0];
-
+out:
 	kfree(buf);
 	return ret;
 }
@@ -471,6 +487,9 @@
 	}
 
 	dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
+	if (urb->actual_length < 1)
+		goto out;
+
 	dev_dbg(dev, "%s mos7840_port->MsrLsr is %d port %d\n", __func__,
 		mos7840_port->MsrLsr, mos7840_port->port_num);
 	data = urb->transfer_buffer;
@@ -1024,6 +1043,7 @@
 	 * (can't set it up in mos7840_startup as the structures *
 	 * were not set up at that time.)                        */
 	if (port0->open_ports == 1) {
+		/* FIXME: Buffer never NULL, so URB is not submitted. */
 		if (serial->port[0]->interrupt_in_buffer == NULL) {
 			/* set up interrupt urb */
 			usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
@@ -1340,10 +1360,12 @@
 	}
 
 	if (urb->transfer_buffer == NULL) {
-		urb->transfer_buffer =
-		    kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
-		if (!urb->transfer_buffer)
+		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
+					       GFP_ATOMIC);
+		if (!urb->transfer_buffer) {
+			bytes_sent = -ENOMEM;
 			goto exit;
+		}
 	}
 	transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
 
@@ -1489,10 +1511,10 @@
 		return -ENODEV;
 
 	status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
-	if (status != 1)
+	if (status < 0)
 		return -EIO;
 	status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
-	if (status != 1)
+	if (status < 0)
 		return -EIO;
 	result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
 	    | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
@@ -2074,6 +2096,7 @@
 				const struct usb_device_id *id)
 {
 	u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+	u16 vid = le16_to_cpu(serial->dev->descriptor.idVendor);
 	u8 *buf;
 	int device_type;
 
@@ -2083,6 +2106,11 @@
 		goto out;
 	}
 
+	if (vid == USB_VENDOR_ID_MOXA && product == MOXA_DEVICE_ID_2210) {
+		device_type = MOSCHIP_DEVICE_ID_7820;
+		goto out;
+	}
+
 	buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
@@ -2116,6 +2144,18 @@
 	return mos7840_num_ports;
 }
 
+static int mos7840_attach(struct usb_serial *serial)
+{
+	if (serial->num_bulk_in < serial->num_ports ||
+			serial->num_bulk_out < serial->num_ports ||
+			serial->num_interrupt_in < 1) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int mos7840_port_probe(struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
@@ -2323,11 +2363,6 @@
 			goto error;
 		} else
 			dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status);
-
-		/* setting configuration feature to one */
-		usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				0x03, 0x00, 0x01, 0x00, NULL, 0x00,
-				MOS_WDR_TIMEOUT);
 	}
 	return 0;
 error:
@@ -2367,6 +2402,49 @@
 	return 0;
 }
 
+static int mos7840_suspend(struct usb_serial *serial, pm_message_t message)
+{
+	struct moschip_port *mos7840_port;
+	struct usb_serial_port *port;
+	int i;
+
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = serial->port[i];
+		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+			continue;
+
+		mos7840_port = usb_get_serial_port_data(port);
+
+		usb_kill_urb(mos7840_port->read_urb);
+		mos7840_port->read_urb_busy = false;
+	}
+
+	return 0;
+}
+
+static int mos7840_resume(struct usb_serial *serial)
+{
+	struct moschip_port *mos7840_port;
+	struct usb_serial_port *port;
+	int res;
+	int i;
+
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = serial->port[i];
+		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+			continue;
+
+		mos7840_port = usb_get_serial_port_data(port);
+
+		mos7840_port->read_urb_busy = true;
+		res = usb_submit_urb(mos7840_port->read_urb, GFP_NOIO);
+		if (res)
+			mos7840_port->read_urb_busy = false;
+	}
+
+	return 0;
+}
+
 static struct usb_serial_driver moschip7840_4port_device = {
 	.driver = {
 		   .owner = THIS_MODULE,
@@ -2391,10 +2469,13 @@
 	.tiocmset = mos7840_tiocmset,
 	.tiocmiwait = usb_serial_generic_tiocmiwait,
 	.get_icount = usb_serial_generic_get_icount,
+	.attach = mos7840_attach,
 	.port_probe = mos7840_port_probe,
 	.port_remove = mos7840_port_remove,
 	.read_bulk_callback = mos7840_bulk_in_callback,
 	.read_int_callback = mos7840_interrupt_callback,
+	.suspend = mos7840_suspend,
+	.resume = mos7840_resume,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
--- linux-4.4.0.orig/drivers/usb/serial/mxuport.c
+++ linux-4.4.0/drivers/usb/serial/mxuport.c
@@ -1259,6 +1259,15 @@
 	return 0;
 }
 
+static void mxuport_release(struct usb_serial *serial)
+{
+	struct usb_serial_port *port0 = serial->port[0];
+	struct usb_serial_port *port1 = serial->port[1];
+
+	usb_serial_generic_close(port1);
+	usb_serial_generic_close(port0);
+}
+
 static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct mxuport_port *mxport = usb_get_serial_port_data(port);
@@ -1361,6 +1370,7 @@
 	.probe			= mxuport_probe,
 	.port_probe		= mxuport_port_probe,
 	.attach			= mxuport_attach,
+	.release		= mxuport_release,
 	.calc_num_ports		= mxuport_calc_num_ports,
 	.open			= mxuport_open,
 	.close			= mxuport_close,
--- linux-4.4.0.orig/drivers/usb/serial/omninet.c
+++ linux-4.4.0/drivers/usb/serial/omninet.c
@@ -38,6 +38,7 @@
 				const unsigned char *buf, int count);
 static int  omninet_write_room(struct tty_struct *tty);
 static void omninet_disconnect(struct usb_serial *serial);
+static int omninet_attach(struct usb_serial *serial);
 static int omninet_port_probe(struct usb_serial_port *port);
 static int omninet_port_remove(struct usb_serial_port *port);
 
@@ -56,6 +57,7 @@
 	.description =		"ZyXEL - omni.net lcd plus usb",
 	.id_table =		id_table,
 	.num_ports =		1,
+	.attach =		omninet_attach,
 	.port_probe =		omninet_port_probe,
 	.port_remove =		omninet_port_remove,
 	.open =			omninet_open,
@@ -104,6 +106,17 @@
 	__u8	od_outseq;	/* Sequence number for bulk_out URBs */
 };
 
+static int omninet_attach(struct usb_serial *serial)
+{
+	/* The second bulk-out endpoint is used for writing. */
+	if (serial->num_bulk_out < 2) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int omninet_port_probe(struct usb_serial_port *port)
 {
 	struct omninet_data *od;
@@ -129,12 +142,6 @@
 
 static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	struct usb_serial	*serial = port->serial;
-	struct usb_serial_port	*wport;
-
-	wport = serial->port[1];
-	tty_port_tty_set(&wport->port, tty);
-
 	return usb_serial_generic_open(tty, port);
 }
 
--- linux-4.4.0.orig/drivers/usb/serial/opticon.c
+++ linux-4.4.0/drivers/usb/serial/opticon.c
@@ -116,7 +116,7 @@
 	retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 				requesttype,
 				USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
-				0, 0, buffer, 1, 0);
+				0, 0, buffer, 1, USB_CTRL_SET_TIMEOUT);
 	kfree(buffer);
 
 	if (retval < 0)
@@ -142,7 +142,7 @@
 	usb_clear_halt(port->serial->dev, port->read_urb->pipe);
 
 	res = usb_serial_generic_open(tty, port);
-	if (!res)
+	if (res)
 		return res;
 
 	/* Request CTS line state, sometimes during opening the current
--- linux-4.4.0.orig/drivers/usb/serial/option.c
+++ linux-4.4.0/drivers/usb/serial/option.c
@@ -199,6 +199,9 @@
 #define DELL_PRODUCT_5800_V2_MINICARD_VZW	0x8196  /* Novatel E362 */
 #define DELL_PRODUCT_5804_MINICARD_ATT		0x819b  /* Novatel E371 */
 
+#define DELL_PRODUCT_5821E			0x81d7
+#define DELL_PRODUCT_5821E_ESIM			0x81e0
+
 #define KYOCERA_VENDOR_ID			0x0c88
 #define KYOCERA_PRODUCT_KPC650			0x17da
 #define KYOCERA_PRODUCT_KPC680			0x180a
@@ -233,6 +236,21 @@
 #define BANDRICH_PRODUCT_1012			0x1012
 
 #define QUALCOMM_VENDOR_ID			0x05C6
+/* These Quectel products use Qualcomm's vendor ID */
+#define QUECTEL_PRODUCT_UC20			0x9003
+#define QUECTEL_PRODUCT_UC15			0x9090
+/* These u-blox products use Qualcomm's vendor ID */
+#define UBLOX_PRODUCT_R410M			0x90b2
+/* These Yuga products use Qualcomm's vendor ID */
+#define YUGA_PRODUCT_CLM920_NC5			0x9625
+
+#define QUECTEL_VENDOR_ID			0x2c7c
+/* These Quectel products use Quectel's vendor ID */
+#define QUECTEL_PRODUCT_EC21			0x0121
+#define QUECTEL_PRODUCT_EC25			0x0125
+#define QUECTEL_PRODUCT_EG95			0x0195
+#define QUECTEL_PRODUCT_BG96			0x0296
+#define QUECTEL_PRODUCT_EP06			0x0306
 
 #define CMOTECH_VENDOR_ID			0x16d8
 #define CMOTECH_PRODUCT_6001			0x6001
@@ -268,8 +286,22 @@
 #define TELIT_PRODUCT_CC864_SINGLE		0x1006
 #define TELIT_PRODUCT_DE910_DUAL		0x1010
 #define TELIT_PRODUCT_UE910_V2			0x1012
+#define TELIT_PRODUCT_LE922_USBCFG1		0x1040
+#define TELIT_PRODUCT_LE922_USBCFG2		0x1041
+#define TELIT_PRODUCT_LE922_USBCFG0		0x1042
+#define TELIT_PRODUCT_LE922_USBCFG3		0x1043
+#define TELIT_PRODUCT_LE922_USBCFG5		0x1045
+#define TELIT_PRODUCT_ME910			0x1100
+#define TELIT_PRODUCT_ME910_DUAL_MODEM		0x1101
 #define TELIT_PRODUCT_LE920			0x1200
 #define TELIT_PRODUCT_LE910			0x1201
+#define TELIT_PRODUCT_LE910_USBCFG4		0x1206
+#define TELIT_PRODUCT_LE920A4_1207		0x1207
+#define TELIT_PRODUCT_LE920A4_1208		0x1208
+#define TELIT_PRODUCT_LE920A4_1211		0x1211
+#define TELIT_PRODUCT_LE920A4_1212		0x1212
+#define TELIT_PRODUCT_LE920A4_1213		0x1213
+#define TELIT_PRODUCT_LE920A4_1214		0x1214
 
 /* ZTE PRODUCTS */
 #define ZTE_VENDOR_ID				0x19d2
@@ -313,6 +345,7 @@
 #define TOSHIBA_PRODUCT_G450			0x0d45
 
 #define ALINK_VENDOR_ID				0x1e0e
+#define SIMCOM_PRODUCT_SIM7100E			0x9001 /* Yes, ALINK_VENDOR_ID */
 #define ALINK_PRODUCT_PH300			0x9100
 #define ALINK_PRODUCT_3GU			0x9200
 
@@ -357,6 +390,9 @@
 #define FOUR_G_SYSTEMS_PRODUCT_W14		0x9603
 #define FOUR_G_SYSTEMS_PRODUCT_W100		0x9b01
 
+/* Fujisoft products */
+#define FUJISOFT_PRODUCT_FS040U			0x9b02
+
 /* iBall 3.5G connect wireless modem */
 #define IBALL_3_5G_CONNECT			0x9605
 
@@ -371,18 +407,26 @@
 #define HAIER_PRODUCT_CE81B			0x10f8
 #define HAIER_PRODUCT_CE100			0x2009
 
-/* Cinterion (formerly Siemens) products */
-#define SIEMENS_VENDOR_ID				0x0681
-#define CINTERION_VENDOR_ID				0x1e2d
+/* Gemalto's Cinterion products (formerly Siemens) */
+#define SIEMENS_VENDOR_ID			0x0681
+#define CINTERION_VENDOR_ID			0x1e2d
+#define CINTERION_PRODUCT_HC25_MDMNET		0x0040
 #define CINTERION_PRODUCT_HC25_MDM		0x0047
-#define CINTERION_PRODUCT_HC25_MDMNET	0x0040
+#define CINTERION_PRODUCT_HC28_MDMNET		0x004A /* same for HC28J */
 #define CINTERION_PRODUCT_HC28_MDM		0x004C
-#define CINTERION_PRODUCT_HC28_MDMNET	0x004A /* same for HC28J */
 #define CINTERION_PRODUCT_EU3_E			0x0051
 #define CINTERION_PRODUCT_EU3_P			0x0052
 #define CINTERION_PRODUCT_PH8			0x0053
 #define CINTERION_PRODUCT_AHXX			0x0055
 #define CINTERION_PRODUCT_PLXX			0x0060
+#define CINTERION_PRODUCT_EXS82			0x006c
+#define CINTERION_PRODUCT_PH8_2RMNET		0x0082
+#define CINTERION_PRODUCT_PH8_AUDIO		0x0083
+#define CINTERION_PRODUCT_AHXX_2RMNET		0x0084
+#define CINTERION_PRODUCT_AHXX_AUDIO		0x0085
+#define CINTERION_PRODUCT_CLS8			0x00b0
+#define CINTERION_PRODUCT_MV31_MBIM		0x00b3
+#define CINTERION_PRODUCT_MV31_RMNET		0x00b7
 
 /* Olivetti products */
 #define OLIVETTI_VENDOR_ID			0x0b3c
@@ -488,6 +532,7 @@
 /* Cellient products */
 #define CELLIENT_VENDOR_ID			0x2692
 #define CELLIENT_PRODUCT_MEN200			0x9005
+#define CELLIENT_PRODUCT_MPL200			0x9025
 
 /* Hyundai Petatel Inc. products */
 #define PETATEL_VENDOR_ID			0x1ff4
@@ -496,6 +541,7 @@
 
 /* TP-LINK Incorporated products */
 #define TPLINK_VENDOR_ID			0x2357
+#define TPLINK_PRODUCT_LTE			0x000D
 #define TPLINK_PRODUCT_MA180			0x0201
 
 /* Changhong products */
@@ -510,110 +556,27 @@
 #define VIATELECOM_VENDOR_ID			0x15eb
 #define VIATELECOM_PRODUCT_CDS7			0x0001
 
-struct option_blacklist_info {
-	/* bitmask of interface numbers blacklisted for send_setup */
-	const unsigned long sendsetup;
-	/* bitmask of interface numbers that are reserved */
-	const unsigned long reserved;
-};
-
-static const struct option_blacklist_info four_g_w14_blacklist = {
-	.sendsetup = BIT(0) | BIT(1),
-};
-
-static const struct option_blacklist_info four_g_w100_blacklist = {
-	.sendsetup = BIT(1) | BIT(2),
-	.reserved = BIT(3),
-};
-
-static const struct option_blacklist_info alcatel_x200_blacklist = {
-	.sendsetup = BIT(0) | BIT(1),
-	.reserved = BIT(4),
-};
-
-static const struct option_blacklist_info zte_0037_blacklist = {
-	.sendsetup = BIT(0) | BIT(1),
-};
-
-static const struct option_blacklist_info zte_k3765_z_blacklist = {
-	.sendsetup = BIT(0) | BIT(1) | BIT(2),
-	.reserved = BIT(4),
-};
-
-static const struct option_blacklist_info zte_ad3812_z_blacklist = {
-	.sendsetup = BIT(0) | BIT(1) | BIT(2),
-};
-
-static const struct option_blacklist_info zte_mc2718_z_blacklist = {
-	.sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4),
-};
-
-static const struct option_blacklist_info zte_mc2716_z_blacklist = {
-	.sendsetup = BIT(1) | BIT(2) | BIT(3),
-};
-
-static const struct option_blacklist_info zte_me3620_mbim_blacklist = {
-	.reserved = BIT(2) | BIT(3) | BIT(4),
-};
-
-static const struct option_blacklist_info zte_me3620_xl_blacklist = {
-	.reserved = BIT(3) | BIT(4) | BIT(5),
-};
-
-static const struct option_blacklist_info zte_zm8620_x_blacklist = {
-	.reserved = BIT(3) | BIT(4) | BIT(5),
-};
-
-static const struct option_blacklist_info huawei_cdc12_blacklist = {
-	.reserved = BIT(1) | BIT(2),
-};
-
-static const struct option_blacklist_info net_intf0_blacklist = {
-	.reserved = BIT(0),
-};
-
-static const struct option_blacklist_info net_intf1_blacklist = {
-	.reserved = BIT(1),
-};
-
-static const struct option_blacklist_info net_intf2_blacklist = {
-	.reserved = BIT(2),
-};
-
-static const struct option_blacklist_info net_intf3_blacklist = {
-	.reserved = BIT(3),
-};
+/* WeTelecom products */
+#define WETELECOM_VENDOR_ID			0x22de
+#define WETELECOM_PRODUCT_WMD200		0x6801
+#define WETELECOM_PRODUCT_6802			0x6802
+#define WETELECOM_PRODUCT_WMD300		0x6803
 
-static const struct option_blacklist_info net_intf4_blacklist = {
-	.reserved = BIT(4),
-};
 
-static const struct option_blacklist_info net_intf5_blacklist = {
-	.reserved = BIT(5),
-};
+/* Device flags */
 
-static const struct option_blacklist_info net_intf6_blacklist = {
-	.reserved = BIT(6),
-};
+/* Highest interface number which can be used with NCTRL() and RSVD() */
+#define FLAG_IFNUM_MAX	7
 
-static const struct option_blacklist_info zte_mf626_blacklist = {
-	.sendsetup = BIT(0) | BIT(1),
-	.reserved = BIT(4),
-};
+/* Interface does not support modem-control requests */
+#define NCTRL(ifnum)	((BIT(ifnum) & 0xff) << 8)
 
-static const struct option_blacklist_info zte_1255_blacklist = {
-	.reserved = BIT(3) | BIT(4),
-};
+/* Interface is reserved */
+#define RSVD(ifnum)	((BIT(ifnum) & 0xff) << 0)
 
-static const struct option_blacklist_info telit_le910_blacklist = {
-	.sendsetup = BIT(0),
-	.reserved = BIT(1) | BIT(2),
-};
+/* Device needs ZLP */
+#define ZLP		BIT(17)
 
-static const struct option_blacklist_info telit_le920_blacklist = {
-	.sendsetup = BIT(0),
-	.reserved = BIT(1) | BIT(5),
-};
 
 static const struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -647,26 +610,26 @@
 	{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) },
 	{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) },
 	{ USB_DEVICE(QUANTA_VENDOR_ID, 0xea42),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t) &net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+	  .driver_info = RSVD(1) | RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+	  .driver_info = RSVD(1) | RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14ac, 0xff, 0xff, 0xff),	/* Huawei E1820 */
-		.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+	  .driver_info = RSVD(1) | RSVD(2) },
 	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) },
 	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x01) },
 	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x02) },
@@ -1017,6 +980,11 @@
 	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) },
 	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) },
 
+	/* Motorola devices */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x2a70, 0xff, 0xff, 0xff) },	/* mdm6600 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x2e0a, 0xff, 0xff, 0xff) },	/* mdm9600 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x4281, 0x0a, 0x00, 0xfc) },	/* mdm ram dl */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x900e, 0xff, 0xff, 0xff) },	/* mdm qc dl */
 
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
@@ -1085,6 +1053,10 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E),
+	  .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+	{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E_ESIM),
+	  .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },	/* ADU-E100, ADU-310 */
 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
@@ -1110,63 +1082,151 @@
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, 0x6001, 0xff, 0xff, 0xff), /* 4G LTE usb-modem U901 */
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
-	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */
+	  .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) },
+	/* Quectel products using Qualcomm vendor ID */
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
+	  .driver_info = RSVD(4) },
+	/* Yuga products use Qualcomm vendor ID */
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, YUGA_PRODUCT_CLM920_NC5),
+	  .driver_info = RSVD(1) | RSVD(4) },
+	/* u-blox products using Qualcomm vendor ID */
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, UBLOX_PRODUCT_R410M),
+	  .driver_info = RSVD(1) | RSVD(3) },
+	/* Quectel products using Quectel vendor ID */
+	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21),
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25),
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95),
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06),
+	  .driver_info = RSVD(4) | RSVD(5) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6004) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6005) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_628A) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHE_628S),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_301),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628S) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_680) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_685A) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720S),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7002),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629K),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7004),
-	  .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7005) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_629),
-	  .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629S),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720I),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7212),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7213),
-	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+	  .driver_info = RSVD(0) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7251),
-	  .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7252),
-	  .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7253),
-	  .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1031, 0xff),	/* Telit LE910C1-EUX */
+	 .driver_info = NCTRL(0) | RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff),	/* Telit LE910C1-EUX (ECM) */
+	 .driver_info = NCTRL(0) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0),
+	  .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG1),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG2),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
+	  .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1050, 0xff),	/* Telit FN980 (rmnet) */
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1051, 0xff),	/* Telit FN980 (MBIM) */
+	  .driver_info = NCTRL(0) | RSVD(1) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1052, 0xff),	/* Telit FN980 (RNDIS) */
+	  .driver_info = NCTRL(2) | RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1053, 0xff),	/* Telit FN980 (ECM) */
+	  .driver_info = NCTRL(0) | RSVD(1) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1054, 0xff),	/* Telit FT980-KS */
+	  .driver_info = NCTRL(2) | RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1055, 0xff),	/* Telit FN980 (PCIe) */
+	  .driver_info = NCTRL(0) | RSVD(1) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
+	  .driver_info = NCTRL(0) | RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff),	/* Telit ME910 (ECM) */
+	  .driver_info = NCTRL(0) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110a, 0xff),	/* Telit ME910G1 */
+	  .driver_info = NCTRL(0) | RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110b, 0xff),	/* Telit ME910G1 (ECM) */
+	  .driver_info = NCTRL(0) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
-		.driver_info = (kernel_ulong_t)&telit_le910_blacklist },
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1203, 0xff),	/* Telit LE910Cx (RNDIS) */
+	  .driver_info = NCTRL(2) | RSVD(3) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
-		.driver_info = (kernel_ulong_t)&telit_le920_blacklist },
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(5) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1207) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1208),
+	  .driver_info = NCTRL(0) | RSVD(1) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1211),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1212),
+	  .driver_info = NCTRL(0) | RSVD(1) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1213, 0xff) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1214),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1230, 0xff),	/* Telit LE910Cx (rmnet) */
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1231, 0xff),	/* Telit LE910Cx (RNDIS) */
+	  .driver_info = NCTRL(2) | RSVD(3) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, 0x1260),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, 0x1261),
+	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, 0x1900),				/* Telit LN940 (QMI) */
+	  .driver_info = NCTRL(0) | RSVD(1) },
+	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1901, 0xff),	/* Telit LN940 (MBIM) */
+	  .driver_info = NCTRL(0) },
+	{ USB_DEVICE(TELIT_VENDOR_ID, 0x9010),				/* Telit SBL FN980 flashing device */
+	  .driver_info = NCTRL(0) | ZLP },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) },
@@ -1182,58 +1242,58 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff,
-	  0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mf626_blacklist },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, 0xff, 0xff),
+	  .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&zte_0037_blacklist },
+	  .driver_info = NCTRL(0) | NCTRL(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0044, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0050, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0056, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0065, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) },
@@ -1258,26 +1318,26 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0096, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0097, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0122, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+	  .driver_info = RSVD(6) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0135, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0136, 0xff, 0xff, 0xff) },
@@ -1293,50 +1353,52 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0189, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0191, 0xff, 0xff, 0xff), /* ZTE EuFi890 */
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0196, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0197, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0199, 0xff, 0xff, 0xff), /* ZTE MF820S */
-	  .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0200, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0201, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */
-	  .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff), /* ONDA MT8205 */
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0330, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0395, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0412, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G */
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0601, 0xff) },	/* GosunCn ZTE WeLink ME3630 (RNDIS mode) */
+	{ USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0602, 0xff) },	/* GosunCn ZTE WeLink ME3630 (MBIM mode) */
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1021, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) },
@@ -1453,23 +1515,23 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1170, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1244, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1246, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1248, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1249, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1250, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1251, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1253, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&zte_1255_blacklist },
+	  .driver_info = RSVD(3) | RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1257, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1258, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1259, 0xff, 0xff, 0xff) },
@@ -1484,12 +1546,13 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff),
-	  .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1274, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1275, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE(ZTE_VENDOR_ID, 0x1275),	/* ZTE P685M */
+	  .driver_info = RSVD(3) | RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1276, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1277, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1278, 0xff, 0xff, 0xff) },
@@ -1520,17 +1583,19 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1303, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1333, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1424, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1425, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff),  /* ZTE MF91 */
-		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff),  /* Telewell TW-LTE 4G v2 */
-		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
+	{ USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x1476, 0xff) },	/* GosunCn ZTE WeLink ME3630 (ECM/NCM mode) */
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1481, 0xff, 0x00, 0x00) }, /* ZTE MF871A */
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
@@ -1548,8 +1613,8 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1596, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1598, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1600, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,
-	  0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff),
+	  .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
 
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */
@@ -1560,21 +1625,93 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+	  .driver_info = RSVD(1) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff),
-		.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) },
+	  .driver_info = RSVD(3) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff42, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff43, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff44, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff45, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff46, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff47, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff48, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff49, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4a, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4b, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4c, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4d, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4e, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4f, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff50, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff51, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff52, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff53, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff54, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff55, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff56, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff57, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff58, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff59, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5a, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5b, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5c, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5d, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5e, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5f, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff60, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff61, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff62, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff63, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff64, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff65, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff66, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff67, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff68, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff69, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6a, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6b, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6c, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6d, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6e, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6f, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff70, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff71, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff72, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff73, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff74, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff75, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff76, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff77, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff78, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff79, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7a, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7b, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7c, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7d, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7e, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7f, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff80, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff81, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff82, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff83, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff84, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff85, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff86, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff87, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff88, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff89, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8a, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) },
@@ -1585,6 +1722,61 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff9f, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa0, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa1, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa2, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa3, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa4, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa5, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa6, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa7, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa8, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa9, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffaa, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffab, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffac, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffae, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffaf, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb0, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb1, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb2, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb3, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb4, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb5, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb6, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb7, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb8, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb9, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffba, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbb, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbc, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbd, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbe, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbf, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc0, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc1, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc2, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc3, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc4, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc5, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc6, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc7, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc8, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc9, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffca, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcb, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcc, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcd, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffce, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcf, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd0, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd1, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd2, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd3, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd4, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd5, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffec, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffee, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xfff6, 0xff, 0xff, 0xff) },
@@ -1598,19 +1790,19 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff),
-	 .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist },
+	 .driver_info = NCTRL(1) | NCTRL(2) | NCTRL(3) | NCTRL(4) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff),
-	 .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
+	 .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
-	 .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
+	 .driver_info = NCTRL(1) | NCTRL(2) | NCTRL(3) },
 	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_L),
-	 .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist },
+	 .driver_info = RSVD(3) | RSVD(4) | RSVD(5) },
 	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_MBIM),
-	 .driver_info = (kernel_ulong_t)&zte_me3620_mbim_blacklist },
+	 .driver_info = RSVD(2) | RSVD(3) | RSVD(4) },
 	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_X),
-	 .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist },
+	 .driver_info = RSVD(3) | RSVD(4) | RSVD(5) },
 	{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ZM8620_X),
-	 .driver_info = (kernel_ulong_t)&zte_zm8620_x_blacklist },
+	 .driver_info = RSVD(3) | RSVD(4) | RSVD(5) },
 	{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) },
 	{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) },
 	{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) },
@@ -1629,30 +1821,40 @@
 	{ USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
 	{ USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E),
+	  .driver_info = RSVD(5) | RSVD(6) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) },	/* Simcom SIM7500/SIM7600 MBIM mode */
+	{ USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff),	/* Simcom SIM7500/SIM7600 RNDIS mode */
+	  .driver_info = RSVD(7) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9205, 0xff) },	/* Simcom SIM7070/SIM7080/SIM7090 AT+ECM mode */
+	{ USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9206, 0xff) },	/* Simcom SIM7070/SIM7080/SIM7090 AT-only mode */
 	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
-	  .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
-	},
+	  .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) },
 	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D),
-	  .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+	  .driver_info = RSVD(6) },
 	{ USB_DEVICE(ALCATEL_VENDOR_ID, 0x0052),
-	  .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+	  .driver_info = RSVD(6) },
 	{ USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b6),
-	  .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+	  .driver_info = RSVD(3) },
 	{ USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b7),
-	  .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+	  .driver_info = RSVD(5) },
 	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L800MA),
-	  .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+	  .driver_info = RSVD(2) },
 	{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
 	{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
 	{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
-  	  .driver_info = (kernel_ulong_t)&four_g_w14_blacklist
-  	},
+	  .driver_info = NCTRL(0) | NCTRL(1) },
 	{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100),
-	  .driver_info = (kernel_ulong_t)&four_g_w100_blacklist
-	},
+	  .driver_info = NCTRL(1) | NCTRL(2) | RSVD(3) },
+	{USB_DEVICE(LONGCHEER_VENDOR_ID, FUJISOFT_PRODUCT_FS040U),
+	 .driver_info = RSVD(3)},
 	{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
+	{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9801, 0xff),
+	  .driver_info = RSVD(3) },
+	{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9803, 0xff),
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
 	{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
 	{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
@@ -1678,31 +1880,44 @@
 	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
 	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
 	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
-	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) },
 	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
-	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, 
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_2RMNET, 0xff),
+	  .driver_info = RSVD(4) | RSVD(5) },
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_AUDIO, 0xff),
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) },
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) },
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_CLS8, 0xff),
+	  .driver_info = RSVD(0) | RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EXS82, 0xff) },
+	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
 	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV31_MBIM, 0xff),
+	  .driver_info = RSVD(3)},
+	{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV31_RMNET, 0xff),
+	  .driver_info = RSVD(0)},
 	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD140),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
 	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD155),
-		.driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+	  .driver_info = RSVD(6) },
 	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200),
-		.driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+	  .driver_info = RSVD(6) },
 	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD160),
-		.driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+	  .driver_info = RSVD(6) },
 	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD500),
-		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
 	{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
 	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
@@ -1775,12 +1990,15 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) },
 	{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
+	{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MPL200),
+	  .driver_info = RSVD(1) | RSVD(4) },
 	{ USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600A) },
 	{ USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, TPLINK_PRODUCT_LTE, 0xff, 0x00, 0x00) },	/* TP-Link LTE Module */
 	{ USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(TPLINK_VENDOR_ID, 0x9000),					/* TP-Link MA260 */
-	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	  .driver_info = RSVD(4) },
 	{ USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) },	/* D-Link DWM-156 (variant) */
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) },	/* D-Link DWM-156 (variant) */
@@ -1788,11 +2006,54 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
-	{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
-	{ USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) },                /* OLICARD300 - MT6225 */
+	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) },			/* D-Link DWM-158 */
+	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d0e, 0xff) },			/* D-Link DWM-157 C1 */
+	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff),			/* D-Link DWM-221 B1 */
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff),			/* D-Link DWM-222 */
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e3d, 0xff),			/* D-Link DWM-222 A2 */
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) },	/* D-Link DWM-152/C1 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) },	/* D-Link DWM-156/C1 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) },	/* D-Link DWM-156/A3 */
+	{ USB_DEVICE_INTERFACE_CLASS(0x1435, 0xd191, 0xff),			/* Wistron Neweb D19Q1 */
+	  .driver_info = RSVD(1) | RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x1690, 0x7588, 0xff),			/* ASKEY WWHC050 */
+	  .driver_info = RSVD(1) | RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2031, 0xff),			/* Olicard 600 */
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2033, 0xff),			/* BroadMobi BM806U */
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2060, 0xff),			/* BroadMobi BM818 */
+	  .driver_info = RSVD(4) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) },			/* OLICARD300 - MT6225 */
 	{ USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
 	{ USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_6802, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD300, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, 0xff, 0xff, 0xff) },	/* HP lt2523 (Novatel E371) */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x10) },	/* HP lt4132 (Huawei ME906s-158) */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x12) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x13) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x14) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x1b) },
+	{ USB_DEVICE(0x0489, 0xe0b4),						/* Foxconn T77W968 */
+	  .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+	{ USB_DEVICE(0x0489, 0xe0b5),						/* Foxconn T77W968 ESIM */
+	  .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+	{ USB_DEVICE(0x1508, 0x1001),						/* Fibocom NL668 (IOT version) */
+	  .driver_info = RSVD(4) | RSVD(5) | RSVD(6) },
+	{ USB_DEVICE(0x2cb7, 0x0104),						/* Fibocom NL678 series */
+	  .driver_info = RSVD(4) | RSVD(5) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff),			/* Fibocom NL678 series */
+	  .driver_info = RSVD(6) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) },			/* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
+	{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) },			/* LongSung M5710 */
+	{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) },			/* GosunCn GM500 RNDIS */
+	{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) },			/* GosunCn GM500 MBIM */
+	{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) },			/* GosunCn GM500 ECM/NCM */
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1836,13 +2097,21 @@
 
 module_usb_serial_driver(serial_drivers, option_ids);
 
+static bool iface_is_reserved(unsigned long device_flags, u8 ifnum)
+{
+	if (ifnum > FLAG_IFNUM_MAX)
+		return false;
+
+	return device_flags & RSVD(ifnum);
+}
+
 static int option_probe(struct usb_serial *serial,
 			const struct usb_device_id *id)
 {
 	struct usb_interface_descriptor *iface_desc =
 				&serial->interface->cur_altsetting->desc;
 	struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
-	const struct option_blacklist_info *blacklist;
+	unsigned long device_flags = id->driver_info;
 
 	/* Never bind to the CD-Rom emulation interface	*/
 	if (iface_desc->bInterfaceClass == 0x08)
@@ -1853,9 +2122,7 @@
 	 * the same class/subclass/protocol as the serial interfaces.  Look at
 	 * the Windows driver .INF files for reserved interface numbers.
 	 */
-	blacklist = (void *)id->driver_info;
-	if (blacklist && test_bit(iface_desc->bInterfaceNumber,
-						&blacklist->reserved))
+	if (iface_is_reserved(device_flags, iface_desc->bInterfaceNumber))
 		return -ENODEV;
 	/*
 	 * Don't bind network interface on Samsung GT-B3730, it is handled by
@@ -1866,31 +2133,41 @@
 	    iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
 		return -ENODEV;
 
-	/* Store the blacklist info so we can use it during attach. */
-	usb_set_serial_data(serial, (void *)blacklist);
+	/* Store the device flags so we can use them during attach. */
+	usb_set_serial_data(serial, (void *)device_flags);
 
 	return 0;
 }
 
+static bool iface_no_modem_control(unsigned long device_flags, u8 ifnum)
+{
+	if (ifnum > FLAG_IFNUM_MAX)
+		return false;
+
+	return device_flags & NCTRL(ifnum);
+}
+
 static int option_attach(struct usb_serial *serial)
 {
 	struct usb_interface_descriptor *iface_desc;
-	const struct option_blacklist_info *blacklist;
 	struct usb_wwan_intf_private *data;
+	unsigned long device_flags;
 
 	data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
-	/* Retrieve blacklist info stored at probe. */
-	blacklist = usb_get_serial_data(serial);
+	/* Retrieve device flags stored at probe. */
+	device_flags = (unsigned long)usb_get_serial_data(serial);
 
 	iface_desc = &serial->interface->cur_altsetting->desc;
 
-	if (!blacklist || !test_bit(iface_desc->bInterfaceNumber,
-						&blacklist->sendsetup)) {
+	if (!iface_no_modem_control(device_flags, iface_desc->bInterfaceNumber))
 		data->use_send_setup = 1;
-	}
+
+	if (device_flags & ZLP)
+		data->use_zlp = 1;
+
 	spin_lock_init(&data->susp_lock);
 
 	usb_set_serial_data(serial, data);
--- linux-4.4.0.orig/drivers/usb/serial/oti6858.c
+++ linux-4.4.0/drivers/usb/serial/oti6858.c
@@ -134,6 +134,7 @@
 static int oti6858_tiocmget(struct tty_struct *tty);
 static int oti6858_tiocmset(struct tty_struct *tty,
 				unsigned int set, unsigned int clear);
+static int oti6858_attach(struct usb_serial *serial);
 static int oti6858_port_probe(struct usb_serial_port *port);
 static int oti6858_port_remove(struct usb_serial_port *port);
 
@@ -158,6 +159,7 @@
 	.write_bulk_callback =	oti6858_write_bulk_callback,
 	.write_room =		oti6858_write_room,
 	.chars_in_buffer =	oti6858_chars_in_buffer,
+	.attach =		oti6858_attach,
 	.port_probe =		oti6858_port_probe,
 	.port_remove =		oti6858_port_remove,
 };
@@ -324,6 +326,20 @@
 	usb_serial_port_softint(port);
 }
 
+static int oti6858_attach(struct usb_serial *serial)
+{
+	unsigned char num_ports = serial->num_ports;
+
+	if (serial->num_bulk_in < num_ports ||
+			serial->num_bulk_out < num_ports ||
+			serial->num_interrupt_in < num_ports) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int oti6858_port_probe(struct usb_serial_port *port)
 {
 	struct oti6858_private *priv;
--- linux-4.4.0.orig/drivers/usb/serial/pl2303.c
+++ linux-4.4.0/drivers/usb/serial/pl2303.c
@@ -39,6 +39,7 @@
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
+	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_CHILITAG) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
@@ -46,9 +47,12 @@
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) },
+	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
 	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC485) },
+	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) },
 	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
 	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
 	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
@@ -83,15 +87,23 @@
 	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
 	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220TA_PRODUCT_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_LD381_PRODUCT_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_LD381GC_PRODUCT_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_LD960TA_PRODUCT_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_LM920_PRODUCT_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_LM940_PRODUCT_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_TD620_PRODUCT_ID) },
 	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
 	{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
 	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
 	{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
 	{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
+	{ USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -220,9 +232,17 @@
 static int pl2303_startup(struct usb_serial *serial)
 {
 	struct pl2303_serial_private *spriv;
+	unsigned char num_ports = serial->num_ports;
 	enum pl2303_type type = TYPE_01;
 	unsigned char *buf;
 
+	if (serial->num_bulk_in < num_ports ||
+			serial->num_bulk_out < num_ports ||
+			serial->num_interrupt_in < num_ports) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
 	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
 	if (!spriv)
 		return -ENOMEM;
--- linux-4.4.0.orig/drivers/usb/serial/pl2303.h
+++ linux-4.4.0/drivers/usb/serial/pl2303.h
@@ -13,10 +13,12 @@
 
 #define PL2303_VENDOR_ID	0x067b
 #define PL2303_PRODUCT_ID	0x2303
+#define PL2303_PRODUCT_ID_TB		0x2304
 #define PL2303_PRODUCT_ID_RSAQ2		0x04bb
 #define PL2303_PRODUCT_ID_DCU11		0x1234
 #define PL2303_PRODUCT_ID_PHAROS	0xaaa0
 #define PL2303_PRODUCT_ID_RSAQ3		0xaaa2
+#define PL2303_PRODUCT_ID_CHILITAG	0xaaa8
 #define PL2303_PRODUCT_ID_ALDIGA	0x0611
 #define PL2303_PRODUCT_ID_MMX		0x0612
 #define PL2303_PRODUCT_ID_GPRS		0x0609
@@ -24,9 +26,12 @@
 #define PL2303_PRODUCT_ID_MOTOROLA	0x0307
 #define PL2303_PRODUCT_ID_ZTEK		0xe1f1
 
+
 #define ATEN_VENDOR_ID		0x0557
 #define ATEN_VENDOR_ID2		0x0547
 #define ATEN_PRODUCT_ID		0x2008
+#define ATEN_PRODUCT_UC485	0x2021
+#define ATEN_PRODUCT_ID2	0x2118
 
 #define IODATA_VENDOR_ID	0x04bb
 #define IODATA_PRODUCT_ID	0x0a03
@@ -120,10 +125,17 @@
 
 /* Hewlett-Packard POS Pole Displays */
 #define HP_VENDOR_ID		0x03f0
+#define HP_LD381GC_PRODUCT_ID	0x0183
+#define HP_LM920_PRODUCT_ID	0x026b
+#define HP_TD620_PRODUCT_ID	0x0956
 #define HP_LD960_PRODUCT_ID	0x0b39
+#define HP_LD381_PRODUCT_ID	0x0f7f
 #define HP_LCM220_PRODUCT_ID	0x3139
 #define HP_LCM960_PRODUCT_ID	0x3239
 #define HP_LD220_PRODUCT_ID	0x3524
+#define HP_LD220TA_PRODUCT_ID	0x4349
+#define HP_LD960TA_PRODUCT_ID	0x4439
+#define HP_LM940_PRODUCT_ID	0x5039
 
 /* Cressi Edy (diving computer) PC interface */
 #define CRESSI_VENDOR_ID	0x04b8
@@ -149,3 +161,6 @@
 #define SMART_VENDOR_ID	0x0b8c
 #define SMART_PRODUCT_ID	0x2303
 
+/* Allied Telesis VT-Kit3 */
+#define AT_VENDOR_ID		0x0caa
+#define AT_VTKIT3_PRODUCT_ID	0x3001
--- linux-4.4.0.orig/drivers/usb/serial/qcserial.c
+++ linux-4.4.0/drivers/usb/serial/qcserial.c
@@ -124,6 +124,7 @@
 	{USB_DEVICE(0x1410, 0xa021)},	/* Novatel Gobi 3000 Composite */
 	{USB_DEVICE(0x413c, 0x8193)},	/* Dell Gobi 3000 QDL */
 	{USB_DEVICE(0x413c, 0x8194)},	/* Dell Gobi 3000 Composite */
+	{USB_DEVICE(0x413c, 0x81a6)},	/* Dell DW5570 QDL (MC8805) */
 	{USB_DEVICE(0x1199, 0x68a4)},	/* Sierra Wireless QDL */
 	{USB_DEVICE(0x1199, 0x68a5)},	/* Sierra Wireless Modem */
 	{USB_DEVICE(0x1199, 0x68a8)},	/* Sierra Wireless QDL */
@@ -147,6 +148,7 @@
 	{DEVICE_SWI(0x1199, 0x68a2)},	/* Sierra Wireless MC7710 */
 	{DEVICE_SWI(0x1199, 0x68c0)},	/* Sierra Wireless MC7304/MC7354 */
 	{DEVICE_SWI(0x1199, 0x901c)},	/* Sierra Wireless EM7700 */
+	{DEVICE_SWI(0x1199, 0x901e)},	/* Sierra Wireless EM7355 QDL */
 	{DEVICE_SWI(0x1199, 0x901f)},	/* Sierra Wireless EM7355 */
 	{DEVICE_SWI(0x1199, 0x9040)},	/* Sierra Wireless Modem */
 	{DEVICE_SWI(0x1199, 0x9041)},	/* Sierra Wireless MC7305/MC7355 */
@@ -157,14 +159,31 @@
 	{DEVICE_SWI(0x1199, 0x9056)},	/* Sierra Wireless Modem */
 	{DEVICE_SWI(0x1199, 0x9060)},	/* Sierra Wireless Modem */
 	{DEVICE_SWI(0x1199, 0x9061)},	/* Sierra Wireless Modem */
-	{DEVICE_SWI(0x1199, 0x9070)},	/* Sierra Wireless MC74xx/EM74xx */
-	{DEVICE_SWI(0x1199, 0x9071)},	/* Sierra Wireless MC74xx/EM74xx */
+	{DEVICE_SWI(0x1199, 0x9062)},	/* Sierra Wireless EM7305 QDL */
+	{DEVICE_SWI(0x1199, 0x9063)},	/* Sierra Wireless EM7305 */
+	{DEVICE_SWI(0x1199, 0x9070)},	/* Sierra Wireless MC74xx */
+	{DEVICE_SWI(0x1199, 0x9071)},	/* Sierra Wireless MC74xx */
+	{DEVICE_SWI(0x1199, 0x9078)},	/* Sierra Wireless EM74xx */
+	{DEVICE_SWI(0x1199, 0x9079)},	/* Sierra Wireless EM74xx */
+	{DEVICE_SWI(0x1199, 0x907a)},	/* Sierra Wireless EM74xx QDL */
+	{DEVICE_SWI(0x1199, 0x907b)},	/* Sierra Wireless EM74xx */
+	{DEVICE_SWI(0x1199, 0x9090)},	/* Sierra Wireless EM7565 QDL */
+	{DEVICE_SWI(0x1199, 0x9091)},	/* Sierra Wireless EM7565 */
 	{DEVICE_SWI(0x413c, 0x81a2)},	/* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
 	{DEVICE_SWI(0x413c, 0x81a3)},	/* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
 	{DEVICE_SWI(0x413c, 0x81a4)},	/* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
 	{DEVICE_SWI(0x413c, 0x81a8)},	/* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
 	{DEVICE_SWI(0x413c, 0x81a9)},	/* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
 	{DEVICE_SWI(0x413c, 0x81b1)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
+	{DEVICE_SWI(0x413c, 0x81b3)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
+	{DEVICE_SWI(0x413c, 0x81b5)},	/* Dell Wireless 5811e QDL */
+	{DEVICE_SWI(0x413c, 0x81b6)},	/* Dell Wireless 5811e QDL */
+	{DEVICE_SWI(0x413c, 0x81cb)},	/* Dell Wireless 5816e QDL */
+	{DEVICE_SWI(0x413c, 0x81cc)},	/* Dell Wireless 5816e */
+	{DEVICE_SWI(0x413c, 0x81cf)},   /* Dell Wireless 5819 */
+	{DEVICE_SWI(0x413c, 0x81d0)},   /* Dell Wireless 5819 */
+	{DEVICE_SWI(0x413c, 0x81d1)},   /* Dell Wireless 5818 */
+	{DEVICE_SWI(0x413c, 0x81d2)},   /* Dell Wireless 5818 */
 
 	/* Huawei devices */
 	{DEVICE_HWI(0x03f0, 0x581d)},	/* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
@@ -332,6 +351,7 @@
 			break;
 		case 2:
 			dev_dbg(dev, "NMEA GPS interface found\n");
+			sendsetup = true;
 			break;
 		case 3:
 			dev_dbg(dev, "Modem port found\n");
--- linux-4.4.0.orig/drivers/usb/serial/quatech2.c
+++ linux-4.4.0/drivers/usb/serial/quatech2.c
@@ -141,6 +141,7 @@
 
 	serial_priv = usb_get_serial_data(serial);
 
+	usb_kill_urb(serial_priv->read_urb);
 	usb_free_urb(serial_priv->read_urb);
 	kfree(serial_priv->read_buffer);
 	kfree(serial_priv);
@@ -187,22 +188,22 @@
 }
 
 
-static inline int qt2_getdevice(struct usb_device *dev, u8 *data)
-{
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       QT_SET_GET_DEVICE, 0xc0, 0, 0,
-			       data, 3, QT2_USB_TIMEOUT);
-}
-
 static inline int qt2_getregister(struct usb_device *dev,
 				  u8 uart,
 				  u8 reg,
 				  u8 *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       QT_SET_GET_REGISTER, 0xc0, reg,
-			       uart, data, sizeof(*data), QT2_USB_TIMEOUT);
+	int ret;
 
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			      QT_SET_GET_REGISTER, 0xc0, reg,
+			      uart, data, sizeof(*data), QT2_USB_TIMEOUT);
+	if (ret < sizeof(*data)) {
+		if (ret >= 0)
+			ret = -EIO;
+	}
+
+	return ret;
 }
 
 static inline int qt2_setregister(struct usb_device *dev,
@@ -371,9 +372,11 @@
 				 0xc0, 0,
 				 device_port, data, 2, QT2_USB_TIMEOUT);
 
-	if (status < 0) {
+	if (status < 2) {
 		dev_err(&port->dev, "%s - open port failed %i\n", __func__,
 			status);
+		if (status >= 0)
+			status = -EIO;
 		kfree(data);
 		return status;
 	}
@@ -407,16 +410,12 @@
 {
 	struct usb_serial *serial;
 	struct qt2_port_private *port_priv;
-	unsigned long flags;
 	int i;
 
 	serial = port->serial;
 	port_priv = usb_get_serial_port_data(port);
 
-	spin_lock_irqsave(&port_priv->urb_lock, flags);
 	usb_kill_urb(port_priv->write_urb);
-	port_priv->urb_in_use = false;
-	spin_unlock_irqrestore(&port_priv->urb_lock, flags);
 
 	/* flush the port transmit buffer */
 	i = usb_control_msg(serial->dev,
@@ -873,7 +872,10 @@
 	u8 newMSR = (u8) *ch;
 	unsigned long flags;
 
+	/* May be called from qt2_process_read_urb() for an unbound port. */
 	port_priv = usb_get_serial_port_data(port);
+	if (!port_priv)
+		return;
 
 	spin_lock_irqsave(&port_priv->lock, flags);
 	port_priv->shadowMSR = newMSR;
@@ -901,7 +903,10 @@
 	unsigned long flags;
 	u8 newLSR = (u8) *ch;
 
+	/* May be called from qt2_process_read_urb() for an unbound port. */
 	port_priv = usb_get_serial_port_data(port);
+	if (!port_priv)
+		return;
 
 	if (newLSR & UART_LSR_BI)
 		newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI);
--- linux-4.4.0.orig/drivers/usb/serial/safe_serial.c
+++ linux-4.4.0/drivers/usb/serial/safe_serial.c
@@ -205,6 +205,11 @@
 	if (!safe)
 		goto out;
 
+	if (length < 2) {
+		dev_err(&port->dev, "malformed packet\n");
+		return;
+	}
+
 	fcs = fcs_compute10(data, length, CRC10_INITFCS);
 	if (fcs) {
 		dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
--- linux-4.4.0.orig/drivers/usb/serial/sierra.c
+++ linux-4.4.0/drivers/usb/serial/sierra.c
@@ -790,9 +790,9 @@
 		kfree(urb->transfer_buffer);
 		usb_free_urb(urb);
 		usb_autopm_put_interface_async(serial->interface);
-		spin_lock(&portdata->lock);
+		spin_lock_irq(&portdata->lock);
 		portdata->outstanding_urbs--;
-		spin_unlock(&portdata->lock);
+		spin_unlock_irq(&portdata->lock);
 	}
 
 	sierra_stop_rx_urbs(port);
--- linux-4.4.0.orig/drivers/usb/serial/spcp8x5.c
+++ linux-4.4.0/drivers/usb/serial/spcp8x5.c
@@ -154,6 +154,19 @@
 	return 0;
 }
 
+static int spcp8x5_attach(struct usb_serial *serial)
+{
+	unsigned char num_ports = serial->num_ports;
+
+	if (serial->num_bulk_in < num_ports ||
+			serial->num_bulk_out < num_ports) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int spcp8x5_port_probe(struct usb_serial_port *port)
 {
 	const struct usb_device_id *id = usb_get_serial_data(port->serial);
@@ -219,11 +232,17 @@
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 			      GET_UART_STATUS, GET_UART_STATUS_TYPE,
 			      0, GET_UART_STATUS_MSR, buf, 1, 100);
-	if (ret < 0)
+	if (ret < 1) {
 		dev_err(&port->dev, "failed to get modem status: %d\n", ret);
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
 
 	dev_dbg(&port->dev, "0xc0:0x22:0:6  %d - 0x02%x\n", ret, *buf);
 	*status = *buf;
+	ret = 0;
+out:
 	kfree(buf);
 
 	return ret;
@@ -477,6 +496,7 @@
 	.tiocmget		= spcp8x5_tiocmget,
 	.tiocmset		= spcp8x5_tiocmset,
 	.probe			= spcp8x5_probe,
+	.attach			= spcp8x5_attach,
 	.port_probe		= spcp8x5_port_probe,
 	.port_remove		= spcp8x5_port_remove,
 };
--- linux-4.4.0.orig/drivers/usb/serial/ssu100.c
+++ linux-4.4.0/drivers/usb/serial/ssu100.c
@@ -80,9 +80,17 @@
 
 static inline int ssu100_getdevice(struct usb_device *dev, u8 *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       QT_SET_GET_DEVICE, 0xc0, 0, 0,
-			       data, 3, 300);
+	int ret;
+
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			      QT_SET_GET_DEVICE, 0xc0, 0, 0,
+			      data, 3, 300);
+	if (ret < 3) {
+		if (ret >= 0)
+			ret = -EIO;
+	}
+
+	return ret;
 }
 
 static inline int ssu100_getregister(struct usb_device *dev,
@@ -90,10 +98,17 @@
 				     unsigned short reg,
 				     u8 *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       QT_SET_GET_REGISTER, 0xc0, reg,
-			       uart, data, sizeof(*data), 300);
+	int ret;
 
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			      QT_SET_GET_REGISTER, 0xc0, reg,
+			      uart, data, sizeof(*data), 300);
+	if (ret < sizeof(*data)) {
+		if (ret >= 0)
+			ret = -EIO;
+	}
+
+	return ret;
 }
 
 
@@ -289,8 +304,10 @@
 				 QT_OPEN_CLOSE_CHANNEL,
 				 QT_TRANSFER_IN, 0x01,
 				 0, data, 2, 300);
-	if (result < 0) {
+	if (result < 2) {
 		dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result);
+		if (result >= 0)
+			result = -EIO;
 		kfree(data);
 		return result;
 	}
--- linux-4.4.0.orig/drivers/usb/serial/ti_usb_3410_5052.c
+++ linux-4.4.0/drivers/usb/serial/ti_usb_3410_5052.c
@@ -339,6 +339,13 @@
 		goto free_tdev;
 	}
 
+	if (serial->num_bulk_in < serial->num_ports ||
+			serial->num_bulk_out < serial->num_ports) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		status = -ENODEV;
+		goto free_tdev;
+	}
+
 	return 0;
 
 free_tdev:
@@ -535,7 +542,6 @@
 	struct ti_port *tport;
 	int port_number;
 	int status;
-	int do_unlock;
 	unsigned long flags;
 
 	tdev = usb_get_serial_data(port->serial);
@@ -562,16 +568,13 @@
 			"%s - cannot send close port command, %d\n"
 							, __func__, status);
 
-	/* if mutex_lock is interrupted, continue anyway */
-	do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
+	mutex_lock(&tdev->td_open_close_lock);
 	--tport->tp_tdev->td_open_port_count;
-	if (tport->tp_tdev->td_open_port_count <= 0) {
+	if (tport->tp_tdev->td_open_port_count == 0) {
 		/* last port is closed, shut down interrupt urb */
 		usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
-		tport->tp_tdev->td_open_port_count = 0;
 	}
-	if (do_unlock)
-		mutex_unlock(&tdev->td_open_close_lock);
+	mutex_unlock(&tdev->td_open_close_lock);
 }
 
 
@@ -1345,13 +1348,10 @@
 		(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT),
 		value, moduleid, data, size, 1000);
 
-	if (status == size)
-		status = 0;
+	if (status < 0)
+		return status;
 
-	if (status > 0)
-		status = -ECOMM;
-
-	return status;
+	return 0;
 }
 
 
@@ -1367,8 +1367,7 @@
 
 	if (status == size)
 		status = 0;
-
-	if (status > 0)
+	else if (status >= 0)
 		status = -ECOMM;
 
 	return status;
--- linux-4.4.0.orig/drivers/usb/serial/ti_usb_3410_5052.h
+++ linux-4.4.0/drivers/usb/serial/ti_usb_3410_5052.h
@@ -227,7 +227,7 @@
 } __attribute__((packed));
 
 /* Interrupt codes */
-#define TI_GET_PORT_FROM_CODE(c)	(((c) >> 4) - 3)
+#define TI_GET_PORT_FROM_CODE(c)	(((c) >> 6) & 0x01)
 #define TI_GET_FUNC_FROM_CODE(c)	((c) & 0x0f)
 #define TI_CODE_HARDWARE_ERROR		0xFF
 #define TI_CODE_DATA_ERROR		0x03
--- linux-4.4.0.orig/drivers/usb/serial/usb-serial-simple.c
+++ linux-4.4.0/drivers/usb/serial/usb-serial-simple.c
@@ -54,7 +54,8 @@
 /* Infineon Flashloader driver */
 #define FLASHLOADER_IDS()		\
 	{ USB_DEVICE_INTERFACE_CLASS(0x058b, 0x0041, USB_CLASS_CDC_DATA) }, \
-	{ USB_DEVICE(0x8087, 0x0716) }
+	{ USB_DEVICE(0x8087, 0x0716) }, \
+	{ USB_DEVICE(0x8087, 0x0801) }
 DEVICE(flashloader, FLASHLOADER_IDS);
 
 /* Google Serial USB SubClass */
@@ -65,6 +66,11 @@
 					0x01) }
 DEVICE(google, GOOGLE_IDS);
 
+/* Libtransistor USB console */
+#define LIBTRANSISTOR_IDS()			\
+	{ USB_DEVICE(0x1209, 0x8b00) }
+DEVICE(libtransistor, LIBTRANSISTOR_IDS);
+
 /* ViVOpay USB Serial Driver */
 #define VIVOPAY_IDS()			\
 	{ USB_DEVICE(0x1d5f, 0x1004) }	/* ViVOpay 8800 */
@@ -79,6 +85,15 @@
 	{ USB_DEVICE(0x22b8, 0x2c64) }	/* Motorola V950 phone */
 DEVICE(moto_modem, MOTO_IDS);
 
+/* Motorola Tetra driver */
+#define MOTOROLA_TETRA_IDS()			\
+	{ USB_DEVICE(0x0cad, 0x9011) },	/* Motorola Solutions TETRA PEI */ \
+	{ USB_DEVICE(0x0cad, 0x9012) },	/* MTP6550 */ \
+	{ USB_DEVICE(0x0cad, 0x9013) },	/* MTP3xxx */ \
+	{ USB_DEVICE(0x0cad, 0x9015) },	/* MTP85xx */ \
+	{ USB_DEVICE(0x0cad, 0x9016) }	/* TPG2200 */
+DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS);
+
 /* Novatel Wireless GPS driver */
 #define NOVATEL_IDS()			\
 	{ USB_DEVICE(0x09d7, 0x0100) }	/* NovAtel FlexPack GPS */
@@ -107,8 +122,10 @@
 	&funsoft_device,
 	&flashloader_device,
 	&google_device,
+	&libtransistor_device,
 	&vivopay_device,
 	&moto_modem_device,
+	&motorola_tetra_device,
 	&novatel_gps_device,
 	&hp4x_device,
 	&suunto_device,
@@ -122,8 +139,10 @@
 	FUNSOFT_IDS(),
 	FLASHLOADER_IDS(),
 	GOOGLE_IDS(),
+	LIBTRANSISTOR_IDS(),
 	VIVOPAY_IDS(),
 	MOTO_IDS(),
+	MOTOROLA_TETRA_IDS(),
 	NOVATEL_IDS(),
 	HP4X_IDS(),
 	SUUNTO_IDS(),
--- linux-4.4.0.orig/drivers/usb/serial/usb-serial.c
+++ linux-4.4.0/drivers/usb/serial/usb-serial.c
@@ -314,10 +314,7 @@
 	serial = port->serial;
 	owner = serial->type->driver.owner;
 
-	mutex_lock(&serial->disc_mutex);
-	if (!serial->disconnected)
-		usb_autopm_put_interface(serial->interface);
-	mutex_unlock(&serial->disc_mutex);
+	usb_autopm_put_interface(serial->interface);
 
 	usb_serial_put(serial);
 	module_put(owner);
@@ -1077,7 +1074,8 @@
 
 	serial->disconnected = 0;
 
-	usb_serial_console_init(serial->port[0]->minor);
+	if (num_ports > 0)
+		usb_serial_console_init(serial->port[0]->minor);
 exit:
 	module_put(type->driver.owner);
 	return 0;
@@ -1352,6 +1350,9 @@
 		return -EINVAL;
 	}
 
+	/* Prevent individual ports from being unbound. */
+	driver->driver.suppress_bind_attrs = true;
+
 	usb_serial_operations_init(driver);
 
 	/* Add this device to our list of devices */
@@ -1432,7 +1433,7 @@
 
 	rc = usb_register(udriver);
 	if (rc)
-		return rc;
+		goto failed_usb_register;
 
 	for (sd = serial_drivers; *sd; ++sd) {
 		(*sd)->usb_driver = udriver;
@@ -1450,6 +1451,8 @@
 	while (sd-- > serial_drivers)
 		usb_serial_deregister(*sd);
 	usb_deregister(udriver);
+failed_usb_register:
+	kfree(udriver);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(usb_serial_register_drivers);
--- linux-4.4.0.orig/drivers/usb/serial/usb-wwan.h
+++ linux-4.4.0/drivers/usb/serial/usb-wwan.h
@@ -35,6 +35,7 @@
 	spinlock_t susp_lock;
 	unsigned int suspended:1;
 	unsigned int use_send_setup:1;
+	unsigned int use_zlp:1;
 	int in_flight;
 	unsigned int open_ports;
 	void *private;
--- linux-4.4.0.orig/drivers/usb/serial/usb_wwan.c
+++ linux-4.4.0/drivers/usb/serial/usb_wwan.c
@@ -305,6 +305,10 @@
 	if (status) {
 		dev_dbg(dev, "%s: nonzero status: %d on endpoint %02x.\n",
 			__func__, status, endpoint);
+
+		/* don't resubmit on fatal errors */
+		if (status == -ESHUTDOWN || status == -ENOENT)
+			return;
 	} else {
 		if (urb->actual_length) {
 			tty_insert_flip_string(&port->port, data,
@@ -495,6 +499,7 @@
 				      void (*callback) (struct urb *))
 {
 	struct usb_serial *serial = port->serial;
+	struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
 	struct urb *urb;
 
 	urb = usb_alloc_urb(0, GFP_KERNEL);	/* No ISO */
@@ -505,6 +510,9 @@
 			  usb_sndbulkpipe(serial->dev, endpoint) | dir,
 			  buf, len, callback, ctx);
 
+	if (intfdata->use_zlp && dir == USB_DIR_OUT)
+		urb->transfer_flags |= URB_ZERO_PACKET;
+
 	return urb;
 }
 
--- linux-4.4.0.orig/drivers/usb/serial/visor.c
+++ linux-4.4.0/drivers/usb/serial/visor.c
@@ -338,47 +338,48 @@
 		goto exit;
 	}
 
-	if (retval == sizeof(*connection_info)) {
-			connection_info = (struct visor_connection_info *)
-							transfer_buffer;
-
-		num_ports = le16_to_cpu(connection_info->num_ports);
-		for (i = 0; i < num_ports; ++i) {
-			switch (
-			   connection_info->connections[i].port_function_id) {
-			case VISOR_FUNCTION_GENERIC:
-				string = "Generic";
-				break;
-			case VISOR_FUNCTION_DEBUGGER:
-				string = "Debugger";
-				break;
-			case VISOR_FUNCTION_HOTSYNC:
-				string = "HotSync";
-				break;
-			case VISOR_FUNCTION_CONSOLE:
-				string = "Console";
-				break;
-			case VISOR_FUNCTION_REMOTE_FILE_SYS:
-				string = "Remote File System";
-				break;
-			default:
-				string = "unknown";
-				break;
-			}
-			dev_info(dev, "%s: port %d, is for %s use\n",
-				serial->type->description,
-				connection_info->connections[i].port, string);
-		}
+	if (retval != sizeof(*connection_info)) {
+		dev_err(dev, "Invalid connection information received from device\n");
+		retval = -ENODEV;
+		goto exit;
 	}
-	/*
-	* Handle devices that report invalid stuff here.
-	*/
+
+	connection_info = (struct visor_connection_info *)transfer_buffer;
+
+	num_ports = le16_to_cpu(connection_info->num_ports);
+
+	/* Handle devices that report invalid stuff here. */
 	if (num_ports == 0 || num_ports > 2) {
 		dev_warn(dev, "%s: No valid connect info available\n",
 			serial->type->description);
 		num_ports = 2;
 	}
 
+	for (i = 0; i < num_ports; ++i) {
+		switch (connection_info->connections[i].port_function_id) {
+		case VISOR_FUNCTION_GENERIC:
+			string = "Generic";
+			break;
+		case VISOR_FUNCTION_DEBUGGER:
+			string = "Debugger";
+			break;
+		case VISOR_FUNCTION_HOTSYNC:
+			string = "HotSync";
+			break;
+		case VISOR_FUNCTION_CONSOLE:
+			string = "Console";
+			break;
+		case VISOR_FUNCTION_REMOTE_FILE_SYS:
+			string = "Remote File System";
+			break;
+		default:
+			string = "unknown";
+			break;
+		}
+		dev_info(dev, "%s: port %d, is for %s use\n",
+			serial->type->description,
+			connection_info->connections[i].port, string);
+	}
 	dev_info(dev, "%s: Number of ports: %d\n", serial->type->description,
 		num_ports);
 
@@ -544,6 +545,11 @@
 		(serial->num_interrupt_in == 0))
 		return 0;
 
+	if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) {
+		dev_err(&serial->interface->dev, "missing endpoints\n");
+		return -ENODEV;
+	}
+
 	/*
 	* It appears that Treos and Kyoceras want to use the
 	* 1st bulk in endpoint to communicate with the 2nd bulk out endpoint,
@@ -597,8 +603,10 @@
 	 */
 
 	/* some sanity check */
-	if (serial->num_ports < 2)
-		return -1;
+	if (serial->num_bulk_out < 2) {
+		dev_err(&serial->interface->dev, "missing bulk out endpoints\n");
+		return -ENODEV;
+	}
 
 	/* port 0 now uses the modified endpoint Address */
 	port = serial->port[0];
--- linux-4.4.0.orig/drivers/usb/serial/whiteheat.c
+++ linux-4.4.0/drivers/usb/serial/whiteheat.c
@@ -604,6 +604,10 @@
 
 	command_port = port->serial->port[COMMAND_PORT];
 	command_info = usb_get_serial_port_data(command_port);
+
+	if (command_port->bulk_out_size < datasize + 1)
+		return -EIO;
+
 	mutex_lock(&command_info->mutex);
 	command_info->command_finished = false;
 
@@ -677,6 +681,7 @@
 	struct device *dev = &port->dev;
 	struct whiteheat_port_settings port_settings;
 	unsigned int cflag = tty->termios.c_cflag;
+	speed_t baud;
 
 	port_settings.port = port->port_number + 1;
 
@@ -737,11 +742,13 @@
 	dev_dbg(dev, "%s - XON = %2x, XOFF = %2x\n", __func__, port_settings.xon, port_settings.xoff);
 
 	/* get the baud rate wanted */
-	port_settings.baud = tty_get_baud_rate(tty);
-	dev_dbg(dev, "%s - baud rate = %d\n", __func__, port_settings.baud);
+	baud = tty_get_baud_rate(tty);
+	port_settings.baud = cpu_to_le32(baud);
+	dev_dbg(dev, "%s - baud rate = %u\n", __func__, baud);
 
 	/* fixme: should set validated settings */
-	tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud);
+	tty_encode_baud_rate(tty, baud, baud);
+
 	/* handle any settings that aren't specified in the tty structure */
 	port_settings.lloop = 0;
 
--- linux-4.4.0.orig/drivers/usb/serial/whiteheat.h
+++ linux-4.4.0/drivers/usb/serial/whiteheat.h
@@ -91,7 +91,7 @@
 
 struct whiteheat_port_settings {
 	__u8	port;		/* port number (1 to N) */
-	__u32	baud;		/* any value 7 - 460800, firmware calculates
+	__le32	baud;		/* any value 7 - 460800, firmware calculates
 				   best fit; arrives little endian */
 	__u8	bits;		/* 5, 6, 7, or 8 */
 	__u8	stop;		/* 1 or 2, default 1 (2 = 1.5 if bits = 5) */
--- linux-4.4.0.orig/drivers/usb/storage/alauda.c
+++ linux-4.4.0/drivers/usb/storage/alauda.c
@@ -117,6 +117,8 @@
 	unsigned char sense_key;
 	unsigned long sense_asc;	/* additional sense code */
 	unsigned long sense_ascq;	/* additional sense code qualifier */
+
+	bool media_initialized;
 };
 
 #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
@@ -481,11 +483,12 @@
 	}
 
 	/* Check for media change */
-	if (status[0] & 0x08) {
+	if (status[0] & 0x08 || !info->media_initialized) {
 		usb_stor_dbg(us, "Media change detected\n");
 		alauda_free_maps(&MEDIA_INFO(us));
-		alauda_init_media(us);
-
+		rc = alauda_init_media(us);
+		if (rc == USB_STOR_TRANSPORT_GOOD)
+			info->media_initialized = true;
 		info->sense_key = UNIT_ATTENTION;
 		info->sense_asc = 0x28;
 		info->sense_ascq = 0x00;
--- linux-4.4.0.orig/drivers/usb/storage/ene_ub6250.c
+++ linux-4.4.0/drivers/usb/storage/ene_ub6250.c
@@ -446,6 +446,10 @@
 #define SD_BLOCK_LEN  9
 
 struct ene_ub6250_info {
+
+	/* I/O bounce buffer */
+	u8		*bbuf;
+
 	/* for 6250 code */
 	struct SD_STATUS	SD_Status;
 	struct MS_STATUS	MS_Status;
@@ -493,8 +497,11 @@
 
 static void ene_ub6250_info_destructor(void *extra)
 {
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) extra;
+
 	if (!extra)
 		return;
+	kfree(info->bbuf);
 }
 
 static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
@@ -858,8 +865,9 @@
 		u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat)
 {
 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
 	int result;
-	u8 ExtBuf[4];
 	u32 bn = PhyBlockAddr * 0x20 + PageNum;
 
 	/* printk(KERN_INFO "MS --- MS_ReaderReadPage,
@@ -902,7 +910,7 @@
 	bcb->CDB[2]     = (unsigned char)(PhyBlockAddr>>16);
 	bcb->CDB[6]     = 0x01;
 
-	result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
+	result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
@@ -911,9 +919,9 @@
 	ExtraDat->status0  = 0x10;  /* Not yet,fireware support */
 
 	ExtraDat->status1  = 0x00;  /* Not yet,fireware support */
-	ExtraDat->ovrflg   = ExtBuf[0];
-	ExtraDat->mngflg   = ExtBuf[1];
-	ExtraDat->logadr   = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
+	ExtraDat->ovrflg   = bbuf[0];
+	ExtraDat->mngflg   = bbuf[1];
+	ExtraDat->logadr   = memstick_logaddr(bbuf[2], bbuf[3]);
 
 	return USB_STOR_TRANSPORT_GOOD;
 }
@@ -928,7 +936,7 @@
 	struct ms_lib_type_extdat ExtraData;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
 
-	PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+	PageBuffer = kzalloc(MS_BYTES_PER_PAGE * 2, GFP_KERNEL);
 	if (PageBuffer == NULL)
 		return (u32)-1;
 
@@ -1339,8 +1347,9 @@
 				u8 PageNum, struct ms_lib_type_extdat *ExtraDat)
 {
 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
 	int result;
-	u8 ExtBuf[4];
 
 	/* printk("MS_LibReadExtra --- PhyBlock = %x, PageNum = %x\n", PhyBlock, PageNum); */
 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
@@ -1355,7 +1364,7 @@
 	bcb->CDB[2]     = (unsigned char)(PhyBlock>>16);
 	bcb->CDB[6]     = 0x01;
 
-	result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
+	result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
@@ -1363,9 +1372,9 @@
 	ExtraDat->intr     = 0x80;  /* Not yet, waiting for fireware support */
 	ExtraDat->status0  = 0x10;  /* Not yet, waiting for fireware support */
 	ExtraDat->status1  = 0x00;  /* Not yet, waiting for fireware support */
-	ExtraDat->ovrflg   = ExtBuf[0];
-	ExtraDat->mngflg   = ExtBuf[1];
-	ExtraDat->logadr   = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
+	ExtraDat->ovrflg   = bbuf[0];
+	ExtraDat->mngflg   = bbuf[1];
+	ExtraDat->logadr   = memstick_logaddr(bbuf[2], bbuf[3]);
 
 	return USB_STOR_TRANSPORT_GOOD;
 }
@@ -1569,9 +1578,9 @@
 	u16 PhyBlock, newblk, i;
 	u16 LogStart, LogEnde;
 	struct ms_lib_type_extdat extdat;
-	u8 buf[0x200];
 	u32 count = 0, index = 0;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
 
 	for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) {
 		ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde);
@@ -1585,14 +1594,16 @@
 			}
 
 			if (count == PhyBlock) {
-				ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, &buf);
+				ms_lib_read_extrablock(us, PhyBlock, 0, 0x80,
+						bbuf);
 				count += 0x80;
 			}
 			index = (PhyBlock % 0x80) * 4;
 
-			extdat.ovrflg = buf[index];
-			extdat.mngflg = buf[index+1];
-			extdat.logadr = memstick_logaddr(buf[index+2], buf[index+3]);
+			extdat.ovrflg = bbuf[index];
+			extdat.mngflg = bbuf[index+1];
+			extdat.logadr = memstick_logaddr(bbuf[index+2],
+					bbuf[index+3]);
 
 			if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
 				ms_lib_setacquired_errorblock(us, PhyBlock);
@@ -1942,6 +1953,8 @@
 	bcb->CDB[0] = 0xEF;
 
 	result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
+	if (us->srb != NULL)
+		scsi_set_resid(us->srb, 0);
 	info->BIN_FLAG = flag;
 	kfree(buf);
 
@@ -2075,9 +2088,9 @@
 {
 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
 	int result;
-	u8 buf[0x200];
 	u16 MSP_BlockSize, MSP_UserAreaBlocks;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
 
 	printk(KERN_INFO "transport --- ENE_MSInit\n");
 
@@ -2096,13 +2109,13 @@
 	bcb->CDB[0]     = 0xF1;
 	bcb->CDB[1]     = 0x01;
 
-	result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
+	result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
 	if (result != USB_STOR_XFER_GOOD) {
 		printk(KERN_ERR "Execution MS Init Code Fail !!\n");
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 	/* the same part to test ENE */
-	info->MS_Status = *(struct MS_STATUS *)&buf[0];
+	info->MS_Status = *(struct MS_STATUS *) bbuf;
 
 	if (info->MS_Status.Insert && info->MS_Status.Ready) {
 		printk(KERN_INFO "Insert     = %x\n", info->MS_Status.Insert);
@@ -2111,15 +2124,15 @@
 		printk(KERN_INFO "IsMSPHG    = %x\n", info->MS_Status.IsMSPHG);
 		printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP);
 		if (info->MS_Status.IsMSPro) {
-			MSP_BlockSize      = (buf[6] << 8) | buf[7];
-			MSP_UserAreaBlocks = (buf[10] << 8) | buf[11];
+			MSP_BlockSize      = (bbuf[6] << 8) | bbuf[7];
+			MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11];
 			info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
 		} else {
 			ms_card_init(us); /* Card is MS (to ms.c)*/
 		}
 		usb_stor_dbg(us, "MS Init Code OK !!\n");
 	} else {
-		usb_stor_dbg(us, "MS Card Not Ready --- %x\n", buf[0]);
+		usb_stor_dbg(us, "MS Card Not Ready --- %x\n", bbuf[0]);
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
@@ -2129,9 +2142,9 @@
 static int ene_sd_init(struct us_data *us)
 {
 	int result;
-	u8  buf[0x200];
 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
 
 	usb_stor_dbg(us, "transport --- ENE_SDInit\n");
 	/* SD Init Part-1 */
@@ -2165,17 +2178,17 @@
 	bcb->Flags              = US_BULK_FLAG_IN;
 	bcb->CDB[0]             = 0xF1;
 
-	result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
+	result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
 	if (result != USB_STOR_XFER_GOOD) {
 		usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
-	info->SD_Status =  *(struct SD_STATUS *)&buf[0];
+	info->SD_Status =  *(struct SD_STATUS *) bbuf;
 	if (info->SD_Status.Insert && info->SD_Status.Ready) {
 		struct SD_STATUS *s = &info->SD_Status;
 
-		ene_get_card_status(us, (unsigned char *)&buf);
+		ene_get_card_status(us, bbuf);
 		usb_stor_dbg(us, "Insert     = %x\n", s->Insert);
 		usb_stor_dbg(us, "Ready      = %x\n", s->Ready);
 		usb_stor_dbg(us, "IsMMC      = %x\n", s->IsMMC);
@@ -2183,7 +2196,7 @@
 		usb_stor_dbg(us, "HiSpeed    = %x\n", s->HiSpeed);
 		usb_stor_dbg(us, "WtP        = %x\n", s->WtP);
 	} else {
-		usb_stor_dbg(us, "SD Card Not Ready --- %x\n", buf[0]);
+		usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]);
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 	return USB_STOR_TRANSPORT_GOOD;
@@ -2193,13 +2206,15 @@
 static int ene_init(struct us_data *us)
 {
 	int result;
-	u8  misc_reg03 = 0;
+	u8  misc_reg03;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+	u8 *bbuf = info->bbuf;
 
-	result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
+	result = ene_get_card_type(us, REG_CARD_STATUS, bbuf);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
+	misc_reg03 = bbuf[0];
 	if (misc_reg03 & 0x01) {
 		if (!info->SD_Status.Ready) {
 			result = ene_sd_init(us);
@@ -2293,21 +2308,22 @@
 
 static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-	int result = 0;
+	int result = USB_STOR_XFER_GOOD;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
 
 	/*US_DEBUG(usb_stor_show_command(us, srb)); */
 	scsi_set_resid(srb, 0);
-	if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) {
+	if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready)))
 		result = ene_init(us);
-	} else {
+	if (result == USB_STOR_XFER_GOOD) {
+		result = USB_STOR_TRANSPORT_ERROR;
 		if (info->SD_Status.Ready)
 			result = sd_scsi_irp(us, srb);
 
 		if (info->MS_Status.Ready)
 			result = ms_scsi_irp(us, srb);
 	}
-	return 0;
+	return result;
 }
 
 static struct scsi_host_template ene_ub6250_host_template;
@@ -2316,8 +2332,9 @@
 			 const struct usb_device_id *id)
 {
 	int result;
-	u8  misc_reg03 = 0;
+	u8  misc_reg03;
 	struct us_data *us;
+	struct ene_ub6250_info *info;
 
 	result = usb_stor_probe1(&us, intf, id,
 		   (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list,
@@ -2326,11 +2343,16 @@
 		return result;
 
 	/* FIXME: where should the code alloc extra buf ? */
-	if (!us->extra) {
-		us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
-		if (!us->extra)
-			return -ENOMEM;
-		us->extra_destructor = ene_ub6250_info_destructor;
+	us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
+	if (!us->extra)
+		return -ENOMEM;
+	us->extra_destructor = ene_ub6250_info_destructor;
+
+	info = (struct ene_ub6250_info *)(us->extra);
+	info->bbuf = kmalloc(512, GFP_KERNEL);
+	if (!info->bbuf) {
+		kfree(us->extra);
+		return -ENOMEM;
 	}
 
 	us->transport_name = "ene_ub6250";
@@ -2342,12 +2364,13 @@
 		return result;
 
 	/* probe card type */
-	result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
+	result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf);
 	if (result != USB_STOR_XFER_GOOD) {
 		usb_stor_disconnect(intf);
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
+	misc_reg03 = info->bbuf[0];
 	if (!(misc_reg03 & 0x01)) {
 		pr_info("ums_eneub6250: This driver only supports SD/MS cards. "
 			"It does not support SM cards.\n");
--- linux-4.4.0.orig/drivers/usb/storage/isd200.c
+++ linux-4.4.0/drivers/usb/storage/isd200.c
@@ -1520,8 +1520,11 @@
 
 	/* Make sure driver was initialized */
 
-	if (us->extra == NULL)
+	if (us->extra == NULL) {
 		usb_stor_dbg(us, "ERROR Driver not initialized\n");
+		srb->result = DID_ERROR << 16;
+		return;
+	}
 
 	scsi_set_resid(srb, 0);
 	/* scsi_bufflen might change in protocol translation to ata */
--- linux-4.4.0.orig/drivers/usb/storage/realtek_cr.c
+++ linux-4.4.0/drivers/usb/storage/realtek_cr.c
@@ -50,7 +50,7 @@
 
 static int auto_delink_en = 1;
 module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
+MODULE_PARM_DESC(auto_delink_en, "auto delink mode (0=firmware, 1=software [default])");
 
 #ifdef CONFIG_REALTEK_AUTOPM
 static int ss_en = 1;
@@ -772,18 +772,16 @@
 		break;
 	case RTS51X_STAT_IDLE:
 	case RTS51X_STAT_SS:
-		usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n",
-			     atomic_read(&us->pusb_intf->pm_usage_cnt),
+		usb_stor_dbg(us, "RTS51X_STAT_SS, power.usage:%d\n",
 			     atomic_read(&us->pusb_intf->dev.power.usage_count));
 
-		if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) {
+		if (atomic_read(&us->pusb_intf->dev.power.usage_count) > 0) {
 			usb_stor_dbg(us, "Ready to enter SS state\n");
 			rts51x_set_stat(chip, RTS51X_STAT_SS);
 			/* ignore mass storage interface's children */
 			pm_suspend_ignore_children(&us->pusb_intf->dev, true);
 			usb_autopm_put_interface_async(us->pusb_intf);
-			usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n",
-				     atomic_read(&us->pusb_intf->pm_usage_cnt),
+			usb_stor_dbg(us, "RTS51X_STAT_SS 01, power.usage:%d\n",
 				     atomic_read(&us->pusb_intf->dev.power.usage_count));
 		}
 		break;
@@ -816,11 +814,10 @@
 	int ret;
 
 	if (working_scsi(srb)) {
-		usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n",
-			     atomic_read(&us->pusb_intf->pm_usage_cnt),
+		usb_stor_dbg(us, "working scsi, power.usage:%d\n",
 			     atomic_read(&us->pusb_intf->dev.power.usage_count));
 
-		if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) {
+		if (atomic_read(&us->pusb_intf->dev.power.usage_count) <= 0) {
 			ret = usb_autopm_get_interface(us->pusb_intf);
 			usb_stor_dbg(us, "working scsi, ret=%d\n", ret);
 		}
@@ -1009,12 +1006,15 @@
 			goto INIT_FAIL;
 	}
 
-	if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) ||
-	    CHECK_FW_VER(chip, 0x5901))
-		SET_AUTO_DELINK(chip);
-	if (STATUS_LEN(chip) == 16) {
-		if (SUPPORT_AUTO_DELINK(chip))
+	if (CHECK_PID(chip, 0x0138) || CHECK_PID(chip, 0x0158) ||
+	    CHECK_PID(chip, 0x0159)) {
+		if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) ||
+				CHECK_FW_VER(chip, 0x5901))
 			SET_AUTO_DELINK(chip);
+		if (STATUS_LEN(chip) == 16) {
+			if (SUPPORT_AUTO_DELINK(chip))
+				SET_AUTO_DELINK(chip);
+		}
 	}
 #ifdef CONFIG_REALTEK_AUTOPM
 	if (ss_en)
--- linux-4.4.0.orig/drivers/usb/storage/scsiglue.c
+++ linux-4.4.0/drivers/usb/storage/scsiglue.c
@@ -223,8 +223,12 @@
 		if (!(us->fflags & US_FL_NEEDS_CAP16))
 			sdev->try_rc_10_first = 1;
 
-		/* assume SPC3 or latter devices support sense size > 18 */
-		if (sdev->scsi_level > SCSI_SPC_2)
+		/*
+		 * assume SPC3 or latter devices support sense size > 18
+		 * unless US_FL_BAD_SENSE quirk is specified.
+		 */
+		if (sdev->scsi_level > SCSI_SPC_2 &&
+		    !(us->fflags & US_FL_BAD_SENSE))
 			us->fflags |= US_FL_SANE_SENSE;
 
 		/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
@@ -340,6 +344,15 @@
 		done(srb);
 		return 0;
 	}
+
+	if ((us->fflags & US_FL_NO_ATA_1X) &&
+			(srb->cmnd[0] == ATA_12 || srb->cmnd[0] == ATA_16)) {
+		memcpy(srb->sense_buffer, usb_stor_sense_invalidCDB,
+		       sizeof(usb_stor_sense_invalidCDB));
+		srb->result = SAM_STAT_CHECK_CONDITION;
+		done(srb);
+		return 0;
+	}
 
 	/* enqueue the command and wake up the control thread */
 	srb->scsi_done = done;
--- linux-4.4.0.orig/drivers/usb/storage/transport.c
+++ linux-4.4.0/drivers/usb/storage/transport.c
@@ -808,12 +808,24 @@
 			if (result == USB_STOR_TRANSPORT_GOOD) {
 				srb->result = SAM_STAT_GOOD;
 				srb->sense_buffer[0] = 0x0;
+			}
+
+			/*
+			 * ATA-passthru commands use sense data to report
+			 * the command completion status, and often devices
+			 * return Check Condition status when nothing is
+			 * wrong.
+			 */
+			else if (srb->cmnd[0] == ATA_16 ||
+					srb->cmnd[0] == ATA_12) {
+				/* leave the data alone */
+			}
 
 			/* If there was a problem, report an unspecified
 			 * hardware error to prevent the higher layers from
 			 * entering an infinite retry loop.
 			 */
-			} else {
+			else {
 				srb->result = DID_ERROR << 16;
 				if ((sshdr.response_code & 0x72) == 0x72)
 					srb->sense_buffer[1] = HARDWARE_ERROR;
@@ -919,10 +931,15 @@
 
 	/* COMMAND STAGE */
 	/* let's send the command via the control pipe */
+	/*
+	 * Command is sometime (f.e. after scsi_eh_prep_cmnd) on the stack.
+	 * Stack may be vmallocated.  So no DMA for us.  Make a copy.
+	 */
+	memcpy(us->iobuf, srb->cmnd, srb->cmd_len);
 	result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
 				      US_CBI_ADSC, 
 				      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
-				      us->ifnum, srb->cmnd, srb->cmd_len);
+				      us->ifnum, us->iobuf, srb->cmd_len);
 
 	/* check the return code for the command */
 	usb_stor_dbg(us, "Call to usb_stor_ctrl_transfer() returned %d\n",
--- linux-4.4.0.orig/drivers/usb/storage/uas-detect.h
+++ linux-4.4.0/drivers/usb/storage/uas-detect.h
@@ -9,7 +9,8 @@
 		intf->desc.bInterfaceProtocol == USB_PR_UAS);
 }
 
-static int uas_find_uas_alt_setting(struct usb_interface *intf)
+static struct usb_host_interface *uas_find_uas_alt_setting(
+		struct usb_interface *intf)
 {
 	int i;
 
@@ -17,10 +18,10 @@
 		struct usb_host_interface *alt = &intf->altsetting[i];
 
 		if (uas_is_interface(alt))
-			return alt->desc.bAlternateSetting;
+			return alt;
 	}
 
-	return -ENODEV;
+	return NULL;
 }
 
 static int uas_find_endpoints(struct usb_host_interface *alt,
@@ -58,14 +59,14 @@
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
 	unsigned long flags = id->driver_info;
-	int r, alt;
-
+	struct usb_host_interface *alt;
+	int r;
 
 	alt = uas_find_uas_alt_setting(intf);
-	if (alt < 0)
+	if (!alt)
 		return 0;
 
-	r = uas_find_endpoints(&intf->altsetting[alt], eps);
+	r = uas_find_endpoints(alt, eps);
 	if (r < 0)
 		return 0;
 
@@ -110,6 +111,10 @@
 		}
 	}
 
+	/* All Seagate disk enclosures have broken ATA pass-through support */
+	if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bc2)
+		flags |= US_FL_NO_ATA_1X;
+
 	usb_stor_adjust_quirks(udev, &flags);
 
 	if (flags & US_FL_IGNORE_UAS) {
--- linux-4.4.0.orig/drivers/usb/storage/uas.c
+++ linux-4.4.0/drivers/usb/storage/uas.c
@@ -2,7 +2,7 @@
  * USB Attached SCSI
  * Note that this is not the same as the USB Mass Storage driver
  *
- * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2014
+ * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2016
  * Copyright Matthew Wilcox for Intel Corp, 2010
  * Copyright Sarah Sharp for Intel Corp, 2010
  *
@@ -46,6 +46,7 @@
 	struct scsi_cmnd *cmnd[MAX_CMNDS];
 	spinlock_t lock;
 	struct work_struct work;
+	struct work_struct scan_work;      /* for async scanning */
 };
 
 enum {
@@ -81,6 +82,19 @@
 static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix,
 				int status);
 
+/*
+ * This driver needs its own workqueue, as we need to control memory allocation.
+ *
+ * In the course of error handling and power management uas_wait_for_pending_cmnds()
+ * needs to flush pending work items. In these contexts we cannot allocate memory
+ * by doing block IO as we would deadlock. For the same reason we cannot wait
+ * for anything allocating memory not heeding these constraints.
+ *
+ * So we have to control all work items that can be on the workqueue we flush.
+ * Hence we cannot share a queue and need our own.
+ */
+static struct workqueue_struct *workqueue;
+
 static void uas_do_work(struct work_struct *work)
 {
 	struct uas_dev_info *devinfo =
@@ -109,12 +123,23 @@
 		if (!err)
 			cmdinfo->state &= ~IS_IN_WORK_LIST;
 		else
-			schedule_work(&devinfo->work);
+			queue_work(workqueue, &devinfo->work);
 	}
 out:
 	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
+static void uas_scan_work(struct work_struct *work)
+{
+	struct uas_dev_info *devinfo =
+		container_of(work, struct uas_dev_info, scan_work);
+	struct Scsi_Host *shost = usb_get_intfdata(devinfo->intf);
+
+	dev_dbg(&devinfo->intf->dev, "starting scan\n");
+	scsi_scan_host(shost);
+	dev_dbg(&devinfo->intf->dev, "scan complete\n");
+}
+
 static void uas_add_work(struct uas_cmd_info *cmdinfo)
 {
 	struct scsi_pointer *scp = (void *)cmdinfo;
@@ -123,7 +148,7 @@
 
 	lockdep_assert_held(&devinfo->lock);
 	cmdinfo->state |= IS_IN_WORK_LIST;
-	schedule_work(&devinfo->work);
+	queue_work(workqueue, &devinfo->work);
 }
 
 static void uas_zap_pending(struct uas_dev_info *devinfo, int result)
@@ -179,6 +204,9 @@
 	struct uas_cmd_info *ci = (void *)&cmnd->SCp;
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 
+	if (status == -ENODEV) /* too late */
+		return;
+
 	scmd_printk(KERN_INFO, cmnd,
 		    "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ",
 		    prefix, status, cmdinfo->uas_tag,
@@ -618,8 +646,7 @@
 	if (devinfo->resetting) {
 		cmnd->result = DID_ERROR << 16;
 		cmnd->scsi_done(cmnd);
-		spin_unlock_irqrestore(&devinfo->lock, flags);
-		return 0;
+		goto zombie;
 	}
 
 	/* Find a free uas-tag */
@@ -654,6 +681,16 @@
 		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
 
 	err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
+	/*
+	 * in case of fatal errors the SCSI layer is peculiar
+	 * a command that has finished is a success for the purpose
+	 * of queueing, no matter how fatal the error
+	 */
+	if (err == -ENODEV) {
+		cmnd->result = DID_ERROR << 16;
+		cmnd->scsi_done(cmnd);
+		goto zombie;
+	}
 	if (err) {
 		/* If we did nothing, give up now */
 		if (cmdinfo->state & SUBMIT_STATUS_URB) {
@@ -664,6 +701,7 @@
 	}
 
 	devinfo->cmnd[idx] = cmnd;
+zombie:
 	spin_unlock_irqrestore(&devinfo->lock, flags);
 	return 0;
 }
@@ -757,6 +795,17 @@
 	return SUCCESS;
 }
 
+static int uas_target_alloc(struct scsi_target *starget)
+{
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)
+			dev_to_shost(starget->dev.parent)->hostdata;
+
+	if (devinfo->flags & US_FL_NO_REPORT_LUNS)
+		starget->no_report_luns = 1;
+
+	return 0;
+}
+
 static int uas_slave_alloc(struct scsi_device *sdev)
 {
 	struct uas_dev_info *devinfo =
@@ -764,20 +813,10 @@
 
 	sdev->hostdata = devinfo;
 
-	/* USB has unusual DMA-alignment requirements: Although the
-	 * starting address of each scatter-gather element doesn't matter,
-	 * the length of each element except the last must be divisible
-	 * by the Bulk maxpacket value.  There's currently no way to
-	 * express this by block-layer constraints, so we'll cop out
-	 * and simply require addresses to be aligned at 512-byte
-	 * boundaries.  This is okay since most block I/O involves
-	 * hardware sectors that are multiples of 512 bytes in length,
-	 * and since host controllers up through USB 2.0 have maxpacket
-	 * values no larger than 512.
-	 *
-	 * But it doesn't suffice for Wireless USB, where Bulk maxpacket
-	 * values can be as large as 2048.  To make that work properly
-	 * will require changes to the block layer.
+	/*
+	 * The protocol has no requirements on alignment in the strict sense.
+	 * Controllers may or may not have alignment restrictions.
+	 * As this is not exported, we use an extremely conservative guess.
 	 */
 	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
 
@@ -808,11 +847,12 @@
 	.module = THIS_MODULE,
 	.name = "uas",
 	.queuecommand = uas_queuecommand,
+	.target_alloc = uas_target_alloc,
 	.slave_alloc = uas_slave_alloc,
 	.slave_configure = uas_slave_configure,
 	.eh_abort_handler = uas_eh_abort_handler,
 	.eh_bus_reset_handler = uas_eh_bus_reset_handler,
-	.can_queue = 65536,	/* Is there a limit on the _host_ ? */
+	.can_queue = MAX_CMNDS,
 	.this_id = -1,
 	.sg_tablesize = SG_NONE,
 	.skip_settle_delay = 1,
@@ -837,14 +877,14 @@
 static int uas_switch_interface(struct usb_device *udev,
 				struct usb_interface *intf)
 {
-	int alt;
+	struct usb_host_interface *alt;
 
 	alt = uas_find_uas_alt_setting(intf);
-	if (alt < 0)
-		return alt;
+	if (!alt)
+		return -ENODEV;
 
-	return usb_set_interface(udev,
-			intf->altsetting[0].desc.bInterfaceNumber, alt);
+	return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+			alt->desc.bAlternateSetting);
 }
 
 static int uas_configure_endpoints(struct uas_dev_info *devinfo)
@@ -927,17 +967,26 @@
 	init_usb_anchor(&devinfo->data_urbs);
 	spin_lock_init(&devinfo->lock);
 	INIT_WORK(&devinfo->work, uas_do_work);
+	INIT_WORK(&devinfo->scan_work, uas_scan_work);
 
 	result = uas_configure_endpoints(devinfo);
 	if (result)
 		goto set_alt0;
 
+	/*
+	 * 1 tag is reserved for untagged commands +
+	 * 1 tag to avoid off by one errors in some bridge firmwares
+	 */
+	shost->can_queue = devinfo->qdepth - 2;
+
 	usb_set_intfdata(intf, shost);
 	result = scsi_add_host(shost, &intf->dev);
 	if (result)
 		goto free_streams;
 
-	scsi_scan_host(shost);
+	/* Submit the delayed_work for SCSI-device scanning */
+	schedule_work(&devinfo->scan_work);
+
 	return result;
 
 free_streams:
@@ -1034,20 +1083,19 @@
 		return 0;
 
 	err = uas_configure_endpoints(devinfo);
-	if (err) {
+	if (err && err != -ENODEV)
 		shost_printk(KERN_ERR, shost,
 			     "%s: alloc streams error %d after reset",
 			     __func__, err);
-		return 1;
-	}
 
+	/* we must unblock the host in every case lest we deadlock */
 	spin_lock_irqsave(shost->host_lock, flags);
 	scsi_report_bus_reset(shost, 0);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	scsi_unblock_requests(shost);
 
-	return 0;
+	return err ? 1 : 0;
 }
 
 static int uas_suspend(struct usb_interface *intf, pm_message_t message)
@@ -1106,6 +1154,12 @@
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
 	uas_zap_pending(devinfo, DID_NO_CONNECT);
 
+	/*
+	 * Prevent SCSI scanning (if it hasn't started yet)
+	 * or wait for the SCSI-scanning routine to stop.
+	 */
+	cancel_work_sync(&devinfo->scan_work);
+
 	scsi_remove_host(shost);
 	uas_free_streams(devinfo);
 	scsi_host_put(shost);
@@ -1145,7 +1199,31 @@
 	.id_table = uas_usb_ids,
 };
 
-module_usb_driver(uas_driver);
+static int __init uas_init(void)
+{
+	int rv;
+
+	workqueue = alloc_workqueue("uas", WQ_MEM_RECLAIM, 0);
+	if (!workqueue)
+		return -ENOMEM;
+
+	rv = usb_register(&uas_driver);
+	if (rv) {
+		destroy_workqueue(workqueue);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void __exit uas_exit(void)
+{
+	usb_deregister(&uas_driver);
+	destroy_workqueue(workqueue);
+}
+
+module_init(uas_init);
+module_exit(uas_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR(
--- linux-4.4.0.orig/drivers/usb/storage/unusual_devs.h
+++ linux-4.4.0/drivers/usb/storage/unusual_devs.h
@@ -1206,6 +1206,12 @@
 		USB_SC_RBC, USB_PR_BULK, NULL,
 		0 ),
 
+UNUSUAL_DEV(0x090c, 0x1000, 0x1100, 0x1100,
+		"Samsung",
+		"Flash Drive FIT",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64),
+
 /* aeb */
 UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
 		"Feiya",
@@ -1262,6 +1268,13 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init,
 		0),
 
+/* Reported by Timo Aaltonen <tjaalton@ubuntu.com> */
+UNUSUAL_DEV( 0x0af0, 0x7011, 0x0000, 0x9999,
+		"Option",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init,
+		0 ),
+
 /* Reported by F. Aben <f.aben@option.com>
  * This device (wrongly) has a vendor-specific device descriptor.
  * The entry is needed so usb-storage can bind to it's mass-storage
@@ -1379,6 +1392,13 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
 		US_FL_SANE_SENSE ),
 
+/* Reported by Kris Lindgren <kris.lindgren@gmail.com> */
+UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999,
+		"Seagate",
+		"External",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT ),
+
 UNUSUAL_DEV(  0x0d49, 0x7310, 0x0000, 0x9999,
 		"Maxtor",
 		"USB to SATA",
@@ -1386,6 +1406,18 @@
 		US_FL_SANE_SENSE),
 
 /*
+ * Reported by Icenowy Zheng <icenowy@aosc.io>
+ * The SMI SM3350 USB-UFS bridge controller will enter a wrong state
+ * that do not process read/write command if a long sense is requested,
+ * so force to use 18-byte sense.
+ */
+UNUSUAL_DEV(  0x090c, 0x3350, 0x0000, 0xffff,
+		"SMI",
+		"SM3350 UFS-to-USB-Mass-Storage bridge",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BAD_SENSE ),
+
+/*
  * Pete Zaitcev <zaitcev@yahoo.com>, bz#164688.
  * The device blatantly ignores LUN and returns 1 in GetMaxLUN.
  */
@@ -1987,7 +2019,7 @@
 		US_FL_IGNORE_RESIDUE ),
 
 /* Reported by Michael Büsch <m@bues.ch> */
-UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0116,
+UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0117,
 		"JMicron",
 		"USB to ATA/ATAPI Bridge",
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
@@ -2135,6 +2167,27 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Teijo Kinnunen <teijo.kinnunen@code-q.fi> */
+UNUSUAL_DEV(  0x152d, 0x2567, 0x0117, 0x0117,
+		"JMicron",
+		"USB to ATA/ATAPI Bridge",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA ),
+
+/* Reported-by George Cherian <george.cherian@cavium.com> */
+UNUSUAL_DEV(0x152d, 0x9561, 0x0000, 0x9999,
+		"JMicron",
+		"JMS56x",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_OPCODES),
+
+/* Reported by David Kozub <zub@linux.fjfi.cvut.cz> */
+UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999,
+		"JMicron",
+		"JMS567",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA),
+
 /*
  * Patch by Constantin Baranov <const@tltsu.ru>
  * Report by Andreas Koenecke.
@@ -2162,6 +2215,13 @@
 		USB_SC_DEVICE,USB_PR_DEVICE,NULL,
 		US_FL_MAX_SECTORS_64 ),
 
+/* Reported by Cyril Roelandt <tipecaml@gmail.com> */
+UNUSUAL_DEV(  0x357d, 0x7788, 0x0114, 0x0114,
+		"JMicron",
+		"USB to ATA/ATAPI Bridge",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA | US_FL_IGNORE_UAS ),
+
 /* Reported by Andrey Rahmatullin <wrar@altlinux.org> */
 UNUSUAL_DEV(  0x4102, 0x1020, 0x0100,  0x0100,
 		"iRiver",
@@ -2185,6 +2245,13 @@
 		"Micro Mini 1GB",
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
 
+/* Reported-by: Tim Anderson <tsa@biglakesoftware.com> */
+UNUSUAL_DEV(  0x2ca3, 0x0031, 0x0000, 0x9999,
+		"DJI",
+		"CineSSD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_ATA_1X),
+
 /*
  * Nick Bowler <nbowler@elliptictech.com>
  * SCSI stack spams (otherwise harmless) error messages.
--- linux-4.4.0.orig/drivers/usb/storage/unusual_realtek.h
+++ linux-4.4.0/drivers/usb/storage/unusual_realtek.h
@@ -28,6 +28,11 @@
 		"USB Card Reader",
 		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
 
+UNUSUAL_DEV(0x0bda, 0x0153, 0x0000, 0x9999,
+		"Realtek",
+		"USB Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
 UNUSUAL_DEV(0x0bda, 0x0158, 0x0000, 0x9999,
 		"Realtek",
 		"USB Card Reader",
@@ -37,5 +42,15 @@
 		"Realtek",
 		"USB Card Reader",
 		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+UNUSUAL_DEV(0x0bda, 0x0177, 0x0000, 0x9999,
+		"Realtek",
+		"USB Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+UNUSUAL_DEV(0x0bda, 0x0184, 0x0000, 0x9999,
+		"Realtek",
+		"USB Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
 
 #endif  /* defined(CONFIG_USB_STORAGE_REALTEK) || ... */
--- linux-4.4.0.orig/drivers/usb/storage/unusual_uas.h
+++ linux-4.4.0/drivers/usb/storage/unusual_uas.h
@@ -40,6 +40,20 @@
  * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org>
  */
 
+/* Reported-by: Till Dörges <doerges@pre-sense.de> */
+UNUSUAL_DEV(0x054c, 0x087d, 0x0000, 0x9999,
+		"Sony",
+		"PSZ-HA*",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_OPCODES),
+
+/* Reported-by: Julian Groß <julian.g@posteo.de> */
+UNUSUAL_DEV(0x059f, 0x105f, 0x0000, 0x9999,
+		"LaCie",
+		"2Big Quadra USB3",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_OPCODES),
+
 /*
  * Apricorn USB3 dongle sometimes returns "USBSUSBSUSBS" in response to SCSI
  * commands in UAS mode.  Observed with the 1.28 firmware; are there others?
@@ -64,6 +78,13 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
 		US_FL_NO_ATA_1X),
 
+/* Reported-by: David Webb <djw@noc.ac.uk> */
+UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
+		"Seagate",
+		"Expansion Desk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_LUNS),
+
 /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
 UNUSUAL_DEV(0x0bc2, 0x3320, 0x0000, 0x9999,
 		"Seagate",
@@ -116,9 +137,9 @@
 /* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
 UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
 		"Initio Corporation",
-		"",
+		"INIC-3069",
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
-		US_FL_NO_ATA_1X),
+		US_FL_NO_ATA_1X | US_FL_IGNORE_RESIDUE),
 
 /* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
 UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
@@ -134,6 +155,27 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
 		US_FL_BROKEN_FUA | US_FL_NO_REPORT_OPCODES),
 
+/* Reported-by: David Kozub <zub@linux.fjfi.cvut.cz> */
+UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999,
+		"JMicron",
+		"JMS567",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA),
+
+/* Reported-by: Thinh Nguyen <thinhn@synopsys.com> */
+UNUSUAL_DEV(0x154b, 0xf00b, 0x0000, 0x9999,
+		"PNY",
+		"Pro Elite SSD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_ATA_1X),
+
+/* Reported-by: Thinh Nguyen <thinhn@synopsys.com> */
+UNUSUAL_DEV(0x154b, 0xf00d, 0x0000, 0x9999,
+		"PNY",
+		"Pro Elite SSD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_ATA_1X),
+
 /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
 UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
 		"VIA",
@@ -141,12 +183,22 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
 		US_FL_NO_ATA_1X),
 
-/* Reported-by: Takeo Nakayama <javhera@gmx.com> */
+/* Reported-by: Icenowy Zheng <icenowy@aosc.io> */
+UNUSUAL_DEV(0x2537, 0x1068, 0x0000, 0x9999,
+		"Norelsys",
+		"NS1068X",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_UAS),
+
+/*
+ * Initially Reported-by: Takeo Nakayama <javhera@gmx.com>
+ * UAS Ignore Reported by Steven Ellis <sellis@redhat.com>
+ */
 UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999,
 		"JMicron",
 		"JMS566",
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
-		US_FL_NO_REPORT_OPCODES),
+		US_FL_NO_REPORT_OPCODES | US_FL_IGNORE_UAS),
 
 /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
 UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999,
--- linux-4.4.0.orig/drivers/usb/storage/usb.c
+++ linux-4.4.0/drivers/usb/storage/usb.c
@@ -482,7 +482,7 @@
 			US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
 			US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
 			US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES |
-			US_FL_MAX_SECTORS_240);
+			US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS);
 
 	p = quirks;
 	while (*p) {
@@ -532,6 +532,9 @@
 		case 'i':
 			f |= US_FL_IGNORE_DEVICE;
 			break;
+		case 'j':
+			f |= US_FL_NO_REPORT_LUNS;
+			break;
 		case 'l':
 			f |= US_FL_NOT_LOCKABLE;
 			break;
--- linux-4.4.0.orig/drivers/usb/usb-skeleton.c
+++ linux-4.4.0/drivers/usb/usb-skeleton.c
@@ -63,6 +63,7 @@
 	spinlock_t		err_lock;		/* lock for errors */
 	struct kref		kref;
 	struct mutex		io_mutex;		/* synchronize I/O with disconnect */
+	unsigned long		disconnected:1;
 	wait_queue_head_t	bulk_in_wait;		/* to wait for an ongoing read */
 };
 #define to_skel_dev(d) container_of(d, struct usb_skel, kref)
@@ -75,6 +76,7 @@
 	struct usb_skel *dev = to_skel_dev(kref);
 
 	usb_free_urb(dev->bulk_in_urb);
+	usb_put_intf(dev->interface);
 	usb_put_dev(dev->udev);
 	kfree(dev->bulk_in_buffer);
 	kfree(dev);
@@ -126,10 +128,7 @@
 		return -ENODEV;
 
 	/* allow the device to be autosuspended */
-	mutex_lock(&dev->io_mutex);
-	if (dev->interface)
-		usb_autopm_put_interface(dev->interface);
-	mutex_unlock(&dev->io_mutex);
+	usb_autopm_put_interface(dev->interface);
 
 	/* decrement the count on our device */
 	kref_put(&dev->kref, skel_delete);
@@ -241,7 +240,7 @@
 	if (rv < 0)
 		return rv;
 
-	if (!dev->interface) {		/* disconnect() was called */
+	if (dev->disconnected) {		/* disconnect() was called */
 		rv = -ENODEV;
 		goto exit;
 	}
@@ -422,7 +421,7 @@
 
 	/* this lock makes sure we don't submit URBs to gone devices */
 	mutex_lock(&dev->io_mutex);
-	if (!dev->interface) {		/* disconnect() was called */
+	if (dev->disconnected) {		/* disconnect() was called */
 		mutex_unlock(&dev->io_mutex);
 		retval = -ENODEV;
 		goto error;
@@ -511,7 +510,7 @@
 	init_waitqueue_head(&dev->bulk_in_wait);
 
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
-	dev->interface = interface;
+	dev->interface = usb_get_intf(interface);
 
 	/* set up the endpoint information */
 	/* use only the first bulk-in and bulk-out endpoints */
@@ -590,7 +589,7 @@
 
 	/* prevent more I/O from starting */
 	mutex_lock(&dev->io_mutex);
-	dev->interface = NULL;
+	dev->disconnected = 1;
 	mutex_unlock(&dev->io_mutex);
 
 	usb_kill_anchored_urbs(&dev->submitted);
--- linux-4.4.0.orig/drivers/usb/usbip/stub.h
+++ linux-4.4.0/drivers/usb/usbip/stub.h
@@ -88,6 +88,7 @@
 	struct stub_device *sdev;
 	struct usb_device *udev;
 	char shutdown_busid;
+	spinlock_t busid_lock;
 };
 
 /* stub_priv is allocated from stub_priv_cache */
@@ -98,6 +99,7 @@
 
 /* stub_main.c */
 struct bus_id_priv *get_busid_priv(const char *busid);
+void put_busid_priv(struct bus_id_priv *bid);
 int del_match_busid(char *busid);
 void stub_device_cleanup_urbs(struct stub_device *sdev);
 
--- linux-4.4.0.orig/drivers/usb/usbip/stub_dev.c
+++ linux-4.4.0/drivers/usb/usbip/stub_dev.c
@@ -60,6 +60,8 @@
 	int sockfd = 0;
 	struct socket *socket;
 	int rv;
+	struct task_struct *tcp_rx = NULL;
+	struct task_struct *tcp_tx = NULL;
 
 	if (!sdev) {
 		dev_err(dev, "sdev is null\n");
@@ -83,22 +85,47 @@
 		}
 
 		socket = sockfd_lookup(sockfd, &err);
-		if (!socket)
+		if (!socket) {
+			dev_err(dev, "failed to lookup sock");
 			goto err;
+		}
 
-		sdev->ud.tcp_socket = socket;
+		if (socket->type != SOCK_STREAM) {
+			dev_err(dev, "Expecting SOCK_STREAM - found %d",
+				socket->type);
+			goto sock_err;
+		}
 
+		/* unlock and create threads and get tasks */
 		spin_unlock_irq(&sdev->ud.lock);
+		tcp_rx = kthread_create(stub_rx_loop, &sdev->ud, "stub_rx");
+		if (IS_ERR(tcp_rx)) {
+			sockfd_put(socket);
+			return -EINVAL;
+		}
+		tcp_tx = kthread_create(stub_tx_loop, &sdev->ud, "stub_tx");
+		if (IS_ERR(tcp_tx)) {
+			kthread_stop(tcp_rx);
+			sockfd_put(socket);
+			return -EINVAL;
+		}
 
-		sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud,
-						  "stub_rx");
-		sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud,
-						  "stub_tx");
+		/* get task structs now */
+		get_task_struct(tcp_rx);
+		get_task_struct(tcp_tx);
 
+		/* lock and update sdev->ud state */
 		spin_lock_irq(&sdev->ud.lock);
+		sdev->ud.tcp_socket = socket;
+		sdev->ud.sockfd = sockfd;
+		sdev->ud.tcp_rx = tcp_rx;
+		sdev->ud.tcp_tx = tcp_tx;
 		sdev->ud.status = SDEV_ST_USED;
 		spin_unlock_irq(&sdev->ud.lock);
 
+		wake_up_process(sdev->ud.tcp_rx);
+		wake_up_process(sdev->ud.tcp_tx);
+
 	} else {
 		dev_info(dev, "stub down\n");
 
@@ -113,6 +140,8 @@
 
 	return count;
 
+sock_err:
+	sockfd_put(socket);
 err:
 	spin_unlock_irq(&sdev->ud.lock);
 	return -EINVAL;
@@ -163,8 +192,7 @@
 	 * step 1?
 	 */
 	if (ud->tcp_socket) {
-		dev_dbg(&sdev->udev->dev, "shutdown tcp_socket %p\n",
-			ud->tcp_socket);
+		dev_dbg(&sdev->udev->dev, "shutdown sockfd %d\n", ud->sockfd);
 		kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
 	}
 
@@ -187,6 +215,7 @@
 	if (ud->tcp_socket) {
 		sockfd_put(ud->tcp_socket);
 		ud->tcp_socket = NULL;
+		ud->sockfd = -1;
 	}
 
 	/* 3. free used data */
@@ -281,6 +310,7 @@
 	sdev->ud.status		= SDEV_ST_AVAILABLE;
 	spin_lock_init(&sdev->ud.lock);
 	sdev->ud.tcp_socket	= NULL;
+	sdev->ud.sockfd		= -1;
 
 	INIT_LIST_HEAD(&sdev->priv_init);
 	INIT_LIST_HEAD(&sdev->priv_tx);
@@ -312,9 +342,9 @@
 	struct stub_device *sdev = NULL;
 	const char *udev_busid = dev_name(&udev->dev);
 	struct bus_id_priv *busid_priv;
-	int rc;
+	int rc = 0;
 
-	dev_dbg(&udev->dev, "Enter\n");
+	dev_dbg(&udev->dev, "Enter probe\n");
 
 	/* check we should claim or not by busid_table */
 	busid_priv = get_busid_priv(udev_busid);
@@ -329,13 +359,15 @@
 		 * other matched drivers by the driver core.
 		 * See driver_probe_device() in driver/base/dd.c
 		 */
-		return -ENODEV;
+		rc = -ENODEV;
+		goto call_put_busid_priv;
 	}
 
 	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) {
 		dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n",
 			 udev_busid);
-		return -ENODEV;
+		rc = -ENODEV;
+		goto call_put_busid_priv;
 	}
 
 	if (!strcmp(udev->bus->bus_name, "vhci_hcd")) {
@@ -343,13 +375,16 @@
 			"%s is attached on vhci_hcd... skip!\n",
 			udev_busid);
 
-		return -ENODEV;
+		rc = -ENODEV;
+		goto call_put_busid_priv;
 	}
 
 	/* ok, this is my device */
 	sdev = stub_device_alloc(udev);
-	if (!sdev)
-		return -ENOMEM;
+	if (!sdev) {
+		rc = -ENOMEM;
+		goto call_put_busid_priv;
+	}
 
 	dev_info(&udev->dev,
 		"usbip-host: register new device (bus %u dev %u)\n",
@@ -381,7 +416,9 @@
 	}
 	busid_priv->status = STUB_BUSID_ALLOC;
 
-	return 0;
+	rc = 0;
+	goto call_put_busid_priv;
+
 err_files:
 	usb_hub_release_port(udev->parent, udev->portnum,
 			     (struct usb_dev_state *) udev);
@@ -392,6 +429,9 @@
 
 	busid_priv->sdev = NULL;
 	stub_device_free(sdev);
+
+call_put_busid_priv:
+	put_busid_priv(busid_priv);
 	return rc;
 }
 
@@ -417,7 +457,7 @@
 	struct bus_id_priv *busid_priv;
 	int rc;
 
-	dev_dbg(&udev->dev, "Enter\n");
+	dev_dbg(&udev->dev, "Enter disconnect\n");
 
 	busid_priv = get_busid_priv(udev_busid);
 	if (!busid_priv) {
@@ -430,7 +470,7 @@
 	/* get stub_device */
 	if (!sdev) {
 		dev_err(&udev->dev, "could not get device");
-		return;
+		goto call_put_busid_priv;
 	}
 
 	dev_set_drvdata(&udev->dev, NULL);
@@ -445,12 +485,12 @@
 				  (struct usb_dev_state *) udev);
 	if (rc) {
 		dev_dbg(&udev->dev, "unable to release port\n");
-		return;
+		goto call_put_busid_priv;
 	}
 
 	/* If usb reset is called from event handler */
 	if (busid_priv->sdev->ud.eh == current)
-		return;
+		goto call_put_busid_priv;
 
 	/* shutdown the current connection */
 	shutdown_busid(busid_priv);
@@ -461,12 +501,11 @@
 	busid_priv->sdev = NULL;
 	stub_device_free(sdev);
 
-	if (busid_priv->status == STUB_BUSID_ALLOC) {
+	if (busid_priv->status == STUB_BUSID_ALLOC)
 		busid_priv->status = STUB_BUSID_ADDED;
-	} else {
-		busid_priv->status = STUB_BUSID_OTHER;
-		del_match_busid((char *)udev_busid);
-	}
+
+call_put_busid_priv:
+	put_busid_priv(busid_priv);
 }
 
 #ifdef CONFIG_PM
--- linux-4.4.0.orig/drivers/usb/usbip/stub_main.c
+++ linux-4.4.0/drivers/usb/usbip/stub_main.c
@@ -28,6 +28,7 @@
 #define DRIVER_DESC "USB/IP Host Driver"
 
 struct kmem_cache *stub_priv_cache;
+
 /*
  * busid_tables defines matching busids that usbip can grab. A user can change
  * dynamically what device is locally used and what device is exported to a
@@ -39,6 +40,8 @@
 
 static void init_busid_table(void)
 {
+	int i;
+
 	/*
 	 * This also sets the bus_table[i].status to
 	 * STUB_BUSID_OTHER, which is 0.
@@ -46,6 +49,9 @@
 	memset(busid_table, 0, sizeof(busid_table));
 
 	spin_lock_init(&busid_table_lock);
+
+	for (i = 0; i < MAX_BUSID; i++)
+		spin_lock_init(&busid_table[i].busid_lock);
 }
 
 /*
@@ -57,15 +63,20 @@
 	int i;
 	int idx = -1;
 
-	for (i = 0; i < MAX_BUSID; i++)
+	for (i = 0; i < MAX_BUSID; i++) {
+		spin_lock(&busid_table[i].busid_lock);
 		if (busid_table[i].name[0])
 			if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
 				idx = i;
+				spin_unlock(&busid_table[i].busid_lock);
 				break;
 			}
+		spin_unlock(&busid_table[i].busid_lock);
+	}
 	return idx;
 }
 
+/* Returns holding busid_lock. Should call put_busid_priv() to unlock */
 struct bus_id_priv *get_busid_priv(const char *busid)
 {
 	int idx;
@@ -73,13 +84,22 @@
 
 	spin_lock(&busid_table_lock);
 	idx = get_busid_idx(busid);
-	if (idx >= 0)
+	if (idx >= 0) {
 		bid = &(busid_table[idx]);
+		/* get busid_lock before returning */
+		spin_lock(&bid->busid_lock);
+	}
 	spin_unlock(&busid_table_lock);
 
 	return bid;
 }
 
+void put_busid_priv(struct bus_id_priv *bid)
+{
+	if (bid)
+		spin_unlock(&bid->busid_lock);
+}
+
 static int add_match_busid(char *busid)
 {
 	int i;
@@ -92,15 +112,19 @@
 		goto out;
 	}
 
-	for (i = 0; i < MAX_BUSID; i++)
+	for (i = 0; i < MAX_BUSID; i++) {
+		spin_lock(&busid_table[i].busid_lock);
 		if (!busid_table[i].name[0]) {
 			strlcpy(busid_table[i].name, busid, BUSID_SIZE);
 			if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
 			    (busid_table[i].status != STUB_BUSID_REMOV))
 				busid_table[i].status = STUB_BUSID_ADDED;
 			ret = 0;
+			spin_unlock(&busid_table[i].busid_lock);
 			break;
 		}
+		spin_unlock(&busid_table[i].busid_lock);
+	}
 
 out:
 	spin_unlock(&busid_table_lock);
@@ -121,6 +145,8 @@
 	/* found */
 	ret = 0;
 
+	spin_lock(&busid_table[idx].busid_lock);
+
 	if (busid_table[idx].status == STUB_BUSID_OTHER)
 		memset(busid_table[idx].name, 0, BUSID_SIZE);
 
@@ -128,6 +154,7 @@
 	    (busid_table[idx].status != STUB_BUSID_ADDED))
 		busid_table[idx].status = STUB_BUSID_REMOV;
 
+	spin_unlock(&busid_table[idx].busid_lock);
 out:
 	spin_unlock(&busid_table_lock);
 
@@ -140,9 +167,12 @@
 	char *out = buf;
 
 	spin_lock(&busid_table_lock);
-	for (i = 0; i < MAX_BUSID; i++)
+	for (i = 0; i < MAX_BUSID; i++) {
+		spin_lock(&busid_table[i].busid_lock);
 		if (busid_table[i].name[0])
 			out += sprintf(out, "%s ", busid_table[i].name);
+		spin_unlock(&busid_table[i].busid_lock);
+	}
 	spin_unlock(&busid_table_lock);
 	out += sprintf(out, "\n");
 
@@ -184,6 +214,51 @@
 static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
 		   store_match_busid);
 
+static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
+{
+	int ret;
+
+	/* device_attach() callers should hold parent lock for USB */
+	if (busid_priv->udev->dev.parent)
+		device_lock(busid_priv->udev->dev.parent);
+	ret = device_attach(&busid_priv->udev->dev);
+	if (busid_priv->udev->dev.parent)
+		device_unlock(busid_priv->udev->dev.parent);
+	if (ret < 0) {
+		dev_err(&busid_priv->udev->dev, "rebind failed\n");
+		return ret;
+	}
+	return 0;
+}
+
+static void stub_device_rebind(void)
+{
+#if IS_MODULE(CONFIG_USBIP_HOST)
+	struct bus_id_priv *busid_priv;
+	int i;
+
+	/* update status to STUB_BUSID_OTHER so probe ignores the device */
+	spin_lock(&busid_table_lock);
+	for (i = 0; i < MAX_BUSID; i++) {
+		if (busid_table[i].name[0] &&
+		    busid_table[i].shutdown_busid) {
+			busid_priv = &(busid_table[i]);
+			busid_priv->status = STUB_BUSID_OTHER;
+		}
+	}
+	spin_unlock(&busid_table_lock);
+
+	/* now run rebind - no need to hold locks. driver files are removed */
+	for (i = 0; i < MAX_BUSID; i++) {
+		if (busid_table[i].name[0] &&
+		    busid_table[i].shutdown_busid) {
+			busid_priv = &(busid_table[i]);
+			do_rebind(busid_table[i].name, busid_priv);
+		}
+	}
+#endif
+}
+
 static ssize_t rebind_store(struct device_driver *dev, const char *buf,
 				 size_t count)
 {
@@ -201,11 +276,17 @@
 	if (!bid)
 		return -ENODEV;
 
-	ret = device_attach(&bid->udev->dev);
-	if (ret < 0) {
-		dev_err(&bid->udev->dev, "rebind failed\n");
+	/* mark the device for deletion so probe ignores it during rescan */
+	bid->status = STUB_BUSID_OTHER;
+	/* release the busid lock */
+	put_busid_priv(bid);
+
+	ret = do_rebind((char *) buf, bid);
+	if (ret < 0)
 		return ret;
-	}
+
+	/* delete device from busid_table */
+	del_match_busid((char *) buf);
 
 	return count;
 }
@@ -252,17 +333,22 @@
 	struct stub_priv *priv;
 	struct urb *urb;
 
-	dev_dbg(&sdev->udev->dev, "free sdev %p\n", sdev);
+	dev_dbg(&sdev->udev->dev, "Stub device cleaning up urbs\n");
 
 	while ((priv = stub_priv_pop(sdev))) {
 		urb = priv->urb;
-		dev_dbg(&sdev->udev->dev, "free urb %p\n", urb);
+		dev_dbg(&sdev->udev->dev, "free urb seqnum %lu\n",
+			priv->seqnum);
 		usb_kill_urb(urb);
 
 		kmem_cache_free(stub_priv_cache, priv);
 
 		kfree(urb->transfer_buffer);
+		urb->transfer_buffer = NULL;
+
 		kfree(urb->setup_packet);
+		urb->setup_packet = NULL;
+
 		usb_free_urb(urb);
 	}
 }
@@ -323,6 +409,9 @@
 	 */
 	usb_deregister_device_driver(&stub_driver);
 
+	/* initiate scan to attach devices */
+	stub_device_rebind();
+
 	kmem_cache_destroy(stub_priv_cache);
 }
 
--- linux-4.4.0.orig/drivers/usb/usbip/stub_rx.c
+++ linux-4.4.0/drivers/usb/usbip/stub_rx.c
@@ -230,9 +230,6 @@
 		if (priv->seqnum != pdu->u.cmd_unlink.seqnum)
 			continue;
 
-		dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
-			 priv->urb);
-
 		/*
 		 * This matched urb is not completed yet (i.e., be in
 		 * flight in usb hcd hardware/driver). Now we are
@@ -271,8 +268,8 @@
 		ret = usb_unlink_urb(priv->urb);
 		if (ret != -EINPROGRESS)
 			dev_err(&priv->urb->dev->dev,
-				"failed to unlink a urb %p, ret %d\n",
-				priv->urb, ret);
+				"failed to unlink a urb # %lu, ret %d\n",
+				priv->seqnum, ret);
 
 		return 0;
 	}
@@ -341,23 +338,26 @@
 	return priv;
 }
 
-static int get_pipe(struct stub_device *sdev, int epnum, int dir)
+static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu)
 {
 	struct usb_device *udev = sdev->udev;
 	struct usb_host_endpoint *ep;
 	struct usb_endpoint_descriptor *epd = NULL;
+	int epnum = pdu->base.ep;
+	int dir = pdu->base.direction;
+
+	if (epnum < 0 || epnum > 15)
+		goto err_ret;
 
 	if (dir == USBIP_DIR_IN)
 		ep = udev->ep_in[epnum & 0x7f];
 	else
 		ep = udev->ep_out[epnum & 0x7f];
-	if (!ep) {
-		dev_err(&sdev->interface->dev, "no such endpoint?, %d\n",
-			epnum);
-		BUG();
-	}
+	if (!ep)
+		goto err_ret;
 
 	epd = &ep->desc;
+
 	if (usb_endpoint_xfer_control(epd)) {
 		if (dir == USBIP_DIR_OUT)
 			return usb_sndctrlpipe(udev, epnum);
@@ -380,15 +380,25 @@
 	}
 
 	if (usb_endpoint_xfer_isoc(epd)) {
+		/* validate number of packets */
+		if (pdu->u.cmd_submit.number_of_packets < 0 ||
+		    pdu->u.cmd_submit.number_of_packets >
+		    USBIP_MAX_ISO_PACKETS) {
+			dev_err(&sdev->udev->dev,
+				"CMD_SUBMIT: isoc invalid num packets %d\n",
+				pdu->u.cmd_submit.number_of_packets);
+			return -1;
+		}
 		if (dir == USBIP_DIR_OUT)
 			return usb_sndisocpipe(udev, epnum);
 		else
 			return usb_rcvisocpipe(udev, epnum);
 	}
 
+err_ret:
 	/* NOT REACHED */
-	dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum);
-	return 0;
+	dev_err(&sdev->udev->dev, "CMD_SUBMIT: invalid epnum %d\n", epnum);
+	return -1;
 }
 
 static void masking_bogus_flags(struct urb *urb)
@@ -452,7 +462,10 @@
 	struct stub_priv *priv;
 	struct usbip_device *ud = &sdev->ud;
 	struct usb_device *udev = sdev->udev;
-	int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
+	int pipe = get_pipe(sdev, pdu);
+
+	if (pipe == -1)
+		return;
 
 	priv = stub_priv_alloc(sdev, pdu);
 	if (!priv)
--- linux-4.4.0.orig/drivers/usb/usbip/stub_tx.c
+++ linux-4.4.0/drivers/usb/usbip/stub_tx.c
@@ -28,7 +28,11 @@
 	struct urb *urb = priv->urb;
 
 	kfree(urb->setup_packet);
+	urb->setup_packet = NULL;
+
 	kfree(urb->transfer_buffer);
+	urb->transfer_buffer = NULL;
+
 	list_del(&priv->list);
 	kmem_cache_free(stub_priv_cache, priv);
 	usb_free_urb(urb);
@@ -174,6 +178,13 @@
 		memset(&pdu_header, 0, sizeof(pdu_header));
 		memset(&msg, 0, sizeof(msg));
 
+		if (urb->actual_length > 0 && !urb->transfer_buffer) {
+			dev_err(&sdev->udev->dev,
+				"urb: actual_length %d transfer_buffer null\n",
+				urb->actual_length);
+			return -1;
+		}
+
 		if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
 			iovnum = 2 + urb->number_of_packets;
 		else
@@ -190,8 +201,8 @@
 
 		/* 1. setup usbip_header */
 		setup_ret_submit_pdu(&pdu_header, urb);
-		usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n",
-				  pdu_header.base.seqnum, urb);
+		usbip_dbg_stub_tx("setup txdata seqnum: %d\n",
+				  pdu_header.base.seqnum);
 		usbip_header_correct_endian(&pdu_header, 1);
 
 		iov[iovnum].iov_base = &pdu_header;
--- linux-4.4.0.orig/drivers/usb/usbip/usbip_common.c
+++ linux-4.4.0/drivers/usb/usbip/usbip_common.c
@@ -103,7 +103,7 @@
 	dev_dbg(dev, "       devnum(%d) devpath(%s) usb speed(%s)",
 		udev->devnum, udev->devpath, usb_speed_string(udev->speed));
 
-	pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport);
+	pr_debug("tt hub ttport %d\n", udev->ttport);
 
 	dev_dbg(dev, "                    ");
 	for (i = 0; i < 16; i++)
@@ -136,12 +136,8 @@
 	}
 	pr_debug("\n");
 
-	dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus);
-
-	dev_dbg(dev,
-		"descriptor %p, config %p, actconfig %p, rawdescriptors %p\n",
-		&udev->descriptor, udev->config,
-		udev->actconfig, udev->rawdescriptors);
+	dev_dbg(dev, "parent %s, bus %s\n", dev_name(&udev->parent->dev),
+		udev->bus->bus_name);
 
 	dev_dbg(dev, "have_langid %d, string_langid %d\n",
 		udev->have_langid, udev->string_langid);
@@ -249,9 +245,6 @@
 
 	dev = &urb->dev->dev;
 
-	dev_dbg(dev, "   urb                   :%p\n", urb);
-	dev_dbg(dev, "   dev                   :%p\n", urb->dev);
-
 	usbip_dump_usb_device(urb->dev);
 
 	dev_dbg(dev, "   pipe                  :%08x ", urb->pipe);
@@ -260,11 +253,9 @@
 
 	dev_dbg(dev, "   status                :%d\n", urb->status);
 	dev_dbg(dev, "   transfer_flags        :%08X\n", urb->transfer_flags);
-	dev_dbg(dev, "   transfer_buffer       :%p\n", urb->transfer_buffer);
 	dev_dbg(dev, "   transfer_buffer_length:%d\n",
 						urb->transfer_buffer_length);
 	dev_dbg(dev, "   actual_length         :%d\n", urb->actual_length);
-	dev_dbg(dev, "   setup_packet          :%p\n", urb->setup_packet);
 
 	if (urb->setup_packet && usb_pipetype(urb->pipe) == PIPE_CONTROL)
 		usbip_dump_usb_ctrlrequest(
@@ -274,8 +265,6 @@
 	dev_dbg(dev, "   number_of_packets     :%d\n", urb->number_of_packets);
 	dev_dbg(dev, "   interval              :%d\n", urb->interval);
 	dev_dbg(dev, "   error_count           :%d\n", urb->error_count);
-	dev_dbg(dev, "   context               :%p\n", urb->context);
-	dev_dbg(dev, "   complete              :%p\n", urb->complete);
 }
 EXPORT_SYMBOL_GPL(usbip_dump_urb);
 
@@ -328,18 +317,14 @@
 	struct msghdr msg;
 	struct kvec iov;
 	int total = 0;
-
 	/* for blocks of if (usbip_dbg_flag_xmit) */
 	char *bp = buf;
 	int osize = size;
 
-	usbip_dbg_xmit("enter\n");
-
-	if (!sock || !buf || !size) {
-		pr_err("invalid arg, sock %p buff %p size %d\n", sock, buf,
-		       size);
+	if (!sock || !buf || !size)
 		return -EINVAL;
-	}
+
+	usbip_dbg_xmit("enter\n");
 
 	do {
 		sock->sk->sk_allocation = GFP_NOIO;
@@ -352,11 +337,8 @@
 		msg.msg_flags      = MSG_NOSIGNAL;
 
 		result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL);
-		if (result <= 0) {
-			pr_debug("receive sock %p buf %p size %u ret %d total %d\n",
-				 sock, buf, size, result, total);
+		if (result <= 0)
 			goto err;
-		}
 
 		size -= result;
 		buf += result;
@@ -741,6 +723,17 @@
 	if (!(size > 0))
 		return 0;
 
+	if (size > urb->transfer_buffer_length) {
+		/* should not happen, probably malicious packet */
+		if (ud->side == USBIP_STUB) {
+			usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+			return 0;
+		} else {
+			usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+			return -EPIPE;
+		}
+	}
+
 	ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
 	if (ret != size) {
 		dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
--- linux-4.4.0.orig/drivers/usb/usbip/usbip_common.h
+++ linux-4.4.0/drivers/usb/usbip/usbip_common.h
@@ -134,6 +134,13 @@
 #define USBIP_DIR_OUT	0x00
 #define USBIP_DIR_IN	0x01
 
+/*
+ * Arbitrary limit for the maximum number of isochronous packets in an URB,
+ * compare for example the uhci_submit_isochronous function in
+ * drivers/usb/host/uhci-q.c
+ */
+#define USBIP_MAX_ISO_PACKETS 1024
+
 /**
  * struct usbip_header_basic - data pertinent to every request
  * @command: the usbip request type
@@ -248,7 +255,7 @@
 #define	SDEV_EVENT_ERROR_SUBMIT	(USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
 #define	SDEV_EVENT_ERROR_MALLOC	(USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
 
-#define	VDEV_EVENT_REMOVED	(USBIP_EH_SHUTDOWN | USBIP_EH_BYE)
+#define	VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE)
 #define	VDEV_EVENT_DOWN		(USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
 #define	VDEV_EVENT_ERROR_TCP	(USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
 #define	VDEV_EVENT_ERROR_MALLOC	(USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
@@ -261,6 +268,7 @@
 	/* lock for status */
 	spinlock_t lock;
 
+	int sockfd;
 	struct socket *tcp_socket;
 
 	struct task_struct *tcp_rx;
--- linux-4.4.0.orig/drivers/usb/usbip/usbip_event.c
+++ linux-4.4.0/drivers/usb/usbip/usbip_event.c
@@ -117,11 +117,12 @@
 int usbip_event_happened(struct usbip_device *ud)
 {
 	int happened = 0;
+	unsigned long flags;
 
-	spin_lock(&ud->lock);
+	spin_lock_irqsave(&ud->lock, flags);
 	if (ud->event != 0)
 		happened = 1;
-	spin_unlock(&ud->lock);
+	spin_unlock_irqrestore(&ud->lock, flags);
 
 	return happened;
 }
--- linux-4.4.0.orig/drivers/usb/usbip/vhci_hcd.c
+++ linux-4.4.0/drivers/usb/usbip/vhci_hcd.c
@@ -121,9 +121,11 @@
 
 void rh_port_connect(int rhport, enum usb_device_speed speed)
 {
+	unsigned long	flags;
+
 	usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport);
 
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 
 	the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
 		| (1 << USB_PORT_FEAT_C_CONNECTION);
@@ -139,22 +141,24 @@
 		break;
 	}
 
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
 }
 
 static void rh_port_disconnect(int rhport)
 {
+	unsigned long	flags;
+
 	usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
 
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 
 	the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
 	the_controller->port_status[rhport] |=
 					(1 << USB_PORT_FEAT_C_CONNECTION);
 
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 	usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
 }
 
@@ -182,13 +186,14 @@
 	int		retval;
 	int		rhport;
 	int		changed = 0;
+	unsigned long	flags;
 
 	retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8);
 	memset(buf, 0, retval);
 
 	vhci = hcd_to_vhci(hcd);
 
-	spin_lock(&vhci->lock);
+	spin_lock_irqsave(&vhci->lock, flags);
 	if (!HCD_HW_ACCESSIBLE(hcd)) {
 		usbip_dbg_vhci_rh("hw accessible flag not on?\n");
 		goto done;
@@ -209,20 +214,25 @@
 		usb_hcd_resume_root_hub(hcd);
 
 done:
-	spin_unlock(&vhci->lock);
+	spin_unlock_irqrestore(&vhci->lock, flags);
 	return changed ? retval : 0;
 }
 
 static inline void hub_descriptor(struct usb_hub_descriptor *desc)
 {
+	int width;
+
 	memset(desc, 0, sizeof(*desc));
 	desc->bDescriptorType = USB_DT_HUB;
-	desc->bDescLength = 9;
 	desc->wHubCharacteristics = cpu_to_le16(
 		HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM);
+
 	desc->bNbrPorts = VHCI_NPORTS;
-	desc->u.hs.DeviceRemovable[0] = 0xff;
-	desc->u.hs.DeviceRemovable[1] = 0xff;
+	BUILD_BUG_ON(VHCI_NPORTS > USB_MAXCHILDREN);
+	width = desc->bNbrPorts / 8 + 1;
+	desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * width;
+	memset(&desc->u.hs.DeviceRemovable[0], 0, width);
+	memset(&desc->u.hs.DeviceRemovable[width], 0xff, width);
 }
 
 static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
@@ -231,6 +241,7 @@
 	struct vhci_hcd	*dum;
 	int             retval = 0;
 	int		rhport;
+	unsigned long	flags;
 
 	u32 prev_port_status[VHCI_NPORTS];
 
@@ -249,7 +260,7 @@
 
 	dum = hcd_to_vhci(hcd);
 
-	spin_lock(&dum->lock);
+	spin_lock_irqsave(&dum->lock, flags);
 
 	/* store old status and compare now and old later */
 	if (usbip_dbg_flag_vhci_rh) {
@@ -274,7 +285,7 @@
 		case USB_PORT_FEAT_POWER:
 			usbip_dbg_vhci_rh(
 				" ClearPortFeature: USB_PORT_FEAT_POWER\n");
-			dum->port_status[rhport] = 0;
+			dum->port_status[rhport] &= ~USB_PORT_STAT_POWER;
 			dum->resuming = 0;
 			break;
 		case USB_PORT_FEAT_C_RESET:
@@ -292,6 +303,7 @@
 			default:
 				break;
 			}
+			break;
 		default:
 			usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n",
 					  wValue);
@@ -403,7 +415,7 @@
 	}
 	usbip_dbg_vhci_rh(" bye\n");
 
-	spin_unlock(&dum->lock);
+	spin_unlock_irqrestore(&dum->lock, flags);
 
 	return retval;
 }
@@ -426,6 +438,7 @@
 {
 	struct vhci_device *vdev = get_vdev(urb->dev);
 	struct vhci_priv *priv;
+	unsigned long flags;
 
 	if (!vdev) {
 		pr_err("could not get virtual device");
@@ -438,7 +451,7 @@
 		return;
 	}
 
-	spin_lock(&vdev->priv_lock);
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 
 	priv->seqnum = atomic_inc_return(&the_controller->seqnum);
 	if (priv->seqnum == 0xffff)
@@ -452,7 +465,7 @@
 	list_add_tail(&priv->list, &vdev->priv_tx);
 
 	wake_up(&vdev->waitq_tx);
-	spin_unlock(&vdev->priv_lock);
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 }
 
 static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
@@ -461,18 +474,16 @@
 	struct device *dev = &urb->dev->dev;
 	int ret = 0;
 	struct vhci_device *vdev;
-
-	usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
-			  hcd, urb, mem_flags);
+	unsigned long flags;
 
 	/* patch to usb_sg_init() is in 2.5.60 */
 	BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
 
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 
 	if (urb->status != -EINPROGRESS) {
 		dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 		return urb->status;
 	}
 
@@ -484,7 +495,7 @@
 	    vdev->ud.status == VDEV_ST_ERROR) {
 		dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport);
 		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 		return -ENODEV;
 	}
 	spin_unlock(&vdev->ud.lock);
@@ -557,14 +568,14 @@
 
 out:
 	vhci_tx_urb(urb);
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	return 0;
 
 no_need_xmit:
 	usb_hcd_unlink_urb_from_ep(hcd, urb);
 no_need_unlink:
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 	if (!ret)
 		usb_hcd_giveback_urb(vhci_to_hcd(the_controller),
 				     urb, urb->status);
@@ -621,16 +632,15 @@
 {
 	struct vhci_priv *priv;
 	struct vhci_device *vdev;
+	unsigned long flags;
 
-	pr_info("dequeue a urb %p\n", urb);
-
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 
 	priv = urb->hcpriv;
 	if (!priv) {
 		/* URB was never linked! or will be soon given back by
 		 * vhci_rx. */
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 		return -EIDRM;
 	}
 
@@ -639,7 +649,7 @@
 
 		ret = usb_hcd_check_unlink_urb(hcd, urb, status);
 		if (ret) {
-			spin_unlock(&the_controller->lock);
+			spin_unlock_irqrestore(&the_controller->lock, flags);
 			return ret;
 		}
 	}
@@ -651,7 +661,6 @@
 		/* tcp connection is closed */
 		spin_lock(&vdev->priv_lock);
 
-		pr_info("device %p seems to be disconnected\n", vdev);
 		list_del(&priv->list);
 		kfree(priv);
 		urb->hcpriv = NULL;
@@ -663,14 +672,12 @@
 		 * vhci_rx will receive RET_UNLINK and give back the URB.
 		 * Otherwise, we give back it here.
 		 */
-		pr_info("gives back urb %p\n", urb);
-
 		usb_hcd_unlink_urb_from_ep(hcd, urb);
 
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
 				     urb->status);
-		spin_lock(&the_controller->lock);
+		spin_lock_irqsave(&the_controller->lock, flags);
 
 	} else {
 		/* tcp connection is alive */
@@ -682,7 +689,7 @@
 		unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
 		if (!unlink) {
 			spin_unlock(&vdev->priv_lock);
-			spin_unlock(&the_controller->lock);
+			spin_unlock_irqrestore(&the_controller->lock, flags);
 			usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
 			return -ENOMEM;
 		}
@@ -693,8 +700,6 @@
 
 		unlink->unlink_seqnum = priv->seqnum;
 
-		pr_info("device %p seems to be still connected\n", vdev);
-
 		/* send cmd_unlink and try to cancel the pending URB in the
 		 * peer */
 		list_add_tail(&unlink->list, &vdev->unlink_tx);
@@ -703,7 +708,7 @@
 		spin_unlock(&vdev->priv_lock);
 	}
 
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	usbip_dbg_vhci_hc("leave\n");
 	return 0;
@@ -712,8 +717,9 @@
 static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
 {
 	struct vhci_unlink *unlink, *tmp;
+	unsigned long flags;
 
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 	spin_lock(&vdev->priv_lock);
 
 	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
@@ -747,19 +753,19 @@
 		list_del(&unlink->list);
 
 		spin_unlock(&vdev->priv_lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 
 		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
 				     urb->status);
 
-		spin_lock(&the_controller->lock);
+		spin_lock_irqsave(&the_controller->lock, flags);
 		spin_lock(&vdev->priv_lock);
 
 		kfree(unlink);
 	}
 
 	spin_unlock(&vdev->priv_lock);
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 }
 
 /*
@@ -773,7 +779,7 @@
 
 	/* need this? see stub_dev.c */
 	if (ud->tcp_socket) {
-		pr_debug("shutdown tcp_socket %p\n", ud->tcp_socket);
+		pr_debug("shutdown sockfd %d\n", ud->sockfd);
 		kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
 	}
 
@@ -792,6 +798,7 @@
 	if (vdev->ud.tcp_socket) {
 		sockfd_put(vdev->ud.tcp_socket);
 		vdev->ud.tcp_socket = NULL;
+		vdev->ud.sockfd = -1;
 	}
 	pr_info("release socket\n");
 
@@ -826,8 +833,9 @@
 static void vhci_device_reset(struct usbip_device *ud)
 {
 	struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+	unsigned long flags;
 
-	spin_lock(&ud->lock);
+	spin_lock_irqsave(&ud->lock, flags);
 
 	vdev->speed  = 0;
 	vdev->devid  = 0;
@@ -838,17 +846,20 @@
 	if (ud->tcp_socket) {
 		sockfd_put(ud->tcp_socket);
 		ud->tcp_socket = NULL;
+		ud->sockfd = -1;
 	}
 	ud->status = VDEV_ST_NULL;
 
-	spin_unlock(&ud->lock);
+	spin_unlock_irqrestore(&ud->lock, flags);
 }
 
 static void vhci_device_unusable(struct usbip_device *ud)
 {
-	spin_lock(&ud->lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ud->lock, flags);
 	ud->status = VDEV_ST_ERROR;
-	spin_unlock(&ud->lock);
+	spin_unlock_irqrestore(&ud->lock, flags);
 }
 
 static void vhci_device_init(struct vhci_device *vdev)
@@ -938,12 +949,13 @@
 static int vhci_bus_suspend(struct usb_hcd *hcd)
 {
 	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+	unsigned long flags;
 
 	dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
 
-	spin_lock(&vhci->lock);
+	spin_lock_irqsave(&vhci->lock, flags);
 	hcd->state = HC_STATE_SUSPENDED;
-	spin_unlock(&vhci->lock);
+	spin_unlock_irqrestore(&vhci->lock, flags);
 
 	return 0;
 }
@@ -952,15 +964,16 @@
 {
 	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
 	int rc = 0;
+	unsigned long flags;
 
 	dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
 
-	spin_lock(&vhci->lock);
+	spin_lock_irqsave(&vhci->lock, flags);
 	if (!HCD_HW_ACCESSIBLE(hcd))
 		rc = -ESHUTDOWN;
 	else
 		hcd->state = HC_STATE_RUNNING;
-	spin_unlock(&vhci->lock);
+	spin_unlock_irqrestore(&vhci->lock, flags);
 
 	return rc;
 }
@@ -1058,17 +1071,18 @@
 	int rhport = 0;
 	int connected = 0;
 	int ret = 0;
+	unsigned long flags;
 
 	hcd = platform_get_drvdata(pdev);
 
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 
 	for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
 		if (the_controller->port_status[rhport] &
 		    USB_PORT_STAT_CONNECTION)
 			connected += 1;
 
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	if (connected > 0) {
 		dev_info(&pdev->dev,
--- linux-4.4.0.orig/drivers/usb/usbip/vhci_rx.c
+++ linux-4.4.0/drivers/usb/usbip/vhci_rx.c
@@ -37,24 +37,23 @@
 		urb = priv->urb;
 		status = urb->status;
 
-		usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n",
-				urb, priv, seqnum);
+		usbip_dbg_vhci_rx("find urb seqnum %u\n", seqnum);
 
 		switch (status) {
 		case -ENOENT:
 			/* fall through */
 		case -ECONNRESET:
-			dev_info(&urb->dev->dev,
-				 "urb %p was unlinked %ssynchronuously.\n", urb,
-				 status == -ENOENT ? "" : "a");
+			dev_dbg(&urb->dev->dev,
+				 "urb seq# %u was unlinked %ssynchronuously\n",
+				 seqnum, status == -ENOENT ? "" : "a");
 			break;
 		case -EINPROGRESS:
 			/* no info output */
 			break;
 		default:
-			dev_info(&urb->dev->dev,
-				 "urb %p may be in a error, status %d\n", urb,
-				 status);
+			dev_dbg(&urb->dev->dev,
+				 "urb seq# %u may be in a error, status %d\n",
+				 seqnum, status);
 		}
 
 		list_del(&priv->list);
@@ -72,14 +71,15 @@
 {
 	struct usbip_device *ud = &vdev->ud;
 	struct urb *urb;
+	unsigned long flags;
 
-	spin_lock(&vdev->priv_lock);
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 	urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
-	spin_unlock(&vdev->priv_lock);
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 
 	if (!urb) {
-		pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
-		pr_info("max seqnum %d\n",
+		pr_err("cannot find a urb of seqnum %u max seqnum %d\n",
+			pdu->base.seqnum,
 			atomic_read(&the_controller->seqnum));
 		usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
 		return;
@@ -89,24 +89,29 @@
 	usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0);
 
 	/* recv transfer buffer */
-	if (usbip_recv_xbuff(ud, urb) < 0)
-		return;
+	if (usbip_recv_xbuff(ud, urb) < 0) {
+		urb->status = -EPROTO;
+		goto error;
+	}
 
 	/* recv iso_packet_descriptor */
-	if (usbip_recv_iso(ud, urb) < 0)
-		return;
+	if (usbip_recv_iso(ud, urb) < 0) {
+		urb->status = -EPROTO;
+		goto error;
+	}
 
 	/* restore the padding in iso packets */
 	usbip_pad_iso(ud, urb);
 
+error:
 	if (usbip_dbg_flag_vhci_rx)
 		usbip_dump_urb(urb);
 
-	usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
+	usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum);
 
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 	usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
 
@@ -117,8 +122,9 @@
 						  struct usbip_header *pdu)
 {
 	struct vhci_unlink *unlink, *tmp;
+	unsigned long flags;
 
-	spin_lock(&vdev->priv_lock);
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 
 	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
 		pr_info("unlink->seqnum %lu\n", unlink->seqnum);
@@ -127,12 +133,12 @@
 					  unlink->seqnum);
 			list_del(&unlink->list);
 
-			spin_unlock(&vdev->priv_lock);
+			spin_unlock_irqrestore(&vdev->priv_lock, flags);
 			return unlink;
 		}
 	}
 
-	spin_unlock(&vdev->priv_lock);
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 
 	return NULL;
 }
@@ -142,6 +148,7 @@
 {
 	struct vhci_unlink *unlink;
 	struct urb *urb;
+	unsigned long flags;
 
 	usbip_dump_header(pdu);
 
@@ -152,9 +159,9 @@
 		return;
 	}
 
-	spin_lock(&vdev->priv_lock);
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 	urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
-	spin_unlock(&vdev->priv_lock);
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 
 	if (!urb) {
 		/*
@@ -165,15 +172,15 @@
 		pr_info("the urb (seqnum %d) was already given back\n",
 			pdu->base.seqnum);
 	} else {
-		usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
+		usbip_dbg_vhci_rx("now giveback urb %d\n", pdu->base.seqnum);
 
 		/* If unlink is successful, status is -ECONNRESET */
 		urb->status = pdu->u.ret_unlink.status;
 		pr_info("urb->status %d\n", urb->status);
 
-		spin_lock(&the_controller->lock);
+		spin_lock_irqsave(&the_controller->lock, flags);
 		usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 
 		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
 				     urb->status);
@@ -185,10 +192,11 @@
 static int vhci_priv_tx_empty(struct vhci_device *vdev)
 {
 	int empty = 0;
+	unsigned long flags;
 
-	spin_lock(&vdev->priv_lock);
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 	empty = list_empty(&vdev->priv_rx);
-	spin_unlock(&vdev->priv_lock);
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 
 	return empty;
 }
--- linux-4.4.0.orig/drivers/usb/usbip/vhci_sysfs.c
+++ linux-4.4.0/drivers/usb/usbip/vhci_sysfs.c
@@ -21,6 +21,9 @@
 #include <linux/file.h>
 #include <linux/net.h>
 
+/* Hardening for Spectre-v1 */
+#include <linux/nospec.h>
+
 #include "usbip_common.h"
 #include "vhci.h"
 
@@ -32,23 +35,28 @@
 {
 	char *s = out;
 	int i = 0;
+	unsigned long flags;
 
 	BUG_ON(!the_controller || !out);
 
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 
 	/*
 	 * output example:
-	 * prt sta spd dev socket           local_busid
-	 * 000 004 000 000         c5a7bb80 1-2.3
-	 * 001 004 000 000         d8cee980 2-3.4
+	 * port sta spd dev      sockfd local_busid
+	 * 0000 004 000 00000000 000003 1-2.3
+	 * 0001 004 000 00000000 000004 2-3.4
 	 *
-	 * IP address can be retrieved from a socket pointer address by looking
-	 * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
-	 * port number and its peer IP address.
+	 * Output includes socket fd instead of socket pointer address to
+	 * avoid leaking kernel memory address in:
+	 *	/sys/devices/platform/vhci_hcd.0/status and in debug output.
+	 * The socket pointer address is not used at the moment and it was
+	 * made visible as a convenient way to find IP address from socket
+	 * pointer address by looking up /proc/net/{tcp,tcp6}. As this opens
+	 * a security hole, the change is made to use sockfd instead.
 	 */
 	out += sprintf(out,
-		       "prt sta spd bus dev socket           local_busid\n");
+		       "prt sta spd dev      sockfd local_busid\n");
 
 	for (i = 0; i < VHCI_NPORTS; i++) {
 		struct vhci_device *vdev = port_to_vdev(i);
@@ -59,18 +67,17 @@
 		if (vdev->ud.status == VDEV_ST_USED) {
 			out += sprintf(out, "%03u %08x ",
 				       vdev->speed, vdev->devid);
-			out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
+			out += sprintf(out, "%06u ", vdev->ud.sockfd);
 			out += sprintf(out, "%s", dev_name(&vdev->udev->dev));
 
-		} else {
-			out += sprintf(out, "000 000 000 0000000000000000 0-0");
-		}
+		} else
+			out += sprintf(out, "000 00000000 000000 0-0");
 
 		out += sprintf(out, "\n");
 		spin_unlock(&vdev->ud.lock);
 	}
 
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	return out - s;
 }
@@ -80,11 +87,12 @@
 static int vhci_port_disconnect(__u32 rhport)
 {
 	struct vhci_device *vdev;
+	unsigned long flags;
 
 	usbip_dbg_vhci_sysfs("enter\n");
 
 	/* lock */
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 
 	vdev = port_to_vdev(rhport);
 
@@ -94,14 +102,14 @@
 
 		/* unlock */
 		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 
 		return -EINVAL;
 	}
 
 	/* unlock */
 	spin_unlock(&vdev->ud.lock);
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
 
@@ -122,6 +130,7 @@
 		dev_err(dev, "invalid port %u\n", rhport);
 		return -EINVAL;
 	}
+	rhport = array_index_nospec(rhport, VHCI_NPORTS);
 
 	err = vhci_port_disconnect(rhport);
 	if (err < 0)
@@ -134,13 +143,14 @@
 static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
 
 /* Sysfs entry to establish a virtual connection */
-static int valid_args(__u32 rhport, enum usb_device_speed speed)
+static int valid_args(__u32 *rhport, enum usb_device_speed speed)
 {
 	/* check rhport */
-	if (rhport >= VHCI_NPORTS) {
-		pr_err("port %u\n", rhport);
+	if (*rhport >= VHCI_NPORTS) {
+		pr_err("port %u\n", *rhport);
 		return -EINVAL;
 	}
+	*rhport = array_index_nospec(*rhport, VHCI_NPORTS);
 
 	/* check speed */
 	switch (speed) {
@@ -177,6 +187,7 @@
 	int sockfd = 0;
 	__u32 rhport = 0, devid = 0, speed = 0;
 	int err;
+	unsigned long flags;
 
 	/*
 	 * @rhport: port number of vhci_hcd
@@ -191,25 +202,33 @@
 			     rhport, sockfd, devid, speed);
 
 	/* check received parameters */
-	if (valid_args(rhport, speed) < 0)
+	if (valid_args(&rhport, speed) < 0)
 		return -EINVAL;
 
 	/* Extract socket from fd. */
 	socket = sockfd_lookup(sockfd, &err);
-	if (!socket)
+	if (!socket) {
+		dev_err(dev, "failed to lookup sock");
+		return -EINVAL;
+	}
+	if (socket->type != SOCK_STREAM) {
+		dev_err(dev, "Expecting SOCK_STREAM - found %d",
+			socket->type);
+		sockfd_put(socket);
 		return -EINVAL;
+	}
 
 	/* now need lock until setting vdev status as used */
 
 	/* begin a lock */
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 	vdev = port_to_vdev(rhport);
 	spin_lock(&vdev->ud.lock);
 
 	if (vdev->ud.status != VDEV_ST_NULL) {
 		/* end of the lock */
 		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 
 		sockfd_put(socket);
 
@@ -223,11 +242,12 @@
 
 	vdev->devid         = devid;
 	vdev->speed         = speed;
+	vdev->ud.sockfd     = sockfd;
 	vdev->ud.tcp_socket = socket;
 	vdev->ud.status     = VDEV_ST_NOTASSIGNED;
 
 	spin_unlock(&vdev->ud.lock);
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 	/* end the lock */
 
 	vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
--- linux-4.4.0.orig/drivers/usb/usbip/vhci_tx.c
+++ linux-4.4.0/drivers/usb/usbip/vhci_tx.c
@@ -47,16 +47,17 @@
 static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
 {
 	struct vhci_priv *priv, *tmp;
+	unsigned long flags;
 
-	spin_lock(&vdev->priv_lock);
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 
 	list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
 		list_move_tail(&priv->list, &vdev->priv_rx);
-		spin_unlock(&vdev->priv_lock);
+		spin_unlock_irqrestore(&vdev->priv_lock, flags);
 		return priv;
 	}
 
-	spin_unlock(&vdev->priv_lock);
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 
 	return NULL;
 }
@@ -82,7 +83,8 @@
 		memset(&msg, 0, sizeof(msg));
 		memset(&iov, 0, sizeof(iov));
 
-		usbip_dbg_vhci_tx("setup txdata urb %p\n", urb);
+		usbip_dbg_vhci_tx("setup txdata urb seqnum %lu\n",
+				  priv->seqnum);
 
 		/* 1. setup usbip_header */
 		setup_cmd_submit_pdu(&pdu_header, urb);
@@ -136,16 +138,17 @@
 static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
 {
 	struct vhci_unlink *unlink, *tmp;
+	unsigned long flags;
 
-	spin_lock(&vdev->priv_lock);
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 
 	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
 		list_move_tail(&unlink->list, &vdev->unlink_rx);
-		spin_unlock(&vdev->priv_lock);
+		spin_unlock_irqrestore(&vdev->priv_lock, flags);
 		return unlink;
 	}
 
-	spin_unlock(&vdev->priv_lock);
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 
 	return NULL;
 }
--- linux-4.4.0.orig/drivers/usb/wusbcore/security.c
+++ linux-4.4.0/drivers/usb/wusbcore/security.c
@@ -230,7 +230,7 @@
 
 	result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
 				    0, secd, sizeof(*secd));
-	if (result < sizeof(*secd)) {
+	if (result < (int)sizeof(*secd)) {
 		dev_err(dev, "Can't read security descriptor or "
 			"not enough data: %d\n", result);
 		goto out;
--- linux-4.4.0.orig/drivers/usb/wusbcore/wa-hc.c
+++ linux-4.4.0/drivers/usb/wusbcore/wa-hc.c
@@ -39,6 +39,9 @@
 	int result;
 	struct device *dev = &iface->dev;
 
+	if (iface->cur_altsetting->desc.bNumEndpoints < 3)
+		return -ENODEV;
+
 	result = wa_rpipes_create(wa);
 	if (result < 0)
 		goto error_rpipes_create;
--- linux-4.4.0.orig/drivers/uwb/hwa-rc.c
+++ linux-4.4.0/drivers/uwb/hwa-rc.c
@@ -825,6 +825,11 @@
 	struct hwarc *hwarc;
 	struct device *dev = &iface->dev;
 
+	if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+	if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc))
+		return -ENODEV;
+
 	result = -ENOMEM;
 	uwb_rc = uwb_rc_alloc();
 	if (uwb_rc == NULL) {
@@ -870,6 +875,7 @@
 error_rc_add:
 	usb_put_intf(iface);
 	usb_put_dev(hwarc->usb_dev);
+	kfree(hwarc);
 error_alloc:
 	uwb_rc_put(uwb_rc);
 error_rc_alloc:
--- linux-4.4.0.orig/drivers/uwb/i1480/dfu/usb.c
+++ linux-4.4.0/drivers/uwb/i1480/dfu/usb.c
@@ -341,6 +341,7 @@
 static
 int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id)
 {
+	struct usb_device *udev = interface_to_usbdev(iface);
 	struct i1480_usb *i1480_usb;
 	struct i1480 *i1480;
 	struct device *dev = &iface->dev;
@@ -352,8 +353,8 @@
 			iface->cur_altsetting->desc.bInterfaceNumber);
 		goto error;
 	}
-	if (iface->num_altsetting > 1
-	    && interface_to_usbdev(iface)->descriptor.idProduct == 0xbabe) {
+	if (iface->num_altsetting > 1 &&
+			le16_to_cpu(udev->descriptor.idProduct) == 0xbabe) {
 		/* Need altsetting #1 [HW QUIRK] or EP1 won't work */
 		result = usb_set_interface(interface_to_usbdev(iface), 0, 1);
 		if (result < 0)
@@ -362,6 +363,9 @@
 				 result);
 	}
 
+	if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	result = -ENOMEM;
 	i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
 	if (i1480_usb == NULL) {
--- linux-4.4.0.orig/drivers/uwb/lc-rc.c
+++ linux-4.4.0/drivers/uwb/lc-rc.c
@@ -56,8 +56,11 @@
 	struct uwb_rc *rc = NULL;
 
 	dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match);
-	if (dev)
+	if (dev) {
 		rc = dev_get_drvdata(dev);
+		put_device(dev);
+	}
+
 	return rc;
 }
 
@@ -467,7 +470,9 @@
 	if (dev) {
 		rc = dev_get_drvdata(dev);
 		__uwb_rc_get(rc);
+		put_device(dev);
 	}
+
 	return rc;
 }
 EXPORT_SYMBOL_GPL(__uwb_rc_try_get);
@@ -520,8 +525,11 @@
 
 	dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev,
 				find_rc_grandpa);
-	if (dev)
+	if (dev) {
 		rc = dev_get_drvdata(dev);
+		put_device(dev);
+	}
+
 	return rc;
 }
 EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
@@ -553,8 +561,10 @@
 	struct uwb_rc *rc = NULL;
 
 	dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev);
-	if (dev)
+	if (dev) {
 		rc = dev_get_drvdata(dev);
+		put_device(dev);
+	}
 
 	return rc;
 }
--- linux-4.4.0.orig/drivers/uwb/pal.c
+++ linux-4.4.0/drivers/uwb/pal.c
@@ -97,6 +97,8 @@
 
 	dev = class_find_device(&uwb_rc_class, NULL, target_rc,	find_rc);
 
+	put_device(dev);
+
 	return (dev != NULL);
 }
 
--- linux-4.4.0.orig/drivers/uwb/uwbd.c
+++ linux-4.4.0/drivers/uwb/uwbd.c
@@ -303,18 +303,22 @@
 /** Start the UWB daemon */
 void uwbd_start(struct uwb_rc *rc)
 {
-	rc->uwbd.task = kthread_run(uwbd, rc, "uwbd");
-	if (rc->uwbd.task == NULL)
+	struct task_struct *task = kthread_run(uwbd, rc, "uwbd");
+	if (IS_ERR(task)) {
+		rc->uwbd.task = NULL;
 		printk(KERN_ERR "UWB: Cannot start management daemon; "
 		       "UWB won't work\n");
-	else
+	} else {
+		rc->uwbd.task = task;
 		rc->uwbd.pid = rc->uwbd.task->pid;
+	}
 }
 
 /* Stop the UWB daemon and free any unprocessed events */
 void uwbd_stop(struct uwb_rc *rc)
 {
-	kthread_stop(rc->uwbd.task);
+	if (rc->uwbd.task)
+		kthread_stop(rc->uwbd.task);
 	uwbd_flush(rc);
 }
 
--- linux-4.4.0.orig/drivers/vfio/pci/Kconfig
+++ linux-4.4.0/drivers/vfio/pci/Kconfig
@@ -1,6 +1,7 @@
 config VFIO_PCI
 	tristate "VFIO support for PCI devices"
 	depends on VFIO && PCI && EVENTFD
+	depends on MMU
 	select VFIO_VIRQFD
 	select IRQ_BYPASS_MANAGER
 	help
--- linux-4.4.0.orig/drivers/vfio/pci/vfio_pci.c
+++ linux-4.4.0/drivers/vfio/pci/vfio_pci.c
@@ -28,6 +28,7 @@
 #include <linux/uaccess.h>
 #include <linux/vfio.h>
 #include <linux/vgaarb.h>
+#include <linux/mm.h>
 
 #include "vfio_pci_private.h"
 
@@ -111,6 +112,36 @@
 }
 
 static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev);
+static int vfio_pci_try_zap_and_vma_lock_cb(struct pci_dev *pdev, void *data);
+
+/*
+ * INTx masking requires the ability to disable INTx signaling via PCI_COMMAND
+ * _and_ the ability detect when the device is asserting INTx via PCI_STATUS.
+ * If a device implements the former but not the latter we would typically
+ * expect broken_intx_masking be set and require an exclusive interrupt.
+ * However since we do have control of the device's ability to assert INTx,
+ * we can instead pretend that the device does not implement INTx, virtualizing
+ * the pin register to report zero and maintaining DisINTx set on the host.
+ */
+static bool vfio_pci_nointx(struct pci_dev *pdev)
+{
+	switch (pdev->vendor) {
+	case PCI_VENDOR_ID_INTEL:
+		switch (pdev->device) {
+		/* All i40e (XL710/X710) 10/20/40GbE NICs */
+		case 0x1572:
+		case 0x1574:
+		case 0x1580 ... 0x1581:
+		case 0x1583 ... 0x1589:
+		case 0x37d0 ... 0x37d2:
+			return true;
+		default:
+			return false;
+		}
+	}
+
+	return false;
+}
 
 static int vfio_pci_enable(struct vfio_pci_device *vdev)
 {
@@ -135,23 +166,29 @@
 		pr_debug("%s: Couldn't store %s saved state\n",
 			 __func__, dev_name(&pdev->dev));
 
-	ret = vfio_config_init(vdev);
-	if (ret) {
-		kfree(vdev->pci_saved_state);
-		vdev->pci_saved_state = NULL;
-		pci_disable_device(pdev);
-		return ret;
+	if (likely(!nointxmask)) {
+		if (vfio_pci_nointx(pdev)) {
+			dev_info(&pdev->dev, "Masking broken INTx support\n");
+			vdev->nointx = true;
+			pci_intx(pdev, 0);
+		} else
+			vdev->pci_2_3 = pci_intx_mask_supported(pdev);
 	}
 
-	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);
 	}
 
+	ret = vfio_config_init(vdev);
+	if (ret) {
+		kfree(vdev->pci_saved_state);
+		vdev->pci_saved_state = NULL;
+		pci_disable_device(pdev);
+		return ret;
+	}
+
 	msix_pos = pdev->msix_cap;
 	if (msix_pos) {
 		u16 flags;
@@ -221,11 +258,20 @@
 	pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
 
 	/*
-	 * Try to reset the device.  The success of this is dependent on
-	 * being able to lock the device, which is not always possible.
+	 * Try to get the locks ourselves to prevent a deadlock. The
+	 * success of this is dependent on being able to lock the device,
+	 * which is not always possible.
+	 * We can not use the "try" reset interface here, which will
+	 * overwrite the previously restored configuration information.
 	 */
-	if (vdev->reset_works && !pci_try_reset_function(pdev))
-		vdev->needs_reset = false;
+	if (vdev->reset_works && pci_cfg_access_trylock(pdev)) {
+		if (device_trylock(&pdev->dev)) {
+			if (!__pci_reset_function_locked(pdev))
+				vdev->needs_reset = false;
+			device_unlock(&pdev->dev);
+		}
+		pci_cfg_access_unlock(pdev);
+	}
 
 	pci_restore_state(pdev);
 out:
@@ -246,6 +292,19 @@
 	if (!(--vdev->refcnt)) {
 		vfio_spapr_pci_eeh_release(vdev->pdev);
 		vfio_pci_disable(vdev);
+		mutex_lock(&vdev->igate);
+		if (vdev->err_trigger) {
+			eventfd_ctx_put(vdev->err_trigger);
+			vdev->err_trigger = NULL;
+		}
+		mutex_unlock(&vdev->igate);
+
+		mutex_lock(&vdev->igate);
+		if (vdev->req_trigger) {
+			eventfd_ctx_put(vdev->req_trigger);
+			vdev->req_trigger = NULL;
+		}
+		mutex_unlock(&vdev->igate);
 	}
 
 	mutex_unlock(&driver_lock);
@@ -283,7 +342,7 @@
 	if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) {
 		u8 pin;
 		pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin);
-		if (IS_ENABLED(CONFIG_VFIO_PCI_INTX) && pin)
+		if (IS_ENABLED(CONFIG_VFIO_PCI_INTX) && !vdev->nointx && pin)
 			return 1;
 
 	} else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) {
@@ -421,6 +480,12 @@
 	return walk.ret;
 }
 
+struct vfio_devices {
+	struct vfio_device **devices;
+	int cur_index;
+	int max_index;
+};
+
 static long vfio_pci_ioctl(void *device_data,
 			   unsigned int cmd, unsigned long arg)
 {
@@ -446,7 +511,8 @@
 		info.num_regions = VFIO_PCI_NUM_REGIONS;
 		info.num_irqs = VFIO_PCI_NUM_IRQS;
 
-		return copy_to_user((void __user *)arg, &info, minsz);
+		return copy_to_user((void __user *)arg, &info, minsz) ?
+			-EFAULT : 0;
 
 	} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
 		struct pci_dev *pdev = vdev->pdev;
@@ -486,6 +552,7 @@
 		{
 			void __iomem *io;
 			size_t size;
+			u16 cmd;
 
 			info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
 			info.flags = 0;
@@ -495,15 +562,20 @@
 			if (!info.size)
 				break;
 
-			/* Is it really there? */
+			/*
+			 * Is it really there?  Enable memory decode for
+			 * implicit access in pci_map_rom().
+			 */
+			cmd = vfio_pci_memory_lock_and_enable(vdev);
 			io = pci_map_rom(pdev, &size);
-			if (!io || !size) {
+			if (io) {
+				info.flags = VFIO_REGION_INFO_FLAG_READ;
+				pci_unmap_rom(pdev, io);
+			} else {
 				info.size = 0;
-				break;
 			}
-			pci_unmap_rom(pdev, io);
+			vfio_pci_memory_unlock_and_restore(vdev, cmd);
 
-			info.flags = VFIO_REGION_INFO_FLAG_READ;
 			break;
 		}
 		case VFIO_PCI_VGA_REGION_INDEX:
@@ -520,7 +592,8 @@
 			return -EINVAL;
 		}
 
-		return copy_to_user((void __user *)arg, &info, minsz);
+		return copy_to_user((void __user *)arg, &info, minsz) ?
+			-EFAULT : 0;
 
 	} else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
 		struct vfio_irq_info info;
@@ -555,12 +628,14 @@
 		else
 			info.flags |= VFIO_IRQ_INFO_NORESIZE;
 
-		return copy_to_user((void __user *)arg, &info, minsz);
+		return copy_to_user((void __user *)arg, &info, minsz) ?
+			-EFAULT : 0;
 
 	} else if (cmd == VFIO_DEVICE_SET_IRQS) {
 		struct vfio_irq_set hdr;
+		size_t size;
 		u8 *data = NULL;
-		int ret = 0;
+		int max, ret = 0;
 
 		minsz = offsetofend(struct vfio_irq_set, count);
 
@@ -568,23 +643,31 @@
 			return -EFAULT;
 
 		if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS ||
+		    hdr.count >= (U32_MAX - hdr.start) ||
 		    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;
-			int max = vfio_pci_get_irq_count(vdev, hdr.index);
+		max = vfio_pci_get_irq_count(vdev, hdr.index);
+		if (hdr.start >= max || hdr.start + hdr.count > max)
+			return -EINVAL;
 
-			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;
+		switch (hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) {
+		case VFIO_IRQ_SET_DATA_NONE:
+			size = 0;
+			break;
+		case VFIO_IRQ_SET_DATA_BOOL:
+			size = sizeof(uint8_t);
+			break;
+		case VFIO_IRQ_SET_DATA_EVENTFD:
+			size = sizeof(int32_t);
+			break;
+		default:
+			return -EINVAL;
+		}
 
-			if (hdr.argsz - minsz < hdr.count * size ||
-			    hdr.start >= max || hdr.start + hdr.count > max)
+		if (size) {
+			if (hdr.argsz - minsz < hdr.count * size)
 				return -EINVAL;
 
 			data = memdup_user((void __user *)(arg + minsz),
@@ -604,8 +687,16 @@
 		return ret;
 
 	} else if (cmd == VFIO_DEVICE_RESET) {
-		return vdev->reset_works ?
-			pci_try_reset_function(vdev->pdev) : -EINVAL;
+		int ret;
+
+		if (!vdev->reset_works)
+			return -EINVAL;
+
+		vfio_pci_zap_and_down_write_memory_lock(vdev);
+		ret = pci_try_reset_function(vdev->pdev);
+		up_write(&vdev->memory_lock);
+
+		return ret;
 
 	} else if (cmd == VFIO_DEVICE_GET_PCI_HOT_RESET_INFO) {
 		struct vfio_pci_hot_reset_info hdr;
@@ -685,8 +776,9 @@
 		int32_t *group_fds;
 		struct vfio_pci_group_entry *groups;
 		struct vfio_pci_group_info info;
+		struct vfio_devices devs = { .cur_index = 0 };
 		bool slot = false;
-		int i, count = 0, ret = 0;
+		int i, group_idx, mem_idx = 0, count = 0, ret = 0;
 
 		minsz = offsetofend(struct vfio_pci_hot_reset, count);
 
@@ -738,9 +830,9 @@
 		 * user interface and store the group and iommu ID.  This
 		 * ensures the group is held across the reset.
 		 */
-		for (i = 0; i < hdr.count; i++) {
+		for (group_idx = 0; group_idx < hdr.count; group_idx++) {
 			struct vfio_group *group;
-			struct fd f = fdget(group_fds[i]);
+			struct fd f = fdget(group_fds[group_idx]);
 			if (!f.file) {
 				ret = -EBADF;
 				break;
@@ -753,8 +845,9 @@
 				break;
 			}
 
-			groups[i].group = group;
-			groups[i].id = vfio_external_user_iommu_id(group);
+			groups[group_idx].group = group;
+			groups[group_idx].id =
+					vfio_external_user_iommu_id(group);
 		}
 
 		kfree(group_fds);
@@ -773,14 +866,65 @@
 		ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
 						    vfio_pci_validate_devs,
 						    &info, slot);
-		if (!ret)
-			/* User has access, do the reset */
-			ret = slot ? pci_try_reset_slot(vdev->pdev->slot) :
-				     pci_try_reset_bus(vdev->pdev->bus);
+
+		if (ret)
+			goto hot_reset_release;
+
+		devs.max_index = count;
+		devs.devices = kcalloc(count, sizeof(struct vfio_device *),
+				       GFP_KERNEL);
+		if (!devs.devices) {
+			ret = -ENOMEM;
+			goto hot_reset_release;
+		}
+
+		/*
+		 * We need to get memory_lock for each device, but devices
+		 * can share mmap_sem, therefore we need to zap and hold
+		 * the vma_lock for each device, and only then get each
+		 * memory_lock.
+		 */
+		ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
+					    vfio_pci_try_zap_and_vma_lock_cb,
+					    &devs, slot);
+		if (ret)
+			goto hot_reset_release;
+
+		for (; mem_idx < devs.cur_index; mem_idx++) {
+			struct vfio_pci_device *tmp;
+
+			tmp = vfio_device_data(devs.devices[mem_idx]);
+
+			ret = down_write_trylock(&tmp->memory_lock);
+			if (!ret) {
+				ret = -EBUSY;
+				goto hot_reset_release;
+			}
+			mutex_unlock(&tmp->vma_lock);
+		}
+
+		/* User has access, do the reset */
+		ret = slot ? pci_try_reset_slot(vdev->pdev->slot) :
+				pci_try_reset_bus(vdev->pdev->bus);
 
 hot_reset_release:
-		for (i--; i >= 0; i--)
-			vfio_group_put_external_user(groups[i].group);
+		for (i = 0; i < devs.cur_index; i++) {
+			struct vfio_device *device;
+			struct vfio_pci_device *tmp;
+
+			device = devs.devices[i];
+			tmp = vfio_device_data(device);
+
+			if (i < mem_idx)
+				up_write(&tmp->memory_lock);
+			else
+				mutex_unlock(&tmp->vma_lock);
+			vfio_device_put(device);
+		}
+		kfree(devs.devices);
+
+		for (group_idx--; group_idx >= 0; group_idx--)
+			vfio_group_put_external_user(groups[group_idx].group);
 
 		kfree(groups);
 		return ret;
@@ -835,6 +979,201 @@
 	return vfio_pci_rw(device_data, (char __user *)buf, count, ppos, true);
 }
 
+/* Return 1 on zap and vma_lock acquired, 0 on contention (only with @try) */
+static int vfio_pci_zap_and_vma_lock(struct vfio_pci_device *vdev, bool try)
+{
+	struct vfio_pci_mmap_vma *mmap_vma, *tmp;
+
+	/*
+	 * Lock ordering:
+	 * vma_lock is nested under mmap_sem for vm_ops callback paths.
+	 * The memory_lock semaphore is used by both code paths calling
+	 * into this function to zap vmas and the vm_ops.fault callback
+	 * to protect the memory enable state of the device.
+	 *
+	 * When zapping vmas we need to maintain the mmap_sem => vma_lock
+	 * ordering, which requires using vma_lock to walk vma_list to
+	 * acquire an mm, then dropping vma_lock to get the mmap_sem and
+	 * reacquiring vma_lock.  This logic is derived from similar
+	 * requirements in uverbs_user_mmap_disassociate().
+	 *
+	 * mmap_sem must always be the top-level lock when it is taken.
+	 * Therefore we can only hold the memory_lock write lock when
+	 * vma_list is empty, as we'd need to take mmap_sem to clear
+	 * entries.  vma_list can only be guaranteed empty when holding
+	 * vma_lock, thus memory_lock is nested under vma_lock.
+	 *
+	 * This enables the vm_ops.fault callback to acquire vma_lock,
+	 * followed by memory_lock read lock, while already holding
+	 * mmap_sem without risk of deadlock.
+	 */
+	while (1) {
+		struct mm_struct *mm = NULL;
+
+		if (try) {
+			if (!mutex_trylock(&vdev->vma_lock))
+				return 0;
+		} else {
+			mutex_lock(&vdev->vma_lock);
+		}
+		while (!list_empty(&vdev->vma_list)) {
+			mmap_vma = list_first_entry(&vdev->vma_list,
+						    struct vfio_pci_mmap_vma,
+						    vma_next);
+			mm = mmap_vma->vma->vm_mm;
+			if (mmget_not_zero(mm))
+				break;
+
+			list_del(&mmap_vma->vma_next);
+			kfree(mmap_vma);
+			mm = NULL;
+		}
+		if (!mm)
+			return 1;
+		mutex_unlock(&vdev->vma_lock);
+
+		if (try) {
+			if (!down_read_trylock(&mm->mmap_sem)) {
+				mmput(mm);
+				return 0;
+			}
+		} else {
+			down_read(&mm->mmap_sem);
+		}
+		if (mmget_still_valid(mm)) {
+			if (try) {
+				if (!mutex_trylock(&vdev->vma_lock)) {
+					up_read(&mm->mmap_sem);
+					mmput(mm);
+					return 0;
+				}
+			} else {
+				mutex_lock(&vdev->vma_lock);
+			}
+			list_for_each_entry_safe(mmap_vma, tmp,
+						 &vdev->vma_list, vma_next) {
+				struct vm_area_struct *vma = mmap_vma->vma;
+
+				if (vma->vm_mm != mm)
+					continue;
+
+				list_del(&mmap_vma->vma_next);
+				kfree(mmap_vma);
+
+				zap_vma_ptes(vma, vma->vm_start,
+					     vma->vm_end - vma->vm_start);
+			}
+			mutex_unlock(&vdev->vma_lock);
+		}
+		up_read(&mm->mmap_sem);
+		mmput(mm);
+	}
+}
+
+void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_device *vdev)
+{
+	vfio_pci_zap_and_vma_lock(vdev, false);
+	down_write(&vdev->memory_lock);
+	mutex_unlock(&vdev->vma_lock);
+}
+
+u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_device *vdev)
+{
+	u16 cmd;
+
+	down_write(&vdev->memory_lock);
+	pci_read_config_word(vdev->pdev, PCI_COMMAND, &cmd);
+	if (!(cmd & PCI_COMMAND_MEMORY))
+		pci_write_config_word(vdev->pdev, PCI_COMMAND,
+				      cmd | PCI_COMMAND_MEMORY);
+
+	return cmd;
+}
+
+void vfio_pci_memory_unlock_and_restore(struct vfio_pci_device *vdev, u16 cmd)
+{
+	pci_write_config_word(vdev->pdev, PCI_COMMAND, cmd);
+	up_write(&vdev->memory_lock);
+}
+
+/* Caller holds vma_lock */
+static int __vfio_pci_add_vma(struct vfio_pci_device *vdev,
+			      struct vm_area_struct *vma)
+{
+	struct vfio_pci_mmap_vma *mmap_vma;
+
+	mmap_vma = kmalloc(sizeof(*mmap_vma), GFP_KERNEL);
+	if (!mmap_vma)
+		return -ENOMEM;
+
+	mmap_vma->vma = vma;
+	list_add(&mmap_vma->vma_next, &vdev->vma_list);
+
+	return 0;
+}
+
+/*
+ * Zap mmaps on open so that we can fault them in on access and therefore
+ * our vma_list only tracks mappings accessed since last zap.
+ */
+static void vfio_pci_mmap_open(struct vm_area_struct *vma)
+{
+	zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start);
+}
+
+static void vfio_pci_mmap_close(struct vm_area_struct *vma)
+{
+	struct vfio_pci_device *vdev = vma->vm_private_data;
+	struct vfio_pci_mmap_vma *mmap_vma;
+
+	mutex_lock(&vdev->vma_lock);
+	list_for_each_entry(mmap_vma, &vdev->vma_list, vma_next) {
+		if (mmap_vma->vma == vma) {
+			list_del(&mmap_vma->vma_next);
+			kfree(mmap_vma);
+			break;
+		}
+	}
+	mutex_unlock(&vdev->vma_lock);
+}
+
+static int vfio_pci_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct vfio_pci_device *vdev = vma->vm_private_data;
+	int ret = VM_FAULT_NOPAGE;
+
+	mutex_lock(&vdev->vma_lock);
+	down_read(&vdev->memory_lock);
+
+	if (!__vfio_pci_memory_enabled(vdev)) {
+		ret = VM_FAULT_SIGBUS;
+		mutex_unlock(&vdev->vma_lock);
+		goto up_out;
+	}
+
+	if (__vfio_pci_add_vma(vdev, vma)) {
+		ret = VM_FAULT_OOM;
+		mutex_unlock(&vdev->vma_lock);
+		goto up_out;
+	}
+
+	mutex_unlock(&vdev->vma_lock);
+
+	if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start, vma->vm_page_prot))
+		ret = VM_FAULT_SIGBUS;
+
+up_out:
+	up_read(&vdev->memory_lock);
+	return ret;
+}
+
+static const struct vm_operations_struct vfio_pci_mmap_ops = {
+	.open = vfio_pci_mmap_open,
+	.close = vfio_pci_mmap_close,
+	.fault = vfio_pci_mmap_fault,
+};
+
 static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
 {
 	struct vfio_pci_device *vdev = device_data;
@@ -890,14 +1229,24 @@
 			return ret;
 
 		vdev->barmap[index] = pci_iomap(pdev, index, 0);
+		if (!vdev->barmap[index]) {
+			pci_release_selected_regions(pdev, 1 << index);
+			return -ENOMEM;
+		}
 	}
 
 	vma->vm_private_data = vdev;
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	vma->vm_pgoff = (pci_resource_start(pdev, index) >> PAGE_SHIFT) + pgoff;
 
-	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
-			       req_len, vma->vm_page_prot);
+	/*
+	 * See remap_pfn_range(), called from vfio_pci_fault() but we can't
+	 * change vm_flags within the fault handler.  Set them now.
+	 */
+	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+	vma->vm_ops = &vfio_pci_mmap_ops;
+
+	return 0;
 }
 
 static void vfio_pci_request(void *device_data, unsigned int count)
@@ -955,6 +1304,9 @@
 	mutex_init(&vdev->igate);
 	spin_lock_init(&vdev->irqlock);
 
+	mutex_init(&vdev->vma_lock);
+	INIT_LIST_HEAD(&vdev->vma_list);
+	init_rwsem(&vdev->memory_lock);
 	ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev);
 	if (ret) {
 		iommu_group_put(group);
@@ -1047,12 +1399,6 @@
 	.err_handler	= &vfio_err_handlers,
 };
 
-struct vfio_devices {
-	struct vfio_device **devices;
-	int cur_index;
-	int max_index;
-};
-
 static int vfio_pci_get_devs(struct pci_dev *pdev, void *data)
 {
 	struct vfio_devices *devs = data;
@@ -1074,6 +1420,39 @@
 	return 0;
 }
 
+static int vfio_pci_try_zap_and_vma_lock_cb(struct pci_dev *pdev, void *data)
+{
+	struct vfio_devices *devs = data;
+	struct vfio_device *device;
+	struct vfio_pci_device *vdev;
+
+	if (devs->cur_index == devs->max_index)
+		return -ENOSPC;
+
+	device = vfio_device_get_from_dev(&pdev->dev);
+	if (!device)
+		return -EINVAL;
+
+	if (pci_dev_driver(pdev) != &vfio_pci_driver) {
+		vfio_device_put(device);
+		return -EBUSY;
+	}
+
+	vdev = vfio_device_data(device);
+
+	/*
+	 * Locking multiple devices is prone to deadlock, runaway and
+	 * unwind if we hit contention.
+	 */
+	if (!vfio_pci_zap_and_vma_lock(vdev, true)) {
+		vfio_device_put(device);
+		return -EBUSY;
+	}
+
+	devs->devices[devs->cur_index++] = device;
+	return 0;
+}
+
 /*
  * Attempt to do a bus/slot reset if there are devices affected by a reset for
  * this device that are needs_reset and all of the affected devices are unused
@@ -1175,11 +1554,11 @@
 		rc = pci_add_dynid(&vfio_pci_driver, vendor, device,
 				   subvendor, subdevice, class, class_mask, 0);
 		if (rc)
-			pr_warn("failed to add dynamic id [%04hx:%04hx[%04hx:%04hx]] class %#08x/%08x (%d)\n",
+			pr_warn("failed to add dynamic id [%04x:%04x[%04x:%04x]] class %#08x/%08x (%d)\n",
 				vendor, device, subvendor, subdevice,
 				class, class_mask, rc);
 		else
-			pr_info("add [%04hx:%04hx[%04hx:%04hx]] class %#08x/%08x\n",
+			pr_info("add [%04x:%04x[%04x:%04x]] class %#08x/%08x\n",
 				vendor, device, subvendor, subdevice,
 				class, class_mask);
 	}
--- linux-4.4.0.orig/drivers/vfio/pci/vfio_pci_config.c
+++ linux-4.4.0/drivers/vfio/pci/vfio_pci_config.c
@@ -379,6 +379,20 @@
 	*(__le32 *)(&p->write[off]) = cpu_to_le32(write);
 }
 
+/* Caller should hold memory_lock semaphore */
+bool __vfio_pci_memory_enabled(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u16 cmd = le16_to_cpu(*(__le16 *)&vdev->vconfig[PCI_COMMAND]);
+
+	/*
+	 * SR-IOV VF memory enable is handled by the MSE bit in the
+	 * PF SR-IOV capability, there's therefore no need to trigger
+	 * faults based on the virtual value.
+	 */
+	return pdev->is_virtfn || (cmd & PCI_COMMAND_MEMORY);
+}
+
 /*
  * Restore the *real* BARs after we detect a FLR or backdoor reset.
  * (backdoor = some device specific technique that we didn't catch)
@@ -387,6 +401,7 @@
 {
 	struct pci_dev *pdev = vdev->pdev;
 	u32 *rbar = vdev->rbar;
+	u16 cmd;
 	int i;
 
 	if (pdev->is_virtfn)
@@ -399,6 +414,12 @@
 		pci_user_write_config_dword(pdev, i, *rbar);
 
 	pci_user_write_config_dword(pdev, PCI_ROM_ADDRESS, *rbar);
+
+	if (vdev->nointx) {
+		pci_user_read_config_word(pdev, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_INTX_DISABLE;
+		pci_user_write_config_word(pdev, PCI_COMMAND, cmd);
+	}
 }
 
 static __le32 vfio_generate_bar_flags(struct pci_dev *pdev, int bar)
@@ -510,13 +531,18 @@
 
 		new_cmd = le32_to_cpu(val);
 
+		phys_io = !!(phys_cmd & PCI_COMMAND_IO);
+		virt_io = !!(le16_to_cpu(*virt_cmd) & PCI_COMMAND_IO);
+		new_io = !!(new_cmd & PCI_COMMAND_IO);
+
 		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 (!new_mem)
+			vfio_pci_zap_and_down_write_memory_lock(vdev);
+		else
+			down_write(&vdev->memory_lock);
 
 		/*
 		 * If the user is writing mem/io enable (new_mem/io) and we
@@ -532,8 +558,11 @@
 	}
 
 	count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
-	if (count < 0)
+	if (count < 0) {
+		if (offset == PCI_COMMAND)
+			up_write(&vdev->memory_lock);
 		return count;
+	}
 
 	/*
 	 * Save current memory/io enable bits in vconfig to allow for
@@ -544,6 +573,8 @@
 
 		*virt_cmd &= cpu_to_le16(~mask);
 		*virt_cmd |= cpu_to_le16(new_cmd & mask);
+
+		up_write(&vdev->memory_lock);
 	}
 
 	/* Emulate INTx disable */
@@ -698,7 +729,8 @@
 		if (pci_write_vpd(pdev, addr & ~PCI_VPD_ADDR_F, 4, &data) != 4)
 			return count;
 	} else {
-		if (pci_read_vpd(pdev, addr, 4, &data) != 4)
+		data = 0;
+		if (pci_read_vpd(pdev, addr, 4, &data) < 0)
 			return count;
 		*pdata = cpu_to_le32(data);
 	}
@@ -752,6 +784,65 @@
 	return 0;
 }
 
+static int vfio_exp_config_write(struct vfio_pci_device *vdev, int pos,
+				 int count, struct perm_bits *perm,
+				 int offset, __le32 val)
+{
+	__le16 *ctrl = (__le16 *)(vdev->vconfig + pos -
+				  offset + PCI_EXP_DEVCTL);
+	int readrq = le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ;
+
+	count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
+	if (count < 0)
+		return count;
+
+	/*
+	 * The FLR bit is virtualized, if set and the device supports PCIe
+	 * FLR, issue a reset_function.  Regardless, clear the bit, the spec
+	 * requires it to be always read as zero.  NB, reset_function might
+	 * not use a PCIe FLR, we don't have that level of granularity.
+	 */
+	if (*ctrl & cpu_to_le16(PCI_EXP_DEVCTL_BCR_FLR)) {
+		u32 cap;
+		int ret;
+
+		*ctrl &= ~cpu_to_le16(PCI_EXP_DEVCTL_BCR_FLR);
+
+		ret = pci_user_read_config_dword(vdev->pdev,
+						 pos - offset + PCI_EXP_DEVCAP,
+						 &cap);
+
+		if (!ret && (cap & PCI_EXP_DEVCAP_FLR)) {
+			vfio_pci_zap_and_down_write_memory_lock(vdev);
+			pci_try_reset_function(vdev->pdev);
+			up_write(&vdev->memory_lock);
+		}
+	}
+
+	/*
+	 * MPS is virtualized to the user, writes do not change the physical
+	 * register since determining a proper MPS value requires a system wide
+	 * device view.  The MRRS is largely independent of MPS, but since the
+	 * user does not have that system-wide view, they might set a safe, but
+	 * inefficiently low value.  Here we allow writes through to hardware,
+	 * but we set the floor to the physical device MPS setting, so that
+	 * we can at least use full TLPs, as defined by the MPS value.
+	 *
+	 * NB, if any devices actually depend on an artificially low MRRS
+	 * setting, this will need to be revisited, perhaps with a quirk
+	 * though pcie_set_readrq().
+	 */
+	if (readrq != (le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ)) {
+		readrq = 128 <<
+			((le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ) >> 12);
+		readrq = max(readrq, pcie_get_mps(vdev->pdev));
+
+		pcie_set_readrq(vdev->pdev, readrq);
+	}
+
+	return count;
+}
+
 /* Permissions for PCI Express capability */
 static int __init init_pci_cap_exp_perm(struct perm_bits *perm)
 {
@@ -759,26 +850,70 @@
 	if (alloc_perm_bits(perm, PCI_CAP_EXP_ENDPOINT_SIZEOF_V2))
 		return -ENOMEM;
 
+	perm->writefn = vfio_exp_config_write;
+
 	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
+	 * Allow writes to device control fields, except devctl_phantom,
+	 * which could confuse IOMMU, MPS, which can break communication
+	 * with other physical devices, and the ARI bit in devctl2, which
+	 * is set at probe time.  FLR and MRRS get virtualized via our
+	 * writefn.
 	 */
-	p_setw(perm, PCI_EXP_DEVCTL, NO_VIRT, ~PCI_EXP_DEVCTL_PHANTOM);
+	p_setw(perm, PCI_EXP_DEVCTL,
+	       PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD |
+	       PCI_EXP_DEVCTL_READRQ, ~PCI_EXP_DEVCTL_PHANTOM);
 	p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI);
 	return 0;
 }
 
+static int vfio_af_config_write(struct vfio_pci_device *vdev, int pos,
+				int count, struct perm_bits *perm,
+				int offset, __le32 val)
+{
+	u8 *ctrl = vdev->vconfig + pos - offset + PCI_AF_CTRL;
+
+	count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
+	if (count < 0)
+		return count;
+
+	/*
+	 * The FLR bit is virtualized, if set and the device supports AF
+	 * FLR, issue a reset_function.  Regardless, clear the bit, the spec
+	 * requires it to be always read as zero.  NB, reset_function might
+	 * not use an AF FLR, we don't have that level of granularity.
+	 */
+	if (*ctrl & PCI_AF_CTRL_FLR) {
+		u8 cap;
+		int ret;
+
+		*ctrl &= ~PCI_AF_CTRL_FLR;
+
+		ret = pci_user_read_config_byte(vdev->pdev,
+						pos - offset + PCI_AF_CAP,
+						&cap);
+
+		if (!ret && (cap & PCI_AF_CAP_FLR) && (cap & PCI_AF_CAP_TP)) {
+			vfio_pci_zap_and_down_write_memory_lock(vdev);
+			pci_try_reset_function(vdev->pdev);
+			up_write(&vdev->memory_lock);
+		}
+	}
+
+	return count;
+}
+
 /* 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;
 
+	perm->writefn = vfio_af_config_write;
+
 	p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
-	p_setb(perm, PCI_AF_CTRL, NO_VIRT, PCI_AF_CTRL_FLR);
+	p_setb(perm, PCI_AF_CTRL, PCI_AF_CTRL_FLR, PCI_AF_CTRL_FLR);
 	return 0;
 }
 
@@ -1033,8 +1168,10 @@
 		return -ENOMEM;
 
 	ret = init_pci_cap_msi_perm(vdev->msi_perm, len, flags);
-	if (ret)
+	if (ret) {
+		kfree(vdev->msi_perm);
 		return ret;
+	}
 
 	return len;
 }
@@ -1305,7 +1442,12 @@
 		if (ret)
 			return ret;
 
-		if (cap <= PCI_CAP_ID_MAX) {
+		/*
+		 * ID 0 is a NULL capability, conflicting with our fake
+		 * PCI_CAP_ID_BASIC.  As it has no content, consider it
+		 * hidden for now.
+		 */
+		if (cap && cap <= PCI_CAP_ID_MAX) {
 			len = pci_cap_length[cap];
 			if (len == 0xFF) { /* Variable length */
 				len = vfio_cap_len(vdev, cap, pos);
@@ -1515,9 +1657,18 @@
 	if (pdev->is_virtfn) {
 		*(__le16 *)&vconfig[PCI_VENDOR_ID] = cpu_to_le16(pdev->vendor);
 		*(__le16 *)&vconfig[PCI_DEVICE_ID] = cpu_to_le16(pdev->device);
+
+		/*
+		 * VFs do no implement the memory enable bit of the COMMAND
+		 * register therefore we'll not have it set in our initial
+		 * copy of config space after pci_enable_device().  For
+		 * consistency with PFs, set the virtual enable bit here.
+		 */
+		*(__le16 *)&vconfig[PCI_COMMAND] |=
+					cpu_to_le16(PCI_COMMAND_MEMORY);
 	}
 
-	if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX))
+	if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx)
 		vconfig[PCI_INTERRUPT_PIN] = 0;
 
 	ret = vfio_cap_init(vdev);
@@ -1544,8 +1695,11 @@
 	vdev->vconfig = NULL;
 	kfree(vdev->pci_config_map);
 	vdev->pci_config_map = NULL;
-	kfree(vdev->msi_perm);
-	vdev->msi_perm = NULL;
+	if (vdev->msi_perm) {
+		free_perm_bits(vdev->msi_perm);
+		kfree(vdev->msi_perm);
+		vdev->msi_perm = NULL;
+	}
 }
 
 /*
--- linux-4.4.0.orig/drivers/vfio/pci/vfio_pci_intrs.c
+++ linux-4.4.0/drivers/vfio/pci/vfio_pci_intrs.c
@@ -32,15 +32,22 @@
 {
 	struct vfio_pci_device *vdev = opaque;
 
-	if (likely(is_intx(vdev) && !vdev->virq_disabled))
-		eventfd_signal(vdev->ctx[0].trigger, 1);
+	if (likely(is_intx(vdev) && !vdev->virq_disabled)) {
+		struct eventfd_ctx *trigger;
+
+		trigger = READ_ONCE(vdev->ctx[0].trigger);
+		if (likely(trigger))
+			eventfd_signal(trigger, 1);
+	}
 }
 
-void vfio_pci_intx_mask(struct vfio_pci_device *vdev)
+static void __vfio_pci_intx_mask(struct vfio_pci_device *vdev)
 {
 	struct pci_dev *pdev = vdev->pdev;
 	unsigned long flags;
 
+	lockdep_assert_held(&vdev->igate);
+
 	spin_lock_irqsave(&vdev->irqlock, flags);
 
 	/*
@@ -68,6 +75,13 @@
 	spin_unlock_irqrestore(&vdev->irqlock, flags);
 }
 
+void vfio_pci_intx_mask(struct vfio_pci_device *vdev)
+{
+	mutex_lock(&vdev->igate);
+	__vfio_pci_intx_mask(vdev);
+	mutex_unlock(&vdev->igate);
+}
+
 /*
  * If this is triggered by an eventfd, we can't call eventfd_signal
  * or else we'll deadlock on the eventfd wait queue.  Return >0 when
@@ -110,12 +124,21 @@
 	return ret;
 }
 
-void vfio_pci_intx_unmask(struct vfio_pci_device *vdev)
+static void __vfio_pci_intx_unmask(struct vfio_pci_device *vdev)
 {
+	lockdep_assert_held(&vdev->igate);
+
 	if (vfio_pci_intx_unmask_handler(vdev, NULL) > 0)
 		vfio_send_intx_eventfd(vdev, NULL);
 }
 
+void vfio_pci_intx_unmask(struct vfio_pci_device *vdev)
+{
+	mutex_lock(&vdev->igate);
+	__vfio_pci_intx_unmask(vdev);
+	mutex_unlock(&vdev->igate);
+}
+
 static irqreturn_t vfio_intx_handler(int irq, void *dev_id)
 {
 	struct vfio_pci_device *vdev = dev_id;
@@ -142,95 +165,104 @@
 	return ret;
 }
 
-static int vfio_intx_enable(struct vfio_pci_device *vdev)
+static int vfio_intx_enable(struct vfio_pci_device *vdev,
+			    struct eventfd_ctx *trigger)
 {
+	struct pci_dev *pdev = vdev->pdev;
+	unsigned long irqflags;
+	char *name;
+	int ret;
+
 	if (!is_irq_none(vdev))
 		return -EINVAL;
 
-	if (!vdev->pdev->irq)
+	if (!pdev->irq)
 		return -ENODEV;
 
+	name = kasprintf(GFP_KERNEL, "vfio-intx(%s)", pci_name(pdev));
+	if (!name)
+		return -ENOMEM;
+
 	vdev->ctx = kzalloc(sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
 	if (!vdev->ctx)
 		return -ENOMEM;
 
 	vdev->num_ctx = 1;
 
+	vdev->ctx[0].name = name;
+	vdev->ctx[0].trigger = trigger;
+
 	/*
-	 * If the virtual interrupt is masked, restore it.  Devices
-	 * supporting DisINTx can be masked at the hardware level
-	 * here, non-PCI-2.3 devices will have to wait until the
-	 * interrupt is enabled.
+	 * Fill the initial masked state based on virq_disabled.  After
+	 * enable, changing the DisINTx bit in vconfig directly changes INTx
+	 * masking.  igate prevents races during setup, once running masked
+	 * is protected via irqlock.
+	 *
+	 * Devices supporting DisINTx also reflect the current mask state in
+	 * the physical DisINTx bit, which is not affected during IRQ setup.
+	 *
+	 * Devices without DisINTx support require an exclusive interrupt.
+	 * IRQ masking is performed at the IRQ chip.  Again, igate protects
+	 * against races during setup and IRQ handlers and irqfds are not
+	 * yet active, therefore masked is stable and can be used to
+	 * conditionally auto-enable the IRQ.
+	 *
+	 * irq_type must be stable while the IRQ handler is registered,
+	 * therefore it must be set before request_irq().
 	 */
 	vdev->ctx[0].masked = vdev->virq_disabled;
-	if (vdev->pci_2_3)
-		pci_intx(vdev->pdev, !vdev->ctx[0].masked);
+	if (vdev->pci_2_3) {
+		pci_intx(pdev, !vdev->ctx[0].masked);
+		irqflags = IRQF_SHARED;
+	} else {
+		irqflags = vdev->ctx[0].masked ? IRQF_NO_AUTOEN : 0;
+	}
 
 	vdev->irq_type = VFIO_PCI_INTX_IRQ_INDEX;
 
+	ret = request_irq(pdev->irq, vfio_intx_handler,
+			  irqflags, vdev->ctx[0].name, vdev);
+	if (ret) {
+		vdev->irq_type = VFIO_PCI_NUM_IRQS;
+		kfree(name);
+		vdev->num_ctx = 0;
+		kfree(vdev->ctx);
+		return ret;
+	}
+
 	return 0;
 }
 
-static int vfio_intx_set_signal(struct vfio_pci_device *vdev, int fd)
+static int vfio_intx_set_signal(struct vfio_pci_device *vdev,
+				struct eventfd_ctx *trigger)
 {
 	struct pci_dev *pdev = vdev->pdev;
-	unsigned long irqflags = IRQF_SHARED;
-	struct eventfd_ctx *trigger;
-	unsigned long flags;
-	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;
+	struct eventfd_ctx *old;
 
-	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);
-	}
+	old = vdev->ctx[0].trigger;
 
-	vdev->ctx[0].trigger = trigger;
-
-	if (!vdev->pci_2_3)
-		irqflags = 0;
+	WRITE_ONCE(vdev->ctx[0].trigger, trigger);
 
-	ret = request_irq(pdev->irq, vfio_intx_handler,
-			  irqflags, vdev->ctx[0].name, vdev);
-	if (ret) {
-		vdev->ctx[0].trigger = NULL;
-		kfree(vdev->ctx[0].name);
-		eventfd_ctx_put(trigger);
-		return ret;
+	/* Releasing an old ctx requires synchronizing in-flight users */
+	if (old) {
+		synchronize_irq(pdev->irq);
+		vfio_virqfd_flush_thread(&vdev->ctx[0].unmask);
+		eventfd_ctx_put(old);
 	}
 
-	/*
-	 * INTx disable will stick across the new irq setup,
-	 * disable_irq won't.
-	 */
-	spin_lock_irqsave(&vdev->irqlock, flags);
-	if (!vdev->pci_2_3 && vdev->ctx[0].masked)
-		disable_irq_nosync(pdev->irq);
-	spin_unlock_irqrestore(&vdev->irqlock, flags);
-
 	return 0;
 }
 
 static void vfio_intx_disable(struct vfio_pci_device *vdev)
 {
-	vfio_intx_set_signal(vdev, -1);
+	struct pci_dev *pdev = vdev->pdev;
+
 	vfio_virqfd_disable(&vdev->ctx[0].unmask);
 	vfio_virqfd_disable(&vdev->ctx[0].mask);
+	free_irq(pdev->irq, vdev);
+	if (vdev->ctx[0].trigger)
+		eventfd_ctx_put(vdev->ctx[0].trigger);
+	kfree(vdev->ctx[0].name);
 	vdev->irq_type = VFIO_PCI_NUM_IRQS;
 	vdev->num_ctx = 0;
 	kfree(vdev->ctx);
@@ -251,14 +283,16 @@
 {
 	struct pci_dev *pdev = vdev->pdev;
 	int ret;
+	u16 cmd;
 
 	if (!is_irq_none(vdev))
 		return -EINVAL;
 
-	vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+	vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
 	if (!vdev->ctx)
 		return -ENOMEM;
 
+	cmd = vfio_pci_memory_lock_and_enable(vdev);
 	if (msix) {
 		int i;
 
@@ -276,6 +310,7 @@
 		if (ret < nvec) {
 			if (ret > 0)
 				pci_disable_msix(pdev);
+			vfio_pci_memory_unlock_and_restore(vdev, cmd);
 			kfree(vdev->msix);
 			kfree(vdev->ctx);
 			return ret;
@@ -285,10 +320,12 @@
 		if (ret < nvec) {
 			if (ret > 0)
 				pci_disable_msi(pdev);
+			vfio_pci_memory_unlock_and_restore(vdev, cmd);
 			kfree(vdev->ctx);
 			return ret;
 		}
 	}
+	vfio_pci_memory_unlock_and_restore(vdev, cmd);
 
 	vdev->num_ctx = nvec;
 	vdev->irq_type = msix ? VFIO_PCI_MSIX_IRQ_INDEX :
@@ -313,13 +350,18 @@
 	char *name = msix ? "vfio-msix" : "vfio-msi";
 	struct eventfd_ctx *trigger;
 	int ret;
+	u16 cmd;
 
 	if (vector >= vdev->num_ctx)
 		return -EINVAL;
 
 	if (vdev->ctx[vector].trigger) {
-		free_irq(irq, vdev->ctx[vector].trigger);
 		irq_bypass_unregister_producer(&vdev->ctx[vector].producer);
+
+		cmd = vfio_pci_memory_lock_and_enable(vdev);
+		free_irq(irq, vdev->ctx[vector].trigger);
+		vfio_pci_memory_unlock_and_restore(vdev, cmd);
+
 		kfree(vdev->ctx[vector].name);
 		eventfd_ctx_put(vdev->ctx[vector].trigger);
 		vdev->ctx[vector].trigger = NULL;
@@ -346,6 +388,7 @@
 	 * such a reset it would be unsuccessful. To avoid this, restore the
 	 * cached value of the message prior to enabling.
 	 */
+	cmd = vfio_pci_memory_lock_and_enable(vdev);
 	if (msix) {
 		struct msi_msg msg;
 
@@ -355,6 +398,7 @@
 
 	ret = request_irq(irq, vfio_msihandler, 0,
 			  vdev->ctx[vector].name, trigger);
+	vfio_pci_memory_unlock_and_restore(vdev, cmd);
 	if (ret) {
 		kfree(vdev->ctx[vector].name);
 		eventfd_ctx_put(trigger);
@@ -364,11 +408,13 @@
 	vdev->ctx[vector].producer.token = trigger;
 	vdev->ctx[vector].producer.irq = irq;
 	ret = irq_bypass_register_producer(&vdev->ctx[vector].producer);
-	if (unlikely(ret))
+	if (unlikely(ret)) {
 		dev_info(&pdev->dev,
 		"irq bypass producer (token %p) registration fails: %d\n",
 		vdev->ctx[vector].producer.token, ret);
 
+		vdev->ctx[vector].producer.token = NULL;
+	}
 	vdev->ctx[vector].trigger = trigger;
 
 	return 0;
@@ -399,19 +445,22 @@
 {
 	struct pci_dev *pdev = vdev->pdev;
 	int i;
-
-	vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix);
+	u16 cmd;
 
 	for (i = 0; i < vdev->num_ctx; i++) {
 		vfio_virqfd_disable(&vdev->ctx[i].unmask);
 		vfio_virqfd_disable(&vdev->ctx[i].mask);
 	}
 
+	vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix);
+
+	cmd = vfio_pci_memory_lock_and_enable(vdev);
 	if (msix) {
 		pci_disable_msix(vdev->pdev);
 		kfree(vdev->msix);
 	} else
 		pci_disable_msi(pdev);
+	vfio_pci_memory_unlock_and_restore(vdev, cmd);
 
 	vdev->irq_type = VFIO_PCI_NUM_IRQS;
 	vdev->num_ctx = 0;
@@ -429,11 +478,11 @@
 		return -EINVAL;
 
 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
-		vfio_pci_intx_unmask(vdev);
+		__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);
+			__vfio_pci_intx_unmask(vdev);
 	} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
 		int32_t fd = *(int32_t *)data;
 		if (fd >= 0)
@@ -456,11 +505,11 @@
 		return -EINVAL;
 
 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
-		vfio_pci_intx_mask(vdev);
+		__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);
+			__vfio_pci_intx_mask(vdev);
 	} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
 		return -ENOTTY; /* XXX implement me */
 	}
@@ -481,19 +530,23 @@
 		return -EINVAL;
 
 	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+		struct eventfd_ctx *trigger = NULL;
 		int32_t fd = *(int32_t *)data;
 		int ret;
 
-		if (is_intx(vdev))
-			return vfio_intx_set_signal(vdev, fd);
+		if (fd >= 0) {
+			trigger = eventfd_ctx_fdget(fd);
+			if (IS_ERR(trigger))
+				return PTR_ERR(trigger);
+		}
 
-		ret = vfio_intx_enable(vdev);
-		if (ret)
-			return ret;
+		if (is_intx(vdev))
+			ret = vfio_intx_set_signal(vdev, trigger);
+		else
+			ret = vfio_intx_enable(vdev, trigger);
 
-		ret = vfio_intx_set_signal(vdev, fd);
-		if (ret)
-			vfio_intx_disable(vdev);
+		if (ret && trigger)
+			eventfd_ctx_put(trigger);
 
 		return ret;
 	}
@@ -563,67 +616,80 @@
 }
 
 static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx,
-					   uint32_t flags, void *data)
+					   unsigned int count, uint32_t flags,
+					   void *data)
 {
-	int32_t fd = *(int32_t *)data;
-
-	if (!(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
-		return -EINVAL;
-
 	/* DATA_NONE/DATA_BOOL enables loopback testing */
 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
-		if (*ctx)
-			eventfd_signal(*ctx, 1);
-		return 0;
+		if (*ctx) {
+			if (count) {
+				eventfd_signal(*ctx, 1);
+			} else {
+				eventfd_ctx_put(*ctx);
+				*ctx = NULL;
+			}
+			return 0;
+		}
 	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
-		uint8_t trigger = *(uint8_t *)data;
+		uint8_t trigger;
+
+		if (!count)
+			return -EINVAL;
+
+		trigger = *(uint8_t *)data;
 		if (trigger && *ctx)
 			eventfd_signal(*ctx, 1);
-		return 0;
-	}
 
-	/* Handle SET_DATA_EVENTFD */
-	if (fd == -1) {
-		if (*ctx)
-			eventfd_ctx_put(*ctx);
-		*ctx = NULL;
 		return 0;
-	} else if (fd >= 0) {
-		struct eventfd_ctx *efdctx;
-		efdctx = eventfd_ctx_fdget(fd);
-		if (IS_ERR(efdctx))
-			return PTR_ERR(efdctx);
-		if (*ctx)
-			eventfd_ctx_put(*ctx);
-		*ctx = efdctx;
+	} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+		int32_t fd;
+
+		if (!count)
+			return -EINVAL;
+
+		fd = *(int32_t *)data;
+		if (fd == -1) {
+			if (*ctx)
+				eventfd_ctx_put(*ctx);
+			*ctx = NULL;
+		} else if (fd >= 0) {
+			struct eventfd_ctx *efdctx;
+
+			efdctx = eventfd_ctx_fdget(fd);
+			if (IS_ERR(efdctx))
+				return PTR_ERR(efdctx);
+
+			if (*ctx)
+				eventfd_ctx_put(*ctx);
+
+			*ctx = efdctx;
+		}
 		return 0;
-	} else
-		return -EINVAL;
+	}
+
+	return -EINVAL;
 }
 
 static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
 				    unsigned index, unsigned start,
 				    unsigned count, uint32_t flags, void *data)
 {
-	if (index != VFIO_PCI_ERR_IRQ_INDEX)
+	if (index != VFIO_PCI_ERR_IRQ_INDEX || start != 0 || count > 1)
 		return -EINVAL;
 
-	/*
-	 * We should sanitize start & count, but that wasn't caught
-	 * originally, so this IRQ index must forever ignore them :-(
-	 */
-
-	return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger, flags, data);
+	return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger,
+					       count, flags, data);
 }
 
 static int vfio_pci_set_req_trigger(struct vfio_pci_device *vdev,
 				    unsigned index, unsigned start,
 				    unsigned count, uint32_t flags, void *data)
 {
-	if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count != 1)
+	if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count > 1)
 		return -EINVAL;
 
-	return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger, flags, data);
+	return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger,
+					       count, flags, data);
 }
 
 int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
--- linux-4.4.0.orig/drivers/vfio/pci/vfio_pci_private.h
+++ linux-4.4.0/drivers/vfio/pci/vfio_pci_private.h
@@ -33,6 +33,11 @@
 	struct irq_bypass_producer	producer;
 };
 
+struct vfio_pci_mmap_vma {
+	struct vm_area_struct	*vma;
+	struct list_head	vma_next;
+};
+
 struct vfio_pci_device {
 	struct pci_dev		*pdev;
 	void __iomem		*barmap[PCI_STD_RESOURCE_END + 1];
@@ -57,10 +62,14 @@
 	bool			bardirty;
 	bool			has_vga;
 	bool			needs_reset;
+	bool			nointx;
 	struct pci_saved_state	*pci_saved_state;
 	int			refcnt;
 	struct eventfd_ctx	*err_trigger;
 	struct eventfd_ctx	*req_trigger;
+	struct mutex		vma_lock;
+	struct list_head	vma_list;
+	struct rw_semaphore	memory_lock;
 };
 
 #define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX)
@@ -91,4 +100,11 @@
 
 extern int vfio_config_init(struct vfio_pci_device *vdev);
 extern void vfio_config_free(struct vfio_pci_device *vdev);
+
+extern bool __vfio_pci_memory_enabled(struct vfio_pci_device *vdev);
+extern void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_device
+						    *vdev);
+extern u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_device *vdev);
+extern void vfio_pci_memory_unlock_and_restore(struct vfio_pci_device *vdev,
+					       u16 cmd);
 #endif /* VFIO_PCI_PRIVATE_H */
--- linux-4.4.0.orig/drivers/vfio/pci/vfio_pci_rdwr.c
+++ linux-4.4.0/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -122,6 +122,7 @@
 	size_t x_start = 0, x_end = 0;
 	resource_size_t end;
 	void __iomem *io;
+	struct resource *res = &vdev->pdev->resource[bar];
 	ssize_t done;
 
 	if (!pci_resource_start(pdev, bar))
@@ -134,6 +135,14 @@
 
 	count = min(count, (size_t)(end - pos));
 
+	if (res->flags & IORESOURCE_MEM) {
+		down_read(&vdev->memory_lock);
+		if (!__vfio_pci_memory_enabled(vdev)) {
+			up_read(&vdev->memory_lock);
+			return -EIO;
+		}
+	}
+
 	if (bar == PCI_ROM_RESOURCE) {
 		/*
 		 * The ROM can fill less space than the BAR, so we start the
@@ -141,20 +150,21 @@
 		 * filling large ROM BARs much faster.
 		 */
 		io = pci_map_rom(pdev, &x_start);
-		if (!io)
-			return -ENOMEM;
+		if (!io) {
+			done = -ENOMEM;
+			goto out;
+		}
 		x_end = end;
 	} else if (!vdev->barmap[bar]) {
-		int ret;
-
-		ret = pci_request_selected_regions(pdev, 1 << bar, "vfio");
-		if (ret)
-			return ret;
+		done = pci_request_selected_regions(pdev, 1 << bar, "vfio");
+		if (done)
+			goto out;
 
 		io = pci_iomap(pdev, bar, 0);
 		if (!io) {
 			pci_release_selected_regions(pdev, 1 << bar);
-			return -ENOMEM;
+			done = -ENOMEM;
+			goto out;
 		}
 
 		vdev->barmap[bar] = io;
@@ -173,6 +183,9 @@
 
 	if (bar == PCI_ROM_RESOURCE)
 		pci_unmap_rom(pdev, io);
+out:
+	if (res->flags & IORESOURCE_MEM)
+		up_read(&vdev->memory_lock);
 
 	return done;
 }
@@ -190,7 +203,10 @@
 	if (!vdev->has_vga)
 		return -EINVAL;
 
-	switch (pos) {
+	if (pos > 0xbfffful)
+		return -EINVAL;
+
+	switch ((u32)pos) {
 	case 0xa0000 ... 0xbffff:
 		count = min(count, (size_t)(0xc0000 - pos));
 		iomem = ioremap_nocache(0xa0000, 0xbffff - 0xa0000 + 1);
--- linux-4.4.0.orig/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
+++ linux-4.4.0/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
@@ -110,7 +110,7 @@
 	usleep_range(10, 15);
 
 	count = 2000;
-	while (count-- && (ioread32(xgmac_regs->ioaddr + DMA_MR) & 1))
+	while (--count && (ioread32(xgmac_regs->ioaddr + DMA_MR) & 1))
 		usleep_range(500, 600);
 
 	if (!count)
--- linux-4.4.0.orig/drivers/vfio/platform/vfio_platform_common.c
+++ linux-4.4.0/drivers/vfio/platform/vfio_platform_common.c
@@ -219,7 +219,8 @@
 		info.num_regions = vdev->num_regions;
 		info.num_irqs = vdev->num_irqs;
 
-		return copy_to_user((void __user *)arg, &info, minsz);
+		return copy_to_user((void __user *)arg, &info, minsz) ?
+			-EFAULT : 0;
 
 	} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
 		struct vfio_region_info info;
@@ -240,7 +241,8 @@
 		info.size = vdev->regions[info.index].size;
 		info.flags = vdev->regions[info.index].flags;
 
-		return copy_to_user((void __user *)arg, &info, minsz);
+		return copy_to_user((void __user *)arg, &info, minsz) ?
+			-EFAULT : 0;
 
 	} else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
 		struct vfio_irq_info info;
@@ -259,7 +261,8 @@
 		info.flags = vdev->irqs[info.index].flags;
 		info.count = vdev->irqs[info.index].count;
 
-		return copy_to_user((void __user *)arg, &info, minsz);
+		return copy_to_user((void __user *)arg, &info, minsz) ?
+			-EFAULT : 0;
 
 	} else if (cmd == VFIO_DEVICE_SET_IRQS) {
 		struct vfio_irq_set hdr;
--- linux-4.4.0.orig/drivers/vfio/vfio.c
+++ linux-4.4.0/drivers/vfio/vfio.c
@@ -296,6 +296,34 @@
 	kref_put_mutex(&group->kref, vfio_group_release, &vfio.group_lock);
 }
 
+struct vfio_group_put_work {
+	struct work_struct work;
+	struct vfio_group *group;
+};
+
+static void vfio_group_put_bg(struct work_struct *work)
+{
+	struct vfio_group_put_work *do_work;
+
+	do_work = container_of(work, struct vfio_group_put_work, work);
+
+	vfio_group_put(do_work->group);
+	kfree(do_work);
+}
+
+static void vfio_group_schedule_put(struct vfio_group *group)
+{
+	struct vfio_group_put_work *do_work;
+
+	do_work = kmalloc(sizeof(*do_work), GFP_KERNEL);
+	if (WARN_ON(!do_work))
+		return;
+
+	INIT_WORK(&do_work->work, vfio_group_put_bg);
+	do_work->group = group;
+	schedule_work(&do_work->work);
+}
+
 /* Assume group_lock or group reference is held */
 static void vfio_group_get(struct vfio_group *group)
 {
@@ -620,7 +648,14 @@
 		break;
 	}
 
-	vfio_group_put(group);
+	/*
+	 * If we're the last reference to the group, the group will be
+	 * released, which includes unregistering the iommu group notifier.
+	 * We hold a read-lock on that notifier list, unregistering needs
+	 * a write-lock... deadlock.  Release our reference asynchronously
+	 * to avoid that situation.
+	 */
+	vfio_group_schedule_put(group);
 	return NOTIFY_OK;
 }
 
@@ -1552,6 +1587,15 @@
 }
 EXPORT_SYMBOL_GPL(vfio_group_put_external_user);
 
+bool vfio_external_group_match_file(struct vfio_group *test_group,
+				    struct file *filep)
+{
+	struct vfio_group *group = filep->private_data;
+
+	return (filep->f_op == &vfio_group_fops) && (group == test_group);
+}
+EXPORT_SYMBOL_GPL(vfio_external_group_match_file);
+
 int vfio_external_user_iommu_id(struct vfio_group *group)
 {
 	return iommu_group_id(group->iommu_group);
--- linux-4.4.0.orig/drivers/vfio/vfio_iommu_spapr_tce.c
+++ linux-4.4.0/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -511,6 +511,12 @@
 	unsigned long hpa;
 	enum dma_data_direction dirtmp;
 
+	if (!tbl->it_userspace) {
+		ret = tce_iommu_userspace_view_alloc(tbl);
+		if (ret)
+			return ret;
+	}
+
 	for (i = 0; i < pages; ++i) {
 		struct mm_iommu_table_group_mem_t *mem = NULL;
 		unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl,
@@ -584,15 +590,6 @@
 	WARN_ON(!ret && !(*ptbl)->it_ops->free);
 	WARN_ON(!ret && ((*ptbl)->it_allocated_size != table_size));
 
-	if (!ret && container->v2) {
-		ret = tce_iommu_userspace_view_alloc(*ptbl);
-		if (ret)
-			(*ptbl)->it_ops->free(*ptbl);
-	}
-
-	if (ret)
-		decrement_locked_vm(table_size >> PAGE_SHIFT);
-
 	return ret;
 }
 
@@ -1064,10 +1061,7 @@
 		if (!tbl || !tbl->it_map)
 			continue;
 
-		rc = tce_iommu_userspace_view_alloc(tbl);
-		if (!rc)
-			rc = iommu_take_ownership(tbl);
-
+		rc = iommu_take_ownership(tbl);
 		if (rc) {
 			for (j = 0; j < i; ++j)
 				iommu_release_ownership(
@@ -1169,6 +1163,10 @@
 	/* pr_debug("tce_vfio: Attaching group #%u to iommu %p\n",
 			iommu_group_id(iommu_group), iommu_group); */
 	table_group = iommu_group_get_iommudata(iommu_group);
+	if (!table_group) {
+		ret = -ENODEV;
+		goto unlock_exit;
+	}
 
 	if (tce_groups_attached(container) && (!table_group->ops ||
 			!table_group->ops->take_ownership ||
--- linux-4.4.0.orig/drivers/vfio/vfio_iommu_type1.c
+++ linux-4.4.0/drivers/vfio/vfio_iommu_type1.c
@@ -53,10 +53,16 @@
 MODULE_PARM_DESC(disable_hugepages,
 		 "Disable VFIO IOMMU support for IOMMU hugepages.");
 
+static unsigned int dma_entry_limit __read_mostly = U16_MAX;
+module_param_named(dma_entry_limit, dma_entry_limit, uint, 0644);
+MODULE_PARM_DESC(dma_entry_limit,
+		 "Maximum number of user DMA mappings per container (65535).");
+
 struct vfio_iommu {
 	struct list_head	domain_list;
 	struct mutex		lock;
 	struct rb_root		dma_list;
+	unsigned int		dma_avail;
 	bool			v2;
 	bool			nesting;
 };
@@ -130,57 +136,34 @@
 	rb_erase(&old->node, &iommu->dma_list);
 }
 
-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)
+static int vfio_lock_acct(long npage, bool *lock_cap)
 {
-	struct vwork *vwork = container_of(work, struct vwork, work);
-	struct mm_struct *mm;
+	int ret = 0;
 
-	mm = vwork->mm;
-	down_write(&mm->mmap_sem);
-	mm->locked_vm += vwork->npage;
-	up_write(&mm->mmap_sem);
-	mmput(mm);
-	kfree(vwork);
-}
+	if (!npage)
+		return 0;
 
-static void vfio_lock_acct(long npage)
-{
-	struct vwork *vwork;
-	struct mm_struct *mm;
+	if (!current->mm)
+		return -ESRCH; /* process exited */
 
-	if (!current->mm || !npage)
-		return; /* process exited or nothing to do */
+	down_write(&current->mm->mmap_sem);
+	if (npage > 0) {
+		if (lock_cap ? !*lock_cap : !capable(CAP_IPC_LOCK)) {
+			unsigned long limit;
 
-	if (down_write_trylock(&current->mm->mmap_sem)) {
-		current->mm->locked_vm += npage;
-		up_write(&current->mm->mmap_sem);
-		return;
-	}
+			limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
 
-	/*
-	 * 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;
+			if (current->mm->locked_vm + npage > limit)
+				ret = -ENOMEM;
+		}
 	}
-	INIT_WORK(&vwork->work, vfio_lock_acct_bg);
-	vwork->mm = mm;
-	vwork->npage = npage;
-	schedule_work(&vwork->work);
+
+	if (!ret)
+		current->mm->locked_vm += npage;
+
+	up_write(&current->mm->mmap_sem);
+
+	return ret;
 }
 
 /*
@@ -228,6 +211,26 @@
 	return 0;
 }
 
+static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm,
+			    unsigned long vaddr, unsigned long *pfn,
+			    bool write_fault)
+{
+	int ret;
+
+	ret = follow_pfn(vma, vaddr, pfn);
+	if (ret) {
+		ret = fixup_user_fault(NULL, mm, vaddr,
+				       (write_fault ?  FAULT_FLAG_WRITE : 0));
+
+		if (ret)
+			return ret;
+
+		ret = follow_pfn(vma, vaddr, pfn);
+	}
+
+	return ret;
+}
+
 static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn)
 {
 	struct page *page[1];
@@ -241,12 +244,16 @@
 
 	down_read(&current->mm->mmap_sem);
 
+retry:
 	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;
+		ret = follow_fault_pfn(vma, current->mm, vaddr, pfn, prot & IOMMU_WRITE);
+		if (ret == -EAGAIN)
+			goto retry;
+
+		if (!ret && !is_invalid_reserved_pfn(*pfn))
+			ret = -EFAULT;
 	}
 
 	up_read(&current->mm->mmap_sem);
@@ -262,9 +269,9 @@
 static long vfio_pin_pages(unsigned long vaddr, long npage,
 			   int prot, unsigned long *pfn_base)
 {
-	unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+	unsigned long pfn = 0, limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
 	bool lock_cap = capable(CAP_IPC_LOCK);
-	long ret, i;
+	long ret, i = 1;
 	bool rsvd;
 
 	if (!current->mm)
@@ -283,16 +290,11 @@
 		return -ENOMEM;
 	}
 
-	if (unlikely(disable_hugepages)) {
-		if (!rsvd)
-			vfio_lock_acct(1);
-		return 1;
-	}
+	if (unlikely(disable_hugepages))
+		goto out;
 
 	/* Lock all the consecutive pages from pfn_base */
-	for (i = 1, vaddr += PAGE_SIZE; i < npage; i++, vaddr += PAGE_SIZE) {
-		unsigned long pfn = 0;
-
+	for (vaddr += PAGE_SIZE; i < npage; i++, vaddr += PAGE_SIZE) {
 		ret = vaddr_get_pfn(vaddr, prot, &pfn);
 		if (ret)
 			break;
@@ -308,12 +310,24 @@
 			put_pfn(pfn, prot);
 			pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
 				__func__, limit << PAGE_SHIFT);
-			break;
+			ret = -ENOMEM;
+			goto unpin_out;
 		}
 	}
 
+out:
 	if (!rsvd)
-		vfio_lock_acct(i);
+		ret = vfio_lock_acct(i, &lock_cap);
+
+unpin_out:
+	if (ret) {
+		if (!rsvd) {
+			for (pfn = *pfn_base ; i ; pfn++, i--)
+				put_pfn(pfn, prot);
+		}
+
+		return ret;
+	}
 
 	return i;
 }
@@ -328,7 +342,7 @@
 		unlocked += put_pfn(pfn++, prot);
 
 	if (do_accounting)
-		vfio_lock_acct(-unlocked);
+		vfio_lock_acct(-unlocked, NULL);
 
 	return unlocked;
 }
@@ -390,7 +404,7 @@
 		cond_resched();
 	}
 
-	vfio_lock_acct(-unlocked);
+	vfio_lock_acct(-unlocked, NULL);
 }
 
 static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
@@ -398,6 +412,7 @@
 	vfio_unmap_unpin(iommu, dma);
 	vfio_unlink_dma(iommu, dma);
 	kfree(dma);
+	iommu->dma_avail++;
 }
 
 static unsigned long vfio_pgsize_bitmap(struct vfio_iommu *iommu)
@@ -598,12 +613,18 @@
 		return -EEXIST;
 	}
 
+	if (!iommu->dma_avail) {
+		mutex_unlock(&iommu->lock);
+		return -ENOSPC;
+	}
+
 	dma = kzalloc(sizeof(*dma), GFP_KERNEL);
 	if (!dma) {
 		mutex_unlock(&iommu->lock);
 		return -ENOMEM;
 	}
 
+	iommu->dma_avail--;
 	dma->iova = iova;
 	dma->vaddr = vaddr;
 	dma->prot = prot;
@@ -919,6 +940,7 @@
 
 	INIT_LIST_HEAD(&iommu->domain_list);
 	iommu->dma_list = RB_ROOT;
+	iommu->dma_avail = dma_entry_limit;
 	mutex_init(&iommu->lock);
 
 	return iommu;
@@ -999,7 +1021,8 @@
 
 		info.iova_pgsizes = vfio_pgsize_bitmap(iommu);
 
-		return copy_to_user((void __user *)arg, &info, minsz);
+		return copy_to_user((void __user *)arg, &info, minsz) ?
+			-EFAULT : 0;
 
 	} else if (cmd == VFIO_IOMMU_MAP_DMA) {
 		struct vfio_iommu_type1_dma_map map;
@@ -1032,7 +1055,8 @@
 		if (ret)
 			return ret;
 
-		return copy_to_user((void __user *)arg, &unmap, minsz);
+		return copy_to_user((void __user *)arg, &unmap, minsz) ?
+			-EFAULT : 0;
 	}
 
 	return -ENOTTY;
--- linux-4.4.0.orig/drivers/vfio/virqfd.c
+++ linux-4.4.0/drivers/vfio/virqfd.c
@@ -104,6 +104,13 @@
 		virqfd->thread(virqfd->opaque, virqfd->data);
 }
 
+static void virqfd_flush_inject(struct work_struct *work)
+{
+	struct virqfd *virqfd = container_of(work, struct virqfd, flush_inject);
+
+	flush_work(&virqfd->inject);
+}
+
 int vfio_virqfd_enable(void *opaque,
 		       int (*handler)(void *, void *),
 		       void (*thread)(void *, void *),
@@ -127,6 +134,7 @@
 
 	INIT_WORK(&virqfd->shutdown, virqfd_shutdown);
 	INIT_WORK(&virqfd->inject, virqfd_inject);
+	INIT_WORK(&virqfd->flush_inject, virqfd_flush_inject);
 
 	irqfd = fdget(fd);
 	if (!irqfd.file) {
@@ -217,6 +225,19 @@
 }
 EXPORT_SYMBOL_GPL(vfio_virqfd_disable);
 
+void vfio_virqfd_flush_thread(struct virqfd **pvirqfd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&virqfd_lock, flags);
+	if (*pvirqfd && (*pvirqfd)->thread)
+		queue_work(vfio_irqfd_cleanup_wq, &(*pvirqfd)->flush_inject);
+	spin_unlock_irqrestore(&virqfd_lock, flags);
+
+	flush_workqueue(vfio_irqfd_cleanup_wq);
+}
+EXPORT_SYMBOL_GPL(vfio_virqfd_flush_thread);
+
 module_init(vfio_virqfd_init);
 module_exit(vfio_virqfd_exit);
 
--- linux-4.4.0.orig/drivers/vhost/net.c
+++ linux-4.4.0/drivers/vhost/net.c
@@ -30,7 +30,7 @@
 
 #include "vhost.h"
 
-static int experimental_zcopytx = 1;
+static int experimental_zcopytx = 0;
 module_param(experimental_zcopytx, int, 0444);
 MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
 		                       " 1 -Enable; 0 - Disable");
@@ -39,6 +39,12 @@
  * Using this limit prevents one virtqueue from starving others. */
 #define VHOST_NET_WEIGHT 0x80000
 
+/* Max number of packets transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others with small
+ * pkts.
+ */
+#define VHOST_NET_PKT_WEIGHT 256
+
 /* MAX number of TX used buffers for outstanding zerocopy */
 #define VHOST_MAX_PEND 128
 #define VHOST_GOODCOPY_LEN 256
@@ -287,6 +293,15 @@
 	rcu_read_unlock_bh();
 }
 
+static bool vhost_exceeds_maxpend(struct vhost_net *net)
+{
+	struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX];
+	struct vhost_virtqueue *vq = &nvq->vq;
+
+	return (nvq->upend_idx + UIO_MAXIOV - nvq->done_idx) % UIO_MAXIOV >
+	       min_t(unsigned int, VHOST_MAX_PEND, vq->num >> 2);
+}
+
 /* Expects to be always run from workqueue - which acts as
  * read-size critical section for our kind of RCU. */
 static void handle_tx(struct vhost_net *net)
@@ -307,7 +322,9 @@
 	size_t hdr_size;
 	struct socket *sock;
 	struct vhost_net_ubuf_ref *uninitialized_var(ubufs);
+	struct ubuf_info *ubuf;
 	bool zcopy, zcopy_used;
+	int sent_pkts = 0;
 
 	mutex_lock(&vq->mutex);
 	sock = vq->private_data;
@@ -319,17 +336,11 @@
 	hdr_size = nvq->vhost_hlen;
 	zcopy = nvq->ubufs;
 
-	for (;;) {
+	do {
 		/* Release DMAs done buffers first */
 		if (zcopy)
 			vhost_zerocopy_signal_used(net, vq);
 
-		/* If more outstanding DMAs, queue the work.
-		 * Handle upend_idx wrap around
-		 */
-		if (unlikely((nvq->upend_idx + vq->num - VHOST_MAX_PEND)
-			      % UIO_MAXIOV == nvq->done_idx))
-			break;
 
 		head = vhost_get_vq_desc(vq, vq->iov,
 					 ARRAY_SIZE(vq->iov),
@@ -365,15 +376,12 @@
 		len = msg_data_left(&msg);
 
 		zcopy_used = zcopy && len >= VHOST_GOODCOPY_LEN
-				   && (nvq->upend_idx + 1) % UIO_MAXIOV !=
-				      nvq->done_idx
+				   && !vhost_exceeds_maxpend(net)
 				   && vhost_net_tx_select_zcopy(net);
 
 		/* use msg_control to pass vhost zerocopy ubuf info to skb */
 		if (zcopy_used) {
-			struct ubuf_info *ubuf;
 			ubuf = nvq->ubuf_info + nvq->upend_idx;
-
 			vq->heads[nvq->upend_idx].id = cpu_to_vhost32(vq, head);
 			vq->heads[nvq->upend_idx].len = VHOST_DMA_IN_PROGRESS;
 			ubuf->callback = vhost_zerocopy_callback;
@@ -388,11 +396,21 @@
 			msg.msg_control = NULL;
 			ubufs = NULL;
 		}
+		total_len += len;
+		if (total_len < VHOST_NET_WEIGHT &&
+		    !vhost_vq_avail_empty(&net->dev, vq) &&
+		    likely(!vhost_exceeds_maxpend(net))) {
+			msg.msg_flags |= MSG_MORE;
+		} else {
+			msg.msg_flags &= ~MSG_MORE;
+		}
+
 		/* TODO: Check specific error and bomb out unless ENOBUFS? */
 		err = sock->ops->sendmsg(sock, &msg, len);
 		if (unlikely(err < 0)) {
 			if (zcopy_used) {
-				vhost_net_ubuf_put(ubufs);
+				if (vq->heads[ubuf->desc].len == VHOST_DMA_IN_PROGRESS)
+					vhost_net_ubuf_put(ubufs);
 				nvq->upend_idx = ((unsigned)nvq->upend_idx - 1)
 					% UIO_MAXIOV;
 			}
@@ -406,13 +424,8 @@
 			vhost_add_used_and_signal(&net->dev, vq, head, 0);
 		else
 			vhost_zerocopy_signal_used(net, vq);
-		total_len += len;
 		vhost_net_tx_packet(net);
-		if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
-			vhost_poll_queue(&vq->poll);
-			break;
-		}
-	}
+	} while (likely(!vhost_exceeds_weight(vq, ++sent_pkts, total_len)));
 out:
 	mutex_unlock(&vq->mutex);
 }
@@ -539,6 +552,7 @@
 	struct socket *sock;
 	struct iov_iter fixup;
 	__virtio16 num_buffers;
+	int recv_pkts = 0;
 
 	mutex_lock(&vq->mutex);
 	sock = vq->private_data;
@@ -553,7 +567,11 @@
 		vq->log : NULL;
 	mergeable = vhost_has_feature(vq, VIRTIO_NET_F_MRG_RXBUF);
 
-	while ((sock_len = peek_head_len(sock->sk))) {
+	do {
+		sock_len = peek_head_len(sock->sk);
+
+		if (!sock_len)
+			break;
 		sock_len += sock_hlen;
 		vhost_len = sock_len + vhost_hlen;
 		headcount = get_rx_bufs(vq, vq->heads, vhost_len,
@@ -631,11 +649,8 @@
 		if (unlikely(vq_log))
 			vhost_log_write(vq, vq_log, log, vhost_len);
 		total_len += vhost_len;
-		if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
-			vhost_poll_queue(&vq->poll);
-			break;
-		}
-	}
+	} while (likely(!vhost_exceeds_weight(vq, ++recv_pkts, total_len)));
+
 out:
 	mutex_unlock(&vq->mutex);
 }
@@ -704,7 +719,8 @@
 		n->vqs[i].vhost_hlen = 0;
 		n->vqs[i].sock_hlen = 0;
 	}
-	vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX);
+	vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX,
+		       VHOST_NET_PKT_WEIGHT, VHOST_NET_WEIGHT);
 
 	vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT, dev);
 	vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN, dev);
@@ -810,11 +826,7 @@
 
 static struct socket *get_raw_socket(int fd)
 {
-	struct {
-		struct sockaddr_ll sa;
-		char  buf[MAX_ADDR_LEN];
-	} uaddr;
-	int uaddr_len = sizeof uaddr, r;
+	int r;
 	struct socket *sock = sockfd_lookup(fd, &r);
 
 	if (!sock)
@@ -826,12 +838,7 @@
 		goto err;
 	}
 
-	r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
-			       &uaddr_len, 0);
-	if (r)
-		goto err;
-
-	if (uaddr.sa.sll_family != AF_PACKET) {
+	if (sock->sk->sk_family != AF_PACKET) {
 		r = -EPFNOSUPPORT;
 		goto err;
 	}
@@ -955,7 +962,8 @@
 	if (ubufs)
 		vhost_net_ubuf_put_wait_and_free(ubufs);
 err_ubufs:
-	sockfd_put(sock);
+	if (sock)
+		sockfd_put(sock);
 err_vq:
 	mutex_unlock(&vq->mutex);
 err:
@@ -981,6 +989,7 @@
 	}
 	vhost_net_stop(n, &tx_sock, &rx_sock);
 	vhost_net_flush(n);
+	vhost_dev_stop(&n->dev);
 	vhost_dev_reset_owner(&n->dev, memory);
 	vhost_net_vq_reset(n);
 done:
--- linux-4.4.0.orig/drivers/vhost/scsi.c
+++ linux-4.4.0/drivers/vhost/scsi.c
@@ -58,6 +58,12 @@
 #define VHOST_SCSI_PREALLOC_UPAGES 2048
 #define VHOST_SCSI_PREALLOC_PROT_SGLS 512
 
+/* Max number of requests before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others with
+ * request.
+ */
+#define VHOST_SCSI_WEIGHT 256
+
 struct vhost_scsi_inflight {
 	/* Wait for the flush operation to finish */
 	struct completion comp;
@@ -88,7 +94,7 @@
 	struct scatterlist *tvc_prot_sgl;
 	struct page **tvc_upages;
 	/* Pointer to response header iovec */
-	struct iovec *tvc_resp_iov;
+	struct iovec tvc_resp_iov;
 	/* Pointer to vhost_scsi for our device */
 	struct vhost_scsi *tvc_vhost;
 	/* Pointer to vhost_virtqueue for the cmd */
@@ -557,7 +563,7 @@
 		memcpy(v_rsp.sense, cmd->tvc_sense_buf,
 		       se_cmd->scsi_sense_length);
 
-		iov_iter_init(&iov_iter, READ, cmd->tvc_resp_iov,
+		iov_iter_init(&iov_iter, READ, &cmd->tvc_resp_iov,
 			      cmd->tvc_in_iovs, sizeof(v_rsp));
 		ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
 		if (likely(ret == sizeof(v_rsp))) {
@@ -703,6 +709,7 @@
 		      struct scatterlist *sg, int sg_count)
 {
 	size_t off = iter->iov_offset;
+	struct scatterlist *p = sg;
 	int i, ret;
 
 	for (i = 0; i < iter->nr_segs; i++) {
@@ -711,8 +718,8 @@
 
 		ret = vhost_scsi_map_to_sgl(cmd, base, len, sg, write);
 		if (ret < 0) {
-			for (i = 0; i < sg_count; i++) {
-				struct page *page = sg_page(&sg[i]);
+			while (p < sg) {
+				struct page *page = sg_page(p++);
 				if (page)
 					put_page(page);
 			}
@@ -854,7 +861,7 @@
 	u64 tag;
 	u32 exp_data_len, data_direction;
 	unsigned out, in;
-	int head, ret, prot_bytes;
+	int head, ret, prot_bytes, c = 0;
 	size_t req_size, rsp_size = sizeof(struct virtio_scsi_cmd_resp);
 	size_t out_size, in_size;
 	u16 lun;
@@ -873,7 +880,7 @@
 
 	vhost_disable_notify(&vs->dev, vq);
 
-	for (;;) {
+	do {
 		head = vhost_get_vq_desc(vq, vq->iov,
 					 ARRAY_SIZE(vq->iov), &out, &in,
 					 NULL, NULL);
@@ -1008,7 +1015,8 @@
 				prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesin);
 			}
 			/*
-			 * Set prot_iter to data_iter, and advance past any
+			 * Set prot_iter to data_iter and truncate it to
+			 * prot_bytes, and advance data_iter past any
 			 * preceeding prot_bytes that may be present.
 			 *
 			 * Also fix up the exp_data_len to reflect only the
@@ -1017,6 +1025,7 @@
 			if (prot_bytes) {
 				exp_data_len -= prot_bytes;
 				prot_iter = data_iter;
+				iov_iter_truncate(&prot_iter, prot_bytes);
 				iov_iter_advance(&data_iter, prot_bytes);
 			}
 			tag = vhost64_to_cpu(vq, v_req_pi.tag);
@@ -1054,7 +1063,7 @@
 		}
 		cmd->tvc_vhost = vs;
 		cmd->tvc_vq = vq;
-		cmd->tvc_resp_iov = &vq->iov[out];
+		cmd->tvc_resp_iov = vq->iov[out];
 		cmd->tvc_in_iovs = in;
 
 		pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
@@ -1087,7 +1096,7 @@
 		 */
 		INIT_WORK(&cmd->work, vhost_scsi_submission_work);
 		queue_work(vhost_scsi_workqueue, &cmd->work);
-	}
+	} while (likely(!vhost_exceeds_weight(vq, ++c, 0)));
 out:
 	mutex_unlock(&vq->mutex);
 }
@@ -1440,7 +1449,7 @@
 		vqs[i] = &vs->vqs[i].vq;
 		vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
 	}
-	vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ);
+	vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, VHOST_SCSI_WEIGHT, 0);
 
 	vhost_scsi_init_inflight(vs, NULL);
 
--- linux-4.4.0.orig/drivers/vhost/test.c
+++ linux-4.4.0/drivers/vhost/test.c
@@ -23,6 +23,12 @@
  * Using this limit prevents one virtqueue from starving others. */
 #define VHOST_TEST_WEIGHT 0x80000
 
+/* Max number of packets transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others with
+ * pkts.
+ */
+#define VHOST_TEST_PKT_WEIGHT 256
+
 enum {
 	VHOST_TEST_VQ = 0,
 	VHOST_TEST_VQ_MAX = 1,
@@ -81,10 +87,8 @@
 		}
 		vhost_add_used_and_signal(&n->dev, vq, head, 0);
 		total_len += len;
-		if (unlikely(total_len >= VHOST_TEST_WEIGHT)) {
-			vhost_poll_queue(&vq->poll);
+		if (unlikely(vhost_exceeds_weight(vq, 0, total_len)))
 			break;
-		}
 	}
 
 	mutex_unlock(&vq->mutex);
@@ -116,7 +120,8 @@
 	dev = &n->dev;
 	vqs[VHOST_TEST_VQ] = &n->vqs[VHOST_TEST_VQ];
 	n->vqs[VHOST_TEST_VQ].handle_kick = handle_vq_kick;
-	vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX);
+	vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX,
+		       VHOST_TEST_PKT_WEIGHT, VHOST_TEST_WEIGHT);
 
 	f->private_data = n;
 
--- linux-4.4.0.orig/drivers/vhost/vhost.c
+++ linux-4.4.0/drivers/vhost/vhost.c
@@ -27,6 +27,7 @@
 #include <linux/cgroup.h>
 #include <linux/module.h>
 #include <linux/sort.h>
+#include <linux/nospec.h>
 
 #include "vhost.h"
 
@@ -173,8 +174,7 @@
 	if (mask)
 		vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
 	if (mask & POLLERR) {
-		if (poll->wqh)
-			remove_wait_queue(poll->wqh, &poll->wait);
+		vhost_poll_stop(poll);
 		ret = -EINVAL;
 	}
 
@@ -370,8 +370,24 @@
 		vhost_vq_free_iovecs(dev->vqs[i]);
 }
 
+bool vhost_exceeds_weight(struct vhost_virtqueue *vq,
+			  int pkts, int total_len)
+{
+	struct vhost_dev *dev = vq->dev;
+
+	if ((dev->byte_weight && total_len >= dev->byte_weight) ||
+	    pkts >= dev->weight) {
+		vhost_poll_queue(&vq->poll);
+		return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(vhost_exceeds_weight);
+
 void vhost_dev_init(struct vhost_dev *dev,
-		    struct vhost_virtqueue **vqs, int nvqs)
+		    struct vhost_virtqueue **vqs, int nvqs,
+		    int weight, int byte_weight)
 {
 	struct vhost_virtqueue *vq;
 	int i;
@@ -386,6 +402,8 @@
 	spin_lock_init(&dev->work_lock);
 	INIT_LIST_HEAD(&dev->work_list);
 	dev->worker = NULL;
+	dev->weight = weight;
+	dev->byte_weight = byte_weight;
 
 	for (i = 0; i < dev->nvqs; ++i) {
 		vq = dev->vqs[i];
@@ -749,6 +767,7 @@
 	if (idx >= d->nvqs)
 		return -ENOBUFS;
 
+	idx = array_index_nospec(idx, d->nvqs);
 	vq = d->vqs[idx];
 
 	mutex_lock(&vq->mutex);
@@ -1305,7 +1324,7 @@
 		/* If this is an input descriptor, increment that count. */
 		if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) {
 			*in_num += ret;
-			if (unlikely(log)) {
+			if (unlikely(log && ret)) {
 				log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
 				log[*log_num].len = vhost32_to_cpu(vq, desc.len);
 				++*log_num;
@@ -1434,7 +1453,7 @@
 			/* If this is an input descriptor,
 			 * increment that count. */
 			*in_num += ret;
-			if (unlikely(log)) {
+			if (unlikely(log && ret)) {
 				log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
 				log[*log_num].len = vhost32_to_cpu(vq, desc.len);
 				++*log_num;
@@ -1549,6 +1568,8 @@
 		return -EFAULT;
 	}
 	if (unlikely(vq->log_used)) {
+		/* Make sure used idx is seen before log. */
+		smp_wmb();
 		/* Log used index update. */
 		log_write(vq->log_base,
 			  vq->log_addr + offsetof(struct vring_used, idx),
@@ -1626,6 +1647,20 @@
 }
 EXPORT_SYMBOL_GPL(vhost_add_used_and_signal_n);
 
+/* return true if we're sure that avaiable ring is empty */
+bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+{
+	__virtio16 avail_idx;
+	int r;
+
+	r = __get_user(avail_idx, &vq->avail->idx);
+	if (r)
+		return false;
+
+	return vhost16_to_cpu(vq, avail_idx) == vq->avail_idx;
+}
+EXPORT_SYMBOL_GPL(vhost_vq_avail_empty);
+
 /* OK, now we need to know about added descriptors. */
 bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
--- linux-4.4.0.orig/drivers/vhost/vhost.h
+++ linux-4.4.0/drivers/vhost/vhost.h
@@ -127,9 +127,13 @@
 	spinlock_t work_lock;
 	struct list_head work_list;
 	struct task_struct *worker;
+	int weight;
+	int byte_weight;
 };
 
-void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs);
+bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len);
+void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs,
+		    int nvqs, int weight, int byte_weight);
 long vhost_dev_set_owner(struct vhost_dev *dev);
 bool vhost_dev_has_owner(struct vhost_dev *dev);
 long vhost_dev_check_owner(struct vhost_dev *);
@@ -158,6 +162,7 @@
 			       struct vring_used_elem *heads, unsigned count);
 void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
 void vhost_disable_notify(struct vhost_dev *, struct vhost_virtqueue *);
+bool vhost_vq_avail_empty(struct vhost_dev *, struct vhost_virtqueue *);
 bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *);
 
 int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
--- linux-4.4.0.orig/drivers/vhost/vringh.c
+++ linux-4.4.0/drivers/vhost/vringh.c
@@ -272,13 +272,14 @@
 	desc_max = vrh->vring.num;
 	up_next = -1;
 
+	/* You must want something! */
+	if (WARN_ON(!riov && !wiov))
+		return -EINVAL;
+
 	if (riov)
 		riov->i = riov->used = 0;
-	else if (wiov)
+	if (wiov)
 		wiov->i = wiov->used = 0;
-	else
-		/* You must want something! */
-		BUG();
 
 	for (;;) {
 		void *addr;
--- linux-4.4.0.orig/drivers/video/backlight/adp5520_bl.c
+++ linux-4.4.0/drivers/video/backlight/adp5520_bl.c
@@ -332,10 +332,18 @@
 	}
 
 	platform_set_drvdata(pdev, bl);
-	ret |= adp5520_bl_setup(bl);
+	ret = adp5520_bl_setup(bl);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup\n");
+		if (data->pdata->en_ambl_sens)
+			sysfs_remove_group(&bl->dev.kobj,
+					&adp5520_bl_attr_group);
+		return ret;
+	}
+
 	backlight_update_status(bl);
 
-	return ret;
+	return 0;
 }
 
 static int adp5520_bl_remove(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/video/backlight/as3711_bl.c
+++ linux-4.4.0/drivers/video/backlight/as3711_bl.c
@@ -262,10 +262,10 @@
 static int as3711_backlight_parse_dt(struct device *dev)
 {
 	struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
-	struct device_node *bl =
-		of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
+	struct device_node *bl, *fb;
 	int ret;
 
+	bl = of_get_child_by_name(dev->parent->of_node, "backlight");
 	if (!bl) {
 		dev_dbg(dev, "backlight node not found\n");
 		return -ENODEV;
@@ -279,7 +279,7 @@
 		if (pdata->su1_max_uA <= 0)
 			ret = -EINVAL;
 		if (ret < 0)
-			return ret;
+			goto err_put_bl;
 	}
 
 	fb = of_parse_phandle(bl, "su2-dev", 0);
@@ -292,7 +292,7 @@
 		if (pdata->su2_max_uA <= 0)
 			ret = -EINVAL;
 		if (ret < 0)
-			return ret;
+			goto err_put_bl;
 
 		if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
 			pdata->su2_feedback = AS3711_SU2_VOLTAGE;
@@ -314,8 +314,10 @@
 			pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
 			count++;
 		}
-		if (count != 1)
-			return -EINVAL;
+		if (count != 1) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 
 		count = 0;
 		if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
@@ -334,8 +336,10 @@
 			pdata->su2_fbprot = AS3711_SU2_GPIO4;
 			count++;
 		}
-		if (count != 1)
-			return -EINVAL;
+		if (count != 1) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 
 		count = 0;
 		if (of_find_property(bl, "su2-auto-curr1", NULL)) {
@@ -355,11 +359,20 @@
 		 * At least one su2-auto-curr* must be specified iff
 		 * AS3711_SU2_CURR_AUTO is used
 		 */
-		if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO))
-			return -EINVAL;
+		if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 	}
 
+	of_node_put(bl);
+
 	return 0;
+
+err_put_bl:
+	of_node_put(bl);
+
+	return ret;
 }
 
 static int as3711_backlight_probe(struct platform_device *pdev)
--- linux-4.4.0.orig/drivers/video/backlight/lcd.c
+++ linux-4.4.0/drivers/video/backlight/lcd.c
@@ -226,6 +226,8 @@
 	dev_set_name(&new_ld->dev, "%s", name);
 	dev_set_drvdata(&new_ld->dev, devdata);
 
+	new_ld->ops = ops;
+
 	rc = device_register(&new_ld->dev);
 	if (rc) {
 		put_device(&new_ld->dev);
@@ -238,8 +240,6 @@
 		return ERR_PTR(rc);
 	}
 
-	new_ld->ops = ops;
-
 	return new_ld;
 }
 EXPORT_SYMBOL(lcd_device_register);
--- linux-4.4.0.orig/drivers/video/backlight/lm3630a_bl.c
+++ linux-4.4.0/drivers/video/backlight/lm3630a_bl.c
@@ -200,7 +200,7 @@
 				      LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE);
 	if (ret < 0)
 		goto out_i2c_err;
-	return bl->props.brightness;
+	return 0;
 
 out_i2c_err:
 	dev_err(pchip->dev, "i2c failed to access\n");
@@ -277,7 +277,7 @@
 				      LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE);
 	if (ret < 0)
 		goto out_i2c_err;
-	return bl->props.brightness;
+	return 0;
 
 out_i2c_err:
 	dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
--- linux-4.4.0.orig/drivers/video/backlight/lm3639_bl.c
+++ linux-4.4.0/drivers/video/backlight/lm3639_bl.c
@@ -400,10 +400,8 @@
 
 	regmap_write(pchip->regmap, REG_ENABLE, 0x00);
 
-	if (&pchip->cdev_torch)
-		led_classdev_unregister(&pchip->cdev_torch);
-	if (&pchip->cdev_flash)
-		led_classdev_unregister(&pchip->cdev_flash);
+	led_classdev_unregister(&pchip->cdev_torch);
+	led_classdev_unregister(&pchip->cdev_flash);
 	if (pchip->bled)
 		device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
 	return 0;
--- linux-4.4.0.orig/drivers/video/backlight/max8925_bl.c
+++ linux-4.4.0/drivers/video/backlight/max8925_bl.c
@@ -116,7 +116,7 @@
 	if (!pdata)
 		return;
 
-	np = of_find_node_by_name(nproot, "backlight");
+	np = of_get_child_by_name(nproot, "backlight");
 	if (!np) {
 		dev_err(&pdev->dev, "failed to find backlight node\n");
 		return;
@@ -125,6 +125,8 @@
 	if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
 		pdata->dual_string = val;
 
+	of_node_put(np);
+
 	pdev->dev.platform_data = pdata;
 }
 
--- linux-4.4.0.orig/drivers/video/backlight/pwm_bl.c
+++ linux-4.4.0/drivers/video/backlight/pwm_bl.c
@@ -79,14 +79,17 @@
 static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness)
 {
 	unsigned int lth = pb->lth_brightness;
-	int duty_cycle;
+	u64 duty_cycle;
 
 	if (pb->levels)
 		duty_cycle = pb->levels[brightness];
 	else
 		duty_cycle = brightness;
 
-	return (duty_cycle * (pb->period - lth) / pb->scale) + lth;
+	duty_cycle *= pb->period - lth;
+	do_div(duty_cycle, pb->scale);
+
+	return duty_cycle + lth;
 }
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
--- linux-4.4.0.orig/drivers/video/backlight/sky81452-backlight.c
+++ linux-4.4.0/drivers/video/backlight/sky81452-backlight.c
@@ -207,6 +207,7 @@
 					num_entry);
 		if (ret < 0) {
 			dev_err(dev, "led-sources node is invalid.\n");
+			of_node_put(np);
 			return ERR_PTR(-EINVAL);
 		}
 
--- linux-4.4.0.orig/drivers/video/backlight/tps65217_bl.c
+++ linux-4.4.0/drivers/video/backlight/tps65217_bl.c
@@ -184,11 +184,11 @@
 tps65217_bl_parse_dt(struct platform_device *pdev)
 {
 	struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
-	struct device_node *node = of_node_get(tps->dev->of_node);
+	struct device_node *node;
 	struct tps65217_bl_pdata *pdata, *err;
 	u32 val;
 
-	node = of_find_node_by_name(node, "backlight");
+	node = of_get_child_by_name(tps->dev->of_node, "backlight");
 	if (!node)
 		return ERR_PTR(-ENODEV);
 
--- linux-4.4.0.orig/drivers/video/console/Kconfig
+++ linux-4.4.0/drivers/video/console/Kconfig
@@ -22,31 +22,6 @@
 
 	  Say Y.
 
-config VGACON_SOFT_SCROLLBACK
-       bool "Enable Scrollback Buffer in System RAM"
-       depends on VGA_CONSOLE
-       default n
-       help
-         The scrollback buffer of the standard VGA console is located in
-	 the VGA RAM.  The size of this RAM is fixed and is quite small.
-	 If you require a larger scrollback buffer, this can be placed in
-	 System RAM which is dynamically allocated during initialization.
-	 Placing the scrollback buffer in System RAM will slightly slow
-	 down the console.
-
-	 If you want this feature, say 'Y' here and enter the amount of
-	 RAM to allocate for this buffer.  If unsure, say 'N'.
-
-config VGACON_SOFT_SCROLLBACK_SIZE
-       int "Scrollback Buffer Size (in KB)"
-       depends on VGACON_SOFT_SCROLLBACK
-       range 1 1024
-       default "64"
-       help
-         Enter the amount of System RAM to allocate for the scrollback
-	 buffer.  Each 64KB will give you approximately 16 80x25
-	 screenfuls of scrollback buffer
-
 config MDA_CONSOLE
 	depends on !M68K && !PARISC && ISA
 	tristate "MDA text console (dual-headed)"
--- linux-4.4.0.orig/drivers/video/console/bitblit.c
+++ linux-4.4.0/drivers/video/console/bitblit.c
@@ -216,7 +216,7 @@
 	region.color = 0;
 	region.rop = ROP_COPY;
 
-	if (rw && !bottom_only) {
+	if ((int) rw > 0 && !bottom_only) {
 		region.dx = info->var.xoffset + rs;
 		region.dy = 0;
 		region.width = rw;
@@ -224,7 +224,7 @@
 		info->fbops->fb_fillrect(info, &region);
 	}
 
-	if (bh) {
+	if ((int) bh > 0) {
 		region.dx = info->var.xoffset;
 		region.dy = info->var.yoffset + bs;
 		region.width = rs;
@@ -234,7 +234,7 @@
 }
 
 static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-		       int softback_lines, int fg, int bg)
+		       int fg, int bg)
 {
 	struct fb_cursor cursor;
 	struct fbcon_ops *ops = info->fbcon_par;
@@ -247,15 +247,6 @@
 
 	cursor.set = 0;
 
-	if (softback_lines) {
-		if (y + softback_lines >= vc->vc_rows) {
-			mode = CM_ERASE;
-			ops->cursor_flash = 0;
-			return;
-		} else
-			y += softback_lines;
-	}
-
  	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
 	src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
--- linux-4.4.0.orig/drivers/video/console/dummycon.c
+++ linux-4.4.0/drivers/video/console/dummycon.c
@@ -68,7 +68,6 @@
     .con_switch =	DUMMY,
     .con_blank =	DUMMY,
     .con_font_set =	DUMMY,
-    .con_font_get =	DUMMY,
     .con_font_default =	DUMMY,
     .con_font_copy =	DUMMY,
     .con_set_palette =	DUMMY,
--- linux-4.4.0.orig/drivers/video/console/fbcon.c
+++ linux-4.4.0/drivers/video/console/fbcon.c
@@ -101,12 +101,6 @@
 /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
    enums.  */
 static int logo_shown = FBCON_LOGO_CANSHOW;
-/* Software scrollback */
-static int fbcon_softback_size = 32768;
-static unsigned long softback_buf, softback_curr;
-static unsigned long softback_in;
-static unsigned long softback_top, softback_end;
-static int softback_lines;
 /* console mappings */
 static int first_fb_vc;
 static int last_fb_vc = MAX_NR_CONSOLES - 1;
@@ -140,8 +134,6 @@
 
 static const struct consw fb_con;
 
-#define CM_SOFTBACK	(8)
-
 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
 
 static int fbcon_set_origin(struct vc_data *);
@@ -171,7 +163,6 @@
 static int fbcon_switch(struct vc_data *vc);
 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
 static int fbcon_set_palette(struct vc_data *vc, unsigned char *table);
-static int fbcon_scrolldelta(struct vc_data *vc, int lines);
 
 /*
  *  Internal routines
@@ -350,18 +341,6 @@
 	return color;
 }
 
-static void fbcon_update_softback(struct vc_data *vc)
-{
-	int l = fbcon_softback_size / vc->vc_size_row;
-
-	if (l > 5)
-		softback_end = softback_buf + l * vc->vc_size_row;
-	else
-		/* Smaller scrollback makes no sense, and 0 would screw
-		   the operation totally */
-		softback_top = 0;
-}
-
 static void fb_flashcursor(struct work_struct *work)
 {
 	struct fb_info *info = container_of(work, struct fb_info, queue);
@@ -391,7 +370,7 @@
 	c = scr_readw((u16 *) vc->vc_pos);
 	mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
 		CM_ERASE : CM_DRAW;
-	ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
+	ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
 		    get_color(vc, info, c, 0));
 	console_unlock();
 }
@@ -451,13 +430,7 @@
 		}
 		
 		if (!strncmp(options, "scrollback:", 11)) {
-			options += 11;
-			if (*options) {
-				fbcon_softback_size = simple_strtoul(options, &options, 0);
-				if (*options == 'k' || *options == 'K') {
-					fbcon_softback_size *= 1024;
-				}
-			}
+			pr_warn("Ignoring scrollback size option\n");
 			continue;
 		}
 		
@@ -709,6 +682,7 @@
 	}
 
 	if (!err) {
+		ops->cur_blink_jiffies = HZ / 5;
 		info->fbcon_par = ops;
 
 		if (vc)
@@ -956,35 +930,11 @@
 	ops->currcon = -1;
 	ops->graphics = 1;
 	ops->cur_rotate = -1;
+	ops->cur_blink_jiffies = HZ / 5;
 	info->fbcon_par = ops;
 	p->con_rotate = initial_rotation;
 	set_blitting_type(vc, info);
 
-	if (info->fix.type != FB_TYPE_TEXT) {
-		if (fbcon_softback_size) {
-			if (!softback_buf) {
-				softback_buf =
-				    (unsigned long)
-				    kmalloc(fbcon_softback_size,
-					    GFP_KERNEL);
-				if (!softback_buf) {
-					fbcon_softback_size = 0;
-					softback_top = 0;
-				}
-			}
-		} else {
-			if (softback_buf) {
-				kfree((void *) softback_buf);
-				softback_buf = 0;
-				softback_top = 0;
-			}
-		}
-		if (softback_buf)
-			softback_in = softback_top = softback_curr =
-			    softback_buf;
-		softback_lines = 0;
-	}
-
 	/* Setup default font */
 	if (!p->fontdata && !vc->vc_font.data) {
 		if (!fontname[0] || !(font = find_font(fontname)))
@@ -1147,9 +1097,6 @@
 	if (logo)
 		fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
 
-	if (vc == svc && softback_buf)
-		fbcon_update_softback(vc);
-
 	if (ops->rotate_font && ops->rotate_font(info, vc)) {
 		ops->rotate = FB_ROTATE_UR;
 		set_blitting_type(vc, info);
@@ -1166,6 +1113,8 @@
 	p->userfont = 0;
 }
 
+static void set_vc_hi_font(struct vc_data *vc, bool set);
+
 static void fbcon_deinit(struct vc_data *vc)
 {
 	struct display *p = &fb_display[vc->vc_num];
@@ -1201,6 +1150,9 @@
 	if (free_font)
 		vc->vc_font.data = NULL;
 
+	if (vc->vc_hi_font_mask)
+		set_vc_hi_font(vc, false);
+
 	if (!con_is_bound(&fb_con))
 		fbcon_exit();
 
@@ -1304,7 +1256,6 @@
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
 	struct fbcon_ops *ops = info->fbcon_par;
-	int y;
  	int c = scr_readw((u16 *) vc->vc_pos);
 
 	ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
@@ -1318,16 +1269,8 @@
 		fbcon_add_cursor_timer(info);
 
 	ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
-	if (mode & CM_SOFTBACK) {
-		mode &= ~CM_SOFTBACK;
-		y = softback_lines;
-	} else {
-		if (softback_lines)
-			fbcon_set_origin(vc);
-		y = 0;
-	}
 
-	ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
+	ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
 		    get_color(vc, info, c, 0));
 }
 
@@ -1398,8 +1341,6 @@
 
 	if (CON_IS_VISIBLE(vc)) {
 		update_screen(vc);
-		if (softback_buf)
-			fbcon_update_softback(vc);
 	}
 }
 
@@ -1537,99 +1478,6 @@
 	scrollback_current = 0;
 }
 
-static void fbcon_redraw_softback(struct vc_data *vc, struct display *p,
-				  long delta)
-{
-	int count = vc->vc_rows;
-	unsigned short *d, *s;
-	unsigned long n;
-	int line = 0;
-
-	d = (u16 *) softback_curr;
-	if (d == (u16 *) softback_in)
-		d = (u16 *) vc->vc_origin;
-	n = softback_curr + delta * vc->vc_size_row;
-	softback_lines -= delta;
-	if (delta < 0) {
-		if (softback_curr < softback_top && n < softback_buf) {
-			n += softback_end - softback_buf;
-			if (n < softback_top) {
-				softback_lines -=
-				    (softback_top - n) / vc->vc_size_row;
-				n = softback_top;
-			}
-		} else if (softback_curr >= softback_top
-			   && n < softback_top) {
-			softback_lines -=
-			    (softback_top - n) / vc->vc_size_row;
-			n = softback_top;
-		}
-	} else {
-		if (softback_curr > softback_in && n >= softback_end) {
-			n += softback_buf - softback_end;
-			if (n > softback_in) {
-				n = softback_in;
-				softback_lines = 0;
-			}
-		} else if (softback_curr <= softback_in && n > softback_in) {
-			n = softback_in;
-			softback_lines = 0;
-		}
-	}
-	if (n == softback_curr)
-		return;
-	softback_curr = n;
-	s = (u16 *) softback_curr;
-	if (s == (u16 *) softback_in)
-		s = (u16 *) vc->vc_origin;
-	while (count--) {
-		unsigned short *start;
-		unsigned short *le;
-		unsigned short c;
-		int x = 0;
-		unsigned short attr = 1;
-
-		start = s;
-		le = advance_row(s, 1);
-		do {
-			c = scr_readw(s);
-			if (attr != (c & 0xff00)) {
-				attr = c & 0xff00;
-				if (s > start) {
-					fbcon_putcs(vc, start, s - start,
-						    line, x);
-					x += s - start;
-					start = s;
-				}
-			}
-			if (c == scr_readw(d)) {
-				if (s > start) {
-					fbcon_putcs(vc, start, s - start,
-						    line, x);
-					x += s - start + 1;
-					start = s + 1;
-				} else {
-					x++;
-					start++;
-				}
-			}
-			s++;
-			d++;
-		} while (s < le);
-		if (s > start)
-			fbcon_putcs(vc, start, s - start, line, x);
-		line++;
-		if (d == (u16 *) softback_end)
-			d = (u16 *) softback_buf;
-		if (d == (u16 *) softback_in)
-			d = (u16 *) vc->vc_origin;
-		if (s == (u16 *) softback_end)
-			s = (u16 *) softback_buf;
-		if (s == (u16 *) softback_in)
-			s = (u16 *) vc->vc_origin;
-	}
-}
-
 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
 			      int line, int count, int dy)
 {
@@ -1769,31 +1617,6 @@
 	}
 }
 
-static inline void fbcon_softback_note(struct vc_data *vc, int t,
-				       int count)
-{
-	unsigned short *p;
-
-	if (vc->vc_num != fg_console)
-		return;
-	p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
-
-	while (count) {
-		scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
-		count--;
-		p = advance_row(p, 1);
-		softback_in += vc->vc_size_row;
-		if (softback_in == softback_end)
-			softback_in = softback_buf;
-		if (softback_in == softback_top) {
-			softback_top += vc->vc_size_row;
-			if (softback_top == softback_end)
-				softback_top = softback_buf;
-		}
-	}
-	softback_curr = softback_in;
-}
-
 static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
 			int count)
 {
@@ -1816,8 +1639,6 @@
 	case SM_UP:
 		if (count > vc->vc_rows)	/* Maximum realistic size */
 			count = vc->vc_rows;
-		if (softback_top)
-			fbcon_softback_note(vc, t, count);
 		if (logo_shown >= 0)
 			goto redraw_up;
 		switch (p->scrollmode) {
@@ -2110,6 +1931,9 @@
 	}
 }
 
+#define PITCH(w) (((w) + 7) >> 3)
+#define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
+
 static int fbcon_resize(struct vc_data *vc, unsigned int width, 
 			unsigned int height, unsigned int user)
 {
@@ -2119,6 +1943,24 @@
 	struct fb_var_screeninfo var = info->var;
 	int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
 
+	if (p->userfont && FNTSIZE(vc->vc_font.data)) {
+		int size;
+		int pitch = PITCH(vc->vc_font.width);
+
+		/*
+		 * If user font, ensure that a possible change to user font
+		 * height or width will not allow a font data out-of-bounds access.
+		 * NOTE: must use original charcount in calculation as font
+		 * charcount can change and cannot be used to determine the
+		 * font data allocated size.
+		 */
+		if (pitch <= 0)
+			return -EINVAL;
+		size = CALC_FONTSZ(vc->vc_font.height, pitch, FNTCHARCNT(vc->vc_font.data));
+		if (size > FNTSIZE(vc->vc_font.data))
+			return -EINVAL;
+	}
+
 	virt_w = FBCON_SWAP(ops->rotate, width, height);
 	virt_h = FBCON_SWAP(ops->rotate, height, width);
 	virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
@@ -2167,14 +2009,6 @@
 	info = registered_fb[con2fb_map[vc->vc_num]];
 	ops = info->fbcon_par;
 
-	if (softback_top) {
-		if (softback_lines)
-			fbcon_set_origin(vc);
-		softback_top = softback_curr = softback_in = softback_buf;
-		softback_lines = 0;
-		fbcon_update_softback(vc);
-	}
-
 	if (logo_shown >= 0) {
 		struct vc_data *conp2 = vc_cons[logo_shown].d;
 
@@ -2400,6 +2234,9 @@
 
 	if (font->width <= 8) {
 		j = vc->vc_font.height;
+		if (font->charcount * j > FNTSIZE(fontdata))
+			return -EINVAL;
+
 		for (i = 0; i < font->charcount; i++) {
 			memcpy(data, fontdata, j);
 			memset(data + j, 0, 32 - j);
@@ -2408,6 +2245,9 @@
 		}
 	} else if (font->width <= 16) {
 		j = vc->vc_font.height * 2;
+		if (font->charcount * j > FNTSIZE(fontdata))
+			return -EINVAL;
+
 		for (i = 0; i < font->charcount; i++) {
 			memcpy(data, fontdata, j);
 			memset(data + j, 0, 64 - j);
@@ -2415,6 +2255,9 @@
 			fontdata += j;
 		}
 	} else if (font->width <= 24) {
+		if (font->charcount * (vc->vc_font.height * sizeof(u32)) > FNTSIZE(fontdata))
+			return -EINVAL;
+
 		for (i = 0; i < font->charcount; i++) {
 			for (j = 0; j < vc->vc_font.height; j++) {
 				*data++ = fontdata[0];
@@ -2427,6 +2270,9 @@
 		}
 	} else {
 		j = vc->vc_font.height * 4;
+		if (font->charcount * j > FNTSIZE(fontdata))
+			return -EINVAL;
+
 		for (i = 0; i < font->charcount; i++) {
 			memcpy(data, fontdata, j);
 			memset(data + j, 0, 128 - j);
@@ -2437,32 +2283,10 @@
 	return 0;
 }
 
-static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
-			     const u8 * data, int userfont)
+/* set/clear vc_hi_font_mask and update vc attrs accordingly */
+static void set_vc_hi_font(struct vc_data *vc, bool set)
 {
-	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
-	struct fbcon_ops *ops = info->fbcon_par;
-	struct display *p = &fb_display[vc->vc_num];
-	int resize;
-	int cnt;
-	char *old_data = NULL;
-
-	if (CON_IS_VISIBLE(vc) && softback_lines)
-		fbcon_set_origin(vc);
-
-	resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
-	if (p->userfont)
-		old_data = vc->vc_font.data;
-	if (userfont)
-		cnt = FNTCHARCNT(data);
-	else
-		cnt = 256;
-	vc->vc_font.data = (void *)(p->fontdata = data);
-	if ((p->userfont = userfont))
-		REFCOUNT(data)++;
-	vc->vc_font.width = w;
-	vc->vc_font.height = h;
-	if (vc->vc_hi_font_mask && cnt == 256) {
+	if (!set) {
 		vc->vc_hi_font_mask = 0;
 		if (vc->vc_can_do_color) {
 			vc->vc_complement_mask >>= 1;
@@ -2485,7 +2309,7 @@
 			    ((c & 0xfe00) >> 1) | (c & 0xff);
 			vc->vc_attr >>= 1;
 		}
-	} else if (!vc->vc_hi_font_mask && cnt == 512) {
+	} else {
 		vc->vc_hi_font_mask = 0x100;
 		if (vc->vc_can_do_color) {
 			vc->vc_complement_mask <<= 1;
@@ -2517,8 +2341,35 @@
 			} else
 				vc->vc_video_erase_char = c & ~0x100;
 		}
-
 	}
+}
+
+static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
+			     const u8 * data, int userfont)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct display *p = &fb_display[vc->vc_num];
+	int resize;
+	int cnt;
+	char *old_data = NULL;
+
+	resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
+	if (p->userfont)
+		old_data = vc->vc_font.data;
+	if (userfont)
+		cnt = FNTCHARCNT(data);
+	else
+		cnt = 256;
+	vc->vc_font.data = (void *)(p->fontdata = data);
+	if ((p->userfont = userfont))
+		REFCOUNT(data)++;
+	vc->vc_font.width = w;
+	vc->vc_font.height = h;
+	if (vc->vc_hi_font_mask && cnt == 256)
+		set_vc_hi_font(vc, false);
+	else if (!vc->vc_hi_font_mask && cnt == 512)
+		set_vc_hi_font(vc, true);
 
 	if (resize) {
 		int cols, rows;
@@ -2528,8 +2379,6 @@
 		cols /= w;
 		rows /= h;
 		vc_resize(vc, cols, rows);
-		if (CON_IS_VISIBLE(vc) && softback_buf)
-			fbcon_update_softback(vc);
 	} else if (CON_IS_VISIBLE(vc)
 		   && vc->vc_mode == KD_TEXT) {
 		fbcon_clear_margins(vc, 0);
@@ -2572,23 +2421,31 @@
 	int size;
 	int i, csum;
 	u8 *new_data, *data = font->data;
-	int pitch = (font->width+7) >> 3;
+	int pitch = PITCH(font->width);
 
 	/* Is there a reason why fbconsole couldn't handle any charcount >256?
 	 * If not this check should be changed to charcount < 256 */
 	if (charcount != 256 && charcount != 512)
 		return -EINVAL;
 
+	/* font bigger than screen resolution ? */
+	if (w > FBCON_SWAP(info->var.rotate, info->var.xres, info->var.yres) ||
+	    h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres))
+		return -EINVAL;
+
+	if (font->width > 32 || font->height > 32)
+		return -EINVAL;
+
 	/* Make sure drawing engine can handle the font */
-	if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
-	    !(info->pixmap.blit_y & (1 << (font->height - 1))))
+	if (!(info->pixmap.blit_x & BIT(font->width - 1)) ||
+	    !(info->pixmap.blit_y & BIT(font->height - 1)))
 		return -EINVAL;
 
 	/* Make sure driver can handle the font length */
 	if (fbcon_invalid_charcount(info, charcount))
 		return -EINVAL;
 
-	size = h * pitch * charcount;
+	size = CALC_FONTSZ(h, pitch, charcount);
 
 	new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER);
 
@@ -2687,19 +2544,7 @@
 
 static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
 {
-	unsigned long p;
-	int line;
-	
-	if (vc->vc_num != fg_console || !softback_lines)
-		return (u16 *) (vc->vc_origin + offset);
-	line = offset / vc->vc_size_row;
-	if (line >= softback_lines)
-		return (u16 *) (vc->vc_origin + offset -
-				softback_lines * vc->vc_size_row);
-	p = softback_curr + offset;
-	if (p >= softback_end)
-		p += softback_buf - softback_end;
-	return (u16 *) p;
+	return (u16 *) (vc->vc_origin + offset);
 }
 
 static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
@@ -2713,22 +2558,7 @@
 
 		x = offset % vc->vc_cols;
 		y = offset / vc->vc_cols;
-		if (vc->vc_num == fg_console)
-			y += softback_lines;
-		ret = pos + (vc->vc_cols - x) * 2;
-	} else if (vc->vc_num == fg_console && softback_lines) {
-		unsigned long offset = pos - softback_curr;
-
-		if (pos < softback_curr)
-			offset += softback_end - softback_buf;
-		offset /= 2;
-		x = offset % vc->vc_cols;
-		y = offset / vc->vc_cols;
 		ret = pos + (vc->vc_cols - x) * 2;
-		if (ret == softback_end)
-			ret = softback_buf;
-		if (ret == softback_in)
-			ret = vc->vc_origin;
 	} else {
 		/* Should not happen */
 		x = y = 0;
@@ -2756,107 +2586,11 @@
 			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
 			    (((a) & 0x0700) << 4);
 		scr_writew(a, p++);
-		if (p == (u16 *) softback_end)
-			p = (u16 *) softback_buf;
-		if (p == (u16 *) softback_in)
-			p = (u16 *) vc->vc_origin;
 	}
 }
 
-static int fbcon_scrolldelta(struct vc_data *vc, int lines)
-{
-	struct fb_info *info = registered_fb[con2fb_map[fg_console]];
-	struct fbcon_ops *ops = info->fbcon_par;
-	struct display *disp = &fb_display[fg_console];
-	int offset, limit, scrollback_old;
-
-	if (softback_top) {
-		if (vc->vc_num != fg_console)
-			return 0;
-		if (vc->vc_mode != KD_TEXT || !lines)
-			return 0;
-		if (logo_shown >= 0) {
-			struct vc_data *conp2 = vc_cons[logo_shown].d;
-
-			if (conp2->vc_top == logo_lines
-			    && conp2->vc_bottom == conp2->vc_rows)
-				conp2->vc_top = 0;
-			if (logo_shown == vc->vc_num) {
-				unsigned long p, q;
-				int i;
-
-				p = softback_in;
-				q = vc->vc_origin +
-				    logo_lines * vc->vc_size_row;
-				for (i = 0; i < logo_lines; i++) {
-					if (p == softback_top)
-						break;
-					if (p == softback_buf)
-						p = softback_end;
-					p -= vc->vc_size_row;
-					q -= vc->vc_size_row;
-					scr_memcpyw((u16 *) q, (u16 *) p,
-						    vc->vc_size_row);
-				}
-				softback_in = softback_curr = p;
-				update_region(vc, vc->vc_origin,
-					      logo_lines * vc->vc_cols);
-			}
-			logo_shown = FBCON_LOGO_CANSHOW;
-		}
-		fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
-		fbcon_redraw_softback(vc, disp, lines);
-		fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
-		return 0;
-	}
-
-	if (!scrollback_phys_max)
-		return -ENOSYS;
-
-	scrollback_old = scrollback_current;
-	scrollback_current -= lines;
-	if (scrollback_current < 0)
-		scrollback_current = 0;
-	else if (scrollback_current > scrollback_max)
-		scrollback_current = scrollback_max;
-	if (scrollback_current == scrollback_old)
-		return 0;
-
-	if (fbcon_is_inactive(vc, info))
-		return 0;
-
-	fbcon_cursor(vc, CM_ERASE);
-
-	offset = disp->yscroll - scrollback_current;
-	limit = disp->vrows;
-	switch (disp->scrollmode) {
-	case SCROLL_WRAP_MOVE:
-		info->var.vmode |= FB_VMODE_YWRAP;
-		break;
-	case SCROLL_PAN_MOVE:
-	case SCROLL_PAN_REDRAW:
-		limit -= vc->vc_rows;
-		info->var.vmode &= ~FB_VMODE_YWRAP;
-		break;
-	}
-	if (offset < 0)
-		offset += limit;
-	else if (offset >= limit)
-		offset -= limit;
-
-	ops->var.xoffset = 0;
-	ops->var.yoffset = offset * vc->vc_font.height;
-	ops->update_start(info);
-
-	if (!scrollback_current)
-		fbcon_cursor(vc, CM_DRAW);
-	return 0;
-}
-
 static int fbcon_set_origin(struct vc_data *vc)
 {
-	if (softback_lines)
-		fbcon_scrolldelta(vc, softback_lines);
 	return 0;
 }
 
@@ -2920,8 +2654,6 @@
 
 		fbcon_set_palette(vc, color_table);
 		update_screen(vc);
-		if (softback_buf)
-			fbcon_update_softback(vc);
 	}
 }
 
@@ -2960,6 +2692,34 @@
 		fbcon_modechanged(info);
 }
 
+/* let fbcon check if it supports a new screen resolution */
+int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct vc_data *vc;
+	unsigned int i;
+
+	WARN_CONSOLE_UNLOCKED();
+
+	if (!ops)
+		return 0;
+
+	/* prevent setting a screen size which is smaller than font size */
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
+		vc = vc_cons[i].d;
+		if (!vc || vc->vc_mode != KD_TEXT ||
+			   registered_fb[con2fb_map[i]] != info)
+			continue;
+
+		if (vc->vc_font.width  > FBCON_SWAP(var->rotate, var->xres, var->yres) ||
+		    vc->vc_font.height > FBCON_SWAP(var->rotate, var->yres, var->xres))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(fbcon_modechange_possible);
+
 static int fbcon_mode_deleted(struct fb_info *info,
 			      struct fb_videomode *mode)
 {
@@ -3017,7 +2777,7 @@
 	for (i = first_fb_vc; i <= last_fb_vc; i++) {
 		if (con2fb_map[i] != idx &&
 		    con2fb_map[i] != -1) {
-			new_idx = i;
+			new_idx = con2fb_map[i];
 			break;
 		}
 	}
@@ -3342,7 +3102,6 @@
 	.con_font_default	= fbcon_set_def_font,
 	.con_font_copy 		= fbcon_copy_font,
 	.con_set_palette 	= fbcon_set_palette,
-	.con_scrolldelta 	= fbcon_scrolldelta,
 	.con_set_origin 	= fbcon_set_origin,
 	.con_invert_region 	= fbcon_invert_region,
 	.con_screen_pos 	= fbcon_screen_pos,
@@ -3551,9 +3310,6 @@
 	if (fbcon_has_exited)
 		return;
 
-	kfree((void *)softback_buf);
-	softback_buf = 0UL;
-
 	for (i = 0; i < FB_MAX; i++) {
 		int pending = 0;
 
--- linux-4.4.0.orig/drivers/video/console/fbcon.h
+++ linux-4.4.0/drivers/video/console/fbcon.h
@@ -62,7 +62,7 @@
 	void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
 			      int bottom_only);
 	void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
-		       int softback_lines, int fg, int bg);
+		       int fg, int bg);
 	int  (*update_start)(struct fb_info *info);
 	int  (*rotate_font)(struct fb_info *info, struct vc_data *vc);
 	struct fb_var_screeninfo var;  /* copy of the current fb_var_screeninfo */
@@ -151,13 +151,6 @@
 #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
 #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
 
-/* Font */
-#define REFCOUNT(fd)	(((int *)(fd))[-1])
-#define FNTSIZE(fd)	(((int *)(fd))[-2])
-#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
-#define FNTSUM(fd)	(((int *)(fd))[-4])
-#define FONT_EXTRA_WORDS 4
-
     /*
      *  Scroll Method
      */
@@ -261,5 +254,13 @@
 #define fbcon_set_rotate(x) do {} while(0)
 #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE
+int fbcon_modechange_possible(struct fb_info *info,
+			     struct fb_var_screeninfo *var);
+#else
+static inline int fbcon_modechange_possible(struct fb_info *info,
+			      struct fb_var_screeninfo *var) { return 0; }
+#endif
+
 #endif /* _VIDEO_FBCON_H */
 
--- linux-4.4.0.orig/drivers/video/console/fbcon_ccw.c
+++ linux-4.4.0/drivers/video/console/fbcon_ccw.c
@@ -201,7 +201,7 @@
 	region.color = 0;
 	region.rop = ROP_COPY;
 
-	if (rw && !bottom_only) {
+	if ((int) rw > 0 && !bottom_only) {
 		region.dx = 0;
 		region.dy = info->var.yoffset;
 		region.height = rw;
@@ -209,7 +209,7 @@
 		info->fbops->fb_fillrect(info, &region);
 	}
 
-	if (bh) {
+	if ((int) bh > 0) {
 		region.dx = info->var.xoffset + bs;
 		region.dy = 0;
                 region.height = info->var.yres_virtual;
@@ -219,7 +219,7 @@
 }
 
 static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-		       int softback_lines, int fg, int bg)
+		       int fg, int bg)
 {
 	struct fb_cursor cursor;
 	struct fbcon_ops *ops = info->fbcon_par;
@@ -236,15 +236,6 @@
 
 	cursor.set = 0;
 
-	if (softback_lines) {
-		if (y + softback_lines >= vc->vc_rows) {
-			mode = CM_ERASE;
-			ops->cursor_flash = 0;
-			return;
-		} else
-			y += softback_lines;
-	}
-
  	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
 	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
--- linux-4.4.0.orig/drivers/video/console/fbcon_cw.c
+++ linux-4.4.0/drivers/video/console/fbcon_cw.c
@@ -184,7 +184,7 @@
 	region.color = 0;
 	region.rop = ROP_COPY;
 
-	if (rw && !bottom_only) {
+	if ((int) rw > 0 && !bottom_only) {
 		region.dx = 0;
 		region.dy = info->var.yoffset + rs;
 		region.height = rw;
@@ -192,7 +192,7 @@
 		info->fbops->fb_fillrect(info, &region);
 	}
 
-	if (bh) {
+	if ((int) bh > 0) {
 		region.dx = info->var.xoffset;
 		region.dy = info->var.yoffset;
                 region.height = info->var.yres;
@@ -202,7 +202,7 @@
 }
 
 static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-		      int softback_lines, int fg, int bg)
+		      int fg, int bg)
 {
 	struct fb_cursor cursor;
 	struct fbcon_ops *ops = info->fbcon_par;
@@ -219,15 +219,6 @@
 
 	cursor.set = 0;
 
-	if (softback_lines) {
-		if (y + softback_lines >= vc->vc_rows) {
-			mode = CM_ERASE;
-			ops->cursor_flash = 0;
-			return;
-		} else
-			y += softback_lines;
-	}
-
  	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
 	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
--- linux-4.4.0.orig/drivers/video/console/fbcon_rotate.c
+++ linux-4.4.0/drivers/video/console/fbcon_rotate.c
@@ -14,6 +14,7 @@
 #include <linux/fb.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
+#include <linux/font.h>
 #include <asm/types.h>
 #include "fbcon.h"
 #include "fbcon_rotate.h"
--- linux-4.4.0.orig/drivers/video/console/fbcon_ud.c
+++ linux-4.4.0/drivers/video/console/fbcon_ud.c
@@ -231,7 +231,7 @@
 	region.color = 0;
 	region.rop = ROP_COPY;
 
-	if (rw && !bottom_only) {
+	if ((int) rw > 0 && !bottom_only) {
 		region.dy = 0;
 		region.dx = info->var.xoffset;
 		region.width  = rw;
@@ -239,7 +239,7 @@
 		info->fbops->fb_fillrect(info, &region);
 	}
 
-	if (bh) {
+	if ((int) bh > 0) {
 		region.dy = info->var.yoffset;
 		region.dx = info->var.xoffset;
                 region.height  = bh;
@@ -249,7 +249,7 @@
 }
 
 static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-		      int softback_lines, int fg, int bg)
+		      int fg, int bg)
 {
 	struct fb_cursor cursor;
 	struct fbcon_ops *ops = info->fbcon_par;
@@ -267,15 +267,6 @@
 
 	cursor.set = 0;
 
-	if (softback_lines) {
-		if (y + softback_lines >= vc->vc_rows) {
-			mode = CM_ERASE;
-			ops->cursor_flash = 0;
-			return;
-		} else
-			y += softback_lines;
-	}
-
  	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
 	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
--- linux-4.4.0.orig/drivers/video/console/newport_con.c
+++ linux-4.4.0/drivers/video/console/newport_con.c
@@ -31,17 +31,14 @@
 #include <linux/linux_logo.h>
 #include <linux/font.h>
 
-#define FONT_DATA ((unsigned char *)font_vga_8x16.data)
+#define NEWPORT_LEN	0x10000
 
-/* borrowed from fbcon.c */
-#define REFCOUNT(fd)	(((int *)(fd))[-1])
-#define FNTSIZE(fd)	(((int *)(fd))[-2])
-#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
-#define FONT_EXTRA_WORDS 3
+#define FONT_DATA ((unsigned char *)font_vga_8x16.data)
 
 static unsigned char *font_data[MAX_NR_CONSOLES];
 
 static struct newport_regs *npregs;
+static unsigned long newport_addr;
 
 static int logo_active;
 static int topscan;
@@ -519,6 +516,7 @@
 	FNTSIZE(new_data) = size;
 	FNTCHARCNT(new_data) = op->charcount;
 	REFCOUNT(new_data) = 0;	/* usage counter */
+	FNTSUM(new_data) = 0;
 
 	p = new_data;
 	for (i = 0; i < op->charcount; i++) {
@@ -743,7 +741,6 @@
 static int newport_probe(struct gio_device *dev,
 			 const struct gio_device_id *id)
 {
-	unsigned long newport_addr;
 	int err;
 
 	if (!dev->resource.start)
@@ -753,7 +750,7 @@
 		return -EBUSY; /* we only support one Newport as console */
 
 	newport_addr = dev->resource.start + 0xF0000;
-	if (!request_mem_region(newport_addr, 0x10000, "Newport"))
+	if (!request_mem_region(newport_addr, NEWPORT_LEN, "Newport"))
 		return -ENODEV;
 
 	npregs = (struct newport_regs *)/* ioremap cannot fail */
@@ -761,6 +758,11 @@
 	console_lock();
 	err = do_take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
 	console_unlock();
+
+	if (err) {
+		iounmap((void *)npregs);
+		release_mem_region(newport_addr, NEWPORT_LEN);
+	}
 	return err;
 }
 
@@ -768,6 +770,7 @@
 {
 	give_up_console(&newport_con);
 	iounmap((void *)npregs);
+	release_mem_region(newport_addr, NEWPORT_LEN);
 }
 
 static struct gio_device_id newport_ids[] = {
--- linux-4.4.0.orig/drivers/video/console/tileblit.c
+++ linux-4.4.0/drivers/video/console/tileblit.c
@@ -13,6 +13,7 @@
 #include <linux/fb.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
+#include <linux/font.h>
 #include <asm/types.h>
 #include "fbcon.h"
 
@@ -80,7 +81,7 @@
 }
 
 static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-			int softback_lines, int fg, int bg)
+			int fg, int bg)
 {
 	struct fb_tilecursor cursor;
 	int use_sw = (vc->vc_cursor_type & 0x10);
--- linux-4.4.0.orig/drivers/video/console/vgacon.c
+++ linux-4.4.0/drivers/video/console/vgacon.c
@@ -180,155 +180,6 @@
 	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
 }
 
-#ifdef CONFIG_VGACON_SOFT_SCROLLBACK
-/* software scrollback */
-static void *vgacon_scrollback;
-static int vgacon_scrollback_tail;
-static int vgacon_scrollback_size;
-static int vgacon_scrollback_rows;
-static int vgacon_scrollback_cnt;
-static int vgacon_scrollback_cur;
-static int vgacon_scrollback_save;
-static int vgacon_scrollback_restore;
-
-static void vgacon_scrollback_init(int pitch)
-{
-	int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch;
-
-	if (vgacon_scrollback) {
-		vgacon_scrollback_cnt  = 0;
-		vgacon_scrollback_tail = 0;
-		vgacon_scrollback_cur  = 0;
-		vgacon_scrollback_rows = rows - 1;
-		vgacon_scrollback_size = rows * pitch;
-	}
-}
-
-static void vgacon_scrollback_startup(void)
-{
-	vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT);
-	vgacon_scrollback_init(vga_video_num_columns * 2);
-}
-
-static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
-{
-	void *p;
-
-	if (!vgacon_scrollback_size || c->vc_num != fg_console)
-		return;
-
-	p = (void *) (c->vc_origin + t * c->vc_size_row);
-
-	while (count--) {
-		scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail,
-			    p, c->vc_size_row);
-		vgacon_scrollback_cnt++;
-		p += c->vc_size_row;
-		vgacon_scrollback_tail += c->vc_size_row;
-
-		if (vgacon_scrollback_tail >= vgacon_scrollback_size)
-			vgacon_scrollback_tail = 0;
-
-		if (vgacon_scrollback_cnt > vgacon_scrollback_rows)
-			vgacon_scrollback_cnt = vgacon_scrollback_rows;
-
-		vgacon_scrollback_cur = vgacon_scrollback_cnt;
-	}
-}
-
-static void vgacon_restore_screen(struct vc_data *c)
-{
-	vgacon_scrollback_save = 0;
-
-	if (!vga_is_gfx && !vgacon_scrollback_restore) {
-		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
-			    c->vc_screenbuf_size > vga_vram_size ?
-			    vga_vram_size : c->vc_screenbuf_size);
-		vgacon_scrollback_restore = 1;
-		vgacon_scrollback_cur = vgacon_scrollback_cnt;
-	}
-}
-
-static int vgacon_scrolldelta(struct vc_data *c, int lines)
-{
-	int start, end, count, soff;
-
-	if (!lines) {
-		c->vc_visible_origin = c->vc_origin;
-		vga_set_mem_top(c);
-		return 1;
-	}
-
-	if (!vgacon_scrollback)
-		return 1;
-
-	if (!vgacon_scrollback_save) {
-		vgacon_cursor(c, CM_ERASE);
-		vgacon_save_screen(c);
-		vgacon_scrollback_save = 1;
-	}
-
-	vgacon_scrollback_restore = 0;
-	start = vgacon_scrollback_cur + lines;
-	end = start + abs(lines);
-
-	if (start < 0)
-		start = 0;
-
-	if (start > vgacon_scrollback_cnt)
-		start = vgacon_scrollback_cnt;
-
-	if (end < 0)
-		end = 0;
-
-	if (end > vgacon_scrollback_cnt)
-		end = vgacon_scrollback_cnt;
-
-	vgacon_scrollback_cur = start;
-	count = end - start;
-	soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) *
-					 c->vc_size_row);
-	soff -= count * c->vc_size_row;
-
-	if (soff < 0)
-		soff += vgacon_scrollback_size;
-
-	count = vgacon_scrollback_cnt - start;
-
-	if (count > c->vc_rows)
-		count = c->vc_rows;
-
-	if (count) {
-		int copysize;
-
-		int diff = c->vc_rows - count;
-		void *d = (void *) c->vc_origin;
-		void *s = (void *) c->vc_screenbuf;
-
-		count *= c->vc_size_row;
-		/* how much memory to end of buffer left? */
-		copysize = min(count, vgacon_scrollback_size - soff);
-		scr_memcpyw(d, vgacon_scrollback + soff, copysize);
-		d += copysize;
-		count -= copysize;
-
-		if (count) {
-			scr_memcpyw(d, vgacon_scrollback, count);
-			d += count;
-		}
-
-		if (diff)
-			scr_memcpyw(d, s, diff * c->vc_size_row);
-	} else
-		vgacon_cursor(c, CM_MOVE);
-
-	return 1;
-}
-#else
-#define vgacon_scrollback_startup(...) do { } while (0)
-#define vgacon_scrollback_init(...)    do { } while (0)
-#define vgacon_scrollback_update(...)  do { } while (0)
-
 static void vgacon_restore_screen(struct vc_data *c)
 {
 	if (c->vc_origin != c->vc_visible_origin)
@@ -365,7 +216,6 @@
 	vga_set_mem_top(c);
 	return 1;
 }
-#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
 
 static const char *vgacon_startup(void)
 {
@@ -409,7 +259,10 @@
 		vga_video_port_val = VGA_CRT_DM;
 		if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
 			static struct resource ega_console_resource =
-			    { .name = "ega", .start = 0x3B0, .end = 0x3BF };
+			    { .name	= "ega",
+			      .flags	= IORESOURCE_IO,
+			      .start	= 0x3B0,
+			      .end	= 0x3BF };
 			vga_video_type = VIDEO_TYPE_EGAM;
 			vga_vram_size = 0x8000;
 			display_desc = "EGA+";
@@ -417,9 +270,15 @@
 					 &ega_console_resource);
 		} else {
 			static struct resource mda1_console_resource =
-			    { .name = "mda", .start = 0x3B0, .end = 0x3BB };
+			    { .name	= "mda",
+			      .flags	= IORESOURCE_IO,
+			      .start	= 0x3B0,
+			      .end	= 0x3BB };
 			static struct resource mda2_console_resource =
-			    { .name = "mda", .start = 0x3BF, .end = 0x3BF };
+			    { .name	= "mda",
+			      .flags	= IORESOURCE_IO,
+			      .start	= 0x3BF,
+			      .end	= 0x3BF };
 			vga_video_type = VIDEO_TYPE_MDA;
 			vga_vram_size = 0x2000;
 			display_desc = "*MDA";
@@ -441,15 +300,21 @@
 			vga_vram_size = 0x8000;
 
 			if (!screen_info.orig_video_isVGA) {
-				static struct resource ega_console_resource
-				    = { .name = "ega", .start = 0x3C0, .end = 0x3DF };
+				static struct resource ega_console_resource =
+				    { .name	= "ega",
+				      .flags	= IORESOURCE_IO,
+				      .start	= 0x3C0,
+				      .end	= 0x3DF };
 				vga_video_type = VIDEO_TYPE_EGAC;
 				display_desc = "EGA";
 				request_resource(&ioport_resource,
 						 &ega_console_resource);
 			} else {
-				static struct resource vga_console_resource
-				    = { .name = "vga+", .start = 0x3C0, .end = 0x3DF };
+				static struct resource vga_console_resource =
+				    { .name	= "vga+",
+				      .flags	= IORESOURCE_IO,
+				      .start	= 0x3C0,
+				      .end	= 0x3DF };
 				vga_video_type = VIDEO_TYPE_VGAC;
 				display_desc = "VGA+";
 				request_resource(&ioport_resource,
@@ -493,7 +358,10 @@
 			}
 		} else {
 			static struct resource cga_console_resource =
-			    { .name = "cga", .start = 0x3D4, .end = 0x3D5 };
+			    { .name	= "cga",
+			      .flags	= IORESOURCE_IO,
+			      .start	= 0x3D4,
+			      .end	= 0x3D5 };
 			vga_video_type = VIDEO_TYPE_CGA;
 			vga_vram_size = 0x2000;
 			display_desc = "*CGA";
@@ -544,10 +412,7 @@
 	vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
 	vgacon_yres = vga_scan_lines;
 
-	if (!vga_init_done) {
-		vgacon_scrollback_startup();
-		vga_init_done = 1;
-	}
+	vga_init_done = 1;
 
 	return display_desc;
 }
@@ -843,7 +708,6 @@
 			vgacon_doresize(c, c->vc_cols, c->vc_rows);
 	}
 
-	vgacon_scrollback_init(c->vc_size_row);
 	return 0;		/* Redrawing not needed */
 }
 
@@ -1312,6 +1176,9 @@
 static int vgacon_resize(struct vc_data *c, unsigned int width,
 			 unsigned int height, unsigned int user)
 {
+	if ((width << 1) * height > vga_vram_size)
+		return -EINVAL;
+
 	if (width % 2 || width > screen_info.orig_video_cols ||
 	    height > (screen_info.orig_video_lines * vga_default_font_height)/
 	    c->vc_font.height)
@@ -1373,7 +1240,6 @@
 	oldo = c->vc_origin;
 	delta = lines * c->vc_size_row;
 	if (dir == SM_UP) {
-		vgacon_scrollback_update(c, t, lines);
 		if (c->vc_scr_end + delta >= vga_vram_end) {
 			scr_memcpyw((u16 *) vga_vram_base,
 				    (u16 *) (oldo + delta),
--- linux-4.4.0.orig/drivers/video/fbdev/Kconfig
+++ linux-4.4.0/drivers/video/fbdev/Kconfig
@@ -1397,6 +1397,7 @@
 	select FB_CFB_IMAGEBLIT
 	select FB_BACKLIGHT if FB_ATY_BACKLIGHT
 	select FB_MACMODES if PPC
+	select FB_ATY_CT if SPARC64 && PCI
 	help
 	  This driver supports graphics boards with the ATI Mach64 chips.
 	  Say Y if you have such a graphics board.
@@ -1407,7 +1408,6 @@
 config FB_ATY_CT
 	bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support"
 	depends on PCI && FB_ATY
-	default y if SPARC64 && PCI
 	help
 	  Say Y here to support use of ATI's 64-bit Rage boards (or other
 	  boards based on the Mach64 CT, VT, GT, and LT chipsets) as a
@@ -1506,6 +1506,7 @@
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	select FB_BOOT_VESA_SUPPORT if FB_SIS = y
+	select FB_SIS_300 if !FB_SIS_315
 	help
 	  This is the frame buffer device driver for the SiS 300, 315, 330
 	  and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets.
@@ -1990,16 +1991,6 @@
 	---help---
 	  Frame buffer driver for the on-chip SH-Mobile LCD controller.
 
-config FB_SH_MOBILE_HDMI
-	tristate "SuperH Mobile HDMI controller support"
-	depends on FB_SH_MOBILE_LCDC
-	select FB_MODE_HELPERS
-	select SOUND
-	select SND
-	select SND_SOC
-	---help---
-	  Driver for the on-chip SH-Mobile HDMI controller.
-
 config FB_TMIO
 	tristate "Toshiba Mobile IO FrameBuffer support"
 	depends on FB && (MFD_TMIO || COMPILE_TEST)
@@ -2249,7 +2240,6 @@
 	select FB_SYS_IMAGEBLIT
 	select FB_SYS_FOPS
 	select FB_DEFERRED_IO
-	select INPUT_XEN_KBDDEV_FRONTEND if INPUT_MISC
 	select XEN_XENBUS_FRONTEND
 	default y
 	help
--- linux-4.4.0.orig/drivers/video/fbdev/Makefile
+++ linux-4.4.0/drivers/video/fbdev/Makefile
@@ -118,7 +118,6 @@
 obj-$(CONFIG_FB_SMSCUFX)	  += smscufx.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_SH_MIPI_DSI)	  += sh_mipi_dsi.o
-obj-$(CONFIG_FB_SH_MOBILE_HDMI)	  += sh_mobile_hdmi.o
 obj-$(CONFIG_FB_SH_MOBILE_MERAM)  += sh_mobile_meram.o
 obj-$(CONFIG_FB_SH_MOBILE_LCDC)	  += sh_mobile_lcdcfb.o
 obj-$(CONFIG_FB_OMAP)             += omap/
--- linux-4.4.0.orig/drivers/video/fbdev/amba-clcd.c
+++ linux-4.4.0/drivers/video/fbdev/amba-clcd.c
@@ -759,8 +759,8 @@
 	if (err)
 		return err;
 
-	framesize = fb->panel->mode.xres * fb->panel->mode.yres *
-			fb->panel->bpp / 8;
+	framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres *
+			fb->panel->bpp / 8);
 	fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize,
 			&dma, GFP_KERNEL);
 	if (!fb->fb.screen_base)
--- linux-4.4.0.orig/drivers/video/fbdev/arcfb.c
+++ linux-4.4.0/drivers/video/fbdev/arcfb.c
@@ -645,17 +645,17 @@
 MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
 module_param(arcfb_enable, uint, 0);
 MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board");
-module_param(dio_addr, ulong, 0);
+module_param_hw(dio_addr, ulong, ioport, 0);
 MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
-module_param(cio_addr, ulong, 0);
+module_param_hw(cio_addr, ulong, ioport, 0);
 MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
-module_param(c2io_addr, ulong, 0);
+module_param_hw(c2io_addr, ulong, ioport, 0);
 MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
 module_param(splashval, ulong, 0);
 MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green");
 module_param(tuhold, ulong, 0);
 MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board");
-module_param(irq, uint, 0);
+module_param_hw(irq, uint, irq, 0);
 MODULE_PARM_DESC(irq, "IRQ for the Arc board");
 
 module_init(arcfb_init);
--- linux-4.4.0.orig/drivers/video/fbdev/atmel_lcdfb.c
+++ linux-4.4.0/drivers/video/fbdev/atmel_lcdfb.c
@@ -1120,7 +1120,7 @@
 		goto put_display_node;
 	}
 
-	timings_np = of_find_node_by_name(display_np, "display-timings");
+	timings_np = of_get_child_by_name(display_np, "display-timings");
 	if (!timings_np) {
 		dev_err(dev, "failed to find display-timings node\n");
 		ret = -ENODEV;
@@ -1141,6 +1141,12 @@
 		fb_add_videomode(&fb_vm, &info->modelist);
 	}
 
+	/*
+	 * FIXME: Make sure we are not referencing any fields in display_np
+	 * and timings_np and drop our references to them before returning to
+	 * avoid leaking the nodes on probe deferral and driver unbind.
+	 */
+
 	return 0;
 
 put_timings_node:
--- linux-4.4.0.orig/drivers/video/fbdev/aty/atyfb.h
+++ linux-4.4.0/drivers/video/fbdev/aty/atyfb.h
@@ -332,6 +332,8 @@
 extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll);
 extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
 
+extern const u8 aty_postdividers[8];
+
 
     /*
      *  Hardware cursor support
@@ -358,7 +360,6 @@
 
 extern void aty_reset_engine(const struct atyfb_par *par);
 extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info);
-extern u8   aty_ld_pll_ct(int offset, const struct atyfb_par *par);
 
 void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
--- linux-4.4.0.orig/drivers/video/fbdev/aty/atyfb_base.c
+++ linux-4.4.0/drivers/video/fbdev/aty/atyfb_base.c
@@ -1861,7 +1861,7 @@
 #if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
 	case ATYIO_CLKR:
 		if (M64_HAS(INTEGRATED)) {
-			struct atyclk clk;
+			struct atyclk clk = { 0 };
 			union aty_pll *pll = &par->pll;
 			u32 dsp_config = pll->ct.dsp_config;
 			u32 dsp_on_off = pll->ct.dsp_on_off;
@@ -3093,17 +3093,18 @@
 		/*
 		 * PLL Reference Divider M:
 		 */
-		M = pll_regs[2];
+		M = pll_regs[PLL_REF_DIV];
 
 		/*
 		 * PLL Feedback Divider N (Dependent on CLOCK_CNTL):
 		 */
-		N = pll_regs[7 + (clock_cntl & 3)];
+		N = pll_regs[VCLK0_FB_DIV + (clock_cntl & 3)];
 
 		/*
 		 * PLL Post Divider P (Dependent on CLOCK_CNTL):
 		 */
-		P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
+		P = aty_postdividers[((pll_regs[VCLK_POST_DIV] >> ((clock_cntl & 3) << 1)) & 3) |
+		                     ((pll_regs[PLL_EXT_CNTL] >> (2 + (clock_cntl & 3))) & 4)];
 
 		/*
 		 * PLL Divider Q:
--- linux-4.4.0.orig/drivers/video/fbdev/aty/mach64_accel.c
+++ linux-4.4.0/drivers/video/fbdev/aty/mach64_accel.c
@@ -126,7 +126,7 @@
 
 	/* set host attributes */
 	wait_for_fifo(13, par);
-	aty_st_le32(HOST_CNTL, 0, par);
+	aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par);
 
 	/* set pattern attributes */
 	aty_st_le32(PAT_REG0, 0, par);
@@ -232,7 +232,8 @@
 		rotation = rotation24bpp(dx, direction);
 	}
 
-	wait_for_fifo(4, par);
+	wait_for_fifo(5, par);
+	aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par);
 	aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par);
 	aty_st_le32(SRC_Y_X, (sx << 16) | sy, par);
 	aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par);
@@ -268,7 +269,8 @@
 		rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
 	}
 
-	wait_for_fifo(3, par);
+	wait_for_fifo(4, par);
+	aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par);
 	aty_st_le32(DP_FRGD_CLR, color, par);
 	aty_st_le32(DP_SRC,
 		    BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
@@ -283,7 +285,7 @@
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width;
-	u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix;
+	u32 pix_width, rotation = 0, src, mix;
 
 	if (par->asleep)
 		return;
@@ -295,8 +297,7 @@
 		return;
 	}
 
-	pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
-	host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
+	pix_width = par->crtc.dp_pix_width;
 
 	switch (image->depth) {
 	case 1:
@@ -344,7 +345,7 @@
 		 * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit
 		 * this hwaccelerated triple has an issue with not aligned data
 		 */
-		if (M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
+		if (image->depth == 1 && M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
 			pix_width |= DP_HOST_TRIPLE_EN;
 	}
 
@@ -369,19 +370,18 @@
 		mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D;
 	}
 
-	wait_for_fifo(6, par);
-	aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par);
+	wait_for_fifo(5, par);
 	aty_st_le32(DP_PIX_WIDTH, pix_width, par);
 	aty_st_le32(DP_MIX, mix, par);
 	aty_st_le32(DP_SRC, src, par);
-	aty_st_le32(HOST_CNTL, host_cntl, par);
+	aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par);
 	aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par);
 
 	draw_rect(dx, dy, width, image->height, par);
 	src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
 
 	/* manual triple each pixel */
-	if (info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
+	if (image->depth == 1 && info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
 		int inbit, outbit, mult24, byte_id_in_dword, width;
 		u8 *pbitmapin = (u8*)image->data, *pbitmapout;
 		u32 hostdword;
@@ -414,7 +414,7 @@
 				}
 			}
 			wait_for_fifo(1, par);
-			aty_st_le32(HOST_DATA0, hostdword, par);
+			aty_st_le32(HOST_DATA0, le32_to_cpu(hostdword), par);
 		}
 	} else {
 		u32 *pbitmap, dwords = (src_bytes + 3) / 4;
@@ -423,8 +423,4 @@
 			aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par);
 		}
 	}
-
-	/* restore pix_width */
-	wait_for_fifo(1, par);
-	aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);
 }
--- linux-4.4.0.orig/drivers/video/fbdev/aty/mach64_ct.c
+++ linux-4.4.0/drivers/video/fbdev/aty/mach64_ct.c
@@ -114,7 +114,7 @@
  */
 
 #define Maximum_DSP_PRECISION 7
-static u8 postdividers[] = {1,2,4,8,3};
+const u8 aty_postdividers[8] = {1,2,4,8,3,5,6,12};
 
 static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
 {
@@ -221,7 +221,7 @@
 		pll->vclk_post_div += (q <  64*8);
 		pll->vclk_post_div += (q <  32*8);
 	}
-	pll->vclk_post_div_real = postdividers[pll->vclk_post_div];
+	pll->vclk_post_div_real = aty_postdividers[pll->vclk_post_div];
 	//    pll->vclk_post_div <<= 6;
 	pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
 	pllvclk = (1000000 * 2 * pll->vclk_fb_div) /
@@ -512,7 +512,7 @@
 		u8 mclk_fb_div, pll_ext_cntl;
 		pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
 		pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
-		pll->ct.xclk_post_div_real = postdividers[pll_ext_cntl & 0x07];
+		pll->ct.xclk_post_div_real = aty_postdividers[pll_ext_cntl & 0x07];
 		mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
 		if (pll_ext_cntl & PLL_MFB_TIMES_4_2B)
 			mclk_fb_div <<= 1;
@@ -534,7 +534,7 @@
 		xpost_div += (q <  64*8);
 		xpost_div += (q <  32*8);
 	}
-	pll->ct.xclk_post_div_real = postdividers[xpost_div];
+	pll->ct.xclk_post_div_real = aty_postdividers[xpost_div];
 	pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;
 
 #ifdef CONFIG_PPC
@@ -583,7 +583,7 @@
 			mpost_div += (q <  64*8);
 			mpost_div += (q <  32*8);
 		}
-		sclk_post_div_real = postdividers[mpost_div];
+		sclk_post_div_real = aty_postdividers[mpost_div];
 		pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
 		pll->ct.spll_cntl2 = mpost_div << 4;
 #ifdef DEBUG
--- linux-4.4.0.orig/drivers/video/fbdev/au1200fb.c
+++ linux-4.4.0/drivers/video/fbdev/au1200fb.c
@@ -1680,8 +1680,10 @@
 
 		fbi = framebuffer_alloc(sizeof(struct au1200fb_device),
 					&dev->dev);
-		if (!fbi)
+		if (!fbi) {
+			ret = -ENOMEM;
 			goto failed;
+		}
 
 		_au1200fb_infos[plane] = fbi;
 		fbdev = fbi->par;
@@ -1699,7 +1701,8 @@
 		if (!fbdev->fb_mem) {
 			print_err("fail to allocate frambuffer (size: %dK))",
 				  fbdev->fb_len / 1024);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto failed;
 		}
 
 		/*
--- linux-4.4.0.orig/drivers/video/fbdev/auo_k190x.c
+++ linux-4.4.0/drivers/video/fbdev/auo_k190x.c
@@ -773,9 +773,7 @@
 /*
  * Power-management
  */
-
-#ifdef CONFIG_PM
-static int auok190x_runtime_suspend(struct device *dev)
+static int __maybe_unused auok190x_runtime_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct fb_info *info = platform_get_drvdata(pdev);
@@ -822,7 +820,7 @@
 	return 0;
 }
 
-static int auok190x_runtime_resume(struct device *dev)
+static int __maybe_unused auok190x_runtime_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct fb_info *info = platform_get_drvdata(pdev);
@@ -856,7 +854,7 @@
 	return 0;
 }
 
-static int auok190x_suspend(struct device *dev)
+static int __maybe_unused auok190x_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct fb_info *info = platform_get_drvdata(pdev);
@@ -896,7 +894,7 @@
 	return 0;
 }
 
-static int auok190x_resume(struct device *dev)
+static int __maybe_unused auok190x_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct fb_info *info = platform_get_drvdata(pdev);
@@ -933,7 +931,6 @@
 
 	return 0;
 }
-#endif
 
 const struct dev_pm_ops auok190x_pm = {
 	SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume,
--- linux-4.4.0.orig/drivers/video/fbdev/chipsfb.c
+++ linux-4.4.0/drivers/video/fbdev/chipsfb.c
@@ -350,7 +350,7 @@
 static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
 {
 	struct fb_info *p;
-	unsigned long addr, size;
+	unsigned long addr;
 	unsigned short cmd;
 	int rc = -ENODEV;
 
@@ -362,7 +362,6 @@
 	if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
 		goto err_disable;
 	addr = pci_resource_start(dp, 0);
-	size = pci_resource_len(dp, 0);
 	if (addr == 0)
 		goto err_disable;
 
--- linux-4.4.0.orig/drivers/video/fbdev/clps711x-fb.c
+++ linux-4.4.0/drivers/video/fbdev/clps711x-fb.c
@@ -287,14 +287,17 @@
 	}
 
 	ret = of_get_fb_videomode(disp, &cfb->mode, OF_USE_NATIVE_MODE);
-	if (ret)
+	if (ret) {
+		of_node_put(disp);
 		goto out_fb_release;
+	}
 
 	of_property_read_u32(disp, "ac-prescale", &cfb->ac_prescale);
 	cfb->cmap_invert = of_property_read_bool(disp, "cmap-invert");
 
 	ret = of_property_read_u32(disp, "bits-per-pixel",
 				   &info->var.bits_per_pixel);
+	of_node_put(disp);
 	if (ret)
 		goto out_fb_release;
 
--- linux-4.4.0.orig/drivers/video/fbdev/cobalt_lcdfb.c
+++ linux-4.4.0/drivers/video/fbdev/cobalt_lcdfb.c
@@ -350,6 +350,11 @@
 	info->screen_size = resource_size(res);
 	info->screen_base = devm_ioremap(&dev->dev, res->start,
 					 info->screen_size);
+	if (!info->screen_base) {
+		framebuffer_release(info);
+		return -ENOMEM;
+	}
+
 	info->fbops = &cobalt_lcd_fbops;
 	info->fix = cobalt_lcdfb_fix;
 	info->fix.smem_start = res->start;
--- linux-4.4.0.orig/drivers/video/fbdev/controlfb.h
+++ linux-4.4.0/drivers/video/fbdev/controlfb.h
@@ -141,5 +141,7 @@
 	{{ 1, 2}},	/* 1152x870, 75Hz */
 	{{ 0, 1}},	/* 1280x960, 75Hz */
 	{{ 0, 1}},	/* 1280x1024, 75Hz */
+	{{ 1, 2}},	/* 1152x768, 60Hz */
+	{{ 0, 1}},	/* 1600x1024, 60Hz */
 };
 
--- linux-4.4.0.orig/drivers/video/fbdev/core/fbcmap.c
+++ linux-4.4.0/drivers/video/fbdev/core/fbcmap.c
@@ -94,6 +94,8 @@
 	int size = len * sizeof(u16);
 	int ret = -ENOMEM;
 
+	flags |= __GFP_NOWARN;
+
 	if (cmap->len != len) {
 		fb_dealloc_cmap(cmap);
 		if (!len)
@@ -163,17 +165,18 @@
 
 int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
 {
-	int tooff = 0, fromoff = 0;
-	int size;
+	unsigned int tooff = 0, fromoff = 0;
+	size_t size;
 
 	if (to->start > from->start)
 		fromoff = to->start - from->start;
 	else
 		tooff = from->start - to->start;
-	size = to->len - tooff;
-	if (size > (int) (from->len - fromoff))
-		size = from->len - fromoff;
-	if (size <= 0)
+	if (fromoff >= from->len || tooff >= to->len)
+		return -EINVAL;
+
+	size = min_t(size_t, to->len - tooff, from->len - fromoff);
+	if (size == 0)
 		return -EINVAL;
 	size *= sizeof(u16);
 
@@ -187,17 +190,18 @@
 
 int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
 {
-	int tooff = 0, fromoff = 0;
-	int size;
+	unsigned int tooff = 0, fromoff = 0;
+	size_t size;
 
 	if (to->start > from->start)
 		fromoff = to->start - from->start;
 	else
 		tooff = from->start - to->start;
-	size = to->len - tooff;
-	if (size > (int) (from->len - fromoff))
-		size = from->len - fromoff;
-	if (size <= 0)
+	if (fromoff >= from->len || tooff >= to->len)
+		return -EINVAL;
+
+	size = min_t(size_t, to->len - tooff, from->len - fromoff);
+	if (size == 0)
 		return -EINVAL;
 	size *= sizeof(u16);
 
--- linux-4.4.0.orig/drivers/video/fbdev/core/fbmem.c
+++ linux-4.4.0/drivers/video/fbdev/core/fbmem.c
@@ -35,6 +35,7 @@
 
 #include <asm/fb.h>
 
+#include "../../console/fbcon.h"
 
     /*
      *  Frame buffer device initialization and setup routines
@@ -425,6 +426,9 @@
 {
 	unsigned int x;
 
+	if (image->width > info->var.xres || image->height > info->var.yres)
+		return;
+
 	if (rotate == FB_ROTATE_UR) {
 		for (x = 0;
 		     x < num && image->dx + image->width <= info->var.xres;
@@ -433,7 +437,9 @@
 			image->dx += image->width + 8;
 		}
 	} else if (rotate == FB_ROTATE_UD) {
-		for (x = 0; x < num; x++) {
+		u32 dx = image->dx;
+
+		for (x = 0; x < num && image->dx <= dx; x++) {
 			info->fbops->fb_imageblit(info, image);
 			image->dx -= image->width + 8;
 		}
@@ -445,7 +451,9 @@
 			image->dy += image->height + 8;
 		}
 	} else if (rotate == FB_ROTATE_CCW) {
-		for (x = 0; x < num; x++) {
+		u32 dy = image->dy;
+
+		for (x = 0; x < num && image->dy <= dy; x++) {
 			info->fbops->fb_imageblit(info, image);
 			image->dy -= image->height + 8;
 		}
@@ -999,6 +1007,16 @@
 		if (ret)
 			goto done;
 
+		/* verify that virtual resolution >= physical resolution */
+		if (var->xres_virtual < var->xres ||
+		    var->yres_virtual < var->yres) {
+			pr_warn("WARNING: fbcon: Driver '%s' missed to adjust virtual screen size (%ux%u vs. %ux%u)\n",
+				info->fix.id,
+				var->xres_virtual, var->yres_virtual,
+				var->xres, var->yres);
+			return -EINVAL;
+		}
+
 		if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
 			struct fb_var_screeninfo old_var;
 			struct fb_videomode mode;
@@ -1114,9 +1132,12 @@
 			console_unlock();
 			return -ENODEV;
 		}
-		info->flags |= FBINFO_MISC_USEREVENT;
-		ret = fb_set_var(info, &var);
-		info->flags &= ~FBINFO_MISC_USEREVENT;
+		ret = fbcon_modechange_possible(info, &var);
+		if (!ret) {
+			info->flags |= FBINFO_MISC_USEREVENT;
+			ret = fb_set_var(info, &var);
+			info->flags &= ~FBINFO_MISC_USEREVENT;
+		}
 		unlock_fb_info(info);
 		console_unlock();
 		if (!ret && copy_to_user(argp, &var, sizeof(var)))
@@ -1125,7 +1146,7 @@
 	case FBIOGET_FSCREENINFO:
 		if (!lock_fb_info(info))
 			return -ENODEV;
-		fix = info->fix;
+		memcpy(&fix, &info->fix, sizeof(fix));
 		unlock_fb_info(info);
 
 		ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
@@ -1687,12 +1708,12 @@
 	return 0;
 }
 
-static int do_unregister_framebuffer(struct fb_info *fb_info)
+static int unbind_console(struct fb_info *fb_info)
 {
 	struct fb_event event;
-	int i, ret = 0;
+	int ret;
+	int i = fb_info->node;
 
-	i = fb_info->node;
 	if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
 		return -EINVAL;
 
@@ -1707,17 +1728,29 @@
 	unlock_fb_info(fb_info);
 	console_unlock();
 
+	return ret;
+}
+
+static int __unlink_framebuffer(struct fb_info *fb_info);
+
+static int do_unregister_framebuffer(struct fb_info *fb_info)
+{
+	struct fb_event event;
+	int ret;
+
+	ret = unbind_console(fb_info);
+
 	if (ret)
 		return -EINVAL;
 
 	pm_vt_switch_unregister(fb_info->dev);
 
-	unlink_framebuffer(fb_info);
+	__unlink_framebuffer(fb_info);
 	if (fb_info->pixmap.addr &&
 	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
 		kfree(fb_info->pixmap.addr);
 	fb_destroy_modelist(&fb_info->modelist);
-	registered_fb[i] = NULL;
+	registered_fb[fb_info->node] = NULL;
 	num_registered_fb--;
 	fb_cleanup_device(fb_info);
 	event.info = fb_info;
@@ -1730,7 +1763,7 @@
 	return 0;
 }
 
-int unlink_framebuffer(struct fb_info *fb_info)
+static int __unlink_framebuffer(struct fb_info *fb_info)
 {
 	int i;
 
@@ -1742,6 +1775,20 @@
 		device_destroy(fb_class, MKDEV(FB_MAJOR, i));
 		fb_info->dev = NULL;
 	}
+
+	return 0;
+}
+
+int unlink_framebuffer(struct fb_info *fb_info)
+{
+	int ret;
+
+	ret = __unlink_framebuffer(fb_info);
+	if (ret)
+		return ret;
+
+	unbind_console(fb_info);
+
 	return 0;
 }
 EXPORT_SYMBOL(unlink_framebuffer);
--- linux-4.4.0.orig/drivers/video/fbdev/core/fbmon.c
+++ linux-4.4.0/drivers/video/fbdev/core/fbmon.c
@@ -997,97 +997,6 @@
 	DPRINTK("========================================\n");
 }
 
-/**
- * fb_edid_add_monspecs() - add monitor video modes from E-EDID data
- * @edid:	128 byte array with an E-EDID block
- * @spacs:	monitor specs to be extended
- */
-void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
-{
-	unsigned char *block;
-	struct fb_videomode *m;
-	int num = 0, i;
-	u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE];
-	u8 pos = 4, svd_n = 0;
-
-	if (!edid)
-		return;
-
-	if (!edid_checksum(edid))
-		return;
-
-	if (edid[0] != 0x2 ||
-	    edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE)
-		return;
-
-	DPRINTK("  Short Video Descriptors\n");
-
-	while (pos < edid[2]) {
-		u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7;
-		pr_debug("Data block %u of %u bytes\n", type, len);
-		if (type == 2) {
-			for (i = pos; i < pos + len; i++) {
-				u8 idx = edid[pos + i] & 0x7f;
-				svd[svd_n++] = idx;
-				pr_debug("N%sative mode #%d\n",
-					 edid[pos + i] & 0x80 ? "" : "on-n", idx);
-			}
-		} else if (type == 3 && len >= 3) {
-			/* Check Vendor Specific Data Block.  For HDMI,
-			   it is always 00-0C-03 for HDMI Licensing, LLC. */
-			if (edid[pos + 1] == 3 && edid[pos + 2] == 0xc &&
-			    edid[pos + 3] == 0)
-				specs->misc |= FB_MISC_HDMI;
-		}
-		pos += len + 1;
-	}
-
-	block = edid + edid[2];
-
-	DPRINTK("  Extended Detailed Timings\n");
-
-	for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE;
-	     i++, block += DETAILED_TIMING_DESCRIPTION_SIZE)
-		if (PIXEL_CLOCK)
-			edt[num++] = block - edid;
-
-	/* Yikes, EDID data is totally useless */
-	if (!(num + svd_n))
-		return;
-
-	m = kzalloc((specs->modedb_len + num + svd_n) *
-		       sizeof(struct fb_videomode), GFP_KERNEL);
-
-	if (!m)
-		return;
-
-	memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode));
-
-	for (i = specs->modedb_len; i < specs->modedb_len + num; i++) {
-		get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]);
-		if (i == specs->modedb_len)
-			m[i].flag |= FB_MODE_IS_FIRST;
-		pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh);
-	}
-
-	for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) {
-		int idx = svd[i - specs->modedb_len - num];
-		if (!idx || idx >= ARRAY_SIZE(cea_modes)) {
-			pr_warning("Reserved SVD code %d\n", idx);
-		} else if (!cea_modes[idx].xres) {
-			pr_warning("Unimplemented SVD code %d\n", idx);
-		} else {
-			memcpy(&m[i], cea_modes + idx, sizeof(m[i]));
-			pr_debug("Adding SVD #%d: %ux%u@%u\n", idx,
-				 m[i].xres, m[i].yres, m[i].refresh);
-		}
-	}
-
-	kfree(specs->modedb);
-	specs->modedb = m;
-	specs->modedb_len = specs->modedb_len + num + svd_n;
-}
-
 /*
  * VESA Generalized Timing Formula (GTF)
  */
@@ -1498,9 +1407,6 @@
 {
 	specs = NULL;
 }
-void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
-{
-}
 void fb_destroy_modedb(struct fb_videomode *modedb)
 {
 }
@@ -1608,7 +1514,6 @@
 
 EXPORT_SYMBOL(fb_parse_edid);
 EXPORT_SYMBOL(fb_edid_to_monspecs);
-EXPORT_SYMBOL(fb_edid_add_monspecs);
 EXPORT_SYMBOL(fb_get_mode);
 EXPORT_SYMBOL(fb_validate_mode);
 EXPORT_SYMBOL(fb_destroy_modedb);
--- linux-4.4.0.orig/drivers/video/fbdev/core/modedb.c
+++ linux-4.4.0/drivers/video/fbdev/core/modedb.c
@@ -289,63 +289,6 @@
 };
 
 #ifdef CONFIG_FB_MODE_HELPERS
-const struct fb_videomode cea_modes[65] = {
-	/* #1: 640x480p@59.94/60Hz */
-	[1] = {
-		NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0,
-		FB_VMODE_NONINTERLACED, 0,
-	},
-	/* #3: 720x480p@59.94/60Hz */
-	[3] = {
-		NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
-		FB_VMODE_NONINTERLACED, 0,
-	},
-	/* #5: 1920x1080i@59.94/60Hz */
-	[5] = {
-		NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
-		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-		FB_VMODE_INTERLACED, 0,
-	},
-	/* #7: 720(1440)x480iH@59.94/60Hz */
-	[7] = {
-		NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
-		FB_VMODE_INTERLACED, 0,
-	},
-	/* #9: 720(1440)x240pH@59.94/60Hz */
-	[9] = {
-		NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0,
-		FB_VMODE_NONINTERLACED, 0,
-	},
-	/* #18: 720x576pH@50Hz */
-	[18] = {
-		NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
-		FB_VMODE_NONINTERLACED, 0,
-	},
-	/* #19: 1280x720p@50Hz */
-	[19] = {
-		NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
-		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-		FB_VMODE_NONINTERLACED, 0,
-	},
-	/* #20: 1920x1080i@50Hz */
-	[20] = {
-		NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
-		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-		FB_VMODE_INTERLACED, 0,
-	},
-	/* #32: 1920x1080p@23.98/24Hz */
-	[32] = {
-		NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
-		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-		FB_VMODE_NONINTERLACED, 0,
-	},
-	/* #35: (2880)x480p4x@59.94/60Hz */
-	[35] = {
-		NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0,
-		FB_VMODE_NONINTERLACED, 0,
-	},
-};
-
 const struct fb_videomode vesa_modes[] = {
 	/* 0 640x350-85 VESA */
 	{ NULL, 85, 640, 350, 31746,  96, 32, 60, 32, 64, 3,
@@ -644,7 +587,7 @@
  *
  *     Valid mode specifiers for @mode_option:
  *
- *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][p][m] or
  *     <name>[-<bpp>][@<refresh>]
  *
  *     with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
@@ -653,10 +596,10 @@
  *      If 'M' is present after yres (and before refresh/bpp if present),
  *      the function will compute the timings using VESA(tm) Coordinated
  *      Video Timings (CVT).  If 'R' is present after 'M', will compute with
- *      reduced blanking (for flatpanels).  If 'i' is present, compute
- *      interlaced mode.  If 'm' is present, add margins equal to 1.8%
- *      of xres rounded down to 8 pixels, and 1.8% of yres. The char
- *      'i' and 'm' must be after 'M' and 'R'. Example:
+ *      reduced blanking (for flatpanels).  If 'i' or 'p' are present, compute
+ *      interlaced or progressive mode.  If 'm' is present, add margins equal
+ *      to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The chars
+ *      'i', 'p' and 'm' must be after 'M' and 'R'. Example:
  *
  *      1024x768MR-8@60m - Reduced blank with margins at 60Hz.
  *
@@ -697,7 +640,8 @@
 		unsigned int namelen = strlen(name);
 		int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
 		unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
-		int yres_specified = 0, cvt = 0, rb = 0, interlace = 0;
+		int yres_specified = 0, cvt = 0, rb = 0;
+		int interlace_specified = 0, interlace = 0;
 		int margins = 0;
 		u32 best, diff, tdiff;
 
@@ -748,9 +692,17 @@
 				if (!cvt)
 					margins = 1;
 				break;
+			case 'p':
+				if (!cvt) {
+					interlace = 0;
+					interlace_specified = 1;
+				}
+				break;
 			case 'i':
-				if (!cvt)
+				if (!cvt) {
 					interlace = 1;
+					interlace_specified = 1;
+				}
 				break;
 			default:
 				goto done;
@@ -819,11 +771,21 @@
 			if ((name_matches(db[i], name, namelen) ||
 			     (res_specified && res_matches(db[i], xres, yres))) &&
 			    !fb_try_mode(var, info, &db[i], bpp)) {
-				if (refresh_specified && db[i].refresh == refresh)
-					return 1;
+				const int db_interlace = (db[i].vmode &
+					FB_VMODE_INTERLACED ? 1 : 0);
+				int score = abs(db[i].refresh - refresh);
+
+				if (interlace_specified)
+					score += abs(db_interlace - interlace);
+
+				if (!interlace_specified ||
+				    db_interlace == interlace)
+					if (refresh_specified &&
+					    db[i].refresh == refresh)
+						return 1;
 
-				if (abs(db[i].refresh - refresh) < diff) {
-					diff = abs(db[i].refresh - refresh);
+				if (score < diff) {
+					diff = score;
 					best = i;
 				}
 			}
@@ -914,6 +876,9 @@
 	if (var->vmode & FB_VMODE_DOUBLE)
 		vtotal *= 2;
 
+	if (!htotal || !vtotal)
+		return;
+
 	hfreq = pixclock/htotal;
 	mode->refresh = hfreq/vtotal;
 }
--- linux-4.4.0.orig/drivers/video/fbdev/da8xx-fb.c
+++ linux-4.4.0/drivers/video/fbdev/da8xx-fb.c
@@ -209,8 +209,7 @@
 		.lower_margin   = 2,
 		.hsync_len      = 0,
 		.vsync_len      = 0,
-		.sync           = FB_SYNC_CLK_INVERT |
-			FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.sync           = FB_SYNC_CLK_INVERT,
 	},
 	/* Sharp LK043T1DG01 */
 	[1] = {
@@ -224,7 +223,7 @@
 		.lower_margin   = 2,
 		.hsync_len      = 41,
 		.vsync_len      = 10,
-		.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.sync           = 0,
 		.flag           = 0,
 	},
 	[2] = {
@@ -239,7 +238,7 @@
 		.lower_margin   = 10,
 		.hsync_len      = 10,
 		.vsync_len      = 10,
-		.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.sync           = 0,
 		.flag           = 0,
 	},
 	[3] = {
--- linux-4.4.0.orig/drivers/video/fbdev/efifb.c
+++ linux-4.4.0/drivers/video/fbdev/efifb.c
@@ -52,9 +52,9 @@
 		return 1;
 
 	if (regno < 16) {
-		red   >>= 8;
-		green >>= 8;
-		blue  >>= 8;
+		red   >>= 16 - info->var.red.length;
+		green >>= 16 - info->var.green.length;
+		blue  >>= 16 - info->var.blue.length;
 		((u32 *)(info->pseudo_palette))[regno] =
 			(red   << info->var.red.offset)   |
 			(green << info->var.green.offset) |
--- linux-4.4.0.orig/drivers/video/fbdev/exynos/s6e8ax0.c
+++ linux-4.4.0/drivers/video/fbdev/exynos/s6e8ax0.c
@@ -829,8 +829,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+static int __maybe_unused s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
 {
 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
 
@@ -843,7 +842,7 @@
 	return 0;
 }
 
-static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
+static int __maybe_unused s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
 {
 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
 
@@ -855,10 +854,6 @@
 
 	return 0;
 }
-#else
-#define s6e8ax0_suspend		NULL
-#define s6e8ax0_resume		NULL
-#endif
 
 static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
 	.name = "s6e8ax0",
@@ -867,8 +862,8 @@
 	.power_on = s6e8ax0_power_on,
 	.set_sequence = s6e8ax0_set_sequence,
 	.probe = s6e8ax0_probe,
-	.suspend = s6e8ax0_suspend,
-	.resume = s6e8ax0_resume,
+	.suspend = IS_ENABLED(CONFIG_PM) ? s6e8ax0_suspend : NULL,
+	.resume = IS_ENABLED(CONFIG_PM) ? s6e8ax0_resume : NULL,
 };
 
 static int s6e8ax0_init(void)
--- linux-4.4.0.orig/drivers/video/fbdev/geode/video_gx.c
+++ linux-4.4.0/drivers/video/fbdev/geode/video_gx.c
@@ -127,7 +127,7 @@
 	int timeout = 1000;
 
 	/* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */
-	if (cpu_data(0).x86_mask == 1) {
+	if (cpu_data(0).x86_stepping == 1) {
 		pll_table = gx_pll_table_14MHz;
 		pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
 	} else {
--- linux-4.4.0.orig/drivers/video/fbdev/goldfishfb.c
+++ linux-4.4.0/drivers/video/fbdev/goldfishfb.c
@@ -234,7 +234,7 @@
 	fb->fb.var.activate	= FB_ACTIVATE_NOW;
 	fb->fb.var.height	= readl(fb->reg_base + FB_GET_PHYS_HEIGHT);
 	fb->fb.var.width	= readl(fb->reg_base + FB_GET_PHYS_WIDTH);
-	fb->fb.var.pixclock	= 10000;
+	fb->fb.var.pixclock	= 0;
 
 	fb->fb.var.red.offset = 11;
 	fb->fb.var.red.length = 5;
@@ -301,6 +301,7 @@
 	dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base,
 						fb->fb.fix.smem_start);
 	iounmap(fb->reg_base);
+	kfree(fb);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/video/fbdev/hgafb.c
+++ linux-4.4.0/drivers/video/fbdev/hgafb.c
@@ -285,6 +285,8 @@
 	hga_vram_len  = 0x08000;
 
 	hga_vram = ioremap(0xb0000, hga_vram_len);
+	if (!hga_vram)
+		goto error;
 
 	if (request_region(0x3b0, 12, "hgafb"))
 		release_io_ports = 1;
--- linux-4.4.0.orig/drivers/video/fbdev/hyperv_fb.c
+++ linux-4.4.0/drivers/video/fbdev/hyperv_fb.c
@@ -712,7 +712,10 @@
 		goto err1;
 	}
 
-	fb_virt = ioremap(par->mem->start, screen_fb_size);
+	/*
+	 * Map the VRAM cacheable for performance.
+	 */
+	fb_virt = ioremap_wc(par->mem->start, screen_fb_size);
 	if (!fb_virt)
 		goto err2;
 
@@ -743,7 +746,7 @@
 err3:
 	iounmap(fb_virt);
 err2:
-	release_mem_region(par->mem->start, screen_fb_size);
+	vmbus_free_mmio(par->mem->start, screen_fb_size);
 	par->mem = NULL;
 err1:
 	if (!gen2vm)
@@ -758,7 +761,7 @@
 	struct hvfb_par *par = info->par;
 
 	iounmap(info->screen_base);
-	release_mem_region(par->mem->start, screen_fb_size);
+	vmbus_free_mmio(par->mem->start, screen_fb_size);
 	par->mem = NULL;
 }
 
--- linux-4.4.0.orig/drivers/video/fbdev/i740fb.c
+++ linux-4.4.0/drivers/video/fbdev/i740fb.c
@@ -657,6 +657,9 @@
 
 static int i740fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+	if (!var->pixclock)
+		return -EINVAL;
+
 	switch (var->bits_per_pixel) {
 	case 8:
 		var->red.offset	= var->green.offset = var->blue.offset = 0;
--- linux-4.4.0.orig/drivers/video/fbdev/imsttfb.c
+++ linux-4.4.0/drivers/video/fbdev/imsttfb.c
@@ -1517,6 +1517,11 @@
 	info->fix.smem_start = addr;
 	info->screen_base = (__u8 *)ioremap(addr, par->ramdac == IBM ?
 					    0x400000 : 0x800000);
+	if (!info->screen_base) {
+		release_mem_region(addr, size);
+		framebuffer_release(info);
+		return -ENOMEM;
+	}
 	info->fix.mmio_start = addr + 0x800000;
 	par->dc_regs = ioremap(addr + 0x800000, 0x1000);
 	par->cmap_regs_phys = addr + 0x840000;
--- linux-4.4.0.orig/drivers/video/fbdev/intelfb/intelfbdrv.c
+++ linux-4.4.0/drivers/video/fbdev/intelfb/intelfbdrv.c
@@ -302,7 +302,7 @@
 }
 
 static __inline__ int get_opt_bool(const char *this_opt, const char *name,
-				   int *ret)
+				   bool *ret)
 {
 	if (!ret)
 		return 0;
--- linux-4.4.0.orig/drivers/video/fbdev/matrox/matroxfb_Ti3026.c
+++ linux-4.4.0/drivers/video/fbdev/matrox/matroxfb_Ti3026.c
@@ -372,7 +372,7 @@
 
 	DBG(__func__)
 
-	memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
+	memcpy(hw->DACreg, MGADACbpp32, sizeof(MGADACbpp32));
 	switch (minfo->fbcon.var.bits_per_pixel) {
 		case 4:	hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1;	/* or _8_1, they are same */
 			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
--- linux-4.4.0.orig/drivers/video/fbdev/mmp/core.c
+++ linux-4.4.0/drivers/video/fbdev/mmp/core.c
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
+#include <linux/module.h>
 #include <video/mmp_disp.h>
 
 static struct mmp_overlay *path_get_overlay(struct mmp_path *path,
@@ -249,3 +250,7 @@
 	mutex_unlock(&disp_lock);
 }
 EXPORT_SYMBOL_GPL(mmp_unregister_path);
+
+MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");
+MODULE_DESCRIPTION("Marvell MMP display framework");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/video/fbdev/n411.c
+++ linux-4.4.0/drivers/video/fbdev/n411.c
@@ -187,11 +187,11 @@
 
 module_param(nosplash, uint, 0);
 MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
-module_param(dio_addr, ulong, 0);
+module_param_hw(dio_addr, ulong, ioport, 0);
 MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
-module_param(cio_addr, ulong, 0);
+module_param_hw(cio_addr, ulong, ioport, 0);
 MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
-module_param(c2io_addr, ulong, 0);
+module_param_hw(c2io_addr, ulong, ioport, 0);
 MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
 module_param(splashval, ulong, 0);
 MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white");
--- linux-4.4.0.orig/drivers/video/fbdev/neofb.c
+++ linux-4.4.0/drivers/video/fbdev/neofb.c
@@ -1820,6 +1820,7 @@
 #else
 		printk(KERN_ERR
 		       "neofb: Only 640x480, 800x600/480 and 1024x768 panels are currently supported\n");
+		kfree(info->monspecs.modedb);
 		return -1;
 #endif
 	default:
--- linux-4.4.0.orig/drivers/video/fbdev/omap/omapfb_main.c
+++ linux-4.4.0/drivers/video/fbdev/omap/omapfb_main.c
@@ -977,7 +977,7 @@
 {
 	int r;
 
-	if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
+	if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM)
 		return -EINVAL;
 
 	if (!notifier_inited) {
--- linux-4.4.0.orig/drivers/video/fbdev/omap2/dss/dss.c
+++ linux-4.4.0/drivers/video/fbdev/omap2/dss/dss.c
@@ -843,7 +843,7 @@
 };
 
 static const struct dss_features omap3630_dss_feats = {
-	.fck_div_max		=	32,
+	.fck_div_max		=	31,
 	.dss_fck_multiplier	=	1,
 	.parent_clk_name	=	"dpll4_ck",
 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
--- linux-4.4.0.orig/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
+++ linux-4.4.0/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
@@ -194,7 +194,7 @@
 	dss = of_find_matching_node(NULL, omapdss_of_match);
 
 	if (dss == NULL || !of_device_is_available(dss))
-		return 0;
+		goto put_node;
 
 	omapdss_walk_device(dss, true);
 
@@ -221,6 +221,8 @@
 		kfree(n);
 	}
 
+put_node:
+	of_node_put(dss);
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
+++ linux-4.4.0/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
@@ -496,6 +496,9 @@
 	if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
 		return -EFAULT;
 
+	if (mr->w > 4096 || mr->h > 4096)
+		return -EINVAL;
+
 	if (mr->w * mr->h * 3 > mr->buffer_size)
 		return -EINVAL;
 
@@ -509,7 +512,7 @@
 			mr->x, mr->y, mr->w, mr->h);
 
 	if (r > 0) {
-		if (copy_to_user(mr->buffer, buf, mr->buffer_size))
+		if (copy_to_user(mr->buffer, buf, r))
 			r = -EFAULT;
 	}
 
@@ -606,6 +609,8 @@
 
 	int r = 0;
 
+	memset(&p, 0, sizeof(p));
+
 	switch (cmd) {
 	case OMAPFB_SYNC_GFX:
 		DBG("ioctl SYNC_GFX\n");
--- linux-4.4.0.orig/drivers/video/fbdev/pmag-ba-fb.c
+++ linux-4.4.0/drivers/video/fbdev/pmag-ba-fb.c
@@ -129,7 +129,7 @@
 /*
  * Turn the hardware cursor off.
  */
-static void __init pmagbafb_erase_cursor(struct fb_info *info)
+static void pmagbafb_erase_cursor(struct fb_info *info)
 {
 	struct pmagbafb_par *par = info->par;
 
--- linux-4.4.0.orig/drivers/video/fbdev/pvr2fb.c
+++ linux-4.4.0/drivers/video/fbdev/pvr2fb.c
@@ -687,7 +687,7 @@
 		return -ENOMEM;
 
 	ret = get_user_pages_unlocked(current, current->mm, (unsigned long)buf,
-				      nr_pages, WRITE, 0, pages);
+				      nr_pages, pages, FOLL_WRITE);
 
 	if (ret < nr_pages) {
 		nr_pages = ret;
@@ -1029,6 +1029,8 @@
 	if (!options || !*options)
 		return 0;
 
+	cable_arg[0] = output_arg[0] = 0;
+
 	while ((this_opt = strsep(&options, ","))) {
 		if (!*this_opt)
 			continue;
--- linux-4.4.0.orig/drivers/video/fbdev/pxa168fb.c
+++ linux-4.4.0/drivers/video/fbdev/pxa168fb.c
@@ -712,7 +712,7 @@
 	/*
 	 * enable controller clock
 	 */
-	clk_enable(fbi->clk);
+	clk_prepare_enable(fbi->clk);
 
 	pxa168fb_set_par(info);
 
@@ -767,7 +767,7 @@
 failed_free_cmap:
 	fb_dealloc_cmap(&info->cmap);
 failed_free_clk:
-	clk_disable(fbi->clk);
+	clk_disable_unprepare(fbi->clk);
 failed_free_fbmem:
 	dma_free_coherent(fbi->dev, info->fix.smem_len,
 			info->screen_base, fbi->fb_start_dma);
@@ -807,7 +807,7 @@
 	dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
 				info->screen_base, info->fix.smem_start);
 
-	clk_disable(fbi->clk);
+	clk_disable_unprepare(fbi->clk);
 
 	framebuffer_release(info);
 
--- linux-4.4.0.orig/drivers/video/fbdev/pxa3xx-gcu.c
+++ linux-4.4.0/drivers/video/fbdev/pxa3xx-gcu.c
@@ -626,8 +626,8 @@
 	/* request the IRQ */
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(dev, "no IRQ defined\n");
-		return -ENODEV;
+		dev_err(dev, "no IRQ defined: %d\n", irq);
+		return irq;
 	}
 
 	ret = devm_request_irq(dev, irq, pxa3xx_gcu_handle_irq,
--- linux-4.4.0.orig/drivers/video/fbdev/pxafb.c
+++ linux-4.4.0/drivers/video/fbdev/pxafb.c
@@ -2273,6 +2273,7 @@
 	info = &fbi->fb;
 
 	pxafb_overlay_exit(fbi);
+	cancel_work_sync(&fbi->task);
 	unregister_framebuffer(info);
 
 	pxafb_disable_controller(fbi);
--- linux-4.4.0.orig/drivers/video/fbdev/sbuslib.c
+++ linux-4.4.0/drivers/video/fbdev/sbuslib.c
@@ -105,11 +105,11 @@
 		struct fbtype __user *f = (struct fbtype __user *) arg;
 
 		if (put_user(type, &f->fb_type) ||
-		    __put_user(info->var.yres, &f->fb_height) ||
-		    __put_user(info->var.xres, &f->fb_width) ||
-		    __put_user(fb_depth, &f->fb_depth) ||
-		    __put_user(0, &f->fb_cmsize) ||
-		    __put_user(fb_size, &f->fb_cmsize))
+		    put_user(info->var.yres, &f->fb_height) ||
+		    put_user(info->var.xres, &f->fb_width) ||
+		    put_user(fb_depth, &f->fb_depth) ||
+		    put_user(0, &f->fb_cmsize) ||
+		    put_user(fb_size, &f->fb_cmsize))
 			return -EFAULT;
 		return 0;
 	}
@@ -121,13 +121,13 @@
 		unsigned char __user *ured;
 		unsigned char __user *ugreen;
 		unsigned char __user *ublue;
-		int index, count, i;
+		unsigned int index, count, i;
 
 		if (get_user(index, &c->index) ||
-		    __get_user(count, &c->count) ||
-		    __get_user(ured, &c->red) ||
-		    __get_user(ugreen, &c->green) ||
-		    __get_user(ublue, &c->blue))
+		    get_user(count, &c->count) ||
+		    get_user(ured, &c->red) ||
+		    get_user(ugreen, &c->green) ||
+		    get_user(ublue, &c->blue))
 			return -EFAULT;
 
 		cmap.len = 1;
@@ -160,17 +160,17 @@
 		unsigned char __user *ugreen;
 		unsigned char __user *ublue;
 		struct fb_cmap *cmap = &info->cmap;
-		int index, count, i;
+		unsigned int index, count, i;
 		u8 red, green, blue;
 
 		if (get_user(index, &c->index) ||
-		    __get_user(count, &c->count) ||
-		    __get_user(ured, &c->red) ||
-		    __get_user(ugreen, &c->green) ||
-		    __get_user(ublue, &c->blue))
+		    get_user(count, &c->count) ||
+		    get_user(ured, &c->red) ||
+		    get_user(ugreen, &c->green) ||
+		    get_user(ublue, &c->blue))
 			return -EFAULT;
 
-		if (index + count > cmap->len)
+		if (index > cmap->len || count > cmap->len - index)
 			return -EINVAL;
 
 		for (i = 0; i < count; i++) {
--- linux-4.4.0.orig/drivers/video/fbdev/sis/init.c
+++ linux-4.4.0/drivers/video/fbdev/sis/init.c
@@ -2428,6 +2428,11 @@
 
    i = 0;
 
+	if (SiS_Pr->ChipType == SIS_730)
+		queuedata = &FQBQData730[0];
+	else
+		queuedata = &FQBQData[0];
+
    if(ModeNo > 0x13) {
 
       /* Get VCLK  */
@@ -2445,12 +2450,6 @@
       /* Get half colordepth */
       colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)];
 
-      if(SiS_Pr->ChipType == SIS_730) {
-	 queuedata = &FQBQData730[0];
-      } else {
-	 queuedata = &FQBQData[0];
-      }
-
       do {
 	 templ = SiS_CalcDelay2(SiS_Pr, queuedata[i]) * VCLK * colorth;
 
--- linux-4.4.0.orig/drivers/video/fbdev/sis/init301.c
+++ linux-4.4.0/drivers/video/fbdev/sis/init301.c
@@ -522,9 +522,7 @@
 	    SiS_DDC2Delay(SiS_Pr, 0x4000);
 	 }
 
-      } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* ||
-	 (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-	 (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) {			/* 315 series, LVDS; Special */
+      } else if (SiS_Pr->SiS_IF_DEF_LVDS == 1) {			/* 315 series, LVDS; Special */
 
 	 if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
 	    PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
@@ -2151,17 +2149,15 @@
 		unsigned short RefreshRateTableIndex)
 {
   unsigned short CRT2Index, VCLKIndex = 0, VCLKIndexGEN = 0, VCLKIndexGENCRT = 0;
-  unsigned short modeflag, resinfo, tempbx;
+  unsigned short resinfo, tempbx;
   const unsigned char *CHTVVCLKPtr = NULL;
 
   if(ModeNo <= 0x13) {
-     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
      CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
      VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03;
      VCLKIndexGENCRT = VCLKIndexGEN;
   } else {
-     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
      CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
      VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
@@ -7270,7 +7266,7 @@
 static void
 SiS_SetGroup4_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
 {
-   unsigned short temp, temp1, resinfo = 0;
+   unsigned short temp, temp1;
    unsigned char  *ROMAddr = SiS_Pr->VirtualRomBase;
 
    if(!(SiS_Pr->SiS_VBType & VB_SIS30xCLV)) return;
@@ -7282,10 +7278,6 @@
       if(!(ROMAddr[0x61] & 0x04)) return;
    }
 
-   if(ModeNo > 0x13) {
-      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-   }
-
    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0x08);
    temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x3a);
    if(!(temp & 0x01)) {
--- linux-4.4.0.orig/drivers/video/fbdev/sis/sis_main.c
+++ linux-4.4.0/drivers/video/fbdev/sis/sis_main.c
@@ -1437,6 +1437,8 @@
 
 	vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
 
+	if (!var->pixclock)
+		return -EINVAL;
 	pixclock = var->pixclock;
 
 	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
--- linux-4.4.0.orig/drivers/video/fbdev/sm501fb.c
+++ linux-4.4.0/drivers/video/fbdev/sm501fb.c
@@ -1600,6 +1600,7 @@
 	info->fbmem = ioremap(res->start, resource_size(res));
 	if (info->fbmem == NULL) {
 		dev_err(dev, "cannot remap framebuffer\n");
+		ret = -ENXIO;
 		goto err_mem_res;
 	}
 
--- linux-4.4.0.orig/drivers/video/fbdev/sm712.h
+++ linux-4.4.0/drivers/video/fbdev/sm712.h
@@ -15,14 +15,10 @@
 
 #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 SCREEN_X_RES          1024
+#define SCREEN_Y_RES_PC       768
+#define SCREEN_Y_RES_NETBOOK  600
+#define SCREEN_BPP            16
 
 #define dac_reg	(0x3c8)
 #define dac_val	(0x3c9)
--- linux-4.4.0.orig/drivers/video/fbdev/sm712fb.c
+++ linux-4.4.0/drivers/video/fbdev/sm712fb.c
@@ -28,9 +28,7 @@
 #include <linux/console.h>
 #include <linux/screen_info.h>
 
-#ifdef CONFIG_PM
 #include <linux/pm.h>
-#endif
 
 #include "sm712.h"
 
@@ -532,6 +530,65 @@
 			0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
 		},
 	},
+	{	/*  1024 x 768  16Bpp  60Hz */
+		1024, 768, 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, 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,
+			0x0F, 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#5: 1024 x 768  24Bpp  60Hz */
 		1024, 768, 24, 60,
 		/*  Init_MISC */
@@ -829,67 +886,80 @@
 
 static int smtc_blank(int blank_mode, struct fb_info *info)
 {
+	struct smtcfb_info *sfb = info->par;
+
 	/* clear DPMS setting */
 	switch (blank_mode) {
 	case FB_BLANK_UNBLANK:
 		/* Screen On: HSync: On, VSync : On */
+
+		switch (sfb->chip_id) {
+		case 0x710:
+		case 0x712:
+			smtc_seqw(0x6a, 0x16);
+			smtc_seqw(0x6b, 0x02);
+			break;
+		case 0x720:
+			smtc_seqw(0x6a, 0x0d);
+			smtc_seqw(0x6b, 0x02);
+			break;
+		}
+
+		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
 		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));
+		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
 		break;
 	case FB_BLANK_NORMAL:
 		/* Screen Off: HSync: On, VSync : On   Soft blank */
+		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
 		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
 		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(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
 		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(0x20, (smtc_seqr(0x20) & (~0xB0)));
 		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));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
 		break;
 	case FB_BLANK_HSYNC_SUSPEND:
 		/* Screen On: HSync: Off, VSync : On */
+		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
 		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(0x20, (smtc_seqr(0x20) & (~0xB0)));
 		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));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
 		break;
 	case FB_BLANK_POWERDOWN:
 		/* Screen On: HSync: Off, VSync : Off */
+		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
 		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(0x20, (smtc_seqr(0x20) & (~0xB0)));
 		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));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
 		break;
 	default:
 		return -EINVAL;
@@ -976,7 +1046,7 @@
 	if (count + p > total_size)
 		count = total_size - p;
 
-	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+	buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
 
@@ -988,24 +1058,13 @@
 	while (count) {
 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 		dst = buffer;
-		for (i = c >> 2; i--;) {
-			*dst = fb_readl(src++);
-			*dst = big_swap(*dst);
-			dst++;
-		}
-		if (c & 3) {
-			u8 *dst8 = (u8 *)dst;
-			u8 __iomem *src8 = (u8 __iomem *)src;
+		for (i = (c + 3) >> 2; i--;) {
+			u32 val;
 
-			for (i = c & 3; i--;) {
-				if (i & 1) {
-					*dst8++ = fb_readb(++src8);
-				} else {
-					*dst8++ = fb_readb(--src8);
-					src8 += 2;
-				}
-			}
-			src = (u32 __iomem *)src8;
+			val = fb_readl(src);
+			*dst = big_swap(val);
+			src++;
+			dst++;
 		}
 
 		if (copy_to_user(buf, buffer, c)) {
@@ -1146,8 +1205,10 @@
 
 		/* init SEQ register SR30 - SR75 */
 		for (i = 0; i < SIZE_SR30_SR75; i++)
-			if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a &&
-			    (i + 0x30) != 0x6b)
+			if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 &&
+			    (i + 0x30) != 0x6a && (i + 0x30) != 0x6b &&
+			    (i + 0x30) != 0x70 && (i + 0x30) != 0x71 &&
+			    (i + 0x30) != 0x74 && (i + 0x30) != 0x75)
 				smtc_seqw(i + 0x30,
 					  vgamode[j].init_sr30_sr75[i]);
 
@@ -1172,8 +1233,12 @@
 			smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
 
 		/* init CRTC register CR30 - CR4D */
-		for (i = 0; i < SIZE_CR30_CR4D; i++)
+		for (i = 0; i < SIZE_CR30_CR4D; i++) {
+			if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F)
+				/* side-effect, don't write to CR3B-CR3F */
+				continue;
 			smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
+		}
 
 		/* init CRTC register CR90 - CRA7 */
 		for (i = 0; i < SIZE_CR90_CRA7; i++)
@@ -1324,6 +1389,11 @@
 {
 	sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
 
+	if (sfb->chip_id == 0x720)
+		/* on SM720, the framebuffer starts at the 1 MB offset */
+		sfb->fb->fix.smem_start += 0x00200000;
+
+	/* XXX: is it safe for SM720 on Big-Endian? */
 	if (sfb->fb->var.bits_per_pixel == 32)
 		sfb->fb->fix.smem_start += big_addr;
 
@@ -1347,6 +1417,8 @@
 static void smtc_unmap_smem(struct smtcfb_info *sfb)
 {
 	if (sfb && sfb->fb->screen_base) {
+		if (sfb->chip_id == 0x720)
+			sfb->fb->screen_base -= 0x00200000;
 		iounmap(sfb->fb->screen_base);
 		sfb->fb->screen_base = NULL;
 	}
@@ -1361,12 +1433,82 @@
 	outb_p(0x11, 0x3c5);
 }
 
+static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
+{
+	u8 vram;
+
+	switch (sfb->chip_id) {
+	case 0x710:
+	case 0x712:
+		/*
+		 * Assume SM712 graphics chip has 4MB VRAM.
+		 *
+		 * FIXME: SM712 can have 2MB VRAM, which is used on earlier
+		 * laptops, such as IBM Thinkpad 240X. This driver would
+		 * probably crash on those machines. If anyone gets one of
+		 * those and is willing to help, run "git blame" and send me
+		 * an E-mail.
+		 */
+		return 0x00400000;
+	case 0x720:
+		outb_p(0x76, 0x3c4);
+		vram = inb_p(0x3c5) >> 6;
+
+		if (vram == 0x00)
+			return 0x00800000;  /* 8 MB */
+		else if (vram == 0x01)
+			return 0x01000000;  /* 16 MB */
+		else if (vram == 0x02)
+			return 0x00400000;  /* illegal, fallback to 4 MB */
+		else if (vram == 0x03)
+			return 0x00400000;  /* 4 MB */
+	}
+	return 0;  /* unknown hardware */
+}
+
+static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
+{
+	/* get mode parameter from smtc_scr_info */
+	if (smtc_scr_info.lfb_width != 0) {
+		sfb->fb->var.xres = smtc_scr_info.lfb_width;
+		sfb->fb->var.yres = smtc_scr_info.lfb_height;
+		sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
+		goto final;
+	}
+
+	/*
+	 * No parameter, default resolution is 1024x768-16.
+	 *
+	 * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
+	 * panel, also see the comments about Thinkpad 240X above.
+	 */
+	sfb->fb->var.xres = SCREEN_X_RES;
+	sfb->fb->var.yres = SCREEN_Y_RES_PC;
+	sfb->fb->var.bits_per_pixel = SCREEN_BPP;
+
+#ifdef CONFIG_MIPS
+	/*
+	 * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
+	 * target platform of this driver, but nearly all old x86 laptops have
+	 * 1024x768. Lighting 768 panels using 600's timings would partially
+	 * garble the display, so we don't want that. But it's not possible to
+	 * distinguish them reliably.
+	 *
+	 * So we change the default to 768, but keep 600 as-is on MIPS.
+	 */
+	sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
+#endif
+
+final:
+	big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
+}
+
 static int smtcfb_pci_probe(struct pci_dev *pdev,
 			    const struct pci_device_id *ent)
 {
 	struct smtcfb_info *sfb;
 	struct fb_info *info;
-	u_long smem_size = 0x00800000;	/* default 8MB */
+	u_long smem_size;
 	int err;
 	unsigned long mmio_base;
 
@@ -1406,29 +1548,19 @@
 
 	sm7xx_init_hw();
 
-	/* get mode parameter from smtc_scr_info */
-	if (smtc_scr_info.lfb_width != 0) {
-		sfb->fb->var.xres = smtc_scr_info.lfb_width;
-		sfb->fb->var.yres = smtc_scr_info.lfb_height;
-		sfb->fb->var.bits_per_pixel = smtc_scr_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;
-	}
-
-	big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
 	/* Map address and memory detection */
 	mmio_base = pci_resource_start(pdev, 0);
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
 
+	smem_size = sm7xx_vram_probe(sfb);
+	dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
+					smem_size / 1048576);
+
 	switch (sfb->chip_id) {
 	case 0x710:
 	case 0x712:
 		sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
 		sfb->fb->fix.mmio_len = 0x00400000;
-		smem_size = SM712_VIDEOMEMORYSIZE;
 		sfb->lfb = ioremap(mmio_base, mmio_addr);
 		if (!sfb->lfb) {
 			dev_err(&pdev->dev,
@@ -1460,8 +1592,7 @@
 	case 0x720:
 		sfb->fb->fix.mmio_start = mmio_base;
 		sfb->fb->fix.mmio_len = 0x00200000;
-		smem_size = SM722_VIDEOMEMORYSIZE;
-		sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
+		sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
 		sfb->lfb = sfb->dp_regs + 0x00200000;
 		sfb->mmio = (smtc_regbaseaddress =
 		    sfb->dp_regs + 0x000c0000);
@@ -1478,6 +1609,9 @@
 		goto failed_fb;
 	}
 
+	/* probe and decide resolution */
+	sm7xx_resolution_probe(sfb);
+
 	/* can support 32 bpp */
 	if (15 == sfb->fb->var.bits_per_pixel)
 		sfb->fb->var.bits_per_pixel = 16;
@@ -1488,7 +1622,11 @@
 	if (err)
 		goto failed;
 
-	smtcfb_setmode(sfb);
+	/*
+	 * The screen would be temporarily garbled when sm712fb takes over
+	 * vesafb or VGA text mode. Zero the framebuffer.
+	 */
+	memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
 
 	err = register_framebuffer(info);
 	if (err < 0)
@@ -1545,8 +1683,7 @@
 	pci_disable_device(pdev);
 }
 
-#ifdef CONFIG_PM
-static int smtcfb_pci_suspend(struct device *device)
+static int __maybe_unused smtcfb_pci_suspend(struct device *device)
 {
 	struct pci_dev *pdev = to_pci_dev(device);
 	struct smtcfb_info *sfb;
@@ -1569,7 +1706,7 @@
 	return 0;
 }
 
-static int smtcfb_pci_resume(struct device *device)
+static int __maybe_unused smtcfb_pci_resume(struct device *device)
 {
 	struct pci_dev *pdev = to_pci_dev(device);
 	struct smtcfb_info *sfb;
@@ -1610,20 +1747,13 @@
 }
 
 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, 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 = smtcfb_pci_remove,
-	.driver.pm  = SM7XX_PM_OPS,
+	.driver.pm  = &sm7xx_pm_ops,
 };
 
 static int __init sm712fb_init(void)
--- linux-4.4.0.orig/drivers/video/fbdev/smscufx.c
+++ linux-4.4.0/drivers/video/fbdev/smscufx.c
@@ -140,6 +140,8 @@
 static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size);
 static void ufx_free_urb_list(struct ufx_data *dev);
 
+static DEFINE_MUTEX(disconnect_mutex);
+
 /* reads a control register */
 static int ufx_reg_read(struct ufx_data *dev, u32 index, u32 *data)
 {
@@ -1073,9 +1075,13 @@
 	if (user == 0 && !console)
 		return -EBUSY;
 
+	mutex_lock(&disconnect_mutex);
+
 	/* If the USB device is gone, we don't accept new opens */
-	if (dev->virtualized)
+	if (dev->virtualized) {
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
+	}
 
 	dev->fb_count++;
 
@@ -1100,6 +1106,8 @@
 	pr_debug("open /dev/fb%d user=%d fb_info=%p count=%d",
 		info->node, user, info, dev->fb_count);
 
+	mutex_unlock(&disconnect_mutex);
+
 	return 0;
 }
 
@@ -1763,6 +1771,8 @@
 	struct ufx_data *dev;
 	struct fb_info *info;
 
+	mutex_lock(&disconnect_mutex);
+
 	dev = usb_get_intfdata(interface);
 	info = dev->info;
 
@@ -1784,6 +1794,8 @@
 	kref_put(&dev->kref, ufx_free);
 
 	/* consider ufx_data freed */
+
+	mutex_unlock(&disconnect_mutex);
 }
 
 static struct usb_driver ufx_driver = {
--- linux-4.4.0.orig/drivers/video/fbdev/ssd1307fb.c
+++ linux-4.4.0/drivers/video/fbdev/ssd1307fb.c
@@ -421,7 +421,7 @@
 	if (ret < 0)
 		return ret;
 
-	ret = ssd1307fb_write_cmd(par->client, 0x0);
+	ret = ssd1307fb_write_cmd(par->client, par->page_offset);
 	if (ret < 0)
 		return ret;
 
--- linux-4.4.0.orig/drivers/video/fbdev/udlfb.c
+++ linux-4.4.0/drivers/video/fbdev/udlfb.c
@@ -769,11 +769,11 @@
 
 	for (i = 0; i < len; i++) {
 		ret = usb_control_msg(dev->udev,
-				    usb_rcvctrlpipe(dev->udev, 0), (0x02),
-				    (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
-				    HZ);
-		if (ret < 1) {
-			pr_err("Read EDID byte %d failed err %x\n", i, ret);
+				      usb_rcvctrlpipe(dev->udev, 0), 0x02,
+				      (0x80 | (0x02 << 5)), i << 8, 0xA1,
+				      rbuf, 2, USB_CTRL_GET_TIMEOUT);
+		if (ret < 2) {
+			pr_err("Read EDID byte %d failed: %d\n", i, ret);
 			i--;
 			break;
 		}
@@ -1487,15 +1487,25 @@
 static int dlfb_select_std_channel(struct dlfb_data *dev)
 {
 	int ret;
-	u8 set_def_chn[] = {	   0x57, 0xCD, 0xDC, 0xA7,
+	void *buf;
+	static const u8 set_def_chn[] = {
+				0x57, 0xCD, 0xDC, 0xA7,
 				0x1C, 0x88, 0x5E, 0x15,
 				0x60, 0xFE, 0xC6, 0x97,
 				0x16, 0x3D, 0x47, 0xF2  };
 
+	buf = kmemdup(set_def_chn, sizeof(set_def_chn), GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
 	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
 			NR_USB_REQUEST_CHANNEL,
 			(USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
-			set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
+			buf, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
+
+	kfree(buf);
+
 	return ret;
 }
 
--- linux-4.4.0.orig/drivers/video/fbdev/uvesafb.c
+++ linux-4.4.0/drivers/video/fbdev/uvesafb.c
@@ -1059,7 +1059,8 @@
 		    info->cmap.len || cmap->start < info->cmap.start)
 			return -EINVAL;
 
-		entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL);
+		entries = kmalloc_array(cmap->len, sizeof(*entries),
+					GFP_KERNEL);
 		if (!entries)
 			return -ENOMEM;
 
--- linux-4.4.0.orig/drivers/video/fbdev/vesafb.c
+++ linux-4.4.0/drivers/video/fbdev/vesafb.c
@@ -51,7 +51,7 @@
 };
 
 static int   inverse    __read_mostly;
-static int   mtrr       __read_mostly;		/* disable mtrr */
+static int   mtrr       __read_mostly = 3;	/* enable mtrr write-comb. */
 static int   vram_remap;			/* Set amount of memory to be used */
 static int   vram_total;			/* Set total amount of memory */
 static int   pmi_setpal __read_mostly = 1;	/* pmi for palette changes ??? */
--- linux-4.4.0.orig/drivers/video/fbdev/vfb.c
+++ linux-4.4.0/drivers/video/fbdev/vfb.c
@@ -291,8 +291,23 @@
  */
 static int vfb_set_par(struct fb_info *info)
 {
+	switch (info->var.bits_per_pixel) {
+	case 1:
+		info->fix.visual = FB_VISUAL_MONO01;
+		break;
+	case 8:
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 16:
+	case 24:
+	case 32:
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
+	}
+
 	info->fix.line_length = get_line_length(info->var.xres_virtual,
 						info->var.bits_per_pixel);
+
 	return 0;
 }
 
@@ -525,6 +540,8 @@
 		goto err2;
 	platform_set_drvdata(dev, info);
 
+	vfb_set_par(info);
+
 	fb_info(info, "Virtual frame buffer device, using %ldK of video memory\n",
 		videomemorysize >> 10);
 	return 0;
--- linux-4.4.0.orig/drivers/video/fbdev/vga16fb.c
+++ linux-4.4.0/drivers/video/fbdev/vga16fb.c
@@ -243,7 +243,7 @@
 }
 
 static void vga16fb_clock_chip(struct vga16fb_par *par,
-			       unsigned int pixclock,
+			       unsigned int *pixclock,
 			       const struct fb_info *info,
 			       int mul, int div)
 {
@@ -259,14 +259,14 @@
 		{     0 /* bad */,    0x00, 0x00}};
 	int err;
 
-	pixclock = (pixclock * mul) / div;
+	*pixclock = (*pixclock * mul) / div;
 	best = vgaclocks;
-	err = pixclock - best->pixclock;
+	err = *pixclock - best->pixclock;
 	if (err < 0) err = -err;
 	for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
 		int tmp;
 
-		tmp = pixclock - ptr->pixclock;
+		tmp = *pixclock - ptr->pixclock;
 		if (tmp < 0) tmp = -tmp;
 		if (tmp < err) {
 			err = tmp;
@@ -275,7 +275,7 @@
 	}
 	par->misc |= best->misc;
 	par->clkdiv = best->seq_clock_mode;
-	pixclock = (best->pixclock * div) / mul;		
+	*pixclock = (best->pixclock * div) / mul;
 }
 			       
 #define FAIL(X) return -EINVAL
@@ -497,10 +497,10 @@
 
 	if (mode & MODE_8BPP)
 		/* pixel clock == vga clock / 2 */
-		vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
+		vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
 	else
 		/* pixel clock == vga clock */
-		vga16fb_clock_chip(par, var->pixclock, info, 1, 1);
+		vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
 	
 	var->red.offset = var->green.offset = var->blue.offset = 
 	var->transp.offset = 0;
@@ -1122,7 +1122,7 @@
         char oldop = setop(0);
         char oldsr = setsr(0);
         char oldmask = selectmask();
-        const char *cdat = image->data;
+	const unsigned char *cdat = image->data;
 	u32 dx = image->dx;
         char __iomem *where;
         int y;
--- linux-4.4.0.orig/drivers/video/fbdev/via/viafbdev.c
+++ linux-4.4.0/drivers/video/fbdev/via/viafbdev.c
@@ -19,6 +19,7 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
@@ -1468,7 +1469,7 @@
 
 #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
 
-static int viafb_sup_odev_proc_show(struct seq_file *m, void *v)
+static int __maybe_unused viafb_sup_odev_proc_show(struct seq_file *m, void *v)
 {
 	via_odev_to_seq(m, supported_odev_map[
 		viaparinfo->shared->chip_info.gfx_chip_name]);
@@ -1630,16 +1631,14 @@
 }
 static void viafb_remove_proc(struct viafb_shared *shared)
 {
-	struct proc_dir_entry *viafb_entry = shared->proc_entry,
-		*iga1_entry = shared->iga1_proc_entry,
-		*iga2_entry = shared->iga2_proc_entry;
+	struct proc_dir_entry *viafb_entry = shared->proc_entry;
 
 	if (!viafb_entry)
 		return;
 
-	remove_proc_entry("output_devices", iga2_entry);
+	remove_proc_entry("output_devices", shared->iga2_proc_entry);
 	remove_proc_entry("iga2", viafb_entry);
-	remove_proc_entry("output_devices", iga1_entry);
+	remove_proc_entry("output_devices", shared->iga1_proc_entry);
 	remove_proc_entry("iga1", viafb_entry);
 	remove_proc_entry("supported_output_devices", viafb_entry);
 
--- linux-4.4.0.orig/drivers/video/fbdev/w100fb.c
+++ linux-4.4.0/drivers/video/fbdev/w100fb.c
@@ -583,6 +583,7 @@
 		memsize=par->mach->mem->size;
 		memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
 		vfree(par->saved_extmem);
+		par->saved_extmem = NULL;
 	}
 	if (par->saved_intmem) {
 		memsize=MEM_INT_SIZE;
@@ -591,6 +592,7 @@
 		else
 			memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
 		vfree(par->saved_intmem);
+		par->saved_intmem = NULL;
 	}
 }
 
--- linux-4.4.0.orig/drivers/video/fbdev/xen-fbfront.c
+++ linux-4.4.0/drivers/video/fbdev/xen-fbfront.c
@@ -644,7 +644,6 @@
 		break;
 
 	case XenbusStateInitWait:
-InitWait:
 		xenbus_switch_state(dev, XenbusStateConnected);
 		break;
 
@@ -655,7 +654,8 @@
 		 * get Connected twice here.
 		 */
 		if (dev->state != XenbusStateConnected)
-			goto InitWait; /* no InitWait seen yet, fudge it */
+			/* no InitWait seen yet, fudge it */
+			xenbus_switch_state(dev, XenbusStateConnected);
 
 		if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
 				 "request-update", "%d", &val) < 0)
--- linux-4.4.0.orig/drivers/video/hdmi.c
+++ linux-4.4.0/drivers/video/hdmi.c
@@ -321,6 +321,17 @@
 }
 EXPORT_SYMBOL(hdmi_vendor_infoframe_init);
 
+static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
+{
+	/* for side by side (half) we also need to provide 3D_Ext_Data */
+	if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
+		return 6;
+	else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return 5;
+	else
+		return 4;
+}
+
 /**
  * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
  * @frame: HDMI infoframe
@@ -341,19 +352,11 @@
 	u8 *ptr = buffer;
 	size_t length;
 
-	/* empty info frame */
-	if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID)
-		return -EINVAL;
-
 	/* only one of those can be supplied */
 	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
 		return -EINVAL;
 
-	/* for side by side (half) we also need to provide 3D_Ext_Data */
-	if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
-		frame->length = 6;
-	else
-		frame->length = 5;
+	frame->length = hdmi_vendor_infoframe_length(frame);
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -372,14 +375,16 @@
 	ptr[5] = 0x0c;
 	ptr[6] = 0x00;
 
-	if (frame->vic) {
-		ptr[7] = 0x1 << 5;	/* video format */
-		ptr[8] = frame->vic;
-	} else {
+	if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
 		ptr[7] = 0x2 << 5;	/* video format */
 		ptr[8] = (frame->s3d_struct & 0xf) << 4;
 		if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
 			ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
+	} else if (frame->vic) {
+		ptr[7] = 0x1 << 5;	/* video format */
+		ptr[8] = frame->vic;
+	} else {
+		ptr[7] = 0x0 << 5;	/* video format */
 	}
 
 	hdmi_infoframe_set_checksum(buffer, length);
@@ -1027,12 +1032,12 @@
 	if (ptr[0] & 0x10)
 		frame->active_aspect = ptr[1] & 0xf;
 	if (ptr[0] & 0x8) {
-		frame->top_bar = (ptr[5] << 8) + ptr[6];
-		frame->bottom_bar = (ptr[7] << 8) + ptr[8];
+		frame->top_bar = (ptr[6] << 8) | ptr[5];
+		frame->bottom_bar = (ptr[8] << 8) | ptr[7];
 	}
 	if (ptr[0] & 0x4) {
-		frame->left_bar = (ptr[9] << 8) + ptr[10];
-		frame->right_bar = (ptr[11] << 8) + ptr[12];
+		frame->left_bar = (ptr[10] << 8) | ptr[9];
+		frame->right_bar = (ptr[12] << 8) | ptr[11];
 	}
 	frame->scan_mode = ptr[0] & 0x3;
 
@@ -1161,7 +1166,7 @@
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
 	    ptr[1] != 1 ||
-	    (ptr[2] != 5 && ptr[2] != 6))
+	    (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
 		return -EINVAL;
 
 	length = ptr[2];
@@ -1189,16 +1194,22 @@
 
 	hvf->length = length;
 
-	if (hdmi_video_format == 0x1) {
-		hvf->vic = ptr[4];
-	} else if (hdmi_video_format == 0x2) {
+	if (hdmi_video_format == 0x2) {
+		if (length != 5 && length != 6)
+			return -EINVAL;
 		hvf->s3d_struct = ptr[4] >> 4;
 		if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
-			if (length == 6)
-				hvf->s3d_ext_data = ptr[5] >> 4;
-			else
+			if (length != 6)
 				return -EINVAL;
+			hvf->s3d_ext_data = ptr[5] >> 4;
 		}
+	} else if (hdmi_video_format == 0x1) {
+		if (length != 5)
+			return -EINVAL;
+		hvf->vic = ptr[4];
+	} else {
+		if (length != 4)
+			return -EINVAL;
 	}
 
 	return 0;
--- linux-4.4.0.orig/drivers/virt/fsl_hypervisor.c
+++ linux-4.4.0/drivers/virt/fsl_hypervisor.c
@@ -157,7 +157,7 @@
 
 	unsigned int i;
 	long ret = 0;
-	int num_pinned; /* return value from get_user_pages() */
+	int num_pinned = 0; /* return value from get_user_pages_fast() */
 	phys_addr_t remote_paddr; /* The next address in the remote buffer */
 	uint32_t count; /* The number of bytes left to copy */
 
@@ -174,7 +174,7 @@
 		return -EINVAL;
 
 	/*
-	 * The array of pages returned by get_user_pages() covers only
+	 * The array of pages returned by get_user_pages_fast() covers only
 	 * page-aligned memory.  Since the user buffer is probably not
 	 * page-aligned, we need to handle the discrepancy.
 	 *
@@ -215,13 +215,16 @@
 	 * hypervisor.
 	 */
 	lb_offset = param.local_vaddr & (PAGE_SIZE - 1);
+	if (param.count == 0 ||
+	    param.count > U64_MAX - lb_offset - PAGE_SIZE + 1)
+		return -EINVAL;
 	num_pages = (param.count + lb_offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
 	/* Allocate the buffers we need */
 
 	/*
 	 * 'pages' is an array of struct page pointers that's initialized by
-	 * get_user_pages().
+	 * get_user_pages_fast().
 	 */
 	pages = kzalloc(num_pages * sizeof(struct page *), GFP_KERNEL);
 	if (!pages) {
@@ -238,7 +241,7 @@
 	if (!sg_list_unaligned) {
 		pr_debug("fsl-hv: could not allocate S/G list\n");
 		ret = -ENOMEM;
-		goto exit;
+		goto free_pages;
 	}
 	sg_list = PTR_ALIGN(sg_list_unaligned, sizeof(struct fh_sg_list));
 
@@ -246,12 +249,11 @@
 	down_read(&current->mm->mmap_sem);
 	num_pinned = get_user_pages(current, current->mm,
 		param.local_vaddr - lb_offset, num_pages,
-		(param.source == -1) ? READ : WRITE,
-		0, pages, NULL);
+		(param.source == -1) ? 0 : FOLL_WRITE,
+		pages, NULL);
 	up_read(&current->mm->mmap_sem);
 
 	if (num_pinned != num_pages) {
-		/* get_user_pages() failed */
 		pr_debug("fsl-hv: could not lock source buffer\n");
 		ret = (num_pinned < 0) ? num_pinned : -EFAULT;
 		goto exit;
@@ -293,13 +295,13 @@
 		virt_to_phys(sg_list), num_pages);
 
 exit:
-	if (pages) {
-		for (i = 0; i < num_pages; i++)
-			if (pages[i])
-				put_page(pages[i]);
+	if (pages && (num_pinned > 0)) {
+		for (i = 0; i < num_pinned; i++)
+			put_page(pages[i]);
 	}
 
 	kfree(sg_list_unaligned);
+free_pages:
 	kfree(pages);
 
 	if (!ret)
@@ -335,8 +337,8 @@
 	struct fsl_hv_ioctl_prop param;
 	char __user *upath, *upropname;
 	void __user *upropval;
-	char *path = NULL, *propname = NULL;
-	void *propval = NULL;
+	char *path, *propname;
+	void *propval;
 	int ret = 0;
 
 	/* Get the parameters from the user. */
@@ -348,32 +350,30 @@
 	upropval = (void __user *)(uintptr_t)param.propval;
 
 	path = strndup_user(upath, FH_DTPROP_MAX_PATHLEN);
-	if (IS_ERR(path)) {
-		ret = PTR_ERR(path);
-		goto out;
-	}
+	if (IS_ERR(path))
+		return PTR_ERR(path);
 
 	propname = strndup_user(upropname, FH_DTPROP_MAX_PATHLEN);
 	if (IS_ERR(propname)) {
 		ret = PTR_ERR(propname);
-		goto out;
+		goto err_free_path;
 	}
 
 	if (param.proplen > FH_DTPROP_MAX_PROPLEN) {
 		ret = -EINVAL;
-		goto out;
+		goto err_free_propname;
 	}
 
 	propval = kmalloc(param.proplen, GFP_KERNEL);
 	if (!propval) {
 		ret = -ENOMEM;
-		goto out;
+		goto err_free_propname;
 	}
 
 	if (set) {
 		if (copy_from_user(propval, upropval, param.proplen)) {
 			ret = -EFAULT;
-			goto out;
+			goto err_free_propval;
 		}
 
 		param.ret = fh_partition_set_dtprop(param.handle,
@@ -392,7 +392,7 @@
 			if (copy_to_user(upropval, propval, param.proplen) ||
 			    put_user(param.proplen, &p->proplen)) {
 				ret = -EFAULT;
-				goto out;
+				goto err_free_propval;
 			}
 		}
 	}
@@ -400,10 +400,12 @@
 	if (put_user(param.ret, &p->ret))
 		ret = -EFAULT;
 
-out:
-	kfree(path);
+err_free_propval:
 	kfree(propval);
+err_free_propname:
 	kfree(propname);
+err_free_path:
+	kfree(path);
 
 	return ret;
 }
--- linux-4.4.0.orig/drivers/virtio/virtio.c
+++ linux-4.4.0/drivers/virtio/virtio.c
@@ -323,6 +323,8 @@
 	/* device_register() causes the bus infrastructure to look for a
 	 * matching driver. */
 	err = device_register(&dev->dev);
+	if (err)
+		ida_simple_remove(&virtio_index_ida, dev->index);
 out:
 	if (err)
 		add_status(dev, VIRTIO_CONFIG_S_FAILED);
--- linux-4.4.0.orig/drivers/virtio/virtio_balloon.c
+++ linux-4.4.0/drivers/virtio/virtio_balloon.c
@@ -30,6 +30,7 @@
 #include <linux/balloon_compaction.h>
 #include <linux/oom.h>
 #include <linux/wait.h>
+#include <linux/mm.h>
 
 /*
  * Balloon device works in 4K page units.  So each page is pointed to by
@@ -73,7 +74,7 @@
 
 	/* The array of pfns we tell the Host about. */
 	unsigned int num_pfns;
-	u32 pfns[VIRTIO_BALLOON_ARRAY_PFNS_MAX];
+	__virtio32 pfns[VIRTIO_BALLOON_ARRAY_PFNS_MAX];
 
 	/* Memory statistics */
 	int need_stats_update;
@@ -125,14 +126,16 @@
 	wait_event(vb->acked, virtqueue_get_buf(vq, &len));
 }
 
-static void set_page_pfns(u32 pfns[], struct page *page)
+static void set_page_pfns(struct virtio_balloon *vb,
+			  __virtio32 pfns[], struct page *page)
 {
 	unsigned int i;
 
 	/* Set balloon pfns pointing at this page.
 	 * Note that the first pfn points at start of the page. */
 	for (i = 0; i < VIRTIO_BALLOON_PAGES_PER_PAGE; i++)
-		pfns[i] = page_to_balloon_pfn(page) + i;
+		pfns[i] = cpu_to_virtio32(vb->vdev,
+					  page_to_balloon_pfn(page) + i);
 }
 
 static void fill_balloon(struct virtio_balloon *vb, size_t num)
@@ -155,7 +158,7 @@
 			msleep(200);
 			break;
 		}
-		set_page_pfns(vb->pfns + vb->num_pfns, page);
+		set_page_pfns(vb, vb->pfns + vb->num_pfns, page);
 		vb->num_pages += VIRTIO_BALLOON_PAGES_PER_PAGE;
 		if (!virtio_has_feature(vb->vdev,
 					VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
@@ -171,10 +174,12 @@
 static void release_pages_balloon(struct virtio_balloon *vb)
 {
 	unsigned int i;
+	struct page *page;
 
 	/* Find pfns pointing at start of each page, get pages and free them. */
 	for (i = 0; i < vb->num_pfns; i += VIRTIO_BALLOON_PAGES_PER_PAGE) {
-		struct page *page = balloon_pfn_to_page(vb->pfns[i]);
+		page = balloon_pfn_to_page(virtio32_to_cpu(vb->vdev,
+							   vb->pfns[i]));
 		if (!virtio_has_feature(vb->vdev,
 					VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
 			adjust_managed_page_count(page, 1);
@@ -192,12 +197,14 @@
 	num = min(num, ARRAY_SIZE(vb->pfns));
 
 	mutex_lock(&vb->balloon_lock);
+	/* We can't release more pages than taken */
+	num = min(num, (size_t)vb->num_pages);
 	for (vb->num_pfns = 0; vb->num_pfns < num;
 	     vb->num_pfns += VIRTIO_BALLOON_PAGES_PER_PAGE) {
 		page = balloon_page_dequeue(vb_dev_info);
 		if (!page)
 			break;
-		set_page_pfns(vb->pfns + vb->num_pfns, page);
+		set_page_pfns(vb, vb->pfns + vb->num_pfns, page);
 		vb->num_pages -= VIRTIO_BALLOON_PAGES_PER_PAGE;
 	}
 
@@ -209,8 +216,8 @@
 	 */
 	if (vb->num_pfns != 0)
 		tell_host(vb, vb->deflate_vq);
-	mutex_unlock(&vb->balloon_lock);
 	release_pages_balloon(vb);
+	mutex_unlock(&vb->balloon_lock);
 	return num_freed_pages;
 }
 
@@ -229,20 +236,27 @@
 	unsigned long events[NR_VM_EVENT_ITEMS];
 	struct sysinfo i;
 	int idx = 0;
+	long available;
 
 	all_vm_events(events);
 	si_meminfo(&i);
 
+	available = si_mem_available();
+
+#ifdef CONFIG_VM_EVENT_COUNTERS
 	update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_IN,
 				pages_to_bytes(events[PSWPIN]));
 	update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_OUT,
 				pages_to_bytes(events[PSWPOUT]));
 	update_stat(vb, idx++, VIRTIO_BALLOON_S_MAJFLT, events[PGMAJFAULT]);
 	update_stat(vb, idx++, VIRTIO_BALLOON_S_MINFLT, events[PGFAULT]);
+#endif
 	update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMFREE,
 				pages_to_bytes(i.freeram));
 	update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMTOT,
 				pages_to_bytes(i.totalram));
+	update_stat(vb, idx++, VIRTIO_BALLOON_S_AVAIL,
+				pages_to_bytes(available));
 }
 
 /*
@@ -410,6 +424,8 @@
 		 * Prime this virtqueue with one buffer so the hypervisor can
 		 * use it to signal us later (it can't be broken yet!).
 		 */
+		update_balloon_stats(vb);
+
 		sg_init_one(&sg, vb->stats, sizeof vb->stats);
 		if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
 		    < 0)
@@ -458,6 +474,17 @@
 
 	get_page(newpage); /* balloon reference */
 
+	/*
+	  * When we migrate a page to a different zone and adjusted the
+	  * managed page count when inflating, we have to fixup the count of
+	  * both involved zones.
+	  */
+	if (!virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM) &&
+	    page_zone(page) != page_zone(newpage)) {
+		adjust_managed_page_count(page, 1);
+		adjust_managed_page_count(newpage, -1);
+	}
+
 	/* balloon's page migration 1st step  -- inflate "newpage" */
 	spin_lock_irqsave(&vb_dev_info->pages_lock, flags);
 	balloon_page_insert(vb_dev_info, newpage);
@@ -465,13 +492,15 @@
 	__count_vm_event(BALLOON_MIGRATE);
 	spin_unlock_irqrestore(&vb_dev_info->pages_lock, flags);
 	vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE;
-	set_page_pfns(vb->pfns, newpage);
+	set_page_pfns(vb, vb->pfns, newpage);
 	tell_host(vb, vb->inflate_vq);
 
 	/* balloon's page migration 2nd step -- deflate "page" */
+	spin_lock_irqsave(&vb_dev_info->pages_lock, flags);
 	balloon_page_delete(page);
+	spin_unlock_irqrestore(&vb_dev_info->pages_lock, flags);
 	vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE;
-	set_page_pfns(vb->pfns, page);
+	set_page_pfns(vb, vb->pfns, page);
 	tell_host(vb, vb->deflate_vq);
 
 	mutex_unlock(&vb->balloon_lock);
--- linux-4.4.0.orig/drivers/virtio/virtio_pci_common.c
+++ linux-4.4.0/drivers/virtio/virtio_pci_common.c
@@ -545,6 +545,7 @@
 static void virtio_pci_remove(struct pci_dev *pci_dev)
 {
 	struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+	struct device *dev = get_device(&vp_dev->vdev.dev);
 
 	unregister_virtio_device(&vp_dev->vdev);
 
@@ -554,6 +555,7 @@
 		virtio_pci_modern_remove(vp_dev);
 
 	pci_disable_device(pci_dev);
+	put_device(dev);
 }
 
 static struct pci_driver virtio_pci_driver = {
--- linux-4.4.0.orig/drivers/virtio/virtio_pci_modern.c
+++ linux-4.4.0/drivers/virtio/virtio_pci_modern.c
@@ -17,6 +17,7 @@
  *
  */
 
+#include <linux/delay.h>
 #define VIRTIO_PCI_NO_LEGACY
 #include "virtio_pci_common.h"
 
@@ -271,9 +272,13 @@
 	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
 	/* 0 status means a reset. */
 	vp_iowrite8(0, &vp_dev->common->device_status);
-	/* Flush out the status write, and flush in device writes,
-	 * including MSI-X interrupts, if any. */
-	vp_ioread8(&vp_dev->common->device_status);
+	/* After writing 0 to device_status, the driver MUST wait for a read of
+	 * device_status to return 0 before reinitializing the device.
+	 * This will flush out the status write, and flush in device writes,
+	 * including MSI-X interrupts, if any.
+	 */
+	while (vp_ioread8(&vp_dev->common->device_status))
+		msleep(1);
 	/* Flush pending VQ/configuration callbacks. */
 	vp_synchronize_vectors(vdev);
 }
--- linux-4.4.0.orig/drivers/virtio/virtio_ring.c
+++ linux-4.4.0/drivers/virtio/virtio_ring.c
@@ -202,6 +202,8 @@
 		 * host should service the ring ASAP. */
 		if (out_sgs)
 			vq->notify(&vq->vq);
+		if (indirect)
+			kfree(desc);
 		END_USE(vq);
 		return -ENOSPC;
 	}
@@ -546,7 +548,8 @@
 
 	if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
 		vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
-		vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+		if (!vq->event)
+			vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
 	}
 
 }
@@ -578,7 +581,8 @@
 	 * entry. Always do both to keep code simple. */
 	if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) {
 		vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT;
-		vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+		if (!vq->event)
+			vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
 	}
 	vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx);
 	END_USE(vq);
@@ -599,6 +603,9 @@
 {
 	struct vring_virtqueue *vq = to_vvq(_vq);
 
+	if (unlikely(vq->broken))
+		return false;
+
 	virtio_mb(vq->weak_barriers);
 	return (u16)last_used_idx != virtio16_to_cpu(_vq->vdev, vq->vring.used->idx);
 }
@@ -646,10 +653,11 @@
 	 * more to do. */
 	/* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to
 	 * either clear the flags bit or point the event index at the next
-	 * entry. Always do both to keep code simple. */
+	 * entry. Always update the event index to keep code simple. */
 	if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) {
 		vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT;
-		vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+		if (!vq->event)
+			vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
 	}
 	/* TODO: tune this threshold */
 	bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4;
@@ -768,7 +776,8 @@
 	/* No callback?  Tell other side not to bother us. */
 	if (!callback) {
 		vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
-		vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow);
+		if (!vq->event)
+			vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow);
 	}
 
 	/* Put everything in free lists. */
--- linux-4.4.0.orig/drivers/vme/bridges/vme_ca91cx42.c
+++ linux-4.4.0/drivers/vme/bridges/vme_ca91cx42.c
@@ -467,7 +467,7 @@
 	vme_bound = ioread32(bridge->base + CA91CX42_VSI_BD[i]);
 	pci_offset = ioread32(bridge->base + CA91CX42_VSI_TO[i]);
 
-	*pci_base = (dma_addr_t)vme_base + pci_offset;
+	*pci_base = (dma_addr_t)*vme_base + pci_offset;
 	*size = (unsigned long long)((vme_bound - *vme_base) + granularity);
 
 	*enabled = 0;
--- linux-4.4.0.orig/drivers/w1/masters/ds2490.c
+++ linux-4.4.0/drivers/w1/masters/ds2490.c
@@ -153,6 +153,9 @@
 	 */
 	u16			spu_bit;
 
+	u8			st_buf[ST_SIZE];
+	u8			byte_buf;
+
 	struct w1_bus_master	master;
 };
 
@@ -174,7 +177,6 @@
 	u8			data_in_buffer_status;
 	u8			reserved1;
 	u8			reserved2;
-
 };
 
 static struct usb_device_id ds_id_table [] = {
@@ -244,28 +246,6 @@
 	return err;
 }
 
-static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
-				 unsigned char *buf, int size)
-{
-	int count, err;
-
-	memset(st, 0, sizeof(*st));
-
-	count = 0;
-	err = usb_interrupt_msg(dev->udev, usb_rcvintpipe(dev->udev,
-		dev->ep[EP_STATUS]), buf, size, &count, 1000);
-	if (err < 0) {
-		pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n",
-		       dev->ep[EP_STATUS], err);
-		return err;
-	}
-
-	if (count >= sizeof(*st))
-		memcpy(st, buf, sizeof(*st));
-
-	return count;
-}
-
 static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off)
 {
 	pr_info("%45s: %8x\n", str, buf[off]);
@@ -324,6 +304,35 @@
 	}
 }
 
+static int ds_recv_status(struct ds_device *dev, struct ds_status *st,
+			  bool dump)
+{
+	int count, err;
+
+	if (st)
+		memset(st, 0, sizeof(*st));
+
+	count = 0;
+	err = usb_interrupt_msg(dev->udev,
+				usb_rcvintpipe(dev->udev,
+					       dev->ep[EP_STATUS]),
+				dev->st_buf, sizeof(dev->st_buf),
+				&count, 1000);
+	if (err < 0) {
+		pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n",
+		       dev->ep[EP_STATUS], err);
+		return err;
+	}
+
+	if (dump)
+		ds_dump_status(dev, dev->st_buf, count);
+
+	if (st && count >= sizeof(*st))
+		memcpy(st, dev->st_buf, sizeof(*st));
+
+	return count;
+}
+
 static void ds_reset_device(struct ds_device *dev)
 {
 	ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
@@ -344,7 +353,6 @@
 static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
 {
 	int count, err;
-	struct ds_status st;
 
 	/* Careful on size.  If size is less than what is available in
 	 * the input buffer, the device fails the bulk transfer and
@@ -359,14 +367,9 @@
 	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
 				buf, size, &count, 1000);
 	if (err < 0) {
-		u8 buf[ST_SIZE];
-		int count;
-
 		pr_info("Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
 		usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
-
-		count = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
-		ds_dump_status(dev, buf, count);
+		ds_recv_status(dev, NULL, true);
 		return err;
 	}
 
@@ -404,7 +407,6 @@
 {
 	struct ds_status st;
 	int count = 0, err = 0;
-	u8 buf[ST_SIZE];
 
 	do {
 		err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
@@ -413,7 +415,7 @@
 		err = ds_send_control(dev, CTL_RESUME_EXE, 0);
 		if (err)
 			break;
-		err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
+		err = ds_recv_status(dev, &st, false);
 		if (err)
 			break;
 
@@ -456,18 +458,17 @@
 
 static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
 {
-	u8 buf[ST_SIZE];
 	int err, count = 0;
 
 	do {
 		st->status = 0;
-		err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
+		err = ds_recv_status(dev, st, false);
 #if 0
 		if (err >= 0) {
 			int i;
 			printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
 			for (i=0; i<err; ++i)
-				printk("%02x ", buf[i]);
+				printk("%02x ", dev->st_buf[i]);
 			printk("\n");
 		}
 #endif
@@ -485,7 +486,7 @@
 	 * can do something with it).
 	 */
 	if (err > 16 || count >= 100 || err < 0)
-		ds_dump_status(dev, buf, err);
+		ds_dump_status(dev, dev->st_buf, err);
 
 	/* Extended data isn't an error.  Well, a short is, but the dump
 	 * would have already told the user that and we can't do anything
@@ -608,7 +609,6 @@
 {
 	int err;
 	struct ds_status st;
-	u8 rbyte;
 
 	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | dev->spu_bit, byte);
 	if (err)
@@ -621,11 +621,11 @@
 	if (err)
 		return err;
 
-	err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
+	err = ds_recv_data(dev, &dev->byte_buf, 1);
 	if (err < 0)
 		return err;
 
-	return !(byte == rbyte);
+	return !(byte == dev->byte_buf);
 }
 
 static int ds_read_byte(struct ds_device *dev, u8 *byte)
@@ -712,7 +712,6 @@
 	int err;
 	u16 value, index;
 	struct ds_status st;
-	u8 st_buf[ST_SIZE];
 	int search_limit;
 	int found = 0;
 	int i;
@@ -724,7 +723,12 @@
 	/* FIFO 128 bytes, bulk packet size 64, read a multiple of the
 	 * packet size.
 	 */
-	u64 buf[2*64/8];
+	const size_t bufsize = 2 * 64;
+	u64 *buf;
+
+	buf = kmalloc(bufsize, GFP_KERNEL);
+	if (!buf)
+		return;
 
 	mutex_lock(&master->bus_mutex);
 
@@ -745,10 +749,9 @@
 	do {
 		schedule_timeout(jtime);
 
-		if (ds_recv_status_nodump(dev, &st, st_buf, sizeof(st_buf)) <
-			sizeof(st)) {
+		err = ds_recv_status(dev, &st, false);
+		if (err < 0 || err < sizeof(st))
 			break;
-		}
 
 		if (st.data_in_buffer_status) {
 			/* Bulk in can receive partial ids, but when it does
@@ -758,7 +761,7 @@
 			 * bulk without first checking if status says there
 			 * is data to read.
 			 */
-			err = ds_recv_data(dev, (u8 *)buf, sizeof(buf));
+			err = ds_recv_data(dev, (u8 *)buf, bufsize);
 			if (err < 0)
 				break;
 			for (i = 0; i < err/8; ++i) {
@@ -794,9 +797,14 @@
 	}
 search_out:
 	mutex_unlock(&master->bus_mutex);
+	kfree(buf);
 }
 
 #if 0
+/*
+ * FIXME: if this disabled code is ever used in the future all ds_send_data()
+ * calls must be changed to use a DMAable buffer.
+ */
 static int ds_match_access(struct ds_device *dev, u64 init)
 {
 	int err;
@@ -845,13 +853,12 @@
 
 static u8 ds9490r_touch_bit(void *data, u8 bit)
 {
-	u8 ret;
 	struct ds_device *dev = data;
 
-	if (ds_touch_bit(dev, bit, &ret))
+	if (ds_touch_bit(dev, bit, &dev->byte_buf))
 		return 0;
 
-	return ret;
+	return dev->byte_buf;
 }
 
 #if 0
@@ -866,13 +873,12 @@
 {
 	struct ds_device *dev = data;
 	int err;
-	u8 bit = 0;
 
-	err = ds_touch_bit(dev, 1, &bit);
+	err = ds_touch_bit(dev, 1, &dev->byte_buf);
 	if (err)
 		return 0;
 
-	return bit & 1;
+	return dev->byte_buf & 1;
 }
 #endif
 
@@ -887,32 +893,52 @@
 {
 	struct ds_device *dev = data;
 	int err;
-	u8 byte = 0;
 
-	err = ds_read_byte(dev, &byte);
+	err = ds_read_byte(dev, &dev->byte_buf);
 	if (err)
 		return 0;
 
-	return byte;
+	return dev->byte_buf;
 }
 
 static void ds9490r_write_block(void *data, const u8 *buf, int len)
 {
 	struct ds_device *dev = data;
+	u8 *tbuf;
+
+	if (len <= 0)
+		return;
+
+	tbuf = kmalloc(len, GFP_KERNEL);
+	if (!tbuf)
+		return;
+
+	memcpy(tbuf, buf, len);
+	ds_write_block(dev, tbuf, len);
 
-	ds_write_block(dev, (u8 *)buf, len);
+	kfree(tbuf);
 }
 
 static u8 ds9490r_read_block(void *data, u8 *buf, int len)
 {
 	struct ds_device *dev = data;
 	int err;
+	u8 *tbuf;
 
-	err = ds_read_block(dev, buf, len);
-	if (err < 0)
+	if (len <= 0)
+		return 0;
+
+	tbuf = kmalloc(len, GFP_KERNEL);
+	if (!tbuf)
 		return 0;
 
-	return len;
+	err = ds_read_block(dev, tbuf, len);
+	if (err >= 0)
+		memcpy(buf, tbuf, len);
+
+	kfree(tbuf);
+
+	return err >= 0 ? len : 0;
 }
 
 static u8 ds9490r_reset(void *data)
@@ -1013,15 +1039,15 @@
 	/* alternative 3, 1ms interrupt (greatly speeds search), 64 byte bulk */
 	alt = 3;
 	err = usb_set_interface(dev->udev,
-		intf->altsetting[alt].desc.bInterfaceNumber, alt);
+		intf->cur_altsetting->desc.bInterfaceNumber, alt);
 	if (err) {
 		dev_err(&dev->udev->dev, "Failed to set alternative setting %d "
 			"for %d interface: err=%d.\n", alt,
-			intf->altsetting[alt].desc.bInterfaceNumber, err);
+			intf->cur_altsetting->desc.bInterfaceNumber, err);
 		goto err_out_clear;
 	}
 
-	iface_desc = &intf->altsetting[alt];
+	iface_desc = intf->cur_altsetting;
 	if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
 		pr_info("Num endpoints=%d. It is not DS9490R.\n",
 			iface_desc->desc.bNumEndpoints);
--- linux-4.4.0.orig/drivers/w1/masters/mxc_w1.c
+++ linux-4.4.0/drivers/w1/masters/mxc_w1.c
@@ -15,7 +15,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/jiffies.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
@@ -48,12 +48,12 @@
 static u8 mxc_w1_ds2_reset_bus(void *data)
 {
 	struct mxc_w1_device *dev = data;
-	unsigned long timeout;
+	ktime_t timeout;
 
 	writeb(MXC_W1_CONTROL_RPP, dev->regs + MXC_W1_CONTROL);
 
 	/* Wait for reset sequence 511+512us, use 1500us for sure */
-	timeout = jiffies + usecs_to_jiffies(1500);
+	timeout = ktime_add_us(ktime_get(), 1500);
 
 	udelay(511 + 512);
 
@@ -63,7 +63,7 @@
 		/* PST bit is valid after the RPP bit is self-cleared */
 		if (!(ctrl & MXC_W1_CONTROL_RPP))
 			return !(ctrl & MXC_W1_CONTROL_PST);
-	} while (time_is_after_jiffies(timeout));
+	} while (ktime_before(ktime_get(), timeout));
 
 	return 1;
 }
@@ -76,12 +76,12 @@
 static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
 {
 	struct mxc_w1_device *dev = data;
-	unsigned long timeout;
+	ktime_t timeout;
 
 	writeb(MXC_W1_CONTROL_WR(bit), dev->regs + MXC_W1_CONTROL);
 
 	/* Wait for read/write bit (60us, Max 120us), use 200us for sure */
-	timeout = jiffies + usecs_to_jiffies(200);
+	timeout = ktime_add_us(ktime_get(), 200);
 
 	udelay(60);
 
@@ -91,7 +91,7 @@
 		/* RDST bit is valid after the WR1/RD bit is self-cleared */
 		if (!(ctrl & MXC_W1_CONTROL_WR(bit)))
 			return !!(ctrl & MXC_W1_CONTROL_RDST);
-	} while (time_is_after_jiffies(timeout));
+	} while (ktime_before(ktime_get(), timeout));
 
 	return 0;
 }
@@ -113,6 +113,10 @@
 	if (IS_ERR(mdev->clk))
 		return PTR_ERR(mdev->clk);
 
+	err = clk_prepare_enable(mdev->clk);
+	if (err)
+		return err;
+
 	clkrate = clk_get_rate(mdev->clk);
 	if (clkrate < 10000000)
 		dev_warn(&pdev->dev,
@@ -126,12 +130,10 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	mdev->regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(mdev->regs))
-		return PTR_ERR(mdev->regs);
-
-	err = clk_prepare_enable(mdev->clk);
-	if (err)
-		return err;
+	if (IS_ERR(mdev->regs)) {
+		err = PTR_ERR(mdev->regs);
+		goto out_disable_clk;
+	}
 
 	/* Software reset 1-Wire module */
 	writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET);
@@ -147,8 +149,12 @@
 
 	err = w1_add_master_device(&mdev->bus_master);
 	if (err)
-		clk_disable_unprepare(mdev->clk);
+		goto out_disable_clk;
+
+	return 0;
 
+out_disable_clk:
+	clk_disable_unprepare(mdev->clk);
 	return err;
 }
 
--- linux-4.4.0.orig/drivers/w1/masters/omap_hdq.c
+++ linux-4.4.0/drivers/w1/masters/omap_hdq.c
@@ -204,7 +204,7 @@
 	/* check irqstatus */
 	if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
 		dev_dbg(hdq_data->dev, "timeout waiting for"
-			" TXCOMPLETE/RXCOMPLETE, %x", *status);
+			" TXCOMPLETE/RXCOMPLETE, %x\n", *status);
 		ret = -ETIMEDOUT;
 		goto out;
 	}
@@ -215,7 +215,7 @@
 			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\n", tmp_status);
 	}
 
 out:
@@ -231,7 +231,7 @@
 	spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
 	hdq_data->hdq_irqstatus = hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
 	spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
-	dev_dbg(hdq_data->dev, "hdq_isr: %x", hdq_data->hdq_irqstatus);
+	dev_dbg(hdq_data->dev, "hdq_isr: %x\n", hdq_data->hdq_irqstatus);
 
 	if (hdq_data->hdq_irqstatus &
 		(OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE
@@ -339,7 +339,7 @@
 	tmp_status = hdq_data->hdq_irqstatus;
 	/* check irqstatus */
 	if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) {
-		dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x",
+		dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x\n",
 				tmp_status);
 		ret = -ETIMEDOUT;
 		goto out;
@@ -366,7 +366,7 @@
 			&tmp_status);
 	if (ret)
 		dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits"
-			" return to zero, %x", tmp_status);
+			" return to zero, %x\n", tmp_status);
 
 out:
 	mutex_unlock(&hdq_data->hdq_mutex);
@@ -390,8 +390,6 @@
 		goto out;
 	}
 
-	hdq_data->hdq_irqstatus = 0;
-
 	if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
 		hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
 			OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
@@ -787,6 +785,8 @@
 	/* remove module dependency */
 	pm_runtime_disable(&pdev->dev);
 
+	w1_remove_master_device(&omap_w1_master);
+
 	return 0;
 }
 
--- linux-4.4.0.orig/drivers/w1/w1.c
+++ linux-4.4.0/drivers/w1/w1.c
@@ -741,7 +741,7 @@
 
 	/* slave modules need to be loaded in a context with unlocked mutex */
 	mutex_unlock(&dev->mutex);
-	request_module("w1-family-0x%02x", rn->family);
+	request_module("w1-family-0x%02X", rn->family);
 	mutex_lock(&dev->mutex);
 
 	spin_lock(&w1_flock);
@@ -763,6 +763,7 @@
 		dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
 			 sl->name);
 		w1_family_put(sl->family);
+		atomic_dec(&sl->master->refcnt);
 		kfree(sl);
 		return err;
 	}
--- linux-4.4.0.orig/drivers/w1/w1_io.c
+++ linux-4.4.0/drivers/w1/w1_io.c
@@ -437,8 +437,7 @@
 	if (w1_reset_bus(dev))
 		return -1;
 
-	/* This will make only the last matched slave perform a skip ROM. */
-	w1_write_8(dev, W1_RESUME_CMD);
+	w1_write_8(dev, dev->slave_count > 1 ? W1_RESUME_CMD : W1_SKIP_ROM);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(w1_reset_resume_command);
--- linux-4.4.0.orig/drivers/watchdog/bcm2835_wdt.c
+++ linux-4.4.0/drivers/watchdog/bcm2835_wdt.c
@@ -248,6 +248,7 @@
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+MODULE_ALIAS("platform:bcm2835-wdt");
 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
 MODULE_DESCRIPTION("Driver for Broadcom BCM2835 watchdog timer");
 MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/drivers/watchdog/bcm_kona_wdt.c
+++ linux-4.4.0/drivers/watchdog/bcm_kona_wdt.c
@@ -304,6 +304,8 @@
 	if (!wdt)
 		return -ENOMEM;
 
+	spin_lock_init(&wdt->lock);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	wdt->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(wdt->base))
@@ -316,7 +318,6 @@
 		return ret;
 	}
 
-	spin_lock_init(&wdt->lock);
 	platform_set_drvdata(pdev, wdt);
 	watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt);
 	bcm_kona_wdt_wdd.parent = &pdev->dev;
--- linux-4.4.0.orig/drivers/watchdog/cpu5wdt.c
+++ linux-4.4.0/drivers/watchdog/cpu5wdt.c
@@ -265,7 +265,7 @@
 	if (cpu5wdt_device.queue) {
 		cpu5wdt_device.queue = 0;
 		wait_for_completion(&cpu5wdt_device.stop);
-		del_timer(&cpu5wdt_device.timer);
+		del_timer_sync(&cpu5wdt_device.timer);
 	}
 
 	misc_deregister(&cpu5wdt_misc);
@@ -289,7 +289,7 @@
 MODULE_SUPPORTED_DEVICE("sma cpu5 watchdog");
 MODULE_LICENSE("GPL");
 
-module_param(port, int, 0);
+module_param_hw(port, int, ioport, 0);
 MODULE_PARM_DESC(port, "base address of watchdog card, default is 0x91");
 
 module_param(verbose, int, 0);
--- linux-4.4.0.orig/drivers/watchdog/da9062_wdt.c
+++ linux-4.4.0/drivers/watchdog/da9062_wdt.c
@@ -94,11 +94,6 @@
 					      unsigned int regval)
 {
 	struct da9062 *chip = wdt->hw;
-	int ret;
-
-	ret = da9062_reset_watchdog_timer(wdt);
-	if (ret)
-		return ret;
 
 	return regmap_update_bits(chip->regmap,
 				  DA9062AA_CONTROL_D,
@@ -126,13 +121,6 @@
 	struct da9062_watchdog *wdt = watchdog_get_drvdata(wdd);
 	int ret;
 
-	ret = da9062_reset_watchdog_timer(wdt);
-	if (ret) {
-		dev_err(wdt->hw->dev, "Failed to ping the watchdog (err = %d)\n",
-			ret);
-		return ret;
-	}
-
 	ret = regmap_update_bits(wdt->hw->regmap,
 				 DA9062AA_CONTROL_D,
 				 DA9062AA_TWDSCALE_MASK,
--- linux-4.4.0.orig/drivers/watchdog/eurotechwdt.c
+++ linux-4.4.0/drivers/watchdog/eurotechwdt.c
@@ -97,9 +97,9 @@
 #define WDT_TIMER_CFG		0xf3
 
 
-module_param(io, int, 0);
+module_param_hw(io, int, ioport, 0);
 MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)");
-module_param(irq, int, 0);
+module_param_hw(irq, int, irq, 0);
 MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)");
 module_param(ev, charp, 0);
 MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `int')");
--- linux-4.4.0.orig/drivers/watchdog/f71808e_wdt.c
+++ linux-4.4.0/drivers/watchdog/f71808e_wdt.c
@@ -450,7 +450,7 @@
 
 	is_running = (superio_inb(watchdog.sioaddr, SIO_REG_ENABLE) & BIT(0))
 		&& (superio_inb(watchdog.sioaddr, F71808FG_REG_WDT_CONF)
-			& F71808FG_FLAG_WD_EN);
+			& BIT(F71808FG_FLAG_WD_EN));
 
 	superio_exit(watchdog.sioaddr);
 
@@ -520,7 +520,8 @@
 				char c;
 				if (get_user(c, buf + i))
 					return -EFAULT;
-				expect_close = (c == 'V');
+				if (c == 'V')
+					expect_close = true;
 			}
 
 			/* Properly order writes across fork()ed processes */
@@ -641,9 +642,9 @@
 	 * into the module have been registered yet.
 	 */
 	watchdog.sioaddr = sioaddr;
-	watchdog.ident.options = WDIOC_SETTIMEOUT
-				| WDIOF_MAGICCLOSE
-				| WDIOF_KEEPALIVEPING;
+	watchdog.ident.options = WDIOF_MAGICCLOSE
+				| WDIOF_KEEPALIVEPING
+				| WDIOF_CARDRESET;
 
 	snprintf(watchdog.ident.identity,
 		sizeof(watchdog.ident.identity), "%s watchdog",
--- linux-4.4.0.orig/drivers/watchdog/hpwdt.c
+++ linux-4.4.0/drivers/watchdog/hpwdt.c
@@ -51,6 +51,7 @@
 static unsigned long hpwdt_is_open;
 
 static void __iomem *pci_mem_addr;		/* the PCI-memory address */
+static unsigned long __iomem *hpwdt_nmistat;
 static unsigned long __iomem *hpwdt_timer_reg;
 static unsigned long __iomem *hpwdt_timer_con;
 
@@ -474,6 +475,11 @@
 }
 
 #ifdef CONFIG_HPWDT_NMI_DECODING
+static int hpwdt_my_nmi(void)
+{
+	return ioread8(hpwdt_nmistat) & 0x6;
+}
+
 /*
  *	NMI Handler
  */
@@ -485,6 +491,9 @@
 	if (!hpwdt_nmi_decoding)
 		goto out;
 
+	if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi())
+		return NMI_DONE;
+
 	spin_lock_irqsave(&rom_lock, rom_pl);
 	if (!die_nmi_called && !is_icru && !is_uefi)
 		asminline_call(&cmn_regs, cru_rom_addr);
@@ -700,7 +709,7 @@
 		smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
 		if (smbios_proliant_ptr->misc_features & 0x01)
 			is_icru = 1;
-		if (smbios_proliant_ptr->misc_features & 0x408)
+		if (smbios_proliant_ptr->misc_features & 0x1400)
 			is_uefi = 1;
 	}
 }
@@ -840,6 +849,7 @@
 		retval = -ENOMEM;
 		goto error_pci_iomap;
 	}
+	hpwdt_nmistat	= pci_mem_addr + 0x6e;
 	hpwdt_timer_reg = pci_mem_addr + 0x70;
 	hpwdt_timer_con = pci_mem_addr + 0x72;
 
--- linux-4.4.0.orig/drivers/watchdog/imx2_wdt.c
+++ linux-4.4.0/drivers/watchdog/imx2_wdt.c
@@ -161,15 +161,21 @@
 	mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2);
 }
 
-static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
-				unsigned int new_timeout)
+static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
+				   unsigned int new_timeout)
 {
 	struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-	wdog->timeout = new_timeout;
-
 	regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
 			   WDOG_SEC_TO_COUNT(new_timeout));
+}
+
+static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
+				unsigned int new_timeout)
+{
+	__imx2_wdt_set_timeout(wdog, new_timeout);
+
+	wdog->timeout = new_timeout;
 	return 0;
 }
 
@@ -353,7 +359,11 @@
 
 	/* The watchdog IP block is running */
 	if (imx2_wdt_is_running(wdev)) {
-		imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+		/*
+		 * Don't update wdog->timeout, we'll restore the current value
+		 * during resume.
+		 */
+		__imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
 		imx2_wdt_ping(wdog);
 
 		/* The watchdog is not active */
--- linux-4.4.0.orig/drivers/watchdog/kempld_wdt.c
+++ linux-4.4.0/drivers/watchdog/kempld_wdt.c
@@ -140,12 +140,19 @@
 					unsigned int timeout)
 {
 	struct kempld_device_data *pld = wdt_data->pld;
-	u32 prescaler = kempld_prescaler[PRESCALER_21];
+	u32 prescaler;
 	u64 stage_timeout64;
 	u32 stage_timeout;
 	u32 remainder;
 	u8 stage_cfg;
 
+#if GCC_VERSION < 40400
+	/* work around a bug compiling do_div() */
+	prescaler = READ_ONCE(kempld_prescaler[PRESCALER_21]);
+#else
+	prescaler = kempld_prescaler[PRESCALER_21];
+#endif
+
 	if (!stage)
 		return -EINVAL;
 
--- linux-4.4.0.orig/drivers/watchdog/pc87413_wdt.c
+++ linux-4.4.0/drivers/watchdog/pc87413_wdt.c
@@ -579,7 +579,7 @@
 MODULE_DESCRIPTION("PC87413 WDT driver");
 MODULE_LICENSE("GPL");
 
-module_param(io, int, 0);
+module_param_hw(io, int, ioport, 0);
 MODULE_PARM_DESC(io, MODNAME " I/O port (default: "
 					__MODULE_STRING(IO_DEFAULT) ").");
 
--- linux-4.4.0.orig/drivers/watchdog/pcwd_usb.c
+++ linux-4.4.0/drivers/watchdog/pcwd_usb.c
@@ -630,6 +630,9 @@
 		return -ENODEV;
 	}
 
+	if (iface_desc->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	/* check out the endpoint: it has to be Interrupt & IN */
 	endpoint = &iface_desc->endpoint[0].desc;
 
--- linux-4.4.0.orig/drivers/watchdog/rc32434_wdt.c
+++ linux-4.4.0/drivers/watchdog/rc32434_wdt.c
@@ -237,7 +237,7 @@
 			return -EINVAL;
 		/* Fall through */
 	case WDIOC_GETTIMEOUT:
-		return copy_to_user(argp, &timeout, sizeof(int));
+		return copy_to_user(argp, &timeout, sizeof(int)) ? -EFAULT : 0;
 	default:
 		return -ENOTTY;
 	}
--- linux-4.4.0.orig/drivers/watchdog/rdc321x_wdt.c
+++ linux-4.4.0/drivers/watchdog/rdc321x_wdt.c
@@ -244,6 +244,8 @@
 
 	rdc321x_wdt_device.sb_pdev = pdata->sb_pdev;
 	rdc321x_wdt_device.base_reg = r->start;
+	rdc321x_wdt_device.queue = 0;
+	rdc321x_wdt_device.default_ticks = ticks;
 
 	err = misc_register(&rdc321x_wdt_misc);
 	if (err < 0) {
@@ -258,14 +260,11 @@
 				rdc321x_wdt_device.base_reg, RDC_WDT_RST);
 
 	init_completion(&rdc321x_wdt_device.stop);
-	rdc321x_wdt_device.queue = 0;
 
 	clear_bit(0, &rdc321x_wdt_device.inuse);
 
 	setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0);
 
-	rdc321x_wdt_device.default_ticks = ticks;
-
 	dev_info(&pdev->dev, "watchdog init success\n");
 
 	return 0;
--- linux-4.4.0.orig/drivers/watchdog/rn5t618_wdt.c
+++ linux-4.4.0/drivers/watchdog/rn5t618_wdt.c
@@ -193,6 +193,7 @@
 
 module_platform_driver(rn5t618_wdt_driver);
 
+MODULE_ALIAS("platform:rn5t618-wdt");
 MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
 MODULE_DESCRIPTION("RN5T618 watchdog driver");
 MODULE_LICENSE("GPL v2");
--- linux-4.4.0.orig/drivers/watchdog/sc1200wdt.c
+++ linux-4.4.0/drivers/watchdog/sc1200wdt.c
@@ -88,7 +88,7 @@
 	"When set to 0 driver ISA PnP support will be disabled");
 #endif
 
-module_param(io, int, 0);
+module_param_hw(io, int, ioport, 0);
 MODULE_PARM_DESC(io, "io port");
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
--- linux-4.4.0.orig/drivers/watchdog/sp5100_tco.h
+++ linux-4.4.0/drivers/watchdog/sp5100_tco.h
@@ -54,7 +54,7 @@
 #define SB800_PM_WATCHDOG_CONFIG	0x4C
 
 #define SB800_PCI_WATCHDOG_DECODE_EN	(1 << 0)
-#define SB800_PM_WATCHDOG_DISABLE	(1 << 2)
+#define SB800_PM_WATCHDOG_DISABLE	(1 << 1)
 #define SB800_PM_WATCHDOG_SECOND_RES	(3 << 0)
 #define SB800_ACPI_MMIO_DECODE_EN	(1 << 0)
 #define SB800_ACPI_MMIO_SEL		(1 << 1)
--- linux-4.4.0.orig/drivers/watchdog/wdt.c
+++ linux-4.4.0/drivers/watchdog/wdt.c
@@ -78,9 +78,9 @@
 
 static DEFINE_SPINLOCK(wdt_lock);
 
-module_param(io, int, 0);
+module_param_hw(io, int, ioport, 0);
 MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
-module_param(irq, int, 0);
+module_param_hw(irq, int, irq, 0);
 MODULE_PARM_DESC(irq, "WDT irq (default=11)");
 
 /* Support for the Fan Tachometer on the WDT501-P */
--- linux-4.4.0.orig/drivers/xen/Kconfig
+++ linux-4.4.0/drivers/xen/Kconfig
@@ -239,7 +239,7 @@
 
 config XEN_ACPI_PROCESSOR
 	tristate "Xen ACPI processor"
-	depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ
+	depends on XEN && XEN_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ
 	default m
 	help
           This ACPI processor uploads Power Management information to the Xen
--- linux-4.4.0.orig/drivers/xen/balloon.c
+++ linux-4.4.0/drivers/xen/balloon.c
@@ -247,6 +247,19 @@
 }
 
 #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
+static void release_memory_resource(struct resource *resource)
+{
+	if (!resource)
+		return;
+
+	/*
+	 * No need to reset region to identity mapped since we now
+	 * know that no I/O can be in this region
+	 */
+	release_resource(resource);
+	kfree(resource);
+}
+
 static struct resource *additional_memory_resource(phys_addr_t size)
 {
 	struct resource *res;
@@ -268,20 +281,21 @@
 		return NULL;
 	}
 
-	return res;
-}
-
-static void release_memory_resource(struct resource *resource)
-{
-	if (!resource)
-		return;
+#ifdef CONFIG_SPARSEMEM
+	{
+		unsigned long limit = 1UL << (MAX_PHYSMEM_BITS - PAGE_SHIFT);
+		unsigned long pfn = res->start >> PAGE_SHIFT;
+
+		if (pfn > limit) {
+			pr_err("New System RAM resource outside addressable RAM (%lu > %lu)\n",
+			       pfn, limit);
+			release_memory_resource(res);
+			return NULL;
+		}
+	}
+#endif
 
-	/*
-	 * No need to reset region to identity mapped since we now
-	 * know that no I/O can be in this region
-	 */
-	release_resource(resource);
-	kfree(resource);
+	return res;
 }
 
 static enum bp_state reserve_additional_memory(void)
@@ -338,7 +352,7 @@
 	}
 #endif
 
-	rc = add_memory_resource(nid, resource);
+	rc = add_memory_resource(nid, resource, false);
 	if (rc) {
 		pr_warn("Cannot add additional memory (%i)\n", rc);
 		goto err;
@@ -378,7 +392,8 @@
 #else
 static enum bp_state reserve_additional_memory(void)
 {
-	balloon_stats.target_pages = balloon_stats.current_pages;
+	balloon_stats.target_pages = balloon_stats.current_pages +
+				     balloon_stats.target_unpopulated;
 	return BP_ECANCELED;
 }
 #endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */
@@ -569,8 +584,15 @@
 				state = reserve_additional_memory();
 		}
 
-		if (credit < 0)
-			state = decrease_reservation(-credit, GFP_BALLOON);
+		if (credit < 0) {
+			long n_pages;
+
+			n_pages = min(-credit, si_mem_available());
+			state = decrease_reservation(n_pages, GFP_BALLOON);
+			if (state == BP_DONE && n_pages != -credit &&
+			    n_pages < totalreserve_pages)
+				state = BP_EAGAIN;
+		}
 
 		state = update_schedule(state);
 
@@ -601,14 +623,19 @@
 	if (xen_hotplug_unpopulated) {
 		st = reserve_additional_memory();
 		if (st != BP_ECANCELED) {
+			int rc;
+
 			mutex_unlock(&balloon_mutex);
-			wait_event(balloon_wq,
+			rc = wait_event_interruptible(balloon_wq,
 				   !list_empty(&ballooned_pages));
 			mutex_lock(&balloon_mutex);
-			return 0;
+			return rc ? -ENOMEM : 0;
 		}
 	}
 
+	if (si_mem_available() < nr_pages)
+		return -ENOMEM;
+
 	st = decrease_reservation(nr_pages, GFP_USER);
 	if (st != BP_DONE)
 		return -ENOMEM;
@@ -658,6 +685,12 @@
  out_undo:
 	mutex_unlock(&balloon_mutex);
 	free_xenballooned_pages(pgno, pages);
+	/*
+	 * NB: free_xenballooned_pages will only subtract pgno pages, but since
+	 * target_unpopulated is incremented with nr_pages at the start we need
+	 * to remove the remaining ones also, or accounting will be screwed.
+	 */
+	balloon_stats.target_unpopulated -= nr_pages - pgno;
 	return ret;
 }
 EXPORT_SYMBOL(alloc_xenballooned_pages);
@@ -732,7 +765,7 @@
 	balloon_stats.schedule_delay = 1;
 	balloon_stats.max_schedule_delay = 32;
 	balloon_stats.retry_count = 1;
-	balloon_stats.max_retry_count = RETRY_UNLIMITED;
+	balloon_stats.max_retry_count = 4;
 
 #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
 	set_online_page_callback(&xen_online_page);
--- linux-4.4.0.orig/drivers/xen/biomerge.c
+++ linux-4.4.0/drivers/xen/biomerge.c
@@ -10,8 +10,7 @@
 	unsigned long bfn1 = pfn_to_bfn(page_to_pfn(vec1->bv_page));
 	unsigned long bfn2 = pfn_to_bfn(page_to_pfn(vec2->bv_page));
 
-	return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) &&
-		((bfn1 == bfn2) || ((bfn1+1) == bfn2));
+	return bfn1 + PFN_DOWN(vec1->bv_offset + vec1->bv_len) == bfn2;
 #else
 	/*
 	 * XXX: Add support for merging bio_vec when using different page
--- linux-4.4.0.orig/drivers/xen/cpu_hotplug.c
+++ linux-4.4.0/drivers/xen/cpu_hotplug.c
@@ -18,15 +18,16 @@
 
 static void disable_hotplug_cpu(int cpu)
 {
-	if (cpu_online(cpu)) {
-		lock_device_hotplug();
+	if (!cpu_is_hotpluggable(cpu))
+		return;
+	lock_device_hotplug();
+	if (cpu_online(cpu))
 		device_offline(get_cpu_device(cpu));
-		unlock_device_hotplug();
-	}
-	if (cpu_present(cpu))
+	if (!cpu_online(cpu) && cpu_present(cpu)) {
 		xen_arch_unregister_cpu(cpu);
-
-	set_cpu_present(cpu, false);
+		set_cpu_present(cpu, false);
+	}
+	unlock_device_hotplug();
 }
 
 static int vcpu_online(unsigned int cpu)
@@ -52,7 +53,7 @@
 }
 static void vcpu_hotplug(unsigned int cpu)
 {
-	if (!cpu_possible(cpu))
+	if (cpu >= nr_cpu_ids || !cpu_possible(cpu))
 		return;
 
 	switch (vcpu_online(cpu)) {
--- linux-4.4.0.orig/drivers/xen/events/events_2l.c
+++ linux-4.4.0/drivers/xen/events/events_2l.c
@@ -46,6 +46,11 @@
 	return EVTCHN_2L_NR_CHANNELS;
 }
 
+static void evtchn_2l_remove(evtchn_port_t evtchn, unsigned int cpu)
+{
+	clear_bit(evtchn, BM(per_cpu(cpu_evtchn_mask, cpu)));
+}
+
 static void evtchn_2l_bind_to_cpu(struct irq_info *info, unsigned cpu)
 {
 	clear_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, info->cpu)));
@@ -70,12 +75,6 @@
 	return sync_test_bit(port, BM(&s->evtchn_pending[0]));
 }
 
-static bool evtchn_2l_test_and_set_mask(unsigned port)
-{
-	struct shared_info *s = HYPERVISOR_shared_info;
-	return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0]));
-}
-
 static void evtchn_2l_mask(unsigned port)
 {
 	struct shared_info *s = HYPERVISOR_shared_info;
@@ -90,6 +89,8 @@
 
 	BUG_ON(!irqs_disabled());
 
+	smp_wmb();	/* All writes before unmask must be visible. */
+
 	if (unlikely((cpu != cpu_from_evtchn(port))))
 		do_hypercall = 1;
 	else {
@@ -158,7 +159,7 @@
  * a bitset of words which contain pending event bits.  The second
  * level is a bitset of pending events themselves.
  */
-static void evtchn_2l_handle_events(unsigned cpu)
+static void evtchn_2l_handle_events(unsigned cpu, struct evtchn_loop_ctrl *ctrl)
 {
 	int irq;
 	xen_ulong_t pending_words;
@@ -239,10 +240,7 @@
 
 			/* Process port. */
 			port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx;
-			irq = get_evtchn_to_irq(port);
-
-			if (irq != -1)
-				generic_handle_irq(irq);
+			handle_irq_for_port(port, ctrl);
 
 			bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD;
 
@@ -354,18 +352,27 @@
 				EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD);
 }
 
+static int evtchn_2l_percpu_deinit(unsigned int cpu)
+{
+	memset(per_cpu(cpu_evtchn_mask, cpu), 0, sizeof(xen_ulong_t) *
+			EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD);
+
+	return 0;
+}
+
 static const struct evtchn_ops evtchn_ops_2l = {
 	.max_channels      = evtchn_2l_max_channels,
 	.nr_channels       = evtchn_2l_max_channels,
+	.remove            = evtchn_2l_remove,
 	.bind_to_cpu       = evtchn_2l_bind_to_cpu,
 	.clear_pending     = evtchn_2l_clear_pending,
 	.set_pending       = evtchn_2l_set_pending,
 	.is_pending        = evtchn_2l_is_pending,
-	.test_and_set_mask = evtchn_2l_test_and_set_mask,
 	.mask              = evtchn_2l_mask,
 	.unmask            = evtchn_2l_unmask,
 	.handle_events     = evtchn_2l_handle_events,
 	.resume	           = evtchn_2l_resume,
+	.percpu_deinit     = evtchn_2l_percpu_deinit,
 };
 
 void __init xen_evtchn_2l_init(void)
--- linux-4.4.0.orig/drivers/xen/events/events_base.c
+++ linux-4.4.0/drivers/xen/events/events_base.c
@@ -32,6 +32,10 @@
 #include <linux/slab.h>
 #include <linux/irqnr.h>
 #include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/cpu.h>
+#include <linux/atomic.h>
+#include <linux/ktime.h>
 
 #ifdef CONFIG_X86
 #include <asm/desc.h>
@@ -62,6 +66,15 @@
 
 #include "events_internal.h"
 
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "xen."
+
+static uint __read_mostly event_loop_timeout = 2;
+module_param(event_loop_timeout, uint, 0644);
+
+static uint __read_mostly event_eoi_delay = 10;
+module_param(event_eoi_delay, uint, 0644);
+
 const struct evtchn_ops *evtchn_ops;
 
 /*
@@ -70,6 +83,25 @@
  */
 static DEFINE_MUTEX(irq_mapping_update_lock);
 
+/*
+ * Lock protecting event handling loop against removing event channels.
+ * Adding of event channels is no issue as the associated IRQ becomes active
+ * only after everything is setup (before request_[threaded_]irq() the handler
+ * can't be entered for an event, as the event channel will be unmasked only
+ * then).
+ */
+static DEFINE_RWLOCK(evtchn_rwlock);
+
+/*
+ * Lock hierarchy:
+ *
+ * irq_mapping_update_lock
+ *   evtchn_rwlock
+ *     IRQ-desc lock
+ *       percpu eoi_list_lock
+ *         irq_info->lock
+ */
+
 static LIST_HEAD(xen_irq_list_head);
 
 /* IRQ <-> VIRQ mapping. */
@@ -91,18 +123,23 @@
 /* Xen will never allocate port zero for any purpose. */
 #define VALID_EVTCHN(chn)	((chn) != 0)
 
+static struct irq_info *legacy_info_ptrs[NR_IRQS_LEGACY];
+
 static struct irq_chip xen_dynamic_chip;
+static struct irq_chip xen_lateeoi_chip;
 static struct irq_chip xen_percpu_chip;
 static struct irq_chip xen_pirq_chip;
 static void enable_dynirq(struct irq_data *data);
 static void disable_dynirq(struct irq_data *data);
 
+static DEFINE_PER_CPU(unsigned int, irq_epoch);
+
 static void clear_evtchn_to_irq_row(unsigned row)
 {
 	unsigned col;
 
 	for (col = 0; col < EVTCHN_PER_ROW; col++)
-		evtchn_to_irq[row][col] = -1;
+		WRITE_ONCE(evtchn_to_irq[row][col], -1);
 }
 
 static void clear_evtchn_to_irq_all(void)
@@ -139,7 +176,7 @@
 		clear_evtchn_to_irq_row(row);
 	}
 
-	evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)] = irq;
+	WRITE_ONCE(evtchn_to_irq[row][col], irq);
 	return 0;
 }
 
@@ -149,13 +186,24 @@
 		return -1;
 	if (evtchn_to_irq[EVTCHN_ROW(evtchn)] == NULL)
 		return -1;
-	return evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)];
+	return READ_ONCE(evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)]);
 }
 
 /* Get info for IRQ */
 struct irq_info *info_for_irq(unsigned irq)
 {
-	return irq_get_handler_data(irq);
+	if (irq < nr_legacy_irqs())
+		return legacy_info_ptrs[irq];
+	else
+		return irq_get_chip_data(irq);
+}
+
+static void set_info_for_irq(unsigned int irq, struct irq_info *info)
+{
+	if (irq < nr_legacy_irqs())
+		legacy_info_ptrs[irq] = info;
+	else
+		irq_set_chip_data(irq, info);
 }
 
 /* Constructors for packed IRQ information. */
@@ -173,6 +221,8 @@
 	info->irq = irq;
 	info->evtchn = evtchn;
 	info->cpu = cpu;
+	info->mask_reason = EVT_MASK_REASON_EXPLICIT;
+	spin_lock_init(&info->lock);
 
 	ret = set_evtchn_to_irq(evtchn, irq);
 	if (ret < 0)
@@ -239,6 +289,7 @@
 static void xen_irq_info_cleanup(struct irq_info *info)
 {
 	set_evtchn_to_irq(info->evtchn, -1);
+	xen_evtchn_port_remove(info->evtchn, info->cpu);
 	info->evtchn = 0;
 }
 
@@ -247,10 +298,14 @@
  */
 unsigned int evtchn_from_irq(unsigned irq)
 {
-	if (unlikely(WARN(irq >= nr_irqs, "Invalid irq %d!\n", irq)))
+	const struct irq_info *info = NULL;
+
+	if (likely(irq < nr_irqs))
+		info = info_for_irq(irq);
+	if (!info)
 		return 0;
 
-	return info_for_irq(irq)->evtchn;
+	return info->evtchn;
 }
 
 unsigned irq_from_evtchn(unsigned int evtchn)
@@ -315,6 +370,34 @@
 	return ret;
 }
 
+static void do_mask(struct irq_info *info, u8 reason)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock, flags);
+
+	if (!info->mask_reason)
+		mask_evtchn(info->evtchn);
+
+	info->mask_reason |= reason;
+
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static void do_unmask(struct irq_info *info, u8 reason)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock, flags);
+
+	info->mask_reason &= ~reason;
+
+	if (!info->mask_reason)
+		unmask_evtchn(info->evtchn);
+
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
 #ifdef CONFIG_X86
 static bool pirq_check_eoi_map(unsigned irq)
 {
@@ -369,9 +452,157 @@
 }
 EXPORT_SYMBOL_GPL(notify_remote_via_irq);
 
+struct lateeoi_work {
+	struct delayed_work delayed;
+	spinlock_t eoi_list_lock;
+	struct list_head eoi_list;
+};
+
+static DEFINE_PER_CPU(struct lateeoi_work, lateeoi);
+
+static void lateeoi_list_del(struct irq_info *info)
+{
+	struct lateeoi_work *eoi = &per_cpu(lateeoi, info->eoi_cpu);
+	unsigned long flags;
+
+	spin_lock_irqsave(&eoi->eoi_list_lock, flags);
+	list_del_init(&info->eoi_list);
+	spin_unlock_irqrestore(&eoi->eoi_list_lock, flags);
+}
+
+static void lateeoi_list_add(struct irq_info *info)
+{
+	struct lateeoi_work *eoi = &per_cpu(lateeoi, info->eoi_cpu);
+	struct irq_info *elem;
+	u64 now = get_jiffies_64();
+	unsigned long delay;
+	unsigned long flags;
+
+	if (now < info->eoi_time)
+		delay = info->eoi_time - now;
+	else
+		delay = 1;
+
+	spin_lock_irqsave(&eoi->eoi_list_lock, flags);
+
+	if (list_empty(&eoi->eoi_list)) {
+		list_add(&info->eoi_list, &eoi->eoi_list);
+		mod_delayed_work_on(info->eoi_cpu, system_wq,
+				    &eoi->delayed, delay);
+	} else {
+		list_for_each_entry_reverse(elem, &eoi->eoi_list, eoi_list) {
+			if (elem->eoi_time <= info->eoi_time)
+				break;
+		}
+		list_add(&info->eoi_list, &elem->eoi_list);
+	}
+
+	spin_unlock_irqrestore(&eoi->eoi_list_lock, flags);
+}
+
+static void xen_irq_lateeoi_locked(struct irq_info *info, bool spurious)
+{
+	evtchn_port_t evtchn;
+	unsigned int cpu;
+	unsigned int delay = 0;
+
+	evtchn = info->evtchn;
+	if (!VALID_EVTCHN(evtchn) || !list_empty(&info->eoi_list))
+		return;
+
+	if (spurious) {
+		if ((1 << info->spurious_cnt) < (HZ << 2))
+			info->spurious_cnt++;
+		if (info->spurious_cnt > 1) {
+			delay = 1 << (info->spurious_cnt - 2);
+			if (delay > HZ)
+				delay = HZ;
+			if (!info->eoi_time)
+				info->eoi_cpu = smp_processor_id();
+			info->eoi_time = get_jiffies_64() + delay;
+		}
+	} else {
+		info->spurious_cnt = 0;
+	}
+
+	cpu = info->eoi_cpu;
+	if (info->eoi_time &&
+	    (info->irq_epoch == per_cpu(irq_epoch, cpu) || delay)) {
+		lateeoi_list_add(info);
+		return;
+	}
+
+	info->eoi_time = 0;
+	do_unmask(info, EVT_MASK_REASON_EOI_PENDING);
+}
+
+static void xen_irq_lateeoi_worker(struct work_struct *work)
+{
+	struct lateeoi_work *eoi;
+	struct irq_info *info;
+	u64 now = get_jiffies_64();
+	unsigned long flags;
+
+	eoi = container_of(to_delayed_work(work), struct lateeoi_work, delayed);
+
+	read_lock_irqsave(&evtchn_rwlock, flags);
+
+	while (true) {
+		spin_lock(&eoi->eoi_list_lock);
+
+		info = list_first_entry_or_null(&eoi->eoi_list, struct irq_info,
+						eoi_list);
+
+		if (info == NULL || now < info->eoi_time) {
+			spin_unlock(&eoi->eoi_list_lock);
+			break;
+		}
+
+		list_del_init(&info->eoi_list);
+
+		spin_unlock(&eoi->eoi_list_lock);
+
+		info->eoi_time = 0;
+
+		xen_irq_lateeoi_locked(info, false);
+	}
+
+	if (info)
+		mod_delayed_work_on(info->eoi_cpu, system_wq,
+				    &eoi->delayed, info->eoi_time - now);
+
+	read_unlock_irqrestore(&evtchn_rwlock, flags);
+}
+
+static void xen_cpu_init_eoi(unsigned int cpu)
+{
+	struct lateeoi_work *eoi = &per_cpu(lateeoi, cpu);
+
+	INIT_DELAYED_WORK(&eoi->delayed, xen_irq_lateeoi_worker);
+	spin_lock_init(&eoi->eoi_list_lock);
+	INIT_LIST_HEAD(&eoi->eoi_list);
+}
+
+void xen_irq_lateeoi(unsigned int irq, unsigned int eoi_flags)
+{
+	struct irq_info *info;
+	unsigned long flags;
+
+	read_lock_irqsave(&evtchn_rwlock, flags);
+
+	info = info_for_irq(irq);
+
+	if (info)
+		xen_irq_lateeoi_locked(info, eoi_flags & XEN_EOI_FLAG_SPURIOUS);
+
+	read_unlock_irqrestore(&evtchn_rwlock, flags);
+}
+EXPORT_SYMBOL_GPL(xen_irq_lateeoi);
+
 static void xen_irq_init(unsigned irq)
 {
 	struct irq_info *info;
+
 #ifdef CONFIG_SMP
 	/* By default all event channels notify CPU#0. */
 	cpumask_copy(irq_get_affinity_mask(irq), cpumask_of(0));
@@ -384,8 +615,9 @@
 	info->type = IRQT_UNBOUND;
 	info->refcnt = -1;
 
-	irq_set_handler_data(irq, info);
+	set_info_for_irq(irq, info);
 
+	INIT_LIST_HEAD(&info->eoi_list);
 	list_add_tail(&info->list, &xen_irq_list_head);
 }
 
@@ -433,17 +665,25 @@
 
 static void xen_free_irq(unsigned irq)
 {
-	struct irq_info *info = irq_get_handler_data(irq);
+	struct irq_info *info = info_for_irq(irq);
+	unsigned long flags;
 
 	if (WARN_ON(!info))
 		return;
 
+	write_lock_irqsave(&evtchn_rwlock, flags);
+
+	if (!list_empty(&info->eoi_list))
+		lateeoi_list_del(info);
+
 	list_del(&info->list);
 
-	irq_set_handler_data(irq, NULL);
+	set_info_for_irq(irq, NULL);
 
 	WARN_ON(info->refcnt > 0);
 
+	write_unlock_irqrestore(&evtchn_rwlock, flags);
+
 	kfree(info);
 
 	/* Legacy IRQ descriptors are managed by the arch. */
@@ -462,6 +702,12 @@
 		BUG();
 }
 
+static void event_handler_exit(struct irq_info *info)
+{
+	smp_store_release(&info->is_active, 0);
+	clear_evtchn(info->evtchn);
+}
+
 static void pirq_query_unmask(int irq)
 {
 	struct physdev_irq_status_query irq_status;
@@ -480,14 +726,25 @@
 
 static void eoi_pirq(struct irq_data *data)
 {
-	int evtchn = evtchn_from_irq(data->irq);
+	struct irq_info *info = info_for_irq(data->irq);
+	int evtchn = info ? info->evtchn : 0;
 	struct physdev_eoi eoi = { .irq = pirq_from_irq(data->irq) };
 	int rc = 0;
 
-	irq_move_irq(data);
+	if (!VALID_EVTCHN(evtchn))
+		return;
 
-	if (VALID_EVTCHN(evtchn))
-		clear_evtchn(evtchn);
+	if (unlikely(irqd_is_setaffinity_pending(data)) &&
+	    likely(!irqd_irq_disabled(data))) {
+		do_mask(info, EVT_MASK_REASON_TEMPORARY);
+
+		event_handler_exit(info);
+
+		irq_move_masked_irq(data);
+
+		do_unmask(info, EVT_MASK_REASON_TEMPORARY);
+	} else
+		event_handler_exit(info);
 
 	if (pirq_needs_eoi(data->irq)) {
 		rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
@@ -538,7 +795,8 @@
 		goto err;
 
 out:
-	unmask_evtchn(evtchn);
+	do_unmask(info, EVT_MASK_REASON_EXPLICIT);
+
 	eoi_pirq(irq_get_irq_data(irq));
 
 	return 0;
@@ -565,9 +823,9 @@
 	if (!VALID_EVTCHN(evtchn))
 		return;
 
-	mask_evtchn(evtchn);
-	xen_evtchn_close(evtchn);
+	do_mask(info, EVT_MASK_REASON_EXPLICIT);
 	xen_irq_info_cleanup(info);
+	xen_evtchn_close(evtchn);
 }
 
 static void enable_pirq(struct irq_data *data)
@@ -599,7 +857,7 @@
 static void __unbind_from_irq(unsigned int irq)
 {
 	int evtchn = evtchn_from_irq(irq);
-	struct irq_info *info = irq_get_handler_data(irq);
+	struct irq_info *info = info_for_irq(irq);
 
 	if (info->refcnt > 0) {
 		info->refcnt--;
@@ -610,8 +868,6 @@
 	if (VALID_EVTCHN(evtchn)) {
 		unsigned int cpu = cpu_from_irq(irq);
 
-		xen_evtchn_close(evtchn);
-
 		switch (type_from_irq(irq)) {
 		case IRQT_VIRQ:
 			per_cpu(virq_to_irq, cpu)[virq_from_irq(irq)] = -1;
@@ -624,10 +880,9 @@
 		}
 
 		xen_irq_info_cleanup(info);
+		xen_evtchn_close(evtchn);
 	}
 
-	BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND);
-
 	xen_free_irq(irq);
 }
 
@@ -753,8 +1008,8 @@
 	mutex_unlock(&irq_mapping_update_lock);
 	return irq;
 error_irq:
-	for (; i >= 0; i--)
-		__unbind_from_irq(irq + i);
+	while (nvec--)
+		__unbind_from_irq(irq + nvec);
 	mutex_unlock(&irq_mapping_update_lock);
 	return ret;
 }
@@ -826,7 +1081,7 @@
 }
 EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
 
-int bind_evtchn_to_irq(unsigned int evtchn)
+static int bind_evtchn_to_irq_chip(evtchn_port_t evtchn, struct irq_chip *chip)
 {
 	int irq;
 	int ret;
@@ -843,7 +1098,7 @@
 		if (irq < 0)
 			goto out;
 
-		irq_set_chip_and_handler_name(irq, &xen_dynamic_chip,
+		irq_set_chip_and_handler_name(irq, chip,
 					      handle_edge_irq, "event");
 
 		ret = xen_irq_info_evtchn_setup(irq, evtchn);
@@ -864,8 +1119,19 @@
 
 	return irq;
 }
+
+int bind_evtchn_to_irq(evtchn_port_t evtchn)
+{
+	return bind_evtchn_to_irq_chip(evtchn, &xen_dynamic_chip);
+}
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
 
+int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn)
+{
+	return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip);
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq_lateeoi);
+
 static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 {
 	struct evtchn_bind_ipi bind_ipi;
@@ -907,8 +1173,9 @@
 	return irq;
 }
 
-int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-				   unsigned int remote_port)
+static int bind_interdomain_evtchn_to_irq_chip(unsigned int remote_domain,
+					       evtchn_port_t remote_port,
+					       struct irq_chip *chip)
 {
 	struct evtchn_bind_interdomain bind_interdomain;
 	int err;
@@ -919,10 +1186,26 @@
 	err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
 					  &bind_interdomain);
 
-	return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
+	return err ? : bind_evtchn_to_irq_chip(bind_interdomain.local_port,
+					       chip);
+}
+
+int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
+				   evtchn_port_t remote_port)
+{
+	return bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
+						   &xen_dynamic_chip);
 }
 EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq);
 
+int bind_interdomain_evtchn_to_irq_lateeoi(unsigned int remote_domain,
+					   evtchn_port_t remote_port)
+{
+	return bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
+						   &xen_lateeoi_chip);
+}
+EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq_lateeoi);
+
 static int find_virq(unsigned int virq, unsigned int cpu)
 {
 	struct evtchn_status status;
@@ -1018,14 +1301,15 @@
 	mutex_unlock(&irq_mapping_update_lock);
 }
 
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
-			      irq_handler_t handler,
-			      unsigned long irqflags,
-			      const char *devname, void *dev_id)
+static int bind_evtchn_to_irqhandler_chip(evtchn_port_t evtchn,
+					  irq_handler_t handler,
+					  unsigned long irqflags,
+					  const char *devname, void *dev_id,
+					  struct irq_chip *chip)
 {
 	int irq, retval;
 
-	irq = bind_evtchn_to_irq(evtchn);
+	irq = bind_evtchn_to_irq_chip(evtchn, chip);
 	if (irq < 0)
 		return irq;
 	retval = request_irq(irq, handler, irqflags, devname, dev_id);
@@ -1036,18 +1320,38 @@
 
 	return irq;
 }
+
+int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
+			      irq_handler_t handler,
+			      unsigned long irqflags,
+			      const char *devname, void *dev_id)
+{
+	return bind_evtchn_to_irqhandler_chip(evtchn, handler, irqflags,
+					      devname, dev_id,
+					      &xen_dynamic_chip);
+}
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
 
-int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-					  unsigned int remote_port,
-					  irq_handler_t handler,
-					  unsigned long irqflags,
-					  const char *devname,
-					  void *dev_id)
+int bind_evtchn_to_irqhandler_lateeoi(evtchn_port_t evtchn,
+				      irq_handler_t handler,
+				      unsigned long irqflags,
+				      const char *devname, void *dev_id)
+{
+	return bind_evtchn_to_irqhandler_chip(evtchn, handler, irqflags,
+					      devname, dev_id,
+					      &xen_lateeoi_chip);
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler_lateeoi);
+
+static int bind_interdomain_evtchn_to_irqhandler_chip(
+		unsigned int remote_domain, evtchn_port_t remote_port,
+		irq_handler_t handler, unsigned long irqflags,
+		const char *devname, void *dev_id, struct irq_chip *chip)
 {
 	int irq, retval;
 
-	irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
+	irq = bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
+						  chip);
 	if (irq < 0)
 		return irq;
 
@@ -1059,8 +1363,33 @@
 
 	return irq;
 }
+
+int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
+					  evtchn_port_t remote_port,
+					  irq_handler_t handler,
+					  unsigned long irqflags,
+					  const char *devname,
+					  void *dev_id)
+{
+	return bind_interdomain_evtchn_to_irqhandler_chip(remote_domain,
+				remote_port, handler, irqflags, devname,
+				dev_id, &xen_dynamic_chip);
+}
 EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler);
 
+int bind_interdomain_evtchn_to_irqhandler_lateeoi(unsigned int remote_domain,
+						  evtchn_port_t remote_port,
+						  irq_handler_t handler,
+						  unsigned long irqflags,
+						  const char *devname,
+						  void *dev_id)
+{
+	return bind_interdomain_evtchn_to_irqhandler_chip(remote_domain,
+				remote_port, handler, irqflags, devname,
+				dev_id, &xen_lateeoi_chip);
+}
+EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler_lateeoi);
+
 int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
 			    irq_handler_t handler,
 			    unsigned long irqflags, const char *devname, void *dev_id)
@@ -1105,7 +1434,7 @@
 
 void unbind_from_irqhandler(unsigned int irq, void *dev_id)
 {
-	struct irq_info *info = irq_get_handler_data(irq);
+	struct irq_info *info = info_for_irq(irq);
 
 	if (WARN_ON(!info))
 		return;
@@ -1139,7 +1468,7 @@
 	if (irq == -1)
 		return -ENOENT;
 
-	info = irq_get_handler_data(irq);
+	info = info_for_irq(irq);
 
 	if (!info)
 		return -ENOENT;
@@ -1167,13 +1496,13 @@
 	if (irq == -1)
 		goto done;
 
-	info = irq_get_handler_data(irq);
+	info = info_for_irq(irq);
 
 	if (!info)
 		goto done;
 
 	err = -EINVAL;
-	if (info->refcnt <= 0)
+	if (info->refcnt <= 0 || info->refcnt == SHRT_MAX)
 		goto done;
 
 	info->refcnt++;
@@ -1211,6 +1540,56 @@
 	notify_remote_via_irq(irq);
 }
 
+struct evtchn_loop_ctrl {
+	ktime_t timeout;
+	unsigned count;
+	bool defer_eoi;
+};
+
+void handle_irq_for_port(evtchn_port_t port, struct evtchn_loop_ctrl *ctrl)
+{
+	int irq;
+	struct irq_info *info;
+
+	irq = get_evtchn_to_irq(port);
+	if (irq == -1)
+		return;
+
+	/*
+	 * Check for timeout every 256 events.
+	 * We are setting the timeout value only after the first 256
+	 * events in order to not hurt the common case of few loop
+	 * iterations. The 256 is basically an arbitrary value.
+	 *
+	 * In case we are hitting the timeout we need to defer all further
+	 * EOIs in order to ensure to leave the event handling loop rather
+	 * sooner than later.
+	 */
+	if (!ctrl->defer_eoi && !(++ctrl->count & 0xff)) {
+		ktime_t kt = ktime_get();
+
+		if (!ctrl->timeout.tv64) {
+			kt = ktime_add_ms(kt,
+					  jiffies_to_msecs(event_loop_timeout));
+			ctrl->timeout = kt;
+		} else if (kt.tv64 > ctrl->timeout.tv64) {
+			ctrl->defer_eoi = true;
+		}
+	}
+
+	info = info_for_irq(irq);
+	if (xchg_acquire(&info->is_active, 1))
+		return;
+
+	if (ctrl->defer_eoi) {
+		info->eoi_cpu = smp_processor_id();
+		info->irq_epoch = __this_cpu_read(irq_epoch);
+		info->eoi_time = get_jiffies_64() + event_eoi_delay;
+	}
+
+	generic_handle_irq(irq);
+}
+
 static DEFINE_PER_CPU(unsigned, xed_nesting_count);
 
 static void __xen_evtchn_do_upcall(void)
@@ -1218,6 +1597,9 @@
 	struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
 	int cpu = get_cpu();
 	unsigned count;
+	struct evtchn_loop_ctrl ctrl = { 0 };
+
+	read_lock(&evtchn_rwlock);
 
 	do {
 		vcpu_info->evtchn_upcall_pending = 0;
@@ -1225,7 +1607,7 @@
 		if (__this_cpu_inc_return(xed_nesting_count) - 1)
 			goto out;
 
-		xen_evtchn_handle_events(cpu);
+		xen_evtchn_handle_events(cpu, &ctrl);
 
 		BUG_ON(!irqs_disabled());
 
@@ -1234,6 +1616,14 @@
 	} while (count != 1 || vcpu_info->evtchn_upcall_pending);
 
 out:
+	read_unlock(&evtchn_rwlock);
+
+	/*
+	 * Increment irq_epoch only now to defer EOIs only for
+	 * xen_irq_lateeoi() invocations occurring from inside the loop
+	 * above.
+	 */
+	__this_cpu_inc(irq_epoch);
 
 	put_cpu();
 }
@@ -1296,8 +1686,8 @@
 static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
 {
 	struct evtchn_bind_vcpu bind_vcpu;
-	int evtchn = evtchn_from_irq(irq);
-	int masked;
+	struct irq_info *info = info_for_irq(irq);
+	int evtchn = info ? info->evtchn : 0;
 
 	if (!VALID_EVTCHN(evtchn))
 		return -1;
@@ -1313,7 +1703,7 @@
 	 * Mask the event while changing the VCPU binding to prevent
 	 * it being delivered on an unexpected VCPU.
 	 */
-	masked = test_and_set_mask(evtchn);
+	do_mask(info, EVT_MASK_REASON_TEMPORARY);
 
 	/*
 	 * If this fails, it usually just indicates that we're dealing with a
@@ -1323,8 +1713,7 @@
 	if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
 		bind_evtchn_to_cpu(evtchn, tcpu);
 
-	if (!masked)
-		unmask_evtchn(evtchn);
+	do_unmask(info, EVT_MASK_REASON_TEMPORARY);
 
 	return 0;
 }
@@ -1339,28 +1728,41 @@
 
 static void enable_dynirq(struct irq_data *data)
 {
-	int evtchn = evtchn_from_irq(data->irq);
+	struct irq_info *info = info_for_irq(data->irq);
+	evtchn_port_t evtchn = info ? info->evtchn : 0;
 
 	if (VALID_EVTCHN(evtchn))
-		unmask_evtchn(evtchn);
+		do_unmask(info, EVT_MASK_REASON_EXPLICIT);
 }
 
 static void disable_dynirq(struct irq_data *data)
 {
-	int evtchn = evtchn_from_irq(data->irq);
+	struct irq_info *info = info_for_irq(data->irq);
+	evtchn_port_t evtchn = info ? info->evtchn : 0;
 
 	if (VALID_EVTCHN(evtchn))
-		mask_evtchn(evtchn);
+		do_mask(info, EVT_MASK_REASON_EXPLICIT);
 }
 
 static void ack_dynirq(struct irq_data *data)
 {
-	int evtchn = evtchn_from_irq(data->irq);
+	struct irq_info *info = info_for_irq(data->irq);
+	evtchn_port_t evtchn = info ? info->evtchn : 0;
+
+	if (!VALID_EVTCHN(evtchn))
+		return;
 
-	irq_move_irq(data);
+	if (unlikely(irqd_is_setaffinity_pending(data)) &&
+	    likely(!irqd_irq_disabled(data))) {
+		do_mask(info, EVT_MASK_REASON_TEMPORARY);
 
-	if (VALID_EVTCHN(evtchn))
-		clear_evtchn(evtchn);
+		event_handler_exit(info);
+
+		irq_move_masked_irq(data);
+
+		do_unmask(info, EVT_MASK_REASON_TEMPORARY);
+	} else
+		event_handler_exit(info);
 }
 
 static void mask_ack_dynirq(struct irq_data *data)
@@ -1369,18 +1771,39 @@
 	ack_dynirq(data);
 }
 
+static void lateeoi_ack_dynirq(struct irq_data *data)
+{
+	struct irq_info *info = info_for_irq(data->irq);
+	evtchn_port_t evtchn = info ? info->evtchn : 0;
+
+	if (VALID_EVTCHN(evtchn)) {
+		do_mask(info, EVT_MASK_REASON_EOI_PENDING);
+		event_handler_exit(info);
+	}
+}
+
+static void lateeoi_mask_ack_dynirq(struct irq_data *data)
+{
+	struct irq_info *info = info_for_irq(data->irq);
+	evtchn_port_t evtchn = info ? info->evtchn : 0;
+
+	if (VALID_EVTCHN(evtchn)) {
+		do_mask(info, EVT_MASK_REASON_EXPLICIT);
+		event_handler_exit(info);
+	}
+}
+
 static int retrigger_dynirq(struct irq_data *data)
 {
-	unsigned int evtchn = evtchn_from_irq(data->irq);
-	int masked;
+	struct irq_info *info = info_for_irq(data->irq);
+	evtchn_port_t evtchn = info ? info->evtchn : 0;
 
 	if (!VALID_EVTCHN(evtchn))
 		return 0;
 
-	masked = test_and_set_mask(evtchn);
+	do_mask(info, EVT_MASK_REASON_TEMPORARY);
 	set_evtchn(evtchn);
-	if (!masked)
-		unmask_evtchn(evtchn);
+	do_unmask(info, EVT_MASK_REASON_TEMPORARY);
 
 	return 1;
 }
@@ -1475,10 +1898,11 @@
 /* Clear an irq's pending state, in preparation for polling on it */
 void xen_clear_irq_pending(int irq)
 {
-	int evtchn = evtchn_from_irq(irq);
+	struct irq_info *info = info_for_irq(irq);
+	evtchn_port_t evtchn = info ? info->evtchn : 0;
 
 	if (VALID_EVTCHN(evtchn))
-		clear_evtchn(evtchn);
+		event_handler_exit(info);
 }
 EXPORT_SYMBOL(xen_clear_irq_pending);
 void xen_set_irq_pending(int irq)
@@ -1579,6 +2003,21 @@
 	.irq_retrigger		= retrigger_dynirq,
 };
 
+static struct irq_chip xen_lateeoi_chip __read_mostly = {
+	/* The chip name needs to contain "xen-dyn" for irqbalance to work. */
+	.name			= "xen-dyn-lateeoi",
+
+	.irq_disable		= disable_dynirq,
+	.irq_mask		= disable_dynirq,
+	.irq_unmask		= enable_dynirq,
+
+	.irq_ack		= lateeoi_ack_dynirq,
+	.irq_mask_ack		= lateeoi_mask_ack_dynirq,
+
+	.irq_set_affinity	= set_affinity_irq,
+	.irq_retrigger		= retrigger_dynirq,
+};
+
 static struct irq_chip xen_pirq_chip __read_mostly = {
 	.name			= "xen-pirq",
 
@@ -1646,12 +2085,55 @@
 void xen_callback_vector(void) {}
 #endif
 
-#undef MODULE_PARAM_PREFIX
-#define MODULE_PARAM_PREFIX "xen."
-
 static bool fifo_events = true;
 module_param(fifo_events, bool, 0);
 
+static int xen_evtchn_cpu_prepare(unsigned int cpu)
+{
+	int ret = 0;
+
+	xen_cpu_init_eoi(cpu);
+
+	if (evtchn_ops->percpu_init)
+		ret = evtchn_ops->percpu_init(cpu);
+
+	return ret;
+}
+
+static int xen_evtchn_cpu_dead(unsigned int cpu)
+{
+	int ret = 0;
+
+	if (evtchn_ops->percpu_deinit)
+		ret = evtchn_ops->percpu_deinit(cpu);
+
+	return ret;
+}
+
+static int evtchn_cpu_notification(struct notifier_block *self,
+				   unsigned long action, void *hcpu)
+{
+	int cpu = (long)hcpu;
+	int ret = 0;
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+		ret = xen_evtchn_cpu_prepare(cpu);
+		break;
+	case CPU_DEAD:
+		ret = xen_evtchn_cpu_dead(cpu);
+		break;
+	default:
+		break;
+	}
+
+	return ret < 0 ? NOTIFY_BAD : NOTIFY_OK;
+}
+
+static struct notifier_block evtchn_cpu_notifier = {
+	.notifier_call  = evtchn_cpu_notification,
+};
+
 void __init xen_init_IRQ(void)
 {
 	int ret = -EINVAL;
@@ -1661,6 +2143,10 @@
 	if (ret < 0)
 		xen_evtchn_2l_init();
 
+	xen_cpu_init_eoi(smp_processor_id());
+
+	register_cpu_notifier(&evtchn_cpu_notifier);
+
 	evtchn_to_irq = kcalloc(EVTCHN_ROW(xen_evtchn_max_channels()),
 				sizeof(*evtchn_to_irq), GFP_KERNEL);
 	BUG_ON(!evtchn_to_irq);
--- linux-4.4.0.orig/drivers/xen/events/events_fifo.c
+++ linux-4.4.0/drivers/xen/events/events_fifo.c
@@ -209,12 +209,6 @@
 	return sync_test_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
 }
 
-static bool evtchn_fifo_test_and_set_mask(unsigned port)
-{
-	event_word_t *word = event_word_from_port(port);
-	return sync_test_and_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
-}
-
 static void evtchn_fifo_mask(unsigned port)
 {
 	event_word_t *word = event_word_from_port(port);
@@ -227,19 +221,25 @@
 	return sync_test_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
 }
 /*
- * Clear MASKED, spinning if BUSY is set.
+ * Clear MASKED if not PENDING, spinning if BUSY is set.
+ * Return true if mask was cleared.
  */
-static void clear_masked(volatile event_word_t *word)
+static bool clear_masked_cond(volatile event_word_t *word)
 {
 	event_word_t new, old, w;
 
 	w = *word;
 
 	do {
+		if (w & (1 << EVTCHN_FIFO_PENDING))
+			return false;
+
 		old = w & ~(1 << EVTCHN_FIFO_BUSY);
 		new = old & ~(1 << EVTCHN_FIFO_MASKED);
 		w = sync_cmpxchg(word, old, new);
 	} while (w != old);
+
+	return true;
 }
 
 static void evtchn_fifo_unmask(unsigned port)
@@ -248,8 +248,7 @@
 
 	BUG_ON(!irqs_disabled());
 
-	clear_masked(word);
-	if (evtchn_fifo_is_pending(port)) {
+	if (!clear_masked_cond(word)) {
 		struct evtchn_unmask unmask = { .port = port };
 		(void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
 	}
@@ -270,19 +269,9 @@
 	return w & EVTCHN_FIFO_LINK_MASK;
 }
 
-static void handle_irq_for_port(unsigned port)
-{
-	int irq;
-
-	irq = get_evtchn_to_irq(port);
-	if (irq != -1)
-		generic_handle_irq(irq);
-}
-
-static void consume_one_event(unsigned cpu,
+static void consume_one_event(unsigned cpu, struct evtchn_loop_ctrl *ctrl,
 			      struct evtchn_fifo_control_block *control_block,
-			      unsigned priority, unsigned long *ready,
-			      bool drop)
+			      unsigned priority, unsigned long *ready)
 {
 	struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
 	uint32_t head;
@@ -315,16 +304,17 @@
 		clear_bit(priority, ready);
 
 	if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) {
-		if (unlikely(drop))
+		if (unlikely(!ctrl))
 			pr_warn("Dropping pending event for port %u\n", port);
 		else
-			handle_irq_for_port(port);
+			handle_irq_for_port(port, ctrl);
 	}
 
 	q->head[priority] = head;
 }
 
-static void __evtchn_fifo_handle_events(unsigned cpu, bool drop)
+static void __evtchn_fifo_handle_events(unsigned cpu,
+					struct evtchn_loop_ctrl *ctrl)
 {
 	struct evtchn_fifo_control_block *control_block;
 	unsigned long ready;
@@ -336,14 +326,15 @@
 
 	while (ready) {
 		q = find_first_bit(&ready, EVTCHN_FIFO_MAX_QUEUES);
-		consume_one_event(cpu, control_block, q, &ready, drop);
+		consume_one_event(cpu, ctrl, control_block, q, &ready);
 		ready |= xchg(&control_block->ready, 0);
 	}
 }
 
-static void evtchn_fifo_handle_events(unsigned cpu)
+static void evtchn_fifo_handle_events(unsigned cpu,
+				      struct evtchn_loop_ctrl *ctrl)
 {
-	__evtchn_fifo_handle_events(cpu, false);
+	__evtchn_fifo_handle_events(cpu, ctrl);
 }
 
 static void evtchn_fifo_resume(void)
@@ -381,21 +372,6 @@
 	event_array_pages = 0;
 }
 
-static const struct evtchn_ops evtchn_ops_fifo = {
-	.max_channels      = evtchn_fifo_max_channels,
-	.nr_channels       = evtchn_fifo_nr_channels,
-	.setup             = evtchn_fifo_setup,
-	.bind_to_cpu       = evtchn_fifo_bind_to_cpu,
-	.clear_pending     = evtchn_fifo_clear_pending,
-	.set_pending       = evtchn_fifo_set_pending,
-	.is_pending        = evtchn_fifo_is_pending,
-	.test_and_set_mask = evtchn_fifo_test_and_set_mask,
-	.mask              = evtchn_fifo_mask,
-	.unmask            = evtchn_fifo_unmask,
-	.handle_events     = evtchn_fifo_handle_events,
-	.resume            = evtchn_fifo_resume,
-};
-
 static int evtchn_fifo_alloc_control_block(unsigned cpu)
 {
 	void *control_block = NULL;
@@ -418,29 +394,33 @@
 	return ret;
 }
 
-static int evtchn_fifo_cpu_notification(struct notifier_block *self,
-						  unsigned long action,
-						  void *hcpu)
-{
-	int cpu = (long)hcpu;
-	int ret = 0;
-
-	switch (action) {
-	case CPU_UP_PREPARE:
-		if (!per_cpu(cpu_control_block, cpu))
-			ret = evtchn_fifo_alloc_control_block(cpu);
-		break;
-	case CPU_DEAD:
-		__evtchn_fifo_handle_events(cpu, true);
-		break;
-	default:
-		break;
-	}
-	return ret < 0 ? NOTIFY_BAD : NOTIFY_OK;
+static int evtchn_fifo_percpu_init(unsigned int cpu)
+{
+	if (!per_cpu(cpu_control_block, cpu))
+		return evtchn_fifo_alloc_control_block(cpu);
+	return 0;
 }
 
-static struct notifier_block evtchn_fifo_cpu_notifier = {
-	.notifier_call	= evtchn_fifo_cpu_notification,
+static int evtchn_fifo_percpu_deinit(unsigned int cpu)
+{
+	__evtchn_fifo_handle_events(cpu, NULL);
+	return 0;
+}
+
+static const struct evtchn_ops evtchn_ops_fifo = {
+	.max_channels      = evtchn_fifo_max_channels,
+	.nr_channels       = evtchn_fifo_nr_channels,
+	.setup             = evtchn_fifo_setup,
+	.bind_to_cpu       = evtchn_fifo_bind_to_cpu,
+	.clear_pending     = evtchn_fifo_clear_pending,
+	.set_pending       = evtchn_fifo_set_pending,
+	.is_pending        = evtchn_fifo_is_pending,
+	.mask              = evtchn_fifo_mask,
+	.unmask            = evtchn_fifo_unmask,
+	.handle_events     = evtchn_fifo_handle_events,
+	.resume            = evtchn_fifo_resume,
+	.percpu_init       = evtchn_fifo_percpu_init,
+	.percpu_deinit     = evtchn_fifo_percpu_deinit,
 };
 
 int __init xen_evtchn_fifo_init(void)
@@ -456,7 +436,6 @@
 
 	evtchn_ops = &evtchn_ops_fifo;
 
-	register_cpu_notifier(&evtchn_fifo_cpu_notifier);
 out:
 	put_cpu();
 	return ret;
--- linux-4.4.0.orig/drivers/xen/events/events_internal.h
+++ linux-4.4.0/drivers/xen/events/events_internal.h
@@ -32,11 +32,22 @@
  */
 struct irq_info {
 	struct list_head list;
-	int refcnt;
-	enum xen_irq_type type;	/* type */
+	struct list_head eoi_list;
+	short refcnt;
+	short spurious_cnt;
+	short type;		/* type */
+	u8 mask_reason;		/* Why is event channel masked */
+#define EVT_MASK_REASON_EXPLICIT	0x01
+#define EVT_MASK_REASON_TEMPORARY	0x02
+#define EVT_MASK_REASON_EOI_PENDING	0x04
+	u8 is_active;		/* Is event just being handled? */
 	unsigned irq;
 	unsigned int evtchn;	/* event channel */
 	unsigned short cpu;	/* cpu bound */
+	unsigned short eoi_cpu;	/* EOI must happen on this cpu */
+	unsigned int irq_epoch;	/* If eoi_cpu valid: irq_epoch of event */
+	u64 eoi_time;		/* Time in jiffies when to EOI. */
+	spinlock_t lock;
 
 	union {
 		unsigned short virq;
@@ -55,28 +66,34 @@
 #define PIRQ_SHAREABLE	(1 << 1)
 #define PIRQ_MSI_GROUP	(1 << 2)
 
+struct evtchn_loop_ctrl;
+
 struct evtchn_ops {
 	unsigned (*max_channels)(void);
 	unsigned (*nr_channels)(void);
 
 	int (*setup)(struct irq_info *info);
+	void (*remove)(evtchn_port_t port, unsigned int cpu);
 	void (*bind_to_cpu)(struct irq_info *info, unsigned cpu);
 
 	void (*clear_pending)(unsigned port);
 	void (*set_pending)(unsigned port);
 	bool (*is_pending)(unsigned port);
-	bool (*test_and_set_mask)(unsigned port);
 	void (*mask)(unsigned port);
 	void (*unmask)(unsigned port);
 
-	void (*handle_events)(unsigned cpu);
+	void (*handle_events)(unsigned cpu, struct evtchn_loop_ctrl *ctrl);
 	void (*resume)(void);
+
+	int (*percpu_init)(unsigned int cpu);
+	int (*percpu_deinit)(unsigned int cpu);
 };
 
 extern const struct evtchn_ops *evtchn_ops;
 
 extern int **evtchn_to_irq;
 int get_evtchn_to_irq(unsigned int evtchn);
+void handle_irq_for_port(evtchn_port_t port, struct evtchn_loop_ctrl *ctrl);
 
 struct irq_info *info_for_irq(unsigned irq);
 unsigned cpu_from_irq(unsigned irq);
@@ -98,6 +115,13 @@
 	return 0;
 }
 
+static inline void xen_evtchn_port_remove(evtchn_port_t evtchn,
+					  unsigned int cpu)
+{
+	if (evtchn_ops->remove)
+		evtchn_ops->remove(evtchn, cpu);
+}
+
 static inline void xen_evtchn_port_bind_to_cpu(struct irq_info *info,
 					       unsigned cpu)
 {
@@ -119,11 +143,6 @@
 	return evtchn_ops->is_pending(port);
 }
 
-static inline bool test_and_set_mask(unsigned port)
-{
-	return evtchn_ops->test_and_set_mask(port);
-}
-
 static inline void mask_evtchn(unsigned port)
 {
 	return evtchn_ops->mask(port);
@@ -134,9 +153,10 @@
 	return evtchn_ops->unmask(port);
 }
 
-static inline void xen_evtchn_handle_events(unsigned cpu)
+static inline void xen_evtchn_handle_events(unsigned cpu,
+					    struct evtchn_loop_ctrl *ctrl)
 {
-	return evtchn_ops->handle_events(cpu);
+	return evtchn_ops->handle_events(cpu, ctrl);
 }
 
 static inline void xen_evtchn_resume(void)
--- linux-4.4.0.orig/drivers/xen/evtchn.c
+++ linux-4.4.0/drivers/xen/evtchn.c
@@ -173,7 +173,6 @@
 	     "Interrupt for port %d, but apparently not enabled; per-user %p\n",
 	     evtchn->port, u);
 
-	disable_irq_nosync(irq);
 	evtchn->enabled = false;
 
 	spin_lock(&u->ring_prod_lock);
@@ -299,7 +298,7 @@
 		evtchn = find_evtchn(u, port);
 		if (evtchn && !evtchn->enabled) {
 			evtchn->enabled = true;
-			enable_irq(irq_from_evtchn(port));
+			xen_irq_lateeoi(irq_from_evtchn(port), 0);
 		}
 	}
 
@@ -316,7 +315,6 @@
 {
 	unsigned int new_size;
 	evtchn_port_t *new_ring, *old_ring;
-	unsigned int p, c;
 
 	/*
 	 * Ensure the ring is large enough to capture all possible
@@ -346,20 +344,17 @@
 	/*
 	 * Copy the old ring contents to the new ring.
 	 *
-	 * If the ring contents crosses the end of the current ring,
-	 * it needs to be copied in two chunks.
+	 * To take care of wrapping, a full ring, and the new index
+	 * pointing into the second half, simply copy the old contents
+	 * twice.
 	 *
 	 * +---------+    +------------------+
-	 * |34567  12| -> |       1234567    |
-	 * +-----p-c-+    +------------------+
+	 * |34567  12| -> |34567  1234567  12|
+	 * +-----p-c-+    +-------c------p---+
 	 */
-	p = evtchn_ring_offset(u, u->ring_prod);
-	c = evtchn_ring_offset(u, u->ring_cons);
-	if (p < c) {
-		memcpy(new_ring + c, u->ring + c, (u->ring_size - c) * sizeof(*u->ring));
-		memcpy(new_ring + u->ring_size, u->ring, p * sizeof(*u->ring));
-	} else
-		memcpy(new_ring + c, u->ring + c, (p - c) * sizeof(*u->ring));
+	memcpy(new_ring, old_ring, u->ring_size * sizeof(*u->ring));
+	memcpy(new_ring + u->ring_size, old_ring,
+	       u->ring_size * sizeof(*u->ring));
 
 	u->ring = new_ring;
 	u->ring_size = new_size;
@@ -403,8 +398,8 @@
 	if (rc < 0)
 		goto err;
 
-	rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, 0,
-				       u->name, evtchn);
+	rc = bind_evtchn_to_irqhandler_lateeoi(port, evtchn_interrupt, 0,
+					       u->name, evtchn);
 	if (rc < 0)
 		goto err;
 
--- linux-4.4.0.orig/drivers/xen/gntdev.c
+++ linux-4.4.0/drivers/xen/gntdev.c
@@ -293,36 +293,47 @@
 		 * to the kernel linear addresses of the struct pages.
 		 * These ptes are completely different from the user ptes dealt
 		 * with find_grant_ptes.
+		 * Note that GNTMAP_device_map isn't needed here: The
+		 * dev_bus_addr output field gets consumed only from ->map_ops,
+		 * and by not requesting it when mapping we also avoid needing
+		 * to mirror dev_bus_addr into ->unmap_ops (and holding an extra
+		 * reference to the page in the hypervisor).
 		 */
+		unsigned int flags = (map->flags & ~GNTMAP_device_map) |
+				     GNTMAP_host_map;
+
 		for (i = 0; i < map->count; i++) {
 			unsigned long address = (unsigned long)
 				pfn_to_kaddr(page_to_pfn(map->pages[i]));
 			BUG_ON(PageHighMem(map->pages[i]));
 
-			gnttab_set_map_op(&map->kmap_ops[i], address,
-				map->flags | GNTMAP_host_map,
+			gnttab_set_map_op(&map->kmap_ops[i], address, flags,
 				map->grants[i].ref,
 				map->grants[i].domid);
 			gnttab_set_unmap_op(&map->kunmap_ops[i], address,
-				map->flags | GNTMAP_host_map, -1);
+				flags, -1);
 		}
 	}
 
 	pr_debug("map %d+%d\n", map->index, map->count);
 	err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL,
 			map->pages, map->count);
-	if (err)
-		return err;
 
 	for (i = 0; i < map->count; i++) {
-		if (map->map_ops[i].status) {
+		if (map->map_ops[i].status == GNTST_okay)
+			map->unmap_ops[i].handle = map->map_ops[i].handle;
+		else if (!err)
 			err = -EINVAL;
-			continue;
-		}
 
-		map->unmap_ops[i].handle = map->map_ops[i].handle;
-		if (use_ptemod)
-			map->kunmap_ops[i].handle = map->kmap_ops[i].handle;
+		if (map->flags & GNTMAP_device_map)
+			map->unmap_ops[i].dev_bus_addr = map->map_ops[i].dev_bus_addr;
+
+		if (use_ptemod) {
+			if (map->kmap_ops[i].status == GNTST_okay)
+				map->kunmap_ops[i].handle = map->kmap_ops[i].handle;
+			else if (!err)
+				err = -EINVAL;
+		}
 	}
 	return err;
 }
@@ -378,10 +389,8 @@
 		}
 		range = 0;
 		while (range < pages) {
-			if (map->unmap_ops[offset+range].handle == -1) {
-				range--;
+			if (map->unmap_ops[offset+range].handle == -1)
 				break;
-			}
 			range++;
 		}
 		err = __unmap_grant_pages(map, offset, range);
@@ -804,7 +813,7 @@
 
 	vma->vm_ops = &gntdev_vmops;
 
-	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_MIXEDMAP;
 
 	if (use_ptemod)
 		vma->vm_flags |= VM_DONTCOPY;
@@ -827,6 +836,7 @@
 	mutex_unlock(&priv->lock);
 
 	if (use_ptemod) {
+		map->pages_vm_start = vma->vm_start;
 		err = apply_to_page_range(vma->vm_mm, vma->vm_start,
 					  vma->vm_end - vma->vm_start,
 					  find_grant_ptes, map);
@@ -864,7 +874,6 @@
 					    set_grant_ptes_as_special, NULL);
 		}
 #endif
-		map->pages_vm_start = vma->vm_start;
 	}
 
 	return 0;
@@ -876,8 +885,10 @@
 out_unlock_put:
 	mutex_unlock(&priv->lock);
 out_put_map:
-	if (use_ptemod)
+	if (use_ptemod) {
 		map->vma = NULL;
+		unmap_grant_pages(map, 0, map->count);
+	}
 	gntdev_put_map(priv, map);
 	return err;
 }
--- linux-4.4.0.orig/drivers/xen/grant-table.c
+++ linux-4.4.0/drivers/xen/grant-table.c
@@ -121,6 +121,10 @@
 	 * by bit operations.
 	 */
 	int (*query_foreign_access)(grant_ref_t ref);
+	/*
+	 * Read the frame number related to a given grant reference.
+	 */
+	unsigned long (*read_frame)(grant_ref_t ref);
 };
 
 struct unmap_refs_callback_data {
@@ -296,6 +300,11 @@
 }
 EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
 
+static unsigned long gnttab_read_frame_v1(grant_ref_t ref)
+{
+	return gnttab_shared.v1[ref].frame;
+}
+
 struct deferred_entry {
 	struct list_head list;
 	grant_ref_t ref;
@@ -325,12 +334,9 @@
 		spin_unlock_irqrestore(&gnttab_list_lock, flags);
 		if (_gnttab_end_foreign_access_ref(entry->ref, entry->ro)) {
 			put_free_entry(entry->ref);
-			if (entry->page) {
-				pr_debug("freeing g.e. %#x (pfn %#lx)\n",
-					 entry->ref, page_to_pfn(entry->page));
-				__free_page(entry->page);
-			} else
-				pr_info("freeing g.e. %#x\n", entry->ref);
+			pr_debug("freeing g.e. %#x (pfn %#lx)\n",
+				 entry->ref, page_to_pfn(entry->page));
+			put_page(entry->page);
 			kfree(entry);
 			entry = NULL;
 		} else {
@@ -355,9 +361,18 @@
 static void gnttab_add_deferred(grant_ref_t ref, bool readonly,
 				struct page *page)
 {
-	struct deferred_entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	struct deferred_entry *entry;
+	gfp_t gfp = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
 	const char *what = KERN_WARNING "leaking";
 
+	entry = kmalloc(sizeof(*entry), gfp);
+	if (!page) {
+		unsigned long gfn = gnttab_interface->read_frame(ref);
+
+		page = pfn_to_page(gfn_to_pfn(gfn));
+		get_page(page);
+	}
+
 	if (entry) {
 		unsigned long flags;
 
@@ -378,13 +393,23 @@
 	       what, ref, page ? page_to_pfn(page) : -1);
 }
 
+int gnttab_try_end_foreign_access(grant_ref_t ref)
+{
+	int ret = _gnttab_end_foreign_access_ref(ref, 0);
+
+	if (ret)
+		put_free_entry(ref);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(gnttab_try_end_foreign_access);
+
 void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
 			       unsigned long page)
 {
-	if (gnttab_end_foreign_access_ref(ref, readonly)) {
-		put_free_entry(ref);
+	if (gnttab_try_end_foreign_access(ref)) {
 		if (page != 0)
-			free_page(page);
+			put_page(virt_to_page(page));
 	} else
 		gnttab_add_deferred(ref, readonly,
 				    page ? virt_to_page(page) : NULL);
@@ -1020,6 +1045,7 @@
 	.end_foreign_access_ref		= gnttab_end_foreign_access_ref_v1,
 	.end_foreign_transfer_ref	= gnttab_end_foreign_transfer_ref_v1,
 	.query_foreign_access		= gnttab_query_foreign_access_v1,
+	.read_frame			= gnttab_read_frame_v1,
 };
 
 static void gnttab_request_version(void)
--- linux-4.4.0.orig/drivers/xen/manage.c
+++ linux-4.4.0/drivers/xen/manage.c
@@ -275,8 +275,18 @@
 	err = xenbus_transaction_start(&xbt);
 	if (err)
 		return;
-	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
-		pr_err("Unable to read sysrq code in control/sysrq\n");
+	err = xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key);
+	if (err < 0) {
+		/*
+		 * The Xenstore watch fires directly after registering it and
+		 * after a suspend/resume cycle. So ENOENT is no error but
+		 * might happen in those cases. ERANGE is observed when we get
+		 * an empty value (''), this happens when we acknowledge the
+		 * request by writing '\0' below.
+		 */
+		if (err != -ENOENT && err != -ERANGE)
+			pr_err("Error %d reading sysrq code in control/sysrq\n",
+			       err);
 		xenbus_transaction_end(xbt, 1);
 		return;
 	}
--- linux-4.4.0.orig/drivers/xen/pci.c
+++ linux-4.4.0/drivers/xen/pci.c
@@ -29,6 +29,8 @@
 #include "../pci/pci.h"
 #ifdef CONFIG_PCI_MMCONFIG
 #include <asm/pci_x86.h>
+
+static int xen_mcfg_late(void);
 #endif
 
 static bool __read_mostly pci_seg_supported = true;
@@ -40,7 +42,18 @@
 #ifdef CONFIG_PCI_IOV
 	struct pci_dev *physfn = pci_dev->physfn;
 #endif
-
+#ifdef CONFIG_PCI_MMCONFIG
+	static bool pci_mcfg_reserved = false;
+	/*
+	 * Reserve MCFG areas in Xen on first invocation due to this being
+	 * potentially called from inside of acpi_init immediately after
+	 * MCFG table has been finally parsed.
+	 */
+	if (!pci_mcfg_reserved) {
+		xen_mcfg_late();
+		pci_mcfg_reserved = true;
+	}
+#endif
 	if (pci_seg_supported) {
 		struct {
 			struct physdev_pci_device_add add;
@@ -213,7 +226,7 @@
 arch_initcall(register_xen_pci_notifier);
 
 #ifdef CONFIG_PCI_MMCONFIG
-static int __init xen_mcfg_late(void)
+static int xen_mcfg_late(void)
 {
 	struct pci_mmcfg_region *cfg;
 	int rc;
@@ -252,8 +265,4 @@
 	}
 	return 0;
 }
-/*
- * Needs to be done after acpi_init which are subsys_initcall.
- */
-subsys_initcall_sync(xen_mcfg_late);
 #endif
--- linux-4.4.0.orig/drivers/xen/preempt.c
+++ linux-4.4.0/drivers/xen/preempt.c
@@ -31,13 +31,15 @@
 asmlinkage __visible void xen_maybe_preempt_hcall(void)
 {
 	if (unlikely(__this_cpu_read(xen_in_preemptible_hcall)
-		     && need_resched())) {
+		     && need_resched() && !preempt_count())) {
 		/*
 		 * Clear flag as we may be rescheduled on a different
 		 * cpu.
 		 */
 		__this_cpu_write(xen_in_preemptible_hcall, false);
-		_cond_resched();
+		local_irq_enable();
+		cond_resched();
+		local_irq_disable();
 		__this_cpu_write(xen_in_preemptible_hcall, true);
 	}
 }
--- linux-4.4.0.orig/drivers/xen/privcmd.c
+++ linux-4.4.0/drivers/xen/privcmd.c
@@ -335,8 +335,8 @@
 				st->global_error = 1;
 		}
 	}
-	st->va += PAGE_SIZE * nr;
-	st->index += nr;
+	st->va += XEN_PAGE_SIZE * nr;
+	st->index += nr / XEN_PFN_PER_PAGE;
 
 	return 0;
 }
--- linux-4.4.0.orig/drivers/xen/swiotlb-xen.c
+++ linux-4.4.0/drivers/xen/swiotlb-xen.c
@@ -310,6 +310,9 @@
 	*/
 	flags &= ~(__GFP_DMA | __GFP_HIGHMEM);
 
+	/* Convert the size to actually allocated. */
+	size = 1UL << (order + XEN_PAGE_SHIFT);
+
 	/* On ARM this function returns an ioremap'ped virtual address for
 	 * which virt_to_phys doesn't return the corresponding physical
 	 * address. In fact on ARM virt_to_phys only works for kernel direct
@@ -359,8 +362,11 @@
 	 * physical address */
 	phys = xen_bus_to_phys(dev_addr);
 
-	if (((dev_addr + size - 1 > dma_mask)) ||
-	    range_straddles_page_boundary(phys, size))
+	/* Convert the size to actually allocated. */
+	size = 1UL << (order + XEN_PAGE_SHIFT);
+
+	if (!WARN_ON((dev_addr + size - 1 > dma_mask) ||
+		     range_straddles_page_boundary(phys, size)))
 		xen_destroy_contiguous_region(phys, order);
 
 	xen_free_coherent_pages(hwdev, size, vaddr, (dma_addr_t)phys, attrs);
@@ -409,9 +415,9 @@
 	if (map == SWIOTLB_MAP_ERROR)
 		return DMA_ERROR_CODE;
 
+	dev_addr = xen_phys_to_bus(map);
 	xen_dma_map_page(dev, pfn_to_page(map >> PAGE_SHIFT),
 					dev_addr, map & ~PAGE_MASK, size, dir, attrs);
-	dev_addr = xen_phys_to_bus(map);
 
 	/*
 	 * Ensure that the address returned is DMA'ble
@@ -567,13 +573,14 @@
 				sg_dma_len(sgl) = 0;
 				return 0;
 			}
+			dev_addr = xen_phys_to_bus(map);
 			xen_dma_map_page(hwdev, pfn_to_page(map >> PAGE_SHIFT),
 						dev_addr,
 						map & ~PAGE_MASK,
 						sg->length,
 						dir,
 						attrs);
-			sg->dma_address = xen_phys_to_bus(map);
+			sg->dma_address = dev_addr;
 		} else {
 			/* we are not interested in the dma_addr returned by
 			 * xen_dma_map_page, only in the potential cache flushes executed
@@ -679,3 +686,22 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(xen_swiotlb_set_dma_mask);
+
+/*
+ * Create userspace mapping for the DMA-coherent memory.
+ * This function should be called with the pages from the current domain only,
+ * passing pages mapped from other domains would lead to memory corruption.
+ */
+int
+xen_swiotlb_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)
+{
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+	if (__generic_dma_ops(dev)->mmap)
+		return __generic_dma_ops(dev)->mmap(dev, vma, cpu_addr,
+						    dma_addr, size, attrs);
+#endif
+	return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_dma_mmap);
--- linux-4.4.0.orig/drivers/xen/xen-acpi-processor.c
+++ linux-4.4.0/drivers/xen/xen-acpi-processor.c
@@ -27,10 +27,10 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/syscore_ops.h>
 #include <linux/acpi.h>
 #include <acpi/processor.h>
 #include <xen/xen.h>
-#include <xen/xen-ops.h>
 #include <xen/interface/platform.h>
 #include <asm/xen/hypercall.h>
 
@@ -362,9 +362,9 @@
 	}
 	/* There are more ACPI Processor objects than in x2APIC or MADT.
 	 * This can happen with incorrect ACPI SSDT declerations. */
-	if (acpi_id > nr_acpi_bits) {
-		pr_debug("We only have %u, trying to set %u\n",
-			 nr_acpi_bits, acpi_id);
+	if (acpi_id >= nr_acpi_bits) {
+		pr_debug("max acpi id %u, trying to set %u\n",
+			 nr_acpi_bits - 1, acpi_id);
 		return AE_OK;
 	}
 	/* OK, There is a ACPI Processor object */
@@ -423,36 +423,7 @@
 
 	return 0;
 }
-static int __init check_prereq(void)
-{
-	struct cpuinfo_x86 *c = &cpu_data(0);
-
-	if (!xen_initial_domain())
-		return -ENODEV;
-
-	if (!acpi_gbl_FADT.smi_command)
-		return -ENODEV;
 
-	if (c->x86_vendor == X86_VENDOR_INTEL) {
-		if (!cpu_has(c, X86_FEATURE_EST))
-			return -ENODEV;
-
-		return 0;
-	}
-	if (c->x86_vendor == X86_VENDOR_AMD) {
-		/* Copied from powernow-k8.h, can't include ../cpufreq/powernow
-		 * as we get compile warnings for the static functions.
-		 */
-#define CPUID_FREQ_VOLT_CAPABILITIES    0x80000007
-#define USE_HW_PSTATE                   0x00000080
-		u32 eax, ebx, ecx, edx;
-		cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
-		if ((edx & USE_HW_PSTATE) != USE_HW_PSTATE)
-			return -ENODEV;
-		return 0;
-	}
-	return -ENODEV;
-}
 /* acpi_perf_data is a pointer to percpu data. */
 static struct acpi_processor_performance __percpu *acpi_perf_data;
 
@@ -495,24 +466,42 @@
 	return rc;
 }
 
-static int xen_acpi_processor_resume(struct notifier_block *nb,
-				     unsigned long action, void *data)
+static void xen_acpi_processor_resume_worker(struct work_struct *dummy)
 {
+	int rc;
+
 	bitmap_zero(acpi_ids_done, nr_acpi_bits);
-	return xen_upload_processor_pm_data();
+
+	rc = xen_upload_processor_pm_data();
+	if (rc != 0)
+		pr_info("ACPI data upload failed, error = %d\n", rc);
 }
 
-struct notifier_block xen_acpi_processor_resume_nb = {
-	.notifier_call = xen_acpi_processor_resume,
+static void xen_acpi_processor_resume(void)
+{
+	static DECLARE_WORK(wq, xen_acpi_processor_resume_worker);
+
+	/*
+	 * xen_upload_processor_pm_data() calls non-atomic code.
+	 * However, the context for xen_acpi_processor_resume is syscore
+	 * with only the boot CPU online and in an atomic context.
+	 *
+	 * So defer the upload for some point safer.
+	 */
+	schedule_work(&wq);
+}
+
+static struct syscore_ops xap_syscore_ops = {
+	.resume	= xen_acpi_processor_resume,
 };
 
 static int __init xen_acpi_processor_init(void)
 {
 	unsigned int i;
-	int rc = check_prereq();
+	int rc;
 
-	if (rc)
-		return rc;
+	if (!xen_initial_domain())
+		return -ENODEV;
 
 	nr_acpi_bits = get_max_acpi_id() + 1;
 	acpi_ids_done = kcalloc(BITS_TO_LONGS(nr_acpi_bits), sizeof(unsigned long), GFP_KERNEL);
@@ -556,7 +545,7 @@
 	if (rc)
 		goto err_unregister;
 
-	xen_resume_notifier_register(&xen_acpi_processor_resume_nb);
+	register_syscore_ops(&xap_syscore_ops);
 
 	return 0;
 err_unregister:
@@ -573,7 +562,7 @@
 {
 	int i;
 
-	xen_resume_notifier_unregister(&xen_acpi_processor_resume_nb);
+	unregister_syscore_ops(&xap_syscore_ops);
 	kfree(acpi_ids_done);
 	kfree(acpi_id_present);
 	kfree(acpi_id_cst_present);
--- linux-4.4.0.orig/drivers/xen/xen-pciback/conf_space.c
+++ linux-4.4.0/drivers/xen/xen-pciback/conf_space.c
@@ -183,8 +183,7 @@
 		field_start = OFFSET(cfg_entry);
 		field_end = OFFSET(cfg_entry) + field->size;
 
-		if ((req_start >= field_start && req_start < field_end)
-		    || (req_end > field_start && req_end <= field_end)) {
+		 if (req_end > field_start && field_end > req_start) {
 			err = conf_space_read(dev, cfg_entry, field_start,
 					      &tmp_val);
 			if (err)
@@ -230,8 +229,7 @@
 		field_start = OFFSET(cfg_entry);
 		field_end = OFFSET(cfg_entry) + field->size;
 
-		if ((req_start >= field_start && req_start < field_end)
-		    || (req_end > field_start && req_end <= field_end)) {
+		 if (req_end > field_start && field_end > req_start) {
 			tmp_val = 0;
 
 			err = xen_pcibk_config_read(dev, field_start,
--- linux-4.4.0.orig/drivers/xen/xen-pciback/conf_space_capability.c
+++ linux-4.4.0/drivers/xen/xen-pciback/conf_space_capability.c
@@ -115,13 +115,12 @@
 {
 	int err;
 	u16 old_value;
-	pci_power_t new_state, old_state;
+	pci_power_t new_state;
 
 	err = pci_read_config_word(dev, offset, &old_value);
 	if (err)
 		goto out;
 
-	old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK);
 	new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
 
 	new_value &= PM_OK_BITS;
--- linux-4.4.0.orig/drivers/xen/xen-pciback/pci_stub.c
+++ linux-4.4.0/drivers/xen/xen-pciback/pci_stub.c
@@ -104,7 +104,8 @@
 	 * is called from "unbind" which takes a device_lock mutex.
 	 */
 	__pci_reset_function_locked(dev);
-	if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
+	if (dev_data &&
+	    pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
 		dev_info(&dev->dev, "Could not reload PCI state\n");
 	else
 		pci_restore_state(dev);
@@ -680,10 +681,17 @@
 	wmb();
 	notify_remote_via_irq(pdev->evtchn_irq);
 
+	/* Enable IRQ to signal "request done". */
+	xen_pcibk_lateeoi(pdev, 0);
+
 	ret = wait_event_timeout(xen_pcibk_aer_wait_queue,
 				 !(test_bit(_XEN_PCIB_active, (unsigned long *)
 				 &sh_info->flags)), 300*HZ);
 
+	/* Enable IRQ for pcifront request if not already active. */
+	if (!test_bit(_PDEVF_op_active, &pdev->flags))
+		xen_pcibk_lateeoi(pdev, 0);
+
 	if (!ret) {
 		if (test_bit(_XEN_PCIB_active,
 			(unsigned long *)&sh_info->flags)) {
@@ -697,13 +705,6 @@
 	}
 	clear_bit(_PCIB_op_pending, (unsigned long *)&pdev->flags);
 
-	if (test_bit(_XEN_PCIF_active,
-		(unsigned long *)&sh_info->flags)) {
-		dev_dbg(&psdev->dev->dev,
-			"schedule pci_conf service in " DRV_NAME "\n");
-		xen_pcibk_test_and_schedule_op(psdev->pdev);
-	}
-
 	res = (pci_ers_result_t)aer_op->err;
 	return res;
 }
--- linux-4.4.0.orig/drivers/xen/xen-pciback/pciback.h
+++ linux-4.4.0/drivers/xen/xen-pciback/pciback.h
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/atomic.h>
+#include <xen/events.h>
 #include <xen/interface/io/pciif.h>
 
 #define DRV_NAME	"xen-pciback"
@@ -26,6 +27,8 @@
 #define PDEVF_op_active		(1<<(_PDEVF_op_active))
 #define _PCIB_op_pending	(1)
 #define PCIB_op_pending		(1<<(_PCIB_op_pending))
+#define _EOI_pending		(2)
+#define EOI_pending		(1<<(_EOI_pending))
 
 struct xen_pcibk_device {
 	void *pci_dev_data;
@@ -182,12 +185,17 @@
 irqreturn_t xen_pcibk_handle_event(int irq, void *dev_id);
 void xen_pcibk_do_op(struct work_struct *data);
 
+static inline void xen_pcibk_lateeoi(struct xen_pcibk_device *pdev,
+				     unsigned int eoi_flag)
+{
+	if (test_and_clear_bit(_EOI_pending, &pdev->flags))
+		xen_irq_lateeoi(pdev->evtchn_irq, eoi_flag);
+}
+
 int xen_pcibk_xenbus_register(void);
 void xen_pcibk_xenbus_unregister(void);
 
 extern int verbose_request;
-
-void xen_pcibk_test_and_schedule_op(struct xen_pcibk_device *pdev);
 #endif
 
 /* Handles shared IRQs that can to device domain and control domain. */
--- linux-4.4.0.orig/drivers/xen/xen-pciback/pciback_ops.c
+++ linux-4.4.0/drivers/xen/xen-pciback/pciback_ops.c
@@ -126,8 +126,6 @@
 		if (pci_is_enabled(dev))
 			pci_disable_device(dev);
 
-		pci_write_config_word(dev, PCI_COMMAND, 0);
-
 		dev->is_busmaster = 0;
 	} else {
 		pci_read_config_word(dev, PCI_COMMAND, &cmd);
@@ -227,8 +225,9 @@
 	/*
 	 * PCI_COMMAND_MEMORY must be enabled, otherwise we may not be able
 	 * to access the BARs where the MSI-X entries reside.
+	 * But VF devices are unique in which the PF needs to be checked.
 	 */
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	pci_read_config_word(pci_physfn(dev), PCI_COMMAND, &cmd);
 	if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY))
 		return -ENXIO;
 
@@ -297,26 +296,41 @@
 	return 0;
 }
 #endif
+
+static inline bool xen_pcibk_test_op_pending(struct xen_pcibk_device *pdev)
+{
+	return test_bit(_XEN_PCIF_active,
+			(unsigned long *)&pdev->sh_info->flags) &&
+	       !test_and_set_bit(_PDEVF_op_active, &pdev->flags);
+}
+
 /*
 * Now the same evtchn is used for both pcifront conf_read_write request
 * as well as pcie aer front end ack. We use a new work_queue to schedule
 * xen_pcibk conf_read_write service for avoiding confict with aer_core
 * do_recovery job which also use the system default work_queue
 */
-void xen_pcibk_test_and_schedule_op(struct xen_pcibk_device *pdev)
+static void xen_pcibk_test_and_schedule_op(struct xen_pcibk_device *pdev)
 {
+	bool eoi = true;
+
 	/* Check that frontend is requesting an operation and that we are not
 	 * already processing a request */
-	if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)
-	    && !test_and_set_bit(_PDEVF_op_active, &pdev->flags)) {
+	if (xen_pcibk_test_op_pending(pdev)) {
 		queue_work(xen_pcibk_wq, &pdev->op_work);
+		eoi = false;
 	}
 	/*_XEN_PCIB_active should have been cleared by pcifront. And also make
 	sure xen_pcibk is waiting for ack by checking _PCIB_op_pending*/
 	if (!test_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags)
 	    && test_bit(_PCIB_op_pending, &pdev->flags)) {
 		wake_up(&xen_pcibk_aer_wait_queue);
+		eoi = false;
 	}
+
+	/* EOI if there was nothing to do. */
+	if (eoi)
+		xen_pcibk_lateeoi(pdev, XEN_EOI_FLAG_SPURIOUS);
 }
 
 /* Performing the configuration space reads/writes must not be done in atomic
@@ -324,14 +338,15 @@
  * use of semaphores). This function is intended to be called from a work
  * queue in process context taking a struct xen_pcibk_device as a parameter */
 
-void xen_pcibk_do_op(struct work_struct *data)
+static void xen_pcibk_do_one_op(struct xen_pcibk_device *pdev)
 {
-	struct xen_pcibk_device *pdev =
-		container_of(data, struct xen_pcibk_device, op_work);
 	struct pci_dev *dev;
 	struct xen_pcibk_dev_data *dev_data = NULL;
 	struct xen_pci_op *op = &pdev->op;
 	int test_intx = 0;
+#ifdef CONFIG_PCI_MSI
+	unsigned int nr = 0;
+#endif
 
 	*op = pdev->sh_info->op;
 	barrier();
@@ -360,6 +375,7 @@
 			op->err = xen_pcibk_disable_msi(pdev, dev, op);
 			break;
 		case XEN_PCI_OP_enable_msix:
+			nr = op->value;
 			op->err = xen_pcibk_enable_msix(pdev, dev, op);
 			break;
 		case XEN_PCI_OP_disable_msix:
@@ -382,7 +398,7 @@
 	if (op->cmd == XEN_PCI_OP_enable_msix && op->err == 0) {
 		unsigned int i;
 
-		for (i = 0; i < op->value; i++)
+		for (i = 0; i < nr; i++)
 			pdev->sh_info->op.msix_entries[i].vector =
 				op->msix_entries[i].vector;
 	}
@@ -396,16 +412,31 @@
 	smp_mb__before_atomic(); /* /after/ clearing PCIF_active */
 	clear_bit(_PDEVF_op_active, &pdev->flags);
 	smp_mb__after_atomic(); /* /before/ final check for work */
+}
 
-	/* Check to see if the driver domain tried to start another request in
-	 * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active.
-	*/
-	xen_pcibk_test_and_schedule_op(pdev);
+void xen_pcibk_do_op(struct work_struct *data)
+{
+	struct xen_pcibk_device *pdev =
+		container_of(data, struct xen_pcibk_device, op_work);
+
+	do {
+		xen_pcibk_do_one_op(pdev);
+	} while (xen_pcibk_test_op_pending(pdev));
+
+	xen_pcibk_lateeoi(pdev, 0);
 }
 
 irqreturn_t xen_pcibk_handle_event(int irq, void *dev_id)
 {
 	struct xen_pcibk_device *pdev = dev_id;
+	bool eoi;
+
+	/* IRQs might come in before pdev->evtchn_irq is written. */
+	if (unlikely(pdev->evtchn_irq != irq))
+		pdev->evtchn_irq = irq;
+
+	eoi = test_and_set_bit(_EOI_pending, &pdev->flags);
+	WARN(eoi, "IRQ while EOI pending\n");
 
 	xen_pcibk_test_and_schedule_op(pdev);
 
--- linux-4.4.0.orig/drivers/xen/xen-pciback/xenbus.c
+++ linux-4.4.0/drivers/xen/xen-pciback/xenbus.c
@@ -124,7 +124,7 @@
 
 	pdev->sh_info = vaddr;
 
-	err = bind_interdomain_evtchn_to_irqhandler(
+	err = bind_interdomain_evtchn_to_irqhandler_lateeoi(
 		pdev->xdev->otherend_id, remote_evtchn, xen_pcibk_handle_event,
 		0, DRV_NAME, pdev);
 	if (err < 0) {
@@ -691,7 +691,7 @@
 
 	/* watch the backend node for backend configuration information */
 	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
-				xen_pcibk_be_watch);
+				NULL, xen_pcibk_be_watch);
 	if (err)
 		goto out;
 
--- linux-4.4.0.orig/drivers/xen/xen-scsiback.c
+++ linux-4.4.0/drivers/xen/xen-scsiback.c
@@ -91,7 +91,6 @@
 	unsigned int irq;
 
 	struct vscsiif_back_ring ring;
-	int ring_error;
 
 	spinlock_t ring_lock;
 	atomic_t nr_unreplied_reqs;
@@ -416,12 +415,12 @@
 		return 0;
 
 	err = gnttab_map_refs(map, NULL, pg, cnt);
-	BUG_ON(err);
 	for (i = 0; i < cnt; i++) {
 		if (unlikely(map[i].status != GNTST_okay)) {
 			pr_err("invalid buffer -- could not remap it\n");
 			map[i].handle = SCSIBACK_INVALID_HANDLE;
-			err = -ENOMEM;
+			if (!err)
+				err = -ENOMEM;
 		} else {
 			get_page(pg[i]);
 		}
@@ -698,7 +697,8 @@
 	return 0;
 }
 
-static int scsiback_do_cmd_fn(struct vscsibk_info *info)
+static int scsiback_do_cmd_fn(struct vscsibk_info *info,
+			      unsigned int *eoi_flags)
 {
 	struct vscsiif_back_ring *ring = &info->ring;
 	struct vscsiif_request ring_req;
@@ -715,11 +715,12 @@
 		rc = ring->rsp_prod_pvt;
 		pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n",
 			   info->domid, rp, rc, rp - rc);
-		info->ring_error = 1;
-		return 0;
+		return -EINVAL;
 	}
 
 	while ((rc != rp)) {
+		*eoi_flags &= ~XEN_EOI_FLAG_SPURIOUS;
+
 		if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
 			break;
 		pending_req = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
@@ -782,13 +783,16 @@
 static irqreturn_t scsiback_irq_fn(int irq, void *dev_id)
 {
 	struct vscsibk_info *info = dev_id;
+	int rc;
+	unsigned int eoi_flags = XEN_EOI_FLAG_SPURIOUS;
 
-	if (info->ring_error)
-		return IRQ_HANDLED;
-
-	while (scsiback_do_cmd_fn(info))
+	while ((rc = scsiback_do_cmd_fn(info, &eoi_flags)) > 0)
 		cond_resched();
 
+	/* In case of a ring error we keep the event channel masked. */
+	if (!rc)
+		xen_irq_lateeoi(irq, eoi_flags);
+
 	return IRQ_HANDLED;
 }
 
@@ -809,7 +813,7 @@
 	sring = (struct vscsiif_sring *)area;
 	BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
 
-	err = bind_interdomain_evtchn_to_irq(info->domid, evtchn);
+	err = bind_interdomain_evtchn_to_irq_lateeoi(info->domid, evtchn);
 	if (err < 0)
 		goto unmap_page;
 
@@ -939,12 +943,12 @@
 	spin_unlock_irqrestore(&info->v2p_lock, flags);
 
 out_free:
-	mutex_lock(&tpg->tv_tpg_mutex);
-	tpg->tv_tpg_fe_count--;
-	mutex_unlock(&tpg->tv_tpg_mutex);
-
-	if (err)
+	if (err) {
+		mutex_lock(&tpg->tv_tpg_mutex);
+		tpg->tv_tpg_fe_count--;
+		mutex_unlock(&tpg->tv_tpg_mutex);
 		kfree(new);
+	}
 
 	return err;
 }
@@ -1210,7 +1214,6 @@
 
 	info->domid = dev->otherend_id;
 	spin_lock_init(&info->ring_lock);
-	info->ring_error = 0;
 	atomic_set(&info->nr_unreplied_reqs, 0);
 	init_waitqueue_head(&info->waiting_to_free);
 	info->dev = dev;
--- linux-4.4.0.orig/drivers/xen/xenbus/xenbus_client.c
+++ linux-4.4.0/drivers/xen/xenbus/xenbus_client.c
@@ -114,18 +114,22 @@
  */
 int xenbus_watch_path(struct xenbus_device *dev, const char *path,
 		      struct xenbus_watch *watch,
+		      bool (*will_handle)(struct xenbus_watch *,
+					  const char **, unsigned int),
 		      void (*callback)(struct xenbus_watch *,
 				       const char **, unsigned int))
 {
 	int err;
 
 	watch->node = path;
+	watch->will_handle = will_handle;
 	watch->callback = callback;
 
 	err = register_xenbus_watch(watch);
 
 	if (err) {
 		watch->node = NULL;
+		watch->will_handle = NULL;
 		watch->callback = NULL;
 		xenbus_dev_fatal(dev, err, "adding watch on %s", path);
 	}
@@ -152,6 +156,8 @@
  */
 int xenbus_watch_pathfmt(struct xenbus_device *dev,
 			 struct xenbus_watch *watch,
+			 bool (*will_handle)(struct xenbus_watch *,
+					     const char **, unsigned int),
 			 void (*callback)(struct xenbus_watch *,
 					const char **, unsigned int),
 			 const char *pathfmt, ...)
@@ -168,7 +174,7 @@
 		xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
 		return -ENOMEM;
 	}
-	err = xenbus_watch_path(dev, path, watch, callback);
+	err = xenbus_watch_path(dev, path, watch, will_handle, callback);
 
 	if (err)
 		kfree(path);
@@ -384,8 +390,14 @@
 	int i, j;
 
 	for (i = 0; i < nr_pages; i++) {
-		err = gnttab_grant_foreign_access(dev->otherend_id,
-						  virt_to_gfn(vaddr), 0);
+		unsigned long gfn;
+
+		if (is_vmalloc_addr(vaddr))
+			gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr));
+		else
+			gfn = virt_to_gfn(vaddr);
+
+		err = gnttab_grant_foreign_access(dev->otherend_id, gfn, 0);
 		if (err < 0) {
 			xenbus_dev_fatal(dev, err,
 					 "granting access to ring page");
@@ -469,7 +481,14 @@
 int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
 			   unsigned int nr_grefs, void **vaddr)
 {
-	return ring_ops->map(dev, gnt_refs, nr_grefs, vaddr);
+	int err;
+
+	err = ring_ops->map(dev, gnt_refs, nr_grefs, vaddr);
+	/* Some hypervisors are buggy and can return 1. */
+	if (err > 0)
+		err = GNTST_general_error;
+
+	return err;
 }
 EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
 
--- linux-4.4.0.orig/drivers/xen/xenbus/xenbus_dev_frontend.c
+++ linux-4.4.0/drivers/xen/xenbus/xenbus_dev_frontend.c
@@ -316,11 +316,18 @@
 			rc = -ENOMEM;
 			goto out;
 		}
+	} else if (u->u.msg.tx_id != 0) {
+		list_for_each_entry(trans, &u->transactions, list)
+			if (trans->handle.id == u->u.msg.tx_id)
+				break;
+		if (&trans->list == &u->transactions)
+			return -ESRCH;
 	}
 
 	reply = xenbus_dev_request_and_reply(&u->u.msg);
 	if (IS_ERR(reply)) {
-		kfree(trans);
+		if (msg_type == XS_TRANSACTION_START)
+			kfree(trans);
 		rc = PTR_ERR(reply);
 		goto out;
 	}
@@ -333,12 +340,7 @@
 			list_add(&trans->list, &u->transactions);
 		}
 	} else if (u->u.msg.type == XS_TRANSACTION_END) {
-		list_for_each_entry(trans, &u->transactions, list)
-			if (trans->handle.id == u->u.msg.tx_id)
-				break;
-		BUG_ON(&trans->list == &u->transactions);
 		list_del(&trans->list);
-
 		kfree(trans);
 	}
 
@@ -534,7 +536,7 @@
 	if (xen_store_evtchn == 0)
 		return -ENOENT;
 
-	nonseekable_open(inode, filp);
+	stream_open(inode, filp);
 
 	u = kzalloc(sizeof(*u), GFP_KERNEL);
 	if (u == NULL)
--- linux-4.4.0.orig/drivers/xen/xenbus/xenbus_probe.c
+++ linux-4.4.0/drivers/xen/xenbus/xenbus_probe.c
@@ -137,6 +137,7 @@
 		container_of(dev->dev.bus, struct xen_bus_type, bus);
 
 	return xenbus_watch_pathfmt(dev, &dev->otherend_watch,
+				    bus->otherend_will_handle,
 				    bus->otherend_changed,
 				    "%s/%s", dev->otherend, "state");
 }
@@ -470,8 +471,11 @@
 
 	/* Register with generic device framework. */
 	err = device_register(&xendev->dev);
-	if (err)
+	if (err) {
+		put_device(&xendev->dev);
+		xendev = NULL;
 		goto fail;
+	}
 
 	return 0;
 fail:
@@ -826,7 +830,7 @@
 	 * Create xenfs mountpoint in /proc for compatibility with
 	 * utilities that expect to find "xenbus" under "/proc/xen".
 	 */
-	proc_mkdir("xen", NULL);
+	proc_create_mount_point("xen");
 #endif
 
 out_error:
--- linux-4.4.0.orig/drivers/xen/xenbus/xenbus_probe.h
+++ linux-4.4.0/drivers/xen/xenbus/xenbus_probe.h
@@ -42,6 +42,8 @@
 	int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename);
 	int (*probe)(struct xen_bus_type *bus, const char *type,
 		     const char *dir);
+	bool (*otherend_will_handle)(struct xenbus_watch *watch,
+				     const char **vec, unsigned int len);
 	void (*otherend_changed)(struct xenbus_watch *watch, const char **vec,
 				 unsigned int len);
 	struct bus_type bus;
--- linux-4.4.0.orig/drivers/xen/xenbus/xenbus_probe_backend.c
+++ linux-4.4.0/drivers/xen/xenbus/xenbus_probe_backend.c
@@ -181,6 +181,12 @@
 	return err;
 }
 
+static bool frontend_will_handle(struct xenbus_watch *watch,
+				 const char **vec, unsigned int len)
+{
+	return watch->nr_pending == 0;
+}
+
 static void frontend_changed(struct xenbus_watch *watch,
 			    const char **vec, unsigned int len)
 {
@@ -192,6 +198,7 @@
 	.levels = 3,		/* backend/type/<frontend>/<id> */
 	.get_bus_id = backend_bus_id,
 	.probe = xenbus_probe_backend,
+	.otherend_will_handle = frontend_will_handle,
 	.otherend_changed = frontend_changed,
 	.bus = {
 		.name		= "xen-backend",
--- linux-4.4.0.orig/drivers/xen/xenbus/xenbus_xs.c
+++ linux-4.4.0/drivers/xen/xenbus/xenbus_xs.c
@@ -250,9 +250,6 @@
 
 	mutex_unlock(&xs_state.request_mutex);
 
-	if (IS_ERR(ret))
-		return ret;
-
 	if ((msg->type == XS_TRANSACTION_END) ||
 	    ((req_msg.type == XS_TRANSACTION_START) &&
 	     (msg->type == XS_ERROR)))
@@ -704,6 +701,8 @@
 
 	sprintf(token, "%lX", (long)watch);
 
+	watch->nr_pending = 0;
+
 	down_read(&xs_state.watch_mutex);
 
 	spin_lock(&watches_lock);
@@ -753,12 +752,15 @@
 
 	/* Cancel pending watch events. */
 	spin_lock(&watch_events_lock);
-	list_for_each_entry_safe(msg, tmp, &watch_events, list) {
-		if (msg->u.watch.handle != watch)
-			continue;
-		list_del(&msg->list);
-		kfree(msg->u.watch.vec);
-		kfree(msg);
+	if (watch->nr_pending) {
+		list_for_each_entry_safe(msg, tmp, &watch_events, list) {
+			if (msg->u.watch.handle != watch)
+				continue;
+			list_del(&msg->list);
+			kfree(msg->u.watch.vec);
+			kfree(msg);
+		}
+		watch->nr_pending = 0;
 	}
 	spin_unlock(&watch_events_lock);
 
@@ -805,7 +807,6 @@
 
 static int xenwatch_thread(void *unused)
 {
-	struct list_head *ent;
 	struct xs_stored_msg *msg;
 
 	for (;;) {
@@ -818,13 +819,15 @@
 		mutex_lock(&xenwatch_mutex);
 
 		spin_lock(&watch_events_lock);
-		ent = watch_events.next;
-		if (ent != &watch_events)
-			list_del(ent);
+		msg = list_first_entry_or_null(&watch_events,
+				struct xs_stored_msg, list);
+		if (msg) {
+			list_del(&msg->list);
+			msg->u.watch.handle->nr_pending--;
+		}
 		spin_unlock(&watch_events_lock);
 
-		if (ent != &watch_events) {
-			msg = list_entry(ent, struct xs_stored_msg, list);
+		if (msg) {
 			msg->u.watch.handle->callback(
 				msg->u.watch.handle,
 				(const char **)msg->u.watch.vec,
@@ -906,9 +909,15 @@
 		spin_lock(&watches_lock);
 		msg->u.watch.handle = find_watch(
 			msg->u.watch.vec[XS_WATCH_TOKEN]);
-		if (msg->u.watch.handle != NULL) {
+		if (msg->u.watch.handle != NULL &&
+				(!msg->u.watch.handle->will_handle ||
+				 msg->u.watch.handle->will_handle(
+					 msg->u.watch.handle,
+					 (const char **)msg->u.watch.vec,
+					 msg->u.watch.vec_size))) {
 			spin_lock(&watch_events_lock);
 			list_add_tail(&msg->list, &watch_events);
+			msg->u.watch.handle->nr_pending++;
 			wake_up(&watch_events_waitq);
 			spin_unlock(&watch_events_lock);
 		} else {
--- linux-4.4.0.orig/drivers/xen/xlate_mmu.c
+++ linux-4.4.0/drivers/xen/xlate_mmu.c
@@ -34,6 +34,7 @@
 #include <asm/xen/hypervisor.h>
 
 #include <xen/xen.h>
+#include <xen/xen-ops.h>
 #include <xen/page.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/memory.h>
--- linux-4.4.0.orig/drivers/zorro/zorro.c
+++ linux-4.4.0/drivers/zorro/zorro.c
@@ -16,6 +16,7 @@
 #include <linux/bitops.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 
 #include <asm/byteorder.h>
@@ -185,6 +186,17 @@
 		z->dev.parent = &bus->dev;
 		z->dev.bus = &zorro_bus_type;
 		z->dev.id = i;
+		switch (z->rom.er_Type & ERT_TYPEMASK) {
+		case ERT_ZORROIII:
+			z->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+			break;
+
+		case ERT_ZORROII:
+		default:
+			z->dev.coherent_dma_mask = DMA_BIT_MASK(24);
+			break;
+		}
+		z->dev.dma_mask = &z->dev.coherent_dma_mask;
 	}
 
 	/* ... then register them */
--- linux-4.4.0.orig/dropped.txt
+++ linux-4.4.0/dropped.txt
@@ -0,0 +1,11 @@
+UBUNTU: SAUCE: (no-up) dell-wmi: Demote unknown WMI event message to pr_debug
+UBUNTU: SAUCE: (no-up) arm64: dts: Add X-Gene reboot driver dts node
+UBUNTU: SAUCE: (no-up) Add documentation for generic SYSCON reboot driver.
+UBUNTU: SAUCE: fix perf_regs definitions for arm64
+UBUNTU: SAUCE: aufs3 -- (no-up) aufs3-mmap.patch
+Revert "UBUNTU: SAUCE: aufs3 -- (no-up) aufs3-mmap.patch"
+UBUNTU: SAUCE: aufs3 -- (no-up) aufs3-mmap.patch
+UBUNTU: SAUCE: aufs3 -- avoid aufs3-mmap.patch include hell for arm64
+UBUNTU: SAUCE: (no-up) irqchip:gic: change access of gicc_ctrl register to read modify write.
+UBUNTU: SAUCE: (no-up) PCI: Increase BAR size quirk for IBM ipr SAS Crocodile adapters
+
--- linux-4.4.0.orig/firmware/Makefile
+++ linux-4.4.0/firmware/Makefile
@@ -20,80 +20,32 @@
 # accurate. In the latter case it doesn't matter -- it'll use $(fw-shipped-all).
 # But be aware that the config file might not be included at all.
 
-ifdef CONFIG_ACENIC_OMIT_TIGON_I
-acenic-objs := acenic/tg2.bin
-fw-shipped- += acenic/tg1.bin
-else
-acenic-objs := acenic/tg1.bin acenic/tg2.bin
-endif
-fw-shipped-$(CONFIG_ACENIC) += $(acenic-objs)
-fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \
-					 adaptec/starfire_tx.bin
-fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin
-fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw
-fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-6.2.9.0.fw \
-			      bnx2x/bnx2x-e1h-6.2.9.0.fw \
-			      bnx2x/bnx2x-e2-6.2.9.0.fw
-fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1a.fw \
-			     bnx2/bnx2-rv2p-09-6.0.17.fw \
-			     bnx2/bnx2-rv2p-09ax-6.0.17.fw \
-			     bnx2/bnx2-mips-06-6.2.1.fw \
-			     bnx2/bnx2-rv2p-06-6.0.15.fw
-fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
-fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
-				   cxgb3/t3c_psram-1.1.0.bin \
-				   cxgb3/ael2005_opt_edc.bin \
-				   cxgb3/ael2005_twx_edc.bin \
-				   cxgb3/ael2020_twx_edc.bin
-fw-shipped-$(CONFIG_DRM_MGA) += matrox/g200_warp.fw matrox/g400_warp.fw
-fw-shipped-$(CONFIG_DRM_R128) += r128/r128_cce.bin
-fw-shipped-$(CONFIG_DRM_RADEON) += radeon/R100_cp.bin radeon/R200_cp.bin \
-				   radeon/R300_cp.bin radeon/R420_cp.bin \
-				   radeon/RS690_cp.bin radeon/RS600_cp.bin \
-				   radeon/R520_cp.bin \
-				   radeon/R600_pfp.bin radeon/R600_me.bin \
-				   radeon/RV610_pfp.bin radeon/RV610_me.bin \
-				   radeon/RV630_pfp.bin radeon/RV630_me.bin \
-				   radeon/RV620_pfp.bin radeon/RV620_me.bin \
-				   radeon/RV635_pfp.bin radeon/RV635_me.bin \
-				   radeon/RV670_pfp.bin radeon/RV670_me.bin \
-				   radeon/RS780_pfp.bin radeon/RS780_me.bin \
-				   radeon/RV770_pfp.bin radeon/RV770_me.bin \
-				   radeon/RV730_pfp.bin radeon/RV730_me.bin \
-				   radeon/RV710_pfp.bin radeon/RV710_me.bin
-fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin
-fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
+fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-7.12.30.0.fw \
+			      bnx2x/bnx2x-e1h-7.12.30.0.fw \
+			      bnx2x/bnx2x-e2-7.12.30.0.fw
+fw-shipped-$(CONFIG_BNX2) += 	bnx2/bnx2-mips-09-6.2.1b.fw \
+				bnx2/bnx2-rv2p-06-6.0.15.fw \
+				bnx2/bnx2-mips-06-6.2.3.fw \
+				bnx2/bnx2-rv2p-09-6.0.17.fw \
+				bnx2/bnx2-rv2p-09ax-6.0.17.fw
 fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
 			     e100/d102e_ucode.bin
-fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin
-fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis cis/PCMLM28.cis \
-				     cis/DP83903.cis cis/NE2K.cis \
-				     cis/tamarack.cis cis/PE-200.cis \
-				     cis/PE520.cis
-fw-shipped-$(CONFIG_PCMCIA_3C589) += cis/3CXEM556.cis
-fw-shipped-$(CONFIG_PCMCIA_3C574) += cis/3CCFEM556.cis
-fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \
-				       cis/COMpad2.cis cis/COMpad4.cis \
-				       cis/SW_555_SER.cis cis/SW_7xx_SER.cis \
-				       cis/SW_8xx_SER.cis
-fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin
-fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \
-				      advansys/3550.bin advansys/38C0800.bin
+fw-shipped-$(CONFIG_PCMCIA_PCNET) += 
+				     
+fw-shipped-$(CONFIG_PCMCIA_3C589) += 
+fw-shipped-$(CONFIG_PCMCIA_3C574) += 
+fw-shipped-$(CONFIG_SERIAL_8250_CS) +=
+				       
 fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \
 					 qlogic/12160.bin
 fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin
 fw-shipped-$(CONFIG_INFINIBAND_QIB) += qlogic/sd7220.fw
 fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp
-fw-shipped-$(CONFIG_SND_MAESTRO3) += ess/maestro3_assp_kernel.fw \
-				     ess/maestro3_assp_minisrc.fw
 fw-shipped-$(CONFIG_SND_SB16_CSP) += sb16/mulaw_main.csp sb16/alaw_main.csp \
 				     sb16/ima_adpcm_init.csp \
 				     sb16/ima_adpcm_playback.csp \
 				     sb16/ima_adpcm_capture.csp
-fw-shipped-$(CONFIG_SND_YMFPCI) += yamaha/ds1_ctrl.fw yamaha/ds1_dsp.fw \
-				   yamaha/ds1e_ctrl.fw
 fw-shipped-$(CONFIG_SND_WAVEFRONT) += yamaha/yss225_registers.bin
-fw-shipped-$(CONFIG_TEHUTI) += tehuti/bdx.bin
 fw-shipped-$(CONFIG_TIGON3) += tigon/tg3.bin tigon/tg3_tso.bin \
 			       tigon/tg3_tso5.bin
 fw-shipped-$(CONFIG_TYPHOON) += 3com/typhoon.bin
@@ -101,40 +53,8 @@
 				  emi26/bitstream.fw
 fw-shipped-$(CONFIG_USB_EMI62) += emi62/loader.fw emi62/bitstream.fw \
 				  emi62/spdif.fw emi62/midi.fw
-fw-shipped-$(CONFIG_USB_KAWETH) += kaweth/new_code.bin kaweth/trigger_code.bin \
-				   kaweth/new_code_fix.bin \
-				   kaweth/trigger_code_fix.bin
-ifdef CONFIG_FIRMWARE_IN_KERNEL
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_MPR) += keyspan/mpr.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA18X) += keyspan/usa18x.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19) += keyspan/usa19.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19QI) += keyspan/usa19qi.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19QW) += keyspan/usa19qw.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19W) += keyspan/usa19w.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28) += keyspan/usa28.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28XA) += keyspan/usa28xa.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28XB) += keyspan/usa28xb.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28X) += keyspan/usa28x.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA49W) += keyspan/usa49w.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA49WLC) += keyspan/usa49wlc.fw
-else
-fw-shipped- += keyspan/mpr.fw keyspan/usa18x.fw keyspan/usa19.fw	\
-	keyspan/usa19qi.fw keyspan/usa19qw.fw keyspan/usa19w.fw		\
-	keyspan/usa28.fw keyspan/usa28xa.fw keyspan/usa28xb.fw		\
-	keyspan/usa28x.fw keyspan/usa49w.fw keyspan/usa49wlc.fw
-endif
-fw-shipped-$(CONFIG_USB_SERIAL_TI) += ti_3410.fw ti_5052.fw \
-				      mts_cdma.fw mts_gsm.fw mts_edge.fw
-fw-shipped-$(CONFIG_USB_SERIAL_EDGEPORT) += edgeport/boot.fw edgeport/boot2.fw \
-					    edgeport/down.fw edgeport/down2.fw
-fw-shipped-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += edgeport/down3.bin
 fw-shipped-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat_loader.fw whiteheat.fw \
 					   # whiteheat_loader_debug.fw
-fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda/keyspan_pda.fw
-fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw
-fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw
-fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
-fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
 
 fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
 
@@ -156,7 +76,7 @@
 		  PROGBITS=$(if $(CONFIG_ARM),%,@)progbits;		     \
 		  echo "/* Generated by firmware/Makefile */"		> $@;\
 		  echo "    .section .rodata"				>>$@;\
-		  echo "    .p2align $${ASM_ALIGN}"			>>$@;\
+		  echo "    .p2align 4"					>>$@;\
 		  echo "_fw_$${FWSTR}_bin:"				>>$@;\
 		  echo "    .incbin \"$(2)\""				>>$@;\
 		  echo "_fw_end:"					>>$@;\
--- linux-4.4.0.orig/firmware/WHENCE
+++ linux-4.4.0/firmware/WHENCE
@@ -619,16 +619,6 @@
 
 --------------------------------------------------------------------------
 
-Driver: MYRI_SBUS - MyriCOM Gigabit Ethernet
-
-File: myricom/lanai.bin
-
-Licence: Unknown
-
-Found in hex form in kernel source.
-
---------------------------------------------------------------------------
-
 Driver: bnx2x: Broadcom Everest
 
 File: bnx2x/bnx2x-e1-6.2.9.0.fw
--- linux-4.4.0.orig/firmware/bnx2/bnx2-mips-06-6.2.3.fw.ihex
+++ linux-4.4.0/firmware/bnx2/bnx2-mips-06-6.2.3.fw.ihex
@@ -0,0 +1,5804 @@
+:10000000080001180800000000004A68000000C84D
+:1000100000000000000000000000000008004A6826
+:100020000000001400004B30080000A00800000091
+:100030000000569400004B44080058200000008443
+:100040000000A1D808005694000001580000A25CEE
+:100050000800321008000000000072F00000A3B495
+:10006000000000000000000000000000080072F026
+:1000700000000024000116A40800049008000400F9
+:10008000000017D4000116C80000000000000000A6
+:100090000000000000000000000000000000000060
+:1000A000080000A80800000000003BFC00012E9C96
+:1000B0000000000000000000000000000000000040
+:1000C00000000000000000000A00004600000000E0
+:1000D000000000000000000D636F6D362E322E33DD
+:1000E0000000000006020302000000000000000300
+:1000F000000000C800000032000000030000000003
+:1001000000000000000000000000000000000000EF
+:1001100000000010000001360000EA600000000549
+:1001200000000000000000000000000000000008C7
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000020000000000000000000000008D
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000010000000005F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E0000000000010000003000000000000000DEF
+:1001F0000000000D3C02080024424AA03C03080015
+:1002000024634B9CAC4000000043202B1480FFFD76
+:10021000244200043C1D080037BD7FFC03A0F021F0
+:100220003C100800261001183C1C0800279C4AA01E
+:100230000E000168000000000000000D27470100CB
+:1002400090E3000B2402001A94E5000814620028D1
+:10025000000020218CE200003C0308008C63004475
+:1002600094E60014000211C20002104030A4000203
+:10027000005A10212463000130A50004A446008028
+:100280003C010800AC23004410A000190004202BFE
+:100290008F4202B804410008240400013C02080017
+:1002A0008C420060244200013C010800AC22006046
+:1002B00003E00008008010218CE2002094E3001687
+:1002C00000002021AF4202808CE20004A743028498
+:1002D000AF4202883C021000AF4202B83C02080064
+:1002E0008C42005C244200013C010800AC22005C0E
+:1002F00003E00008008010212747010090E3000B75
+:100300002402000394E50008146200280000202164
+:100310008CE200003C0308008C63004494E6001467
+:10032000000211C20002104030A40002005A102145
+:100330002463000130A50004A44600803C010800AD
+:10034000AC23004410A000190004202B8F4202B8F7
+:1003500004410008240400013C0208008C420060B3
+:10036000244200013C010800AC22006003E00008C8
+:10037000008010218CE2002094E300160000202170
+:10038000AF4202808CE20004A7430284AF4202889D
+:100390003C021000AF4202B83C0208008C42005CF4
+:1003A000244200013C010800AC22005C03E000088C
+:1003B000008010218F4301002402010050620003DD
+:1003C000000311C20000000D000311C20002104022
+:1003D000005A1021A440008003E000080000102112
+:1003E0009362000003E00008AF80000003E0000813
+:1003F0000000102103E00008000010212402010089
+:1004000014820008000000003C0208008C4200FC3E
+:10041000244200013C010800AC2200FC0A0000DD7F
+:1004200030A200203C0208008C42008424420001DB
+:100430003C010800AC22008430A2002010400008DB
+:1004400030A300103C0208008C4201082442000145
+:100450003C010800AC22010803E000080000000095
+:1004600010600008000000003C0208008C420104FB
+:10047000244200013C010800AC22010403E0000812
+:10048000000000003C0208008C42010024420001F0
+:100490003C010800AC22010003E00008000000005D
+:1004A00027BDFFE8AFBF0010274401009483000878
+:1004B000306200041040001B306600028F4202B818
+:1004C00004410008240500013C0208008C42006041
+:1004D000244200013C010800AC2200600A0001290E
+:1004E0008FBF00108C82002094830016000028210A
+:1004F000AF4202808C820004A7430284AF4202888C
+:100500003C021000AF4202B83C0208008C42005C82
+:10051000244200013C010800AC22005C0A000129D1
+:100520008FBF001010C00006006028218F4401001A
+:100530000E0000CD000000000A0001282405000183
+:100540008F8200088F4301045043000700002821D8
+:100550008F4401000E0000CD000000008F42010416
+:10056000AF820008000028218FBF001000A01021DA
+:1005700003E0000827BD001827BDFFE8AFBF001447
+:10058000AFB00010974201083043700024022000F1
+:100590001062000B286220011440002F000010217F
+:1005A00024024000106200250000000024026000C8
+:1005B00010620026000010210A0001658FBF0014A0
+:1005C00027500100920200091040001A2403000184
+:1005D0003C0208008C420020104000160000182148
+:1005E0000E00049300000000960300083C0608007B
+:1005F00094C64B5E8E0400188F8200209605000C76
+:1006000000031C0000661825AC440000AC45000443
+:1006100024040001AC400008AC40000CAC400010C9
+:10062000AC400014AC4000180E0004B8AC43001CF1
+:10063000000018210A000164006010210E0003254B
+:10064000000000000A000164000010210E000EE905
+:1006500000000000000010218FBF00148FB00010B8
+:1006600003E0000827BD001827BDFFE0AFB2001867
+:100670003C036010AFBF001CAFB10014AFB000105E
+:100680008C6450002402FF7F3C1A800000822024EA
+:100690003484380C24020037AC6450003C1208004B
+:1006A00026524AD8AF42000824020C80AF420024F0
+:1006B0003C1B80083C06080024C60324024010218D
+:1006C0002404001D2484FFFFAC4600000481FFFDCC
+:1006D000244200043C020800244204B03C0108000B
+:1006E000AC224AE03C020800244202303C010800EF
+:1006F000AC224AE43C020800244201743C03080096
+:100700002463032C3C040800248403D83C0508001F
+:1007100024A538F03C010800AC224B403C02080004
+:10072000244202EC3C010800AC264B243C010800AA
+:10073000AC254B343C010800AC234B3C3C01080089
+:10074000AC244B443C010800AC224B483C0108005F
+:10075000AC234ADC3C010800AC204AE83C0108001C
+:10076000AC204AEC3C010800AC204AF03C010800F7
+:10077000AC204AF43C010800AC204AF83C010800D7
+:10078000AC204AFC3C010800AC204B003C010800B6
+:10079000AC244B043C010800AC204B083C01080091
+:1007A000AC204B0C3C010800AC204B103C01080075
+:1007B000AC204B143C010800AC204B183C01080055
+:1007C000AC264B1C3C010800AC264B203C01080029
+:1007D000AC254B303C010800AC234B380E000623FF
+:1007E000000000003C028000344200708C42000097
+:1007F000AF8200143C0308008C6300208F82000449
+:10080000104300043C0280000E00045BAF83000430
+:100810003C028000344600703C0308008C6300A05A
+:100820003C0208008C4200A4104300048F84001492
+:100830003C010800AC2300A4A743009E8CCA000022
+:100840003C0308008C6300BC3C0208008C4200B8EA
+:100850000144202300641821000040210064202B63
+:1008600000481021004410213C010800AC2300BCCA
+:100870003C010800AC2200B88F5100003222000772
+:100880001040FFDCAF8A00148CC600003C05080055
+:100890008CA500BC3C0408008C8400B800CA30233E
+:1008A00000A628210000102100A6302B0082202164
+:1008B00000862021322700013C010800AC2500BC45
+:1008C0003C010800AC2400B810E0001F32220002F6
+:1008D0008F420100AF4200208F420104AF4200A8C6
+:1008E0009342010B0E0000C6305000FF2E02001E86
+:1008F00054400004001010800E0000C90A000213CA
+:1009000000000000005210218C4200000040F80955
+:1009100000000000104000053C0240008F4301042D
+:100920003C026020AC4300143C024000AF4201385E
+:100930003C0208008C420034244200013C010800C3
+:10094000AC220034322200021040000E3222000499
+:100950008F4201400E0000C6AF4200200E000295FB
+:10096000000000003C024000AF4201783C02080059
+:100970008C420038244200013C010800AC220038BF
+:10098000322200041040FF983C0280008F42018018
+:100990000E0000C6AF4200208F43018024020F00EA
+:1009A00014620005000000008F420188A742009CED
+:1009B0000A0002483C0240009362000024030050F9
+:1009C000304200FF144300083C0240000E00027B4E
+:1009D00000000000544000043C0240000E000D7571
+:1009E000000000003C024000AF4201B83C02080099
+:1009F0008C42003C244200013C010800AC22003C37
+:100A00000A0001C83C0280003C0290003442000110
+:100A100000822025AF4400208F4200200440FFFECA
+:100A20000000000003E00008000000003C0280001D
+:100A3000344200010082202503E00008AF4400207A
+:100A400027BDFFE0AFB10014AFB0001000808821D7
+:100A5000AFBF00180E00025030B000FF9362007D5F
+:100A60000220202102028025A370007D8F70007477
+:100A70003C0280000E000259020280241600000988
+:100A80008FBF00188F4201F80440FFFE24020002CD
+:100A9000AF5101C0A34201C43C021000AF4201F8B3
+:100AA0008FBF00188FB100148FB0001003E0000852
+:100AB00027BD002027BDFFE8AFBF0010974201848B
+:100AC0008F440188304202001040000500002821B8
+:100AD0000E000FAA000000000A00028D240500018C
+:100AE0003C02FF0004800005008218243C02040040
+:100AF000506200019362003E240500018FBF001088
+:100B000000A0102103E0000827BD0018A360002208
+:100B10008F4401400A00025E2405000127BDFFE862
+:100B2000AFBF0014AFB0001093620000304400FF6C
+:100B300038830020388200300003182B0002102B6D
+:100B40000062182410600003240200501482008008
+:100B50008FBF001493620005304200011040007CFA
+:100B60008FBF0014934201482443FFFF2C6200050D
+:100B7000104000788FB00010000310803C03080084
+:100B800024634A68004310218C42000000400008A2
+:100B9000000000000E0002508F4401408F70000CD6
+:100BA0008F4201441602000224020001AF62000CD1
+:100BB0000E0002598F4401408F420144145000043A
+:100BC0008FBF00148FB000100A000F2027BD00183F
+:100BD0008F62000C0A0003040000000097620010FE
+:100BE0008F4301443042FFFF1462001A00000000EE
+:100BF00024020001A76200108F4202380443001053
+:100C00008F4201403C02003F3446F0003C0560004A
+:100C10003C04FFC08CA22BBC0044182400461024C6
+:100C20000002130200031D82106200390000000060
+:100C30008F4202380440FFF7000000008F4201405D
+:100C4000AF4202003C021000AF4202380A00032209
+:100C50008FBF0014976200100A0003040000000018
+:100C60000E0002508F440140976200128F430144EE
+:100C70003050FFFF1603000224020001A762001299
+:100C80000E0002598F4401408F42014416020004B5
+:100C90008FBF00148FB000100A00029127BD00180A
+:100CA000976200120A00030400000000976200141B
+:100CB0008F4301443042FFFF14620006240200010A
+:100CC0008FBF00148FB00010A76200140A00124AF0
+:100CD00027BD0018976200141440001D8FBF001438
+:100CE0000A00031C00000000976200168F430144B5
+:100CF0003042FFFF1462000B240200018FBF00147A
+:100D00008FB00010A76200160A000B1227BD001852
+:100D10009742007824420004A76200100A000322D0
+:100D20008FBF001497620016240300013042FFFFBA
+:100D3000144300078FBF00143C0208008C4200706F
+:100D4000244200013C010800AC2200708FBF001457
+:100D50008FB0001003E0000827BD001827BDFFE892
+:100D6000AFBF0014AFB000108F50010093620000BD
+:100D700093430109304400FF2402001F106200A5C4
+:100D80002862002010400018240200382862000A5F
+:100D90001040000C2402000B286200081040002CB8
+:100DA00000000000046000E52862000214400028F2
+:100DB00024020006106200268FBF00140A00041FE0
+:100DC0008FB000101062005E2862000B144000DC3F
+:100DD0008FBF00142402000E106200738FB0001049
+:100DE0000A00041F00000000106200C028620039E1
+:100DF0001040000A2402008024020036106200CA5B
+:100E000028620037104000B424020035106200C18F
+:100E10008FBF00140A00041F8FB000101062002B57
+:100E20002862008110400006240200C82402003914
+:100E3000106200B48FBF00140A00041F8FB00010AE
+:100E4000106200998FBF00140A00041F8FB00010B9
+:100E50003C0208008C420020104000B98FBF0014F3
+:100E60000E000493000000008F4201008F830020D9
+:100E70009745010C97460108AC6200008F420104BF
+:100E80003C04080094844B5E00052C00AC62000416
+:100E90008F4201180006340000C43025AC620008FF
+:100EA0008F42011C24040001AC62000C9342010A31
+:100EB00000A22825AC650010AC600014AC600018DE
+:100EC000AC66001C0A0003F58FBF00143C0208004A
+:100ED0008C4200201040009A8FBF00140E00049333
+:100EE00000000000974401083C03080094634B5E37
+:100EF0009745010C000422029746010E8F820020C4
+:100F0000000426000083202500052C003C030080FF
+:100F100000A6282500832025AC400000AC4000043A
+:100F2000AC400008AC40000CAC450010AC400014D4
+:100F3000AC400018AC44001C0A0003F42404000177
+:100F40009742010C14400015000000009362000558
+:100F50003042001014400011000000000E0002504A
+:100F6000020020219362000502002021344200107B
+:100F70000E000259A36200059362000024030020C2
+:100F8000304200FF1043006D020020218FBF00148B
+:100F90008FB000100A000FC027BD00180000000D20
+:100FA0000A00041E8FBF00143C0208008C4200207F
+:100FB000104000638FBF00140E0004930000000077
+:100FC0008F4201048F8300209744010C3C050800E8
+:100FD00094A54B5EAC6200009762002C00042400D4
+:100FE0003042FFFF008220253C02400E00A228254F
+:100FF000AC640004AC600008AC60000CAC60001095
+:10100000AC600014AC600018AC65001C0A0003F46E
+:10101000240400010E00025002002021A7600008F5
+:101020000E00025902002021020020210E00025E63
+:10103000240500013C0208008C42002010400040C2
+:101040008FBF00140E000493000000009742010CB3
+:101050008F8300203C05080094A54B5E000214001D
+:10106000AC700000AC620004AC6000088F64004CFF
+:101070003C02401F00A22825AC64000C8F62005087
+:1010800024040001AC6200108F620054AC620014B2
+:10109000AC600018AC65001C8FBF00148FB000104E
+:1010A0000A0004B827BD0018240200205082002541
+:1010B0008FB000100E000F0A020020211040002007
+:1010C0008FBF0014020020218FB0001000002821E3
+:1010D0000A00025E27BD0018020020218FBF001405
+:1010E0008FB000100A00058027BD00189745010C3D
+:1010F000020020218FBF00148FB000100A0005A04D
+:1011000027BD0018020020218FB000100A0005C57D
+:1011100027BD00189345010D020020218FB000105B
+:101120000A00060F27BD0018020020218FBF0014FF
+:101130008FB000100A0005EB27BD00188FBF001408
+:101140008FB0001003E0000827BD00188F4202781E
+:101150000440FFFE2402000234840080AF440240B9
+:10116000A34202443C02100003E00008AF420278B0
+:101170003C04080094844B6A3C0208008C424B7487
+:101180003083FFFF000318C000431021AF42003C32
+:101190003C0208008C424B70AF4200383C020050C9
+:1011A00034420008AF4200300000000000000000A0
+:1011B000000000008F420000304200201040FFFD80
+:1011C000000000008F4204003C010800AC224B608C
+:1011D0008F4204043C010800AC224B643C02002016
+:1011E000AF420030000000003C02080094424B680F
+:1011F0003C03080094634B6C3C05080094A54B6EBF
+:1012000024840001004310213083FFFF3C010800CB
+:10121000A4224B683C010800A4244B6A1465000317
+:10122000000000003C010800A4204B6A03E0000815
+:10123000000000003C05000A27BDFFE80345282107
+:101240003C04080024844B50AFBF00100E00051D65
+:101250002406000A3C02080094424B523C0308005A
+:1012600094634B6E3042000F244200030043180485
+:1012700024027FFF0043102B10400002AF83001CAC
+:101280000000000D0E00042A000000003C020800CF
+:1012900094424B5A8FBF001027BD001803E000088E
+:1012A000A74200A23C02000A034210219443000618
+:1012B0003C02080094424B5A3C010800A4234B56C0
+:1012C000004310238F83001C00021400000214034B
+:1012D0000043102B03E000083842000127BDFFE85F
+:1012E000AFBF00103C02000A0342102194420006E6
+:1012F0003C010800A4224B560E00047700000000B9
+:101300005440FFF93C02000A8FBF001003E00008C0
+:1013100027BD001827BDFFE8AFBF00100E000477FF
+:101320000000000010400003000000000E000485D3
+:10133000000000003C0208008C424B608FBF001090
+:1013400027430400AF4200383C0208008C424B6443
+:1013500027BD0018AF830020AF42003C3C020005CF
+:10136000AF42003003E00008AF8000188F82001801
+:101370003C0300060002114000431025AF4200303C
+:101380000000000000000000000000008F4200008C
+:10139000304200101040FFFD27420400AF820020C1
+:1013A00003E00008AF8000183C0608008CC64B64C0
+:1013B0008F8500188F8300203C02080094424B5A0E
+:1013C00027BDFFE024A50001246300202442000182
+:1013D00024C70020AFB10014AFB00010AFBF001899
+:1013E000AF850018AF8300203C010800A4224B5AAF
+:1013F000309000FF3C010800AC274B6404C100089A
+:101400000000882104E00006000000003C02080003
+:101410008C424B60244200013C010800AC224B602E
+:101420003C02080094424B5A3C03080094634B680A
+:101430000010202B004310262C42000100441025F0
+:10144000144000048F830018240200101462000F5F
+:10145000000000000E0004A9241100013C03080054
+:1014600094634B5A3C02080094424B681462000398
+:10147000000000000E00042A000000001600000317
+:10148000000000000E000493000000003C03080070
+:1014900094634B5E3C02080094424B5C2463000161
+:1014A0003064FFFF3C010800A4234B5E148200035C
+:1014B000000000003C010800A4204B5E1200000662
+:1014C000000000003C02080094424B5AA74200A2D0
+:1014D0000A00050B022010210E0004770000000016
+:1014E00010400004022010210E00048500000000BE
+:1014F000022010218FBF00188FB100148FB0001090
+:1015000003E0000827BD00203084FFFF30A5FFFF67
+:101510000000182110800007000000003082000148
+:101520001040000200042042006518210A00051343
+:101530000005284003E000080060102110C00006EC
+:1015400024C6FFFF8CA2000024A50004AC8200008A
+:101550000A00051D2484000403E0000800000000C8
+:1015600010A0000824A3FFFFAC86000000000000CC
+:10157000000000002402FFFF2463FFFF1462FFFA53
+:101580002484000403E0000800000000240200019D
+:10159000AF62000CA7620010A7620012A7620014DD
+:1015A00003E00008A76200163082007F034210218A
+:1015B0003C08000E004818213C0208008C42002024
+:1015C00027BDFFD82407FF80AFB3001CAFB20018BF
+:1015D000AFB10014AFB00010AFBF00200080802179
+:1015E00030B100FF0087202430D200FF1040002FD0
+:1015F00000009821AF44002C9062000024030050AA
+:10160000304200FF1443000E000000003C020800BE
+:101610008C4200E00202102100471024AF42002C4F
+:101620003C0208008C4200E0020210213042007FA0
+:101630000342102100481021944200D43053FFFF90
+:101640000E000493000000003C02080094424B5E30
+:101650008F8300200011340000C2302500122C00BE
+:101660003C02400000C2302534A50001AC700000EF
+:101670008FBF0020AC6000048FB20018AC7300086C
+:101680008FB10014AC60000C8FB3001CAC6500106F
+:101690008FB00010AC60001424040001AC6000188E
+:1016A00027BD00280A0004B8AC66001C8FBF0020CC
+:1016B0008FB3001C8FB200188FB100148FB00010D0
+:1016C00003E0000827BD00289343010F2402001007
+:1016D0001062000E2865001110A0000724020012FD
+:1016E000240200082405003A1062000600003021A0
+:1016F00003E0000800000000240500351462FFFC30
+:10170000000030210A000538000000008F420074FC
+:1017100024420FA003E00008AF62000C27BDFFE8E1
+:10172000AFBF00100E00025E240500018FBF001045
+:1017300024020001A762001227BD00182402000144
+:1017400003E00008A360002227BDFFE0AFB1001452
+:10175000AFB00010AFBF001830B1FFFF0E00025055
+:10176000008080219362003F24030004304200FF88
+:101770001443000C02002021122000082402000A59
+:101780000E00053100000000936200052403FFFEF7
+:1017900000431024A362000524020012A362003F4C
+:1017A000020020210E000259A360008116200003D0
+:1017B000020020210E0005950000000002002021FB
+:1017C000322600FF8FBF00188FB100148FB00010B9
+:1017D000240500380A00053827BD002027BDFFE09A
+:1017E000AFBF001CAFB20018AFB10014AFB0001013
+:1017F0000E000250008080210E0005310000000024
+:101800009362003F24120018305100FF123200038F
+:101810000200202124020012A362003F936200050F
+:101820002403FFFE004310240E000259A3620005AA
+:10183000020020212405002016320007000030217C
+:101840008FBF001C8FB200188FB100148FB0001032
+:101850000A00025E27BD00208FBF001C8FB2001857
+:101860008FB100148FB00010240500390A0005382C
+:1018700027BD002027BDFFE8AFB00010AFBF0014A8
+:101880009742010C2405003600808021144000108E
+:10189000304600FF0E00025000000000240200123B
+:1018A000A362003F93620005344200100E00053130
+:1018B000A36200050E00025902002021020020212F
+:1018C0000E00025E240500200A000604000000004D
+:1018D0000E000538000000000E000250020020211A
+:1018E000936200232403FF9F020020210043102461
+:1018F0008FBF00148FB00010A36200230A000259AA
+:1019000027BD001827BDFFE0AFBF0018AFB100141E
+:10191000AFB0001030B100FF0E00025000808021F7
+:10192000240200120E000531A362003F0E0002598E
+:101930000200202102002021022030218FBF001848
+:101940008FB100148FB00010240500350A0005384F
+:1019500027BD0020A380002C03E00008A380002DF9
+:101960008F4202780440FFFE8F820034AF42024073
+:1019700024020002A34202443C02100003E00008DB
+:10198000AF4202783C0360008C6254003042000891
+:101990001440FFFD000000008C625408AF82000C70
+:1019A00024020052AC605408AC645430AC6254342D
+:1019B0002402000803E00008AC6254003C0260000E
+:1019C0008C42540030420008104000053C03600087
+:1019D0008C625400304200081440FFFD00000000FB
+:1019E0008F83000C3C02600003E00008AC43540805
+:1019F00090A3000024020005008040213063003FD6
+:101A000000004821146200050000502190A2001C33
+:101A100094A3001E304900FF306AFFFFAD00000CA8
+:101A2000AD000010AD000024950200148D05001CCF
+:101A30008D0400183042FFFF0049102300021100FE
+:101A4000000237C3004038210086202300A2102B5B
+:101A50000082202300A72823AD05001CAD04001838
+:101A6000A5090014A5090020A50A001603E0000836
+:101A7000A50A00228F4201F80440FFFE2402000262
+:101A8000AF4401C0A34201C43C02100003E00008BF
+:101A9000AF4201F83C0208008C4200B427BDFFE8C9
+:101AA000AFBF001424420001AFB000103C01080099
+:101AB000AC2200B48F4300243C02001F30AA00FF78
+:101AC0003442FF8030D800FF006280240080F8217B
+:101AD00030EF00FF1158003B01405821240CFF80DB
+:101AE0003C19000A3163007F000310C00003194055
+:101AF000006218213C0208008C4200DC25680001CD
+:101B0000310D007F03E21021004310213043007F9C
+:101B100003431821004C102400794821AF420024CF
+:101B20008D220024016C1824006C7026AD22000C5C
+:101B30008D220024310800FFAD22001095220014F0
+:101B4000952300208D27001C3042FFFF3063FFFFEC
+:101B50008D2600180043102300021100000227C345
+:101B60000040282100C4302300E2102B00C23023A3
+:101B700000E53823AD27001CAD2600189522002073
+:101B8000A522001495220022154B000AA52200165A
+:101B90008D2300248D220008254600013145008058
+:101BA0001462000430C4007F108F000238AA008045
+:101BB00000C0502151AF000131C800FF1518FFC906
+:101BC000010058218F8400343082007F03421821A5
+:101BD0003C02000A006218212402FF8000822024B7
+:101BE000AF440024A06A0079A06A00838C62005090
+:101BF0008F840034AC6200708C6500743C027FFFFF
+:101C00003442FFFF00A228240E00066BAC6500746E
+:101C1000AF5000248FBF00148FB0001003E0000805
+:101C200027BD001827BDFFC0AFBE0038AFB70034D6
+:101C3000AFB5002CAFB20020AFB1001CAFB00018A0
+:101C4000AFBF003CAFB60030AFB40028AFB3002444
+:101C50008F4500248F4600288F43002C3C02001F34
+:101C60003442FF800062182400C230240080A82182
+:101C7000AFA3001400A2F0240E00062FAFA60010A0
+:101C80003C0208008C4200E02410FF8003608821A1
+:101C900002A2102100501024AF4200243C02080090
+:101CA0008C4200E002A210213042007F0342182142
+:101CB0003C02000A00629021924200D293630084A9
+:101CC000305700FF306300FF24020001106200342F
+:101CD000036020212402000214620036000000008C
+:101CE0000E001216024028219223008392220083C4
+:101CF0003063007F3042007F000210C000031940B3
+:101D0000006218213C0208008C4200DC02A2102173
+:101D10000043382100F01024AF42002892250078BB
+:101D20009224008330E2007F034218213C02000C21
+:101D300014850007006280212402FFFFA24200F107
+:101D40002402FFFFA64200F20A0007272402FFFF39
+:101D500096020020A24200F196020022A64200F262
+:101D60008E020024AE4200F492220083A24200F0D0
+:101D70008E4200C8AE4200FC8E4200C4AE4200F863
+:101D80008E220050AE4201008E4200CCAE420104D1
+:101D9000922200853042003F0A0007823442004010
+:101DA0000E00123902402821922200850A00078283
+:101DB0003042003F936200852403FFDF3042003F42
+:101DC000A36200859362008500431024A36200850E
+:101DD0009363008393620078307400FF304200FF09
+:101DE00010540036240AFF803C0C000C3283007F24
+:101DF000000310C000031940006218213C020800D3
+:101E00008C4200DC268800013109007F02A21021EB
+:101E10000043382130E2007F0342182100EA1024F9
+:101E2000AF420028006C80218E020024028A182410
+:101E3000006A5826AE02000C8E020024310800FF12
+:101E4000AE02001096020014960300208E07001CBC
+:101E50003042FFFF3063FFFF8E060018004310235F
+:101E600000021100000227C30040282100C43023D3
+:101E700000E2102B00C2302300E53823AE07001C1F
+:101E8000AE06001896020020A60200149602002258
+:101E9000A602001692220079304200FF105400077B
+:101EA0000000000051370001316800FF92220078E5
+:101EB000304200FF1448FFCD0100A0219222008390
+:101EC000A22200798E2200500A0007E2AE220070A2
+:101ED000A22200858E22004C2405FF80AE42010C18
+:101EE0009222008534420020A2220085924200D135
+:101EF0003C0308008C6300DC305400FF3C02080007
+:101F00008C4200E400143140001420C002A31821C8
+:101F100000C4202102A210210064382100461021B3
+:101F20000045182400E52824AF450028AF43002CC5
+:101F30003042007F924400D030E3007F03422821EA
+:101F4000034318213C02000C006280213C02000E79
+:101F5000309600FF00A298211296002A000000008F
+:101F60008E02000C02002021026028211040002572
+:101F7000261000280E00064A000000009262000DA4
+:101F800026830001307400FF3042007FA262000D02
+:101F90002404FF801697FFF0267300203C020800FF
+:101FA0008C4200DC0000A02102A210210044102479
+:101FB000AF4200283C0208008C4200E43C030800C9
+:101FC0008C6300DC02A2102100441024AF42002CDC
+:101FD0003C0208008C4200E402A318213063007F19
+:101FE00002A210213042007F034220210343182126
+:101FF0003C02000C006280213C02000E0A0007A493
+:10200000008298218E4200D8AE2200508E4200D825
+:10201000AE22007092250083924600D19223008365
+:10202000924400D12402FF8000A228243063007F64
+:10203000308400FF00A628250064182A10600002E2
+:1020400030A500FF38A50080A2250083A2250079D5
+:102050000E00063D000000009222007E02A020211A
+:10206000A222007A8E2300743C027FFF3442FFFFDD
+:10207000006218240E00066BAE2300748FA20010BD
+:10208000AF5E00248FBF003CAF4200288FBE0038F7
+:102090008FA200148FB700348FB600308FB5002C9C
+:1020A0008FB400288FB300248FB200208FB1001CA2
+:1020B0008FB0001827BD004003E00008AF42002C9D
+:1020C00090A2000024420001A0A200003C030800EE
+:1020D0008C6300F4304200FF1443000F0080302175
+:1020E000A0A000003C0208008C4200E48F84003471
+:1020F000008220213082007F034218213C02000C24
+:10210000006218212402FF8000822024ACC300005A
+:1021100003E00008AF4400288C8200002442002025
+:1021200003E00008AC82000094C200003C080800F4
+:10213000950800CA30E7FFFF008048210102102106
+:10214000A4C2000094C200003042FFFF00E2102B46
+:1021500054400001A4C7000094A200003C03080002
+:102160008C6300CC24420001A4A2000094A20000D1
+:102170003042FFFF544300078F8600280107102BD1
+:10218000A4A000005440000101003821A4C70000B1
+:102190008F8600288CC4001CAF44003C94A2000031
+:1021A0008F43003C3042FFFF000210C00062182144
+:1021B000AF43003C8F42003C008220231880000483
+:1021C000000000008CC200180A00084324420001ED
+:1021D0008CC20018AF4200383C020050344200105C
+:1021E000AF420030000000000000000000000000CE
+:1021F0008F420000304200201040FFFD0000000030
+:102200008F420404AD2200048F420400AD2200007E
+:102210003C020020AF42003003E000080000000054
+:1022200027BDFFE0AFB20018AFB10014AFB000108F
+:10223000AFBF001C94C2000000C080213C12080007
+:10224000965200C624420001A60200009603000038
+:1022500094E2000000E03021144300058FB100300B
+:102260000E000818024038210A000875000000001E
+:102270008C8300048C820004244200400461000727
+:10228000AC8200048C8200040440000400000000C2
+:102290008C82000024420001AC8200009602000003
+:1022A0003042FFFF50520001A600000096220000BD
+:1022B00024420001A62200008F82002896230000FD
+:1022C00094420016144300048FBF001C2402000136
+:1022D000A62200008FBF001C8FB200188FB100141F
+:1022E0008FB0001003E0000827BD00208F89002870
+:1022F00027BDFFE0AFBF00188D220028274804004B
+:1023000030E700FFAF4200388D22002CAF8800304C
+:10231000AF42003C3C020005AF420030000000002C
+:1023200000000000000000000000000000000000AD
+:10233000000000008C82000C8C82000CAD020000BA
+:102340008C820010AD0200048C820018AD020008DF
+:102350008C82001CAD02000C8CA20014AD02001097
+:102360008C820020AD02001490820005304200FFF4
+:1023700000021200AD0200188CA20018AD02001C71
+:102380008CA2000CAD0200208CA20010AD02002433
+:102390008CA2001CAD0200288CA20020AD02002CF3
+:1023A000AD060030AD000034978300263402FFFFF5
+:1023B00014620002006020213404FFFF10E00011CD
+:1023C000AD04003895230036952400362402000120
+:1023D0003063FFFF000318C20069182190650040B8
+:1023E000308400070082100400451025A0620040E0
+:1023F0008F820028944200563042FFFF0A0008DC1A
+:10240000AD02003C952300369524003624020001DD
+:102410003063FFFF000318C2006918219065004077
+:1024200030840007008210040002102700451024A9
+:10243000A0620040AD00003C000000000000000071
+:10244000000000003C02000634420040AF42003071
+:102450000000000000000000000000008F420000AB
+:10246000304200101040FFFD8F860028AF880030FA
+:1024700024C2005624C7003C24C4002824C50032CE
+:1024800024C600360E000856AFA200108FBF0018F9
+:1024900003E0000827BD00208F8300243C060800CD
+:1024A0008CC600E88F82003430633FFF0003198040
+:1024B00000461021004310212403FF803046007F96
+:1024C00000431024AF420028034618213C02000CB0
+:1024D0000062302190C2000D30A500FF00003821BD
+:1024E00034420010A0C2000D8F8900288F8A00247A
+:1024F00095230036000A13823048000324020001AD
+:10250000A4C3000E1102000B2902000210400005B6
+:10251000240200021100000C240300010A0009201B
+:102520000000182111020006000000000A00092026
+:10253000000018218CC2002C0A000920244300014D
+:102540008CC20014244300018CC200180043102BDD
+:1025500050400009240700012402002714A20003B0
+:10256000000000000A00092C240700019522003E0B
+:1025700024420001A522003E000A138230430003DA
+:102580002C62000210400009008028211460000421
+:102590000000000094C200360A00093C3046FFFFEC
+:1025A0008CC600380A00093C008028210000302138
+:1025B0003C04080024844B780A00088900000000CD
+:1025C000274901008D22000C9523000601202021BF
+:1025D000000216023046003F3063FFFF240200274E
+:1025E00000C0282128C7002810C2000EAF83002495
+:1025F00010E00008240200312402002110C200096A
+:102600002402002510C200079382002D0A00095BF6
+:102610000000000010C200059382002D0A00095B33
+:10262000000000000A0008F4000000000A0006266E
+:102630000000000095230006912400058D25000C64
+:102640008D2600108D2700188D28001C8D29002054
+:10265000244200013C010800A4234B7E3C010800F9
+:10266000A0244B7D3C010800AC254B843C010800B4
+:10267000AC264B883C010800AC274B903C0108007D
+:10268000AC284B943C010800AC294B9803E00008AF
+:10269000A382002D8F87002827BDFFC0AFB3003471
+:1026A000AFB20030AFB1002CAFB00028AFBF0038E0
+:1026B0003C0208008C4200D094E3003030B0FFFFB1
+:1026C000005010073045FFFF3063FFFF00C0982126
+:1026D000A7A200103C110800963100C614A3000602
+:1026E0003092FFFF8CE2002424420030AF42003CD5
+:1026F0000A0009948CE2002094E200323042FFFF8D
+:1027000054A2000827A400188CE2002C24420030B8
+:10271000AF42003C8CE20028AF4200380A0009A218
+:102720008F84002827A5001027A60020022038212A
+:102730000E000818A7A000208FA200182442003025
+:10274000AF4200388FA2001CAF42003C8F840028AB
+:102750003C020005AF42003094820034274304005D
+:102760003042FFFF0202102B14400007AF830030FD
+:1027700094820054948300340202102100431023F9
+:102780000A0009B63043FFFF94830054948200345A
+:102790000223182100501023006218233063FFFF2A
+:1027A000948200163042FFFF144300030000000033
+:1027B0000A0009C424030001948200163042FFFF7E
+:1027C0000043102B104000058F82003094820016C9
+:1027D000006210233043FFFF8F820030AC530000B3
+:1027E000AC400004AC520008AC43000C3C020006B4
+:1027F00034420010AF420030000000000000000032
+:10280000000000008F420000304200101040FFFD29
+:10281000001018C2006418219065004032040007BF
+:10282000240200018FBF00388FB300348FB2003014
+:102830008FB1002C8FB000280082100400451025B5
+:1028400027BD004003E00008A062004027BDFFA8AC
+:10285000AFB60050AFB5004CAFB40048AFB30044C2
+:10286000AFB1003CAFBF0054AFB20040AFB00038D2
+:102870008C9000003C0208008C4200E88F860034F7
+:10288000960300022413FF8000C2302130633FFF13
+:102890000003198000C3382100F3102490B2000017
+:1028A000AF42002C9203000230E2007F034230214D
+:1028B0003C02000E00C28821306300C024020040A8
+:1028C0000080A82100A0B021146200260000A021F1
+:1028D0008E3400388E2200181440000224020001B9
+:1028E000AE2200189202000D304200201440001564
+:1028F0008F8200343C0308008C6300DC001238C077
+:10290000001231400043102100C730210046382119
+:1029100030E300073C02008030E6007800C230253A
+:102920000343182100F31024AF4208002463090078
+:10293000AF4608108E2200188C6300080043102157
+:10294000AE2200188E22002C8E2300182442000193
+:102950000062182B1060003D000000000A000A7899
+:1029600000000000920300022402FFC00043102474
+:10297000304200FF1440000524020001AE2200187E
+:10298000962200360A000A613054FFFF8E2200149E
+:1029900024420001AE22001892020000000216003C
+:1029A0000002160304410029000000009602000204
+:1029B00027A4001000802821A7A20016960200027A
+:1029C00024070001000030213042FFFFAF820024C5
+:1029D0000E000889AFA0001C960300023C0408000A
+:1029E0008C8400E88F82003430633FFF000319803D
+:1029F00000441021004310213043007F3C05000CAF
+:102A00000053102403431821AF4200280065182109
+:102A10009062000D001221403042007FA062000D44
+:102A20003C0308008C6300E48F82003400431021D3
+:102A30000044382130E2007F03421021004510217C
+:102A400000F31824AF430028AEA200009222000D2C
+:102A5000304200101040001302A020218F83002874
+:102A60008EA40000028030219462003E2442FFFFC9
+:102A7000A462003E948400029625000E3084FFFF7D
+:102A80000E00097330A5FFFF8F82002894430034A5
+:102A90009622000E1443000302A02021240200010C
+:102AA000A382002C02C028210E0007FE00000000B7
+:102AB0008FBF00548FB600508FB5004C8FB40048C4
+:102AC0008FB300448FB200408FB1003C8FB000380C
+:102AD00003E0000827BD00588F82002827BDFFD0E3
+:102AE000AFB40028AFB20020AFBF002CAFB30024BA
+:102AF000AFB1001CAFB00018904400D0904300D19B
+:102B00000000A021309200FFA3A30010306300FF5B
+:102B10008C5100D88C5300DC1072002B2402000171
+:102B20003C0308008C6300E493A400108F820034FF
+:102B30002406FF800004214000431021004410219E
+:102B40003043007F00461024AF4200280343182181
+:102B50003C02000C006218218C62000427A40014BF
+:102B600027A50010022280210270102304400015C6
+:102B7000AFA300149062000D00C21024304200FF89
+:102B800014400007020088219062000D344200408A
+:102B90000E0007FEA062000D0A000ABD93A20010FD
+:102BA0000E0009E1241400018F830028AC7000D8C6
+:102BB00093A20010A06200D193A200101452FFD87B
+:102BC0000000000024020001168200048FBF002CC8
+:102BD0000E000626000000008FBF002C8FB40028D6
+:102BE0008FB300248FB200208FB1001C8FB000186B
+:102BF00003E0000827BD003027BDFFD8AFB3001C9D
+:102C0000AFB20018AFB10014AFB00010AFBF0020DA
+:102C10000080982100E0802130B1FFFF0E00049376
+:102C200030D200FF000000000000000000000000A3
+:102C30008F820020AC510000AC520004AC5300085D
+:102C4000AC40000CAC400010AC400014AC4000188C
+:102C50003C03080094634B5E02038025AC50001CCB
+:102C6000000000000000000000000000240400013B
+:102C70008FBF00208FB3001C8FB200188FB10014DB
+:102C80008FB000100A0004B827BD002827BDFFE858
+:102C9000AFB00010AFBF001430A5FFFF30C600FF7B
+:102CA0000080802124020C80AF420024000000003C
+:102CB0000000000000000000000000000000000014
+:102CC0000E000ACC000000003C040800248400E050
+:102CD0008C8200002403FF808FBF001402021021A9
+:102CE00000431024AF4200248C8200003C03000A01
+:102CF000020280213210007F035010218FB000109B
+:102D00000043102127BD001803E00008AF8200280F
+:102D100027BDFFE8AFBF00108F4401403C0308000F
+:102D20008C6300E02402FF80AF840034008318210C
+:102D300000621024AF4200243C02000803424021FC
+:102D4000950500023063007F3C02000A034318210E
+:102D50000062182130A5FFFF3402FFFF0000302180
+:102D60003C07602010A20006AF8300282402FFFF6A
+:102D7000A5020002946500D40E000AF130A5FFFF01
+:102D80008FBF001024020C8027BD001803E000084C
+:102D9000AF4200243C020008034240219502000299
+:102DA0003C0A0800954A00C63046FFFF14C00007E1
+:102DB0003402FFFF8F8200288F8400343C0760209C
+:102DC000944500D40A000B5A30A5FFFF10C200241E
+:102DD0008F87002894E2005494E400163045FFFFEA
+:102DE00000A6102300A6182B3089FFFF10600004F6
+:102DF0003044FFFF00C51023012210233044FFFFA1
+:102E0000008A102B1040000C012A1023240200011C
+:102E1000A50200162402FFFFA502000294E500D4DB
+:102E20008F8400340000302130A5FFFF3C07602074
+:102E30000A000AF1000000000044102A10400008B7
+:102E4000000000009502001630420001104000040E
+:102E5000000000009742007E24420014A5020016E4
+:102E600003E00008000000008F84002827BDFFE079
+:102E7000AFBF0018948200349483003E1060001AA3
+:102E80003048FFFF9383002C2402000114620027C6
+:102E90008FBF00188F820028000818C23108000771
+:102EA000006218212447003A244900542444002099
+:102EB000244500302446003490620040304200FF38
+:102EC0000102100730420001104000168FBF0018A9
+:102ED0000E000856AFA900108F82002894420034DB
+:102EE0000A000B733048FFFF94830036948200344D
+:102EF0001043000E8FBF001894820036A482003465
+:102F000094820056A48200548C82002CAC8200244F
+:102F100094820032A48200309482003CA482003A61
+:102F20008FBF00180A000B3327BD002003E0000804
+:102F300027BD002027BDFFE8AFBF00108F4A01006A
+:102F40003C0508008CA500E03C02080090424B8440
+:102F50003C0C0800958C4B7E01452821304B003FEE
+:102F600030A2007F03424021396900323C02000A4E
+:102F70003963003F2C630001010240212D2900012B
+:102F80002402FF8000A2282401234825AF8A0034B0
+:102F900000801821AF450024000030210080282146
+:102FA00024070001AF8800283C04080024844B78E3
+:102FB000AF8C002415200007A380002D24020020E0
+:102FC0005562000F006020213402FFFF5582000C83
+:102FD000006020212402002015620005000000008E
+:102FE0008C6300142402FFFF106200070000000041
+:102FF0000E000889000000000A000BD0000000004D
+:103000000E0008F4016028210E000B68000000008B
+:103010008FBF001024020C8027BD001803E00008B9
+:10302000AF4200243C0208008C4200E027BDFFA014
+:10303000AFB1003C008210212411FF80AFBE0058C8
+:10304000AFB70054AFB20040AFB00038AFBF005CC4
+:10305000AFB60050AFB5004CAFB40048AFB30044BA
+:10306000005110248F4800248F4900288F470028E2
+:10307000AF4200243C0208008C4200E00080902116
+:1030800024060006008210213042007F03421821EE
+:103090003C02000A006280213C02001F3442FF8093
+:1030A00000E2382427A40010260500F00122F024B5
+:1030B0000102B8240E00051DAFA700308FA2001832
+:1030C000AE0200C48FA2001CAE0200C88FA2002472
+:1030D000AE0200CC93A40010920300D12402FF8022
+:1030E0000082102400431025304900FF3083007F08
+:1030F0003122007F0062102A10400004000310C03B
+:1031000001311026304900FF000310C000031940B0
+:10311000006218213C0208008C4200DC920400D2BC
+:10312000024210210043102100511024AF42002818
+:1031300093A300103063007F000310C00003194008
+:10314000006218213C0208008C4200DC024210217F
+:10315000004310213042007F034218213C02000C42
+:10316000006240218FA300142402FFFF1062003090
+:10317000309500FF93A2001195030014304400FF26
+:103180003063FFFF0064182B1060000D000000008A
+:10319000950400148D07001C8D0600183084FFFF75
+:1031A00000442023000421000000102100E4382105
+:1031B00000E4202B00C230210A000C4A00C4302158
+:1031C000950400148D07001C8D0600183084FFFF45
+:1031D000008220230004210000001021008018211B
+:1031E00000C2302300E4202B00C4302300E3382346
+:1031F000AD07001CAD06001893A20011A502001433
+:1032000097A20012A50200168FA20014AD020010B2
+:103210008FA20014AD02000C93A20011A5020020A1
+:1032200097A20012A50200228FA20014AD02002472
+:103230002406FF80024610243256007FAF4200244D
+:10324000035618213C02000A006280218E02004CC5
+:103250008FA200203124007F000428C0AE0200505D
+:103260008FA200200004214000852821AE020070BA
+:1032700093A2001001208821A202008393A20010D3
+:10328000A2020079920200853042003FA20200852E
+:103290003C0208008C4200DC024210210045102153
+:1032A00000461024AF42002C3C0208008C4200E48F
+:1032B0003C0308008C6300DC024210210044102112
+:1032C00000461024AF4200283C0208008C4200E473
+:1032D00002431821006518210242102100441021E8
+:1032E0003042007F3063007F93A50010034220210D
+:1032F000034318213C02000E006240213C02000CF6
+:1033000010B1008C008248213233007F1660001912
+:103310002404FF803C0208008C4200DC02421021A1
+:1033200000441024AF42002C3C0208008C4200E410
+:103330003C0308008C6300DC02421021004410248E
+:10334000AF4200283C0208008C4200E402431821EE
+:103350003063007F024210213042007F034220216F
+:10336000034318213C02000E006240213C02000C85
+:10337000008248219124000D2414FF8000001021B8
+:1033800000942025A124000D950400029505001449
+:103390008D07001C3084FFFF30A5FFFF8D0600184D
+:1033A000008520230004210000E4382100C23021E0
+:1033B00000E4202B00C43021AD07001CAD0600182E
+:1033C00095020002A5020014A50000168D02000857
+:1033D000AD0200108D020008AD02000C9502000243
+:1033E000A5020020A50000228D020008AD020024E5
+:1033F0009122000D30420040104000422622000180
+:103400003C0208008C4200E0A3B300283C10000AF4
+:103410000242102100541024AF4200243C02080054
+:103420008C4200E0A380002C27A4002C0242102133
+:103430003042007F03421821007018218C6200D8AE
+:103440008D26000427A50028AFA9002C00461021D6
+:10345000AC6200D80E0009E1AF83002893A30028D6
+:103460008F8200280E000626A04300D10E000B68B4
+:103470000000000002541024AF4200243C02080067
+:103480008C4200DC00132940001320C000A420213E
+:10349000024210210044102100541024AF42002C9D
+:1034A0003C0208008C4200E43C0308008C6300DC12
+:1034B00003563021024210210045102100541024EF
+:1034C000AF4200283C0208008C4200E4024318216D
+:1034D0000064182102421021004510213042007F73
+:1034E0003063007F03422021034318213C02000E79
+:1034F000006240213C02000C00D080210082482163
+:10350000262200013043007F14750005304400FF7F
+:103510002403FF800223102400431026304400FFC0
+:1035200093A2001000808821250800281444FF760B
+:103530002529002093A400108FA300142402FFFF6C
+:103540001062000A308900FF2482000124830001F8
+:103550003042007F14550005306900FF2403FF80CE
+:103560000083102400431026304900FF92020078A7
+:10357000305300FF11330032012088213C02080043
+:103580008C4200DC3225007F000520C00005294068
+:1035900000A42021024210212406FF8000441021B3
+:1035A00000461024AF42002C3C0308008C6300DC72
+:1035B0003C0208008C4200E4024318210242102120
+:1035C0000045102100641821004610243063007F5C
+:1035D000AF420028034318213C02000E0062402144
+:1035E0003C0208008C4200E48D06000C0100202102
+:1035F00002421021004510213042007F0342182171
+:103600003C02000C0062482110C0000D012028215E
+:103610000E00064A000000002402FF800222182447
+:1036200026240001006228263082007F1455000203
+:10363000308300FF30A300FF1473FFD000608821A7
+:103640008E0300743C027FFF3442FFFF00621824A7
+:10365000AE0300740E00066B02402021AF57002419
+:103660008FA20030AF5E00288FBF005C8FBE005875
+:103670008FB700548FB600508FB5004C8FB4004800
+:103680008FB300448FB200408FB1003C8FB0003840
+:1036900027BD006003E00008AF42002C27BDFFD823
+:1036A000AFB1001CAFBF0020AFB000182751018898
+:1036B000922200032408FF803C03000A3047007F69
+:1036C000A3A700108F4601803C0208008C4200E056
+:1036D000AF86003400C2282100A81024AF42002485
+:1036E0009224000030A2007F0342102100431021E9
+:1036F000AF8200283084007F24020002148200255B
+:10370000000719403C0208008C4200E400C210216E
+:103710000043282130A2007F0342182100A8102472
+:10372000AF4200283C02000C006218219062000D9C
+:10373000AFA3001400481025A062000D8FA3001451
+:103740009062000D304200405040006A8FBF002060
+:103750008F860028A380002C27A400148CC200D8D8
+:103760008C63000427A50010004310210E0009E11E
+:10377000ACC200D893A300108F8200280E0006264A
+:10378000A04300D10E000B68000000000A000E0BE1
+:103790008FBF00200E00062F00C020210E00063D26
+:1037A000000000003C020008034280219223000137
+:1037B0009202007B1443004F8FBF00209222000032
+:1037C0003044007F24020004108200172882000584
+:1037D00010400006240200052402000310820007A6
+:1037E0008FB1001C0A000E0C0000000010820012B5
+:1037F0008FBF00200A000E0C8FB1001C92050083C1
+:10380000920600788E0700748F84003430A500FF84
+:1038100000073E0230C600FF0E00067330E7007F4F
+:103820000A000E0B8FBF00200E000BD78F840034D0
+:103830000A000E0B8FBF002024020C80AF42002430
+:103840009202003E30420040104000200000000084
+:103850009202003E00021600000216030441000618
+:10386000000000008F8400340E0005A024050093A2
+:103870000A000E0B8FBF00209202003F24030018A5
+:10388000304200FF1443000C8F84003424050039BB
+:103890000E000538000030210E0002508F840034E5
+:1038A00024020012A202003F0E0002598F8400344D
+:1038B0000A000E0B8FBF0020240500360E000538CD
+:1038C000000030210A000E0B8FBF00200E000250B6
+:1038D0008F8400349202000534420020A2020005C9
+:1038E0000E0002598F8400340E000FC08F84003404
+:1038F0008FBF00208FB1001C8FB0001824020C80F5
+:1039000027BD002803E00008AF42002427BDFFE8E0
+:10391000AFB00010AFBF001427430100946200084D
+:103920000002140000021403044100020000802180
+:103930002410000194620008304200801040001AF8
+:10394000020010219462000830422000104000164E
+:10395000020010218C6300183C021C2D344219ED2A
+:10396000240600061062000F3C0760213C0208009C
+:103970008C4200D4104000078F8200288F830028DB
+:10398000906200623042000F34420040A062006248
+:103990008F8200288F840034944500D40E000AF1F1
+:1039A00030A5FFFF020010218FBF00148FB0001060
+:1039B00003E0000827BD001827BDFFE0AFB10014E9
+:1039C000AFB00010A380002CAFBF00188F450100DE
+:1039D0003C0308008C6300E02402FF80AF850034C4
+:1039E00000A318213064007F0344202100621824C2
+:1039F0003C02000A00822021AF430024275001002E
+:103A00008E0200148C8300DCAF8400280043102356
+:103A100018400004000088218E0200140E000A8461
+:103A2000AC8200DC9202000B24030002304200FF53
+:103A30001443002F0000000096020008304300FFEE
+:103A40002402008214620005240200840E00093E54
+:103A5000000000000A000E97000000001462000938
+:103A6000240200818F8200288F8400343C0760216B
+:103A7000944500D49206000530A5FFFF0A000E868B
+:103A800030C600FF14620027000000009202000A06
+:103A9000304300FF306200201040000430620040DC
+:103AA0008F8400340A000E82240600401040000477
+:103AB000000316008F8400340A000E8224060041A1
+:103AC00000021603044100178F84003424060042CC
+:103AD0008F8200283C076019944500D430A5FFFF71
+:103AE0000E000AF1000000000A000E97000000001E
+:103AF0009202000B24030016304200FF1043000620
+:103B0000000000009202000B24030017304200FF67
+:103B100014430004000000000E000E11000000001D
+:103B2000004088210E000B68000000009202000A8D
+:103B3000304200081040000624020C808F850028C7
+:103B40003C0400080E0011EE0344202124020C80E6
+:103B5000AF4200248FBF0018022010218FB0001048
+:103B60008FB1001403E0000827BD002027BDFFE847
+:103B7000AFBF0014AFB000108F5000243C0308000A
+:103B80008C6300E08F4501002402FF8000A3182110
+:103B90003064007F03442021006218243C02000AA4
+:103BA00000822021AF850034AF4300249082006260
+:103BB000AF8400283042000F34420050A0820062DF
+:103BC0003C02001F3442FF800E00062602028024C1
+:103BD000AF5000248FBF00148FB0001003E0000826
+:103BE00027BD00183C0208008C4200201040001D38
+:103BF0002745010090A300093C0200080342202150
+:103C000024020018546200033C0200080A000ED887
+:103C10002402000803422021240200161462000539
+:103C20002402001724020012A082003F0A000EE2C4
+:103C300094A700085462000694A700089362000548
+:103C40002403FFFE00431024A362000594A700088C
+:103C500090A6001B8CA4000094A500060A000ACCC4
+:103C600000073C0003E000080000000027440100BA
+:103C700094820008304500FF38A3008238A20084F7
+:103C80002C6300012C420001006218251060000620
+:103C9000240200839382002D1040000D00000000DC
+:103CA0000A000B9B0000000014A2000524A2FF8064
+:103CB0008F4301043C02602003E00008AC43001481
+:103CC000304200FF2C420002104000032402002278
+:103CD0000A000E3C0000000014A2000300000000D7
+:103CE0000A000EA9000000000A000EC70000000034
+:103CF0009363007E9362007A144300090000202140
+:103D00009362000024030050304200FF144300047B
+:103D1000240400019362007E24420001A362007E1D
+:103D200003E00008008010218F4201F80440FFFEEC
+:103D300024020002AF4401C0A34201C43C021000AF
+:103D400003E00008AF4201F827BDFFE8AFBF001055
+:103D50009362003F2403000A304200FF14430046F0
+:103D6000000000008F6300548F62004C1062007DE1
+:103D7000036030219362000024030050304200FFB2
+:103D80001443002F000000008F4401403C02080053
+:103D90008C4200E02403FF800082102100431024A5
+:103DA000AF4200243C0208008C4200E08F650054C2
+:103DB0003C03000A008220213084007F034410214C
+:103DC00000431021AC4501089762003C8F63004C12
+:103DD0003042FFFF0002104000621821AF63005C18
+:103DE0008F6300548F64004C9762003C006418237A
+:103DF0003042FFFF00031843000210400043102A26
+:103E000010400006000000008F6200548F63004CD9
+:103E1000004310230A000F58000210439762003C31
+:103E20003042FFFF00021040ACC2006424020001D7
+:103E3000A0C0007CA0C2008424020C80AF420024F9
+:103E40000E000F0A8F440140104000478FBF001042
+:103E50008F4301408F4201F80440FFFE240200021C
+:103E6000AF4301C0A34201C43C021000AF4201F8BD
+:103E70000A000FA88FBF00109362003F24030010B8
+:103E8000304200FF14430004000000008F44014052
+:103E90000A000F94000028219362003F24030016BB
+:103EA000304200FF1443000424020014A362003FC8
+:103EB0000A000FA2000000008F62004C8F630050C8
+:103EC00000431023044100288FBF0010936200813B
+:103ED00024420001A3620081936200812C4200040D
+:103EE00014400010000000009362003F240300040F
+:103EF000304200FF14430006000000008F440140E0
+:103F00008FBF0010240500930A0005A027BD0018EC
+:103F10008F440140240500938FBF00100A00060F54
+:103F200027BD00188F4401400E0002500000000021
+:103F30008F6200542442FFFFAF6200548F62005032
+:103F40002442FFFFAF6200500E0002598F4401402F
+:103F50008F4401408FBF0010240500040A00025E58
+:103F600027BD00188FBF001003E0000827BD001810
+:103F70008F4201889363007E00021402304400FFE8
+:103F8000306300FF1464000D0000000093620080A5
+:103F9000304200FF1044000900000000A3640080CC
+:103FA0009362000024030050304200FF14430004D9
+:103FB000000000000A0006D78F440180A36400803F
+:103FC00003E000080000000027BDFFE8AFB00010CC
+:103FD000AFBF00149362000524030030304200306C
+:103FE00014430089008080213C0208008C4200209C
+:103FF00010400080020020210E0004930000000009
+:104000008F850020ACB000009362003E9363003FB8
+:10401000304200FF00021200306300FF0043102511
+:10402000ACA2000493620082000216000002160394
+:1040300004410005000000003C0308008C630048B8
+:104040000A000FE6000000009362003E304200408C
+:10405000144000030000182193620081304300FFE8
+:104060009362008200031E00304200FF0002140031
+:1040700000621825ACA300088F620040ACA2000CBF
+:104080008F620048ACA200108F62004CACA20014FA
+:104090008F6200508F63004C0043102304410003E3
+:1040A000000000000A000FFA8F62004C8F6200507F
+:1040B000ACA200183C02080094424B5E3C03C00BCB
+:1040C00000002021004310250E0004B8ACA2001C03
+:1040D0008F6200548F840020AC8200008F620058F1
+:1040E000AC8200048F62005CAC8200088F620060CA
+:1040F0008F43007400431021AC82000C8F62006477
+:10410000AC820010976300689762006A00031C008D
+:104110003042FFFF00621825AC83001493620082D6
+:1041200024030080304200FF14430003000000001D
+:104130000A00102EAC8000188F63000C24020001CE
+:104140001062000E2402FFFF9362003E30420040E6
+:104150001440000A2402FFFF8F63000C8F4200749A
+:10416000006218233C020800006210241440000280
+:10417000000028210060282100051043AC820018AF
+:104180003C02080094424B5E3C03C00C000020211E
+:10419000004310258F8300200E0004B8AC62001C81
+:1041A0008F6200188F8300203C05080094A54B5EA9
+:1041B00024040001AC620000AC6000048F66006C57
+:1041C0003C02400D00A22825AC6600088F6200DC8E
+:1041D000AC62000CAC600010936200050002160097
+:1041E000AC620014AC6000180E0004B8AC65001C92
+:1041F000020020218FBF00148FB00010A3600005C3
+:104200000A00042127BD00188FBF00148FB00010D2
+:1042100003E0000827BD00189742007C30C600FF6D
+:10422000A08600843047FFFF2402000514C2000B63
+:1042300024E3465090A201122C42000710400007D0
+:1042400024E30A0090A30112240200140062100467
+:1042500000E210210A0010663047FFFF3067FFFFC1
+:1042600003E00008A4870014AC87004C8CA201086E
+:104270000080402100A0482100E2102330C600FF4A
+:104280001840000393AA001324E2FFFCACA201082B
+:1042900030C2000110400008000000008D020050F4
+:1042A00000E2102304410013240600058D0200548F
+:1042B00010E20010000000008D02005414E2001A09
+:1042C000000000003C0208008C4200D83042002070
+:1042D0001040000A2402000191030078910200833B
+:1042E000144300062402000101002021012028219E
+:1042F000240600040A00105400000000A1000084FD
+:1043000011400009A50200148F4301008F4201F8FB
+:104310000440FFFE24020002AF4301C0A34201C4D7
+:104320003C021000AF4201F803E00008000000006A
+:1043300027BDFFE88FA90028AFBF001000804021F3
+:1043400000E918231860007330C600FFA080007CCD
+:10435000A08000818CA2010800E210230440004DDF
+:10436000000000008C8200509483003C8C84006428
+:10437000004748233063FFFF012318210083202BCF
+:1043800010800004000000008D0200640A0010B7D5
+:1043900000E210219502003C3042FFFF0122102173
+:1043A00000E21021AD02005C9502003C8D03005C30
+:1043B0003042FFFF0002104000E210210043102BAA
+:1043C00010400003000000000A0010C68D02005CCF
+:1043D0009502003C3042FFFF0002104000E2102135
+:1043E000AD02005CA1000084AD07004C8CA2010866
+:1043F00000E210231840000224E2FFFCACA20108F6
+:1044000030C200011040000A000000008D02005080
+:1044100000E2102304410004010020218D02005419
+:1044200014E20003000000000A0010E82406000562
+:104430008D02005414E200478FBF00103C020800B8
+:104440008C4200D8304200201040000A24020001B3
+:1044500091030078910200831443000624020001B6
+:1044600001002021240600048FBF00100A00105410
+:1044700027BD0018A1000084A50200148F4301008D
+:104480008F4201F80440FFFE240200020A00110DD1
+:10449000000000008C82005C004910230043102BB8
+:1044A00054400001AC87005C9502003C3042FFFFA5
+:1044B0000062102B14400007240200029502003C09
+:1044C0008D03005C3042FFFF00621821AD03005CE9
+:1044D00024020002AD07004CA10200840E000F0A66
+:1044E0008F4401001040001B8FBF00108F4301005C
+:1044F0008F4201F80440FFFE24020002AF4301C0D6
+:10450000A34201C43C021000AF4201F80A0011238B
+:104510008FBF001030C200101040000E8FBF00107F
+:104520008C83005C9482003C006918233042FFFFBA
+:10453000006218213C023FFF3444FFFF0083102B30
+:10454000544000010080182101231021AD02005CBD
+:104550008FBF001003E0000827BD001827BDFFE84B
+:104560008FAA0028AFBF00100080402100EA482336
+:104570001920002130C600FF8C83005C8C8200640F
+:10458000006A18230043102B5040001000691821C6
+:1045900094A2011001221021A4A2011094A20110E2
+:1045A0003042FFFF0043102B1440000A3C023FFF43
+:1045B00094A2011000431023A4A201109482003C95
+:1045C0003042FFFF0A00114200621821A4A001102E
+:1045D0003C023FFF3444FFFF0083102B5440000196
+:1045E0000080182100671021AD02005CA100007C52
+:1045F0000A00118AA100008130C200101040003C66
+:10460000000000008C820050004A1023184000383F
+:10461000000000009082007C24420001A082007C07
+:104620009082007C3C0308008C630024304200FF31
+:104630000043102B1440005C8FBF00108CA20108B7
+:1046400000E2102318400058000000008C83005442
+:104650009482003C006A18233042FFFF0003184395
+:10466000000210400043102A104000050000000026
+:104670008C820054004A10230A001171000210437A
+:104680009482003C3042FFFF00021040AD02006403
+:104690009502003C8D0400649503003C3042FFFF0E
+:1046A00000021040008220213063FFFF00831821A8
+:1046B00001431021AD02005C8D020054ACA2010840
+:1046C00024020002A10200840E000F0A8F440100A0
+:1046D000104000358FBF00108F4301008F4201F85A
+:1046E0000440FFFE240200020A0011B30000000093
+:1046F000AD07004C8CA2010800E210231840000214
+:1047000024E2FFFCACA2010830C200011040000A04
+:10471000000000008D02005000E21023044100045C
+:10472000010020218D02005414E20003000000006B
+:104730000A0011AA240600058D02005414E2001A92
+:104740008FBF00103C0208008C4200D8304200208D
+:104750001040000A240200019103007891020083B6
+:104760001443000624020001010020212406000455
+:104770008FBF00100A00105427BD0018A10000844C
+:10478000A50200148F4301008F4201F80440FFFE90
+:1047900024020002AF4301C0A34201C43C02100046
+:1047A000AF4201F88FBF001003E0000827BD0018DA
+:1047B0008FAA00108C8200500080402130C600FF7C
+:1047C000004A102300A048211840000700E01821EB
+:1047D00024020001A0800084A0A00112A482001481
+:1047E0000A001125AFAA0010A0800081AD07004C7F
+:1047F0008CA2010800E210231840000224E2FFFC12
+:10480000ACA2010830C20001104000080000000006
+:104810008D0200500062102304410013240600059D
+:104820008D02005410620010000000008D02005440
+:1048300014620011000000003C0208008C4200D805
+:10484000304200201040000A240200019103007849
+:10485000910200831443000624020001010020217C
+:1048600001202821240600040A0010540000000042
+:10487000A1000084A502001403E00008000000006D
+:1048800027BDFFE0AFBF0018274201009046000A95
+:104890008C4800148C8B004C9082008430C900FF3F
+:1048A00001681823304A00FF1C60001A2D460006DC
+:1048B000240200010142100410C00016304300031E
+:1048C000012030210100382114600007304C000C19
+:1048D00015800009304200301440000B8FBF0018D3
+:1048E0000A001214000000000E001125AFAB0010EA
+:1048F0000A0012148FBF00180E00109AAFAB001000
+:104900000A0012148FBF0018AFAB00100E0011BACE
+:10491000AFAA00148FBF001803E0000827BD0020D5
+:1049200024020003A08200848C82005403E000086B
+:10493000ACA201083C0200080342182190620081E9
+:10494000240600433C07601924420001A062008154
+:10495000906300813C0208008C4200C0306300FF7D
+:10496000146200102403FF803C0208008C4200E027
+:104970000082102100431024AF4200243C020800B2
+:104980008C4200E03C03000A008210213042007F8C
+:104990000342102100431021944500D40A000AF17B
+:1049A00030A5FFFF03E000080000000027BDFFE086
+:1049B000AFBF0018AFB10014AFB000108F4201803C
+:1049C0000080802100A088210E00121B00402021C1
+:1049D000A20000848E0200548FBF00188FB0001018
+:1049E000AE2201088FB1001403E0000827BD0020AB
+:1049F00027BDFFE03C020008AFB00010AFBF0018B9
+:104A0000AFB10014034280218F5101409203008412
+:104A10008E0400508E02004C14820040306600FF6D
+:104A20003C0208008C4200E02403FF800222102197
+:104A300000431024AF4200243C0208008C4200E0F6
+:104A40009744007C92050081022210213042007FB1
+:104A5000034218213C02000A0062182114A0000B36
+:104A60003084FFFF2402000554C20014248205DCB8
+:104A70009062011224420001A062011224020C8003
+:104A8000AF4200240A00127324020005A060011244
+:104A90002402000514C20009248205DC9202008170
+:104AA0002C4200075040000524820A009203008136
+:104AB0002402001400621004008210213044FFFF21
+:104AC000A60400140E00121B022020219602003CB6
+:104AD0008E03004C022020213042FFFF00021040D4
+:104AE000006218210E000250AE03005C9202007DAD
+:104AF00002202021344200400E000259A202007D13
+:104B00008F4201F80440FFFE24020002AF5101C0B1
+:104B1000A34201C43C021000AF4201F88FBF00184D
+:104B20008FB100148FB0001003E0000827BD0020F3
+:104B300008000ACC08000B1408000B9808000BE4CE
+:104B400008000C200A0000280000000000000000FF
+:104B50000000000D6370362E322E3300000000007E
+:104B60000602030400000000000000000000000036
+:104B70000000000000000000000000000000000035
+:104B80000000000000000000000000000000002005
+:104B90000000000000000000000000000000000015
+:104BA0000000000000000000000000000000000005
+:104BB00000000000000000000000000000000001F4
+:104BC0000000002B000000000000000400030D4066
+:104BD00000000000000000000000000000000000D5
+:104BE00000000000000000001000000300000000B2
+:104BF0000000000D0000000D3C020800244258A4F3
+:104C00003C03080024635F70AC4000000043202B8D
+:104C10001480FFFD244200043C1D080037BD7FFCCA
+:104C200003A0F0213C100800261000A03C1C080046
+:104C3000279C58A40E0001AC000000000000000DED
+:104C400027BDFFE83C096018AFBF00108D2C500055
+:104C5000240DFF7F24080031018D5824356A380C5B
+:104C600024070C003C1A8000AD2A50003C04800A46
+:104C7000AF4800083C1B8008AF4700240E00091510
+:104C8000AF8400100E0008D8000000000E000825B8
+:104C9000000000000E001252000000003C046016EC
+:104CA0008C8500003C06FFFF3C02535300A61824ED
+:104CB0001062004734867C0094C201F2A780002C69
+:104CC00010400003A78000CC38581E1EA798002C67
+:104CD00094C201F810400004978300CC38591E1E7E
+:104CE000A79900CC978300CC2C7F006753E000018C
+:104CF000240300669784002C2C82040114400002D7
+:104D000000602821240404003C0760008CE904387A
+:104D10002403103C3128FFFF1103001F30B9FFFFAF
+:104D200057200010A38000CE24020050A38200CEA2
+:104D3000939F00CE53E0000FA78500CCA78000CC46
+:104D4000978500CC8FBF0010A780002CA78000346F
+:104D5000A78000E63C010800AC25008003E00008C5
+:104D600027BD0018939F00CE57E0FFF5A78000CC29
+:104D7000A78500CC978500CC8FBF0010A784002C9E
+:104D8000A7800034A78000E63C010800AC25008025
+:104D900003E0000827BD0018A38000CE8CCB003CA8
+:104DA000316A00011140000E0000000030A7FFFF33
+:104DB00010E0FFDE240200508CCC00C831860001D8
+:104DC00014C0FFDC939F00CE0A00007A2402005139
+:104DD0008C8F00043C0E60000A00005D01EE302163
+:104DE0008CEF0808240D5708000F740211CD000441
+:104DF00030B8FFFF240500660A00007B240404008D
+:104E00001700FFCC939F00CE0A00007A24020050C6
+:104E10008F8600103089FFFF000939408CC30010D5
+:104E20003C08005000E82025AF4300388CC5001432
+:104E300027420400AF82001CAF45003CAF44003065
+:104E40000000000000000000000000000000000062
+:104E50000000000000000000000000000000000052
+:104E60008F4B0000316A00201140FFFD0000000060
+:104E700003E00008000000008F840010948A001AEC
+:104E80008C8700243149FFFF000940C000E8302131
+:104E9000AF46003C8C8500248F43003C00A31023C8
+:104EA00018400029000000008C8B002025620001C2
+:104EB0003C0D005035AC0008AF420038AF4C00301C
+:104EC00000000000000000000000000000000000E2
+:104ED00000000000000000000000000000000000D2
+:104EE0008F4F000031EE002011C0FFFD00000000D8
+:104EF0008F4A04003C080020AC8A00108F4904044B
+:104F0000AC890014AF4800300000000094860018FF
+:104F10009487001C00C71821A48300189485001AE8
+:104F200024A20001A482001A9498001A9499001EE9
+:104F3000133800030000000003E000080000000038
+:104F400003E00008A480001A8C8200200A0000DC24
+:104F50003C0D00500A0000CD000000003C0308009A
+:104F60008C6300208F82001827BDFFE810620008C4
+:104F7000AFBF00100E000104AF8300183C0308000F
+:104F80008C63002024040001106400048F89001049
+:104F90008FBF001003E0000827BD00188FBF00106E
+:104FA0003C076012A520000A9528000A34E500108D
+:104FB00027BD00183106FFFF03E00008ACA60090F3
+:104FC0003C0208008C42002027BDFFC8AFBF003460
+:104FD000AFBE0030AFB7002CAFB60028AFB500248D
+:104FE000AFB40020AFB3001CAFB20018AFB10014D3
+:104FF00010400050AFB000108F840010948600065F
+:105000009483000A00C3282330B6FFFF12C0004A71
+:105010008FBF003494890018948A000A012A402323
+:105020003102FFFF02C2382B14E0000202C020212F
+:10503000004020212C8C0005158000020080A0215A
+:10504000241400040E0000B3028020218F8700107A
+:1050500002809821AF80001494ED000A028088211C
+:105060001280004E31B2FFFF3C1770003C1540002B
+:105070003C1E60008F8F001C8DEE000001D71824AD
+:10508000507500500220202102A3802B160000350D
+:105090003C182000507800470220202124100001F5
+:1050A0008F83001414600039029158230230F823D2
+:1050B0000250C82133F1FFFF1620FFEE3332FFFF0D
+:1050C0008F8700103C110020AF510030000000001D
+:1050D00094E6000A3C1E601237D5001002662821B3
+:1050E000A4E5000A94E2000A94F2000A94F400187D
+:1050F0003057FFFF1292003BAEB700908CED0014CA
+:105100008CE400100013714001AE4021000E5FC31B
+:10511000010E502B008B4821012A1821ACE8001405
+:10512000ACE3001002D3382330F6FFFF16C0FFB9FE
+:105130008F8400108FBF00348FBE00308FB7002CDB
+:105140008FB600288FB500248FB400208FB3001CC9
+:105150008FB200188FB100148FB0001003E0000868
+:1051600027BD0038107E001B000000001477FFCC24
+:10517000241000010E00159B000000008F83001416
+:105180001060FFCB0230F823029158238F87001064
+:10519000017020210A0001973093FFFF8F830014D4
+:1051A0001460FFCB3C110020AF5100300A000163B6
+:1051B000000000000E00077D024028210A00015770
+:1051C000004080210E00033A024028210A000157C6
+:1051D000004080210E001463022020210A000157A4
+:1051E000004080210E0000CD000000000A0001797F
+:1051F00002D3382327BDFFE8AFB00010AFBF0014C3
+:105200000E00003F000000003C028000345000709F
+:105210000A0001BA8E0600008F4F000039EE00012F
+:1052200031C20001104000248F8600A88E070000C4
+:105230003C0C08008D8C003C3C0908008D2900388E
+:1052400000E66823018D28210000502100AD302B9D
+:10525000012A4021010620213C010800AC25003C28
+:10526000AF8700A83C010800AC2400380E000106FE
+:10527000000000003C0308008C6300701060FFE633
+:10528000006020213C0508008CA500683C06080051
+:105290008CC6006C0E00152A000000003C010800BE
+:1052A000AC2000708F4F000039EE000131C20001C8
+:1052B0001440FFDE8F8600A88E0A00008F8B00A8A6
+:1052C0003C0508008CA5003C3C0408008C84003898
+:1052D000014B482300A938210082182100E9402B06
+:1052E000006810213C010800AC27003C3C0108008C
+:1052F000AC2200388F5F01002419FF0024180C0035
+:1053000003F9202410980012AF840000AF4400205D
+:10531000936D0000240C002031A600FF10CC001279
+:10532000240E005010CE00043C194000AF59013843
+:105330000A0001B3000000000E0011C800000000C8
+:105340003C194000AF5901380A0001B300000000C9
+:105350000E00011F000000003C194000AF59013849
+:105360000A0001B3000000008F58010000802821CE
+:10537000330F00FF01E020210E0002F1AF8F000487
+:105380003C194000AF5901380A0001B30000000089
+:1053900000A4102B2403000110400009000030215C
+:1053A0000005284000A4102B04A0000300031840AF
+:1053B0005440FFFC000528405060000A0004182BF0
+:1053C0000085382B54E000040003184200C3302548
+:1053D00000852023000318421460FFF900052842CD
+:1053E0000004182B03E0000800C310218F4201B80D
+:1053F0000440FFFE00000000AF4401803C031000A9
+:1054000024040040AF450184A3440188A3460189D8
+:10541000A747018A03E00008AF4301B83084FFFFCB
+:105420000080382130A5FFFF000020210A00022A59
+:10543000240600803087FFFF8CA40000240600387B
+:105440000A00022A000028218F8300388F8600304E
+:105450001066000B008040213C07080024E75A1822
+:10546000000328C000A710218C4400002463000121
+:10547000108800053063000F5466FFFA000328C04F
+:1054800003E00008000010213C07080024E75A1C34
+:1054900000A7302103E000088CC200003C0390000C
+:1054A0003462000100822025AF4400208F45002097
+:1054B00004A0FFFE0000000003E000080000000060
+:1054C0003C038000346200010082202503E00008D4
+:1054D000AF44002027BDFFE0AFB100143091FFFFC3
+:1054E000AFB00010AFBF00181220001300A0802141
+:1054F0008CA2000024040002240601401040000F8A
+:10550000004028210E000C5C00000000000010216B
+:10551000AE000000022038218FBF00188FB10014A8
+:105520008FB0001000402021000028210000302111
+:105530000A00022A27BD00208CA200000220382188
+:105540008FBF00188FB100148FB0001000402021D1
+:1055500000002821000030210A00022A27BD002077
+:1055600000A010213087FFFF8CA500048C440000B0
+:105570000A00022A2406000627BDFFE0AFB0001093
+:10558000AFBF0018AFB100149363003E00808021CC
+:105590000080282130620040000020211040000FD0
+:1055A0008E1100000E000851022020219367000098
+:1055B0002404005030E500FF50A400128E0F0000BC
+:1055C000022020218FBF00188FB100148FB000106F
+:1055D000A762013C0A00091127BD00200E000287C6
+:1055E000000000000E0008510220202193670000F7
+:1055F0002404005030E500FF14A4FFF20220202113
+:105600008E0F00003C1008008E1000503C0D000C66
+:10561000240BFF8001F05021314E007F01DA602120
+:10562000018D4021014B4824AF4900280220202150
+:105630008FBF00188FB100148FB00010A50200D6E4
+:1056400027BD00200A000911AF8800D027BDFFE068
+:10565000AFBF0018AFB10014AFB0001093660001E7
+:10566000008080210E00025630D1000493640005B2
+:10567000001029C2A765000034830040A363000521
+:105680000E00025F020020210E00091302002021FB
+:1056900024020001AF62000C02002821A762001062
+:1056A00024040002A762001224060140A76200142D
+:1056B0000E000C5CA76200161620000F8FBF0018AA
+:1056C000978C00343C0B08008D6B00782588FFFF19
+:1056D0003109FFFF256A0001012A382B10E000067E
+:1056E000A78800343C0F6006240E001635ED00102C
+:1056F000ADAE00508FBF00188FB100148FB00010F6
+:1057000003E0000827BD002027BDFFE0AFB1001473
+:10571000AFBF0018AFB0001000A088211080000AB1
+:105720003C03600024020080108200120000000090
+:105730000000000D8FBF00188FB100148FB0001053
+:1057400003E0000827BD00208C682BF80500FFFE51
+:1057500000000000AC712BC08FBF00188FB1001487
+:105760008FB000103C09100027BD002003E00008A6
+:10577000AC692BF80E00025600A0202193650005AD
+:10578000022020210E00025F30B000FF2403003E03
+:105790001603FFE7000000008F4401780480FFFE3D
+:1057A000240700073C061000AF51014002202021D1
+:1057B000A34701448FBF00188FB100148FB00010B1
+:1057C000AF4601780A0002C227BD002027BDFFE8CE
+:1057D000AFBF0014AFB000108F50002000000000D9
+:1057E0000E000913AF440020AF5000208FBF0014FB
+:1057F0008FB0001003E0000827BD00183084FFFFC1
+:10580000008038212406003500A020210A00022A49
+:10581000000028213084FFFF008038212406003654
+:1058200000A020210A00022A0000282127BDFFD065
+:10583000AFB3001C3093FFFFAFB50024AFB2001828
+:10584000AFBF0028AFB40020AFB10014AFB000105C
+:1058500030B5FFFF12600027000090218F90001CE0
+:105860008E0300003C0680002402004000033E023C
+:1058700000032C0230E4007F006688241482001D9F
+:1058800030A500FF8F8300282C68000A510000100B
+:105890008F910014000358803C0C0800258C56940E
+:1058A000016C50218D49000001200008000000001B
+:1058B00002B210213045FFFF0E000236240400849E
+:1058C000162000028F90001CAF8000288F910014DA
+:1058D000260C002026430001018080213072FFFF4A
+:1058E00016200004AF8C001C0253502B1540FFDC27
+:1058F00000000000024010218FBF00288FB5002457
+:105900008FB400208FB3001C8FB200188FB1001429
+:105910008FB0001003E0000827BD0030240E0034D3
+:1059200014AE00F9000000009203000E241F168040
+:105930003C07000CA36300219202000D0347C8211D
+:105940003C066000A3620020961100123C0A7FFF13
+:10595000354CFFFFA771003C960B00102403000597
+:105960003168FFFFAF6800848E05001CAF5F002820
+:105970008F3800008CC4444803057826008F3021FE
+:10598000AF66004C8F69004C24CE00013C057F00BF
+:10599000AF6900508F740050AF740054AF66007050
+:1059A000AF6E00588F6D005824140050AF6D005C2E
+:1059B000A3600023AF6C0064A36300378E02001461
+:1059C000AF6200488F710048AF7100248E0B001841
+:1059D000AF6B006C9208000CA3680036937F003E0A
+:1059E00037F90020A379003E8F78007403058024E6
+:1059F000360F4000AF6F007493640000308900FFE1
+:105A0000513402452404FF803C04080024845A9841
+:105A10000E00028D000000003C1008008E105A9805
+:105A20000E00025602002021240600042407000173
+:105A3000A366007D020020210E00025FA36700051F
+:105A40008F5F017807E0FFFE240B0002AF5001409A
+:105A5000A34B01448F90001C3C081000AF48017814
+:105A60000A000362AF8000282CAD003751A0FF98D8
+:105A70008F9100140005A0803C180800271856BC20
+:105A8000029878218DEE000001C00008000000009F
+:105A90002418000614B80011000000003C0808009B
+:105AA0008D085A9824040005AF4800208E1F001866
+:105AB000AF7F00188F79004CAF79001C8F650050C4
+:105AC000122000C0AF6500700A000362AF84002896
+:105AD0002406000710A60083240300063C050800E6
+:105AE00024A55A980E000264240400818F90001CA3
+:105AF0000011102B0A000362AF8200282407000463
+:105B000014A7FFF6240500503C1808008F185A9877
+:105B1000AF5800208E0F0008AF6F00408E090008BC
+:105B2000AF6900448E14000CAF7400488E0E001054
+:105B3000AF6E004C8E0D0010AF6D00848E0A001405
+:105B4000AF6A00508E0C0018AF6C00548E04001C1D
+:105B5000AF64005893630000306B00FF116501D8FB
+:105B6000000000008F7400488F6900400289702394
+:105B700005C000042404008C1620FFDE240200036C
+:105B8000240400823C05080024A55A980E000287D0
+:105B9000000000008F90001C000010210A0003622A
+:105BA000AF820028240F000514AFFFCC240520008D
+:105BB0003C0708008CE75A98AF4700208E06000487
+:105BC000AF66005C9208000824100008A36800215A
+:105BD0008F9F001C93F90009A37900208F86001C79
+:105BE00090D8000A330400FF10900011000000005C
+:105BF0002885000914A0006924020002240A00205C
+:105C0000108A000B34058000288D002115A00008A3
+:105C100024054000240E0040108E00053C050001C4
+:105C200024140080109400023C050002240540006A
+:105C30008F7800743C19FF00031980240205782531
+:105C4000AF6F007490C4000BA36400818F84001CAC
+:105C50009489000C11200192000000009490000C27
+:105C60002406FFBF24050004A770003C908F000E9F
+:105C7000A36F003E8F84001C9089000FA369003F32
+:105C80008F8B001C8D6E00108F54007401D468231C
+:105C9000AF6D00608D6A0014AF6A0064956C0018E7
+:105CA000A76C00689563001AA763006A8D62001CE8
+:105CB000AF62006C9167000EA367003E9368003EE0
+:105CC0000106F8241220014BA37F003E8F90001C98
+:105CD0000A000362AF8500282407002214A7FF7F73
+:105CE000240300073C0B08008D6B5A981220000C0F
+:105CF000AF4B00200A000362AF830028240C00335E
+:105D000010AC0014240A00283C05080024A55A9869
+:105D10000E00023C240400810A0003EB8F90001C5B
+:105D20003C04080024845A980E00028D00000000F4
+:105D30009363000024110050306200FF10510135C0
+:105D4000000000008F90001C000018210A00036270
+:105D5000AF8300283C0D08008DAD5A9824040081C3
+:105D6000AF4D00203C05080024A55A980E00023CC7
+:105D7000A36A00348F90001C240200090A00036209
+:105D8000AF82002802B288213225FFFF0E000236C2
+:105D9000240400840A0003628F90001C1082FFA478
+:105DA00024050400288B000311600170240C0004FA
+:105DB000240300015483FF9E240540000A00043B95
+:105DC000240501003C04080024845A988F62004C8A
+:105DD0000E00028D8F6300508F90001C0000202168
+:105DE0000A000362AF8400288E1000042404008A95
+:105DF000AF50002093790005333800021700015F8F
+:105E0000020028219368002302002821311F00206E
+:105E100017E0015A2404008D9367003F2406001206
+:105E200030E200FF10460155240400810E000256A6
+:105E30000200202193630023240500040200202196
+:105E4000346B0042A36B00230E00025FA365007D4C
+:105E50008F4401780480FFFE240A0002AF50014005
+:105E6000A34A01448F90001C3C0C1000AF4C0178F9
+:105E70000A0003EC0011102B8E1000042404008A89
+:105E8000AF500020936E000531CD000215A0001622
+:105E900002002821936F003F2414000402002821EF
+:105EA00031E900FF11340010240400810E00025675
+:105EB000020020219362002324080012241FFFFE09
+:105EC00034460020A3660023A368003F93790005B1
+:105ED00002002021033FC0240E00025FA3780005CA
+:105EE00002002821000020210E00033400000000E1
+:105EF0000A0003EB8F90001C8E1000043C03000886
+:105F00000343A021AF500020928B000024050050D5
+:105F1000316400FF10850161240700880200202100
+:105F2000000028210E00022A2406000E928D000097
+:105F3000240EFF800200282101AE8025A2900000DF
+:105F4000240400040E000C5C240600300A0003EB5D
+:105F50008F90001C8E0800043C14080026945A9868
+:105F60003C010800AC285A98AF480020921F00035B
+:105F700033F9000413200002240200122402000658
+:105F8000A362003F920B001B2404FFC03165003F59
+:105F900000A43825A367003E9206000330C200012A
+:105FA00014400132000000008E020008AE8200089A
+:105FB0003C0208008C425AA010400131000249C244
+:105FC000A76900088E14000C240C0001240300149F
+:105FD000AF74002C8E0E0010AF6E0030960D0016C0
+:105FE000A76D0038960A0014A76A003AAF6C000C3F
+:105FF000A76C0010A76C0012A76C0014A76C001609
+:1060000012200136A3630034920F000331F0000226
+:106010002E1100018F90001C262200080A00036246
+:10602000AF8200288E0400043C0E0008034E30218D
+:10603000AF4400208E05000890CD0000240C0050D5
+:1060400031AA00FF114C00862407008824060009AD
+:106050000E00022A000000000A0003EB8F90001CD3
+:106060008E04001C0E00024100000000104000F4ED
+:10607000004050218F89001C240700890140202105
+:106080008D25001C240600010E00022A00000000DD
+:106090000A0003EB8F90001C960D00023C140800D0
+:1060A00026945A9831AA0004514000B83C10600070
+:1060B0008E0E001C3C010800AC2E5A98AF4E0020FA
+:1060C000920700102408001430E200FF144800D6A4
+:1060D00000000000960B00023163000114600165AE
+:1060E000000000008E020004AE8200083C1408008C
+:1060F0008E945AA01280015B000000008F7400741F
+:106100003C0380002404000102835825AF6B007417
+:10611000A3600005AF64000C3C0708008CE75AA0A0
+:106120008F86001CA7640010000711C2A76400122C
+:10613000A7640014A7640016A76200088CC80008B2
+:1061400024040002AF68002C8CC5000CAF65003041
+:1061500090DF0010A37F00348F99001C9330001152
+:10616000A37000358F98001C930F0012A36F0036A8
+:106170008F89001C912E0013A36E00378F90001C96
+:10618000960D0014A76D0038960A0016A76A003A0B
+:106190008E0C0018AF6C00245620FDCCAF84002874
+:1061A0003C05080024A55A980E0002640000202136
+:1061B0008F90001C0A0004A7000020218E1000040C
+:1061C00024070081AF500020936900233134001070
+:1061D000128000170000000002002021000028218A
+:1061E0002406001F0E00022A000000000A0003EB34
+:1061F0008F90001C3C05080024A55A980E000287C9
+:10620000240400828F90001C000028210A000362F1
+:10621000AF8500283C0408008C845A980E0014E8CE
+:10622000000000008F90001C0A000482000018216A
+:106230000E00025602002021937800230200202144
+:10624000370F00100E00025FA36F002300003821FB
+:1062500002002021000028210A0005A82406001FB2
+:10626000920F000C31E90001112000030000000032
+:106270009618000EA4D8002C921F000C33F90002CF
+:1062800013200005000038218E0200149608001229
+:10629000ACC2001CA4C8001A0A0005432406000969
+:1062A0003C05080024A55A980E0002872404008BA0
+:1062B0008F90001C0011282B0A000362AF85002874
+:1062C000AF6000843C0A08008D4A5A983C0D0800D3
+:1062D0008DAD0050240CFF803C02000C014D1821B4
+:1062E000006C2024AF4400288E070014306B007F20
+:1062F000017A282100A2C821AF2700D88E060014F9
+:10630000AF9900D0AF2600DC8E080010251FFFFEDD
+:106310000A000408AF3F01083C0508008CA55A9804
+:106320003C1908008F39005024CCFFFE00B9C02171
+:1063300003047824AF4F00283C1408008E945A9828
+:106340003C0908008D2900500289702131CD007F61
+:1063500001BA502101478021AE0600D8AF9000D08D
+:10636000AE0000DC0A0003B1AE0C0108548CFE3014
+:10637000240540000A00043B240510000E00032EF3
+:10638000000000000A0003EB8F90001C8E0F442CCD
+:106390003C186C62370979703C010800AC205A98AF
+:1063A00015E9000824050140979F00349786002CCA
+:1063B0000280282103E6C82B132000112404009238
+:1063C000240501400E000C7A240400023C01080060
+:1063D000AC225A98AF4200203C0508008CA55A9880
+:1063E00010A00005240400830E00084500000000F2
+:1063F00010400009240400833C05080024A55A9895
+:106400000E000264000000008F90001C0011202B81
+:106410000A000362AF8400280E0008490000000053
+:106420000A00055F8F90001C0E00084D0000000060
+:106430003C05080024A55A980A00062F2404008B66
+:10644000240400040E000C7A240500301440002AB5
+:10645000004050218F89001C240700830140202127
+:106460008D25001C0A000551240600018E04000839
+:106470000E000241000000000A00051BAE82000869
+:106480003C05080024A55A980E00023C240400870D
+:106490008F90001C0A0005360011102B8F830038E6
+:1064A0008F8600301066FE9D000038213C070800F2
+:1064B00024E75A1C000320C0008728218CAC000070
+:1064C00011900061246A00013143000F5466FFFA05
+:1064D000000320C00A0004F6000038213C05080033
+:1064E00024A55A980E000287240400828F90001C75
+:1064F0000A000536000010213C0B0008034B202148
+:106500002403005024070001AF420020A0830000B4
+:10651000A08700018F82001C90480004A08800180A
+:106520008F85001C90A60005A08600198F9F001C77
+:1065300093F90006A099001A8F90001C921800078A
+:10654000A098001B8F94001C928F0008A08F001C45
+:106550008F89001C912E0009A08E001D8F8D001CBC
+:1065600091AC000AA08C001E8F8B001C3C0C080014
+:10657000258C5A1C9163000B3C0B0800256B5A18A4
+:10658000A083001F8F87001C90E8000CA0880020CB
+:106590008F82001C9045000D24024646A0850021F4
+:1065A0008F86001C90DF000EA09F00228F99001C98
+:1065B0009330000FA09000238F98001C93140010BC
+:1065C000A09400248F8F001C91E90011A089002560
+:1065D0008F89001C8F8E00308F900038952D00140D
+:1065E000000E18C025C80001A48D002895270016AC
+:1065F000006C3021006BC821A487002A9525001863
+:106600003108000FA485002CA482002E8D3F001CB1
+:10661000ACCA0000AF88003011100006AF3F000088
+:10662000000038218D25001C014020210A00055161
+:1066300024060001250C00013184000F00003821E0
+:106640000A0006B8AF8400383C07080024E75A184F
+:106650000087302100003821ACA000000A0004F6B9
+:10666000ACC000003C05080024A55A980A00062F7B
+:10667000240400878E0400040E0002410000000084
+:106680000A00056AAE8200083084FFFF30C600FFB2
+:106690008F4201B80440FFFE00064400010430258B
+:1066A0003C07200000C720253C031000AF400180BC
+:1066B000AF450184AF44018803E00008AF4301B84F
+:1066C00027BDFFE8AFB00010AFBF00143C0760006B
+:1066D000240600021080000600A080210010102B6C
+:1066E0008FBF00148FB0001003E0000827BD001812
+:1066F0003C09600EAD2000348CE5201C8F82001C0C
+:106700002408FFFC00A81824ACE3201C0E0006D1CE
+:106710008C45000C0010102B8FBF00148FB00010A0
+:1067200003E0000827BD00183C02600E344701005A
+:1067300024090018274A040000000000000000009F
+:10674000000000003C06005034C30200AF44003893
+:10675000AF45003CAF430030014018218F4B000093
+:10676000316800201100FFFD2406007F2408FFFF90
+:106770008C6C000024C6FFFF24630004ACEC000016
+:1067800014C8FFFB24E70004000000000000000024
+:10679000000000003C0F0020AF4F00300000000060
+:1067A00024AD020001A5702B2529FFFF008E2021BA
+:1067B0001520FFE101A0282103E0000800000000EF
+:1067C00027BDFFE0AFB10014AFBF0018AFB000109D
+:1067D0003C05600E8CA20034008088211440000625
+:1067E0003C0460008C87201C2408FFFC00E8302457
+:1067F00034C30001AC83201C8F8B001C24090001D2
+:10680000ACA90034956900028D6500148D70000CF0
+:106810002D2400818D6700048D660008108000071C
+:106820008D6A00102D2C00041580000E30CE00075C
+:10683000312D000311A0000B000000002404008B88
+:10684000020028210E0006D1240600030011102B9F
+:106850008FBF00188FB100148FB0001003E0000844
+:1068600027BD002015C0FFF62404008B3C03002048
+:10687000AF4300300000000024020001AF8200148A
+:106880000000000000000000000000003C1F01505C
+:10689000013FC825253800033C0F600EAF47003884
+:1068A00000181882AF46003C35E8003CAF59003074
+:1068B000274704008F4400003086002010C0FFFDF1
+:1068C00000000000106000082466FFFF2403FFFFA3
+:1068D0008CEB000024C6FFFF24E70004AD0B000092
+:1068E00014C3FFFB250800043C08600EAD09003806
+:1068F0000000000000000000000000003C07002035
+:10690000AF470030000000000E0006F901402021D2
+:1069100002002821000020210E0006D124060003D9
+:106920000011102B8FBF00188FB100148FB0001012
+:1069300003E0000827BD002027BDFFE0AFB200182C
+:106940003092FFFFAFB10014AFBF001CAFB000101A
+:106950001640000D000088210A0007AA022010211D
+:1069600024050001508500278CE5000C0000000D77
+:10697000262300013071FFFF24E200200232382B71
+:1069800010E00019AF82001C8F8200141440001622
+:106990008F87001C3C0670003C0320008CE5000043
+:1069A00000A62024148300108F84003C00054402BC
+:1069B0003C09800000A980241480FFE9310600FF13
+:1069C0002CCA00095140FFEB262300010006688015
+:1069D0003C0E080025CE579801AE60218D8B00003B
+:1069E0000160000800000000022010218FBF001C81
+:1069F0008FB200188FB100148FB0001003E00008B0
+:106A000027BD00200E0006D1240400841600FFD804
+:106A10008F87001C0A00078BAF80003C90EF0002BC
+:106A200000002021240600090E0006D1000F2E00D0
+:106A30008F87001C0010102B0A00078BAF82003CD0
+:106A4000020028210E0006DF240400018F87001CAD
+:106A50000A00078BAF82003C020028210E0006DFEF
+:106A6000000020210A0007C38F87001C0E00071FAB
+:106A7000020020210A0007C38F87001C30B0FFFFEF
+:106A8000001019C08F5801B80700FFFE3C1F2004FA
+:106A90003C191000AF430180AF400184AF5F018813
+:106AA000AF5901B80A00078C262300013082FFFF8E
+:106AB00014400003000018210004240224030010E5
+:106AC000308500FF14A000053087000F2466000801
+:106AD0000004220230C300FF3087000F14E00005DD
+:106AE000308900032468000400042102310300FF00
+:106AF0003089000315200005388B0001246A00024C
+:106B000000042082314300FF388B00013164000112
+:106B100010800002246C0001318300FF03E00008B4
+:106B200000601021308BFFFF000B394230E600FF80
+:106B30003C09080025295998000640800109602178
+:106B40008D8700003164001F240A0001008A1804A8
+:106B500030A500FF00E3202514A000020003102749
+:106B600000E22024240F000100CF700401096821F5
+:106B7000000E282714800005ADA400008F86000CAD
+:106B800000A6102403E00008AF82000C8F88000CE0
+:106B900001C8102503E00008AF82000C3C06001F6E
+:106BA0003C0360003084FFFF34C5FF8024020020D6
+:106BB000AC602008AC60200CAC602010AC652014E8
+:106BC000AC642018AC62200000000000000000004F
+:106BD00003E000080000000027BDFFE82402FFFFDB
+:106BE000AFBF0010AF82000C000020213C0608005F
+:106BF00024C659982405FFFF248900010004408021
+:106C00003124FFFF010618212C87002014E0FFFA31
+:106C1000AC6500000E0008160000202124020001CF
+:106C20003C04600024050020AC822018AC852000C4
+:106C3000000000000000000000000000244A0001E5
+:106C40003142FFFF2C46040014C0FFF78FBF001035
+:106C500003E0000827BD00188F8300082C620400A1
+:106C600003E00008384200018F830008246200011D
+:106C700003E00008AF8200088F8300082462FFFF52
+:106C800003E00008AF82000827BDFFE0AFB10014A9
+:106C9000AFBF0018AFB000108F6B00303C06600033
+:106CA00000808821ACCB20088F6A002C3C02800039
+:106CB00024030008ACCA200C9769003A9768003892
+:106CC00000092C003107FFFF00A72025ACC42010CD
+:106CD000ACC22014ACC32000000000000000000083
+:106CE000000000003C0360008C6D200031AC000807
+:106CF0001580FFF9000000008C6E201405C00020F4
+:106D0000000000000E0007DA8F84000C00024080B3
+:106D10003C09080025295998010938218CE4000014
+:106D20000E0007DA00028140020220213090FFFFAE
+:106D3000020020210E0007F8000028213C0C8000F2
+:106D4000022C58253210FFFF3C116000240A00205D
+:106D5000AE2B2014AE302018AE2A20000000000018
+:106D60000000000000000000020010218FBF00188A
+:106D70008FB100148FB0001003E0000827BD002081
+:106D80008C6620143C02001F3443FF803C1FFFE848
+:106D900000C3C02437F9080003198021001079C20C
+:106DA0003C0C8000022C582531F0FFFF3C116000A4
+:106DB000240A0020AE2B2014AE302018AE2A20006A
+:106DC0000000000000000000000000000200102190
+:106DD0008FBF00188FB100148FB0001003E00008BF
+:106DE00027BD002027BDFFE8AFB000103402FFFF31
+:106DF0003090FFFFAFBF00141202000602002021F6
+:106E00000E00081600000000020020210E0007F806
+:106E1000240500018F8400088FBF00148FB000107C
+:106E20002483FFFF27BD001803E00008AF8300089C
+:106E3000000439C230E6003F00043B42000718401E
+:106E4000240210002CC4002024C8FFE0AF42002C14
+:106E5000246300011480000330A900FF00071840DC
+:106E6000310600FF0003608024080001019A5821C8
+:106E70003C0A000E00C82804016A382111200005D0
+:106E8000000530278CE900000125302503E00008CB
+:106E9000ACE600008CEE000001C6682403E00008A8
+:106EA000ACED000027BDFFE8AFBF0014AFB000108D
+:106EB0003C0460008C8508083403F00030A2F00028
+:106EC00050430006240200018C8708083404E000C7
+:106ED00030E6F00010C4001E24020002AF82004021
+:106EE0003C1060003C0A0200AE0A0814240910009D
+:106EF0003C08000E8E03440003482021AF49002CBB
+:106F0000240501200E000CC0000030218F830040BA
+:106F1000106000043C021691240B0001106B000E5F
+:106F20003C023D2C344F0090AE0F44088FBF00143C
+:106F30008FB000103C0C6000240E10003C0D0200CD
+:106F400027BD0018AD8E442003E00008AD8D081069
+:106F50000A0008E7AF8000403C0218DA344F009086
+:106F6000AE0F44088FBF00148FB000103C0C6000BF
+:106F7000240E10003C0D020027BD0018AD8E4420E9
+:106F800003E00008AD8D08100A0008BB24050001CD
+:106F90000A0008BB000028213C08080025085DA461
+:106FA0002404FFFF010018212402001E2442FFFFD9
+:106FB000AC6400000441FFFD246300043C070800AA
+:106FC00024E75E208CE5FFFC2404001C240600015D
+:106FD000308A001F0146480424840001000910275C
+:106FE0002C8300201460FFFA00A22824ACE5FFFCEB
+:106FF0003C05666634A4616E3C06080024C65EE06B
+:10700000AF840058AF88009C2404FFFF00C0182103
+:107010002402001F2442FFFFAC6400000441FFFD76
+:10702000246300043C0766663C05080024A55EA0B6
+:10703000AF86004834E6616EAF8600982404FFFFF7
+:1070400000A018212402000F2442FFFFAC640000BE
+:107050000441FFFD246300043C0B66663C06080007
+:1070600024C65E203568616EAF8500A4AF880070CD
+:107070002404FFFF00C018212402001F2442FFFF48
+:10708000AC6400000441FFFD246300043C0D66660F
+:107090003C0A0800254A5F6035AC616EAF860090FF
+:1070A000AF8C005C2404FFFF014018212402000380
+:1070B0002442FFFFAC6400000441FFFD2463000490
+:1070C0003C09080025295F708D27FFFC2404000679
+:1070D000240500013099001F0325C0042484000109
+:1070E000001878272C8E002015C0FFFA00EF3824F6
+:1070F000AD27FFFC3C09666624030400240403DC7E
+:1071000024050200240600663522616E3C08080052
+:1071100025085AA4AF820074AF830044AF83006C8B
+:10712000AF830050AF830084AF8A008CAF840064CB
+:10713000AF85004CAF860054AF840078AF85006007
+:10714000AF86008001001821240200022442FFFFC4
+:10715000AC6000000441FFFD24630004240400032C
+:107160002403000C3C0A0800254A5AB0AF8A006884
+:107170000A00098E2405FFFF000418802484000102
+:10718000006858212C8700C014E0FFFBAD650000AB
+:107190003C0E666635CD616E240C17A024081800DD
+:1071A000AF8D0088AF8C009403E00008AF88007CAE
+:1071B0002484007F000421C200004021000030210F
+:1071C00000003821000028210A0009A5AF8400A092
+:1071D0001060000624E7000100C4302124A500014E
+:1071E0002CC20BF51440FFFA2CA300663C090800E2
+:1071F00025295F6001201821240200032442FFFF9B
+:10720000AC6000000441FFFD2463000410E0001A9C
+:1072100024E3FFFF0003294210A0000A0000202100
+:107220002406FFFF3C03080024635F602484000100
+:107230000085502BAC660000250800011540FFFBBF
+:107240002463000430E2001F10400008000868803A
+:10725000240C0001004C38040008588001692821E2
+:1072600024E6FFFF03E00008ACA6000001A94021CE
+:107270002409FFFFAD09000003E000080000000042
+:10728000AF4400283C04000C034420210005288260
+:107290000A000CC000003021000421803C03600083
+:1072A000AC6410080000000000052980AC65100CDB
+:1072B0000000000003E000088C62100C27BDFFE80E
+:1072C0000080282124040038AFBF00140E0009D527
+:1072D000AFB0001024040E00AF4400283C10000C96
+:1072E00003502021240500100E000CC000003021A6
+:1072F00003501021AC400000AC40000424040038CE
+:107300008FBF00148FB0001024053FFF27BD001869
+:107310000A0009D58C430000000421803C03600072
+:10732000AC641008000000008C62100C03E0000840
+:107330000002118227BDFFC8AFB400208F940068FF
+:10734000AFBE0030AFB7002CAFB600280000B821A8
+:107350000080B021241E00C0AFBF0034AFB50024B0
+:10736000AFB3001CAFB20018AFB10014AFB0001043
+:107370000A000A12AFA5003C504000018F9400683B
+:1073800027DEFFFF13C00028269400048E92000021
+:107390003C03080024635DA01240FFF70283102B1A
+:1073A0003C04080024845AA4028410230002A8C0CC
+:1073B000000098210A000A212411000100118840D0
+:1073C000122000260000000002B380210251282470
+:1073D0000200202110A0FFF9267300010E0009DE33
+:1073E000000000000016684032EC000101AC2021D2
+:1073F0000E0009D5020028218F89009426F700018C
+:107400008FA6003C3AEB0001316A00012528FFFFFE
+:107410000011382702CAB021AF88009416E6FFE7B2
+:1074200002479024AE92000002E010218FBF00348A
+:107430008FBE00308FB7002C8FB600288FB5002488
+:107440008FB400208FB3001C8FB200188FB10014CE
+:107450008FB0001003E0000827BD00383C0E080084
+:1074600025CE5DA0028E102B0A000A0DAE92000000
+:1074700027BDFFD8AFB10014AFB00010AFBF0020E0
+:10748000AFB3001CAFB2001800A0882110A0001FED
+:10749000000480403C13080026735AA40A000A5ACC
+:1074A0002412000112200019261000010E0009F517
+:1074B00002002021000231422444FFA0000618806F
+:1074C0003045001F2C8217A1007318212631FFFFC1
+:1074D0001040FFF400B230048C690000020020214B
+:1074E00024053FFF012640241500FFEE0126382524
+:1074F0000E0009D5AC6700008F8A009426100001A9
+:10750000254700011620FFE9AF8700948FBF0020B8
+:107510008FB3001C8FB200188FB100148FB0001011
+:1075200003E0000827BD00288F85009C00805821BB
+:107530000000402100004821240A001F3C0C0800E4
+:10754000258C5E1C3C0D080025AD5DA48CA60000BA
+:1075500050C000140000402100AD1023000238C0CC
+:10756000240300010A000A930000202115000003F3
+:1075700000E410212448202400004821252900018E
+:10758000512B00132506DFDC106000062484000167
+:1075900000C3702415C0FFF5000318400A000A91CB
+:1075A0000000402110AC002624A300040060282124
+:1075B000254AFFFF1540FFE5AF85009C512B0004D5
+:1075C0002506DFDC0000402103E000080100102157
+:1075D0000006614230C5001F000C50803C070800C7
+:1075E00024E75DA424040001014730211120000F8D
+:1075F00000A420043C05080024A55E20148000059A
+:107600002529FFFF24C6000410C50011000000005A
+:10761000240400018CCF00000004C0270004204097
+:1076200001F868241520FFF5ACCD00008F99007893
+:1076300001001021032B482303E00008AF890078E4
+:107640003C05080024A55DA40A000A9B0000402117
+:107650003C06080024C65DA40A000AB42404000104
+:10766000308800FF240200021102000A24030003F4
+:107670001103005C8F8900A4240400041104005F3E
+:1076800024050005110500670000182103E000082B
+:10769000006010218F8900483C0C0800258C5EE0BA
+:1076A0003C04080024845F60240300201060000F65
+:1076B00000005821240D0002240E00033C0F080096
+:1076C00025EF5EE08D27000014E0000B30F9FFFF8E
+:1076D000252900040124C02B53000001018048210A
+:1076E0002463FFFF5460FFF88D270000016018211C
+:1076F00003E0000800601021132000323C0500FF69
+:1077000030E200FF004030211040004200005021D4
+:1077100024050001000020210005C84000A6C02467
+:1077200017000003332500FF14A0FFFB2484000191
+:10773000012CC023001828C000AA6021008C502111
+:107740003144001F240C0001008C18040003102792
+:1077500000E23024110D0041AD260000110E004C56
+:10776000000A1840110D00368F87006C510E00562C
+:107770008F8C0060240D0004110D005A8F8E008440
+:10778000240E0005150EFFDA01601821240B1430B9
+:1077900011400006000018218F8400A0246300011E
+:1077A000006A402B1500FFFD016458218F8A00807C
+:1077B000AF89008C016018212549FFFF0A000AEB00
+:1077C000AF89008000E52024000736021080FFD03A
+:1077D000240A001800075402314600FF0A000AF389
+:1077E000240A00103C0C0800258C5EA03C04080014
+:1077F00024845EE00A000ADA240300103C0C08002E
+:10780000258C5E203C04080024845EA00A000AD96E
+:107810008F89009000071A02306600FF0A000AF301
+:10782000240A00088F89008C3C0C0800258C5F60BE
+:107830003C04080024845F700A000ADA2403000470
+:10784000000A4080250B003024E6FFFF016018216C
+:10785000AF8900480A000AEBAF86006C000AC982B3
+:10786000001978803C07080024E75EA001E720218A
+:10787000000A18428C8F00003079001F032C380456
+:107880000007C02701F860240A000B08AC8C000038
+:10789000000331420006288000AF28213062001F1B
+:1078A0008CB8000024630001004CC804000321428E
+:1078B000001938270004108003073024004F2021CE
+:1078C0000A000B4CACA60000000A68C025AB0032D1
+:1078D000258AFFFF01601821AF8900A40A000AEB86
+:1078E000AF8A0060254B1030AF89009001601821ED
+:1078F00025C9FFFF0A000AEBAF8900843086000724
+:107900002CC2000610400014000000000006408059
+:107910003C030800246357BC010338218CE40000B9
+:1079200000800008000000002409000310A9000ED8
+:1079300000000000240A000510AA000B000000004F
+:10794000240B000110AB0008000000008F8C00A089
+:1079500010AC00050000000003E00008000010214A
+:107960000A000A7900A020210A000AC700C02021CD
+:1079700027BDFFE8308400FF240300021083000BC2
+:10798000AFBF0010240600031086003A240800044C
+:1079900010880068240E0005108E007F2CAF143074
+:1079A0008FBF001003E0000827BD00182CA2003094
+:1079B0001440FFFC8FBF001024A5FFD0000531C28A
+:1079C000000668803C07080024E75EE001A730213C
+:1079D0008CC900000005288230AC001F240B000178
+:1079E000018B50048F840048012A4025ACC8000058
+:1079F0008C83000050600001AF8600488F98006CB7
+:107A000030AE000124A6FFFF270F000115C00002C1
+:107A1000AF8F006C24A600010006414200082080C0
+:107A2000008718218C79000030C2001F2406000155
+:107A30000046F804033F382410E0FFDA8FBF00103F
+:107A40000005C182001870803C0F080025EF5EA081
+:107A500001CF48218D2B00000005684231A5001F91
+:107A600000A66004016C502527BD001803E0000843
+:107A7000AD2A00002CA7003014E0FFCA8FBF001011
+:107A800030B900071723FFC724A8FFCE00086A02F9
+:107A9000000D60803C0B0800256B5EA0018B30213F
+:107AA0008CC40000000828C230AA001F240800016E
+:107AB000014848048F8200A400891825ACC3000047
+:107AC0008C5F000053E00001AF8600A40005704009
+:107AD000000E7942000F28803C04080024845EE0F8
+:107AE00000A418218C6B000025DF000131CD001FA0
+:107AF000001F514201A86004016C4825000A108053
+:107B0000AC690000004428218CA600008F9800601A
+:107B100033F9001F8FBF00100328380400C77825F1
+:107B2000270E000127BD0018ACAF000003E00008DD
+:107B3000AF8E006024A5EFD02CB804001300FF998D
+:107B40008FBF001000053142000658803C0A080033
+:107B5000254A5E20016A30218CC4000030A3001F3A
+:107B600024090001006910048F9900900082F82513
+:107B7000ACDF00008F27000050E00001AF860090CE
+:107B80008F8D00848FBF001027BD001825AC000129
+:107B900003E00008AF8C008415E0FF828FBF001067
+:107BA0008F8600A0000610400046F821001F21002B
+:107BB00003E4C8210019384024F8143000B8402BE1
+:107BC0001100FF788FBF001024A4EBD00E00021329
+:107BD00000C0282100027942000F70803C0D08008F
+:107BE00025AD5F6001CD20218C8B0000304C001F43
+:107BF00024060001018618048F89008C016350253A
+:107C0000AC8A00008D25000050A00001AF84008CDC
+:107C10008F9800808FBF001027BD00182708000133
+:107C200003E00008AF88008030A5000724030003AC
+:107C300010A3001028A2000414400008240700022A
+:107C40002403000410A300152408000510A8000F49
+:107C50008F8500A003E000080000000014A7FFFDCE
+:107C60000080282114C3FFFB240400020A000B8BB0
+:107C700000000000240900050080282110C9FFFB36
+:107C80002404000303E000080000000014C5FFF115
+:107C9000008028210A000B8B24040005240A00011F
+:107CA0000080282110CAFFF12404000403E000082A
+:107CB0000000000027BDFFE0AFB00010000581C24A
+:107CC0002603FFD024C5003F2C6223D024C6007FAA
+:107CD000AFB20018AFB10014AFBF001C309100FF6D
+:107CE000000691C2000529820200202110400008F0
+:107CF0002403FFFF0E000A4B0000000002002021B9
+:107D0000022028210E000C390240302100001821E9
+:107D10008FBF001C8FB200188FB100148FB00010FD
+:107D20000060102103E0000827BD002027BDFFD818
+:107D300024A2007FAFB3001CAFB20018000299C2AA
+:107D4000309200FF24A3003F02402021026028213E
+:107D5000AFB10014AFB00010AFBF00200E000B6E2B
+:107D60000003898200408021004020210220282138
+:107D700014400009000018218FBF00208FB3001CA1
+:107D80008FB200188FB100148FB000100060102166
+:107D900003E0000827BD00280E0009FC00000000D9
+:107DA00000402821020020211051FFF3001019C0CB
+:107DB0000E000A4B00000000020020210240282192
+:107DC0000E000C39026030218FBF00208FB3001CE1
+:107DD0008FB200188FB100148FB00010000018216E
+:107DE0000060102103E0000827BD00283084FFFF59
+:107DF00030A5FFFF1080000700001821308200012D
+:107E00001040000200042042006518211480FFFB8E
+:107E10000005284003E000080060102110C00007A2
+:107E2000000000008CA2000024C6FFFF24A500046F
+:107E3000AC82000014C0FFFB2484000403E00008AF
+:107E40000000000010A0000824A3FFFFAC86000083
+:107E500000000000000000002402FFFF2463FFFF79
+:107E60001462FFFA2484000403E00008000000000C
+:107E700030A5FFFF8F4201B80440FFFE3C076015AC
+:107E800000A730253C031000AF440180AF400184BF
+:107E9000AF46018803E00008AF4301B88F8500D0EA
+:107EA0002C864000008018218CA700840087102BAE
+:107EB00014400010000000008CA800842D06400033
+:107EC00050C0000F240340008CAA0084008A482B75
+:107ED000512000018CA3008400035A42000B208033
+:107EE0003C05080024A558200085182103E000085F
+:107EF0008C62000014C0FFF4000000002403400066
+:107F000000035A42000B20803C05080024A558209D
+:107F10000085182103E000088C6200008F8300D0E8
+:107F2000906600D024C50001A06500D08F8500D0E8
+:107F3000906400D090A200D210440017000000000E
+:107F4000936C00788F8B00BC318A00FFA16A000C13
+:107F500025490001938700C4312200FF3048007F8B
+:107F60001107000B00026827A36200788F4E01788A
+:107F700005C0FFFE8F9900B0241800023C0F1000CE
+:107F8000AF590140A358014403E00008AF4F017806
+:107F90000A000D0931A20080A0A000D00A000CFF49
+:107FA000000000008F8700D027BDFFC8AFBF0030A2
+:107FB000AFB7002CAFB60028AFB50024AFB4002097
+:107FC000AFB3001CAFB20018AFB10014AFB00010D7
+:107FD00094E300E094E200E2104300D72405FFFFA1
+:107FE0003C047FFF3497FFFF2415FF800A000DF04B
+:107FF0003C16000E108A00D18FBF00308F9100B068
+:108000003C1808008F18005C001230C0001291402C
+:108010000311702101D57824AF4F002C94EC00E2BD
+:1080200031CD007F01BA5821318A7FFF0176482186
+:10803000000A804002091021945300003C08080007
+:108040008D0800580246C02132733FFF001319808B
+:10805000010320210224282130BF007F03FAC82118
+:1080600000B5A024AF54002C0336A0218E87001049
+:108070008E8F003003785821256D008800EF702323
+:10808000240C0002AE8E0010AF8D00ACA16C0088F5
+:10809000976A003C8E8400308F9100AC0E000CD6A5
+:1080A0003150FFFF00024B80020940253C02420094
+:1080B00001022025AE2400048E8300048F8D00ACC5
+:1080C0008E860000240E0008ADA3001CADA600188B
+:1080D000ADA0000CADA00010929F000A33F900FF84
+:1080E000A5B90014968500083C1F000CA5A5001634
+:1080F0009298000A331100FFA5B100209690000865
+:1081000024180005A5B00022ADA00024928F000B1A
+:108110002410C00031E700FFA5A70002A1AE0001B6
+:108120008E8C00308F8B00AC8F8400B0AD6C00085B
+:108130003C0A08008D4A005401444821013540247E
+:10814000AF4800283C0208008C4200540044302113
+:1081500030C3007F007AC821033F282102458821CF
+:10816000AF9100BCAF8500C0A23800008F8A00BC70
+:108170002403FFBF2418FFDF954F000201F03824CD
+:1081800000F37025A54E0002914D000231AC003F76
+:10819000358B0040A14B00028F8600BC8F8900D038
+:1081A000ACC000048D28007C3C098000ACC80008ED
+:1081B00090C4000D3082007FA0C2000D8F8500BCEE
+:1081C00090BF000D03E3C824A0B9000D8F9100BC3F
+:1081D0009233000D02789024A232000D8E9000346C
+:1081E0008F8B00BCAD7000108E87002C8E8F0030FE
+:1081F00000EF7023AD6E0014916D001831AC007F5C
+:10820000A16C00188F9F00BC8E8A00308FE8001888
+:10821000015720240109302400C41025AFE20018C2
+:108220009283000AA3E3001C969900088F8500BC86
+:108230008F9800D0A4B9001E8E9000308E8400303C
+:108240000E0002138F0500848F8500D0000291403C
+:108250000002990090AF00BC0253882100403021F9
+:1082600031E7000210E0000302118021000290803B
+:108270000212802190B900BC3327000410E00002F4
+:108280000006F880021F80218E9800308F8B00BC82
+:1082900024068000330F0003000F702331CD00034C
+:1082A000020D6021AD6C000494A400E294AA00E2E7
+:1082B00094B000E231497FFF2522000130537FFF57
+:1082C0000206182400734025A4A800E294A400E24A
+:1082D0003C1408008E94006030917FFF123400221D
+:1082E000000000000E000CF6000000008F8700D098
+:1082F0000000282194F300E094F000E21213000F34
+:108300008FBF003090E900D090E800D1313200FFFB
+:10831000310400FF0244302B14C0FF36264A00010E
+:1083200090EE00D2264B000131CD00FF008D602180
+:10833000158BFF338F9100B08FBF00308FB7002CAB
+:108340008FB600288FB500248FB400208FB3001C97
+:108350008FB200188FB100148FB0001000A0102150
+:1083600003E0000827BD003894A300E20066402423
+:10837000A4A800E290A400E290B900E2309100FFCE
+:108380000011A1C20014F827001F39C03332007F4A
+:10839000024730250A000DE8A0A600E23084FFFF66
+:1083A00030A5FFFFAF440018AF45001C03E00008F4
+:1083B0008F42001427BDFFB8AFB000208F9000D0CF
+:1083C0003084FFFFAFA40010AFBF0044AFBE004039
+:1083D000AFB7003CAFB60038AFB50034AFB4003033
+:1083E000AFB3002CAFB20028AFB10024A7A0001893
+:1083F000920600D1920500D030C400FF30A300FFE8
+:108400000064102B10400122AFA00014920900D08C
+:108410008FB50010312800FF0088382324F4FFFFB7
+:108420000014882B0015982B02339024524001260B
+:108430008FB40014961E0012961F00108FB7001004
+:1084400003DFC823001714000019C400000224032E
+:108450000018140302E2B02A52C00001004020219B
+:108460000284282B10A0000200801821028018210D
+:1084700000033C0000071C033064FFFF2C8600094A
+:1084800014C000020060B821241700088E0A0008FA
+:10849000001769808E09000C31ABFFFF3C0C001007
+:1084A000016C402527520400AF4A0038AF9200B853
+:1084B000AF49003CAF480030000000000000000061
+:1084C00000000000000000000000000000000000AC
+:1084D00000000000000000008F4F000031EE00207F
+:1084E00011C0FFFD0017982A027110240A000E83A4
+:1084F0000000B02155E001019258000131130080C5
+:10850000126001CF012020219655001232A5FFFFF5
+:108510000E000CCBA7B500188F9000D00291A023BD
+:1085200026CD00018F9100B8000DB4000016B403F1
+:108530002638004002D7582A0014882B2405000151
+:108540000300902101711024AF9800B8AFA500146A
+:10855000104001BC8F8900B03C0C08008D8C005489
+:10856000240BFF80921E00D001895021014B28244A
+:10857000921900D0AF4500288E4700103C08080033
+:108580008D0800583C1808008F18005430E33FFF56
+:108590000003218001043021012658212402FF809C
+:1085A0000162F824920C00D0AF5F002C92480000CA
+:1085B00033D100FF333500FF0309982100117140CA
+:1085C000001578C0326D007F01CF382101BA282113
+:1085D000318300FF3164007F3C0A000C00AA88212F
+:1085E0000367F02100033140009A10213108003F59
+:1085F0003C1F000E00D1C021005F982127D90088C0
+:108600002D150008AF9100C0AF9900ACAF9800BC29
+:10861000AF9300B412A0018A00008821240E00014B
+:10862000010E4004310D005D11A0FFB2310F0002B8
+:108630008E4A00283C0300803C04FFEFAE6A000035
+:108640008E450024A260000A3488FFFFAE65000456
+:108650009247002C3C1FFF9F37FEFFFFA267000CD4
+:108660008E62000C3C180040A267000B00433025CE
+:1086700000C8C824033E88240238A825AE75000C23
+:108680008E490004AE6000183C0F00FFAE69001474
+:108690008E4D002C35EEFFFF8F8B00B001AE6024B5
+:1086A000AE6C00108E470008A660000896450012C8
+:1086B000AE6700208E42000C30B03FFF00105180AA
+:1086C000AE6200248E5E0014014B182130A400011C
+:1086D000AE7E00288E590018000331C2000443808A
+:1086E000AE79002C8E51001C00C8F821A67F001C1A
+:1086F000AE710030965800028E550020A678001EFC
+:10870000AE75003492490033313000045600000544
+:10871000925000008F8C00D08D8B007CAE6B0030AF
+:10872000925000008F8F00BCA1F00000924E0033E9
+:1087300031CD000251A00007925E00018F8900BC7C
+:108740002418FF80913100000311A825A1350000F5
+:10875000925E00018F9900BC2409FFBF240BFFDF4C
+:10876000A33E00018F9500BC92B8000D3311007F2D
+:10877000A2B1000D8F8E00BC91D0000D02097824AB
+:10878000A1CF000D8F8800BC8E6D0014910A000DE2
+:108790002DAC0001000C2940014B382400E51825C0
+:1087A000A103000D964200128F8800BC8F8700D075
+:1087B000A50200028E45000490FF00BC30A4000317
+:1087C0000004302330DE000300BE102133F9000224
+:1087D00017200002244400342444003090E200BCFE
+:1087E00000A2302430DF000417E0000224830004DC
+:1087F000008018218F8F00AC24090002AD03000413
+:10880000A1E90000924E003F8F8D00ACA1AE0001A7
+:108810008F9500AC924C003F8E440004A6AC000241
+:10882000976B003C0E000CD63170FFFF00025380A6
+:10883000020A38253C05420000E51825AEA30004D5
+:108840008F8600AC8E480038ACC800188E440034C7
+:10885000ACC4001CACC0000CACC00010A4C0001420
+:10886000A4C00016A4C00020A4C00022ACC00024F4
+:108870008E6400145080000124040001ACC4000880
+:108880000E000CF6241100010A000E768F9000D025
+:10889000920F00D2920E00D08FB5001031EB00FF86
+:1088A00031CD00FF008D6023016C50212554FFFF66
+:1088B0000014882B0015982B023390241640FEDDFF
+:1088C000000000008FB400148FBF00448FBE004032
+:1088D0003A8200018FB7003C8FB600388FB5003464
+:1088E0008FB400308FB3002C8FB200288FB10024DA
+:1088F0008FB0002003E0000827BD0048331100209E
+:10890000122000EF24150001921E00BC241F00015C
+:108910000000A82133D900011320000DAFBF001CB7
+:108920008E4400148E0800840088102B144000022E
+:10893000008030218E0600848E03006400C3A82BC3
+:1089400016A0000200C020218E0400640080A8212F
+:108950008E4700148E05006400E5302B14C0000221
+:1089600000E020218E0400640095F02313C0000471
+:108970008FAC001C240A0002AFAA001C8FAC001CA4
+:10898000028C582B156000A8000018218E4F00386B
+:108990008E6D000C3C0E0080AE6F00008E4A0034DD
+:1089A0003C10FF9F01AE5825AE6A00049246003F7E
+:1089B000360CFFFF016C38243C0500203C03FFEF20
+:1089C000A266000B00E510253468FFFF8F8700B812
+:1089D0000048F8243C04000803E4C825AE79000CE4
+:1089E0008CF80014AE60001802BE7821AE78001436
+:1089F0008CF10018AE71001C8CE90008AE690024EF
+:108A00008CEE000CAE6F002CAE600028AE6E002025
+:108A1000A6600038A660003A8CED001401B58023F2
+:108A2000021E902312400011AE72001090EA003D29
+:108A30008E6500048E640000000A310000A6C82183
+:108A4000000010210326402B0082F82103E8C021FA
+:108A5000AE790004AE78000090F1003DA271000AEA
+:108A60008F8900B895320006A67200088F9800AC76
+:108A70002419000202A02021A31900009769003CDC
+:108A80008F9200AC0E000CD63131FFFF00027B80CC
+:108A90008F8500B8022F68253C0E420001AE80256C
+:108AA000AE5000048F8400AC8CAC0038AC8C001845
+:108AB0008CAB0034AC8B001CAC80000CAC80001084
+:108AC000A4800014A4800016A4800020A4800022AA
+:108AD000AC80002490A7003FA487000212A00135BB
+:108AE0002403000153C0000290A2003D90A2003E6A
+:108AF00024480001A08800018F9F00ACAFF500085A
+:108B00008F8300D024070034906600BC30C500027B
+:108B100050A00001240700308F9200B88F8A00BC5B
+:108B2000906D00BC924B00002412C00032A50003DF
+:108B3000A14B00008F8600B88F8800BC240200047F
+:108B400090C400010045182330790003A1040001FE
+:108B50008F8A00BC8F9F00B800F53821955800021D
+:108B600097E9001200F9382103128824312F3FFFC2
+:108B7000022F7025A54E00029150000231A800047A
+:108B8000320C003F358B0040A14B000212A00002C6
+:108B90008F8500BC00E838218F8E00D0ACA7000480
+:108BA000240BFFBF8DCD007C2EA400012403FFDF2A
+:108BB000ACAD000890B0000D00044140320C007FC5
+:108BC000A0AC000D8F8600BC90CA000D014B102494
+:108BD000A0C2000D8F8700BC90E5000D00A3F82413
+:108BE00003E8C825A0F9000D8F9100B88F8D00BC57
+:108BF0008E380020ADB800108E290024ADA90014D5
+:108C00008E2F0028ADAF00188E2E002C0E000CF613
+:108C1000ADAE001C8FB0001C240C0002120C00EE44
+:108C20008F9000D08FA3001C006088211460000288
+:108C30000060A8210000A02156A0FE390291A023C7
+:108C40000014882B8FA90010960700103C1E0020EE
+:108C50000136402302C750213112FFFFA60A00103F
+:108C6000AFB20010AF5E0030000000009617001099
+:108C7000961300121277008F000000008E05000C82
+:108C80008E0B00080016698000AD7021000DC7C36F
+:108C900001CDA82B0178782101F56021AE0E000CE2
+:108CA000AE0C00088FB300100013B82B02378024DD
+:108CB0001200FF048F9000D00A000E3C000000005C
+:108CC0008E4D0038A6600008240B0003AE6D000036
+:108CD0008E500034A260000A8F9800B8AE70000475
+:108CE0003C0500809311003FA26B000C8E6F000CBE
+:108CF0003C0EFF9FA271000B01E5102535CCFFFF54
+:108D00003C03FFEF8F9200B8004C30243464FFFF27
+:108D100000C4F824AE7F000C8E590014964800124F
+:108D20008F8A00B0AE7900108E490014AE60001832
+:108D3000AE600020AE690014AE6000248E470018BB
+:108D400031093FFF0009F180AE6700288E4D000811
+:108D500003CA802131180001AE6D00308E4F000C27
+:108D60008F8C00AC001089C200185B80022B282178
+:108D7000240E0002A665001CA6600036AE6F002C13
+:108D8000A18E00009763003C8F8A00AC3C04420037
+:108D90003062FFFF00443025AD4600048F9F00B8CD
+:108DA000240700012411C0008FF30038240600348A
+:108DB000AD5300188FF90034AD59001CAD40000CC4
+:108DC000AD400010A5400014A5400016A5400020AD
+:108DD000A5400022AD400024A5550002A147000196
+:108DE0008F9E00AC8F8800B88F9200BCAFD5000872
+:108DF000910D0000A24D00008F9000B88F8B00BC39
+:108E000092180001A17800018F8400BC94850002B3
+:108E100000B1782401E97025A48E0002908C000234
+:108E20003183003FA08300028F8300D08F8400BC79
+:108E3000906200BC305300025260000124060030F2
+:108E4000AC8600048C6F007C2403FFBF02A0882145
+:108E5000AC8F0008908E000D31CC007FA08C000DEF
+:108E60008F8600BC90C2000D00432024A0C4000DDA
+:108E70008F8900BC913F000D37F90020A139000D0A
+:108E80008F8800B88F9300BC8D070020AE6700105C
+:108E90008D0A0024AE6A00148D1E0028AE7E0018D4
+:108EA0008D12002C0E000CF6AE72001C0A00103D54
+:108EB0008F9000D0960E00148E03000431CCFFFF7B
+:108EC000000C10C000622021AF44003C8E1F000443
+:108ED0008F46003C03E6C8231B20003C0000000036
+:108EE0008E0F000025E200013C05001034B500089B
+:108EF000AF420038AF550030000000000000000015
+:108F00000000000000000000000000000000000061
+:108F100000000000000000008F580000330B00200C
+:108F20001160FFFD000000008F5304003C0D002085
+:108F3000AE1300088F570404AE17000CAF4D00307D
+:108F4000000000003C0608008CC600442416000106
+:108F500010D600BD00000000961F00123C0508005E
+:108F60008CA5004000BFC821A61900129609001464
+:108F700025270001A6070014960A00143144FFFFBC
+:108F80005486FF498FB30010A60000140E000E1681
+:108F900030A5FFFF3C0408008C84002496030012D7
+:108FA0000044102300623023A60600120A00105964
+:108FB0008FB30010A08300018F8200AC2404000155
+:108FC000AC4400080A000FF08F8300D08E0200002E
+:108FD0000A0010EA3C0500108F8200C08FA7001C19
+:108FE000921800D0920B00D0920E00D0331100FFE7
+:108FF000316900FF00117940000928C001E56021B6
+:1090000031C300FF036C50210003314000C2C8216E
+:10901000255F0088AF9F00ACAF9900BCA1470088D6
+:109020009768003C03C020218F9100AC0E000CD645
+:109030003110FFFF00026B80020DC0253C0442008E
+:109040008F8D00B803045825AE2B00048DA900387D
+:109050008F8B00AC0000882100118100AD690018E1
+:109060008DAF00343C087FFF3504FFFFAD6F001C5F
+:1090700091AC003E8D65001C8D660018000C190037
+:10908000000C770200A33821020E102500E3F82B14
+:1090900000C2C821033F5021AD67001CAD6A001813
+:1090A000AD60000CAD60001091B8003E24050005D5
+:1090B00003C45024A578001495A9000403C02021FE
+:1090C000A569001691AF003EA56F002095B1000480
+:1090D000A5710022AD60002491AE003FA56E000294
+:1090E00091B0003E91AC003D01901023244300015B
+:1090F000A16300018F8600AC8F9F00BCACDE00082E
+:10910000A3E500008F9000BC8F9900B82405FFBF35
+:1091100096070002973800120247782433093FFF70
+:1091200001E98825A6110002921200022418FFDF2F
+:10913000324E003F35CD0040A20D00028F8600BCAC
+:109140008F8C00D02412FFFFACC000048D8B007CFC
+:109150003C0C8000ACCB000890C2000D3043007F77
+:10916000A0C3000D8F8700BC90FF000D03E5C8244D
+:10917000A0F9000D8F9100BC9229000D01387824D0
+:10918000A22F000D8F9000BCAE120010AE1500147F
+:10919000920E00182415FF8002AE6825A20D00185B
+:1091A0008F8500BC8F8300B88CAB0018016C102435
+:1091B000004A3025ACA600189068003EA0A8001C0C
+:1091C0008F9F00B88F8700BC8F9800D097F900045C
+:1091D000A4F9001E0E0002138F0500848F8600D0B4
+:1091E000000279400002490090D200BC01E98821C8
+:1091F000004028213255000212A0000303D1202193
+:109200000002A8800095202190CD00BC31B200045E
+:109210001240000333DF0003000540800088202156
+:10922000240600048F9E00BC00DFC8233327000300
+:1092300000875021AFCA00040E000CF6A665003866
+:109240000A0010388F9000D0961E00123C080800CB
+:109250008D080024011E9021A61200120A00105948
+:109260008FB3001027BDFFE03C1808008F18005096
+:10927000AFB00010AFBF0018AFB10014AF8400B0A2
+:1092800093710074030478212410FF8031EE007F75
+:109290003225007F01F0582401DA68213C0C000AD5
+:1092A000A38500C401AC2821AF4B002494A9001071
+:1092B0009768000690A600620080382124020030E2
+:1092C0000109202330C300F0AF8500D010620019DF
+:1092D0003090FFFF90AE0062240DFFF0240A005092
+:1092E00001AE6024318B00FF116A002F00000000E6
+:1092F00016000007241F0C00AF5F00248FB100147C
+:109300008FBF00188FB0001003E0000827BD0020B9
+:109310000E000E1C02002021241F0C00AF5F002451
+:109320008FB100148FBF00188FB0001003E0000849
+:1093300027BD002094A200E094A400E290BF011396
+:10934000008218263079FFFF33E700C014E00009DF
+:109350002F31000116000038000000005620FFE603
+:10936000241F0C000E000D18000000000A0011ED73
+:10937000241F0C001620FFDE000000000E000D1858
+:10938000000000001440FFDC241F0C001600002227
+:109390008F8300D0906901133122003FA062011336
+:1093A0000A0011ED241F0C0094AF00D48F8600D466
+:1093B00000E02821240400050E000C5C31F0FFFFC2
+:1093C0001440000524030003979100E600001821D3
+:1093D0002625FFFFA78500E68F5801B80700FFFE8E
+:1093E0003C196013AF400180241F0C00AF50018472
+:1093F000007938253C101000AF4701888FB1001468
+:10940000AF5001B8AF5F00248FB000108FBF0018BD
+:1094100003E0000827BD00200E000E1C02002021E2
+:109420005040FFB5241F0C008F8300D090690113BA
+:109430000A0012163122003F0E000E1C02002021ED
+:109440001440FFAD241F0C00122000078F8300D0B2
+:10945000906801133106003F34C20040A06201133E
+:109460000A0011ED241F0C000E000D180000000072
+:109470005040FFA1241F0C008F8300D0906801137F
+:109480003106003F0A00124634C20040AF9B00C8BC
+:1094900003E00008AF8000EC3089FFFF0009404284
+:1094A0002D020041000921801440000200095040B3
+:1094B00024080040000830C0000811400046582130
+:1094C000256701A800E2C821272F007F2418FF800C
+:1094D00001F818240064302100CA702125CC00FF57
+:1094E000240DFF00018D202425650088240A0088B2
+:1094F0003C010800AC2A004C3C010800AC2500509F
+:10950000AF8400D43C010800AC2900603C01080095
+:10951000AC2800643C010800AC2700543C01080062
+:10952000AC2300583C010800AC26005C03E00008B6
+:1095300000000000308300FF30C6FFFF30E400FF72
+:109540008F4201B80440FFFE00034C00012438257F
+:109550003C08600000E820253C031000AF45018076
+:10956000AF460184AF44018803E00008AF4301B86F
+:109570008F86001C3C096012352700108CCB00043C
+:109580003C0C600E35850010316A00062D48000144
+:10959000ACE800C48CC40004ACA431808CC20008C8
+:1095A00094C30002ACA2318403E00008A78300E466
+:1095B0003C0308008C6300508F8400E88F86001CF9
+:1095C0002402FF800064C0210302C824AF59002890
+:1095D0008CCD00043305007F00BA78213C0E000CCE
+:1095E00001EE2821ACAD00588CC80008AF8500D032
+:1095F0003C076012ACA8005C8CCC001034E8001072
+:10960000ACAC000C8CCB000CACAB000894AA0014E2
+:109610003C0208008C42004425490001A4A9001422
+:1096200094A400143083FFFF106200178F8400D0D1
+:109630003C0A08008D4A0040A4AA00128CCE0018F3
+:10964000AC8E00248CCD0014AC8D00208CC700188B
+:10965000AC87002C8CCC001424060001AC8C0028B4
+:109660008D0B00BC5166001A8D0200B48D0200B84B
+:10967000A482003A948F003AA48F003C948800D4CE
+:1096800003E000083102FFFF3C0908008D29002497
+:10969000A4A000148F8400D0A4A900128CCE0018BE
+:1096A000AC8E00248CCD0014AC8D00208CC700182B
+:1096B000AC87002C8CCC001424060001AC8C002854
+:1096C0008D0B00BC5566FFEA8D0200B88D0200B418
+:1096D000A482003A948F003AA48F003C948800D46E
+:1096E00003E000083102FFFF8F86001C3C0C0800DD
+:1096F0008D8C0050240BFF808CCD00083C03000CA7
+:10970000000D51C0018A4021010B4824AF8A00E8B6
+:10971000AF49002890C700073105007F00BA10212B
+:109720000043282130E4000410800039AF8500D0C8
+:1097300090CF000731EE000811C000380000000093
+:109740008CD9000C8CC400140324C02B13000030EF
+:10975000000000008CC2000CACA200648CCD00188C
+:109760002402FFF8ACAD00688CCC0010ACAC0080DB
+:109770008CCB000CACAB00848CCA001CACAA007C67
+:1097800090A900BC01224024A0A800BC90C30007FF
+:109790003067000810E000048F8500D090AF00BC57
+:1097A00035EE0001A0AE00BC90D9000733380001AF
+:1097B000130000088F8300D08F8700D0240400346A
+:1097C00090E800BC35030002A0E300BC8F8300D00A
+:1097D000AC6400C090C900073126000210C000052B
+:1097E00000000000906A00BC35420004A06200BC8A
+:1097F0008F8300D09065011330AD003FA06D011341
+:109800008F8C00D0958B00D403E000083162FFFFFD
+:109810008CC200140A001305000000000A001306A1
+:10982000ACA0006427BDFFD8AFB000108F90001C23
+:10983000AFBF0024AFB40020AFB20018AFB1001426
+:10984000AFB3001C9613000E3C07600A3C14600680
+:109850003264FFFF369300100E00125534F40410EA
+:109860008F8400D43C11600E0E00099B363100102D
+:10987000920E00153C0708008CE700603C12601255
+:1098800031CD000FA38D00F08E0E00048E0D000868
+:1098900096080012961F00109619001A9618001EBE
+:1098A000960F001C310CFFFF33EBFFFF332AFFFF45
+:1098B0003309FFFF31E6FFFF3C010800AC2B0040FD
+:1098C0003C010800AC2C00243C010800AC2A0044F8
+:1098D000AE293178AE26317C92020015960300162F
+:1098E00036520010304400FF3065FFFF3C06080090
+:1098F0008CC60064AE243188AE4500B492080014D2
+:1099000096190018241F0001011FC004332FFFFF08
+:109910003C0508008CA50058AE5800B8AE4F00BCFE
+:10992000920C0014AF8E00D8AF8D00DC318B00FF9D
+:10993000AE4B00C0920A0015AE670048AE66004C00
+:10994000314900FFAE4900C8AE65007C3C03080009
+:109950008C6300503C0408008C84004C3C080800D8
+:109960008D0800543C0208008C42005C8FBF00242C
+:10997000AE6300808FB00010AE8300748FB3001C04
+:10998000AE22319CAE4200DCAE2731A0AE2631A41F
+:10999000AE24318CAE233190AE283194AE2531986F
+:1099A000AE870050AE860054AE8500708FB10014B3
+:1099B000AE4700E0AE4600E4AE4400CCAE4300D07B
+:1099C000AE4800D4AE4500D88FB400208FB2001846
+:1099D00003E0000827BD002827BDFFE0AFB1001459
+:1099E000AFBF0018241100010E000845AFB00010F1
+:1099F00010510005978400E6978300CC0083102B5C
+:109A0000144000088F8500D4240700028FBF00187F
+:109A10008FB100148FB0001000E0102103E00008A7
+:109A200027BD00200E000C7A24040005AF8200E858
+:109A30001040FFF6240700020E0008498F90001C1A
+:109A4000979F00E68F9900E88F8D00C827EF0001EF
+:109A5000240E0050AF590020A78F00E6A1AE0000F1
+:109A60003C0C08008D8C00648F8600C8240A80009E
+:109A7000000C5E00ACCB0074A4C0000694C9000AC0
+:109A8000241FFF803C0D000C012AC024A4D8000A2A
+:109A900090C8000A24182000011F1825A0C3000A3E
+:109AA0008F8700C8A0E000788F8500C800003821AB
+:109AB000A0A000833C0208008C4200508F8400E884
+:109AC0000044782101FFC824AF590028960B0002FA
+:109AD00031EE007F01DA6021018D3021A4CB00D46A
+:109AE000960A0002AF8600D03C0E000425492401EE
+:109AF000A4C900E68E080004ACC800048E03000868
+:109B0000ACC30000A4C00010A4C00014A0C000D0CA
+:109B10008F8500D02403FFBFA0A000D13C04080023
+:109B20008C8400648F8200D0A04400D28E1F000C71
+:109B30008F8A00D0978F00E4AD5F001C8E19001053
+:109B400024100030AD590018A5400030A551005434
+:109B5000A5510056A54F0016AD4E0068AD580080C7
+:109B6000AD580084914D006231AC000F358B001070
+:109B7000A14B00628F8600D090C900633128007F1E
+:109B8000A0C800638F8400D02406FFFF9085006387
+:109B900000A31024A08200638F9100D000E0102168
+:109BA000923F00BC37F90001A23900BC8F8A00D077
+:109BB000938F00F0AD580064AD5000C0914E00D3BB
+:109BC000000F690031CC000F018D5825A14B00D347
+:109BD0008F8500D08F8900DCACA900E88F8800D881
+:109BE0008FBF00188FB100148FB0001027BD002068
+:109BF000ACA800ECA4A600D6A4A000E0A4A000E2BB
+:109C000003E000080000000027BDFFE0AFB0001037
+:109C10008F90001CAFB10014AFBF00188E19000464
+:109C20003C1808008F180050240FFF80001989C0CD
+:109C30000238702131CD007F01CF602401BA50215C
+:109C40003C0B000CAF4C0028014B4021950900D47F
+:109C5000950400D68E0700043131FFFFAF8800D095
+:109C60000E000913000721C08E0600048F8300C870
+:109C7000000629C0AF4500209064003E30820040BD
+:109C8000144000068F8400D0341FFFFF948300D659
+:109C90003062FFFF145F000400000000948400D6CF
+:109CA0000E0008A83084FFFF8E050004022030213A
+:109CB0008FBF00188FB100148FB000102404002251
+:109CC00000003821000529C00A00127C27BD0020B1
+:109CD00027BDFFE0AFB100143091FFFFAFB000101F
+:109CE000AFBF00181220001D000080218F86001CCD
+:109CF0008CC500002403000600053F020005140285
+:109D000030E4000714830015304500FF2CA800063E
+:109D10001100004D000558803C0C0800258C57D4DC
+:109D2000016C50218D490000012000080000000056
+:109D30008F8E00EC240D000111CD005900000000B1
+:109D4000260B00013170FFFF24CA00200211202BD6
+:109D5000014030211480FFE6AF8A001C0200102170
+:109D60008FBF00188FB100148FB0001003E00008FF
+:109D700027BD0020938700CE14E00038240400148F
+:109D80000E001338000000008F86001C2402000122
+:109D90000A00147FAF8200EC8F8900EC24080002D7
+:109DA0001128003B2404001300002821000030216A
+:109DB000240700010E00127C000000000A00147F3E
+:109DC0008F86001C8F8700EC2405000214E5FFF647
+:109DD000240400120E0012E9000000008F8500E844
+:109DE00000403021240400120E00127C00003821B3
+:109DF0000A00147F8F86001C8F8300EC241F000351
+:109E0000147FFFD0260B00010E00129B0000000003
+:109E10008F8500E800403021240200022404001055
+:109E200000003821AF8200EC0E00127C0000000020
+:109E30000A00147F8F86001C8F8F00EC240600021E
+:109E400011E6000B0000000024040010000028218F
+:109E5000000030210A00149C240700010000282182
+:109E60000E00127C000030210A00147F8F86001C37
+:109E70000E0013A500000000144000128F99001C72
+:109E80008F86001C240200030A00147FAF8200ECBE
+:109E90000E001431000000000A00147F8F86001CA1
+:109EA0000E00128B000000002402000224040014A3
+:109EB0000000282100003021000038210A0014B9D8
+:109EC000AF8200EC004038212404001097380002D3
+:109ED000000028210E00127C3306FFFF0A00147FC9
+:109EE0008F86001C8F8400C83C077FFF34E6FFFF8D
+:109EF0008C8500742402000100A61824AC83007431
+:109F000003E00008A082000510A000362CA200800B
+:109F1000274A04003C0B000524090080104000077C
+:109F20002408008030A6000F00C540212D030081C9
+:109F30001460000200A0482124080080AF4B0030CC
+:109F400000000000000000000000000011000009F7
+:109F500000003821014030218C8D000024E70004EE
+:109F600000E8602BACCD0000248400041580FFFACB
+:109F700024C60004000000000000000000000000F3
+:109F80003C0E0006010E3825AF47003000000000EF
+:109F900000000000000000008F4F000031E80010BA
+:109FA0001100FFFD000000008F42003C8F43003C89
+:109FB0000049C8210323C02B130000040000000047
+:109FC0008F4C003825860001AF4600388F47003C93
+:109FD00000A9282300E96821AF4D003C14A0FFCE62
+:109FE0002CA2008003E000080000000027BDFFD085
+:109FF0003C020002AFB100143C11000CAF45003828
+:10A00000AFB3001CAF46003C00809821AF42003047
+:10A0100024050088AF44002803512021AFBF002849
+:10A02000AFB50024AFB40020AFB200180E0014F199
+:10A03000AFB000103C1F08008FFF004C3C18080018
+:10A040008F1800642410FF8003F3A82132B9007F29
+:10A0500002B078240018A0C0033A70210018914083
+:10A0600001D12021AF4F00280E0014F10254282105
+:10A070003C0D08008DAD00502405012001B358218E
+:10A08000316C007F01705024019A48210131202158
+:10A090000E0014F1AF4A00283C0808008D08005457
+:10A0A0003C0508008CA500640113382130E6007FD0
+:10A0B00000F0182400DA202100912021AF4300286D
+:10A0C0000E0014F1000529403C0208008C420058A3
+:10A0D0003C1008008E1000601200001C0053882104
+:10A0E0002415FF800A0015743C14000C3226007FF2
+:10A0F0000235182400DA202102402821AF4300282D
+:10A10000009420210E0014F12610FFC01200000F51
+:10A11000023288212E05004110A0FFF42412100005
+:10A120003226007F001091800235182400DA2021A9
+:10A1300002402821AF430028009420210E0014F192
+:10A14000000080211600FFF3023288213C0B08003A
+:10A150008D6B005C240AFF802405000201734021FE
+:10A16000010A4824AF4900283C0408009484006296
+:10A170003110007F021A88213C07000C0E000CAA47
+:10A180000227982100402821026020218FBF00284B
+:10A190008FB500248FB400208FB3001C8FB200183D
+:10A1A0008FB100148FB000100A0014F127BD0030E9
+:10A1B0008F83001C8C62000410400003000000002C
+:10A1C00003E00008000000008C6400108C650008AB
+:10A1D0000A00152A8C66000C000000000000001B1D
+:10A1E0000000000F0000000A000000080000000648
+:10A1F000000000050000000500000004000000044D
+:10A200000000000300000003000000030000000342
+:10A210000000000300000002000000020000000235
+:10A220000000000200000002000000020000000226
+:10A230000000000200000002000000020000000216
+:10A240000000000200000002000000020000000206
+:10A2500000000001000000010000000108000F24C0
+:10A2600008000D6C08000FB80800106008000F4CC3
+:10A2700008000F8C0800119408000D88080011B820
+:10A2800008000DD8080015540800151C08000D889A
+:10A2900008000D8808000D880800124008001240D0
+:10A2A00008000D8808000D88080014E008000D88DB
+:10A2B00008000D8808000D8808000D88080013B4F8
+:10A2C00008000D8808000D8808000D8808000D881A
+:10A2D00008000D8808000D8808000D8808000D880A
+:10A2E00008000D8808000D8808000D8808000D88FA
+:10A2F00008000D8808000D8808000FAC08000D88C4
+:10A3000008000D880800167808000D8808000D88E0
+:10A3100008000D8808000D8808000D8808000D88C9
+:10A3200008000D8808000D8808000D8808000D88B9
+:10A3300008000D8808000D8808000D8808000D88A9
+:10A3400008000D8808000D8808000D88080014100A
+:10A3500008000D8808000D8808001334080012A4B6
+:10A3600008001E2C08001EFC08001F1408001F28EF
+:10A3700008001F3808001E2C08001E2C08001E2C88
+:10A3800008001ED808002E1408002E1C08002DE41A
+:10A3900008002DF008002DFC08002E08080052F4DB
+:10A3A000080052B40800528008005254080052308D
+:10A3B000080051EC0A000C840000000000000000BE
+:10A3C0000000000D727870362E322E33000000002F
+:10A3D000060203030000000000000001000000006E
+:10A3E000000000000000000000000000000000006D
+:10A3F000000000000000000000000000000000005D
+:10A40000000000000000000000000000000000004C
+:10A41000000000000000000000000000000000003C
+:10A42000000000000000000000000000000000002C
+:10A43000000000000000000000000000000000001C
+:10A44000000000000000000000000000000000000C
+:10A4500000000000000000000000000000000000FC
+:10A4600000000000000000000000000000000000EC
+:10A4700000000000000000000000000000000000DC
+:10A4800000000000000000000000000000000000CC
+:10A4900000000000000000000000000000000000BC
+:10A4A00000000000000000000000000000000000AC
+:10A4B000000000000000000000000000000000009C
+:10A4C000000000000000000000000000000000008C
+:10A4D000000000000000000000000000000000007C
+:10A4E000000000000000000000000000000000006C
+:10A4F000000000000000000000000000000000005C
+:10A50000000000000000000000000000000000004B
+:10A51000000000000000000000000000000000003B
+:10A52000000000000000000000000000000000002B
+:10A53000000000000000000000000000000000001B
+:10A54000000000000000000000000000000000000B
+:10A5500000000000000000000000000000000000FB
+:10A5600000000000000000000000000000000000EB
+:10A5700000000000000000000000000000000000DB
+:10A5800000000000000000000000000000000000CB
+:10A5900000000000000000000000000000000000BB
+:10A5A00000000000000000000000000000000000AB
+:10A5B000000000000000000000000000000000009B
+:10A5C000000000000000000000000000000000008B
+:10A5D000000000000000000000000000000000007B
+:10A5E000000000000000000000000000000000006B
+:10A5F000000000000000000000000000000000005B
+:10A60000000000000000000000000000000000004A
+:10A61000000000000000000000000000000000003A
+:10A62000000000000000000000000000000000002A
+:10A63000000000000000000000000000000000001A
+:10A64000000000000000000000000000000000000A
+:10A6500000000000000000000000000000000000FA
+:10A6600000000000000000000000000000000000EA
+:10A6700000000000000000000000000000000000DA
+:10A6800000000000000000000000000000000000CA
+:10A6900000000000000000000000000000000000BA
+:10A6A00000000000000000000000000000000000AA
+:10A6B000000000000000000000000000000000009A
+:10A6C000000000000000000000000000000000008A
+:10A6D000000000000000000000000000000000007A
+:10A6E000000000000000000000000000000000006A
+:10A6F000000000000000000000000000000000005A
+:10A700000000000000000000000000000000000049
+:10A710000000000000000000000000000000000039
+:10A720000000000000000000000000000000000029
+:10A730000000000000000000000000000000000019
+:10A740000000000000000000000000000000000009
+:10A7500000000000000000000000000000000000F9
+:10A7600000000000000000000000000000000000E9
+:10A7700000000000000000000000000000000000D9
+:10A7800000000000000000000000000000000000C9
+:10A7900000000000000000000000000000000000B9
+:10A7A00000000000000000000000000000000000A9
+:10A7B0000000000000000000000000000000000099
+:10A7C0000000000000000000000000000000000089
+:10A7D0000000000000000000000000000000000079
+:10A7E0000000000000000000000000000000000069
+:10A7F0000000000000000000000000000000000059
+:10A800000000000000000000000000000000000048
+:10A810000000000000000000000000000000000038
+:10A820000000000000000000000000000000000028
+:10A830000000000000000000000000000000000018
+:10A840000000000000000000000000000000000008
+:10A8500000000000000000000000000000000000F8
+:10A8600000000000000000000000000000000000E8
+:10A8700000000000000000000000000000000000D8
+:10A8800000000000000000000000000000000000C8
+:10A8900000000000000000000000000000000000B8
+:10A8A00000000000000000000000000000000000A8
+:10A8B0000000000000000000000000000000000098
+:10A8C0000000000000000000000000000000000088
+:10A8D0000000000000000000000000000000000078
+:10A8E0000000000000000000000000000000000068
+:10A8F0000000000000000000000000000000000058
+:10A900000000000000000000000000000000000047
+:10A910000000000000000000000000000000000037
+:10A920000000000000000000000000000000000027
+:10A930000000000000000000000000000000000017
+:10A940000000000000000000000000000000000007
+:10A9500000000000000000000000000000000000F7
+:10A9600000000000000000000000000000000000E7
+:10A9700000000000000000000000000000000000D7
+:10A9800000000000000000000000000000000000C7
+:10A9900000000000000000000000000000000000B7
+:10A9A00000000000000000000000000000000000A7
+:10A9B0000000000000000000000000000000000097
+:10A9C0000000000000000000000000000000000087
+:10A9D0000000000000000000000000000000000077
+:10A9E0000000000000000000000000000000000067
+:10A9F0000000000000000000000000000000000057
+:10AA00000000000000000000000000000000000046
+:10AA10000000000000000000000000000000000036
+:10AA20000000000000000000000000000000000026
+:10AA30000000000000000000000000000000000016
+:10AA40000000000000000000000000000000000006
+:10AA500000000000000000000000000000000000F6
+:10AA600000000000000000000000000000000000E6
+:10AA700000000000000000000000000000000000D6
+:10AA800000000000000000000000000000000000C6
+:10AA900000000000000000000000000000000000B6
+:10AAA00000000000000000000000000000000000A6
+:10AAB0000000000000000000000000000000000096
+:10AAC0000000000000000000000000000000000086
+:10AAD0000000000000000000000000000000000076
+:10AAE0000000000000000000000000000000000066
+:10AAF0000000000000000000000000000000000056
+:10AB00000000000000000000000000000000000045
+:10AB10000000000000000000000000000000000035
+:10AB20000000000000000000000000000000000025
+:10AB30000000000000000000000000000000000015
+:10AB40000000000000000000000000000000000005
+:10AB500000000000000000000000000000000000F5
+:10AB600000000000000000000000000000000000E5
+:10AB700000000000000000000000000000000000D5
+:10AB800000000000000000000000000000000000C5
+:10AB900000000000000000000000000000000000B5
+:10ABA00000000000000000000000000000000000A5
+:10ABB0000000000000000000000000000000000095
+:10ABC0000000000000000000000000000000000085
+:10ABD0000000000000000000000000000000000075
+:10ABE0000000000000000000000000000000000065
+:10ABF0000000000000000000000000000000000055
+:10AC00000000000000000000000000000000000044
+:10AC10000000000000000000000000000000000034
+:10AC20000000000000000000000000000000000024
+:10AC30000000000000000000000000000000000014
+:10AC40000000000000000000000000000000000004
+:10AC500000000000000000000000000000000000F4
+:10AC600000000000000000000000000000000000E4
+:10AC700000000000000000000000000000000000D4
+:10AC800000000000000000000000000000000000C4
+:10AC900000000000000000000000000000000000B4
+:10ACA00000000000000000000000000000000000A4
+:10ACB0000000000000000000000000000000000094
+:10ACC0000000000000000000000000000000000084
+:10ACD0000000000000000000000000000000000074
+:10ACE0000000000000000000000000000000000064
+:10ACF0000000000000000000000000000000000054
+:10AD00000000000000000000000000000000000043
+:10AD10000000000000000000000000000000000033
+:10AD20000000000000000000000000000000000023
+:10AD30000000000000000000000000000000000013
+:10AD40000000000000000000000000000000000003
+:10AD500000000000000000000000000000000000F3
+:10AD600000000000000000000000000000000000E3
+:10AD700000000000000000000000000000000000D3
+:10AD800000000000000000000000000000000000C3
+:10AD900000000000000000000000000000000000B3
+:10ADA00000000000000000000000000000000000A3
+:10ADB0000000000000000000000000000000000093
+:10ADC0000000000000000000000000000000000083
+:10ADD0000000000000000000000000000000000073
+:10ADE0000000000000000000000000000000000063
+:10ADF0000000000000000000000000000000000053
+:10AE00000000000000000000000000000000000042
+:10AE10000000000000000000000000000000000032
+:10AE20000000000000000000000000000000000022
+:10AE30000000000000000000000000000000000012
+:10AE40000000000000000000000000000000000002
+:10AE500000000000000000000000000000000000F2
+:10AE600000000000000000000000000000000000E2
+:10AE700000000000000000000000000000000000D2
+:10AE800000000000000000000000000000000000C2
+:10AE900000000000000000000000000000000000B2
+:10AEA00000000000000000000000000000000000A2
+:10AEB0000000000000000000000000000000000092
+:10AEC0000000000000000000000000000000000082
+:10AED0000000000000000000000000000000000072
+:10AEE0000000000000000000000000000000000062
+:10AEF0000000000000000000000000000000000052
+:10AF00000000000000000000000000000000000041
+:10AF10000000000000000000000000000000000031
+:10AF20000000000000000000000000000000000021
+:10AF30000000000000000000000000000000000011
+:10AF40000000000000000000000000000000000001
+:10AF500000000000000000000000000000000000F1
+:10AF600000000000000000000000000000000000E1
+:10AF700000000000000000000000000000000000D1
+:10AF800000000000000000000000000000000000C1
+:10AF900000000000000000000000000000000000B1
+:10AFA00000000000000000000000000000000000A1
+:10AFB0000000000000000000000000000000000091
+:10AFC0000000000000000000000000000000000081
+:10AFD0000000000000000000000000000000000071
+:10AFE0000000000000000000000000000000000061
+:10AFF0000000000000000000000000000000000051
+:10B000000000000000000000000000000000000040
+:10B010000000000000000000000000000000000030
+:10B020000000000000000000000000000000000020
+:10B030000000000000000000000000000000000010
+:10B040000000000000000000000000000000000000
+:10B0500000000000000000000000000000000000F0
+:10B0600000000000000000000000000000000000E0
+:10B0700000000000000000000000000000000000D0
+:10B0800000000000000000000000000000000000C0
+:10B0900000000000000000000000000000000000B0
+:10B0A00000000000000000000000000000000000A0
+:10B0B0000000000000000000000000000000000090
+:10B0C0000000000000000000000000000000000080
+:10B0D0000000000000000000000000000000000070
+:10B0E0000000000000000000000000000000000060
+:10B0F0000000000000000000000000000000000050
+:10B10000000000000000000000000000000000003F
+:10B11000000000000000000000000000000000002F
+:10B12000000000000000000000000000000000001F
+:10B13000000000000000000000000000000000000F
+:10B1400000000000000000000000000000000000FF
+:10B1500000000000000000000000000000000000EF
+:10B1600000000000000000000000000000000000DF
+:10B1700000000000000000000000000000000000CF
+:10B1800000000000000000000000000000000000BF
+:10B1900000000000000000000000000000000000AF
+:10B1A000000000000000000000000000000000009F
+:10B1B000000000000000000000000000000000008F
+:10B1C000000000000000000000000000000000007F
+:10B1D000000000000000000000000000000000006F
+:10B1E000000000000000000000000000000000005F
+:10B1F000000000000000000000000000000000004F
+:10B20000000000000000000000000000000000003E
+:10B21000000000000000000000000000000000002E
+:10B22000000000000000000000000000000000001E
+:10B23000000000000000000000000000000000000E
+:10B2400000000000000000000000000000000000FE
+:10B2500000000000000000000000000000000000EE
+:10B2600000000000000000000000000000000000DE
+:10B2700000000000000000000000000000000000CE
+:10B2800000000000000000000000000000000000BE
+:10B2900000000000000000000000000000000000AE
+:10B2A000000000000000000000000000000000009E
+:10B2B000000000000000000000000000000000008E
+:10B2C000000000000000000000000000000000007E
+:10B2D000000000000000000000000000000000006E
+:10B2E000000000000000000000000000000000005E
+:10B2F000000000000000000000000000000000004E
+:10B30000000000000000000000000000000000003D
+:10B31000000000000000000000000000000000002D
+:10B32000000000000000000000000000000000001D
+:10B33000000000000000000000000000000000000D
+:10B3400000000000000000000000000000000000FD
+:10B3500000000000000000000000000000000000ED
+:10B3600000000000000000000000000000000000DD
+:10B3700000000000000000000000000000000000CD
+:10B3800000000000000000000000000000000000BD
+:10B3900000000000000000000000000000000000AD
+:10B3A000000000000000000000000000000000009D
+:10B3B000000000000000000000000000000000008D
+:10B3C000000000000000000000000000000000007D
+:10B3D000000000000000000000000000000000006D
+:10B3E000000000000000000000000000000000005D
+:10B3F000000000000000000000000000000000004D
+:10B40000000000000000000000000000000000003C
+:10B41000000000000000000000000000000000002C
+:10B42000000000000000000000000000000000001C
+:10B43000000000000000000000000000000000000C
+:10B4400000000000000000000000000000000000FC
+:10B4500000000000000000000000000000000000EC
+:10B4600000000000000000000000000000000000DC
+:10B4700000000000000000000000000000000000CC
+:10B4800000000000000000000000000000000000BC
+:10B4900000000000000000000000000000000000AC
+:10B4A000000000000000000000000000000000009C
+:10B4B000000000000000000000000000000000008C
+:10B4C000000000000000000000000000000000007C
+:10B4D000000000000000000000000000000000006C
+:10B4E000000000000000000000000000000000005C
+:10B4F000000000000000000000000000000000004C
+:10B50000000000000000000000000000000000003B
+:10B51000000000000000000000000000000000002B
+:10B52000000000000000000000000000000000001B
+:10B53000000000000000000000000000000000000B
+:10B5400000000000000000000000000000000000FB
+:10B5500000000000000000000000000000000000EB
+:10B5600000000000000000000000000000000000DB
+:10B5700000000000000000000000000000000000CB
+:10B5800000000000000000000000000000000000BB
+:10B5900000000000000000000000000000000000AB
+:10B5A000000000000000000000000000000000009B
+:10B5B000000000000000000000000000000000008B
+:10B5C000000000000000000000000000000000007B
+:10B5D000000000000000000000000000000000006B
+:10B5E000000000000000000000000000000000005B
+:10B5F000000000000000000000000000000000004B
+:10B60000000000000000000000000000000000003A
+:10B61000000000000000000000000000000000002A
+:10B62000000000000000000000000000000000001A
+:10B63000000000000000000000000000000000000A
+:10B6400000000000000000000000000000000000FA
+:10B6500000000000000000000000000000000000EA
+:10B6600000000000000000000000000000000000DA
+:10B6700000000000000000000000000000000000CA
+:10B6800000000000000000000000000000000000BA
+:10B6900000000000000000000000000000000000AA
+:10B6A000000000000000000000000000000000009A
+:10B6B000000000000000000000000000000000008A
+:10B6C000000000000000000000000000000000007A
+:10B6D000000000000000000000000000000000006A
+:10B6E000000000000000000000000000000000005A
+:10B6F000000000000000000000000000000000004A
+:10B700000000000000000000000000000000000039
+:10B710000000000000000000000000000000000029
+:10B720000000000000000000000000000000000019
+:10B730000000000000000000000000000000000009
+:10B7400000000000000000000000000000000000F9
+:10B7500000000000000000000000000000000000E9
+:10B7600000000000000000000000000000000000D9
+:10B7700000000000000000000000000000000000C9
+:10B7800000000000000000000000000000000000B9
+:10B7900000000000000000000000000000000000A9
+:10B7A0000000000000000000000000000000000099
+:10B7B0000000000000000000000000000000000089
+:10B7C0000000000000000000000000000000000079
+:10B7D0000000000000000000000000000000000069
+:10B7E0000000000000000000000000000000000059
+:10B7F0000000000000000000000000000000000049
+:10B800000000000000000000000000000000000038
+:10B810000000000000000000000000000000000028
+:10B820000000000000000000000000000000000018
+:10B830000000000000000000000000000000000008
+:10B8400000000000000000000000000000000000F8
+:10B8500000000000000000000000000000000000E8
+:10B8600000000000000000000000000000000000D8
+:10B8700000000000000000000000000000000000C8
+:10B8800000000000000000000000000000000000B8
+:10B8900000000000000000000000000000000000A8
+:10B8A0000000000000000000000000000000000098
+:10B8B0000000000000000000000000000000000088
+:10B8C0000000000000000000000000000000000078
+:10B8D0000000000000000000000000000000000068
+:10B8E0000000000000000000000000000000000058
+:10B8F0000000000000000000000000000000000048
+:10B900000000000000000000000000000000000037
+:10B910000000000000000000000000000000000027
+:10B920000000000000000000000000000000000017
+:10B930000000000000000000000000000000000007
+:10B9400000000000000000000000000000000000F7
+:10B9500000000000000000000000000000000000E7
+:10B9600000000000000000000000000000000000D7
+:10B9700000000000000000000000000000000000C7
+:10B9800000000000000000000000000000000000B7
+:10B9900000000000000000000000000000000000A7
+:10B9A0000000000000000000000000000000000097
+:10B9B0000000000000000000000000000000000087
+:10B9C0000000000000000000000000000000000077
+:10B9D0000000000000000000000000000000000067
+:10B9E0000000000000000000000000000000000057
+:10B9F0000000000000000000000000000000000047
+:10BA00000000000000000000000000000000000036
+:10BA10000000000000000000000000000000000026
+:10BA20000000000000000000000000000000000016
+:10BA30000000000000000000000000000000000006
+:10BA400000000000000000000000000000000000F6
+:10BA500000000000000000000000000000000000E6
+:10BA600000000000000000000000000000000000D6
+:10BA700000000000000000000000000000000000C6
+:10BA800000000000000000000000000000000000B6
+:10BA900000000000000000000000000000000000A6
+:10BAA0000000000000000000000000000000000096
+:10BAB0000000000000000000000000000000000086
+:10BAC0000000000000000000000000000000000076
+:10BAD0000000000000000000000000000000000066
+:10BAE0000000000000000000000000000000000056
+:10BAF0000000000000000000000000000000000046
+:10BB00000000000000000000000000000000000035
+:10BB10000000000000000000000000000000000025
+:10BB20000000000000000000000000000000000015
+:10BB30000000000000000000000000000000000005
+:10BB400000000000000000000000000000000000F5
+:10BB500000000000000000000000000000000000E5
+:10BB600000000000000000000000000000000000D5
+:10BB700000000000000000000000000000000000C5
+:10BB800000000000000000000000000000000000B5
+:10BB900000000000000000000000000000000000A5
+:10BBA0000000000000000000000000000000000095
+:10BBB0000000000000000000000000000000000085
+:10BBC0000000000000000000000000000000000075
+:10BBD0000000000000000000000000000000000065
+:10BBE0000000000000000000000000000000000055
+:10BBF0000000000000000000000000000000000045
+:10BC00000000000000000000000000000000000034
+:10BC10000000000000000000000000000000000024
+:10BC20000000000000000000000000000000000014
+:10BC30000000000000000000000000000000000004
+:10BC400000000000000000000000000000000000F4
+:10BC500000000000000000000000000000000000E4
+:10BC600000000000000000000000000000000000D4
+:10BC700000000000000000000000000000000000C4
+:10BC800000000000000000000000000000000000B4
+:10BC900000000000000000000000000000000000A4
+:10BCA0000000000000000000000000000000000094
+:10BCB0000000000000000000000000000000000084
+:10BCC0000000000000000000000000000000000074
+:10BCD0000000000000000000000000000000000064
+:10BCE0000000000000000000000000000000000054
+:10BCF0000000000000000000000000000000000044
+:10BD00000000000000000000000000000000000033
+:10BD10000000000000000000000000000000000023
+:10BD20000000000000000000000000000000000013
+:10BD30000000000000000000000000000000000003
+:10BD400000000000000000000000000000000000F3
+:10BD500000000000000000000000000000000000E3
+:10BD600000000000000000000000000000000000D3
+:10BD700000000000000000000000000000000000C3
+:10BD800000000000000000000000000000000000B3
+:10BD900000000000000000000000000000000000A3
+:10BDA0000000000000000000000000000000000093
+:10BDB0000000000000000000000000000000000083
+:10BDC0000000000000000000000000000000000073
+:10BDD0000000000000000000000000000000000063
+:10BDE0000000000000000000000000000000000053
+:10BDF0000000000000000000000000000000000043
+:10BE00000000000000000000000000000000000032
+:10BE10000000000000000000000000000000000022
+:10BE20000000000000000000000000000000000012
+:10BE30000000000000000000000000000000000002
+:10BE400000000000000000000000000000000000F2
+:10BE500000000000000000000000000000000000E2
+:10BE600000000000000000000000000000000000D2
+:10BE700000000000000000000000000000000000C2
+:10BE800000000000000000000000000000000000B2
+:10BE900000000000000000000000000000000000A2
+:10BEA0000000000000000000000000000000000092
+:10BEB0000000000000000000000000000000000082
+:10BEC0000000000000000000000000000000000072
+:10BED0000000000000000000000000000000000062
+:10BEE0000000000000000000000000000000000052
+:10BEF0000000000000000000000000000000000042
+:10BF00000000000000000000000000000000000031
+:10BF10000000000000000000000000000000000021
+:10BF20000000000000000000000000000000000011
+:10BF30000000000000000000000000000000000001
+:10BF400000000000000000000000000000000000F1
+:10BF500000000000000000000000000000000000E1
+:10BF600000000000000000000000000000000000D1
+:10BF700000000000000000000000000000000000C1
+:10BF800000000000000000000000000000000000B1
+:10BF900000000000000000000000000000000000A1
+:10BFA0000000000000000000000000000000000091
+:10BFB0000000000000000000000000000000000081
+:10BFC0000000000000000000000000000000000071
+:10BFD0000000000000000000000000000000000061
+:10BFE0000000000000000000000000000000000051
+:10BFF0000000000000000000000000000000000041
+:10C000000000000000000000000000000000000030
+:10C010000000000000000000000000000000000020
+:10C020000000000000000000000000000000000010
+:10C030000000000000000000000000000000000000
+:10C0400000000000000000000000000000000000F0
+:10C0500000000000000000000000000000000000E0
+:10C0600000000000000000000000000000000000D0
+:10C0700000000000000000000000000000000000C0
+:10C0800000000000000000000000000000000000B0
+:10C0900000000000000000000000000000000000A0
+:10C0A0000000000000000000000000000000000090
+:10C0B0000000000000000000000000000000000080
+:10C0C0000000000000000000000000000000000070
+:10C0D0000000000000000000000000000000000060
+:10C0E0000000000000000000000000000000000050
+:10C0F0000000000000000000000000000000000040
+:10C10000000000000000000000000000000000002F
+:10C11000000000000000000000000000000000001F
+:10C12000000000000000000000000000000000000F
+:10C1300000000000000000000000000000000000FF
+:10C1400000000000000000000000000000000000EF
+:10C1500000000000000000000000000000000000DF
+:10C1600000000000000000000000000000000000CF
+:10C1700000000000000000000000000000000000BF
+:10C1800000000000000000000000000000000000AF
+:10C19000000000000000000000000000000000009F
+:10C1A000000000000000000000000000000000008F
+:10C1B000000000000000000000000000000000007F
+:10C1C000000000000000000000000000000000006F
+:10C1D000000000000000000000000000000000005F
+:10C1E000000000000000000000000000000000004F
+:10C1F000000000000000000000000000000000003F
+:10C20000000000000000000000000000000000002E
+:10C21000000000000000000000000000000000001E
+:10C22000000000000000000000000000000000000E
+:10C2300000000000000000000000000000000000FE
+:10C2400000000000000000000000000000000000EE
+:10C2500000000000000000000000000000000000DE
+:10C2600000000000000000000000000000000000CE
+:10C2700000000000000000000000000000000000BE
+:10C2800000000000000000000000000000000000AE
+:10C29000000000000000000000000000000000009E
+:10C2A000000000000000000000000000000000008E
+:10C2B000000000000000000000000000000000007E
+:10C2C000000000000000000000000000000000006E
+:10C2D000000000000000000000000000000000005E
+:10C2E000000000000000000000000000000000004E
+:10C2F000000000000000000000000000000000003E
+:10C30000000000000000000000000000000000002D
+:10C31000000000000000000000000000000000001D
+:10C32000000000000000000000000000000000000D
+:10C3300000000000000000000000000000000000FD
+:10C3400000000000000000000000000000000000ED
+:10C3500000000000000000000000000000000000DD
+:10C3600000000000000000000000000000000000CD
+:10C3700000000000000000000000000000000000BD
+:10C3800000000000000000000000000000000000AD
+:10C39000000000000000000000000000000000009D
+:10C3A000000000000000000000000000000000008D
+:10C3B000000000000000000000000000000000007D
+:10C3C000000000000000000000000000000000006D
+:10C3D000000000000000000000000000000000005D
+:10C3E000000000000000000000000000000000004D
+:10C3F000000000000000000000000000000000003D
+:10C40000000000000000000000000000000000002C
+:10C41000000000000000000000000000000000001C
+:10C42000000000000000000000000000000000000C
+:10C4300000000000000000000000000000000000FC
+:10C4400000000000000000000000000000000000EC
+:10C4500000000000000000000000000000000000DC
+:10C4600000000000000000000000000000000000CC
+:10C4700000000000000000000000000000000000BC
+:10C4800000000000000000000000000000000000AC
+:10C49000000000000000000000000000000000009C
+:10C4A000000000000000000000000000000000008C
+:10C4B000000000000000000000000000000000007C
+:10C4C000000000000000000000000000000000006C
+:10C4D000000000000000000000000000000000005C
+:10C4E000000000000000000000000000000000004C
+:10C4F000000000000000000000000000000000003C
+:10C50000000000000000000000000000000000002B
+:10C51000000000000000000000000000000000001B
+:10C52000000000000000000000000000000000000B
+:10C5300000000000000000000000000000000000FB
+:10C5400000000000000000000000000000000000EB
+:10C5500000000000000000000000000000000000DB
+:10C5600000000000000000000000000000000000CB
+:10C5700000000000000000000000000000000000BB
+:10C5800000000000000000000000000000000000AB
+:10C59000000000000000000000000000000000009B
+:10C5A000000000000000000000000000000000008B
+:10C5B000000000000000000000000000000000007B
+:10C5C000000000000000000000000000000000006B
+:10C5D000000000000000000000000000000000005B
+:10C5E000000000000000000000000000000000004B
+:10C5F000000000000000000000000000000000003B
+:10C60000000000000000000000000000000000002A
+:10C61000000000000000000000000000000000001A
+:10C62000000000000000000000000000000000000A
+:10C6300000000000000000000000000000000000FA
+:10C6400000000000000000000000000000000000EA
+:10C6500000000000000000000000000000000000DA
+:10C6600000000000000000000000000000000000CA
+:10C6700000000000000000000000000000000000BA
+:10C6800000000000000000000000000000000000AA
+:10C69000000000000000000000000000000000009A
+:10C6A000000000000000000000000000000000008A
+:10C6B000000000000000000000000000000000007A
+:10C6C000000000000000000000000000000000006A
+:10C6D000000000000000000000000000000000005A
+:10C6E000000000000000000000000000000000004A
+:10C6F000000000000000000000000000000000003A
+:10C700000000000000000000000000000000000029
+:10C710000000000000000000000000000000000019
+:10C720000000000000000000000000000000000009
+:10C7300000000000000000000000000000000000F9
+:10C7400000000000000000000000000000000000E9
+:10C7500000000000000000000000000000000000D9
+:10C7600000000000000000000000000000000000C9
+:10C7700000000000000000000000000000000000B9
+:10C7800000000000000000000000000000000000A9
+:10C790000000000000000000000000000000000099
+:10C7A0000000000000000000000000000000000089
+:10C7B0000000000000000000000000000000000079
+:10C7C0000000000000000000000000000000000069
+:10C7D0000000000000000000000000000000000059
+:10C7E0000000000000000000000000000000000049
+:10C7F0000000000000000000000000000000000039
+:10C800000000000000000000000000000000000028
+:10C810000000000000000000000000000000000018
+:10C820000000000000000000000000000000000008
+:10C8300000000000000000000000000000000000F8
+:10C8400000000000000000000000000000000000E8
+:10C8500000000000000000000000000000000000D8
+:10C8600000000000000000000000000000000000C8
+:10C8700000000000000000000000000000000000B8
+:10C8800000000000000000000000000000000000A8
+:10C890000000000000000000000000000000000098
+:10C8A0000000000000000000000000000000000088
+:10C8B0000000000000000000000000000000000078
+:10C8C0000000000000000000000000000000000068
+:10C8D0000000000000000000000000000000000058
+:10C8E0000000000000000000000000000000000048
+:10C8F0000000000000000000000000000000000038
+:10C900000000000000000000000000000000000027
+:10C910000000000000000000000000000000000017
+:10C920000000000000000000000000000000000007
+:10C9300000000000000000000000000000000000F7
+:10C9400000000000000000000000000000000000E7
+:10C9500000000000000000000000000000000000D7
+:10C9600000000000000000000000000000000000C7
+:10C9700000000000000000000000000000000000B7
+:10C9800000000000000000000000000000000000A7
+:10C990000000000000000000000000000000000097
+:10C9A0000000000000000000000000000000000087
+:10C9B0000000000000000000000000000000000077
+:10C9C0000000000000000000000000000000000067
+:10C9D0000000000000000000000000000000000057
+:10C9E0000000000000000000000000000000000047
+:10C9F0000000000000000000000000000000000037
+:10CA00000000000000000000000000000000000026
+:10CA10000000000000000000000000000000000016
+:10CA20000000000000000000000000000000000006
+:10CA300000000000000000000000000000000000F6
+:10CA400000000000000000000000000000000000E6
+:10CA500000000000000000000000000000000000D6
+:10CA600000000000000000000000000000000000C6
+:10CA700000000000000000000000000000000000B6
+:10CA800000000000000000000000000000000000A6
+:10CA90000000000000000000000000000000000096
+:10CAA0000000000000000000000000000000000086
+:10CAB0000000000000000000000000000000000076
+:10CAC0000000000000000000000000000000000066
+:10CAD0000000000000000000000000000000000056
+:10CAE0000000000000000000000000000000000046
+:10CAF0000000000000000000000000000000000036
+:10CB00000000000000000000000000000000000025
+:10CB10000000000000000000000000000000000015
+:10CB20000000000000000000000000000000000005
+:10CB300000000000000000000000000000000000F5
+:10CB400000000000000000000000000000000000E5
+:10CB500000000000000000000000000000000000D5
+:10CB600000000000000000000000000000000000C5
+:10CB700000000000000000000000000000000000B5
+:10CB800000000000000000000000000000000000A5
+:10CB90000000000000000000000000000000000095
+:10CBA0000000000000000000000000000000000085
+:10CBB0000000000000000000000000000000000075
+:10CBC0000000000000000000000000000000000065
+:10CBD0000000000000000000000000000000000055
+:10CBE0000000000000000000000000000000000045
+:10CBF0000000000000000000000000000000000035
+:10CC00000000000000000000000000000000000024
+:10CC10000000000000000000000000000000000014
+:10CC20000000000000000000000000000000000004
+:10CC300000000000000000000000000000000000F4
+:10CC400000000000000000000000000000000000E4
+:10CC500000000000000000000000000000000000D4
+:10CC600000000000000000000000000000000000C4
+:10CC700000000000000000000000000000000000B4
+:10CC800000000000000000000000000000000000A4
+:10CC90000000000000000000000000000000000094
+:10CCA0000000000000000000000000000000000084
+:10CCB0000000000000000000000000000000000074
+:10CCC0000000000000000000000000000000000064
+:10CCD0000000000000000000000000000000000054
+:10CCE0000000000000000000000000000000000044
+:10CCF0000000000000000000000000000000000034
+:10CD00000000000000000000000000000000000023
+:10CD10000000000000000000000000000000000013
+:10CD20000000000000000000000000000000000003
+:10CD300000000000000000000000000000000000F3
+:10CD400000000000000000000000000000000000E3
+:10CD500000000000000000000000000000000000D3
+:10CD600000000000000000000000000000000000C3
+:10CD700000000000000000000000000000000000B3
+:10CD800000000000000000000000000000000000A3
+:10CD90000000000000000000000000000000000093
+:10CDA0000000000000000000000000000000000083
+:10CDB0000000000000000000000000000000000073
+:10CDC0000000000000000000000000000000000063
+:10CDD0000000000000000000000000000000000053
+:10CDE0000000000000000000000000000000000043
+:10CDF0000000000000000000000000000000000033
+:10CE00000000000000000000000000000000000022
+:10CE10000000000000000000000000000000000012
+:10CE20000000000000000000000000000000000002
+:10CE300000000000000000000000000000000000F2
+:10CE400000000000000000000000000000000000E2
+:10CE500000000000000000000000000000000000D2
+:10CE600000000000000000000000000000000000C2
+:10CE700000000000000000000000000000000000B2
+:10CE800000000000000000000000000000000000A2
+:10CE90000000000000000000000000000000000092
+:10CEA0000000000000000000000000000000000082
+:10CEB0000000000000000000000000000000000072
+:10CEC0000000000000000000000000000000000062
+:10CED0000000000000000000000000000000000052
+:10CEE0000000000000000000000000000000000042
+:10CEF0000000000000000000000000000000000032
+:10CF00000000000000000000000000000000000021
+:10CF10000000000000000000000000000000000011
+:10CF20000000000000000000000000000000000001
+:10CF300000000000000000000000000000000000F1
+:10CF400000000000000000000000000000000000E1
+:10CF500000000000000000000000000000000000D1
+:10CF600000000000000000000000000000000000C1
+:10CF700000000000000000000000000000000000B1
+:10CF800000000000000000000000000000000000A1
+:10CF90000000000000000000000000000000000091
+:10CFA0000000000000000000000000000000000081
+:10CFB0000000000000000000000000000000000071
+:10CFC0000000000000000000000000000000000061
+:10CFD0000000000000000000000000000000000051
+:10CFE0000000000000000000000000000000000041
+:10CFF0000000000000000000000000000000000031
+:10D000000000000000000000000000000000000020
+:10D010000000000000000000000000000000000010
+:10D020000000000000000000000000000000000000
+:10D0300000000000000000000000000000000000F0
+:10D0400000000000000000000000000000000000E0
+:10D0500000000000000000000000000000000000D0
+:10D0600000000000000000000000000000000000C0
+:10D0700000000000000000000000000000000000B0
+:10D0800000000000000000000000000000000000A0
+:10D090000000000000000000000000000000000090
+:10D0A0000000000000000000000000000000000080
+:10D0B0000000000000000000000000000000000070
+:10D0C0000000000000000000000000000000000060
+:10D0D0000000000000000000000000000000000050
+:10D0E0000000000000000000000000000000000040
+:10D0F0000000000000000000000000000000000030
+:10D10000000000000000000000000000000000001F
+:10D11000000000000000000000000000000000000F
+:10D1200000000000000000000000000000000000FF
+:10D1300000000000000000000000000000000000EF
+:10D1400000000000000000000000000000000000DF
+:10D1500000000000000000000000000000000000CF
+:10D1600000000000000000000000000000000000BF
+:10D1700000000000000000000000000000000000AF
+:10D18000000000000000000000000000000000009F
+:10D19000000000000000000000000000000000008F
+:10D1A000000000000000000000000000000000007F
+:10D1B000000000000000000000000000000000006F
+:10D1C000000000000000000000000000000000005F
+:10D1D000000000000000000000000000000000004F
+:10D1E000000000000000000000000000000000003F
+:10D1F000000000000000000000000000000000002F
+:10D20000000000000000000000000000000000001E
+:10D21000000000000000000000000000000000000E
+:10D2200000000000000000000000000000000000FE
+:10D2300000000000000000000000000000000000EE
+:10D2400000000000000000000000000000000000DE
+:10D2500000000000000000000000000000000000CE
+:10D2600000000000000000000000000000000000BE
+:10D2700000000000000000000000000000000000AE
+:10D28000000000000000000000000000000000009E
+:10D29000000000000000000000000000000000008E
+:10D2A000000000000000000000000000000000007E
+:10D2B000000000000000000000000000000000006E
+:10D2C000000000000000000000000000000000005E
+:10D2D000000000000000000000000000000000004E
+:10D2E000000000000000000000000000000000003E
+:10D2F000000000000000000000000000000000002E
+:10D30000000000000000000000000000000000001D
+:10D31000000000000000000000000000000000000D
+:10D3200000000000000000000000000000000000FD
+:10D3300000000000000000000000000000000000ED
+:10D3400000000000000000000000000000000000DD
+:10D3500000000000000000000000000000000000CD
+:10D3600000000000000000000000000000000000BD
+:10D3700000000000000000000000000000000000AD
+:10D38000000000000000000000000000000000009D
+:10D39000000000000000000000000000000000008D
+:10D3A000000000000000000000000000000000007D
+:10D3B000000000000000000000000000000000006D
+:10D3C000000000000000000000000000000000005D
+:10D3D000000000000000000000000000000000004D
+:10D3E000000000000000000000000000000000003D
+:10D3F000000000000000000000000000000000002D
+:10D40000000000000000000000000000000000001C
+:10D41000000000000000000000000000000000000C
+:10D4200000000000000000000000000000000000FC
+:10D4300000000000000000000000000000000000EC
+:10D4400000000000000000000000000000000000DC
+:10D4500000000000000000000000000000000000CC
+:10D4600000000000000000000000000000000000BC
+:10D4700000000000000000000000000000000000AC
+:10D48000000000000000000000000000000000009C
+:10D49000000000000000000000000000000000008C
+:10D4A000000000000000000000000000000000007C
+:10D4B000000000000000000000000000000000006C
+:10D4C000000000000000000000000000000000005C
+:10D4D000000000000000000000000000000000004C
+:10D4E000000000000000000000000000000000003C
+:10D4F000000000000000000000000000000000002C
+:10D50000000000000000000000000000000000001B
+:10D51000000000000000000000000000000000000B
+:10D5200000000000000000000000000000000000FB
+:10D5300000000000000000000000000000000000EB
+:10D5400000000000000000000000000000000000DB
+:10D5500000000000000000000000000000000000CB
+:10D5600000000000000000000000000000000000BB
+:10D5700000000000000000000000000000000000AB
+:10D58000000000000000000000000000000000009B
+:10D59000000000000000008000000000000000000B
+:10D5A000000000000000000000000000000000007B
+:10D5B00000000000000000000000000A0000000061
+:10D5C0000000000000000000100000030000000048
+:10D5D0000000000D0000000D3C02080024427340D2
+:10D5E0003C030800246377CCAC4000000043202BB0
+:10D5F0001480FFFD244200043C1D080037BD7FFC61
+:10D6000003A0F0213C100800261032103C1C08003A
+:10D61000279C73400E0010FE000000000000000D6B
+:10D6200030A5FFFF30C600FF274301808F4201B8BD
+:10D630000440FFFE24020002AC640000A465000860
+:10D64000A066000AA062000B3C021000AC67001844
+:10D6500003E00008AF4201B83C0360008C624FF861
+:10D660000440FFFE3C020200AC644FC0AC624FC4F9
+:10D670003C02100003E00008AC624FF89482000CFA
+:10D680002486001400A0382100021302000210803A
+:10D690000082402100C8102B1040005700000000FD
+:10D6A00090C300002C6200095040005190C200015C
+:10D6B000000310803C030800246372F00043102133
+:10D6C0008C420000004000080000000090C30001F0
+:10D6D0002402000A1462003A000000000106102330
+:10D6E0002C42000A1440003624C600028CE20000DE
+:10D6F00034420100ACE2000090C2000090C300017F
+:10D7000090C4000290C5000300031C000002160034
+:10D710000043102500042200004410250045102578
+:10D7200024C60004ACE2000490C2000090C30001D3
+:10D7300090C4000290C500030002160000031C0004
+:10D740000043102500042200004410250045102548
+:10D7500024C600040A000CB8ACE2000890C3000123
+:10D76000240200041462001624C6000290C20000C5
+:10D7700090C400018CE30000000212000044102558
+:10D780003463000424C60002ACE2000C0A000CB8AA
+:10D79000ACE3000090C300012402000314620008FF
+:10D7A00024C600028CE2000090C3000024C60001E1
+:10D7B00034420008A0E300100A000CB8ACE20000FC
+:10D7C00003E000082402000190C3000124020002CB
+:10D7D0001062000224C40002010020210A000CB8DB
+:10D7E000008030210A000CB824C6000190C200015C
+:10D7F0000A000CB800C2302103E00008000010212C
+:10D8000027BDFFE8AFBF0014AFB000100E00130239
+:10D8100000808021936200052403FFFE0200202186
+:10D82000004310248FBF00148FB00010A3620005C6
+:10D830000A00130B27BD001827BDFFE8AFB000108A
+:10D84000AFBF00140E000F3C0080802193620000E7
+:10D8500024030050304200FF14430004240201005E
+:10D86000AF4201800A000D3002002021AF4001804C
+:10D87000020020218FBF00148FB000100A000FE7B4
+:10D8800027BD001827BDFF80AFBE0078AFB700747A
+:10D89000AFB20060AFBF007CAFB60070AFB5006C38
+:10D8A000AFB40068AFB30064AFB1005CAFB0005874
+:10D8B0008F5001283C0208008C4231A02403FF80D5
+:10D8C0009365003F0202102100431024AF42002460
+:10D8D0003C0208008C4231A09364000530B200FF86
+:10D8E000020210213042007F034218210004202749
+:10D8F0003C02000A0062182130840001AF8300144A
+:10D900000000F0210000B82114800053AFA00050A7
+:10D9100093430116934401128F450104306300FFC5
+:10D920003C020001308400FF00A2282403431021A0
+:10D9300003441821245640002467400014A001CD60
+:10D940002402000193620000304300FF2402002003
+:10D950001062000524020050106200060000000062
+:10D960000A000D74000000000000000D0A000D7D8B
+:10D97000AFA000303C1E080027DE738C0A000D7D2E
+:10D98000AFA000303C0208008C4200DC24420001C1
+:10D990003C010800AC2200DC0E00139F00000000D8
+:10D9A0000A000F318FBF007C8F4201043C0300202E
+:10D9B00092D3000D004310240002202B00042140CC
+:10D9C000AFA400308F4301043C02004000621824E1
+:10D9D000146000023485004000802821326200205B
+:10D9E000AFA500301440000234A6008000A0302112
+:10D9F00010C0000BAFA6003093C500088F67004C25
+:10DA00000200202100052B0034A5008130A5F08103
+:10DA10000E000C9B30C600FF0A000F2E0000000015
+:10DA20009362003E304200401040000F2402000488
+:10DA300056420007240200120200202100E02821A3
+:10DA40000E0013F702C030210A000F318FBF007C97
+:10DA500016420005000000000E000D2100002021EC
+:10DA60000A000F318FBF007C9743011A96C4000E45
+:10DA700093620035326500043075FFFF00442004D6
+:10DA8000AFA400548ED1000410A000158ED400085D
+:10DA90009362003E3042004010400007000000004A
+:10DAA0000E0013E0022020211040000D00000000B5
+:10DAB0000A000F2E000000008F6200440222102393
+:10DAC0000440016A000000008F6200480222102317
+:10DAD00004410166240400160A000E218FC20004CE
+:10DAE0008F6200480222102304400008000000005A
+:10DAF0003C0208008C423100244200013C01080035
+:10DB0000AC2231000A000F23000000008F620040A9
+:10DB100002221023184000128F8400143C020800D7
+:10DB20008C423100327300FC0000A8212442000125
+:10DB30003C010800AC2231008F6300409482011C3C
+:10DB4000022318233042FFFF0043102A50400010E8
+:10DB50002402000C8F6200400A000DF20222102302
+:10DB60009483011C9762003C0043102B1040000678
+:10DB7000000000009482011C00551023A482011CA7
+:10DB80000A000DF72402000CA480011C2402000CE2
+:10DB9000AFA200308F620040005120231880000D9A
+:10DBA00002A4102A1440012600000000149500066B
+:10DBB00002A410233A620001304200011440012007
+:10DBC0000000000002A41023022488210A000E098C
+:10DBD0003055FFFF00002021326200021040001A81
+:10DBE000326200109362003E30420040504000110B
+:10DBF0008FC200040E00130202002021240200182C
+:10DC0000A362003F936200052403FFFE020020216F
+:10DC1000004310240E00130BA362000524040039F6
+:10DC2000000028210E0013C9240600180A000F3036
+:10DC300024020001240400170040F809000000003D
+:10DC40000A000F302402000110400108000000000B
+:10DC50008F63004C8F620054028210231C4001032A
+:10DC600002831023044200010060A021AFA4001829
+:10DC7000AFB10010AFB50014934201208F65004092
+:10DC80009763003C304200FF034210210044102102
+:10DC90008FA400543063FFFF244240000083182B00
+:10DCA0008FA40030AFA20020AFA50028008320255C
+:10DCB000AFA40030AFA50024AFA0002CAFB4003457
+:10DCC0009362003E30420008504000118FC20000B5
+:10DCD00002C0202127A500380E000CB2AFA00038EA
+:10DCE0005440000B8FC200008FA200383042010068
+:10DCF000504000078FC200008FA3003C8F6200607D
+:10DD00000062102304430001AF6300608FC2000073
+:10DD10000040F80927A400108FA200303042000212
+:10DD200054400001327300FE9362003E30420040D6
+:10DD3000104000378FA200248F6200541682001A10
+:10DD40003262000124020014124200102A4200151F
+:10DD500010400006240200162402000C12420007A4
+:10DD6000326200010A000E7D000000001242000530
+:10DD7000326200010A000E7D000000000A000E78E9
+:10DD80002417000E0A000E78241700100A000E7CDB
+:10DD900024170012936200232403FFBD00431024C4
+:10DDA000A362002332620001104000198FA20024F8
+:10DDB0002402000C1242000E2A42000D1040000600
+:10DDC0002402000E2402000A124200078FA200243F
+:10DDD0000A000E9524420001124200088FA200247E
+:10DDE0000A000E95244200010A000E932417000831
+:10DDF0002402000E16E20002241700162417001059
+:10DE00008FA2002424420001AFA200248FA200248C
+:10DE10008FA300148F76004000431021AF620040B2
+:10DE20008F8200149442011C104000090000000081
+:10DE30008F6200488F6400409763003C00441023C9
+:10DE40003063FFFF0043102A104000088FA20054E7
+:10DE5000936400368F6300403402FFFC008210049C
+:10DE600000621821AF6300488FA200548FA60030D3
+:10DE70000282902130C200081040000E0000000015
+:10DE80008F6200581642000430C600FF9742011A04
+:10DE90005040000134C6001093C500088FA700341D
+:10DEA0000200202100052B0034A500800E000C9BF1
+:10DEB00030A5F0808F620040005610231840001BF0
+:10DEC0008FA200183C0208008C42319830420010AA
+:10DED0001040000D24020001976200681440000AFF
+:10DEE000240200018F8200149442011C1440000699
+:10DEF00024020001A76200689742007A244200646D
+:10DF00000A000EE9A7620012A76200120E001302B7
+:10DF1000020020219362007D2403000102002021E1
+:10DF2000344200010A000EE7AFA300501840000A77
+:10DF3000000000000E001302020020219362007D09
+:10DF40002403000102002021AFA30050344200044A
+:10DF50000E00130BA362007D9362003E304200402E
+:10DF60001440000C326200011040000A0000000062
+:10DF70008F6300408FC20004240400182463000152
+:10DF80000040F809AF6300408FA200300A000F3054
+:10DF9000304200048F620058105200100000000050
+:10DFA0008F620018022210231C4000082404000184
+:10DFB0008F62001816220009000000008F62001C0A
+:10DFC000028210230440000500000000AF720058D8
+:10DFD000AFA40050AF710018AF74001C12E0000B2A
+:10DFE0008FA200500E00130202002021A377003FF1
+:10DFF0000E00130B0200202102E030212404003720
+:10E000000E0013C9000028218FA200501040000309
+:10E01000000000000E000CA90200202112A0000543
+:10E02000000018218FA2003030420004504000113F
+:10E0300000601021240300010A000F30006010214D
+:10E040000E001302020020219362007D02002021B5
+:10E05000344200040E00130BA362007D0E000CA9D5
+:10E06000020020210A000F3024020001AF400044CA
+:10E07000240200018FBF007C8FBE00788FB7007430
+:10E080008FB600708FB5006C8FB400688FB30064DA
+:10E090008FB200608FB1005C8FB0005803E00008C1
+:10E0A00027BD00808F4201B80440FFFE2402080013
+:10E0B000AF4201B803E00008000000003C02000885
+:10E0C00003421021944200483084FFFF2484001250
+:10E0D0003045FFFF10A0001700A4102B10400016C1
+:10E0E00024020003934201202403001AA343018B5E
+:10E0F000304200FF2446FFFE8F82000000A6182B4E
+:10E100003863000100021382004310241040000510
+:10E110008F84000434820001A746019403E00008C4
+:10E12000AF8200042402FFFE0082102403E00008F6
+:10E13000AF8200042402000303E00008A342018B25
+:10E1400027BDFFE0AFB10014AFB00010AFBF0018A3
+:10E1500030B0FFFF30D1FFFF8F4201B80440FFFE17
+:10E1600000000000AF440180AF4400200E000F42C9
+:10E17000020020218F8300008F840004A750019AA1
+:10E18000A750018EA74301908F8300083082800042
+:10E19000AF4301A8A75101881040000E8F820004F0
+:10E1A00093420116304200FC24420004005A102120
+:10E1B0008C4240003042FFFF144000068F82000472
+:10E1C0003C02FFFF34427FFF00821024AF82000434
+:10E1D0008F8200042403BFFF00431024A74201A63E
+:10E1E0009743010C8F42010400031C003042FFFFE3
+:10E1F00000621825AF4301AC3C021000AF4201B8E9
+:10E200008FBF00188FB100148FB0001003E000081A
+:10E2100027BD00208F470070934201128F830000BA
+:10E2200027BDFFF0304200FF00022882306201006B
+:10E23000000030211040004324A40003306240005D
+:10E24000104000103062200000041080005A10219D
+:10E250008C43400024A4000400041080AFA30000FD
+:10E26000005A10218C424000AFA2000493420116D4
+:10E27000304200FC005A10218C4240000A000FC0BE
+:10E28000AFA200081040002F0000302100041080D1
+:10E29000005A10218C43400024A400040004108084
+:10E2A000AFA30000005A10218C424000AFA000082C
+:10E2B000AFA200048FA80008000030210000202138
+:10E2C000240A00083C0908002529010003A41021A4
+:10E2D000148A000300042A001100000A0000000054
+:10E2E00090420000248400012C83000C00A2102125
+:10E2F00000021080004910218C4200001460FFF3DE
+:10E3000000C230263C0408008C8431048F42007027
+:10E310002C83002010600009004738233C030800CC
+:10E32000246331080004108000431021248300017D
+:10E33000AC4700003C010800AC233104AF86000864
+:10E340002406000100C0102103E0000827BD0010D2
+:10E350003C0208008C42003827BDFFD0AFB5002436
+:10E36000AFB40020AFB10014AFBF0028AFB3001CA2
+:10E37000AFB20018AFB00010000088213C150800B3
+:10E3800026B50038144000022454FFFF0000A021ED
+:10E390009742010E8F8400003042FFFF308340001F
+:10E3A0001060000A245200043C0200200082102465
+:10E3B00050400007308280008F8200042403BFFF9A
+:10E3C000008318240A0010103442100030828000AC
+:10E3D0001040000A3C020020008210241040000778
+:10E3E0008F8200043C03FFFF34637FFF0083182407
+:10E3F00034428000AF820004AF8300000E000F980B
+:10E400000000000014400007000000009743011EB8
+:10E410009742011C3063FFFF0002140000621825C0
+:10E42000AF8300089742010C8F4340003045FFFF47
+:10E430003402FFFF14620003000000000A001028ED
+:10E44000241100208F42400030420100544000015E
+:10E45000241100108F8400003082100050400014FE
+:10E4600036310001308200201440000B3C021000C5
+:10E47000008210245040000E363100013C030E0093
+:10E480003C020DFF008318243442FFFF0043102B91
+:10E4900050400007363100013C0208008C42002C3D
+:10E4A000244200013C010800AC22002C363100055A
+:10E4B0003C0608008CC6003454C000238F85000041
+:10E4C0008F820004304240005440001F8F850000BE
+:10E4D0003C021F01008210243C0310005443001A28
+:10E4E0008F85000030A20200144000178F850000C5
+:10E4F0003250FFFF363100028F4201B80440FFFE68
+:10E5000000000000AF400180020020210E000F42F9
+:10E51000AF4000208F8300042402BFFFA750019A60
+:10E52000006218248F820000A750018EA751018835
+:10E53000A74301A6A74201903C021000AF4201B8D8
+:10E540000A0010F5000010213C02100000A2102467
+:10E550001040003A0000000010C0000F0000000052
+:10E5600030A201001040000C3C0302003C020F00EE
+:10E5700000A2102410430008000000008F82000851
+:10E58000005410240055102190420004244200043D
+:10E590000A00109F000221C00000000000051602C2
+:10E5A0003050000F3A0300022E4203EF38420001C0
+:10E5B0002C6300010062182414600073240200011F
+:10E5C0003C0308008C6300D02E06000C386200016A
+:10E5D0002C4200010046102414400015001021C0F8
+:10E5E0002602FFFC2C4200045440001100002021B0
+:10E5F000386200022C420001004610241040000343
+:10E60000000512420A00109F000020210010182B64
+:10E610000043102450400006001021C000002021BB
+:10E620003245FFFF0E000F633226FFFB001021C0B2
+:10E630003245FFFF0A0010F2362600028F424000EA
+:10E640003C0308008C630024304201001040004667
+:10E6500030620001322200043070000D14400002CC
+:10E660002413000424130002000512C238420001E2
+:10E670002E4303EF304200013863000100431025B0
+:10E68000104000033231FFFB2402FFFB0202802412
+:10E6900010C000183202000130A201001040001525
+:10E6A000320200013C020F0000A210243C030200D1
+:10E6B0001043000F8F8200082403FFFE0203802412
+:10E6C00000541024005510219042000402333025DC
+:10E6D0002442000412000002000221C03226FFFF83
+:10E6E0000E000F633245FFFF1200002700001021CB
+:10E6F000320200011040000D320200042402000129
+:10E7000012020002023330253226FFFF00002021D2
+:10E710000E000F633245FFFF2402FFFE0202802439
+:10E7200012000019000010213202000410400016EF
+:10E7300024020001240200041202000202333025E8
+:10E740003226FFFF3245FFFF0E000F632404010055
+:10E750002402FFFB020280241200000B00001021A3
+:10E760000A0010F5240200011040000700001021EB
+:10E770003245FFFF36260002000020210E000F6305
+:10E7800000000000000010218FBF00288FB500247A
+:10E790008FB400208FB3001C8FB200188FB100140B
+:10E7A0008FB0001003E0000827BD003027BDFFD068
+:10E7B000AFB000103C04600CAFBF002CAFB6002817
+:10E7C000AFB50024AFB40020AFB3001CAFB2001847
+:10E7D000AFB100148C8250002403FF7F3C1A8000EC
+:10E7E000004310243442380CAC8250002402000351
+:10E7F0003C106000AF4200088E0208083C1B8008F5
+:10E800003C010800AC2000203042FFF038420010EC
+:10E810002C4200010E001B8DAF8200183C04FFFF4C
+:10E820003C020400348308063442000CAE0219484E
+:10E83000AE03194C3C0560168E0219808CA30000B3
+:10E840003442020000641824AE0219803C02535383
+:10E850001462000334A47C008CA200040050202128
+:10E860008C82007C8C830078AF820010AF83000C18
+:10E870008F55000032A200031040FFFD32A20001BC
+:10E880001040013D32A200028F420128AF42002019
+:10E890008F4201048F430100AF8200000E000F3C45
+:10E8A000AF8300043C0208008C4200C01040000806
+:10E8B0008F8400003C0208008C4200C42442000106
+:10E8C0003C010800AC2200C40A00126900000000EC
+:10E8D0003C020010008210241440010C8F830004BD
+:10E8E0003C0208008C4200203C0308008C63003886
+:10E8F00000008821244200013C010800AC220020D5
+:10E900003C16080026D60038146000022474FFFF6D
+:10E910000000A0219742010E308340003042FFFFEB
+:10E920001060000A245200043C02002000821024DF
+:10E9300050400007308280008F8200042403BFFF14
+:10E94000008318240A0011703442100030828000C5
+:10E950001040000A3C0200200082102410400007F2
+:10E960008F8200043C03FFFF34637FFF0083182481
+:10E9700034428000AF820004AF8300000E000F9885
+:10E980000000000014400007000000009743011E33
+:10E990009742011C3063FFFF00021400006218253B
+:10E9A000AF8300089742010C8F4340003045FFFFC2
+:10E9B0003402FFFF14620003000000000A00118807
+:10E9C000241100208F4240003042010054400001D9
+:10E9D000241100108F840000308210005040001479
+:10E9E00036310001308200201440000B3C02100040
+:10E9F000008210245040000E363100013C030E000E
+:10EA00003C020DFF008318243442FFFF0043102B0B
+:10EA100050400007363100013C0208008C42002CB7
+:10EA2000244200013C010800AC22002C36310005D4
+:10EA30003C0608008CC6003454C000238F850000BB
+:10EA40008F820004304240005440001F8F85000038
+:10EA50003C021F01008210243C0310005443001AA2
+:10EA60008F85000030A20200144000178F8500003F
+:10EA70003250FFFF363100028F4201B80440FFFEE2
+:10EA800000000000AF400180020020210E000F4274
+:10EA9000AF4000208F8300042402BFFFA750019ADB
+:10EAA000006218248F820000A750018EA7510188B0
+:10EAB000A74301A6A74201903C021000AF4201B853
+:10EAC0000A001267000010213C02100000A210246E
+:10EAD0001040003A0000000010C0000F00000000CD
+:10EAE00030A201001040000C3C0302003C020F0069
+:10EAF00000A2102410430008000000008F820008CC
+:10EB000000541024005610219042000424420004B6
+:10EB10000A0011FF000221C00000000000051602DB
+:10EB20003050000F3A0300022E4203EF384200013A
+:10EB30002C63000100621824146000852402000187
+:10EB40003C0308008C6300D02E06000C38620001E4
+:10EB50002C4200010046102414400015001021C072
+:10EB60002602FFFC2C42000454400011000020212A
+:10EB7000386200022C42000100461024504000037D
+:10EB8000000512420A0011FF000020210010182B7E
+:10EB90000043102450400006001021C00000202136
+:10EBA0003245FFFF0E000F633226FFFB001021C02D
+:10EBB0003245FFFF0A001252362600028F42400003
+:10EBC0003C0308008C6300243042010010400046E2
+:10EBD00030620001322200043070000D1440000247
+:10EBE0002413000424130002000512C2384200015D
+:10EBF0002E4303EF3042000138630001004310252B
+:10EC0000104000033231FFFB2402FFFB020280248C
+:10EC100010C000183202000130A20100104000159F
+:10EC2000320200013C020F0000A210243C0302004B
+:10EC30001043000F8F8200082403FFFE020380248C
+:10EC40000054102400561021904200040233302555
+:10EC50002442000412000002000221C03226FFFFFD
+:10EC60000E000F633245FFFF120000390000102133
+:10EC7000320200011040000D3202000424020001A3
+:10EC800012020002023330253226FFFF000020214D
+:10EC90000E000F633245FFFF2402FFFE02028024B4
+:10ECA0001200002B00001021320200041040002846
+:10ECB0002402000124020004120200020233302563
+:10ECC0003226FFFF3245FFFF0E000F6324040100D0
+:10ECD0002402FFFB020280241200001D000010210C
+:10ECE0000A001267240200015040001900001021A0
+:10ECF0003245FFFF36260002000020210E000F6380
+:10ED0000000000000A001267000010212402BFFF6B
+:10ED1000006210241040000800000000240287FF59
+:10ED200000621024144000083C020060008210249D
+:10ED300010400005000000000E000D34000000002F
+:10ED40000A001267000000000E0012C70000000059
+:10ED5000104000063C0240008F4301243C0260202A
+:10ED6000AC430014000000003C024000AF420138F8
+:10ED70000000000032A200021040FEBD00000000B2
+:10ED80008F4201403C044000AF4200208F430148C5
+:10ED90003C02700000621824106400420000000071
+:10EDA0000083102B144000063C0260003C0220004F
+:10EDB000106200073C0240000A0012C3000000007D
+:10EDC0001062003C3C0240000A0012C30000000038
+:10EDD0008F4501408F4601448F42014800021402D2
+:10EDE000304300FF240200041462000A274401801B
+:10EDF0008F4201B80440FFFE2402001CAC850000D5
+:10EE0000A082000B3C021000AF4201B80A0012C3FE
+:10EE10003C0240002402000914620012000616029F
+:10EE2000000229C0AF4500208F4201B80440FFFE18
+:10EE30002402000124030003AF450180A343018B9A
+:10EE4000A740018EA740019AA7400190AF4001A8BA
+:10EE5000A7420188A74201A6AF4001AC3C021000C6
+:10EE6000AF4201B88F4201B80440FFFE000000002D
+:10EE7000AC8500008F42014800021402A482000801
+:10EE800024020002A082000B8F420148A4820010DD
+:10EE90003C021000AC860024AF4201B80A0012C345
+:10EEA0003C0240000E001310000000000A0012C3D4
+:10EEB0003C0240000E001BC2000000003C0240006B
+:10EEC000AF420178000000000A00112F000000008E
+:10EED0008F4201003042003E144000112402000124
+:10EEE000AF4000488F420100304207C0104000058B
+:10EEF00000000000AF40004CAF40005003E00008AD
+:10EF000024020001AF400054AF4000408F42010096
+:10EF10003042380054400001AF4000442402000158
+:10EF200003E00008000000008F4201B80440FFFE2B
+:10EF300024020001AF440180AF400184A74501884D
+:10EF4000A342018A24020002A342018B9742014A94
+:10EF500014C00004A7420190AF4001A40A0012EFC0
+:10EF60003C0210008F420144AF4201A43C02100059
+:10EF7000AF4001A803E00008AF4201B88F4201B8DA
+:10EF80000440FFFE24020002AF440180AF4401842C
+:10EF9000A7450188A342018AA342018B9742014AF7
+:10EFA000A7420190AF4001A48F420144AF4201A8A3
+:10EFB0003C02100003E00008AF4201B83C029000A0
+:10EFC0003442000100822025AF4400208F420020FF
+:10EFD0000440FFFE0000000003E000080000000005
+:10EFE0003C028000344200010082202503E000083A
+:10EFF000AF44002027BDFFE8AFBF0014AFB0001042
+:10F000008F50014093430149934201489344014882
+:10F01000306300FF304200FF00021200006228252A
+:10F020002402001910620076308400802862001AE1
+:10F030001040001C24020020240200081062007707
+:10F04000286200091040000E2402000B2402000177
+:10F0500010620034286200025040000524020006BD
+:10F0600050600034020020210A00139A00000000C2
+:10F0700010620030020020210A00139A00000000F4
+:10F080001062003B2862000C504000022402000E77
+:10F090002402000910620056020020210A00139A7F
+:10F0A0000000000010620056286200211040000F8E
+:10F0B000240200382402001C106200582862001D3F
+:10F0C000104000062402001F2402001B1062004CA6
+:10F0D000000000000A00139A000000001062004ABD
+:10F0E000020020210A00139A00000000106200456F
+:10F0F0002862003910400007240200802462FFCB00
+:10F100002C42000210400045020020210A00139604
+:10F110000000302110620009000000000A00139A6C
+:10F12000000000001480003D020020210A0013901E
+:10F130008FBF00140A001396240600018F4201B805
+:10F140000440FFFE24020002A342018BA745018870
+:10F150009742014AA74201908F420144A74201927F
+:10F160003C021000AF4201B80A00139C8FBF00148C
+:10F170009742014A144000290000000093620005F4
+:10F180003042000414400025000000000E0013026D
+:10F190000200202193620005020020213442000475
+:10F1A0000E00130BA36200059362000530420004B9
+:10F1B00014400002000000000000000D93620000F7
+:10F1C00024030020304200FF14430014000000001C
+:10F1D0008F4201B80440FFFE24020005AF500180B9
+:10F1E000A342018B3C0210000A00139AAF4201B8FF
+:10F1F0008FBF00148FB000100A0012F227BD001854
+:10F200000000000D02002021000030218FBF0014FB
+:10F210008FB000100A0012DD27BD00180000000D9D
+:10F220008FBF00148FB0001003E0000827BD001846
+:10F2300027BDFFE8AFBF00100E000F3C000000002C
+:10F24000AF4001808FBF0010000020210A000FE7AF
+:10F2500027BD00183084FFFF30A5FFFF00001821F4
+:10F260001080000700000000308200011040000202
+:10F2700000042042006518210A0013AB0005284055
+:10F2800003E000080060102110C0000624C6FFFF44
+:10F290008CA2000024A50004AC8200000A0013B573
+:10F2A0002484000403E000080000000010A000080F
+:10F2B00024A3FFFFAC860000000000000000000057
+:10F2C0002402FFFF2463FFFF1462FFFA248400047A
+:10F2D00003E0000800000000308300FF30A500FFBD
+:10F2E00030C600FF274701808F4201B80440FFFE6F
+:10F2F000000000008F42012834634000ACE20000AF
+:10F3000024020001ACE00004A4E30008A0E2000A2B
+:10F3100024020002A0E2000B3C021000A4E5001051
+:10F32000ACE00024ACE00028A4E6001203E00008F2
+:10F33000AF4201B827BDFFE8AFBF00109362003FA6
+:10F3400024030012304200FF1043000D00803021E2
+:10F350008F620044008210230440000A8FBF001017
+:10F360008F620048240400390000282100C21023C5
+:10F3700004410004240600120E0013C9000000001E
+:10F380008FBF00102402000103E0000827BD001811
+:10F3900027BDFFC8AFB20030AFB1002CAFBF003403
+:10F3A000AFB0002890C5000D0080902130A400105F
+:10F3B0001080000B00C088218CC300088F620054AD
+:10F3C0001062000730A20005144000B524040001BB
+:10F3D0000E000D21000020210A0014BB0040202156
+:10F3E00030A200051040000930A30012108000ACCC
+:10F3F000240400018E2300088F620054146200A9C7
+:10F400008FBF00340A00142C240400382402001298
+:10F41000146200A3240400010220202127A500106B
+:10F420000E000CB2AFA000101040001102402021CD
+:10F430008E220008AF620084AF6000400E0013020D
+:10F44000000000009362007D024020213442002031
+:10F450000E00130BA362007D0E000CA902402021B8
+:10F46000240400382405008D0A0014B82406001274
+:10F470009362003E304200081040000F8FA200103F
+:10F4800030420100104000078FA300148F6200601B
+:10F490000062102304430008AF6300600A001441B7
+:10F4A00000000000AF6000609362003E2403FFF79D
+:10F4B00000431024A362003E9362003E30420008E5
+:10F4C000144000022406000300003021936200343F
+:10F4D000936300378F640084304200FF306300FF85
+:10F4E00000661821000318800043282100A4202B67
+:10F4F0001080000B000000009763003C8F620084C6
+:10F500003063FFFF004510230062182B14600004D5
+:10F51000000000008F6200840A00145D0045802313
+:10F520009762003C3050FFFF8FA300103062000450
+:10F5300010400004000628808FA2001C0A001465F9
+:10F540000202102B2E02021850400003240202185F
+:10F550000A00146E020510233063000410600003DB
+:10F56000004510238FA2001C00451023004080217D
+:10F570002C42008054400001241000800E00130231
+:10F580000240202124020001AF62000C9362003E81
+:10F59000001020403042007FA362003E8E22000413
+:10F5A00024420001AF620040A770003C8F6200500F
+:10F5B0009623000E00431021AF6200588F62005066
+:10F5C00000441021AF62005C8E220004AF6200187C
+:10F5D0008E220008AF62001C8FA20010304200088B
+:10F5E0005440000A93A20020A360003693620036C4
+:10F5F0002403FFDFA36200359362003E0043102422
+:10F60000A362003E0A0014988E220008A36200350F
+:10F610008E220008AF62004C8F6200248F6300408E
+:10F6200000431021AF6200489362000024030050A1
+:10F63000304200FF144300122403FF803C02080004
+:10F640008C4231A00242102100431024AF42002816
+:10F650003C0208008C4231A08E2400083C03000CC0
+:10F66000024210213042007F03421021004310214A
+:10F67000AC4400D88E230008AF820014AC4300DCF9
+:10F680000E00130B02402021240400380000282122
+:10F690002406000A0E0013C9000000002404000123
+:10F6A0008FBF00348FB200308FB1002C8FB0002894
+:10F6B0000080102103E0000827BD003827BDFFF8B7
+:10F6C00027420180AFA20000308A00FF8F4201B8BC
+:10F6D0000440FFFE000000008F4601283C020800A5
+:10F6E0008C4231A02403FF80AF86004800C2102165
+:10F6F00000431024AF4200243C0208008C4231A099
+:10F700008FA900008FA8000000C210213042007FA6
+:10F71000034218213C02000A00621821946400D4BC
+:10F720008FA700008FA5000024020002AF83001401
+:10F73000A0A2000B8FA30000354260003084FFFFC1
+:10F74000A4E200083C021000AD260000AD04000455
+:10F75000AC60002427BD0008AF4201B803E00008F8
+:10F76000240200018F88003C938200288F830014BC
+:10F770003C07080024E7779800481023304200FF38
+:10F78000304900FC246500888F860040304A000321
+:10F790001120000900002021248200048CA3000015
+:10F7A000304400FF0089102AACE3000024A50004C7
+:10F7B0001440FFF924E70004114000090000202153
+:10F7C0002482000190A30000304400FF008A102B27
+:10F7D000A0E3000024A500011440FFF924E7000184
+:10F7E00030C20003144000048F85003C3102000346
+:10F7F0001040000D0000000010A0000900002021B2
+:10F800002482000190C30000304400FF0085102BCB
+:10F81000A0E3000024C600011440FFF924E7000122
+:10F8200003E00008000000001100FFFD000020219F
+:10F83000248200048CC30000304400FF0088102B99
+:10F84000ACE3000024C600041440FFF924E70004E0
+:10F8500003E00008000000008F83003C9382002832
+:10F8600030C600FF30A500FF00431023304300FFE7
+:10F870008F820014008038210043102114C0000240
+:10F88000244800880083382130E20003144000053A
+:10F8900030A2000314400003306200031040000D4A
+:10F8A0000000000010A000090000202124820001B7
+:10F8B00090E30000304400FF0085102BA1030000FE
+:10F8C00024E700011440FFF92508000103E00008C7
+:10F8D0000000000010A0FFFD000020212482000491
+:10F8E0008CE30000304400FF0085102BAD030000C6
+:10F8F00024E700041440FFF92508000403E0000891
+:10F90000000000000080482130AAFFFF30C600FF41
+:10F9100030E7FFFF274801808F4201B80440FFFE17
+:10F920008F820048AD0200008F420124AD02000426
+:10F930008D220020A5070008A102000A240200165B
+:10F94000A102000B934301208D2200088D240004A6
+:10F95000306300FF004310219783003A00441021D8
+:10F960008D250024004310233C0308008C6331A044
+:10F970008F840014A502000C246300E82402FFFF1A
+:10F98000A50A000EA5030010A5060012AD0500187B
+:10F99000AD020024948201142403FFF73042FFFFDC
+:10F9A000AD0200288C820118AD02002C3C02100030
+:10F9B000AD000030AF4201B88D220020004310247A
+:10F9C00003E00008AD2200208F82001430E7FFFF23
+:10F9D00000804821904200D330A5FFFF30C600FFD1
+:10F9E0000002110030420F0000E238252748018054
+:10F9F0008F4201B80440FFFE8F820048AD02000034
+:10FA00008F420124AD0200048D220020A5070008CA
+:10FA1000A102000A24020017A102000B9343012057
+:10FA20008D2200088D240004306300FF0043102164
+:10FA30009783003A004410218F8400140043102360
+:10FA40003C0308008C6331A0A502000CA505000E44
+:10FA5000246300E8A5030010A5060012AD00001401
+:10FA60008D220024AD0200188C82005CAD02001CC7
+:10FA70008C820058AD0200202402FFFFAD0200245A
+:10FA8000948200E63042FFFFAD02002894820060BD
+:10FA9000948300BE30427FFF3063FFFF00021200FC
+:10FAA00000431021AD02002C3C021000AD000030DC
+:10FAB000AF4201B8948200BE2403FFF700A21021D8
+:10FAC000A48200BE8D2200200043102403E0000821
+:10FAD000AD220020274301808F4201B80440FFFE81
+:10FAE0008F8200249442001C3042FFFF000211C0AC
+:10FAF000AC62000024020019A062000B3C0210005E
+:10FB0000AC60003003E00008AF4201B88F87002CE2
+:10FB100030C300FF8F4201B80440FFFE8F820048CF
+:10FB200034636000ACA2000093820044A0A20005F0
+:10FB30008CE20010A4A20006A4A300088C8200207E
+:10FB40002403FFF7A0A2000A24020002A0A2000BD7
+:10FB50008CE20000ACA200108CE20004ACA2001405
+:10FB60008CE2001CACA200248CE20020ACA2002895
+:10FB70008CE2002CACA2002C8C820024ACA20018D9
+:10FB80003C021000AF4201B88C82002000431024D8
+:10FB900003E00008AC8200208F86001427BDFFE838
+:10FBA000AFBF0014AFB0001090C20063304200201D
+:10FBB0001040000830A500FF8CC2007C2403FFDF4A
+:10FBC00024420001ACC2007C90C2006300431024B8
+:10FBD000A0C2006310A000238F830014275001806F
+:10FBE000020028210E0015D6240600828F82001400
+:10FBF000904200633042004050400019A38000440E
+:10FC00008F83002C8F4201B80440FFFE8F82004892
+:10FC1000AE02000024026082A60200082402000254
+:10FC2000A202000B8C620008AE0200108C62000C75
+:10FC3000AE0200148C620014AE0200188C62001830
+:10FC4000AE0200248C620024AE0200288C620028E0
+:10FC5000AE02002C3C021000AF4201B8A380004469
+:10FC60008F8300148FBF00148FB000109062006368
+:10FC700027BD00183042007FA06200639782003ADF
+:10FC80008F86003C8F850014938300280046102344
+:10FC9000A782003AA4A000E490A400638F820040F1
+:10FCA000AF83003C2403FFBF0046102100832024C3
+:10FCB000AF820040A0A400638F820014A04000BD6A
+:10FCC0008F82001403E00008A44000BE8F8A001455
+:10FCD00027BDFFE0AFB10014AFB000108F88003C2B
+:10FCE000AFBF00189389001C954200E430D100FF9B
+:10FCF0000109182B0080802130AC00FF3047FFFF46
+:10FD00000000582114600003310600FF012030215B
+:10FD1000010958239783003A0068102B1440003CD7
+:10FD20000000000014680007240200018E02002079
+:10FD30002403FFFB34E7800000431024AE020020C0
+:10FD40002402000134E70880158200053165FFFFB9
+:10FD50000E001554020020210A00169102002021F5
+:10FD60000E001585020020218F8400482743018062
+:10FD70008F4201B80440FFFE24020018AC6400006A
+:10FD8000A062000B8F840014948200E6A46200102D
+:10FD90003C021000AC600030AF4201B894820060B9
+:10FDA00024420001A4820060948200603C030800A9
+:10FDB0008C63318830427FFF5443000F02002021C2
+:10FDC000948200602403800000431024A482006019
+:10FDD0009082006090830060304200FF000211C2F8
+:10FDE00000021027000211C03063007F0062182556
+:10FDF000A083006002002021022028218FBF00186C
+:10FE00008FB100148FB000100A0015F927BD002033
+:10FE1000914200632403FF8000431025A142006348
+:10FE20009782003A3048FFFF110000209383001CA6
+:10FE30008F840014004B1023304600FF948300E4AD
+:10FE40002402EFFF0168282B00621824A48300E439
+:10FE500014A000038E020020010058210000302170
+:10FE60002403FFFB34E7800000431024AE0200208F
+:10FE700024020001158200053165FFFF0E001554B4
+:10FE8000020020210A0016B99783003A0E0015855A
+:10FE9000020020219783003A8F82003CA780003A1D
+:10FEA00000431023AF82003C9383001C8F82001418
+:10FEB0008FBF00188FB100148FB0001027BD002035
+:10FEC00003E00008A04300BD938200442403000126
+:10FED00027BDFFE8004330042C420020AFB00010E3
+:10FEE000AFBF00142410FFFE10400005274501801D
+:10FEF0003C0208008C4231900A0016D600461024BD
+:10FF00003C0208008C423194004610241440000743
+:10FF1000240600848F8300142410FFFF9062006287
+:10FF20003042000F34420040A06200620E0015D63D
+:10FF300000000000020010218FBF00148FB00010DD
+:10FF400003E0000827BD00188F83002427BDFFE0D1
+:10FF5000AFB20018AFB10014AFB00010AFBF001CBB
+:10FF60009062000D00A0902130D100FF3042007F50
+:10FF7000A062000D8F8500148E4300180080802140
+:10FF80008CA2007C146200052402000E90A2006383
+:10FF9000344200200A0016FFA0A200630E0016C51E
+:10FFA000A38200442403FFFF104300472404FFFF03
+:10FFB00052200045000020218E4300003C0200102A
+:10FFC00000621024504000043C020008020020217E
+:10FFD0000A00170E24020015006210245040000988
+:10FFE0008E45000002002021240200140E0016C5D8
+:10FFF000A38200442403FFFF104300332404FFFFC7
+:020000021000EC
+:100000008E4500003C02000200A2102410400016A1
+:100010003C0200048F8600248CC200148CC30010A4
+:100020008CC40014004310230044102B50400005E2
+:10003000020020218E43002C8CC2001010620003AD
+:10004000020020210A00173F240200123C02000493
+:1000500000A210245040001C00002021020020219A
+:100060000A00173F2402001300A2102410400006CB
+:100070008F8300248C620010504000130000202168
+:100080000A001739020020218C6200105040000441
+:100090008E42002C020020210A00173F240200118A
+:1000A00050400009000020210200202124020017F6
+:1000B0000E0016C5A38200442403FFFF1043000274
+:1000C0002404FFFF000020218FBF001C8FB2001806
+:1000D0008FB100148FB000100080102103E00008E1
+:1000E00027BD00208F83001427BDFFD8AFB40020A8
+:1000F000AFB3001CAFB20018AFB10014AFB0001026
+:10010000AFBF0024906200638F91002C2412FFFF88
+:100110003442004092250000A06200638E2200104D
+:100120000080982130B0003F105200060360A021EB
+:100130002402000D0E0016C5A38200441052005484
+:100140002404FFFF8F8300148E2200188C63007C30
+:1001500010430007026020212402000E0E0016C585
+:10016000A38200442403FFFF104300492404FFFF3F
+:1001700024040020120400048F83001490620063A2
+:1001800034420020A06200638F85003410A000205C
+:1001900000000000560400048F8200140260202139
+:1001A0000A0017902402000A9683000A9442006015
+:1001B0003042FFFF144300048F8200202404FFFD1F
+:1001C0000A0017B7AF82003C3C0208008C42318C19
+:1001D0000045102B14400006026020210000282159
+:1001E0000E001646240600010A0017B70000202161
+:1001F0002402002D0E0016C5A38200442403FFFF35
+:10020000104300232404FFFF0A0017B70000202139
+:10021000160400058F8400148E2300142402FFFFAF
+:100220005062001802602021948200602442000184
+:10023000A4820060948200603C0308008C633188D3
+:1002400030427FFF5443000F0260202194820060FF
+:100250002403800000431024A48200609082006088
+:1002600090830060304200FF000211C2000210279C
+:10027000000211C03063007F00621825A083006077
+:10028000026020210E0015F9240500010000202144
+:100290008FBF00248FB400208FB3001C8FB20018D2
+:1002A0008FB100148FB000100080102103E000080F
+:1002B00027BD00288F83001427BDFFE8AFB00010D2
+:1002C000AFBF0014906200638F87002C00808021F4
+:1002D000344200408CE60010A06200633C0308003A
+:1002E0008C6331B030C23FFF0043102B1040004EF2
+:1002F0008F8500302402FF8090A3000D004310245E
+:10030000304200FF504000490200202100061382C5
+:10031000304800032402000255020044020020215C
+:1003200094A2001C8F85001424030023A4A20114AE
+:100330008CE60000000616023042003F1043001019
+:100340003C0300838CE300188CA2007C1062000642
+:100350002402000E0E0016C5A38200442403FFFFF2
+:10036000104300382404FFFF8F8300149062006361
+:1003700034420020A06200630A0017FC8F8300242F
+:1003800000C31024144300078F83002490A200624E
+:100390003042000F34420020A0A20062A38800383F
+:1003A0008F8300249062000D3042007FA062000D18
+:1003B0008F83003410600018020020218F840030E9
+:1003C0008C8200100043102B1040000924020018FA
+:1003D000020020210E0016C5A38200442403FFFF63
+:1003E000104300182404FFFF0A00182400002021F5
+:1003F0008C820010240500010200202100431023FC
+:100400008F830024240600010E001646AC62001003
+:100410000A001824000020210E0015F9240500010F
+:100420000A00182400002021020020212402000DCF
+:100430008FBF00148FB0001027BD00180A0016C52A
+:10044000A38200448FBF00148FB0001000801021E1
+:1004500003E0000827BD001827BDFFC8AFB2002089
+:10046000AFBF0034AFB60030AFB5002CAFB400283A
+:10047000AFB30024AFB1001CAFB000188F46012805
+:100480003C0308008C6331A02402FF80AF86004843
+:1004900000C318213065007F03452821006218241D
+:1004A0003C02000AAF43002400A2282190A200626F
+:1004B00000809021AF850014304200FF000211023D
+:1004C000A382003890A200BC304200021440000217
+:1004D00024030034240300308F820014A3830028F7
+:1004E000938300388C4200C0A3800044AF82003C5C
+:1004F000240200041062031C8F84003C8E4400041C
+:10050000508003198F84003C8E4200103083FFFF1F
+:10051000A784003A106002FFAF8200408F8400146D
+:100520002403FF809082006300621024304200FFA9
+:10053000144002CF9785003A9383003824020002CA
+:1005400030B6FFFF14620005000088219382002866
+:100550002403FFFD0A001B19AF82003C8F82003C80
+:1005600002C2102B144002A18F8400400E0014EC34
+:1005700000000000938300283C040800248477983E
+:10058000240200341462002EAF84002C3C0A0800C0
+:100590008D4A77C82402FFFFAFA2001000803821E7
+:1005A0002405002F3C09080025297398240800FF22
+:1005B0002406FFFF90E2000024A3FFFF00062202B2
+:1005C00000C21026304200FF0002108000491021B6
+:1005D0008C420000306500FF24E7000114A8FFF5FD
+:1005E0000082302600061027AFA20014AFA2001030
+:1005F0000000282127A7001027A6001400C51023FB
+:100600009044000324A2000100A71821304500FFF8
+:100610002CA200041440FFF9A06400008FA2001077
+:100620001142000724020005024020210E0016C5D9
+:10063000A38200442403FFFF104300642404FFFF4F
+:100640003C0208009042779C104000098F82001401
+:10065000024020212402000C0E0016C5A382004493
+:100660002403FFFF104300592404FFFF8F8200146E
+:10067000A380001C3C0308008C63779C8C440080A2
+:100680003C0200FF3442FFFF006218240083202B4D
+:1006900010800008AF83003402402021240200199A
+:1006A0000E0016C5A38200442403FFFF1043004739
+:1006B0002404FFFF8F87003C9782003A8F85003427
+:1006C000AF8700200047202310A0003BA784003AFA
+:1006D0008F86001430A200030002102390C300BCD8
+:1006E0003050000300B0282100031882307300014D
+:1006F0000013108000A228213C0308008C6331A065
+:100700008F8200483084FFFF0085202B004310219A
+:1007100010800011244200888F84002C1082000E6B
+:100720003C033F013C0208008C42779800431024B0
+:100730003C0325001443000630E500FF8C820000D6
+:10074000ACC200888C8200100A0018E9ACC2009884
+:100750000E001529000030219382001C8F850014A3
+:100760008F830040020238218F82003CA387001C47
+:1007700094A400E4006218218F82003434841000B5
+:10078000AF83004000503021A4A400E41260000EAA
+:10079000AF86003C24E20004A382001C94A200E483
+:1007A00024C30004AF83003C34422000A4A200E430
+:1007B0000A001906000020218F820040AF80003C13
+:1007C00000471021AF820040000020212414FFFFC9
+:1007D000109402112403FFFF3C0808008D0877A83D
+:1007E0003C0208008C4231B03C03080090637798CB
+:1007F00031043FFF0082102B1040001B3067003F88
+:100800003C0208008C4231A88F83004800042180FC
+:1008100000621821006418213062007F0342282101
+:100820003C02000C00A228213C020080344200015E
+:100830003066007800C230252402FF800062102458
+:10084000AF42002830640007AF4208048F820014D2
+:100850000344202124840940AF460814AF850024B6
+:10086000AF840030AC4301189383003824020003A6
+:10087000146201CF240200012402002610E201D1FB
+:1008800028E2002710400013240200322402002234
+:1008900010E201CC28E200231040000824020024CA
+:1008A0002402002010E201B82402002110E20147D6
+:1008B000024020210A001AFB2402000B10E201C1B1
+:1008C0002402002510E20010024020210A001AFB39
+:1008D0002402000B10E201AE28E2003310400006B3
+:1008E0002402003F2402003110E2009A024020213D
+:1008F0000A001AFB2402000B10E201A5024020218D
+:100900000A001AFB2402000B8F90002C3C03080005
+:100910008C6331B08F8500308E0400100000A82158
+:100920008CB3001430823FFF0043102B8CB10020A9
+:100930005040018F0240202190A3000D2402FF802F
+:1009400000431024304200FF504001890240202122
+:10095000000413823042000314400185024020212C
+:1009600094A3001C8F8200148E040028A443011459
+:100970008CA20010026218231064000302402021A0
+:100980000A00197C2402001F8F82003400621021AB
+:100990000262102B104000088F83002402402021A7
+:1009A000240200180E0016C5A382004410540174DE
+:1009B0002404FFFF8F8300248F8400348C62001096
+:1009C0000224882100441023AC6200108F8200149E
+:1009D000AC7100208C4200680051102B10400009BF
+:1009E0008F830030024020212402001D0E0016C516
+:1009F000A38200442403FFFF104301612404FFFF8E
+:100A00008F8300308E0200248C6300241043000783
+:100A1000024020212402001C0E0016C5A3820044BF
+:100A20002403FFFF104301562404FFFF8F8400249A
+:100A30008C82002424420001AC8200241233000482
+:100A40008F8200148C4200685622000E8E02000035
+:100A50008E0200003C030080004310241440000D6F
+:100A60002402001A024020210E0016C5A382004471
+:100A70002403FFFF104301422404FFFF0A0019BAB8
+:100A80008E0200143C0300800043102450400003F9
+:100A90008E020014AC8000208E0200142411FFFF8F
+:100AA0001051000E3C0308003C0208008C423190BB
+:100AB000004310242403001B14400007A3830044B8
+:100AC0000E0016C5024020211051012D2404FFFF05
+:100AD0000A0019CB8E030000A38000448E0300009F
+:100AE0003C02000100621024104000123C02008011
+:100AF0000062102414400008024020212402001A41
+:100B00000E0016C5A38200442403FFFF1043011CFE
+:100B10002404FFFF02402021020028210E0016E5D8
+:100B2000240600012403FFFF104301152404FFFFE6
+:100B3000241500018F83002402A0302102402021CF
+:100B40009462003624050001244200010A001ADFE5
+:100B5000A46200368F90002C3C0308008C6331B0F7
+:100B60008E13001032623FFF0043102B10400089AB
+:100B70008F8400302402FF809083000D00431024F6
+:100B8000304200FF104000842402000D0013138245
+:100B900030420003240300011443007F2402000DAF
+:100BA0009082000D30420008544000048F820034CF
+:100BB000024020210A001A102402002450400004A0
+:100BC0008E03000C024020210A001A102402002784
+:100BD0008C82002054620006024020218E0300080F
+:100BE0008C820024506200098E02001402402021F1
+:100BF000240200200E0016C5A38200441054007188
+:100C00002403FFFF0A001A458F8400242411FFFFEC
+:100C1000145100048F860014024020210A001A405B
+:100C2000240200258E0300188CC2007C1062000391
+:100C30002402000E0A001A40024020218E030024E4
+:100C40008C82002810620003240200210A001A404E
+:100C5000024020218E0500288C82002C10A2000367
+:100C60002402001F0A001A40024020218E03002C9B
+:100C700014600003240200230A001A4002402021CD
+:100C80008CC200680043102B104000032402002691
+:100C90000A001A40024020218C82001400651821AD
+:100CA0000043102B104000088F84002402402021B4
+:100CB000240200220E0016C5A382004410510041F8
+:100CC0002403FFFF8F8400242403FFF79082000D8C
+:100CD00000431024A082000D8F8600143C030800FE
+:100CE0008C6331AC8F82004894C400E08F8500246F
+:100CF0000043102130847FFF000420400044102175
+:100D00003043007F034320213C03000E0083202159
+:100D10002403FF8000431024AF42002CA493000062
+:100D20008CA2002824420001ACA200288CA2002C36
+:100D30008E03002C00431021ACA2002C8E02002C4C
+:100D4000ACA200308E020014ACA2003494A2003A8F
+:100D500024420001A4A2003A94C600E03C0208002C
+:100D60008C4231B024C4000130837FFF1462000F35
+:100D700000803021240280000082302430C2FFFF36
+:100D8000000213C2304200FF000210270A001A7E40
+:100D9000000233C02402000D024020210E0016C5BF
+:100DA000A38200440A001A84004018218F82001494
+:100DB00002402021240500010E0015F9A44600E0A0
+:100DC000000018210A001B16006088218F90002C5B
+:100DD0003C0308008C6331B08E05001030A23FFF49
+:100DE0000043102B104000612402FF808F840030EC
+:100DF0009083000D00431024304200FF5040005CFF
+:100E0000024020218F8200341040000B0005138225
+:100E10008F8200149763000A944200603042FFFF03
+:100E200014430005000513828F8200202404FFFD77
+:100E30000A001AF3AF82003C304200031440000E57
+:100E40000000000092020002104000058E03002402
+:100E500050600015920300030A001AAF02402021DF
+:100E60008C82002450620010920300030240202173
+:100E70000A001AB72402000F9082000D30420008C9
+:100E80005440000992030003024020212402001074
+:100E90000E0016C5A38200442403FFFF1043003850
+:100EA0002404FFFF92030003240200025462000C9A
+:100EB000920200038F820034544000099202000322
+:100EC000024020212402002C0E0016C5A3820044FB
+:100ED0002403FFFF1043002A2404FFFF92020003B3
+:100EE0000200282102402021384600102CC60001B3
+:100EF0002C4200010E0016E5004630252410FFFFAD
+:100F00001050001F2404FFFF8F8300341060001373
+:100F1000024020213C0208008C42318C0043102BFF
+:100F200014400007000000000000282124060001F2
+:100F30000E001646000000000A001AF300002021EF
+:100F40002402002D0E0016C5A38200441050000C90
+:100F50002404FFFF0A001AF3000020210E0015F9F7
+:100F6000240500010A001AF300002021024020217C
+:100F70002402000D0E0016C5A3820044004020216B
+:100F80000A001B16008088211514000E00000000C6
+:100F90000E00174C024020210A001B160040882139
+:100FA0000E0016C5A38200440A001B1600408821CB
+:100FB00014620017022018212402002314E2000505
+:100FC0002402000B0E0017C0024020210A001B164D
+:100FD0000040882102402021A38200440E0016C553
+:100FE0002411FFFF0A001B170220182130A500FF63
+:100FF0000E001529240600019783003A8F82003CD9
+:10100000A780003A00431023AF82003C0220182141
+:101010001220003E9782003A2402FFFD5462003EF7
+:101020008E4300208E4200048F830014005610234C
+:10103000AE420004906200633042007FA062006311
+:101040008E4200208F840014A780003A34420002B0
+:10105000AE420020A48000E4908200632403FFBF1E
+:1010600000431024A08200630A001B598E43002015
+:101070009082006300621024304200FF1040002381
+:101080009782003A90820088908300BD2485008872
+:101090003042003F2444FFE02C820020A383001C48
+:1010A00010400019AF85002C2402000100821804B2
+:1010B000306200191440000C3C02800034420002EF
+:1010C000006210241440000B306200201040000F1A
+:1010D0009782003A90A600010240202124050001D9
+:1010E0000A001B5330C60001024020210A001B5297
+:1010F00024050001024020210000282124060001CF
+:101100000E001646000000009782003A1440FD04CD
+:101110008F8400148E4300203062000410400012BF
+:101120008F84003C2402FFFB00621024AE420020AA
+:10113000274301808F4201B80440FFFE8F820048A0
+:10114000AC6200008F420124AC6200042402608380
+:10115000A462000824020002A062000B3C021000FE
+:10116000AF4201B88F84003C8F8300148FBF0034DE
+:101170008FB600308FB5002C8FB400288FB30024B9
+:101180008FB200208FB1001C8FB000182402000124
+:1011900027BD003803E00008AC6400C030A500FFA4
+:1011A0002403000124A900010069102B1040000C49
+:1011B00000004021240A000100A31023004A380443
+:1011C00024630001308200010069302B10400002CE
+:1011D000000420420107402554C0FFF800A310235B
+:1011E00003E00008010010213C020800244260A432
+:1011F0003C010800AC22738C3C02080024425308D6
+:101200003C010800AC2273902402000627BDFFE0D9
+:101210003C010800A02273943C021EDCAFB200180F
+:10122000AFB10014AFBF001CAFB0001034526F411B
+:1012300000008821240500080E001B7A02202021CE
+:10124000001180803C07080024E773980002160014
+:1012500002071821AC6200000000282124A200012E
+:101260003045FFFF8C6200002CA6000804410002FC
+:10127000000220400092202614C0FFF8AC64000059
+:10128000020780218E0400000E001B7A2405002036
+:10129000262300013071FFFF2E2301001460FFE5BB
+:1012A000AE0200008FBF001C8FB200188FB1001477
+:1012B0008FB0001003E0000827BD002027BDFFD835
+:1012C000AFB3001CAFB20018AFBF0020AFB1001425
+:1012D000AFB000108F5101408F48014800089402C0
+:1012E000324300FF311300FF8F4201B80440FFFE7C
+:1012F00027500180AE1100008F420144AE0200046D
+:1013000024020002A6120008A202000B240200140C
+:10131000AE1300241062002528620015104000085A
+:101320002402001524020010106200302402001272
+:10133000106200098FBF00200A001CB58FB3001C8B
+:101340001062007024020022106200378FBF00205C
+:101350000A001CB58FB3001C3C0208008C4231A06F
+:101360002403FF800222102100431024AF420024F6
+:101370003C0208008C4231A0022210213042007F42
+:10138000034218213C02000A00621821166000BCCA
+:10139000AF830014906200623042000F344200308C
+:1013A000A06200620A001CB48FBF00203C046000F1
+:1013B0008C832C083C02F0033442FFFF00621824A7
+:1013C000AC832C083C0208008C4231A08C832C0892
+:1013D000244200740002108200021480006218256A
+:1013E000AC832C080A001CB48FBF00203C0208000C
+:1013F0008C4231A02403FF800222102100431024DC
+:10140000AF4200243C0208008C4231A03C03000A99
+:10141000022210213042007F03421021004310219C
+:101420000A001CB3AF8200143C0208008C4231A0B9
+:101430002405FF800222102100451024AF42002421
+:101440003C0208008C4231A0022210213042007F71
+:10145000034218213C02000A0062182190620063D6
+:1014600000A21024304200FF10400085AF8300141A
+:1014700024620088944300123C0208008C4231A888
+:1014800030633FFF00031980022210210043102126
+:101490003043007F03432021004510243C03000C0F
+:1014A00000832021AF4200289082000D00A210246A
+:1014B000304200FF10400072AF8400249082000D83
+:1014C000304200101440006F8FBF00200E0015C87E
+:1014D000000000008F4201B80440FFFE0000000041
+:1014E000AE1100008F420144AE020004240200024B
+:1014F000A6120008A202000BAE1300240A001CB4BE
+:101500008FBF00202406FF8002261024AF42002057
+:101510003C0208008C4231A031043FFF00042180CE
+:101520000222102100461024AF4200243C03080090
+:101530008C6331A83C0208008C4231A03227007F26
+:101540000223182102221021006418213042007F5A
+:101550003064007F034228213C02000A0066182400
+:1015600000A22821034420213C02000C00822021FB
+:10157000AF4300283C020008034718210062902175
+:10158000AF850014AF8400240E0015C8010080212F
+:101590008F4201B80440FFFE8F8200248F84001424
+:1015A000274501809042000DACB10000A4B00006B8
+:1015B000000216000002160300021027000237C2C4
+:1015C00014C00016248200889442001232033FFFA8
+:1015D00030423FFF14430012240260829083006374
+:1015E0002402FF8000431024304200FF5040000CD2
+:1015F00024026082908200623042000F3442004038
+:10160000A082006224026084A4A200082402000DCB
+:10161000A0A200050A001C9E3C0227002402608252
+:10162000A4A20008A0A000053C02270000061C00A0
+:101630000062182524020002A0A2000BACA3001037
+:10164000ACA00014ACA00024ACA00028ACA0002CDE
+:101650008E42004C8F840024ACA200189083000DB1
+:101660002402FF8000431024304200FF1040000598
+:101670008FBF00209082000D3042007FA082000DBD
+:101680008FBF00208FB3001C8FB200188FB10014E1
+:101690008FB000103C02100027BD002803E00008B6
+:1016A000AF4201B80800343008003430080033A8D5
+:1016B000080033E0080034140800343808003438D7
+:1016C00008003438080033180A0001240000000024
+:1016D000000000000000000D747061362E322E33C1
+:1016E00000000000060203010000000000000000EE
+:1016F00000000000000000000000000000000000EA
+:1017000000000000000000000000000000000000D9
+:1017100000000000000000000000000000000000C9
+:1017200000000000000000000000000000000000B9
+:1017300000000000000000000000000000000000A9
+:101740000000000000000000000000000000000099
+:101750000000000000000000000000001000000376
+:10176000000000000000000D0000000D3C02080019
+:1017700024421C003C03080024632094AC40000079
+:101780000043202B1480FFFD244200043C1D080070
+:1017900037BD2FFC03A0F0213C1008002610049058
+:1017A0003C1C0800279C1C000E00015C000000008F
+:1017B0000000000D3084FFFF308200078F85001885
+:1017C00010400002248300073064FFF800853021B8
+:1017D00030C41FFF03441821247B4000AF85001C48
+:1017E000AF84001803E00008AF4400843084FFFF9A
+:1017F000308200078F8500208F860028104000026D
+:10180000248300073064FFF8008520210086182B10
+:1018100014600002AF8500240086202303442821A1
+:1018200034068000AF840020AF44008000A6202151
+:1018300003E00008AF84003827BDFFD8AFB3001C19
+:10184000AFB20018AFB00010AFBF0024AFB400209B
+:10185000AFB100143C0860088D1450002418FF7FBD
+:101860003C1A8000029898243672380CAD12500051
+:101870008F5100083C07601C3C08600036300001B6
+:10188000AF500008AF800018AF400080AF40008428
+:101890008CE600088D0F08083C0760168CEC0000F1
+:1018A00031EEFFF039CA00103C0DFFFF340B800011
+:1018B0003C030080034B48212D440001018D282466
+:1018C0003C0253533C010800AC230420AF8900388C
+:1018D000AF860028AF840010275B400014A20003ED
+:1018E00034E37C008CF90004032818218C7F007CF1
+:1018F0008C6500783C0280003C0B08008D6B048CEA
+:101900003C0A08008D4A048834520070AF85003CC0
+:10191000AF9F00403C13080026731C440240A021E6
+:101920008E4800008F46000038C30001306400017B
+:1019300010800017AF880034028048218D2F0000EE
+:101940003C0508008CA5045C3C1808008F1804585E
+:1019500001E8102300A280210000C8210202402BD0
+:1019600003198821022838213C010800AC30045CAE
+:101970003C010800AC2704588F4E000039CD00010F
+:1019800031AC00011580FFED01E04021AF8F003444
+:101990008E5100003C0708008CE7045C3C0D0800F9
+:1019A0008DAD04580228802300F0602100007021D2
+:1019B0000190302B01AE1821006620213C01080067
+:1019C000AC2C045C3C010800AC2404588F46010890
+:1019D0008F47010030C92000AF860000AF87000CA0
+:1019E0001120000A00C040213C1808008F18042C68
+:1019F000270800013C010800AC28042C3C184000DA
+:101A0000AF5801380A000196000000009749010410
+:101A100000002821014550213122FFFF0162582199
+:101A20000162F82B015F502130D902003C0108000F
+:101A3000AC2B048C3C010800AC2A0488172000154C
+:101A400024040F0010E400130000000024080D001F
+:101A500010E8023B30CD000611A0FFE93C18400021
+:101A6000936E00002409001031C400F01089027147
+:101A700024020070108202E58F880014250F0001F7
+:101A8000AF8F00143C184000AF5801380A0001968F
+:101A900000000000974C01041180FFD93C18400061
+:101AA00030C34000146000A1000000008F460178A0
+:101AB00004C0FFFE8F87003824100800240F0008A0
+:101AC0008CE30008AF500178A74F0140A7400142C6
+:101AD000974E01048F86000031C9FFFF30CD000111
+:101AE00011A002E1012040212531FFFE241800024F
+:101AF000A75801463228FFFFA75101483C190800AA
+:101B00008F39043C172002D08F8C000C30DF00206E
+:101B100017E00002240400092404000130C20C0074
+:101B2000240504005045000134840004A744014A00
+:101B30003C1108008E3104203C1800483C10000184
+:101B40000238182530CF00020070282511E000046B
+:101B5000000018213C19010000B9282524030001C8
+:101B600030DF000453E00005AF8300083C0600109E
+:101B700000A6282524030001AF830008AF4510000C
+:101B80000000000000000000000000000000000055
+:101B90008F83000810600023000000008F451000B4
+:101BA00004A1FFFE000000001060001E0000000005
+:101BB0008F4410003C0C0020008C102410400019B1
+:101BC0008F8E000031CD000211A000160000000031
+:101BD000974F101415E000130000000097591008EB
+:101BE0003338FFFF271100060011188200033080F0
+:101BF00000C7282132300001322300031200032CD9
+:101C00008CA200000000000D00C7F821AFE2000028
+:101C10003C0508008CA5043024A600013C01080006
+:101C2000AC2604308F6D00003402FFFFAF8D00043E
+:101C30008CEC0000118202A6000020218CED000037
+:101C400031AC01001180028A000000003C02080053
+:101C50008C4204743C0308008C63044C3C1F080055
+:101C60008FFF04703C1808008F1804480048382182
+:101C70000068802100E8282B03E430210208402B73
+:101C80000304882100C57021022878213C01080046
+:101C9000AC30044C3C010800AC2F04483C01080067
+:101CA000AC2704743C010800AC2E04708F8400182B
+:101CB0000120302131290007249F000833F91FFF3C
+:101CC00003594021AF84001CAF990018251B400028
+:101CD000AF590084112000038F83002024C2000725
+:101CE0003046FFF88F84002800C3282100A4302B41
+:101CF00014C00002AF83002400A428230345602100
+:101D0000340D8000018D10213C0F1000AF850020A4
+:101D1000AF820038AF450080AF4F01788F88001444
+:101D2000250F00010A0001EFAF8F00148F62000839
+:101D30008F670000240500300007760231C300F0F1
+:101D4000106500A7240F0040546FFF4C8F880014CB
+:101D50008F4B01780560FFFE0000000030CA0200D2
+:101D600015400003000612820000000D00061282DA
+:101D7000304D0003000D4900012D18210003808023
+:101D8000020D402100086080019380218E1F000019
+:101D900017E00002000000000000000D8F6E00043C
+:101DA00005C202BD92070006920E000592020004D1
+:101DB0003C090001000E18800070F8218FED00181A
+:101DC000277100082448000501A96021000830821D
+:101DD000AFEC0018022020210E00059E26050014FD
+:101DE000920A00068F7900043C0B7FFF000A2080D6
+:101DF000009178218DF800043566FFFF0326282422
+:101E000003053821ADE70004920E0005920D000491
+:101E1000960C0008000E10800051C8218F2300008E
+:101E2000974901043C07FFFF006758243128FFFF52
+:101E3000010DF82103EC50233144FFFF01643025EC
+:101E4000AF260000920300072418000110780275E5
+:101E5000240F0003106F0285000000008E050010A3
+:101E60002419000AA7590140A7450142921800040D
+:101E70008F860000240F0001A7580144A7400146A7
+:101E80009747010430D100023C050041A7470148B3
+:101E900000001821A74F014A1220000330CB000494
+:101EA0003C0501412403000151600005AF83000897
+:101EB0003C06001000A6282524030001AF8300087B
+:101EC000AF4510000000000000000000000000000E
+:101ED000000000008F8A000811400004000000008C
+:101EE0008F4410000481FFFE000000008F6B000093
+:101EF000920800043C1108008E310444AF8B0004AA
+:101F000097590104311800FF3C0E08008DCE0440A3
+:101F10003325FFFF0305382102276021000010212F
+:101F2000250F000A31E8FFFF0187482B01C2682115
+:101F300001A9F821311000073C010800AC2C044431
+:101F40003C010800AC3F0440120000038F8C0018D5
+:101F50002506000730C8FFF8010C682131BF1FFFBC
+:101F6000AF8C001CAF9F0018AF5F00849744010442
+:101F7000035F80213084FFFF308A00071140000397
+:101F8000261B4000248900073124FFF88F8200209F
+:101F90008F850028008220210085702B15C000024B
+:101FA000AF820024008520233C0B08008D6B048C3D
+:101FB0003C0A08008D4A04880344882134038000C9
+:101FC000022310213C0F1000AF840020AF820038A4
+:101FD000AF440080AF4F01780A0002968F8800144A
+:101FE0008F5001780600FFFE30D10200162000035A
+:101FF000000612820000000D00061282305F00030E
+:10200000001F1900007F302100062080009FC8219A
+:1020100000194880013380218E180000130000024F
+:10202000000000000000000D8F6C000C058001FB1B
+:102030008F870038240E0001AE0E00008CE30008EC
+:10204000A20000078F65000400055402314D00FF17
+:1020500025A80005000830822CCB00411560000245
+:10206000A20A00040000000D8F7800043C03FFFF6B
+:1020700000E02821330BFFFF256C000B000C1082C1
+:1020800000022080008748218D3F000026040014B4
+:10209000A618000803E3C8240E00059EAD39000011
+:1020A0008F4F01083C11100001F1382410E001AB02
+:1020B00000000000974D01049208000725AAFFECDC
+:1020C000350600023144FFFFA2060007960600080D
+:1020D0002CC7001354E0000592030007921100077B
+:1020E000362F0001A20F00079203000724180001F9
+:1020F000107801C224090003106901D58F880038C7
+:1021000030CBFFFF257100020011788331E400FF1E
+:1021100000042880A20F000500A848218D2D000092
+:10212000974A01043C0EFFFF01AEF8243143FFFF44
+:10213000006B1023244CFFFE03ECC825AD390000D2
+:10214000920600053C03FFF63462FFFF30D800FF23
+:102150000018388000F08821922F00143C04FF7F83
+:102160003487FFFF31EE000F01C65821316500FFB3
+:1021700000055080015068218DAC00200148F821F5
+:10218000A20B00060182C824AE0C000CAFF9000CB3
+:10219000920900068E11000C032778240009C080E4
+:1021A0000310702195C60026030828210227202449
+:1021B000AE04000CADCF0020ADC60024ACA60010CC
+:1021C0008F8800003C0B08008D6B048C3C0A0800D3
+:1021D0008D4A0488241F001024190002A75F0140C3
+:1021E000A7400142A7400144A7590146974901046D
+:1021F00024070001310600022538FFFEA7580148D8
+:102200003C050009A747014A10C00003000018213F
+:102210003C05010924030001310C00045180000534
+:10222000AF8300083C08001000A828252403000103
+:10223000AF830008AF451000000000000000000060
+:1022400000000000000000009205000424AE00021F
+:1022500031CD0007000D182330620007AE020010D8
+:102260008F90000812000004000000008F4F100043
+:1022700005E1FFFE000000008F7100008F8E001846
+:102280003C0308008C630444AF91000497450104AB
+:1022900025CF001031E61FFF30A2FFFFAF8E001CDC
+:1022A000AF860018AF4600842449FFFE3C0C0800AE
+:1022B0008D8C0440974D010401208021000947C303
+:1022C0000070C02131A9FFFF0310F82B0188C8213D
+:1022D000033F202103463821313100073C0108002B
+:1022E000AC3804443C010800AC2404401220000334
+:1022F00024FB40002527000730E9FFF88F860020E7
+:102300008F8400280126382100E4C02B170000022A
+:10231000AF86002400E438230347202134198000CD
+:10232000009910213C0F1000AF870020AF820038C9
+:10233000AF470080AF4F01780A0002968F880014E3
+:102340009747010410E0FDAE3C1840008F5801781B
+:102350000700FFFE30C5400010A000033C1F00082E
+:102360000000000D3C1F0008AF5F01402410080072
+:102370008F860000AF5001789744010430D90001E6
+:10238000132000ED3086FFFF24CCFFFE240D000259
+:10239000A74D0146A74C01488F9100182408000D55
+:1023A000A748014A8F630000262F000831E21FFF73
+:1023B0000342702130C90007AF830004AF91001CB5
+:1023C000AF82001800C03821AF4200841120000302
+:1023D00025DB400024D800073307FFF88F85002055
+:1023E0008F84002800E5302100C4382B14E000025F
+:1023F000AF85002400C430238F8400140346F821E5
+:10240000340C8000AF86002003EC8021AF460080B2
+:10241000249900013C0610003C184000AF460178AA
+:10242000AF900038AF990014AF5801380A000196F8
+:10243000000000008F630000975101043067FFFF28
+:102440003228FFFF8F4F017805E0FFFE30EC0007D8
+:10245000000CF82333F0000724F9FFFE2404000ADF
+:10246000A7440140A7500142A7590144A740014693
+:10247000A74801488F45010830B800201700000226
+:10248000240300092403000130CD0002A743014AC0
+:102490003C04004111A00003000018213C0401414C
+:1024A0002403000130C9000451200005AF83000857
+:1024B0003C0600100086202524030001AF8300089D
+:1024C000AF44100000000000000000000000000009
+:1024D000000000008F8E000811C000040000000002
+:1024E0008F4210000441FFFE000000008F7F0000BB
+:1024F000276400088F91003CAF9F0004948500087A
+:102500009490000A9499000C30AFFFFF0010C400B3
+:102510003323FFFF11F100A6030320253C0E080022
+:102520008DCE04443C0C08008D8C044000E88821CA
+:102530002626FFFE01C628210000682100A6F82BF0
+:10254000018D2021009F80213C010800AC2504441E
+:102550003C010800AC30044024E200083042FFFF98
+:102560003047000710E000038F830018244F000756
+:1025700031E2FFF83106FFFF30C800070043802139
+:1025800032191FFF0359C021AF83001CAF990018F7
+:10259000271B4000AF590084110000038F8C0020DE
+:1025A00024C5000730A6FFF88F84002800CC28211E
+:1025B00000A4F82B17E00002AF8C002400A428230D
+:1025C000AF850020AF4500803C0408008C840434B3
+:1025D00003454821340E8000012E6821108000053B
+:1025E000AF8D0038939100172406000E12260011BB
+:1025F0002407043F3C021000AF4201788F8800148A
+:10260000250F00010A0001EFAF8F00140E0005C472
+:1026100000E020218F8800143C0B08008D6B048C97
+:102620003C0A08008D4A0488250F00010A0001EFCA
+:10263000AF8F00143C021000A7470148AF42017859
+:102640000A0004CE8F88001424040F001184003D7A
+:1026500030CE002015C0000224030009240300012D
+:102660000A00021AA743014A0A00020DA7400146C8
+:1026700094EF000894F1000A94F0000C8F8C003C59
+:10268000001174003207FFFF31EDFFFF11AC00377E
+:1026900001C720253C1808008F1804443C0F08008F
+:1026A0008DEF0440000080210308682101A8382B29
+:1026B00001F0702101C760213C010800AC2D0444E9
+:1026C0003C010800AC2C04400A00027A8F840018F8
+:1026D0003C0208008C42047C3C0308008C630454D8
+:1026E0003C1F08008FFF04783C1808008F18045026
+:1026F000004838210068802100E8282B03E43021BD
+:102700000208402B0304882100C57021022878218B
+:102710003C010800AC3004543C010800AC2F0450CC
+:102720003C010800AC27047C3C010800AC2E047876
+:102730000A00027A8F840018A74001460A00043577
+:102740008F91001830CD002015A0FFC52403000D87
+:10275000240300050A00021AA743014A974E010408
+:1027600025C5FFF00A00038130A4FFFF8F980040C9
+:102770001498FFC8000010213C0508008CA5046CCB
+:102780003C1F08008FFF046800A8C8210328302BD5
+:1027900003E22021008640213C010800AC39046C92
+:1027A0003C010800AC2804680A00027A8F840018F3
+:1027B0008F8C0040148CFF5900E8C8213C18080099
+:1027C0008F18046C3C1108008E3104682723FFFE2B
+:1027D00003034821000010210123302B0222702125
+:1027E00001C668213C010800AC29046C3C010800CA
+:1027F000AC2D04680A0004A524E200088F88003884
+:102800003C03FFFF8D02000C0043F82403E4C825BD
+:10281000AD19000C0A00038F30CBFFFF0A0003C381
+:10282000AE000000974A0104920400048E26000CBA
+:10283000014458212579FFF200C7C0243325FFFF4A
+:1028400003053825AE27000C0A0002E68E050010AD
+:102850003C0DFFFF8D0A0010014D582401646025D6
+:10286000AD0C00100A00038F30CBFFFF974301042B
+:10287000920E00048E290010006E1021244DFFEEF0
+:102880000127602431A8FFFF0188F825AE3F001022
+:102890000A0002E68E0500108E0F000CAE0000004C
+:1028A00000078880023028210A0002B8ACAF00205F
+:1028B0001460000D3058FFFF3C04FFFF0044682403
+:1028C00001A47026000E602B000D102B004CF82484
+:1028D00013E00002000000000000000D8CAF0000BB
+:1028E0000A00025001E410253B03FFFF0003882B80
+:1028F0000018802B0211202410800002000000002C
+:102900000000000D8CB900000A0002503722FFFFC2
+:102910003084FFFF30A5FFFF108000070000182162
+:10292000308200011040000200042042006518219E
+:102930001480FFFB0005284003E000080060102120
+:1029400010C00007000000008CA2000024C6FFFF9A
+:1029500024A50004AC82000014C0FFFB2484000402
+:1029600003E000080000000010A0000824A3FFFFFF
+:10297000AC86000000000000000000002402FFFF01
+:102980002463FFFF1462FFFA2484000403E00008BC
+:1029900000000000308EFFFF30D8FFFF00057C00F4
+:1029A00001F8602539CDFFFF01AC5021014C582BB7
+:1029B000014B4821000944023127FFFF00E8302184
+:1029C0000006240230C5FFFF00A418213862FFFF73
+:1029D00003E000083042FFFF3C0C08008D8C0484AB
+:1029E000240BFF8027BDFFD001845021014B4824D8
+:1029F000AF4900203C0808008D080484AFB20020D5
+:102A0000AFB00018AFBF0028AFB30024AFB1001CB7
+:102A1000936600040104382130E4007F009A1021FD
+:102A20003C0300080043902130C500200360802152
+:102A30003C080111277B000814A000022646007004
+:102A40002646006C9213000497510104920F000473
+:102A50003267000F322EFFFF31ED004001C72823FF
+:102A600011A0000500004821925900BC3338000431
+:102A70001700009000000000924300BC307F00046B
+:102A800013E0000F0000000010A0000D0000000087
+:102A9000960E0002240AFF8000A7602125CDFFFECC
+:102AA000A74D1016920B0004014B2024308200FF2A
+:102AB00010400085010C40253C0F0400010F40250B
+:102AC0008F5301780660FFFE2404000AA7440140EA
+:102AD000960D00022404000931AC0007000C5823B5
+:102AE000316A0007A74A0142960200022443FFFE12
+:102AF000A7430144A7400146975F0104A75F01482F
+:102B00008F590108333800205300000124040001CC
+:102B1000920F000431EE001015C000023483001043
+:102B200000801821A743014A0000000000000000B7
+:102B30000000000000000000AF481000000000008E
+:102B40000000000000000000000000008F51100095
+:102B50000621FFFE3113FFFF12600003000000009A
+:102B60008F481018ACC8000096030006307FFFFFA6
+:102B700027F900020019988200138880023B302157
+:102B80008CD800001520005700183402920300046E
+:102B90002405FF8000A3F82433F100FF1220002C4D
+:102BA00000000000924700BC30F2000212400028F2
+:102BB00000000000974B100C2562FFFEA742101684
+:102BC000000000003C0A040035490030AF49100005
+:102BD00000000000000000000000000000000000F5
+:102BE0008F4C10000581FFFE000000009749100C7B
+:102BF0008F51101C00C020213127FFFF24F200302C
+:102C0000001218820003288000BBF8213226FFFF43
+:102C1000AFF100000E0005B300112C020013C880B4
+:102C2000033B98218E78000000027400AFB80010BA
+:102C30008FA80010310FFFFFAFAF00108FA400105E
+:102C400001C46825AFAD00108FA60010AE6600006D
+:102C500097730008976D000A9766000C8F8A003CF6
+:102C6000000D5C0030CCFFFF3262FFFF104A0036DF
+:102C7000016C2025960600023C10100024D30008A9
+:102C80000E00013B3264FFFF974C01040E00014926
+:102C90003184FFFFAF5001788FBF00288FB300242D
+:102CA0008FB200208FB1001C8FB0001803E0000825
+:102CB00027BD003010A0FF700000000024A5FFFC1D
+:102CC0000A0005EC240900048CD10000AF51101853
+:102CD0008F5301780660FF7A2404000A0A00060177
+:102CE0000000000000A7C8218F8800388F4E101CFC
+:102CF0000019C0820018788001E82021AC8E000005
+:102D0000000E2C0200C020210E0005B331C6FFFFCB
+:102D1000023B28218CAD000000025400004030210D
+:102D2000AFAD00108FAC0010318BFFFFAFAB0010C8
+:102D30008FA2001001424825AFA900108FA70010F4
+:102D40000A000631ACA700008F8F0040148FFFC926
+:102D50000000000097420104960B00023C050800A9
+:102D60008CA5046C3049FFFF316AFFFF3C1108005D
+:102D70008E310468012A382124F2FFFE00B240217E
+:102D80000012FFC30112C82B023FC02103192021EA
+:102D90003C010800AC28046C3C010800AC24046829
+:102DA0000A00066B0000000000A4102B1040000970
+:102DB000240300010005284000A4102B04A00003F8
+:102DC000000318405440FFFC000528401060000735
+:102DD000000000000085302B14C0000200031842E0
+:102DE000008520231460FFFB0005284203E0000853
+:102DF000008010218F85002C27BDFFE800053027BB
+:102E00002CC300012CA400020083102510400003F5
+:102E1000AFBF00102405007FAF85002C00052827D8
+:102E200030A5FFFF0E000592240426F58F830030A5
+:102E3000240402BD004030210083382B10E000093B
+:102E400024050001000420400083102B04800003AF
+:102E5000000528405440FFFC0004204010A000085A
+:102E600000C350210064402B1500000200052842D9
+:102E70000064182314A0FFFB0004204200C350216B
+:102E80008FBF0010000A4C02312200FF27BD00183E
+:102E9000AF8A002C03E00008AF8900300A00002A46
+:102EA00000000000000000000000000D7478703683
+:102EB0002E322E3300000000060203000000000046
+:102EC000000001360000EA60000000000000000081
+:102ED00000000000000000000000000000000000F2
+:102EE00000000000000000000000000000000000E2
+:102EF00000000000000000000000000000000016BC
+:102F000000000000000000000000000000000000C1
+:102F100000000000000000000000000000000000B1
+:102F200000000000000000000000000000000000A1
+:102F3000000000000000138800000000000005DC15
+:102F4000000000000000000010000003000000006E
+:102F50000000000D0000000D3C02080024423C204F
+:102F60003C03080024633DD4AC4000000043202B08
+:102F70001480FFFD244200043C1D080037BD7FFC87
+:102F800003A0F0213C100800261000A83C1C0800FB
+:102F9000279C3C200E0002BA000000000000000D3B
+:102FA0008F8300383C088000350700708CE50000F6
+:102FB000008330253C02900000C22025AF85003000
+:102FC000AF4400208F4900200520FFFE3C03800015
+:102FD000346200708C4500008F8600303C19080078
+:102FE0008F39007C3C0E08008DCE007800A620238F
+:102FF00003245821000078210164682B01CF60214F
+:10300000018D50213C010800AC2B007C3C010800E4
+:10301000AC2A007803E00008000000000A0000412C
+:10302000240400018F8400383C05800034A2000194
+:103030000082182503E00008AF43002003E00008E9
+:10304000000010213084FFFF30A5FFFF1080000733
+:1030500000001821308200011040000200042042CC
+:10306000006518211480FFFB0005284003E00008DC
+:103070000060102110C00007000000008CA20000BA
+:1030800024C6FFFF24A50004AC82000014C0FFFB8F
+:103090002484000403E000080000000010A00008E1
+:1030A00024A3FFFFAC860000000000000000000029
+:1030B0002402FFFF2463FFFF1462FFFA248400044C
+:1030C00003E0000800000000308AFFFF93A800130F
+:1030D000A74A014497490E1630C600FF3C02100073
+:1030E000A7490146AF450148A3460152A748015AE6
+:1030F000AF4701608FA400188FA30014A7440158A4
+:10310000AF43015403E00008AF42017803E0000838
+:10311000000000003C038000346200708C49000015
+:103120008F8800002484000727BDFFF83084FFF853
+:10313000AF890030974D008A31ACFFFFAFAC000083
+:103140008FAB0000016850232547FFFF30E61FFFCB
+:1031500000C4282B14A0FFF73C0C8000358B0070B6
+:103160008D6A00003C0708008CE700843C060800DC
+:103170008CC6008000081082014918230002788064
+:1031800000E370210000202101C3C82B00C4C0212E
+:1031900001FA4021031948212502400027BD0008FB
+:1031A0003C010800AC2E00843C010800AC290080E2
+:1031B00003E00008000000008F8200002486000762
+:1031C00030C5FFF800A2182130641FFF03E000089B
+:1031D000AF8400008F8700388F8A004027BDFFB87A
+:1031E0008F860044AFB60040AFBF0044AFB5003C8F
+:1031F000AFB40038AFB30034AFB20030AFB1002C81
+:10320000AFB000288F4501048D4900ACAF47008066
+:103210008CC8002000A938230000B021AF480E1050
+:103220008F440E1000004821AF440E148CC20024BD
+:10323000AF420E188F430E18AF430E1C10E001254D
+:103240002D230001936B0008116000D400000000E2
+:10325000976E001031CDFFFF00ED602B158000CF81
+:103260000000000097700010320FFFFFAF4F0E00FC
+:103270008F520000325100081220FFFD00000000B4
+:1032800097540E088F460E043285FFFF30B30001BD
+:1032900012600132000000000000000D30B8A040B4
+:1032A00024150040131500C030A9A0001120012DE5
+:1032B00000000000937F000813E0000800000000F9
+:1032C00097630010306BFFFF00CB402B1100000311
+:1032D00030AC00401180012300000000A785003CB5
+:1032E000AF8600349366000800E02821AFA70020D5
+:1032F00014C0012427B30020AF60000C9782003C6B
+:103300003047400014E00002240300162403000E9E
+:1033100024194007A363000AAF790014938A003E82
+:103320008F740014315800070018AA4002959025A8
+:10333000AF7200149784003C8F700014309100101D
+:1033400002117825AF6F0014978E003C31CD000834
+:1033500011A00147000028218F6700143C021000D3
+:103360003C0C810000E22825AF65001497460E0A48
+:103370002408000E3405FFFC30C3FFFF006C582505
+:10338000AF6B0004A3680002937F000A27E90004E2
+:10339000A369000A9786003C9363000A30CC1F00A3
+:1033A000000C598301634021251F0028A37F0009D9
+:1033B00097490E0CA769001093790009272A00028B
+:1033C000315800070018A82332B10007A371000B81
+:1033D00093740009976400108F910034978F003C1C
+:1033E000329200FF024480210205702131ED00403D
+:1033F00011A0000531C4FFFF0091282B3C12800072
+:1034000010A000140000A0210224382B14E0011B9E
+:103410008FA500208F4D0E14AF4D0E108F420E1C45
+:10342000AF420E18AF440E008F4F000031EE00087F
+:1034300011C0FFFD0000000097540E080080882195
+:1034400000009021A794003C8F500E04241400012A
+:10345000AF900034976400103095FFFF8E68000035
+:103460000111F82317E00009AE7F00008F650014FA
+:103470008F8B004434A60040AF6600148F4C0E10B2
+:10348000AD6C00208F430E18AD63002493670008D5
+:1034900014E000D2000000000E00009E2404001082
+:1034A0008F8900483C08320000402821312600FF67
+:1034B0000006FC0003E8502525390001AF990048BB
+:1034C000AC4A0000937800099370000A330400FFAF
+:1034D00000047400320F00FF01CF6825AC4D0004DA
+:1034E0008F820048064000EAACA20008ACA0000CA5
+:1034F0009783003C306B0008156000022628000608
+:1035000026280002974E0E148F450E1C8F6700046C
+:10351000936D000231C4FFFF31A200FFAFA2001083
+:103520008F6C0014AFA800180E00008BAFAC001415
+:10353000240400100E0000C7000000008E7200007E
+:1035400016400005000000008F6400142405FFBF32
+:1035500000859824AF7300148F79000C033538214F
+:10356000AF67000C9375000816A00008000000006B
+:1035700012800006000000008F7F00143C0BEFFF5C
+:103580003568FFFE03E84824AF690014A3740008FF
+:103590008FA500200A00024602202021AF470E001E
+:1035A0000A0000F5000000008F5901780720FFFE97
+:1035B000241F08008F840000AF5F0178974B008ABA
+:1035C000316AFFFF014448232528FFFF31021FFF16
+:1035D0002C4300081460FFF9000000008F8E0048A3
+:1035E0008F8D003800C048210344202125C60001EA
+:1035F000240C0F00AF86004800E9382324864000E1
+:1036000031CA00FF11AC0005240800019391003E6F
+:103610003230000700107A4035E80001000AAC00A3
+:103620003C18010002B8A025AC9440008F930048DC
+:1036300030B2003630A40008ACD3000410800097EC
+:1036400001123025974E0E0A8F8D00003C0281003A
+:1036500031CCFFFF25AB0008018240253C03100060
+:1036600031651FFF25390006241F000EAF48016099
+:1036700000C33025A75F015AAF850000A759015844
+:1036800014E0000A8F93003824120F0052720002D7
+:103690002416000134C600408F580E108F94004449
+:1036A000AE9800208F550E18AE9500248F450E144D
+:1036B000AF4501448F590E1CAF590148A34A01522E
+:1036C0003C0A1000AF460154AF4A017814E0FEDD19
+:1036D0002D2300010076A025128000178FBF004423
+:1036E0008F84003824160F0010960084000000001C
+:1036F0008F45017804A0FFFE24150F001095006E81
+:10370000000000008F470E14240202403C1F1000EE
+:10371000AF4701448F440E1CAF440148A3400152FF
+:10372000A740015AAF400160A7400158AF42015481
+:10373000AF5F01788FBF00448FB600408FB5003C6B
+:103740008FB400388FB300348FB200308FB1002CAB
+:103750008FB0002803E0000827BD004814C0FED049
+:1037600030B8A0408F420E148F84004400004821DE
+:10377000AC8200208F510E1CAC9100240A00020E76
+:103780002D2300018F910034978A003C3C12800069
+:103790000220A821315800401700FF300000A0216E
+:1037A000976900108F9200343139FFFF13320035D2
+:1037B00000002021008048211480FEA000A03821B4
+:1037C0008F420E148F840044AC8200208F510E1C57
+:1037D000AC9100240A00020E2D230001936A000917
+:1037E0009378000B315000FF330F00FF020F702160
+:1037F00025C2000A3050FFFF0E00009E020020216B
+:103800008F8600483C1F410024CD0001AF8D004849
+:10381000936C000930C600FF00064400318300FFAE
+:10382000246B0002010B4825013FC825AC5900005C
+:103830008F67000C97440E1400F22825AC45000455
+:103840008F450E1C8F670004936A00023084FFFFCF
+:10385000315800FFAFB800108F6F0014AFB10018DF
+:103860000E00008BAFAF00140A0001A60200202159
+:10387000AF6000040A00013EA36000020A00024695
+:1038800000002021000090210A0001702414000192
+:103890003C1280000A000195ACB2000C8F91000030
+:1038A00025240002A744015826300008320F1FFFCC
+:1038B0000A0001F9AF8F0000AF40014C1120002C2D
+:1038C000000000008F590E10AF5901448F430E18AD
+:1038D000240200403C1F1000AF430148A3400152A6
+:1038E000A740015AAF400160A7400158AF420154C0
+:1038F000AF5F01780A0002278FBF00441120000645
+:103900000000000097460E0830CC004015800002F1
+:10391000000000000000000D8F4D017805A0FFFEA3
+:103920000000000097530E103C120500240E2000EA
+:10393000326AFFFF0152C025AF58014C8F4F0E1461
+:103940003C021000AF4F01448F500E1CAF50014895
+:10395000A34001528F840038A740015AAF40016054
+:10396000A7400158AF4E01540A000215AF4201783A
+:103970008F490E14AF4901448F430E1C0A00028E7A
+:10398000240200403C0E20FF27BDFFE03C1A8000CF
+:103990003C0F800835CDFFFDAFBF001CAFB2001853
+:1039A000AFB10014AFB00010AF8F0040AF4D0E00AC
+:1039B0000000000000000000000000000000000007
+:1039C000000000003C0C00FF358BFFFDAF4B0E00EC
+:1039D0003C0660048CC95000240AFF7F3C11600043
+:1039E000012A40243507380CACC750008E24043817
+:1039F00024050009AF4500083083FFFF38622F71AE
+:103A00002450C0B3AF8000480E000068AF800000B3
+:103A100052000001AE20442C0E0004353C11800001
+:103A20000E000ED9363000708F8A00403C1208001C
+:103A300026523C88020088218E0800008F5F00001B
+:103A40003BF900013338000113000017AF88003044
+:103A5000022048218D2700003C0F08008DEF006CEC
+:103A60003C0C08008D8C006800E8C02301F8282178
+:103A70000000682100B8302B018D582101664021DB
+:103A80003C010800AC25006C3C010800AC28006833
+:103A90008F44000038830001306200011440FFEDC4
+:103AA00000E04021AF8700308E0C00003C0508008C
+:103AB0008CA5006C3C0408008C84006801883023CD
+:103AC00000A638210000102100E6402B00821821BA
+:103AD0000068F8213C010800AC27006C3C0108009C
+:103AE000AC3F00688F49010025590088AF99004418
+:103AF000AF890038AF4900208E070000AF87003043
+:103B00008F4D017805A0FFFE000000008E0600002A
+:103B10003C0B08008D6B00743C0408008C84007022
+:103B200000C728230165F8210000102103E5402B80
+:103B30000082382100E8C821240908003C0108005F
+:103B4000AC3F00743C010800AC390070AF4901780B
+:103B500093580108A398003E938F003E31EE000178
+:103B600015C000158F830038240E0D00106E00194B
+:103B7000240F0F00106F001D00000000915900007D
+:103B800024180050332900FF113800043C1F400066
+:103B9000AF5F01380A0002E7000000000E00090EC6
+:103BA000000000008F8A00403C1F4000AF5F0138DA
+:103BB0000A0002E700000000938D003E31AC0006D1
+:103BC000000C51000E0000CE0152D8210A00034320
+:103BD0008F8A00403C1B0800277B3D080E0000CE6A
+:103BE000000000000A0003438F8A00403C1B0800CD
+:103BF000277B3D280E0000CE000000000A00034392
+:103C00008F8A004090AA00018FAB00108CAC00108E
+:103C10003C0300FF8D680004AD6C00208CAD0014E7
+:103C200000E060213462FFFFAD6D00248CA7001816
+:103C30003C09FF000109C024AD6700288CAE001CC0
+:103C40000182C82403197825AD6F0004AD6E002CE5
+:103C50008CAD0008314A00FFAD6D001C94A9000234
+:103C60003128FFFFAD68001090A70000A56000029A
+:103C7000A1600004A167000090A30002306200FF71
+:103C80000002198210600005240500011065000E75
+:103C90000000000003E00008A16A00018CD80028A1
+:103CA000354A0080AD7800188CCF0014AD6F001439
+:103CB0008CCE0030AD6E00088CC4002CA16A0001CF
+:103CC00003E00008AD64000C8CCD001CAD6D001845
+:103CD0008CC90014AD6900148CC80024AD680008BC
+:103CE0008CC70020AD67000C8CC200148C8300646C
+:103CF0000043C82B13200007000000008CC20014F2
+:103D0000144CFFE400000000354A008003E0000886
+:103D1000A16A00018C8200640A000399000000007F
+:103D200090AA000027BDFFF88FA9001CA3AA0000DD
+:103D30008FAE00003C0FFF808FA8001835E2FFFF18
+:103D40008CCD002C01C26024AFAC0000A120000487
+:103D500000E06021A7A000028FB800008D270004BA
+:103D60000188182100A0582100C05021006D28268C
+:103D70003C06FF7F3C0F00FF2CAD000135EEFFFF3E
+:103D800034D9FFFF3C02FF0003193024000D1DC091
+:103D9000010EC82400E2C02400C370250319782551
+:103DA000AD2E0000AD2F00048D450024AFAE000005
+:103DB000AD2500088D4D00202405FFFFAD2D000C22
+:103DC000956800023107FFFFAD27001091660018CB
+:103DD00030C200FF000219C2506000018D4500345E
+:103DE000AD2500148D67000827BD0008AD27001C15
+:103DF0008C8B00CCAD2C0028AD20002CAD2B0024EA
+:103E0000AD20001803E00008AD20002027BDFFE032
+:103E1000AFB20018AFB10014AFB00010AFBF001CBC
+:103E20009098000000C088213C0D00FF330F007FF8
+:103E3000A0CF0000908E000135ACFFFF3C0AFF00D0
+:103E4000A0CE000194A6001EA22000048CAB00149A
+:103E50008E29000400A08021016C2824012A40241E
+:103E60000080902101052025A6260002AE24000432
+:103E700026050020262400080E00007624060002F5
+:103E800092470000260500282624001400071E0083
+:103E90000003160324060004044000032403FFFF6C
+:103EA000965900023323FFFF0E000076AE23001068
+:103EB000262400248FBF001C8FB200188FB100147D
+:103EC0008FB0001024050003000030210A0000809C
+:103ED00027BD002027BDFFD8AFB1001CAFB0001830
+:103EE000AFBF002090A80000240200018FB0003C6A
+:103EF0003103003F00808821106200148FAA00382F
+:103F0000240B0005506B0016AFAA001000A0202162
+:103F100000C028210E0003DC02003021922400BCE6
+:103F2000308300021060000326060030ACC00000A1
+:103F300024C600048FBF00208FB1001C8FB0001872
+:103F400000C0102103E0000827BD002801403821EF
+:103F50000E00035AAFB000100A0004200000000059
+:103F60000E0003A1AFB000140A00042000000000FE
+:103F70003C02000A034218213C04080024843D6CE2
+:103F80002405001A000030210A000080AF8300548D
+:103F90003C038000346200708C48000000A058216F
+:103FA00000C04821308A00FFAF8800308F4401787C
+:103FB0000480FFFE3C0C8000358600708CC500003C
+:103FC0003C0308008C6300743C1808008F180070D4
+:103FD00000A82023006468210000C82101A4782BD8
+:103FE0000319702101CF60213C010800AC2D007441
+:103FF0003C010800AC2C00708F480E14AF480144FF
+:10400000AF47014CA34A0152A74B01589346010800
+:1040100030C5000854A0000135291000934B090059
+:1040200024070050316A00FF11470007000000001C
+:104030008F450E1CAF450148AF4901543C091000A3
+:1040400003E00008AF490178934D010831A800084A
+:104050001100001000000000934F010831EE001025
+:1040600051C00001352900083C04080090843DD06F
+:10407000A34401508F4309A4AF4301488F4209A0D4
+:10408000AF420144AF4901543C09100003E000086D
+:10409000AF4901783C1908008F393D8C333800084E
+:1040A0005700FFF1352900080A00047300000000E2
+:1040B00024070040AF470814AF4008108F4209445E
+:1040C0008F4309508F4409548F45095C8F46094C32
+:1040D000AF820064AF830050AF84004CAF85005CBA
+:1040E00003E00008AF8600609346010930C5007FF9
+:1040F000000518C0000521400083102103E00008DE
+:10410000244200883C09080091293D9124A800021E
+:104110003C05110000093C0000E8302500C51825C9
+:1041200024820008AC83000003E00008AC80000497
+:104130009347010B8F4A002C974F09083C18000E3B
+:104140000358482131EEFFFF000E41C0AF48002C5C
+:1041500097430908952C001A008040212403000190
+:10416000318BFFFFAC8B00008D2D001C00A058216F
+:1041700000C06021AC8D00048D24002030E7004099
+:10418000AD04000891220019304400031083004858
+:104190002885000214A00062240600021086005642
+:1041A00024190003109900660000000010E0003A96
+:1041B000000000003C07080094E73D8624E200016F
+:1041C000934F0934934709219525002A31EE00FFCA
+:1041D000000E488230ED00FF978700580009360036
+:1041E000000D1C003044FFFF00C310250044C02513
+:1041F00000A778213C19400003197025000F4C00DE
+:10420000AD090004AD0E0000934D09203C030006EB
+:1042100025090014000D360000C32025AD04000858
+:104220008F59092C24E5000130A27FFFAD19000C45
+:104230008F580930A782005825020028AD180010B9
+:104240008F4F0938AD0F0014AD2B00048F4E09407D
+:10425000AD2E0008934D09373C05080090A53D9010
+:104260008F4409488F46094031A700FF00EC182110
+:10427000008678230003C7000005CC0003196025E1
+:1042800031E8FFFC01885825AD2B000CAD20001053
+:1042900003E00008AF4A002C3C0D080095AD3D86B8
+:1042A0003C0E080095CE3D800A0004C901AE1021E5
+:1042B0003C05080094A53D8A3C06080094C63D8054
+:1042C0003C18080097183D7C952E002400A6782104
+:1042D00001F86823000E240025A2FFF200821825B1
+:1042E00024190800AD03000CAD190014AD00001036
+:1042F0000A0004C4250800189526002495250028E6
+:104300000006C40000057C00370E810035ED080072
+:10431000AD0E000CAD0D00100A0004C425080014F9
+:104320001480FFA200000000952400240004140063
+:1043300034430800AD03000C0A0004C42508001033
+:104340003C03080094633D8A3C05080094A53D8029
+:104350003C06080094C63D7C953900249538002819
+:10436000006520210086782300196C000018740075
+:1043700025E2FFEE01C2202535A3810024190800A3
+:10438000AD03000CAD040010AD190018AD00001411
+:104390000A0004C42508001C03E00008240201F4FC
+:1043A00027BDFFE8AFB00010AFBF00140E000060E3
+:1043B0000080802124050040AF4508148F83005001
+:1043C0008F84004C8F85005C0070182100641023DE
+:1043D00018400004AF830050AF6300548F66005450
+:1043E000AF86004C1200000C000000008F440074E7
+:1043F000936800813409FA002D07000710E00005DA
+:1044000000891021936C0081240B01F4018B50046E
+:1044100001441021AF62000C8F4E095C01C5682376
+:1044200019A000048FBF00148F4F095CAF8F005C90
+:104430008FBF00148FB000100A00006227BD001863
+:104440008F8400648F8300508F82004CAF640044DF
+:10445000AF63005003E00008AF6200543C038000EB
+:10446000346200708C43000027BDFFF8308700FFE6
+:1044700030A900FF30C800FFAF8300308F440178BF
+:104480000480FFFE3C028000345900708F38000029
+:10449000A3A700033C0708008CE700748FAC000062
+:1044A0003C0608008CC60070030378233C0E7FFF97
+:1044B00000EFC82135CDFFFF00005021018D2824D9
+:1044C00000CA1821000847C0032F202B00A8102580
+:1044D0000064C021AFA200003C010800AC390074A8
+:1044E0003C010800AC380070934F010AA3A0000201
+:1044F0003C0E80FFA3AF00018FAC0000312B007F8A
+:1045000035CDFFFF018D4824000B5600012A4025C0
+:10451000240730002406FF803C05100027BD00085A
+:10452000AF48014CAF470154A7400158A346015280
+:1045300003E00008AF45017827BDFFE8AFBF0014D6
+:10454000AFB000108F6500743C068000309000FF13
+:1045500000A620250E000060AF6400749363000580
+:10456000346200080E000062A362000502002021F0
+:104570008FBF00148FB00010240500052406000131
+:104580000A00057027BD001827BDFFE03C0380002E
+:10459000AFB00010AFBF0018AFB1001434620070AC
+:1045A0008C470000309000FF30A800FFAF8700303C
+:1045B0008F4401780480FFFE3C18800037110070A2
+:1045C0008E2F00003C0D08008DAD00743C0A0800E1
+:1045D0008D4A007001E7702301AE282100005821A8
+:1045E00000AE302B014B4821012638213C01080048
+:1045F000AC250074000088213C010800AC27007045
+:104600001100000F000000008F6200742619FFFFE8
+:104610003208007F0002FE0233E5007F150000062D
+:10462000332200FF2407FF800207202624A3FFFF78
+:1046300000838025320200FF0040802124111008F1
+:104640000E000060000000008F49081831250004AA
+:1046500014A0FFFD3218007F001878C000187140C8
+:1046600001CF682125AC0088AF4C0818274A098083
+:104670008D4B0020AF4B01448D460024AF460148CE
+:10468000A35001500E000062A740015802201021E3
+:104690008FBF00188FB100148FB0001003E0000826
+:1046A00027BD002027BDFFE8308400FFAFBF00100A
+:1046B0000E0005BB30A500FF8F8300508FBF001098
+:1046C000344500402404FF903C02100027BD001830
+:1046D000AF43014CA3440152AF45015403E000082D
+:1046E000AF4201789343093E306200081040000D4C
+:1046F0003C0901013528080AAC8800008F47007486
+:10470000AC8700043C06080090C63D9030C5001000
+:1047100050A00006AC8000088F6A0060AC8A0008D8
+:104720002484000C03E00008008010210A00062207
+:104730002484000C27BDFFE8AFBF0014AFB0001009
+:104740009346093F00A050210005288000853823AA
+:1047500030C200FF240300063C09080095293D866D
+:1047600024E8FFD824050004104300372406000283
+:104770009750093C3C0F020400063400320EFFFF44
+:1047800001CF6825AC8D0000934C093E318B002091
+:104790001160000800000000934309363C02010349
+:1047A000345F0300307900FF033FC0252405000873
+:1047B000AC98000493430934935909210005F88209
+:1047C000306200FF0002C082332F00FF00186E002D
+:1047D000000F740001AE6025018920253C094000CE
+:1047E00000898025ACF0FFD8934309378F4F0948E3
+:1047F0008F580940306200FF004AC821033F7021F2
+:1048000001F86023000E6F0001A650253185FFFCE2
+:10481000001F58800145482501683821AD09002056
+:104820000E00006024F00028240400040E00006242
+:10483000A364003F020010218FBF00148FB000104E
+:1048400003E0000827BD00180A0006352406001200
+:1048500027BDFFD024090010AFB60028AFB5002453
+:10486000AFB40020AFB10014AFB000103C0108009D
+:10487000A0293D90AFBF002CAFB3001CAFB2001811
+:1048800097480908309400FF3C02000E3107FFFFF3
+:10489000000731C0AF46002C974409089344010B30
+:1048A00030B500FF03428021308300300000B0218A
+:1048B0001060012500008821240C00043C01080040
+:1048C000A02C3D90934B093E000B5600000A2E038E
+:1048D00004A0016000000000AF400048934F010BAE
+:1048E00031EE002011C00006000000009358093E80
+:1048F00000189E0000139603064001890000000086
+:104900009344010B30830040106000038F930050EC
+:104910008F8200502453FFFF9347093E30E6000882
+:1049200014C0000224120003000090219619002CEC
+:1049300093580934934F0937A7990058330C00FF57
+:1049400031EE00FF024E6821000D5880016C5021AD
+:10495000015140213C010800A4283D869205001821
+:1049600030A900FF010918213C010800A4233D885B
+:104970009211001816200002000000000000000D37
+:104980003C010800A4233D8A3C010800A4203D808E
+:104990003C010800A4203D7C935F010B3063FFFFC6
+:1049A00033F00040120000022464000A2464000B6B
+:1049B0003091FFFF0E00009E022020219358010B32
+:1049C0003C08080095083D8A0040202100185982C3
+:1049D000316700010E00049A01072821934C010B56
+:1049E0008F4B002C974E09083C0F000E034F4021BF
+:1049F00031CDFFFF000D51C0AF4A002C974309088D
+:104A00009505001A004038212404000130A9FFFF59
+:104A1000AC4900008D06001C00404821318A00404E
+:104A2000AC4600048D020020ACE20008910300199E
+:104A300030630003106400EC28790002172001188D
+:104A4000241000021070010C241F0003107F011EAF
+:104A500000000000114000DE000000003C090800DA
+:104A600095293D8625220001935F0934934E092143
+:104A70009504002A33F900FF0019C08231CF00FFEE
+:104A8000978E005800184600000F6C00010D80251D
+:104A90003045FFFF02051025008E50213C034000E9
+:104AA00000433025000A6400ACEC0004ACE60000D2
+:104AB000935F09203C19000624EC0014001FC60077
+:104AC00003197825ACEF00088F48092C25CD00018B
+:104AD00031A57FFFACE8000C8F500930A785005846
+:104AE00024E80028ACF000108F4409380100802130
+:104AF000ACE40014AD9300048F530940AD9300085B
+:104B0000934A09373C19080093393D908F4309486F
+:104B10008F460940314200FF0052F82100667023A1
+:104B2000001F7F000019C40001F8282531CDFFFCCB
+:104B300000AD2025AD84000CAD800010AF4B002CE3
+:104B4000934B093E317300081260000D3C060101D1
+:104B500034CC080AACEC00288F530074AD13000469
+:104B60003C0B0800916B3D903167001050E0000352
+:104B7000AD0000088F6A0060AD0A00082510000C27
+:104B800012C0003D000000009343093F24160006B8
+:104B900024060004306200FF105600C924070002FA
+:104BA0009758093C3C0F0204330DFFFF01AF40252D
+:104BB000AE0800009345093E30A400201080000894
+:104BC00000000000935309363C0B0103357F0300BE
+:104BD000327900FF033F7025AE0E00042406000862
+:104BE000934F093493480921312AFFFF31ED00FF2B
+:104BF000000D1082310300FF0002B60000032C00FC
+:104C000002C56025018A9825001220803C094000D9
+:104C10000204502302695825AD4BFFD8935F093732
+:104C20008F4F09488F58094033F900FF0332702134
+:104C30000006B08201D668210007440001F828234D
+:104C4000000D1F000068302530A2FFFC2547FFD86B
+:104C500000C260250016808002074821ACEC0020CD
+:104C6000253000280E00006024120004A372003FCB
+:104C70000E000062000000009347010B30F200407C
+:104C8000124000053C1900FF8E180000372EFFFF70
+:104C9000030E3024AE0600000E0000C702202021C3
+:104CA0003C10080092103D90321100031220000FBA
+:104CB00002A028218F89005025330001AF930050B6
+:104CC000AF7300508F6B00540173F8231BE0000298
+:104CD000026020218F640054AF6400548F4C007434
+:104CE000258401F4AF64000C02A028210280202159
+:104CF000A76000680E0005BB3C1410008F850050B3
+:104D000034550006AF45014C8F8A00488FBF002CF8
+:104D10008FB3001C25560001AF9600488FB20018D3
+:104D2000A34A01528FB60028AF5501548FB1001429
+:104D3000AF5401788FB500248FB400208FB00010DD
+:104D400003E0000827BD00309358093E00189E007C
+:104D500000139603064200362411000293440923EF
+:104D6000308300021060FEDD8F8600608F8200506D
+:104D700014C2FEDA000000000E0000600000000017
+:104D80009369003F24070016312800FF1107000C2B
+:104D9000240500083C0C0800918C3D90358B0001E7
+:104DA0003C010800A02B3D90936A003F314300FF77
+:104DB00010650065240D000A106D005E2402000CD1
+:104DC0000E000062000000000A00069000000000D3
+:104DD0003C09080095293D863C0A0800954A3D801B
+:104DE0000A0006F3012A10213C09080095293D8A92
+:104DF0003C04080094843D803C06080094C63D7C39
+:104E000095030024012410210046F8230003CC0060
+:104E100027F0FFF20330C025240F0800ACF8000C87
+:104E2000ACEF0014ACE000100A0006EE24E7001816
+:104E30003C010800A0313D90935F093E241600011B
+:104E400033F900201720FEA5241100080A0006905F
+:104E5000241100048F6E00848F4D094011A0FE9E26
+:104E6000AF8E0050240F00143C010800A02F3D908D
+:104E70000A00068F00000000950E0024950D002802
+:104E8000000E6400000D2C003589810034A6080056
+:104E9000ACE9000CACE600100A0006EE24E70014B2
+:104EA0001460FEEC000000009502002400021C00CB
+:104EB00034640800ACE4000C0A0006EE24E700109D
+:104EC0000A000741240700123C02080094423D8A70
+:104ED0003C06080094C63D803C03080094633D7C7A
+:104EE00095100024951900280046F82103E3C023FB
+:104EF00000106C0000197400270FFFEE01CF282569
+:104F000035AC8100ACEC000CACE5001024070800C7
+:104F1000AD2700182527001C0A0006EEAD2000145E
+:104F20008F7F004CAF7F00548F7900540A000699A0
+:104F3000AF790050A362003F0E0000620000000045
+:104F40000A00069000000000240200140A0008274E
+:104F5000A362003F27BDFFE8308400FFAFBF001011
+:104F60000E0005BB30A500FF9378007E9379007F8B
+:104F7000936E00809368007A332F00FF001866005C
+:104F8000000F6C0031CB00FF018D4825000B520053
+:104F90008FBF0010012A3825310600FF344470000D
+:104FA00000E628252402FF813C03100027BD0018DD
+:104FB000AF45014CAF440154A342015203E0000845
+:104FC000AF43017827BDFFD8AFB20018AFB10014CE
+:104FD000AFB00010AFBF0020AFB3001C9342010977
+:104FE000308600FF30B000FF000618C23204000215
+:104FF0003071000114800005305200FF93670005F6
+:1050000030E5000810A0000D30C80010024020213B
+:105010000E0005A702202821240400018FBF0020D4
+:105020008FB3001C8FB200188FB100148FB0001026
+:105030000080102103E0000827BD00281500003281
+:105040000000000093430109000028213062007F26
+:10505000000220C00002F94003E49821267900886C
+:10506000033B98218E7800248E6F0008130F0046B2
+:10507000000000008F640084241800020004FD82F8
+:1050800033F900031338007C0000000093660083AE
+:10509000934A0109514600043205007C10A00060CB
+:1050A000000000003205007C14A0005302402021C3
+:1050B00016200006320400018E7F00248F5901045F
+:1050C00017F9FFD600002021320400011080000AE9
+:1050D000024020218F4209408F9300641053000644
+:1050E000000000000E00066D022028218F430940B9
+:1050F000AF630044024020210E0006020220282156
+:105100000A000860240400013C0908008D2900649D
+:10511000252600013C010800AC26006416000012A0
+:10512000000000008F6D00843C0E00C001AE6024C2
+:1051300015800005024020210E00082E02202821A3
+:105140000A00086024040001240500040E00057014
+:1051500024060001024020210E00082E02202821F2
+:105160000A000860240400010E000041240400012C
+:10517000936B007D020B50250E000062A36A007D38
+:105180000A0008A38F6D00848F6600748F480104A5
+:105190008E67002400064E021507FFB63126007FF9
+:1051A000936B008326440001308A007F1146004340
+:1051B000316300FF5464FFB08F6400842645000112
+:1051C00030B1007F30A200FF122600042405000148
+:1051D000004090210A00087624110001240FFF806E
+:1051E000024F702401CF9026324200FF00409021F0
+:1051F0000A000876241100010E00066D0220282105
+:10520000321800301300FFAA321000820240202121
+:105210000E0005A7022028210A00086024040001CE
+:105220008F6E00743C0F80002405000301CF902591
+:10523000AF72007493710083240600010E000570A4
+:10524000322400FF0E00004124040001936D007D14
+:10525000020D60250E000062A36C007D3C0B08006F
+:105260008D6B0054257000013C010800AC300054E7
+:105270000A000860240400018F6800743C09800063
+:105280002405000401093825AF6700749363008387
+:10529000240600010E000570306400FF0E0000417E
+:1052A000240400019362007D020298250E00006232
+:1052B000A373007D0A00086024040001324D0080C1
+:1052C00039AC0080546CFF6C8F6400840A0008C9FC
+:1052D0002645000127BDFFC83C0A0008AFBF0030CB
+:1052E000AFB5002CAFB40028AFB30024AFB200209C
+:1052F000AFB1001CAFB00018034AD8212409004008
+:10530000AF490814AF4008108F4209448F43095039
+:105310008F4609548F47095C8F48094C9344010814
+:105320009345010BAF820064308400FF30A500FF7D
+:10533000AF830050AF86004CAF87005C0E00084A78
+:10534000AF8800601440017D8FBF0030A760006807
+:10535000934D0900240B00503C15080026B53D482C
+:1053600031AC00FF3C12080026523D58118B00035F
+:10537000000000000000A8210000902193510109C5
+:105380008F9F005024040010322E007F000E68C052
+:10539000000E6140018D282124B40088AF54081804
+:1053A0008F4901048F4A09A43C0B000E034BC02116
+:1053B000012A10233C010800AC223D6C8F430958A0
+:1053C0003C010800A0243D9097470908007F302346
+:1053D0003C010800AC263D7030E8FFFF0008C9C062
+:1053E0003C010800AC3F3D94AF59002C974209089E
+:1053F0009710002C8EB10000930F001803749821B1
+:10540000A7900058AF9300440220F80931F000FF44
+:10541000304E000215C001B2304F000111E0014FC3
+:10542000000000009343093E3066000814C00002EB
+:10543000241400030000A0218F5809A424130001A4
+:105440003C010800AC383D98934F0934935109371B
+:1054500031EC00FF322E00FF028E6821000D288003
+:1054600000AC5021015058213C010800A42B3D887C
+:105470003C010800A42A3D8693490934312200FFEB
+:1054800002022021249000103C010800A4303D8439
+:10549000240700068F9F00503C010800AC273D8C7C
+:1054A0008F88005C8F59095800008021011F282334
+:1054B00004A00149033F20230480014700A4302BAE
+:1054C00010C00149000000003C010800AC253D70FF
+:1054D0008E4200000040F809000000003043000246
+:1054E000146000F80040882130440001548000100E
+:1054F0008E4200043C0908008D293D743C0AC0001E
+:10550000012A8025AF500E008F45000030AB000807
+:105510001160FFFD00000000974D0E0824100001EF
+:10552000A78D003C8F4C0E04AF8C00348E420004DB
+:105530000040F8090000000002228825322E0002F7
+:1055400015C00180000000003C09080095293D7C41
+:105550003C06080094C63D883C0A0800954A3D7EFA
+:105560003C1908008F393D74012660213C18080061
+:105570008F183D983C03080094633D92018A2021D6
+:105580008F4E09400329F821248F000203E32821CC
+:10559000031968213C010800A42C3D8AAF8E0064E9
+:1055A0003C010800AC2D3D983C010800A4253D803D
+:1055B0000E00009E31E4FFFF8F870048004020214D
+:1055C0003C010800A0273D918E42000824E800011C
+:1055D000AF8800480040F809000000009344010B28
+:1055E0008F4C002C974A09083C0B000E034B4021BE
+:1055F0003149FFFF000919C08F8B0050AF43002CC9
+:10560000974309089506001A00403821308A004067
+:1056100030DFFFFFAC5F00008D19001C0040482107
+:10562000AC5900048D180020AC580008910F0019E7
+:1056300031E30003107300F0000000002862000254
+:105640001440010924050002106500FD240D00032B
+:10565000106D010D00000000114000D90000000095
+:105660003C0A0800954A3D8625420001934D0934C5
+:1056700093580921950E002A31A300FF00032082D0
+:10568000331F00FF9798005800047E00001FCC00D5
+:1056900001F940253049FFFF0109102501D83021CB
+:1056A0003C0540000045502500066C00ACED0004B0
+:1056B000ACEA0000934309203C04000624ED0014EA
+:1056C0000003FE0003E4C825ACF900088F49092C4B
+:1056D000270F000131EE7FFFACE9000C8F48093045
+:1056E000A78E005824E90028ACE800108F4509383F
+:1056F00001204021ACE50014ADAB00048F4209400D
+:10570000ADA20008934B09373C1F080093FF3D9062
+:105710008F4309488F4A0940316600FF00D4202199
+:10572000006A78230004C700001FCC000319282555
+:1057300031EEFFFC00AE1025ADA2000CADA00010B4
+:10574000AF4C002C934C093E318B00085160000F88
+:105750008E58000C3C06010134CA080AACEA002845
+:105760008F4B0074AD2B00043C0C0800918C3D90D5
+:105770003187001050E00003AD2000088F62006008
+:10578000AD2200082528000C8E58000C0300F809F3
+:10579000010020213C19080097393D8A3C1F080070
+:1057A00097FF3D7E033F782125E900020E0000C7E8
+:1057B0003124FFFF3C0E08008DCE3D6C3C080800F4
+:1057C0008D083D7401C828233C010800AC253D6CC0
+:1057D00014A00006000000003C0308008C633D8C10
+:1057E000346400403C010800AC243D8C1200007081
+:1057F0008F8C00448F470E108F900044AE0700201E
+:105800008F4D0E18AE0D00243C10080096103D8000
+:105810000E0000600000000024020040AF420814A7
+:105820008F8600508F8A004C00D01821006A5823C0
+:1058300019600004AF830050AF6300548F650054BB
+:10584000AF85004C1200000C000000008F44007473
+:10585000936800813409FA002D0E000711C000057D
+:1058600000891821937F0081241901F403F9780439
+:1058700001E41821AF63000C8F44095C8F83005C46
+:105880000083C0231B000003000000008F50095C50
+:10589000AF90005C0E000062000000008F8C005092
+:1058A0008E4700103C010800AC2C3D9400E0F80944
+:1058B000000000003C0D08008DAD3D6C55A0FEF5CC
+:1058C000240700068F450024975909088F8B006430
+:1058D0008F9400503C0F001F978200588F86005411
+:1058E0008F93004C3328FFFF35E9FF8000A9502437
+:1058F000000871C032320100AF4E0024A4C2002C57
+:10590000AF4A0024AF6B0044AF740050AF73005433
+:105910001640008032380010570000868EA4000424
+:10592000322300405460001B8EB100088EB0000C82
+:105930000200F809000000008FBF00308FB5002C76
+:105940008FB400288FB300248FB200208FB1001CC9
+:105950008FB0001803E0000827BD00389347010905
+:105960008F8800380007FE0003E8C825AF59008083
+:105970008F5809A08F5309A4AFB80010AF580E1468
+:105980008FB40010AF540E10AF530E1C0A00096202
+:10599000AF530E180220F809000000008EB0000C72
+:1059A0000200F809000000000A000AA88FBF0030BA
+:1059B000A5800020A59300220A000A5BAD93002475
+:1059C0003C09080095293D863C06080094C63D80A8
+:1059D0000A0009F4012610213C010800AC203D70AA
+:1059E0000A00098E8E4200003C010800AC243D7084
+:1059F0000A00098E8E4200003C03080094633D8A31
+:105A00003C04080094843D803C1F080097FF3D7CC7
+:105A1000951800240064C821033F782300186C0007
+:105A200025EEFFF201AE2825AC45000C240208004B
+:105A3000ACE20014ACE000100A0009EF24E7001803
+:105A400095060024950900280006240000091C0082
+:105A5000349F810034790800ACFF000CACF90010D1
+:105A60000A0009EF24E700141460FEFB00000000A8
+:105A70009518002400187C0035EE0800ACEE000CF0
+:105A80000A0009EF24E700103C07080094E73D8076
+:105A90003C04080094843D8A3C03080094633D7CE8
+:105AA00095190024951800280087F82103E378232E
+:105AB0002407080000192C0000186C0025EEFFEEEA
+:105AC00001AE302534A28100AD2700182527001C27
+:105AD000AD22000CAD2600100A0009EFAD20001425
+:105AE00093520109000028210E000602324400FFF3
+:105AF0008FBF00308FB5002C8FB400288FB30024E7
+:105B00008FB200208FB1001C8FB0001803E0000896
+:105B100027BD0038935F010933E400FF0E00066DD6
+:105B200000002821323800105300FF7E322300404D
+:105B30008EA400040080F809000000000A000AA2F8
+:105B4000322300401200FF5F000000008F540E144B
+:105B50008F920044AE5400208F530E1C0A000A8A14
+:105B6000AE5300248F82001C008040213C040100C1
+:105B70009047008530E3002010600009000000001D
+:105B80003C0708008CE73D948F83001800E3202336
+:105B9000048000089389000414E30003010020211D
+:105BA00003E00008008010213C04010003E000082D
+:105BB000008010211120000B006738238F8C0020FB
+:105BC00024090034918B00BC316A0002514000016D
+:105BD0002409003000E9682B15A0FFF10100202105
+:105BE00000E938232419FFFC00B9C02400F9782407
+:105BF00000F8702B15C0FFEA01E8202130C2000335
+:105C00000002182314C00012306900030000302184
+:105C100000A9702101C6682100ED602B1180FFE012
+:105C20003C0401002D2F00010006482B01053821FE
+:105C300001E9302414C0FFDA24E4FFFC2419FFFC3E
+:105C400000B9C0240308202103E0000800801021CF
+:105C50008F8B002024060004916A00BC31440004AC
+:105C60001480FFEC00A970210A000B5E00003021B7
+:105C700027BDFFE8AFBF00108F460100934A01091E
+:105C80003C1F08008FFF00902407FF80314F00FF6A
+:105C900031E8007F0008614003E6C821032CC021E1
+:105CA00027090120012770243C010800A02F3DD0C6
+:105CB000AF4E080C3C0D08008DAD00903C040080F8
+:105CC0003482000301A65821016C182124650120AB
+:105CD00030AA007801424025AF48081C3C1F08004C
+:105CE0008FFF00908F88004003E6C0213319000722
+:105CF00003074824033A7821AF49002825E909C061
+:105D0000952E00023C0D08008DAD008C3C0A080069
+:105D10008D4A009031CC3FFF01A61821000C59801C
+:105D2000006B282100A72024AF44002C95220002FC
+:105D30003C1F08008FFF008C9107008530593FFF02
+:105D400003E678210019C1800146702101F868211D
+:105D500031CC007F31AB007F019A2821017A50219C
+:105D60003C03000C3C04000E00A328210144102138
+:105D700030E6002027470980AF82002CAF88001C46
+:105D8000AF890024AF85002010C00006AF8700282F
+:105D90008D0200508CA4010C0044302318C0007701
+:105DA00000000000910C0085240DFFDF018D3824D8
+:105DB000A10700858F8B001C8F8900248F87002806
+:105DC0008D65004CAF850018912F000D31EE00203D
+:105DD00011C000170000000024090001A38900047D
+:105DE000AF80000C8CE400248F85000C240A00088E
+:105DF000AF800008AF8000103C010800A42A3D7E5F
+:105E00003C010800A4203D920E000B32000030211E
+:105E10008F8500248FBF0010AF82001490A8000D62
+:105E200027BD00180008394203E0000830E20001F5
+:105E3000913F00022418000133F900FF001921826C
+:105E400010980039240800021088005B8F86002C0F
+:105E50008CE5002414A0001B8F9F002091220000DD
+:105E6000240A00053046003F10CA00472404000100
+:105E70008F860008A3840004AF860010AF86000C54
+:105E80008CE400248F85000C240A00083C010800E3
+:105E9000A42A3D7E3C010800A4203D920E000B3256
+:105EA000000000008F8500248FBF0010AF82001417
+:105EB00090A8000D27BD00180008394203E0000833
+:105EC00030E200018CF800088CF900248FEE00C449
+:105ED000A38000048CE40024AF8E000C8F85000C9E
+:105EE0008F86000803197823240A0008AF8F00105A
+:105EF0003C010800A42A3D7E3C010800A4203D92FC
+:105F00000E000B32000000008F8500248FBF0010B0
+:105F1000AF82001490A8000D27BD00180008394278
+:105F200003E0000830E20001912300003062003FEE
+:105F3000104400278F8500208CE400241480002169
+:105F4000000000008D2E00183C187FFF8F85002078
+:105F5000370FFFFF01CF1824AF8300088F9F000881
+:105F60008CA8008403E8C82B1720000203E020213E
+:105F70008CA400840A000BEDAF8400088CA3010CF4
+:105F80000A000BCBAF8300188D2C00188F860008F9
+:105F90003C0D7FFF8F89002035A3FFFF018358242C
+:105FA00024040001AF8B0010AD2000CCA3840004BA
+:105FB0000A000BF9AF86000C8CCA00140A000BED26
+:105FC000AF8A00088CA300C80A000C30AF83000819
+:105FD0008F84002C8CAC00648C8D0014018D582BA8
+:105FE00011600004000000008CA200640A000C3064
+:105FF000AF8200088C8200140A000C30AF820008C7
+:106000008F85000C27BDFFE0AFBF0018AFB10014B3
+:1060100014A00007AFB000108F86002424020005F2
+:1060200090C400003083003F106200B68F840020CF
+:106030008F91000800A080218F8C00283C0508006B
+:106040008CA53D708D8B000431663FFF00C5502B41
+:106050005540000100C02821938D000411A0007359
+:1060600000B0F82B8F98002024040034930F00BC5C
+:1060700031EE000251C000012404003000A4C82BFE
+:10608000172000D10000000000A4282300B0F82B46
+:106090003C010800A4243D7C17E000680200202198
+:1060A0003C0308008C633D6C0083102B54400001BE
+:1060B000008018218F8800243C010800AC233D7427
+:1060C000000048219104000D308300205060000141
+:1060D0008F490E188F8300140123382B10E00059CC
+:1060E000000000003C0408008C843D7400895821A5
+:1060F000006B502B114000560090602B006930233C
+:1061000000C020213C010800AC263D7412000003B1
+:10611000241FFFFC1090008A32270003009FC82430
+:106120003C010800AC393D743C010800A4203D92BC
+:106130008F84000C120400078F830020AF910008A9
+:10614000020020218C7100CCAF90000C26300001A1
+:10615000AC7000CC3C0208008C423D748F8A001069
+:10616000240700180082202301422823AF84000C5A
+:1061700010800002AF850010240700108F86001CDD
+:106180003C010800A0273D902407004090CC0085EA
+:10619000318B00C0116700408F8D001414A00015D2
+:1061A00000002021934A01098F420974314500FF04
+:1061B0000002260224A300013090007F3071007F8E
+:1061C0001230007A2407FF80A0C300833C09080036
+:1061D0008D293D8C8F880024240D0002352C000869
+:1061E0003C010800A02D3DD13C010800AC2C3D8CA9
+:1061F00024040010910E000D31C6002010C00005CF
+:1062000000801821240800013C010800AC283D74DE
+:10621000348300018FBF00188FB100148FB00010BD
+:106220000060102103E0000827BD00203C010800A9
+:10623000A4203D7C13E0FF9A020020210A000C817B
+:1062400000A020213C0408008C843D740090602B49
+:106250001180FFAE000000003C0F080095EF3D7C70
+:1062600001E4702101C6682B11A000072C820004F4
+:106270003C1F60008FF954043338003F1700FFE5DE
+:10628000240300422C8200041040FFA0240300429B
+:106290000A000CDF8FBF0018152DFFC000000000A2
+:1062A0008CDF00743C0380002405FF8003E3C825D5
+:1062B000ACD9007490D80085240E0004240400108A
+:1062C000330F003F01E54025A0C800858F880024DA
+:1062D0003C010800A02E3DD1240300019106000DD1
+:1062E00030C9002015200003000000003C03080016
+:1062F0008C633D743C010800AC233D6C0A000CD655
+:10630000000000008F8700108C88008400E8282B94
+:1063100014A0000200E088218C910084240900016F
+:10632000A38900048F440E18022028210E000B328E
+:1063300002203021022080210A000C67AF82001465
+:1063400000071823306600033C010800A4263D9294
+:10635000122000058F8C0020918B00BC316A000454
+:106360001540001524CD00043C0F080095EF3D9228
+:1063700001E4702100AE302B50C0FF6E8F84000C02
+:106380002C85000514A0FFA32403004230980003CD
+:1063900017000002009818232483FFFC3C0108002A
+:1063A000AC233D740A000CA30000000000A7582491
+:1063B0000A000CCB016718263C010800A42D3D9271
+:1063C0000A000D33000000003C010800AC203D74C1
+:1063D0000A000CDE240300428F83001014600007C3
+:1063E000000010218F88002424050005910600007C
+:1063F00030C400FF108500030000000003E0000827
+:1064000000000000910A0018314900FF000939C25C
+:1064100014E0FFFA8F85001C3C04080094843D7C46
+:106420003C0308008C633D943C1908008F393D748F
+:106430003C0F080095EF3D920064C0218CAD0054E4
+:106440000319702101CF6021018D58231960001DAF
+:1064500000000000910E001C8F8C002C974B0E103A
+:1064600031CD00FF8D850004016D30238D88000043
+:1064700030CEFFFF000E510000AAC82100003821D5
+:1064800001072021032A182B0083C021AD990004A5
+:10649000AD980000918F000A01CF6821A18D000AFC
+:1064A0008F88002C974B0E12A50B0008950A003818
+:1064B00025490001A50900389107000D34E60008C0
+:1064C000A106000D03E000080000000027BDFFE06A
+:1064D000938700048F8F00248FAD00143C0E7FFF44
+:1064E0008F89000C35C8FFFFAFBF001CAFB000188C
+:1064F00001A8182491EA000D000717C03C1FBFFF38
+:10650000006258252D2E00018F90001837F9FFFFEB
+:106510003C1808008F183D943C0F080095EF3D8A09
+:1065200001796824000E47803C07EFFF3C05F0FF2F
+:1065300001A818253149002034E2FFFF34ACFFFFE9
+:106540000310582327A500102406000225EA0002A4
+:1065500000621824008080211520000200004021E4
+:106560008F480E1CA7AA0012056000372407000000
+:1065700030FF00FF001FCF008F8B001C00793825F3
+:10658000AFA70014916F00853C08080091083D9169
+:106590003C18DFFF31EE00C0370AFFFF000E182B5A
+:1065A0003C1F080097FF3D8400EA6824A3A800115F
+:1065B0000003174001A248258FB90010AFA90014AD
+:1065C0003C0A0800914A3D93A7BF00168FA800140B
+:1065D000032CC0243C0B01003C0F0FFF030B1825BC
+:1065E0003147000335EEFFFF010C68240007160059
+:1065F000006EF8243C09700001A2C82503E9582563
+:10660000AFB90014AFAB00100E000076A3A00015C8
+:106610008F8C0024260200089186000D30C40020D3
+:10662000108000068FBF001C3C05080094A53D802B
+:1066300024B0FFFF3C010800A4303D808FB000185B
+:1066400003E0000827BD00208F9800140118502B8C
+:106650005540FFC7240700010A000DB630FF00FFB8
+:106660009382000427BDFFE0AFBF00181040000F69
+:10667000008050218F880024240B00058F8900089A
+:10668000910700008F8400200100282130E3003FA3
+:106690008F86002C106B000800003821AFA9001075
+:1066A0000E00040EAFAA0014A38000048FBF0018D0
+:1066B00003E0000827BD00208D1900183C0F0800DA
+:1066C0008DEF3D748F9800103C027FFF8D08001401
+:1066D000345FFFFF033F682401F8702101AE60239F
+:1066E00001883821AFA900100E00040EAFAA0014D3
+:1066F0000A000E04A38000048F8700243C050800D4
+:1067000094A53D923C0208008C423D8C90E6000D21
+:106710000005240030C300201060002C00444025F8
+:106720008F85001C00006021240B000190A30085D0
+:1067300000004821240A00013C0F800035EE007063
+:106740008DC70000AF8700308F5801780700FFFE2B
+:106750003C038000347900708F3800003C0508004D
+:106760008CA500743C0D08008DAD007003077823E4
+:1067700000AF38210000102100EF302B01A22021B2
+:10678000008618213C010800AC2700743C01080079
+:10679000AC230070AF4B01483C1908008F393D9481
+:1067A000A7490144A74A0146AF59014C3C0B0800D8
+:1067B000916B3D91A34B0152AF4801543C0810002E
+:1067C000A74C015803E00008AF4801788F4B0E1C1E
+:1067D0003C0A08008D4A3D7497490E16974D0E14D9
+:1067E00001456021312AFFFF0A000E2731A9FFFF72
+:1067F0008F8300249064000D308200201040002917
+:10680000000000000000482100005021000040214D
+:106810003C07800034EB00708D670000AF870030CC
+:106820008F4C01780580FFFE3C0D800035AC007078
+:106830008D8B00003C0508008CA500743C0408000A
+:106840008C8400700167302300A67821000010219D
+:1068500001E6C82B0082C021031970213C01080009
+:10686000AC2F00743C010800AC2E0070AF49014809
+:106870003C0D08008DAD3D94A7480144240900401B
+:10688000A74A01463C081000240AFF91AF4D014C75
+:10689000A34A0152AF490154A740015803E0000840
+:1068A000AF4801788F490E1897460E1297450E1083
+:1068B00030CAFFFF0A000E5D30A8FFFF8F8300245F
+:1068C00027BDFFF89064000D308200201040003A90
+:1068D00000000000240B000100004821240A0001F0
+:1068E0003C088000350700708CE30000AF83003067
+:1068F0008F4C01780580FFFE3C0E80003C040800B0
+:1069000090843DD035C700708CEC00003C05080039
+:106910008CA50074A3A400033C1908008F390070F3
+:106920008FAD00000183302300A638210000102124
+:106930000322782100E6C02B01F8602101AE40253A
+:10694000AFA800003C010800AC2700743C0108001F
+:10695000AC2C00709346010A3C04080090843DD1A1
+:10696000A3A00002A3A600018FA300003C0580FFA6
+:106970003099007F34A2FFFF006278240019C6001E
+:1069800001F87025240D3000AF4E014C27BD0008E2
+:10699000AF4D0154A7400158AF4B0148A7490144EE
+:1069A000A74A01463C091000240AFF80A34A01526D
+:1069B00003E00008AF4901788F4B0E1897460E127E
+:1069C00097450E1030CAFFFF0A000E9130A9FFFF55
+:1069D0008F85001C2402008090A40085308300C0B5
+:1069E000106200058F8600208F8800088F87000CBA
+:1069F000ACC800C8ACC700C403E000080000000039
+:106A00003C0A0800254A39543C09080025293A2047
+:106A10003C08080025082DD43C07080024E73B3437
+:106A20003C06080024C637C43C05080024A5353CB4
+:106A30003C040800248431643C0308002463385C6F
+:106A40003C020800244236303C010800AC2A3D508C
+:106A50003C010800AC293D4C3C010800AC283D48F5
+:106A60003C010800AC273D543C010800AC263D64C5
+:106A70003C010800AC253D5C3C010800AC243D58BD
+:106A80003C010800AC233D683C010800AC223D609D
+:086A900003E000080000000013
+:00000001FF
--- linux-4.4.0.orig/firmware/bnx2/bnx2-mips-09-6.2.1b.fw.ihex
+++ linux-4.4.0/firmware/bnx2/bnx2-mips-09-6.2.1b.fw.ihex
@@ -0,0 +1,6496 @@
+:10000000080001180800000000005594000000C816
+:1000100000000000000000000000000008005594EF
+:10002000000000380000565C080000A00800000036
+:100030000000574400005694080059200000008436
+:100040000000ADD808005744000001C00000AE5CBD
+:100050000800321008000000000092580000B01C98
+:10006000000000000000000000000000080092589E
+:100070000000033C000142740800049008000400E2
+:10008000000012FC000145B000000000000000006C
+:1000900000000000080016FC00000004000158AC3D
+:1000A000080000A80800000000003D00000158B052
+:1000B00000000000000000000000000008003D00FB
+:1000C00000000030000195B00A000046000000006A
+:1000D000000000000000000D636F6D362E322E31DF
+:1000E00062000000060201020000000000000003A0
+:1000F000000000C800000032000000030000000003
+:1001000000000000000000000000000000000000EF
+:1001100000000010000001360000EA600000000549
+:1001200000000000000000000000000000000008C7
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000020000000000000000000000008D
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000010000000005F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E0000000000010000003000000000000000DEF
+:1001F0000000000D3C020800244256083C030800A1
+:1002000024635754AC4000000043202B1480FFFDB2
+:10021000244200043C1D080037BD9FFC03A0F021D0
+:100220003C100800261001183C1C0800279C5608AA
+:100230000E000256000000000000000D27BDFFB4B4
+:10024000AFA10000AFA20004AFA30008AFA4000C50
+:10025000AFA50010AFA60014AFA70018AFA8001CF0
+:10026000AFA90020AFAA0024AFAB0028AFAC002C90
+:10027000AFAD0030AFAE0034AFAF0038AFB8003C28
+:10028000AFB90040AFBC0044AFBF00480E001544FA
+:10029000000000008FBF00488FBC00448FB90040B1
+:1002A0008FB8003C8FAF00388FAE00348FAD003078
+:1002B0008FAC002C8FAB00288FAA00248FA90020C0
+:1002C0008FA8001C8FA700188FA600148FA5001000
+:1002D0008FA4000C8FA300088FA200048FA1000040
+:1002E00027BD004C3C1B60108F7A5030377B502864
+:1002F00003400008AF7A00008F82002427BDFFE092
+:10030000AFB00010AFBF0018AFB100148C42000CAA
+:100310003C1080008E110100104000348FBF001887
+:100320000E000D84000000008F85002024047FFF54
+:100330000091202BACB100008E030104960201084D
+:1003400000031C003042FFFF00621825ACA300042C
+:100350009202010A96030114304200FF3063FFFF4E
+:100360000002140000431025ACA200089603010C03
+:100370009602010E00031C003042FFFF00621825A8
+:10038000ACA3000C960301109602011200031C009E
+:100390003042FFFF00621825ACA300108E02011846
+:1003A000ACA200148E02011CACA20018148000083C
+:1003B0008F820024978200003C0420050044182509
+:1003C00024420001ACA3001C0A0000C6A782000062
+:1003D0003C0340189442001E00431025ACA2001CB0
+:1003E0000E000DB8240400018FBF00188FB1001457
+:1003F0008FB000100000102103E0000827BD00208E
+:100400003C0780008CE202B834E50100044100089A
+:10041000240300013C0208008C42006024420001D9
+:100420003C010800AC22006003E0000800601021DD
+:100430003C0208008C42005C8CA4002094A30016AF
+:100440008CA6000494A5000E24420001ACE40280B6
+:100450002463FFFC3C010800AC22005C3C0210005D
+:10046000A4E30284A4E5028600001821ACE6028819
+:10047000ACE202B803E000080060102127BDFFE0F5
+:100480003C028000AFB0001034420100AFBF001C3E
+:10049000AFB20018AFB100148C43000094450008BF
+:1004A0002462FE002C42038110400003000381C23D
+:1004B0000A00010226100004240201001462000553
+:1004C0003C1180003C02800890420004305000FF44
+:1004D0003C11800036320100964300143202000FB6
+:1004E00000021500004310253C0308008C63004403
+:1004F00030A40004AE220080246300013C01080007
+:10050000AC2300441080000730A200028FBF001C03
+:100510008FB200188FB100148FB000100A0000CE07
+:1005200027BD00201040002D0000182130A20080BF
+:1005300010400005362200708E44001C0E000C672F
+:10054000240500A0362200708C4400008F82000C2D
+:10055000008210232C43012C10600004AF82001095
+:10056000240300010A000145AF84000C8E42000400
+:100570003C036020AF84000CAC6200143C02080015
+:100580008C42005850400015000018218C62000475
+:10059000240301FE304203FF144300100000182121
+:1005A0002E020004104000032E0200080A00014041
+:1005B0000000802114400003000000000A000140F8
+:1005C0002610FFF90000000D2402000202021004B0
+:1005D0003C036000AC626914000018218FBF001C4E
+:1005E0008FB200188FB100148FB00010006010217E
+:1005F00003E0000827BD00203C0480008C8301003C
+:1006000024020100506200033C0280080000000D3B
+:100610003C02800890430004000010213063000F6A
+:1006200000031D0003E00008AC8300800004188074
+:100630002782FF9C00621821000410C00044102390
+:100640008C640000000210C03C030800246356E4E0
+:10065000004310213C038000AC64009003E00008DC
+:10066000AF8200243C0208008C42011410400019A3
+:100670003084400030A2007F000231C03C02020002
+:100680001080001400A218253C026020AC43001426
+:100690003C0408008C8456B83C0308008C630110AD
+:1006A0003C02800024050900AC4500200086202182
+:1006B000246300013C028008AC4400643C01080053
+:1006C000AC2301103C010800AC2456B803E000083C
+:1006D000000000003C02602003E00008AC4500146C
+:1006E00003E000080000102103E0000800001021D2
+:1006F00030A2000810400008240201003C0208005B
+:100700008C42010C244200013C010800AC22010C87
+:1007100003E0000800000000148200080000000050
+:100720003C0208008C4200FC244200013C0108000D
+:10073000AC2200FC0A0001A330A200203C02080009
+:100740008C420084244200013C010800AC22008459
+:1007500030A200201040000830A200103C02080027
+:100760008C420108244200013C010800AC2201082F
+:1007700003E0000800000000104000080000000036
+:100780003C0208008C420104244200013C010800A4
+:10079000AC22010403E00008000000003C02080055
+:1007A0008C420100244200013C010800AC220100FF
+:1007B00003E000080000000027BDFFE0AFB1001417
+:1007C0003C118000AFB20018AFBF001CAFB00010EA
+:1007D0003632010096500008320200041040000733
+:1007E000320300028FBF001C8FB200188FB10014BB
+:1007F0008FB000100A0000CE27BD00201060000B53
+:10080000020028218E2401000E00018A0000000051
+:100810003202008010400003240500A10E000C6786
+:100820008E44001C0A0001E3240200018E2301040F
+:100830008F82000810430006020028218E24010048
+:100840000E00018A000000008E220104AF82000821
+:10085000000010218FBF001C8FB200188FB1001450
+:100860008FB0001003E0000827BD00202C82000498
+:1008700014400002000018212483FFFD240200021E
+:10088000006210043C03600003E00008AC626914DD
+:1008900027BDFFE0AFBF001CAFB20018AFB100141E
+:1008A000AFB000103C048000948201083043700017
+:1008B000240220001062000A2862200154400052E5
+:1008C0008FBF001C24024000106200482402600018
+:1008D0001062004A8FBF001C0A0002518FB200183C
+:1008E00034820100904300098C5000189451000C90
+:1008F000240200091062001C0000902128620009F7
+:10090000144000218F8200242402000A5062001249
+:10091000323100FF2402000B1062000F00000000C3
+:100920002402000C146200188F8200243C0208008C
+:100930008C4256B824030900AC83002000501021DB
+:100940003C038008AC6200643C010800AC2256B84D
+:100950000A0002508FBF001C0E0001E900102602A1
+:100960000A0002308F8200240E0001E900102602E6
+:100970003C0380089462001A8C72000C3042FFFF26
+:10098000020280258F8200248C42000C5040001E01
+:100990008FBF001C0E000D84000000003C02800090
+:1009A00034420100944300088F82002400031C009D
+:1009B0009444001E8F82002000641825AC50000073
+:1009C00024040001AC510004AC520008AC40000CFF
+:1009D000AC400010AC400014AC4000180E000DB844
+:1009E000AC43001C0A0002508FBF001C0E000440E4
+:1009F000000000000A0002508FBF001C0E000C9F78
+:100A0000000000008FBF001C8FB200188FB10014CF
+:100A10008FB000100000102103E0000827BD002067
+:100A200027BDFFD8AFB400203C036010AFBF002447
+:100A3000AFB3001CAFB20018AFB10014AFB00010DC
+:100A40008C6450002402FF7F3C1408002694563822
+:100A5000008220243484380CAC6450003C028000B6
+:100A6000240300370E0014B0AC4300083C07080014
+:100A700024E70618028010212404001D2484FFFFAF
+:100A8000AC4700000481FFFD244200043C02080042
+:100A9000244207C83C010800AC2256403C02080032
+:100AA000244202303C030800246306203C04080072
+:100AB000248403B43C05080024A506F03C06080085
+:100AC00024C62C9C3C010800AC2256803C02080045
+:100AD000244205303C010800AC2756843C01080044
+:100AE000AC2656943C010800AC23569C3C010800FF
+:100AF000AC2456A03C010800AC2556A43C010800DB
+:100B0000AC2256A83C010800AC23563C3C0108002E
+:100B1000AC2456443C010800AC2056603C0108005F
+:100B2000AC2556643C010800AC2056703C0108001E
+:100B3000AC27567C3C010800AC2656903C010800CE
+:100B4000AC2356980E00056E00000000AF80000C2C
+:100B50003C0280008C5300008F8300043C0208009C
+:100B60008C420020106200213262000700008821C0
+:100B70002792FF9C3C100800261056E43C02080017
+:100B80008C42002024050001022518040043202483
+:100B90008F820004004310245044000C26310001D1
+:100BA00010800008AF9000248E4300003C028000BB
+:100BB000AC4300900E000D4BAE05000C0A0002C1C4
+:100BC00026310001AE00000C263100012E22000269
+:100BD000261000381440FFE9265200043C020800A9
+:100BE0008C420020AF820004326200071040FFD91F
+:100BF0003C028000326200011040002D326200028F
+:100C00003C0580008CA2010000002021ACA2002045
+:100C10008CA301042C42078110400008ACA300A85B
+:100C200094A2010824032000304270001443000302
+:100C30003C02800890420005304400FF0E0001593C
+:100C4000000000003C0280009042010B304300FF96
+:100C50002C62001E54400004000310800E00018628
+:100C60000A0002EC00000000005410218C42000039
+:100C70000040F80900000000104000043C02800021
+:100C80008C4301043C026020AC4300143C02080089
+:100C90008C4200343C0440003C03800024420001AC
+:100CA000AC6401383C010800AC220034326200021E
+:100CB00010400010326200043C1080008E0201409F
+:100CC000000020210E000159AE0200200E00038317
+:100CD000000000003C024000AE0201783C02080027
+:100CE0008C420038244200013C010800AC2200384C
+:100CF000326200041040FF973C0280003C108000EC
+:100D00008E020180000020210E000159AE02002059
+:100D10008E03018024020F00546200073C02800809
+:100D20008E0201883C0300E03042FFFF00431025A3
+:100D30000A000328AE020080344200809042000086
+:100D400024030050304200FF14430007000000005D
+:100D50000E000362000000001440000300000000C9
+:100D60000E000971000000003C0208008C42003CAB
+:100D70003C0440003C03800024420001AC6401B804
+:100D80003C010800AC22003C0A0002A33C028000A7
+:100D90003C02900034420001008220253C02800089
+:100DA000AC4400203C0380008C6200200440FFFE25
+:100DB0000000000003E00008000000003C0280008A
+:100DC000344300010083202503E00008AC440020E8
+:100DD00027BDFFE0AFB10014AFB000100080882144
+:100DE000AFBF00180E00033230B000FF8F83FF94B6
+:100DF000022020219062002502028025A07000259B
+:100E00008C7000183C0280000E00033D020280241A
+:100E10001600000B8FBF00183C0480008C8201F884
+:100E20000440FFFE348201C024030002AC510000E4
+:100E3000A04300043C021000AC8201F88FBF0018F0
+:100E40008FB100148FB0001003E0000827BD002010
+:100E500027BDFFE83C028000AFBF00103442018094
+:100E6000944300048C4400083063020010600005C5
+:100E7000000028210E00100C000000000A0003787A
+:100E8000240500013C02FF000480000700821824B2
+:100E90003C02040014620004240500018F82FF94C8
+:100EA00090420008240500018FBF001000A010210F
+:100EB00003E0000827BD00188F82FF982405000179
+:100EC000A040001A3C028000344201400A00034264
+:100ED0008C4400008F85FF9427BDFFE0AFBF001C4E
+:100EE000AFB20018AFB10014AFB0001090A2000074
+:100EF000304400FF38830020388200300003182B74
+:100F00000002102B0062182410600003240200501D
+:100F1000148200A88FBF001C90A20005304200017F
+:100F2000104000A48FBF001C3C02800034420140EE
+:100F3000904200082443FFFF2C6200051040009EF1
+:100F40008FB20018000310803C030800246355ACE6
+:100F5000004310218C420000004000080000000007
+:100F60003C028000345101400E0003328E24000008
+:100F70008F92FF948E2200048E50000C1602000205
+:100F800024020001AE42000C0E00033D8E2400003E
+:100F90008E220004145000068FBF001C8FB2001870
+:100FA0008FB100148FB000100A000F7827BD002009
+:100FB0008E42000C0A000419000000003C0480006E
+:100FC0003482014094A300108C4200043063FFFF80
+:100FD0001443001C0000000024020001A4A2001021
+:100FE0008C8202380441000F3C0380003C02003F29
+:100FF0003448F0003C0760003C06FFC08CE22BBC8C
+:1010000000461824004810240002130200031D8229
+:10101000106200583C0280008C8202380440FFF7C6
+:101020003C038000346201408C44000034620200C2
+:10103000AC4400003C021000AC6202380A00043BE1
+:101040008FBF001C94A200100A00041900000000C9
+:10105000240200201482000F3C0280003C03800028
+:1010600094A20012346301408C6300043042FFFFFD
+:10107000146200050000000024020001A4A2001276
+:101080000A0004028FBF001C94A200120A00041977
+:1010900000000000345101400E0003328E24000095
+:1010A0008F92FF948E230004964200123050FFFF6F
+:1010B0001603000224020001A64200120E00033DA6
+:1010C0008E2400008E220004160200068FBF001C32
+:1010D0008FB200188FB100148FB000100A00037C8B
+:1010E00027BD0020964200120A00041900000000EB
+:1010F0003C03800094A20014346301408C6300041C
+:101100003042FFFF14620008240200018FBF001C60
+:101110008FB200188FB100148FB00010A4A2001479
+:101120000A00146327BD002094A20014144000217B
+:101130008FBF001C0A000435000000003C03800043
+:1011400094A20016346301408C6300043042FFFF18
+:101150001462000D240200018FBF001C8FB2001822
+:101160008FB100148FB00010A4A200160A000B1457
+:1011700027BD00209442007824420004A4A200105D
+:101180000A00043B8FBF001C94A200162403000138
+:101190003042FFFF144300078FBF001C3C020800D1
+:1011A0008C420070244200013C010800AC22007017
+:1011B0008FBF001C8FB200188FB100148FB00010C9
+:1011C00003E0000827BD002027BDFFD8AFB20018FC
+:1011D0008F92FF94AFB10014AFBF0020AFB3001CDB
+:1011E000AFB000103C028000345101008C5001006F
+:1011F0009242000092230009304400FF2402001FA5
+:10120000106200AB28620020104000192402003850
+:101210002862000A1040000D2402000B286200081A
+:101220001040002E8F820024046001042862000216
+:101230001440002A8F820024240200061062002637
+:101240008FBF00200A00055F8FB3001C1062006092
+:101250002862000B144000FA8FBF00202402000E09
+:10126000106200788F8200240A00055F8FB3001C93
+:10127000106200D2286200391040000A2402008067
+:1012800024020036106200E528620037104000C3D7
+:1012900024020035106200D98FBF00200A00055FCC
+:1012A0008FB3001C1062002D2862008110400006E0
+:1012B000240200C824020039106200C98FBF002038
+:1012C0000A00055F8FB3001C106200A28FBF0020D0
+:1012D0000A00055F8FB3001C8F8200248C42000C33
+:1012E000104000D78FBF00200E000D8400000000CA
+:1012F0003C038000346301008C6200008F85002075
+:10130000946700089466000CACA200008C64000492
+:101310008F82002400063400ACA400049448001E10
+:101320008C62001800073C0000E83825ACA20008D9
+:101330008C62001C24040001ACA2000C9062000A24
+:1013400000C23025ACA60010ACA00014ACA0001860
+:10135000ACA7001C0A00051D8FBF00208F8200244F
+:101360008C42000C104000B68FBF00200E000D8490
+:10137000000000008F820024962400089625000CAF
+:101380009443001E000422029626000E8F82002045
+:10139000000426000083202500052C003C0300806B
+:1013A00000A6282500832025AC400000AC400004A6
+:1013B000AC400008AC40000CAC450010AC40001440
+:1013C000AC400018AC44001C0A00051C24040001B9
+:1013D0009622000C14400018000000009242000504
+:1013E0003042001014400014000000000E000332D0
+:1013F0000200202192420005020020213442001008
+:101400000E00033DA242000592420000240300208A
+:10141000304200FF10430089020020218FBF0020CE
+:101420008FB3001C8FB200188FB100148FB0001062
+:101430000A00107527BD00280000000D0A00055E97
+:101440008FBF00208C42000C1040007D8FBF002019
+:101450000E000D84000000008E2200048F84002006
+:101460009623000CAC8200003C0280089445002CBE
+:101470008F82002400031C0030A5FFFF9446001E4D
+:101480003C02400E0065182500C23025AC830004E4
+:10149000AC800008AC80000CAC800010AC80001464
+:1014A000AC800018AC86001C0A00051C2404000156
+:1014B0000E000332020020218F93FF9802002021AA
+:1014C0000E00033DA660000C020020210E00034226
+:1014D000240500018F8200248C42000C104000582B
+:1014E0008FBF00200E000D84000000009622000C2B
+:1014F0008F83002000021400AC700000AC62000476
+:10150000AC6000088E4400388F820024AC64000C6C
+:101510008E46003C9445001E3C02401FAC66001005
+:1015200000A228258E62000424040001AC6200148D
+:10153000AC600018AC65001C8FBF00208FB3001C8E
+:101540008FB200188FB100148FB000100A000DB8D0
+:1015500027BD0028240200201082003A8FB3001C0F
+:101560000E000F5E00000000104000358FBF00200D
+:101570003C0480008C8201F80440FFFE348201C0EC
+:1015800024030002AC500000A04300043C02100001
+:10159000AC8201F80A00055E8FBF00200200202106
+:1015A0008FBF00208FB3001C8FB200188FB10014C2
+:1015B0008FB000100A000EA727BD00289625000C4A
+:1015C000020020218FBF00208FB3001C8FB20018B3
+:1015D0008FB100148FB000100A000ECC27BD002878
+:1015E000020020218FB3001C8FB200188FB10014AD
+:1015F0008FB000100A000EF727BD00289225000DBD
+:10160000020020218FB3001C8FB200188FB100148C
+:101610008FB000100A000F4827BD002802002021CB
+:101620008FBF00208FB3001C8FB200188FB1001441
+:101630008FB000100A000F1F27BD00288FBF0020A9
+:101640008FB3001C8FB200188FB100148FB0001040
+:1016500003E0000827BD00283C0580008CA202782A
+:101660000440FFFE34A2024024030002AC44000008
+:10167000A04300043C02100003E00008ACA2027882
+:10168000A380001803E00008A38000193C03800039
+:101690008C6202780440FFFE8F82001CAC62024024
+:1016A00024020002A06202443C02100003E0000891
+:1016B000AC6202783C02600003E000088C425404F3
+:1016C0009083003024020005008040213063003FF9
+:1016D0000000482114620005000050219082004C57
+:1016E0009483004E304900FF306AFFFFAD00000CCC
+:1016F000AD000010AD000024950200148D05001C03
+:101700008D0400183042FFFF004910230002110031
+:10171000000237C3004038210086202300A2102B8E
+:101720000082202300A72823AD05001CAD0400186B
+:10173000A5090014A5090020A50A001603E0000869
+:10174000A50A002203E000080000000027BDFFD822
+:10175000AFB200183C128008AFB40020AFB3001C39
+:10176000AFB10014AFBF0024AFB00010365101007C
+:101770003C0260008C4254049222000C3C1408008D
+:10178000929400F7304300FF2402000110620032FF
+:101790000080982124020002146200353650008037
+:1017A0000E00143D000000009202004C2403FF8054
+:1017B0003C0480003042007F000211C024420240FD
+:1017C0000262102100431824AC8300949245000863
+:1017D0009204004C3042007F3C03800614850007D1
+:1017E000004380212402FFFFA22200112402FFFFF8
+:1017F000A62200120A0005D22402FFFF9602002052
+:10180000A222001196020022A62200128E020024BB
+:101810003C048008AE2200143485008090A2004C65
+:1018200034830100A06200108CA2003CAC6200185E
+:101830008C820068AC6200F48C820064AC6200F0C0
+:101840008C82006CAC6200F824020001A0A2006847
+:101850000A0005EE3C0480080E001456000000004B
+:1018600036420080A04000680A0005EE3C04800873
+:10187000A2000068A20000690A0006293C02800854
+:10188000348300808C62003834850100AC62006CC7
+:1018900024020001A062006990A200D59083000894
+:1018A000305100FF3072007F12320019001111C058
+:1018B00024420240026210212403FF8000431824C6
+:1018C0003C048000AC8300943042007F3C038006DF
+:1018D000004380218E02000C1040000D02002021E8
+:1018E0000E00057E0000000026220001305100FF9E
+:1018F0009203003C023410260002102B0002102339
+:101900003063007F022288240A0005F8A203003C0D
+:101910003C088008350401008C8200E03507008017
+:10192000ACE2003C8C8200E0AD02000090E5004C8F
+:10193000908600D590E3004C908400D52402FF806F
+:1019400000A228243063007F308400FF00A62825F1
+:101950000064182A1060000230A500FF38A500803E
+:10196000A0E5004CA10500093C0280089043000E50
+:10197000344400803C058000A043000A8C8300189A
+:101980003C027FFF3442FFFF00621824AC83001842
+:101990008CA201F80440FFFE00000000ACB301C0BF
+:1019A0008FBF00248FB400208FB3001C8FB20018AB
+:1019B0008FB100148FB0001024020002A0A201C455
+:1019C00027BD00283C02100003E00008ACA201F88B
+:1019D00090A2000024420001A0A200003C030800E5
+:1019E0008C6300F4304200FF144300020080302179
+:1019F000A0A0000090A200008F84001C000211C073
+:101A00002442024024830040008220212402FF80DF
+:101A1000008220243063007F3C02800A006218218B
+:101A20003C028000AC44002403E00008ACC300008A
+:101A300094820006908300058C85000C8C86001033
+:101A40008C8700188C88001C8C8400203C010800C6
+:101A5000A42256C63C010800A02356C53C0108003C
+:101A6000AC2556CC3C010800AC2656D03C01080001
+:101A7000AC2756D83C010800AC2856DC3C010800D5
+:101A8000AC2456E003E00008000000003C0280089F
+:101A9000344201008C4400343C038000346504006F
+:101AA000AC6400388C420038AF850028AC62003C42
+:101AB0003C020005AC6200300000000000000000A5
+:101AC00003E00008000000003C020006308400FF34
+:101AD000008220253C028000AC4400300000000061
+:101AE00000000000000000003C0380008C62000049
+:101AF000304200101040FFFD3462040003E0000893
+:101B0000AF82002894C200003C080800950800CA73
+:101B100030E7FFFF0080482101021021A4C200002D
+:101B200094C200003042FFFF00E2102B544000013D
+:101B3000A4C7000094A200003C0308008C6300CC02
+:101B400024420001A4A2000094A200003042FFFF42
+:101B5000144300073C0280080107102BA4A00000DA
+:101B60005440000101003821A4C700003C02800855
+:101B7000344601008CC3002894A200003C0480007D
+:101B80003042FFFE000210C000621021AC82003C17
+:101B90008C82003C006218231860000400000000E2
+:101BA0008CC200240A0006BA244200018CC2002420
+:101BB000AC8200383C020050344200103C038000EC
+:101BC000AC620030000000000000000000000000D7
+:101BD0008C620000304200201040FFFD0000000039
+:101BE00094A200003C04800030420001000210C0BA
+:101BF000004410218C430400AD2300008C420404F7
+:101C0000AD2200043C02002003E00008AC8200305A
+:101C100027BDFFE0AFB20018AFB10014AFB00010A5
+:101C2000AFBF001C94C2000000C080213C1208001D
+:101C3000965200C624420001A6020000960300004E
+:101C400094E2000000E03021144300058FB1003021
+:101C50000E00068F024038210A0006F10000000045
+:101C60008C8300048C82000424420040046100073D
+:101C7000AC8200048C8200040440000400000000D8
+:101C80008C82000024420001AC8200009602000019
+:101C90003042FFFF50520001A600000096220000D3
+:101CA00024420001A62200003C02800834420100C8
+:101CB000962300009442003C144300048FBF001C94
+:101CC00024020001A62200008FBF001C8FB2001862
+:101CD0008FB100148FB0001003E0000827BD002072
+:101CE00027BDFFE03C028008AFBF0018344201006E
+:101CF0008C4800343C03800034690400AC68003830
+:101D00008C42003830E700FFAF890028AC62003C0D
+:101D10003C020005AC620030000000000000000042
+:101D200000000000000000000000000000000000B3
+:101D30008C82000C8C82000C97830016AD22000070
+:101D40008C82001000604021AD2200048C820018BB
+:101D5000AD2200088C82001CAD22000C8CA2001465
+:101D6000AD2200108C820020AD220014908200056C
+:101D7000304200FF00021200AD2200188CA20018B1
+:101D8000AD22001C8CA2000CAD2200208CA2001001
+:101D9000AD2200248CA2001CAD2200288CA20020C1
+:101DA000AD22002C3402FFFFAD260030AD20003400
+:101DB000506200013408FFFFAD28003850E00011E8
+:101DC0003C0280083C048008348401009482005066
+:101DD0003042FFFFAD22003C9483004494850044D0
+:101DE000240200013063FFFF000318C200641821C1
+:101DF0009064006430A5000700A210040A00075C8C
+:101E00000044102534420100AD20003C94430044BE
+:101E1000944400443063FFFF000318C2006218219D
+:101E200030840007906500642402000100821004E1
+:101E30000002102700451024A0620064000000008A
+:101E400000000000000000003C0200063442004098
+:101E50003C038000AC620030000000000000000085
+:101E6000000000008C620000304200101040FFFDB6
+:101E70003C06800834C201503463040034C7014A70
+:101E800034C4013434C5014034C60144AFA200104B
+:101E90000E0006D2AF8300288FBF001803E00008B1
+:101EA00027BD00208F8300143C0608008CC600E884
+:101EB0008F82001C30633FFF000319800046102111
+:101EC000004310212403FF80004318243C068000B7
+:101ED000ACC300283042007F3C03800C004330211B
+:101EE00090C2000D30A500FF0000382134420010E0
+:101EF000A0C2000D8F8900143C028008344201000A
+:101F00009443004400091382304800032402000176
+:101F1000A4C3000E1102000B2902000210400005AC
+:101F2000240200021100000C240300010A0007A48F
+:101F30000000182111020006000000000A0007A49A
+:101F4000000018218CC2002C0A0007A424430001C1
+:101F50008CC20014244300018CC200180043102BD3
+:101F60005040000A240700012402002714A20003A5
+:101F70003C0380080A0007B1240700013463010014
+:101F80009462004C24420001A462004C00091382B8
+:101F9000304300032C620002104000090080282119
+:101FA000146000040000000094C200340A0007C15D
+:101FB0003046FFFF8CC600380A0007C10080282188
+:101FC000000030213C040800248456C00A000706A3
+:101FD0000000000027BDFF90AFB60068AFB50064F9
+:101FE000AFB40060AFB3005CAFB20058AFB1005403
+:101FF000AFBF006CAFB000508C9000000080B021EB
+:102000003C0208008C4200E8960400328F83001CDA
+:102010002414FF8030843FFF0062182100042180D7
+:1020200000641821007410243C13800000A090214B
+:1020300090A50000AE620028920400323C02800CA1
+:102040003063007F00628821308400C02402004099
+:10205000148200320000A8218E3500388E2200182C
+:102060001440000224020001AE2200189202003C3B
+:10207000304200201440000E8F83001C000511C068
+:102080002442024000621821306400783C02008043
+:102090000082202500741824AE630800AE64081086
+:1020A0008E2200188E03000800431021AE22001873
+:1020B0008E22002C8E230018244200010062182B6F
+:1020C0001060004300000000924200002442000122
+:1020D000A24200003C0308008C6300F4304200FF81
+:1020E00050430001A2400000924200008F84001C77
+:1020F000000211C024420240248300403063007F6C
+:10210000008220213C02800A0094202400621821D1
+:10211000AE6400240A0008D2AEC30000920300326D
+:102120002402FFC000431024304200FF1440000589
+:1021300024020001AE220018962200340A00084250
+:102140003055FFFF8E22001424420001AE220018F9
+:102150009202003000021600000216030441001C27
+:10216000000000009602003227A400100080282101
+:10217000A7A20016960200320000302124070001B9
+:102180003042FFFFAF8200140E000706AFA0001C14
+:10219000960200328F83001C3C0408008C8400E807
+:1021A00030423FFF000211800064182100621821B4
+:1021B00000741024AE62002C3063007F3C02800E5D
+:1021C000006218219062000D3042007FA062000D75
+:1021D0009222000D304200105040007892420000E0
+:1021E0003C028008344401009482004C8EC30000FD
+:1021F0003C130800967300C62442FFFFA482004CE3
+:10220000946200329623000E3054FFFF3070FFFFBF
+:102210003C0308008C6300D000701807A7A30038A7
+:102220009482003E3063FFFF3042FFFF14620007DC
+:10223000000000008C8200303C038000244200300B
+:10224000AC62003C0A00086A8C82002C9482004038
+:102250003042FFFF5462000927A400408C820038FE
+:102260003C03800024420030AC62003C8C8200348D
+:10227000AC6200380A0008793C03800027A50038CA
+:1022800027A60048026038210E00068FA7A000484C
+:102290008FA300403C02800024630030AC43003830
+:1022A0008FA30044AC43003C3C0380003C0200058B
+:1022B000AC6200303C028008344401009482004249
+:1022C000346304003042FFFF0202102B1440000769
+:1022D000AF8300289482004E9483004202021021B2
+:1022E000004310230A00088F3043FFFF9483004E01
+:1022F00094820042026318210050102300621823C8
+:102300003063FFFF3C028008344401009482003CAB
+:102310003042FFFF14430003000000000A00089F42
+:10232000240300019482003C3042FFFF0062102B26
+:10233000144000058F8200289482003C0062102324
+:102340003043FFFF8F820028AC550000AC400004F2
+:10235000AC540008AC43000C3C02000634420010B0
+:102360003C038000AC620030000000000000000070
+:10237000000000008C620000304200101040FFFDA1
+:102380003C04800834840100001018C20064182145
+:102390009065006432020007240600010046100424
+:1023A00000451025A0620064948300429622000E2E
+:1023B00050430001A386001892420000244200010D
+:1023C000A24200003C0308008C6300F4304200FF8E
+:1023D00050430001A2400000924200008F84001C84
+:1023E000000211C0244202402483004000822021C8
+:1023F0002402FF80008220243063007F3C02800A98
+:10240000006218213C028000AC440024AEC30000EE
+:102410008FBF006C8FB600688FB500648FB400600A
+:102420008FB3005C8FB200588FB100548FB0005052
+:1024300003E0000827BD007027BDFFD8AFB3001C24
+:10244000AFB20018AFB10014AFB00010AFBF0020A2
+:102450000080982100E0802130B1FFFF0E000D8444
+:1024600030D200FF0000000000000000000000006B
+:102470008F8200208F830024AC510000AC520004F6
+:10248000AC530008AC40000CAC400010AC40001451
+:10249000AC4000189463001E02038025AC50001C61
+:1024A0000000000000000000000000002404000103
+:1024B0008FBF00208FB3001C8FB200188FB10014A3
+:1024C0008FB000100A000DB827BD002830A5FFFF0F
+:1024D0000A0008DC30C600FF3C02800834430100DB
+:1024E0009462000E3C080800950800C63046FFFFC5
+:1024F00014C000043402FFFF946500EA0A000929B1
+:102500008F84001C10C20027000000009462004E5F
+:102510009464003C3045FFFF00A6102300A6182B52
+:102520003087FFFF106000043044FFFF00C5102318
+:1025300000E210233044FFFF0088102B1040000EF3
+:1025400000E810233C028008344401002403000109
+:1025500034420080A44300162402FFFFA482000E30
+:10256000948500EA8F84001C0000302130A5FFFF15
+:102570000A0009013C0760200044102A10400009AD
+:102580003C0280083443008094620016304200010F
+:10259000104000043C0280009442007E244200145B
+:1025A000A462001603E000080000000027BDFFE061
+:1025B0003C028008AFBF001CAFB0001834420100DD
+:1025C000944300429442004C104000193068FFFFD1
+:1025D0009383001824020001146200298FBF001C9D
+:1025E0003C06800834D00100000810C200501021C1
+:1025F000904200643103000734C70148304200FFB5
+:10260000006210073042000134C9014E34C4012C6D
+:1026100034C5013E1040001634C601420E0006D2F9
+:10262000AFA90010960200420A0009463048FFFF99
+:102630003C028008344401009483004494820042A8
+:102640001043000F8FBF001C94820044A4820042FC
+:1026500094820050A482004E8C820038AC820030FC
+:1026600094820040A482003E9482004AA4820048E2
+:102670008FBF001C8FB000180A00090427BD00207E
+:102680008FB0001803E0000827BD002027BDFFA081
+:10269000AFB1004C3C118000AFBF0058AFB3005445
+:1026A000AFB20050AFB000483626018890C2000398
+:1026B0003044007FA3A400108E32018090C200003D
+:1026C0003043007F240200031062003BAF92001CE5
+:1026D00028620004104000062402000424020002C4
+:1026E000106200098FBF00580A000B0F8FB300540F
+:1026F0001062004D240200051062014E8FBF005889
+:102700000A000B0F8FB30054000411C002421021C5
+:102710002404FF8024420240004410242643004049
+:10272000AE2200243063007F3C02800A0062182140
+:102730009062003CAFA3003C00441025A062003C26
+:102740008FA3003C9062003C304200401040016C7E
+:102750008FBF00583C108008A3800018361001007D
+:102760008E0200E08C63003427A4003C27A50010F3
+:10277000004310210E0007C3AE0200E093A2001038
+:102780003C038000A20200D58C6202780440FFFE68
+:102790008F82001CAC62024024020002A06202444C
+:1027A0003C021000AC6202780E0009390000000003
+:1027B0000A000B0E8FBF00583C05800890C3000133
+:1027C00090A2000B1443014E8FBF005834A4008028
+:1027D0008C8200189082004C90A200083C0260009D
+:1027E0008C4254048C8300183C027FFF3442FFFF6C
+:1027F000006218243C0208008C4200B4AC8300182C
+:102800003C038000244200013C010800AC2200B4DB
+:102810008C6201F80440FFFE8F82001CAC6201C094
+:102820000A000AD6240200023C10800890C300016E
+:102830009202000B144301328FBF005827A40018E6
+:1028400036050110240600033C0260008C4254044B
+:102850000E000E470000000027A40028360501F0F6
+:102860000E000E47240600038FA200283603010045
+:10287000AE0200648FA2002CAE0200688FA200306E
+:10288000AE02006C93A40018906300D52402FF8070
+:102890000082102400431025304900FF3084007F5F
+:1028A0003122007F0082102A544000013929008023
+:1028B000000411C0244202402403FF800242102180
+:1028C00000431024AE220094264200403042007F94
+:1028D0003C038006004340218FA3001C2402FFFF1D
+:1028E000AFA800403C130800927300F71062003359
+:1028F00093A2001995030014304400FF3063FFFFDA
+:102900000064182B106000100000000095040014F3
+:102910008D07001C8D0600183084FFFF0044202323
+:102920000004210000E438210000102100E4202BE5
+:1029300000C2302100C43021AD07001CAD060018D4
+:102940000A000A2F93A20019950400148D07001C99
+:102950008D0600183084FFFF008220230004210030
+:10296000000010210080182100C2302300E4202B39
+:1029700000C4302300E33823AD07001CAD06001867
+:1029800093A200198FA30040A462001497A2001A1A
+:10299000A46200168FA2001CAC6200108FA2001C63
+:1029A000AC62000C93A20019A462002097A2001A46
+:1029B000A46200228FA2001CAC6200243C048008A8
+:1029C000348300808C6200388FA20020012088218F
+:1029D000AC62003C8FA20020AC82000093A20018E1
+:1029E000A062004C93A20018A0820009A0600068B9
+:1029F00093A20018105100512407FF803229007F54
+:102A0000000911C024420240024210213046007FDA
+:102A10003C03800000471024AC6200943C02800616
+:102A200000C2302190C2003CAFA60040000020212F
+:102A300000471025A0C2003C8FA80040950200026C
+:102A4000950300148D07001C3042FFFF3063FFFF29
+:102A50008D060018004310230002110000E2382107
+:102A600000E2102B00C4302100C23021AD07001C51
+:102A7000AD06001895020002A5020014A50000167C
+:102A80008D020008AD0200108D020008AD02000C9E
+:102A900095020002A5020020A50000228D02000878
+:102AA000AD0200249102003C304200401040001A68
+:102AB000262200013C108008A3A90038A38000183A
+:102AC000361001008E0200E08D03003427A4004080
+:102AD00027A50038004310210E0007C3AE0200E016
+:102AE00093A200383C038000A20200D58C620278D9
+:102AF0000440FFFE8F82001CAC62024024020002F0
+:102B0000A06202443C021000AC6202780E00093957
+:102B100000000000262200013043007F14730004EF
+:102B2000004020212403FF8002231024004320269C
+:102B300093A200180A000A4B309100FF93A40018DA
+:102B40008FA3001C2402FFFF1062000A308900FFDF
+:102B500024820001248300013042007F14530005C9
+:102B6000306900FF2403FF800083102400431026F7
+:102B7000304900FF3C028008904200080120882173
+:102B8000305000FF123000193222007F000211C0C5
+:102B900002421021244202402403FF8000431824F3
+:102BA0003C048000AC8300943042007F3C038006EC
+:102BB000004310218C43000C004020211060000BCA
+:102BC000AFA200400E00057E000000002623000199
+:102BD0002405FF803062007F145300020225202468
+:102BE000008518260A000AAF307100FF3C048008F7
+:102BF000348400808C8300183C027FFF3442FFFF46
+:102C000000621824AC8300183C0380008C6201F839
+:102C10000440FFFE00000000AC7201C0240200026C
+:102C2000A06201C43C021000AC6201F80A000B0E65
+:102C30008FBF00583C04800890C300019082000BB5
+:102C40001443002F8FBF0058349000809202000878
+:102C500030420040104000200000000092020008B6
+:102C60000002160000021603044100050240202164
+:102C70000E000ECC240500930A000B0E8FBF0058E7
+:102C80009202000924030018304200FF1443000D93
+:102C900002402021240500390E000E64000030217E
+:102CA0000E0003328F84001C8F82FF9424030012D5
+:102CB000A04300090E00033D8F84001C0A000B0E88
+:102CC0008FBF0058240500360E000E64000030212E
+:102CD0000A000B0E8FBF00580E0003320240202165
+:102CE000920200058F84001C344200200E00033D38
+:102CF000A20200050E0010758F84001C8FBF0058C3
+:102D00008FB300548FB200508FB1004C8FB0004889
+:102D100003E0000827BD00603C0280083445010044
+:102D20003C0280008C42014094A3000E0000302140
+:102D300000402021AF82001C3063FFFF3402FFFF00
+:102D4000106200063C0760202402FFFFA4A2000ED0
+:102D500094A500EA0A00090130A5FFFF03E000087E
+:102D60000000000027BDFFC83C0280003C06800830
+:102D7000AFB5002CAFB1001CAFBF0030AFB400281E
+:102D8000AFB30024AFB20020AFB00018345101003F
+:102D900034C501008C4301008E2200148CA400E491
+:102DA0000000A821AF83001C0044102318400052EB
+:102DB000A38000188E22001400005021ACA200E471
+:102DC00090C3000890A200D53073007FA3A200102A
+:102DD0008CB200E08CB400E4304200FF1053003BA2
+:102DE00093A200108F83001C2407FF80000211C0F3
+:102DF0000062102124420240246300400047102456
+:102E00003063007F3C0980003C08800A006818217C
+:102E1000AD2200248C62003427A4001427A50010E2
+:102E2000024280210290102304400028AFA3001426
+:102E30009062003C00E21024304200FF1440001970
+:102E4000020090219062003C34420040A062003CAD
+:102E50008F86001C93A3001024C200403042007FE4
+:102E6000004828213C0208008C4200F42463000141
+:102E7000306400FF14820002A3A30010A3A000107E
+:102E800093A20010AFA50014000211C0244202401A
+:102E900000C2102100471024AD2200240A000B4577
+:102EA00093A200100E0007C3000000003C0280083F
+:102EB00034420100AC5000E093A30010240A00014A
+:102EC000A04300D50A000B4593A200102402000184
+:102ED000154200093C0380008C6202780440FFFE2A
+:102EE0008F82001CAC62024024020002A0620244F5
+:102EF0003C021000AC6202789222000B2403000214
+:102F0000304200FF144300720000000096220008C7
+:102F1000304300FF24020082146200402402008437
+:102F20003C028000344901008D22000C95230006EC
+:102F3000000216023063FFFF3045003F24020027E5
+:102F400010A2000FAF83001428A200281040000830
+:102F5000240200312402002110A2000924020025CD
+:102F600010A20007938200190A000BBD00000000A8
+:102F700010A20007938200190A000BBD0000000098
+:102F80000E000777012020210A000C3D0000000000
+:102F90003C0380008C6202780440FFFE8F82001C9C
+:102FA000AC62024024020002A06202443C02100013
+:102FB000AC6202780A000C3D000000009523000678
+:102FC000912400058D25000C8D2600108D270018FA
+:102FD0008D28001C8D290020244200013C0108009E
+:102FE000A42356C63C010800A02456C53C01080095
+:102FF000AC2556CC3C010800AC2656D03C0108005C
+:10300000AC2756D83C010800AC2856DC3C0108002F
+:10301000AC2956E00A000C3DA38200191462000A94
+:10302000240200813C02800834420100944500EAF9
+:10303000922600058F84001C30A5FFFF30C600FFDC
+:103040000A000BFE3C0760211462005C00000000D7
+:103050009222000A304300FF306200201040000737
+:10306000306200403C02800834420100944500EA8E
+:103070008F84001C0A000BFC24060040104000074F
+:10308000000316003C02800834420100944500EA27
+:103090008F84001C0A000BFC24060041000216036A
+:1030A000044100463C02800834420100944500EA95
+:1030B0008F84001C2406004230A5FFFF3C076019E6
+:1030C0000E000901000000000A000C3D0000000095
+:1030D0009222000B24040016304200FF1044000628
+:1030E0003C0680009222000B24030017304200FFB0
+:1030F000144300320000000034C5010090A2000B10
+:10310000304200FF1444000B000080218CA20020FC
+:103110008CA400202403FF800043102400021140EF
+:103120003084007F004410253C032000004310251C
+:10313000ACC2083094A2000800021400000214037C
+:10314000044200012410000194A2000830420080D3
+:103150005040001A0200A82194A20008304220002A
+:10316000504000160200A8218CA300183C021C2D20
+:10317000344219ED106200110200A8213C0208003F
+:103180008C4200D4104000053C0280082403000457
+:1031900034420100A04300FC3C028008344201009C
+:1031A000944500EA8F84001C2406000630A5FFFF2A
+:1031B0000E0009013C0760210200A8210E00093918
+:1031C000000000009222000A304200081040000473
+:1031D00002A010210E0013790000000002A01021AF
+:1031E0008FBF00308FB5002C8FB400288FB3002420
+:1031F0008FB200208FB1001C8FB0001803E00008D0
+:1032000027BD00382402FF80008220243C02900069
+:1032100034420007008220253C028000AC4400209C
+:103220003C0380008C6200200440FFFE0000000090
+:1032300003E00008000000003C0380002402FF803F
+:10324000008220243462000700822025AC64002024
+:103250008C6200200440FFFE0000000003E0000834
+:103260000000000027BDFFD8AFB3001CAFB10014B1
+:10327000AFB00010AFBF0020AFB200183C1180000B
+:103280003C0280088E32002034530100AE2400201E
+:10329000966300EA000514003C074000004738250B
+:1032A00000A08021000030210E0009013065FFFFE1
+:1032B000240200A1160200022402FFFFA2620009FC
+:1032C000AE3200208FBF00208FB3001C8FB20018D9
+:1032D0008FB100148FB0001003E0000827BD002854
+:1032E0003C0280082403000527BDFFE834420100AA
+:1032F000A04300FCAFBF00103C0280008C420100E4
+:10330000240500A1004020210E000C67AF82001CA4
+:103310003C0380008C6202780440FFFE8F82001C18
+:103320008FBF001027BD0018AC62024024020002CB
+:10333000A06202443C021000AC62027803E0000884
+:103340000000000027BDFFE83C068000AFBF001072
+:1033500034C7010094E20008304400FF3883008243
+:10336000388200842C6300012C4200010062182581
+:103370001060002D24020083938200195040003B0E
+:103380008FBF00103C020800904256CC8CC4010054
+:103390003C06080094C656C63045003F38A30032AC
+:1033A00038A2003F2C6300012C4200010062182566
+:1033B000AF84001CAF860014A380001914600007BE
+:1033C00000E020212402002014A2001200000000CE
+:1033D0003402FFFF14C2000F00000000240200208E
+:1033E00014A2000500E028218CE300142402FFFF52
+:1033F0005062000B8FBF00103C040800248456C0AC
+:10340000000030210E000706240700010A000CD638
+:103410008FBF00100E000777000000008FBF001064
+:103420000A00093927BD001814820004240200850F
+:103430008CC501040A000CE1000020211482000662
+:103440002482FF808CC50104240440008FBF00103B
+:103450000A00016727BD0018304200FF2C4200021D
+:1034600010400004240200228FBF00100A000B2726
+:1034700027BD0018148200048F8200248FBF001023
+:103480000A000C8627BD00188C42000C1040001E5C
+:1034900000E0282190E300092402001814620003D0
+:1034A000240200160A000CFC240300081462000722
+:1034B00024020017240300123C02800834420080DA
+:1034C000A04300090A000D0994A7000854620007F0
+:1034D00094A700088F82FF942404FFFE9043000508
+:1034E00000641824A043000594A7000890A6001BC0
+:1034F0008CA4000094A500068FBF001000073C00BC
+:103500000A0008DC27BD00188FBF001003E0000888
+:1035100027BD00188F8500243C04800094A2002A57
+:103520008CA30034000230C02402FFF000C210243B
+:1035300000621821AC83003C8CA200303C03800068
+:10354000AC8200383C02005034420010AC620030C3
+:103550000000000000000000000000008C6200007D
+:10356000304200201040FFFD30C20008104000062D
+:103570003C0280008C620408ACA200208C62040C27
+:103580000A000D34ACA200248C430400ACA300203C
+:103590008C420404ACA200243C0300203C028000C6
+:1035A000AC4300303C0480008C8200300043102487
+:1035B0001440FFFD8F8600243C020040AC820030A6
+:1035C00094C3002A94C2002894C4002C94C5002EF1
+:1035D00024630001004410213064FFFFA4C20028CE
+:1035E00014850002A4C3002AA4C0002A03E0000836
+:1035F000000000008F84002427BDFFE83C05800404
+:1036000024840010AFBF00100E000E472406000AED
+:103610008F840024948200129483002E3042000F85
+:10362000244200030043180424027FFF0043102BB0
+:1036300010400002AC8300000000000D0E000D13CE
+:10364000000000008F8300248FBF001027BD0018EA
+:10365000946200149463001A3042000F00021500B7
+:10366000006218253C02800003E00008AC4300A083
+:103670008F8300243C028004944400069462001A64
+:103680008C650000A4640016004410233042FFFF44
+:103690000045102B03E00008384200018F8400240D
+:1036A0003C0780049486001A8C85000094E2000692
+:1036B000A482001694E3000600C310233042FFFFEB
+:1036C0000045102B384200011440FFF8A483001677
+:1036D00003E00008000000008F8400243C02800406
+:1036E000944200069483001A8C850000A482001680
+:1036F000006210233042FFFF0045102B38420001CA
+:103700005040000D8F850024006030213C0780046C
+:1037100094E20006A482001694E3000600C310237E
+:103720003042FFFF0045102B384200011440FFF8E3
+:10373000A48300168F8500243C03800034620400BB
+:103740008CA40020AF820020AC6400388CA200243E
+:10375000AC62003C3C020005AC62003003E00008B3
+:10376000ACA000048F8400243C0300068C8200047B
+:1037700000021140004310253C038000AC62003081
+:103780000000000000000000000000008C6200004B
+:10379000304200101040FFFD34620400AC80000491
+:1037A00003E00008AF8200208F86002427BDFFE0E1
+:1037B000AFB10014AFB00010AFBF00188CC300044D
+:1037C0008CC500248F820020309000FF94C4001A22
+:1037D00024630001244200202484000124A7002047
+:1037E000ACC30004AF820020A4C4001AACC70024FC
+:1037F00004A100060000882104E2000594C2001A1A
+:103800008CC2002024420001ACC2002094C2001AE5
+:1038100094C300282E040001004310262C4200010E
+:10382000004410245040000594C2001A24020001F4
+:10383000ACC2000894C2001A94C300280010202BC8
+:10384000004310262C4200010044102514400007BC
+:10385000000000008CC20008144000042402001084
+:103860008CC300041462000F8F8500240E000DA786
+:10387000241100018F820024944300289442001AEE
+:1038800014430003000000000E000D1300000000B0
+:10389000160000048F8500240E000D840000000037
+:1038A0008F85002494A2001E94A4001C24420001D1
+:1038B0003043FFFF14640002A4A2001EA4A0001E57
+:1038C0001200000A3C02800494A2001494A3001A7F
+:1038D0003042000F00021500006218253C028000F3
+:1038E000AC4300A00A000E1EACA0000894420006E3
+:1038F00094A3001A8CA40000A4A200160062102356
+:103900003042FFFF0044102B384200011040000DF0
+:1039100002201021006030213C07800494E2000660
+:10392000A4A2001694E3000600C310233042FFFF58
+:103930000044102B384200011440FFF8A4A30016E5
+:10394000022010218FBF00188FB100148FB000101B
+:1039500003E0000827BD002003E00008000000008D
+:103960008F82002C3C03000600021140004310250A
+:103970003C038000AC62003000000000000000004A
+:10398000000000008C620000304200101040FFFD7B
+:1039900034620400AF82002803E00008AF80002CEE
+:1039A00003E000080000102103E000080000000010
+:1039B0003084FFFF30A5FFFF0000182110800007B2
+:1039C000000000003082000110400002000420428C
+:1039D000006518210A000E3D0005284003E000089C
+:1039E0000060102110C0000624C6FFFF8CA200005A
+:1039F00024A50004AC8200000A000E4724840004C1
+:103A000003E000080000000010A0000824A3FFFF4E
+:103A1000AC86000000000000000000002402FFFF50
+:103A20002463FFFF1462FFFA2484000403E000080B
+:103A3000000000003C0280083442008024030001A2
+:103A4000AC43000CA4430010A4430012A443001490
+:103A500003E00008A44300168F82002427BDFFD88E
+:103A6000AFB3001CAFB20018AFB10014AFB000107C
+:103A7000AFBF00208C47000C248200802409FF8007
+:103A80003C08800E3043007F008080213C0A80008B
+:103A9000004920240068182130B100FF30D200FF17
+:103AA00010E000290000982126020100AD44002CFE
+:103AB000004928243042007F004820219062000005
+:103AC00024030050304200FF1443000400000000B3
+:103AD000AD45002C948200EA3053FFFF0E000D84A8
+:103AE000000000008F8200248F83002000112C0032
+:103AF0009442001E001224003484000100A22825F4
+:103B00003C02400000A22825AC7000008FBF0020BE
+:103B1000AC6000048FB20018AC7300088FB10014C1
+:103B2000AC60000C8FB3001CAC6400108FB00010B0
+:103B3000AC60001424040001AC60001827BD00280C
+:103B40000A000DB8AC65001C8FBF00208FB3001CAD
+:103B50008FB200188FB100148FB0001003E000087E
+:103B600027BD00283C06800034C201009043000FAE
+:103B7000240200101062000E2865001110A000073A
+:103B800024020012240200082405003A10620006F4
+:103B90000000302103E0000800000000240500358B
+:103BA0001462FFFC000030210A000E6400000000D7
+:103BB0008CC200748F83FF9424420FA003E000089E
+:103BC000AC62000C27BDFFE8AFBF00100E0003423F
+:103BD000240500013C0480088FBF0010240200016E
+:103BE00034830080A462001227BD00182402000163
+:103BF00003E00008A080001A27BDFFE0AFB2001864
+:103C0000AFB10014AFB00010AFBF001C30B2FFFF67
+:103C10000E000332008088213C028008345000806E
+:103C20009202000924030004304200FF1443000CF8
+:103C30003C028008124000082402000A0E000E5BBD
+:103C400000000000920200052403FFFE0043102440
+:103C5000A202000524020012A20200093C02800810
+:103C600034420080022020210E00033DA0400027A6
+:103C700016400003022020210E000EBF00000000AD
+:103C800002202021324600FF8FBF001C8FB2001897
+:103C90008FB100148FB00010240500380A000E64A4
+:103CA00027BD002027BDFFE0AFBF001CAFB200184A
+:103CB000AFB10014AFB000100E00033200808021BD
+:103CC0000E000E5B000000003C02800834450080BE
+:103CD00090A2000924120018305100FF1232000394
+:103CE0000200202124020012A0A2000990A20005D7
+:103CF0002403FFFE004310240E00033DA0A2000594
+:103D00000200202124050020163200070000302187
+:103D10008FBF001C8FB200188FB100148FB000103D
+:103D20000A00034227BD00208FBF001C8FB200187D
+:103D30008FB100148FB00010240500390A000E6402
+:103D400027BD002027BDFFE83C028000AFB0001077
+:103D5000AFBF0014344201009442000C2405003629
+:103D60000080802114400012304600FF0E00033214
+:103D7000000000003C02800834420080240300124E
+:103D8000A043000990430005346300100E000E5B51
+:103D9000A04300050E00033D020020210200202167
+:103DA0000E000342240500200A000F3C0000000022
+:103DB0000E000E64000000000E00033202002021FD
+:103DC0003C0280089043001B2405FF9F0200202135
+:103DD000006518248FBF00148FB00010A043001B93
+:103DE0000A00033D27BD001827BDFFE0AFBF001844
+:103DF000AFB10014AFB0001030B100FF0E000332BD
+:103E0000008080213C02800824030012344200809C
+:103E10000E000E5BA04300090E00033D02002021AE
+:103E200002002021022030218FBF00188FB1001422
+:103E30008FB00010240500350A000E6427BD002055
+:103E40003C0480089083000E9082000A1443000B0B
+:103E5000000028218F82FF942403005024050001D4
+:103E600090420000304200FF1443000400000000B4
+:103E70009082000E24420001A082000E03E00008A0
+:103E800000A010213C0380008C6201F80440FFFE7A
+:103E900024020002AC6401C0A06201C43C02100014
+:103EA00003E00008AC6201F827BDFFE0AFB20018E4
+:103EB0003C128008AFB10014AFBF001CAFB00010BF
+:103EC00036510080922200092403000A304200FF8C
+:103ED0001443003E000000008E4300048E22003890
+:103EE000506200808FBF001C92220000240300500B
+:103EF000304200FF144300253C0280008C42014008
+:103F00008E4300043642010002202821AC43001CED
+:103F10009622005C8E2300383042FFFF00021040E2
+:103F200000621821AE23001C8E4300048E2400384A
+:103F30009622005C006418233042FFFF0003184300
+:103F4000000210400043102A10400006000000004C
+:103F50008E4200048E230038004310230A000FAA6B
+:103F6000000220439622005C3042FFFF0002204006
+:103F70003C0280083443010034420080ACA4002C91
+:103F8000A040002424020001A062000C0E000F5E7D
+:103F900000000000104000538FBF001C3C02800056
+:103FA0008C4401403C0380008C6201F80440FFFE19
+:103FB00024020002AC6401C0A06201C43C021000F3
+:103FC000AC6201F80A0010078FBF001C92220009A2
+:103FD00024030010304200FF144300043C02800020
+:103FE0008C4401400A000FEE0000282192220009B3
+:103FF00024030016304200FF14430006240200147C
+:10400000A22200093C0280008C4401400A001001F9
+:104010008FBF001C8E2200388E23003C00431023EB
+:10402000044100308FBF001C92220027244200016F
+:10403000A2220027922200272C42000414400016DE
+:104040003C1080009222000924030004304200FF4B
+:10405000144300093C0280008C4401408FBF001CC7
+:104060008FB200188FB100148FB000102405009398
+:104070000A000ECC27BD00208C440140240500938B
+:104080008FBF001C8FB200188FB100148FB00010CA
+:104090000A000F4827BD00208E0401400E000332A5
+:1040A000000000008E4200042442FFFFAE420004E4
+:1040B0008E22003C2442FFFFAE22003C0E00033D56
+:1040C0008E0401408E0401408FBF001C8FB2001887
+:1040D0008FB100148FB00010240500040A000342C1
+:1040E00027BD00208FB200188FB100148FB00010D0
+:1040F00003E0000827BD00203C0680008CC2018838
+:104100003C038008346500809063000E00021402B6
+:10411000304400FF306300FF1464000E3C0280084E
+:1041200090A20026304200FF104400098F82FF94C5
+:10413000A0A400262403005090420000304200FF5B
+:1041400014430006000000000A0005A18CC4018091
+:104150003C02800834420080A044002603E00008AE
+:104160000000000027BDFFE030E700FFAFB20018FD
+:10417000AFBF001CAFB10014AFB0001000809021A1
+:1041800014E0000630C600FF000000000000000D33
+:10419000000000000A001060240001163C038008A3
+:1041A0009062000E304200FF14460023346200800B
+:1041B00090420026304200FF1446001F000000001D
+:1041C0009062000F304200FF1446001B0000000008
+:1041D0009062000A304200FF144600038F90FF9463
+:1041E0000000000D8F90FF948F82FF983C1180009B
+:1041F000AE05003CAC450000A066000A0E0003328C
+:104200008E240100A20000240E00033D8E24010034
+:104210003C0380008C6201F80440FFFE240200028F
+:10422000AC7201C0A06201C43C021000AC6201F893
+:104230000A0010618FBF001C000000000000000D8C
+:10424000000000002400013F8FBF001C8FB2001847
+:104250008FB100148FB0001003E0000827BD0020CC
+:104260008F83FF943C0280008C44010034420100A3
+:104270008C65003C9046001B0A00102724070001B3
+:104280003C0280089043000E9042000A0043102632
+:10429000304200FF03E000080002102B27BDFFE0C2
+:1042A0003C028008AFB10014AFB00010AFBF0018DF
+:1042B0003450008092020005240300303042003068
+:1042C00014430085008088218F8200248C42000CDA
+:1042D000104000828FBF00180E000D840000000007
+:1042E0008F860020ACD100009202000892030009E2
+:1042F000304200FF00021200306300FF004310252F
+:10430000ACC200049202004D000216000002160327
+:1043100004410005000000003C0308008C630048D5
+:104320000A00109F3C1080089202000830420040B2
+:10433000144000030000182192020027304300FFC0
+:104340003C108008361100809222004D00031E00B0
+:10435000304200FF0002140000621825ACC30008C0
+:104360008E2400308F820024ACC4000C8E250034D3
+:104370009443001E3C02C00BACC50010006218251F
+:104380008E22003800002021ACC200148E22003C96
+:10439000ACC200180E000DB8ACC3001C8E020004A5
+:1043A0008F8400203C058000AC8200008E2200201B
+:1043B000AC8200048E22001CAC8200088E220058C1
+:1043C0008CA3007400431021AC82000C8E22002CC0
+:1043D000AC8200108E2200408E23004400021400A4
+:1043E00000431025AC8200149222004D240300806B
+:1043F000304200FF1443000400000000AC800018AD
+:104400000A0010E38F8200248E23000C2402000196
+:104410001062000E2402FFFF92220008304200408A
+:104420001440000A2402FFFF8E23000C8CA20074AB
+:10443000006218233C0208000062102414400002AD
+:10444000000028210060282100051043AC820018DC
+:104450008F820024000020219443001E3C02C00CE7
+:10446000006218258F8200200E000DB8AC43001C9E
+:104470003C038008346201008C4200008F850020DC
+:10448000346300808FBF0018ACA20000ACA0000411
+:104490008C6400488F8200248FB10014ACA4000803
+:1044A000ACA0000CACA00010906300059446001E68
+:1044B0003C02400D00031E0000C23025ACA30014D6
+:1044C0008FB00010ACA0001824040001ACA6001CA2
+:1044D0000A000DB827BD00208FBF00188FB100144F
+:1044E0008FB0001003E0000827BD00203C028000D0
+:1044F0009443007C3C02800834460100308400FF75
+:104500003065FFFF2402000524A34650A0C4000C20
+:104510005482000C3065FFFF90C2000D2C42000752
+:104520001040000724A30A0090C3000D24020014C9
+:104530000062100400A210210A00111F3045FFFF85
+:104540003065FFFF3C0280083442008003E0000831
+:10455000A44500143C03800834680080AD05003891
+:10456000346701008CE2001C308400FF00A210239D
+:104570001840000330C600FF24A2FFFCACE2001C80
+:1045800030820001504000083C0380088D02003C4E
+:1045900000A2102304410012240400058C620004D0
+:1045A00010A2000F3C0380088C62000414A2001EBD
+:1045B000000000003C0208008C4200D8304200207D
+:1045C000104000093C0280083462008090630008BB
+:1045D0009042004C144300043C0280082404000470
+:1045E0000A00110900000000344300803442010039
+:1045F000A040000C24020001A462001410C0000AB4
+:104600003C0280008C4401003C0380008C6201F875
+:104610000440FFFE24020002AC6401C0A06201C499
+:104620003C021000AC6201F803E00008000000004A
+:1046300027BDFFE800A61823AFBF00101860008058
+:10464000308800FF3C02800834470080A0E000244E
+:1046500034440100A0E000278C82001C00A210233B
+:1046600004400056000000008CE2003C94E3005C33
+:104670008CE4002C004530233063FFFF00C3182179
+:104680000083202B1080000400E018218CE2002C15
+:104690000A00117800A2102194E2005C3042FFFF72
+:1046A00000C2102100A21021AC62001C3C02800854
+:1046B000344400809482005C8C83001C3042FFFFF5
+:1046C0000002104000A210210043102B10400004F3
+:1046D000000000008C82001C0A00118B3C06800840
+:1046E0009482005C3042FFFF0002104000A21021C3
+:1046F0003C06800834C3010034C70080AC82001C33
+:10470000A060000CACE500388C62001C00A21023F5
+:104710001840000224A2FFFCAC62001C3102000120
+:10472000104000083C0380088CE2003C00A21023EB
+:1047300004410012240400058CC2000410A20010E1
+:104740008FBF00108C62000414A2004F8FBF0010B6
+:104750003C0208008C4200D8304200201040000A81
+:104760003C02800834620080906300089042004C54
+:10477000144300053C028008240400048FBF00108D
+:104780000A00110927BD001834430080344201009B
+:10479000A040000C24020001A46200143C0280002E
+:1047A0008C4401003C0380008C6201F80440FFFE51
+:1047B000240200020A0011D8000000008CE2001C54
+:1047C000004610230043102B54400001ACE5001CB0
+:1047D00094E2005C3042FFFF0062102B144000079F
+:1047E0002402000294E2005C8CE3001C3042FFFFD4
+:1047F00000621821ACE3001C24020002ACE5003882
+:104800000E000F5EA082000C1040001F8FBF001032
+:104810003C0280008C4401003C0380008C6201F863
+:104820000440FFFE24020002AC6401C0A06201C487
+:104830003C021000AC6201F80A0011F08FBF0010BA
+:1048400031020010104000108FBF00103C028008A1
+:10485000344500808CA3001C94A2005C00661823E1
+:104860003042FFFF006218213C023FFF3444FFFF4B
+:104870000083102B544000010080182100C3102138
+:10488000ACA2001C8FBF001003E0000827BD001879
+:1048900027BDFFE800C0402100A63023AFBF0010B5
+:1048A00018C00026308A00FF3C028008344900808E
+:1048B0008D24001C8D23002C008820230064182BDD
+:1048C0001060000F344701008CE2002000461021E8
+:1048D000ACE200208CE200200044102B1440000BBE
+:1048E0003C023FFF8CE2002000441023ACE2002099
+:1048F0009522005C3042FFFF0A0012100082202146
+:10490000ACE00020008620213C023FFF3443FFFF43
+:104910000064102B54400001006020213C028008FC
+:104920003442008000851821AC43001CA0400024C4
+:10493000A04000270A0012623C03800831420010A8
+:10494000104000433C0380083C06800834C40080CB
+:104950008C82003C004810235840003E34660080A2
+:104960009082002424420001A0820024908200242E
+:104970003C0308008C630024304200FF0043102BEE
+:10498000144000688FBF001034C201008C42001C2C
+:1049900000A2102318400063000000008CC3000434
+:1049A0009482005C006818233042FFFF0003184324
+:1049B000000210400043102A1040000500000000D3
+:1049C0008CC20004004810230A0012450002104364
+:1049D0009482005C3042FFFF000210403C068008D9
+:1049E000AC82002C34C5008094A2005C8CA4002C06
+:1049F00094A3005C3042FFFF00021040008220219F
+:104A00003063FFFF0083202101041021ACA2001CB1
+:104A10008CC2000434C60100ACC2001C2402000297
+:104A20000E000F5EA0C2000C1040003E8FBF0010B1
+:104A30003C0280008C4401003C0380008C6201F841
+:104A40000440FFFE240200020A001292000000004F
+:104A500034660080ACC50038346401008C82001CD0
+:104A600000A210231840000224A2FFFCAC82001C0C
+:104A7000314200015040000A3C0380088CC2003CD7
+:104A800000A2102304430014240400058C620004D7
+:104A900014A200033C0380080A00128424040005C9
+:104AA0008C62000414A2001F8FBF00103C0208009B
+:104AB0008C4200D8304200201040000A3C0280089E
+:104AC00034620080906300089042004C144300055B
+:104AD0003C028008240400048FBF00100A00110962
+:104AE00027BD00183443008034420100A040000C70
+:104AF00024020001A46200143C0280008C440100E6
+:104B00003C0380008C6201F80440FFFE2402000296
+:104B1000AC6401C0A06201C43C021000AC6201F8A8
+:104B20008FBF001003E0000827BD001827BDFFE875
+:104B30003C0A8008AFBF0010354900808D22003C40
+:104B400000C04021308400FF004610231840009D23
+:104B500030E700FF354701002402000100A63023A2
+:104B6000A0E0000CA0E0000DA522001418C0002455
+:104B7000308200108D23001C8D22002C0068182329
+:104B80000043102B1040000F000000008CE20020BA
+:104B900000461021ACE200208CE200200043102BE4
+:104BA0001440000B3C023FFF8CE200200043102326
+:104BB000ACE200209522005C3042FFFF0A0012C1E7
+:104BC00000621821ACE00020006618213C023FFF83
+:104BD0003446FFFF00C3102B5440000100C01821D1
+:104BE0003C0280083442008000651821AC43001C60
+:104BF000A0400024A04000270A00130F3C038008B7
+:104C0000104000403C0380088D22003C00481023E7
+:104C10005840003D34670080912200242442000166
+:104C2000A1220024912200243C0308008C6300246C
+:104C3000304200FF0043102B1440009A8FBF001039
+:104C40008CE2001C00A21023184000960000000017
+:104C50008D4300049522005C006818233042FFFF5A
+:104C600000031843000210400043102A10400005C2
+:104C7000012020218D420004004810230A0012F276
+:104C8000000210439522005C3042FFFF00021040FA
+:104C90003C068008AC82002C34C5008094A2005CE5
+:104CA0008CA4002C94A3005C3042FFFF0002104053
+:104CB000008220213063FFFF0083182101031021AF
+:104CC000ACA2001C8CC2000434C60100ACC2001CA3
+:104CD000240200020E000F5EA0C2000C1040007102
+:104CE0008FBF00103C0280008C4401003C03800018
+:104CF0008C6201F80440FFFE240200020A0013390E
+:104D00000000000034670080ACE500383466010024
+:104D10008CC2001C00A210231840000224A2FFFC39
+:104D2000ACC2001C30820001504000083C038008E7
+:104D30008CE2003C00A2102304430051240400052F
+:104D40008C62000410A2003E3C0380088C620004C8
+:104D500054A200548FBF00103C0208008C4200D8BF
+:104D600030420020104000063C028008346200807F
+:104D7000906300089042004C104300403C028008C1
+:104D80003443008034420100A040000C24020001A2
+:104D9000A46200143C0280008C4401003C038000AB
+:104DA0008C6201F80440FFFE24020002AC6401C0E2
+:104DB000A06201C43C021000AC6201F80A00137743
+:104DC0008FBF001024020005A120002714E2000A72
+:104DD0003C038008354301009062000D2C42000620
+:104DE000504000053C0380089062000D2442000101
+:104DF000A062000D3C03800834670080ACE50038F9
+:104E0000346601008CC2001C00A21023184000026E
+:104E100024A2FFFCACC2001C308200015040000AFA
+:104E20003C0380088CE2003C00A2102304410014E3
+:104E3000240400058C62000414A200033C038008D3
+:104E40000A00136E240400058C62000414A20015ED
+:104E50008FBF00103C0208008C4200D83042002076
+:104E60001040000A3C028008346200809063000811
+:104E70009042004C144300053C02800824040004C6
+:104E80008FBF00100A00110927BD001834430080AD
+:104E900034420100A040000C24020001A46200146E
+:104EA0008FBF001003E0000827BD00183C0B8008EE
+:104EB00027BDFFE83C028000AFBF00103442010074
+:104EC000356A00809044000A356901008C45001461
+:104ED0008D4800389123000C308400FF0105102319
+:104EE0001C4000B3306700FF2CE20006504000B1C8
+:104EF0008FBF00102402000100E2300430C2000322
+:104F00005440000800A8302330C2000C144000A117
+:104F100030C20030144000A38FBF00100A00143BC1
+:104F20000000000018C00024308200108D43001CD7
+:104F30008D42002C006818230043102B1040000FF6
+:104F4000000000008D22002000461021AD2200202C
+:104F50008D2200200043102B1440000B3C023FFF29
+:104F60008D22002000431023AD2200209542005CDA
+:104F70003042FFFF0A0013AF00621821AD2000206D
+:104F8000006618213C023FFF3446FFFF00C3102B90
+:104F90005440000100C018213C02800834420080C7
+:104FA00000651821AC43001CA0400024A04000274D
+:104FB0000A0013FD3C038008104000403C038008B9
+:104FC0008D42003C004810231840003D34670080AB
+:104FD0009142002424420001A14200249142002475
+:104FE0003C0308008C630024304200FF0043102B78
+:104FF000144000708FBF00108D22001C00A21023EF
+:105000001840006C000000008D6300049542005CB5
+:10501000006818233042FFFF0003184300021040CD
+:105020000043102A10400005014020218D62000439
+:10503000004810230A0013E0000210439542005C70
+:105040003042FFFF000210403C068008AC82002C7A
+:1050500034C5008094A2005C8CA4002C94A3005C56
+:105060003042FFFF00021040008220213063FFFF2A
+:105070000083182101031021ACA2001C8CC2000483
+:1050800034C60100ACC2001C240200020E000F5EF8
+:10509000A0C2000C104000478FBF00103C028000EF
+:1050A0008C4401003C0380008C6201F80440FFFE48
+:1050B000240200020A00142D000000003467008062
+:1050C000ACE50038346601008CC2001C00A210233D
+:1050D0001840000224A2FFFCACC2001C3082000178
+:1050E0005040000A3C0380088CE2003C00A21023E0
+:1050F00004430014240400058C62000414A200037D
+:105100003C0380080A00141F240400058C6200047C
+:1051100014A200288FBF00103C0208008C4200D867
+:10512000304200201040000A3C02800834620080B7
+:10513000906300089042004C144300053C02800834
+:10514000240400048FBF00100A00110927BD0018B5
+:105150003443008034420100A040000C24020001CE
+:10516000A46200143C0280008C4401003C038000D7
+:105170008C6201F80440FFFE24020002AC6401C00E
+:10518000A06201C43C021000AC6201F80A00143BAA
+:105190008FBF00108FBF0010010030210A00115A8C
+:1051A00027BD0018010030210A00129927BD001800
+:1051B0008FBF001003E0000827BD00183C038008E3
+:1051C0003464010024020003A082000C8C620004FD
+:1051D00003E00008AC82001C3C05800834A300807A
+:1051E0009062002734A501002406004324420001F8
+:1051F000A0620027906300273C0208008C42004810
+:10520000306300FF146200043C07602194A500EAAB
+:105210000A00090130A5FFFF03E0000800000000BC
+:1052200027BDFFE8AFBF00103C0280000E00144411
+:105230008C4401803C02800834430100A060000CD3
+:105240008C4200048FBF001027BD001803E0000847
+:10525000AC62001C27BDFFE03C028008AFBF001815
+:10526000AFB10014AFB000103445008034460100E7
+:105270003C0880008D09014090C3000C8CA4003CC8
+:105280008CA200381482003B306700FF9502007C3E
+:1052900090A30027146000093045FFFF2402000599
+:1052A00054E200083C04800890C2000D2442000132
+:1052B000A0C2000D0A00147F3C048008A0C0000DAD
+:1052C0003C048008348201009042000C2403000555
+:1052D000304200FF1443000A24A205DC348300801E
+:1052E000906200272C4200075040000524A20A00CB
+:1052F00090630027240200140062100400A2102111
+:105300003C108008361000803045FFFF012020212E
+:105310000E001444A60500149602005C8E030038AB
+:105320003C1180003042FFFF000210400062182153
+:10533000AE03001C0E0003328E24014092020025B1
+:1053400034420040A20200250E00033D8E2401409D
+:105350008E2401403C0380008C6201F80440FFFE73
+:1053600024020002AC6401C0A06201C43C0210002F
+:10537000AC6201F88FBF00188FB100148FB000101D
+:1053800003E0000827BD00203C0360103C02080039
+:1053900024420174AC62502C8C6250003C048000AA
+:1053A00034420080AC6250003C0208002442547C2D
+:1053B0003C010800AC2256003C020800244254384C
+:1053C0003C010800AC2256043C020002AC840008F8
+:1053D000AC82000C03E000082402000100A0302190
+:1053E0003C1C0800279C56083C0200023C050400B7
+:1053F00000852826008220260004102B2CA5000101
+:105400002C840001000210803C0308002463560035
+:105410000085202500431821108000030000102182
+:10542000AC6600002402000103E000080000000058
+:105430003C1C0800279C56083C0200023C05040066
+:1054400000852826008220260004102B2CA50001B0
+:105450002C840001000210803C03080024635600E5
+:105460000085202500431821108000050000102130
+:105470003C02080024425438AC62000024020001BF
+:1054800003E00008000000003C0200023C030400AE
+:1054900000821026008318262C4200012C63000194
+:1054A000004310251040000B000028213C1C080080
+:1054B000279C56083C0380008C62000824050001EC
+:1054C00000431025AC6200088C62000C00441025DB
+:1054D000AC62000C03E0000800A010213C1C080096
+:1054E000279C56083C0580008CA3000C0004202754
+:1054F000240200010064182403E00008ACA3000C9F
+:105500003C020002148200063C0560008CA208D018
+:105510002403FFFE0043102403E00008ACA208D0DF
+:105520003C02040014820005000000008CA208D098
+:105530002403FFFD00431024ACA208D003E00008C0
+:10554000000000003C02601A344200108C430080CE
+:1055500027BDFFF88C440084AFA3000093A3000094
+:10556000240200041462001AAFA4000493A20001F4
+:105570001040000797A300023062FFFC3C0380004C
+:10558000004310218C4200000A001536AFA200042F
+:105590003062FFFC3C03800000431021AC4400005B
+:1055A000A3A000003C0560008CA208D02403FFFEED
+:1055B0003C04601A00431024ACA208D08FA300045E
+:1055C0008FA2000034840010AC830084AC82008081
+:1055D00003E0000827BD000827BDFFE8AFBF0010AB
+:1055E0003C1C0800279C56083C0280008C43000CA1
+:1055F0008C420004004318243C0200021060001496
+:10560000006228243C0204003C04000210A00005B3
+:10561000006210243C0208008C4256000A00155B10
+:1056200000000000104000073C0404003C02080099
+:105630008C4256040040F809000000000A00156082
+:10564000000000000000000D3C1C0800279C5608CC
+:105650008FBF001003E0000827BD0018800802403B
+:1056600080080100800800808008000000000C8095
+:105670000000320008000E9808000EF408000F88A1
+:1056800008001028080010748008010080080080BD
+:10569000800800000A000028000000000000000050
+:1056A0000000000D6370362E322E316200000000C3
+:1056B00006020104000000000000000000000000DD
+:1056C000000000000000000038003C000000000066
+:1056D00000000000000000000000000000000020AA
+:1056E00000000000000000000000000000000000BA
+:1056F00000000000000000000000000000000000AA
+:10570000000000000000000021003800000000013F
+:105710000000002B000000000000000400030D400A
+:105720000000000000000000000000000000000079
+:105730000000000000000000100000030000000056
+:105740000000000D0000000D3C020800244259AC8E
+:105750003C03080024635BF4AC4000000043202BB2
+:105760001480FFFD244200043C1D080037BD9FFC4F
+:1057700003A0F0213C100800261000A03C1C0800EB
+:10578000279C59AC0E0002F6000000000000000D3E
+:1057900027BDFFB4AFA10000AFA20004AFA3000873
+:1057A000AFA4000CAFA50010AFA60014AFA700185F
+:1057B000AFA8001CAFA90020AFAA0024AFAB0028FF
+:1057C000AFAC002CAFAD0030AFAE0034AFAF00389F
+:1057D000AFB8003CAFB90040AFBC0044AFBF004819
+:1057E0000E000820000000008FBF00488FBC00445E
+:1057F0008FB900408FB8003C8FAF00388FAE0034B7
+:105800008FAD00308FAC002C8FAB00288FAA002406
+:105810008FA900208FA8001C8FA700188FA6001446
+:105820008FA500108FA4000C8FA300088FA2000486
+:105830008FA1000027BD004C3C1B60188F7A5030B0
+:10584000377B502803400008AF7A000000A01821E1
+:1058500000801021008028213C0460003C0760008B
+:105860002406000810600006348420788C42000072
+:10587000ACE220088C63000003E00008ACE3200CDD
+:105880000A000F8100000000240300403C02600079
+:1058900003E00008AC4320003C0760008F86000452
+:1058A0008CE520740086102100A2182B14600007DC
+:1058B000000028218F8AFDA024050001A1440013C7
+:1058C0008F89000401244021AF88000403E0000810
+:1058D00000A010218F84FDA08F8500049086001306
+:1058E00030C300FF00A31023AF82000403E00008D0
+:1058F000A08000138F84FDA027BDFFE8AFB000108B
+:10590000AFBF001490890011908700112402002875
+:10591000312800FF3906002830E300FF2485002CE1
+:105920002CD00001106200162484001C0E00006EB2
+:10593000000000008F8FFDA03C05600024020204DF
+:1059400095EE003E95ED003C000E5C0031ACFFFF93
+:10595000016C5025ACAA2010520000012402000462
+:10596000ACA22000000000000000000000000000C9
+:105970008FBF00148FB0001003E0000827BD00188F
+:105980000A0000A6000028218F85FDA027BDFFD8B2
+:10599000AFBF0020AFB3001CAFB20018AFB100140E
+:1059A000AFB000100080982190A4001124B0001C1A
+:1059B00024B1002C308300FF386200280E000090D4
+:1059C0002C5200010E00009800000000020020216F
+:1059D0001240000202202821000028210E00006E43
+:1059E000000000008F8DFDA03C0880003C05600099
+:1059F00095AC003E95AB003C02683025000C4C0095
+:105A0000316AFFFF012A3825ACA7201024020202C8
+:105A1000ACA6201452400001240200028FBF0020D7
+:105A20008FB3001C8FB200188FB100148FB000101C
+:105A300027BD002803E00008ACA2200027BDFFE03E
+:105A4000AFB20018AFB10014AFB00010AFBF001C70
+:105A50003C1160008E2320748F82000430D0FFFF41
+:105A600030F2FFFF1062000C2406008F0E00006E63
+:105A7000000000003C06801F0010440034C5FF00F9
+:105A80000112382524040002AE2720100000302126
+:105A9000AE252014AE2420008FBF001C8FB200184A
+:105AA0008FB100148FB0001000C0102103E0000877
+:105AB00027BD002027BDFFE0AFB0001030D0FFFFB2
+:105AC000AFBF0018AFB100140E00006E30F1FFFF41
+:105AD00000102400009180253C036000AC70201071
+:105AE0008FBF00188FB100148FB000102402000483
+:105AF000AC62200027BD002003E000080000102158
+:105B000027BDFFE03C046018AFBF0018AFB1001420
+:105B1000AFB000108C8850002403FF7F34028071E6
+:105B20000103382434E5380C241F00313C1980006F
+:105B3000AC8550003C11800AAC8253BCAF3F0008DA
+:105B40000E00054CAF9100400E00050A3C116000AC
+:105B50000E00007D000000008E3008083C0F570941
+:105B60002418FFF00218602435EEE00035EDF00057
+:105B7000018E5026018D58262D4600012D69000109
+:105B8000AF86004C0E000D09AF8900503C06601630
+:105B90008CC700003C0860148D0500A03C03FFFF8B
+:105BA00000E320243C02535300052FC2108200550D
+:105BB00034D07C00960201F2A780006C10400003F4
+:105BC000A780007C384B1E1EA78B006C960201F844
+:105BD000104000048F8D0050384C1E1EA78C007C96
+:105BE0008F8D005011A000058F83004C240E0020E3
+:105BF000A78E007CA78E006C8F83004C1060000580
+:105C00009785007C240F0020A78F007CA78F006C55
+:105C10009785007C2CB8008153000001240500808A
+:105C20009784006C2C91040152200001240404008C
+:105C30001060000B3C0260008FBF00188FB1001491
+:105C40008FB0001027BD0020A784006CA785007CC2
+:105C5000A380007EA780007403E00008A780009264
+:105C60008C4704382419103C30FFFFFF13F9000360
+:105C700030A8FFFF1100004624030050A380007EDF
+:105C80009386007E50C00024A785007CA780007CFE
+:105C90009798007CA780006CA7800074A780009272
+:105CA0003C010800AC3800800E00078700000000AF
+:105CB0003C0F60008DED0808240EFFF03C0B600ED9
+:105CC000260C0388356A00100000482100002821B6
+:105CD00001AE20243C105709AF8C0010AF8A004859
+:105CE000AF89001810900023AF8500148FBF0018F3
+:105CF0008FB100148FB0001027BD002003E0000812
+:105D0000AF80005400055080014648218D260004D4
+:105D10000A00014800D180219798007CA784006C7C
+:105D2000A7800074A78000923C010800AC38008076
+:105D30000E000787000000003C0F60008DED080892
+:105D4000240EFFF03C0B600E260C0388356A001011
+:105D5000000048210000282101AE20243C105709F2
+:105D6000AF8C0010AF8A0048AF8900181490FFDF95
+:105D7000AF85001424110001AF9100548FBF0018AB
+:105D80008FB100148FB0001003E0000827BD002081
+:105D90000A00017BA383007E3083FFFF8F880040D1
+:105DA0008F87003C000321403C0580003C020050EE
+:105DB000008248253C0660003C0A010034AC040027
+:105DC0008CCD08E001AA58241160000500000000F5
+:105DD0008CCF08E024E7000101EA7025ACCE08E092
+:105DE0008D19001001805821ACB900388D180014AD
+:105DF000ACB8003CACA9003000000000000000007E
+:105E00000000000000000000000000000000000092
+:105E100000000000000000003C0380008C640000D3
+:105E2000308200201040FFFD3C0F60008DED08E047
+:105E30003C0E010001AE18241460FFE100000000D8
+:105E4000AF87003C03E00008AF8B00588F8500400F
+:105E5000240BFFF03C06800094A7001A8CA90024B4
+:105E600030ECFFFF000C38C000EB5024012A402129
+:105E7000ACC8003C8CA400248CC3003C00831023DD
+:105E800018400033000000008CAD002025A2000166
+:105E90003C0F0050ACC2003835EE00103C068000CC
+:105EA000ACCE003000000000000000000000000048
+:105EB00000000000000000000000000000000000E2
+:105EC000000000003C0480008C9900003338002062
+:105ED0001300FFFD30E20008104000173C0980006D
+:105EE0008C880408ACA800108C83040CACA30014AC
+:105EF0003C1900203C188000AF19003094AE001807
+:105F000094AF001C01CF3021A4A6001894AD001A54
+:105F100025A70001A4A7001A94AB001A94AC001E98
+:105F2000118B00030000000003E0000800000000E7
+:105F300003E00008A4A0001A8D2A0400ACAA0010F7
+:105F40008D240404ACA400140A0002183C1900209B
+:105F50008CA200200A0002003C0F00500A0001EE53
+:105F60000000000027BDFFE8AFBF00100E000232A6
+:105F7000000000008F8900408FBF00103C038000AC
+:105F8000A520000A9528000A9527000427BD0018BF
+:105F90003105FFFF30E6000F0006150000A22025A6
+:105FA00003E00008AC6400803C0508008CA50020DC
+:105FB0008F83000C27BDFFE8AFB00010AFBF001407
+:105FC00010A300100000802124040001020430040A
+:105FD00000A6202400C3102450440006261000010F
+:105FE000001018802787FDA41480000A006718217C
+:105FF000261000012E0900025520FFF38F83000CAC
+:10600000AF85000C8FBF00148FB0001003E00008B4
+:1060100027BD00188C6800003C058000ACA8002457
+:106020000E000234261000013C0508008CA500205B
+:106030000A0002592E0900022405000100851804F7
+:106040003C0408008C84002027BDFFC8AFBF00348B
+:1060500000831024AFBE0030AFB7002CAFB60028CD
+:10606000AFB50024AFB40020AFB3001CAFB200182E
+:10607000AFB1001410400051AFB000108F84004049
+:10608000948700069488000A00E8302330D5FFFF8B
+:1060900012A0004B8FBF0034948B0018948C000A20
+:1060A000016C50233142FFFF02A2482B1520000251
+:1060B00002A02021004020212C8F000515E00002C5
+:1060C00000809821241300040E0001C102602021E9
+:1060D0008F87004002609021AF80004494F4000A52
+:1060E000026080211260004E3291FFFF3C1670006A
+:1060F0003C1440003C1E20003C1760008F99005863
+:106100008F380000031618241074004F0283F82BF8
+:1061100017E0003600000000107E00478F86004424
+:1061200014C0003A2403000102031023022320219B
+:106130003050FFFF1600FFF13091FFFF8F870040C6
+:106140003C1100203C108000AE11003094EB000A9E
+:106150003C178000024B5021A4EA000A94E9000A8F
+:1061600094E800043123FFFF3106000F00062D00E4
+:106170000065F025AEFE008094F3000A94F6001846
+:1061800012D30036001221408CFF00148CF4001052
+:1061900003E468210000C02101A4782B029870213B
+:1061A00001CF6021ACED0014ACEC001002B238233A
+:1061B00030F5FFFF16A0FFB88F8400408FBF00347A
+:1061C0008FBE00308FB7002C8FB600288FB500240B
+:1061D0008FB400208FB3001C8FB200188FB1001451
+:1061E0008FB0001003E0000827BD00381477FFCC03
+:1061F0008F8600440E000EE202002021004018218C
+:106200008F86004410C0FFC9020310230270702360
+:106210008F87004001C368210A0002E431B2FFFF0A
+:106220008F86004414C0FFC93C1100203C10800040
+:106230000A0002AEAE1100300E00046602002021FA
+:106240000A0002DB00401821020020210E0009395B
+:10625000022028210A0002DB004018210E0001EE76
+:10626000000000000A0002C702B2382327BDFFC8A1
+:10627000AFB7002CAFB60028AFB50024AFB40020F4
+:10628000AFB3001CAFB20018AFB10014AFB0001034
+:10629000AFBF00300E00011B241300013C047FFF40
+:1062A0003C0380083C0220003C010800AC20007048
+:1062B0003496FFFF34770080345200033C1512C03F
+:1062C000241400013C1080002411FF800E000245C0
+:1062D000000000008F8700488F8B00188F89001402
+:1062E0008CEA00EC8CE800E8014B302B01092823F4
+:1062F00000A6102314400006014B18231440000E82
+:106300003C05800002A3602B1180000B0000000000
+:106310003C0560008CEE00EC8CED00E88CA4180CC1
+:10632000AF8E001804800053AF8D00148F8F0010C3
+:10633000ADF400003C0580008CBF00003BF900017B
+:10634000333800011700FFE13C0380008C6201003C
+:1063500024060C0010460009000000008C680100B3
+:106360002D043080548000103C0480008C690100B2
+:106370002D2331811060000C3C0480008CAA0100A8
+:1063800011460004000020218CA6010024C5FF81D5
+:1063900030A400FF8E0B01000E000269AE0B00243A
+:1063A0000A00034F3C0480008C8D01002DAC3300AB
+:1063B00011800022000000003C0708008CE70098D4
+:1063C00024EE00013C010800AC2E00983C04800043
+:1063D0008C8201001440000300000000566000148D
+:1063E0003C0440008C9F01008C9801000000982123
+:1063F00003F1C82400193940330F007F00EF7025E6
+:1064000001D26825AC8D08308C8C01008C85010090
+:10641000258B0100017130240006514030A3007F1C
+:106420000143482501324025AC8808303C04400037
+:10643000AE0401380A00030E000000008C99010030
+:10644000240F0020AC99002092F80000330300FFD5
+:10645000106F000C241F0050547FFFDD3C048000AF
+:106460008C8401000E00154E000000000A00034F4E
+:106470003C04800000963824ACA7180C0A000327BF
+:106480008F8F00108C8501000E0008F72404008017
+:106490000A00034F3C04800000A4102B24030001D9
+:1064A00010400009000030210005284000A4102BF6
+:1064B00004A00003000318405440FFFC00052840DE
+:1064C0005060000A0004182B0085382B54E00004AB
+:1064D0000003184200C33025008520230003184222
+:1064E0001460FFF9000528420004182B03E000089F
+:1064F00000C310213084FFFF30C600FF3C0780003E
+:106500008CE201B80440FFFE00064C000124302557
+:106510003C08200000C820253C031000ACE00180AE
+:10652000ACE50184ACE4018803E00008ACE301B809
+:106530003C0660008CC5201C2402FFF03083020062
+:10654000308601001060000E00A2282434A500014E
+:106550003087300010E0000530830C0034A50004C3
+:106560003C04600003E00008AC85201C1060FFFDC7
+:106570003C04600034A5000803E00008AC85201C42
+:1065800054C0FFF334A500020A0003B03087300086
+:1065900027BDFFE8AFB00010AFBF00143C0760009C
+:1065A000240600021080001100A080218F83005873
+:1065B0000E0003A78C6400188F8200580000202171
+:1065C000240600018C45000C0E000398000000001A
+:1065D0001600000224020003000010218FBF0014E7
+:1065E0008FB0001003E0000827BD00188CE8201CC5
+:1065F0002409FFF001092824ACE5201C8F870058EE
+:106600000A0003CD8CE5000C3C02600E00804021A6
+:1066100034460100240900180000000000000000BA
+:10662000000000003C0A00503C0380003547020097
+:10663000AC68003834640400AC65003CAC670030E2
+:106640008C6C0000318B00201160FFFD2407FFFFE0
+:106650002403007F8C8D00002463FFFF248400044A
+:10666000ACCD00001467FFFB24C60004000000004E
+:10667000000000000000000024A402000085282B78
+:106680003C0300203C0E80002529FFFF010540212E
+:10669000ADC300301520FFE00080282103E0000892
+:1066A000000000008F82005827BDFFD8AFB3001C48
+:1066B000AFBF0020AFB20018AFB10014AFB00010F0
+:1066C00094460002008098218C5200182CC300814F
+:1066D0008C4800048C4700088C51000C8C49001039
+:1066E000106000078C4A00142CC4000414800013AE
+:1066F00030EB000730C5000310A0001000000000C0
+:106700002410008B02002021022028210E00039873
+:10671000240600031660000224020003000010217A
+:106720008FBF00208FB3001C8FB200188FB10014F0
+:106730008FB0001003E0000827BD00281560FFF1AE
+:106740002410008B3C0C80003C030020241F00011F
+:10675000AD830030AF9F0044000000000000000047
+:10676000000000002419FFF024D8000F031978243A
+:106770003C1000D0AD88003801F0702524CD000316
+:106780003C08600EAD87003C35850400AD8E0030BE
+:10679000000D38823504003C3C0380008C6B000007
+:1067A000316200201040FFFD0000000010E00008F2
+:1067B00024E3FFFF2407FFFF8CA800002463FFFFF2
+:1067C00024A50004AC8800001467FFFB24840004A7
+:1067D0003C05600EACA60038000000000000000080
+:1067E000000000008F8600543C0400203C0780001D
+:1067F000ACE4003054C000060120202102402021DA
+:106800000E0003A7000080210A00041D02002021C1
+:106810000E0003DD01402821024020210E0003A7C5
+:10682000000080210A00041D0200202127BDFFE096
+:10683000AFB200183092FFFFAFB10014AFBF001C21
+:10684000AFB000101640000D000088210A0004932C
+:106850000220102124050003508500278CE5000C40
+:106860000000000D262800013111FFFF24E2002066
+:106870000232802B12000019AF8200588F82004430
+:10688000144000168F8700583C0670003C0320001F
+:106890008CE5000000A62024148300108F84006083
+:1068A000000544023C09800000A980241480FFE90F
+:1068B000310600FF2CCA000B5140FFEB26280001D7
+:1068C000000668803C0E080025CE575801AE6021B6
+:1068D0008D8B0000016000080000000002201021E4
+:1068E0008FBF001C8FB200188FB100148FB0001042
+:1068F00003E0000827BD00200E0003982404008454
+:106900001600FFD88F8700580A000474AF8000601B
+:10691000020028210E0003BF240400018F870058C5
+:106920000A000474AF820060020028210E0003BF39
+:10693000000020210A0004A38F8700580E000404E1
+:10694000020020218F8700580A000474AF82006083
+:1069500030AFFFFF000F19C03C0480008C9001B8DD
+:106960000600FFFE3C1920043C181000AC83018097
+:10697000AC800184AC990188AC9801B80A00047518
+:106980002628000190E2000390E30002000020218D
+:106990000002FE0000033A0000FF2825240600083C
+:1069A0000E000398000000001600FFDC2402000324
+:1069B0008F870058000010210A000474AF82006025
+:1069C00090E8000200002021240600090A0004C308
+:1069D00000082E0090E4000C240900FF308500FF21
+:1069E00010A900150000302190F9000290F8000372
+:1069F000308F00FF94EB000400196E000018740043
+:106A0000000F62000186202501AE5025014B28258C
+:106A10003084FF8B0A0004C32406000A90E30002BE
+:106A200090FF0004000020210003360000DF28252D
+:106A30000A0004C32406000B0A0004D52406008BB8
+:106A4000000449C23127003F000443423C02800059
+:106A500000082040240316802CE60020AC43002CC4
+:106A600024EAFFE02482000114C0000330A900FFE3
+:106A700000801021314700FF000260803C0D800043
+:106A8000240A0001018D20213C0B000E00EA28049D
+:106A9000008B302111200005000538278CCE000026
+:106AA00001C5382503E00008ACC700008CD8000001
+:106AB0000307782403E00008ACCF000027BDFFE007
+:106AC000AFB10014AFB00010AFBF00183C076000BA
+:106AD0008CE408083402F0003C1160003083F000C0
+:106AE000240501C03C04800E000030211062000625
+:106AF000241000018CEA08083149F0003928E00030
+:106B00000008382B000780403C0D0200AE2D081411
+:106B1000240C16803C0B80008E2744000E000F8B47
+:106B2000AD6C002C120000043C02169124050001FB
+:106B3000120500103C023D2C345800E0AE384408E9
+:106B40003C1108008E31007C8FBF00183C066000AD
+:106B500000118540360F16808FB100148FB00010E1
+:106B60003C0E020027BD0020ACCF442003E000080B
+:106B7000ACCE08103C0218DA345800E0AE384408B5
+:106B80003C1108008E31007C8FBF00183C0660006D
+:106B900000118540360F16808FB100148FB00010A1
+:106BA0003C0E020027BD0020ACCF442003E00008CB
+:106BB000ACCE08100A0004EB240500010A0004EB27
+:106BC0000000282124020400A7820024A780001CC2
+:106BD000000020213C06080024C65A582405FFFF67
+:106BE00024890001000440803124FFFF01061821A0
+:106BF0002C87002014E0FFFAAC6500002404040098
+:106C0000A7840026A780001E000020213C06080063
+:106C100024C65AD82405FFFF248D0001000460809B
+:106C200031A4FFFF018658212C8A00201540FFFA6D
+:106C3000AD650000A7800028A7800020A780002263
+:106C4000000020213C06080024C65B582405FFFFF5
+:106C5000249900010004C0803324FFFF030678213B
+:106C60002C8E000415C0FFFAADE500003C05600065
+:106C70008CA73D002403E08F00E31024344601403C
+:106C800003E00008ACA63D002487007F000731C266
+:106C900024C5FFFF000518C2246400013082FFFFF5
+:106CA000000238C0A78400303C010800AC27003047
+:106CB000AF80002C0000282100002021000030219E
+:106CC0002489000100A728213124FFFF2CA81701E7
+:106CD000110000032C8300801460FFF924C600011A
+:106CE00000C02821AF86002C10C0001DA786002AF6
+:106CF00024CAFFFF000A11423C08080025085B581F
+:106D00001040000A00002021004030212407FFFF2E
+:106D1000248E00010004688031C4FFFF01A86021B7
+:106D20000086582B1560FFFAAD87000030A2001FC7
+:106D30005040000800043080240300010043C804D0
+:106D400000041080004878212738FFFF03E0000886
+:106D5000ADF8000000C820212405FFFFAC8500002D
+:106D600003E000080000000030A5FFFF30C6FFFF71
+:106D700030A8001F0080602130E700FF0005294295
+:106D80000000502110C0001D24090001240B000147
+:106D900025180001010B2004330800FF0126782686
+:106DA000390E00202DED00012DC2000101A2182591
+:106DB0001060000D014450250005C880032C4021BF
+:106DC0000100182110E0000F000A20278D040000A8
+:106DD000008A1825AD03000024AD00010000402109
+:106DE0000000502131A5FFFF252E000131C9FFFF12
+:106DF00000C9102B1040FFE72518000103E0000830
+:106E0000000000008D0A0000014440240A0005D162
+:106E1000AC68000027BDFFE830A5FFFF30C6FFFFCC
+:106E2000AFB00010AFBF001430E7FFFF00005021EB
+:106E30003410FFFF0000602124AF001F00C0482174
+:106E4000241800012419002005E0001601E010219B
+:106E50000002F943019F682A0009702B01AE40240B
+:106E600011000017000C18800064102110E00005CC
+:106E70008C4B000000F840040008382301675824B8
+:106E800000003821154000410000402155600016E7
+:106E90003169FFFF258B0001316CFFFF05E1FFEC3D
+:106EA00001E0102124A2003E0002F943019F682A5C
+:106EB0000009702B01AE40241500FFEB000C188078
+:106EC000154600053402FFFF020028210E0005B51B
+:106ED00000003821020010218FBF00148FB0001075
+:106EE00003E0000827BD00181520000301601821E9
+:106EF000000B1C0224080010306A00FF154000053A
+:106F0000306E000F250D000800031A0231A800FFA3
+:106F1000306E000F15C00005307F000325100004FF
+:106F200000031902320800FF307F000317E000055C
+:106F3000386900012502000200031882304800FF72
+:106F4000386900013123000110600004310300FFA3
+:106F5000250A0001314800FF310300FF000C6940A1
+:106F600001A34021240A000110CAFFD53110FFFF00
+:106F7000246E000131C800FF1119FFC638C9000195
+:106F80002D1F002053E0001C258B0001240D000163
+:106F90000A000648240E002051460017258B0001E8
+:106FA00025090001312800FF2D0900205120001281
+:106FB000258B000125430001010D5004014B1024D5
+:106FC000250900011440FFF4306AFFFF3127FFFF5D
+:106FD00010EE000C2582FFFF304CFFFF0000502117
+:106FE0003410FFFF312800FF2D0900205520FFF24B
+:106FF00025430001258B0001014648260A000602B0
+:10700000316CFFFF00003821000050210A000654B7
+:107010003410FFFF27BDFFD8AFB0001030F0FFFFE6
+:10702000AFB10014001039423211FFE000071080A8
+:10703000AFB3001C00B1282330D3FFFFAFB200185C
+:1070400030A5FFFF00809021026030210044202104
+:10705000AFBF00200E0005E03207001F022288218A
+:107060003403FFFF0240202102002821026030216A
+:1070700000003821104300093231FFFF02201021A7
+:107080008FBF00208FB3001C8FB200188FB1001487
+:107090008FB0001003E0000827BD00280E0005E0B7
+:1070A0000000000000408821022010218FBF002036
+:1070B0008FB3001C8FB200188FB100148FB0001076
+:1070C00003E0000827BD0028000424003C03600002
+:1070D000AC603D0810A00002348210063482101605
+:1070E00003E00008AC623D0427BDFFE0AFB0001034
+:1070F000309000FF2E020006AFBF001810400008BD
+:10710000AFB10014001030803C03080024635784A2
+:1071100000C328218CA400000080000800000000AB
+:10712000000020218FBF00188FB100148FB0001015
+:107130000080102103E0000827BD00209791002A5D
+:1071400016200051000020213C020800904200332C
+:107150000A0006BB00000000978D002615A0003134
+:10716000000020210A0006BB2402000897870024A3
+:1071700014E0001A00001821006020212402000100
+:107180001080FFE98FBF0018000429C2004530219C
+:1071900000A6582B1160FFE43C0880003C0720004B
+:1071A000000569C001A76025AD0C00203C038008E4
+:1071B0002402001F2442FFFFAC6000000441FFFDD9
+:1071C0002463000424A5000100A6702B15C0FFF560
+:1071D000000569C00A0006A58FBF00189787001C2C
+:1071E0003C04080024845A58240504000E0006605C
+:1071F00024060001978B002424440001308AFFFFFD
+:107200002569FFFF2D48040000402821150000409B
+:10721000A789002424AC3800000C19C00A0006B964
+:10722000A780001C9787001E3C04080024845AD8BD
+:10723000240504000E00066024060001979900262C
+:10724000244400013098FFFF272FFFFF2F0E04007A
+:107250000040882115C0002CA78F0026A780001EA3
+:107260003A020003262401003084FFFF0E00068D41
+:107270002C4500010011F8C027F00100001021C0CA
+:107280000A0006BB240200089785002E978700227B
+:107290003C04080024845B580E00066024060001AC
+:1072A0009787002A8F89002C2445000130A8FFFF12
+:1072B00024E3FFFF0109302B0040802114C0001897
+:1072C000A783002AA7800022978500300E000F7543
+:1072D00002002021244A05003144FFFF0E00068DE4
+:1072E000240500013C05080094A500320E000F752E
+:1072F00002002021244521003C0208009042003376
+:107300000A0006BB000521C00A0006F3A784001E80
+:1073100024AC3800000C19C00A0006B9A784001C70
+:107320000A00070DA7850022308400FF27BDFFE873
+:107330002C820006AFBF0014AFB000101040001543
+:1073400000A03821000440803C0308002463579CBF
+:10735000010328218CA40000008000080000000028
+:1073600024CC007F000751C2000C59C23170FFFFCE
+:107370002547C40030E5FFFF2784001C02003021B0
+:107380000E0005B52407000197860028020620217B
+:10739000A78400288FBF00148FB0001003E00008FE
+:1073A00027BD00183C0508008CA50030000779C2F5
+:1073B0000E00038125E4DF003045FFFF3C04080098
+:1073C00024845B58240600010E0005B52407000143
+:1073D000978E002A8FBF00148FB0001025CD0001BA
+:1073E00027BD001803E00008A78D002A0007C9C2C6
+:1073F0002738FF00001878C231F0FFFF3C04080076
+:1074000024845AD802002821240600010E0005B564
+:1074100024070001978D0026260E0100000E84002F
+:1074200025AC00013C0B6000A78C0026AD603D0838
+:1074300036040006000030213C0760008CE23D0469
+:10744000305F000617E0FFFD24C9000100061B00A5
+:10745000312600FF006440252CC50004ACE83D0443
+:1074600014A0FFF68FBF00148FB0001003E00008D7
+:1074700027BD0018000751C22549C8002406000195
+:10748000240700013C04080024845A580E0005B566
+:107490003125FFFF978700248FBF00148FB00010A5
+:1074A00024E6000127BD001803E00008A786002499
+:1074B0003C0660183C090800252900FCACC9502C8A
+:1074C0008CC850003C0580003C020002350700805B
+:1074D000ACC750003C04080024841FE03C030800B3
+:1074E00024631F98ACA50008ACA2000C3C01080066
+:1074F000AC2459A43C010800AC2359A803E00008BF
+:107500002402000100A030213C1C0800279C59AC3B
+:107510003C0C04003C0B0002008B3826008C4026FB
+:107520002CE200010007502B2D050001000A4880C5
+:107530003C030800246359A4004520250123182199
+:107540001080000300001021AC660000240200013E
+:1075500003E00008000000003C1C0800279C59AC18
+:107560003C0B04003C0A0002008A3026008B3826BF
+:107570002CC200010006482B2CE5000100094080C8
+:107580003C030800246359A4004520250103182169
+:1075900010800005000010213C0C0800258C1F986D
+:1075A000AC6C00002402000103E0000800000000B1
+:1075B0003C0900023C080400008830260089382677
+:1075C0002CC30001008028212CE400010083102539
+:1075D0001040000B000030213C1C0800279C59ACD7
+:1075E0003C0A80008D4E00082406000101CA68256F
+:1075F000AD4D00088D4C000C01855825AD4B000C9D
+:1076000003E0000800C010213C1C0800279C59AC76
+:107610003C0580008CA6000C0004202724020001F9
+:1076200000C4182403E00008ACA3000C3C020002D4
+:107630001082000B3C0560003C070400108700032B
+:107640000000000003E00008000000008CA908D042
+:10765000240AFFFD012A402403E00008ACA808D05A
+:107660008CA408D02406FFFE0086182403E000083E
+:10767000ACA308D03C05601A34A600108CC300806F
+:1076800027BDFFF88CC50084AFA3000093A40000C1
+:107690002402001010820003AFA5000403E00008DC
+:1076A00027BD000893A7000114E0001497AC000266
+:1076B00097B800023C0F8000330EFFFC01CF682119
+:1076C000ADA50000A3A000003C0660008CC708D058
+:1076D0002408FFFE3C04601A00E82824ACC508D04A
+:1076E0008FA300048FA200003499001027BD00086A
+:1076F000AF22008003E00008AF2300843C0B800031
+:10770000318AFFFC014B48218D2800000A00080C3B
+:10771000AFA8000427BDFFE8AFBF00103C1C080065
+:10772000279C59AC3C0580008CA4000C8CA2000462
+:107730003C0300020044282410A0000A00A31824DF
+:107740003C0604003C0400021460000900A610245A
+:107750001440000F3C0404000000000D3C1C080015
+:10776000279C59AC8FBF001003E0000827BD00180C
+:107770003C0208008C4259A40040F80900000000B7
+:107780003C1C0800279C59AC0A0008358FBF00102C
+:107790003C0208008C4259A80040F8090000000093
+:1077A0000A00083B000000003C0880008D0201B880
+:1077B0000440FFFE35090180AD2400003C031000A9
+:1077C00024040040AD250004A1240008A1260009DE
+:1077D000A527000A03E00008AD0301B83084FFFFCD
+:1077E0000080382130A5FFFF000020210A00084555
+:1077F000240600803087FFFF8CA400002406003898
+:107800000A000845000028218F8300788F860070C9
+:107810001066000B008040213C07080024E75B68ED
+:10782000000328C000A710218C440000246300013D
+:10783000108800053063000F5466FFFA000328C06B
+:1078400003E00008000010213C07080024E75B6CFF
+:1078500000A7302103E000088CC200003C03900028
+:1078600034620001008220253C038000AC640020CB
+:107870008C65002004A0FFFE0000000003E000086B
+:10788000000000003C0280003443000100832025FA
+:1078900003E00008AC44002027BDFFE0AFB10014B6
+:1078A0003091FFFFAFB00010AFBF001812200013DF
+:1078B00000A080218CA20000240400022406020003
+:1078C0001040000F004028210E0007250000000096
+:1078D00000001021AE000000022038218FBF0018E8
+:1078E0008FB100148FB0001000402021000028212B
+:1078F000000030210A00084527BD00208CA20000AE
+:10790000022038218FBF00188FB100148FB00010F3
+:107910000040202100002821000030210A000845F5
+:1079200027BD002000A010213087FFFF8CA5000498
+:107930008C4400000A000845240600068F83FD9C45
+:1079400027BDFFE8AFBF0014AFB00010906700087C
+:10795000008010210080282130E600400000202116
+:1079600010C000088C5000000E0000BD0200202155
+:10797000020020218FBF00148FB000100A000548BC
+:1079800027BD00180E0008A4000000000E0000BD76
+:1079900002002021020020218FBF00148FB00010B0
+:1079A0000A00054827BD001827BDFFE0AFB0001052
+:1079B0008F90FD9CAFBF001CAFB20018AFB1001498
+:1079C00092060001008088210E00087230D2000467
+:1079D00092040005001129C2A6050000348300406E
+:1079E000A20300050E00087C022020210E00054A9B
+:1079F0000220202124020001AE02000C02202821D6
+:107A0000A602001024040002A602001224060200AE
+:107A1000A60200140E000725A60200161640000F4D
+:107A20008FBF001C978C00743C0B08008D6B007896
+:107A30002588FFFF3109FFFF256A0001012A382B45
+:107A400010E00006A78800743C0F6006240E0016A4
+:107A500035ED0010ADAE00508FBF001C8FB2001886
+:107A60008FB100148FB0001003E0000827BD002084
+:107A700027BDFFE0AFB10014AFBF0018AFB00010DA
+:107A80001080000400A088212402008010820007DA
+:107A9000000000000000000D8FBF00188FB100141F
+:107AA0008FB0001003E0000827BD00200E00087210
+:107AB00000A020218F86FD9C0220202190C500057A
+:107AC0000E00087C30B000FF2403003E1603FFF1D7
+:107AD0003C0680008CC401780480FFFE34C801405D
+:107AE000240900073C071000AD11000002202021EE
+:107AF000A10900048FBF00188FB100148FB00010CF
+:107B0000ACC701780A0008C527BD002027BDFFE0EB
+:107B1000AFB00010AFBF0018AFB100143C10800030
+:107B20008E110020000000000E00054AAE04002067
+:107B3000AE1100208FBF00188FB100148FB000105D
+:107B400003E0000827BD00203084FFFF00803821BB
+:107B50002406003500A020210A0008450000282145
+:107B60003084FFFF008038212406003600A0202149
+:107B70000A0008450000282127BDFFD0AFB500242A
+:107B80003095FFFFAFB60028AFB40020AFBF002C88
+:107B9000AFB3001CAFB20018AFB10014AFB000100B
+:107BA00030B6FFFF12A000270000A0218F920058DE
+:107BB0008E4300003C0680002402004000033E0289
+:107BC00000032C0230E4007F006698241482001D1C
+:107BD00030A500FF8F8300682C68000A1100001098
+:107BE0008F8D0044000358803C0C0800258C57B84A
+:107BF000016C50218D4900000120000800000000A8
+:107C000002D4302130C5FFFF0E0008522404008446
+:107C1000166000028F920058AF8000688F8D00447C
+:107C20002659002026980001032090213314FFFFDD
+:107C300015A00004AF9900580295202B1480FFDC9A
+:107C400000000000028010218FBF002C8FB600289A
+:107C50008FB500248FB400208FB3001C8FB20018A2
+:107C60008FB100148FB0001003E0000827BD003072
+:107C70002407003414A70149000000009247000EB9
+:107C80008F9FFDA08F90FD9C24181600A3E700197C
+:107C90009242000D3C0880003C07800CA3E20018D3
+:107CA000964A00123C0D60003C117FFFA60A005C62
+:107CB000964400103623FFFF240200053099FFFF91
+:107CC000AE1900548E46001CAD1800288CEF000041
+:107CD0008DAE444801E6482601C93021AE06003881
+:107CE0008E05003824CB00013C0E7F00AE05003C21
+:107CF0008E0C003CAFEC0004AE0B00208E13002075
+:107D0000AE13001CA3E0001BAE03002CA3E2001284
+:107D10008E4A001424130050AE0A00348E0400343E
+:107D2000AFE400148E590018AE1900489258000CA8
+:107D3000A218004E920D000835AF0020A20F0008D7
+:107D40008E090018012E282434AC4000AE0C001817
+:107D5000920B0000317200FF1253027F2403FF8058
+:107D60003C04080024845BE80E0008AA0000000020
+:107D70003C1108008E315BE80E00087202202021C1
+:107D80002405000424080001A2050025022020216A
+:107D90000E00087CA20800053C0580008CB001782C
+:107DA0000600FFFE8F92005834AE0140240F0002FF
+:107DB0003C091000ADD10000A1CF0004ACA90178AE
+:107DC0000A000962AF8000682CAD003751A0FF9413
+:107DD0008F8D0044000580803C110800263157E05B
+:107DE000021178218DEE000001C0000800000000A3
+:107DF0002411000414B1008C3C0780003C080800EA
+:107E00008D085BE88F86FD9CACE800208E4500085D
+:107E10008F99FDA0240D0050ACC500308E4C000899
+:107E2000ACCC00508E4B000CACCB00348E43001019
+:107E3000ACC300388E4A0010ACCA00548E42001405
+:107E4000ACC2003C8E5F0018AF3F00048E50001C97
+:107E5000ACD0002090C40000309800FF130D024AFF
+:107E6000000000008CC400348CD00030009030231F
+:107E700004C000F12404008C126000EE2402000310
+:107E80000A000962AF8200682419000514B900666F
+:107E90003C0580003C0808008D085BE88F86FD9C4F
+:107EA000ACA800208E4C00048F8AFDA0240720007F
+:107EB000ACCC001C924B000824120008A14B001906
+:107EC0008F82005890430009A14300188F85005805
+:107ED00090BF000A33E400FF1092001028890009C7
+:107EE000152000BA240E0002240D0020108D000B76
+:107EF000340780002898002117000008240740005C
+:107F000024100040109000053C0700012419008057
+:107F1000109900023C070002240740008CC20018A0
+:107F20003C03FF00004350240147F825ACDF001854
+:107F300090B2000BA0D200278F8300589464000CED
+:107F4000108001FE000000009467000C3C1F8000C0
+:107F50002405FFBFA4C7005C9063000E2407000443
+:107F6000A0C300088F820058904A000FA0CA0009E1
+:107F70008F8900588D3200108FE400740244C823AA
+:107F8000ACD900588D300014ACD0002C95380018B6
+:107F9000330DFFFFACCD00409531001A322FFFFFAB
+:107FA000ACCF00448D2E001CACCE00489128000EB2
+:107FB000A0C8000890CC000801855824126001B6C2
+:107FC000A0CB00088F9200580A000962AF870068B2
+:107FD0002406000614A600143C0E80003C0F080086
+:107FE0008DEF5BE88F85FD98ADCF00208E4900189E
+:107FF0008F86FD9C8F8BFDA0ACA900008CC800383B
+:1080000024040005ACA800048CCC003C1260008164
+:10801000AD6C00000A000962AF84006824110007FB
+:1080200010B1004B240400063C05080024A55BE8C1
+:108030000E000881240400818F9200580013102B39
+:108040000A000962AF820068241F002314BFFFF6F4
+:108050003C0C80003C0508008CA55BE88F8BFDA0E4
+:10806000AD8500208F91FD9C8E4600042564002084
+:1080700026450014AE260028240600030E000F81BA
+:10808000257000308F87005802002021240600034D
+:108090000E000F8124E500083C04080024845BE8FE
+:1080A0000E0008AA0000000092230000240A0050DD
+:1080B000306200FF544AFFE18F9200580E000F6CAF
+:1080C000000000000A000A6A8F920058240800335A
+:1080D00014A800323C0380003C1108008E315BE89C
+:1080E0008F8FFDA0AC7100208E420008240D002867
+:1080F0008F89FD9CADE200308E4A000C24060009F9
+:10810000ADEA00348E5F0010ADFF00388E440014DD
+:10811000ADE400208E590018ADF900248E58001CE3
+:10812000ADF80028A1ED00118E4E00041260003160
+:10813000AD2E00288F9200580A000962AF860068B1
+:10814000240D002214ADFFB8000000002404000735
+:108150003C1008008E105BE83C188000AF10002037
+:108160005660FEAEAF8400683C04080024845BE8DF
+:108170000E0008AA241300508F84FD9C90920000EA
+:10818000325900FF1333014B000000008F9200585A
+:10819000000020210A000962AF8400683C05080045
+:1081A00024A55BE80E000858240400810A000A6A2E
+:1081B0008F92005802D498213265FFFF0E000852BA
+:1081C000240400840A0009628F920058108EFF5325
+:1081D000240704002887000310E00179241100041B
+:1081E000240F0001548FFF4D240740000A000A228B
+:1081F000240701003C05080024A55BE80E0008A444
+:10820000240400828F920058000030210A00096285
+:10821000AF8600683C04080024845BE88CC2003808
+:108220000E0008AA8CC3003C8F9200580A000AC0B6
+:1082300000002021240400823C05080024A55BE8FE
+:108240000E0008A4000000008F92005800001021CA
+:108250000A000962AF8200688E5000048F91FD9C75
+:108260003C078000ACF00020922C00050200282181
+:10827000318B0002156001562404008A8F92FDA004
+:108280002404008D9245001B30A6002014C001502C
+:1082900002002821922E00092408001231C900FF93
+:1082A0001128014B240400810E00087202002021D5
+:1082B0009258001B240F000402002021370D0042B9
+:1082C000A24D001B0E00087CA22F00253C0580005B
+:1082D0008CA401780480FFFE34B90140241F000201
+:1082E000AF300000A33F00048F9200583C101000F4
+:1082F000ACB001780A000A6B0013102B8E500004FA
+:108300008F91FD9C3C038000AC700020922A0005F8
+:108310000200282131420002144000172404008A80
+:10832000922C00092412000402002821318B00FF46
+:1083300011720011240400810E0008720200202135
+:108340008F89FDA0240800122405FFFE912F001B39
+:108350000200202135EE0020A12E001BA2280009DA
+:108360009226000500C538240E00087CA2270005CF
+:1083700002002821000020210E0009330000000027
+:108380000A000A6A8F9200588E4C00043C07800055
+:108390003C10080026105BE8ACEC00203C01080013
+:1083A000AC2C5BE8924B0003317100041220013BBE
+:1083B0008F84FD9C24020006A0820009924F001BBE
+:1083C000240EFFC031E9003F012E4025A08800089F
+:1083D0009245000330A6000114C0013200000000E5
+:1083E0008E420008AE0200083C0208008C425BF09E
+:1083F000104001318F90FDA0000219C28F8DFD9CAD
+:10840000A603000C8E4A000C24180001240400145A
+:10841000AE0A002C8E420010AE02001C965F0016C1
+:10842000A61F003C96590014A619003EADB8000CDA
+:10843000A5B80010A5B80012A5B80014A5B800167C
+:1084400012600144A2040011925100033232000272
+:108450002E5300018F920058266200080A0009621C
+:10846000AF8200688E4400043C1980003C068008FE
+:10847000AF2400208E45000890D80000240D005045
+:10848000331100FF122D009C2407008824060009E8
+:108490000E000845000000000A000A6A8F9200588A
+:1084A0008E5000043C0980003C118008AD30002053
+:1084B0009228000024050050310400FF10850110AF
+:1084C0002407008802002021000028210E00084512
+:1084D0002406000E922D00002418FF80020028219F
+:1084E00001B8802524040004240600300E0007256E
+:1084F000A23000000A000A6A8F9200588E500004D1
+:108500008F91FDA03C028000AC500020923F001BE8
+:1085100033F900101320006C240700810200202191
+:10852000000028212406001F0E000845000000005E
+:108530000A000A6A8F9200588E44001C0E00085DE3
+:1085400000000000104000E3004048218F880058E0
+:1085500024070089012020218D05001C240600012C
+:108560000E000845000000000A000A6A8F920058B9
+:10857000964900023C10080026105BE831280004F0
+:10858000110000973C0460008E4E001C3C0F8000E0
+:10859000ADEE00203C010800AC2E5BE896470002DF
+:1085A00030E40001148000E6000000008E42000468
+:1085B000AE0200083C1008008E105BF0120000ECC8
+:1085C0003C0F80008F92FD9C241000018E4E0018FD
+:1085D0008F8DFDA08F9FFD9801CF4825AE490018D3
+:1085E000A2400005AE50000C3C0808008D085BF06E
+:1085F0008F840058A6500010000839C2A6500012FF
+:10860000A6500014A6500016A5A7000C8C8C0008DC
+:108610008F8B00588F8A0058ADAC002C8D63000CF6
+:1086200024070002ADA3001C91460010A1A6001172
+:108630008F82005890450011A3E500088F990058DB
+:1086400093380012A258004E8F910058922F0013B9
+:10865000A1AF00128F920058964E0014A5AE003CB8
+:1086600096490016A5A9003E8E480018ADA8001432
+:108670005660FD6AAF8700683C05080024A55BE8EA
+:108680000E000881000020218F9200580000382140
+:108690000A000962AF8700683C05080024A55BE872
+:1086A0000E0008A4240400828F9200580A000A4D8C
+:1086B000000038210E000F6C000000008F9200585F
+:1086C0000A000AC0000020210E00087202002021CA
+:1086D0009223001B02002021346A00100E00087C47
+:1086E000A22A001B000038210200202100002821BE
+:1086F0000A000BA52406001F9242000C305F000107
+:1087000013E0000300000000964A000EA4CA002CEB
+:10871000924B000C316300025060000600003821CB
+:108720008E470014964C0012ACC7001CA4CC001A53
+:10873000000038210A000B7F240600093C050800D0
+:1087400024A55BE80E0008A42404008B8F92005837
+:108750000A000A4D0013382B3C0C08008D8C5BE896
+:1087600024DFFFFE25930100326B007F016790211B
+:1087700002638824AD110028AE4600E0AE4000E45C
+:108780000A0009B3AE5F001CACC000543C0D0800E9
+:108790008DAD5BE83C18800C37090100ACED00287A
+:1087A0008E510014AD3100E08E4F0014AD2F00E467
+:1087B0008E4E001025C7FFFE0A0009F4AD27001CED
+:1087C0005491FDD6240740000A000A222407100015
+:1087D0000E00092D000000000A000A6A8F9200585E
+:1087E0008C83442C3C12DEAD3651BEEF3C010800B8
+:1087F000AC205BE810710062000000003C196C6264
+:1088000037387970147800082404000297850074C2
+:108810009782006C2404009200A2F82B13E0001948
+:1088200002002821240400020E00069524050200FF
+:108830003C068000ACC200203C010800AC225BE892
+:108840001040000D8F8C0058240A002824040003D7
+:10885000918B0010316300FF546A00012404000171
+:108860000E0000810000000010400004240400837A
+:108870000A000BC28F920058240400833C050800B4
+:1088800024A55BE80E000881000000008F920058CC
+:108890000013382B0A000962AF8700680A000B49F1
+:1088A000240200128E4400080E00085D0000000043
+:1088B0000A000B55AE0200083C05080024A55BE841
+:1088C0000E000858240400878F9200580A000B728B
+:1088D0000013102B240400040E000695240500301C
+:1088E0001440002A004048218F8800582407008344
+:1088F000012020218D05001C0A000BB32406000175
+:108900008F8300788F8600701066FEEE000038219D
+:108910003C07080024E75B6C000320C00087282187
+:108920008CAE000011D0005D246F000131E3000F18
+:108930005466FFFA000320C00A000B8C00003821A7
+:108940008E4400040E00085D000000000A000BC801
+:10895000AE0200083C05080024A55BE80E0008A450
+:10896000240400828F9200580A000B72000010212C
+:108970003C05080024A55BE80A000C7C2404008761
+:108980008C83442C0A000C5B3C196C628F88005865
+:108990003C0780083C0C8000240B0050240A000196
+:1089A000AD820020A0EB0000A0EA000191030004CA
+:1089B000A0E3001891040005A0E400199106000648
+:1089C0003C04080024845B6CA0E6001A91020007B6
+:1089D0003C06080024C65B68A0E2001B9105000865
+:1089E000A0E5001C911F0009A0FF001D9119000ABD
+:1089F000A0F9001E9118000BA0F8001F9112000CA6
+:108A0000A0F200209111000DA0F100219110000EA4
+:108A1000A0F00022910F000FA0EF0023910E001094
+:108A2000A0EE0024910D0011A0ED0025950C00147E
+:108A3000A4EC0028950B00168F8A00708F920078A6
+:108A4000A4EB002A95030018000A10C02545000178
+:108A5000A4E3002C8D1F001C0044C0210046C82147
+:108A600030A5000FAF3F0000AF09000010B20006B4
+:108A7000AF850070000038218D05001C01202021E9
+:108A80000A000BB32406000124AD000131A7000F3A
+:108A9000AF8700780A000CF9000038213C06080076
+:108AA00024C65B680086902100003821ACA000003D
+:108AB0000A000B8CAE4000003C0482013C036000C5
+:108AC00034820E02AC603D68AF80009803E000087D
+:108AD000AC623D6C27BDFFE8AFB000103090FFFFE7
+:108AE000001018422C620041AFBF00141440000275
+:108AF00024040080240300403C010800AC300060E6
+:108B00003C010800AC2300640E000F7500602821B2
+:108B1000244802BF2409FF8001092824001039805D
+:108B2000001030408FBF00148FB0001000A720212C
+:108B300000861821AF8300803C010800AC25005856
+:108B40003C010800AC24005C03E0000827BD0018CD
+:108B5000308300FF30C6FFFF30E400FF3C08800098
+:108B60008D0201B80440FFFE000354000144382583
+:108B70003C09600000E920253C031000AD050180A0
+:108B8000AD060184AD04018803E00008AD0301B81F
+:108B90008F8500583C0A6012354800108CAC0004E8
+:108BA0003C0D600E35A60010318B00062D690001CA
+:108BB000AD0900C48CA70004ACC731808CA20008AA
+:108BC00094A40002ACC231848CA3001C0460000396
+:108BD000A784009003E00008000000008CAF00189C
+:108BE000ACCF31D08CAE001C03E00008ACCE31D449
+:108BF0008F8500588F87FF288F86FF308CAE00044A
+:108C00003C0F601235E80010ACEE00788CAD000827
+:108C1000ACED007C8CAC0010ACCC004C8CAB000CF0
+:108C2000ACCB004894CA00543C0208008C4200447B
+:108C300025490001A4C9005494C400543083FFFFA7
+:108C400010620017000000003C0208008C42004047
+:108C5000A4C200528CA30018ACE300308CA2001414
+:108C6000ACE2002C8CB90018ACF900388CB80014B8
+:108C700024050001ACF800348D0600BC50C5001975
+:108C80008D0200B48D0200B8A4E2004894E40048CC
+:108C9000A4E4004A94E800EA03E000083102FFFF80
+:108CA0003C0208008C420024A4C00054A4C200521C
+:108CB0008CA30018ACE300308CA20014ACE2002CB2
+:108CC0008CB90018ACF900388CB8001424050001E8
+:108CD000ACF800348D0600BC54C5FFEB8D0200B823
+:108CE0008D0200B4A4E2004894E40048A4E4004AE1
+:108CF00094E800EA03E000083102FFFF8F86005885
+:108D00003C0480008CC900088CC80008000929C0F8
+:108D1000000839C0AC87002090C30007306200040F
+:108D20001040003EAF85009490CB0007316A0008E8
+:108D30001140003D8F87FF2C8CCD000C8CCE001491
+:108D400001AE602B11800036000000008CC2000CC8
+:108D5000ACE200708CCB00188F85FF288F88FF3025
+:108D6000ACEB00748CCA00102402FFF8ACAA00D847
+:108D70008CC9000CAD0900608CC4001CACA400D0F0
+:108D800090E3007C0062C824A0F9007C90D8000722
+:108D9000330F000811E000040000000090ED007C9B
+:108DA00035AC0001A0EC007C90CF000731EE000153
+:108DB00011C000060000000090E3007C241800347D
+:108DC00034790002A0F9007CACB800DC90C2000746
+:108DD0003046000210C000040000000090E8007C53
+:108DE00035040004A0E4007C90ED007D3C0B600E97
+:108DF000356A001031AC003FA0EC007D8D4931D4C4
+:108E00003127000110E00002240E0001A0AE00098D
+:108E100094AF00EA03E0000831E2FFFF8F87FF2CE8
+:108E20000A000DAF8CC200140A000DB0ACE0007057
+:108E30008F8C005827BDFFD8AFB3001CAFB200180D
+:108E4000AFB00010AFBF0020AFB10014918F00157C
+:108E50003C13600E3673001031EB000FA38B009CA7
+:108E60008D8F00048D8B0008959F0012959900103E
+:108E70009584001A9598001E958E001C33EDFFFF17
+:108E8000332AFFFF3089FFFF3308FFFF31C7FFFFA1
+:108E90003C010800AC2D00243C010800AC29004432
+:108EA0003C010800AC2A0040AE683178AE67317CE6
+:108EB00091850015959100163C12601236520010F3
+:108EC00030A200FF3230FFFFAE623188AE5000B4F6
+:108ED00091830014959F0018240600010066C804C1
+:108EE00033F8FFFFAE5900B8AE5800BC918E0014A5
+:108EF000AF8F00843C08600631CD00FFAE4D00C04E
+:108F0000918A00159584000E3C07600A314900FFE4
+:108F1000AF8B00883084FFFFAE4900C835110010C8
+:108F20000E000D1034F004103C0208008C4200606A
+:108F30003C0308008C6300643C0608008CC60058A3
+:108F40003C0508008CA5005C8F8400808FBF00204A
+:108F5000AE23004CAE65319CAE030054AE4500DC40
+:108F6000AE6231A0AE6331A4AE663198AE22004845
+:108F70008FB3001CAE0200508FB10014AE4200E06F
+:108F8000AE4300E4AE4600D88FB000108FB2001898
+:108F90000A00057D27BD0028978500929783007CF5
+:108FA00027BDFFE8AFB0001000A3102BAFBF001427
+:108FB000240400058F900058104000552409000239
+:108FC0000E0006958F850080AF8200942404000374
+:108FD0001040004F240900023C0680000E00008172
+:108FE000ACC2002024070001240820001040004DDE
+:108FF00024040005978E00928F8AFF2C24090050CC
+:1090000025C50001A7850092A14900003C0D08007C
+:109010008DAD0064240380008F84FF28000D66005E
+:10902000AD4C0018A5400006954B000A8F85FF3017
+:109030002402FF8001633024A546000A915F000AE4
+:109040000000482103E2C825A159000AA0A0000899
+:10905000A140004CA08000D5961800029783009094
+:109060003C020004A49800EA960F00022418FFBFF7
+:1090700025EE2401A48E00BE8E0D0004ACAD00448C
+:109080008E0C0008ACAC0040A4A00050A4A000547A
+:109090008E0B000C240C0030AC8B00288E060010C8
+:1090A000AC860024A480003EA487004EA487005014
+:1090B000A483003CAD420074AC8800D8ACA800602A
+:1090C000A08700FC909F00D433F9007FA09900D4C2
+:1090D000909000D402187824A08F00D4914E007C88
+:1090E00035CD0001A14D007C938B009CAD480070F4
+:1090F000AC8C00DCA08B00D68F8800888F87008422
+:10910000AC8800C4AC8700C8A5400078A540007AB0
+:109110008FBF00148FB000100120102103E0000861
+:1091200027BD00188F8500940E0007258F860080CC
+:109130000A000E9F2409000227BDFFE0AFB0001017
+:109140008F900058AFB10014AFBF00188E09000413
+:109150000E00054A000921C08E0800048F84FF28F4
+:109160008F82FF30000839C03C068000ACC7002069
+:10917000948500EA904300131460001C30B1FFFF97
+:109180008F8CFF2C918B0008316A00401540000B3A
+:10919000000000008E0D0004022030218FBF001857
+:1091A0008FB100148FB00010240400220000382179
+:1091B000000D29C00A000D2F27BD00200E000098C9
+:1091C000000000008E0D0004022030218FBF001827
+:1091D0008FB100148FB00010240400220000382149
+:1091E000000D29C00A000D2F27BD00200E000090A1
+:1091F000000000008E0D0004022030218FBF0018F7
+:109200008FB100148FB00010240400220000382118
+:10921000000D29C00A000D2F27BD002027BDFFE04B
+:10922000AFB200183092FFFFAFB00010AFBF001C0C
+:10923000AFB100141240001E000080218F8600583C
+:109240008CC500002403000600053F02000514023F
+:1092500030E4000714830016304500FF2CA80006F8
+:1092600011000040000558803C0C0800258C58BCBB
+:10927000016C50218D490000012000080000000011
+:109280008F8E0098240D000111CD005024020002A1
+:10929000AF820098260900013130FFFF24C800206A
+:1092A0000212202B010030211480FFE5AF88005806
+:1092B000020010218FBF001C8FB200188FB1001464
+:1092C0008FB0001003E0000827BD00209387007EC8
+:1092D00054E00034000030210E000DE700000000D3
+:1092E0008F8600580A000EFF240200018F87009825
+:1092F0002405000210E50031240400130000282199
+:1093000000003021240700010E000D2F0000000096
+:109310000A000F008F8600588F83009824020002F5
+:109320001462FFF6240400120E000D9A00000000E3
+:109330008F85009400403021240400120E000D2F70
+:10934000000038210A000F008F8600588F83009894
+:109350002411000310710029241F0002107FFFCE8A
+:1093600026090001240400100000282100003021FB
+:109370000A000F1D240700018F91009824060002A7
+:109380001626FFF9240400100E000E410000000014
+:10939000144000238F9800588F8600580A000EFF53
+:1093A00024020003240400140E000D2F00002821C5
+:1093B0008F8600580A000EFF240200020E000EA93C
+:1093C000000000000A000F008F8600580E000D3FBD
+:1093D00000000000241900022404001400002821C9
+:1093E0000000302100003821AF9900980E000D2FA9
+:1093F000000000000A000F008F8600580E000D5775
+:10940000000000008F8500942419000200403021E4
+:1094100024040010000038210A000F56AF9900986C
+:109420000040382124040010970F0002000028217A
+:109430000E000D2F31E6FFFF8F8600580A000F0047
+:10944000AF9100988F84FF2C3C077FFF34E6FFFF2D
+:109450008C8500182402000100A61824AC83001893
+:1094600003E00008A08200053084FFFF30A5FFFF65
+:109470001080000700001821308200011040000217
+:1094800000042042006518211480FFFB00052840DD
+:1094900003E000080060102110C000070000000079
+:1094A0008CA2000024C6FFFF24A50004AC820000AB
+:1094B00014C0FFFB2484000403E000080000000047
+:1094C00010A0000824A3FFFFAC86000000000000ED
+:1094D000000000002402FFFF2463FFFF1462FFFA74
+:1094E0002484000403E0000800000000000411C010
+:1094F00003E000082442024027BDFFE8AFB000109F
+:1095000000808021AFBF00140E000F9600A0202124
+:1095100000504821240AFF808FBF00148FB0001034
+:10952000012A30243127007F3C08800A3C042100B6
+:1095300000E8102100C428253C03800027BD001846
+:10954000AC650024AF820038AC400000AC6500245C
+:1095500003E00008AC4000403C0D08008DAD005811
+:1095600000056180240AFF8001A45821016C482174
+:10957000012A30243127007F3C08800C3C04210064
+:1095800000E8102100C428253C038000AC650028B9
+:10959000AF82003403E00008AC40002430A5FFFF98
+:1095A0003C0680008CC201B80440FFFE3C086015F8
+:1095B00000A838253C031000ACC40180ACC0018475
+:1095C000ACC7018803E00008ACC301B83C0D08003B
+:1095D0008DAD005800056180240AFF8001A4582148
+:1095E000016C4021010A4824000931403107007F05
+:1095F00000C728253C04200000A418253C02800058
+:10960000AC43083003E00008AF80003427BDFFE81A
+:10961000AFB0001000808021AFBF00140E000F9685
+:1096200000A0202100504821240BFF80012B502452
+:10963000000A39403128007F3C0620008FBF00140B
+:109640008FB0001000E8282534C2000100A21825C0
+:109650003C04800027BD0018AC83083003E00008FC
+:10966000AF8000383C0580088CA700603C0680086D
+:109670000087102B144000112C8340008CA8006040
+:109680002D0340001060000F240340008CC90060CF
+:109690000089282B14A00002008018218CC30060D0
+:1096A00000035A42000B30803C0A0800254A59202A
+:1096B00000CA202103E000088C8200001460FFF340
+:1096C0002403400000035A42000B30803C0A08008B
+:1096D000254A592000CA202103E000088C8200009E
+:1096E0003C05800890A60008938400AB24C20001CA
+:1096F000304200FF3043007F1064000C0002382726
+:10970000A0A200083C0480008C85017804A0FFFE24
+:109710008F8A00A0240900023C081000AC8A014096
+:10972000A089014403E00008AC8801780A00101BFE
+:1097300030E2008027BDFFD8AFB200188F9200A49E
+:10974000AFBF0020AFB3001CAFB00010AFB100142A
+:109750008F9300348E5900283C1000803C0EFFEFA0
+:10976000AE7900008E580024A260000A35CDFFFFBC
+:10977000AE7800049251002C3C0BFF9F356AFFFF2E
+:10978000A271000C8E6F000C3C080040A271000B0F
+:1097900001F06025018D4824012A382400E8302595
+:1097A000AE66000C8E450004AE6000183C0400FF5D
+:1097B000AE6500148E43002C3482FFFFA6600008C3
+:1097C0000062F824AE7F00108E5900088F9000A030
+:1097D000964E0012AE7900208E51000C31D83FFF1A
+:1097E00000187980AE7100248E4D001401F06021C4
+:1097F00031CB0001AE6D00288E4A0018000C41C22A
+:10980000000B4B80AE6A002C8E46001C01093821EB
+:10981000A667001CAE660030964500028E4400200C
+:10982000A665001EAE64003492430033306200042B
+:1098300054400006924700003C0280083443010077
+:109840008C7F00D0AE7F0030924700008F860038BA
+:10985000A0C700309245003330A4000250800007BA
+:10986000925100018F880038240BFF80910A00304C
+:10987000014B4825A1090030925100018F9000381A
+:10988000240CFFBF2404FFDFA21100318F8D0038AC
+:109890003C1880083711008091AF003C31EE007F0A
+:1098A000A1AE003C8F890038912B003C016C502404
+:1098B000A12A003C8F9F00388E68001493E6003C7C
+:1098C0002D0700010007114000C4282400A218251C
+:1098D000A3E3003C8F87003896590012A4F90032A8
+:1098E0008E450004922E007C30B0000300107823D7
+:1098F00031ED000300AD102131CC000215800002D3
+:1099000024460034244600303C0280083443008062
+:10991000907F007C00BFC824333800041700000289
+:1099200024C2000400C010218F98003824190002BE
+:10993000ACE20034A3190000924F003F8F8E003834
+:109940003C0C8008358B0080A1CF00018F9100383E
+:10995000924D003F8E440004A62D0002956A005CE3
+:109960000E000FF43150FFFF00024B800209382532
+:109970003C08420000E82825AE2500048E4400384B
+:109980008F850038ACA400188E460034ACA6001CAD
+:10999000ACA0000CACA00010A4A00014A4A0001661
+:1099A000A4A00020A4A00022ACA000248E62001479
+:1099B00050400001240200018FBF00208FB3001C23
+:1099C0008FB200188FB100148FB00010ACA2000845
+:1099D0000A00101327BD002827BDFFC83C058008DA
+:1099E00034A40080AFBF0034AFBE0030AFB7002C4E
+:1099F000AFB60028AFB50024AFB40020AFB3001C51
+:109A0000AFB20018AFB10014AFB00010948300786B
+:109A10009482007A104300512405FFFF0080F0215A
+:109A20000A0011230080B821108B004D8FBF003435
+:109A30008F8600A03C1808008F18005C2411FF805E
+:109A40003C1680000306782101F18024AED0002C62
+:109A500096EE007A31EC007F3C0D800E31CB7FFF1B
+:109A6000018D5021000B4840012AA82196A4000036
+:109A70003C0808008D0800582405FF8030953FFF02
+:109A800001061821001539800067C8210325F82434
+:109A90003C02010003E290253338007F3C11800C2A
+:109AA000AED20028031190219250000D320F000415
+:109AB00011E0003702E0982196E3007A96E8007AF8
+:109AC00096E5007A2404800031077FFF24E300013B
+:109AD00030627FFF00A4F82403E2C825A6F9007ACB
+:109AE00096E6007A3C1408008E94006030D67FFF22
+:109AF00012D400C1000000008E5800188F8400A00E
+:109B000002A028212713FFFF0E000FCEAE53002C1A
+:109B100097D5007897D4007A12950010000028217C
+:109B20003C098008352401003C0A8008914800085F
+:109B3000908700D53114007F30E400FF0284302B81
+:109B400014C0FFB9268B0001938E00AB268C000158
+:109B5000008E682115ACFFB78F8600A08FBF003440
+:109B60008FBE00308FB7002C8FB600288FB5002431
+:109B70008FB400208FB3001C8FB200188FB1001477
+:109B80008FB0001000A0102103E0000827BD0038AE
+:109B900000C020210E000F99028028218E4B00105A
+:109BA0008E4C00308F84003824090002016C502351
+:109BB000AE4A0010A089000096E3005C8E4400309D
+:109BC0008F9100380E000FF43070FFFF00024380C9
+:109BD000020838253C02420000E22825AE25000498
+:109BE0008E5F00048F8A00388E590000240B000815
+:109BF000AD5F001CAD590018AD40000CAD40001029
+:109C00009246000A240400052408C00030D000FF5A
+:109C1000A550001496580008A55800169251000A45
+:109C20003C188008322F00FFA54F0020964E0008F8
+:109C300037110100A54E0022AD400024924D000BCB
+:109C400031AC00FFA54C0002A14B00018E49003051
+:109C50008F830038240BFFBFAC690008A06400307C
+:109C60008F9000382403FFDF9607003200E8282495
+:109C700000B51025A6020032921F003233F9003FD2
+:109C800037260040A20600328F8C0038AD800034A9
+:109C90008E2F00D0AD8F0038918E003C3C0F7FFF9F
+:109CA00031CD007FA18D003C8F84003835EEFFFF61
+:109CB000908A003C014B4824A089003C8F850038E5
+:109CC00090A8003C01033824A0A7003C8E42003439
+:109CD0008F9100383C038008AE2200408E59002C42
+:109CE0008E5F0030033F3023AE26004492300048A0
+:109CF0003218007FA23800488F8800388E4D00301F
+:109D00008D0C004801AE582401965024014B482583
+:109D1000AD0900489244000AA104004C964700088F
+:109D20008F850038A4A7004E8E5000308E4400303E
+:109D30000E0003818C65006092F9007C0002F940FE
+:109D4000004028210002110003E2302133360002D6
+:109D500012C00003020680210005B0800216802197
+:109D6000926D007C31B30004126000020005708027
+:109D7000020E80218E4B00308F8800382405800031
+:109D8000316A0003000A4823312400030204182129
+:109D9000AD03003496E4007A96F0007A96F1007AEA
+:109DA00032027FFF2447000130FF7FFF0225C824D5
+:109DB000033F3025A6E6007A96F8007A3C120800A8
+:109DC0008E520060330F7FFF11F200180000000078
+:109DD0008F8400A00E000FCE02A028218F8400A047
+:109DE0000E000FDE028028210E001013000000007C
+:109DF0000A00111F0000000096F1007A022480245E
+:109E0000A6F0007A92EF007A92EB007A31EE00FF32
+:109E1000000E69C2000D6027000C51C03169007F3F
+:109E2000012A20250A001119A2E4007A96E6007A98
+:109E300000C5C024A6F8007A92EF007A92F3007A67
+:109E400031F200FF001271C2000E6827000DB1C090
+:109E5000326C007F01962825A2E5007A0A0011D015
+:109E60008F8400A03C0380003084FFFF30A5FFFFFB
+:109E7000AC640018AC65001C03E000088C620014A0
+:109E800027BDFFA03C068008AFBF005CAFBE0058F6
+:109E9000AFB70054AFB60050AFB5004CAFB40048F8
+:109EA000AFB30044AFB20040AFB1003CAFB0003838
+:109EB00034C80100910500D590C700083084FFFF29
+:109EC00030A500FF30E2007F0045182AAFA4001043
+:109ED000A7A00018A7A0002610600055AFA000148E
+:109EE00090CA00083149007F00A9302324D3FFFF26
+:109EF0000013802B8FB400100014902B02128824C2
+:109F0000522000888FB300143C03800894790052DB
+:109F1000947E00508FB60010033EC0230018BC0092
+:109F2000001714030016FC0002C2A82A16A00002A3
+:109F3000001F2C030040282100133C0000072403CD
+:109F400000A4102A5440000100A020212885000907
+:109F500014A000020080A021241400083C0C8008FA
+:109F60008D860048001459808D88004C3C03800089
+:109F70003169FFFF3C0A0010012A202534710400DA
+:109F8000AC660038AF9100A4AC68003CAC64003013
+:109F900000000000000000000000000000000000C1
+:109FA00000000000000000000000000000000000B1
+:109FB0008C6E000031CD002011A0FFFD0014782A26
+:109FC00001F01024104000390000A8213C16800840
+:109FD00092D700083C1280008E44010032F6007FC8
+:109FE0000E000F9902C028218E3900108E44010006
+:109FF0000000902133373FFF0E000FB102E028210F
+:10A00000923800003302003F2C500008520000102C
+:10A0100000008821000210803C030800246358E4FB
+:10A020000043F8218FFE000003C00008000000007C
+:10A0300090CF0008938C00AB31EE007F00AE682318
+:10A04000018D58210A0012172573FFFF0000882197
+:10A050003C1E80008FC401000E000FCE02E02821BC
+:10A060008FC401000E000FDE02C028211220000F55
+:10A070000013802B8F8B00A426A400010004AC00E9
+:10A08000027298230015AC032578004002B4B02A70
+:10A090000013802B241700010300882102D0102414
+:10A0A000AF9800A41440FFC9AFB700143C07800864
+:10A0B00094E200508FAE00103C05800002A288217F
+:10A0C0003C060020A4F10050ACA6003094F40050EF
+:10A0D00094EF005201D51823306CFFFF11F4001EDD
+:10A0E000AFAC00108CEF004C001561808CF500487F
+:10A0F00001EC28210000202100AC582B02A4C02133
+:10A10000030BB021ACE5004CACF600488FB4001056
+:10A110000014902B021288241620FF7C3C03800838
+:10A120008FB300148FBF005C8FBE00583A620001ED
+:10A130008FB700548FB600508FB5004C8FB40048D5
+:10A140008FB300448FB200408FB1003C8FB0003815
+:10A1500003E0000827BD006094FE00548CF2004428
+:10A1600033C9FFFE0009C8C00259F821ACBF003C4A
+:10A170008CE800448CAD003C010D50231940003B9D
+:10A18000000000008CF7004026E20001ACA200387D
+:10A190003C05005034A700103C038000AC67003041
+:10A1A00000000000000000000000000000000000AF
+:10A1B000000000000000000000000000000000009F
+:10A1C0008C7800003316002012C0FFFD3C1180087F
+:10A1D000962200543C1580003C068008304E000159
+:10A1E000000E18C0007578218DEC04003C070800B3
+:10A1F0008CE700443C040020ACCC00488DF40404FF
+:10A20000240B0001ACD4004C10EB0260AEA4003073
+:10A21000963900523C0508008CA5004000B99021F9
+:10A22000A6320052963F005427ED0001A62D00549F
+:10A230009626005430C4FFFF5487FF2F8FB40010C0
+:10A2400030A5FFFF0E0011F4A62000543C070800C3
+:10A250008CE70024963E00520047B82303D74823DA
+:10A26000A62900520A0012198FB400108CE2004097
+:10A270000A0012BE00000000922400012407000121
+:10A280003085007F14A7001C97AD00268E2B00148C
+:10A29000240CC000316A3FFF01AC48243C06080092
+:10A2A0008CC60060012A402531043FFF0086882BC0
+:10A2B00012200011A7A800263C0508008CA5005814
+:10A2C0008F9100A0000439802402FF8000B1182182
+:10A2D0000067F82103E2F02433F8007F3C1280008D
+:10A2E0003C19800EAE5E002C0319702191D0000D38
+:10A2F000360F0004A1CF000D0E001028241200011B
+:10A30000241100013C1E80008FC401000E000FCEFE
+:10A3100002E028218FC401000E000FDE02C02821B8
+:10A320001620FF558F8B00A40A0012860013802B85
+:10A330008F8600A490C80001310400201080019194
+:10A34000241000013C048008348B0080916A007C5A
+:10A350008F9E0034AFA0002C314900011120000F66
+:10A36000AFB000288CCD00148C8E006001AE602B45
+:10A370001580000201A038218C8700603C188008FD
+:10A38000370300808C70007000F0782B15E000021D
+:10A3900000E020218C640070AFA4002C3C028008F7
+:10A3A000344500808CD200148CBF0070025FC82B33
+:10A3B00017200002024020218CA400708FA7002CDF
+:10A3C0000087182310600003AFA3003024050002AB
+:10A3D000AFA500288FA400280264882B162000BA9D
+:10A3E000000018218CD000388FCE000C3C0F00806C
+:10A3F000AFD000008CCD00343C0CFF9F01CF58251E
+:10A40000AFCD000490CA003F3586FFFF01662024CF
+:10A410003C0900203C08FFEFA3CA000B0089382547
+:10A420003511FFFF00F118243C0500088F8700A4B8
+:10A430000065C825AFD9000C8CE20014AFC000182D
+:10A440008FA60030AFC200148CF800188FB0002C1B
+:10A450003C1FFFFBAFD8001C8CEF000837F2FFFF5A
+:10A4600003326824AFCF00248CEC000C020670216C
+:10A47000AFCD000CA7C00038A7C0003AAFCE002C6B
+:10A48000AFCC0020AFC000288CEA00148FAB002CAA
+:10A49000014B48230126402311000011AFC80010D2
+:10A4A00090EB003D8FC900048FC80000000B5100E5
+:10A4B000012A28210000102100AA882B010218215E
+:10A4C0000071F821AFC50004AFDF000090F2003D3D
+:10A4D000A3D2000A8F9900A497380006A7D80008D5
+:10A4E0008F910038240800023C038008A228000055
+:10A4F0003465008094BF005C8FA4002C33F0FFFF14
+:10A500000E000FF48F9200380002CB808F8500A4DC
+:10A51000021978253C18420001F87025AE4E00045F
+:10A520008F8400388CAD0038AC8D00188CAC0034B2
+:10A53000AC8C001CAC80000CAC800010A48000141B
+:10A54000A4800016A4800020A4800022AC800024F7
+:10A5500090A6003F8FA7002CA486000250E0019235
+:10A56000240700018FA200305040000290A2003D5D
+:10A5700090A2003E244A0001A08A00018F84003886
+:10A580008FA9002CAC8900083C128008364D008051
+:10A5900091AC007C3186000214C000022407003414
+:10A5A000240700308F8500A43C198008373F0080C5
+:10A5B00090B0000093F9007C240E0004A0900030BD
+:10A5C0008F8F00A48FB8002C8F8D003891F200017E
+:10A5D0003304000301C46023A1B200318F8E003820
+:10A5E0008F8600A42402C00095CA003294C90012CC
+:10A5F0008FAB002C0142402431233FFF010388250B
+:10A60000A5D1003291D000323185000300EBF82152
+:10A610003218003F370F0040A1CF00328FA4002C2A
+:10A6200003E5382133280004108000028F850038AC
+:10A6300000E838213C0A8008ACA700343549010005
+:10A640008D2800D08FA3002C2419FFBFACA80038A0
+:10A6500090B1003C2C640001240FFFDF3227007F03
+:10A66000A0A7003C8F98003800049140931F003C45
+:10A6700003F98024A310003C8F8C0038918E003C9D
+:10A6800001CF682401B23025A186003C8F8900A447
+:10A690008F8800388D2B0020AD0B00408D220024C8
+:10A6A000AD0200448D2A0028AD0A00488D23002CFD
+:10A6B0000E001013AD03004C8FB1002824070002D8
+:10A6C000122700118FA300280003282B00058023E8
+:10A6D0000270982400608021006090210A00126FAF
+:10A6E0000010882B962900128F8400A00000902172
+:10A6F0003125FFFFA7A900180E000FC22411000189
+:10A700000A00131D3C1E80003C0B80003C12800898
+:10A710008D640100924900088F92FF340E000F995A
+:10A720003125007F8F9900388FA700288FA4003033
+:10A73000A3270000965F005C33F0FFFF0E000FF4CC
+:10A740008F91003800026B80020D80253C0842008A
+:10A750008F8D00A402085025AE2A00048DA5003874
+:10A760008F8A003800007821000F1100AD450018D5
+:10A770008DB800343C047FFF3488FFFFAD58001CC7
+:10A7800091A6003E8D4C001C8D4900180006190052
+:10A79000000677020183C821004E58250323882B29
+:10A7A000012B382100F1F821AD59001CAD5F0018D4
+:10A7B000AD40000CAD40001091B0003E8FA40030C1
+:10A7C00024090005A550001495A500042419C00013
+:10A7D00000884024A545001691B8003EA5580020E9
+:10A7E00095AF0004A54F0022AD40002491AE003F7C
+:10A7F000A54E000291A6003E91AC003D01861023BB
+:10A80000244B0001A14B00018F9100388FA3003031
+:10A810003C028008344B0100AE230008A22900301E
+:10A820008F8C00388F8700A4959F003294F000121F
+:10A830002407FFBF033FC02432053FFF03057825EF
+:10A84000A58F0032918E00322418FFDF31CD003FFA
+:10A8500035A60040A18600328F910038240DFFFFFD
+:10A86000240CFF80AE2000348D6A00D0AE2A003860
+:10A870009223003C3069007FA229003C8F90003871
+:10A880003C0380009219003C0327F824A21F003CDF
+:10A890008F8E003891C5003C00B87824A1CF003CD1
+:10A8A0008F8A00383C0E8008AD4D00408FA6002CEA
+:10A8B000AD46004491420048004C5825A14B004849
+:10A8C0008F9000388F9900A48E09004801238824B6
+:10A8D00002283825AE070048933F003EA21F004CD7
+:10A8E0008F9800A48F8F003897050004A5E5004ECF
+:10A8F0000E0003818DC500609246007C8FAC003055
+:10A9000000026940000291000040282130CB000283
+:10A9100001B21021156000AA018230213C0E80088E
+:10A9200035C20080904C007C31830004106000032D
+:10A930008FB900300005788000CF3021241F00043B
+:10A940008F910038332D000303ED8023320800037C
+:10A9500000C85021AE2A00343C188000A7C500383A
+:10A960003C0680088F04010090DE00080E000FDE18
+:10A9700033C5007F0E001013000000000A00140D04
+:10A980008FA300288F9800348CC90038241F00033F
+:10A99000A7000008AF0900008CC50034A300000A1E
+:10A9A0008F9900A4AF0500043C080080932D003F60
+:10A9B000A31F000C8F0A000C3C02FF9FA30D000B8D
+:10A9C0000148F0253451FFFF3C12FFEF8F9900A49E
+:10A9D00003D170243646FFFF01C61824AF03000CD4
+:10A9E0008F2C0014972900128F8400A0AF0C001048
+:10A9F0008F2F0014AF000018AF000020AF0F00141D
+:10AA0000AF0000248F270018312F3FFF000F59801F
+:10AA1000AF0700288F2500080164F821312D0001BF
+:10AA2000AF0500308F31000C8F920038001F51C2EB
+:10AA3000000D438001481021241E00023C068008BE
+:10AA4000A702001CA7000034AF11002CA25E00007A
+:10AA500034D20080964E005C8F9900383C0342004F
+:10AA600031CCFFFF01833825AF2700048F8B00A472
+:10AA7000240500012402C0008D640038240700343E
+:10AA8000AF2400188D690034AF29001CAF20000CE2
+:10AA9000AF200010A7200014A7200016A720002038
+:10AAA000A7200022AF200024A7300002A325000128
+:10AAB0008F8800388F9F00A4AD10000893ED000030
+:10AAC000A10D00308F8A00A48F98003891510001A9
+:10AAD000A31100318F8B0038957E003203C27024A1
+:10AAE00001CF6025A56C0032916300323064003FD5
+:10AAF000A16400329249007C3125000214A00002BA
+:10AB00008F840038240700303C198008AC8700345B
+:10AB1000373201008E5F00D0240AFFBF020090216F
+:10AB2000AC9F0038908D003C31A8007FA088003C8D
+:10AB30008F9E003893C2003C004A8824A3D1003C79
+:10AB40008F8300380010882B9066003C34CE0020A4
+:10AB5000A06E003C8F8400A48F9800388C8C00205D
+:10AB6000AF0C00408C8F0024AF0F00448C8700286E
+:10AB7000AF0700488C8B002CAF0B004C0E0010135D
+:10AB80003C1E80000A0012700000000094C80052B1
+:10AB90003C0A08008D4A002401488821A4D10052B3
+:10ABA0000A0012198FB40010A08700018F840038AA
+:10ABB000240B0001AC8B00080A0013BE3C12800875
+:10ABC000000520800A0014A200C4302127BDFFE048
+:10ABD0003C0D8008AFB20018AFB00010AFBF001C32
+:10ABE000AFB1001435B200808E4C001835A80100BA
+:10ABF000964B000695A70050910900FC000C5602E8
+:10AC0000016728233143007F312600FF240200031F
+:10AC1000AF8300A8AF8400A010C2001B30B0FFFFBC
+:10AC2000910600FC2412000530C200FF10520033D0
+:10AC300000000000160000098FBF001C8FB2001832
+:10AC40008FB100148FB00010240D0C003C0C80005C
+:10AC500027BD002003E00008AD8D00240E0011FB8D
+:10AC6000020020218FBF001C8FB200188FB100148A
+:10AC70008FB00010240D0C003C0C800027BD00207C
+:10AC800003E00008AD8D0024965800789651007AB4
+:10AC9000924E007D0238782631E8FFFF31C400C0B3
+:10ACA000148000092D11000116000037000000007B
+:10ACB0005620FFE28FBF001C0E0010D100000000E4
+:10ACC0000A00156A8FBF001C1620FFDA0000000082
+:10ACD0000E0010D1000000001440FFD88FBF001CF0
+:10ACE0001600002200000000925F007D33E2003F6A
+:10ACF000A242007D0A00156A8FBF001C950900EA78
+:10AD00008F86008000802821240400050E0007257E
+:10AD10003130FFFF978300923C0480002465FFFFE1
+:10AD2000A78500928C8A01B80540FFFE0000000054
+:10AD3000AC8001808FBF001CAC9001848FB20018E2
+:10AD40008FB100148FB000103C0760133C0B100053
+:10AD5000240D0C003C0C800027BD0020AC8701882E
+:10AD6000AC8B01B803E00008AD8D00240E0011FB90
+:10AD7000020020215040FFB18FBF001C925F007D78
+:10AD80000A00159733E2003F0E0011FB020020215C
+:10AD90001440FFAA8FBF001C122000070000000013
+:10ADA0009259007D3330003F36020040A242007DC0
+:10ADB0000A00156A8FBF001C0E0010D100000000B1
+:10ADC0005040FF9E8FBF001C9259007D3330003FE2
+:10ADD0000A0015C636020040000000000000001BFB
+:10ADE0000000000F0000000A00000008000000063C
+:10ADF0000000000500000005000000040000000441
+:10AE00000000000300000003000000030000000336
+:10AE10000000000300000002000000020000000229
+:10AE2000000000020000000200000002000000021A
+:10AE3000000000020000000200000002000000020A
+:10AE400000000002000000020000000200000002FA
+:10AE50000000000100000001000000018008010066
+:10AE6000800800808008000000000C000000308096
+:10AE7000080011D00800127C08001294080012A8E3
+:10AE8000080012BC080011D0080011D0080012F010
+:10AE90000800132C080013400800138808001A8CBF
+:10AEA00008001A8C08001AC408001AC408001AD82E
+:10AEB00008001AA808001D0008001CCC08001D5836
+:10AEC00008001D5808001DE008001D108008024001
+:10AED000080027340800256C0800275C080027F4C8
+:10AEE0000800293C0800298808002AAC080029B479
+:10AEF00008002A38080025DC08002EDC08002EA4F3
+:10AF000008002588080025880800258808002B20CF
+:10AF100008002B20080025880800258808002DD06F
+:10AF2000080025880800258808002588080025884D
+:10AF300008002E0C080025880800258808002588B0
+:10AF4000080025880800258808002588080025882D
+:10AF5000080025880800258808002588080025881D
+:10AF6000080025880800258808002588080029A8E9
+:10AF7000080025880800258808002E680800258814
+:10AF800008002588080025880800258808002588ED
+:10AF900008002588080025880800258808002588DD
+:10AFA00008002588080025880800258808002588CD
+:10AFB00008002588080025880800258808002588BD
+:10AFC00008002CF4080025880800258808002C6853
+:10AFD00008002BC408003CE408003CB808003C848E
+:10AFE00008003C5808003C3808003BEC8008010091
+:10AFF00080080080800800008008008008004C6401
+:10B0000008004C9C08004BE408004C6408004C64A9
+:10B01000080049B808004C64080050500A000C842D
+:10B0200000000000000000000000000D7278703683
+:10B030002E322E31620000000602010300000000E3
+:10B0400000000001000000000000000000000000FF
+:10B0500000000000000000000000000000000000F0
+:10B0600000000000000000000000000000000000E0
+:10B0700000000000000000000000000000000000D0
+:10B0800000000000000000000000000000000000C0
+:10B0900000000000000000000000000000000000B0
+:10B0A00000000000000000000000000000000000A0
+:10B0B0000000000000000000000000000000000090
+:10B0C0000000000000000000000000000000000080
+:10B0D0000000000000000000000000000000000070
+:10B0E0000000000000000000000000000000000060
+:10B0F0000000000000000000000000000000000050
+:10B10000000000000000000000000000000000003F
+:10B11000000000000000000000000000000000002F
+:10B12000000000000000000000000000000000001F
+:10B13000000000000000000000000000000000000F
+:10B1400000000000000000000000000000000000FF
+:10B1500000000000000000000000000000000000EF
+:10B1600000000000000000000000000000000000DF
+:10B1700000000000000000000000000000000000CF
+:10B1800000000000000000000000000000000000BF
+:10B1900000000000000000000000000000000000AF
+:10B1A000000000000000000000000000000000009F
+:10B1B000000000000000000000000000000000008F
+:10B1C000000000000000000000000000000000007F
+:10B1D000000000000000000000000000000000006F
+:10B1E000000000000000000000000000000000005F
+:10B1F000000000000000000000000000000000004F
+:10B20000000000000000000000000000000000003E
+:10B21000000000000000000000000000000000002E
+:10B22000000000000000000000000000000000001E
+:10B23000000000000000000000000000000000000E
+:10B2400000000000000000000000000000000000FE
+:10B2500000000000000000000000000000000000EE
+:10B2600000000000000000000000000000000000DE
+:10B2700000000000000000000000000000000000CE
+:10B2800000000000000000000000000000000000BE
+:10B2900000000000000000000000000000000000AE
+:10B2A000000000000000000000000000000000009E
+:10B2B000000000000000000000000000000000008E
+:10B2C000000000000000000000000000000000007E
+:10B2D000000000000000000000000000000000006E
+:10B2E000000000000000000000000000000000005E
+:10B2F000000000000000000000000000000000004E
+:10B30000000000000000000000000000000000003D
+:10B31000000000000000000000000000000000002D
+:10B32000000000000000000000000000000000001D
+:10B33000000000000000000000000000000000000D
+:10B3400000000000000000000000000000000000FD
+:10B3500000000000000000000000000000000000ED
+:10B3600000000000000000000000000000000000DD
+:10B3700000000000000000000000000000000000CD
+:10B3800000000000000000000000000000000000BD
+:10B3900000000000000000000000000000000000AD
+:10B3A000000000000000000000000000000000009D
+:10B3B000000000000000000000000000000000008D
+:10B3C000000000000000000000000000000000007D
+:10B3D000000000000000000000000000000000006D
+:10B3E000000000000000000000000000000000005D
+:10B3F000000000000000000000000000000000004D
+:10B40000000000000000000000000000000000003C
+:10B41000000000000000000000000000000000002C
+:10B42000000000000000000000000000000000001C
+:10B43000000000000000000000000000000000000C
+:10B4400000000000000000000000000000000000FC
+:10B4500000000000000000000000000000000000EC
+:10B4600000000000000000000000000000000000DC
+:10B4700000000000000000000000000000000000CC
+:10B4800000000000000000000000000000000000BC
+:10B4900000000000000000000000000000000000AC
+:10B4A000000000000000000000000000000000009C
+:10B4B000000000000000000000000000000000008C
+:10B4C000000000000000000000000000000000007C
+:10B4D000000000000000000000000000000000006C
+:10B4E000000000000000000000000000000000005C
+:10B4F000000000000000000000000000000000004C
+:10B50000000000000000000000000000000000003B
+:10B51000000000000000000000000000000000002B
+:10B52000000000000000000000000000000000001B
+:10B53000000000000000000000000000000000000B
+:10B5400000000000000000000000000000000000FB
+:10B5500000000000000000000000000000000000EB
+:10B5600000000000000000000000000000000000DB
+:10B5700000000000000000000000000000000000CB
+:10B5800000000000000000000000000000000000BB
+:10B5900000000000000000000000000000000000AB
+:10B5A000000000000000000000000000000000009B
+:10B5B000000000000000000000000000000000008B
+:10B5C000000000000000000000000000000000007B
+:10B5D000000000000000000000000000000000006B
+:10B5E000000000000000000000000000000000005B
+:10B5F000000000000000000000000000000000004B
+:10B60000000000000000000000000000000000003A
+:10B61000000000000000000000000000000000002A
+:10B62000000000000000000000000000000000001A
+:10B63000000000000000000000000000000000000A
+:10B6400000000000000000000000000000000000FA
+:10B6500000000000000000000000000000000000EA
+:10B6600000000000000000000000000000000000DA
+:10B6700000000000000000000000000000000000CA
+:10B6800000000000000000000000000000000000BA
+:10B6900000000000000000000000000000000000AA
+:10B6A000000000000000000000000000000000009A
+:10B6B000000000000000000000000000000000008A
+:10B6C000000000000000000000000000000000007A
+:10B6D000000000000000000000000000000000006A
+:10B6E000000000000000000000000000000000005A
+:10B6F000000000000000000000000000000000004A
+:10B700000000000000000000000000000000000039
+:10B710000000000000000000000000000000000029
+:10B720000000000000000000000000000000000019
+:10B730000000000000000000000000000000000009
+:10B7400000000000000000000000000000000000F9
+:10B7500000000000000000000000000000000000E9
+:10B7600000000000000000000000000000000000D9
+:10B7700000000000000000000000000000000000C9
+:10B7800000000000000000000000000000000000B9
+:10B7900000000000000000000000000000000000A9
+:10B7A0000000000000000000000000000000000099
+:10B7B0000000000000000000000000000000000089
+:10B7C0000000000000000000000000000000000079
+:10B7D0000000000000000000000000000000000069
+:10B7E0000000000000000000000000000000000059
+:10B7F0000000000000000000000000000000000049
+:10B800000000000000000000000000000000000038
+:10B810000000000000000000000000000000000028
+:10B820000000000000000000000000000000000018
+:10B830000000000000000000000000000000000008
+:10B8400000000000000000000000000000000000F8
+:10B8500000000000000000000000000000000000E8
+:10B8600000000000000000000000000000000000D8
+:10B8700000000000000000000000000000000000C8
+:10B8800000000000000000000000000000000000B8
+:10B8900000000000000000000000000000000000A8
+:10B8A0000000000000000000000000000000000098
+:10B8B0000000000000000000000000000000000088
+:10B8C0000000000000000000000000000000000078
+:10B8D0000000000000000000000000000000000068
+:10B8E0000000000000000000000000000000000058
+:10B8F0000000000000000000000000000000000048
+:10B900000000000000000000000000000000000037
+:10B910000000000000000000000000000000000027
+:10B920000000000000000000000000000000000017
+:10B930000000000000000000000000000000000007
+:10B9400000000000000000000000000000000000F7
+:10B9500000000000000000000000000000000000E7
+:10B9600000000000000000000000000000000000D7
+:10B9700000000000000000000000000000000000C7
+:10B9800000000000000000000000000000000000B7
+:10B9900000000000000000000000000000000000A7
+:10B9A0000000000000000000000000000000000097
+:10B9B0000000000000000000000000000000000087
+:10B9C0000000000000000000000000000000000077
+:10B9D0000000000000000000000000000000000067
+:10B9E0000000000000000000000000000000000057
+:10B9F0000000000000000000000000000000000047
+:10BA00000000000000000000000000000000000036
+:10BA10000000000000000000000000000000000026
+:10BA20000000000000000000000000000000000016
+:10BA30000000000000000000000000000000000006
+:10BA400000000000000000000000000000000000F6
+:10BA500000000000000000000000000000000000E6
+:10BA600000000000000000000000000000000000D6
+:10BA700000000000000000000000000000000000C6
+:10BA800000000000000000000000000000000000B6
+:10BA900000000000000000000000000000000000A6
+:10BAA0000000000000000000000000000000000096
+:10BAB0000000000000000000000000000000000086
+:10BAC0000000000000000000000000000000000076
+:10BAD0000000000000000000000000000000000066
+:10BAE0000000000000000000000000000000000056
+:10BAF0000000000000000000000000000000000046
+:10BB00000000000000000000000000000000000035
+:10BB10000000000000000000000000000000000025
+:10BB20000000000000000000000000000000000015
+:10BB30000000000000000000000000000000000005
+:10BB400000000000000000000000000000000000F5
+:10BB500000000000000000000000000000000000E5
+:10BB600000000000000000000000000000000000D5
+:10BB700000000000000000000000000000000000C5
+:10BB800000000000000000000000000000000000B5
+:10BB900000000000000000000000000000000000A5
+:10BBA0000000000000000000000000000000000095
+:10BBB0000000000000000000000000000000000085
+:10BBC0000000000000000000000000000000000075
+:10BBD0000000000000000000000000000000000065
+:10BBE0000000000000000000000000000000000055
+:10BBF0000000000000000000000000000000000045
+:10BC00000000000000000000000000000000000034
+:10BC10000000000000000000000000000000000024
+:10BC20000000000000000000000000000000000014
+:10BC30000000000000000000000000000000000004
+:10BC400000000000000000000000000000000000F4
+:10BC500000000000000000000000000000000000E4
+:10BC600000000000000000000000000000000000D4
+:10BC700000000000000000000000000000000000C4
+:10BC800000000000000000000000000000000000B4
+:10BC900000000000000000000000000000000000A4
+:10BCA0000000000000000000000000000000000094
+:10BCB0000000000000000000000000000000000084
+:10BCC0000000000000000000000000000000000074
+:10BCD0000000000000000000000000000000000064
+:10BCE0000000000000000000000000000000000054
+:10BCF0000000000000000000000000000000000044
+:10BD00000000000000000000000000000000000033
+:10BD10000000000000000000000000000000000023
+:10BD20000000000000000000000000000000000013
+:10BD30000000000000000000000000000000000003
+:10BD400000000000000000000000000000000000F3
+:10BD500000000000000000000000000000000000E3
+:10BD600000000000000000000000000000000000D3
+:10BD700000000000000000000000000000000000C3
+:10BD800000000000000000000000000000000000B3
+:10BD900000000000000000000000000000000000A3
+:10BDA0000000000000000000000000000000000093
+:10BDB0000000000000000000000000000000000083
+:10BDC0000000000000000000000000000000000073
+:10BDD0000000000000000000000000000000000063
+:10BDE0000000000000000000000000000000000053
+:10BDF0000000000000000000000000000000000043
+:10BE00000000000000000000000000000000000032
+:10BE10000000000000000000000000000000000022
+:10BE20000000000000000000000000000000000012
+:10BE30000000000000000000000000000000000002
+:10BE400000000000000000000000000000000000F2
+:10BE500000000000000000000000000000000000E2
+:10BE600000000000000000000000000000000000D2
+:10BE700000000000000000000000000000000000C2
+:10BE800000000000000000000000000000000000B2
+:10BE900000000000000000000000000000000000A2
+:10BEA0000000000000000000000000000000000092
+:10BEB0000000000000000000000000000000000082
+:10BEC0000000000000000000000000000000000072
+:10BED0000000000000000000000000000000000062
+:10BEE0000000000000000000000000000000000052
+:10BEF0000000000000000000000000000000000042
+:10BF00000000000000000000000000000000000031
+:10BF10000000000000000000000000000000000021
+:10BF20000000000000000000000000000000000011
+:10BF30000000000000000000000000000000000001
+:10BF400000000000000000000000000000000000F1
+:10BF500000000000000000000000000000000000E1
+:10BF600000000000000000000000000000000000D1
+:10BF700000000000000000000000000000000000C1
+:10BF800000000000000000000000000000000000B1
+:10BF900000000000000000000000000000000000A1
+:10BFA0000000000000000000000000000000000091
+:10BFB0000000000000000000000000000000000081
+:10BFC0000000000000000000000000000000000071
+:10BFD0000000000000000000000000000000000061
+:10BFE0000000000000000000000000000000000051
+:10BFF0000000000000000000000000000000000041
+:10C000000000000000000000000000000000000030
+:10C010000000000000000000000000000000000020
+:10C020000000000000000000000000000000000010
+:10C030000000000000000000000000000000000000
+:10C0400000000000000000000000000000000000F0
+:10C0500000000000000000000000000000000000E0
+:10C0600000000000000000000000000000000000D0
+:10C0700000000000000000000000000000000000C0
+:10C0800000000000000000000000000000000000B0
+:10C0900000000000000000000000000000000000A0
+:10C0A0000000000000000000000000000000000090
+:10C0B0000000000000000000000000000000000080
+:10C0C0000000000000000000000000000000000070
+:10C0D0000000000000000000000000000000000060
+:10C0E0000000000000000000000000000000000050
+:10C0F0000000000000000000000000000000000040
+:10C10000000000000000000000000000000000002F
+:10C11000000000000000000000000000000000001F
+:10C12000000000000000000000000000000000000F
+:10C1300000000000000000000000000000000000FF
+:10C1400000000000000000000000000000000000EF
+:10C1500000000000000000000000000000000000DF
+:10C1600000000000000000000000000000000000CF
+:10C1700000000000000000000000000000000000BF
+:10C1800000000000000000000000000000000000AF
+:10C19000000000000000000000000000000000009F
+:10C1A000000000000000000000000000000000008F
+:10C1B000000000000000000000000000000000007F
+:10C1C000000000000000000000000000000000006F
+:10C1D000000000000000000000000000000000005F
+:10C1E000000000000000000000000000000000004F
+:10C1F000000000000000000000000000000000003F
+:10C20000000000000000000000000000000000002E
+:10C21000000000000000000000000000000000001E
+:10C22000000000000000000000000000000000000E
+:10C2300000000000000000000000000000000000FE
+:10C2400000000000000000000000000000000000EE
+:10C2500000000000000000000000000000000000DE
+:10C2600000000000000000000000000000000000CE
+:10C2700000000000000000000000000000000000BE
+:10C2800000000000000000000000000000000000AE
+:10C29000000000000000000000000000000000009E
+:10C2A000000000000000000000000000000000008E
+:10C2B000000000000000000000000000000000007E
+:10C2C000000000000000000000000000000000006E
+:10C2D000000000000000000000000000000000005E
+:10C2E000000000000000000000000000000000004E
+:10C2F000000000000000000000000000000000003E
+:10C30000000000000000000000000000000000002D
+:10C31000000000000000000000000000000000001D
+:10C32000000000000000000000000000000000000D
+:10C3300000000000000000000000000000000000FD
+:10C3400000000000000000000000000000000000ED
+:10C3500000000000000000000000000000000000DD
+:10C3600000000000000000000000000000000000CD
+:10C3700000000000000000000000000000000000BD
+:10C3800000000000000000000000000000000000AD
+:10C39000000000000000000000000000000000009D
+:10C3A000000000000000000000000000000000008D
+:10C3B000000000000000000000000000000000007D
+:10C3C000000000000000000000000000000000006D
+:10C3D000000000000000000000000000000000005D
+:10C3E000000000000000000000000000000000004D
+:10C3F000000000000000000000000000000000003D
+:10C40000000000000000000000000000000000002C
+:10C41000000000000000000000000000000000001C
+:10C42000000000000000000000000000000000000C
+:10C4300000000000000000000000000000000000FC
+:10C4400000000000000000000000000000000000EC
+:10C4500000000000000000000000000000000000DC
+:10C4600000000000000000000000000000000000CC
+:10C4700000000000000000000000000000000000BC
+:10C4800000000000000000000000000000000000AC
+:10C49000000000000000000000000000000000009C
+:10C4A000000000000000000000000000000000008C
+:10C4B000000000000000000000000000000000007C
+:10C4C000000000000000000000000000000000006C
+:10C4D000000000000000000000000000000000005C
+:10C4E000000000000000000000000000000000004C
+:10C4F000000000000000000000000000000000003C
+:10C50000000000000000000000000000000000002B
+:10C51000000000000000000000000000000000001B
+:10C52000000000000000000000000000000000000B
+:10C5300000000000000000000000000000000000FB
+:10C5400000000000000000000000000000000000EB
+:10C5500000000000000000000000000000000000DB
+:10C5600000000000000000000000000000000000CB
+:10C5700000000000000000000000000000000000BB
+:10C5800000000000000000000000000000000000AB
+:10C59000000000000000000000000000000000009B
+:10C5A000000000000000000000000000000000008B
+:10C5B000000000000000000000000000000000007B
+:10C5C000000000000000000000000000000000006B
+:10C5D000000000000000000000000000000000005B
+:10C5E000000000000000000000000000000000004B
+:10C5F000000000000000000000000000000000003B
+:10C60000000000000000000000000000000000002A
+:10C61000000000000000000000000000000000001A
+:10C62000000000000000000000000000000000000A
+:10C6300000000000000000000000000000000000FA
+:10C6400000000000000000000000000000000000EA
+:10C6500000000000000000000000000000000000DA
+:10C6600000000000000000000000000000000000CA
+:10C6700000000000000000000000000000000000BA
+:10C6800000000000000000000000000000000000AA
+:10C69000000000000000000000000000000000009A
+:10C6A000000000000000000000000000000000008A
+:10C6B000000000000000000000000000000000007A
+:10C6C000000000000000000000000000000000006A
+:10C6D000000000000000000000000000000000005A
+:10C6E000000000000000000000000000000000004A
+:10C6F000000000000000000000000000000000003A
+:10C700000000000000000000000000000000000029
+:10C710000000000000000000000000000000000019
+:10C720000000000000000000000000000000000009
+:10C7300000000000000000000000000000000000F9
+:10C7400000000000000000000000000000000000E9
+:10C7500000000000000000000000000000000000D9
+:10C7600000000000000000000000000000000000C9
+:10C7700000000000000000000000000000000000B9
+:10C7800000000000000000000000000000000000A9
+:10C790000000000000000000000000000000000099
+:10C7A0000000000000000000000000000000000089
+:10C7B0000000000000000000000000000000000079
+:10C7C0000000000000000000000000000000000069
+:10C7D0000000000000000000000000000000000059
+:10C7E0000000000000000000000000000000000049
+:10C7F0000000000000000000000000000000000039
+:10C800000000000000000000000000000000000028
+:10C810000000000000000000000000000000000018
+:10C820000000000000000000000000000000000008
+:10C8300000000000000000000000000000000000F8
+:10C8400000000000000000000000000000000000E8
+:10C8500000000000000000000000000000000000D8
+:10C8600000000000000000000000000000000000C8
+:10C8700000000000000000000000000000000000B8
+:10C8800000000000000000000000000000000000A8
+:10C890000000000000000000000000000000000098
+:10C8A0000000000000000000000000000000000088
+:10C8B0000000000000000000000000000000000078
+:10C8C0000000000000000000000000000000000068
+:10C8D0000000000000000000000000000000000058
+:10C8E0000000000000000000000000000000000048
+:10C8F0000000000000000000000000000000000038
+:10C900000000000000000000000000000000000027
+:10C910000000000000000000000000000000000017
+:10C920000000000000000000000000000000000007
+:10C9300000000000000000000000000000000000F7
+:10C9400000000000000000000000000000000000E7
+:10C9500000000000000000000000000000000000D7
+:10C9600000000000000000000000000000000000C7
+:10C9700000000000000000000000000000000000B7
+:10C9800000000000000000000000000000000000A7
+:10C990000000000000000000000000000000000097
+:10C9A0000000000000000000000000000000000087
+:10C9B0000000000000000000000000000000000077
+:10C9C0000000000000000000000000000000000067
+:10C9D0000000000000000000000000000000000057
+:10C9E0000000000000000000000000000000000047
+:10C9F0000000000000000000000000000000000037
+:10CA00000000000000000000000000000000000026
+:10CA10000000000000000000000000000000000016
+:10CA20000000000000000000000000000000000006
+:10CA300000000000000000000000000000000000F6
+:10CA400000000000000000000000000000000000E6
+:10CA500000000000000000000000000000000000D6
+:10CA600000000000000000000000000000000000C6
+:10CA700000000000000000000000000000000000B6
+:10CA800000000000000000000000000000000000A6
+:10CA90000000000000000000000000000000000096
+:10CAA0000000000000000000000000000000000086
+:10CAB0000000000000000000000000000000000076
+:10CAC0000000000000000000000000000000000066
+:10CAD0000000000000000000000000000000000056
+:10CAE0000000000000000000000000000000000046
+:10CAF0000000000000000000000000000000000036
+:10CB00000000000000000000000000000000000025
+:10CB10000000000000000000000000000000000015
+:10CB20000000000000000000000000000000000005
+:10CB300000000000000000000000000000000000F5
+:10CB400000000000000000000000000000000000E5
+:10CB500000000000000000000000000000000000D5
+:10CB600000000000000000000000000000000000C5
+:10CB700000000000000000000000000000000000B5
+:10CB800000000000000000000000000000000000A5
+:10CB90000000000000000000000000000000000095
+:10CBA0000000000000000000000000000000000085
+:10CBB0000000000000000000000000000000000075
+:10CBC0000000000000000000000000000000000065
+:10CBD0000000000000000000000000000000000055
+:10CBE0000000000000000000000000000000000045
+:10CBF0000000000000000000000000000000000035
+:10CC00000000000000000000000000000000000024
+:10CC10000000000000000000000000000000000014
+:10CC20000000000000000000000000000000000004
+:10CC300000000000000000000000000000000000F4
+:10CC400000000000000000000000000000000000E4
+:10CC500000000000000000000000000000000000D4
+:10CC600000000000000000000000000000000000C4
+:10CC700000000000000000000000000000000000B4
+:10CC800000000000000000000000000000000000A4
+:10CC90000000000000000000000000000000000094
+:10CCA0000000000000000000000000000000000084
+:10CCB0000000000000000000000000000000000074
+:10CCC0000000000000000000000000000000000064
+:10CCD0000000000000000000000000000000000054
+:10CCE0000000000000000000000000000000000044
+:10CCF0000000000000000000000000000000000034
+:10CD00000000000000000000000000000000000023
+:10CD10000000000000000000000000000000000013
+:10CD20000000000000000000000000000000000003
+:10CD300000000000000000000000000000000000F3
+:10CD400000000000000000000000000000000000E3
+:10CD500000000000000000000000000000000000D3
+:10CD600000000000000000000000000000000000C3
+:10CD700000000000000000000000000000000000B3
+:10CD800000000000000000000000000000000000A3
+:10CD90000000000000000000000000000000000093
+:10CDA0000000000000000000000000000000000083
+:10CDB0000000000000000000000000000000000073
+:10CDC0000000000000000000000000000000000063
+:10CDD0000000000000000000000000000000000053
+:10CDE0000000000000000000000000000000000043
+:10CDF0000000000000000000000000000000000033
+:10CE00000000000000000000000000000000000022
+:10CE10000000000000000000000000000000000012
+:10CE20000000000000000000000000000000000002
+:10CE300000000000000000000000000000000000F2
+:10CE400000000000000000000000000000000000E2
+:10CE500000000000000000000000000000000000D2
+:10CE600000000000000000000000000000000000C2
+:10CE700000000000000000000000000000000000B2
+:10CE800000000000000000000000000000000000A2
+:10CE90000000000000000000000000000000000092
+:10CEA0000000000000000000000000000000000082
+:10CEB0000000000000000000000000000000000072
+:10CEC0000000000000000000000000000000000062
+:10CED0000000000000000000000000000000000052
+:10CEE0000000000000000000000000000000000042
+:10CEF0000000000000000000000000000000000032
+:10CF00000000000000000000000000000000000021
+:10CF10000000000000000000000000000000000011
+:10CF20000000000000000000000000000000000001
+:10CF300000000000000000000000000000000000F1
+:10CF400000000000000000000000000000000000E1
+:10CF500000000000000000000000000000000000D1
+:10CF600000000000000000000000000000000000C1
+:10CF700000000000000000000000000000000000B1
+:10CF800000000000000000000000000000000000A1
+:10CF90000000000000000000000000000000000091
+:10CFA0000000000000000000000000000000000081
+:10CFB0000000000000000000000000000000000071
+:10CFC0000000000000000000000000000000000061
+:10CFD0000000000000000000000000000000000051
+:10CFE0000000000000000000000000000000000041
+:10CFF0000000000000000000000000000000000031
+:10D000000000000000000000000000000000000020
+:10D010000000000000000000000000000000000010
+:10D020000000000000000000000000000000000000
+:10D0300000000000000000000000000000000000F0
+:10D0400000000000000000000000000000000000E0
+:10D0500000000000000000000000000000000000D0
+:10D0600000000000000000000000000000000000C0
+:10D0700000000000000000000000000000000000B0
+:10D0800000000000000000000000000000000000A0
+:10D090000000000000000000000000000000000090
+:10D0A0000000000000000000000000000000000080
+:10D0B0000000000000000000000000000000000070
+:10D0C0000000000000000000000000000000000060
+:10D0D0000000000000000000000000000000000050
+:10D0E0000000000000000000000000000000000040
+:10D0F0000000000000000000000000000000000030
+:10D10000000000000000000000000000000000001F
+:10D11000000000000000000000000000000000000F
+:10D1200000000000000000000000000000000000FF
+:10D1300000000000000000000000000000000000EF
+:10D1400000000000000000000000000000000000DF
+:10D1500000000000000000000000000000000000CF
+:10D1600000000000000000000000000000000000BF
+:10D1700000000000000000000000000000000000AF
+:10D18000000000000000000000000000000000009F
+:10D19000000000000000000000000000000000008F
+:10D1A000000000000000000000000000000000007F
+:10D1B000000000000000000000000000000000006F
+:10D1C000000000000000000000000000000000005F
+:10D1D000000000000000000000000000000000004F
+:10D1E000000000000000000000000000000000003F
+:10D1F000000000000000000000000000000000002F
+:10D20000000000000000000000000000000000001E
+:10D21000000000000000000000000000000000000E
+:10D2200000000000000000000000000000000000FE
+:10D2300000000000000000000000000000000000EE
+:10D2400000000000000000000000000000000000DE
+:10D2500000000000000000000000000000000000CE
+:10D2600000000000000000000000000000000000BE
+:10D2700000000000000000000000000000000000AE
+:10D28000000000000000000000000000000000009E
+:10D29000000000000000000000000000000000008E
+:10D2A000000000000000000000000000000000007E
+:10D2B000000000000000000000000000000000006E
+:10D2C000000000000000000000000000000000005E
+:10D2D000000000000000000000000000000000004E
+:10D2E000000000000000000000000000000000003E
+:10D2F000000000000000000000000000000000002E
+:10D30000000000000000000000000000000000001D
+:10D31000000000000000000000000000000000000D
+:10D3200000000000000000000000000000000000FD
+:10D3300000000000000000000000000000000000ED
+:10D3400000000000000000000000000000000000DD
+:10D3500000000000000000000000000000000000CD
+:10D3600000000000000000000000000000000000BD
+:10D3700000000000000000000000000000000000AD
+:10D38000000000000000000000000000000000009D
+:10D39000000000000000000000000000000000008D
+:10D3A000000000000000000000000000000000007D
+:10D3B000000000000000000000000000000000006D
+:10D3C000000000000000000000000000000000005D
+:10D3D000000000000000000000000000000000004D
+:10D3E000000000000000000000000000000000003D
+:10D3F000000000000000000000000000000000002D
+:10D40000000000000000000000000000000000001C
+:10D41000000000000000000000000000000000000C
+:10D4200000000000000000000000000000000000FC
+:10D4300000000000000000000000000000000000EC
+:10D4400000000000000000000000000000000000DC
+:10D4500000000000000000000000000000000000CC
+:10D4600000000000000000000000000000000000BC
+:10D4700000000000000000000000000000000000AC
+:10D48000000000000000000000000000000000009C
+:10D49000000000000000000000000000000000008C
+:10D4A000000000000000000000000000000000007C
+:10D4B000000000000000000000000000000000006C
+:10D4C000000000000000000000000000000000005C
+:10D4D000000000000000000000000000000000004C
+:10D4E000000000000000000000000000000000003C
+:10D4F000000000000000000000000000000000002C
+:10D50000000000000000000000000000000000001B
+:10D51000000000000000000000000000000000000B
+:10D5200000000000000000000000000000000000FB
+:10D5300000000000000000000000000000000000EB
+:10D5400000000000000000000000000000000000DB
+:10D5500000000000000000000000000000000000CB
+:10D5600000000000000000000000000000000000BB
+:10D5700000000000000000000000000000000000AB
+:10D58000000000000000000000000000000000009B
+:10D59000000000000000000000000000000000008B
+:10D5A000000000000000000000000000000000007B
+:10D5B000000000000000000000000000000000006B
+:10D5C000000000000000000000000000000000005B
+:10D5D000000000000000000000000000000000004B
+:10D5E000000000000000000000000000000000003B
+:10D5F000000000000000000000000000000000002B
+:10D60000000000000000000000000000000000001A
+:10D61000000000000000000000000000000000000A
+:10D6200000000000000000000000000000000000FA
+:10D6300000000000000000000000000000000000EA
+:10D6400000000000000000000000000000000000DA
+:10D6500000000000000000000000000000000000CA
+:10D6600000000000000000000000000000000000BA
+:10D6700000000000000000000000000000000000AA
+:10D68000000000000000000000000000000000009A
+:10D69000000000000000000000000000000000008A
+:10D6A000000000000000000000000000000000007A
+:10D6B000000000000000000000000000000000006A
+:10D6C000000000000000000000000000000000005A
+:10D6D000000000000000000000000000000000004A
+:10D6E000000000000000000000000000000000003A
+:10D6F000000000000000000000000000000000002A
+:10D700000000000000000000000000000000000019
+:10D710000000000000000000000000000000000009
+:10D7200000000000000000000000000000000000F9
+:10D7300000000000000000000000000000000000E9
+:10D7400000000000000000000000000000000000D9
+:10D7500000000000000000000000000000000000C9
+:10D7600000000000000000000000000000000000B9
+:10D7700000000000000000000000000000000000A9
+:10D780000000000000000000000000000000000099
+:10D790000000000000000000000000000000000089
+:10D7A0000000000000000000000000000000000079
+:10D7B0000000000000000000000000000000000069
+:10D7C0000000000000000000000000000000000059
+:10D7D0000000000000000000000000000000000049
+:10D7E0000000000000000000000000000000000039
+:10D7F0000000000000000000000000000000000029
+:10D800000000000000000000000000000000000018
+:10D810000000000000000000000000000000000008
+:10D8200000000000000000000000000000000000F8
+:10D8300000000000000000000000000000000000E8
+:10D8400000000000000000000000000000000000D8
+:10D8500000000000000000000000000000000000C8
+:10D8600000000000000000000000000000000000B8
+:10D8700000000000000000000000000000000000A8
+:10D880000000000000000000000000000000000098
+:10D890000000000000000000000000000000000088
+:10D8A0000000000000000000000000000000000078
+:10D8B0000000000000000000000000000000000068
+:10D8C0000000000000000000000000000000000058
+:10D8D0000000000000000000000000000000000048
+:10D8E0000000000000000000000000000000000038
+:10D8F0000000000000000000000000000000000028
+:10D900000000000000000000000000000000000017
+:10D910000000000000000000000000000000000007
+:10D9200000000000000000000000000000000000F7
+:10D9300000000000000000000000000000000000E7
+:10D9400000000000000000000000000000000000D7
+:10D9500000000000000000000000000000000000C7
+:10D9600000000000000000000000000000000000B7
+:10D9700000000000000000000000000000000000A7
+:10D980000000000000000000000000000000000097
+:10D990000000000000000000000000000000000087
+:10D9A0000000000000000000000000000000000077
+:10D9B0000000000000000000000000000000000067
+:10D9C0000000000000000000000000000000000057
+:10D9D0000000000000000000000000000000000047
+:10D9E0000000000000000000000000000000000037
+:10D9F0000000000000000000000000000000000027
+:10DA00000000000000000000000000000000000016
+:10DA10000000000000000000000000000000000006
+:10DA200000000000000000000000000000000000F6
+:10DA300000000000000000000000000000000000E6
+:10DA400000000000000000000000000000000000D6
+:10DA500000000000000000000000000000000000C6
+:10DA600000000000000000000000000000000000B6
+:10DA700000000000000000000000000000000000A6
+:10DA80000000000000000000000000000000000096
+:10DA90000000000000000000000000000000000086
+:10DAA0000000000000000000000000000000000076
+:10DAB0000000000000000000000000000000000066
+:10DAC0000000000000000000000000000000000056
+:10DAD0000000000000000000000000000000000046
+:10DAE0000000000000000000000000000000000036
+:10DAF0000000000000000000000000000000000026
+:10DB00000000000000000000000000000000000015
+:10DB10000000000000000000000000000000000005
+:10DB200000000000000000000000000000000000F5
+:10DB300000000000000000000000000000000000E5
+:10DB400000000000000000000000000000000000D5
+:10DB500000000000000000000000000000000000C5
+:10DB600000000000000000000000000000000000B5
+:10DB700000000000000000000000000000000000A5
+:10DB80000000000000000000000000000000000095
+:10DB90000000000000000000000000000000000085
+:10DBA0000000000000000000000000000000000075
+:10DBB0000000000000000000000000000000000065
+:10DBC0000000000000000000000000000000000055
+:10DBD0000000000000000000000000000000000045
+:10DBE0000000000000000000000000000000000035
+:10DBF0000000000000000000000000000000000025
+:10DC00000000000000000000000000000000000014
+:10DC10000000000000000000000000000000000004
+:10DC200000000000000000000000000000000000F4
+:10DC300000000000000000000000000000000000E4
+:10DC400000000000000000000000000000000000D4
+:10DC500000000000000000000000000000000000C4
+:10DC600000000000000000000000000000000000B4
+:10DC700000000000000000000000000000000000A4
+:10DC80000000000000000000000000000000000094
+:10DC90000000000000000000000000000000000084
+:10DCA0000000000000000000000000000000000074
+:10DCB0000000000000000000000000000000000064
+:10DCC0000000000000000000000000000000000054
+:10DCD0000000000000000000000000000000000044
+:10DCE0000000000000000000000000000000000034
+:10DCF0000000000000000000000000000000000024
+:10DD00000000000000000000000000000000000013
+:10DD10000000000000000000000000000000000003
+:10DD200000000000000000000000000000000000F3
+:10DD300000000000000000000000000000000000E3
+:10DD400000000000000000000000000000000000D3
+:10DD500000000000000000000000000000000000C3
+:10DD600000000000000000000000000000000000B3
+:10DD700000000000000000000000000000000000A3
+:10DD80000000000000000000000000000000000093
+:10DD90000000000000000000000000000000000083
+:10DDA0000000000000000000000000000000000073
+:10DDB0000000000000000000000000000000000063
+:10DDC0000000000000000000000000000000000053
+:10DDD0000000000000000000000000000000000043
+:10DDE0000000000000000000000000000000000033
+:10DDF0000000000000000000000000000000000023
+:10DE00000000000000000000000000000000000012
+:10DE10000000000000000000000000000000000002
+:10DE200000000000000000000000000000000000F2
+:10DE300000000000000000000000000000000000E2
+:10DE400000000000000000000000000000000000D2
+:10DE500000000000000000000000000000000000C2
+:10DE600000000000000000000000000000000000B2
+:10DE700000000000000000000000000000000000A2
+:10DE80000000000000000000000000000000000092
+:10DE90000000000000000000000000000000000082
+:10DEA0000000000000000000000000000000000072
+:10DEB0000000000000000000000000000000000062
+:10DEC0000000000000000000000000000000000052
+:10DED0000000000000000000000000000000000042
+:10DEE0000000000000000000000000000000000032
+:10DEF0000000000000000000000000000000000022
+:10DF00000000000000000000000000000000000011
+:10DF10000000000000000000000000000000000001
+:10DF200000000000000000000000000000000000F1
+:10DF300000000000000000000000000000000000E1
+:10DF400000000000000000000000000000000000D1
+:10DF500000000000000000000000000000000000C1
+:10DF600000000000000000000000000000000000B1
+:10DF700000000000000000000000000000000000A1
+:10DF80000000000000000000000000000000000091
+:10DF90000000000000000000000000000000000081
+:10DFA0000000000000000000000000000000000071
+:10DFB0000000000000000000000000000000000061
+:10DFC0000000000000000000000000000000000051
+:10DFD0000000000000000000000000000000000041
+:10DFE0000000000000000000000000000000000031
+:10DFF0000000000000000000000000000000000021
+:10E000000000000000000000000000000000000010
+:10E010000000000000000000000000000000000000
+:10E0200000000000000000000000000000000000F0
+:10E0300000000000000000000000000000000000E0
+:10E0400000000000000000000000000000000000D0
+:10E0500000000000000000000000000000000000C0
+:10E0600000000000000000000000000000000000B0
+:10E0700000000000000000000000000000000000A0
+:10E080000000000000000000000000000000000090
+:10E090000000000000000000000000000000000080
+:10E0A0000000000000000000000000000000000070
+:10E0B0000000000000000000000000000000000060
+:10E0C0000000000000000000000000000000000050
+:10E0D0000000000000000000000000000000000040
+:10E0E0000000000000000000000000000000000030
+:10E0F0000000000000000000000000000000000020
+:10E10000000000000000000000000000000000000F
+:10E1100000000000000000000000000000000000FF
+:10E1200000000000000000000000000000000000EF
+:10E1300000000000000000000000000000000000DF
+:10E1400000000000000000000000000000000000CF
+:10E1500000000000000000000000000000000000BF
+:10E1600000000000000000000000000000000000AF
+:10E17000000000000000000000000000000000009F
+:10E18000000000000000000000000000000000008F
+:10E19000000000000000000000000000000000007F
+:10E1A000000000000000000000000000000000006F
+:10E1B000000000000000000000000000000000005F
+:10E1C000000000000000000000000000000000004F
+:10E1D000000000000000000000000000000000003F
+:10E1E000000000000000000000000000000000002F
+:10E1F000000000000000000000000000000000809F
+:10E20000000000000000000000000000000000000E
+:10E2100000000000000000000000000000000000FE
+:10E220000000000A000000000000000000000000E4
+:10E2300010000003000000000000000D0000000DB1
+:10E240003C020801244295C03C030801246397FC6A
+:10E25000AC4000000043202B1480FFFD244200044A
+:10E260003C1D080037BD9FFC03A0F0213C100800B6
+:10E27000261032103C1C0801279C95C00E0012BECF
+:10E28000000000000000000D3C02800030A5FFFFF0
+:10E2900030C600FF344301803C0880008D0901B87E
+:10E2A0000520FFFE00000000AC6400002404000212
+:10E2B000A4650008A066000AA064000BAC67001803
+:10E2C0003C03100003E00008AD0301B83C0560000A
+:10E2D0008CA24FF80440FFFE00000000ACA44FC029
+:10E2E0003C0310003C040200ACA44FC403E000084F
+:10E2F000ACA34FF89486000C00A050212488001491
+:10E3000000062B0200051080004448210109182B4B
+:10E310001060001100000000910300002C6400094F
+:10E320005080000991190001000360803C0D080134
+:10E3300025AD9258018D58218D67000000E000083E
+:10E340000000000091190001011940210109302B42
+:10E3500054C0FFF29103000003E000080000102108
+:10E360000A000CCC25080001910F0001240E000AC0
+:10E3700015EE00400128C8232F38000A1700003D81
+:10E38000250D00028D580000250F0006370E0100F4
+:10E39000AD4E0000910C000291AB000191A400026F
+:10E3A00091A60003000C2E00000B3C0000A71025D6
+:10E3B00000041A000043C8250326C025AD580004F8
+:10E3C000910E000691ED000191E7000291E5000336
+:10E3D000000E5E00000D6400016C30250007220075
+:10E3E00000C41025004518252508000A0A000CCC99
+:10E3F000AD430008910F000125040002240800022B
+:10E4000055E80001012020210A000CCC00804021A9
+:10E41000910C0001240B0003158B00160000000076
+:10E420008D580000910E000225080003370D0008EA
+:10E43000A14E00100A000CCCAD4D00009119000156
+:10E44000240F0004172F000B0000000091070002AA
+:10E45000910400038D43000000072A0000A410254A
+:10E460003466000425080004AD42000C0A000CCC00
+:10E47000AD46000003E000082402000127BDFFE8CC
+:10E48000AFBF0014AFB000100E00164E0080802108
+:10E490003C0480083485008090A600052403FFFE1C
+:10E4A0000200202100C310248FBF00148FB0001081
+:10E4B000A0A200050A00165827BD001827BDFFE8D6
+:10E4C000AFB00010AFBF00140E000FD40080802149
+:10E4D0003C06800834C5008090A40000240200504F
+:10E4E000308300FF106200073C09800002002021F9
+:10E4F0008FBF00148FB00010AD2001800A00108F74
+:10E5000027BD0018240801003C07800002002021DC
+:10E510008FBF00148FB00010ACE801800A00108F8C
+:10E5200027BD001827BDFF783C058008AFBE0080DE
+:10E53000AFB7007CAFB3006CAFB10064AFBF008475
+:10E54000AFB60078AFB50074AFB40070AFB200687A
+:10E55000AFB0006034A600803C0580008CB201287A
+:10E5600090C400098CA701043C020001309100FF17
+:10E5700000E218240000B8210000F021106000071C
+:10E58000000098213C0908008D2931F02413000176
+:10E59000252800013C010800AC2831F0ACA0008423
+:10E5A00090CC0005000C5827316A0001154000721C
+:10E5B000AFA0005090CD00002406002031A400FF41
+:10E5C00010860018240E0050108E009300000000EA
+:10E5D0003C1008008E1000DC260F00013C010800F2
+:10E5E000AC2F00DC0E0016C7000000000040182110
+:10E5F0008FBF00848FBE00808FB7007C8FB60078FD
+:10E600008FB500748FB400708FB3006C8FB2006848
+:10E610008FB100648FB000600060102103E000083B
+:10E6200027BD00880000000D3C1F8000AFA0003017
+:10E6300097E501168FE201043C04002030B9FFFF8A
+:10E64000004438240007182B00033140AFA60030E7
+:10E650008FF5010437F80C003C1600400338802188
+:10E6600002B6A02434C40040128000479215000D69
+:10E6700032A800201500000234860080008030217E
+:10E6800014C0009FAFA600303C0D800835A6008066
+:10E6900090CC0008318B0040516000063C06800899
+:10E6A000240E0004122E00A8240F0012122F003294
+:10E6B0003C06800834C401003C0280009447011AE3
+:10E6C0009619000E909F00088E18000830E3FFFF97
+:10E6D00003F9B00432B40004AFB6005CAFA3005835
+:10E6E0008E1600041280002EAFB8005434C3008090
+:10E6F000906800083105004014A0002500000000CB
+:10E700008C70005002D090230640000500000000ED
+:10E710008C71003402D1A82306A201678EE20008A2
+:10E72000126000063C1280003C1508008EB531F4E2
+:10E7300026B600013C010800AC3631F4AE4000447E
+:10E74000240300018FBF00848FBE00808FB7007C40
+:10E750008FB600788FB500748FB400708FB3006CE3
+:10E760008FB200688FB100648FB00060006010212C
+:10E7700003E0000827BD00880E000D2800002021BE
+:10E780000A000D75004018210A000D9500C02021D7
+:10E790000E00171702C020211440FFE10000000006
+:10E7A0003C0B8008356400808C8A003402CA482300
+:10E7B0000520001D000000003C1E08008FDE310017
+:10E7C00027D700013C010800AC3731001260000679
+:10E7D000024020213C1408008E9431F42690000160
+:10E7E0003C010800AC3031F40E00164E3C1E80088F
+:10E7F00037CD008091B700250240202136EE00047D
+:10E800000E001658A1AE00250E000CAC02402021CF
+:10E810000A000DCA240300013C17080126F796C020
+:10E820000A000D843C1F80008C86003002C66023E5
+:10E830001980000C2419000C908F004F3C14080024
+:10E840008E94310032B500FC35ED0001268E0001BA
+:10E850003C010800AC2E3100A08D004FAFA0005845
+:10E860002419000CAFB900308C9800300316A02397
+:10E870001A80010B8FA300580074F82A17E0FFD309
+:10E88000000000001074002A8FA5005802D4B021A7
+:10E8900000B410233044FFFFAFA4005832A8000298
+:10E8A0001100002E32AB00103C15800836B00080FD
+:10E8B0009216000832D30040526000FB8EE200083E
+:10E8C0000E00164E02402021240A0018A20A000958
+:10E8D000921100052409FFFE024020210229902404
+:10E8E0000E001658A2120005240400390000282149
+:10E8F0000E0016F2240600180A000DCA24030001B7
+:10E9000092FE000C3C0A800835490080001EBB00C6
+:10E910008D27003836F10081024020213225F08118
+:10E920000E000C9B30C600FF0A000DC10000000065
+:10E930003AA7000130E300011460FFA402D4B02123
+:10E940000A000E1D00000000024020210E001734B6
+:10E95000020028210A000D75004018211160FF7087
+:10E960003C0F80083C0D800835EE00808DC40038D7
+:10E970008FA300548DA60004006660231D80FF68ED
+:10E98000000000000064C02307020001AFA400548F
+:10E990003C1F08008FFF31E433F9000113200015FC
+:10E9A0008FAC00583C07800094E3011A10600012FD
+:10E9B0003C0680080E00216A024020213C03080129
+:10E9C000906396F13064000214800145000000005D
+:10E9D000306C0004118000078FAC0058306600FBDB
+:10E9E0003C010801A02696F132B500FCAFA000580A
+:10E9F0008FAC00583C06800834D30080AFB40018B8
+:10EA0000AFB60010AFAC00143C088000950B01209D
+:10EA10008E6F0030966A005C8FA3005C8FBF003061
+:10EA20003169FFFF3144FFFF8FAE005401341021E4
+:10EA3000350540000064382B0045C82103E7C02598
+:10EA4000AFB90020AFAF0028AFB80030AFAF00249F
+:10EA5000AFA0002CAFAE0034926D000831B40008B6
+:10EA6000168000BB020020218EE200040040F8095D
+:10EA700027A400108FAF003031F300025660000170
+:10EA800032B500FE3C048008349F008093F90008F2
+:10EA900033380040530000138FA400248C850004F9
+:10EAA0008FA7005410A700D52404001432B0000131
+:10EAB0001200000C8FA400242414000C1234011A3C
+:10EAC0002A2D000D11A001022413000E240E000AAD
+:10EAD000522E0001241E00088FAF002425E40001FF
+:10EAE000AFA400248FAA00143C0B80083565008079
+:10EAF000008A48218CB10030ACA9003090A4004EAF
+:10EB00008CA700303408FFFF0088180400E3F821C8
+:10EB1000ACBF00348FA600308FB900548FB8005CB2
+:10EB200030C200081040000B033898218CAC002044
+:10EB3000119300D330C600FF92EE000C8FA7003473
+:10EB400002402021000E6B0035B400800E000C9BAB
+:10EB50003285F0803C028008345000808E0F0030F7
+:10EB600001F1302318C00097264800803C070800B8
+:10EB70008CE731E42404FF80010418243118007F5D
+:10EB80003C1F80003C19800430F10001AFE300908D
+:10EB900012200006031928213C030801906396F116
+:10EBA00030690008152000C6306A00F73C10800864
+:10EBB00036040080908C004F318B000115600042BC
+:10EBC000000000003C0608008CC6319830CE0010D2
+:10EBD00051C0004230F9000190AF006B55E0003F9A
+:10EBE00030F9000124180001A0B8006B3C1180002E
+:10EBF0009622007A24470064A48700123C0D800806
+:10EC000035A5008090B40008329000401600000442
+:10EC10003C03800832AE000115C0008B00000000EC
+:10EC2000346400808C86002010D3000A3463010015
+:10EC30008C67000002C7782319E000978FBF00544B
+:10EC4000AC93002024130001AC760000AFB3005059
+:10EC5000AC7F000417C0004E000000008FA90050D8
+:10EC60001520000B000000003C030801906396F1A2
+:10EC7000306A00011140002E8FAB0058306400FE56
+:10EC80003C010801A02496F10A000D75000018212E
+:10EC90000E000CAC024020210A000F1300000000FF
+:10ECA0000A000E200000A0210040F80924040017EB
+:10ECB0000A000DCA240300010040F80924040016CC
+:10ECC0000A000DCA240300019094004F240DFFFE9A
+:10ECD000028D2824A085004F30F900011320000682
+:10ECE0003C0480083C030801906396F1307F0010DB
+:10ECF00017E00051306800EF34900080240A0001D2
+:10ED0000024020210E00164EA60A00129203002592
+:10ED100024090001AFA90050346200010240202103
+:10ED20000E001658A20200250A000EF93C0D8008BC
+:10ED30001160FE83000018218FA5003030AC000464
+:10ED40001180FE2C8FBF00840A000DCB240300012C
+:10ED500027A500380E000CB6AFA000385440FF4382
+:10ED60008EE200048FB40038329001005200FF3F61
+:10ED70008EE200048FA3003C8E6E0058006E682364
+:10ED800005A3FF39AE6300580A000E948EE200041A
+:10ED90000E00164E024020213C038008346800809B
+:10EDA000024020210E001658A11E000903C0302188
+:10EDB000240400370E0016F2000028210A000F116B
+:10EDC0008FA900508FAB00185960FF8D3C0D800853
+:10EDD0000E00164E02402021920C00252405000151
+:10EDE000AFA5005035820004024020210E001658C5
+:10EDF000A20200250A000EF93C0D800812240059D9
+:10EE00002A2300151060004D240900162408000C68
+:10EE10005628FF2732B000013C0A8008914C001BA5
+:10EE20002406FFBD241E000E01865824A14B001BA2
+:10EE30000A000EA532B000013C010801A02896F19D
+:10EE40000A000EF93C0D80088CB500308EFE0008DB
+:10EE50002404001826B6000103C0F809ACB600303F
+:10EE60003C030801906396F13077000116E0FF81C2
+:10EE7000306A00018FB200300A000D753243000481
+:10EE80003C1080009605011A50A0FF2B34C60010DC
+:10EE90000A000EC892EE000C8C6200001456FF6D42
+:10EEA000000000008C7800048FB9005403388823D8
+:10EEB0000621FF638FBF00540A000F0E0000000000
+:10EEC0003C010801A02A96F10A000F3030F9000138
+:10EED0001633FF028FAF00240A000EB0241E00106C
+:10EEE0000E00164E024020213C0B80083568008041
+:10EEF00091090025240A0001AFAA0050353300040F
+:10EF0000024020210E001658A11300253C050801DF
+:10EF100090A596F130A200FD3C010801A02296F1D7
+:10EF20000A000E6D004018212411000E53D1FEEA94
+:10EF3000241E00100A000EAF241E00165629FEDC07
+:10EF400032B000013C0A8008914C001B2406FFBD32
+:10EF5000241E001001865824A14B001B0A000EA598
+:10EF600032B000010A000EA4241E00123C038000EF
+:10EF70008C6201B80440FFFE24040800AC6401B8B0
+:10EF800003E000080000000030A5FFFF30C6FFFFCF
+:10EF90003C0780008CE201B80440FFFE34EA0180A7
+:10EFA000AD440000ACE400203C0480089483004899
+:10EFB0003068FFFF11000016AF88000824AB001274
+:10EFC000010B482B512000133C04800034EF01005A
+:10EFD00095EE00208F890000240D001A31CCFFFF30
+:10EFE00031274000A14D000B10E000362583FFFEC5
+:10EFF0000103C02B170000348F9900048F88000490
+:10F00000A5430014350700010A001003AF87000470
+:10F010003C04800024030003348201808F890000B7
+:10F020008F870004A043000B3C088000350C018052
+:10F03000A585000EA585001A8F85000C30EB800099
+:10F04000A5890010AD850028A58600081160000F75
+:10F050008F85001435190100972A00163158FFFCDE
+:10F06000270F000401E870218DCD400031A6FFFF7D
+:10F0700014C000072403BFFF3C02FFFF34487FFF9A
+:10F0800000E83824AF8700048F8500142403BFFFF5
+:10F090003C04800000E3582434830180A46B0026E4
+:10F0A000AC69002C10A0000300054C02A465001000
+:10F0B000A46900263C071000AC8701B803E00008F3
+:10F0C000000000008F990004240AFFFE032A382460
+:10F0D0000A001003AF87000427BDFFE88FA20028B5
+:10F0E00030A5FFFF30C6FFFFAFBF0010AF87000C99
+:10F0F000AF820014AF8000040E000FDBAF80000071
+:10F100008FBF001027BD001803E00008AF80001477
+:10F110003C06800034C4007034C701008C8A0000B3
+:10F1200090E500128F84000027BDFFF030A300FFA0
+:10F13000000318823082400010400037246500032D
+:10F140000005C8800326C0218F0E4000246F0004F4
+:10F15000000F6880AFAE000001A660218D8B4000DB
+:10F16000AFAB000494E900163128FFFC01063821FA
+:10F170008CE64000AFA600088FA9000800003021EF
+:10F18000000028213C07080024E701000A0010675E
+:10F19000240800089059000024A500012CAC000CA4
+:10F1A0000079C0210018788001E770218DCD000022
+:10F1B0001180000600CD302603A5102114A8FFF50C
+:10F1C00000051A005520FFF4905900003C0480000F
+:10F1D000348700703C0508008CA531048CE30000E6
+:10F1E0002CA2002010400009006A38230005488046
+:10F1F0003C0B0800256B3108012B402124AA00019B
+:10F20000AD0700003C010800AC2A310400C0102109
+:10F2100003E0000827BD0010308220001040000BE2
+:10F2200000055880016648218D24400024680004B0
+:10F2300000083880AFA4000000E618218C6540006B
+:10F24000AFA000080A001057AFA500040000000D91
+:10F250000A0010588FA9000827BDFFE03C07800076
+:10F2600034E60100AFBF001CAFB20018AFB100140C
+:10F27000AFB0001094C5000E8F87000030A4FFFFD0
+:10F280002483000430E2400010400010AF830028C7
+:10F290003C09002000E940241100000D30EC800002
+:10F2A0008F8A0004240BBFFF00EB38243543100085
+:10F2B000AF87000030F220001640000B3C1900041C
+:10F2C000241FFFBF0A0010B7007F102430EC80001D
+:10F2D000158000423C0E002030F220001240FFF862
+:10F2E0008F8300043C19000400F9C0241300FFF5CB
+:10F2F000241FFFBF34620040AF82000430E20100EF
+:10F300001040001130F010008F83002C10600006B8
+:10F310003C0F80003C05002000E52024148000C044
+:10F320003C0800043C0F800035EE010095CD001E26
+:10F3300095CC001C31AAFFFF000C5C00014B482556
+:10F34000AF89000C30F010001200000824110001F9
+:10F3500030F100201620008B3C18100000F890249B
+:10F36000164000823C040C002411000130E801002A
+:10F370001500000B3C0900018F85000430A94000F6
+:10F38000152000073C0900013C0C1F0100EC58242B
+:10F390003C0A1000116A01183C1080003C09000171
+:10F3A00000E9302410C000173C0B10003C18080086
+:10F3B0008F1800243307000214E0014024030001E9
+:10F3C0008FBF001C8FB200188FB100148FB00010D7
+:10F3D0000060102103E0000827BD002000EE682433
+:10F3E00011A0FFBE30F220008F8F00043C11FFFF00
+:10F3F00036307FFF00F0382435E380000A0010A685
+:10F40000AF87000000EB102450400065AF8000245F
+:10F410008F8C002C3C0D0F0000ED18241580008807
+:10F42000AF83001030E8010011000086938F0010B8
+:10F430003C0A0200106A00833C1280003650010032
+:10F44000920500139789002A3626000230AF00FF8C
+:10F4500025EE0004000E19C03C0480008C9801B811
+:10F460000700FFFE34880180AD0300003C198008CE
+:10F47000AC830020973100483225FFFF10A0015CCB
+:10F48000AF8500082523001200A3F82B53E0015993
+:10F490008F850004348D010095AC00202402001AF1
+:10F4A00030E44000318BFFFFA102000B108001927D
+:10F4B0002563FFFE00A3502B154001908F8F0004A1
+:10F4C000A50300148F88000435050001AF850004F2
+:10F4D0003C08800035190180A729000EA729001AD1
+:10F4E0008F89000C30B18000A7270010AF290028B9
+:10F4F000A72600081220000E3C04800035020100FF
+:10F50000944C0016318BFFFC256400040088182100
+:10F510008C7F400033E6FFFF14C000053C048000F0
+:10F520003C0AFFFF354D7FFF00AD2824AF85000466
+:10F53000240EBFFF00AE402434850180A4A800261D
+:10F54000ACA7002C3C071000AC8701B800001821C4
+:10F550008FBF001C8FB200188FB100148FB0001045
+:10F560000060102103E0000827BD00203C020BFFD3
+:10F5700000E41824345FFFFF03E3C82B5320FF7B14
+:10F58000241100013C0608008CC6002C24C5000193
+:10F590003C010800AC25002C0A0010D42411000501
+:10F5A0008F85002410A0002FAF80001090A30000D2
+:10F5B000146000792419000310A0002A30E601002D
+:10F5C00010C000CC8F860010241F000210DF00C97D
+:10F5D0008F8B000C3C0708008CE7003824E4FFFF09
+:10F5E00014E0000201641824000018213C0D0800FA
+:10F5F00025AD0038006D1021904C00048F85002847
+:10F6000025830004000321C030A5FFFF3626000239
+:10F610000E000FDB000000000A00114D0000182151
+:10F6200000E8302414C0FF403C0F80000E00103D65
+:10F63000000000008F8700000A0010CAAF82000C93
+:10F64000938F00103C18080127189640000F90C0B7
+:10F6500002588021AF9000248F85002414A0FFD38E
+:10F66000AF8F00103C0480008C86400030C5010044
+:10F6700010A000BC322300043C0C08008D8C002438
+:10F6800024120004106000C23190000D3C04800080
+:10F690008C8D40003402FFFF11A201003231FFFBCC
+:10F6A0008C884000310A01005540000124110010EF
+:10F6B00030EE080011C000BE2419FFFB8F9800280F
+:10F6C0002F0F03EF51E000010219802430E90100FF
+:10F6D00011200014320800018F87002C14E000FB79
+:10F6E0008F8C000C3C05800034AB0100917F00132F
+:10F6F00033E300FF246A00042403FFFE0203802496
+:10F70000000A21C012000002023230253226FFFF1B
+:10F710000E000FDB9785002A1200FF290000182138
+:10F72000320800011100000D32180004240E0001FF
+:10F73000120E0002023230253226FFFF9785002A82
+:10F740000E000FDB00002021240FFFFE020F80249B
+:10F750001200FF1B00001821321800045300FF188C
+:10F760002403000102323025241200045612000145
+:10F770003226FFFF9785002A0E000FDB24040100CC
+:10F780002419FFFB021988241220FF0D0000182104
+:10F790000A0010E9240300011079009C00003021C8
+:10F7A00090AD00012402000211A200BE30EA004028
+:10F7B00090B90001241800011338007F30E900409F
+:10F7C0008CA600049785002A00C020210E000FDBC4
+:10F7D0003626000200004021010018218FBF001CC6
+:10F7E0008FB200188FB100148FB00010006010218C
+:10F7F00003E0000827BD0020360F010095EE000C45
+:10F8000031CD020015A0FEE63C0900013C1880083D
+:10F81000971200489789002A362600023248FFFFD7
+:10F82000AF8800083C0380008C7101B80620FFFE01
+:10F83000346A0180AD4000001100008E3C0F800052
+:10F84000253F0012011FC82B1320008B240E00033C
+:10F85000346C0100958B00202402001A30E4400033
+:10F860003163FFFFA142000B108000A72463FFFE5D
+:10F870000103682B15A000A52408FFFE34A5000194
+:10F88000A5430014AF8500043C0480002412BFFF90
+:10F8900000B2802434850180A4A9000EA4A9001A16
+:10F8A000A4A60008A4B00026A4A700103C071000DE
+:10F8B000AC8701B80A00114D000018213C038000FC
+:10F8C00034640100949F000E3C1908008F3900D861
+:10F8D0002404008033E5FFFF273100013C010800CC
+:10F8E000AC3100D80E000FDB240600030A00114DD6
+:10F8F00000001821240A000210CA00598F85002830
+:10F900003C0308008C6300D0240E0001106E005EE2
+:10F910002CCF000C24D2FFFC2E5000041600002136
+:10F9200000002021241800021078001B2CD9000CA4
+:10F9300024DFFFF82FE900041520FF330000202109
+:10F9400030EB020051600004000621C054C00022C8
+:10F9500030A5FFFF000621C030A5FFFF0A00117D82
+:10F96000362600023C0908008D29002431300001B0
+:10F970005200FEF7000018219785002A3626000263
+:10F980000E000FDB000020210A00114D000018219D
+:10F990000A00119C241200021320FFE624DFFFF866
+:10F9A0000000202130A5FFFF0A00117D362600024D
+:10F9B0000A0011AC021980245120FF828CA6000499
+:10F9C0003C05080190A5964110A0FF7E2408000187
+:10F9D0000A0011F0010018210E000FDB3226000191
+:10F9E0008F8600108F8500280A00124F000621C064
+:10F9F0008F8500043C18800024120003371001801A
+:10FA0000A212000B0A00112E3C08800090A30001F6
+:10FA1000241100011071FF70240800012409000264
+:10FA20005069000430E60040240800010A0011F08B
+:10FA30000100182150C0FFFD240800013C0C80008B
+:10FA4000358B01009563001094A40002307FFFFF06
+:10FA5000509FFF62010018210A001284240800014F
+:10FA60002CA803EF1100FE56240300010A001239EE
+:10FA700000000000240E000335EA0180A14E000BB7
+:10FA80000A00121C3C04800011E0FFA2000621C005
+:10FA900030A5FFFF0A00117D362600020A0011A5DD
+:10FAA000241100201140FFC63C1280003650010096
+:10FAB000960F001094AE000231E80FFF15C8FFC08A
+:10FAC000000000000A0011E690B900013C060800A1
+:10FAD0008CC6003824C4FFFF14C00002018418241F
+:10FAE000000018213C0D080025AD0038006D1021E4
+:10FAF0000A0011B6904300048F8F0004240EFFFE0D
+:10FB00000A00112C01EE28242408FFFE0A00121A14
+:10FB100000A8282427BDFFC8AFB00010AFBF003435
+:10FB20003C10600CAFBE0030AFB7002CAFB6002861
+:10FB3000AFB50024AFB40020AFB3001CAFB20018C3
+:10FB4000AFB100148E0E5000240FFF7F3C068000E2
+:10FB500001CF682435AC380C240B0003AE0C5000E8
+:10FB6000ACCB00083C010800AC2000200E001819A6
+:10FB7000000000003C0A0010354980513C06601628
+:10FB8000AE09537C8CC700003C0860148D0500A0B2
+:10FB90003C03FFFF00E320243C02535300051FC237
+:10FBA0001482000634C57C000003A08002869821E0
+:10FBB0008E7200043C116000025128218CBF007C31
+:10FBC0008CA200783C1E600037C420203C05080150
+:10FBD00024A59288AF820018AF9F001C0E0016DD8E
+:10FBE0002406000A3C190001273996403C01080010
+:10FBF000AC3931DC0E0020DDAF8000148FD708084F
+:10FC00002418FFF03C15570902F8B02412D502F56C
+:10FC100024040001AF80002C3C1480003697018042
+:10FC20003C1E080127DE9644369301008E900000AA
+:10FC30003205000310A0FFFD3207000110E000882C
+:10FC4000320600028E7100283C048000AE91002034
+:10FC50008E6500048E66000000A0382100C040219F
+:10FC60008C8301B80460FFFE3C0B0010240A0800DE
+:10FC700000AB4824AC8A01B8552000E0240BBFFF3C
+:10FC80009675000E3C1208008E52002030AC4000E9
+:10FC900032AFFFFF264E000125ED00043C010800B5
+:10FCA000AC2E0020118000E8AF8D00283C18002009
+:10FCB00000B8B02412C000E530B980002408BFFFAE
+:10FCC00000A8382434C81000AF87000030E62000B8
+:10FCD00010C000E92409FFBF3C03000400E328240E
+:10FCE00010A00002010910243502004030EA010092
+:10FCF00011400010AF8200048F8B002C11600007B0
+:10FD00003C0D002000ED6024118000043C0F000435
+:10FD100000EF702411C00239000000009668001E38
+:10FD20009678001C3115FFFF0018B40002B690252C
+:10FD3000AF92000C30F910001320001324150001BD
+:10FD400030FF002017E0000A3C04100000E41024FB
+:10FD50001040000D3C0A0C003C090BFF00EA18247F
+:10FD60003525FFFF00A3302B10C0000830ED010047
+:10FD70003C0C08008D8C002C24150005258B0001FF
+:10FD80003C010800AC2B002C30ED010015A0000B4D
+:10FD90003C0500018F85000430AE400055C00007CF
+:10FDA0003C0500013C161F0100F690243C0F10009A
+:10FDB000124F01CE000000003C05000100E5302498
+:10FDC00010C000AF3C0C10003C1F08008FFF002447
+:10FDD00033E90002152000712403000100601021A6
+:10FDE000104000083C0680003C08800035180100E7
+:10FDF0008F0F00243C056020ACAF00140000000011
+:10FE00003C0680003C194000ACD9013800000000DD
+:10FE10005220001332060002262B0140262C0080BF
+:10FE2000240EFF80016E2024018E6824000D1940ED
+:10FE3000318A007F0004A9403172007F3C16200007
+:10FE400036C20002006A482502B2382500E2882541
+:10FE50000122F825ACDF0830ACD1083032060002B0
+:10FE600010C0FF723C188000370501408CA80000CC
+:10FE700024100040AF08002090AF000831E300706C
+:10FE8000107000D428790041532000082405006038
+:10FE9000241100201071000E3C0A40003C09800033
+:10FEA000AD2A01780A001304000000001465FFFB6E
+:10FEB0003C0A40000E001FFA000000003C0A40000F
+:10FEC0003C098000AD2A01780A00130400000000FC
+:10FED00090A90009241F00048CA70000312800FF0E
+:10FEE000111F01B22503FFFA2C7200061240001404
+:10FEF0003C0680008CA9000494A4000A310500FF90
+:10FF000000095E022D6A00083086FFFF15400002DE
+:10FF10002567000424070003240C000910AC01FA33
+:10FF200028AD000A11A001DE2410000A240E0008EA
+:10FF300010AE0028000731C000C038213C06800008
+:10FF40008CD501B806A0FFFE34D20180AE47000078
+:10FF500034CB0140916E0008240300023C0A4000AB
+:10FF600031C400FF00046A0001A86025A64C000807
+:10FF7000A243000B9562000A3C0810003C09800077
+:10FF8000A64200108D670004AE470024ACC801B83B
+:10FF9000AD2A01780A001304000000003C0A80002A
+:10FFA000354401009483000E3C0208008C4200D8C6
+:10FFB000240400803065FFFF245500013C01080047
+:10FFC000AC3500D80E000FDB240600030A001370C6
+:10FFD000000018210009320230D900FF2418000166
+:10FFE0001738FFD5000731C08F910020262200016D
+:10FFF000AF8200200A0013C800C0382100CB2024A3
+:020000021000EC
+:10000000AF85000010800008AF860004240D87FF34
+:1000100000CD6024158000083C0E006000AE302446
+:1000200010C00005000000000E000D42000000009E
+:100030000A001371000000000E0016050000000009
+:100040000A0013710000000030B980005320FF1F28
+:10005000AF8500003C02002000A2F82453E0FF1B03
+:10006000AF8500003C07FFFF34E47FFF00A4382485
+:100070000A00132B34C880000A001334010910242D
+:1000800000EC58245160005AAF8000248F8D002C62
+:100090003C0E0F0000EE182415A00075AF83001071
+:1000A00030EF010011E00073939800103C12020041
+:1000B000107200703C06800034D9010093280013B0
+:1000C0009789002A36A60002311800FF271600047F
+:1000D000001619C03C0480008C8501B804A0FFFE06
+:1000E00034880180AD0300003C158008AC830020FB
+:1000F00096BF004833E5FFFF10A001BCAF850008A4
+:100100002523001200A3102B504001B98F85000455
+:10011000348D010095AC0020240B001A30E440001F
+:10012000318AFFFFA10B000B108001BA2543FFFEAF
+:1001300000A3702B15C001B88F9600048F8F0004A8
+:10014000A503001435E50001AF8500043C088000DC
+:1001500035150180A6A9000EA6A9001A8F89000CEA
+:1001600030BF8000A6A70010AEA90028A6A60008F0
+:1001700013E0000F3C0F8000350C0100958B00163A
+:10018000316AFFFC25440004008818218C6240007D
+:100190003046FFFF14C000072416BFFF3C0EFFFFD0
+:1001A00035CD7FFF00AD2824AF8500043C0F8000D3
+:1001B0002416BFFF00B6902435E50180A4B20026C6
+:1001C000ACA7002C3C071000ADE701B80A00137083
+:1001D000000018210E00165D000000003C0A4000DF
+:1001E0003C098000AD2A01780A00130400000000D9
+:1001F0008F85002410A00027AF80001090A300007E
+:10020000106000742409000310690101000030210E
+:1002100090AE0001240D000211CD014230EF0040EC
+:1002200090A90001241F0001113F000930E20040A5
+:100230008CA600049785002A00C020210E000FDB49
+:1002400036A60002000040210A00137001001821A8
+:100250005040FFF88CA600043C07080190E7964147
+:1002600010E0FFF4240800010A00137001001821B7
+:10027000939800103C1F080127FF96400018C8C043
+:10028000033F4021AF8800248F85002414A0FFDBAA
+:10029000AF9800103C0480008C86400030C50100FF
+:1002A00010A0008732AB00043C0C08008D8C0024A9
+:1002B00024160004156000033192000D241600027C
+:1002C0003C0480008C8E4000340DFFFF11CD0113E3
+:1002D00032B5FFFB8C984000330F010055E0000160
+:1002E0002415001030E80800110000382409FFFB35
+:1002F0008F9F00282FF903EF53200001024990241B
+:1003000030E2010010400014325F00018F87002CA2
+:1003100014E0010E8F8C000C3C0480003486010038
+:1003200090C5001330AA00FF25430004000321C03C
+:100330002419FFFE025990241240000202B6302513
+:1003400032A6FFFF0E000FDB9785002A1240FEA3A6
+:1003500000001821325F000113E0000D3247000455
+:10036000240900011249000202B6302532A6FFFF1F
+:100370009785002A0E000FDB000020212402FFFEDB
+:10038000024290241240FE950000182132470004DA
+:1003900050E0FE922403000102B63025241600042A
+:1003A0005656000132A6FFFF9785002A0E000FDB8C
+:1003B000240401002403FFFB0243A82412A0FE87AB
+:1003C000000018210A001370240300010A0014B968
+:1003D0000249902410A0FFAF30E5010010A00017E3
+:1003E0008F8600102403000210C300148F84000CB9
+:1003F0003C0608008CC6003824CAFFFF14C0000267
+:10040000008A1024000010213C0E080025CE003880
+:10041000004E682191AC00048F850028258B0004D4
+:10042000000B21C030A5FFFF36A600020E000FDB37
+:10043000000000000A00137000001821240F0002C1
+:1004400010CF0088241600013C0308008C6300D004
+:100450001076008D8F85002824D9FFFC2F280004FA
+:100460001500006300002021241F0002107F005DA2
+:100470002CC9000C24C3FFF82C6200041440FFE9CF
+:100480000000202130EA020051400004000621C093
+:1004900054C0000530A5FFFF000621C030A5FFFFB6
+:1004A0000A00150436A600020E000FDB32A600017A
+:1004B0008F8600108F8500280A001520000621C0B5
+:1004C0003C0A08008D4A0024315200015240FE438C
+:1004D000000018219785002A36A600020E000FDBC7
+:1004E000000020210A001370000018219668000CFB
+:1004F000311802005700FE313C0500013C1F800806
+:1005000097F900489789002A36A600023328FFFF92
+:10051000AF8800083C0380008C7501B806A0FFFE80
+:100520003C04800034820180AC400000110000B621
+:1005300024180003252A0012010A182B106000B2AB
+:1005400000000000966F00203C0E8000240D001A71
+:1005500031ECFFFF35CA018030EB4000A14D000BAC
+:10056000116000B02583FFFE0103902B164000AE02
+:100570002416FFFE34A50001A5430014AF85000436
+:100580002419BFFF00B94024A6E9000EA6E9001A0D
+:10059000A6E60008A6E80026A6E700103C07100023
+:1005A000AE8701B80A001370000018213C048000D7
+:1005B0008C8201B80440FFFE349601802415001C93
+:1005C000AEC70000A2D5000B3C071000AC8701B8F5
+:1005D0003C0A40003C098000AD2A01780A0013045F
+:1005E000000000005120FFA424C3FFF800002021D8
+:1005F00030A5FFFF0A00150436A600020E00103DCC
+:10060000000000008F8700000A001346AF82000C34
+:1006100090A30001241500011075FF0B24080001B0
+:10062000240600021066000430E2004024080001A5
+:100630000A001370010018215040FFFD240800013A
+:100640003C0C8000358B0100956A001094A40002D8
+:100650003143FFFF5083FDE1010018210A00158599
+:10066000240800018F8500282CB203EF1240FDDB27
+:10067000240300013C0308008C6300D02416000111
+:100680001476FF7624D9FFFC2CD8000C1300FF72DF
+:10069000000621C030A5FFFF0A00150436A600029F
+:1006A00010B00037240F000B14AFFE23000731C039
+:1006B000312600FF00065600000A4E0305220047BF
+:1006C00030C6007F0006F8C03C16080126D69640CA
+:1006D00003F68021A2000001A20000003C0F600090
+:1006E0008DF918202405000100C588040011302769
+:1006F0000326C024000731C000C03821ADF81820FF
+:100700000A0013C8A60000028F850020000731C030
+:1007100024A2FFFF0A0013F6AF8200200A0014B2E1
+:100720002415002011E0FECC3C1980003728010080
+:100730009518001094B6000233120FFF16D2FEC6B1
+:10074000000000000A00148290A900013C0B080080
+:100750008D6B0038256DFFFF15600002018D1024A0
+:10076000000010213C080800250800380048C0217E
+:10077000930F000425EE00040A0014C5000E21C0EA
+:1007800000065202241F00FF115FFDEB000731C07D
+:10079000000A20C03C0E080125CE9640008EA821FC
+:1007A000009E602100095C02240D00013C076000EE
+:1007B000A2AD0000AD860000A2AB00018CF21820B3
+:1007C00024030001014310040242B025ACF61820B6
+:1007D00000C038210A0013C8A6A900020A0015AA01
+:1007E000AF8000200A0012FFAF84002C8F85000428
+:1007F0003C1980002408000337380180A308000B4F
+:100800000A00144D3C088000A2F8000B0A00155A9B
+:100810002419BFFF8F9600042412FFFE0A00144B18
+:1008200002D228242416FFFE0A00155800B62824F8
+:100830003C038000346401008C85000030A2003E3F
+:100840001440000800000000AC6000488C870000E5
+:1008500030E607C010C0000500000000AC60004C8E
+:10086000AC60005003E0000824020001AC600054BA
+:10087000AC6000408C880000310438001080FFF923
+:10088000000000002402000103E00008AC60004406
+:100890003C0380008C6201B80440FFFE3467018095
+:1008A000ACE4000024080001ACE00004A4E500086A
+:1008B00024050002A0E8000A34640140A0E5000B12
+:1008C0009483000A14C00008A4E30010ACE00024E4
+:1008D0003C07800034E901803C041000AD20002872
+:1008E00003E00008ACE401B88C8600043C0410006E
+:1008F000ACE600243C07800034E90180AD200028EC
+:1009000003E00008ACE401B83C0680008CC201B8EA
+:100910000440FFFE34C7018024090002ACE400005B
+:10092000ACE40004A4E50008A0E9000A34C50140D5
+:10093000A0E9000B94A8000A3C041000A4E80010F1
+:10094000ACE000248CA30004ACE3002803E0000822
+:10095000ACC401B83C039000346200010082202541
+:100960003C038000AC6400208C65002004A0FFFEE6
+:100970000000000003E00008000000003C028000CE
+:10098000344300010083202503E00008AC4400202C
+:1009900027BDFFE03C098000AFBF0018AFB10014D5
+:1009A000AFB00010352801408D10000091040009FF
+:1009B0009107000891050008308400FF30E600FF31
+:1009C00000061A002C820081008330251040002A86
+:1009D00030A50080000460803C0D080125AD92B078
+:1009E000018D58218D6A00000140000800000000C0
+:1009F0003C038000346201409445000A14A0001EAC
+:100A00008F91FCC09227000530E6000414C0001A44
+:100A1000000000000E00164E02002021922A000560
+:100A200002002021354900040E001658A2290005B5
+:100A30009228000531040004148000020000000028
+:100A40000000000D922D0000240B002031AC00FFAF
+:100A5000158B00093C0580008CAE01B805C0FFFE77
+:100A600034B10180AE3000003C0F100024100005AE
+:100A7000A230000BACAF01B80000000D8FBF001812
+:100A80008FB100148FB0001003E0000827BD0020D4
+:100A90000200202100C028218FBF00188FB1001450
+:100AA0008FB00010240600010A00161D27BD00208B
+:100AB0000000000D0200202100C028218FBF001877
+:100AC0008FB100148FB00010000030210A00161DF5
+:100AD00027BD002014A0FFE8000000000200202134
+:100AE0008FBF00188FB100148FB0001000C02821F4
+:100AF0000A00163B27BD00203C0780008CEE01B8A1
+:100B000005C0FFFE34F00180241F0002A21F000B6D
+:100B100034F80140A60600089719000A3C0F10009F
+:100B2000A61900108F110004A6110012ACEF01B835
+:100B30000A0016998FBF001827BDFFE8AFBF00104D
+:100B40000E000FD4000000003C0280008FBF001098
+:100B500000002021AC4001800A00108F27BD001842
+:100B60003084FFFF30A5FFFF108000070000182130
+:100B7000308200011040000200042042006518216C
+:100B80001480FFFB0005284003E0000800601021EE
+:100B900010C00007000000008CA2000024C6FFFF68
+:100BA00024A50004AC82000014C0FFFB24840004D0
+:100BB00003E000080000000010A0000824A3FFFFCD
+:100BC000AC86000000000000000000002402FFFFCF
+:100BD0002463FFFF1462FFFA2484000403E000088A
+:100BE000000000003C03800027BDFFF83462018054
+:100BF000AFA20000308C00FF30AD00FF30CE00FF10
+:100C00003C0B80008D6401B80480FFFE00000000F2
+:100C10008FA900008D6801288FAA00008FA700000F
+:100C20008FA400002405000124020002A085000A10
+:100C30008FA30000359940003C051000A062000B16
+:100C40008FB800008FAC00008FA600008FAF0000AF
+:100C500027BD0008AD280000AD400004AD80002491
+:100C6000ACC00028A4F90008A70D0010A5EE0012E2
+:100C700003E00008AD6501B83C06800827BDFFE829
+:100C800034C50080AFBF001090A7000924020012F5
+:100C900030E300FF1062000B008030218CA8005070
+:100CA00000882023048000088FBF00108CAA003425
+:100CB000240400390000282100CA4823052000052B
+:100CC000240600128FBF00102402000103E0000878
+:100CD00027BD00180E0016F2000000008FBF0010A4
+:100CE0002402000103E0000827BD001827BDFFC84B
+:100CF000AFB20030AFB00028AFBF0034AFB1002CAE
+:100D000000A0802190A5000D30A6001010C000109A
+:100D1000008090213C0280088C4400048E0300086F
+:100D20001064000C30A7000530A6000510C0009329
+:100D3000240400018FBF00348FB200308FB1002C2B
+:100D40008FB000280080102103E0000827BD003884
+:100D500030A7000510E0000F30AB001210C00006F5
+:100D6000240400013C0980088E0800088D25000439
+:100D70005105009C240400388FBF00348FB200302E
+:100D80008FB1002C8FB000280080102103E00008F4
+:100D900027BD0038240A0012156AFFE6240400016A
+:100DA0000200202127A500100E000CB6AFA00010F5
+:100DB0001440007C3C19800837240080909800087B
+:100DC000331100081220000A8FA7001030FF010025
+:100DD00013E000A48FA300148C8600580066102333
+:100DE000044000043C0A8008AC8300588FA7001020
+:100DF0003C0A800835480080910900083124000829
+:100E00001480000224080003000040213C1F8008D9
+:100E100093F1001193F9001237E600808CCC005456
+:100E2000333800FF03087821322D00FF000F708057
+:100E300001AE282100AC582B1160006F00000000AB
+:100E400094CA005C8CC900543144FFFF0125102373
+:100E50000082182B14600068000000008CCB005446
+:100E60000165182330EC00041180006C000830800C
+:100E70008FA8001C0068102B1040006230ED0004A9
+:100E8000006610232C46008010C00002004088211C
+:100E9000241100800E00164E024020213C0D8008D7
+:100EA00035A6008024070001ACC7000C90C80008DC
+:100EB0000011484035A70100310C007FA0CC00088C
+:100EC0008E05000424AB0001ACCB0030A4D1005C43
+:100ED0008CCA003C9602000E01422021ACC40020C6
+:100EE0008CC3003C0069F821ACDF001C8E190004A3
+:100EF000ACF900008E180008ACF800048FB10010A7
+:100F0000322F000855E0004793A60020A0C0004EF5
+:100F100090D8004E2411FFDFA0F8000890CF000801
+:100F200001F17024A0CE00088E0500083C0B80085B
+:100F300035690080AD2500388D6A00148D2200309F
+:100F40002419005001422021AD24003491230000D7
+:100F5000307F00FF13F90036264F01000E001658AF
+:100F60000240202124040038000028210E0016F23F
+:100F70002406000A0A001757240400010E000D2859
+:100F8000000020218FBF00348FB200308FB1002CC1
+:100F90008FB00028004020210080102103E00008CD
+:100FA00027BD00388E0E00083C0F800835F0008009
+:100FB000AE0E005402402021AE0000300E00164E4E
+:100FC00000000000920D00250240202135AC0020D9
+:100FD0000E001658A20C00250E000CAC0240202179
+:100FE000240400382405008D0E0016F22406001299
+:100FF0000A0017572404000194C5005C0A001792E8
+:1010000030A3FFFF2407021811A0FF9E00E6102363
+:101010008FAE001C0A00179A01C610230A0017970A
+:101020002C620218A0E600080A0017C48E0500080A
+:101030002406FF8001E6C0243C118000AE38002861
+:101040008E0D000831E7007F3C0E800C00EE602121
+:10105000AD8D00E08E080008AF8C00380A0017D074
+:10106000AD8800E4AC800058908500082403FFF7A9
+:1010700000A33824A08700080A0017758FA7001066
+:101080003C05080024A560A83C04080024846FF4F3
+:101090003C020800244260B0240300063C01080121
+:1010A000AC2596C03C010801AC2496C43C01080163
+:1010B000AC2296C83C010801A02396CC03E00008AE
+:1010C0000000000003E00008240200013C02800050
+:1010D000308800FF344701803C0680008CC301B893
+:1010E0000460FFFE000000008CC501282418FF806A
+:1010F0003C0D800A24AF010001F8702431EC007F20
+:10110000ACCE0024018D2021ACE50000948B00EAD8
+:101110003509600024080002316AFFFFACEA0004D0
+:1011200024020001A4E90008A0E8000BACE00024C0
+:101130003C071000ACC701B8AF84003803E00008DA
+:10114000AF85006C938800488F8900608F820038DB
+:1011500030C600FF0109382330E900FF01221821C1
+:1011600030A500FF2468008810C000020124382147
+:101170000080382130E400031480000330AA00030B
+:101180001140000D312B000310A0000900001021B8
+:1011900090ED0000244E000131C200FF0045602B9D
+:1011A000A10D000024E700011580FFF925080001CA
+:1011B00003E00008000000001560FFF300000000DD
+:1011C00010A0FFFB000010218CF80000245900043F
+:1011D000332200FF0045782BAD18000024E70004FF
+:1011E00015E0FFF92508000403E0000800000000F6
+:1011F00093850048938800588F8700600004320070
+:101200003103007F00E5102B30C47F001040000F39
+:10121000006428258F8400383C0980008C8A00EC0B
+:10122000AD2A00A43C03800000A35825AC6B00A0AD
+:101230008C6C00A00580FFFE000000008C6D00ACEF
+:10124000AC8D00EC03E000088C6200A80A00188254
+:101250008F840038938800593C0280000080502120
+:10126000310300FEA383005930ABFFFF30CC00FFF9
+:1012700030E7FFFF344801803C0980008D2401B82D
+:101280000480FFFE8F8D006C24180016AD0D000049
+:101290008D2201248F8D0038AD0200048D5900206D
+:1012A000A5070008240201C4A119000AA118000B17
+:1012B000952F01208D4E00088D4700049783005C18
+:1012C0008D59002401CF302100C7282100A32023FD
+:1012D0002418FFFFA504000CA50B000EA5020010AA
+:1012E000A50C0012AD190018AD18002495AF00E848
+:1012F0003C0B10002407FFF731EEFFFFAD0E002876
+:101300008DAC0084AD0C002CAD2B01B88D460020B7
+:1013100000C7282403E00008AD4500208F8800386E
+:101320000080582130E7FFFF910900D63C02800081
+:1013300030A5FFFF312400FF00041A00006750258C
+:1013400030C600FF344701803C0980008D2C01B875
+:101350000580FFFE8F82006C240F0017ACE20000B6
+:101360008D390124ACF900048D780020A4EA00082E
+:10137000241901C4A0F8000AA0EF000B9523012056
+:101380008D6E00088D6D00049784005C01C35021B0
+:10139000014D602101841023A4E2000CA4E5000E9D
+:1013A000A4F90010A4E60012ACE000148D7800242B
+:1013B000240DFFFFACF800188D0F007CACEF001C73
+:1013C0008D0E00783C0F1000ACEE0020ACED002438
+:1013D000950A00BE240DFFF73146FFFFACE600285A
+:1013E000950C00809504008231837FFF0003CA00C2
+:1013F0003082FFFF0322C021ACF8002CAD2F01B8D2
+:10140000950E00828D6A002000AE3021014D282407
+:10141000A506008203E00008AD6500203C028000C4
+:10142000344501803C0480008C8301B80460FFFED9
+:101430008F8A0044240600199549001C3128FFFFBB
+:10144000000839C0ACA70000A0A6000B3C051000A6
+:1014500003E00008AC8501B88F87004C0080402174
+:1014600030C400FF3C0680008CC201B80440FFFE7F
+:101470008F89006C9383006834996000ACA90000E8
+:10148000A0A300058CE20010240F00022403FFF744
+:10149000A4A20006A4B900088D180020A0B8000A74
+:1014A000A0AF000B8CEE0000ACAE00108CED000481
+:1014B000ACAD00148CEC001CACAC00248CEB002018
+:1014C000ACAB00288CEA002C3C071000ACAA002C26
+:1014D0008D090024ACA90018ACC701B88D05002007
+:1014E00000A3202403E00008AD0400208F8600380C
+:1014F00027BDFFE0AFB10014AFBF0018AFB00010C0
+:1015000090C300D430A500FF3062002010400008D6
+:10151000008088218CCB00D02409FFDF256A0001E0
+:10152000ACCA00D090C800D401093824A0C700D4A8
+:1015300014A000403C0C80008F840038908700D4B9
+:101540002418FFBF2406FFEF30E3007FA08300D400
+:10155000979F005C8F8200608F8D003803E2C82364
+:10156000A799005CA5A000BC91AF00D401F870243D
+:10157000A1AE00D48F8C0038A18000D78F8A0038AC
+:10158000A5400082AD4000EC914500D400A658244F
+:10159000A14B00D48F9000348F8400609786005C4C
+:1015A0000204282110C0000FAF850034A38000582A
+:1015B0003C0780008E2C000894ED01208E2B000447
+:1015C000018D5021014B8021020620233086FFFF30
+:1015D00030C8000F3909000131310001162000091F
+:1015E000A3880058938600488FBF00188FB100145D
+:1015F0008FB0001027BD0020AF85006403E0000815
+:10160000AF86006000C870238FBF00189386004823
+:101610008FB100148FB0001034EF0C00010F28219F
+:1016200027BD0020ACEE0084AF85006403E0000815
+:10163000AF86006035900180020028210E00190F4E
+:10164000240600828F840038908600D430C5004084
+:1016500050A0FFBAA38000688F85004C3C06800034
+:101660008CCD01B805A0FFFE8F89006C2408608234
+:1016700024070002AE090000A6080008A207000B1C
+:101680008CA300083C0E1000AE0300108CA2000CCE
+:10169000AE0200148CBF0014AE1F00188CB90018E5
+:1016A000AE1900248CB80024AE1800288CAF002896
+:1016B000AE0F002CACCE01B80A001948A380006818
+:1016C0008F8A003827BDFFE0AFB10014AFB0001023
+:1016D0008F880060AFBF00189389003C954200BC22
+:1016E00030D100FF0109182B0080802130AC00FFB1
+:1016F0003047FFFF0000582114600003310600FF4F
+:1017000001203021010958239783005C0068202BB9
+:101710001480002700000000106800562419000102
+:101720001199006334E708803165FFFF0E0018C08F
+:10173000020020218F83006C3C07800034E601808A
+:101740003C0580008CAB01B80560FFFE240A001840
+:101750008F840038ACC30000A0CA000B948900BE7F
+:101760003C081000A4C90010ACC00030ACA801B8FF
+:101770009482008024430001A4830080949F008011
+:101780003C0608008CC6318833EC7FFF1186005E72
+:101790000000000002002021022028218FBF001835
+:1017A0008FB100148FB000100A00193427BD00203B
+:1017B000914400D42403FF8000838825A15100D4E4
+:1017C0009784005C3088FFFF51000023938C003C1D
+:1017D0008F8500382402EFFF008B782394AE00BC85
+:1017E0000168502B31E900FF01C26824A4AD00BCA0
+:1017F00051400039010058213C1F800037E60100AC
+:101800008CD800043C190001031940245500000144
+:1018100034E740008E0A00202403FFFB241100015E
+:1018200001432024AE0400201191002D34E78000F4
+:1018300002002021012030210E0018C03165FFFF79
+:101840009787005C8F890060A780005C0127802358
+:10185000AF900060938C003C8F8B00388FBF0018D6
+:101860008FB100148FB0001027BD002003E00008E6
+:10187000A16C00D73C0D800035AA01008D48000402
+:101880003C0900010109282454A0000134E740006C
+:101890008E0F00202418FFFB34E7800001F870242D
+:1018A00024190001AE0E00201599FF9F34E708802F
+:1018B000020020210E00188E3165FFFF020020215A
+:1018C000022028218FBF00188FB100148FB00010A4
+:1018D0000A00193427BD00200A0019F7000048212A
+:1018E00002002021012030210E00188E3165FFFFFB
+:1018F0009787005C8F890060A780005C01278023A8
+:101900000A001A0EAF900060948C0080241F8000A3
+:10191000019F3024A4860080908B0080908F0080EF
+:10192000316700FF0007C9C20019C027001871C045
+:1019300031ED007F01AE2825A08500800A0019DF67
+:1019400002002021938500682403000127BDFFE8E1
+:1019500000A330042CA20020AFB00010AFBF0014D1
+:1019600000C01821104000132410FFFE3C0708009F
+:101970008CE7319000E610243C088000350501809A
+:1019800014400005240600848F890038240A0004CE
+:101990002410FFFFA12A00FC0E00190F0000000018
+:1019A000020010218FBF00148FB0001003E0000868
+:1019B00027BD00183C0608008CC631940A001A574F
+:1019C00000C310248F87004427BDFFE0AFB200188A
+:1019D000AFB10014AFB00010AFBF001C30D000FF9B
+:1019E00090E6000D00A088210080902130C5007F86
+:1019F000A0E5000D8F8500388E2300188CA200D042
+:101A00001062002E240A000E0E001A4AA38A0068F3
+:101A10002409FFFF104900222404FFFF5200002088
+:101A2000000020218E2600003C0C001000CC582421
+:101A3000156000393C0E000800CE682455A0003F18
+:101A4000024020213C18000200D880241200001F10
+:101A50003C0A00048F8700448CE200148CE30010E1
+:101A60008CE500140043F82303E5C82B1320000580
+:101A7000024020218E24002C8CF1001010910031A6
+:101A80000240202124020012A38200680E001A4A9C
+:101A90002412FFFF105200022404FFFF0000202147
+:101AA0008FBF001C8FB200188FB100148FB00010D0
+:101AB0000080102103E0000827BD002090A800D47A
+:101AC000350400200A001A80A0A400D400CA4824CB
+:101AD0001520000B8F8B00448F8D00448DAC0010BF
+:101AE0001580000B024020218E2E002C51C0FFECEF
+:101AF00000002021024020210A001A9B2402001726
+:101B00008D66001050C0FFE6000020210240202119
+:101B10000A001A9B24020011024020212402001511
+:101B20000E001A4AA3820068240FFFFF104FFFDC4B
+:101B30002404FFFF0A001A8A8E2600000A001AC138
+:101B4000240200143C08000400C8382450E0FFD4EC
+:101B500000002021024020210A001A9B24020013C9
+:101B60008F85003827BDFFD8AFB3001CAFB2001877
+:101B7000AFB10014AFB00010AFBF002090A700D4E9
+:101B80008F90004C2412FFFF34E2004092060000C8
+:101B9000A0A200D48E0300100080982110720006CD
+:101BA00030D1003F2408000D0E001A4AA3880068B7
+:101BB000105200252404FFFF8F8A00388E09001878
+:101BC0008D4400D01124000702602021240C000E57
+:101BD0000E001A4AA38C0068240BFFFF104B001A5A
+:101BE0002404FFFF24040020122400048F8D0038F9
+:101BF00091AF00D435EE0020A1AE00D48F85005403
+:101C000010A00019000000001224004A8F9800382C
+:101C10008F92FCC0971000809651000A5230004805
+:101C20008F9300403C1F08008FFF318C03E5C82BC9
+:101C30001720001E02602021000028210E0019A993
+:101C400024060001000020218FBF00208FB3001C5C
+:101C50008FB200188FB100148FB0001000801021D7
+:101C600003E0000827BD00285224002A8E05001436
+:101C70008F840038948A008025490001A48900805F
+:101C8000948800803C0208008C42318831077FFF35
+:101C900010E2000E00000000026020210E00193446
+:101CA000240500010A001B0B000020212402002D46
+:101CB0000E001A4AA38200682403FFFF1443FFE1C9
+:101CC0002404FFFF0A001B0C8FBF002094990080A2
+:101CD000241F800024050001033FC024A498008035
+:101CE00090920080908E0080325100FF001181C2DE
+:101CF00000107827000F69C031CC007F018D582576
+:101D0000A08B00800E001934026020210A001B0BFA
+:101D1000000020212406FFFF54A6FFD68F84003840
+:101D2000026020210E001934240500010A001B0B5B
+:101D300000002021026020210A001B252402000A45
+:101D40002404FFFD0A001B0BAF9300608F8800384E
+:101D500027BDFFE8AFB00010AFBF0014910A00D458
+:101D60008F87004C00808021354900408CE60010B0
+:101D7000A10900D43C0208008C4231B030C53FFFBD
+:101D800000A2182B106000078F850050240DFF80E3
+:101D900090AE000D01AE6024318B00FF156000088D
+:101DA0000006C382020020212403000D8FBF00140F
+:101DB0008FB0001027BD00180A001A4AA3830068DC
+:101DC00033060003240F000254CFFFF70200202146
+:101DD00094A2001C8F85003824190023A4A200E8D7
+:101DE0008CE8000000081E02307F003F13F9003528
+:101DF0003C0A00838CE800188CA600D0110600086D
+:101E0000000000002405000E0E001A4AA385006899
+:101E10002407FFFF104700182404FFFF8F850038B8
+:101E200090A900D435240020A0A400D48F8C0044B5
+:101E3000918E000D31CD007FA18D000D8F83005458
+:101E40001060001C020020218F8400508C9800102C
+:101E50000303782B11E0000D241900180200202143
+:101E6000A39900680E001A4A2410FFFF10500002C8
+:101E70002404FFFF000020218FBF00148FB000104A
+:101E80000080102103E0000827BD00188C86001098
+:101E90008F9F00440200202100C31023AFE20010F6
+:101EA000240500010E0019A9240600010A001B9751
+:101EB000000020210E001934240500010A001B97A0
+:101EC00000002021010A5824156AFFD98F8C004494
+:101ED000A0A600FC0A001B84A386005A30A500FFC0
+:101EE0002406000124A9000100C9102B1040000C99
+:101EF00000004021240A000100A61823308B0001B5
+:101F000024C60001006A3804000420421160000267
+:101F100000C9182B010740251460FFF800A61823FC
+:101F200003E000080100102127BDFFD8AFB0001862
+:101F30008F90004CAFB1001CAFBF00202403FFFF07
+:101F40002411002FAFA30010920600002405000802
+:101F500026100001006620260E001BB0308400FF12
+:101F600000021E003C021EDC34466F410A001BD8F2
+:101F70000000102110A00009008018212445000154
+:101F800030A2FFFF2C4500080461FFFA0003204047
+:101F90000086202614A0FFF9008018210E001BB037
+:101FA000240500208FA300102629FFFF313100FFF8
+:101FB00000034202240700FF1627FFE20102182651
+:101FC00000035027AFAA0014AFAA00100000302170
+:101FD00027A8001027A7001400E6782391ED00033E
+:101FE00024CE000100C8602131C600FF2CCB0004C4
+:101FF0001560FFF9A18D00008FA200108FBF002097
+:102000008FB1001C8FB0001803E0000827BD002826
+:1020100027BDFFD0AFB3001CAFB00010AFBF00288A
+:10202000AFB50024AFB40020AFB20018AFB10014B8
+:102030003C0C80008D880128240FFF803C06800A1C
+:1020400025100100250B0080020F68243205007F57
+:10205000016F7024AD8E009000A62821AD8D002464
+:1020600090A600FC3169007F3C0A8004012A1821F7
+:10207000A386005A9067007C00809821AF830030CF
+:1020800030E20002AF88006CAF85003800A0182154
+:10209000144000022404003424040030A3840048C7
+:1020A0008C7200DC30D100FF24040004AF92006089
+:1020B00012240004A38000688E7400041680001EA1
+:1020C0003C0880009386005930C7000110E0000FE3
+:1020D0008F9300608CB000848CA800842404FF805F
+:1020E000020410240002F940310A007F03EA482567
+:1020F0003C0C2000012C902530CD00FE3C038000DC
+:10210000AC720830A38D00598F9300608FBF0028F8
+:102110008FB50024ACB300DC8FB400208FB3001C5B
+:102120008FB200188FB100148FB00010240200018C
+:1021300003E0000827BD00308E7F000895020120D3
+:102140008E67001003E2C8213326FFFF30D8000F4E
+:1021500033150001AF87003416A00058A39800582B
+:1021600035090C000309382100D81823AD03008479
+:10217000AF8700648E6A00043148FFFF1100007EC3
+:10218000A78A005C90AC00D42407FF8000EC3024C8
+:1021900030CB00FF1560004B9786005C938E005A91
+:1021A000240D000230D5FFFF11CD02A20000A021B6
+:1021B0008F85006002A5802B160000BC9388004824
+:1021C0003C11800096240120310400FF1485008812
+:1021D0008F8400648F9800343312000356400085CA
+:1021E00030A500FF8F900064310C00FF24060034FE
+:1021F00011860095AF90004C9204000414800118E1
+:102200008F8E0038A380003C8E0D00048DC800D84E
+:102210003C0600FF34CCFFFF01AC30240106182B34
+:1022200014600120AF8600548F8700609798005C8F
+:10223000AF8700400307402310C000C7A788005C99
+:102240008F91003030C3000300035823922A007C92
+:102250003171000302261021000A20823092000111
+:102260000012488000492821311FFFFF03E5C82BD9
+:10227000132001208F8800388F8500348F880064F8
+:102280001105025A3C0E3F018E0600003C0C250051
+:1022900000CE682411AC01638F84004C30E500FF50
+:1022A0000E00184A000030218F8800388F870060A8
+:1022B0008F8500340A001DB78F8600540A001C5613
+:1022C000AF87006490A400D400E48024320200FFB1
+:1022D000104000169386005990A6008890AE00D753
+:1022E00024A8008830D4003F2686FFE02CD10020AF
+:1022F000A38E003C1220000CAF88004C240B000180
+:1023000000CB20043095001916A0012B3C0680005C
+:1023100034CF0002008FC0241700022E3099002015
+:1023200017200234000000009386005930CB0001D2
+:102330001160000F9788005C8CBF00848CA900841A
+:10234000240AFF8003EA6024000C19403132007F28
+:10235000007238253C0D200000EDC82530D800FE65
+:102360003C0F8000ADF90830A39800599788005CB5
+:102370001500FF84000000008E630020306200041E
+:102380001040FF51938600592404FFFB0064802411
+:102390003C038000AE700020346601808C7301B86D
+:1023A0000660FFFE8F98006C347501003C1400013C
+:1023B000ACD800008C6B012424076085ACCB0004F2
+:1023C0008EAE000401D488245220000124076083CB
+:1023D00024190002A4C700083C0F1000A0D9000B6C
+:1023E0003C068000ACCF01B80A001C2B9386005934
+:1023F00030A500FF0E00184A240600018F88006CEB
+:102400003C05800034A90900250201889388004812
+:10241000304A0007304B00783C0340802407FF809F
+:102420000163C825014980210047F824310C00FFD1
+:1024300024060034ACBF0800AF90004CACB90810C3
+:102440005586FF6E920400048F8400388E11003090
+:10245000908E00D431CD001015A000108F83006045
+:102460002C6F000515E000E400000000909800D4F7
+:102470002465FFFC331200101640000830A400FF52
+:102480008F9F00648F99003413F90004388700018E
+:1024900030E20001144001C8000000000E001BC320
+:1024A000000000000A001DF8000000008F84006496
+:1024B00030C500FF0E00184A24060001939800481A
+:1024C000240B0034130B00A08F8500388F8600602A
+:1024D0009783005C306EFFFF00CE8823AF910060D1
+:1024E000A780005C1280FF90028018212414FFFD59
+:1024F0005474FFA28E6300208E6A00042403FFBF81
+:102500002408FFEF0155F823AE7F000490AC00D4FF
+:102510003189007FA0A900D48E7200208F8F0038EF
+:10252000A780005C364D0002AE6D0020A5E000BC27
+:1025300091E500D400A3C824A1F900D48F950038F8
+:10254000AEA000EC92B800D403085824A2AB00D48B
+:102550000A001CD78F8500388F910034AF8000604F
+:1025600002275821AF8B0034000020212403FFFFF5
+:10257000108301B48F8500388E0C00103C0D0800CC
+:102580008DAD31B09208000031843FFF008D802B6B
+:1025900012000023310D003F3C1908008F3931A88B
+:1025A0008F9F006C000479802408FF80033F202166
+:1025B000008FC821938500590328F8243C06008029
+:1025C0003C0F800034D80001001F91403331007F60
+:1025D0008F8600380251502535EE0940332B0078A4
+:1025E000333000073C0310003C02800C017890253A
+:1025F000020E48210143C0250222382134AE0001D9
+:10260000ADFF0804AF890050ADF20814AF87004455
+:10261000ADFF0028ACD90084ADF80830A38E005976
+:102620009383005A24070003106700272407000142
+:102630001467FFAC8F8500382411002311B1008589
+:1026400000000000240E000B026020210E001A4A38
+:10265000A38E00680040A0210A001D328F8500383B
+:1026600002602021240B000C0E001A4AA38B006884
+:10267000240AFFFF104AFFBD2404FFFF8F8E00389D
+:10268000A380003C8E0D00048DC800D83C0600FFDE
+:1026900034CCFFFF01AC30240106182B1060FEE2A1
+:1026A000AF86005402602021241200190E001A4A3D
+:1026B000A3920068240FFFFF104FFFAC2404FFFF1C
+:1026C0000A001C838F86005425A3FFE02C74002091
+:1026D0001280FFDD240E000B000328803C1108014E
+:1026E000263194B400B148218D2D000001A00008CE
+:1026F000000000008F85003400A710219385003C66
+:10270000AF82003402251821A383003C951F00BC32
+:102710000226282137F91000A51900BC5240FF926B
+:10272000AF850060246A0004A38A003C950900BCC0
+:1027300024A40004AF84006035322000A51200BC40
+:102740000A001D54000020218F8600602CC800055F
+:102750001500FF609783005C3065FFFF00C5C8234C
+:102760002F2F000511E00003306400FF24CDFFFC93
+:1027700031A400FF8F8900648F920034113200046D
+:10278000389F000133EC0001158001380000000083
+:102790008F840038908700D434E60010A08600D4DF
+:1027A0008F8500388F8600609783005CACA000ECBA
+:1027B0000A001D2F306EFFFF8CB500848CB400849E
+:1027C0003C04100002A7302400068940328E007FAE
+:1027D000022E8025020410253C08800024050001FB
+:1027E00002602021240600010E0019A9AD02083064
+:1027F0000A001CC38F8500388C8200EC1222FE7EFA
+:102800000260202124090005A38900680E001A4AED
+:102810002411FFFF1451FE782404FFFF0A001D5508
+:102820002403FFFF8F8F004C8F8800388DF8000045
+:10283000AD1800888DE70010AD0700988F87006005
+:102840000A001DB78F8600542406FFFF118600057D
+:10285000000000000E001B4C026020210A001D8FAA
+:102860000040A0210E001AD1026020210A001D8F15
+:102870000040A0218F90004C3C0208008C4231B0F7
+:102880008E110010322C3FFF0182282B10A0000C6B
+:10289000240BFF808F85005090A3000D01637024EE
+:1028A00031CA00FF1140000702602021001143825D
+:1028B000310600032418000110D8010600000000B2
+:1028C000026020212403000D0E001A4AA383006831
+:1028D000004020218F8500380A001D320080A02191
+:1028E0008F90004C3C0A08008D4A31B08F85005013
+:1028F0008E0400100000A0218CB1001430823FFF34
+:10290000004A602B8CB200205180FFEE0260202133
+:1029100090B8000D240BFF800178702431C300FFB4
+:102920005060FFE80260202100044382310600036A
+:1029300014C0FFE40260202194BF001C8F9900386E
+:102940008E060028A73F00E88CAF0010022F20233E
+:1029500014C4013A026020218F83005400C368210F
+:10296000022D382B14E00136240200188F8A00440F
+:102970008F820030024390218D4B00100163702341
+:10298000AD4E0010AD5200208C4C00740192282BEB
+:1029900014A0015F026020218F8400508E08002463
+:1029A0008C86002411060007026020212419001CD7
+:1029B0000E001A4AA3990068240FFFFF104FFFC5AD
+:1029C0002404FFFF8F8400448C87002424FF00012F
+:1029D000AC9F00241251012F8F8D00308DB10074F7
+:1029E0001232012C3C0B00808E0E000001CB5024D3
+:1029F00015400075000000008E0300142411FFFF35
+:102A0000107100073C0808003C0608008CC6319095
+:102A100000C8C0241300015202602021A380006876
+:102A20008E0300003C19000100792024108000135F
+:102A30003C1F0080007FA02416800009020028218E
+:102A4000026020212411001A0E001A4AA391006886
+:102A50002407FFFF1047FF9F2404FFFF02002821E7
+:102A6000026020210E001A6A240600012410FFFFD4
+:102A70001050FF982404FFFF241400018F8D0044A0
+:102A8000026020210280302195A900342405000134
+:102A9000253200010E0019A9A5B200340000202142
+:102AA0008F8500380A001D320080A0218F90004CD5
+:102AB0003C1408008E9431B08E07001030E53FFFC3
+:102AC00000B4C82B132000618F8600502412FF80B1
+:102AD00090C9000D0249682431A400FF5080005CB9
+:102AE000026020218F8C00541180000700078B8228
+:102AF0008F8500388F82FCC094BF0080944A000A02
+:102B0000515F00F78F8600403227000314E0006415
+:102B100000000000920E000211C000D8000000006A
+:102B20008E0B0024156000D902602021920400035E
+:102B300024190002308500FF14B90005308900FF18
+:102B40008F940054128000EA240D002C308900FF7D
+:102B5000392C00102D8400012D3200010244302553
+:102B6000020028210E001A6A026020212410FFFFB3
+:102B7000105000BF8F8500388F830054106000D341
+:102B8000240500013C0A08008D4A318C0143F82BD2
+:102B900017E000B22402002D02602021000028214D
+:102BA0000E0019A9240600018F85003800001821A5
+:102BB0000A001D320060A0210E0018750000000000
+:102BC0000A001DF800000000AC8000200A001E78FA
+:102BD0008E03001400002821026020210E0019A994
+:102BE000240600010A001CC38F8500380A001DB7A7
+:102BF0008F8800388CAA00848CAC00843C031000C1
+:102C00000147F824001F91403189007F024968255F
+:102C100001A32825ACC50830910700012405000157
+:102C2000026020210E0019A930E600010A001CC331
+:102C30008F850038938F00482403FFFD0A001D3460
+:102C4000AF8F00600A001D342403FFFF02602021C3
+:102C50002410000D0E001A4AA390006800401821AD
+:102C60008F8500380A001D320060A0210E00187503
+:102C7000000000009783005C8F86006000402021E8
+:102C80003070FFFF00D010232C4A00051140FE11C8
+:102C90008F850038ACA400EC0A001D2F306EFFFFBA
+:102CA00090CF000D31E300085460FFA192040003AF
+:102CB00002602021240200100E001A4AA38200683C
+:102CC0002403FFFF5443FF9A920400030A001F12DB
+:102CD0008F85003890A4000D308F000811E000951A
+:102CE0008F990054572000A6026020218E1F000CEF
+:102CF0008CB4002057F40005026020218E0D0008DE
+:102D00008CA7002411A7003A026020212402002091
+:102D1000A38200680E001A4A2412FFFF1052FEED33
+:102D20002404FFFF8F9F00442402FFF73C14800E11
+:102D300093EA000D2419FF803C03800001423824EF
+:102D4000A3E7000D8F9F00303C0908008D2931ACAE
+:102D50008F8C006C97F200788F870044012C302113
+:102D6000324D7FFF000D204000C4782131E5007F07
+:102D700000B4C02101F94024AC68002CA711000068
+:102D80008CEB0028256E0001ACEE00288CEA002CAC
+:102D90008E02002C01426021ACEC002C8E09002C2C
+:102DA000ACE900308E120014ACF2003494ED003A1D
+:102DB00025A40001A4E4003A97E600783C1108003D
+:102DC0008E3131B024C3000130707FFF1211005CDE
+:102DD000006030218F8F0030026020212405000127
+:102DE0000E001934A5E600780A001EA1000020217B
+:102DF0008E0900142412FFFF1132006B8F8A0038F5
+:102E00008E0200188D4C00D0144C00650260202109
+:102E10008E0B00248CAE0028116E005B2402002172
+:102E20000E001A4AA38200681452FFBE2404FFFF5A
+:102E30008F8500380A001D320080A0212402001F67
+:102E40000E001A4AA38200682409FFFF1049FEA160
+:102E50002404FFFF0A001E548F83005402602021C7
+:102E60000E001A4AA38200681450FF508F85003864
+:102E70002403FFFF0A001D320060A0218CD800242B
+:102E80008E0800241118FF29026020210A001F2744
+:102E90002402000F8E0900003C05008001259024CB
+:102EA0001640FF492402001A026020210E001A4A2F
+:102EB000A3820068240CFFFF144CFECF2404FFFF04
+:102EC0008F8500380A001D320080A0210E001934C1
+:102ED000026020218F8500380A001EE500001821BD
+:102EE0002403FFFD0060A0210A001D32AF860060B0
+:102EF000026020210E001A4AA38D00682403FFFF00
+:102F00001043FF588F8500380A001ECC920400033E
+:102F10002418001D0E001A4AA39800682403FFFF1E
+:102F20001443FE9D2404FFFF8F8500380A001D32E4
+:102F30000080A021026020210A001F3D24020024FD
+:102F4000240880000068C024330BFFFF000B73C20D
+:102F500031D000FF001088270A001F6E001133C017
+:102F6000240F001B0E001A4AA38F00681451FEACF8
+:102F70002404FFFF8F8500380A001D320080A02145
+:102F80000A001F3D240200278E0600288CA3002C77
+:102F900010C30008026020210A001F812402001FC4
+:102FA0000A001F812402000E026020210A001F81F6
+:102FB000240200258E04002C1080000D8F8F00301D
+:102FC0008DE800740104C02B5700000C0260202122
+:102FD0008CB900140086A0210334282B10A0FF52C6
+:102FE0008F9F0044026020210A001F8124020022DA
+:102FF000026020210A001F81240200230A001F8191
+:103000002402002627BDFFD8AFB3001CAFB10014C7
+:10301000AFBF0020AFB20018AFB000103C0280007C
+:103020008C5201408C4B01483C048000000B8C0208
+:10303000322300FF317300FF8C8501B804A0FFFE2E
+:1030400034900180AE1200008C8701442464FFF0AC
+:10305000240600022C830013AE070004A61100080A
+:10306000A206000BAE1300241060004F8FBF00209B
+:10307000000448803C0A0801254A9534012A402171
+:103080008D04000000800008000000003C030800E0
+:103090008C6331A831693FFF00099980007280215B
+:1030A000021370212405FF80264D0100264C00806C
+:1030B0003C02800031B1007F3198007F31CA007F2F
+:1030C0003C1F800A3C1980043C0F800C01C5202461
+:1030D00001A5302401853824014F1821AC46002475
+:1030E000023F402103194821AC470090AC4400281E
+:1030F000AF830044AF880038AF8900300E0019005C
+:10310000016080213C0380008C6B01B80560FFFEEC
+:103110008F8700448F8600383465018090E8000D69
+:10312000ACB20000A4B0000600082600000416039C
+:1031300000029027001227C21080008124C200885C
+:10314000241F6082A4BF0008A0A000052402000282
+:10315000A0A2000B8F8B0030000424003C08270045
+:1031600000889025ACB20010ACA00014ACA00024E4
+:10317000ACA00028ACA0002C8D6900382413FF807F
+:10318000ACA9001890E3000D02638024320500FF13
+:1031900010A000058FBF002090ED000D31AC007F26
+:1031A000A0EC000D8FBF00208FB3001C8FB2001861
+:1031B0008FB100148FB000103C0A10003C0E80004C
+:1031C00027BD002803E00008ADCA01B8265F010052
+:1031D0002405FF8033F8007F3C06800003E5782457
+:1031E0003C19800A03192021ACCF0024908E00D412
+:1031F00000AE682431AC00FF11800024AF84003899
+:10320000248E008895CD00123C0C08008D8C31A8CE
+:1032100031AB3FFF01924821000B5180012A402130
+:1032200001052024ACC400283107007F3C06800C37
+:1032300000E620219083000D00A31024304500FFFC
+:1032400010A0FFD8AF8400449098000D330F0010F9
+:1032500015E0FFD58FBF00200E0019000000000010
+:103260003C0380008C7901B80720FFFE00000000BD
+:10327000AE1200008C7F0144AE1F0004A6110008AE
+:1032800024110002A211000BAE1300243C1308010C
+:10329000927396F0327000015200FFC38FBF00207E
+:1032A0000E002146024020210A0020638FBF00202B
+:1032B0003C1260008E452C083C03F0033462FFFF93
+:1032C00000A2F824AE5F2C088E582C083C1901C0CF
+:1032D00003199825AE532C080A0020638FBF0020E5
+:1032E000264D010031AF007F3C10800A240EFF8084
+:1032F00001F0282101AE60243C0B8000AD6C00245D
+:103300001660FFA8AF85003824110003A0B100FCAF
+:103310000A0020638FBF002026480100310A007F89
+:103320003C0B800A2409FF80014B30210109202435
+:103330003C078000ACE400240A002062AF8600381D
+:10334000944E0012320C3FFF31CD3FFF15ACFF7D94
+:10335000241F608290D900D42418FF800319782498
+:1033600031EA00FF1140FF7700000000240700044D
+:10337000A0C700FC8F870044241160842406000D40
+:10338000A4B10008A0A600050A00204D24020002F6
+:103390003C040001248496DC24030014240200FE73
+:1033A0003C010800AC2431EC3C010800AC2331E8BE
+:1033B0003C010801A42296F83C040801248496F8F4
+:1033C0000000182100643021A0C300042463000120
+:1033D0002C6500FF54A0FFFC006430213C0708006E
+:1033E00024E7010003E00008AF87007800A058211F
+:1033F000008048210000102114A00012000050217C
+:103400000A002142000000003C010801A42096F8B7
+:103410003C05080194A596F88F8200783C0C0801C1
+:10342000258C96F800E2182100AC2021014B302BAE
+:10343000A089000400001021A460000810C0003919
+:10344000010048218F8600780009384000E94021BA
+:103450000008388000E6282190A8000B90B9000AE7
+:103460000008204000881021000218800066C0215A
+:10347000A319000A8F85007800E5782191EE000AF3
+:1034800091E6000B000E684001AE6021000C208028
+:1034900000851021A046000B3C030801906396F2C2
+:1034A000106000222462FFFF8F8300383C01080176
+:1034B000A02296F2906C00FF118000040000000032
+:1034C000906E00FF25CDFFFFA06D00FF3C190801A5
+:1034D000973996F8272300013078FFFF2F0F00FF60
+:1034E00011E0FFC9254A00013C010801A42396F818
+:1034F0003C05080194A596F88F8200783C0C0801E1
+:10350000258C96F800E2182100AC2021014B302BCD
+:10351000A089000400001021A460000814C0FFC9A5
+:103520000100482103E000080000000003E000085B
+:103530002402000227BDFFE0248501002407FF804C
+:10354000AFB00010AFBF0018AFB1001400A718242F
+:103550003C10800030A4007F3C06800A00862821B1
+:103560008E110024AE03002490A200FF1440000836
+:10357000AF850038A0A000098FBF0018AE1100244D
+:103580008FB100148FB0001003E0000827BD0020A9
+:1035900090A900FD90A800FF312400FF0E0020F448
+:1035A000310500FF8F8500388FBF0018A0A00009EB
+:1035B000AE1100248FB100148FB0001003E000089A
+:1035C00027BD002027BDFFD0AFB20020AFB1001C47
+:1035D000AFB00018AFBF002CAFB40028AFB30024C9
+:1035E0003C0980009533011635320C00952F011AE5
+:1035F0003271FFFF023280218E08000431EEFFFF9E
+:10360000248B0100010E6821240CFF8025A5FFFFFB
+:10361000016C50243166007F3C07800AAD2A0024EB
+:1036200000C73021AF850074AF8800703C010801ED
+:10363000A02096F190C300090200D02100809821BB
+:10364000306300FF2862000510400048AF86003854
+:10365000286400021480008E24140001240D00054B
+:103660003C010801A02D96D590CC00FD3C0108013D
+:10367000A02096D63C010801A02096D790CB000A46
+:10368000240AFF80318500FF014B4824312700FFC9
+:1036900010E0000C000058213C12800836510080D8
+:1036A0008E2F00308CD0005C01F0702305C0018E9D
+:1036B0008F87007090D4000A3284007FA0C4000A73
+:1036C0008F8600383C118008363000808E0F003025
+:1036D0008F87007000EF702319C000EE000000001B
+:1036E00090D4000924120002328400FF1092024795
+:1036F000000000008CC2005800E2F82327F9FFFF09
+:103700001B2001300000000090C5000924080004BF
+:1037100030A300FF10680057240A00013C01080193
+:10372000A02A96D590C900FF252700013C01080179
+:10373000A02796D43C030801906396D52406000583
+:103740001066006A2C780005130000C40000902168
+:103750000003F8803C0408012484958003E4C82118
+:103760008F25000000A0000800000000241800FFC2
+:103770001078005C0000000090CC000A90CA00099C
+:103780003C080801910896F13187008000EA48253D
+:103790003C010801A02996DC90C500FD3C140801FD
+:1037A000929496F2311100013C010801A02596DDAA
+:1037B00090DF00FE3C010801A03F96DE90D200FFA2
+:1037C0003C010801A03296DF8CD900543C0108016D
+:1037D000AC3996E08CD000583C010801AC3096E43E
+:1037E0008CC3005C3C010801AC3496EC3C01080140
+:1037F000AC2396E8162000088FBF002C8FB4002859
+:103800008FB300248FB200208FB1001C8FB000183E
+:1038100003E0000827BD00303C1180009624010E13
+:103820000E000FD43094FFFF3C0B08018D6B96F413
+:103830000260382102802821AE2B01803C13080150
+:103840008E7396D401602021240600830E00102F71
+:10385000AFB300108FBF002C8FB400288FB30024AB
+:103860008FB200208FB1001C8FB0001803E0000859
+:1038700027BD00303C1808008F1831FC270F0001CD
+:103880003C010800AC2F31FC0A0021D700000000E9
+:103890001474FFB900000000A0C000FF3C05080040
+:1038A0008CA531E43C0308008C6331E03C02080045
+:1038B0008C4232048F99003834A80001241F000282
+:1038C0003C010801AC2396F43C010801A02896F0C5
+:1038D0003C010801A02296F3A33F00090A002190B1
+:1038E0008F8600380E002146000000000A0021D714
+:1038F0008F8600383C1F080193FF96D424190001DD
+:1039000013F902298F8700703C100801921096D895
+:103910003C06080190C696D610C000050200A02102
+:103920003C040801908496D9109001E48F870078B8
+:10393000001088408F9F0078023048210009C8801D
+:10394000033F702195D80008270F0001A5CF00087C
+:103950003C040801908496D93C05080190A596D6B0
+:103960000E0020F4000000008F8700780230202134
+:103970000004308000C720218C8500048F820074F1
+:1039800000A2402305020006AC8200048C8A0000DD
+:103990008F830070014310235C400001AC83000062
+:1039A0008F86003890CB00FF2D6C00025580002DD3
+:1039B000241400010230F821001F40800107282153
+:1039C00090B9000B8CAE00040019C0400319782197
+:1039D000000F1880006710218C4D000001AE882375
+:1039E0002630FFFF5E00001F241400018C440004F9
+:1039F0008CAA0000008A482319200019240E000414
+:103A00003C010801A02E96D590AD000B8CAB0004B4
+:103A1000000D8840022D80210010108000471021E9
+:103A20008C44000401646023058202009443000872
+:103A300090DF00FE90B9000B33E500FF54B900049D
+:103A40000107A021A0D400FE8F8700780107A021E4
+:103A50009284000B0E0020F4240500018F860038AC
+:103A600024140001125400962E500001160000424A
+:103A70003C08FFFF241900021659FF3F0000000018
+:103A8000A0C000FF8F860038A0D200090A0021D70D
+:103A90008F86003890C700092404000230E300FF3D
+:103AA0001064016F24090004106901528F880074AA
+:103AB0008CCE0054010E682325B10001062001754B
+:103AC000241800043C010801A03896D53C010801E7
+:103AD000A02096D490D400FD90D200FF2E4F00027B
+:103AE00015E0FF14328400FF000438408F8900780D
+:103AF00090DF00FF00E41021000220800089C8212F
+:103B00002FE500029324000B14A0FF0A24070002F3
+:103B100000041840006480210010588001692821A9
+:103B20008CAC0004010C50230540FF020000000093
+:103B30003C030801906396D614600005246F0001D1
+:103B40003C010801A02496D93C010801A02796D782
+:103B50003C010801A02F96D690CE00FF24E700017B
+:103B600031CD00FF01A7882B1220FFE990A4000BA4
+:103B70000A0021C6000000003C0508018CA596D46F
+:103B80003C12000400A8F82413F2000624020005E9
+:103B90003C090801912996D5152000022402000352
+:103BA000240200053C010801A02296F190C700FF05
+:103BB00014E0012024020002A0C200090A0021D75B
+:103BC0008F86003890CC00FF1180FEDA240A0001B5
+:103BD0008F8C00748F890078240F00030180682186
+:103BE0001160001E240E0002000540400105A021C6
+:103BF00000142080008990218E51000401918023BF
+:103C00000600FECC000000003C020801904296D65F
+:103C100014400005245800013C010801A02A96D751
+:103C20003C010801A02596D93C010801A03896D690
+:103C300090DF00FF010510210002C88033E500FF7E
+:103C4000254A00010329202100AA402B1500FEB9B6
+:103C50009085000B1560FFE50005404000054040E1
+:103C600001051821000310803C010801A02A96D408
+:103C70003C010801A02596D8004918218C64000455
+:103C800000E4F82327F9FFFF1F20FFE900000000F0
+:103C90008C63000000E358230560013A01A38823E8
+:103CA00010E301170184C0231B00FEA200000000E6
+:103CB0003C010801A02E96D50A002305240B000123
+:103CC000240E0004A0CE00093C0D08008DAD31F893
+:103CD0008F86003825A200013C010800AC2231F893
+:103CE0000A0021D7000000008CD9005C00F9C02335
+:103CF0001F00FE7B000000008CDF005C10FFFF65F2
+:103D00008F8400748CC3005C008340232502000173
+:103D10001C40FF60000000008CC9005C248700018B
+:103D200000E9282B10A0FE943C0D80008DAB01040F
+:103D30003C0C0001016C50241140FE8F2402001045
+:103D40003C010801A02296F10A0021D700000000E2
+:103D50008F9100748F86003826220001ACC2005C6F
+:103D60000A002292241400018F8700382404FF8067
+:103D70000000882190E9000A241400010124302564
+:103D8000A0E6000A3C05080190A596D63C0408016F
+:103D9000908496D90E0020F4000000008F86003831
+:103DA0008F85007890C800FD310700FF0007404074
+:103DB0000107F821001FC0800305C8219323000BD1
+:103DC000A0C300FD8F8500788F8600380305602131
+:103DD000918F000B000F704001CF6821000D808093
+:103DE000020510218C4B0000ACCB00548D840004E4
+:103DF0008F83007400645023194000022482000164
+:103E00002462000101074821ACC2005C0009308037
+:103E100000C5402100E02021240500010E0020F40F
+:103E20009110000B8F86003890C500FF10A0FF0C8A
+:103E3000001070408F85007801D06821000D10803F
+:103E4000004558218D6400008F8C0074018450233C
+:103E50002547000104E0FF02263100013C03080170
+:103E6000906396D62E2F0002247800013C010801B1
+:103E7000A03896D63C010801A03496D711E0FEF890
+:103E8000020038210A002365000740408F84003873
+:103E90008F8300748C85005800A340230502FE9A8E
+:103EA000AC8300580A00223B000000003C070801D8
+:103EB00090E796F2240200FF10E200BE8F860038E1
+:103EC0003C110801963196FA3C030801246396F8E8
+:103ED000262500013230FFFF30ABFFFF02036021D7
+:103EE0002D6A00FF1540008D918700043C010801F8
+:103EF000A42096FA8F88003800074840012728211F
+:103F0000911800FF000530802405000127140001EE
+:103F1000A11400FF3C120801925296F28F8800789B
+:103F20008F8E0070264F000100C820213C0108013F
+:103F3000A02F96F2AC8E00008F8D0074A48500082F
+:103F4000AC8D00043C030801906396D414600077A4
+:103F5000000090213C010801A02596D4A087000B09
+:103F60008F8C007800CC5021A147000A8F82003846
+:103F7000A04700FD8F840038A08700FE8F860038A0
+:103F80008F9F0070ACDF00548F990074ACD900583B
+:103F90008F8D00780127C02100185880016DA02165
+:103FA000928F000A000F704001CF18210003888013
+:103FB000022D8021A207000B8F8600780166602108
+:103FC000918A000B000A1040004A2021000428803A
+:103FD00000A64021A107000A3C07800834E90080C0
+:103FE0008D2200308F860038ACC2005C0A0022921D
+:103FF0002414000190CA00FF1540FEAD8F880074A4
+:10400000A0C400090A0021D78F860038A0C000FD97
+:104010008F98003824060001A30000FE3C0108012F
+:10402000A02696D53C010801A02096D40A0021C6FE
+:104030000000000090CB00FF3C040801908496F340
+:10404000316C00FF0184502B1540000F2402000347
+:1040500024020004A0C200090A0021D78F8600387C
+:1040600090C3000A2410FF8002035824316C00FF23
+:104070001180FDC1000000003C010801A02096D580
+:104080000A0021C600000000A0C200090A0021D7D2
+:104090008F86003890D4000A2412FF8002544824EE
+:1040A000312800FF1500FFF4240200083C0108013C
+:1040B000A02296F10A0021D70000000000108840DD
+:1040C0008F8B0070023018210003688001A7202127
+:1040D000AC8B00008F8A0074240C0001A48C0008B3
+:1040E000AC8A00043C05080190A596D62402000184
+:1040F00010A2FE1E24A5FFFF0A0022519084000B8F
+:104100000184A0231A80FD8B000000003C010801FF
+:10411000A02E96D50A002305240B00013C010801BE
+:10412000A42596FA0A0023B78F880038240B0001D3
+:10413000106B00228F9800388F85003890BF00FFE9
+:1041400033F900FF1079002B000000003C1F08012C
+:1041500093FF96D8001FC840033FC0210018A080DD
+:104160000288782191EE000AA08E000A8F8D0078D7
+:104170003C030801906396D800CD88210A0023DD16
+:10418000A223000B263000010600003101A4902379
+:104190000640002B240200033C010801A02F96D505
+:1041A0000A002305240B00018F8900380A00223BF6
+:1041B000AD2700540A00229124120001931400FD3F
+:1041C000A094000B8F8800388F8F0078910E00FE2E
+:1041D00000CF6821A1AE000A8F910038A22700FD10
+:1041E0008F8300708F900038AE0300540A0023DEE6
+:1041F0008F8D007890B000FEA090000A8F8B003861
+:104200008F8C0078916A00FD00CC1021A04A000B31
+:104210008F840038A08700FE8F8600748F85003859
+:10422000ACA600580A0023DE8F8D007894B80008F1
+:10423000ACA40004030378210A002285A4AF00087F
+:104240003C010801A02296D50A0021C6000000000A
+:1042500090CF0009240D000431EE00FF11CDFD8543
+:10426000240200013C010801A02296D50A0021C6C3
+:1042700000000000080033440800334408003420E4
+:10428000080033F4080033D8080033280800332826
+:10429000080033280800334C8008010080080080A3
+:1042A000800800005F865437E4AC62CC50103A4579
+:1042B00036621985BF14C0E81BC27A1E84F4B55655
+:1042C000094EA6FE7DDA01E7C04D748108005A74DC
+:1042D00008005AB808005A5C08005A5C08005A5C8A
+:1042E00008005A5C08005A7408005A5C08005A5CBE
+:1042F00008005AC008005A5C080059D408005A5CEB
+:1043000008005A5C08005AC008005A5C08005A5C51
+:1043100008005A5C08005A5C08005A5C08005A5CA5
+:1043200008005A5C08005A5C08005A5C08005A5C95
+:1043300008005A9408005A5C08005A9408005A5C15
+:1043400008005A5C08005A5C08005A9808005A9401
+:1043500008005A5C08005A5C08005A5C08005A5C65
+:1043600008005A5C08005A5C08005A5C08005A5C55
+:1043700008005A5C08005A5C08005A5C08005A5C45
+:1043800008005A5C08005A5C08005A5C08005A5C35
+:1043900008005A5C08005A5C08005A5C08005A5C25
+:1043A00008005A9808005A9808005A5C08005A9861
+:1043B00008005A5C08005A5C08005A5C08005A5C05
+:1043C00008005A5C08005A5C08005A5C08005A5CF5
+:1043D00008005A5C08005A5C08005A5C08005A5CE5
+:1043E00008005A5C08005A5C08005A5C08005A5CD5
+:1043F00008005A5C08005A5C08005A5C08005A5CC5
+:1044000008005A5C08005A5C08005A5C08005A5CB4
+:1044100008005A5C08005A5C08005A5C08005A5CA4
+:1044200008005A5C08005A5C08005A5C08005A5C94
+:1044300008005A5C08005A5C08005A5C08005A5C84
+:1044400008005A5C08005A5C08005A5C08005A5C74
+:1044500008005A5C08005A5C08005A5C08005A5C64
+:1044600008005A5C08005A5C08005A5C08005A5C54
+:1044700008005A5C08005A5C08005A5C08005A5C44
+:1044800008005A5C08005A5C08005A5C08005A5C34
+:1044900008005A5C08005A5C08005A5C08005A5C24
+:1044A00008005A5C08005A5C08005A5C08005A5C14
+:1044B00008005A5C08005A5C08005A5C08005A5C04
+:1044C00008005A5C08005A5C08005A5C08005ADC74
+:1044D0000800782C08007A900800783808007628C0
+:1044E00008007838080078C4080078380800762872
+:1044F0000800762808007628080076280800762824
+:104500000800762808007628080076280800762813
+:1045100008007628080078580800784808007628AF
+:1045200008007628080076280800762808007628F3
+:1045300008007628080076280800762808007628E3
+:1045400008007628080076280800762808007848B1
+:10455000080082FC08008188080082C40800818865
+:104560000800829408008070080081880800818813
+:1045700008008188080081880800818808008188F7
+:1045800008008188080081880800818808008188E7
+:104590000800818808008188080081B008008D34F7
+:1045A00008008E9008008E70080088D808008D4C96
+:1045B0000A00012400000000000000000000000DBF
+:1045C000747061362E322E31620000000602010145
+:1045D00000000000000000000000000000000000DB
+:1045E00000000000000000000000000000000000CB
+:1045F00000000000000000000000000000000000BB
+:1046000000000000000000000000000000000000AA
+:10461000000000000000000000000000000000009A
+:10462000000000000000000000000000000000008A
+:10463000000000000000000000000000000000007A
+:104640000000000010000003000000000000000D4A
+:104650000000000D3C020800244217203C03080023
+:1046600024632A10AC4000000043202B1480FFFD7F
+:10467000244200043C1D080037BD2FFC03A0F0219C
+:104680003C100800261004903C1C0800279C1720B2
+:104690000E000262000000000000000D2402FF80F6
+:1046A00027BDFFE000821024AFB00010AF42002011
+:1046B000AFBF0018AFB10014936500043084007FD1
+:1046C000034418213C0200080062182130A5002094
+:1046D000036080213C080111277B000814A0000220
+:1046E0002466005C2466005892020004974301048B
+:1046F000920400043047000F3063FFFF3084004015
+:10470000006728231080000900004821920200055C
+:1047100030420004104000050000000010A000031B
+:104720000000000024A5FFFC2409000492020005FB
+:1047300030420004104000120000000010A00010E1
+:10474000000000009602000200A72021010440257D
+:104750002442FFFEA7421016920300042402FF80A9
+:1047600000431024304200FF104000033C020400CC
+:104770000A000174010240258CC20000AF421018EB
+:104780008F4201780440FFFE2402000AA742014044
+:1047900096020002240400093042000700021023A0
+:1047A00030420007A7420142960200022442FFFE67
+:1047B000A7420144A740014697420104A74201488D
+:1047C0008F420108304200205040000124040001C3
+:1047D00092020004304200101440000234830010A2
+:1047E00000801821A743014A0000000000000000DB
+:1047F0000000000000000000AF48100000000000B2
+:104800000000000000000000000000008F421000C7
+:104810000441FFFE3102FFFF1040000700000000CE
+:1048200092020004304200401440000300000000E7
+:104830008F421018ACC20000960200063042FFFF03
+:10484000244200020002104300021040036288214B
+:10485000962200001120000D3044FFFF00A7102118
+:104860008F8300388F45101C0002108200021080D8
+:1048700000431021AC45000030A6FFFF0E00058D5F
+:1048800000052C0200402021A62200009203000413
+:104890002402FF8000431024304200FF1040001F1C
+:1048A0000000000092020005304200021040001B90
+:1048B000000000009742100C2442FFFEA742101691
+:1048C000000000003C02040034420030AF421000FF
+:1048D00000000000000000000000000000000000D8
+:1048E0008F4210000441FFFE000000009742100CB0
+:1048F0008F45101C3042FFFF24420030000210821E
+:1049000000021080005B1021AC45000030A6FFFFC4
+:104910000E00058D00052C02A62200009604000260
+:10492000248400080E0001E93084FFFF974401044D
+:104930000E0001F73084FFFF8FBF00188FB1001405
+:104940008FB000103C02100027BD002003E00008DB
+:10495000AF4201783084FFFF308200078F8500244A
+:1049600010400002248300073064FFF800A41021E7
+:1049700030421FFF03421821247B4000AF850028EE
+:10498000AF82002403E00008AF4200843084FFFFC0
+:104990003082000F8F85002C8F860034104000027B
+:1049A0002483000F3064FFF000A410210046182B70
+:1049B000AF8500300046202314600002AF82002C37
+:1049C000AF84002C8F82002C340480000342182115
+:1049D00000641821AF83003803E00008AF42008074
+:1049E0008F820014104000088F8200048F82FFDC49
+:1049F000144000058F8200043C02FFBF3442FFFFD9
+:104A0000008220248F82000430430006240200022A
+:104A10001062000F3C0201012C62000350400005AF
+:104A2000240200041060000F3C0200010A00023062
+:104A30000000000010620005240200061462000C51
+:104A40003C0201110A000229008210253C020011DB
+:104A500000821025AF421000240200010A0002303B
+:104A6000AF82000C00821025AF421000AF80000C16
+:104A700000000000000000000000000003E000084B
+:104A8000000000008F82000C1040000400000000B5
+:104A90008F4210000441FFFE0000000003E0000808
+:104AA000000000008F8200102443F800000231C291
+:104AB00024C2FFF02C6303011060000300021042C7
+:104AC0000A000257AC8200008F85001800C5102B29
+:104AD0001440000B0000182100C5102324470001DA
+:104AE0008F82001C00A210212442FFFF0046102BE1
+:104AF000544000042402FFFF0A000257AC87000064
+:104B00002402FFFF0A000260AC8200008C820000D9
+:104B10000002194000621821000318800062182169
+:104B2000000318803C0208002442175C0062182130
+:104B300003E000080060102127BDFFD8AFBF0020B0
+:104B4000AFB1001CAFB000183C0460088C8250006C
+:104B50002403FF7F3C066000004310243442380CDD
+:104B6000AC8250008CC24C1C3C1A80000002160221
+:104B70003042000F10400007AF82001C8CC34C1C59
+:104B80003C02001F3442FC0000621824000319C2DA
+:104B9000AF8300188F420008275B400034420001B9
+:104BA000AF420008AF8000243C02601CAF40008090
+:104BB000AF4000848C4500088CC308083402800094
+:104BC000034220212402FFF0006218243C020080EE
+:104BD0003C010800AC2204203C025709AF84003895
+:104BE00014620004AF850034240200010A0002921E
+:104BF000AF820014AF8000148F42000038420001E1
+:104C0000304200011440FFFC8F8200141040001657
+:104C10000000000097420104104000058F8300004F
+:104C2000146000072462FFFF0A0002A72C62000A3A
+:104C30002C620010504000048F83000024620001A9
+:104C4000AF8200008F8300002C62000A1440000332
+:104C50002C6200070A0002AEAF80FFDC10400002A9
+:104C600024020001AF82FFDC8F4301088F44010062
+:104C700030622000AF83000410400008AF840010B1
+:104C80003C0208008C42042C244200013C01080034
+:104C9000AC22042C0A00058A3C0240003065020068
+:104CA00014A0000324020F001482026024020D00ED
+:104CB00097420104104002C83C02400030624000AC
+:104CC000144000AD8F8200388C4400088F42017878
+:104CD0000440FFFE24020800AF42017824020008CD
+:104CE000A7420140A7400142974201048F8400047B
+:104CF0003051FFFF30820001104000070220802168
+:104D00002623FFFE240200023070FFFFA742014667
+:104D10000A0002DBA7430148A74001463C02080005
+:104D20008C42043C1440000D8F8300103082002020
+:104D30001440000224030009240300010060202124
+:104D40008F830010240209005062000134840004A3
+:104D5000A744014A0A0002F60000000024020F00E6
+:104D60001462000530820020144000062403000D68
+:104D70000A0002F524030005144000022403000980
+:104D800024030001A743014A3C0208008C4204208E
+:104D90003C0400480E00020C004420250E000235A1
+:104DA000000000008F82000C1040003E0000000058
+:104DB0008F4210003C0300200043102410400039B3
+:104DC0008F820004304200021040003600000000D4
+:104DD000974210141440003300000000974210085E
+:104DE0008F8800383042FFFF2442000600021882FC
+:104DF0000003388000E83021304300018CC40000FB
+:104E000010600004304200030000000D0A00033768
+:104E100000E81021544000103084FFFF3C05FFFFE4
+:104E200000852024008518260003182B0004102B71
+:104E300000431024104000050000000000000000A6
+:104E40000000000D00000000240002228CC20000BF
+:104E50000A000336004520253883FFFF0003182B86
+:104E60000004102B00431024104000050000000037
+:104E7000000000000000000D000000002400022BD4
+:104E80008CC200003444FFFF00E81021AC44000055
+:104E90003C0208008C420430244200013C0108001E
+:104EA000AC2204308F6200008F840038AF8200088B
+:104EB0008C8300003402FFFF1462000F00001021F9
+:104EC0003C0508008CA504543C0408008C84045064
+:104ED00000B0282100B0302B008220210086202144
+:104EE0003C010800AC2504543C010800AC240450EB
+:104EF0000A000580240400088C8200003042010072
+:104F00001040000F000010213C0508008CA5044C47
+:104F10003C0408008C84044800B0282100B0302BE9
+:104F200000822021008620213C010800AC25044C91
+:104F30003C010800AC2404480A0005802404000851
+:104F40003C0508008CA504443C0408008C84044003
+:104F500000B0282100B0302B0082202100862021C3
+:104F60003C010800AC2504443C010800AC2404408A
+:104F70000A000580240400088F6200088F62000088
+:104F800000021602304300F02402003010620005D7
+:104F900024020040106200E08F8200200A00058891
+:104FA0002442000114A000050000000000000000E1
+:104FB0000000000D00000000240002568F4201781E
+:104FC0000440FFFE000000000E00023D27A4001078
+:104FD0001440000500408021000000000000000D8A
+:104FE000000000002400025D8E0200001040000559
+:104FF00000000000000000000000000D00000000A4
+:10500000240002608F62000C0443000324020001AC
+:105010000A00042EAE000000AE0200008F820038AD
+:105020008C480008A20000078F65000C8F64000404
+:1050300030A3FFFF0004240200852023308200FFFC
+:105040000043102124420005000230832CC200815D
+:10505000A605000A14400005A20400040000000098
+:105060000000000D00000000240002788F85003849
+:105070000E0005AB260400148F6200048F43010864
+:10508000A60200083C02100000621824106000080C
+:105090000000000097420104920300072442FFEC45
+:1050A000346300023045FFFF0A0003C3A203000778
+:1050B000974201042442FFF03045FFFF96060008A6
+:1050C0002CC200135440000592030007920200070F
+:1050D00034420001A20200079203000724020001EB
+:1050E00010620005240200031062000B8F8200385A
+:1050F0000A0003E030C6FFFF8F8200383C04FFFF48
+:105100008C43000C0064182400651825AC43000C87
+:105110000A0003E030C6FFFF3C04FFFF8C43001091
+:105120000064182400651825AC43001030C6FFFF4A
+:1051300024C2000200021083A20200058F830038FF
+:10514000304200FF00021080004328218CA800009C
+:105150008CA2000024030004000217021443001272
+:1051600000000000974201043C03FFFF01031824E4
+:105170003042FFFF004610232442FFFE006240251C
+:10518000ACA8000092030005306200FF000210800E
+:1051900000501021904200143042000F00431021B3
+:1051A0000A000415A20200068CA400049742010420
+:1051B0009603000A3088FFFF3042FFFF00461023AD
+:1051C0002442FFD60002140001024025ACA80004CE
+:1051D000920200079204000524630028000318834C
+:1051E0000064182134420004A2030006A202000752
+:1051F0008F8200042403FFFB34420002004310248A
+:10520000AF820004920300068F87003800031880E5
+:10521000007010218C4400203C02FFF63442FFFF56
+:105220000082402400671821AE04000CAC68000C1A
+:10523000920500063C03FF7F8E02000C00052880CB
+:1052400000B020213463FFFF01033024948800263E
+:1052500000A7282100431024AE02000CAC860020D9
+:10526000AC880024ACA8001024020010A742014022
+:1052700024020002A7400142A7400144A742014680
+:10528000974201043C0400082442FFFEA742014863
+:10529000240200010E00020CA742014A9603000AF4
+:1052A0009202000400431021244200023042000711
+:1052B00000021023304200070E000235AE0200103B
+:1052C0008F6200003C0308008C6304442404001037
+:1052D000AF820008974201043042FFFF2442FFFEE4
+:1052E00000403821000237C33C0208008C420440D1
+:1052F000006718210067282B004610210045102167
+:105300003C010800AC2304443C010800AC220440EA
+:105310000A0005150000000014A0000500000000B0
+:10532000000000000000000D000000002400030A3F
+:105330008F4201780440FFFE000000000E00023D95
+:1053400027A4001414400005004080210000000044
+:105350000000000D00000000240003118E02000078
+:105360005440000692020007000000000000000DFB
+:10537000000000002400031C9202000730420004D9
+:10538000104000058F8200042403FFFB344200021A
+:1053900000431024AF8200048F620004044300081D
+:1053A00092020007920200068E03000CAE0000007D
+:1053B0000002108000501021AC4300209202000730
+:1053C00030420004544000099602000A920200058F
+:1053D0003C03000100021080005010218C46001890
+:1053E00000C33021AC4600189602000A9206000461
+:1053F000277100080220202100C2302124C60005A8
+:10540000260500140E0005AB00063082920400064B
+:105410008F6500043C027FFF000420800091202162
+:105420008C8300043442FFFF00A228240065182169
+:10543000AC8300049202000792040005920300046A
+:10544000304200041040001496070008308400FF2A
+:1054500000042080009120218C86000497420104E2
+:105460009605000A306300FF3042FFFF0043102121
+:105470000045102130E3FFFF004310232442FFD8F2
+:1054800030C6FFFF0002140000C23025AC860004C5
+:105490000A0004C992030007308500FF0005288038
+:1054A00000B128218CA4000097420104306300FF62
+:1054B0003042FFFF00431021004710233C03FFFF51
+:1054C000008320243042FFFF00822025ACA400008E
+:1054D0009203000724020001106200060000000091
+:1054E0002402000310620011000000000A0004EC16
+:1054F0008E03001097420104920300049605000AEF
+:105500008E24000C00431021004510212442FFF29C
+:105510003C03FFFF008320243042FFFF0082202550
+:10552000AE24000C0A0004EC8E0300109742010424
+:10553000920300049605000A8E24001000431021F7
+:10554000004510212442FFEE3C03FFFF008320248E
+:105550003042FFFF00822025AE2400108E03001091
+:105560002402000AA7420140A74301429603000A11
+:10557000920200043C04004000431021A742014471
+:10558000A740014697420104A742014824020001B6
+:105590000E00020CA742014A0E0002350000000076
+:1055A0008F6200009203000400002021AF820008F7
+:1055B000974201049606000A3042FFFF006218215C
+:1055C000006028213C0308008C6304443C0208006E
+:1055D0008C42044000651821004410210065382BDE
+:1055E000004710213C010800AC2304443C010800A2
+:1055F000AC22044092040004008620212484000A86
+:105600003084FFFF0E0001E9000000009744010410
+:105610003084FFFF0E0001F7000000003C02100084
+:10562000AF4201780A0005878F820020148200278C
+:105630003062000697420104104000673C024000BF
+:105640003062400010400005000000000000000033
+:105650000000000D00000000240004208F420178AB
+:105660000440FFFE24020800AF4201782402000833
+:10567000A7420140A74001428F82000497430104E2
+:1056800030420001104000073070FFFF2603FFFE8C
+:1056900024020002A7420146A74301480A00053F31
+:1056A0002402000DA74001462402000DA742014A32
+:1056B0008F62000024040008AF8200080E0001E998
+:1056C000000000000A0005190200202110400042DD
+:1056D0003C02400093620000304300F024020010BE
+:1056E0001062000524020070106200358F820020D5
+:1056F0000A000588244200018F62000097430104DC
+:105700003050FFFF3071FFFF8F4201780440FFFEF1
+:105710003202000700021023304200072403000A6F
+:105720002604FFFEA7430140A7420142A7440144CB
+:10573000A7400146A75101488F420108304200208E
+:10574000144000022403000924030001A743014A76
+:105750000E00020C3C0400400E0002350000000068
+:105760003C0708008CE70444021110212442FFFE8C
+:105770003C0608008CC604400040182100E3382194
+:10578000000010218F65000000E3402B00C2302193
+:105790002604000800C830213084FFFFAF850008D0
+:1057A0003C010800AC2704443C010800AC2604403E
+:1057B0000E0001E9000000000A0005190220202166
+:1057C0000E00013B000000008F82002024420001F7
+:1057D000AF8200203C024000AF4201380A00029232
+:1057E000000000003084FFFF30C6FFFF00052C00E2
+:1057F00000A628253882FFFF004510210045282BF0
+:105800000045102100021C023042FFFF004310211E
+:1058100000021C023042FFFF004310213842FFFF0C
+:1058200003E000083042FFFF3084FFFF30A5FFFF98
+:1058300000001821108000070000000030820001E5
+:105840001040000200042042006518210A0005A152
+:105850000005284003E000080060102110C0000689
+:1058600024C6FFFF8CA2000024A50004AC82000027
+:105870000A0005AB2484000403E0000800000000D7
+:1058800010A0000824A3FFFFAC8600000000000069
+:10589000000000002402FFFF2463FFFF1462FFFAF0
+:1058A0002484000403E00008000000000000000160
+:1058B0000A00002A00000000000000000000000DA7
+:1058C000747870362E322E3162000000060201001C
+:1058D00000000000000001360000EA600000000047
+:1058E00000000000000000000000000000000000B8
+:1058F00000000000000000000000000000000000A8
+:105900000000000000000000000000000000000097
+:105910000000001600000000000000000000000071
+:105920000000000000000000000000000000000077
+:105930000000000000000000000000000000000067
+:1059400000000000000000000000138800000000BC
+:10595000000005DC00000000000000001000000353
+:10596000000000000000000D0000000D3C020800D7
+:1059700024423D683C0308002463401CAC40000006
+:105980000043202B1480FFFD244200043C1D08002E
+:1059900037BD7FFC03A0F0213C100800261000A8B2
+:1059A0003C1C0800279C3D680E00044E00000000CF
+:1059B0000000000D27BDFFB4AFA10000AFA200049E
+:1059C000AFA30008AFA4000CAFA50010AFA6001451
+:1059D000AFA70018AFA8001CAFA90020AFAA0024F1
+:1059E000AFAB0028AFAC002CAFAD0030AFAE003491
+:1059F000AFAF0038AFB8003CAFB90040AFBC004417
+:105A0000AFBF00480E000591000000008FBF0048A6
+:105A10008FBC00448FB900408FB8003C8FAF003876
+:105A20008FAE00348FAD00308FAC002C8FAB0028D0
+:105A30008FAA00248FA900208FA8001C8FA7001810
+:105A40008FA600148FA500108FA4000C8FA3000850
+:105A50008FA200048FA1000027BD004C3C1B6004F6
+:105A60008F7A5030377B502803400008AF7A00000F
+:105A70008F86003C3C0390003C0280000086282575
+:105A800000A32025AC4400203C0380008C6700204C
+:105A900004E0FFFE0000000003E00008000000003A
+:105AA0000A000070240400018F85003C3C04800043
+:105AB0003483000100A3102503E00008AC8200201D
+:105AC00003E00008000010213084FFFF30A5FFFF35
+:105AD00010800007000018213082000110400002F1
+:105AE00000042042006518211480FFFB00052840B7
+:105AF00003E000080060102110C000070000000053
+:105B00008CA2000024C6FFFF24A50004AC82000084
+:105B100014C0FFFB2484000403E000080000000020
+:105B200010A0000824A3FFFFAC86000000000000C6
+:105B3000000000002402FFFF2463FFFF1462FFFA4D
+:105B40002484000403E000080000000090AA003153
+:105B50008FAB00108CAC00403C0300FF8D6800044C
+:105B6000AD6C00208CAD004400E060213462FFFF8A
+:105B7000AD6D00248CA700483C09FF000109C0243A
+:105B8000AD6700288CAE004C0182C824031978252B
+:105B9000AD6F0004AD6E002C8CAD0038314A00FFB3
+:105BA000AD6D001C94A900323128FFFFAD680010D4
+:105BB00090A70030A5600002A1600004A16700006A
+:105BC00090A30032306200FF0002198210600005CD
+:105BD000240500011065000E0000000003E000082D
+:105BE000A16A00018CD80028354A0080AD780018E1
+:105BF0008CCF0014AD6F00148CCE0030AD6E000859
+:105C00008CC4002CA16A000103E00008AD64000C04
+:105C10008CCD001CAD6D00188CC90014AD6900144A
+:105C20008CC80024AD6800088CC70020AD67000C4C
+:105C30008CC200148C8300700043C82B1320000713
+:105C4000000000008CC20014144CFFE400000000AF
+:105C5000354A008003E00008A16A00018C820070D0
+:105C60000A0000E6000000009089003027BDFFF820
+:105C70008FA8001CA3A900008FA300003C0DFF808B
+:105C800035A2FFFF8CAC002C00625824AFAB0000A3
+:105C9000A100000400C05821A7A000028D06000446
+:105CA00000A048210167C8218FA500000080502175
+:105CB0003C18FF7F032C20263C0E00FF2C8C00019B
+:105CC000370FFFFF35CDFFFF3C02FF0000AFC824B8
+:105CD00000EDC02400C27824000C1DC003236825F9
+:105CE00001F87025AD0D0000AD0E00048D240024D8
+:105CF000AFAD0000AD0400088D2C00202404FFFF90
+:105D0000AD0C000C9547003230E6FFFFAD060010E9
+:105D10009145004830A200FF000219C25060000106
+:105D20008D240034AD0400148D4700388FAA00186C
+:105D300027BD0008AD0B0028AD0A0024AD07001CEC
+:105D4000AD00002CAD00001803E00008AD000020FD
+:105D500027BDFFE0AFB20018AFB10014AFB0001024
+:105D6000AFBF001C9098003000C088213C0D00FFA0
+:105D7000330F007FA0CF0000908E003135ACFFFFC5
+:105D80003C0AFF00A0CE000194A6001EA220000441
+:105D90008CAB00148E29000400A08021016C282403
+:105DA000012A40240080902101052025A62600021A
+:105DB000AE24000426050020262400080E000092D0
+:105DC00024060002924700302605002826240014ED
+:105DD00000071E000003160324060004044000030D
+:105DE0002403FFFF965900323323FFFF0E00009279
+:105DF000AE230010262400248FBF001C8FB2001891
+:105E00008FB100148FB00010240500030000302172
+:105E10000A00009C27BD002027BDFFD8AFB1001CA1
+:105E2000AFB00018AFBF002090A9003024020001DD
+:105E300000E050213123003F00A040218FB00040FE
+:105E40000080882100C04821106200148FA700380C
+:105E5000240B000500A0202100C02821106B001396
+:105E6000020030210E000128000000009225007C75
+:105E700030A400021080000326030030AE00003082
+:105E8000260300348FBF00208FB1001C8FB0001894
+:105E90000060102103E0000827BD00280E0000A7C5
+:105EA000AFB000100A00016F000000008FA3003C9B
+:105EB000010020210120282101403021AFA3001042
+:105EC0000E0000EEAFB000140A00016F00000000E9
+:105ED0003C06800034C20E008C4400108F850044C4
+:105EE000ACA400208C43001803E00008ACA30024FD
+:105EF0003C06800034C20E008C4400148F850044A0
+:105F0000ACA400208C43001C03E00008ACA30024D8
+:105F10009382000C1040001B2483000F2404FFF028
+:105F20000064382410E00019978B00109784000E4D
+:105F30009389000D3C0A601C0A0001AC01644023F7
+:105F400001037021006428231126000231C2FFFFE3
+:105F500030A2FFFF0047302B50C0000E00E4482164
+:105F60008D4D000C31A3FFFF00036400000C2C03D7
+:105F700004A1FFF30000302130637FFF0A0001A479
+:105F80002406000103E00008000000009784000ED2
+:105F900000E448213123FFFF3168FFFF0068382B00
+:105FA00054E0FFF8A783000E938A000D114000050E
+:105FB000240F0001006BC023A380000D03E0000844
+:105FC000A798000E006BC023A38F000D03E000080C
+:105FD000A798000E03E000080000000027BDFFE8BE
+:105FE000AFB000103C10800036030140308BFFFF43
+:105FF00093AA002BAFBF0014A46B000436040E005C
+:106000009488001630C600FF8FA90030A4680006EF
+:10601000AC650008A0660012A46A001AAC670020F4
+:106020008FA5002CA4690018012020210E000198E2
+:10603000AC6500143C021000AE0201788FBF001462
+:106040008FB0001003E0000827BD00188F85000006
+:106050002484000727BDFFF83084FFF83C06800049
+:1060600094CB008A316AFFFFAFAA00008FA900001D
+:10607000012540232507FFFF30E31FFF0064102B9D
+:106080001440FFF700056882000D288034CC4000E2
+:1060900000AC102103E0000827BD00088F8200003B
+:1060A0002486000730C5FFF800A2182130641FFFC6
+:1060B00003E00008AF8400008F87003C8F84004419
+:1060C00027BDFFB0AFB70044AFB40038AFB1002C6C
+:1060D000AFBF0048AFB60040AFB5003CAFB300342F
+:1060E000AFB20030AFB000283C0B80008C8600249B
+:1060F000AD6700808C8A002035670E00356901008D
+:10610000ACEA00108C8800248D2500040000B82122
+:10611000ACE800188CE3001000A688230000A02142
+:10612000ACE300148CE20018ACE2001C122000FE6C
+:1061300000E0B021936C0008118000F40000000022
+:10614000976F001031EEFFFF022E682B15A000EFB5
+:1061500000000000977200103250FFFFAED0000028
+:106160003C0380008C740000329300081260FFFD35
+:106170000000000096D800088EC700043305FFFF1A
+:1061800030B5000112A000E4000000000000000D86
+:1061900030BFA0402419004013F9011B30B4A00007
+:1061A000128000DF000000009373000812600008F6
+:1061B00000000000976D001031ACFFFF00EC202BB9
+:1061C0001080000330AE004011C000D50000000078
+:1061D000A7850040AF87003893630008022028217C
+:1061E000AFB10020146000F527B40020AF60000CB0
+:1061F000978F004031F14000162000022403001662
+:106200002403000E24054007A363000AAF650014B1
+:10621000938A00428F70001431550001001512401E
+:1062200002024825AF690014979F00408F78001440
+:1062300033F9001003194025AF680014979200400D
+:106240003247000810E0016E000000008F67001464
+:106250003C1210003C11800000F27825AF6F001452
+:1062600036230E00946E000A3C0D81002406000EB9
+:1062700031CCFFFF018D2025AF640004A36600022E
+:106280009373000A3406FFFC266B0004A36B000A1C
+:1062900097980040330820001100015F00000000C3
+:1062A0003C05800034A90E00979900409538000CF9
+:1062B00097870040001940423312C00031030003A9
+:1062C00000127B0330F11000006F6825001172038B
+:1062D00001AE6025000C20C0A76400129793004017
+:1062E000936A000A001359823175003C02AA1021FA
+:1062F0002450003CA3700009953F000C33F93FFF88
+:10630000A779001097700012936900090130F821F5
+:1063100027E5000230B900070019C0233308000741
+:10632000A368000B9371000997720012976F001019
+:10633000322700FF8F910038978D004000F218211E
+:10634000006F702101C6602131A6004010C0000519
+:106350003185FFFF00B1102B3C1280001040001768
+:10636000000098210225A82B56A0013E8FA50020F1
+:106370003C048000348A0E008D5300143C068000DB
+:10638000AD5300108D4B001CAD4B0018AD45000007
+:106390008CCD000031AC00081180FFFD34CE0E0022
+:1063A00095C3000800A0882100009021A783004029
+:1063B0008DC6000424130001AF860038976F0010CB
+:1063C00031F5FFFF8E9F000003F1282310A0011F6D
+:1063D000AE85000093620008144000DD000000005C
+:1063E0000E0001E7240400108F900048004028218F
+:1063F0003C023200320600FF000654000142F8253C
+:1064000026090001AF890048ACBF0000937900095C
+:1064100097780012936F000A332800FF3303FFFFC1
+:106420000103382100076C0031EE00FF01AE60254A
+:10643000ACAC00048F840048978B0040316A200088
+:106440001140010AACA4000897640012308BFFFFD2
+:1064500006400108ACAB000C978E004031C5000827
+:1064600014A0000226280006262800023C1F8000F7
+:1064700037E70E0094F900148CE5001C8F670004C8
+:10648000937800023324FFFF330300FFAFA3001013
+:106490008F6F0014AFA800180E0001CBAFAF00142F
+:1064A000240400100E0001FB000000008E9200008A
+:1064B00016400005000000008F7800142403FFBF81
+:1064C0000303A024AF7400148F67000C00F5C821EB
+:1064D000AF79000C9375000816A0000800000000BA
+:1064E00012600006000000008F6800143C0AEFFFF5
+:1064F0003549FFFE0109F824AF7F0014A37300089B
+:106500008FA500200A00034F02202021AED10000F9
+:106510000A00022D3C03800014E0FF1E30BFA040A3
+:106520000E0001900000A0212E9100010237B0253D
+:1065300012C000188FBF00488F87003C24170F003F
+:1065400010F700D43C0680008CD901780720FFFEAC
+:10655000241F0F0010FF00F634CA0E008D560014E1
+:1065600034C7014024080240ACF600048D49001CE9
+:106570003C141000ACE90008A0E00012A4E0001AEE
+:10658000ACE00020A4E00018ACE80014ACD4017822
+:106590008FBF00488FB700448FB600408FB5003CD6
+:1065A0008FB400388FB300348FB200308FB1002C1D
+:1065B0008FB0002803E0000827BD00508F910038FD
+:1065C000978800403C1280000220A821310700403B
+:1065D00014E0FF7C00009821977900108F9200381A
+:1065E0003338FFFF131200A8000020210080A021F3
+:1065F000108000F300A088211620FECE00000000CD
+:106600000A00031F2E9100013C0380008C62017878
+:106610000440FFFE240808008F860000AC68017863
+:106620003C038000946D008A31ACFFFF0186582343
+:10663000256AFFFF31441FFF2C8900081520FFF950
+:10664000000000008F8F0048347040008F83003CB2
+:1066500000E0A021240E0F0025E70001AF870048CD
+:1066600000D03021023488233C08800031F500FF3F
+:10667000106E0005240700019398004233130001B7
+:106680000013924036470001001524003C0A010027
+:10669000008A4825ACC900008F82004830BF003610
+:1066A00030B90008ACC200041320009900FF9825FF
+:1066B00035120E009650000A8F8700003C0F8100B3
+:1066C0003203FFFF24ED000835060140006F60250E
+:1066D0003C0E100031AB1FFF269200062405000E71
+:1066E000ACCC0020026E9825A4C5001AAF8B000028
+:1066F000A4D20018162000083C1080008F89003CAE
+:1067000024020F00512200022417000136730040BA
+:106710000E0001883C10800036060E008CCB001461
+:10672000360A014002402021AD4B00048CC5001CFC
+:10673000AD450008A1550012AD5300140E0001989C
+:106740003C151000AE1501780A000352000000004D
+:10675000936F0009976E0012936D000B31E500FFF7
+:1067600000AE202131AC00FF008C80212602000AFF
+:106770003050FFFF0E0001E7020020218F86004805
+:106780003C0341003C05800024CB0001AF8B004856
+:10679000936A00099769001230C600FF315F00FF5D
+:1067A0003128FFFF03E8382124F900020006C40065
+:1067B0000319782501E37025AC4E00008F6D000CA5
+:1067C00034A40E00948B001401B26025AC4C00047C
+:1067D0008C85001C8F670004936A00023164FFFF00
+:1067E000314900FFAFA900108F680014AFB1001845
+:1067F0000E0001CBAFA800140A0002FD0200202108
+:10680000AF600004A36000029798004033082000A6
+:106810001500FEA300003021A760001297840040FD
+:10682000936B000A3C10800030931F0000135183CB
+:10683000014BA82126A20028A362000936090E00F8
+:10684000953F000C0A000295A77F00108F7000147E
+:10685000360900400E000188AF6900140A0002C921
+:10686000000000000A00034F000020210641FEFA4C
+:10687000ACA0000C8CAC000C3C0D8000018D902570
+:106880000A0002EAACB2000C000090210A0002C526
+:1068900024130001128000073C028000344B0E00DC
+:1068A0009566000830D300401260004900000000E7
+:1068B0003C0680008CD001780600FFFE34C50E0037
+:1068C00094B500103C03050034CC014032B8FFFF02
+:1068D00003039025AD92000C8CAF0014240D200012
+:1068E0003C041000AD8F00048CAE001CAD8E00087F
+:1068F000A1800012A580001AAD800020A58000189C
+:10690000AD8D0014ACC401780A0003263C0680005B
+:106910008F9F0000351801402692000227F90008D9
+:1069200033281FFFA71200180A000391AF88000048
+:106930003C02800034450140ACA0000C1280001BDA
+:1069400034530E0034510E008E370010ACB70004E3
+:106950008E2400183C0B8000ACA400083570014068
+:1069600024040040A20000128FBF0048A600001AB5
+:106970008FB70044AE0000208FB60040A60000187C
+:106980008FB5003CAE0400148FB400388FB30034D0
+:106990008FB200308FB1002C8FB000283C02100065
+:1069A00027BD005003E00008AD6201788E66001438
+:1069B000ACA600048E64001C0A00042A3C0B800074
+:1069C0000E0001902E9100010A0003200237B0252D
+:1069D000000000000000000D00000000240003691A
+:1069E0000A0004013C06800027BDFFD8AFBF00208D
+:1069F0003C0980003C1F20FFAFB200183C0760003C
+:106A000035320E002402001037F9FFFDACE23008E9
+:106A1000AFB3001CAFB10014AFB00010AE5900000E
+:106A20000000000000000000000000000000000066
+:106A3000000000003C1800FF3713FFFDAE530000BC
+:106A40003C0B60048D7050002411FF7F3C0E00024F
+:106A50000211782435EC380C35CD0109ACED4C1819
+:106A6000240A0009AD6C50008CE80438AD2A0008F7
+:106A7000AD2000148CE54C1C3106FFFF38C42F718B
+:106A800000051E023062000F2486C0B310400007CC
+:106A9000AF8200088CE54C1C3C09001F3528FC0027
+:106AA00000A81824000321C2AF8400048CF1080858
+:106AB0003C0F57092412F0000232702435F0001008
+:106AC00001D0602601CF68262DAA00012D8B000180
+:106AD000014B382550E00009A380000C3C1F601CCE
+:106AE0008FF8000824190001A399000C33137C00CF
+:106AF000A7930010A780000EA380000DAF80004870
+:106B000014C00003AF8000003C066000ACC0442C01
+:106B10000E0005B93C1080000E000F1A361101005E
+:106B20003C12080026523DD03C13080026733E500C
+:106B30008E03000038640001308200011440FFFC25
+:106B40003C0B800A8E2600002407FF8024C90240E7
+:106B5000312A007F014B402101272824AE06002066
+:106B6000AF880044AE0500243C048000AF86003CA2
+:106B70008C8C01780580FFFE24180800922F0008F5
+:106B8000AC980178A38F0042938E004231CD000172
+:106B900011A0000F24050D0024DFF8002FF90301D8
+:106BA0001320001C000629C224A4FFF00004104298
+:106BB000000231400E00020200D2D8213C02400007
+:106BC0003C068000ACC201380A0004A000000000AE
+:106BD00010C50023240D0F0010CD00273C1F800896
+:106BE00037F9008093380000240E0050330F00FF67
+:106BF00015EEFFF33C0240000E000A3600000000D4
+:106C00003C0240003C068000ACC201380A0004A0EF
+:106C1000000000008F83000400A3402B1500000B30
+:106C20008F8B0008006B50212547FFFF00E5482BA4
+:106C30001520000600A36023000C19400E0002027C
+:106C40000073D8210A0004C43C0240000000000D7B
+:106C50000E000202000000000A0004C43C024000D2
+:106C60003C1B0800277B3F500E0002020000000082
+:106C70000A0004C43C0240003C1B0800277B3F7014
+:106C80000E000202000000000A0004C43C024000A2
+:106C90003C0660043C09080025290104ACC9502CBD
+:106CA0008CC850003C0580003C0200023507008083
+:106CB000ACC750003C040800248415A43C03080021
+:106CC0002463155CACA50008ACA2000C3C010800D4
+:106CD000AC243D603C010800AC233D6403E00008A7
+:106CE0002402000100A030213C1C0800279C3D68C4
+:106CF0003C0C04003C0B0002008B3826008C402624
+:106D00002CE200010007502B2D050001000A4880ED
+:106D10003C03080024633D60004520250123182121
+:106D20001080000300001021AC6600002402000166
+:106D300003E00008000000003C1C0800279C3D68A0
+:106D40003C0B04003C0A0002008A3026008B3826E7
+:106D50002CC200010006482B2CE5000100094080F0
+:106D60003C03080024633D600045202501031821F1
+:106D700010800005000010213C0C0800258C155CDB
+:106D8000AC6C00002402000103E0000800000000D9
+:106D90003C0900023C08040000883026008938269F
+:106DA0002CC30001008028212CE400010083102561
+:106DB0001040000B000030213C1C0800279C3D685F
+:106DC0003C0A80008D4E00082406000101CA682597
+:106DD000AD4D00088D4C000C01855825AD4B000CC5
+:106DE00003E0000800C010213C1C0800279C3D68FF
+:106DF0003C0580008CA6000C000420272402000122
+:106E000000C4182403E00008ACA3000C3C020002FC
+:106E10001082000B3C0560003C0704001087000353
+:106E20000000000003E00008000000008CA908D06A
+:106E3000240AFFFD012A402403E00008ACA808D082
+:106E40008CA408D02406FFFE0086182403E0000866
+:106E5000ACA308D03C05601A34A600108CC3008097
+:106E600027BDFFF88CC50084AFA3000093A40000E9
+:106E70002402000110820003AFA5000403E0000813
+:106E800027BD000893A7000114E0001497AC00028E
+:106E900097B800023C0F8000330EFFFC01CF682141
+:106EA000ADA50000A3A000003C0660008CC708D080
+:106EB0002408FFFE3C04601A00E82824ACC508D072
+:106EC0008FA300048FA200003499001027BD000892
+:106ED000AF22008003E00008AF2300843C0B800059
+:106EE000318AFFFC014B48218D2800000A00057DF6
+:106EF000AFA8000427BDFFE8AFBF00103C1C08008E
+:106F0000279C3D683C0580008CA4000C8CA20004EA
+:106F10003C0300020044282410A0000A00A3182407
+:106F20003C0604003C0400021460000900A6102482
+:106F30001440000F3C0404000000000D3C1C08003D
+:106F4000279C3D688FBF001003E0000827BD001894
+:106F50003C0208008C423D600040F809000000003F
+:106F60003C1C0800279C3D680A0005A68FBF001046
+:106F70003C0208008C423D640040F809000000001B
+:106F80000A0005AC00000000000411C003E0000886
+:106F9000244202403C04080024843FB42405001A23
+:106FA0000A00009C0000302127BDFFE0AFB00010B8
+:106FB0003C108000AFBF0018AFB1001436110100C3
+:106FC000922200090E0005B63044007F8E3F00007B
+:106FD0008F89003C3C0F008003E26021258800403F
+:106FE0000049F821240DFF80310E00783198007897
+:106FF00035F9000135F100020319382501D1482582
+:10700000010D302403ED5824018D2824240A00406A
+:1070100024040080240300C0AE0B0024AE0008103E
+:10702000AE0A0814AE040818AE03081CAE05080426
+:10703000AE070820AE060808AE0908243609090084
+:107040009539000C3605098033ED007F3338FFFF9A
+:10705000001889C0AE110800AE0F0828952C000C4E
+:107060008FBF00188FB10014318BFFFF000B51C090
+:10707000AE0A002C8CA400508FB000108CA3003CF2
+:107080008D2700048CA8001C8CA600383C0E800ABA
+:1070900001AE102127BD0020AF820044AF84005014
+:1070A000AF830054AF87004CAF88005C03E000085A
+:1070B000AF8600603C09080091293FD924A800024E
+:1070C0003C05110000093C0000E8302500C51825EA
+:1070D00024820008AC83000003E00008AC800004B8
+:1070E0003C098000352309009128010B906A0011AA
+:1070F0002402002800804821314700FF00A07021B1
+:1071000000C068213108004010E20002340C86DD26
+:10711000240C08003C0A800035420A9A944700007B
+:10712000354B0A9C35460AA030F9FFFFAD39000007
+:107130008D780000354B0A8024040001AD3800042E
+:107140008CCF0000AD2F00089165001930A300031B
+:107150001064009028640002148000AF240500022F
+:107160001065009E240F0003106F00B435450AA47B
+:10717000240A0800118A0048000000005100003D68
+:107180003C0B80003C0480003483090090670012AF
+:1071900030E200FF004D7821000FC8802724000155
+:1071A0003C0A8000354F090091E50019354C0980F3
+:1071B0008D87002830A300FF0003150000475825E5
+:1071C0000004C4003C19600001793025370806FF2F
+:1071D000AD260000AD2800048DEA002C25280028EB
+:1071E000AD2A00088DEC0030AD2C000C8DE500348C
+:1071F000AD2500108DE400383C05800034AC093C1E
+:10720000AD2400148DE3001CAD2300188DE7002091
+:10721000AD27001C8DE20024AD2200208DF900284E
+:1072200034A20100AD3900248D830000AD0E0004AE
+:1072300034B90900AD0300008C47000C250200148E
+:10724000AD070008932B00123C04080090843FD83F
+:10725000AD000010317800FF030D302100064F0013
+:1072600000047C00012F702535CDFFFC03E00008F1
+:10727000AD0D000C35780900930600123C0508009E
+:1072800094A53FC830C800FF010D5021000A60805E
+:107290000A00063C018520211500005B000000006B
+:1072A0003C08080095083FCE3C06080094C63FC83D
+:1072B000010610213C0B800035790900933800113C
+:1072C000932A001935660A80330800FF94CF002AFC
+:1072D00000086082314500FF978A0058000C1E00AC
+:1072E000000524003047FFFF006410250047C0253B
+:1072F00001EA30213C0B4000030B402500066400EE
+:10730000AD280000AD2C0004932500183C030006B6
+:107310002528001400053E0000E31025AD220008DA
+:107320008F24002C3C05800034AC093CAD24000CBB
+:107330008F38001C34A20100254F0001AD38001029
+:107340008D830000AD0E000431EB7FFFAD03000024
+:107350008C47000C34B90900A78B0058AD07000812
+:10736000932B00123C04080090843FD8250200149F
+:10737000317800FF030D302100064F0000047C002F
+:10738000012F702535CDFFFCAD00001003E0000893
+:10739000AD0D000C3C02080094423FD23C050800B1
+:1073A00094A53FC835440AA43C07080094E73FC4AD
+:1073B000948B00000045C8210327C023000B1C004C
+:1073C0002706FFF200665025AD2A000CAD20001004
+:1073D000AD2C00140A00063025290018354F0AA4E8
+:1073E00095E50000956400280005140000043C00A9
+:1073F0003459810000EC5825AD39000CAD2B00103C
+:107400000A000630252900143C0C0800958C3FCE5C
+:107410000A000681258200015460FF56240A0800F4
+:1074200035580AA49706000000061C00006C502581
+:10743000AD2A000C0A000630252900103C03080084
+:1074400094633FD23C07080094E73FC83C0F080014
+:1074500095EF3FC494A4000095790028006710219F
+:10746000004F582300041C00001934002578FFEE5B
+:1074700000D87825346A8100AD2A000CAD2F0010A9
+:10748000AD200014AD2C00180A0006302529001C80
+:1074900003E00008240207D027BDFFE0AFB20018C8
+:1074A000AFB10014AFB00010AFBF001C0E00007CE5
+:1074B000008088218F8800548F87004C3C0580080D
+:1074C00034B20080011128213C1080002402008089
+:1074D000240300C000A72023AE0208183C06800841
+:1074E000AE03081C18800004AF850054ACC500042E
+:1074F0008CC90004AF89004C1220000936040980B1
+:107500000E0006F800000000924C00278E0B00745D
+:1075100001825004014B3021AE46000C3604098034
+:107520008C8E001C8F8F005C01CF682319A0000493
+:107530008FBF001C8C90001CAF90005C8FBF001CA4
+:107540008FB200188FB100148FB000100A00007EB7
+:1075500027BD00208F8600508F8300548F82004CFF
+:107560003C05800834A40080AC860050AC83003C0D
+:1075700003E00008ACA200043C0308008C63005444
+:1075800027BDFFF8308400FF2462000130A500FF12
+:107590003C010800AC22005430C600FF3C078000CC
+:1075A0008CE801780500FFFE3C0C7FFFA3A40003DC
+:1075B0008FAA0000358BFFFF014B4824000627C02F
+:1075C00001244025AFA8000034E201009043000AE6
+:1075D000A3A000023C1980FFA3A300018FAF00000D
+:1075E00030AE007F3738FFFF01F86024000E6E00D8
+:1075F0003C0A002034E50140018D58253549200022
+:107600002406FF803C04100027BD0008ACAB000C32
+:10761000ACA90014A4A00018A0A6001203E0000862
+:10762000ACE40178308800FF30A700FF3C03800005
+:107630008C6201780440FFFE3C0C8000358A0A0011
+:107640008D4B00203584014035850980AC8B0004CA
+:107650008D4900240007302B00061540AC89000836
+:10766000A088001090A3004CA083002D03E0000828
+:10767000A480001827BDFFE8308400FFAFBF0010D2
+:107680000E00075D30A500FF8F8300548FBF0010F0
+:107690003C06800034C50140344700402404FF907C
+:1076A0003C02100027BD0018ACA3000CA0A40012DF
+:1076B000ACA7001403E00008ACC2017827BDFFE0CE
+:1076C0003C088008AFBF001CAFB20018AFB1001477
+:1076D000AFB00010351000808E0600183C07800007
+:1076E000309200FF00C72025AE0400180E00007C79
+:1076F00030B100FF92030005346200080E00007EE6
+:10770000A2020005024020210E000771022028215C
+:10771000024020218FBF001C8FB200188FB10014CF
+:107720008FB0001024050005240600010A0007326E
+:1077300027BD00203C05800034A309809066000826
+:1077400030C200081040000F3C0A01013549080A08
+:10775000AC8900008CA80074AC8800043C070800C9
+:1077600090E73FD830E5001050A00008AC8000083A
+:107770003C0D800835AC00808D8B0058AC8B000828
+:107780002484000C03E00008008010210A0007B5E3
+:107790002484000C27BDFFE83C098000AFB0001036
+:1077A000AFBF00143526098090C8000924020006E6
+:1077B00000A05821310300FF3527090000808021F7
+:1077C000240500041062007B2408000294CF005CB2
+:1077D0003C0E020431EDFFFF01AE6025AE0C00004F
+:1077E00090CA00083144002010800008000000000A
+:1077F00090C2004E3C1F010337F90300305800FFD0
+:107800000319302524050008AE06000490F9001184
+:1078100090E6001290E40011333800FF00187082E7
+:1078200030CF00FF01CF5021014B6821308900FF8C
+:1078300031AAFFFF39230028000A60801460002C61
+:10784000020C482390E400123C198000372F0100FD
+:10785000308C00FF018B1821000310800045F821B7
+:10786000001F8400360706FFAD270004373F0900DC
+:1078700093EC001193EE0012372609800005C082B8
+:107880008DE4000C8CC5003431CD00FF01AB10211C
+:107890000058182100A4F8230008840000033F00CA
+:1078A00000F0302533F9FFFF318F00FC00D970253F
+:1078B0000158202101E9682100045080ADAE000C80
+:1078C0000E00007C012A80213C088008240B000463
+:1078D000350500800E00007EA0AB000902001021DB
+:1078E0008FBF00148FB0001003E0000827BD001800
+:1078F00090EC001190E300193C18080097183FCE57
+:10790000318200FF0002F882307000FF001FCE00BD
+:1079100000103C000327302500D870253C0F4000A4
+:1079200001CF68253C198000AD2D0000373F0900CC
+:1079300093EC001193EE0012372F010037260980D7
+:107940000005C0828DE4000C8CC5003431CD00FFF1
+:1079500001AB10210058182100A4F823000884006E
+:1079600000033F0000F0302533F9FFFF318F00FCAA
+:1079700000D970250158202101E9682100045080B8
+:10798000ADAE000C0E00007C012A80213C0880086E
+:10799000240B0004350500800E00007EA0AB00091A
+:1079A000020010218FBF00148FB0001003E0000808
+:1079B00027BD00180A0007C72408001227BDFFD002
+:1079C0003C038000AFB60028AFB50024AFB4002060
+:1079D000AFB10014AFBF002CAFB3001CAFB20018A2
+:1079E000AFB000103467010090E6000B309400FF48
+:1079F00030B500FF30C200300000B02110400099C7
+:107A000000008821346409809088000800082E0056
+:107A100000051E03046000C0240400048F86005487
+:107A20003C010800A0243FD83C0C8000AD800048F9
+:107A30003C048000348E010091CD000B31A5002064
+:107A400010A000073C078000349309809272000860
+:107A50000012860000107E0305E000C43C1F800871
+:107A600034EC0100918A000B34EB09809169000825
+:107A7000314400400004402B3123000800C8982303
+:107A80001460000224120003000090213C108000CA
+:107A900036180A8036040900970E002C90830011D6
+:107AA0009089001293050018307F00FF312800FFF5
+:107AB000024810210002C880930D0018033F78216E
+:107AC00001F1302130B100FF00D11821A78E0058FC
+:107AD0003C010800A4263FCE3C010800A4233FD06F
+:107AE00015A00002000000000000000D920B010B29
+:107AF0003065FFFF3C010800A4233FD2316A0040FB
+:107B00003C010800A4203FC83C010800A4203FC459
+:107B10001140000224A4000A24A4000B3091FFFFAE
+:107B20000E0001E7022020219206010B3C0C080008
+:107B3000958C3FD2004020210006698231A70001C8
+:107B40000E00060101872821004020210260282123
+:107B50000E00060C024030210E0007A1004020213B
+:107B600016C00069004020219212010B32560040DD
+:107B700012C000053C0500FF8C93000034AEFFFFEF
+:107B8000026E8024AC9000000E0001FB0220202138
+:107B90003C0F080091EF3FD831F10003122000168E
+:107BA0003C1380088F8200543C09800835280080EF
+:107BB000245F0001AD1F003C3C0580088CB9000427
+:107BC00003E02021033FC0231B000002AF9F0054AD
+:107BD0008CA400040E0006F8ACA400043C0780004E
+:107BE0008CEB00743C04800834830080004B5021EF
+:107BF000AC6A000C3C1380083670008002802021A3
+:107C000002A02821A200006B0E00075D3C1480003A
+:107C10008F920054368C0140AD92000C8F86004844
+:107C20003C151000344D000624D60001AF960048E4
+:107C30008FBF002CA18600128FB60028AD8D0014D6
+:107C40008FB3001CAE9501788FB200188FB5002459
+:107C50008FB400208FB100148FB0001003E0000833
+:107C600027BD003034640980908F0008000F760033
+:107C7000000E6E0305A00033347F090093F8001B4B
+:107C8000241900103C010800A0393FD8331300022A
+:107C90001260FF678F8600548F8200601446FF6574
+:107CA0003C0480000E00007C000000003C048008C2
+:107CB0003485008090A8000924060016310300FFD7
+:107CC0001066000D0000000090AB00093C070800A2
+:107CD00090E73FD824090008316400FF34EA00012E
+:107CE0003C010800A02A3FD81089002F240C000A6C
+:107CF000108C00282402000C0E00007E0000000002
+:107D00000A0008608F8600540E0007B9024028213F
+:107D10000A0008AE004020213C0B8008356A008034
+:107D20008D4600548CE9000C1120FF3DAF860054B5
+:107D3000240700143C010800A0273FD80A00085F70
+:107D40003C0C800090910008241200023C010800C5
+:107D5000A0323FD8323000201200000B2416000160
+:107D60008F8600540A0008602411000837F800804C
+:107D70008F020038AFE200048FF90004AF19003C15
+:107D80000A00086C3C0780008F8600540A000860D7
+:107D900024110004A0A200090E00007E00000000D3
+:107DA0000A0008608F860054240200140A00093A71
+:107DB000A0A2000927BDFFE8AFB000103C10800072
+:107DC000AFBF001436020100904400090E00075DA9
+:107DD000240500013C0480089099000E3483008043
+:107DE000909F000F906F00269089000A33F800FFE3
+:107DF00000196E000018740031EC00FF01AE502530
+:107E0000000C5A00014B3825312800FF3603014091
+:107E10003445600000E830252402FF813C04100056
+:107E2000AC66000C8FBF0014AC650014A062001299
+:107E3000AE0401788FB0001003E0000827BD0018E1
+:107E400027BDFFE8308400FFAFBF00100E00075DC4
+:107E500030A500FF3C05800034A4014034470040B9
+:107E60002406FF92AC870014A08600128F83005472
+:107E70008FBF00103C02100027BD0018AC83000C1F
+:107E800003E00008ACA2017827BDFFD8AFB0001016
+:107E9000308400FF30B000FF3C058000AFB100141B
+:107EA000AFBF0020AFB3001CAFB20018000410C277
+:107EB00034A60100320300023051000114600007B3
+:107EC00090D200093C098008353300809268000593
+:107ED0003107000810E0000C308A00100240202119
+:107EE0000E00078302202821240200018FBF0020FA
+:107EF0008FB3001C8FB200188FB100148FB0001028
+:107F000003E0000827BD00281540003434A50A000E
+:107F10008CB800248CAF0008130F004B00003821F0
+:107F20003C0D800835B30080926C00682406000286
+:107F3000318B00FF116600843C06800034C20100D2
+:107F40009263004C90590009307F00FF53F9000400
+:107F50003213007C10E00069000000003213007C46
+:107F60005660005C0240202116200009320D0001FD
+:107F70003C0C800035840100358B0A008D6500249F
+:107F80008C86000414A6FFD900001021320D0001D8
+:107F900011A0000E024020213C1880003710010083
+:107FA0008E0F000C8F8E005011EE000800000000B4
+:107FB0000E000843022028218E19000C3C1F800867
+:107FC00037F00080AE190050024020210E000771EA
+:107FD000022028210A00098F240200013C05080024
+:107FE0008CA5006424A400013C010800AC240064BA
+:107FF0001600000D00000000022028210E0007716D
+:1080000002402021926E0068240C000231CD00FF56
+:1080100011AC0022024020210E00094100000000A6
+:108020000A00098F240200010E00007024040001E0
+:10803000926B0025020B30250E00007EA266002503
+:108040000A0009D3022028218E6200188CDF000468
+:108050008CB9002400021E0217F9FFB13065007FC1
+:108060009268004C264400013093007F1265004066
+:10807000310300FF1464FFAB3C0D8008264700016C
+:1080800030F1007F30E200FF1225000B24070001D1
+:10809000004090210A00099C2411000124050004DD
+:1080A0000E000732240600010E0009410000000006
+:1080B0000A00098F240200012405FF8002452024C4
+:1080C00000859026324200FF004090210A00099C62
+:1080D000241100010E00084302202821320700303D
+:1080E00010E0FFA132100082024020210E00078321
+:1080F000022028210A00098F240200018E6900183D
+:108100000240202102202821012640250E0009647A
+:10811000AE6800189264004C240500032406000198
+:108120000E000732308400FF0E00007024040001AE
+:1081300092710025021150250E00007EA26A0025D2
+:108140000A00098F240200018E6F00183C1880007D
+:108150000240202101F87025022028210E0007711D
+:10816000AE6E00189264004C0A000A1B240500043D
+:10817000324A0080394900801469FF6A3C0D80084A
+:108180000A0009F42647000127BDFFC0AFB0001860
+:108190003C108000AFBF0038AFB70034AFB600303E
+:1081A000AFB5002CAFB40028AFB30024AFB20020AD
+:1081B0000E0005BEAFB1001C360201009045000B59
+:1081C0000E00097690440008144000E78FBF003885
+:1081D0003C08800835070080A0E0006B3606098067
+:1081E00090C50000240300503C17080026F73F907C
+:1081F00030A400FF3C13080026733FA01083000347
+:108200003C1080000000B82100009821241F0010BD
+:108210003611010036120A00361509808E580024E6
+:108220008E3400048EAF00208F8C00543C01080077
+:10823000A03F3FD836190A80972B002C8EF60000FD
+:10824000932A00180298702301EC68233C0108006F
+:10825000AC2E3FB43C010800AC2D3FB83C010800F7
+:10826000AC2C3FDCA78B005802C0F809315400FF4A
+:1082700030490002152000E930420001504000C49E
+:108280009227000992A90008312800081500000271
+:10829000241500030000A8213C0A80003543090092
+:1082A00035440A008C8D00249072001190700012E9
+:1082B000907F0011325900FF321100FF02B11021EE
+:1082C0000002C08033EF00FF0319B021028F70213C
+:1082D00002D4602125CB00103C010800A4363FCE1B
+:1082E0003C010800AC2D3FE03C010800A42C3FD02D
+:1082F0003C010800A42B3FCC3556010035540980C1
+:1083000035510E008F8700548F89005C8E850020C8
+:1083100024080006012730233C010800AC283FD484
+:1083200000A7282304C000B50000902104A000B3DA
+:1083300000C5502B114000B5000000003C010800B2
+:10834000AC263FB88E6200000040F8090000000033
+:108350003046000214C0007400408021304B000100
+:10836000556000118E6200043C0D08008DAD3FBCCD
+:108370003C0EC0003C04800001AE6025AE2C000025
+:108380008C980000330F000811E0FFFD0000000092
+:10839000963F000824120001A79F00408E39000478
+:1083A000AF9900388E6200040040F8090000000018
+:1083B0000202802532030002146000B300000000B6
+:1083C0003C09080095293FC43C06080094C63FD0EC
+:1083D0003C0A0800954A3FC63C0708008CE73FBCB2
+:1083E000012670213C0308008C633FE03C08080034
+:1083F00095083FDA01CA20218ED9000C00E9282116
+:10840000249F000200A878210067C02133E4FFFF09
+:10841000AF9900503C010800AC383FE03C01080037
+:10842000A42F3FC83C010800A42E3FD20E0001E754
+:10843000000000008F8D0048004020213C01080012
+:10844000A02D3FD98E62000825AC0001AF8C0048FA
+:108450000040F809000000008F85005402A0302180
+:108460000E00060C004020210E0007A10040202134
+:108470008E6B000C0160F809004020213C0A0800C6
+:10848000954A3FD23C06080094C63FC601464821A3
+:10849000252800020E0001FB3104FFFF3C05080007
+:1084A0008CA53FB43C0708008CE73FBC00A7202305
+:1084B0003C010800AC243FB414800006000000001A
+:1084C0003C0208008C423FD4344B00403C01080081
+:1084D000AC2B3FD4124000438F8E00448E2D0010F1
+:1084E0008F920044AE4D00208E2C0018AE4C00241C
+:1084F0003C04080094843FC80E0006FA0000000007
+:108500008F9F00548E6700103C010800AC3F3FDC99
+:1085100000E0F809000000003C1908008F393FB462
+:108520001720FF798F870054979300583C11800ED5
+:10853000321601000E000729A633002C16C0004594
+:10854000320300105460004C8EE5000432080040F5
+:108550005500001D8EF000088EE4000C0080F80924
+:10856000000000008FBF00388FB700348FB6003096
+:108570008FB5002C8FB400288FB300248FB2002059
+:108580008FB1001C8FB0001803E0000827BD004029
+:108590008F86003C36110E0000072E0000A6202515
+:1085A000AE0400808E4300208E500024AFA3001044
+:1085B000AE2300148FB20010AE320010AE30001C9B
+:1085C0000A000A75AE3000180200F8090000000029
+:1085D0008EE4000C0080F809000000000A000B2E59
+:1085E0008FBF003824180001240F0001A5C000200F
+:1085F000A5D800220A000B10ADCF00243C010800D2
+:10860000AC203FB80A000AA68E6200003C010800B8
+:10861000AC253FB80A000AA68E6200009224000929
+:108620000E000771000028218FBF00388FB700347B
+:108630008FB600308FB5002C8FB400288FB3002484
+:108640008FB200208FB1001C8FB0001803E000082B
+:1086500027BD00403C1480009295010900002821AC
+:108660000E00084332A400FF320300105060FFB830
+:10867000320800408EE5000400A0F8090000000068
+:108680000A000B28320800405240FFA89793005878
+:108690008E3400148F930044AE7400208E35001C7D
+:1086A000AE7500240A000B1F979300588F820014A8
+:1086B0000004218003E00008008210213C078008AC
+:1086C00034E200809043006900804021106000097E
+:1086D0003C0401003C0708008CE73FDC8F8300303E
+:1086E00000E32023048000089389001C14E30003A6
+:1086F0000100202103E00008008010213C0401005B
+:1087000003E00008008010211120000B00673823CF
+:108710003C0D800035AC0980918B007C316A0002F1
+:10872000114000202409003400E9702B15C0FFF12E
+:108730000100202100E938232403FFFC00A3C82402
+:1087400000E3C02400F9782B15E0FFEA030820219C
+:1087500030C400030004102314C000143049000387
+:108760000000302100A9782101E6702100EE682B7D
+:1087700011A0FFE03C0401002D3800010006C82BC9
+:10878000010548210319382414E0FFDA2524FFFCF1
+:108790002402FFFC00A218240068202103E0000846
+:1087A000008010210A000B9E240900303C0C800040
+:1087B0003586098090CB007C316A00041540FFE9C2
+:1087C000240600040A000BAD000030213C03080021
+:1087D0008C63005C8F82001827BDFFE0AFBF0018DC
+:1087E000AFB1001410620005AFB00010000329C043
+:1087F00024A40280AF840014AF8300183C108000D2
+:1088000036020A0094450032361101000E000B7F3B
+:1088100030A43FFF8E240000241FFF803C11008005
+:108820000082C021031F60243309007F000CC9406F
+:1088300003294025330E0078362F00033C0D10002D
+:10884000010D502501CF5825AE0C002836080980AF
+:10885000AE0C080CAE0B082CAE0A08309103006970
+:108860003C06800C0126382110600006AF870034DA
+:108870008D09003C8D03006C0123382318E0008231
+:10888000000000003C0B8008356A00803C1080002E
+:10889000A1400069360609808CC200383C06800081
+:1088A00034C50A0090A8003C310C00201180001A49
+:1088B000AF820030240D00013C0E800035D10A004B
+:1088C000A38D001CAF8000248E2400248F850024FB
+:1088D000240D0008AF800020AF8000283C01080074
+:1088E000A42D3FC63C010800A4203FDA0E000B83F4
+:1088F000000030219228003C8FBF00188FB1001477
+:108900008FB0001000086142AF82002C27BD00200C
+:1089100003E000083182000190B80032240E00010B
+:10892000330F00FF000F2182108E00412419000236
+:108930001099006434C40AC03C03800034640A0007
+:108940008C8F002415E0001E34660900909F0030D3
+:108950002418000533F9003F1338004E24030001AA
+:108960008F860020A383001CAF860028AF860024DA
+:108970003C0E800035D10A008E2400248F8500240F
+:10898000240D00083C010800A42D3FC63C0108004E
+:10899000A4203FDA0E000B83000000009228003C68
+:1089A0008FBF00188FB100148FB000100008614213
+:1089B000AF82002C27BD002003E0000831820001B7
+:1089C0008C8A00088C8B00248CD000643C0E8000C4
+:1089D00035D10A00014B2823AF900024A380001C4E
+:1089E000AF8500288E2400248F8600208F850024E8
+:1089F000240D00083C010800A42D3FC63C010800DE
+:108A0000A4203FDA0E000B83000000009228003CF7
+:108A10008FBF00188FB100148FB0001000086142A2
+:108A2000AF82002C27BD002003E000083182000146
+:108A300090A200303051003F5224002834C50AC0B3
+:108A40008CB000241600002234CB09008CA600480C
+:108A50003C0A7FFF3545FFFF00C510243C0E800017
+:108A6000AF82002035C509008F8800208CAD0060E2
+:108A7000010D602B15800002010020218CA40060F4
+:108A80000A000C22AF8400208D02006C0A000BFC4F
+:108A90003C0680008C8200488F8600203C097FFFC6
+:108AA0003527FFFF004788243C0480082403000189
+:108AB000AF910028AC80006CA383001C0A000C302E
+:108AC000AF8600248C9F00140A000C22AF9F002068
+:108AD0008D6200680A000C6C3C0E800034C4098072
+:108AE0008C8900708CA300140123382B10E0000443
+:108AF000000000008C8200700A000C6C3C0E8000AC
+:108B00008CA200140A000C6C3C0E80008F8500249F
+:108B100027BDFFE0AFBF0018AFB1001414A00008DC
+:108B2000AFB000103C04800034870A0090E60030AB
+:108B30002402000530C3003F106200B934840900EC
+:108B40008F91002000A080213C048000348E0A0018
+:108B50008DCD00043C0608008CC63FB831A73FFF0E
+:108B600000E6602B5580000100E03021938F001C4F
+:108B700011E0007800D0282B349F098093F9007C05
+:108B800033380002130000792403003400C3102B93
+:108B9000144000D90000000000C3302300D0282B6F
+:108BA0003C010800A4233FC414A0006E0200182159
+:108BB0003C0408008C843FB40064402B5500000145
+:108BC000006020213C05800034A90A00912A003C65
+:108BD0003C010800AC243FBC31430020146000037A
+:108BE0000000482134AB0E008D6900188F88002CDE
+:108BF0000128202B1080005F000000003C050800C9
+:108C00008CA53FBC00A96821010D602B1180005C80
+:108C100000B0702B0109382300E028213C01080036
+:108C2000AC273FBC12000003240AFFFC10B0008DEB
+:108C30003224000300AA18243C010800A4203FDAD3
+:108C40003C010800AC233FBC006028218F84002435
+:108C5000120400063C0B80088D6C006C0200202181
+:108C6000AF91002025900001AD70006C8F8D002821
+:108C700000858823AF91002401A52023AF8400281C
+:108C80001220000224070018240700103C18800856
+:108C90003706008090CF00683C010800A0273FD82D
+:108CA0002407000131EE00FF11C70047000000005B
+:108CB00014800018000028213C06800034D109806F
+:108CC00034CD010091A600098E2C001824C40001A7
+:108CD000000C86023205007F308B007F1165007F1B
+:108CE0002407FF803C19800837290080A124004C0C
+:108CF0003C0808008D083FD4241800023C010800FD
+:108D0000A0384019350F00083C010800AC2F3FD4B3
+:108D1000240500103C02800034440A009083003C8B
+:108D2000307F002013E0000500A02021240A00016C
+:108D30003C010800AC2A3FBC34A400018FBF0018DE
+:108D40008FB100148FB000100080102103E00008E4
+:108D500027BD00203C010800A4203FC410A0FF94C0
+:108D6000020018210A000CC000C018210A000CB72C
+:108D7000240300303C0508008CA53FBC00B0702BDC
+:108D800011C0FFA8000000003C19080097393FC43B
+:108D90000325C0210307782B11E000072CAA00044B
+:108DA0003C0360008C625404305F003F17E0FFE337
+:108DB000240400422CAA00041140FF9A240400421B
+:108DC0000A000D248FBF00181528FFB9000000000D
+:108DD0008CCA00183C1F800024020002015F182585
+:108DE000ACC3001837F90A00A0C200689329003C00
+:108DF0002404000400A01021312800203C010800B8
+:108E0000A0244019110000022405001024020001D2
+:108E10003C010800AC223FB40A000D1A3C0280005D
+:108E20008F8800288C8900600109282B14A000027B
+:108E3000010088218C9100603C048000348B0E007E
+:108E40008D640018240A000102202821022030210C
+:108E5000A38A001C0E000B83022080210A000CA6AE
+:108E6000AF82002C00045823122000073164000355
+:108E70003C0E800035C7098090ED007C31AC0004C9
+:108E800015800019248F00043C010800A4243FDA57
+:108E90003C1F080097FF3FDA03E5C82100D9C02B2B
+:108EA0001300FF6B8F8400242CA6000514C0FFA3C1
+:108EB0002404004230A200031440000200A2182340
+:108EC00024A3FFFC3C010800AC233FBC3C0108008C
+:108ED000A4203FDA0A000CE70060282100C77024B4
+:108EE0000A000D0D01C720263C010800A42F3FDA1F
+:108EF0000A000D78000000003C010800AC203FBCD7
+:108F00000A000D23240400428F8300283C058000C2
+:108F100034AA0A00146000060000102191470030B6
+:108F20002406000530E400FF108600030000000066
+:108F300003E0000800000000914B0048316900FF89
+:108F4000000941C21500FFFA3C0680083C040800F5
+:108F500094843FC43C0308008C633FDC3C19080048
+:108F60008F393FBC3C0F080095EF3FDA0064C02109
+:108F70008CCD00040319702101CF602134AB0E00A9
+:108F8000018D282318A0001D00000000914F004C07
+:108F90008F8C0034956D001031EE00FF8D89000438
+:108FA00001AE30238D8A000030CEFFFF000E290075
+:108FB0000125C82100003821014720210325182B55
+:108FC0000083C021AD990004AD980000918F000A84
+:108FD00001CF6821A18D000A956500128F8A0034A7
+:108FE000A5450008954B003825690001A5490038C2
+:108FF0009148000D35070008A147000D03E0000867
+:109000000000000027BDFFD8AFB000189388001CF7
+:109010008FB000143C0A80003C197FFF8F8700242A
+:109020003738FFFFAFBF0020AFB1001C355F0A002B
+:109030000218182493EB003C00087FC03C02BFFFDD
+:10904000006F60252CF000013449FFFF3C1F080031
+:109050008FFF3FDC8F9900303C18080097183FD2F3
+:1090600001897824001047803C07EFFF3C05F0FFA2
+:1090700001E818253C1180003169002034E2FFFF2F
+:1090800034ADFFFF362E098027A50010240600020C
+:1090900003F96023270B0002354A0E0000621824F2
+:1090A0000080802115200002000040218D48001C16
+:1090B000A7AB0012058000392407000030E800FF4C
+:1090C00000083F00006758253C028008AFAB001441
+:1090D000344F008091EA00683C08080091083FD9AD
+:1090E0003C09DFFF352CFFFF000AF82B3C0208008B
+:1090F00094423FCCA3A80011016CC024001FCF40B4
+:10910000031918258FA70010AFA300143C0C08000A
+:10911000918C3FDBA7A200168FAB001400ED482412
+:109120003C0F01003C0A0FFF012FC82531980003B6
+:10913000355FFFFF016D40243C027000033F38247F
+:1091400000181E0000E2482501037825AFAF001487
+:10915000AFA9001091CC007C0E000092A3AC0015CA
+:10916000362D0A0091A6003C30C400201080000675
+:10917000260200083C11080096313FC8262EFFFF4A
+:109180003C010800A42E3FC88FBF00208FB1001CF7
+:109190008FB0001803E0000827BD00288F8B002C3B
+:1091A000010B502B5540FFC5240700010A000E0497
+:1091B00030E800FF9383001C3C02800027BDFFD8ED
+:1091C00034480A0000805021AFBF002034460AC056
+:1091D000010028211060000E3444098091070030FE
+:1091E000240B00058F89002030EC003F118B000B11
+:1091F00000003821AFA900103C0B80088D69006C7D
+:10920000AFAA00180E00015AAFA90014A380001CD9
+:109210008FBF002003E0000827BD00288D1F0048F5
+:109220003C1808008F183FBC8F9900283C027FFF34
+:109230008D0800443443FFFFAFA900103C0B8008A9
+:109240008D69006C03E370240319782101CF682332
+:1092500001A83821AFAA00180E00015AAFA90014C6
+:109260000A000E58A380001C3C05800034A60A00AA
+:1092700090C7003C3C06080094C63FDA3C02080058
+:109280008C423FD430E30020000624001060001E12
+:10929000004438253C0880083505008090A300680C
+:1092A00000004821240800010000282124040001B6
+:1092B0003C0680008CCD017805A0FFFE34CF014034
+:1092C000ADE800083C0208008C423FDCA5E5000444
+:1092D000A5E40006ADE2000C3C04080090843FD9F0
+:1092E0003C03800834790080A1E40012ADE700144B
+:1092F000A5E900189338004C3C0E1000A1F8002D91
+:1093000003E00008ACCE017834A90E008D28001CC3
+:109310003C0C08008D8C3FBC952B0016952A001440
+:10932000018648213164FFFF0A000E803145FFFFAE
+:109330003C04800034830A009065003C30A2002089
+:109340001040001934870E00000040210000382131
+:10935000000020213C0680008CC901780520FFFE1A
+:1093600034CA014034CF010091EB0009AD48000838
+:109370003C0E08008DCE3FDC240DFF91240C0040F4
+:109380003C081000A5440004A5470006AD4E000CA3
+:10939000A14D0012AD4C0014A5400018A14B002DAA
+:1093A00003E00008ACC801788CE8001894E60012CD
+:1093B00094E4001030C7FFFF0A000EA93084FFFFBD
+:1093C0003C04800034830A009065003C30A20020F9
+:1093D0001040002727BDFFF82409000100003821B4
+:1093E000240800013C0680008CCA01780540FFFE7D
+:1093F0003C0280FF34C40100908D00093C0C080041
+:10940000918C4019A3AD00038FAB00003185007F24
+:109410003459FFFF01665025AFAA00009083000A6F
+:10942000A3A0000200057E00A3A300018FB80000E6
+:1094300034CB0140240C30000319702401CF68257F
+:10944000AD6D000C27BD0008AD6C0014A5600018C0
+:10945000AD690008A56700042409FF80A56800061F
+:109460003C081000A169001203E00008ACC80178B4
+:1094700034870E008CE9001894E6001294E4001082
+:1094800030C8FFFF0A000ECD3087FFFF27BDFFE089
+:10949000AFB100143C118000AFB00010AFBF001896
+:1094A00036380A00970F0032363001000E000B7F6D
+:1094B00031E43FFF8E0E0000240DFF803C042000AD
+:1094C00001C25821016D6024000C4940316A007FBF
+:1094D000012A4025010438253C048008AE270830C5
+:1094E0003486008090C500682403000230A200FF8B
+:1094F000104300048F9F00208F990024AC9F0068C8
+:10950000AC9900648FBF00188FB100148FB00010A9
+:1095100003E0000827BD00203C0A0800254A3A80E5
+:109520003C09080025293B103C08080025082F1C91
+:109530003C07080024E73BDC3C06080024C639044D
+:109540003C05080024A536583C0408002484325CFD
+:109550003C030800246339B83C0208002442375415
+:109560003C010800AC2A3F983C010800AC293F941C
+:109570003C010800AC283F903C010800AC273F9C10
+:109580003C010800AC263FAC3C010800AC253FA4E0
+:109590003C010800AC243FA03C010800AC233FB0D4
+:1095A0003C010800AC223FA803E0000800000000D6
+:1095B00080000940800009008008010080080080C8
+:1095C00080080000800E00008008008080080000F5
+:1095D00080000A8080000A00800009808000090065
+:00000001FF
--- linux-4.4.0.orig/firmware/bnx2/bnx2-rv2p-09-6.0.17.fw.ihex
+++ linux-4.4.0/firmware/bnx2/bnx2-rv2p-09-6.0.17.fw.ihex
@@ -3,8 +3,7 @@
 :1000200000000000000000000000000000000000D0
 :1000300000000E88000009500000000500000000CC
 :1000400000000000000000000000000000000000B0
-:080050000000000000000000A8
-:0800580000000010B180000659
+:10005000000000000000000000000010B180000659
 :100060000000001F05060011000000080500FFFF4A
 :10007000000000180002000000000008050000FF5A
 :10008000000000180002000000000008AC000001A1
@@ -382,11 +381,3 @@
 :1017C0000000000C2980000000000010001F000035
 :0817D000000000188000FE3546
 :00000001FF
-/*
- * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
- *
- * Permission is hereby granted for the distribution of this firmware data
- * in hexadecimal or equivalent format, provided this copyright notice is
- * accompanying it.
- */
--- linux-4.4.0.orig/firmware/bnx2/bnx2-rv2p-09ax-6.0.17.fw.ihex
+++ linux-4.4.0/firmware/bnx2/bnx2-rv2p-09ax-6.0.17.fw.ihex
@@ -3,8 +3,7 @@
 :1000200000000000000000000000000000000000D0
 :1000300000001010000009C80000000500000000CA
 :1000400000000000000000000000000000000000B0
-:080050000000000000000000A8
-:0800580000000010B180000659
+:10005000000000000000000000000010B180000659
 :100060000000001F03060011000000080500FFFF4C
 :10007000000000180002000000000008050000FF5A
 :10008000000000180002000000000008AC000001A1
@@ -155,8 +154,7 @@
 :100990000000001091D40000000000080500005580
 :1009A000000000188000FF360000000C29800001C4
 :1009B0000000000C1F800001000000082A00000752
-:0809C000000000188000FEDEBB
-:0809C80000000010B1800004E2
+:1009C000000000188000FEDE00000010B18000046E
 :1009D0000000001F0306001100000008050000FFD2
 :1009E0000000001800020000000000002A000000C3
 :1009F00000000010B1D400000000001091DE0000E3
@@ -415,11 +413,3 @@
 :1019C00000000010001F00000000000C6BD7000199
 :0819D000000000188000FE0475
 :00000001FF
-/*
- * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
- *
- * Permission is hereby granted for the distribution of this firmware data
- * in hexadecimal or equivalent format, provided this copyright notice is
- * accompanying it.
- */
--- linux-4.4.0.orig/firmware/bnx2x/bnx2x-e1-7.12.30.0.fw.ihex
+++ linux-4.4.0/firmware/bnx2x/bnx2x-e1-7.12.30.0.fw.ihex
@@ -0,0 +1,10640 @@
+:100000000000165800000068000005D8000016C85F
+:10001000000031D400001CA80000006C00004E80DD
+:10002000000076EC00004EF00000009C0000C5E0EF
+:100030000000C9800000C680000000880001900810
+:1000400000003C1800019098000000880001CCB826
+:100050000000B9680001CD480000120C000286B80B
+:1000600000000004000298C8020600DC0000000145
+:100070000306100002000000010600D80000000086
+:100080000306020000030200020600DC000000007C
+:1000900002060068000000B80206007800000114A3
+:1000A000010600B800000000010600C800000000C2
+:1000B0000206006C000000B80206007C000001147B
+:1000C000010600BC00000000010600CC000000009A
+:1000D000020D004400000032030D004C0004020336
+:1000E000040D005C00000004030D008C00110207E9
+:1000F000020D015C00000001030D01640002021802
+:10010000020D020400000001030D020C0003021A9C
+:10011000030D02200002021D040D028000000012E7
+:10012000030D03000018021F040D03600000000C03
+:10013000040D400000000A00030D0004000F023708
+:10014000020D01140000000D020D01180000002D29
+:100150000310100000030246021010100000026499
+:10016000071011000010024908101140000000089B
+:100170000710116000100259081011A000000018AB
+:1001800007101800020002690210101000000000A1
+:1001900004104C0000000100021040280000001074
+:1001A000031040400002046902104058002800007B
+:1001B000021040840084924A02104058000000005F
+:1001C000030C20080003046B030C201C0004046EC5
+:1001D000030C203800110472040C207C0000004F36
+:1001E000030C21B800110483040C21FC0000000F53
+:1001F000030C223800040494010C22480000000083
+:10020000010C224C00000000010C225000000000F4
+:10021000010C225400000000010C225800000000D4
+:10022000010C225C00000000010C226000000000B4
+:10023000010C226400000000010C22680000000094
+:10024000010C226C00000000010C22700000000074
+:10025000010C227400000000010C22780000000054
+:10026000010C227C00000000020C24BC00000001F4
+:100270000A00000100000001020C2000000003E859
+:100280000A00000100000002020C20000000000A29
+:100290000A00000100000004020C20000000000120
+:1002A0000520040000860000062007800010049846
+:1002B000042200000000160004228000000000401C
+:1002C00004223BD000000008042248000000000681
+:1002D000032248180004049A042248280000000C55
+:1002E000032248580004049E042248680000000CC1
+:1002F00003224898000404A2042248A80000000C2D
+:10030000032248D8000404A6042248E80000000C98
+:1003100003224918000404AA042249280000000C02
+:1003200003224958000404AE042249680000000C6E
+:1003300003224998000404B2042249A80000000CDA
+:10034000032249D8000404B6042249E80000000C46
+:1003500003224A18000404BA04224A280000000CB0
+:1003600003224A58000404BE04224A680000000C1C
+:1003700003224A98000404C204224AA80000000C88
+:1003800003224AD8000404C604224AE80000000CF4
+:1003900003224B18000404CA04224B280000000C5E
+:1003A00003224B58000404CE04224B680000000CCA
+:1003B00003224B98000404D204224BA80000000C36
+:1003C00003224BD8000404D604224BE80000000CA2
+:1003D00003224C18000404DA04224C280000000C0C
+:1003E00003224C58000404DE04224C680000000C78
+:1003F00003224C98000404E204224CA80000000CE4
+:1004000003224CD8000404E604224CE80000000C4F
+:1004100003224D18000404EA04224D280000000CB9
+:1004200003224D58000404EE04224D680000000C25
+:1004300003224D98000404F204224DA80000000C91
+:1004400003224DD8000404F604224DE80000000CFD
+:1004500003224E18000404FA04224E280000000C67
+:1004600003224E58000404FE04224E680000000CD3
+:1004700003224E980004050204224EA80000000C3E
+:1004800003224ED80004050604224EE80000000CAA
+:1004900003224F180004050A04224F280000000C14
+:1004A00003224F580004050E04224F680000000C80
+:1004B00003224F980004051204224FA80000000CEC
+:1004C00003224FD80004051604224FE8000000065E
+:1004D000032251980004051A022380000000001036
+:1004E00002238040000000120223808000000030C0
+:1004F000022380C00000000E022383800007A12099
+:10050000022383C0000001F402238BC0000000011D
+:100510000A00000200000001022383000007A1205E
+:1005200002238340000001F40A00000200000002E0
+:10053000022383000000138802238340000000058B
+:100540000A000002000000040223830000000138BA
+:1005500002238340000000000524000036A30000B1
+:100560000524800005710DA9062489C06D2E051E85
+:100570000120000000000000012000040000000035
+:1005800001200008000000000120000C0000000015
+:1005900001200010000000000120001400000000F5
+:1005A00003200020001A0520032000A40002053AC1
+:1005B000022002240000000002200234000000009B
+:1005C0000220024C00000000022002E40000FFFFB5
+:1005D000082020000000080004221400000000028F
+:1005E00004221490000000300422390000000010A2
+:1005F0000422510800000002042251A80000000655
+:1006000004221408000000020422155000000030EB
+:1006100004223940000000100422511000000002A2
+:10062000042251C00000000604102400000000E075
+:100630000310201C0002053C021020C00000000135
+:10064000031020040002053E02170008000000020B
+:100650000217002C000000030317003800020540B9
+:100660000317004400060542031700600005054813
+:10067000031700780002054D021700040000000F68
+:100680000410806800000004021080000000108048
+:1006900004108040000000020410802800000002C6
+:1006A0000210803800000010031080400002054F47
+:1006B00002108050000000000210810000000000C5
+:1006C000041081200000000202108008000002B522
+:1006D0000210801000000000021081080001FFFFDE
+:1006E000041082000000004A041081400000000253
+:1006F0000210800000001A80041090000000002406
+:10070000041091200000004A041093700000004A79
+:10071000041095C00000004A021080040000108000
+:100720000410804800000002041080300000000225
+:100730000210803C000000100310804800020551A8
+:10074000021080540000000002108104000000002C
+:1007500004108128000000020210800C000002B585
+:1007600002108014000000000210810C0001FFFF45
+:10077000041084000000004A0410814800000002B8
+:100780000210800400001A800410909000000024E1
+:10079000041092480000004A041094980000004A97
+:1007A000041096E80000004A0200A468000AFFDC7A
+:1007B0000200A280000000010300A294000405537F
+:1007C0000200A4FCFF000000030100B40002055772
+:1007D000020100DC000000010301010000020559D4
+:1007E0000201007C003000000201008400000028AB
+:1007F0000201008C00000000020101300000000432
+:10080000040101380000001102010328000000006B
+:100810000201055400000030020100C40000000184
+:10082000020100CC00000001020100F800000001FC
+:10083000020100F000000001020100800030000011
+:100840000201008800000028020100900000000062
+:1008500002010134000000040401017C00000011C9
+:100860000201032C000000000201056400000030BA
+:10087000020100C800000001020100D000000001D8
+:10088000020100FC00000001020100F40000000170
+:1008900002140000000000010214000C000000011E
+:1008A000031400400002055B0214000C000000006D
+:1008B00002140000000000000214006C00000000A0
+:1008C00002140004000000010214003000000001C6
+:1008D00002140004000000000214005C000000008C
+:1008E000021400080000000102140034000000019E
+:1008F0000214000800000000021400600000000064
+:10090000030400040012055D030400540003056F96
+:100910000204007000000004030400780004057263
+:1009200004040088000000050304009C0003057611
+:10093000040400A800000004030400B800050579C1
+:10094000040400CC00000004030400DC0004057E65
+:10095000040400EC00000004010401240000000075
+:1009600001040128000000000104012C0000000027
+:100970000104013000000000020401340000000FF7
+:1009800003120490002205820212052000000002DA
+:1009900002120388000000640212039000000008A5
+:1009A0000312039C000305A4021203BC0000000410
+:1009B000021203C400000004021203D00000000071
+:1009C000021203DC000000000212036C00000001B0
+:1009D000021203680000003F031201BC003C05A79F
+:1009E000031202B0000205E303120324000205E52E
+:1009F000021201B00000000107103800000505E7F1
+:100A000007103C00000505EC07103C20000505F12F
+:100A100003168030000805F602168054000000021C
+:100A200003168060000505FE0416807400000007B0
+:100A300003168090000206030316809C000506053D
+:100A4000041680B000000007031680CC0008060AD8
+:100A5000021680F000000007041680F40000000C6D
+:100A60000316812400040612041681340000000CD1
+:100A700003168164003B0616041682500000000431
+:100A80000316826000020651041682680000000806
+:100A90000316828800080653041682A80000000A84
+:100AA00002168804000000040316880C0010065B80
+:100AB000021680EC000000FF030404080014066B1B
+:100AC000030500440002067F030500500004068170
+:100AD0000405006000000004030500900013068573
+:100AE00002050114000000010305011C0002069824
+:100AF00002050204000000010305020C0002069A30
+:100B00000305021C0003069C040502400000000AC5
+:100B1000030502800020069F0405400000000D0030
+:100B200003050004001006BF020500E00000000EEF
+:100B3000020500E40000002E04164024000000021C
+:100B400003164030000306CF021640440000002088
+:100B5000021640700000001C02164208000000014E
+:100B6000021642100000000102164220000000019F
+:100B70000216422800000001021642300000000167
+:100B80000216423800000001021642600000000117
+:100B90000A000001000000010216401C0003D09072
+:100BA0000A000001000000020216401C000009C4F7
+:100BB0000A000001000000040216401C0000009C16
+:100BC0000216400000000001021640D8000000019B
+:100BD00003164008000306D202164240000000003F
+:100BE0000216424800000000081642700000000291
+:100BF0000216425000000000021642580000000099
+:100C0000081642800000000203042008000406D5F4
+:100C10000304201C000406D90404203800000080CE
+:100C200003042238000406DD01042248000000000D
+:100C30000104224C000000000104225000000000CA
+:100C400001042254000000000104225800000000AA
+:100C50000104225C0000000001042260000000008A
+:100C6000010422640000000001042268000000006A
+:100C70000104226C0000000001042270000000004A
+:100C8000010422740000000001042278000000002A
+:100C90000104227C00000000020424BC00000001CA
+:100CA0000A0000010000000102042000000003E827
+:100CB0000A00000100000002020420000000000AF7
+:100CC0000A000001000000040204200000000001EE
+:100CD00005180400006A000006180760001406E109
+:100CE000041A000000001600041A800000000040F2
+:100CF000031A08B0000206E3031A19C8000206E549
+:100D0000031A2FC0000406E7041A2FD000000006C3
+:100D1000031A2FE8000206EB031A300003F906ED70
+:100D2000041A3FE400000007031A487000040AE6B2
+:100D3000021B800000000034021B804000000018ED
+:100D4000021B80800000000C021B80C000000020FD
+:100D5000021B83800007A120021B83C0000001F456
+:100D6000021B8BC0000000010A000002000000010D
+:100D7000021B83000007A120021B8340000001F436
+:100D80000A00000200000002021B8300000013881A
+:100D9000021B8340000000050A000002000000045E
+:100DA000021B830000000138021B8340000000008A
+:100DB000051C000031730000051C8000358B0C5DA4
+:100DC000051D00000FEB19C0061D21B05BCA0AEA21
+:100DD00001180000000000000118000400000000DD
+:100DE00001180008000000000118000C00000000BD
+:100DF000011800100000000001180014000000009D
+:100E000003180020001A0AEC031800A400020B06C5
+:100E10000218022400000000021802340000000042
+:100E20000218024C00000000021802E4000000FF5B
+:100E30000818100000000400041A08000000000256
+:100E4000041A082000000012041A09C0000000481B
+:100E5000041A250000000010041A2580000000126A
+:100E6000041A261000000012031A2FB000020B080B
+:100E7000041A400000000006041A4030000000027E
+:100E8000041A482000000002031A4C5000020B0A0A
+:100E9000041A081000000002041A0868000000127A
+:100EA000041A0AE000000048041A2540000000105F
+:100EB000041A25C800000012041A26580000001267
+:100EC000031A2FB800020B0C041A40180000000689
+:100ED000041A403800000002041A482800000002EA
+:100EE000031A4C5800020B0E020E004C0000003298
+:100EF000030E005400040B10040E006400000004F4
+:100F0000030E009400130B14020E014400000001B4
+:100F1000030E014C00020B27020E02040000000128
+:100F2000030E020C00020B29030E021C00040B2B03
+:100F3000030E0280001B0B2F040E02EC00000017B2
+:100F4000040E200000000800030E000400110B4AEC
+:100F5000020E01100000000F020E01140000002F0D
+:100F6000020C100000000028030C400800040B5B7A
+:100F7000030C401C00040B5F030C403800020B63A1
+:100F8000040C40400000005E020C41B8000000016B
+:100F9000040C41BC0000001F030C423800040B6528
+:100FA000010C424800000000010C424C000000000F
+:100FB000010C425000000000010C425400000000EF
+:100FC000010C425800000000010C425C00000000CF
+:100FD000010C426000000000010C426400000000AF
+:100FE000010C426800000000010C426C000000008F
+:100FF000010C427000000000010C4274000000006F
+:10100000010C427800000000010C427C000000004E
+:10101000010C428000000000020C44C000000001EE
+:101020000A00000100000001020C4000000003E87B
+:101030000A00000100000002020C40000000000A4B
+:101040000A00000100000004020C40000000000142
+:1010500005300400009B00000630076800130B6990
+:10106000043200000000160004328000000000403E
+:101070000332183000020B6B03322E7000040B6D2C
+:101080000432508000000008033250A000020B71AF
+:10109000023380000000001A023380400000004E3E
+:1010A0000233808000000010023380C00000002066
+:1010B000023383800007A120023383C0000001F4C3
+:1010C00002338BC0000000010A0000020000000192
+:1010D000023383000007A12002338340000001F4A3
+:1010E0000A0000020000000202338300000013889F
+:1010F00002338340000000050A00000200000004E3
+:1011000002338300000001380233834000000000F6
+:1011100005340000332800000534800028840CCA00
+:1011200005350000279416EB0535800036A820D041
+:10113000053600000F982E7A063621503BD60B73E9
+:101140000130000000000000013000040000000039
+:1011500001300008000000000130000C0000000019
+:1011600001300010000000000130001400000000F9
+:1011700003300020001A0B75033000A400020B8F0F
+:10118000023002240000000002300234000000009F
+:101190000230024C00000000023002E40000FFFFB9
+:1011A000083020000000080004322DE0000000029A
+:1011B00004324000000000D8043246C00000012084
+:1011C000043250C80000002404322DE80000000260
+:1011D00004324360000000D804324B40000001207C
+:1011E000043251580000002402020058000000326E
+:1011F0000302006000040B91040200700000000470
+:10120000030200A0000E0B95030200DC00070BA3F5
+:10121000020200FC000000060202012000000000A3
+:101220000202013400000002020201B000000001CD
+:101230000202020C000000010302021400020BAAC9
+:1012400002020404000000010302040C00020BACC3
+:101250000302041C00040BAE03020480001F0BB247
+:10126000040204FC000000130402800000002000BF
+:101270000302000400140BD102020108000000C8A0
+:101280000202011800000002020201C40000000076
+:10129000020201CC00000000020201D400000002A2
+:1012A000020201DC00000002020201E4000000FF73
+:1012B000020201EC000000FF0202010C000000C865
+:1012C0000202011C00000002020201C8000000002E
+:1012D000020201D000000000020201D8000000025A
+:1012E000020201E000000002020201E8000000FF2B
+:1012F000020201F0000000FF0216100000000028AA
+:101300000316600800030BE50316601C00040BE8DD
+:1013100003166038000D0BEC0416606C000000131F
+:10132000031660B800020BF9041660C00000003E0E
+:10133000021661B800000001041661BC0000001F25
+:101340000316623800040BFB01166248000000001F
+:101350000116624C000000000116625000000000FF
+:1013600001166254000000000116625800000000DF
+:101370000116625C000000000116626000000000BF
+:10138000011662640000000001166268000000009F
+:101390000116626C0000000001166270000000007F
+:1013A000011662740000000001166278000000005F
+:1013B0000116627C00000000021664BC00000001FF
+:1013C0000A0000010000000102166000000003E8AE
+:1013D0000A00000100000002021660000000000A7E
+:1013E0000A00000100000004021660000000000175
+:1013F00005280400008800000628076800130BFF7A
+:10140000042A000000001600042A800000000040AA
+:10141000032A250000020C01032A296000040C03A2
+:10142000032A2F4800020C07032A336800020C0924
+:10143000032A392000020C0B032A393000020C0D5C
+:10144000032A3AC800020C0F042A3AD00000000612
+:10145000032A3B9800020C11032A3C2000040C13C1
+:10146000022A3CD000000000022B80000000000097
+:10147000022B804000000018022B80800000000C2E
+:10148000022B80C000000066022B83800007A12091
+:10149000022B83C0000001F4022B8BC0000000016E
+:1014A0000A00000200000001022B83000007A120B7
+:1014B000022B8340000001F40A0000020000000239
+:1014C000022B830000001388022B834000000005DC
+:1014D0000A00000200000004022B83000000013813
+:1014E000022B8340000000000A00000100000020E1
+:1014F000022A3CD400000000052C0000384F0000F8
+:10150000052C80003A560E14052D00003C6D1CAAD7
+:10151000052D80000A4F2BC6062D93704D920C1797
+:101520000128000000000000012800040000000065
+:1015300001280008000000000128000C0000000045
+:101540000128001000000000012800140000000025
+:1015500003280020001A0C19032800A400020C33F1
+:1015600002280224000000000228023400000000CB
+:101570000228024C00000000022802E40000FFFFE5
+:101580000828200000000800042A3910000000028A
+:10159000042A393800000020042A3A3800000010DC
+:1015A000032A3AE800020C35032A3AF800100C37F7
+:1015B000042A3C3000000002042A5000000000020F
+:1015C000042A501000000002042A502000000002EB
+:1015D000042A503000000002022A5040000000009F
+:1015E000042A50480000000E042A391800000002A6
+:1015F000042A39B800000020042A3A7800000010BC
+:10160000032A3AF000020C47032A3B3800100C4929
+:10161000042A3C3800000002042A5008000000029E
+:10162000042A501800000002042A5028000000027A
+:10163000042A503800000002022A50440000000032
+:10164000042A50800000000E0400A00000000016D4
+:101650000300A06C00060C590400A08400000005E3
+:101660000200A0980FE000000400A09C00000014FD
+:101670000300A0EC00080C5F0400A22C0000000492
+:101680000200A060000003070300A10C00060C6725
+:101690000400A124000000050200A1380FE00000B2
+:1016A0000400A13C000000140300A18C00080C6D94
+:1016B0000400A23C000000040200A0640000030734
+:1016C000000000000000000000000000000000001A
+:1016D000000000000000000000000000000000000A
+:1016E00000000000000000000000000000000000FA
+:1016F0000000000000000005000500090009000DC1
+:1017000000000000000000000000000000000000D9
+:1017100000000000000000000000000000000000C9
+:10172000000D001B001B001C001C001D0000000021
+:1017300000000000000000000000000000000000A9
+:10174000000000000000000000000000001D002557
+:101750000000000000000000000000000000000089
+:101760000000000000000000000000000000000079
+:1017700000000000000000000025002B0000000019
+:101780000000000000000000000000000000000059
+:101790000000000000000000000000000000000049
+:1017A00000000000002B00470000000000000000C7
+:1017B0000000000000000000000000000000000029
+:1017C0000000000000000000000000000000000019
+:1017D000004700AE00AE00B300B300B80000000048
+:1017E00000000000000000000000000000000000F9
+:1017F00000000000000000000000000000000000E9
+:1018000000000000000000000000000000000000D8
+:1018100000000000000000000000000000000000C8
+:10182000000000000000000000B800BC0000000044
+:1018300000000000000000000000000000000000A8
+:101840000000000000000000000000000000000098
+:101850000000000000BC00C3000000000000000009
+:101860000000000000000000000000000000000078
+:101870000000000000000000000000000000000068
+:1018800000C300C400C400D600D600E80000000079
+:101890000000000000000000000000000000000048
+:1018A0000000000000000000000000000000000038
+:1018B0000000000000000000000000000000000028
+:1018C0000000000000000000000000000000000018
+:1018D000000000000000000000E800EC0000000034
+:1018E00000000000000000000000000000000000F8
+:1018F00000000000000000000000000000000000E8
+:101900000000000000EC00EF00EF00FA00FA010513
+:1019100000000000000000000000000000000000C7
+:1019200000000000000000000000000000000000B7
+:101930000105010B010B010F010F01130000000055
+:101940000000000000000000000000000000000097
+:101950000000000000000000000000000000000087
+:101960000000000000000000000000000000000077
+:101970000000000000000000000000000000000067
+:10198000000000000000000001130123000000001F
+:101990000000000000000000000000000000000047
+:1019A0000000000000000000000000000000000037
+:1019B00000000000012301320000000000000000D0
+:1019C0000000000000000000000000000000000017
+:1019D0000000000000000000000000000000000007
+:1019E000013201350000000000000000000000008E
+:1019F00000000000000000000000000000000000E7
+:101A00000000000000000000000000000135014A55
+:101A100000000000000000000000000000000000C6
+:101A200000000000000000000000000000000000B6
+:101A30000000000000000000014A014B000000000F
+:101A40000000000000000000000000000000000096
+:101A50000000000000000000000000000000000086
+:101A600000000000014B0158015801590159015A69
+:101A70000000000000000000000000000000000066
+:101A80000000000000000000000000000000000056
+:101A9000015A016E016E01710171017400000000B4
+:101AA0000000000000000000000000000000000036
+:101AB0000000000000000000000000000174018D23
+:101AC0000000000000000000000000000000000016
+:101AD0000000000000000000000000000000000006
+:101AE0000000000000000000018D01BA01BA01C52C
+:101AF00001C501D00000000000000000000000004F
+:101B000000000000000000000000000000000000D5
+:101B10000000000001D001DD01DD01DE01DE01DF9A
+:101B200000000000000000000000000000000000B5
+:101B300000000000000000000000000000000000A5
+:101B400001DF01E0000000000000000000000000D4
+:101B50000000000000000000000000000000000085
+:101B600000000000000000000000000001E001FD96
+:101B70000000000000000000000000000000000065
+:101B80000000000000000000000000000000000055
+:101B9000000000000000000001FD02280228022CC5
+:101BA000022C0230000000000000000000000000D5
+:101BB0000000000000000000000000000000000025
+:101BC00000000000023002420242024A024A02526F
+:101BD0000000000000000000000000000000000005
+:101BE00000000000000000000000000000000000F5
+:101BF000025202530000000000000000000000003C
+:101C000000000000000000000000000000000000D4
+:101C100000000000000000000000000002530271FC
+:101C200000000000000000000000000000000000B4
+:101C300000000000000000000000000000000000A4
+:101C40000000000000000000027102A402A402B023
+:101C500002B002BC00000000000000000000000014
+:101C60000000000000000000000000000000000074
+:101C70000000000002BC02BD02BD02C402C402CBCF
+:101C80000000000000000000000000000000000054
+:101C90000000000000000000000000000000000044
+:101CA00000000000000000000000200000004000D4
+:101CB00000006000000080000000A0000000C000E4
+:101CC0000000E000000100000001200000014000D1
+:101CD00000016000000180000001A0000001C000C0
+:101CE0000001E000000200000002200000024000AD
+:101CF00000026000000280000002A0000002C0009C
+:101D00000002E00000030000000320000003400088
+:101D100000036000000380000003A0000003C00077
+:101D20000003E00000040000000420000004400064
+:101D300000046000000480000004A0000004C00053
+:101D40000004E00000050000000520000005400040
+:101D500000056000000580000005A0000005C0002F
+:101D60000005E0000006000000062000000640001C
+:101D700000066000000680000006A0000006C0000B
+:101D80000006E000000700000007200000074000F8
+:101D900000076000000780000007A0000007C000E7
+:101DA0000007E000000800000008200000084000D4
+:101DB00000086000000880000008A0000008C000C3
+:101DC0000008E000000900000009200000094000B0
+:101DD00000096000000980000009A0000009C0009F
+:101DE0000009E000000A0000000A2000000A40008C
+:101DF000000A6000000A8000000AA000000AC0007B
+:101E0000000AE000000B0000000B2000000B400067
+:101E1000000B6000000B8000000BA000000BC00056
+:101E2000000BE000000C0000000C2000000C400043
+:101E3000000C6000000C8000000CA000000CC00032
+:101E4000000CE000000D0000000D2000000D40001F
+:101E5000000D6000000D8000000DA000000DC0000E
+:101E6000000DE000000E0000000E2000000E4000FB
+:101E7000000E6000000E8000000EA000000EC000EA
+:101E8000000EE000000F0000000F2000000F4000D7
+:101E9000000F6000000F8000000FA000000FC000C6
+:101EA000000FE000001000000010200000104000B3
+:101EB00000106000001080000010A0000010C000A2
+:101EC0000010E0000011000000112000001140008F
+:101ED00000116000001180000011A0000011C0007E
+:101EE0000011E0000012000000122000001240006B
+:101EF00000126000001280000012A0000012C0005A
+:101F00000012E00000130000001320000013400046
+:101F100000136000001380000013A0000013C00035
+:101F20000013E00000140000001420000014400022
+:101F300000146000001480000014A0000014C00011
+:101F40000014E000001500000015200000154000FE
+:101F500000156000001580000015A0000015C000ED
+:101F60000015E000001600000016200000164000DA
+:101F700000166000001680000016A0000016C000C9
+:101F80000016E000001700000017200000174000B6
+:101F900000176000001780000017A0000017C000A5
+:101FA0000017E00000180000001820000018400092
+:101FB00000186000001880000018A0000018C00081
+:101FC0000018E0000019000000192000001940006E
+:101FD00000196000001980000019A0000019C0005D
+:101FE0000019E000001A0000001A2000001A40004A
+:101FF000001A6000001A8000001AA000001AC00039
+:10200000001AE000001B0000001B2000001B400025
+:10201000001B6000001B8000001BA000001BC00014
+:10202000001BE000001C0000001C2000001C400001
+:10203000001C6000001C8000001CA000001CC000F0
+:10204000001CE000001D0000001D2000001D4000DD
+:10205000001D6000001D8000001DA000001DC000CC
+:10206000001DE000001E0000001E2000001E4000B9
+:10207000001E6000001E8000001EA000001EC000A8
+:10208000001EE000001F0000001F2000001F400095
+:10209000001F6000001F8000001FA000001FC00084
+:1020A000001FE00000200000002020000020400071
+:1020B00000206000002080000020A0000020C00060
+:1020C0000020E0000021000000212000002140004D
+:1020D00000216000002180000021A0000021C0003C
+:1020E0000021E00000220000002220000022400029
+:1020F00000226000002280000022A0000022C00018
+:102100000022E00000230000002320000023400004
+:1021100000236000002380000023A0000023C000F3
+:102120000023E000002400000024200000244000E0
+:1021300000246000002480000024A0000024C000CF
+:102140000024E000002500000025200000254000BC
+:1021500000256000002580000025A0000025C000AB
+:102160000025E00000260000002620000026400098
+:1021700000266000002680000026A0000026C00087
+:102180000026E00000270000002720000027400074
+:1021900000276000002780000027A0000027C00063
+:1021A0000027E00000280000002820000028400050
+:1021B00000286000002880000028A0000028C0003F
+:1021C0000028E0000029000000292000002940002C
+:1021D00000296000002980000029A0000029C0001B
+:1021E0000029E000002A0000002A2000002A400008
+:1021F000002A6000002A8000002AA000002AC000F7
+:10220000002AE000002B0000002B2000002B4000E3
+:10221000002B6000002B8000002BA000002BC000D2
+:10222000002BE000002C0000002C2000002C4000BF
+:10223000002C6000002C8000002CA000002CC000AE
+:10224000002CE000002D0000002D2000002D40009B
+:10225000002D6000002D8000002DA000002DC0008A
+:10226000002DE000002E0000002E2000002E400077
+:10227000002E6000002E8000002EA000002EC00066
+:10228000002EE000002F0000002F2000002F400053
+:10229000002F6000002F8000002FA000002FC00042
+:1022A000002FE0000030000000302000003040002F
+:1022B00000306000003080000030A0000030C0001E
+:1022C0000030E0000031000000312000003140000B
+:1022D00000316000003180000031A0000031C000FA
+:1022E0000031E000003200000032200000324000E7
+:1022F00000326000003280000032A0000032C000D6
+:102300000032E000003300000033200000334000C2
+:1023100000336000003380000033A0000033C000B1
+:102320000033E0000034000000342000003440009E
+:1023300000346000003480000034A0000034C0008D
+:102340000034E0000035000000352000003540007A
+:1023500000356000003580000035A0000035C00069
+:102360000035E00000360000003620000036400056
+:1023700000366000003680000036A0000036C00045
+:102380000036E00000370000003720000037400032
+:1023900000376000003780000037A0000037C00021
+:1023A0000037E0000038000000382000003840000E
+:1023B00000386000003880000038A0000038C000FD
+:1023C0000038E000003900000039200000394000EA
+:1023D00000396000003980000039A0000039C000D9
+:1023E0000039E000003A0000003A2000003A4000C6
+:1023F000003A6000003A8000003AA000003AC000B5
+:10240000003AE000003B0000003B2000003B4000A1
+:10241000003B6000003B8000003BA000003BC00090
+:10242000003BE000003C0000003C2000003C40007D
+:10243000003C6000003C8000003CA000003CC0006C
+:10244000003CE000003D0000003D2000003D400059
+:10245000003D6000003D8000003DA000003DC00048
+:10246000003DE000003E0000003E2000003E400035
+:10247000003E6000003E8000003EA000003EC00024
+:10248000003EE000003F0000003F2000003F400011
+:10249000003F6000003F8000003FA000003FC00000
+:1024A000003FE000003FE00100000000000001FFED
+:1024B0000000020000000001000000020000000017
+:1024C000000000080215002002150020081000007E
+:1024D00000000033000000020000000000000005C2
+:1024E00000000005000000000000000000000002E5
+:1024F00000000003000000020000000100000004D2
+:1025000000000002000000020000000100000002C4
+:102510000000002000000040000000400000000318
+:102520000000001800002000000040C00000618092
+:10253000000082400000A3000000C3C00000E4804F
+:102540000001054000012600000146C0000167802F
+:10255000000188400001A9000001C9C00001EA8013
+:1025600000020B4000022C0000024CC000026D80F3
+:1025700000028E400002AF000002CFC00002F080D7
+:1025800000001140000000010000000100000001F7
+:102590000000000100000001000000010000000137
+:1025A0000000000100000001000000010000000127
+:1025B0000000000100000001000000010000000117
+:1025C0000003D0000000003D00000001000D0000ED
+:1025D000000700D000028140000B81680002022049
+:1025E00000010240000F025000010340000C0000F7
+:1025F000000800C000028140000B81680002022038
+:102600000001024000070250000202C0001000005A
+:102610000008010000028180000B81A80002026016
+:1026200000018280000E82980008038000000000F4
+:102630000000000000028000000B8028000200E083
+:10264000000101000000811000000118FFFFFFF3EE
+:1026500001AFFFFF000000000000000000000000CC
+:10266000000000000000000000000000FFFFFFF17C
+:1026700000EFFFFF0000000000000000000000006D
+:10268000000000000001000000000000FFFFFFF656
+:10269000005FFFFF000000000000000000000000DD
+:1026A000000000000002000000000000FFFFF40630
+:1026B0001CBFFFFF00000005000000000000001428
+:1026C000000000000004000000000000FFFFFFF217
+:1026D000004FFFFF000000000000000000000000AD
+:1026E000000000000008000000000000FFFFFFFAEB
+:1026F000002FFFFF000000000000000000000000AD
+:10270000000000000010000000000000FFFFFFF7C5
+:1027100001EFFFFF000000000000000000000000CB
+:10272000000000000020000000000000FFFFFFF597
+:10273000002FFFFF0000000000000000000000006C
+:10274000000000000040000000000000FFFFFFF359
+:10275000018FFFFF000000000000000000000000EB
+:10276000000000000000000000000000FFFFFFF17B
+:10277000010FFFFF0000000000000000000000004B
+:10278000000000000001000000000000FFFFFFF655
+:10279000005FFFFF000000000000000000000000DC
+:1027A000000000000002000000000000FFFFF4062F
+:1027B0001CBFFFFF00000005000000000000001427
+:1027C000000000000004000000000000FFFFFFF216
+:1027D000004FFFFF000000000000000000000000AC
+:1027E000000000000008000000000000FFFFFFFAEA
+:1027F000002FFFFF000000000000000000000000AC
+:10280000000000000010000000000000FFFFFFF7C4
+:1028100000EFFFFF000000000000000000000000CB
+:10282000000000000020000000000000FFFFFFF596
+:10283000004FFFFF0000000000000000000000004B
+:10284000000000000040000000000000FFFFFFFF4C
+:1028500000CFFFFF0000000000000000000000CCDF
+:10286000000000000000000000000000FFFFFFFF6C
+:1028700000CFFFFF0000000000000000000000CCBF
+:10288000000000000001000000000000FFFFFFFF4B
+:1028900000CFFFFF0000000000000000000000CC9F
+:1028A000000000000002000000000000FFFFFFFF2A
+:1028B00000CFFFFF0000000000000000000000CC7F
+:1028C000000000000004000000000000FFFFFFFF08
+:1028D00000CFFFFF0000000000000000000000CC5F
+:1028E000000000000008000000000000FFFFFFFFE4
+:1028F00000CFFFFF0000000000000000000000CC3F
+:10290000000000000010000000000000FFFFFFFFBB
+:1029100000CFFFFF0000000000000000000000CC1E
+:10292000000000000020000000000000FFFFFFFF8B
+:1029300000CFFFFF0000000000000000000000CCFE
+:10294000000000000040000000000000FFFFFFF357
+:10295000020FFFFF00000000000000000000000068
+:10296000000000000000000000000000FFFFFFF179
+:10297000010FFFFF00000000000000000000000049
+:10298000000000000001000000000000FFFFFFF653
+:10299000005FFFFF000000000000000000000000DA
+:1029A000000000000002000000000000FFFFF4062D
+:1029B0001CBFFFFF00000005000000000000001425
+:1029C000000000000004000000000000FFFFFFF214
+:1029D000004FFFFF000000000000000000000000AA
+:1029E000000000000008000000000000FFFFFF8A58
+:1029F000042FFFFF000000000000000000000000A6
+:102A0000000000000010000000000000FFFFFF9722
+:102A100005CFFFFF000000000000000000000000E4
+:102A2000000000000020000000000000FFFFFFF594
+:102A3000010FFFFF00000000000000000000000088
+:102A4000000000000040000000000000FFFFFFF356
+:102A5000000FFFFF00000000000000000000000069
+:102A6000000000000000000000000000FFFFFFF178
+:102A7000000FFFFF00000000000000000000000049
+:102A8000000000000001000000000000FFFFFFF652
+:102A9000005FFFFF000000000000000000000000D9
+:102AA000000000000002000000000000FFFFF4062C
+:102AB0001CBFFFFF00000005000000000000001424
+:102AC000000000000004000000000000FFFFFFF213
+:102AD000004FFFFF000000000000000000000000A9
+:102AE000000000000008000000000000FFFFFFFAE7
+:102AF000002FFFFF000000000000000000000000A9
+:102B0000000000000010000000000000FFFFFF9721
+:102B1000040FFFFF000000000000000000000000A4
+:102B2000000000000020000000000000FFFFFFF593
+:102B3000000FFFFF00000000000000000000000088
+:102B4000000000000040000000000000FFFFFFFF49
+:102B500000CFFFFF0000000000000000000000CCDC
+:102B6000000000000000000000000000FFFFFFFF69
+:102B700000CFFFFF0000000000000000000000CCBC
+:102B8000000000000001000000000000FFFFFFFF48
+:102B900000CFFFFF0000000000000000000000CC9C
+:102BA000000000000002000000000000FFFFFFFF27
+:102BB00000CFFFFF0000000000000000000000CC7C
+:102BC000000000000004000000000000FFFFFFFF05
+:102BD00000CFFFFF0000000000000000000000CC5C
+:102BE000000000000008000000000000FFFFFFFFE1
+:102BF00000CFFFFF0000000000000000000000CC3C
+:102C0000000000000010000000000000FFFFFFFFB8
+:102C100000CFFFFF0000000000000000000000CC1B
+:102C2000000000000020000000000000FFFFFFFF88
+:102C300000CFFFFF0000000000000000000000CCFB
+:102C4000000000000040000000000000FFFFFFFF48
+:102C500000CFFFFF0000000000000000000000CCDB
+:102C6000000000000000000000000000FFFFFFFF68
+:102C700000CFFFFF0000000000000000000000CCBB
+:102C8000000000000001000000000000FFFFFFFF47
+:102C900000CFFFFF0000000000000000000000CC9B
+:102CA000000000000002000000000000FFFFFFFF26
+:102CB00000CFFFFF0000000000000000000000CC7B
+:102CC000000000000004000000000000FFFFFFFF04
+:102CD00000CFFFFF0000000000000000000000CC5B
+:102CE000000000000008000000000000FFFFFFFFE0
+:102CF00000CFFFFF0000000000000000000000CC3B
+:102D0000000000000010000000000000FFFFFFFFB7
+:102D100000CFFFFF0000000000000000000000CC1A
+:102D2000000000000020000000000000FFFFFFFF87
+:102D300000CFFFFF0000000000000000000000CCFA
+:102D4000000000000040000000000000FFFFFFFF47
+:102D500000CFFFFF0000000000000000000000CCDA
+:102D6000000000000000000000000000FFFFFFFF67
+:102D700000CFFFFF0000000000000000000000CCBA
+:102D8000000000000001000000000000FFFFFFFF46
+:102D900000CFFFFF0000000000000000000000CC9A
+:102DA000000000000002000000000000FFFFFFFF25
+:102DB00000CFFFFF0000000000000000000000CC7A
+:102DC000000000000004000000000000FFFFFFFF03
+:102DD00000CFFFFF0000000000000000000000CC5A
+:102DE000000000000008000000000000FFFFFFFFDF
+:102DF00000CFFFFF0000000000000000000000CC3A
+:102E0000000000000010000000000000FFFFFFFFB6
+:102E100000CFFFFF0000000000000000000000CC19
+:102E2000000000000020000000000000FFFFFFFF86
+:102E300000CFFFFF0000000000000000000000CCF9
+:102E40000000000000400000000000000000020040
+:102E500000003DFF00000A1100000A0000000A0403
+:102E60000000FFFF0000FFFF0000FFFF0000FFFF6A
+:102E700000000020000000210000002200000023CC
+:102E800000000024000000250000002600000027AC
+:102E900000000028000000290000002A0000002B8C
+:102EA0000000002C0000002D0000002E0000002F6C
+:102EB00000000010000000010000000100000001FF
+:102EC00000000001000000010000000100000001FE
+:102ED00000000001000000010000000100000001EE
+:102EE00000000001000000010000000100000001DE
+:102EF000000000010000000107FFFFFF0000003F8D
+:102F000007FFFFFF0000000F00007FF800007FF8C0
+:102F10000000FF1C0FFFFFFF0000FF1C0FFFFFFF63
+:102F20000000FF1C0FFFFFFF0000FF1C0FFFFFFF53
+:102F30000000FF1C0FFFFFFF0000FF1C0FFFFFFF43
+:102F40000000FF1C0FFFFFFF0000FF1C0FFFFFFF33
+:102F50000000FF1C0FFFFFFF0000FF1C0FFFFFFF23
+:102F60000000FF1C0FFFFFFF0000FF1C0FFFFFFF13
+:102F70000000FF1C0FFFFFFF0000FF1C0FFFFFFF03
+:102F80000000FF1C0FFFFFFF0000FF1C0FFFFFFFF3
+:102F90000000FF1C0FFFFFFF0000FF1C0FFFFFFFE3
+:102FA0000000FF1C0FFFFFFF0000FF1C0FFFFFFFD3
+:102FB0000000FF1C0FFFFFFF0000FF1C0FFFFFFFC3
+:102FC0000000FF1C0FFFFFFF0000FF1C0FFFFFFFB3
+:102FD0000000FF1C0FFFFFFF0000FF1C0FFFFFFFA3
+:102FE0000000FF1C0FFFFFFF0000FF1C0FFFFFFF93
+:102FF0000000FF1C0FFFFFFF0000FF1C0FFFFFFF83
+:103000000000FF1C0FFFFFFF0000FF1C0FFFFFFF72
+:103010000000FF1C0FFFFFFF0000FF1C0FFFFFFF62
+:103020000000FF1C0FFFFFFF0000FF1C0FFFFFFF52
+:103030000000FF1C0FFFFFFF0000FF1C0FFFFFFF42
+:103040000000FF1C0FFFFFFF0000FF1C0FFFFFFF32
+:103050000000FF1C0FFFFFFF0000FF1C0FFFFFFF22
+:103060000000FF1C0FFFFFFF0000FF1C0FFFFFFF12
+:103070000000FF1C0FFFFFFF0000FF1C0FFFFFFF02
+:103080000000FF1C0FFFFFFF0000FF1C0FFFFFFFF2
+:103090000000FF1C0FFFFFFF0000FF1C0FFFFFFFE2
+:1030A0000000FF1C0FFFFFFF0000FF1C0FFFFFFFD2
+:1030B0000000FF1C0FFFFFFF0000FF1C0FFFFFFFC2
+:1030C0000000FF1C0FFFFFFF0000FF1C0FFFFFFFB2
+:1030D0000000FF1C0FFFFFFF0000FF1C0FFFFFFFA2
+:1030E0000000FF1C0FFFFFFF0000FF1C0FFFFFFF92
+:1030F0000000FF1C0FFFFFFF0000FF1C0FFFFFFF82
+:103100000000FF1C0FFFFFFF0000FF1C0FFFFFFF71
+:103110000000FF00000000000000FF0000000000B1
+:103120000000000200001500000000010000000285
+:103130000000000300000000000000040000000187
+:10314000000000000000000100000004000000007A
+:10315000000000010000000300000000000000016A
+:103160000000000400000000000000010000000357
+:10317000000000000000000100000004000000004A
+:103180000000000400000003000000000000000038
+:1031900000003FFF000003FF0000000000000001EE
+:1031A0000000000100000001007C10040000000489
+:1031B00000000000000000020000009000000090ED
+:1031C00000800090081000000000008A00000080CD
+:1031D000000000810000008000000006000007D011
+:1031E0000000076C0000FFFF0000FFFF0000FFFF72
+:1031F0000000FFFF071D291100000000009C0424AF
+:1032000000000000000000010000000100000001BB
+:10321000000000010000000100007FFF000000FF2F
+:10322000000000FF000000FF000000FF000000FFA2
+:10323000000000FF000000FF000000FF0000003E53
+:10324000000000000000003F0000003F0000003FC1
+:10325000000000000000003F0000003F0000003FB1
+:103260000000000F00000043000000000000000606
+:1032700000000000121700002217000032170000A3
+:103280001215000022150000321500000210000087
+:10329000001000001010000020100000301000008E
+:1032A000001000001214000022140000321400006C
+:1032B00000E38340FFFFFFFFFFFFFFFFFFFFFFFF74
+:1032C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E
+:1032D000FFFFFFFFF0003000FFFFFFFFFFFFFFFFDA
+:1032E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE
+:1032F000FFFFFFFFFFFF3328FFFF3338FFFFFFFF14
+:10330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD
+:10331000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD
+:10332000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD
+:10333000FFFFFFFF00003C1000000008000000003D
+:103340000000000000000040000018080000080312
+:103350000000080300000040000000030000080314
+:103360000000080300000803000100030000080338
+:103370000000080300000003000000030000000339
+:103380000000000300000003000000030000000331
+:103390000000000300000003000000030000000321
+:1033A0000000000300000003000000030000000311
+:1033B000000024030000002F000000090000001995
+:1033C00000000184000001830000030600000019D2
+:1033D00000000006000003060000030600000306CC
+:1033E00000000C8600000306000003060000000633
+:1033F00000000006000000060000000600000006B5
+:1034000000000006000000060000000600000006A4
+:103410000000000600000006000000060000000694
+:103420000000000600000006000003060000001374
+:1034300000000006000010040000100400106440AA
+:1034400000106440000000000000000000000000C8
+:10345000000000000000200000000000000000004C
+:10346000000000000000000000002000000000003C
+:10347000000000000000000000000000000020002C
+:103480000000007C0000003D0000003F0000009CA8
+:1034900000000006000000050000000A0000000512
+:1034A000000001400000014000000000000000009A
+:1034B000000000C00000013F00007FFF0000004846
+:1034C000000000480000000000000000000000486C
+:1034D00000000004000000040000000400000004DC
+:1034E00000000004000000040000000400000004CC
+:1034F00000000004000000090000000B0000000AAA
+:1035000000000004000000090000000B0000000A99
+:1035100000000001000000010000000100000001A7
+:103520000000000100000001000000010000000197
+:103530000000000100000001000000010000000187
+:1035400000000004000000090000000B0000000A59
+:103550000000000100000001000000010000000167
+:103560000000000100000001000000010000000157
+:103570000000000100000001000000010000000147
+:1035800000000004000000090000000B0000000A19
+:103590000000000000000000000008000000020021
+:1035A000000001FF00000400000000000000000017
+:1035B0001E491E491E491E490E490E490E490E4913
+:1035C000FFFFFFFF00000000FFFFFFFF0000000003
+:1035D000000025E400008000000000130FFF0FFF33
+:1035E00000000000000000000FFF0FFF100010009F
+:1035F000100010002000200020002000800080002B
+:1036000080008000400040004000400000000000BA
+:10361000000000010101010101200101200101015F
+:10362000010110010101010101200101200101013D
+:10363000010110012001010101011001010101013D
+:10364000012001012001010101011001010101011D
+:1036500001200101000001230000012300000123DB
+:1036600000000123000001230000012300000123CA
+:1036700000000123000001230000012300000123BA
+:1036800000000123000001230000012300000123AA
+:10369000000001230000012300000123000001239A
+:1036A000000001230000002000000032000000079D
+:1036B00000000007000000000000000802150020C4
+:1036C0000215002000000030081000000000003348
+:1036D0000000003000000031000000020000000582
+:1036E00000000006000000020000000200000000D0
+:1036F00000000005000000020000000200000002BF
+:1037000000000001000000060000000100000002AF
+:1037100000000040000000400000002000000013F6
+:103720000000002000010000000204C00003098026
+:1037300000040E4000051300000617C000071C809F
+:103740000008214000092600000A2AC0000B2F8033
+:10375000000C3440000D3900000E3DC0000F4280C7
+:103760000010474000114C00001250C0001355805B
+:1037700000145A4000155F00001663C000176880EF
+:1037800000186D4000197200001A76C0001B7B8083
+:10379000001C8040001D8500001E89C0001F8E8017
+:1037A0000000934000000001000000010000000143
+:1037B0000000000100000001000000010000000105
+:1037C00000000001000000010000000100000001F5
+:1037D00000000001000000010000000100000001E5
+:1037E00000000001000000080000000C00000010B4
+:1037F00000000001000000010000000100000211B3
+:103800000000020000000204000002190000FFFF97
+:103810000000FFFF0000FFFF0000FFFF07FFFFFFAA
+:103820000000003F07FFFFFF0000000F00007FF8CF
+:1038300000007FF800000000140AFF0000000000F4
+:1038400000000001002010010000000001008600BF
+:1038500000000100000000010000000000008602DE
+:1038600000000000000000000000000000008604CE
+:1038700000000000000000000000000000008606BC
+:1038800000000000000000000000000000008608AA
+:103890000000000000000000000000000000860A98
+:1038A0000000000000000000000000000000860C86
+:1038B0000000000000000000000000000000860E74
+:1038C0000000000000000000000000000000861062
+:1038D0000000000000000000000000000000861250
+:1038E000000000000000000000000000000086143E
+:1038F000000000000000000000000000000086162C
+:103900000000000000000000000000000000861819
+:103910000000000000000000000000000000861A07
+:103920000000000000000000000000000000861CF5
+:103930000000000000000000000000000000861EE3
+:1039400000000000000000000000000000008620D1
+:1039500000000000000000000000000000008622BF
+:1039600000000000000000000000000000008624AD
+:10397000000000000000000000000000000086269B
+:103980000000000000000000000000000000862889
+:103990000000000000000000000000000000862A77
+:1039A0000000000000000000000000000000862C65
+:1039B0000000000000000000000000000000862E53
+:1039C0000000000000000000000000000000863041
+:1039D000000000000000000000000000000086322F
+:1039E000000000000000000000000000000086341D
+:1039F000000000000000000000000000000086360B
+:103A000000000000000000000000000000008638F8
+:103A10000000000000000000000000000000863AE6
+:103A20000000000000000000000000000000863CD4
+:103A30000000000000000000000000000000863EC2
+:103A400000000000000000000000000000008640B0
+:103A5000000000000000000000000000000086429E
+:103A6000000000000000000000000000000086448C
+:103A7000000000000000000000000000000086467A
+:103A80000000000000000000000000000000864868
+:103A90000000000000000000000000000000864A56
+:103AA0000000000000000000000000000000864C44
+:103AB0000000000000000000000000000000864E32
+:103AC0000000000000000000000000000000865020
+:103AD000000000000000000000000000000086520E
+:103AE00000000000000000000000000000008654FC
+:103AF00000000000000000000000000000008656EA
+:103B000000000000000000000000000000008658D7
+:103B10000000000000000000000000000000865AC5
+:103B20000000000000000000000000000000865CB3
+:103B30000000000000000000000000000000865EA1
+:103B4000000000000000000000000000000086608F
+:103B5000000000000000000000000000000086627D
+:103B6000000000000000000000000000000086646B
+:103B70000000000000000000000000000000866659
+:103B80000000000000000000000000000000866847
+:103B90000000000000000000000000000000866A35
+:103BA0000000000000000000000000000000866C23
+:103BB0000000000000000000000000000000866E11
+:103BC00000000000000000000000000000008670FF
+:103BD00000000000000000000000000000008672ED
+:103BE00000000000000000000000000000008674DB
+:103BF00000000000000000000000000000008676C9
+:103C000000000000000000000000000000008678B6
+:103C10000000000000000000000000000000867AA4
+:103C20000000000000000000000000000000867C92
+:103C30000000000000000000000000000000867E80
+:103C4000000000000000000000000000000086806E
+:103C5000000000000000000000000000000086825C
+:103C6000000000000000000000000000000086844A
+:103C70000000000000000000000000000000868638
+:103C80000000000000000000000000000000868826
+:103C90000000000000000000000000000000868A14
+:103CA0000000000000000000000000000000868C02
+:103CB0000000000000000000000000000000868EF0
+:103CC00000000000000000000000000000008690DE
+:103CD00000000000000000000000000000008692CC
+:103CE00000000000000000000000000000008694BA
+:103CF00000000000000000000000000000008696A8
+:103D00000000000000000000000000000000869895
+:103D10000000000000000000000000000000869A83
+:103D20000000000000000000000000000000869C71
+:103D30000000000000000000000000000000869E5F
+:103D4000000000000000000000000000000086A04D
+:103D5000000000000000000000000000000086A23B
+:103D6000000000000000000000000000000086A429
+:103D7000000000000000000000000000000086A617
+:103D8000000000000000000000000000000086A805
+:103D9000000000000000000000000000000086AAF3
+:103DA000000000000000000000000000000086ACE1
+:103DB000000000000000000000000000000086AECF
+:103DC000000000000000000000000000000086B0BD
+:103DD000000000000000000000000000000086B2AB
+:103DE000000000000000000000000000000086B499
+:103DF000000000000000000000000000000086B687
+:103E0000000000000000000000000000000086B874
+:103E1000000000000000000000000000000086BA62
+:103E2000000000000000000000000000000086BC50
+:103E3000000000000000000000000000000086BE3E
+:103E4000000000000000000000000000000086C02C
+:103E5000000000000000000000000000000086C21A
+:103E6000000000000000000000000000000086C408
+:103E7000000000000000000000000000000086C6F6
+:103E8000000000000000000000000000000086C8E4
+:103E9000000000000000000000000000000086CAD2
+:103EA000000000000000000000000000000086CCC0
+:103EB000000000000000000000000000000086CEAE
+:103EC000000000000000000000000000000086D09C
+:103ED000000000000000000000000000000086D28A
+:103EE000000000000000000000000000000086D478
+:103EF000000000000000000000000000000086D666
+:103F0000000000000000000000000000000086D853
+:103F1000000000000000000000000000000086DA41
+:103F2000000000000000000000000000000086DC2F
+:103F3000000000000000000000000000000086DE1D
+:103F4000000000000000000000000000000086E00B
+:103F5000000000000000000000000000000086E2F9
+:103F6000000000000000000000000000000086E4E7
+:103F7000000000000000000000000000000086E6D5
+:103F8000000000000000000000000000000086E8C3
+:103F9000000000000000000000000000000086EAB1
+:103FA000000000000000000000000000000086EC9F
+:103FB000000000000000000000000000000086EE8D
+:103FC000000000000000000000000000000086F07B
+:103FD000000000000000000000000000000086F269
+:103FE000000000000000000000000000000086F457
+:103FF000000000000000000000000000000086F645
+:10400000000000000000000000000000000086F832
+:10401000000000000000000000000000000086FA20
+:10402000000000000000000000000000000086FC0E
+:10403000000000000000000000000000000086FEFC
+:1040400000000000000000000000000000008700E9
+:1040500000000000000000000000000000008702D7
+:1040600000000000000000000000000000008704C5
+:1040700000000000000000000000000000008706B3
+:1040800000000000000000000000000000008708A1
+:104090000000000000000000000000000000870A8F
+:1040A0000000000000000000000000000000870C7D
+:1040B0000000000000000000000000000000870E6B
+:1040C0000000000000000000000000000000871059
+:1040D0000000000000000000000000000000871247
+:1040E0000000000000000000000000000000871435
+:1040F0000000000000000000000000000000871623
+:104100000000000000000000000000000000871810
+:104110000000000000000000000000000000871AFE
+:104120000000000000000000000000000000871CEC
+:104130000000000000000000000000000000871EDA
+:1041400000000000000000000000000000008720C8
+:1041500000000000000000000000000000008722B6
+:1041600000000000000000000000000000008724A4
+:104170000000000000000000000000000000872692
+:104180000000000000000000000000000000872880
+:104190000000000000000000000000000000872A6E
+:1041A0000000000000000000000000000000872C5C
+:1041B0000000000000000000000000000000872E4A
+:1041C0000000000000000000000000000000873038
+:1041D0000000000000000000000000000000873226
+:1041E0000000000000000000000000000000873414
+:1041F0000000000000000000000000000000873602
+:1042000000000000000000000000000000008738EF
+:104210000000000000000000000000000000873ADD
+:104220000000000000000000000000000000873CCB
+:104230000000000000000000000000000000873EB9
+:1042400000000000000000000000000000008740A7
+:104250000000000000000000000000000000874295
+:104260000000000000000000000000000000874483
+:104270000000000000000000000000000000874671
+:10428000000000000000000000000000000087485F
+:104290000000000000000000000000000000874A4D
+:1042A0000000000000000000000000000000874C3B
+:1042B0000000000000000000000000000000874E29
+:1042C0000000000000000000000000000000875017
+:1042D0000000000000000000000000000000875205
+:1042E00000000000000000000000000000008754F3
+:1042F00000000000000000000000000000008756E1
+:1043000000000000000000000000000000008758CE
+:104310000000000000000000000000000000875ABC
+:104320000000000000000000000000000000875CAA
+:104330000000000000000000000000000000875E98
+:104340000000000000000000000000000000876086
+:104350000000000000000000000000000000876274
+:104360000000000000000000000000000000876462
+:104370000000000000000000000000000000876650
+:10438000000000000000000000000000000087683E
+:104390000000000000000000000000000000876A2C
+:1043A0000000000000000000000000000000876C1A
+:1043B0000000000000000000000000000000876E08
+:1043C00000000000000000000000000000008770F6
+:1043D00000000000000000000000000000008772E4
+:1043E00000000000000000000000000000008774D2
+:1043F00000000000000000000000000000008776C0
+:1044000000000000000000000000000000008778AD
+:104410000000000000000000000000000000877A9B
+:104420000000000000000000000000000000877C89
+:104430000000000000000000000000000000877E77
+:104440000000000000000000000000000000878065
+:104450000000000000000000000000000000878253
+:104460000000000000000000000000000000878441
+:10447000000000000000000000000000000087862F
+:10448000000000000000000000000000000087881D
+:104490000000000000000000000000000000878A0B
+:1044A0000000000000000000000000000000878CF9
+:1044B0000000000000000000000000000000878EE7
+:1044C00000000000000000000000000000008790D5
+:1044D00000000000000000000000000000008792C3
+:1044E00000000000000000000000000000008794B1
+:1044F000000000000000000000000000000087969F
+:10450000000000000000000000000000000087988C
+:104510000000000000000000000000000000879A7A
+:104520000000000000000000000000000000879C68
+:104530000000000000000000000000000000879E56
+:10454000000000000000000000000000000087A044
+:10455000000000000000000000000000000087A232
+:10456000000000000000000000000000000087A420
+:10457000000000000000000000000000000087A60E
+:10458000000000000000000000000000000087A8FC
+:10459000000000000000000000000000000087AAEA
+:1045A000000000000000000000000000000087ACD8
+:1045B000000000000000000000000000000087AEC6
+:1045C000000000000000000000000000000087B0B4
+:1045D000000000000000000000000000000087B2A2
+:1045E000000000000000000000000000000087B490
+:1045F000000000000000000000000000000087B67E
+:10460000000000000000000000000000000087B86B
+:10461000000000000000000000000000000087BA59
+:10462000000000000000000000000000000087BC47
+:10463000000000000000000000000000000087BE35
+:10464000000000000000000000000000000087C023
+:10465000000000000000000000000000000087C211
+:10466000000000000000000000000000000087C4FF
+:10467000000000000000000000000000000087C6ED
+:10468000000000000000000000000000000087C8DB
+:10469000000000000000000000000000000087CAC9
+:1046A000000000000000000000000000000087CCB7
+:1046B000000000000000000000000000000087CEA5
+:1046C000000000000000000000000000000087D093
+:1046D000000000000000000000000000000087D281
+:1046E000000000000000000000000000000087D46F
+:1046F000000000000000000000000000000087D65D
+:10470000000000000000000000000000000087D84A
+:10471000000000000000000000000000000087DA38
+:10472000000000000000000000000000000087DC26
+:10473000000000000000000000000000000087DE14
+:10474000000000000000000000000000000087E002
+:10475000000000000000000000000000000087E2F0
+:10476000000000000000000000000000000087E4DE
+:10477000000000000000000000000000000087E6CC
+:10478000000000000000000000000000000087E8BA
+:10479000000000000000000000000000000087EAA8
+:1047A000000000000000000000000000000087EC96
+:1047B000000000000000000000000000000087EE84
+:1047C000000000000000000000000000000087F072
+:1047D000000000000000000000000000000087F260
+:1047E000000000000000000000000000000087F44E
+:1047F000000000000000000000000000000087F63C
+:10480000000000000000000000000000000087F829
+:10481000000000000000000000000000000087FA17
+:10482000000000000000000000000000000087FC05
+:10483000000000000000000000000000000087FEF3
+:104840000000FF00000000000000FF00000000006A
+:10485000000000020000150000000001000000023E
+:104860000000000300000000000000040000000140
+:104870000000000000000001000000040000000033
+:104880000000000100000003000000000000000123
+:104890000000000400000000000000010000000310
+:1048A0000000000000000001000000040000000003
+:1048B00000000004000000030000000000000000F1
+:1048C00000003FFF000003FF0000000300BEBC200B
+:1048D00000000000000000050000000300BEBC2036
+:1048E00000000000000000050000000D0000000CAA
+:1048F000000000000000001002150020021500203A
+:1049000000000030081000000000003300000030FC
+:104910000000003100000002000000040000000060
+:104920000000000200000002000000000000000281
+:10493000000000070000000200000002000000016B
+:104940000000000300000001000000020000004021
+:104950000000004000000004000000200000000FE4
+:104960000000001B00008000000103C000018780E0
+:1049700000020B4000028F00000312C0000396806B
+:1049800000041A4000049E00000521C00005A58017
+:10499000000629400006AD00000730C00007B480C3
+:1049A000000838400008BC0000093FC00009C3806F
+:1049B000000A4740000ACB00000B4EC0000BD2801B
+:1049C000000C5640000CDA00000D5DC00000618054
+:1049D00000000001000000010000000100000001D3
+:1049E00000000001000000010000000100000001C3
+:1049F00000000001000000010000000100000001B3
+:104A000000000001000000010000000100000001A2
+:104A100000000001000005AA000005990000059DA6
+:104A2000000003C00000FFFF0000FFFF0000FFFFC9
+:104A30000000FFFF000000460000000C07FFFFFF22
+:104A40000000003F07FFFFFF0000000F00007FF89D
+:104A500000007FF8FFFFFFFFFFFFFFFF0000FF00E8
+:104A6000000000000000FF0000000000000019002E
+:104A7000000000000000000200001500000000011E
+:104A8000000000020000000300000000000000041D
+:104A90000000000100000000000000010000000410
+:104AA0000000000000000001000000030000000002
+:104AB00000000001000000040000000000000001F0
+:104AC00000000003000000000000000100000004DE
+:104AD00000000000000000040000000300000000CF
+:104AE0000000000000003FFF000003FF0000000F77
+:104AF00000000007000000000000000E0315002069
+:104B000003150020010000300810000000000033F1
+:104B1000000000300000003100000003000000062B
+:104B2000000000030000000300000002000000007D
+:104B30000000000200000000000000060000000469
+:104B4000000000020000000200000001000000045C
+:104B500000000001000000020000004000000040D2
+:104B60000000000400000020000000020000001F00
+:104B70000000100000002080000031000000418093
+:104B8000000052000000628000007300000083807B
+:104B9000000094000000A4800000B5000000C58063
+:104BA0000000D6000000E6800000F700000107804A
+:104BB000000118000001288000013900000149802F
+:104BC00000015A0000016A8000017B0000018B8017
+:104BD00000019C000001AC800001BD000001CD80FF
+:104BE0000001DE000001EE8000000F000000000167
+:104BF00000000001000000010000000100000001B1
+:104C000000000001000000010000000100000001A0
+:104C10000000000100000001000000010000000190
+:104C20000000000100000001000000010000000180
+:104C30000000000100000001000000010000061457
+:104C400000000600000006040000FFFF0000FFFF58
+:104C50000000FFFF0000FFFF000000200000002018
+:104C600000000000000000000000002300000024FD
+:104C70000000002500000026000000270000002999
+:104C80000000002A0000002B0000002C00000001A2
+:104C90000000000107FFFFFF0000003F07FFFFFFCC
+:104CA0000000000F00007FF800007FF80000000007
+:104CB00000000001CCCC0201CCCCCCCCCCCC02018D
+:104CC000CCCCCCCCFFFFFFFFFFFFFFFF00000000BC
+:104CD00000010001001E0C07CCCCCCC1FFFFFFFF80
+:104CE000FFFFFFFF10000000000028AD7058103CCF
+:104CF000000000000000FF00000000000000FF00B6
+:104D0000000000000000000200001500000000018B
+:104D1000000000020000000300000000000000048A
+:104D2000000000010000000000000001000000047D
+:104D3000000000000000000100000003000000006F
+:104D4000000000010000000400000000000000015D
+:104D5000000000030000000000000001000000044B
+:104D6000000000000000000400000003000000003C
+:104D70000000000000003FFF000003FF000E0000E5
+:104D8000011600D60000FFFF000000000000FFFF3A
+:104D9000000000000000FFFF000000000000FFFF17
+:104DA000000000000000FFFF000000000000FFFF07
+:104DB0000000000000000000000000000000FFFFF5
+:104DC0000000000000720000012300F30000FFFF5C
+:104DD000000000000000FFFF000000000000FFFFD7
+:104DE000000000000000FFFF000000000000FFFFC7
+:104DF000000000000000FFFF0000000000000000B5
+:104E0000000000000000FFFF00000000BF5C000089
+:104E1000FFF51FEF0000FFFFF00003E000000000BF
+:104E20000000A0005554000055555555000055553B
+:104E3000F0000000555400005555555500005555DB
+:104E4000F0000000BF5C0000FFF51FEF0000FFFF57
+:104E5000F00003E0000000000000A0005554000036
+:104E60005555555500005555F000000055540000AB
+:104E70005555555500005555F00000000000000044
+:104E80001F8B080000000000000BFB51CFC0F00397
+:104E9000099F6347E56730A3F24FB2A0F2071AB744
+:104EA000313130F403F115209EC1845FED6A464C28
+:104EB000B1371208F654310606061108DB4064E0EB
+:104EC000FD368A698FFB9551F95D8A109A072A3E53
+:104ED000014DBE1B2AEF2007A1272A6337D7112ACD
+:104EE0000F00DCF1F0E360030000000000000000B0
+:104EF0001F8B080000000000000BED7D0B7855D5DE
+:104F000099E8DA67EFB3CFFB64279C242790D09D04
+:104F1000906080802721BC2CD69D10E4749AD60323
+:104F2000048D1AF5F0A846410D5CAC696B9B1D928F
+:104F30004004C4A01D9BAAED1CD0B1B4B5BDC11BDB
+:104F40002D9D713A41A58333EDBD94608B15F568B5
+:104F5000AD8F563B51EB407BA9DCFF5F8F73F6DED4
+:104F600079007E753ADFFD063FD9ACBD5EFFFAD70A
+:104F7000FF5EFFDAC7139C4AD44F107206FF5C42F3
+:104F8000C8363739205D4888DF1B3BBC5A873281E1
+:104F90003F8B08D98ACF22F83FE552C87C4202589D
+:104FA000867AB9D8F58A274CC81E1714F2E15D3409
+:104FB0008FB67707DB4852CF8E4BBCC635A4969090
+:104FC000D6A8AA6F9708592F93B6812A2C4F6F2025
+:104FD00073A0BDC4C69F877FE13872A3DE1921E4A8
+:104FE00083544F4CB68CE37CB62A846835F0243B5E
+:104FF0008FC86184CF3D92F612FAE74C1921ED2754
+:10500000AAE3CF8832053914791D815F40169C913F
+:10501000617C5295D339C1F8BFED38AC2915849C19
+:10502000EC88C59FA9185D2FD6B19E90D73C79B862
+:105030004E53BD72362117132F2E26B33E25AFB720
+:10504000201984FA4884E267FDBE6735A5320BD784
+:105050007A850C796A46C34F88C9F021FA1168072E
+:10506000F3AC4F035C96758DEED747E7CF8CAB1052
+:10507000DBBEED7125EBB1DEDF709B3919CAEB1F8A
+:105080005D4E287C007F62F604708BF91DF09F6DE9
+:10509000FEF71A7AB6121721C7DC7A4902F73D7E6D
+:1050A000410381FD5A2131FA12785EBEB487CE37B2
+:1050B0001E9E61BF750DF12C076343943EEE5C08A4
+:1050C000DB48BE407C144FCE7E67A38735A3E9E161
+:1050D000B2A68F811EBE82F480FB18CFA7742ED695
+:1050E000EFC4636B83FB15CF9C09E880F73FF77D26
+:1050F000E0FD46EFFF9631F79F8F2FE840CCF3910C
+:10510000E1E574404842C6F1B265932442C0F72AF3
+:105110004922BEBAF05511EB4F605F3D5AEC219425
+:1051200013F71395B657225E53A67226793FEDDF2B
+:10513000685F8F9BA48804EDDD05953949188F04BD
+:10514000991C72EECFB68EB6B862D9379077CD0380
+:10515000418A3836CF54929A84EB39BD445F111A94
+:105160009F0E86B15F55967E05DC4A31837BBF80FA
+:10517000BBD163CA7328DCFBC782DBAF2508F2C54D
+:10518000F0672F607073FC3BE75BE1FD1F7165AE5C
+:1051900015AFC420058494F0A9FBCA499F9C036500
+:1051A000C365E27E9457F51D44912CE4EADD15F3C6
+:1051B0009F7243B9484D1E443864397610EB4A3625
+:1051C0000F109CB797E361A95CEC7B159EBB1BCAD3
+:1051D00072D6C0F30D228DC957F777C0DADC84ECA4
+:1051E000ECF0D2E7C91719FCE3E1EB810E3D8EED3F
+:1051F00032E556259E82F60F6CD8BBFB52C05B4F42
+:10520000A4BC06F998B44A0AAE2B20B1753D8FF3C1
+:1052100003BCF7DFF8050A27E0F17984C71D49319F
+:105220007A2509C2E80AE0B1E0A3DC300D2D98C56B
+:10523000C734C09B0BF44F5E1F890D118A875771CD
+:105240009C227DC0F0005E26C5635B409564F00043
+:105250005AE5D3E500D73DCF56D46C2759B82B2457
+:10526000974D1E1325569918834EC43EF5039EAAEA
+:105270002AB09C9610CEEDBC2CDA3D4C92EF63BB6D
+:10528000A9493FA5EFA9ED3137AEEBA8C4E80B144F
+:105290002A417AE9E6EBEA5FE3A774D65DA2ED91D5
+:1052A0004B09F9108907E9EA41C9C9DF1F323A61A0
+:1052B000F8513486AF76292949F05EA9324DA48F82
+:1052C0006892BDEF729156BA6E931CC171A2121B07
+:1052D00047D075B85CDFBB1DE69B24317A882EDE93
+:1052E000BAD105789D1455287EA3E9D58D281F7C59
+:1052F000273EFD163EE13DB50BA62607104252D2D1
+:1053000068D6E17C93369BC81924DA983EB2049E95
+:10531000B74AC949088F5FEBEBF4D0C96212E2F3D8
+:105320001EB7493458BF77719F9108E2FE5F4A5615
+:105330005BF442B9C4D6ADE8C4485565F7FF9B326B
+:1053400083BBCF38EABB2188EDFC14DE72D240E982
+:10535000611AB08D0474E0453A60FC300DE70F6CC3
+:10536000EE9324844F8FB9105EA0FF42A4B77BDC7C
+:105370007A11F6BBE746B539C5F0730CE933ECE2B8
+:10538000B8D1E13FC43B2FBF0D9208E70B237E103D
+:105390001F301F4C4AE4B903432EC0636E2389219A
+:1053A0005AC388AF39597C29B503CF4E87FABCCD93
+:1053B0002466E0BE340E99B814A57CC040BAF4C788
+:1053C000637548A780AF4512AC3B4CFA24DC7F459F
+:1053D00033295F3CA0B4BDFC15E8FFC0613966EA23
+:1053E00016FA24409FB3B3782BDE007C68B51B38D7
+:1053F0009DFAB99CE823C9A538BEA73849E9624798
+:105400003EC89570B6BF82F21AF150D944DBABD1D9
+:1054100081E36B505E47A2D5947F15CD85F8D9E125
+:1054200065FB90E5872D74BF7A3B52E4D76EE45F4D
+:1054300036BE574FB067BBACBF86F2AD92C1DD5BE5
+:10544000B52287E07BEF0041FC07FAF653FCC198D8
+:10545000B1BFD719DC4DB02E0F50D710E8A3EFC164
+:10546000F34C29BE4FD179DC513F7D2FD6E96D57E2
+:10547000D9F82442E5CB64CE27256448C2FD215CDF
+:105480009E4EE1DB3AB5784422A0C7F484560FE083
+:1054900092B2E6D853F8FC66EE23457BE8FC0DDAC1
+:1054A000EB30BE644C92CECC1A5FEEA1E27D5DC0C3
+:1054B0002167F11D5DA7BC9AB6EC43B811CA1678F6
+:1054C000FD55F67A90B2D97269761C318F26F49028
+:1054D0001E8B21FF6C77A79A498C900EE9692302F5
+:1054E000FBB4DD973A4E3490B3BD3F31E2D0CE3FAE
+:1054F000959023C837CA8097C0F31B48FC2847748F
+:105500009DCA9B309F6BC742170903BFE41429292A
+:1055100002F31E4CCB44857DD81555529E528E44C5
+:1055200094D7BCBD186757FA5E2FEEDF9D55EF6923
+:10553000F8CC8C1F65ED7D9C3E4E56B808EEAB183E
+:10554000FF648580AB8FF6F7A68127A03E00F3A508
+:1055500090DE499FB70EE5D162302CB1BCD01CA2C1
+:10556000AC674498FD7016790CB60BD5C74AA549AF
+:10557000E52D943BA9FDD2374A7E3E8272C103F2EB
+:1055800013E943C84F31CFF8FB6D0AFD5CA900DE7B
+:105590006E27FE18DA0375527200C76B6F6A27A870
+:1055A000874FAE6A36F0D90E2352BA5EE84AFD7DC7
+:1055B00029A743E8B72B5198C27ECAA4E27C9C7706
+:1055C000D742268FC69B77478759516ED12B3B60B8
+:1055D0005F916F7654D578C7EA17886EAD289F041F
+:1055E000E3C6F5426D0C7BFBECE3AEB08DFB59924C
+:1055F000FCA9943F7A7C42185DBB408F23FDFB835E
+:105600009B09F2959F58E8BD34DB2ECB27F672FF3D
+:10561000EAEBA3888748A1512D011DD702DB274063
+:10562000354602C67EA4F3195B72EA82B02F118F51
+:10563000B1D105F5CB5C23C64E2C836F8BCCFEC954
+:105640002D7F229D006F0478955C04FBB1655AA7FD
+:105650001964F84779B6BDE348D16B6E944FC7E93A
+:10566000F34DAE5F7EC7E9D60FE449E55025B4B3EC
+:10567000F2A562D2F73E1DFA59EDF02819427A528E
+:10568000383D819E1941B95AD40C76978EF464B78F
+:10569000BB9C78FF03D7B3FDA19BE8BA3374522BB0
+:1056A000E8E48877B985CEEFAA3D3FFAD8A9A4BD32
+:1056B000A85F77055FED9D06F466C65CB10A80AB16
+:1056C0000BCB308F3CBBBCDAEA770FB9EB55976553
+:1056D0007F8355309E050F779D271D65E68FD8E7A0
+:1056E000EF898C3B7F818BFA0DA062517EB0A9C9F6
+:1056F000D6A2FB281D3AE111FDAE9592092BDCBE26
+:105700007283E2FD547ADA84F66A2FD083D55EFD87
+:1057100080D301EE77AC0AF71BEA2DFBAD7039118F
+:1057200059D942E1519ABC54CE9016C2EC594E0759
+:105730008AD626ECD81A5C8FD38EFD00891BDEF743
+:10574000BB93D136787F572EE8980BE1E9369B134F
+:10575000B45D3ABAC2A2CF37BB987D9CE9B708F8CE
+:1057600004C6FF21495E82EB2655D120CE2FE8D01A
+:10577000A70D98487FA2FD564E5FFE4A83C9390E99
+:10578000F7E75C5C5E8F03FFB8EB6DB6FB37A2BD3D
+:1057900058E71E57E203C962978E967F691B5D9F8B
+:1057A000AFDC733E831249207F75056BB43516FA62
+:1057B0005CED62FCF565B7B11AF1E4A49FF3958B3B
+:1057C000E3CDDB13B1CFDB969DB76DAC79C142D38E
+:1057D000683C82CB3D25113603A8AF123BDF457DE7
+:1057E0000576727C2DE255D84BDCDE12FAFA6F5743
+:1057F0005D4AF9C7F79C4C907F886298549F001DC2
+:10580000517DD22719CCBF31A8FDE447FB898626FC
+:1058100098FDB448EC7BB9C57E2AC3F998FD64D6DF
+:10582000A30C82E74BBE5417B46FF786E710F03B2A
+:105830004FFAD8F37679202E01DC275D0309A40FF7
+:105840001117F47B13061B8DD1C3398CD37B2EE348
+:1058500038FB39C785760B987FD876213E7794B38D
+:10586000F1FCDE363A8AA438EC4F8E4F61237BBDC3
+:10587000A6B714E5D13199A05D2DF7550FE1F819C0
+:105880003BB498CD077EC8C3DB85FD09F42F73F9BF
+:10589000E4AF72D9EC5077B19FE23BB3DFCDA68481
+:1058A000F3DD26E6E3785682A0D4AAD83EA13D03D4
+:1058B00096361D07CDBC33D45EFD329D47F453822E
+:1058C00064C817A6FA9E58E3670AF68336A84E986E
+:1058D0009EB5F71B8F7E47CDD76487F39CFB0515DC
+:1058E000FD754B5C68FC7E763B79188DBA79A3F721
+:1058F00077792EC8990B47EF33D81F27509E1E7318
+:10590000B72D60C867FBED417B4CC627B39FA91D2F
+:1059100002ED6F5582BD128CE70B0E527BC4A7DBE4
+:10592000EDED5BF11F28972A09954B814A7BBDD38A
+:105930003EF977CED7A0A9646A3F134A23C097C126
+:10594000212A17172A6FA72DFC24D6BD290A7437E0
+:10595000697CBCB8C0430A7AD1FE67FC29F1B280E9
+:10596000E3BD3E298E71824DE002B4D758C755E998
+:10597000B84E79325ADEB6BDB987DAF305318C7389
+:105980006CCF3D415E21E72F77772A26D5E7BDC151
+:105990002DDE329B3D01E5B1F5B9264F604F9CAF3E
+:1059A000FCCDCC1FB1CFDF1319777E1DE7DFC6E337
+:1059B0002CA3E4B016A47A6C328F43D5C84CCF82A6
+:1059C000BFD849989D9EF05AFDC5E69183E81F9681
+:1059D0004CFE45D1219827877453FF10C8B8F6CCE8
+:1059E000DC73A77B8F8BC5434982FBA97CFECC7CF3
+:1059F0003C2ED320337A0378F6AF817F3EB8202D3A
+:105A0000E16460EEBADC005F6993BE85FAAB93593E
+:105A1000DCEFA3FAAB197AD105BD9836FDDCAB7F7C
+:105A20003CFA79959CD193ABE431F464EFC7A49F21
+:105A3000D7F17D8679D7C9F3CEAE9FBFBE324CE594
+:105A400044E88444FD61B3DE90DC487F53490C6335
+:105A5000DAE0F7DD8AF0BB9BCC652896424ADB276B
+:105A6000D08E0B215E6BC9FF0F7EDF0EC493737C5B
+:105A7000A7DF2787BE46F592EF3CFDBEC824F0F7AE
+:105A8000624876D7D4FFD4E2EF7D4B8ED5337F8F3B
+:105A900050FF6E8F9CDC82FE5C648AB11FDB9777BF
+:105AA0005F5B8F718FC83456FF6585D5FF1814353D
+:105AB0008D1B7ADB0C94FBFDABBF5049E3EE51929A
+:105AC000962CFE9AA7393984FC037EDBB7717D01E1
+:105AD000ADEF20B29E1A8D49D87EA91CA4FAE7BD6D
+:105AE0006292F248E3E3F16E1E1FC7B82F9E3BDCC3
+:105AF000D3A1D1726F47943E3D8BD9B9C6CE0E83E8
+:105B0000961F268941A4174F318B03F7F373862E16
+:105B100095B4E2F328F7177585F147F6C9E2D24F3D
+:105B2000BFF8EDFE350857D01F43D48C07575F47A9
+:105B30006505C2D3DF11ABA0717C6948C7F8D0B34B
+:105B40005DAF767A313E240F44B1BCB5FB8DCE06F5
+:105B5000C063D0C5E27EB23EA742B1E8AB7FE3FCB2
+:105B6000A2556EA5F6A96640FD5CEC4FDAC6F26B55
+:105B70007FCEF91ADAD3F35A4D63ED777039EC6CB6
+:105B80007F9CB7DF7EF059A203D30493A684788963
+:105B9000B6CFA7FDB61F7C8BE8B3314E9B3614E021
+:105BA000C3BEA524B617D69DDB5E45E1DC7EF07949
+:105BB0005206FDD21CCED0BA3EBA7F45EDB5B4FF39
+:105BC0003D3E726582C78FD9F98DBE773B95B9FA94
+:105BD00095B8BF6E6D7A1996DFE6FD7D712069B0CC
+:105BE0003FC00B75C68BDEC67D53CA4DBA2E112F32
+:105BF000BA5B62E39A37821D01FF9EAC070D340E3B
+:105C0000269717D463FC7772E54C7ACE3AB931B84F
+:105C10009ABED70BD6B267E5E7F1BDB0FFC24A29FD
+:105C20009D7FB27ED10D58DF3D337E184DA06C1C98
+:105C30002F4DE37844D7A9FD1AE2326B576D590E08
+:105C400099407E500D25E41BE53F3FDA3C96729E5D
+:105C5000A33CD9D1BECC513FD3515F632BB7733C2A
+:105C600093852AC507492B14DEBB783C90B4B95DF7
+:105C700088D7908F950F86EFF7BE52C59EAF5AD644
+:105C80007127AE6B02F955CAF97CB266591FFEE561
+:105C9000F567CB65146F51B413AD72C1802EBB167E
+:105CA00065E48269F59F2D7261A692FFD1E582902D
+:105CB00007BD281FC6D0530F93E47C05E3F0954C35
+:105CC0003E64E541AC15E55F8B32A75E5944E501C2
+:105CD0008D671132678B81E7252E565EAC4CAB3752
+:105CE000AB501E5C509846BB88F397E0077C96C289
+:105CF000536D9F4BE5B59837143D624A115C8F5642
+:105D0000832811EF55E0376C27E26567DDB719F797
+:105D1000B17D8327EE9B900767DBB75D801730D698
+:105D200033E59C4ABFA1CFA1E72BD42ECAA92AA84C
+:105D3000D72DE711D72090B00F390B5D593AA47FCA
+:105D4000C3BE86C6DC5F629465F717F09383F829BB
+:105D5000187A9ECA17273C6AFB0C2A4714C0133EC8
+:105D600043515267042DF222A2ED41BFAFA0D95892
+:105D7000F41B3C978B4CA576E626859FCBA5ED7250
+:105D8000428C0BF26213D28F474B19CCC463F19053
+:105D900082211F0D3187817E7C306E78E11049C2EF
+:105DA000FB6074889E5BA91A58623AC2339FC22373
+:105DB000D6A57279E7F2B2F816D06D928CADCF3AD3
+:105DC0009531F49953CF08387FA830B9279E4BE519
+:105DD0002A8AAFB3D1B5C0ABBF928DEF6CB795EB4C
+:105DE0009D7BB93EEBED58C8CA4F7D83D2E5D7B94C
+:105DF0003EF315F711C4B74F8995A23E32BB97D732
+:105E00003700DDDFEB63FD447B31EEDF71BCFB8AE5
+:105E1000D93E39E77D88AF6312A72767FDA3BC5E33
+:105E20006954D9F940632F93E7C5EA2BF4DC4007A6
+:105E30003D877279C41E1783FD7C14F7D34DDA8633
+:105E40001E2ECDCA7FB1BE7B9F7A8B94CEC67D6D50
+:105E5000A3E798837C9EEC3A78FDC23459CDDBD51C
+:105E6000017C07F8FE0A7AF670BD7536BAFEB1A25B
+:105E7000D9E499A8FFD065FCB342FD5493E2776B57
+:105E80006243E2F3484FDE9D745D8A376C06D07939
+:105E90003D366A7D87916E607D442A45BA11714B0B
+:105EA00073BCF38EFFADD0F30E76CE7172153BF757
+:105EB00018ED4F30BBB7D761F79EAF5F71AE76EF8D
+:105EC000F9FA0D13D8BDBF55CEC1EEED5E7DDF9062
+:105ED000413E82DD7BA1F1AE0BED5E926276EF0575
+:105EE000C67E2C0723F7D6E3F95D64AE90FB8FD412
+:105EF000A3DC8F2C205435FF5FE5DBD4CEFDAA6AEE
+:105F00009C46F832F8AE74317D4B52DEE596F8F1DE
+:105F1000F6CA8FDDCF0FB927F0F3B7E37E7C94F993
+:105F2000CFDDCF2F71B373032A0F552EBABB73AFDA
+:105F30003FDBB9C11556B8D52893AB4A53024FF889
+:105F400047F187136E77218B8B77E75EAED17E0E9C
+:105F5000FEBAD8CDF9D6111FFF4B8D3F46DCFDB4FC
+:105F60006289BB9F46C590FFF1AF47F51874DECC40
+:105F70007CE7796E007287F6779E93FCB5E212ADEE
+:105F8000EE4C7CA0D53D467CE0E38A4BDCEECEC4F3
+:105F9000436E779FC3B941B03496A07676918B203B
+:105FA0007E645FF2B00CFCB22D7ABD6E9666F3C2D1
+:105FB000C4F8FFD33D8D8EDF1D555D1817ED3EBC37
+:105FC000B410EDB4ADEEB6388ED395EBD2F6968E16
+:105FD00086F79B6EA66FE5F61D150F4F10E79279B9
+:105FE0009E5FB7F614852B501DC9C5FC95AE835F27
+:105FF0003C2CA31D152D28457BE71FDD3CBF0A90D7
+:10600000F86B4BBC741BD20FC21F242953C2F97604
+:10601000D1F9CE06DF9D7CBFE4F63B2B1E9E20CE41
+:10602000FA97864FE0B19FF385DCBE93CE2FF02A1E
+:10603000231FA07EA85286304FCA9DF6507B438E08
+:10604000B94C5A16F2A0CA45F32B810F7E84FB4E41
+:106050005EB3F3A9474B0C5179E6D6285CB2AF8DFD
+:10606000CA4791FF134C7653BD14486EB5D9F94217
+:106070006F07DC3CCF2AA8D03C2A95D345D01D3BE6
+:1060800082F412AC9B5E86F422A90C8FBD06AC0B89
+:10609000FCDF5EBE8E3E7E2E29E621A4FCEB2D9811
+:1060A0005F6594D1BCB9B739FEBD2448F9DC8B7863
+:1060B000988B791DBB874A74F45F4291D7F14CBE2F
+:1060C0008C9421DD6EAADBB40CED5BAF6E7AC6CA90
+:1060D000031EAD0F880FE197EB5CBE728CA75533A2
+:1060E0007D40A2B567C9D3E864FBC2F741E05FA970
+:1060F0005218FE319F1CE09579FEA0D8878CBD1EFA
+:1061000065F8CDE4BD9FB0CB2F39C8CF95887267B5
+:106110008B645DFF2E4A0762FDEFB979FEF15F697E
+:10612000FD693793CBE4E9195F6FC17343C315A3CE
+:1061300067EBE540DF163F391064F97C828E7C27DF
+:106140003AC95498C7AFFE75F72F033F780918BFB7
+:106150002B23E2CF46DB395719CF4F14FEB9FF0E80
+:1061600042E3B5A5552C7FB1AC6A0BCD67A4E777A8
+:106170008087923B147A5E0AF574DDA27F69AF6A6C
+:106180003BCF9BB4CE5E2E214C2F7E829FBBD1F79E
+:10619000304F09CFF32B2196F6A8B7E4961CAA2717
+:1061A0001DF2583C9DF9EA0B557BBEBAE83F1E9E96
+:1061B000449EFA2E627C4A9D97A5DBAE3296073547
+:1061C0001AAF4C2E14E8A681FB528879B3180F58E9
+:1061D000CCF266F34892C607C84276FE896E8C35CB
+:1061E000CFFAB32AD3535EF2079A6FA992B449E566
+:1061F00091633FC43EF456B23809EE5F11D4E7F222
+:10620000DDEBC5BF601E7F11C853C0532EC73F6969
+:10621000E0F893888474195EACDACE53558EFF3C57
+:106220001EA7F03BF0ADF27D501DEFDBB87C3B1BB1
+:106230003E9DFB7193A0FF100959F7836863E789BE
+:1062400089FDC8F84DE7395FBB982F08F34DFB086F
+:10625000F339F6E152BE0F5B75B10FA411F7818AD5
+:1062600072E443928CA3FECBD3193F4CE279ABA4EA
+:1062700091E1DD0BFFE13E1436DBF701CD6DB4D3C8
+:10628000BC0E3E180FFF32A7FF25AA712FA5D3D74A
+:106290007C34BEE4CDD0CB93075580737B318961CC
+:1062A0001E2CC1BF30BEF7610EA5931D3192DA02DC
+:1062B000E34C2EBB87C541D105B3F4DFAEAF9830B8
+:1062C0000EDAD781171D08B9ABC34B862E18BF5DF8
+:1062D000484D26315EAC195A1DC69B27C5F51A9A42
+:1062E00067418E188827D5D0A9DEFBB92ACE8389CD
+:1062F000EDDC5C8D33FDEE6D644FD55057233EBD14
+:106300008D0AD52F6A55FD5B0ABED79DF824E77527
+:10631000FE4EDBC8E3B73BD7E7DD8097572D7950BA
+:1063200077A24F0AFBF0818E172E00EE5AF03A71D9
+:106330003DB55A015D476D2C489FE9BA382B27B609
+:1063400063FD88AA33B9D0C0E46958774DB83EFAE6
+:1063500047F86B6559BC08389CF4F3D7C2CF5D8809
+:106360009F0AEBF87D5EB49BF28EC94073E3F7CBD6
+:106370003BA590213CBFF00E0D21DD405B6A977B71
+:106380001783DC42BF54497DE37AB4A3A25AB569AE
+:1063900059CF9F55666FAB98F78E7CAFE8D2CA9005
+:1063A000B55EA578063E3AADD278DDA3DE341D6F2A
+:1063B00080DAC9C12A1741FB74C7E97FF652BBAD29
+:1063C0005565E304BF66931F0FA86E5B7E71467E22
+:1063D0004449DA65F1A385FC2F5293418F25BF51C3
+:1063E0008DB2FC46112F147168271EB676B0782145
+:1063F000F05F45394C7980C7C39FE0E7645AD46F9A
+:10640000201D69514D473AD2A27A392BC7CAB1FC37
+:10641000033C4783F67B3B74DAFE9E8E4A5ADED5F8
+:1064200011E3F75316F2F337839FBBC5E933D591D8
+:10643000A0CF6F7534D3E7831D49FABCBFA395B0D5
+:1064400073B1365A7EB4A39D3EBFDB61D2F7FB3AEF
+:106450007AE9F3918E3E765ED7D14F9F831D29FA5C
+:106460007CAC631FAD1FE818E0F0C7E312C2CBE3BA
+:1064700087B906ACD31AA75EE7A371738DD3ED334A
+:106480002F7AE420ECD36E2EE7761B13CBAD456953
+:106490007B7ED182E3F6FCA20B0FE4D9CAD37A2724
+:1064A000DBED977899AD3E67E14C5B7D2856632B19
+:1064B000072A2FB2B5F7E9F5B672A9F937B6F69FF4
+:1064C000685F61B78FDAAEB2B59FD2BAC6565F9435
+:1064D000BCC9563F7B6093AD3C6BDF976CEDB7D684
+:1064E000AC6D23D584B4787ED0E52D01BA0B24752C
+:1064F0003422A20FFC43179E5B6A51901EE0AFE46A
+:10650000464939E60FB90D66F7B81B4C6ADF43FD03
+:106510004C7C0FF555D80EEA5F413F00EADFE5F508
+:10652000D3793DCD3F52B03FFA090DEC9C4FC543A6
+:1065300056E0D3EE30E81FF44B4F303F2213AF3814
+:106540003D2A8EBAD1837190283B2F15FE1BC0DDEA
+:106550009618C30EB8D3C3F58857A1E308FB287378
+:106560008EA6B373451253A8FF91CBF343447F6FBC
+:1065700003CB0B03AEFA0FCC5FC2EB3067A0CD8C20
+:10658000142B0B3C5ED06F2F57F4D9CBF38ED8CBA6
+:10659000730FDBCB2A3F1F76C2FF3D0EFFF68E81C5
+:1065A00039AF55B0B80D9E6FC06ED0B88D1FF6478D
+:1065B000A3C952ECFE8597E3C90FFC8EE73CA49675
+:1065C000DD07D332EFF5E9D8DE6BC0BAE6603956A5
+:1065D0004EDB713BC87762D96189AE97E54B062ADD
+:1065E000615E0BBD78CBED70072AED65A7BDF58820
+:1065F000E7A3D9DBE3D963A3E4E9E933345F4CDCF7
+:106600009FB88F9F17146DEE3B88F1F4A2751ABDE9
+:1066100017E79EED4AA07FBEB5CA15DF8376359495
+:10662000F159B421D5897651D181D2C7D00EF9D490
+:10663000A9A13AA48BA236AD1AE317D3BD3ABFFF86
+:10664000992CC2F858D181DD523D8C33CDCBE20577
+:10665000458DEC3CBCEB71765EF3CC8B57686918CA
+:10666000F7BD4839953BEF3CE131308EF14E1EBB12
+:106670001FF6CE130B7E827CF0BB8EC379D673CB14
+:10668000777EF0F3F96E18FF9DC77E3E5FA1F98A11
+:1066900029AAA744FDCD6786E7237D9BF5A412F3C5
+:1066A0009A6FD55482E3DEEA65FC43D6313ABEAF39
+:1066B00040DD8AE31714BA76E1B309832EF9D93C99
+:1066C00040C2E9BEE05FDDF49CBEEB593F1DA79DD3
+:1066D000C75F88C6CE953755E85D41286F2AD562D9
+:1066E0008069D2956B7AA662BCF8454FECEFA1BCED
+:1066F000E9D3E0A2637D9146EF4B754BDA122C9BF8
+:1067000025CCAF39594A2A4B411E284B0C3904F38A
+:106710008DCC607905C27F0DA7470C24BB1D4AAA0A
+:106720000BEFC77419848EB34319781ACB3B1A58F0
+:10673000F97657DBEE166A5727FBF0DECAC9F9AEC9
+:106740006AB40FAFF395897BB09EA9F0FEF6050AF7
+:106750007D2FCE119E7ED143D7B3E96732F55343E7
+:106760006E62066A28BD5C628D3304F0460A383BCF
+:106770005FEBA8A470794A5DA61BE0CE8F30BF36D0
+:106780003FCAEEE7879AC04EB1CA71F8FF552FDFB6
+:106790001F4BDCEC00D7C3431D5E3ADEFD1D1A7DA6
+:1067A000FEB8234ADFDFD3A1D3E7931DB109E398F5
+:1067B000E33D7738ECA5FB66C32A00DEFBF8F9F46D
+:1067C000FB552EB3FCC2F1FB3FD87178524345967E
+:1067D0000E4ADAD8F9EBB8ED3BA5EB5600BD793699
+:1067E0002A89BDD42F481659F3E77BDCC92214AAA5
+:1067F000EF798E2F417D017C47F34B0CB2BB4EC32A
+:10680000F3D6752486B82A8AF64978CE02F83F7303
+:1068100046D83FC0983F2AFEC3D339483755640055
+:10682000C152AB0CBD13FB1D9916C338C8A292F21E
+:106830004EE463325BD4C7E41FA09F3078818E475B
+:10684000F5073DC9B95EA0EF0392EB3AE40F9CA7B0
+:106850001E9E5F7BEA8F2A9E47F7BCAA7A31DE56DE
+:10686000F4E42B2ACEDFE34AAB280C9BBC331BF0AD
+:10687000FCBF474DCEC07C80A6DEFDDD58BE2F9C00
+:10688000FC0E1396331B9E89029F78CC07B0FE73D3
+:106890005E62C617C33C6EF36A5C6F0399DEED9DC2
+:1068A0004AEBA760BED4A5305E6F31D4A32D4DCF87
+:1068B00095CABB0D2CE7B27293775AB709FD2FE347
+:1068C00072830493A5E8DF65CA1A94C7383FCFD412
+:1068D0002BAC9E78D953ACEFE6A7FFF89329809FA5
+:1068E0005B9E940630EE54F4E46E8A6794532897C6
+:1068F0000E741CD6BAC57E5BFC8145989781784E94
+:1069000049A932899AA0F43B034A5EBF84FBD1FABD
+:1069100079A2A3DC7CDCC7FCFA456918C722D7172B
+:1069200029EC5EBBF3DE3ABD828EFBB5939D2B1442
+:10693000AD4BAB18873FB0D00CCC81F7EB5797D756
+:1069400074C2BECEE0E3B6035B36A03E8BF8359A48
+:106950000FCEF322DE167E0CCF8BD8C02FACB8B78B
+:1069600010BACF3DBE81028CAB8C7CDF9D678D5B06
+:10697000F7E40E144863BCEF76C37BA433788F70C2
+:106980001DD0CCDC3C18E79603BBA79A80C75B48B8
+:10699000DFB55F42B87F2A13946F6F1D5C94F34993
+:1069A00028DF0C659F8EE7DE472E453C3F34583A82
+:1069B00080F270A797E9E55B0681AE82C8D740F305
+:1069C00020720E187DB314A087677C2F37F8C09E05
+:1069D000FA5199A1B98006D2BEB7BABD174359D5AD
+:1069E00066A0BD95F68D507A5BFF6917BF4C39F2F2
+:1069F0008C518E70105ADEE95DDC8DF927B5CD5EC5
+:106A00006A4F15B81271CCA327475D54BEA2E85B4C
+:106A10000CF89773BBE939DEBFF7B868BE1A1E637E
+:106A2000DE01EF6B15725881E77DE050E37740CCD3
+:106A3000AD0AED07EF7BDD79B84FB1A7515E935EEC
+:106A400042E5F9BC273D347FAAB6CDB891C689B4DA
+:106A5000C5D41E9A4A327F68FEEC27B8DC5CA09150
+:106A60003AF4272FF2B1BCAADAE6CBD763BF69AB01
+:106A70009BFECD80FA8552CAA4E74BCF337DD0531D
+:106A8000F0DD012F946B73140D6315833E63968EB6
+:106A9000FBF4737F35EED3606E4CA3FB1652F2F617
+:106AA00062FC3F0DFE3DE8A5278E6FF8DDC5787EC0
+:106AB000900F8A18E31CD0AE06F07D31CA11C49B3A
+:106AC000B9B9C14039A82637229FBED5BBB91BF33F
+:106AD000EF00EFD3BC80F737BD50867D18EC34A6AD
+:106AE0006896F2823F83DD40F97433E55325F79EC3
+:106AF000F5C8F750FF0CCA931FE511BE2FACBEB608
+:106B00004C9441B42D04383A059F13D30B7AA1D687
+:106B1000D2BE01F8DC5DCFEA0FC17C268DA301ADAA
+:106B2000E7E13AC1FEAD457DA8A4709DB8679877AE
+:106B30007EA9DCF299D9F0DE53C1FC167F2E93CFEB
+:106B4000FE5C9DC6EF067DEC9C7FE4B9600AF1E532
+:106B5000CF6DEBF3607D4939F5470329360E3E7161
+:106B6000FF033C5F5FD296537BD55769BF1FEB7124
+:106B7000DC8755B8BDA738DE7FABD4385802FDDBC3
+:106B8000D3CBA93C497B79FCAC84C5AB6F4F98CB88
+:106B9000D05F9D3932508FE645D5A9234FE1730E62
+:106BA00079B71EC568CC9BFB343E7FE765445BA389
+:106BB000552FC1A57D7271AA8B1EDBEBE92294676C
+:106BC000F36428C33C398B07649CA7F09AF2F33C2A
+:106BD000571FA279063B83AE788A9E3B3EA6ADB690
+:106BE000F4FF079FC82762F2058F7B908EDB495F19
+:106BF0001DDEC785BD67F751B8BC71734741212CB5
+:106C00009EA06831CD04795D17AAA5765E998FF1B3
+:106C1000BF7C70D1656897A82827A0FD833E16DF4A
+:106C20001D2922037B75F4530C42F51ECF2BDCCCBF
+:106C3000E715F2622BF8EBC60520673F37BD5EE42F
+:106C40002BD23CF3A161E90C28CE7B303F91C629C1
+:106C50004654B4271FFF5C413DDAEF3F8CBBD05D4B
+:106C600002B964FC720AF2F71137955BF7E632F964
+:106C700028D6FD1D1F3B6F3BED65F2B6C70DF555E0
+:106C8000F81D0F10DD30BF7A2A405273C14FE2F277
+:106C9000D8935C47E9CC03BA4FA774610A3F893C9B
+:106CA0008EF19562174959FD965361DAFFB497E169
+:106CB000579CBF8E9717F0A4D807C7792B1E442383
+:106CC000DE3767F685C59F7F546FFC925039E176B9
+:106CD0008D753E399FAF4F3D255138C4FB8B5068B1
+:106CE000E37B2549EF97AAA7145A2FD62BDA65EB39
+:106CF000D93A7EAFB1FB316A94F1AB7A40A6F61F68
+:106D0000892A23D6FB2701B4CFA765F94CDC8B1960
+:106D1000BD8ED811EEAF51393B9A0F4D6A076D0EFB
+:106D20001985A88F3CBABDDE99D79281FBD424DBAC
+:106D30003A047F65D75340EB519FA03CB84521DF13
+:106D400040BFEE669E6F70B30CF404F0EFF8C340E2
+:106D500002E7FFBDF0279E64DFB1B979700FCF7BEA
+:106D6000D06D71AC5B0E6CA471A93F68AD456847EE
+:106D70003471FFA8C03524B37B434764E4E79E70B9
+:106D8000A252D298BC54A228FF85BC9CD98DFAF29D
+:106D90003E352B3FD169BDCFCFCA5DBE99DDDDA8A1
+:106DA000DF73993C6DEA7DB2DB2C467D2FCA3FA490
+:106DB00076D47D6AEC698CFB994F7874D4E7D0DF88
+:106DC00040BE33AFAAA4FE4B4F19998C76DF330532
+:106DD000EC7B1F3D4F78F6A22B0DF6E2655E8B5FD4
+:106DE000F54EFEAFA692E098E399B6F1A69EDF7845
+:106DF00030FFA02B275BFF4CC145747CE8A763BF25
+:106E000077F2FD4338FE3B577A691CF841B79D6F16
+:106E1000C5F301CE975B3B34CAAF99FD473EC5F33E
+:106E20006DD2C6F8B398F1A7279A67E3CF2CBD4C73
+:106E30002129CBF97519D7DB597A994AEB4F635F52
+:106E4000CC6BEBD0CF71BEB271E69B7596F9E6D8EC
+:106E5000E643099BB9E736415CD979BFC629EFC43F
+:106E600053C8BB021F1B3F4892077C50BE293D7090
+:106E7000294DCF93B4FC4E68B286DBD78B1EEDEC68
+:106E800042F53DE44EFC07EA7FCC5B413AFFB23B62
+:106E90007101F613E55B5F0B9AB8AFB7A07D02F402
+:106EA000B0E3CD51F72B87A6E8593E1943AE31FC2C
+:106EB000717F1DE537961F3AE276754EE08739E51A
+:106EC000D64EAF53BE31F9F5979B4FB6EDDFE8F9DB
+:106ED000545A9FD54F4942C6D0739B8B8C4262E770
+:106EE0007703F91DD3F1B93D65A27CB857D49B5205
+:106EF0004F4331DAC9D97AB4B70A3CD9FE786FFC6E
+:106F00005EBF681FEC417B6B54FB80A37D99685F7B
+:106F100048DB3BE111F207CB68CF297FF664EC3DFB
+:106F2000846FB7CB315E9E18AF8C8E27ECF8F6DEFF
+:106F3000D9874C05E9B2AF0EF5F208F85118F77889
+:106F40004889F963167BA49DD3A77ACA67C37316D1
+:106F5000BF41FA9E44EDFBB9F9C5658513E57FBFD6
+:106F6000C1F5BA28DF90DC7C29B66FE7FAA1153CA1
+:106F7000011CBFF541D9C6B7FF0DEF7F1578678CAF
+:106F8000639F5431FEFE2F076FD138F016FFA7C262
+:106F9000BB546B3BE8067897EA12BD37B814EA7C1D
+:106FA000C0A3CBF08C1D9E4BC1900D62FC8FC755CA
+:106FB000B18CF18B651FBE7FEC1290DFFB78DEFE9B
+:106FC00005DFDC7CF4D330CE707CEE5C7EFF7FF698
+:106FD0004AB0FB1FF7B373C10BB87DEB84FB713F65
+:106FE000C3C7D1F8929B51BE7E9008D033F963AEEF
+:106FF000D8CF6A31EEB042A6F69FB3DFD10E766EDF
+:107000007E2F3A7CD0FF5842A6F2FA8378450AFBDD
+:107010008F872712976DDF17400FD37A2E4B5E2B89
+:107020007459CF738F12FDAE5AB4671AC786E3B78F
+:1070300008C70538FFCA09E3F36F7278DFC6737EAD
+:1070400078B6EE93699CF4A6047B3AE775F6BFC95F
+:107050009D2A9828BF73FD3ED9763E753678B6F8DE
+:10706000591CF8C694BDDFCD0301C7F938DBF7081A
+:107070008F73012666B2EF1AE86EB457579C60DF33
+:10708000197C0E5F15D17B84FFE487FD5E11AF662E
+:10709000DF9313DFB553405FC020EB76CDA0DF73E5
+:1070A000234D2B69FB437E69ECEF67F2738A7DFC0D
+:1070B000FB70852DA6DBFA1DB66040F8436D2508F0
+:1070C000C7A06ACCFA3E8C7FF4731E1A2FF7AC6C03
+:1070D000DC1102FA397665AE64BD8F98E6F436BFEE
+:1070E000857DBF6DF078D2EDB2F0E79F793DF4BFBA
+:1070F000263D06FE4EF0FACB93123F07374AACDF2F
+:107100006B5403F67A67FF77FC61BAAE63E3DC3B4E
+:107110007C93E3A3B979E2FEA46912FFCE9A31DD34
+:10712000FA9D3527FEBEE84FBEEB07787E29B5BD38
+:10713000781BF2539D97D23151F43908B7C003F050
+:107140007D2F7EBA52ECD36553AAE83E0978C47C01
+:1071500018FAC27849ADC1E26879FCFC63C14E5FA0
+:10716000AA93FA71FC3B9B0AC015A2F34B81FCF178
+:10717000E717E3461432A4C2B8EB5CA936B40B9D02
+:10718000EB10ED86FFB8E43308DFE05197B6A57445
+:10719000F4FA3374C3E5D2F47E3BDD9472BA89F01D
+:1071A0007B6144692B69B6ECDF9400FB9EEBF9D25E
+:1071B000D311B483A0DFF4AFB5B97518F70A85DF32
+:1071C0005783F1ADF4F12CC76724C0DA4764D33F8D
+:1071D00013EDCC5F32F9B26FEF974AC68ADF1CE538
+:1071E000F941FFEAAFB49D6FAD8C571F8AD422BD21
+:1071F000ED8E615C63F0E84525C877972B2CFE3255
+:10720000A89A37E1FE1CBDD6934BE366E7B88EC162
+:10721000E30937EA8FAA2646877B5C89A5F9280708
+:107220001F2317239CAF20AA2DF9779B38DDEF533E
+:10723000935DBE18E8871D7FD7D3EBA5FC4BEDBD52
+:107240001B763CD4837159D23D89F2FDF4A6773781
+:10725000E315D04195C5D39FBB3344CFB1810E6DAB
+:10726000FA26D274B203E3A36B5DFAF5CC4F6672D3
+:10727000E76192FC4C605E56FE8C9237DD2BC57741
+:1072800032A78FF53D55F15D404127FB522B72D659
+:107290005AE8A42BA0DAF0FC0B2EE787B9FC16EF16
+:1072A0009B8EB37C1858078DFFFCEAE2923DB88EA6
+:1072B00048EBC90E6D0E8EC3E22C1FA4CA9EA01F00
+:1072C000A4E4EB17EB84754DFF2EB4BFA2D92E8733
+:1072D000051FAD6A0CD8DFF3FE95B2B19EFA279F69
+:1072E000617EB7182F12077CCDC17525B6844AB3CD
+:1072F0007816F85CE3013C4E23EC821EC05B797784
+:1073000011BDFF94DF95BE0DFDC13F041339791601
+:10731000FAFB2ADFD72C1D323D86ED501FAD50748D
+:10732000F7587A69655C1E13EEB5E1641B19C34F0B
+:10733000CDF0B9430F6AAE3E37B66F266DF4791DB6
+:10734000312EC6E709BE1F19B94C86420B50BEC488
+:10735000651A8F3CD1B632670DACA3C53D10AA812A
+:10736000677F80F1DD0B9B651AE714FAD839DF35AA
+:107370001B64F30AA0B79614D3CB2D1B581CEB9AB1
+:1073800036FB7A86813C16E6219EDB8E7E1AE7FD6F
+:10739000AACCBF0FC9EC85975379D5988745BF27ED
+:1073A000837CB322C0EF4111FABDD024FB27793E84
+:1073B000BEF610C681BF1F607EFE707CEDA5E87A28
+:1073C000DFD04F7E9CD6D12E9A588F27EF906DFA42
+:1073D0007AFAD7ECDF9F9C8F7A04F94E192AB9D636
+:1073E000222703E100C5C7E54DACDE39AE3F1CA442
+:1073F000F5C31FCAAD63D96D7A98E17355FFD8FD07
+:10740000F57088D53F38B61EBB3114E07A62A0040F
+:10741000E5F7AAE6B1C7D91E0CD376276E7EE31A2C
+:107420008C7F1D73D9EF897E25C8E0B82EC8F86C13
+:1074300078EF97B616E17EDC226998CFBD66923E62
+:107440001DE9E5EA0DD5340EDF1C64F4BCD19F18AC
+:1074500046F971C383ABB7E2F941E111978676EB48
+:107460003EC73D54F17CC1A137405FBD86FA2A82F8
+:10747000DFDBA6DF394FC5AE644B3673F270DF99A0
+:10748000DC35F7FA35DCF7E1466E9F9AB36DF6E925
+:107490001B0EFE72EEE70DFD0E7BCC41AF2F931855
+:1074A000B59BCDC68046EF239D7EFF670BD00EBFF8
+:1074B0007E52CC9A0728ECD46195D9D5C3BF9846A3
+:1074C000F313C6A3AB71EDD54699E68FFEA5EDD5B6
+:1074D000E14646E72FDF3137B4668C7EB9C1D273FF
+:1074E000B2575FBE63627E7999E3E175BE2E414F6C
+:1074F000682FAFB1ECFBE4A07D5F9AD7D9E7BDBCA4
+:10750000C53EAFE09363892E3FDA1B84C4A8FD23F8
+:10751000EC57D23D77CCEF8267E55F27F363383CC9
+:10752000C8F76BAA98B8403CAF44D901FB398BD35C
+:10753000FBD1F8DC10D2B3733DC3AE11BAFFE6B78E
+:10754000D8B96545FFEAA78AF4D1F4B7C0B1BE8FB8
+:107550004A7F42AE3BC7C9D05BE347F48B3E663AF5
+:107560001B7F1F52E74467420E5CAD0CB8175531C4
+:10757000F972233C8F6042553E3E75FABC9A9F8358
+:10758000C1E6CDC7FBAFC37BFDF43EBDB93D94AAB8
+:1075900000923EB662D6742B3CB7F17DB9BA7FF942
+:1075A00021CC0938E64AECA276D717D8F9FA8BC76E
+:1075B0001FEBC1F26F405E493AD2DB5A5AFEE0B887
+:1075C0004E7FAF625390F9C3AB9A56BBADE33AE935
+:1075D0007795837E4F707833F69732528B7259AC21
+:1075E00013E56411CCB36AC3EE4538CF0DFD07DD5A
+:1075F00033E0FD3AFC2818CCF7F920EBDFC2ED4E62
+:10760000E285F502FDBF80748BEBFDA2C4F49F926E
+:10761000765BEF4B5EDBF6C6D2B1E4FA439CCE77E5
+:1076200071B9BED19F2C0EE667E56B6153E97CB45E
+:107630006B8A91B72C70977038544FEC1166E7B095
+:107640007564F0780BC3E30BC757F4E4D78E8FC78C
+:1076500007C6E18FB3E1F1D85E3FF59FCC4FB1FD96
+:10766000CDDAB725F49E8080B318E1E4F62DDA89EF
+:10767000820E5ED8F8C63549E68F75337F6CA41646
+:10768000F1F5C39038872D7459EF51FC3A34F677F1
+:107690005C7FC5F9EF6CFC73D54DCF527FE1573756
+:1076A000FD5B099EFB8A7EE3F1C7553C8EB36F9369
+:1076B000A775EF18F39EE4781B252788DDEEB9A1A6
+:1076C00069F5D610A0604B20FC295CEFB8F65C137E
+:1076D000F38BB2F65C2A84790C47397DFC0AEDB94C
+:1076E000AA09ECB956B0E7E658ECB95699DE7770BE
+:1076F000DA73CF91C467E7D566E33CCFAF63F1A8F7
+:10770000971B67B9505E3ED7742FD54BBFE5EB1B77
+:10771000E672FDB926BBDE7825688F678C92A78E4E
+:107720003CE9F1F4CF6FCF53FF80BD5F8272F0B9B7
+:107730003D2DD7DC86F4B7C74FEFB339F7E7D990C3
+:10774000CCED243FF557841C1A5463EF0C46904E41
+:107750008B625BF4D1F439DCC8F4DABE158156B41F
+:10776000E7F6F1FEAFD657EE45FCA0FF84F0A74345
+:10777000DCBF15FE35D75F57531198DD27A1AFD475
+:1077800010931F37F4BFE2D6A1FFB5C26FC63F000A
+:107790008FB67D0ACDB37BC1C5E5C823219A1F25CD
+:1077A000E613EBD24276BC3BE5F7D9F4D8F3299641
+:1077B000FF20E6BDFEC15216A7E2E596CDAC2CF443
+:1077C000DABE948BE9D3F61CBA7EA097D98F43F921
+:1077D000F5F659346FF69CF55CCAF5B1E839C4CFBB
+:1077E000447AEEB3E81CE69F5DCFBD4E489CEEC7E1
+:1077F000E9B5BB16C1FA5EFAD2247ACFE8F57E4627
+:10780000AF9FE2787F494DCFB6C2F73AC7D309BEE2
+:10781000DED733F84D86ADDF8198C7E5DA4B9C0F94
+:107820005E6AB7F3C16742763EB8A1DF0EEF356DF1
+:1078300076789B43EC5CF2A5F62E3FCA9563826E88
+:10784000AE97A9FE399658129A17A1FE78CCBA4F76
+:10785000CD0EFA391BBF5D25817D8FFEF71E3FB52A
+:10786000BB33F1D137D93E7EE065F45E16768DA943
+:107870004732F2F94DFBBEA33D61C5E3939C0F4532
+:10788000F9EA56875F3D62EF3FEC627C6C6E0F5009
+:10789000FB4F53199C1AF82126A3E7F9A80F33F3DD
+:1078A0003BFA5FA5A46CF377723A196FFEB3D95314
+:1078B000FFEDCF8CEDCF7C2FF49FEBCF0C86CE4F1E
+:1078C0009F3CCEED41A75F93D11BDCBE11F6CC9A55
+:1078D0001CFDF54198E2389FE7FAFEE5D4FE1C76E0
+:1078E000257A308FDD3CEAA279AAC38D6BBBB0FC50
+:1078F000417FA9EDF7D58A1DFA4EE89FB3E94F27DE
+:10790000FF3CB76A5B0DCEFBDCAA2B6CF6EFE5A75C
+:10791000A69021CB79A6883764F8D567DFF7912048
+:107920008BFF8D707B32D3EFD4543A4EC62EEE5F70
+:107930004DE30D2D4DBB174996F53C19627EC03FB6
+:1079400085D83A3276B1C2ECE2F1E26D6F3BE4D019
+:10795000737C7F45BC6D95921833DE767993EC90FD
+:107960004FCC4E73CA23D1FE74C82E97C43C4E7CB4
+:107970009EEB7C25412677457C8FBC6DB753C7A312
+:10798000DFCCBC8EF6CE79FFC4F138DEFC07319E29
+:107990003E6FFC78550D8F57CDE7F1AAE1CF7DF210
+:1079A0006718A73BB6E2E9C548872FDFF1FE73579A
+:1079B00044508F1F5A8CE0D7F0F8D5CB98D286F47C
+:1079C0009E94A85D7845FF6AEA97417B26978E4D85
+:1079D000A3F77063616E17AA319B1E74F2E7F73943
+:1079E0009C4F05787E3A19A0E757E78AAF5F8D83F1
+:1079F000AFF3D51BDF17F39F9E3B1BF5C1FE80C67F
+:107A0000CFD386583C6E09FB4EF5A09AB88DE6CFD1
+:107A1000AE0A697B59FC92DA732B08A3A74145DFB4
+:107A20003113EA0713D30C13CAA57FB39CB65FD1F9
+:107A300014D030756939F65904FB551F3471BCDA1E
+:107A4000E1C6EFE1F9C36F9A3D3ADE137A26B156EB
+:107A5000C6F8DBB146895EAD5E7549E21DCCF75ACA
+:107A6000754540C7387A5EBC94DA85DFC5F92C7954
+:107A70006FC732E535DB1AA07E66FEA00B49F09990
+:107A8000F09A6D5E18B7A73311C5BCE5B6F0826DEC
+:107A900098B75C50601CB92406DE7D78D1329AD745
+:107AA0007CBFE87FD136CC53FE4757B214EF233C5E
+:107AB0001FBE72995284F74B1BAA31FFFC855DDF14
+:107AC000A6FD2FBFFCE6CF3F0EF5A7C35F5D86394D
+:107AD00038F35B44FFAE654BCA0959B95894B7797E
+:107AE000B01C0924745735C8C1F0DC650ACE97670D
+:107AF0006CC4FCF5829CB974BC8549C2F264CCBBF1
+:107B0000687F31DEBAF0DC6D980753D4BE84FC1A6E
+:107B1000E4CCC234FBEEE82FEADA96607EFCDFDCD0
+:107B20007DF7B62A90550BE27501CCDB5E7EF7231C
+:107B3000CB3CD5F4BCAA5A87E7CABBBF43C79FDF7B
+:107B400062CEC47A957C7F5BBC1AE1E2E772C5B174
+:107B5000E9B6DFC3AB6471AA4C39CACA835BC6CE2F
+:107B60000FFB750E931B83FEB1EBEF0FDBCF57734B
+:107B70008E13E3D12A3CE725835ED0139779482DF5
+:107B8000C6CDBB30BE3CCF32AF97C125FA11F3B2A0
+:107B90003CA4EF461E33C77A3CC7E9E77C3C2DC6C0
+:107BA000F8385F6676F848B5F410D267BE2C5DB73A
+:107BB0001CDE17F849723FD64F22B4DC4888B13F2B
+:107BC000981DF7A77CD8A5D3120F23BD2E2D2CAA64
+:107BD000C6EFB9C378745D006FB7D7720E05702B0E
+:107BE0000877BEBCA27A639505EE2A06F7601EC32D
+:107BF000C7E09F589C6DF068D95EA4DF1561BBFE9D
+:107C0000987FA4869EABE52F21F477E146EEF2D172
+:107C10007C76E24DC6ACF758BEC3F1B8C19187B3CC
+:107C200041195291CF37F03C9CFCAEB1F741C413DF
+:107C3000379CCA25E65CEB7BB69EEC38115A0FF0F8
+:107C4000B03CF971E0F9C70C3CF63C9BEC382CCF0A
+:107C5000E6E3862793A7272EA4F27145DEB3C80773
+:107C60001E4F7E6E70E43B67E76579CEA59F107965
+:107C700079432AFB9E03836F547EDEFE3A9A8F93EC
+:107C80003DEFE674A0B2F5E33E5BF30A7ECBE97606
+:107C9000A5A06F7ECEBE76323B671FFCD39259CB38
+:107CA000E978EC5C7250617ED77CC5A0E7DDF38F8C
+:107CB000E469785F41D0A5A047414F83796D751481
+:107CC0005FCBA531BF47F5AED07F09761E53D89262
+:107CD00094AD79FE82EF9C7C4AC837F93DE0D8F438
+:107CE0006B502EA03F88F0C7801F6DE7EE0CEECBE7
+:107CF000D196CEA774C0F6AF88DDBB10F8194D0F32
+:107D000053CE420F5369FDFC234FA9B8CE0D1CCEB4
+:107D1000C2E343E159556C1DEBE1F97C0E3B27BAF8
+:107D20002ACCF458EDFF5A12F8248FEFE1A8F3851E
+:107D30007C36DFFE977A90AF8519790DFA84EA31A7
+:107D400022F21687F0DB1DA2FD4FEF7E7B5977797B
+:107D5000163F11340EF2B2F0AEE378BD9EAF1BF0C9
+:107D6000677AF36C72832CACC9CA372127C4786256
+:107D70009C8B72D8380B7278FC4CC83FAE6741DEE2
+:107D800099EC7E988FDADD7F79B9279D45EE2DE756
+:107D9000728FBD3F04E631B65B9B975C8DBF9772D7
+:107DA000F4F0920A8CC78ADF956892923D989FBD45
+:107DB000568DF5842CF47839FE8E44257E0DC6450B
+:107DC000EFD7341D61BF3FB932E13BA7DF9710F316
+:107DD0008BDF99381A67BFA794818BE37FAD7F64EF
+:107DE00033CB17B0F3A728AF9D0E704FB3D40799CC
+:107DF000DE3BE0379A72E6611E0AFF3D84867CDB3B
+:107E0000F9C686B0DD4F11E7D6B501E36AECE76C41
+:107E10003F5A0EB2F6F9FCF76DC1C39167C33EAE8F
+:107E2000B98E108CAB140E10CE9F43AE0D54BF1103
+:107E30005382F5BF9453C2ECCB555069B9A73A2C85
+:107E4000258A69BE7DBE2786F10DD817BAFEA5F238
+:107E50004696D7378DE5F57D392797EBDB915A5C50
+:107E6000677E80D1E1211FF1FA60FC7F81A7B726F0
+:107E70002B97FECFD419F49EB390671939785A1E08
+:107E8000BAC4527F485A5E8C57CE0FE517D6744954
+:107E9000743C9A3F28DAC3B8348F70D987EFBF7D1E
+:107EA000097EEFAC8C8D1781F95758F860419CAD75
+:107EB000FB4E4EFF77E6B0F3E1A50136DEA152207E
+:107EC000139CA702D603FCF0137FB2AA8DC27517CC
+:107ED000CB57F7B3EF0014F07D2BE0BF17F9238DDC
+:107EE000F1D57BFCB95963E31784C7FE0EEFB3BC31
+:107EF0009EA64C40FB1D8D8F39F2D4DBF8C7BED84F
+:107F0000F720B7D7B17B41CE71FE36879D5B801ECF
+:107F1000A3EB1DAD5798FCF32FAAC72F45906E9E7B
+:107F2000B7E26CA706D25EFADDAB598A8BC643B8BE
+:107F30001E1276FF0703CBE977AD9FE478531DDF70
+:107F4000BFEFE6718FF0A900F55B7FC8E1522A5FB1
+:107F5000A3FBAC2C842125FCEE5CC2D42CFBECD61C
+:107F6000ECDFF7089F0AD3FE1B4ECDB5D923A3E55E
+:107F7000F57C5B7E7006CE135750389DEB73E26D37
+:107F800088C32BCA46A5D2402C70D511AD1BE7A9DA
+:107F900023CE7C99C51ABD5F07F486799C20BF99D2
+:107FA0009E80277EAF00F529CA45E18F201F69E03A
+:107FB0008FB4E6D41DCDC9B7E817DE4FF0F1E09FCE
+:107FC000DE3743CC9ECB030D475A38FFB770792F6D
+:107FD000E4B933CF680A97E782DFE3DEA72F7CCDD1
+:107FE000A2E75A73743ACE6149FCEE6F8CE689CDF4
+:107FF0005FCCE401894B04AF1F2F6820B6FC89DFFA
+:10800000E730BBF9F7392C7F43F0CF8A167BBBF7FB
+:10801000B01DD23DE7A3B3E9A58C5C2C607251F191
+:10802000B3EF1EECF9F3127A0F76E4676E9A074706
+:108030000E30BCD45DB9B90BBF43E51E90346B1E46
+:1080400059B07DFF85EB709D7CFD1B220CBE0D9110
+:1080500021B51C409ABC81C1F9FF00307EBD0200F1
+:10806000800000001F8B080000000000000BDD7D79
+:108070000B7854459670DD7EA5937492EE4E27E9F9
+:108080003CB94D000384A4134208CAA393100812FC
+:10809000A4C3CB04419B871025848CA2C61DFF4935
+:1080A00043100151C3A00E3AE874105D66961D039B
+:1080B000323351111B04455731E00B4774DB172253
+:1080C00022447456DC71C7FF9C5375D37D6F120335
+:1080D000CEECF7CDB7996F2CEADEAABAA74E9D7702
+:1080E0009DAACE68DF2F197219FB01FF2630965129
+:1080F000C73C01A89BAD46C6463196566360AC08A6
+:10810000CA46CF76E662CC82CF93188BB1322A1959
+:108110000B48E945D48F6D90A19D1BFA5BA09D3B58
+:10812000202D82711A24683286B175BAEA5CAB03DD
+:10813000CAE458770B3CBBD2E6B35B61FCFA13C1CF
+:10814000601C34197DA2D3E0837E37DA3C89561C4B
+:10815000B703FE93CA98ACB7A6B16CC6624F70B8AD
+:108160005AEDEC3AAF250C2F6377139C8C6D237876
+:1081700092F4EC30B3639D05197C4F9E9BB36D83E5
+:10818000146E9F6C67BE76E89F9CCC7CBB2DD47E22
+:108190001D2B84D66646F34C5E3D64DB0617CD8B03
+:1081A000C6ADC8F66EC7E71529430B5BE079F6C686
+:1081B000A06121F47B66ABAE3210018752165825C0
+:1081C0008203E6911B390F6DBB30FC7E8E47D1CE0A
+:1081D00018A39E5FB8DD2A8227B692E3B7B4D631E2
+:1081E00017E757BFE68FB151F0C9B4F636293617F5
+:1081F000DBDD4BED14BC031CE3100E434C7C1E4B2B
+:10820000C076A5F22A5CCF578D6E6CD2177CF54DE7
+:108210004FE52F4E8CA8AF3111FEDB4CACAE3D3795
+:1082200012AED5F4BDD9561D958FD8BC55F8BD8674
+:108230008E4D265CCF1BB67F68F2E5FEC8FC2F1280
+:108240003F12D025AE437D8D3980F32DADE574B955
+:108250006C8D291005EB52BF735750077576077365
+:108260000F86A2BE7DD78B69809FF47ACF283DD040
+:108270006532105927E2C710343128D3EA83121B24
+:1082800088F858504FF4ED8C75237D1F3231160D50
+:10829000F473A6D4E297F2A134FA7364787FC6151A
+:1082A000E3F6C3FB17A399DF6C0FE3F7A55D930F0C
+:1082B0004BF18CC5ED8E0A6279A3CDB702E7BF61A1
+:1082C000955C8AEBB3A18259916EE428EF1EA2C798
+:1082D0009438B75FBAF8798F16EBAD3C1F7D07E78E
+:1082E00083366BBCE03F56E885B9ADB7C6513D1942
+:1082F00096A104E8F9452387D320E03C6FF5FC0202
+:10830000F98D2113C277335860BFC9D5F3BB1174FF
+:10831000B386DA5F349CED2619E05A26E44769ED0E
+:1083200076E9E38875DF6CD553BBB49D6D924CF450
+:10833000BB7D558583DAB328941B3B25EAB70CDE59
+:108340005F1F21379479F4223F1E46F82C273A0FFD
+:1083500072F911247A53E055D65159AF27AC32D176
+:10836000E72413F347D3780BEB713DD6A5F1F11455
+:108370007ED6F2DF1382AED36AB64BBA5C9C672717
+:10838000CD73798D81D6E5C0D5D72EC671963B5277
+:108390000B900EEFFFD3519304CF9FC27E00CAF221
+:1083A00056C983F286B51E35CD1E81E8FAAD9E25ED
+:1083B000333695F1BF07FF70D424C3F3A97B241A89
+:1083C0006FF99E5D86459630FDB94E1FB816E9736C
+:1083D000797B148B96705D641A574B772017881F32
+:1083E00098DF1418EC22B9E6E772D0E79A111796D5
+:1083F0009BE7055CCCE22DD239500E8E284079F7F0
+:10840000A298A7327E458CFB8019E55EA1E46E61DF
+:1084100008C73182F3658147183F487293B181DE06
+:1084200011E1F17BCAFBE18588DFAF845C84753B99
+:10843000DA9BDC57C6773D3A83C97111EB81788EA0
+:10844000A0A390D544DF0F590D349EA18CE3C960E1
+:10845000E2F337AC360790BF5EB25572FCD8CD84DC
+:108460009F4362BD0F89F55EA75B9DD3C8F5CD879D
+:1084700008CF81ABE319972F5C9EDCFF94C4EB7EA1
+:108480004B80C13FEB7DB3689D9923DAFD38EA0745
+:10849000DF41D3ECB830BD69D755DEBDDF84F3983A
+:1084A000DACEE93A8CAF808A0E414ED17AE33A2196
+:1084B0001E157E57F0A8E0E532E477E867B079BE94
+:1084C00049804FDEE4D4CB9F807CB6CCEBF233B94D
+:1084D000275F2630B36CC961AC91E9D80F006FB14A
+:1084E0009BD7F1EF07F8FFF956A912E5F84D2011D7
+:1084F0009A22E052FADFE434D1F8CB9AFE2315CB6E
+:108500001B9D2F53E9888575867EC6816A3E89B793
+:1085100049D4FF5BB1CE49364E27CB8ADA49DE2EED
+:10852000FBA491F8C652C9E583E5845AAE31768F33
+:10853000D0E31BA9FFB2222E2F973AE2DC92D4B7E8
+:10854000FC592A312FCE837DFF839E15033EA3C5A0
+:108550001CC5FB21364ED79FED800520F9DF6862F0
+:10856000BDE8D7F0788D47C6E03AEFD2BB1F673D34
+:10857000C765C137255CE765665E3DB3B37CCCA7B4
+:108580004027FE1D09EEC130E52F76CEBCFD53E835
+:108590007F66FB04B71EC9A5C54B74D39514EDDEE9
+:1085A00006EBE0D0B34A09F0BDAAFD85F82BA0DFA9
+:1085B000E7FF965F88F26F9C80F3F453FA26C4CBF2
+:1085C000E9A75EB8F7BFA15F5DA020194961F5BFBB
+:1085D0003E6F0A01FCBAC0A6BFA15EABDB9E608DF8
+:1085E00082E72DFFF69BF1585FB63D81E4684BFBB7
+:1085F00063FCFD0EFEFEF4636DE311FF07FEF5C99B
+:108600007D385EBD37DE8DCF3FFFD727C7A3DDF6B0
+:1086100000D039C259EF3378088F0A5D6BE5D4AECC
+:10862000FD44870A9D005D33E2871A2E6F143A3E9F
+:1086300086720BEC8C19659675581E9B125D43F47F
+:108640002CF8B361AEAD8DF49FDFE5C7FE33BDB648
+:10865000820D505D2AE65F9FCBE9621D504D34E0EC
+:10866000293637684A877657CFDB351EE15C17C35A
+:108670004AA2895EE121ACCB0C623618A7F5A5EFC2
+:10868000A43CC64680D83B09740EA36DFF612463E9
+:108690006F83B94AFA2386EB81ABE77D28919E6010
+:1086A00006EB49B186B0C23FA2DF0C349ED2AEDBEE
+:1086B0005E13780038FD627CD237C52B397D1F925E
+:1086C00016B6C4A1BCB9253816E5E733A76E8AA94A
+:1086D000CF8DA473DE3F6D0F970FCBF7B4AD324152
+:1086E000FB2B730A8AF133CB9BCAD9C7C86F7A892F
+:1086F000F8ADC16F51C9C166C16FC956E6B81CBE9D
+:108700005B61600E0B968CBD6924FC3CCEBF6300A0
+:108710001607BC9F5B352F09EDE0078DBED451F8DD
+:10872000BD75428F6DE7F0427FABA590C6B35E5E2C
+:1087300048E3741AED68B7C084A1BFFCFCE4EDAB5C
+:10874000A430DC40D159A8CF70BC220BEA1F7F0DAA
+:10875000E91FD9E4467A388D4D52095F79F3478491
+:10876000E70DF6890FE92CD9C4ED70947BD57168BB
+:1087700037966EB18D0A97C931FCBD763DDEC3F7E1
+:10878000285FEC1E2AD98E449293FDD92707AE3E6E
+:108790004BFC73FFB31F923C6A407AC7EFFB3E511C
+:1087A000E965859E1E7CFA43A2F7191D7C7D1E9407
+:1087B000426B915FFC53A4918F239F377BD8C76096
+:1087C0006836083A5F56F9E1129CFFC08E542BCAF6
+:1087D000ABB3820F1AC68786A09C3CFB34E7834369
+:1087E0003A1DE1F3D0B6E16DA887C0AE25526E68A0
+:1087F00094B745117EB99D5F5ABB785305EAFD3A9F
+:10880000E646BE6ED8539D2193FE8922FCBA1EFD1A
+:10881000682DF2850DACD76819E7F7C12484AFA1A4
+:108820009E8D42FE4E9BE8791AEBAC4362680F279F
+:10883000D73A4A0D445F0B46227D3D98D9BE16F5C6
+:10884000BB1FEC539CCF83C6D63203D41FAC90AD74
+:108850008031C00FE83BECDFADEF66ED21FE75CC5B
+:10886000776F907A910F4FB73971BC861C931BEDCF
+:1088700094A91DDCAE66605723BC0D1DAB7210FEC3
+:10888000A9F2E56E3DBCFF52E047C1D3D48940A7B1
+:10889000383FBF8561FBB3C6CE6BB17EF60F40801B
+:1088A00012B16B29C2772A4F1A89F2E2A5A7C1FE3D
+:1088B000C90BD363DC1FC10E82BADD6095DCC467CF
+:1088C00033A322D7B3D5C8F5954DE89FEC4ABEAE89
+:1088D0009F0A3EFA54C89F4F6D26C1DFAD9CCEADB6
+:1088E000FE3CD4CB5F8AF5A6E150FE8B71972F0E2C
+:1088F000121FD5EFE4F69B23CA53707304DD3ACA06
+:10890000B9BE4C023EAEA652476532FA2F0EF4AB0A
+:10891000E56D7A5ACF19B4BE573A2E2B8C86BAD150
+:10892000CEF5685A8E3497E3C54478494AF46D42CF
+:10893000BBB96BA854BC4DEE49EFD1766EDF25254F
+:108940007A8B24689704FE06D25992BE54178DFD87
+:108950000A2437F64BD2CF20BFB62B29D5BD4DC543
+:10896000D7DC2E3C951CC7D739F0BA614684DC0FA2
+:10897000FBC3D16EF46B4EE9828668179F9FD712B6
+:108980009E5F60554C4DA4BC4A10F3090C6535C878
+:10899000FF609F5BCC28A7AC6017A1DFBDED8AC745
+:1089A000B8DFDD42EDFE6AB3F2EFC13CD04E4BCAF8
+:1089B000F6AEE47A348EE04DCA660BB15F528B534B
+:1089C0004238C2F8B4B6213E1F11EBA9D8E70D40DA
+:1089D000C768D73103E70BF95989E2157DC98130A2
+:1089E0005D733930B583AF6F6C2597032C571A89A7
+:1089F000FA1EE55BF5082E075CF961FE6D30858691
+:108A0000201D5EAC1CA8880D10FF540C1F4271067F
+:108A1000659CB346F023E1F959E053B26B05DDC71D
+:108A20003DC3E95D5997174D7EE2AF1707C6D07A6F
+:108A3000235CE8172AF2B1E199F5437CBDC6151411
+:108A40007DE6F7209E4E0D647CDDC5B866D0917141
+:108A50008554FA513FC43671FD1C9B2B93FE6EC8A2
+:108A6000E91C87FE35ABD451FFBB73DFFC77EC7F8D
+:108A700095DD42FDDB74561ADFD8D4E84F67147FCA
+:108A8000E17ECAB6D800CA15250EA385AB54D08B9B
+:108A900012EF50FC8BE478DEFE4641E7F3ED9C7F5D
+:108AA0006F16A502B7626F43FB8168E0F4A54F948F
+:108AB0007EFFA8B890F21D45AF85F1CCD713E16FCA
+:108AC0001771ACEADCBEDBB5EEE77283FE705D9E2B
+:108AD000496DDB407A55A6F55C2FE8FB4A9B77ACE5
+:108AE0001DF060AFE4FEEFEF25E02FFC7E8D4187A7
+:108AF000747C4B349753DAF195FA7DCD60D25ED613
+:108B0000B7FEB4FE4D4FF032E661381EC513906DCE
+:108B1000CB2ADD38DF7BC43A69FB1998E19B906270
+:108B200037B922E0113617B0041B5F18095740050A
+:108B30009775AC8E0523FC156DFFBEE05D87F3894C
+:108B40008AA867EF63187F8A35C7131D81414FF6E6
+:108B5000FC7A310ED0BDBB9AE41B8F63F5F71D2D57
+:108B60009CD1B21ACE8BC5FF3ADDAE3AA4E77D02A6
+:108B70005E76FFC5CDEFF762BDEE6D3653C9E641B7
+:108B8000BFE2703F8B5B5E857A3E7FAF5C40F6B2A2
+:108B90008EC7EBE2C6B3AFF440AFF125AD39AB51B0
+:108BA0005E7BD570A7D4C4B0A0395C4FF5D955F51C
+:108BB000F4BA3455FBCCC681AAF7039A86A9DEBB6A
+:108BC000FC85AA7AF6BACB55ED07B796A9EA976D58
+:108BD000B952D57E686086AA3E7CC75C55FB11ED14
+:108BE0000BD5F4A1C1DF8655ED35C83F13FEF675F0
+:108BF00019C99B6798ED71A45D736824F25B7E8749
+:108C00007AFE67EC76A2E38412351E2E951E265C52
+:108C1000F871BA55F8289671BA88FD7EDD57FA3C8E
+:108C2000AC6BF8458C3BDECCF9A4BF7157C75E6BCB
+:108C3000403ADF8795087BF86D0D7F57D42490DD8F
+:108C4000C32ECCE8C76EE6FC30278A3522FDCC89DE
+:108C5000E5A5F27E7822979BD989229E7491F47BB8
+:108C60005CD0FBB1BEE817CC9B645CAF4A46FEB457
+:108C7000B572D55718BFA935045901F0CBFD623E36
+:108C80000F8AFE5B9AAD34DEC3CD4E2AB736CBF4E5
+:108C9000FCD1E61C2A03CD6E7ABEADB984CAED6064
+:108CA000C761F9447325953B9ABDD4EE77CD355411
+:108CB000EE6CF6717ED4AEDB053BF93373985A6ED9
+:108CC0005D5DA357AF8BA24F35FDAF661B3BF5F142
+:108CD0003DF1D1A3BF7E5E426F7A5A299B4E145458
+:108CE0001E8CA0CFCB13E31C27919846B3D1E49FF1
+:108CF000F6D3FFDB6677E5C1C1FDD3B5967ED8F725
+:108D0000370F463B58FB7E0E7E3B0DE4E0E64DEB15
+:108D1000FDB93DC70579B82604A49287BC17114751
+:108D2000DEAFA14B8F2141E5DF2AE55382BE4A0524
+:108D30001D966AE8F0FE44AE7F5626727DF87F8D60
+:108D40000E0F44C7911D7DC028672445ACEB81E818
+:108D5000587ACE72983C0BD645F230AB0BE8F24015
+:108D600022DFB793D063A0F8EF202BC52FA22F31BD
+:108D7000CEA1C1A304E6B50BC62B8572BC9DC60F60
+:108D80001A707CB72E2C2F07E27F63C2F4ACEF4938
+:108D90000F308EDF0470FEDEC86413BC7F3751567F
+:108DA000D90F6506FD8FCADF32E4A3BC9EF0F7E859
+:108DB00077897CF4D8FF321F29F4CEBECF1EE48D14
+:108DC000EBF9BE54F0D1DCC467D6FB2D617A2F439A
+:108DD000FB2B028E6342EE1E13F47E40D81B481F0D
+:108DE00085BDD81DAF88F64AFF4BC577A990778C13
+:108DF00085D290FF2FB53F708E01FB959AE3FDB1B0
+:108E00007997DEBF2F7CF6E8D7E1B8A83810481A6A
+:108E100009F97C89806E89D9E2477A625B8C674266
+:108E200011747C7B8CF7D34468DF61641DB8BF008C
+:108E30006A5BB62613DD135EE1CF6B867A81A88F5D
+:108E4000F64B44CF51506942FE08BDF81DCA8B0253
+:108E5000518E162586419DC837B971069CA75B4186
+:108E6000938867162BD58960AAC0FBCB4515448132
+:108E7000B4D28EEE482BC3FDF00D927B9D1EBEA793
+:108E80004F71B52050232B4BF5E8E78C62AD548E23
+:108E9000659D2D0E28C7B32E3DB62F31B7B71800EC
+:108EA000CE01EC7B2BD179CA13CB7F00D7B0C9CCD4
+:108EB000F785BF8DE6A5BF8C91BFE3FF203A807E8A
+:108EC000CD34E68B72001E6ED37BE6E3B8D5B63B9D
+:108ED000F231B80AF2E2A310C55925E2F3324B5140
+:108EE000CDF5C49FFC39E1D1156E47757DCFFA03EE
+:108EF00077F27840CB7A4EC72DAB785D7608BF4CC1
+:108F000094431D42BEE34A24133E08EFD1CCEFC781
+:108F10007D5B9603F82CE6F8257C590E13BE63584A
+:108F20003BE12B7ACE16820F04BDF5E4704066D08B
+:108F3000CB7E88ED395E5FE398CDAD1E33D045EC36
+:108F4000BC80DFD8CB3806B4D7E03B8659263FEA51
+:108F5000F9369D2F1FF1C6327486487B2FCAEA6509
+:108F60006C60981E2F02FFA32F06FFC63277A7075B
+:108F70004868768CE4DEF613D6C1EBB02BF82552A8
+:108F8000DC97CADAD08FAF73302703FA3759CCC4D5
+:108F9000276B32B9DF6F1AC6DCAB115F5E1DE14B88
+:108FA000991F3C60917602E0613AC26F0A481F2225
+:108FB0005E4CCE46F2C79821948EEDF6497CBDB545
+:108FC000FC5AEB9004BF66707A653FAEBF764DB336
+:108FD000BDE72066DA76E5AB4EA897DAAE715801A8
+:108FE000A4070AAE34805CD875941133FDD531E9FD
+:108FF0006EB45376CDB6FD3A09DAD727873618C155
+:109000002ED9355FA2F75F26F1F7EF95B2768CDBAC
+:109010003C60F72D45F8E7BE2A1F42B4EF7AF1C64F
+:109020002CD40B8E7277488FF8BE264AC67D1DF66B
+:109030003DC00178780C410038DB315E68E4CF2711
+:10904000C0F35A85AFFB9023A395BA5F6206A88F41
+:1090500053EA62DCED58CF0EB757E44EF6E29FFDBF
+:10906000E7FF433BA5534F790F520DDF07192DCA78
+:1090700071A22C10A5BD92DB354B37B29112F41FB3
+:10908000B458D9C7890A0C867F0ED80AEFA1FED939
+:1090900026361279E2A4516EB1203D8E606E8C139B
+:1090A00003A1137DBE9D690B603CE23389B5501C62
+:1090B000793D8F23631FDC4F742F86B52E4293CFEB
+:1090C0001CC078F81BCDEDF96B8C11F20FD6C6538E
+:1090D000CCC32B1C0FB9E4178D65E13F9C67451885
+:1090E0004FC44793447D723D8F834579402EA27EC5
+:1090F000D2C8D36816709A095F2ECAC3D04F66567D
+:109100008437AB3208AA12E4A5A794E4E228E67BF0
+:10911000A113CA319E5D424E065A708A14C2C846D7
+:10912000FD271B703DCBC142C57A256BA5F24AD6FF
+:109130004E6515EBA4F22AD645A597598D58FEC168
+:10914000E122FA1D6F06398DFC6E9029DE77F265FB
+:10915000AB1BE38E332A7D26B917FB628981F17D33
+:1091600038E6CB42FE60065FD69C087BE164EDD515
+:10917000F33DD04F16FB28CAF3671DDC4E3E24F8A2
+:10918000E64149C891E55200FDDE076B4D943F73FF
+:109190006CB9B40DE3EFF09EE2AEFE5A33C5E11EAA
+:1091A00034CA99683F7CE39079FCAC7ED76D2C1E65
+:1091B000F7EF96A622BF1E977C93EAA0DF922A1EA5
+:1091C0003767067FE6EC083EFF6C01874BC93750D6
+:1091D0009E1F11F2FB1BA43180EB33809FF6DF94BE
+:1091E000B8DA5C1BC9990A50FC3F8371DF17F3089A
+:1091F00008B9A0F04F9D420706BF290DFACD71BBFB
+:10920000088F73033C2E5B616041B477BBE1AF69AB
+:10921000BB85017DCCADDB6F58924BF942149F5C4E
+:1092200022F287A43AF94E07EE2BDEC1F757C2F9B6
+:10923000417C7F78C9BC5DF3296EB0388A215F2CF0
+:10924000D9B2E97DE4F7ABEB26CB883FF81EC545E4
+:109250002799F9FE9F19BE8FFB6593EB445E46DDAF
+:109260005D9D489FD0CE83F6EE24686F28C4BC1B5A
+:109270009ECF16E3E7F941311395FCA0C643499808
+:109280001FB482B9FDF0D9ABB7B6498CC7FFC81E71
+:10929000EACF5E79E4AEEF6DA88F48AF0F00789A01
+:1092A000F4F22723713E56EA3FD7CCF1B7AEAE8534
+:1092B000E8F02F353009F8EE9C5617D5D941CEDFAE
+:1092C000736A0A421827325746D13C5122E17E8008
+:1092D000995512BF17301E87B809F30AE87D50056B
+:1092E0005F0FFB1FE41DEA87BEEC26653EE62613F2
+:1092F0008757332F455EA05CE9EA85CFA5CA97B8AA
+:109300009D254AE47BE4D742B35B1FA74312F3EAEF
+:10931000B9DCF4338A87B33BB83E897E4242BD6DE7
+:1093200076F8AF4592FBECE0A03B2D84AE56166973
+:10933000F79BCBBCD77B23F86C7DA9777E64DEC31B
+:10934000B024CE6FC39344FCF9557F167EE7D46BEF
+:109350005C3FF8AF8F9229EED40F1E60EA015DF6F4
+:1093600045CC77B190E7A20CDB83720BAEE7B8A4D3
+:109370008104475165B51EED8CA7DA46BF3186F5ED
+:109380005CA7BEE8488B9F6FED9E8A24B20B3CBA67
+:109390008BB19B2BF419D7D403FD9C9F17457CA55B
+:1093A000E8C1425C14E4DB4E1600DE46FD407A2341
+:1093B000751DB34A32C62301F7AA78A4991954F14E
+:1093C00048ABAA9E5EE754B5CF6C9455EF0734E5E1
+:1093D000A8DEBBFC6E553D7B5D89AAFDE0568FAAD9
+:1093E0007ED9964A55FBA101AFAA3E7C478DAAFDC6
+:1093F00079985210E653F496DEEDC7F5F57B3A7393
+:109400008BC37A7D44BB4FD57F74684115CAA7FCD6
+:109410008E3AD538EC04D86566CCDB6914EBE1D61E
+:10942000A39C7083F07DD88528E4EFA93DD4DD2787
+:10943000A67C8E727A6E8D316CCF612FB691E28AE6
+:109440006E8D1DA8F57B971EF61FB2007CB5AFFA96
+:10945000D722FDAF4952FBC1157A0BCDEBFC9B7AAD
+:10946000CA1BA943CA7484D7F13C0E84F3DECF0231
+:109470003CAF433D6FC54FAE45FC40BFB9304E10C9
+:109480005E4539D5EB1D2DABD73B3647BDDE716E42
+:10949000F57A2794A8D7DBE6C9E915BF8995EA755F
+:1094A00057F05B02FF43FCFEA3F1B933491B471899
+:1094B0004BF2F42F5B843CED290766998B7BCA0144
+:1094C000056F3DE48185FB27DDF2608B90075BB47F
+:1094D000F2C0F3422AC037CA07FE218CFBCEFCD172
+:1094E000E928D7D2D85EF25B4050FA303F06F87BCD
+:1094F0003FF2776C933BE4473DB0358AECC8638715
+:10950000961CD2217C95DCBEBF5B3844AF60102A2C
+:1095100089ECFA5792A08C3137FAD14CCF6AF2928B
+:10952000DC7C17FD65DCDCD1C80BA691775A3B5873
+:1095300091279F8DE3F4F4CE6B2CB05A42BFFA28EA
+:10954000F9B397AA17FAF3A7BBE5E83CAE37468B09
+:10955000922DF493FDAEE89196129F4BCA467DE2A0
+:10956000D1335DA47F1D22BD3281F949EE5E51E900
+:10957000FEF54AC4DB9477D2D15ED2FAD980E7B344
+:1095800088AFD8A6769EA75C29119EB5F8D599B963
+:109590005D1293C1F755BF4D52F651BDDFE23A2936
+:1095A00078DE1DED26BA7AAB96FB1F454707B55806
+:1095B000A05FF20D2E37F6DB6D73BF80F5B79673A3
+:1095C0007F70D49B1E3DE6236537BA282F6DB7CB3D
+:1095D0005B8EF5B76EE1EF8B8FFB285F6950137FD1
+:1095E0005FB8BAF18538187FF62FF8FB67BF5CAB20
+:1095F0008F87F781D5A27F696B39D6DFBA93BF1FFA
+:109600007D22D082F5A1EBC4F7A5F617E2D1BEBC4E
+:1096100047E279745ABF47F83913C47AF4584FE1D6
+:109620000F8C17ED15BF66420D5FA7C55DDE49447F
+:10963000669AF5D2DAEB15CC47F5C9CC4FE514168E
+:10964000A0722A0BD2FB692C44F5E9E04263BD9A73
+:10965000C946EA9F9C43789F092291E20B256E330D
+:10966000DAE38E4F5EB99DC587F7A5153BA0D5EE11
+:109670005D8E7682A3DC7B0BDA07E5C9DC8E0D9765
+:10968000DC4E48B6FBB3DCF0FE9451EC1376EF2FC2
+:109690001753FE0334D98876ECE8649EE79ABDB18F
+:1096A000D1807C795586E4C6BC86C968E7027E8293
+:1096B000BF32D8307F0DD7A2377F381CF7D2C475A0
+:1096C0000D7EF22B0AF5F270649679C983EE46FF9F
+:1096D000783732661AE021396FAA3F035B733BA6E5
+:1096E000BF766F8ABC98DD629F7196D7A523FA2C4E
+:1096F00050DB49F392B97DA494A3DEFCC7CEAB70D6
+:10970000B59FF2A4676F8B623C9F85A561DECA128C
+:10971000D648EB7A72849FD6559143B305DDCD16BA
+:10972000F474B22D8AD6E1B3EBA58004F02CD9FAFB
+:10973000D271A4B73EEDA4DCC1246F6609FA9C6324
+:109740006E9C5F8F74ADD84FBF1AA6FF6138E15190
+:109750002D07FBB00393445DF99E7E3CF327013C4B
+:10976000EFCDE77230DD2F915EB85839E850BE2753
+:10977000E4609AF23D0F901CD4B3C45BA99ECF3F26
+:109780004994E9F55A3DE25B85F4EF64AD12D633B6
+:1097900059179532B3AE4ECAC650965B87F59443BF
+:1097A0000757E1F836947B38EFF5078A50EE1945F4
+:1097B000DCD76806FD89F138878792330D07BBE354
+:1097C00064F727A37DF977C6C9C0621A4DFE326BD4
+:1097D000CCC7F213A3651DC56DB5F1941EF11775C5
+:1097E000DC615C2BC783D4AAE8039F13E7876990E9
+:1097F0002ABD30C62D633941F292FCB832D1B7335D
+:109800003909E3138D19D85E670EE9510F6C10E723
+:109810006E360C51FC4B583D2CAD3CCE9D2FD67274
+:109820006DB2692DC6D9D6C6746DC8C679EDD3613F
+:10983000062773812FD76989E827CBD42FCFCAE1B8
+:10984000BF17C7877E313AB918E188D1CB43B0FC46
+:109850004807AB0670243237D54D7A6BD22A1E4F9B
+:109860003C90CCF3376324F8CE9BCFE924F4BFF3CC
+:10987000C67C6447BFF7C9BDDB766C0392F9E6305E
+:1098800057BBF7EED0FBA360FCBCA727C6BE06ED16
+:10989000573EC77933BF4447F2EF0B13DB88793269
+:1098A00033CC7AB301EC892F6E15792B0677567578
+:1098B000447CE02A279783C7FA88F715C597FE15D9
+:1098C000E13A96CAFB6BDF87841C2D9EC7F3F7D85D
+:1098D000A914C2C3D7494C955F51147F158DA3D4E9
+:1098E0008D176CCC17718EC968F032AB059F3BE8C1
+:1098F0007902D8A118AF4FB0951890DECA98F5A09C
+:1099000007F081470A70A2492DFCDC5157AA254077
+:1099100071BEB186AE6EFB6F20EA196E3F521CD647
+:1099200085FB1C6ABB319FA9EBDAB8EB5F843C3442
+:109930005E4867FE91BDC19945CF3D664B508F0A89
+:10994000AFC89D8372D96379E538CFFF02791001E2
+:10995000CFBFD83DE39C80933D269E2FB548E79925
+:109960004AC2E098CE8E7EA8C16EF6635E60C238B1
+:109970003BE5C929DF1B9DC2E3EB7BC022C1F5B1EA
+:10998000EA986F97A5E77CD7005FB9000E570AD712
+:10999000674A7B458ECD57F8CA6F23BB669EE0AB06
+:1099A0005F396D3C5FCBCAF7413E5AFFE59DF87CBD
+:1099B000C1D1181322FBBA792C7E04F4F33D9078C0
+:1099C000C423231DBBF7631E0BBB8FDB0FD6B29CDA
+:1099D000628A1BB389B49F29F9D349BE5EAC7E6805
+:1099E0004E58F0690ADAABF101D90AE3C40C3B45E1
+:1099F000F970EE1446F32E47BB21BB97F5B47CA358
+:109A000043BAD0AE2B7E00D7A1BFF58DD1B3469E11
+:109A10000F161A1299E7D59C50FA69CA28CA4B0D3D
+:109A2000DA31AFF1B9284E5F876169A1BE62DF50BC
+:109A30008A8B3DE6F47D8C708F9EC8ED0D76B06B01
+:109A400008C6D716C58B3C33A7475E05EDEF1BEB69
+:109A500028D8200B6443BDDC6CA37CB1D92962FFFC
+:109A60005CCCE352E9D7813A07E95F9202DBA4FEBE
+:109A7000E7ABE4D92AF3FC3885D3B7522AF3D09E5A
+:109A80006BFB58D0DFC729FC9CCB634E2FCD7BC529
+:109A90008CAE0F6C00C322138F77F637DF3A31CECE
+:109AA0004F9DEFC5AEEB5F80D611AF8B622E0EAE31
+:109AB0009FFF9DEB70B1709D4C1170E55D1C5CF7D4
+:109AC000FD9DF8F230BE3EFDC105EB7912D7934DF6
+:109AD000EC1A82F35864BF38F8F6FC9D7843F8EC32
+:109AE0001707DF63C88F2CC8E19BC3DC46A75E0065
+:109AF0001371CE447BBE648E01746B61F8FC89CE19
+:109B00001CF06197593966A627BBE4A79D33E95E2F
+:109B1000C76416B4A1BFB82F8AE2F8CCDD35245251
+:109B2000AF3E23D6EF31A7E779847FD11021172AE2
+:109B3000D5ED9ED7B4DB502AF474958EF4DBDDB9F5
+:109B400083E89CB4CECCA71C9321D33EC14B826F3B
+:109B5000953C5E657FEF265B5D1DEE6B287A69EDB7
+:109B6000B0BA1CDCCFF0387BD74B0A1CA79B0F5B2D
+:109B70000719FBC6C332FDEEE2C65EF6457E67F707
+:109B8000BD9B129137B06CC7CBD641117197112C88
+:109B9000A4E3F67D978EC77945DE4BCAA5E1FDF5B6
+:109BA000288EF7E6042FC967454F343CF35B19F55F
+:109BB0000FD8030CE3BA5D713124AF5B8695E444A2
+:109BC000EEE3FC3545D1E7FA3EF4B949F53CD86CF3
+:109BD00066FE887C55CF29C344B4C34A99758D95D8
+:109BE000CA58E68FA0DBB05D23317FAF768D819EB2
+:109BF0002BEBD2979DA0E4A9069BDBCD9F80FFB6FF
+:109C0000A639271ACB03CDEEE84F607D1E4A281DEA
+:109C1000E3C47D146F87F913555C36A8AAA7FA0E22
+:109C20009B3F51C5653B55F5CCC6E3AAF6039A4266
+:109C3000AAF72EFF29D5FBEC755DAAFAE0D60BAA90
+:109C4000F6EB74FC9C41599199F2EA2FDBC2A223F6
+:109C5000DF2BF9AF468792FFAAA3F64303E6E8C8D5
+:109C600071CB3C16BF0DEDF2559C0F86EFB0AADE0E
+:109C700097FE6D26ED17313BB3E1FED88876A7EA53
+:109C80003B466B8EAAEE31F33C998712168C41FB52
+:109C9000ABDC5CA07A5FCA76A9E6D19D4FDD4F9E12
+:109CA0008BC1B09EE28EB82739B6B0675EF5430926
+:109CB0001EFA9E96FEFD778D15FB41DC8F06BAA538
+:109CC0007D9C2EC94C7A5C12E78395EF4C73727BB6
+:109CD000AE5E43B7F586A009E9AAFEEFA4DB471202
+:109CE0003CAF24203D95F77EBFC1AD4ECE375F9887
+:109CF0007A7F3F57C067BC001E58AF746FA1E75F03
+:109D000094F1FEB4430A727BA54D8DDF3AF19D7B41
+:109D100045BC62659C27C5FE23795EC60BB12CD07D
+:109D20002B1FC7D3F32F06FEF8F76EBDE4EFE9FB58
+:109D3000989F899EC33AF68A9FBB047EBEB0F7FE09
+:109D4000BEC5A9C8A55495DCB8CB2973BC767F27BE
+:109D500083DEA3DFD4BBFC72D0F3FEFC2666F6B92B
+:109D6000490EFFC3FD25C6E3699768AF2F4CE1702C
+:109D7000F5377ED0E949203BE527EAED18D4D1A993
+:109D800034CE4EE4CBB5267E3E102413C537147F67
+:109D90008869FDA51C9EBF36DFF90AD91131187BF1
+:109DA00000BD1CF38B68DA57B94EB29A10FE6BCD2A
+:109DB0005DEFFF1ADA9F782ECAC4E3238A3F14AB03
+:109DC000C7FDBA8B855389AB28F71D607C1CE55D08
+:109DD000FE846174CEE53EF4F31006715EE13E80D0
+:109DE0002115E44FDED1D909415C278CEBC0FB780B
+:109DF0009C2FC09DA0B3D079A4BEBE9F00022CBDF5
+:109E000010CF7DF07D9484BD86D391EBA0DD47F922
+:109E1000A6F3EB18D4BB6F3BD5FB297F6155AF0F81
+:109E2000477C953808CF794F4F4C89BC5FA43B2FB6
+:109E300053C9F7EB23EEDC1D0FD2C47F94B8CFB823
+:109E40004B8CFF749FEBD7C47FFA8B5B7D6BF77DE8
+:109E5000ED247A53C7AF4C0778BBAEB668B23394E3
+:109E6000789632CFEF04BF7F90E8F90EF5F409A79A
+:109E7000E7BFB13C16CDE341C7A64C4EC0A97DC398
+:109E80003C09E8EF62FE6EBABDE7BA60DC664D845D
+:109E90003C3866EB5D7ED853B9FC3897D94974B825
+:109EA000A1B42BEBE122F25BADDB008FCBF7F278B4
+:109EB000E972B43BD0DED8A3B6372A45FFBBAB76F8
+:109EC0007B113F6DB8B9C4F78F449C8FDB9593EC41
+:109ED0009EC45468770AEF99C138798C28E3B9FC9D
+:109EE000CC12E39844395294A7847C3D65E7ED1584
+:109EF000B89576A344F949B3D9BC6670F8BDFCABFC
+:109F0000A846F44393B295F358C02930AF86BD29D3
+:109F1000E47F2C6EFDD084E79C46A7969A529378F6
+:109F20003BC4CF6243C86487F637DB7CC311DE06CF
+:109F3000997976537C2E649A09F33827ECAB7346F3
+:109F40001EEF3A17CD4B059ED1A9D526EC776E5C56
+:109F5000C884F850EA0DACEB5ACCEB1C9DEAA5EF97
+:109F600041FD514DFD0303D45798447C532B473298
+:109F7000E2547266FEDE97898EAF35B3B5E9F0FE26
+:109F8000BABD2926745EEAE2FD43ACAA78CA4F93B3
+:109F90001F5A3BA33F7E93F68ABC3451B27D2FA754
+:109FA000E3FA8FDDF75A22966BA5468A3B47E4B960
+:109FB0001E7F16D641AFEB4A8CE433655F67BC1950
+:109FC000F86D20C529F839F924D35A2BF0D91AE0B5
+:109FD000032C7F99CAFD475C731E470D58D14E5123
+:109FE000E2AF2BCD1CAE8668CF7D65E8671DD56BD3
+:109FF000E2AEFCBEA0A4164F02C6CDBA8EEA258AF8
+:10A00000D38838EC4A11875DB9AB3405C7BD35F547
+:10A010007FD78E52E26D0D3603732484FB29F36CD7
+:10A0200010F76168D74F79FFECDFF4BDC657CF89D1
+:10A03000F77DD9671BC4BC1A2E0C55D9270DC00754
+:10A040000867C385DC1FB54F7ED9DDDFA6B23FC2EE
+:10A05000FD1DF47C1AF31D443EA8B699FD7AA46F49
+:10A06000832793CB459E075527E8A84E913301B52A
+:10A070009C51EE3BC2FB7FF07C318CF71BE41B65EF
+:10A08000BC378D7C3F770193498E2DD0D80FCAFD08
+:10A09000488B2CB3884F16AD3386F303E8BF1E13ED
+:10A0A000DA35D7B76A9F6BF36B397FC0F78F467E7F
+:10A0B0005F99CFF298AAC31E6C56D449FB710DACC0
+:10A0C00095E440C31E90A3F1584607717F8475A89C
+:10A0D000E7774364DE2FC07B236B37B924F487D541
+:10A0E000F0D4B34E1A6F79FB8FC3A9F801788E8430
+:10A0F000FBCD6395FC007ABF2B55267EFB7254E79F
+:10A100001341F88E3E6EA219F5F2D98ECFDFA6BCB0
+:10A110004627B75B180B3D7805FCB3AE436FC538D7
+:10A120004E5DC70BA40FFA5AA7EEF3F5AC8BE6AF62
+:10A13000EC1B68E9E6C9541EB7B83CDDF336E2D142
+:10A1400038B09DEEF5EABA859F6377E8C17201F8F1
+:10A150009D21F0C074E1FB6998DB63C638E984286F
+:10A160007ECFCEFBD632339ED34FB6E9BC28EFD795
+:10A170005817DAF0BE925471CF46B2A4F3A2BC9E37
+:10A180000FBC88F77D75D51A1E473E77DD1A1BCCAC
+:10A19000867578DEC4CC484F8E581FDDCBD065D392
+:10A1A000D3F74B6BBF19690678D2BEB714625EA1B4
+:10A1B00002F784F2AE9118C7684EF0BD8470671E36
+:10A1C0000F9D943081D8E2A17DD5DF093EFEDD618F
+:10A1D0005DE5B65EE61D9FC6F9715892C18BFB1D09
+:10A1E000C383CCD3D60B5F29ED94F3CB7DF1DD9EF9
+:10A1F000B2D0B5C897187FEDED7BFA34AE977E8963
+:10A200007776E03E803DB404F1B8E74AA01198DFCC
+:10A21000D9E752B6AD8E98DF03625DCE4EE17AED9E
+:10A220008DD91686F2B6D8D028D972C3F2A62EC11F
+:10A23000BB13F939655E5047F113215F503ECB6483
+:10A2400017ABFD2605DE35629F48F197B4F2580B37
+:10A250007FC3054925977E89749B14295F0CF4BE42
+:10A26000427F07E5357CDE2A517EDAE7CCD742F51E
+:10A270008D12E55D7E7E8CDB691839918A513E70C6
+:10A2800079B3E4F19964F72EF4F1FCE605DB97511C
+:10A290007E11D6EF00FA5AE0E4E7A216AE51FB17A2
+:10A2A0008B37AAF90FF781D16FBA1E2F7400FE5CAD
+:10A2B00072BFBA7D1DE3FBA4759ABCA46421D77A52
+:10A2C0009CFF4B13F671312BBE94734B1B99C793B4
+:10A2D000867691C837FE7C7B76CAC2887ED7644872
+:10A2E000AA733AA7414F0D827E679AAD54CE4CF3C4
+:10A2F00054A6C1FB8569BEA9589E3B2AF066E81AA0
+:10A3000042F2BA86CBD1280C22C23FA3AE3193BD14
+:10A310007B17DE7B05F88B8AE2F259D1E77AFDCD17
+:10A32000FA789CE7A7454EE2E37F9B5C8979161B90
+:10A330004A3D05C85F1BAA2D74AF419B8EDF6F6736
+:10A340008EE2F7ED047E37E600EE6D0F6ADF54868D
+:10A35000F70B584341162F63DC6715E5ABAC1BCFF9
+:10A36000E8FE32E53B2521EF2E84276B9685EE2112
+:10A3700071E8DB9C1817710C37897B13B89E691044
+:10A3800038FE75477602EAE3F37B2FA37218E3EBFE
+:10A39000AFE4E5E33759C43EDA9966A8479C6B1CE5
+:10A3A000D62E058DB8BFDEBEAA16E9A57E75E724B8
+:10A3B000BCB7A5EBDF19E5CD389E4F2D93E3C3F075
+:10A3C000D5EF7ADC4EE70B845CBB06FD3EDC8311E7
+:10A3D0007654F73902E1B7D408FAACDDCBFD956BC2
+:10A3E00062397E17327716F69B6B66F13AC0D93523
+:10A3F000E5EDA3501EB165461BDA71979C3722F438
+:10A4000099B6DD693CE380F2F0E9288A2B353C11EE
+:10A410004771B915BA2EFAFE9634A1F7878878FFEE
+:10A4200020E6C13CA3867D97D1FE5614DE9B54489E
+:10A43000F2CB8CEB7A08E52CCCFB8667A3E9DEB681
+:10A44000EE7B49ACCC8F7CBA625F0AF9A78E6C4F69
+:10A45000C14DB9783F46288BF81BE49504B6D8AEB9
+:10A4600087674CC33C95863490B7503F91E69B6616
+:10A47000003A6C18185A82216C437A137F3F2C746F
+:10A4800012EBF1E92DFC7D6168891EEA43D337F1B7
+:10A490003A268A016115A76F9986E7F14EDBB85E0F
+:10A4A000396BE4F1DFB34F0FDDE68F58F781E95CDC
+:10A4B000DE9D8EE6ED4EBBD8753310DF39A12191BC
+:10A4C000F9F026D14ED17FCA3C957E303EEDCF6A61
+:10A4D000C70FA671797B83B84F66422C5B47F76044
+:10A4E00019981FF3AC0EEEBD8CF0F2781A3FC78EB0
+:10A4F00070E2FEBE328EF69CBAF2DD1BD15EB45025
+:10A50000FB9A48FDF19A5837F8CE1AFA4EAEA700DA
+:10A51000F9A461464601AE1BAC9741AC97C14CE72C
+:10A520004CDBA83D8E6BC33CAD72AE37262426B6FD
+:10A5300021DF2B7083FD6321BD2CE07F47E89D1B4D
+:10A540005A04BE0066CC6B6B7886EF7FE2FAA23EBF
+:10A55000199ACEE73F309DC385ED69BC0CC0EF88EA
+:10A560004B9FDFE7FF4BF38B58170FD2C9C18EA16A
+:10A57000B42E0AFC8C6D528D737A95A65F09E3F7B1
+:10A58000AAD8B3A9DF5DD1CCCCEF3BDBD6DDCF952C
+:10A59000C7ED0BA47FE59E30E61940FB54F5423A27
+:10A5A00074DFEFD5CECF47B041303FC4EB8CAA2249
+:10A5B000313FAB989F95CF2FA0A247F66657D6ACF8
+:10A5C000B89E74DA8DF7EEF1720BC5782AFEED6D48
+:10A5D0003C5CF7BED6233DFD1FBC1E0A9CE05E45D9
+:10A5E000AE43379E35F029F844BE157C48799A5A17
+:10A5F0003E8CEF5E470DFFBA7EE2F7C43EDCF2DB35
+:10A60000611DF1FC83ACA6E7E57B5CBA85B9E17E10
+:10A6100077EFD0C44FF6FCCC8F7EFD8ABDD5941762
+:10A620006A5C0D7292F209F4248FCFC1BBB5308FF2
+:10A63000733B5D019CC79D42CEDC69EB8A97287E07
+:10A64000A3D7A19DDB057E33EAEFAE68788EE716CF
+:10A65000E0F9E311F33EE7ED8AB745AC57D1F3FAE1
+:10A6600078DCF70A05C08EEDC5DE50EE710A31FECA
+:10A67000BE426FC96AC23CF2D6EC42DC623B6F66F6
+:10A68000594D0EAC0F2EF413C5F238E3A7CCFBF6F0
+:10A690001508B7C89B627E8F2115E87A91A0EBBAA6
+:10A6A000975BE2C92FDB0BF6577C2FF69565564278
+:10A6B00050EE6957DDC81A498FD66DD53EE7F1C80F
+:10A6C0001B3579DD3E11C7D5DA5B75E9C2DE2A603C
+:10A6D000055C2F727BE126114750F2E5CF897C792A
+:10A6E0009827E1FFFC4E89E7C733F975F4931A0EFA
+:10A6F000EBE9FE2986D9D36322E3965D26B49FB4A5
+:10A700007684B63CF387F78B7F0E4DEAFFF85EDE6A
+:10A71000AFA13CF3C777873C8BF53FBD93F51EEBAC
+:10A72000D9BE7CDF77749FDAB97D510CFD9473FB41
+:10A730005ECAFA39D69F897223DCE75647D13EB00C
+:10A740007F5F1C9D033C9729CEE53EF76D5E88E256
+:10A75000446B687D1E48E779A9E7F7FEF503A493EB
+:10A76000F37BC18A76A15E8E25D9BDE29968BA2FA6
+:10A77000F5DC73DF1647DAA17FEF7C1AC47D81E731
+:10A78000E2580DC5D90C5D5912D911E31291CF963B
+:10A79000EFD96F427FAEFCF9FFC90B61BBDDFB4D0A
+:10A7A0006C04E98F47317F35F0EBE7EEC1739E67AC
+:10A7B00051A6815E1FBBF56FA4D7B5788171CFFE1E
+:10A7C0001CE7F17C2CAD0FE0A50EFDAFBEF0F1A7AC
+:10A7D0007F527C9C3376D27D80E7764923FD7224BC
+:10A7E0005E247E8FF6DEB88059A2F9F3E7FBBECD7A
+:10A7F00043FBF68BF65574BF427FF37E3B9DDF93A0
+:10A80000F77F67DE52F062E6FD977FD2F556E8FFEC
+:10A81000E7E95C2F68F9A027FFFFE956AAFF3ECEC3
+:10A820004DF05E24FF2765FC73CEFF27AFFB6E89DA
+:10A83000E26CFDAD7BD13FE9BCFB5FF797C5BAC7C2
+:10A8400059F1FEC373CFFD4F168B987F7FF39E990E
+:10A85000F1CFC9E7FDCD5B1BC7DCFC1C7B18ED0904
+:10A86000E3349311CFD7CCF14AF4FB07B371C7A2FD
+:10A8700010F3BD3ACB6231DF639E44E760E179506B
+:10A8800026BBCDDBB9189EBF5DB3D989FAC0889DC0
+:10A89000709F608144E7A6675B9D65688724EE65CD
+:10A8A0000FCBB41FC3F35667CF492DC4F64798EFBB
+:10A8B0009E51C857B38CFC1C8C33C710792F29FCD0
+:10A8C000CD3A5C4CE74CE8EFF60C7E0FC3DB63AF90
+:10A8D0007FCB03EFAF6AF13662BC6C7A96B702D7D2
+:10A8E00071FA1C5B01DA11B37181A0E9CF33B8FFB3
+:10A8F000341B3BDB111EAF91FC7C655FC733EC273B
+:10A90000EDEBE49BBA4EDC0C705B8FF038A751D8AE
+:10A91000434ADC6306D623F6C5A7358DAC9A087E7C
+:10A92000C813021EB6B8ED4E4711CDD31F87F3AC46
+:10A93000DF4FE79ABAEB2B3F54BFBF435AABAAAFE6
+:10A9400071A9EB1B4BD746F6EF6B3E332A0B241F46
+:10A95000E8F8C4FB25557EA9522AF0BDB68AD592E7
+:10A96000BDEEF0C89897CBF063A9F85EA7F223C3B9
+:10A9700078E278A915F9BCD3CAD882C87875BB88A3
+:10A9800097B56708FFDE21E2E26E8FDCDBBD59CAB6
+:10A9900078EF2E9D20615C1453B67ADBB7090A78F4
+:10A9A000DF4D902B94FB20D16E3F56CBE3207DE111
+:10A9B000E1ED29AECC8100E79CBD4015409765359F
+:10A9C0000B8CC8D773164F9090EF8F4D0BE9B0CC1E
+:10A9D0001F08F38072EE0FEED4EA087C1D11F3D845
+:10A9E0007C8FDA4F53CAAFC4FB3FEBF87EEB9FE39B
+:10A9F000E5CCDADCC8FE669EEF1FC7E54ABE8119CA
+:10AA0000F4117133BC478DF2196AF83AE1F76744E3
+:10AA10007CE784C0E766713FCCBB4BF38D0B22DE35
+:10AA2000C765F2759AD107DEE23239DEC01E277E95
+:10AA3000DD5C2505F8FDCA1E0BFA134B05FF6D16EC
+:10AA4000E75267E2B95D78B474EC52F22BD856EE57
+:10AA50005798E17FB85F51103468F6513AE95EA328
+:10AA6000991ABF619AF027A6F5734EF44286259C89
+:10AA7000D7007272DA404E4FE0F7CA741FA5A047A4
+:10AA8000651DFAA21FEDF9DCBEE8C1EAD4333C9F94
+:10AA9000A1F819F9A57C1F24DFC8F97CF361EE87C2
+:10AAA0006DAE3A6F477FF38426FE3BAD29BB6A50FB
+:10AAB000C4BEE56BD34C35FC3E4DEEFF1C13FECF00
+:10AAC000E6CA91D1A596F0FA6CAEFC9ACE9574F3D5
+:10AAD00003FB717EC837713F7E6665149D7B9AE9E2
+:10AAE00096DF5FC6EB56D4EB65556D5948C715FA2E
+:10AAF000DC47FE059EBF561545679F14F9F4C64313
+:10AB00008F65A15FEADEB1B40243A405CC77279E2E
+:10AB1000A39A5125B9C92F14F1879378C60DFA2746
+:10AB200006F87DF4FA2A2ED713B7DADA26C37A8D1F
+:10AB3000C814E7F6AA78BBCD356AFAB941C8EBA5C7
+:10AB4000A31E3B3208CA1BA72D1C85E38FCA94792C
+:10AB50005C02E988CE1F1F3D886AA5AEA6807E6F85
+:10AB600046391FADF49FC3DCD523A570FBD35B1E14
+:10AB70007B10D1B4B472C1A860049D2971FD1BB7CC
+:10AB8000ABFDD7C422B5FFBB34A07E3F07FAE0BDC2
+:10AB9000F073FAA1C7F24CA0C7E1617A54BEA7AC2A
+:10ABA0009B76BDB479360AFE3B4AF495684FE4DBE8
+:10ABB0003DBEC87DE09B043E95B263EF7FFD7919F1
+:10ABC000EA453C6F2CA312B64DC4ADD7DABAD222F7
+:10ABD000544365E6828358BFA611EAF07E5E26BF25
+:10ABE000D76EBEF5C30AFC6989EB9CD28B582E90B8
+:10ABF0005D93EC50AE10785F9453FA228687AADCFE
+:10AC0000D5741F6E857E636C1EF2C7567E1F01C809
+:10AC100021BFAE973C9852306222CF89979BA355B3
+:10AC2000E7CB2BAC36557DB23355D57E8AEC52BD81
+:10AC30009F9A3354F5BECA5DA07AFFDB4C9E4FFD50
+:10AC4000E4239FBD7A3BCCF3C9317AFCE50C760452
+:10AC5000F1E208E305E0BD1FE13D32E6B62CFC5D04
+:10AC60009CDB32F9EF9EBCB175F45BB7B3B07C7B73
+:10AC7000BB8A71FA34F078C92CC6F9F16D26E87AEE
+:10AC80008A44F19F5942BECDF4AAE966C658E387CB
+:10AC90005128B744FC645AA576DF384470CE29E1C8
+:10ACA000FBBB899AFDA93942EEF547674F3EF26D2D
+:10ACB0001AF2E7A64C755ED79312BF3FC1FF16FF8D
+:10ACC000DD8DBEE458B7FCD2D0D76F055D2925C80D
+:10ACD00087049413F926753BA57C17EC53038CF37A
+:10ACE0005EB399CAF79BAD54FE67B393CA0F9B65D9
+:10ACF0002A3F6ECEA1F2B7995C1E2636C13A46ECC9
+:10AD0000332656794D3FC6275AF97624A423FE38B8
+:10AD100032FE967897259CAFF0874C7E3EEAB39240
+:10AD20008F2D526E984E3B421F59D03EA865013A76
+:10AD3000BF7A0D0BD279D6F92C44F5EBF008A83E7A
+:10AD40009CCFB0887928CE9560F55279043F9D0656
+:10AD5000F492F99FF7E2BD5679A82F2D94A7B92E4A
+:10AD6000920FBE13789B92E979217314E2B7F183B5
+:10AD700099281FC71B19DA7F4CDCBF94C8F7C8D8C5
+:10AD8000678F8C8E5ED88BDEB5672E7C2D73542436
+:10AD90007E7C266CF7A4729F8FB83FCA903C4865B2
+:10ADA000BF1C17F89D9FE1792393F67B1CE2F723E4
+:10ADB000BCCE1FD5177637D92FCA7C40F24B183F2F
+:10ADC000FD4AE87FA57DBE09E4287C7F9ADB67C247
+:10ADD000BCA7B22D05D1A15EE1F77D9A99A4869F0B
+:10ADE000CB114E4F7DADAF4217974A570AFDB46461
+:10ADF00078CEE3BC0DE25E2783BDC6897863D65961
+:10AE0000441FDF654A3F6A07E4957CBC7124FA253C
+:10AE100045FC1EB0BC8E4E0BCA8B37D0EFC9473DE8
+:10AE2000F959D94840E9B10E6645B970A428FB35F7
+:10AE3000D46B47B646C978DEF933497E0DF9DBDFBE
+:10AE4000A6A77BBC008F749FDC924A5B21FEDEC20A
+:10AE5000F47146D283277D2EFABD8291591C9E53F0
+:10AE6000C27EF283FD81FDA64FBBED839500C7C96D
+:10AE7000AA21F8CB0A40274BE32F47FBE2A16C1D28
+:10AE80000F97BA8D64376DD193BC79B36AD25B8B5F
+:10AE900023E4D8498D1C9BC3C98D9D64FE24DCE747
+:10AEA0009B23F4E4AC1A8DFCAA52D76B34F22951DF
+:10AEB000ECAB6BE596563E0DCA8A0BEB417D4FFB22
+:10AEC000EA94A52B783BCAA94A89F03413FC3E5F6B
+:10AED0003EDA0905C69316A40389E840915333ABC3
+:10AEE000C01F2CC272C14833B42F07FF04FDD49990
+:10AEF0007BDCC62596483A5B6062E8B76C5940BF78
+:10AF000037303FC33B2A8BE8C16BBD1CF0B1792FB2
+:10AF10005FC7FCADEFFC19E7BF64CB576F0E02BCF7
+:10AF20008FA8D45B513F1EDB3A3A0EEDAC37025F7F
+:10AF30003B586E24BD3752FE43D9D6AFD2907EB572
+:10AF4000F2C05FC6E877B0CE482C88BF4B74A634F9
+:10AF5000B90CC73F936932F07208AFA79698797D14
+:10AF600052259615FAB12FE0BD70E7ABF8FD59AF49
+:10AF70008BBCD3AB4216BAE7AF3EA4FB300AF368F2
+:10AF8000BBD4F7BC4CB8A0BEE7A594A9F56AB959E3
+:10AF9000AD57CFBC3C8FFCEB0AAB4BA37F876AF469
+:10AFA0006F81AA7E5548E747FA9A9A3346D5AFC3D0
+:10AFB000C472703DBAA418FA3DA66AC6F7F3A74357
+:10AFC00089BF7B7315E3E738A6B94B55FDEAC1A1EC
+:10AFD00046FC607BCCF7985E3245F5BD7AEC0FCF2E
+:10AFE000ABCD5E75BFA6FF227AB8A2E97BB2BF0BDC
+:10AFF00082EDAAF7230F77A8C671775ACBD11D2D02
+:10B000003CEE7E01CB3598379600AC11F296A35BEF
+:10B01000527CAAF1052CB579C5B7E9D89D1897B926
+:10B020004DEFAB43B9FFAD2E9043E7C1D32765E2A7
+:10B030007E49B56D2D1D1F9EC67CAB90AEC67C13A0
+:10B0400068C1FA84EFDB294FB905CF7927E0BA56FA
+:10B05000C5BE86719E7689ECEA7A8B38E76D6FCF34
+:10B060008BFC5D93EE73DE4E8F7301B4BFD33188DA
+:10B07000E21DDEF2380FEEDF2EFFE365747EACD604
+:10B0800055BA292B299C37C61CEAF300B52ECF2EC2
+:10B09000CC0F8A29D7F3B8CA6423C5556274DE7809
+:10B0A000715F03C5EF4C938D948F9B3C80CB9D9833
+:10B0B000FF6032E6BFC624FAF423B0DF5489213F93
+:10B0C0002AF0CDA8E2E7C47F9B25FC71A177AA9363
+:10B0D000DEDC49FB8903F8EF251657C9878C68A089
+:10B0E0005B0D56949B89C7BDD61100E71E4711F131
+:10B0F000ED9EE39DE32419DBCBD43EA5B2F4E652EA
+:10B10000FCDEFD7AFA5D9D3DD689B1D89EE50CA1A5
+:10B110003CA69B443E68E23CF91DF4ABD861231386
+:10B120003F1B43F3B00E8BF9779C47E271CF329A05
+:10B130006F8E45C6DF7501F85CF83B491F37E35D4C
+:10B14000707DEB998F372625E1BE6E75A935097F95
+:10B150005FA47A935EB9D486B697F067FC78FDFA5F
+:10B16000D727025C3BBAEB2CC800EF1B4C4C5C06AB
+:10B17000C15834D4ABA5EEF6D327E6523C4079EF64
+:10B180006725747E59BC5F42EFAD9AF194F15FCDB3
+:10B19000BAFEF57516C493382768B026513EE1F71C
+:10B1A0003F489179B6317AB918E973A14ECEC3B24E
+:10B1B00028DEF706D28755E71E82F59547477E8041
+:10B1C0007E12C897935B50BE4C3492DC5D91C3EF06
+:10B1D0007DDE6392FF781CF7379362287FC678F78D
+:10B1E0000DED1D30EE0AEB7F117F01FDD279F7F3F3
+:10B1F0009D3A3BC63B17EABBE7E3C1BB563ED2854F
+:10B20000EBC8770BC3F3F1E079C20D11F3C3DF3E56
+:10B210005924DA5B06DC3C7D0DD2FB6233F9BB3787
+:10B220000B1EDE6067AD98D7F975CEE573F0BB5F96
+:10B230006F3452F2F31E7C897AD11943E7368F744A
+:10B24000EA3C18B7F13B62DA0653FDBC19E333ED73
+:10B25000B0DE1E9CA03C4435EED76327FF47368EF8
+:10B26000D7A9D321DE16854C4C46F96160C12890E0
+:10B2700043C56317EA07E6F27BCC3DE0AFDDE0F2C1
+:10B28000FC7716E5952871BF7FB9A4B8DF0AC6E53B
+:10B29000D78A9255B928DF574C94483FAF68FA8651
+:10B2A000F0CA0CFC3C8F292A10588D74FB6C348F2B
+:10B2B000675A3CAA7B1EEE91B9DFDF9CE0B9474E8E
+:10B2C00042F9F735C93FA5FF1991EF80E7C431DF97
+:10B2D000BEFE6FFAEB30EE04F2731DCAD77A76C069
+:10B2E0007453849DC5DABFEA9697F9BAB01D66B863
+:10B2F0005F4FFA453B2F83AF8ABE572D5967E31D39
+:10B30000A3B7CAEF4EC77C9EEA68EB6CCC072A97BE
+:10B310000F4DC7FC9FEA4CEB6CCCFFB9F63703BD71
+:10B32000544FB53EA07333F60BF90A2FB57759DFAA
+:10B33000C2FA6D0344BD40A18B515E0FF25D1CAF9C
+:10B340000F1D30CAEBA7788485CE0B9EAF8CA6DF8D
+:10B350008FEC0BEF339B9E55F90F3DDE8BDF7BA30C
+:10B36000C42EC0F39753F8EFBE28F916CB6764508C
+:10B37000BEC515420EE2EFE994D8C3F9CE5F7EDA7E
+:10B38000B904EF8999B9673DDD573FB3691F7DAFB8
+:10B390009E815501CF6FCAF6950E1885F770843ED1
+:10B3A00040F9BA7CDA1B43E83E616B17DD4B6E1443
+:10B3B000E7BA808F9C0B90FF1C06D2EFB5CC47FEFE
+:10B3C000C62CCB2726BD0EE36E6EF243B4F2BC61F1
+:10B3D0006C34FF9D3F26D1BDAFEDCDA0EF8025762B
+:10B3E000377750E9E9D84FF9CDB59A3CE6FEECB98C
+:10B3F0001EF9D51AB9E251F28C35E75C1F4AF0EA22
+:10B400005DA3F03C51790AF7A3F83C7A7CDF32C89F
+:10B410008878D0C2319305C9AFEA0F9EB3719DD72A
+:10B420009AB2F1778EF8FA2EB7BB06633FC0F70ADF
+:10B430008E6FC0BF1ECFA57626737F62A78CF2E009
+:10B440007C8E99F6E362861DCFEBED7792B5F87BA3
+:10B450001FE64A7AC81032E13D520DC7F93D0A1580
+:10B46000FA7AD283E73B5C2C320EB85ED04982F880
+:10B47000FD2AA01737D28B239B0529EFF14F2FEF21
+:10B48000C4BCC7F5421F2AF4392196B5637EA54294
+:10B4900047405F6EA42F859EC2F9362FECC47C9B7B
+:10B4A000B2011CAE3D315CEE75FD819F5BD2C2F9ED
+:10B4B0009B014A5C560DEFA31709E7A3FF2038153F
+:10B4C000B9A4E049914B4CC8EDDA1AD7B60D52B881
+:10B4D0003EA3CA45FEAA02674FFAD92EF7463FFDA2
+:10B4E000D18D6900FF9D33453E2A7029726E4FF859
+:10B4F0007E150117BF2F370C17BF2721A1E96992CD
+:10B50000D3FA38FE3B68B3729C74BF4B42E779862E
+:10B510007EC16B0306D27712DABFA3D4D184A6BD55
+:10B52000D4BE3F3E54F482761E8A9EE8391F99BEEF
+:10B53000A3D51FE398B82F137592847E80FA3ECC72
+:10B54000523CD9A0F2037EA689BFDDAE6A3FD9B9CD
+:10B550004AF57E8ABC5EF57E6ACE26557D9AFB2131
+:10B5600055FBE9256DAAF7D5E61DAAFAD85027D9CB
+:10B57000DB479A2BC94F1F7FAA8BECEEA0F0E70F99
+:10B58000087FFE20FAF3C0972FA23F0FE5E1663750
+:10B590003D7FA5B984CA579B3D5476367BA9D4F22A
+:10B5A000F3554F5D6D40FFA6A4B395ECFEDF67FA3F
+:10B5B000D2506F4ED7055AE25C78AF1EB7CF999341
+:10B5C000DB978A7D70E7FE31AFA37D99F8AA9E458F
+:10B5D000CB7DEB93840B7AE68988DB27547531BCED
+:10B5E000A73941C481FE3F8BFE2018008000000077
+:10B5F0001F8B080000000000000BB5390B7054D7FA
+:10B6000075E7ED7BFB117A9256425F24E0AD56C898
+:10B610007210E2E96B2144784848410E9F95A08E54
+:10B62000C0225E7F011B2159CAC44A9C997D7409BE
+:10B63000C694CE28F54C8B5B3C5D91312113774647
+:10B6400076314329E0B5E3DA4ACDA46BA3C438557B
+:10B65000C99A24141AC12E981833F68C72CEBDEFF5
+:10B66000B1FB1614D9CC74359AB3E7DE73EF3DF70E
+:10B67000DCF3DFB512EC72E60074CA52B8A00A40DF
+:10B68000516C007900DD809F1A842EB0E7E622EC31
+:10B6900016D420B0711D7268127CAE7C80BF02FE91
+:10B6A000C1F1B01FE99D12E8B49FA889F075A2CB43
+:10B6B0009D2D4103C0062252905E06988F749BE434
+:10B6C000513B7801368EFD75EFC3380EBBF47A5FBF
+:10B6D0000611AD745FA80010F4DFD8A616024CD195
+:10B6E00067F9ED104002A2A3CF94487CE3977A80DB
+:10B6F0001F0A6A44437EF56C497D1987DAC4CAACD7
+:10B70000686562DD9FE6DB189D89AFF3AF06693699
+:10B71000C0DAA02E66D601C4DF07F520EEB57DE8BD
+:10B72000133E2EC11EBA4F1FEED54472724BE17B01
+:10B7300032711E7ED44AF4DBC7152697BEC69D958E
+:10B740005045EB3E65EBFA560A1F3B11EF1BBA0E54
+:10B75000522DF1F14A90E8AF9D05D589F4F74D8659
+:10B76000A22FE0398DF1E1D62CC4977E110A12ACDC
+:10B770000E8F82E432EE85FFB563C740AA48E0260B
+:10B78000DF2702DD20D9014E05FC0C86035B415A00
+:10B7900000F056A09FE16F078618FE4E4067702CA0
+:10B7A000B087C1FF0C0CB3F9D381FD0CFF6520C439
+:10B7B000602470988D3BE6037BFF76C5CD20B8569C
+:10B7C00028BE45246E0E137AA1E890A417DB0BFF68
+:10B7D0009DDD7B26FD984E1F00428A80FB6DAA707E
+:10B7E000C15E0FC083306C5F8AB07B8BBE68A77070
+:10B7F000F77AB111FC7660503A1FC5711B0830858D
+:10B80000FB6E90CBEC88C0866EFBF96892BCD78348
+:10B810005F25FAAED5D67130D69BFB3AE62B4C8F1E
+:10B82000C456111AF1BE4EF169B55FFEEAE7399CC4
+:10B830002AB38399CFE3EF622F0418C2F3ECD9BF88
+:10B840003E14461676C9E3DF166D779043AE14BFFB
+:10B85000B5BE14E0D522BEFEABF207A0DAE9DD6783
+:10B86000E2AFD5A3ED55EA894F37938BF99E8E85CC
+:10B87000FC3DDBC4C943FF44FA7F245D7592AD7E75
+:10B88000312500EAC7775C5C0FAE475A0BFC49765E
+:10B890006ADADF686094E9E56B81630CF6B93F61B1
+:10B8A000F63429D81EF255DE7EEF3E1BF85FC3F159
+:10B8B0001A27B8049293A7E525E2AB4D6C8E687405
+:10B8C000BE5B62F6379DFEF40D5D65FB4F3B8FFB63
+:10B8D0008FE23BF79DAC773F2227C6FF47118C7B59
+:10B8E0004BEE0BAE845CBEAC9E2E8B775BEC7EF990
+:10B8F000677E8BDDAF806D96F956D7D316BCCDFD34
+:10B900003D0BFD370A775AE63B94E72DF3DFACF8A1
+:10B9100091055FA3BE68A15FD7386299EFD47E6AB4
+:10B92000995F2B8246F25DE7EF60EFB409ED95F485
+:10B93000EA4108337DDE0C51863F842A40F0615095
+:10B94000187C143407CD3F0E9A9FD195F8CFD0FBC9
+:10B95000D885A84CF3978F7E5EE647B98AD9E3571E
+:10B960005E80DBFDDC97F56BA63F33FDDB6E076C7D
+:10B970001D45BDD895EDD0492FED793923A227F18A
+:10B980001E7F30E2DE74F613ABC607437E63AFA7BB
+:10B9900003A01EC5326685047C72EDC4BB67852A90
+:10B9A0003293721BF9B54143469A4B0E8B385EDBDE
+:10B9B000A3FED720D2C369111690DE837D3279DFD2
+:10B9C00036095D2CF93F49ADD8BC28717ED086FC84
+:10B9D000A21C0E237C15F9CEEC894A4A92BE8187BF
+:10B9E000F3BB62E34AA0F826F56800389FE9062D0C
+:10B9F00084789B0BEAD268DF2F3EA9A47DD77E8690
+:10BA00000F867ABDD70E617AB782C66A0190EEC5FD
+:10BA10002C4DF0A0FCF5E79AB32FA05F05F413536B
+:10BA2000F36FC76B4441A37BC73BD242073DB7EBE3
+:10BA300073B6C1CF76C33E6A6683AB90CEF7932CC4
+:10BA4000515E1DF71EDC8BF2AAF0E41876122FEF80
+:10BA5000A2B882E182D699717A320D985DAF3F9695
+:10BA6000860139B17F89279BD1AD775D67FA668EF4
+:10BA7000EF18BA69B1D71D95FCFE3541A5F669846A
+:10BA800083143B96E0FBCFF1CDF7E0FA6DEFBDE21A
+:10BA90002856E8BC03DFFD0DF9833199FBA3D37968
+:10BAA000ECAE3101BA4793E4BCDE75959D07306278
+:10BAB000D18F336B3EAC227FB5FE48BA4EEF6CF2AD
+:10BAC000F581A02C223D36FD57EFA94BE7A094FC51
+:10BAD000D5D573CF92FC5E771AF9C54D363FE0F5A8
+:10BAE000D791FC5F1BB331F9F676380F925E82A4D2
+:10BAF0002CEACA48C82576C9CA572A7FE679265F44
+:10BB0000938260F18F2B8CF779C988EB9733D5CD71
+:10BB1000F42E978F16DB7421317E263B52952DFF34
+:10BB2000FFC5F94D60E47DA3C1456E64091EC3BC29
+:10BB30008FE9C1DDC577537F4003C58D7C08C67989
+:10BB4000809792105F66E0C10C0839905E90DFB973
+:10BB500049F6BACC8040468074CD06FFBB857E2076
+:10BB6000FE5C30CCE05E4155082E177C12B0F342EB
+:10BB70004C7FDBA1BF84C6832BA2413A54CA8161AA
+:10BB80007131C0C5DCAEBC9DC4653EEC06C42587E2
+:10BB90006ECF27FBEFCA525F5612F25A6F9CB71551
+:10BBA000FF9B512E52362812D26FC57CD38E72DD88
+:10BBB000B065E3DF5612BDBB99C9B1CBB807AD2361
+:10BBC000393E70BA7F0DC5EB6FBDF977BFD470FCFD
+:10BBD00052CE7003F1F37F918355FF82344F9E392B
+:10BBE0009149F3DBC39176143DEC8038F3BBA6FC9E
+:10BBF0007B20C2E0B721CEA01FDC6CFE1150197C67
+:10BC00000C7C0C3E01FD0C7E5474A0172D003616E2
+:10BC1000ECB35F87841C9ECADED540E7B85BF62F85
+:10BC200020BDD35BA082F2A02157661560427B2322
+:10BC30008DC3CE6C5917B3D83CF39FFAB9B45010EA
+:10BC4000F57C0DF85F20FD1FB7F7DFC7E5DBBF9878
+:10BC5000F42196ED0001E96379DC7FE89721F43265
+:10BC6000CA396637D65F55185ED75AC3E23ADC50F8
+:10BC700058BEBF94F2125722AFA95B6863EB618A8A
+:10BC8000D32F8B4B963CA66EB18DED079FE3BC87FF
+:10BC9000E2AEF417F39C0DA5394CDF96D0007EADD3
+:10BCA0009B6DEBA7B8C23E784EB0307F84F21D1377
+:10BCB000772AEE11F27BEF7978DD11CBB4313DC1FB
+:10BCC000CF065703F1CBDF75E989F70C7DC4C22994
+:10BCD0009FDECB1897C26FD2F80E239EA01766F98D
+:10BCE0005F33E927C9EB98359E40E14289D6371981
+:10BCF0002C98F598807BF5E4903E47447ACFAF438B
+:10BD00009C410DDC2CAEB580CAE04AF03188FACDFA
+:10BD1000E02A1866F07E18657035441884AFA96A69
+:10BD20000D9E6F7385458AD7003F705FC0D0081D98
+:10BD30005B6C531422BF05FDA3F2CC72B96CF8A55D
+:10BD400099E58206DDF065E4E2E7FCA5CAA5A482D8
+:10BD5000D9912917531E69102A24392E83A84870B7
+:10BD600039F038BF02CD91F056D018DE36A33CC270
+:10BD700041C0FB3546FD92BFF20EF268E57A62EAF9
+:10BD80004D9B2833BDBB26E78F38719D526A33E245
+:10BD900022AA2EBEDF809BDFB3012AFEA119E9EAA9
+:10BDA000C7EC9851031C0F68F03BB4816B98718409
+:10BDB00069FDB8A8EA48DAF45828E842BC680FB828
+:10BDC000E96ECE421B28497A9CA6CC0225299F4BBE
+:10BDD000AFC8B1E04D6322AB5733D4399675598D56
+:10BDE000A5163AB44F91F83E1E05F847E4FB08D972
+:10BDF00037BD9BAE452A1B12FE365BFB9A659F65DD
+:10BE000091275603C6F3D9AB6A2CE3709DDB5B2305
+:10BE1000FED13B2D857EA6D74D93563B74C2BEAB5B
+:10BE2000940F34468781F42D6D3CC92E695E6EBF38
+:10BE300044FB3B21691DF2373451BDEAEDA47DC2BC
+:10BE4000A519B92CAF298112B267F33D52FD3EFA14
+:10BE5000B742F24375E92D9F50686C2ECDEF9430B8
+:10BE60003FA8AB6D19F422BEEAA087E34B5BFEB599
+:10BE700014F1FB0F96754A4BC89FB4D4DA55809DD8
+:10BE80003B1774AE443CF83EF77FE02AE7EF6AD4F4
+:10BE90003BD7E4EFAA6E7ABF125925BD79CE8177E0
+:10BEA000423E5C4E0E452FAF2B8F0790FE9E049FA7
+:10BEB0004E27CF17915EA7FC2EEFA2BE91FA0E7609
+:10BEC000AFC2F467DEAAF05B76856C4CA9A57ECA8A
+:10BED000BC397EADB43EB13FF2414A05C5061FE60E
+:10BEE000BA25B24323F941AEA796EEFD9D39BE3681
+:10BEF0005A17CB7031BF6DD21D36F2D225D2B03871
+:10BF000028D338F0BA741A3858AAADA17D52C74D5B
+:10BF10007B1550B83D942F3CA9BA24E6FF9BDDB7B2
+:10BF2000F24EA45DF2982692CB6FE8EEFF39C13E47
+:10BF300031FE04E9474FA97F13EDDBEBBB32AF9A2B
+:10BF4000F2F33FE00549CE50C2ED0EB8BF3E79EAAC
+:10BF500017CF1673D407497EA5EFD4CD4FFF1BFD35
+:10BF600050DF355925F25826BFE7D2132F0E32394C
+:10BF7000806CF1A3A61F6A3AE60C931E2E3D71EF6A
+:10BF8000E344B7ECCC8497F2BBE513D120B5AF62A4
+:10BF9000273F2CE6F66FE433DA0DE16EF219F40F69
+:10BFA000CCBE077E25B27A7580121BC25F15423A5D
+:10BFB000EA4BEF98FD63279EFFBF469C454F2E1727
+:10BFC00035F07C82DD0F229924A7AD071E5D4DFA66
+:10BFD00001215EBF2BF8477676DF59AB7DF58E5A8F
+:10BFE000EBFB3EB237EA5F25C7BF3BD8D35EB22733
+:10BFF00012E05C98CBF8177BB2FC77C8534D7823DE
+:10C00000A0AE7A1BEBB17DA00DD3FBD54BA0915F09
+:10C010006C137FC0EC61606E658D932571DC0F6ED3
+:10C0200049E3F779B04460721978490499E84E3AC7
+:10C0300042643723E8361B497FEA9E677ABDC5E034
+:10C04000CDB49F6D7B0450B03E8003B3994E2D3E1E
+:10C05000E4647A3E72C8B987E4B2F850814630F899
+:10C06000C3593AC59FC50E5E7F04D3E27304CA3339
+:10C070004E3A6C9417509A20E0398B4BE3A594DF2D
+:10C08000BC61F8EBA091DF80526EF1DB0319E5058E
+:10C09000548FDD9A8F4A16FB0F1A75461DF147F52E
+:10C0A00045BF9DD58F03699CFF37DF7F209DF2FE42
+:10C0B000D7255FBA5B263F5F9A0577E87798B03E51
+:10C0C0008CC2FF0B7D8BBAF17D11D2DBBAFD1297CA
+:10C0D000478A9E511C714242EE89F85366893FD7C8
+:10C0E00080EBE1B5120851DD60BEA7193FF27CD6A6
+:10C0F000B853D06D8D3B457E6BDC29DE6A8D37737E
+:10C10000FBADF166FE90358E78746BFCF0EE69B293
+:10C11000D02F186EB1E0F7ECBFDF427F6FA8CB8263
+:10C120002F3CBCC942BF68F411CBFCE2634F5AE616
+:10C130008FC328CB13A68B7BD5E1010BBD19F76A02
+:10C14000C7BE7FC7B8A7E31FB347239E37E23B5064
+:10C150005F6FBAF89716550B29DFBEDBF8075EC391
+:10C160005E8DF8F727ACE8C87F39491F44CA0F79BC
+:10C170005E996AAFD3E995E977D11FAF2B457DEA88
+:10C180004BFFA29CF6EB755D99578B70ED984D2790
+:10C19000BD582BBB3E26FE51DF2AA45CD2A3592AF0
+:10C1A000E53D663CF21976B14E96985F5B9BCEED0D
+:10C1B000661D0E37917DA7D477823C7653C8A43E86
+:10C1C0009590D2A74AB3F4A966EAA7D747C216BC8E
+:10C1D0007A1C44F2E3F5BF578219784EED04EFCF95
+:10C1E000A7D69375517F90C2C47D93183614AA27A1
+:10C1F000393F4D9F8DFE9CE853EB1FB8B88FD59902
+:10C200000EC3AE52EBCE676C589F62BC7B46F4B354
+:10C210007CF486EDB63AB4506279A89FE5A51B8BF5
+:10C22000FC4D5EF43FEFDEAA4F791D0A300A14F789
+:10C2300063F49D82977EB05393A99EC2EF73D0B8EA
+:10C24000F57FEED4292FCF0577B481B767E8D3E91E
+:10C25000F5B7D37EE7055E0F5E5952BCBB16F96C8D
+:10C26000A7788DE3053DA3E0E7FDA26F78EB6FFFB4
+:10C270005D2515A6F66D8F04C20CA657AAAC5E48C4
+:10C28000ED2FFD919858C2F6D5997F1912785FC6A7
+:10C29000A897371B728FDA80D7837BEDAC5E33FBB8
+:10C2A0000C3DC63DCEE3D456F4FB9B8FBDCBDEE305
+:10C2B000A9C249A37FD3AFBA71DDA325720DD51DE5
+:10C2C000A0D5AA5D96BE43B1F855E2F44CF77FAA1B
+:10C2D000F092A54F05AFF0F833FDFE3AF3C749726F
+:10C2E00060FB9FEFE0F1EA7C47710B6426EF7F85EE
+:10C2F000F5BD36F7BF6FD1EF87863EB2E8F3C3FADC
+:10C30000C796F9686EDC5E8CF78F1E2D6A7F10E58C
+:10C3100079F9756703BD07BEFF2E6F527F2BDA7167
+:10C32000EF4AC8FC32F7FC23E363221061EF6BDEB7
+:10C33000F35CE02CC3A3812883A9F734FB042674A3
+:10C34000BC05CC2FC485592AF51753EDE7199B7608
+:10C350008EF4BEA4AC94F77B80EBC1338376564752
+:10C36000A226EF7F18F11B0FA457EF456C62457EA4
+:10C370000BC5F589B90E89C3728E1735BA38DEBE82
+:10C380008A60CC2EEFA13EC384C0FBD9F717F95FBA
+:10C390002639F43D19AF227BBB9217FFD486E7B64E
+:10C3A000E7F80FD3B880EEAE88F5BDF472CA932FCC
+:10C3B000DAF42A016DFAC68F3F67F9FFC559FA15FD
+:10C3C000403CE6BDC1EA838B0E6E87BFF57EC8ECAC
+:10C3D000EE57B8994479C57181F52306B3FD47C876
+:10C3E0009E86ED10A6FBC4FF4D18A1FB831C759023
+:10C3F0007E9AFDC8981D21F501D3387CC3CBF3A1EB
+:10C40000B097FFEE60C25E57D441F1E16F0EBCE61B
+:10C4100023798DD8149E774348A377DF71EC696642
+:10C42000C7BF35ECBA4DDC574EFDF06BAB9D40FEFF
+:10C4300018F9D36C645FA79CCCBEF2F1AE9447FDB3
+:10C440008783D71D356F38C34272BFD3EB61FBE7DB
+:10C450007AD143E3BADC6FA68582F41ED1C8BCCE84
+:10C460000C76AF877CE46FC681F5372F531F98F7A2
+:10C47000013407E25D470B585FE0032FCFA77A7FB7
+:10C4800071FE1CF13FE0F5FF9AE47DAB9F0A910B32
+:10C490006E2FE38FD51F4E1176093933EBA7D91FC5
+:10C4A00035F1336B9E2B277DAF1105C6572AFD67EB
+:10C4B0005EDE8F98B0F33C9035422D7C6BD536EA2A
+:10C4C000D37655323F32BB8CCB3D554EF6322EF7EC
+:10C4D0001AACDDA80FEE9C8531BB667AB95F7E3C55
+:10C4E000F2F79508AF64280BC8FF9AF746399C25E8
+:10C4F000FD30E56DCAC1DCC7E413CFF7D3EF0435D7
+:10C50000EF9DB617E0BEDB7EE6A1F6CCAD7B997C55
+:10C51000EE9EA34D79937EFF46FD62EFA277A4B114
+:10C52000F7EE3DF5D1B96771DDB69F2CAA253D31F7
+:10C53000D7A5F28B7CCE25FE3EB085597F10F994AD
+:10C54000CBF2A88FFD413EC9D7E4F76EDF2736371F
+:10C55000C27E2F8A8DDC9CA7E0FA5EE377965EA30D
+:10C56000DF0347ACFD1D94AF4EF56D6A5C014A19BF
+:10C57000F229BFE1F1C369AE2F912CEBBF37CBE7B6
+:10C580002DC37B1E35FC01D287C8EE29EFA0F872BF
+:10C59000ABAF6CC4A37AC3050967791FB99E202588
+:10C5A0000495592C1ED599E7215FA40FBB059DC5A5
+:10C5B00071B3DF1434E2B6F8E820EBC335C2308340
+:10C5C00036178F530D25B22AB2438D3ED2F3EFB00A
+:10C5D0003AF2CF3F65DAF7B021000000000000001A
+:10C5E0001F8B080000000000000BFB51CFC0F003C0
+:10C5F000099FE142E59F1043E573A0C92FE444E59C
+:10C60000FF6047E5B7A0CBA3E12646FCF284F00922
+:10C61000A0FE8B407C0B881F1330CB9708BBF6998C
+:10C6200042E854203D1D88F70371872E0343B93E2D
+:10C6300003C34D203D5D9732F7A2E37E6DEA9A3742
+:10C640008A49C3932C50F9858E0C0CB39D1818EEB3
+:10C650003943F85D48F25F8062458E1076AB350352
+:10C66000431990DF6481DDDC36A07C39509EC5051E
+:10C67000C207009B5EE59168030000000000000017
+:10C680001F8B080000000000000BED7D0B7895C5A6
+:10C69000B5E8FC8FFD4A767676C24E0810927FE7A9
+:10C6A000014113D884F09062BB09118306D9282A6E
+:10C6B0005ADAB30354908746A535B6D4EC900701F7
+:10C6C0000306811AAD0737905AB456A382458FF6F8
+:10C6D0000641C56A299C23D55ADB1B5289B1A55E48
+:10C6E000B4DAFA7D570F77AD3533C9FFFF7941EBE7
+:10C6F000777AEE776F5A9CCC3FAF356BAD59B3D696
+:10C700009A351397378BB16CC6CEE1CFD718DBE8DB
+:10C71000600795498C79DCA1A39506E419FC5CC2FD
+:10C720005823A6A3E05F5CD5D934C61218FFD132D6
+:10C73000D5532E1F636714A89C061F3252A9BEEE64
+:10C74000AD6251AAD1C2D8544C0D6724C99C8FB098
+:10C750004811630E278BB617325627FBC79F00631D
+:10C760002E7F68EF6685B131CC49F5F5803BA6C1D7
+:10C7700038BABF8545BD385E740CF553C12CF03016
+:10C780001666388E23BD20390AFD322F8747CE4FDB
+:10C79000A60FD7544DD4F34D79075BDCEEC5F67187
+:10C7A0001ACF71378B8F80F1D8E7D7185717F5D587
+:10C7B00073281C4E996FC37685FDE16EDB363763B7
+:10C7C000197C9F22E0B7C329DBC33CA6D0FCC4BCC4
+:10C7D00024FC6DDBC671F8038101E177B8EF98A8FE
+:10C7E0008FE883577E6F489B66440B0522D219FE63
+:10C7F0001F50CFD87683B56840D7F40A3586F49AAF
+:10C8000050668C5A0A452E85D3F7F79E6819F6E3D1
+:10C81000548D5215BE05DBD80607B46B10F3BB4C24
+:10C82000ABF074017C3B2239C94B215DC514A2B722
+:10C830001DAED61A980BE0F59E1A37A57FFBDD7862
+:10C840009A87BD9E4C1FA8E92C32D3E181E88E79EE
+:10C85000E34A188B05D4503E8C9F51593FEA26403D
+:10C860008163AC51ACE15C562A3A4E2A41E1F35A5D
+:10C8700022E0003C2EE17C25E81F90F804784C78FB
+:10C88000F08423617FA1090F2C125660BCB47D2C6B
+:10C89000D4C1080FDFC27E7202307FC80717B5947B
+:10C8A0009AF100FD7BF2019E9DAFE5176F36FAE02D
+:10C8B0007E94A99CFF33039C8FF55006C2619F2F85
+:10C8C000CC8CEAFD00F0548803B07605D7C126CCA5
+:10C8D0009BF090CFA2DF4138C62C4E886913215DB2
+:10C8E0001356713E0D8AE4D30C86FC54DFCBF7D18E
+:10C8F000477F44FC973E19E1DA20E17948198CEF33
+:10C90000360CC477631647C22AB4BF488936627BA7
+:10C91000ADC048C1AEDC6B429436CAF163EC38F668
+:10C920003B52D041F27F9261EC41FEBF1FE902FD14
+:10C930008F2C6FBC4D05F8D3CBF5980BD2919D95FC
+:10C94000150CF0EE7E77DE078C7F27F93166490BF8
+:10C95000A29F651A55B588EFA4F96D61EC7AB412FF
+:10C96000BD9FE0A88AC5CA689CA88270EE7444186E
+:10C97000D2D1312B168E003CAD95D358A589CFF678
+:10C9800021B030BE1660E178611F1FFC40E3BF6F2D
+:10C99000AF58EA595188F512084F17B192B0DF8BA2
+:10C9A000FC006C00FCE0407E30881F7E8CE5C66297
+:10C9B000E3256C170CB4942A06AD8391C8D700C741
+:10C9C000286CB7B3D2B938CEF1F226F1A72AF062BB
+:10C9D000C0FF004F1E91BF953908AE048117370B79
+:10C9E00031960BEB6E624B5805FC0596B09001F545
+:10C9F000126C78D242F11896A7AD61A13074A519D6
+:10CA0000D1D9E3387EFE0DFB4B622D614710EA1B46
+:10CA10007186E9037AD5FFFC3ECCE381A35A28C690
+:10CA20004C7CC9802F4DF26CF472587F05823758C8
+:10CA30001F7F4AB9E067915730BF370DE487CF2495
+:10CA40007F84DC66998BA85E5675E89D95304476A8
+:10CA5000206332A158F7AB8887BD6E3EEF3EFEDF04
+:10CA600040F38FD7C4D91F1CB84E3B15E43F2316A3
+:10CA7000213ECC5ECF54C46B56F559055359EEA8F0
+:10CA8000D68CF746F4CDA3A1F9EA6486E5EE908A48
+:10CA90007C90DB32F92577807830F4239A47842D17
+:10CAA0004AC2A155D601F3FB09A4E7827DF2326B9D
+:10CAB0007D02EB70F7CDDB51EDE4FDC7C287F200DC
+:10CAC000EEF982A5E70B3AB012C77B9D124F3934BD
+:10CAD000C1BE3C4CF8CF77C17F506E4D56E23F52FD
+:10CAE000FA9757083A56E077392EC0A3298AD80F0B
+:10CAF000F97AAE1065870FBC356E0ACCE7584863EB
+:10CB00002EC4DA81579BA740FFBFBA04F286A05318
+:10CB10003AF6C7F1FBAB200B9761F954251E837ED3
+:10CB2000E7CFD04EE17AAB98B5F123941F1508BF3B
+:10CB300069BE1F1EFC8B8EF8BD7596F57B32C29EBA
+:10CB4000460CC3FB17656B8B35EAFF588912C7A5E6
+:10CB50007DE477EF6FFD0AC0F7C62C2584F01D0B2E
+:10CB6000FDC1CBBC7DE3F6E2CB607EC4977D1CC9E2
+:10CB700067403092E7A902DF690C967D2EFD4AFBE3
+:10CB8000D70831BF747F95C2A09F8C192D87F812EA
+:10CB9000E6741C1D6E9FAD436E67D2B8DFC4092FCB
+:10CBA000CCD0A711F40C4500D02126C655CEB950E3
+:10CBB000BE8000F761397C97F4017C8D5C63A2171D
+:10CBC000FC4B5A6CCD7B0AAC79CD4CDF60DF7C240A
+:10CBD0009F7B849EC0C25103D75B93127B1B977AC5
+:10CBE00073D3FDE10A582F8E4EC67C0194037A3C24
+:10CBF0008E75F3F83EAFE1BC01CF4919CE78077CC2
+:10CC000077837A761CE58ADEE246FC3A0A4261CDF9
+:10CC1000E89B3F5B974A7C932470BBA9A43805D757
+:10CC200085EC0FE4A565BDDBF721DD7072BDCA6838
+:10CC30003ACE539DE8E7023D4D09D23E51AE209DCC
+:10CC40005A9401F52C39CE60FB7B1F9D59810EF360
+:10CC5000BA932584707FA89E55FD76143E1E66D13A
+:10CC60006BB07FC7ACCE5A9C57F257ABB371BDFBCC
+:10CC70002E6655285F167F6509EB8634231089756B
+:10CC8000C3F76A45E3FD9DCDA2790B71CE1C1D371C
+:10CC90003003F77D6F281C463CB1C9B42F807CA0BF
+:10CCA0007495C2F783DB455A2DD75D9875209FC9CF
+:10CCB0007E70FF477872C2FE521DE0D1BC5C1EC977
+:10CCC000FDDF3EBF9B453F1B93BE9321F48D33D8C0
+:10CCD0009F53F4B771EC4DEE81F41FBF128D2926DE
+:10CCE000BDCD991122F9F715D8F709DF796166866C
+:10CCF000CBED6D61C8E7AB14BF653C1DE41CAE17FE
+:10CD0000DF5796D038FA2CA92783FE5D48F45B459F
+:10CD1000FD2DB6EA9F9E4098D647127BC8DF9D48FE
+:10CD2000BFE69D83C586B843FEFBB8C41D7701FDF1
+:10CD3000933C20250108AFF21E8D83FB19EEA3C999
+:10CD4000D809ACC7CD35C78B7407F6C3D80C60C5FE
+:10CD5000A490695DF1E4CD3C1857A862D0AE773D50
+:10CD6000D2BAF17AA35CBE86F87A72C3FF505EDC59
+:10CD7000099F66A6627DFF21D4479367E816F9E113
+:10CD80002F08913C48095BBFCF058221FC2997A958
+:10CD900071DAC358B8223FBD6FFCBF797C1311789C
+:10CDA000942B49D07F4A1AECF358FF24DF2747D849
+:10CDB000E4B309BE2E840FB773842FB9B033A652E3
+:10CDC0007D90861AC1D7658663046BFE08E900F082
+:10CDD00059BEE3BCBE5ADC373E8CD7651EAFDACDF8
+:10CDE000E1C37AB3A0BCFADD8F8A8E98DAC74A59BC
+:10CDF00041154CE6392529D07D314306D0717FF9A4
+:10CE0000949D0997E3BED49A49EBC2E7E76DBCEE67
+:10CE1000E3C444290827D0EF6F35678B8E98F44C14
+:10CE2000A0D7C7167ACD107903E425C7AFB59C65A6
+:10CE300012BF505E2378F8BEF77B4FBCCE04BFC450
+:10CE4000F39D5ABC5CC171D57804E19076A2C71DF0
+:10CE50000E73BD91F3E979F4D3F425F5731445C845
+:10CE600070FDD8DBD9FB857AD351AE423A09D3CDD8
+:10CE700079D05F2EF65345B851F430F5D3ABB708EF
+:10CE80007DC829F421873BD21484FEB4373516833C
+:10CE9000BCD63299F4CE5EFDC5E0E33903AC6DB388
+:10CEA000D45B4CF2CE53A05AF4173D3381F49C5E10
+:10CEB0003A2D8E2938DEB7459D5EFD86453B504FA5
+:10CEC000D7818736334A3B703F448985ED71C99CD1
+:10CED000A3FDF77B349E6CBFB9A098E4935D8EE907
+:10CEE000D80EEAA018E4FBA0B5DDE0FB826DBC45DE
+:10CEF0005678CFBB9D5737BA659B9CA1DAE9ACDB6E
+:10CF0000A48F65E3E245F9FF399403BC955840F3DB
+:10CF10008E65223DBBC01EEB007DE1533DB604F1A2
+:10CF2000F5A9E16200213BEAF03766201F342806AC
+:10CF3000D2A9B279E1022CAF7C530BA841411CC8A5
+:10CF40001F0DCE23BAE5AA5CDF677AA78EFB65E5E5
+:10CF50008CE05C94B1E57743BF48EF1C97F223A8BF
+:10CF6000377B46ED726C7795718303E5EEAB8FD717
+:10CF7000D1B8AB8CCB75946313B11FE0D33F3FF6B0
+:10CF8000D43406F01DFD6912EBC07D5E8F3B71BF8E
+:10CF90005FB55F233B67F59349A43FAC7A7AEDDE3A
+:10CFA0000AE847F95912C153FEF48A475C045F1D31
+:10CFB000F5B3EAD96B92EF43384F6A6033405ACBEE
+:10CFC000F7B7B5306737B43F1B74EDDD13ECC39F83
+:10CFD000C487CC2F6B0E3666207CFB82A4EFCBEF90
+:10CFE000AB74F62F11E8A712D2AB07D8F716A9DC5D
+:10CFF0002E3D13742D4678957D87BE49F36CBFDEB8
+:10D0000081F354EA539CA7013FF304DEA01ECD2711
+:10D01000F6A812CF87F2338F2A7C7EED45BB3D41C7
+:10D020001C7FB77329F9956AA93EC0FF2FB8DF2F7F
+:10D03000DB176C1C0DF59635058368CFCE79F2A70A
+:10D04000BE4E6EE77A15A0F72D628DDDBA4FEB402C
+:10D050007DE796FD6B49CE439EF49FD54FBEF86C9D
+:10D060002C09DB6B9675754BFB3D24D7573FE3A22C
+:10D070007DE38F6F6A210FF673D06191F37FCC78D7
+:10D08000CC877649C91B56F98FE37E964AE3543A1A
+:10D0900093FBB703CC3B91FF6E6DDF44E3DCCAF832
+:10D0A000BE43E530DF3FE22FA3FAEF0BDF53613FD2
+:10D0B00040B93C9D4D47FE5EA345923B90DEFB464A
+:10D0C0000CA89FC97D40EA67600FEC8AC1B8679ED3
+:10D0D000FED32E9CF7D12FFEB2EB7B88F7173D7E57
+:10D0E000E4F35B1F3BBDEBBB90FFF341978AFCB2BF
+:10D0F000EAB10F7E8FE57F7D6E7C2AEA6D3B55AEEF
+:10D10000077D18FC5B3AEA61EB5EBC6C24F2E5BA81
+:10D11000037346B201E4864C3F04BE8ABBCCEB34B9
+:10D120004EFD1807A1BF91907D41A436BA1DDEAF18
+:10D130007578816FFEFCB68BF4945BE15B35ECABEC
+:10D14000B754ADA8403B0BF3EB01CFB73CCEED9FFE
+:10D15000FE788E8D513330ED1883A6D72DFBAF5955
+:10D16000706909A68E9081F365671BD1AEB7B7EBE6
+:10D17000A5DF9B40BF49FDCB6F651CEFB7E2FE3FCB
+:10D18000B13FFDFE8CBF5CD29F7ECFA8623F17F4FB
+:10D19000FBEBA337247760E1FE11167FA39D7E6B26
+:10D1A0000F5C9B3C905C36E3B7E33CF0BB52D8FB92
+:10D1B000B56AF8B08AEBF3E99F3CF220E0F7C3DFF1
+:10D1C000B8421580900F7FFA69162A793D8EB3DF39
+:10D1D000C4F577F645977F0FB459F5E25BCE30D0B2
+:10D1E000F9C303279C06ED87A02A821CFF90F5FE59
+:10D1F0001C47B97E8BC233B7B62575A0BF47D2E9AD
+:10D2000096F8C272C347DFC90F744B9CF3FD2DF132
+:10D21000438B9401E8F6BFD51C2E4FE3698497B584
+:10D22000C671A7DF6BA5A73203E9786A2EF2DD602D
+:10D230007494F3F7E3FCA79BE8DA36F4BAFC70B712
+:10D240004B5792FBE8FBA1F01BDF1A57DE6203ACE1
+:10D2500057E9EF60DA9221E964E7874F6DEB59B641
+:10D2600097F31E6E3D0F3F9F0BC3D76914A269FD54
+:10D27000F1567B1997CFC7822ED2B74F388CFBEF70
+:10D2800040FE78CDC1F64093AB72DED78D01ECCF76
+:10D290005F015F1AE3FBF291191FD58F80769159D8
+:10D2A000B09F187D7CDA5B3E4B6386091ECDBF378D
+:10D2B00082FACC60F8D47C6EF21FB1B0DE8DF450EF
+:10D2C000519F55FBF023FD1BD15E360D53FE5BBD18
+:10D2D0007950AC41DEACC05F019ECA708913F58302
+:10D2E000E52CEAD4811E2B590BE557B1764AD7B00D
+:10D2F000E394BA320D27F7BF97F9BB494F59A39D65
+:10D300004B3C7FBD44C2774C31EE2D03FE7164303F
+:10D31000F29BBE3C8AC5715D38C7BC90897CD00C3D
+:10D32000F86380BFC61A3F1AEBACA92683D2DE731E
+:10D330009430288800FFED7E0E3FDBF7D8638FA581
+:10D340000B1507F0D0002A41BB891F0F0B7A9CAC4C
+:10D3500071535AD6DCEEC075ADAC79CA81FBE6CB11
+:10D360004AFBCB7EDC0FD62AC5C2BF76591AC887C6
+:10D37000DC663FF9C15F177EE1DCC593D5A5A67DCC
+:10D38000FFEBD80F7CFFFA9AC9A3717FD9FB8536D2
+:10D39000A01D5DAF713F7EED1627E9A7BB6A19C9D5
+:10D3A000F55D97B8C672E32D83F4E799427F3E326C
+:10D3B000DB35761DD4FBCD4A2D84FEB0DFF4DC973F
+:10D3C00084FBCDA1BB7E307F1A7C9FF926FF3E18DF
+:10D3D000DEF7A05C8479B6C17C513E3E0278C4FC85
+:10D3E0003EC023A68FD518943E5E5340E54FD484AB
+:10D3F00028DF5E3383F24FD78429BFBFA69CF2CFCC
+:10D40000D644287FB06631A52FD4ACA4EFBECDEEB4
+:10D4100028EA393FAFA9A2EF33632115F7C78E9AE7
+:10D420006A2ABF524B253ECF6D0EA951F45736B133
+:10D4300026942FD53116467FF21E47E70D11139D16
+:10D44000AED4B8FE748F485F56426A0ACC37960253
+:10D45000FA28CC3777D1E497904ED77A8306B27BFF
+:10D460001F5D2A1DA585E74F8FAB35EE2729F36A8F
+:10D47000ACC0A4FF5CB708F2A675786C766726CAC4
+:10D480008B63A07EB1D18C75D6EFAA8D417F8F9C26
+:10D49000059B18E1CA70903F748F27BA7902C0B516
+:10D4A0006B94A3640F54DD33D93FDAAC1FFEBBA0ED
+:10D4B000FFEE14AE874E3FCCFDA9F10FC6EDD9406B
+:10D4C0007BC77F9E3B07F4CFC2DF73D19924FC3723
+:10D4D00005FE04F3394BFC2EE187476709B47FFE54
+:10D4E0002E7F1CF5F0B8A2121E20652AE9EFEA1E75
+:10D4F000D4BB99A124A05CDF0D65C908DF06750FB8
+:10D50000FA4F9F17788BFBFD6AC8046716EBF55F2F
+:10D510006824DF0D6638A7E17746FE10590EC37701
+:10D520009C137B1EFA4BA81CA69455CFFD8FA67E9C
+:10D53000689F28889BF2F0EFE27D563F4A51BB3549
+:10D540003FE9A0353FB9C39A9F72D49A9F7ADC9A7B
+:10D550009FFEB6357FADCEE98DE717E8FFCE167298
+:10D560008F199D74DE928D7E70904359317EDE9BC3
+:10D57000B55EB7F973ADFE6E862E9769E26808FE58
+:10D580007349A7B5BE21FCE186CDDFC29614A8661B
+:10D590003B708BCEC82EDE328BFBB5E1A7CC13409F
+:10D5A0007FB6E247B9F34AEB2785EB20CD6A053D0C
+:10D5B0001DF6831FFFEB2B99287FE7DEA54670DD64
+:10D5C000CD0D767A90DE6E23245C72BD7856CF4DF9
+:10D5D0001F9C7E61102508CF962FF8FA4B9DA793CC
+:10D5E0001DF571CCD8A305FBF03441D07895E0C788
+:10D5F000F9B31C16BC5664382C74BDF4AC15EF5F3F
+:10D60000FBCCEE2F33F18176E1F909824EBB40AEBF
+:10D61000E17EE071B6903CF4FC9AFBB7F2ABC32F0D
+:10D62000A1BF3E8B9D9A8DF649368BD7613AB33AAE
+:10D630000198D004471BA78B1B3031D07947DE8E71
+:10D64000F3A3273595CE7D139E739AC08E9F02F962
+:10D6500095733ED0F1BC6011DFAF24DD810EACCB01
+:10D66000CC17E63C8CFF4EC7A30ED42BB23EE3741E
+:10D67000B7B7BFB1BA53890D20D7B23E73527D9967
+:10D68000DF05FB40976378397A372A2569FDE5E99C
+:10D69000C417C1A085FC13B14E05D34977C5354CDD
+:10D6A000DB7BFC2AEE47A10646E5936BA11CF2CF7B
+:10D6B000544339EA079FC32C005EE93298F201AF68
+:10D6C00067D4772A289FFD31BFDA09F582D58CFA15
+:10D6D000F1C7E21AE68D9E4E0FD603F9D8A1045089
+:10D6E0003EAAF10D24DFBA368D47F85F56DB117E76
+:10D6F000C6CFC2D8F3D5461CFDED52FEB1E3F17B97
+:10D7000048AE02BDF13BCAD9049493B5AA90B35C6C
+:10D710005ED1FA07399B1D53C39E891679A5925C89
+:10D720005BCFF9D6CD9A6A51AFBA5079F43CC25367
+:10D7300038BC5C7A49EC43A009D1F704B7C2F5B80C
+:10D7400041E4D46C6695ABFF5572EBDFB12DC09907
+:10D75000EA30521492132A4379158F5DCDF576E1A4
+:10D7600067227A6BFDF97297D047643EBB9EEFFF4C
+:10D77000F67A27E4BEC7BEC6CCFC93556FDC3B4BA4
+:10D78000E83D86817831B6E1795DF0A846E7D8C1F9
+:10D79000FAE3E548F7FC1295E1560BF050FB88D010
+:10D7A000A73C4ECE2F9E46C6E56C8C7967A7F78ABC
+:10D7B00004160F8F48457D30BB5AB5F8430AE4F98B
+:10D7C000689CDB3DD27F9FDF63F57B64815D5C10ED
+:10D7D0004478ADF65116E293EF8756BB49E0AB773C
+:10D7E000DF64DCDFF99F8807E59F2F677BE5BFE0FB
+:10D7F00013296FA5FCCDAF8E2C9846F356480FC960
+:10D800008A313AE7CB66670FB9203FB385C79BFCE7
+:10D81000BF2E7783A8A7A13DF6D939D2EF664A7A01
+:10D82000F7F4C56DF0B82AFF6E94579F9D7A3F5E5E
+:10D8300087FEEBD474B213EF947A4B89880B124DA8
+:10D84000E4386794E89D7A5AFF38973BC5B8A9F346
+:10D85000F2868C134B0AA956FA08BBD485716E2642
+:10D860003A788CD1967AD20E03148651EE66CCE4C7
+:10D870007680ECF7239DEBEF773A542B1C421F7117
+:10D88000087AD9E191769FB4F7B6E8C7DDDCFF618D
+:10D89000D56B1CCCAAC7C8F65BBE882C267D46CAB1
+:10D8A000A9EA5405FDDABBAAAF4EC6F899190ED500
+:10D8B000E21777087AC8F67B6DFEA43C195F23E86F
+:10D8C000D780F573FBCA4789FE72035C9E0D474FF4
+:10D8D000597F087A8E720C40CF2D3AC83FD413413D
+:10D8E000FEE1798A948F0ED13E37707636EEA3D959
+:10D8F000EBC32A8E3F0EFE8D00BCE4355BE5597EFE
+:10D9000000089EC37AE5A343C847BB3CDC55DD3520
+:10D910002F88E702CDBA81700F2A075B4D728DFE0A
+:10D92000CBE31E736DE77E0E21071D83C8414907B7
+:10D93000C705CA4156602ACFB1F0C979C9B93CC6FA
+:10D94000FD10C3CBC3F0499487174BFC087998D7D7
+:10D950002BDF3F22B9E76865A1B88172B0B316F337
+:10D96000D90FF138AB8D0AB7FB2E1678CC0E2458A0
+:10D97000D6D74A87D8F71E97E7C403CBC7710FD90C
+:10D98000F7F718F975241F1495149796E5E0BCACC9
+:10D99000F11B8EB226F23BE696733DC1D16CEDC70A
+:10D9A000BDDF9ABF0D3B9CCAE73BA2F8C2E1B28F34
+:10D9B0002FD7FF60FE0ABB1C92F284798B49CEA45C
+:10D9C000CE5BF7EA58D4079B449C248BB9B2207FE6
+:10D9D00067BD41FE19606292D30E8F4084382FA933
+:10D9E00016F289B5072DE519A365DCC9590FAE9B61
+:10D9F00086F55DA477A6DE9573EF7836389C83F9BB
+:10DA0000A5EECFFE7D39AE3B07E81FE82774E83C62
+:10DA1000EEF26FA794D00666E1278B5D26E5A05D48
+:10DA20009E0D27C74E08B9FAF7CAB1876DF59F1644
+:10DA3000FDE5AE3FBF7D49D61F428E3DED1820FE6D
+:10DA4000F2FFCBB17FB61CE37A9D5D8E49B9349C61
+:10DA50001CB3CBAD0B960B027F76F990AD85FF8A98
+:10DA6000FCF271F9BA8D545DE82BA9B51B2EC7F3F2
+:10DA7000B8C1E4443C9633A45CB1AF57E97F5E0083
+:10DA8000FA911B44CB025826060C7545E6F117CED9
+:10DA900042E99FF4A8C709E5F313C76EC0EA1B1D4E
+:10DAA000670314941066863F9D9FCB239F29071B15
+:10DAB00023A8973A5815E9037506EBD4C8F9BCC4F6
+:10DAC0008FE75C0AEB64E72EEED393EC706D44FFB6
+:10DAD00034ADB30EB293C9EF07FDAA896746A17FA3
+:10DAE00039D3A958CE0764CAAAF533BDF8CC21F8BA
+:10DAF00063A807532C10DAC4977AC81F3951EFA4D2
+:10DB0000789832FFC232B4FBE78682C532B68251C2
+:10DB10003E85D6B5E68C8E77C2380BBC1795E17C76
+:10DB2000303E84E2DE06D1177BE190E70C61D6A996
+:10DB300098F61F5720A8A6B0BE79FFDE1329467CB1
+:10DB4000063359298278995698DC3904BD1E117123
+:10DB5000F5E8AFC7B8AB67816E9876809CC5744F07
+:10DB60008D41E9C19A024AF7D584A8FEAE9A19946C
+:10DB70007FB9264CF99FD744289FCF22A538FEB8FD
+:10DB800007CB47A31CAA73B295741FC316EF76A5E3
+:10DB900093FB67655AE13408FF0D3831F4A79E7096
+:10DBA000F2B8573D3CE6EA249EA27C98A41F3AE2D4
+:10DBB00087AA57BCDB49F32E6C6AAF4F827C7B91FE
+:10DBC000A2B2498CF95E48E85080DF7DC5EFF7DCF2
+:10DBD00003E54F164127F0BDA8B5E508F2F513455A
+:10DBE000203FB15EC1C6DB705DF85EF8F5F728ED49
+:10DBF000E8FE3ED2C3F5F959FF95D8AFDA317A3550
+:10DC0000D277A93784FE8F079F7786B1DC17FAE1B8
+:10DC10001D58BF90856F5C0D5DFB0A1FFD36C9372F
+:10DC20003DA6F900EEC2883F84FBE383CE96391807
+:10DC30008FF9E4752C84E756BEC27FBB93DAB777C1
+:10DC4000DC85F5D3E355B3518627175FF2C3FBA0FC
+:10DC5000BC75C2847BAE8434E3F9D64D98DE5BF4A8
+:10DC60008D2B8B216DC9DB7E02C5CC83996F8EBE57
+:10DC700003F2716790F0F45ADEF68A62E8FFA1358C
+:10DC8000A9B43FBC96773805F7A989F91AF9299FF5
+:10DC90009EA5979BED836F3B799C638DD3C9E3343D
+:10DCA000F334BAAF20E5AE3E8BC7CD3B0EF2F84D54
+:10DCB000C7411EB7E90954D11A84FDA506E9CADA9D
+:10DCC000ACFB8FDC67EA9C7EE147E84C45FFCF81E7
+:10DCD0004CD58FFC7E20F3EA44DCE72165145F9D80
+:10DCE000C7E34A269E885C5904F06FACBA7D7A2D52
+:10DCF000F51349BC1EE0D8E04CA07EEE41FFC1D434
+:10DD000021DA7F04ED619C8D6BA0BDD1D77EB393EA
+:10DD1000C7DF6F1FAE7D70216F5FB5CE32FE7DA273
+:10DD2000FD0FB17DDAE0EDEDEBE84101F781379FC2
+:10DD30004E41F9D8A6B4E73140C98B8D57D7E9B029
+:10DD4000AEAF50E3EF61BC2E73AE98B318D6694501
+:10DD50006F1C6E3881CEA3D6A5929FBA58C89A2B55
+:10DD6000D5F0E642E4BF5F680CCFC706970B6ADFC9
+:10DD7000FE4002C764FF533ED5961F6DAB9F6329DB
+:10DD80007FCD29CEC3D945B67AC596FC9507C795F0
+:10DD9000211F5FD9915ECA7C83C3F7FA8B7CDDBCFF
+:10DDA0008E6B988C71106433187B4691F91573CA89
+:10DDB00060FECF88F263CEB575B585544EFE45F84A
+:10DDC000BED87CAE784CC8E977041F6BFBDD749F2E
+:10DDD00045F2A1B6BFF138E6F50E277DD7DE709E7D
+:10DDE000A27CE126FAAEBDD0487AB9C7DBCBD7EF2B
+:10DDF000105FB70FCCD76C39F747B8C4DCABD9F19B
+:10DE00001B492EEC50795CDDE3FC7CC1857A2EF158
+:10DE100021D78B0B7BEB579553FD0A9DE828F5E244
+:10DE20004251FFA7C00BC7715FD28F131F54B38E2F
+:10DE30002B2EC638AE37548672E7F08EE2D7910F9C
+:10DE40009E3CAA515C3C8BE652FB8952FF8AE7F369
+:10DE5000BCD0B393B3647FFE44E4D7FD4AE8F542F7
+:10DE600094A7F3749263727F96FC1612FDC8FD7A34
+:10DE7000BD8B9F1F3EF1426A228EBBBD4CA7F2496B
+:10DE8000FA53246727FA6797A6183C9EF4F9629420
+:10DE9000BFF123F8BDEDC5712AB2E2EB499DF75DF4
+:10DEA00089F08E5543782E97CFB651184251B591CF
+:10DEB000300FD274570AF53F717DECD5EFE3FCF2D9
+:10DEC000FEA2E279F0A4964F5E4A443C7530BAA7B0
+:10DED00095B74DD75698D6592853A57597B76D075E
+:10DEE000C9BD8640DB4C4DD0E9C624ECD7C5E55A08
+:10DEF000263FDF36C9AD7417F273F3C0F4CDD7589F
+:10DF00004CC3715F55E3747E57EE4F5C683AFF7BFC
+:10DF1000AA1DE428C057F8D4A2DB5F837AF5FE99E6
+:10DF200053783C4178F4CDA4AFCF9A82F27E9C4BDB
+:10DF3000DCCBF30FAA9F8F730DA09F7F5CFE8982BD
+:10DF400078CB2E4824B99BDDCEF9F7A9CF0DADF7DC
+:10DF500070DDB4EE26EEB7FAF7D426ABDF289B9936
+:10DF6000FC46A49F5AD7377BF7E2BEFA39A4FFF1EB
+:10DF70007B0D42AFCF1765A93B55DA879F6861716A
+:10DF80008A438C85BDB3A7F5DD637918F90850BEC7
+:10DF90005BE8B34FC5BA1214E2539D62375F794113
+:10DFA0000D75A07D26CECD1DF5C74B911FE5FD1744
+:10DFB0005753A48EE45E89C362174C7DB385EE91FE
+:10DFC000CCDB6FF5F74A3DB6D8661FE489B8993CBB
+:10DFD0009B7D608F7FB9D6658D7FD9FA5D8DE2ED2F
+:10DFE00062BFD6681DB75DC262784F150D428AF7D1
+:10DFF0005E3A9ACE3924FD643CCC3217F7271DF9DE
+:10E00000DDFB09C8B74FB48CA375B60A27497293D4
+:10E01000C781E48975F5744B0ED9B98767FE22A1D3
+:10E0200093F44F7E2FA748946F80EFC847CF00BE70
+:10E03000B18B1FED2F1E83F7B2EE2B7393B3CFB7C7
+:10E04000373206E31F0FEC16F7E474CE5F186B4B04
+:10E05000EB1FBFA19F3D13EC46A87F874BC4432A0B
+:10E06000913B90DF54378F1BF6E5DE9681F6EDC6C7
+:10E07000A0C2EF1D0ED3CFFABE7ED69BFB91FAEF66
+:10E080000235AA73FEEC20399225F822CBEDE5F299
+:10E09000D8AE371FE7FB05E8BF1B5DA8EFA11E4FF9
+:10E0A0007EF8CE52EAE7FCF5DF98D97ECDF2DF1696
+:10E0B000B6EABFD1EDD8BF113036203E5D997EBAA9
+:10E0C000E7789988E3FFB89AC7810C36CE5EA1073E
+:10E0D0003F2CF4E2DD421F3E8EFA703EDDA37C1839
+:10E0E000F191D5CCEF456455F37B9475CED062DCCD
+:10E0F000DF5FDED83507F7FB0687BF18F7FF1F6F16
+:10E10000ECAA738FC2F8E0B3A330FFDCC677E7B8A0
+:10E11000A1DC57A7D0567C00F2B159308ECAF11F4E
+:10E120007B8409BD97A59603BC139607489FCC56E0
+:10E13000FD5714A09C5AA5921CF7B5713DD20EFF55
+:10E14000C3C2EFE5AB3B751BD2FB3917D7AF9F13AB
+:10E15000F494F9295AF439928B3AD37533FDAAA372
+:10E16000423EB58C46F93400BDB55EFFFF50F46EFB
+:10E17000EBA5F7AB380ED03B1C50FAE8FDBCCBCF7B
+:10E18000E9A9C33845E74FFF2C61770F66E7B93E31
+:10E19000BB182F49F7E6815E27911FB232B93ED0F6
+:10E1A0004B2F15EC122FC2C7EF1DFAB48555B8CE10
+:10E1B000DE17EB5BA69D025FCC6BBDAF04F2BC1318
+:10E1C000E7E5D1AB44103D97E7BE3AE8C76BC2AB79
+:10E1D000B03311AF68674ED14A4F63BB1E97D497D7
+:10E1E000ABE85E2FD3ABE85ED5DF8DEFCC5E7CFF76
+:10E1F00085AFAF4E95E2C718B74BCF17BF7DF7136A
+:10E200008C7A8ACFFA2E0B81ADCDE678175AE2F5DB
+:10E21000E5FE6FEFE7308B6AEE3493DCFCDD4617EA
+:10E22000B65BC0603E84A70E8A5B2F1D619428A850
+:10E230000FC7DC656F80482C45E56634E65D657880
+:10E240002E589AC8F3654DFFA33E06ED4B31B694A8
+:10E25000F4C5DC323CCF2ECDE5E5E5A2BCD019F605
+:10E26000BBA75AE444DCECA705B9908EE539FE144F
+:10E27000D25F1C017E0F6B38FB18FD353A75729624
+:10E28000C7AD54F37BAB712127C0DE3570BEE83FCC
+:10E290001BCADE9DE0E67C24D38BD0184D33D9BB5E
+:10E2A0008F4A7B373E9ADBBBF1D1667EA8665C3E27
+:10E2B000B0591EAEA7083D3347EA8136392CF5CC5C
+:10E2C0001C8F956FE2A3A4DD114AC07DAB4F5F8C1C
+:10E2D00050DECE57524F94FBD9827D9CCF7CFF59A4
+:10E2E00057D90470CC057A225D5D82DFAA3C06F125
+:10E2F000F59E66AE3FA4DEC5E87EE78F5A525370A6
+:10E300008F79C315BECC4CA76657F8721BDDA236B9
+:10E31000BACD47FCF6A79B90E7EB19C589667B3D14
+:10E32000343F490789F7B7049D4E0879FE1F429E86
+:10E33000E7B3F075D86F9D939F6BC77EA1915C1D6D
+:10E340008C0F068D8F14749672649987D3B72FE55E
+:10E3500072F72D11D79B3383CDF427F7F57B9B9B69
+:10E36000DB336F79AC768E4CABDCBCBDAF2E42F2AA
+:10E3700049C6A14D68E2FBB4AC77BB5B9EE31B2AA8
+:10E38000BF47D4A222BF5E8F7041BFB933D82CFFE4
+:10E39000A4BEFA31C187D727F072FBB835725C2171
+:10E3A00017E5B879CDD6716B7BC70DA9FC3D8E30D2
+:10E3B0008D3FA1E92CDDB3CE15F7AF8D964818F34C
+:10E3C0006F7DE3CED33B517F4F2B28167A34C3F7B2
+:10E3D00030EE13F03CE80C67E0781AE009FD3459A0
+:10E3E0000037A60E2F233BCE511D237DCFA4DFDFA8
+:10E3F00047FC9339B07E2FF1EED35999CB24AF323D
+:10E400003DAAC5DF27E779FD925A473AC037BED506
+:10E410004F7E9585650AADBB60387337C6397C225F
+:10E42000F0F2E8BFB27684639CCB68C027351EBE8D
+:10E4300081D1B9C3837783BDEBC379F0FDBAA15411
+:10E4400025FFCFC88ADA076E8674FCC399F43DE3D2
+:10E450000E95FAFFAD3BC8E314EB53E9FB0FAB029B
+:10E46000F4FD81E53CBF774D1ECFD7ABE4CFD96B30
+:10E47000F3EBB4BB359AC7F36EF1AE49BD4AF64F24
+:10E480003FBFCE7ABEFF3996F3F32813FE9E27FCDA
+:10E490000DE2D7F9B95BEE532D9E0484C7CBFD3A4C
+:10E4A0007BBDC5242FF67A855FA45EA5F3D8078EC1
+:10E4B000877E51007C525725FD32A184EBA19F1726
+:10E4C000DDDCAFF20ACA91B421DA9F85F6304EDD69
+:10E4D0001AE917E2ED5F16ED8F61FBA943B4372609
+:10E4E000F3F6E8D7318DFF4B37F7CFFC7A98F67B00
+:10E4F0009B9F4E59615A0F27453B270BBFB309E637
+:10E500009DA4F1FBAB3F565A6E5C85FA5ABE9BE464
+:10E5100046B061B99BFB7DACEBF83D37E7B34F04E8
+:10E520007F1FAEBF8FE2B026D4EF28457CB2166EB7
+:10E53000EF061BCA54B3BD9BB79CDBBBC18600E78B
+:10E54000239BBDFB895BD8BBCBF9BB23267A7EE23C
+:10E550001EC2DE95F200D643BD793DDC26E454EFC1
+:10E560007A10F266B8F520E5DB97B51EAEF0FC63D5
+:10E57000EB21D5C3D7C3048FF0735EF87A98E01906
+:10E58000C2CF29E5343429435709EA79B8CF3E2C64
+:10E590006A49F990BD9EEBD1BDF2137F00FE96C58E
+:10E5A0005C7E82FECDE924BE8F8CA6D3F900BEF836
+:10E5B00080FE87228FD08FFFC17557E8E1EB66AAF6
+:10E5C00067987533C8BA2B11ED2FF50CB36E075948
+:10E5D00077B33C7CFD5C364C7BFBBA2BF3FC63EBE6
+:10E5E000EE1AC197721F3E5CDFA5A0BD9E55FF1EAF
+:10E5F0009DAF81BA11C2EB2DC1065D358F6B2CE743
+:10E60000F00CB6EE9679065D77CB3C43ACBB893A0D
+:10E61000D82D44DFF3D3E7EDE76EC3C507A19EFF16
+:10E62000033A5F0ADFED31EDEB0062BDE053BA7FE4
+:10E6300022F954AEDB5E3E95FA457F3EE5F31A843F
+:10E640004FA5DEE67746EB3C53FBD643361619D88A
+:10E650003FBFFF3CF8BB0D2BDF8E1A64376C46B80A
+:10E66000B366443A707DF7BEDB303E9481F1F275BB
+:10E6700029D677B1F440682FC297FCD59EF6C3E83F
+:10E68000974B2B9E8274BA5FAC7BFBFB0492BE401F
+:10E69000A7FB711C49B75E3F2F30ACD9AFD038EA29
+:10E6A000BAC1DE5978D863D21B1C01FECE82FDDDD3
+:10E6B00003B09F845EE908A1ADFAD228B61FEDAA87
+:10E6C00097E47B47429F5A9011A4F78D1C60B71ABC
+:10E6D00060B71EF604C57E0B3A0AF0D17C613FDEBE
+:10E6E00019885D5EC9D0AE8B93BEFD273DDA8E7072
+:10E6F000FC32F1EEC5FC5D123FE95D2F8973C9580C
+:10E700001A13764207F99B5C821EA52CE456515FD2
+:10E7100047BEC3F39F598CEE5BB10485D33513F824
+:10E72000D0742E5E2AF0CD32855FC2762EEB723326
+:10E730007702EC238AFBD0DB78BFCEA533B78FE21C
+:10E7400004ADE7B2C047AF7A38FD75DD8467478016
+:10E75000F35F178BBE8EE55B67FEF16D0DE0F9F39D
+:10E76000018F8171F1B71A9D57E51AFF7DE725EFFB
+:10E7700091CAF807D8492DF7D565FC83B457B2770D
+:10E78000707B657C8CBF5F5510DB40EF36A17D89C7
+:10E79000E5B93B74867C0DE5B42FC9F6E3E34E4B37
+:10E7A0003C46B0C99ACF15EF43E48BFBF3F41DFA56
+:10E7B000C915F19CB9B6EFF2FEDF2EFC30801FC503
+:10E7C000EE3FFDC233F0FDC1C1EC25E92FF5B1B03C
+:10E7D0009680FC5CCDFD0F75692C667EF749A652CC
+:10E7E0003E686E7E0F4FBE4B21ED2B9627FC2F62AD
+:10E7F0003D30413F4FA6B107F1959AA0487F652A69
+:10E800008D27D7B5EDDEDA2625CAFD35DE182F17A0
+:10E81000F7D8E8090A95DB7906DA75E2DE9AB7A43B
+:10E820008A7CA3AECCAA0EF4CB261530039B2B0515
+:10E830007186FB4942417B06DE7BBA67B07B4F099C
+:10E84000DC3EAA2D7212BCF7FC4E21FFE33DF9DF3E
+:10E85000C930DF4393F13447C67EC7DD69C2EBC6DA
+:10E86000C0ED6EDC2737665E3D24BE1D2D1AC5E166
+:10E870000E5BAF89D71BACDC15E0F7C5FE3636F66C
+:10E880002AA2DA85F15C24770DCB3998A3379E2B29
+:10E8900042EF08497F833C076B7047288EB4219371
+:10E8A000BFAB35E8789F2914C79BAD85CB916E87A8
+:10E8B0008AAE23BC3A8C767A7F27B110F60F485D7A
+:10E8C000A138DD4FF01630BA3F311CDE7313B8DECD
+:10E8D0008DFBA8F9BE9933D49281FB8F33CFC950F9
+:10E8E000BEE85E6BF926F16E8153C4B1C9FED24514
+:10E8F0007F9522451E98518CFCFA4884BF83E12500
+:10E90000B940FD40E1482DBC94F3A1F5BB9A547287
+:10E910001CF9E0F6B14E63283FF43B352C92E7C07A
+:10E920007898AA56F42BB7264C6F68C8A0B846F260
+:10E930007BD56FBEAE01E3A27FAB727F13D3DBD377
+:10E940001616A15DFDECD4CA01E8FFDB84F66F93D7
+:10E95000FCCC72FA517E6E1CCBF9F1EBD727D1FDBE
+:10E960002359EF51B18E64FCA4BD9F1D62FE187146
+:10E97000C1FD969122F37D39FB3DDBAFAF54227987
+:10E980002639F24EEFFE174F42FDA121ED91FC8199
+:10E99000E07DC713FF16F9C5C65AE1BDF13A0E2F47
+:10E9A000E8F353B17D4B826A8157A600C758F3390B
+:10E9B000DEDD625ED0AE48F847084E3B7CBF95ED89
+:10E9C000F5F62481CFFCCA01F0F05B4FFB80F07DAF
+:10E9D0001DE1339D1BFDDC864FC0DBD88545FDE185
+:10E9E000DA99E0B7C04774C6FEAF4DA2FD4ED2FD26
+:10E9F000FB095710DDDF11FE6BC0639AC0E3D481C1
+:10EA0000E07C27213E20DD6FBCDE0AE7CBFDE08CF9
+:10EA1000170D84BFF38073C879FE1815B2B4A1DA5C
+:10EA20000D3CEE0BA2DDAF67E9A43FC6407FCCC72B
+:10EA3000F3B11155DF31DF67BDCDCBEDBFDBBC9C42
+:10EA40002F3EAD28BBB78CA17E1B247D6CC5EB1A75
+:10EA5000D99F199318C9F39E78EEEE98090F9B6B16
+:10EA6000F8BD19DC0762AEBEF384CD25A93E03C60E
+:10EA7000E9A9BF83E450EC5D85EC87C1D66FF5BB97
+:10EA80002B5EF93E946F294D5869B64F3353781C6D
+:10EA9000CEC264BE2F4CF4C6AE0AE27E16D60D6618
+:10EAA000D23F2AFD55FC5C362BE446BFAA8385B6CF
+:10EAB0005E0CF39DF8DC229FF53E78945DC87DF0F6
+:10EAC000D479792710EF9F1ED5E8DE4E8F1EB9EA64
+:10EAD00012C4A757A773D086F8356BF9658FC85451
+:10EAE000A46F522B97CF4D357C33589E50FA05CAF0
+:10EAF000B5B7C4FD9EF7BFAAC4F1DD8643D3566502
+:10EB0000A1DCEEBEEBF84AFCFED7A909F4BECD02AB
+:10EB1000A8E64EE5717F942E996C50BC149004DFEA
+:10EB20000B5850716539C545254ABD37EC536730E0
+:10EB3000F6F61589D4FF9AD6E06EFEEE5694DE4BBB
+:10EB40005823E38BF5A873B1F9BC8475CEB90BD308
+:10EB50004C16BE16E30C5B175E81FD2E58B496EE84
+:10EB6000CF2C986114535A7E4F04F5B99B2A9471A7
+:10EB7000E8575C50FE949F7F3FE4273F45F3B2C6C1
+:10EB800051808F9E026F089F2858507E82CA6F2A3C
+:10EB90005754D4DF7B962F6F1C85F49F91407E9B4A
+:10EBA000A5E53C9E6C758592C7FB3B45F5575628FD
+:10EBB000394632E63FA27EE7D757BE01D36215F34E
+:10EBC000F6EA48D7792C46E73B97B3F8370FD03EA3
+:10EBD000C4FD1E37B5F27770B65E745108F798958C
+:10EBE000F1A75E190DF984AF1684B8BFB437BED44F
+:10EBF000796E0CE336613A3727B0DF040DB45C5808
+:10EC0000A223BD2C5C3603DF0D8D533EC7BBABA1E9
+:10EC10001EF4AF6415CA43F42E5BB82C03CB79BE47
+:10EC200073DFE70D472EE9CB3FDB90DE7864947805
+:10EC3000777434BE5B36612ECA9DE44B5804D7A965
+:10EC4000CEF8FD2720458CEEEFC1EF1BA6F5C1B134
+:10EC5000DA2BFC2FA21E7C7A0AEBFD7AF1B22D781A
+:10EC60007FB6BB49F3A31CAF9F10F6E1FB072C1A3C
+:10EC7000F2E13E72EFA11B7C781F2879D3355791C2
+:10EC8000FEBE5BF1E33A5FD91973221E6E8E29ED49
+:10EC9000B83E4EEB6C2EE6FF543FDBA8857C7672C7
+:10ECA0003EF14F77EB0827C6DD75B6297EEC36F9C5
+:10ECB000D21D8DD84FF7AC24DAEF3B9B73A9DFCA86
+:10ECC000568DE214BAE3B53E3C6FEA6A7AC6373332
+:10ECD00080798DDA9D66B5948F35F17301B4BD08E6
+:10ECE0009E266D0F7F8F93BF0B9988BFC37A49AC67
+:10ECF00057C213300E2199CBAB3F6486B2502E25FC
+:10ED000036FFEC4E8C47EC627CBDC422C2DEC01FD5
+:10ED1000688F67A2C80781268DDADF9CC8E542624A
+:10ED2000E4C2EE97DDDCC9E15BB143891B30CFF76C
+:10ED3000AA2273311E71D9E30ABB6F80F6CB1E5233
+:10ED4000A87E653BAF6F2F4F8C69649FFC51896E25
+:10ED500025B8776A4CBC436AA9771AE0C6F2C4A703
+:10ED600094DD6C8072589D47F0BDBE00933FD6F293
+:10ED700040BBD2C1E3606DDF85DD0378B0C4338F63
+:10ED8000AD58B6039FA11CDBEFBD4C7ECF329D2852
+:10ED9000C3FADDFB5EFD90C3F2DE66BA7C2FD87647
+:10EDA000CFADFB0CBFD7182B5169BEE9AD5C5FEE50
+:10EDB0008614DF1F7823C3F108E91F673BBCD70126
+:10EDC0009FCEBD418DA0BF686E30EAC1FD44DE0B11
+:10EDD000F7E5F27DA9D43DF9881FBE5F91C7E381B5
+:10EDE000657C707926CF6FF9A2EA9BDCEF32F07D6B
+:10EDF000059A8F4A70123F84C57D85F182CFFE63EC
+:10EE0000037FD7A06736C8E160FFB8776831B512D5
+:10EE1000C6EBDA343215633D7A14E197788DF3B599
+:10EE20003D2E7E45857211C5C1B018F97D57C65378
+:10EE3000E8BEC7BC026BBDC8430AF9AD2E376CDF14
+:10EE40009B36D2BB9F6BE2A728AE694DD816776F71
+:10EE5000E78FE1F2E21ED01C41D7A322DE688EB814
+:10EE60001759CEB695A5C27C6E5ECCE3E751AE6273
+:10EE7000FE5B4BF87DC86FB5255AEFDB791D43DE8D
+:10EE8000874C5F32F07D9F0CFEA9F77EE9D8B24532
+:10EE900014879065E3C30C71EF672CDEFB01F83239
+:10EEA000D659DF793DE93C5E9E8BF8CF5268BF753D
+:10EEB000675ADFB1457BC56CD77F94C8E3F15886AC
+:10EEC00041FBF6CD474730735CD2CD5E1EA7CBDA4F
+:10EED0001C67CDFE8D8F8F5E33A41DE831ACE3D867
+:10EEE000DF61EC27DF01B71B4CFB8C49AEC7855CAB
+:10EEF0004F42FE9772BD3CD120B8DF0B87B63AF087
+:10EF0000ACDE08537C836F0E5F1737E1FE087C761A
+:10EF10008DCECAF4547A7798D2426CC7FD44E4BFD0
+:10EF200079A52083FC9037B5EE36F09DF87E70C150
+:10EF3000DED6386D40B862480F844B31C1559F0210
+:10EF4000FB4D2EC227CEB5CAF9BED3AFDF0CEB7E88
+:10EF500066EAB745EE634AC980F3F539906F33C26C
+:10EF60001917D22F088D6D43F61B09F99CB9FDFBCB
+:10EF70008559D44A3CA803C3DB4B1F3B1E10CE5E11
+:10EF80003C2C063C14F5B5F309FCD9D763F7E2DC59
+:10EF9000AD530D2B7DF93D8C41E63B0C7DD2BCBCC5
+:10EFA0009FC1E824EBA7CAFE068107B65F9F6308EE
+:10EFB000BA0ED63EE2E5FC66EFE77CE7E114E5D366
+:10EFC000443F83E159D64F3F5FBC4661DD68FDF1A8
+:10EFD0000A43B763FBCB137BF136A03ED567F754EA
+:10EFE00066E1FED22DEC6E69F774B772BB47DA3B6F
+:10EFF00068E7C44698EC9ECC2A8ADBD95C924376BB
+:10F000004F57AB46E76CFEE9CD5979857D713DCD13
+:10F010007EFEAE628F78AFDE6EEF3C2BCA537C5C17
+:10F02000AFB9D11BBD6A36C0D515D8E0540CD6CFC8
+:10F03000EE81A13BF15DD63AF10EF1E99523B65E82
+:10F0400087F5FE4E7B877E806E6B318541D6CE1074
+:10F05000F1E29F43ED69F8FE161F776D27DFB73E9B
+:10F06000295FE74424AFF59BEEA9C3BF152D4A07DE
+:10F07000BE5BB102FAEF2A10E301BEBB7AED271E98
+:10F080000F8EF6520CF405ADE19A26D4F797272C93
+:10F090007DC40BF3763C70CD54B2AB74D063A1FE4B
+:10F0A000C9547E4FE4D0B48B4EA072D4F34B0743C7
+:10F0B0007FD0ECE985DB50EE759D70D01DA3D9D3D0
+:10F0C0009B77B950CFFD8D8BF25DCFB118D2FB3B52
+:10F0D000E9CE38D2EF4F8778FEAF0FBAE89D8506AC
+:10F0E00047FB2E2FE4DFFF4D1243BB0CEDB6A80B00
+:10F0F000E356401060DC375447FB0AC4583A7FAFF0
+:10F10000CD18C9D3764A7742BD2E7AF7AD43E5DFF5
+:10F110008FA7F3FAD1913C3D4B69B787EB2D12EFE6
+:10F120002FA4717B7B71AAF40FB12C94270DE80FEB
+:10F130004478E6AB71F3FB9F327D2495B76B489121
+:10F140007A50E8067AFFB4225DC57DEECDC8B28460
+:10F15000A978AED89AA3A2FD134AE27C74A22C77B8
+:10F16000AC13FAFD59BD8BCE09DE2B53E20ED84FFE
+:10F170004E058D0DA4BF6D6221F42B8C73801E0390
+:10F18000F9718A128A41EFDDEFB2B803ECB2F75A97
+:10F19000B75F86DF4FEB0AD955ADA9DCFE9ABE43B7
+:10F1A0003BE5003A5F3563F62FAF80F292C7751AE0
+:10F1B000F72769974F3D89FD366864F7BD9CE622C5
+:10F1C000A5F6273BA7C771FC36164EC0F7A862F11B
+:10F1D00081E388E6A472B873762FF319B81EBD2AAE
+:10F1E000C595DF7B68D33103E16829D51155A75157
+:10F1F000C040BF37C567B7D54293933EBE7E4E3AF7
+:10F20000A38DA8CFC71ED4E89D58E4238C13EB161A
+:10F21000EFAE9D6EAD23FBA8BB657C08D7D2CA7844
+:10F220006D16BD5F9CC4F5C43A5CBF6437879A9085
+:10F230005F7B364D1961FE7B23B124A7A41BD93512
+:10F24000F27D07A9BF8F65F2A7576EF1F7EF5BB9A3
+:10F250009D90D5AAD1BB2E63E3AE0EF1FE86E5DD0F
+:10F2600014A847E71963855E3F86C50F95E0F775DB
+:10F27000567D6B4C3DAF377A8D5D0FE3FABD5FACC9
+:10F28000D72E719FEF2B3DB677BC855EEFB7E9F5C2
+:10F29000170BBEB1CFAFBB7E0EBD3F3966274823EB
+:10F2A000AB5CE6F36BE2F7A4B2C0CE19E89DADB15A
+:10F2B0003BB8FD02F5480FB3CFA7BB87F3FFEA7D4C
+:10F2C000DCCEB2CF6BD5998E46DC64D63C6ED503CE
+:10F2D000EDF0B735F17B0833BD3CAE6E668BBADB23
+:10F2E00050F07DF7F63AF4B33BD202F44E6043900F
+:10F2F000AFA3D47965C966BFEAC624BE2E739B54FA
+:10F3000016368D93DF92C0C2263D707C6BAA253FD6
+:10F31000213EDA52FFE27D3996F2A2F68B2CE5937C
+:10F320000E165BF2933B665AEA4F395A6AC94F3D53
+:10F330007E85A5FEF4B7AFB6E42FE9BCD152FF2B12
+:10F340003D4B2DE5979E5D65293F29E22FBFF6D9FC
+:10F35000ED96EFB3D9F72CED36087E7065A82C6ECC
+:10F36000AAE74BE4FA29EAE131CB79BBCAA2A67A33
+:10F37000778BF629972D1A52CFBE57ECAF9BC4BBA3
+:10F380008075F82EA00BFF9E5106A50DF82E20A427
+:10F390001BC5BB805BF05D4017F65BF200EA819F06
+:10F3A00066F0B386CA4CB60BCF455D207B0D83B1AA
+:10F3B00011D3385F25C5F8DFCF881AB118BDEB34FB
+:10F3C000CBAAD727E459DFF1D6BDA99677BEBD8574
+:10F3D000A32DE5CE408E25EFCEBCC852DF57526C30
+:10F3E000C9DBED86CFBC5CFFEA62D163E457C86835
+:10F3F00021BFDD6076CA7578869036F8FB7EEFE334
+:10F40000FB7E06BEEFD792657EDFEF9742AE7D6052
+:10F410007BDFAF7BE7F83D1B681DF3F7FDF0792339
+:10F4200044E04DA9BCFE0A16DA8AE7C4D2BE26BD66
+:10F43000009646770AD75FBA1535CCFD1DAEDD08BC
+:10F440004737BEEF87F92D9A78DFAF92F4CA3F783D
+:10F45000F9FB7EEF3FA8D1FB7EA79581E337415FA3
+:10F4600090F638BDEFB756E4EDEFF9111CA0EF743C
+:10F47000FBAB9C18EFB0F62185E4CDDABEF6FF2D8C
+:10F48000DEF5DB2EF6EB61DFF56BE5F2F0BFF05D4C
+:10F490003FA2FF96107FD72FBC237ADF3CA0DBFC76
+:10F4A0000C2DA4187DEFF8497F8EA4CF60FE9BBF82
+:10F4B000D72F73690A970BF3453B0D6681DFBFECCD
+:10F4C000F7A4B22EF01D15BBFF44FA31A4FF642946
+:10F4D000FA4FA04AB9B14D473C8E7C5CA17720A47D
+:10F4E0009F6575D397EB47195BB6AE2C57B970FF84
+:10F4F00089DD5F82FB1CD2F524526D34CAF59F343E
+:10F50000E27D806D623D6ECF8C24A7221DC53B1C21
+:10F51000AB853C68F629967847FB7B69598F2B03AE
+:10F52000BE97B644D831DB46855EC33F55133BC911
+:10F53000EF8F254C0EDCB01CF2A7C209A47FC9F7DF
+:10F5400029283E05D6F51635E69B13EC1B278EFBC6
+:10F55000C178BC5FCFF78336F14EEC23E29DD87DB6
+:10F56000B81FD0BBB17C3F781CDF891D8FF3697F4A
+:10F5700009EF577FBA884D8E013D2FDAC7485F0CDF
+:10F5800094A5C7F13CE75426D7079142785FEF94E2
+:10F59000F0DDB818DF177ADFC7F039E57B26641F86
+:10F5A0002D1738FDBAB8975529E8EE12EBEF1B8BF3
+:10F5B0003A1DF877D4B6B73C9386FE7256CFDF7308
+:10F5C0000E0BFA7FA3DA6179CF23C06A8FD5A0BF73
+:10F5D000BE5933E241ECD77A6F8F191105E1DE068F
+:10F5E0004AEE8390FF43E7AB7E7A4735A43394B36A
+:10F5F0002E5BFD40DB422503C66719FE51783E387D
+:10F60000901DE99F66B523D17EAE0B47683E03D8B7
+:10F61000910AC6EF9CAF1D791FE234AD8FAE373132
+:10F62000CE47D9AD03F3C9589FB083A2563925DF21
+:10F630008596714B6C645586DFDB9F0FEDED5C2288
+:10F64000BE07F042EF4FE33C918E597AA782EDED71
+:10F65000EFE85DE8FBE077F9C47BF185ACD0F23EE2
+:10F66000B858374B051FDBFB91713EB8CEFC438C7D
+:10F67000D76F7D3571BC497CF6087CDAF1978D8FA8
+:10F68000DCCD84F1B7FA36C6745C6765643FBDD7DC
+:10F69000CBE7617A7FA64DECA5929FFF28E250361A
+:10F6A000A4713ECF167CBD7D1FBFF7990DEB16CF21
+:10F6B000F7F2E4FB342DFCFEA8E4E7B488F5FEA9DC
+:10F6C0005C070176C83F07DA2FAFD7C47B2D563EC3
+:10F6D00095743AF5B98BF4869E3227BDA769E7E7A2
+:10F6E00034D641FCFE2DE0F70E80BDA7F372E7286B
+:10F6F0007E3E44F6A39D3E2C233217CBB75DCBFD57
+:10F70000064FFA443C96A0D7B6518CEEDBDAE551B1
+:10F71000D730F248D26F9B12F955DE00F6B99D7EC4
+:10F720005F96DCEACA8C6FC03CCC77327FFFDB2A65
+:10F73000AFD21685154700E5CA648AEB9CEF4BE70C
+:10F74000FABA4D8E497AAF71F37676F975A9CF2062
+:10F75000FA4BFA6D6F07F9857165ADCB7C3361FCAF
+:10F76000BA1695A1FC003BDC87F1463D7A07E95FBC
+:10F77000CFB7077D616F9F9DD9D394EBCB31F177E4
+:10F7800097D807BA9BB85FACBBA9CE976B2AFF830B
+:10F790008FC721F43063EB259C37AD7635B3DA990A
+:10F7A000AC1EECECF43E3B7B58BB53F0ADB43BFFDE
+:10F7B000517BBAE702EDE980387FB2CFABABC7B877
+:10F7C0006A06D06DF91A9DEC947EF6745CCC2B3EE3
+:10F7D000C8BC741E2F00F506B4A7190B913D619F9C
+:10F7E000CFB233558D68FFAC68B19EF30D6A47B751
+:10F7F0006A163BBA8EB56BA4F79F61EC00E4DB5A46
+:10F8000052B7929FA43E97CC0549D749C2EE68C330
+:10F810000E47A35FE7F6463C17BF41F863EB2FE5C1
+:10F82000EF3A77EE73915DD6D9AC51BE32AEC515C5
+:10F83000187F99F44FEB5C8F947187BDEF8E015C5C
+:10F84000E8D7EB6EBDC6F2CE6B14EB69FDD725FE93
+:10F85000DDD70ED3BB632363CA80EF93A4F939DCF1
+:10F860009F1EFD8BC2F9EF6BB46E96097E4B6F3E07
+:10F8700041EFA9AD2E5119DA6D2399D188EF388F58
+:10F880005C6CDB57C47A5B29703A9245EE25FE1614
+:10F89000EF80C9B8F6EEF81D29A8276449F95A6D1A
+:10F8A0007DFF6BE9E3567D61A4EDFE7EB6E03BBBD8
+:10F8B0007C7D429E0F09BC901E9E8BA9552E0CA6E6
+:10F8C000FFAD5278FD379287D1FFF60D8CC7874484
+:10F8D000BBC1F4BF0F50DE1AEC9FA6FF7D9029DF5D
+:10F8E000B91A5AFFDB92EC94EF72123D979EAFFE6D
+:10F8F000D77461FADF8A56D0FF9421F4BF9D5CFF74
+:10F90000EB1E4EFF7B68E16CFA73B342FF33C74DC9
+:10F9100099F5BEDEB8A96F86DCFAD0715317A4FF43
+:10F920007D22E2CF245DD788F598DD3EB0FEF78DCD
+:10F93000E4FFBBF4BFE792ADFA845DFFAB147CFC3F
+:10F94000A5E97FF543EB7F127F52FFDB73EF131BBB
+:10F950006379B8CEF248FFEB1A46FF7B4FDC7BCED3
+:10F96000F3DBF4BF168DF4A45EFDAFF5EFD3FF9685
+:10F97000B669642F0FA6FF7D80FA5FC9F0FADF6ACF
+:10F98000D4FF82A8FF8DA7B8AFC1F5BF768A0393D5
+:10F99000FADFFF4A3E3FFD6F387BF4CBD6FFFE0F08
+:10F9A00059CD09A4008000001F8B08000000000052
+:10F9B000000BED7D097854C7956EDDBEBD686935D5
+:10F9C000575BAB2584B85AB00408D30261C0C14369
+:10F9D0000B642C088B58ECE08CC3D7422C02897C3A
+:10F9E00022F19699BCA70B92B02C24D132622C1C28
+:10F9F000CCB48870C41827CA32134826F35A8678C4
+:10FA0000EC2476F042269E386F5A0B02644D1ECECF
+:10FA1000D819BE0909EF9CAABA52DFDBDDEA16E06D
+:10FA20000CDFCB93BFE452B7EAD67AEA9CFF9C3A4C
+:10FA300075BAA7AE80F8F209F9BB3A27F15908392F
+:10FA40005DB788A60F67F6BE1A574CC8279B48912A
+:10FA50002213D29FE9DD8F69A59C149D24F4CF5A0F
+:10FA6000721FBC17E05F909FBAC925985208F9C26F
+:10FA7000D345F34578D53AC50E2F09B11003F115DA
+:10FA800010F2C79BF087656FDC2404BE73C7B0EF2C
+:10FA9000FE92D412021F54F82B56937B09F91F5380
+:10FAA00064F6DD072BAF62FAB0F2DD549715CA5E3B
+:10FAB00087EFA1CADDD83294B7F7082EAF957584C9
+:10FAC00040BB1649EA6A86FAAFF75FF6D643DA9882
+:10FAD000642F12A1AAE229064216409962C148E0A9
+:10FAE000FB38FE0976E7E65242460577F11468CF07
+:10FAF0002879889BD6E722E509F81DA1FDB0C5D776
+:10FB00003E590EEF7F2129B624CC7F3CC980F56C8D
+:10FB10008F65F5B82481969B9245C88542786174BB
+:10FB2000DB08941BEEA8B41148BF6372B72D86FEA4
+:10FB30005C7E43749E80FE0C5BCBA724158EB7BF02
+:10FB40008E7FAFA65FAD2374FEB19C04F52C33CA43
+:10FB5000467CAAF9EA73798C48E7958E05FE37DC76
+:10FB6000B9710AF61FBF27F9E3E59679734BB11F08
+:10FB7000CB89B301EBD17FD7688401E3BA6E8AF7F2
+:10FB80009E1482DBD916B7EC4109FA77D14CAA7AD8
+:10FB90000B83F377F2FE13975196605D7189715D67
+:10FBA0004DB8AEB984D457C152E7E2CBC7A4E1D96E
+:10FBB00034DF70139EEF2CABFD22CEEBB004F311BB
+:10FBC00030BE27C2CD0794930A27311F31ACBCBE8B
+:10FBD0005C50BDBC9C7E9E5C92ACE987BE7EE2F030
+:10FBE0009B914EBE6835F65B6C903E63BAE68FE142
+:10FBF000F939F8FFC6213F9437C0886F02BDBEBBFC
+:10FC00007AB911D7A794BFA7E5B2C7CBD1B4189CD6
+:10FC10005E29114ABF2A3D441C0F2FB7DCE88C6EC9
+:10FC20009E8C51CE93F1D6E629D2FEE909DA3F1235
+:10FC3000DD37FDB87FAC91F7CF8C4481CECF5DBC72
+:10FC40007F5E09DC3FC4E131AF07BA11133AEC150E
+:10FC5000565C5F8366FED427E9067A52DB017AAAF6
+:10FC6000E67470D039CF26433D8399A40CEB7B50CA
+:10FC7000B4EE3D07EDFFD6B52419D837295958936E
+:10FC80003508F526279A69BD92E83E1E0FF9E4571C
+:10FC90001682FD1BEE73E707EEB79FAAFB97287647
+:10FCA000C322286F21B5BD940FFA048303F86A9527
+:10FCB00040AC31E3E3FDA96466FC9478EC980FABAB
+:10FCC00026E077FA724019D61258E762CE0F8A39C9
+:10FCD0007F27178C03B84F5CF01F8E6B2EE7FF76E3
+:10FCE00022387DB0CE35EF894E2F144BDBCCCAA91C
+:10FCF000F5CD7D5DA4FBCC425A3E126DF85D407E91
+:10FD0000F6B8BCB0E8DEA7E13FA0DE9DC556AF0F58
+:10FD1000D24F7FF0D19CF301F5B6C83EF354C86FC3
+:10FD2000D94C9C28E7761EDB2B201D5C921252904A
+:10FD30005FC1DA17E23E847976FA709EA17F38CFF0
+:10FD400052AE2FC600DF492F8B9202F58EDC78DE93
+:10FD5000560EEB71D56F29C3F9FBCFBA6B73CECFBB
+:10FD600020E49B404F4678F6D6C510A38990EFD487
+:10FD70004934FDBD3A074DFF439D4C9F67400EE35C
+:10FD8000F307208731FF1F410E63FA9FEA5C34EDD1
+:10FD9000AB2BA36992C8E8458A2FCF72423B7D47BF
+:10FDA0003EB7E52BD08FFE12ABD302FDEF3FEB9EAB
+:10FDB0003ED17E867536B175F39970DD5A97C5557B
+:10FDC0007943F175BEAF3E6F75AF2D81D20329FB2C
+:10FDD000CD824C82F8BC0545B9887CBE9CAEE3A5BB
+:10FDE000AAE4B647B01C2995860BC6F97DF8FE1823
+:10FDF000C97000BF7B0E696F02B9EB0ECB375C9404
+:10FE00006F7448127D3FA430FE11AE9EEA58D6FFB3
+:10FE100060F9EDA1DF15F27AAE9EE67C288CBCEA93
+:10FE20000EC77FFEC4F2AA27021F4E32C98902D034
+:10FE3000C96F3B45A208E3FC0EF0D8CD9BB09E5B9A
+:10FE4000B1606E70BB7F83ED5AC6D3694D0C77E904
+:10FE5000CBFD3091CDE327AFFF8740A8FC5B4A7113
+:10FE6000DE2ED60562EF7EBB0CF7E1EE6203910554
+:10FE7000DC97CE03D8EFB4CD06AD5CE5F8701BDFA0
+:10FE8000A369A4FCD062243685507E92C5EB1BF694
+:10FE90007C39D105E3CF42BE82F2F769D8F7504FE3
+:10FEA0000CFC877CA5B2C734E00FA8378D18070279
+:10FEB000E5EE74CE2FA6EBF8457F82CCF81B9F179A
+:10FEC0003B9F17BB0EC7B60B6433EEF3C3994C1EB2
+:10FED000A9F8B40AFB0A74FC5F895A1C739CAF9F93
+:10FEE0009ACEF2869EC79FF0EFDAD39D6FE4C17C75
+:10FEF00029174527E2EDB8A29447B7417AC415E720
+:10FF0000A4FB90F7CFC2FBD76A506CCBB3C7DBF131
+:10FF100002BFC1E709E037B87EDDC06F30FD12F0E7
+:10FF20001B7CF64489FB67F530FE99526AF78AD04C
+:10FF3000B5112E77880EFFEB71BE91CB1F753D6B0F
+:10FF4000C2E07D956F7F6193DF6482FCC3BD1CEFCF
+:10FF500037983472E20B4F6BD73385EC7BAB0EFADC
+:10FF6000B5F5B4287BB3B15EED3A12B95CC07EB78B
+:10FF70001F15C80B90FED0FFCF12F26BC569242766
+:10FF8000B383E5843191AD7B4AD3FA7DE9F8D22180
+:10FF9000A5A39CBE5B7157A4FDAED2E376C2E8D1A7
+:10FFA000DE119DBEB42A31A2BEB42A3184BEB42A69
+:10FFB00091A8EB4DE9B292B73BBD25349D7F596DB9
+:10FFC000C75D40F9F1137C2DB03E4C53BA463A4F11
+:10FFD000AB7504CEA74ADFFAEF545C00EB3AEC674E
+:10FFE0007287201D6619FD027E3FFD691D9F111F4E
+:10FFF000A3FC2FDCFCEB71C2E5442D1E50BF57E77C
+:020000021000EC
+:10000000D9CDC7ABAF47C501C82726A2A320FEA004
+:10001000C0BC158ECFE755BECFF5F337BD1B069993
+:1000200001B2ABFD6C9392877CA281E2C32BB84FE7
+:10003000D9FA50BED92DF0E9E5FBB19FCBD117938A
+:10004000D83E9DCEF7E5E10691E2B0E9C0770C30ED
+:10005000FF792A7FF530FEA9EEC7D4722D3E53F703
+:10006000710AE9939603FFA8E9011C2707F3577566
+:100070009D466E00C78072574BCDDEFD42F07E4C30
+:10008000253E09F377C27E45DC76D5FFCFE6A9CCC5
+:10009000FEE03C2907AF0F71D4BE968EFBFD61C90F
+:1000A000D90CF9D392B4EBD59E4EE8B8F4FCD41F2A
+:1000B000819FAAEBD72E94FF3C2F3BF2FADD29BE9D
+:1000C000EB477B4B4AF4F61663A29DD243387B8BF9
+:1000D0002A4FF5FCF770A2ACB5B77880FF1622AEB8
+:1000E000FC7E961FE827DFDC7BDC8EEBF0AFB1E413
+:1000F00004D4271C7F9DBE1FFD087066003DAFB372
+:1001000067AB7A818DEB0536C49772BA919085847E
+:10011000984D176A91EF5C2EB612C4CB976F3CB521
+:10012000159583CA633104D7BFF2FAE7B65065A1CB
+:10013000C342F973B767EB054C5F39260A28778607
+:10014000AC5A7E77F958A5E4867E3666D76E41DCD8
+:10015000BD2CA6E8BC04F517744B948F954AEB4B65
+:1001600013213DEB344BF759D97E2974BCFD2AB2DB
+:10017000AA7BE58F9625C1D35990780E9FF39C45B5
+:10018000CB9391ED2D5A7F0E9FAF627B50FE3ED7F1
+:10019000DEE5296CEAB2CAE7E0C3FFCE6CE8575649
+:1001A00093409A21F5CDA66F9B912FCF7DA59D3EC3
+:1001B0007BBBF799112F3ABBFAE8B3E8DB5DF4F9A2
+:1001C000DD9E0A9A0FEB2112953FC2DFFCA3253476
+:1001D0007F5BCBDEF94BA0A1ED9D16D900E31F1686
+:1001E0000C3EC46B4AAB48F54AC923B830BDB34591
+:1001F0003C61A1F95F5A81F4AEBC2210DC0F83B0E0
+:10020000BE09D0AFE32F885E9C5FE9B440907EB614
+:1002100076B2F2D54DED141FE39F1148E58B9CCECD
+:10022000179E3BBCF67EF8EEC31F1B7AF7E32089CE
+:1002300051E1FBD080F4F3C54ED115CBEC1B0AC3C2
+:10024000574DFB6EC254CE3D635402E571914F9BF6
+:100250009EFFBA36FDA160A07869C105EDFB85BFA0
+:10026000D4A67F94C0E50261EDC5C50802B6573239
+:10027000DE2FCA1F7E043207E9A168EE9A37713D6E
+:10028000C8FF329019300FFFC6D7ADBFFC0B59B075
+:1002900015C867E74E9B5F59185E0FA88C569F687C
+:1002A000617AC03AC88A49A24F1F3EFFC5EC4A583E
+:1002B0008074DD2C3A4F40DEBAC78A64E49739C8AF
+:1002C0002AE7417AF567CB705F5D2A7FF11CF2D394
+:1002D000B8820B55B80F1615C71111E99CD4E6E08A
+:1002E0007E5C422E88B81E679328F3237F41AED1EF
+:1002F000F42F57C553795DD199DD65A1F622B71961
+:10030000E9B002EAEF65F646F3E639B43F0AA1FD2B
+:10031000F22FFF0A3E3389EB616CBF73FD2A6C7FBD
+:10032000DDA63D74BFAF5B24CFA3CFB283E5023C13
+:100330007794819C9F82E96F4BEC7D9F84FD7FC108
+:10034000BAF5403AF2E78238A701C755F636CD87AD
+:10035000F2062C7F75DB369AAF2C8A73E2BC57AF5E
+:1003600016EEC1F735AB853C565F3F2DBF6BB590A0
+:1003700023CFC5F447B4DE3592FB67C86E57AFFC98
+:10038000BA11D7E7E223D507908E2F2F8E9B87FBDC
+:10039000F483A41C3AFEB86F7D244F8572BBBABBB0
+:1003A000E4ADA8C72D67EBB783D7B7D1484A8D30E6
+:1003B000CED5843D09617698D70A1C5DCD304F3B80
+:1003C0003AD977649C6ECC37B142FCB71DB54EA4C8
+:1003D000706847042A8325DE934A5CA5C0AFE20C0F
+:1003E0005E9AAE4C7DEAD986C5400F06C877127278
+:1003F00004F31D98CFD2297FFBC3E6F38B314DA8C0
+:10040000FCF5A6FECB2A05D6A38DA70979F4B3C8BF
+:1004100047D5FC6F1C79E0B3983F653129C7753328
+:100420001246F7D04585F269A813F9423CEFD796FA
+:100430005466678987FE7A92E87B5702AC673C7402
+:10044000DC3E8FBE57A6CCA3EF7D56FE34E113C42D
+:100450008D1DE7A390D51F47142FEE1F52E06E4568
+:1004600079DA705494707E40F1B5216E236EC586A2
+:10047000F474A86F572BD2F15597D1190BEB30E5D7
+:10048000E8E1B5487720F8A419507E9BDF65C67572
+:10049000AAEE117AB18BC346EF6B1950DF684B8916
+:1004A000AC40FA73A933E8BA55FA3D6B711DAA7BCB
+:1004B000C41401C6551DE34E40FEB2EE909082E595
+:1004C000463D253617E5435EDB62FCBE1DFA431050
+:1004D000DF0854AFA07C11DBF588274E32CC221BFD
+:1004E000715EF0DF401AF1802767021D7D98CCF421
+:1004F000EE2B994A16D245BCF7FB4F213D0FF1EF89
+:10050000416E7A4FAA9807BE4F1118BF4BF188AEC3
+:1005100099504E4E66FBBDDACFCA57760B5ED44B70
+:10052000E3CBB5FC083AB2C206F9574E811E01F37F
+:1005300052D9B25E40B973C5A464A1FCBB92CDF49C
+:10054000C0003AE3765CC96681F15575276623CE13
+:10055000CE4F667C6D574BD19BC5D8DEE3C4294393
+:100560007D553D156D380FD50E93D3055F5DC67E65
+:10057000E2BEEA1268FFE35D4605ED5EC3318CBE64
+:100580002F7B852ED4DF47855A1BDA459539A0CFBE
+:1005900060730A399F771F9B3A3A055EC187FB2D2E
+:1005A00085E33718D750205E9B166487065254F5B2
+:1005B0005DE8D7EE4DDAF2768E0FEC24E03D7CF765
+:1005C000B3CEFA7328EE3726B37D5B7D5A482C856F
+:1005D0004E2CEE10E7E1343426BA1330DDF86C6EA1
+:1005E000523DA46DC96C1F9BD3DFA378E027C5855E
+:1005F0000694EF6653ED564C9B5F2C30E0F85E306E
+:10060000BB3BD6235F78C140F92A74EA09A4CF1511
+:1006100047930D482F8DD96EDB459C8F745312E69E
+:100620000FAE140E48C01736BBDB1FB4A7A0992A23
+:1006300091CAFDF854662F1B34C9CB285D3C0BF8DA
+:10064000319B92925205FB24A72C7B3F8ECB76FFE9
+:10065000A2952EC8CF596B20D89F7530C618D84F99
+:1006600079091B0C3827F7986A33907E36A530FE3F
+:100670009CF3C143AF0B28176FFC4721EEA30D3944
+:10068000B53B705C53F79C4F7C08EB7936AF889E86
+:1006900083192FC4485AFA30DC5C48E75836ABF36C
+:1006A0006DA0F3AA307C4DFA705E5BFFC0708D1EAA
+:1006B00067FE86D33DF0D55902F0D977F78B945E6B
+:1006C000864B042FE2B3F26E41417C0D352DA8C05C
+:1006D000FD7C322D09E76BCD129386AECBBB9FB963
+:1006E00020DE8B38426EC7F551DE1029AE5EED304C
+:1006F0002981EB8EF6429CCF5DDD89F31057938202
+:10070000807A7282E9BEA6BB9FDA7F6A5CFA7AF4CD
+:10071000FB23425A21EFE5D951DF65F4F83AE06A4C
+:1007200004E7CB396E2D23EDA549B8BF36136A2FE8
+:100730005E491423A6773E06381FCAEFF402470C21
+:10074000DCC75613A5DB18AEBFE8CF59EC8F69E9BB
+:100750003D0BE9DD46F190669FE417E51EB2C0F758
+:1007600062CCD7CB8792C7D7A59EDB83FEA64E2946
+:10077000477B6D675D137D7E8BEFFB34D1F5CD64D8
+:10078000D48F8D4E07D2CBA0A9BCBC04F779A3406F
+:10079000E75DD53FAAF978E91FA477E233808F514E
+:1007A000FB5236B6FF126D3FED74451FCAE1349817
+:1007B0000764F3E9DE7D349DEE9629FDA76D86FE84
+:1007C000048C2BDD0DFD0A3CBF480C4D679B535834
+:1007D000BF557CADCF77A4B07D95DB6420AE80FAA9
+:1007E0006778E2882BA0FEFCCE244D7AA6374353CF
+:1007F0007E764F8E267F4EEF2C4DFEDC33F334E9B0
+:1008000022DFFD9AF2F35F5FA6492FB8B04A537E0C
+:10081000E12F3768D28BFD9FD794FFCC95AD9AFC22
+:1008200007AEEDD6E42FBDFE254DBA84FCB5A67CFF
+:10083000D2CAD229280F2E82B84639BF3FE1E5033C
+:100840000AD0414632C38D20E8E93E57E57A243B81
+:10085000AC7ABEAD9FEF203B6C0FB30FE8CB25A465
+:10086000466787AD19B3C32A07D0BE14CE0E5B1DF1
+:10087000C90E7B7A623B6C55AF49632788D60EFB65
+:1008800054B21C951D963CA6B503BD740DB00BF279
+:10089000338789CACF973ADF2943FEB862C132CA8B
+:1008A000D7D579B2C3FCFBE68FA7573C6A28473BF4
+:1008B000D58A6C772CDA09636427AEE8181F9E2C62
+:1008C000FFCEE4EBB05BC7A707553EDDA3E5D3231E
+:1008D000A7C2F0E91EC6A707A3E4D3BB7B189F7E7F
+:1008E000E09A16C72CBDAE4D6711DF818CEC3BC181
+:1008F000A75D1743F169957FAA7C7A2BE7D36572D0
+:10090000BB11E721CD23906468FF0F686F4F1DE78F
+:10091000EBDB9AB47CBB86D3812A5FBF56F36A6C4B
+:100920007E807C1D2072DB4C9C974E03D583613EFC
+:10093000B390BFAAEB7A9EE3BC6EE28A9B89FCD699
+:10094000CBE64FBF6F7E97C2CAE5745552FBD97094
+:10095000935886FBEB50DF4CDBFD50FFA0679911ED
+:1009600055C541541C20BDC35BD2BD0F3EF95E8A04
+:1009700089F6EFA2D97B90EAE32F88F249364DE65B
+:100980000D683F26CC0E37D2D59E856AC16067A51B
+:100990002D07EA7D2285C9F1814ED60E31CAF49C1D
+:1009A000FB6AD7FC64A403B55F4FA688B45F578881
+:1009B000BB6D51001EA6FB2F878CE1BE6944FD1B59
+:1009C0005B1FE126AC4366A7A858605EB3508F87D3
+:1009D000E7B46E8B0FE73940CFA7FB0DCAD1F3D533
+:1009E000697C1F4F25DEBE627CFFB8562E4EED801F
+:1009F00072F07D468DF63DE1F851E2747085B0737A
+:100A000082CF5CD19693F87E977438F2149FFF6181
+:100A1000F810E9A3E634E0F1ECE0F10E777CF7356D
+:100A2000C4E3535B05D6967EBC5E91E2E52C2FB302
+:100A30005B8C987ACD483741E3F5B2714C3BCD7071
+:100A4000B27E9CFAF155F69A8602F78FBEFF034DEF
+:100A5000953637E51332D5A7BA9B36D1F5543A44CB
+:100A60006A97B8BF93EDFFFB3D862EE4BB9F21BD87
+:100A7000F5880B07F093FB711DEF6D76517B16A186
+:100A800072E4F5646BB3B284EA6536D49F063D0622
+:100A900082F437D0399FEA57035E4142FDEA07DE10
+:100AA0007D549FD2D3B33AFF83DE7A4A6FEAFB7359
+:100AB000EA3C7B19DD0D7BE7DB7203F2CF737A1B17
+:100AC000244ADBE210F3AF9F6FD200F4671FA73F09
+:100AD000FDFCEBE75DA52F75FE6F97CE06F9FE8A4C
+:100AE00096CE5EE6FB4E3FAE2B5794B5540FAB014E
+:100AF000812D87A0AB16BE8F5AD83E0A1A9791D97E
+:100B000085A01CDD47FAF1801E49ED36FAF1EC1A9A
+:100B1000F51D402340CD6993B6FF41FD26745DFA73
+:100B2000DA9FC9F217A25D56D1D9651751BBECA067
+:100B3000CE2EBB22353ABBEC28DA6551AF44BB2C34
+:100B4000E27D6E97DD75FDA12D4C1F67FE23637658
+:100B5000D95E5140FBD5D6145973FE3DDACBECB2C9
+:100B60003EC43F0BD04E2527A1DD5C3D27A9C02EFA
+:100B7000A01C6FE0E71BF837C179D4EF9319CE9C26
+:100B8000E03CEAF7C90B82CFA37E8F46DC0591F1EA
+:100B9000D636DE9F8878CB13FA1CAB2C95D1931EEA
+:100BA0006F6DE7FDB477E8CFBD6B27C45BBBF83949
+:100BB0006958BCD50D78CB1A1E6FEDECB935BC5514
+:100BC000C8D73122DE4A65EBEA7530FA51D7B5064F
+:100BD000CBA31ED51BDD39E3CCD488EB3A3335C427
+:100BE000BACE4C65EBDAF0C0C717D0303FD4293A03
+:100BF00071BE863CCBA99C965A0509EB4FE4B8E13F
+:100C0000B2E0DB42286E7151BEACB7A75D4F62E522
+:100C1000109FA3DD4CB5AB05D9E760EFECBF6FDCEF
+:100C20006EA8E603486CA7F9BCBD5F403913EAE340
+:100C30000DA2771FFDCE45F5BD68EB837F7A305F4F
+:100C4000C0FA52597DC694F1FA1AD2159B2937443D
+:100C50007D507CBF3D647D5ECCFF05E41B03FB251E
+:100C600043BFE6603B5C4FD9AC507BE0E4FD6E9C3B
+:100C7000D42EAEDAC90715E6F71AD43FC83E107A6B
+:100C8000FE68BE92CAC64B2477821068A72C97E8EC
+:100C9000BA455B9F01F3B343D4C3ED9D63E32D538A
+:100CA00034F5C2DB7D6ABD86D0F5D2796CE7F437C6
+:100CB000D9FE7C4DF79D5DED27D1E269751E863723
+:100CC00027DBCC949F68E927496D4FF7DD71FE5D06
+:100CD00083E06E5B208CCFDB8958A6BF9C2892B244
+:100CE0003604F0AF3F72FDA43F91D92D169E63F8F4
+:100CF000E46A57FE89FDB4FE3FD27D8DF019F78F6F
+:100D00006267E5FD05B5664CCFF4CA36A00C727576
+:100D10008D7933EEF7AB82C145ED6B5D962EB4AFA6
+:100D2000419A507F8B7DE2094CABFAD21E3E3F28A0
+:100D3000ABA614D3739313C897AFA0FD04FA392060
+:100D4000496667403F779231BD45C4F9DAC3D33075
+:100D5000CFBE9BDC2E82E7597B38BFDA0372057168
+:100D6000C79EF1EF287F2BF01A357ACEEC1EAD3EF0
+:100D700034A7579B9EECF956A473AD57EC9CDF71DA
+:100D8000BBD67442989D47F60BB8BED3B9FE93D537
+:100D9000C4F043D657F5F841EF27CC7090CCEB590F
+:100DA000ECD79697399F977538A271A69BDACB87B7
+:100DB00063D97C473A378DE7FD8EF6DC746169852F
+:100DC000486DD011F4F256A3BB19F5B15687A95856
+:100DD00061454A63217F75B120A1FEAAEAE73F7B06
+:100DE0007147CB4AF9CEEBE7EB393DAFE1DF893014
+:100DF0006BF85EAF5747D2A323E9C7BF2D1B127410
+:100E0000B879527AB4DEDE59ADB377EE407B27A4D1
+:100E1000779C8E67675B6ABF2669EF44C2C4C9725C
+:100E2000B05763FAFBB4D2C74B7385603BA8A3B439
+:100E300089FA714C2B33509CEE78DCA8D18F62324A
+:100E4000B578F6552BC30DB071A97EBE2689F16128
+:100E5000154744C269AA1F53449CD611DA2E76D690
+:100E60001EDA2EB693CFB7FDD8DBD44EE48ED23F38
+:100E7000B122925DAC21827FA2726BFE89B25DD6F7
+:100E8000F85985C36991E4C5592E8FC6FC193CDC1D
+:100E90009FC1B39EFA23CC3D92CDFC19B87F03B914
+:100EA00040DEC5F3BE815E2827A35FC35EFA7EE104
+:100EB000B9F93F457BF3E82981A0FFC0FC5302F557
+:100EC0005B701F13BD68A71EC573FF00BF07D50E5B
+:100ED0002929824BA0FE1FCC3F01CAADC860F67025
+:100EE0006A3FB91CE35CE1807A8E3F272065A2FF50
+:100EF00003F567A86A82F202B6BBDC8CE5078F882F
+:100F000064BFCCEA0CF46B181436507D4EF9B1A1D5
+:100F100017ED3D417E0D4D4C8FBB5DBF86487CFF7C
+:100F200037A9D1F933FC06D723757CDD6C61F081DC
+:100F30008A0B111F180D28EF953611F907C7E1AA82
+:100F40003E63F744A75F6D51E552781CBEC51E0293
+:100F5000876FB133FAB1D59302C4953BC538E789A1
+:100F60006CB4870F391D90FEB8213F07EDADC96BFA
+:100F7000364DD90AFD98EFE07883CB79C75CE24320
+:100F80003EDEDF904BCF339BEB98FF94E5FA6CA2EB
+:100F900080206981B402FBDA92596BC1769B8B7316
+:100FA0006C32DA4B1AC4329403D2C2D35979F0FCB2
+:100FB000CF5F3F43F31FCD34D1FA472A008F140689
+:100FC000FBB57BD359FEB319AC1F7BAC12F76B3F5B
+:100FD00061A6DBC3659471FCF4DF3265BD7E01EF71
+:100FE0002F9172464FDF3BBCF62FE9CCA87EED6E09
+:100FF00072333E98CFA84FBD5F3BFD53CF01A09108
+:10100000F845310ADA75615F2C0DD417E3FDCF5C2A
+:1010100040BEFA71D9E366945BF192910C04F0D171
+:101020009D1D820FF10DE0223250C0DB43FB93D1B6
+:10103000F9D622A477AB81FAB72574C2BE01F9298B
+:101040009EDCD8B448C67B285B853418B7A971E309
+:1010500002AC9718BD0770FF5C4C62FE72490972C2
+:101060003BF2BF2FBF6DA2FE59250B0BA99DA1EF2F
+:10107000BE59C7E3D13EFD7E2CC17D57B2F0F4715D
+:101080003CD71E78DF42D34DB04E6E98AC03F0F4DF
+:10109000C2FA0DF4B9E7A27E7B04D20333E07F6F7E
+:1010A000B817B2F34FF5BE886240FBC31133F3A704
+:1010B0001FDD04826C0A9DF43496DFCB9F17E87D18
+:1010C00014DC38ECE94EC3E7FAAC6C7E5FE51A4DF0
+:1010D0008FDED81883F534DE10A91DE83C9E4BA1A5
+:1010E0003D63D13D944F00A569FCFD952CA6AF6FE3
+:1010F000147D6FA15D8DFCAD48CFCF3F3936FFE742
+:101100008B6973EC9CF960572E3D67BE52BEE6CDED
+:1011100064481FFEAA6CC0EA76940907D0FFE40475
+:10112000A7D76EF4F7B3A07F9FC4FDFB1CDCBF8F75
+:10113000F9FB9D467F3F0BDE0371D2742FFAFB59FA
+:10114000F01E888BA6BF575746D3FF50574ED36724
+:10115000EA36D3E70FEADCF4F98F755534FF9FEADE
+:101160006A69DA57F7344D1F9ACAC6B1FCD9D2560C
+:10117000C451BB3C22C1FB1FF900AE90FFEE5E6480
+:10118000F6229DED76303F1E521843FD74D65E70F8
+:10119000376563BA47988F69FFAFC9193C9FD8BDBF
+:1011A00049A4F8BDB2D0DC8576C581078533028CB1
+:1011B000B3D223663D8D80AED048BF274EF938A606
+:1011C000DB4A3639717E4E986431B908E8E66B3FE8
+:1011D00059133313E8D54CEA939C909E4A9432A05D
+:1011E000CFF9C51FEDFE0EA4DF7DE16C6B0CD27D47
+:1011F00049F1ABC934BDAB35261BCFD7972550DF9E
+:10120000176557EB79781E14FCC604CCCFE83D98DF
+:1012100002F56DC641DC8FE91953EAF3B0FF84DAB9
+:1012200047E71DDFD5AA00749825012E95B0FDB3C0
+:10123000B4BE4207E053E778FA5E19706A40BEB365
+:1012400000F02AA4672A675BCBA06A97BBE4CD3C79
+:10125000287F34FD3B079BE4E0F6DECBB9D667413F
+:101260003F843642EF9FD964C64F6D4ABEB75E08D1
+:10127000BFFFDB4CFECE4AFCAED142BFEB473D2C5C
+:1012800040AF499CC6F8EEFF4C67F2A12D96D57B86
+:10129000F9618317F9A8BEBE1F4EE7E512593DA0BC
+:1012A000E03D4AFDC236D90DC8D7DF2BAF8C43BA1B
+:1012B000ADEFCC31205FF7A731FA78BB34779A19BC
+:1012C000D6FBFB0D1619ED75974A05AF09D6BB3F46
+:1012D0005BDE4FFD4CB83FC43D26C584F6C47B049D
+:1012E000C1A920DD7F40BC2658FF4BDEC30FE2FBC7
+:1012F000CB46C1896C6C6D3ADB7F0B8F89FD26E094
+:10130000436B1795BCB90AF28B4F1B69BB2FA73EE5
+:10131000B400FD329423A213B63FF971AA858EEB77
+:10132000E5930BBDCCDF8D9FC334843E87A94E6708
+:10133000FC39A7F1EBF41C66C46AA0FCFE505FFA0E
+:101340005B7271F0394C450F3B87B9672AE3EF17A1
+:10135000CDD2013C1F500E88323D0F327ACD1B405A
+:101360000FEE57EDE10D5FA77CAFDF934FFD7E776A
+:10137000F77465A1FC70F176EB1BD4F31867D922E2
+:10138000E47BCF6ACF635CE9E690F6E388E7300D53
+:10139000DC2EDEC0ECE2D37A2CA1CF611AF8B9C4FE
+:1013A0001D3A871920DE7A3A1FDB08950BD1DAC97E
+:1013B0007F9526703EAB1D677F4D29F5D39DDA05DD
+:1013C000B3A7C5956C9C4D7C9C4D61ECFFDC2F292F
+:1013D000B389F55F3FAE7E0430C5E3FE58C1F6F237
+:1013E000726A2FDFDE32F1794C779391D2CDFDE82E
+:1013F000F71BE2DCC5949A62463B755BB6765FAA42
+:10140000CF9EA96CBFFDB9FB375C34CBEDA5B85FAF
+:10141000DF09BD5F57F27D630131EB0DA847B523AE
+:1014200026380D4409A82F5636107720BE76303E58
+:1014300095F8E0A609EF631CE2F2F6592E6FEBB9BE
+:101440007FFD4194B7F06C44790BCF67B8BC6DE574
+:10145000FEF550EF51D4333E7150F591546492E350
+:1014600022A42D780602E349BD8FD15B82225079F8
+:10147000E9961505F51A698956EF8BCB8BD3A48DA8
+:10148000D624E20B1897B53043936F4EC9D1A463AD
+:10149000326769CADB8AE769D2B013A4E1789E8615
+:1014A0008E7EB2BAF4502996AB17B2D0BEE1E7FEF9
+:1014B000452A6EF62BD1E2E6248A9BFB15C6D7A4FB
+:1014C000854B34B8D93B8D9D5F0F86C1CDFF279DDD
+:1014D000E52FCD10F87D50C0CDF2247073D5E1B664
+:1014E00047E8A86E0F37533D171AB1EB70F336DE9D
+:1014F000AE5D879BED7ADCEC01DC7CEF2DE1E62A2A
+:10150000C704B819F0F1DB288746DE34717C5C48EB
+:1015100071F428E0684B76305E1E3D0B0018CA3F20
+:1015200039CBECC5F51BE88334E4FFEE8085A69B40
+:101530004DF2712BCADBF713E8B99E1E5FC36A1B1D
+:10154000193E56F1B41637ABB81BCA19B4389AE134
+:10155000671537EBF1484326E37707D3557D95DDD3
+:1015600077688E65FB231C2E69C86238A63951B591
+:10157000C34D8C4B3E7284C62503884BE646C62578
+:1015800083884B00BF0CB4305C72157109D4BB5119
+:10159000C525DD804BEEBDF3B864F364714937C3F4
+:1015A00025EF67A8FE217A5CE2D1E092A1935D5B12
+:1015B0003264C427C9F4BC7E593A9BA74878645961
+:1015C000BA39A49CBE7BF1C8E4FC424639BDE8C7E9
+:1015D000D7DFB19CE1905641265A3B497438A44567
+:1015E000A0E30D8B43AEB075AC3E161A87EC1CF52C
+:1015F0001E4039B13BC2B97DB438A499FB59A23F12
+:101600006145C0BE3C35EDCFC3CF528D8F11098FE0
+:1016100094F27DF1FFF1C6C478A3C821D37146C20C
+:101620001DDF486376F90122BD857479D6A14D137B
+:101630008742E3DC54A9716EBCDA38376978591AED
+:10164000F98FC349CFB192D572AB8D9A72B1288B05
+:101650001604DFD76A4B93E9F797CA5FCCC27DAD1A
+:10166000DED7D297EBE2E3D197EB3B19EE9EE22F68
+:101670006B719E4716580D2877473E62F70B7EF731
+:10168000628C01ED5B669387F28FD1EE7C9AFECA85
+:1016900054D5AEA4F593E9F6BC4AEF99F77B052A39
+:1016A000A7AAAE5BE8BD2B7382CF9608EDBEE460BF
+:1016B000FD57FD6954FF97BE930BB99F8EF338FA1F
+:1016C00065EAFB3580FD42B987FD2A0EEED710F69C
+:1016D0000BCA3760BF42F8EF747B96BD55877A6CB2
+:1016E0002FF40BCAD560BFACD82F972D11DA3D9CD3
+:1016F000A6EDD79087F54BD577229DFBED4D8BEE70
+:10170000DC6F2F6F477FFED71CE5BDCC7AC7E4EEB8
+:101710006536F0F9D6DFCB7CC1ACB3D33849CCA267
+:1017200079B05E698C6EDE439988F9FB2D14C7D8B9
+:10173000643FF95221C6D3798ECAF3AB61E3E96401
+:10174000660DC2FBF70BD4783A12B587AAF174FA8A
+:10175000319E4E005EFE76BA2AAFA28BA733502090
+:10176000F2F2B7162FC7FD29C5CBD916365E0E315A
+:10177000E3B98C1A2F679B87C5CBF9697A94F1720C
+:101780009E67F1722EDD5848E3E50C7ECAF172F4D3
+:10179000FACC5B056C7D3ECC0F7F0E30517C9BE01C
+:1017A0007380C9C5B7F9773BE397079DFBA95EA690
+:1017B000DED30F47778F6646477724637274B7A2EC
+:1017C00040E4FCEED6E86EF79F3C4E13E85D29C17D
+:1017D000719A3232A2A4BB834077A86F619C26EB3A
+:1017E000A71FA7E9494E67E1E22BED2B60F4174AEA
+:1017F0009F9E90FE82F4E9C9D1DF2607A3BF70F156
+:101800006BAAB16128B7FD1E41E3D719149FE2749A
+:10181000687FC805FCBB70F16BFA31DE02764617B3
+:101820006FA15DB85080CF3B1D472152DC4AF53C8B
+:101830007F909F0FFD55863D64DC4A356E420A2934
+:101840007A03F5B0ED3526D92B8FC751D0C7ABD170
+:10185000C7C7B0FE81C5BBB882F12EB283E3D5A85D
+:10186000FB229594AFC0F39A1DE5CCAFE34A84B850
+:1018700035C4E13E1018F7220A7AF29B909E5CE193
+:10188000E8C92D7C1AF4F4EB19B7464FAFCC1026FB
+:101890008C8774354CFC8E4F8B9EAE4688CBA1D284
+:1018A000D3254E4FE723D3D34ABC27B0E316E969CB
+:1018B00028223DB9E9F99F9BD3D350447A62F25D67
+:1018C000A5A728E4A3969E82CFC927454FAA7CB43A
+:1018D000010D69F1DBC4E77087FA4EAD453BDE00D0
+:1018E000DE9380BCFA9E5C7A4FA2BE41900418D76A
+:1018F0000F1A1243DE9350ED2F03687709A0BFBC87
+:10190000A98CEE46B8FD65A421D796ABC90F730E1E
+:101910004422DC8FD0D95DC2DE8F68B833F723262E
+:101920006B6F499F1AC6DE7245A2FE3435783F823E
+:10193000048F33A2BD45BD1F11C6DE42482DD533ED
+:1019400083ED2C4E6A678974FF66CCCED2A3BD6747
+:10195000534F7A45EA973A4AC8DF0BA8376D684378
+:101960003FF1FE8E5C6A1754D7F31AF74FE9C60AA7
+:1019700033D0DEB7B105EF715EC918D387DBEEFF58
+:1019800014E86C6F043ADBFBFF289DEDE0E30E47A3
+:101990006761EFE1DC369DF942DEC3A9413A837904
+:1019A000AF8CD69E778B74F66FFC5C5EA5B3EAA312
+:1019B0006F1C443A5B3095F943AA7466035A5F94EE
+:1019C00044F556DF52E47B7603BD37AAF2C3DCAFA1
+:1019D000126A0751F5D870F778AAF01E0FB55B3C74
+:1019E000CFEEF1746BE32BF5F37B3CAA1D43F5C7F7
+:1019F00054ED186ABD433C6ED3108FDB54C3EF0720
+:101A0000D560BDC521EAF5B0B84DAA1D42AD57B5A8
+:101A100043D862587C0562F45339E65F4C9CE8A7D2
+:101A2000AF8ECFD6647621DD50524F62E5511EE86D
+:101A3000E5807ADE51C5ED587AB950ED254A2CC6BD
+:101A4000A5891194D8B990E6F7532E75919EE42993
+:101A500088FB04FA7C3783D93B2EB55AE83998BF06
+:101A60008B9C4984F743B1C299C4B9E3F9FE760B64
+:101A70005DB7B5CFEF6AC5786B7ABFE613B1CCAF6F
+:101A8000F972BAA918FB77A2C89DB521801FFC3B4B
+:101A9000A7FBE144E607A7FADD0FBC927F02D74916
+:101AA000F5BB3772DC742D8F958F27AE36432E1918
+:101AB000F36BA67EABD0A58144766E372018581CF8
+:101AC000E25798FFFD00FADF63BA9DC75191B3E971
+:101AD0007D80212BEBEF41EE77FFE198DFBDD3EC6A
+:101AE0000CE8673CD1FADDAB7EF87ABF7BDA8F5C1D
+:101AF0008C4B25B8F8F9DA5DE5773F6D063FCFFAF4
+:101B00006FF6BBD7FBC3B71A890FD7AB758940E314
+:101B100075119DFFFB6B9D1FD7E06BD50FFE1B2F33
+:101B2000BE9689FBE64EFBC19F9AC9F891FEDEF98D
+:101B3000DDEE07BF1BFDE0E510713F7A3E1D3FF86B
+:101B4000C61BA28BDEBF7F9CC5159AAC3F7CA3EF62
+:101B5000FDB25C946B99D94E540DF4FEF1C6F1734D
+:101B60002E4D1C28B209E8E6BE71BA894F5976D5C8
+:101B700068A3FB939E63ABEDE3CE1C0898C791145A
+:101B8000D22402DF325E67F4A3AFA7AF6763593692
+:101B90008CE7B7C7989DA45AAA7D0B0DB7C62641FE
+:101BA00036427D254D02A5CFEDDD8217EDE7C6EB70
+:101BB000665ACFF6EE7637BDFF9E17436205E67F85
+:101BC000306002F8C1E39E34F3B827492BB751BD0A
+:101BD000F463AFD08BF2AF2A4531E3B988492232A2
+:101BE000C6413349DAB8245505CA6BC8AFE20A5971
+:101BF000BECAF7E30BB4F14A729ACCC4953C1E6F8F
+:101C000063E55123C569E3F7D6BC36AA7FEAE2CC87
+:101C10003F912984F99D86641E675E5A8B7ABD1AAE
+:101C200067BEDFAA8DF3FC736E2F54D36A7C562CEB
+:101C3000379938CFFD0D61E2CCF7E496623F6E2311
+:101C4000CEFC5F65A686FF9D861FF1FE4FF6771AD4
+:101C5000C6EF8F393572ECB54C46AF833A3976F51D
+:101C600094568EA971B73ECFDBBFA4BF3FB69EC9C5
+:101C7000AFB1FB63A7407E0901F7C78E68EF8FA95C
+:101C80007CEC92557B7F6C84DB1FF4724C7F7F4C25
+:101C9000E57F7A3936768F82CB313BB9BBE4D833D6
+:101CA000F977C7FDB1E69912F547EA8F65F3BDE410
+:101CB000DA85E5882756E565D3785F7F71FDDA39E7
+:101CC0004C9765B2F4D7F2395FBBCBEF83FD9CDB59
+:101CD0002D23DD075B59A04D3F244F2E7ECA9D96D4
+:101CE000836E9D1CACE072B042B9BBEF833538C641
+:101CF000E223D1FB60E37C468B97374E0B8D9787B1
+:101D00004E69EFA9C673BC5CC0F9CCA08ECF0CCDD8
+:101D1000617C6648C5C99CCF0CA938B955CB6754BE
+:101D2000F93B1896CFF826E4332A7ED6F3195A2FBA
+:101D3000F099F85EC6670270F65DC1671EBE4BF88B
+:101D40004C1BF2196BF47CE6AF67DC1A9F5967F500
+:101D500019E9B916E72FAE0EF7732BA1FC1A8748C5
+:101D6000EDCA2B1EDD40711279209EDE7F08C16F07
+:101D7000FE7517D24711F3F39F2CDFC999111DFE91
+:101D8000BEDBF88E3EEEDE2E7E0F7597F7EEE63B5D
+:101D90007BD318DFF19B088DDF190E376EE3F6FB5E
+:101DA00060DCE8A378B12293D533EA49A6F10E2688
+:101DB0006B07F84D18BE367A24B41DE0DD995ABE83
+:101DC000A6EAF3A389ECFEFDA88A9F8E30BE36AA50
+:101DD000E2A7D6D0F849CFD72E8DF135CFEDE1A7C8
+:101DE000EEBB133F915977AD1D80AE7BAB93D9010C
+:101DF000F4FC47D5FB3FED7875BF93A3C33FB76BAA
+:101E000007C822F2A1D2ECC8E5A28D2BA7DA01C641
+:101E1000E2CA750A346685CAAF76F4DC5E1C503DB2
+:101E20003F7AA8F89D9252C3EDF3217DDCC8D2A37E
+:101E300007A91EFBF607496B303E30FA21A39FB27B
+:101E40005E9F7B97DF5F5DC6FDAED5FEABBF339770
+:101E5000B63A796DB14CEF934FEA77E6726264431C
+:101E6000AD95DE3BE67667AE0FFF6F167F57B5CBBD
+:101E7000E6C45CEB437FF69C16E2AC27C1F6D620A5
+:101E80003F2C6B747E58EF54B816A09FF860A3489F
+:101E9000EF910F6613DF52C465A906CA4F0762852A
+:101EA0009EDCB9841CB86776567F809E7DE0D9FCA5
+:101EB000AC01C4092D02FF5D1AC9FC4840FCBF8A71
+:101EC0002CB3466FEFDFCCFDA9A11C8D7F6D94E88C
+:101ED000EFB10D24303EBCF199BD4F627CA5580393
+:101EE00071233F9CCDEDAFFA67F2D32F970F05EC2E
+:101EF000C7E4D52EB33B01FDA1D63B9480F6F5CFC8
+:101F000046859D9334DE38EC467AADCAABB2238E5B
+:101F1000ADF2C5523EB0E358C54B6857999DC7FD19
+:101F2000C274769B9DFCFEC34E7EDF61C76A27F5B7
+:101F300083D9C9ED42C9DC4EB35377FF416F1F4AC5
+:101F400047879BD4F17B0563EB8B0592503EFA3BB0
+:101F50000DE2ADC7BB1FE4F1EE5BCD6CBD5B9F3303
+:101F6000D0FB0DF9061F8D6BFF3CBFC7FB00F18B4B
+:101F700044BDE701E5963608F49EBA1AF77E7B83E6
+:101F8000E0453FC9ED18EFDECAD66B73C204F1EE2F
+:101F90001BD6AFC2FE848B775F81F1E9E7868A7733
+:101FA0009FB402EFAD5F5D12437FF7448D775F8191
+:101FB000F1EEE762BCFB149AAFC6BBDFA6C6BB1F3F
+:101FC0008B9F1F6DBCFBA934AE811AEFFE57B96C15
+:101FD0001EE20E77154C95C7E3DD07F0C309E3D683
+:101FE0001F9CA5C6A5F7D2F4929E8A430DE9E37122
+:101FF000EBF7CCD6C6AD5F50F8CC1116B79EA59FB7
+:102000007BF1A523E7D3C7E3D46F7AB9EF61E4434B
+:10201000D1C6A95FC8FD22EF789CFA4651423A200A
+:102020002E0FC539C4EDA5F19BD438F5C36A9CFACF
+:10203000C64A7AFE3A16A7DE53F21AC6CBAAEA15AA
+:10204000681FAB7AD79B713FFF2C7706A5EFEDABEE
+:10205000DD2C3EBD574CC1F3DAEA18772B9ED3AD89
+:102060007B9EC5A7EF077C87F6BCF138F50A8DB3D8
+:10207000AEC6A91FE671EAB7737A0D1BA7BE83C56A
+:10208000A97F2397C9D5914C167727BEF3FB4F61E3
+:10209000DCF068E3D47F92C5F84DF56A567E7B6725
+:1020A000B838F56E1AA77EA48BC5A9DFDED14FEF35
+:1020B000158C98BC14E78E6433FE162C773D36E4FD
+:1020C000D7BB3B13B3F1FCED06972B3B3A589CFA78
+:1020D0006A8C530FA5767B05CA9F7677085E97803A
+:1020E00071D5247A0EAEA49BA83F8E1AA7BE1F05F9
+:1020F0002BD27787D0857826629CFA0E760FE3562E
+:10210000E3D4579DD1FA05848D53DF507F0EE3AFA2
+:10211000164CCF6171797B789CFA1616A7BE99C7C9
+:10212000A96FBE5371EA1B930D68B76ACE966C1700
+:1021300053C6E3D45F0A13A7FE5A2EC3A79722C63D
+:10214000A9DFCCE2D43F32719CFA41E42B0BC6E309
+:10215000D4E379D3527ADE349BF2E170F1EAF5B838
+:10216000710C4F46C08F6B389DEFD0C53BEEC778E2
+:10217000C7905FDEA98D773C7C344CBCE34E16EFF4
+:10218000B85FE0F74E23C43BDED119655CFACE3F61
+:102190006D5CFA4FEB7CEA4EC5A59F95CBF8CAA5BE
+:1021A0005B8C43BF5B60E9A0F8F33DFBFAF0DC27F2
+:1021B000DAF8F3CD61E2CF3F95C3EF1586893F3F53
+:1021C00027EFCFE35ED464E3CFAB7AC46DE0361182
+:1021D0007F6636D2EF14BD359DF117FDEF146D6F9C
+:1021E000507FA788E1EBBB0DB755DF21DCF62EE76A
+:1021F000AF71DFBA35DC66CCD3E2B6FFCAFD830629
+:10220000B775E76971DBE84396E702715BD2EC656D
+:10221000CF05FEFED0C1EEDD1B26F3FB429FE4326C
+:10222000DCF67F01DA7E2DB8008000001F8B0800ED
+:1022300000000000000BED7D0F7854D5B5EF3E7324
+:10224000CE4C2661984CFE4F20843349800426648E
+:102250004212088A388108C1A28EE895E845EFF05D
+:102260003F406CE3AD7F687BDFE54002061AE20485
+:10227000A3C68ABC09061B7B910ED55AEABDF5257B
+:10228000883C6A5153159FB5B45F120549CCFB1EBB
+:102290005A7DCDFD4AEB5B6BEF7D92396766321359
+:1022A000C0DBDAEF854F4FF6D9FBECBDD7DA6BAF69
+:1022B000F55B6BAF7332C14C882F99900984B827B6
+:1022C000CE81AB44483A5ECD44499C43EF7759F800
+:1022D000D588573BE94A87F6C42929BDF9842410DB
+:1022E000C5FFA501CAF9DEBD8652421A768AB63DFF
+:1022F0000294DD3EABA710AE5EBFD533919047BAD6
+:1023000037ED2D4B25E4BC5B72C5CB8424EE5C7BA2
+:102310003381F6A445B04D7310B2AED76DCA84FABE
+:102320002D7E2140A0BE4F524E4E82FAA1D60A59B0
+:102330008166C773A7119246C8FA5E2F7D6E8B5FC8
+:102340004C15E0B92D66EFDE6BE0B95B9E1052B123
+:10235000DD90AFC2EA76C22F44B1CE87FB432D3069
+:102360001F289D27425500EEAFC72AB84F7CE2C117
+:1023700043384F4264692ED085BFE7C0B55570170A
+:102380005809F91FB9021D6F30CB9BEDB1C0FDB6E6
+:102390009F3D24C0FD8FF8F38A87F8F9F384C0F3DA
+:1023A000A9F87B2E5C7DA2BB6036B04766CF6FE993
+:1023B00065EDD7B7097EBC35C1C3F8863F5FD2FF54
+:1023C0007B9758A17EB05D203F00BAD7B7160B5E51
+:1023D00098E7A0D19F6D8371071DA43A40E981E77A
+:1023E000CCFC3911FFEFB3C6C1739BDB921C7B8021
+:1023F0000F25322C4219211B5A8BDF28453EDE4F18
+:102400005CD01DD9EC8741815F9B5B05BF1B7EFDC6
+:1024100058B0DD5C0E6525D3E83A04F513DC921262
+:102420000774F599891BE7F971ABD0AE407F434241
+:102430001DE59F52289143949DE444DE5CC63ACA50
+:102440008256A18B009DA9BDAB97132BA5EBA39141
+:10245000F9C17F530894553A1DF462413EA5538E4D
+:102460001352B33CA81EFE4B3FBB6C00FB4B2741F5
+:10247000FDC073A71BEA5F9D04BFFF939C43F9B99E
+:10248000B95348AA8449CC6F12E7201B9A93BC1316
+:102490002B819EE6DDB9C9F5D0AF35A5EE415C2FA5
+:1024A00053E6BB7538D9D74B9D0611E83619EBD6E4
+:1024B00060D9F474BE4181F20F4CDED65B91DE1F11
+:1024C000185C0799183C80F2B964678A610FF4D3ED
+:1024D000ECB059CF40BF1F671A93B1FEDC32619751
+:1024E000AD88906A6FCB0DE9D0CE2D25158BD06EBF
+:1024F0007A1EE3FB39A3BC88CAC56EE23AE4A0A207
+:10250000A4D4C03EC9A972EC40BAACD7542F7343CF
+:102510007DCE1D0682F3B9056834C37ECA9BB8C25E
+:10252000803C996EAC9B84F29399E7A074E69C5D25
+:102530007A0AE56DAFE4A95E0DF3D8BB60964B81D6
+:10254000F156E4D46D40FA26DF7B226929F6B73BC9
+:10255000AF988AC3A87C18BE9C07EDFF5C778FC735
+:1025600049792D9B54BE1B287FA9FCB909E946FE79
+:10257000A6E50874FE1B970B3305A0EF9D1D229561
+:1025800097BE0AC17F10EA3DFB05459C8D0FBBCB72
+:102590005623BF9ECE48C6FD74D302A3468E3DFB94
+:1025A0001FEE11518E04B905D743F9A5E83A04F39B
+:1025B0005D6E372AC172013546E4DFC6FD4973906E
+:1025C000CF243FA89F9C5039AFDDDF27E0BC6BDDF7
+:1025D000FA7EF4FB214A5921EFE601131673F93B09
+:1025E000B50D2AE3A08CF20BF4559196CA64DC2752
+:1025F000D5C4E587FA654491B0BC6515717541791C
+:102600004B2768C0E0F12D462AA7B86DF8BC47E516
+:1026100019C64B5FA5DD0FD928DFC09F6CDDBEF862
+:1026200038953422DF45F3339E8F526051F6BF6AEE
+:102630002981713FDB2FB9E260DC7A01D61FE56AA0
+:10264000671CE5E797F873FDE8F5F16D8A4702D559
+:10265000D8B6AD915E2F3A98DEE9BB8E74E13A6E42
+:1026600004BDB3036E55ECBFD55301E5DA06C105D1
+:102670006493DAB616933C11E5D6B704F5ACD22EC6
+:1026800004709FD776ED3E69443EAC2232EAE9CD34
+:10269000D57E9309CAE95E42E56CF33A9FB006E441
+:1026A0002AA31AC60DA22FD30BE307C9437312C87E
+:1026B0009F2574BED739D87E697684AF4F9DC9EA0D
+:1026C000731B0DC41DD4FF345F027107F53FA32DAA
+:1026D00059532EF04FD2B49FD599A3A92F0CCCD427
+:1026E000D4171D9BA32917775DA3695F726A91A612
+:1026F0005CD673A3A6FDBCF75768CAF37BEFD2B4D0
+:10270000BFF6C21A4DFD7517376BEAAF1FFE674D56
+:10271000B9827C4FD33E79596522DA8133262880ED
+:10272000025CF6A4D4A400BF928D729200F2F0591C
+:10273000A348504FF737DE96E885FBE412F00FF61A
+:10274000F966EC400C272760C0E346CB199D82DB7D
+:10275000EF0C6D27717DF0C5A93F0884CAF5F5D44B
+:10276000BEADE3FB26DDE76841FD5B7B4AA4F66571
+:10277000AF5427A09CED6D1288CF817261205DC19E
+:10278000F6EDD297F4F92D9CB60CE279A41CED81FC
+:10279000422C15E9B81FD84FFFE16F27B9818E6C25
+:1027A0006E4FC856A91FF78919FEE1FE5A1B30F675
+:1027B00007EB9B0C22F507EFA3A9DC7E4CC5FB4180
+:1027C000F643E50BD57FB97865F3FB0BD20BA4DE9E
+:1027D00044989E10A1576CAFD757D75DD4DAEBEB76
+:1027E00087F5F67B9C7A485F56DC67C2E925427A1A
+:1027F00005C44F7ABD5425B748C8EF8C3681A4086C
+:10280000A3FA2B3B5BA6FB5ED5331B505F05CDB314
+:102810009FC8CD05A847DA0C04F508E8F36CC46539
+:10282000EABABF25B375EF20EE8402D4071D22C596
+:10283000077AF9F82DD72F39879EB1CA884F1AC564
+:102840002A94A347BA0B6EBE069E3BE75B24C5C322
+:1028500073E70047A23DDCD851D1B11D1E79D2618A
+:10286000A4FD9F31F97F9589FDFF4894B1FF41C2D6
+:102870007087D2211C44BB79AEF3196B0EF477FE3E
+:10288000D0F67B26C13CEFE2E3F577B271882437BE
+:1028900023DE3B7FA82405ED873AAF7F7488B4DD43
+:1028A00000F1379733BC41711D95AF1C32825FA692
+:1028B00010F567641D842F81DF599DA212877CEC7F
+:1028C00014DDF1709DD21647F14D76F07A3968BB70
+:1028D0003EC44B53B89C4E26FEEE52BC7FBF56DF23
+:1028E0004F6E8276F0FCA45AED7DC271908DAFF7E9
+:1028F000002C69C082FA42DBCEC6E5D9A6C343CD1F
+:102900009C1F831708B5D3B5AD0C57EAE91D6CBA07
+:10291000EDA415EA273F2F109B1C86DE0E4E6F0795
+:10292000A3F782D163427D1C426F07A797E33D3D29
+:102930009D7AFAB6048C5A3A74F3EF6F7CC6EAA516
+:102940007856A6FE414763295D4FA54924D3609E72
+:10295000D77432FC718DCFD08E745D4B02F58883B5
+:10296000FBF1916BF07FED3ED413CD0E567E474EBA
+:10297000784CC942F97BEE66ECE79CCF4050FEFAFA
+:102980003B6FA37E427F8760433FE1E58E16EA17E7
+:10299000E8E559E5FFB98E47A9DCA9F73B1D6C3F77
+:1029A0000C7680DCA19C77DC66CD0DB257CFA1BC44
+:1029B00021EE23BEE66BC2F05FCF6FD200F2973EEE
+:1029C0002A7F7AFEEBF9AECA97CAFF2B95B373E361
+:1029D00094331F97333D5D03177C6FA2FF505B2B31
+:1029E000112A567AB96AE574B546A00BF482399972
+:1029F000B6A374E9E9017FC88472A1A767C35060D8
+:102A0000177146972FB441B82EDD2D3FCBEE85F6DA
+:102A1000334C8103E988833E8827078124E1407590
+:102A2000762FAEF7A7DEA9B6A0F54CC971707A7DF6
+:102A300056831DAF3D564339109F09139E87FE43B1
+:102A40000FF527064B2D04FD87C14B0F517FA26662
+:102A5000BF99EC80476B8697DE43FD595F1C41BFF1
+:102A6000B0C3B7A607CB039DA280787FA943A6FD7C
+:102A7000ABE30D76AEB5E13EC810DD9F3ACA62C742
+:102A80006B224CA73C393A6E13CDCF523C1909BF8B
+:102A9000FD4A66F38986E3C830CC379DFBCD886B51
+:102AA000C13FC6FD407F80FE389BAD1DFDFDE1BEF0
+:102AB0008FFDF5509692D3A95F2422CE437E960ACD
+:102AC000121ADF04FE884AFF90E015916EC9E623D2
+:102AD00014BF8019407B24F2F53BE7B0D1ABDFCEC9
+:102AE000F83F827B1A18EEE96BD0E29E1AEC22378F
+:102AF00006DCE367F3D7B75BC8FD7D3DEED9C0E7E1
+:102B00009DDEC6FCE85A37D3B71944A6386833E0CF
+:102B100020F40F62C03DB784C33D7D87DFA9A2F6D4
+:102B2000BCCC400C8EC8F867B30EFFA8FE5A241C1C
+:102B3000A4FA6D23FEDC7708F5E7A2E123BD9F1719
+:102B4000829722FA7D5DD46F519E96AE8ADFD79729
+:102B500076F26426F9FAF97DAA3F17C9FFEBDE9FEA
+:102B60009B887A49EF07AA72A8FA817ABFAE1E6DD8
+:102B70000CD8BB8BED77FB1467743CD73A95C973BF
+:102B8000343C97967B7978EE9D1C237D6EBC78AEA5
+:102B900095FB17D1F0DC6339CCBEFEBDE3B9539C85
+:102BA0001F7AFA069BEAEF413E4E7E4C9089230C39
+:102BB0007DD1F0838AD73AC2DB59153F6E380CFAC3
+:102BC000CC1106C70D75517B5BDB66D4C4E9AE3E04
+:102BD0009E5BD882B80C6398E8E7B6FDF7F47DCA2F
+:102BE00082AB8FE7FA73386E8E80E73ECC61FEC30E
+:102BF000DF2B9E7B3D676C3CB705F19C1C46CEAE3F
+:102C000018CF7585C573B543DE5D4011C8DFD87830
+:102C1000EE75E43DC5733FA4B86D86C97F80DA9137
+:102C20002878EE48AE83EFABB1F1DC10C773431CDC
+:102C3000CF6D403C07E50D88E7E839810ECF0518D8
+:102C40009EDB9E236BF0DC506004CFCDCAA5F16003
+:102C50000FC56FCA4E81DA4315B7A9F6760B5F47E9
+:102C6000FA03E58D94E3A3E5CD022BAB382EE3F018
+:102C7000EA6ED4B31960A7F0B825B3737B379E977B
+:102C8000647A658AB77C53654A6FAC786E13FE8EA2
+:102C900078AE23363C97931315CFE5E484C173399E
+:102CA0007CFDBE6AFC16F89AE1B70D88DF12C7C03A
+:102CB0006F6D80DFAC978FDFCE3F19237E6B03FCF7
+:102CC000363B76FCB6A12D36FCB6A1ADDB84EBFB22
+:102CD000D7C26F1B397EDB7895E2F664AB9C88F235
+:102CE0007CB9B86D666ED72318BF9D9A6BA372AA84
+:102CF000FA3597BB1FEFCA6571F231F6E35DB9692A
+:102D0000A1FBF12E9411B83F5D66F320123B1F9A90
+:102D1000804DA0CB86EB3EEF590CE37CD420BAF07B
+:102D2000D647BEC5CD88036D8F09361C770A1A8930
+:102D3000323C47ECBA87D0F57253BBFF7FB299BFE4
+:102D400036DEFECE6787EFCFBA989DE3AD5E2EE408
+:102D5000C8B04F6E9348A504FA733961D741D47750
+:102D6000CC9EB9717F9CCCB7B7238658DDD02EAFEF
+:102D7000B1447FFE053E6EA4E7553EAEC8E9A9A268
+:102D8000B877AE81DA1BFD391B8972BEF654EDF1BE
+:102D9000F81941E7747BFF4C28CEB929F7D02318E6
+:102DA000B75A4DE4643CF2DB93C4EE13E5DA16F750
+:102DB00082503C34C1AC3DA797B8FF8E7CC6F378F7
+:102DC000F5BC5EE2E303090AEE7702B66FC75CBCAE
+:102DD000CFE6A7D69B0869C17A0B5FCFF7A01DC6C7
+:102DE0000FFA3A44FF76FA9CDB8EF2126B7FF0AB5F
+:102DF0000FEB27F279617F52EA687F0D997EAB5124
+:102E00000CD31F34DF911EB63F3FD6BF07F552F0FB
+:102E1000BC649857218EC3E5B7DA4FE5E5AB5EAFEA
+:102E2000B4836E1FAE83BA5ECD496C5F13E580CF6D
+:102E30009D151A8FCCCCE0FB81B8CA681EC4AA7C51
+:102E4000030EFA00D72DCF5E24241171B2DD48F3B2
+:102E5000089E6D7B9BDA9125658BE8F9B04A4F7A25
+:102E60009B48BA4A46CB4BEE3478503F2C7178E3FE
+:102E70000DF0BC5976E109D1E879EF38E9FDB73CAE
+:102E800021ECF9EF85CB3CFFBD30CEF3DF68E72BBB
+:102E900057EFFC37FC398BDE8EAC433B4246EDC826
+:102EA0001A6E47D6F8B4E729E3B52368C87011EC69
+:102EB000ECD6885D595AFA7645A521D4AED82B1B9D
+:102EC0003F457E4EA932507FC07EBF365FC29CA573
+:102ED000C5CD450848D2C2EC2F10C35DE1F73FAD28
+:102EE000CFC893D93EB279270AA541F93B1E9F3539
+:102EF00078FF4337DBD5FE0CE1F73FDDAF4ADEF864
+:102F0000E661C07A4798F179FED0C83EAFF26BE631
+:102F100093AE3EA75B67959EBEEA47AD26BA2E5A92
+:102F20003D96ACCE47F75C2B3E07FBA041B03597F2
+:102F30003942E98F958E164E7FB4735A7A9E1A0BDA
+:102F4000DEF585C7BB7D79E1F1EE262E5FE91DBF79
+:102F5000667AB0D440D0BFCF205DBBD03FFAAACEB6
+:102F6000676BF71BFB83E531D6F3D90A55FEA29CAC
+:102F7000D3465BBF769DDC5923C8876A9F503E24A9
+:102F8000C42782BF59444CC471987A7E9EDE191BB7
+:102F90000E3B9617D52F3A9617C62F3A86F3A5F60D
+:102FA000A1F7ED5920F7D9FB05827AF5C8FE761313
+:102FB0000A5BD173B7D26BA075B509E330AE271D9C
+:102FC000B45CBCBB825E498F6B02FA83FD7EF61C4B
+:102FD000F04FC475ACE5E397B41FA5CFD90E1F35EC
+:102FE0004D86766BF70B32E693CC7B55EC42B91CE1
+:102FF0007A5EF4E3B9C59030E724FA91CA6302CD52
+:10300000F3B2B50A6EDC879B0F8B07E368FD8A5D20
+:10301000F49CE14991C6193F015E2640F9C01EF1BA
+:10302000A0C2E272444A1FF5DFE6BDBAB6793ED4CB
+:103030000FBE6608EC80F6358D217103035D3F3FBE
+:10304000B31F66D2B81DF3078B8E69F57E7197B6F4
+:103050005C724A5B1E140C342FAEAC477B7FDEFBE8
+:10306000DAF2EF26F3F5216CBC04B320E07815C149
+:1030700072E1C07624263FF54AF32B0E4C0BBF6F4E
+:10308000A9FF0FFC4ADFCFF22BD6F3FC8A0C1018F5
+:10309000B4A7EBEE27FE2E21F2FE5D6B66CF47F460
+:1030A000539BDEA1FA209A9FBAAEF5F2F671D43C9A
+:1030B0000B1D5ED0E38265F9DAF252F90AEDBDBE6E
+:1030C0001CD5FEB3F840CD56E2C794C965C447F19C
+:1030D000C0A66A66FF37F9C7E74766C8F755A25A20
+:1030E000891507E8EDFF88DDE738209AFDBF2F83BB
+:1030F000D9C95E23A179A3A178D3DB9084FB3C409E
+:10310000E83900B9D8C3F1A681ECA1F8F3B894026C
+:10311000F54B7EE97621BB54DC59B6E0D7C7936402
+:10312000C49D3BA4648C87FD9CB8C0AD258FCB8C1F
+:103130003FE6FFF0BA88767DC2E24E577EF1E21498
+:1031400019FDAF8B27A87E255A1C9A6F6E398EB158
+:10315000CD99B6A38B105A173B2BEAC19D2673DD80
+:10316000F7A1FB484EB6DD7F02DC38C0BDBDF58956
+:1031700038AE5CECC2755CF6B95F4A84ABBBB5EEA9
+:10318000834DD0F026579C0BD5CBCED4CF9C188F37
+:1031900053F17BCEA163CD88CB553D4FF524CE2393
+:1031A000109B9E2F9A1655CF174D0BA3E78B905966
+:1031B000A8E7F9FE5883552018531BC3EB87C72691
+:1031C00071BFDEAB5D3FCAA9749E1A04F321197565
+:1031D000F6E078E701D43F33429F8B234D547EE2E3
+:1031E00088741EF98DBCC1FD982DF50AF8FCD4AD8C
+:1031F0003A7D22AEA2FA4E3F2FF5BAF5ECA785270D
+:1032000082E4EEF5691353CFA313EA244EBACFF844
+:10321000F32A9F57737AF5FDFC71DBC5C213C09B7F
+:1032200047B33C89B631C653E952CBD90D7CBD3882
+:103230003F0775FDABFC9BDA29D0757FE1D08D7B14
+:1032400015006B09C527E8F9D65016A962F9D46EA6
+:10325000AA1F3BD4982BD7A317E259F117D34D746B
+:10326000BDA7923A2A278FFA455717C8C3D433A26D
+:10327000CB00FCCF53F5A78FE94737D703691E4929
+:10328000A33FE3B8BE4C25DDB6C520B7EB3B441ADF
+:10329000A7D2EB4F759D062EC511CCA31FAC34D120
+:1032A0003C80385DBB34D265C3FAB52E89A03D1889
+:1032B000EC5DB9849EBF7908F5B7F4EB43ECAE93AF
+:1032C000769877CB3FD85C346E375DBB5E2D9984A2
+:1032D000D2A59C61E78309C5A977AE43BFDD9D40B8
+:1032E000F791CAE738CEE716A1271FAF23EBB77CCB
+:1032F000C598F2A2AE9F1FF42D5E0F6EB3513BD95D
+:10330000B1CD4ECBCF6E93E9B5735B3EBDFE689BEE
+:103310008BD61FDE564ECB8F66058E23DEF8E27607
+:1033200052ACC0FCFBB2FC3B1218BDC58718999685
+:103330008AB918BFE4FB82AFE3503C2B9F98944EB0
+:10334000D7314E678FFE91AF6B2A298EBF16E39A55
+:10335000B54619D76535B707A481D9C148EB6AF9D5
+:10336000335BA78F709D1CD89F6E3DF9BAA711EFF4
+:103370002E5C1F2FAC4F17D47DD4FB3F6DE8B72BCD
+:10338000B07E871CA1EB7B6212F777ECC4A459379F
+:10339000BE0E5EBA47417E94F07EC137BE66FA63C8
+:1033A00005CAE3ACC8FA43D5D3574D7F0498DE8DE8
+:1033B000A43FBEA1D31FD73E3B8DEB8F52AA3F3E09
+:1033C0008CA23F06B8DC9DD4EB0FD8F75DA557AEB5
+:1033D0003FD63688343E11497FF4A1FE488DAE3F7A
+:1033E000D6A1FE70A0FE9877D23EA6FE60EFE5A8BB
+:1033F00072D818A3FE1842FD1124B77F2BFA630878
+:10340000F5476A74FDD1CFEDC077A3EB8FDD787EF1
+:10341000BAFE32F5C785A8FAC343F5FB06AE3F2EC8
+:1034200044D11FDF1DD11FA07782D6CD3A81C5C3FD
+:10343000DFB3F9ADC928BFF727D37DBE86CBEB0339
+:1034400059CC2F490487A187E66504ACE83FAECE8E
+:1034500062FD7DD2986245BF33523F1B38BF42FBAD
+:103460005134FD5C684BA1E5687E56A47D1FE26780
+:1034700005C2E3A8A61942D83CF6D1F88883C6292C
+:10348000F57E56CD15FA597B25DB9BE540D7DE55F9
+:10349000928CF216C9CFAAF9AAFC2C32763EFBDF39
+:1034A0008A9FE5453FCB31EA67ADAE66F2BD5AF97A
+:1034B000DBF6B31AEC23E76634DF6A247EC3E3301D
+:1034C00047FCF7D1B84BD1D32C6E136863711B172F
+:1034D000C66DA05CDC722BBDBED05A4CAF6ADC4618
+:1034E000CD0728D9DBCDE23681EE939352E9FB7B01
+:1034F0009AB8CD873C6EF3A170D084F5CA933C6E28
+:10350000D3C6E2361B316E2360FD1A16D7D92DD2F1
+:10351000FA4FCC7233EAA903270D01E00CF64726D7
+:10352000623C7FB748EDC4C7828124B0F6EA7B9144
+:1035300034AE93C2E54C1FBF49E1711DB25CBAA223
+:10354000384EB4F8CDE2291CCF4489DF2CC6449C08
+:10355000B4A0F5F0F1F5F075B378DA5181C5D31464
+:10356000753D587C8CF4D8DE413EF6F3F8DBBC5751
+:103570004B683EDB27C0048C5F951C1228DF37ECBC
+:1035800017FD9887F509C69D2CA3EBB69ECB97CA6D
+:10359000FF9AFD8CFF9F086B9650FEEF1564B4AB4D
+:1035A0001F9B158AC30FEC135032890DE687FCDE92
+:1035B000DCC8E26CF35E5DBC0BE771E1A848769075
+:1035C00051FE67E02F229EAB1CB7224E555E33049E
+:1035D000B03FFD7A64E07AA09E59C5EE7F55EBF1CD
+:1035E00052566CF1B497D0D7C675E3384E8D77A795
+:1035F000FB38FEC29F31FCEDB3D3A3FADB67A7878C
+:10360000F1B7CF4EE7E35EA5F84761569F01D37649
+:1036100096DCB9AF92C63F7E415C98D7F6B8EC6FA6
+:10362000A0F18F2E2F8D43448B7F9494764BE1CE67
+:10363000DF22C53DCA16AC1653A1DF7995AB9B9628
+:103640004179E925A501E31C4B1C3D8B69FC23AFA7
+:1036500098C65D165C2495F130AF1B4B051BCEFB65
+:10366000874F9FCC0A8E7BBC35FDBE663CB7ACB1A4
+:10367000BB4F60BE598D45A2795AC46FBC38B25E4B
+:10368000417AD500FA19F56A65C8FBBB5ABD1B52D1
+:10369000764BB26D2E4F6182791A111FC17AD7D73E
+:1036A00010AF99E6A5ACB221CE17903F707D7B514B
+:1036B000DD371147C0025A717F9D792FD780EBA06B
+:1036C000AE6F5A81A0C9AF3ACE71609F8DE1FD45C2
+:1036D000922C85C3FD8BCDA2C66EF799C7F60F4617
+:1036E000FAE5ED1675E656A27ED829B9E87B568A2A
+:1036F00045203F1522F7BF2E61D1C08CB2D1F7F41F
+:103700007E31E3FA66CCCF6D1108D513E89F509C4B
+:10371000C4F7C1166410F0EBB5990C9F44F4530E36
+:1037200087F7EF1EE3CFB564BA7E991706770F448B
+:10373000C0DD7B0D7EEB62E1EAE3E9999D6C1FA79A
+:1037400056A6FBF1DC7A60C43FD2E26A3D7EEECD44
+:1037500034A971318AABD6735CA5E26A1547AB38E0
+:10376000F8EEDB7B8D46A87FB4F585343C87D2E349
+:103770006BC0E1F4FD890D2F0A34BE72F7566DBEA1
+:10378000951E5F0F5ED2FAEF7A1CDD9F9A7C73055F
+:1037900019F597BC3CDEF2516F9CDB8C7C27663FB1
+:1037A000E26FBDDCD7D7B8B767C2FD8117CB6EBE5D
+:1037B000166E6DB6D5D13C4B23F108766C64B765B7
+:1037C000DE4A7143A5ED7CFEE87E88249F0834CE56
+:1037D00007EDB3FF9D4E58DE87599B0FF246B64C5E
+:1037E000F979A5F92067783F91F24160D4749E4F32
+:1037F00029603EA5EA079772FAE36A046209C24BA0
+:10380000A5AA3FD42369D6EB0B72C9C0F4A140E549
+:103810006773168BBB67546BFDA4A2532CAF54F592
+:103820006F8B22F849FAF5A376939E7F5AFCE8E75E
+:10383000EAFDDA26D94FED6D13E04E94E38DFBEFF0
+:1038400013D08EACCBD7FAB7378816EAB77FF6AE6F
+:1038500048DFC3B1E57699D1FFB27D5FB461DE6820
+:10386000FFA527ACA8C7067AE3683EAEEAD71E815B
+:103870007D86F95F01D8679291909FC03EC3F28B1D
+:10388000B0CFB0FC12EC33BC1E837D86D797619F0E
+:1038900061FD7FC03EC3F22BDBDCB4DCB5AD8A96A4
+:1038A0009D93983DDCBB28E128CDAFDF1767C3A30C
+:1038B000A4EE96A5D9DF81F90D5558E8FC867EAEB9
+:1038C000CD83D55F5D9372B8FD568C6C1DBB8CB8F3
+:1038D0008E91F4550DD757DE8228FA2A425EA6ABA8
+:1038E000606C7DD51F21CEF85FA5AFFAB3581E7569
+:1038F000347DE59A6452CFA935E7E551F5D561D01D
+:1039000057CEC8FAAAB646A0F19C58F555A4B84EB1
+:10391000247D3588FAAA744C7D254C467D5553D6B6
+:103920000CB7A15F0FE5BF571114B4CB6995A6760C
+:103930007C274BB2F94D0C675D9EDEBADDCEF49666
+:103940006D4220DB05FCE87EFE67BFFFEE38E456E3
+:103950002FAFB00F68BED527332E3661CEC9D58ABA
+:103960004B7C55FACDFB15E9B77511F51B8B1FABD9
+:10397000FA6D9D8FE9375210A37E7B02F41BF47B16
+:10398000EED23CAB2728BEF255E9B70F7BE358FED9
+:1039900023D9783BEE17757D7B9FFCE2369A532442
+:1039A000D9DEC44538F39E48827162443C67013CCD
+:1039B00007FD2C061C17134E9462C489D265E3C41C
+:1039C000D9056170A2AAF7689E3AC6F5DBC2EBD1B1
+:1039D000BDF9DC1FFA9AC4F56F2A18FB5C507D9F75
+:1039E00054DFCF65C7F55BB571FD01EC3F37947FC0
+:1039F000533B585C7FEE734B5AC713D757CF937E18
+:103A000093AF8BEB07AE4E5C7F73E3D871FD7E1EE8
+:103A1000D71F8812D7DFC8E3FA03BD3F64793B1193
+:103A2000E3FA752783E3C3F505DA73984871FD73EC
+:103A300051FC0B75FD5A04CF5B98271B6DFDAE96AC
+:103A40005D3F1725AE9F76BB5B30A6A29D2D2E4114
+:103A50007174615CBF2CD4CEEBE3BC7AFBFE7CBE00
+:103A6000CC9EE3EBF76813F347A2E5FB6DD4C9A343
+:103A70007A0D8967EF0FBFFF8D33A3C5B359BE5FC2
+:103A8000CD48BE9F7B17EABF4871ECDAD13876F893
+:103A90007CBFC0B793500F47CC13F25FDEF758845A
+:103AA0002C39A67CBF91385EA740503E8F74B27807
+:103AB0006A11E6C1615CB591C5535D2DDB595CB5FA
+:103AC000FD3E1AD77B613F8BF7A9F1B9B59C9E9259
+:103AD000A347E97DDBE1A3F4BC6B53AB20A3EC8EE1
+:103AE000E4C3ED6571D021611F3B4FD7C555373712
+:103AF000B1B8DE90B086ED2B1E57FD10E3AAA9A148
+:103B000071D5C1DD2C4E3B8871D5D2D0B8AA1AD759
+:103B1000FB6BC5F17E3F25B638DEEF31AE1A14C718
+:103B2000DBA2AED7E1D8E2782F15448DE3BD541067
+:103B3000268EF752018910C7FBDBC89BCF9C25FC62
+:103B4000FFBCF931F2E6D7AE62E7396B7D57F6FE7E
+:103B500055A4739C9D974437E6492AF7B3EF308EFE
+:103B6000377F7E67D76FAA72315E94E5A0DFA3D45A
+:103B70009FF34876417D3F88EA4BF57D26723BC82E
+:103B8000E3DC51799C90BA6840B262BD44FAB5F169
+:103B900052D21FC4C7C154D228829C48C34C2EF5B0
+:103BA000FD7477DE56E540FB017802CF7B36D8BA4C
+:103BB000DE14711F1D166409FAAB382C507F71ADED
+:103BC0004FF0E37981346CA2FDACF5B578F1FE9A43
+:103BD0003C338987FB7BC09EF4039E6EE0EFA1ED32
+:103BE000E1EFA1252FCBDB85FEC0E71D42009775D5
+:103BF00053AACF847ACD682332E216A34DFBDEE8C8
+:103C0000A67CDF49C413094E564F970AE34AF9DAF6
+:103C1000F749731A4DC49D12FA9DB2F1BE37F45E96
+:103C200050DC29DC7B43AABD588DCF63FE5C43F892
+:103C300073DF3FCEF87AE5BFFC64E6D83859CD177C
+:103C4000BC6A38B971ECFC39957F6AFECB533FFAF8
+:103C5000D3A30C27A75A6527E65FA9F192B1F3E732
+:103C600042F25FFE4EF2E72ECC8C2DFF255A5CEB24
+:103C7000AF8593FBA3E4CFE971726F66F8FC173D43
+:103C80008ED4E3E40CC4C969413839C070F2D57AE6
+:103C9000FFEF3DF57D53FEFEDF57FDBECDFDB38446
+:103CA00071BE6FE31DF37D9B2BC5DF1B2EF37D9B48
+:103CB000FC99B2261F3912FE1EF77B64B3E4ABFAFF
+:103CC0001ED932F445AFE27B6423F212EB7B649C95
+:103CD0009EF1BE4776F72CF9AABC477617D21F840F
+:103CE000BBC7FB5ED2F4598668EF874F9F15E6FD90
+:103CF000F0E93ABE47A273339F5FB4F7AD54BBAE51
+:103D00007FDF4AB4907CDCD77692E0C2F8F256B3FB
+:103D100075364904BD18CFAE0F19BC5E94CB87C46D
+:103D200080D981FABDD4DB86F3FDA32160AB80721C
+:103D30007DFAEB1E1C6ED5D6EFB92A0107D952C801
+:103D40003F85FB9EEC2A03F1A2BD7A86EFDFB3C666
+:103D5000AE2949B0AFAE2D5DF4CCACB230EDB7FEBC
+:103D60002BED6FA148EA0261F0C5CB1CF73F65203F
+:103D700035D8EFCA7B7F32F02CE224D93907D994A9
+:103D800090DFB3BC04D6A1F1AD5CFA7DEA9FF0717F
+:103D900081D052E4EF2F5CDEA3C1E39A659BC4F8A7
+:103DA0001F988FF50BFFE43CFA16F4D7F80D0B7D46
+:103DB0003FDE9DEBBAA5244CBC13FA7919F9611EBC
+:103DC000DEF329FA196A3FAFC4F73E45686640C57D
+:103DD0001DEF03967A25A977B200E5E3B31C77A41B
+:103DE000664239AD7732D69F503E7DECC47C2803C5
+:103DF00056C4386BDCE14F1FC378E4C21B879E7941
+:103E000004F31CA69BE87B1EBBF9B9903A6EBE5327
+:103E1000A4F4E43BB57C385D3B361FDE0EE5C3DB26
+:103E2000E1F8F046A9FB1DBC0F93A474376E23AED6
+:103E3000753047774620BE04FD2E39F0DC23D0CD07
+:103E4000A43C858252E8E7B7D8DE3CCCF0BEDA4F1E
+:103E50005EA9FB2CF2E774EDDBCBF1BB16F1A745B5
+:103E60001AB732E7116582953ED71FFC5C854CEE90
+:103E7000177246D7A1BD98C97732CA01F4576FF2BD
+:103E8000D96FC5F841DEE3DFB641FB5D0EA5DA135D
+:103E9000463E7EEB64FB2E09A68CCF35D80E9A8366
+:103EA000BF272038191F8ECC715FC4F99904E2C175
+:103EB000767BCA19BFACA753E6507C9A474A578015
+:103EC000DE4A2D64ED61BEC3B4FD7C1F5522F1793D
+:103ED0008CCE3DCE7D04E397F1F65676CDEB25985A
+:103EE000FF114F02665C67E3F3E4F18672A4C395A9
+:103EF0008F65B9D0F7B804EBDE8E492D80EF2641EF
+:103F000019F3430E802247BF4D9964A2E7447ABA61
+:103F1000089FC7F75DEEF6627CBF35AEF79947A004
+:103F2000FDEE02133D5F5868F055AF41B9B9D1427B
+:103F30007114DCAF0EC6E7655C5ECA9CECBB61BB6E
+:103F4000FFD34CEBF57C8D559EB29C21F294E50C91
+:103F50002F4F539CE1E42931A23C4D738697A7F67D
+:103F6000E2B251B950AF92DD44FD7C6978570FBB86
+:103F70009AFBF0B978B38BE9F52A864BC5E104DAF0
+:103F80004E1C6EA2FEBE64ABA3EB047AF8D42C4A9E
+:103F90008741425CA0EA69D1E2A6F5A7547D1C6185
+:103FA0001C028B8AF64DCADB15769C78731D41B9CD
+:103FB0008771129D638C93E864E32CBCD1E245FBCE
+:103FC000B210F566D0FAFDCE29517A7FCCE53B924E
+:103FD000FC2715B2784F24F91F1E957F0FF2399AEE
+:103FE000FC171432B98175A9A6ED23CA7F07BD2637
+:103FF000E433F94FE0F23FEC244A5539CE97C9FB40
+:1040000046E76E2AEFEA7E985BF894663F14411902
+:10401000DF138B445F32A7CF8AF43951BE4405E3E6
+:10402000497F20850731FE642DB749F87DCD6F3A71
+:10403000D57DEBBED7C9F212A97D6D2717BBE37002
+:104040009F2D10A8BF305109B8CD482FF111CC0BCE
+:1040500079903F77C0C0ECBB329DB0735BC947908D
+:104060001FFA7D1A9FD755EA0D9AA789EF5377A1BA
+:10407000E7BF21BF0E186C096847D5F5D0D3F3010F
+:104080001F6F7D09DBD7D1F4FF41D4FF657865CF81
+:1040900025FFC95C176E1F2FFCE6CB03CF8ED18F97
+:1040A0009FEB8327783FAA9E4E50F574FE889E7E34
+:1040B00082EEC7DA3DAA9E7E11F534ECEB36E46B56
+:1040C000C8BE4E817D2D84DDD77E675AF47D7D1577
+:1040D000F673E358FBAC71649F8DCDE74FB89DFD3F
+:1040E00084F3E972F9FC06E7EF89E87C3E1181CFA1
+:1040F000AF85D59F91F9FC4604FDF926DE1FC31E4E
+:10410000BF4BD74737BE19C775D0FAF783D70FEA29
+:104110003F170C6887088DBB267FCB4AFD43751D72
+:10412000553B7515D77500E71F695D171A188E5A2C
+:104130007A78E5E334FE75E5E3FD74ACF17EEA647C
+:104140007445B3DB09A376FB2FC83FBD1E6CE7DFC8
+:1041500011FCBECB6B2CA4F1CEDE65A8770E7C37AC
+:1041600059C06F1065B9BB04C4CB2A1FBFE7647880
+:104170005E7D2ECBCDDA676D4D16301F2AA8BFC4E9
+:10418000B1FAD3CF03E6975C48F596FB03A4FB0393
+:10419000A70E7F715CD09EACD4A05E960B991D9249
+:1041A000B97D50CB334ADC930B195ECAC6F1FF5080
+:1041B0002ADE6FC8617A99E16CA6878D85AC7F8312
+:1041C000C74FF0FB8109E584FA55A3FAFCEE43AA38
+:1041D0003E5F6FC1F692AACF6760FF530BD5EFFB2E
+:1041E000B0FE22CD732EB71773F93AA86598A78B46
+:1041F000CFB364AC79EAF914EB7CD7727B0DF3BDD5
+:10420000AEB02C727FEA7AE1B32413FFDE0EDB9F9F
+:10421000379FCE9D83FBB36A047F7A96623F15E594
+:10422000C28B2CFE614BC0FE9E3201BD4EFC6ED295
+:10423000BE0A13CCA3FD5F6CFCEFD1F8B763F9A9FC
+:104240007A5B31C6CD56F075D2CBE7C8F3A64041B4
+:104250008993F2E30E1CE7FA050C0F249E66DF0D2E
+:10426000AB20B0DF45DCEF8ADD05F36D1414FB1ADB
+:1042700094FB651696CF6DB99DCE5FDFFF087EC5B6
+:10428000ACFA20B92596D228EDB7D3F6B6094A9DE7
+:10429000673CEDE300375882F998528C7CBCB95CDE
+:1042A00050504F559029EDC8EB07B9BCC2FADC87D6
+:1042B00072402C40ECFC51BE86F6AFD075A8F0D40D
+:1042C00009C8D7F87C180AEEC67B148C451283EC1B
+:1042D00023F85DE1843CC2CEE52CEFD2FE46E751E7
+:1042E00052A29DC775CF049F978164A8F25D4FE5E8
+:1042F00025C6F9E8FD766511D3C7CAEFE3FDF5CC15
+:104300006F7F84D247EAE6D1EF6091BA2276EDA2C0
+:1043100071B0EBB95EBBDE6C61E76597A4A1E0BC50
+:104320007401C4783262B391FCF15EE1CB09318D46
+:104330007B20DCB8B1C60B9E2B0C89173C57384646
+:10434000BCC04A7A151193C46C2C8E8CDB69F21CAC
+:10435000B6EF10B7BDC8F77D62041CF6221F4F955B
+:10436000CF953B17911CB8C699893231995D319F21
+:1043700017F6C7CF0B693B66172B6CE4C554C328EF
+:104380003D2A7D6ABF2779BF23F335315C7FD6484C
+:10439000AA8F5A187D7382E6B3A2B4E264309D2AD4
+:1043A0007DFAF99EDAB6D55509382065EB62F261DF
+:1043B0000AE647796919E7193F87AE9B62A4F9C7F6
+:1043C0003DF7FCB380DFFBF5BE8DFDA6E4FBD6ED2B
+:1043D000033EA5BC18EF0209223DE6DC261788DA69
+:1043E000B78EB173AF58E562BCF2D03DF1C1794CE4
+:1043F0006F3139A8BFA1B83A15358B92B9F234F8AC
+:1044000007F56FB8DEB74079E0F9CC957690FBFA06
+:104410005FBBAAD340C54F3EF2C7C79B60DFD7DF63
+:104420005ADC86ED53FEFDFFA6DF80E53B056AEF13
+:104430008D473257A2BDAFEFD6E2AED17DB293C564
+:10444000C14B3DB38B501E25AF4CC7AF1022B46794
+:104450007A6A2B427BC475C306A6DF4A9369B0F221
+:104460007A7EBE423E4FA2E537394FEADDFDBFC23C
+:10447000F877F78238398EC97FC26CAAF76DA78B9F
+:10448000E0FEBE4506039E3FBF7A5D4613EA55DF58
+:10449000228340FFBED44D6C1EC6D45E71B5257418
+:1044A0001E71A5EE6F623FF5770BD5E1E26141ED3C
+:1044B000BE5184575877FC7B817845B935C2FE15CB
+:1044C0007999CB6FD26CEA3F0AA5A9F4BD109B1471
+:1044D000FCFD3E55AE5479FAE5B4FF958D7807E4BE
+:1044E0002773765AA8BC2C9BFE9BE9CC5EEAE4417C
+:1044F000CFBF107E7D66413BFA56B9182F5842F95E
+:104500000BFC9B81F37CEB12E3ABAF7C06FD0EF75B
+:10451000ABF3E30A7AA99DF214E07CC02E954E1409
+:10452000639A7FF1F8E6EF7ADF8BF3BF64D2ACFFDA
+:10453000CD11D65F9CF8B905E785F4A03D80F92F31
+:10454000C4F1C429BD59A817D479C7AAFF96CD666E
+:10455000F63A48FF2D9B9D1659FFC1BA2EC77AC067
+:10456000319F7F0BC5DCC6704C24BD74E7EC71EB4A
+:10457000A53B678F432F85E1FFEAF1F05F3D2F36C2
+:1045800072764351B6417921FE2ED3F3BCDEB8DCFE
+:1045900051F9168649D7442B9373FC1EF6AEE2629E
+:1045A000B3490CED3756FE7F2794FFDF198BFF3799
+:1045B0008843F4BB389F2D10285DEE61983AD5777B
+:1045C000E04205CD7BA1B989FA2389A0F382CFF11E
+:1045D00093DC66127CFE9F5265D394D33C764DFBF0
+:1045E0008C6A9968BF339DAFA99F5CE3D294A7D42E
+:1045F000956BDA4FDDEAD6941D4A95A67D6EA347EA
+:10460000539EE6ABD6B49FD1E6D5D417F86B34F5FC
+:10461000B33AEB34E5C2C0564DFBA2638AA6BEB8DE
+:10462000AB51535F72CAA72997F5B469DACF7BDF24
+:10463000AFA99FDFDBA9A9BFF6424053BEEEE2312E
+:104640004DFB8564245F47C0F395CF40C0F0DCCAC2
+:10465000532CD0782AC0AB1EFCFB06B711F5C7203F
+:104660004BEA3A1A34CFD373BDDBD473C2E5EC7B8B
+:10467000FD0AFC433BE9D1E5C52C047D8BDFCF77F8
+:10468000BBB4DFF55FC8CF0B17EABEBF5E41721245
+:104690006598D7C25322C1F7B5974791AB50BA0876
+:1046A000CD8FF59C11A9BD278ABB07F38946E91276
+:1046B000C645979A2740C8459A77BDB05C203F1001
+:1046C000C2D0C9E901BC2BE1FE0FA197E70BE8E9D5
+:1046D000D59FFF9F9FCDCFFB5DC4152E5F3E121F60
+:1046E0002A14338DDF55B805FA9EBB7ADE1FC20F40
+:1046F000CC7709C235F1B2761F4EC8D7EEC3892EEA
+:10470000FB987214C25F858C8BBF32FCC379DC824C
+:104710000D609EB70C13FA7E4124FEDE2269F3A6DB
+:1047200062E56B529196AF5F9005B794C8CCCF4BC2
+:104730001D23DF05FC930CC41991EC4A5E91D6CF82
+:104740008CC1AEE41505DBA1F1DB1527CE2756BBE6
+:1047500012ABFE9F5F14A2FFE7178DA1FF47FC8FEE
+:1047600005ECEF0DA876097EDC181FB2DAA7FBF185
+:104770009CF886A2B1FD901B8AF47EC86752B01FD8
+:10478000E28ECB48E071BEE3183755FD928A05C52D
+:10479000B7605ADB711E278A95CE3B42E9BC632C79
+:1047A0003A5FD9CEE202AFBC21D2BFDBFB5AAAD816
+:1047B0009506F4ED2385F47D2EF5DCA2CA4BD8FED8
+:1047C000935A3AD11983F97AB1DF2AB942D864C130
+:1047D000FBF7D16B2439BAB768DCF8E4DEA22BC34F
+:1047E000270F8C478EA2F93B0F8975EF7B8184FAE6
+:1047F0009D8C0FCAEF26D0F8E0C3BBD9DF937E783B
+:104800003BF3575A399DF5FC5AE662F251612DA7E8
+:10481000F873A73091EB398FFD5F919F7613CDC769
+:10482000067EEEC1F99EC89C4BFF9ED11F4EBF6312
+:10483000093E8738CBE97C8FD3F9BB0746E8DC47D4
+:10484000E9AC5E4BFF1EB84AE7DD0FAA7466D9A833
+:104850005E403D017AC1640BD0B8F212D142E96BDF
+:10486000C8237ECCC306495C7E433A4F2D85E78939
+:10487000B8FC14DACF2F9C12FD1B6266F5BD2C9993
+:10488000E5BF34C23FAA5F79FEA8D12E69F2D7E313
+:10489000516FCDA6799C9A7C19B57DBC2EBF46AFD1
+:1048A000CFFEAD88BF3F6122194C9FFD4B23A682EE
+:1048B00010E2B507FB377A7DA6964FF4E666F486DC
+:1048C000D927EA35B1FC426E9E06AF5DD49453AA57
+:1048D0008673F334788DE4059733AACD79C1ED332F
+:1048E000BD364D79728D5DD37E4A9DACA99FBA3598
+:1048F0005F53EF505C9A726E63B9A6FD349F5B53B1
+:104900009ED156A5695FE0F768CAB33AAB35ED0BA7
+:10491000035E4DFD11FC857E1FFFD24ACC8B3A828F
+:104920008933E07FFFE6C7FFB9929ED7F5ADB4D3D8
+:10493000F7B1D2EE3007CBA1FE7A228DC96BA47AF3
+:10494000757F46AAAFE27A6B676AFF9E59A978BE67
+:104950009947CFA3492A8FD30B4C1E2F72BD6630C7
+:10496000B3FC9A21C17B11F58F1ADF57F36DAA8032
+:104970008E6B407F2E93BFE3AA0CA2777BD69A362C
+:1049800094F78761BFA1BC3F4C08FFDE3CA3FF61E9
+:1049900089F163847EA1AE11532C46F994598DF9A7
+:1049A000762A9FFEF2E3F46A8CF7EEEA5B6A47FF31
+:1049B000F04412F001EAFF1FAA04856000800000A5
+:1049C0001F8B080000000000000BC57D0B7C54C548
+:1049D000B9F89C3DFB4AB29B6CDE01026C08685042
+:1049E000C04DB2098104D89080B13C0C2818498090
+:1049F0000D2F7904121075ABF4B210C243C36D7C55
+:104A0000B5A82D77A1D86BABB6A0D8528B98007AF9
+:104A1000415143558C2F4C857A1551A2886E15CB88
+:104A2000FFFBBE99D93D679315ACEDFFC61F4EE65F
+:104A3000CC9C797CEFEF9B6F4E2E5C809F318C5D20
+:104A400088280FADF6B9CA4D8CED5FEDA5F2E0EA0E
+:104A500085AEF2418C3DBFBA81EA871456B5D3C604
+:104A600058859979770E09BF77A5CBC0586AB87C6D
+:104A7000C6E54D701530F6D211F50B2FC31F87B167
+:104A80007268F4790E0F7AA39F17C67B9F79D3F1D2
+:104A9000BD766B76B32B85B1FA3DAACBE264EC9A76
+:104AA000CBDEBCCC0BF35EEE72D0F84D8A7F20CB10
+:104AB000867598FC159543707C0F63698C19159A5F
+:104AC0008C35A58E77CD81FE835CF0A0009FDC4EF7
+:104AD000EDB758797BE4BE65696466D62AFB64311C
+:104AE000A6644DAB62B08E8A5433B340BD4261952B
+:104AF000B8FFC8F77AE1BE619E6B9C3F7695CBF715
+:104B0000E1DF9ACC395B989BB10D19F03E2C65031F
+:104B1000368C847FFE5E551E186783117EEFCDD8DC
+:104B20003F7E9F56E52FC1C64CC70771E27D95B108
+:104B300018DC17ECD36833FBD561503A1A18C2E978
+:104B4000B4E22D4138B14C8311F715CBE48F875572
+:104B5000DAB1F4139C22C7F36107580FB399030F1E
+:104B6000C37E18AE15EA9F1FCADE76A7121D2E1B44
+:104B7000563B328DA6709DB100ED7703D203C1DFA5
+:104B80009531D54EE3338417CBB0D1F8B83DD60B71
+:104B9000FFE7CD9902EDD3057DDC9EEB9942EB77E3
+:104BA000003E47449F57EEE3F6DCCA2A17EEC7E8FB
+:104BB000CDA1FD5DE27BDDCB16410F2EA7164E2960
+:104BC000F07BBB0DC78776D8CF7D36598776282BEB
+:104BD00007B6B04E781EE3E4EDAAC2F795EE0D30AD
+:104BE00033EC37CECD1CF8C880FDA0BF23AEDD630B
+:104BF000C8656CBDABAC2A6330B40FF466185C5466
+:104C0000EF30C27C492AD41D387F59C741C0FB36DA
+:104C1000E6B8428176AB714CC7A1518CC5334E17B3
+:104C20008C8DE9F00CC1765967AD2C07EAB1A1BAB9
+:104C3000C79A01F501A1BA1FEB5B0D9CCED6BBC68E
+:104C400074AC1B82FC58B986E06D6D9D9803EBF542
+:104C50005814C79D4EA483148223AC3816E1111555
+:104C60008EA2DFC5E0BD6DC8138706003DF9338C09
+:104C7000AE4130FE466CD2BCF7B8CB4CFDEC79DED1
+:104C80007B713DF6555D4624C1BB8624D991BFC3D7
+:104C9000780844E081C3BD32274078881D1820BCC5
+:104CA000F4CFF8C25F0AF3F50718E276983389F07B
+:104CB000B22D63A58278D93644E0258719902E63FA
+:104CC0006199E9F0A0D1CC1622DDC6E5304F00F1A4
+:104CD0006561B32BA1FCB5A0CFA75CAA28B9FC489D
+:104CE000C8B88F39A13DA6C240FD134419DEFF3A72
+:104CF000EAF794CB28E88BC3E325B77717EE13F0D8
+:104D0000578172E3C83A03F1DBB67503B6290AE2AC
+:104D1000C1519E03E57FAD66AE7926C2530BF63FC7
+:104D2000E24A8EF572BCEDE9116F629F17C35B34E6
+:104D30007C1D1372375AFBF41BD54ADC9FC1EABDB8
+:104D40007F1ACCBB744F72AE0AF31EAB52DDED502E
+:104D50005FF64C7A2E4088B50BB9576FE84A63F07E
+:104D6000E04EDBF64A2C2D7BEEF6F471A29C72EA43
+:104D7000D651BFB794E4D7DAB8F812C477E43A8EC4
+:104D80009D7F2305E5F9A4BF5B48CE02529D469066
+:104D90006FB30989B4ADD706427D9690F35F08FCE6
+:104DA000BCB6BA8AC699D5593B910D63C4B89D5C0F
+:104DB0000E2B172CF07EB84E729DF94C27B16E85E4
+:104DC000FF2E00EF1C338268857D1DF32B2E801C87
+:104DD000AB354E31E37CB57EDE8FDE837F732A7385
+:104DE000C7233BCCDDA87F3EFF9D6B3E42A69DCFF7
+:104DF0008C273B73C2F3DC50551BD20767E9FF01D8
+:104E00004E1F468FC900747064AAC250EE4EABBCF0
+:104E1000D1559E131EEF8D6FD5D9088763F82EAE3E
+:104E2000ABE6F2ED7EA53B3CC6E4CAFD57929E0E72
+:104E3000C18778E1E27008C1EBFF081EE3D5890461
+:104E400087B95314D28F9170008A9F384EB39FBF99
+:104E5000C87D32D7B13858DF896613C18FB502F1EA
+:104E600014323699BFAADDD7FBB82E07FC87FB8228
+:104E7000419A9261BEF9004CE4A3EBFCD0AE996F6D
+:104E80003E6BFE0CF5EC1C5699D0AAD0BEDE8FB25C
+:104E9000AFF7B5FB8A5C77E43E27097DE17BE7B39A
+:104EA000A10735E33163EB10B48BDCB9F6940FAE98
+:104EB00084FA30E6423D7DD67D5D422BE2CF9DDA1D
+:104EC000A3DCFD6A75D7D08383BAEBE3D9BE293A58
+:104ED000FB4361DE50DD0176C48A0CD5793219F8C6
+:104EE000B6CA743F92E1146BA791215CD49A04E492
+:104EF000C729CCEAB441FF3B00D91760CD933D31BF
+:104F00004E9B665F9FB72815283757C070BE3CC2BE
+:104F10000FD955B305DC57649869FCD9CCDF86708E
+:104F2000047AFB424B6FD1E0707D78FFC3BECFFEA9
+:104F30008F82CEC47D3B9259AB0278ED52AC81EDAD
+:104F400030478DEF0E57793EEE9FF9CD202A17E5B9
+:104F50006609FDCFD76B62F2A781ECA51A61CFBEBF
+:104F6000636255BB6C58B6F6CDD3C8F7A9EED245EF
+:104F7000B91A3956E3FB0F1A1FD531D29DA4CF5968
+:104F8000565BABCAE9EE74883E88EE6A1CB83FC037
+:104F900007BB00F6D8FADE8B5D086FA91FC1BE59AA
+:104FA00089E3AF8F8D1FC6125848BEC7205ED10E51
+:104FB000CC317EADA5D36EFAF9E0BC47B6013F789F
+:104FC0006D46762754BDCAC9267C0F206242FA9AE4
+:104FD000ED337DAE7DDF6B072902FB9D936123BB23
+:104FE000727DEF910EAA43DB48C4AB1FFA5BC3EBA3
+:104FF000F722DAE0F9FA2BD8CF3AB379BF55B044AB
+:10500000B65133EE80F0B891F375D34F11E3478E6C
+:10501000B3DE00FA19E0A3DAE72D24FB34A3B7834B
+:105020006CAE1C6E47DE976BD0E99539D6E44C63C5
+:1050300072B8FE7E2F5B95563FCB52BE27E116B667
+:10504000C3DEED389819B6C3EE6A7AA3E3505F8DDC
+:105050001DE67FA303EDF57FD60E7B7AD71B648711
+:105060003163C37B3F81FDDCF3824A784AF695B118
+:1050700013B06E23980D0949642FFBB1B4FAFAD02E
+:105080007E1423400AE09EEC044507EFEFCF75D273
+:10509000BA8D4ED66A87C5251B5D8A0B9EDF23EC31
+:1050A00019FA013AB827C9B1ED4E20798B95AD8B2D
+:1050B00049C2F7F8BEE57CA171735C8A6308F10F01
+:1050C000D93F926F24BC5E46FDA2A5FB8BF3C9CBF2
+:1050D000B905DDF9E48881EFDB0FFB7E18B63033CC
+:1050E000E3C7F47CBA6F2E9537FA1651D921F4191B
+:1050F000F8811DC80FED55AFCEBC0DFDC0DD1617F4
+:10510000A82FF669D5AB0B7EEE44F800BEF1FD1B6F
+:10511000EF9D5608ED9B6C46B2F336F6E5FEA9BA54
+:105120004621FB6193D35CB11BCA99AE52731E0A30
+:10513000BC8C7803F2EBE7B19C5F67BACAE9F95718
+:10514000EF6EC89883F661462C4A14783FEBA706A9
+:10515000F4630EC37A19F225237DBCDECCCB60AE9E
+:1051600091E0121470EDCAE576D0469337A701DAC4
+:10517000AD41588D861EAD463F73D8F0B9919EABB8
+:105180000AAC0FC78BF5E6DCA2819F1CD71A04E698
+:10519000CDEFE97D333DC77DD1FB497C3DB29F9288
+:1051A000C7DF57F20C629C389A6F7D12ACCBA61DFC
+:1051B000279E3F177C16C9270DB9652684CB4C97CF
+:1051C000C79C47FCD2694239392BE35087127F29AB
+:1051D00072AE534139673FAFB4F607BCC796AA8198
+:1051E000B5408FB18A63921BFDCF52930BE1DA9EDB
+:1051F00093621F00F31F353AEC49B08FF43C8EFFE9
+:10520000CA71607FA2BD5F6A227A3E9A33EFD72AC5
+:10521000B7F9AC5A7D33DBEA0F083D13B673783F1C
+:10522000A7B150F48375CD2E573D31F1DDED9FA32D
+:10523000439226B9617CFF2A95FC95D9E3D4636338
+:10524000B1711D3BA8B533415C1C1C08E31D17D58B
+:105250004EE6309729613B63B64F6FFF30F44E0A3C
+:10526000D14EE03FDDEC26B7EBF96427C26367055A
+:10527000C163A8C181F0B8543B8AB1BB09BF71E3D7
+:105280009E74A01F64CFE372C15EFEAA87FCA47166
+:10529000678D04B7128525C23A9B7D06E681793673
+:1052A000BB4D0105DEDF9CD379780CF2A3DBE8A4CB
+:1052B00038404EFBF565D45E40FEC52B38C508EA84
+:1052C0004FFE8ADF660B0C42FD5DF0BA75AE865E5E
+:1052D00036BBDF1F8C7A6CABA0231083B67185615F
+:1052E000B8217C9C2444D7105E0FDE1E4BF87CAFA7
+:1052F000590D58781F03E2D39EC1F9719C6AA3F936
+:10530000E6DEAF0430DE32B7E058A905FACF6D52C1
+:10531000882F67AF52FF6AE1F0D6D965DE864AB2C0
+:10532000176AFD11F69AB0E7607033D2EFA5DA7311
+:1053300091F6C9C23C619FE4B13CAD7D12CD7F9234
+:10534000F6898D799621FFCC31320FC1A7E43A82DC
+:10535000EB38F5F4E131B0AFCFDD0306201C460990
+:105360003F66B3EF2D2BE273F37995F89B193B174A
+:1053700021BCD43B4626A33C6FBBFD8AF413D0BEB0
+:10538000268FFBD15B0DCE9F9720FDBE6022B91A00
+:105390006D3D569FCA0602BFC7F8142A253EECBED3
+:1053A0001866D4C819009107E74D75772903347240
+:1053B000E5A7795C0F24AEE2FE72AA9B799CE80710
+:1053C000E60CD88E7E2C28243FE22D7690330FF504
+:1053D0009AEC7F5AE1F13A6379831FFDC1FEB00E6A
+:1053E0009CCF09EB40FD96E58BA3FA005F3295D97F
+:1053F000BE442A07FAFA50FB205F369597F9B2E8C7
+:10540000F9E5BE2BA99EE3CBA772B02F97CA2B7CE0
+:10541000C5545E09FA0DFB0DF1955239D437819EC2
+:105420000FF35D47E555BE2954BA7CD5D49EEB9B5E
+:105430004B659EAF969EE7FB9650DDEDBB99EA0566
+:10544000BEE55416FAEEA072B8AF91CA22DF1AEA8E
+:1054500037C27717D547FAEEA5B2D877379525BE6C
+:1054600087A85DDA192FE3AF60CF4D4E9CE3207B18
+:105470009BB95C68976D8D227F5F16F27B749EE707
+:105480000F79A9E17EAACA1AB4FD65BF17F2B8FE6A
+:1054900049649CCE0CD6566B36F9EDD979E8B76FD6
+:1054A00005FE77027E960D1EB01DE5E87342CEC65E
+:1054B0009A5A3C7D94B09F9E58EE21FF7CD99EE580
+:1054C00054B2A2E44B8AFB3C25E4CF56A39FA1DE55
+:1054D000DCDAC05C7E781433B05D41F9B06D88A130
+:1054E00002E5F95D433E6F437E9E54E071A3797AF5
+:1054F000D71083C14A72AAD48DEBFC36CFC4E932EF
+:10550000CFF33AEEBBBF3BF547D7417BFF750607AC
+:1055100034B344B789E23889302DCA351957D916C2
+:10552000ABD7835F0A7880A4BE0FDFDFDA7B20D1A0
+:1055300025D4AFE1FC3480FCC6ADE656C588F20D3B
+:105540001C9A87A5ACC7FEEBE7FC1AF96DC046D7DD
+:105550007E5C5F7FBF2B1FD7FBA5E0BBAC16E7D8F7
+:10556000185850F616CFFE18783E28E01D1B0BF594
+:10557000CB1FF1EFC772F0CEC0D83828AFDCD3BA5A
+:105580001FC3AF435B3BC7DAA07ED5217600C54081
+:105590006EBBB3CC0EF5FC0ECF010C4316747ACB68
+:1055A000E2114FE640633CAC67EB71E65A03F5113C
+:1055B0005DFE03243E051E427460610D687F599DA7
+:1055C0002D1E8477E64A07C567647C73ABB133262A
+:1055D00091E286B05FDC1FE01FE57CA6A78BE09F11
+:1055E000E966790042B66D9D847F16D14956BE2288
+:1055F000E2731E533EC6F3621DA51877EA1AC71C54
+:10560000DBA17DF2501EBF32370D203D22E90DE0B7
+:105610003A788A5D0B7F4E5F5B23ECD26870CDCA0F
+:105620003753FFFFDF708D84E72EA4E382EE709581
+:10563000F06CC57D8CB838FFE6E573FA03FE1D9665
+:105640009F1ABDDF0DF91C4E9170DE66608740D752
+:1056500000BE38BD6602FE30FE33558C7BA9709DBE
+:1056600098FF7F43AF91701D9CFFDD702563B417D9
+:10567000BEE788C5F38E687206C7C37DF724DF18BE
+:10568000C525B3B6AB00875A01D73B83DB2A713CF3
+:1056900029DF8C7BEFF6F46161F93634FF22720B5F
+:1056A000A7A678B62D80F2C126E21740091373DC55
+:1056B000E80F2849682FD50BBE79C655B914F10DEE
+:1056C00056AA1BE983B9F4F1F589AAA314E50D2BB9
+:1056D00056C8FEBDB6E4A847257C39F3548E4D3A32
+:1056E0009F51EF88DD8EF8CC02BBC1087400BFB6B5
+:1056F0006299C076B6925FB28EE5A1BE678EDA0C73
+:105700002DDF49BD1EE64B491F49E40F22DD62FF34
+:1057100027057C12643FF49EA0DFFA1FF7A67320D2
+:10572000F9DE365B26BDF7647E22EDCFDCA72EA71F
+:105730007648747A7E4FD2F3BA2708BE7125DC5EB4
+:1057400048589744F49D50EE4DC3E1C3743DC78C57
+:1057500074FD783E8FB74B390E7EF4EC2908FF2498
+:105760005ED24112CA9D3E99DBB9DCBE34FA5FF5C8
+:105770006FA6FF5582AEA3F141FF12479B8AE71344
+:10578000E5CCE144BE2E411D86E71366929F0CEDE9
+:105790005FA82700793FA8105C5B311EEA37D889E3
+:1057A000DE544B6739D18B2591FC83675CDE3FE784
+:1057B0007F071FAD373B7319985C6F3D79F2461B2D
+:1057C000D0DDFA2CE02740DDE1FC4F6E6C2E4278F4
+:1057D0007632517F00DBFFD978068CFF26C6331C5A
+:1057E000713C6E80E77B533574D82EE8E0F27CCFB5
+:1057F000CBB85EE08BB7902F4A195B69C8663F381B
+:105800000E1219FF907C76313B45CA8F30BF3B7238
+:1058100025BF235D83BC3E49FC2BC68B6677350BC9
+:1058200039FC45FEC5ECAEA45223974B82BF397FAD
+:10583000DEC9F8394934B97442D25514B964B7B6DF
+:105840006CD9C1C2F15CAB809F5C5F4CC6FA76F448
+:105850007BEC229EBB0AE3B9406F311319F94FD696
+:1058600081FC39FEF41CD70DD0FC723C19D765C2FF
+:105870005FBB59BCDBB2D6953010FD8F97799C0485
+:10588000A497D301ED13F17758AFE252084F2DFFE3
+:10589000C1F97452260BAC05D298F8B5C23C30DE83
+:1058A00091AF552A23E3B293E03DB4538E28D680BE
+:1058B00015FAB7E55A9819CF4BEC06E137B666F6FC
+:1058C000C37A9E85E2F807738727E0B9EBD923AF47
+:1058D000DABC437AD0B3DE5A5D5C2B4C17FA7DDE1E
+:1058E00030F3391BC2F721C7586B16F9BDFC1CD326
+:1058F0002CE47E48BFBBCDC24EF50E716339AF6B51
+:105900009D19C5B2839F63B20C4E3FBD6CBB0F7B2C
+:10591000E0D75E75DC7EEDCD026B1CB6EE74F992BD
+:10592000DB5B88A1EE87E439611DB7B3363AF939FC
+:1059300061697DEF920130C003A17342EF609CD793
+:1059400093BC3317E9E8A1AFF7C420C99C6347565D
+:10595000927F91FF6E8A13E3DA05CFA5223C26459C
+:10596000AC5F96323E17E9EF8E77EBE3F1E758C96B
+:10597000B5387EB478BC8C1B4ABF17E3828E1EF408
+:105980004324BCE5FC35400E9437605248EE1DC1FF
+:10599000AE23486E54B9E9FC13E4911BE5C7D0006F
+:1059A000CAFF97DCF9745EC15CC9521F676ACF41B8
+:1059B000E57AE0F9A09ECE476BA2E471D4BBB9DCD6
+:1059C000AA3171B9A62C7FAE06F150936B512C59B8
+:1059D000613A9DCDCFE2D82C37D7FBB35D1B3E5348
+:1059E000E3BB9F77CC7273FFF788A935D321E2A57B
+:1059F000AE1EE8331A5CDE34FA67225CDEF45A1C11
+:105A00007E18EF25EFF074D6C3BA65F916D207C039
+:105A10007F24C2AC40833774D67BC07F07E6F798FB
+:105A2000BA9F2785DA6B63288E5E85F0D2AC7B8BBC
+:105A3000D8F7EBA264167F0EC69137CEB9DFCAC085
+:105A4000EED934F0F3023FC07D13EB2AD84EF13586
+:105A50003BC52742F02BE2F0ABAA3D57B046931767
+:105A600034FBC02607D26D55D6BA54FF90EEF07CB9
+:105A7000DDCDF71523E8D9C63C0F227D84E22B0348
+:105A8000AFE7F47020C6D50AF35A5FCFCE437D2F1F
+:105A9000E32B382ED10DE371E0950EBE0E94315AF2
+:105AA000BAAEF22DD3C98B98A0C202DABAB185E2A0
+:105AB000A83141233D8FE49F9F20FFC485F9E7D89B
+:105AC000F90D0EA4272B9E6B0F099FABDB7392E899
+:105AD0001CFD5895EAE1F113C736F4CFFFEAE67AE8
+:105AE00045CA77793E1779DE26CFD9EC11E77631B2
+:105AF00039D6EF3CB793FB0D9FD7E9E11CB99F4323
+:105B0000EE28E77351E84AD293A4AF68F42AE92B50
+:105B1000F2B9A4AF8EDA4D394EA4ABD89EEDCD0FBD
+:105B200005BFCA7A643E813C478F7CEF7762FCB345
+:105B3000DE11C44F5566FFA04B9157922E2E963F13
+:105B400071039E93F430DE5BA1791FA0738B9B0BD6
+:105B50000C0EA4BFCDF0CF8F7CE23651DED49BE794
+:105B60002D0CED407B81E1576B29EEBAAEEFCF50A3
+:105B70007FD65AE89CA315F8BC0EE0BB49F07B2801
+:105B80004EDBAC0606A1BE00CDAB3D079E54C0E384
+:105B9000E89BEFCB0DA07F143BD0AA6BDF543035D0
+:105BA000A1956A2D93E6C038739CFC1CB18AF1F371
+:105BB00040EBB71B2A917E37995A32726D61381CBF
+:105BC00018F4A51DF37198123E6776827DD75A3B73
+:105BD0003CAD93E83583CE47AD0EDE36B7209FCE81
+:105BE000073B319F90CEF145BC98713E9C9BE54EA2
+:105BF000437CC838AF26BEAE8BDB468BF35E6A7C37
+:105C000057D27F249D0F2AD0F3EDF788F35E59A079
+:105C10008DF33AAFD7C913297F243FBC25F6DF3176
+:105C2000E86793F0DCA9633EB70E0F0CFAD94BABD3
+:105C3000DD98676674A2BEB17EFBDFE3900ED822CA
+:105C4000A5C7F8EE2D52FEE2397F4E18FE377A17BF
+:105C500085EA48C6D50B97EBF21322E57F74FEFC6C
+:105C60006EFEEB7273FF4AEA07D4034936AE070CA7
+:105C7000F630BD47D30752FE47EA85483D5055DB15
+:105C8000E4F20FA5F2111CC79A1DDB10E8413F4456
+:105C9000CA75397FE4BA63822A0B246BF9D249FDB5
+:105CA000C272DD4CEDF09383FE978FC5BAD0EE98AB
+:105CB000E5F22C2C207DEF5984E5189767718166F9
+:105CC000FC4613CF87540DCCBB8BFCD3CA0CAD5F05
+:105CD000B4A980D3415329EFD7965A98F137281B9E
+:105CE000FF9A9B6182797F5AC0F3C70EDA0B133A91
+:105CF0007B905BB2FCA9A09FBB500E21FF0B3C4ADE
+:105D00007F1EB6EFC1B84B93A93203FDC2F8114F05
+:105D1000B40F00B8373A0C0E05B6DA20D6D1C80C4D
+:105D2000A417D6796C15BB87607F4672A4C9EE793B
+:105D3000D82FEC9D6976ECCFD765B419BFD6F29712
+:105D4000CFE8B720BC7C567E6E10B9CEFB0B38FC7A
+:105D50006F427B2435BCEFC87E9B0AB8BEAB757919
+:105D6000EE43784E7079361550FCD646E789341FDD
+:105D7000E6AF5A797EC45731BCF48FE5EBF51F8F3F
+:105D80000934C27A2D6EEF567CFF36D5CFD0BF6E68
+:105D90008CBFF52AB487A53D28CFB923E7AF317072
+:105DA00079FD1BB15EB4D3106EC5EEB1BF2928E8F2
+:105DB000A1BFB0CFC00EDF8FE7DDA54EF6450017BF
+:105DC00069F43A31EE23F343C17EDD5940F1A086F8
+:105DD000693DE55DDE739178978C37811FFDC702C1
+:105DE0001E5FFA1396A545E047A39DEF92E374B2B8
+:105DF000EF1A07E044E7BF9700BFE771BFE6F886F8
+:105E0000E1381E60FE2ADCCFA5C2EF6877F81DFDE1
+:105E10002EF87DF5EEE509A80FC0BF677D92BAF7B1
+:105E200093E7FCB2BE31513FFFFA3C5E7F47D0F3AF
+:105E30000C710EDF25D621FD628B95F963508F4DD5
+:105E4000641E941B325F2224C70AECFC3C3F7F6C2B
+:105E500017C2777D96427904EB137929FB3D5650A2
+:105E6000DA85FB3925E6EB127636C6ABD0CE9071DB
+:105E700000D9FF29EC8FE723057C5C104A83119E33
+:105E80006655ED118EE70AF879CEFE5C3EEE787924
+:105E90001EBA599E97EAF3E1E63EC348AFE379297B
+:105EA000F26BB4BC376F8EE3790CDD9C6343641EE8
+:105EB000DF0FD29F08CFB8A4EEFAD35E18D29FAE00
+:105EC000EFA93F930BB5763C73E9E249527F7646E2
+:105ED0009CF3C8F28A42DEDE2CFC679483287F9311
+:105EE00054D64072D8C8FDCB7BE2797C13E94EB121
+:105EF000E17B9C5E22E34F32EE24E35032EE24E35A
+:105F00005091F1A74E7367533AE0A96B30736D67F8
+:105F1000784EBABCCD84E754392C0FF1B43E8BC512
+:105F200017B9294FC485F1FDC4EB1DEB4D504F74DB
+:105F3000B22444AB09C6B5C3B8330BB308FFCDFEDA
+:105F4000EBDAD2A15FEDBACFC80E4C2B7126A1853A
+:105F5000B02D9447BC960DD0D0CFD8424EEF094E0D
+:105F60001E6F65563FBDE7B124E6DEC9B4FDE4FD12
+:105F70000C4F6921D1238F4B27324E47CCC5E38E7E
+:105F8000D7B276CA3B5B6FD84972657E7ED9D5D8C9
+:105F90005FF24DA3812DDCA589BF46E61B55167E19
+:105FA00077BED13D22AEB61EC6DB45F15D190F4C62
+:105FB0005670BDD07F9D2909E1A1C74F082F1171EF
+:105FC000C26871C1D81ACEEF91F4729B80D71C972A
+:105FD000670EC1E1FC850B6A21BF0E81F882F718BC
+:105FE000EAFD98143BC569639CFC7C9B39141E0F29
+:105FF00032F3B89CF93296BFC689F9E4B68D0AE649
+:10600000EDCD3330CCCF2D13E378AA98F2410E8139
+:106010009271796C641F483E5205F060DEB10294C3
+:1060200016407D1CC0A9CCF6C2DF15E0C7F4813C48
+:10603000CE9B9E9240F90FF74489BBCBFCAE703EDD
+:10604000DB8FDED6DE2BB8ABA9FC6D7D3E5BF9DBCA
+:106050003F249FEDBE3F94BFBD4E87B77F6D3E9BF3
+:10606000947F1DAAB7E30E80FF34105AE8B74E8321
+:10607000116B283EC9FD8AEB059CFD5F039CAD6159
+:10608000384FDB7B98E0D7618275C3FCA6B11CD486
+:10609000A6DB1348CF49BF6EBAB5651CDA0767CCDB
+:1060A0005DC370DEA57F7CFC0F68672EFEFDFDF1F1
+:1060B000980CF191B1250D9FD73DDC148FF7303E40
+:1060C00034FAE3D1DEF928A056F44457EF083984B6
+:1060D0007E8D02EB5B26D6F721C81FBC8FB0E84D42
+:1060E0004B600DCC5FFF88A5D502FB5DB67B11C967
+:1060F0006BA8FF95D737901CAEDFA397C38BFFFB30
+:10610000FE3427BFAFD2C79041E8EA832058B6C318
+:1061100044718E65AFA92E9886D5B3AEF5B8BEC8CA
+:10612000F7711D418043FD4EB5D69CD0BD1D249313
+:1061300019F552BDD003F511F27E61147FE94529AE
+:10614000EF87B3E148CF0017572BDA13B01E72EF79
+:1061500002A964BF34FEC6E2C1F8ED476FA56F43E4
+:10616000BFE6F48E17E3952161F9CFD85A82DBE9B7
+:106170009DD9093DC56F65F9E96ACE2461FB86E3C7
+:10618000D1B90716980ED5BDBCAC33B5C617035CA4
+:10619000EAB6995C7E785CF7B8EA41938B01FCD152
+:1061A0003F5EF2F873C746C27A96EC32A54CE4DB48
+:1061B000B12969617CD5C33FA437899FC54F3E672C
+:1061C000760EE5CF31EF55E269C9AE3633C6BB2254
+:1061D000E159B6B3CDCCFDDF087CEDFCEB78A4FB38
+:1061E000C6DF7C65467AFC689FC2D2B3BABFBFF0F7
+:1061F000E117E3B1DFC5F0767A471CD907A7F72A84
+:1062000024A7A2E1EFB142CE4F40DFBF7B1AE65D8B
+:10621000F896C585FB5EF8BB9BE371FDFF6B6CE0F8
+:1062200074FECBA634940B0B4DFE340795FCF9C2DB
+:10623000ADB710FDDD74F416F2DF81BE7B198A68FC
+:106240007FBD705FF37F318DF6B5F09773695FECBA
+:106250000185A18974CEC82A76F580CFA9C3B9FC7F
+:10626000FDDFED1652D6FF6BE6FCE9FF8B1AE079F5
+:1062700018CB89BFE57D3D8A5C41FD9C95E327678E
+:10628000B8CCEFE0F980F5A257FD8E0D74EE71AA3F
+:10629000AF271DF50CC0419717A81E1D97CEF1C260
+:1062A000F303E93DE0FF327C8EFDDB4D9E9861BA41
+:1062B000F7845FC9E75F29E68775C72A57419916B2
+:1062C0003A876CC7752C53F83B483798F7E617FBAD
+:1062D0000CF1FB8E4D1C3F82DFBF788DCB91658129
+:1062E00029152407DA4DADE9D82FD076BD4272C00A
+:1062F00012BE8FA8E5E31D26410FFA76589751D1BB
+:10630000C2739F42F1A405F7413F8DFF5FBFFB2E93
+:106310008A57D7E37D475D5E21E743196FBC292289
+:106320002E2ACB48393071B8880F0A39108A57FEA7
+:1063300022F53BE383D23FA933057EFD20F2EB9BA0
+:10634000163AE7AA7BDC44F99F1F3F76E0D80CA001
+:10635000EF8F774A3ED5CBD5483E5DF8C434D6138F
+:106360009F7E9C52C97AE45378DE239FA6309263C5
+:10637000FF32B91A82B79E2F6F8A22576F8D8027FE
+:10638000D8ED09C5503DF5DB25FD292F2B02AE12B6
+:106390009E91F23171B8B347F9083FAF310D1C251A
+:1063A000FC247D2E7E7429CD13A25B499F524F851C
+:1063B000E83372BF7A3846B6170F67B41E93C165CB
+:1063C000C5D0CC8CD41D76F4471A855D0B06E82128
+:1063D0000C294FF3648B7C2DCEDF225794ED1D2EBC
+:1063E000E35D9CDFE47D1F8B97F3BD8C675818F04D
+:1063F0002F8733F1FDCBA90B2672E36745845C310F
+:10640000905FD09E52F46B91F74072C1424D78FF7D
+:106410006533C1E35A8F4A70B078781EB1667CC28A
+:1064200063A3E744269E4F3516595C2887A13FC1D8
+:10643000699A97C3739A67C24708BFC92987AA3068
+:106440007FFADA223DDFCE88E0C31BAAF4EDD3D970
+:10645000F654B447A72F34B180827690BEFF3DC377
+:10646000F939D30DACA1C9C1E959C0497FEF84897D
+:10647000F3DBC9428EC97CDB577628E45FBE523419
+:10648000B73917EB8F81D508EDE74AF29915E0F09F
+:10649000B289ED21FBD6E3713A0AE95E0D3FDF2DAB
+:1064A000FA1FB2B3128A0C3AF992E889D5AD3FB916
+:1064B0002249574FADECADEB9F5E3540D7DECB7B2D
+:1064C00085AEBDCFC23C5DBD6FC3485DFFFEBEB1B2
+:1064D000BA7A96FF47BAFED91BA7EAEA835A66E85A
+:1064E000FA5FBE658EAE7D7060B1AEFDCA4756E8FC
+:1064F000EA4377DEAEEB7FD59EB5BAF6DCD63B75C8
+:10650000EDF987EED1D50BDA1FD4F51FDEB15DD7DB
+:106510003EA2F3B7BAF6E20F9FD0D547753DADEB7B
+:106520003F26B85F572F652FEAFA97595FD5D5C731
+:1065300039DED6F5BF3AE384AEFD1AE7C7BA7689ED
+:10654000FF09396775CFD161F2033D2CE68FD8245E
+:10655000D737BA718CAC92FC47336BA0D28AF989D9
+:10656000D9785F9DFB9536F433A12C2AF3A616A1AA
+:10657000DED9EA5F8FC4F5F288AFFAA1FE78A5E410
+:106580003ADDB9D7B5F8AB134AABCD8FF254C67527
+:10659000E2832A6BCD073A0C2A543A8271AC15FC7F
+:1065A0008DC4600C9549C1647A9E1C4CA43225D8D8
+:1065B000879EA7067B519916CCA6323D9845654625
+:1065C000F04A2A7B050753D93B984FEFF509E6526D
+:1065D00099192CA6E77D8323A8EC172CA3E7FD834C
+:1065E000A5543A8313A8CC0A5E43E580E075D42F06
+:1065F0003B3885CA81C16A7A3E287823959705E79A
+:10660000527979B096CA9CE0122A0707175179454A
+:10661000F0667AEFCAE0722A8704EFA0E743833F6F
+:10662000A67258B091CAAB826BA87405EFA27EB96E
+:10663000C14D54E605EFA5E7F9C1BBA974071FA238
+:10664000E705C107A82C0CFE8ACAE1C16D541605E6
+:106650001FA57244F037548E0C3E49EF1507775151
+:106660005912FC333D1F15FC1395A38307E8F998D5
+:10667000601B959EE08BF4BC347898CAB1C157E991
+:106680007959F02895E5C1B7E9F9B8E09B548E0F28
+:106690009EA0F2EAE05FA9AC087E4CE535C18FA868
+:1066A000FC51F02CBD3721F819951383DFD0F34945
+:1066B000C1BF5319F2074AA2DEBB335CA038F21601
+:1066C000A2A31A41AF3F8F8B27F977ED2A7EDF60B7
+:1066D0007DE9D9728A872EB738453E7084BC3C6FFD
+:1066E000437BA1095B7AF13130DF65A6A0CB578AE5
+:1066F0000EA4E2F9D5FABCCE3A8C536DCEEAACC109
+:10670000F2D622AEB7961771FF706511B75F9F1B67
+:10671000E19D5C06CF17F735F8D17E581CEF4CB8D9
+:1067200001BA3C2BE4394B49E2F983B6AE7E6847A7
+:106730002C13FCB46CEFFF74A0DC55802D7C68E753
+:10674000C8FB387BF4FB57604D3549A8AF5C562B2E
+:10675000C6733319C5A723F5C2C5E2C2B38BBC9B70
+:106760008A489F340CE7EFF3B8B0D43397F0FEDDDE
+:106770003FF0FD07483E44797F43CAAD95B5583593
+:106780007A8C93001FD5021FD50D37915D037A8E49
+:10679000ECB94EB0E750B75BEAF4F77E2D8EDD26FC
+:1067A000F403AA57F273C7C876F889C73CAEEA4C1F
+:1067B00003C3381794D4AF1AED399D9FB093EE49B7
+:1067C00055A31F16DFBD7D4E147B6F7791DE8F962C
+:1067D00074572DED1475D5213C2F3E7744A518C76D
+:1067E00081543353A0DEB9D44274CB36727BF0EDC2
+:1067F000D43FF4756AFCEA5A90871E3CA75D7A5B29
+:1068000006D2ED86A65D268C6B74F65D4E973D2212
+:10681000FDE8CEBE8CFCDC6AFF7223D99939403189
+:1068200069C21E72A2DDE6DC897064FDAC2E3CBF3D
+:10683000530DFA73EEA2119CAE65F91EC68BD00FF4
+:1068400059C6F37A4C8606BACFC9FAC51A387FF909
+:10685000EBB03EAFF9F201687F55189915F35CE58E
+:10686000781A3B2B96E06B04C068ECB3483BEC44D1
+:1068700051A2F00BF9BDDE13E27B35F8A3C87D50C1
+:10688000FEA1C78C79B096142BB7E75AA62C41FB12
+:10689000F0BDD03D26D81BCC538D6B048057AF8AFA
+:1068A000F30C86F60F05FF9A44FE10D0895F6BDF6C
+:1068B00056A39E83FED78C907120BE3F6FB3C589CF
+:1068C00074D3E37A0C2C94DFEA6D4E0C501C35C562
+:1068D00048EB32F5F5CCC273028B1FD687FC6DEC0A
+:1068E000BAA516CF03FC89FC9EEF3A653CCA1B4B48
+:1068F000F39AE5D80EF06346E47723339A018EB518
+:10690000CC313E03E1DDCCF38D75FB427A6F5668E6
+:106910005FF6D07A3DB330756DAE9FE7D5013DD0BF
+:10692000FC4D3FB17BF8FA946DA89F257EAAC5BCAB
+:10693000D52D7FBC0DE591579C7F548BF9678BBC9F
+:10694000C968701A3942DAF39EE36FB8BBCF2BD710
+:106950002BE1D4A4F0FC68FF66651BD28F65959D82
+:10696000FC75B97F8B5847F98801B41F0987CE356C
+:106970003754D5C2BE4E6EBE1CBFECD16D3D48DB58
+:106980004C431F9174653270FCB07E8CFC6949F7F2
+:10699000925EF247F0F8AB2C5DA17D69E2086A983F
+:1069A0002E23C79772EC6A6D7F787E7526CF077DA0
+:1069B0004FC45D878ED852E387F95E2A12FAC1D997
+:1069C0009043E78D623D0848E20F41B7169BD533EF
+:1069D00018E03146ACA749A92438F8375B881E2255
+:1069E000FD7267880E98D75C28E4A8019F3BE9797F
+:1069F00075B385E02DF1FD7EE8FB3F9E7E53501E72
+:106A00003B041C057D7D2BF4DEB7454E313FD03D68
+:106A1000E2EF6E0BC903899FF77008905F3346540D
+:106A20004E1B5140FC398CE4FB2A7EEFA5C6D036C4
+:106A300008CF2F6BD6B65219965B1C6E15BDE57745
+:106A4000625C943FC2326D940720F354CF3617D066
+:106A500039A3379EF7538CDEE158AFF8C7DCE11855
+:106A600097656FD9E97ECCCC6C367BEA1091DF0755
+:106A7000EB99D9784D05EE73A980CB2BE05F7B2E87
+:106A800067ECE86A2BF300B1BCBADA41F5D7576777
+:106A900050FD8DD54E2ADF5C9D43E54933A78F9984
+:106AA000C9324FDA41F7106F16F2F1E610BC5766A3
+:106AB000A0BF5CF18F57312388A5F89FAE19378AA4
+:106AC000FC4894C1213AADBA3E4E1C52F07A6D6535
+:106AD000B1AEBD53E41FB09CFCF0F3019C2E907E40
+:106AE000E76CCCA2F3AF1B2726EBDE9BBEB18FAECB
+:106AF0007EA7C0F7948A6CDDF3193557EAEAB5E250
+:106B00003E32B3C61AB4F13110D73C4F58E4FDDC25
+:106B1000BCFCEA84DB60FE9B8FAAD41E89875BE7FE
+:106B2000FA67E1FA6EFD95C585F701E66E51983F6B
+:106B300099E0C7F5C73195F86EDE16957961BE53B9
+:106B4000899EF40418EAC318BEAF0F5F57B735A289
+:106B5000FEF84736D74FBFB6907EFAD0C4FC0EFC85
+:106B60004E010A2D787EEAE820BA573133BBB52FA3
+:106B7000DE2BEF7A2A86CEEBE676F2F99892477111
+:106B80008B0F13992711E8F293492D0B285F5D3D78
+:106B9000928AE7309F3C01FA17DE5FB4FCF54207AA
+:106BA000C075F1F33B8F21899F6C519903E3548F9A
+:106BB00058B6F17BCA9E74E487F03E03C3286FB3D6
+:106BC000B07217D2F7A9058161E4A7AF4A25FA8E02
+:106BD00084C749B37738C6CBFD4897309EF756BB7C
+:106BE00015FDAFB926575A2ED1118FD3F999BB177E
+:106BF000A338EC13443F279B078D27F9B851611840
+:106C0000E796E3033F4D46389E6C493620FEE73455
+:106C1000AB742E86F762896FE57769EE56BD6083A7
+:106C2000E0FB5E1E27D2E311245B3AC26D03388479
+:106C3000A87F6645890F7E0ABCE3D5C4A1163FC371
+:106C4000BF27C4DCCE9F96C0FA26EF282BA03C8835
+:106C50000C3EFE1749926EF877943EF7F014EA73F3
+:106C60003BEC01A487D386278E1B010F6D06EFDB5B
+:106C700008BF8593FD5B15C0FF99BD27FE13E3FC9C
+:106C8000A71E37B970781BF3BC43F2C3C7ED217957
+:106C90009EBCF8B73144275FF6BD621BE22F2C3F44
+:106CA000D6F07D8BFEB8221ED76E4D53009E5E2718
+:106CB0001B8F71E46AB653C455389C9CB8288093E6
+:106CC000A38EC7D34E14D8EF6457017E22ECA113D4
+:106CD000821F3F137C2EE55CEE485E9F2BF5CA3E7B
+:106CE0006E1FC9EFF72C641C1E329EAF8C1C4072C5
+:106CF0006EA1B067E907F6BD04E80DF1B9C091B81F
+:106D000012BFCB54F7488C2B00EF8D1EC9F917C664
+:106D100070205F2E12AFDCC402CD7930DFD2474C39
+:106D2000AE56DA8EFCEE8F91E4C42913D86E493842
+:106D30009E42E3D7B528018C3725943498719D4B3A
+:106D4000762B2C99FB45149793F7DB171B3753FCD5
+:106D50006D718E4276317BC47452EB872CDDA9BFF6
+:106D6000D75E1F719F7DBEB5B95DE57906FA7BFCE4
+:106D70002D26D29356665D83E354C6D9695D8B5B3D
+:106D8000B8BF165EBFCA2E002C177803CF4F263827
+:106D900028AE00EBBE8E7129CB691F8B711F59DDA8
+:106DA000D715B9AF4B5DE702571BD149E47A357867
+:106DB00070EAF1D04EF1E4BF359818FA7D0BFC9CD7
+:106DC0000E16EC057867111DB4E3F706241DFC2DA3
+:106DD000A581CE55FEF60B85B56485E942D2C3A2E6
+:106DE0005D0133EAFB8F594BBC0DF8A46ECBAEE9C5
+:106DF00028C26FFAC55133DA0F3549AD830C8908C3
+:106E00003AE72F2BFA86E9735140BFFF258FE8EB55
+:106E1000FF2AF8301157A5F7002EF377A8644768CA
+:106E2000FAE9EC20A6369BF11ED7B980E24279BA86
+:106E3000103F9B91F7FDD75B1FBAFFFFEF5D77A473
+:106E40003FB76CA4F0E75C3C0FE6F386693CBF7685
+:106E500055CFF7A923CF4322F5E93B269EF7D283EE
+:106E60005EBD16E902F4AA012F094693C70B843EC2
+:106E70009D8FFA13CA0FB63C198F71B5BFDDF76449
+:106E80001A9DF3A0FE19A2D5C7A01F511FFF31867E
+:106E9000CE4F6B7E6969C5F8F3E9DD9600CBEA3E1B
+:106EA000FEAF0ABD9BE9CE81D09FA794A385F8BD14
+:106EB000292957A39DE7FEBBF63B07F79B8F760476
+:106EC000DFEFFB1BF93E4F34F37DCFEBB65FBDFD2B
+:106ED000F1614C2BE9FB0F77A90CED0A694748BB20
+:106EE00040EEF31C6BD98ADF095BBAE28DE346A062
+:106EF0008F4597B50F6B8575D5DC6D217B60D153C0
+:106F00007682D729A5349DEE7BB5583C3684E323A1
+:106F100031F43CBC8E907DF0D4C8548D7D7089F0E6
+:106F2000937120C5E9E0F911BF60F47D4B3C1FC1AE
+:106F300073096633907E897CFFB4D0434B5503D9E7
+:106F4000A775666EA79E117EEA0B23B9FDFEC248A7
+:106F5000EED7B48F74087BB56B2BC2EBE833160702
+:106F6000EA9F76338F0F1F3579B6FC04F6B5A4D8A7
+:106F7000FB0AD243A5C13613F9666DDC3013CAA1F2
+:106F800075890BE85C69166B37213C26174D7162D9
+:106F90005CE5789AD5A512FFB34A56188EDFBC6C13
+:106FA000E27935C711CFB0AF6A71DE703C06C425F7
+:106FB000CC7FBC9799E243FE672CA48737C4F27854
+:106FC000304B49A0EFA2CE10FC3EB3DCE241FFBE45
+:106FD000BA7C432596309E9F01BC6AAC5D4D988279
+:106FE000B2C6C0F5DD9A2416407CB3759D0508BF76
+:106FF000ABD83A07E695C0EE775F48FE2E3CE8F343
+:107000007AEA307E3592710415117C75F53A336F4A
+:107010003714FF78E67D9950471B1DEDD16BD4C026
+:10702000F62C8C731B089FD762BE0BD9AF19BAEF31
+:10703000DB4D857F25B0CFA946E6372451B9D1066F
+:10704000E5B422D69A00FB6B3DACCF3BBAA1D5D0BC
+:107050007A399E63195BDB282F46654D68124F65B0
+:1070600059A61578EEBFF6D2D69B59BC6EE67D25A3
+:107070005037F0FBD65D3F56E87B6BB38CECA00A33
+:10708000EBA94F72FAE9F97285ECEA6A60263C9F37
+:1070900085F68DF179F89E42F485F8E5793C3CFF60
+:1070A00049E209FA5963E179EFE22CEE6F8AF56E55
+:1070B000F11AD2F07BBE4B851F35CBCAD661BE1C00
+:1070C000F87BF118C7C985656AF1546F96FED64EF4
+:1070D000F354B06F97ECFD9F8E2C80CB65C59C9EC2
+:1070E00097C878E963FA786945B193E655D02E03DD
+:1070F00078568B321A7F8C13E38D2BE6FC915B2C38
+:10710000FDFE9DE4E72D1171DA68F32DB5B05682CE
+:10711000D73316C2BB9CF75A519615F338865C8755
+:10712000A4F3050CEC816C2CB91E330032294FA757
+:10713000E55794DFB9F0171ABB87FEDF42E7D08B23
+:1071400077443ED7E8418A4FE8E3E58AB96B1EAE43
+:107150004F191DE342BEA836EF24FF5B018702E909
+:107160006B4194F74C2DDCDF3235737B86E22A6E5F
+:107170008CCF2801948FB599AE0CBAA728ECDD0509
+:1071800002FF73521A48CF2E40BB86CE59791C9508
+:107190006DE1EB360A3B756E8B5ECFD76E8CDC17DC
+:1071A000D7F7F23EA905F7A9D1D726A1EF1B4DAE1F
+:1071B0000C94B326A6D7FB8D0A5FBF3F95C77B58BB
+:1071C0000A6F370ABB4EF2FDF46293EE7B72E7D88A
+:1071D0007923C25FB65796E39DE2E872E35A4F5CAB
+:1071E000AB42E7CB571FE2E5A6763A1F16F9D0D798
+:1071F0000A3E87E764C75456287E3CB2B8D6633A45
+:10720000A5DDAFFC5E53A41DB2BA384A5E4649F212
+:1072100025E565C8BCF11A94D7940FCEE3D22BC2F2
+:10722000E7C73928BF6B945817DAE3328EFF79032A
+:10723000BF6F54F32ED77332AE7FA6D4EE3740F92A
+:107240008EA8D7C49B8D68BFCE4CB8753296B7A9AF
+:107250009D34CF57862ED20FFBE27DE5288E3F6FFF
+:1072600078DD8E68585F9ABF056C2AF6DF7F7E75E1
+:10727000A6B52F9D0A8AFCC4F7DEC5BCA5EBCFC31B
+:107280003EA8DE39D303FED899E7BA66E1DDA3173D
+:10729000FFDC39D308F039737FD756AC9FF8F32958
+:1072A0005EDFDCD52F86EA9FF1FA1A319EFFB39993
+:1072B00038DE990778FD4FD0EE2779D23A08F73BB0
+:1072C000B921C6857104198FAA31ECA7121D6D94DE
+:1072D00043922FBE1CF4D9AC156447765D86F2A0AC
+:1072E0003EB6D5948EFCBE8BCBC7A52B4BE34B197A
+:1072F000D21F3F1F7D5AE863C5E321B96981B1629E
+:10730000810E9E413F22B5BB7E6743603DEEF07A21
+:107310001E2DE6FD22D7F54971E5A3C5A9F83DC5A7
+:1073200093743FF9CB519E478BF9F9D3412C174FFA
+:1073300051FC6680177B2D7099B01BC86FDE60D042
+:10734000E7C93F2AE49C2C5F2FE1E3D62C1F447948
+:107350007B30DECB3F64BCB9385E41783C09CFF965
+:10736000029E30FE5B3F647C29B7E478AE51DDD6E7
+:10737000FFC10F19FF9151FAF54BFB54EE6328DA68
+:107380006080E7E2D18CE359AC473E6F525A536FAD
+:10739000C078D76195E2574DA91F18F1BB04ECA442
+:1073A0008DDBC1319CEF624A443CF7272E8AABF952
+:1073B0005FE2F7EF9B52A767A0BDF7F1E3372553D4
+:1073C0001C4AD88F1FB7BD69C6FCBD65417EDFBEB4
+:1073D0003EC8EFDF2FDBDD661E8F793E509669E2F7
+:1073E0001675E1EFFA18310F5FAE23A6C420E41D35
+:1073F0008F9B1CC7BC9D21DDE5487A4928FE4DFBCB
+:107400001E26F677C6E3719468F62D9FCB7B5391C9
+:10741000E3D488713EC5E427CD7857291C7F35B168
+:107420005C1FCF2DB45B9D80AFC28ECA323BC0EFD4
+:10743000A62DFC7B46A7468CED57A2C1BB7C2F1C1A
+:107440002FEEEA395EBC97C78BE57C2EB1CE9AA4AD
+:10745000F695606CB09ABDE95BADA3189BF073160E
+:10746000CA97C6B86C8545D687CD2ACFC478A44ABA
+:10747000F5317B2FDF8AF7D80E89FB0B33870F8D11
+:107480004579D799156770801C9C3AA2B606E132FF
+:1074900073F8A8F1F8BCD462BFAC96C7F389FEA616
+:1074A0008EA82CC276EC8F71A69AE5A605285F3FC0
+:1074B000F7C7503CD23B2CCE8BF1BC430656CE34A2
+:1074C000F7680A05BE6A4A38BDC9F9E5BC300FC97C
+:1074D00069EF3D7D282E3663446975496A78DE1967
+:1074E00023BC15DA79619BC3E87BB951E68FC4DF11
+:1074F000B8121EE7AE2EE1F8AB2C01FAD3E8A7A92B
+:10750000E571BAFAF5139399471B97BEBE8FAE5E2D
+:107510005593ADEB3F63DE95BAF6499676B7D63E06
+:107520009178BB543F6A3CF07D02C0A5BD8D0DDD56
+:107530008D7C9865A77392251BAFA1387742B09ACE
+:10754000CABA966BE893454B83D7517D99F8CEE63E
+:10755000A43E33D7A2DD7228B69DE2B087FE9048E4
+:10756000FEE32B6AEB650FE178163BF1F5A4DF5FD4
+:107570004DF974CB76AF798CE27FCEB87C8CD74E48
+:1075800052D92105F30983317C3CF52FEEE500D774
+:1075900009655C6F4E421D0EED8D22DE188D6F1A4F
+:1075A0004BB81E3175F2758F0B4ED17D8F7453C958
+:1075B00000DDBD4853EA0E23D9D7623FA64E85CAE7
+:1075C0001F05AFA4B27EF714239E2BBF90F3AB141C
+:1075D000D41FD09FBE9311924B926F1A86277CD7EF
+:1075E000F7092C42FE548B73E91A8FE7BF90BE2631
+:1075F000AFEA3462BC87D9CC0EF4532717E5662C6A
+:10760000D08CD3D8762373D2792D33A35EAE865235
+:107610002BAFBC11F7AE64F97084BC92729C3DF63E
+:1076200029FF6EB38C6B0BFAB847D0AB7CBF1D65DE
+:1076300028E2ED297E5E758BC7BB07D7DB5ECAAA41
+:107640009E20F9D1DE0FFD8F7FD5FA01BF56C47F92
+:10765000BC91CF1B5F94B51DEF753D13DA07A7D31F
+:107660008BEDE3B7A2FF2B2AF3217DBC32664C3BA6
+:107670007E87A4ED8EFC7C948BCCD1751EE9AE7E0A
+:107680005F71367D4FA384DFE3ADDFC7F3C9EBF74E
+:1076900059289F7C5272D707DC3F8971A27F82EF05
+:1076A000211D9F81468CDF5F51EA7D09E151BFEFCB
+:1076B000A37CD4779EBD5F1DBFC38D59BA76BAAF88
+:1076C000F249B1E765922751D679317EEC4E5F16CB
+:1076D000E2CBB34E3EBE7723E743AFE0C75A41BF8C
+:1076E00073043F4A7E3621DDE523FD71BAAB0B26DC
+:1076F000F2FE02CEB373F8FDB9A5C12C7A5FF2F1A8
+:107700009C55CA655B903F8D76BAF73347F083E4AA
+:10771000D365C1641D9F4ABEDDE5F17E8B7009F122
+:107720006D23F07BFCA5D0C9DF8D987F612A514C79
+:1077300048271628CB34FC5D29F05E3B8FFB27B52C
+:10774000401FDAF378C3A8EF47EF6704BDCFB1B5A8
+:107750000EC2FB6226B023F1FB3C35A94E925F2B93
+:107760003629F4F1B11526AE57573CC0FF1E00EA8A
+:107770005BB4DF0B3B1ACCDAFB1A3706873127C024
+:10778000E7BAE0402A4F8DF03A46A5225EA60BBC30
+:107790000CBBA4F3C22F1A86A7A35DF3C51113B5C2
+:1077A0001778787CCE14B0B8B665617CCEAB22DE9B
+:1077B0003EECCB1CF76AE27318EFC3B89F3C2794EA
+:1077C000F13A4B8A41776E79CED8D20FEDED6E71DA
+:1077D000BB526E7F9DDE61E279E86D7F29C47BB686
+:1077E000A7B23C14BFBB50E8BD6214DA875303BF95
+:1077F0003361BCBDE5C96378B42DE15933964D20A2
+:10780000BF67BF81E4FECE66B522C0F578DC144DBB
+:10781000BE92B42B0E336E8F483A5D1CCC26F848CE
+:107820007D23E5F71F576790132DE578343D14C984
+:107830002F522F9D6D78633CAEEBEC6E858E42250A
+:107840007D87F590427C05428AE83CAC7F389D4BB1
+:10785000B93D09E34280874909FD29EE26E578A470
+:107860007E2AFE4DF6EEA79D98473EB312E71D73A4
+:10787000A54277A2EB9EE8E5F6F620A7A5BE96F016
+:1078800090F07941D47B7B3CF3908E2ECE3F3164D7
+:10789000E75AFC5318C95928B572D61461D7CAE7FC
+:1078A0008B46C9FB2497C637378CD2FB13729DEDEC
+:1078B0006619B7E6EB7F9171FB43CE738B67AA1F06
+:1078C000F7817A83ECEA51DCBEFD57ED2B9AFE6816
+:1078D0001AF5FDF4C70A010FB93FB90FB9AF23621A
+:1078E000BF97AA5F1E1CF5CFE917F26150FEC624B0
+:1078F000501C66F4B323BEB8C3897AC662443BE326
+:107900008CA7ECC1519A75CA75C975BE24D60D7A7B
+:10791000E8BF4669F0259FFFB37A49F26B24BF4563
+:10792000F26F24DF46DA8B926F22F953F2B5E4D37B
+:107930000977717B9465737B54F2EDA1580E9F43D8
+:10794000572452DC7AD96E1EC766B68480D69E94C0
+:10795000FA6F92BAFD3FF1DEDBA43329AE4616D6AC
+:1079600087926F99C7FB2AC269ECA3DF3CF9160B1B
+:10797000F3EBC5E9F34F26D25B750AD9371628B564
+:107980007ACB1B85EF3ABE27DF3D2FFABFA272FAF2
+:10799000F62798C92EBB18FD9D1AC5BFD7F66FA054
+:1079A000BF5308AF6876F819C1DF407F67904EFF7C
+:1079B0007576D01B6EFC9EF35937D84159613A9ABF
+:1079C000F022D0893B4C2721FA30F715F29ACBF1FF
+:1079D0000917785E9E57C401243DBFE5F1268F2E1E
+:1079E00008D3C3A158FF10B46B2ED5BEAD4E69604D
+:1079F000784FD60BA5563E59C477C523F19F31FA6F
+:107A0000FBE1DF3C3A84FF4B923B39A3FF69BB3675
+:107A10007FF477D8B5CC11AB8B17B84CAE04CC8BB8
+:107A200071BDA422C6A2E253DDC2E11D825BAB514F
+:107A3000DA07C9681F009DB847FF103A6195191809
+:107A4000E7A7BF5340E7379FCC467C1C50659DC7D6
+:107A500029DAB0DE1BF87CF427EFADD3C42DEF118B
+:107A6000F1917D22CE85F19D5D3DE8EBA7C770FFCA
+:107A7000F2C037A71EFD3DC69FFA9BC96E00089C49
+:107A8000EF0238BCDFD74CF93DB27F5B7FB30FF715
+:107A9000D966599D315FC32707FAA79DC77CD603D6
+:107AA000E9FCEFB41DB8239FDEF7D7F3FBC3FBFA65
+:107AB0007DB07938D4F72D53F18BA2617D57C7F390
+:107AC000974C293BEDF335EB3B509F5FE2D4E8DF69
+:107AD00073C2FF7F3BF356FAFB366DFD57B6E3DF0B
+:107AE0008BF3A7F3EF3A5AFE5EE3C07BC8652AFF2B
+:107AF0002EE892D15C4F1E0FCE686F877E4DB60187
+:107B000078F202CF45BC2D73BA95EEEFA618086F38
+:107B100026FB4C8759B31F4F8A91AF2B4BFFBDBC3F
+:107B2000CFC5B8FB043DEE571DB46F588703E30182
+:107B3000B3BFA9E96887794CFD0A9D787EF0EEE82D
+:107B40006C913FED28413BB54CEDCC671ABD76A357
+:107B500041E8AF88FC6C0B9E6B0CD3E5975A298FDC
+:107B6000E12279D391F9ADF8A3A485F34841B70C8C
+:107B7000C372F3688E77E467FC3E83CC9F3E24ECAF
+:107B80001E908AE5F85CE621CB3C69535FB66C2A0F
+:107B9000D119CF8F7F508C23E79179A6D522EF3969
+:107BA000943F9C6E1EB607F0DF6933D33D4CF95C01
+:107BB000CE572DE68B96672CD7F1DBD1FCFBC58D1C
+:107BC0003FE1F1AECE7E4E3A97C01F6D7EB1CC271D
+:107BD000EEECC79651DEB598AF499CF7596C7FB86B
+:107BE0000DCF674279C56B8B33503F36C938C152D0
+:107BF00091C705F031A769F2AC53CC94675D0DEFE6
+:107C0000670DD3C8C5EF9987DC2D3F38A22EED1B39
+:107C1000491F2351361420DDA7AD22BE4AB712DD1D
+:107C2000EFFBFAF60ECC037E2FCD4A7233C4A7E9E0
+:107C30001925F8770EDBEA93577569F864DFD77B6F
+:107C40005FC2FB07FE34633EF2E5E86FCE0FC5BFAF
+:107C500003D2969E42FD47AFFEF8E33FA21FFD4DC3
+:107C60002C7D5F6ADFD7239D2837554327C907F648
+:107C7000752CD1795942558653C317AF0BBE7AB0D4
+:107C8000C8F32ACA3D350DE8DF1696636ADA742F09
+:107C9000F26B635F6243FCFBA9146F6E14F890E310
+:107CA000BC2BF4C2BB92AE8C4EBA2FB35FE574ED21
+:107CB000DFC0EF419B52F7D8B5F1A94F45FFB6B8E9
+:107CC000042E9FEA93CFE33E6B33BD66C5A9EDC793
+:107CD000BF4F6DB126107FB759C678917F6B6DD3BA
+:107CE0004DA47760BE6928BF47F3EF643526727BE9
+:107CF000E03D43A513F1F85C91B7700CBCFFBE8961
+:107D0000AFDBE368B7631EB467657222E69B8C162F
+:107D1000F2A7ADBFD1A78DA39AC770F898C770F925
+:107D2000D1D6FF56C29BC4639BE559C28B29ED7A1D
+:107D3000CA6B1F8DF218F1B03ACE85EB6F4BB712BC
+:107D40005DB6A5F3EF4DB7D5AB1C1E0956B20F417A
+:107D500091115D8C4E3792BC7E77B45317FF92F829
+:107D6000DDAF367470796525BBE2EDBAE4F38817B0
+:107D70009329C181FB7FCFD05580F2E1DDD149FC51
+:107D80003BCB86CA0CA6F1176684E555062BFC4E44
+:107D90007965BE947B1E17935716FCD3C0C09F0312
+:107DA00004FC2E26A7F0C754D8831C12722E52DE74
+:107DB00084EE59FC9BF8774604FFCAE7529F49B806
+:107DC0007E19AAF3BF3724F366DE1776ABBF2F23E5
+:107DD00079549DE9A1FBC76C5DC641ED79BB09E50E
+:107DE00021F4DB709F1A40BF439EBB6F4819EF28F8
+:107DF00005BAD8D0C2EF01C34F33E6C1CD15EF2D80
+:107E0000702FBF0CC77B680C8F237B3F748CC7EF30
+:107E1000A11FCF9C5AB906F379328D0CE9EFD97FB7
+:107E2000F0EF5C9574B59725205FF9F9B94CC82F30
+:107E3000386DA4EF46D43207E543BE17EFABC0F769
+:107E40001B7FA9887D343CEF457AFF25FFFE61E367
+:107E50002DF6788C3B15F77D6D12DA05C5F7A792E4
+:107E60003D769C35B4E37AFDCD2AD127D8E3077B54
+:107E7000E1FE9544923B874DED2F6541FBE15B921E
+:107E8000D1D2640B8CECA001E86381E0AB6A919FD6
+:107E90008170B1E2779800BFF8770301DFAC771EFD
+:107EA0009D3393FD7AC800949987F623A7873AF10A
+:107EB0003E8C67C5FC44A6EE2DC038BA9453C64428
+:107EC00037D9A79FEE995F88FC694ABDDE8BFB3BE3
+:107ED000B3774921C2E1B6312AFF1E78F376FA3B27
+:107EE00005963D77FB71DFA7117868B76EE4DF1563
+:107EF000967F37D522BEB378B171D7CA715B427F06
+:107F00008FF5BBC7DDA2CFA7687C20C68ADFB798F4
+:107F1000775FC473E1E744FE3DABEA667DFD610136
+:107F200017996F10CD6E8DCC57B87F8C4D7F0FEEAB
+:107F300022EFCB7C8587059FB07722CEF11A6E7336
+:107F4000A09C3D0BF4C8F57D8315EBC7F11E9FD2B5
+:107F50007DBCCED58CEE6D5C17C17792CF0E08BF7D
+:107F600003EFBDA05DFCACD9B912E5EBB3B17D1553
+:107F70003FC9D39DC9781EB05BECFFD9D0DF297013
+:107F8000955C07FAE159715F68B7C0CF9F4FE7D1A1
+:107F9000DFC1DD17CC2B99A3B58BD5CE4787939C3A
+:107FA00036D0B92E7E1FE1C91EE070CD6855B74EA0
+:107FB00069BF4BF970AF58B7A4D7C8F78F0AF9D883
+:107FC000B9DAC74E68BEFFEC157E983C4FB5A438B1
+:107FD000757C3BB178ECE1310561BE60076E645998
+:107FE000745F279FFC94A362FFC0BBE3311EC032C5
+:107FF000F4DFC1FC2CE23CFEDE901CFB7EFECB6776
+:10800000C5E0BF68ECFDBBC5FE43EB3A0F35A007EA
+:1080100055C4996BF07C14F8F453B1BEF176037D2E
+:108020006764C2CF5B1F267D72734C1EEA930A0BF6
+:10803000FFBB139837BD4203B74F05BC26FC94EB3A
+:10804000EB098DBCC471B6D9C2ED3563F97BB22E94
+:10805000F729D7F759B1B8BF15251FF8DF5DFE3FE7
+:10806000FA813CB6008000001F8B08000000000071
+:10807000000BAD590D7014C7957EB3B3B33BFADD59
+:108080004512482020BBFC1829081884004988F2B2
+:10809000AC7EB0B82079650A237C4A32011B0961A5
+:1080A000CC1AE288A452B7830558C5512E99F8120C
+:1080B0002AA5F8C62A705439C759127CA5C4602F66
+:1080C0009CB145EC23F25D52C555EC631D30062C86
+:1080D000832C5F0ABB8E9CEEBDEE19697B65E17057
+:1080E00075A2A8D69BF7BAFBFD7CEFF5EB56434D86
+:1080F000ECBFD42900F9BA6AB8A7033C580E003384
+:10810000F03FA459BA1BE06B7F8FBF56120D3AA8FF
+:1081100000BF931D3A3D515B82FC1F8CF14DE2D7AD
+:1081200055F9ECF9A04B302E3F4DF7260E95D0E7D0
+:108130006E80E5381809777851125D867456125DA5
+:108140009E42F770F96C7702FC99F4DD62DF1B70D8
+:108150007DA9946867BDE13553CA001A4F48FE8374
+:10816000018087AA6E7A00F76DA849BC51887616FF
+:10817000C7FD46661A7E3F21313D2BE20596E9E6B2
+:10818000EAC334804781FF7863922EE7215D2E5940
+:10819000738200A3F473EFF858A1BBB85E346F2A62
+:1081A0009FE316E783A7ECEEE6C30A7BFE1C363F8F
+:1081B000EEBD8BFD3756816E654E94BBCF91BB8D66
+:1081C000B4B33EFA6C3DDA67954C94BF9FE471BD41
+:1081D00041976B07A0BF36C64B2C7535C615382E98
+:1081E00036C5171A660957574FB1F74EFAAEB6D7CC
+:1081F0004DB63720CE8FDFC95F3513E6DBB8681385
+:1082000071525735AA431E8D880B5CE7B170DA2195
+:10821000F051FC6D5C9B2B0C1D79836930865301FA
+:10822000D7E64AA316FDF81838F215968E74D8359D
+:1082300026CF717E521A9B5F84F8F1019FBF3B5E8F
+:108240006E917F301E8CCF68F71D701E4BA1AB5214
+:10825000F2C2C635CBCB32CA0BC99A2F4DF4CFD35D
+:10826000769C3F96A03986FB0F56C337C334CEE1C8
+:10827000E34B948DE8B71FDA72CF39714E4FF2C3DA
+:10828000CCF138E34F1C8A04BB999F36E539766FF1
+:1082900034D6CDC3F939B048429CF4E9EBAD7DB397
+:1082A000687ED80D1AE6026CB0DEC67AB2C9F6CB8B
+:1082B0004BFA830993E52D4894673B180030EE276D
+:1082C000245346BB7650DCBFC0AEEF4DC48D99320F
+:1082D0005F57EE30DF9C385F4F990F4ADEDDCCB739
+:1082E000E3B22E256EF52971AB4DA15B1CDA12EAC3
+:1082F0009653CF36B5050F14A21EED2F4A7E926A13
+:10830000A88979A4A500FF12378CCC0AC26740293E
+:1083100044CE9BF1CD0915B1DB44F58BE1758BA5FE
+:10832000631CD6537E33FA61435F427889EC2F4059
+:10833000F97F8D3F62A998070FED7B4601A4DF8985
+:10834000B75A6E8CD7A6B25FBC41EBB9F76E4BAC97
+:1083500093EE80CFEE143B7A52683345FED92FA9B5
+:10836000E3FB52E67F3F857F28853E924277A5E674
+:10837000877FCD34AAF7FB2438085F9E2797EC78D7
+:10838000FE4E8E95A968FF47F1EF58FB0BF01CEBF2
+:10839000E438FF58EF309271AA00FFF9DB3C30E976
+:1083A0003C5026A94F1727C34951EAB9C5F9B51959
+:1083B0007FF9D520AEB7B5DBEBF7220E2FA78116DC
+:1083C00047DAFC83AC1D43A911C4692E9D6B6AC0BA
+:1083D00047FB5E3EB70C0EA23D3B06E4F7BDD9005D
+:1083E000AF3FE365763E7242B6BC2C7E7A6603EA06
+:1083F000DB66E37ADBB392E95D8C74A4751D2C66B1
+:10840000349BB7F55DEE9FAD31C90AE0BC6D96F2C5
+:10841000A784CA6D1C25B701E7B79E94AC38F25B00
+:108420008F88FC1D3191DE09873E9117D3E8FE53FA
+:10843000A2C8FE8EFEB948BF60FEEF79F79345AF44
+:1084400027C9036805E48F29A1ACBC2B0B89046DF7
+:10845000946AAFDCE233BEE0FC72C65BD1E145AFAB
+:10846000CF07C8043D3F44FEFD7E2E1E82009BDDEB
+:10847000A0C7C8AFEEF8D48DA877E7B9DC52C2C167
+:108480006B2E50CB7368BFBD36CEB8FC50D40058AD
+:10849000007023DAC6C6CA13CFC885E8AF9BD2FBEB
+:1084A0004FAFC2F9C31FBBB45E20B9081607941BB7
+:1084B0002AAB0A9490FC1E46033C69E38EE7F1EA7E
+:1084C00013A7E542A46EF45FCA20FDC19FEEA2731C
+:1084D0007CB76DF3A7119C84F1FB74C86D4190BE0D
+:1084E000201FE3B4DB6F030BB4FC0EE4BF765E0128
+:1084F000EA571CBF5DFF2E4694F6BB8DDEC1F556D4
+:10850000D9EBB51E91C1580670FA9F724F56125E94
+:10851000327C7E740B5CEF93D93E5755DF0BEB70CA
+:108520009FAB3DEBA701E6CD23CAB04743BDB45393
+:108530004DD93ADAF101CAC599BF2C99FAA2CA7A83
+:10854000584FF32AE36E08E0BC0FDC9A44F1BF7188
+:1085500019111CA4FC70D7539FF0C8AF659E57A794
+:10856000DDCFCF0F8EEB55536E9B61FB3712E2E7E9
+:10857000CB873DBF6A24F96B47153FE973E3A8C277
+:10858000E6B7235E5D88ABAB7D12C37BFBEF658DE9
+:108590008EE26B7D12E7232E55C2F9E38AEEF14D90
+:1085A000C4758D2387F824DC3BF86ED7AD35407653
+:1085B000D97856F1DF28F651532076C08FFA6FEF45
+:1085C000FBBFE13815BF6D84DB0CFCA5144A09B76D
+:1085D00023910DBE7892FD93E176280A0C6FCEF7B9
+:1085E000DC1341A910C6EB81590D4511D4BFD3034B
+:1085F000456E8AAB2B5D3B46FBABD98BA9B9B895D1
+:10860000C6C70E97FF2CE1A803CF03EA6F6E8482E2
+:10861000CCDFB75C5A1DD1302FAC4B383F5111D451
+:10862000280FE41A5724C6EB994AB81BB4FD185614
+:108630000F0DE6A2BD3F0F397D24305CEEF2737E54
+:108640009D9CC9FC3CD28C7EC675DD66F18FAAA8C4
+:10865000FE0D2860D17CFC62FB4F1A65F527E023F4
+:10866000F9F0800C07490F5D61FC00A87B290E1B07
+:10867000A86EE17EDE02170492FC9916488740D16D
+:1086800038FD0708FBA8EE74DAF6E2013C380FF576
+:108690006AB6F5CE28CA11E49B33B7B2F8676933DE
+:1086A0008475C1502EF3FD030C078DF42D8FFA5BFA
+:1086B0005ED73634233F691DA5EA935A32236CE313
+:1086C00000915C40E78E52C5D771E4C233D75C831A
+:1086D0006C66FFE53BE16441B55DDF8AA19870D22D
+:1086E00029F1FDCDA9601D63752002B4BE83879773
+:1086F00043128B436775808DF2328C1BE236A1C02A
+:10870000ECA52C7EFE5924DF9491F3E700C6E874B3
+:10871000E822BBAF35ADCA79622EF65BE7421F187F
+:108720006EC45FD3B29C97E720FDD6E94B9C5E9266
+:10873000B35C417AAF74C5A8457A30A4BF46F5B39F
+:10874000B3DAEF9C9F6C5DFC7E86BEFFC30AE36CD0
+:1087500008BFEFF4647649D847DCBC677836DD178C
+:108760001CF9C4A9C2598894711AF5D34A8806869F
+:10877000E3C9C65B21FD7CE80BBEEFC8C038E33E11
+:10878000BB5E7E2F3B80EB6E233FA15D5090C9F016
+:10879000F884EDD3A1C6F83D71F4DB8751C89B87FF
+:1087A000F91470197F243D07826FCEA6BAFB614F82
+:1087B0006736D5C38F5F92B57528FFA80C1CF7B735
+:1087C000E5F8BDF8BD7ECE825EC2E5D0F1A7667E3B
+:1087D0000BF5BD64E37E28C8FBE5A1E35E5B6ED3C9
+:1087E000515962E7CC65D277EC7C39BA81E9B5366C
+:1087F00013CF153C974FADE4F1F2BAC1CCCA612357
+:1088000064E377054799DD47AD317E369D43812D81
+:1088100005BC8F41E860DDBCDFC6F3FDEEF8698979
+:10882000F0A6F9DC646F233797F8A61BD771A9A0CF
+:10883000907DC5D0E3A7BA835AF78CE6B2FCD4E2A8
+:10884000986FBBB05FA0636217F98DE8E39265068D
+:10885000A94F50D879FFA15D3F52EBE84E18CCA646
+:10886000B8B6F56C61F9E3D4CDB17CF1BBFF5FEA3A
+:108870006576B55D2F97C2D2BB3CE7F3AA93FC5F48
+:1088800027B704DC64DFD4A252DEEFF07AD59AC6B3
+:10889000ED71E2B1EB2773F3D93950EE65FD5BABB7
+:1088A000AD0BF4E4B2F81D08CA407D41437F2104BA
+:1088B000F0D3B67E0902789EAEEBCF6574F667D32F
+:1088C00019DDF0D3FC6ACAF3B17EFDA70B187DED6C
+:1088D00085B7CA8C9271FF8FFC9EFB1F52EA279EC0
+:1088E000A63FAA42FE8376BD1C011E9F113D83C593
+:1088F000C7B173BF5DE77CE5625D9CA28B7531B744
+:108900005EAC7B53C362BDCB6F9E23F0A71B5F158C
+:10891000F8856DA5023D2B5229C87F654FB54007EC
+:10892000CDBF11E4E7763D20D0F3BB1F12E4171C46
+:10893000D92CF08BAD7681BFB06F97402F8A7D4FD9
+:10894000905FD2FFA4C05F1A3F28F0970D1C16E875
+:10895000E5833F16E4575EE815F815899F09FC5535
+:10896000577F29D0AB877F23C8DFFBD919810EC180
+:108970005B827C8DFAEF025DE7FFA3207F5FC1255C
+:1089800081BF36F091C0FF5AD1A702DDA0FDB7200C
+:108990001F5E00593AE647F74AE33BD588B766D7EA
+:1089A000A19FC4F1FBC8C025379D1BCAD725C82588
+:1089B000DC7F49FEA4E6DFDFA59C437F86CC6FB851
+:1089C000E87D09CB10CC9D3CFFC26AC043EF509BB1
+:1089D000CD372FB0FA449FA68DD7ADCD6A669C9D4A
+:1089E000935DCAD058FEA3FC843A66D7B762D8E735
+:1089F000BFA28ED7AFC9F4A7CCB9E2AC87FADE54D8
+:108A0000F01CC2FC9074B40DF356C2C3AF05EBA2C8
+:108A100074F2CDCF995ECF69AA3A97A45BFC64A7A4
+:108A200004866B7421E5E73A9028DF6212CBCFC948
+:108A3000D6F161FFEA4E8AC3145D057792FF72EBAF
+:108A4000FD023D355C20C8E7370704FE74A348E00B
+:108A500017B669023D2B522EC87F658F2ED041B3C9
+:108A60005E909FDB1516E8F9DDCD82FC822386C07F
+:108A70002FB6DA04FEC2BE88402F8AED11E497F4C7
+:108A80009B027F69BC4BE02F1BE816E8E583470497
+:108A9000F995172C815F91E813F8ABAEC6047AF50F
+:108AA00070BF207FEF6771810EC13941BE467D479F
+:108AB000A0EBFCFF21C8DF57F0BEC05F1BB826F05B
+:108AC0001FFD488B53FEC02B92762C4079F889C04D
+:108AD00057F2B0DFA6F72348D7E8DC4FEDB71D9C6F
+:108AE00035689F0BFB74B822EC1DB54386441AE22F
+:108AF000EF76F51CA70F575599CBB1BCAD87E7A909
+:108B0000EFF09912C31D1DC52D393613FB0076C435
+:108B1000A05E3ECA1324725C41935839D5A075E219
+:108B2000F78CF1BC9939BAECAFCF9B747AEFC4F3F0
+:108B3000B3BCC618A57AD21E3BBE86EE1B6D6A3743
+:108B4000CBEB3AB9C497C073EC7C1A7F1F4C5D6FB6
+:108B5000AD8A7E4CDAEF5C5AF7CCD23BD49DB5EAB5
+:108B600010931F5B57E1EB4A68CCAEA4F59FC67B20
+:108B7000901BAF82DD51CC33AC3387A37E463F1BC5
+:108B80002D60F40FA301361E8916B1F1C7518DF186
+:108B90007BA2E58C7E2EAA33DA8AD6B3B1371A6669
+:108BA000DF8F469B19FD02DEEF69ECC3FB3D8D3F75
+:108BB000C37B3CF15FC4FB3BD12F454D36C6A25D64
+:108BC000ECFB2FA3DD8C3E113DC2E87F8E5A6CEC8E
+:108BD0008FF6B1F137D118E39F8CF633FAD5689C44
+:108BE000D1F1E800A3CF440719FD7AF402A3DF888E
+:108BF00026D83810BDCAC6DF468719FFEDE8678C56
+:108C00001E72411BF5332B6A78BF0272A6CEEE4D61
+:108C1000D50B7A097FCEF7EDAB8C1535F43EEB81A1
+:108C20007EAA5B4F662C560CF6EE2ED6B9D4385C75
+:108C3000B7D757B0BF2EC3759519F7F47622FEF655
+:108C4000D2A51B71B53727D04B779190BDCF53E993
+:108C500060A6B17E95F7A5AD361E218FD7F1AD3652
+:108C6000945BED3C584E782C62787CFB6EEAB873CE
+:108C7000CFBD5E6134915D5B33231EDEC669F75064
+:108C80005FDCE0E5EF37C3E764AD3730F9BA3BBBF3
+:108C9000D76251BE03FFD56B33E97CACFF1FD920EF
+:108CA0003F9C57B29AE9FD628B6DEF961A97307E22
+:108CB000BB32BCB906C7D657BFCBCEC596C7E7FBFC
+:108CC000C8CFF7D3D31FE675130414F6F712D0CF2D
+:108CD00006E9DE88174BA23782C9C6072A8CED64E5
+:108CE000CF266CA0894E48F0C26E89ECE1F84FD5D2
+:108CF00063770D7F87DF5DE312C6C395E1DDB4CEF8
+:108D0000C395F77DC3859F7EB12AC0F46B84E1E7EC
+:108D1000488F9DB38D8B8573C7DF095A6090E90733
+:108D20004EDFA982736F67EF072D52BA46F7F6033D
+:108D300021FE6E63BE97661DC3ADDFB5EBDA484416
+:108D4000617868792FCB423021FDC412AA0B5FC72E
+:108D5000FB8AA774BC0EB620ED2AA5FDEA95A9B83A
+:108D60004E4BB9ACD153A9531F511E3C58CF3ACAF0
+:108D700083CC8E16BC68F0FB0FB077886F9EF4B280
+:108D8000FA77B6C2E826FBDA2B64D383F7BDF61C6C
+:108D9000AC12A8DA532E1E77F3B732ABCF6E3F7FFB
+:108DA000BFD8DA3365A91CE0F8685A0470C18E9701
+:108DB00013FFC7BA704CAA4F88AB1E8AE38D5FAF12
+:108DC0002CA2F8EF7CB5224071ECA4F5F3C6D727AE
+:108DD000BDC81FB2AFE4F9833C4ECC3FC315595612
+:108DE0002FEA795A863DC7BFA01E9EB1E376BE40EA
+:108DF00061EF619D769E39FC576CFD5EB171D67056
+:108E0000E6DCAC0E5CF7B10145A3F75D284B94247A
+:108E1000DFF7C7F0BAE7ADE9F392ECD8D9FFFE1A55
+:108E20009DDDF713250F64717529BEFBEDBC74F64B
+:108E300051A8FFA2C323CF3D34762F9B437EE2751A
+:108E4000DFC19DECC9329ECF4CB683E30D717F9A92
+:108E5000E13E7B0FC3FD48E4836F535227D085F476
+:108E60003E62FCA3DF43F8DA0C1A1B1F86301B5B43
+:108E7000111E14B76D60B1713B240E2C43F9B0F98B
+:108E8000ADD9849F9D305C5B807EDCD0B5F76C01F2
+:108E9000AAB2BEFB99BAE9A8F7833D4165068E4D9B
+:108EA000471FDF4F7F3EC2BCF937DAFFA11743FBF4
+:108EB000E9FD15F3E60ADD8B1AED7B3BE24E9711D7
+:108EC0005772B6AABB307E0F1FE6F5F182EDDFC305
+:108ED00095FA05C253CB931C67C3A7BC2C7E63795C
+:108EE00053BEFD62A18BFA3E607F0FBC79AAD8DA2F
+:108EF0008BFC76EA7BE5E43ED0398F791FB01DFB11
+:108F000000C2EB7585E3E23AE60DD5CFEB12AE5326
+:108F10003AB13F70FACA0E39C2FAE95B2E3445A65F
+:108F20007BE60F98BFDA546B31F905CFE111B21728
+:108F30001261768F6DCF57F93E538C434B699F9FDB
+:108F40004B2CAF92EA3B8C665011E2EB3EADF0F752
+:108F50009854BD53F5F17AC054A93F2E7FE373EACC
+:108F600027CC6A6E87F99FDC8E0ED9285821F33EF4
+:108F700085D6C573224E7DB2E2522DF64695B2FFDC
+:108F8000BE49F695FC7CFD81BFF077677316B0FA99
+:108F900092AA4FEAFEDE74AE9F73EE74C83C1E8E3A
+:108FA0003E85B5FC3D1366EBCCEE81607E911FD70C
+:108FB0006FF47C95F567AA6CCCA845FE3B69FCDD97
+:108FC000C8792772EEDD70BB7326FFFB509CF55706
+:108FD000CE3D0452DE5DC2AA5FA1B8343A7954AEE8
+:108FE000087934F62E5325DE67D6D3793097EE33E1
+:108FF000EF3A7E12EE33FF0BDF219D2A5021000055
+:1090000000000000000000001F8B080000000000AE
+:10901000000BBBC8C6C0F0A31E8139D851F9E8388F
+:10902000174D7E23337EF584F01AA0FEE540BC0880
+:1090300088E702F10C209E0CC47D40DC09C46B590A
+:1090400019185600F162209E07C43381780A10F780
+:109050000371172BC21C07A03F3CD9F0DBF590151C
+:1090600053CC9713C1DE4BC0EFA378F8E373DC0C4D
+:109070000C8778107C535E54F9F3DC08B6802065C9
+:1090800076C903F50300446FD3A5800300000000F8
+:1090900000000000000000001F8B0800000000001E
+:1090A000000BDD7D097855D5B9E8DAC3994F4E76C6
+:1090B00006C24908B03300613E04C480A81B8888FA
+:1090C000945E0F8A16ADB71E0625322522559EB531
+:1090D000CDCE0004418C80350AB5072A880ABD51DF
+:1090E00051B10DDE035A0D8A2D54B44EB5B1B63EC2
+:1090F000AC0A11EBD03E5BDFFFFF6BED9CBD77123E
+:10910000A0EDBDEFFBDE85DAC5DA7B4DFFB0FE6971
+:10911000FD6B1F5F7800932F64EC6BFC03E51A0F67
+:10912000DB278D66CCEF8FB5CF655087FFD804C69F
+:109130005663990FFF2565958D672CC0F81FA550C4
+:109140007ED71761EC32AFCED839F0209A4DED3D85
+:10915000E11A968047FAAD4AA27504B68C32EC3714
+:10916000103BC2F3A9F5FE37878C636C7B63B1ECCF
+:10917000837A0993A8FFB6A6E22083F6727DB4A095
+:1091800003CA87776517C8D04E5FEF654A114D292E
+:10919000B33CC68AFC7C1CC64C86F5818CD7B7379D
+:1091A0005E96C9C2505FBFFA1365541A2EAB2C35B8
+:1091B00065962AE36BFF9A613FF5CF1D561DC61FCA
+:1091C00087FFE883FF57C8C7F5F377CFFDD647EB96
+:1091D000FD4993CC7CACFB3A1EDE55FC6219AE1304
+:1091E000DE2B2CBD0E5C9F313EBDBE7F743D041F47
+:1091F000AE27D59FF0A774C1ADFF46CF0594693265
+:10920000BB5DA792E8707B6DF2BCD2418C15A83B88
+:1092100064402ABB5D4DFA355C87691C8D42FF0AAC
+:1092200066F5672C17EA93041D2795C926F60F9556
+:10923000417FDB7AAC7536D532660C013EA8F5531A
+:1092400099E69758340EE35784AF9FC900DFABBF50
+:109250005FD381486CC8F2EAF5B0FE61DAB40FF072
+:10926000F98BFDA7F9919EAC43FD7D07C050067FA9
+:10927000BF2E66AC51DD95A58D40D2C3731BDC01BA
+:109280009DB7B3D6318CD9EAF07E52D83B57867160
+:10929000BD038C681CC7ADB2BD87712769572E9678
+:1092A000001ED6691BB7388DCF476B356600210F7E
+:1092B000D69651792FD475ACFF4D99D31A4ED3570A
+:1092C00013FCBA7CB24CCC71D7317D3BB26A33FE11
+:1092D0001F8CF3AC071109A33EC4923B24EA5750FC
+:1092E00005F5CDB3F2CA892E95401758E76649FFB8
+:1092F00003F6372FF2EAD8EE5EB57916F6DB1CCF0F
+:10930000964DA93B7DF2E3B2D917D63FAC12F017C8
+:10931000A1FABB43609C831E66C4A15FF30D2C8938
+:10932000F8CDFF328FE963A19F01F887762F06EE13
+:10933000F9D007EFEF9AEED57D521ADF06FC45F81B
+:10934000270CD42E31E1FDA61B54562F75C7BB9BAD
+:109350002FCA9FB3BD473E89733EE9468FE99C1EE5
+:10936000DDE830F3F474B0CA3B6A93EC3DC0E5DA53
+:10937000DA28D16343AD4EE51AA40FF0DB7A6C9A7C
+:10938000DF7DFFC076AB42F9D21464558F211FC434
+:10939000CA7B6C67958CD5919C598B742BA0E51872
+:1093A00088F4E0B8AE7A2A580AF3E3FB89E23D88F4
+:1093B0008226A9EBBDC900BECC747B3304EDD70671
+:1093C00078FD2DF33EC32C4CD73F649B0C7352F7B2
+:1093D000F71B3C9D863286B1A7CD6B8C1101C7F877
+:1093E000068E6F5F9F7F52F7F13604F8FAFECEEEDD
+:1093F000A4FA1A09A05644190320A05F65058D4BF5
+:10940000F59DD909F3B909E9795E6709D3043EBF2F
+:1094100096C50F22FE9352F35459C2793BE6305859
+:10942000573BF6877133CBF83CEDE65AA3414DE349
+:10943000E515D668221C96FC5504BF28A6DF5422E9
+:1094400028BF77190AE048C9611ACA7716E37A413A
+:10945000D60CD6114ED343D1D4F7EDFCD5C517A207
+:109460007DEF74E4EDBAD6EF696E5060FD07F1153B
+:10947000D4A70CAEF8D524E073DF114F0CE70F2012
+:109480005E8135025F296C623636AA3114DC4743AF
+:10949000414642ED67B8E9802F82A5052C69933BD0
+:1094A0004CAD89C647A6C785F98E633B0B5F679AAB
+:1094B0005FED6D7ED520FCAC11F3BBE7DD1088CDF0
+:1094C00041B9366562C5A58CC61924D37E16FD9AAE
+:1094D000CFD765EC3752E27A3382E367A7E188E0C1
+:1094E0003C305F66058C6BC3AF351EE085E1785676
+:1094F0003FAB3DC02BC677E2C53D0EE02F1ACF38FB
+:109500001DFDBFE4F49FEAA2BF7196F4FF6F1AF746
+:1095100053E06194C32B267B9326879F215D2CF813
+:109520002D782DF8DC70AF918CDF4C2A12F64F7637
+:109530009A9E9F62BF3EE9F9BBF1118B5D8AF336BB
+:109540001FF5B0DB4F33AFD5DF3DEF8A97957C56E3
+:10955000DC7D5EF77ADDF3667F39941939A052908D
+:1095600077004FF5755ED257CD952C89F46F6EBF9D
+:1095700088EC948D323B84FC6AFEDAC376C0901B83
+:10958000519E92DD308EFA253358FE65237A97A7D7
+:109590001BC13E30498F425B289B253607E572F69A
+:1095A0002EAEC79A3DCD970CC6F12F92C7EC60F452
+:1095B000FCDDBEA02F9A03CDB3A6D99EE7607B7CCD
+:1095C0009E915C3B785CFA79C10DB981B9617AFFF3
+:1095D0002E8E67CD9F335D66A60DDE2C2F9B1BEF75
+:1095E000619DDF97645AE7D342BFDC2BF44B5650A2
+:1095F0009B8BF8D0EABDFA76C0C75D178D2F9867B0
+:10960000E3A31F8AFDD52CF4D3C13BF224E4B32C91
+:1096100083492AAC2F6B264857C0D7D39E585D2468
+:109620008BB11B2566D4C07AB28E375F8572D7ACFA
+:10963000DBC77CD0BFA012EA1AE8E9488ABDD00790
+:10964000EB8CE4F056E955A301F447F2E54D0DB873
+:109650008E157F845E30E504B559A921FCE7F6A894
+:10966000CF7EF247FF9C24C03961FDEA2397133374
+:10967000251DFC33F10F4E3E781AE11D827047A97B
+:109680004C48CCB1CF34FC27C0A1E13E1B45F6F7D6
+:109690006415F1F2218BA1BD3BC11F7BB30A59A117
+:1096A00092C51AF4EEEBD12A9DFB0DE0996A87E78B
+:1096B000BF0A8E6B99718FD4A7F7F1BAEB87C48F6D
+:1096C000B1FD04217FB32A934A227C3AB82BDE44B1
+:1096D000FB4DBB98C3DDDBF86E78D7097CC27C7B81
+:1096E000A473BACFF7DF850F18F7599267FFE2B876
+:1096F000597F70CBAB662157522A97F356DD6058DD
+:10970000F77A19F975A8F3C82FC43FA8A70A633FD1
+:1097100041F97654F2123ED42897DB97791347111A
+:109720002F6C2673F88F7E2DCE50AE790BCA321374
+:1097300068BF85737BD4FB4DB52DB3548FADEE61FF
+:10974000C24EE770788B593207E1FA6ABE7ED9C8FB
+:1097500074BB7C21F7ACFA7D5DFD9CEB8571EEBDA1
+:109760001EEA1E6DFC58D47B1FE0FA7B582FC0F117
+:10977000816493F3AA66325CF77D370CE6EB5FD029
+:1097800033FEF3FD5B66A93969BE244402FF658997
+:1097900071EF88B2662513EAE3C0BE063E2C29D4D9
+:1097A0000FAAC097F985A916F4C3D7328EE74DBE2C
+:1097B000C45F108F1ED934FD45C85F35347FA38048
+:1097C000EB22E523FFEFA1BEA1A23813E5D8405953
+:1097D00072E825ABDC04721AF1793BF873587EF11C
+:1097E000DB21B4FEDEF87D4BAD7F963AC8569FA9CB
+:1097F0004E477EDAB2A4FC682580BC2AB7B49C74BC
+:109800007595A4225C0189EFAB2C99CBCF4DDFBCC1
+:1098100099D609F8CB9271FDB91C6F8CC519DA572E
+:10982000F847B5E1A3C4300CF40B2D7C1403BA2423
+:109830009827733D8BA574C243810C70E56B350688
+:10984000E2C93F493FA8E8693C80E3D35402EDEF09
+:109850003C34A8FC76DB3EBE46E67A809572BB813E
+:10986000A931D29BBDC98F66C0D3080F914BC27579
+:10987000AE1175ABDD5B526238C2936B04497EE476
+:10988000C69312C275AFD07F56DCA351C0D53C251C
+:10989000487CD7D85FDB86F18CF1D67AB64A6E3E2B
+:1098A0001B2F9F93C68FC567B986919200CE9427D0
+:1098B0003111E157F4668DF64F3CA581C7CA564970
+:1098C000027E931DC1F1B2051D2C7ED7A2FAF6DBF4
+:1098D00061DE19822FB263AB6F44BF2DAB5425BF3D
+:1098E0002EBB632EF991DEB72F21BF139E93FF9AF3
+:1098F0003BDD24F1921FD52723BE1FF32466E0FA37
+:10990000B4312B52387416330C2F8C7BA7C76048A8
+:10991000377552C2C0B8C0A66F8E67736D7CF56D87
+:109920008417D70DEE77329CA6FB5D0A5FE71DE337
+:10993000B2030BC3D82E48782961E30C8C5F140363
+:10994000D969BF22FD19D1FF6A9CDF57D97C80CB32
+:10995000115D46BC00DFF7453CDDE9E98C62BF3BA9
+:10996000BFE99D93E4F838867CE997052E74F80BDF
+:10997000F8F1897AA9ECA175F9111F083F2A6F58EF
+:109980009367584D4A02F91A99CE6288463FE267BA
+:10999000541A3FCA0893617C2A33CE62063450A21F
+:1099A000DA81C11C3FCB083FAC26857456C3A6891B
+:1099B000FCB945ADF9DDF7018E2DED4ACCD46D7CB7
+:1099C000C862E46758782A5C02FBAD07FB3524E4E3
+:1099D000D90B52E256D926BFD7E783FCB0C5BB2CC2
+:1099E000F9CC46CCA6F6BEC254743ECCEB8F46C72B
+:1099F000D03E55358A6FACB7647E17DFD773FF183A
+:109A0000ED1DD8EFDE28972F81D204433DE6D79B8A
+:109A1000A9F415727EB4DE7B572AFA1F50BE8DE082
+:109A2000F26F758CC7BFBCFE14433A84814C68B793
+:109A3000C37688EDA019136C7606F2BBCC52B086C3
+:109A400047A0E4F18724CDEFD3838EB89877A5970C
+:109A50008F0F9625EED7FCB77D7CBF09FDF39614DA
+:109A6000DF42F26081D87F961C88CFE6FAE9581968
+:109A7000C1BB43C4CFBAEF770EF71730F611C49BC2
+:109A80009AA038E4CECDF38208C7CE96CB3213E14C
+:109A9000DEE523DABD293018B6813CC5724BAD46F0
+:109AA0006597BC1471A5AD422E58CF830ADF0FBF56
+:109AB000167272A73F1EA478DDB357CD180AA82CE2
+:109AC0003DA6C45026F4BBAB35EB74F3172E71C61C
+:109AD000119972CD69D7BBF2EDFC59CFD9DA3F2B82
+:109AE00067E4BE1F827F9CCBCEFD5A3973FF2F6A7D
+:109AF000A3B39EF3FCEB78D92AE211C186ABEA301E
+:109B00001EC1521792BC2C16DB34BF8991BF56BAC6
+:109B10008225C987F9EA6BFEBE2B0E6A84E7427D77
+:109B200010DFD36C67D3BCDB514EF47F556132F04C
+:109B3000D320B15FD9661E97F2C35F8C3F51680591
+:109B4000C62D59C092296857D2EC8C37E6B3F59FE1
+:109B5000A0DDD2DF151FCBC77D3F0ADF3BE35F856A
+:109B6000E0575694FFEB74F833D261F8FF7B3A6C00
+:109B7000515B039AAD7F3F89C5915FFB2DFD833417
+:109B8000CFC6AF0185EB0DB632CCDEB3C5F9FA49CD
+:109B9000298A3F6D5B224F4779BB05F0407186DC17
+:109BA0008E9F62972FDE59974FF655DEFB17A01C4C
+:109BB000CC53425CEF4D67DC5E604E3904FA2F4FA8
+:109BC000B1D909DB1A2F63DC6E67C7304EAA0B7A56
+:109BD0006FF9AA41F2021D07AD64B17AA8EB82DEEB
+:109BE000959B6B0E78E079F10A46F117663AE95FCA
+:109BF000BC80D37FD07ACE57FD573AE39C208FEBC1
+:109C0000BDB0DEBE60F6DE07B5D2CD4EFEE82BE479
+:109C10007F5F177FE8C00739C007A5CD89DB71FCDE
+:109C2000FC630AB7915DF30FD25B2F41FC94029E57
+:109C300092647FDAC65190BF62F5480F375FF645F0
+:109C4000BE1CD57DDE7F95EFA62ACEFDFF190BCF7A
+:109C5000DB05D5E4AADD2F0EA656866CD74F16DF9E
+:109C600085997109D289C57BB6DBD3F2D514E71883
+:109C700085329D030998262F8F06F15C60AB577BD8
+:109C800011CF57CCD71486FA61EBF28202FBFAB7F8
+:109C900079B8DCDC16E0E53C85CBCB84E2A17281AF
+:109CA000A86F8DF078706FF2DDF263067F1966A9F8
+:109CB000B1F6BAD75557592AC75E8F50BDB13F2369
+:109CC0007F461FC04CBBBE5D93D14A760F5A12141B
+:109CD000B712F2E9D92C7EEED1182ECF64F45E973C
+:109CE000EDE7388DE1E2BECC06A715EFEE0D8FEE65
+:109CF00078B7EE35A259D0BF316B5A746E2EC6C9F3
+:109D0000B87EFF81D02B0ACE09C26E95F2445D7DEC
+:109D100029D859CCA855FAF07EB85E3D1BEC3346E5
+:109D2000EDC81E73CFB748098A733DF5AFCEF87DF5
+:109D300058233925F8F57A257107F2813985A5D0A0
+:109D40004E37C19D6C40BEAEA911F63DA73FB4DBB6
+:109D500088F3433B13EDAAAE76891AD6154FE4ED8E
+:109D6000EE11ED0C47BB78B7765BC5BCCC31AFD1FB
+:109D70006DDE6D62BC14B38F17EB36DE4E319EC9BB
+:109D8000ECE3E9DDC67BC45A9FA39DD6AD5DAB680D
+:109D9000C71CF332E7BC5DEFF3BCE27D82ECC1D5BA
+:109DA000F9D7FBC94F3ADEDFC1576E3A1DCCE77CCD
+:109DB000F65CFEB426E4839B0E79E89CF240BE93E9
+:109DC000FFACF60DB5AC62C920E43793CE0B1BC2D5
+:109DD000DB691EEB7957BBF076ADE7E71B7B69BF0C
+:109DE00051B4F79F968F1B908F81DF1A449CD1FD51
+:109DF0007EBCCAF7F39A3299FC4CF7FBC9E23DD816
+:109E000069E4BF05CACCF346D8E4E4FF2F7096ABF3
+:109E10005C9FAE295BDE3C055C8ECF1AFE5A877EC6
+:109E20007D53697D1CEBAF9A7FADAB2CFA9F076722
+:109E3000B61AA8B7C3F93316A8AF94FEE7C139BA6A
+:109E4000B1AF03CE1F9B7D4F0BE76AE1BFBBC79D40
+:109E5000A8F238C12A4F82FCDAD5F95746513FAEF5
+:109E600016E78471F5CDBABA3036499CAF62BB3E75
+:109E7000961FA3937E39533FDF50358EFBACA9D498
+:109E8000B9DF5E177AC42ADF40E30DC6F70F5279B7
+:109E9000B244BE373948F027C6DD3E07C79EF4BC42
+:109EA000802F4775D66358B7ED5BF807E9158CC36B
+:109EB0007E5DD25DAF6C1C2AF4ED305E5AEBBA3D8C
+:109EC000C394EDFA36CBD2B7970C0EA0BC9B5A5F69
+:109ED000764929C6590E2B8CEC3F97DE9D5C3FBD21
+:109EE0001DF32736B67BC4FBA843BEAEABE5F90E27
+:109EF0002037FB32E20B9E2760D92F5DF3650CBE45
+:109F0000A414F0700AEC3C7BBCB851E8E946A1A768
+:109F1000DDF4FC9BE09347601ECC3BD8097C87E5D1
+:109F20007D504F083B1DCBFF003B3D01EBD85F1B35
+:109F3000A5FA815A9DCA87603D58DE591BA3F7FFD9
+:109F4000595B41F535C2CE2FD82D1B48C7B5C2DEAF
+:109F5000BFBF964DC0F8DD1DB57E2A1B6AB5091836
+:109F6000F7DB531BA5FA3DB53AD51FA82DA3FAD6AA
+:109F7000DA18D5EFAEADA0FA24E9B22615CF2DAA96
+:109F800018D9F50F9B83B7A3C955B45B25BBA1A80E
+:109F900011F4E0B8F4730BCE49D2943B901F47B74D
+:109FA000CAD46E741B28BC9EDB6DC4F1CF6FE5E391
+:109FB0009DFF6796B2CF636B770FB69BDCC2E14320
+:109FC0003D20F53CDE569C77680B1F6FE803604729
+:109FD000F43CDE361C2F732B5F5FE624B04B7A6EA9
+:109FE000B713C7BB702B1FEFC2AF58AA97791FC119
+:109FF000F142D9B1B971F2575A0F60BBECE95A3648
+:10A00000C6214339B11BF9735DC6B891AF903F0FBC
+:10A01000637BE2673655C6388D2E9E637B7ADED130
+:10A0200080ED03A5621C2F1F7FC325DC6EC8AAD458
+:10A03000B6FB611D3B443D7BBABE0DEB211F9F2F3C
+:10A0400032A08649B0DFB20A354982FA20A8CB5047
+:10A050000F7B755A5FCE0C266F87AE1B8A4D26C1CB
+:10A060003ECED279BB1D5097A11EF6E912AE2BE76A
+:10A070001BD00EF83E32A499DADD29CED3060DD1DD
+:10A0800026D3FA2A75C9AFA7CFD7B24BA11FAC7F91
+:10A090006065C764DCFA8B3CCCB802DEDF792397BD
+:10A0A0003FAFA8D553308F20439C87499EB6297572
+:10A0B00060A7860A78FC2AD42FF67A02E5CC682FAE
+:10A0C0009D03860B621D7824C94605C7E03965B833
+:10A0D0005FEC7812D6C5C67AA99E092694960DFB28
+:10A0E00038F370D9DC1EF69DBBFCF4F0548A178659
+:10A0F00047C8CCE841DF58A536C9791E1B9D5E5381
+:10A10000A7823CAF4078A07E2FC23391B18FD5EFAC
+:10A110004DC17C8CD2E9BC3E70D5AE2975202A4356
+:10A1200003001EC06768602A7F61AE0D9E01A9A270
+:10A1300035B9367806A6863E382E0D4F3EC283715D
+:10A14000859B383C9FAA465FAD07B8DCEB2F58E0F3
+:10A150003CCFD1BD7A3ECA7F65BA773BBABE4A9240
+:10A16000AF6FB567443DFA050DE7335502E4350896
+:10A17000FF2AD3CF9A108F881F3C477847D85B5D62
+:10A1800074D9EB357322BDE335D48FD5F076FE77E5
+:10A19000B15DB880C31FDE1B34737AC8CBEB82037A
+:10A1A000FB51BBF0BBF6F1DDF075A787518FF4983A
+:10A1B000B5EA4EF96EA8F715F80749366572697762
+:10A1C000FA6CBC0EE01D0DA580371FE12DE7F8CD20
+:10A1D00086F93FB7E0B5E836DB7BDA758706F275BE
+:10A1E000876603BCA390AE1C4FE1D9C1D3E2293CE2
+:10A1F00090E3293C3BFCAE7DFCBF6190BDCF99E96B
+:10A20000DA20E06810FE71BE7A0638569C816E1620
+:10A210001C2B04DD2C38569C816E161C2B9C743B29
+:10A220005B38EE1270DC95C1ED9FFCB0E0BFDEE064
+:10A23000987396F498E3A2C79CB3A4C79C7F921E20
+:10A24000D63E12F4C854391CD638DDF6513F233AB5
+:10A25000D721DF0CBDCE26DFDEC179CFC17D619471
+:10A260006DB3C9393587CB83C6F339DE1A33C47C65
+:10A27000614EFFDEE7EBB86FB163BE8EEDEB7A9C0B
+:10A28000AFE3E1476CF38DFA399FEF4C7180D96AE7
+:10A29000628347C40114BBBF5B9374F8BBD06E9359
+:10A2A00068672A76FF399174F8CFD0AEC523FC6C6D
+:10A2B00047BB78B7763F12ED98635EA3DBBCDB4506
+:10A2C000BB946C1F2FD66DBC07453B53B68FA77749
+:10A2D0001B6FB780C370B4D3BAB57B54B4638E79A7
+:10A2E00099735EC66EA4F8F6775DE732EE323BEE08
+:10A2F00075C4FBB44A2F9DA358759FEE7CAF32DB2B
+:10A30000FBA2F47CD67819E25C8925E23AAE7B7533
+:10A3100046E2753C02FBD5AAF7A6E462FE371ECCE6
+:10A32000827EFE95E74FF514A71FC7CF7954B67C00
+:10A3300020EA5F5F4C65C9229EAF8578F097AA142A
+:10A34000575FE5315212C1C9E3687E3DC6E3B8A24A
+:10A350003F10D271EE6595D6FAD4A897E26C6AB434
+:10A36000E9082F55CA7366CDDDCE4BDF46FCFA589F
+:10A370001C0F0DBBCE4BAD797AC3A3ED3CBE0CF3E5
+:10A38000796E61C118E603DC2C27DE47FAAFAC5CBE
+:10A39000C9704B7C7151159D3347598D84406A7D3E
+:10A3A000855D32DF1FC3FDA14D9D447E55431FA730
+:10A3B000FF36C4CBEDFCCF3D0AC1AF85B85C627EF1
+:10A3C000337F960DEE2CD10EDEDF88783F67B5FC2B
+:10A3D0006C5314EA996C8C0476D3A6ACC0D4E90013
+:10A3E000875622FA17F6D2BF843D8AED8779BF3EA1
+:10A3F000A862FB818CF4DE98D5050D26E0431BC2D4
+:10A40000E51B1BA76F6B84F5B7FC7BDE18CC53CE26
+:10A41000F9B79545985FD535CE704EEFB1D80FE7B7
+:10A420004B803D3E3E9D8FB7C997087AF1BC6DBA0F
+:10A430009942BC28612B0FC1A038A4D9C74BE77C37
+:10A440006E7C678AF157CDF553DC2C3ACF9B44FBE9
+:10A45000F987B271018E07F3245DF3F43D9B792EE9
+:10A46000524664FEDE86F762AF33EF61B5C873E82B
+:10A470008D0FD60CB8353F41F06BD6FA488E58EBAD
+:10A480002B13CF59D8CCA7FDAA4199916EDF3CF58B
+:10A490000712F63F29254679295E9A50EDF98BDEA1
+:10A4A000708D89EBB7DA3700FC926D7CEB398BF25B
+:10A4B000F1BBEAD3795D157CAD4DBD86E2176A2507
+:10A4C000CFAB61739CF929AA56D395678178EB9E2F
+:10A4D0006751A8519C9F7179DD15777C27906C801E
+:10A4E000FDBAD21F198546F417015EDEA234B74BC0
+:10A4F000D0EE0BB9398EC058F73CFCFEB8C10F61E5
+:10A50000F87CEE7EEE71A1DDB97CFE9AD158AE2DBD
+:10A5100085F14A709C1AF2A325354E72A1EB1C59A5
+:10A520009C4FAB426679FD097F11C6B7C1CFC67398
+:10A5300073A5790CC571BBCE93C1C6A3FC80287BE3
+:10A5400040E4F3303B1FF94B9DE7239EC2A0435EDE
+:10A55000B239A684F35972D73A6F56C3B019097F3E
+:10A560008690E75CAEE2143C5EF13D87BC56C32C9E
+:10A570001588207CE5CC7E7E61C95F94855CFE7E7B
+:10A58000EFACE47CB7F9663BD779D6FDC2AAFEBE34
+:10A59000EDBCAEF77E2A7BDF760ED5E86544EFC5CD
+:10A5A0007B3EBBDF04BA7DF4D887F79B8087257F8D
+:10A5B000FFF4FEEFA17DF04C4043F957FDF01FEF93
+:10A5C000BF15E8F1F13E9F8CFEDFA2873F78E77B65
+:10A5D00050FFFCE921D91832BA57ECC7138FFE257A
+:10A5E0004F877156ECBF88E22A2B9E98EA38FF709D
+:10A5F00097276A793E697A7D495A8FBE4FC24330A8
+:10A60000C6DA44C98CB004F85C86FF84F99EDDABE1
+:10A61000B000ACEFE3D77D491FE0BB1A9EAD04BB91
+:10A620006859EB523A1FC4FA6D60972DDBBD86CE98
+:10A63000D3AAF7791CE76CC0B9FDE42896A97E98E7
+:10A64000C2B36CEFE5979E3F0E4B0FE58154B3CE3E
+:10A65000D5E84FB9FBE1FC5FC2B8D5C794B9DED1EC
+:10A66000DDDF57B37826EAC5EADD6BF9BCAE73BC13
+:10A670008FF11F13BA9FCF3DE5759E0B7FFED0551E
+:10A6800099297CB937A747FD669DCF2D7DE28AD3F6
+:10A690009E039E10F1A233E1573B5F8EF71487A70C
+:10A6A0009B197D304F96DB9F774E92F331054EAB71
+:10A6B000E3E750DA942FDB310F2BF950F618E4035F
+:10A6C000EB1C2ECC847C13E78A6EF9F1C3FE6C2B55
+:10A6D0009677E74339BABB3CF98537F126E90B9702
+:10A6E0005CF9A124DA65F1FB38203FFC41A0FBDDD9
+:10A6F00052677B093E9F2593BE86E74DC16C5BFB8D
+:10A7000009E2FE8E61E8DA78BE6FB87C8347B0DF7D
+:10A710003C4CFC19163351A87841EE91FC42BB0623
+:10A72000CA206BA5F2CFDE62EE27B023548FCC3A5D
+:10A7300085378918DDC8182F408671FBF8C35C7E09
+:10A74000CF563FB2DBD301B695EC69ECF2B5952F4D
+:10A750009877E67EB8DE7E98BF2FEEADE55AEB0522
+:10A76000B985F5FC2E783486F0F5136FFB3293EC47
+:10A77000990230D370BDFD5907D507E212A02C62B3
+:10A78000893A86F2CA8853FE5B80BD4DFA4336652E
+:10A79000E9EBE1697AF9FC11334479A5DC8EF20A20
+:10A7A0003BCAA2AB2FBC9AF2296E918D3712DCBE48
+:10A7B000CAF60150DE776E3997E387D36FB3F09B0B
+:10A7C000366738EDA8FE3EEEC758E5E62C41B72BBC
+:10A7D00004DDD4B834CB96C747F82AC0D8EA8EA98E
+:10A7E00064BFA87CFDEEE7D67C682FCEE5764E8769
+:10A7F00064CBD71BEDE3716FB043CA308FDBA73555
+:10A80000632679975E45BBA3E3347126CBEE58539C
+:10A810009BA0F23C0C129F63B34F85BDA30AFAC004
+:10A820003CE7FC6BF3684C1DC4F906F5D55B52E2BE
+:10A83000421CCF8FF9A511B4BF797E9422F2C32CAC
+:10A840003FD51AE7121F97D35669E551F906AC3C7C
+:10A850008EFE67F3E4A8D8C771B23F678876805F41
+:10A86000B253EE9684BF24F9C57E62BA9697DE4F46
+:10A870000A987D9457078063E943FE5690AF92543F
+:10A8800086709F001F2EF615139E3258475A89C3B3
+:10A89000FCABCFD79298BFA802C2946C2A53585AE7
+:10A8A000FC82CF3DD93C8E1F81F23A5F36F723B050
+:10A8B0005E8E76663C81F800BEAF93695C43C1FD55
+:10A8C0009127D69767EDAF39CEFDD5C597594E7C08
+:10A8D0002D12FCB858F009CE8F72A5FB3EEEE65F54
+:10A8E0002CF7F5E05F20E6108F0D19AB8B904EDA58
+:10A8F00068F6891CC3E707A71E8E92FDFE28D61BAB
+:10A900001AFF93FB0363393FDFEA7B96F8593B5705
+:10A91000F807154EFFA0C9C7CF8F4CC17F6C92B00E
+:10A920002BB51AB25BC1FEBECB47EF855C36B87D56
+:10A93000DB55AFE4EDBBEA23F8FB7FC22EADC37954
+:10A94000CE64975AFABCA84B8E39FDE22291A77AC1
+:10A9500091122639E05DC9EFB3E8853C8FB5A8B008
+:10A960009EF25A718321DF14AC54E9DE0DBCA77C42
+:10A9700056ABBFDEE8F49BFD0B9C7E7381C8031BC6
+:10A98000C06CCF615105220FACC0ED578BBC1B2BA7
+:10A990002FDEBD4FDD7AFD31DF3F9777F70BC9D84A
+:10A9A000E7237F84E7DD346439F351D2FAD9247A7E
+:10A9B000FDA3F679C3E431AFE7029FF579FAF7C456
+:10A9C0006707AEC8A3F39DFBC23C9FAA2583DF1394
+:10A9D00077EF6F906B3FC67B3EFD5682FA207ED6A6
+:10A9E000E8FE7348BC9712CFFF4542BA68469D9473
+:10A9F00097967BAC9CF39117E9ACA05E4D52BD4B92
+:10AA00008FB24E2A15AD3985A6E4C19553B2F01E1A
+:10AA10004E88AD77EC338B1F4EAD6064F7A96C7830
+:10AA200026D6A32B549E67651A47A27969BEB2F851
+:10AA3000200BC4923DDF3667BABFCBF7C07A9FB810
+:10AA4000E6A8F79D1375B4CF4F805D877034727B95
+:10AA50000ED38B797C2C4EFC175D02B82BEA9E4FEF
+:10AA600018157964F90B522497FBD538F3BDA2224F
+:10AA7000DF2BEAEAE7E6A3FFE313F621A877E42356
+:10AA8000C0432CC5CF25E91E8BDAE123BC14005E40
+:10AA9000100FA718A77FFFB92C691675C78BC5675C
+:10AAA000F0BF580AD63F00C649C1735FD489A7805A
+:10AAB000EEC453A8CC89A78C98134F16BE332B74C1
+:10AAC000473B0B6FD6BDF0DEF05458D55A87F0FCEB
+:10AAD000B378D2FD4E3C7DC6DA0EE0BBFBC4770FE7
+:10AAE00090607E9BBDA4A82949D2D3F8C8AF02FECE
+:10AAF0008575DCDF0BFFF7CF653A1E95B31119E4BE
+:10AB0000FF47053EA5959CEF7BB31BDD7C0EDC5A11
+:10AB100087837AF05A4F09F2F9DB82CFDF636877D7
+:10AB200079D0DE1A8525974FFE5C839266D5308FEB
+:10AB300097819CBDD08F72BE5076E457FAC47D1BBE
+:10AB40004B2E282A1E44623D45F275886887763070
+:10AB5000B3C13504F5E228D44B1C6E292CF6F1560E
+:10AB6000D09336BFD2D207670B27D36264A7F850C1
+:10AB70005F86D2FB7860973D691C43BEB4F27B07C9
+:10AB80009A26D1D9CAEBD56F03BB153BB9F27B4BE3
+:10AB9000CC38F947C5EB9D7C5228E4F68015CE7C75
+:10ABA000CF4221E70B5D79BDFDF5D659B44F6E93C9
+:10ABB000D15266FD6EE3DF5918B082690B6CFDFB64
+:10ABC0002522DA0258778188A3BAF9AEDAEF94F336
+:10ABD00037CD9A4DF2E2C7B76D0FF624EFB7D4FA2E
+:10ABE000B50500F48EDA2895BB6A352A8B5B8E1882
+:10ABF0000158CFE0468E8FA239A9A235502F32FDE1
+:10AC0000313B9F8659E2077EA06FF2C6ABA7A03FFB
+:10AC10005EDA98988CEAE5DF14A3169FB32A1E1714
+:10AC20001DBCB2505B3016F36707D0FADD7AA3DFA4
+:10AC3000D2BD476BA1E9F6DB80AF01B6815FFA0CAC
+:10AC4000B47F302716E1D4CD9484E78377F9B91D1A
+:10AC500078B93FBE1EC72FAE6153088D55D9348FCA
+:10AC6000859FDEF49395170FF31D42FDA166653BAA
+:10AC7000EE296C1734D9E1E7768C1527EAB27F9B71
+:10AC8000ACFB06BA4CF7459A8BEAFDF6F890B86F24
+:10AC900020331E07BA05EF1B4878B93EF100ED13CB
+:10ACA000CD160F2A4EC77FFA2D2D0DA25CDEEE3792
+:10ACB000E520EAB5EF327000191B9A04FADBF90AB5
+:10ACC000FEABC8C63C830EB2A72C780BFD61C2EF69
+:10ACD000E5FE442BE205F185E375E147E4BB0F1483
+:10ACE000FC5D761B23B95CDC0C0A10F8AFACA9B391
+:10ACF0000EE9374DC8F3ED429EC3CA67CEB5C9EB26
+:10AD0000ED09231BCF852DF96AC9531073420FE952
+:10AD1000E4670FBDCDC9F7C5426E96BAE466B1903F
+:10AD2000B7C5AEE743935A8F7C6FC1E9E6FB5F5A24
+:10AD3000F2B62FCBC738D4676C52DF8BF4345F5830
+:10AD400079F36EFBC61D8FB0C61F9372CE2FA92656
+:10AD5000C5913D51A6217FB6F4B1E4B2D38FEFB2D5
+:10AD60003B620913EFB5B2794CC3B877746682F2CF
+:10AD700050A378BF07D7758C9F2BACF5F27EB2DF5E
+:10AD800094300FDC5F78E47CE4C70FFC615ACF6538
+:10AD9000DEF80748CF9C993C6E9983725A39BDFC06
+:10ADA0003395B4FC6BF4274E617F4B0EEA094D0ED0
+:10ADB000F720872DB9EB96B32197BCF4A989D43C31
+:10ADC000BD3BDC783BD97EBF6D4D7F21BF0BB91EEB
+:10ADD000DBB24415E7E4AB2A8D52C6D65DF168B408
+:10ADE0000F5D8A6529AD02EA9748F47ED8DA1F35EF
+:10ADF000A27FB16E16AF5704EE69C4F3847557494C
+:10AE0000E47F9C27DE03A4B45F3D7E0B7F35D7161D
+:10AE1000E1795021B707D7149EFE9E4203C6A38650
+:10AE2000A4DB296A8CEE0F5972C0E78A7BAA61679E
+:10AE30005C575DC2EF0B5AF2415DC2CF8BD68DBC21
+:10AE4000BE1DD781F163A4A3D75F43F9DABEE61B29
+:10AE5000295FD92D27FC424EDC2CEE25819C9003E6
+:10AE6000A82F3567DCD89213322A58783F785C0DCA
+:10AE7000C58B7D7A42D6C3E9B88C2567FD6A9CC52F
+:10AE8000E0B9677A0DC3F7BE9971CA4BF289FB65C9
+:10AE9000B23F7600F9D39F7B2446F2CFC58F1302D1
+:10AEA00016FF191302508EC279A19C14B0E26931C9
+:10AEB00089C7A9797E71A33F7E01B6D30BB57A8984
+:10AEC0009D3D7FD19FF122EE85E77A9AC14E17F71B
+:10AED000B2F83A13FDF592EEFCB9C16B645D0470F3
+:10AEE00035FCD213C3FCA133F9233FAA05F9EA4983
+:10AEF000EB414BFF59FAF0FB8122EBBB07E4B710A3
+:10AF00001FC3F8EBDF1E9EA418BBE08FF50BD874AF
+:10AF10007E0F93F3A54FF8985FF49F17F4022A6F02
+:10AF20000B288437EBFE8CC567C15EF2AC2DFEB4F6
+:10AF3000DA5BFCE96E77B67CE9F5279A8A01EE21A7
+:10AF4000E25C6348F38D07033DE82D6B5CB93B5F22
+:10AF5000DE867CD99BFE7ADD6F7C1FE9BFA13C5663
+:10AF600015EF619D4B823C6EB165C9E6800E78BAE3
+:10AF700017F165DBC7C110C7C317439713BEB60BE4
+:10AF80007C3DB8D589AFE819F065B5FF2FC0971F94
+:10AF9000BF0B1116F8EAED5EE169F0B5FD74F8BA81
+:10AFA0003DBEBDA918CF1513726C908EDF6792530A
+:10AFB0001742FDDE2A7937DEE3DC1CDFEE1F847CDE
+:10AFC000D672B03004EFEF0966F07B7B5AAA1DDB26
+:10AFD00099A5327DDF692DB023EA95352DF24F4CCE
+:10AFE0001B3FEE2CE4F7A3D614CE0BCEB7E161677E
+:10AFF000CBC1A85D2EEE74DD13B4CAF941C971AEA0
+:10B0000079DF027ECF2A3FC19278DFAD52DC6B0A36
+:10B01000E4F27848C0E0F521617ECFE9B931ABE9CF
+:10B02000BB0E6B0B7978DFB22B5A5C7685E5AF07E8
+:10B030004BF9F79E5A12FC7B179EF3B9FD1312F6DB
+:10B0400037BCA7784A7084D3CE5684FDE0DBEA7A19
+:10B050002EEC0D8FCBAEB0DA2B67F0DFB22A3B2897
+:10B060006EF44640D8D37DD940B42BEE8BCB044749
+:10B070003EC0813267FD75CD12DA83F95F2906DFA4
+:10B08000FFCDD1AB47A6ED8B4F0241C2E37A11D77A
+:10B090001BF31C5330941299A4517CD3C2EFC90006
+:10B0A0008FEFAD177962E71C33948CD3B51371C859
+:10B0B000097F3095480FEDF604C57D6F353507E9FA
+:10B0C000B6768C57C378E67A89CB47F3658FE06311
+:10B0D0004674DD799DB60DE3568FB517AFA3ABB5BA
+:10B0E00009BD1CC77B0CF44B71B87739F97890AF68
+:10B0F00067F0F498C1BF43678D97DACDCF4753D13E
+:10B100006B001FCF04B93E792C08F281F09428B06F
+:10B11000C70DFF5DACD7C2D3937A62DD48D457B078
+:10B120000E1C26BBB086617EA735DF63857CBEC75B
+:10B130005E97C92ECB8FBDB61BF587359E35DF9345
+:10B14000C19EE5D1B5421E59F8FE999E5C37CA36BC
+:10B150009F6FBA733EDF02980FEAF9C765CA2BEEFC
+:10B160006DBE9FF532DF5C0B3E41B767F48E75A371
+:10B17000619C20CE87FC8FF3857B98EFCB8D528628
+:10B180006D7FEE17F33C63E1514D145C669343A36E
+:10B19000C4BE7D10E4C77C1877EDA0D501E4E39D23
+:10B1A0005292E4993946A6EFEEACDF7A2A85794EC1
+:10B1B0000F1A8CA2BE5915E664F4D79705B385DC47
+:10B1C0009D42FD24B5B90EF7A3D2C2B85D857E7944
+:10B1D00026EBE1FCAA99EC890133F9F79C2CBB2FF3
+:10B1E000DA52F3E25094132B65FA7E0D03375A1DA1
+:10B1F0009F8E7BB478C478E2FCC9B217F2851D7DBE
+:10B200001ABB21C6ACF325AAF3F3282B0EC2CA0D34
+:10B210008A6758F17F2BCE67C5FDAD787F264B4DF1
+:10B22000B69F43953083BE673848C4458A0C7D0A73
+:10B23000C6CB07B724A6209F65AF60F47D489FB0BA
+:10B24000C343253FCAEA8A0B9E07F305BBEE2114D0
+:10B25000A0BD9013ECBA8740F522D77B35C1F58F9E
+:10B26000BA80CB3776B85BBED1A2601FCA83E071CB
+:10B270001711DF7E4AD8619BE31B0328CFFFE2371B
+:10B28000EA50FFD6093B0DECFEE5D88FCD06BAA0FB
+:10B29000DF0E6DD00F51C24CFE47E89AA623E3F2B1
+:10B2A0007E25F717DDF4EA8DAE16FD2C7AFEA37429
+:10B2B000C44F4A29E8EF603C89EC42F3B4719E42E6
+:10B2C000B593CE177516237A96B238D1B3C0AFC9ED
+:10B2D00048C7E24ABD2E80F4147AB33FE82BD49BD2
+:10B2E000F7C7971311DDF454CB047DE23C1EC38EE7
+:10B2F000488E3817D0E7FEE039DDE9737B7C4A00E1
+:10B30000F5F7CE98DC8AFBDBADB799D63C1DF1B9D9
+:10B31000B3B09CCE0B5ACA3606D00E00BD4D768017
+:10B320005925D37D97B3D0DFE417CDBFFD2DF28B28
+:10B33000D667897B8283BCC91D45A87F746EB777A9
+:10B340001E999A998BF150AE27D67B52D1D8086CB2
+:10B350009F9A330FE5C28FB85C7830EE960B49FFA9
+:10B360007C2452308B9F876EADBF84FC3FD524FB7D
+:10B37000DF9AFFDCE0B9ABC82F0BA728CF6EFDAC7E
+:10B38000E5F43D034B8EB8DB9DDCFF9BFE98E7F1B7
+:10B39000DBEB3ECD80CDC87EA77666E07A8EDFF609
+:10B3A0004A8601EF7F7B9B42F783BE23E25CD7D6C0
+:10B3B000FE6D3CDE0F7F45C8C79121E325E2EF9586
+:10B3C0007D88E96E482A18D4E57C05FF2DDE15C27C
+:10B3D0004DDF555FDA9AE3A85BF1A0A53E7E8EB5FE
+:10B3E00078F7016F3F80FB865D59140F3A2EBEDF60
+:10B3F000767C6FFF6D18B70E8464316FFC2D9C173F
+:10B40000D78374F85D9B8FA5480E1FF170FD67CC44
+:10B41000C4F38684E00FF7BA9E7F2644E35E77B7D5
+:10B420004276D35CC0E54A10B989AAC5144F71AF02
+:10B43000FBBADFB63E5F00EBBA6EAD44DFF1C0F69B
+:10B44000B7819F9758B986E2886EB8E69ACE3C904D
+:10B45000F9ADB3283E396F85447A79DE5689F6EF27
+:10B46000FC2667BBC7DAA77A917FAF6B763E5FD8C1
+:10B47000B68EE659E88A57BAEDA5BF07859D349E7A
+:10B480009D8B76D2A9F6CB28EED89BFF6DD947C706
+:10B49000C16EC70B4D7FAAF553F951AD46E54B413F
+:10B4A000CEB78BF71D789E64837A643CF2D563ED4A
+:10B4B000EF85AE8657CBA3DC5EBF60DBA70D4F32B6
+:10B4C0008AF7285C7E18243FAE11F8BF90F9F5305A
+:10B4D000AC738788C38DFD12EA36F84E354BE4B75E
+:10B4E000C1EED7306FE71A8477148ECFEDF46BF08E
+:10B4F0003BB9A781BB7FC8196FFD57E1EEADDF52A5
+:10B5000085E753BA9F5BFBE125615F34ECBF671AA7
+:10B51000F2CB89BB243A3F3BE149AEA6FADD52ACFF
+:10B520004EA7651F43796BF1A79BFFC0CFF5E2BE25
+:10B53000EEE2B3B63B081F161FC0BE898A7CA5A8E1
+:10B540005CD103BFB9F8CACD4F273C1D03709FBB28
+:10B55000F9E9442F7EC898103F9F5FA01BD3308E1F
+:10B56000721D8B533E14D0F9D5FF4A38ACEF2795A6
+:10B57000F39814E6751995B04F1FFB8AFB37F57BDE
+:10B580004B36A15D3CE625557C97D9243EBB00FF98
+:10B5900009738C29D12FFFF938FEDE64DDF172C109
+:10B5A0000B5F6D9AA99F193F6EBC74C9A1767E7E10
+:10B5B00076C1574E3FE786B635918928B70E737925
+:10B5C0005D7E5875E7977139F7D49E2751DE2E7A44
+:10B5D0006B638441F981DA9C8774D8F3C0AA8881AF
+:10B5E0007257352388D70F924A8FF7A01F0A49D682
+:10B5F00077D91CF96FB03E13E3DF37BCE14BD6C1FE
+:10B60000FAAA77F952A827973DB788E80075D29B28
+:10B61000CBF6F69CFFB6E8C1BBF3749EBFEECC83BD
+:10B620007BC043E781CBC0CF42B63D631E5CAB32EB
+:10B63000D79BD9537E5DA717E546B5F007DD797036
+:10B6400055BD9CA3B4849C79708017F2FB4C580FB5
+:10B650009D1125B9DE6978C867FA619D1FBCD9774D
+:10B660001B9E037FF4C04B1169447A9F5B79681F6E
+:10B67000B5969CF6BB6727843CB0EABDE5C7ED01F3
+:10B680007E407C2F017CA3DDB2E4A81C1A81718965
+:10B690006D1E5AD793AF1FCC1B09F5C58F7A726701
+:10B6A0007270C2A88F2C7A75E5270AFA2C7AFC17DB
+:10B6B0005ECC93ECCA5314745AFCE8012FF2891B38
+:10B6C0009F535B0F783BC23DD0ABF5DD69747FF5CE
+:10B6D000A12FBCA8673E7846627D8BBAF7AFDAF13E
+:10B6E0005204DB9D896E1F3DC0F5E4476D52522A1E
+:10B6F000EA9D7EFF0B65EF39DDCFF5CC29AC0CBFA1
+:10B700006BD9E06565E89798723086F6903B1EC865
+:10B71000C4F7BE6E39C8E83BDA1786AD781FFF0E56
+:10B72000DC2D2FF0E71E8CDDC27FE56F0F4FA2FDF1
+:10B730001F9B2AD7F0EFE0893C8070749B8F073EF7
+:10B74000294E754AC8114F98FB99633ACAEE9984FD
+:10B75000718D760F4BEAE973F153C7F9BE1EDFAE68
+:10B7600090FDFF248B2B68AFFAA232D36DF808E866
+:10B7700041A6DBF8335496EDA837223C781E21CE43
+:10B78000D7C7F2572C2356E01867ACC6BF9F9E5907
+:10B7900051ECE8CF0E3BCFC5993242C1F57D960200
+:10B7A0001B1CE01A7FCC799E3351D0E3DC5C53A1A3
+:10B7B00034A0B75DEFC3D329CE32F10C7196EF867A
+:10B7C00085FE2C6005B8CFE8AE0AD22B2B42F6AB33
+:10B7D00047D8F9F8DD32CCBBFBB9C0672C247FAA6F
+:10B7E000038EFB8503D354D8BFB1B1F24D25781F2A
+:10B7F000617D2EAF9F273F5E0CF511EBFB4CC3FB29
+:10B8000009B1D1F2580FDD8BCF9B5689F749648976
+:10B8100095E3F95F01FF0EC63A2FEC2BD8178D1177
+:10B82000666465E37D566606CA713E9D7F0F0D1CFA
+:10B830008F00E68189F8B11AE1FD1A3DBCDFD98E8F
+:10B84000678D53AEEAF49D4E5F29C05A949EA75C63
+:10B85000E5F08F087B892FD4294614FD1435DB1BB6
+:10B860006BA0769CDFCFB604F93700E59FA29CA2BF
+:10B870003CE9CE7F0F515CFCCD20E7FF6F65AEF752
+:10B880000C837AB97FC04DB879DE94767F17CB3FB1
+:10B89000861313C314E7E7F78FAFFE8EB29DE2392C
+:10B8A000E19A0CA48364707D2B0111AEC17CD07928
+:10B8B00031BF5A8222CA998FA628E59D299A37C39B
+:10B8C000312FB8797ED4B7DFC2BB403A8E0B75E01A
+:10B8D000DBDF54F0FA9C647143874EEB9811063815
+:10B8E000C6F892FD319FF96A39F95D9EA7E7CCE36E
+:10B8F0003A1114FC2FBED3852211C719B76FB19529
+:10B90000BF45F2BBFA55117F3CC2F5A4953F83CBEE
+:10B910005849DFEBEECCC3CEE71D96C92F737F9756
+:10B920007EC261EEA74F70F1F579E25CFFBC33D8BF
+:10B93000C9F3C342AF087E3FDB3CAC6725E306C4D6
+:10B94000C34C9519F6DF0D582E1CD153878B33311C
+:10B950007E7458E8692B6FD1AB2B745EBCD7A55FA2
+:10B960002C7E1B794C9B8FF819798C5D8B72C19D55
+:10B97000CFD3358FC6F139868DBA07BFDFDC9B1C6C
+:10B98000B3D66BC9B32CC329C772A63BE5589FB881
+:10B99000538EF59DE39457F909A79CEA5735CCF1EE
+:10B9A000BE7F4DB9A33E70E54447FB225004F67AB2
+:10B9B00049D30C47FB41CD9739EA435AAE76B41FC1
+:10B9C0009A9CE7783F7CD722C77B4B5EF7267F4760
+:10B9D000B62E77B4B7E4EFE87DB73AC6B5E4AF0961
+:10B9E0007F911FCB5131015E63221FAA37F9ABC88B
+:10B9F0003553513FC652A682F6C53F2B879F74C967
+:10BA0000E1CFD8CC0A46E7BFFC9CB937BEB4F27A86
+:10BA10009510D7874AA65CF32894A3C3DC1F8985B9
+:10BA200045BC4BE37C7272FF108A33631E1CDA2123
+:10BA3000273DE1268C1365012FA11C71EBE7ACB605
+:10BA40001728FEE43EB7BB45D1293EF7856C4CC0B4
+:10BA5000F5F561AD14F76994C5BDC7297ED21F1BEA
+:10BA600064F95A7B3CF6D530DF1FAF8AF56D01399A
+:10BA70008D72B95F08ECD872DEDFFEFB08911CC640
+:10BA8000CFADCDA5AB2B0BF1FB571D657A16EC2B7B
+:10BA9000AC9F9F9667203FC722BE405E75E03E0583
+:10BAA00039D53F0553CDC9ADF148005B3F3F333138
+:10BAB0002F18F0752DC66DB358AEB47C04C61FBBED
+:10BAC000E4A5FE3530CDB38B8653FEF5A9AAA1F4CB
+:10BAD0001DA553B0F62374FEA5F3DF7999CECFCB25
+:10BAE000AE12E760A7169450BB37BE03BB15F8EF44
+:10BAF00097B872D06F6F78F97741CEE467566DDBF7
+:10BB00009481E7C36F94F1F338EBB994C1E3C85261
+:10BB1000864278AA5E10A27CDB65490F9DD3542330
+:10BB20005AD05E4CF27D8E75F4B3D6366E74DEDF7D
+:10BB30006AAF31D17FAF6E9B45F90BDFFA0DF7632A
+:10BB4000BFF57F78DCC59A4FCBE0DF57D3C47C5775
+:10BB50004281F78BAF04FC6761F9C2A469B86FE05A
+:10BB6000794A82FAA5ED601A00BE67258A3C88BC36
+:10BB70005758ECD52760C9FD32F8BCB359DC83FCBB
+:10BB8000F01A4B7CFC6A916D3C6B1C5814EAE5DFA3
+:10BB900064999E3CE097CEF325D24F309F1F9FC7FC
+:10BBA000AFE9B70A45A4359F35CE652C46E35EC1A3
+:10BBB0000C2A9911A4EFB458F271F90DA1540E8C0E
+:10BBC000B71CEC738CB39CACEBFCE9CDB0AEDF2DB5
+:10BBD000FACB1394689FE8E88F7EE9552D0AFD9E05
+:10BBE000CAC1A0519A81FBA322E7ECBE6B07643463
+:10BBF000516F323EDFCB82DE73DA72C60ABD1DCBD7
+:10BC000000F8DF7C664F7F941B2F0E7D7010BF9F66
+:10BC10007A96E30B791F13FC05FA80ECE7932C1856
+:10BC2000F3F5603F3F2AF4EE2DB241F1D95B141ECB
+:10BC3000A7FD42E6769B22C7A22AD45BDB9410F2D2
+:10BC400069048D23DBEFA144308951FCFE891FFC80
+:10BC500088E162FF5D9CF11FD31AB99FEFD4E7C260
+:10BC60006FB1F4771CFEA2BC3C0FEF3B4928BF9D8F
+:10BC7000FEEF84944CFEC53FABAFAFCA70CAC5B3EC
+:10BC8000D7D7897948D7D6322EB75A53419EFF0A63
+:10BC90002A00ED314B8FBBFB57897DB70C7D629439
+:10BCA0009F082BDA9F203F32F83D045329A73A0B17
+:10BCB00067535EB3D187D7CD4C289FD2787BAF74C2
+:10BCC000A2CC0F726AF91D8FAF6E9A84F712395E9B
+:10BCD000B18EBFAFC2FC21AED72D39F2DC30FEDD14
+:10BCE000C0AF004AC4B7F05FDCEB1B077C4BCACD8A
+:10BCF000E27BD13FF5FC5F23E817EEC9D67F751EC6
+:10BD0000DA7B871486FB29A07678B37A80F349948E
+:10BD10004B4318DB97C1E5B07F9F44DFD9F1EBDCE3
+:10BD2000EF0A68DA18CA6D4FB010C65D3E7EB48463
+:10BD3000FCB05884CBEF9A507C3DF2F99FA4A3E36A
+:10BD4000B512B28FEE407C5B786D4DF1EF928F545F
+:10BD500059939A9DC6AB357F75CB583A5C58D692AD
+:10BD600043E550F4B3E151758AC377625F43764F80
+:10BD7000FEFAC8B6B10BE95E5FDFCECFDF429FF0BF
+:10BD80003FF8BD604C69C7FB200F7F399CC6DB9133
+:10BD900051C4ED2B95A91EB22B93327EB7AADAC7F8
+:10BDA000E5DF892F156AD735EEBEC98A06B41E9124
+:10BDB0006A3E88F67FA0CDA753DCF901FEBDC140E5
+:10BDC0005B2089FA4ED53ADF473B5E6DF3690D3A49
+:10BDD0009EF376BE83FCD5B9DF47BF2BB1C7DB4CE2
+:10BDE000ED3B073119EB438152F8FDB080D6CCB260
+:10BDF0006DF004DAEE419B1BF982BE3314509BD9DF
+:10BE0000F9363AC5223CDFE0F90CCE4F7B82293966
+:10BE1000CCC765DB695DE975E2BAF0388AAF732893
+:10BE2000C525F678619DB9B42E0DF96028E3EB6461
+:10BE30006D4374D4CB2AAC87FC9A5226A34870AFCA
+:10BE4000AB7A144BA27CD950CFD2BF8F04F2A23A66
+:10BE500098AEFB616FED2916FADA3CBE1A7F47A84F
+:10BE6000AB8E02AD22DDFFED8C0F573716DAF68F61
+:10BE7000CAF7D342D4177DD2FB08F18071B15EF7C7
+:10BE80005B98B72BDBA67E8AF03F9A0AC7E8F7E2F9
+:10BE9000C4F782AD38CB0A29F5FE856847A50E8E1A
+:10BEA000D2614D4B5EF8D900BCB2B7586EFBE14889
+:10BEB00078BFCA9B781FF9F5A9B76516013CFCE964
+:10BEC000A14072268C53F6F4B63C3CFF708FB7E667
+:10BED000F5FA8DFDD07E7A5AD231AE7BD2D349713C
+:10BEE000D4656DFFDB8BF1BB8BF7BDEB45BBE10789
+:10BEF000914427EE8B8A7D7553118F13587303C6B7
+:10BF0000CD40AED2F74C5AA35C1E9D3A36787B1DCD
+:10BF1000EEAFCEC440E4CBA8D857161DDAC4FE7CE1
+:10BF200006ED06289F1076CB1307AE2AD16DE7F6F3
+:10BF3000263B48F19F7AF65C3FC4B7F5FC6452A5F6
+:10BF4000FC93E1AFF9AF356C7C971DE1FB3D5BCC19
+:10BF5000978C24BC118CF31FF8BD3702707D2875B7
+:10BF60004EC357B09F7D119BBFD30AF68F9D7FBBF9
+:10BF7000ED67D77EAA563BBD142F3CCE48AE00BD20
+:10BF80001B33817E8FBCB66F18DDBFEB8C7F1BF13E
+:10BF9000F0F9AB5E8679114F083BB6EED5CF47A1DD
+:10BFA0001CFB7CFFE28188BF2F855D02FC3F057F83
+:10BFB000BBABF3514672CDDAA723709FC2524668DD
+:10BFC000FC3C7104F27F11F2FF9119B42F9F90197C
+:10BFD000DF877C3F00FF6B282F4668B01FA8FF104B
+:10BFE000DAE77B8EC8FCDC0EF4049EFBED9101B514
+:10BFF000C067E33CA983D86F1CCC5BA7E37E3D12EE
+:10C00000C4BC08B657CEC578DF38FC7EB20D2F0B06
+:10C010003322849785023FB70A3D12C24354DBBEE8
+:10C02000B0E95D5E177AF9FB917E6B36E38FB269FA
+:10C030002187DFC7A22192F737095DB9FC17132FBB
+:10C04000DD0DF02D7F59A1F7E38D9AA9A8562AA6F8
+:10C05000373F8BE5C478EB540C7FA2BED0812EE72E
+:10C060004069805C9D34E7C8B3FC8EAB311CEDA009
+:10C07000BD072F198EE7D027DFF0D16F399CDC3355
+:10C08000E3113CA73CF94680C9528F768A83CFDC06
+:10C09000E549A9238271A02B360CBB5805DF78D95E
+:10C0A000040EE7651BCAD698A0035F891857205F66
+:10C0B0001DCF4C5C1101FC9C3CFAD73C94DD4F1C1D
+:10C0C000FB7D04F5FA5EAF315CA3927F7FD13DFE2C
+:10C0D000D408E78771E2DC10F713DA471FB7E46C86
+:10C0E000C3FDF4F15EC5C803B9757384C7A92C7F7D
+:10C0F000F03A8E3656B597DBCBD71B3CDE7A1DDA8D
+:10C100003358DFEC71F86D558CFB47834DD615071E
+:10C11000477FBBCA65AFD0F97B2EC65125FA0E8A80
+:10C120003B8EBA44F8894BCEE0FFDD1C11718912B9
+:10C130005682760EF003F99F9DAF2AB1EDA8DB542D
+:10C14000D6EE83F53C22BE4B09F290F69365EFE400
+:10C150006AC6531A9E33087EDB23FCB5CE3D52924D
+:10C16000F87F17A37B5D138FEBDB287FC034E8FBE0
+:10C17000DA5542BE4D54B9BF3BF15849CC44F8851D
+:10C180009D5761241B30BFE9FA5D522C496A94C364
+:10C19000076AB52B6E83F02F6C03F8253C3F75C101
+:10C1A000DF72F479CC4958DAEABE1FDF733CF9310B
+:10C1B000FC470FE701F745841D38800DB0DB81ACEB
+:10C1C0003DFBB4F7E22DBBFA4371BFF5D7627CF8B3
+:10C1D00013C6FCB7F704FC4F087E596670789624A6
+:10C1E00095247EE766BEE00FB69EF38775EFA45AEE
+:10C1F000C0BD742BA7BB1BBEAADD1EB27B01617440
+:10C20000FE51B5D5C95F8B04FC8B5CF02FC34BD3BB
+:10C21000B6F92DFB7BBEE0DFDED6B3D8C3E9B7F8B5
+:10C2200055FE7B13FF5DEB73D3E5658B6F87B161C3
+:10C230000EBA4C3FFDF70ABAFC1D971D6BD9C1160B
+:10C240001FB8FB4F13F6EFC52DDC5EDC7BE46013FB
+:10C25000DABBE5FB150DCFF7F61E3915C1F397B123
+:10C26000FB79FEF7C9B6B1EBF03B168FB7975E8E40
+:10C2700079AFE54765DA07635F2E4F626A71F9CBE4
+:10C28000E5A1123AFFD273100F270F73BD79F27038
+:10C29000E92B78AE73B2BD721CAAE9BAC3E521D40A
+:10C2A000EF8F33EEA74B2FFFF99738EFD843EA789B
+:10C2B0008CD3AD8E2AB4DF2EBE77EE4EF4D3FE18AB
+:10C2C000E17EF4F34796CF263A1C96357C7EE2B0A9
+:10C2D0004CED96FC48A13C4EA6DC96FB6D78FF59D0
+:10C2E0009B47E3EBF5D0FCD5FB07E5CCB7F95FF353
+:10C2F000049F9667E99B66A21D971F22BBF7E2FE8B
+:10C300001ED27B1F15847E82F6CB60631B9DD37E7D
+:10C31000F4B39B649CF7E41E89450180E7A3CFFE3C
+:10C3200094BEEBF1E4513A579ABAF7289D23CDB366
+:10C33000FC39712E6AF1D342F4DBC0AFFCF84850EF
+:10C34000E457347B912E4B8F5AF50E2FEAE7B8B0A5
+:10C350007B963DF02ED517A11D0FEB59F480447943
+:10C36000A8CFEE7F8ACEA396EDE6E7518BF66D9BC4
+:10C3700086ED16B3563A4F74CB8B852DCEFA0D82CF
+:10C380000F6F38031F0EC8147C38940DA5EF664C50
+:10C39000E6DFDF684DCD1BB807E63FF5BA8FF8E161
+:10C3A00034FC487AEDB088D79C4AC906C26FB53BC9
+:10C3B00071F89417EDC2696D9F10DE66B61DA84432
+:10C3C0007C7C932596207CDF6C0B6928FF6676F0D9
+:10C3D0007D37A3CD47F72FBFC95A1BF97939973756
+:10C3E0000B051D170ABC9F7CC6C7CF5B7E2A91DD5B
+:10C3F000B110046B0E88B425227ECBB63AE9021246
+:10C40000FD3BFC5CCE4776D337CA9CF89AC1B8FC9A
+:10C4100098B14F22F9F10DA6D3EF407EA31D032959
+:10C42000305F7E887E2767C96EF7392EF7C797B9C8
+:10C43000F45B2C93EBDB7FF47706E22E7ACCECE412
+:10C44000F26986D0A3EDA9FA11183FB2F0E3A6472E
+:10C45000BB7EFAF3DA5F0AFBD8AA5F0A1B05EDB0D0
+:10C46000568DE3FFD0913E9437B4688262A23DF0CE
+:10C470006426B77B97FCFDF24B31C1F423F9E0CD84
+:10C48000BBE1FD87735B07235EC01FA8CA84F72F3B
+:10C4900014CE5F3F06FAFF698F2786F28419DB0608
+:10C4A000A39DB426BA69269E2F55EFE6BFF379A265
+:10C4B0004231497EAA9DD370BE0FF74B1AC655ABC9
+:10C4C000F77DCAFD01E41328E36DD245C8276067F4
+:10C4D000AFC804791737B23C48BF6595129DEBCDC4
+:10C4E000AAFCC48B78057BFBBB9936FFF950690920
+:10C4F000F9CF87549DBE8BD89BBDBDEC4B6EDF59E9
+:10C50000CF97C1BE447C2E6B93C8AF4CDB777D25A3
+:10C51000B2EFF63FF55C36C985AC31A84E7F92D9B3
+:10C520006527515ECAF542CF30A991F6C3DE831F5D
+:10C530005C89F0753EED61C52808A164E7823CFC8A
+:10C540007590ECA213AFF1738A851A3FBF39312F72
+:10C55000D9988D76FD4312D911D70B7D85EF313EE9
+:10C56000793DD86B1794E3AF49D60BBFA5914AF735
+:10C57000BEAFDAF70AE54359F6063D2FEE2E2F96A9
+:10C580000ABE5D7A8638D2F0679E2A46BA3C99295F
+:10C59000EC08C19700C73A949F270F291A9E1FEFF6
+:10C5A0003DF897FB0BD06E027BB818E5B3B02FF6C1
+:10C5B0001E0C907F70F268388978FC93E0BF8F443E
+:10C5C0005CB7AE4221BCC8137889F3D177C2F67F3D
+:10C5D000312001F2F691679E1A86F35B79058B771D
+:10C5E00039F3D296B63AF3CE2CFC560BFCC2BA06FF
+:10C5F000E3FD346B5D4FA81D91580FFB46920E1260
+:10C60000DD64C9E90F563FAD38BEEB03F05C8BF239
+:10C61000AC3DD3CA53EFCC43FD773853277EA86B8C
+:10C62000E37496F7F312E6BF92C7393C347FB7F74D
+:10C6300053CC25E4CF1585E83CB51DFC76FCEDE434
+:10C64000F6D703E48FDDFCEB4543ECBF4BC024EE93
+:10C65000B7567B3AF3C84F3CCABF3B34837D42F99F
+:10C660001333DA3CB98029F67CF1CF553A77182597
+:10C67000B173601C13E7ED8BF1B5E7A8FF95992224
+:10C680003E3E81F7AF177CB5F7D73342E8A79DDC74
+:10C69000DF87F22DDF127EEFF1CCF87BB8CF2C7F55
+:10C6A000A337FBD1E6EF103EAA014EDC478FBFEE69
+:10C6B0004BCE94D03FFDE2B56F23BC8754CAABAEDE
+:10C6C000DBEF33D16FAA7E3340DF236089C46894E7
+:10C6D0001B373FB370089D1B48F5448FCF9F39D45B
+:10C6E00044FD9EF450846FE9FE57F348AF3E71CE8F
+:10C6F00026B453C02EF906DA298FB779C84E297FA0
+:10C70000791CF1DBE387C7E594D0771B62211C77A6
+:10C71000E921358EFB7BE9A1712FCD44FBE2E529B0
+:10C7200064A7482F8FCB41B93356FCAE8F74A894C1
+:10C73000EAFF1776D3957D00800000001F8B08006C
+:10C7400000000000000B8D566D885465147EDEFBE2
+:10C750003173D7999DBDFBE1A8ACD9DD55F723C74F
+:10C76000E9EE9AEEFA5557ADD842735C332524278B
+:10C770008D88D255834828F0AE9B609A24E18F8241
+:10C78000889B50F4C362AC4DF6C72AB3B8A6AD106F
+:10C790001B16AE12310A5981DB6E4548124CE7BCBC
+:10C7A000F78EB35F41B32C67DE8F73CE739EF3BCFD
+:10C7B000EF3BF93C7D1E02EE94A9C06260A4AF6419
+:10C7C0009B9300046AABD10A2898276D3ED8B7B373
+:10C7D000FB7C0851B23DAAE3258AF305BF98A90165
+:10C7E000D3810AD392F13A33C2410BC539E5DB9DBF
+:10C7F0003D5FC42DDAF7929E899B14A7F3A4EEAF98
+:10C800007FEA5BE098F4736D0598015CE2A959C07A
+:10C8100080F09E03411CD0B125437E0357D3F756C9
+:10C82000B05D95AE677BDC14326F018F8BD512370C
+:10C83000447B356602C3DD7A9B172DAE17EC51F6AB
+:10C84000A37CB14A6C4B4DB17EC054E4FAE321A401
+:10C85000392FE044672D01BEE1AF54E213FD2FAE46
+:10C860003563C0BA60DF65A4CAB21412ADFA8D5C3C
+:10C870000390A2BF7C2D50FFAE762367407EF2F47A
+:10C88000BF09968EB9C046FABEAF02C834D8D3ED00
+:10C8900028CFBFF5BB9A2CE6DFB84E7742F74FC6DC
+:10C8A0007577BD4D9F10579379E5B88662FF306B61
+:10C8B000437F4371DD314BAB6E2EA02F75A8CB1398
+:10C8C0009F50A3115105FC755137D51ADEE5CD4BAC
+:10C8D0002D9C9CE7F6FE991BFA75E0ABFD54763D66
+:10C8E0007071BF21ED39E13C6652DD6B3538992915
+:10C8F000F87BA1D4EF4B67E395648EFBD577F5B356
+:10C90000F20780D1AB25A8659EFE2114C4E72E3323
+:10C91000C038C1BF13EDB28F07F0E4381D16FA39E5
+:10C920000CB4651293FBB923E8474743F83AF3D9AF
+:10C93000A18E8698EF370FBD93621DE9BD9D2EE74E
+:10C940006B0FF93A2DF877F4EC453AC178C300F152
+:10C9500032FC88F0C242E29E1396B8C3A8953C0D03
+:10C960007E504EEB9B864A7098D6FB1AAF8472E4D9
+:10C9700047C2FB0E71D2855F0E7665074326CDAFA9
+:10C9800037FC3EB35E4078EABA9F3D8860FEF566AC
+:10C990009A278D3ED83C868F405FEB5BC7F7B71375
+:10C9A00015AE3C97A24ADA7A0C3E5A4D38363BC255
+:10C9B000F668FF0667FCFEF62D4DE789FE2974E256
+:10C9C000EB6CA25EDE33D3074D721819FCE3A98528
+:10C9D000146FA0F1E739CC4747A07FBBDEEAC9510D
+:10C9E0003EFB92D9D4453EBB23B1A449FA7C9BF9C6
+:10C9F00026BFC6D2F451E9EFDD789E2E8FBBFE71C3
+:10CA0000D394EB03BA379BCF7DE1BCD933B0686FC9
+:10CA1000746CFFFCBE1D653D30F04425B0F4BFF5DD
+:10CA2000CF84FBFABA9064FE07FABE4E86C6F4E9DC
+:10CA3000D6CBE97ACEB7FBCCB9B8151DAB2B25D038
+:10CA40009526AD10BECE14315E67B7586709B6DFC4
+:10CA5000C797B31EBAD74C1756717DF7979763F3F4
+:10CA6000C7C41DEE55E57E68B9BA4DA563711E9425
+:10CA70003887337E3C6AAECBFAEA38DDB4E4B04F97
+:10CA8000BFABF078DEF68F594F4097DC5FD06789F7
+:10CA9000EE3AD5548F8E3D2EDB4C08D2DF3D1BF68F
+:10CAA0003EA2F1089D4D50DD23D7CD0F5DA9CFD912
+:10CAB000601D9E0E74F46DC06B0B5D4EACC3A5C8BB
+:10CAC000A87C1E5AA0612B8F356435B22BE0A97C5F
+:10CAD0003E5AB46C9F48CA7957235DAE444ECE533C
+:10CAE000291AFBAD82A5F1780DDC2E7A2CD0DBFD66
+:10CAF000B91AA154D9B8567E9374C657CB54FD2A9F
+:10CB0000F2A1E1664177B4D90E931E1245DC4B8445
+:10CB10008FBBC581B18FF2DF09CEF5720C4A1C764E
+:10CB2000C4AF77F46F782704E4D3B195F62DD7D04E
+:10CB3000A6521D2B3518D3687CAA5F91E7F86CCEFE
+:10CB4000F2F87EB32B03BF5FC9AFA658E732DA5FB6
+:10CB500056C1631CD2253FD929EB1D366B7C5D6223
+:10CB6000F4198EB3A6378CC334A518AECA3AFF3376
+:10CB700078F722C45B8CE22C3B26304438ECB97E3B
+:10CB80007D85F8CB40F99A79BF5F178D3144F31159
+:10CB9000C3F7031E36991F918D2BF9C8FFE7712447
+:10CBA0000E893BB663F4B7D7B8CE3361F30441B214
+:10CBB0007B2F0C097AA784E380F9B48D68568D71B8
+:10CBC000C3B45B77EF057AA7C2E5DBF572C2232C0D
+:10CBD00053F28934AC54293FC5EF9BFC6E28BCAF9F
+:10CBE000D26FD32FD4A7CD81BEAE4D8B2551067CFD
+:10CBF000E2B55BACE32D5586CD7C371B731681E225
+:10CC0000FE144DEBE5C4DB357172BE0CA2798B3995
+:10CC1000EE1B6A06CC2FFD3A90BADC67F8716E976E
+:10CC2000F896CF1AEB3342D7B141788E90EE0D1AB9
+:10CC3000BBABFD3EBA3F96785D94E7553525457709
+:10CC40005BB10D8E87DAF4500B596DB563EDA1F32E
+:10CC50001966FC9122FE8979B89E15857A94623D09
+:10CC600093F3B8FA7D359CC7EACA0959D702AEAB2F
+:10CC700029ECDD93A5F9A715EF15C61181D32A710B
+:10CC8000200BBECFCD80A7429D26F34FBA8343FC35
+:10CC90003714F92FD47B649A5FA78EA01E8BFAB04D
+:10CCA00070721DFF029EEE0248C0090000000000E5
+:10CCB00000000000000000001F8B080000000000C2
+:10CCC000000B9BC2CFC0F0A31E81FF72A2F2D1F174
+:10CCD0004A0E54FE1A2EFCEA0961150604FB193BA4
+:10CCE00003C3572608DE0AC59140EC0AC5A2CC1042
+:10CCF000ACC382D0E3CBC6C01006C4F1409CC18651
+:10CD0000DFAE2E164C317B390686738A087EB62438
+:10CD100003C312201695A2CC5FA3786860494354E0
+:10CD2000FE7C2D547E9F0E303D20A959A0459AF9D6
+:10CD300062460C0CE2400C00564D6D566803000034
+:10CD400000000000000000001F8B08000000000031
+:10CD5000000BC57D0F7C14D5B5F09DD999D9D9CDDF
+:10CD60006E761296B0094B988404A20DB80901039F
+:10CD7000461D30D0587DED8A56A355BA0481A002D5
+:10CD80000BB592B6B63B90BF4020ABA2A588760308
+:10CD9000E2C33F3CA34FADFDAA75A968D1E7D7A672
+:10CDA000AD7DC53EEC0BA8885631DAAAF83EADEF52
+:10CDB0009E73EF6467870DE86BBFDF5B7F7273E77D
+:10CDC000DEB9F7DC73CE3DE7DC73CFBDE3F6951239
+:10CDD000E97C423E831F4DBB65F284701621EDE174
+:10CDE0002E93D05F37FC338B902E488BE9FF29516F
+:10CDF000223309F110F67385C5C3EE7C42562B3AF7
+:10CE00002163E9835021D6977C5112D3A186A40FC8
+:10CE1000A958D5FC6C52569E7CE6FA3CF94FA664A4
+:10CE2000E74DD60FF92E2145847C9B97D19F01F9C0
+:10CE3000469EB1C663A524A2907455A69D46C2F233
+:10CE4000BA2890CF04789A5D6EF5D3A6E64F2301F9
+:10CE5000423EF2B0D49C4B8BEA68FA274FAABD8CB5
+:10CE60008E5F887D89C1133F3B3A15D3B3206D1780
+:10CE700048F3802F071C643D213308D990884E7FEA
+:10CE80004DCE3CF7484943ACC3B623BB016F3E22AD
+:10CE9000C1783608D6F0060D579010351899BE9116
+:10CEA000E6665378A19DD54A7436A430FCA89F90BD
+:10CEB0007D957734B7D07AEF4794881B9FEAACBF53
+:10CEC000CAC9E362D5502F4900BECD339E0BC57C45
+:10CED000D82FD120F51103E025E4FB04E8FB01E0A5
+:10CEE00055CFC0F71522623B997164E3EB39F883A3
+:10CEF00096B727F4868A4A427A65BDAF01F0F47F7F
+:10CF00005D91DD582BDD0C78DB3CA348DC48C7D4B1
+:10CF10002E53FC5078BA13FA7489D6EF4C54617AC8
+:10CF20003E29C77636CF60F0EE9B31393044D3CE00
+:10CF3000B1DEE614C21F1932E9F8D60E3D7CCE46AA
+:10CF40003D93570EFD04F3E7937CA4DB660FC33FCC
+:10CF5000C5108E27C32783CD8B697D7F9D56CBDE81
+:10CF6000377CC5B43C8FB0F1925431F295A2B1BC7C
+:10CF7000B78ED2C9E23FFA7FE3588910FABEAB8E72
+:10CF8000A4DC94FE7987965D4CA6C13C481A04FA4D
+:10CF9000ABA678A1F535FADF6774287E6813E8E65A
+:10CFA000232983D6572B58B9D59E62C723F013E99E
+:10CFB0007DCF05ED399ECB1FBB2269DA0EF9BD0B83
+:10CFC000F94396A383E7033EEB768E33850C5DE44D
+:10CFD0003A361FE5D8B4E98DD329FF1EEA3F677FB3
+:10CFE00055A63F93F8834761B06793B391CF5D57E0
+:10CFF000076239F8D44A3F4AA4CED92F235E443B76
+:10D000001E47ABDF99A0949E92C97795C54214152F
+:10D010002469FE932151D476C9B19010A1F4DF7533
+:10D02000A1D144F3F294482842FB6F2FA08D9610B3
+:10D030007227599136299DE5F6642842D30DB2E353
+:10D04000F905117CDEEE61FCE3ECFF8F1473487F81
+:10D05000391922AE8C5C7073FABA43CF7D2C50FC28
+:10D060006E16A26D87813F0BF2913F69798F5488CC
+:10D070006993520B95559473AAF59E443AA45A4C61
+:10D080001B95421857B2B905DFF7B1F9FA766CDB98
+:10D09000229AEFA9298A6CB4CD9B9F1101E1E9E2A4
+:10D0A000FCDE2B67C37D00CA29BF3F41644CBBFC3B
+:10D0B0009C6FB5F6D025FE1CED703CBD48969BA636
+:10D0C0000FC6418840F9C22C5352BB4156186668BE
+:10D0D000811F80CE968FA3D1CB2917DDBA2D0FFFEC
+:10D0E00068367E2D877FC31AF20FAFFF3340CE58CC
+:10D0F00084C32CB0C3A1AD0B2D007968D27E281C4F
+:10D100006A88FE3D29AB3EE281A46939E019740BBF
+:10D110006DAF3B78737211FD530A12338FF2B15425
+:10D12000D1F59E0B528DEA131FC8BBD8CF50DE69D4
+:10D13000244B0F49C44C0BD0AF3907C72D59F39975
+:10D140007C3B5B4F9C1F3B087274B35FD1D79781C8
+:10D150009E52D2C00FF01B9EC9F984B623D5750D1F
+:10D160000AB45F7730DFCC9B06EDF53238C20EFC97
+:10D170009C66FE38E7DF30CCBF2F65E69F44A28176
+:10D1800034C01D0D8900A79FC3294514D3C5FA1DBE
+:10D19000847E47E6E1D90B022067A4907298E125CE
+:10D1A00049ECFD77C3FCA3839822443F053C758E70
+:10D1B000DB42408EB6CBF183C09F66A5C2E5F1602D
+:10D1C000E892A999F79E03F94EE9B2038A00BFDB02
+:10D1D000C2E2E7E19F76C77CA743627AC40C227D56
+:10D1E000A411FDC5E6A12C30BA540A8C9F4992C9FE
+:10D1F000957CDE8F027A7712D035858DE59134E605
+:10D20000DD6410F3AE70B46F12CEC7A11ED027EE4E
+:10D210007A91F2DCC970F52554C4C36870F79DCBD0
+:10D22000F489CB1727D7DBF05724E473FBE26A0DB0
+:10D23000E8249831F219D08BEA4DA6672321D4EF68
+:10D240008936F22AD5579E5F5C48743ADF14185726
+:10D2500031F053C43080AF4375CC5E0246A47FB634
+:10D260008FD57682DE93C3EA227D1AA4DA253AF2BC
+:10D27000DD3A6C57AE387309E343A6C7E530E77B68
+:10D280009D20FFC94113E9689B07E708008F9A3D7D
+:10D290000FACF7492888769805EFC97688C9C76921
+:10D2A0008D2BA530FB65244F58DE64FA90B7AED4C1
+:10D2B00033B8947A2FF2A7D2281D1DB2E933ABDD23
+:10D2C00076C2F031A207B8DCC31F054DD622BB36AB
+:10D2D00052BA7515CF0F2DA6CF9B0566CF908BB395
+:10D2E000C763BD4FC7DB0CE3953486076B9C5DC5F8
+:10D2F000930398F731BBD339CE2E6A8F48722E38FC
+:10D3000052CC5E2921A931743CE493E9552037576A
+:10D31000021D73B4F3EE28F0BFFBD49711FEF8E9B9
+:10D32000E18FE782FFDDA7A630F89F189B852F2BA2
+:10D330005DA94E6A90A6DBE9C5E69197B7DF172293
+:10D340004917B5D7BD0DA2097A7F427068DB223A32
+:10D350003F3611368E1782B104F4BB224AD6D31958
+:10D360004E56DE18D5C1C4DAC8C733CFE5F31CA1C9
+:10D3700069D2280FB450BEDA2D0859769E95FE88E2
+:10D38000CE73C0632F9D57907EF40A837BB4F9B5AA
+:10D390003DA1CD027B6E247FADD494A2ED6F6FBD15
+:10D3A000F592F9147F9DC18A5A54CFAD02DAB91EA5
+:10D3B0002E177E68C9058E1F8AB71F02FC16FFFF55
+:10D3C00068C9E5C8FFF0936C78081A860176EC0806
+:10D3D0001EE8FBA0170BDA48844A10C0434AA0EDB0
+:10D3E000AED0281E683F2B1B07E7D0B9358207FA5D
+:10D3F000F354D0FAB73C5F59BBD146B7570526174F
+:10D400004975219FCF743EF9479F4F1B289EAA2B39
+:10D41000219F16A01EC8E36A1BFFB508B187018EC5
+:10D4200070059B3FE1F8B002E3396EE94312427B9D
+:10D43000B563643E275B7722BF15D5005C4F09CCEE
+:10D440000E273B84D1F8EC2968DFC967E10A232D58
+:10D45000D0F15E2DC5F641B94B1FD040E42BF12130
+:10D460004C3BF97A850E6310DA0D717A58FCEE099F
+:10D47000E928BF7EC3F92354DFB55AA478F6564B8A
+:10D48000A69B8E2334B4E86230BD954317BE49D8BD
+:10D4900073B443C3319340BF1343E63AC0FB7429CE
+:10D4A000F61BA0A767D68D40164A3F230D76F42DB4
+:10D4B000B24134906F0D3123EA033ACF248B6CFCD8
+:10D4C00075848FDBA5112365A3FF461783B3AF6176
+:10D4D000A7BACC07F5BC4887525267407B1380FC43
+:10D4E000147E09F840473E380CE3D7AB0671C9B249
+:10D4F000521B14003ECAFFB8DEB845D68A818F6E33
+:10D5000059A234A7183E5E02FE54458E0B9DFE07BD
+:10D510007602CFDF2FC8D89F0AF800794822A8A743
+:10D52000E4DA785AA0725F8B9108A05105FC4CCBCD
+:10D53000E0C755671258EF15C449C4A0E5AE50CAFC
+:10D540009C4C103F1F207E48DC00DD29F94CD001A7
+:10D5500064BB14FFCFEFD3FADB0FB82226B1F1A3DF
+:10D5600043BE8F6FA5F32E873CB6F486CB6770BEA3
+:10D5700088A07CA7F84C823C57B9DCBB48884A227B
+:10D58000F071416BDACE57ED0A6945FED42FC37AAC
+:10D590001B2AE7EB401FDA30DA091B1C7682B5CE76
+:10D5A000ED4AA4504F123D88F02AA108C22107631A
+:10D5B000983AE172B5B9F4D7C6D8FAAD60F68E4B99
+:10D5C000E5EBD4E42D6C9DEC23DC8E8990CB40FF01
+:10D5D0005226063BF5019AC27AC992EF52D09BB50A
+:10D5E000DE72B52959ED5BE989482400EDB784E680
+:10D5F000CCAEA0E54BDB56CFAEA0727759DB865997
+:10D6000012CD1FED599CCFE48EAEC07C3ABA6D4965
+:10D610003EC07B74C7127C7E74C724CC934F3EFB04
+:10D62000CC45F963E9C8FC8D63FD65DB04B467F79D
+:10D63000BDB2AC14D6B3CBB675AF065363598F6C7D
+:10D640001839E8B5563470FDD299186C78AD12FCD3
+:10D650000C04F1771E4CA2B1A88F999D2519B84EE4
+:10D660009828C6CE15E978DB86D6FDF27C8AEA8F4B
+:10D67000FCA2EEA27878C6573E0EFA5BABC4A76850
+:10D68000363B676DA11243FEF66DCDD23BB344C667
+:10D69000CF4EB966CE25CD5EB0EFF3E9CA84B6DBD6
+:10D6A000E863F3EAFD2101FD0CED9CCE4EBCCA6D92
+:10D6B0009B107F23795F84E8D5193BD155C552ABC8
+:10D6C000FC32D18B74BB4274613A5D8C5D01FC0805
+:10D6D000D3BCAD10E649EF2CA60F7D689F21DE5C20
+:10D6E000009F8676BD59AAE8ED1457DD53ADF57F4E
+:10D6F0009CD943529C807EB7E06C0CB3F969C13F62
+:10D700009A1EDB9488CE027DD79D68467DB6C93FC0
+:10D7100004BC47D64B119453EB817675E807EBDFD9
+:10D720005906F48A61BDF55AFCC01CF6BC76270187
+:10D73000BDD08AEDACD7E36AB9ED796F22CE9E1BDE
+:10D740007175AEED797EDB161CE77A33DE5416CCAC
+:10D750003CB7E05A4F5637CDC9F97C4D4FEEFA37FA
+:10D76000F640FD7678AEDB9FB73595DB9EC3C20AE7
+:10D77000E6B38B736F77C58D6A8B8D3EEB7D9126FB
+:10D78000B46F41E8DAEB55AD19A59EE1A8375A7B95
+:10D790006676BDC868EDD1D55956BDD1DA2362563B
+:10D7A000BD3ADA5EF5C9F5BAEB6ECC7A6EA594EFA8
+:10D7B000EE156D76901BF86E0CFA439B400EBA4C3A
+:10D7C000A27EB796B25535E9280F10F2AF22B35BAF
+:10D7D000DA2CBE0E13A99E96BB2A88745EA16D7DBD
+:10D7E000A45355518B7CAF663DD7A81D6D5F579EE6
+:10D7F000C4DF649B07F99BCE3FE1F3F36F7BC24428
+:10D80000FEEA49D4235F5AF3CE596FBFC8ED1C47D7
+:10D81000BF749CE4BB857C5D0C72F79007D7F774EE
+:10D82000AE49F5856C9CE7D5DAC611A2E32B64E31B
+:10D83000CC7AAE678FCF7ADEE9901BB256ABEAA8FE
+:10D840001F983E580B7AB68490F7C4EBE780BF630D
+:10D8500044BE1573F91662F26DB4F17726EA678358
+:10D860003F7263C2C0B43D54AB0D81BFC92791B4B0
+:10D870008FC90598CF543E9AA057D6962027124FAD
+:10D88000306682FDE8AEA20A86B2BA126676873B9F
+:10D890009C22CBAA99BFB0AD16ED4F26873F4920F9
+:10D8A000FF6EE2B689B76D3EEA11273C79A1467C4E
+:10D8B000EE1CD77431FA17E037A9AD23B77CBB85CE
+:10D8C0005449201F8837B20EE52F41BBEC7D4A0F2B
+:10D8D00037D0C367BA73F921A4B60B906FADFE0AB7
+:10D8E000DB1373C08FD6F649BBBB14E6FD2177640A
+:10D8F000BD0E7A62CD32A0EF9A573CC42D8C8E4F6C
+:10D90000B9ED5B08BFABED1B59E37305238847975F
+:10D9100046F5421DC216A9D4997E5FC6E43DB9B949
+:10D9200016DEBF89BD1FBB11F5AB13AEE9A231C630
+:10D9300095830FCDBDE4A017F51AD1D651F89E7985
+:10D94000E56CEC67CD61C6FF141F889FF7297EC088
+:10D950009E94387D2CF8BA134D48FF0D89D8EC0AF7
+:10D960003A1FF2385EDC15146E80AF9AC35DC1E0D9
+:10D97000EE4C44B15E6FA215DFCBAB36913F3CBE9F
+:10D9800038F076A67E15AB9F571D853941BCCEF287
+:10D9900088551E335C34EF7396D7D17202E5830449
+:10D9A000EC576F0585CF364FA85EAF077CF823ADE7
+:10D9B00059CFA5D08D8847279EF61F9E12183A850D
+:10D9C0003FAA27D186F2A00FF41AEDB8A72CD61CD7
+:10D9D00005BF24E83719E609D35F1DA09768BA058B
+:10D9E000F4164DD7C064837587C4ECDF5EE85087BA
+:10D9F0007F34A2D2FC662E679332E34BA54E4AEDEC
+:10DA000014607E0CA0FFA65762CF7BEB75DC374914
+:10DA10007A78BD0682F52CBD237958BBBDD4AC0401
+:10DA2000FCF406F514749D2CA0EB0258A796A5559E
+:10DA3000F4F747A8BEB2F1A9A6A49BA0BEF55CF37B
+:10DA4000A6A32C2FD5E66A5F2B4C6B65415EAEDB3F
+:10DA5000DA294F6BA6ED3DEB7952A1ED0533CF935B
+:10DA6000DE41D65F1DEDAFECE4F69385832AB65F09
+:10DA7000C7F4B0B50E4B960FAAA6ED3DABFDCDD2C7
+:10DA8000A0BAE61472CC1F69CEB2EBF3AA289DB2FD
+:10DA9000F4450AE913A86FCDAA276BF1ACFC33AFAC
+:10DAA0004CC99297FB87269D925F8E02BFD8E4F304
+:10DAB000514F6C212920E4DF5CCFCEE908D3BC1C98
+:10DAC0002B15687E57E15BEB9ACE05BB99C987D6CB
+:10DAD000B63928C796F62E56409E2F6BBB88E55365
+:10DAE00002CAD1A55C0EB498240CFAE50917B3FB61
+:10DAF0002CFD49753AEACF9660B67E69D1987E6969
+:10DB00000965EB97961DB2C30FA597A2DDDD7601DF
+:10DB1000CA19ABDEB2DE6F3178A01FB0C3414EA38D
+:10DB2000BC8D9536D3FAF7BB3C08C7D10D534A6379
+:10DB3000B89ED4EF6E03BFE9722FFAF99DF8B1FCDD
+:10DB40007713418ECDC8E881A58EFD3367BA14F4F2
+:10DB500000F42BC510CE2FDADF7D2ED6DF524BFF1F
+:10DB6000D0F1364FCDF47F24C870B1C3A532BD2E9D
+:10DB7000517CE4F0038EE02F7663963CFFA278DBC5
+:10DB8000C5FBB99FC3F579DFB7CADFE078B7F91FE6
+:10DB9000CF00BCFC4FF9E95D97D7B2C750CE905685
+:10DBA0002FDA2D7F3F5F990C9F5F90CE13458DD369
+:10DBB000818E6BAA8D6E0E7A59EFFD96E3F31D50A0
+:10DBC00016634FA693134F475ABDA28BDAA1470E97
+:10DBD000CCC3F5F272C017ADB75DD117C23AA595A7
+:10DBE000E3EB28D57F1DB29D2E8B9FABA7FCD6D231
+:10DBF000535620D8FAA7F92E70212FDD51500B2053
+:10DC00002CEF61785EB66DD1EC0E1B3E28BE2BC0AA
+:10DC10000E1E2BA9B9F15DC1F15D9D6D07B75431A1
+:10DC20003BB825E2C0772A37BE5B38DFD07176DC9F
+:10DC30008AE3BC20E0F165F0B438C4D6EBDBF3F541
+:10DC40007CD01347A93EEBA072EB08B7D78F489161
+:10DC50002DB3605EF5BA6AECF3EA881AD97265AE44
+:10DC6000E7BEC8AF72D57F75C78CFC4539E4B49365
+:10DC70004E8B4337F2F9C1EC928FA85D02FEE21F92
+:10DC8000B8623512C839DFFD6F823FEA23FFEC5FCF
+:10DC9000E9582D5B8F5BED84E2D2113B3E3C55345D
+:10DCA0006F93FB6E3D3B2F115BFD321BBF420F5448
+:10DCB0004FCBC4FAA538FF10F2B66DBF4C1E2A58E0
+:10DCC0000CFEA939BA99063BFBFDA0A8BB73ECAFCB
+:10DCD00064E4913E7D440FE162AB6AFA88BE01FFC5
+:10DCE00045B0FC947EE2F6C413B3EDFAC52551832A
+:10DCF000C9EE1F68FBF96CE0E3FD4191D9BB3EAD75
+:10DD0000DF8DE35AEF88474865E55D6D5DC8EF56E6
+:10DD1000DECDFD5B844475DC37F0C40E82CA2ED89C
+:10DD200012597F61B16D5F20BC95D54B313ECE1B42
+:10DD30007BF93D1B738C1F3DB460AFA7D7A19F51EA
+:10DD4000D523585FAA20640CADAF509C0EB2F58568
+:10DD50000AF6A5A782F9BDDAC09907787F82C519AE
+:10DD600078B8FCE8AE38A241BD8F2664BF47C0E852
+:10DD70009B69AF27927CDA4FFE542945000FE120C2
+:10DD8000F74B474FE99796427C3F31D433C852E670
+:10DD90009F9569B950867EE34EE04B921472EF274F
+:10DDA000F17E46E703D6CFAD0963FA6B9519BE5FE6
+:10DDB0000B7C4F71BF35D184F12E45242E803DF868
+:10DDC000A910BB15FA939A2269E0BD8FFEA9E797C7
+:10DDD000E0F32E1CA7D708942EBF96493A1AA2F951
+:10DDE0003CFD6170A9FE7BE79B737DB4FF4230F67A
+:10DDF000E97AE1EE8E8FD7C3BAA970925E2346A06E
+:10DE0000BB0FE6BE08F5C7EBEFC1FB5DEA7B7321F4
+:10DE1000BEA0708AFE309497DEFA06E62DFBA2873C
+:10DE2000F21DC0D99748CF06B8764BCCBFFCCF12B5
+:10DE30009BC7AA64A2BF51A5FC07FEC280348CF91F
+:10DE400040DB73B35F83791D2269C093E55F78215E
+:10DE5000187B5082FD85E8D07C5987F5181181EF39
+:10DE600037CAA96D1827E067FBAEF36801D88DEFBC
+:10DE7000D7E93BEDEBACFF90985F3D993888FEBE4B
+:10DE80004D09B6DFD2C5F75B362442C43E4F7CEE67
+:10DE900074E419583F9CADA09DA019945075A0E65C
+:10DEA000B57EB09729CE58FC109FD7693EBED54AA3
+:10DEB000340D707EF4CA15C88FEF0F5D4A4879861D
+:10DEC000CE27D1B56EA861643ED37A9BE48166A06B
+:10DED000C71BD2D2B9418ACF4DC028B381FCDF9A8B
+:10DEE0000BFE944D7E469F373B96237DA46A292DD9
+:10DEF000C33E66D5A1ABC0DFB991A47AC0FF656A05
+:10DF0000128B9B20D2DF60FFBF03E26D285FC85FEA
+:10DF1000BA4A15683F8AC8FCDDE405163FD409A457
+:10DF2000281C9DFFA460A4C16E0F0774B6AE774B8A
+:10DF30005CCF52FD0EF4EAE2F85042C43C0FE651C9
+:10DF400023C51745BD2A33FC74245AB3E2B21A859F
+:10DF5000D87B802F39281E867D0E3976C374A0FFAA
+:10DF6000EF24AECF4954C5F9C1E5AB2547A58B5584
+:10DF70009C6FB6F9F53B9C5F0F32BA38E7D707E4E0
+:10DF80001031205EE8D0970FC03EF0BD8903C897DE
+:10DF9000E4C9092827FC9AED059BBC967690B42726
+:10DFA000DF169F50277D68D707CEF8032267C71F6B
+:10DFB00058F10B4ADBF7CEB1FBC5C5508CC0BAC0D7
+:10DFC0008A3BF0CA7A967E53DA7E80F5BB126DE703
+:10DFD00000BF8EC0CBD7417E0E1FB999C11FE2F2A0
+:10DFE000CB1ADF33AF2C4BAFA0F8DF9E64B2797B46
+:10DFF0008CADF7FC0554F20A99792A25D9F846E840
+:10E00000EC18DF7899F9ADEE491CC3FEC30003E6B6
+:10E010008731EFA788FA3F10CFB3DF81473EEE8A02
+:10E02000E224AEFFA9DC667874B44F0E9C1AFFBBE5
+:10E03000299E583CC617A3438D9C3B0E8BB4D1DF61
+:10E040004C7043F0DF27B4746666FFDDC28345176A
+:10E050002B4FD7758153F9C17E9C38319BADEBC9ED
+:10E060003990FEF8E6352AF437F16692023D3031F8
+:10E07000CCF87B629278ABEA301F8131EA262BD74D
+:10E0800079B99E34D4B23ACC63399D06582EF1F258
+:10E09000EEE0FA7D5374982FFC7972F8375F06B979
+:10E0A000D44A22205A651E2F1A0A0D3F3F05ECC4A0
+:10E0B00036E61F2110C940F17A37C76BF8E6A05841
+:10E0C00045D392509478983FC9606A85D5DBC1F1F9
+:10E0D000E136EF1100AD652152D804EDC5B2DBDBAE
+:10E0E0006ED50B31B8494F76F936DEDF244D8269A3
+:10E0F0004ACA4386067E7252CFFC3256BD246F67F1
+:10E100005228DA5466F31359E55B78B927148DE287
+:10E11000FB4956EE093E6A94D1B43FB1ED1CE0C70D
+:10E120008E44CF396C9EB0F736F1F72A42C480781E
+:10E13000941F2792586ECD2BAB9E25C7A50EE68760
+:10E140009C7C731CE34C2CFA7672F965A5C0F71021
+:10E150008A5B598CB8A3E323682FC0BCBC993E9757
+:10E160007A29BF4ECBC1EF84E54BE98FC7C10AB016
+:10E170005EB1F8CBF21FEC3F7C7616BF9136CA5FDA
+:10E18000563BA04FE294CFEC7163ADEA3959E531CB
+:10E190002DBBDC0865E7EBF5ECFAD555D9E5159113
+:10E1A000AC720B8EDE4433FAEB3627DA6635D27466
+:10E1B0001BF7FF6E1EAB97C0BA60E758B62FF4A3EB
+:10E1C000441CFD7B7771BF7007F70F6EE47EBF3E86
+:10E1D000EE27EC01FF1FC895B6F659104FB93D5117
+:10E1E0003FAB91E6F7723C93866C794EE5FC5E1985
+:10E1F000EC87BAA8E942FE60F27DB327DE0CEBB0F3
+:10E20000F1B14141B4E1ED6999E9FD305FDF50833F
+:10E2100052B0C7FD3DCDFBB1E421AD1884FE327A8A
+:10E220002CB54E617AAC06FAFBB9CCE327746AA12F
+:10E23000D8E276F243DA3AF8BB51309E06F8368FD0
+:10E240008DA3DF4FD2A206F8B903868EEBBC30B5A2
+:10E250009B619CDEAA81B40871AB15ECB9D640F184
+:10E26000615B876C2E48A3BFB37B0941FF9647CF04
+:10E27000F64F16C37A9CB633DBB5E05732857F0282
+:10E28000F787B7FB9716B3FD67B62FD722C43E8139
+:10E2900072F72137EA4B7798C5435C20457F0DCF55
+:10E2A000C77CB507F7017E0D736606C6CBA19D50EE
+:10E2B00078D1D52AC643713D4BAECEA683853F2B80
+:10E2C0006E84D26548B6ED835B74F9B56CADCB63F3
+:10E2D000C5C0E73709B1A3508F548554FBFE91E2C6
+:10E2E0008B1AA002ADFAD638CE520C84D382AF5C22
+:10E2F00031FE0CEF8FB44B68BB7E8843304D91C22A
+:10E300003D01E0A5F2EFFF4163334E865BBED18055
+:10E310009DAB93C7D79C3BAEC8191766EDA3AF065C
+:10E32000B868FFC765C6EF8563E2A11A1BDF4D54CD
+:10E33000185F75CBD63E295F07F2780AFCC17A11C7
+:10E34000F2747E152B2CAE9662C5CC3B0BEC746A36
+:10E35000D8801CEC5652BBA95C191763F6E7F64E41
+:10E3600005ED5AB9B56831C43BD0399B867D6FB98C
+:10E37000A36BB580F11171A49F0A127552C63FECD0
+:10E3800083F83E9AE693614C35A2E13AE1DD4543DC
+:10E390003701117EE48E952AB4FF1BD4D8440805BA
+:10E3A000B9E92B837F12E8F35285E1FD5CC928515E
+:10E3B000669CB2FE4278EE23C644A8378E18BA8215
+:10E3C000EBDFEC78566B9F9DFE5EF4DBE84FEE11C1
+:10E3D0009DF3FC4C685FE6F18A237115BE60CEF8B0
+:10E3E00031E73A89FE5EF3CD3C55FB3A5B87707EA0
+:10E3F000B7DAFF61DEB47CB0CB9EE97161DAD53665
+:10E4000009D33F89644B3DEC0FBEE022B9FC865630
+:10E410003A047600E5D54685D94D17F17E16499A1E
+:10E4200002EBEE45E6C7B3EDFEE24526F3FB2C9288
+:10E43000187D17B55D718F3DDED25A073BDFCBF8F3
+:10E44000A7862600FF3BCF4D38CF55AC75259B04E2
+:10E450003ACE8FC464149032327ED53058AB8CBF24
+:10E460003F473B3DFFA0760E007F9DAE9DD39D0FA5
+:10E47000719E0BD95041DB03FE57A3D88A2065C794
+:10E48000BD58F1340AB797DB432CFE85544570BE66
+:10E4900029F46F584FBB9202D3173CFE45AD10B321
+:10E4A000E2929D712FA4D914ECF1BC561C0C3A3A9F
+:10E4B00066DAE51C61E71B3466875BE73CD037888A
+:10E4C000E777BE97759E42F231BB7743456D561C88
+:10E4D000B24458DC38848B313F54F67BA3CF0F47CE
+:10E4E0007F9765C3FDB9DFF349FA519BBD30FA7BD5
+:10E4F00012396AF35FED047982FEDDCF302E1D897B
+:10E500008DE34E8F473B28C1E2AB3F90D2DF003C0A
+:10E510007D30AC10387FF1A44CF66B407741D06170
+:10E52000BD6A68977C0DCA8D975C41B18C2397E6D4
+:10E530009F7CAF09FD49F72A32DF4F1B7441BBC6F0
+:10E540005FB54683E2AFE107B45D90ABEF2B02C845
+:10E55000D5397F4D2F86FCB9C3CD32C8D55F3EF883
+:10E560000CF67BDDF07C09F20FF376DEB9FFE19962
+:10E5700084B6F3E45E3F49A31D9152605D73DDA351
+:10E580002EB42BAF7FC88FF3F7BA4756ECBA98B6C4
+:10E590002BFCC48FF0343CB2EC5EE64F6BC7715F6E
+:10E5A000F7F8A5813E80F3F72EA252FE7B721DF391
+:10E5B0008BAD70834D43C8F07BCA2EFBBE95858F13
+:10E5C00091F5B256B35F03F8F694D5B86CF4BA4E31
+:10E5D00022DF047BC3A0E9821CEB943F7079F4F640
+:10E5E0007B0AC6650B7BF62DC4710E5C81E316E8D1
+:10E5F0004C799DE2E7453E5E5A0FC763DE27A42AA9
+:10E6000069F9DBF7096C7C0353FB3D65D07FBFD212
+:10E61000828B50B65F42E1FF26D85F8D7B6A3A4A13
+:10E62000EA60BFB8AC0C42A92E78682FCA4F3807F1
+:10E6300024507AAF246CDEADDAE34AC37A66E5A3F0
+:10E640002B30AE91E6717D73FD434F3D6EFAE17D57
+:10E6500057D67C5B39B009D77DD7FFAB3B92A6ED8F
+:10E66000BFF5922BE281769E90B3FCB76F0DEECE94
+:10E6700007BA9C7F22DBAF0BFD9E28C47E16298142
+:10E6800093DFA398C7F8EC55031BB09F55C4E6F77A
+:10E69000A5E37D0BFE283E799DF937257B9D798387
+:10E6A0002B1A4803BDF78CC9A9A746CE19703D7532
+:10E6B000FDDE0FEE3669BF6F3FF2E7BB61DC37FC72
+:10E6C000ED2F777F0FD6373FF768A06756DDFFFA4B
+:10E6D000DDDFA5E37DE709B708FC72DDFD6FFEE92C
+:10E6E0007B34FFE14FA71482DD187233FBF6F8C3C9
+:10E6F0001F17E9B49D1B9F9A370EC67FE363178CE3
+:10E7000023A7D8773C4EF92AE5B6CFD314B6A33F5A
+:10E710002180F2A68CC95307DD9E79F4995280EFCF
+:10E720009D836E8C0B58A5B3388095032B30FE1259
+:10E73000F2B0FE59F960379EB33A19CFE67831C48A
+:10E74000E63B84E2AE7CF4D2AF9D5B07A98C719C62
+:10E75000ABC87017F8019DEF8DD0EF254ABFB34EBF
+:10E760002E5F4518DE573DB881F5EBA0DF3BF0C7C3
+:10E77000AC93E937D39D4DBF0FEFBB329086C247B4
+:10E78000C7E4F4C75AF45BF1D8D74F792EE5B863E4
+:10E79000DE8E86DF56EE3797DCC67C37CCCF47F26D
+:10E7A0004C38DA70FC6577EA625A76BCF32FA5B074
+:10E7B000A83C260F2F84F937FC945B83FDF1454F6D
+:10E7C000FD41017976FCB1DF283AEA3FE213A81C4B
+:10E7D0003F4E467E8320D731DE1EF0738F3F0D7E85
+:10E7E000819537B7229D56A62E69D2F3F139FA0BDF
+:10E7F00056A618DFAF4CEDBB4CC841B7EFBB0B9929
+:10E80000DC4E8DE5F65B868E423DD0EFF07CE0B7C6
+:10E81000D1E8678D5B83719F6DA3A7299F723E1E10
+:10E82000EF774B0294F3737B96BDBD2A25FC81E400
+:10E8300098A7D6BEC5173D37B4D63D8ABF888FF797
+:10E8400074F3F8F4E3F962F85AE6D6B15D27DED640
+:10E8500075BA510EFFA9C68D71498765FD876BE9B1
+:10E860007C1C7E5E261067B1B0F60D59CFE167FEC5
+:10E870004FCA8FBA8D1F636DEF758EA3EFC56E669D
+:10E880007AC4B9BF13BBD945741B7EDEA50B2CD04F
+:10E8900017ABEEF6A4C03E75FDFCE585200756FDDE
+:10E8A000DC8F7260A57BF85EDC97FCB19BEC663C6C
+:10E8B0008776C532EED77BE6B1B558FF382D87FA9B
+:10E8C000EFFE3471F43B741CCBB7B1CAEF3E129823
+:10E8D00046E8BCBE9EFE0DFBC4CB9EFEDE57814FBC
+:10E8E000210FFB9A47C7C61F87F68FDE35A106FAB0
+:10E8F0007FE6B18FB0BFE30FE511D0AFC79F7EE3D6
+:10E900003CC0E79F1FFFC934907FCBB6C9BADDEF8B
+:10E91000B2DC7EEED9A65FAF1FD88CE7BFAE8772A0
+:10E92000565FF88CCF19B0A7A07FB04FAE7F2260A2
+:10E9300078A665D5C37656B9876F8AA07E334BC457
+:10E940007AA46F09D0F9FA3DD9FD3FE966FA7795C7
+:10E9500032BC94D54F96307E18C4F79EE772DC2AFD
+:10E9600077BE6FD5FFA5BB3CAB9EF5FE4A3789E766
+:10E970008A3B7C89B77BFD9E4FA764B7C7F8F6E456
+:10E980007ED8F3E35EB6FE5CF1B81FE9BDE2696ACA
+:10E99000DF4C83FC2F4B01BF2B9E5E8BF459E14E65
+:10E9A0002F04FFC6F0C36E0276CBDB0F3F8FE56FFF
+:10E9B000CBE9D242A8F7A4E730CC5B275C2B06DC7E
+:10E9C000FCF06776BFB05FC9FC7869DC3F72F17D0F
+:10E9D0002EBA928DECE671672C4EB218D7C5CEF5E3
+:10E9E00081572D23B9CE8B77C2BE03F8FB549368B1
+:10E9F00076FF3E617193FFE5E00B458E69B05E5393
+:10EA0000041205BCCA52AC07FC9272285843212557
+:10EA10005DA105E8D7E9ADD670FEA82AA3AF9BB6E5
+:10EA20008FF6ECFEAD18FFAF86A5F7B3F6975FF350
+:10EA3000619C1EA9B03D2F4717373EF755D3E736E7
+:10EA40007A28C1D6ACF3D1CE7DEC9F090C1FA6DF8E
+:10EA5000CDCE8512D305F3EECACC0608FAB75FB661
+:10EA6000CE674A1DACBCC02AEE60E57C9EAE6A61F2
+:10EA7000F3D049AF2B9FECC6F39A573E598C7E8753
+:10EA80002B7D535E07F9FB331E8F6616B8911E6708
+:10EA90003D19BDF49F68FE9AD64A3C7F543D10BD97
+:10EAA000682ACD5FDD3A09FD5C5F52193F7EA35FA6
+:10EAB00034654A2F94A100FF770484FF9BB0D0A057
+:10EAC0002F2E22BAC2164D29ACBF980CF8597E6081
+:10EAD0002CC499DBDE77F9E0FDD502EE635DF5FB32
+:10EAE00097E6012EFFF8D2914E48BFF92251F26805
+:10EAF000BF8B1ED5BB981B82B7F7246D4FCCB49744
+:10EB0000C123F3B7104945BC64F0A422DE5E1ED9D0
+:10EB1000A730F15CA50DCFB8AEB4F03C82B740F39E
+:10EB200057480EFE1F29F74D7E9D4CCBC0E5C4F320
+:10EB3000CB241262EBA35ED61F3F37FF177844ED5C
+:10EB4000868379FF2283FFE8650A3FC47BBC9C3F34
+:10EB5000793FBE27FB7A408F7F83A46578FF1A3206
+:10EB60002403FE9CF85D4C0C05CA979074172CEE9C
+:10EB70007EE48E5DA9523856BA62138BA0DFF02076
+:10EB8000C635911773DB4319FBC6E4F38EA7AA4A77
+:10EB9000D4228C2B41785B86DE4B005C2DB47BD07D
+:10EBA0002B1E62E96B76DEA3E5D09B9FDACBC948CA
+:10EBB00039F3CF8FB4A3F6E2FEBAAD5E96BCC67A47
+:10EBC00042AE7668DE163771729EC1E17CDEA2E647
+:10EBD000E3B9921C7011B308F067FDD8FBAF0903CD
+:10EBE00067C2F9FB1E756E630F95CB0F140E96A8C6
+:10EBF00034BF519DDF01F17C7BE97209F66F69BE7C
+:10EC0000D16C80BCB110D66D8B25CACAB6FDD75B5E
+:10EC100054E667BE45657E4E5A6E42F966C8CFC05F
+:10EC2000F82A12A679B86B214CE9FEEA83E5BF3ACF
+:10EC3000531F9D3E2DBD9FB9F51C721E2EB008CEF0
+:10EC400064EB7AF44B3E1731DDAE8C1FF88BFA1370
+:10EC50000B4904D32089626AC523844812D3123237
+:10EC60008069980C625A4A8631D58926323E67F30C
+:10EC7000A09C44305F490C4CF796513D10C4F3679B
+:10EC8000919D39E4FEB86BD8BD117FA57A017C8CCB
+:10EC900069B53CA71E70A9173574D8CF3FDDA7E230
+:10ECA0007A78EF3A1DE9603D4F73399556991F7791
+:10ECB000EFBAC8C118950F47EE5323E08F7FD54FA9
+:10ECC0009402DAEFAB9BFF50BEC897A9F740213BF7
+:10ECD000C775E2F04FCE84730F5B55639F8A70A4B3
+:10ECE000913F2D7E59ACFA98DFB9577EDBAE07BE57
+:10ECF000A9469F87F977E05FBC68E7ADB945403B1F
+:10ED00008FE802CEA76B399D1E281C780BE29DCDA3
+:10ED10002D6E1DE4E6B5BDEEC378BE3939CFB0B770
+:10ED2000F732E72392FC21EEB35E7B1A3FCFB51496
+:10ED30008DC067CE7608995000F631FA1C6CF555F7
+:10ED4000C2CED9518262BC413E5FCFB4EEFC3804E2
+:10ED5000715C6F73BDD8BA85C4408F1E13197EFADB
+:10ED6000F879C83754E6F7B6EABDCDE11D93BA127B
+:10ED7000FDF4AB95D8DB800FCAA759FE79F5620385
+:10ED8000CB8F2949BCF7A4EF4A76DFC0D486CBAF3E
+:10ED900007BD34B5F926B44F6E175221BCBFE13E12
+:10EDA00037DA0F73CE6C7E0FF7639A151DF03AB504
+:10EDB000593140DE7AC1A941FB997C711C4E6891A2
+:10EDC000B7CE4D9580DFB015E28CD0DF13F360BC79
+:10EDD000D013EC3CFD75DC7F78C79E0B02A75A6709
+:10EDE00003906656FC1635ACB2E44EA1235FE2A850
+:10EDF0005F9E553E1EC284E87C1FEF23693F4DF79E
+:10EE0000AE37E700DFF7B59008AC0B278062A2F4BD
+:10EE10001B4FE505DCA301EE362F4DC334AF166260
+:10EE20003971F1F2004D7789034D40D4523E7E4D49
+:10EE30001ABEB0B30CE66B8F10F7D9C73FACA291E6
+:10EE4000C2C75FC461A2ED1068B7AFB95683F29430
+:10EE500042D6003C779CCBE851DDFCE142A447C39D
+:10EE6000FCE590F6CB546F82FFA69FE8EB01FF7B99
+:10EE7000A62CC1E78AD602CFADF7AA9ABBA240BFA3
+:10EE8000A90D45182F77C15001B6FB16D00DCBEF59
+:10EE90005800E56E92CA877316A45924A0FFF74E56
+:10EEA00088FF7202B4AF93085D0982CB8E780A3175
+:10EEB00035FD85B0CD4952102F33351C45BD5C2C36
+:10EEC000B1E7741C868CE5E9729847530F2D7F07D4
+:10EED000FBF558F6646CC36CDAEE03F5228173C25D
+:10EEE000CFBEE2467BE1ADB20ABCA7E681C2C81F35
+:10EEF000CF077A7DB2AB14F6ED765EA510F0436EC7
+:10EF00000727157DFF8E4FE321F08F558495349CA4
+:10EF100063DD3BC1749702DFFEC685F204E8A1D62B
+:10EF2000229D483E4D77EE3CFBAA5FD0E7B7258691
+:10EF30001A3A709D19295E608B2FBE4D8E5C097147
+:10EF4000425FDBF0506390CEB7DB789CD00F3C2F54
+:10EF500074C0398FBEC7A84CA7765C9F157757350C
+:10EF6000ACDAEFA368F60859EBBD3E7EDF0BA918BB
+:10EF7000E6F136C32AF4F7EC2B6B43B00FDDD75024
+:10EF80005B0EEBE1EECDADC540E73B3E1D0E81BC17
+:10EF9000BC8D8F6F2A9D9E7329DC150D747C146FB8
+:10EFA000B72B8322C805F37182F36EEAE5FFD50C17
+:10EFB000F2C1DDF6BB0688EF69F31470FFEC30DEBA
+:10EFC00093713B9C7FF565E0706B6C3F76AD87F984
+:10EFD00023D778987C8873B8E95CCC920770FEDF01
+:10EFE00083FB075103F8777DDE57D1EFDFE6E1FBC6
+:10EFF00084EA30C6EFE5786FAD87B6A75E7695D127
+:10F000004932EFD1F1E3B9DFBE7367E2B89F7DE526
+:10F01000A310F831FB36EF2985F15BE37EEBD35883
+:10F0200031E0A1A299D1D51AC75489A4E1BE1BE24F
+:10F030008B94C37EF3160F936B5639A567F9D76D82
+:10F04000F4D8C2C779BB979757B1F732E5FCFD7C7E
+:10F050007E4EB8C259CEF0F3EC2B572CDF0DF3E8FF
+:10F060003135022E843B36B78500DE6E80D3978122
+:10F0700013F4138CEB4DEB5C3A0429533E0AABA41A
+:10F0800043ADCD25C7989F97D4B338454B9E8C6A26
+:10F090000786A822B7E1D9BABFE385606C37E0DB09
+:10F0A000DD3CA8801B49AF189A0FE93CD7C518EF83
+:10F0B000E0E6FBF4CE768F25E84A85AEDF6E4F5052
+:10F0C00000315E4FC3FC6D8910A6A9848ECF9FE2EC
+:10F0D00078F28A4CDF6C74DC13F628C793554F86A0
+:10F0E0001D8849103FC7F68DA5AA2EF4074815D6EE
+:10F0F000FD2F23FBDB4F01DC24963BBE8C16087CE6
+:10F10000BF7D1FF061D1656C5FB9A899EDB76FE164
+:10F1100074B7FC57163CCF73389EE770FD073879FB
+:10F12000A11F7EBF883BCCEF19B0EE1BE1E7194E63
+:10F1300081F7212137DE5F02F857240FCF2FD62128
+:10F140005E96C54F5AF1927F6D60F76D8DA6C72C04
+:10F15000BC5B74D8908861FEB6442BA681CB18FEA8
+:10F16000528938E65B84E861E82FD070EAF11FE548
+:10F17000F3F9CF1C0F9F779C777832FBEA18171CA6
+:10F1800064F785DC71E5E5A1C5F4F9871E7E5F486B
+:10F190005CC819B740E9F921C067EDEFC37E23CC05
+:10F1A000F7FF50A327501E90E4234B840C3CA75B31
+:10F1B000F71C81B85C3AEED7200EB7F2F4FB966BE1
+:10F1C0006FBB418175DBA742CCEDA5EF7F74EB5798
+:10F1D0004C70072DEEADC17D3E6A37AA5EB0F303D9
+:10F1E000FA8720E78939751EC4DFB6B8F5C7217FD5
+:10F1F000B84E9D07F1B62DE3F49B60BD71C946DFA3
+:10F200003C88176D99C8F4C0928D0D9DA0077EE5CE
+:10F21000310ABCB84F2C17C07E9DD37E3B793CD9B8
+:10F22000FB75265C00C2F8CAB4E391F253A9F7EF6C
+:10F23000E2278B8F543E8F35623F3741E7D199806B
+:10F24000178BAF4EC7476779191FD5F0F442AFC689
+:10F25000F50BE3230F97074E38667919DF6DE072DF
+:10F2600082CAB51EBBFCB3E461918BC4412EEDBBD9
+:10F27000EAFEABE05E38F79EC9E530BEA02BF5474D
+:10F28000B027C9034AED6E1B7FDDFFF1AE92053E4C
+:10F290009043A992DD507E3F2DD7215E391E82FD1D
+:10F2A000B9EAF0870BE17EA2EA0A92AAC4345D5E55
+:10F2B00046C719E4706EE5F5A6868B16839FFEEFB0
+:10F2C000A5DF8F3DD14B191F3039F50F68EF1AA01C
+:10F2D0000FC5AFC0D6577F5F7B14CFA84FC09E54D9
+:10F2E000B81D04570E9148E4CC7F04BCFF5BEF07C8
+:10F2F00048CC84BB5E02107F45E9E8EE5D4760BE06
+:10F3000050FEEE02FC79B6F69BA0FF56350CE07A73
+:10F31000C6E26B6522E337ABDDBBBD6C7D7937E7B9
+:10F320006FF8E9743E4EC63F58BE97E6A7C01F541B
+:10F33000AE4CE1E74CAA4812D7CF6792014CABC95B
+:10F3400020A6D3C830A611A2B920AD2511178F076A
+:10F350009A09E90D6AECC7A0927EE48EDD097CF380
+:10F36000CE84D83F43BCC6FABC95B3611EA6BC563A
+:10F37000FC553A6B5D4BB8DFFF74EBDC71C4B8C76A
+:10F380009B233E087EA39DA389D8E2BFAD73345F63
+:10F39000E03CC4A3D0DF49E721CED2DF63E71B56B0
+:10F3A000A07CB5CE336C1E7B0DCAD7C2B309FA6BF5
+:10F3B000FE7DE39A67419E4A17474D84E1A5DCF143
+:10F3C00070562A8F63F1651D05976B183FA6B2FD35
+:10F3D0002B89FB93AC7ABFF3EAEC7E32479CD93F92
+:10F3E000BA9F93EF378BFE1EE76FC67E2966A96131
+:10F3F000C50D1E477CF1F8384963F27734B8D6E77B
+:10F400002DACB79F437215CC6CDA478726E65D1D9D
+:10F41000B1EFC359E31DA9E763707DD1783CAABF62
+:10F42000FF1DE077C6E539F582959EE0F3E75EAF14
+:10F43000F11778CF16C7F6118C33471CDB09784ECD
+:10F44000F9F46386A76C3E3DA60C5EB98CCAF5D76D
+:10F450000BBCB87EDBF7E26F8BE1BE08A5C02B6268
+:10F46000BC07F7B778B99FA0A384F9A736A55C18A5
+:10F4700027BC6970AEBE2E08F1ED0A72DFEEAAB9A4
+:10F480007953C13EE871B1F3EADC8FA214EFC7F102
+:10F49000DDEA7721FC9B4EB4CF84F7CC7A82EBDD9A
+:10F4A000B9F586BE0ED6916710B4F75BC79CD896A7
+:10F4B00047F377BEBC0C9D7A0D7EE65FB9B35FE182
+:10F4C000F7BB1284E3E88CE8EE8D6599FCB2E0822C
+:10F4D000DD306F6A21B099D6FFF6864918EF06F73E
+:10F4E0003330F7AAE962FB55569A76B1FD2E96772E
+:10F4F000E23BC0F74D9CCF3FF5337D1B38F7B2039D
+:10F5000017D0F697B4E25D1630CFF715D37CB281F1
+:10F51000EA489A0FF4B0B89AA4346CC2D224D960E5
+:10F5200050CAD3E7E121B81384CCCA93B19DFC9EA5
+:10F530005D02AC6FBCAD2C6EFB24FD9EC7C69F94D4
+:10F54000864C17B64322266D3F9FB603FE9CD3BD63
+:10F550005F93C7ECC8243FE7B86CEB228C9B59B68D
+:10F560006D9C00F8B5EA5D98C7C6B5DB10F9BD170C
+:10F57000516CFFC8483EAE403FFE60EC6EB827D2EB
+:10F580001F52902F7C3B040FF8157C2926FC020D9E
+:10F5900031F46775D272F0632E23B152905F03D2BB
+:10F5A000C0CB4B015F147E702107B60A881FA9B03B
+:10F5B000F5EEEF001FCE4ACE023C7EBBFF53720633
+:10F5C000EDE7051F3BB719D04EE07D40813A76BE8E
+:10F5D0002ABF21F73807FCD97EC27C2E67FD5B77F6
+:10F5E000227E4AEA59FCFC9DF2407191EDFD0F7CB0
+:10F5F0008C2F2DFE72B65B9CC7D6B55DC5F7221F5A
+:10F600007B253A3EC05F582170CF86B8E33778EF4C
+:10F6100072A04E8C7C19647F247E10E8D45BCFB737
+:10F620007FC85033C6412F57302EEF18E757B381AC
+:10F63000DD83EAECEF591F1BC75B756213C0D3B7BC
+:10F64000FCB962E0971DFEE150B01ACA193C7D7EFC
+:10F650001FBB9FF2FC7BBF3A89F6E77A607191A0ED
+:10F66000DBDB61E3AAA0F61B9C77DB94F7F3CE0EFD
+:10F67000CA9B15E050A3F6F5539B9FED84F3577793
+:10F68000F5BB387D758C3BFA456AD27808513D7AD6
+:10F6900003F32F1E8B59FEB334FA0FEF9C136371E3
+:10F6A000A4CB458CEFD95EF75B15CE696CAF10111A
+:10F6B000DFFDA9F67CE0877E23580BF9C981059B05
+:10F6C000F2C6C2BD7E736F9D0CFC9BAC1070BED0A9
+:10F6D000BFA599781A08DFDBC2EF7BD0E69314C48C
+:10F6E000CB153428686F1444D8B9914D275C6CFD54
+:10F6F00051CFF6B7B4E4C1EF0191B506B6CED5C28D
+:10F70000777C8B119DE9DF00170D1ADFB7D11A95B1
+:10F71000AC78005AEE6BC57B7CD97D7A161C814192
+:10F7200031BD14EA87BC8717E7B37A45B548DFF4E3
+:10F730004CFABC20747929D827816AF1F0E2691962
+:10F740007FF05D028B7F3567293B013EFADC403A52
+:10F75000CF66795ADEFC08F0F181E128C229454BD9
+:10F76000C13F15A83F7A35C017D8FA071C4F00F6DD
+:10F77000912035B2E12DCA371EC9E3768461E3EFEB
+:10F78000FC3A769F21EECBD0FE5F5FC4EECBC8E79C
+:10F79000E7E1EE1238BF2D217C7F95D6B29FBF02E4
+:10F7A000508AF87D7E22FADD1E8441FBF93ED5DBCE
+:10F7B000032E7C7F5BB38EFB12C714D6DEEB17B231
+:10F7C0007EFC0D5DABA19EBFDEB6EF44FFFF751E54
+:10F7D000B3F3EE1232EB5CE8A718FA29CFE4F17C20
+:10F7E0000DEDF7E1FD851755433FD716E23E6B0758
+:10F7F000C72BFE287DF0F0399523059AD738830E64
+:10F800006E079F270FF37A5B0E68BF80389B39FF26
+:10F810007648053FD72E5F88DD135EFF3E9E93ED51
+:10F82000D318DC2571C65F25A16115FC7B4B7A04DA
+:10F830006D27DF7F83FD309DC343F8BDACE11E2DF6
+:10F8400005F356EF110C8863853D7F71260FF9840F
+:10F850007D9FB8B91A909DDFF0BE80F80B713AB465
+:10F8600032FCF4E943705731B9B347C03850ABDDCF
+:10F87000927ADA2EE58B3B291CA0775FDF2A929DD6
+:10F880006599F1A2FD49F1D47283887C15AE27FDFC
+:10F89000700069719C601CC7EEF0C0F3F0DED1DB34
+:10F8A000DDE887060606B84AF97B8BEB295CB45E77
+:10F8B0009F31DC0376E5EE1BD83DB8A5ADECF9E24F
+:10F8C000AD3F590B7EE2DD2A8367592BC34BE936E6
+:10F8D000F67C191FC7927A3A0E80AB91D197A2D6C7
+:10F8E000FC4C84FE197F1F5D4EFAC1DFAD4C880DC4
+:10F8F0004E06F91E271AC4F194F766F3AF35AECA67
+:10F9000011FC32F8F31B8A74C0C344339B7F2C3C38
+:10F91000B7F0FA95306EC07F1BAB27C1CDD0F4791C
+:10F920004B2BC37F653D4B17F3FD4F11CA611F156C
+:10F93000C603E50D8F63DA1BBA765040BDADE81003
+:10F940007BDCB2D5D12F2529C8251FC7E3EEE729D7
+:10F95000D940086C65F45F57E865F6C7B90AEE6BE5
+:10F96000F95A59BB0F8BD1EDA0C7CC8D6E8CAF87E8
+:10F970007BB375DB7AE1C8A72CFE74F3B9CA1EC04D
+:10F98000171D80807CCDFB795864F8366B997CAB71
+:10F990003D9BC5AF6E89287B404F17D417CE55408D
+:10F9A0001E363039571039FA7D2604B2F77B7D07B1
+:10F9B000D8BDA1A16BB3F14FC763C0FA74448E1ACE
+:10F9C00004FB2972EC0B43BD022AEFB4BAA2B920A2
+:10F9D0005767D8DBA7E5852F4A288F7D07A2E52842
+:10F9E0007F0FEC5800FED84247BD947F12CE3FDF18
+:10F9F00081B888F560579FD6EBE6F79882294E6A62
+:10FA000031DD0F29D5ED661ECB9B4221E045228DCD
+:10FA1000B03F34278AF753587AADB746A989557352
+:10FA2000FA14629A26A738F7DB5B537406E86DDF99
+:10FA30008158B98670EB3A4B354C2D78ACFAC95ADF
+:10FA400082F8F3FBC5ACF3AC56AA35FE2D6B1FFA5A
+:10FA5000AD7CF3A67F037C9EA7A03DDB2E0FE33D8C
+:10FA6000EFED8FF9C0E34CEE2F4895C0BD3DF7F99F
+:10FA7000993CB4FA23D597A17D0C2136305E42988B
+:10FA8000FE38D35FD50FF361AA61A29D3CB5222C4D
+:10FA9000B4A3506271819DC4D0414E9A6111F9ACFA
+:10FAA0003BD47513F0E3961EA110E4C396FAF22E30
+:10FAB000906B037122821C4D723939373ED404F5A4
+:10FAC00036EF13F13CEDE69F1AFA1F69FE430A0375
+:10FAD000D89373EB937128BFB3D287E577FE3436A2
+:10FAE00045B3E10522B399BD4C246E478B3C5E4C77
+:10FAF000C8653F7BC72E50C06E9BB87591097EF1DB
+:10FB000082AD0573400EEB8D54C4423C6088A287E1
+:10FB1000E6BDFCDCB46ED0E767C3BDABAC5C0FB335
+:10FB20007C672286EB6052CDFCF667F65F8AF71D94
+:10FB30009E79863800BD770E368E017BE368AB88F0
+:10FB400062E5D1942BCB7EB5D6DFF24BA90D70AE1A
+:10FB50007CC656116E6825BBB75D3006F86834FD6B
+:10FB6000F172DE19D639399443384F5D197DB245AB
+:10FB7000E3727C2BD727E121D427E11D549F7039F4
+:10FB80000EFAA49CCF6FB80802EA576E2B403BB028
+:10FB90007C878072BC7C2B93C74B43433D289740A6
+:10FBA0000F08197D45F513C6AFC173C88FDF21A4B7
+:10FBB000F020AA147D01EAB76C1B87F27349C818BC
+:10FBC00003714B4B9AA5C84E3D236F752E3FFB1A10
+:10FBD00044E4AFFC1D029E67B7E4EB445EAEDFC0B9
+:10FBE000F4CAC49E752847F51D2CC518B7A28CBE53
+:10FBF0003B0AC148142F13E303A827742E5F2DFA84
+:10FC00001029A29FEA3EF1CE1DFD73701DB1639FC6
+:10FC100020D27453708D02E71DABF8FCB0ECF7F105
+:10FC20007C08E11D87D93AE70666F71F2DEEFA2A10
+:10FC30008CA3AB7FB102EBD09208D343BEF0D27B52
+:10FC4000414E9EC5D79923E7EEE3AD784EC3CFE191
+:10FC5000CFAF1B36A0BDC0D605579C8176FBC078C0
+:10FC600041CFC0F9862F9FAD3BEA860C2CAF67A62B
+:10FC7000E1EE86680FACE3960445C4A9AFA71DE189
+:10FC8000A0EB1E4DB0F989FFD39787FDE7D7B37579
+:10FC9000D0E6AD6C1DD425A7E19B20243F22E2FADB
+:10FCA00047AC8F6D5B04F4A2EB535837740BD1ABA8
+:10FCB00060FD48ED47A63F824C1EF44D98BC13E80A
+:10FCC000BB65460AEF1DBE8EDB55B88EA076FCAA3A
+:10FCD0004D2DF3C1AF638DD3CDC7E90F3BC6599FFF
+:10FCE0003DCE45797C9CF5836C9C756C9CB47ED62E
+:10FCF000388F49695CBF1E8B106D9D0EEB295A1E13
+:10FD00008475E02379D05EA61DF3AB408700C5075C
+:10FD1000D021B0F51726D45B42DF83769CFCF00936
+:10FD2000E0692CBC4FD8BE7DA3D35E3875BCD3032D
+:10FD30008584EB4BA6C74ED2832AFB2E83CFA19797
+:10FD4000BCF96523F7DD985976F0C057908F1E14E3
+:10FD500071DFFBAD7CE6A7F707599C127D6E8E0321
+:10FD6000BD4053D47F039239C5E69FF2D565EB853C
+:10FD70006B4106E55A8FF275289106F1BEBFEE5928
+:10FD8000B199F6EF811CF4B1F5FA411FF34F760BF0
+:10FD90004306F2CFA8EB4F01E5422028A6BE4CFF58
+:10FDA000EC3E97E165CB0C11CF675D07F37506F864
+:10FDB000615EC375686F2BE547C4571CF7935BC73B
+:10FDC000A858BF6F063BCF3590DE897EAC8DA90F5A
+:10FDD0000F2EC6F5163BA7BEA7FFDE1EB807D65BE3
+:10FDE00065CC70D9E0CDAF1AC5EFE057AD7BDA0531
+:10FDF000A627AC94E90B2BEF7CCF0D7E179B9F477A
+:10FE0000D634D487917D7F3D08B1629D5A09C6AB37
+:10FE10002EE4FA79E49EEA949FF9F9D2ECFB03967A
+:10FE20009FCD75A89BDD6793F92EC2423FC8878698
+:10FE3000EC7B6C2CFF5B971C8F029EBA66A0C422E1
+:10FE40007EF0E3F8C07F41F240C4C9550B66ACB305
+:10FE50008DBF93FB9BE40605E9DA5793EDBF5BEB9F
+:10FE600067F78C7D9BC3EB2251BC9F5219647C4485
+:10FE7000E1C6F5AB5247500F5278D1FF492E169C80
+:10FE8000E7496FF483FC4CAF3761DE59F05AF43A1E
+:10FE9000DFCFF68BFAE4E19086FA2F1675B1798BF5
+:10FEA000FEA84D7583682C75C98C7FF2B7BA09C05E
+:10FEB00021D6B3EF468DE7FE8BD757B073DB5BF8E7
+:10FEC000AD39DED0E52AE8876E79B819FCE7961CD3
+:10FED00072CA1FC013B4DB9972A17EEA24B124FA5E
+:10FEE00009682B20CF06A4E85740CEB4D469113B53
+:10FEF000FE16E531BCB400FE7C8CCFEDF7ED7E97AD
+:10FF0000FB755AB89C9039DE7066D9EFA5AA66F7E2
+:10FF100046485BD97A5885FB46C50C3E6DF4BF1B3D
+:10FF2000E9DF949BFEDE3C86C74707CBF1DEEED1CE
+:10FF3000EC55CB2E75DA9557FB74845793A81D5951
+:10FF40009BB1332DFDD82DA4FE781ECCABFB149DA8
+:10FF5000C5E9C6426087B926FB302EE70169C05B60
+:10FF60008BC6ADC9EE654A733E2146F43BB4BEDC98
+:10FF7000E3C2BCBC43386CE71F1BBF3BC77B39F8EF
+:10FF80005F9CFC648DF7F23C26A7B41365C418632C
+:10FF90005B1F348EF80B04B0AF5E9F43103EED4400
+:10FFA00005D6CBE1BF29037BD1E9B7216408E5CCB5
+:10FFB000FF96BFA6ABB848003CFC2FF86B8EF94FFC
+:10FFC000E1AF210E3F8CD37FE3F4C38CE6CFB1FCCD
+:10FFD0002FF0B3FB719CFE982208C09C04FE9C7617
+:10FFE0000FDC877D8CFB010F6C7A639E19CEC49168
+:10FFF000C86909E1936E6074B2E69125572D399B6B
+:020000022000DC
+:1000000043AE4ECA3B855C9DC4E7EFDE757CDE04E3
+:1000100089047AF581077FA142FCE9442E1F47F449
+:100020002EE85B9B7EF583BE9D767A7D9B6C2438A3
+:100030003F0AF9380A86595A38C4EE332B2032A6C3
+:10004000498934413F054DD9783AEB09A71DB28E55
+:10005000F9CF55237809F04B938871FA671FCCAE1E
+:10006000D754F66CF0524A97C279622DDB0FE0EF5D
+:10007000F9C8D8CB805E8D12BE77CEB1ECF732F6E0
+:1000800031AFAF31B8CE3F719A7A41E6CF77C27FB8
+:1000900081EACE0D7FC818FBF56006FE2F87B2EB14
+:1000A000352F7A76EC15B9E00F93A2E6BA0CFC175F
+:1000B00055B94F0D97CEE0FF5AFD69EA55E486FF2A
+:1000C000D2A651E0AF2217C279962B9A4FD32EA712
+:1000D000EB375A4F5DEF9B6DCE7E4CB63E098A1EC4
+:1000E000E067779A7DB7442632A6EE617E1F9E2692
+:1000F000A35CB3FA91C3D9741A9D7FCCE0823A5CB9
+:10010000B7639CB1930F2EAE91914FDC6345F6DD42
+:100110009B11FEE1740B32FC9F962F38FF38F9607B
+:1001200034FE71C2EFE48B0CFF98632F0F66E0770B
+:10013000F201B5EB907FE4704564A3FD3D8B7F82B7
+:100140008CEF4ECB179C7F9C7C90837F901F9CF004
+:100150003BF9E3FF1B5F6832CA153761FC20EBFFF8
+:1001600053BE48072FB5F18593BED139F390FE27D2
+:10017000F305A707E78BD3D29BF38593BE9F972FF9
+:100180004EA6B7C5178CEE16FC4EFAC6D67D5B633D
+:10019000F7E98CF0C3E7A3AF4EE9EBFBFCF39DD886
+:1001A000E12D3F99CEA7A72FBBEF4CB3E8AB33FAB5
+:1001B0006A1AD3177284A5DD167D8DCF47DF6E9541
+:1001C000CA7FF4B732FC38E974D9259D4847CD4140
+:1001D000DF6E1FC72BA7EFE9E8D6CDE97B3AF9DC44
+:1001E0006DD1D701BF936E23F561AD16CCF88B9D11
+:1001F000748BAD933D76FA7687E34D9F876EDD9FD6
+:10020000733E12239BAEA3D1AFD51D4F631CDB38C9
+:10021000F6DD1F775813ECF7F08E0F30FBA2086C59
+:100220002FDA6E6B5EEEF3A67A80C5592CB4EA0520
+:10023000B2E398ACB492D7EBE7F55E81742C9C677F
+:1002400088B6827DF3C83EBD7881EFE4F1DCBACE9A
+:10025000FA8E972E2CB0C587CE0EB075CEAB098D19
+:1002600018B6EF25267B6BE6831FA73039A70BD284
+:100270006B7BC7102307BE0A4E4C42BB3CD35F8A40
+:10028000F955E669B8FF5D70623296BF9A50B17D4C
+:10029000E81FD6CD27B79F374AFBC5A7693FCCD605
+:1002A00005F407E77CACF82757E0C9B7603DD919DA
+:1002B0005674F06358E78B9CF8A4F2869DFF0936CC
+:1002C0001A43367A7F9DE34586733DF07D883D2E47
+:1002D000663F3BEAB58B565C7A2C64C7EB359C4E87
+:1002E0006A4AE27E9758C87E0E21C9DB6F17220743
+:1002F00063C0E713D87DA9DDE766EF0BB40698DF8E
+:10030000AD2330E25F44BF83EC7BEE20F83F652BEA
+:100310004E2C2865C589B58B7CFEAC61F67A7725B5
+:10032000B9473C0BE305314EB38BAE43F0FCA7A0BD
+:100330005AEB2D3CDF6BF93FBBF7517B16FC9D7EE2
+:100340003105FB7CE325B2DF0DE71442EC9CC2884B
+:100350001F6C219B9F5DB710B39CB6DF05A747C1FB
+:100360008FB188EDDB767DCAE0E85AA2A770FFC99D
+:1003700030F46051E6DC1CBC577816C31FD0EBAEDE
+:100380009052037E6A6BFC567FCE73541047436CC9
+:10039000F16EA3E18190087E7F49F6291AF8734E29
+:1003A00087B7D6009B4FD70474C4F7D45D0ABB3718
+:1003B0007CBC82F7B958742CDF2061DCDC5F8937A4
+:1003C00002E36C2F88BB2114BB9D2EB396DBFCB2DD
+:1003D0001D09BDC11E9FDB314A9CD596422627EEE2
+:1003E0002F60F7F1ED155637DBCFD5E515303E38E8
+:1003F000C1F98AD44555163FDAF15BB80FBB4B13F0
+:1004000075C05B4FEA5AFCBEC3AE90A8093AA40B74
+:10041000D4EB701D206AB007BA2BB41EEB9BB43E20
+:100420008C67BFD682E7B33B7AC5E91007450974EC
+:10043000714D51665DBCAB516474AE22A94A3AAEAF
+:100440005B1A6B4BE0BB9293B5C2396C332C2E62B6
+:100450001CF95642B6D3F2FD9B15BC6726A9F9F0EC
+:100460007E03DFD641037C25BB04E2A9C0752FB310
+:10047000C7E6BB7C98DF5D2F61FCD5BEFECB5F90ED
+:10048000693BB71822DE4B10E0DFED3B14607E5372
+:1004900009BE4F47E9B5AB5FBA10DEAB3AA302F92C
+:1004A000674FBF82F7DDEDEAEF2A417F7D43F6FD1E
+:1004B00035FBE6CC2C817D205F5DF6F35D57464B26
+:1004C000F0BB8C27DD8341396B66E6DCEC81DB1504
+:1004D00001DE77DE5FAEF5D460DC36E9F5E1BDB56F
+:1004E0007FA0F314F685F7888688DF43FA133B571D
+:1004F0007DCF2D5D59DFBFD9176474EC4D904A88CC
+:10050000BFAC2A13A3201FACEF0EFBF8F7CE2D7A59
+:100510003BD3F20D8DA7BCB75C5227659DD3B4F8D1
+:10052000CD171914E11EA8498F6A357914FE49BD0B
+:10053000FA134314CEDD534B6BC07564F1DF73B710
+:100540005F7ED572FA7CCD5E463FEF2137DE439069
+:10055000C7E32377EFBB92C0BD29796DC14AB84785
+:10056000D1AB1755C2FD8972248DEB715F9B520987
+:10057000F777CD7FA8FA94DF3FDA98D02AE1FECA58
+:10058000AD091553EBBCC9971EBA18BFF7F9DFCFF9
+:1005900030E3C300800000001F8B08000000000053
+:1005A000000BED7D0B7854D5B9E8DA7BF6BC929957
+:1005B00030934C92C98BCC8404120D38098122628D
+:1005C000DD2401C2C376025183220EEF008104B400
+:1005D0008A2D1E06089040D480E1795027C458B473
+:1005E000DA137A142962CF0868D16B7B22B6542DB6
+:1005F00072025A0BA8185BABF49C56EFFFFF6BED31
+:10060000CC9E4922787BEEF7DDEF7E277C7C3BEBAE
+:10061000BDD6BFFEF7FAD7CAD75FC3CF4D8CD91D61
+:100620001263C98C7D2DD2CAAA785FC3C8483AD953
+:1006300029FB4336063F2177A53D92FF0AB61BC52D
+:10064000D866895577DA22F9B1E5AC444D9BE06272
+:10065000AC7DBBC9B11992E32B4BD297943076AEE7
+:10066000D9E4307B18EB7870E843B3201D7CD3C00D
+:10067000F2A0BC63FBE8F48585917EDAB1FFC2BECF
+:10068000FD178A79EF4F0BEE917CD030F8D1E4372B
+:10069000DC90B606F7304CB3F7791AAAB1B158FE20
+:1006A00087C92ACC73BF117E4F67ACC0F12F9383EB
+:1006B0009876066F971D8C3D64FD5DD3F1EB219D0F
+:1006C000177C5782F40B492C5C3E06D25E5EFFF12C
+:1006D000475C8D4198C7FEE13CFDC42317A87DBB54
+:1006E000588FABCDC418ACA7BDAD219141BDD6CAC2
+:1006F000DCC11EF89E2B0AB919F467DEBAFE842508
+:100700000DEA49BC3D630B2B542C17E9918E05155E
+:10071000D8DFF8CADC9DB3005E5BBB8C3E84CF396A
+:10072000A3A309D3ED009FB550B53DCB9FEEEF07D6
+:100730001ECD6BDC79CDB0B606FCE645F2ED3E771A
+:10074000DE33F98C7EBE86FF464774BA5DF2A7237E
+:10075000BCD6C3F80ACCAFC3E827F8DDDD72234F5F
+:10076000DBFDE9088F792DA3783A59CC3F38BC02DC
+:10077000E1D991C6D3531D0515089FD879B41B7DC7
+:10078000E9BEC2AB9887A8F77FBA8E81E070B5E367
+:10079000FF7FDCFE769FEDCAED5F17F43A603FDE27
+:1007A000ABEBE71FC5C7FF69FF7FB7FD7A470EEDCB
+:1007B000F395F181117F8D935900F9FBF6AA52EB65
+:1007C0001C1D9FFFB14BE6FD603DE4F34C95FCC062
+:1007D0001BCF354DB206005FB7B2AAD7CD4318CBB9
+:1007E0006FCB4D0840BBFCCAE97179C0271B5CC8C0
+:1007F0006DE1FBB7F59629986E951DEB3C50DF0136
+:10080000E5C0E75A208D2CB1C5556AC5FAC166D935
+:10081000877261834BB6CED38D0FF52A502EB5A8C3
+:10082000D3A3E44587901720C9C266E86F536ECE04
+:10083000BECDDE48F96A17C7F3D6C619EFE643798D
+:1008400043B34C6B3EBE7DE2899B60BC0E87EC31AE
+:1008500043FDE38EE2CD63707E6E9999A17CA8631F
+:10086000FA9402483B2B649F077B679ECA02A877D5
+:10087000AD3970E226E847C9903D41483BCBEB6576
+:1008800006E941AD8C25A1EC684E642C8531878545
+:10089000C37623F3975A715D6398AF03D22FFB6140
+:1008A0007CE4F73E16C271E1C75E341ADAE26F30BB
+:1008B000D0C47FC9B4E6427947399F87727AF2057E
+:1008C0003682B1729797D691D43D671AA6B7B616FD
+:1008D000BF9E0FFDDA6E917DD82E719A72AEDB123B
+:1008E000D9CF8471D169A6F82B71DCCDB72828C384
+:1008F000998D41B9B6FF5E5C9FAEBE0E7EC97E4B40
+:100900005EAEAE9FF87C4754FA274AFD7F3C80FBE1
+:10091000D865F005711F3B155A5FBB838524E8E756
+:10092000DC2BEC09761DC8DB66BEEE4DAA2534CC67
+:100930002BE420C265AB12823D641DAFB0C3586F7B
+:10094000EB2BCC270D228053B963636208E77BE071
+:1009500059134BC4FA765B280FD21FADF18D6B4053
+:100960004469D949F05E62E1F033C82D3E0678D87B
+:10097000C4D41C6660ECC44F97B48C877157FECA10
+:10098000E043785EFCE9143793116F6FBB1DE7738A
+:100990007E9F9D19681F1C33E743DA91E8F6A1DEBC
+:1009A000D2807AC3585A669041DF4BA12F2EC75987
+:1009B000D0027878CEEA998D72F325D7ED532CA02A
+:1009C000473C1BC7CB9F6B9DBD39380EF486B61BC9
+:1009D000F3510F58BF6D7C93B508F40FB3E82FA8FF
+:1009E0006C1E0FF87A4096B4FE55067A4727EA1334
+:1009F000949EF67A39ACDD216BF5276C46B95B73B2
+:100A0000CC24C64F8F1B0FE5074A1D23DDD06FAAEC
+:100A1000CB35C59285FD69F30B594AB17F136F9FA2
+:100A2000E00A55E07C8A86749EF921ACCF7C9FC990
+:100A3000B78F89F1713FEE35EDDB27F5D52F2E27E6
+:100A4000C9C40F3A4B5805D217CCAF3AA4A33B7F89
+:100A50009281CA67896F67E846D903F31CA23015F3
+:100A6000F907C02C691AD2D783FBC66ED6F1A96AE2
+:100A7000671CD5AF31B37AAC77A85BDE42F8D2EA17
+:100A800070E23EC8ADFE756721FF726222D5CB0BC6
+:100A90004F4F9750EFDAFF567121D40B3E6723BDBD
+:100AA000F1E2FE197B0C38FF463333C0FCCFD96D21
+:100AB000D54F42BD0DA16BCB118FB4F1AC627E9BC3
+:100AC0009A8B3B57C17C2EDA6C0EC98378EBAB4610
+:100AD000FCFA89CDE4084AB4FF69C8CF72E510E991
+:100AE0003FF76C7DAEB12113D2028EEF271D6E440D
+:100AF0007DADC9EF8B9310DF336586ED36B9A65B0C
+:100B00008098D8A3E357D277932B27C306E54DAA45
+:100B1000C9C3A0BC653CD797DB1475BA17F2DB5A82
+:100B20005C52D013995FBC80733BEAB0B83E172388
+:100B30007A78DA097801F37B3A99B5AF07B8981D4E
+:100B4000AC18D765CCAC57D57EF4EF74D10F031D2C
+:100B5000D8369A4882E821A5FCD48F905F9C3775DF
+:100B6000CD5C84F072C6F9F6417E87B52B4D82FECE
+:100B70005312E3645C472AAE0640D520B3A938EE91
+:100B8000864CE6588BF98DE6A001DAA7349ACFE2BD
+:100B90007703D231EEEB7C16C2F5A536CB67CD09D3
+:100BA00050DEFDD91A1CC7DD2A874D587F968979FA
+:100BB00074F2C57DFAC2DF59024E0FF2757C26250C
+:100BC000C1BFDD097CCD9CE99002369EEF86F9C756
+:100BD000B1DE1F3783B44924E29AE5A019FA7F7683
+:100BE0002DE70F9BD6B210E2EFB9E7D933081F9378
+:100BF000A5B9CB9040ED2DAB8A75705D0D7085F178
+:100C00004C8D9B56E03A4CF9BA79C0FFD349290480
+:100C1000BF4CD62D21FF7854D839C43AA1281B7176
+:100C20002407E1184EB801E1F8805C8C7024DB03E6
+:100C3000E6872C0BCBB5FD38E8E47227B61F8FE8AA
+:100C4000474B3F2EDA1D389E3815F1FBF1606231BB
+:100C5000B21AD8871A2ED778FFC9D80E51D911A742
+:100C60001620FF4FE2F6D081B8FA1A7F3FF8B02382
+:100C7000898FBFE135D85880CB81759EBBE720BCFA
+:100C80004A6586F4FFB2CAF7F15C39C821849FCA6D
+:100C9000E1D9D2CA4228D746FE4A6992613E99E319
+:100CA000E544CE1F0186305F3BFE024D5B7C7E46F5
+:100CB000FAA18BA9D611480FFE6A9C07531C52E576
+:100CC00070A27F26C3BCE3457D7B797005E2478B2C
+:100CD000C56175A0BE90E99B928BE335498E7D047A
+:100CE0000CBF5C698FC0C526E012DF0AED603F6D66
+:100CF0008D128D83FD2272276039EC53BCEBE07DB1
+:100D00001296ABFC3BA82A1AEFEC63A2F779AB80F2
+:100D1000C7DAC438C28B96655C0E13BFC47D5DC252
+:100D2000F129DE17DD4F86C22A4CC5086F47DA7CF1
+:100D300084E36633C3FDCF0E46F79FDE985A8AF8E8
+:100D400097C974EDA1FFBF399DB41FE927F64E97EF
+:100D5000611D1D354C3600D264B0A05A53CCF70744
+:100D6000F58D4D2932F59BE14A2C453A02B854786D
+:100D7000213F3DD553ACE7A346979F1517623D47EA
+:100D8000E950A8F79344BE7FB04784E719277AEE6D
+:100D90004678A7D746AF83E9E9CF70E5B4D1921082
+:100DA0008C877E8C31747B31D1CBF98DC00B146F65
+:100DB000C86F403230E4A317137CAFA3BE15BC57F5
+:100DC000F175403EEA66993047E333723015FA33E5
+:100DD0003FC3E9D8D8A904872590B8574D589EF944
+:100DE00095593FDFFDCF8F4B47B9D26EE474641045
+:100DF000FAA9068703892682EB8144C1FFD821A284
+:100E0000977BC55C4B5FC82C437EDC91C5C8BE3E5A
+:100E10002FFBF7C4E3BCDE35A3EE08FD17AEC772A7
+:100E2000A70A7A870EBE9B947A8BB390961492DDB4
+:100E3000DFFEBB01F51ED8DF76A1D768F91DE1758D
+:100E4000CBE7305C4F70B403D6E10CCB9A5E8114D3
+:100E5000A9D70B821690DB0586E0BD8B411EBDB97C
+:100E60006DF9648715E53E137AC1BCC92AC8A7A2EB
+:100E7000F592687F4713A6237A00909D25A207303C
+:100E8000563FB906EB676AED674E5601E89D162D91
+:100E90003DF435F44F34183B47A3DEA23A438DA806
+:100EA000D76CB0FAAB91C77D96F4F964F467687AB1
+:100EB000CEF9472E3705A1AFE186AE6B2C507F47A8
+:100EC000CB754DE559489FBE38BFFDCAF069577CC8
+:100ED00071B8FE76B1FE0989C326AFCDBDF27EDFC3
+:100EE00081FB0DFB9C95C8F9DF7003D72362F9DF06
+:100EF0000AADBCDD548F7A4BE9301BA7F7076F7D35
+:100F000002E9BDF405DBEE78E47FEFCC3462BA2E63
+:100F10005111F8E3790CF3DBDF31939E8CF638CD79
+:100F2000F3F9590CFD3CC690490DF583178B120B54
+:100F3000080FFBAC33CF4674B9FF795B88C138CF5B
+:100F4000AE037EDD8F3F279828F8F51A803D119378
+:100F50004F4638E626FB55648643DC81207E4D6093
+:100F600087A9FDD87FCAE50CA62645D26D0E95E669
+:100F7000AB5C1E4CF9FF64F0AF4B84FEDFCFDDB7F6
+:100F8000780BB4DB23E4CBC4416A03E6AF97D58783
+:100F90002BBC7DE7A57D1BD678C6A14EDC9B36F623
+:100FA000EF077C7C1087FB3F6017A824AFED71C46E
+:100FB000C706B40BB6B97AED02E27B1BE4509EF78C
+:100FC0001BEC8221451E941756438B05BFB9B2EF27
+:100FD000E1F15EB40F0E5F7C1AED83A7E2C93E68B3
+:100FE00090823F5D85F68891DB033549169A3FFC78
+:100FF00078513E0D6C17EC6CAC28BCB25D104B2FD9
+:10100000C52A237C5214568EFCAF0CF938C0CF7819
+:101010009CEB558A07F86402E79BF8B5B87C244F2F
+:1010200035BEA28414AA67380D7A1A7E9B3792FEC9
+:10103000A338FC0CF5A915A6C031DC5F608B0AC291
+:10104000C3CAD7C20C3695050A07E617DDDB3C9309
+:101050001B61BE86E37167A9DF301FDF707AD3673B
+:10106000A83FB1E7A2FB8371FE1DC7B11CF287E365
+:1010700075FD6BFCE9E0B6C19371FD9D213BF5FF69
+:10108000D6B6CCD782B9DFD07FB84FFFBFEFAF7FE6
+:101090008D1FFE725B5613D939D0D20C30ACD9C932
+:1010A000EDA937B7654E5EAB7CC3386FF419E77CAA
+:1010B000BFEB107CF35FB7799B70DECFAEADAFEEC8
+:1010C0008F8E1312B99F2456FE1951FE1573B997CE
+:1010D000AADB4F33CABF1103CBBF54C407E8AF2606
+:1010E0009EF3B9233D72FCBB642FA53811F53A1568
+:1010F0003FD9B18ECC14692DD26F121FDF11BA9374
+:10110000A13F5A76793676A35DD25499CEF47E7695
+:10111000B49F906EC07ECA23FBE934B7AF9EAF6523
+:10112000799E881D7571FFDD16C4A38093CBD9D439
+:101130004407E1A7F558718071570AC14F93FF43E7
+:1011400007051C49C928EFB97C37673229407A2C3A
+:10115000B7AFFE513BE70127E72F1D56DF944968E3
+:10116000BF94CA0EA44FCD4E01BBC08A7AE5A6ED4E
+:1011700032D9B9BDF689B05F347BA841E67C646B97
+:10118000ABBC0FE1760EE66505FEB2B5B9F82DB43D
+:101190005B37D42BE457E963C7B8C0BE81FE5A1A47
+:1011A0000D53C98F037612DA41EEF9D1F592070596
+:1011B0008A100EB67299F4D68EFC7D641FC6DA1DB5
+:1011C00057D25763F5D0587D33735574F9B7D7F7B5
+:1011D000B8BE76B57A1FFEF4A7EF91FE497CC4DC59
+:1011E000847A04D96790BE9468263D4109737C5087
+:1011F000900EF18BF48774006C14E501D05D7512CC
+:10120000F2A95A4941FD4DA347748FA01C8CF53FAC
+:1012100068DF694E93D003A2F96AFB83430723DE9C
+:101220009D337A66A39DF233E1177D4E7C0BC47922
+:1012300092567E50F84F0F0D507E58941F11DFD8F4
+:10124000F25F8876E101DA1F15ED8E0FD0FE55D1E1
+:10125000EEC400E5AF8BF23706E8FFD7A25DD700FA
+:10126000ED4F8A76BF19A0FD29D1EEED3EE55CCEAB
+:10127000BF2BCA4FC7F47F46D4EF16F9850E0FF780
+:10128000670C704EA6D9AB9887F621A95C4322FB68
+:10129000F96F4E59F89781464747EC408D6F384BB0
+:1012A0005808FD129A7DA9D981EF39F9B8B672B004
+:1012B0004729B393F0A6FD0AF05993C4F9EBFEE178
+:1012C000DC8F8C78B3408767EB938CBCBC88C321E0
+:1012D000B2AEA1B2B62E19F2B7087BBB50F8C7F771
+:1012E0003B23FDCDD3F55727FC51ED57C0ABA5628D
+:1012F0005EED57D8FF1F613D5D7F03E1615D4CBD31
+:1013000081F0617DCCB803D1C5A2987A3F15F53A3A
+:10131000C5F72E2187AE840FB178D52EF4AB829617
+:10132000579AF07CB1FD0AF4719F5817FEE8FD064C
+:10133000B66699F02099F544E14702EB223F8A8690
+:101340001FC6CB5EA68EC434974FCE240FCDDBA82C
+:10135000F819EAFDC6CBB9549EB71F4C7A904B1BC7
+:101360009E87D9C337AFD52105A07ECBF3C02021FE
+:10137000ED740D35A1BC9AABDEABA2BCAC3DDEA5D5
+:101380007A1322FBAE0ABCBE921FB6F689776F971E
+:1013900074ED260979D7ABEF3D746B941D12CB0F1A
+:1013A000EF48B4D038FF15A7DE827A4CCD20EECFBF
+:1013B0006365CC81FA34E85F12EA0F1DC98CFCA08A
+:1013C000B20BF407289F9B696293D0FF9AC4E11483
+:1013D0006665B622D4339AB93F4AD31F0A0C8E3FB2
+:1013E000A3DF9525593C28BF51DF42BF087C8F9B66
+:1013F000E15BECE4FBF12DF42DD599DC57DF524590
+:101400003FFF8D7A70AEEBAAF4E0FEFDE7DF420FFE
+:10141000F6B9FAD5839DD7325893BA357EB327AD46
+:101420006FFF9A5E3CDAF5E889E037E9AB7DF5E2DB
+:10143000EFBAFA81DFB73D1F682F117657BE85ECF2
+:10144000AE2485B9938AB1C3693E3C6FFB9B83F39D
+:10145000AD2B9D335DE95CE94AE749B7B9ECAE0FC6
+:1014600071213EE6433D64E2BF146EAB00FC5CF9C3
+:10147000A681FC37AB5AEE35E3DA63F15EB10C19A5
+:10148000D700BCA0750DF46F8CD8A79BD738280D5A
+:101490007ACA64C4F3B887129D6837FE9B38CF7C44
+:1014A000B9999FA39DAB9279FCC589ED15782EF96A
+:1014B000B9CACF2DB757AD9B8E70696D34F0738666
+:1014C000C6F58D63209D3F4176183C7AFBD89DA7D9
+:1014D000B78F87B90248D9D06F29E97D0D7F2BB32B
+:1014E000A0DCDBE4981E877AB9769ED9D1CACF39C1
+:1014F000B75641BEEDCAE79CB1EBEE7688F303C662
+:10150000CF69AE3D36B312E36FE6362716593DB4C8
+:101510006EF2C79A05FF515619F23E007E968C7AFC
+:1015200031E0D35C87CAF05C435965E2F94CB73FC0
+:10153000B05FF14ECE0FA18BA094487C322F57DBC9
+:101540005FC3C0F4A9D1A346A71A5DEAE87107D129
+:10155000E3AC687D4FC35FEDBCABC4F56805FA85AD
+:101560009E95B81DB9C7F5CF8D88AF460FA37134CE
+:10157000FDD088E38DD0E999A7CD443F465790FA36
+:10158000D38DDB41E39E60FDEA99DAB9DB16D75EC5
+:101590008A6FD9AE04A7D3794848616827BCEC9A12
+:1015A0005E81E7382D025F5A4E18C98EF81CE80696
+:1015B000FD3B786E1EE8679F34FCB00B79188B27D3
+:1015C00073857CE940F90276C8DC4667B47C69BD66
+:1015D00095A17C31A27C29EC2B5F4638391E8C709A
+:1015E00072FB4C9323F198C6F52ABE7C5CDF7E63C8
+:1015F00090E24B8EB6DDEB26BBF0E7816C473FF304
+:10160000EDC5BB411E215F8356F4670103B2CA6377
+:10161000085E3609E057DB0BBF15E477FD81C09DFE
+:101620005A3CA786F12718B8FF2BEE0989CE1996E8
+:101630000615DAB7DAE0BA15E807077E44F2CFFB01
+:101640008491E1B93D94D33E6AED97769A5958C793
+:101650001F963F07699D7DE365CDC417170398C2A8
+:101660003ABEE3C573F3042C8FCE67865983100FFF
+:10167000AC08F4B4BEEB5D75BAED86E3BAFE2F6834
+:10168000FCE83BEC3B642F89F603C1EBCB35A11B97
+:101690008EC33E974AEAA7C897191EE65FCFD84384
+:1016A000D730B24F63EBA31B09E13B6F55197B1F8A
+:1016B000E8EFA0C9315E41BBFC3189FC06EBE2BF1B
+:1016C0003B51413FD479181AD2F3EE5F3A12E974D4
+:1016D00079574B5902CAE166A908DD5DDB8FD61741
+:1016E0003920DD73A7ED46D423984DF5E03920FA73
+:1016F0009A51DFFAD8C8CB8377DA8A506ECFA952D5
+:10170000DF41FC4835AC286A41FBFC6FB03AA8BF0A
+:1017100040ECE60BAD95260FE0CB2225FCB204F39E
+:101720009E33CB3306E139A7D3AAE237D5C4142BB5
+:10173000C8873916A6C4C137358E5928AD300BA6D7
+:1017400047AF637721BF4B18E337CD81FEE71CF924
+:10175000F15FB8B21E227C9C73E4B5BFA21DBE40EF
+:10176000F59B50AFB876BF899FED08B80FEF8C4E50
+:101770005F77283A5D148E4E8F3C119D7E10610F6D
+:10178000FF5FFCFBDDFFF100C0B3E75706D2B79661
+:10179000023BFA2EF0B183D7802D80EB5642837145
+:1017A0007C3063591CC0E7E2D3768A1FB9B4C637D0
+:1017B000AE1C007BF4BC4CBE9BA54FDBDBD04F7C4A
+:1017C000F0ABF71FC2F3BF9E67E3E91CB56CE933CA
+:1017D0003FBD1FD21F3D15EFA4F882DD2F3C86F8D8
+:1017E0007CF1D9610C59D647C2CFFAF2BB873FDCF6
+:1017F00003F94B7E1A5F84F53E7AF685A10897259A
+:101800003F796930C6D95C7CFA27A329FDF45323BC
+:10181000F07BF1A91F0FC5FC8F849F22F8B4B90D8E
+:10182000F76DE933D6B34900B70F3FB1D9F4E7DC20
+:10183000DAF76AFB5D8AFD22FE60BF4877CF6CEA6B
+:101840004A427ADB6F0F26E9F8CA92FD5B3ED3A7C6
+:1018500063BF4BF6F3F90C5CCEFB5D02901E037088
+:10186000FFD0C8E5D8D2FDE6A8FD1AB62B7AFF0A4C
+:1018700042D1E9BA4BD5539C304EFEA559539CD06A
+:10188000DF2521EF62C70B24733BACEE5074FF875A
+:1018900095FEEB2F4CE672311F4F98757C22DDDCF4
+:1018A000FFB942ADA8FFF4D3BDF50DDC8F0264068D
+:1018B0007AD952416F2FF6C625B17B3280AE968A17
+:1018C000735F2D7F29D3AD8FFC2ABE41E85F7689F7
+:1018D000FEBF3402FDE07EAD098CFC00F8C9876BC9
+:1018E000EA0BCA75FAC5A2BD7336A6C1FED51EC8DD
+:1018F0002BC2E1B5FC6B3A8D24776B9F3A9680F250
+:10190000E2E2FE633B16203E761A59BC87F2533062
+:10191000FFE3CE5712EE80FC45BBBC457A3D66D155
+:10192000AE1F1494EBF8DFB7A54B8D8FD43A381C5B
+:101930005E18D3353103F077E92EC987D59676DE68
+:1019400032E366C4BBBD061FFA19472BCC6F28C60D
+:10195000753CFF6A3AE4D7BD346A34AE07BAA8C210
+:10196000FCCDB27FEA70E45B8F19297E0AF24FC882
+:10197000804747F3B799CEC13A4262BF37DF6AABBF
+:1019800041BD09FA3B2E43BB84272455A4DFC6FA88
+:10199000E74B3B13D0EEBB60B435E239C2057BFDAB
+:1019A0005B388FE0B3BC5F16E6F35E2CCE0B6A8E1D
+:1019B00018498F38F8D59F6F1D8BF4DE66F022FF33
+:1019C00058B42B1AAF1C6A8B09E5410DF4ED8671F2
+:1019D0002FB6D9A9FF8BC9A1C128570F7ED57E0686
+:1019E000E9ACE729B3AC8FB3A9D9FFCBBF225F5DC8
+:1019F0001C8AEE2F162F5E11EB839F7C3D7EF5C572
+:101A00001FA628A323E5B5AB404EE8CE836A3F6806
+:101A100031A11EBA789AE91BC7FBF3E917867A64ED
+:101A2000C2D320DA79C10306F2D37EF48989F8FEA5
+:101A3000D26B58B907D6B9DC3D725C39F4BF743A41
+:101A4000ABC034FC481618FF22FE3684A7E9FC051B
+:101A5000F19EFCC4E1876E003CF8E86706B619E623
+:101A6000978EE776009FC32C9C20237FEB34C838E9
+:101A7000CEC5F3A000025C3E76841312914ECE6F69
+:101A8000263FE1DACE6309DD98EE4CA2F3F581F84A
+:101A9000CDE167ADB20CF0FFF8FC93F1AC1FFA5D3D
+:101AA000729E9FABC7F21F4D0E9FC55F415E7F9C2C
+:101AB000ACFE3119E18E4605E809A949F545F5FD69
+:101AC000F4A7B59B23F176A9869554EF9354FF674D
+:101AD000D8DE5E12F4A2FC4E0C587C683FBC6FF05E
+:101AE000DDEB1882723660223F444332F5BF88C175
+:101AF000FE40FE3C858515C0D779289F47509AF84F
+:101B0000FFBCFD52088F52ECCDE6A8F3BF85AD9027
+:101B1000D6AF63AFAE1CF8CD6294DF09740E1646E3
+:101B20007FEE9227A2EB2F05F31DC7AD7DE66BB3C9
+:101B3000BE5FD03CB5384F13EA8D7F1170F9245544
+:101B40008D4B81FCBB25FF77B1DD02F3016AEF12FB
+:101B5000F1133D07A4D03E9427426FA8BBFFFE823D
+:101B6000F9A0AF7CBAEA4705F393847F06E97F9733
+:101B70004476E6D27216CE82F9DD2EF49FA547A4F4
+:101B8000F070482F8075A31E31F61929680739B700
+:101B9000C0C282098867BFE1FB512BD683F50615C9
+:101BA00023FC8204CFC5AC8BE633B686FB55C61E3C
+:101BB00092284E29164E357B63E0A6874B0EC22332
+:101BC0001ACECB9F03F844E10B870FE83DCC0AFB0C
+:101BD000B55DF0F5336047E8F54A8651FC506FFB80
+:101BE0005A89CAB7DF62626E98D78E990BDB31AE25
+:101BF000E661F47388B8428C03DCACC5FD01C158C2
+:101C000060BCB8912C72DE3886F42A4A8FDB91359D
+:101C1000755726F4630CA4A19F6A4725E8B95C9F19
+:101C2000B1A23EB3D51D188FFB34CFE07F150D8CCC
+:101C3000F9B23A58417C5BC5E1B7B3B8BEA0BE1F4C
+:101C400079A8E1F30EA94BA5F3A10724E28FF14790
+:101C50000E843360DECB2A3CE4F74CBEED74FE5CB0
+:101C60001877660AE74F838E7279B55B620D682735
+:101C7000BA011F24D89792E7B6A6A1DEC9E69B8ACF
+:101C8000F19CE9612797073D6FB21BE97C26BEBE38
+:101C90000DE38C52EFCA2FC6F31F58EF5DD3A19FFF
+:101CA000D9291E9A479A8DEFAF7B5DD0BB12F253B4
+:101CB0000126F6441CCFBFE215EC67388F6783FC22
+:101CC00046D43FDD6CAD84F5362673786F9CC3AA8D
+:101CD0007F5648E76BCAA044FE7D1BBE6075361870
+:101CE000E19BAA80FECAF31B709CED097C1DC9B262
+:101CF000E1AE4ADCAF629E4E5C2DA9FB0879B7D2FB
+:101D0000BC52CDAC02D789F9E8878369A907A83C02
+:101D1000C4F1A2ACBE88E63B847FDFE8B6040D8048
+:101D2000C76FB834BD336C23BDF3509A8C72E71E75
+:101D3000212F3F35AAA92391EFBE6964A8FFBB06F6
+:101D4000C7D4CFCD9791AFDE23E4D4E7BEB24148EC
+:101D500054878CEABF3382AB41DAD7CF397E738A9E
+:101D6000F0035FCE60219D5CA8ABFE82F4EFBACB9E
+:101D700083A3F23F5E032B19A6931F35472762BD4D
+:101D800065AC6B23E2DBB24E030BE9E8E39095EB25
+:101D9000FB5FBE6726BABBBB63D83E1E37E64998D9
+:101DA0006E8FD041DD65030B024EDF6090A97E5D32
+:101DB000B589FC4E758D8636A4D3BACB265E9ECDF2
+:101DC000FBABBB9CC48249585FA273C29E2603F939
+:101DD000492F187B36A25E137CC94B70AABB9C426C
+:101DE000F5703CD4A3EA2E4B943E877A1FF4732EF1
+:101DF0002407F3AE43BDF04BB15E8597431784E7EC
+:101E000087B89C9B06720DF9155360DE607F5FF208
+:101E1000BD9F80F03D27F4CD74437702C67FB21793
+:101E2000B9BCFA780D302680D3254F37C92B0D5E0B
+:101E3000971CDD0908A74BD51A5D8615EC678FEF57
+:101E40006505FD3FB5BE9727321DBE44E01ACF821F
+:101E50003AB8A6ACEF0ACBC0235EDB316F4B610111
+:101E60006CE151C10F820BB6A8E3A0DC2047F1075B
+:101E70008C5DD1E28A1145B6CB06717F67E196F29F
+:101E80004C5D5AD4EF6D1F5C34B51CFA2B29E4ED80
+:101E9000DFDA51F3BFD6293A39A0F40CF6DB7569C5
+:101EA0004B4CDA06E9E1BAB423A6DC1553EE8E49B1
+:101EB00067F2FAB307758F32808D766647ED54BCB2
+:101EC0007F343BA3FB0778DFABD95037B53C0DE53A
+:101ED000A96F22EE57DD21C9C1D56E0EBFE53E4682
+:101EE000FA9ECDD76DC2F396F812DFABA857D44255
+:101EF0003D09F023BE30CC907FD5754AE4B7EB6D39
+:101F0000D7C9F5C4DACEB3D46EC0FEF365A2F3CD63
+:101F1000F9E7A8DEB2559F9850AF69AADDE647B948
+:101F2000B3C2C4F91560959A0178B1FC5025F99BAC
+:101F30007E3FFCC86F31DC33FE9ECFD62A50E5BD14
+:101F4000657F1C85ED7E8F5D5F8F7C365480ED67ED
+:101F5000D5CC2DC0FCC4C2AEDFDE0AF5CE18BB1F47
+:101F6000C5389294D4B55315A877C6DE9D8571C93E
+:101F7000EE9D5B783AB9FB5184CB969DCD04A73397
+:101F800059DD5932A4B376BEC2CBF3BA1FC5F48C67
+:101F9000D4A779F9F0EE2C8303DDAA3F21387638F7
+:101FA000385F7B0CEC53E48FBF8F915BF654CED738
+:101FB0004FE6AA96543A97E572E351B0412CC0F728
+:101FC00066EFE97EB603E034FB87F1283158C7C7D6
+:101FD00033A6D0B91E0BFA510F4DE528CCE51BF105
+:101FE0006985F4823494698911B8DA077779701EAB
+:101FF000B172E00FC96A338EAB7D1FF0C017E0DB12
+:102000009CEA117A497D9107FA9D35CBE6437F2EF4
+:1020100053BA47213E3D6CE5EB023AA0FDB2E1BE6A
+:10202000C1BC8688F50C49E5F695256502F57BF778
+:102030007B93765BB85DC6EDEC6546D24B5A2BD5EB
+:1020400034F407B456A6507CF4C1AF0C5CBFE93041
+:10205000D33A6E473E81FEE62246F9AD5B0B286E11
+:1020600056D36B5B1797A5219FB9C1509A8678D834
+:10207000536922FD1FF81AE763CB8C6D94D6F8DA0A
+:1020800032A3E06B20AF088E9DC9FAFB97771899B1
+:102090001FF9D81D6D9C8FF5E64B904FFCA53319A9
+:1020A000F9D5D5E66F2F56D3908F69F34A5DDF4996
+:1020B000F348DDE94D44F893A0443D65EBB07D085D
+:1020C000DFADEEE904FFD6CA27AD730B23F82BE78B
+:1020D000A9D3108EB78B383C0D4FF007FD58F31E77
+:1020E000496D437F4AB3803BE82123503F5BE6D6EE
+:1020F000F69311DD34A7723FE56C73D888F4F03F96
+:10210000FBF20FEFCB9A7F645F96ADFAE355F137A0
+:102110008DEE764861632AEED34B5C5FC47C94FB02
+:10212000135302DB5275FEEED93F5A9646F14062D8
+:102130003EF1F7BD50711B24CFDC7EB1E349687FCF
+:10214000E68756D26B62F5D133EF5A9AD1DF155F2D
+:10215000D8BD0CF7357155BC03F58B33C2BF76463D
+:10216000AC7BF40F97BE41F71D520DB42EC0A334C3
+:10217000E177095A707E95A66FC6A3970C14FF6D80
+:102180008DC5A38E61028F42BB17A28CBDCD46FECA
+:10219000D9D63C99F497D6FBE3C9CE68F576137C83
+:1021A0005BAFF7505C12E8391C8F669AA85F042079
+:1021B000D6FFB43A3D84F007BCE3E3CEB410FE6A28
+:1021C000F18D9FD6E4507CE30D066EC7F4E4C9A1FF
+:1021D000683CEC49A8D4E1CFA7C2BFF529EA39830E
+:1021E00074F98CEB3F20BF490FBBDAFC94F52ADD74
+:1021F0000FD1F050C3BB0FB601DE48A45E0C453AC8
+:10220000F8ADC01F8DDF2E7307DEC4FD8EE8C39CC2
+:10221000AEE63D3C9CDA6DB273FEBCD7CA1A2DC542
+:102220009171F782DD807205ECCB5388B77741C39B
+:102230004390BE2B35F08B6E1C6F9586BF7E13E2EC
+:10224000DB0261D7B2D5D1761BC631F5A60D7DD3A1
+:102250000B55EEFFED6337B3AFCCD1EDB85E125F37
+:10226000D863443CDF696541AB4E6EED42E72EAC6E
+:102270006B17EC3BD2A556EFCF1FC7C978BFE0C4A0
+:102280001B2307E1F9CA9F996F10FA81EAA06FF446
+:102290007FD6C579C80F7583418EE25BCB712989E2
+:1022A00091FD3F77288DF003DBE17CEB72C1E64BBB
+:1022B000447C51E750BBB5768FB62F547FD7308E14
+:1022C0004F1ABE3C2F097CE97992F8E7CF8731C4D9
+:1022D000FB4BC9BCFEA526431BE27D1D4208FB0F3C
+:1022E000FE7D0DFA77CE29A1C52887833571541F4D
+:1022F000FDA87A3B58D3A32FC1EF786FE11C0B2CBC
+:10230000A673E36A5E5FD39B19A2404AE47C68B976
+:10231000CCCF0F757AF450B20B5FB416A31E5D2BB1
+:10232000EEED60EC39F98DB091CE8E41F88C2BA694
+:10233000EF7103ED43F768BFBDAF9DB35C3E3774EB
+:10234000653F766D6FF9AE3FD23D243C47D2EF7FBB
+:102350006D044FA4AF251C5F8737DE081FAA137ECC
+:102360000AD2B371FEE58CEE23DA453ABEA22B8485
+:102370007C29F968F744B25FCE831D8DF50A593187
+:10238000FA3BC71E693B867A68627957166E5F9D75
+:10239000F0D36978A5CDF3FA235B0D681F6874A5A7
+:1023A000A3271A67414D3A9D537423B3BC1E33D7FC
+:1023B000517BB45BF93D1C356D01CC69C7E21CBA99
+:1023C0003712AF70BEBFA065D8BEB5827E91EE3524
+:1023D0007B1734C3D148575BDDA5D3DCD0CF77D38F
+:1023E0004A27E1978CA4EB0786A70617AD1EDABB38
+:1023F000DFE4275BF909D007F0A78AD7F252913EB4
+:10240000564A9E54A48F0F0D01F28B45FC3861FA99
+:10241000D60A3A5F28FC3F0B357FCF2E73549C239E
+:10242000FA51F5E925C20FC4F69B23F18BE8D729B1
+:1024300067613BF4B70CFD47F8ED8C6EB79CF55027
+:10244000BBBA435F47C5E1B256BEBEBBC4FEEFB6E2
+:1024500072BF8F73759B81DB717C7D838A55EF061C
+:10246000E49BAF19C92FF1072C22BEA58E467EFD35
+:10247000496A69A51BEAC5A1FD0BEBFE00E417EE56
+:102480002BE8C9774D477B714DA080E2151475F498
+:10249000F47EF07BF3616B0DE2C3036E39EA1CF945
+:1024A0003B6E23A5C93F84F4DF6426FA1F9D23F405
+:1024B0009A26F33EE433F3CD3CCDB6F0739FE5B7F7
+:1024C000DA02D8DF39E1BF6A72733DB9C9CDE32AB8
+:1024D000B5B4B63EED5C0FFD34FA7B670FF7D6E37B
+:1024E000FE11A604289E6A8731645D40FCD14F7EB0
+:1024F000F23F7DCCF7FFC48979C437FE047C03CF5B
+:1025000085E70BFFE99F9887F8652F7F6C3344C9F7
+:10251000C5F34FA40AB9C9EF1768E77ABDE5E787A5
+:102520006A7C3028933FD2AAC94D15E559F0F9616C
+:1025300024FF99904BE78F6451FD0FF1BC0F407859
+:102540005E09EC5E40FE687E2E705EF31B2CB9388F
+:1025500002F5A1F32C681E8CFCEE8899E4FF874CF1
+:10256000C4CD840CFB38FF0B65CCD0EDDB6171FF73
+:10257000EF3C0B2FA47A9D56F21B68E5E9669ECFCF
+:10258000FE15F275FCEE45A3A87FC02AE9F30F9A69
+:10259000C29C9FFF8CE7FFCE1CF8855B8707B509BF
+:1025A000E1A14EDBD5C00F181DE2C54B7651CEF927
+:1025B000C5F9C6613EF4CFF7CA91DD5C3E5D30F2ED
+:1025C000F6C19F7B097E0F17733C3BDC66685B0797
+:1025D000553FF59B282EFABCF0B768705B77E1C9D0
+:1025E0008C6E5A3FE7FB3B8C1CEEC1368017EA5DD0
+:1025F000267526AD73B33989E40DF267F41B37F203
+:10260000F88D81F84EDDBE79740F7EC0F29ABFCD91
+:10261000A67E62CE012FD5FC6930BF7FE9A6C3A498
+:10262000E50E5116DB5E9347AE9E94FEE44C6FBD03
+:10263000F31B5760BDD871485F1ACDE52BF2B1BAD4
+:1026400098F345A64F1BFAA6FFE676F6C6C1625C74
+:10265000E358A6FD44D7FB0A633292B13CBAFF0FA0
+:102660008CC1043AB7BA20131F5AD63A6736AE3B2C
+:102670003B39604C83FA87B76D1A4D70107831F68C
+:10268000A342AED7B5F0F3880F8CEA6CA46F6779DC
+:10269000D83457274F33D338DF9967E6F61486FFCF
+:1026A000E9F994563EBA349A3F68DF8C34CE27EC71
+:1026B0005D5CAE3136C38CF2FE30FEEAD1D7E37AF0
+:1026C00065669A87FACB3ECFFD3BD9AB43EB31EE43
+:1026D000A1B673CE48045BF6EA30F1950F8C2C8CD2
+:1026E000FAFD07BB053EA33F03FA5D3886F7BBD072
+:1026F00000FA25E2AC389F5C22A0B9D00C7A28F011
+:10270000F117F68F37D8A1DF257B251FC64D8D1514
+:102710007C1EF5976C943BE2FCBA86756DEC86FEE8
+:10272000173633CB188A7308193208CE8CEED5CE03
+:102730003377933F91FD442A42FE00F2AA2101DA49
+:102740002D5143E4778C3D3F64FAF33FDC0F3C9717
+:10275000D29DDF2C6B69A2F32F4D0EA2BC62317AA1
+:102760006B341E05FB95B39A1CD2E42DE8D965693C
+:102770007C9FA2CE6D96B17A7E2E25E45DEFB842A5
+:102780005E7E68E0F279A1792B7DABD3BCB44F4B70
+:10279000583797B7203F91EF5F697FAB059E68FB85
+:1027A0005A0B0CF246E87F26EEB74E0FAA5DCDC25B
+:1027B000CB46F0AF7D04C193EB0116AE07E037EED8
+:1027C0002AF481583D2056EEC7CAFB541397EF1ADE
+:1027D0001EE8FDFAA8DF8C5D1D32E07EBEBA46A57C
+:1027E000F3F95596841118B7F5A5957F83A59CAE8E
+:1027F0008267AC641FDC67F0ED7A13507FE2269E9F
+:10280000CFFE239EF8E8FA262E1FD6AFE5F2778B8F
+:10281000A08F55E2BB57D0C1511C270FEF0F54D0EA
+:1028200078132D450AD2EF64C767831541C73680F8
+:10283000F32481D7CBCDE18D688F1E4B5BF6B85367
+:10284000DC377740F944FC05F23F31067E8C0ECE32
+:1028500009CCD3807AF66E736053DA2854677DF31F
+:10286000574A1877B47C1CD2958DA98D989FCAD4ED
+:10287000A6348A03CB74503C94C0376D5E65AC8738
+:10288000CE97265ACEDE8B72529B67ECBC6A2D81A6
+:10289000C73154ED58DA7BB3593FF38279ECC271FA
+:1028A000EE8DF336B0E879EC16F3D89336AAEF3C08
+:1028B0002C48EF068C03B5539C952EDEAF9DE69D0C
+:1028C0002947C5CD6AF17E1ABD1CFB84E5A0DDC693
+:1028D0001AD1378870E1F83AC1663E8BF87FD4C8C8
+:1028E0000E213DADB7B37CD4A38FB138DF3A2F753D
+:1028F00093EB4AA1A953FD638CD353F0B495F657DB
+:10290000B2F0737EC6021EB4778E59CD2AF1598F6C
+:10291000272A5E4EE3C3C7DECB22BBFFA8D56C439C
+:102920003C82FA947FF4BDF8500E8EE7D2C5C3E521
+:10293000F4C53B5435CF239FDB584FEF18B85927C8
+:10294000BDEB705AD029635D12CE2FF31EE6A1793C
+:102950008CF159B81F9E9FD7978975C4CEAFCC62B2
+:10296000A3F84D66337EDCADE34FAC65A7AA87D7ED
+:102970005184E3A0083C35F8C5CEBBCFFA7701DC23
+:1029800047EBE06E817623E89C8E6524F6D39E6546
+:102990003A3FBC9687F2239FD8951AE8C67DFED2AF
+:1029A00058CFE3BD2A2D24F7122B7AE8FED999C817
+:1029B0007B0AB4CE636258397E5C26C643FD55D08F
+:1029C00059ECBCB4F5C4AE33160EDA7CAFB4CEE32A
+:1029D0005A7FB1EB750CD03E669DA34DFEFF42FCC5
+:1029E0003F2377DB89DF8A7BAE75E23C103112FB37
+:1029F0009D2BFA9DDB2D51BF7B58CF4343911F1D6B
+:102A00003138502ECD3D620853FC6CE304B53B6A6F
+:102A10003C8EFF5A7BB6AB2701F143EBE7D39AFF1D
+:102A20004CC038E581DA3BD225A2A7A333BFA078FA
+:102A30008D3D47DAE93C7A4725601ED9A53E3A4FDD
+:102A4000FB2783FF966CA8F77E8D4CF8FD7E4D1C0E
+:102A5000C5CF6AFCF435E41F7957E6AB8CD57F8788
+:102A6000E36FFD75F89DF8FD399FBBE87DC0176FDA
+:102A70007E0364FFC44973EEC1F49C7F6EBDD9062A
+:102A8000C431B14CE2EF01EED9FD10C63D4FBC6D33
+:102A9000CE3DC9509E9879D3F75C587E8724CECB23
+:102AA000367D0FE3A426DE2591F2D5BE17EAD3B911
+:102AB00042C088E777B7E23B378514CFA0EAE3C48A
+:102AC00046A6F338F991E91C9F4AD23D942610217D
+:102AD000DFAFE6710F601F19B99F2460C4799FBCF6
+:102AE00011B8E620EC3790D5A2D3B74E4D36DFA90A
+:102AF00016F27A7ABFF3A47429CAEF16AB674D4C6D
+:102B0000E7F2553BFFC0F6B70CD797F3FBEE937097
+:102B10007ED08FCDC3E530CEAB6A38FFEAF5DE5309
+:102B200033C74F4032BC251FF832433C0CDC9C8E2F
+:102B30007C33ED133BD723BB87E33ACE18BB79DC5C
+:102B40009093FB81919F1C8686132A7C4FDC07BFE4
+:102B5000DF97CEDFF53965A4B743D8B104735B03C3
+:102B60002CE584E0AFF8D3ACC90B818FF81E8C261E
+:102B70001F7EE9DDA9A07C99C23A15C4FF69AC8B20
+:102B8000BEDF633DF4F5338711BFD3998FBE9F8EAF
+:102B9000EF1E4D7E04217740BECCC7797F92C5E5FC
+:102BA0005F050B1C417DEE6D1C1FF93F0B13BDF63D
+:102BB000F2C118FE3E201FC4E9A544CEBD343E2C10
+:102BC0000580FF63FD8D41E2C7A92C700F8E9FC168
+:102BD000C294CE027E4CFE9A5E3E1C4DEFBDE71FB6
+:102BE00005129D4FEF8C4F207BF36481B44FBC1FC7
+:102BF00066C07B72042F6834295F9A8376CF4E01BA
+:102C0000CF4915A9F3303D69D6C62E9CC7A4FC3721
+:102C10006FC7F440707BD1E89F908CFB7733DFBFA8
+:102C200077D6D4101DFAC20E7A47634AA193E20503
+:102C30008B4FF88E617A5A094F17767695E2BB1A58
+:102C4000DF1BC7D3230EF51CC5B4BF9CA7AF3B1237
+:102C500096313D35DF5B8C69E72C17C539B32A7196
+:102C60005E10B3CF9359B0EA66C48BDFE418517C91
+:102C700087D287129E5E3F5F6213A1DDF555D29326
+:102C8000924E3F60C1A70CC807ABC53E3903FC5C40
+:102C9000B73A5069C4FB158007F7E2FA60FF9F401E
+:102CA000F86BF8706FDC9B672480DB41110F1B9C75
+:102CB000CEE10CF298E05C15E07E55FCA94A41FD9E
+:102CC00048FB7110DFD5F8FA2949B49FC3DF5FF9DB
+:102CD000DD3B207A019FCAFDDE7246F21F140D3CD7
+:102CE000C70998E9DCA67CD66D53E85DB7C0A62E6F
+:102CF0008A8B76E8E2DA119F3E3045A58F09FC7495
+:102D00005749E4BF62FAB87603C6BFF0FBBA6E1B40
+:102D1000D7375203A6A83879B413A2EA33F5583A44
+:102D2000E9030AC59FE48BF813F8358CF193F0554D
+:102D300031FED2987E9EFCFEEF582507C62DDF108F
+:102D4000F257123E0B3BEA3601EF172CDC5F506561
+:102D50009342F86B957FEB9DB8DE84B76D1EF487C8
+:102D6000221E9B4A22F061420E3F2DE4D6B56E66CC
+:102D7000C926392F05D12F71ED0BE9DC1E75F3BB88
+:102D8000F3D7ACF4905E54354B620EC49BE6387AB0
+:102D9000EF01E6F1F5D7BA7BA4B7CD12F3585D1277
+:102DA000421706AB192CEBE5EFC1622D9EC66344BA
+:102DB000E63DDD1F6061DC1737F3A13FFC3755B2FC
+:102DC0006A71D1E30EE4D79567713C98629328FE4F
+:102DD000BBF4723C0B8FC4FD0E352462BD774C846E
+:102DE000BFC95573EE447EA5F1B15271CEC3AA7925
+:102DF000DC7616E08B9FE2242545D1F18958FE82CE
+:102E00008E189C6F5A6F1ABA49417EC1C81FCE2CCA
+:102E1000DD0477BBA63709FB4A7BEFEB866EE73C08
+:102E2000DC9FD1364EE7F8240BFACB2D19393C6ED6
+:102E3000A9FA976F63BEE4E17872EA13361AE77B6A
+:102E40006A80777DED195C8EBDF2DEA22CB4234F33
+:102E5000D9FD59683FA66778283FB7CA1C9661BC60
+:102E6000536901CA3F25E2BBB1FE594C3BFD594EA7
+:102E7000AAEFA5F1B17E228E9B15A0FC5EF962D56A
+:102E8000DA0DCBC47647BD9E598807A70A52253C68
+:102E900077CB14F3C8CD87F1747E9FDCEA4D5D38A3
+:102EA0003ED821EC7DBAE7158EE2DFE81EB1170FA0
+:102EB000CCB76F403F0DC68DC17E617CD843265F85
+:102EC000A301E8A3B43C24FCBAD1FC38F5E3960D89
+:102ED000985BCD7CE52E1EE72A37A644F8EFEF0479
+:102EE0009DEED4F84191E0DB8B0691DFEB37737AEE
+:102EF000F97614BF9B14E07C7B925FE3D79BBA709A
+:102F00007F6E66DD0AF6FB7DBC2A0FE355325F5506
+:102F1000B1847CDA43F815B472FE3929C0F7BB9C42
+:102F2000F9899F57FCB6611A8A9319CCD3AF1CD488
+:102F3000E4DFAB8B1E273BF2DBF277E0A3DFCF1899
+:102F4000D597CF1776F2F49442CEE781CFF833923B
+:102F500023F2E86AE5AB34EB556E37C5EC57C4BED7
+:102F6000E1F2342247791C57964D0EADA3CEEAA567
+:102F7000FEE4E96F237A46B4BD739572BE777CC6D2
+:102F8000FD72191A1932C981766CA6683FDAC282BD
+:102F9000F128FFAB84FD27EC3190FF3FC82066C5C8
+:102FA000ED3037DA61800FED29458477B1F32D706C
+:102FB000ABAB10CE130C361FF2A93FFD86BF6339B1
+:102FC000599D3901E3C5A6B0C006FDFDAD6160574E
+:102FD000283ABE5F10B2804D1C495FBBDF11951EC1
+:102FE000DEE98EAA7FDD214F547911080D7DF9C8E5
+:102FF00013BEA8F4A8AE3151F5BFF3B61A95BEBE04
+:10300000BB22AAFE0DE7FD51E9A12C24E3626FEC7F
+:10301000A98E6AF727164A74905C57BBF253E8FEF4
+:1030200021FDDC743910D57EB8B827369E2D8E6A06
+:10303000CF9EE3F750EBE11FEEDB3531F750878A87
+:1030400077556FAD3246EEABD27C9AC9DF3634A6E7
+:103050007EECBDB06732EC2EDC27A0E91294A77D90
+:10306000F687F17B8165FB5928E4C5F5505D76CD87
+:103070006EFEBE5EECBAB47B63CCF08C82F5FEE2F1
+:1030800091183E29607647EFA7D513BD9FF1F9D17E
+:10309000FB69F745EFE7A031D1FBE954A3F733A96A
+:1030A000227A3F93FDD1FB995A1DBD9F6981E8FDAE
+:1030B000CCA889DECFACFAE87DCC5E15BD5FDE60C2
+:1030C0004D54F990C6FA687C14FB99D7B22AAA9D90
+:1030D000B69F41F8F74DFB5966DB2AA3BD5FF1446B
+:1030E000F4BDE4ABDDD73FC6ECEBD5DEF7033EF72E
+:1030F00009D27519F337244ABC3FBD1DF3BA900BB2
+:10310000C7D26E2E4FF4F0F228BBA66013D9359AC1
+:103110003E83662ED2C55416267EDE570E78284E84
+:103120006A06FADD20BDDC10DE88FAC117695C9FF3
+:1031300005FE2C65921F6D2BB59F82768E14F16370
+:10314000F5C787F1BCE26AF95FAF5FEB7BF5E45F3F
+:10315000D2FC4C03FA973C5911BE064CB36C5599FE
+:103160001FEF317E29CE957AACDCFF5C76FF78CA02
+:103170002FB3AC203F4EE91BFC5DFC529B44F13B5E
+:10318000651566D22F7BEDA20B32C9D793959E2C85
+:103190008CE7393939B5DFB8B0A3F6DBDEAB87266B
+:1031A0006522BEF764116F7FD2E90D61FDA3125352
+:1031B00083284F93B9BC3E6937A838DE4989DFEBD5
+:1031C0003D49BE37F8CEF150FDDEF3B5652CEA7C03
+:1031D000ED70BD439CAF7138F4FC8069711A6417BF
+:1031E0001FB6E588F3C9B3A457F75CCFE8FDCB0B56
+:1031F000C6CE30DD83D9EEA57345420BECAF859F7B
+:10320000D74D10F7990F2B2069719E85FC7EE861E0
+:1032100011EF734AEC2BF9D9B19F66BB66C7F07901
+:10322000B51490FE1C2BE70E33CF5ABA6FBA9A89A9
+:10323000B8ADCED32BB17EF5507A0799E6A1D3571E
+:103240000FB3CE0FB69550BC07D53FE9ECFCFC247C
+:10325000C265F135BE208BE0876BC4D447EFF1A087
+:10326000FDB389CED1CAABF8FDEF72C75A05E94963
+:10327000AAE6F8134B4F5BDD816AC4DB56EF53457A
+:103280002BA1AF0A6F8715EB97093FF5EBBD767A57
+:10329000347D1D4B7B60EFCA7EE8AA571F622DF478
+:1032A000FD07E86929A7A7366AAFD99D40F7B59908
+:1032B000A322EB04006761FCDE25A791F138A92069
+:1032C000D3EB1903D195069F0A47D1712C8E854BFC
+:1032D0007D4A6075A6EE5CA422D177BADE85FE3504
+:1032E000B32F48EB8ED61B4E0E00A73E7C67F23004
+:1032F000F2E794558DA7754D6041FA4E6621E59B26
+:10330000F9CF80FE95169CA7A65F4E177C07E0B408
+:103310003533B92FDFD1F4B15EB8C4DA4357EB6768
+:10332000E9D5B3A2F5423606E810F075BDC68F6246
+:10333000E03451DC4F7FC72189F7D8D5696929B8B6
+:103340006EFEF34E23A79F72E04F28B7A70AF9C479
+:103350000AB9DEE0837F38AFBF305BC0827EA9DC74
+:10336000687DA254DC432F8F7917A3D74E14F7D76B
+:103370004B63CA63E1A0AD33565E69769CF67EF37B
+:1033800040EB3E9A29E49A870DFB1ACA416691BE2A
+:10339000D2F55B03F9C95F49BE6DFE56C0A7618FC8
+:1033A0005F43EFBDBC9272C73D6F62FAB1A1A4C783
+:1033B0004F4C5FBC7705A49FDC5348E59ADC7B2328
+:1033C00093FB21CB656901FAB1F24BDEB9DD0BF35A
+:1033D000396E657762DACD6A5A2B611C77614EF1DE
+:1033E0007AE4072646F5A65EB76CA4FE5CF974265F
+:1033F000F71B4F15F1AA59F8445B317D15F443646E
+:10340000B9438A03FA3589FB3A190A6BC077FE4C37
+:10341000EE169B03E11BC7FB2DCF0967DE8DF6C8B7
+:10342000411BBDCF7CAD2FFEEC109C8F24D17CAE18
+:10343000CD97C2F87E7279A2A85F1ACE7D04EB3FC9
+:103440006D2A463E7CADEFE60B58BF5CBC3B9AA0B4
+:10345000068C05E82F10FE8E630ADF8F2F322DB405
+:10346000EE176CE38D784FFE563FF737B983DD0DCD
+:1034700049B8DEEAF125B85E6D7D7FC9E4F13955C2
+:103480006378BD2AFF1CE37CDDFA6F557BE85D9F06
+:103490005BABCF127FFC5D0CFD56E22F72847EFD8C
+:1034A000F80BE0C99B7702FD225F99E5257A9CC164
+:1034B00054FADEC202C4CFAA590BA56F679DF49DD2
+:1034C000C5BA38DD9EEDA5DB6C570ED1AD394B4743
+:1034D000B7B731F652B7B72FBD0EC4BF80BEED5996
+:1034E000A3FAD2D740FCBAAC7AC5DE95FDD8C16547
+:1034F0007943683D11BEDD497CE7DBFA79B575C0DB
+:10350000BA72B29223FA0F0339807E6D98EF103EA3
+:10351000DFE8F51DED871FE9F5A26FAB0FA1FF05F1
+:10352000F580AC7AC6EDD2183DE81BCE2DC7D2FC93
+:10353000AE706ED9E71C34457DD4931C3917A87B37
+:10354000DB62F160DC74899FE5601C40F2F857BCD7
+:10355000D06F9D38BF88EF626A1BE43F2AE25B0FA1
+:10356000783DD4AFDBC4E325F01DAC221BC6097443
+:1035700085299E2A19F4154FE47CFF513BB4C3F70B
+:10358000ABBD9C7E7BDB5B58439CAE7DE91D9CCF35
+:103590007EF1A089DE01614A201BF59894DFF37764
+:1035A00076CF3D64A2B8B621264E772E2D6E9D6D46
+:1035B000E47F6720CBCBCFE7A4A36E74EA04D9667F
+:1035C000FA6A718FE7C47D962F9C3E7A0FF38B07C2
+:1035D0005324D4D3CE29EAABD530EE90479CD23ACF
+:1035E00016A95F95E5E1ED3CEA6727705D95361E0B
+:1035F00047C60245F45E8EA1648A05CFB30DAB7B4E
+:103600004E40FB655936FAFB55E5D9A74FE17B41A2
+:10361000179E33D21B888B3B660C0A63334575FBC0
+:1036200087F795DB8B43C6283B64E9FEE8F4B2CE0E
+:10363000E8745D8C1C88E5F73FCAEAE5E33EE4E305
+:10364000576B9FA892BA16E96089D877B3B9FE7C08
+:103650001BACDBFC707EF15AC46BD6F332BED19D3D
+:10366000F288B798E2BFB2385FF767F99BB09D392F
+:10367000BB7004DA55A5D9D3E6D03EEEB6D2DF4D05
+:10368000F9021F52C1F44B5C3EB60EE6E5AD7BCCB1
+:103690001E49C8D351A3316E86D34FDD2E2E0FE1C4
+:1036A000C7C2DF93512DB88FAD26D59486EDFE8924
+:1036B000F9703E35BB16517C572DEBA278E95F8B34
+:1036C000FDAA333C63B2C0AFAD89EE52F4D3B6FE6F
+:1036D00054A2773A95BF2B7EC41F0CAFA0FB0F16E8
+:1036E000D5817FF763D92127BD8FD091C5CFC39AEC
+:1036F000C645DF67B03C57194457E64D7F2FA77783
+:103700008216ADBA83DE57E9BDCF2CE2DF16DD3F6E
+:1037100093F28FEDFE3209FBFDF04199FCE11F3E73
+:103720003ABE0BFF8ECCA2669BC7D2DF7A593DFD15
+:103730003D920689DFB3FE84D5FFFA7E00D91F458E
+:103740003C1C73D427103D7BEA13F4F741DAF71AD7
+:10375000E81DA83FEE1D49EFC8B64E9F320AE5F0BE
+:103760004DCE127A274A2BD7F47B2571CC9348474C
+:1037700037FDDD407450FEF0B838F4D72A20C7304A
+:10378000BED4D35C4AF1964BFC714E0F31331E47C9
+:10379000DEFEA085F483BAE689B42F35CD3504F773
+:1037A0002133D265ECB7FD198939705D8671716B73
+:1037B000A17EDDC3E4AE61ED4CA9E8CF5FBC30CBA8
+:1037C00040FB747C7A9C2F0CF52F087FC8F86C3E68
+:1037D0009F89867153D0AE5AF6A04C719FCB1E3C88
+:1037E0009942EF123C61A0777F40A34A4778C4D248
+:1037F0008D36BF58FA3143BFD83E968EDA83FC7DB2
+:10380000F1587AC29FB0EE7CFC447331CD2B96CE3A
+:10381000E636E7D07B09AC91D3DB05A007D23FAFFA
+:103820009EDE3E45FEADD11BCB9C1E1547ADD1970C
+:1038300096D6F8B9765E6BF131B5C346F78C55BCB8
+:1038400047ED1ACCCF6B5D83F93BBCCA5F57EEFFE7
+:1038500015CC7F6F56E02BA4CF6CA616217E793F46
+:1038600067F8FC019D4BD379732EBFEFB2C3E89785
+:10387000492F5402FFFA2BC83736D78C443A778A3F
+:10388000FEFC5901F360E867FEEAC0672F33C4B756
+:103890006B88DEE75FAE92F1BCDBD6AADDAFF497B2
+:1038A0005A5DF4F7074A101F353E9D07F36DEBE7AD
+:1038B0001CBA7830D77BF25C7EEA27219BBF4FD5BC
+:1038C0009ACCE96BCF2A7EEEAFE95709620FBD1E95
+:1038D000FEBE97650C87C74AB7C18371F2300EE50B
+:1038E0007BC7C8C149F0B58DE1F732E34BC2F4DEC6
+:1038F000711EE6031E797D8CDE41D1CAA1FE59CC32
+:103900009799C56383319AE137C487BC7CFE7E9961
+:10391000B795E76BFBFFA71689E8136C5007FE1DF0
+:10392000118CBF277959C2E5E54AB7C9A37F5FE388
+:10393000BB69E3870F46F9A4AAB92EEDDD52F8F969
+:103940002F11BF085C8AE2D7EE2A6401BCD7A6AD6E
+:10395000676CABBA11F130166EF3C53C1FC4790227
+:10396000AA8CF5413A7FE0F939067BA2F0499B9F8A
+:1039700069B94D417A7E14F511D87F53BADB86744C
+:1039800004EBA03826C6E27C78CEA5C55964A5E72D
+:10399000537D2DDEC215075FD01F807D2A888726C4
+:1039A0009995E33D8EFB643F9DB7DD6768A17EBFBF
+:1039B00094B9DE93E9F01F580870CD301C285A01E5
+:1039C000F39B6D51FD83494FF1D0FDDE7303BC1BAA
+:1039D0003FDB32FE16825F6374FC49CA7AC18717E7
+:1039E000CBC487B53894D8B8933D728B05C70F0EFA
+:1039F000E6E74CCCC2EF61ED18CBE8EF50AEBF9ECE
+:103A0000DB85DAFED489FD918E48B42F2C266E46D4
+:103A10008BAB8917F1C1DAB8730B95B0B99FF1F18F
+:103A2000473F6FAD7EFCEE2E2FCE6BA0767B41EF35
+:103A3000C2F853B6D1E7C17A1F7A02AB100E19EB68
+:103A4000E778783C659717E1368D79F64A43302E52
+:103A5000CC9389EFB74DB3FCF26DEC7F9A857592EC
+:103A60009EEA8BB593A3F5F0E5C2DFD62BD75EE2D5
+:103A7000FEB6E59ABFED08F7B7D5097F5BEC7DB9D7
+:103A8000BA43E3D38C905EEE3749E87FBB2039E23E
+:103A9000707E07BF2AA37B74DA3D318FF0AFB51675
+:103AA000753FF623945B8B0BC93F7149DC2F685D32
+:103AB0005B9A86C431E0FDCB0D72DB3EAFEEFEE5D6
+:103AC00006799F883F17F7DE1C71F4F765C43E66E0
+:103AD0000B78B789FB6F6DC21F26ADE6F73CDA6243
+:103AE000FC5BF1857C9CC40699DE2708E141EA2055
+:103AF000ACC7B8DFCC6611F1398E38FE6E01BFC796
+:103B0000943286C3B64DBB3727F0438814D6EA54A7
+:103B1000D3F0FEBFBDD0EFB5E11B63594FFC3A2E89
+:103B2000F95BDCCF67DF6DF9E6FBF95BFC586EC132
+:103B3000D826518E621CE445EFDF0FC1B8E54DF683
+:103B400048B9027A95A5414B57FA27E4C27A2591E4
+:103B50000E2E7E18E38A1EB6B2A8F1F4F35362FA71
+:103B6000377A284E48B47FEC7B13147A1F43A4FFA6
+:103B7000F3217C8FE06163747F84EAA23D26B4F177
+:103B8000E4B68296E67111B90572EC7788F79E1E4D
+:103B90004729FD990721DFE21D3388991A2F571114
+:103BA0007F37BAB8FD8C3101F8B45E5D6ECE3E3A17
+:103BB000E7573C145F61F57A487F3D3B98DB232B48
+:103BC0004C5CDE28472AE9495923F3EDFB9597E43D
+:103BD000DD1F902FA5644F7B15F5134DDE811EBFB1
+:103BE000F1FBD06FD376E01BD08FA555C4318BFD90
+:103BF00036F79EBB07994CF5FCA390BFA8D9814F1F
+:103C000007EBEE61E4B57A4CD89FF6774C5A17E78C
+:103C1000C8924E3E2AD95C1FCDCBE7F229AF35D4EE
+:103C20009803FD29CE2A92AB5ABD1C47AE8CEBCF30
+:103C3000C914720EE428EA9F39AD013AF2CF51025D
+:103C40003371DD39D50B4DA87F2BD95CFF2A690C68
+:103C500059C7E35ED6C8F49EFFC7423E181DF3491C
+:103C60003F37565B6C88BC7BFC4F5AB1FFBCFC7D78
+:103C7000343E7328F42E1753F8DF2D7C2C5119B5E0
+:103C800059379FCD0EA502E731DA105841F10D49A1
+:103C90006355A497ACC42915BE04CEF7EFB6E17DF9
+:103CA000E0FEDF2B9DEDE1FBD220F983DF477A2B8D
+:103CB00002DD9C45CAB3C53B0E19D9FCFE9127E82D
+:103CC000203D7FDCE77ED27F33B2155AC72F94EEBA
+:103CD00078D4EFF298BA622EAED36FF370BF792723
+:103CE000D9A9AE351EBAC76271756FB90ECB7DFC0E
+:103CF000EF4A6AFAF2A59FA7521CCE83D981FCEC49
+:103D000051B89EEE4770DFD916FEF71A2EFDDC4C37
+:103D10007CC2F5A3428A236972753F52C1E8FD0354
+:103D2000B2932DAEB06508C2F1B2EC93104F619B17
+:103D3000F05D1F9B8DBF375402744AF700DC12C53B
+:103D4000A9D87C3D6F61FF533C6FF9701D65E27D22
+:103D5000A4587D8198B376FEC3707D41F6A1855C41
+:103D60003F0D5F2745F488094C257FB8A65FECC05E
+:103D7000EB8AD074876CA1F389922E0E8729AB5FF2
+:103D8000A6F1ECBE4E15FDD2F3D19F09E99CFCE9EA
+:103D9000741F61410BA7A7B9020F9902FA37F0D738
+:103DA0008AEC78112FDC405F926BB89E66139D2BD6
+:103DB000E4347A4DFAF7B5B4F75DE6B6F0F7704C37
+:103DC000E29E584E89882B645BA87C46B624FA5D37
+:103DD00027BEDAFB227CDCDE77878A38BFBE2B77F2
+:103DE0003ABDF39358724D31CEDBAD300BC6B32CD8
+:103DF00016FDC4BE3BA4CDA7A4A2258DE2847ADF24
+:103E00001DE27260E077877A26E460F9640FFDFDB9
+:103E1000ADE5D99EFFB7DE1F02BAC0F787D664F3BF
+:103E20007B41BDEF0FF9A2EF87C6BE3BB4398DFBD6
+:103E3000EFF7B0D02E7CAF23986F72205CA7E5BF60
+:103E4000FA8DFA437DCA8C468CCFBD34F3F219BC8F
+:103E50007BBB7D6DE54CBA17379CDF7B67C103BE2A
+:103E600019241FA3F58CC8FDBE2174FF997C2A6913
+:103E7000FDDCEB2B5242FAFBCBB68E547EDF7D800D
+:103E80007B7D36E780F7FAC224B7C5BD3E940BD8D8
+:103E90007F6D91D28674ABBDE36913F7CED84BFC2E
+:103EA0005CCCD6C6F5044D1FFAF4252BF9E76CA0BF
+:103EB000F7A05EC27ECEEF675C127654D0A7ECE32B
+:103EC000E769AA7B86CE4E6F107CCE26851752FFFF
+:103ED00007FEDBEFF71DCED6C9953EF7FB06842320
+:103EE0008F37EC79D01E753E69DB3D2CFA5D81265B
+:103EF0007E4FFCFD7CFE771B237A56D8A17F5FC0E6
+:103F000066E4EF53CC13F7F334F8CDF39BE8EF7985
+:103F1000D824FE0E0653C20EFD7DB079C5F3E9BC70
+:103F200064207B799EB8A737AF31FA5ED3EF50B1EA
+:103F30004B46FFD278BA6774EFB64AF29F2CC4FBA7
+:103F40004943D0BFD222EE1B45FC48F82EF112D6D1
+:103F500049F99E4625E886F57ADE8E0FA1C801ED67
+:103F6000C0C3BE83FA9A9FF8A03753F685B199244F
+:103F70004BA8A778D0EB9C0AD36F52084E6D8D5298
+:103F800008E34B3735C8E23C95F3F16083AC623F00
+:103F9000309E1BF5F22F85BC1DE411F22AE6EF7F5F
+:103FA00069FD3718393F5CCBE430A665897F37A1BE
+:103FB0003CEDC71ED2FA6B30D65B50DEF764C9E425
+:103FC000776D3006EA70DF1ADE899751DE37D8EB5D
+:103FD0001B2B7839D1DA17D67005F93F8BF8DF271C
+:103FE00025F283F9FF6FAFD51F430080000000006A
+:103FF0001F8B080000000000000BCD7D097C54D50C
+:10400000D5F87DB327990993909540329390050890
+:10401000C9244044409C2484468D74D80414710201
+:1040200001B20341DB68C14C4C80A0E133D4284885
+:1040300051266C6A051B10904AB4C3A6B46A8DADB4
+:10404000B6B8F125A82802128356DADAFA3FE7DC7F
+:10405000FB26EF0DA4D0DFF7EFEFFB62EDF52EEFBF
+:104060002EE79E73EED9EE9DC4F783DA1E9618BB39
+:1040700090A0616C0C630B9A8C8C9918FDFD00FF6D
+:104080002E6C51E7176F54E7CBBCEAFC02E6FE55F5
+:104090008C96B18A67D5E51712ACBC7F6633B02425
+:1040A000C61AF5B63FD84733D6B356C7B6DA18ABFB
+:1040B0001FAC71B21B18D30CE16962D8A4D90CEA09
+:1040C00059988125C3FC9A75F0DF11903645B47973
+:1040D00020DF18C666B79BFFE7F30D9C67B42D85FC
+:1040E000E609FDD3788D6B252F8E077F4E9CCF82FE
+:1040F0005DC66D0FDB21B5D842711DE7A49E342D3E
+:10410000947BD6596C3BA81DAC338AB1F956DEE7D7
+:10411000279263A70FDA6B1EDDBD3605BF7F449B78
+:104120000D23B2FCE96627F6FFF29766AF11BE2BAE
+:104130000598C58643DEF1EE6B581FB82EF8B3E93B
+:1041400072A05FFC2FD8AAF911CC199401FFAD6CB5
+:104150009788FF6F602C4DE4A1CF8448D7CDB64837
+:10416000E8370F0A60FC973719BD0D30DEE39A4F30
+:10417000F6BC8EF0DF13E440F857AFE8D9C9E0FB96
+:104180006F22DC93B1FDF9FB3F982C4139D3F1EF5D
+:104190002EBE12BD15F16474A3B1AF7FFCBF66459E
+:1041A0001EC76F8245DC0869ABBABC7473C077EC7C
+:1041B0009F46E53C196B21B83F61700FB3C2BE6EDC
+:1041C00072E5E4E07C9ED0B71432A85F1FE39E8DB9
+:1041D000F3FAB4C0F59AC64EDB91E21AC9D8ABDF48
+:1041E0002F48D2011C3D274D8E1D50FEAAAE2B2418
+:1041F0002C9DB1F404983CB48F31314F70382FC7E7
+:104200007E0D0FB17B5C90FE807F37F7A50B6C12A3
+:104210008DBFDCE60C4F80947D0FB302786B11B636
+:10422000D095C9BCD7A985715887644D86A4DAC6D4
+:10423000BA17873266EE909C89009F2543355E0948
+:10424000C6AF366BBA6F80F264B386F0850DD57950
+:1042500093B1BC957916C37EE93AEA3DD81FB4F311
+:10426000DC00F965063E4F791ED507A73237CC2F03
+:1042700024C2A55908E3E94B3504A327F42EEAEF3D
+:104280000968EB81FE46C3FE7BCD58E3A57947194B
+:104290005C7941501F15E5737870DF984BE3B230BD
+:1042A000B6D2E6DC6883FACFB02816E830DA598750
+:1042B00070FCF67CB046CA64ECC4BBD30774413FC3
+:1042C000DF32D7002BC0ED8CD6FD132BE0F562E674
+:1042D0003120DCCB989752D63A90F675918EF974CE
+:1042E00000CF45339CEF4B199CBE7C01F4A5CC5705
+:1042F000B24EA2770674E653E043A5CE7758023853
+:104300005599982F04D376F577D5AC87BE5B72F0BC
+:1043100007A34F45071C4FA2B535594B71FD4EE71A
+:10432000D008D827336FC2FE1ECBE1293998CF02BF
+:10433000F3BB279DB94D89D7DFEEACAD254A03EB22
+:104340006D92F8F893B566A709E05AB54E43740A22
+:104350001D158D817E4A19C78B25B6C96719CC3FBB
+:1043600002C80EE9D97440EB7DC84EED1D3EC8571A
+:10437000BD627160D3525B6911CB40F8E84F772979
+:10438000D653CEF64CB6129C5C03904F543CABAE69
+:10439000AF6A57E79730DDE92E198ED0BEF6A3B687
+:1043A000F1C71474D561B3449C194173B3FF807095
+:1043B000D7CE1DE0BE0ABECBE97775DEF1C7F4B0FB
+:1043C0002AC97904F1A25CC79CEDE957B61B3F846A
+:1043D000D3C751F3A5816E457D5E3AA033E473F2F5
+:1043E000AE4E579D4857D06F4827E02BB433E93C79
+:1043F0002C4CF17D7FDFBD6FD3D077470DBCFE51D4
+:104400004B8813E11763604DA6ECBE76311AD6686F
+:10441000027C7426B83EC4F99B6C3603CE6F9BDEDB
+:10442000C334C8172299630780E1293DF30441BBD7
+:1044300038AD86F6334E6BDA8A7CF08FF17C5DD72F
+:10444000C28F90F41E3DC2314EBB87F06E888679D4
+:1044500018F467D0C0B980FD86301604F3DA1CC4A6
+:104460003C381FA86712AF672C1BBF633E09D26898
+:10447000D8CB10287F14CF17E4BF23CDDEAD308515
+:104480005828473E0510EB92A0FC911C930DF96D46
+:10449000B486CFBBBFFD8BD6318F399C5266C11419
+:1044A000966CF917ED657E116DE4F38A0E59DA8684
+:1044B000708ABE272DBB01F029C8EED2D92309CFBF
+:1044C00033907FC870A916F8EE87CB41C96709ED14
+:1044D000A39B1098B30EF95D8B91F81DA12CE56399
+:1044E000BD782E9EC23CF08FAA185718EF5F9CA78C
+:1044F0008F8E24F983D50E24FEB4C602FB9D4E7028
+:1045000054EDB34CF79B25BEDF39799D747EF6AC34
+:10451000640CE127B74B1078166F97547C7585C0F3
+:10452000C37BECCE043BF473FE7D93890D80298E12
+:10453000E6745BED3213FF66ACCBF033284B3828C2
+:10454000591F463E94A6A1FE360F710FC379AFF9ED
+:10455000C0ECD1C2770FA79D5E1D87FC39C2918345
+:10456000EC3109CB819FBA86B84762FF252BDC5F0F
+:104570001F46B6396D7806E263CE0FF9AB0BF97CB6
+:10458000AD5B7148235BAAA4B3DBED1CDFE5F456F9
+:104590003BC7CBF3C01573615E0911CE3988170C88
+:1045A000CE8364D882105BA713F3D5FBB870429317
+:1045B000C0F3E9678309DED5FB72B38E63BE3D2885
+:1045C0000BDBE77C6826789FBF7F90570BF5EB12DB
+:1045D000DC79B81ECBE81E09E7777ECF2D59980607
+:1045E000D2818CFFD14037D87FF45D26921F643C86
+:1045F00078420FFB9FD4471FA3ED369A7782389FEE
+:104600001256B8D842735FDE1CC1F707CA3538DED0
+:10461000725BC16884D768BB8EBEAB89D1DA3E1DA0
+:1046200088A8667D88D9AFC45F3B50B819F8DD23F0
+:104630002004FD804BF7405E21FFF4B6488508D783
+:104640001A10C46AB3FBE6237F5F1363A0FE432EF8
+:10465000EB083F13AD06DA774B93C0D7158CF07794
+:10466000424F67FE0058EFD056DF042D741184636B
+:10467000C5127E3C9209E5110375131E86F2A76BE5
+:10468000B38F9820AF5BDB79136E81BD9569822073
+:10469000D5FD43E7C275D21FD497B45A399EEB9625
+:1046A000A64D03BA5A2BF677F310E732DC87BCF736
+:1046B000F434FE5FD67179F02F61B9670F4760DE81
+:1046C000088CA67F7AF6B023263616D6D19C686071
+:1046D000E9B80E89E0CB860262C07C75EB3EF2F051
+:1046E000F9BD3B04A7B2CD6EA671E77B1C93116C9C
+:1046F000F8BD2606E0DD62CDC3795B9AA769C4E602
+:10470000C74A509EDC344363837C720BEF3770FCE6
+:104710004D82CE7EF3BDB610E5710D743A14CFBD57
+:10472000A1E16D5AA427384F70FD55A911B4FEC7F9
+:10473000047EEB5A5D0C512850FEA9DA57CF9478CD
+:1047400028F31D99DFC878F71BE817D7F51B6622F9
+:10475000F95CC6BF463D87B7E71F1AA28304C6CFE0
+:10476000B3A447BF8FA57ED9439CDF0B3EA8D3DB04
+:1047700056C720EFAAEF9A88705ED01CA6A94EC734
+:104780007E1C35D4CF3A33A37E9A138FA4215F6861
+:10479000B232C986FD2D4E207AFCD0C8105F74EB72
+:1047A000CC1A3C5774EB9D58CA74615179947F1CA4
+:1047B000F2D0FE3EBB9EE65D21F0B151EA9148AEDB
+:1047C00062CE2C9463EFB1BB0F201E84087EC46AB6
+:1047D00083BDC9842F9D44B74FE7740E41F83D6DEA
+:1047E00060A5B89EBC47D3A711BEACD54946C45FEF
+:1047F0009D3B210CF29693D1241F1EB16B5478AFD0
+:10480000C0973806FB9AF88AD685F4A8D373BCD72C
+:10481000AD05BD0ABEFB2CD27D1CE97182A7331FFA
+:10482000F163E2DA4F43726DD77F0E30A787DA2D3E
+:1048300091F9478744FCA3249E51FB5A536806F222
+:10484000DDEF82781A110C29F0CD372F803C0A79E0
+:104850008FD0533CA782BC781EFD54DB53AF8375C9
+:104860009FB4F3F1BED3707EB3145284C33C93FB68
+:10487000439C6F6D57560CEEFFA1D0A83C942B6162
+:1048800092F1787E9DD6733D31100EF34CB95D08E0
+:10489000EF37851E89E3DB611EE1B5F92EE40F11C8
+:1048A00006EF938B905FCF34937E147E7F2E952FEF
+:1048B000FFF81909F5AFFC52467435C865F022FCC3
+:1048C0000F4962DEAF6809EF06153A63F5900F777E
+:1048D000192413D46B63464D2881EF5BDBF8FEB6D9
+:1048E000EE48F522BC0FFC534BF99E62E6DD0AF957
+:1048F000D62CDB9325585F964E72FCCF2581CF0BCB
+:1049000019F5DB6AD1D038AD5580C0D81EFE95B000
+:10491000FD321BD1C178AD86F77737EF8FE9BAE862
+:104920005CBE38D66A457E353E81F7D733C74072C4
+:10493000875FBF9B9DE67D98BE973C2497CC09A6D8
+:10494000FAB3023F3CC989DE1DF63E7E76F1DE7089
+:104950002FEAC10CF8A609F4DD3C517551E8E99E37
+:10496000D2606A7FD1ABF124C3BEE67549DDB82FB2
+:104970001799E8AF94D327D3B5FB34387EA1CD8106
+:10498000F363A6026797424F80F61ED4BB3C660DC8
+:104990001F5FD7138AFC53DE47A827BE13D5E08CD0
+:1049A000457AEC996AD028E50139FD9DE03BE95153
+:1049B000CE84C4317D782AE3F3A1ECE83CD467FAD5
+:1049C000C3EB3F32CEFF6727BAD212A13EFF8E5B08
+:1049D0001A6992455C2F3A2A011E013E1A0C5CAE00
+:1049E00031DC11B7B5C1AE945F38DF3924DA8D8878
+:1049F0006326D4F781163DB87FC30F0C27FE98932A
+:104A0000C8E789A4837684E1E26C1B2EB5D78401C4
+:104A1000DE1F396D8F47FC93F1FA50701CE1BB0229
+:104A2000AFC7E3FC02E7C574AE91D3465E399FC9B8
+:104A300089CE5C828768DFBFDCE8A179190CEDCBF9
+:104A4000083FAA802E607DEF62157CB7ED0EA34F64
+:104A50008BFBAB3737211D9F0C99F75A2480D26C02
+:104A600072FF18FB9F3DEB96D598978E0CB4D5C07E
+:104A7000BC2F1677E5A07EF5A4D13D1DE75B6972DA
+:104A80002744C1BA7ED2DB794A42BEE81A28CE5BFF
+:104A9000D748D7C8FEE7932FF1F1730CEEB938CEA3
+:104AA00051A9CBE24822BCA7EF983992FA3925E008
+:104AB0007558EF9CF035CCFFF0FA84AC06984F7E29
+:104AC000E8FB772DC1F3794374169EF3325C8E8A2E
+:104AD000752DD4B8A27C5AD57CCB68BED6E284D8DA
+:104AE000449AEF3CE2E366315F9D63F0BF9A6F83C7
+:104AF0004CCF2B25C2E7CDC180F2D97D74E5FE48AD
+:104B0000D3867465D434B471BE6072203EBF2DE686
+:104B1000037A0C43F917BE23F97807730C471E106C
+:104B200067E47415B74622BE399F39487F2D61AEC0
+:104B30007814115727BAEB71DEFF1DF2CF31766E74
+:104B40005218F32EF47FE0A16807CAB96C029FFFE8
+:104B5000B5F69FB1660DDA45A609FBD64221174D81
+:104B6000674E3D8E3793B9F5088F3F7C6570A25E26
+:104B7000FC07A1FFCC621E2A9FC3BC94DEC57CD477
+:104B8000FE6ED645F977423286D402FCA76E484DB8
+:104B900046FC56C07B03EE2BE0C73D11881F0FBEBD
+:104BA000C3F1A335F2BAF075AAC00FA0DB2D44B74C
+:104BB000E1F98DC837D9248E177DF4D1D53000E0C6
+:104BC0003735CA9E85F0B8F97BBE1F933FB5B669ED
+:104BD000A53EBC00C6618E85F5FF486C59672F3F26
+:104BE000BF4E38EB2322605E055A33ED43A7434B9B
+:104BF000E7C2EBB915450887D7EBF9FEBCFEA481E7
+:104C0000F6670AF33686417A4BC4D4013EEC073589
+:104C10002618AF335DA273A170B0BE4FCF877F6FF0
+:104C20001DAACE4FD9C8ED0E454E6DB711D374B540
+:104C30009D600A6BFE5A9B81A9DA5E7018D7127EBE
+:104C4000A5DDE068A2B01B0C67C3C91E77FD7683A3
+:104C5000DF262AEC060CAD93C0B77E1CC4F96AE7C8
+:104C600084A3E32FC2BA2F75D809CB1F4AE172EF94
+:104C7000DF135DEFE077D586AE79B8CFA7EBA0AFB5
+:104C800054C63EAD333127E0F2993A2BE5BFA88BED
+:104C9000A1F4CB3A1BA5E7EBD2A8FEAB3A07E5534C
+:104CA000929CEF237EAC09E2FB208FBF5CE0E79A89
+:104CB00021391B5C30FE9A37F5942F6D6F990CAA41
+:104CC0003A5B3EE4F4432100EFE5CF49649FA9E855
+:104CD000701ACC30DF85C7DCAB51FC5DFC66D714A5
+:104CE000641F559725E606D2189FE2FA1CC719F3F0
+:104CF000DEA7510897CFEBC6D23CCED639691EE766
+:104D0000EA0A29CD4D729DC776D54DD2B138E8EF6C
+:104D1000F65DDD3A4C0B0050B8BF139DCCEB857DA2
+:104D2000D8A877BB111F36C69A1C880FB923A73D98
+:104D3000752F437EECFE0BC26566F8828281503E81
+:104D40009975350E847637CF951C3E5B1FDE5E9BD2
+:104D50004E391CAA044E5C785522F8FC719F96E6E9
+:104D6000D17B32D80B270CEBDD174278D7DB6424DC
+:104D700079E290C1638C87FCA1F86007F2C743F128
+:104D800083E85C340A3A3A07FBC460DDD3F7274571
+:104D9000A39E706EF74F6394F6A073E1ED7FF90068
+:104DA000F9D6C71AC7561AB9FDCC26C8BF343886FB
+:104DB000F8CC57820F571B383DB0539AADC807CF78
+:104DC00005737AEB793F782BF2BBD3B21CFF7E7070
+:104DD0001BCA09392FC4E531F539179314D9B7AE79
+:104DE0009AFD23A251FF618323083E69924E53AB83
+:104DF000B01FE0BC6DA97DF9617B179F7EC0D6977F
+:104E00003FB4F76E279EA33B773FD9FB32C259E8E8
+:104E100007CFBDF0D4A05F40AE72CFAA605C27CAB6
+:104E20007963817E0EAD0F21FE7648EF38558BF306
+:104E30007CCA4C76A667FEEBFED307315D57957DA5
+:104E40003F822C299CF6A3E4E77326C742BB9D074B
+:104E5000581692D70898631CCC2F7DE3D74750E4AF
+:104E6000C8F086E50F8272C7B359470741FEF9972C
+:104E7000241FDAF7B3DBDBB64AC843BFDF3608E5E9
+:104E8000D99B936C2AB97EC490C2135A9277D5F2FB
+:104E9000427AEBD779D8DFEE415C6E00F9E1CB7A4C
+:104EA0003BD2C39FB2DDA4DF717BCA985766BE3187
+:104EB0009EE1BA3CB128CF7A8A0D6447C7E5EB2161
+:104EC0007F615F12C92507341E3A8F3CF34D0EDC1B
+:104ED0008F0B2ECF93B87F55D01EE5CEAA2C4FE86E
+:104EE00038D4F33E1EEA000C64439EFE5121C2A753
+:104EF0007ADFE3930741BB0B13984382A997EEBF78
+:104F00003499F61DB451D46F2EEC6B88BA13BE7B66
+:104F1000243D6F0C9EBF2E6D3B8DC396F07136887D
+:104F2000F38E7565905F8550DB86FA3F3361797843
+:104F300047D8E138D6B75F4B3AEAEDE80F18ED36BF
+:104F40003950FFDC68F7C4A2BD4E3E3FE11C2C4641
+:104F5000BC8935887EADD3494FB8DEF34FB6E7C97B
+:104F6000FD6D3070FB9C6CEFDB6CE0E7F90EE03F11
+:104F7000887FF2790DE32E4B1AD3672F64D617B3CF
+:104F8000AC30CFCF408E22BBC0758E2FCB574B8419
+:104F9000DE9427CEDFD9031B5EE982F58E31B95747
+:104FA000E2380B9993DBDD750E1BCA23834DCE07C8
+:104FB00093E81CED89C735C0B9FA10E6ABB5207788
+:104FC0002529E42ED3F59DAB0D427F0BE4B70D965A
+:104FD0009C59681F69407E8B74744C53F91A9C97D6
+:104FE00037F196B0EE517FB6E1BADFD23394F71BBA
+:104FF00018BBEABA5F057A75039FF1C179E04EC527
+:10500000469D0D688F71C2FF2CF0DDC4CBA808F25D
+:1050100031F1FC0AFC1EE0BD05D797CB4254ED9C54
+:105020002C8CECC3CC1C7E5DEB9C107CF57365B9BD
+:10503000E548D2A380C7CBBFE5C2D4F26FB3891FC6
+:10504000F6B79E57C47A7E96E2DE93A4A0DF9BBE9D
+:10505000B1EA901E61BEFB112F27EAB4CCADF493E8
+:10506000C9F8799DF3BD4F621EB4E7B2AF0DA45FDE
+:105070007508FDADA32C9DF4C30386A5FFBD12F5F5
+:10508000AFDFEB895F7558B81EDB31358AE48E439C
+:1050900032DF2DD6927CDA1124BEDF114DF5838CE0
+:1050A000BC9E45335E2FF73F278AFA07FE48E78B01
+:1050B00007F447D257A73A6383513F9D1AA5A1F140
+:1050C000FF7974C4AF90CF4F35915EEDD78BB31895
+:1050D000E99DADF55C2F1EA45DFAC648E4130D21D1
+:1050E00034CF56CBD626F4B3B5AED43A10AF5AED82
+:1050F000BEBB502F6CFD3A85EC1DA0F7929F00F4CB
+:105100005BD2BF7A8AB56D5BB93E2BE7B70A7D7675
+:10511000F65EE27F1ECB5480EBFB62BF4EEAB81E08
+:105120007912F5D5CC3E7FC149D42F493EF4585071
+:105130007F724F09D121DE0796CBFB20977FA00716
+:105140007D14E100FAE80E853EDA1AD612897EB6A1
+:10515000BF27B97B110FE62CDC11C4F9B13708F574
+:10516000DA07B5AE6FB07C53B063CA1DC8874BB8C1
+:105170005EF6815EC0F5AF5C0F7EB5E4F8025CD7E9
+:10518000AB3D314C692795F1C06F0758A9117600E6
+:10519000BE4F5BB64793DE3E3E01F000EBDFD2F23E
+:1051A000735AAE37A7F07AAD4478D4B32748B60324
+:1051B00090BDD9B33F95C62F9CC6E5D5DE159A366E
+:1051C000940D7C758E099392E17B61EFF3745868BE
+:1051D000FFB70878DE23F8D41661F7F7B4EB853E05
+:1051E000EF8B5B82E3760C23FDDFC704FE1D0CA171
+:1051F000FA5EC6FBEB351BB6E13E5F147CA741E2CD
+:1052000072C416E65B44EDDB8354701E64E4E5EC87
+:10521000452857C0E7905EB4DF132429CB0F187CD4
+:105220003B695E7B79F99F8DEE94A10A3AAD0CF54E
+:10523000A58499AF07AE700E20BEDDAFF5D7231E53
+:105240006C593A52862BFFFE4923D5FBED2B557640
+:10525000615FF1AE4DC1F61D91048FAF567C92B3E4
+:10526000D14670CD3888EDF619891E64B8CAF3DBD3
+:1052700022F0CE2DEC0FEC412E579DB2765994FEC4
+:10528000B653AE3316E4531FD56A7D86D0FEF9C9F6
+:10529000DC8D9FFF03FD6D735D866ED423FA6DF781
+:1052A000E07CF26BF65B5FFAFD3CEAA7521DCF7023
+:1052B000EF50A76BA8124FCF6A54F6A897119E9291
+:1052C000029E167F3D8F9BF8225D6DAF3A1B2CE04E
+:1052D000C9ED499EFD76821313F874E6AC86E41896
+:1052E000795E2FEB38BC5E16F6297FB9B027F9E15D
+:1052F000F825C011BE6BB03A4C4A382644BACB11DF
+:105300003F1E32679BBAA0BC7440DE09941FAB7588
+:10531000703EC3BEB40C752FC17A596E91EDA15584
+:10532000E9BE79740EAEB8BE73B622B8A35A4A84E9
+:105330006974EC388029CC8BE0C1F672FEECD6F8AB
+:1053400042455EC27956C07F4E0C47BF329C5DE13C
+:105350003C8FF26A609C0B917C14AF4739A1A25D2F
+:10536000EB0C0AC5BCA1AF9D1DF35E922340BF3379
+:105370008D0579A622ECE07F8D87F272B3D9B482D5
+:10538000FC95EA7893F27D6B3A9332AE2CBF727C37
+:10539000BE3E6676DAD09E503C96D78DABCD679FE9
+:1053A0008C0238093BE2FC66AE0FC35F3DF2FB9214
+:1053B0005689A11E51EC99752BE255F18CC2B3A808
+:1053C0009F143F5ABF1AE59FC5C2DEBCF8E0E1BF9B
+:1053D000E27EC8F10BC5EDCF7C8BF2E8FC80F8953E
+:1053E00092E680795D236EA57CFB0F46751C0B97BA
+:1053F000A3C775B46991AE168AF933CF4486EB1A08
+:1054000027A3A090233EC5CC8D1887E1DA83F8311D
+:10541000AE957F57C578DC851C0FB1C808E732C050
+:10542000FB84C54070B8B47100D9132E097CBEB49A
+:1054300099C3A56A20CF576D93C82F5725F84BD530
+:1054400033DC0EB408E038209BC7693815F3AE147E
+:1054500070C1780D65396BE172A81C9F81711B4E7C
+:10546000857FAD12D675329CC76B28BF53C66B289B
+:10547000CB15F62A61E7F212BCB6E8BDCFED847910
+:105480006A1F0C96E35582514E5DFEF18F9E447B60
+:10549000ABDF9E5EA6EF478E1076F31D9C8FEAFB76
+:1054A000E4086E5F5F3F4CC811CE1494B3D96341DA
+:1054B000A4D7B4466A3C41585FC6F5DF563BE727A0
+:1054C000AD735284FD7CAF8FCEBDC725FFB988FC7C
+:1054D000FBCEF57DFC9DC65D6711FCDD9962A2FAED
+:1054E000610EC18F787D2493F9BB9037BC915361D5
+:1054F0007D1FE07F027CEFD43317F29F3BDB38FF48
+:1055000091E58D3B2528C7F63A6F24CA0332DC02A9
+:10551000CB653E2197B7863963C3D3294EEA1FCAAC
+:1055200073AB35CC1B84714FACF4FAECBB3B04FF7E
+:10553000ED591F44F3FF54E2F15625C1AE876F4683
+:10554000FA7B223111F1CA82CA5B24FAE101BEBCA6
+:105550003DD983E5FD2E813D443DACE4E7A9849728
+:10556000729CC7A92C6E6F0B19CDFDC051A29FA8CC
+:10557000648D2A8D09E671149F16703BA165B4CB2A
+:105580008072D20E1B8F0F2831B87E7793623E3027
+:10559000AE09E16413FDC9702BD1484EF47F94FC31
+:1055A000DC48F400F320BE9E532351FCC7A7C2FE83
+:1055B00027EF0B635C2EBAF3EDC86CF247B07AD9D3
+:1055C0006EEF417F1EC873C477FBC547C0573CA729
+:1055D000C202F171872CD7727C637771F91CC49B6E
+:1055E0003943A1DF05D30DA40FA12DF76F28E716CE
+:1055F000D8BC57956BCBF46D5BED0AB9B64CBFF5D3
+:105600006A78E6C78F003C0BC49BFEF0E93AF0ECE9
+:10561000D6E4C8FEF10CBE1FE3B2F48F67552FED40
+:105620003EE0817996FFEAF15006EDCEEA5AA21CDF
+:10563000D06FE58E55A14E48BFD07942B1BFB35E61
+:105640006DE1D5FCCE4DC992DF1E2B29FC385FE8F9
+:10565000BC2FBC0C70297BDFE8809D634B9E35FA24
+:105660008C648728233905F2DD3CBF86ECA34B0E02
+:1056700006C4633DF37894CD42F38C43BF3848A40D
+:10568000E42FADDEAEA778AEEA77B50E448B25AC3D
+:105690006735CE2FF07B9CC765C0DB25EDDA62C392
+:1056A000802BEB61C70CC8E796EC7BE46BB4DB04A2
+:1056B000C673950A3B5BA07DF6A7C996883368B888
+:1056C000BC81DD80E729C0C5E1437C84F924F36D0A
+:1056D00027FC6D78EE99175E86799EFD203A0B5572
+:1056E000B5F3DBDF0895D2FBECB5B21DFB7C7BD2BA
+:1056F00000F755E02AA75F093B5FDFBE71BE6D3B37
+:1057000028519011EBE069A5DE173A1EC6AB6CD3A9
+:1057100093DDA772F7B69D9B501E01F863DC49C567
+:10572000EEE37F1A07F98A3DFA8822BE1CB314D52E
+:10573000B75F4B6CDC4E22EF4FF98BC70DB691BCB7
+:105740001CE50B799F2AF61C36B09157C233BFFD7A
+:10575000B0A1CB7C95FD6AEF9E8CF6C086E7BE3388
+:1057600020BD9D7D5562D1F62BBF2FDDF14628B6B9
+:10577000BBD6BE9DDF1E427CF17C8744F122FDED4D
+:10578000DF6CDC8C3188DF161606E3967E60F4163B
+:10579000E1BEFED772C2F3CF754B399E3FB52ACA20
+:1057A00009F32ED57BA2AC94F2F2D2A7EF13F8E75F
+:1057B0008CD5904CE489C5F52CDC3C93D653FAD4B7
+:1057C000025A0F7B526263600BBE053976CF55F6E5
+:1057D000F11F820F7EBE153611D6F3B9884FF4FC47
+:1057E000412BF8CE32924FEE136BA48819C87F2B51
+:1057F000E25DFF98ECF7439A94F2EB92ED6B3A710D
+:105800003FBE1CE28C463D16D6EF117092301E470B
+:10581000FB4E4134DF0F1EAF4CDFC159908FE5D8EE
+:10582000BE534F71CB8AEF086EF2F8F78AF161DE52
+:10583000C128477F1EC5E31D18BA48106F24FE4DCE
+:10584000F58AD2221BC07F84F027F8E97CFB5A4EF0
+:10585000D782CEBF7997F38F6AEFD442A2FF4EBDB5
+:105860002F1ADB790FCF9088FE03E34E051E6CD70D
+:105870000B3C50D7C3BC7492129EAF723FDEA2564F
+:10588000457C2BC249F85F96801CEC4B53AE53F815
+:1058900091847F65B1A0F7C0FD0BA4FFEF92857FD7
+:1058A00046D0BFFC3DDB7C757F401FBD7B681F2B56
+:1058B00041BE4039A8F27D23C93995EBB5149FF458
+:1058C00049F3D1A81B01AFCFB5CBF4A9E6A77EFA67
+:1058D0005CC1E3574BF7EE90103F03E9F35CA95727
+:1058E000BA2A7D42F955E9B394FDFFE5A77E78AB6E
+:1058F000E971713FFCD49EA2E6A7DFB2F40168070C
+:1059000067D6E204B2B705C0558667205FEC402633
+:105910001779255F64E81A57C051869F8C9FA0B9FC
+:10592000D1387EBC95F1533E9FFCF819B85E351C0A
+:1059300003EBCF08FEE3FA358F27AB047EC5E39671
+:105940003DAFC58D267A74127B612DAF61FC625F1D
+:10595000DE1B906F0F68EF0CC8BB02DABB03F24B83
+:1059600055ED2B0F1E35F0B8329FAA9DB1F636D2F9
+:1059700097AE9413BC9CAEF77D6DF0205E0CEEA14B
+:10598000F8B63CADE34416ECEB6D9617CDC8571A4C
+:1059900084BECE98E304DA95270F4E12721BE717E8
+:1059A000F9825F3C90C2F961BEA982F6A18169B813
+:1059B000FDEE0A3EA821F9EC75D34D3B51DECF1F19
+:1059C000BC8EF8FCA4C15A9F3183D26E4C273B3861
+:1059D000DE370C1E3518E5FF06B3D1214938FE6DC0
+:1059E00067957E2A39CD37BD351BF5A94966353F08
+:1059F000B92D803FDC6253D717B2BD1128BF16A660
+:105A0000EB9917FBC7F60ABE393BC54AEBBA85B519
+:105A1000345A399D51FE2601D7C1BA2C1DF2DD49F9
+:105A2000BA778EA21E93FB0DB3717CE0F0CDFFC65A
+:105A3000A143F8E69AC3746417B70D09433E832C5B
+:105A4000E68738C6A6B4EFF90AE589293342C87F4C
+:105A50003385B5FF1EFD3C6C86D601B238EB7EC1A6
+:105A60006240FFCBEDED5FEB70BF6F9F20A15AC589
+:105A7000BA83ACF1CBA0BF622D8F736D117CBA21BC
+:105A800088CBA9C5AB87A42442F9ED189F77153FB1
+:105A9000F361B15F0DB9D2663CBF121AB8FE20B7F0
+:105AA000C77EB0DFD753F839F50B91CAF9847CDE95
+:105AB000BEA4C9D89D148AA9DE970AE98461795BDE
+:105AC00052601E4589EC35AEE74836949FBB83840F
+:105AD0009D699D9DE47737807A23AEB33689D13AAC
+:105AE000731D8658A8EF5E6FB7A25F3424DD49DFCF
+:105AF0002F6A916CE867EACE655CFEB718486F3A8A
+:105B000065F50D457E7BCA31CC81727C82AC178EE7
+:105B1000E47155FA34F78B388FE296E237111FD9CA
+:105B2000F7B0EE1CF4D33102FE237706331FC9E130
+:105B30008E50A49B07B5AE8329B0AE4F6AB51EEC5C
+:105B4000E793D260F2D72668B9DFE9AB141BC1B77F
+:105B500008FD50D91827D83507FBD93C5C94875BE2
+:105B600073CC38FEAA2086F32B0EB7CEC3F917AF3D
+:105B70004E25FF5DD1435CAF8AD331930EBE6F4D8E
+:105B8000E17C6D6E7D6B21D9C1EAC33518E738D849
+:105B9000C474185F7E7B7B16D1F303C3DCBFC07572
+:105BA0007CB1928DC37D5AD0BC9EF4B4026DFA00D4
+:105BB000C4BB5E66A37B25FDC9993BEB780CE2B3C1
+:105BC00075264A7F5967653AE061BBEA6228FF4261
+:105BD0009D8DD2F6BA342ADF5BE7A0FCBEBAB19441
+:105BE0003F50E7A4FCC1BA424A5FAE7351F950205E
+:105BF00004B47BC07A3CC66C9E0FE279A7219CE777
+:105C0000711DB01ED233317411ED6543A05C134E8B
+:105C1000ED289E1FDAB1A86CB266798221C523F502
+:105C200072367DC70688EF26427E884EDC2F80FEC6
+:105C3000117EF27EC0F7BE28C57E1468CFAFBB01CF
+:105C4000E0D95BAA71A07CDECBBA76BF447933D9A8
+:105C500041E20DEC20CA3D5D0F9A19CA195A8D23F5
+:105C6000C688F132A018E814E7D7DD4B83984EC1FF
+:105C700027EEA90D53E5231E3C791C8FA18B51EE15
+:105C80001F106F4EDD7FE1B367A0FF2D2BCF8C443B
+:105C90003A8779ECD880E3AE0876186D646767E1DF
+:105CA000986FD4CBF6368AEBA3FB66368C170EE9D9
+:105CB000C6F3E86983F54FCFA0DCB35A6B45BAF859
+:105CC00000F70FE0FD91D8BFF98D9C4FB2960D649F
+:105CD000F72C96F96A5381D37F4E01D06253133962
+:105CE0009D06737B7E77E9E9DD2F41BFDD2B0C0E2E
+:105CF000C1B29DA69C2BC7F7F71FD0DFE95846F627
+:105D000027D08A592DDA253B6CA71623DE3E6CA4DA
+:105D1000387E090E87B950EE6E7AFD24F623D59EA3
+:105D200020FBA0DB64A6B835E6D19F57F627D5BE89
+:105D300046ED58D7E0309413881FDE8C760BA70110
+:105D4000E3A1B14FC49BF9694718F205D622595116
+:105D5000142811E525721CB6CE3D6C061C74B35395
+:105D6000B5B4DEC5A93CCEDDCFCF46733DBECC9BDE
+:105D7000BA55ABB04F3F302C6F74AA928FCD90883C
+:105D80007F01BD9B90BE270C9B3F2E750C951F4637
+:105D9000FE5694E71B5A43FB5AC99CE82F89610EB3
+:105DA000B417E2BE62FFBD4D3A92FB647A50E2AB9B
+:105DB00021BC0F9F01CF9D1A4E074C8BF59062BB03
+:105DC000FF149DCEB371FA91E950A6339C9F269B98
+:105DD000C677EA14FC4DDF94AB41FBB94C4F647FAE
+:105DE000CDC17BA5FCAFA459A27B06252D598645C4
+:105DF0008A7365BE285F80F73914E5CB705FC6E013
+:105E0000BD436F7D0CDA67C47D0FCC27021C9F2831
+:105E100077467898A21FB17F0D41AEAAFDA87FEF0B
+:105E20000EA173B078F5DDB78F417EFAC240C2DFB4
+:105E30002FA7ECA1F8B5F98D73EE7B0FCADDCF0665
+:105E400051F98A547723F2CB2F25DBBCFD28877BC1
+:105E5000EC778C81EF3371B3C99EE16DA2711FCED7
+:105E60001D437179CC664039519EF7FCB4ECD5E8FE
+:105E7000079DDF9C1BC189D45D86FBDB30E74E1D8F
+:105E8000DA1FEF13F35B8C3E7394FBC57909703214
+:105E9000A03DE70BF4A0939D8BDBB5BEFCE5F3675B
+:105EA000F07CFFCB73162B82B33C939FD72CDD9BEA
+:105EB000339DEBA12A7D60D2F31F87225F97E5D93E
+:105EC00025FBB45C7E7570BF03E4497E0D944B8F57
+:105ED000BDF061E855F5807DDC8E712D3D408EABC7
+:105EE0005BF26B2ECFCAFBB144BA4CFAF392575611
+:105EF000455D2D5E0DF54FE407817AC1B5F486400E
+:105F00007DE19954B5BE70BDF17172BEB43623E91E
+:105F1000D351182FE7DE83745B5E9B9384F1E4D545
+:105F2000B5132995E3E74A6B4750BBF2DA5154FEAB
+:105F3000869083988E51DC658DD08F7BBDC903D848
+:105F4000BF187FC94698247CDFABB30D40BB821CD1
+:105F500027CD743D24BF55FC26291CF1ABACE331A1
+:105F60008306CAFF9ECAE5B30B01FA4DF5AE4FC8D2
+:105F7000EE50C53A695F60BF9849A9E76E34D038E2
+:105F8000FDCDAFE279CB52C4DBB276C9B903FAA931
+:105F900030DA1E45F9A5E28DE97A8F621FFF8C7811
+:105FA0001B79E5FCDF4CB5A9CA71BE8CFA69FF0A02
+:105FB000E3CCD8AF42483EBBD8C1EDAF9FEFD26E25
+:105FC0004379ACAC7D4F35D949768558D114F2A5CB
+:105FD0009ECB8B723F9F083AF9245523E8AE9DDA99
+:105FE0009FDB15C21EB6F3F9221FF85252DF1F388D
+:105FF0002BBE3B2BE0E5117426B72F33B71850BFEB
+:10600000B9F0F2F48887705E07FF183A14CA2F8936
+:10601000F55DDC175248F0D8F7F72987503FDB973A
+:106020001F2129F80B4BD3F3F978B91FE64207B7C4
+:106030005F54219C012FCE09BBC3B91706B6F1737B
+:10604000DAAB8A073BB7EFC5504D7ADF3E2E31B54C
+:1060500034E112E57B36417A8F07E5465DC7540F80
+:10606000F276A26B18676D5A8B0BF995DCCE6472D1
+:1060700052BC8E7C1F99C9F18422FE05E487B7DCEF
+:1060800030FF9A320343F9615EA66DD65D780EBE8D
+:10609000A1A7FD60836D1BD08F32EFED810CF9520B
+:1060A0008DDD41F6A279A3387FE9B6F3B8F79EFB00
+:1060B0002D64CFAE6C929813FD6631F13CCEC6AF25
+:1060C0008F39DE5E83768BDF27917DBCD2AB656E28
+:1060D0006C37D6973255615F8E077CC1EF87A7F189
+:1060E000FD3C85F764CC785E1E4911710C128E233D
+:1060F000B73F2FF952283E638F3A3EA0729A2F0580
+:10610000EDFA957B63C9AE7F5EDCB7C1729C7F659B
+:10611000368F03F0B77FE0480AE263E5FCF6342BE4
+:10612000ADCBFA15E915FB2D742F51F39245F8E329
+:1061300082B6E2794CBE43C8978546519C775E1A79
+:10614000D7579EF6D3A72306F9EEA095E650659C97
+:10615000C320A985C733EC50C7399C32F072CF4EAB
+:10616000F53ACEEBA11CCFA71DEA3887F386161EA1
+:10617000E7B0535D5E16DA42EBEAC6380F84D77398
+:10618000DCAFC6CC9D07B0FFF2E783882ECAEB6A6E
+:10619000A7A07EFB65AC77D14128FFF2B9610CE581
+:1061A00056D84F9253CA3C12F1FF7260131827075A
+:1061B0006921C6BB95FF72433CD9635772B9F68417
+:1061C000E509D23F7AB71B25E4E767236D03307FEB
+:1061D000F6B70319C2FDACD4128FF32907490FE5B6
+:1061E00013376B994776E5ED46867EFDF2ED468ADC
+:1061F0004B38BBE3BB614A3B3694ABFCB5F2BCFC0D
+:10620000E7771AA7DBF9024F16A571FDB962D81F0F
+:106210000E20BE77DBF9FEC0FE919EB6694F10E5F9
+:106220002B76476E45BA296F0FEAD6921CA651E924
+:106230007B65C000D14E56C6B83CF3E52E3DC55730
+:106240000025115FAC147CB1403B81EEDB5F6A1F1F
+:106250003500E151AEC9FA31AEBBFCF7C974370065
+:10626000E04FF3C53FD4D7CEEE8CA377178AC2D9BF
+:106270003DD3101EB57FA7788AB3E12D19E157D120
+:10628000ABCA5FB2501C6BF99A1B34644FD7727D56
+:106290001052A7C4EF17E7A03C51B52664A9D2AFAE
+:1062A000526E3E43F11E81F0DB9BC6F9569588FB8A
+:1062B000AAD8C9DFC3A8047AC3B8E88AD5DC2ECE31
+:1062C0007E29D1BDC9E541BED0F1905FBE434BFEF2
+:1062D000800A437B4A24CCFBA934CE37A1BD1BC71F
+:1062E000F57F6F706CA07E7F3F93F6FDA9B4081A0E
+:1062F000EF7CFB6351B8AF81ED9707011F312BDBBA
+:106300006D0B55EEBFDCCEBFAE766EAFB9C43A7F33
+:10631000F2217CF2CDAE209A17F07B8AAB0B5C2F7A
+:10632000CC97F0B2E20523C5959D13F7C33EAFE3CA
+:10633000BCBE62F56D8FD27AFF309DE257177BD5D8
+:10634000DF5FB275E6A01DE1D2BEDB75F8FDD63485
+:106350007EEFAF6ACD78DA67F6B69EBE0BDCB75536
+:10636000A29D9FFE7687F07817D6FE02F6776E77AD
+:106370008806E9AF3B8CE3C7B95C98279E03BBA3B3
+:10638000B3E94E090A538067E5568E67E7C2DAE340
+:10639000AD549F9AA5C22B1FB4447CC46F30AEA3EA
+:1063A00096CB6F15A666B2EB633C484E36A53EE32E
+:1063B00055E246100FD14E10334CF8DF703C8C2361
+:1063C000C1FEE83C6A37A0FFD12DE4CECA5D8171E1
+:1063D0001FBCFECF6992EC5FB045C87128405215D2
+:1063E0001E89FC03158DCBCA90CF542C5D7F17E21C
+:1063F000A53CFF0A1D2B447ED02D69691EDD41405E
+:106400001728AF2AC749E4A935AA6F9DDD62BCCF22
+:10641000D26C346F908B590BF453D9283553FF82CB
+:106420004F50FC91E23B008301CF99EE5C511FB0CD
+:10643000DE6E112FD9B35B6A539E2F81EB1E348C15
+:10644000F3F96EBBEDD109117D7177907FFBE6D139
+:1064500094A77B6B0DB87937D267840767E7F07331
+:1064600002CEF92C841B6A48FE780C2DBD1BA38B31
+:10647000CDE6FA19C6B7A37E8629EA673623D7CFB9
+:10648000308FFA19A6A89F6139EA679847FD0CF387
+:10649000A89F611EF5334C513FC3F271C3389F7CF6
+:1064A000997947E860BC3352E7EA5889FCD2DCFFAF
+:1064B0007CD64CFCCFEF9F3EAB51FBA7CF6A02FDD1
+:1064C000D3214AFFF4B5E2B01222DDA9C322699FAD
+:1064D00055FDBD9CE81D81FAEE1B6956B19FEDA4E8
+:1064E000FFA76C36A8E09EB65D9D1FBE4B9D4FDF9B
+:1064F000A7CE6774A8F38E63EAFC5748EB385E7644
+:106500009019E379BA567DBE1AD5A96F22DCE9C38A
+:10651000283EBB67278FBBF6117FE9AA87FDE5FB05
+:10652000CDED6ED01BE2AF1CCF7BCDF774AEF98EF4
+:106530008E1A1FE478A42DFA9E58E4939F3C676A54
+:10654000C6797E22ECA56CB689E4AB1AFF79C4F556
+:10655000AA9A75D2563C876F1D164EDFF79E48A645
+:10656000F3A93FFD62C1E551249FFBF3CD9286E282
+:10657000A463A2E8BC93E5B77809E437E47BB07E76
+:10658000940B53376A54F31FE60D56C177C4B3E139
+:10659000AAFCC8F641AAF699071355F559BEE1EAD7
+:1065A00078AE19F587F97D08310F21AF4E6F1EA522
+:1065B000FAAEC4355EF5DDF29526C2AFE5EF69C9E6
+:1065C000AE5A8A15183F827225ACB314BF457FEED0
+:1065D000761E47C26AD5E77AA98E79AC30F505E216
+:1065E000FC91E3C04BADCC1906FD5CC86AD989EFBC
+:1065F000CA94FDF68F39568CE79372A3D17EF17C55
+:10660000B2FB5EC49B78BD730AF96BF62487D5A3F1
+:10661000DC79E238F9A5653C89D75B83713FDB5AA9
+:10662000B83E80761C6D78DF7EB7B50C0C1E6AEE26
+:106630005B77DFFEA693FC7CE98416D501569A2B86
+:10664000790C997DF3AF11E7853CDF4F85DEC0867D
+:10665000F27EEE15F595D9AF3F1D0E5B775E73E4C4
+:106660002F6B607EE7B2DA537C90966F6A8BBA1319
+:10667000F509A37B1DAEA3E6ADFC50F4277EBB4B12
+:106680004FF7AA3E6BDDF634C679AC69D96640BBDC
+:1066900041B9CE6B203FF7736D068CF3F8D1B36D23
+:1066A00054BEE8D962D233BFD02F35907CFA94C45F
+:1066B000F6DBFBD65F9A276DB6C2BC2F0A3E5A1A8C
+:1066C000CCDCED64679E703C02CFDB67258A77984F
+:1066D0003923571F89F2FBAE30BACFF98C681F8877
+:1066E000F7BD6F6AB95D6C06DFEFFEEE994EBF6CC9
+:1066F000273C9F717904E95F337DC3B8BE9BAED65A
+:10670000774B0DB6B791AFB3DF69493EF5DB1D1C82
+:106710007A9287319E11E3275D13B42ABC5B32293C
+:10672000448597B359B82AFEF20E3648959F519486
+:10673000A46A3F6BC688007E90DD574FFC609C2AA0
+:106740000E130650D14515B6A0B8BC3C553B2CE7FE
+:10675000F19DB7AAFA5BFED6A8681EAF38ADAF3D73
+:10676000CABFDBB97FA36A5FD856D4BF4BC5FDFC57
+:10677000D96E5E5E7D90973316ECBFDF3040CBED77
+:1067800009CAFB194CF8ED707C846B95B03355A5A4
+:1067900071FB52427EA7C144F2B944F762AB5B245D
+:1067A0008233C05737309CE75764D3F7A681D97D31
+:1067B0007852BD4F7D7F12FB47BF72F5096D31D214
+:1067C00043603D9C53AB07E1BC8BA42CD43B176FBB
+:1067D0000CF44B37935FB01AED468AFDC9447F0B2A
+:1067E000E29BF0E7CCC60AD8B2CAF63DAF617F3370
+:1067F0005D1C2F03F147D60B1631C023F42B01BDCE
+:106800007A6DFDC303EF76A1BE21C3A5DAC9F12DD0
+:1068100010BF0621FE613C2C03B841BF8BF7490E27
+:106820007C670ADB239C0621FE05C085E018000F6B
+:10683000194E32DCD858F5FCAF841F5F077CC7AE19
+:1068400006BFC075F5074F79BDD32E73FB87BCDE3D
+:10685000456E8E078B603DE817BD03DF731985F821
+:10686000C1F9470FF08FBDB84E1787D38C22359DE5
+:10687000F9F1C5C5F15CC6979997A3A89F7F1F5FE3
+:10688000BAC84E7BBD7822DBF565BE8BF6C462F2DA
+:10689000473F74D5773B02ED91370E17F6C8316C40
+:1068A0008C2A1EA49F7B4281F120F2391D784E1460
+:1068B000FF969F13FE7344F0FF9A956944F7321FC9
+:1068C000758B72B7B0D3C9E31443DEA6C8AF6E4C64
+:1068D0008AEF52C811EE55FA28EC27BE7E20A5C5D6
+:1068E00041568A7B2AAEE7F128A7D746478D85FD1A
+:1068F0003BBD8AC7A39CBE7F743CC6959C5E554039
+:10690000E927EB8DB3E95DA1074D0CE3C1AB0E4464
+:10691000F3FBD95A73D46CB4BBED1D48F72B170E9B
+:10692000E7726BE5AAFDA1184655B18A9FBB3F4EA1
+:1069300076170F27FB7BDB4E32785BDB3290EF2B39
+:10694000ECB3CBB1BE0AEDB39077D727539CDC17DD
+:106950003846369E4FFC9CFF22C87A078EF7C573D7
+:106960007ABA270BF54EF493DC2BF9CEDC4CF7E822
+:10697000A428B43B9D7F4F4BF6AF32EDE10C1CAF2A
+:10698000B2EE603C9A0E4AB3E1FC043C986484F990
+:10699000A0FD61D5B678722636B5D1BB8681F6608A
+:1069A000197E1F0A3FFA4E714EA3BC8F29CAFB2CD9
+:1069B00095CBFB9847791F5394F7B17CC946B5BC7A
+:1069C00026DB8313B45F67D5A4F7F98598B5EB1878
+:1069D000F9851F33DA50EF18AC13EF99097F91EC6A
+:1069E0009F91FD46C58F2D66F8E24D711C7348BC22
+:1069F0003DF99102FD47C5785710DB3DA2A3F7F1A1
+:106A0000E82F87FB5771DDB2DF09BF0FCD56F86164
+:106A100085FF47CFACF1783F3121DFFA9393DC8FCC
+:106A20004DFA53511ED747E5757508FFBF9CA6A0C8
+:106A3000FD18FD3B1A470CF2E1298DC3C87EECC955
+:106A400063694B497E30A7619CF27229D881F2EFCD
+:106A500072DC67CC7F1CC4FDA0DE58151D04BE5F30
+:106A600073530FC8880ABABCF9B2899528E83F97D2
+:106A700085A9F2F9A65855FB02AB5D55FFA39861B5
+:106A8000AAFA5B6C59AAFC6D6937AADADFEEC85521
+:106A9000E57F3CF61655FBA9CEA9AAFCF4C239AA9B
+:106AA000F6335DC5AAFA59B3CB54F573DCCB54F970
+:106AB000BB4AEF57B5BF7B69BDAAFEA7A08F229C3A
+:106AC0003B501F35E23D4E13A5DF69AC3A46F24319
+:106AD000B219E96942BE66E9D5E23EDE15747B79FA
+:106AE00084736DFA187EAF16E96E88FCCE1E03A97A
+:106AF00093F4F2CE58A4930921472ED9606FC63D76
+:106B0000DF3853077C6FC20D474625417EF9F38776
+:106B100066EA80AF4E187FE4C544C8FF6CC4B73C3A
+:106B20009F79E412D69F7BDEC7DB4F672422AD1925
+:106B3000B16CA607E7757362B383DB69C4FD211FDF
+:106B4000E1A93FEED064F62529E27B707D25C97866
+:106B5000FFCD4AE911A03F4C8F01FD9500BF7D0D8F
+:106B6000E80FD313A06F63F9EF40DFC6F44DD0B741
+:106B700031FD3DE8DB987682BE8DE91FEA6653FA67
+:106B80006E9D9BBEFB535D29A527EB9652F90775B9
+:106B9000B5947E54E7A1728433E6BF1F2EEC310713
+:106BA000F5E795EFE7C8FE70D9FFCD5E7598309E8A
+:106BB0008075E9C2CE98FAFCDAFDE979681039A34C
+:106BC000900BA399D33882FC2583AD74FE88F2E440
+:106BD00044B77904D0DB7BF6E9C9A3203FEB7BF710
+:106BE0002A24F9F734DC0E1FD8EF69B1CF9D239C1E
+:106BF00061D89FFF7D46C18736EB39DF91F90CFDE7
+:106C000029F885CC576E32F17B350A7E43FC42C1B0
+:106C100087888F147CC388AE2736E9C87F68D13156
+:106C20001FFA97657E0300C9C77B63FACB8CECDC47
+:106C3000F89EA2219BDA39B5906EFF2BB4CF50F0AD
+:106C40003F23F3D07B8E822F423B1ABFE01B37F1EC
+:106C5000C389C2FF3EC400072E6F47710116D4DB03
+:106C6000F0FB815D4771BCB8BF830C00ED405CA1B7
+:106C7000F814990F62FB10DEDE87FD0EFD1B8C1FE2
+:106C80008A70B3F177E3723BED681FDA7C9FC981AC
+:106C9000F63DF95D4A327A019CA60B7E45411C986F
+:106CA00017E73C7B369AEC5779A27E73A23B1FF71D
+:106CB000CD65B47E1C4274953404E598A9427EFFEC
+:106CC00017FB56F87F61DF2662C708EF0846FCFA1B
+:106CD000FFEABE8DD6F1770D8C95268AB7BAD63EDF
+:106CE000DED3C3260F80267727B94FA37C507CD9EB
+:106CF000F61AE64B745906DC3AB97E11D68FB9B252
+:106D0000DEFD4D8F7E8062BF6F123C7A4D3FEDE518
+:106D100076F27BC772FFDBFB197F79018FDF2D7C59
+:106D20008FDBF9DFF0BF07E03467C17EE733DE4F6A
+:106D30007EFA6292DF9999CBC536F807F9D2CD97E2
+:106D4000752A39B99089B81DE6D521FE1506F8E3F4
+:106D50006F1572F4AD017274A05CBC79848893B62F
+:106D600033FBBFF98ECD56C46759EEC23838C4DF45
+:106D7000249BD63421BBEFDD1AF9FDA349827E0A9C
+:106D8000989BCEB51F310FA5B7C0FC313D86EF1FD4
+:106D900065607CA78FCEC3DB81E162F98F5194815E
+:106DA000FCD190297331863A7F54FE502C57BCCBCE
+:106DB000B01FE751AD75FFB755F12EC3914936F2BB
+:106DC0009F1E31F17B1B485FFAF0BE751C85736016
+:106DD000289C03C7E13C1A0AEB791DCE23CCFF1691
+:106DE000CE234CE576936DEA38B25BD3F87B8BB754
+:106DF00059F34121EA1F4EB765FC7A30C2F18DB0DC
+:106E0000D44968977F23EC8649B8BE37C2A2353C87
+:106E1000351AFED53D6019DF6F4BE7F7076EB34EAD
+:106E2000A6F1AA4242C5FB2D1F87C6005EF49A8ECA
+:106E30006668213D8B1344BD28C00EF5791D4BC7F4
+:106E4000F54DAC1D4FDFDF5C7B23A595263E7FB65D
+:106E50003D5AA38CE7DD667077217FFB7CB396F00B
+:106E6000F5C2DE204711F4F385F7C5505C0FC8FB6F
+:106E70009F22BC2BB5B66607DA6FDEE071ADECFB86
+:106E8000A3F1182FE37FD768FB74553CB88C0F959E
+:106E900026BE0E59AFFA499293E88B89F758E4B8A9
+:106EA00099C1467E1F4D7E1F04E5088A030F38AF47
+:106EB0007382393F196CE47CD4CF270C3CCFDC2F94
+:106EC000D2FB6BDBAACD0E3CA786C538FF8AF397B1
+:106ED000EDB8BD8343E89EE844DF08F2A716A21D83
+:106EE00001A67A44C4D9FD68C4527322E0D51D2995
+:106EF0006E6D3ADD43F85E8B7CE9CD64890D94D0EC
+:106F0000EE3BCA4C7AE435E82690EE42D205DD65C8
+:106F1000B08C1FF83B5814D7D3FBAED6C1F5491E31
+:106F20003F20CBD11359CA06B40FE49FD06304436A
+:106F30005F9C5A0CF72FCA74597082C713196334B7
+:106F4000CCA6E01741B66066538E9F16AECA5B1C96
+:106F50008354ED078C4D54D5873987ABEA07166605
+:106F6000ABF291AE71AAF6D1B3F354F958F7ADAACA
+:106F7000F671A5D354F9214BEF54B54FA89DAFAA94
+:106F8000B77BCA55F5A0D1D03E1CB74A6C935DF1D2
+:106F9000BE8AC7D99916C5F923FE2535D5A8BE2BBB
+:106FA000342FA2F7C5925B1E50F5CF6CDC3EE18119
+:106FB0007F10AFBEC58B099016C4A8ED16F9D6DCBC
+:106FC00063B82571220E8A31870DF96FBE556DC7E2
+:106FD000883317525C7BDC35E2A48AFE5D3C700F7F
+:106FE000BF3A1E54F2F33C100FD07FA05C27FA0F7B
+:106FF00094F040FF81328FFE03657BF41F28EBD1B4
+:107000007FA0AC1F75428D07633AD57870C34935B0
+:107010001E1C47FE9FD4FF7EDDD8A5C61379BFC6D0
+:107020007F31EDAAFB351BFEA1F391F1F37512C080
+:10703000CDC7AEDC3779BFE4FDFB9FEE5B43C0BE3E
+:107040007DCB9AC764D1FB86702E69FB3F370B4D11
+:1070500057D7D364BE15A8AF05EACF72FCEF95EF02
+:10706000BE7659F05CFC4ED33512BF8F653DC7F13B
+:107070001EF24B51EE2771BC688C1680FA4D657775
+:10708000D0BBD51787F49CC277BB3DF75B38FF4E6A
+:10709000E7FDCD6BE0EF48C8F39E17C7E38FB6A6B8
+:1070A0000BFFB3A36B0CFA2377A473B9D6E2B052EB
+:1070B0005C7B713A13F1BB2C7EDE48057F5DA1231A
+:1070C000FE3ACFE4FE653ADE4F10EF88CB71EED783
+:1070D000F1EEECAFF03BFFBB1765EA774436F9DF22
+:1070E00011F105A562FDE31AD5FB2C9B2A6DFEF775
+:1070F00059C8CEB992BFE39ABA91A9CE75FFBB2207
+:10710000CB6C743F6D98D7A48A0FC7F766D0AF3D9C
+:10711000E259ABAA7C647B8CAA9F4DE25D9CCC8338
+:107120003655BB4DE2FD912C5F9AAAFDA8130EF5D2
+:10713000F7E25D92319D6355DF77C9EFD994F1F79E
+:1071400035500F40B9FE86934E55BB848A9A292844
+:10715000570C11F2F58D5D85AAFE132E066B304E8D
+:10716000FBAB741E4F3EFE0B97AA9E741EC4839FFA
+:1071700046111EC87A8A426F213DC5C0F87BE006E1
+:10718000D03310FFE478E8403B96DF4E65EAB38BDE
+:1071900029E394653DC31FAFAC736A107FE5786542
+:1071A0003F1EE0FBEF3CDE80E0F0F40351AAF7491C
+:1071B000BE15F8F8550AE3F7F24DDCCE85F153F829
+:1071C0004E31D375C5E2BB43DFA77339E497439DC6
+:1071D0007F4BA7F6DC1FFEB4A1E77D3C47E765F2D5
+:1071E00071E66A34F74C4DE7F1647B157A9D7124A2
+:1071F000FFFEAD0C9ECE1B20EEA7FF8CDF7397D752
+:107200001163608DF47E83AE6B18E2F7DDCDEDEB9C
+:10721000D0B436D7D0A2E771D85E3DD277511EC820
+:10722000B9598CD5FF32E171732CBE8FAE23FB4A66
+:10723000E8EECD778084ECBFBF9300FF8DFB8036F6
+:107240005ED4ABDC19DAABDABDE57B29B6657AD75B
+:107250005633DD6F2944FD4DAE5F9EC1E1E41DAAAA
+:1072600021BFA8FCFB017EFBF3485E3F55ACB34059
+:10727000FB7D31AE6FA1C540F7A0263A5D4FA0DD82
+:107280007B7EAB9EB5A18DC703FA4B14C5AFD05F13
+:10729000B18DEB256EC1B7318F7E93628F9ACF2E61
+:1072A000C6DFEF90886F135D2F301BBCF8D6E682E7
+:1072B0002675BB858CF7B7D8CCDFEF5C18785F51AB
+:1072C000E8398BAFA1E7FC74A4E0D7992CF307C58C
+:1072D000BBA3BDA0078BB87FFE6E52AD81CE511906
+:1072E000EF15784DFAF57F2AAE9F89737EA880A3AB
+:1072F0004C67323EC9F423E313EE2FEE9FBCBF78F8
+:107300007FA8DBDCB7BFFF5BF788FC70BB861DBCCA
+:107310003FBB77205FA13F853DA43F7BB7CC67FC97
+:107320007C8401FF48EA8397ECBF2F153812286749
+:10733000F57A9328FE1AEF3169F93C299E4B3EB746
+:107340006DE8B751F815807E82F17D7B4FA38EEEFC
+:10735000ED07C257A69FFEE20BCE637C01F25AD91D
+:107360003F24EACF7B2E7553FDBE207AB7ED4256FF
+:107370006706FA3D64BF51A01FAA77858961DC5A70
+:10738000EF3E0BF9E5D14F3300DF27AADF9681FEF0
+:107390001B793EEE2EB5DF2930FD71B27BCBC831B3
+:1073A000E8BFD1DF417172668D15FDCF6BCD47E827
+:1073B000DE3DE8FBDE91917DFA5D119C73B86FC0F4
+:1073C000970A71BF653F4BE07AFC743681DF43E872
+:1073D000F5F0B8F3DE4289E6FB1E7391BC522459E6
+:1073E00049CF57E2E7BFE3AF997E398BF667C6E531
+:1073F000F1B44E77D38D944F49F068303E99DD2536
+:10740000917D7AD676B62AD8867146B3C6A0BEF6E6
+:10741000E6482ED7A488F325102EC9829E766A24CA
+:10742000F23FEE7C88C7CF8DD8E5D4E0BB38B3F708
+:1074300059C53BD84BB3513EB82BA07D8A8E9DD009
+:10744000670B3C86F6CFDC60DF4A71CC197CDCFA36
+:10745000E15681275D3A97426EAAA997882FD548B1
+:107460004C8E3722BE24E72FB5887C01CF2F5FC515
+:10747000F35DE2BDCB9DC2BE81F0C314E18776808F
+:107480005DC2BE81F0C314E187E548DF9847FAC6C4
+:107490003CD237E691BE3145FAC6F2F9CC158F0ED3
+:1074A00043F4E34C52F069F4E34C52F05BF4E3280C
+:1074B000F3E8C751B6473F8EB21EFD38CA7AF4E3EF
+:1074C00028F3E8C751B6473F8E32CFC6DED2974782
+:1074D000BFA073AA2A3F1DF484498AF301FD38CA6C
+:1074E000FED18FA3EACFBD4CF5FD5DAC56F57DD244
+:1074F000D27A55FB7B6A25959FA784F5103E2FD83D
+:107500003890F07075A22B2803F6FB9E593DF4EEDF
+:107510006881B6A30CF1A1A62AD8C1F7B9A590EF4E
+:10752000BB86E268B7E86DD1F44EDE5B5AC6F799C8
+:10753000C7F106E227FA3326E9B95F0553F4AB60D9
+:107540008A7E154CD1AF82EF0CA25F0553F4AB607D
+:1075500039FA553045BF0AA6E857C114FD2A98A24A
+:107560005F0553F4ABE077E857C114FD2A588E7ECF
+:10757000154CD1AF82E5A7D0AF02F9128CB9847552
+:107580008E6CF11C479BD494CDA78E619A32A07863
+:10759000AF04A83EEA85C859E8474A0929CE0E73C8
+:1075A000009F96E2664D82BC5BC4C765B01E92FF29
+:1075B000C85F0EEB77FB18C9EB23FF1A4BF57DF480
+:1075C000C2E969E4312BC9A9F5427F92BFCF425786
+:1075D0004D525FFBBEFCD5DB058E2FB7233EA69830
+:1075E000877C2F39E1751B9D4F400774CF4CFEFD02
+:1075F0001BB72797DEE52D3270B90AF8C238D49749
+:10760000467824E756C5FE1509F971C42E668841EF
+:10761000BEB065DE68FA2ED8FFDDDFCE627CC158D1
+:107620003BBD6B38611773B6C1F73333B89F7642F1
+:107630004FFB11E46BC58D53E93BB9DFE2CDF1742B
+:10764000DFB2982D7D007FA7858D9628BE0AF8D0E1
+:1076500031E443F2BAE4F6202E9F40BBE8F5DE6B3E
+:10766000B969745801C68FB10E46EFE8DC3EFA1DC9
+:10767000D5BA695B72A85FE2FFA91E89DE679BE24B
+:10768000A97F08D5C7DB3DCB8E63BC997B3B73D804
+:107690006DC4BA29FE5F9EDF70E71E0D1C1FA08E11
+:1076A000766AF037844055393A50B1BF80E1337083
+:1076B0003FB21C7AF23B4DD559F5748F3FE05C0C1C
+:1076C0008CC7088CEBAB5979B91BE32C6BF6F373C1
+:1076D00056960F8A459CD7A5463DC54B14EF37D229
+:1076E000BB67EE8D12D1B11CAF7141F366D42CF89B
+:1076F000AE2AC91BAFC1B8F0416D19E15A3A47D75C
+:1077000064C03CCF37F2388AEEC617E99EDDA5C6C5
+:1077100099F46EBD6CEF2F11F02911F13A15CCFAE6
+:10772000278C7794DF7597E39B580B9787653B47CA
+:10773000F15B3C0E24504E2E6BD4539C4D59807CF3
+:107740005C21E4E38A6BC8C74F6588F8180773FCAF
+:107750009B7E806D190AB980C9EFFE8AF7EC8BDF3A
+:107760003A3A93CEFBA5C91A3CEF6539616E3D9755
+:1077700003D81E46BFDB33B73E9FCED3B9FB9DF483
+:107780006EC2DBE2FC9F76398EE0FE4771DECFC42D
+:10779000B842807F51571095DF713996D259977949
+:1077A0009C21DEF940FCE8FA35A3B8895E8F91CBC5
+:1077B0001F1D4CC42DAAF1338B590B10DF873BA53D
+:1077C000A3285EDD8EF203F4371BE5898188EFC5BF
+:1077D000AB2211DFBD8CE4BC407C2FD22F3D8EF557
+:1077E000453B18F975647C777BEC05B8BE2985129A
+:1077F000439631DBFD8E0EE91CF88015BF730BBD7F
+:107800004EC6EB403A981722F45D33B7B7F8F560EF
+:107810009C243E92E8593E0BE5B27968431BC411A3
+:107820000BE3B52CE9BCFEEC0BCB67350EFDDFBFDF
+:10783000D72FDFE7EFD3B3B95E8FFAB58BE2493EBE
+:107840002A8826F9262C5B69EF3C2DE87683232FC6
+:107850002313BEAB599B1CFDAFEE6F2E807D43BA48
+:107860009C37A0EB3EFC85025D26734E1A8BBF9FB2
+:10787000C1E447257D18B777A7C86B331FFB735347
+:107880003AC199D7673E380BE319D6AEF87900FFB5
+:10789000733971BF42D29DE4F7E94F8F7F2FCA79C8
+:1078A0004326B45F902EFFCE288FBF3FBDF6F3E78F
+:1078B00095760AD9CEC5580FC9F94F4C8BC912EF2E
+:1078C000AF103D6C2A1F4C760D7BA6C61FB7F49FE8
+:1078D000B8A7B0D2E68ACB247EDA6222FD28ADE7D3
+:1078E000C91D30FEBC3AFEAE9EAC476D290FA67591
+:1078F0006C79C0407C50D6A7E61A3A8FD3EF346536
+:10790000F2761FD6FE5C8FE704EC2BAD636E397FF9
+:107910004F7383C39586E384A43BE89D0B77BA57E6
+:10792000C2DFBF1C64E5F85F94D893A521BB9C79A6
+:107930008CEA7709B5EC18DA45E726CAF7BBF8BD3B
+:1079400075996FCAEDFE92C9F9C95FC53CEE6C919D
+:10795000EFB3B7AD8A423B455316FDD4DF06877BB4
+:107960001CCE634187FD35FC7D89EA83FC5DF3799C
+:10797000D1E2FE36EB8957BEDF3745F4FB1D466585
+:10798000D33D05711F40DC379F1361A57D033C6F1C
+:10799000443D718AD82FD9BED5A7F7EAC8AE60A8F2
+:1079A00035D0BB8EA8AF1AB215F630C6F55F19DE1A
+:1079B000B21EDB07672B7F77C562B0217C8ACD2999
+:1079C00093915E8A5BA470E49305DAA2D7488E5C3B
+:1079D0006F4F4439D29329A9E2B7178AF3B0E6F181
+:1079E0002403FE9E42CD5A90C2906F85DBA89F9ED5
+:1079F0007592752BE2B3B047CBEB2FD97823D153D7
+:107A00008917D2ABBC3724A71FAD3F147923E2AF4F
+:107A1000CF49F19C2556602B0ABBC302B11F81F9E7
+:107A2000A599DC7E3517C45784D7DDF7DA0DF3D17D
+:107A3000EE06E208C6D779326DAA7BCCD08EE2186A
+:107A400014EFD058D10E8CE3652BFA9F1FF0BB7B4F
+:107A500045895C9E7A20D342FDCD6F0933E0BBC0DF
+:107A6000C5562BCDF30A3808F82FF079F50E9C0F88
+:107A7000C64F40FE4EAB579F4D78689B8C7CBCA494
+:107A800099BFABEB6EE6E3B99BC20C23B17DB07539
+:107A900032D9A95749169C5F51B8D340EFC8ACB74B
+:107AA000AB7E672B104EC562DE2530BF85AAF2F58E
+:107AB0007AA49739E2BC98DF984BF7CF4B747CDD02
+:107AC000CF093C750BB87EB62CE861B4AFCF0D6F13
+:107AD00029B81FE970515818C65BFE2293CB8DCF91
+:107AE000093A91E132C7DA42EBF2C3F571800374CF
+:107AF000B9D0EAA2FEE78ADF6D2D691574D55A6CFC
+:107B00004837E33BB96EC3601ADF42FDCDD9C8E701
+:107B1000D9373E7F1F68EE267EFFE3CCE3B3E269F0
+:107B20001DAD1BF48CD6F10EC3DF014738223ECACF
+:107B30007821DF77F6EB379966EABF43CCDF6F3FFA
+:107B40000E7897A3A4B998DEF15810C3E85D29997F
+:107B5000BE647A93E92CD04E3447D889F4CDDD65E4
+:107B6000C8BF647E00E7EAD2BD57396F32049DDF9B
+:107B700029F603E0437C4AAEFF4CD09FCCB7FCE72C
+:107B8000F600DEEF3B62BFE6E6F992F1BD27B9BD34
+:107B90003CEEDC70FE1DEE0FCA32EF88F1B07D0DB9
+:107BA000B557DFCF58E0B7B3EC5A1585E7E81E8923
+:107BB000EC5935EB8E0EF929D2FBEE10BA5772AEA6
+:107BC000724735FEFE16D379E395EF8C2E04390704
+:107BD000E97C91383F4B7C57A7F715A9EED3990A5A
+:107BE000BDA1E4B1DD29C83F61FD3EE41B1FED3EB0
+:107BF000F4DE385BDF7928AF677E531BF1CBBB9B8C
+:107C0000C3B2B59C5F3621BFCC107058D0C8F78D79
+:107C1000C1BEA11C28EF6F7123BF0FB7A036C78B61
+:107C20007628BF5C11C03F03F753DE67793FE7F862
+:107C3000CF83F505CAF3C00FBF3EFD807ED7B2B734
+:107C40009DC3AFB759CFED54BBB85DED5CCD4BBF15
+:107C5000BF03DAFD3FB9CDAD4D008000000000004C
+:107C60001F8B080000000000000BDD587B5054E71C
+:107C7000153FF7DEDDBBBBB00BBB2B2C6F585E4A4C
+:107C8000CC02775725B576F4C6A871328E5D4CAB21
+:107C90009028AC550C2A20A4B681D6294B375182A6
+:107CA000934A27181FAD66A1EAB41D93AE91A94E61
+:107CB0004A3A9BD04C92D68E56675A47A7642D1DE0
+:107CC0005F6D6475A6553B69EC39DF772F8B284DC6
+:107CD000FEEA1F65068EDFE3BC7FE77CE77A5D087E
+:107CE000B7644900F7E8670140C31D2FC02C800D21
+:107CF00077E631FA5C742EC0B4C4B94EB7CD08240F
+:107D000029E989F573AFBF313DE001585D14B9F140
+:107D1000761A40BCCDA40C00C03AFCFD920FE06F77
+:107D2000475F35E6E0FEB30D8203D541BA52887F46
+:107D3000009E89F41B8BAC78AFD56B8714DA770380
+:107D4000CCC17D003582FBAB45F80D3813EB5AA44E
+:107D5000C750CFD6364B0A54129FC369AF0098AFB5
+:107D6000888C6F5911D4FB3D09BB46DBD6FE00F071
+:107D70007CD402F52B90BF09F9DF223B455FBE6141
+:107D800036DAF98AC93720A04169916380EBBA2DB0
+:107D90001E5F4F21D3FBA18076CF560426B7A424C3
+:107DA0001626FB720C0016DC9745089A910E88DCAB
+:107DB000BF2289D31F25451E69B53E182F9D9634D5
+:107DC000C56E923D2500419243D486FEAD26BFD3B9
+:107DD000D91A5C7C3F4A34CF0041D1C7F4064DDA52
+:107DE000DA82F77BCABE012ADA6BCC0445427B7388
+:107DF000CD680FEEE7A07FB22F212F0FE549B82FF6
+:107E0000E3BE487A44B1DE8FF6E524477E06988FBC
+:107E10009C2D337D2174514E826EF2A77A0A7FA782
+:107E2000B25BB777B490C77D3C1E26A4CE841FBA40
+:107E30003D508676A0DEBAEF96F7F7A0AAD12E25A0
+:107E40009FE235959FA3850150094F59A00C3CC472
+:107E5000CFC9FE4159EF6217C9CF702B3DA8126AF6
+:107E6000CC22B800D69B81FD2C963CA931B4F356A8
+:107E70006F712AA0DE51018240F6B759448613CDB6
+:107E80008F239D78197DF869A799D19F77DA0166CC
+:107E9000001CEDCC64EB373BDD8C463ACBD87E87BB
+:107EA000E2E4FE41CCB6C286FE26018B3344095B78
+:107EB0000023EDC5CC5F7D7F9993E371B5336613E5
+:107EC00008871D924838FC6BABA5075209A7311BE8
+:107ED000D50BB417C3615435FA78CC3657BFE74E8B
+:107EE000E069C41EB339A91E8C5C0FD8E4F061941C
+:107EF000B3666BB5BC16F7D7B49F330A485FA4BC12
+:107F0000A27D05C5113583E26993ED2427645332C0
+:107F1000C99E9043C9744EA89B64EB4AD94DF12980
+:107F20008C96D8E9BED7C2E23F625DB9248BFCD9FA
+:107F3000EB2089B0555046DAD12E78C9A41C46B240
+:107F40004C846E81E1212AE790BD5D02EB03FABE0D
+:107F5000B12CF0AA82F82A908EFDF302C97D29592E
+:107F6000213BE053D45B053093844AACFE54AAFB1A
+:107F70001BD3793FC03508B83E28C76AE91C325D7B
+:107F800022E0FDE729AFC40FDADACED705B2FBF461
+:107F90000E92FF9104241FF3FE275A377C6404D30A
+:107FA000045C346AB868E87FDA457858BF57627D68
+:107FB000AF01A91BE97E3AC416B8BDEF0917E16607
+:107FC000FD0F17BF162C07C817C04FFD28DFA82EBE
+:107FD000A7BE71B57F86A34B48C4EF62D8B434EC1A
+:107FE000A1FD13BFAF42BD374EA67BC96C44B94A51
+:107FF000F75F2E49637818A4BE85796993797D1857
+:10800000B67605E95ACBC96A08903DFD3BF201F509
+:10801000AD6F0E4D277AB5DF5213C6FD45F6EA4522
+:108020000E94BBE1C70EAF84AC179B2496FF4D7F27
+:10803000281DA07EF0A156C74D9F0D1FB417A33F6A
+:10804000B86747BDFF8824878378D4D479325F42EC
+:10805000D506536098F2B1591C5A3917E56CDADF2E
+:108060009F0FECBE3BC3FE5FFAD865AC0F37E2BF93
+:10807000F97BE7999C4FC453CB6B91BFA9F9780A60
+:10808000C9D9BCFB5C951DF7BF5A1A384DF2AF0B2E
+:10809000FD47EC1480BDFD157EF44315D433B4BF09
+:1080A000C9807DDDF3A0FC3F5670FB9739FD2B6B3B
+:1080B00067B33C2A13713F99369E1458DEF4F59A43
+:1080C00070AA0C28371005D94E799040A63A0B8635
+:1080D00004F170217F27A8FE02769009F757B4FAC1
+:1080E000B89ADA9B4FF5B0F1C89E7CC2FF351B5F92
+:1080F000AF3EB2EAB7D40F03874C32E12460005997
+:1081000041BE754141A53C432382332BA1FFA6927A
+:10811000CCECDFB877D67DEF274098ED5F33C052C7
+:10812000F2BB40BAE96D437AD1106D205C5C6CB54E
+:108130002841963F8EFB8BBDD212DA0F6E15A054EC
+:10814000A0F5715B89954196E1B7C53EDED732084F
+:108150009F75A9EE3DCF521FF89D91F58D64CF1903
+:1081600055C275F36021C39F6E4760F05D56DF9B7B
+:10817000F09D77A37D4D86A84CF9DE34784C76A32C
+:108180009CA6A3E817AE371F7D57A63ED472D25BDC
+:10819000C5F00BBD4075D60CBCCE5A06B9FFCD83D9
+:1081A00097E47513F2B8B6CCB93D4701701C7B7DDE
+:1081B000D56EBCB796F2F3658005BFD851D3856FF5
+:1081C000CA824A3BF30F0CF17CBF8DDEB3B332CDD4
+:1081D0000FCD2F6AF2CACE6E2F62767B8DC284BC21
+:1081E0003BBD4696279DBF79D0C1F8DACD2915D47D
+:1081F000376F5B380D2E44D914B7114B3884F1AC6E
+:108200003307DC5EBC9FBEF9DB8F411119DF5A4991
+:1082100038442798FEBF18A126F210BCD7991F2F0B
+:1082200025BE21ED5D8B362775D3DCA1B6580D44F4
+:1082300043CD563687A86D672D981118BA91240A38
+:10824000290485F8B0887A4FB802955EB43703B038
+:10825000EA3080B91011A8BEC6DEB9328BEC1ECB55
+:108260008B8F00BA6214F6D52CC23EF3188E41EC07
+:108270001DF1C466917DE9EFF1F7E28011BAE9DD05
+:1082800005831F56E07E54D0FCBB2B8609CF4342AA
+:10829000F42724DF6FB27617A23DCD5E8EE79622DB
+:1082A000FF7CD2EF2F92CABDA4D768ED16303E797D
+:1082B00038BF507F95B333AD846B4155A11DE58B1D
+:1082C000C2FBEBA88FEC8C9BC18472435A3CF3B287
+:1082D00097B2F75170A7E19B05F09E470C9A50FFAB
+:1082E0004E3087E99E2C5A54763EF4C15D01698E6A
+:1082F00074733815CF735E1094109A5A77EBF24668
+:108300008ACFC8DDA3168AFF982BF034D9952DC5E6
+:10831000CA77A1A93BEDCAF900C9F39B952E37C7CF
+:10832000B419F1BD90FF13863AEEA638917F613CF7
+:10833000E912C5772C7EF98D13B3899A15C2C7C28D
+:1083400021296AAA20A6C56AAC8CF3DC637906D51C
+:108350005C959003BD7B80EA668BF66EE8F2A6E240
+:108360001FCB741B285FE089A7EC427DA121C9DEE9
+:1083700003747FF83CF9B9D06C8D4A29C467FC7B43
+:10838000CC3C41EF993CC7E547D95306F77058718B
+:1083900085781EE7A742EBC47ED7E9E5FDBF53CB46
+:1083A000971E6FE6FC7DEF1BAFF72DE36BF7698A35
+:1083B000D7057CDFC89E5B4338CF3CA48FEAF41C12
+:1083C000CD3338A7BC5DAC7652DC751CE879D7F5A7
+:1083D000EAF9D5F308DF39F37E6A21CB5FF92E6025
+:1083E000EFEF81D302CB5F0FD5C5FE3B035ECA6BB7
+:1083F000C8B6A490F0FCFF96B7C97D259084B4F26E
+:10840000C1FEF282E44F9A81F4B6D8CBEA1BFBCDD1
+:108410009B149F7A4FAB40F1C19BC217EC37C789C1
+:108420006F1E3DAA6C4E13C3ECFBC4C0F5850E65F0
+:1084300084696E98578093049D77D8B47377177DBD
+:10844000CF84B6E1DC0BC42F70FE8E64767ECDA89F
+:10845000D9DB51CCE6433288C90B72793447D3FC5F
+:108460001D223DC8170C26B37BA1B0182C4D65E723
+:108470006CBEA65A66729A80CBD1ED6A7587E9BB4D
+:10848000C915E2FCF16FC9619A1703A9CF2FA7BEE6
+:108490001018E37DF182D7A1F5FDD81C9A93777E61
+:1084A000DF0684433DDFD9A0E15BCBB7A4E53BDB2E
+:1084B000C3F39D6D15A326CA5BE3227562DEA65148
+:1084C0006F44B9DFFCF393FBCCB8FE95DE1FDF9160
+:1084D000989D7DD56A56521A519748F3CF2F3FE3A6
+:1084E000F352FCB089D92965CEFACA7A7C07FBBC65
+:1084F000E17D1BE8DED73D4A10F58E889A9C67F82F
+:108500005CDD671383C4D7579B14065A17F2F3BE7A
+:108510008D33D95C359EB7D2FBF336D698CBE28348
+:1085200079E3E7AFD898DEC47911CFAB24B03E81B0
+:10853000F9AA798BBDF3F194EAF2043EC6B4B961AD
+:108540004CCBCBF83EE03EDD37C45328AE9FB7EFAF
+:10855000710544DF9CC4799F43CDA2396872DC77F2
+:108560007779BBA7131E6CA29DE6FBA9F2A5E727AE
+:1085700079957C90E68EF13C05390E9343F398FF94
+:10858000AFE979E990D8BB35398F90CB71A1CFFD98
+:1085900005C14BFBF87B1D7B84EA07EBAE8CBE1755
+:1085A00047A87F5526702BA858ABCE044EF53E3613
+:1085B000B97E8576EC6B290FABDF087B9F6F8B5103
+:1085C000BD7EA7537CE0D73888E1FA80A0649A8A00
+:1085D000BF50FD3EEAC3FEBA37235041FC695ABF83
+:1085E000D82F86BD241FF1D418E17D52A0387FAC6E
+:1085F000C5AF1EFBD134AC93A53EFEFF18B06D5243
+:108600005FD2E25DA7DDFFF813ACA7CA44BEEAB5AE
+:10861000EF9EBA6DA64BD4DFEAB61979FCDB17AB37
+:1086200093E4B0FEACCB01F7CD74F247E7ABDFF8D3
+:10863000AF749A0BA7E48FE53A2E276BFD11FDADC1
+:1086400092FD4F919F2362CCA6607C4EFD5BAA21D8
+:10865000FF2E61BCDD84934319FCBBCCC165ACF03B
+:10866000F177AEC7E4AF26BE53DE2BA5F49D039F82
+:108670000EE7921D4B5CFEAFD1FECB25B764DAAF9F
+:1086800087D80101E58ED45ECF23BBEADB3F60FDD6
+:10869000BB5EEFDF9F13A7C9F1D1E396F0F7563A1F
+:1086A000CDBBFFAB78FD0772A96C9D701300000075
+:1086B000000000000000000000000040000000007A
+:1086C000000000000000004000000000000000006A
+:1086D0000000002800000000000000000000001062
+:1086E000000000000000000000000040000000004A
+:1086F000000000000000001000000000000000006A
+:108700000000000800000000000000000000000061
+:108710000000000000000000000000000000000059
+:108720000000000000000000000000000000000049
+:108730000000000000000000000000000000000039
+:108740000000000000000000000000000000000029
+:108750000000000000000000000000000000000019
+:108760000000000000000000000000000000000009
+:1087700000000000000000000000000000000000F9
+:1087800000000000000000000000000000000000E9
+:1087900000000000000000000000000000000000D9
+:1087A00000000000000000000000000000000000C9
+:1087B00000000000000000000000000000000000B9
+:1087C00000000000000000000000000000000000A9
+:1087D0000000000000000000000000000000000099
+:1087E0000000000000000000000000000000000089
+:1087F0000000000000000000000000000000000079
+:108800000000000000000000000000000000000068
+:108810000000000000000000000000000000000058
+:108820000000332000100000000000080000332882
+:1088300000100000000000020000332000100000C3
+:108840000000001080000000000000000000000098
+:108850008000000000000000000000008000000018
+:108860000000000000000000800000000000000088
+:108870000000000000003358000100040000000167
+:1088800000003360000000000000000200003368B8
+:1088900000000000000000080000336C0000000031
+:1088A0000000000200003920000000000000000865
+:1088B00000003AF800400000000000400000393895
+:1088C000008000000000004800003A38004000002E
+:1088D0000000000800003A480040000000000018B6
+:1088E00000003370002800000000002800003C2039
+:1088F000000800000000000100003C21000800000A
+:108900000000000100003C220008000000000001FF
+:1089100000002008001000000000001000002000EF
+:1089200000000000000000088000000000000000BF
+:108930000000000000000000000000000000000037
+:108940000000000000000000000000000000000027
+:108950000000000000000000000000000000000017
+:108960000000000000000000000000000000000007
+:1089700000000000000000000000000000000000F7
+:1089800000000000000000000000000000000000E7
+:1089900000000000000000000000000000000000D7
+:1089A00000000000000000000000000000000000C7
+:1089B00000000000000000000000000000000000B7
+:1089C00000000000000000000000000000000000A7
+:1089D0000000000000000000000000000000000097
+:1089E0000000000000000000800000000000000007
+:1089F00000000000800000000000000000000000F7
+:108A00008000000000000000000000008000000066
+:108A100000000000000000008000000000000000D6
+:108A200000000000800000000000000000000000C6
+:108A30008000000000000000000000008000000036
+:108A400000000000000000008000000000000000A6
+:108A50000000000080000000000000000000000096
+:108A60008000000000000000000000008000000006
+:108A700000000000000000000000000000000000F6
+:108A800000000000000000000000000000000000E6
+:108A900000000000000000000000000000000000D6
+:108AA00000000000000000000000000000000000C6
+:108AB0000000000080000000000000000000000036
+:108AC00080000000000000000000000080000000A6
+:108AD0000000000000000000000000000000000096
+:108AE0000000000080000000000000000000000006
+:108AF0008000000000000000000000008000000076
+:108B00000000000000000000000000000000000065
+:108B10000000000000000000000000000000000055
+:108B20000000000000000000000000000000000045
+:108B30000000000000000000000000000000000035
+:108B40000000000000000000000000000000000025
+:108B50008000000000000000000000000000000095
+:108B60000000000000000000000019C80000000024
+:108B700000000008000020080010000000000010A5
+:108B8000000020000000000000000008800000003D
+:108B90000000000000000000800000000000000055
+:108BA00000000000000000000000000000000000C5
+:108BB00000000000000000000000000000004870FD
+:108BC00000080000000000010000487100080000DB
+:108BD00000000001000048720008000000000001D1
+:108BE0000000404000380000000000388000000015
+:108BF00000000000000000008000000000000000F5
+:108C000000000000800000000000000000000000E4
+:108C10008000000000000000000000008000000054
+:108C200000000000000000008000000000000000C4
+:108C300000000000800000000000000000000000B4
+:108C40008000000000000000000000008000000024
+:108C50000000000000000000800000000000000094
+:108C60000000000080000000000000000000000084
+:108C700000000000000000000000000000000000F4
+:108C800000000000000000000000000000000000E4
+:108C900000000000000000000000000000000000D4
+:108CA0000000000000000000000000008000000044
+:108CB0000000000000000000800000000000000034
+:108CC00000000000000000000000000000000000A4
+:108CD0008000000000000000000000008000000094
+:108CE0000000000000000000800000000000000004
+:108CF00000000000800000000000000000000000F4
+:108D00008000000000000000000000008000000063
+:108D100000000000000000000000400000400000D3
+:108D2000000000400000480000400000000000403B
+:108D30000000482E00400000000000010000480034
+:108D40000040000200000001000048010040000255
+:108D50000000000000003000004000000000004063
+:108D60008000000000000000000000000000300053
+:108D7000000800400000000400003004000800402B
+:108D80000000000400003B800028000000000028D4
+:108D900000003BD0001000000000001000003BDA93
+:108DA00000100000000000010000380000800000FA
+:108DB0000000008000003800000800800000000271
+:108DC00000003900004000000000004000002008C2
+:108DD0000010000000000010000020000000000053
+:108DE0000000000800005198000800000000000189
+:108DF0000000519900080000000000010000519A95
+:108E0000000800000000000100003980001000048C
+:108E100000000004000051A80030001800000010FD
+:108E2000000051B000300018000000028000000077
+:108E300000000000000000008000000000000000B2
+:108E400000000000800000000000000000000000A2
+:108E50008000000000000000000000008000000012
+:108E60000000000000000000800000000000000082
+:108E70000000000080000000000000000000000072
+:108E800000000000000000000000000000000000E2
+:108E900000000000000000000000000000000000D2
+:108EA00000000000000000000000000000000000C2
+:108EB00080000000000000000000000080000000B2
+:108EC00000000000000000000000000000000000A2
+:108ED0000000000080000000000000000000000012
+:108EE0008000000000000000000000008000000082
+:108EF00000000000000000008000000000000000F2
+:108F000000000000800000000000000000000000E1
+:108F1000000023E800800000000000800000000145
+:108F20000000000000000000000020080010000009
+:108F300000000010000020000000000000000008F9
+:108F400000002E70000800000000000100002E71DB
+:108F5000000800000000000100002E720008000060
+:108F600000000001000024E8003800000000003884
+:108F700000002DD000080000000000088000000064
+:108F80000000000000000000800000000000000061
+:108F90000000000080000000000000000000000051
+:108FA00080000000000000000000000080000000C1
+:108FB0000000000000000000800000000000000031
+:108FC00000000000000000000000000000000000A1
+:108FD0000000000000000000000000000000000091
+:108FE0000000000000000000000000000000000081
+:108FF00000000000800000000000000000000000F1
+:1090000080000000000000000000000000000000E0
+:1090100000000000000000008000000000000000D0
+:1090200000000000800000000000000000000000C0
+:109030008000000000000000000000008000000030
+:1090400000000000000000008000000000000000A0
+:1090500000000000000025000040000000000008A3
+:1090600000002508004000000000002080000000F3
+:109070000000000000000000800000000000000070
+:109080000000000080000000000000000000000060
+:1090900080000000000000000000000080000000D0
+:1090A0000000000000000000000030000000000090
+:1090B00000001000000050A10000000000000001AE
+:1090C000000050B80000000000000002000050C87E
+:1090D0000090000800000008800000000000000070
+:1090E00000000000000029600008000000000001EE
+:1090F0000000296100080000000000010000297044
+:1091000000080004000000020000297800080004A4
+:1091100000000004800000000000000000000000CB
+:1091200000002FB0000800000000000400002FB471
+:10913000000800000000000400002FC00000000034
+:109140000000000800002FC8000000000000000818
+:10915000000030000000000000000010000050403F
+:1091600000010001000000010000500000000000AC
+:1091700000000020000008080010000000000004AB
+:109180000000080C0010000000000001000008B7FB
+:109190000000000000000001000008B60000000010
+:1091A000000000010000100000400020000000044A
+:1091B000000010040040002000000004000010081F
+:1091C00000400020000000020000100A00400020C3
+:1091D000000000020000100C004000200000000110
+:1091E0000000100D00400020000000010000100EE3
+:1091F000004000200000000100001010004000208E
+:1092000000000004000010140040002000000004D2
+:109210000000101800400020000000040000101C96
+:109220000040002000000004000030000100008029
+:109230000008000400003004010000800008000461
+:109240000000000A0000000000000000000030687C
+:109250000100008000000001000030690100008072
+:10926000000000010000306C0100008000000002DE
+:109270000000306E0100008000000002000030702D
+:109280000100008000000004000030740100008034
+:1092900000000004000030660100008000000002B1
+:1092A0000000306401000080000000010000306018
+:1092B0000100008000000002000030620100008018
+:1092C0000000000200003050010000800000000497
+:1092D00000003054010000800000000400003058FD
+:1092E00001000080000000040000305C01000080EC
+:1092F000000000040000307C01000080000000013C
+:109300000000307D010000800000000100001C18FA
+:10931000001000000000000400001C3000100000DD
+:109320000000000400001C380010000000000004D1
+:10933000800000000000000000000000800000002D
+:10934000000000000000000080000000000000009D
+:10935000000000008000000000000000000000008D
+:1093600000004C10000800000000000200004C1239
+:10937000000800000000000200004C14000800007B
+:109380000000000200004C1600080000000000026F
+:1093900000004C20000800000000000800004C0005
+:1093A000000800000000000200004C02000800005D
+:1093B0000000000100004C04000800000000000252
+:1093C00000004C30000800000000000800004C4085
+:1093D000000800000000000400004C4400080000E9
+:1093E0000000000100004C500008000000000002D6
+:1093F00000004C54000800000000000200004C5225
+:10940000000800000000000200004C60000800009E
+:10941000000000040000140000080000000000022A
+:109420000000140200080000000000010000140405
+:1094300000080000000000020000141000080000F6
+:1094400000000002000014140008000000000002E8
+:10945000000014160008000000000002000019B807
+:1094600000080000000000080000142000080000B0
+:1094700000000002000014240008000000000002A8
+:10948000000019C8000800000000000800002C10AF
+:10949000000800000000000100002C11000800007E
+:1094A0000000000100002C12000800000000000174
+:1094B00000002C13000800000000000100002C0038
+:1094C000000800000000000200002C02000800005C
+:1094D0000000000100002C04000800000000000251
+:1094E00000002C30000800000000000200002C32B8
+:1094F000000800000000000200002C3400080000FA
+:109500000000000200002C20000800000000000104
+:1095100000002C21000800000000000100002C22A7
+:10952000000800000000000100002C2300080000DB
+:109530000000000100002C240008000000000001D1
+:1095400000002C25000800000000000100002C266F
+:109550000008000000000001000014800008000066
+:10956000000000020000148200080000000000015A
+:1095700000001484000800000000000200001492A3
+:1095800000C00018000000020000149000C0001885
+:10959000000000020000149C00C000180000000839
+:1095A0000000149400C0001800000008000014A778
+:1095B00000C0001800000001000014A400C0001842
+:1095C00000000002000014A600C000180000000106
+:1095D000000016100008000000000008000016201F
+:1095E000000800000000000800001630000800001D
+:1095F00000000008800000000000000000000000E3
+:10960000800000000000000000000000800000005A
+:1096100000000000000000008000000000000000CA
+:1096200000000000800000000000000000000000BA
+:10963000800000000000000000000000800000002A
+:10964000000000000000000080000000000000009A
+:10965000000000008000000000000000000000008A
+:1096600080000000000000000000000080000000FA
+:10967000000000000000000080000000000000006A
+:10968000000000008000000000000000000000005A
+:1096900080000000000000000000000080000000CA
+:1096A000000000000000000080000000000000003A
+:1096B000000000008000000000000000000000002A
+:1096C000800000000000000000000000800000009A
+:1096D000000000000000000080000000000000000A
+:1096E00000000000800000000000000000000000FA
+:1096F000800000000000000000000000800000006A
+:1097000000000000000000008000000000000000D9
+:1097100000000000800000000000000000000000C9
+:109720008000000000000000000000008000000039
+:1097300000000000000000008000000000000000A9
+:109740000000000080000000000000000000000099
+:109750008000000000000000000000008000000009
+:109760000000000000000000800000000000000079
+:109770000000000080000000000000000000000069
+:1097800080000000000000000000000080000000D9
+:109790000000000000000000800000000000000049
+:1097A0000000000080000000000000000000000039
+:1097B00080000000000000000000000080000000A9
+:1097C0000000000000000000800000000000000019
+:1097D0000000000080000000000000000000000009
+:1097E0008000000000000000000000008000000079
+:1097F00000000000000000008000000000000000E9
+:1098000000000000800000000000000000000000D8
+:109810008000000000000000000000008000000048
+:1098200000000000000000008000000000000000B8
+:1098300000000000800000000000000000000000A8
+:109840008000000000000000000000008000000018
+:109850000000000000000000800000000000000088
+:109860000000000080000000000000000000000078
+:1098700080000000000000000000000080000000E8
+:109880000000000000000000800000000000000058
+:109890000000000080000000000000000000000048
+:1098A0008000000000000000000000000000000038
+:1098B0000000000000000000800000000000000028
+:1098C0000000000000000000070C1E000000000067
+:00000001FF
--- linux-4.4.0.orig/firmware/bnx2x/bnx2x-e1h-7.12.30.0.fw.ihex
+++ linux-4.4.0/firmware/bnx2x/bnx2x-e1h-7.12.30.0.fw.ihex
@@ -0,0 +1,11190 @@
+:10000000000021F800000068000005D80000226808
+:10001000000036EC000028480000007000005F3847
+:1000200000007A8C00005FB0000000A00000DA4001
+:100030000000D2DC0000DAE8000000880001ADC852
+:1000400000003CA40001AE58000000880001EB0055
+:100050000000BD780001EB900000120C0002A91016
+:10006000000000040002BB20020600DC00000001CA
+:100070000306100002000000010600D80000000086
+:100080000306020000030200020600DC000000007C
+:10009000010600B800000000010600C800000000D2
+:1000A0000206016C00000000010600BC0000000018
+:1000B000010600CC000000000206017000000000F4
+:1000C000020D004400000032030D004C0004020346
+:1000D000040D005C00000004030D008C00110207F9
+:1000E000020D015C00000001030D01640002021812
+:1000F000020D020400000001030D020C0003021AAD
+:10010000030D02200002021D040D028000000012F7
+:10011000030D03000018021F040D03600000000C13
+:10012000040D400000000A00030D0004000F023718
+:10013000020D01140000000D020D01180000002D39
+:10014000020D01140000001D020D01180000003D09
+:10015000020D01140000004D020D01180000006D99
+:10016000020D01140000005D020D01180000007D69
+:10017000031010000003024602101050000000019E
+:10018000071011000010024908101140000000087B
+:100190000710116000100259081011A0000000188B
+:1001A000071018000200026904104C000000010052
+:1001B00002104028000000100310404000020469B3
+:1001C0000210405800280000021040840084924A27
+:1001D0000210405800000000030C20080003046BCC
+:1001E000030C201C0004046E030C20380011047260
+:1001F000040C207C0000004F030C21B80011048384
+:10020000040C21FC0000000F030C223800040494AD
+:10021000010C224800000000010C224C00000000EC
+:10022000010C225000000000010C225400000000CC
+:10023000010C225800000000010C225C00000000AC
+:10024000010C226000000000010C2264000000008C
+:10025000010C226800000000010C226C000000006C
+:10026000010C227000000000010C2274000000004C
+:10027000010C227800000000010C227C000000002C
+:100280000A00000100000001020C2000000003E849
+:100290000A00000100000002020C20000000000A19
+:1002A0000A00000100000004020C20000000000110
+:1002B0000520040000860000062007800010049836
+:1002C000042200000000400004232400000000403D
+:1002D000032212500010049A0422B14000000020B2
+:1002E0000422C800000000060322C818000404AA63
+:1002F0000422C8280000000C0322C858000404AEE1
+:100300000422C8680000000C0322C898000404B24C
+:100310000422C8A80000000C0322C8D8000404B6B8
+:100320000422C8E80000000C0322C918000404BA23
+:100330000422C9280000000C0322C958000404BE8E
+:100340000422C9680000000C0322C998000404C2FA
+:100350000422C9A80000000C0322C9D8000404C666
+:100360000422C9E80000000C0322CA18000404CAD1
+:100370000422CA280000000C0322CA58000404CE3C
+:100380000422CA680000000C0322CA98000404D2A8
+:100390000422CAA80000000C0322CAD8000404D614
+:1003A0000422CAE80000000C0322CB18000404DA7F
+:1003B0000422CB280000000C0322CB58000404DEEA
+:1003C0000422CB680000000C0322CB98000404E256
+:1003D0000422CBA80000000C0322CBD8000404E6C2
+:1003E0000422CBE80000000C0322CC18000404EA2D
+:1003F0000422CC280000000C0322CC58000404EE98
+:100400000422CC680000000C0322CC98000404F203
+:100410000422CCA80000000C0322CCD8000404F66F
+:100420000422CCE80000000C0322CD18000404FADA
+:100430000422CD280000000C0322CD58000404FE45
+:100440000422CD680000000C0322CD9800040502B0
+:100450000422CDA80000000C0322CDD8000405061C
+:100460000422CDE80000000C0322CE180004050A87
+:100470000422CE280000000C0322CE580004050EF2
+:100480000422CE680000000C0322CE98000405125E
+:100490000422CEA80000000C0322CED800040516CA
+:1004A0000422CEE80000000C0322CF180004051A35
+:1004B0000422CF280000000C0322CF580004051EA0
+:1004C0000422CF680000000C0322CF98000405220C
+:1004D0000422CFA80000000C0322CFD80004052678
+:1004E0000422CFE800000006022380000000001074
+:1004F00002238040000000120223808000000030B0
+:10050000022380C00000000E022383800007A12088
+:10051000022383C0000001F402238BC0000000010D
+:100520000A00000200000001022383000007A1204E
+:1005300002238340000001F40A00000200000002D0
+:10054000022383000000138802238340000000057B
+:100550000A000002000000040223830000000138AA
+:1005600002238340000000000524000036500000F4
+:100570000524800006540D9406248B306D00052A56
+:100580000A000001000000020223148000000000A5
+:100590000A00000100000004022314800000000093
+:1005A0000120000000000000012000040000000005
+:1005B00001200008000000000120000C00000000E5
+:1005C00001200010000000000120001400000000C5
+:1005D00003200020001A052C032000A40002054679
+:1005E000022002240000000002200234000000006B
+:1005F0000220024C00000000022002E40000FFFF85
+:100600000820200000000800042211080000000259
+:1006100004221290000000060422340000000002B0
+:10062000042260400000003004228C000000001012
+:100630000422111000000002042212A8000000068B
+:10064000042234080000000204226100000000308F
+:1006500004228C4000000010042211180000000247
+:10066000042212C000000006042234100000000220
+:10067000042261C00000003004228C8000000010C1
+:100680000422112000000002042212D800000006FB
+:1006900004223418000000020422628000000030AE
+:1006A00004228CC000000010042211280000000267
+:1006B000042212F000000006042234200000000290
+:1006C000042263400000003004228D00000000106E
+:1006D000042211300000000204221308000000066A
+:1006E00004223428000000020422640000000030CC
+:1006F00004228D4000000010042211380000000286
+:1007000004221320000000060422343000000002FE
+:10071000042264C00000003004228D80000000101C
+:1007200004221140000000020422133800000006D9
+:1007300004223438000000020422658000000030EA
+:1007400004228DC00000001004102400000000E00E
+:100750000310201C00020548021020C00000000207
+:10076000031020040002054A0217000800000002DE
+:100770000217002C00000003031700380002054C8C
+:10078000031700480005054E0317006000050553D8
+:100790000317007800020558021700040000000F3C
+:1007A0000210800000001080041080400000000251
+:1007B000021080AC00000000021080380000001021
+:1007C00002108100000000000410812000000002DF
+:1007D00002108008000002B5021080100000000026
+:1007E000021081080001FFFF041082000000004A8F
+:1007F00004108140000000020210800000001A80F6
+:100800000410900000000024041091200000004A11
+:10081000041093700000004A041095C00000004AC4
+:1008200002108004000010800410804800000002C4
+:10083000021080B0000000010210803C0000001097
+:100840000210810400000000041081280000000252
+:100850000210800C000002B502108014000000009D
+:100860000210810C0001FFFF041084000000004A08
+:1008700004108148000000020210800400001A8069
+:100880000410909000000024041092480000004AD8
+:10089000041094980000004A041096E80000004AF2
+:1008A0000210800000001080041080400000000250
+:1008B000021080AC0000000202108038000000101E
+:1008C00002108100000000000410812000000002DE
+:1008D00002108008000002B5021080100000000025
+:1008E000021081080001FFFF041082000000004A8E
+:1008F00004108140000000020210800000001A80F5
+:100900000410900000000024041091200000004A10
+:10091000041093700000004A041095C00000004AC3
+:1009200002108004000010800410804800000002C3
+:10093000021080B0000000030210803C0000001094
+:100940000210810400000000041081280000000251
+:100950000210800C000002B502108014000000009C
+:100960000210810C0001FFFF041084000000004A07
+:1009700004108148000000020210800400001A8068
+:100980000410909000000024041092480000004AD7
+:10099000041094980000004A041096E80000004AF1
+:1009A000021080000000108004108040000000024F
+:1009B000021080AC0000000402108038000000101B
+:1009C00002108100000000000410812000000002DD
+:1009D00002108008000002B5021080100000000024
+:1009E000021081080001FFFF041082000000004A8D
+:1009F00004108140000000020210800000001A80F4
+:100A00000410900000000024041091200000004A0F
+:100A1000041093700000004A041095C00000004AC2
+:100A200002108004000010800410804800000002C2
+:100A3000021080B0000000050210803C0000001091
+:100A40000210810400000000041081280000000250
+:100A50000210800C000002B502108014000000009B
+:100A60000210810C0001FFFF041084000000004A06
+:100A700004108148000000020210800400001A8067
+:100A80000410909000000024041092480000004AD6
+:100A9000041094980000004A041096E80000004AF0
+:100AA000021080000000108004108040000000024E
+:100AB000021080AC00000006021080380000001018
+:100AC00002108100000000000410812000000002DC
+:100AD00002108008000002B5021080100000000023
+:100AE000021081080001FFFF041082000000004A8C
+:100AF00004108140000000020210800000001A80F3
+:100B00000410900000000024041091200000004A0E
+:100B1000041093700000004A041095C00000004AC1
+:100B200002108004000010800410804800000002C1
+:100B3000021080B0000000070210803C000000108E
+:100B4000021081040000000004108128000000024F
+:100B50000210800C000002B502108014000000009A
+:100B60000210810C0001FFFF041084000000004A05
+:100B700004108148000000020210800400001A8066
+:100B80000410909000000024041092480000004AD5
+:100B9000041094980000004A041096E80000004AEF
+:100BA0000200A468000B01C80300A2940004055AC7
+:100BB0000A000001000000800200A5F8000000000B
+:100BC0000A000001000001000200A5F80000000179
+:100BD0000200A270000000000200A27400000000E9
+:100BE0000200A270000000000200A27400000000D9
+:100BF0000200A270000000000200A27400000000C9
+:100C00000200A270000000000200A27400000000B8
+:100C1000030100B40002055E020100DC00000001D7
+:100C200003010100000205600201007C00300000A9
+:100C300002010084000000280201008C0000000076
+:100C4000020101300000000402010328000000003E
+:100C50000201055400000030020160580000FFFF4F
+:100C600002016070000000070201608000000001C6
+:100C7000020100C400000001020100CC00000001DC
+:100C8000020100F800000001020100F00000000174
+:100C900002010080003000000201008800000028EE
+:100CA0000201009000000000020101340000000475
+:100CB0000201032C00000000020105640000003066
+:100CC0000201605C0000FFFF020160740000000789
+:100CD0000201608400000001020100C80000000160
+:100CE000020100D000000001020100FC0000000130
+:100CF000020100F4000000010401013800000011AD
+:100D00000401017C00000011040101380000001101
+:100D10000401017C000000110401013800000011F1
+:100D20000401017C000000110401013800000011E1
+:100D30000401017C00000011021400000000000109
+:100D40000214000C000000010314004000020562C0
+:100D50000214000C0000000002140000000000005B
+:100D60000214006C000000000214000400000001E6
+:100D70000214003000000001021400040000000012
+:100D80000214005C000000000214000800000001D2
+:100D900002140034000000010214000800000000EA
+:100DA0000214006000000000030400040012056447
+:100DB00002040054000000430204005C000000062E
+:100DC00002040070000000040304007800040576AB
+:100DD00004040088000000050304009C0003057A59
+:100DE000040400A800000004030400B80005057D09
+:100DF000040400CC00000004030400DC00040582AD
+:100E0000040400EC000000040104012400000000C0
+:100E100001040128000000000104012C0000000072
+:100E20000104013000000000020401340000000F42
+:100E3000020401D000008906021205B00000000182
+:100E400003120490002205860312066C000205A816
+:100E500002120388000000640212039000000008E0
+:100E60000312039C000305AA031203BC000305AD93
+:100E7000021203D0000000000212036C0000000107
+:100E8000021203680000003F031201BC003C05B0E1
+:100E9000031202B0000205EC03120324000205EE67
+:100EA000021205B400000001021201B000000001AE
+:100EB00007103800000505F007103820000505F57B
+:100EC00007103C00000505FA03168030000805FFF6
+:100ED0000216805400000002031680600005060719
+:100EE0000416807400000007031680900002060CB0
+:100EF0000316809C0005060E041680B00000000753
+:100F0000031680CC00080613021680F000000007CC
+:100F1000041680F40000000C031681240004061B54
+:100F2000041681340000000C031681640032061F91
+:100F30000316823400070651041682500000000494
+:100F4000031682600002065804168268000000083A
+:100F5000031682880008065A041682A80000000AB8
+:100F600002168804000000040316880C00100662B4
+:100F70000316E000001006720416E40C0000000CDA
+:100F80000316E43C000406820416E44C0000000C46
+:100F90000316E47C002E06860416E53400000004E7
+:100FA0000316E544000206B40416E54C00000008F0
+:100FB0000316E56C000606B60316E6BC000806BC80
+:100FC000021680EC000000FF03040408001406C4AD
+:100FD000020404CC0000000103050044000206D80E
+:100FE00003050050000406DA040500600000000458
+:100FF00003050090001306DE020501140000000145
+:101000000305011C000206F10205020400000001B4
+:101010000305020C000206F30305021C000306F59B
+:10102000040502400000000A03050280002006F8C3
+:101030000405400000000D0003050004001007181F
+:10104000020500E00000000E020500E40000002E92
+:10105000020500E00000001E020500E40000003E62
+:10106000020500E00000004E020500E40000006EF2
+:10107000020500E00000005E020500E40000007EC2
+:101080000416402400000002031640300003072825
+:101090000216404400000020021640700000001CB0
+:1010A0000216420800000001021642100000000172
+:1010B0000216422000000001021642280000000132
+:1010C0000216423000000001021642380000000102
+:1010D00002164260000000020A0000010000000148
+:1010E0000216401C0003D0900A000001000000021C
+:1010F0000216401C000009C40A00000100000004A0
+:101100000216401C0000009C021640000000000176
+:10111000021640D800000001031640080003072B08
+:101120000216424000000000021642480000000083
+:101130000816427000000002021642500000000033
+:10114000021642580000000008164280000000020B
+:10115000030420080004072E0304201C00040732A7
+:1011600002042038000000200404203C0000001F7E
+:10117000020420B800000001040420BC0000005F4D
+:10118000030422380004073601042248000000004E
+:101190000104224C00000000010422500000000065
+:1011A0000104225400000000010422580000000045
+:1011B0000104225C00000000010422600000000025
+:1011C0000104226400000000010422680000000005
+:1011D0000104226C000000000104227000000000E5
+:1011E00001042274000000000104227800000000C5
+:1011F0000104227C000000000A0000010000000140
+:1012000002042000000003E80A00000100000002C0
+:10121000020420000000000A0A000001000000048F
+:101220000204200000000001051804000070000006
+:10123000061807600014073A041A00000000400076
+:10124000041B240000000040031A1EC80002073CD3
+:10125000031A40400004073E041A405000000006F4
+:10126000031A406800020742031A52C000020744F2
+:10127000031A800003F90746041A8FE400000007F0
+:10128000031AA08000100B3F021B800000000034F6
+:10129000021B804000000018021B80800000000C30
+:1012A000021B80C000000020021B83800007A120D9
+:1012B000021B83C0000001F4021B8BC00000000170
+:1012C0000A00000200000001021B83000007A120A9
+:1012D000021B8340000001F40A000002000000022B
+:1012E000021B830000001388021B834000000005DE
+:1012F0000A00000200000004021B83000000013805
+:10130000021B834000000000051C0000317A000031
+:10131000051C800035910C5F051D0000137B19C46E
+:10132000061D2B105A9E0B4F0A0000010000000200
+:10133000021B1480000000000A00000100000004ED
+:10134000021B1480000000000118000000000000D3
+:10135000011800040000000001180008000000004F
+:101360000118000C0000000001180010000000002F
+:10137000011800140000000003180020001A0B518F
+:10138000031800A400020B6B0218022400000000E6
+:1013900002180234000000000218024C0000000095
+:1013A000021802E4000000FF08181000000004000A
+:1013B000041A300000000010041A308000000010F1
+:1013C000041A310000000010041A318000000010DF
+:1013D000041A330000000012041A339000000012B7
+:1013E000041A342000000070041A90000000000667
+:1013F000041A304000000010041A30C00000001031
+:10140000041A314000000010041A31C0000000101E
+:10141000041A334800000012041A33D800000012E6
+:10142000041A35E000000070041A9018000000064D
+:10143000031A400000020B6D041A50000000000265
+:10144000041A508000000012031A614000020B6F62
+:10145000041A903000000002041AA00000000002EC
+:10146000031A400800020B71041A50100000000219
+:10147000041A50C800000012031A614800020B73DE
+:10148000041A903800000002041AA00800000002AC
+:10149000031A401000020B75041A502000000002CD
+:1014A000041A511000000012031A615000020B7759
+:1014B000041A904000000002041AA010000000026C
+:1014C000031A401800020B79041A50300000000281
+:1014D000041A515800000012031A615800020B7BD5
+:1014E000041A904800000002041AA018000000022C
+:1014F000031A402000020B7D041A50400000000235
+:10150000041A51A000000012031A616000020B7F50
+:10151000041A905000000002041AA02000000002EB
+:10152000031A402800020B81041A505000000002E8
+:10153000041A51E800000012031A616800020B83CC
+:10154000041A905800000002041AA02800000002AB
+:10155000031A403000020B85041A5060000000029C
+:10156000041A523000000012031A617000020B8747
+:10157000041A906000000002041AA030000000026B
+:10158000031A403800020B89041A50700000000250
+:10159000041A527800000012031A617800020B8BC3
+:1015A000041A906800000002041AA038000000022B
+:1015B000020E004C00000032030E005400040B8D9C
+:1015C000040E006400000004030E009400130B914D
+:1015D000020E014400000001030E014C00020BA4A6
+:1015E000020E020400000001030E020C00020BA612
+:1015F000030E021C00040BA8030E0280001B0BACA0
+:10160000040E02EC00000017040E20000000080089
+:10161000030E000400110BC7020E01100000000FA2
+:10162000020E01140000002F020E01100000001F26
+:10163000020E01140000003F020E01100000004FD6
+:10164000020E01140000006F020E01100000005F86
+:10165000020E01140000007F020C100000000028A0
+:10166000030C400800040BD8030C401C00040BDCE6
+:10167000030C403800050BE0040C404C0000005BFC
+:10168000030C41B800050BE5040C41CC0000001B25
+:10169000030C423800040BEA010C42480000000031
+:1016A000010C424C00000000010C42500000000000
+:1016B000010C425400000000010C425800000000E0
+:1016C000010C425C00000000010C426000000000C0
+:1016D000010C426400000000010C426800000000A0
+:1016E000010C426C00000000010C42700000000080
+:1016F000010C427400000000010C42780000000060
+:10170000010C427C00000000010C4280000000003F
+:101710000A00000100000001020C4000000003E884
+:101720000A00000100000002020C40000000000A54
+:101730000A00000100000004020C4000000000014B
+:1017400005300400009E00000630076800130BEE11
+:101750000432000000004000043324000000004078
+:1017600004323E800000001003323EC000020BF045
+:10177000033274C000080BF20332850000100BFA2C
+:10178000023380000000001A023380400000004E47
+:101790000233808000000010023380C0000000206F
+:1017A000023383800007A120023383C0000001F4CC
+:1017B00002338BC0000000010A000002000000019B
+:1017C000023383000007A12002338340000001F4AC
+:1017D0000A000002000000020233830000001388A8
+:1017E00002338340000000050A00000200000004EC
+:1017F0000233830000000138023383400000000000
+:1018000005340000346A000005348000283C0D1BBC
+:101810000535000024B7172A0535800034C8205844
+:10182000053600001CB42D8A063640B037EA0C0A93
+:101830000A000001000000020233148000000000D2
+:101840000A000001000000040233148000000000C0
+:101850000130000000000000013000040000000022
+:1018600001300008000000000130000C0000000002
+:1018700001300010000000000130001400000000E2
+:1018800003300020001A0C0C033000A400020C26C8
+:101890000230022400000000023002340000000088
+:1018A0000230024C00000000023002E40000FFFFA2
+:1018B000083020000000080004321000000001C0C1
+:1018C00004321E000000003804323000000001C065
+:1018D00004325000000000200432510000000020BB
+:1018E00004325200000000200432530000000020A7
+:1018F0000432540000000020043255000000002093
+:10190000043256000000002004325700000000207E
+:10191000043258000000002004325900000000206A
+:1019200004325A000000002004325B000000002056
+:1019300004325C000000002004325D000000002042
+:1019400004325E000000002004325F00000000202E
+:1019500004328450000000020332846000040C282A
+:1019600004321700000001C004321EE000000038FD
+:1019700004323700000001C0043250800000002013
+:101980000432518000000020043252800000002008
+:1019900004325380000000200432548000000020F4
+:1019A00004325580000000200432568000000020E0
+:1019B00004325780000000200432588000000020CC
+:1019C000043259800000002004325A8000000020B8
+:1019D00004325B800000002004325C8000000020A4
+:1019E00004325D800000002004325E800000002090
+:1019F00004325F800000002004328458000000029E
+:101A00000332847000040C2C0432401000000002E9
+:101A10000432841000000002043240200000000262
+:101A2000043284180000000204324030000000023A
+:101A30000432842000000002043240400000000212
+:101A400004328428000000020432405000000002EA
+:101A500004328430000000020432406000000002C2
+:101A6000043284380000000204324070000000029A
+:101A70000432844000000002043240800000000272
+:101A800004328448000000020202005800000032C4
+:101A90000302006000040C30040200700000000427
+:101AA000030200A0000E0C34030200DC00070C420D
+:101AB000020200FC000000060202012000000000FB
+:101AC0000202013400000002020201B00000000125
+:101AD0000202020C000000010302021400020C4981
+:101AE00002020404000000010302040C00020C4B7B
+:101AF0000302041C00040C4D0302048000200C515E
+:101B00000402050000000012040280000000200012
+:101B10000302000400140C7102020108000000C856
+:101B20000202011800000002020201C400000000CD
+:101B3000020201CC00000000020201D400000002F9
+:101B4000020201DC00000002020201E4000000FFCA
+:101B5000020201EC000000FF0202010C000000C8BC
+:101B60000202011C00000002020201C80000000085
+:101B7000020201D000000000020201D800000002B1
+:101B8000020201E000000002020201E8000000FF82
+:101B9000020201F0000000FF02020108000000C87C
+:101BA0000202011800000002020201C4000000004D
+:101BB000020201CC00000000020201D40000000279
+:101BC000020201DC00000002020201E4000000FF4A
+:101BD000020201EC000000FF0202010C000000C83C
+:101BE0000202011C00000002020201C80000000005
+:101BF000020201D000000000020201D80000000231
+:101C0000020201E000000002020201E8000000FF01
+:101C1000020201F0000000FF02020108000000C8FB
+:101C20000202011800000002020201C400000000CC
+:101C3000020201CC00000000020201D400000002F8
+:101C4000020201DC00000002020201E4000000FFC9
+:101C5000020201EC000000FF0202010C000000C8BB
+:101C60000202011C00000002020201C80000000084
+:101C7000020201D000000000020201D800000002B0
+:101C8000020201E000000002020201E8000000FF81
+:101C9000020201F0000000FF02020108000000C87B
+:101CA0000202011800000002020201C4000000004C
+:101CB000020201CC00000000020201D40000000278
+:101CC000020201DC00000002020201E4000000FF49
+:101CD000020201EC000000FF0202010C000000C83B
+:101CE0000202011C00000002020201C80000000004
+:101CF000020201D000000000020201D80000000230
+:101D0000020201E000000002020201E8000000FF00
+:101D1000020201F0000000FF02161000000000287F
+:101D20000316600800030C850316601C00040C8871
+:101D300003166038000D0C8C0416606C0000001354
+:101D4000031660B800020C99041660C00000003E43
+:101D5000021661B800000001041661BC0000001FFB
+:101D60000316623800040C9B011662480000000054
+:101D70000116624C000000000116625000000000D5
+:101D800001166254000000000116625800000000B5
+:101D90000116625C00000000011662600000000095
+:101DA0000116626400000000011662680000000075
+:101DB0000116626C00000000011662700000000055
+:101DC0000116627400000000011662780000000035
+:101DD0000116627C000000000A0000010000000102
+:101DE00002166000000003E80A0000010000000283
+:101DF000021660000000000A0A0000010000000452
+:101E000002166000000000010528040000870000A1
+:101E10000628076800130C9F042A000000004000F9
+:101E2000042B240000000040032A300000020CA113
+:101E3000032A400000100CA3032A840800080CB3F6
+:101E4000032A93C800040CBB032A96F000020CBFBF
+:101E5000042A96F800000006032A994000020CC1EB
+:101E6000022A9A2800000001032AC0C000100CC3F7
+:101E7000022B800000000000022B804000000018B0
+:101E8000022B80800000000C022B80C00000006646
+:101E9000022B83800007A120022B83C0000001F4E5
+:101EA000022B8BC0000000010A00000200000001AC
+:101EB000022B83000007A120022B8340000001F4C5
+:101EC0000A00000200000002022B830000001388B9
+:101ED000022B8340000000050A00000200000004FD
+:101EE000022B830000000138022B83400000000019
+:101EF0000A00000100000020022A9A2C00000000C5
+:101F0000052C000038390000052C80003B470E0FDF
+:101F1000052D00003C671CE1052D80000D892BFB81
+:101F2000062D9A804CB00CD30A000001000000027C
+:101F3000022B1480000000000A00000100000004D1
+:101F4000022B1480000000000128000000000000A7
+:101F50000128000400000000012800080000000023
+:101F60000128000C00000000012800100000000003
+:101F7000012800140000000003280020001A0CD5DE
+:101F8000032800A400020CEF022802240000000035
+:101F900002280234000000000228024C0000000069
+:101FA000022802E40000FFFF0828200000000800CB
+:101FB000042A500000000002042A50100000000211
+:101FC000042A502000000002042A503000000002C1
+:101FD000042A93E000000020042A94E00000000E90
+:101FE000032A951800020CF1042A95600000000EE7
+:101FF000032A959800020CF3042A95E00000000ED5
+:10200000032A961800020CF5042A96600000000EC0
+:10201000032A969800020CF7032A971000020CF985
+:10202000042A500800000002042A50180000000290
+:10203000042A502800000002042A50380000000240
+:10204000042A946000000020042A95200000000E5D
+:10205000032A955800020CFB042A95A00000000EEC
+:10206000032A95D800020CFD042A96200000000ED9
+:10207000032A965800020CFF042A96A00000000EC6
+:10208000032A96D800020D01032A971800020D03B7
+:10209000042A50480000000E032A972000100D0566
+:1020A000042A995000000002042AC0000000000227
+:1020B000042A50800000000E032A976000100D15BE
+:1020C000042A995800000002042AC00800000002F7
+:1020D000042A50B80000000E032A97A000100D2516
+:1020E000042A996000000002042AC01000000002C7
+:1020F000042A50F00000000E032A97E000100D356E
+:10210000042A996800000002042AC0180000000296
+:10211000042A51280000000E032A982000100D45C3
+:10212000042A997000000002042AC0200000000266
+:10213000042A51600000000E032A986000100D551B
+:10214000042A997800000002042AC0280000000236
+:10215000042A51980000000E032A98A000100D6573
+:10216000042A998000000002042AC0300000000206
+:10217000042A51D00000000E032A98E000100D75CB
+:10218000042A998800000002042AC03800000002D6
+:102190000400A0000000000C0400A0500000000299
+:1021A0000300A0EC00080D850300A18C00080D8D34
+:1021B0000200A45C00000C000200A61C000000034A
+:1021C0000300A06C00060D950400A084000000052B
+:1021D0000200A0980FE000000400A09C000000078F
+:1021E0000300A0B8000D0D9B0400A22C0000000409
+:1021F0000300A10C00060DA80400A12400000005A6
+:102200000200A1380FE000000400A13C000000071C
+:102210000300A158000D0DAE0400A23C0000000414
+:102220000200A030000000000200A0340000000006
+:102230000200A038000000000200A03C00000000E6
+:102240000200A040000000000200A04400000000C6
+:102250000200A048000000000200A04C00000000A6
+:10226000000000000000000000000000000000006E
+:10227000000000000000000000000000000000005E
+:10228000000000000000000000000000000000004E
+:102290000000000000000005000500080008000B19
+:1022A000000000000000000000000000000000002E
+:1022B000000000000000000000000000000000001E
+:1022C000000B001900000000000000000019001AB7
+:1022D000001A001B001B001C001C001D001D001E1E
+:1022E000001E001F001F00200020002100210028E8
+:1022F00000000000000000000000000000000000DE
+:1023000000000000000000000000000000000000CD
+:1023100000000000000000000028002E0000000067
+:1023200000000000000000000000000000000000AD
+:10233000000000000000000000000000000000009D
+:1023400000000000002E0049000000000000000016
+:10235000000000000000000000000000000000007D
+:10236000000000000000000000000000000000006D
+:10237000004900B4000000000000000000B400B9F3
+:1023800000B900BE00BE00C300C300C800C800CD35
+:1023900000CD00D200D200D700D700DC0000000042
+:1023A000000000000000000000000000000000002D
+:1023B000000000000000000000000000000000001D
+:1023C000000000000000000000DC00E00000000051
+:1023D00000000000000000000000000000000000FD
+:1023E00000000000000000000000000000000000ED
+:1023F0000000000000E000E7000000000000000016
+:1024000000000000000000000000000000000000CC
+:1024100000000000000000000000000000000000BC
+:1024200000000000000000000000000000E700F7CE
+:1024300000F70107010701170117012701270137DD
+:1024400001370147014701570157016700000000AC
+:10245000000000000000000000000000000000007C
+:10246000000000000000000000000000000000006C
+:1024700000000000000000000167016D0000000086
+:1024800000000000016D016E016E016F016F0170AF
+:1024900001700171017101720172017301730174A4
+:1024A000017401750175017801780185018501923A
+:1024B0000192019301930194019401950195019674
+:1024C0000196019701970198019801990199019A44
+:1024D000019A01A001A001A401A401A8000000002C
+:1024E00000000000000000000000000000000000EC
+:1024F00000000000000000000000000000000000DC
+:1025000000000000000000000000000000000000CB
+:1025100000000000000000000000000000000000BB
+:10252000000000000000000001A801BA0000000047
+:10253000000000000000000000000000000000009B
+:10254000000000000000000000000000000000008B
+:102550000000000001BA01C90000000000000000F6
+:10256000000000000000000000000000000000006B
+:10257000000000000000000000000000000000005B
+:1025800001C901CC000000000000000000000000B4
+:10259000000000000000000000000000000000003B
+:1025A00000000000000000000000000001CC01EC71
+:1025B000000000000000000000000000000000001B
+:1025C000000000000000000000000000000000000B
+:1025D000000000000000000001EC01EE000000001F
+:1025E00000000000000000000000000000000000EB
+:1025F00000000000000000000000000000000000DB
+:102600000000000001EE01FB0000000000000000DF
+:1026100001FB01FC01FC01FD01FD01FE01FE01FFCA
+:1026200001FF020002000201020102020202020393
+:10263000020302170217021A021A021D000000000C
+:10264000000000000000000000000000000000008A
+:10265000000000000000000000000000021D023821
+:10266000000000000000000000000000000000006A
+:10267000000000000000000000000000000000005A
+:1026800000000000000000000238026902690271C7
+:10269000027102790279027F027F02850285028B34
+:1026A000028B0291029102970297029D029D02A362
+:1026B00002A302A902A902B6000000000000000067
+:1026C00002B602B702B702B802B802B902B902BA3A
+:1026D00002BA02BB02BB02BC02BC02BD02BD02BE0A
+:1026E00002BE02BF00000000000000000000000069
+:1026F00000000000000000000000000000000000DA
+:1027000000000000000000000000000002BF02DB2B
+:1027100000000000000000000000000000000000B9
+:1027200000000000000000000000000000000000A9
+:10273000000000000000000002DB030A030A031F80
+:10274000031F033403340336033603380338033AD4
+:10275000033A033C033C033E033E03400340034271
+:10276000034203440344035600000000000000003D
+:102770000356035E035E03660366036E036E037611
+:102780000376037E037E03860386038E038E039601
+:102790000396039700000000000000000000000006
+:1027A0000000000000000000000000000000000029
+:1027B000000000000000000000000000039703B4C8
+:1027C0000000000000000000000000000000000009
+:1027D00000000000000000000000000000000000F9
+:1027E000000000000000000003B403E903E903F760
+:1027F00003F70405040504090409040D040D04117C
+:1028000004110415041504190419041D041D0421E0
+:10281000042104250425042B042B0431043104373E
+:1028200004370438043804390439043A043A043BC0
+:10283000043B043C043C043D043D043E043E043F90
+:102840000000000000000000000020000000400028
+:1028500000006000000080000000A0000000C00038
+:102860000000E00000010000000120000001400025
+:1028700000016000000180000001A0000001C00014
+:102880000001E00000020000000220000002400001
+:1028900000026000000280000002A0000002C000F0
+:1028A0000002E000000300000003200000034000DD
+:1028B00000036000000380000003A0000003C000CC
+:1028C0000003E000000400000004200000044000B9
+:1028D00000046000000480000004A0000004C000A8
+:1028E0000004E00000050000000520000005400095
+:1028F00000056000000580000005A0000005C00084
+:102900000005E00000060000000620000006400070
+:1029100000066000000680000006A0000006C0005F
+:102920000006E0000007000000072000000740004C
+:1029300000076000000780000007A0000007C0003B
+:102940000007E00000080000000820000008400028
+:1029500000086000000880000008A0000008C00017
+:102960000008E00000090000000920000009400004
+:1029700000096000000980000009A0000009C000F3
+:102980000009E000000A0000000A2000000A4000E0
+:10299000000A6000000A8000000AA000000AC000CF
+:1029A000000AE000000B0000000B2000000B4000BC
+:1029B000000B6000000B8000000BA000000BC000AB
+:1029C000000BE000000C0000000C2000000C400098
+:1029D000000C6000000C8000000CA000000CC00087
+:1029E000000CE000000D0000000D2000000D400074
+:1029F000000D6000000D8000000DA000000DC00063
+:102A0000000DE000000E0000000E2000000E40004F
+:102A1000000E6000000E8000000EA000000EC0003E
+:102A2000000EE000000F0000000F2000000F40002B
+:102A3000000F6000000F8000000FA000000FC0001A
+:102A4000000FE00000100000001020000010400007
+:102A500000106000001080000010A0000010C000F6
+:102A60000010E000001100000011200000114000E3
+:102A700000116000001180000011A0000011C000D2
+:102A80000011E000001200000012200000124000BF
+:102A900000126000001280000012A0000012C000AE
+:102AA0000012E0000013000000132000001340009B
+:102AB00000136000001380000013A0000013C0008A
+:102AC0000013E00000140000001420000014400077
+:102AD00000146000001480000014A0000014C00066
+:102AE0000014E00000150000001520000015400053
+:102AF00000156000001580000015A0000015C00042
+:102B00000015E0000016000000162000001640002E
+:102B100000166000001680000016A0000016C0001D
+:102B20000016E0000017000000172000001740000A
+:102B300000176000001780000017A0000017C000F9
+:102B40000017E000001800000018200000184000E6
+:102B500000186000001880000018A0000018C000D5
+:102B60000018E000001900000019200000194000C2
+:102B700000196000001980000019A0000019C000B1
+:102B80000019E000001A0000001A2000001A40009E
+:102B9000001A6000001A8000001AA000001AC0008D
+:102BA000001AE000001B0000001B2000001B40007A
+:102BB000001B6000001B8000001BA000001BC00069
+:102BC000001BE000001C0000001C2000001C400056
+:102BD000001C6000001C8000001CA000001CC00045
+:102BE000001CE000001D0000001D2000001D400032
+:102BF000001D6000001D8000001DA000001DC00021
+:102C0000001DE000001E0000001E2000001E40000D
+:102C1000001E6000001E8000001EA000001EC000FC
+:102C2000001EE000001F0000001F2000001F4000E9
+:102C3000001F6000001F8000001FA000001FC000D8
+:102C4000001FE000002000000020200000204000C5
+:102C500000206000002080000020A0000020C000B4
+:102C60000020E000002100000021200000214000A1
+:102C700000216000002180000021A0000021C00090
+:102C80000021E0000022000000222000002240007D
+:102C900000226000002280000022A0000022C0006C
+:102CA0000022E00000230000002320000023400059
+:102CB00000236000002380000023A0000023C00048
+:102CC0000023E00000240000002420000024400035
+:102CD00000246000002480000024A0000024C00024
+:102CE0000024E00000250000002520000025400011
+:102CF00000256000002580000025A0000025C00000
+:102D00000025E000002600000026200000264000EC
+:102D100000266000002680000026A0000026C000DB
+:102D20000026E000002700000027200000274000C8
+:102D300000276000002780000027A0000027C000B7
+:102D40000027E000002800000028200000284000A4
+:102D500000286000002880000028A0000028C00093
+:102D60000028E00000290000002920000029400080
+:102D700000296000002980000029A0000029C0006F
+:102D80000029E000002A0000002A2000002A40005C
+:102D9000002A6000002A8000002AA000002AC0004B
+:102DA000002AE000002B0000002B2000002B400038
+:102DB000002B6000002B8000002BA000002BC00027
+:102DC000002BE000002C0000002C2000002C400014
+:102DD000002C6000002C8000002CA000002CC00003
+:102DE000002CE000002D0000002D2000002D4000F0
+:102DF000002D6000002D8000002DA000002DC000DF
+:102E0000002DE000002E0000002E2000002E4000CB
+:102E1000002E6000002E8000002EA000002EC000BA
+:102E2000002EE000002F0000002F2000002F4000A7
+:102E3000002F6000002F8000002FA000002FC00096
+:102E4000002FE00000300000003020000030400083
+:102E500000306000003080000030A0000030C00072
+:102E60000030E0000031000000312000003140005F
+:102E700000316000003180000031A0000031C0004E
+:102E80000031E0000032000000322000003240003B
+:102E900000326000003280000032A0000032C0002A
+:102EA0000032E00000330000003320000033400017
+:102EB00000336000003380000033A0000033C00006
+:102EC0000033E000003400000034200000344000F3
+:102ED00000346000003480000034A0000034C000E2
+:102EE0000034E000003500000035200000354000CF
+:102EF00000356000003580000035A0000035C000BE
+:102F00000035E000003600000036200000364000AA
+:102F100000366000003680000036A0000036C00099
+:102F20000036E00000370000003720000037400086
+:102F300000376000003780000037A0000037C00075
+:102F40000037E00000380000003820000038400062
+:102F500000386000003880000038A0000038C00051
+:102F60000038E0000039000000392000003940003E
+:102F700000396000003980000039A0000039C0002D
+:102F80000039E000003A0000003A2000003A40001A
+:102F9000003A6000003A8000003AA000003AC00009
+:102FA000003AE000003B0000003B2000003B4000F6
+:102FB000003B6000003B8000003BA000003BC000E5
+:102FC000003BE000003C0000003C2000003C4000D2
+:102FD000003C6000003C8000003CA000003CC000C1
+:102FE000003CE000003D0000003D2000003D4000AE
+:102FF000003D6000003D8000003DA000003DC0009D
+:10300000003DE000003E0000003E2000003E400089
+:10301000003E6000003E8000003EA000003EC00078
+:10302000003EE000003F0000003F2000003F400065
+:10303000003F6000003F8000003FA000003FC00054
+:10304000003FE000003FE00100000000000001FF41
+:10305000000002000000000100000002000000006B
+:1030600000000008021500200215002008100000D2
+:103070000000003300000002000000000000000516
+:103080000000000500000000000000000000000239
+:103090000000000300000002000000010000000426
+:1030A0000000000200000002000000010000000219
+:1030B000000000200000004000000040000000036D
+:1030C0000000001800002000000040C000006180E7
+:1030D000000082400000A3000000C3C00000E480A4
+:1030E0000001054000012600000146C00001678084
+:1030F000000188400001A9000001C9C00001EA8068
+:1031000000020B4000022C0000024CC000026D8047
+:1031100000028E400002AF000002CFC00002F0802B
+:10312000000011400000000100000001000000014B
+:10313000000000010000000100000001000000018B
+:10314000000000010000000100000001000000017B
+:10315000000000010000000100000001000000016B
+:103160000003D0000000003D00000001000D000041
+:10317000000700D000028140000B8168000202209D
+:1031800000010240000F025000010340000C00004B
+:10319000000800C000028140000B8168000202208C
+:1031A0000001024000070250000202C000100000AF
+:1031B0000008010000028180000B81A8000202606B
+:1031C00000018280000E8298000803800000000049
+:1031D000000000000002800000090028000200B882
+:1031E000000100D8000000E8000000E8FFFFFFF346
+:1031F00001AFFFFF00000000000000000000000021
+:10320000000000000000000000000000FFFFFFF1D0
+:1032100000EFFFFF000000000000000000000000C1
+:10322000000000000001000000000000FFFFFFF6AA
+:10323000005FFFFF00000000000000000000000031
+:10324000000000000002000000000000FFFFF40684
+:103250001CBFFFFF0000000500000000000000147C
+:10326000000000000004000000000000FFFFFFF26B
+:10327000004FFFFF00000000000000000000000001
+:10328000000000000008000000000000FFFFFFFA3F
+:10329000002FFFFF00000000000000000000000001
+:1032A000000000000010000000000000FFFFFFF71A
+:1032B00001EFFFFF00000000000000000000000020
+:1032C000000000000020000000000000FFFFFFF5EC
+:1032D000002FFFFF000000000000000000000000C1
+:1032E000000000000040000000000000FFFFFFF3AE
+:1032F000018FFFFF00000000000000000000000040
+:10330000000000000000000000000000FFFFFFF1CF
+:10331000010FFFFF0000000000000000000000009F
+:10332000000000000001000000000000FFFFFFF6A9
+:10333000005FFFFF00000000000000000000000030
+:10334000000000000002000000000000FFFFF40683
+:103350001CBFFFFF0000000500000000000000147B
+:10336000000000000004000000000000FFFFFFF26A
+:10337000004FFFFF00000000000000000000000000
+:10338000000000000008000000000000FFFFFFFA3E
+:10339000002FFFFF00000000000000000000000000
+:1033A000000000000010000000000000FFFFFFF719
+:1033B00000EFFFFF00000000000000000000000020
+:1033C000000000000020000000000000FFFFFFF5EB
+:1033D000004FFFFF000000000000000000000000A0
+:1033E000000000000040000000000000FFFFFFFFA1
+:1033F00000CFFFFF0000000000000000000000CC34
+:10340000000000000000000000000000FFFFFFFFC0
+:1034100000CFFFFF0000000000000000000000CC13
+:10342000000000000001000000000000FFFFFFFF9F
+:1034300000CFFFFF0000000000000000000000CCF3
+:10344000000000000002000000000000FFFFFFFF7E
+:1034500000CFFFFF0000000000000000000000CCD3
+:10346000000000000004000000000000FFFFFFFF5C
+:1034700000CFFFFF0000000000000000000000CCB3
+:10348000000000000008000000000000FFFFFFFF38
+:1034900000CFFFFF0000000000000000000000CC93
+:1034A000000000000010000000000000FFFFFFFF10
+:1034B00000CFFFFF0000000000000000000000CC73
+:1034C000000000000020000000000000FFFFFFFFE0
+:1034D00000CFFFFF0000000000000000000000CC53
+:1034E000000000000040000000000000FFFFFFF3AC
+:1034F000020FFFFF000000000000000000000000BD
+:10350000000000000000000000000000FFFFFFF1CD
+:10351000010FFFFF0000000000000000000000009D
+:10352000000000000001000000000000FFFFFFF6A7
+:10353000005FFFFF0000000000000000000000002E
+:10354000000000000002000000000000FFFFF40681
+:103550001CBFFFFF00000005000000000000001479
+:10356000000000000004000000000000FFFFFFF268
+:10357000004FFFFF000000000000000000000000FE
+:10358000000000000008000000000000FFFFFF8AAC
+:10359000042FFFFF000000000000000000000000FA
+:1035A000000000000010000000000000FFFFFF9777
+:1035B00005CFFFFF00000000000000000000000039
+:1035C000000000000020000000000000FFFFFFF5E9
+:1035D000010FFFFF000000000000000000000000DD
+:1035E000000000000040000000000000FFFFFFF3AB
+:1035F000000FFFFF000000000000000000000000BE
+:10360000000000000000000000000000FFFFFFF1CC
+:10361000000FFFFF0000000000000000000000009D
+:10362000000000000001000000000000FFFFFFF6A6
+:10363000005FFFFF0000000000000000000000002D
+:10364000000000000002000000000000FFFFFF0675
+:103650001CBFFFFF0000000000000000000000147D
+:10366000000000000004000000000000FFFFFFF267
+:10367000004FFFFF000000000000000000000000FD
+:10368000000000000008000000000000FFFFFFFA3B
+:10369000002FFFFF000000000000000000000000FD
+:1036A000000000000010000000000000FFFFFFF716
+:1036B000000FFFFF000000000000000000000000FD
+:1036C000000000000020000000000000FFFFFFFFDE
+:1036D00000CFFFFF0000000000000000000000CC51
+:1036E000000000000040000000000000FFFFFFFF9E
+:1036F00000CFFFFF0000000000000000000000CC31
+:10370000000000000000000000000000FFFFFFFFBD
+:1037100000CFFFFF0000000000000000000000CC10
+:10372000000000000001000000000000FFFFFFFF9C
+:1037300000CFFFFF0000000000000000000000CCF0
+:10374000000000000002000000000000FFFFFFFF7B
+:1037500000CFFFFF0000000000000000000000CCD0
+:10376000000000000004000000000000FFFFFFFF59
+:1037700000CFFFFF0000000000000000000000CCB0
+:10378000000000000008000000000000FFFFFFFF35
+:1037900000CFFFFF0000000000000000000000CC90
+:1037A000000000000010000000000000FFFFFFFF0D
+:1037B00000CFFFFF0000000000000000000000CC70
+:1037C000000000000020000000000000FFFFFFFFDD
+:1037D00000CFFFFF0000000000000000000000CC50
+:1037E000000000000040000000000000FFFFFFFF9D
+:1037F00000CFFFFF0000000000000000000000CC30
+:10380000000000000000000000000000FFFFFFFFBC
+:1038100000CFFFFF0000000000000000000000CC0F
+:10382000000000000001000000000000FFFFFFFF9B
+:1038300000CFFFFF0000000000000000000000CCEF
+:10384000000000000002000000000000FFFFFFFF7A
+:1038500000CFFFFF0000000000000000000000CCCF
+:10386000000000000004000000000000FFFFFFFF58
+:1038700000CFFFFF0000000000000000000000CCAF
+:10388000000000000008000000000000FFFFFFFF34
+:1038900000CFFFFF0000000000000000000000CC8F
+:1038A000000000000010000000000000FFFFFFFF0C
+:1038B00000CFFFFF0000000000000000000000CC6F
+:1038C000000000000020000000000000FFFFFFFFDC
+:1038D00000CFFFFF0000000000000000000000CC4F
+:1038E000000000000040000000000000FFFFFFFF9C
+:1038F00000CFFFFF0000000000000000000000CC2F
+:10390000000000000000000000000000FFFFFFFFBB
+:1039100000CFFFFF0000000000000000000000CC0E
+:10392000000000000001000000000000FFFFFFFF9A
+:1039300000CFFFFF0000000000000000000000CCEE
+:10394000000000000002000000000000FFFFFFFF79
+:1039500000CFFFFF0000000000000000000000CCCE
+:10396000000000000004000000000000FFFFFFFF57
+:1039700000CFFFFF0000000000000000000000CCAE
+:10398000000000000008000000000000FFFFFFFF33
+:1039900000CFFFFF0000000000000000000000CC8E
+:1039A000000000000010000000000000FFFFFFFF0B
+:1039B00000CFFFFF0000000000000000000000CC6E
+:1039C000000000000020000000000000FFFFFFFFDB
+:1039D00000CFFFFF0000000000000000000000CC4E
+:1039E0000000000000400000000000000000020095
+:1039F00000003DFF00000211000002000000020470
+:103A00000000FFFF0000FFFF0000FFFF0000FFFFBE
+:103A10000000002000000021000000220000002320
+:103A20000000002400000025000000260000002700
+:103A300000000028000000290000002A0000002BE0
+:103A40000000002C0000002D0000002E0000002FC0
+:103A50000000001000000001000000010000000153
+:103A60000000000100000001000000010000000152
+:103A70000000000100000001000000010000000142
+:103A80000000000100000001000000010000000132
+:103A9000000000010000000107FFFFFF0000003FE1
+:103AA00007FFFFFF0000000F00007FF800007FF815
+:103AB0000000FF00000000000000FF000000000008
+:103AC0000000FF00000000000000FF0000000000F8
+:103AD0000000FF00000000000000FF0000000000E8
+:103AE0000000FF00000000000000FF0000000000D8
+:103AF0000000FF1C0FFFFFFF0000FF1C0FFFFFFF78
+:103B00000000FF1C0FFFFFFF0000FF1C0FFFFFFF67
+:103B10000000FF1C0FFFFFFF0000FF1C0FFFFFFF57
+:103B20000000FF1C0FFFFFFF0000FF1C0FFFFFFF47
+:103B30000000FF1C0FFFFFFF0000FF1C0FFFFFFF37
+:103B40000000FF1C0FFFFFFF0000FF1C0FFFFFFF27
+:103B50000000FF1C0FFFFFFF0000FF1C0FFFFFFF17
+:103B60000000FF1C0FFFFFFF0000FF1C0FFFFFFF07
+:103B70000000FF1C0FFFFFFF0000FF1C0FFFFFFFF7
+:103B80000000FF1C0FFFFFFF0000FF1C0FFFFFFFE7
+:103B90000000FF1C0FFFFFFF0000FF1C0FFFFFFFD7
+:103BA0000000FF1C0FFFFFFF0000FF1C0FFFFFFFC7
+:103BB0000000FF1C0FFFFFFF0000FF1C0FFFFFFFB7
+:103BC0000000FF1C0FFFFFFF0000FF1C0FFFFFFFA7
+:103BD0000000FF1C0FFFFFFF0000FF1C0FFFFFFF97
+:103BE0000000FF1C0FFFFFFF0000FF1C0FFFFFFF87
+:103BF0000000FF1C0FFFFFFF0000FF1C0FFFFFFF77
+:103C00000000FF1C0FFFFFFF0000FF1C0FFFFFFF66
+:103C10000000FF1C0FFFFFFF0000FF1C0FFFFFFF56
+:103C20000000FF1C0FFFFFFF0000FF1C0FFFFFFF46
+:103C30000000FF1C0FFFFFFF0000FF1C0FFFFFFF36
+:103C40000000FF1C0FFFFFFF0000FF1C0FFFFFFF26
+:103C50000000FF1C0FFFFFFF0000FF1C0FFFFFFF16
+:103C60000000FF1C0FFFFFFF0000FF1C0FFFFFFF06
+:103C70000000FF1C0FFFFFFF0000FF1C0FFFFFFFF6
+:103C80000000FF1C0FFFFFFF0000FF1C0FFFFFFFE6
+:103C90000000FF1C0FFFFFFF0000FF1C0FFFFFFFD6
+:103CA0000000FF1C0FFFFFFF0000FF1C0FFFFFFFC6
+:103CB0000000FF1C0FFFFFFF0000FF1C0FFFFFFFB6
+:103CC0000000FF1C0FFFFFFF0000FF1C0FFFFFFFA6
+:103CD0000000FF1C0FFFFFFF0000FF1C0FFFFFFF96
+:103CE0000000FF1C0FFFFFFF0000FF1C0FFFFFFF86
+:103CF00000000002000015000000000100000002AA
+:103D000000000003000000000000000400000001AB
+:103D1000000000000000000100000004000000009E
+:103D2000000000010000000300000000000000018E
+:103D3000000000040000000000000001000000037B
+:103D4000000000000000000100000004000000006E
+:103D5000000000040000000300000000000000005C
+:103D600000003FFF000003FF000000000000000112
+:103D70000000000100000001007C100400000004AD
+:103D80000000000200000090000000900080009001
+:103D9000081000000000008A000000800000008180
+:103DA0000000008000000006000007D00000076C43
+:103DB000071D291100000000009C042400000000E1
+:103DC00000000001000000010000000100000001EF
+:103DD0000000000100007FFF000000FF000000FF66
+:103DE000000000FF000000FF0000007F000000FF57
+:103DF000000000FF000000FF0000003E0000000087
+:103E00000000003F0000003F0000003F0000003FB6
+:103E10000000003F0000003F0000003F0000000FD6
+:103E200000000000121700002217000032170000E7
+:103E300012150000221500003215000002100000CB
+:103E400000100000101000002010000030100000D2
+:103E500000100000121400002214000032140000B0
+:103E600000E38340FFFFFFFFFFFFFFFFFFFFFFFFB8
+:103E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52
+:103E8000FFFFFFFFF0005000F0001000FFFFFFFFFA
+:103E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32
+:103EA000FFFFFFFFFF809000FFFFFFFFFFFFFFFF0F
+:103EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12
+:103EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02
+:103ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2
+:103EE000FFFFFFFF00003C10000000010000000089
+:103EF00000000008000000080000000200000004AC
+:103F00000000000500000004000000400000180848
+:103F10000000080300000803000000400000000348
+:103F2000000008030000080300000803000100036C
+:103F30000000080300000803000000030000000365
+:103F40000000000300000003000000030000000365
+:103F50000000000300000003000000030000000355
+:103F60000000000300000003000000030000000345
+:103F700000000003000024030000002F00000009DF
+:103F80000000001900000184000001830000030606
+:103F900000000019000000060000030600000306F0
+:103FA0000000030600000C86000003060000030664
+:103FB00000000006000000060000000600000006E9
+:103FC00000000006000000060000000600000006D9
+:103FD00000000006000000060000000600000006C9
+:103FE00000000006000000060000000600000306B6
+:103FF0000000001300000006000010040000100480
+:104000000010644000106440000000000000000048
+:104010000000000000000000000020000000000080
+:10402000000000000000000000000000040020006C
+:104030000000000000000000000000000000000080
+:10404000000020000000007C0000003D0000003F58
+:104050000000009C00000006000000050000000AAF
+:1040600000000005000001400000014000000000C9
+:1040700000000000000000C00000013F00007FFFC2
+:1040800000000048000000480000000000000000A0
+:1040900000000048000000040000000400000004CC
+:1040A0000000000400000004000000040000000400
+:1040B0000000000400000004000000090000000BE4
+:1040C0000000000A00000004000000090000000BCE
+:1040D0000000000A000000010000000100000001D3
+:1040E00000000001000000010000000100000001CC
+:1040F00000000001000000010000000100000001BC
+:104100000000000100000004000000090000000B96
+:104110000000000A00000001000000010000000192
+:10412000000000010000000100000001000000018B
+:10413000000000010000000100000001000000017B
+:104140000000000100000004000000090000000B56
+:104150000000000A0000000000000000000008004D
+:1041600000000200000001FF000004000000000049
+:10417000000000001E491E491E491E490E490E49F5
+:104180000E490E49FFFFFFFF00000000000025E47C
+:1041900000008000000000130FFF0FFF0000000070
+:1041A000000000000FFF0FFF1000100010001000B3
+:1041B000200020002000200080008000800080007F
+:1041C00040004000400040000000000000000001EE
+:1041D0000101010101200101200101010101100182
+:1041E0000101010101200101200101010101100172
+:1041F0002001010101011001010101010120010162
+:104200002001010101011001010101010120010151
+:104210000101010101200101200101010101100141
+:104220000101010101200101200101010101100131
+:104230000101010101200101200101010101100121
+:104240000101010101200101200101010101100111
+:1042500000000004000000090000000B0000000A3C
+:1042600000000004000000090000000B0000000A2C
+:10427000000000010000000100000001000000013A
+:10428000000000010000000100000001000000012A
+:10429000000000010000000100000001000000011A
+:1042A00000000004000000090000000B0000000AEC
+:1042B00000000001000000010000000100000001FA
+:1042C00000000001000000010000000100000001EA
+:1042D00000000001000000010000000100000001DA
+:1042E00000000004000000090000000B0000000AAC
+:1042F0001E491E491E491E490E490E490E490E49C6
+:10430000FFFFFFFF000000000FFF0FFF0000000095
+:10431000000000000FFF0FFF100010001000100041
+:10432000200020002000200080008000800080000D
+:10433000400040004000400000000000000000027B
+:10434000000000010000000300000004000000065F
+:104350000000000500000007000001230000012309
+:1043600000000123000001230000012300000123BD
+:1043700000000123000001230000012300000123AD
+:10438000000001230000012300000123000001239D
+:10439000000001230000012300000123000001238D
+:1043A0000000012300000123000000200000003273
+:1043B00000000007000000070000000000000008E7
+:1043C0000215002002150020000000300810000037
+:1043D0000000003300000030000000310000000247
+:1043E00000000005000000060000000200000002BE
+:1043F00000000000000000050000000200000002B4
+:1044000000000002000000010000000600000001A2
+:1044100000000002000000400000004000000020FA
+:10442000000000130000002000010000000204C092
+:104430000003098000040E4000051300000617C0A9
+:1044400000071C800008214000092600000A2AC03D
+:10445000000B2F80000C3440000D3900000E3DC0D1
+:10446000000F42800010474000114C00001250C065
+:104470000013558000145A4000155F00001663C0F9
+:104480000017688000186D4000197200001A76C08D
+:10449000001B7B80001C8040001D8500001E89C021
+:1044A000001F8E800000934000000001000000010A
+:1044B00000000001000000010000000100000001F8
+:1044C00000000001000000010000000100000001E8
+:1044D00000000001000000010000000100000001D8
+:1044E0000000000100000001000000080000000CB6
+:1044F00000000010000000010000000100000001A9
+:104500000000021100000200000002040000021975
+:104510000000FFFF0000FFFF0000FFFF0000FFFFA3
+:1045200007FFFFFF0000003F07FFFFFF0000000F35
+:1045300000007FF800007FF800000000000000018C
+:1045400000201001000000000100900000000100A8
+:10455000000000010000000000000000140AFF003D
+:1045600000009002000000000000000000000000B9
+:1045700000009004000000000000000000000000A7
+:104580000000900600000000000000000000000095
+:104590000000900800000000000000000000000083
+:1045A0000000900A00000000000000000000000071
+:1045B0000000900C0000000000000000000000005F
+:1045C0000000900E0000000000000000000000004D
+:1045D000000090100000000000000000000000003B
+:1045E0000000901200000000000000000000000029
+:1045F0000000901400000000000000000000000017
+:104600000000901600000000000000000000000004
+:1046100000009018000000000000000000000000F2
+:104620000000901A000000000000000000000000E0
+:104630000000901C000000000000000000000000CE
+:104640000000901E000000000000000000000000BC
+:1046500000009020000000000000000000000000AA
+:104660000000902200000000000000000000000098
+:104670000000902400000000000000000000000086
+:104680000000902600000000000000000000000074
+:104690000000902800000000000000000000000062
+:1046A0000000902A00000000000000000000000050
+:1046B0000000902C0000000000000000000000003E
+:1046C0000000902E0000000000000000000000002C
+:1046D000000090300000000000000000000000001A
+:1046E0000000903200000000000000000000000008
+:1046F00000009034000000000000000000000000F6
+:1047000000009036000000000000000000000000E3
+:1047100000009038000000000000000000000000D1
+:104720000000903A000000000000000000000000BF
+:104730000000903C000000000000000000000000AD
+:104740000000903E0000000000000000000000009B
+:104750000000904000000000000000000000000089
+:104760000000904200000000000000000000000077
+:104770000000904400000000000000000000000065
+:104780000000904600000000000000000000000053
+:104790000000904800000000000000000000000041
+:1047A0000000904A0000000000000000000000002F
+:1047B0000000904C0000000000000000000000001D
+:1047C0000000904E0000000000000000000000000B
+:1047D00000009050000000000000000000000000F9
+:1047E00000009052000000000000000000000000E7
+:1047F00000009054000000000000000000000000D5
+:1048000000009056000000000000000000000000C2
+:1048100000009058000000000000000000000000B0
+:104820000000905A0000000000000000000000009E
+:104830000000905C0000000000000000000000008C
+:104840000000905E0000000000000000000000007A
+:104850000000906000000000000000000000000068
+:104860000000906200000000000000000000000056
+:104870000000906400000000000000000000000044
+:104880000000906600000000000000000000000032
+:104890000000906800000000000000000000000020
+:1048A0000000906A0000000000000000000000000E
+:1048B0000000906C000000000000000000000000FC
+:1048C0000000906E000000000000000000000000EA
+:1048D00000009070000000000000000000000000D8
+:1048E00000009072000000000000000000000000C6
+:1048F00000009074000000000000000000000000B4
+:1049000000009076000000000000000000000000A1
+:10491000000090780000000000000000000000008F
+:104920000000907A0000000000000000000000007D
+:104930000000907C0000000000000000000000006B
+:104940000000907E00000000000000000000000059
+:104950000000908000000000000000000000000047
+:104960000000908200000000000000000000000035
+:104970000000908400000000000000000000000023
+:104980000000908600000000000000000000000011
+:1049900000009088000000000000000000000000FF
+:1049A0000000908A000000000000000000000000ED
+:1049B0000000908C000000000000000000000000DB
+:1049C0000000908E000000000000000000000000C9
+:1049D00000009090000000000000000000000000B7
+:1049E00000009092000000000000000000000000A5
+:1049F0000000909400000000000000000000000093
+:104A00000000909600000000000000000000000080
+:104A1000000090980000000000000000000000006E
+:104A20000000909A0000000000000000000000005C
+:104A30000000909C0000000000000000000000004A
+:104A40000000909E00000000000000000000000038
+:104A5000000090A000000000000000000000000026
+:104A6000000090A200000000000000000000000014
+:104A7000000090A400000000000000000000000002
+:104A8000000090A6000000000000000000000000F0
+:104A9000000090A8000000000000000000000000DE
+:104AA000000090AA000000000000000000000000CC
+:104AB000000090AC000000000000000000000000BA
+:104AC000000090AE000000000000000000000000A8
+:104AD000000090B000000000000000000000000096
+:104AE000000090B200000000000000000000000084
+:104AF000000090B400000000000000000000000072
+:104B0000000090B60000000000000000000000005F
+:104B1000000090B80000000000000000000000004D
+:104B2000000090BA0000000000000000000000003B
+:104B3000000090BC00000000000000000000000029
+:104B4000000090BE00000000000000000000000017
+:104B5000000090C000000000000000000000000005
+:104B6000000090C2000000000000000000000000F3
+:104B7000000090C4000000000000000000000000E1
+:104B8000000090C6000000000000000000000000CF
+:104B9000000090C8000000000000000000000000BD
+:104BA000000090CA000000000000000000000000AB
+:104BB000000090CC00000000000000000000000099
+:104BC000000090CE00000000000000000000000087
+:104BD000000090D000000000000000000000000075
+:104BE000000090D200000000000000000000000063
+:104BF000000090D400000000000000000000000051
+:104C0000000090D60000000000000000000000003E
+:104C1000000090D80000000000000000000000002C
+:104C2000000090DA0000000000000000000000001A
+:104C3000000090DC00000000000000000000000008
+:104C4000000090DE000000000000000000000000F6
+:104C5000000090E0000000000000000000000000E4
+:104C6000000090E2000000000000000000000000D2
+:104C7000000090E4000000000000000000000000C0
+:104C8000000090E6000000000000000000000000AE
+:104C9000000090E80000000000000000000000009C
+:104CA000000090EA0000000000000000000000008A
+:104CB000000090EC00000000000000000000000078
+:104CC000000090EE00000000000000000000000066
+:104CD000000090F000000000000000000000000054
+:104CE000000090F200000000000000000000000042
+:104CF000000090F400000000000000000000000030
+:104D0000000090F60000000000000000000000001D
+:104D1000000090F80000000000000000000000000B
+:104D2000000090FA000000000000000000000000F9
+:104D3000000090FC000000000000000000000000E7
+:104D4000000090FE000000000000000000000000D5
+:104D500000009100000000000000000000000000C2
+:104D600000009102000000000000000000000000B0
+:104D7000000091040000000000000000000000009E
+:104D8000000091060000000000000000000000008C
+:104D9000000091080000000000000000000000007A
+:104DA0000000910A00000000000000000000000068
+:104DB0000000910C00000000000000000000000056
+:104DC0000000910E00000000000000000000000044
+:104DD0000000911000000000000000000000000032
+:104DE0000000911200000000000000000000000020
+:104DF000000091140000000000000000000000000E
+:104E000000009116000000000000000000000000FB
+:104E100000009118000000000000000000000000E9
+:104E20000000911A000000000000000000000000D7
+:104E30000000911C000000000000000000000000C5
+:104E40000000911E000000000000000000000000B3
+:104E500000009120000000000000000000000000A1
+:104E6000000091220000000000000000000000008F
+:104E7000000091240000000000000000000000007D
+:104E8000000091260000000000000000000000006B
+:104E90000000912800000000000000000000000059
+:104EA0000000912A00000000000000000000000047
+:104EB0000000912C00000000000000000000000035
+:104EC0000000912E00000000000000000000000023
+:104ED0000000913000000000000000000000000011
+:104EE00000009132000000000000000000000000FF
+:104EF00000009134000000000000000000000000ED
+:104F000000009136000000000000000000000000DA
+:104F100000009138000000000000000000000000C8
+:104F20000000913A000000000000000000000000B6
+:104F30000000913C000000000000000000000000A4
+:104F40000000913E00000000000000000000000092
+:104F50000000914000000000000000000000000080
+:104F6000000091420000000000000000000000006E
+:104F7000000091440000000000000000000000005C
+:104F8000000091460000000000000000000000004A
+:104F90000000914800000000000000000000000038
+:104FA0000000914A00000000000000000000000026
+:104FB0000000914C00000000000000000000000014
+:104FC0000000914E00000000000000000000000002
+:104FD00000009150000000000000000000000000F0
+:104FE00000009152000000000000000000000000DE
+:104FF00000009154000000000000000000000000CC
+:1050000000009156000000000000000000000000B9
+:1050100000009158000000000000000000000000A7
+:105020000000915A00000000000000000000000095
+:105030000000915C00000000000000000000000083
+:105040000000915E00000000000000000000000071
+:10505000000091600000000000000000000000005F
+:10506000000091620000000000000000000000004D
+:10507000000091640000000000000000000000003B
+:105080000000916600000000000000000000000029
+:105090000000916800000000000000000000000017
+:1050A0000000916A00000000000000000000000005
+:1050B0000000916C000000000000000000000000F3
+:1050C0000000916E000000000000000000000000E1
+:1050D00000009170000000000000000000000000CF
+:1050E00000009172000000000000000000000000BD
+:1050F00000009174000000000000000000000000AB
+:105100000000917600000000000000000000000098
+:105110000000917800000000000000000000000086
+:105120000000917A00000000000000000000000074
+:105130000000917C00000000000000000000000062
+:105140000000917E00000000000000000000000050
+:10515000000091800000000000000000000000003E
+:10516000000091820000000000000000000000002C
+:10517000000091840000000000000000000000001A
+:105180000000918600000000000000000000000008
+:1051900000009188000000000000000000000000F6
+:1051A0000000918A000000000000000000000000E4
+:1051B0000000918C000000000000000000000000D2
+:1051C0000000918E000000000000000000000000C0
+:1051D00000009190000000000000000000000000AE
+:1051E000000091920000000000000000000000009C
+:1051F000000091940000000000000000000000008A
+:105200000000919600000000000000000000000077
+:105210000000919800000000000000000000000065
+:105220000000919A00000000000000000000000053
+:105230000000919C00000000000000000000000041
+:105240000000919E0000000000000000000000002F
+:10525000000091A00000000000000000000000001D
+:10526000000091A20000000000000000000000000B
+:10527000000091A4000000000000000000000000F9
+:10528000000091A6000000000000000000000000E7
+:10529000000091A8000000000000000000000000D5
+:1052A000000091AA000000000000000000000000C3
+:1052B000000091AC000000000000000000000000B1
+:1052C000000091AE0000000000000000000000009F
+:1052D000000091B00000000000000000000000008D
+:1052E000000091B20000000000000000000000007B
+:1052F000000091B400000000000000000000000069
+:10530000000091B600000000000000000000000056
+:10531000000091B800000000000000000000000044
+:10532000000091BA00000000000000000000000032
+:10533000000091BC00000000000000000000000020
+:10534000000091BE0000000000000000000000000E
+:10535000000091C0000000000000000000000000FC
+:10536000000091C2000000000000000000000000EA
+:10537000000091C4000000000000000000000000D8
+:10538000000091C6000000000000000000000000C6
+:10539000000091C8000000000000000000000000B4
+:1053A000000091CA000000000000000000000000A2
+:1053B000000091CC00000000000000000000000090
+:1053C000000091CE0000000000000000000000007E
+:1053D000000091D00000000000000000000000006C
+:1053E000000091D20000000000000000000000005A
+:1053F000000091D400000000000000000000000048
+:10540000000091D600000000000000000000000035
+:10541000000091D800000000000000000000000023
+:10542000000091DA00000000000000000000000011
+:10543000000091DC000000000000000000000000FF
+:10544000000091DE000000000000000000000000ED
+:10545000000091E0000000000000000000000000DB
+:10546000000091E2000000000000000000000000C9
+:10547000000091E4000000000000000000000000B7
+:10548000000091E6000000000000000000000000A5
+:10549000000091E800000000000000000000000093
+:1054A000000091EA00000000000000000000000081
+:1054B000000091EC0000000000000000000000006F
+:1054C000000091EE0000000000000000000000005D
+:1054D000000091F00000000000000000000000004B
+:1054E000000091F200000000000000000000000039
+:1054F000000091F400000000000000000000000027
+:10550000000091F600000000000000000000000014
+:10551000000091F800000000000000000000000002
+:10552000000091FA000000000000000000000000F0
+:10553000000091FC000000000000000000000000DE
+:10554000000091FE0000FF00000000000000FF00CE
+:10555000000000000000FF00000000000000FF004D
+:10556000000000000000FF00000000000000FF003D
+:10557000000000000000FF00000000000000FF002D
+:105580000000000000000002000015000000000103
+:105590000000000200000003000000000000000402
+:1055A00000000001000000000000000100000004F5
+:1055B00000000000000000010000000300000000E7
+:1055C00000000001000000040000000000000001D5
+:1055D00000000003000000000000000100000004C3
+:1055E00000000000000000040000000300000000B4
+:1055F0000000000000003FFF000003FF0000000368
+:1056000000BEBC20000000000000000500000003F8
+:1056100000BEBC20000000000000000500000003E8
+:1056200000BEBC20000000000000000500000003D8
+:1056300000BEBC20000000000000000500000003C8
+:1056400000BEBC20000000000000000500000003B8
+:1056500000BEBC20000000000000000500000003A8
+:1056600000BEBC2000000000000000050000000398
+:1056700000BEBC2000000000000000050000000D7E
+:105680000000000C000000000000001002150020C7
+:105690000215002000000030081000000000003358
+:1056A0000000003000000031000000020000000493
+:1056B00000000000000000020000000200000000E6
+:1056C00000000002000000070000000200000002CD
+:1056D00000000001000000030000000100000002C3
+:1056E0000000004000000040000000040000002016
+:1056F0000000000F0000001B00008000000103C03C
+:105700000001878000020B4000028F00000312C0DE
+:105710000003968000041A4000049E00000521C08A
+:105720000005A580000629400006AD00000730C036
+:105730000007B480000838400008BC0000093FC0E2
+:105740000009C380000A4740000ACB00000B4EC08E
+:10575000000BD280000C5640000CDA00000D5DC03A
+:105760000000618000000001000000010000000155
+:105770000000000100000001000000010000000125
+:105780000000000100000001000000010000000115
+:105790000000000100000001000000010000000105
+:1057A00000000001000000010000101100001000C6
+:1057B00000001004000010210000FFFF0000FFFFA8
+:1057C0000000FFFF0000FFFF000000460000001087
+:1057D00000000000000000000000001800000001B0
+:1057E00000000000000000000000000000000001B8
+:1057F00007FFFFFF0000003F07FFFFFF0000000F53
+:1058000000007FF800007FF8000019000000000091
+:10581000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98
+:10582000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88
+:105830000000FF00000000000000FF00000000006A
+:105840000000FF00000000000000FF00000000005A
+:105850000000FF00000000000000FF00000000004A
+:105860000000FF00000000000000FF00000000003A
+:10587000000000020000150000000001000000020E
+:105880000000000300000000000000040000000110
+:105890000000000000000001000000040000000003
+:1058A00000000001000000030000000000000001F3
+:1058B00000000004000000000000000100000003E0
+:1058C00000000000000000010000000400000000D3
+:1058D00000000004000000030000000000000000C1
+:1058E00000003FFF000003FF00000000039387005B
+:1058F000000000000000000000000000039387008B
+:1059000000000000000000000000000F0000000781
+:10591000000000000000000E031500200315002009
+:1059200001000030081000000000003300000030CB
+:10593000000000310000000300000006000000032A
+:105940000000000300000002000000000000000250
+:10595000000000000000000600000004000000023B
+:10596000000000020000000100000004000000012F
+:1059700000000002000000400000004000000004A1
+:1059800000000020000000020000002000001000C5
+:105990000000208000003100000041800000520023
+:1059A000000062800000730000008380000094000B
+:1059B0000000A4800000B5000000C5800000D600F3
+:1059C0000000E6800000F7000001078000011800D9
+:1059D00000012880000139000001498000015A00BF
+:1059E00000016A8000017B0000018B8000019C00A7
+:1059F0000001AC800001BD000001CD800001DE008F
+:105A00000001EE800001FF0000000F800000000197
+:105A10000000000100000001000000010000000182
+:105A20000000000100000001000000010000000172
+:105A30000000000100000001000000010000000162
+:105A40000000000100000001000000010000000152
+:105A5000000000010000000100000001000012240D
+:105A600000001210000012140000FFFF0000FFFFF2
+:105A70000000FFFF0000FFFF0000002000000020EA
+:105A800000000000000000000000002300000024CF
+:105A9000000000250000002600000027000000296B
+:105AA0000000002A0000002B0000002C0000000174
+:105AB0000000000107FFFFFF0000003F07FFFFFF9E
+:105AC0000000000F00007FF800007FF800000000D9
+:105AD00000000001CCCC0201CCCCCCCCCCCC02015F
+:105AE000CCCCCCCCCCCC0201CCCCCCCCCCCC020120
+:105AF000CCCCCCCCCCCC0201CCCCCCCCCCCC020110
+:105B0000CCCCCCCCCCCC0201CCCCCCCCCCCC0201FF
+:105B1000CCCCCCCCFFFFFFFFFFFFFFFFFFFFFFFF61
+:105B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85
+:105B3000FFFFFFFF0000000000010001001E0C0736
+:105B4000CCCCCCC510000000000028AD7058103C33
+:105B5000000000000000FF00000000000000FF0047
+:105B6000000000000000FF00000000000000FF0037
+:105B7000000000000000FF00000000000000FF0027
+:105B8000000000000000FF00000000000000FF0017
+:105B900000000000000000020000150000000001ED
+:105BA00000000002000000030000000000000004EC
+:105BB00000000001000000000000000100000004DF
+:105BC00000000000000000010000000300000000D1
+:105BD00000000001000000040000000000000001BF
+:105BE00000000003000000000000000100000004AD
+:105BF000000000000000000400000003000000009E
+:105C00000000000000003FFF000003FF002625A069
+:105C100000000000002625A000000000002625A0AE
+:105C200000000000002625A000000000000E00007B
+:105C3000011600D6002625A000000000002625A0A1
+:105C400000000000002625A000000000002625A07E
+:105C50000000000000720000012300F30000FFFFBD
+:105C6000000000000000FFFF000000000000FFFF38
+:105C7000000000000000FFFF000000000000FFFF28
+:105C8000000000000000FFFF000000000000000016
+:105C9000000000000000FFFF000000000000FFFF08
+:105CA000000000000000FFFF000000000000FFFFF8
+:105CB000000000000000FFFF000000000000FFFFE8
+:105CC000000000000000FFFF0000000000000000D6
+:105CD000000000000000FFFF000000000000FFFFC8
+:105CE000000000000000FFFF000000000000FFFFB8
+:105CF000000000000000FFFF000000000000FFFFA8
+:105D0000000000000000FFFF000000000000000095
+:105D1000000000000000FFFF000000000000FFFF87
+:105D2000000000000000FFFF000000000000FFFF77
+:105D3000000000000000FFFF000000000000FFFF67
+:105D4000000000000000FFFF000000000000000055
+:105D5000000000000000FFFF000000000000FFFF47
+:105D6000000000000000FFFF000000000000FFFF37
+:105D7000000000000000FFFF000000000000FFFF27
+:105D8000000000000000FFFF000000000000000015
+:105D9000000000000000FFFF000000000000FFFF07
+:105DA000000000000000FFFF000000000000FFFFF7
+:105DB000000000000000FFFF000000000000FFFFE7
+:105DC000000000000000FFFF0000000000000000D5
+:105DD000000000000000FFFF000000000000FFFFC7
+:105DE000000000000000FFFF000000000000FFFFB7
+:105DF000000000000000FFFF000000000000FFFFA7
+:105E0000000000000000FFFF000000000000000094
+:105E1000000000000000FFFF000000000000FFFF86
+:105E2000000000000000FFFF000000000000FFFF76
+:105E3000000000000000FFFF000000000000FFFF66
+:105E4000000000000000FFFF000000000000000054
+:105E5000000000000000FFFF00000000555400009B
+:105E60005555555500005555F0000000555400009B
+:105E70005555555500005555F0000000555400008B
+:105E80005555555500005555F00000000000000024
+:105E9000000100000000501400000000FF5C000042
+:105EA000FFF55FFF0000FFFFF00003E000000000CF
+:105EB0000000A0000000040000000000000000003E
+:105EC00000000000000010000000000000000000C2
+:105ED0000000000000004000000000000000000082
+:105EE0000000000000010000FF5C0000FFF55FFF04
+:105EF0000000FFFFF00003E0000000000000A00031
+:105F00000000080000000000000000000000000089
+:105F10000000200000000000000000000000000061
+:105F200000008000000000000000000000000000F1
+:105F300000020000000000001F8B080000000000AD
+:105F4000000BFB51CFC0F003096FE440E50BB3A099
+:105F5000F2D171152B7E794298878132FDBACC0C33
+:105F60000CE6405C07C48ECCF8D5F232618A7D968F
+:105F700044B067893330308942D826A294B96B1473
+:105F80000F0DBC4B0595BF4E09429B42C577A3C977
+:105F9000AF87CA27C943E83D2AD8CD4D86CA03003A
+:105FA000760E86656003000000000000000000001F
+:105FB0001F8B080000000000000BED7D6D6054D5C4
+:105FC00099F0B93377EE7C676E42122624C19B109C
+:105FD0002140C0490810BA717B13828C6D5A0708A2
+:105FE0009A6AB483504D153458DA66BBEECE255FFD
+:105FF000C48010B4C554B13BA6D697EDBA6D74A356
+:10600000C5ADED3B8876E9DBF66D4AD0A2A2446BC4
+:1060100069BBD536B67E75D75DF73CCF3967E6DE0E
+:106020009B4C0057DFB73F96EE7A3873BE9EF37CE9
+:106030009FE73CE7E20ECC25851F25E43DF843CBE6
+:106040005D2E7258BA8810AF27726C9346EB84FEAF
+:106050005945481F9445F4FF930E99AC20C447D886
+:106060001F6789E325770E211F77D2CE05F487704D
+:106070001EF677053A489CFE44B6861CA49090CF45
+:106080007B58FFB7BD394B4988904E0F2BBFE8CBEB
+:106090001986B23741486A01B4CF4D123A9F42483F
+:1060A000A55C0B237C916F9441D9B132B604CB8BA4
+:1060B000A09C431C842C877A897AC6CFE67ECF09C0
+:1060C000FFFD6B02F089F5C8A97803ACEF24E24F1D
+:1060D00094C07827D9F3BA732921724788DC5A43D0
+:1060E000EBAA42527CCC7BB8B1B6503C90C18BBD80
+:1060F000EC3CD5907CB232D37F3109E69F594CFFFE
+:10610000221319E1E0E3093108ACEF86BF6A53E7D7
+:10611000793BA1279F744DC553B675059E06121E87
+:1061200092A2937627542C7D25444F06902EFAC3D5
+:10613000553043D270E4533A6AE50F0F10131C5EDA
+:10614000064794488C5E246EC1577FC91D1E7D860C
+:106150007D930A8A27B1EFF2A9FBA3A4D047E8FAFE
+:106160007E0ACF30EE7F2435131C9F4AC3D14ECC1C
+:10617000FB3F7F383E6719EF5A48C818AC2FD3F55C
+:106180004CF3108DD159D6F8B873C4BB92EFB0F070
+:1061900087BFD267A9CB813C2BFF4CE1CB41CEAF6F
+:1061A0003127E363514F223FBAE69238E0AD1B7EC0
+:1061B0002AE2AC4AF1E656235F1F9080AB15EC2F24
+:1061C000E77B0C27CA5BFCAF717C33B1C8A38BCED5
+:1061D0002BD1FEAEC2CA501CF820C0E4D1BE9F5DD8
+:1061E0000923295F6891FBD691008307D7994B92C9
+:1061F000B3A87C9077576BEB83D9F1325E4AC7D155
+:1062000075D6D335611D01B75CC2E0BE03E0A6F4CC
+:10621000959BDD06C81B85FB0EA4B70D6EAF1A2338
+:1062200020D2E39F58C0E08E16201EECEBADF77431
+:1062300027E5659C8F906F880EF42B15FB9718FE51
+:10624000F61711C4D3BDE1CA271C94D66525910861
+:10625000CC7F4778E8082DC88F95F8308C77971059
+:1062600009D62BDD3149405E075C6C3F6B9CF5DE47
+:10627000976979677379E85AFAFB31E0D3E553E11E
+:106280003948E551A6F2BB9BCA23E0F3ED1718FC91
+:10629000D9F0D5972016BCF775C8D124EDDF177E4D
+:1062A00022772DC55B6F7E450DB24BBB24C3BE7CF0
+:1062B0001293937FE6EB1FDCFE0502F3533CFE33A3
+:1062C000C0EFCA1F244CCFC408E32B0A8F091FE577
+:1062D0007A5257617F5187017ABA8CEB85703F897A
+:1062E000A4181E8EC2BC459593BA9BAEA3C6558713
+:1062F000A265F04048E48715B4FFD00F2FAC1930E9
+:10630000C9874BE2FA373F9FD15D8E54C6A6E11391
+:1063100041A7BD144F552EE47B09FA7D0DEA263CBA
+:10632000F492F809E85754E743BA156D89B8605FED
+:10633000C725014718F5540FDFD7DE8FF890CF7AC5
+:106340004AD5FB9CD43E9C16F6E0A064E12B8AA7BC
+:10635000D38C4F187E6495E1EBA4147F99AD9734EC
+:106360004077E56CD1418D926E0769473930C81886
+:10637000CC334722993F743DB5561B06BEFE23D74A
+:106380005B739AFAB63B005E4D46FCCE99D8D44C6E
+:10639000289F074F5DFA1B28E9EF2FB96959DA3EAC
+:1063A00069001F16D7261B00BFBEAD830D80EFFF0F
+:1063B0002BC5FF0870176F21EB9A907527507E87C9
+:1063C0005C49A2823EAF1FD36301A0FB25649349C1
+:1063D0008FC9807F90AB4AA6F705DDEF75327EB995
+:1063E000237ADC7B7D00FAF9102FE5A44987F9CAEE
+:1063F000A8B848741FBE0CFD9D129D27B46310966B
+:10640000256AA5DA057052BE9F0D7C36E4328A609B
+:10641000DCD076A535C9F07202F832C7C171A2D1BD
+:10642000FF513CA9BCFE13AA8100AE1C8E971C81B3
+:106430000FBA2E1861E745138693DAF5595B484485
+:10644000D33278922344027B1F6E2711DA93F8C36C
+:106450000F239EE4DAC994CCF014063873E214F1E9
+:10646000546FFBD4C12300679FDC71FA6FE87EFA9A
+:106470008E39238666E24742F97149065FEE309510
+:106480003B93BD167CE9E3FA623B895748A80FE2CB
+:10649000C81FAEC2C361B31CCB0AD5CFB0FFCA16AA
+:1064A000ECAF84474E5E0BFA393F5C8DF22AAB6845
+:1064B00047767B88C5CE13D285F8EF4F24C92F5C71
+:1064C00020AF6C7E8F166365A7537B05F459258337
+:1064D000BBBF6A7D08EC95C73382F4F70F3E84F6A4
+:1064E00093CE19F986C6E06E5902F6D681F6EF1FF3
+:1064F00068F91EFA47495CC715F665EC2281F91563
+:106500009C3F0D8F47BF9A503CB787150DF8F84652
+:1065100027E900F96A0FCF6F023A08FD799D54C44C
+:10652000E4C9D9ACEDA4EBBF99EC8D38B5EC7AADEC
+:106530005DA63C5003567CCF18C82F49BA26278445
+:106540003D2C9FEA2FAD93B8BFB492AC04FBF82664
+:10655000A90AED9C61FE7F4D1C5351BF727FC9DEBD
+:106560002EF6712321AFB8F3609F86F2298AA79B8C
+:10657000240FD259EC4FCEEB2F447DC9F9E4C6432A
+:106580003F54CD7C71A34CDDA99AA9F0A7ED8D18DD
+:1065900047DD3058E7C6090A97D9EE4F19C7EC7C9A
+:1065A0007A5E99D8F5D3E724DAEE6DFABC3187EE3E
+:1065B000FFC607D7317D4EE107FECD0AB758DF068B
+:1065C000FFD9D6FF43536F1FA8CA132EAD340674EC
+:1065D0008F2E68027F5BD86F81E7756B7A0BA7F30C
+:1065E0007FD3FC22134D053C3B039114F2C76D751C
+:1065F0002007FF4BF24E6B27CFC60F77023FF82DD7
+:10660000FC7059CB87C00FDFE2FC20FC0BB17F3B55
+:106610001EDB9B5CA8B7B3F2011F7FEE74E0E3A61C
+:10662000D2FF9FA6A53F9F5FF08158E77DC34BF245
+:10663000D19F98037FD5C03F4849641E7643FFA988
+:1066400098C333B7625202FED0626A2398EBF2D647
+:10665000C81350DE9BFB40D17D1AF46852CFD07531
+:10666000257D96F4DEE219FC73BACD33023E67064F
+:106670000ED13E67ABFCF284496ED42DB46EDA4F76
+:106680004EBDB5DD474CED6599F9F2B8BE225A24EE
+:1066900062F63FF6BA265A4984FA05D21FF57CDA2B
+:1066A000BED73B7192A8D4CFB8ED2D3D4AEB3973DC
+:1066B000C5F960D203FAF6DF258DE1A92E8AE70835
+:1066C00095AFBD4F77901CCADFB96572124CFE9131
+:1066D00009273D0B50A9D2E4A41B7D8328FA25216C
+:1066E000AEF7C53C8313E31E42F9EFF6FABC5CCB70
+:1066F000FC61D63F28CEC3CB1DC4519B99FF6DCA08
+:10670000D363E0EFC863389EE895088F989F683F91
+:106710003B368FF6F7AC9109F863732726D1BFBBE0
+:1067200080909D602F643D99427447CFCD2F93EBAD
+:1067300014F4B7E4BAFE3156327F85BA69763EF575
+:10674000389683DDA17EFABC8C1F25D6C9CE078280
+:10675000FFD879FE8BF43C0F76A740D12517AD7793
+:1067600096904817DD9726C5F31DE0CFB6747CBA26
+:1067700097D6A5CB3B174CD0F93B2906D0FED5398F
+:10678000922C0E40F9958EDB1B9B9D8479E4592554
+:106790000500C7DE3AE6AF64836377822CAB30F93D
+:1067A0009BBBE5110FE06B77558D67BA71FEB0B2F8
+:1067B000AC62169D37AACD56673887669F77BD6550
+:1067C000DEBF95E211C7F2A9F313CED70E4A7C9033
+:1067D000135FE0CB780E9ACAEFA6BA736A7D68534E
+:1067E0001FFA2BF9B3F56A89F2F9B3D43D885197B2
+:1067F00039DFAF3F0472F0D3AE4F3704289DF2DD8E
+:10680000FA76076D7FCD51DEB007EA947140294CCE
+:10681000747D4CDA09E3C1267F84905F757D61A7A2
+:10682000C1F10F7E4F5F22957CC505718763C95703
+:10683000E87E9B1DCCFFBCCCC1F85A91E3E8AFB811
+:10684000C3B49F596E65E6C7FA2BE938B37E0C9343
+:1068500014F0974C185F533FB405F053D44A8EB8E8
+:1068600034E02FFB79AC2AF4B2890E6D0EEB796C13
+:1068700000CE61263AF83CCFCC35FB3D7D89937341
+:1068800019FC1373017EEA37EAE0CF1B7584005FC1
+:10689000ED4BFC1ADB73EA3AF07C9523B37DA7F548
+:1068A00089839D2F44299396500AE8A2DE8FFA33FC
+:1068B00087EF43DE1122B7E6417DCFEB204F39AAA7
+:1068C000FC9659AFD9EDDE2D0EABDD0B75FE16E152
+:1068D00016F1A310C73F3935CCD611E711E7AB113C
+:1068E00038970AFB37E0E071143E2E87D075291DDA
+:1068F000C0A9E7FC83703839BF887DD9E1E9B1C10F
+:1069000073B63898587F2FF8FFC007E9B8CB18C680
+:106910005D48AD7C06D615F1167798D2C11247A115
+:10692000F430ADAFD6FFDAD23E141C40BE4EEB8140
+:106930004AAA07100749CF3A937F3F50797EF2BFAA
+:10694000479EF080DEDC1B78B91FF4A91171442E3C
+:10695000A43076439DAEE35C52516DF6773FA73489
+:106960003E6096DF40159DCF04E700E889F7B37ECF
+:10697000BE75FDDEFCACEB3FEA607AF45573BCAD4E
+:10698000BFEC0B1EA08F1D1E31EE7B52FC2D33DCA5
+:10699000EE121DF9FB9D8979678953A42C710A9029
+:1069A000EF4815936FB3DF91DE0F972F51FF0AE881
+:1069B00005BA6E90F2018C0B46AC740FC079701E54
+:1069C000C4AB529EA7408FB778303E44DA088B7B29
+:1069D0007036A776E7E7B06F596572198830BBF358
+:1069E000155062CBF17C1AEEA0BF0FE4525E0F810E
+:1069F000BE88B7C6F03C3C115E6FE28F394EA62FC1
+:106A0000D2E356517D09FDAAC201584FE8A12112D7
+:106A1000FF25ACE76FED48313D14B7ACD70FFC480C
+:106A2000EBDE4A06BF80FB0DAE07EDF00BB8656EDE
+:106A300037F337B4A15D48EFB7D5EA0F8AFE22AE2F
+:106A4000F37167EC2B0E53FC62AA3D9CF0AC33FB58
+:106A50003DE76907ED65402231D037DD811AF55AEF
+:106A600093DCBB39FE962ABADBB97C2ABF9DAF9D69
+:106A7000CCB66E6FBE75DDC2CCBA85D3AD6B8FB3AD
+:106A8000EEAD3C13FB0CD02D9663F8E1DC14637A79
+:106A9000585653884F999FB7859E17E7F61C3E6757
+:106AA0004F1D3B7F5347CA403F83F215FA198312AB
+:106AB000D3C3946FE1FC1D202C1E5CC0CFDF2F726E
+:106AC0007E2725A6B87039ACC7CEDF4623E8425AE8
+:106AD000BE184C764BD9EF41C4FDC7DB8E64549A87
+:106AE00097B957F1B9060DF00FA9FFA5C3DCEF6305
+:106AF000BEFE99E63BDB78FB7AE21E66A0221943D4
+:106B00003996E97CF887E1351DD7E0F81567648F81
+:106B1000C7F094817E3BE12410AF710E56A760DE72
+:106B2000747CA384AD43EDC5FD0322AEB122737F17
+:106B3000E3ADB4C6E15D25D6383C693524733C5FCE
+:106B4000C43FE4007582AA18FDC01F861B268893E7
+:106B5000C056DEC37390F5DE480E90943707EC4ABA
+:106B60000D31DB3F99B0FB838C5DB58ECBC6DF5317
+:106B7000D66BB1C279CEE302B276C6C45FD9C7592B
+:106B8000CF5F7F03085C9E9DCEEB72A93EBA28437F
+:106B90006FEAAFEE72164CA5FB0957C745400C379C
+:106BA000F8F558B2731AFAAF141F37CB817ED0C3F1
+:106BB000DEC028041D8957B39EE36E86BFA01D2743
+:106BC000A8BFFC95D676BB5F7BB753DC0FD163CDF6
+:106BD0008A8C9F95E309A4507FD6C9AFA6FB9BF092
+:106BE000714B98F2DFACECF871108F16A0EB7AB80D
+:106BF000FC4ABC2EE0F8C3A01405BFF316EA927459
+:106C0000D698E755705EBBDE99AA978DCA615ADFA8
+:106C10005B51188173DA40EE29F212397FFDBC878F
+:106C20009E4F41AFEE0BFCE118F805193F85D5A743
+:106C3000F113BEEB349DB3FFBB7A3ABD7EBE75FD4A
+:106C4000DEFCACEBFF08F4743F8FDB4FD1D76A401A
+:106C500036C7D55FE0F42D25A99D849DEF621E7394
+:106C60003CA275F208C41F4AE73F53F49406FE7035
+:106C70000FC61FA8BB59FBDEB273E77F8F83DDAF62
+:106C800091088F8364E2FA6C3D7ECFF27B6E6F28B1
+:106C90003C0F5D4BFF7A70E504C643E831C9E1A2C1
+:106CA000F095B5685D180F99BFE209F00FDE6F3CF3
+:106CB00024CD2FF5C29F9DB4F8B3FBEA3F1C3B4E99
+:106CC000E4B43D25F234F674DF79FAB1D9D6B5DBF8
+:106CD000F15066DDD074EBDAE569FF861CD413FE53
+:106CE0005352D24DF17ED786EFA39DF09EF26A10EB
+:106CF00077311A59FCC0984B227067DA5911D38149
+:106D00001E9A142F95293F35BCF85818E207BB2F5F
+:106D1000ECB88098CF0FB5D638C2EDB638C2EDB515
+:106D20001F4E1CE1F60F2E8EB04A3E87388233F894
+:106D300065B45BDEF38C23E4CFD2ABA508D41E6D23
+:106D4000FC715D267ED0DCD3DF182882F801C17883
+:106D500041ACE7709701F18262FD21E87F42FE4E6F
+:106D600023C4D9F2E7B1F6C5BDB41DFC2D0F3D67B4
+:106D700053BD7C331007EE57E2CA4BE08FB94B0C82
+:106D8000E67F85C984648A03B85BE32990AF1F2B33
+:106D9000F1CB818E2175F088A4C17D0BBBA75DE38B
+:106DA0000CA03DFA4309C1F85B367C427E04DCCB83
+:106DB000DEC3E3027B122AD6BF9A0863E9AE64F70A
+:106DC000E8FD091DDB7B496C33E0D55DC2EE1D8714
+:106DD00078DCA15B21ED501EE7F7E33FE57C9C29C1
+:106DE000593CE0E80BDF79F63A802BE08B008AB261
+:106DF000C1D597A88CC07AFB12112CFB25EA05D1CE
+:106E0000A345A7FC912ECF2AAA879CA922A8F7C93F
+:106E10001FED6A5A95D15B4E6D694436E9BB2FC9A7
+:106E20004C6F2A5BFB308F45D1597B31C4BDA7E144
+:106E30003323D37F0CFBABACFF41AEA7EDFD77F165
+:106E4000FDDD73E4AB44A3FE92B79EC563429D2B68
+:106E500022F22CF8FD31A2517DB5C7359292E8BEE1
+:106E6000F79592C830DDB7BBB38AB7DF46CAE9B839
+:106E70007D7C5D8FCEE8A776D662FB1EEF243FA710
+:106E8000119E2FC0EE55A99D6F05FABAD4F9E550B1
+:106E9000BF878F0FC2ED3DF52BE8E9D71E97BC07E2
+:106EA000E826D71AB82F1197C4B9C05EE512D4AF3F
+:106EB0003D37453D6B71440AEF9F4BB60474702615
+:106EC0004ADA0B1BB1DCBA08EF594A6A039BB0BE21
+:106ED000A5703394DF93CB70FD922D959FC1F62D55
+:106EE0001FB91E7E2F9E6B8BD3D6451D00979FEB3F
+:106EF000B4DBABCA4364063D82164CE83F94431FA3
+:106F0000F844A67A9EAD3EC7D6BFDCD6BEC8D65ED4
+:106F100063A977723C935A85D91B758EE5BE924C56
+:106F2000CE61F0F3BC9C23DBFA3C2F0558698EBB85
+:106F3000F59F655F633293F312D5B43FF88FC7971F
+:106F4000A99723DEC2781F4FF583EE30E9875AAA4E
+:106F50001F965AF483613E9F9BF4C37340F7F7ABCF
+:106F60001F06132C6FA39FE76DD8DB7B49FC0CE851
+:106F70001FB7CECEE919BD1069077D1870F535CA67
+:106F8000AB502F60BC944A6C17E42B791CACFEAA62
+:106F9000FCD78DA01F8FBEB060F64455C61F1AA443
+:106FA0007253BE849565B4543A97452A4C72ED0FDE
+:106FB0008F18703FAF84D51A8C99F1DF152A77D0DE
+:106FC0004FC463CF4ABF86038C7EB404FAA9FC3E4B
+:106FD000EC36A0DF0C76680FC50B5990A907759F9A
+:106FE000AED1FDE73AD8FD77B0A9B051CB31B503AA
+:106FF000DD20CE137164F811FF4BE91BB4D099E882
+:10700000E5D9E94CF114023C15A61E437D63874B7C
+:10701000E95C88FA4AA6F882D21F9ED4F52A93FE2C
+:10702000C857EF83F36261ABBEEA979017923F17A0
+:10703000FDD2792E9E173261D51B625EAA3FE6B95A
+:10704000001E7550672E218BB314A66E43383CDAB0
+:107050001889D332A88E19A0E7E430D1E0A82F8395
+:107060001E5C96D98F027A0FE0F318B84FCAB77139
+:1070700032BD5DAB764D63D7ECF646C077BD8BE98C
+:107080006151421C7C6206F9137170814F5F654447
+:107090009ACE2FE9E3F6E74E6ED7F626EA58FD8939
+:1070A000AF9232BADFB52E16DFF7960C12E06BAF57
+:1070B0001C2903BB64F4FC7D6313B5F3777AD938DC
+:1070C000D15FCC7B19C7B7B784D1C7BEEE0617D343
+:1070D000E7B3B85DB3B7B7F176B999DF4B35F37B5A
+:1070E000A912C62F721DB37764724A9CB0CD05F900
+:1070F0000FA423757F59C60E88FDDDF9C4B3286F30
+:10710000C1920ECCA3D9C2F199D9076FAF1D239BB1
+:1071100078BF060A5F3BE76FC1CF6E6EBFCE95AFFB
+:107120006F76A96C3F1E03F59CE08FBF77EA1D2E9A
+:107130009CD7C0F6BED85616B7F2F0BC544F8EE1BD
+:1071400087C3EE8929FBFC2BE01FBA4F229501FF74
+:1071500088FC2F23CB3D5BAC01EFD9F249A48BA077
+:107160007FBC13D675C7B2DCB3A5E3EBCC3F1E00E2
+:10717000FFB82CE31F9F6F9CFD5CFDE3F38D9FCF59
+:10718000E01FDFEB3A07FFB867D381944EDE877FBD
+:107190007C91FEBA03FC63E34FCC3F5EA03F04F555
+:1071A000C0975F6D8CC27DDA326E0F8CF71A416E1C
+:1071B000F2571234DDDFEA25DDE00F57BBF56F0330
+:1071C000FDD2F8D6D2F1024B1CB75F3BDF3841123B
+:1071D000F1311018EE2FB7C409587D9A737ACA3569
+:1071E000439CA0FFBCE3047CFD7CEBFABDF959D7BE
+:1071F0001F63FC4F06414F2A9CBF7B72AF437ACE80
+:10720000709FE1534C702B61769F21B7C408A6177D
+:10721000DAE4C50EB76B368BBFF7E45EAEE2389B9F
+:10722000BC4D7239B6C7E13FA8F9A789EF7F9BE152
+:1072300081D99D6FC322CB3FFCFD7C07F870B969F3
+:10724000BDF3BC9FA07A08C7DBF34F3FE87B3A7BD6
+:10725000992DAE51AC30BBB154D18B813FFEBBF701
+:1072600073D9D6B5C7351629E9B8C622E51CE21A86
+:1072700081B2480CFDF02207DE3B3BBDF163900F6D
+:10728000B92B7C9D669465F2EFC4FCD72AF370FE9F
+:107290009EB0E280B86ACFB135B3C17FEB7375445D
+:1072A000619EEE5C873A5C3615DE98C2ECB7B3D3CC
+:1072B000BFECFE19E2644E85D9E11EF50984CB5F6F
+:1072C0009D9F0BF9B4DD47FEEA9813FCAA70619903
+:1072D00097D66F52B81F4585FC17A678EB2E7070B5
+:1072E00000FE00491A12AC9783EB9D0DBE7A4E2F1B
+:1072F00067A777D9FD33C4693F68F8041E3FAE68BD
+:107300007CFD00AE2FF0EA043900FB5025A7209F3A
+:10731000D735E1463FC41961F9D3697D50E5C03CDA
+:10732000192A075B81EEE415AB9CBAD5580ACA95B9
+:107330000ABB37747A3BF0BE57E4EF05E232DA2538
+:107340007F9CD927B15F61C7FD2E964FA10464CC05
+:10735000EFF5F0FCBC802B3206FC1268985F0EFC47
+:1073600032CAF1D8A7B37DF5C13EE09C01F7A05524
+:10737000997508A9B8ABAD16E204E5350374EB7F47
+:10738000C7C7292480FB53381E9489EDA952D0DB4E
+:107390000ACF032827E5C0B7B734DCF22F008212EA
+:1073A00036DCD3E5034CB507C40BFB753638BC158A
+:1073B00070BF53CDEC01D16ACF922FB493E18BD340
+:1073C00041E05FAE62F9D52EC82FA57877EA941E0A
+:1073D0004B337448FBEFA7ECF1014667A2E5A35CD1
+:1073E00039032CEF5621F26D6D65E6FD33BE15FBBA
+:1073F000FF86C2F353FF3FEDFF4E85E9657274E1EE
+:107400005D6D9067AC3B225E185F62E56F7F40C6A2
+:10741000F757828FDCA73691B9B4DFF7FE5CE0A79F
+:10742000A70788EFC150F69FED96FB328DE7878B5B
+:10743000737BCE0E82F1DE0BEA65A4AF56DFB5DDBD
+:107440000176881EE0A07DCE0E19633BB41DF72D9A
+:10745000C65F602896BC67758BB53E87E7E39412DC
+:10746000D3EF749D393CFF7C0E31BDFF027F8CE76A
+:10747000BD08B9B3EFD39E37F35BC59ACF7CAE7925
+:10748000333713FD75D41F9C3FBB17B1772B53F1D6
+:10749000CAF442A1D681F97EB3E93907E304F52C99
+:1074A0008F3F8FC4316E40EAD83DAA6C839BB89958
+:1074B0009D729337F01D8042260CD447367A083AE5
+:1074C000ECAA243CBF510F14D1F65C2E4FF81E10CD
+:1074D000DE0F14517D4AF1940BF887734A13C7AB42
+:1074E0004424E0CB9C7AEB7B3A85BFB7CBE3F10B2E
+:1074F0009F8D0E0AD001DFFD597F9FE7962C794DB5
+:10750000D9F069A747A99BEBAF20095ADEE3A9F997
+:10751000D3BE2B4ABFC313E7A8F37DFF27D60BD0FA
+:10752000F5E6BD8FF56C74B884D3A1BF42D0813429
+:10753000031D667139EA079984FB104E87595C0E6A
+:107540004833C3BB87FE0FE830BBD54A07EF39E2AB
+:10755000DDC9FD90B794D8256E94634DC2F7455BA5
+:10756000FC187772A7F9E5F1230A9C132B08C6BD16
+:107570001F82472DB4FFEECF1EC310E79CB95D9864
+:107580005F4BA046C7293C5E35105E3F631CEAF6A0
+:1075900004C1778D43FC9D63B67E61251E873872DA
+:1075A000B076C2007F60D60EAD06547E38CEF8B4F9
+:1075B000A45E1B86BDF4093E020E35DDBB23871792
+:1075C000225FE29F921A36AEAF9424BBE890BC1DB6
+:1075D000CCEEF795B1F84C68879C72D17A5ED525D0
+:1075E000BFC1770E720781735B5EB315CFA18E1F8B
+:1075F000B44A78596DC22BE4F7954C5E8374AAB7F0
+:10760000BE5FCCB6BF732DFB28BE5E36E55FF54787
+:10761000D83EDE2C219857EC8E5315077632AE16E5
+:1076200002BDDDF14800CB898628FB3D3600E53000
+:10763000D00FE2183C0FB8A8C4617BD7383DFE20BC
+:10764000340F21E910C78B802364E32B3B3EECF51C
+:107650000F1A0F70AE06BE283DE124E0F7641B57F9
+:10766000FA8E4C52D4FE0F785229E83F5042D01F78
+:1076700077D7B3F7AC0139F955B8DF7187D56A838D
+:1076800064C67DDBCDFC4E85BFBF25B2266D089A52
+:10769000DBD9FBC7B714FD5BEE029097073D10974F
+:1076A000DBED4A617C6577358590AE136857D878F5
+:1076B000C8FF35E98B4FB85D96BCF9B4BE08930995
+:1076C00087E9DC2CF4FD8F95F8F7601D9147AB84BA
+:1076D000D9BD8D881B8A78B47DFF221E7E38412259
+:1076E000E007F42546B0FEE40B5F4478EB741FDE40
+:1076F00097D4E9AA067C52A76B15AC1EA960F56861
+:1077000014F8BDAE89DDEF912D5E8C47E77279DF0D
+:10771000D5B41EEF0DF6F2787B3FDCC7D1F251B83D
+:107720008FA3E537131A965F4B5462793011C1F578
+:10773000EF4ED4617D08EEE968FD8E4414EB8712AC
+:10774000312C1F48B462797F228EE570A21DFB2583
+:10775000131D581F4D7462FDE18481F591443F96DD
+:10776000DF4A0C62F9606288DF0F26B11C481CC238
+:10777000FE022FAB26283ECC725DE7B0F8155ECD39
+:107780009A7FB4F2A4F51DF0E243732CFD2FE82C90
+:10779000B7B497762CB2B417B7D758EA45F18F58DB
+:1077A000FACF8A365AEA0B931FB3F45F30B4DE5235
+:1077B000BF70F04A4BFF79FDD75ADACB8C1B2CED0A
+:1077C000CBC76EB1D4971DFB92A5BF88370ED638B4
+:1077D000B713CABBFE7E578FA7949A393F29032758
+:1077E00061A838AF07E2C3B970EB7B11F8ADA40212
+:1077F0009483AB89F935AE1203E3B9B47D11FC4E25
+:10780000DBABA01F6DC7B8296D7F9DB7CFE7ED98A3
+:10781000A724C378F0F74BD83D9F0AC606E2FC398F
+:107820004C4F3B4FB173423A1EF1EE94B8A9E6813A
+:107830003887CEE2C7E27CA6FAE31DB169E4A1CEA7
+:10784000C3ED854796CDF9B6E97B348DDD2B928863
+:107850008CE70D6EA3D3E33D2524E55D0A7698E71A
+:10786000615340DEA37DAA53AC2EF079D1616B7DCC
+:10787000C988B51E8C58EBFE4A6B5DCD1247BF8A96
+:10788000C3DF9748AE847C7788CBE8CC3F44B815FB
+:107890004A1F15FD6AF6FEC7C3F7A750F986FB1EFF
+:1078A00052CBDE1F0BBF4FD1B5F9D0DFD3C4F2E20C
+:1078B000142AF7D84FE49B9F5A7B4CC2FD323FDB22
+:1078C0001DA6EB9AF8C65367CD8357C249A493DB34
+:1078D000B61FBB5F75B9E7FDE5A367F3BBA6E8D1AB
+:1078E00077DFC3BC32B7CA37FA2E6D87F739F07726
+:1078F000C86B2C9563F03E3B524BF4FB685922A7B2
+:10790000A4ED267C6FF530FDAFC1E16C392CB9BF19
+:1079100001F94F8E17C1BBF903FCFEE1ED17EE6ACA
+:1079200070835F7D9D86EF45C5F8031EE6978F85C2
+:107930001DC857C1183BFF284527F4065ACFAB8511
+:10794000BB7FA08786F92E105A05D89E98EB23732B
+:1079500068E573CFBAB1FFD1B9EC3DF42DB98AE532
+:10796000DE33FFDDCF4580BF5D17DC1A063DFEEB41
+:1079700004A9D97221BC9FF360F96A42C5F27789E4
+:1079800030966F955E87F932EE444718C6B9F5C553
+:1079900096FB49CA2E4ECA43E9FAAE230B25C8030B
+:1079A0000846C7748877BB8F7AF15D45505586BD10
+:1079B00026387A5CF1A24D00FCA7143C9FECF70E30
+:1079C00036401CC3F80CA9FE069D7597AFA33297ED
+:1079D000AEB7AB9C7C7ADD34FCBC9DE389729253DC
+:1079E00031F96B91E860430EF8C25B4884824F5CCA
+:1079F000BD540D407DB93A02F39678E83AE0076E3F
+:107A000051B56E0DFA533B5D95A197CB4B620F05B7
+:107A1000A01FA36BA997DDD714C50625A063F72384
+:107A2000EC1EEDC917AE50E19EE40FF91568C75E74
+:107A30007BD4AD43BCE5B53CF65EFCB54757FE00D4
+:107A4000F4D46F13C7F2CCF7C9AF7DEB672B5C940E
+:107A500060AF3DFCB315323255D2F26E65DB7BE38D
+:107A60002BC07F351A4965072D6F5615CC63BF199A
+:107A70006482ED0BE5F540A1D207F317CE76EC85D5
+:107A8000B2D9C7F212441E27E17AA9F0FFB8308FAD
+:107A9000A2FB873E9CA7531E398AF868A2E7425A88
+:107AA000DC72A1D61DA0F55BCAD4089500D29D6BEF
+:107AB000B8E7021D5E70B3F64B8913DB8B547C4F25
+:107AC0009DEB19C7F728EE270753C0D6FB25DD1914
+:107AD000043A2E64F389B8C1DB65A4B28CEA7179EB
+:107AE000F54814E09E0C3AC8B004F7348C1EBBE98C
+:107AF000B914D60BBD4276E668908FDCB1BF0DFDA0
+:107B000041F65D972B7CE52CEEC5EF6B76BEF0C59C
+:107B10000533F92BA2FC3EF7579E4878B03C9C50A9
+:107B2000231554FE538930D6EF4C6858BF3B51891A
+:107B3000F5DD890896F561164FA2FC2C81FCD7ABC8
+:107B40004CFF5D9CCFE20EC59A43572E8276967706
+:107B50005AC0F5C1C561F6BD9BFDFCBEB6F8D4BFE9
+:107B6000B482DEAB7F83FA9D263D562013CFAC3C1A
+:107B7000CC633442983F4ADB2B39DCCE8CDE117A61
+:107B8000A660AB75FC7ED7089EAB8C4B199EEDF3BF
+:107B900007F9FC79D46D754E337F306AED3FA83913
+:107BA0000CD745E7EF4FDF63F3A70F6CA358A27C18
+:107BB0007580E733DCB36D45E85A137DE07B182F01
+:107BC0009BF8FFE0F615A14DB4FDC076A2A921D324
+:107BD0003C7CFCC1C4B1C2A60B33FC5BDAC1EEF144
+:107BE00045BF12837C3A66D2F7831D727418E31680
+:107BF00054BF52BEE9055D8F8F5A234D7A09CE8B53
+:107C0000F512EFBA26C8BF28DAC1E4B8D1B3FF082D
+:107C1000988420D5137E4AE7A2DA41490F64F43DE7
+:107C2000FAD1146FFF5BCF6B5201EFB56404C05201
+:107C30006A756D27C44DC7E645E0DEFFA30D3547E5
+:107C4000F0BB44CB457BA4FBDB1087195DA041EA68
+:107C5000C7FD9EF8122F95EFEF4B0E84BB283C28F2
+:107C600035D2F2EE27FEA4809EECF993E201B92C06
+:107C70007AFC2505EEC77BA40905F3EBBC0F344164
+:107C80003E09D5930BE19EBDD95BDD0BF50339F1C0
+:107C9000BF27689B1E687A92EADD42F7C43DD0FF99
+:107CA000122F31A2F5741DD7C45560A49BC8708FE4
+:107CB000672EB617433E9E4EE7EBA7F8F83EC8186E
+:107CC000E6A7DCD7A343FF5C566FF6267B0C5A5F12
+:107CD000CBF51D09C4CB400ED37595D683A6BACC7F
+:107CE000EAC4C34AB19F6D47FFF483628A8F9B1E2B
+:107CF000974620F5A4E871AA2100EF87F763DEC15B
+:107D0000E1C431B547D057E0998AFA2AC8EB01BCE3
+:107D100026A564B98447177C9F2EE70D1D81FBA320
+:107D2000F6CF100DC464D4C7FC985513741E133FCE
+:107D3000AF92D97B68FB7B67FC740ED0670FBB5793
+:107D40002DDA32A1C07DCDE13AC3BF94FE7EE3A619
+:107D50008A9A9D948E657CDE4E62F89BC02F5215E8
+:107D600015E44CE4D5BC2ACEB73CAF66AB97555D65
+:107D70005D8C1F7BBD238500E7E43FBAF2CCF71B87
+:107D8000BDB92385D234BF5379C6DF0DFA3BC07528
+:107D9000583572F3E83C371DDE3F170CFA4D64F09E
+:107DA0009A2F01DC3F761280E337475685FE82D654
+:107DB000B7D13A98AAAFCB6397009EBF3E5A36021E
+:107DC0007AB4C7CBE0BF6994F25100CE4594E6D4B3
+:107DD000493DAC0F2E9629FD8F0E5CB3C67B312139
+:107DE0008F95EBAA83D2FCF4407BAF07EA8ABA10E6
+:107DF000FCF6D30337237FDD78A983C98F71F35352
+:107E00007A05C0C1E4A7C77BB807E4A7B6D583E766
+:107E1000B942472C0AEF36C87107DA6F30C5F5143E
+:107E2000FFCEDC1E4F3985EBF7BD0E8CFFC07537DA
+:107E3000BC7FAC95C931999607A8E308DF8F30FA6B
+:107E4000641C477FEF77E5019D067578F74CFA993A
+:107E50007E5BFEB81BF3EE6A3BF4CF623C51AD474C
+:107E6000BF7A2E49FFC13CED0B08D3D32B55D2204E
+:107E7000D37E35DC0ED6B65E7E238C9BB7A9E54754
+:107E80003A6DAF93D8776EC8B32C1EDA93FBC088D7
+:107E900087D66B43B20AF1A051AFBE1842AE933FF2
+:107EA000F355039D4673232AD22D28E781DDEA99F5
+:107EB00070186E2AA78F9EDCFADB8BE19EA9C0A307
+:107EC000417EBA93F6ABA1F80E80DEC07BFEC926D8
+:107ED0001DF49912DF0E72F9D26D933D90C749F1EE
+:107EE0003ECF43F13EE19DC4F3D1E84EBD5835D5B8
+:107EF00057FE07D5D22897933DA0B7E4DC3B6E042C
+:107F000039A7ED4F7AE87E1ECB137A8DB5D7968BC5
+:107F10003AF5D7A91E70EE14724D0C0FD5FBB5A61D
+:107F2000FE4D54AE5D8DACFD7B743DA0239C833A29
+:107F3000F3609F04BFBF32B9504EC23E8166F0BEAF
+:107F4000E11267DBC797407CE342128110902F97C4
+:107F5000E9635FAE86F1C5512FCB07997C3A900457
+:107F60007CF9723B06DDD05E5A41E05ECD9F64F342
+:107F70004009F4F7F3772192BA0ECF3DDE4AEBFBCE
+:107F80007EF16E04EB905FC2CF0DB2EDF7AF95E9D5
+:107F9000474AE9F8CE8975A84F4E7A799CBD94DDA1
+:107FA0006B7C3166AC8538C7A2C991467083AADE66
+:107FB000197B02CAA5E4F546509B114FEE51287F6C
+:107FC000C1FDBD1AB57A356CED2FEA93DD187ED26E
+:107FD000268A409F2D77D23A5D27543FE28475660A
+:107FE0005F5D719EF91729CC7FD813704493783F59
+:107FF000FDB0BAC934FE319FB89F64FAC5C5FD8D86
+:108000004E32D8A0A0FEE1EF9FB8BE71F18397CCAD
+:10801000BFA726AB11D5A0FAB621588BFEE81C1FCE
+:10802000F3879D47565D06E70405F404ED7FD0CB4A
+:10803000EE01268BC8C8B006F7A33AC13C399E9F13
+:10804000BA83AF2BF4455FC243F405843CF2C9F90F
+:108050008D1897A464C6F70CA971E93D7AEEBA238E
+:10806000F39D0405FCDE473E59D8A8523A7D27EA25
+:10807000806337D54BFACF8B41BEC75CA8B7EECC37
+:10808000B5DAEB437CDF6F7819BCD45E7F1ACE156E
+:10809000BBE8FA49BABEF28E9F24A97FD9CFF5B1C9
+:1080A0003BBE05F9CC1DA660225F18E2BC4D1E291F
+:1080B0008373B58324CDF70AEFE4E0F837BC6C1D79
+:1080C000714F9F2D7FE4BB3E0777E6ECDF678B2285
+:1080D0005D76A4E9C2EE291E6BD47F4E504FB81CCA
+:1080E000D3DD632FE5F329EF480887F8BDC6C7F84D
+:1080F0004DBC8B57DE91B15DEC57F4CBB4B37DFC36
+:108100004E65EFB094309357E5B013FD4D129627AE
+:10811000CDEF9CFC708E98979133F1FE6AEA3E2277
+:108120006378EEAF607A76AA1C1AE8F7EC08EAB337
+:10813000C11EB9356BBB3DFF290DF73BB32CFB10BE
+:10814000F295D94F21B6833D017D70934CBE0AF163
+:10815000C16D3C2F659B93F213857FE08D640CD637
+:10816000FF9D38F73CCEBE7FB26D743FCF8FD12CD0
+:10817000F1CF9B0E6FC7FC137FE73FAC8477586F3E
+:10818000A8ED45E04FF865A6AF48AB07EDFE7EAF22
+:1081900038D72C60F761F4FFF0FB3B84F50B546992
+:1081A000C3E0679EE0E7CA66101EBA4E4F500F4B01
+:1081B0002C16A0CB94063D0542AF3ED0037274400E
+:1081C000C9E85D089A1CF0B17A97EF819E1EF00B0A
+:1081D0007259FF666F7DAF51027E82A8AFEC057FBA
+:1081E000EB8012390AE751E351B70670D2F13AFA3F
+:1081F000055756B23CF5323207F0F064AE827E4C41
+:10820000CF23EE6138DF53BF72ADD7746E7C2DF78C
+:1082100099B9A46ADAF90CCB7CA5E7371F5D7FD446
+:108220007151A6FDC9DC15479D6C9C06E35ECB55DC
+:1082300030DFFFB54F79F05EE1A0CB2AEFA2BCDBC7
+:1082400027E24F2ACA799A6F40BE217F8274307A22
+:108250009530B97687F32C729DE1B3629234E5478D
+:10826000CCE1F63EC36773B1FD0D4EBFBE84768E82
+:10827000EB9567596FF159D65B6A590F3473FA3D24
+:10828000E60CF717F6F75F763D294AA127737C6C59
+:10829000FE8BA5F8777CB47EC3C4C825980E2AA9A6
+:1082A000053B69972BB95FBEEAC19DDDC09E9F5318
+:1082B00062BFF316B0BC28908FA54AEC029FA97E3E
+:1082C000F32B01C341F9E026F06B287D077ECDDE5C
+:1082D000ED0AF9F27A62A9622D235FD3E843863F63
+:1082E0001E8F00BD0FF5AF8FB91C3BA7D18B197C3A
+:1082F0005AF55D8F57B3E193E9BD0F6E3DA7857EBB
+:1083000053D753B03D63D7E2844C631F7714E99889
+:108310000F6492771DE41D9E83703FCC00FD706753
+:10832000BA7D676F5309F8D7997682E7B5CC78F8AC
+:108330006EC29D3E51DFD30B7EDA94FE7E5BFF72F0
+:1083400051BF0BFBDBE139E0CBD4C10F94FFC39DE0
+:10835000F61301BEFD0EDB7C79A23E8CF309FFBF54
+:10836000C3FB8F4F1932F0E56003D8F3497AFE82E0
+:10837000F73C5F9723BE88C98FE9E0FCA9BCE3B551
+:10838000E03983DF00FE4EC2567AEE7861EDEC995B
+:10839000EE7B7FC5FD0151BF3EBEE312E8DFC1EDBC
+:1083A0004A3B3D41C0FCED079D16B9FD1F78FF5CBF
+:1083B000E05D98C5AFA962F2FD67076F5116784B73
+:1083C000FE9FC2BB46ED38E2A2F0AED1247CC7BA14
+:1083D00086B679A98CAE851C0E5AAEA10E7000FD32
+:1083E00096247BFF41EB10F758FB9F7F3CF151AA8D
+:1083F000BF0FF1F7220BEEDD71FC523ACF7874D942
+:1084000032BC2F90F5251BE87961D4CFEE9F177011
+:10841000BFD80EF7A89FE1E37874F536CC1788F93A
+:1084200031F7E38423F2935AF09FD63BD16FB48F98
+:108430003B9E60F91977F87371FC899893E51B44AA
+:108440002F4C3AA5EC782251A7EDBBCD3E6B3E40B8
+:1084500085E630E7C11C27DAEDB5E0CF344F0FC712
+:10846000AB09F63DEC13B10D33DE0BFD2BEFF76BD3
+:10847000C827A1E50D234E8CFF6E8D3931DE6B5F71
+:10848000D73E7EAB2B5538533EFCB611A7E59EF484
+:108490006CF0ECF4B378F78D87ACE33E9BF4DBF241
+:1084A0002D18DDF3797C8C626211FBCEAFE682730E
+:1084B000EBFA53ECBBCA3F879F56E13BD6C7FD742E
+:1084C000DEF5D16AF6FD5CF15D6799E0BDCC96BD45
+:1084D0000BD1EF256D1BB0FF937EC9E25FA7E9C406
+:1084E000EFC70EF1EFE1CE6E335CE6EFCFFA03FC9F
+:1084F0003C4BE2A500CFA8A22FFE473AFFF14FBAAE
+:10850000D93BD00DCDBB83947F4E6CCC95CCEF6125
+:108510004FF3F556B4B17B98D1933197C3249FEFB5
+:10852000727EA4E3AF9E98067FCFF3F68D7189E744
+:108530005BE8A5E6EF53BB026C7ED13E855FE0F0C1
+:1085400051007ED4F4EF5E7FC5E76F6D99793C6989
+:108550009BC5838DFA7CF37766EDF8EBF4C727FDB6
+:1085600074BE67A4F8BD9F073E6EF0201F13595BD1
+:108570000A700B3C50B9EF874F750B3A5D565C851E
+:108580007412F088F520640671965A9DC5DFF27862
+:108590007EF3CA3DDEE44E3CFFF1EF8ACB14AE2001
+:1085A000AE4F0205D9D717F3E6CB24A5D079B7385B
+:1085B000921DE017DAF721FA8DFF69F5C701BED1E8
+:1085C000E30EB5AB6CEAFED37CC3F5D2FC212BDF06
+:1085D000689C6FF2F93B65EA7F95B69ABFD314F0B9
+:1085E000E2F8F3E5A79F82DF44CBF95F8EBB34BA94
+:1085F000EEE5328B9BC0FCE6EF401DE3FD670558BE
+:10860000FF7CA7E15B047EE6CF997E39347C43E9A9
+:1086100074727B9CEB8D1FFA2B2DF2B2215AFD5404
+:108620007E2DF0DBFE08C443468F7F04C76FE4EB6A
+:108630008F2AC60D409FE357BA73217E70AEFB00B0
+:10864000B900FB51C5F9F03E476C4D01D0EF6172A6
+:1086500031C0F9129777317E3BE7FB434ABCDB0B15
+:10866000F703810BFAFA3D28BFE8EF5D1798D707AB
+:108670007140D2C3E838BFE5F51D909F37AAB038E6
+:10868000FCD3B705318F82F2A1C5DEE4B7BC9D8073
+:10869000B8EA6687761DFB080FD33BBD24FEB1C048
+:1086A000F28CFE99A26F7A3688EF4FCE9FEEFBF1E7
+:1086B000E2BBC8824F0E25D787369BF0DE15502CC3
+:1086C000F7A4CF70FD3D6ECB076C39C9F2AEE83E22
+:1086D000306EF4DCC5A5F7C13EF2DBDF4E40BE4292
+:1086E0005780C567DE4C963F0AFB15FB17FBA4FBC2
+:1086F0009AFF4DDAFF8A56AB1E1672B4B1D96FFDE0
+:108700009D8FAF74EA37E2F9E4E3ECDC2DE6CB8F22
+:10871000527C2D857DC5BA8265193C0B7C5EEBA62B
+:10872000789C47D8C3500A6FE5BE22FCFE4441F74F
+:10873000C4E7E13CF8462016CA33E9A5BF0958F55D
+:10874000B3B0BBD00FECD17A59734D679736449DC7
+:10875000D3C2BD3927DE41A639A7A6E5DC66075599
+:10876000C7A00BFAB7920E2C3F4DF48BA13CC5E984
+:1087700021C69F22A9E04AF017A24E8CB79CEAD8E6
+:1087800080F7826DAE91600D2DEF0A303DF6FC0E44
+:1087900027C6477FCDF7615FEFEAAD4EE30ACA6FA8
+:1087A0006D496697DBB6B2F8D7D51DD6FD8C53F66A
+:1087B000A8CB033C771CBF14D6FD5B27FF3E36F3E6
+:1087C000174E27F3AA21DF6F1C700F72B3DE2FDE66
+:1087D00035E277D2E3ECAFE4D9E8E6A7207EFC608F
+:1087E000A00CE11B8F6EBE048EF6D70F91EF4F6881
+:1087F000E017CD6CC7E3B73A2DF67AFE97ADDFDF11
+:108800005ED12AA17E2772AAF41A931EF285FC88F3
+:10881000EFCB5B58BB7D5E6F28C0E0F94F67FB7400
+:108820007EDB05216E0787A61F7F4128C8DA0F4E21
+:108830006FC7DA73FCFC5E6F04EDF7C6D6E9E7B9E3
+:108840002DC8ECDDA96DBFBA1AEE994E38ACEF9386
+:108850006F0D32FEBC26C8E46C7CF84B7D45408F22
+:108860009B2415DE0B5C3B4B9B0FFC72D5D66A8CB0
+:10887000DF5FC1FB77F863C7417F5C7F70531FDC0C
+:108880003BCC1E73A8E0B71EB2BD7F16E57336BBA6
+:1088900041EDD52B60AFF2E1FBCEF85DED64E45322
+:1088A000419CDA08E501DD99DE35867D2AD07DBC64
+:1088B00099FBA7C6128B7F7A86F365367A5E3F6492
+:1088C000F3C76CFC7A9A44D06F369AFD2ABEE37CDB
+:1088D000F78F3F59097EF875B322E67C53E1A78EE6
+:1088E0002BCCAF1E7F661EE64364E3ABACFE6A335F
+:1088F0002B3F687F75BC99F1F9E95B9705AF9D66E1
+:108900009C1A64F271367FF5F4AD33CBCB69BEAF00
+:10891000335C8F0B7E027FD99C475014B4EABDD6DE
+:108920002DD6752F6FB3AE2BE4E444ACDB07FE0607
+:108930002111F47F84FF4A7A969DD3BB15010FC89D
+:10894000FDB5554C5DC0397003E80E4ACF451CAEED
+:10895000E3D16541E067FB7EC61D93487FE36BEC86
+:10896000BEF3C2A14D4F146953F96F45D0CA77EFDA
+:1089700097FF845EB7CF93E6B7E6F7792EFA90F9C2
+:108980002C3B1D92E7C467420F5C258FB8565531CA
+:10899000FDF2595AFE143EE2067E5440C3F22A7E8E
+:1089A0007F4689B702DEA18E0FFB08C4AF8D8160C0
+:1089B000F24288FFAF5F3CDF0CCF0E4E97AB86D6FE
+:1089C0003D05EEFD09476C2FFA5D5F60F7F22F9CC5
+:1089D0007CB817EABFA4FA4AD280DF3663FDCD9394
+:1089E0001AFEFB08DB83B9ECFCD1B2C9659ED7CE79
+:1089F000BF1B6DFCFB3C8737ED7FC993B5A097C5C6
+:108A00003E414F16D175366EDDBF0AD6B97EE88875
+:108A10006B21FD7D337C489CC2BB25C8C6B709BF0E
+:108A2000D743F74BF9FF79E05BD8EF5F49CCFEC93C
+:108A3000132EF33BF36B3A7EB5663ABD3ECCF9FCA0
+:108A4000F620D3BB1DFE7871B020A35F67B794AD4D
+:108A500000BFA618CE1026B84B381C8A3BF200F394
+:108A600073D83ED278BC89E1F1F993EB7B0B6AB302
+:108A7000E3F1EE2CF271363C9E18F6B1EF3AFF2589
+:108A8000A36FC6BF2D4D7699FCB4628093FBB7E00F
+:108A9000270A3E787EFBAFAE8EB3F3580F3B8F4D67
+:108AA000D602BE1ECDE1F7869A66F9F7A27E116462
+:108AB000FEAE1DCEE7B85C9D4D7EAEBCE187785E14
+:108AC00078EE861F95C27DB118974D3EAEE4719C3D
+:108AD00043B7B8DB87A759F72D8EB7297A8258FD9F
+:108AE0009EEB5B36F5010ABAFC397F09FBCDEACF74
+:108AF000B5B07351C69F4B0621FFE1677C9DE7C06F
+:108B00009FAB9AC19F6BA7FEDC52933FD7EEC47711
+:108B100025767FEE6912FBC4F2DA4C9CE7D92D2C46
+:108B20001E75BA79B103F4E5D32D77A25DFA0DE78E
+:108B3000CB71AED79F6EB1DA8D099BDD98A24F4FF6
+:108B40005AF3F5B3D99FDF9CA7FDA1FE7E29E8C1AA
+:108B5000A7EF6BBB1ACFD9F7F9F0BDA49D3EC77242
+:108B60009CCCAF033E35E9A15125F2DA683EF069AD
+:108B7000117E0FDFCE9FE3CDCCAE1D5AEF6F077F86
+:108B8000EE101FFF726325BE6F82F313C07F3A475A
+:108B9000E2E75A7EBEE6F6EB2A5481193A097BE5F4
+:108BA000CA61FAE3FAA197F0DC7C0DFFEE39FEA171
+:108BB000F0A803C5988FF7BC83EB91078278BF2A92
+:108BC000D613FB0AE558E5F5B3492BBECE66C79E22
+:108BD0004DB2BC09B1EE7507CB589C8AD7DB76B095
+:108BE000BAB06B87922C5FFACDCE10EE9FF2CB928B
+:108BF0004768FD4CE7E21A737EF559ED5CD2F1A1AE
+:108C0000D839C0CF4C76AE39E7DCFCA93384449127
+:108C10001EEF6EDEBB8AEEEFC52FCDC27F87EBCC99
+:108C200010E3D78B39BD5F54269698E13BC3F77BA1
+:108C30008AD3F94C1ABFF11CF3F7186AB95E7B911D
+:108C4000CBC18B9D5639F8588E550EAE1FB2C27BE4
+:108C5000758715DE2B72D8BDE48B9DDD3ED02B27AA
+:108C600004DF5CE744FB7322B63AB83C1FCFE31144
+:108C7000339DAEC8393F79BB52A2FE3D9CBFEFF396
+:108C8000A1DF9D8E8F56323ABEE961FC5E16724CB2
+:108C90001BDF4CEBE74A2BDDC19F30E3F1BB5C0EE1
+:108CA00045FDAA76DBB93A621D3FEE60726C0CF8A6
+:108CB000D1FF531506A74ACF2106E3E715600FD36E
+:108CC000EBDBC65F29272DEB1B9C4FB2AD7F367FB8
+:108CD000EA7FCE33D39F67BE9953764EF1F70FEA02
+:108CE0003CF34FE7C9DFA3DC1FB49F6BD27683FB55
+:108CF00037C29FB936A49D19A54BFC9CEBE1EB86CE
+:108D0000D6A1FF39EE88F562BEFE71870AFC38DE17
+:108D1000BCB91BEA6F0E9559FE3DAF629BBF25ECB7
+:108D2000CFD9ECA75D7E9EDEB8AB06D67D7AE31583
+:108D300016FFF7F2778A49CA749F29E20D6979F51F
+:108D40005AE9FEFB208BFFFD9EFB93E971EFCCC53A
+:108D500079D27EF1D0268C37B4B5EC5F2599F6F345
+:108D60005D6ED71ECFD1AC7EB1CCFCE26CF1B6DF2C
+:108D7000DAECD8D39CBE22DEB6518E4D1B6FBBBC45
+:108D8000C569D34FCC4FB3EB23D1FFDF73AC7A4926
+:108D9000AC63C7E7B9AE5712647A57C4F748957603
+:108DA0004EFFAE697A5D5B7FFBBA7FCAD12C78B18A
+:108DB000AF8F8F4366885755F378D50A1EAF1AFFD9
+:108DC000E45FFC04E27427D61FAD073E3C7DEB1F39
+:108DD0009FBE221FECF853F5007E358F5F9D8654B1
+:108DE00038E0F7B8847EE115439BF05C46FB33BD69
+:108DF00074621EBEF7BE88CF4FF591C50EDAE5F35B
+:108E0000410EE79180CAEFAF464A31AFFD1CF1F544
+:108E10005C167C9DAFDD7830C0F3EADF5DB604EC14
+:108E2000C1481A9E148BC7AD66DF511F55629FC79C
+:108E3000BCDB8D417598C52FD19F5B4F183F8DCA04
+:108E4000DAEE45B47D34364F3768BDEC63EBB0FFE6
+:108E5000FA16BF0ADFC559076356517A35060C98D2
+:108E6000AF76BCF91FE0FEE197AD6E0DBEA3F364D3
+:108E70006CB313E26F279A250279BF1B3F1A7B0D53
+:108E8000F2C9365EE1D7F0FD7BB40CFDC26FC27A49
+:108E9000A6BCB713A26EBCB4AB89B62F2A1875C096
+:108EA000168EEE7B699787CEDBBB3316867CE79BFD
+:108EB000F73DBA0BF2CE0B0BF5B18F4608F9BB7D2F
+:108EC00087D7623EF4DD62FC63BB20BFF9BB8E78BE
+:108ED00019BC5B38B9EFE45AC84B97A5A66AC85BC2
+:108EE0007F2EB4A01FFA5F7EF9B6CF3C42DBFF7D38
+:108EF000DF7FAC851C9C156D62BC23BA5A26644387
+:108F0000BDA82B1EA8E7FB639AA39A90CFEC7B78B1
+:108F1000AD0CEBE5E9F85EB560F0E15D305F5D9CBE
+:108F2000F03C996074754566BECDFB1EDE65D07A57
+:108F300051E76AF20BAA67EA260C7C3FF24C43C762
+:108F40006AC8ABBF540DF5572D246465B4C10FF941
+:108F5000DE31757ED45D8DF755D51A2DD7AB0B114B
+:108F6000DE156DC62268578CAAFE28E6F2F27BB9A0
+:108F700092C87CCBBFFF5BC9E254E97A98D547BB66
+:108F8000A6CF0FFB85CAF4C6A86FFAF6AF86ACF77A
+:108F9000ABA193447F90964FF9C8A887DA89CBDCC0
+:108FA000A416E2E65D3CBE9C5ED7C3E012E3887186
+:108FB000591EE8A1661E338776B8C7B98BCBD9BCDA
+:108FC0000893E30227F3C327ABA5AF037F16382529
+:108FD0007CBF57E823F187A07D167BCFD74C880E46
+:108FE000EFECC4BC3FE6D3AE9917BB1FF875CDECD0
+:108FF000A2EAEE329C0FF745E1EDF198EEA128DCF4
+:1090000032C05DE05C5FBDBDCA047715837B348FE1
+:10901000E163F4DF589C6DF478F930F0EFBA9055C5
+:109020000E578CD5E0BD5AC16A82FFEEDAE4ED5EE0
+:10903000CC83279EB8E5DF8F3BC4F7B9D59687B3BD
+:10904000554E2920E75B791E4E41F7F47410F1C4A8
+:10905000ADEFE412C3F27E92ED27334F3EB6537864
+:10906000587E7D1678FE390D8F35CF26330FCBB362
+:10907000F9B0E149E7E98987C17C5E912F2DF2883B
+:10908000B3E9CFADB63CE9CCBA2C3FBAEC0291972C
+:109090009752D8BFD7C1E09B929FF750C36CF65D43
+:1090A0001171DFCDF94061FB073A9BF30A7EC3F1F2
+:1090B000B741F037BF67DF3C87DDB38FFEDBEAC522
+:1090C000EB703E762F392AB373D70A59C7FBEE15DA
+:1090D00063792ABC73107C29F851F0D3685E47038A
+:1090E000E26B9D34EDF7CE26855CC6D87DCCECB620
+:1090F000B8D3FC3E40C89D5D4E09B997BF438FCCA5
+:10910000BF1AF4029C0701FE089547CBBD3B837B49
+:109110006388D937CA078C7E45ECBD86C08F9D1FFA
+:10912000FE0B5192C7FB0080000000001F8B08005F
+:1091300000000000000BDD7D0D7C54D595F87DF31B
+:10914000662633C924793399C977C20CE123088490
+:109150004908212A1F9384402C4127E12B41D0E16B
+:1091600043881262546CB3BBD64C08D218598D3F59
+:109170002DA52D6B87145DD6A53520DAA888C3A749
+:10918000D82A06A48A15DDF1A380883045BB6297F2
+:10919000D6FF3DE7DE9B99F79210B0EEFFB7BB69B3
+:1091A000F57ADFBBF7BE73CFD73DE7DC73EFD45F53
+:1091B000CC20FEF1847C037F5309FD0B103281909B
+:1091C0007A7DD0A8586879311BDF17F5EC3512A8E5
+:1091D0002F249EC01842528E07134643B9D027AFA2
+:1091E000A4E5BB4A02210E426A13152C0B9F2D8B5E
+:1091F000BBBE90903FF6E81418B56812FDD775F421
+:109200001F7FFDA1D261B49FA8D327C449C84E3D9A
+:10921000FDAF74AC074DA648FBD73BEA2BD6D2F680
+:1092200045FCBB76993EB745E05D9A28E1F76E4B69
+:109230002408F78158E237D922F3B8298690E20250
+:109240005A35B94778C7D2EFD8C8AD5E4B643C31C8
+:10925000CEB58A84ED8B7849FC37D94811219530F9
+:1092600014852FC72DF9099D0F596F0E0C77D14F1B
+:10927000CA3A0A0C21E17CE9979D00822CDD5A450F
+:10928000C74B8E25BEEDB4742411ACD3FE9EED9673
+:10929000C878AF13F6579EE3DD02E395A7A4E5B7C0
+:1092A000BA587F808BC2BFD654A0825F5F6C83F7B1
+:1092B00055F9778D893C3F60A453A2ED96DA7C8BFB
+:1092C000258A93A387CA86130AD2DDA9B2F3932411
+:1092D00042E648BE0708856BA9D1FD40BC2B32CFC2
+:1092E00079C4E4B4E41272176DFC0D7D3FA727D654
+:1092F0002F53D2CDF69A9D161383ED1BFACF850E10
+:10930000A9A28B7EEF6E4294A682BEFC7177AA1151
+:10931000BF73B42227D1170D17C7FFD2D8F06A0246
+:10932000B4221D0C9F7A867F515F3A82C29D13F54D
+:10933000DE42DFC713F29B38CF6C85D273998EF86B
+:10934000E0FB641AADA445BEBF3291D127028F1F46
+:10935000E93FDEE259A04CE8DB5E5B8AF6F4FFC130
+:1093600018E4139F3C96D271C9AD84B4D35A4A17FE
+:10937000E50B0BF07550570F7494895FA2F3FF4013
+:10938000C9C24E6FCDA52FC745C67B4BF2664AB406
+:10939000BFDF11E37E5242BAE0FCCBE5BBF618EC2E
+:1093A0004067C9DD4AC7FD47C5CAE649C285304F97
+:1093B000471CE3C303666232D3F15FA525D25D4F3C
+:1093C0003CC0576F668FEA6CA7E3ED34B27602BFFC
+:1093D000E4921C9C1AF5FE805495A9D0FA01474AE4
+:1093E00041AB84E3117314FFD37109C033E36F5FA2
+:1093F0009C9D4AE96118CAC6B3D3EF5747C9C1C497
+:109400000A36EF36CEFF6D4A1C96E5716CBC032E12
+:10941000CA26F09DE1743E541E0EC6FAC634225C84
+:10942000FF8CED80EFBB683D99D32DD9C8EA2F5949
+:10943000997C7E6965E37E9F97C909AC9D963EBF86
+:10944000E3EF753034EDD75ED9E925944F66CA4E07
+:10945000AC9B4D8D840C85975E02FCD45E42E7D3B5
+:10946000CF388F2B3A46E732365FD710427A005E0C
+:10947000AAD708F26B0B7E476F7A2B1BF8F8E1E254
+:109480004E05F878AD81D474F5D3DE181732019DFE
+:10949000C968BDEE492A4FA4B84207F27C2F9799BC
+:1094A0003F775525827EDCA5B0F91A65D208E3081E
+:1094B00078D63603C3119270318E04E9F77E03F03B
+:1094C000C1F7733F417AEB8BA99AA15D0DC4EB57AD
+:1094D000A2E86DA0ED82B911B94CB89880FDEB2FD0
+:1094E0008E2781A4CBE9ED227C4F52299CC9517073
+:1094F0009E988F706AE7A7C55F90C32BEA9E5CFDBC
+:10950000341205570951D6C2774AA89047C347C8B5
+:1095100024E5E4685A50BEFB46463DCED60B5A6E53
+:10952000B6A09EAF00FD5845E74AAE65F2A450DDF7
+:10953000BD4229390A72DFBBCEF07E429E77FEE53E
+:109540000B7F3CC5D3CEA3436D6BE8E39BB91EB83C
+:109550003991F189D0EBA067AAE32370A7737A0849
+:10956000B9AF3095793E89C2DB0A85F1D52189D121
+:109570009D107716F42F9AC4F402A990C8705A4C23
+:109580009CC6E443F43B07937740C9E444C851F5D3
+:109590004275BB0BD06E029471D87EB0F5A9573FCF
+:1095A0002633FDA88F4DC8238950660708D5D39B65
+:1095B000FF5AE66C8175E70D83BB139A7733FC94F1
+:1095C000D4AE6ED5D3E7862E49892191EF5B9A24DC
+:1095D000CF32E0032E87F5760667BD3D681C464115
+:1095E0004BAF67F06676ED91F4517C9059C7DA99EC
+:1095F000AD068427BD862ED074BD4A6FF46C2194CD
+:10960000FFE3E1391D2FCE4A387E03524621F6236F
+:10961000ED14A5E96E36AEC51D9096D2711A38BD0F
+:10962000DB745563405FB525C7B9415F55DA7C49A6
+:1096300056E0DB13C1603CE0F9448FDE07F4B779F4
+:10964000EC5647647E4E5949073D107782C1D5C11B
+:10965000E91DE1FF87B87EED64722F934304F14C5E
+:1096600082205FCE05B9A82F45FB641BD757C9C41C
+:10967000B7C382EDDB08D281E03C93D78CE86C77EE
+:1096800045E81459AF4715C07A9DB33EA85F42FB29
+:10969000BDB84957114D6F5116703D46E731367AC6
+:1096A0001E83AD4BA29D21563DBF483BA6B7E2B8F5
+:1096B000BE2EA9B52F80F9D5AF7D3E2E867E32BD58
+:1096C0006BB31487FAED616C27F04EE1980278D6FF
+:1096D000F2537A5789B305E8FABAC12D9181E1AC0A
+:1096E0006F923DCBA2ECC4FAB546A4C36623A98B06
+:1096F000D6E384ACC1EFCEB732FDF60B9BF746F84C
+:109700006E43F7A346A0EBED5B3E34FAFAD137BDCA
+:10971000FDAF104F12E54FA0477D8D2900F32EA914
+:1097200065FCB972AD311043E953BF6D7B5007F64C
+:10973000DA7DC40DF25BDFB5FD603AC55346BD6707
+:10974000022C25C994D97AC644F45F7A7D5082757B
+:1097500025BD6B713DF2796A9C1BF81CEC2C58FFFF
+:10976000CE9658FC125DF7CF1AFCB94EFAFEAC2B20
+:10977000D6EDA7EF0F9A993C0B3CBFBA7DC6218965
+:10978000E2357E474C10CA7A9BEF2E987F7B8BB3D5
+:1097900004E8D45E4E14E01F678C7727F2654ABC5C
+:1097A000DB2F5DF9BCC53A2D9E4FBC8FC9C32FADD1
+:1097B000095C0E4901D8170F59E3B14ED763D42F76
+:1097C000070D0C4E3D87F34BABC78F7C09C248BFDA
+:1097D0009B49027B8CAEBEDF8DE29F75308F2B875D
+:1097E000B3CBE8A470ADE47AA4A4768BF47114DD55
+:1097F0007F6C95995ED9B65972221F6F6929B7633C
+:109800007B1203FA639B84FD56D2F7B745E90F310B
+:109810008F7EF4C826988FE544CF7EA64782C86F16
+:10982000025E414741AFAD56277E7F3AB5D7CC386F
+:10983000DE927AA0475B3A1B4FC8B5560EB772BE90
+:109840004EAFD922E9D06EEAC179AEAAD1235DF636
+:10985000CEBF65198CB3CA9E960F7CF8F86F8E1830
+:1098600025FAFC39DE6F5587E4C175A6E388712EB1
+:10987000E87BFFBFC9B03ECF644B28D9F0DC11A311
+:10988000933E9FB953C2F156EDDCAE5F6A89F09FFB
+:10989000EBCCDE5B803F5775C510B3047461EB976A
+:1098A00096EFA87E4079207E23F757286198BDEB7C
+:1098B00082F54DE8CF2F395CC4E22DD4D9411F8EFB
+:1098C000CD07BD77883F17E397C7BAF79A40FF15D2
+:1098D000307BD675E628C2F93B8E473A7E10F527D5
+:1098E000B5CE601D13E3F7D5FBA3D14EFD82AF4784
+:1098F000946E6FF5A7FFC5F8AE27AA89333E8A1E7E
+:1099000080E7283EFAC86AC4EF7F64D5E378FA524C
+:109910008627BD91CD5FBFC61400F97AD55AC1F034
+:109920006333217E0E707A1FE0F46ED3ADC96D648F
+:10993000EBCEC700CFDEF90984E917A64F1E7F568C
+:109940006275BF25007E55BD6F0ED299D8CD6EB41D
+:10995000077DFB8D73E323FCA6A5AB73C71E23CC49
+:10996000636617E3EB08BE022A3EA47A0AE90D7487
+:10997000023C0A7917781478C9E5F26EB479BE040E
+:10998000BB49F87D968561F4A7B57299C8FDBE46BE
+:10999000F0FB28BC456E5687BFFEFC3D0197E82FC3
+:1099A000FCBD954DBFCBFE84AE0377A4BE8625F8E3
+:1099B00011607F0BBF42B4576C6CFDFB9AD33985A5
+:1099C000F3D1CAC22ED4B72B3F6944B9B15430FD8C
+:1099D0006039A1D66BC2AFA00E37EFC7F4E50A7BA2
+:1099E000BC5B9206D63F2B24E245BFF112B53EA9DF
+:1099F0007D5E6FE673E4EF736DCC2F38B595120082
+:109A0000F57F23DA9B038FD778F85AA0F376D9FD38
+:109A100024E93B2E091E9380CE2BB97D7D765BD940
+:109A2000B57FA47CE2DF9AE81E4EA7FCD9B6D9FF29
+:109A3000F047DAFFEC96A96E7087EDAD5EE49BB05F
+:109A4000C3ECEE74613CA302FCCB96AE7D09102FF3
+:109A5000F9F4DFC71580FE9BCAE13CF3ACDC047867
+:109A600039F3ECBE87FF42FBD505F2938115D6FC96
+:109A7000EB2BC610855F1778F46FB0AED56D4944F7
+:109A8000BBAFF5DF7F3105EA2BB724A21E6DEDFADF
+:109A9000257BBF95BD3FF3CBCD5300FF7BFFF599F1
+:109AA000DD305EBD37C10DCF3FFDD767A680FDF627
+:109AB00063CAE70067BD4FEF413C0ABED6EAA9ED95
+:109AC0007B900F059F50BEC67808A961FA46F0F159
+:109AD00051D05BD4DEA82EB5B44179F406730DF2F3
+:109AE0003397CF8605D6CDB8FEF95D7EE83FDB6BB8
+:109AF000CD073FFC763E7FEA8333BF94720DF8C9F1
+:109B0000716382C60CDA6EFEC2ED5300CEB65852B7
+:109B10006C467EA50F295DAA51D8E8381DAF7E2D71
+:109B2000E5113296AABD93B9E84F6EF986F2EBDBE8
+:109B300006E60FB7713B7CFEC20F255C27885E39B5
+:109B400029E21FF2E5D6373D8E27DAF5DA6D1C0FD4
+:109B50006DDCFFA7E3E37A53B49AF1F70169492B6F
+:109B6000F82F07EE0D4E02FDF9E2E9BB63EBC744A7
+:109B7000F339EB9FBE93E987553B37B71869FBEF85
+:109B8000E5E617C167563595918F93805F2494B7AA
+:109B900006BF45A5075B6C4CCE921562BF0EE20F67
+:109BA0007A62B74049C83103E2E7491E87A1224ED5
+:109BB000F17EBE65A103ECE10D065FDA04F85E1BE1
+:109BC0005FC7B63078697FC55280E329D715E03882
+:109BD0003D061BD82D04E360CE57666C6991227058
+:109BE000538ECE86F50CC62BB4C0FAE3AFC1F5C7D1
+:109BF0006974033F9C81266988AFBC456323F3D613
+:109C0000C60B40EF55C583DD58F233DB844829E2AB
+:109C10000B5A7ABCCFDFA72479B0245B93504F0E48
+:109C2000669FEC9D7F0EE5E7F1973E447DD400FCF6
+:109C30000EDFF77DA25A97053F6D78E143E4F7EA1E
+:109C40006E469F0D52681DC88BFF0669FC9320E786
+:109C5000CD1EF23135341B389FAFACF87039CC7F54
+:109C600068779A02FAEA1C97838629A111A027CF68
+:109C7000BDC0E4E0804E87F83CD0397A33AC43D4A1
+:109C8000AE45566E687476C6207E99BD5F52BBECB9
+:109C9000D17258F7EB881BE4BA616755A613D79FBA
+:109CA00018C4AFEB898FD6815C58A9F56A76C2FCDF
+:109CB0003E980EF035D4930920DFE9D33C2F409D28
+:109CC00074337F36B9D65EA247FE5A3C1EF86B430A
+:109CD00056D73A58DFFDD43E85F96C307494EA6962
+:109CE0007D43B953A118A3F8A1EB1DF4EF5DEFE696
+:109CF000EC44F9B52F72B74BFDE8871736A7C27849
+:109D00000DB94637D82933BB995D4DA85D0DF036A6
+:109D100074B7E402FC339DD7B965FAFE738E1F81D8
+:109D2000A799D3289FC2FCFC1602EDCF197A6E8149
+:109D3000FAB9E728034A28AE2500DFE93C693CE888
+:109D40008B575FA0F64F5E841FE39FA77610ADDBB5
+:109D5000F48AE446399B1D134DCF0E035BAFAC7CF8
+:109D6000FDC9A960743DC5E5E89458276C46CEDF6F
+:109D70003C4EA9F8F3605DFE9CD31B8703FDCFC763
+:109D80005DB52C887254BF8DD96FF6184FFE3D51CA
+:109D90007C6B2F63EBA588173B641D8B1B83FF62D5
+:109DA00007FFDAD929233DAB91BEDFB38F2C30D327
+:109DB0007A4C12832B3D575AC0F06244BC38927CD7
+:109DC0008F82DD1C1E2515753AFBF27B5C128F839A
+:109DD00025790B217EE5A0FE462BC6AB4B7466169B
+:109DE000BF76433F875C8DFE6DD891E6EE54C93552
+:109DF000B30B4F27C7333A07DED45747E9FD885FD7
+:109E00006C76835F735A17D49BA3E2D9627E8196E6
+:109E1000D89A687D654D62F6416014A901F9A7F6EC
+:109E2000B905E39F0AB58BC0FFEEBCFE97CCFF6E71
+:109E300045F8FF6A53D8F7E83CC04E73E47857B34F
+:109E400075341EE175E49025D0CFD19A2A011C11FA
+:109E50007C2A9B019FBFE0F414F67903E563B0EB25
+:109E6000889EC985F32509E31603E981085F333D20
+:109E700030B39BD137AE82E90132461A0FEB3DE891
+:109E8000B7AAB14C0FB8C645E4B7C1181A017C781F
+:109E9000A57AA03C2E80F2533E7A04C61BC438E754
+:109EA0000CD48FA4CFCF513945BB96F37DFC8B8C5E
+:109EB000DF055D0E1AFD285F0787C622BD012EF063
+:109EC0000B857E6C78F1C111BE7EE30B623DF363BE
+:109ED0005CF2F450C2E8CEC785BD99F8022CFDB003
+:109EE0003EC435B1F59954E8B07D7BEEB15F417B5E
+:109EF0009DA92B087C63CEEC990CFEB63789C5CBA7
+:109F000066CA6C7F28BBC94BE0FBC9E09300FE3AF0
+:109F1000E302A057443C460B5719E77F11F710FEA8
+:109F200005C491A17D7D12F3576EE57C756F92A4F7
+:109F30005A9785BD4DDB0F050367A0F544F4FBAED2
+:109F4000E243E23B625D8BE0B945150787F9548D2A
+:109F500019B85DC71EA637F00FE8F262DAE6765C44
+:109F6000579D48CF87387F57DABC53926869AB60FA
+:109F7000FEEFAF455CD3378AC5ABCD4C4F69C717F1
+:109F8000F54720EE3B72E0F553F99BCCF6658887E8
+:109F9000805C603C01C4B6B4C20DF37D84E34FDB4A
+:109FA0004F4FF45F8684DDE48A8287DB5C10C69DB8
+:109FB000D2CF3E53EF7727A9E3E0DAFE03C1DBA659
+:109FC0008963B7E5EC26107F8A332530BE2597D00C
+:109FD0009E7F908F43F9DE5D85FA8DC5B106FB8EBD
+:109FE000164EB3530DE795E2BF4DB7BD0EF8793766
+:109FF00087976CBAB2F9FD9AD3EBE166139664D9F0
+:10A000002855BCDFE276B6C03A3F6E97331FED6548
+:10A010001D8BD7C54F217F9229BF261477E4AE014F
+:10A020007DED55C39D52134B8251FB81693E9BAA26
+:10A030009E5197AE6A9FD53854F57E48D335AAF71E
+:10A040002E7F81AA9ED3769DAAFDF08E52557DE487
+:10A05000C6EFA9DA8F0A54ABEAA3B72E50B51FDBBF
+:10A06000B544CD1F1AFCB5B774D580FC4CFDDB1789
+:10A07000A5A86F5E2456D8AF23A6D07890B771DD1F
+:10A08000EAF99F4BB2211F2716ABF170B5FC30F5F2
+:10A09000E2E5F956C8511C617C1177A9ED4F721E9B
+:10A0A000D435F2C2C79D62627232D8B86BE26ED10B
+:10A0B000039FEF864A943DFCB646BECB6B12D93E59
+:10A0C000CBC5EA41EC66260FF3624823F0CFBC38DB
+:10A0D000568AF763ED4CEE87DB793CE90AF9F738ED
+:10A0E000E7F7A303F12F356F92815E1504FD69A593
+:10A0F000A2E54F10BFA9D507493E9597C7F97C3611
+:10A10000F0FE1B9B151CEF67CDA9586E6A76E2F333
+:10A11000279A73B10C34BBF179677331965BA81D34
+:10A1200007E553CD15586E6DF662BBA79B6BB0DC8F
+:10A13000D6EC63F2A8A5DB451BFA33F3885A6FCD42
+:10A14000AFD1EE87F9D93AA4E93F9FACEF817D7793
+:10A150002D3EFAF4971726F6B74E8BB2E9444960C4
+:10A160007F54FB49F6783BEEBF4D2413D13F1DA42D
+:10A17000FF57CD9EC07EC3E07CADE51F72E99EE136
+:10A1800060076BDFCF03464EA7FCFBB8ADDD6FE980
+:10A190003B2ED5876B439455F240F6A2E2C87B3440
+:10A1A0007CE9D127AAFC5B513EC7F9AB84F36189F6
+:10A1B000860F37703EFCFEFF513EDC6B8E473B7ACC
+:10A1C000AFC199E988A2EB5E731C3E27B9C43987F9
+:10A1D000D245F210C545F972BF9DEDD349E031601B
+:10A1E000FC779882F10BF355C639347894A879ED51
+:10A1F000A2E395D0728A0DC70FEA617CB72EA22F19
+:10A20000719F3E36C2CF725F7EA0E3F88D14CE5FA1
+:10A210001B88D348DFBF6777AAEC8752BD7C59FD06
+:10A220005B0A7294D717FE3EFDAE528E9EFC6F966F
+:10A2300023C1EFE452CE306F7CDFF7255C8E16DA57
+:10A24000AF6FF78F89F07B29D85F51701CE3FC7EDC
+:10A25000CCCEFD1B6E6F007F14F46377BC6E57DBB2
+:10A2600067578BEF12AEEF0809A583FC5F6D7F2A5D
+:10A27000397AE857624AF0C7E55D7DFF81F0D9A7DA
+:10A280005FB7FD8AE24054D34830FE720EDD729310
+:10A29000C50FFC44361ACE86A2F8B829CE7BCA4E2A
+:10A2A000DB771B4837EC2FD065DBA92423DF235E47
+:10A2B000E99FD744EBF9BC3ED12F213FC7D04A13C9
+:10A2C000C847E8E0D7A02FF27939919710064D05DD
+:10A2D000B91913AF077DE31668E2F1CC22519D4610
+:10A2E0004D9564913207E31269B50DDC910E02FBC6
+:10A2F000E2ED92BB4DA6DF93535CAD00D4F88A1219
+:10A3000099E0165B079693484F2BE4CE4D216119D7
+:10A31000DA179BBA5AF514CE21E4927212782DE521
+:10A32000A955DF50D7F02B33DB1F6E32B1F207B1E6
+:10A33000099D507E6566FBC5FE5282FE8FFF83F845
+:10A3400000F895F74BBE3807C5CB573ACF22F88EA9
+:10A350003E29D3C1E3A91F8530EE2AA1DC975A0A12
+:10A360006B6E437965CF11AFAE483BACCB7DEB3F15
+:10A370007E80C5075A1F647CDDDAC2EAC31CCCCFDD
+:10A380004B77307E1EEBE0FA1E28938CF8413A980A
+:10A3900089DF0FFBB82497E2B788E11BF1673984A6
+:10A3A000F88F255D883FF3BC8D081F9538CC5F91F1
+:10A3B000825EF24D5CDFF1061AC764EAF098289FCE
+:10A3C000C42D0CF80DFD8CA3E774D2CF3162BEDD35
+:10A3D0004CD9371EF046327548F758319EE2E5F900
+:10A3E0004D8C3FBF053D265F093D0CA5EE1E0F6558
+:10A3F000B1B9B112E6915C2D5DE6396C62BF1959B5
+:10A4000075771AD90C7E7F9D9DA4427E9CD16242B5
+:10A41000395A9BE5C4B8BE710471AF01FC797588E7
+:10A420003F315F91C725E492E2652EC06F0C481F53
+:10A43000029E8CA98DE8AF117D2803DAED9618FDF8
+:10A44000B5F27C2BE7078A50C6CFE4F2EBDBF65976
+:10A45000D6F7EC286CC367BE5E4CEB25D69BED0AA5
+:10A46000212336ECFC9E9EDA25DB8F10143669C35F
+:10A47000A18740FF6E9F6BFDB983B6BF2B65E94393
+:10A4800006AA57B62F92F0FD17F09EE2F7BD12D242
+:10A4900005719D9F24F95639281C0B5E771E801C80
+:10A4A000B6ED07EFC806FCDBCBDC2119F07D738C21
+:10A4B00013F67DC8250A07C5C32F01040A6717C410
+:10A4C000130DECF954FABC56A067003D3351D4FD8E
+:10A4D00012D1D3FA6451E7E36E817A4EA4BDD04B1A
+:10A4E00039CBEEFA8F1F821DD323635E8454C3F6EB
+:10A4F0004926F272322FF37969AB6076CF8AF56420
+:10A50000BC44FB0F5B26F6796202C3E97F0ED94497
+:10A51000DFD3FAA947C9789091930667AB05F87124
+:10A520002C71431C99E8197FBE9D650D40BCE294D7
+:10A53000445A31CEFC208B33431FD86F742FA3B401
+:10A540002E0493D0148078F95BCDC4B37678947ED2
+:10A55000A4B4F114B1F00BC3C318F49B2691C81F27
+:10A56000CCB33C822794ABE9BC3EA39EC5C9623CF8
+:10A57000546FC2FAA5D1B76612483521BE5C98A7C0
+:10A5800021CF200AC09B5D11A44B29D5A79E12D4D0
+:10A590009B13886F5F0F2DAFF56CE77A34D00A53A9
+:10A5A000C410470EAC8F4E3DD0B38C5AB050AF2084
+:10A5B0001D587E8F746159497AB0BC9184B1F412F0
+:10A5C000C500E54B0E17CAD31413D5E320FF7A2735
+:10A5D000C6034FBEA6B8212E595DE1333AFBB13F09
+:10A5E00096EB09DBA723BE6CCC1FD3FBB2E745D9A2
+:10A5F00013276BE72FF2D07E4E9D3ADF728F83D9FF
+:10A600000BBFE3FA7383C4F5C82A29007EF1865A8A
+:10A6100023E6D71C5D2575427C9EBEC7B8ACBFD66D
+:10A620008471BA0D066716D8177F7138597CAD7ED4
+:10A63000FB0F401F1DBD61451AC8EB71C937BD8EA8
+:10A64000F65B5EC9E2EA44EFCF9A1B25E7A7163313
+:10A65000B8443E42AF3DC3E5F82FA05B20FE4EE17B
+:10A6600047FD25E26E0BACA867CA498D1EF2A13FDB
+:10A67000E6F30870BD20E4A74EF081DE6F4CA7FD25
+:10A68000E6B95D88C7050116B72DD79320D8C3BD9D
+:10A69000F0D76CBE9750FE5850B747BF7C0CE613FE
+:10A6A000613C7339CF2F92EA9C0FD861DFF13EB63F
+:10A6B000FF12C91F62FBC7CB176E5F8471856531BE
+:10A6C00004E462F9C647DF07799F5F37C309F8A33F
+:10A6D000DFC3B8E97413DB1F34D1EFC37EDA8C3AE1
+:10A6E0009EB751F7A31EE04FDACE03F6F074DA5EA0
+:10A6F0005F0079392CEF2DD6CFF28762A789FCA1B4
+:10A70000C6030EC81FBA93B8FDF4B3F3376D96585D
+:10A710005E2B41BF65307BE65F7E74C98AF62DAC47
+:10A72000FB43283C4DB213F6F3895EC1FE0B4C0C83
+:10A730007F6D75ADC8877FAEA193A0DF9DD7E16225
+:10A7400079F0FB997CCFABC90F411CC9541183F33D
+:10A75000048D04715F13A94079CF272C4E7137CF38
+:10A7600037A756AF0ABE3EFE01D577B03E0C645700
+:10A7700089F9989A8C0C5ECDBC84BE00BD12EE4760
+:10A78000CEA58A57991DC64B907B90D702935B8EBE
+:10A79000D7018B7965A637FD04E3E5E43EB69E98C4
+:10A7A0009F92601D37D9FDB780A97D6AFFB0072C45
+:10A7B00088AE0E12ED17984ABDB745E7233F58E221
+:10A7C0005D149D17E14E66FC8DBBF8C0E3AFFBB393
+:10A7D000E13BA7DF60EB83FFB61827C6A506C103E0
+:10A7E0009D7A40977305F35DC6F5392F23F6A2B322
+:10A7F00015E859963C14E129ACA892C1EE7876F39D
+:10A80000C4B7AE257DE934101F69F1F37592676610
+:10A8100032B3AB7557625797CB9937D753FEB9B060
+:10A820003006E54AAC8305401490DB1E12A0B20D41
+:10A83000EB03AE1B696D44919C10AF84DC693E0E46
+:10A84000B0718D89E855F14A4555CFA84B55B5CF24
+:10A850006A74AADE0F69CA55BD77F9DDAA7A4E5B24
+:10A86000B1AAFDF00E8FAA3E726385AAFDA880579B
+:10A87000551FBDB546D5FE029D5290CEA7F0F7B24A
+:10A88000DB0FF4F57B7AC61445D6F5B15D3E55FF76
+:10A8900089A1C595A09FC675D7A9C62127A85D66C1
+:10A8A00082BC9E464E0FB70C7AC24D95EFCF5C80AE
+:10A8B00042F61EDBD3BAFBC40D9F829E5E506388B6
+:10A8C000D873D08BACC7B8A35B63076AFDE215876A
+:10A8D000FC072C14BEDAD7FDEB80FFDB93D57E722C
+:10A8E000B96CC1795D3826635E491D70A63D42C7CB
+:10A8F0000B3010CC7B0F09B0BC0FF5BC851F5D0B76
+:10A90000F8A1FD16D07182F4554CAA9ADE66A79A7A
+:10A91000DE71B96A7AC7BBD5F44E2C56D3DBEAC9CF
+:10A92000ED17BF49156ABA0BFC16D3FF017EBF6B4A
+:10A930007CEE00FCC591A838C324D4A77FDEC8F5FF
+:10A94000695F3D30C754D4570F08BCF5D10716E6F0
+:10A95000AFF4EA838D5C1F6CD4EA03CFBE340ADF08
+:10A96000041FF51FE9B8EF2C9A98017A2D9DEC127F
+:10A97000F9FC3EC89FA1F2FD6AF204D8F77387FC88
+:10A98000B00E6C8A413B72FB811168E71F1D4E2699
+:10A99000A3BB50C1ECFC762383B327D9C2F28464F5
+:10A9A0006F0FF437343506C13E7E17FC69D8FCD1F1
+:10A9B000E80BA2D1775A3B58E8935393193FBDF364
+:10A9C0000609AC91C0EF3E82FEEED5AE0B83F9DBFB
+:10A9D000BD7A74215B3726F2922CF1A3FD2ED6911D
+:10A9E000D6629F0BF2F60B4C1E99E8A2FDEF10AE5B
+:10A9F0002B53891FF5EEF515EE9FAF26602FBD9303
+:10AA000001F692D60FA778FE92E1B9777F55854F70
+:10AA1000EDFEEAA564B1BFEABD941CB5BFBAC3ECB4
+:10AA2000467EFA7D2DF33B0A8F0C6BB5D07EC9B7FD
+:10AA3000BBDCD06F87D5BD0FEABF5FC5FCC009C7BF
+:10AA40003C32E429E534BA305F6D87CB5B06F5DF35
+:10AA5000DFCBDE171DF7611ED3B026F6BE604DE3D7
+:10AA6000BE783AFEDCFBD9FB973E5F87E784026B3A
+:10AA700078FF928E32A8FFFE01F67EE289402BD449
+:10AA800047B5F1EF4B5DFB12C0AEFC6789E5D769B6
+:10AA9000FD1DEEDF4CE574E84347EE074CE1ED8524
+:10AAA0003F33B586D16759D83B1DD94B4327AD9D60
+:10AAB0005E4E7C589F41FC58DE400258CE24417CBB
+:10AAC0003F8B84B07E131CD1A1F52AE23440BD2215
+:10AAD0002517F97A36757531CE50EC36811D6EFF2B
+:10AAE000E4B7FF401222FBD562FDEFB07957817DBC
+:10AAF000602FF3DE0B7641450AB35F23A5D87FF6BE
+:10AB000067BBE9FBD3FC3C5264DFB908F3226893CE
+:10AB1000F560BF4E4A61F92939EB1BF5208F376686
+:10AB20004A6EC8779801F62DC54FF0277A2BE4B509
+:10AB3000012DFAF38323F1304DBC57EF477FA2403C
+:10AB4000768E062159FC93A71E02BF780708643A47
+:10AB500055423FE99AE947E78BD92F83B53BC6F3C6
+:10AB60006576F0FDC7395E970EF9335F6D1F2D4E88
+:10AB700061F69128271CFB6EE755B0C68FF9D37399
+:10AB80003B6308CB7321E990CFB29C34225D4F8E9A
+:10AB9000F51BD8B945A67FE672BE9BCBF9E9E4E682
+:10ABA00018A4C3A9DBA48044E159BEE9D5E3C06F72
+:10ABB00003DA476386A39E99C3F9739EA971513D39
+:10ABC000F0B5B09B7E728DFCCD68C4A35AFF0D60BA
+:10ABD000FF39785D7C4F9E42FC0E0ACF7B8B98FE3E
+:10ABE000CBF04BB81E5CA9FEB36BF45FBAF89E873E
+:10ABF000B21CAD670BFD57CFE6EFE06546BD76FDB5
+:10AC0000F0B500FFA7920E09EA59248CA593286B92
+:10AC10001C3910D272EBA09E72607F0B8C6F057D89
+:10AC200007F37E706F21E83B038F071B4C74DD0434
+:10AC3000BBDCEEC1A44DFDFEDE78D94F5320BEF340
+:10AC40001DC7CBA8E5340EF8FC1383A50DE3BADAD3
+:10AC5000784A9FF88B3AEE30B983E143EA10EB81F2
+:10AC60002F15E6096992AA75E15AB713CAA9921776
+:10AC7000F548A5DDB723C501F189C64C68AF33851A
+:10AC8000645807DAF9F99C767E3EA77D84F0332973
+:10AC900035A1F4E4229F8CE3B45D976C5C07F1B6B8
+:10ACA00075B1E1F61C98D76E1D647A469DEFE3FD01
+:10ACB000F879C53C85CDE361F80EED17AB7316014D
+:10ACC0003CB1B27304941FE92815293C49C48D7521
+:10ACD000A3AC385A5C18577C2D05992F1C2BD1EF4B
+:10ACE0001C7B5927811F9E77ED4736F07F9FD9D572
+:10ACF000B9B593B2D09787D8F2FBF056D91F43C7A6
+:10AD0000CF7B615ADC1BB4FDEA9799AC8E2BD6A1A0
+:10AD10003EFCCC48D6433E4DB549F6EA29FD3FFB03
+:10AD20003ECF6FD1BBB3ABA2E20473D3585CF7E85C
+:10AD30000071BFF18925BA540AD7D1B4FECF819EE4
+:10AD4000E27A559CCF23B94EC4C3170EA2CAC318CA
+:10AD50009F78238E23EA868B56E28B3A2768D07B36
+:10AD6000091CE5335CB4E3F3446A8F425C3FD15A7B
+:10AD7000AC07FE2B25CA7E8F84478391BE8E567604
+:10AD80003E299C660960BC6F923EDC6B070E8575A0
+:10AD900087D991188F75C17E88DA7E1C47D4756D6E
+:10ADA000FCF5125F270C9AF3FB1138D9B97D8FC9D6
+:10ADB000129461012C74E7829EF6587E7B9CE58993
+:10ADC00051FD1005CF7D499E69691322E78D97EAF1
+:10ADD0003C3351391CD5D9C01FD5DB4C7EC81F4C24
+:10ADE0009C6CC37C3AF1BD29A98C3E3BE9D205F4A9
+:10ADF0005174C487E7DD35F35D4BE5CB45E1C84DC4
+:10AE000065708BF642AF2D12F2E5B7A29DB390CBE1
+:10AE1000D71369ECDCF42285ED977CF4E0E70FC0F2
+:10AE2000F3C547628D80EC5B179284B1B49FEFC786
+:10AE300049873D4EE063F71EC877218F307B42295A
+:10AE4000CD2D62E7D3A7E1BEA7E4CF407D7BA5EB84
+:10AE5000C5FDCAE2B3C017B10901A742C789BDE663
+:10AE600034E6CD4DA4F4877994811D91D30F3D2D07
+:10AE70005FEA802FB474850F001D06A36F2C3F3F3F
+:10AE80004C486844743ED8FD4AC9D9D40998BF1AC1
+:10AE9000B441FEE3CB318CBF0E51D2D2FA9DBB47F9
+:10AEA000617CECE934DF196827CEAD92FD613C1777
+:10AEB000BB3481E7A3A57AF01CE92393ECF9ED4EAE
+:10AEC0008E6C5A2F335931AF6C612A931B318FAB83
+:10AED000E55F3BAC41C0FF9214E894069FAFC8C742
+:10AEE00015F33C93CAD67F518A7968CFBF9DE1FCA8
+:10AEF00077263501CBA7D3BC38EF3BABC31F5873C4
+:10AF0000E0FE037E8FC020F3BDF3EF9CEF95D2F5FA
+:10AF1000520A61E77B63AF0CAE35FF9FE0FA3C95C8
+:10AF2000C3957765706DF83BE1F210469FC1E0A2D2
+:10AF3000F4FC1CE48F4C0BE3FD104B6D5706DF4B0C
+:10AF4000DF017CB62B83EF69842FC8E09B47DC864A
+:10AF500054990313751E457B0E659E9EAEAD0591FB
+:10AF6000732A3A53C0075DE6E49A08E8D76F7B1E60
+:10AF7000A5978EC9246805FF7C770CC6F3893B3CF6
+:10AF8000227A5DDDC3E5E6E934CF419097A523B889
+:10AF90005EA850B73BC8F128DA89FB1648A50ED742
+:10AFA000B7F6DC619D2CDF974DD99CE9C4FD82C3C7
+:10AFB0005C6E45BEAFD8E7BBDB5A5707FB1B625D33
+:10AFC0005A774D5D2EEC6B7852FB5F977AE5BCF9B2
+:10AFD0009032CC30301E56CA3B8A1AFBD91FD99604
+:10AFE000E40BA546E5E3ADDCFA9A322C2A0E349642
+:10AFF0008474CCDE0FEB58BC97E7C7A45C1DDE77EA
+:10B00000C0980ED0CF5ED4CF629D6878F1DF9CB03F
+:10B01000FE507B80407C371C1F8BFABAF59AE2DC2D
+:10B02000E8FD1C5D9A58CFE501D673A3EA79B0D943
+:10B0300044FCD1F7339C66F73344EE658823FE2841
+:10B04000BE8DD83512F1F76BD7E8F1B9A0CB4076B9
+:10B0500082C8670D3607AB3F31C0BD16C5B3A1DC52
+:10B06000DBEC99FD09F5EF362A251EB0231CDE43E3
+:10B07000D59F44E139A5A647554FF31DAFFE240ADD
+:10B08000BE8CBA90EA7D56E369D5FB214D6155DD52
+:10B09000E5BFA86A9FD3466647D78777986647B7C4
+:10B0A0006FD3B1F308A58526CCBF1FB95151BD1789
+:10B0B00079B206BBC893D561FB518154D5B8A51EA2
+:10B0C0008BDF0AF6790B9383D15B9DAA714AFE361A
+:10B0D0001BF78D888D58619F6C6C57AEAABF4129B4
+:10B0E00056B5F798583ECD4665B1270DEC09538902
+:10B0F0007A3CB24735EFDEBCEB41F261F4FA07313E
+:10B10000FE087B93930AFAE65F6F543CF83D2DFFEF
+:10B11000FB7F3489EF0B31BF9AF22DEEE7842513C4
+:10B12000AEE3123F472CBE3387F36DBD866F23F726
+:10B1300090FC7D7CBB49F1FC16CEB78A7B5CB4F3F6
+:10B14000FC611AD3339F19FB7FBFB857AECCAAFB63
+:10B1500052227C6FC1E79F958A7B76D87D29ABAD63
+:10B160006AFCDEC9BFF3308F5FAC8EF7A4D82E9394
+:10B170000F66B8184702FDCA71023EFF6CE8E5BFD2
+:10B18000F7C3ABFE9E3CC0FC8CF89CD2B15FFC3C8C
+:10B190002CF067EBFF7D7B2FFED2547AE3E134275E
+:10B1A000BB9FA6F73B99F81EFCA6FEF5971D9F0FC7
+:10B1B000E6371193CF8D7AF83BF79708C27BB5F647
+:10B1C000FA921406D760E3BF9AE6494EC5FC936F26
+:10B1D000B76EC7C21A9D86E33C0B72B9CEC8CE11BA
+:10B1E00052CD84F10EE10F11ADBF94CBF2DC16A568
+:10B1F000FE16ED88588841D07539F67E33EEAFDC07
+:10B200002A294680FF1653F8FD9FD3F6275E8E311C
+:10B21000B27889F087E264D8B7BB5238459C45DCE8
+:10B220008B007172D077E3A65E83E7611E013F0F4A
+:10B2300060E0E71A1EA130A451FD9377646E62109E
+:10B24000E804711EFA3E01E64BE14ED459F0DCD21F
+:10B2500040DF4FA40A2CA300CE87B0FD94C45DFA52
+:10B2600033D174D0EEA77CD9F3452CACBBEFA7A9A2
+:10B27000F755FE4C2ADF1C0DF82AB6239EF35E9884
+:10B2800096127D0F496FFEA6C80B1C200EDD1B1702
+:10B29000D2C48144FC67F255C6817ACFFF6BE2408D
+:10B2A00083C5B1BE4EF2FD17F0C940F12CE35EF646
+:10B2B0003CBCD98CF686886F89F94AE94CAE437656
+:10B2C0008F944EBFFF719A47970E7114338B0B1DED
+:10B2D00085EFE4C1FEC48C4498EA97C49308FE2F1E
+:10B2E000E4FD66D8FAD209E2386BA3E4FEA8B57F84
+:10B2F0007D9291CEF4CDF9AC1EE4CBF69270F6CFF0
+:10B300000AD18F553A295E57ED62F1D45560878096
+:10B31000FDB1536D7F5471B807BB17AC22C99309B7
+:10B32000F33A0DF7D3401C3D9697094C9F8EE4707D
+:10B3300024F272122F4F737D7BDAC6DAF7F2217F87
+:10B340003F857FFF936693776D943DEAFC494C23DC
+:10B35000F8A58E1C718E8B4A0E9D57C3AE14F44710
+:10B3600096757C6884F3519EF49244C033B403FC18
+:10B370002CD3878C36DAFE5E9BAF109E37388967F8
+:10B3800007F477868CB3E93CCE737BEBBC81C5BFF9
+:10B39000CE9B5929E0F1A45725C23CCF4F0E19018D
+:10B3A0001FA2DE40C2B7403EA827DD8BDFA3F527F2
+:10B3B00034F50FF4B47EA791C73DB57A25335EA569
+:10B3C0007716ED7A0DF9FA1613599741DFDFBA2B8C
+:10B3D000C508CE4C5D827F84A28AAF7C3B7DA2B53E
+:10B3E0003B06933F6917CF57E325D9FD5A06D07F17
+:10B3F000D2EE3792A05C2735625C3A2A3FF6F84BD2
+:10B40000940EB22E9C142D7762DF678A89CADF50B2
+:10B410008C5BB0F3F50EE33AB8976C2D950728379F
+:10B42000A5337F692D970BC84D63F1D58082F7A2B4
+:10B43000F1B8EC6A1383AFC1EC79A414FCAF23B26A
+:10B44000261ECBEE1B72B47A12219E163E224B189A
+:10B45000BFE1F1D9D53C3EBB7A7B490A8CEB4FFF6B
+:10B46000EFB5AF441CAEC1AA27F6C4483F31DF0692
+:10B470007E9F86968EE2FD4B7F93FB8DBB7ECDDF5C
+:10B480000F64B73DCEE7D5707194CA6E69A0F20023
+:10B4900070365C1C7359BB6513E7FF06B037FAEDD5
+:10B4A0006FC7E7F74BBEC3C0EF5556935F063ED755
+:10B4B0007BB2D83D6B2C4FAA8EF3539DD03701B58C
+:10B4C000BE11F72589FB36E978FF06F225C63B66F3
+:10B4D00060FBBD8B8913F5D9628D5D21EE575A6AE9
+:10B4E0009983F2B2B4CD10C91FC07F7B8C60EFDCB2
+:10B4F000D6A17DAECDBF657242BFFF5EF4F7C57CBD
+:10B5000056C5561EF240B3C21EDCB76B201DA80FF5
+:10B510001A76527D9A00A53908FB28A45B3DBFDB53
+:10B52000A3F38229BC77902EA34B023F590D4F3DC8
+:10B53000E9C1F156755D1E4EE11FC03914E64FABEF
+:10B54000EF037C29DD8974FB7C42CF5341FA1D391E
+:10B550007E9A09D6EB73DD9FBE8D798FA9CC9EA113
+:10B560002BD386EBE97FD675CB0AC477EABAF7E12D
+:10B57000BA30109D7ACFE79330CE5FEC2768F9E6BA
+:10B580008574BECF9AE909011E0D43BBF05EB0F091
+:10B59000BDEC1CBC5DA6160D853F35443D335DE416
+:10B5A0007E1BE2F698207E3A3586DDD3F3BE526AE2
+:10B5B0008273FEC9569D17F4FE5A658915EE3B4904
+:10B5C000E3F774244B3A2FE8ED455416E1BEB07012
+:10B5D000ADFE499073D7F7E38239940EAF18D97D49
+:10B5E0009FF6381FDEEB10B6CAF8FD92DA2FC79B24
+:10B5F000283CE9972C05907728E09E5A161E0FF1FB
+:10B600008DFB15DF11803BEB78E8A4040914160FBD
+:10B61000EEBF3ECDE5F8E943BA8ACE7EE69D9AC1FB
+:10B62000E67D8D43EF857D90D141761FE340EDC4EB
+:10B63000F9E781E46E6769E816904B88CBF6F7BDB1
+:10B64000F80CD66E136C2842BCDF165A0E78DCF963
+:10B650003DCA23747EE75E4EE95C1335BF5F707DA3
+:10B6600071EE06B6BE897B218BF48D92754C44DF5A
+:10B67000AC50BCCFC3FCE17E568CAB70FD027ADAD5
+:10B6800089F6B2DA9F12F0AEE5FB47C28F1AECFEE4
+:10B69000CB868B924A2F6DE27C1BD12F7A7C5F2E5A
+:10B6A0005BD0CEFA3420619EE8A784E5437CDA21A2
+:10B6B000615ED7A74799FD061115A908F403D33792
+:10B6C000CB9F1CBF0EC463898FE53F2FDEB212F300
+:10B6D0008FA07E1FE5AFC5A9EC5CD592B56ABF43CC
+:10B6E0008C771BF12606C1AE58AF96C73AC2F64F0B
+:10B6F000611F19FCAC4F8F327B71F9E3EA71EAB636
+:10B70000CC3C05DFABD3E43325737DA7B5AB6764D1
+:10B71000F03CAF22527435E7A15611CFAC0CD8C71C
+:10B72000E779CA9F6EC9495912D56F6596A43A2F19
+:10B730007B86AE5FC3E8DA7AB659C1727186672E2E
+:10B74000F43F7F84CDBB31C3579BE1803A9B17D137
+:10B7500087D9BD99354CCFC640F091FE67CCCDA6B8
+:10B7600000E4C9FE08EED5A2F88D8961FA5BACFB56
+:10B77000B27C8F9C00F3FD63612ACAF9BFCFA8C0D9
+:10B78000FDD6124F3EC85F7B9505EF4DD8AC63F7F1
+:10B79000E79962D87D3E81A7AFDD0B2C3DACEBD1A4
+:10B7A000D20C50EFA120497042BCA805F35EDAA686
+:10B7B00010BC1F4D7CA738E4DD0EF064CFB1E03D36
+:10B7C000277679732AC453ECA38DFC5E06B60E353A
+:10B7D000701AFCBC3B07EF67BDB06B2496D710C650
+:10B7E0001F22AF1FBE49A2F6DFCE36D37AD4B9C925
+:10B7F0006BBAA4A001F6E9BB5A6A81BEF56B7AA6C2
+:10B80000C3BD30E15F11CCBFB1BF9256EA4C88C0D6
+:10B8100057BFFD491B9E4FE07AEF66F01761EF8638
+:10B82000DB5BBDE710B8BF53C3F9B77617F3736E90
+:10B830008E63F85D42DCD9D06F818924E828CE6E12
+:10B840002EEB9A80F703AF3458C1DEBBEAFC13BE7F
+:10B85000DE69DB9D011F0DF4E50B31188F6A782A34
+:10B860001EE37977EAC2F8FDA732B85D3182EF13A3
+:10B870000C231EC8576AD83D12F7C562E05EA602C7
+:10B88000D46F26A0EB01D0C374DEB7BF64C67BE1E2
+:10B890007AEF3D51881FE4F8CEDD29E8D7DA733C12
+:10B8A000F9778F81FB3742D928FF549F49D4567BC3
+:10B8B000E5E7EFCED2C37D1AE9541FD3FA998C5332
+:10B8C000AC3E34B41C6E3EB7657EC3EAD7844E42AC
+:10B8D0003D3333F646C88F6928082D87D0F8C4CC8D
+:10B8E0005456874433CA58D33287DC08E74DCE58C4
+:10B8F000D9BA73CEC0E2C6E75E18D5E98FA2BB3BCA
+:10B9000093EF7B9959BB332E769F33C90DA9EEBFB8
+:10B91000B5678A73516C7D14F314FDE8F8B8AFABCA
+:10B920001DFF7006EB773BBFAF666A1C6933B3FB44
+:10B93000A9FD90AFB57FD748C4CBB319EC1C10C09C
+:10B94000097901621CED3978F1DD3BC09EB460FBE2
+:10B950009AE8F5E53D4E37FA9DB5F89D319E7C900D
+:10B960009386EACC7CA01BA5979ED34BCFEECFDD70
+:10B970008CED615C2BE47B95B175656A52D2669063
+:10B980007B0137B58F2CB86E73F8FFC8D7A5DB5B8A
+:10B9900039BE28CC901FD7F022DB3705FAC27A33A4
+:10B9A0003193AD83EECC487B1C2F93E277ECD5CF5F
+:10B9B000EF2BFEDDEF7A7E5174F1009FECEF1E85D8
+:10B9C0007411F013F2A86A9C332D9A7EC504F336E5
+:10B9D0001B6C39D8EF47FC3E72718F2EF473E53142
+:10B9E000FB03F85FDC43463C43707FAB9E6B87DE16
+:10B9F000FBC3BAD8F90A328CCE0FF05A5D59C8E7AA
+:10BA0000A7F0F929D1F71FF7CADDB170F69CF8BE8F
+:10BA10007CDA8BF7DEF1C614F0F154F2DBDF78400C
+:10BA2000F781E8312AF33BE637012775BFA2E9D059
+:10BA30008B670D7C029F20B75C0EF1BE5AAD1C6671
+:10BA4000F6D25123BFAE6FF93DBE7FB7EA1F281D66
+:10BA5000E1FC8453CDCFAB76BA744BC644FAB56FD4
+:10BA6000D5C45976DEE507FFFFCE5D55985F6A586D
+:10BA700043F05EEEF0CB32EAE3F3F4DD3A3A8FF3D3
+:10BA8000DB5C0198C7035CCF3C600D274818E79149
+:10BA900075600787A97F0DEB79D84C9FC3B907FA6A
+:10BAA000FCC9A8799FF78613AC51F42A7C454E80D7
+:10BAB000FDB25080DAB9FDD81DE29EA81061EFA951
+:10BAC0005D96DD0479E81D390590F376C144B29B9B
+:10BAD000EC501F5EE0478E65F1C9F33CDFEA8FC48E
+:10BAE000FBF6F5B01EFB3DFA34CAD74B395F9FE732
+:10BAF000795875AFB526A0FFB68BDA69097DEDAE32
+:10BB0000E5962DE8DFAD00BB4CEA6B6FDDC1E39736
+:10BB1000759B34CF77513B0CF486264FDCC7E3C1CD
+:10BB20005A3BAC2993C735F3493E5B2799FD7037E3
+:10BB30008F3B88FCFBF33CFF9ECE1BE971619BC4ED
+:10BB4000F2ED89F34DF0AB1A0EC978DF15F13BD059
+:10BB5000DE8BC43FC346B0A7B47685B63CFBDCFBA6
+:10BB600045FF449BD43FFF5EDECF6979F6F9774706
+:10BB7000BC04F5DFBC93FD1EE9DBBE6CF7D7787F14
+:10BB8000DBF9DD3104ECE4F3BB5FCDFE27A8BF1881
+:10BB9000E306B8CFAF89C1FD64FFEE783C57783E2D
+:10BBA0008B9FFB7DF9ABBC10C697D622BD9ECC34D3
+:10BBB000229D2FECFAAF0F806F2EEC8A71823D74BC
+:10BBC000E7EE38D4E577BE68C6FB59CFBFFC5551C8
+:10BBD000B47DFAF7CEA781DF4F783E9ED4607C4ECD
+:10BBE0001FCE96D0AE989C0472B76AE71E23F87FEA
+:10BBF00065AFFC352F04ED76EC3192B1B89E3C0177
+:10BC000079B15D9BCA1F8673A3E740C7D175BEF2A9
+:10BC10005FD6DD08E746B578A1E39EFB2798C72BE2
+:10BC200071481F8A973AF0D706C2C7AB992CFFF725
+:10BC30007F1A3ECE1B7AF0FEC1F3DBA5F1E007458B
+:10BC4000F022B17BBB77C5074C12CE9F3DDFFD557F
+:10BC50001ED8BB9F75B5E07D0E83CDFBE4FFB9799F
+:10BC60004BC12B99B721EB7FE6BC05FF3F94E964FC
+:10BC7000FB6C1A39E82BFFBFF93ED67F1DEF4678E3
+:10BC8000AF50FE8767FDCF94FF6F4DF71D12C6E5DD
+:10BC900006A3FBB4FFB5747F8DD33D5E81FB16CF49
+:10BCA000BFFCD76C1235FFC1E6BDF47FE9BCB571AE
+:10BCB000CFC75E263F033BC330CB688073C4B3BCA1
+:10BCC00012FEDEC25CD8E92880F325E163B3216F60
+:10BCD000A446C673B5F479D089769CB767197DFE02
+:10BCE00046E163A9B01E1824778F07F6156A0D98F0
+:10BCF000DF3A57492D05FB216917F99913F7715858
+:10BD0000FEEBDC796905D0FE30E9298D03B95AC80C
+:10BD1000CFD7A4E6EAA3EF41A57F730E15E1F9158D
+:10BD2000FC6BCF62FEDCDC09AD06B0676E6CF536ED
+:10BD3000427CEDA6ECF0306B549CECE12C17CE7BF2
+:10BD4000AEDE6B8073D8738160FDEC0BCE85416DE8
+:10BD500000A7D7C07E2F88EF1379AEF956FB44E3D6
+:10BD60008CE113F7D0F9288759BCD4C0ED24111FFA
+:10BD70009905F59CC838494DFB7CD3A8BFF2028FCA
+:10BD80003391659BCB9300FF74407437EAF7942797
+:10BD90001546D5577FA87E7F9F345D555FEB52D700
+:10BDA000D7974C8FEE3FD07C6615BA0C3EDAA0FADE
+:10BDB000714995BF2A4A01DF632DA416F7D5ED1E00
+:10BDC00027E4FD127B21CEEF852C9DCADF8CE08914
+:10BDD000E1A596E70B279592C5D1FB25FBB2989F6D
+:10BDE000B32F8BFB11761E5F777B9CFDDDDF25C6B5
+:10BDF0007B77C53803C457299F60DC6ECE2E6273F3
+:10BE000046ED1F1FE5E3BE9BE82B67792CCCFF7F37
+:10BE10007B428AEA7756B4E51BB58BB386D2F6A58A
+:10BE2000DE237A909759CB6E32801E78BBEA431D91
+:10BE30008498C60D65F02FF8C6995515358F109F5B
+:10BE4000FFD17F56FB71A23466B3F9FD41C7F66D91
+:10BE5000FF90E0CBAA55F53761FFB7E359FF717A40
+:10BE6000A297A3E26AB36002902751C8E8B3E01B2F
+:10BE70004F567554FF737CBEC7F87D34809FC55103
+:10BE8000EF87F2EF0B7C69E11B9ACDFAB74C66E7BE
+:10BE900061DF9E45F07705926A66E0F95111477EB1
+:10BEA000BB82C591215E0C7EC80A2EA76FF3F3C238
+:10BEB000D5FCBCF09B065F16E06945CD0A8C1B9350
+:10BEC0004DCC1F31D1FFC17E487E50AFF24FAA3515
+:10BED00071DE241E274ED23CD7FA1BF1D996C8F941
+:10BEE0005EAA4F93387DA8BFECC47B32397F8606AB
+:10BEF000E14FEDB9E081F8434995897E7CC41F1973
+:10BF000057C2F657C61998DC1F3DC4FCB7A3155F8E
+:10BF1000D8C04F157489C87BAB6F58D47EE863379F
+:10BF2000C4B07BD1B89F748CFB4947BD6F594AC6DA
+:10BF300044E8F686F70B1B9E9311F2412E2F1FE368
+:10BF40008CCCFF5F591983E7AE56BADDEFAF04BD65
+:10BF50005019A3007CA5858BB3601D2B9727FDCBC3
+:10BF6000BD00F7B6183C7BF5D94FDFCA843889BBD2
+:10BF7000F007D3F1DE0849C1F3DAA0B89EA3F89F19
+:10BF80005DB9F8308C3B6B9B24411EB0D06FE5D976
+:10BF90004C2FCBDBEE3A9846C74BAAB4BA67900851
+:10BFA0003F7DF65309F969F936C64F827FEEE07A94
+:10BFB000BDAC32BC10DA3DB62DC609FC75C736C61D
+:10BFC000372B67ED383C8CC03E80BB2489F6AFCA66
+:10BFD00076B2B801F115C1FEC2ACCA960D85386DB6
+:10BFE000764E5B8C47F9EF61F85D84CF7E65C07B50
+:10BFF0007DC4782D9357E0F3B77F25E379FEE5C440
+:10C000003F1DAE845D0E7C0EE7AB49C74138673CEF
+:10C010008B8F7FB462BC15D66DED7EA3D85F584E72
+:10C02000FF817BEC930A35FB1C5B34FEF720E7AC09
+:10C030006F053E16F9402323E30B7A6BE9ACCD077D
+:10C040001274E82E962B809FC6D93CBE683DFB300B
+:10C05000E7235176EFFACF3FAC8475B7909D8FF60A
+:10C0600010EB34D80AAEAD2B2984E5ACD494BF1FB5
+:10C07000EA3737D23AC55353B6819F73F9B01C7E65
+:10C0800052E5D654E920948B9DAEE9F0D3190F0107
+:10C090005DE8B84B734B0E4238AAD25D85F7FB962C
+:10C0A000CBEBE3F240AEE87780BFA85EF3EBFA5942
+:10C0B000874BA891147DAEBDCC64569D872F57AC9D
+:10C0C000AAFA8CD43455FB1B9C2ED5FB99B9A354EA
+:10C0D000EF2BDDF9AAF787B2D97DDDCF4C38557942
+:10C0E0000F9DE733D7CAF04B6CE430E0C51EC10B9F
+:10C0F00085F77180F7F0B5EF64DE46E7F35836FB5D
+:10C100001D17A2677198DB7BF9AD67218CF3D866A8
+:10C1100019F9EDF6CAE5C86F751366A09D22F4E71C
+:10C12000639B981C3C46D8FD56737ECAF6E1564C7C
+:10C13000327C1893D7976FAA79BCA665328513FA1B
+:10C140005338018FCB3769DA554E47FE9DA3D197FF
+:10C15000D55C8F6AF5AB96FF9E99F0553AC87D572E
+:10C16000B63A2FED1989E975FFEFD9EF8B0CA417BB
+:10C170007BF5A186EF0E6533BD2BCA72794C22E8A0
+:10C180009D7146753B51BE4BED623D45FC7BCD2616
+:10C190002CDF6F56B0FC8FE6542C3F6C7662F97141
+:10C1A000732E9687B2995D92D444E91BB51F9A54B9
+:10C1B000E9355E4E7EB4FAF2704887727378CA032E
+:10C1C000092E4B24AFE258363BDF75BAF8638B3447
+:10C1D00026C2BFDDA18F2C607FD492009EC7BD997F
+:10C1E00004F17CEE2212C2FAAD70A4558EE45D2CEF
+:10C1F000251EDCB74A54BC581E864FA753B978A2F7
+:10C20000E111D84FC98375D98279A66DD1F2913ADF
+:10C2100084E1EDB66CCF47D9A0D76D3D2766837E0C
+:10C220009D6220605F127E8F5412DBAB236F4C98AF
+:10C23000685ED2CFFA3E327BC9D9EC09D1F8F11948
+:10C24000A1DD33E25E227E0F963E7918C6697BE956
+:10C25000CAF1BB2ACB7301BE2FF245A8DD9F7AD964
+:10C26000F5C7E6C67558CC87AE2812C4719521EA89
+:10C27000F5709CD16784F8EB727723EE5B976ECAFA
+:10C280003787FAE18B91D93EFD100DFC4CBF307E13
+:10C290001A88BE822FAE96AF04FF6CC8F258E1BB7D
+:10C2A0007A7E3F95DE56930A7823CA1CE48FD42108
+:10C2B000D265ED8ABCE28FD78F8705AA5287F7B285
+:10C2C000E675BBCDA0478E727FEB70E5477B87D1CB
+:10C2D000F787BBD9BD318F554C34C33AFF98C59F02
+:10C2E0000D78392DB9CDFF08FAE8495941FF88B0DA
+:10C2F00075724565F250A0D34D9327A01E3955E9BC
+:10C300002A00BD3D97C3F32961F4F47B25BC0FEBF4
+:10C31000F40D3FCA8671DE98905200DF21F2A5C766
+:10C3200057D3F77FDE24DBA0DFDB852BE6DE43CBB4
+:10C33000535B64767EBCC215003FB65C3E61417FB4
+:10C3400097EBBBF9302EEDFF06713A805E7336C96C
+:10C35000A8B7E683BEA37A66DE42B55E12EBFF297C
+:10C36000B02725F8FD1CF5FBA44D6CDDFDB6F6DF0E
+:10C37000F42197BFDFE5530B8BB75753FFD347F13A
+:10C380005D56E1329C043FA44942BE107AABBA929A
+:10C39000F9A5D5158BC79BE8FC12031325D087653B
+:10C3A00095CE72F04F67554845D176E1AC8ABBD047
+:10C3B0008F9EB5E92EFCDDAC5559DEF9431CC02734
+:10C3C0005EEF75A0DFE9F780F9C705DEF903CC6FF2
+:10C3D000C5A63F1D1B46C71F5BA953603D7D2C3082
+:10C3E000321EE87C74CB1776F42B7AE5A0C308F9EB
+:10C3F0008AA55BFE940E72A0D513FE5282BF03760F
+:10C40000562241F85DA6B325C9A530FED92CA39EBE
+:10C410009523583DADD8C4EAD32BA0A476DE3EB810
+:10C42000F7EE4225BB1FECC69005EF2FBC31A4F3FD
+:10C4300003FDEA43BA0F63203F38ACBEC766EA4546
+:10C44000F53D362544BD0EBFC9F371CB4CEAF5F876
+:10C45000EC6B0BD1EF2F57D4EBF28D71099DD07E91
+:10C4600046EA28CDFA9DAFAADF6462798C3373AFB8
+:10C4700055F5EF36925CC85B0D4BB1F8FB54558413
+:10C48000E51FDC444BF81DA059EE1255FB7AEAD0AB
+:10C49000039EA01DE4ADDC547C83EA3BF5D08F3EC7
+:10C4A000AF3279D5FD9AFE13F9E3FAA64B68EFE7B0
+:10C4B00007BB54EFC71FEA568DE3EE51CAC01D2ECD
+:10C4C00038EEDE07A5C88F5E0B7970B42C0C79CBE3
+:10C4D000C0EC2D3ADDB80FCA81F2A67F2013FC5DB7
+:10C4E000ECAF74BE3ACC0BD505BA16D3791E9314B3
+:10C4F0000794F74BBE27411F15873BCA206DE7FA0B
+:10C500004B8156285BE13C7B22D0B932EE0D88434B
+:10C51000754968CFD75BF879765B575EF4EFBCF46A
+:10C520009E674FF5A42EA6ED1FB00FC3788CB72CD5
+:10C53000DE03FBCDAB9E1F89E7E47E38B4E439F817
+:10C540009EC8832376F5B9871F0EF5BC04F94EB15A
+:10C55000654C6F901906D437B13A6F02BFA702E35A
+:10C560008BC61906CC33BECEC9F453ECEF8813F258
+:10C570007A63937CF258E8375322105712F05557DC
+:10C58000B2F3F06F0CE17101BE3E55398E6D03FFC1
+:10C59000FD3A103A3A4E51A5F300FC8E3551F40A9B
+:10C5A000D86B49C7BDCA580AE74E7BE11EE0939D90
+:10C5B000C77B264B4E68EFC4F6291525F794C0F7C4
+:10C5C0001E97F17786762AD3E2A03D09B8D93E15A9
+:10C5D000CF6F4D5AE87C07EC2D72C840F8CFE8E0E9
+:10C5E0003C946B627F05F3483AEE5989F3CDB53838
+:10C5F000E1776E287C2EF8DDA88F9BE1EEBB81D71A
+:10C60000A38FD73B1CA057AA4A1407FCDE4AD5A328
+:10C6100072EFEFCCC3120E3FBBCCEA5FBD398DBECB
+:10C62000DFDA5B274192CBEFD761BF434FCCB9FC38
+:10C63000778A59FB9BA659303E21DEFB49319ED3B8
+:10C64000E6EF2FE27B45339E183F3CE4AB37DB2C13
+:10C650008027661713BDE2C0FCC84BDFE0EFC78937
+:10C66000BCE158D959047CB944E7CC83727CA2EF71
+:10C670002BE00F45E71E01F5D547C67F0079CA5468
+:10C68000DF9CDC08FA669A01F5F09DB9EC1EEC9D82
+:10C6900046E7F3C7613FD6118BF93E86876EEFEA16
+:10C6A000A6E3DEA9FC27CA19E55F3CD77FA147674F
+:10C6B000033BF9FF01D519CFF7008000000000000F
+:10C6C0001F8B080000000000000BCD3A0B70545582
+:10C6D00096E7F57BFD4B3A49E79F10C0D7F960908C
+:10C6E000009DAF01823C1270C8C8A713508303D2CB
+:10C6F000A2086A0221CC8E99D19A6E6C54A4B42AF5
+:10C70000AEEE2EB383550DB5B26CADB31B1DD48CFC
+:10C7100022DBA0AB7145B711DCC1598A6AD919C5B2
+:10C72000359026B8223596EC39E7BE47F7EB9009ED
+:10C730005AB3559B54389CFBCEBDF7DC73CFFFBD7D
+:10C74000B532004C00FAD1C00170DA92C0954A802F
+:10C75000B584CF1678393EDF91C0230EC4EFD6E9F9
+:10C76000BDAAD5B7AD0AFF7F8FC30205005B1C4C85
+:10C77000033B72A04F9E0970A172F66D9087F0493D
+:10C780002B8004B09F1E221E2C4A0B3F8FF80751AE
+:10C790008B26D5219E97B6BB82F11147A90BA03FEE
+:10C7A000801BDB9136E8B5404362DD0B4D3F78AF2F
+:10C7B0008CD68B5A2CA0221F311BA8B500D50A4459
+:10C7C000EC35000D4D6BE552E4E704CDBF1EE0A94A
+:10C7D000526DB25A4F3317B83FC57349DACFE4CB25
+:10C7E000E90097E967DE6808A000D1D1CF6594D150
+:10C7F000263A760EC2C6AD553003E102E9133BC1BD
+:10C80000DE2F41A92572BFD7970160B387C38FE0A0
+:10C8100039E075A7F7799AECD226B74D4FACFBA259
+:10C820000705960FF073B7F6A207F9E9ECBD004AC9
+:10C830006E62FED05658E343BEFBACB0A60D61E776
+:10C84000B7F29A36944327C076A986E0615B4F55CC
+:10C85000129FFDE741D1653213975E285765C5F0F9
+:10C86000B9F2ACFC893D73F4B914FF62DEAF4D72CE
+:10C87000DF0A6E80BFF53CE0536621EE74DF2A21AB
+:10C88000BEDE73BB4F29467C92FB560BE28F84F7CA
+:10C890000BBCD8FD57162FC01ECFFB02F7B83F22A6
+:10C8A000FC97EAFB627EB5A117EFF834E4B72D439D
+:10C8B000E04BD4777CC12AE2CBA5D17D8F2C728648
+:10C8C000ED9EB1E5BEBCF775E66FCCE7B2C4F28170
+:10C8D0000EFC43399F6D2DDEBD03D78372ADDA8226
+:10C8E0007857FBC49A1DA83F6B54FC07E55B807723
+:10C8F000D6887FFF6A0370A0FCCEFE217AAFA50C1C
+:10C90000D7D9FFC4792993F63BC8FB75823A1D70CD
+:10C91000FCB972FF3AD2930FA5D829C07BEF5A72A7
+:10C920006C0A908EBBE3E5743FD62280DE1C3ACFC2
+:10C93000E2A2BB70BF913CC56B47FD5B097E2BD16A
+:10C94000AF70FDDE26237D3B78ADB41EE429F1985F
+:10C95000A147A5001B9B9CCCF74690C29244FADDF0
+:10C960000F0A9AC44B810186DAC0A113C4D74A507A
+:10C970004ED33C0B1ACB653CDF8A0EEBE9987ECF99
+:10C9800097F1AF7DB119079DDED057F8E6B2447636
+:10C99000F863A241FE34872B22CFA0A7D6A1647EE4
+:10C9A00076BA7DD797E279BF8CB614FAAB12E71846
+:10C9B000B5BFABDC4A7248E56339446C443F1E3F67
+:10C9C000E732A277DA501E56FD7EBB723C15340F5B
+:10C9D000E5FD8C9037CA1F716B5EB4C0EF22F9BEC3
+:10C9E000A0923F18A974801DE59476C38919FEAA08
+:10C9F000D1FA902A3F09CF44F655A8C46C5E5C6713
+:10CA0000E309D0C2BC5EA73C9DD61BF000B91363FE
+:10CA1000FEAF484F903E6B40623AD4172FE94B5E11
+:10CA200019442CA8AF79AFBEFB424822BA0CA633FA
+:10CA3000F4735E3AF43B73127A84FAE525FD32F41E
+:10CA4000695E0BF282F3E7E5BEF94208E577AF2AAB
+:10CA5000F8DA9F26FC5EFC6567788F67349F6FEA83
+:10CA60007A9BCAEFE16BE4F3F09F894FC32F1972F1
+:10CA700032FC12E87E7B6587670FD99981B72F4614
+:10CA8000DC93E073B4FEFC9D7A35FD194F6F6E5058
+:10CA9000DDBC9EE11F0DBE0C3F87716451BF89AFA5
+:10CAA000ECDD66BEB2D93F64F5FE86FDB49CA1F014
+:10CAB000F88ACAA2DD328D4747D047039C574B59AD
+:10CAC000EE59FD9700AA88FE00D38F6787465C4821
+:10CAD0003D871127469F47E5F3A4C68FB9E8D0D814
+:10CAE0008F534C42FEE77DED07A532B1DE7CB8EFF7
+:10CAF0008A9F27BCC5B1D9842F74FFD444FF83A279
+:10CB0000ADA6E7ADEA13A6E7B7543E6DC297787FAE
+:10CB100061A25FD6B8DBF4BCCDB1CF8437C5A22DFE
+:10CB2000A84EF0416011281500379D89BF4978242F
+:10CB3000E066FC70A088E15B0195EDF2ED4025C355
+:10CB4000C18097C7FF2DD0C8F0484063180DF81872
+:10CB5000A6DAF3D25FDFAE002EDC18ED6BA190F207
+:10CB6000FE64FF4D14379759C2A10CBC8F1B4FF6C2
+:10CB7000CBE417C0EF35E51D8F1E9AF5EF5BD07E35
+:10CB8000728FC8E054C78E27595FCBA0D526E18BA2
+:10CB9000E340F12B0B5D663FC2A50A6CB3E3FDB623
+:10CBA000B9944821DED7023D7E53F801B4A30E07A5
+:10CBB000BA2CD4A78E0EC91B021E0F420EB3E0730F
+:10CBC000203FB7EAAA88E3113FD2DB1508D27AB238
+:10CBD00026C34D449797AB505EB3828890CF5B716C
+:10CBE000CFEB90EE0E573FC78F95838F74DD85E3B3
+:10CBF000B02D584FFA7F257F09FECE7279DAB5E75E
+:10CC00002F0B2846A2DC1E95BC518DF2AE6C85F32D
+:10CC100013C38E8C79C574BEFA04BE4CCF179686AA
+:10CC2000827226CA337E14BC7BD4841DA27CB6D308
+:10CC3000790C3B68732B91EB33299E3EDD42F49DCA
+:10CC4000C755968B610F9DBD5FF1BC54FD477F1F9B
+:10CC500022FA9113E0257F77E35038F60CEED318D3
+:10CC6000EF6BC1BB8039DF844304AB23FD263DADB0
+:10CC70001D1C30E9A5C1F7814007EBCFC1809F6142
+:10CC800024B041D7CB6EC6DF0AF432FE7620C870DE
+:10CC900030B05DD7CB3E7E7E24B093F10F02615D54
+:10CCA0003FF7F1F80DAA90E3FD1EDD2F39E6ABBE8C
+:10CCB000E9246E01137AA10621492F3A8B843F1E85
+:10CCC0004F3FC6D20780B04A7EFA0E8C87E4CF7EF3
+:10CCD0008419E21C841DEB83D3B74ADF5F2FBE7B30
+:10CCE000BCF77BAF25DE1B7E4E6E9139FFB2CB9B2E
+:10CCF000BDDDAEEFBE9FCD2EF2A8F1F713F762E4D3
+:10CD000067D6ECFFD81BC1B16DAEE377523E364A11
+:10CD10000E2979D9EB54F3E47F77FEB0F2B1D2BD9E
+:10CD20008FC7DFFA52ED9F3CF949F14CBF4FDB341E
+:10CD3000719F0BE5A1BDBF24FDDF9FCEF9646AFEA4
+:10CD400066E46706FF86FDA5FACB4DEE0B6C4F43FC
+:10CD50009285E375EAB93759C0FF128ED7D8C12141
+:10CD6000A19CA696361FF270BED114D5687FB7E29B
+:10CD70004DCE8F46CDEF3DCFEB8FF91CD727BFB9F6
+:10CD8000E98D7AF75A57625C2A15790DCAC5FDA953
+:10CD90002321976BD5D3B9F10E93DDFFBF8B8FDACB
+:10CDA0003F989E2FC5B042F25DE66FE57BBA832ABD
+:10CDB0003A99EC36C2FABC1A628CAF41152078174A
+:10CDC000A80CEF06CD46CFD781E627D835C97F918D
+:10CDD000EEC72AC55CF4FCEC2B7F2CA7FC58CE3E9A
+:10CDE0007EEE1918EDE7AED5AF19FECCF06F8FD9F6
+:10CDF0006003E551DBB26D41D24B6B7E0EE747C657
+:10CE00007D384B45DC1BCB7E86ABF1C290DFE197D2
+:10CE1000D3B9BE19CE48E3FA463BF0CE0989F2A059
+:10CE200088393E1BF548ED2A2FC769C0385D417A25
+:10CE30009F529F2C5444DD068AB77275521D1DB255
+:10CE400020BF28877D085F44BE3357C5143549DFAE
+:10CE5000CA757EE7AF5C005C0FAFD238CFCB74638E
+:10CE60009E4DF5A803EA9CB4EE3717AA68DDA57AB3
+:10CE70001EB0C30A11BAB7C2C66A89F2C09D6EADB0
+:10CE800082EAA3E0E34DD99FA25F05AC7D2F5F3717
+:10CE90001AAF91258DCE1D6F15797DAA3ED7EBFC7B
+:10CEA00074EAF651930B8E22DADF0F9C8F0EB74E89
+:10CEB000E57C7A71698EEE1FE253DA29AE60B82004
+:10CEC000DC88D3434E91872F1F7062404EACAF95E4
+:10CED000668BBCDFF1A5296FDFD87BC964AF1BABC4
+:10CEE000C4F96B426AED66845B287660FDFE6C894E
+:10CEF000AF85CE79DF7B2FD84A54DA6FD74F7E4784
+:10CF0000FE60D025FCD1917C3EEBB0041DFD497242
+:10CF10005EEE382FFA17B0DBA41FC796FC96EBB570
+:10CF2000E5FBD38374CF065F469D67F8AFAE839F62
+:10CF30009F8252F257E74F3D44F27BD9AEE71797F5
+:10CF4000F839D6871DC4D74B8316966F57AB7D0F24
+:10CF5000E92528EAF4F68C845C863F37F395CA9F6E
+:10CF6000B19FC1D7902499FCE33AFD7E0E515CC776
+:10CF7000FDCE667A57D3BD9C7DA5C4129412E3C73B
+:10CF8000B2A333B25DFF7771FE0ED0F3BEFED07454
+:10CF900037F51DEEC1BC8FF5E0FBC577437F40033D
+:10CFA000D55DC0AD37DE0FF0504A01D51D020F65CB
+:10CFB00040D886F492EBED4B64AF7375C8C510D2C0
+:10CFC00035E9FC3F267503F1E7803E863B24AF4AF6
+:10CFD000709EE45380F70BB39C6E86EE89341E9AE4
+:10CFE0001F0BD1A68ADE073C93D79EBF95B82C8035
+:10CFF000C70071C516B41690FDB767799F5713F235
+:10D000005AAEEFB701FF9A502E4A36A80AD26FC027
+:10D010007CD38A725DB17EE5535544EF6E6239B6BA
+:10D02000EBE7A07924C7DB8E742FA1787DFBA1BF2D
+:10D03000FC40C3F1CF73FA1A889FFF8EEE99F12B53
+:10D04000A4B9FFD8814C7ADE1989DE8CA2878D10B5
+:10D0500067BF6BC87F154419DE0971867E70F3F3D4
+:10D06000B5E065780FF818DE0BDD0C3F2EDED585B8
+:10D0700016002B0B9FB47E0909393C90BDAD81F69B
+:10D080007137EFAC20BD0B364325E541179D993331
+:10D09000A8C8E87508F8605AE61E826DD9AEA09C53
+:10D0A00045CF2787A9EEF9B9E41F28CDE779EC57DA
+:10D0B00083A732C254E71FB776CF24790F67DB40CE
+:10D0C00042FAE17CE147826781FBA9C3569DFEBC21
+:10D0D000CA785D4B0DC777B8A872DE3F87F2134759
+:10D0E00022BFA99B66E1F97059D0CF8D2BA67CA6F3
+:10D0F0008E9A8B34FF8FF8DC43F157F993F9CE4FBA
+:10D10000CB72F8FCB36800FF5B976BE94EAED3437C
+:10D110004505A26FA7E376D5CD757B5CB7C3E14C1F
+:10D120000BEB0BFEAC703410BFE27EE71C784FD7E0
+:10D130004B2CA00AE8DEF471257288C637EA710527
+:10D14000BD31E7814DA4A7A49703E6B80245D314E7
+:10D150009A3F5B67C1A8CB245C6B550EE97554A65A
+:10D160007BBD09E20C3570737C6B062FC305E06351
+:10D17000887ACE7011F431FC21F4335C0C51867046
+:10D1800083D75B83FB5B1C1199E236C0C3EE4F3142
+:10D190004442EB7A0BF59FEB6E87EE7ED7F872C9AF
+:10D1A000291375D9F87241C36EB816B9F8057FA96D
+:10D1B000729958C9F664C8C5908713C24524C7B987
+:10D1C000109309522B99E6CF47B324BC0534C617F8
+:10D1D0008E2B8F4808F07C8D31BFC2757BAA3C5ADC
+:10D1E000849E187AB35076792314878EE756535E5F
+:10D1F000BA40970390EAE2FDF5B8C5391BA0F26F7B
+:10D200009A90AE7ED08A9935C06B010DFE0B6D6091
+:10D2100004BA65EE3BC700FA70DFD9F784430EA469
+:10D220002BDE0E6E3A9BBDC8026A921E3BD534506F
+:10D2300093F2BAF4CA1C133E7B50E6BA35C33BC125
+:10D24000342FABB1D444F71AF4B39CF6939DD37D3D
+:10D2500005B5685543C2DF666B3798E6CF8DDEBBF8
+:10D2600098EC3D77518D691CBE1476D688BF743F0B
+:10D27000CE18FA5F84B387CCF61772A2FFC07DEC9C
+:10D28000F0E479CA0B9CC793EC91F4DB75F3E7B437
+:10D29000BE1D92E6A13C7A4FCE0FBF954477A62CD7
+:10D2A000238FEF63224C243B36EE21D5EFA37F2B57
+:10D2B000A2B85497DE7C814A9ABBCAF6B5D17B816D
+:10D2C000BADAE62D65887795ED6FA3F70275739A44
+:10D2D0007F5D8AF8A6B257C5F399CDB5562FC056D3
+:10D2E00069A06D013E0F1D15FE0F54F17EA747AFDB
+:10D2F00077424785FF1B71FDC4EBA6FB9FE8F292C6
+:10D30000DE3C6EC3B3213F0EBB807299A82F5F0B2A
+:10D31000E0BCEB13FCDAED226F44FA20E579F96703
+:10D32000822BA9FF30A35C65FF327951E4B055250B
+:10D330001B536BA9AF5259E25F57969F581FF9E1F3
+:10D34000B857A2F363CC9BE5B269C417E4796AE9E4
+:10D35000FC8F94F8EEA779C3190EF6DB06DD3E3D8F
+:10D360003F9DA5F4C95B5C340EACB763C19D655AA3
+:10D370004FD955C60D7B9550C8AB286FB8DFEB5021
+:10D3800038CE36B9AFE49F781FB3EED16472F90D91
+:10D390001DDD6F12DC24C7EF25FDDB5AE60F107F81
+:10D3A0005DBE7393AB294FFF838D9B5B78C1C2EE4B
+:10D3B00040F8EB370EBEFB5089407D90E457361D98
+:10D3C000BCF4D57FA2FD6C1A7179897C38539C73AB
+:10D3D000CE815F6C613980CBE4470D3F347BC01E4A
+:10D3E000213D9C7360EA3AA29B7BEC6419E9EDBC99
+:10D3F00093B110B5B186DFF86D89B07FE37DDC4570
+:10D40000E9FBE435E81F382EF5BC21F17BA51E09A8
+:10D41000D85FF47C247B91023ED3E36BD7A095DFE9
+:10D4200087A12777153788BC82CEF79943E859271B
+:10D430004433495E1B76DDBD98FBB66151CFABF836
+:10D440004B7677E30925A5EF8B7686745DFD297D04
+:10D45000DF5D2D9FD17A9B92E3E155ECEC45C3CE85
+:10D4600026C1243E8FBC2ACB7F95FCD58017035A5A
+:10D47000F82DBCD82ED05EA5FBAC5740EBE7F76A81
+:10D480000FB37DF44CAAAAB18BBE37FBC5F54E7124
+:10D49000BE072689BABBE739195C2C275B98EC6874
+:10D4A00037BAD146D2A7C1A758CFD7EB6730ECE93E
+:10D4B000BEED12BF4F855DB9AC6333F7DA59EF7734
+:10D4C000EFB56F27F9CCDC5BA8110C3D9A16A47858
+:10D4D00034D326EA9290333E81DFE3BE61B3509E9F
+:10D4E000406903BDB79C591A2FA5BCE733DD7F8780
+:10D4F000F4FCC778AF6BF8F1909EF7F4644C29A464
+:10D500007AED0A9D7B82F0F7867FD0EB903AE2932A
+:10D51000EA8FF804B18E539CE3D0D1DBD2A92E78E8
+:10D5200059F1A5BB5D143F4AB3E02AFD902BF55994
+:10D53000042FE14FF435EA8E3F19257DAEDBA908B3
+:10D54000B924F44F8F4F32F74D60545C2A37C5A58C
+:10D5500011A2607F0661AA2B8C7B35E24ABECF1CEC
+:10D560008F0A3BCCF1A8D86F8E47251BCC7168522F
+:10D57000B7390E5DD76B8E339EA039BE946D9F6D0B
+:10D58000A2AFE86B36E1D7EFFCA1897E6AB8DD84F3
+:10D590004FDB7787897E7AFF5AD3F39903F77FA70A
+:10D5A000B8581DE931D11B71B176F067578D8B41A9
+:10D5B000FC65FB0461F78D780FD4F71B2F3E36C650
+:10D5C000FA80ECEDFBC6C9A9E5E638F93F58F991B8
+:10D5D0007FB3935EC8943F8ABC33D57EC7D22FC336
+:10D5E0002F6F2DF3FF98E2C0A6F46FA6D07A5D8E60
+:10D5F00073936B112E1DB404493F96BA1C9F10FF04
+:10D60000A877950AE53590E625BF67C42B9F6E1F66
+:10D61000CB5C0AFBBBA5E9C27E96E1F06CB2F79445
+:10D620003AD0A84396354A29FD2CA7A99F355EDF3D
+:10D63000BD3E1A31E1D5C741263F5FFF7B3594815E
+:10D64000FBD49E147DFCD4BAB32EE60F915BBE7161
+:10D6500008C38A4AF5E7E0257A4F395787B3BFEE0A
+:10D660007F93E6A5D649F0ECD3645C60731BE710AA
+:10D670007E23B55E7D501675ED458B9FF357E37E97
+:10D680008C7C36345FD4AD46BDBA76827F5D39CAB4
+:10D690005FB688BA151D4BAE78EFD20F0487698C40
+:10D6A000835D63BB467D876CE0EF5F2C50DF4EDF10
+:10D6B0003960AEE98E3588B60EFD3C5CEEDF5C8EDF
+:10D6C0007EE2B424EAC873B34A1EAB457E37EBF161
+:10D6D000BD70553FF8459FA9A73C7FF4FB9854982F
+:10D6E000DAEFDD1F88304CAFF2727D91DA97FA8263
+:10D6F0009898C5EB06D9EFF44AA29FA3D7D9ABF50A
+:10D700007B885940D48F3BAC5CDF19FD8955FA39D1
+:10D710004EE3A30D1817560FBCC3F7F240D190DEAD
+:10D72000F7E9F6BA71DEDD135DFCDD0568B5DE767E
+:10D7300053BFA244FE2E717DBCF33F50F4B9A9BF84
+:10D74000052F88F834F6FA41F6D34972E0F54FB761
+:10D750008A7876BAB5A4193293D73FC7FDB2D5DD22
+:10D76000474DFABEA6F763937EDF15FCC4F43C96E2
+:10D7700017B796E0F963AF14DFFC2394E7D997ED70
+:10D780000D741F78FFFF5C9ED4178BB54E5D00991A
+:10D79000D772CE2F988F938128DFAF71CE5381132C
+:10D7A0008CC7023186A9E734FA0B06B41D06F613BE
+:10D7B0007129CD4B7DC9B1FA0E86FD2CAA28E575DD
+:10D7C0001E94B55322CF177A71B1C7CA75E8C9F94B
+:10D7D00005CD14F74F4EB229024E117871A343E0E4
+:10D7E000372F22386C756DA7BEC44949F4C13F9AE2
+:10D7F000F0D55E1B2EBD7C82FF28C963B839FE952B
+:10D8000085F29EBCD864B2AB45B9FEE3342EA11BB1
+:10D810002CE6BE59700AE5D7672CC119F45D52D9C0
+:10D82000F34FB7533D71262D788EBE5B2AA978AA97
+:10D830009DEA893336618FE9155D6C7F1FE1A20A8D
+:10D84000E51FAF49DCC7F88B1C7F8CECB9CF0A1100
+:10D85000FEEEE237D26E9203B86236D253A39F39FE
+:10D860006C4548F6EC14F08B72F11DC350B9C89F9B
+:10D870000CD8E588D9A89FB363D71E1FF98D5B64C8
+:10D8800095E9ACD0A7D1FD6F1CD8CCF69C5E01FA0F
+:10D89000771C4F4EA17EFAC8623B909F46FE34FA39
+:10D8A0005E2378D0CE7696FA7D52CDBFD8235252E1
+:10D8B000BFF4DB720FAF9F5706FCFD54DE2D4EEE1A
+:10D8C000FF402C3A99BEB1A2EFC47CD43F380E9AE7
+:10D8D000F81E6AEA1EBD7FA0D9106F7FA590FB09D4
+:10D8E000DF968BBCABEBDDD3A788FFE7CAFD968A3A
+:10D8F000FCA47E2C443F7597317F5CB7D865D82651
+:10D90000E58CAFA7467FD5C08F2D797C0AE97D0DC8
+:10D910007DA775957CB6BC42F071D20A29DF7119DA
+:10D920007C1BDF7155B13F995771F5EFB8AA2B8475
+:10D93000DC6BB0E6A33EBA3D0D7D7ACDD8723FBB1D
+:10D940002EFAD7551EFA0E49AD20BD36CE8D725037
+:10D950002A92FAE6861C8C750C3E717F3FBD67A843
+:10D9600079EF88B510D7BDEF1F3DD4D6B9722E839D
+:10D97000CF674BB4691549F68EFAC5F7126C75F28C
+:10D980007D771DFCF8D44338EFBEBF9F5E4B7A62B3
+:10D99000CC4BE517F99C44FC7D6889D8F4EFD21A8A
+:10D9A00069DD97063FE4EFA30C7EBFEFFD0C4F8AC5
+:10D9B000F2FBA6E1DD9726AB38BF4B7F4FD3657CEA
+:10D9C00027B6DFDC1742F906A92E4E8D2F40A94459
+:10D9D00001F0374A1447ECC6FC898A697E6FBA6F3A
+:10D9E00019F1FF8AEE17903ECCF68FF908C5992BF6
+:10D9F0007D693D2ED5EBAE473A21FAD0F50429BE1C
+:10DA00005765715CAA33F643BE481F1E9382DC97AC
+:10DA1000B812D7F5BEB47CF716EEDF35421F438B44
+:10DA200043C4AB86892EAFCC9BEAFDA727DEE6FA7E
+:10DA3000F37F01B3C10BF8102B00000000000000C1
+:10DA40001F8B080000000000000BFB51CFC0F0034B
+:10DA500009BFE541E5674AA2F28F70A0F25DB951B6
+:10DA6000F996ACA8FC4634F30861356ED2D47F64D5
+:10DA70006460F80DC4AC4C0C0CFC4CF8D56E612401
+:10DA80006C5E9B2584D606D2B140DC0EC46F0D18A7
+:10DA900018EE1B313038183230FC3520CD7D84F043
+:10DAA000273DEA9A378A49C32936A87C3F5706861C
+:10DAB0000637068663EE107E3492FC5DA098BF2B7D
+:10DAC000841D670F9403F2836CB09B1B0F948F012E
+:10DAD000CABF839A0300878BB61268030000000058
+:10DAE00000000000000000001F8B08000000000084
+:10DAF000000BED7D0B7854E599F0772E73C96432F5
+:10DB000099DC20C0309C0909040938847095EA101A
+:10DB100082064419905A445A274005B948B46E8D7C
+:10DB20002DDD9CDC2060C068711B29C5E122052F1A
+:10DB3000352A50DAB5FB0F17956AD70D8A5511BBF8
+:10DB4000212262D7BA48DB95DFA72EFBBEEFF79DF7
+:10DB5000E49C9399807DFAECBFFFFFFCE9633FBE34
+:10DB6000F3DDDFFBFB7E97717983CC7F1D6397F03C
+:10DB70000FD2750E7650BA9A31B73B7CAC8A411EF3
+:10DB8000FE6393185B8BE900F82F2EAB6C3C636946
+:10DB90008CFF2901F9B4CB0745B2C6581E7CC8CF0B
+:10DBA000A6FAAAB79AC5A8462B63E330D59CD10C38
+:10DBB00073BE9A61DE1164B1F612C61A8CFEF12FA3
+:10DBC0009731973FBC7383C4D820E6A4FA6AAE5B52
+:10DBD00057601CD5AFB358098E171B44FDCC629615
+:10DBE000F93016E1FDF62BCEC47ACCCBE763ACCF8F
+:10DBF00048B7D5B226D561CA3BD87C9C072C90C6C5
+:10DC0000737C8FC5734643F62FB7687347C17C2476
+:10DC100096B49FDD83A19DB7F7BC773F767DFE620A
+:10DC2000E86FAC98BF7D9E467B58C7585A9F58975F
+:10DC300031FFDD8F0DE3F30FE4125CECE3BADC4A55
+:10DC4000933AB667BEDDF81B3C5EE3FD4047FD003E
+:10DC50001D62BCABB4D67A0950942ED6D1965B79AE
+:10DC60001BE2F7D1DC7CFA5EB047D798CCD8CEF473
+:10DC7000D874737FF93126637FEB1C7C9DD3959517
+:10DC8000695D90FF87F905998B20BF9C498477FBDC
+:10DC9000FCB6D4C29A00BEEB6BDD947EFEFE705AD9
+:10DCA0008FBD9E9136D5FA1BCDF8685AA656C6A1EF
+:10DCB000FEC0BB763D762780C031582B557021CBF6
+:10DCC0002415D79586EB80792F14E3031C1772BABD
+:10DCD00012F8CF35E009F330C321521DF1C3F7FC30
+:10DCE00079B2EE02FC8E60D509A98CB1FE7B583862
+:10DCF000A1D1FABF8DFD1504980C9863A185AD875D
+:10DD00001D5ACFFA198BAD2F82F9FCE8D745A51B18
+:10DD10004C787C128187F45FC2F1C5D4703ECEC3CB
+:10DD2000BE4EC674AAF708C0A7A408F3ED5214E8C3
+:10DD30006B2BE64DEB2F62B1EFE27A06557A88EE57
+:10DD400007AD8C713C48069DC28A809E1ABBE95E75
+:10DD5000DBBB8BE8AFDF980D30DF7A633E5BA55409
+:10DD600074579F8CEE0654563317B41FB4241CC14D
+:10DD7000F46129B60EEBE54AD12C3614E7916031F7
+:10DD80008043B3310F9D7560FF0324D6F307F3C8BA
+:10DD9000096B3B368480CE103FD07E4074ED3D321F
+:10DDA000AC233FAAEA242F3AAB663180BFF7D48C6C
+:10DDB0008F19FF7E1AF13168494702BB08845B2541
+:10DDC000847FCED70B0F217DD649B136EC47A94EC3
+:10DDD000B0E934884E70FB91A39A213E5D531291B5
+:10DDE00028CC6BCB5DE3599589CEF60A382801160D
+:10DDF000897B7BE8A14DE1F4F3E8BCFAB4A55EAC05
+:10DE0000E7A1795EC5CA227E2FD24538C1802E5C3B
+:10DE100048178CE8620F966B31ED30B60B055A0F40
+:10DE2000E3BC800FFA23FC601E03B0DD8FEE72CEE0
+:10DE3000A771747602E9344736D003FF033865CB07
+:10DE40007CDCD5CC41E3E508B8785918260972770F
+:10DE50009856A702FCFA2D61610DEAE5D8E0A414FA
+:10DE6000870F6179FF952C1C817225AC4F0D71F8DD
+:10DE7000BC88FD65CFEF483850EC696109FB6B52F7
+:10DE8000ABFFF50750BFE918D4D44CF4C9803E4726
+:10DE9000F5C0C9990BFC572C6884F5D06908F10AC4
+:10DEA000F5FD2CFA0AF6BF23AF467799E8C8E1E4FE
+:10DEB000F29B35CEA37AAE80B665190C11CCCD1F7E
+:10DEC000A3E078AA5F4638EC705BE90F2914FB7B6E
+:10DED000BC36CE3E7020BF56131D0E591325FA0ACC
+:10DEE000D69C9730EF0A744A9837CA1D358A762631
+:10DEF00007C7CB2539D6D43C379361B95B9311FE64
+:10DF000005ADA17A7719D160F8091A31CAE6015D29
+:10DF10000F013A48C0FA9E82F45208BFC7697C5785
+:10DF20008D8725DC3DEB76D43879FF7AE45021CC1F
+:10DF3000FB2681BE9B100F007F56E638D369C0A92F
+:10DF400080A8A9270FF0FEC303F07F30BE3E468AAB
+:10DF50003F21F52E9F85781C4DEAE04CA7312ECC51
+:10DF60004795B81C433E4478CD126547F6BF3D6CDB
+:10DF70002C2CF5F5B0C210EEF5FB5F69190BFDFF17
+:10DF8000CB2485F894F084F5398DB17F09B148052B
+:10DF9000968F93E23AF47BD34485F86AD694759FC2
+:10DFA0002998E2FC4DEBFDF4E01F5584EBEA29D6FD
+:10DFB000EF7E9C3BC9D30A9233C67C56952AD4FF88
+:10DFC000EB65521C59FBE8FB1F6DBA06E6F79B296F
+:10DFD0005218E7F77AF8032FE2C318B71B5E1AF35B
+:10DFE00023BCECE31874E66A0C393B893FBF43EB72
+:10DFF000F93B51A78669D7E743FF28709E10EBF5E0
+:10E00000C37CAAC47AAB54E69E082A5E6EE6ED177E
+:10E01000A99A13E9A0AAD945F8B68FC3C2E5448FDF
+:10E0200055A2FF439D3B1F1D0FFD9F6A5668FEA72B
+:10E030001A39FE4ED5C0FA007E5D2C913101CAF529
+:10E04000134A18C7EF6AFE202346F3D482282FBF55
+:10E050002EF8E35F417E2786337612F45D023B5251
+:10E06000B5E05C283FE9887F13599BB15D9113208F
+:10E07000B24FA2201EC8D89D752FE83AC0BD4BE212
+:10E08000F9D2BA17223AF5DBB2F606D3FA628D124C
+:10E09000975B51467A6FBD90B3315D2239EB0E84A8
+:10E0A000772A30CF29282D490F46A748828EC8DE0F
+:10E0B0002A848AE37BE0994AFF9EC6F9BB7AF2592B
+:10E0C00052EC7AEC27D6F8998395E078594EA493D0
+:10E0D000A5929FC3518D0FC6FEBBBAF5517CF01CB3
+:10E0E000F378697CFE4BA5E4F6817DBC3B1AB3AEA8
+:10E0F000CF47BE5D2985492DBAE383BF65924F772F
+:10E100004A3EA247BD8AEB617D8044E31AE5B78BA6
+:10E1100071964A42EFFDF5EB5E9A7CDD063F746630
+:10E12000A0DC3C557D4B26A78318F187414FBF3EAD
+:10E13000FD8A83E8785E1EC9A7D81AC5225F6E5F84
+:10E14000966EC92F6CE4FDA49A1FAB71F5D42F30E5
+:10E15000D131CB257AC8E645F02922A17E66C2EEF0
+:10E16000CB11F4D3CF5F2D3168973FB1F510D94F64
+:10E1700042EE0D8CB44F5521F768C6B077E3C45713
+:10E180004C53611D01FC17E92C55177C2A5D72A1C7
+:10E190003E6691B4D1580EDF0DBE02BA1BB052B527
+:10E1A000F0734ECC9ACFA8B4E615B33C0CF5ACC7CF
+:10E1B000586F86B04F5944D790BE5AA4C43BC83F4D
+:10E1C0002DEED722B380CF029D8CF9804EB2A36A88
+:10E1D0003C8E75CBB83E1B8CEB86EF399A339E8014
+:10E1E0007EC1AD611D48976A871BF1E8AA0C2754D0
+:10E1F000D3FA19760AEBCD1173DB386B6E16CA2D84
+:10E20000A33F98579FF69B1A76EA284FD57073075D
+:10E210004F55F2835C508EA408F6D5B3C487AD5237
+:10E2200052FFC4182725DEBBF1CC8A5558D7FDCC48
+:10E230001346BF22D3197E27064D6B4A9CE17AC054
+:10E240009B634A671DEAD9A32CF6228E97796DCD80
+:10E2500010A427E9DA9AE19DB06EDF48568D7C3232
+:10E26000FF9A85EC2CDABDB951FD2C947F2429BC92
+:10E27000FFF34182832266E748DCC634B49FBDE1E8
+:10E280004804F52A1B437695C31DA6F41DE42F8090
+:10E290005FA7E0B38F246EDFC1B2124877463F60BC
+:10E2A0002FBD8EF32988F8CB55989FE235FC88EA7C
+:10E2B00077AA509E66B8499E4E574A32BB4CF4FF2F
+:10E2C000B6E8AFDB9F117E448FDFE36B44FDFC605B
+:10E2D000C6C17C61DF7F82E33AC5B80F8EBAD39D99
+:10E2E000CCCFB85F8AFDBB64A233677E98EC0C5636
+:10E2F0001861E6795FC3621F623D772416417A5147
+:10E30000BCDC1E7907E5DE381CF7403EE65510C838
+:10E31000C86FBE6B16D278EA14C33FAD36FCD37714
+:10E3200008FFF3AD7E9F3B17C6037ECC605BFD67A5
+:10E33000D389D50A2FC17AF472C6ED86DF65C41B76
+:10E3400000049FA7F946B34CC0B39BA7F77B7C3B67
+:10E3500030FD3C2D18473BE473B9B5521ADAE37728
+:10E36000A739741DF5958B4522C8F77F457FCD7F72
+:10E37000E3FE8E2189A5EAEF72EDEDE331567D359E
+:10E38000CADDF585AD5184BBAA427FF467B30B8526
+:10E39000BDE944BE46FE70479B43D08F7242616820
+:10E3A000FF2AAD63C8AEEFB60F353E8E3397EDDA78
+:10E3B00060D885267E7017CA163B420D78AC76C5AC
+:10E3C0007CD033267BA5DB7E64B104EA6715680543
+:10E3D000FD44481369683F02A5627B5CD22592D751
+:10E3E000DF67663DB5BEB09425D3072AB6833AC829
+:10E3F0001E5C6E5ADBA59623B6F1E659E77BC5EDA8
+:10E40000BCAA76D6A48752B753D959B3BD8BBA04E8
+:10E41000E5C35FA0DCB06B68DD7A00F1D925F4EFCD
+:10E420009F557D21C2EBCF1A485018F458967F2D86
+:10E43000DA037A93A4219EAA5AE6644A505E754292
+:10E44000C995430239903F169A41788BCA0E61975D
+:10E4500074AA285FAB2686AE47F955F9F7D02FE2AC
+:10E46000BBC0253D01F5A64EAC5B82ED6ED66E734A
+:10E47000B820FFCAD30D34EE72ED0615633CB7CB5E
+:10E48000DC2FFBC393CF8D6730BF63CF64B004E94B
+:10E4900091B813F5C8F27D4A04E3122B9ECD207D7E
+:10E4A000B3FCF9553B67413FD2CF33683E95CF2F40
+:10E4B000DDEDA2F935D07C961FB825F3119CE75B02
+:10E4C0000A7303AD1DABE3F6D22A5833FA29E743AA
+:10E4D000AE9D3B423DF033E061E417B784D6A2FD28
+:10E4E000BB7C4F688C62C2D77295DD112D21FBF782
+:10E4F0008EB949E45D9DCCE5F42721D77C9CAFB46F
+:10E50000E7D0B7689DEDDF70E03AA5C62CE787003D
+:10E510009FEF8AF5423D5A8FBE578A1741F9277BF4
+:10E5200025BEBEF651DBD34238FE76E7228ADFD520
+:10E53000517D98FF1DA80F16EF09AD1D08F5163780
+:10E540008742C8EAD39E7DC6C7EDF88857027CDFB4
+:10E550002D786CF51E2581FEC0DDFB56911F0579D7
+:10E56000F20F563CFBAB037A06B6572C7C7577FB53
+:10E57000839FA13C5DF1822B9C80FE7F0FF6771A72
+:10E58000F673D0D165B6277EDFF1840FF152F61B0A
+:10E59000D5F21DC7BD984DE35439337BB703C83B53
+:10E5A00091FE56B7AFA77156EFBBE923F4CB5633B4
+:10E5B000E8C7649FFC1EFF017ABAE6545DE351D3BD
+:10E5C000FCF6CA19B928BFD9043601E97CA512CDD9
+:10E5D00044BB83EDC9491A27FCBC566F3CEA20BAFC
+:10E5E00027BA00BF6B9B0EE37FF2FCBF6DC3F51F24
+:10E5F000FBF28FDBBE8FF0FF559A1FE97DF5931F6D
+:10E600006EFB1EE4FF70D02523DD2C7FF2E3DF617B
+:10E61000F97FFC627836EAFB2332D7939F863EEF80
+:10E6200087FAFABE5F4DEF8F70B86FFFB4FEAC0F84
+:10E630007BF253A0AFB8CBCCAF71EA473B08FDF5F6
+:10E6400087EC8B22B5E1EFC83E25E105FAF9C33B23
+:10E65000AE38D2F76AF856530AE5D54B293E81F910
+:10E660003500EFBB9FE67E666F78EB83640AC225B8
+:10E670000661E8EAEE7DB7CCFE5A19A68EB086EBAD
+:10E6800065E7D7A2DF666FD78DC71380C7AB7B97CF
+:10E69000AF661CEEAB590B1FB7FA868F88BE6C783D
+:10E6A000FC03FE63526F3C76D9F0F81F7B6FCB4CB6
+:10E6B00060E1BE9CA4F69981C755FBBFDEA7DDFED5
+:10E6C000A98D8F53C17999B0779F95231764E4C3BF
+:10E6D000E79FDABD05E0FCE9BBAEF02C00CCA7CF8C
+:10E6E000FC3908C6023BE738FF2DE4C7F3BF72F9D7
+:10E6F00077409BE5BF7ADB19017C7FBAFFB8531BDB
+:10E7000045CBF14A20D73F65DD7F1D28E7EF16FE98
+:10E71000E2EA5D1909B44F0D7CDD1D9F53A9F9E8AC
+:10E720003BD9AD77C7391FDC1D3F344F4A82BF91BB
+:10E730004A0197E3F13C82CB2AAD83FC6C335EA5A2
+:10E740008988CFD3D723FDA5C2A7B17E3FAE7F82F4
+:10E7500009BFBBFAE6D34FB7BB5429B3379E3F1569
+:10E7600071D9D571E9ED647837E24C4C59D827BEA0
+:10E77000EC7451A458E9C2686FACFF72FC7DF97566
+:10E780007D35B8E522D3E7F5865FDD742EB75F0FE0
+:10E79000015FC2A7E30EED47DF413AF9B583ED8093
+:10E7A0002637177CA46AA37ACFF75F803EB5E13D98
+:10E7B000F9E8C4CF1A73A05D744A88C7ED6CFB0AF0
+:10E7C000D1290AD3CC7E9CFFC8B567C6A686A7E22E
+:10E7D0007353FC8E45D4B3880FD00DD225B9073EB4
+:10E7E000E469F663628F08FF2294FF76775E65E83E
+:10E7F0008F2EC57FC27CAA22654EB41B96B098D3DB
+:10E8000001E932D64AF9E5AC9DD295AC8352574026
+:10E810007372BFA0C27F96EC9795CAA5F42BB75729
+:10E820008CF9BD2E690F5500FD38F219ED131C1936
+:10E83000C0E2C81FCE412F06900E5A007E0CE0B7F2
+:10E84000B6D68F462D6BAECDA7B47B1F2B3284EC92
+:10E85000D07BFD7CFE6CCF934F3ED94F983E008716
+:10E86000263015DA4DF4F816E203DA1FAF75537A45
+:10E870006B4BBB03F95B5AF91CC5138E48EDD3F300
+:10E88000D06F5A2595F2B8A67F7A2EE487B6F84B5A
+:10E8900031DEFF9AC4F96068E5187991A9DFDBB130
+:10E8A0001FC8DFBE72CC40D4373BBF542C7113233A
+:10E8B000DDA7F0F849DD4627D9ADDBEA18C9F96DC7
+:10E8C000935C83C92F060B0BD73359D8D547A7BA0A
+:10E8D00006DF07F5DE5DA684310EF9EEB94732504A
+:10E8E000FF1C7AE01F6EC278DAE413FC7B2AB8EFD3
+:10E8F00010F1B25D225EB61BE088F93D00474C9FE7
+:10E90000ACD5287DBAB698CA7F561BA67C7BED4451
+:10E91000CA3F5F1BA1FCBEDA4ACA1FA88D52FE6027
+:10E92000ED7C4A5FAC5D46DF7D1BDC31B47FFEA928
+:10E93000B69ABE4FD6C332EACB446D0D957F5FC900
+:10E94000263A1FDA129663F05D6B666EF24B74BE68
+:10E950005FB0C3D1795BD404CFEF2BDCEFFD4791DF
+:10E960001E91C2F58497DBC04E85F50EAD18539EFF
+:10E97000077C34675E484372EFC14BC8515E72E555
+:10E98000F8A817FDDF3A4F61C526BE9B5B61CDBF7E
+:10E990003EB53380F2E275740C063236BAE9401D9A
+:10E9A000C615779F672C13E795EFA038F48EB4D87F
+:10E9B000861130AF6D031C653BA0DD8E31FE816694
+:10E9C000BB515639FEB76771FB74C2111E078D7FAC
+:10E9D0003C6C473DE990FFBC7409F01FC47F23FFE6
+:10E9E00089FAACD8EF31C749E20F88FD0F749EA1B8
+:10E9F000FD2F1FF0C7D13E8F4B32C1015226935DD0
+:10EA00002FEF407B9C699207E5FB7628CBC4F9D5B4
+:10EA1000CB3B306EFD4B01B7B8DF2F874DF30CB207
+:10EA2000EEB89442F25D639A733C7E67E4571BE54F
+:10EA3000307CE292D07DB8DF43E5B0A460238BA0A8
+:10EA40001F66EA87F44471DC9487FF46EE31C5B94E
+:10EA5000E0BF51EDD6FCD507ADF931096B7EEC3145
+:10EA60006B7E5C87353FE11D6B7EB32AE2963A3BB5
+:10EA700081FB0E4384DC635AA784F01D22F6818259
+:10EA80003ADF6F0FAE516D7174EB3E03C32DA5F1EC
+:10EA9000BC0BFCBF499DD6FA9AD887D06CFB10AC52
+:10EAA0009ACB2DC33FDCA832F297374EE1FB09F039
+:10EAB0005791968BFB08921FE5CECB6D7F2AB90F3D
+:10EAC000D2601BD8EF6032FDF4272F0750FE5EFFA7
+:10EAD000801C45BEBB3ED49986F8766B6111A2E9D5
+:10EAE00086B37C69426AFC454094E07C367EC9F975
+:10EAF0002F7B864AFED5055DDB81F16E034E230434
+:10EB00008EF7AADC1EBE698AC302D759F90E0B5EC6
+:10EB1000BF76DE0AF7EB2E5AF3A6F909387EB5FC6C
+:10EB20000881A76D20D7501FA4395B491EA6FD564A
+:10EB300009EB50A7A8267218B70782ECF454DCB78B
+:10EB40003CB9E6BC447ED739C6F6C3BA26D778802E
+:10EB5000184DF3D9C5F1E3068824DB6F2ADC7C6508
+:10EB600078A5A646B0D804EF8266F0F3418F0797E8
+:10EB70004DFB58C5FD9A2556FC033E5897993ECC4F
+:10EB80007918FFE4B29D1B717D0B968D198FE018EB
+:10EB90007251A1FEECFD2C48EC75A0BFBB6059552D
+:10EBA0000EEEDD1BFC0CDF5F72E1F735E1EB314669
+:10EBB00016BC28256F5FD32935249193432E3A93B1
+:10EBC000D64FA577821755AA6FE4B7811EEA725C0B
+:10EBD0005E8EFF0C8DA271BDE5F9E85F7549A8F75F
+:10EBE0007E56035A1DBE5F5D175730DF7ECE2F6302
+:10EBF0001A6EEAA4F2310F30CABFA04339CAC7BFA8
+:10EC000000F4000F462863ECC7BC1EC82719F58323
+:10EC1000BFC62FA3DE0FE9FCBBBF86B10CD4ABBAD5
+:10EC20004C765EF09CDFC34C72FA970FB0783D745F
+:10EC30001604B36A4A29CACFEC99C548572FC9EDC3
+:10EC4000B89E5F82DCF560BE0EE42EB62F642AD635
+:10EC5000238C1AF266A8452ECA283F87E832C5FDE4
+:10EC6000D91ACE276ED65C8776DCE5E4DF84233BB9
+:10EC700007617CC22E077F897AA0E4F2F2F082223B
+:10EC80008B383DE7678F5BE2F6630AF9389559E503
+:10EC9000F97F97BC9451CFE1BEBB43CB92483EC9AC
+:10ECA0000CE5645C9FCBFD0511F7223C2BBDE9719F
+:10ECB0009BB083BAE9B991DB1DBDE8DC21E2ECEC45
+:10ECC0003A66A69B60A3F6D014616F691AC2457BB1
+:10ECD00018F76743C7143ACF126AECA844FA282AF7
+:10ECE00093199A78301F6A1F15765C1A4A65944FFB
+:10ECF0006B1997EF3AF34EEDD72D82583C92938DD6
+:10ED000076E8901A6B1CB4D8D80F8F737FCB0DFFA9
+:10ED100043F95474CE1A8709827F5E1CC2F95AFDEA
+:10ED2000B2A038CF10B4FB6B025EDDFA1AF7EDDD4E
+:10ED3000647D5C427AFC3F2DDFBBF58EA01343CE91
+:10ED40001B72BFA8263A7B3CAD5B22BE0CEA8CF658
+:10ED5000A986B0F38750CE4D6EE5E749FEAF93F339
+:10ED60006BC05F29492DDFED7AC024DF2D723FA5EE
+:10ED70007CB7E901BBBCFF5BC9F92AC1AFECE22556
+:10ED8000B267271B74768E515C97FEE81C957F3B1B
+:10ED9000EEB75D3CFD51BC01E3F8D9FDC82F3E60E4
+:10EDA000D86965E21C1AB3CE63801C3BA026395794
+:10EDB00075C09013330AFB3C97981196AD74619C13
+:10EDC00053C1739526FCA769032DF5F472CEF7FAAB
+:10EDD000AB8E30FAA08707B07DE8C71C16FACAB020
+:10EDE000C767E78776E0BA1C1747320DE0B3D0114A
+:10EDF0001272053C723CEF2271BA76E446E763FD7D
+:10EE0000FB3B250DE5C62C607484D3FD8ED80C0722
+:10EE1000ACFF9FD3FF7E3EDF27EEA4735887250EFD
+:10EE2000373D8FC5C9AE07B311E9CF25F8A49C853E
+:10EE3000DDB282FB775EDA276353F87E2DF3480458
+:10EE40006716503F319FAB2917786001C6CFD14478
+:10EE500098E6EFC7F723B03F17081C0FE82FC97DCE
+:10EE6000E81D8C57B954E6F611DD2FF49F1D89F586
+:10EE70003AD92548172BB19883AF4FC5788243E024
+:10EE8000CB911BA37D960F586C09966F9AFCFB776C
+:10EE9000148CB7EE4FD3148A6F76DE3C54FB9FBBC5
+:10EEA0002E23CE00FC1D41FCE64FE67EAE41473FDF
+:10EEB0007088736F4E9E76D39DB0B7090E49F67178
+:10EEC0008CB88611CFD8A876B8799CCF6AB73B9812
+:10EED000D54E37DA6FFC323A9FEC75431FB6644B60
+:10EEE000A85776B6CCCDC47379471DB2653FA8400C
+:10EEF000F05F4A7DD82CCEED097E6DC2FA437BCA05
+:10EF00009F10EB0CE65E19FF1AF5FBE0DF271C49AA
+:10EF1000F877A30A7A16FDA013E21C9DD0C3063D24
+:10EF20000573FDE5688F851AB93D3F1CCF404ABD8A
+:10EF3000F5A6A17F0B84FE1DC262E59249EF1A7A05
+:10EF4000656773E9AB68BF0D794B09E3BE8AA15FC2
+:10EF5000404F74713DC1F5EDB0ADAA2DAE1865C836
+:10EF60008F4398E93BC6B184BE75A4D0B70E810724
+:10EF7000C757D4B7ACD8545E60A1932BD2A760AF6B
+:10EF80003C54215D413B3DF29659EF3E23F4EE1097
+:10EF9000A10747B1D3F5E900AF8216168E43F96891
+:10EFA000D6519E0E3808B5F173BDC6B959038EA16E
+:10EFB00066ABFEFD93615F5D460F0F6D33E5E9FFC4
+:10EFC000758A5B1A7430B2AC6B6A854CF0B7E86531
+:10EFD000474533C5D7839532ED7B396AACFDB89F81
+:10EFE000B6EAF72FB1C33CBEDE9CECAF3E2FFBF878
+:10EFF00006FFA7D29776BD63C813E62D2539933D4A
+:10F00000E3BE5706033CE39BB552E4A3698B9A5DCC
+:10F010004180F7CE56AD949F4374CB6497761F74AE
+:10F02000E1FB8435F84F9477A7242E3FF574D2DFA7
+:10F03000463D63FCED2D73DDE81765E715CC0EB199
+:10F04000D4F34C15777D78C8EF2A719C10D8B9E8B5
+:10F050001FFD6848F030F2A1E3549A86F9A9BFBBBE
+:10F060002D82F268E7697E4E71675EF5105662A1E7
+:10F07000334B3CC2908F76397739F91613F2F66F1D
+:10F0800025DFA63ABF9A7C33EAF721DFA63AFFBF15
+:10F090007CFB1F28DFAC7EC53336BFE272F2CD2E7B
+:10F0A000CFBEB2BC1072D42E37662B912627D0D398
+:10F0B00085CAFB6E4843BA10766B765DBD0BF3A92B
+:10F0C000E4475C2FE853DED8F9D8D877990D76AAB3
+:10F0D0001B44CE6C60130D869A19E878F13C23BB73
+:10F0E000B30DE77153FA97B9C4546A359D5FB7DB26
+:10F0F0004F52FBDA28A7836AE2A3068D752AB4E98A
+:10F1000092DC7EB2CF6B1DE37E0E0C4FF199A0B066
+:10F1100087E5F44F062C82EF4F3925CBBE9891B28C
+:10F120001AB0F30CB815D0FC75F4C35CC27E645FF2
+:10F130004B237BAF44EDA473F915FE391559F0FD4F
+:10F14000FA70A8D4386BC4289F457CFD88337600BC
+:10F15000F974B6F7AA0AE20B715F2A95DFD03D0F6A
+:10F16000637F2D0286B9492FB972437216EB59F7A6
+:10F17000CEF4E821EC3F1460E538453C87D7D90749
+:10F18000BE5E14F7787601DED422C68E00DE30DD56
+:10F1900001F217D303B51A95BF545B4CE93FD586EE
+:10F1A000293D583B91CAF7D64628DD565B4969BCD4
+:10F1B000364AE5452CFA06E275CA856503915E1A62
+:10F1C0009C6C19DD0713F7B18CF1DF73F2FD062398
+:10F1D0003DE5D4080FEB1C1C6EFA7127B7A7D5C804
+:10F1E000203C778D29D287ABA555453ACDF11F97A5
+:10F1F00033219DEB3DAE6740DA3E4392D13FF205AD
+:10F200003C093C5AEC1BF6D139D0586CDD0CE804B3
+:10F21000BE3F3B03E4E7D5C0679B1309ECCE376BD9
+:10F22000ED3D4857BEC06FBF4F69E2EC0F102FCEC7
+:10F23000467DC183D05F86DCB16005E2799B93CEC9
+:10F24000356EF9276784EA15FEF83B988E6291A91E
+:10F2500059D0B5AF72EFDF113ED5586316F0F3A861
+:10F2600079FE30C6D1B7383B1B70BFA67D010BE3DA
+:10F27000FE8CAFF21FEFA7F6FB120F60FDFE7F3989
+:10F280001F7B04EABD7053F3BB78E7E7A1195F4623
+:10F29000A7419A3FE1EC827B217DFE60E3769CC72B
+:10F2A0006307E7A5A3DFD21A7EE461147F635CDC09
+:10F2B000BF730E38EA1E0AFD6FA996494FB4840F3A
+:10F2C000533EB02A9BF2A3C7C851D443CF4FE1F7B6
+:10F2D000AE0CB83B5DFC9CA8DF25EEE185F9BD29AD
+:10F2E000430EAB65FCDE8EE3457E1ED67190E7DDF6
+:10F2F000B9D54CD248DFF85D645759F591A17772C2
+:10F300005D7EE35C7536C627F7B7C97EA4FFFD6D49
+:10F3100073D3D11E8094A1DE718465D293A38F47ED
+:10F320006F1C05F3DE5D7DEF843AEA279AFE0D98A7
+:10F33000478E8BDFDF09A02C19D747FBCFA03D8C70
+:10F34000B37B25B4D77ADA0FC2F6B0CE426C9FD722
+:10F3500047FBD01CDEBEFA3ECBF843C5F825971913
+:10F36000DFCE5723C5B8FB4F3C9F85F4FF53492B95
+:10F37000C2A3C937BB7EDCA04EC2FB43E1D3747F7E
+:10F3800060EDB3D3E603DFCEC073CDE4CF577BF897
+:10F39000BE6C98ECA952217BE6CAD51B4AD0FF7CF3
+:10F3A0005561B84F9C5A4EC83DF104124026FD41AC
+:10F3B000F96C5B7EA0AD7E81A57C81AB40ECEB5F00
+:10F3C00065AB576AC9CF7D715805D2F5DC44BF7271
+:10F3D000A4EB54F37B6330E79F3732F8D024D82670
+:10F3E0008AFB5418B4D19F9D5601EBCFF1F1FC1D5F
+:10F3F000EBF637D479A99CEE23BD90C1E31E467F7E
+:10F4000077B8B8DC5E21E858893BC95F570EAEA5D6
+:10F41000F3DB063D2AB3DCA7E93C7782D3B312586D
+:10F420004B76BB5AB9BE0353B7B79BAE57105DB707
+:10F4300027A76B1022849771C20EAA619D5B483E7C
+:10F44000EC93493EB0EA4CB297C7898635C28F3FEC
+:10F45000B26FEE83586FDD2C9599EDEAD1A21FC3F0
+:10F460007E1EDD3D603EE5AF761BFD74BE8AE75D26
+:10F47000D95199F09FFD52C16C5267FA20EAE76AB0
+:10F48000712F23B3FB7C7C98E8749F749EDAE93774
+:10F49000F176867E36E82B2CC637F475A53B9BF0BB
+:10F4A000FD42A25CC6FDC0ACE9D2182C9FD1527DB2
+:10F4B00018E75D5C534D681FB6479B5DC2F98CE44D
+:10F4C000C50B5B172D780372A3B7F27B8033DA7814
+:10F4D0003A2A2E533A3AC0CFD1CF88F374B7F0DB33
+:10F4E0001C012E77466DE5FED34B82DE46178EB5A6
+:10F4F000D81D8E7D932DF98B9D43FBB44376D74663
+:10F500002DF74E7F2ACE6518F873D8FC9497041D0A
+:10F5100019F832F068AF773C8FDF4B4B3D2E3F1F21
+:10F52000B68799E81B00B6A74D16F9DF29D35571A8
+:10F53000FF7A724FF9BAADD6F2178CF67AD7348CBF
+:10F54000D3BFD0A652FEC5755DD3EA0A01BD02BE87
+:10F550008E360E3F35C008AE0E0147939C7EC9859E
+:10F56000FCEBB6D2B3EC8E909F30CB1B6A40BD79DA
+:10F570003F7CFB25B0F4B8531DE52031701F623A83
+:10F58000C6757F931151519FB58F92C278EE686610
+:10F5900073EB513CB758F7FEF01FAFC438E20127B8
+:10F5A000F95D1F087DF4B983CBE19AA372B81EBE42
+:10F5B0001F39FAC6DC1B818E1C8D059673238E7D48
+:10F5C000F322783F972558B808BE8FDAAF2A4B4D03
+:10F5D000F80C471C245747EDCFBD11AF3636E5EE8A
+:10F5E0009AAC083E5C9081E3B9F87D8D8843B7AD55
+:10F5F000F703E2DF96E4FC3B5361BA82FCFA8ACC63
+:10F60000FDD64A7FFA1CD33987E78E819E84714BE1
+:10F610007FBD6BDF1B50AFD13F792C3F37D5BAF0A0
+:10F620005EF2CFA68C45BDFE4717BF97C5FC29FDEE
+:10F63000B13F22DCEDFED885CA33746F2758924E55
+:10F64000722AB84FC829E15F151BF2C026C727757B
+:10F650007A2C7162B9D11A370E9AE538C533AD727A
+:10F660009C9D1AD9535E80F3C87D2D93FC072DEB2A
+:10F670002A58D78D2FCADA06A2C688772ACC630EFD
+:10F68000E3F37816CF39019E6E7C0C4C7FA087ED9A
+:10F69000427E18FB23CF35CB54DE5428C5F1A8CACF
+:10F6A000CBB9329DEB759DE0F7EEE6083FC755D329
+:10F6B000514E7AADC261F503D774D6A31E1DBDCFDE
+:10F6C000E4DFC17F3384DF72A3CDEF9B81E7045178
+:10F6D0008ED8FC44FB39BF02B7F59CDFA6EF293476
+:10F6E0002FFDB70ADD0FF8E924A6E37B081800C058
+:10F6F000F9672D1A18A7B8AEB817F9BCC08371FE08
+:10F70000EF6A37F7BF8FBEFFB907EDE9F1C80440D4
+:10F7100067CF6EFD2EEDD7FEF458411AAEEFC8E468
+:10F72000931E714E9AE247867CAF9F7CF2D5BB60F8
+:10F730009C17B6CBE416ED39583A08CF4F3C52E14E
+:10F740002666F3ED8CD2BEEAFEED465C9FD3D57AF9
+:10F750008107825D2EDE0BE4F181EBDC3CDE3A407A
+:10F760008E5EE7CEEBE167DFD0AA8118C7D81DE235
+:10F77000F7E82ED74F654F3F95E67E0C3F67B61CE6
+:10F7800053F9E1B604C9CDA0A0F320C6C5916EED32
+:10F79000FE5107B703C0CFB9C53D0EF717AAC57E06
+:10F7A0005FA29C2E5F5CB99FA35BE214FE7B225696
+:10F7B0003F277607F6AFE56AF528575C01BF8C71E5
+:10F7C000FFE98A97F079A1869F734B35CECE5A7E9A
+:10F7D000FFE871F47F8A90AEFD943F827E0FF92F8F
+:10F7E000B115088F600BBFFF13ACE1F7F41B9CE170
+:10F7F000F968B73DDC5C598176DC3A87BF14F3DFEA
+:10F8000069AE6C74437E887C7E00F3E3FDE5F20A0A
+:10F81000CCFBF0920BB0661DE4F5008C2373F8EB83
+:10F82000BBC53E81CAB22B61BE2396E492BF304471
+:10F83000F6CF2C46F9B49CDB13BE5DE027F87ACFF7
+:10F84000FF71A13F7D0DA7EF417C37B9B9FFD424EB
+:10F85000E8D4C82F56624D08273C76A99AF157C3C1
+:10F86000F74940AE0D44B99404DF4AF73E635FF8B0
+:10F87000DED58DEF1F1AF8CE0AF5E07BADDBB85769
+:10F880000AE38CBA72FC07193FA799CA9F775D1CDF
+:10F89000898F7074E7015FDB095F016EDF75E34BF1
+:10F8A00006BFD38BFB25DC7EF42973AA91CF5E10B3
+:10F8B0007032D2A7DD224EECB5DEEB0339FE34F612
+:10F8C000EB56ABC5214F2EC77D0DD08FD7045711F6
+:10F8D0004F40B8623C61B152FE1CB6DBE736FCA07B
+:10F8E0006ABA7768C437FE6A7807BAE1FDBFB0FF2D
+:10F8F00059C897B84FC53AF93DD12B84AF714FAB7A
+:10F90000E75E96D6E847F9F83D166E80754CF3CE63
+:10F91000B1DC5732EC037B7F4759ECB8DB1437A9D5
+:10F920007BFFFE3B90BEEFEF92283E3B9BC5547E93
+:10F93000E92A41F777CA73B43209FD1E7D75C56F98
+:10F94000C0EE2F47614876CEDD1568E794A7F37CBB
+:10F95000CEFAD626BC375D8E67EAC92FD8C0CB87D2
+:10F96000F2F2FE580EF97F74467E47F4DD2337E24B
+:10F97000E6B83DC88933585EE0CF2ACFD2707F9079
+:10F98000DF57BC52391117F26187888FD8CB81EECF
+:10F99000CE63FF41DD2E2792C73BFEB7A03323FD88
+:10F9A00042E891EE78C74623DE111EC8E31DE181CF
+:10F9B000667AE98EBB4F4913FB96223EDF6D3758BE
+:10F9C000E5B43D2E6FD0558F9F10E1FEA68DCE0C75
+:10F9D000FFA0487C3BB2DE99B80EE0B563A29BE085
+:10F9E00035BB85D361FEA6652A9A1A869CEFF4F092
+:10F9F000F594087ADCDE5C3E13CFA7664FE7B77458
+:10FA0000DBDC91DCB4BC1E7CCD7747FAA559F1173D
+:10FA1000B3E12F907605F80B7AD32CF0EFA64F8147
+:10FA2000B737459CEB6D11DF2A6291229C4783D347
+:10FA3000D85FE7EF00A4A28394E7C2057E0DF9F238
+:10FA4000A687E3B527E5FAF5A8A85730914DF667E4
+:10FA5000F6F41B49E3F58EA6B1A4E785AF4BE3F2BC
+:10FA6000C9D71025B965ECF7879AB9FE36EA4D4D2E
+:10FA700093849FAEC92467999FD20A31AFC2896C23
+:10FA80008A79DCD962DC0A0F2FB78F7BB331AE9055
+:10FA900097C6B845AD30AE895FA2DDE346C4B85124
+:10FAA00019F93CD4CCDFF9285CC3482F6B9BA31118
+:10FAB000CC1FCDBAA1F061B4E7F38A4BB95D1D61EB
+:10FAC000F80E539598CF1667241FC70B029C304E33
+:10FAD000A7C0BC3175D430F2DF1D5E9DEE8998EC75
+:10FAE000FD2AA2A740727BDF80BB4F65152E93FCD9
+:10FAF0001A2AF062E48D751AF1DBD1FBFC742FEF4A
+:10FB0000965912F1DB8848603B9E1FF842C065E7BA
+:10FB10002EC6FD5B57C78215789EBA89DFDBDE52A1
+:10FB2000CFE31B5B9C9DCFBF86EBDCE024BF69D796
+:10FB30007EEF8CABA0BF7ED17B0EE541BE6DFFDAC0
+:10FB4000E75E83FC5378090FFADBBBEB919968877A
+:10FB50006F5DC9E376467ED03DB9947FACE59119DF
+:10FB6000C3503EEC92E91D85BDB6789E9EC6E379F2
+:10FB70001BD2B85FA2B670BFBB3B9E3785FBDD0EC4
+:10FB80005DC4F396F0F37326386E2038A688E76DCF
+:10FB90004A137A9CB5A679601E7BBD3C9EB7D7FB05
+:10FBA00008D9BF7BBD221E1691693FEBB18ED69955
+:10FBB00057015C1AAA8D785CABE71BB81F95C6E3AA
+:10FBC00069FF80038C33B7E7E72D8346FBF3ADB4C1
+:10FBD000FE8695463C90B77F54B4DF86EDF3FA1865
+:10FBE0005F7B98B7C7789E69FC9FA4F1B8DCEECB29
+:10FBF0008CBF77D7F3594B4DFAEF0931EE0801D797
+:10FC00009107ABCB51D439594758E86FB7F9BCFCD1
+:10FC1000E3CFB475BE0AE54F49D56FCC40BC0DE0CB
+:10FC2000F69C61B719F57E2EE8E91541FF47B6CE7F
+:10FC300065E83F38B60AFF780D237C0FFFC99F2483
+:10FC4000F37C862CE171C7E13FB9EFD51149FCE3A4
+:10FC500057D25C3CAEBB84CFD784E75708CF29FC92
+:10FC6000E30B954B64F8CC4635F238DAA8D6B5C428
+:10FC70006FA3F6E99C8F2F8E25BB6BC8C531F41896
+:10FC800045F0E23594775C9C44F9216D7CBC3DC223
+:10FC9000EE1ADDCCDB3B305E81FB507AA9C56FFDEF
+:10FCA00022AD80BFCB56638FEF7C508FFB60179ED9
+:10FCB000F687CDE7CEECE9368CF398F4F2E3DDFB82
+:10FCC0003C3CCE53608BDF7C21E4953DCE63D41B5E
+:10FCD00026B128B67F6AC3DC4CD6477CC9D8EF353D
+:10FCE000FA1BF6031E67A73FDCB7CD8DD0FDE5619B
+:10FCF0008FFDE9D7B8A7AAE65594211F7F91C6EFDB
+:10FD0000E5DAE33146BF809F2F50DF19F832FC312E
+:10FD1000438E831C6B34CBB1D31ED9F2CE86A12780
+:10FD20000C3936326E9563C3518E493D7A69FB7644
+:10FD300046782E76B55F7815E5D87ABB1CD34B5F35
+:10FD400045FA7A84CBB1D6AD8B24945FFD17D60DDE
+:10FD5000580EE9C867D710FDE57F87EF3F347A7802
+:10FD60001CE8A75BEFA5EF3FAE16F26B09CFEF5D86
+:10FD700059C8F35B65925F763936C0C3E5D8628FA8
+:10FD8000D897D86ADB97B8BC1C5BECE9635FC2D03C
+:10FD9000B3D0A4C2956DA60B1B1C0DBD27F0D93A9C
+:10FDA0009FEB3D23DF3FD68FF4EF1D02FE172A4F56
+:10FDB000907D5212AB1B83F65085FFB46CB69F2F1B
+:10FDC000CB37ED9C6F9E117CE3684FCE2F7778B2D6
+:10FDD00053F04BDFF1D0CBF18926E2C746F91D9EE7
+:10FDE000E47C62D42B117CF2B3FABEE3A1069F1827
+:10FDF000FD95A4E09392E7AC7C7287E7B27C7287B2
+:10FE000027099F80BF4BFC837E99C59F12FEEE524F
+:10FE10008FE18FA5D263420F6CE5F235951EBBD3FF
+:10FE2000C3F5C16A0C968E4BA2878CF629F4D8DDF7
+:10FE30001EAE87EEEFD5DE367E0A3DF65DD1BE16EC
+:10FE4000DB27D383A2BD5D8FFDBD98F7E8A75B0FCD
+:10FE5000E3FE694AFDF58BB6F86B50FE3389CF5F40
+:10FE6000AF93296E36E28925F42E8A5D8FB50A3E5E
+:10FE7000880B3C1FD1418FE13C76CDA3F339861E20
+:10FE80001BF144723D36E209D5539C448FC53D2297
+:10FE9000CEDB5B8FC53D7DC4792F541E253D562C8E
+:10FEA000F458B1D063C5F18E2BD363367E1C69E85C
+:10FEB000B1147CF9A687EF5BF4E6CB170E239D5DAA
+:10FEC00038F8B7D563867F914A8F75F3E715EA3125
+:10FED000A3BFC7DB79FCBB873F63BBADFCB9643C08
+:10FEE000F2E79B424EF7C19F6F7AF27AF36789CAB5
+:10FEF000E33A571AEFB09F3FB9DC796917EB9CFAE8
+:10FF0000309DB38868E926FF0650D96896F76FDA06
+:10FF1000ED7FC3BF12EB4E25EF03E986BC6F24795A
+:10FF20003FAC5BDE3FF7D5E4BDCD4E4A651F05D241
+:10FF3000FF7BE47D20BD6F79DF6D175DA1BC37FAD3
+:10FF40007BBCCD4A4FA3F7013D41D1E36B163D8207
+:10FF500076F1E8FD4BE85E41205D492AEF818E0293
+:10FF60008847837E5CFB741D434420E789BED02F05
+:10FF70005593C879239EF0B83356949E541F548BE2
+:10FF80007D19BDEFF7B8F29DB48F159C184D20DD9B
+:10FF90001F65B1D1D85FAFF7B88687F3F13E6B43E9
+:10FFA00096F16E9EC13FE19D484799D79E6B3F8277
+:10FFB000FB4979A56371BDD7A48BF7836DEF489991
+:10FFC000F8E79A74937EEBD97F6661735C7CED8071
+:10FFD0005B53BD8B352DDD64CF3872F9BB58F6F716
+:10FFE000A91437BFEFAF97B3E26A6F4F3C83158A0E
+:10FFF00038A8886B1AEB710734BA67305BE07780FA
+:020000021000EC
+:100000001C9D4DF035E667BB1FBF5E8AF14797BC6C
+:100010003A2F17F7E5E968184CA2B196BF57B051CF
+:10002000DC8F077891FE52BC617ABFD751C2346C25
+:100030002E95B4935F945E529D8FF7ABD7A5B85FB2
+:10004000FDB09857DD6027CD77C3FB12DDABDB50E9
+:10005000343EDF7CDFDD2578EC68C67877A7899EA3
+:100060001B02A5745EB5C13BB7CF7725BCADFCBE06
+:10007000CC65EB352B96FB2AF65409B366DC875228
+:10008000D4307F97F6948BEC6F9778BF98754AE2DF
+:10009000BD531EE733E62D79AB89EE8CF89E4BF00D
+:1000A000E9B4D2896EFCDEE00ED3F9FE8640DFF2C1
+:1000B000DF85F77672E83CE03AA49743237693DE37
+:1000C000F668D5F45E9C2B0074330ADF8568E7EF91
+:1000D0005E013E700BE3727888A573F9EAF0CBAC51
+:1000E000D824B79CFED67C7CE7D659E864184FF13B
+:1000F00095C9967BEFEB25BE6FE51472C8E8EF1645
+:10010000D15F5CA44813134B917E5F26FA0548D358
+:100110003940EA070A6F5022DBD3F37A7F37DEBF1C
+:10012000115382BF7B2CEF6D19F7DF8CF8E290CD75
+:100130008CE867B8CEE573B15E7F8F4CFE083F2F29
+:100140003B74B3CA90BFA19CFC10A3FDF0B8D3725E
+:100150007E36D46CCD0F15FB9845E2FD2FFA0EFDCF
+:100160000C15FB9E436DDF8D774AB6E18724FB219A
+:10017000F6FDCFC3E919B9B46EDB3B27A9E8C0D8B7
+:10018000E7F4B1C831E2E71ABE8FD03098915EB67D
+:10019000D737E4E6C5D337F4A9874E821E6A349D6B
+:1001A000C3784FE8A193811D198B4ACCFDD5115E10
+:1001B000DFAB7DE7DA338E1E3DE43BFCAE2394419A
+:1001C000E94BFD806EBEB932340649FD9BD5871CD4
+:1001D000E6F73016AE7CF7DA33A6F52FC8BFB5B117
+:1001E00091E842FD02F78F317C89EF9DD13E4D5E53
+:1001F000CF38EB607E678AF0DD06EE1F6F2A72C68D
+:10020000BDF0CF4D5FF2FBB7FA697EBEBDA9763E69
+:10021000D5237908F0CFF5723F3773E53D6E7E5FE9
+:100220002AEAE6F299F3A9D27D3E48E853C1A78AAB
+:1002300010F44726BD4C72A78685E9BC1E3BC1CF92
+:10024000756D3AF42EF19D1D8EADB5FC5CC983F839
+:100250005E06094FAEC7BD46DC5FE86BAFE8BF4145
+:10026000BCA751C312CD8B4DFDAFCDAF7717E4E2E4
+:1002700039C102CBBB632D2AC7CB865AEB39F66F47
+:100280007A0D3BB32342E726BC8CEE1D679685139F
+:10029000888FCC955288DE53047C94C37A32A7743D
+:1002A000925CD894422EFCBBB09F16564B749F6A4A
+:1002B00013C097C3FB88A33FC2FB6BFCFD3E7BBB17
+:1002C0008898C7FF6BF05DED35ECAEBF0D7C07790C
+:1002D000397CD580EE42BBD4CE17AE40DC619603AC
+:1002E000412956E9CDA3F7E6697EEB1DADF9F796F6
+:1002F000A01ED66FA07B12B9D6FAA676B3BDE37A5C
+:10030000B75BDF6D3FCC233E710780BFCCF23F1758
+:10031000F8C824EF7BF8BF9EE3B73097BF136BE3B9
+:10032000DB54F26743C561B706F36BF1CA64677AC1
+:10033000A696B90B4DF35DEEE57184062FB7431F0A
+:100340008C1C761796F42E6FF1CB963894917ABC6C
+:100350002A8D93E9D5049ECE47F03E21DE07443C2A
+:1003600079F30E77E0F9BAA64001C5B52E379F356F
+:100370005EFE9E61AAF918E5A9E6335ECCE71A9CF9
+:10038000CFB8CBCFE74C7AB401F164D877767D282B
+:10039000679475A0DCBB77B053EB6B1FF4642DBB87
+:1003A000B6B088DE796DC3F30EBF68B9616D533E98
+:1003B000DDBFA2FDD827BC4BD7E27EEC7B32DFF756
+:1003C000646A7BDE9C51B8CF73605C5512FA79CFBA
+:1003D000D3FE77B4DF1974FA51BEAE13F6DAEDDF4F
+:1003E000C8A077408C7AAF0AFE582725DF1FDBEFC5
+:1003F00095855C681FC5F7D7A3A3CC710CFB7B5711
+:10040000B72F93AE2D34D1E3C9EE7BB4F10C3C078A
+:10041000D694B7BB28D97C4FA6C5BF4DFA60B0753E
+:10042000BE0B6EE5F305F93F0EDB3F27F8CF98EFE3
+:100430003ADB3BDA467F8F7B8D7D33982FED9BF146
+:10044000DF4FB1CFEF3DA3BDDA9E21E059549504B3
+:100450000EEFA5B5279DDFED383FD33EE1BF0A394A
+:10046000DA33AFF6C17346F59ED701AF1127E3F338
+:10047000233C63FF5FCF207D68E07D5BCB82B5B816
+:100480004F7F52F8B100C73C01C771C9E679D2135A
+:100490004F8AF705DFB0CEF36CAF79C6472583DF0F
+:1004A00015CCB3CF751EC339E7F5D52EF9B8EF6378
+:1004B0003B18F7B75354F21B75F01B8BD09ECDD170
+:1004C000BF6B7E57EA873E1E27F9A18FD3E99F674E
+:1004D000553C54C130DE10A27DE765AF291457CFDB
+:1004E000BF9A25E45C7C877EE876DD0407435FE005
+:1004F000FE33FE408371EE654359B60FE54C57E37A
+:100500007712185FD34FF1F7D553F1EFE70EDD8582
+:10051000F18D8DE59E6566B9E2CFE5F36BCEE2EB3A
+:100520001AEDD56F0EA1BE8BA81A33DDBFA9F25705
+:10053000F3F7C3836137C60B1D2CB26924148EFEFA
+:10054000C53C9FF55DB618FB2AEFB265CF283C8EFF
+:1005500070FFF33185DEB138A7466F9E84F0F4AAB0
+:10056000640734C56F59C52FDB45C7217E33DAB820
+:10057000BFD25CCBC8896CF2960FC930F9B987C677
+:100580007B088F67BF26D1B980B79DB16D2E80CF14
+:10059000B9932EB683CEA3804ECAE6F790285D3875
+:1005A00046A3F72E0025F86EDFEC593756A2FD1D45
+:1005B000CE0819FBDA3E7922C04DBCA7B1718B443D
+:1005C000F87967663AE597B5F17196A11D427C1AF4
+:1005D00073CE379FEF619DD31EC034C0225FC7FB2F
+:1005E0004F6D736662FFB3E7ADA27391B3276AA53F
+:1005F00094563E1895287DCECFF387FCB4FFD29A4F
+:1006000043BF93D05526D17DBA3B2BF9FD96D995A2
+:10061000C7A95ED792256B0720FE277AE81C6D6C70
+:1006200096340CF7CBBF5D09FE3BD45B3C4B2AE410
+:10063000F54F53FD45B3A4028DF29F51FF2FB71E16
+:10064000D98CEA63266BA5733A95AC9AD2B76E5DE6
+:1006500041FDFE7E9287EE310DF3717BD7D3B07DE5
+:10066000193E83B7A879CCCB382FCFB5C561BE8FE3
+:10067000DF7DEFCD796910E331AC7E5C7F23DD78DF
+:1006800014D0E6C0AA93C0C1A800387BE438E52B9B
+:100690007CCFAE6D9C84D61694835E5984E513B1ED
+:1006A0009CE73BF764AC3B3AA9277FA069F8BAA363
+:1006B0000330CFE5CF68DFE41B50FE644EE2F12942
+:1006C00095F17741E0934EEF84C1BFEBC7F7CC6360
+:1006D000A34FEC8F8B7AF0E939ACF7DBF98B37E27B
+:1006E00079CCB3CD8A1FE579E388B04FC5B8782CB3
+:1006F000E243BA7BE8D05D9B26C17A3FD495309A1D
+:100700008099EB6FB999DE03D82EF991EF9775EACE
+:10071000CE8150BEF469A91DF965C5D6CF3AA64170
+:10072000BEAA8DDF83BC35AB88C6ADEA8CDE8C7487
+:10073000B3B44DC9C5F3B24BDDCC87F43E7B9D9479
+:10074000AB43BD2EB5D587EF477D1C3FE4C3F78291
+:10075000CEB637F8B412940B8B89CF3E6475BEC900
+:1007600088EF667E5EA58A71B9C59A951DFC7749AA
+:10077000F87BFFF47B50C037E98D526404E0FDF64E
+:100780002C2E4FCF04A2419403E99B7F7E3FDE8F46
+:10079000EA629CAEF5A8388F887FE3F17781189DD7
+:1007A00077CB6D56A8FD8319BC7D7AB4EF77579649
+:1007B00076F2FEEE7A5A8A6BA1DEE51F54B75F8FA0
+:1007C000EFFC7FBB5D628F68BDCBD37585FCEC6FA2
+:1007D000EFE2FED88A56E847EA5DEFF7526C13CD98
+:1007E000BB0EECEE24E59D306F2C4F7F58DACE9295
+:1007F000CC03B8F368E1787E948A2559476EAB94B0
+:10080000E072C1F65DF8F70007CBBDEEC1B3166F1D
+:1008100046B37570AFDF41E0EF0FF523CCB05EEF6C
+:10082000B0ADDCE5B0DCD7EC27FCFF7EB6FB9A6709
+:100830003FE1EFFDE86532ADB75F1B8F2B9D85145F
+:10084000EF97FD26DFB19BEC90F309EFAD40AFD7FA
+:10085000DFC6F7D9AE0FC5D250AF18EFB4F9867224
+:10086000FD54EE1E73D40FDF6716F27B8AC67E71CD
+:100870006580E7377EA97F8BC7C393DFA3A6F5C842
+:10088000344FA28788B847FD2D41676FD673FFF9B3
+:10089000DC54298EEF60DBEFE3428B71F87B015D66
+:1008A000EBFB67E3B9F373923887F56B4ED7F6FB32
+:1008B000BA77CD92AEC27762A18603FDA265F12C14
+:1008C0007A1F7346B1B55E749744FB3D3768B6EF47
+:1008D000CDEBE89ECFCAF86909E7BD3262BB0F6C69
+:1008E000A78FCBE5C5BB05D3045E8F89F3F0D3C4D6
+:1008F00079F74AF6704536ACA76A3E0BC7199E5782
+:10090000D755CCAF58C8EFF5AE684CB7DEEBF53A2B
+:10091000FABCD7DB6FA1FD9D2B9D997F07CE787721
+:100920006970C53CDA5F09DAE8305FBC533058BC07
+:1009300053907F9FF59EF05BCE8ECAA108FF208F5B
+:1009400037BA03D6DFF3C17D1873FC2AC7C7F72572
+:1009500058BE46FAFBAE6339CC7C1EED2E2FBF2F5E
+:10096000C87639CE9BEF595F38D6F7EFA2A469B6A7
+:100970007BE72C40F16A030EBDE43BC0B2DEA46706
+:100980004C723D2EE47A06D2BF21D797676834EFC8
+:100990000F22914DF8DE2CD322741ED7378DF3C56C
+:1009A0009DA81F417FDEA2B20A359B7E7F89D29B24
+:1009B000453B267E8FE4E5E27CDA1FBAB36DBB8649
+:1009C00071A85EF302DDB6767CD279E9880F9C9738
+:1009D000649A576316E81B05E727ECD94AAE777A85
+:1009E000F59B6FD567A67E5B0D3D2695255DAFCF48
+:1009F00081749B1FA173C857DA2F088D87FBEC37D2
+:100A00001AF13987F6EE17565167C0414E3EDF6E38
+:100A1000FCD8E18078E986C37C8083A95F9F809FB2
+:100A20009D1FCFCE1FBA699C66C52FBF1F9E62BD9A
+:100A300097C1CF049F46FA3A159E8CFAD9467F2972
+:100A4000E6D3288509EEA9F09AAAFDBD3EBE0E7B2D
+:100A50003F57BA0EA7289FDFC73A10CE46FD7E57F4
+:100A60000AD718F08DD21BAE30743BB6BF4BD44BB7
+:100A7000654FF5F83F5564879C15FEB7E1FF9C6D07
+:100A8000E3FE8FE1F7A0BFA3E798FC9F40B50BE51D
+:100A9000C786B202EEFFB4291427F14F9815C43867
+:100AA0008AE1E79CCEE6719D3355FCDD5ABBDF93AE
+:100AB00093C3CB4BFDDCEF59E08DDD3C15E6D595BE
+:100AC0005BEF9434D6CBFF71E14E0CBE3B207E1F12
+:100AD000E6C365399B6EC57A7FA5DF437F80B75536
+:100AE00098C220AB26BA75710FEC3AFCBE448CBBA1
+:100AF000AA93EBAD3F55DEE74420AFF29BDE6F8358
+:100B0000FF96829D82EF382E85FEBB8AC57821B480
+:100B1000230D3F8A9FDB40BF49077B4169BAA51976
+:100B2000CC6BF09B161DF3E1FECC63B78CE3EF2E8C
+:100B300080FD0AF5DFCAE6F7D60F8DBFEA381A47FF
+:100B40005DFFEC60E8DF4C9D50F230F955C7BBF318
+:100B5000E4577DF2AE8BF2AC38B60DCFEB35BD9BD2
+:100B6000467AE093434C477CFEC71617BD3FD8E456
+:100B7000486CC3DF1938F76E06F961E8BFC55C78C9
+:100B80009E1A0401DD47D565F4B3408CF5E3EFA769
+:100B90006BFD79DA4EE9A350AF8B7E402C21F3EF49
+:100BA0001DFD78FD587F9E9EA7F46C1AB75B0CB8AC
+:100BB00057E471BF7B7C9E11276241E4BF2634E27B
+:100BC000D13EB9498E9B7FA7C348DF16F59BB20C77
+:100BD0003B287C1BC2A36A563F19D77722BAD83369
+:100BE0000ECFE5B415C8E8FFCCCDE476CFF18AA1ED
+:100BF000839DD0EFCF1B5DF4DED8071552DC017664
+:100C0000CBE990564FF6DB7A16C6F8C23007D831DA
+:100C100065B8AF2E8575E8FDEC2946F53E68FBE129
+:100C200074B46F3E5425F2ABFE3397FBA113362B01
+:100C3000A71D80E79B274EFDE799D0AEEC6995C6CE
+:100C40007D2AEF86716F61BF4D0AF97F2FE5B9C824
+:100C5000A87DEAD109711C7F178B78F0FCBD1E4F6F
+:100C60007EBEFDE35C3EEF82ED8BC9CF382BE29672
+:100C70000F1D5AFFBA06ED3E6C2D5711541FA2806E
+:100C8000817EEF8C4FDD55074DBC599C7FDE72C6CF
+:100C9000D6A23DAF6F51E8F75C908EF0DEC259717D
+:100CA000DFF6C3B606F28BCEB60C0F235F2D8BD7C3
+:100CB00005D18FD921E0D580FC4B71A37033D2EBE5
+:100CC000B9F563733698E6B923D369ECCF6BDDFBD6
+:100CD000FC48AFC27E1FCC8CBF6EB9C57FD7AC8D30
+:100CE000FB11C13685DE391D1C7725C4BB9496F7F0
+:100CF00044A11EEDDB0D1676FD20163F5486DFEF76
+:100D0000B3DA5B831A79BD812BED7618B7EFFD82DC
+:100D10005FBB443CFC9A73D67A7E61D7FB6D76FD4F
+:100D20004D9952D2F59D6D1C4BBFEB32E851809A24
+:100D3000552EF3F5352B747E24087E4EB277AF071F
+:100D40006F06FF6534D5233BCCBE9EB3E738FDAFBD
+:100D5000D8C3FD34FBBA967F92588B4A66E5D3B66A
+:100D6000DF8FB4CD7F57338F634FF6F27BA0935B59
+:100D7000E5EDE8AF5DC3DA1B70FFD991974BEFF655
+:100D80003785381F65CFA8C834C757F766F278E9AA
+:100D9000D06699454CE314B57A58C464070E6FCBFE
+:100DA000B6E447C4075AEA8FDC5360291FD57E9505
+:100DB000A5FCEA83A596FC98C4644BFDB1C7CA2D77
+:100DC000F9711D332DF527BC33D7929FD4B9C0528A
+:100DD000FF9A738B2CE55F3BBFDC52FE96B80F7415
+:100DE000DDC57B2DDFA7B2EF5BDAED127CE1CA97A0
+:100DF00059DC54CF97CEED53B4C375537DB497638C
+:100E0000A67A71414F59D3E7F569673709FDFA2092
+:100E1000BED33F1CF741F93BFD1BF19D7E17FEBE83
+:100E2000B3466903BED30FDF1F12EFF4674D2F7B6C
+:100E30000CF5FA9F8BF91E3CE03288FBF9E06D93CC
+:100E40007B9B732D233991A9F3DFD98CF9233A9E2B
+:100E50003F70E6CA96DF47F496587F9FD51DC8B607
+:100E6000D8FDBEB28196724F6181F5F7BABC575971
+:100E7000F2FE29A57DFA0D0333B9FDD5C562AF5346
+:100E80005C22BF957E7F24959F5283BEE6B8D4EF47
+:100E9000ED9FC3F7F6357C6FBF3A38D704E74F05AF
+:100EA000FC3FCAE2768DF18EF3996786EFA8273E64
+:100EB000E6EFEDE3B3E6F46E551EC7F707C5D54E72
+:100EC00002A85645F6EE992C27FDBED31949E6BF78
+:100ED000DFF48C6B3BEA8D33C63BFB1B15F1CE3E3A
+:100EE000F7C7C98E0056FAC0CBDFDBFF688B42EF35
+:100EF000EDFF9B88639FF5479D61D33CC15E30FC4D
+:100F0000717A6F7F95C8DBDFD7A77EC1DE59B559EF
+:100F10002239BAAAA7DDFF88F7F5C7E4C957F6BE9C
+:100F20007E1B9783FF8DEFEB13DE3786F9FBFA917B
+:100F3000CD313AEF7653BE427AD0784FDF88E3184E
+:100F4000784915B7F9AAF198FF028688DAD60080A9
+:100F5000000000001F8B080000000000000BED7D6A
+:100F600009585CC7956EDD5E599B0B0D4D83A0B98A
+:100F70002C3648465223A135B2DD4858468E16B469
+:100F8000C45112DB690496D096879738CA9BCCE38C
+:100F90004A208C244060E1043948D32828C11392A8
+:100FA000C17626513C997960693476C6F648B69583
+:100FB00097F8397ED06A3689F7458EE3442F9F3201
+:100FC0007AE754D585BEB7BBE94696679C99513EF2
+:100FD0007F37D555B76E2D67F9EB9C530717210363
+:100FE00037B30919B10A84A410B28E18E4C128429B
+:100FF000F4E426C1DFD7DA8DB48CFF6EC27F775F51
+:1010000083FA82A9F2BDD7D565C2DFA7657D60D915
+:1010100041A4A3A5D9E1DB11D97529CF46C82AFC83
+:101020004122E4D55AA834C3FBEFAD19271642CAB2
+:10103000485B69523121DBB612A7079A94496D06C5
+:1010400002E5D44E8158A1FF5583156BC93C427609
+:1010500034C612E23FBE38A30FBF13455CE4660EF0
+:10106000FDAE6F72FCF05DDB43069FFF7C6120F0FC
+:10107000232176F613C92C7DB23457C079F8BD0709
+:10108000DFB397367EA087716596E986CCF05DFB6D
+:10109000937EF5F05F548651D56FD29AD2047721B2
+:1010A00021974C504827A43BE1674FCB503E5C9CB6
+:1010B000D32624C37E34EA8900FD7A1B3727B8E3A0
+:1010C000E01DFC776FE0F3DD5A42FAF3A7CA23D59F
+:1010D000FA320FB48F29AAB7E4F9BDB75A3412B265
+:1010E0008890B16A639907BE73C49964C92B0CAC2C
+:1010F0001FDAC3DED77EA74C34D0FA3762CBCB449D
+:10110000A0932FEDFD6A148EAB4D205BFBE0792C94
+:10111000A33C2109FA23D7A13DACD71E5823924BFB
+:10112000C85951A0EF29FD9CD48CD7D127B83C8554
+:1011300081DF3BC6DF6B4B73BE9607EB215FD23B73
+:101140004F139C57F217AAA03CE48A71E227C80DFE
+:1011500068BF989206FD5EB34EB6ACCA9EFA8E0783
+:10116000E8069FA76A45D20F8DBA6BEDB4FCDD5A35
+:10117000893E7B6A0BE8F3AF6B9DB4BEB776292D31
+:101180001FCBE87B2506E8E9A32DA44806FA9BD3EC
+:1011900003FDC377934B6D1E3D7C78288394E1BC9F
+:1011A00091A24AE0FB4302A35333D1917ED8F77F4B
+:1011B000C579C06FF5A289F2158C93106857C5697F
+:1011C000E04BA406998C54703A35235DC3F3E12DAE
+:1011D000834623F473ACF5A51417AE67BDD18B74A9
+:1011E000E3E2F4FAF03E28FBD15532D9FF662D8CAC
+:1011F000CBEDD14B1E01FB357827E90CF94C2A17B2
+:1012000070DC6DCD02790ECA6383FF24EA703D9DC8
+:1012100006723A1BC7AB6E9F2C6F1CB0C3F7895D7B
+:101220004CDB184FC817E3DCEB4BA0E84D3E6012D7
+:10123000F077974112611E0251E64B068D308F3ACE
+:1012400057399DCF70B5B5E5416C474AC591026CE1
+:10125000E7166EDE159A7E81FFC8881FFFFD0878AD
+:1012600088AF17DDD7DD7C5FB37A83D3C91651C74A
+:10127000DAEFCBD2E1FA7E95CF05570CF9D6CCC781
+:1012800049526BECA21F5DFF15D28739F03D3369DF
+:10129000A27C0CEB323258C0E689FB9865B826E098
+:1012A000FBD237607FFDE583FEA169F973DF7BFB2D
+:1012B000EBCFF9ED579F189F3C02EB410A4921956E
+:1012C00073FC7D856FB6D33E03FBF943AD5C7FCEE7
+:1012D000C8F84C9CE67B01FCD5C1D64D594FAFA652
+:1012E0007F65FDB21A6192CB09392ECE69940DC883
+:1012F000675B2C127C6718E9BC90AE675C098CAF09
+:101300005BE0CBCBE979349A15BD7613E5D72C4E4B
+:10131000D7C73AF5CE7EA0B32CE05B1DAC7F1ED2C2
+:1013200039EE6DAB81D2AF42CF29E57EF447A6F806
+:1013300020990C88AB80FF1EF5E8A97CCFD2D0A9FC
+:10134000B24F633780E3E03BDE5293E740107A4EC2
+:1013500021FDA20EFAA9007AEF47793AF8F9D5698A
+:1013600048FFE5C4795A0ADC1FA0FBD576E497CF85
+:1013700089CEC3503FA2D9AFB63442E7A5954723E3
+:10138000288F2412521E29FBD72694FF4B5E76F835
+:10139000FDBB5D726B24C3732086CDB7E8349BA67A
+:1013A0004A5EA56C7109C664942B450B911CEB45F4
+:1013B0001BDD47AD1C53F67B67147B4F2BBF9E1480
+:1013C00025F61EDFBF63DD20BF807EEA3A2A2DCBE3
+:1013D000613C75AD3A82EB7374E0904502B93266B8
+:1013E000E8373981AE5EEECBB6603BA04B4A67630F
+:1013F0008DB9961C3FFA4E4B647A00F421D55B23DD
+:101400008D75965CBFFAF4443DA5DF3122B52C639F
+:10141000B4291916A37E867F4CBF2BB842B8899B8E
+:10142000524FCE21AEC8E4649CD1A897CD40478EE0
+:1014300046BD2BDA42F5BAEC4F3F999C6EA11DD503
+:10144000EBB38867A0187ECF78528D1366D5433DE5
+:10145000B44BDFA3C50F240ED74DE472688CCFF3D5
+:101460003363EA76225F3791F8FD0EDFF96C22C311
+:1014700065DA7979C7A4F54B61DF2AF718A878D324
+:10148000CE33C3C3E7E509312FE0F1A824DA8ECECD
+:101490004B3B1FE05053797CE07CAA265A1B8017F7
+:1014A000C8CE26A30ADF68C7DDDD68A038627907E9
+:1014B000EC0FECFFF2565D970453A9237D7AD447D5
+:1014C000F204217F0BE5EED6A49665503F569FAB04
+:1014D00043FA53F6756302DBF76EEC10F0D17872C5
+:1014E0001DC5477F11CFE8ACFE6E03D5C7833D66AF
+:1014F0000F0AE9C156F69D0A8FDE83B8E960BCC8C1
+:10150000D60D96C704EB168BFD80A84B324A89880E
+:10151000AF7E0BE392E1BD910E86AF14BEDD85ED8B
+:1015200082C8DF6F727DA194537B82EBA36D496CFF
+:10153000DC1FBDFAA1C0E8EF5ECA378F727AB3B57F
+:101540005F2CC371EF29D6115C8F54223588D04FA0
+:10155000EA56C66F93EBCFF9AD9AAF692A293F4A95
+:10156000E95B26540E3B787F239E271211273814FF
+:10157000F9BA8FC9D728F81FCAD76D7D46957C4D1B
+:101580002506AF3F6ECDE274A795AF17709DFDF4B1
+:10159000B00D2B72F1A9960BB70FAFB6ABF0686721
+:1015A00022C3A3E38857E310AF2E50E159A5FEF202
+:1015B0001E261702E468E2245E3D9918015EAD160E
+:1015C000D8BEA72585C1AB1ED8F720F31B4F9C1EA4
+:1015D000AF8E87D10F9F345E1D9FD4E3D3E3D577C1
+:1015E00013D578F5D110F23E00AFB633791F295EDE
+:1015F000DD25035ECD9E06AFC2463D877C8D78B566
+:10160000781ABCDAB35148C302C7ABF3E2E4F5D9A8
+:10161000B8CE1A9C5A21D650FE278F38A30CB0EEB4
+:1016200046E26AB90B2AE7FD748BC54DD7E5D6F0C3
+:101630006A0A7C13F73D52BCFAD7897F5E78D5944D
+:10164000F4E9C2ABCAFA2978F537899766845787D7
+:10165000385E7D2C498357EB6F135EED06BC2A85FF
+:10166000C6ABE388578BC3E3D54AC4AB422478D5D5
+:1016700079DE1FAFAE48FACF8557DF4D9C1EAFEE27
+:101680000871DEFE79A244E96812AF76F2F336A75C
+:10169000EB4A4E77B62626EFE93FF8AE5914BB0E5B
+:1016A00043FFD787463D75503624D98AF4D0D56E8E
+:1016B000A44B9403C58201F99893D9148ED5B977B8
+:1016C000A31E32883261F2C645105FED4E246C1CB9
+:1016D00051B1F53E2B21BFD85A49E5D1D346A6A733
+:1016E0007E21BA2D497E72E4EB5C3F3D1D0FF588EB
+:1016F00087ED6E4B113C2DB1F253E5749C4E1D7E6F
+:10170000BF2A9AAD97F2DEB3490C47260070B85055
+:1017100048C598059029E0A65C0BE2B9B78C520B3E
+:10172000E2C9B1D7F4CE53F09E370EF4A31FDF7693
+:101730006BF4E22B7CDFB11DE2979506C9108CCFCC
+:101740005745E955B846C107F83EF1E3FB951DB989
+:10175000A5389E55C4598FFD68DF3B688005433D21
+:10176000B025D6735A08FCCEC1B895CF25A5507BBD
+:101770005A755F10B9FB333E7EAD5E30225D00DDF1
+:10178000D7551377542EFEF89088FC03F53AD4030E
+:101790006FAD94BF82EBEA15195E50FAFB395FCF4B
+:1017A00080F51099BC8B783DA2A6978F93FDF276B9
+:1017B000DA757A3649528D43DB3FB10F521CFF95E3
+:1017C00038033D9F9033C66B93F2C6CFFE09A73313
+:1017D000AACFDE5EBBCA80FB53AAB16F6AEDA4DA62
+:1017E000F2C92446C70A3D849D0F6FB7CAE08C6CCE
+:1017F0009D0C11AE93E1D6D62952FE1B8F90FF1E91
+:101800008D56F3BFD1CADE9BE23F91F2DD507B647F
+:10181000FCF75C72087AFBF4F05F8C75D114FF1151
+:101820007BAB09F1983EBEDD561187F4A153C90F79
+:10183000E549BA811E95EF003DF6231D2D62785FC4
+:10184000827E2E737D7E9F3EEEB1B3F0FDDFBA56F1
+:10185000585157952CD9E3B80CFD5EB2323D2EEAB3
+:10186000DD2763A19EFC6F33C1F18D0CB8F3FDD76A
+:10187000AF80AF3FCCC0A65B0AEDCDA486D96FFB8D
+:10188000059D1DF61F0E00717E7ABDC0CA713069BC
+:10189000B5E9A8F1FF8280EF69DB2938A398CB93E3
+:1018A00062AE5FC805830A07CFE7FAC74604AA8F6E
+:1018B00077BFC37042EA56359E98FF2AB323287833
+:1018C00061BE1647707DA5C50DA9F87FE8B932CE77
+:1018D00083B8418B139AA4BEF3E950DFB495385115
+:1018E000CFEEE97B4C403A586905BC8087638E1780
+:1018F000609D9DFDB8CE303E5C6731B73F0AED6B11
+:10190000E2F7F4A29C8DF8E57B9672D88F2B836664
+:101910006AFF5670C20F819E0C7710D20738C00044
+:10192000E517010760F9478003B0FC63C001F83C8C
+:101930000338009F2F030EC0FA9F010EC0F23FD460
+:10194000BA68B9BFB68C961FB6329C27C6963B9C28
+:10195000F09D81673FFFC8D7D1EE5F12E734C3F82F
+:10196000877EEACE9A4ECEC03E1BD9BEF51B71DFF4
+:101970009A57C6547BFCFC2BBEA65C1D9E572F3786
+:101980006D4ED806BF3F691582D2A7F6BCEAAB669A
+:10199000E7CD982283EABCFAB8D548C73B38795ED0
+:1019A0007D3C68FD6808FFCA79EBE479F5BCD5EFAA
+:1019B000BCAA8CF74A379CAFF11CD73DB3F3F59521
+:1019C000C9F3F539D5781AF9782626C7FB62D0FA1B
+:1019D000AB21C67B18C79B42C77B18F93EDCF97A5E
+:1019E0001B3F5F6F4C0E73BE6E0C7EBECEE6F22FB9
+:1019F000D4F9DAF7EFEC0FF245E80F3A6F559FAFE5
+:101A0000DD919EAFE5999DAF777686F1073DCFFCDE
+:101A100041A3E1FC41DD1BF7A74B6426FE207714B0
+:101A2000FA83AA43F98318AE0ACDB7C1FD4191EA02
+:101A3000E75F5B23D3CF3B34F838503F337CFC4126
+:101A400092487F1FEC647A3A9CFD701BA73BEDBC6B
+:101A500002EC8721E8FC454EE75AFB61355F5F9B4E
+:101A6000E762192A9B2AB41F52B9EF6C407D1DCA48
+:101A70007EA8D8EB43DA0FBB9F4844BA0A653FAC57
+:101A80006CBD35FBA10EFD0111D80F23DD573B5F67
+:101A90009770FBBA3BECB9A786EEE3FE24661F1EE7
+:101AA000EDCDA5FBAC8CB39A8F33CB13DC7EF34D1D
+:101AB0002B3FE7FD99D86FEE4956EB77ADFDA62297
+:101AC00004BDDEB2FDA69E9F97F97A0E6BFA57D63B
+:101AD0002FAB5DA076FDFCE47F3EC4EC3755D47E91
+:101AE0003312C67E33C1F7772099C9D149FB4D9F88
+:101AF0009EE2968F6BBF71B74EEF6FF4717FE3304C
+:101B0000DA6F84F0F69BE141B3C95E1CB9FDE6C90A
+:101B1000E4C8EC37E1E21FFEBDEC374368BF298E15
+:101B2000DC7E73DE3ABDFD667B08FDF863ABA4B6D0
+:101B3000DF7430FD18EABCFE56A8F3D3BFF179DD9F
+:101B400088E35E14BA7F852F153BB28DDB91E9BF28
+:101B500069EC4F1F5AC3DA9F3EB406B13F7D08B20D
+:101B60007726FAF5B508E5707558FD2A5139ACE8C5
+:101B700057AF87C9E14FABFD20DCBE0D3CFB13C75F
+:101B800020B4CB37F59DB401FD57BF1B4D4EC1941A
+:101B90008593AFD2DF273E80F38ADFF7F529D9CAD4
+:101BA000F9D2C2CF97163CA74869200C9710623231
+:101BB0005EA8C1FD1E2F8EA33863FCC6D7B661B9DF
+:101BC000AA338AA0DDB8EAFAE71FC132693753DCCD
+:101BD000D6DDBAED02E282B16EBDA087B2294152D4
+:101BE000D1FB7877A588FB5A347FDD1B77E161F55F
+:101BF0007FEAC81DD0444860F31A2A7FD881FE913D
+:101C0000CFCECF5C5809ED3E4C66FAD16367E30155
+:101C100004F416BE07F89C1C86D20F1B1F33E1FE8E
+:101C2000CD3FB1DF84EBD4E719A04FE70B15F4F7F4
+:101C3000A2E35DB4FC528F40E271DC1D7A0FC9A6AD
+:101C40007CAD47BEAEE4F4B9B0AD8DB613BBDBCE10
+:101C5000A39C7CB45790F07CB7E4EC667A5EF59D6B
+:101C600010C80168E7131E5FB802E5CA0FCC12CE98
+:101C7000D79141C88A05F05EA740D05EBCAD437FD6
+:101C8000CA9C4DDB35A03C95BBF404E58F238F182F
+:101C9000B01DFE33005D7E85F3D555E1806539B614
+:101CA000FB475D1FCA653FFFB80EE5CF573A98DF87
+:101CB0009C9C31CA0C0F35EEBF09EB33FF8C3ADE2A
+:101CC000B1A85F5D5EF8AABABCE882BABCE497EA44
+:101CD000F2FB09DC1F44D87762A20401BF533235FE
+:101CE0001EAA57DE4F20749F0E66CB8FE0F97B65EE
+:101CF00054D13911C65FD02D52FE2F15379626428A
+:101D0000794E2F2B5FB6B07E0BED175F4113F33C7E
+:101D1000E98395685A7116249EC5E70267D12A6443
+:101D2000FDE2A51BCFE2D3676174B0D8F5D8AA64F1
+:101D3000F65947F95CD007D1EC7BA78A44C7263F08
+:101D4000FA6D486172602891C989256799FF7DF015
+:101D5000D9FC5307A8BDF05FA91CB3F273DF0B7663
+:101D6000D67EACA0C684EB3FDB2359D02434B8CE5A
+:101D7000B415F1C2A0A073D1B88067CD5D68BF81F2
+:101D800032D5B3B08FA74E33DD41FDF87BE90E416C
+:101D90003FF04E02D48F1ED69F42FE18E6E74EAFAC
+:101DA000E83239FDC6B9834CAEB71ED7712F2F0369
+:101DB00055F7DF14A6E8622FA78BBDAD02DDF7BD96
+:101DC000C46F9FE0BD028F4115077B578F7A1FE7D5
+:101DD000F6A9CBB79B4E7E6DE774229377307E25B4
+:101DE0008B108633A54101E57816D78B8E46663F6A
+:101DF000727C431BCFA1B5DFB2B81489F7B36C5026
+:101E0000DD5EE27A55D2C4751C9CED76A09C1F89DC
+:101E100066F23F1C1D1E4B617A29523A5C525AA150
+:101E2000A7F4579345F5888293BF7B8DEDB76C3748
+:101E300052FB63B3C17D7836D05BB3DD582CB3263B
+:101E4000A5D150BFB658101147D9E07CD6BF9090AD
+:101E5000D74F6C6F5A03E5D55FD095239DADCE76F5
+:101E600047235D45494E8CBC25CD7F62F4ED173F7D
+:101E7000A3BBB9648ADE6C9CDE6C9C1E5C3C5EFA83
+:101E8000434ECF9F74BCF46FCB7C82268E6946F1A3
+:101E9000D24A1CB4122FBD0BE3A5A17E0D910D58A3
+:101EA000DEFE10E04B78657BCFED8D9356E2B46F8C
+:101EB00057BCB4CFC2700230AE03E97D0361F14B71
+:101EC000F0ECC7E7FF32B9E217A1FDFCB0DE790AFA
+:101ED000EA363C5424E1F77370CB40FE6F58FBD9CF
+:101EE000325C87E1F21367F17C105370A11AE5CDE3
+:101EF000D2E21882FAB29BD4E4A09C5A412EE85157
+:101F00000E5C41FD0CDFBB875CA3E55F3E104BF12F
+:101F1000574547769799CA37B709E5239C9F5CF4E4
+:101F2000BC62709BB6CEA5E391091DD7E0AAAFE3D2
+:101F30003383B83E87DFEFD8F8007E7FC396BD7449
+:101F40003F362C9516D067D99172019EDBD70A795E
+:101F50002401CB2F88ECF70111C7FF5CDCB6863477
+:101F6000D8A7CB2BA2E8B96643D9455ABFBD0C040C
+:101F700024B4BF5C5545EBE5A5314ED4E77BD60ACA
+:101F80007792F9B0CF658003697F43B47DE55A212C
+:101F9000479A8FE50F68BFEB44F7EBD09CAC5DF33D
+:101FA0001D03D2F7A5077737A09F797C59CC02246F
+:101FB000A7785B0E9D7FCC4B5D3D704C23954D5DAE
+:101FC000D236E01FCB2A86F3B6F3FE361B48A901B2
+:101FD000E6B996B02721CC4F70BEC0DE7518D66921
+:101FE0007B077BCF8F5E4D3767E1E6114A2F06CE28
+:101FF0005F317AD87DD8E24E3B7195020E8AD17955
+:1020000068F9990ECB91FA34E07D1DD43B09B93FB4
+:102010000DEAED58CFCA5F5BB7B9E9DCB2A9F2337C
+:10202000278EF132A1E7CB79C77FB816E3C61296A7
+:102030009172DC2703E76318924CE53FBC43FCE256
+:10204000C39A791C6B2C8CAF3589FEEE8A87FD8B89
+:102050008581DA16D0DFE58405F4F7FE38FE34E238
+:10206000138E4B369C7F21EB3F86C81ED4E3A4C061
+:10207000DD8CE7C1FAE37A11D783B8440BD22F7114
+:10208000CB16A49FA3033B9B916E475D062742E6B8
+:1020900084E34FACA7CE846641BC03C65739E8A49D
+:1020A000B868778FD087431C3178CEA74379A2B523
+:1020B00044C2F35666EA1D540E550DD6D0F776F796
+:1020C000E893D14EBC3BCA1D8F71971B8E09C9D8AE
+:1020D0006EA2A9C842FDDBC4F326FA99269AF554EC
+:1020E0004E8E1281DA2DABB00ABFDB04FA96D237DE
+:1020F0008B378CC53502528805BD381BE8283D95C5
+:10210000E1F8B10C99EA8158CF4FBE86F47B99BFB4
+:102110000FE73E2A9FE93F781F8F0BC83FC94D7AD2
+:10212000D76CA0BB0D362637770F12C2F0ACE0C1DA
+:1021300038B8D872AD5CAC596D413C8B764A1867A3
+:1021400055EB4601F1EB985176208E1ECB66FA3E98
+:10215000502E8A1633E2EFCEC46C5CEF076D4CFF55
+:10216000EC682D7AA318BFF7247122DD57F754D0FD
+:10217000B8C3DD76A3D305E571818D47EE12E8F88B
+:10218000635D061A3F3912C5E879DC2374A1FF6349
+:102190004268A5EB27CF35507C09DC7E2E6F317D60
+:1021A00095FE4BF608FDC85FC9DCFE00F352C9B1CD
+:1021B000CC00BF2AD3C354CFC0C0766D51B7B7711E
+:1021C0003D6CD3E8E1D73BEAF469D0FE00F229AEDA
+:1021D00067AF90580A8358D6AEA7FC7B30D11D8FCD
+:1021E000E583877293EAA06CB132BE35A5BD43CFBB
+:1021F000153F2F2ED4A1DDDA64ACA1E70AD3890202
+:102200001DE2A8E74CEEF68D28479FD351390A838B
+:10221000FA2AD2E7EAE3561DE2FE83D96ECB25DC2B
+:1022200097346312D6FBD6080D22C899ADEEB6FBE3
+:102230006CC9680E4EA47ABF84E3159F515A49E9D0
+:10224000E21071225DC168E56AE0939CB2EC03384C
+:102250002FCBF2A56B5CF05ECE7A1DC1F16C409D78
+:1022600003FC9417BF49876B72A7B1261DE9E7707D
+:102270002A3B2FE5BC77FFAB02E2F21B1F16221FA1
+:102280006DCA91B7E3BC66ED3D97783FF67328AF12
+:1022900008E7DF6CB81025AAE92322BDAEE001ED06
+:1022A000F9302F95D1ED8EB5C21C01E4DEDB0718A5
+:1022B000DE1D29113C78CE2BEF1464FD3C2AFE165E
+:1022C00055203F9F484DC2F55AB7C2A8A2EBF2CEA7
+:1022D000A72FA0DE1B11A436DC1FF9353DB50B6915
+:1022E0007103FAAF703D7774262E403E25057EFDC2
+:1022F00004C1037B3A87049CCF1E97B69F30B84138
+:102300005BE6F8321C8EA8E6F7AE141CB193E388A6
+:102310009D9E5826DBC9ADE108053768F1427E5124
+:10232000EE5133BCAF8F3A7B8F6FE1D4BED471DCFA
+:10233000FFCD5AF91EF41B76D436D2E7FB9CEFEFA3
+:10234000D7BB7E6DA3B8C169477AF119CBCB4B706F
+:10235000DD0F0A74DD55717B12FB1EB59BE3337BE9
+:10236000AA4CE343B3F1FBE7E9F7537B2B4AF07C3C
+:102370009ABA150D1E84A479F6D3729A5BA2F49FC3
+:10238000BA15C6E3B7EF696E1897DF3C0F2606A7AC
+:10239000B39654C637CA394F5BBF9ED7E736EA8833
+:1023A000CBAFBF3B5A6388CBEF7BF91D49AAF26CD8
+:1023B0004FBAAAFD5D3D39AAFAB97D7354F5F3CF42
+:1023C0002C50958BFA97ABDA2F7C75A5AABCE8C286
+:1023D00003AAF64B7EB949555E36F84555FBCF8CBE
+:1023E0006D53D5DF7D6D97AAFEDEEB8FABCA25E47A
+:1023F0002F54ED43DD9F5B630B1EF75D7FF7EF2EE0
+:10240000E0C1F672871E353EB9DCB490DE4B10DBBE
+:102410000411C9DE6593E87BE342FF2384C60139DA
+:10242000A99EFEA4E3C557D985A0F1E23B383DDA69
+:102430003A99BF672A5E5C9E365E7C375FA390FE4A
+:102440009EDEE9E3C5AB6F315EFCBBB87E7E71B04A
+:10245000A1FC3DE1CE75DFED788BCE77F5A29554EA
+:102460001F28EBA49CE794F2ED3ECF6DE2FBB00B8E
+:10247000E57BC2947CF7A17C87FAF21E90EFB85EF0
+:102480005CBE5F793E847CEF01F93E0FED5020DFAA
+:102490008BC3CBF75D3D4CBE873B273A487F437AE1
+:1024A000F6ED90EFB778AFB649A0B61C07BFE7A32B
+:1024B000E883CA46B5BCFF36E723452F7F7BCF2B89
+:1024C000D1F97E7AD94BA496D9B8DF1D3A42E52FCF
+:1024D00071523B93B2AF1FDA047EEFC31583E77BE3
+:1024E000D9C3D64FCB37857CBF72BA2A699C90720C
+:1024F0003FE8E8C06C6AD7F3B5AE3444C37B3E3CDA
+:1025000060E039D753D2BD1F5EB992CAE21A2E9944
+:102510003C47685CED737AE9345B26D326E0F7111B
+:10252000C2FCF857BA1E73A0DFDBD75149EF237DF9
+:102530009FE35E6F07FB0E31482DCB50CF772DB454
+:102540001EF61B5F6FAA9EE163E26E59CA70B0FA75
+:102550003E12C78BCAFDA3807B3B1D7A19CFC30EE9
+:10256000B43FC233B3D3DC4F82DCDF8176D4CEA359
+:10257000DC4F0A792FA99DDDEFB9DDF792FE0F5FE1
+:102580008F9131B6BE7B7A01C7FB9D1B94F98EB447
+:10259000BF74DE02EB34AB4D20A21464BE9A7B4ABA
+:1025A000578C7D26A49B80F9F27B4A99BD0C5F6B0A
+:1025B000E719704FA94F6D3FD08EDFDB58C9E3FE9E
+:1025C000257A0EEB6EDC42F7536ED753BBB8F6DEBE
+:1025D000D267485F1DE2491A8FBE1CF7F1B523E8A8
+:1025E0006F3A887306FDF307DBF78EC82BE8798E08
+:1025F000EA155FAB8E20FD793B56AD477CEDF508C3
+:10260000229ECB5EF6ECA7E7302D3D2BEBEFF3D40B
+:10261000A9EEBFFD3F8E3B473CFCFE9B6795EAFE63
+:10262000DB1F39BDF9887C6BF7DFC2DD1353EEBFCA
+:1026300079C2DC7F8B90CE7C33A4B3213E7FEDBC8E
+:10264000C6C6E4F5F4FC86F7DF82D1552B9F576BA5
+:1026500098FB6FADA1EEBFD504BDFFB663A29FDEB0
+:102660007FDBD33B3D7D0D61401EECCB40F3D3DCE3
+:102670002F246BFC42658E41DCEF0FD4716CDFB010
+:1026800047E6179AE07EA109EE17DAC1FD423BAE9C
+:102690002F617EA1268D5FA88FF9853A5225951F5F
+:1026A0006BA28FF9857EC37153059192D05FAC8D7B
+:1026B0000FB0D547E6872C4A0DEB872C4A0DE287F1
+:1026C0002CC2F54A098FB794B8FCB078AB2938DE34
+:1026D000FA1FDC6E1BEE7EDEAE49BCD53A6D7C8DFA
+:1026E00072BF2024DEEA9C1E6FEDEC51C76F458A55
+:1026F000B7B6F17D0C87B716DB357E3C253F035F0F
+:10270000475B5F64F71BBEACF81F42EFEB97ED8BA6
+:1027100002F7F5CB7612D49E96CFF122E273B49BEA
+:102720002976B500FB1CBC7F60F1949D50A907B0D1
+:10273000D786F5F339DEF805B433E279BC5EEFD91C
+:102740004FDF73D1F35EA4FDC1FF6DC57A271F175C
+:10275000F667489EEAAF3E4DB6187383F427A10D85
+:1027600026687F1EACFF05D41BFCC725C1B8E6E276
+:1027700077B83D7BABCCEC8101FED517987FF50790
+:1027800003F4D9D7D7459FCEE7DB987FF534F3BF65
+:10279000BED4F918F58BBABBCD120D1ED2F857C7AF
+:1027A000850556E60F1528DE123DFBA93DB1A25561
+:1027B00090501D2C396B35A1FD78EC10F3B38A8D48
+:1027C0001B4D2897B6B5BF40FDF3577BF5241EEA95
+:1027D0005F68D47BD016A8F85DC7051DA1711E8760
+:1027E000987F2E949F35C0AFDAC870CDC7F5AB8EF9
+:1027F000093A7AEE0FE7377B2A2532FFEA53298C14
+:102800004E238D83B8C2F167B83888CAB0F7005C30
+:10281000AA38085F536471864A7C485839D81B3CF3
+:10282000CE707D5A64E7CEEAC9384371DA736755D2
+:102830003839D83ABD1CACF0DC9A1CEC4991228A9C
+:10284000330CE05B58EE86E07285D6FF8D9DF72B4A
+:10285000BAE3057FFB7DB948F1A2D21EBAD9AFF425
+:10286000A70B2E57A81CC84D63F415E93874589F60
+:102870001DE4FBDC7F30293FCA64D5786CCA7BFE3F
+:10288000F4AD9F9ACFC856ABC544F75B2D1F939408
+:10289000F168DE5B92C6DEAB17DC2D8B84C0F94796
+:1028A0003A8F623EFFC97870659F1A23C315A060F6
+:1028B000C2E10A9216045710FC6E4AF879966ADA59
+:1028C0005942ACA3A21F701D0D685712E4163DFCBF
+:1028D0006EA9230528E777E8639C682F485AE373BD
+:1028E000A29CFD5D7D7E0EDA31ACEBB6D07B069707
+:1028F000D219FE181298DCB0CF27FD68BF18AACFF6
+:10290000ED423E3F5CCBE290CCD7EF2232C8A1260D
+:1029100028CBC0CFE68C1A33BF0F40E324BDF52C83
+:102920002E5F5CD2E9C07BF17F30CA66B47B3CEE9F
+:10293000E0F7E62B4C5B715D957B0FCA3A9DCA6050
+:10294000F52B3318FFEF8D13793CF729135D16979C
+:1029500041C2F515B81CC0FC3E02DE8F23E574BFF2
+:102960007C3F3AB6FE4BB81F53F7A5C9CDD840F906
+:10297000A23CB5F1DCF49F6297838FC42E8D627602
+:10298000F31BD0DA4F6FC50E323BF9EFCADE3121AF
+:1029900011C58A06E2F5C3DB7B9B847E1EA741BC82
+:1029A00005FC7B78AE03798AE702394E47E325E3DD
+:1029B0003B04222F04A8737A73E35209EF296D3B7D
+:1029C0009506F3361EDCBC88DE0737781AD09F7672
+:1029D0002989C55F26C54B6D28F79EB86824E8EFA6
+:1029E00019589C4E717AC9928C9366C4DDBF32131C
+:1029F000F4FF962C799DDE37F2FE2A9A961B619F92
+:102A0000DCB0580DF0F4601CD9807B3ECACB67A1C6
+:102A1000ECBD03FE7BCDBD84F923641DE279E55E48
+:102A2000D1B3A61A1AAF38BA85C886F974D153192A
+:102A3000EEEFE34F6264ED2FD8D8D39D8ACF371DD8
+:102A4000CA39E11A2D8FDED81C85FB7FF0869EDA0D
+:102A50002FCE25EB283F4D2CBDF394996E6639D5CA
+:102A600047DB785CDE7589D1E1667D7FCB52F4FB74
+:102A7000FD0D8B97FAA877E1BF2CA79F657E9F235A
+:102A8000C77375340F4EF9BA37ACD0EED837241D62
+:102A900076575D26344809182FCAE8B51BE347CDA1
+:102AA000182F2AF278513B8F1765F1A3BD183F6AA2
+:102AB000C67B424E5AEEC3F85133DE1372D1F28F09
+:102AC0006ACB68F9C7B5E5B47CA6762B7DBE5CEB16
+:102AD000A6CF9FD556D3FA7FA8ADA1E5FEDA7DB487
+:102AE0007C436274BCEA506933DA8B76C1F91D719C
+:102AF0004DFEF30241FDB973A989E607D9693F602C
+:102B0000C27D268551D44FBEFE82BB311BCBDDC2B8
+:102B1000422C8FFE9A9C41BFCECE2D7A1A875455F7
+:102B200068EAC2FB4183F70967D01E58D5FEC4FB93
+:102B300078FF88141AE8FBC4491CFBA0DC52B2C51C
+:102B40008978ED9451D25B8B00579F7C784314AC0D
+:102B500071AC89D42539A1EC207219D0EDC2E20FF5
+:102B600076BD08E5D733171F8D827E634B8A5FB130
+:102B7000D2F2480B96F3E257C6535F34196939070E
+:102B8000CF23C2A0211EEB4F90E6E4D900137112AF
+:102B9000CBB17C20A12E0FC74FA8DD212E6BA40541
+:102BA000E3A7E788175F4914F17BACFF42FB072BD3
+:102BB000D9F759799E947836C9AFDE5950B4CA0A0C
+:102BC000E507C9E2A365D0B5CB5DF2461EB4FF4C64
+:102BD000A7AEB991047EEF9D9C6B0348FFA32D84A3
+:102BE000DE4FC470315C278B9CEFA91342F3FFD0FA
+:102BF0003242EDA64AB9C558F308D2FB50347B2ABD
+:102C0000BFE76531F92E6530BCD612CDFA1FFD9CA9
+:102C10008EDA5FB5FDEAB259FB9644D60FD0F717AE
+:102C2000687CC6169B0EF5C73BE5953148BF751D00
+:102C3000393AD41F07D2199D5C2CCDCD34C1BEFFCB
+:102C4000A4DE2CE179F872A9E031C2FE0E654B07D3
+:102C5000FCFD94771A65239ED7EF1404A70CBD8F53
+:102C6000BE473C46A08FCB9DC7EEC3DFC70C821387
+:102C7000C5D9B559D9B4DF251EFD9011E6B97E69D5
+:102C8000C91B0F407D71AF817EF7FB29F72F427F73
+:102C9000A9DCAC77821820FF9862A6F3FAFE697867
+:102CA00023DBCFCE591FDCCE199FC1F834E7E07784
+:102CB000A89DF34A9C8ECAFDA303696F4AC581761D
+:102CC000CE8A1E66E7CC7228764EB101ED6F728314
+:102CD0005EA2F65683C7B409F4F790626FAAFF4E5E
+:102CE00003FAAD86DAF3693CF9AE9E2E07EA19EFD6
+:102CF0002CF6DDBA7AC5DEE92C43BFF795430BAD60
+:102D000087FDF4AE779689DFAB9CA19DB39EDB6710
+:102D1000EA997D26B3C7DC4FE3D7881A9767D47347
+:102D2000BB5F383B675364F6272FF1D4D1F5A82257
+:102D3000543F446A87FA4B4E3FDA790EEDD942EDA3
+:102D40002DB34E08ECFCA59D67B8FC529DDC9ED9C6
+:102D500018DC0E3554C5F6B5AA9BD957B5F3DB3947
+:102D6000E16C401056D93ABD3D6A321F539C2EA8E3
+:102D70005DD398926C42DCD492ADE64BE5F952D625
+:102D80007FF91DB17CC9C4FD3A6F05E7D7AB9C6FD5
+:102D9000CC761DF1F8F56389ADA1E7C2783816CA83
+:102DA0007EFD454B3AE2F66BF736C78789F76D999A
+:102DB000F69ECF41AE778FF07B1B4F73BDDB8C7AD5
+:102DC00017E8EE10EA5D78D6F17B1B47B9DE857E09
+:102DD0008F633CD24705D4FC432AE28803ED1CA054
+:102DE000F5903D48CA3D84CAA70459A0F1DA6ED1D6
+:102DF00025E379D494ACBE87145718A32A476524D9
+:102E0000A9CE8596E274557D4C5E8EAADE103747BA
+:102E10005516572C509F2B498648EF2D11861B3F86
+:102E20005A5B7AB414FBAD131C887306B9DF5FC11B
+:102E3000CF8372A4F83989E2E72199C93571C95A5B
+:102E400007DE7BD5E2675F058B4BD6E2E71D994C29
+:102E5000AE9A33993CF822E2676906F8B9FA9836D7
+:102E60003FE62DE1677ACE858FD834F8598963B073
+:102E700069F0B34D8B9F7B013FCFBB25FC1C336BAF
+:102E80001AFC3CB078CE45A49F2B6F1809E2CE9275
+:102E90002585144F8F5D54CABD27CD14379B6979A2
+:102EA000ECA70088A1FCD41C9307F7CF3BC0CABF96
+:102EB0006F30D3F261A374320ECAA3BF8AA77673B0
+:102EC0002DCE86DD36309CACDCD357E367057F43DF
+:102ED0003B1DB7A7AB70B4829FB578E4A95C26EF21
+:102EE000E666E814B94FFD948711971487C625F755
+:102EF000E6B0F70E232EA1E7D0E971C9312E2FB429
+:102F0000B8C48BB8647E785CE2E3B8C4DB7A8CC664
+:102F10005F8D232E817E3F52704937E09279B71F33
+:102F200097FC71D60C714937C3256F6532FE0AC410
+:102F300025AD2A5C327CBAEB118C3BF5D55BA93F01
+:102F4000CC17211EF1FDD9E19199F9C35AF83A68DD
+:102F5000E737D4B499E19036E1D670486B181C82FB
+:102F60007E5EE87F8F27380EA99EF050BFD8AEBE98
+:102F700008F34286C12187B319FF609C4F851F5F0C
+:102F8000FE3789F1E37F741CA2E451098747466646
+:102F9000313DF45F78637ABCF1360673A484C71DB3
+:102FA0006BD299BFCC4BC437912EBF348BDF4FE42B
+:102FB000E570F9947E8AB1EDC89F7627BD97635579
+:102FC000DAAD35A8DA7D1F85DBA2C0FB784E1C2761
+:102FD000FC7EB9FC8403F95AB98FA76DB76A56F025
+:102FE0007603A7FF89DAABF24DFD2769FCE8A4BFA1
+:102FF000F99735C86F5716C5E950EF5EF980C5FDE2
+:10300000FEFE44940EED5C2663EB23587FB53B9F98
+:10301000C601F74DDA97D47EE8EED617DFAC857699
+:10302000439D02D5533BAE9BE9FD07537C9F251181
+:103030009E65B3D83A2BFEEAABBDCCBF3C70FA7E9E
+:10304000EE0777513FB8765C5E1C17EA3D1C57715E
+:10305000E0B886715C503EEDC8E6F25D3BAE4D34A3
+:10306000EFC5502F1BD7EEC971955B12D14FC4D756
+:103070005519D7703B1B9772DE09778FC99A1ED9F5
+:103080007D3A2BA733ED7D26459E85FBCE1DB3668D
+:10309000765FEA4E4E07DA7B7BCF9934F61A2789A2
+:1030A0005ABA00F89FAFC33B398CEF460F98298E70
+:1030B000B14883E4F1C2A97C33831D2CDF8CE27715
+:1030C0000A2517B4F9660627F3CD3CA9CAD7FA60DA
+:1030D00006CF7F33F9F7070EA8F2CD28F56321F26A
+:1030E000CD6CCD98CC37B3356351E4F95CED7709FD
+:1030F000AA7BB091E673BD365B98369FAB37C4FDB3
+:10310000FB36E142013E6FF7BD7A6F987BF58A1F6F
+:10311000CEC71D23C73282DFAB57EED12793A268FB
+:10312000C4F98FEE314A1E69EA5EBD36BF8C365F48
+:1031300042DC9F58FECA2B3CFF8136BF8C721F3F7A
+:103140008594AF46BF7265398B0BBF12268FAB36A5
+:103150000F4230BFC4747F7720885F6246795C5B22
+:10316000B8FFE78873253D1F2AF97C02F38E653886
+:103170002E039D55CD65F92744BD783216198FE78A
+:103180001D1BC2BC637E74FD528682D722CB3BF6E8
+:10319000D5B97ADEFED6F28A6D7F87E5AFB8DD79E4
+:1031A000C5DC21F38AB9E9BD3125AF985B6679C5E5
+:1031B000DEC850E7B1089957EC5B2CAFD8F08D25ED
+:1031C00034AFD8E54F38AF98F63C5F9ECFF6E76F47
+:1031D000E7B0A722FFBC3D2C9FF5959E99C93FEF14
+:1031E000647E30753EEBDF73F93695CF7A65D07A21
+:1031F0005F08F9777D4AFE5DF7977F11F0892A1FF6
+:1032000053209FCC2C1F93C227CA3A8DDDE23A8D02
+:103210004DAE933A2FD92C7E3E9CCA4B9614B43EA9
+:10322000D4DFA9C9CC9C5CA7CCCC08F444A5C0E4ED
+:10323000F6C373C2E88910F164CFCC16A6CD4B3625
+:103240001122CFEE27A52726C2E4CF55F4C455AEF0
+:1032500027B66686D513AF613CEB0ED41364E67ACD
+:10326000C2C7F31C87D61335E7514F3CCAF5842FEC
+:103270004C3E32622FA7F990153D11CCFE36AD9E23
+:1032800008B4BFCD484FFC3E5DD1139BA8DD633829
+:10329000647ECA99E9897D9933D313670A3F9E9E5C
+:1032A000D8F509E989CA907AC2D3E09F7FB2B28982
+:1032B000E989673223CC3F7904F404DA076F7CCBC9
+:1032C00082787DFCDF584FFCA090EDCF03856A3DEE
+:1032D000E16B67F26FB87D66F26F2A8FA41A27FF41
+:1032E0001D976F5338795BD0FA91107FF7E0EFA705
+:1032F000E4DFDFFBCBBF08F844AD2702F864667A51
+:1033000042E1130B8C517DEE98DE8F7C74E0F9F571
+:10331000188FE0E5F1F3753DB9F45E735DBD20E211
+:103320003ABF5C9F18347E5EB11B7AB9BD70521FE4
+:1033300038D87E5DE176C32BF5B9AAF8F94C470879
+:103340007B21091337AFB117868C9BAF0F1337FF63
+:1033500009D909931C21EC8463E29BB8BE21E3E602
+:10336000C3D90995B8F9107642905F41E3E6AB27DF
+:103370005CD44F59D51BA17DB0477DFF22F0EFC62D
+:103380002C68C17B3E434DB9D49E3DA98FB93D4CBD
+:10339000F9BB317F9CD5DD2CA3BF2773D2AED3B24E
+:1033A000FC13A0B35D61E86CD77F503AFB72183A0A
+:1033B000DB13EAEF137D6C3AEB0B4A67BB153A0B54
+:1033C00073FFE7E3D2D9FE74359DC577A637E3FDD9
+:1033D000D3790E359D5980D69726517B4BFFBD285A
+:1033E000F76C3A7A5F5C9187B9DF20D47EA7D85F0B
+:1033F000A6E28FAD1694DB53F1C7A2C53F9FF57FC0
+:103400007708AAF8E321BBC8E38F6BA6CD87F94DF7
+:10341000BE5F53F1C7FD34EFDA44AF3A0FF9688865
+:103420003CE4EF70BB8852BEED79C8EB734B711C66
+:103430001F230FF9B71D8B42FF1D8057385E9FE990
+:10344000DF0150EEDD0CF37B37C3FCDECD6E7EEF8B
+:1034500066F7F56FB17B37DDEA7B3743EDECDE8D48
+:10346000627F54EE6128F647A5DFABD82FB4BB8A44
+:10347000FD16FBDFE709D16F2FF42B4CD95B957E4E
+:10348000157BAB258AE95DADBE55FCA1D1E9CCAE7B
+:10349000ADD5BF551E22472700DF460972F47CE4F4
+:1034A00023661FBBDC457AACF0FB70B4409FAF676E
+:1034B000327BE8E567CD34CE74B48B9C4984F683C7
+:1034C000D1C29944BFFAD1FD66CA1FBF491B699199
+:1034D000F380BE2A5C8BD0FF397E504FEF1B8C6788
+:1034E000035FE07EA6E8E87E7AA1FF5CE8A7E1CE74
+:1034F000BB1C437E74D47028DFE14539DE24F0FC28
+:10350000A0A2E9C1F8A9FAF7B97C9D94D35BB99F51
+:1035100010DAD138608348F3D17B39BF6C7EFAB1C1
+:10352000A7F0FE5EB48EB891BF5A395D6B9F29FB40
+:10353000FEF91EE447EBBED7E8BDFF942DE526F764
+:103540005C38AFB46FB4CBD0DFC13FE9297F6AE903
+:10355000ACB450CD2701744A369665A39C6964FECD
+:10356000D583C9CFB8711F46EEA8B621BD0077D26A
+:10357000F9B5CE6638DFFB974C0EECE5FEFE918187
+:103580009D8E28F4AB765458A3A1FD5EEEEFDFDEEE
+:103590009FB61AF36B6EDFE25C8C7A6D6FF2CA71C4
+:1035A00003FEBED62954E2FB9A3880947D6FD2F98F
+:1035B000217E9BFC1D3EF9721A9363D67DAFD379B1
+:1035C00007D893E322B3275F7C2F691DE65D413F57
+:1035D00032FA99B57CF93A3FF7646429F734D47F1D
+:1035E0008F2275AD757DB144EF03CCE8EF51E44413
+:1035F00049BA9A381AC7CDE5AF48FF5EDEE8FB2C22
+:10360000AF8932EE9C289817AC634E1371D23C29D7
+:103610001A7E38155DC3F3DFC9AAFC77DBB3D8FE89
+:103620008E69F2DF0D1F57E7BF8BE576E8AC7CD6DD
+:10363000DE57704195FF6E782E8B331916742CFF70
+:10364000DD7196FF6E58C97FD7A6CE7FA7E433F011
+:10365000C5B17BF3FF97E7BF1B99CC7FE7A17F57ED
+:103660005119A75F1E3B9AFF2E9697B5F9EF68BFD9
+:1036700030AED81E81DECF899D7AEF5391FFEEB335
+:10368000F9BA4F45FEBB96D9A283C5AFB2F55E71BC
+:10369000EDC22ADC8707F2B269DE9D7BAE5F3B8B11
+:1036A000E5B20C56BE7127DBF799E6B3DB10D76F96
+:1036B000A0E7759EF7C0D5EE7E660DB45F67D75361
+:1036C0007BD2EA2F6CA2F283DC1D4BE39103F32043
+:1036D000D4BCBB13FA1B2D32537E9D693E84FC0281
+:1036E000C697DAFC06DA3C066B0AD4E5FBA599E539
+:1036F00027B8DDF9ED7687CA4BD3FBF1F2D27CD245
+:10370000F9EDACDCEF3C682434BF95963E4E453372
+:10371000FA184D3316E37E9E2A723B36F9F1F9F51D
+:103720002CB65F23894CBF4DCAA32E904794CF99E6
+:103730003C327079F4369747570BFA28DF13299BF0
+:10374000DEEB194ED4C8A32E9047D97EF2E807C10C
+:10375000F3715EE5F2E808974763FC7E8B361FA79E
+:103760009F5CF9B3CEC779F353228FB472A5D940C9
+:10377000FA71DF9B57081E99EA21755ECCF31DBFD5
+:10378000DB833F2B72E5FF0348B774EE0080000037
+:103790001F8B080000000000000BED7D0D5854D772
+:1037A000B9EEDAB3F70CC38FE306014111F7F0E786
+:1037B000A02083823F89D141390653D4D144435B51
+:1037C0009333A0222AC9C1137B624FF35C47458B18
+:1037D000147050927013CD1D08A6A487D38E27E9CC
+:1037E00049DAE7A40F1AAF2739352D4D6ADAA73722
+:1037F0004F3BFC888ADE7B4DDA9E78EF31C7FB7D3C
+:103800006BAD0D339B196640CCCFB9873ECD76EDBD
+:10381000B5F6FAF9D6B7DEEFFDBEB5F69EEF9FBA64
+:1038200090E2C82164F5D77576770C5CCD8E485D43
+:103830003C2146C56A20F0D7F859CDE3F61CFC9729
+:10384000E4F41AF14A747716C37F15A21816119280
+:1038500048EFE015F22D84D808397BC74C48428EDA
+:1038600000FF2164ED323DBD8F7F77E0FFA5497AEF
+:10387000B51E9A7EE0A6E497BFE2967FDAA75D7256
+:10388000471C9DFEA464402069A1CB11A7ED520600
+:10389000747615A17D27EFEC87CC08487BCB4BC90C
+:1038A0007C424A4873715C0121BBCA88D50DF96B13
+:1038B0008853C2F4D62DC4DA0D8F6CED8C26C4B7B4
+:1038C0005F31FA01ACDF0823BEC3DA1F18EE37B44C
+:1038D00097B8451AF01D2774800A2B89DD22A91F8D
+:1038E000ADB9464C841CBE2DDA8A41DECEBDC47D06
+:1038F0001A4496EA5B0FC831A9B8EE6311CACD2A03
+:10390000D1F546403F93F6FAE4E3FC146C2C31C346
+:10391000F30F36880B7098C614BD5FBBAFCC804ADE
+:103920000B79A3305FD17CBEC8B6D93AECCFB7785B
+:10393000D9E8F895D72413E64BA4CFA77D82691F59
+:10394000391E7E867413EC6F8740FB1B754B24DD9C
+:10395000D346D777B8FBEB4623C8AFA2AE7C5A2438
+:10396000941B8A2775621EA4BBB38FA07E5558ACEA
+:10397000AB23B1F65B42C0E7CF76A61B0428F789DC
+:103980004C56C13491FE652E07C1FA328CE420F406
+:10399000ABA8CEDC5C0CE9CA1ED18AF951B70C0188
+:1039A000EBA9ECD863507209D9717283C101573AFF
+:1039B0005571D8AE44CBDFC1BF1584D4EF27A44FD7
+:1039C0004F48ED7EE772498FE93A7ADD2EDB570BDF
+:1039D000D08E144F141DE8855E867C1FF96FCFB121
+:1039E0001FD1417EB485E5475BE0391FF9A7D519A2
+:1039F000880DDAB984AB690621D75FDCD4E8847519
+:103A0000F6CA4D42A6A21C93F4548EED918EFA6C28
+:103A1000A8E74AB2BEA01DEA69CF77A46ECC19E927
+:103A2000DFEB0A9BC7C15852E681FB8BDF86C9805A
+:103A3000F2038D73DA0F0AD8DABFDFB903E396F029
+:103A4000DF90D53E8795BF61E931609A2866931D66
+:103A5000C63F106B2873C3F30382CE86CF3B1B2374
+:103A6000DAB07D48131C87F38CD87EDA4C46ADEF74
+:103A70001BD0E7A990FF3FEBC5762794EF17A01F57
+:103A800070AF4F761BAC3EFD7C820CAF5F11F547EB
+:103A9000C5058990EE3B02938B94C8EB4D876BA7CD
+:103AA000608B9C3F524ED53B8B5BF2C389799DFE68
+:103AB000B890EBF14FE7BDE99FCEEFF64F2F7CC7F3
+:103AC0003F5DD8E39F5EFC5BFFF42FE6E8D8BA7158
+:103AD000925F236ECC265426F07FAF609F02698EE2
+:103AE0001BA975626F04AC9BD467B4EBDD1F0FE0BC
+:103AF0002F06D79FC2EB59EAF52FAF201ECCC72C5B
+:103B00009FFB380F35FEFADC0882C4796BB40A6E6D
+:103B100027E4DB5A1CC7D7801EAD4D12AD02D4FB83
+:103B20007D8EE789ADB02E178ECCCB64E3FB37B921
+:103B30007EADE5CF89300ABC3FD9F89E4A9463C573
+:103B4000E6D0E582E1BB8AB32ABE57727C2F519A38
+:103B50002594E3F43A814C338FD8818AD66804F5F2
+:103B600091FEDD25CE3F58F07E51B16EFCB8AEC55A
+:103B7000F1B835C553715E551C197CF1238A234772
+:103B800000B7DC7308899CA1D0F950F1CDABF7B632
+:103B9000EAA07F26ECFB02ECB697AE6FEF5262AD67
+:103BA000378F9437D5196C386EF5B9F5D836BB76A2
+:103BB000E3F53706DB9442D0972BF5A2B51DF2D67C
+:103BC0006FC957509E69A80A50EFFAD2AF95E0F33B
+:103BD00003F653A21EAA8CB2F454A17D585210458C
+:103BE0004468A783D4A421FE2C233D22AEF704B35E
+:103BF00099F282E5E4264DFFF621903794DF5A6B67
+:103C00006E8BA0F32C1B707D6D85FA115F88241BD1
+:103C1000CAA6D0FE3859FFBCABBE8DD71462DB8478
+:103C2000EDD76E7808FBB3FE9127E8FCAD5FA22CC0
+:103C3000A0D792EFD905B896970A19240FD36764D5
+:103C400076FFAC8CE55F88895B9D04F2B8B6CC68E2
+:103C500045DC5E5FF22B9A5F5E024008E5AF6D8B3C
+:103C6000A7F9CE2551D64CC8AF2E15B2F07E658986
+:103C70002091A958BE9796DF592AA429B4FE8F69CE
+:103C8000BD6B65C745284E4AD7BC2CE1BAB9B4799B
+:103C9000E6EA2418DFD5A5510B44C8D8966DA67264
+:103CA0008F7AADAD3319CAEDEC68532A62FCF4D9B2
+:103CB000706726613A98487193AEBF2811B44326C5
+:103CC000E43BD9C4560CCA15A573D3F49E57DB5CEC
+:103CD000B550D1541DE45B09993B17F297603ED370
+:103CE00093C3D9F226D493269E262473932D06F3EC
+:103CF00059F926D78C67CF2F1D29BFEC07964D4E5B
+:103D0000D0B3A94B891DED8CC4D73D3CE2A4F80D7E
+:103D1000CFF8F288EA6C039DCF68E8AF2B8EDEB750
+:103D20004D817989868E272EA0F79D5317D0FBDD14
+:103D300031FCAAC76B12E94E84F22487D51F459C3B
+:103D4000EE3BD8078BA311F5B4F6B028D7637B36CA
+:103D500017B55BC4E136A15E1C3BBBB311F571D056
+:103D6000265923419E530F6F5D87EB983C2BC899D2
+:103D7000507EBBD7BE3A19D2D527050F76B157AAC8
+:103D800031CC84F2D71B8A142794572C9954FE5BAC
+:103D9000BD0EFA5CF549315E80E7AA8D8EC6FB2028
+:103DA000BDFE98100F2B985C6FD960B2D179A959DC
+:103DB000B714EE5F7F16FA03A9412294A05CB662A5
+:103DC00016D44B5AB8BD84AA25940BF6191647741D
+:103DD0008360CBC6F56D613C7828C5916A87FAA2ED
+:103DE0005BDF785A80FB97F109D42F3BE37DF40F1A
+:103DF0009E8FC77FC3BA886F11E9F3DF32339CAD62
+:103E0000F6B2F25B5B0537528168BB16471DAB4DBE
+:103E1000D09FA153027901C6B9B5215F40BC18D229
+:103E2000BB53656877C8CC78C3681C759922E0B924
+:103E30005DADB166C48567CCCCEE5536E4BF5700A6
+:103E4000F7ABF712AB02F5ED3A29D0F67735086EED
+:103E50001BFCF3AA20AF5B82FD4FD65B4F432DD1F5
+:103E600036C98976B0178112F5BD416843FB745D90
+:103E700070AE5B8A3C275722A7193C9ECF58C4449A
+:103E80004745D82074E33A8A47FC35D171F9E1DE21
+:103E90002C0D6E126E47A95D827EED28F5C7CD44CC
+:103EA0006E47133576F462ED21712694EF34A7D175
+:103EB000F9D8D529C422EF5EEA12E9BA6C8A754CAA
+:103EC000413ED974343DEE10A44DD36AFE06E7CBD3
+:103ED00090FCEB1AECECBF14E4E84418B7415F53D4
+:103EE0008169C3298B0E79D00B0647CB06C4C7174F
+:103EF00074141FA153DF42FD5C7D789AAE1EEB3532
+:103F0000CBA64B8CD7C5617EFF1AE1880C7851E6B1
+:103F100068FE8B4428679362F3B1FDF72C4CEEFDED
+:103F20007A6525E5D7478915F50A7AEBAC82759253
+:103F300056623E88E332DD57B6C606F9699B7504C2
+:103F4000FBB39EE37BC6948D3A944996BE6606EA1F
+:103F50004FB785E14CDA470FBE83FAD628D9CBCAD2
+:103F600091372C9B67C575B031ADA612C737F38961
+:103F7000F3B10F627D4733F2194DF1E701C3FC2025
+:103F8000041FD89DC5F4BCAA54982BC0F83E38C86D
+:103F9000F8696F91E06E877CBB5B708AF3F1615BBF
+:103FA0006139EA47DBF4385C4F5AFFD0EEFE6E0F02
+:103FB000DAC55E41A1FCDEF9AE683DAD8CE6159038
+:103FC000A347F955B96317A09C89C5A79E00FE6059
+:103FD000B5BB57A07865D3D613825768D39C0F8E94
+:103FE000D78FACE67E64F55DFA912A9FD1F289AB5A
+:103FF000E05FA1DC45E3DBCB0780F79D75BF1DB318
+:1040000010DAFDE4A4648D807E1C1260FE51AF0EB8
+:10401000475079AABC50BD3EC7FD9E56EEF774646A
+:10402000B2F9EC7D00FC3DA8A70A7007FD8C22F7D1
+:10403000067B11A477D70AB4DEDDADCDD4BFEAD7B5
+:10404000BB56CFC0F93A2578709DEFEEFEF6053DE0
+:10405000E2CA16A2204EEF2A731B0C909FE8205450
+:10406000CF766D730915A057D3CBFCFDA96487BF2C
+:10407000FFD4140BFA1733BABF6F66B2F5D2640ED1
+:104080009CFFF35C969F5EA723369FFA325D51C476
+:10409000E6D3DE9CD638BF74B67B865FF9799D691E
+:1040A0007EF9B99EB97EF9796F2EF04BE777DFE79D
+:1040B000577EE13B2BFDD2853D0FF9955FFCDB8DF3
+:1040C0007EE9A5DE6FF895BFFF6A855FFE0337774F
+:1040D000F9E5AFB8F5D77EE922F21DBFF25ADEA8A6
+:1040E000FA9F77C1F3DE4633DD88F541F9C6E33A3E
+:1040F00037E2E01C5D37E5731BD318BF7B80784542
+:10410000C20085965B512BB4A13D57F95E65ADE0C9
+:1041100046BE5739593C0F79D9183CEFB225CA8AA7
+:10412000FDD6F2BCCB4178DE56E48D3E3C6FFB38C9
+:1041300079DE966C2687A8D73EF626417A7BCBF8A7
+:1041400078DEBAF92A8F633CAF6CFE8AE6DAA523E3
+:104150003CAF67BECA0359BAB06BC9F3E79347D205
+:10416000C767953DEFCBEBDE98FFD4A3E3E1752B5A
+:1041700072BE64BCAE746C5E97A8F2BAD2CF87D719
+:104180004DB3305E36515EE749E3BCAE948C93D7B5
+:10419000F51A26C2EBDE48D3D1F9FCCAF0BA37F5DE
+:1041A000E3E275FD6981795D3DF23A48D723AF239B
+:1041B00093C7EBEA91D7C587E675177299DC278B11
+:1041C000D7FD2497E1CA08AF23DD2B18AFA3383CF5
+:1041D000D9BC6E15E70195C8EBA606E075ADC0EB3E
+:1041E0004CF830E37583FF3508AF6B055E373F7CD5
+:1041F0005E57D91A26AF6BEDA5F1FF2F8AD755214F
+:10420000AF837455E7DDC58D82F1BA39F9E9C7226C
+:10421000D246789DCA6F0EF1F8AB96B7FD6386C0A3
+:10422000FD083BE569CEC3029533B90DCFC13C57BC
+:10423000139F3F4857E1D507A776092C3DDD532E44
+:10424000CC88477E46A8DD4CEE3C40D3C90E85EABB
+:104250007528DE561FCBF44BCBCBC40CB61EEACD73
+:1042600081F3FF85E7FF276F0B1CEF6B8F64726B89
+:10427000CFB7A56EF4E1BD6FA6B3791F88657AA1AB
+:10428000EE0F0CBE3AA7FD20C557B63FA0DA212796
+:10429000B75F57707F201DE5A798E240F4831BD8D5
+:1042A000FEC020EE0F205EBDCAF60706717F00D368
+:1042B000A7C02E621D1ADCB812C3F633D4FD81A14B
+:1042C000E1FD018FC1EAD3CF71EF0F7409B648D376
+:1042D000976F7FA0CBC2F4F48BDE1FA8CF9653510B
+:1042E0001F7A2399BC97DDEC5985F3F0508699EE3F
+:1042F000072EBF75F36D4C97A4B0F4BC6C36EFDAA3
+:104300007D05ED7E54A3C4F6A31A93F4054E56A47E
+:104310003812F24B0B04197159DD5FB878AAB261FB
+:104320008D32F9FB0BEFF3B859A8FD853516FFF474
+:1043300083CAF8ECC064EF1F3B34F6A19CDB8772A4
+:10434000E7E4EE2BA8F66256F1DE625CFA77BBBFBB
+:10435000903553667A219154D4DF3EA23465A33E52
+:10436000B4EA08B51FC49E8A7C5D5DC7EBD3D9FC57
+:1043700074105B14EA89B343A47C518BE76DDC1E97
+:10438000A59D7ED9A4205FAD134B105F8E9DCD5EA1
+:1043900087BCBCDFB552C27DE07E7480309ED351B5
+:1043A000D471001EF9CB0C3D7DEE92C11D4DE30A88
+:1043B0003F1015AC7F88301EEAEC10283FEFEF7CF1
+:1043C000D9948678757ACFE3B8A5A1F0F6FA3A5970
+:1043D0003B44529AEE435E727AE134D45BB55FE6B9
+:1043E0000C9196BB46DC4D4B7C787E2AFE2B8D0CC7
+:1043F000F3D95944FD1BD607E10ECC7B4AA7E8440C
+:10440000B9A6768A74FF72566B04E5BBA9BE7A63BF
+:10441000A6E5E8FA9FC579F04CE23E5B80F7F7FA33
+:10442000CFEF4C172B37A35A3BEF0C1764AE77D75F
+:1044300040D5709DDF7FD5BF9CCCF141D6E0C32332
+:104440005C1EDAF10DB99E7A1CEDC3CC464121E623
+:1044500000E3EBE0E3EB60E3D38E6B16E7F7508EFF
+:10446000F65B3B9EA1AB84DA9F4A0FF36BB4E3AAE1
+:10447000BEE1394272307EE4AF87DAFEF7D5BD6C1B
+:104480007250FC50A8BFD85157DC847AE374890479
+:104490003C3E725F27B373F7B9746DD8CEFDC47319
+:1044A00008FDA23E7CE43E3AAEE3B61CE41B84DA8F
+:1044B000D187D3B71F77A6A0FEBDBA0EF5A2DFA5A0
+:1044C00023A87F7D9D0BA9DFD8D721C80294FD6961
+:1044D00047B3C916809FA8F2EFEF3841F54EBDFFF4
+:1044E0002497F35007E81DEA79C74253BA8FDDFBE2
+:1044F0002BAE6FFDC4D5749F1040DF34F227B5A0FA
+:104500007F8923FA17723EB87EA9F371B77AD63F36
+:104510004E3DDB9CC1F0403BAE6B575D26F413ABC8
+:10452000AB2566DBB47AD6C0C7D510645C128B535A
+:1045300041B9807A069E34DD2FD48E67F70D07D5FA
+:10454000AF4A8FBF1F39BADF84CECBD967BF9FEA8E
+:1045500085F2730CEE97D0FFD8F1BB48D20E431210
+:104560005E5A92EAC5F9FED8315BF699CFE99966B1
+:104570003E5E97494741B9C7A45B02834F860E2F21
+:10458000467FB287FA97D70B6208F5976F3F5D4178
+:10459000D7C34923C1386AE5AD47E9FA232D110491
+:1045A00071ACC355D183E96B5DA280FBA653321475
+:1045B000DA2FB5BDEB5D5B655C070F8AB63732124B
+:1045C00046F37B119A5D82719771F27CD17881FA02
+:1045D00015A1F8FED7D2597F42F1FE50BCE295D624
+:1045E000F74B709CAB0B57523F571DDFBD3EAF9052
+:1045F0009C19787FE2CA04F727AE8C737F22D439E6
+:1046000088C9DB9F088FA76CD7F0940ACE532A5A2B
+:10461000EE0D4F99AC73107F863EE23CFE5D06E3E3
+:104620002BEE24B6DEE2F44A2C3D2F5627D2F5D6E7
+:1046300057F7F05407C6F9F87AD88E1588A3F1FC1D
+:10464000B9FDE07844F8ACEB16C1E60E80FBEFF163
+:10465000FDAD3FBFF347CE1757D075B4938F33B13D
+:10466000E3572594BF14E88802ED4F279E2332DDDF
+:10467000DFD0916EDF78DEED3BF4B96A239B9FE9D2
+:10468000C47E8CF20F2789294AE4B8097F7D9EA752
+:1046900062D1FEA4725C27FBA43E948B11FE87F3CB
+:1046A000B0DBADEFF395D37422F5F9CA7536C7E9DF
+:1046B000D978DF07EF7E8FB892302297613F8BB0B9
+:1046C0007EFE3B8E57F091672D93676FADBF3C77B1
+:1046D000F0E742CAF324C833C0FECCF52C662FB5F0
+:1046E000F2AC54E5D9CAE292BB6DC01FA83C61BDD3
+:1046F000613CF31D91EA6918725D1F48AEBD9E0FC3
+:10470000E83C4D2F047FD61C5CBEBBBAF47DBE7A5C
+:10471000A7C6BF82C9598D830DC7C7BE4D28AE68D5
+:10472000E5AF95BB366EA69D87E071B46EBABFE764
+:104730003C254D4A1CADB2F5AC01E7F73F4A1C8D54
+:10474000EC53A6222FD0E2CD701C8AC7D3B4F1B3AC
+:104750004368178137FE63C7A96627B3B7A7330B32
+:10476000C3DF0755ED70A8FD50D5EE06DB178D4F62
+:1047700053E83A0D656F43F9694969E1F9699BB3FB
+:1047800026E6A7C567E969FDE3F5D32E717B1CCA50
+:104790004FFB30F3FF0F3F2D92CB5FF59B76373009
+:1047A000DCD38E77C8B5F002EE07CD3C23B0B6B4AB
+:1047B000E3D5F80957F45603EE078C1A2FF7138642
+:1047C000FD38CD3847F96B5DF7D84F73FE9EFA6917
+:1047D0004D66964E69BFFC9C73D9E4FB69E9DC8E9B
+:1047E00007F3D332B244B65FF31FD44F8BCE1ADB3C
+:1047F0004FDB8D7E9A1240AFEEDA4F7318502FB414
+:10480000E3A9BCD17D0437A143E9577416E17EDAF0
+:104810003F733FAD3B2C3FEDFF6685E7A70DA19FA2
+:1048200086716BF4D3B0DE93EC3D831DE8A7D1FD18
+:10483000608D9FD6097E1A943F8787061246DA1B41
+:10484000EA647EDABDE64F1F05E1A35F56FEA4FAD7
+:104850005D41F913F7BF26CA9F547F2D247F1A3E6E
+:104860005F161E7F0AF77C596FC205031EAFFDAAB3
+:104870009D2F53CF8D05E35167DDE95371BD4D94F5
+:10488000477564EA288F22B7EED0FDA75D5881C82E
+:10489000DEFB70C770A5023947C8323D1F74ABF705
+:1048A0008AFB10A4A5B8441A77C8CAE4FB2C058279
+:1048B00084931EC91F51DB4FD639B2909F49B293E2
+:1048C00030FB6323C8FBB2D0E8148EB4BB536DB782
+:1048D00023BC76F765F1F73F82B7BB2F2B6174BB22
+:1048E000FB10A71226DEAE3D3364BBF6CC00EDDA3A
+:1048F0003359BB8E2C7FBF78743CC6511B8BBCCC0C
+:1049000043280F24377B783C4647EA697CE69C3491
+:104910000DCF39BC6BB3A23AAA7199C265BF3A17E1
+:10492000AB605CE6A0148778F81362C5269F535CE1
+:10493000541F8DFFE4B0127F7D0F1897B15AF257C4
+:104940004D837A4AC9CDF3542EC43F4E6331369F0E
+:1049500043DB36573EB33216AEF9394587F0B5AE74
+:1049600045B63DABB0D90BAD7BCF831B46569BBD47
+:1049700087F07D24A3926FC575B2E64F6E69AA8257
+:10498000EFC3D4FC6E27145C6B8DB0A20A1E8EFFA1
+:104990002407E5D4F819A1F1DF399673C730FE4B2F
+:1049A00088F7FD79F07C6A974010377ED875C08013
+:1049B000F1C2BC36B301ED91A76E0F4D5B4FE5D34D
+:1049C000747EE3067A7DADA5885E018744E21367B5
+:1049D0005BD8DC46EFCB9D6D869918E7EB1214F49B
+:1049E0000B2ABBF62C5C06FDA970410A3A24D7417C
+:1049F0001AFD88AE0805CFBF0D086986196C5F9552
+:104A00009EA3B97252245320FF4C9DE8C63347A998
+:104A1000D0D7650BD8FB5951F4FC08DB7F4DCD2076
+:104A200012DEA71207E1A28C100F7DECB20EF16F1F
+:104A30005A1DB3D7A494C9D948EA0EE079ACF1EE77
+:104A4000875E1774747F31D4BEE8E6D95C7F09C3F2
+:104A5000CB28A320607B45C49F2F6C9ECDF4558E40
+:104A60009653F1FDB1B387A73FBE0FC67DA328863D
+:104A7000BECF77E327FE765C7B457C66F6BC5B8F1A
+:104A8000F6BC716514C59BBE93DFD8E49442C7831E
+:104A90002AF9BA0C697F5B03C783244BE0F8C5365B
+:104AA00042759E24BACCD4DEEE067B8B7CAA51AA3A
+:104AB00011E87B5B1E81B8CCC1EDEFCE5071A18EA9
+:104AC000B1E342D51ABB1B6E5C28543CE85EBFE7DD
+:104AD00035D1B826AC63017965B8EF770DE0641481
+:104AE0008ED8B751EF7BA9B800FC09EDFE0F5B191A
+:104AF0001EE41DDD40F1C0D3B287A6ADA7185EE469
+:104B0000B79D61B8D05544D3A371A199E142473311
+:104B1000C5855D0D800B04AF0C07B4B850D9398C36
+:104B20000B47F0BCA3F35991FAF5975B26860BD39C
+:104B3000B99E6B71613AE202EACF16767FA2B83075
+:104B400084B890131A173A146EC743E042078C9545
+:104B5000E1079F87063E0F0D6D0C9F5F2D67F8CC18
+:104B6000E7C57A94E172FEB30CAF5F3B7926F03C67
+:104B7000FC3D9B1FD95544E7A1AA81E1735503C3AE
+:104B8000E74A0F9F87D63603FA1137848A23349E6B
+:104B90007194E1F2E2B7D39BF05CE4D07FD7790E59
+:104BA000621F7B147A6E559D871B380F05C1E7E1A4
+:104BB00049FC47007C7E52C5E737F57785CFE1CECB
+:104BC000C3D530F1F92AC76795C76CE57A94D81038
+:104BD0001E8FA99A1392C754CD09C063AAE6B07676
+:104BE0007F9026B3F625C61FD473C9B50FFCA9075D
+:104BF00089C0E55A91DAFDCB2D0FD3B891DC28C8D6
+:104C0000D86E1BC6CD0AF11CABE771E61FD8E93C94
+:104C1000FD957962F5559A15FA9CB6BE50FEDDDD1C
+:104C2000DA973396C0FE5D15FE13BA94E866F66512
+:104C30002BDA1742D7B90DF7A3B6EF25EEEE31EC1C
+:104C4000CB363EC741FD3BD707940F86F2EFB63710
+:104C50004C6CFF21A49D09F1BD88BB3DEF73F7FBB0
+:104C600067DCAFDE47DC6E01FD2FC67F7796B1F8BB
+:104C7000F5CEAEF1C5AFA72B7B8A51ADC2DD47D3D0
+:104C8000FA61C3FB667C1F2DD4FED9B4196C1D7864
+:104C9000F5849E1F1FC6590FC759CF0166EF86794D
+:104CA000B0C070F68040A6A0BE81FDC1F322F98D90
+:104CB000CCAEBDD6C1F1B381E1A78ABBDB79BFFB26
+:104CC0008505279229BF15A81D934FEEA1E7F8B7D8
+:104CD00075313B08576ABFAAEBC476E263D7FA8501
+:104CE000BFA6F53A9F8D50104F650FC36515572F1E
+:104CF0000BE7183EB7317CA692F5B17757DDD3A20A
+:104D0000F17B0FF7CAEE85C2D9CEF4F0EC5D274EE9
+:104D1000BE8F9F3A5EFFB8C01212670B2C0170B6AF
+:104D200000FBEA13B7DA98D643E33A3B16E9683C4E
+:104D30006DBCFBEB2F569F8B9C133F72DE5CF5B76F
+:104D400076675D76611CB79C287119667C9F8BF035
+:104D500073391F1DB7A58C8EF786C2558A7FE1C4B3
+:104D6000CDDC81E3666BB303F3F6917D5CF65D9178
+:104D70001D9CB7ABB8BA0D7155088EABBB43E06A4A
+:104D8000A324FF02E3E18D5B24FABE4A305CDD76AA
+:104D9000F21EE12AB9B7E728270B571D88ABE611A9
+:104DA0005C2D2F6371ADF19E9FFCBC71557B7E72B3
+:104DB000B2E22EB929BD3A3CD6B3FAEBC78B69DC17
+:104DC000E52D42DF537B4E71D7D2B84BB783F296B5
+:104DD00050EB7561C15929D0BA0D166F295C562E5A
+:104DE000C643BD8B8BCB1BD6A03EDC76D6627C65E2
+:104DF000B5B967158DBB64E4D378CFB29BEC5CF09A
+:104E00004305C097C8C8F747D4F5FFBE65A899C643
+:104E10005B38BE513E8EF8E6090FDFFE101ADFFE4A
+:104E20001008DFFEC0F1CDB48ABDEF538EEFEF4D19
+:104E300025E46189144B71187F62D727395FA40F6D
+:104E4000C2B82E5892DAF0AC60792D7B5F2FD4F384
+:104E5000F9E6B19FD7BE3FB716CB2730FE89EFC921
+:104E6000A9EFD18D7A1F0F14F4E0A291F702D57C3F
+:104E70000321CD98BF89D7F32194D363BCBC43747D
+:104E80001FA0CFD99270FCE1D607FF7461FE669F28
+:104E9000FAA4F891FA6A93DD26BD18A03E287E3068
+:104EA00031607D6ECCFF10F225DF7E29D0AF5C6CC7
+:104EB00087F3F03237DD27FC69324F136B217D1FFA
+:104EC00090E39883EBC96C67601CCF9EC5F5621FA9
+:104ED000ACB34523EB8C6A76220F0DE0BA985E9353
+:104EE000E41B47FA6FDC4E689F8B200D749D4710C2
+:104EF0006910C7815DC671CC966E0AF8BCF20CE0F1
+:104F0000A92F8E885BA85D0A169FDAF7D181DAF3A4
+:104F10003E78F1A3EC29F18338E9392487E2217F37
+:104F20005E5D17C1ECDAA7FB9DB5E7F5849C48B13F
+:104F30004F1D2B1EF6128E6BCE483A95DB3F559EC9
+:104F4000439AFA55F9CDEE14E83A6D7DB5A509E31B
+:104F5000664F26D9CEE37EE4933112DDC703BFF45A
+:104F6000E630CEF9E0AC0E2484E3281EF51E9FF651
+:104F7000BD064DDA2629F2227E1411E6474F6A68F3
+:104F8000BF0E55118791FA575BE4C179345F7707FB
+:104F9000AEEFAFAC7912D71F911413F2824B1FA65C
+:104FA000EB1027D4711C9827F8F198735C0E7D32B2
+:104FB00093D74A499102C96D9551F4B3E37DC6B1C7
+:104FC000E53B5C2F2FB7B236BD18E30987252B8D43
+:104FD00033396304F2632178FD876356FEAFECC278
+:104FE00091F779CEBDBAFE98D3677E76F3F999DD55
+:104FF00015D81FDC96C2F9E45744DFA7CC057D9F86
+:10500000175CDF553B3069FAEE617253E5D9ABA905
+:105010005F95DFEC5A81F2CD7FCD5E40F57D14AE19
+:10502000011C1D098CBB34BF295B61B8233BA6E082
+:1050300077E186DF67B6BB4C017137487D3ACC37E4
+:1050400007A887BF173D8C93256EBF7AE1EE01B5A7
+:105050005E5DE07A29FE66CD25B49FE3ED8F159F56
+:105060004B18B99FA8F693F8F339550EBD65274C38
+:10507000068A0BFE76274E6D4FF3DCC2B9ECB95AA7
+:10508000416E2A348F965BB0E7D669FA650AD22F53
+:10509000D58E61BF248CEF08EE2611D65554FEEB59
+:1050A0002605F4E37A0A3B2F01FDA5FCBC43E0CBC7
+:1050B00088F3F8C148B68E6AE6B1F7DF67233E4150
+:1050C000BD275A456B37CCD3EC4B22FD5E5486CAC4
+:1050D000DF5D8C9FDB380F4DB04B7EF1F708CED7EC
+:1050E000E3C9597915C60D3CA2D54D46F377753DF8
+:1050F000DEB81D41BFD335546CA0E7CC2234E51295
+:1051000048B78CF9E5003B18E719F2BE7181FAC186
+:105110007642F7B1B5EB9024C9F4BB04CD9B642B68
+:10512000FAF74ECDBA6C4E067E8DBCF4123B1716C4
+:10513000951FFFF56DB89F6E8BA2FB67EA7AA2F808
+:1051400002726C167A2C781D5EA7A51BC7C4057564
+:105150009DBA81EFE3B57DBF4CF1A8637F124DBFCF
+:10516000B25FA1D7CEFD167AFDC17E2BCDEFDABF9F
+:1051700084A64FA478CE615CF5CF8F907CF49BAE73
+:10518000A6B80F46B1F1E673BF3FA608D73BE724A8
+:10519000EA3CF671A258362B91EA5B84C61FFA26C8
+:1051A0009FD778927F14E3BA3BAAF50ACE4B39F722
+:1051B00047482DDB470936AF319FB1791AC07932A4
+:1051C000637D9AF9E4F39E406A2E60BC63BB9DF94F
+:1051D0003103DE7F96E97B94307FA7CDA3E7B76CE0
+:1051E00016F72392ECAB937DE6ADBE20AD19ED5FD3
+:1051F0007F8B48F0BB06975B1E1E53EEBFD3E06368
+:105200007F153BEF14952F99327CECCBBB73D9F90A
+:105210003D6F959EE67FCF5A61CA88199D3F58CD54
+:10522000CEE969DBF9F95C89E6BF176DFFF95CE847
+:10523000F7379FF89611FBD5CCDFFF441C8FF3D9CD
+:10524000FFAF14981E5DD4D8ED51781E242E7A92AB
+:105250003FD79C6C7D372380DEDE40BD5546EB6D2D
+:10526000A3CE6D5A254CBE3ECEED24D47F892F4E61
+:1052700074E379A01B882F39A3F552AB7FB7520C8A
+:105280006C9EB9BE56701D50F552D543558F1E7B8E
+:10529000C4ABC7EFEB9DA87B2D01F7FFB4FA097AE9
+:1052A0004CCFA76E7B5DA0F8F2D83EFF3882563F08
+:1052B000876E3F4AF7238700008F07D0C366B3B2DB
+:1052C0000E3FD5D71B5F2CE077EA86BCCFB3F3AC9B
+:1052D0008F70FF55C3E362CCC4660439C40846FA34
+:1052E0001D8243558CD7E9896DDDFD50CF133FD624
+:1052F0003B517FAF151BDAF0FD164976D3F3C6C0DC
+:1053000020E541CB08DF0BA6CF88FC833E3CB209E9
+:105310003B95103EAE7B83E1BA7372707D67DDD83A
+:10532000B8DE87B88E7E15C78B60B8BE0B711DFACC
+:10533000DE8BF28E1F0BD7DD4766F8E0C3FDF3FC72
+:10534000FD8B60B81E6C7D7CD1B87E03713D3E3410
+:10535000AE5FE1B87E222524AEBF8BDF77D98EB851
+:10536000AE8C1FD755FB1B1CD7D9F768B6725C1FD4
+:10537000425C2F088EEB2752545CB75EF0B5C71124
+:10538000C6E8DA8169E02F974D33A1BCBFAB67B89F
+:10539000F9A12C9BE27CE4BF8FE3DE77A7B0EFBDE1
+:1053A000F426C9A67CB89AA2597C82E06B5B209255
+:1053B000ED5C3EEA73CFA5B2E7A6A612D283B82170
+:1053C000D94CE8B71C4C65FC72A0259DA6C1BFFA5C
+:1053D00005E2C1A50F45E2EB5F69AFC37E500CF05B
+:1053E00073786E15F83F61F9575298FE953461FF56
+:1053F000EA857909C1FD2BF5BCE5EC9381EDCA6F17
+:10540000E67EB5E2093F99F7C5C613AED33E8F9647
+:105410001FF8AFD4BF6AFFBBDDCF3A331077F65227
+:105420007CBE12029FFB393E77E66AF0B96172F0EA
+:10543000B9224CDE7D3D043EABBCFBBA77CE91A4D5
+:1054400031F1D99F77FFEF30F13918EF56F98B3AE8
+:105450007FCD82FD97B89FF279E17328DE9DF088B9
+:105460004DC0F75B1EDB97BF10D5F116E273C26823
+:105470007C56E7DB6164CF69F9CEA7E81F268CCCA8
+:10548000DF0927F09D98D0E7B9D4F3095A398CDAAF
+:10549000176A08BCFE2BE60B21F685D8FB7DDBF1F5
+:1054A000FD3EE17378BFAF6562E7B8621445E595EC
+:1054B00063EE0769E3D275FC7D236D5C7A5AA9D34C
+:1054C000E0C07319EEF254275C6FA4B2FA073FDB19
+:1054D0009A8ADFF7772618A8BD23B71F4EDA306502
+:1054E000C44FB906F324F8CC53303DD5FA29D786FA
+:1054F000FD94023F3FE5F11CF63D88FE613FA5DDCE
+:10550000CF4F51F38782F8298E1C89E6839FE2C82A
+:105510004908EDA7ECE27ECACCDC107E4A67607DCC
+:10552000BA9EC3F429989F3210629DDF6B3F65607D
+:10553000188FC7F653DE9AE5EFA7EC08D74F393935
+:10554000B69F525125D0737AE1FA2983DC4F89AF97
+:105550008B4DD6A58DC6E7DEF8478AF0FCFDA0F797
+:10556000D11233EA651D7B2F3BB49F626B5A04D77F
+:105570005D720D7D0FE61B3BFDFD1442EC84EE4B8E
+:105580004CD04FF957EC143DE7EA61E75CFFFE8D24
+:10559000DFFF6DC1DD9F73FDFEACCCCD4E1AC47331
+:1055A00025F2F75A04CC57ED6B011F6F449540620A
+:1055B0007C70A440E5C13D92DFBCFC99DCD6B1FD16
+:1055C0004181EAC9AE1476BE657A99BF5DCD7B870D
+:1055D000BDDFA3DACDBC20FC583B3FF45C069E1F28
+:1055E0002988A1FBE85A7BD9A0307FA6A18CD0EFF7
+:1055F000136F6DD823E0FAFC30C73F5EF517620CDD
+:10560000E5039FFC9AFDEE879CDE6D44BF4AFE9E3B
+:1056100028E37CF6DD7EDEE4FB3D58D55EFE10D649
+:105620009394498807D613BE9FF00FB09E30FD3A81
+:10563000AC27FADD34584F787D13D6135E7F0AEB22
+:1056400009F3FF09D613A67FB6DF46D3DDFB4B680F
+:10565000FA9A37827D4FDDB97933DAA751F3E2FB4D
+:105660001D06DCC7F204DEC7AACEF96AF14E63EE6E
+:10567000D8BCB39CE398B69E09F3CEDAB179A72AD9
+:105680003F95777E9CB3E839943FC6B9F03D56EF1D
+:10569000703CE68BE19D3B5C22C5B960BC7380C762
+:1056A0000542F1CEED3C2E70DDFBF485E43179A7A7
+:1056B0007FDC70796E78BCB3F74BCA3B7BC7C93BC4
+:1056C000DF9A3536EFAC0A62BF1A72147FDEE966E4
+:1056D000F62B5CFFBC3A373CFFBC32A47F5EE3E7AD
+:1056E0009F5F69E5FEF93DC2F9CA7B84F38EA0385D
+:1056F000EF3892EC83F30E27C3F913B961E2FCF3A0
+:1057000080F3D0CEE5DB8B4DBEDF8FBC5738DFAFEB
+:10571000E23CE97CD817E7D5F74CC2D50F4F2EE312
+:1057200083A1F4A33AA47E38FDF4E3AA87E9875A5B
+:10573000FE5E9DE35B75FA203DC7A39EE3AB8F251C
+:10574000DCFE09C76DCB467F5FEBCBFA1DA067B8C7
+:105750009FF79FDF010AFC1DA06DFC3B1CDBEED117
+:10576000778026EDF7EEBAD8F79DEFFDEFDD797E75
+:1057700021D2737B82827EEEE7F57B77451E81FE28
+:10578000CEDEB616F69DFC6D2DCDC3BF7F17690E1C
+:10579000FE7B77716B32685CEA4F1D8207D5804EC5
+:1057A00055DCC87A0AF777EF76CAAE317FF76E67B5
+:1057B0008E6B42BF7B37DE7369CDFC7C5ED8E7D24F
+:1057C000429C9B73F13847B07373DAF869A29B9FD0
+:1057D0002BC1BF31CE29A6A93C3EF839C5B49C00E7
+:1057E000E714F1DB14BEE71A86C7A14CEC7C5D73AD
+:1057F0001ADF67E0E7EBEEF577B17E335F18E77706
+:10580000B11C4790FF87718E3A70DCACEBA958B49D
+:10581000C3C1E26695EE89C5CDFE90AB8415371BFA
+:10582000EF79A1BF9DAF84755E28DC733D5D689BF9
+:105830002670AE27D839A3617DD19C330A76EE4716
+:105840001DCF78CFFD74CF67EB2ED8B99F70C7F10D
+:10585000161FFF44DF97383A3FE43A3D3A3FC03ADB
+:105860003D3ADF7F9D061BE77B9A72C1CE29A9B81E
+:10587000A63DA7F469A4693EFEEE8818432CB8BE85
+:1058800093489415E350FB8CECFED351A676BC7E76
+:105890001A99EAC6CA9F161D0E1CFFA73A8F11F768
+:1058A000EBDF5BECF80CFB1F1D7BDE8ECD1E4EBCD0
+:1058B000CF82EB7DCBBEEFD88B8157C9D3C85F06B3
+:1058C000FABD9C2D3AE240DE6ACC63EBF9237DF70A
+:1058D000AC5818BFB064A531AF3040F97DFF85D614
+:1058E000B75C24359E00B8309BD7F3A28E5461BDBF
+:1058F0008F3EF10FD75E81F14429390B506C5196E0
+:105900009ED285302F75BF4CA7DFA59E9EC7ED7632
+:1059100012294079EF2F7024FAB66B5464899D17D1
+:10592000F02CC5FCE5FF9673E697505FDDD762E883
+:105930007B7AB674EBFA85C2E87E403DB3B11EE3D4
+:10594000ADFA8F91D7A9F5FC2CD2FB22FDCD13E740
+:105950001F1FFD2DD8829FC57A670A909EF3A30F63
+:105960001E8D5F0AE904EF4CCC3F4F3AE8EFA8FCEC
+:105970000C6C22F2FEEABC8EE7D18E2D7FE8C6CBFE
+:10598000C7A0FF24CB40BF837094C791D5761BF38B
+:10599000443AFE463E2E550E17ABC796C3622E37CD
+:1059A0001F392C0E2487134B6C4BF03E74928EBB28
+:1059B0006E3FB16F833EDAA67B2217C2C4272B9EAF
+:1059C000578F413533329C9404403D362607C6AF8D
+:1059D000D47A8616DB8AF0FEC5EAF74BF17B289174
+:1059E00017D9EF881A338833DA449F7B302F61E46C
+:1059F000B92285EC15D246E6614721D3F738D403A6
+:105A0000A8EF90C195B401AE72C6734FC950FE881D
+:105A1000D95D1648DF6C56B60EC18DA0BFFF532B63
+:105A2000B71B2B7CCA5572B9ED5D64DB84FD33086E
+:105A3000C48EE5EA973079992E4E5B40E36219A453
+:105A40006023E0D8B7ADAC3CF4F7315A7EA98B8225
+:105A50004A64061B677DCE7182F1A0C8A41676CD7C
+:105A6000F0D2F51D493C469CE75DD6D79EAF4DC2AE
+:105A70007158E9EFE71CF6AC6C9560DEDBF0E50BE6
+:105A8000E02FFB218DEF27BD04C08E3CD939C3E048
+:105A90003E1D200EB2DDCAE66F6D816D4721CA251D
+:105AA000C2FBF231287F34DB40FDDDE53A57590572
+:105AB000EACD4331D45F80FB65BE76F5053EEE1737
+:105AC000F2D8B9ABA3FFC748F3B5720D579F0E8C40
+:105AD0005E5707F21202EAD341BC3F4A9FA606D5A1
+:105AE000A7FA20FAB4A3B070442FD4AB9464A07E7C
+:105AF0009574EB480FBB1A7BE973462BAD4F2A61B7
+:105B00007106F156142D27DE6AA0FE9524D7D079B0
+:105B1000025CCECDA3EB4227214F50715B8CB1D1FB
+:105B2000FCDCBC30DBC93812AA9DBD63B5B397B7A6
+:105B3000B3FCA11807DA9BE5889B3EF3B7D2CACE27
+:105B4000C3C55BD979E360FAFF3721F4FF31EBB0CD
+:105B5000FEFF18FB134AFF9BB8DEC1BCBC45CB0758
+:105B6000D5FF0E7A8DB230FD8FE2FAFF9895384B53
+:105B700092B0BF4CDF2FFEE8FE56F4E3D5F5F0A25D
+:105B800067ADDF7A688134AE8760E37B9A8FDF840C
+:105B9000E38376DE2B109DE807FD91E4B6A3BF6F8B
+:105BA0005A224BF89DC30FF2D47EDBDECFA37E9B3F
+:105BB00097DADB3672F36C04AEB365028D534E7127
+:105BC0007A6C461C2F7111DC67FC1F5CAF5FD23111
+:105BD0007BEFCC22743D12C945501EDA751A99D15B
+:105BE0005DE0F099A7DD5CBEA7ADF63E94D74B3AD9
+:105BF000390AF99E3A1FDAF1ACE0F29DB798ADEBA5
+:105C000050F81F6165F81FC1DB89FB37634DA07534
+:105C1000BCFCC99F5E7B658C7AF4BCDDDB7CBC2A56
+:105C20004E47A9386D19C6E9DB14A7ABEB559C7E2E
+:105C30001D711AD6F56701EDC43458D790FE7FAFB9
+:105C400086736100800000001F8B080000000000C8
+:105C5000000BC57D0B7C54D5D1F8B97BF71936C93B
+:105C6000E64596F70612091260936C5E10E086878F
+:105C7000C696C7A2A28104B20141C008415157A5EE
+:105C80001F37E641D0F01951FBD1D28F6E102D7D18
+:105C9000E807CAD7A29FB58B6045050D9F8A88AFDC
+:105CA000285A5FB45290BA6D6DFDCFCCB927BBF7BF
+:105CB000260BA1B6FF0F7E3A9C7BCE3D67CE9C990A
+:105CC000393373E69E1DE4D9FDD37B196383B35545
+:105CD000C64632B6C117B0788B18B347DAFE28270C
+:105CE00001F4B8CC0127639F9528D717C1F3EBE1E6
+:105CF0003F96C198D96D55E5F10023AD5D1CDADF03
+:105D0000A7F6762FF563AE6CA7F7E54802B59323A7
+:105D1000ED5D5836BB1A58208FB141A6C0EF274021
+:105D20003FCC6D32B362C61C8CFF919D0AD5FF7EBD
+:105D3000021F67CA774E3D746F3AFCFB12AB370700
+:105D4000C0268955ED067CBEC13F5319F37B65C65D
+:105D50008A104AD43EF5AFF68610BCDF64ED70CFF2
+:105D60008376AEECEFDFEC8271A7AC7EEAD347CE50
+:105D7000D34F01BE0FFD8CD1E0E1FAFF9D55E863E2
+:105D80002CE1B0EC953C30AF5CA60E4822FA8CF1C9
+:105D9000C238F6FABB697E151EB65782F9DE5FAAD5
+:105DA0005C8ACF8730EFDC42E8A26D03F35F676166
+:105DB0004C49DBEDC0F2A0DE742EA07E7AD3B91080
+:105DC0009F8BF11D62FCEC9EF1CB687D0CE3DB71D7
+:105DD000DC2CAA9F1CDB2FD47F2999802E36181C1F
+:105DE000FA4B5D93146A94A2EB38DB07EB9AF14F00
+:105DF0005DD739885FBC759D02B8B0898CFD624261
+:105E0000C25635EF9F32DE60EF79F868B097CF6BFE
+:105E1000BB15E60EF357075B430F6745D75DC035EB
+:105E20001AFF003D9622FEAD59B858B00EFF3569F5
+:105E3000AB3A94B14EC62A915F66FB02AB683CD682
+:105E40007D05037EDA7E47AA7437B41DAA84A59423
+:105E5000BC281DBB2778088AF7862ABCFDD060AA1B
+:105E6000A44ABAFED69DAF3F231E80DF6D88DFC3F4
+:105E70005E652ABE3715E707E5549935607F4D26E4
+:105E8000B60261676A68851F608BD744F52D1A5F7B
+:105E90008BF2EF8B1515FB017E69C27ECEFAE4759D
+:105EA00026A0775229E743C087F913195BA5F56F40
+:105EB000F28758373C4F28654A08E0119FAC9A009A
+:105EC000DFB36CD1C3B2C4DF5BE6C4F6669AF706F3
+:105ED0009FD28EFD377B5D5416FDC5C3739B86D75D
+:105EE000360DCF6D513C1FF4527F81ADE7C3D348CF
+:105EF000A7FEE27B68420FBE3B886FE3F427D60B18
+:105F0000DF6583E0793397CF39874715A07C3EAAB8
+:105F1000E1BDC1E7FF05F653512AED45FE050D949D
+:105F200080FD6DB3C27C613DB7D56FA9B0021E9DE7
+:105F3000EB5DF932716AA811CBDB9A5CF977433FCC
+:105F4000BFD2F8D0C89F3DEF5B778F29CC237AFC76
+:105F50000F8E33B5BC6B5621BC9F0C7A027BAB60B5
+:105F600020EF32CABBEAF602BE6D92EA5E827C7F07
+:105F700085D3FB3036705E4DF81BFB1790B1BB68C4
+:105F80001E62BECCE9BB40FB466AEF1AA036F82F72
+:105F9000A6BD4DADC2F6513AA6E5231DE7944A2AA7
+:105FA000EAA90A36AC1369FD16F2015F9F63B43E9D
+:105FB0004E986C5994AEBDFB57A97D85BF4142BA3E
+:105FC0003A72612878EAF0C373A09BC9D3C1BA01C1
+:105FD0002664035FE4617FAF517F513C0A0BF57883
+:105FE0004C7E08F188F6DF2AF0F984E4B69FF87C4D
+:105FF000E5481ACF92190BDA39BC2D216907C2AFD7
+:106000001CC3430CF4D99192C0399C9F3A8DEB6923
+:10601000F5DDC45013F21A6B98E01F8730CC50BFE7
+:106020004DD5F4DB54BB93F421FBDA7CAADBCE9F85
+:106030007D03FC26013B0F49C5528DEB7763A1CC54
+:10604000BAA56F06F46B7C4B7E46FCF16B8277FA47
+:106050006714C22CD358ADDFD97B9E352616407EFF
+:1060600071E573FE7DDB121E86FA4B2A9DE6CA2F70
+:10607000EAA37DF0DFA8BF24D6ADCA3E241FF33EBD
+:10608000EC417C01FF022E8757C2B843F2B91E00D3
+:106090005495DD7D8C3B245FD2F1EBB52DD3D848F0
+:1060A00080363B531353394C2E2079F1E4533BBED9
+:1060B0004F56B8D8DE7453743E627EA2DF715ABF69
+:1060C0003DF85A617E79382F56B5C7C9E757108316
+:1060D0008FBBB4625CEC3CC5FC8CF81EDA10F4CFCC
+:1060E00000BB202D389D9D4C63ECD90D012A239EC9
+:1060F0008E025A3FD502D0CCBA16DF04289C6481A8
+:1061000032EC372DB7E3BA2D40A7B4BD0E2F701473
+:10611000EBB28F6AF702EBADD9277B6D9EFEF3C71A
+:10612000C5F285911FF627DE3A01F55AD3CCFCAAB9
+:1061300074D438EA91AAC3A5503EE23DEE84F2BC85
+:106140003D47AADC20FF4D47BD5519A0FA9BF6FC40
+:106150007C6B3BC847D3BCFCADD83EED7F7EE69E52
+:1061600089E50512D90137427B15F783FD7A7B2C2F
+:106170002A3F2DC44F474AFCDF2F407933073CC8E4
+:106180008F4D15529CF65C7F0541E4B3D1DE8B98B0
+:10619000B8DE3B089A7120D0451808CD1544AF975A
+:1061A00035DA34291FBC2441FBFDE5368F2D8BE405
+:1061B000E1A67CDAB75C8727C0F32DD34CA6BBA140
+:1061C000746072663BEADB8E692609E9DE349BE384
+:1061D0006149EF96EB9CBDF13852A21CC37E9A1622
+:1061E00041BBBCF8F842BB27707E36587F670187F9
+:1061F000C8BF169067592B6B7C7C7B3ED927922FAA
+:106200007D14E167467A18F94BF0D50B396F0C47CE
+:106210003B08F8A811DF33F2CD1597BC7909DF47A9
+:10622000F57CD18B7EBDE875C689FBEB2BA5B2430F
+:1062300072F6A62FD0EF5E1CEF95AF395D3B4A4753
+:106240007B18D0F540996D4C37ED5FFEFBB01EDE3C
+:10625000F225CAFDC2FF071787BFF77800F1FFDA02
+:10626000AA5BFF3971D65F4EFCD28978E17C709FC2
+:1062700000FC1FC1759387750F45FD20F0EEAF1E22
+:10628000DCA3E98F183DB827BF8F7D5DE80958D79B
+:10629000BDF9DCBEF9720DB2B98BDB37F1F4D3FE78
+:1062A0007CBD9DD00FFDB43F76FC0BE9A73EE8FF17
+:1062B000C2C5D01FD435D1DBA2911B8A1E1794A76B
+:1062C000E0BFE13DD893BB6DA3A2FC2D455838310A
+:1062D00089F3B91DF8BE353FDF6E957BF7DB5FFABA
+:1062E000BFDF9BFEEF9F8FFE33E5534DC9A0E7CE86
+:1062F000944B342F2502A893BE04D72A06EF29F623
+:1063000076F2539241E7997335BD0AFFA528766668
+:10631000B647CB69952E5D39C3EFD6B5CFACF2E861
+:10632000EA07057275F543567875E5610DA5BAF66D
+:1063300023828AAE9CA556EADA8F6AF3EBCA391D2E
+:1063400055BAF6A3B70674F563422B74F563773537
+:10635000E8CAE3760775ED27EC5375F5F9E1365D8C
+:106360007DE1A10E5DB9A86BABAE7DC9F190AEBE6B
+:10637000AC7B97AE7ED227BB75E5C9A7F7E9DA4FAC
+:106380006166B59B97A56F60A9CF008349B07EFE7B
+:106390007CC9ABC23A81D9D5950DF27D15137F4CDE
+:1063A0001EB3584793EE7DF60DE8A5ABBAEB66E158
+:1063B0007EC766593EC4E72AFCC5FD12A8F8616C89
+:1063C000BB29A06F25808AD7127D8EF8BC7DC5A71A
+:1063D0006C3CF5FB61CF7E8B76061B99EC01BCA66D
+:1063E0001C925908CAB32EC057BDE7C5BC619CD7E3
+:1063F000EB32EDFB4C55BAB207C6CE4BBAA87929A1
+:10640000F097DB01A7CDB8AF4F2995D80FA53EE691
+:10641000A9CD07EC6033CA7FAFF932EE971BE71BBB
+:106420007CBBB1F9604CBB390589E9BF437DE065B0
+:10643000DE6F64943327CDE7CC6BA03F587C3A5491
+:10644000A8D029E8990A450A21DDBEDAA0361FB492
+:10645000F4410F378BF209CCCBE1D1CBE1805CBDAD
+:106460001C267ADDE7E5A35EF455D945D1D7037F35
+:10647000118FB9D800F09C1B61A170567CFACE3503
+:106480005BA2F4BB08BADE8E741D1BA5EB39563E29
+:10649000B7D0C3FD3FB40B8C7A4ED00FFC960D687D
+:1064A00067C4DB57DA0B2E7A5F692FF876FBCA03D5
+:1064B000F87E7FF795FEEAFFCE825E7E4867417FD9
+:1064C000FC10D0FFE887887D09FE2818374A725FE4
+:1064D00012BA1BBA7CB480FBA3F1FC9147B571A33F
+:1064E000FEC81973AC3FA2D83213B4F85F1BC65371
+:1064F000857F52519E3F17D0606DE8E316F57F9E71
+:10650000CF14F4DAE79E2938CF3EF74C238F173C9F
+:106510007344F6EE80A19E4B97C31930BF2D6C5C7F
+:1065200008FDDC2926BEDE9501C6E5CF7CDF2E7492
+:10653000CA00DF4348BF4A4F85B4D289CFD7128CF7
+:10654000C747AF5F3C1FBDFE2DF9E89D828BB04F62
+:106550002ED6EFF9CAD4703C00B0A985FB291B37B1
+:1065600031B2E73736F2F2DFB4F99ED2E08F0B3961
+:106570009F542495921DDA22256AFACEEFFE37A4A5
+:10658000ABDBCA30DE03743D8BF33E38A83819ED1F
+:10659000CBB3875F750662FC84B7B5F91ED3E6FB03
+:1065A000CE2D3DF3FD2BC94DD5D2CD4531F35D74D4
+:1065B000AB98EF5017E95DD417A01FACAEDD144FB8
+:1065C000BD4C76D2BC9AB359C846FEBD326BE6408C
+:1065D00054C25CFF3279D621DC47CFE599990C7A19
+:1065E000C78EFA0DFD488FF903D4476DF097F42C50
+:1065F000EA2FA093C50DCF63F49203F517B41FC023
+:10660000787BA1BF447B078B69DF875E4B2FD4F477
+:106610009A956572BDB6BE6D2CE2C502EE583FC7B5
+:10662000A8D744F960F7A8CCEE3EE445C0E4527B1D
+:1066300053768CBE4D515CBA725AA5BB293B069F5E
+:106640000CBF47579F5995ABAB1F14F0EACA43568E
+:1066500094EADA0F6B5074E511C14A5DFB2CD5AF9B
+:106660002B8F6AABD2B5CFE908E8EA476F5DA1ABE3
+:106670001F136AD095C7EE0AEADA8FDBADEAEA1F8C
+:10668000C37F0C86FFD43D0B14A0D363A0E7D00FCB
+:106690009FF6C4630B30CED9FAFEB56E8671E38CDB
+:1066A0006BECB17C6884073338BFC6AB17721AAF86
+:1066B000BE52D35F26BBBF320BF8D7EE1A5920C3A8
+:1066C0003A3FB66F9A6B09F4BBB090CB114BD7C76A
+:1066D000F5C5FB834C81858545D17300B46C30FED4
+:1066E0005609F39908FAF40ACFEDFE1931F36E1C3E
+:1066F000BA642BF2FD46903BE4FB8D8CCF5BD061FE
+:10670000A399D3A5870E5243DB5829965E2F2F50AD
+:10671000F2A2F45AF1C44B0BD472A4D7E56EF4176D
+:106720000FA6003DCEC37746BD7570C30AFF8C1C13
+:10673000C67EBBA181CA87B4F3A84A4D4F8AF71E13
+:10674000D4F48880E8FF17623CE4B0FC658066D72B
+:106750007FFFBFF03CFBEC7D852E7E3E20A9D90C4F
+:10676000EC874A4BA892E2B99A1F6796382D5B32A4
+:106770002EF32E81E7F716F27D87B13BA8FE164176
+:10678000EB38F33783408763F4819435BF0AF7977A
+:10679000CA0C580F28574ACCDFD77EDA54C8E37F9B
+:1067A000FD5F4FBE4E623DC53A19F5A11DE705D00C
+:1067B000ECD4CE9FA2E7498F205FB1A1C07703A39D
+:1067C0007C27F84BC4738DFD05B101DA0F4E7EBEF8
+:1067D000440A15EDDC43A33AEF96E2D365E306974E
+:1067E0006246BBD6E54976211F4A7C5F01C3CE7D58
+:1067F00065E2BFBE9D283316223A1BDB07F19F18C6
+:1068000047713B695E48568CEF833ECE9D07F5AFDE
+:106810006BEB33B94879B190A0FF30F219B307722E
+:10682000915E507E99E8E9EA297751D90D658C6B24
+:10683000BB5C143F8F471F416F78EF8D421EFF13E3
+:10684000FDBC49FD38793F507E8BEAD37BCAEF50BF
+:1068500079286FDFDF717AE6DB25871E8675FBD22C
+:10686000AC24A7023DAE092E257B64417025C1B63C
+:106870000DAE8A0F817E2736F89B9B015EB3A0D0B8
+:10688000E5017A2F58B694A0E8B71AF91ADEB76670
+:1068900099FD78DE206799FC3B49AEF839882C8554
+:1068A000347A3653792110783DD889D52BE635379F
+:1068B000C7F0BB03F11B85FE8DF92FB1FEC27049F5
+:1068C000F97361CCB9C8C5CF0F7411F0E997CEEC5C
+:1068D000908A7CCBA6B9FA3AC710F38CD7BF9867D9
+:1068E000EF71F93C05BDC4F34DD9052EAEB743BADF
+:1068F00038BB2367860BF551B5A4E19968E7F2A48C
+:10690000B55B08E33C8EEF99BD1EE4CF859ADE109F
+:10691000E7720B81F3D6A746C71D2EF947F8327AE6
+:10692000D3B3BFF44A8731BA70BDCC1D747EF480F6
+:106930005394A11EA03F9B9F27393CBC5EE0911958
+:1069400008313C7F1AE0632E7C64C276682F0FE822
+:10695000524CF9A0EF7CD90BDD63A03E3BE03679C9
+:10696000A97CC29C81E7A35076E1F8D9270E96A3B3
+:106970001FE1BA54827ABBD973E2D06446AE26EDE9
+:1069800047CC7302F55C674F998519ECFB9D093D77
+:1069900065C50EBE71E7C89EB28AE5EDDAF97BA542
+:1069A000CF73A299C761A7FB907FECE159B9E9E8E1
+:1069B0009F482EB44BFB7BAED55F3A76E63D7E68B2
+:1069C00024DAD36EB337C7837624D3BDB7C667A5A1
+:1069D00076AF1605E6233E89EB4F93DB7E4F5E6A6A
+:1069E00022F243741D428675E074F7E786B473BDE6
+:1069F00010ADCB08F7976A058C37A29C9BB5CC935A
+:106A00004AEBD2E95E47E7829D79DABAE482570F12
+:106A1000E504403313ED7BED9C75402E3F3776D96E
+:106A2000B87FB3C2C7F7DFDB7CB206F9FE97EC7E16
+:106A300080A1BC3B2A4DD43E5983D1F973B9BECD58
+:106A400067D6F64B4E8FFB4B0337FB62FCC4C3CDBE
+:106A500026DA2F3A9B47764A12AE836B462EC01F2A
+:106A60006B7924B04E57225D0E7BD312027CDDEE93
+:106A7000E873DDB4795E68DDE2AD97F033E2D55FAF
+:106A8000B340F687C86E0B3C381FC6BD715F5A3ED7
+:106A9000DA6DC7AA645F179457FF3A93CEB5B7680B
+:106AA000F45A633A3D10F7D94DCE2D7E84B67D8DD4
+:106AB000CA101411934787C79AA72B68FFBD6B4074
+:106AC0005239AEB7118F635FBF91EE87FAD97FB6A7
+:106AD00091BC63A005E332B5B48834ADD7306EB352
+:106AE00058B3537EE9E3F6E36B1BAAA89FC5C28F98
+:106AF00001C1D5F4A7F40D3864B5D132D9252CC81D
+:106B0000E33176F88B7ECE3133980630AF63AA44FA
+:106B1000F1A63AF33C2B8E57A7EAE3364BFCF997E4
+:106B2000A1382C6DD33F5FA6F93DCB0CF19F6BAB29
+:106B3000EA7AEC99B32CAADF9859B198800F0E5FCE
+:106B40002931B41BE6FB17F867C4D8F36FFC4DAED0
+:106B5000453A1CC37711AF9AD13B309FC4480FA967
+:106B600088F3E76B1BFC6467F6D08764E1C274E8C6
+:106B7000A1D7FF113D2E9367111D96CE93C8BE334A
+:106B8000D241F8AD623EFF2BE6C9BCC706007E27A6
+:106B9000DB2D443F169E4AE73C73F8ABB1F322FF6E
+:106BA000D4057F793CD4D39206E32D0362A21C5D09
+:106BB000A55A747EED32CDAF5DC2FCC96189E6F5A0
+:106BC000419C79E9FC5B23DEC679CED6F60BA31F88
+:106BD000CCCCE13CB463FEE4D3E2A7E3799CEFAC18
+:106BE000EFAAE430AE1F2A8F3EF4AED11F167C55BB
+:106BF0001B9CA7B39F2516E829BBC0AEB8C92D7B47
+:106C00003E4CC37882E54164C379F66E33C5A9E58D
+:106C10009A6494C779CCEE7142FB3B61B1314E3A34
+:106C20004771789C31F89EE9902A516FDE04DD05AA
+:106C3000296EA6905F50ABD1FD26B795FAAF65EAF5
+:106C40007EA423F0DB97B1FC168F0E038B7AE63F10
+:106C5000FE62E67F3FDAE23CCE19C678C669C91EFD
+:106C6000DA2145E354F04FD50AAA726C5196A697E3
+:106C700015FD79156B207BBF1F71ABB1457DC4AD90
+:106C8000C479BCE0CFC5766758E67C77AA873F74A5
+:106C9000E7F1018671A9D6C1ABBC48EFD6041E97B7
+:106CA00012FB24D8B325182F6C4DE0F129A1E71D64
+:106CB000B8BE32E6B9805D1843B75EFBF4C1EB762F
+:106CC00075825C049C667637B5CA25FC022E81DF8E
+:106CD000690BF6531BB49C89ED2790085A05E6BF53
+:106CE000C4CDF3095A074F745199713F9BA9D03E07
+:106CF00026FE1EC065C4E7768FAE7F6C4F76595B6B
+:106D00004CFF23098D630AE0D57A9785F0328EDF38
+:106D10006BFF328C67ECAF55CB2B9313AF5B41FE0F
+:106D2000977BB08B6CB25CEEAF2C2C32E9F69D25D4
+:106D3000F634C59C162D7F30C85915BB7F0B28DE55
+:106D400013F48CDA69619D9D764FCB53270E0D8B22
+:106D5000B1D3D4A74E607CE11FB5D3D4FF7EEA4403
+:106D600033D9390DEF7D0FE3B42FCA4427913F6229
+:106D700006B3223995FC3215A13D3884E623F2484A
+:106D8000D23C5E09D7ABADC8C3F33B3DFC9C35CDCF
+:106D9000EC95BCF07C8B66EFD01FCC7348757562A8
+:106DA000FEA1CDCE9A1DA9F81E9FB718AFA7DF5C34
+:106DB000AFE4CA8B1FFF7DA0E8A2F3671E28EA2379
+:106DC0007FE6B089CF5B8579635C7E91FB767A6ED6
+:106DD000F4C7B66BE39D6481EDD84F57D5AB8B6E8E
+:106DE000C338C75E1BC55DFF50F5EAF2FFF0207D9A
+:106DF00060BDF1FD05F7CF2F4E47BBC44C7660DB7D
+:106E0000301E7F911B25B22F3679AC957B017E50C9
+:106E1000587118FB63951E13F2F39904CECF1F141B
+:106E2000CEA0E75FBDB3D1BD04ED477702E5DFC972
+:106E30008D59F7629E217B01F06528AF8CF6EB56E9
+:106E40002B87CF14F17CC36734BAFEB288FBCF6DB9
+:106E500096406E431EE6ED023631FC6837AB0CFD02
+:106E6000787BC44CCF6549223FAB3521907B4B0CDE
+:106E7000FD44BFF6080871615FEF5BE939CE8BDE38
+:106E80004FE5F88876CF1771FBF4790D1F7B64000E
+:106E90008DD79A0A783963FB49E2CF353933CA492D
+:106EA00041D1F497501F7E50A81C2E2279E9B6A03C
+:106EB0001E5DEC3E745C4AEA8F1EE4F1F9C4AFA596
+:106EC000F008CCBFAE904377013F2648AED93ED400
+:106ED000E91516CAE7E8CA4D4FC47395A366572251
+:106EE000FAE7EF14717BCF3F53263FDB5F61217ED2
+:106EF0003E9A7BDD2332B709EDB1FB51AD5D0D69E3
+:106F0000FB50D40EE2ED3CE662AD1DE0553B43562E
+:106F10001C49BDEDA3A379A9B37DD0BFBA5E267F7E
+:106F2000A676A67C0C8F0CC0DC3F186B8782BA3823
+:106F300088E7D0EF6AC56EE6B24E97A276486D50EC
+:106F40006F1F31F45E8AD18EE07F7AD9553EEF6FA4
+:106F5000D33C488FDD95448F712617D2A3BF761698
+:106F600063F7119D06CC7CC2857ED2ABA817D0DF1B
+:106F70009AF1AA427ED4CCB366A25BB9C45200CFC8
+:106F8000F6A0892930CE669F2584E7DE9B73BB5F20
+:106F9000988AF2E8337BC82FCFEDBA7A3AD51791A9
+:106FA000FFF10A0E5146EDF9F989D319CAC1FDBDA9
+:106FB000E875FBD2187ED9ECFB600CEE73DB353E36
+:106FC0000235E89C591CA51BD2C7434A94FBF10724
+:106FD000EF48A0F57CAF5DD6CE2DC010013A27BAA0
+:106FE000B93CCED4CE35963E2885309EB8B4E8580C
+:106FF000850DDA2F6D91482E6BD7CBEFDB38BD7541
+:10700000765BA0C14FF6449D6AB0E7347B0F3AB778
+:1070100022FFF6D7DE33DA2FE38BB5F38C0256105E
+:107020006BBFC4F3AF84FDE204AA17C3BC9798F901
+:1070300039232BBF8AE83A533EF5C25498D719DF5B
+:10704000C89148879F6871D8CDC113765CCFCD5F5A
+:10705000CB24DFCCDCBD12E925DF39310DF5F9FE9B
+:107060003B2ECD3C09F597175BA9FD7693E73FCA08
+:10707000917F5FB4905E8D878F3D28B36C9077478A
+:10708000502228D62331E860E6183D9388E7A130E6
+:107090006E86EFB4343246AFCC2FE67299B29EFBC7
+:1070A000D3193EA678D04FCC1EB903FD5CD89028EA
+:1070B000CFD691E52940FE11ED079978DEB87946E3
+:1070C000833AC483E726328DE7013C707FCB0A0EFA
+:1070D000A0F2C8601AC151C11482D9C121549F13B2
+:1070E0001C45F09260163D1F1D1C4BE5DC6021C164
+:1070F00031C17C82970627111C0BFB1BB6CB0B56AC
+:10710000101C17FC2E3D1F1FBC8AE084E03C82DE71
+:107110006035D5E70797122C08D6D1F3C2E00D549D
+:10712000F6056FA67251702DC1E2E09D044B824DB1
+:10713000044B838DD4AE2C780F952706EF27382982
+:10714000781FC1F2E036AA1776C6CBF84FB0F3E647
+:10715000A42C71F1BC11AF17FD82ED71F4EF03C5E2
+:107160005C7F9B8B95F5C519D176B296776F6CD7FE
+:1071700051CCF7A114ED3CDB640FDB47915F3F8AF4
+:10718000CE63B683FC63FECAEA9C913B508FDEA3BC
+:10719000AD8FC3A22A43B2A27E7CCA0CFEBDC5EA53
+:1071A0007D6BF9794C695ABFE2427716F3F7B79BCA
+:1071B0005586FBE6F60646F93B8EEC2E09F543674D
+:1071C0009EA912F5F93D7967F6A33CCF2E52300205
+:1071D000036593C94E7AAAC287781E28B6D07C5E12
+:1071E0002D52B6E1BC47F832BE7315D48F6836B95C
+:1071F000A09AA5F82C14E749816151AF89B84B6773
+:10720000827E1F7C5AA30B68EA07F0FDED83B30B67
+:10721000B8BDCCBFCF90EF1C497EE5766B5832A34A
+:107220007E0387E761A1EBB17DEB924750DE46B666
+:10723000799F45FC46A8DE42C4F7E9621EDFCAEA30
+:10724000F04C730042A3B62ACFE2D9424E28302D2B
+:1072500001CAA377A9CF221CB33B346D00C0B1FB98
+:10726000C2CFA2DB332EDC3DCD09E50987D801541E
+:1072700003F95D9EE989502E3CAE1CC0B076517773
+:10728000607A12AE9335D49404F86C7F97791BA181
+:107290005C765A3D40EA535B871E3EB0B106B4BFF0
+:1072A000EC9E0E05E93D749D8BE237C0095C2F987A
+:1072B000BB1D29145784F9E2FC60FD51CF0F554ED8
+:1072C00013FD87FA5801909075360BFA67119F7C71
+:1072D000ACF105D0FF25A47F6782AB02E352A7671C
+:1072E00032D70EA89F338EC7B7AC2D23691F11FC70
+:1072F00006741D332F3196FE5C9F6D37D8A5F1E8DB
+:10730000FAB1A6CFFE7FD3D548CFDB343E36D25577
+:10731000D0338CF328BBB0FC46A2F2FB65ACFC1A60
+:10732000DB0D2BE17432D2B9D3C40EC15E13F3BDB1
+:107330009189617CC85D62BA28BAA696FCDFF0AB81
+:1073400091AE5F205D8BE2D3958CD141F89E2B816D
+:10735000F591F724F40CF687F3EE4BBF318A5B66A8
+:10736000EDC07C87D11A5D3745EEF3637F42BF994C
+:107370009F6E54701F12FAEDEC85F4160E4DF16EEF
+:10738000279DB338B5F80670C2AC5C1FFA03522AC9
+:10739000EE7745DA781B7CFEC2123A37633E3A1725
+:1073A000F3EAE3EFB3645705EA1B364922FB776E35
+:1073B000F95145A6F5F214F0EF88F8F9A37C67C2FD
+:1073C0000E5CCF2CB01BCCC007F0CF30C264B63BF4
+:1073D0004C7E49332BC0FD9EB9EADCB17227F6F52D
+:1073E000A85C0AFE48257F10F916DBDF5E22E9F271
+:1073F0009F288A8EFEFBED83E99C53BCD7E91C4A8B
+:10740000EFDD5E9242FD5A87D4E7D6E5C5E7E78710
+:10741000053F373F4EF41D50CEED85E4E654E2EFD4
+:10742000E4198181D87D94AF975891AF6F2E913533
+:1074300039E07A1CFCE85AFCEEB33395433AB04489
+:10744000BD3364E80EAEB7FBC7FFD3FEC5FC3FAD4E
+:10745000C4A3C963DF7230A2DCB51FF3D146CC6090
+:107460002E0FCA7539EE61787E6125FDC9D0FE8583
+:107470007232B037E66F025DC3182F554D89C46F65
+:10748000B2AD7B06F18B2D85FC830DBE4063C979BF
+:10749000F453ABD593CFC0E40AFDEAF96A67197ECD
+:1074A0005F00F2044B776F4957757B29D2B39B6914
+:1074B000E56D58FF8FC633A0FFB7F0DCC93580C734
+:1074C0000DF01C39F65CFAFB1A1FFCBE587900F16E
+:1074D00005B90821AC606C9D09BF77F896711063FF
+:1074E000FC43C8D985EC14A13FA2F2EECA17F28E74
+:1074F0007C0DFAFA6724BF5A7FF1ECAE2B4BB8BD76
+:10750000F554C985ECAED40A33D74B9A7C73F9DCB9
+:10751000C4F8394A3CBDF453C15771F452A2BD635B
+:10752000EB4E168DF7DA35FA09FC1C6EFE1D6EA2C5
+:1075300016EF5D8FF15EE037C72C46FE933D9B3F13
+:10754000C73F7DC77D43BAB88F88FB32CD5FBB593B
+:107550007BB7E32E6F327E5FA2BECCE324E2FB80DA
+:1075600059F86FC057F24AB44E1DFFC6E574F65085
+:1075700016BA0B5863D65F24A6407F87FF221334C8
+:10758000C66D67C37B68A71C96EC21BB84DF49D816
+:107590009815CF53124D9ADF181E3A1CCB05368A28
+:1075A000F31FCC2FA1BC1D63DE9D80D706EAFACC69
+:1075B0004334CEF3DA45CF3991BEDB5CD3EC59E4EA
+:1075C000F7F2734EABA6F77BF6F712AB66A706CEC3
+:1075D00020BF245E77BAD98A6AD9C5CF39999BF37F
+:1075E000CF20E7DE17302E3AA89EDBAF8359A8D113
+:1075F000E5ECCD97F79706BE2E81FEB68973C47A67
+:107600006E67B579F83962C59AC1E523A1831FF485
+:107610009C2306BEC0F64ADAEE7CE4A36D7FD9E770
+:10762000C0BCE173ECF03AF22F0ADF49F760DCBB33
+:10763000E8B90CA4C76C03FE028AF89CD1DF7596EA
+:10764000EAE3F5222F395EBC5EC40D85DF8B714104
+:10765000571FFB8391DE62FC1A6007CA13B048A46F
+:10766000F70E63D332D21BC34BF97EAAD87DA83F55
+:10767000C651FEEE115F219D67306F9AD88F87C685
+:107680009E930A7CE0794E5FE7A73571F2948A4AAF
+:10769000B9DEAAB170BD26AD7DAE06D7A126DF2624
+:1076A000D9B2A27C5ACBCFEA58B6D6BED6BB91F29D
+:1076B000BD8DE721D9A53C1FEBB0253CD4A5C54B1A
+:1076C000BD7DF0673CBABC695617215DDE0CD85C05
+:1076D00098D771245092C9FAC05BC013C81F399C57
+:1076E00076D85FCFBAA1B3DEC7FA1FC7FC354BEF20
+:1076F000F3A69EFA3A07C5D1AB0C79218B4BB9FDA5
+:10770000B04D83CCA6E6621CB96DC98376360EF304
+:1077100042CE14A989A8E74E17EDA0F85A22C52732
+:107720007AE857CAE9575577AEA83126EFADF6C0CB
+:107730002617F26D55567306DE2B60A4E7B6523E4F
+:107740002F87C6CF4EA6044A63E32BD957737E38E2
+:10775000E0F086615CFBEBA30A70BF17F115EC97B4
+:10776000E7D5F238F03AED5C03754C2C5F570557BE
+:10777000EBF4852322B1506CD9DC41715447C44CE1
+:10778000CF8DF233BD548B1769F273ECEB8D2EE481
+:10779000273B9E7BE745CFDD137353E99CFD58954E
+:1077A0004C765F428E8BBE97FE4929DF57847E1749
+:1077B000E777C6F338710E976838D773E4DACF7B72
+:1077C000AE27E61B3DCFD3D3D9389F7F2F8D737E55
+:1077D0001787AF043F09FE8AC7AF82BF8CCF057FF2
+:1077E0001DAFDB94EB41BE4AE8DBDE7C4C6B27CA65
+:1077F000C67C0371CE6E7C6F9D26B7670365244FF0
+:10780000555635A73FFA4AF0C585F22BAEB5F2BC06
+:1078100058E3F350CFB83FA0738B9B8B4C2EE4BF43
+:10782000CDF09F8A72E2B3509ED49B5FDB18DA8161
+:107830008945A687EEA2B86BF3B0EFE3FE5967A3C4
+:10784000738E30C8793DC8F9264DDE7BE2B4ED7207
+:107850002807F70B26E9CE896717F138FAE607F211
+:1078600043E81F2564DB75F59B8AAE4C0E53A96374
+:1078700036DE33B0C4C3CF17AB183F1FB4FF6DA3C0
+:107880001FF97793A5C39DEF8CD2E140CE9F1231B3
+:107890005F8749D173680FD877E1BA9281DDC4AFB1
+:1078A000FC7CD2EEE2754B8B0AE91CB21BF365E956
+:1078B0009C5F8B17332E874BB37C03713D449C3701
+:1078C00026BEAE8BDBC68BF3F637BE2BF8DFC8E7E0
+:1078D0009FC7E1F378EB1C13E7FD23EE533D7AC815
+:1078E00073B54E9F08FD23E4E18436FFE339DF9F43
+:1078F0008DE74EC79771EBF040CEF78F6CF0517E5D
+:10790000207DBF6CFFDB4F66221FB095529FF1DDDB
+:107910004942FF621E406E94FE0B022B7BCAC8C612
+:10792000D52BD6EAF2178CFA3FBE7C9E5FFE7E59BD
+:10793000CAED20B13FE03E90EAE4FB802931CAEF76
+:10794000F1F603A1FF8DFB82711FA8AA6BF1AAE3D8
+:1079500008EEC27EECA312E87E20A3DE32EA753187
+:10796000BE116F474466A1B458B9F4F07DA547AF86
+:107970005BA91E1918FDAF204BF0A2DDF1F742659F
+:107980007C19B44BF3291310FEB450F196C5E89F4F
+:10799000260BCFBB954D2CB087FC53BF2E5F776E67
+:1079A00019C7A7A582B7DB9F51ECFE0860D3FBF98E
+:1079B0006E0B8C3BBF8C9FFF1D4C3C7F5EFEBD1A47
+:1079C000FFDC837A08E55F5B47E1CFC3F4158CBB2E
+:1079D000B458FC6EF40B93CA1EEF1A09746F7299B7
+:1079E0005C124CB5B88CF34D93CB4C71D966A7B9EA
+:1079F0007227B567A4475A12958755CDDE999F889F
+:107A0000ED395E66A73E6F3568566D48AFA09D9F05
+:107A10001B18F1ACD6E63B4EB347C4BC8DEDE696E1
+:107A2000F1B896DBA72C44BA1E2C54E696115F3BA6
+:107A3000E93C91C6932FFE7B9F232581E5D8DF5734
+:107A40002695A1BFDD94589C8BFB687FBFCB5AABBA
+:107A5000D129E6BBACB5657DF053CCF7DFF43D58DA
+:107A600085877D1942A4B57B0E443E29D8B3417C5D
+:107A70009FD91BE6F795A7B9E502F12F117F02BF49
+:107A80007A43198F373522AC2865749F8EF05BB727
+:107A900098BAD9F9FA013AD179703FEE13B9B72CF7
+:107AA000A3375DAD490D13B0FFFED2F187BDE9F8F4
+:107AB000C3F3D1F1AB774627E33E21EE4131B61354
+:107AC000E7FFA2DC96A21FBFB580971FD6C61DAAEE
+:107AD0009D873FA9F1A3F097C57D1DF659FC1E199E
+:107AE000914721FA79B22C91DA3F5332ED49C4B76C
+:107AF000358BDF13D19AA2BFB7625D59C59348A7F2
+:107B000027B4FE9F447ECFE0712CB43F447C40B448
+:107B1000FF9ED6FE7B65D39EE47CEE19837C629546
+:107B2000E53EE9F84C19B707C57785E2FBAFA59BA1
+:107B300065DDF75F3DFBE8AF19EDF7788E8A721CC3
+:107B40002F5F2E90EBFA2D8674CEB13C91FFF7ADEE
+:107B5000F655A4E780D4DEFBEAB1B2BEF3DFE2E97A
+:107B6000B7987DF5EDB258FB9E79757126B1AF7669
+:107B70001BCE7F043CABAD7FBBE657A37E44BD8CE0
+:107B8000F757917E3673BF734B128F7B22DFE13D37
+:107B90001867CBF4F932222E25E251223E25E2511C
+:107BA0003DF7BD18E252DDD6EE964C58A7D36318C8
+:107BB0007DA799B27EED7E0B9E5FE5B2025CA7D6F3
+:107BC0002C96548AF5F9262FC6FD53AE76B55AA0E9
+:107BD0009CE261A9B8AC16BC3F04FABD6462169F72
+:107BE000877AD5FE4C6857D7FC47B20F07967B5271
+:107BF000D172E8ECC93FBE8BEECD11F31F3091D3AB
+:107C000027D9C3E3B0CCAED27B8A2D25FF6E16DB1D
+:107C1000CEA4C5AF958489C48F3C5E9DC2381F3108
+:107C20002F8F47CE655D94A7D66ADA4DFA656CC989
+:107C30007417B6177283F781ED8989CB1AF3900612
+:107C400069E3C4CB43DAA2C5DB5AA1BF3D14F715E3
+:107C500071C23409F185F6CD9654A487BE9F9E75F6
+:107C600031C40FE3C50B136AB8BC1BF945D1E895C5
+:107C7000ED53C64E4459FBFA9B6FE4E2E87795F06A
+:107C80001E437BC0919E48F15B87879F7B3397C4DF
+:107C9000E344561EAFB35EC20A1B3D9887EE6C9359
+:107CA00080E9D875268679BDD3B57E942A26FD2E27
+:107CB0009748C9B85E36B3DF09799135E2C1B8D3C8
+:107CC0003452DA60E907009DA63B5FFCB304F298EA
+:107CD00099CDE3BF99E9C99417B1254E3C5EE47D87
+:107CE000F5E4B9A9E3DFD1E5B959C6BCA3CB736309
+:107CF00063DEF936796E8B268E79E75F99E726F495
+:107D0000DF713970FC4EA0FF7C505AE8CFCE871E41
+:107D10006B286EE926BA5DADD159FD0BD0D91EA5F1
+:107D2000F3FCA75F20FA1DB7F0FB492CD338A92D2F
+:107D30007724879AC8DE0951FFD7D83B66621CEDCD
+:107D40000BEBE9F138EE8DBF7AF497687FAEFAAFAE
+:107D500007933049E25373C7407C5EFF704B127E3D
+:107D6000BFF189594D423BE8D3905CD9175F3D3252
+:107D700051D8E98A5302FC566BF87D02FA07BF63BB
+:107D800058F9A62DD408E3AFD9650BDB60BEABF77D
+:107D9000AE247D0DE5F7797923E9E135FBF47A78B6
+:107DA000D54F1E1CE8E1DFB30D31B969B986200952
+:107DB00056EFB450FC63F56BB21786616BD8E95689
+:107DC000C4CFF83EE211013AACD92DD759937BD7F5
+:107DD0008366B2E2BEB446DB07D6ECBDE2636496CE
+:107DE0003506BDBF228E3FF5E0442D0E52C24A90AB
+:107DF000AF813E74EF830A7891FB17CA207BA6E916
+:107E0000A73605E3BB9F9EC8EC44BFE7D4CE97924C
+:107E1000A4BCE83E20EE573AB57B54F2F9BE67FDAC
+:107E2000C3062E2C517B87AFA7671F209809C5A7D3
+:107E300039ACB7849326017DEA3B2D5E151ED73FF2
+:107E40002A2B6882315807F49F6F78F4B9631301C5
+:107E50009F1BF658D267F1E938A581D1755B03FF06
+:107E600021DF89755AF5C47356CF38FE1CF363C5FC
+:107E70007ADDB067BF15E36146BA4EDFBDDFCAFDEC
+:107E800063C3BAED7EFF32E4FFA69F7E6545BEFC6C
+:107E9000F419896566F57E7FC5C32F2561BB0BADDF
+:107EA000DFA99D03C84E38F5B444FAEA42EB780BDB
+:107EB0007E7B9941FCFED85330FE8A13362FCE7F4D
+:107EC000C5633727E13C3E363770BEFFCF9681A8A9
+:107ED000275658D4812E82FCF98AEDB7103F5E7F79
+:107EE000F416F2F381DF07994A699E83707ECB7E98
+:107EF000349FE6B7E23F97D2FCD80F2486297FE76C
+:107F0000CCAC724F1FEB3A7C12D7C71FEFB0D1E653
+:107F1000FDB195CBABFABFFCBB37B0D049DEC5771E
+:107F2000AB14E182F2393B5FA7B31345BE2FCF1BE1
+:107F30005CA3B55AB373239D8F7C364CC9C47D07AF
+:107F4000E8A0CB1F948FCECCE4EBC3F308E93DD07F
+:107F500007D3F139B6EFB2288EF1BAF734FF938F19
+:107F6000BF4E1B1FF04E9026001CD8735ED985783B
+:107F7000AC96F83BC83F981F375B9B678FFCEFDCE4
+:107F8000C4D74993FF2F5FE37A6575685E25E9855D
+:107F90002E4B3813DB85F65F2D915EB045BFCB8D40
+:107FA00095EB9D168D2FF4F58097598AA5E733122E
+:107FB000C59DD6ECBD87E2D8CB1F80F631721CE59B
+:107FC000176BF47956542E457CF27A431C5540A326
+:107FD0005E704FD2EC414D2FF4C4377F9471DE7840
+:107FE000A2F05FEA2DA1477E88F2FBA68DCEC5EAFE
+:107FF0001FB550BEE8E7BF38706C21F0FBE7BB85CA
+:10800000DCEAF5AD516E573C3E9FF525B79FA7FBC7
+:10801000599F720BCFFB94DB747E9FCD3F4DDF6A7F
+:10802000EB104F4EAF8FA36FA74FD2EB5BB0EB932C
+:108030002741F1B39FDD3082F2B90CF4157435EAB3
+:10804000CDB7277AFAD49BF0E73516434F4147C1A5
+:10805000AFAB7E7E238DD3C3C7825FC53ED6C3AF91
+:10806000C679EBE969ACB7E22400758BC96BC74FE1
+:10807000C21666EC4C447FA549DC6FCABC8730143D
+:108080003D5F19A5E5797179D7724CD9A64962FF90
+:10809000E5F227BE23B205B81E6862268A8FDB98F8
+:1080A000FE1EA1973396F37B8134B98EEA1913F93A
+:1080B0000D5DE9A58F68F912A427E86E10137E57AD
+:1080C000B399E8315791890E3685E71FC7F44FEB16
+:1080D000D8A49C1C8AE75A4DA5362FEA67684F74CE
+:1080E0009A1FE0F49CAF7C97DFDF947EA80AF3AE82
+:1080F000E796EAE578A1411EAFADD2D75FC37664BB
+:10810000A0BD7ACD0A0B0B496827E9DBD74EE2E721
+:1081100053D7B2861617E76B8D4EFAEF599876EE65
+:108120003B47D36B224FF7959D12F99FAF942E6D6D
+:10813000CFC7F22FC0AA84FA73E585CC0E7478D924
+:10814000C2F691FDAB281E5731BF1714EBA5D2E73D
+:10815000C90E4B2E35E9F44C8A92A0C33FAD32557F
+:1081600057CEF00FD6B5CFAC1AA9AB1F14B85457E1
+:108170003F644581AE3CAC61A2AEFD88E0345D3920
+:108180004BFD8EAEFDA8B62B75E59C8E85BAF6A389
+:10819000B72ED1D58F09ADD2D58FDD7593AE3C6E9C
+:1081A000F71DBAF613F6DDA5ABCF0FDFADAB2F3C55
+:1081B000B445572EEAFAA1AE7DC9F11DBAFAB2EE66
+:1081C0009FE9EA277DF2B8AE3CF9F453BAF653239F
+:1081D000CFEACA15EC255DFBE9F65775E599AEB710
+:1081E00074ED2F779FD4D55FE1F95C572FD6FFBB95
+:1081F000B96775CFD1A152811F56F1476CB6F7AF61
+:10820000BA7ECCCC4FFEA5953510B4635E23C00476
+:10821000C6FD4E27FAA100875D1EF86012F2EB76CC
+:10822000B51599EBE5B2AF86E33EF24AF955BAF3DC
+:1082300032BAC7CB0310EF534D8AC67D9222320B60
+:1082400017021F462482AEC80016067F2425E220AE
+:10825000981A49A3E769911482E99121F43C2332E9
+:1082600088E0C0C8288299912C82EEC85882832267
+:1082700063080E8E14D27B4322F904874626D1F37D
+:1082800061913282C323D3E9F9884805414FE4BBA9
+:1082900004B32257101C19B98ADA8D8ACC23981D91
+:1082A000A9A6E7399105042F892C25383A52473081
+:1082B000377203C1319195042F8DDC4CEF8D8DAC5D
+:1082C000259817B9939E8F8BDC4E707CA489E0842F
+:1082D0004823416FE41E6A971FD944B020723F3D86
+:1082E0002F8CDC47D017D946CF8B223F20581C79E2
+:1082F000886049A4936069E4E704CB223F253831C4
+:10830000F204BD3729B2876079E47FE8F9E4C893C5
+:1083100004A7440ED0F3A991FD0495C84BF4BC22E8
+:10832000F202C1699157E9F9F4C8518233226FD141
+:10833000F3999137095E163949F0F2C8FB042B23F3
+:108340009F13BC22F229C1EF44CED27BDF8DFC917A
+:10835000E0ACC85FE9F9ECC89F09F6F809E571BF20
+:10836000E7337D03F03EBCB41FF4DB9CF55CDFFD1E
+:10837000C7803F1C24FD5766F3F03D662BF1598DF5
+:10838000C6CF2DF83FD867F7977D3C14EDC5D68A48
+:10839000936FDF8C76D65A1BCF93E9A54FBF766AD1
+:1083A000F626C3FC99451ABFBE527A2003CFC35AA2
+:1083B0000BBAEB31BEB539ABBB06E165E5DC5EACB3
+:1083C00028E7FBDA8C726EE76E9B1C28BC1C9EAF04
+:1083D0001A6652D1BE5895E449BE169AB44FD2EEF1
+:1083E0006F4F4FE5B901CED3C3D1CE58ADC9D9EA4D
+:1083F000A79F3F8EFA58027109A21D24BEEFD9A78C
+:10840000A78B0438D5E07DCCCC6BB7631ED750E684
+:10841000E1F75AEBF78B0BC595F3CA030BCBFB883F
+:108420002B47EFC956FB75DF36F4B3F49FD44F7D6D
+:108430007FFAD9987EABBF0E8B66C53C1BD6A95A76
+:108440005B27261F5E84EF9D536D1E8CF557ABD7BF
+:10845000935D64ABD77F7F5C0DFAAC02F6DDEA7505
+:10846000FC7CD3582FF6D5EE7ACE67DD4A831DFD0E
+:1084700093EAA1266A5F6DB88FAB11F809DBBFD50F
+:10848000C8BF9759A2D98581FACB293E1BD0FCBD24
+:10849000C005BE6FB9BBDC608F6BFC592DEC1D793C
+:1084A000FD213CAF3E7758A658CA810C2BC3FB80F8
+:1084B000BB6FB4D1B8AC8DDB956F65FC729827C6E5
+:1084C0006FAF03BDAAE039F18DB7B991BF37B6ECF4
+:1084D000B160FCA47BD85AFAD8C4E8A7770F63E44C
+:1084E0004757AB6BE9BE4A960B1C3650B3AB3C68A2
+:1084F000FF7976A39DCD86DBE97E3FD9A43F674F08
+:108500009ACCE540C0F7302E8572B79AE715594CE2
+:108510000DF43D291B9E60E2FEA35A8FE5EBDA477E
+:108520008F443BAED2CCEC98672BFA8BB1D712C8F4
+:10853000DF31036162EC3CA33DF764798A663FF169
+:10854000EF8E4F6AF741E11F49CC83F21F152BE6EE
+:10855000E1DAD2EDDC2EEC987703AED77B3DDF512C
+:10856000C1DC8AB5FB5380E0D5EB072863A0FE1978
+:108570004DDE2D5AFE12F08F1A6B27237F61FB11FF
+:108580009385BDCBE71768B779300EDB273E26D63B
+:10859000935F1B684F0951BC36DD4C785986298B97
+:1085A000F13CC2A6027EA80FCCA76FA9C373073502
+:1085B00085E27A8166E932D44FB6F6C6B5588FF7B0
+:1085C000769953E9FE5FB315E858C75C97B991DE19
+:1085D000ED3CDF59372FD027D5ED12CDEBA4A6CF38
+:1085E0006007588CA9734B559ED707FC40E3B77CB6
+:1085F0002F51E1F8499DB8CF8BF5A9D6C6ADEEF85D
+:10860000D56D12F1393F27A8D6C6AFD5F236E3D1E2
+:10861000C9D54327E5DD377CBDC715F80A3AB5480B
+:108620003C3F5BDD2C7522FFD8D627521C40CCDFA7
+:10863000A6E13178F2489A8FA04377E3B5557530BB
+:10864000AF0F378FC65FBAE9850FE99018FE30F299
+:1086500095C5C4D7870D67E4A70BBE17FCE298CC7D
+:10866000E3E1025A270B7AC6C427E4285F1AFB17F6
+:10867000FAEDF2D8F6F0FCF2A13C1FF53D2DBE2B31
+:108680004F6E5A8CF7BC3F54AEED279E06BAA749F1
+:10869000E0838424F9D0F8D6E6B42B63801E191A3F
+:1086A0009D5B243FD141DD6C237E30FAF97F2AEFB8
+:1086B000F1D302D6624DBF9AF0B9879E57B7DB88D7
+:1086C000DE62BD3FE8B9E74A193E8FEEA1D2E8A8C5
+:1086D000F1D7AB1A5FBD8AEF17D1FAD1FDC2EA7D9F
+:1086E00036D207627DDEC32E407F7927FBC74E2E30
+:1086F00022F91C4F7A7F3DFFEEA6C6B43F07CF4B51
+:108700006BEE0A138CEA2D4EB7CAC1E21E1B2FE591
+:10871000AFB08689948720F264CFB617D1796620EE
+:1087200089B793CC81122C57FE7D6909C67FD98900
+:1087300044FA3E67D128567B659E965F08F82C6AFE
+:10874000BAA212E7395DA3DF2BE0A72BA3193BBA2E
+:10875000C1CE1460965737B8A8FCFA063795DFD813
+:10876000E021F8E6865C821F5A397F2C4A1379DAB9
+:108770002EFA0EF20A4D3F5ED1C3FFEBDCE87757CD
+:10878000FEFD55CC4862E9EAC38B674E267F9452C2
+:1087900078049F565D3D403B0CE1E53AFF245D7D4A
+:1087A000B796FFC0720BA3CF4772BE40FE5DD29654
+:1087B00045E76C0B66A5E9DEBBA66D88AE1C98CCC0
+:1087C000D76B5EE528DDF385356375E53AED7B68AB
+:1087D000E629A5FD4AC4DDC012E5F4D7F28E6E5E2F
+:1087E0007B79F26D30FECD4765AA37AEC3AD4BD570
+:1087F000C588DFAD0FD9BCF83DC2D2AD1253D388C6
+:108800007E7CFF382693DC5DB755660118EFB31404
+:10881000253319BAFAC4C1E7F5C9EB7227DA0B950B
+:108820007F1FC5F7A7476CB43F7D6261AA8BEEB18D
+:1088300092487E3F3B9A43DF752C1A151E86DFB5A2
+:108840009FFE6F079D0B2EEDE6E331A980E21F9F8F
+:10885000A4302505F8F2F7B33B9653BEBC7C380331
+:10886000CF7B7EFFB84CF779AE5CFB7AB10BE8BAF0
+:10887000EAB7BB8F618ACB871D327361DC6B97AD22
+:10888000937F27AD64A23C44E7191A8F7CF9E24438
+:10889000FFC6C9B0DE9F2D0F8D277F7F7D06B717DE
+:1088A0000CF4F8D01A28C178BC8A7C09FD056E4DFD
+:1088B000B4A31FB7D4E21D984F7CC4E37E2AF30D06
+:1088C0006214DF7D9CF8E7C3F69CCB483FB6490CA9
+:1088D000E3E8A27F90A73948C70F3BD24CB8FE4BC4
+:1088E000DA65FEBB2DCC6325B915F7E6DC2707C09A
+:1088F00006C1F7033CDEA45F4790D04CA4DBC697CB
+:10890000F93D138BE3C41BFF00B213888967ADFAEE
+:1089100035BFEF88F93CF796A31DBF737A11E55D6B
+:108920000478FF5FA60ABEE1F73C9D51780AF7B9CB
+:108930009D8921E48753A6C7DF35C33A9C3605F6E7
+:10894000A07E583147DD8EBFCFF3C5D327FF1DCFA3
+:10895000113E7BD4E2C5EE9D4C799CF44790DB43FD
+:10896000E2DC7AD5CF1CC4277F1A766927AE5F5424
+:108970007F34F2796BED19FE0216D1333C50027A46
+:10898000063CEC32B2FFD86E2D3EC3E9E441A48030
+:108990004EAE7A1E973B599478379B00EB63B087B5
+:1089A0004E6AF2F8BC26E742CFD9A7F0F252B1AF37
+:1089B0003CC3ED2371BFD00AC6E921CE0B563470FB
+:1089C0007BF638EE6BF0DE9A86CB3FE671312E1FD8
+:1089D0003700DFE1BA2E77A5ACC3FBA3EA7739BC39
+:1089E00021787FE0148FB64F8066063AAFD45EB927
+:1089F0009E85DA0B60DC1B7759BC619A96B89FC8DC
+:108A00004CFAE233B01D4B53B13F89FAAFEF9042BD
+:108A100018BF4A2E6FB022BE37EC95581A8FBB5143
+:108A20009C4F7C67BFCABC99E279AB7225B297D9DB
+:108A3000AE98FBCEA1DF1B77EBBFAF5F63F8AE7ED6
+:108A4000999DFF2ED93266B84FA0C342FBA59DD990
+:108A50001BE93EF9018984D7AA0E6E7747F197D9B1
+:108A60003740D3E581D06FE7101D246F88F5C663CA
+:108A700066FA5A9AC72A9C47566FBC8CF3EA2F9E17
+:108A8000CBBDFB895F8CF8C6AC8347BF0E5D14A7D6
+:108A9000FEA8C1C2D05F5CAE727E58FE34BFAF5D2F
+:108AA000DCBF6FE4878FD21BE8FCE6A31F49AC2331
+:108AB0002BCA1F822F56EE095971FFFF9C7524396E
+:108AC000416EEAB7EEB9A60CDEBFFE4747AD684F70
+:108AD000D4A486734C294842E78F2B8745F97565E6
+:108AE000484F871B76E9CBFF2C3A312D5E4BEF01C7
+:108AF0007D96ED94C9AE8869A7B38B98DC6EC5EFFF
+:108B0000CACE85242FEAD715788D47C1C5E3BBA609
+:108B1000E73E827F2DDE46FFEEB229FA7BE6CF34B8
+:108B2000CCE7F9BEEBFBFEBEDB78DE62DC5FDFB6D6
+:108B3000F07C9B3EF6D9B9C817B0CF9AF0A3C578A0
+:108B4000FA79B9B6BF2EC3FD14E0EFB63E9184F1B9
+:108B5000BA8F1E7862209D23E17E9417BB3FC37EAF
+:108B600089FBF3AFF8EF26D5FCA72D8C71ED537B75
+:108B70006D2196D5BBFFFA89816553106F6D3FFD5E
+:108B80004C3A5A8CF763093D1BEFFCF85F35DF2543
+:108B900038DF42B42BF87C3F68E3F33CD9CEE77D65
+:108BA0005DAFF9EAED914F1C61DAFF3FD92333B491
+:108BB00033845D21EC0431CF73AC633BDE6B76E331
+:108BC0004D6FBC6B06FE587949D778FCDD829AFB65
+:108BD0006C641FACFCEF44A2D767524526CAE7A9D4
+:108BE0000E9B823FF5766A97839E47F1E8B1173670
+:108BF0004F89B517FA493F1147923C2E9E97F123B2
+:108C0000E641BB13CF5DF0BC83394DB4DF18DF3FC5
+:108C1000A8ED4B37CA26B257EBADDC6EFD42F35BD5
+:108C20007768F53BA670FB75D714F1BB84A7B72313
+:108C3000BD8EFEDAE6C27DA8CBCAE3CE472DCAD6EA
+:108C4000EFC1BC664C0DFC640AEC9B7E937311CAA9
+:108C5000CD5D03C65B500F35A72CA7F3AAC5AC8B1F
+:108C6000EECD9A533ACF83DFEBBD3BD0EE9549FE74
+:108C7000999F1547E33C2F5B783ECFBBB8CE30AF12
+:108C80006AED1CE35D07A84D18FFDD4156CA23516C
+:108C90007F6DA37D7963028F33B3F464BA8778A1C3
+:108CA00026EF8B66D814D493D53336FA11427F2A37
+:108CB000037AD5D84FB7E4C3388D26BEEF35A63238
+:108CC0001E876AEE2E42FA4D60CD2ECC6781D9EF19
+:108CD000FD26ED7CEBA0CF27AAC7B8D644C617A8BF
+:108CE00094E8AB2BD75B79FD8929CB6A1F180A65FD
+:108CF000B4D9D13EBD420EEDC8C2F8B989D6732EA3
+:108D0000E6D9903DEBD6DDC77725FC570EF3BCD2F4
+:108D1000CC54532AC13627C0F9A52C9C0CF30BBFA9
+:108D2000A0CF77BA366C0A8FC6F33173783FE5E38C
+:108D3000C8AC054DE42B5996E526CC2FB8AB7FF88F
+:108D40007E39A5A1F68172289BF8F7DFA76F97E817
+:108D50007EB8C56676107FF7614DAA47A5E76B25FB
+:108D6000B2B3AB4198F0FC17EADB920AF03D89F808
+:108D70000BD797E70FF1BC2BB14ED0CE9E00CFCFD3
+:108D80004CC922BBAB5AC3776BC03410EFCFBE5176
+:108D9000F3AB16DB5933E6E981FF9784719D7C4084
+:108DA00033769DD65885FFB5DB8ABF8777C3D3CF8F
+:108DB0001FCF02BAFC5DE3E71B44BCF517FA78ABA2
+:108DC00067AA87C6C5DF7E45FEA8D6603CF918367F
+:108DD00095F7376C2A970FC754E1DFED26BFEF06F2
+:108DE0002DCE1B6FBC1B6D2C4CF4FAB58DD65D8C53
+:108DF0003B578343A6F2B886C043F0F97206F6C02B
+:108E000028847C1F33C162525E50C7439457BAE234
+:108E100047FADF9D010385CEB957ED343E8FD90760
+:108E200075BF1BC5E3F092F5F475889F34C5E14525
+:108E3000B9A8B6EE267F5C020703F96B799CF72C84
+:108E40001DDCFFB2B473BB86E22C3E8CD748F4BB6A
+:108E50002E7543BD6ED40B4BD21B685F1576F07236
+:108E60008D0F6CDAEFB92C473B07E37568E720FDFF
+:108E7000B672FCCD9ADDBAB443BFDFD7B519E7C7E8
+:108E8000F77D4B4FBFFADF87B168FB7E93C5EB469A
+:108E90007D6B61FAFDBF49E2F35033781C88A5F37E
+:108EA0007AB366E709F99F30D5A2BBE7EE1CFBDA7F
+:108EB0008CEB20EAFD33189B52105F7FCC55068463
+:108EC000253ABFBEFC10879BBAE8FC59CBC79EABC6
+:108ED000C93B3C277BC65F29D1EF1ACF552C9FC5D4
+:108EE000CE57DC2365B447AAA6C6C9FF284FEB5767
+:108EF000FE87C85FAF41BD4DBF9FC7E3D53745CFA4
+:108F0000A773518FD748095EB4CF45FCFF6D0D9E06
+:108F100069E0DF43D5BC03FBA1D4FB5CE08B8A4452
+:108F2000D504B026C96AC6755E947CEB1C84E2BC8D
+:108F3000E06D0D7E65EAA6F16B59F7E798677D79DC
+:108F40007A57222E4BCDDA1CCA536BAD28DC0A3679
+:108F5000176BFACDFE5AFB303A8DD4F2268FBC87C0
+:108F60007983577F0DF3A3F2CBB50A8EFBDCE9C5FD
+:108F7000F8ADD44F7EF372AD19E8F6C583A7B76399
+:108F8000F937BF395E6B06BA7CB1F9F4700795DF2B
+:108F9000E3F58D5A7FEA7BB5D8DF173FE0E507A1FF
+:108FA0005E257B259C837498D3E0F062DC41C4AFDE
+:108FB0006A4CCF1244C71CF594909B3FE5FC917E10
+:108FC000AF1234C025A82FD624842D99A80FF6708F
+:108FD000FD79E3BA8AA40A867CC9CF65B768FA4BE3
+:108FE0005214D2AB36E82B01F8E3C1299ADE32ECF9
+:108FF000FF2C0FF0F145F1D988FA2DA3375E2F4CE5
+:10900000F56F9C5A84F73F7E48DF53BF57A15079D4
+:10901000DBE44008E1AA79926AC5DF167F2D7489E6
+:109020006657909FBDD1A4CFDFDFA8E941019F51D2
+:10903000A0DF8CE8FA407F3FFB36FDCD52389EA280
+:109040003F41CF651A3DA1FF5FE278FF68FF42AF65
+:1090500089FE0655F4C2FFD96FD3FF7D86FE84FDDD
+:109060002AE6310E6D3458E7344C5C2E8AE2239E9A
+:10907000B748E18C6B313EF6824CF1AE968CDF99AD
+:10908000F11E05E69FC4ED640797C78FA6F2386C02
+:10909000CBF7BC1487538FF0FB025A32AE71A33D5D
+:1090A000F8F9A3D7A751DC4AB32F3FDFFFA615F38A
+:1090B000085747F8FD006B22FCBE80D57BF75B2F7D
+:1090C000C3FC2280D363E21CF5D17B88CCF87D8081
+:1090D000C0E3A3A9262D0ECEE32CEF62BE505E1F87
+:1090E000F692D2132FA7798FD7E6F7E20CE5D4D406
+:1090F00098798BE7E23B2F633F33152E0F2F4E6598
+:109100007D7E77F6AF82FF0F0CC68CA60080000034
+:109110001F8B080000000000000BB55B097C54E5C4
+:10912000B53F77EEBD3393649299908404B2304397
+:109130000043D9862C102081C94A2C0407700910DD
+:109140007482B288406244492BFDCD404090F27C4D
+:109150007179155B6A278816ABD5A860A945980474
+:10916000A4C1756AEB93F7B43050AB6C4A047DC66A
+:109170004AE59DF37DF74BE64E12305DC28FDF97D7
+:1091800073BFED7CE7FCCFF29D7B03A0B83E3603B6
+:109190008C93002ECB00D5D1708BDB0270EB845802
+:1091A000B37D1CC084A3EE92D84480A5DB1CD9B249
+:1091B0001D2050586C72250148342FAB7B5EC56072
+:1091C0008020CE03A56320505B37D9001300EEC288
+:1091D000B5E9E7E2BE3C2B8CA6DFF87E4E9A978974
+:1091E000FB0D08AE86F100652E8BDF5C0830E35185
+:1091F0001C32984D71018EAB3069B46FA8A7340D45
+:10920000E96F654667B9D2FC3E5CAF9DF8C576E173
+:10921000C431D1301620E48831D8ACD85F5853E639
+:10922000CAA3E785E5F4BCC8143BA2C6C2D61DE1BB
+:109230008EA57EB783FA693CE039ABEF5497009E68
+:10924000F3822F0A640780676C8CC74FEB1BA01456
+:109250000620AFF4330D6088CB009044FCE24A79DD
+:10926000DDFB8B7D711FA0753C0FA536D33ACEC2B6
+:10927000A252DA47ECEB2CF48C27F9897DF1986344
+:10928000E9795FFB8B7D453B96F6C7F54A697F5CC4
+:10929000C75D20834B93F165FC3FA73446475F3F92
+:1092A00033015C59DDF48DD7A7EAE8AAEA4CDDF872
+:1092B000F9B78DD2F5579A82B975966E7D0BBD417F
+:1092C000036E3EA8277FA2458531FECA674B3E2B21
+:1092D000CA25D80A6376E3F97C8E58E793D87BC712
+:1092E000E66B017200AC9D0B58BBA209E9048095A6
+:1092F0009D7319BDAA3386D195A90BD7431CC939D3
+:10930000580EB9D8BE1C0F8DC8C33B7260C4CF685D
+:109310003D13AE87B8AC7C7E7A05E979D5EE75CF82
+:10932000D238B0C7E40CC7719532B44BA8BFDACEBF
+:1093300028BE9EFC6EEE9D28D71925B13E8395F57B
+:1093400003E9B7312F760BE9A35185AA965EE4BEF7
+:10935000C22531B9AB21CE7759E76CB69EE8AF771D
+:109360000D65E715B49AB4535964E93E8F1A9258C3
+:10937000FBFDCE51ACADDD3D5BB1E33EAF673D9152
+:10938000E8B1B0F1166AC13D456F377513AD644F52
+:109390007DC9D9D489FA473E16744AE0C2757DC5A5
+:1093A000AECD84AF596B438A19E50316A3ED49DCB2
+:1093B0007A56FEF8942561EB34B6CE033BE2CE94A8
+:1093C0000846173E5F806D4958BF0781D9D2CBBE92
+:1093D0000F68F80358C7DA59DA3848FB1688EF9B4C
+:1093E0006D9C6F818F7BB5F1627E1079219CFBF6BD
+:1093F00098FCC4D763C59E66B28F601154BDC8FC8B
+:1094000047306376ECBF8E7FD4AF99F41FA7F07D11
+:10941000E3F21D3B7C685F4F759D83E3F46AE77858
+:10942000581BFF8E0C0D848F77A64D0BBA70BDD6DE
+:109430007B7372C82F82ADE312E1AE76FF94CC2D20
+:10944000C8EFCB2E231B5FBB1F71CC9E9BFC12EE83
+:109450005B99D0F131F1D1F16A947D8783CF231CE0
+:109460009FC7CE2DB88EB1CCF332E9AF76FFE91CA1
+:109470000FEEE3DAF7D5B17B71BECB12EB24768E1B
+:109480004C73FD86F9933EF8BC9A3DF6C49789D992
+:10949000E5453B5FDFB399DBA147B3C71A0DBF8B2F
+:1094A000347B14F6AC12EE72087F1C772B3AE3F98A
+:1094B000784DCEB764497E92F3CA4E079B2FEC7865
+:1094C000D15A69C436B24F25D639DC4EEB727B10C7
+:1094D00076BAAA334167A7C26EDF2BF67C4C72E9DD
+:1094E000B2DB46B4F7B8EF8293AF15FB18E4B74090
+:1094F000520927266C4BC2ECDBADE9BDE63689E9A3
+:10950000A906F1015277FFD97EE2FDA8367E9125AA
+:1095100030DC80EBA97551CEF5B85E75929DF9AF40
+:10952000FAFB914091D4AB3CAED63F263951332C57
+:10953000DE8295E26D9DD113C6DFBCCEB16047F9E6
+:10954000CCED1CC6DA40A1E76BD27F4DE78D9A5E69
+:10955000C6B216ECF9061808B09AF44A78847CAEC4
+:10956000678DBF2FEA2626AFC1FDBF785365FD7911
+:109570002EDFCDC48FEA37399B919F53511E99F44A
+:10958000762A1D6C0F238BA754F0D9501FB76E930A
+:10959000C187EBDF86AD07DB53F1E08ACF26BBC383
+:1095A0007386C5892F95A60CC0B8B0B2FEFD630ABC
+:1095B000BAC2DB4704C70670DDEAA240D24DB8EE5E
+:1095C000B99DAAD387FBAE687D778201FBCF385C5B
+:1095D000C980BEF7F5C99E842214DDF239FEE75436
+:1095E000A4CF36BDF4DFF9F66E795617C30CE2ABA3
+:1095F000BACDC0FC7ECB56B9C2CFE378CCEC31619A
+:10960000B8D6F28A23C0F31181D3E59D994C3E224E
+:10961000DE08FFFD1B6F0A1EA2DB8FF7158722ED08
+:1096200045C4A58B75EF97135F17774B141CBBF0E0
+:10963000DD1D87246657E8A418CEBBE30FC7B9F039
+:10964000DB95B281E1AED23AC4DFE8E8F6E391F10E
+:1096500069CAD399BB5FC175963FB3D04DFB4E1B12
+:1096600025818CFBAE787150AEA7173F2DE2B590E7
+:109670008790CFEB1A3DB5D8555994F75DEC27CAC2
+:10968000C8FCAC6F36303F8B6DB89F55853D404868
+:109690009913DBFD7C4E51FFECC6A58D177C0B3E6C
+:1096A00083469E5F09FEDF009E7F887D1E2B9E7392
+:1096B0003BE187E206EDBFAA88C7E97FD5B9FA8A00
+:1096C0001FAB8AFA173F16449C4F9C439CEB4DED11
+:1096D000BCDF35BE341619D9BEFD8D2F8419961FF7
+:1096E0004559FD4F62FFD40393BEB8D74E71C6A44F
+:1096F000509EF17A69496351189F822FC1E75B1A26
+:10970000DF1887361785DD03C4F37F342E097B8D80
+:10971000B4B748FB8DB4DBC87C51D84DA47D0ABBDF
+:1097200016763AE3C73C1F854C9E8F0ABBC57C9ECC
+:10973000C9A7FD7BF17EF237AB683EC391D51F9E72
+:109740004F8AF85729EF786032D9EFF944672374CC
+:10975000C74361B7C38A3DFB484EC5CF7CF3D2FFF8
+:1097600042B7BD5E1D9FBF5559DC5A21B1FCC6846E
+:109770006D78DCF2F46177ADFDB4BBE78BF87DE684
+:109780001D99E3DB6735B2BCEC6AF8FBE3BF0F7FE2
+:109790007F24FCF595871F25FB4E62F83BCAECFE43
+:1097A0005F9607BD9F6B47BE2EE6621EE4E8C6D1FA
+:1097B0008C371027B9DD38E9C287315DF3D7DC8FEC
+:1097C000CFB80C7524670FE93F2C4FFAB6D87389D0
+:1097D000F81478688FF68DA6BCE6BBE6B70B12EBE3
+:1097E000C085E33DD886FB2713E975744FFD4BC553
+:1097F000FDD3FFF9A2FEE5B5F1C5FF705E9B569C57
+:10980000D7775E0B2E9EBF087D3855A7750DCE7796
+:10981000BE2593C6FAD4A7BC8DCBBB4B6E0145E4E5
+:109820000709941F204ED28BFF099C5496B47C618B
+:10983000C6D4764AF1E01A6512DE9FF341AB4FA41D
+:1098400036BB86313F0230999F80EA15CC8E189D39
+:1098500076A294EE990F77F5FBA8BFACC0DA55DF7E
+:10986000205310E327170F3AB195F1DDC4F5E7094E
+:1098700029EE3161742ED2B161747E04BD9D8F8F4B
+:1098800053426063EBF8D973C29D94CD71C2D7EB9C
+:10989000288F47B9CFDA2DD9482FF30BCE1BA92E2D
+:1098A0005359123A9C8AE7AC6C1B5A63C154653E0B
+:1098B000F93DE47361DBF79A7D8A260FD4CF0A4D18
+:1098C0007CA616C925A37E56E44BFEA18E9EF25BB4
+:1098D00058AC8F8FF4A3E8E78331B77FF3497F6CEF
+:1098E000FE50363F60EAC7FE371580CBDF4B9E74D3
+:1098F0008718770969B13ECA6C2E9EAFB7FACB5D67
+:10990000DAF8A0C1B012505EF7B64D6D36A7A35E6F
+:1099100081E3E2476D85353E8E3F70459CF74AFCFA
+:10992000D6F4725EBB7E7EE04AF25ADA63BE868B64
+:10993000657A9C94155C76919D9615202E288F71E2
+:10994000476DA57B476589866B5F458D2B0DCF17CE
+:1099500005BA3A5C17AE7DD7D610AE5781183FA333
+:1099600099FC93DBD0359EE37C9FD4353F0BF143CC
+:10997000A19DE63FDAF6FD66AADBA13E583FA3951E
+:109980002BE0BC25822E88B00B0DD7CC2EC94FA35F
+:109990007C864B3DE5F362318F739F4A3CAE048B6E
+:1099A000795E191CCADB778B795C794593639BD010
+:1099B0007374981CD2BAF58C3F01BAFF849D9BC981
+:1099C000695EA238F7ED3533D13F0407C01809713D
+:1099D000F266F1E2E60D8534DFAD007A3C0596369D
+:1099E000BF89FE679E2697778B979DD07023919DA8
+:1099F000AD640040BDEF967C329E6B25E9BD977348
+:109A00003DDE1337BE88F92EF50AF377F69CEF8A10
+:109A1000980F6A627FE66B7A9919A1B78A08BD959B
+:109A200046D0D582F6EBFC96F067F39639EE4B45BF
+:109A30003E963F2B310F8E7ED9288D07F8A4ADBE00
+:109A4000C63289F0695753B1E76CDBEA1366C4EE9E
+:109A50006CF25F0CAF77333F3D97EC9BD1F7D4B8F6
+:109A6000AC8497BA8D2938FEF3B635CD66B483F948
+:109A70001B1E5401E92FDB7ED0ACA0BEE6E53E7F85
+:109A800098D653D6DD7B62A6E30AF86C8A38C7F60F
+:109A900008DA1731FE91ABF8F10D11F3D746F46FE8
+:109AA0008DA0B745D09B23EDC3563E90FCFD060923
+:109AB000B6C0D5EDC45422F2C1965C339EDF7A70F5
+:109AC00073F3464CB96734729CC797DC5F138E53AF
+:109AD00015F8CF8244F0513C50FBF04F72491F38CB
+:109AE000C98A8C5BA2DF9D42CF8F69F6811A5944E7
+:109AF00079F0C1AEF8CAEDAD55E67C0D2E997772BE
+:109B0000039BCFEF290F69EF25F61B6019D93BAEF8
+:109B100053F1422FFEFFA1527E5F3CF8CD99679E24
+:109B200047B9F88618D97D1D338F4B1D789E93E970
+:109B3000C63C8A93627CEB106303C59156933765EC
+:109B400071587C383864E0A51A9C7F30196C14D7A2
+:109B50000FDE9BC3E6FB6A65E770A4F7677CFC1F1A
+:109B60001391DEBF4ACEA17E314F5D21B338A326CB
+:109B7000B6C42E0EE3EF606D4E813DECDEFBA556C4
+:109B800077FF20ED1E1BC5EBD621AB8345C46FB21A
+:109B9000C2F8357D5D6D93F079898C7928B59A1E70
+:109BA0008F75CE0F0671DC46CB50F254F89CFBB992
+:109BB0008D69379A699DC64403CB97D4D88536639F
+:109BC000D8795C890AE7CB01EEF03CFC754D8F3FFC
+:109BD00029E1F97F9B6C63E7463E6C5487BFE59BA8
+:109BE000EAA341DC47CD9860071CBAA724938D3BBC
+:109BF0006EB015507DA8440EE540D87D729E41BBE5
+:109C00003766A1771DC8F25AEE77CC5B83F258A273
+:109C1000155F88D799CC974970182B0C13B471062F
+:109C20005D3F5C46DCA9060DDF19C0EE170CA8B439
+:109C30002ECDC57DF14E3796DAC5255CEF9447AB46
+:109C4000548F4934BBA2E83D83566FC0DB48293DA1
+:109C5000AFC0FD14BAEF49280792533AAC9AC370CB
+:109C6000D6A292DDD56BEB887D16687C2D40F9D1AC
+:109C70007A0B14508CE8C76E49368EDD8BFA0F597B
+:109C80008C4E8297782EF65BA0ED778BCCEF11A6E9
+:109C900015AA2F14F65E46F0B1BE249EC9B3F14753
+:109CA000FC3D5328C3EE07ED9C72B85CD6C6BAA241
+:109CB000E87D580686780B3B0FDB6F23C53FA22D4E
+:109CC0002FAF91E2BA9F87D64F49A17BE946519FBA
+:109CD0005F29B17B20D99991CE45BF0FA573195D3E
+:109CE00023E95C38DF3136CC6F44F0CB6A90429F79
+:109CF000993DF5349D6873DFB4A82B087C0C2805CA
+:109D000026E7D62103D732BB4A3633DCEFFFDB0F21
+:109D10008FD6207D7CA099DD57BAEC3439A5C04E92
+:109D2000765A9BB0B623CC4EF6FF6DDF5B1368FE10
+:109D3000402587EC72EA3797C6DC4AE39213D9F8DC
+:109D4000A9DEB3677F43F5EB6FA26D121B3FD94EBF
+:109D5000F715D91062FE01FE16CD705E62AD4AB1F4
+:109D600087D9C5AF35BB5A59E07AA604F9940722C2
+:109D7000FE2DDD7E4C1E78A387ECB5319D99216CBC
+:109D80004295925D356AFA10EBECD1EC768FB61EF7
+:109D900028F60C9ADF26735CFB36490CD76AD2DEB4
+:109DA000D8F0F74287351CB6C658B97FAA4DB844DB
+:109DB000E7AC49F318257BF83899AD6B325B997D98
+:109DC000B79AA679C87E6B2C37AAECBE87FBDD80DC
+:109DD000FBBD56A2B0F51AE379BE74DCE0B6931E63
+:109DE0007F56E0892BC5E72755CEB7CB168C95E873
+:109DF0001EB73A21DE872C4CD5FC4FEB10A5213C39
+:109E00007F3EA6F1774CF31FAD43EE617A137A6C77
+:109E1000351D607A51075EEF94995ED01F931EBC8A
+:109E2000314EE2BF35D9CC70D99A6C64F7CDD65A91
+:109E300099CBC36A66710CE31CC3C5D46485F9EB86
+:109E40003D2576DDFB38A1DF36B9EE28F75766767B
+:109E50009FFF6045C225D28BAA5A6D74FEE3868EA1
+:109E60003CF20F7B4A06303E65833B05C2EA74F341
+:109E7000BBFD550A4CB8A2BF32128EFF597F85F345
+:109E80002A54B4CFBF097F75153F453FEA845EFC75
+:109E900090E6E722FD8D98F7EFB2DFF911F62B9EE1
+:109EA0008B7826E4FA7F5D34A25AF08F3CACBBD3AA
+:109EB000C4E4637A44F6934C16A4B94E539D0E360F
+:109EC000A41C1A86FC2DE15BC249C91D7C9FF0844D
+:109ED000F6457A5D52B77426D5F9362596DB8AF0B9
+:109EE000F9A626C9C9DF8BC05605D7BF559BB72435
+:109EF000F7CE11B4DE5DA5FCFDADE794AD3C0EC719
+:109F00001D4B9BE35E9748AD0284BF03DFCAECBBE9
+:109F100088828E608995ECCAC7BF8710F8F29C537F
+:109F2000CA299ED680ED3ECA638EC73554D0FCC682
+:109F30009F4BEC1C27A5BAC31EE20F69F21F8D7759
+:109F4000C7C6D1A5684AFA9F2A292F98F25F49AC63
+:109F50000E720CEA82C4AF6FABCCF0D9A8C2A1419B
+:109F60008457299EF99D236AF02D07F61FB93B817E
+:109F70002A3CB044814306C4C7D4526E570BCC96DA
+:109F800000E190E462C6E70B51BFC6014CDF3038F8
+:109F90009B92265E376A372032B3A96EC3F1505ABE
+:109FA000CAFD0EAE674EA07A81BC2F8FDE5F0B3FDD
+:109FB000A5C4E7B2BAD0677B174F20FB5493AEF726
+:109FC000D0F9CEEFBB6302C9E1BA52EE57EEDFFA29
+:109FD000909BE165EF3A1F9D679081DB61EDE64D57
+:109FE0009FCBA88FDA7D4540FED424F1BCE26AEB1A
+:109FF000CEA775F15CF737E1BAF27758779BFA5143
+:10A00000388E1B1F8B324BE3006E7B24E2B9565F08
+:10A01000ACF1E99F2FD8AAA77FA4C905E46A6B6FAA
+:10A02000EF5944DBF0E1BA0D87C2DE87AD2CB524D1
+:10A030007E3C0A7F99081359FDFC2AF3BFF2FA36D9
+:10A040001C52693F6E27E08CAC4FAEB1919FBD882A
+:10A0500078E4F1BECE4CF4B134036CE9258F0F796E
+:10A0600051D1683AA322EC4ED8D941ADDE7712E344
+:10A070000FE5C5078CF6D5E45F0F44A74B3EE64FCE
+:10A080005B12E83DFC560D57078C3C8F46C60AE62E
+:10A09000627C384079B585FAB9DE7F772EBB80CEF9
+:10A0A000B7BF33BB6051785E2C879E99C8FC34B72C
+:10A0B0004BBC4654BCD48B1C1C5A5C127C8AFC5D85
+:10A0C000F8878735BE055E23E73F5DCAE365C8DBD9
+:10A0D000007F19DEB34E2EBE633225DA75763B6CF7
+:10A0E0005A71736952B75DC0C179E0A0FBD3DA1C25
+:10A0F000561F7C5AD33FDA6E39DD3F20C59D125E74
+:10A100006F7D6B9AFEBDCEC35D7EAC7FF797B7A621
+:10A11000E1FD252CDF7F503B7F175F9790423CC8C5
+:10A12000DAFBDD6AFA2E09EDF4B0C65F79ACC14DF9
+:10A13000F176C6A38127593CB92B2A9BE2498509B0
+:10A140006E996DA1EFAC02C3EBC3E4765893D78C44
+:10A15000FFE4F11AEF77ACA5759A2DDDFDD5C57C2E
+:10A160009EA0C539057F6F4DB369F7D40400BC8745
+:10A1700097C6FCFDA520CA794993C966423E3FA215
+:10A180003A12F9B35779DE7201CFC3FC8BD96EA5B1
+:10A19000FBE2474772187E57B6CB274C68C7871E2D
+:10A1A000E4FE7EF16EEEEFA9425C897E7E99160F89
+:10A1B0006E7F44F299D0BF2D23FF3E96D16CDE9284
+:10A1C0000FC119C0794BFE243BED34CEAF9E0CB7C6
+:10A1D00063BAF6D2BA4B5B247F40A2EFD9F4FDB547
+:10A1E000B0F573F29B2B5B229ED74DFF84E2482D86
+:10A1F0002827C3E3DF71E6847ADA3DDA07D3FBA7C9
+:10A20000A5B1DCFE9DE0EC8FFD5BC07591F028E40C
+:10A21000B948D1EAF74A20E926CA1F8F2464D33D02
+:10A220001EEDCF9CCFE2FD3A9DFCCF7911F1D7A076
+:10A230003FF52E63EDE4DD0FCAA976AAC39F7860CF
+:10A240000ACEEFF8D4E0DC0134AE8E05F7CFCEE5D0
+:10A25000B27BE66768373CD8AFD7EE337ED616EED2
+:10A260006E955381FCF35F62D8F7491175FA8B75CF
+:10A2700026A6DF8BE714ED1EA2FFEE0005904C75BD
+:10A28000FC036FABEC3D8090DB991F70FF24703DA9
+:10A29000455B6FA9F69D41EB3309FB26136E62AC5B
+:10A2A00036CAD3CFEC92D93EA7CCD6A7A81E736AE4
+:10A2B000FBDC818076B858ED303A912FE7ABB3E301
+:10A2C000A80EF9571C1760F2F2CB148F2757C05C09
+:10A2D0009A3739A0801DE7FD55714A8483CF3E022D
+:10A2E0006842FA2CBD2FC0718B7FCBF34968559A19
+:10A2F000873BBAF92AC9D78EA1C9B7B28CDBFB2735
+:10A30000DB5F9A45E34FEF546DC4CF673B55367F13
+:10A3100039E2D680F83AB58BBF375CBE4FF2476161
+:10A32000FFE95D12C3E772C4A719E5B0F24ED56527
+:10A33000B4F6C47709CDA3718853C2BFC0F9729730
+:10A34000BF9CDD27345C9BF1DF654C59E2A1E53E03
+:10A350001BF27FC7AE7F0ECF91382E2BD3F09B0D13
+:10A36000D984DF0B753758036172E80BBFE730EE15
+:10A3700010EEC4F384DD0E2995ADEA63FEC3570CDD
+:10A3800059F43D61A311B214D2AF21DA497EE1AB99
+:10A39000A8B8B1940F359879BB263A6E07B55F45DA
+:10A3A00065F889DF35B2ED357A8FFB4E9983ADF3D1
+:10A3B00095C1AED23D606E62A894A5CA250697816C
+:10A3C000DEA7359A441E6D269C0635B9BA313F4F3B
+:10A3D0004079FCB84CD4A180E1B8DEC6FBCB640B5D
+:10A3E00093FB852A943BCE577C231F2DA0FB48BBB3
+:10A3F0000A7E9A0F5DF9ADC4EA1060B7D27877BBD8
+:10A400000C5B683F17CF9FED605E477AB981FC19FE
+:10A41000DD07520C600F937F943D1AEC61727E0F42
+:10A42000DC56F2478DDAF9C1E70A525E5BA5F11DF1
+:10A4300093354037BECAB284E121D63958B72E7859
+:10A4400078DE62C77FB4FF2C7A86FC5FE7E2FEEE1F
+:10A45000862AEC0F5B67531497AF5AF039939F5BD2
+:10A46000C38B5AA0CF7FDC69E5A749FE78FE8FAE8B
+:10A470008497E872C44B0CFE3212465EE67516EE07
+:10A48000F793C4BDA60EDC6171F3E1327E9F59568D
+:10A490006E67FA94730C2CFE8454C818CFEECDB6B8
+:10A4A000741A3F3B66C09776D4D12FCADE5E44EF64
+:10A4B000DF664F1970772666CABF2CFB13A7730699
+:10A4C000EC198AF4D3AFBDCBE97103F254A4D74998
+:10A4D000EF2D2A453FF35C99EBE76549B48F4DAB0F
+:10A4E0002BF275F1B9BF0CF7BF79B2E7096A6B8D32
+:10A4F00096CD94279E1FD1914179A6181F7A3535A4
+:10A500009DEE515D34F2E71C4D3468FCF7DE1E2DE4
+:10A51000733DCBF7D53F5F19837A1E472DE21AE5CD
+:10A520005DBFE7CF71765CFF7692D720D2633EBBEA
+:10A5300077ADD670099EC90CA7776B3AF9C40B7535
+:10A54000C3C8CE660546D0F7559506CF3EDAE793E9
+:10A55000ED8D69F528EF4F5F343967E2B853FE9708
+:10A56000E2C85FAFD0EA4970490E4CC3FE8AA1D75A
+:10A57000EC20BC9E7B61535A0D9EE35019CF1FCE39
+:10A5800039783E7CEE0593366EDE4E7A578FF1E8D1
+:10A5900035924F571CDA7903E3F35A0BC61F8CE34D
+:10A5A0005BA6F0BC00EFA1BED801AC85387CAE62E2
+:10A5B0002BB3F78E7E7E6FC5FE388A57F65B5378D5
+:10A5C000BD1A2185FEF53A0DE7D729815689EE752A
+:10A5D0004EAB42E79DC58F4BFD3E05D7319841A557
+:10A5E000F38C84ED36C21972BDFD7242B7DDD6BF61
+:10A5F000CAEDB65EE27940FD7BB2D347F2D2FCC928
+:10A60000CA7695E50991FEF61333F72F2B2018C76C
+:10A61000F4BEFD56665FC2CF76D9934DF96EFE75D6
+:10A620007BC977F2AF9F0BFF3A1EC6F7333FF88A1C
+:10A63000F42DF4512657DB153A6F525636CF97B8A2
+:10A640005F5B1AC5CF27F453FFF3CC64163F5A065D
+:10A65000B2BAFD528D67D89EC0F4799F4306CA27CF
+:10A660002AF7A6821D1FDDBE5762DF1BCEDC9BC012
+:10A67000E8B8CE418CAEFC657231C475EBB5F2978B
+:10A68000D730FAF4536FE4D2FD0BF5C1E47F01E358
+:10A690009C09BAF9117E16A3F0A305D87FA3E6574B
+:10A6A000376A7E4F9C8FF243FA6EF2822B967D3F83
+:10A6B0006ACDD7FBCF7897DE7F2654E8FD63925BA7
+:10A6C000EF1793AB86EAFA0779BEA7EB4F5D96AD1D
+:10A6D000A3D3EB26EBC60F6928D6D10EDFF775E3BF
+:10A6E0003337CFD1D1C39BE6EBC65FB36D91AE7F5D
+:10A6F000A47FB9AE7FD4AE7A1D3DA6E587BAF1E35B
+:10A70000F6AED7F58F0F6CD1F5E7B43FA4A3F38273
+:10A710003FD58D9F787487AE7F52E857BAFE29A740
+:10A720005ED4D1851DAFE8C64FEB6CD3D145F08622
+:10A730006E7C89F98F3ABACCF6816EFCF494BFE84E
+:10A74000FAAFB59FD5F5CFC8BAA8A38314F7C71140
+:10A750002EB85D563ABFD1CD0FC286E1E4F7164E52
+:10A76000F12C2847FC1962CE2914678E2E94200103
+:10A77000A17EA17DAE8D70D8DFFBFAAD11F1EB4B60
+:10A78000B0DC4CDFA99AE80BE1CC9EF3055EDD66F8
+:10A79000BB91EAE28B7CBF3FCAFC173D1AD8EDD7CC
+:10A7A0001669F518D8AC9EEBF20738BE879FD3FC2C
+:10A7B000DF48D860A3FB9FF06F7DF14F96F4B1584E
+:10A7C0000FF93DAF62FC423B925C7836B46309837B
+:10A7D0006635FA4D69DFEFBF667C3DEE349BD9BD2F
+:10A7E000B4DA467E47028FE1F228B2D799407584E9
+:10A7F0000B2D12B3D7C875445E66C5B0A484C92BAF
+:10A80000DE6506254C6F0915361D9DE44ED18D4F32
+:10A81000AEB2EBFA0779B274FDA9CB9C3A3ABD2EE1
+:10A820005F377E48834B473B7C15BAF1999BDD3AF5
+:10A830007A7853956EFC35DB3CBAFE91FE65BAFE24
+:10A8400051BBEA74F4989606DDF8717B7DBAFEF18F
+:10A8500081CDBAFE9CF6261D9D17DCA61B3FF1A8F4
+:10A860005FD73F29B44BD73FE5548B8E2EECD8AB46
+:10A870001B3FAD33A0A38BE0886E7C89F90F3ABAF9
+:10A88000CCF63FBAF1D3534EE8FAAFB59FD6F5AF49
+:10A8900038EB0CB0EF1C7F27B1BFA711F89991F5E9
+:10A8A000B96E9C9A88793B7D4F00D14ECA0FFACA87
+:10A8B000D705EE2A9D5FEBF65D23D7317B3A513EFB
+:10A8C00054CBE321148574A3CFCDEADD36B35D22EA
+:10A8D0007BB2FA24863F4A89ABD93D37917DFFC3CD
+:10A8E000420FF267257B416280C1E1A0FB444CB777
+:10A8F000DDA45DCEE987DD687959FA74CF47E54973
+:10A9000074EF7AA19CEE2BCBCC4DCCAECBE4D1D660
+:10A9100010FA93B7A37AAF3B5D6B463986ED772487
+:10A92000AA292DFB0A7EE75AF33936BE6B5D95AF37
+:10A930002BE1F9C2EB330FE03D4A41FFD2E4453B46
+:10A94000C30BF0435E1BA31FF1A630FA275E3B6BDF
+:10A95000B779B358FB53AF93F56FF7E633FA71AF9E
+:10A960008BD17E6F056B7778DDECF94E6F15A39F69
+:10A97000F27A58BBCBBB8CB5BFF2D6B1FE67BD0D2A
+:10A980008C7ECEEB636D8B77337BFEA2B789D1BB18
+:10A99000BDDB18FDB2D7CFDABDDE5DAC7DC5DBC255
+:10A9A000FAF779F7327ABF37C0E880B79DD16DDE0C
+:10A9B00020A30F798F32FAB037C4DA76EF29D6BEEA
+:10A9C000EEED60FD6F7A3B197D4EAB2FA64ED7DEC4
+:10A9D00083C91617BB6F155FB38370279E974EF31D
+:10A9E000A44ECF63DF89EF25BFB53E66ACCAFC7FBE
+:10A9F000849F8BD4C3196D7DB518D3477AFF337804
+:10AA0000C40EFA9E739D81DFDBD70DB0EFA03BCC67
+:10AA100088E9FC9EB2291A7C512C9FE579EB520DF6
+:10AA20008790C8FDB8780FB154C37D1EE1318BE12A
+:10AA3000F1CDFEF871714F0E147A264CA77ABCA5A1
+:10AA4000CEC8D33A27FBFBC14A13AF03751C919DB7
+:10AA50003BEC7DAF5BAB7DEFDC67FFFED369141F82
+:10AA60002BBE953D2487B7D5D82AAA83546872ADEA
+:10AA7000986ED0B533A7BAA7939C97EEFF018B8B46
+:10AA8000D5770EB7929CAFA34F40D07E67835D65AC
+:10AA9000DFCDE17DC141F74DBC90127D13F8589B8D
+:10AAA00055E871D379E661624D744882A7EE92E869
+:10AAB0003C1CFF917C546972AF9A6ED0B5CBA7BA9B
+:10AAC000AB888FDB264FBFD9808F7E3CCDAE7D7F9C
+:10AAD000DFF138F1519BE1399E9AD95D67A886A0D4
+:10AAE000CADFDF6979A8563FC53C95D51FAAA5687E
+:10AAF00027DD1BEE2BD2DE27FE3996DD573FD4E251
+:10AB0000DE879A3FBB50A7325C54FF39C64F758829
+:10AB10000B757FB5102C457C5C88F71B7A8F5E8D9A
+:10AB20002DBD8FA9A6E22EAE57BD5662DF91F7E587
+:10AB300027C5FB99E9050E76BE6ACC7FD9BD299160
+:10AB4000FF3F3F297507D5477F56E869A0732F9FC0
+:10AB500024FB8CF477A336FF08AA336E32703CF8DE
+:10AB60005E9799DF566C6E9744F5D7EDF1E3D9FB0C
+:10AB70005CC40D7D071BD0F42870B14AFB9E5EE0DB
+:10AB800001F1B681F4F3D96F2766112E6AF74F628F
+:10AB9000EFBD1B0DFCEF77C4FA402569DC4FB68E84
+:10ABA0006EDEC2F5C7CED93129D64FDFFDB6CAD089
+:10ABB000F0422F7EF2571AAEDE4E5159BDAD51B361
+:10ABC0003FD1FF84C6DF13DAB8CAB623E9F4F74AE7
+:10ABD000ABDA5527D5912137343ABC7ED085E38650
+:10ABE00027EE191686F3DABD27789D1E42A3E7C427
+:10ABF000727649EF1B357B15FBA894975130495469
+:10AC0000CE75DDDF86929C783C1078948DB19E667F
+:10AC10004BF839BAECE169660F710DCC1E100FAB21
+:10AC2000C9D8432842AAB7787E613312EE168193C1
+:10AC3000B5B7819BB54B112684FFDBC1CFDA3B2032
+:10AC4000741F7D10E4F6D56450BCA9858ED214948F
+:10AC5000E30D9BD7BD9682ACCC6D7AB06C10F27DC3
+:10AC6000E376873A18DBD93BEFDC489F17A23DBD5E
+:10AC700042FBCF7FB66823D577D19E3EA6FBD22C70
+:10AC8000EDBE8F3874C9882B39CECCEA62B73DC48B
+:10AC9000FD664093EFF2A9AE00CDAF5E0F0C2F1D05
+:10ACA000AF9A98FEBAEC29FF8EE3A906CA07817D08
+:10ACB0002F7AFED591FE75D8BF1C789CEECE3379E5
+:10ACC0007C16767046E57838F36B897D1F7F46C227
+:10ACD000F9D97DE35FE49B68AFDCFE8EC5327BF97A
+:10ACE000CAC0F304C8F0A4646792BC7CF7517DF934
+:10ACF0008CC13F212E93C5EB0F887FB5D8B3753C2F
+:10AD0000D5E99E939C8DC8CB99787F469D45E7FFFA
+:10AD1000E1720C3929BEDE032AAFF344E6B7E21C28
+:10AD2000917C9A8CE0A3F7A85D794DFEE1AF29EF05
+:10AD3000E8C9AF27855E6036922A32892FB7BD37C2
+:10AD40003E3644EC2FF6956C7CDDF6BFF33AB72F18
+:10AD50001DD8F73757AB8B9AA2397F223EF5E48B8B
+:10AD6000EBCB5CC1EBA6823F74205936DC4751A285
+:10AD70009D64C77F88E27529516F12F7F57CD9630E
+:10AD8000AAC8A37E5EAF6A777C328CC5D74B8D692B
+:10AD9000FC3BC300CBCBC43D6696B0AB7C5567573C
+:10ADA0001051EF8182DEEF3F6EB34D253B984BF1A2
+:10ADB0002493EE431F0AF9B1FBD0FF03211A67D792
+:10ADC000B0400000000000001F8B080000000000E1
+:10ADD000000BBBC5C6C0F0A31E8185D851F9E8B8E9
+:10ADE0000C4D7E03337EF584F06AA0FE6540BC10F6
+:10ADF00088E700F174209E04C4BD40DC01C46B5898
+:10AE000019189603F122209E0BC43380783210F774
+:10AE10000171272BC21C37A03F02D8F0DBF5981533
+:10AE2000532C9213C13E41C0EFA378F8E307DC0C2A
+:10AE30000CB77910FC005E54F987DC08B6A52065D4
+:10AE4000767901F503006133110A800300000000E8
+:10AE500000000000000000001F8B08000000000040
+:10AE6000000BDD7D0B7854D5B5F03E8F39F3C8CC9F
+:10AE7000E4E4452621C0C903081270081103A21E8C
+:10AE8000206254FA3B3E8B5E6F1D1E2A208F88B4D1
+:10AE9000D2D6DE4C1E8404A20D881681E2808AB6CA
+:10AEA000C26D50B46883777854638B6D68B1A257D4
+:10AEB0006DB45E2F568414AB582FB7FE6BADBD4FEB
+:10AEC00066CE4902D4DEFEDFF75FA8DDEC73F6D96B
+:10AED0007BAFF7DA6BAFBDC7ED1FCA328731F625FE
+:10AEE000FEB994B1952EB65B3A9F318F27DC398B32
+:10AEF000411DFE6313196BC2320FFE8BCB2A9BC020
+:10AF00009897F13F4A81FCAE3BC8D8CD9AC1580E04
+:10AF10003C0865527B97BF8645E1D1D66F2B33DB6A
+:10AF2000FDD8D2646C1063067E08CFF7B77C9657C5
+:10AF30009ACDD8A38D45B21B1E153389B10B18CB02
+:10AF40009F9FFD8BD20A68D22A3305DAD5B70CCA87
+:10AF5000EF86EFB7149AF93AF5C364ECA7D0C3FBB8
+:10AF6000612C46FD0E63BCFE68E3B5E9AC0CEA6DEE
+:10AF70004D7F528249B8AC72784C66090F9FFB979F
+:10AF80000CBF53FFDC5D2AEA858C55E03F100E565E
+:10AF9000C5104E43B43DF0F6A93C9CD763302F3723
+:10AFA000EB3B8FFCF915BE5129F3B6E681F333274D
+:10AFB00024E7F7B7CE87E0CBC1A98415A660D53CBE
+:10AFC000149A4028E67FD49FCB91318C35D41AED6A
+:10AFD000252EFE281BDE5F2CC66B50C31EC4DBC5AE
+:10AFE0007E39E61EDB777CD50FDFA58CCFD84CC22F
+:10AFF000A72A9EADAA05CA01C0CDB51E2A97665CD8
+:10B00000EB61D0DF846CA03BF4D7E2324311A87B24
+:10B0100083915004E01D9F3DFD4306CF27EAB7CF43
+:10B02000C0F217C39B8EB8012F2B74CD70233CEF59
+:10B03000ABEF217CA5F0F7CB2278AE7666E2FC265A
+:10B0400030FEDC823BAD14EA29F31AEF787FB1AE13
+:10B05000CD92A17FCF503E2E6B4F690FFD5E9C7D40
+:10B06000E39D12D09FFDD9FEDCC2E7DE5A9D9923F5
+:10B0700019DB5C5B4A703D037503EBFF6DF12BA799
+:10B08000AF26187D699E0C88656CDD11632BB26A52
+:10B090001BFE1FF4F388ABFB26649A589E663C2E79
+:10B0A00061CBF8C3B743BB076F1854BE0AF03F210A
+:10B0B000C2F1F4A0D4FD2E7E1FBB86B77B460D5F88
+:10B0C00087F507AFCF9463525FBA8EBF5E8EE5C23D
+:10B0D000FC2786008F41AABF3B722CD2FBF18FDC8C
+:10B0E000F05D59B566AC82EFC67F3E8819598C4D2C
+:10B0F000420683793CF02A8BD7E3F308A7C32FBE1F
+:10B100003DDDDB5D96C4BB097F110FEB06C0BB9331
+:10B110007FA6AAAEE47BF8EF629817CA7B1F7A5429
+:10B12000033D82FDD06106D061ECC074B0CA15B594
+:10B1300071F687E18CDD5F1B22BAB4D41A54B60ACB
+:10B14000FAB461D3897DF9F73E99CD6B07F8EEF338
+:10B15000B1794F239C6679BFEDAC92B13AD233F707
+:10B16000A3AC4CA2E998AC92B1F4ECDE7AC257825F
+:10B170007C0DFFCA17EF0BA07FA9B71E6300872FB6
+:10B18000D93E9606EDEFF7F2FABFC73698B1826462
+:10B19000FD23F680199BDCF77D8B2B6E4AE3187B31
+:10B1A0003E768B59E6B5F56F62FFA9F3F34CEEDB03
+:10B1B0005F8B97B7FF2BFB3ED59BA44408F5039507
+:10B1C000610002BEABAAC47EA1AE33B62D331A3BDA
+:10B1D000303139CE11168DC580FEB7B2C83EC4FFDE
+:10B1E0000629DEA014E2B86D3319CCAB13BF877EFD
+:10B1F0007D93F9B89DB116B3414DE2E5B7AC318608
+:10B200007058FA57117CAB346B31D4BBF52D9F9934
+:10B2100012F0A392C574B781506492FD907593A10A
+:10B220003EB7E8A1E8EA07A9FCD5CB17A2FDC07498
+:10B23000E4ED7AE7EF8A4F9361FEFBF015D4A74E59
+:10B24000AAFCF564185FEB7285515F0711AFD065FA
+:10B25000F0B4C2269563A3A829010D5B81D1514E9C
+:10B260005F406607BE48AFCC67F1D4F9A8D150243F
+:10B2700090EC17C63B8AED2C7C9D6D7C15C737FA88
+:10B28000195F3569FC2631BE73DC166F7826EAD566
+:10B29000A9232AAF66D4CF70D92D25BF6B1D65C8F1
+:10B2A000F8DD1889DB4D2FF65F9E84C38BE3C078F1
+:10B2B000BE12E837458F5AFD015E18EA63EB3BABDF
+:10B2C0003DC04B746B1D65C78BB31FC05F08EDCECF
+:10B2D000C0F4DFC6E93F1EE8CF52E81F06FA979D8B
+:10B2E00003FDFF41FD7E023C8CF02F1BA7C563854B
+:10B2F000C28FC94CC26FC16BC1E784BB49325F9F2B
+:10B300002C113D19E2CDA2E727F85D4E72FC3E7C80
+:10B31000C4C284F7D6432EB6EA0CE35ADF3BC75DBE
+:10B32000F6EAFE1058A43EE33AE7EB1C37F3F3517C
+:10B33000CC04FB5084BC0378AAFF9E4676AC6939E6
+:10B340008B23FD9B3A2F233F65AD1CED447E8DFD85
+:10B35000C6C51E872ED7A23E453BD85C41DF3D12B5
+:10B360008886AEF50FAC4FD7819F100382AC853233
+:10B370003E12F1C4C88E66CF53C98E35B98C961271
+:10B38000ECFFDBF2B8C7193D7F3717EC4293D75873
+:10B390005395F23C07DBE3F340F89592ECE4F3AC11
+:10B3A000AFBDEF9DE5A7F7EFE6A6F875391199C592
+:10B3B00052F034548B4623FDCCF35E4926FABC8010
+:10B3C000F685EC3DB72F437DDDB3101FDA02CDD8F3
+:10B3D0000AF8D8FCED1BF367C3F7FB1E1C21BD5711
+:10B3E00086769BCBD766619FACFE32971B12FA41E3
+:10B3F0002FB8BAF7063318AB9198590378CF3C169B
+:10B40000FE27D4BFB5D26EE686F12AAA79BDF2FE38
+:10B410007F632F539D91FEDC587798F4E986571F80
+:10B420006DC0F1977D08AD60A8496A5CA921BC6731
+:10B43000F76BC71EFFD033330EF39AB4AEA9EB3AC5
+:10B440006286B88D6F2E3A6AA7FF0B02CE6704DCC6
+:10B450005189D9E44B13F2A5F5CAD7883A15F5C33B
+:10B4600009467A73922772F37CA84FAA66E106A375
+:10B47000EF7CB46A90B314FC033CD352E1F99F8291
+:10B48000E356663E245D30707F7DED427433B69F97
+:10B4900024F45B6675BB122D3B13DC37129CDA5526
+:10B4A0008CF4F540FD3BE1451F0CE70DE36D977211
+:10B4B000FA8EF78FC207F4BB9FF4D8DFD96FE6513D
+:10B4C000A75E6F13FA24A1A2DD4BD6230CF58B36B1
+:10B4D0009445D1DF52843EA13F30B45A107E14719E
+:10B4E000D12569D45E0D7908AF376BD12EA2DB0C64
+:10B4F000665B377AF4082825E82FBF349DE8E2EF31
+:10B500007FFECDB5914CD595527731E19F7338B41C
+:10B510002216CF42B84ECF31AE1D936C9787F34BB6
+:10B52000E96FC310EB3BFB7C2D7FDDA54F18BF0AF5
+:10B530006A4771FE397DE70B701C9552F4BBAAC7B0
+:10B5400018D177FE083EFFB9D9FDFA2B799EEB3270
+:10B55000D5AC245F16CE30EA5583BA34910FE91585
+:10B56000D41FF01F3D12857FAE667CDE6EB9A71337
+:10B57000EDD36677F414E22FAFB98B49D02E6B462A
+:10B580008245018E15880718F732C5EF453DD5660F
+:10B5900016A5A3DE1A224B36FA5AE546D0CBEA703E
+:10B5A000BE8EC3F2D4DB2369DE03F17943AD2723DA
+:10B5B00015EF0D0BD5EA38F4DFE07FFAD074007593
+:10B5C00045764939D9E679928A7078250E47BA18B6
+:10B5D0007FE3A26F117E006FE932C0EDCAE6F8B2D8
+:10B5E000F808FFA829F01799515387F75993F93AAA
+:10B5F000B510FC53F473329A5938C1080F21EC2767
+:10B600002F9448A0090F54E953118F161EE08F178D
+:10B61000EDC59A578697231DAD79DF2CCB9C7FCB48
+:10B62000B89FC0D430F97303E98D56C053D970E286
+:10B630007B09DB6DC27A0A1EDE94A2A364A447D8FC
+:10B640001753609E7973E312C2F5B064CD23447141
+:10B650008346C137ADE53EE2B7C621FA16F4172B93
+:10B66000646E87D826C9C95F15728A9C59FC9517E4
+:10B670008E52BCE1DF5CD14AC2E3B2761DE5C6372B
+:10B68000B75B477F60A5356E8C75617FD9820E16DA
+:10B690009F67961A5B91CFAB055DB22B9BEEC2758F
+:10B6A0005A56994AEBB8ECEE59B4BEF4BD75C5874D
+:10B6B0008C3FA7F56A5EA48B96A5F9A5E65EC4F754
+:10B6C0004E57B41AC7CF9C78C0243E04FA6800CF06
+:10B6D0001A5794E13A529B1C37711DBE71D18D6C83
+:10B6E000560A5FDD24F0EF02F3132F4BD2FD01E188
+:10B6F000D87D7F72B9F78E326CE723BC14B1EB8929
+:10B700000F0A5984FC5C2D49FF99881FFF8CB629CC
+:10B7100038AF4048AFC77900DFE7229ED6B8F43C87
+:10B720009CC79A451AE93BC0C761E4CB7459E0C392
+:10B7300080BF809F80CCC72D925D349E0FF08D4ED0
+:10B74000A6BBA8CB54409F825A0A63F37481270B8F
+:10B750002FAE9270A781FC388381A709EF05DE5CCC
+:10B76000A5E00714117E16227E0266C2447C69D9C8
+:10B770006D7B310E74EAED0BAB910E27FD3243FA6F
+:10B780005B7CE8E43FD50FF2D6AF1E0E935F9726A1
+:10B79000F4D94B52F4DB728A1ED2F23B43D1147FB0
+:10B7A00047D3B87E6665D7733D529008CD81F13D91
+:10B7B000A1D03842B9AA535CA3D51AAB97FFEB6965
+:10B7C000BC16E1E768A11AE23F6F4994F48DC7689F
+:10B7D000A3D25DC0F9D27AAF2D578CF75188CBB880
+:10B7E000FE6B0A5F9B8E7E91E649105FF8DBF632B6
+:10B7F000C42B8845F8711A31CAAE0F20DFF3B8D7D1
+:10B800005350F2B8439CC6771B3E9648B173DA7228
+:10B810008DF72FE431EF2D37C95DB6B03F6F4A91F8
+:10B820000DA4172C39B4EC43E47A2EEFD55E82F7E1
+:10B830007111A7EB2BF71CEE53D07717E24D8DFA61
+:10B84000D01FDEB66EB60FE1D8B6FEDAF454FC3A7D
+:10B85000CB87413F244040B7805EC57263AD4E65E3
+:10B86000AFDE15F1A44D424EADE75E85EB8143425C
+:10B870002EB779223E8A6FEEBFE9CA5180CA92C3C1
+:10B880004A1875C3E035ED19671ABF60A16CC3177C
+:10B89000536E39E37C97BF7528E3404AFB7D7220E5
+:10B8A000FB83D1F08F0BD9855F2A67FFFE546D575C
+:10B8B000C601D7DF8F974D220EE1556EAA8B21DE90
+:10B8C000139792DE2C12AA2BAF99D13AAD64198B43
+:10B8D0001BD8F6F497FC7D6FDCD7F4CF823AA96AC7
+:10B8E000A86F6B9EBD0AE56CC86B0AC375F87094AF
+:10B8F0004F8C3BADE371270FFCC5B8138558A0DF13
+:10B90000E2B92C9E8076C56DF638631E6BA5B8F142
+:10B9100010477C2B0FF500EA4596D21E9E1780B08B
+:10B920005796FFFD74F804E990F6FF9E0E1BD5763E
+:10B93000AF9EF2FD608945905F072F7A5F9A9DC2A6
+:10B94000AF1E85F3295BEE677F4889E30D96127978
+:10B95000A83FB72C94C93FD8B890C749DDD9DDFFBF
+:10B960008A9F9C7A67751EF957833EB804F5618EED
+:10B9700092C6FBA966DC6F60763D0476304749F1DC
+:10B9800017B6345E4B7A07FE1CC6F8A821E8BDF155
+:10B990007483A4011D872F67E17AA81B82DE55EB13
+:10B9A0006AF6BAE079D132EEC7B3989DFE45733995
+:10B9B000FD87B772BE1AB25C7DCF1E2708D76B30E9
+:10B9C000DF5C50BF1BA056B2CECE1FB9C21EE43AF8
+:10B9D000F8C3003EC8023E28698BAEC2FEF30E2BB0
+:10B9E000DC47768C3FDC68BF02F15302788A93FF14
+:10B9F00099D28F82FC15AE477A38F93217F9726CFA
+:10BA0000DF71FF5EBE9BAAD8E5FF535676F39350D5
+:10BA10007D64C5F64323A855444EF5972CBEF333F9
+:10BA2000B31AE9C422E7B61E63EC72D2C3D67ECA4B
+:10BA300094A5211FC66B3669BA0FF75562BF53181C
+:10BA4000DA874D4BF3F353E7BF45F8775BBCBC9CFB
+:10BA500025F8F056C545E51C85C7E13705791C7802
+:10BA600020FD6ED9D3919FFB59222BB5AE39EA2A1E
+:10BA70004B8C4FAD07A9DE98C3C8EE6CC53225FECE
+:10BA8000B022D0CEF8BED45C19F59322F4D3FE8C4C
+:10BA9000E91E84AFD15F2EF681A204BFF5BED15F4F
+:10BAA00094CB52E06CC438F7C881F1B802E3DCE80B
+:10BAB000F78BB8CC569719CA80B231637A6856367C
+:10BAC000C6C706917DFF9EB02B0A8E09CAAEB16132
+:10BAD000575D3DF0E61A66FE8B7201FF0EFDABADC1
+:10BAE000191318EEEF413B33DE0FBFCC577C1C6FB0
+:10BAF00086FA853D6EEFD7895F04BFDEA6445B9171
+:10BB00000F62535902FDB518ACC71AD09ED7801FDB
+:10BB10001B48D21FDAAD11ED6218BFEB6D17B5D619
+:10BB200003BDED1EC279423BD3D62ED2A7DD46D14E
+:10BB30001FB38D6BF619372EFA4BB0D4FEC27DFAC7
+:10BB40007B5CB48BB1D4FE8C3EFDFDD89A9FAD9D3D
+:10BB5000DEA7DD4F443B661B97D9C7ED7D3F54B34D
+:10BB6000DE93BFB722E7460FAD97E2336D7CE5A4C5
+:10BB7000D3BE1CCE670772A657231FDCFD8A8BD667
+:10BB80000B7B73ECFC67B56FA865CD0B5DB80E64DD
+:10BB9000B45FD8E0DF4AE358CF7BDBF9B7EAFD3F7B
+:10BBA0009F3D40FBD9A2BDE78C7CDC20F8B841F07A
+:10BBB000B1F3FD052A97EFE652B027FDC8B3A9728D
+:10BBC00079676A84D6715A296B2F4BD167FFBFC042
+:10BBD000394EC0D15C5ADF3635CCD89F952FEA3C20
+:10BBE00040FF96D0DAB629507F8D7D515725FDEF65
+:10BBF0008333A3D1539F0AE70B314FFDFF4638C76C
+:10BC0000AAB936381F61B9F5558503C3B942C4CB0B
+:10BC10009DFD4E54F9FA79A52B427A7B45CEB74269
+:10BC200038DF1543B87EBFBAF18DBA3A3F36894E38
+:10BC30005661FC95F05F17DA23D520FB72B6EF3C16
+:10BC4000A3D408CA594B88FB6FD6B8AF0B3B62959B
+:10BC500047C879037F2D4F25FF8EE568F1E1021E6D
+:10BC60008CBB7DAAE836B9CC54756E3F44FD7CD5BB
+:10BC7000FE1EFEF105FA313AC25FDCD7AEAC157696
+:10BC8000B6AFBD8DCBA9F636C3B2B7578CA07DEE4B
+:10BC9000FD2D23AEC07D86C6830A23FFCF6177F7D3
+:10BCA000B64CEF34E0FDDA4E97786FDAF4EB7DE0D6
+:10BCB0002F231F80DECC65C4177CFFD9F25F7AC7C3
+:10BCC0000BF0714E829FE74EE1D346B11FDD28F69F
+:10BCD000A39DF43C2DF4DB0E18C7800F9F04BEC358
+:10BCE000BC830D508F42FD51A847A1BE13FC742C9C
+:10BCF0005FAC0DD1F315B506954FC17CF0F99ADA1A
+:10BD0000309589DA4A2A5BD0CF87327F974C71967B
+:10BD1000D5E8EF433D5ECB5A31DEF7FD5A0F950D66
+:10BD2000B53A953FA90D51B9BED6A0725B6D299564
+:10BD30009B6AC3543E545BD98AF1BFC9D2B52B91DB
+:10BD4000AFF2E731A27BFEF7466C4597AB78974A96
+:10BD5000E314B7821DAC483EB7E09C2C4D6DC5EF97
+:10BD6000C6EDE6F31977000C5EFFEDD660BB4B76AF
+:10BD7000F3FE2EF91CEC7476BFED1E52318E149733
+:10BD8000C95F71411BA9FFFE36627FA3E32AB51B81
+:10BD9000BD9D511CA99F7671EC2FE3313EBF8C2ACB
+:10BDA000161BA0DDE3D8CE7C8CF767322931C0B8F2
+:10BDB0003FC67681CCF0AC08F167FB1419E36FD570
+:10BDC0007A26C6230359E1BBF873B31E9F7B4BF859
+:10BDD000F3606F7B633F3EF7958AE7BDED7B14050B
+:10BDE0009EA795897E34DEBEED0AEE376454E95B8A
+:10BDF0003D308F27AEE0F4C9AC36B6603DE0E6DFFB
+:10BE0000EB23DA9804F29651A24B12C03912EA32AF
+:10BE1000C86B5033A6C8F07DD6954CDE0A9FB69D00
+:10BE20001767123CCF28E5ED9E80BA0CDF05DD4692
+:10BE30001DCE2BEB2A68077CAF9FDF4EED5688FDA9
+:10BE4000A491E7EB7BF17D5A9521A168AC13FB4DE2
+:10BE500099658624C3F885556C2A8AFE7C17336F52
+:10BE600080EF57DCC5F5CF6F1A174FC5BC85F42A94
+:10BE7000C6F31C56FC6C6A1DA896403E8F5F0506F3
+:10BE8000878F44316E74A146FB7FC1FC70770CF53F
+:10BE9000CE04DF38DC9F0C0E0E1F8DE3FB8BF87B8E
+:10BEA00060D5989E09729C7EAC74D619D63F56F91F
+:10BEB000C9C16914370C56C8CCECC7DE58A5966DBD
+:10BEC000DF1FC9AB8ED5213C17223C08AF80E75855
+:10BED000E377A6623EC408B1BF37D4F5248707F7DD
+:10BEE0004B603E816189BC3BB253E0199A285C5992
+:10BEF0009102CFB0C4A827B293F0640B780AEEE6A3
+:10BF0000F07CA29AB97A3FFAC439FF9C887D9F6879
+:10BF1000ABCBA0B8A8523D62032E7D9527F9FC5605
+:10BF2000AC185D5F5F02FA2087A9523A94627DE502
+:10BF3000F2B0661C17F183FB096F0B7DD54B970E92
+:10BF40002D96D54F1E99550606B31ADECEF32EB6A2
+:10BF50000B8AEF821DBE337E1714DF053BFCEF66B4
+:10BF6000050786AF2F3DA2F52AD8D788EBFBF283D1
+:10BF7000500F550B7E8A6D9C3AA5A42F7DD65EC3CB
+:10BF8000E15D2BE0CDB6E005FC6602BC9F5AF05A9D
+:10BF9000749B79167887C1BCA99D80577C179C79C2
+:10BFA0001678C577C19976784FE3A6C60567A76B63
+:10BFB0008380A341AC8FB3D5B3C0B10CE0E8271F99
+:10BFC000B20F1CCB3C349F5E3896F9CEF85D2F1C27
+:10BFD000CBFCEFA6C27BAE70AC1170AC09887C01C3
+:10BFE0003FC0517E06386E3947386E71C071CB390B
+:10BFF000C271CB5783A3578E043D5C821E563F7D92
+:10C00000E468B0199A65D36FA65197A2DFDEB6C671
+:10C010001D6C966E49D1736A16D7078D38DEF950BC
+:10C0200006C478026F038FC7062FB48D07A6BBDF47
+:10C03000F1C064A68C17DECFC73B5B1CE03A357AB3
+:10C040009F4BC401948A81E300D06EAD4BACB39595
+:10C05000EC81E300D0EE07A29D696B17E9D36E93E4
+:10C060001897D9C635FB8CBB45F49790B3078E0360
+:10C0700040BB6DA2BF985C31701C00DA3D65CDCF2E
+:10C08000D64EEFD3AE5DB463B6711D7100C6EEA29D
+:10C09000F8F6371DFB32CE327BAE66CB17CE9C61F5
+:10C0A000AFFB2BEC750DFEF6C6070B93E359FDA510
+:10C0B0005BFBF8D11A03E7B32A103F82F92A875CA9
+:10C0C0007F989A0DCF576570FD79C8F5513DC5E948
+:10C0D000B1027EB0DF8AC34FE6F1BF53E364822F23
+:10C0E00038468D338C4B3299FC427F8116C738A776
+:10C0F0003FDC25519E0DFA1C340F1E5F0B54447813
+:10C100007C57F4030C73C6FD59B554A3389C5ADA16
+:10C11000DCC54B95F2CF595B9FFDD47710EF6EDCF9
+:10C12000DF2B4EEEA75AE30C84DF243D5829E6C1ED
+:10C13000DCC37C61DC3FCDD098A4C2A7CB0B78BC1C
+:10C14000F99B72F48FC8275A55CDAD8D5097A62F05
+:10C150001F89EB8F106602813CE8B9C27F99E30921
+:10C16000A37CE9D326D33E1DE809DB3A6F8CC6D702
+:10C170008D5FB814C2879EC6F510F3C4F2AE49C9EC
+:10C1800067088976F0FE2EA4CF454DEAFEE64AA860
+:10C19000A7B37112F823996BFCD3AA012EBD587C6A
+:10C1A0005F30C0F7C56C27B60F6BD27E15DB0F630F
+:10C1B000642F2F6C1AD280F9A0FA486E875985B186
+:10C1C000A511E6BFFE9F078DC33CC0ACFFB3BC10FA
+:10C1D000F5406F3FA3392B4CC4EFB07D14FCF6093A
+:10C1E000C97CBDCDEE6850C37DB9EAAE04AA16C5C0
+:10C1F000EFCC5B284B7F2F050F83347BDE42532D22
+:10C20000CF57B0EA9AE75719EF8F87EF677928EE93
+:10C21000169AADC5D1FF7E5036ABB40B68FCB8633F
+:10C22000FCA1F8FC5CC72F157025C7F7B0D4FC073C
+:10C2300067B972E877F2A2840FBEAE857991FEB13C
+:10C24000E635563C67FE581EC9B90E6520D9BE6D4D
+:10C25000DABF48F8FD71295A41F30F45D5D47CC7A0
+:10C26000AC1926F1ABD5BE01E09652FAB79EB310D9
+:10C27000EFBFB75ECDEBAAE07B7DDA2D14F750ABB4
+:10C28000783E0E9B69CF6B51F51A2B4F2384F3E850
+:10C290009BA751A0D3BE14E37ABE375EF94E20DED1
+:10C2A00080FB3BDEE05806766FB98797F7F8825B34
+:10C2B000B13CE51D1AC77D9253725BA7A424CF87BA
+:10C2C000785DB118EA07904B13FB3CDBF7CEF140E9
+:10C2D0003F9C8FF36A29698B207C2E15FA33E8B9CD
+:10C2E0007D3F5AEC735B7BEA9A27EA29C43839AC64
+:10C2F000D763C80F6DE3281EDCBB2F0DBE22E505FA
+:10C3000085D863222F88A5F293A7C4BECFE22AF076
+:10C31000D9F42C9B1993703C4B7F5BFBD6AA1F84EE
+:10C3200095F0690ABBC0F5310EC1E31EDFB5E97DAA
+:10C33000D5CF12DE20C257CE52F74154C6F53AA6E9
+:10C3400023723DFEDD73B2177DC6BBDE3ECF73FEAA
+:10C35000CEAF1A1FA4D8FF81BF53D90729FB59AD0F
+:10C3600098680774BF73C7A79B6340B7634F7FB4D8
+:10C3700039067858F8D74F367F17FD8F17BD3AEA40
+:10C38000C7253FFE8FCDDF017A7CBCDB2D7BA0BEB5
+:10C39000E0C71FBEF35DA87FF6FCC84C0C3D6D11D5
+:10C3A000FAE1F8CEBF0C32A09F657B2EA3F8CCB289
+:10C3B00067A7D9F6519CE571D0237177EAFCE2D4E6
+:10C3C0008FB15BC2CD34C63A44C94CBF04F85C8C13
+:10C3D000FF84F1F6EF529817E6F7F11137E5C92E11
+:10C3E0008167CBC1BF5ADCBE88F619B17E2FF877C2
+:10C3F0008BB7AFA47DB925BB5DB6FD3AE0D8C1725D
+:10C4000008CBC4604C095ABCEBBAAB2FAEC0D245C6
+:10C41000F9254B584F13AECB9CDFE1F89F43BF4B40
+:10C420000E2BB3B4F3FBBE5FC222E9B86FBD647BD1
+:10C430000B1FB7FD6BFF8972B2C4B12FF831FE63D9
+:10C4400062DFFDBE8466DFEFFBEC4737A527F0E532
+:10C45000AEAC7EF352ACFDBE45CFDE70C67D45C4AA
+:10C4600073E21CF0AC5F2C47FA8BEB03A7109F3CE8
+:10C4700024F224BE3F59CEC3943ABD85EF6BE953F5
+:10C480003FEF2C86FA23F3B3C7213F58FB7A7E2671
+:10C49000F49ED8A71C489F3C34846DC2F2C13C284E
+:10C4A000CF4FEA975F69D1F7B59C81F5CC4392787D
+:10C4B0009EC1E2786E07F489C7578E79C13D9DC54C
+:10C4C000F8FC1A99EC3B3C6FF665A6B49FC8DB33C9
+:10C4D000D334F4095C8EB89E824783285EC1FF9CEA
+:10C4E000178EA192D1407FA13EF3A05F548C794971
+:10C4F000ED54FE552B22F8FCAC8BEAC16B4EE2C921
+:10C500002446273C2608D0A1DF1C8F9FEBF7EBD5F4
+:10C5100063BD7C50847A7E13F9E9F8C997561EE210
+:10C52000A0B37F87F31D4CE7240AA87DB6355F7161
+:10C530008E2FAF171E9D217C83C5DB5C1623FF2742
+:10C540003F92A07208EBA672184E41A1BCBE3AC63B
+:10C55000FD7309F1EB656F917D9163B2F4E5E82419
+:10C56000FD2CFA30E18769C20F73D2F51EC57C231A
+:10C570005A48FE58811BF378E49ADDDD50D7DEB9C6
+:10C58000A7270A1FAF13F67E5DC0EE778D74737D0B
+:10C590006295EB3204DD6E10745323D235297E2868
+:10C5A000E10BFC9DF356FE681AF93B2A9FBFF3B9D5
+:10C5B000359E2BDBA47DC94081CEF3AEA28088944A
+:10C5C000BCC0896E1ED7DFEC8E94E3BCFD7ADB5EC7
+:10C5D000C9E07E49773FF2619556FE66536D94CA75
+:10C5E0002A0C3EC32402D9350CBF07BFE712778A55
+:10C5F0003FA40A3AFDEDFDEBE4FFA05D45B97A5397
+:10C600008A56633EBBDB606DA877DC053CDF4A11D0
+:10C61000F966965F65F573AD9BFB535669E56569F1
+:10C62000F9F39EDC0278699B1212721C213FF53AE5
+:10C630004107C02BF92F0F4A62FD2579841C314335
+:10C640001F94942305DC40E42717004AF97BC8D7E0
+:10C650000AF2539CCA34940F9097656E2E3F01D610
+:10C660009D34E6D978EE468FE3390C1510A4645258
+:10C6700099C0D2E2137CEECAE4FB0241D4F3EE4C43
+:10C680009ED78C75947F39321FF10CFC5E2753BF07
+:10C69000A682723148CC6F90255733ED72D5CB8F7F
+:10C6A00019767CDD2DF0B44CF0058E8FFAA4AFFC2A
+:10C6B0009E755DF23D773FEB12C4249D130D34153A
+:10C6C00022DDF4F3D99FE4303E7E79DAC14AF2FBF1
+:10C6D0007762BD41FDF9B46A106E7D3CE7EB152B26
+:10C6E0003BA7D1BAE042B1AEA8B4AF2B1E10F35DA8
+:10C6F0002DF8904D16FEA75E43FE2DF8E79B703E89
+:10C70000ABDD623FC8E47E706FBD8AB7EFAD97F1D5
+:10C71000F75FC17F6D759F83FF6AD979A3577FD972
+:10C72000D7DD561ED1658A9FF4816F19B80F80E757
+:10C73000616195F2928D70FD5D78EE94EC1BEE17C1
+:10C740002C53E90C00BCA775A8F5FDB09866F3174B
+:10C750000373EDF5FCDE3C33FBFA3C5FE499E5B393
+:10C7600094753CEA4B91D7639DC376CAADD3CEEFA7
+:10C77000717FB57CB20392B99FF48738C73DB09FF3
+:10C7800017237A7F55FFBD61CAB823D9C06F39CF4F
+:10C790001F257EDB7BC3208A176CF0F3BCADF5014F
+:10C7A0007E0EDD29F7B08E7F6404E07DF0727ECED0
+:10C7B0001AED0F9EAF4E13EFA5E84B7FA1F3A6BA7B
+:10C7C00059270D4AEA3F56CEF949437A2B6867E369
+:10C7D00054EFB5ABAC874A456F4BA0ABB96FF9D4FA
+:10C7E0000C3CA798C65A6DF267F1C5C965FCFC946C
+:10C7F000CA46A7633D047C40F95C31B32B84E7C291
+:10C80000057F168A3CE10C13631549FA64557B5881
+:10C810006ABE6F4E44B7D57367866CEDF3A2E0F73E
+:10C82000211C8DDCCFC374661E878B101F861602F9
+:10C83000EE0AFBE62D8644BE5ADEDC04E9EBC13588
+:10C84000F6BCB290C82B0B39BE73F293DB23FC46C7
+:10C8500030F7C84F80877082EF7FD23921B5DB4D2A
+:10C8600078C907BC201E4E324EF721B3189DB37312
+:10C87000E2C5E237F85F3801F31F0AFD24709C908F
+:10C880001D4F5EC38EA7B4523B9E02613B9E2C7C23
+:10C89000A7571AB67616DEAC73E703E1A9605E7B94
+:10C8A0001DC2F355F154E6C0D3A7AC632FBEDB2005
+:10C8B000EE5540827952FC27454D489291C447DE9F
+:10C8C0003CE05F98C7E601F87F483633704B9E9591
+:10C8D00005285E1012F8949673BE1FC88F74F23943
+:10C8E000706B1D76EAC2E343C5C8E76F093EFF03DC
+:10C8F000433FCCE509C6D2C662C9F59407FC194C82
+:10C90000CE55FD3CFE06FAF62A0FEAFB02D996C781
+:10C91000E916E77A2CFDA0A8CC9053FCD591A21D76
+:10C92000FAC52C05AE91682FC7A27DE2704B7E211F
+:10C93000C79BC07EA6AC3B2DBB70AE70323D4CFE9B
+:10C940008B1BED685A528E2D3D360CE1243FD33CB3
+:10C950008CFC3942CC675833BF3F6284D0E7C6BDF8
+:10C96000E0CFE2C7EBEDF99C9FB219B45E75E66BC0
+:10C9700016083D3E74993DBFB440E8FD02471EF1E4
+:10C9800010A3FD1A9297988C1E341B1CE3F76A0CB7
+:10C990005DC6C27353FA1D1C0D86E78E4F9EE77469
+:10C9A000F2DFBD1EFBFAEEEE6BAE27BD118F6DED13
+:10C9B000378F7C63AD273C17F3886B43543E59ABEC
+:10C9C0005359BCA92BE685F98C140E6BE14CBE5F64
+:10C9D00059D8AC8553F9D5CFA2AB910F1EB96BC115
+:10C9E00054C4C3F0C6E814D4CB5F53CC56E20F71E5
+:10C9F0002E6DE4F2029AF788E543A974DA91C18BAF
+:10CA0000761DAA85A65BEF05FE467BFAB9DB44FFDF
+:10CA1000087370F17B23A64FF5C0FBE266A31CFBF5
+:10CA2000DFECE1FED2AD1EF3611A671E3F5761E1F4
+:10CA300067207B65E5E1C378AFA01D5133326DE718
+:10CA400022B60A5C3FEDE17E8D154FB2FA696AB6F7
+:10CA5000CE3718948752D45658EF498D2389F30D59
+:10CA600032E3F1A27BF07C034C758627BA93E6A9EA
+:10CA7000A7C48D8A9271A2C18B4A7CA89FB77A62A3
+:10CA800032DE2D30F89B0C16868C8D8A03FD6DFCF2
+:10CA9000032E18803AF4B130F19D05EFAD9E680782
+:10CAA000F65FE0F187E7427F858D864C717591577F
+:10CAB0003F4CF075E9BD8CF472511BA3387D69734E
+:10CAC0004F1DF6335DE8F3AD429F833CCC9895A2B1
+:10CAD000AFB746CD4C3A9723F4ABA54F41CD093BB8
+:10CAE00064D03D24A3EEB5F37B91D09B250EBD59B8
+:10CAF00024F46D91E3F9A8B8DE2FBF5B7039F9FD1E
+:10CB00004D8BDF73591EC6A93E6593732F3392FC7C
+:10CB100060E5E73BFD1C679CC2EA7F5CC23EBEA4A9
+:10CB2000C628DEEC0A311DF9727D8EA597EDEBFA71
+:10CB30005EBF231C8DA13FCE66331DE3E6A11951D4
+:10CB4000CA770D55B3B081F33ACCF7295A34FE9D1C
+:10CB5000EC8949986FEE29E8BA18F9F0538F9FF8DD
+:10CB6000F4662DF229D2336B06DF1FC9423DAD9C1E
+:10CB700059FFC594A4FE5BE389FED57341520F1A99
+:10CB8000515DF6F7A3872DBDEBD4B3690E7DE95651
+:10CB9000A389D9465FB8615A46EA7ECDCA21427F51
+:10CBA00017703BB671A12AEEB1585D8507A356DF19
+:10CBB000B03394A3D330091DD61DABAF90E8FD84EC
+:10CBC00096471B719DB1FA1A5EAFF2FE90D76F9235
+:10CBD000681D72B9780F15CAD772792CFCD5DC5A4A
+:10CBE0005881F8E3FEE0CA82339F8768A8E579524E
+:10CBF000563B450DF3FC6D21FF6E475C54F5DBE3BE
+:10CC0000BEEA427E3ED1D20BEA42EEF7AF1E737B04
+:10CC100027CE03E3CB4847CD53C3505EDC6D77513D
+:10CC20005EB4533F78847EF89638FF04FA21E845D5
+:10CC30007BA9DBE3CA967E08A28185F7232B6A9045
+:10CC4000C8B00EAF918DB2649CC6D2AF1E35C2C2C1
+:10CC5000F0DE555DC30C6C37839FA37357F3736D80
+:10CC6000B227BC17F9D393DD1526BDE7E0C7CBBCCF
+:10CC700016FF999779817F26E1B817E0312A2BCEEC
+:10CC80001696781C9BC705D6782257E2BC8D02BD4C
+:10CC90005E62E7CE5FF4678288831522DC263B5311
+:10CCA0001CCCE2EB745CC717F7E5CFFB3533E332FE
+:10CCB00080ABE157AE30E6290DB42EF9612DE8D3F3
+:10CCC000E149BB67D93BCBFE59EB9655DE427B7EF3
+:10CCD000B658BF103FC338AD6F8D8E532C5EF049F0
+:10CCE000EB5C56CDCF7F72FE748B35E7A921B37D07
+:10CCF0009A1FEFF350A83FEBBC8EC56FBE01F2BA8E
+:10CD00002D3EB5DA5B7CEA6C77AEFCA979A2CD4505
+:10CD100068CFC5FEC7C8B6BBF679FBB15B56BF721C
+:10CD20005FFE6CF19EC17EBDEF3157E1FBFBCBC3D3
+:10CD3000F3FABB7FE1DB3E6E4F372E5CE745BE7DED
+:10CD400018F19522CFBE348E8753A39612BE7EE291
+:10CD5000E5FBA14F6CB2E32B74167C59EDFF07F095
+:10CD6000E51981FBD7025F039D633C03BE7E82F21F
+:10CD70003310BE5645B63617613E40540E0F87FE3F
+:10CD8000D745E4C4A5507F789EBC1DCF89AE8B6C7F
+:10CD9000F50C473E5BBFAF200DDE3FE60BF0738224
+:10CDA0007AA213DBC54A64BA47AA45E579902BD726
+:10CDB000CB8FC652F8715B01CFE75D5930DB372767
+:10CDC000050FDBD6EFB39D17DDE638976895353E46
+:10CDD000C9B61FBB612E3FD7951765713C5F5725BC
+:10CDE000CE5179B3797CC46BF2FA483F3F577560F6
+:10CDF0005CD314D4332D053CFC6FF917EB1DFE8575
+:10CE0000B56EF795F07BA5D647C1E4423BD7C5DCAC
+:10CE1000FF4913FE37BCA773C9BE32BB9FAD083FA5
+:10CE2000C2BDC9F15CF81D2E877F61B557CEB28EA9
+:10CE3000CBA8EAA638D2075E1147C965C3D0BFD8D0
+:10CE40001091098E3C8003754FEB6D6D740F48DEB9
+:10CE500069C5E4F2DF16BA794CD2CFF8AB979F6B75
+:10CE60006E1571BF71079882571D0427EB14FFB42C
+:10CE7000F07BDACBFDD956919776C16153099CA915
+:10CE80009D88534E7C3FA604FB69F7829037A62607
+:10CE90006622DD5AC6693AC63B5B25AE2763AFBA48
+:10CEA000041F334ED7F583B6601CEBE9CEA2D574D0
+:10CEB0009437CAFDECA78DA85CE41F586F267C7CD4
+:10CEC0003E23AAC326F3A7F6F7D276BE8F9A08DDD3
+:10CED00002F8F8A58FDB95A77DA01F084FD1FCD4E1
+:10CEE00038E2029F6CC3D3734674F518B45B300FFD
+:10CEF000EC26B3A086C965C9F19E2EE0E33D7D44D2
+:10CF000026FF2C2FFCBBED6847ACFEACF19EF3F581
+:10CF1000AF8F165AE3097CBF60C4578F4D19CF5DA0
+:10CF20006D1FCF3D17C6837ADE5199F298071AEF2D
+:10CF30008501C65B2CE861D1ED45A37BF5F9185F4F
+:10CF4000C4F190FF713C7F3FE37DBE560AA4C8E761
+:10CF50002F701CE8E7450B8F6A34FFDA143D74919B
+:10CF600090DB27407FCC817E5B863779918FB749F4
+:10CF700071D267B17132DDEFD3BAE96402F3AA9ED0
+:10CF800030319B04F8BD323605D7EDDFF5650ABDBB
+:10CF90003B95BE93D436BA0F4659CFB87F85EBF395
+:10CFA00074D6CFBE561BF9154367806E6349FF2FB9
+:10CFB000B4BEE617782FA277B91CA676B08C562798
+:10CFC00024E31FEB5DA23FB12F65F90D79C29F3EAF
+:10CFD00083FF1066D6BE13D5F93E95150F61E52681
+:10CFE000C535ACFD012BDE67ED0B58FB01E92C319B
+:10CFF00025757FAA18CF0314E3B9621E1F29340DCB
+:10D00000BA6762C4FAE854CAAF5EC6E81CBF5BF8F0
+:10D01000E369C53FCCE88D0F5E04EF7DD6398768A4
+:10D020003EAE870C9F750E82D7C73ADEAB516E7F3E
+:10D03000D4B95CBFB1837DF298EEF15D80F771F2F7
+:10D04000B88A15EF3EE0E5FDAE8BACF5A23E7779F0
+:10D05000CDFBC9FE0A7F0DFCFF5A1F8E733DD00524
+:10D06000D7ED7E7E9F97E267F2DF42D7241D19D766
+:10D07000F7CBF9BAD149AF81E86AD1CFA2E7DF4A4D
+:10D080004730958682EB1E3D22FCC3D819E33D054F
+:10D090006A8F44EB1D16267A96B008D133DFA3CBF6
+:10D0A00048C7A22AA3CE8BF414767308D82BB49B5E
+:10D0B0009B234B89884E7AAAA5823E111E8F615D03
+:10D0C000922DDE05F4790AF1ECA4CFAAC8542FDA28
+:10D0D000EF6D61B91DE5DB69B799DE568DF8DC5659
+:10D0E000504EFB07EB4BD77AD10F00BB4D7E406C07
+:10D0F0009E4CE76BCEC17ED3FAA8C6F71EAD8F5A01
+:10D1000033C4B9C4E15AFCF142B43F06F1C3E49E12
+:10D11000AE6978C7617A25B713ADAE44285C86ED59
+:10D12000133367A35EF821D70B4F449C7A21EE9905
+:10D1300003E5C5BE0CE2DB759BEAAFA075A01AA3A0
+:10D140007580357ED5AA8B57D0FACC9FA0F38BADD6
+:10D15000D72CA5FB132C3DE26C7762CFEB43301F3D
+:10D16000E4EDDB3E098030B2DFAB3D019CCFD17BEB
+:10D170007F1B30E1FDDBF72A74FEEF1BF8DD44C6B0
+:10D180006EADFDEF09781EBD5BE8B78BD2CC23C432
+:10D19000DFCB7388E9E6C7150CEE72BE82FFEE7C2A
+:10D1A000320D85BEB7BEA83DCB56B7E2418BDC7CC5
+:10D1B0005FEBCEED7BB5C100F7FC2733281E74541E
+:10D1C000DC137774D7902D18BFCE4D93C5B891A3BB
+:10D1D000288F381FA4C3EF3BDC2C417AB8CBC5EDB8
+:10D1E0009F3903F71DA2823F9CF37AE9C534EAF721
+:10D1F000B60715F29B66012E9783CA8DCEBB93E2CC
+:10D200002ACE79DFF676FB4BF930AFDB5AA430FA41
+:10D21000A1D8FE5E58EF4597AFA438A213AE59319E
+:10D220007BBEC89CF6BB346266A56C7A2EF4F369AB
+:10D23000B344F23EA7D9DEEE8E8ED5D4DFD39DD394
+:10D2400034E4E3DBDA1CEFE75DF59FE887DDE18896
+:10D250005B3AFD267F9AF09726B00BD15F3AD979D9
+:10D260002DC51F075A8F5B7ED251F0DFF120D51FED
+:10D270006B3D541EABD5A93CE23378FED0EEBD2FFA
+:10D28000918E50BB26207F3DDDF987B49BE1D5D23E
+:10D2900010F7DB2FD9F249C3738CE23F0AD723265C
+:10D2A000E9915B041D2E651EC30FF37C5CC4E3C6CD
+:10D2B0007F0EF514F84EB649B47E032DA0639ECFC1
+:10D2C0002D888FB1D83FF7D76FC17B79CF00F7E8B2
+:10D2D00034FB7EDBDF0BF740DF2D52787EA6F3B9FF
+:10D2E000251747845FD3B0E707D3916F8EAF91685E
+:10D2F0003FEDB82BDE44F507A5709D41D33E8C7AF7
+:10D30000D7E253D0201ACAB3931F2DBEE8E5BB8ED7
+:10D31000FB082F163F801C85449E5348AEEC87FFC8
+:10D320001C7CE6E4ABE3AEEEA128F74EBE3A3EC06D
+:10D33000BAE4D234BE9F3FD730A7637CE536166986
+:10D34000E2E701CDD7FE11F0587C54CE6356981712
+:10D3500066E27D854F9FE6EB9EFA5DC50FA0BF3C60
+:10D36000EE97AAB8173A46ED2FC17FC218E38A8D0F
+:10D37000EB7E56C1DFC39B3EF8B9E4E5D30FCC305A
+:10D38000CE8E27277E7AF55327DF5FBBE4B47DFD81
+:10D3900033BF63657012EAB3835C8F971F549DF9A6
+:10D3A000695CFFFD74C773A88717FCFBDA2083F262
+:10D3B00043B56D10D263C7632B8226EA63351644EA
+:10D3C000FC7E1857FA3D8FFD429A24E242F6FC3962
+:10D3D000985F0CE3E2F3DF70C7EB607E4B9E74272F
+:10D3E000D07E2E3EB080E80075B2A78B77F59F3FC8
+:10D3F000B7E0890707193C8FDE9E47F7988BF60B3D
+:10D4000017C3FA0BD9F8AC7974EDCA2C2DBDBFFC4B
+:10D41000BC1E0DF5C812B14E5C72E04AA2BF338F3C
+:10D420006E9EB03F4E79FF9143DE013FB42E8CC11A
+:10D43000BCE84E9A38B74B0D3F72C770DFE2C33776
+:10D4400073B7E07EF1B1C77E19C4F37596FC5B79C2
+:10D450006CC7DA8BCF781FDB71A127ACFA40F97566
+:10D460003B802F10EF0B01EFE8D72C3C24A79561F0
+:10D47000DC628B8BE6F5DC917D83C640FDCE9DAEF4
+:10D48000EC191C1C3FDA2B8B6EBD798E824E0B9EE5
+:10D49000F9B986F996BDF98E825E77EEDCAB21BFD5
+:10D4A00038F13AAD7DAFD6EDEF876EEDEF4EA7F3D5
+:10D4B000B43F3AA5A17FF2E18B12CB2DECFBFDBC72
+:10D4C000C77F19C47667A3DFB1C7B81D3DD621C594
+:10D4D000A5C2B3D3B105697541DF7DC0D854568A62
+:10D4E000F76D3668AC14D72F31D91746BFE96C7980
+:10D4F0000D37F80BADFBB9E8BCEA3DFB19DD3B4746
+:10D500002744A17EEA2546F77FBBB20D2595AEE103
+:10D510006932F91BBD79044775E20B26EE1B3F29E2
+:10D52000F44CBE9FFB1BE3BA4B7F80F7B2BA3A5D67
+:10D530002C6E24F7D54F1EE6723FA153A175C3731D
+:10D5400098172AE1FEB9DC7BC70ADF3FF731238554
+:10D550006FD34A336DF5468413F733C4FEFC78FE6F
+:10D560008A05C2F9B67EC68BFBDCD32B8B6CDFB38E
+:10D5700083F67D758417E77761829FF39870D8BE34
+:10D580001FA4083C4E12F40A2762849FCAB7ECED30
+:10D5900026F9AB294E33E92C719AFBFD62FF279FD8
+:10D5A000E5A31C528E09D2312348FEAF4BAC13F0D9
+:10D5B0001E35CCE73BECE7F6319C267F62E03988EC
+:10D5C000D6ACE9780E223C5EBEBB18EA97FA874DCE
+:10D5D00057416EC317C9CF14417D8ADFE0F5F3E5EB
+:10D5E000F12ED0A45B58E1F42A68AFCA122BC7FD14
+:10D5F000C37C8DE2C2AB35903B909BC62033338019
+:10D600006FD3DC2CE62DC7F10C1A2F0D162E5ECC35
+:10D610003313F16435C8BF6B74F1EFCEB53FAB9FE8
+:10D6200072D5A07B45DD25006B61729C7295C35F4E
+:10D63000E6E7F71BAB53CD10AE73D44C2DDC40EDB9
+:10D64000B81C9C6B097A7228EAC9377D5C0E14E518
+:10D6500024E565F7FC731AC5D9DFF47179F87A7A95
+:10D66000ABEB3CA8977B86DE8DC2F5A6B4FD9B2470
+:10D67000648168C44FF681D1B9E99BBFA1D07D8494
+:10D68000CC5F13407A4826B7CF1210E316CC379DF3
+:10D690001DF6A8C5A8CAEC796FC9F1CB7B12347E00
+:10D6A000C0363E2C1B3D68FFBF8E67880CEC1FEA1E
+:10D6B000C0CFAF57F2FACC785143B741F399E54761
+:10D6C000B972C787601EF5CD72FC9B3C2FD09E2798
+:10D6D00076DC27E442DC33862A14FB398EE301DF53
+:10D6E00056ECE6FE8425C74B3EE6FE00EBE276D61E
+:10D6F000CACFC1E9207C4C393D08DB7D7A50A67B3E
+:10D70000A1CA0FD8F9FD22911730F1208F034C7474
+:10D71000F0FD45BBAFA23CEF8BCEE27FDFEB17768F
+:10D7200049C8C3B9E67DED93CC7AA4D30C9599A9E9
+:10D73000BF7FB0542C744F1E2C4AC7F8D43B69529B
+:10D740006F7E22E64B6A20EEB81FBDCB619F2C7E18
+:10D750001C73589F83F31E7398DD2AF2EA6C794399
+:10D76000BDE3E81CBFE3D8D81FE011AD3EFAEE28B8
+:10D77000D777D67C2DBD9761DAF55D56B55DDFE5CF
+:10D7800044ECFA2E77A65DAFE545EDFA6CF0BCF3FC
+:10D790006CEF87D494DBEAC3964FB2B52F040392A3
+:10D7A0005A2F6EBED2D67E78DBB5B6FAC8F537DB17
+:10D7B000DA8F8ACFB6BD1FFDE402DB7BD0EB0AEA2D
+:10D7C000AF81F4F498F6A5B6F6969E3E7FF7776C97
+:10D7D000FD5A7A3A067F912FCB51F5025EC322EFB4
+:10D7E000EA6C7AFAC2EC1872FA57D6D3BF76E8E937
+:10D7F0004FD98C4A46FBCC7C3F7B20BEB4CED32A8B
+:10D8000069DC6E2AE972CD4E28AB841EBFCC2FE2B4
+:10D810006B3AE793137B46521C1BF3EDD08FB1ECB0
+:10D82000F80997BF19E35119C053A86706B2EB195D
+:10D830001D2F53BCABCF3927D9A078E03A2542F948
+:10D84000ECB0162D948B93F77DDC2FCBB7A6C67D5D
+:10D850004FF8B99C9C10767C23E873D4DF83D3C047
+:10D860002F2EA7EF6CBFF710C4DC5E3AB7FE9DA663
+:10D87000AA02BCD7ABBBD4C80091C2FA90A4FEB335
+:10D88000F41DE8D9F1B4CE0D44FF0BF519E8B12130
+:10D8900068FF6766D7B8248071B087C5304F19F02C
+:10D8A000772BC6893358B6B4B40CE39DBD7AD5F84E
+:10D8B000129868FF82D1940F7E72DE28BA27EAA4FC
+:10D8C000BFF7FE18CA73614698F6E76E12FB6E2723
+:10D8D000E71653BB37BE01D20BFCF82B8400ECE3F8
+:10D8E0001B1AC7C3D9D6B3F3B63C10C07DE9374A7B
+:10D8F000F9FE9FF5BC20C0D7110501BEEFB7646EDD
+:10D900001AE5FB2E8EBB685F6809A207FDCF38972A
+:10D910007BACE3FAADA5716D04E9619D2FF374D67C
+:10D92000C4304EB0A4E31ACA9BF8FAEB7CBDFCF5F8
+:10D93000FFE2711E6BBCD1017EFFEBE800DF97BDFB
+:10D94000110A3C3F7D23D02103CB97274F473982D3
+:10D95000E70909EA5777822B01F8BE265AE842E424
+:10D96000FD96855F7B16A63C2160D07CAF671117C2
+:10D97000F2F1EF58F4E3D70A53FAB3FA8149A11D43
+:10D980007F3D23E61A04FAADE76289EC178CE7C104
+:10D99000E7915B06AF4095698D67F5732D0B53BF1B
+:10D9A0003730D325FC189BBE5C3A3F2D9105FD2DE9
+:10D9B000057F1FE3B227EA7AFEF55B30AFDF2FF871
+:10D9C000CBB378E53D8B760FC175F04DEB15660056
+:10D9D000BD7FED332F0DA0BC54669DDB395820630D
+:10D9E0000CED2AE3E3BD2AE83DB3236BBCB0EF574F
+:10D9F000617F6FBEB86308EA915F8C7A6238E55F39
+:10DA0000579C5BFF967CEEECB5B7DC1E8405BF81AE
+:10DA1000BD20BFFC04F385D14F1E486E770ABB7C46
+:10DA20008F62923E392547C43900582642D9DEA17B
+:10DA3000308C77B7835F84721C44A1B6E40F7C847A
+:10DA40002026555ABFB702EB95D1423E6FBBEFC5BA
+:10DA5000E98DB45F65F7032AC4FAC8B2F711F88BF1
+:10DA60007AF522E1878F5C6F5F6F4F4CC8B48EE907
+:10DA7000B5F34EFB8EEB9673B0EFCB035FD5BE478D
+:10DA8000EB0280EFF652AED7DA133E9E978B3F152E
+:10DA9000342669F79DDFAF0C703D761FAEC5E1FB04
+:10DAA000AB1166A8A7817E09F0731331A59CEACC5F
+:10DAB0009F49F9D6660EAFC7D2A1FCBDCEDB6BD2B3
+:10DAC000F1524F06DEF3B0BFA9B900CF5372FC622A
+:10DAD000BD01FF6D8C273DB3D4D23307CEE3F726CB
+:10DAE0009E062811EF625DE49C5F05F035378642A3
+:10DAF0002EC4F78997BE08E23A7447A6F1EB8BD0A3
+:10DB00005F7C4561286F5EB55BCBE807CEE7506F61
+:10DB10008D04F90C707DEDD92DD1BD401E83AFE78A
+:10DB2000BCBA3E8EEEF38CB2348CF77CBCB398D684
+:10DB3000775707B9DE8AA5459E4239F8A3746882F3
+:10DB40005E4CFED476AC5B786D4FF0FBD9C7A8ACC9
+:10DB500059CD4CE2D51A7FC9FAF1B4D9B1787D1606
+:10DB600095A3705D0F8F9624387CC7773764F617BE
+:10DB70001F18D331FE0E5AEFE6F67CF6EF9867F4E5
+:10DB8000138DF675F1E8039E5FF9F1E7A3A9BF03D2
+:10DB900001BE5E85F1557C8E3FE486F7762D71736C
+:10DBA000FD78FC7385DAF5F6BB7B8AA203ADCB1258
+:10DBB0006DFB703DE1ED701BF47B298FF1FB16BD11
+:10DBC0001D5E922355EFF900D7036A875B6F007CD7
+:10DBD000ECF0F5BC83FCD5B3C76D6C85F73BB43670
+:10DBE0006ADF339CC9581F05FC81F7A779F5369683
+:10DBF00099028FB7E30794D7047C41F72C79D53687
+:10DC000076710A9DAE0E0608CFFF11E0FCB4C397F3
+:10DC100090FDBC5FB695E6959C27CE0BB7C7F83C48
+:10DC200047511C648706F3CCA679E9C807A3189F5F
+:10DC300027EB1869E03A5185F9D03AA984C9A81AA6
+:10DC40009CF35A3296C551DFDC5FCF6CBF1BB5C465
+:10DC500097AC7B40B676145976FDF326FCFDA464A0
+:10DC60001D145E65F2FBFFBAEF8BA6C6C929F2A3AD
+:10DC700072796A0A703B66C911E201E37103CA9BBB
+:10DC80009FB72BDDA27E82F0EF4CF8C374CFB8B8FB
+:10DC90002FD98AEB2C93121F5C8A7E5762DF5803C0
+:10DCA000E6B4F0E51786E2D1C23BE58E87C6C0FB3D
+:10DCB000FBB4A82B08E3FEF42D9905010F7FFC911E
+:10DCC000373E03FA297D7ECB20DC8F71F6B7F24810
+:10DCD000FDDAC1E86F3D2F19185F3EE1EAA138EE89
+:10DCE000E28EFFD4306E78F9EE7735F42B3607A349
+:10DCF000E9D86FE5EEBA6988C789ACAD01E375A0D4
+:10DD00005FE95E96F61013F18C115BEB50BE7AA2C0
+:10DD1000C3902F2F147265D1A143C8E78BE85740F9
+:10DD2000F9ACF06B9EDD7B53B19192471063FB28F9
+:10DD3000DE54CF0E0C467CF7FA6371FEFB05A37F21
+:10DD4000E7B9D54CE1BB7141EE478E13E3ED0D46CB
+:10DD5000870781BFEEDCFB9E1604B83E927AA6E3ED
+:10DD60002B90E711C194F5513BF847A9FCDB479E86
+:10DD70001DF2B444EDD1284E7994DF830FF46E4C3C
+:10DD800007FA3DF5BBDDE7D1FD2A3D917F423C7CA2
+:10DD9000F69A46BF0FF4ACF07BEB5EFB6C2CEAB15D
+:10DDA000CFF6DC390CF1971BE47E0BF0FF541FCA51
+:10DDB000D94E467ACD92D3329453984A99CEF737BA
+:10DDC000CB90FF0B91FFBBAE24B97C56665C0EB9BD
+:10DDD0003C00FFEBA82FCA749007FA7E24C9F98E85
+:10DDE0002E99EF23829DC07DC81D32A016F8ACC2CB
+:10DDF00095D887DF55C0B87506CA6B970FF334D82E
+:10DE00002E391BE38B15787F740A5E9A02419A6F54
+:10DE100093F0EF1E1676240D377553E422C5FEF2FB
+:10DE2000BAB0CF3FBCFFBC95EB30E9D914F641F84E
+:10DE30003D2C3A9EF4FDDDC2562EFDF9A4ABF1DE79
+:10DE40009AA5AF2AF47E8259330D432195D56DFBF7
+:10DE5000B19C14699F86E156B417F87B7917406925
+:10DE6000825E9D3CB36B3F3F8B6B8E463F69D7BE56
+:10DE70002B46A39F70E20D37FDA6C5891D573E8531
+:10DE8000FBA627DEF03259EAD78FB1F199B33C21D6
+:10DE9000750731AEB42C38E97215D6D28B2772389B
+:10DEA000EF0A56AE8CC1C43E0B9ACB90AF827A94E7
+:10DEB000CA1387BE1884BAFBD9C3EF05D1AEEFD21F
+:10DEC000CCD13A95FCFE4967FFB383FC1EE40AB14E
+:10DED0008F89F284FED2C7EBB3B6A03C7DBC4B3138
+:10DEE00007E1F9E7A0C80712EBC7DB38DAD8BC5D59
+:10DEF000DC9FBEDDE4F1DDDBD0AFC1FA3AFBEFFE23
+:10DF0000CD637C3D3522C628BEB4B85DA2733E23E6
+:10DF1000C5F99D25621D39CFE1BF2CB4E2B28EF860
+:10DF2000ED4211A75D789675E34341E1EF14B362CA
+:10DF3000F477802F68DDDAF39A12DECAE89EA54EE8
+:10DF400037CCEB29713F27E845922BCBEF99A49B67
+:10DF5000BFD779DE0DB71B625DD7B3438A931C3CF4
+:10DF6000C9E8DCD9A4A3C616CA6B889974CFF83C5B
+:10DF7000A1E726897D96491D852447F384DF5769EB
+:10DF800072B86F07B8E3644E397C605EC90F9C7449
+:10DF9000B44D413C2DD824511CF4CE279DE7F839CF
+:10DFA0005E16AE3FF412E64C2C6A77BC1F208EFD45
+:10DFB00034FEA39FFD889F59781ACA86A6FA85ACBD
+:10DFC000B3FFDF9B48EE3FC4481E3F12E7737F2339
+:10DFD000FA873F7ECCCFFB83C0C3EB827F169B9C2E
+:10DFE000FE0BE34A3C0EF39923F885B5727EB1CE61
+:10DFF000C5E0FE0AC1BF4B621BA4BEF0CDDBEE2222
+:10E000007F7881C083B55F376F939DEF16083C2CF6
+:10E0100070E0617154B2CDC3F2CFE708BE1E785EE6
+:10E02000ED37223D176C77F1DF6E524ED33C3FDD6A
+:10E03000C5E9E49CA7353F6BBE7FEB3C9D74EAB11C
+:10E04000E8741E3BCF46A7EA33DFBF90BC97C8EE0B
+:10E05000E75A7EB2C517CEEFA70BFFF8F2F5DC9FAB
+:10E06000DCD5B5AF19FDE1F23D8A8EFB8EBBBA4E11
+:10E0700006713F68FC1E9EB77EA263FC6ABC9FE3EC
+:10E0800099CE92EB304FB7FC904CF231FED5F2387E
+:10E09000A64497BF5A9E564CFB724616AE1B4E1CAA
+:10E0A000E476F5C4C192DFE23ED389CEAA0A446B7E
+:10E0B000DDC1F234B4FFCF30BECE975EFDF3AF705A
+:10E0C000DCF1AFA81330EED7145248AE2E7F78D6CD
+:10E0D000365CD779D2F93AFCA5AEA5D7233D161DFB
+:10E0E00094757C7EFCA04CED16FE50A1BC53A6DCC2
+:10E0F0009BFD4F48AF0E97CEE7EBA2F197EC199E30
+:10E1000035C79FE483D9826FCB338C0766A09F9776
+:10E1100097467EF1E5435C64178FE5A73D8AFECD07
+:10E1200008730BED231F7BE16E19C73DB1436221DC
+:10E1300000E0A5D0FE7FA5FB4A9E3B44FB5CD37666
+:10E140001DA27DADD9D6BA4FECD75A7C7507AEEF7C
+:10E1500060FDFA71974FE483B46948974587AC7ABC
+:10E16000B786F63B22FCA2C58FBD4BF505E8E72339
+:10E170003F3E2651DEECFE3D3F257E5CBC9DEF8F91
+:10E180002DD8BD653AB6BB93B5D33EA7538FCC17F8
+:10E19000FC79C77AC773C18FF3CFC28F53D3455C65
+:10E1A0006E141B45F7814CE1F78BB427660FDB013A
+:10E1B000F33879C44D7C7106BE24FB7750C47D4E84
+:10E1C000266413F160B53B7EF0A486FEE3F48E3F37
+:10E1D00011FE6674ECAD42BC7C8D4517229C5FEB52
+:10E1E00048D371BD3CA39BEB952B3BDC6457BEC66B
+:10E1F000DA1BC5EF3D931EBA43D0F30E81FF132FF8
+:10E20000BAF93ECF0B12F9277780E2CD0255B7500D
+:10E21000C485D9263B7D40F2BEC1F70BDDE45F5DCE
+:10E22000556AC7D7958CEB932BB74BA44F168B75BC
+:10E23000FA55CCB81A9F5FD589811918372F6D26EA
+:10E24000F2DBC2ED8EFD66B17E5FECB07FD7A773C7
+:10E250007FED6FFD5D866FA60B3D21E832A387C77A
+:10E260006BAF447B0378E84CD497613CCAC293936C
+:10E270002E9DC699F7937F25FCE9DEF515080EFA69
+:10E280006DED3AA7C32B5D3994F7B460A21243FF3A
+:10E29000E1AD74AEFF17FEF5BAAB3141F698BCEFB5
+:10E2A0005BDBE1FD47B3DA47205E60FD705F3ABC9F
+:10E2B0007FB9604EEB38F8FE8F3B5C61D42FCCDC2D
+:10E2C0003202F5E5CAD00333707F6BC976FE7BA8B6
+:10E2D000C72B9518E953B5673A8EF7D11E49477D8C
+:10E2E000BC64F7277CFD80FC0265A443BA0CF905E9
+:10E2F000FCF287B1FF8899E1423A2EAE027D0DED26
+:10E30000AFA9FA93867805FF7C437A8A7FFE4A4953
+:10E3100031ADB75F510DBA477220FF7CF1E7DC1FCA
+:10E32000B49E2F0639457C2EEE90681D9AF4077333
+:10E3300025F207F7FCF44026E9898C71489E57D2F4
+:10E34000F9FA01FD06F44F6F17F687498D2417BBC4
+:10E35000F67D7823C2D7F3BC8B9FD984925D08FAEF
+:10E36000F137FC77C18E3F27D1BED11D3ADF273A66
+:10E370003E9BD3F933F06F40E3B3DB851DC3F71841
+:10E38000EFBC1DFCBB4BCAF15737EBC53AA7914A0E
+:10E39000A7FCCFDBFD68135FE6A73C077E5924F896
+:10E3A000DAA9471609FE5D7496F8D3E8177F5A84F8
+:10E3B000F479CBC19F00CF6AD4AB275E51748467D8
+:10E3C000D7BEBF6CCE473F0BFCE822D4DBC20FD9CF
+:10E3D000B5CF4BEB8A1387FC71C4E71F051F1E13D3
+:10E3E000F1E2BA4A85F0234FE4258E87F43DB1E788
+:10E3F000D4D028E8E1A75EFCE97926C5E3E244CF62
+:10E400003B9FB4E7D72D6AB7E7CFC1BCB87FFA3BD3
+:10E41000BEDF04F31A81E7EDAC793DAB7607C3FDAF
+:10E42000C88F24ED23FAC9927D1DB9E479C5767FA2
+:10E4300011C0732BEAB7E3161FA83D83D02E9E4C64
+:10E4400037687E751D9CDEF21E5EC2F837F2F888D2
+:10E450008BC6EFF37E6A6C21AD030BD3685FB713F5
+:10E46000D6FBE950EF3CE225FFF35BBF593032F5B4
+:10E47000F71C98C4D7BB4B5C3D83687D7988DFAFC0
+:10E480007425FB13E5795CD9E1CA064CB1978A7E05
+:10E49000A6D27EC658895D00FDC470DC5CC6FE2F26
+:10E4A000ED2D8E7D008000001F8B08000000000015
+:10E4B000000B8D566B6C5365187E4E7B4E2FEBDA3E
+:10E4C0009DEE52C4112C63ECA2DB38BBC0C64D0FCD
+:10E4D00043CD8253EA70824AA4A2C144D92A12755C
+:10E4E00009269C328980FE20FAC71FC61C49349A2F
+:10E4F000A0296EC3FDD8964E87B0E1CC1490B11818
+:10E5000033F66368C2DC349185C438DFF73B2DDD18
+:10E51000CD689BE6EDF77DEFFD79DEEF1C87D497A4
+:10E520008B3B80831976600D1059670B9925C0616C
+:10E530001C16FBED3F6CF594660393DD39E5F62080
+:10E54000F0B7CF06E4003E35E45649765C1AF38511
+:10E55000D3019CCF04960233FCB96FA1040C611760
+:10E56000E9562057016DC34EB35E026E764FFFF839
+:10E5700014AD6FF6CB1AC87FB4DB696450BCC88891
+:10E58000DB74AE20B3707875C80BBCDAF37C21382D
+:10E590008E4479D5907E4FFF5161774651D97B5398
+:10E5A000F7E50028EFA68E35EF1AA45F3958F15031
+:10E5B00090D66D5D8A0ED2AB18AC32DD14AFEDDBB8
+:10E5C000AAAC95A56CA179D86F53BF1C32D359560C
+:10E5D0005DA8A7B84D83B555128719ACCA1A25FB9B
+:10E5E0004A09A1189D4BFDF9629DAC27A85AFD9AD6
+:10E5F000EC75EFD6695F429EC8CB867C21937AFB8F
+:10E60000DACF3A38EF7D9D76DD9C659FB4AB5265DD
+:10E61000D1971A3528643426E9A8263FA72DB9AF2B
+:10E62000B32DC075BCA8C4022AF9899E52ACF3CFA1
+:10E630002C099C1079181AE1B204B8C05B84C3801D
+:10E64000643E074A7140C14ECE7FE06AF8AE4C96F8
+:10E650009BC3852CBB5449C44BE663A056E40DA96B
+:10E6600041E03ED1AED4715FE6E3D891B0F365618D
+:10E67000776891F34F559BC867AB03618E0BE8E950
+:10E680004BD702DFF15F2AF191BE17EA551F7040A8
+:10E69000B578741121052BE9AC46191B2D0242F403
+:10E6A0009DC9031A10CA8853A8C2F7E4B15117C410
+:10E6B00067867EDBE9D742548B1569391AF96FC436
+:10E6C000DBBFDBCB48F66DBD0E92DB1F5674C7EA8D
+:10E6D0007FE7E1F63A658EBF46C822AE5813DF5A8F
+:10E6E0007EFADEDF57943ADFAB7AB3C73DF4A7007A
+:10E6F0000533D44FD8D33D12F1E4CFF38A6A677E55
+:10E70000C2CC0F952E8C337D68C8DFA700DF1CA21A
+:10E71000B20B693C0EB984FC4AD2232AF5A75E8667
+:10E720001E5BA47F6F7A25D1BF68F195B251C6AB4D
+:10E73000F7EAE77EE2EFD45537F298987F5116D486
+:10E74000CF263591E33CFB281A048E87F1D81C1E96
+:10E7500026F19C00EA62250BF13C96C0A3B9C8796A
+:10E760008DFBD96C9F72302EC78EBE13621E295D41
+:10E770005183E33DE908CEE14D73E77E844B385F7A
+:10E7800027407D997840329D92C87BB953E4ED448F
+:10E790009EE8D3D0077E3A6F1C76E3389DF7165F6C
+:10E7A00071F03C11F12E2140BCB0CA41537CC8A18C
+:10E7B000D2FE36978533F385712D687FE60812FB0C
+:10E7C000AF57D03E71F4DE8A59FD48F06B5BCD5CEB
+:10E7D0007CA3C834C45C4AD9421662E8C15CCA63EF
+:10E7E000872E6926E93FAACFE783C5A7869DE567FF
+:10E7F00073B0085F123C9BCF9B5E357C8AEFC3C928
+:10E80000A13F1E2F25BF03C5D797735F9A1373A02F
+:10E8100015063B4729AE76412D6F259B88C757A625
+:10E82000124FBF4CCC4BC4B3DC04CDC5FDDE7087AA
+:10E83000F0638EEDA5CBE4B69F8DAA2AF40614737F
+:10E8400019DF03C9F9D396A0727FFA6C3C2D1C3BEB
+:10E85000981FA48F922C60DD7FDFCBD1E273658C93
+:10E86000C7406F7F9963166E375E0E1772BC48F70C
+:10E87000D78160FA6C9ED9123C938594248B7736AD
+:10E88000692EEF6E30EF4A585E0E6C607EB46FC931
+:10E890009182A9F348C745DFAA597E27BAEC421FE7
+:10E8A000F26841A377769E47449E1331CB1F816D5A
+:10E8B00030DF9ACF94AF3D6EC160D8789DBFE763DB
+:10E8C000E617D02AF4937C752B869E4BF52878C9E1
+:10E8D00060197340D81B3D4EF3235A4FD2ACF273EC
+:10E8E00062F29AFAA121F8BA0CCCCB33095EDD4A68
+:10E8F000E0544D9712F3721D62769E8F6AC8D8C598
+:10E900006B197199E44698769E976A39DE2B958942
+:10E910007D43269E6EC2A8D8A75264B6DB8CA0CCDD
+:10E92000EB2D305AE9E181AEF62FEC7CCDC403B279
+:10E930007F9CF8C657CD6278A5FA21633CC93F5247
+:10E94000D69CC4879254DE6B252BEF6A1DAE168AC7
+:10E950009FE7B7E67C0386441E9AC7AA77EA16CCDF
+:10E960009312C4A36417E96D905167A73A36C97032
+:10E97000A5D1FA749F4DCC75CF68D0E4FB4ECB4A3D
+:10E98000D8FD4A762B5275AE27FD8C4C5EE3A8224B
+:10E99000FA135FB4DE1CFF0A910779789AFD6CE9DF
+:10E9A00072E2386DD95C869D799EEBB7F0F250DF4C
+:10E9B0007CE467FD0909C39487B6D2AA2FE97F3D9D
+:10E9C000285E05EB5B75D11AC3B4EF7159763449F3
+:10E9D0002AF7478A076C339EFFDFC7C90044DEBEB3
+:10E9E00067A77E3BC875763BD5939492D6756E58D3
+:10E9F000A2F994741DDC4FCD951EB7FB1830F9C6F3
+:10EA0000EDFB819E5BABFD7B4AFDC41329A88A7E8A
+:10EA1000228C20BF672CC1FBEAF83DFC7E407AD4F3
+:10EA2000C391345F19322CB87E21BC76247836929B
+:10EA300066DD039F980D41E6F3CE6C97C67DAF70FF
+:10EA40002DAF04F987375CEAA77A47A453AB843328
+:10EA5000D95CC3FEDFB0C7C07D9E765B7EE9ED4129
+:10EA6000F0B4C565AD5F4BF39D6439EDB6FCF30CB6
+:10EA7000326F3D746DBB28CFB7681E5CB4366A2D0B
+:10EA80007C8D9FBD662BB576DA161264A4690ADA0E
+:10EA9000C8BF5C8B7835E525DFE910E74EAECB9338
+:10EAA000AA2B193F59DFFCF85CEFC664BDB6543E93
+:10EAB000C9BA17C63794BBADFA0F8820DEF01389A8
+:10EAC000FA5F116B98ABB87E0FF41AF11E8138F81B
+:10EAD00079A026FA99EC83CA78114FA1135E49BC3C
+:10EAE000F3527D782BCDAA5F2164859F20E156BA31
+:10EAF000B0BE7F00ABD1094D300B0000000000001C
+:10EB00001F8B080000000000000BBBC6CFC0F0A3A5
+:10EB10001E81F5B850F9E87835072AFF1D01F58404
+:10EB2000B00A0382FD929D81E13113042F84625764
+:10EB300020368462566608966741E8F1646360088F
+:10EB400006E258204E67C36F572D0BA6D81539061D
+:10EB5000860C25047FB72403C37F202E94A2CC5FAC
+:10EB6000A37868E0F786A87C7F6D547EA22E0343CD
+:10EB70009D11821FA04D9AF99F817ABF003100211B
+:10EB8000F9ED9E6803000000000000000000000096
+:10EB90001F8B080000000000000BC57D0D7854D5C8
+:10EBA00099F0B933F7DEF9C9FCDC8449988421DE99
+:10EBB0008404220D38A401631BEB0523C696B523FC
+:10EBC000756DB4964EC25F94BFA05B495BBBB990B4
+:10EBD0007F0C6494A8A068072C2E2A6E83EB5FBF7D
+:10EBE000B57610AAB8F5EBA67DDCAD76D50DA89468
+:10EBF000AAA5C15AA17DDAF2BDEF7BCECDDC1926E4
+:10EC000060DBFD9E9D3EF670EE3DF79CF7BCFFE796
+:10EC10003DEF3971F94A59E802C6CEE0EF32C67AC3
+:10EC200014F6AC14644C61F3FA9A75A833F81533F2
+:10EC3000D68BE525F05FD221B3798C7919FF39C3E2
+:10EC40008E23AED98CAD57A171213C8814507BD94D
+:10EC50001737790B591F75D33FCC33D332EAEC8C7D
+:10EC6000F393D4FF3823B36EF271D837192B62ECCB
+:10EC7000EBE21DFC0CAC37888A351FAB645195A5BF
+:10EC8000AAD2FD34305ED71D123B23E1D3CCF7D698
+:10EC900038A73C81D90CF0D1EEE6E5066F603796D7
+:10ECA000A73CA549160068A57835B63317C027B527
+:10ECB00050BEE54F76527F6D17C5663106FF6E1A5E
+:10ECC000F6E580876D626C2EBCEF18DEF64E65FAB5
+:10ECD000B933124D613FAC8E45F7004A998FC93860
+:10ECE000AFCD9235CD51D319026843D14F6F86F71E
+:10ECF0009F05B871FCF56AECB31C2F068BF9F1FF88
+:10ED000075EAFF807FDE6B7168FF61AD1A75C12304
+:10ED100017D37F1E2F636CEB25FF1906C8994B6E26
+:10ED2000631AC0E7AA60C670357EFF6D86F4FD1DCC
+:10ED3000E2554FC3F579E6A0FED2F067E2EB65FC41
+:10ED400007BCEFEE48A52A14C6B64CD507EB615CAC
+:10ED5000F3FF3AA37BA8D548130BE1B8450E9C4BB3
+:10ED6000B7027881F1063B584286F9DFD1E1A6F27D
+:10ED700032564EFD6CBD64FA6484EFC025D383A384
+:10ED800050DE31CBDB9424F86271EC674374F853A6
+:10ED90009B611E4AD16186F8387564FF67916C9754
+:10EDA0002151000F52919BE8B121C0922E9C6F1906
+:10EDB000A743C32C999E2B756C978B70BA9EE66BFC
+:10EDC000F151A08E99D390FFEB4D03708FE331A4E6
+:10EDD0002360D4576CE37BB90EE866F1254DEF2A2A
+:10EDE000EA47D138DEBCD1F8220405E845F4605585
+:10EDF0001C5F1AFCEF0C4C31EFF76F3319E93C95AF
+:10EE0000B1A7902EBA0D9FF09F930D9C74CE4639FA
+:10EE1000B43D877938DFB8EA57D8AF33EB79DE9F56
+:10EE2000FE2586F3DA5A778B7723CECB7963300EC3
+:10EE3000F0E7D571F9CC8B07120D9F4ED3CFF7C6F3
+:10EE4000FCD421DB789DCC1F3A9607FFB8985D4C27
+:10EE5000FC2FBECFE65BAB3CD561A40E29346F8797
+:10EE60005D0E276ADFD9C1586A46BADE556684014D
+:10EE7000156C1BFBA22183BEE8528CB0148576E58D
+:10EE80005F301A41CF3867A4C251187F201F3A2D36
+:10EE900061EC41734DCA84BAB3B38D9EF7E2D89F3B
+:10EEA000B13DBF3C168E027F747B385F658FFF5F7C
+:10EEB0008031E22BA52DCCA6A5F505810DF8776B49
+:10EEC0002FFE5E02BC6E95A2A747518E8B03247F56
+:10EED000F0BE4F2EA0B251ADC1C66ED27F1EC1078B
+:10EEE00050EB926BA86C500B705E6DAF3523DF1743
+:10EEF000FB38DF7F60849BA1BFFEB945D1CD367959
+:10EF00007A9E49C4A75D0AE7CB2D4AA69EF831BE7A
+:10EF10000778FF153800CB2E3F9F17D3B685AF99E2
+:10EF200095A39F7C8E8F7F376F36CD6A9C07C80074
+:10EF3000C251A926F794E16C13E1C5C4C7997A734D
+:10EF4000227A65EB4B7705D4EDFC1EB6BD2FC7FFCB
+:10EF50008F68C43FA2FDF388D44282C3CCB7C3A15B
+:10EF6000DD195E8CF260C2380087274CCC6E6FCF03
+:10EF7000E79982F78867E00DA4979ABFE2704AC7C5
+:10EF8000EF5986FD59AFC69F27BD135C32D6AC73CF
+:10EF9000B292BC99F3699E0AB37E5FCFB4179719FA
+:10EFA000AF39515EE6A8FA26D42351352505F8ABD2
+:10EFB000B179A8DDE087CFEB7A4624901FD51730D2
+:10EFC000F302D89F90CB70A6BC9E4F5EDAB3E4EDFF
+:10EFD0006496BCA92C164C217E128D244F0101A7EA
+:10EFE0005AAB9A389ECA0646B01C97BBCF2E0EA2CB
+:10EFF0007E5235F58813E052C349661FBF0FE5CD39
+:10F0000005CFA5D89FC9CE041FA4F7B26A865B506E
+:10F01000EF94AA422F8F66F0D3CBA8E7810EDFC111
+:10F020005773F1FF12A28C86510F7677B4B3B741B4
+:10F030004F7B5FB889E9B3D0FE31F20BD4509B61AE
+:10F04000107FD6723F0109817A56ABDA85FA5ED11C
+:10F05000DDCD3AE24DD7AEC192B18DD4AF5235730A
+:10F06000B944CF7B4ED23C42064310E40A46F896A0
+:10F07000B518C10D742E96100E7726FDC7E9AD8523
+:10F08000C8EF80BA1E9B95839FC7FD066B3E4995CE
+:10F09000EBF5F13A9BF03BA0878CFF04FE92C31C7A
+:10F0A0004E39EC25BAC811F9D8A85D2EC4389DF8A0
+:10F0B000CF629B5F3555F035FE428897E84368BFC5
+:10F0C0007A8A178697C2F33A49E5702CCA9C9FF555
+:10F0D0003DCCBF0EE72F6B71C28735EF9EE2E94151
+:10F0E000B493CC574078CF86BF07ECB16CF32F7A3E
+:10F0F000140B8E24F73F4A587212F2FD1F3F5D85B4
+:10F1000072B956D033BB9FDF4C00FF6F7E7025C1B4
+:10F110001F93B81F720EF86352E1D9F0FFE6073370
+:10F1200038FCCF1666E0CB2AD7BA0FA6E44976FAA8
+:10F1300071BD5D2CE8511A19998FE2B0C377FAB509
+:10F1400038D4B7300E7FC2777CA102F56061FC6BCA
+:10F1500088B735ED6D3AF255F132E6C0F1360B3C29
+:10F160005CE18C788E023C773694075BA0EC96B815
+:10F170003ECD86E37E9027E1A75079EA4D0EF73920
+:10F18000EC5D06DE3B57CB8D49E8BFD3F7C44F1784
+:10F1900002FEBA431535E466B64AE4DF79253E9FA0
+:10F1A0000D9224F891E307F0B601F1A68438DEEE63
+:10F1B0005F739DC01FC063C78311373480A7D870A9
+:10F1C00098AE00BA157113F57FB89D814349783028
+:10F1D000B19F3561B6005DF5B5F11109CBCDE3FC0A
+:10F1E000A05D5501EDB7BF5C59B3D946B78312F79F
+:10F1F000FB582DF7EB990C7AC03FB17CF5039EAA22
+:10F200002BB19E92B0DD77B0AEA4DB2D90E27722D9
+:10F210001C910A2E3F91B63115E773C2D2FB2C4CDC
+:10F220007E54D7B87C275A7713BF15CD41B81E90AE
+:10F23000B87E623BA589F8EC815C7212A988A33A7A
+:10F24000645F94E3BBF0BD628E68C80FEEB6312AEE
+:10F250007BADF14D3682FD968CFBDB9CDF03BABEA5
+:10F260001BF5D87E419F92FA9EF50EC07371AD4C8E
+:10F27000F82E196D5EC4603E6EF4CF66D373F2BB98
+:10F2800022AD4913BBBA404FCE479B32438EEFC7E6
+:10F29000F103970E19928E2805B8408EB62B71F2A5
+:10F2A000C355F03B6382CECD36FE7A41CC5B093349
+:10F2B00023599DA6FF0EA7C0927197676535B6F3D7
+:10F2C000127CA5EC5AE287A92C66201FA8693E385B
+:10F2D00080F8D7978D2CC4F1D78647366209FC4F4A
+:10F2E000FEF676C52C4638B6AF51B9BF6DB2578918
+:10F2F0003F1D9CCFE03F9DFC1F51DF2C71FFC48B55
+:10F30000F8C0F983BF8CF6DA353B613840FFE7B7C8
+:10F31000B2287EE645FC04D2F851A249D381FCD93B
+:10F32000C6A20643FD9F38A0EB849FFF40F802A0D1
+:10F33000975509ED41D240DD7BEACD8B1B910E1F25
+:10F34000FA1CCC5996E6C76C3E947D207776BB9C20
+:10F3500065BF2C7BE2F4198CF40E8B92DE776A2C5D
+:10F36000817ADD2DF4DFA7A4D8BB08477F7E6BCA66
+:10F37000CE5F9D2A6B253ED1AFA576FD950B75A47A
+:10F3800013744C76BB3FCBAFB2D6793D1D49B29BCF
+:10F390004CE7764A0D47090E4BAEB3E172B63BF52A
+:10F3A0007726D9C6ADE0F6DEE94E109F78127712C7
+:10F3B0007EE199B0E35176AD1FFD0407F9698F41F5
+:10F3C00089EB024BCFCB216F86FFE66C5733FAB740
+:10F3D000CAD35146EBA3DF26A5A409DF2F0DFF6A90
+:10F3E000A802D60D2DEDC57763B9B27DCE900CE5A0
+:10F3F000D1816901BBFE3BDAB79CEAC776565279E8
+:10F400004AD17F7209F4736C9733BA0907FDE39907
+:10F41000334EE09B16A1AF0EEC70915C1D7B40A2B9
+:10F42000F5D9CA3EC9CC43FF265F2F45FE3FD6BF64
+:10F43000B294E5D0AF2D6F802004F17D5929CBE146
+:10F440006FADECEB5D8FFEC4CAA4621839ECF20616
+:10F4500047342C39D18FA9BAEF1D605D27D21BE844
+:10F4600031D3A1D37B905103FD70E68E92BF3CFF58
+:10F47000ADABC2A35877C42F74A09F7DE4CA308E71
+:10F480007B307F6118FDFC5BDE744551AF6C50DB57
+:10F49000666836783604D438C98F6F28834F2B1CA2
+:10F4A0004A867DB1E03217B0262FFAC901A675024F
+:10F4B0003E1A7C20AEC8EFA312F5DF29F8277BBEE9
+:10F4C0004AFBA7891EE3755F94E9D5E452D33C9CBF
+:10F4D00055BCB4DE1B0EAE1F2E77F0F550A9237E6F
+:10F4E00039CE0BD5487B01C6736A87B8BDF569C7AD
+:10F4F0003E25F0E744F8B4D7709D6DD6A83AC237E0
+:10F5000030CBD2D729BE3E96530CF165C1D900E06D
+:10F510003B6DF04F6427073B4E6F93315ED0C18641
+:10F52000D05E0EFA8719D27D931C253D080BCCC600
+:10F5300069D0CF40B4A006D74F9BDCFCF9262DD56F
+:10F5400078393C77461D35BB75A4A79BBEDFA4A7C1
+:10F55000FAA6D99EF7766843D8FF2623D5676FDFD2
+:10F56000DF11E6CFCD5463596DFA795EFB3C9AFF0B
+:10F570002676A071BEEDB905EF26F6425F59CEE7BB
+:10F5800087FAB07D273E67F6E7870F9785D2CF7160
+:10F5900001837A42A86D361039E46EB1F1F9265F25
+:10F5A000B491FC6814127B3BFD8509DA1959ED26EC
+:10F5B000EACFCC6C5701FDF972B583056546BB43B4
+:10F5C00013B57364B4ABCADDDF4055E6F756097C6A
+:10F5D0007797C326073EC17703B0CE26BE3599FB89
+:10F5E0009BB0AE96EB5957F945E04738B8DD6DB79B
+:10F5F000F83AC2E43A78EFAC60F2E70A6CF1339D76
+:10F60000B9E9791573673CD7C04FCFB00BD9FCCDA2
+:10F61000B67B90BF8B84FC85B8DD3C1FFF821E212A
+:10F620003EEAED18DD86FCA7B04C79B3CA6187F0DD
+:10F630005BB2C68579B26F16D0BC481FB2373CC9E1
+:10F640003D3055901DB9AE80CFF37335B6798461E6
+:10F650007E057C9E19CF2399F3B39E77A13CDAFCFB
+:10F66000AFFF423D87F6205CE3D67D693F69FE5BD4
+:10F67000D78731CED68DFAADFA6CFD36D1FCEFE8E6
+:10F68000181DAAA844793A4E6567B4461B253F5712
+:10F690006629945F3946F2BC418D1968EF3700EC5A
+:10F6A0002680E0AE36283EA15430B438609FC0AF0B
+:10F6B000217B9860E8C778853EF258FAF88F1DC420
+:10F6C000BF9B7D5C343CED27862A72D82F6FF803F0
+:10F6D000B2571B022C9E8B0E071CAAD07BB1238E27
+:10F6E000B9E81755E7D67777B22A8CCF399937BA68
+:10F6F00091F431A7CF87401F8C1B3A7DA62BD77A78
+:10F700005F6E7F7F1BEAE33FA37F3417F17A09E145
+:10F7100075831A0DFF6388EC024A223B8871D9DA9F
+:10F72000F3E357699F427617FC012AC7E91D8A3225
+:10F73000F20734112F0EB168A5CEFD88955CFFB39A
+:10F74000DB6BF0FB52FE7D3C7237E26B22BC7C30FF
+:10F750008E17C3E99C9B031F8FB3D7D03E9DF23316
+:10F760000DE38B07DFBC98C6BDE508970FC00FE11E
+:10F77000EB43C017DA739FA09FD57F7FC718E78F31
+:10F780000EF7DD58FA059E3CBE0435F6D426C6FDBC
+:10F79000994AD2E7A7872A48AEB4BBB1F4D72699D5
+:10F7A00084F4A86843DE4FB7D7A03DC3F7B114BEB9
+:10F7B00097F13DB3BD8F58EFE30CEBAEECF7BAF524
+:10F7C000DE642B511E7C009F5D4F38E2554E905BEE
+:10F7D0007704E0B0F913BE30C767369E0E1D99114D
+:10F7E0001C3D471C68B0431FE2EBC8D3A42F06CBD7
+:10F7F0008CA65835C56BE8798FB0635BD03E41B9B4
+:10F8000019ED1794CBD1E945BAC8DCFFEE63D64FAA
+:10F81000636EA8F7332E1703B818263CC8C9DDE875
+:10F820003FB336F2C7FB64FEBCAF4A4F92FDF68889
+:10F8300076D58CDA597649F6F07E02B00C424459FE
+:10F8400070F7699BC8AE0CE41B06C23B5066BACD8C
+:10F8500010EED6805D936C7A5C351BA95FF1DCE716
+:10F860003563BC2ED7E41A271B3FEEFC4D1A8EE3FE
+:10F870002B30C8CEFBCA4DCDB47D6FB51B50A1DF78
+:10F8800050FAF98037C1C7AD8071CBCE3F4EBF76FD
+:10F89000179F4F81984F79C26DDABE1F6F2727DC03
+:10F8A000B79C639DEFD1816E36BE7085817E1976DF
+:10F8B000264974CBABD2329E076AC319F5836FCE4B
+:10F8C000983C6A1BE7D0E8B473F2D131C147E375C5
+:10F8D0004F7C09CB67ECF9CEE7E77745A0AEC44B88
+:10F8E00025A83F74D7DB1B1BA732B642E891D6F69A
+:10F8F0005F6D437DB76260A98AFA7F65FB6F490E31
+:10F90000572425D2BF2B84BE68315904EDD2634EF3
+:10F910002FD92DCBEE822D27BBDB12CAB44B2D1A6B
+:10F92000B74B2DE14CBBD4B253C98A8F817FEFC74F
+:10F9300071DF1FB2EBB39503B7727818DF875A896E
+:10F94000FAFDD3D83E5EDA04ED1F707A088E63FDAF
+:10F95000334A51EF1E95F407DB314E7F9397E2F463
+:10F96000D9F8B1E28BB8B627BB2BECC78AAC7DAD1A
+:10F97000EC7285B01F4C8E139C7FE9783B9D5CEF49
+:10F98000AFB0EC16CCB769567AFCA3218E8B41A799
+:10F990005BC833E02347DC711C7FA8B7ED78FA0B16
+:10F9A000F1760F8E5388F8E378F8A4DF5BEF7F21C0
+:10F9B000F06E8B935E8878F96BF9E9A8D36BF971D7
+:10F9C000DCDF69F592BFF3B7F395F9D7D1D9A10977
+:10F9D0003AC0BC66D9E896452FEBBB1F097C8EA2C6
+:10F9E000119A7B369DB2F174B4D5EB70C27AF5E80A
+:10F9F000E12B68FD7E13E20BDADDA7EA4B50BFB5C1
+:10FA00000A7C1D03BBD85569A7CBD217EB80DF5A00
+:10FA1000FACAF225DBF850EF09034C2B76E6D72023
+:10FA20000837F5713CAFDCEEB9BBCBA64F00DF1554
+:10FA3000DFA47D29B725BF99F8AE10F8AECEF49FAC
+:10FA40005BAAB8FFDC12CDC2773237BE5B04DFC0E1
+:10FA50003CBBEEA2795E1EF4F8D2785A1A2E263BF1
+:10FA6000795F400FA09E3D06760EE77914FD7CFC81
+:10FA70004E8E6EC5388139E09C6397ABA3EEE8D615
+:10FA8000EB733DF7457F92ABFDDB3BE7069A73E8EE
+:10FA9000E96C3A2D1576DB5C103D9EA4FD7A57B4D7
+:10FAA000139AAC77C62B6568B731F09956DA5F06C2
+:10FAB00081473FEF6DDFEE5FD1BE53969DB7FA2BC6
+:10FAC00069938FDAFDEEC0B2CCBAA72AB3AE325B2F
+:10FAD000BDCCC6B738C23CFB7E5552F011F866B6B5
+:10FAE000FD0765347F29C6D1E6EB26EDAF7CE873D0
+:10FAF000E8AEB289F91C1972DC3ED162CD9D18B70F
+:10FB00003B4EF4D3CBCF19C7EEEA18BDC76E67647E
+:10FB1000D960B8CF2A0BBACBEDC7EE41F93F04FD4F
+:10FB20001CA175E1262BDE26F6CD9319F877B6CF0A
+:10FB3000CE88577844FC85B136DAB7E9F398AFA19F
+:10FB4000E9CE0FCCDC74153CEF13FBA2AC82C7519D
+:10FB5000B03BA48F7FEA75DFDD2CE59A6F178D77B8
+:10FB6000416A9781F1186F155800C0935AC7D8247D
+:10FB7000C0931B703942F1BA841BE53150C7E36E64
+:10FB8000AB645DD02146F1676BFFADBFEE430DDB8B
+:10FB90009D021B3AE24B7FC7D049CC68E7600180E9
+:10FBA0002B38574EE2962CC3603AEE83C96DE17351
+:10FBB000ED47C9BA6AD27E92DE37C24B1E3756581D
+:10FBC0009C61A879BD1A6F9711AE84947BDF4B8C32
+:10FBD0003331FDF938777524B7BDC3998BFCF40D2B
+:10FBE000E0A723FE863AF652FE49116B93D04F945C
+:10FBF0001BA329E4B5B7A4782FCAC324357AA4ABD4
+:10FC000016F72F5D14C793AE6E9F817E49C1647D48
+:10FC10008E04747A4961A918E0B6204FDF8F2BB9A2
+:10FC20009F74BFBBC007742AC045410963DBBA3E5D
+:10FC3000DA84FBF305D3F4390E5AE98D2D78250CBF
+:10FC4000F529FA49FCBEC7FDC182466C3F43DF8FF0
+:10FC5000EF2377BE4D75CBDFE801FE7B87FCE5E344
+:10FC600054DE27F3FD889D32976B55167173E04380
+:10FC70008C67E6C9C354CF6B3F4175166629C49B98
+:10FC800015A70816C677213ED7C446697FC8E9B3D1
+:10FC9000F68392DB715FD4F4F37DD12BE005C95775
+:10FCA00097BEDB2E5F3F95A50C7EEE023381EBFF06
+:10FCB0007EDC178272A023CC32E4C57DF58E77807E
+:10FCC000DF1557ACED00AE377A79FFBD1DD1FB7063
+:10FCD0003E80339EDF23E4FB69D921F279E24F2392
+:10FCE000FEE548DC401FE6D49B5F263EFD70F456DF
+:10FCF000EED388BC94B3E8DD5577DFB87C97535ECC
+:10FD00004513D2E52DB9794108F8A40BFDE1CFE008
+:10FD1000DB750B303ED3E5E7741AED5AB609F306EE
+:10FD2000144D4E29C87FB56FDC80FBE15B44FCCDF0
+:10FD30000CC922CE2CFF19F7E5BB31CF0590EABAEA
+:10FD4000F89B6EDC9AF038DAFEFBDB38BF7FE3F914
+:10FD50003EBD206AED3513F3A51289EDB0FBBF79E6
+:10FD6000619815CC4F9785FD3D7E2BB3EF4B9F11CE
+:10FD700074EFEA384C7C3CDE4F88E7B728F157B681
+:10FD8000219ECBA5F871C41B2E8B984D9F5A71F6FE
+:10FD9000976561EF599B9BEB27AE77C7F77717B94C
+:10FDA0004D67A6FCBD4CF2B78FD3295BFE7EC72200
+:10FDB0000E03402B7BE3CAC388AF9E8EB17B48CE37
+:10FDC000128BC87F2813F9404CEC5BEA621C3DC2E1
+:10FDD000529ED9F8CF01DA4FD6BBE48FEDF6353B12
+:10FDE0005FE094EC0F91FDC9CACFF1B44FDB618F96
+:10FDF000E33B2A120CE5D3CA1390143D835F3DED1B
+:10FE0000D3A97D7F87BEE39D4A1BBC62BD54664D6E
+:10FE10002FF105D26F5EE14759F33BF8E6BDE600EE
+:10FE2000D07907B839681F775439484ECA36826688
+:10FE30002E4BCBAD9E80F905D2E366CFAF40E17C7F
+:10FE40000EEBFB7B118E490803D5C3F7223C6540BE
+:10FE500090FF037E09DBBE88E018C7A373A011E3FF
+:10FE600048BFABE232EDAAE4F162BD5AE0336B1C4D
+:10FE7000B6F33C74A8E2707E523A5429B9E9C0DA6C
+:10FE8000E107705658F8FB23BCCDB13F69D1C5AA34
+:10FE9000C3BA2F685FF79D6D7FF57B51AFECE9A882
+:10FEA000BA17F54A17ACC3F97E114BBAC85E70FE9B
+:10FEB0009713318A63433D2A13BFF3F70ABEC73253
+:10FEC00011FBFC8521AA475175560EF1F795E2FB0F
+:10FED000BEED774965F07CFA76F13C616818CFAEEB
+:10FEE0005CCDA8BFE9A25D7195E1C671D8ED3C6E0D
+:10FEF000C270CBAF48E48BC06FAA262F401E9A5227
+:10FF0000157778B0DD766654EAE9760F08BC7B4257
+:10FF10004FCEC7767A552C86E3B06599FDDD6FB577
+:10FF2000ABE270B33E1E17B2DEEF10E34D1B0ACDFD
+:10FF3000BF109E9757C5165F85EDEA79BBAE8E2838
+:10FF4000F1B7D5FE4ED1DFB4AAF8E60B71BC6A3E1C
+:10FF50009EE2FE02C983D56E50B4ABD8FEAA89FDDD
+:10FF6000E655F1B8A4F57E8B18B7A22A7E178D2727
+:10FF7000FAD9DD5147E37DB7C3A0D2922FEBBB3B4B
+:10FF8000C477DD221F544EF07ED53E467AF81F8599
+:10FF90003C6497280761F4E3B12F186F9AC9E50C08
+:10FFA0007187F13D7D6002BE675007BE2D851FF74A
+:10FFB000FB12B41F6FF19B156F3874E4E20CFE6303
+:10FFC000B703BFD9F3BAFEA12AB3BE3A9A595F5616
+:10FFD00097596F30EE1DF737B15EDF98F9BE369650
+:10FFE000F9BEBA29E3BD05C7F60E4671BF1D1DFA5D
+:10FFF0005003E9A9518A07EE28D44B701DB1BB907C
+:020000022000DC
+:10000000E3F10E8C3B93FD0D53FBAD1837ACC47C74
+:100010000D1E674C88F821C6E71BC83EF338A4B70D
+:10002000FD53430D40F787059E816F32F43BE8FD99
+:100030008715F42F96C54CCA0513FA7E8787DD8095
+:10004000EB36777898396C787B46E179235E6BFDE7
+:10005000086EA0DD7E3D23C6B1F4238B003561BC64
+:100060006EC16F689F70FDF2B422F23F74F05C8A3B
+:10007000CEB65FE592F10CC2B5A310E0C03859745A
+:10008000C4C07DB6296D3AAD07BDE05FE3BC027523
+:1000900063297CAE35F0E791D59971CD1DF9A6A401
+:1000A000C2FB6425A37DAC7C43CB78EF11EBF699C2
+:1000B000CEC52FE27879222ED0E95F511CAF4EE3F6
+:1000C000638114FF10DFCB6FB8783E94C6F3392EEE
+:1000D00096632F2930DF4957F7D17EF64B42BF9701
+:1000E000A1F7827E26D3361F828A2EEC2DBBF12CFF
+:1000F000FCFF277EAF9BDC3F2FEBE2F37F49B1D6BD
+:10010000EBF162B4DFD749F137707C561576DBF737
+:10011000A342B136312E6F6FC15DA91A0497054F06
+:1001200058358EF0BAE51740BF7ECC9F889BB84506
+:100130005A8AF0813E3C29EC68369C4ABB41FE5805
+:10014000C1176E7463FF96FFC09A72E7414DB4DF2A
+:10015000BF1EE182FE4F88F54EC1A444788E2DFE6D
+:1001600057A872FFA75F49E761D1BAD0C92CBBC6B7
+:10017000F38FB10E721454F9FE6EB19B997941F46C
+:10018000D76121807AAF53A5F5FFE4654040A0FF19
+:10019000FD1BD5DD68C795D545B4AE04D94C519E3D
+:1001A000A3D9B31EEDBD153F76635C631ACE679885
+:1001B0004A1FC687A7619C788C4A8D69B47EF84D2A
+:1001C000F3E86D48849DAE784805BCAE76C72F40F5
+:1001D000FFF0B6CF8FBC85FBEE211426806B8E6CB2
+:1001E00068EADC73B65F82CF7DCC28C476939951E0
+:1001F000A4127D32F34CADFD7BF8BDE2B7D19F7DFB
+:10020000D791CD4F3AF68F7E1D361ACFFFF07DB2D3
+:10021000F513FCDEF1CD3B57FFBAC81F8865F47FAC
+:10022000675E40457FECDEBCC08B88FFA31B5D147E
+:100230005778CBC1F348AC710E6C7495A21E1EEDBD
+:100240009F41790D07FB5D01FCAEA77D5AC01E07DB
+:100250001EED9B16CC95F730FE1EFD05D06F86E097
+:10026000972B055CCDB2A6E2BABDD92CBBD7EE77F1
+:10027000379B3C7ED42CF37CCDE6F62F7FD72CB376
+:10028000CF9FAFA7B3BF4BC7B946A7A2BC649F7FA0
+:1002900038DFB989538E64A3342D8D37AF1237718F
+:1002A000DDAC30C320ACFFE5FDF5FD0FF77718F9A5
+:1002B00075A2FECEF7FD44E74136572463A4FF64E0
+:1002C000E88FE456E80191EF63E511B9848DEC8C79
+:1002D0002C0EA27FCBAAA224BF2E688B7997CE8446
+:1002E00024CE6B88BC9F2A47467E4F76BE0F6B326A
+:1002F000257BFEB395FF4301151B5F63FF388E130B
+:10030000FC4B8A638873061483A4BCF96F659C97C1
+:10031000C07C2BF49F3757D564E41FCB8CE78BE36D
+:100320001A8AC7B932BF9B58DEB2C6BB3613EE4F2E
+:10033000FC9D4FD68FD9FC8C89BF93D9315B3C6C27
+:1003400037EA278A239FA1FC732236CD3B3505E986
+:1003500077B083E755FF4E4E7D05F5E7EFC654862F
+:10036000097ECFE5B34398FA6C4A928EEB5F43BBAC
+:100370002688FBDBC6ABCE90C35A5441FDB9938DA2
+:10038000DF45FA3DAC2AC28E8D38B15FE323ADC1A3
+:1003900000FCD5FF23F48B7AFA4355C27CF9F91F90
+:1003A000A59662FDD2B12605F5C64BFB0ED2B83735
+:1003B0008F2D94B1BE5FF4F3EB47F7CF63D0CF73CB
+:1003C0008FFB598AE25B4915F9E6E6279D942FB821
+:1003D000EA7B7E92EF9B9F58F3D022E8577AC64F74
+:1003E000F0D43FB1F26117C1D749F3BEF9E92F0547
+:1003F0000711CEFF703237F0E7731BB9BD59037395
+:1004000076C3F76327D587ECFB63163EAC7A833659
+:10041000E710A662DFBCB76C8ED346AF9B65F6359E
+:10042000F4570C2817E758EFFC5CE5FED107277955
+:10043000DEA1B4F7C0129AE7F09769DE1293E47771
+:10044000013FAF88F9423B9A8FF98894AC84F71F3B
+:100450003C22F1F90DCFDAE529C3F177A92D18DB9C
+:1004600010FB3200FFD7D06F6BD83BA7ABA416F7B9
+:10047000ABCBCA3015E2F2EF3D4EFA15CFF748404C
+:10048000EFB5F84F78BE6EAF3385EB9DB54FAEA19B
+:10049000BC45A8D3FA67D5F77EF0B4E9C7EF9D193C
+:1004A000F9FF6B87EFA0F5E3AA7F714553D0FF7B7F
+:1004B000AF3AA31EECE759E5A8DD2F7F6F644F002C
+:1004C000E972D96939E3398E7BBA80C66956836788
+:1004D0007F0798A77CF575C3FD34CEBA27FFEE974A
+:1004E0009847B92E2B9EFC1EFEA3F8EC75EB193530
+:1004F00073DDBADA29CE1BEC9D94D3FE8D9F3310A9
+:10050000F66FD5E3BF7BD084F13F78E2FD0771FE43
+:10051000ABFFFCDB07BF85EB9FE73D1AC6E1D73D8C
+:10052000FAEE83DF8479FFFA599703F9E6E6477F0D
+:10053000F5D6B7A0FEF1F76714A0FF59ECE2FEF183
+:1005400089FDBF2FC27303FFF0832B26231EFEE11C
+:10055000A9CB279FCB9E9D00FE4ABAECF29A247A43
+:10056000EACFA21303D5E7449945BF834F1E2C451C
+:10057000F87EFD1ACFAF5807CF301EB576780DE55F
+:10058000E962FD76C0F7DA7DBD749EE36C7C9B5317
+:100590001C612EF79892BCF6C92F7DF1D25A2C150A
+:1005A000CA675DC7C67A30CE98FDDD381D5F053A53
+:1005B0005E74F6FB75E29CC7BA7DFD7CDC61A063CE
+:1005C000E06C3AFE1AFF71C9D974AC7365D2F1E3DD
+:1005D00047AE0FA6F0E5939372E6C35A745CF3D46A
+:1005E000DF9FF37CCA892C399E08CFAD12874B71EF
+:1005F000198D2E94D727F2CC30E0E5C4EBAEE4227F
+:100600007877A2FBB7A50CF8E3B832B604E571EC35
+:10061000072E0DF7E79B7FF07315F5DB89A77EAA00
+:10062000EA3CEEE69340AF9F60E3BF11D4F374FE63
+:1006300000F1F45D7F0AE3106B6F6F257AAD4D5EBC
+:10064000D3A807E839C533D626B91CAC4D1EB85619
+:10065000CA413FD355C0F56BB250F887697A4A75E5
+:1006600048C7230B91EF26A2A3356F0DE77DB18D0F
+:10067000AEA6724EF93CB1CB25E3F9D975E29CD018
+:10068000BADB1B89BE965FBF2E29FD3C17BDC7F79D
+:100690004DFEC27344DF744D108F12F33E9F5C9F7A
+:1006A0007F5E7F19DE6EC243A673CFC6DFC66E17AC
+:1006B000E9E7B7E6B8287FEA88A2DFBB01E473EC7C
+:1006C0006585E1FA7349CD2F153DC7B982FF06BE96
+:1006D000D46D7C196F3FD93D19BE8BDFCEED4BF643
+:1006E000FE52FC7627C6F4C6E1F9CD549828B45FD3
+:1006F000F7A087F2999DCFBFBE04F5C2BAE7FDA46B
+:1007000017D6BAC61EA67DD1EFB8D81ECE7BE46F31
+:10071000ACD4781F079FDA40ED4FC07B6CFF9BEF96
+:10072000771CFB06CCE3A6EDBCF16F9E08CE6620DD
+:10073000E7AB5036018F2B7FF8ADAB915FB18EFBED
+:10074000AAC70ADB9EE679CE53E7E0F8079F3A4551
+:10075000E39DF85E1E43BB7BE287BFFC1CE2F3FD1A
+:10076000A79F998DFA70E57645B7EF17DE643F0FC6
+:100770006DB3BBAB86B7D07ED12A7CCFDB4B678411
+:10078000ECA09F85E3A3DFB2EAD9A0E1999DD18EC9
+:10079000FA59E71ABB2D4A76CF2C71D4117D4B90B4
+:1007A000CEABF6668EFF4317B7CBEBD4B115BC7D4D
+:1007B000A284F3C3087DF78A8BC72BACF7D9DF5B24
+:1007C000EDFFCD559ED50FFF7EAD8BB5E5CA47FB3E
+:1007D000B9E877D5DE3FCDC8EC8FF3EDD9E3F0E78C
+:1007E00027BC7C9DBBE6693FD17BCD0FC1EF998DC6
+:1007F000F597289F7CCD0F37107DD6B8524BD03F50
+:100800001BDBEF62E8CF7CB0FF657AFF81922A2D77
+:10081000C076CF798EA0FC66C3B566D8250E8D66EE
+:100820008EDB29F6A9BAC43E9553ECB3E14960F4D6
+:10083000E3687F01EB6F4CA5F5F744EB8780BB8C39
+:10084000E66DAD23AC754337EE7B600CD06D32CDD9
+:100850007E1E8DF1BCCF3F64F187AAC4355CEFA941
+:10086000128B217E15394E79CB4A38340720663DEC
+:10087000E1C594DF3A50AD911CF9DC7CBDE882FE05
+:10088000C9DF3D3444FB4BEE88FCA15DBE3DCB820D
+:1008900064375985ED7939CFF7C378A4AF1A9EDB59
+:1008A000F7BB438733CF4967EDA3FFEBF8B91FD3FD
+:1008B000897277BD75B01651087CFCBA755E53EE2F
+:1008C000E2EFF3ADD75DFCBD90D3752D5C0E0F3616
+:1008D00007098F161EAE7FAE7704E318D73F57BCCB
+:1008E00014E97EBD6FC6BB88D77F451D88FB5AF9CA
+:1008F0002E3A977AD173B12FFD1DD4BFDA5A49E74A
+:10090000B2AA87635F9805F51B5BA751FC6CB69B89
+:10091000F3E35776394C05FA3F24F2ECCC6F4844A8
+:10092000CFAFE102043E6C66BACA1753496ABF945E
+:100930000DFB797DB810CFD7D9BE77FAF0FBF51251
+:10094000ED97DDF01FAF5E8138FCC5AB47BBB1FC56
+:10095000DA2B4CCD83719B9FD47B78B843F4F71C82
+:10096000F4E748F7378E3FD94DF848E3C74DF8B262
+:10097000F0032339E87D1ABFB4CEB4F0DBE901FE01
+:1009800003FC5D1F6CFA3CCBC1F7E3F8F44D7F9795
+:10099000CD4EC3938DDFD799F98351D243037C3C6D
+:1009A000B1EF62F5FF5B7C05FEC3EBD006F34C5E56
+:1009B0000F4C3F44DF29BE3EB4E337B06105F9EF89
+:1009C000463642E5123646659C692A962D7830797E
+:1009D0001A6E17C4A8DCE98A7FC54D71A3D17918B6
+:1009E000F7FAF5D4F8054588EF5772FB4369FFC65F
+:1009F00014711D51BADD941B609D4F69193DD98159
+:100A000070B50059D19E789865A77515E31D2D6FB7
+:100A1000FCEA4FF6F76CFC3D8FF78FF7E3E6E776DD
+:100A20006DED32F434B59372F503F58CBC8DEC3A70
+:100A30008723FB798B9B9F53CE0117E6B6033F5A62
+:100A40003FFEFD3BD2F04C3C77BFD97D79431FE898
+:100A5000E3C70A464ADC501F705FD9D555CFD8E3AB
+:100A6000B07CC2FD61A8379811AC1B4B701DB75408
+:100A70000616B6E50D6D13F2B1CDCDE3A8F0DEC4D8
+:100A8000F783582FA4BC2EBA1A64299640F7B7F7FB
+:100A900095FF64A63E317D5A06CEB8F41CFA1D2F90
+:100AA000B608CDE3EB7C8A9FBC18355D4ED483FC41
+:100AB000DCD95F1AAF2C60512A432C46A59507114B
+:100AC00066092A4BD8309511364265291BA3526717
+:100AD0009A83C705B81C94B328D52B9941E5E365E3
+:100AE000A0FF439837E88DA27D395FBCE8476E6E62
+:100AF0001F277F5526BDF411D8093AE726F47F3623
+:100B00007E9CEE877674D9CF873DE2A675F3E31B12
+:100B100075A28FF5FC47822E3F12FAFDF18D51CA66
+:100B20003B3FFA883B8AE751DEF633351FE0787B9E
+:100B3000CBCFCB9B7DE9768F15F0F8E4E923CFCCC2
+:100B4000C43CD97BDCC68B6E929714F1ADC5474B84
+:100B5000DD3E1EEF1E503EB0DB836677EC276EE86D
+:100B6000E7F03F7BC9EFBBE54E89FC3EA64B24670F
+:100B7000CB04FD1E2B187E0FCFE19B5B5D3AEAD1C3
+:100B80006503AE23A80758E20AC3DEDF5B621E2CB2
+:100B9000712FEDE72E3B4F3C6819A011F92FBB1FB9
+:100BA000C6A6E663FC986213B6F66EE02F2B5F1CB8
+:100BB000D7B301B1CE69DDFDFB30EECB9C74733F42
+:100BC000A8F52D9E3F7F5CC46F07C57EDE076E1EB5
+:100BD0006FB7DA9D744B16BF66DF577012F1A2260D
+:100BE000AFA738BDB58F725C4D34219E06AFE7F7D5
+:100BF00011CCAABF6E15F2C5DD52ECA444710E8E65
+:100C00009F594DB791FF327FE6DE303E0FEE7351B4
+:100C1000BEFDACBD2E03F116F470FF61FAA2363CA6
+:100C200069C6DEBF345982EB81D6F1BCA76440DCD3
+:100C30006B42FA7F95C0CD7BFB2E3F675C19CD855B
+:100C4000698B93E18CCC0C7D5490552FC96A5F9EC3
+:100C5000F17E0AF07831E881293E96F243F9F826D0
+:100C6000733EF2FD2028785C2F4E458305F49B02ED
+:100C70007A04EFD5C0B09C17CA08D4DD05F49E39BC
+:100C8000C5FB20940F39861B91A8D370FE80774D49
+:100C90001EBBAABB0CE5B84F6ACB98FF98DB3EFFA2
+:100CA000220113F4C3B0DFC1A61ACAF74AAAEC1690
+:100CB00084E79E4B393DAA9B3E5E82F4A8AE624912
+:100CC00085CA5439E2DB2BF68F77A9DA0DD8FEBD41
+:100CD000C75D827E0B6FC2F6557B7B6358CEDA37D9
+:100CE0006339D26DB35F6B21BF03FA457A96E1A2F7
+:100CF00002E878CF23AEE426A46F3DDF87013A9562
+:100D0000E2FEE1FB4F01E2C06EBEFFC8A926DC2770
+:100D1000AE6ABA6731B7BF3ED213EE90BE1BE3890D
+:100D20008687CBC77BD81EE4D9BD97EFC701BF1913
+:100D30001EE4C3BD52C67E85AA1BC47F978FAE7FBB
+:100D4000692A8CFFBECE683DE462C381529483BDA4
+:100D50004E8672F0F8540EDFFB493549F382AAA79C
+:100D6000804AD38F652446FE42B1CCEB804703E531
+:100D70006ED61B37FD1AE7B144D0E331666AA81777
+:100D8000DFDB772BE5096DAD673528FFA7147E4FB4
+:100D9000C9AA7D5E9A7F513DA3F39DF3F749A9CB84
+:100DA000309E37A0D2F9D09B9BDA2EC076AE7D92D2
+:100DB0004ECAFF8FB7A64AA0BEFB069E3BD5D09475
+:100DC0002CC538DE7B73C6C278EEF9C7187C037C6D
+:100DD0000CFEA92D8CFAB022A2A6F07CF247A373D8
+:100DE0006E7881E1BCCC528C570DF6837ED6391FCC
+:100DF000B96B88BF58A006F793EBEEEBA2FDFB049E
+:100E0000DD5762C941BF92A07CAA9BFB530D21F024
+:100E10002FFA3DC4EA6C6FFFD12ECC9F1A7C0AE6F4
+:100E200003F41AB4F6E9AAC6DCF67DE05B059DACD6
+:100E3000FAA0B8AF86558CB9B93D1F73E339CA53D0
+:100E4000CAB08AF1CAF9FB4E1E9E467870D3FD4D9A
+:100E5000A7DEDC7001977B4947FB60E10BF0432C78
+:100E6000E1DAD72CE13A661C1F5B4ED379550B0FA4
+:100E700087045E66815A5A5093C6CBDDEA8803F533
+:100E80009FF934A3F5CAACEBFED084F477B57FEAC2
+:100E90003EE4EFFB3DF95C9FC963745FC8DD780EEB
+:100EA000DA9786DFA5F17DED1D1E1E9F1DF2703BBA
+:100EB0007297982FC094AD07EF42BE54DD31A31B4B
+:100EC0009A6CCABB9AF6CBEEF7887D58F718DD33DB
+:100ED00090E3BB1D1ED49FD7DE6074EBE9EF006F7B
+:100EE000197996A794B1D796C27C5601DE36E98867
+:100EF000C7F5C47737D733C2A30D6F197C3511FE00
+:100F00000E4DC04F161E66C92C85F704315FB4FC28
+:100F10001A80FB590FD7FFD67BC6A2E57F6F83EF00
+:100F20005981A7BBBDE27D15FF2EFD5E7C1F10E73A
+:100F3000CD2BB2DF733B03FCF03594CF22E40709DD
+:100F4000E763C9CF3537EDC1FDA22739DFB8F6EE2B
+:100F500057298F353FA922FCABF6AE277E6988C49E
+:100F60008B71DFF19E2D7B69FDFB5ED6FCD0FEA36D
+:100F7000FDF895B0730C93D2C12E46DCACCB9D230B
+:100F8000BF6FFCDC455D88FC6F4B5F4FE87F87C11E
+:100F900081B2DDA7A48AFDDC6061FC3F91CEAEA6E4
+:100FA0001115C3777AC5E8422CAF702EA27C159735
+:100FB000C83FCEEEF77807AC0C416EEFEE70E3DD84
+:100FC0004A20C71AD5B77584A94C76E8F4FC84C0CA
+:100FD000AFD7C1EDF9E6AC7BDADE15FC6BB553702B
+:100FE0002708F7EDAA783E805CD5C3F3752BF8FD92
+:100FF0003BD6394AE0CF1308372C5872E60BC20BA8
+:10100000C9CA9BC07645D7F27C81A2269E37B155CE
+:10101000F0CB89ACFBA0FE20E0F883A0FB2806D92A
+:10102000097F7CFFDA1531B91C84ADBC637E7EE597
+:101030001C781F9572E35DF1C2FB3589230B8B6130
+:10104000084F05CF8FB5F2613FAAE7F7A94DE42716
+:101050005878B7E8D0DF11A7FAB68E562A83D77230
+:10106000FC253BDAA8BE408A15E078C1FA73CF7F31
+:10107000B297CF3FE215FAE413CEF31E8FE05BFC8C
+:1010800085705F94DF5B73CFF5D78597C2F3195EE8
+:1010900071EF4E5BA67DB4FA017ACEF0CE4DE76DCE
+:1010A0005879B7A3EED8850837AC339E582EA5E102
+:1010B00039DF7AF328E66157A6D703EF60FEB572F1
+:1010C000AE7D64A3E665BE8F4CE714DE92E297E046
+:1010D000B8A7EEBA5945FBED1C986F62380EFCF3C9
+:1010E000CF209C2D41FD633A516B5E7D05E659B7DB
+:1010F000B8F4A7B17EB2BEEC0ABC57AD65B27E1B98
+:10110000AEF7B66DAEBC02ED57CB058CF281FF6930
+:10111000F357BBD17E9DF118977B695F5FC9C7FD0F
+:10112000D36C3FF9EC7965EE9FBE8008E4FC652244
+:101130003E2DFE02BE8AFD6D7C65F1935BC8B34611
+:10114000FC63BD0779BA91F848F0D7F9F8A959F0CE
+:10115000D1CD82AF2C3EFA5BE7ED71E43E5F7B8B35
+:1011600018A75FE819D08B7D76FD69E9D322276B3C
+:1011700043BD76E086476F40FFC7B5777A39E225F1
+:10118000E44CFE02ED147B4CADD963E3CF477FFF07
+:1011900050C9621FEAB164C91E7CFF28BCD7319FC9
+:1011A000BD2D8CFBACD5918F97E07D5BD5152C596F
+:1011B0004965AABC0CF01312700E8976B322454B18
+:1011C000717FA545E0C53B9E17D9467678B35FC8C9
+:1011D00091DC16463BD42FFCCCFEA91F3789FB00BF
+:1011E000580AF34B35EE8FE27BFDA2747FA02745B2
+:1011F0007ED8B89E6CF1E6F04B2D3D39E289DD4D8D
+:10120000EF85BEFC5BE902FD7DC7CBE92CF1BCEFAD
+:10121000BFAD3FA017D9355C37A8C26FC42BB858F3
+:10122000343AF37F02DEFFADEF832C6E868164419A
+:10123000CCE7037E700D6C6428AF205F87512F7858
+:101240008676996887D7D50F53DE9B2557EA059C8C
+:101250006FAD7E47BDDC7E8E5AFA1A7E3AD0793A5F
+:10126000FD83D707A03E03FF017A6C8638D754C5AB
+:1012700012143F99C986A9AC662354CE66635446BE
+:1012800099E6C4B286459D22DF6C1E96ABDDF1EF78
+:10129000A069DCE98ABF8974FEF5D4F83F61FECE0F
+:1012A000A6BCB59FA1F39B5E4DE0259511BF606282
+:1012B000BFE77CF18CC9CC38C6F56266FE19FE2604
+:1012C0003AB765E438B7F5579CC3398DE34E780ECD
+:1012D000E722FD243F573348FADE3A47B3A5B0E38F
+:1012E0000A3A577331A3F549C91D433F42FD2E2FDA
+:1012F0008A9904D3AB2CA7BDB34A6532CF67ECCA39
+:10130000BF4EA3BC4637DFCF94457C71DC2E639083
+:101310007AEED9798DFFD3E364F7BF5E8D15E711BF
+:101320009EC7FDAA625E8EE7A5D6E415A6F331AD91
+:10133000BCD489E0DA94B7A4CE7E0ECE993FAFF14B
+:10134000004CCD917763D4BE1F6BCD77BC9D8FC30E
+:10135000F597E67F82FE2B41F8B3F340B3ED945549
+:10136000D6E771793AEE352EC679D9F2263F9B57EA
+:1013700098336FB21EFB07BEBD34AFF06CBE3DAEFE
+:101380008E5CBF12F4F5BBF95E8A031E78E567C573
+:10139000B8AE54F3BD0ECA07127136EBFC475709BD
+:1013A0008F4BDE917452FEF91D230BF48D50DF1329
+:1013B0005689FBF6542DC89B857E4A9F93F2E1F334
+:1013C00044FC4C2D3E44F37BD5EF24F9BBE374E79A
+:1013D0003CFCCEAC836FA0C9823A43DF88EBF00BB4
+:1013E000F9BAAC75D2E9ED7950BFFFF59514E43543
+:1013F000FD3CAE76FF2E711F19FE703F756E6CCFEF
+:10140000E6B2747D6568F11E94A3DBFC328DF3F5C2
+:10141000FE695B7109E2AAC2002FFE4C27DFB7B458
+:10142000CA9493EF7BF27A36BE8362DF2CFBF965B8
+:1014300001AECF82975E7B18EF135ADE4A77B1A0D8
+:10144000DC1F28867AA21E6C25D4837D3CEF2A21DE
+:101450008F99B8644AD41B21135A0523A378E70255
+:10146000FB769E427006FA1E92701DE66DE5E7015E
+:10147000B2C7FB761EC75B421E359DD40F8B9AD038
+:101480007F00FAC1F5DAF9BEFF7A1EF76F13E2BCEE
+:10149000EDCAA166CAAB5AB97DB284F8B5DA6DC996
+:1014A000E3F3DA633832EE6D393A5E6FA3F5A33FAA
+:1014B000147F10EFB3F58755E20BDF4EC9F319A87F
+:1014C000FB925C1906EBE314C7EC86F7B81E5DC906
+:1014D000E2A5A8CF86E5E1D75720BE007EDC520802
+:1014E0000E49841FB9A0F5C16F201F5E92B804F1A8
+:1014F000F8F55D7F6217C238013F3F3F1CD44ED3E1
+:101500007D56C1DA313AD717A8CF3DCF0FFDC28F34
+:10151000137C1B107AD73FB49BF05352C7EFCDBB5F
+:101520005F192E2EB27D7F89E04B8BBFB2FBFD6A27
+:101530001E5FA7F7143F4C7CEC95E3748FF5CA88C7
+:10154000CAF05E18C7CE9F52FE7DB0D611BD126D97
+:1015500041B48DEE951DA813DB806CB409DFF7DE76
+:10156000A4D21DDEC705BF9AF53C0F3B7B3C8F5FC5
+:10157000C4F16A1D8D08CFE04D2F1623BFECF48F08
+:101580008543D5F89EF3CDA0DF47F03A2F7BF86A6C
+:101590008C0F391F5B5A24E9F67EF8BC2AC02FC491
+:1015A0007396FF9E37DA8DF74254602015FCFD33A9
+:1015B0005B7ED98DE7321FD8E514F4D5292FED8550
+:1015C000E4B42998127D6CB54A79CAC7E356DC3475
+:1015D000E5C1F7F7CF8F935C99373928EFEBBEDA87
+:1015E0009FB96740FDBE0A07E17B57B23380FCB06C
+:1015F000CB08517CAF35B8F8DF51FFDCD7BAE0AE8D
+:10160000E9C8BF890A89E405FE2DCFA35367F4DD3D
+:10161000560FC78BB690D18589F9F5FC5C6C7E942A
+:101620009F3BBAE3B493EFB7D6F17B84B5C46BDFCD
+:1016300042226BF57CFDAD45EEB995139DDBE3A031
+:10164000500D9AD8C7D31AD48CBC1078EF6BA5FB79
+:101650009CF97D93161CC111476A05B60F7B8F2C30
+:101660000DF076453544DFD43C789E1FBEAE94F233
+:10167000EBAB1D4796CE4EEF033C20F1FC69F31215
+:101680007537C207CF29BFDEFC0CAFC3FBA627907E
+:101690008F0F8FC5787C37568A71BE60DDB11B1104
+:1016A000BEE0D0CF693E41DC57C4D2C884B72960C0
+:1016B0007C9C67F32B2CFE0ED4F2FB3E699F0EC67A
+:1016C0007FB799DFE712C0F39705342EE7B7E52C13
+:1016D00029F25B6A513EFCE27BFCE13D92E8F3A11A
+:1016E0003F37F814DB8793F68B7DCB0F869DF4FD97
+:1016F000F6263D89F27C5CE5FDBD7B151FC75FDFEB
+:10170000B31EDBF9EB6CFB90F0DF241FE7E307A4CB
+:10171000F4FA9BEE2BC571CAD3F5ED8C8FBBFF504D
+:10172000C117AA719C6505B4DFDE25F04A3FA00F02
+:101730005D82007A245FF31A17C2E44645FFFB4539
+:10174000BBAD87B51730EF6AFE8FDF70A35FF44B38
+:101750005F98DE6FA9FBD08D7C3BA871B84BDA385F
+:101760007F9584C7DC18EF5CDE2769BBC57EAC695A
+:101770009D0BC4FD75715F4EA44F4BA2DCEA7D92B8
+:101780008179CE98FBE198275282711FB0CD5C8F92
+:10179000C80ED47F2811FEC2820EAD1C3F83FA28EA
+:1017A000DE6DC5EEEF93284FD8EAB7A40EFA05BE5A
+:1017B000B81FE040BBFBEE9083ED2E4BCF97FC5162
+:1017C000C053CB6A07F155A48EED92E0FDD23646A8
+:1017D000F93C7B22C32FE377C7EE76E9183747063B
+:1017E00046B84AC5774BEB002E6837688CF5A19F49
+:1017F000B967B583613E4C692B7FBE74E8990DB81B
+:101800007FB1C7CDE159D9CAF152BA9D3F5F29E6F0
+:10181000B1BC0EE681703570FA026ACD330E1C9FA2
+:10182000F3F7B19BD82EDC1750A7C647A6A37E6F4F
+:10183000631AC6D3CB0732F9D79A57E5387E39FCFD
+:1018400081FA221DF1708199C93F169E5B44FB4AC3
+:101850009C37E2BF9DB793F1867078DED2CAF15F04
+:1018600059C7CBA5623FDC81EF715F1DE783EFEBCA
+:101870009FA67220BC6C4422BBADEA989BDE3294DA
+:10188000352E1E419EC7F359108F7B5E06B2A11202
+:1018900018E2F4DF58E0E5FEC7A52AED67FA5A79A9
+:1018A000BFFB1DB1FBD08E999B5DB46F82690ABAF4
+:1018B0006DFD70F44F3C3F79CBA5EA5EC4174C40F8
+:1018C00022BE16E3EC77707C9B355CBFD55CCCF315
+:1018D0009BB746D5BD68A7F3EB0A16A8A80FEBB9CE
+:1018E0009ECB8F1EFB36570299FBFFBEC3FC5EDD0D
+:1018F000F0B24CFCC37C0C5CAF8EEB5183D138450D
+:10190000597902D82EBF06AFF12E5A807A75AEBD36
+:101910007F785FF00ABF9FC07738564EFAF7F0CE57
+:10192000C518272EC86A77D43F8DE4CF77B8CD414C
+:10193000ED30CB6376FA9E5D74C5590D9587B00482
+:10194000DB6EE6F1BA2915205E64D680FB82F36374
+:10195000744F8A65D706E6A873E2D5823E0554A681
+:10196000588EF872BA7DD18568B77D87E3E51AC1D4
+:10197000ADEBBCD4A8B4E0B1DA276A18E1EF1ABF26
+:1019800023E73DD05AC39F33F212DE0B98B7FD1800
+:10199000F1F93995FCD94E656C3BFA479D4FF9300A
+:1019A00012CE1ECD4F96E0FD51EF0BBB3E7ECF70A9
+:1019B000F5B5E41F638A15CE9789FBD267FAAB763B
+:1019C000A13CCC324CF293675544A44E524A3C3F62
+:1019D000B49B193AEA4933E2203EEB0DF7DC467F2F
+:1019E00057A34F2A40FDB0B5AEBC07F5DA701B73A4
+:1019F000A01E7DD5C7FDA2056DA3747FEE96030ED4
+:101A00003AB7BDE5FB86FE0BA87F0C30A03FB9A01E
+:101A10002ED146E7C12A7DF4FEFEEFC7676836BCCB
+:101A200060E63EF797992CFC6887C81B9472F9CF43
+:101A3000DEC2C52AFA6D170C359B18AFCF1FCA9F9F
+:101A40004FE7B41B40C5625E6818D00375AF38BF5E
+:101A5000AF1BF0FC623A8F4DEFF508AF7777A4F833
+:101A60007AB99AEF27CCDCF5A546BC4F73E6858E94
+:101A7000611CBD7BA46112FA1BC75A1DA4569E4C63
+:101A80003A33FC576B3DAEBC9AEC2F877673871CBC
+:101A90003A2AF93DDB2F9F847C3491FD98EABB9074
+:101AA000FB933AD74324A7CEB43DD9AA093D3E249F
+:101AB000EC496494EC496427D813A1C7D19E940BD8
+:101AC000F906FF6923B6AFDC9E4F7E60F94E89F4BC
+:101AD00078F910D7C72BC2A37DA497D00E48697B95
+:101AE00005F689F218F139D6A7EC949212E98FD84D
+:101AF000BF61FB96ED93497F2E0F1B93307F6D796D
+:101B0000934CFB9996BED585FE1CAC77107F05766D
+:101B10004ABBE8CC9CD0AF1788F7FA6A6E572EE81C
+:101B2000DB487A54DFC94BCA752C4ADBBB993E9D12
+:101B3000DFAFD2364C764217FAD5A20F93A3E7BC9B
+:101B40007FBF7BE7AEF9B48ED8794072407947E821
+:101B50001615CFD1AE16F261F9EF53C414223B8FA4
+:101B6000F075CE6AEEF71F2BEEB91AE7D1B36BA969
+:101B70008AEBD09228B743BEC88A87514FDE2AD657
+:101B80008B8CC5F87E6A5B2B9DE3F10BF803B56384
+:101B900006F6171C5AFCE50BC96F1F9E22E969382F
+:101BA0003FE50FF0F55DEDA841EFEBB86BB8A73E50
+:101BB000D687EBB8E52107E1D4D7D74970C0BA473B
+:101BC000936C71EB69FE3CBEAEABE3EBA02D437CA6
+:101BD0001DD4A3A418AE0B025107AD7F1C75F1ED07
+:101BE00078BFE672589FE2BAA1578ADD80EB47F0D2
+:101BF0001FB9FD08717D3038753AC553B7CE4DD247
+:101C0000BDDCFF9CC7E599D611E0C7FFCB1D5D0B7E
+:101C100031AE63CDD325E6E98F64CDB32E739E7BC1
+:101C2000F2C43CEB46F83C6BF93CA17DC63C8FCB43
+:101C3000295ABF1E8F326DA38EEB29781FC275E023
+:101C40001379D85FBA1FF36AA44310F08174080EA9
+:101C5000BD6062BBE5F01DF693CD0F86C0D31E8C30
+:101C600049149EED9F9F2FFFEDB10226EC25B7632F
+:101C700067D9418C1FA19ECFB24B8B0265E3F1392E
+:101C800033C30F1EFE3CF1D13E079DAF7B2FC0F743
+:101C90000DFC219EB706CFCDC9E8E74249F66F5843
+:101CA0003667D8E253BEDA4CBBB0D7C772AF47C570
+:101CB0003A94C92306F243EF25F179F6BF0B13F1ED
+:101CC000F3F57AC4CFE395BDD2A841FC33E1FA53D2
+:101CD00022BD100C399257C23F7B2FE578D93AD7F5
+:101CE00041E7F7FE19E355B8CF5EFC0EAD43075A46
+:101CF0005526F2CA28AEDF3AC94DED07E7F2F37E6A
+:101D0000C3A9DD14C7DA9CFC98F6CFCD3A7E9FC2FA
+:101D1000DE5D0FF79587F03E2563AED3066FA06AB0
+:101D200082B88358BF03A5256E27AC92DB0BAB9E10
+:101D3000FD9D0BE32EB6388FA269640FA3073E7A90
+:101D40000D7307BBB512CA57DE2DECF3F8FDED4954
+:101D50003F8FF3A5F8DFE7B0E26CCE377A4778FC27
+:101D60006FFCEF88ECF623FDEB33EF53B2E26F3DEF
+:101D70004A5B0CF1D433973416F3631CC787F10B1D
+:101D800096872A4EA95A3C77A36DFE2F89789352E5
+:101D9000AF125D07E764C6EFBEEFE7F7DD3DE3E7AF
+:101DA000F13B278BD1FDA9002FAD5B013E8A77B2B5
+:101DB0004552F679E5A711CE9E919618E25BF6C5DD
+:101DC000DCD57A9A3E9D823F0695B1B046F62E1E2E
+:101DD000737239A5F8D31DB523E41CF5289C5F0266
+:101DE000432E86E33AEAC47D01225EF1EE1A7E4F6D
+:101DF000F756713B93377C9D9BFE1E8232D684F151
+:101E0000734BEF64EB1BC40BF6DB9D74923DEA66EB
+:101E1000F104C505A017D45FC332BFB7A3A5568B85
+:101E2000DAF1B547C4315B105F3ECED7F6FBAA9F0F
+:101E300013719C87855E5046B8BC9124D9E3E9D5DF
+:101E4000FC5E137988AF7F55BC0FB73C8D4F1BBD2F
+:101E50004789DE8DB9E97D751ECF377972A43C8044
+:101E6000ED27F24F2D3F34DB8F4CFA74916F067ED5
+:101E7000634DDAAFB4EC61AF94FCC5E7508E1E51F0
+:101E800075D253723C8C7E9773BA8FF2961E9387ED
+:101E9000BD35E4CC9AFC3EB0149FAF9319B16F40AE
+:101EA0007BA5CF497565A7447E92C53736FECE9E89
+:101EB000EF7D14EFCDE2276BBEF759FAF6741933B4
+:101EC00026D9D6030DE3F10109FDA977E7F3BC2A72
+:101ED000ED7405B5CB11AF2943FF303B4E837F4FE7
+:101EE00008F5CAFF567CA6A7B848423CFC2FC46739
+:101EF00066060A793D577C8665C55DB2E335D971C2
+:101F00009789E23756BC057FF6B84D76FCA50813D5
+:101F10006DA761FCA6D383F7AF1F17713FDF806702
+:101F200021E6715BF92C4A8AFFFD1279B5F83B5224
+:101F3000428E2C3D6AE9D51C7A7465DE39F4E84A94
+:101F4000E4B3B9384F21372126A31D7D6CDF0B6E1A
+:101F5000CC335E2AF4E1B89D45FB6AB3A77EB4AFEB
+:101F6000B3CF6F5F130D8CE4A340CC237F8C970518
+:101F7000A332E9877CA6509990F9BDF2F98D997842
+:101F8000BAE8D96CBF63238F97BB8DD035C82F8D2E
+:101F90000E3A9F71F16B99ED1ACB7E14FA12D0A50F
+:101FA000E00A470D8FFF8BEF7CACF05AA45703BFBC
+:101FB0002FEDB3C733BF4BFBC3A2BDC6E1BAECF4F0
+:101FC00079DA8578FC3E1BFECBDDAEDCF0878DC276
+:101FD000BF0FA5E1BF329CD9AEA9F947855FCE05F9
+:101FE0007F841535D5A6E1FF4295EBDC70E91CFE38
+:101FF0002FD69DA75D456EF8BFD43801FC55EC2A5D
+:102000003CBFF4E5A6F3F42BE8FA95D673B7FB5A78
+:102010007BF638265F8F841C1EE46717F20FEA599F
+:10202000A650E91AE3FCA3680AE9356B1C2592491E
+:10203000A789F9C70C2DAEA5753AE59367F3C1A240
+:10204000390AF189ABD0C1FF0ED438FF08BA89FB39
+:10205000F6CECB17827FB2F96022FEC9863F9B2F56
+:10206000D2FC63165E174AC39FCD07E0C711FF2855
+:10207000918AE866FB7716FF8438DF9D972F04FF6F
+:1020800064F3410EFE217EC8863F9B3FFEBFF18573
+:10209000A6905E7131CE0F8AFED7F2452AF4251B39
+:1020A0005F64D33736FF0AA2FFD97C21E821F8E22A
+:1020B000BCF4167C914DDF4FCA1767D3DBE20B4EA1
+:1020C000770BFE6CFAC6377E5DE37972E3FCF0C9EC
+:1020D000E8AB037D7D9F5CDE991DDEF2B3E97C7E7B
+:1020E000FADE42F7E869167D754E5F4DE3F64289E8
+:1020F000F2B2D7A2AFF1C9E8DBEB06FD4FF1558E86
+:102100009F6C3A5D7B4D37D151CBA26FAF4FE055FD
+:10211000D0F77C74EB15F43D9F7EEEB5E89B057F10
+:1021200036DDC6DBE3DA2C948E0F67D32DBE51F17A
+:10213000D8E9DB1B696BFC2474EBFD84F2C88C4C82
+:10214000BA4E44BF56575B8AF2E126F3BF7FE58A59
+:102150006852B36D1DF1D520F72F9AD0F782B235B2
+:102160002FF739E316D12E89EDB0DF60661E935547
+:10217000AE14EDDE16FD5D10E4ED1FDF146B45FFC0
+:10218000E689037AF162DFD9F3B96BA375BE55977F
+:10219000ECE7086E0FF278D7D10E8D19B6F3ED8902
+:1021A000BEB28518B7291898D383E5D2BE49CCC8EA
+:1021B00081AFFCD3D3C82F4F8F97A4FEB42B34DA52
+:1021C000EFCE3F3D9DDE1FED7053FF383EAE93CF07
+:1021D000EE3F6F82FE8BCFD37F84AF0B18BF53D9F6
+:1021E000CA7F72069F7B0FD793DD1195F2D1AD7335
+:1021F00064D9F8047DC3CF79851A8C511BBDEF15C6
+:102200007851F0FC16FEFD92BD4EEE3F67B5EB74C3
+:102210005879F5F18CF319DF09F2B8803B298B3836
+:102220004B9CFE8E97F5FE6741BEBEEC94A2F47700
+:10223000B1CDA92AC969EFA599FB008F8A762F062F
+:10224000C7E3891467507C2FBE86F14EC5CA130BB5
+:10225000C91979629D0E213FB7707FBDB7927DD7B6
+:102260007111E50B52BE670FAC43E8DCAFE4B6D6A4
+:102270005B749EDB8A77F61E007F16E39B7E079DCC
+:10228000879922B3432E3CA7115653F8F706C7E3AC
+:102290005E4BB87CF6DCC94CFCFB483D786A18E321
+:1022A00016CD7C9FB6E74F1C8E9EE53A9DDB61867E
+:1022B000A1878AD2E726F1BB828B38FE905E0F841D
+:1022C000D539F6FBB4ADF1B2CFCB61DE4CC6BDBAA9
+:1022D00013E081B128FDBD30C5A76AF477BACF837A
+:1022E000B747835CAEBE13D409EFB31E52F97DF538
+:1022F0005354BADFC7A26379BF4C79731F316F148F
+:10230000E7D999DFE6A23BC4997103E2A5F3A8449B
+:10231000F1706B1E5D1DA994FD5EFDAE09F2AB7EF2
+:1023200056C0F9E6D1FCB62694E7C7A5F54DF6737D
+:10233000945FCCE77CF9594DC49D6A63E2FEE0AE40
+:102340009F5D8678D61C3AE2AF2FB9CC8DFB13BBCC
+:10235000C30E0DC1DA1D5EECBE99FC698746F78499
+:102360008637FD0CF37A4D688FF33AA4B5D0B9FCEB
+:10237000AE3EC7A7494C99B1684E517A7DBCBB812E
+:10238000C7FDCD2A96AC2CA3BFD3588279EBD3B529
+:1023900082F97C13ACCD4179ED03B0B687F787FAAB
+:1023A000D528E6E126341F9DE7F20D8C18183381FD
+:1023B00035A6A782E2CBDC2F5BE8F4792A60DCFF4C
+:1023C0000740829ADC008000000000001F8B08009C
+:1023D00000000000000BED7D7B7C54D5B5F03E671E
+:1023E000CEBC9249324926C9E44566028180012764
+:1023F00021A480580F214008412721405094411EBC
+:1024000006082460ABD8D2CB0001120C1A2420702D
+:10241000A14E12B0F8BCA1171129F60E0F2D5AEDDE
+:102420008D62B9689106F4DA88AF58ADD2FBB57AFF
+:10243000D75A7B9FE4CC9008DE7EDF3FDFEFA63FDC
+:102440007BD8EFBDD75EEFBDF69EB6D18AC7EC62F2
+:10245000EC784BC1AB4607635B559999DD8CC5742D
+:10246000CE2B65D18C65D821318A31E5FC940FD90A
+:1024700008C65A5B942983A05EF6D0418C41BB0309
+:102480002D89C93E1B63D1E3944B9D16467FDFC265
+:102490007FC7270E4E5902F59A5A4CCC0C695B7EC9
+:1024A0006879D36C578A3D87B10806F9D922DFCD08
+:1024B000BFC102C6B2F01FD0FFE98644A913EA29C2
+:1024C0004CD71EEAC5363309C765AACDF1C10D8CBC
+:1024D000A5D825F6AD0CF39155D90AE3FA2F489EFD
+:1024E000FD50BCCFE8377BA1FDB7F8770B63A6049E
+:1024F00089D6B3790DF3BC6F8475B8656F00CA1FB8
+:102500009458653BCEC7C6D476E8F7B6585E2FFC24
+:102510009BD95014E3D3F517FE552C278375237BE5
+:10252000D37546E817FA8BC8EE90EDF98CD90FD920
+:10253000732361FE76D575A413E6D9366A40AE0DD5
+:10254000D6F9661C4C3E81B197B714BC5305F92BE4
+:102550009FB179086EE7CD170D00F7284BE3E7F838
+:102560006D3B3E9BB986437A95C333281ECA5D896D
+:102570009E41309E313BC0101E11AB4C9EF7213D59
+:10258000E95F72923ABF639E8D6BEC9E4100E4E678
+:102590003516FA364A7C9E37FC4B69CCDDB6DE7ABE
+:1025A0005E3B5F77CFFA563DD85417DF9B4E8805C8
+:1025B000F8D968D79C6551BDF916012FADDFF0F150
+:1025C000B57296AF264F84F5B66E31D937031CC667
+:1025D000970D22BCD95F6FB2E3FADB1A666E9E8359
+:1025E000FBF9868170A26DCBE09445BAFE5AFBE9F7
+:1025F000BF46CCFB40B27FB7E4C1F94597BCE68447
+:10260000B4D5BF9B61DA6FE469A8C6C662B9A544B8
+:1026100005781D009C60298C5537BD31C50FFD1E06
+:1026200088F5DF2EDB197BA8E1AF0DA792219DE590
+:102630007F4782F4DFE259B06834A4DDBCFEFBF1D1
+:1026400005F5547F384F7F186F2BC1742BAE07F6FA
+:10265000DD017480F8DCDA5217C720BFB9AC22C59F
+:1026600005E3EDCF0D3A19F43775EBFED316E8DF2D
+:1026700021F1F6CCBFA958857AFB45FABEA68DC5D7
+:10268000FE1C82CFA3088FA60E23E1C77E236B9882
+:1026900003FDB7027CD662FFE99E146F1FF0D8BC21
+:1026A000C6E9690400D6E1D7D89B1F99EDF43CAD8B
+:1026B000A34BA33D34DD2A7952707E2FC3F8CA188C
+:1026C00080BFD143F03B6C9F5BACC07CDBA23C295C
+:1026D000088FC7EDB3783A41CC9FDD46F36F4BE6E8
+:1026E000E9879A4A8A111EE1F36835BA523C39D714
+:1026F000310F51EF7FBA8EFEE070BDE3FF7FDCFE4D
+:10270000768FEDDAEDA36243F9C055FDB8AFAF9F08
+:102710007F141FFFB7FDFFDBF62FDB33490E5D1B78
+:102720001F18D5B3C9CC87FC777B45A1759E8EEF6A
+:102730007CEC90095FBC765E0F04B5E405DEB87FE3
+:10274000FB242BCACFAD4C79C53C10E46F4B9DA543
+:1027500004F8D7FE46D96E7041BA4CB66641BACE7F
+:10276000815C17BE7F1B194169285F07E5CDDE3804
+:10277000AB1BF95D11AFBFD52117A3FCD9E088B31E
+:10278000CED7C9BBAD8D908FE314E5A52CD2E5B7AC
+:1027900009390F922C68063EBA695066EB66776F6E
+:1027A000F97107C7F3E6E6BCDDD9386EBD4C7CFB9A
+:1027B000D49649A76F81749B5D76A17E74CA9EF7FB
+:1027C0002A9517CBC487078B746CB1E27111945CA6
+:1027D000254321AD386586726D086B5FC9203DD0F9
+:1027E0006E6341D45F8A7CD45F8C537619207DDC84
+:1027F0009B77C282FAD76846FA18B38170023D68A7
+:10280000A080F946FC3FA8EFCF66019209B005B958
+:10281000501E4F43A1BC4F7B251BE542914CFA96BD
+:10282000A6AF3538DC04FF78D4E746A07E97B91907
+:10283000E7193143F660BBB8D250BD2C5C8F638A78
+:10284000B78C41BF8D3314B659BA5A5F0BD7CB7AC8
+:10285000F4022FE815D9BDFD4479EC21E9D697D8CB
+:102860003E16C3D8538A6B37EA3B4D81488F1FF21F
+:10287000BF7ED76C9D0AE92FEBF9FE2A8CB919E0CF
+:10288000C943B80F30EF4D4D4A6008CCA34B16F04A
+:10289000D828133C14CBD45DA8F7B4BDC48EB21BAA
+:1028A000619D2F318F14C3A88338D4BBA2D302B843
+:1028B000CF079F31F17651964016A43F5AE3DD557C
+:1028C000878A45D3A38C2532B6C4C2E16935345911
+:1028D00070DC41B2E7E1F150EFF4B3472F3F897A62
+:1028E000D91391B4DF6D46FBEC0590AE8AB7D0BC2E
+:1028F000E1CF8DFA4F1DEA0FA44F303F83BE961AE9
+:10290000989087CC6F013CED8AF02F47F9296F5FD3
+:102910005D620179FA4C042FFFAB63ED66FF38D49A
+:10292000A76FCE4679FB9B47E6375873191B6AD6CB
+:10293000FA1BB2793CE0ED4159D2FA5719E81FED84
+:10294000A85760DABFFCD52250C9EDB256BF6A3332
+:10295000EA3355274D429F1817311E6071B0D03EA3
+:10296000D209FDCE692E28B1DC8CFD69F33B6129CB
+:1029700084F91D34F1F6D31D278A713EB903DB2F8C
+:10298000FC04D669BEDFE46965627CA49BFB4CADA8
+:10299000A07B5DA567DC2CE8BE3D9F15239DC1FC97
+:1029A0002A033AFADB1E6F207C6CC12FD60B0C97E2
+:1029B000510FCA5440EF46BAB4B0F852A4B386D609
+:1029C000B148375ABB3DB11154BFCACC6A91DF1C24
+:1029D000E9941FC479B436DA630D300FB9D1B3EE80
+:1029E00022E4DF1C1F47F50606F35224D4BF0E9CD9
+:1029F000C9CBC1FD3E6423FDF1F28191BB0D38FFCF
+:102A00006613C376FBA36C958F23FF08DC50847894
+:102A1000A38D77AB98E7A6FABCDAC550FFB2CD66B6
+:102A2000975C88AF9E4AC49FA76C26BB9FE8D09E48
+:102A30008C7C6D901C203DE8C8D6B3F57500B7417D
+:102A4000028ED98EF3A41736785D1112B46B4A93B7
+:102A500019B6DBE428B7A01EB877FC4AFA6E726498
+:102A6000A6DA609C06D5E46250DE349EEBB52D8A72
+:102A70005AEE86FC962687E4D7C1C31BCFE1DCEA79
+:102A80001174E0E07CE1C958C00B483F99C0DAD628
+:102A900003DE9AED2C0FD7654CAB55D53EF4C2B989
+:102AA000A21F06ECC656402440F89F5874F6A7C8EB
+:102AB0002FBA4C1DB3EF4178C546785A21BFCDDA05
+:102AC000918CEB488C8B90711D49B81A00559DCCA8
+:102AD000A6E2B81BD2987D2DE6379BFC68AF243662
+:102AE0009BC87ED980F48BF6CE0216C0F525D5CBD7
+:102AF00017CD58DEF9F91A1CC7D928074D989E63DF
+:102B0000622E1D9F709EFFF0EF68873A19E4EBF884
+:102B10004C65B4F7ED58D81F739A9DDB8158B70008
+:102B2000F953CF9F13F9A7492422EA65BF19FA790F
+:102B3000662D87D7A6B52C80F8BBFF39F634C2C7FF
+:102B40006469EC3044537BCBAA3C1D5C57035C6149
+:102B50003C53F3C615B80E53B66E1E48F48E44C2ED
+:102B60009334D62921BFD82BEC11629D5094813823
+:102B70009289700C46DF8470FC999C8770241B043A
+:102B8000E6872C0ACBB5FDF82FD4B312AEEEC725DD
+:102B9000FAD1D28F8976074FC54DCD817E1FF3C7FD
+:102BA000E521AB817DA8E2F28DF78FE62EEE4F8214
+:102BB0003D421D0AF33F1BCFFB3F18515BD5979D4C
+:102BC000F087782EFF36BC021B0B7039B8CE75EF3C
+:102BD0003C8457A1CC90FE8FAB9C0FEF2F6201334A
+:102BE000C24FE5706A6A64013FC069E4EB4A830C36
+:102BF000F3491B2FC719843DEF87F946E13FA069D0
+:102C000093C7CB504F8C7230D53A02E9C15B89F340
+:102C1000608A5D2A1B4EF4CF649877A4A81F55E400
+:102C20005F81F8D164B15BD15FB035CD5582FE874D
+:102C3000A6EDCCDE4AC0F0C86551BD70B109B844FC
+:102C400036423BD84F5B331F07FB45E48EC672D834
+:102C5000A748C7E1FB252C57F937A62214EFA24657
+:102C600087EEF356018FB5711184C74DCB60FD6EB1
+:102C7000C12F715F97707C8AF484F693AAB0625377
+:102C80001EC2DB9EBC00E1B8C3C470FF33FCA1FDD3
+:102C9000A734271622FEA5315D7BE85F8D8BA5FD4D
+:102CA0004A39BDA75C46FBBF8AC906409A54E6571D
+:102CB000ABF2687FBE4079BE2951A67E531D718557
+:102CC000484720B78B514F4A4972E56D66BDFB6B93
+:102CD0007478595E0ED6B3170E867A4FC5093C4FED
+:102CE000E4789E7ABAFB5E84774A75E83A989EFE4D
+:102CF0000CD74E1B2DD1FE48E8C71846B737C67310
+:102D00007F92861728DE90DF004763C8472F47BBB6
+:102D100036A31EE3BF4FF1EC877CD4D1D2608EC6C0
+:102D2000A7657F12F467862FF20D63BBE21F124D79
+:102D3000E25D356179DA3766FD7C0F3C9743F675C5
+:102D4000AB91EB7B06A1A76A70F82ACE44F3F84A50
+:102D5000F85D807313BDDC27E65AF87CDA04E4C71B
+:102D60006DE95C1FEB923DBB23715EEF98C926872E
+:102D7000FED76379AC0A7A860EBE9B945A4B6C0ED2
+:102D80002D29203BBFFF7783D08B5A518F89E9CD06
+:102D90006F0BAE5B3E8FE17AFC054807B14159D31A
+:102DA0002B9022F57A81DF02F267A8C1FF5515C882
+:102DB000A3C4F8AD53EC4351EE3351BE718A9A0669
+:102DC000727DBD24F4829F3560BA570F00B2B3F410
+:102DD000EA01CCFFC8942AD403D2B4F6ABA7A8006A
+:102DE000F4768B565EFC0ACA953A637B01EA2D7530
+:102DF000B127EA51AFD960F556228F2B684E0CD11E
+:102E000073863B5249CF196EE8186681FA3B9ACA1D
+:102E10001A8AD2913E5D11B8FFD7824FABE28AB0D9
+:102E2000A35CC7F5C3F80D7153A6AC55AEBDDF8FDB
+:102E300089FD9E17C7F9DB7003D723C2F9DF735AE8
+:102E4000799BA916F596C221364EEF0D33F721BFB7
+:102E50002B7CDEB62B12F9DFDBB38D48FFFF1AA700
+:102E6000087CF6EEC6FCD6B7CD0CF54CB4CB699E0B
+:102E7000CFCD21A6640C98D4401F78F154DC506A61
+:102E80007FD53AB3F8B8079EB305400366CFAC03CD
+:102E90007EDD873FEF9498EF863580089C9864D25A
+:102EA0004712BC2A8E9BE9F4F919B433815EA6EA75
+:102EB000E8436BAF5C4965AACE9FD7625719D657D6
+:102EC000AE0CA0FC1506EFCB71D0FF7B835A173FE9
+:102ED00008ED760BF9521FA39EC6FCF5B2FA70B14D
+:102EE000FBEA7969DFBA35C120EAD73D6963DFFEC5
+:102EF000BA4B315C2EFD0FEC0295F8AF2D2230C499
+:102F0000ADB30B1E51AE6917603DFBC6B800DA3594
+:102F10006817C4915D600B6449FDDB0506B9C98380
+:102F2000E336303513E5EAE96797348D47BBE07542
+:102F300003D9054F3D3BF6769CCFE5D628D22F61CD
+:102F400004B213EC714E0FF2E1FEED8317EA8B73BE
+:102F5000AE6D1F84D34D9ECA08AF148515211FDCAA
+:102F600084FC1CF6C5780AF42BE48F2EAEF720FF04
+:102F7000C4AFC9E121F9A8F11725A0503DC379B329
+:102F80001FE58FA17E6307EA398ADD4BFEE4152633
+:102F90009F257E14B14705E1A0E957069BCA7C39FD
+:102FA000FDF38DAC6D8553EA61BE86531117A9DF21
+:102FB000201FDF707E13F9B1D9A1D0FE601C473C01
+:102FC000ECBFE9883718E9EAED5FE353FFE71175D5
+:102FD0008A3F0DED8528EADFB9ED87AFF8077D4719
+:102FE000FFC1ABFA77E13AC2FBD7F8A26DDB2D0D3A
+:102FF00064EF404B33C0B0EA616E57256EFB21F1A0
+:10300000977EC779EDAA7186F7B90EC13FAF3C3202
+:10301000A1C1AFA01E5A5BD9173D97C7717D3C5C1B
+:103020000EE2D94C5A1E977F49BAFD34A31C1CD11D
+:10303000BF1CBC03F101E65315C9F9DDB16E39F2CD
+:103040001DB29B1263918EDA150FE1AB3D2D515AE3
+:103050000BF453E4E0F2D01EB893213F951DDE75CA
+:103060009D689F6CF7A430DD7C5B851DE5073B2ADE
+:103070008BECA8F379A887FA9FAB6659AE5E7BEA22
+:10308000F2817B2D8847FB624DD4EF1D71765A9FEC
+:10309000F5649E0FF53BA2449D1E5015E39B81FBFA
+:1030A000647670396F4E63928FF4596E67FDA3F6A4
+:1030B000CE71E1C76CB3BA4A26C37C130B653BF2F1
+:1030C00017CD5E01FBC03A08F5A92D32D9BB3D767C
+:1030D0008AB06334BBA84EF099AD8D722BC26D3FA0
+:1030E000CCCB0AF4B4B53EEF4C29F4BBA15621FF7A
+:1030F000CA55F68C03EC1CD8B7A666792AC27D2B7C
+:10310000D84B680F391784D69B15E3BB0FF1C8560F
+:103110002493FEDA96DD4A7662B8FD712DBD355CEA
+:103120001F0DD73BD35685967F7FBD8FEB6DD7ABF9
+:10313000FFE15F5F7A1FE9A1C4478636A0DF82EC1A
+:1031400034488F8C1F4A74A904393E284887F845B3
+:10315000FA433A603E264944777B894F554B0A0B28
+:10316000B10355E68DBADA0FA17D9B624D421F086F
+:10317000E5ABAD0D335310EFF61BBDE4D7FEA5F064
+:10318000931E12DF6A71BEA4951F16FED423FD9410
+:103190001F15E5C7C437BCFCD7A25DB09FF6274416
+:1031A000BB53FDB47F59B43BDD4FF9ABA2FCB57EF8
+:1031B000FAFF9D68D7D14FFB3745BBB7FA697F56F9
+:1031C000B43B77553997F7EF88F2F361FD5F10F55F
+:1031D0003B457E8DDDC5FD1AFD9C9B69762BE6A1E6
+:1031E0009D48AAFBC0DEFD34F4E8F340A305BDF61C
+:1031F000A0C63762F35900FD139A9DA9D983EE3812
+:1032000017F7671781BD4899ED8437ADB8BE9CFEAE
+:10321000E1730A1DB0A3E8DC8FF44EC49B853A3CF1
+:103220003B1D6FE4E5B91C0EBDEB1A2C6BEB92A1B4
+:103230007E87B0CB6B84BFFC406C6F7F7ABFF6217A
+:10324000E197D2E6D51F5EB58B7969F5FADBFF60B1
+:103250003C0BE9AF3F3C3C1456AF3F7C381D366E0B
+:103260007F74F174587FCF8A7AEDE2BB2F5E16F03F
+:10327000F86E7C08C7AB56EDFCD6DED5E0CFE9EDA5
+:10328000BF3FFA3826E68B7F7AFF81AD9EF3DD04DF
+:10329000D61D821FD1AC83FC291A7E18AFB8993A8B
+:1032A00012D35C3ECD8CE7F3352A5E86FABFF1CAB5
+:1032B000202A1F78004C7B904B1B9E83D9C37760DC
+:1032C000A35DF241FDA6E78041423AD631534679EB
+:1032D00095A5DEA7A2BCAC3ED5A1BAA3757A732C86
+:1032E00087C7B5FCB1D5FBDEB95DD2B57B30B6473B
+:1032F000AFE6FADEE69921F648383F7C2CCE42F55F
+:103300006F895477A17E5F15C3FD7A6C02B3A37FEA
+:1033100000F42F09F587B60446FE50D901FA03944C
+:1033200067A599D864289F2CD61F64136CB9A86729
+:10333000D473BF94A63F0C35D8BF40BD81C55B5C3C
+:1033400028BF51DF42FF087C4F99E17B9F3857FA35
+:103350001EFA565D6C1F7A5D5D2CFBBFAD072F76A4
+:103360005C971EDCB71FFD7BE8C13F76F4A907C759
+:10337000DEC062715D2336BBC65CDDBFA617FFD41D
+:10338000F16FA7FDDFA5AF5EAD17AFEF6BBCEF7BB5
+:103390004ED09ACFF530BFC7427EA4788539E3F38B
+:1033A0001040A51E3C7F536339DFBAD679D3B5CE22
+:1033B00097AE75AEB4C71145F140604379500F998F
+:1033C000F42F398F14C3BC56BE61203FCE3EA32AD2
+:1033D0005B21BDEABCE459C7AEC67F2D7E478B8B0F
+:1033E000D1EC552D5E66BBE22F273F77739C84722C
+:1033F0004449E07479DC515E8C7EFAD60A7E1ED890
+:103400007A7A7B319E5B7EA9F273CCFAE6F292A1C6
+:10341000A8EF05140FD28D4D56A7E0F9D3F68ACC4C
+:1034200008C257E04B7A3B7988C38794CDF657148E
+:1034300092DE57F7B70916947B9BEC7911A8973762
+:1034400035F273CFB646D93A1FBE5B2B20DFD69B31
+:10345000DFA4F67DEE19BEDE81B1E21C81B1628A85
+:10346000FF3939BB0CE371B2EAE372AD04552FF9B1
+:1034700065A70AFEA3AC3278DE079E9950CFE92AF1
+:10348000CBAE323CDF5030EE08F3996E7FDC18375C
+:10349000C5F90174E197E2884F7A06E9F5C47EE840
+:1034A00053A3478D4E35BAD4D1E31F881EE784EA73
+:1034B0007B1AFE6AE75E0F38FEAD782DD889CF48BB
+:1034C000DC8EFCA3E3C57AC457A38BEB939A7E688A
+:1034D000C4F146E8F44C8CBBC2F9387C349E6EDCF7
+:1034E000CB482FEC34EB53CFD4CEDF3A1CBFA678B9
+:1034F000971E7C09280CED040D4FB60A3CD97ADAE8
+:1035000048FCFB4BA01BE6E6E7E87DC59769F8E1C0
+:1035100015F2301C4F3251BE001F6B43F902DFCC55
+:103520007AAFEC8BEA952F598D3319EAD546942F53
+:103530003957CB9795627F57C6DAE9ABC991DB6201
+:10354000B9BDC6144F36AEEF80D14FF126275AEEE3
+:1035500073925DF8822FC3DEC77CB56F578C4BE842
+:10356000637E2BFAB5800159E5D1042F9B04F0ABA3
+:10357000EE81DF0AF2BFFE58E046B5883F9C68B096
+:1035800091DE16B14FA2F386A57E85F0A3DABF6E59
+:10359000854CFB1720F8B9F719C9EF06E5B48F5A27
+:1035A000FBA5ED6616D4F197E58720ADE3176EC64F
+:1035B000E3EA160398823ABC75E3F979349687E614
+:1035C00033C39C18C4032B023DF9EAF5AE3A3F3EE3
+:1035D000784AD7FF8804E0477898F103F603B2975A
+:1035E00044FBFEE0F5F51A3578CA88E73D6A7E02AD
+:1035F000C20D0F3B80DF3F348C917D1A5E1FDD488A
+:1036000008DFF9AB26B0F7806F1D36D9C72BC88706
+:103610007F2E91DF605DE40F2729784EDD0543435F
+:103620007AFE03BFDD86FEB0E51D4D13A2510E37B5
+:103630004AB9E8E6DA7EA236D70EE9EE3B6D37A34B
+:103640001EC16CAA0BCF03D1E78CFAD6C7465EEE3B
+:10365000BFD3968B727B5E85FA36E2479261456EE8
+:1036600013DAE77F83D541FD8562379F6F2E33B92B
+:10367000005FEE5182C72598F7BC39AED108CF79EB
+:10368000ED5615BF4926A658413ECCB3302502BEA3
+:103690004911CC42698559305DB08ECD457E173DCC
+:1036A000DA6B9A07FDCF3BF68BBF70653DC0FDB866
+:1036B000C75EF92BDAE10B55AF09F58A1B0E98F8B6
+:1036C000198F80FBF0F6D0F48D4742D3B9C1D0F406
+:1036D000C8D3A1E93711F6F0DFAFFE7EEF1F7F06FA
+:1036E000F0EC7EDD40FAD65260473F043E76781813
+:1036F000D038AE5B090CC0F1C18C6511E8F77B32A4
+:103700008AE2493E5DE3DD5504803DD12593EF66B5
+:10371000E993512DE82F3EFCCD7B0FE13960F73363
+:1037200091749E3A61E9D3CF3E00E98F9E888C4523
+:103730007E7079D7F33F27FFE13343C8AEFD48F8E9
+:103740005B8FBF73F483DD90BFE4D9C85CACF7D165
+:1037500033CF0F46B82C79EAC501187773F9C9A79A
+:103760000A28FDE41323F07BF9895F0CC6FC8F3433
+:103770007FE893E616DCB7A54F5B2FC603DC3EF867
+:10378000C466D39F776BDFEBED7729F68BF883FD6B
+:1037900022DD3DBDA9231EE9ED40943F5EC757964B
+:1037A0001C78F0737D3AFCBBE4009F4FFFE5BCDF63
+:1037B0002500E9D100F70F847F7FE90173C87E0DF2
+:1037C000D919BA7F4303A1E99A4F2B4B62619CEC54
+:1037D0004FE794C4427F9F321E9F103EDE7E111F32
+:1037E0005C7324B4FFA34ADFF59F12F23F1B4F9A8C
+:1037F000757C22C5DCF7F9C2C1042E6F9F7CB2A78D
+:10380000BE81FB5180CC402F5B2AE8ED573D714AC9
+:10381000EC47A940574BC5F9AF96BF94E9D607E3EB
+:103820007D61896EB503DF9F2DFAFFDA08F483FB13
+:10383000B526B80DE39C3F58A3AA45BA38AF7BF62E
+:10384000CCDB980CFB577D302B1787D7F287B51B45
+:1038500049EE563F71321AED91CB074EEE5888F87B
+:10386000D86E64A81F427E22E67FDCFE52F41D90D3
+:103870007FCF4E772EF2959E7E774E548B74FCEF61
+:10388000FBD2A5C647AAED1C0ECF8FEE98940AF87E
+:10389000BB74A7E4C16A4BDB674C9F8678B7C7E06F
+:1038A000413F6381C2BC863C5CC7732FA7407ECD7D
+:1038B0008BA30A703DD04505E66F96BD538723DF85
+:1038C000FAB991E2C121FFB40C787422FB11D3251F
+:1038D00058C77F2670FB68F34C5B15EA4DD0DF2993
+:1038E00019DA45EF9354913E87F5BB0ADBA3D1EE7D
+:1038F000FBD068ABC7F3830FA36ACFE03CFCCFF0EB
+:103900007E5990CF7BB13827A83A66243DE2F03744
+:103910005FCC1C8BF4DE627023FFB86767285ED92A
+:10392000D52613CA832AE8DB09E35E6E89A2FE2F3F
+:10393000270406A05C3DFC4DDB05A4B3EE27CCB20A
+:103940003EDEA6EAC06FFE8A7C757120B4BF70BCF3
+:1039500088489434FB365B8F5FE1F590932905BD71
+:10396000E5D5AB404EE8CE85AADF6F32A11EBAB8CE
+:10397000D4F49DE37D71FEF9C12E99F0D44FFEE1A0
+:103980008306F2D37EF48989F8FED261ACC805EBD8
+:103990005CEE9CBEAB08FA5F5ACE8A310D7F920571
+:1039A000C6BF8CFF1AC8D374EE82784F7EE2E04324
+:1039B00037011E7CF44B03C5D3A5E0F91DFA3F582F
+:1039C000305A46FED66E90719CCB5DA000025C3EE4
+:1039D000B607A3E3904EBA36939F706DFBC9688C0F
+:1039E000875FDA1E4FE7ECFDF19BA3CF586519E026
+:1039F000FF71D7E391AC0FFA5DD2C5CFD7C3F98F72
+:103A000026872FE23F415EE726AA398928433058AE
+:103A10001EF484A4F8DADCDA3EFAD3DACD9378BB6C
+:103A200024C34AAA37C6E92DC0F651F97E37CAEF3A
+:103A3000389FC583E749EF193CF7D907A29CF59950
+:103A4000C80F519740FDDFC3607F207FBEC2820A4E
+:103A5000E0EB7C94CF23284DFC7FFE012980472991
+:103A6000518DE69073C045CD90D6AF638FAE1CF8F4
+:103A7000CD6294DFD174FE15447FEE927DA1F5975F
+:103A800082F98EE3563FFDAD59DF2F689E02EF5459
+:103A900013EA8D7F117019E3546FC37549E5169AC7
+:103AA000D7BDDB63288E62A1F920F5E310F114DDA8
+:103AB00007A5402BCA15A13FD43C304F5D007ACBFF
+:103AC00067ABE6AB0BE2859F06F9C04E89ECCDA54E
+:103AD000452C980EF3BC5DE8414B8F49C1E1905EE7
+:103AE00008EB477D62ECD3923F0AE4DD420BF347DB
+:103AF00023BEBDC5F7A55AAC0BEBC5E4211CFD04E4
+:103B0000D7C5AC83E633B68AFB57C61E91286E290B
+:103B10001C5E557BC2E0A7874F26C22514DECB0F63
+:103B2000019C42F086C309F41F66857DDB2EF8FBFD
+:103B300005B027F4FA256030D5DBBE56A2F2ED338E
+:103B40004CCC09F3DA317B511BC6D93C8CFE0E11EB
+:103B5000678871819B7BE20041FD85F12246B2DEE0
+:103B600073C7D1A45F517ADD0E75EA4EB08776181F
+:103B70007DC9E8AFDA5106FA2ED76BACA8D7743AF4
+:103B80007D9B1261DCF906EFCB68682C90D5010AA9
+:103B9000E2DD2A0EBF47F36A87D6F6211735BCDE71
+:103BA0002175A806A4CF9FF1FB3891C70E0653617B
+:103BB000DECB8A5DE4FF4C98753E1BEF9B3C26F8FC
+:103BC00054CC092EB77649AC0EED4527E08304FBB3
+:103BD000927F686B32EA9F6C81290FCF9B1E8EE526
+:103BE00072A1FB0D76339DD344D6B660DC51D2DC96
+:103BF000EC3C3C0782F5CE2D877EF625BA681EC9BF
+:103C000036BEBFCE757EF74AC84F029844C5E178EC
+:103C1000DE152F613FC3797C1BE4D7A31EEA646BDA
+:103C200025ACB73181C37BE33C56F9CB1C3A6753D3
+:103C300062E2F8F71C7CC1FAAC33C23749013D9609
+:103C4000E7D7E138DBA3F93A1264C3DC32DCAF3CDE
+:103C50009E8E5B2DA9AD84BC5B695E4966568CEB7C
+:103C6000C47CF4C7C1B4D483541EE07831A1369724
+:103C7000E63B907F5FEBB4F80D80C7AF3934FD337E
+:103C80006823FD937965E4973F1272F333A39A3466
+:103C900012F9EF1B46867680634058FD41D9BCBEC1
+:103CA00090575F7A26C420511D31AAFFCE08AE0678
+:103CB000A9B58F73FD37C53ED55C4965019D7CA8CC
+:103CC000A9FC8AF4F09A2B0342F23F5E032B19A25F
+:103CD000932355272661BD65AC6323E2DBB27603EF
+:103CE0000BE8E8E38895EBFD8CD5FEF16730FF4BE0
+:103CF000AF65E5E9E340353AA8B962607EC0E99B6B
+:103D00000C32D5AFA934511C404DBDA105E9B4E634
+:103D10008A899767F0FE6AAEC4337F3CD697C84F56
+:103D2000D5DD60207F69EFBC13A9BC673D57A4D0E7
+:103D3000F491AF453D85F2D9E8CE68E46B8B31BE96
+:103D400000D2A520CF903F7D08FAE92F61BC4F3DFE
+:103D500006E21B9F8AF97CBC06180FC0E192C2FDE7
+:103D60002C9702B23F4BA77F5F12FA28535CD1E534
+:103D7000C3AFCE4F3174464B88FFBFE2724E2BFF6C
+:103D8000D4D54972AE276DEF8C46B87E5AA9D17151
+:103D900050C17DDDED39AEA0DFA8DA737C12D3E12E
+:103DA00057EF3E44626C79CF3E24AEEF08CA187AD2
+:103DB000F668C3833956F89E10FCC3FFE0832AF0EF
+:103DC0008B44831CC24F30F6458B4B4694DA2E1B36
+:103DD000447C51E38345E3746951BFA7BD7FCBD4D5
+:103DE000A234A0EF1CDE3EE3D1877EBB4ED1C90FCB
+:103DF000A57B80374A97B684A56D901EAE4BDBC37A
+:103E0000CA1D61E5CEB0741AAF7F574CE72803D8BE
+:103E100076C31E7D642ADE73BA2BB5F3C7786FAC08
+:103E2000D1B07D6A5132CA61CF24E4633547243B67
+:103E300057D739FC967B18E989364FA709CF6922F5
+:103E4000F33D2FA33E520DF524C0DBC89C20437EDA
+:103E500057D32E51DC4A4FBB76AE5F56B75FA47680
+:103E6000FDF69F2D135FD89C7D89EA2D5BF58909AE
+:103E7000F5A1CDD5AD5E94532B4C9CBF29CCA7A604
+:103E800002BD2E3F52467EAA3F0C3FF67B0C178D9B
+:103E9000FCD1E76B15A8F2EEB23F8DC2767FC0AEC3
+:103EA000C7205F0E0CC5F673AAEE1E8AF971391D84
+:103EB000BF9F09F52E183BF762FCC9DD49BF988A00
+:103EC000F7B92E4475A6635CF382470FF27442E79C
+:103ED0005E84CB7F3CFA4B82D385F4CE7419D28BAF
+:103EE0001FFD88A7B33AF762FAB1A40E9E1EDE99B1
+:103EF0006EB0A33BF68DA94590DE6FE77CF0E760DE
+:103F0000D7223FFD43989C9B9DC4F5F107B2D48A0C
+:103F1000243ACFE572662FD82E16E09377EDEE7C2B
+:103F2000663FC0E9AE9F44A28461FB3F9E5EC2F93A
+:103F300085DF8BFA6B1247612E0F89AF2BA44724C4
+:103F4000A30C8CEB856BD4800E17CE235C6E0C4BD0
+:103F500054CF2525F47E13DDF085FAE7925CC28FFD
+:103F6000559BEB827EE7CCB179306E88299DA310FA
+:103F70009F1EB6F275011DD07ED970DF90EF88F5D7
+:103F8000D424713B715AE244EAEFDE7727EFB27036
+:103F90007B8EDBE7CB8CA4C73497A9C9E847682E92
+:103FA0004BA4F8EAC3DF703ED2BDD54AEBB81DF989
+:103FB0004C3CF2033519F1854D37113FD0F850F3E1
+:103FC000E209C9C8A76E321426231E769799C86ED7
+:103FD000003EC8F9DE32630BA5353EB8CC487C50B4
+:103FE000E35B8CB527E8EF71DE61645EE45777B47C
+:103FF00084F2AB3B24C827FED29EA0E757D7CADF86
+:104000009EA726231FD3E695B4BE9DE691F4A83B58
+:104010000EE14F8215F59AAD435A11BE9DCE7282C4
+:104020005773D9E3D6BB737AF1F7892C7527EECF96
+:10403000ED228E4FC313FC43FFD7FC6D492DE8875B
+:104040003927E00E7ACB08D4E78E39B5FD648407B2
+:10405000E792B8BFF32E73D088F4F0BFFBF20FEFF6
+:10406000CB6FFF917D59B6EA4FD7C5DF34BADB215C
+:10407000058D49B84F2F72FD12F3CB014E8D89BECD
+:104080000B493A3FF95D3F5D964C7144623E91F7B2
+:104090003F5F3C0B92176EBFBCFF71687FE12756F4
+:1040A000D283C2F5D70BEF581AD14F1699D3B90C5A
+:1040B000F73B6E55A41DF5ED0BC22F7741ACBBE06D
+:1040C000274B5F43BB33DFC9CFB9008F9285BFC693
+:1040D0006FC1F99599BE1B8F5E3450FCB855E05105
+:1040E000736E60D722AC3723C7E37791BD4BFA0DCF
+:1040F000FB6924D9D3CD5997089ECD63189D2F35E0
+:10410000BB7979F3ECC1013FE191EC273C9A1D4169
+:10411000FD6A78A8C53D7E56E9A4B847C03F3EFE7B
+:104120006299F0B8A77C5026DD97027C24FDA91780
+:104130000FBBA3CB74F8F399F08B7D86FA4C8C2ED1
+:104140005F9C2781FC8E2E8FBAFEFCC4F52ADD2FE2
+:10415000D1F050C3BBF71F01BC9148BD188C74E06F
+:104160007672FCD1F8ED31A72FDD99A0D79F395D8C
+:10417000CD7F7838B5DB14C5F9F31E2BABB7E4F56A
+:104180008EBB07EC0C942B60976662FBB9D0F008ED
+:10419000A4E726F97EDD89E3ADD2F0D76B427C5BE4
+:1041A00028EC61B63AD4CEC3F8A79EB4E1EAF42273
+:1041B00095FB8DAFB2B7D937E6D0765C2F89CCE9C5
+:1041C00036229E3F6A657EAB4E6EED44A730AC6BE7
+:1041D000E7039101A44BADDE171F47C8783FE1F418
+:1041E0006B2363F05CE60BE68941FF510DF48D7E95
+:1041F000536651E761BB9A75512E84C7725C02E425
+:104200002F975DE4D7BAC9C0EFE7743F2711BE60AE
+:104210003B9C6FCD20C6C6C591BD4EF8F54183814C
+:10422000FCD837650416131F5B1CC1F83EF91663F2
+:10423000FF972A87D13DC19B0C9F3F4EFDBD60A6D5
+:10424000F24F133AC99F558390C17EFD7F5FC3FD36
+:10425000F9B06589BDE740E877D5DBCB9FC27F78B1
+:10426000CF41C3DF6A714FA7171F5DD1880FCB65A0
+:104270007EBE18AE5F13752492FF180F73AE47CF42
+:104280001E4C76E6AFAC797A3D3BFC8BF01B974732
+:10429000DF5306DA9FCE026F541FF5E44B8357F6C7
+:1042A000611FF794EFFC13DD6FC273293D5E54F775
+:1042B000E28FF4AD84F3D7E193BB973FD5087F0736
+:1042C000E9DF38EF2246F1CB51221D59DC11407E47
+:1042D0009570A27312D9415D608F63BD1C9687FEF5
+:1042E000D3B1C75A4EA27E1A57D4918EDB5823FC05
+:1042F0007E1ABE69F31C736CAB01ED068DDE74741F
+:1043000046E32CAC4AA1738F4E64A26330731DB593
+:1043100047FB97DFEF519317C29C762CCEA4FB2866
+:10432000910A97070B9B86B4AE15748DFC40B39B26
+:1043300041632C407AEB7416FEB313FA7928B970F6
+:1043400007D227195F63FA87A70617AD1EDACDDFFC
+:10435000E5775BF909D00DF0ADE257B292906E5659
+:104360004AAE24C4D30F0C3EF2B3F5FA8382F4AD07
+:1043700016F4BF48F89116697EA39DE690B849F4FB
+:10438000CBEAD34B843F891D30F7C643A27FA88870
+:1043900005A3A0BF65E887C26F7B68BBE5AC9BDA6D
+:1043A000D51CF93624AE9735F3F5CD15FBBFCBCA36
+:1043B000FD47B1AB5B0CDCBEE3EB8BC953DD1B905F
+:1043C0004E5F31927FE33FB188F8995A807C7C8CB4
+:1043D000B33080F08D403B1AD6FD3EC835DC57D057
+:1043E0009FE796A31DB986A9838CB47F05E57DE080
+:1043F000F7E6A3D62AC487D7043FD6F2373A8D947E
+:10440000263F13F2810633F195824CA1EF34985B7D
+:1044100051DE2C30F3347B909F232D9F69F3617F15
+:1044200097841FEC9C93EBCFE79C3C4E534B6BEB7C
+:10443000D3CE09D1DFA3BFCF76A1A71EF7B3007FEC
+:10444000A2F8AC1DC6807521F14D2FF9DDFFFC31BE
+:10445000DFFFD3A7E72FC679FEB93282E139F30235
+:10446000E18FFD3373111FEDE18F2D069293BDF2A5
+:10447000B496CE07BB5E8BA7F8FE1E79FAA14993CE
+:10448000A77EE4935DED43B9BC05FD8EF4ACE7383F
+:104490003C808F115FF5BF385CDCEBF6EDC2F39624
+:1044A000AEF6040FFA3D3EC07344006597127802E1
+:1044B000F514FF312BE9395D82BF7D76F1E208D436
+:1044C00097BA04FFFA8089FE0286D6FD347E2075F5
+:1044D000BA6EDF8E8A7B855D2CB888EAB55B43FCBB
+:1044E0000929669ECFFE15F275FE9F5F1945FD8373
+:1044F00056499F7FD8147C9CF4E45FF2FC77CCBED5
+:10450000A8641DDFA88E0E0E8EB57D17FC80C1E15C
+:104510007A8FA5737D2303F804C717C2D71EB9D3BA
+:10452000626835737D84F7F38224E0D79D4DFEC524
+:104530000F07BB70FC751FF2FBDD475BB89CFACC24
+:104540006BA278EB2E2117BAC2FC2E1ADC76184526
+:10455000FC128C83F0386C5267D37A379BE3B1DF5F
+:104560001AE4D3E887AEE77121FDF19F9AD6F9747A
+:10457000CFBEDFF2AABFDD45FD849D2F7E5AF5E751
+:1045800001FC7E27BFF7BFDC2ECAC2DB0BF9C71CBC
+:10459000DD897DC99B9E7A5D1B5760BDF071489F88
+:1045A0002AE07218F9594DD8B925D3A70D57A74B52
+:1045B000936343E225C732ED2FB4DEADC86312B07A
+:1045C0003CB4FFF78DFE683A0FFB50A6FD5DD63C6C
+:1045D000EF2E5CF78204DF8C64A87FF4914D050414
+:1045E00007A1878EFD2887EB7D4DFC9CE37DA37A98
+:1045F00017D2796C51D074B74EAE5627F373CFF9FA
+:10460000667E2E8461857A7EA595171486F209ED63
+:10461000BB3499F38BA80E2EDFC08033A3DE701459
+:10462000FFE9D2D7E37CAE3AD945FD657471FF4FFF
+:10463000C6EAC07A8CA7A86E9F3712C196B13A48D5
+:10464000FCE57D230BA2FEFFFEAE28CE0FD0DF01DE
+:10465000FD2E1ACDFB5D6400FD13CF23C4B9E71214
+:1046600001CD4566D053819F3F7F60BC210AFA5D32
+:10467000B247F258A1FE58C1EF515FCA40F923CEAC
+:10468000C5AB58C7C64EE87F5123B38CA6F88980C6
+:104690002195E04CB15D00974E3FD9A54F49B9E84F
+:1046A0000F06B955170DED96A801F26B869F4B3298
+:1046B000FDB922EE079E77E9CE85963535D0B99AB9
+:1046C000260F516EB130BD36148FFC7DCA5B4D1E76
+:1046D000697217F4F06DC97C9F42CE8196B15A7E03
+:1046E000DE25E45ECFB8426E7E60E0727A91792B6F
+:1046F0007D0F24BB697F96B04E2E77418E22FFBF7F
+:10470000D6FE1E10FBABED6B3530CA9BA1FF27C454
+:104710007EF7E0D36A165C36827FA346103CB93E32
+:1047200060E1FA007E23AE432F08D707C2E57FB8C9
+:10473000DC4F327139AFE181FE9C00F59CB1AB03D7
+:1047400006DCCF97D704B6BD9FC5D8D7D6E81118D9
+:104750000FB6CAC2BFF74744B7E2F76BEB8000EA77
+:104760009DFE424E67FE0B51743EF8B5ECD9F9063A
+:104770007C276DE274B4BE81CB8BF56BB93CBE98DF
+:10478000CCFDFFAF88EFD7025E27703C23DE4F38A9
+:1047900040E34EB2E42A48C753ED9F0F50A08A0170
+:1047A000F4A5488C73B6713E6B381245E77E935280
+:1047B0006F0EE23E9F8C32D13B2848F736D897C91E
+:1047C000ACF7CF0EE949F80F1872B26DF07F22FFF7
+:1047D0009C24F6BDDAE27B0C43D73E31FA7E818E13
+:1047E000D33D66DFBB883F1399AB0EF5FD09232649
+:1047F000D33C60D80B989FC4D43F26935E9066A7A5
+:10480000B82C819FDAFCB5796AF347D9857AAAE199
+:104810009899E2CFC2E76710EB59FF4254601D94AC
+:104820009F4C7E7D23E253F8BC35B884CF1FE6FB56
+:1048300005CEEBABE437EE42BC2DB4C03A649AEF40
+:1048400097384F98EF5F92475D3D5F13F291811863
+:10485000AF1AE50F8B53FE86EAA7C92171BE5A7CB9
+:10486000A24687273F6199682FB27A20DB448417DC
+:10487000A7838936F345A4AB13467604E9747D1407
+:10488000CBC6F59F64119E756EEA66103E7920894D
+:10489000FA2719A753FFF928D25F240B8F4B003D4D
+:1048A000C68576D449AB5925FEED7285C4F769FCFF
+:1048B000FDE4BBA9A4179DB09A6D8897581FF9E530
+:1048C00009C912C8947AF1973974717C9957E33306
+:1048D0008A9BAEBC5EBCD6DEA5189DC2F9402A0BF1
+:1048E000D2FB0CE93055E483E93699F68B8938839D
+:1048F00009623DE1F39C60B151DC29B3193FEED46C
+:10490000F13FD6F4A8AA87DB0984674C2F5C3538C1
+:1049100086CFFB2A38EC04F817E8E06F817623E8AD
+:104920005C91A5C6F5D19EA5C5627C33C5EC001F80
+:104930007A3FC9372E2501E37DB81EDA5D6621B9BD
+:104940001A57DC4DF7E62EF4BE0741EB3C2986955D
+:1049500023C7A5611CD78C142E17C3E7A5AD277CF0
+:104960009DE170D0E67BAD759ED2FA0B5FAFBD9F27
+:10497000F661EBCC317967E13A2FC89D51C4CFC5C0
+:10498000BDDC1A717E899889FDDE2DFABDBB53A26C
+:104990007E77B3EE870693DE6CB0A3DCBBFB982179
+:1049A00088F14DAC7EA2DA19321EA703AD3DDBD9EA
+:1049B0001D8DF242EBE7B3AAFF8AC6F8EAFEDA578A
+:1049C000A7707E7862F6571467B2FB581B9D9FEF65
+:1049D0002863AC83EC5F4F34DA652B0CDE4F336019
+:1049E0001DEF55C984FFEF554550DC6F38BFFEAD54
+:1049F000E017D7CBB719ABBD11E73BE9B6795F3A02
+:104A0000E87DC3FF9AF61AE8189326CFFB11A6FF9C
+:104A1000F8CF6F4CB381DC9C3441A273B88D29EF81
+:104A20003D84F1C99366CDFB5102946FDFB3EE561E
+:104A30000796DF218973BA7FBF15E38527CD954897
+:104A4000C91B91CEEB47E6FB8C788E3853BCD7035D
+:104A500059AA3ECEAD2985FB3F9B045E6D4D715139
+:104A60009A4085FA47258FD7007BCC584EE7703E99
+:104A700023CEFBCCCD60C5DC88FDFAD29B747ADDF9
+:104A8000D969E63B551BAFA7F77FEF4B9142FC7FFF
+:104A9000E1FA5C9B185F3B87C1F63386EBCBF9BD2F
+:104AA000FD7D627E361797F738AF8AE1FCABD7AF52
+:104AB000CFCE1EFF125E019AE171D7616F3926DFFA
+:104AC0009329A390DF7F12C5F5D5CEE1B88E0BC632
+:104AD0004E1EF714CBFDD1C8578E021D4F2CF6EC9D
+:104AE000BB1FFE7D2E258EC63B6BA43750D8C968F0
+:104AF000734B1D2CE5B4E0B7F8D7A8C917E8776B5E
+:104B0000E443692B016E2569668A172FB17138FE5F
+:104B1000364BD2F817BD7BA3C99952D6A1207D4C44
+:104B2000CE194272E656D64D692FB31BF15BCE3CCF
+:104B3000F4FD6C7C6701F93334F999DE233F5FC2E1
+:104B40007515B300B59BCA7CC750AF7CBB677E416F
+:104B5000A2EB1E7E19260FFAE59738BDC4DEF339A5
+:104B60008D5F4B0B84BCD8E827FE9CC47CBF4F09EB
+:104B7000E1D71D12F98F467B2CFCDC36942FF49C78
+:104B8000D30C9548FE3C1A194DF6E2E9A152AB99B7
+:104B9000C3C780F700099ED06872B6348FDE4143E8
+:104BA000E10BEDA67A24D24326BB92E6235D4DC5E8
+:104BB000B1A0FD9BA3387CB5754F2E067842F9E471
+:104BC000059B3A90AF4FCE7EE3F6BEE0FB2BA3777A
+:104BD0006202EEFF34BEFF155EC980EF8494674B1E
+:104BE0001427F9D69AD3A467E49E72D1FB21533DD2
+:104BF000B1943FF2B5A08CEF8B4C1B1D4BF198C3C9
+:104C00000F75AEC3F46D2A2FBFF158F7094C97E525
+:104C1000C4E6613AA7DD3E1EFDE225156E8C3460C8
+:104C2000B173144E5F8324ED7DB810BC28FE7D5D0A
+:104C30002982CF943A98F06F8C576293A0FD980A1E
+:104C4000E9717429AF8B5C3E8ECE55FC4F1890AF46
+:104C5000CE12FB193B879F53CF9A5366C47B2680A5
+:104C600037F7E13A014F2252137AF1E7BE88372E27
+:104C7000483091C3222ED87FAB46E7DC1F31DD3BA5
+:104C800024B059CCAB422F6FD1419BD82B27CE4AB1
+:104C9000A2FD3CFE1ECDAB6F83410C7C6142A9BBE3
+:104CA00088915EC1E85C23C96BA673A809D9B34A91
+:104CB000705F2678377550B92D4C8EBCAF8BDF876F
+:104CC000F49BB89FD09FB34222BF1BD3C7F71B30C2
+:104CD000FE87DF5B761673BC4CF29942EE0BA05D4B
+:104CE00013529FA94353493F032D17E09D2DE26FB7
+:104CF000E09F418C2385AF8A71A8C6942E3AC738AD
+:104D0000BD50A2776D6F0A78CB483F1076DF7441B3
+:104D100017CF2FE0FE8D12AF14B0C03F4BB2D7CEED
+:104D2000C1F5469FB3917E8CF86ECAEF850F137262
+:104D3000FD4921076F70324B06E90D921FCF516E6E
+:104D4000783E85DBCF4EFE86C0B0952EDA87925234
+:104D500089919FBB3182DEC183797CFBADEE3EED54
+:104D6000F452318FD5F9017AC7C2314DD6EFD3E174
+:104D70003C2D9EC86F442150E9F5B120D293937920
+:104D8000F0FCE9D50A59C5F70CFDCC42FE6839475D
+:104D9000223C28F74AE49729BC12C9822371BF5DDF
+:104DA0001B1C58EF6D13D14B42C5BC3B996E9F0A3B
+:104DB000C1AE227F54258F5F47CD48D1F19174C099
+:104DC0001F2FDACF617C081D9608D7E49E347493B8
+:104DD000887C85D13900B37412DCA3343D4CD88370
+:104DE000DAFB673775C6CEC7FD29F0723A4FAAFCC9
+:104DF000CD39FC2E4FCD2420E19335E8F797104FA5
+:104E0000A0DED94F5801F289B3FDBC47FC93542D65
+:104E10002E9BEB69E53E7EFF6C964F22B937BE783C
+:104E2000AD82F6F0D7B1FE53C83FCA7324B60EE682
+:104E300031B578AB11F588A205F3D251AF381BE537
+:104E40004D473B797BAA8BE631A8C21C9471FC6468
+:104E50001FE59F15F1F15FBF7BFF5CC49B7257ACF0
+:104E60001BF166BC6B4506E2C3D405B16E847F7D41
+:104E70002AB7DB2A8BF9F8537D6534CE8C05F368AD
+:104E80003F8B2A5BD2703EDA38AFA607D2D04F07ED
+:104E9000F298DEAF1B542AC6B5868E373307C68319
+:104EA000F2F1397CBC19A57CBC1D62BCF24A180F1A
+:104EB000E03443AC6B76698B42EBCB5E41EBFB0F8E
+:104EC00077ED9DD8EEEC141807DA0D2A867100EE06
+:104ED000832A3775E07827D6A8EC3DF44787C921A7
+:104EE000BC5A1495D7BFFCB909FD5E18D707F884E2
+:104EF000F17B0F993CF506B4B78A02C25F1E2A57B0
+:104F0000923E563760BF25CC53E4E0F1C8727D6213
+:104F1000AF1CD1E4C2A31ABFCA15F2677A0CE1F93B
+:104F20009B287F60FE5BA7C7105F9E99CFEF2F691C
+:104F3000F2677231C81BF8CE14F2E6CC189037280D
+:104F4000874AB9DCD6E40CFEE9F9B826776EC3A728
+:104F50000F605E65CCF3561EF205A38BE8C46FE5C7
+:104F600072A78879492E4D61FE8A69A85FBCF567F2
+:104F7000B2C3971B821B11FFC1DE247E7D5F849B21
+:104F8000FA99CE7CE3FE02F99EA09DDEBD2AC9E11E
+:104F90007227EFB4E724A64BF3793AA7BDA310E537
+:104FA000D0ADE3781AE4C0EBC8FF461CE1F2C95B60
+:104FB000A4D5E3E9921C37C92BE093BFE37C32749C
+:104FC000DFDE1274DEB36FE1741CB68F3D7A839717
+:104FD000D31DDB584B7A8293B54BFC5E7687847089
+:104FE00048FB11A373CEFEF486DFF6EA5BA1F6DF81
+:104FF00075EA33DA3C88D3687C85776747BB3F4DD9
+:10500000B42F407F02CE3747D3736A353DE70B0E8E
+:105010000F3E5F27CE17E0DF96984B78193EDF559D
+:105020004EF52B94B7130D360FF2D93FBFC5DF1BDA
+:105030009AAA361421DD9732FF06BB8EEF0C013B96
+:105040004BD1C9ADA1010B5374FEB91B0ED843D28D
+:10505000C3DB9D21F56F3CE20A29CF05A1A72F1FD5
+:1050600079DA13921ED5313AA4FE0FCEA921E93187
+:105070009DC521F56FEAF286A487319F8C8BBDB95F
+:10508000BB32A45DB1CB1D83F433F480C2DF53F295
+:10509000AB1DD989749F94FE6EB9E20BE967B8B86D
+:1050A000F7379E2D0EE9871DE2F78A6BE17FB87F07
+:1050B000C3C2EE150F16EFE556EED3DD3F86FF06B1
+:1050C000E3FDC068FC86D60FBFE777439AB8E79741
+:1050D000CFF2512FB86A9F18BFE739E3000B0424C1
+:1050E0003C57A2BA6CD82EFE6E62F8BAB47B80CC64
+:1050F000F09A82F5FE02F2189F88303B43F7D5EA1A
+:105100000ADDD7C8ECD07D8DF284EE6BCCE8D07D83
+:105110008D5543F735BE38745F13BCA1FB9A541903
+:10512000BAAFC9BED07D4DAD0ADDD7F4DAD0FDCC23
+:105130005815BA5F6E7F5548F9C0FADA50BC14FBB7
+:1051400099D5B42AA49DB69F7EF8DF77EDE78C8AC7
+:10515000F146F4834CF71A43EE995FEFBE2E0ADB5B
+:10516000D7EBBDBF09FCAE3A6D54AF1E837F7ABB4F
+:10517000EE37537EA070FB6EF9A137607F8B6DDC3C
+:10518000BEC33F3DBF2FCA2953F098AC58C889739E
+:10519000595C4E68FA1ABA01C8AEF171FBA444D842
+:1051A0007FE176C974D63D4019D83FFF073E5E8740
+:1051B000F37D39F2D734AF6216A4F66FF5CC3F78A1
+:1051C00095DD87E748D7CB277BF8F5ADB5C4A7AF0A
+:1051D000C9AF5DE9BDFC0F98EB845513BC786FB582
+:1051E000C7CFF5BA91EE634E78603CE5AF7DD74C02
+:1051F000715685A5DC4F3B0195674C77C964DF1577
+:10520000DA787A821DF46AAE47AB7ED4A313B8DC99
+:105210003E53E649C7B8AC33D392B4B82CD25FBB87
+:10522000250B9D339E889AF56E2D8E27E2BCCFE428
+:10523000F2FD3833CF45F47B42D3039671BDFC4C6D
+:10524000148FEB3AB382BF777BC60DEB84F1CEFCB3
+:10525000D8E5D2E2B3D00FD91D2587C5677592BFB7
+:10526000F9E8683BFD1EC64D19ED418C4FEDDE2E71
+:10527000D17AB5F3D2A34D43B4F82C7E4EB2859FBC
+:105280002F7D6864DC1EDE3A94D61557CCE795D1A5
+:1052900025B760D589E25EFB51052435CED7C5EF31
+:1052A000091F15F15B67855C3CDA13A7E527FFC38F
+:1052B000D1CAC174BE1D2E1F8F32FFA04770BCCA59
+:1052C00008117FE7CF7F13EB570DE3F559A8DD0FEA
+:1052D000F5737E89F5BD16AA7F26D6938EF1EB1A5B
+:1052E0009E9C9936391DE9B508EC399C675105BF7C
+:1052F000F75F64DFAA60BE54C9E56838DD753A7DA2
+:10530000E7D312302EEE89152BA1AF2959FBAD48FA
+:10531000A767FAF1ABFC661AD09FDC4B7F25487F6C
+:105320002EFCBAC8BE7C13F428D4BFC3E951F303E2
+:1053300068FA55316B127E124E2FD358A78248DB84
+:10534000AB9F75D37D99ABE92E97E24DD1FF8F745A
+:1053500057827E160E54F23B01FFF812D7A3C1E12B
+:10536000ADD8F69378BE5804F3F2D3ACFC4CAFB78B
+:10537000F4477F1AFCA6D82FD2F9F209EBD703F431
+:10538000FCEB70A2CF90AE3BD79A1217B0DAFBD0ED
+:10539000877FDBAF7FEAD7E7113FCA857FAA5CC072
+:1053A000EF8C95DB37E1F09B50319EFBA7849E3B51
+:1053B00091F9859E1A20B895F6C3BFBEC35F959A32
+:1053C0009E80F077697A2CF9AB007E69E97DE89BD5
+:1053D000BF17EBB85E7D331C7F7BF85945A8DF4AC9
+:1053E000F357B1D19CCED76BFC2C0C8E3D7EBEB05A
+:1053F000712517EF6F9278EFE0553BB717A0626900
+:105400007222E219FF7BB59ED333E001F19D622148
+:105410001F61F9240F3DF03F9CF75F98CD6701387D
+:1054200095E684CABD42F1AE4151D83B2B85E21DC1
+:1054300084C2B07C6DBDE172513B5FE96FDDD3D2B8
+:10544000C53B2C2E36E45B28079948FA50C7EF0D70
+:10545000743EF152C2AC055B611D431E1B46EF0357
+:10546000BD9478C78FDEC0F4CF0793BD302965F1B6
+:105470009E15907E7C770E956B72751646A9C1BEFF
+:1054800016C9D242F40B66E7BF7DBB1BE67DCACAD4
+:10549000EEC4B493553597C138CE9CCCBCF5D04FF3
+:1054A000918951BDA9372E1BA98F17B847F43355E1
+:1054B000C429A7E3937E79F455D05F93EE0C287648
+:1054C000E8D724EE75A52AAC0EDF8534399B6C76BF
+:1054D000845F04EFB7283398762FDA3D876DF4AEFA
+:1054E000F70D9EC88B03713E9244F3B9215B0AE22B
+:1054F000BBDB4571A27E6170D036ACFFA4290FF9E9
+:10550000F90D9E691F62FD22F15E6DB4EA330E450E
+:10551000BF8AF00BFD87C2F1636DBA85ECE7E7E760
+:105520008C37E2BB0A33BDDC2FE7F477D6C5E37ACC
+:105530002BC7E7E37AB5F5F9D379FC55C5685EAFBB
+:10554000C23BCFB840B7FE996A37BDF33AB3F2A277
+:1055500082FCE0F761F45D86FF20FE78D79D3F86F0
+:10556000FE2B8A387FACE8873F7AF11F802F13E645
+:1055700070BE5656CCE97B26AB25BAAC644DF4BD63
+:105580009DB5D3770EEBE0747DB187AE331C9921C6
+:1055900074BD03E97A065385DF9ABDD8E9BE9A9EA9
+:1055A000FBE37B40FF7BD213AEA6BF57FBD1C7B650
+:1055B000463EBB07F9D8EC34BE4E56B9F525A4B328
+:1055C00009C566B2CBAEE263C307D239407FF2A011
+:1055D0003F3ED6BF1ED6A2083DECB9749D1EA693D1
+:1055E0000787FBE26767FAE0677ABDAC5F7DAC5482
+:1055F000F0AF307D0CFD5AB8EEF45AC6CF17C2F4A6
+:10560000B0EF38777E9DE07D8D73E7F073EC6989AC
+:105610006A817B54EF394ECD398BC585F1F6F95E41
+:105620009669C37B38E3E76642798D386F8AEC6010
+:105630006A0BE4EF1571D153335DD4AFD3C4E36883
+:10564000F0DDB55C1BC68F7470BD2981D9912EB574
+:10565000B88FBD51D02E0FDB49D4AEA7BD85D5453F
+:10566000E8DA17DEC1F9F0575B4CE2DCDF9781FA2C
+:1056700052E21FCC14DF7CE92113C53D0E3471BA10
+:105680007568F71DF0975AA0BFCFD2DD7CBDD20957
+:10569000273AA7FC6C337DB5B8D84BE21ED457B17E
+:1056A000FCFDD5AFB6244AA8175E52D4972B61DC17
+:1056B00081DB62252E3F79FD3FA5F3795E72A99FBC
+:1056C0009FC67595D9B83EC87CB918C76936E497A6
+:1056D000580C283F56779F86F6CBD26D76C4E3A24E
+:1056E0008CF367F17DF80F0F19E9CDCDC5FBA7C786
+:1056F00004B199A23ABDC3AFD6A3160742E5C5D2FD
+:1057000003A1E965EDA1E99A3079112E27A20708D6
+:10571000FBC9C53C2807AED77E1A20A98E0118BF49
+:1057200023F6DD6CAEED6A81759B1FCECE5B4B7CA4
+:10573000A7FB38BE0D9FB8CD4DF7437F27F8F97B07
+:10574000E9DE346C67CEC81981FA62614629C5BDAD
+:105750007FB5CB4ABFDBF39595DB015FBDC8E5673D
+:10576000F3005EDEBCDBEC9288CED5D25105184F3B
+:10577000C5E9A766279797F067E1EF17A916DCC779
+:1057800066936A4AC676FFC43C389FAA9DF750DCF0
+:105790005F35EBA078FAF903F87ED5189E3659E00C
+:1057A0009FCD71CE42B4279A9F95E85D58E5EF0AE8
+:1057B000FDEEE026EC720CBE9DACDAF11DE965470A
+:1057C000F8F9CFE801DC5FBC795CE83D18D3A13281
+:1057D0003FFA9A6EF97B11BD7375CFAA5F51BCB6C3
+:1057E000C3D41D3F1EED892D32E1FB3D0FBC40F9B6
+:1057F00052797107FECED0075B6C2EC4E393BBCC0D
+:10580000B4FE0F5EE4FAC5077B393CEE49B3D179AB
+:1058100043F8FAEBA4A0889FEAA0F3F03FEDBD3F68
+:105820001AF7EF4F5A1CBDBD96EEC132576D483C7A
+:105830007DDB1E03BD43F6A73D235FC5778C9BCB65
+:105840004B46A15CBF25369FDE29D3CAB53810254B
+:105850006EF4E34857B7FCDD407451F4F0B808F437
+:105860003F2B2017311ED9D55848F1B94BBC11B187
+:105870002E89D645FBD6B6C542EBAA699C44FB549B
+:10588000D55845FB30707A8A4CE54F4B0C7FC2925D
+:1058900019C645AC85F6350F939B89B531A5B82F50
+:1058A0003FFD5FD30DFC5DCFF2084F10EA7F28FC6F
+:1058B00037E333F87C2619C695A09DB96C8B4C71E3
+:1058C000C2CBB6BC9948EF62EC33D0BB5352F9E877
+:1058D00014F46387D39136BF707A3243BFD83E9CAD
+:1058E000AEDAFC1E7AE73E9CBEF02FA88B7338DD43
+:1058F0009847F30AA7BBBB1B33E9BD0E56CFF5B0E3
+:105900007F1AC07F1FF37BD05F9D9EFE585A794857
+:10591000DCBD466F5A5AE3EFDA79BBC5C3D4FD3616
+:10592000BADFAEE2FDFD27062854FEC4001EC7AD57
+:10593000FC75E581D761FE370EF06D1B80F1764C6A
+:10594000CDA57736BF64F8FC06C515F0F34C7E6F25
+:105950006A87D12B131E2ABE7F7D1DF28D8D5523A4
+:1059600091EE1F17FDBD97EEDB83FD2C58EDFBFC80
+:1059700038437C1B46F4BFE04A05FDBE10FE0E080E
+:10598000BFA7EB2DC4DF07353ABCF9888F1ADFCEED
+:1059900082F9B6F41147F09B015C8FCA7278A99F17
+:1059A0005F64F0FB82CDC8DBA19FDDAB78FC86A6EF
+:1059B000AF458B3D74BB18BD536619CDE1B1D269BB
+:1059C00070213DC23894EF1E2DFB27C3D7369ADFD6
+:1059D000EF8DCC0FD27BDB59980F78E4F6307A87C5
+:1059E000472B87FA17315F6616970DC668847F21AB
+:1059F0003E6465F3F7F3DCCD3C5FDBFF3F374944A2
+:105A00009F600BDBF1F76C2C4CC8CF7C2E3F573AD4
+:105A10004D2EFDFB2E0F258F3F81FBCD54759043FE
+:105A20007B3717FE6689F808E05A14E7383787F99C
+:105A3000F07EA4B69EB1CD2AC5BB85C36D8198E723
+:105A4000169C27A0CA580FA4B3FB9FDF7EC12FB5B9
+:105A5000F6DAFC4CCB6D0AD2F35ED44F60FF4D29D1
+:105A60004E1BD2911627E388802FE80BE929D954E1
+:105A70000FD647F16AA08178F0DCB1BFF81947046E
+:105A80007CA17EBACC14C44F93CC8AF0FED0FD0624
+:105A90002F293B5FCB4DC24F1F94503F4B35B4EC89
+:105AA0005A04FDA6CE4AF3A09EEDB3A85D042FE6EE
+:105AB000A2FBE397FAF95D039F65FC2788975A9C40
+:105AC0009D46B789EB59C8BD3B2DCE283CAE68B783
+:105AD000DC6421FD2C43E81316EE1FDA3196D9D190
+:105AE000BFB27E0CB73FB57DAB11FB261D9368BFDF
+:105AF00058585C9416371529E2CBB571EFCE518218
+:105B0000E63EC6C73FFDBCB5FA91BB3ADC38AFFEF6
+:105B1000DAED01FD0CE397D9468F0BEBF9DD3E3B47
+:105B2000C63DA5AE9FE712F2C48D702B65AE3DD287
+:105B300040F44BB8D2F05DC152CB6FCE61FFA516D9
+:105B4000D64EFAAC27DC1E0FD5E7970BBFA0C3C417
+:105B5000DF8BD0FC82CB855F502AB7905FB0C6CB7D
+:105B6000F5B809C7B8BCABA9E37E41ED3DAD9A23BA
+:105B7000E3938D90BFDC6B92500EBA849FEFF037A9
+:105B800013E8BEA6761FB1E73E6F6EE7CF7F8A723D
+:105B90006D31BF9FF9A9E8A7796D6132124FBFF748
+:105BA0007C37C82DAD6EDD3DDF0D72ABF0DB89FBC0
+:105BB0006CF608FA1D24B19F1902EE2DE29E658B4A
+:105BC000F0D349ABF9BDA116E65A4BEFFDAD66FC2B
+:105BD0007D951C3E4E5C9DDC8AE7BE013CE08EC19B
+:105BE0007A8CFB056D161197618F28E7BF9B44F7F0
+:105BF000EF12477318B7687E3F812742E4B0E6583A
+:105C00003519FD7451395EB7CDC3D81B7B3FF95DA3
+:105C1000C4A8EFF30EC4E6A6EF7E07E29C17DF816F
+:105C2000B060EC9A28477504E449CFEFDC60FCFBD8
+:105C3000A6A8DE7205F4304B9D48FBF77A278288D0
+:105C4000C1B3155E7EF8618C5F7BD8CA42C6D3CFE4
+:105C50004F09EBDFE8A2383091EEBA15FBDB9EA7C7
+:105C6000A5273E8CBF93F3B031B43F4279D11E13C8
+:105C7000DA787BDCF735358EEB956B20E76A11FF20
+:105C80005DDDF642FAF91121FF22EDD3F97BCC5705
+:105C90002A88FF1B1DDC5EC7580D7CFAB1263BB37A
+:105CA00095CEBD146E774724F3DF73FA4906B75FCC
+:105CB0005698B83C528E95A9F8E48191795A5F774D
+:105CC000933CFCA70CDC9F8CD297517FD1E421E858
+:105CD000FD1B6F837E1BB633F22F5B9A453CBCD80D
+:105CE0006F734F3C849FC954CF3B0AC77B3BC3575C
+:105CF0009FA1E3CF59CD2E13F6D726F85EF3E24CE1
+:105D000059D2C9CFBD19FCBC3F2B9BCBAFACE640F1
+:105D10007D26F4A7C45690DCD5EA65DA07C9F43BC2
+:105D20003569420E829C453D38B3D947A118998AFE
+:105D30006F36AE3BB3729109F5F5BD195C3FCBAF41
+:105D40000F5851DF655532FFBD890C178D67B42F91
+:105D500020BDD05869B121F2EEF63E6EC5FEB3B259
+:105D60005B697C6657E8DD38A6801E00F57E1EA7BD
+:105D70008CD2BF2FB3D9AED0EF8616187C2B28EE6D
+:105D8000247EAC8AF4921E5752EC8946397030F763
+:105D90005E1BDE3BEFFB3DDDAF5D7C5FEA24AFFFCA
+:105DA00036A4B75C906DACB73C43BC17722883FF38
+:105DB0001E86CB6F27BB60DC975ED28F0F65F0B875
+:105DC000C45F2B9D91A8FF653175C5DDB84EAFCD81
+:105DD000857E7AC6F87980638D8BEE87591C9D0F7E
+:105DE000DE88E51ED983EF786AFAF4A72F24517C68
+:105DF000D46097EF38E24181A1731BEE3B7B90FFAB
+:105E00009EC8A72F98894F387E9A43F13D0D8ECEBC
+:105E10006DE863DC6BE476B5C511B40C44385E9173
+:105E2000E9BDE248D8267C6FCA66E3EF60E5039DD2
+:105E3000D27D12A744F143364FF719ECBFC475C6A3
+:105E400083EB9820DEED0AD72748E869E7560CD7A0
+:105E5000E7671F58C8D554F76D7CAF9E3191A914E0
+:105E6000BFAFE91F3BF0FA2B34DD215BE87E7B7E80
+:105E7000078743C9EAE3345E94A79DEED52D40FF22
+:105E800028A433B3CBE95ECBC2264E4F770B3C64DC
+:105E90008A2705ED988B1991E21E531D7D49BEE1BD
+:105EA0007A1A4D746E9259EF36E9DF7FD3DE1DBA50
+:105EB000BB89BFD36412F70E33F345DC287B90CA4D
+:105EC0003F1674A9D9EDBDEFD8F0717BDEC3CAE5EA
+:105ED000FC7AEEA0727A7F2A2E7F581ECEDBA93084
+:105EE0000BC615C9028FC2DFC3D2E6935FDC948C68
+:105EF000BF27DFFB1E169703FDBF87D53D3113CBB0
+:105F0000A7B8E877E2CC2E0ED7FF06528A8D6A003A
+:105F1000800000001F8B080000000000000BDD7DEA
+:105F20000B7C54D5B5F73EF34E3209930079F04817
+:105F30006612120224611201411E0E096054A4C3AC
+:105F40004B40294E2040200F106A1B7BB19998F0DE
+:105F500050B1C68A885E2A135E6A051B10292AD8AA
+:105F60000144697D45ABBD609526E8451190085513
+:105F7000B1D75BBFF55FFB9CCC390328FDEEBDBFFD
+:105F8000FBFDBE58DDDDCFB3F7DA6BADBD5E7B4FF9
+:105F90009A53882E4542A4DE1DF42CC91322C52134
+:105FA000447C12951DF0DF7E6890101DF9B1DE8DE6
+:105FB0006E2E5F158376A25E41BB15DD95E92D48F7
+:105FC000CBC4F49D945AE87F5D92647A8452C522D2
+:105FD0001AAD94A6588425569637E23B0F2788DBE6
+:105FE000FCD4BEBBC97CDB444A1F2E92F924AFF01F
+:105FF0006DA4B9A4BA13A992FAD945A99224CB43A6
+:10600000544FD3F2EDA0FA9492C5853CCF2C99DE83
+:106010009B16B6882C211E13A1755B68BEC15C9BC4
+:106020006B8B10627CEE2B4794024A1DA2C59C40EC
+:10603000055EEBE9B65CC17FDF650AB13B79B2C7AB
+:106040004DDFF97CC685633554F670FDC41973D1F4
+:106050003FDFE9DD42EB15C11DDEC9F168DD2BF143
+:10606000C40021CCE877AD10E74EC79A942E421CAD
+:106070003E9CD5A58DE6B3114DD2A85CB8BBB868DF
+:106080003EC3CD2621BA11DC0A2DA18D8A100B1C2E
+:10609000373EFA71576A6359FCD7BB687CE71B5DD2
+:1060A000BDF7D2F8C333846C9768E37604A0A009E7
+:1060B000F53BFA85EEF5601C25CCF5CFD9B9FEA4E9
+:1060C000D5EF5330BF1DD9DE2DBC8AB06B623ECDFB
+:1060D000BFCEFFE8986CEA67153E41F5625F7C68C9
+:1060E0000BB577369B82D934CF6E36F99DB3FB6200
+:1060F0004277A35C91DF11CFC785B6D0773E17B248
+:106100005FD06BD9B885E7E14B9D4CE37E873F5A62
+:106110006FA322789F9D4A781E8FBF23C684765A2C
+:106120007D0F3B95D3F8E2592AF744CA5FB4CAF20F
+:10613000E08E18455FBEDB16DECADFDB29CBDFB79A
+:106140000726631FB4FAAA84704EA2F3FBE02882EC
+:106150002877DEDF3B74AFA283E33D0AB7532639CD
+:106160007CC89F28B46CB42B0CC7DBFC34DE47B969
+:10617000A6B0AD0070247C7546E0A77D97E0E7C728
+:106180003AE7ACFBE43F4541047E73FCB67673010D
+:10619000C3CDDF827E96B06B527CA4DF9CA2F2F16D
+:1061A0002221928F4EE7547C3B0BE3CD5965672447
+:1061B00066FCA37F1703C7060BF155CC681B90EB59
+:1061C000A7BF9A68031ECF138B39AD104D9CD29F89
+:1061D000C3948AC4E7300D1562A168E172F72A4BB7
+:1061E0003095E0E83E121772D33ADD41E116570BC5
+:1061F000E1118427B47E4F2F93378C6E8A4911D4D6
+:10620000CFDD48F52934FD7B8812A95FF32A25A448
+:1062100050BF958D26CE07572BA16CDA8F60A3C98E
+:106220008771E87BA97E5A6793DBCCF4F8A4DBC6C0
+:10623000F3A56987301F2DD5C66FB40A8673BD30AC
+:1062400085913729325DE9B294869C17C3451BAF0F
+:10625000D1BAD8311AFBD7DBE4029F69B4061661C4
+:10626000FF1A8FC69982349FC6F8C5AB4A653DD3E5
+:10627000DA5731E152D47F5568124145C2338DE679
+:106280009F7934A619F8B0C26DE2F946C37B6E93CC
+:10629000313F7F9D31BF2064CCCF1181DFA6D2D2A8
+:1062A0002B9F3496AF70BBE4F8C2CDFBD06875BFAE
+:1062B000E3019F24B862FEF5BD24FC4CBD659A99AC
+:1062C00038663AD34DA24D64D3FC565B24BEAE5E15
+:1062D000D5AD19F36F4C24FA72FED7E71B3DCF16EC
+:1062E000770ECF93C6E7EF35127DA8F0627A9FB3A1
+:1062F000CDBE097C664EBC3B01EB38A574E49A81A7
+:1063000007F7C7BB990F085A67B210B35D72CC8FFD
+:1063100014EFD630B5373DB0FD9E1CF4BFCF5C44C2
+:106320005F1425939D4C6F2F7CE60C81DE2A086656
+:1063300069C4B75FF0BEFB0AEAA3D7457F6ECB10F6
+:106340001A17FF8FB66A7637E18B21FA10FA769921
+:10635000F82FE187C6AF69CCF2EEFE23E0132F14CD
+:106360000BC6D7171EB3871AE87B0F9B3EDAF12ABC
+:10637000E0BF2386CFA99A651D5B05F51FD63DF0CA
+:1063800057B43F7DE7FBE31437F30DEE77765FCA32
+:1063900046E0C9A0467B647CFC67B52E8FEFAFA2B8
+:1063A000450CA3748DB1BC627D543FF10FBB7E9E42
+:1063B00044318CD76B6D817E2EDAD7C7FC43866063
+:1063C0003E6BAD4DA5A0F3B6D4C01798D7C763FDFB
+:1063D000AF983CBC1D397EE2432F7D3B27CB027E2C
+:1063E00079C4E1055F7CC9D2169748FCE850869BCA
+:1063F000C74B758820CE5194635CDBDD92DEA2E949
+:10640000EA5B30036AEFF4F89ECEA0EF886F69561E
+:10641000046F33604B43399C3B7D66F0EBBD8A8B48
+:106420008E0D51E316EDF3897F39F72ABE4C82CFEA
+:10643000A25C5348A1EFD7384DED575379B6D3241A
+:10644000CF955C0BF3879A3522389FF6CBB2B72CE9
+:1064500088D953BBE0D594BFDDE6667CD3E651B363
+:1064600067A208D0FCE2BAF94D73E97BD60A13C3E0
+:10647000682D9D63186F2DB5057D0FA2FD0F313F6F
+:106480000EF1BC936DFEE218AA4F4E0E7B83D837F7
+:10649000E137810F257B7C851EEAF3EF28A2F37696
+:1064A00058AA2F15F92F711E0FA4F3F8DDC97C1E11
+:1064B0007F29FC7C0E9F30077EEA22BC9E2F82CC77
+:1064C0005F178810A7624D57DED7791611B6103CBA
+:1064D000E74DF11D859C00FA0A47D1973E5F255A8A
+:1064E000253F263A0BEBF0A1CA12DEAF109CAA1D85
+:1064F000221C87B4C5D8AF467470BF457BBEB38736
+:106500000D7420F124C5BCA47031D6EFF3F5E94633
+:10651000FBE4944DC4B41E129E8A5784E3697EB78F
+:10652000E5898023F3CADB9D7437259BCC7C1E3222
+:10653000DEAFDAA784EC04EF7166A7CF41F9EAFB7E
+:106540004D4CAF34E0F8C14370DE48FC58E41E7790
+:1065500012E799263738769B43777BB8BD374CF9DD
+:10656000EA7DF15E34AD70578CC7B9B620643DDE6C
+:10657000A65BD742B1639C8BE1E5EF027E51F9A4A3
+:10658000B1BEBAC5985F242CC73BE5326A5FFBC138
+:10659000E8F0CB3AFABAD913DF0DF217CDCDF31DDF
+:1065A000E06F9ED9257009BCD7D2AFEB7CE197ADE7
+:1065B00042A42BBE991E82EF428BF0E15C8F6EF7F6
+:1065C000666F4927079DE7BB0674F5C5797490523D
+:1065D0007E48F1A5E96BA1476178C7B5AA72A925E4
+:1065E000281275FD2FD76FA9C724BF6793F50FC475
+:1065F000C7F900BF549B58E5288AB44B3589460734
+:10660000E1E5D10CFF1DC06F87DB6DC3FC365983FC
+:10661000C204FED05DB0FCF76BAB08C650BB9E66F3
+:1066200013EF674FB36323F86155865CD70FE149D9
+:106630005C5E871570EC69DEC1F847C76B50D07897
+:1066400036139D0F18374E08C8FBEB634410F3A1B7
+:106650007AA1C87A218AD04F849522A92FC451F9F2
+:10666000033867585F70B21C9646E5E05742B4B6EF
+:10667000416EBD6F88C30DBE9B6292F3BEDCFE917E
+:10668000BE10744ABD81F510125982F1DFD35EE36A
+:106690001B297639AF94B8C5CD8053CA6DB9450D65
+:1066A000844F9B3CFEC70147024801F88806971AB1
+:1066B00015DF3BE1B24709C72744E8278EE66C01A6
+:1066C000DF6BB233DF6394E57C1ACBD7C790273EEC
+:1066D000B237D5FF34F04C68E7EA03F92C8788DA43
+:1066E000AECCA756C64BFD86E068D8678DFED72B8B
+:1066F00072BF8714B7F239DA7117E9143AF93A43DD
+:10670000C5B33D2ADE69E5DD3D729FBFF1F89EC746
+:10671000F74F1F753804C9AB830649BAADF13B99F1
+:106720008FD38963FB172ACBD8A3B8EE053FCA35B0
+:10673000F17803D30307019795EF3B8366EA776F00
+:10674000EEF1153DC1A7BB7987804D66A19CF8EAA3
+:1067500047BD03AF62FCF265812FF6837D4EEA5F91
+:10676000007C1CF25DC98A52395F17E4B26E76B1C3
+:10677000584F679F78A41CA6A51FABF33F4DDC7153
+:1067800034CD2BA39B6F06F042D0B9904D5B10E740
+:106790006E65FDA666971452781238A7FEA517C33A
+:1067A000BB66D7E8C243C8B7C414A2FD90BF38196E
+:1067B000DEA7EFEC1132537D8E3BF001D6133FA8DC
+:1067C00043C1FC4EEFB8BE1069341D68F89F427497
+:1067D00083F1536E75B01CA1E1C15A2BED7F568435
+:1067E0003EDEF4B819CE19EA3995B1CC2FE63A233A
+:1067F000796737B93F546EC2F79C9EB16F025E6FE6
+:106800007A2CDC6F49AAD90DBDC52D5C770BCFC59D
+:10681000F8EB210A7712BFBB8F84A1EFB0F420E51B
+:106820007572D0B926A514705D4202596D51643E4F
+:106830005AFF25A9361E3FEE8294EB335D36DEF714
+:10684000F8552ABE2E138CBF233A5A4BBAD07AFB86
+:10685000AC098F30D31031F8561AE3C77D03A9BCB9
+:106860005B57CB08E8A58FD7161D7074839ED03A6E
+:10687000125BE059234C31945AFED3E2C73AF98FA8
+:10688000EACBD7B8249E5B16E7421FCACA94F838F1
+:1068900030DD179749702C7ECFCADFFFEA7E2917BB
+:1068A0007E9538FAE47EC8EDF7DB89D15C9E9E8345
+:1068B000E280037A43E6EA4C9BC8C33A1486AFE809
+:1068C000438841F3B5DCFF4150CEEFDDDE98CAC806
+:1068D0004C27EFDBECA0771CC086FEAC9F34B98A56
+:1068E00031EFF8D5934CEAE6A729549EBD6A8AC9D0
+:1068F0004DF9EC26396EF4F707A9EBF8FDB7E6522F
+:10690000C8E5261AB40FCEBDDCA46633E889CE13E1
+:10691000ACBF7A40375E7F7EA6C46FCB1ABF487388
+:106920005F2C0755EF2A6339289AEF68FC46C3BBF2
+:10693000DFD3B858D7EF8583E5740DFF48AF627891
+:1069400007FFD3C47440EA2E9F67590F7C9BC6F89B
+:106950002DEE96FC5EE58316AB7B05F4424B7DDBAA
+:1069600028C079CEEA44534D1EC6F12EE171EE7770
+:106970000A1E6775E6815CF085552EA1B831DEFCF4
+:106980000CA6C7BFD805F0C572BFD38473C5F2A0EB
+:106990000FA5C292985CCCF987294FEDBB645AF9D8
+:1069A0007BD64C39FF46A54361F94AF80A21CF7ED0
+:1069B000E309F833074B3ECA745C1B1BCA667C694B
+:1069C00065BA7D7C486B6FC0EF719BA8C07A8A1F47
+:1069D000C89BC4F8728F45819C126F096424523E93
+:1069E000FE480ACB893355385F025F7A0ADAD7CC82
+:1069F0007D663FE8D16295786FB987F42BEAD73F7F
+:106A000039701BE63122D85A02FC1875CFC771A322
+:106A1000DD577E0E085F90DB2DD2F8C75E85F9C783
+:106A2000B7E982D7FF754C4201F86EB7584A895FC3
+:106A3000D63A64FE67B1091B91BE7E46DA8BBE8EE4
+:106A4000490FB15C154B29F50FAA7A4CF0583CF36D
+:106A50009F3B32255D7F6DEAA8B7507EB149E203C6
+:106A60002120DB69028E402DE8AAB6AD301578F101
+:106A700062427231E44E9A7C3ACEB5E356A947465B
+:106A8000C327E0187D17FABDAEEA99988F87E6997B
+:106A9000545BE207DFE8660B3D3A0F7C7CAA93F576
+:106AA000A7A43B4773B932A996ED553D5EB77A5915
+:106AB000CFAB104C773DFC3696235F54D4F9EF33BF
+:106AC000335EF628F5A559299FE4B7290EAA37A702
+:106AD0004E7EB49CC659D32CF77F4D993B84FDD88C
+:106AE000FD0FB3B4D7CC152C27AC29743F5A8EFABE
+:106AF00005792CEFFF4A51F1BD5AF0BAD7C49B0477
+:106B0000EC196B6E2704477B8FFCEE9A1FCBF18646
+:106B10009B8F0BE84D1DC3E439A4B313497D6F7AF5
+:106B2000B2B4A76976A2198ED04649C76C473A3BE2
+:106B3000BDBF666F93F5D926D5DEA6AEEF8E4C9E0F
+:106B400087C6F7CE56F4E0F682F8AB83F4E362B57D
+:106B5000EAACAAD7072B249D9E0D49FB51719BD20D
+:106B60008E7D3A2B5AC2B0BB054B85B42F0E957C57
+:106B7000A461AF79238FE718EBD3DB27CF0A512A23
+:106B8000ED4D1D097A7B93569EDCE04B03BD764CA0
+:106B9000B499F4F2829696674A797349B26F5FE6C8
+:106BA000E0081E6BF8FE62514A31F49ECBE1FD9F76
+:106BB000843C1FBECAF4BF82FE25375FDFC8931B2B
+:106BC0002FF5A783AA5DD06693728FEDE69E1B1BFF
+:106BD0003C7AF946F2A517D576037A0A07EC024407
+:106BE000AB41EC67FFDDFD997FBEABD235480BF6BC
+:106BF00086FEEAD9D75F69599248E7F081E39E742F
+:106C0000D80934FC7E31B627E3BD0EBF8FF2FAA25D
+:106C1000E6252CFEFC49F917CFE7E34CDF5FF5EDE5
+:106C20002F2F5706795E365BCBED2CD756137DD0D0
+:106C3000FADE4515F5DB74B33D0CBBF259AB7315A9
+:106C4000E8FB48DCAC57BA13285D8EC0198C3F7D39
+:106C5000DAF52B90570E74752FA1799F2D6B1B02BF
+:106C60003D70BD3DF005EAAB1C818C645AD74FCF17
+:106C7000B51E53C037FD5DD5F3D89FEFCFBFFC7C69
+:106C80004A14F9FD3C5BE0EFA0EB834A5BBC177A4A
+:106C900091A58DFB0967771EE7980AAFFD56DF883F
+:106CA0002F68FEFB1FCC286CA0F994241CBD751125
+:106CB000CEEF47520A2107687039A8AE6BAEC99F64
+:106CC0001C361BE66BCFA221AB5C651969993CDFD2
+:106CD00059CCE79DEA7C2DDE5EDF37DF068D9EEF27
+:106CE00052988ED6C712AA1745E829F081A919F83B
+:106CF0006F37353433FD9539BCC0E7B7D4F9909E72
+:106D000023201F533F969FB7086F7FF0809E7649E0
+:106D10009F3D572A21E0DD6CE1653DBB5CF8D32146
+:106D200042F6C90A6460DE7F8DFBC7608F343D0C7C
+:106D30007E97C6DF7D778A1772B01821E7FF43FB85
+:106D40002FC46A13EC2793543BD85C556E9A2C7C65
+:106D5000567C6FAA0858018F773EB7F9C0DFDF5124
+:106D6000F5A36922C8E5334488D35B4598DBFF5817
+:106D7000B471FEEDB882DEB504FF898FF4CD067ED6
+:106D8000EBE03D384BE2C76DDD801FBF785BE2C7AB
+:106D90009AEE5784AF1355FC20BA1D89714A924A66
+:106DA0001A21778A31122F22F4D1D6D085E03731DB
+:106DB000D95308785CFBADDC8F711FBB9ACD4A04B8
+:106DC0002F887138D368FDD7A95BD67A4E9E73871A
+:106DD0007DF5DDBAD1BCC69A9DBC0FAD5E339F0B6D
+:106DE000AF8EAE647BF8ABF5727F5E1DA6F0F9B690
+:106DF000F50B3A0FA9DF0DA90F8E81AA28CCCEF88A
+:106E0000207DEF4B9F59E07BA5BDAC113B00FD7B86
+:106E1000431F637EC23A699718EF33B7DBF9DC6B27
+:106E2000B100EFC6E719ED0913C4EA2F60AF9F1058
+:106E30006557D88F35255D6C5F989DA5DA17FA8B5D
+:106E4000FE6CBFBB72FB424596CEBE2060CD24FED9
+:106E5000F523089DB4AFAD230E0E3F4BEB3FBFD7DC
+:106E6000C3D89EDF57EA3FFF9AE55F8C7E35B6B602
+:106E700059D8EFE37504E1BEC497EA1CC247387DD8
+:106E8000A2CEC5F94FEB5239FDACCECDE9E9BA5CE3
+:106E9000AEFFBCCECBF9C359BE5A8CB33246EE8797
+:106EA000F6FDA52A9EAE8C9172C6D2983B8E94D1E7
+:106EB0003C96F6964450D1D2348E547BB1704FCB71
+:106EC0002B48A9DC4C3A8C58FA20694634EFB92F8C
+:106ED0000756E0D899FF7ADB04B093C1EF7D9C0C94
+:106EE00078545F50448048E6448E6F25BEFB49DDF0
+:106EF000509ECFC93A1FCFE7545D29A71F65F957A8
+:106F0000F3FA56292FF7A4F16EDAD66E413AD6A7D6
+:106F1000F07937CA274221DA8F75D64000F8B12EB2
+:106F2000CDE105FD8ECE9FF4EB9F08F0E7C05AD06F
+:106F3000EDD4A43963BBC25E25DA1ABB52BB6B67C2
+:106F40002ADEB03B82C73F4CB7121ED52A6E9C7911
+:106F50004961389D792991E1F2A75D669ECFB923F9
+:106F6000B12C579CDB15C7F87F6E953D047A79D11B
+:106F700016B4A753FEC5F4582FF8E68BE93DF8BCCC
+:106F8000B4ABF4758AF64DD0FA273F979502FDE22F
+:106F9000D4F69FA5EAED48A7925ABE7A1FFCEC43AF
+:106FA00093977D84A2E5C46394FF5DAF54E63F9F51
+:106FB000ABFCB9C626E9441C336D047F3C152BE9B4
+:106FC000B0E368EC46F0C1E39AFC7F34B61972C5B1
+:106FD00090677A160BE3F9F73CE015BDBE25CF0D9F
+:106FE0004881FE247A756378E52A1653ADCEFE807B
+:106FF000F9BBFB46F2FD76CE3FFE73B7CE7FB7F30B
+:10700000C73E9CB35BB73F7AEE05C05DD52F9E7A35
+:10701000E6D73DFE9572553B96C762BD9003871239
+:107020005DBDF8601CF3BF17ADDE63B598EFAF9D93
+:107030006CA77AE297771EDF83F4FEEAA23B29FD74
+:107040004B5612EF4FF9AF668C4BA3765B778B42B2
+:1070500090DD009A634F9A5FDEBA2F0E408F2A08A8
+:107060002596F4A072EF93850721A23CFD3B250CE9
+:107070003F41514BF34605A8FCEDA61E907BDBB3C8
+:10708000DC067D7840EFD2C3ECEF8D9227F2D67C00
+:10709000518CF1B6F7907205C9179FD513BC57F6FE
+:1070A000FE7311EB67AA3D66F0BEA9AF0D175857E6
+:1070B000300DF26EB0CCC6F6782CDF4AF933BBB295
+:1070C000586ED96D0AF279159CEDF0625FCEF883A7
+:1070D0008F621FABA93DF4B7EAC260C235D0133F3F
+:1070E000ECE3258C14BD1FBFAE14F0A9D9F5F0B8A0
+:1070F0001ED4EECC08E15568EA15CF9D1FC7FB4FA3
+:10710000DA2CF4A333BB1A926FA17EF7E5150FC6F4
+:10711000F9EC37B7F077C422F99D47D4F350B41592
+:10712000B07F8651DD0DFB8170A03C696FE2FE9E51
+:1071300022B25F8BF6D67B201F0F0A38BCD05FD7F8
+:10714000798269B0F769E72B9D93E63E20299B3A47
+:10715000AE6B32EB13577A3E6AF6406DBC476CD289
+:10716000BEA7D90BD7DBE479BF85F812F04F3BCF30
+:10717000E9BB5DFB0C8ED81B85EBD94217CDF3DF45
+:1071800049CE62BBC2157E5F93BF16A9FA57B17A8A
+:107190003E4FEFDAB0AF8DD63B94E42CAC6FAEF03F
+:1071A00049FBBDC5EBC6B991E1F0B9FBF039DB9104
+:1071B0008E35D0B9DB07ED6ACC249765E9E432C798
+:1071C000959DBB0DAA1E18CD871B54BD6FE9974531
+:1071D0004702E0B3A4CF60BFC4CBA6AA57E85C1DAA
+:1071E000297B74C27D697C11D36D8310975CFF4B42
+:1071F00044B701E23B613A2F027DD1A8B501761D6B
+:107200001FFD2F9EC61D75C1443C417E1BE75B746C
+:107210007F827B31D6395AC419DAF94422DB998549
+:1072200033E98AD63B22F6D2E7CE0855BF1D716EF0
+:10723000E8BFB909AFF7BD6EE5725A3FF3C9CBADF0
+:107240006B9FBAAE9CBE81A97D747AFEC8BFB92C73
+:10725000A04F9AF70C948FB2984540EF7FD3F0F58A
+:107260000AE77D07E21F404F5FD8584FDBABEA7952
+:107270007B17E4B1DD65B74DC66904DFB432FFDAD0
+:107280001B2FF5DEBD139359DF7C51E3C76566966E
+:1072900067F7C6A8FDBBBBB8BE875DD68B5B3BC797
+:1072A000E77366EF8C1E3CFE8B4A78C06F31FE445C
+:1072B00007EB816B26FAD262A1DF4E4C36F1F7FF65
+:1072C000610EB2BE516F673DB5538F2E5CFC5A3EC6
+:1072D000DAD50F607ED2C31C5A057F9DA833F338E0
+:1072E0007B07FB8EBA799E44806EE8B3C569269D04
+:1072F0007EA8E9C5A407B3BED651666E4639E9BD7E
+:107300005A7EA3AAF7AAF111C1F88904D7A3EA7E8D
+:107310001DB148BDF308F4DA8111FFC311E8A32CB5
+:107320004F06E3A16F0526C4594007D1E5DA3E6850
+:10733000E5EF5B497F051C697EFA789235894DDD62
+:10734000E1BFDBD027B016F43963EE9618C99F432E
+:1073500031D0836F37FBD7010F1E8BF54EB8197CE8
+:10736000B95CEA71EFAB700E7E63E27D79A9FCD067
+:107370001CACEBA58E54A1B7BB6A78D0195F72978D
+:1073800089E11C1DA7B3E1F5AE7C4E77DA0DE26D05
+:107390009D7603C075434B3F197F42F0C33A22717B
+:1073A0003AEA3CF6E5F3FE97C2FF06B96299A919DD
+:1073B000B243588DD7D9A0DA11832D569EEF06150A
+:1073C000AEB7A9FC6B8308F7849E16DC1B23E37D14
+:1073D000547BC6863D03F8BB61E1EEC2F689C36605
+:1073E000C1E793C59B8A78A5B32A1F6A50A47C4144
+:1073F000E3C8389C96FFF6B89D3FF6D19DBB17C5F4
+:10740000ED5C0457C1769C0DB55D3BED316CBFB8AA
+:107410003D5E83AB5C5F9547856BF33D3918679F95
+:1074200095ED5227AD1D6F5C8DEF3F9F25ED27C475
+:107430002AD661BC3DBD399E4AB3BF115C0BF6A094
+:10744000DD2E3BC34D83AB6677DBA0E25F679CD04C
+:107450005DA68DD05B02361140F931575BBCDE9FD3
+:1074600077CC7F221E7CEB835A73D8F63D713E3376
+:10747000D5B8A1996ABCD065DBFD6236FB4D2F5BA8
+:10748000AFC60BCDAC32C64DF4C8F67DD5478FB72D
+:10749000274DD171510CDF179C491A7C255D9F74D3
+:1074A0001AEC5D2F7CDA5F85EF8EB089F15651E1E1
+:1074B0002BE11F7CB46F48C67F84E2F4F1512F5852
+:1074C00024DC5E50ED5A9DE5AA3D2AA0DA81C4670E
+:1074D000268E236B70791D7A3896770FB8B2095FC4
+:1074E000EE761639DAA8BCA24BF161C89735163A88
+:1074F000BF697F866407BA67439851E51ACDDE5AA3
+:107500009D179EC5E7E3B22B3B872B63F7D62899DF
+:10751000348DBD5B7623A579319E899D925F074CA2
+:10752000E10435AF609E95F47F4725C16F4D6756E6
+:1075300092CC439E8D8EA761124C96F590232A5BC8
+:10754000CCBE9804E46D91761EE4432C67905EE80F
+:10755000184AF24E65E29E5F0EA7F2854EA76319A8
+:10756000FB438D712D0B77AD6CCD2AB8B8FCE2EFE3
+:10757000CBF509A7CF0D7B44D95059774D6D89F8CC
+:10758000E82A82936A7F9CBD5AE17388FEEA11E77C
+:1075900051BE4611E06365C1693700AFCAA6949E2B
+:1075A000841E53F640FD0AC847F3557BF6FC3DFBAD
+:1075B000BFC17E687112652D4F7C09B96576549CF8
+:1075C0004CF9EAA879FD407CCCC2CDDFD98DF132EF
+:1075D00052CEBE666FB3197435579DBF46BF223871
+:1075E0004A607DD7A830FF18FF1986788FC074E0F5
+:1075F0008F46C7D7AC91FDAB858CF3D0E22FE6D98F
+:10760000E9BC26B81F8EB7313CCEAFEBC27689F30A
+:1076100042C2E7FC7A099FEAAE325FBD49DA27AA87
+:1076200055FB6FF513D29E34CF22E3621117E2D3DC
+:10763000CDBF4A850FE243F4E5A249CAAB5A3C08E4
+:10764000E2447C3A3F5E15AD0B71B1880FD1F7D3A0
+:10765000C787E8CB75762FD55E1662B86DB0869E6B
+:10766000DA4AF334FF22568B8F89853CBBF4C3EB97
+:107670001E85DDB6D32EBFC0CA747C09F942F28FD5
+:107680000763982F583BE50B5F8E8BFAAD79B09F5F
+:1076900097E518339DEF381F2A63E538DD4DCC2F71
+:1076A000D7CCB0A9767869CF5EF3B087E511F02525
+:1076B000E6E70FDA2FE24B98CF2D9DF19ABE1C071B
+:1076C000B78BF1EAF9FE2DDDDDDA79CAF111113956
+:1076D00024D41D7CE87DFC5F82EF2D6A9CE62D6A38
+:1076E0007CA62687DCD2199F19EA0E3941835B7488
+:1076F000B9C62FB4F23589BEB4A43C8ECBDA9CADAA
+:10770000933BD72486621067252AAECC4EBC455DDC
+:107710008706D78F1519DF551EEBBFF75AD0E1DA70
+:10772000CC4CE0D52E287983E1EF97F0D6E0A0EDA0
+:107730007739ED21F4B5F25FF565BCD4E2498E15D9
+:107740004ABB5DDC20E96FDEA78EB32FDB644853B4
+:107750006365BCC6C763A5BD317E90DF06F989CEDF
+:107760004C8E4328B7F9FF3852371FFAAE03707AB0
+:10777000355BDAA734B8959B141FE21FCA7F656793
+:107780007AA079307F1FB244E138938F553BA2B67F
+:107790002F4290DC44E3DEF256F7A27B192FEB3543
+:1077A000FB7FD0C1F2AE4DFA732E878F84AFC09BA2
+:1077B000C44E7C94DF5B332387E5E61E66095FF1E8
+:1077C00040BC1C676C711AF424D882FF8E76633536
+:1077D0007F9089E17591BCBBC0DABCD1A3937717C8
+:1077E0005837221F8D679DF8118567D17873397CD2
+:1077F000BA023CFBE2FBF08CFA0FF6C75F1ECFAA81
+:107800007FB77D7790E6B9F0B70F27086A77D2D2B5
+:1078100094ECA571ABB62C4FF051FAA9259880F1E4
+:107820004E86CCA597F26F7B73944EBBAEA2F30746
+:107830007D6A093DF302C165C151BB17A6DB454F07
+:10784000DAC376B6572C607985F2ED32BF92EDAB94
+:107850008BF644C57D3DF170B29BE3E5833D65BC8D
+:107860007298FDB2359BAD1C3756F3AED90BB458A8
+:10787000243A56607ED1FD318F0B84B78B5ACC658C
+:10788000B62E17D7D38ED9C0E716EDBAEF0BD8773F
+:1078900016EDBAFE139C4FD1F16315AA7D2EDACEF8
+:1078A0009B91A3DA79AF1657E37C25F878C3C04BD8
+:1078B0009A57B6DC7EC6E386A79E78E6059AEFC99E
+:1078C000F7530AA1CA9DDEFC5A829217B1FB6A7671
+:1078D000F1D32D595D029780AF967EAEDA0723FB78
+:1078E00027F9B77B8FC2414D62AF4CABACE184E16D
+:1078F000F4BDAA662BF3D1AAED9BB63E063CA77D4C
+:10790000409C4BE5F6437FBE86F2953BACDDC6CB93
+:10791000E53895E4C8BE2D724BBB8AB64F0B9F3D30
+:107920006473E7CB72C81BDA7E55EED86F13F91774
+:10793000C3B5A465BFADCD79897D6B691FC7768856
+:10794000A7BEB6813E4FBEA48814CFC5FD2BB6BCE2
+:107950009680763FB47FA737C731FD9EDEAB707C43
+:10796000CA0FEDE377D814C6F7789148DFAF78DF18
+:107970001E1A8FFDFDE552C6FB4F2C8B25DEFF7ACC
+:1079800079B28FE65F610D26BB3895E5158FDFA1D3
+:10799000E2A32FCDC4B252300DEB9ABB7E2AAFAB1F
+:1079A000E2D773785DE251450CA6ADF892E4DB1D99
+:1079B00097D8CF2772245FFC64236D26ADEB133577
+:1079C0002E32F88E5995936F6779E50E75AD1CA927
+:1079D00043F92FD578DB65399DFE4D875EAE5DB4EA
+:1079E00079652BF6E5B3DEBE14E8BBB4FEA00A2F22
+:1079F000057140E6B7C7A6C87D91F1D2DC8FCE866F
+:107A00001294A37DAB95E3A675FD186EDAF77FA2FD
+:107A10007E9FE61D0BF9FA93641967417FAD984785
+:107A20008D22FBD42CAB18EF26F8FF595D6727DDBC
+:107A30006FBE47D2B94AF77F7B57F2939AD0C452B0
+:107A4000E607ADD6700ADA85F64F51981F44C7BDD8
+:107A5000AAF8B0D9AAE283B19EE66551F4F07C4958
+:107A6000FA0717A9FE9B796B7471B680D7B25215CD
+:107A70004F6C91724F841E35BFCD7C95FEA3F731BC
+:107A80009A1F3447F103ADBF587F69FF4284FE83DC
+:107A90000CA72A923B60AFAC3A6AE7F3A9EA4133FC
+:107AA000C7477DB4FA60F230C2F3532D1ABD1AF9FC
+:107AB0006C27BD2E93F1B3153BB728C0D3687A3D30
+:107AC0005511522E49AF547E497AAD10FFBD7C56F8
+:107AD000DD8708DC8DF439FF327CF675C0352E0267
+:107AE000D72F455E17D8D385AB2C83ED7451F0D5D5
+:107AF000E01ACD2FE7E6B82FC92F055CF03A786A77
+:107B000070D4F095343CFE4E271E6BF8AA9D5F9D05
+:107B1000F81ABD6E233CA3EB1FC8113C1FFFF332C4
+:107B2000AEAD8AF8988C9F0EBED27310D3A78FD9B2
+:107B30008D687A057194917C282ADF12D5DE17951D
+:107B4000F747B50F44E5171BDA57ED396893F16D28
+:107B500061433B7BED8DAC575D2C4784A45F60D7C0
+:107B600017B620F0A35707C7D9159BBD870B695FD0
+:107B70006F8C7FD6093ED3A0C59F08EF61D815C78B
+:107B8000F5CA52E53AC93F4A54FE91DD57CA13255A
+:107B90008E4ADE8706619276BF8BF8A289F58757F9
+:107BA0001D23B7C23E51D2EB7EE6FF637A99C3F63E
+:107BB000024EDB918EF34AFC6FE875552FD85D1BA2
+:107BC0009C762FEE298DEB75E3C94BDDB32A71BC92
+:107BD000311DFAD618A791BFDC18C527AE771BEB6D
+:107BE0004BC5CE6E906F4BF3AC2284F1D15EC7478C
+:107BF000CD7DE53D9FEB4553A34BD21BE747AA70D4
+:107C0000ED6529B4800F8FB1BC7D107697D17F13BD
+:107C10006E890F12BE257FF35A00DFD1CE440BDBF5
+:107C2000D5DDBD23F7087B0A31A165C7E790332670
+:107C30004C89633FD004D1F226FC45628AB4E7B692
+:107C40003F136F831FE7A6962F2CD8EF9B46285033
+:107C5000BB447B8C2BFD761AAFCC2CE36D87ABF04D
+:107C60006F8891726CD98ADE3999547E13E2042FA1
+:107C7000E1C7AE52FDD00DA395F538CF321AA47EE0
+:107C8000A1B5C7381C6FDA579E5BE3FAAA71446A44
+:107C90003EA344B62F5F656FCF4A406A0DF7A5F447
+:107CA00064BFE21BFA52FDF84CF18AD4831437E426
+:107CB000EBF618D5CE77BF87E5FB000D09BB9DA875
+:107CC000CD12BCCED15E1BEE6FB53FE871C1CF1AAD
+:107CD00097E7E3FEF39A1437FC55EDA385C1FE7ACE
+:107CE000CC15EE03BE7BCC2BF5D40C2D6E2B3F9622
+:107CF000C7DF991B988579943595BD0E7C14DFD22A
+:107D0000BA87C0DF2718F8F7DD122BC22CA77B1328
+:107D10004037B79BFD73FAD2FA3EAA35B37DECA388
+:107D20008A58F6FF6698A5FFEAD1BE6E5EF778F82E
+:107D3000B38A10AFD83603E38C1F20F9D3F824D7C9
+:107D400010F8CF3B96C708CCAF2CC9350BF32F5B8F
+:107D5000D197FD80E3EF967A574F8B7058A8FFB507
+:107D6000EA7833EBD794B23E539F6442BC652F87C9
+:107D7000B020CEFDA69642A6E7BEFD03E330AF4F8E
+:107D8000EF12D7609FE6AC7E90F5B8B1E6BC2EC08E
+:107D90003BEDBEE9E5E4CFAD753216F2C93A07A76F
+:107DA000BFA973090BC954DBEA5239FF4C9D9BD321
+:107DB00096BA5C2EDF59E7E5FCAEBAA19CDF5DE721
+:107DC000E3FC9EBA524E5FA8F373791F2204D84594
+:107DD000683D417B91CCC7C8BCCF9624F35807AD12
+:107DE00087F5508450C2AED69BCA4D49DC8EEF1544
+:107DF000503B915CC456AF602CA5385A2F14713F8C
+:107E0000D145ED378AF2BD2DEA3D071A1FF0D3F6B2
+:107E100083FA879375FB31D67CFA7ED887CF559845
+:107E2000385EF19C68DBFE3BCE3BD94E926E137BF5
+:107E30002007B5FDC2292077984DDE543BE27248F9
+:107E400061B0E8CEAF1F2F8E11161D9FB8AD36D191
+:107E500090EFF68B2387700C0D4F09FC067876ECBB
+:107E6000CE33FFFE048DBFE1AE13F9A0739AC7961F
+:107E700047F0DD65B15EBB1BF3102209F946AB6626
+:107E800097E3B841BEFFE646DC725C3BCEA3C76D0C
+:107E9000AE3F3F01396885D905BA781FFB47F0FE30
+:107EA00040DDBFD98D924F66C4AA7EC6A647D84E84
+:107EB0005AA6F1D755637D9DE71501EF50DF4C19A8
+:107EC000B71E2BFD8FED15C7B7FF8EC66F5F66F32C
+:107ED000AAACDBE71872F13CB4EF448F773C4DB0AD
+:107EE0009D8AB467510B3BE65EF7B1F9C0DF7BEDCD
+:107EF0007CAF40A1436226950756BDCAF7AE95DA1E
+:107F0000C36C4F0C389C1C272782D6D3FAF1945AA5
+:107F1000793F5BB4F54A84BCA0DDAF8E1BE4B3218E
+:107F20003E1B63027F66E71EE0FB9DA24971411F75
+:107F30002A57CBCBB5B8704BA0DF143AF02CB9F26E
+:107F40009E6AD75C1977DFC9D706497D7F41A8EFC4
+:107F500046B3CEFFD1B77F711BE8AB939F4D5198CD
+:107F60008F11DD3B40E727FBCD3E817A2ADF0F3EB4
+:107F700037BE38DC6709EF6F95F0C19F932ABCB01C
+:107F80002B627F31FEB95516960335BAD0E3AD2D7D
+:107F90002982D784EF3E93A40761463DA568F73F49
+:107FA00045AFB3DC928E347AD4E80DF33315F1F794
+:107FB0007D161D9FB3AE1A6D82BD5DA32BB6D70E85
+:107FC000C17D57F957BE5AE17B0FE54D85B679BAA9
+:107FD000F365B65A3E07F74B74E5BDB12F83711FA9
+:107FE00032549F0ABBA27AFF04F94C82E3DA85BEC1
+:107FF0006E4111699FA0EE5F438CBFFA39E8E7DB61
+:10800000E3F83C2C5BF1E39B0683AF3ED395F1F79D
+:10801000B3093B385E6E76E38C3BDEA3F2C093314E
+:108020005C9E9B1B1808BAFC4C71CF7A0E7279D0FB
+:1080300073F360EAFF1714B21E165AC5DFBD77F45A
+:10804000608E03146E1BE4456DDEB3738B56C0AFB8
+:108050003A7B356E2503D9020BB0BF0D336EB1C02C
+:108060003EE9C1FC18CF84D403D47393E06483DD6C
+:10807000E75378E2D91E26ED5F9FFDE6E91338E766
+:10808000BF7A2ADE05702E1C28CF6D91171A22DFC9
+:108090001730EA07639EFE3001FC5D936B17ED32EB
+:1080A0004B39D62BFD14946739365A3E7DF999BF6A
+:1080B000245C522FD825ED1C3FA41768717C8B9E41
+:1080C0009772ADB61F8B940BAC572FDAB73CF952B1
+:1080D0007171D04BC10FA2F5832BD523A2F587294F
+:1080E000B946FDE14AE3F1B47C456D41D6C757215D
+:1080F0003E2F302B17F179B543B26007ACA91DC5EF
+:10810000A916AF57513B80DB2DACBD8ACB7FAACAE5
+:1081100051C22238DE7389AA3F9F0B657711DFF3C6
+:10812000FD45EB6892D4FF9CC5DD0576075DDC3626
+:10813000CB7395BFCF4A029E2DD8FB90CD44E54F1F
+:10814000E6CAEF9C89D2776AB67DC476896AD1CABD
+:10815000FB43FB261C7AFD779D8DBF73B9F9553E15
+:108160001DBF18F8BBA045F16DA1712AEDEE0720E7
+:10817000CF54BE36D91AD4ED67A38ABFD1F3BF332B
+:10818000D76D88A3C27C058FD3F239E2D8C46FE3E0
+:10819000585E3BBB57DA6B3FD966DE04F96C41CBC6
+:1081A0008E1AB6A36C8B73C184FC9955CA8FDA38CA
+:1081B0004DEAF79A72353B480BB73FB52D4EDCEBD5
+:1081C00091F3053FF84C31DE5F58ABF65B9B2BE536
+:1081D000D53C95DEB4F60B9C4D36E83B675E98DCEB
+:1081E000ED6ECC6BCF9F12FA507948ED7776571C25
+:1081F000BF3BB060D77F4C7811FADAAE926E8A8EB0
+:10820000CF6CCFB5CAF984A4DFE6CC5E69DFA806DF
+:108210009C092F4EA9768953CF746D96E776C800D6
+:108220009F53BB9E4D30E545F6719123B40A22B2AF
+:1082300076FF27D61A084260B7EC9D18048F67FABC
+:108240004EC33DBB901F7C4B6B6773F858D8D1EE83
+:108250004B0B2D6E518DA72179E28D00CD7FC90288
+:108260009B803C316BA07BDAAD380F5FB3F27E8828
+:108270005EEE47E0C79DF5565701FEB4C4E3657B4B
+:10828000D2ACAB249F69F7C878FB8E3BE3D9FE5D87
+:10829000B54A113E5A9F7872BC8CDBE9D4CFBC6FD3
+:1082A000AD843DE3CD2C013DAF2A641601B41B1A09
+:1082B000CE99A8B347A713BEA0FFBFA9FB790CF7BF
+:1082C000779C38370FE4B03F79478C82EF68ED4FE9
+:1082D0002BE11C8EF3D8618C33A89A14CE811FA099
+:1082E0006A671AFB014EABF780508EF95715C978B3
+:1082F00082CEF63F3F90037CAC9ADD92EBE275B9FB
+:108300003E673DE3B978BE2F69FA5DBCEABF8B6179
+:108310007F3EFB1C29BF202199E3CBCFE64A3DE6F7
+:10832000F14EFA94F1123DEE7226E8E3257A284DDB
+:10833000322E628B315EE2984D9607B71AD771DA0A
+:10834000DAC4EFA204B718E3254EDB9A64BCC45626
+:1083500063F98284265E57BB55C8B891A7649C8F89
+:1083600070B6EEC6F80B9F8E61BA5858573B01FCA9
+:10837000F2B3B4D0BC3D54FED953FD38AE87F653AA
+:10838000FA37820A9F030B894D20FE8ED252C4D148
+:108390002DFCCD23E96CB7BD4BCAB987E3D7B23EFC
+:1083A000726EB35D015F3FD95DC68D9CFC43577E05
+:1083B0003FE3A4D2948EF92C24890F724A4034CD25
+:1083C00062FBF366BB40FCC4C2CD768E6738B9E56C
+:1083D000EB7E7A7B37951BFCBCDABCB4FA2EFD240D
+:1083E0009FEBD24FC2BD6B3FA94F57F67B6737E477
+:1083F0008B768FDC1FDA3FD6DB1EDB11C3F9CAEDAB
+:10840000DD3742FF5AD812D36E66794CF5E710E398
+:1084100083DD6C8190F2CC67DBAC1C8F81E751C0AF
+:108420000FAB547EA8FC62686A1BCB6923F83D80C1
+:1084300085A6C22EC3693D0B09AFA15FB65BBD3FE8
+:1084400062BC79C3CAFA1AFEA0BF9DDCDA93DF854D
+:10845000189F246E9B847EB5FFC1711827939A0ADA
+:10846000922EA1672DFC5D3CC7C72E5C79B589EDC6
+:10847000EE66A91F52EA53E4BDE721902BAA57C626
+:108480002DD6FB61163A4F709C4834FC6EEB27E505
+:108490009E6A357EAC72AB7CAFA38AE80D71D7952E
+:1084A0002BA4FD5CFC46BED3B234269C80752DDD2A
+:1084B0006266BF41A5AD25A73BCDFB867E92FF51ED
+:1084C000FB00BEDBD9DFE67D84C77D732AEFFB0DA1
+:1084D000FDBAA97E8C8792B1AFD1ED97C6101F71FE
+:1084E000EADB6D4AD0EFBFD6AE735D2DD27E735EF0
+:1084F000B4FEF42FD4E56FDB62785EC4EF393E2F13
+:108500007ABD345FC6CBCA67EC7CBFEF947A3FED8F
+:1085100013E2A7C1BE98CF8D0FF07ADF99CC71B16D
+:10852000F343C6FEE7DDAD43605738BFEB260BFAD9
+:10853000FFA89FBC8F58BD7238EFAF78CBCAFDA2A1
+:10854000F7AD486DD7497FDBE3E4FB4BA2E5198C1F
+:10855000776A7B9C09F4D79E28F1F9D4689A27CED4
+:1085600081ED29457C97054215E1DB4297C4B7535D
+:10857000892DE92EAEEF5B88FA76F51D1C11A696C3
+:10858000C04BF4413C48AD94E32A1DABD9EE8F3883
+:108590009221459C86ED978837011EC26E7048A5D2
+:1085A000233CC7027E5D89F1186F5B6CF05706545F
+:1085B000F9B36A5B74BC88AC6FD4FAD36CBB69F155
+:1085C0002B447F954185FD07958DB72F009FA95CB2
+:1085D000FCE0ADC04B6DFE9516510A7ED0AE987989
+:1085E0001EED314417905BF5DFC994A92B39B2CE4B
+:1085F0005FAADFFB553FB7261F8B261AA7AA515942
+:10860000CDE3AB7C82FDFEBA7E04061BCE99F6D18B
+:108610006A7DD47ADBD5B8CB8EED4AB3FE7C895E19
+:10862000F7ABFDE4B9D4EE713F3002EDDF3073FCFF
+:108630003DE5DFBA96E9DECCF1900DD8BC61724C15
+:10864000FCBB76412F8EEBAE300B4B1AC75BD822AA
+:10865000F11B66A35D0571F3D0D390424F73DBA588
+:108660009E863CF434A4D0D3500E3D0D79E869C801
+:10867000434F431E7A1A52E86928FF44E5932F8836
+:10868000D0008B59E7BFC63DF5419138AE485C97A5
+:10869000C9E8CF3E698AF66773FCD609A575459A85
+:1086A000F2C3F15BE5DD03EFF6EBCEFB6C18EF8573
+:1086B000CCD000E8BDB5E0DF889756DF9FCA596F80
+:1086C00033C03D77B331DF7F9B319FB7CB982FD835
+:1086D0006BCC7B5F36E6FFB59F90DF2B8A71222E35
+:1086E000A86DF9272BA0560DEB1E38DA8FE3BE3BA1
+:1086F000B6CA78EE30F397B67ADA5FB9DFD20E47B2
+:10870000A3017FB5B8E01F7CEFE707DFF931E28313
+:1087100016C7B4C1DA91063EF9D1538ED598E74712
+:10872000AAFD544C77B07CA5C9E99A7EB5E47E8554
+:10873000DF25FBBA5F12F73F779876E37BEC78731F
+:108740002E5CC5F279677EB562E238A9808FCF3D95
+:108750004D7E4B57487E03DFA3F5432EECBBCE6422
+:10876000987FBF50AC01BE039E4C32E4F35B7A1895
+:10877000DA0FDC9369A82F0CF737C6814DA9DF2FDC
+:10878000EF59A8F350E5D5C9ABAF32F42BF70F374B
+:10879000F45B7A9783F16BE97B66B6B356A002F17E
+:1087A00026902B699D15E80B7FEF661977226A8D5D
+:1087B000E77B8545045D4978A74D9E3F5A3C798506
+:1087C0004BF812699C33854D5BF1EECD823FFC691D
+:1087D000880B7180CAE814D831A6E4043CFD096F07
+:1087E000D2ADBE09ECBFD9919D580FB9F3F021F677
+:1087F0005F6B78926E75C5623F9B9BA43E007B8E3B
+:108800003929B2DFCD4D5D63FB3823EB8EEC6F1E53
+:10881000CBCFE70F9BA10E888AD14AD0363032FFEA
+:1088200025EA79A1CDF763556F108D729C9FA8F54D
+:108830005545AF3E9E445B77DA74E0AB9534BF5349
+:10884000852D39614A173ED69C7C0BC1C36A0F5CEB
+:10885000D31FF6F8374A12E067FC729B95DFE3F905
+:10886000F7359B1E475CC8CAA64D36C83F0B2D2165
+:108870001BFBC19F6AB6212EE4BA279BB97CDE930D
+:1088800065AC677E6A5D6C63F9F4D78A78CE13595C
+:108890007F45B1B2DE85F8EEFE928F56C48A400B5A
+:1088A000DB9D471CEA86F3F64985E322A64E196D47
+:1088B000ED0EF97D5B22DF239DA2B68FC6FB73AF61
+:1088C0009BA57D6C8ADCEFCBDD6F9D7CC1C3783EC0
+:1088D000E5C200D6BFA686FB497D37CFA8EF56D8A4
+:1088E000DC6F81AF8B3F9A593EEDB43F78AD2C0FD2
+:1088F000230E127197FE116603DE2D1A1367C0CB8B
+:10890000E922C910B779B3E861C84F199F65683F7C
+:108910006DCA80287E5014A9677E708D217E933E9B
+:1089200060A08B6AB4E073A5D8D00EE5322EF406B1
+:10893000C3784BDFB82A45C6374E8AB487BEBC59C8
+:10894000FA3BAA77256E84FE5D619271CBD303B2A8
+:10895000BC668F2C270DB4F39E4417B3B427E8EF01
+:108960007B08D58F87EF03AED5AABDA93A57DA9910
+:10897000324A5A6D8E6E6A7C300D5DD3A4309C09EC
+:10898000BE96AE4932BFAC88FB3BBA1645F0A46632
+:1089900097F1DE26C687BFB9E6B0B90CF4105D4F7B
+:1089A000E7D48A1E98F778A5107A670DEC450988F8
+:1089B000BB8CF25BC37E043F2FEC47BA7DFA6B7F22
+:1089C000B7C43BD5CF331D15B475552D3B5EC1B82B
+:1089D00053FD123FA3F148D30FE609C227F89B8845
+:1089E0006E43EECBC30577C7A07F68F0A9F149BC01
+:1089F0008BC6B31EC043C4D30A821F8D3B7F97E250
+:108A0000C53B58680F78F5001E46C187E1F9CFC213
+:108A10006D68941D48A3B33D0AD3D9E5E018BDBEE7
+:108A2000CBC1555BF7A40BD21EA2AD7B5E40E2C565
+:108A30003C5A17FCA637E3DD99AB802F929F741048
+:108A40003FD989EFFB25BCA68C37D25D27FEF825E0
+:108A5000DE6BF833F542328FF3CFE34F1BDB6FFF52
+:108A600059BCD1ECFE1A3F869DB18CFDD6771BEC2C
+:108A70003C5A1A6DA73CD95F8D1F192C061BE24783
+:108A80002E730F293A7E443BBFA3CF8FB23FC8F36A
+:108A9000A3F37C51CF852577E5323FD0F86B402D8D
+:108AA0000FA8F63BED3B659477EBF22B1AB3D2DBC4
+:108AB00074F24560B93519E3A4D777E5B42CC6C57F
+:108AC000F15265F5327EE5F83D29C943691F8F2FC4
+:108AD00097F12BC7EF1C948E3894E3CBC772FAD171
+:108AE00083F6E9FC0ED22F1C02F1E5D5BB53E47DE1
+:108AF00071B333793AEC713BBBF27DCEEE03A43C0B
+:108B00005BB5FCB904845F552E97E7F157D981C452
+:108B1000016C9F6FDECA0671577301CE039DDD366F
+:108B20006B00F438D86D291FA8CFE638BB4FF18D04
+:108B3000229C5BF2FCFF34C67533BEF7E95356BE88
+:108B40009F4BF53EF8517EA2844F5CCBF7F69464C0
+:108B5000D8A34EBF6766BBD802F3FE027CAFAA6EF5
+:108B60004F3AAE505414D1B94A7830CE4EF3198CE6
+:108B7000F96D4A67A7E3AA667E8F31DA4EDC094FAA
+:108B8000D54EBC553DBFA10720851E20FA4A3D00A9
+:108B900079E80148A107A07CD13AA31CA7D9893361
+:108BA000CC5FF03BC69ADF48B8DA5E66FFF14376E9
+:108BB00037F4D05E16F5FD35D59FA4F96F34BF525A
+:108BC000D943F3055EE829EB29BC8A6CCF7EA66801
+:108BD000FF52197C8668779F85DFF3E3BF21D20FB0
+:108BE0008B756B7E29F44F28D2F96B55FF9055B8E1
+:108BF000D2711F32A3C4F5D323D2DFCD7AD5F86268
+:108C0000A9A76AEB9AAFC60B68E93BAA5F69ADC931
+:108C10009B0ABE3CA1B11FDB9583C5227731CB15E2
+:108C2000CE5CC43B2F5562BD908B97629F91FF3005
+:108C30005EBE57DA7ABD9427547CD7DEDBD1DED90D
+:108C400019D941B2A38E2EAFBDE010E53AFA1F2D1F
+:108C5000120DF912479AA1FD5897C7507F5D6A3FE0
+:108C600043FDF5EE4243FEC6DC6186F63779471BCD
+:108C7000F23F1A7ABDA1FD44DF44437E72E90C4302
+:108C8000FBA9FE3243FDB4E90B0CF53302B71BF22E
+:108C9000B756DC6968FFE3C5F5867AEDDDA1BDD086
+:108CA00053EDB82FEAE0547B7FE86B93E0F7B247CF
+:108CB00094C87B44C22EE3EE96BE91EDD4DB77964A
+:108CC000ABF4FBC73CDFCCFCC1F23E2FE8AFB7F6FC
+:108CD0003EA020A994F5F6D634D0CB88B803E7F1AE
+:108CE00034EEDF077C38D542FC74C4D507AECA72B7
+:108CF000E13DC5AC9B393FFCC0B39994BF216FD611
+:108D0000CD16E28F23061E388FFA7D79B9323F598E
+:108D1000B00875F3B63F4C0DD23C465C9BB9DA2BDC
+:108D2000ED38DA7BD78CAF9D718B0E67384B170F00
+:108D300084759667E37E9D8BD3034487485F263A0C
+:108D40002C27BEFB0AD121D2C3A48FA3FC8FA48FF2
+:108D5000237D9DF471A46F923E8EB495F471A4EFBF
+:108D6000D44DE7F4DDBA00F7FB735D05A747EA16BB
+:108D700073F9FB75B59C7E5017E472C01BF9ED03C7
+:108D8000547BCB1EE37BE39ADF5CF3938B97BC0EA3
+:108D9000C41F88364BE20947C4FF7D393D10069356
+:108DA000133AB93145F8F60C607F4A2F17FBCBD444
+:108DB000F28399817DE067EF7926675F45F969DF86
+:108DC000069683F4DF33493B7DF4B80F0D90727B38
+:108DD000739EEF00FA8D74C87B38231DF29ECD4838
+:108DE0004B6B03BF53F48D70836FEC57EFD534DCBE
+:108DF00063E17B35CA0549AFA3BA09CE377CD36698
+:108E0000EE7C6C4FC75F46BABCA97CDEAAF5DABD22
+:108E10008D31175A4BC09746396D1C3FA5F1C1F5EE
+:108E200056C9F7F6C79F28C13D13FABEC0F81ADF2E
+:108E3000DBFC8D089B0A22FC6DA4A3CD0C3EA4E3B1
+:108E40007BCCB7940B6D66C8793ABEC87C4D9B4706
+:108E5000BC85C6298AF03D6D9E787FD256C4F53E0A
+:108E600033E633DABB0EEFA5ACA779E0BCE9E4C387
+:108E70007611E4773055FE4CEDF9FB632E04384E45
+:108E800060941A27D0DB4607BF6CC7F10BF1D02BDB
+:108E9000D1BF6BDB41ACAFE77FD0B8D48EC4278E97
+:108EA000A7D1F831DAC7C9F6618CFB10E28E10FF4A
+:108EB000F2779A7702DEE17CDB03BB65CF9FC9774F
+:108EC0003484CFC7709FACF24BE156F3AA9C21BA11
+:108ED0001573BE58ADBF262B60CE435CA3DDF56194
+:108EE0001CD373566FC8531355BDE27BF0C591D7A1
+:108EF000FDBF8E2F832C12AE762A877FE3FF75BCD1
+:108F0000E9192BE7DBF3EF120FFE7FC39FDB3AC4B7
+:108F1000B82ED4E4BBACC043E02F6517DCAF205FB4
+:108F20006E29B40165B47A479F4BD707FED661ED31
+:108F3000A2C3B391EAD9D4EF32EDB576DAFBD4DA35
+:108F4000F8D7A1FDE08BDBBFA69EFF4BC74A3C2AAA
+:108F5000EDA7BD6BEE7316D23825428EF39A7ADEFA
+:108F600095E4CD673D4638A55EE0A67FD8DEA7CA6A
+:108F7000EBD75EB018F4851B543DA254487E5D1AB1
+:108F800015AF7043DE75AC4FDC10A54F44EB07D531
+:108F900079AA7EE0119E7FF25DA1A5A0474DFE4417
+:108FA000DC20F036CB6D768C288ABC23A4BD4B35F3
+:108FB00046A5E3B12260C121729D08727ABD087195
+:108FC000FA32DEA52A403C6C98CFFD9BE8C041F9FF
+:108FD0008F20D251FE60DC8499883D2FB9AAA40F5E
+:108FE000CA75EF61AC007DD798037F75E9DEC338A1
+:108FF00030C6CDFEE5030E79FF057485DFF9D0D6C6
+:109000007190CEC13E740E1EA2F3B80FADE7553A73
+:109010008F91FF039DC748B576E3DCC6B8BB1B72D2
+:10902000EB05C6BBD155420AE2E5E17463C1F3BD6D
+:1090300000C7D712FB8EC1FEBE9678F518ACEFB50F
+:10904000C414934CEDB6EFBB5FADE1FF8D79F2FE3A
+:10905000C58DAE71FCBDEA38C9C7AAE3D2D5F77396
+:109060003E4C48253C39E7385860A6F424260A3D92
+:1090700031CA5EF7499D08629DA36A87F338D7D647
+:109080000EE3B4CA21D7212CC5267D1CF4265B60D3
+:1090900027E0FAC97A33C7EB9FD919E31D4FE37C68
+:1090A0001A7A3601EB22FD6737EAABCCEED55EC803
+:1090B00067AFC97860F1EDC174C41775BE37B57973
+:1090C000B2218E5EC38B2A875C8FA667A6F6F13D20
+:1090D00024E504F91E8E1667D4CB2EEFF969EFB3A1
+:1090E000409EE2F8F928B96548ACE427BDEC92AFA0
+:1090F0006AF0A37E9C178167F97DBC4D354E2FF435
+:1091000095DA54DF6B983FC9F5FC4EC2B95EF1CCDD
+:10911000E70FA8718BA3C203D8FF5C0A7B0B4DF944
+:10912000D558F92ED801354E51E91BF833FABFEA6C
+:109130003ED00BFAD9B9C3E7CDA0F3837D1481F7F4
+:10914000A07E888EA2E9F0589E1A4F54200ABE9342
+:10915000EF95713CD4B977CD5EA9670B837E314A18
+:10916000E43C027B50C9612B223E22F17DA992CFC3
+:1091700068743AF6B08CC3B2A79A845BC73F62DCCE
+:10918000B1C2ADFB7E5C6E92211FEFED6168DF65C1
+:1091900068A6A13ED1D7DF50DFB5B4C890EFEEBFCF
+:1091A000C6D03E657AB1219F16B8C1D0BE67C5242E
+:1091B00043BEF7E25B0CED336A671BEA3DC185866F
+:1091C0007AD2F418FE875C8A78CCA37BE726E86B1A
+:1091D000CD4D967C127F59AB9618FA953AE7F13B44
+:1091E00070D94D3F378C2FDCD27E13A47F805F5F18
+:1091F000E26207A563538D761DB3AAC794B846BF34
+:109200008CADE9A9C69195B88CF69D9ECE52BE173D
+:10921000D0F307E2CA32F2FF493C08F4BF341E54CF
+:10922000098EE38DC603F85BF4EB84BF450F0FF89E
+:109230005BF479F85BF4EDE16FD1D7C3DFA2AFBF88
+:10924000EAB0110F06B71AF1E0EA23463C3884F37E
+:1092500020EBF2FB35ACCD8827DA7E0DFF74D225EA
+:10926000F76B3AFD83FD221263BE3586E016169732
+:10927000DFB7C87EC9FDFBBFDDB79BF3D57354DDF7
+:10928000B72FC5EAC185FC0E259D533ABF6CF43952
+:109290007A8383F4D6EE17EBAD1AFF8AD65F35BB1F
+:1092A00082165F1DFD8EAFA63F6BF1D4D1EFF77E26
+:1092B0006D6A8BC7F979CCD4C4EF209B530235F883
+:1092C000FE6D798B15F8DBBB57AE603C3FDBBBE333
+:1092D00018DE630FDE192FF97A9E1C6756430ADFEA
+:1092E0007FD7D631ABA78CDFFA59BE7ADE7BDB069F
+:1092F000C39FFBF37CA997C77B5D7C4FA02C4FA835
+:1093000071D0227D567EC4CF786E9994B7038E407B
+:109310001DF4F706F57D78EDDEC015BC1BDC88F981
+:1093200077BE37B220FA3D97704C5FFACE636B92EE
+:109330008CEFE4540BC37B238F2DCBD1EEF5CBFA0E
+:10934000DBE5BBBF7DD709C3F9AFF9ADFB851C8653
+:10935000787BBCFB83B880014FBA0CE5F92DA98658
+:10936000FE8FA9EF130DDCE336B47B4C7DFFA530F7
+:109370009C6B687FD561AFB1BFFA2ECCE0D6A186D9
+:10938000FE6DDA7B3E0BE4BB26D01320EF5F7DC47D
+:1093900067689751B96402E486DEAADC3DACADD4BF
+:1093A000307EC6D95813E2DD0FE6CBB8FCE19FFA58
+:1093B0000DF5AC9B010F7E96CCF0D2F499CEDF79FF
+:1093C00050F5179B90EFBCDB5659D83FAAC595477F
+:1093D000DBFB3AED798E88FD501FEFADE91F9D71E3
+:1093E000DF16926BB22271DF9D788877FD65BC062F
+:1093F000C3E1F19F2737EBF1F48FF9521F7C146F13
+:1094000091D1BAB638A43D10F16778675A58DAD2CC
+:10941000F0FED3DB2A1EFBB37D6F011F1F55EF57F4
+:109420003D6EEB388A7375D640F99D992613FF2E51
+:109430001CE2F176EAF4CF0FF2A55D65D34099CE38
+:10944000EA22E723FE45BE2BA0AD23D5261AF9BD9F
+:109450000C4B5B3FE0F78F57B7DC8FAA99B626AB72
+:109460008C670F59F9DDD06292830B092F9EFED9CC
+:10947000C3CE6178F7DEC2F6A78FF2EDD3827D22EC
+:10948000F7A132A818FB005B38F4ADC103CD977C7F
+:10949000875CBBE7E3BEDDEAC7EFD88D378952E8CA
+:1094A000755A7DE94049B7A13E26F62B6BBF0BA14B
+:1094B000D5DF5A20EB730AE4FAC69ABF2DC3FAE649
+:1094C000C64BFD7694CFBF16FE81D96BACA219FABC
+:1094D0004E90F49D648EFFE1BF32B7D457022A1F2D
+:1094E000471EFEA6B2A091EFD279C0F2D67CFC3E18
+:1094F0008B027EEE5D01FBFF9C55C67673851C6F6B
+:10950000BE53BEBB3A37FAFEA7E66FF9013D687C51
+:10951000817AEE0E1403BFD3BD177B4ED5FFCF0962
+:10952000B98FE76A6D7CAE6A78AFC36BD6BBFFA715
+:10953000EE4708F5DCEFA3C251A3330D9F34FAD1F7
+:10954000F009FB8BFDD3F617F7B1DA9D91FDFDDF36
+:10955000BA97D509B71FF0175CCE3F10CD57F84F1B
+:109560006787B99C5F40E3339D7C4410FFC88AC085
+:109570004B8B7FA85071245AEE3A17CAE2F875DC7B
+:109580000B33CB79723C9C768EBBE1DFD2F95F88DE
+:109590007E62F1BB05C1460BBF8F100D5F8D7E2E25
+:1095A000179F711AF119E0B59A1F4DAD3F1D3CDFB1
+:1095B000CEF5BB62F81DDC3385AD05D03F34FF5AD4
+:1095C000B4BFEEDC328740DCDFB95DF1EC6F853F84
+:1095D000AB0BDE85AADF54003F57E739DA66F4CFDC
+:1095E00045A75F65077E52D01D7E2EEBCD1C67E838
+:1095F00034B9E0BFBFC77980DF3548577C77A05EBC
+:10960000D3FBC6D339877D23BE548AFDD6FC51D106
+:10961000EBE9A4B311F23EC7B9A08CDB3F572AFD9A
+:10962000C3EF09E28234DFF18A8BED007AFCFC673C
+:10963000FC5A932F14F2FE4CB9309CD71958358C34
+:10964000F339194113E2BBC5AD0ADBEFA76D16CBA9
+:1096500063DD88D39A3618FA5BB3BA4F39EAF91248
+:109660000D97BF17C87365AB49BE07B4F56E197F78
+:1096700038609BCF847789A6EF72A9EF972F2E824F
+:109680007CE055E94F6B9F631187AD452A1E53FB64
+:1096900027AEF6F03BFB29EAF95138C0A5E2491B99
+:1096A000BF23DD199F552F7F276B8922B4782DE6C4
+:1096B0004B5AFE7C939A1F2BF34B97CB7C9BFA0E55
+:1096C000E956D5FE01F82105FC601FD8A6DA3F0057
+:1096D0003FA4801FCA41DFC883BE91077D230FFAD4
+:1096E000460AFA46F96CE14F876315FEAE313A3E01
+:1096F0000D7FD7181DBF85BF4B9F87BF4BDF1EFE59
+:109700002E7D3DFC5DFA7AF8BBF479F8BBF4EDE10F
+:10971000EFD2E7C5D0EB2379D8D57C130DF9C9A4D6
+:10972000378CD19D0FF077E9C787BFCB305EE076ED
+:1097300043FF5B45ADA17FD6E27A43FBDB6A15832D
+:109740003FAC5C74303ECF59D795F1B04F96FF18BF
+:10975000E8E7B6691DFC1EEC58F3DE05C08725D589
+:10976000B15EB9CF4DA572DF4D1C87BCC1EA4EE199
+:109770007708DF300BB9CF320E3A1A3FE1EF1963A9
+:10978000957E27A4F03B2185DF0929FC4E78E7115F
+:109790007E27A4F03BA11C7E27A4F03B2185DF0996
+:1097A00029FC4E48E177420ABF13FAC1EF84147EC8
+:1097B0002794C3EF84147E27941F83DF89F2C3604C
+:1097C000BB217CCE6F0A1E82AD6AC2FA632F23CD05
+:1097D000E952B6532154770C0C4E831F2E27AEACA2
+:1097E00028D14B7CBA7EF9B43144AA0135BEB040D1
+:1097F00074B0FCC77105B4FE4058CAE9F9DFA47122
+:109800007D845E243DE5BFEC6239B550BD07ADF502
+:109810002F842B2B2BD23E92BF74BBE8EF6BED98BD
+:109820008FE9E6A1DDF3CE78D5CDE713D101DFD7FF
+:10983000D37ED728101CCDEF258FB749B98AF8C23F
+:1098400035D097060415FE5D616DDF3C2AFD0FD80B
+:10985000266CA9E00B1B660DE27EB19DFDFE7E121B
+:109860007118433DFCAEE4886DC2D74CFDFB0F94EC
+:10987000FC684447CB01F0B5B2C689DC4F1BB76C1E
+:109880007D3ADF5B2D138B7F8EDFDF1183148E4FCC
+:10989000233EF432F890B6AECE738A500276D32BC4
+:1098A000BD17347250E258C4DF89BD82DF2BBA691C
+:1098B000D0DB8675F3B60CE17199FFF70D2AFC1E1B
+:1098C000DE8460FDDD501F6F0ADE7E08F17A81CDF7
+:1098D000C2EB7133EBE67B14DAFCFAFB7698E8F81E
+:1098E0002075B4D584DF8682AAD255B7BF84E153F0
+:1098F000B01F855E2BDF4F99687159F95D84A8739D
+:10990000313A6E253A2E72C95D17DA11A7BAE439D9
+:1099100079CE6AF241991A2777BED1CA712565CFEF
+:10992000D9F99DB9C03A85E9588B6B39637A3D798D
+:109930001AF5ABCE0AA59B1057DFA3B920C9CCE717
+:10994000E8CC81B8A7D028E34DDA1B9FE5FB8AE776
+:109950001B9FB3F1FB91AA7FA05C854FB91ADF541E
+:10996000962FE560ED1D7E2D2E4C34497958B37B42
+:1099700094BD21E365A2E5E44A550E5ED068E5F8A2
+:10998000A405517272A51A7F54F90372F2D281AA0A
+:109990009DC32BBCFFA4BFE0CE813A7F81D0DE63A4
+:1099A000567F87A0EC8D8353F9DC5F9C6DC2B9AF05
+:1099B000C90B33EBA53C207608FE5DA699F5257C06
+:1099C000AECE7CCEC7EF51BCA5CA01932EF464F88D
+:1099D000FF493DF7A7223E93F6617C5B0C97DF7C45
+:1099E000218DD3691764BC26EECE004FDA9E171C7A
+:1099F00067722E689772C85EA1C67F1AF1B450B81C
+:109A0000C602EFFBFB948310B36E821C41E34D87CB
+:109A10005CD115785FB6BC3BF03E2458DE8BC6FBAC
+:109A2000F1D6C587503F7E8BF0064504EF0341CF4A
+:109A300058AC6F42A9C2BF2F313DF0B605F44EFCC1
+:109A4000C0857E0155BFD3F03B9A1E66C5A97AAF8B
+:109A500053DA5D3AF5614C128F53068F4D435CED3E
+:109A60002CD8D67AF0B27C88738BCF93F5BFFFEDFC
+:109A7000B1698D7DFEF7DF4BD0DE4988E8DB52BF50
+:109A8000879EEDE7F89B0FC6A6B09C9358A4B783BA
+:109A90001E57E9B7BAB0D8E2A57E4BEEC94EF9BE63
+:109AA0007BB07368DF409FB3BAB4DDA1D0F9F2FE9A
+:109AB00040E11B3314BF7F22B4C73CC3887BBC4545
+:109AC000CD1F1DF88F7F5B95C770E6FC9F079E9C9E
+:109AD00086B88F7B976D8CE2837E1FC8212ECFC7FF
+:109AE000FEA1CBE9F39E145FBC97F6714E9EF67B08
+:109AF000B2F21EC3F17B3E795A6FAFD0EC5D427477
+:109B0000B0BCBF76526AA1FAAE0DD3C3630BE53D7C
+:109B100090AF557EFF3F75DF23D9E3FF6220FB65E1
+:109B20009A1CAC27E5763CBA85BE3FABCEC6F72F74
+:109B3000357D6AC3C2585EC7869FDB981F6A7AD597
+:109B40004C5BEB21FCCED6D181B2DD5F6A7F65052F
+:109B50009FA37DE575CC5C28DF31AD2EF4FF03FCBF
+:109B6000212ECFCBEF8704F2420A7EDFB4874BE28F
+:109B7000FFFF01CAEF279700800000001F8B08003D
+:109B800000000000000BDD597D7054D5153FEFBD7E
+:109B9000DDB79BCD6EF276C9272161771320EA02EB
+:109BA0006F3784519969D79450679AB18B4E31C100
+:109BB000105E48827C2490A44C0DAD369B2E600C28
+:109BC00050420DF2D14A37B1D08F099D808C322599
+:109BD000CEAC52BF5A2CA8D3A923362EC5224A3563
+:109BE0004B662AD2B1DA73EE7D2FBB2CC4FA57FF35
+:109BF0006866989B7BDFBDE79EF33BE7FCCEB9A18F
+:109C0000C69BF08B0B00128FD82B8704802FE8E7C0
+:109C1000EB003325F83DB800EABDB0326407FCE93B
+:109C2000075808D04CBFBA93FB4EAB782817E08C8E
+:109C3000EA66E3F27E2118C5FDCDFD835BF3720079
+:109C400056F5FA174A78A4CDAF292A7E6F1AF5BCCB
+:109C500054845B379C70CA9A0FA0211FDA477C247A
+:109C6000345172AF2329B74C97FB9A1F3F55028C92
+:109C70009BA196EF8BF67A516E5D8EE2EF433945EC
+:109C800026D86271D17E91ED2F3641580CF0310308
+:109C9000D765300501F7CB5D723482228B008232AA
+:109CA0007E9F6185B015BF17A34409C7FD73B8FE39
+:109CB000327E17710EA6F82D21D4A75E565E02C221
+:109CC000C721BB099F46FBEC25F9386FEC175C02F6
+:109CD0001EA9966A5E22F99DBB3D5E8B076099AE18
+:109CE00037D45A45C80368B172BC3AF794CA85B4F0
+:109CF000EF3141A1798DCBCDE424760ACA10CEEBA9
+:109D0000517D0824ED6FDE7707B8A7E118C5B122B1
+:109D1000B99E3EBEB3FB64EE1D781E624199F46DA0
+:109D20005682B2CB97FCDEA4FB237DBE4495989E61
+:109D3000F5008B09AF159B3CF22A3BCD5F3177FADA
+:109D4000C80E8E87710EF7C5685F8D17381EBB5120
+:109D50006F0FBF2F90227F15C94FB9BF86E207E76B
+:109D600021D5C1E4ADEA77CA8217F15314A6E70DF5
+:109D700038E8F837C5A26695F431E1BD385FAE44E6
+:109D8000CD011687EE25058863F30E01FA70A6ED66
+:109D9000E0F769BD4E792EEDB7294BC81F89AD821A
+:109DA00083F4AB7105653BCD777BC4D4F84EC7A96E
+:109DB00051D7BB19F56BB96E7DB7D98DF33AD46B1A
+:109DC00004E5AFDA72972C527C9BB8DDDDE46F8C32
+:109DD0004F4DC7F5EF1D197D908D7AB8FAAB37E37B
+:109DE000BDF5AB9DCE08DAD5A1C76737E15A99C456
+:109DF000A54EE967764DE2BA077140912D4A88C9B0
+:109E0000C7B808531E360FE87935D028FB705C6D53
+:109E1000D2E419EC7E079357B78FEB99BC1F4040F3
+:109E200079F5072CD108E27071CFFD25CC8E81BD6C
+:109E3000666076BC0ED2028E23C5A311170D153CA9
+:109E40001F0DFB7F424EC8A55164F718F98579179D
+:109E5000B6A4E459F38E4608A2BD4D05A00A4232CD
+:109E6000BF8C7C33F2CCC82F23DFEA205E07A5002D
+:109E7000E61DE7D78298E483866C683F66BF31DED3
+:109E80004DBA1ECB757F203E8CA78CEF27F5FC3397
+:109E900078CB58277924F797BABFEAAB62B33A7CFC
+:109EA000C9FDC6BD881B3B47FEB9D74EFBC5C9FDE2
+:109EB0009D6CBF785D7E37E9F95D2D0D6FCD433C1C
+:109EC0003B8F0AAA05973A779E2A7E88F2FD48A61C
+:109ED0004A517BB9F5D086422FF14AB42494C2731B
+:109EE0002D9FFA599EAFFE7411CFF7D8CDF3BDBCAC
+:109EF0005C3BA156A6C4EFE34766137FA2FD31E2A7
+:109F00008D778E9CFCF39D6EC68FE6D0DCA43DABB6
+:109F10007A07195FAED8E10C489C2F7B892F4D3A08
+:109F20000E4D5BB8DF00FD364B48FAB7718B10A4BD
+:109F3000786CEA5A18953C493FA7F367BA3F0D3F42
+:109F40001BFEAC9BAC07BBAB53EBC1247E8A819F4D
+:109F50006F5B01DE3731C2F19BD86106CAE38961CC
+:109F60004714F0FECB9DCFFE6919EEFB50886E289A
+:109F700094AEC70F2A387E343E88F8C1B49BE217EE
+:109F80005753F8ECC19FEBF879473EFE1DF143872C
+:109F9000451DC27B9BF0DFED68DFE5E1C7CD45B82D
+:109FA000FE408BE0247D2FAB1E1E772383662FDAC5
+:109FB000D3D4EE57208BD6F5BA97168FC69C78E38C
+:109FC00028DEB3A923230BE6D339A74B9987A6F93B
+:109FD000C5EB78C0D0EB4247E38F01BF5FC8E0F12B
+:109FE000D78AE78F313F074A4C8C272D01E207C8FB
+:109FF00019394AFE69D8E80BF479D8BDAF08A8B77B
+:10A00000CDCFFD5A56168F927EE86FC8C07519796C
+:10A01000C48AE390C8EDF34A7CFCA96DE496F69BF4
+:10A02000E4D9641D6E8D5F217DCA00FD1FE0A3038E
+:10A03000ED0BF8B9DD38873CBE1ECB0B4CCD0F7D48
+:10A04000E5AB2088FA9A31CE289ED2F9C19097CEFE
+:10A0500013F5A2C8F2B12873E4D7140F451B6F0D96
+:10A06000501D976DD04BF6CC99C2DEA9F436F4BDE5
+:10A07000E0E1B84FE2814177BB2B6987A10F94A340
+:10A080001E786FC30FE60EF6E155177AD412C26B35
+:10A090002A3B2F7834964F894250876E6267BA7D8B
+:10A0A00050DECFF2A221DFAD523F63E44533F10A27
+:10A0B000B0BCC88EA39E13FDA5D9C4DB1704AC07A2
+:10A0C000A47F4786C8E244B7E370376E461B7ED54F
+:10A0D0006D65E36FBA31B1E6000C7717B0F96FBB6D
+:10A0E000DD6C1CE92E67EBDFF6BB186E007107F51F
+:10A0F0005DF536BDCF8B01CBBBB1AE5266AFB15E65
+:10A10000E3E2F158EF8A3BA8AE24364BAC9EBED7B3
+:10A11000CEEB4D2BCAA17C81AE523884575DB82B53
+:10A12000EEB8C3D897D22F8E297107D5DD4D667E44
+:10A130000F38E4E82181FA8FA57223AEAFE87AD315
+:10A140002CE0B85CF7EBCCD291607E0EEBBF587F71
+:10A150001071A805A44FC4A916A4D6EF4CFB32D9A0
+:10A160004DF87862650AEDF76730FCC7ECCB965086
+:10A17000DF35B6CF498C079B0475AC0BF582AD1665
+:10A18000F5100E3522F40A2C1E627211E9DB233021
+:10A190001E30D68F956B6BFDB9D40F1FFDE46DD6C5
+:10A1A0005764AAA4077C86F7623F7C2B099558FE6A
+:10A1B00005218507A99F13707E50C6FA4604A205A3
+:10A1C00045EA9F3BF57A41EE67739DFF66CAEE3321
+:10A1D0008F92FC572518E27CF8179AB7BC6A064B99
+:10A1E0004A5CACD1E3A265F0BE3C8A87E67D12E30F
+:10A1F000BD161CA96E1CA08F4881DB06BE9147715D
+:10A20000D3BCBBFA8930D683120142C44725E6E0AD
+:10A210003DC41B9706E7387B52FAA17351CBDDD4BE
+:10A22000FF5C1A7CF6B58578EFC72772FD8CA7C353
+:10A2300022AB037DE5392C1EFAFCBCFE75C8DC4E52
+:10A24000D3A6C630B07E7E2968A4CFE0A32580F7D0
+:10A2500035B74566D3786930A396F87FB1B274B14B
+:10A2600013E5AEFE99D34F75E85CABC4FCBFEEF5C9
+:10A270005943C40707FDBC0EB77E7EEAA082FD40AD
+:10A280000BAE2978EF3F4732A361FCD4DA7DA244BC
+:10A29000C2ABCD166DBF1FE362BD38BA8CFADE7556
+:10A2A00007064B80ED77E72B5FC26317313FDC1861
+:10A2B000FF6D3F7C8BC9F9483C7D4F1D9E6F6D7BC8
+:10A2C0003A8BE4ACDFF3E64205D73F99A51D22F9AE
+:10A2D0001F0A8387150260DFE0BC10C32F7898E265
+:10A2E000609D0979DD77A3FCE1F93C5E6B5CA165BB
+:10A2F000750B981FD5D4B84F1FD79C1098DF8CF9D9
+:10A300008A68B60CD4C7C64056C80F12C89467E115
+:10A3100088201EF224FB114D01D6B73EA7E7C7A542
+:10A32000ECFE12CA87B587F79650FC7FE0E0F3FA9F
+:10A33000C3F7FF81F850FB8545A638D14C20AB7898
+:10A34000AE29CCFB5C5883C15998BCFF657F26C3FE
+:10A350007FEDBE8AEBEA27F613EC9E0F4C7037D9DF
+:10A360003D53BAE2A7BEE99C29D6427171AE3D4386
+:10A370000D33FFF17838D72F2DA1F5F02601A89FD6
+:10A3800038D7FFB4A38CF5EDC0E2778332C96BF9FF
+:10A3900071D6E7B9F73E403CF04733E38D4CDFD947
+:10A3A000A084F3B6E31E167F861EDAF1E7597EAF6E
+:10A3B000D3FBA456534C267FAF3B7E54A6BEB67546
+:10A3C00098F719EB879F978987369CD0FB0CFDDDAA
+:10A3D000DA063CCF361CE7F6B71D3F2F37A5F6F956
+:10A3E000E5AE6D45D8A9BD7FD456BB07F735927F42
+:10A3F000EE449346266A7BB028E4AA0AE74B5382D0
+:10A40000F56F7DE56FB0F76BDB165D5EF91BDBBCAE
+:10A410004C6FBF5948F1FB25BF99E1629C6F3BCE61
+:10A42000DFBD5733B2E6116F7659F9F8902D6B887E
+:10A43000C6AB1925AC8E6956ED2AC55BB80AEF2468
+:10A440003CC71CECFD9ABBFE7BF3C1CB8C617AFC54
+:10A450008DDEC537897BCD7AD76714C7A37A7D8B0C
+:10A46000B5D97AA9FF086EB09B688CB4D9593F1250
+:10A47000EC782383FAB4D18F6DA2904521913825D1
+:10A48000A23FA57C4D0EE0FDF980D98740CE80111A
+:10A4900081F26CFCB9F72B48FFF1E2C418A049E641
+:10A4A0001E53DD628CA3AC80C2EBA52F5E41F992F6
+:10A4B000FB02AF1B4F9AA197EA2F9842702FAEC7AD
+:10A4C00004DD9E6B6294E27A54883D45F243167B2C
+:10A4D000AF07F5A90E701EB0978672E9FE90579AE5
+:10A4E000EBA77BCDF65E01F129D6DF43F2F4023B08
+:10A4F000E114D171148241E8C27B44E1C526E295A2
+:10A50000ED092BD07BBC78FADDAC4E46745C057748
+:10A510000E7B1BBDE013C316D4633B58A3B44F1688
+:10A520003382B44F187DF99A80639174E554367E76
+:10A530002F7A485023A872C3C445D6CF8E5D1BCE58
+:10A5400020FC17E56BB70510DFE9527CEE2E54793D
+:10A55000BBA2BEA591BC9055ED71F318B762BC5774
+:10A56000F15F6174F3B52C179EAF4AD8CE13CEE3DA
+:10A57000898B479E5D40A355A578A91A9562967967
+:10A5800074A83A182FE767BE607E86A07561520EE8
+:10A59000F4EF05CAA38D7A1D31E44D757EBCC06D04
+:10A5A00022BF812F91B50BEF8B8C4A0ABD9BAB4626
+:10A5B0004FBD45765659ED31298BCE99FF11B7A67F
+:10A5C000DC7BB6D879F13656DAE00B6C5EF222DC31
+:10A5D0009F5FCBBEFE7D581BE0F5A056F79BE10FB9
+:10A5E000700721B5DE19F81B3CB071B20EBACF105E
+:10A5F0006E6F63DD23BD2646B1CFB909BF1AE39B59
+:10A60000D4E760FFD25016AC0D5426E3223D0ED2A3
+:10A61000FD6DF815BE7FF6C56C0FF3E7DC5DC0EA93
+:10A62000F3936704E6CF668AB7039F0EF9C9CF118B
+:10A63000C7128FE6FBFFF3A3C13B9A0DC7F95FC2B8
+:10A640003F361CE7DDC83F57C5906D8E87F1531F1D
+:10A65000E1857CF122F14501B4339EF80ABCB48B4C
+:10A66000CE2DA222CCFA3A314A7DE45AEBB7F6BF9E
+:10A67000378D78023B0EB2AFAB384AEF9A4533DDE7
+:10A680003D26DAF708F0BECBC4F58974DDC6BF4BB2
+:10A690000297B3598A52BFF78119F901E7E19E3950
+:10A6A000ACAF643F388F848BA2D4BF50FF4D7D7B0D
+:10A6B000C4C4D7C3ADC0F645A262785636FBCEFA05
+:10A6C00072CA7966773B309E9ABC77D36C26C7C82E
+:10A6D000072DBBF31EC2491BE7FCF94CC0A9D78963
+:10A6E0007825F5D5DB7FE4008A4FC3FFD3418F7B0C
+:10A6F000DDFF92EEFFE93EEEFFE9763166213FAEE7
+:10A70000591C4CF56382381471FBEE5FBFB9DF8AC8
+:10A71000F393068F3E2731FD0796060B6D3934E61D
+:10A7200089D42F3DF3F953FB57132EDFB133DCA44B
+:10A7300082FBF63723BE037E6EF740DD6CD6578D65
+:10A74000893A5ECB6D5C8E43647207D6DAA24073A1
+:10A750000FBF67609697ED47BFCDDE4772975A9956
+:10A76000DC14BFB17DE36B66E87EE3F724763A98AC
+:10A770005F92DFBD0C3FF41BC30FFD557B8CF507CB
+:10A7800089ACA573937132AEF71BE3BA5F26D7018C
+:10A79000D769BF299195FAF7E2A9D63BF3B4772997
+:10A7A000DE8CEF03CE6021F54FE9F8EFE9F1F7CE4B
+:10A7B000261C1CA242EF82A9FC66F829F37EF92030
+:10A7C000F52B93FE0AF338CC8C2C62F63F61F80728
+:10A7D000E392C54F9A3F61068F0FE3BD30337C7E15
+:10A7E0003FAFEBF15BA87E62DE95D33B738CF86DD7
+:10A7F0007E326E05A4D52E57328F8D7835786EAAAD
+:10A800007C16BA90FFB26E96CF237A7D8778662940
+:10A81000CB6B7305EA23896A8185E5F3D942D2E7D8
+:10A820002BE4B58DCEE5E8BCF25EBE96C5E79C474D
+:10A830000E88513FDD83F1B686FF1D1FA30BF17F0C
+:10A8400057C77525F2D734DC575EA1FF7DEDE134A3
+:10A850001ED3FDD0A0EF7FF723CCB7F9493FAED48C
+:10A86000DF510D0F5BCE131F363C6CE67EE9AA0E5E
+:10A87000A6C9617C6EC801F7955CB2CB38B772EDA2
+:10A88000BF72A9CF9CF27C7C86F362A6CEA768B784
+:10A890004F0EDD5A514976C51D2AE277FADF12FBC9
+:10A8A0007F8AF3E81F77368D255137CAA9A8E0F5CE
+:10A8B00071A7450B54307EA8BAEEFD77DAFFFE2C67
+:10A8C0007A3FC167A766903E3BF24295B4EFB1B2C2
+:10A8D0000999D65742FC4901E58FD57D584CFAAD10
+:10A8E000EC7A99F1FE4A83F7FF0B5EE93819F825F7
+:10A8F000ED9EC8A53EFA7F859B1137FF01F8EF3F1B
+:10A90000E3801A00000000000000000000000000CA
+:10A9100000000040000000000000000000000040B7
+:10A9200000000000000000000000002800000000FF
+:10A930000000000000000010000000000000000007
+:10A9400000000040000000000000000000000010B7
+:10A9500000000000000000000000000800000000EF
+:10A9600000000000000000000000000000000000E7
+:10A9700000000000000000000000000000000000D7
+:10A9800000000000000000000000000000000000C7
+:10A9900000000000000000000000000000000000B7
+:10A9A00000000000000000000000000000000000A7
+:10A9B0000000000000000000000000000000000097
+:10A9C0000000000000000000000000000000000087
+:10A9D0000000000000000000000000000000000077
+:10A9E0000000000000000000000000000000000067
+:10A9F0000000000000000000000000000000000057
+:10AA00000000000000000000000000000000000046
+:10AA10000000000000000000000000000000000036
+:10AA20000000000000000000000000000000000026
+:10AA30000000000000000000000000000000000016
+:10AA40000000000000000000000000000000000006
+:10AA500000000000000000000000000000000000F6
+:10AA600000000000000000000000000000000000E6
+:10AA70000000000000000000000090000010000036
+:10AA80000000000800009008001000000000000214
+:10AA90000000900000100000000000108000000086
+:10AAA0000000000000000000800000000000000026
+:10AAB0000000000080000000000000000000000016
+:10AAC000800000000000000000000000000093B8BB
+:10AAD0000001000400000001000093C0000000001D
+:10AAE00000000002000093C8000000000000000801
+:10AAF000000093CC0000000000000002000093D092
+:10AB00000000000000000008000097200040000046
+:10AB100000000040000093E00080000000000048BA
+:10AB2000000094E00040000000000008000094F0E5
+:10AB300000400000000000180000A00000280000F5
+:10AB4000000000280000C0C0000800000000000154
+:10AB50000000C0C100080000000000010000C0C2E9
+:10AB600000080000000000010000200800100000A4
+:10AB7000000000100000200000000000000000089D
+:10AB80008000000000000000000000000000000045
+:10AB900000000000000000000000000000000000B5
+:10ABA00000000000000000000000000000000000A5
+:10ABB0000000000000000000000000000000000095
+:10ABC0000000000000000000000000000000000085
+:10ABD0000000000000000000000000000000000075
+:10ABE0000000000000000000000000000000000065
+:10ABF0000000000000000000000000000000000055
+:10AC00000000000000000000000000000000000044
+:10AC10000000000000000000000000000000000034
+:10AC20000000000000000000000000000000000024
+:10AC30000000000000000000000000000000000014
+:10AC40008000000000000000000000008000000004
+:10AC50000000000000000000800000000000000074
+:10AC60000000000080000000000000000000000064
+:10AC700080000000000000000000000080000000D4
+:10AC80000000000000000000800000000000000044
+:10AC90000000000080000000000000000000000034
+:10ACA00080000000000000000000000080000000A4
+:10ACB0000000000000000000800000000000000014
+:10ACC0000000000080000000000000000000000004
+:10ACD0000000000000000000000000000000000074
+:10ACE0000000000000000000000000000000000064
+:10ACF0000000000000000000000000000000000054
+:10AD000000000000000000000000000080000000C3
+:10AD100000000000000000008000000000000000B3
+:10AD200000000000800000000000000000000000A3
+:10AD30000000000000000000000000008000000093
+:10AD40000000000000000000800000000000000083
+:10AD50000000000080000000000000000000000073
+:10AD600000000000000000000000000000000000E3
+:10AD700000000000000000000000000000000000D3
+:10AD800000000000000000000000000000000000C3
+:10AD900000000000000000000000000000000000B3
+:10ADA0000000000000000000800000000000000023
+:10ADB0000000000000000000000000000000000093
+:10ADC00000001EC80000000000000008000020086D
+:10ADD0000010000000000010000020000000000033
+:10ADE00000000008800000000000000000000000DB
+:10ADF00080000000000000000000000000000000D3
+:10AE00000000000000000000000000000000000042
+:10AE1000000000000000A080000800000000000109
+:10AE20000000A08100080000000000010000A082D6
+:10AE300000080000000000010000907000380000D1
+:10AE40000000003800001ED80000000000000002D2
+:10AE500000001EDA00000000000000028000000078
+:10AE60000000000000000000800000000000000062
+:10AE70000000000080000000000000000000000052
+:10AE800080000000000000000000000080000000C2
+:10AE90000000000000000000800000000000000032
+:10AEA0000000000080000000000000000000000022
+:10AEB0008000000000000000000000008000000092
+:10AEC0000000000000000000000000000000000082
+:10AED0000000000000000000000000000000000072
+:10AEE0000000000000000000000000000000000062
+:10AEF0000000000000000000000000000000000052
+:10AF000000000000800000000000000000000000C1
+:10AF100080000000000000000000000000000000B1
+:10AF200000000000000000008000000000000000A1
+:10AF30000000000080000000000000000000000091
+:10AF40008000000000000000000000008000000001
+:10AF50000000000000000000800000000000000071
+:10AF60000000000080000000000000000000000061
+:10AF70000000C00000400000000000400000C800C9
+:10AF800000400000000000400000C82E004000000B
+:10AF9000000000010000C8000040000200000001A5
+:10AFA0000000C80100400002000000000000800016
+:10AFB0000040000000000040800000000000000091
+:10AFC00000000000000080000008004000000004B5
+:10AFD0000000800400080040000000040000B000F1
+:10AFE00000280000000000280000B1400010000010
+:10AFF000000000100000B14A001000000000000135
+:10B000000000880000800000000000800000880030
+:10B01000000800800000000200008C0000400000DA
+:10B020000000004000002008001000000000001098
+:10B030000000200000000000000000080000125086
+:10B04000000800000000000100001251000800008C
+:10B050000000000100001252000800000000000182
+:10B0600000008E0000100004000000040000129098
+:10B070000030001800000010000012980030001886
+:10B08000000000028000000000000000000000003E
+:10B0900080000000000000000000000080000000B0
+:10B0A0000000000000000000800000000000000020
+:10B0B0000000000080000000000000000000000010
+:10B0C0008000000000000000000000008000000080
+:10B0D0000000000000000000000000000000000070
+:10B0E0000000000000000000000000000000000060
+:10B0F0000000000000000000000000000000000050
+:10B1000000000000000000008000000000000000BF
+:10B1100000000000800000000000000000000000AF
+:10B12000000000000000000000000000800000009F
+:10B13000000000000000000080000000000000008F
+:10B14000000000008000000000000000000000007F
+:10B1500080000000000000000000000080000000EF
+:10B1600000000000000000000000830800800000D4
+:10B17000000000800000000100000000000000004E
+:10B180000000200800100000000000100000200057
+:10B19000000000000000000800008500000800001A
+:10B1A000000000010000850100080000000000010F
+:10B1B000000085020008000000000001000060009F
+:10B1C000003800000000003880000000000000008F
+:10B1D000000000000000845400080000000000028D
+:10B1E0000000845600080000000000020000846493
+:10B1F00000100000000000048000000000000000BB
+:10B2000000000000800000000000000000000000BE
+:10B2100080000000000000000000000000000000AE
+:10B22000000000000000000000000000000000001E
+:10B23000000000000000000000000000000000000E
+:10B24000000000000000000000000000800000007E
+:10B25000000000000000000080000000000000006E
+:10B2600000000000000000000000000000000000DE
+:10B2700080000000000000000000000080000000CE
+:10B28000000000000000000080000000000000003E
+:10B29000000000008000000000000000000000002E
+:10B2A00080000000000000000000000000003000EE
+:10B2B00000400000000000080000300800400000CE
+:10B2C00000000020000032000020000000000020EC
+:10B2D000000037A800000000000000088000000007
+:10B2E00000000000000000008000000000000000DE
+:10B2F00000000000800000000000000000000000CE
+:10B300000000A000000000000000200000003EC17E
+:10B31000000000000000000100003EE0000000000E
+:10B320000000000200001E0000E00008000000080D
+:10B33000800000000000000000000000000040004D
+:10B3400000080000000000010000400100080000AB
+:10B35000000000010000404000080004000000025E
+:10B3600000004060000800040000000480000000AD
+:10B370000000000000000000000040000008000085
+:10B380000000000400004004000800000000000469
+:10B39000000040400000000000000008000040489D
+:10B3A0000000000000000008000080000000000015
+:10B3B00000000010000050400001000400000001E7
+:10B3C00000005000000000000000002000005008B5
+:10B3D00000100000000000040000500C00100000ED
+:10B3E00000000001000052C7000000000000000142
+:10B3F000000052C600000000000000010000300004
+:10B400000040002000000004000030040040002044
+:10B41000000000040000300800400020000000028E
+:10B420000000300A00400020000000020000300C44
+:10B4300000400020000000010000300D004000200E
+:10B44000000000010000300E00400020000000015C
+:10B450000000301000400020000000040000301404
+:10B4600000400020000000040000301800400020D0
+:10B47000000000040000301C004000200000000418
+:10B48000000050000100008000080004000050048B
+:10B4900001000080000800040000000A0000000015
+:10B4A0000000000000005068010000800000000162
+:10B4B0000000506901000080000000010000506C95
+:10B4C00001000080000000020000506E01000080BA
+:10B4D0000000000200005070010000800000000425
+:10B4E000000050740100008000000004000050665D
+:10B4F0000100008000000002000050640100008094
+:10B500000000000100005060010000800000000207
+:10B510000000506201000080000000020000505056
+:10B520000100008000000004000050540100008071
+:10B5300000000004000050580100008000000004DA
+:10B540000000505C01000080000000040000507CFE
+:10B5500001000080000000010000507D010000801B
+:10B56000000000010000401800100000000000046E
+:10B57000000040900010000000000004000040980F
+:10B580000010000000000004000041100000000056
+:10B590000000000200004112000000000000000254
+:10B5A00000004114000000000000000200004116ED
+:10B5B00000000000000000020000604000080000E1
+:10B5C00000000002000060420008000000000002CD
+:10B5D0000000604400080000000000020000604617
+:10B5E0000008000000000002000060800008000069
+:10B5F00000000008000060000008000000000002D9
+:10B60000000060020008000000000001000060046B
+:10B610000008000000000002000060C000080000F8
+:10B6200000000008000061000008000000000004A5
+:10B6300000006104000800000000000100006140FB
+:10B640000008000000000002000061440008000043
+:10B65000000000020000614200080000000000023B
+:10B66000000061800008000000000004000070007D
+:10B670000008000000000002000070020008000046
+:10B68000000000010000700400080000000000023B
+:10B69000000070400008000000000002000070443C
+:10B6A00000080000000000020000704600080000D2
+:10B6B00000000002000076600008000000000008A2
+:10B6C000000070800008000000000002000070848C
+:10B6D0000008000000000002000076A00008000042
+:10B6E0000000000800008040000800000000000189
+:10B6F00000008041000800000000000100008042BE
+:10B700000008000000000001000080430008000065
+:10B71000000000010000800000080000000000029E
+:10B72000000080020008000000000001000080040A
+:10B730000008000000000002000080C000080000B7
+:10B7400000000002000080C20008000000000002AB
+:10B75000000080C40008000000000002000080809B
+:10B7600000080000000000010000808100080000C7
+:10B7700000000001000080820008000000000001BD
+:10B7800000008083000800000000000100008084A9
+:10B790000008000000000001000080850008000093
+:10B7A0000000000100008086000800000000000189
+:10B7B00000006000000800000000000200006002BD
+:10B7C0000008000000000001000060040008000004
+:10B7D000000000020000604200C0001800000002EB
+:10B7E0000000604000C00018000000020000604C33
+:10B7F00000C00018000000080000604400C00018ED
+:10B80000000000080000605700C0001800000001A0
+:10B810000000605400C000180000000200006056E4
+:10B8200000C0001800000001000066400008000091
+:10B83000000000080000668000080000000000080A
+:10B84000000066C000080000000000088000000042
+:10B850000000000000000000800000000000000068
+:10B860000000000080000000000000000000000058
+:10B8700080000000000000000000000080000000C8
+:10B880000000000000000000800000000000000038
+:10B890000000000080000000000000000000000028
+:10B8A0008000000000000000000000008000000098
+:10B8B0000000000000000000800000000000000008
+:10B8C00000000000800000000000000000000000F8
+:10B8D0008000000000000000000000008000000068
+:10B8E00000000000000000008000000000000000D8
+:10B8F00000000000800000000000000000000000C8
+:10B900008000000000000000000000008000000037
+:10B9100000000000000000008000000000000000A7
+:10B920000000000080000000000000000000000097
+:10B930008000000000000000000000008000000007
+:10B940000000000000000000800000000000000077
+:10B950000000000080000000000000000000000067
+:10B9600080000000000000000000000080000000D7
+:10B970000000000000000000800000000000000047
+:10B980000000000080000000000000000000000037
+:10B9900080000000000000000000000080000000A7
+:10B9A0000000000000000000800000000000000017
+:10B9B0000000000080000000000000000000000007
+:10B9C0008000000000000000000000008000000077
+:10B9D00000000000000000008000000000000000E7
+:10B9E00000000000800000000000000000000000D7
+:10B9F0008000000000000000000000008000000047
+:10BA000000000000000000008000000000000000B6
+:10BA100000000000800000000000000000000000A6
+:10BA20008000000000000000000000008000000016
+:10BA30000000000000000000800000000000000086
+:10BA40000000000080000000000000000000000076
+:10BA500080000000000000000000000080000000E6
+:10BA60000000000000000000800000000000000056
+:10BA70000000000080000000000000000000000046
+:10BA800080000000000000000000000080000000B6
+:10BA90000000000000000000800000000000000026
+:10BAA0000000000080000000000000000000000016
+:10BAB0008000000000000000000000008000000086
+:10BAC00000000000000000008000000000000000F6
+:10BAD00000000000800000000000000000000000E6
+:10BAE0008000000000000000000000008000000056
+:10BAF00000000000000000008000000000000000C6
+:10BB00000000000000000000000000000000000035
+:10BB100080000000000000000000000000000000A5
+:08BB2000070C1E0000000000EC
+:00000001FF
--- linux-4.4.0.orig/firmware/bnx2x/bnx2x-e2-7.12.30.0.fw.ihex
+++ linux-4.4.0/firmware/bnx2x/bnx2x-e2-7.12.30.0.fw.ihex
@@ -0,0 +1,20088 @@
+:10000000000037E000000068000005D8000038500C
+:100010000000556400003E300000009000009398FE
+:100020000000F43000009430000000C40001886833
+:1000300000015EC800018930000000700002E80085
+:10004000000055CC0002E878000000AC00033E48F8
+:100050000001961400033EF80000120C0004D510B5
+:10006000000000040004E720021100B800000001B5
+:10007000020600DC000000010206005000000180C2
+:100080000306100001FF00000A0000010000000844
+:10009000020617FC003FE0010A000001000000100A
+:1000A000030617FC020101FF0A000001000000081E
+:1000B00003060200000304000A0000010000001013
+:1000C00003060200000304030A00000100002000F0
+:1000D0000406024C000000020A0000040000202078
+:1000E000030601E000040406030602440002040AB9
+:1000F000030602540002040C030602640002040E0C
+:100100000A00000300002040030601E00004041080
+:1001100003060240000304140206026400000028E3
+:10012000020600DC000000000A00000100000008D8
+:10013000030601D8000204170A0000020000202074
+:10014000030601C000020419030601D00004041BC9
+:100150000A00000200002040030601C00002041F44
+:10016000030601D0000404210A0000020000204020
+:1001700003060220000204250306023000040427BF
+:10018000020D004400000032030D004C0004042B5B
+:10019000040D005C00000004030D008C0004042F1B
+:1001A000030D00A000050433020D00B8000000029A
+:1001B000030D00C000040438020D015C00000001C2
+:1001C000030D01640002043C020D02040000000162
+:1001D000030D020C0003043E030D02200002044143
+:1001E000040D028000000012030D030000180443F8
+:1001F000040D400000000A000A0000010000000891
+:10020000040D03600000000C030D0004000F045BEC
+:10021000020D01140000000D020D01180000002D58
+:10022000020D01140000001D020D01180000003D28
+:10023000020D01140000004D020D01180000006DB8
+:10024000020D01140000005D020D01180000007D88
+:10025000031010000003046A021010500000000197
+:10026000071011000010046D081011400000000874
+:10027000071011600010047D081011A00000001884
+:10028000071018000200048D04104C00000001004B
+:1002900002107004000000010A00000100000008C4
+:1002A000031040D40002068D021040280000001008
+:1002B000031040400002068F021040580028000042
+:1002C000021040840084924A02104058000000004E
+:1002D0000210413800000001021041380000000106
+:1002E00002104138000000010210413800000001F6
+:1002F00002104138000000010210413800000001E6
+:1003000002104138000000010210413800000001D5
+:10031000030C200800030691030C201C0004069423
+:10032000030C203800040698040C20480000001D2F
+:10033000020C20BC00000001040C20C00000003FA3
+:10034000030C21BC0003069C040C21C80000001C07
+:10035000030C22380004069F010C22480000000014
+:10036000010C224C00000000010C22500000000093
+:10037000010C225400000000010C22580000000073
+:10038000010C225C00000000010C22600000000053
+:10039000010C226400000000010C22680000000033
+:1003A000010C226C00000000010C22700000000013
+:1003B000010C227400000000010C227800000000F3
+:1003C000010C227C00000000030C22D8000406A3CC
+:1003D0000A00000100000009020C2000000003E8F0
+:1003E0000A0000010000000A020C200000000003C7
+:1003F0000A0000010000000C020C200000000001B7
+:100400000A00000100001001020C2000000005DCC1
+:100410000A00000100001002020C2000000000048D
+:100420000A00000100001004020C2000000000017E
+:100430000A00000100002001020C2000000005DC81
+:100440000A00000100002002020C2000000000044D
+:100450000A00000100002004020C2000000000013E
+:10046000052004000070000006200780001006A789
+:1004700004220000000040000423240000001600B5
+:1004800003221170000806A9032211A8009006B1EA
+:100490000422C000000000060322C0180004074127
+:1004A0000422C0280000000C0322C05800040745A5
+:1004B0000422C0680000000C0322C0980004074911
+:1004C0000422C0A80000000C0322C0D80004074D7D
+:1004D0000422C0E80000000C0322C11800040751E8
+:1004E0000422C1280000000C0322C1580004075553
+:1004F0000422C1680000000C0322C19800040759BF
+:100500000422C1A80000000C0322C1D80004075D2A
+:100510000422C1E80000000C0322C2180004076195
+:100520000422C2280000000C0322C2580004076500
+:100530000422C2680000000C0322C298000407696C
+:100540000422C2A80000000C0322C2D80004076DD8
+:100550000422C2E80000000C0322C3180004077143
+:100560000422C3280000000C0322C35800040775AE
+:100570000422C3680000000C0322C398000407791A
+:100580000422C3A80000000C0322C3D80004077D86
+:100590000422C3E80000000C0322C41800040781F1
+:1005A0000422C4280000000C0322C458000407855C
+:1005B0000422C4680000000C0322C49800040789C8
+:1005C0000422C4A80000000C0322C4D80004078D34
+:1005D0000422C4E80000000C0322C518000407919F
+:1005E0000422C5280000000C0322C558000407950A
+:1005F0000422C5680000000C0322C5980004079976
+:100600000422C5A80000000C0322C5D80004079DE1
+:100610000422C5E80000000C0322C618000407A14C
+:100620000422C6280000000C0322C658000407A5B7
+:100630000422C6680000000C0322C698000407A923
+:100640000422C6A80000000C0322C6D8000407AD8F
+:100650000422C6E80000000C0322C718000407B1FA
+:100660000422C7280000000C0322C758000407B565
+:100670000422C7680000000C0322C798000407B9D1
+:100680000422C7A80000000C0322C7D8000407BD3D
+:100690000422C7E80000000C0322C818000407C1A8
+:1006A0000422C8280000000C0322C858000407C513
+:1006B0000422C8680000000C0322C898000407C97F
+:1006C0000422C8A80000000C0322C8D8000407CDEB
+:1006D0000422C8E80000000C0322C918000407D156
+:1006E0000422C9280000000C0322C958000407D5C1
+:1006F0000422C9680000000C0322C998000407D92D
+:100700000422C9A80000000C0322C9D8000407DD98
+:100710000422C9E80000000C0322CA18000407E103
+:100720000422CA280000000C0322CA58000407E56E
+:100730000422CA680000000C0322CA98000407E9DA
+:100740000422CAA80000000C0322CAD8000407ED46
+:100750000422CAE80000000C0322CB18000407F1B1
+:100760000422CB280000000C0322CB58000407F51C
+:100770000422CB680000000C0322CB98000407F988
+:100780000422CBA80000000C0322CBD8000407FDF4
+:100790000422CBE80000000C0322CC18000408015E
+:1007A0000422CC280000000C0322CC5800040805C9
+:1007B0000422CC680000000C0322CC980004080935
+:1007C0000422CCA80000000C0322CCD80004080DA1
+:1007D0000422CCE80000000C0322CD18000408110C
+:1007E0000422CD280000000C0322CD580004081577
+:1007F0000422CD680000000C0322CD9800040819E3
+:100800000422CDA80000000C0322CDD80004081D4E
+:100810000422CDE80000000C0322CE1800040821B9
+:100820000422CE280000000C0322CE580004082524
+:100830000422CE680000000C0322CE980004082990
+:100840000422CEA80000000C0322CED80004082DFC
+:100850000422CEE80000000C0322CF180004083167
+:100860000422CF280000000C0322CF5800040835D2
+:100870000422CF680000000C0322CF98000408393E
+:100880000422CFA80000000C0322CFD80004083DAA
+:100890000422CFE80000000C0322D0180004084115
+:1008A0000422D0280000000C0322D0580004084580
+:1008B0000422D0680000000C0322D09800040849EC
+:1008C0000422D0A80000000C0322D0D80004084D58
+:1008D0000422D0E80000000C0322D11800040851C3
+:1008E0000422D1280000000C0322D158000408552E
+:1008F0000422D1680000000C0322D198000408599A
+:100900000422D1A80000000C0322D1D80004085D05
+:100910000422D1E80000000C0322D2180004086170
+:100920000422D2280000000C0322D25800040865DB
+:100930000422D2680000000C0322D2980004086947
+:100940000422D2A80000000C0322D2D80004086DB3
+:100950000422D2E80000000C0322D318000408711E
+:100960000422D3280000000C0322D3580004087589
+:100970000422D3680000000C0322D39800040879F5
+:100980000422D3A80000000C0322D3D80004087D61
+:100990000422D3E80000000C0322D41800040881CC
+:1009A0000422D4280000000C0322D4580004088537
+:1009B0000422D4680000000C0322D49800040889A3
+:1009C0000422D4A80000000C0322D4D80004088D0F
+:1009D0000422D4E80000000C0322D518000408917A
+:1009E0000422D5280000000C0322D55800040895E5
+:1009F0000422D5680000000C0322D5980004089951
+:100A00000422D5A80000000C0322D5D80004089DBC
+:100A10000422D5E80000000C0322D618000408A127
+:100A20000422D6280000000C0322D658000408A592
+:100A30000422D6680000000C0322D698000408A9FE
+:100A40000422D6A80000000C0322D6D8000408AD6A
+:100A50000422D6E80000000C0322D718000408B1D5
+:100A60000422D7280000000C0322D758000408B540
+:100A70000422D7680000000C0322D798000408B9AC
+:100A80000422D7A80000000C0322D7D8000408BD18
+:100A90000422D7E80000000C0322D818000408C183
+:100AA0000422D8280000000C0322D858000408C5EE
+:100AB0000422D8680000000C0322D898000408C95A
+:100AC0000422D8A80000000C0322D8D8000408CDC6
+:100AD0000422D8E80000000C0322D918000408D131
+:100AE0000422D9280000000C0322D958000408D59C
+:100AF0000422D9680000000C0322D998000408D908
+:100B00000422D9A80000000C0322D9D8000408DD73
+:100B10000422D9E80000000C0322DA18000408E1DE
+:100B20000422DA280000000C0322DA58000408E549
+:100B30000422DA680000000C0322DA98000408E9B5
+:100B40000422DAA80000000C0322DAD8000408ED21
+:100B50000422DAE80000000C0322DB18000408F18C
+:100B60000422DB280000000C0322DB58000408F5F7
+:100B70000422DB680000000C0322DB98000408F963
+:100B80000422DBA80000000C0322DBD8000408FDCF
+:100B90000422DBE80000000C0322DC180004090139
+:100BA0000422DC280000000C0322DC5800040905A4
+:100BB0000422DC680000000C0322DC980004090910
+:100BC0000422DCA80000000C0322DCD80004090D7C
+:100BD0000422DCE80000000C0322DD1800040911E7
+:100BE0000422DD280000000C0322DD580004091552
+:100BF0000422DD680000000C0322DD9800040919BE
+:100C00000422DDA80000000C0322DDD80004091D29
+:100C10000422DDE80000000C0322DE180004092194
+:100C20000422DE280000000C0322DE5800040925FF
+:100C30000422DE680000000C0322DE98000409296B
+:100C40000422DEA80000000C0322DED80004092DD7
+:100C50000422DEE80000000C0322DF180004093142
+:100C60000422DF280000000C0322DF5800040935AD
+:100C70000422DF680000000C0322DF980004093919
+:100C80000422DFA80000000C0322DFD80004093D85
+:100C90000422DFE80000000C0322E01800040941F0
+:100CA0000422E0280000000C0322E058000409455B
+:100CB0000422E0680000000C0322E09800040949C7
+:100CC0000422E0A80000000C0322E0D80004094D33
+:100CD0000422E0E80000000C0322E118000409519E
+:100CE0000422E1280000000C0322E1580004095509
+:100CF0000422E1680000000C0322E1980004095975
+:100D00000422E1A80000000C0322E1D80004095DE0
+:100D10000422E1E8000000060422F6400000002062
+:100D20000223800000000010022380400000001217
+:100D30000223808000000030022380C00000000EEB
+:100D400002238BC0000000010A000002000000081E
+:100D50000223838000086470022383C000000226FF
+:100D60000A000002000000090223830000086470EA
+:100D700002238340000002260A0000020000000A4D
+:100D8000022383000000055F02238340000000016E
+:100D90000A0000020000000C02238300000001573B
+:100DA00002238340000000000A000002000010003F
+:100DB00002238380000C96A8022383C0000003391D
+:100DC0000A0000020000100102238300000C96A814
+:100DD00002238340000003390A00000200001002D1
+:100DE000022383000000080E02238340000000025B
+:100DF0000A00000200001004022383000000020326
+:100E000002238340000000000A00000200002000CE
+:100E100002238380000CF850022383C00000035299
+:100E20000A0000020000200102238300000CF85099
+:100E300002238340000003520A0000020000200247
+:100E4000022383000000084D0223834000000002BB
+:100E50000A000002000020040223830000000213A5
+:100E600002238340000000000524000033580000E6
+:100E70000524800022710CD60624C670659809618D
+:100E80000A0000010000000202231480000000009C
+:100E90000A0000010000000402231480000000008A
+:100EA0000A0000010000001102231480000000006D
+:100EB0000A00000100000008022000BC000000320F
+:100EC0000A00000400000010022000BC0000000224
+:100ED00002238840000000010120013800000000CA
+:100EE00002238840000000000A00000100000011F9
+:100EF0000223148000000001012000000000000017
+:100F00000120000400000000012000080000000093
+:100F10000120000C00000000012000100000000073
+:100F2000012000140000000003200020001A0963C3
+:100F3000032000A40002097D02200224000000001A
+:100F400002200234000000000220024C00000000D9
+:100F5000022002E40000FFFF08202000000008003B
+:100F60000A000001000000100820400000000200FC
+:100F700004221108000000020422340000000002D4
+:100F800004225900000000060422604000000030E6
+:100F90000422F300000000100422111000000002DF
+:100FA0000422340800000002042259180000000640
+:100FB00004226100000000300422F3400000001011
+:100FC0000422111800000002042234100000000264
+:100FD0000422593000000006042261C000000030E5
+:100FE0000422F380000000100422112000000002FF
+:100FF00004223418000000020422594800000006B0
+:1010000004226280000000300422F3C000000010BF
+:1010100004221128000000020422342000000002F3
+:1010200004225960000000060422634000000030E2
+:101030000422F4000000001004221130000000021D
+:10104000042234280000000204225978000000061F
+:1010500004226400000000300422F440000000106C
+:101060000422113800000002042234300000000283
+:101070000422599000000006042264C000000030E1
+:101080000422F4800000001004221140000000023D
+:101090000422343800000002042259A8000000068F
+:1010A00004226580000000300422F4C0000000101B
+:1010B00004102400000000E00310201C0002097F3F
+:1010C000021020C000000002031020040002098169
+:1010D00002170008000000020217002C00000003A5
+:1010E00002170038007C100403170044000609832F
+:1010F000021700700000000C031700780002098935
+:10110000021701C408100000021703440000000188
+:10111000031704000008098B031704300008099323
+:10112000031704800004099B0A0000010000000866
+:101130000217003C000000040A000001000000103B
+:101140000217003C00000008021700040000000F16
+:10115000021701EC00000002021701F40000000277
+:10116000021701EC00000002021701F40000000267
+:10117000021701EC00000002021701F40000000257
+:10118000021701EC00000002021701F40000000247
+:10119000021701EC00000002021701F40000000237
+:1011A000021701EC00000002021701F40000000227
+:1011B000021701EC00000002021701F40000000217
+:1011C000021701EC00000002021701F40000000207
+:1011D0000A0000010000000802130078000000323D
+:1011E0000213003C000061A8041301080000000382
+:1011F000021301040000000002130134000000008B
+:1012000004130108000000030213010400000000A1
+:101210000213013400000000041301080000000361
+:10122000021301040000000002130134000000005A
+:101230000413010800000003021301040000000071
+:101240000213013400000000041301080000000331
+:10125000021301040000000002130134000000002A
+:101260000413010800000003021301040000000041
+:101270000213013400000000041301080000000301
+:1012800002130104000000000213013400000000FA
+:101290000413010800000003021301040000000011
+:1012A00002130134000000000A0000010000008861
+:1012B0000200A5F8000000000A000001000001087B
+:1012C0000200A5F8000000010A00000100000090E3
+:1012D0000200AA84000000000A00000100000110C2
+:1012E0000200AA84000000010A0000010000009032
+:1012F0000200AA88000000000A000001000001109E
+:101300000200AA88000000010200A2700000000094
+:101310000200A274000000000200A27000000000A1
+:101320000200A274000000000200A2700000000091
+:101330000200A274000000000200A2700000000081
+:101340000200A2740000000002016204000000001C
+:101350000A000001000022000401602C00000007C8
+:10136000030100B40002099F030100CC000209A19F
+:10137000020100DC0000000103010100000209A3DA
+:101380000201007C003000000201008400000028FF
+:101390000201008C00000000020101300000000486
+:1013A0000201032800000000020105540000003083
+:1013B000020160580000FFFF0201606000000000B1
+:1013C0000201607000000007020160B00000000030
+:1013D000020160C000000001020160C800000000BE
+:1013E00002016208000000000401805400000003B4
+:1013F0000201807800000000020180E80000000780
+:10140000030180F8000209A50301810C000209A76D
+:1014100002018124000000000A0000020000000810
+:10142000020180E400004688030180EC000209A963
+:101430000A00000100000080020180380000000660
+:101440000A000001000002000201803800000007CD
+:101450000A000001000004000201803800000006BC
+:101460000A00000100000800020180380000000EA0
+:101470000A00000400002000020180EC0000003897
+:1014800002018100000025E40201811400004BC824
+:1014900003018680000409AB020100C400000001C2
+:1014A000020100F800000001020100F0000000014C
+:1014B00002010080003000000201008800000028C6
+:1014C000020100900000000002010134000000044D
+:1014D0000201032C0000000002010564000000303E
+:1014E0000201605C0000FFFF020160640000000078
+:1014F0000201607400000007020160B400000000F7
+:10150000020160C400000001020160CC0000000084
+:101510000201620C00000000040181A80000000428
+:10152000020181D0000000000201823400000007A7
+:1015300003018244000209AF03018258000209B18D
+:101540000A00000200000008020182300000468804
+:1015500003018238000209B30A0000010000008084
+:101560000201818C000000060A0000010000020058
+:101570000201818C000000070A0000010000040045
+:101580000201818C000000060A0000010000080032
+:101590000201818C0000000E0A00000400002000FF
+:1015A00002018238000000380201824C000025E46C
+:1015B0000201826000004BC8030186E0000409B507
+:1015C000020100C800000001020100FC000000014F
+:1015D000020100F4000000010401013800000011C4
+:1015E0000401017C00000011040101380000001119
+:1015F0000401017C00000011040101380000001109
+:101600000401017C000000110401013800000011F8
+:101610000401017C000000110215C0900000892621
+:101620000215C09C000000040A0000010000220016
+:101630000415C07000000007021400000000000143
+:101640000215C024000000000315C0EC000209B917
+:101650000315C100000209BB0A00000100002000C0
+:101660000315C1F4000809BD03140030000209C5C8
+:1016700002140040000000010900000200001008F0
+:1016800003140004000309C7021400440000FFFF14
+:101690000A0000040000200003140038000209CAF8
+:1016A00002140044000FFFFF0315C160000709CCBE
+:1016B0000315C198000209D30900000100001008B9
+:1016C00004140004000000030A00000100002000D0
+:1016D0000415C160000000070214000000000000B3
+:1016E000020090C40000E000020090CC0000F30073
+:1016F000030090D4000209D5020090E000007300BE
+:10170000030090E8000209D7020090F40000730083
+:10171000030090FC000209D9020091080000530068
+:10172000020091100000000403009128000709DB6B
+:101730000300916C000609E2040091840000000699
+:101740000300919C000509E80300942C000309EDB7
+:101750000300942C000309F00300942C000309F308
+:101760000300942C000309F60300942C000309F9EC
+:101770000300942C000309FC0300942C000309FFD0
+:101780000300942C00030A020304000400120A055B
+:1017900002040054000000430204005C0000000644
+:1017A00002040070000000040304007800040A171B
+:1017B00004040088000000050304009C00030A1BC9
+:1017C000040400A800000004030400B800110A1E6D
+:1017D00001040124000000000104012800000000B1
+:1017E0000104012C00000000010401300000000091
+:1017F000020401340000000F030401D000020A2F8C
+:101800000204022C000000040304025800040A3100
+:101810000A00000100002200040401AC00000007DF
+:101820000312049400210A350212038800000064A8
+:1018300002120390000000080312039C00030A56E2
+:10184000031203BC00030A59021203D00000000077
+:101850000212036C00000001031201BC003C0A5C90
+:10186000031202B000020A980312032400020A9A2B
+:10187000021205B400000001031205F800030A9CDF
+:101880000212066C00000001021201B0000000010B
+:10189000021207D800000000021207D80000000062
+:1018A000021207D800000000021207D80000000052
+:1018B000021207D800000000021207D80000000042
+:1018C000021207D800000000021207D80000000032
+:1018D000021030D8000000010710380000050A9FF0
+:1018E0000710392000050AA407103B0000050AA9CB
+:1018F00007103C0000050AAE0316803000080AB34A
+:1019000002168054000000020416807C00000005CE
+:101910000316809000020ABB0316809C00020ABDD9
+:10192000021680AC00000054041680B800000005C8
+:10193000031680CC00080ABF021680F000000007E2
+:101940000316810000060AC70316812800030ACD8A
+:101950000316814000060AD00316816800030AD6E8
+:10196000031681A800030AD9031681E800030ADCE4
+:10197000031681F800030ADF0316820800070AE253
+:101980000316823400020AE904168278000000047B
+:101990000316828800060AEB021688102020010137
+:1019A000021688202020010102168838202001011B
+:1019B00002168848202001010316E6BC00020AF145
+:1019C0000A000014000000080316806000070AF3F4
+:1019D000041680A400000002041680B0000000027B
+:1019E000031680F400030AFA0316811800040AFDA6
+:1019F0000316813400030B010316815800040B0405
+:101A000003168174000D0B08031681B4000D0B152D
+:101A1000021681F4000001FC02168204000000039B
+:101A20000316823C000B0B2204168268000000049F
+:101A30000216880C010101010316881400030B2D06
+:101A40000316882400050B300316883C00030B3571
+:101A50000316E6C400020B380316E6E800050B3A4D
+:101A60000216E794000000010A00001C00001000AC
+:101A70000316806000070B3F041680A400000002DC
+:101A8000041680B000000002031680F400030B4629
+:101A90000316811800040B490316813400030B4D13
+:101AA0000316815800040B500216817800000001D3
+:101AB00002168184000000010216819000000001DE
+:101AC000021681A400000004021681B80000000183
+:101AD000021681C400000001021681D0000000013E
+:101AE000021681E400000004021681F4000001FCEB
+:101AF00002168204000000030316823C00020B540D
+:101B0000021682480092009202168250012401249B
+:101B10000316825800040B56041682680000000465
+:101B20000216880C010101010316881400030B5AE8
+:101B30000316882400050B5D0316883C00030B6226
+:101B40000316E6E800020B650216E6F80000020440
+:101B50000A00000E00001020021681740000000030
+:101B60000316817C00020B670316818800020B6953
+:101B70000316819400040B6B021681B40000000070
+:101B8000031681BC00020B6F031681C800020B71A3
+:101B9000031681D400040B73021682440E490E49C9
+:101BA0000216824C009200920216825401240124F3
+:101BB0000316E6C400020B770316E6F000020B7969
+:101BC0000216E794000000010A00000E0000104019
+:101BD00002168174000000010316817C00020B7B59
+:101BE0000316818800020B7D0316819400040B7F8D
+:101BF000021681B400000001031681BC00020B83B1
+:101C0000031681C800020B85031681D400040B87DC
+:101C100002168244000000000216824C0FFF0FFFE4
+:101C200002168254000000000316E6C400020B8B6B
+:101C30000316E6F000020B8D0216E7940000000088
+:101C40000A000007000020000316806000070B8FC9
+:101C5000031680A400020B96031680B000020B98B6
+:101C6000021681F4000001C0021682040000003F49
+:101C70000216823C0000007F0316E7BC00080B9AA6
+:101C80000A00000F00004020031680F400030BA29E
+:101C90000316811800040BA50316813400030BA959
+:101CA0000316815800040BAC03168174000D0BB0B1
+:101CB000031681B4000D0BBD0316824000060BCA4B
+:101CC00004168258000000060316827000020BD032
+:101CD0000216880C010101010316881400030BD2BF
+:101CE0000316882400050BD50316883C00030BDA85
+:101CF0000316E6C400020BDD0216E79400000001A3
+:101D00000A00000D00004040031680F400030BDFC2
+:101D10000316811800040BE20316813400030BE65E
+:101D20000316815800040BE903168174000D0BEDB6
+:101D3000031681B4000D0BFA03168240000E0C0747
+:101D40000216880C010101010316881400030C150A
+:101D50000316882400050C180316883C00030C1D8C
+:101D60000316E6C400020C200216E79400000000EF
+:101D70000A00000D00008000031680F400030C220E
+:101D80000316811800040C250316813400030C2966
+:101D90000316815800040C2C03168174000D0C30BE
+:101DA000031681B4000D0C3D03168240000E0C4A50
+:101DB0000216880C010101200316881400030C5838
+:101DC0000316882400050C5B0316883C00030C6096
+:101DD0000316E6C400020C630216E794000000013B
+:101DE000021680EC000000FF0304040800140C65D8
+:101DF000020404CC000000010305004400020C7939
+:101E00000305005000080C7B0305009000070C83BD
+:101E1000030500B000020C8A030500C000020C8C10
+:101E2000030500D400020C8E02050114000000011D
+:101E30000305011C00020C900205020400000001D1
+:101E40000305020C00020C920205021C0000002097
+:101E5000040502400000000A0405400000000D00D7
+:101E60000A000002000000080305022000020C9492
+:101E70000305028000200C960A00000200000010FA
+:101E80000305022000020CB603050280001D0CB8F9
+:101E90000305000400100CD5020500E00000000E50
+:101EA000020500E40000002E020500E00000001E14
+:101EB000020500E40000003E020500E00000004EC4
+:101EC000020500E40000006E020500E00000005E74
+:101ED000020500E40000007E041640240000000219
+:101EE0000316403000030CE50216404400000020B9
+:101EF000021640700000001C02164208000000019B
+:101F000002164210000000010216422000000001EB
+:101F100002164228000000010216423000000001B3
+:101F20000216423800000001021642600000000262
+:101F30000A000001000000090216401C0003D090B6
+:101F40000A0000010000000A0216401C0000027195
+:101F50000A0000010000000C0216401C0000009C5A
+:101F60000A000001000010010216401C0005B8D84C
+:101F70000A000001000010020216401C000003A924
+:101F80000A000001000010040216401C000000EAD4
+:101F90000A000001000020010216401C0005B8D80C
+:101FA0000A000001000020020216401C000003A9E4
+:101FB0000A000001000020040216401C000000EA94
+:101FC0000216400000000001021640D80000000187
+:101FD0000316400800030CE802164240000000000F
+:101FE000021642480000000008164270000000027D
+:101FF0000216425000000000021642580000000085
+:1020000008164280000000020304200800040CEBC4
+:102010000304201C00040CEF0304203800020CF31E
+:10202000040420400000001E030420B800020CF548
+:10203000040420C00000005E0304223800040CF7F2
+:1020400001042248000000000104224C00000000AE
+:10205000010422500000000001042254000000008E
+:1020600001042258000000000104225C000000006E
+:10207000010422600000000001042264000000004E
+:1020800001042268000000000104226C000000002E
+:10209000010422700000000001042274000000000E
+:1020A00001042278000000000104227C00000000EE
+:1020B000030422C000040CFB0A0000010000000918
+:1020C00002042000000000FA0A0000010000000ADB
+:1020D00002042000000000010A0000010000000CC2
+:1020E00002042000000000000A00000100001001AE
+:1020F00002042000000001770A0000010000100225
+:1021000002042000000000010A0000010000100489
+:1021100002042000000000000A000001000020016D
+:1021200002042000000001770A00000100002002E4
+:1021300002042000000000010A0000010000200449
+:10214000020420000000000005180400008F0000B9
+:10215000061807B800090CFF041A00000000400030
+:10216000041B240000001600031A16C800020D010B
+:10217000031A17E000900D03031A404000040D936A
+:10218000041A405000000006031A406800020D9730
+:10219000031A52C000020D99031A800003F90D9B27
+:1021A000041A8FE400000007031B3D9000141194F3
+:1021B000021B800000000034021B80400000001859
+:1021C000021B80800000000C021B80C00000002069
+:1021D000021B8BC0000000010A0000030000000881
+:1021E000021A16D000000002021B838000086470EF
+:1021F000021B83C0000002260A0000020000000942
+:10220000021B830000086470021B8340000002264A
+:102210000A0000020000000A021B83000000055FA4
+:10222000021B8340000000010A0000020000000CB5
+:10223000021B830000000157021B834000000000C6
+:102240000A00000100000020021A16D4000000005D
+:102250000A00000100000040021A16D4000000012C
+:102260000A00000300001000021A16D0000000034C
+:10227000021B8380000C96A8021B83C00000033958
+:102280000A00000200001001021B8300000C96A847
+:10229000021B8340000003390A0000020000100204
+:1022A000021B83000000080E021B83400000000296
+:1022B0000A00000200001004021B83000000020359
+:1022C000021B8340000000000A0000030000200001
+:1022D000021A16D000000004021B8380000CF85084
+:1022E000021B83C0000003520A000002000020010C
+:1022F000021B8300000CF850021B834000000352B5
+:102300000A00000200002002021B83000000084DAA
+:10231000021B8340000000020A00000200002004AB
+:10232000021B830000000213021B83400000000018
+:102330000A00000100004000021A16D80000000048
+:102340000A00000100008000021A16D800000001F7
+:10235000041B944800000002051C000032C8000065
+:10236000051C8000373F0CB2051D000034501A8256
+:10237000051D8000356D2796051E0000206734F28C
+:10238000061E4D00366011A80A0000010000000280
+:10239000021B1480000000000A000001000000047D
+:1023A000021B1480000000000A0000010000001160
+:1023B000021B1480000000000A0000020000000858
+:1023C000021800BC00000032021B945C00000032C6
+:1023D0000A00000700000010021800BC0000000204
+:1023E000021B945C00000002021B884000000001F8
+:1023F000021B942C000000020118012800000000BC
+:10240000021B884000000000021B942C000000000A
+:10241000021B9440000000010A00000100000011AE
+:10242000021B1480000000010118000000000000E1
+:10243000011800040000000001180008000000005E
+:102440000118000C0000000001180010000000003E
+:10245000011800140000000003180020001A11AA3F
+:10246000031800A4000211C4021802240000000096
+:1024700002180234000000000218024C00000000A4
+:10248000021802E4000000FF081810000000040019
+:102490000A000001000000100818200000000600DB
+:1024A000031A1A30000411C6041A3000000000128A
+:1024B000041A309000000012041AD4C80000000270
+:1024C000041AD4D800000020041AD5D80000000255
+:1024D000031AD5F8000211CA041B440000000006CC
+:1024E000031A1A40000411CC041A304800000012EC
+:1024F000041A30D800000012041AD4D000000002E0
+:10250000041AD55800000020041AD5E0000000028B
+:10251000031AD600000211D0041B44180000000664
+:10252000031A4000000211D2041A500000000002F9
+:10253000041A508000000012031A6140000211D4F6
+:10254000041AA00000000002041B44300000000236
+:10255000031A4008000211D6041A501000000002AD
+:10256000041A50C800000012031A6148000211D872
+:10257000041AA00800000002041B443800000002F6
+:10258000031A4010000211DA041A50200000000261
+:10259000041A511000000012031A6150000211DCED
+:1025A000041AA01000000002041B444000000002B6
+:1025B000031A4018000211DE041A50300000000215
+:1025C000041A515800000012031A6158000211E069
+:1025D000041AA01800000002041B44480000000276
+:1025E000031A4020000211E2041A504000000002C9
+:1025F000041A51A000000012031A6160000211E4E5
+:10260000041AA02000000002041B44500000000235
+:10261000031A4028000211E6041A5050000000027C
+:10262000041A51E800000012031A6168000211E860
+:10263000041AA02800000002041B445800000002F5
+:10264000031A4030000211EA041A50600000000230
+:10265000041A523000000012031A6170000211ECDB
+:10266000041AA03000000002041B446000000002B5
+:10267000031A4038000211EE041A507000000002E4
+:10268000041A527800000012031A6178000211F057
+:10269000041AA03800000002041B44680000000275
+:1026A000020E004C00000032030E0054000811F22C
+:1026B000030E0094000711FA030E00B40002120189
+:1026C000020E00C400000000020E00CC0000000654
+:1026D000030E00D800021203020E014400000001A4
+:1026E000030E014C00021205020E0204000000015C
+:1026F000030E020C00021207030E021C0004120952
+:10270000030E0280001B120D040E030000000012D5
+:10271000040E2000000008000A000001000000086C
+:10272000040E02EC00000005030E00040011122844
+:10273000020E01100000000F020E01140000002F15
+:10274000020E01100000001F020E01140000003FE5
+:10275000020E01100000004F020E01140000006F75
+:10276000020E01100000005F020E01140000007F45
+:10277000020C100000000028030C4008000412396D
+:10278000030C401C0004123D030C403800061241AB
+:10279000040C40500000001F020C40CC000000015F
+:1027A000040C40D00000003A030C41B80006124768
+:1027B000040C41D00000001A030C42380004124DF2
+:1027C000010C424800000000010C424C00000000D7
+:1027D000010C425000000000010C425400000000B7
+:1027E000010C425800000000010C425C0000000097
+:1027F000010C426000000000010C42640000000077
+:10280000010C426800000000010C426C0000000056
+:10281000010C427000000000010C42740000000036
+:10282000010C427800000000010C427C0000000016
+:10283000010C428000000000030C42D80004125139
+:102840000A00000100000009020C4000000003E83B
+:102850000A0000010000000A020C40000000000312
+:102860000A0000010000000C020C40000000000102
+:102870000A00000100001001020C4000000005DC0D
+:102880000A00000100001002020C400000000004D9
+:102890000A00000100001004020C400000000001CA
+:1028A0000A00000100002001020C4000000005DCCD
+:1028B0000A00000100002002020C40000000000499
+:1028C0000A00000100002004020C4000000000018A
+:1028D0000530040000C30000063007E8000312556D
+:1028E0000432000000004000043324000000160001
+:1028F00003322C7000901257033234C0000812E7E4
+:102900000432408000000010033240C0000212EF89
+:1029100003337400000412F1023380000000001A37
+:10292000023380400000004E02338080000000101F
+:10293000023380C00000002002338BC00000000181
+:102940000A0000020000000802338380000864705F
+:10295000023383C0000002260A00000200000009C2
+:1029600002338300000864700233834000000226B3
+:102970000A0000020000000A023383000000055F25
+:1029800002338340000000010A0000020000000C36
+:10299000023383000000015702338340000000002F
+:1029A0000A0000020000100002338380000C96A889
+:1029B000023383C0000003390A0000020000100146
+:1029C00002338300000C96A80233834000000339D1
+:1029D0000A00000200001002023383000000080E0B
+:1029E00002338340000000020A00000200001004CD
+:1029F0000233830000000203023383400000000022
+:102A00000A0000020000200002338380000CF8500E
+:102A1000023383C0000003520A00000200002001BC
+:102A200002338300000CF85002338340000003524D
+:102A30000A00000200002002023383000000084D5B
+:102A400002338340000000020A000002000020045C
+:102A500002338300000002130233834000000000B1
+:102A600005340000367E00000534800034390DA0A6
+:102A70000535000031581AAF05358000386127054B
+:102A800005360000391A351E0536800034AC436522
+:102A9000053700001C8550900637416017D412F5A9
+:102AA0000A00000100000002023314800000000050
+:102AB0000A0000010000000402331480000000003E
+:102AC0000A00000100000011023314800000000021
+:102AD0000A00000100000008023000BC00000032C3
+:102AE0000A00000400000010023000BC00000002D8
+:102AF000023388400000000101300138000000006E
+:102B000002338840000000000A00000100000011AC
+:102B100002331480000000010130000000000000BA
+:102B20000130000400000000013000080000000037
+:102B30000130000C00000000013000100000000017
+:102B4000013000140000000003300020001A12F7CA
+:102B5000033000A400021311023002240000000020
+:102B600002300234000000000230024C000000007D
+:102B7000023002E40000FFFF0830200000000800DF
+:102B80000A000001000000100830400000000200B0
+:102B900004322C400000000203322C5000041313B6
+:102BA000043293C0000000020432940000000010C0
+:102BB0000432C000000000200432C10000000020E8
+:102BC0000432C200000000200432C30000000020D4
+:102BD0000432C400000000200432C50000000020C0
+:102BE0000432C600000000200432C70000000020AC
+:102BF0000432C800000000200432C9000000002098
+:102C00000432CA00000000200432CB000000002083
+:102C10000432CC00000000200432CD00000000206F
+:102C20000432CE00000000200432CF00000000205B
+:102C30000432DB800000000204322C480000000255
+:102C400003322C6000041317043293C80000000202
+:102C500004329440000000100432C08000000020C4
+:102C60000432C180000000200432C2800000002035
+:102C70000432C380000000200432C4800000002021
+:102C80000432C580000000200432C680000000200D
+:102C90000432C780000000200432C88000000020F9
+:102CA0000432C980000000200432CA8000000020E5
+:102CB0000432CB80000000200432CC8000000020D1
+:102CC0000432CD80000000200432CE8000000020BD
+:102CD0000432CF80000000200432DB8800000002B4
+:102CE000043210100000000204322C000000000228
+:102CF000043210200000000204322C080000000200
+:102D0000043210300000000204322C1000000002D7
+:102D1000043210400000000204322C1800000002AF
+:102D2000043210500000000204322C200000000287
+:102D3000043210600000000204322C28000000025F
+:102D4000043210700000000204322C300000000237
+:102D5000043210800000000204322C38000000020F
+:102D60000202005800000032030200600008131B3A
+:102D7000030200A0000B1323020200D00000000792
+:102D8000030200DC0003132E030200F000021331E3
+:102D9000020200FC0000000C020201200000000002
+:102DA0000202013400000002020201B00000000132
+:102DB0000202020C0000000103020214000213339D
+:102DC00002020404000000010302040C0002133597
+:102DD0000302041C00041337030204800020133B89
+:102DE0000402050000000012040280000000200020
+:102DF000030200040014135B02020108000000C873
+:102E00000202011800000002020201C400000000DA
+:102E1000020201CC00000000020201D40000000206
+:102E2000020201DC00000002020201E4000000FFD7
+:102E3000020201EC000000FF0202010C000000C8C9
+:102E40000202011C00000002020201C80000000092
+:102E5000020201D000000000020201D800000002BE
+:102E6000020201E000000002020201E8000000FF8F
+:102E7000020201F0000000FF02020108000000C889
+:102E80000202011800000002020201C4000000005A
+:102E9000020201CC00000000020201D40000000286
+:102EA000020201DC00000002020201E4000000FF57
+:102EB000020201EC000000FF0202010C000000C849
+:102EC0000202011C00000002020201C80000000012
+:102ED000020201D000000000020201D8000000023E
+:102EE000020201E000000002020201E8000000FF0F
+:102EF000020201F0000000FF02020108000000C809
+:102F00000202011800000002020201C400000000D9
+:102F1000020201CC00000000020201D40000000205
+:102F2000020201DC00000002020201E4000000FFD6
+:102F3000020201EC000000FF0202010C000000C8C8
+:102F40000202011C00000002020201C80000000091
+:102F5000020201D000000000020201D800000002BD
+:102F6000020201E000000002020201E8000000FF8E
+:102F7000020201F0000000FF02020108000000C888
+:102F80000202011800000002020201C40000000059
+:102F9000020201CC00000000020201D40000000285
+:102FA000020201DC00000002020201E4000000FF56
+:102FB000020201EC000000FF0202010C000000C848
+:102FC0000202011C00000002020201C80000000011
+:102FD000020201D000000000020201D8000000023D
+:102FE000020201E000000002020201E8000000FF0E
+:102FF000020201F0000000FF02161000000000288D
+:10300000031660080003136F0316601C000413729C
+:103010000316603800121376041660800000000E5C
+:10302000021660B800000001041660BC0000000831
+:10303000021660DC00000001041660E000000004DD
+:10304000021660F000000001041660F40000003178
+:10305000031661B800021388041661C0000000075F
+:10306000031661DC0006138A041661F400000011E7
+:103070000316623800041390011662480000000035
+:103080000116624C000000000116625000000000B2
+:103090000116625400000000011662580000000092
+:1030A0000116625C00000000011662600000000072
+:1030B0000116626400000000011662680000000052
+:1030C0000116626C00000000011662700000000032
+:1030D0000116627400000000011662780000000012
+:1030E0000116627C00000000011662D4000000009E
+:1030F000031662D8000413940A00000100000009BE
+:1031000002166000000003E80A0000010000000A47
+:1031100002166000000000030A0000010000000C1D
+:1031200002166000000000010A000001000010010A
+:1031300002166000000005DC0A0000010000100219
+:1031400002166000000000040A00000100001004E4
+:1031500002166000000000010A00000100002001CA
+:1031600002166000000005DC0A00000100002002D9
+:1031700002166000000000040A00000100002004A4
+:1031800002166000000000010528040000AB0000EA
+:10319000062807C800071398042A00000000400012
+:1031A000042B240000001600032A30000002139AAA
+:1031B000032A40000010139C032A8408000813AC63
+:1031C000032A9348000413B4032A9668000813B82E
+:1031D000032A98B8000213C0032A9950009013C222
+:1031E000032B4D9000141452022B800000000000AD
+:1031F000022B804000000018022B80800000000C91
+:10320000022B80C000000066022B8BC00000000172
+:103210000A00000300000008022A9CA80000000227
+:10322000022B838000086470022B83C000000226FA
+:103230000A00000200000009022B830000086470ED
+:10324000022B8340000002260A0000020000000A50
+:10325000022B83000000055F022B83400000000169
+:103260000A0000020000000C022B8300000001573E
+:10327000022B8340000000000A0000030000002031
+:10328000022A9CAC00000000032AC4E0000414667B
+:10329000032AC5000002146A0A0000020000004070
+:1032A000022A9CAC00000001032AC4E0000A146C4E
+:1032B0000A00000300001000022A9CA8000000037E
+:1032C000022B8380000C96A8022B83C000000339D8
+:1032D0000A00000200001001022B8300000C96A8D7
+:1032E000022B8340000003390A0000020000100294
+:1032F000022B83000000080E022B83400000000216
+:103300000A00000200001004022B830000000203E8
+:10331000022B8340000000000A0000030000200090
+:10332000022A9CA800000004022B8380000CF850A5
+:10333000022B83C0000003520A000002000020019B
+:10334000022B8300000CF850022B83400000035234
+:103350000A00000200002002022B83000000084D3A
+:10336000022B8340000000020A000002000020043B
+:10337000022B830000000213022B83400000000098
+:103380000A00000100004000022A9CB0000000007A
+:103390000A00000100008000022A9CB00000000129
+:1033A000042B944800000002052C000035FF0000AB
+:1033B000052C80003A950D80052D00002F111C264C
+:1033C000052D80003C3927EB052E00003FEE36FA34
+:1033D000052E80003C5646F6052F000034DD560CC5
+:1033E000052F800009026344062F93900D8E1476FA
+:1033F0000A00000100000002022B148000000000FF
+:103400000A00000100000004022B148000000000EC
+:103410000A00000100000011022B148000000000CF
+:103420000A00000200000008022800BC0000003270
+:10343000022B945C000000320A000007000000101C
+:10344000022800BC00000002022B945C0000000275
+:10345000022B884000000001022B942C0000000287
+:103460000128013800000000022B88400000000005
+:10347000022B942C00000000022B9440000000015D
+:103480000A00000100000011022B1480000000015E
+:1034900001280000000000000128000400000000D6
+:1034A00001280008000000000128000C00000000B6
+:1034B0000128001000000000012800140000000096
+:1034C00003280020001A1478032800A40002149294
+:1034D000022802240000000002280234000000003C
+:1034E0000228024C00000000022802E40000FFFF56
+:1034F00008282000000008000A0000010000001059
+:103500000828400000000200042A500000000002C9
+:10351000042A501000000002042A5020000000027B
+:10352000042A503000000002042A935800000020B2
+:10353000042A94580000000E032A94900002149468
+:10354000042A94D80000000E032A95100002149655
+:10355000042A95580000000E032A95900002149842
+:10356000042A95D80000000E032A96100002149A2F
+:10357000032A96880002149C042ABC9800000002CA
+:10358000042A500800000002042A5018000000021B
+:10359000042A502800000002042A503800000002CB
+:1035A000042A93D800000020042A94980000000EFA
+:1035B000032A94D00002149E042A95180000000EDD
+:1035C000032A9550000214A0042A95980000000ECA
+:1035D000032A95D0000214A2042A96180000000EB7
+:1035E000032A9650000214A4032A9690000214A6FF
+:1035F000042ABCA000000002042A50480000000E6B
+:10360000032A9698001014A8042A98D000000002FB
+:10361000042A991000000002042AC480000000025D
+:10362000042A50800000000E032A96D8001014B817
+:10363000042A98D800000002042A99180000000209
+:10364000042AC48800000002042A50B80000000EBA
+:10365000032A9718001014C8042A98E000000002FA
+:10366000042A992000000002042AC49000000002ED
+:10367000042A50F00000000E032A9758001014D8B6
+:10368000042A98E800000002042A99280000000299
+:10369000042AC49800000002042A51280000000EE9
+:1036A000032A9798001014E8042A98F000000002FA
+:1036B000042A993000000002042AC4A0000000027D
+:1036C000042A51600000000E032A97D8001014F855
+:1036D000042A98F800000002042A99380000000229
+:1036E000042AC4A800000002042A51980000000E19
+:1036F000032A981800101508042A990000000002F7
+:10370000042A994000000002042AC4B0000000020C
+:10371000042A51D00000000E032A985800101518F2
+:10372000042A990800000002042A994800000002B7
+:10373000042AC4B8000000020400A0000000000C2D
+:103740000400A050000000020300A0EC00081528AF
+:103750000300A19C000415300200A45C00000C00D2
+:103760000400A6A8000000020200A6D0000000008D
+:103770000200A61C000000030300A0700005153421
+:103780000400A084000000050200A0980FE00000E3
+:103790000400A09C000000070300A0B8000D15392C
+:1037A0000400A22C000000040200A688000000FC17
+:1037B0000400A68C000000070200A6F40000000030
+:1037C0000300A10C000615460400A124000000051A
+:1037D0000200A1380FE000000400A13C0000000737
+:1037E0000300A158000D154C0400A23C0000000489
+:1037F0000200A6B0000000FC0400A6B40000000710
+:103800000200A6F8000000000200A0300000000046
+:103810000200A034000000000200A03800000000F8
+:103820000200A03C000000000200A04000000000D8
+:103830000200A044000000000200A04800000000B8
+:103840000200A04C0000000000000000000000008A
+:103850000000000100000000000000000000000067
+:103860000000000000000000000000000000000058
+:10387000000000000000000000000000000100182F
+:1038800000180020002000230000000000000000BD
+:103890000000000000000000000000000000000028
+:1038A00000000000000000000023003500000000C0
+:1038B00000000000003500360036003700370038C1
+:1038C000003800390039003A003A003B003B003C28
+:1038D000003C003D003D00440000000000000000EE
+:1038E00000000000000000000000000000000000D8
+:1038F00000000000000000000000000000000000C8
+:103900000044004D0000000000000000004D004E8B
+:10391000004E004F004F0050005000510051005227
+:103920000052005300530054005400550055007FCE
+:103930000000000000000000000000000000000087
+:103940000000000000000000000000000000000077
+:103950000000000000000000007F01E10000000006
+:103960000000000001E101E601E601EB01EB01F0DE
+:1039700001F001F501F501FA01FA01FF01FF02046E
+:103980000204020900000000000000000000000026
+:103990000000000000000000000000000000000027
+:1039A0000000000000000000000000000000000017
+:1039B0000209020D000000000000000000000000ED
+:1039C00000000000000000000000000000000000F7
+:1039D000000000000000000000000000020D021DB9
+:1039E0000000000000000000021D021F021F022153
+:1039F000022102230223022502250227022702298F
+:103A00000229022B022B022D000000000000000002
+:103A100000000000000000000000000000000000A6
+:103A20000000000000000000000000000000000096
+:103A300000000000022D0230000000000000000025
+:103A40000230023302330236023602390239023CB6
+:103A5000023C023F023F0242024202450245024846
+:103A60000248024C024C02500250025402540255C9
+:103A7000025502560256025702570258025802597E
+:103A80000259025A025A025B025B025C025C026348
+:103A900002630289028902AE02AE02AF02AF02B037
+:103AA00002B002B102B102B202B202B302B302B476
+:103AB00002B402B502B502B602B602CF00000000A1
+:103AC00000000000000000000000000000000000F6
+:103AD00000000000000000000000000000000000E6
+:103AE0000000000002CF02DC000000000000000027
+:103AF00002DC02DD02DD02DE02DE02DF02DF02E0C6
+:103B000002E002E102E102E202E202E302E302E495
+:103B100002E402F7000000000000000000000000C6
+:103B20000000000000000000000000000000000095
+:103B300000000000000000000000000002F7030584
+:103B40000000000000000000030503060306030751
+:103B500003070308030803090309030A030A030B05
+:103B6000030B030C030C030D030D031200000000F4
+:103B70000000000000000000000000000000000045
+:103B80000000000000000000000000000000000035
+:103B900000000000031203B000000000000000005D
+:103BA0000000000000000000000000000000000015
+:103BB0000000000000000000000000000000000005
+:103BC00003B003B20000000000000000000000008D
+:103BD00000000000000000000000000000000000E5
+:103BE00000000000000000000000000003B203C657
+:103BF000000000000000000003C603C703C703C89D
+:103C000003C803C903C903CA03CA03CB03CB03CC4C
+:103C100003CC03CD03CD03CE03CE03EE03EE03F1BD
+:103C200003F103F4000000000000000000000000A9
+:103C30000000000000000000000000000000000084
+:103C40000000000003F4041C00000000000000005D
+:103C50000000000000000000000000000000000064
+:103C60000000000000000000000000000000000054
+:103C7000041C04870487048F048F04970497049D11
+:103C8000049D04A304A304A904A904AF04AF04B5CC
+:103C900004B504BB04BB04C104C104C704C704D9F0
+:103CA000000000000000000004D904DA04DA04DB9C
+:103CB00004DB04DC04DC04DD04DD04DE04DE04DFFC
+:103CC00004DF04E004E004E104E104E20000000099
+:103CD00000000000000000000000000000000000E4
+:103CE00000000000000000000000000000000000D4
+:103CF0000000000004E2050D0000000000000000CC
+:103D000000000000000000000000000000000000B3
+:103D100000000000000000000000000000000000A3
+:103D2000050D05650565057A057A058F058F0591F1
+:103D300005910593059305950595059705970599B3
+:103D40000599059B059B059D059D059F059F05B252
+:103D5000000000000000000005B205BA05BA05C267
+:103D600005C205CA05CA05D205D205DA05DA05E29B
+:103D700005E205EA05EA05F205F205F30000000098
+:103D80000000000000000000000000000000000033
+:103D90000000000000000000000000000000000023
+:103DA0000000000005F306240000000000000000F1
+:103DB0000000000000000000000000000000000003
+:103DC00000000000000000000000000000000000F3
+:103DD00006240694069406A306A306B206B206B706
+:103DE00006B706BC06BC06C106C106C606C606CB9B
+:103DF00006CB06D006D006D506D506DA06DA06E2E8
+:103E000006E206EB06EB06F406F406F506F506F602
+:103E100006F606F706F706F806F806F906F906FAB2
+:103E200006FA06FB06FB06FC00000000000000008E
+:103E30000000200000004000000060000000800042
+:103E40000000A0000000C0000000E0000001000031
+:103E5000000120000001400000016000000180001E
+:103E60000001A0000001C0000001E000000200000D
+:103E700000022000000240000002600000028000FA
+:103E80000002A0000002C0000002E00000030000E9
+:103E900000032000000340000003600000038000D6
+:103EA0000003A0000003C0000003E00000040000C5
+:103EB00000042000000440000004600000048000B2
+:103EC0000004A0000004C0000004E00000050000A1
+:103ED000000520000005400000056000000580008E
+:103EE0000005A0000005C0000005E000000600007D
+:103EF000000620000006400000066000000680006A
+:103F00000006A0000006C0000006E0000007000058
+:103F10000007200000074000000760000007800045
+:103F20000007A0000007C0000007E0000008000034
+:103F30000008200000084000000860000008800021
+:103F40000008A0000008C0000008E0000009000010
+:103F500000092000000940000009600000098000FD
+:103F60000009A0000009C0000009E000000A0000EC
+:103F7000000A2000000A4000000A6000000A8000D9
+:103F8000000AA000000AC000000AE000000B0000C8
+:103F9000000B2000000B4000000B6000000B8000B5
+:103FA000000BA000000BC000000BE000000C0000A4
+:103FB000000C2000000C4000000C6000000C800091
+:103FC000000CA000000CC000000CE000000D000080
+:103FD000000D2000000D4000000D6000000D80006D
+:103FE000000DA000000DC000000DE000000E00005C
+:103FF000000E2000000E4000000E6000000E800049
+:10400000000EA000000EC000000EE000000F000037
+:10401000000F2000000F4000000F6000000F800024
+:10402000000FA000000FC000000FE0000010000013
+:104030000010200000104000001060000010800000
+:104040000010A0000010C0000010E00000110000EF
+:1040500000112000001140000011600000118000DC
+:104060000011A0000011C0000011E00000120000CB
+:1040700000122000001240000012600000128000B8
+:104080000012A0000012C0000012E00000130000A7
+:104090000013200000134000001360000013800094
+:1040A0000013A0000013C0000013E0000014000083
+:1040B0000014200000144000001460000014800070
+:1040C0000014A0000014C0000014E000001500005F
+:1040D000001520000015400000156000001580004C
+:1040E0000015A0000015C0000015E000001600003B
+:1040F0000016200000164000001660000016800028
+:104100000016A0000016C0000016E0000017000016
+:104110000017200000174000001760000017800003
+:104120000017A0000017C0000017E00000180000F2
+:1041300000182000001840000018600000188000DF
+:104140000018A0000018C0000018E00000190000CE
+:1041500000192000001940000019600000198000BB
+:104160000019A0000019C0000019E000001A0000AA
+:10417000001A2000001A4000001A6000001A800097
+:10418000001AA000001AC000001AE000001B000086
+:10419000001B2000001B4000001B6000001B800073
+:1041A000001BA000001BC000001BE000001C000062
+:1041B000001C2000001C4000001C6000001C80004F
+:1041C000001CA000001CC000001CE000001D00003E
+:1041D000001D2000001D4000001D6000001D80002B
+:1041E000001DA000001DC000001DE000001E00001A
+:1041F000001E2000001E4000001E6000001E800007
+:10420000001EA000001EC000001EE000001F0000F5
+:10421000001F2000001F4000001F6000001F8000E2
+:10422000001FA000001FC000001FE00000200000D1
+:1042300000202000002040000020600000208000BE
+:104240000020A0000020C0000020E00000210000AD
+:10425000002120000021400000216000002180009A
+:104260000021A0000021C0000021E0000022000089
+:104270000022200000224000002260000022800076
+:104280000022A0000022C0000022E0000023000065
+:104290000023200000234000002360000023800052
+:1042A0000023A0000023C0000023E0000024000041
+:1042B000002420000024400000246000002480002E
+:1042C0000024A0000024C0000024E000002500001D
+:1042D000002520000025400000256000002580000A
+:1042E0000025A0000025C0000025E00000260000F9
+:1042F00000262000002640000026600000268000E6
+:104300000026A0000026C0000026E00000270000D4
+:1043100000272000002740000027600000278000C1
+:104320000027A0000027C0000027E00000280000B0
+:10433000002820000028400000286000002880009D
+:104340000028A0000028C0000028E000002900008C
+:104350000029200000294000002960000029800079
+:104360000029A0000029C0000029E000002A000068
+:10437000002A2000002A4000002A6000002A800055
+:10438000002AA000002AC000002AE000002B000044
+:10439000002B2000002B4000002B6000002B800031
+:1043A000002BA000002BC000002BE000002C000020
+:1043B000002C2000002C4000002C6000002C80000D
+:1043C000002CA000002CC000002CE000002D0000FC
+:1043D000002D2000002D4000002D6000002D8000E9
+:1043E000002DA000002DC000002DE000002E0000D8
+:1043F000002E2000002E4000002E6000002E8000C5
+:10440000002EA000002EC000002EE000002F0000B3
+:10441000002F2000002F4000002F6000002F8000A0
+:10442000002FA000002FC000002FE000003000008F
+:10443000003020000030400000306000003080007C
+:104440000030A0000030C0000030E000003100006B
+:104450000031200000314000003160000031800058
+:104460000031A0000031C0000031E0000032000047
+:104470000032200000324000003260000032800034
+:104480000032A0000032C0000032E0000033000023
+:104490000033200000334000003360000033800010
+:1044A0000033A0000033C0000033E00000340000FF
+:1044B00000342000003440000034600000348000EC
+:1044C0000034A0000034C0000034E00000350000DB
+:1044D00000352000003540000035600000358000C8
+:1044E0000035A0000035C0000035E00000360000B7
+:1044F00000362000003640000036600000368000A4
+:104500000036A0000036C0000036E0000037000092
+:10451000003720000037400000376000003780007F
+:104520000037A0000037C0000037E000003800006E
+:10453000003820000038400000386000003880005B
+:104540000038A0000038C0000038E000003900004A
+:104550000039200000394000003960000039800037
+:104560000039A0000039C0000039E000003A000026
+:10457000003A2000003A4000003A6000003A800013
+:10458000003AA000003AC000003AE000003B000002
+:10459000003B2000003B4000003B6000003B8000EF
+:1045A000003BA000003BC000003BE000003C0000DE
+:1045B000003C2000003C4000003C6000003C8000CB
+:1045C000003CA000003CC000003CE000003D0000BA
+:1045D000003D2000003D4000003D6000003D8000A7
+:1045E000003DA000003DC000003DE000003E000096
+:1045F000003E2000003E4000003E6000003E800083
+:10460000003EA000003EC000003EE000003F000071
+:10461000003F2000003F4000003F6000003F80005E
+:10462000003FA000003FC000003FE000004000004D
+:10463000004020000040400000406000004080003A
+:104640000040A0000040C0000040E0000041000029
+:104650000041200000414000004160000041800016
+:104660000041A0000041C0000041E0000042000005
+:1046700000422000004240000042600000428000F2
+:104680000042A0000042C0000042E00000430000E1
+:1046900000432000004340000043600000438000CE
+:1046A0000043A0000043C0000043E00000440000BD
+:1046B00000442000004440000044600000448000AA
+:1046C0000044A0000044C0000044E0000045000099
+:1046D0000045200000454000004560000045800086
+:1046E0000045A0000045C0000045E0000046000075
+:1046F0000046200000464000004660000046800062
+:104700000046A0000046C0000046E0000047000050
+:10471000004720000047400000476000004780003D
+:104720000047A0000047C0000047E000004800002C
+:104730000048200000484000004860000048800019
+:104740000048A0000048C0000048E0000049000008
+:1047500000492000004940000049600000498000F5
+:104760000049A0000049C0000049E000004A0000E4
+:10477000004A2000004A4000004A6000004A8000D1
+:10478000004AA000004AC000004AE000004B0000C0
+:10479000004B2000004B4000004B6000004B8000AD
+:1047A000004BA000004BC000004BE000004C00009C
+:1047B000004C2000004C4000004C6000004C800089
+:1047C000004CA000004CC000004CE000004D000078
+:1047D000004D2000004D4000004D6000004D800065
+:1047E000004DA000004DC000004DE000004E000054
+:1047F000004E2000004E4000004E6000004E800041
+:10480000004EA000004EC000004EE000004F00002F
+:10481000004F2000004F4000004F6000004F80001C
+:10482000004FA000004FC000004FE000005000000B
+:1048300000502000005040000050600000508000F8
+:104840000050A0000050C0000050E00000510000E7
+:1048500000512000005140000051600000518000D4
+:104860000051A0000051C0000051E00000520000C3
+:1048700000522000005240000052600000528000B0
+:104880000052A0000052C0000052E000005300009F
+:10489000005320000053400000536000005380008C
+:1048A0000053A0000053C0000053E000005400007B
+:1048B0000054200000544000005460000054800068
+:1048C0000054A0000054C0000054E0000055000057
+:1048D0000055200000554000005560000055800044
+:1048E0000055A0000055C0000055E0000056000033
+:1048F0000056200000564000005660000056800020
+:104900000056A0000056C0000056E000005700000E
+:1049100000572000005740000057600000578000FB
+:104920000057A0000057C0000057E00000580000EA
+:1049300000582000005840000058600000588000D7
+:104940000058A0000058C0000058E00000590000C6
+:1049500000592000005940000059600000598000B3
+:104960000059A0000059C0000059E000005A0000A2
+:10497000005A2000005A4000005A6000005A80008F
+:10498000005AA000005AC000005AE000005B00007E
+:10499000005B2000005B4000005B6000005B80006B
+:1049A000005BA000005BC000005BE000005C00005A
+:1049B000005C2000005C4000005C6000005C800047
+:1049C000005CA000005CC000005CE000005D000036
+:1049D000005D2000005D4000005D6000005D800023
+:1049E000005DA000005DC000005DE000005E000012
+:1049F000005E2000005E4000005E6000005E8000FF
+:104A0000005EA000005EC000005EE000005F0000ED
+:104A1000005F2000005F4000005F6000005F8000DA
+:104A2000005FA000005FC000005FE00000600000C9
+:104A300000602000006040000060600000608000B6
+:104A40000060A0000060C0000060E00000610000A5
+:104A50000061200000614000006160000061800092
+:104A60000061A0000061C0000061E0000062000081
+:104A7000006220000062400000626000006280006E
+:104A80000062A0000062C0000062E000006300005D
+:104A9000006320000063400000636000006380004A
+:104AA0000063A0000063C0000063E0000064000039
+:104AB0000064200000644000006460000064800026
+:104AC0000064A0000064C0000064E0000065000015
+:104AD0000065200000654000006560000065800002
+:104AE0000065A0000065C0000065E00000660000F1
+:104AF00000662000006640000066600000668000DE
+:104B00000066A0000066C0000066E00000670000CC
+:104B100000672000006740000067600000678000B9
+:104B20000067A0000067C0000067E00000680000A8
+:104B30000068200000684000006860000068800095
+:104B40000068A0000068C0000068E0000069000084
+:104B50000069200000694000006960000069800071
+:104B60000069A0000069C0000069E000006A000060
+:104B7000006A2000006A4000006A6000006A80004D
+:104B8000006AA000006AC000006AE000006B00003C
+:104B9000006B2000006B4000006B6000006B800029
+:104BA000006BA000006BC000006BE000006C000018
+:104BB000006C2000006C4000006C6000006C800005
+:104BC000006CA000006CC000006CE000006D0000F4
+:104BD000006D2000006D4000006D6000006D8000E1
+:104BE000006DA000006DC000006DE000006E0000D0
+:104BF000006E2000006E4000006E6000006E8000BD
+:104C0000006EA000006EC000006EE000006F0000AB
+:104C1000006F2000006F4000006F6000006F800098
+:104C2000006FA000006FC000006FE0000070000087
+:104C30000070200000704000007060000070800074
+:104C40000070A0000070C0000070E0000071000063
+:104C50000071200000714000007160000071800050
+:104C60000071A0000071C0000071E000007200003F
+:104C7000007220000072400000726000007280002C
+:104C80000072A0000072C0000072E000007300001B
+:104C90000073200000734000007360000073800008
+:104CA0000073A0000073C0000073E00000740000F7
+:104CB00000742000007440000074600000748000E4
+:104CC0000074A0000074C0000074E00000750000D3
+:104CD00000752000007540000075600000758000C0
+:104CE0000075A0000075C0000075E00000760000AF
+:104CF000007620000076400000766000007680009C
+:104D00000076A0000076C0000076E000007700008A
+:104D10000077200000774000007760000077800077
+:104D20000077A0000077C0000077E0000078000066
+:104D30000078200000784000007860000078800053
+:104D40000078A0000078C0000078E0000079000042
+:104D5000007920000079400000796000007980002F
+:104D60000079A0000079C0000079E000007A00001E
+:104D7000007A2000007A4000007A6000007A80000B
+:104D8000007AA000007AC000007AE000007B0000FA
+:104D9000007B2000007B4000007B6000007B8000E7
+:104DA000007BA000007BC000007BE000007C0000D6
+:104DB000007C2000007C4000007C6000007C8000C3
+:104DC000007CA000007CC000007CE000007D0000B2
+:104DD000007D2000007D4000007D6000007D80009F
+:104DE000007DA000007DC000007DE000007E00008E
+:104DF000007E2000007E4000007E6000007E80007B
+:104E0000007EA000007EC000007EE000007F000069
+:104E1000007F2000007F4000007F6000007F800056
+:104E2000007FA000007FC000007FE000007FE00165
+:104E300000000000000001FF000002000000000070
+:104E4000000003FF00000400000004010000040152
+:104E5000000002380000011C0000011C0000011CC1
+:104E60000000005000000050000000500000000151
+:104E700000000158000001A8000000C8000000A0C8
+:104E8000000000C800000000000000000000005A00
+:104E9000000000FA00000401000004010000000A04
+:104EA000000000320000040100000401000001586D
+:104EB000000001A80000001800000068000000B811
+:104EC0000000010800000158000001A800000018BF
+:104ED00000000068000000B80000010800000001A8
+:104EE0000000000200000000000000080215002081
+:104EF000021500200810000000000036000000002D
+:104F00000000000400000004000000000000000099
+:104F10000000000100000004000000020000000288
+:104F2000000000010000000200000020000000401E
+:104F300000000040000000030000001800002000F6
+:104F4000000040C000006180000082400000A3001B
+:104F50000000C3C00000E4800001054000012600FD
+:104F6000000146C000016780000188400001A900DF
+:104F70000001C9C00001EA8000020B4000022C00C1
+:104F800000024CC000026D8000028E400002AF00A3
+:104F90000002CFC00002F0800000114000000001BC
+:104FA00000000001000000010000000100000001FD
+:104FB00000000001000000010000000100000001ED
+:104FC00000000001000000010000000100000001DD
+:104FD00000000001000000010003D0000000003DBF
+:104FE00000000001000D0000000700D00002814019
+:104FF000000B81680002022000010240000F0250F5
+:1050000000010340000C0000000800C000028140C5
+:10501000000B8168000202200001024000070250DC
+:10502000000202C0001000000008010000028180A0
+:10503000000B81A80002026000018280000E8298AD
+:1050400000080380000F0000000100F00002810052
+:1050500000090128000201B8000101D8000E01E892
+:10506000000002C8FFFFFFF301AFFFFF00000000D8
+:105070000000000000000000000000000000000030
+:1050800000000000FFFFFFF100EFFFFF0000000045
+:10509000000000000000000000000000000100000F
+:1050A00000000000FFFFFFF6005FFFFF00000000B0
+:1050B00000000000000000000000000000020000EE
+:1050C00000000000FFFFF4061CBFFFFF000000050A
+:1050D00000000000000000140000000000040000B8
+:1050E00000000000FFFFFFF2004FFFFF0000000084
+:1050F00000000000000000000000000000080000A8
+:1051000000000000FFFFFFFA002FFFFF000000007B
+:10511000000000000000000000000000001000007F
+:1051200000000000FFFFFFF701EFFFFF000000009D
+:10513000000000000000000000000000002000004F
+:1051400000000000FFFFFFF5002FFFFF0000000040
+:10515000000000000000000000000000004000000F
+:1051600000000000FFFFFFF3018FFFFF00000000C1
+:10517000000000000000000000000000000000002F
+:1051800000000000FFFFFFF1010FFFFF0000000023
+:10519000000000000000000000000000000100000E
+:1051A00000000000FFFFFFF6005FFFFF00000000AF
+:1051B00000000000000000000000000000020000ED
+:1051C00000000000FFFFF4061CBFFFFF0000000509
+:1051D00000000000000000140000000000040000B7
+:1051E00000000000FFFFFFF2004FFFFF0000000083
+:1051F00000000000000000000000000000080000A7
+:1052000000000000FFFFFFFA002FFFFF000000007A
+:10521000000000000000000000000000001000007E
+:1052200000000000FFFFFFF700EFFFFF000000009D
+:10523000000000000000000000000000002000004E
+:1052400000000000FFFFFFF5004FFFFF000000001F
+:10525000000000000000000000000000004000000E
+:1052600000000000FFFFFFFF00CFFFFF0000000075
+:1052700000000000000000CC000000000000000062
+:1052800000000000FFFFFFFF00CFFFFF0000000055
+:1052900000000000000000CC000000000001000041
+:1052A00000000000FFFFFFFF00CFFFFF0000000035
+:1052B00000000000000000CC000000000002000020
+:1052C00000000000FFFFFFFF00CFFFFF0000000015
+:1052D00000000000000000CC0000000000040000FE
+:1052E00000000000FFFFFFFF00CFFFFF00000000F5
+:1052F00000000000000000CC0000000000080000DA
+:1053000000000000FFFFFFFF00CFFFFF00000000D4
+:1053100000000000000000CC0000000000100000B1
+:1053200000000000FFFFFFFF00CFFFFF00000000B4
+:1053300000000000000000CC000000000020000081
+:1053400000000000FFFFFFFF00CFFFFF0000000094
+:1053500000000000000000CC000000000040000041
+:1053600000000000FFFFFFF3020FFFFF000000003E
+:10537000000000000000000000000000000000002D
+:1053800000000000FFFFFFF1010FFFFF0000000021
+:10539000000000000000000000000000000100000C
+:1053A00000000000FFFFFFF6005FFFFF00000000AD
+:1053B00000000000000000000000000000020000EB
+:1053C00000000000FFFFF4061CBFFFFF0000000507
+:1053D00000000000000000140000000000040000B5
+:1053E00000000000FFFFFFF2004FFFFF0000000081
+:1053F00000000000000000000000000000080000A5
+:1054000000000000FFFFFF8A042FFFFF00000000E4
+:10541000000000000000000000000000001000007C
+:1054200000000000FFFFFF9705CFFFFF0000000016
+:10543000000000000000000000000000002000004C
+:1054400000000000FFFFFFF5010FFFFF000000005C
+:10545000000000000000000000000000004000000C
+:1054600000000000FFFFFFF301EFFFFF000000005E
+:10547000000000000000000000000000000000002C
+:1054800000000000FFFFFFF1002FFFFF0000000001
+:10549000000000000000000000000000000100000B
+:1054A00000000000FFFFFFF6005FFFFF00000000AC
+:1054B00000000000000000000000000000020000EA
+:1054C00000000000FFFFFF061CBFFFFF0000000000
+:1054D00000000000000000140000000000040000B4
+:1054E00000000000FFFFFFF2004FFFFF0000000080
+:1054F00000000000000000000000000000080000A4
+:1055000000000000FFFFFFFA002FFFFF0000000077
+:10551000000000000000000000000000001000007B
+:1055200000000000FFFFFFF701CFFFFF00000000B9
+:10553000000000000000000000000000002000004B
+:1055400000000000FFFFFFFF00CFFFFF0000000092
+:1055500000000000000000CC00000000004000003F
+:1055600000000000FFFFFFFF00CFFFFF0000000072
+:1055700000000000000000CC00000000000000005F
+:1055800000000000FFFFFFFF00CFFFFF0000000052
+:1055900000000000000000CC00000000000100003E
+:1055A00000000000FFFFFFFF00CFFFFF0000000032
+:1055B00000000000000000CC00000000000200001D
+:1055C00000000000FFFFFFFF00CFFFFF0000000012
+:1055D00000000000000000CC0000000000040000FB
+:1055E00000000000FFFFFFFF00CFFFFF00000000F2
+:1055F00000000000000000CC0000000000080000D7
+:1056000000000000FFFFFFFF00CFFFFF00000000D1
+:1056100000000000000000CC0000000000100000AE
+:1056200000000000FFFFFFFF00CFFFFF00000000B1
+:1056300000000000000000CC00000000002000007E
+:1056400000000000FFFFFFFF00CFFFFF0000000091
+:1056500000000000000000CC00000000004000003E
+:1056600000000000FFFFFFFF00CFFFFF0000000071
+:1056700000000000000000CC00000000000000005E
+:1056800000000000FFFFFFFF00CFFFFF0000000051
+:1056900000000000000000CC00000000000100003D
+:1056A00000000000FFFFFFFF00CFFFFF0000000031
+:1056B00000000000000000CC00000000000200001C
+:1056C00000000000FFFFFFFF00CFFFFF0000000011
+:1056D00000000000000000CC0000000000040000FA
+:1056E00000000000FFFFFFFF00CFFFFF00000000F1
+:1056F00000000000000000CC0000000000080000D6
+:1057000000000000FFFFFFFF00CFFFFF00000000D0
+:1057100000000000000000CC0000000000100000AD
+:1057200000000000FFFFFFFF00CFFFFF00000000B0
+:1057300000000000000000CC00000000002000007D
+:1057400000000000FFFFFFFF00CFFFFF0000000090
+:1057500000000000000000CC00000000004000003D
+:1057600000000000FFFFFFFF00CFFFFF0000000070
+:1057700000000000000000CC00000000000000005D
+:1057800000000000FFFFFFFF00CFFFFF0000000050
+:1057900000000000000000CC00000000000100003C
+:1057A00000000000FFFFFFFF00CFFFFF0000000030
+:1057B00000000000000000CC00000000000200001B
+:1057C00000000000FFFFFFFF00CFFFFF0000000010
+:1057D00000000000000000CC0000000000040000F9
+:1057E00000000000FFFFFFFF00CFFFFF00000000F0
+:1057F00000000000000000CC0000000000080000D5
+:1058000000000000FFFFFFFF00CFFFFF00000000CF
+:1058100000000000000000CC0000000000100000AC
+:1058200000000000FFFFFFFF00CFFFFF00000000AF
+:1058300000000000000000CC00000000002000007C
+:1058400000000000FFFFFFFF00CFFFFF000000008F
+:1058500000000000000000CC00000000004000003C
+:1058600000000000000000320000003200000200D2
+:1058700000003DFF000002110000020000000204D1
+:105880000000FFFF0000FFFF0000FFFF0000FFFF20
+:105890000000000000000037000000210000002090
+:1058A00000000001000000010000000107FFFFFFF1
+:1058B0000000007F07FFFFFF0000003F0000FFFF28
+:1058C0000000FFFF0000FFFF0000FFFF00007FF867
+:1058D00000007FF800000000000028AD000029183B
+:1058E000000029190000000500000007000000006A
+:1058F000000000000000FF00000000000000FF00AA
+:10590000000000000000FF00000000000000FF0099
+:10591000000000000000FF00000000000000FF0089
+:10592000000000000000FF00000000000000FF0079
+:10593000000000000000FF00000000000000FF0069
+:10594000000000000000FF00000000000000FF0059
+:10595000000000000000FF00000000000000FF0049
+:10596000000000000000FF00000000000000FF0039
+:10597000000000000000FF00000000000000FF0029
+:10598000000000000000FF00000000000000FF0019
+:10599000000000000000FF00000000000000FF0009
+:1059A000000000000000FF00000000000000FF00F9
+:1059B000000000000000FF00000000000000FF00E9
+:1059C000000000000000FF00000000000000FF00D9
+:1059D000000000000000FF00000000000000FF00C9
+:1059E000000000000000FF00000000000000FF00B9
+:1059F000000000000000FF00000000000000FF00A9
+:105A0000000000000000FF00000000000000FF0098
+:105A1000000000000000FF00000000000000FF0088
+:105A2000000000000000FF00000000000000FF0078
+:105A3000000000000000FF00000000000000FF0068
+:105A4000000000000000FF00000000000000FF0058
+:105A5000000000000000FF00000000000000FF0048
+:105A6000000000000000FF00000000000000FF0038
+:105A7000000000000000FF00000000000000FF0028
+:105A8000000000000000FF00000000000000FF0018
+:105A9000000000000000FF00000000000000FF0008
+:105AA000000000000000FF00000000000000FF00F8
+:105AB000000000000000FF00000000000000FF00E8
+:105AC000000000000000FF00000000000000FF00D8
+:105AD000000000000000FF00000000000000FF00C8
+:105AE000000000000000FF00000000000000FF00B8
+:105AF000000000000000FF00000000000000FF00A8
+:105B0000000000000000FF00000000000000FF0097
+:105B1000000000000000FF00000000000000FF0087
+:105B2000000000000000FF00000000000000FF0077
+:105B3000000000000000FF1C0FFFFFFF0000FF1C23
+:105B40000FFFFFFF0000FF1C0FFFFFFF0000FF1C07
+:105B50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF7
+:105B60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE7
+:105B70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD7
+:105B80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC7
+:105B90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB7
+:105BA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA7
+:105BB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C97
+:105BC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C87
+:105BD0000FFFFFFF0000FF1C0FFFFFFF0000FF1C77
+:105BE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C67
+:105BF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C57
+:105C00000FFFFFFF0000FF1C0FFFFFFF0000FF1C46
+:105C10000FFFFFFF0000FF1C0FFFFFFF0000FF1C36
+:105C20000FFFFFFF0000FF1C0FFFFFFF0000FF1C26
+:105C30000FFFFFFF0000FF1C0FFFFFFF0000FF1C16
+:105C40000FFFFFFF0000FF1C0FFFFFFF0000FF1C06
+:105C50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF6
+:105C60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE6
+:105C70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD6
+:105C80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC6
+:105C90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB6
+:105CA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA6
+:105CB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C96
+:105CC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C86
+:105CD0000FFFFFFF0000FF1C0FFFFFFF0000FF1C76
+:105CE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C66
+:105CF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C56
+:105D00000FFFFFFF0000FF1C0FFFFFFF0000FF1C45
+:105D10000FFFFFFF0000FF1C0FFFFFFF0000FF1C35
+:105D20000FFFFFFF0000FF1C0FFFFFFF0000FF1C25
+:105D30000FFFFFFF0000FF1C0FFFFFFF0000FF1C15
+:105D40000FFFFFFF0000FF1C0FFFFFFF0000FF1C05
+:105D50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF5
+:105D60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE5
+:105D70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD5
+:105D80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC5
+:105D90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB5
+:105DA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA5
+:105DB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C95
+:105DC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C85
+:105DD0000FFFFFFF0000FF1C0FFFFFFF0000FF1C75
+:105DE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C65
+:105DF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C55
+:105E00000FFFFFFF0000FF1C0FFFFFFF0000FF1C44
+:105E10000FFFFFFF0000FF1C0FFFFFFF0000FF1C34
+:105E20000FFFFFFF0000FF1C0FFFFFFF0000FF1C24
+:105E30000FFFFFFF0000FF1C0FFFFFFF0000FF1C14
+:105E40000FFFFFFF0000FF1C0FFFFFFF0000FF1C04
+:105E50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF4
+:105E60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE4
+:105E70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD4
+:105E80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC4
+:105E90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB4
+:105EA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA4
+:105EB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C94
+:105EC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C84
+:105ED0000FFFFFFF0000FF1C0FFFFFFF0000FF1C74
+:105EE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C64
+:105EF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C54
+:105F00000FFFFFFF0000FF1C0FFFFFFF0000FF1C43
+:105F10000FFFFFFF0000FF1C0FFFFFFF0000FF1C33
+:105F20000FFFFFFF0000FF1C0FFFFFFF0000FF1C23
+:105F30000FFFFFFF0000FF1C0FFFFFFF0000FF1C13
+:105F40000FFFFFFF0000FF1C0FFFFFFF0000FF1C03
+:105F50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF3
+:105F60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE3
+:105F70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD3
+:105F80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC3
+:105F90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB3
+:105FA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA3
+:105FB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C93
+:105FC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C83
+:105FD0000FFFFFFF0000FF1C0FFFFFFF0000FF1C73
+:105FE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C63
+:105FF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C53
+:106000000FFFFFFF0000FF1C0FFFFFFF0000FF1C42
+:106010000FFFFFFF0000FF1C0FFFFFFF0000FF1C32
+:106020000FFFFFFF0000FF1C0FFFFFFF0000FF1C22
+:106030000FFFFFFF0000FF1C0FFFFFFF0000FF1C12
+:106040000FFFFFFF0000FF1C0FFFFFFF0000FF1C02
+:106050000FFFFFFF0000FF1C0FFFFFFF0000FF1CF2
+:106060000FFFFFFF0000FF1C0FFFFFFF0000FF1CE2
+:106070000FFFFFFF0000FF1C0FFFFFFF0000FF1CD2
+:106080000FFFFFFF0000FF1C0FFFFFFF0000FF1CC2
+:106090000FFFFFFF0000FF1C0FFFFFFF0000FF1CB2
+:1060A0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA2
+:1060B0000FFFFFFF0000FF1C0FFFFFFF0000FF1C92
+:1060C0000FFFFFFF0000FF1C0FFFFFFF0000FF1C82
+:1060D0000FFFFFFF0000FF1C0FFFFFFF0000FF1C72
+:1060E0000FFFFFFF0000FF1C0FFFFFFF0000FF1C62
+:1060F0000FFFFFFF0000FF1C0FFFFFFF0000FF1C52
+:106100000FFFFFFF0000FF1C0FFFFFFF0000FF1C41
+:106110000FFFFFFF0000FF1C0FFFFFFF0000FF1C31
+:106120000FFFFFFF0000FF1C0FFFFFFF0000FF1C21
+:106130000FFFFFFF0000FF1C0FFFFFFF0000FF1C11
+:106140000FFFFFFF0000FF1C0FFFFFFF0000FF1C01
+:106150000FFFFFFF0000FF1C0FFFFFFF0000FF1CF1
+:106160000FFFFFFF0000FF1C0FFFFFFF0000FF1CE1
+:106170000FFFFFFF0000FF1C0FFFFFFF0000FF1CD1
+:106180000FFFFFFF0000FF1C0FFFFFFF0000FF1CC1
+:106190000FFFFFFF0000FF1C0FFFFFFF0000FF1CB1
+:1061A0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA1
+:1061B0000FFFFFFF0000FF1C0FFFFFFF0000FF1C91
+:1061C0000FFFFFFF0000FF1C0FFFFFFF0000FF1C81
+:1061D0000FFFFFFF0000FF1C0FFFFFFF0000FF1C71
+:1061E0000FFFFFFF0000FF1C0FFFFFFF0000FF1C61
+:1061F0000FFFFFFF0000FF1C0FFFFFFF0000FF1C51
+:106200000FFFFFFF0000FF1C0FFFFFFF0000FF1C40
+:106210000FFFFFFF0000FF1C0FFFFFFF0000FF1C30
+:106220000FFFFFFF0000FF1C0FFFFFFF0000FF1C20
+:106230000FFFFFFF0000FF1C0FFFFFFF0000FF1C10
+:106240000FFFFFFF0000FF1C0FFFFFFF0000FF1C00
+:106250000FFFFFFF0000FF1C0FFFFFFF0000FF1CF0
+:106260000FFFFFFF0000FF1C0FFFFFFF0000FF1CE0
+:106270000FFFFFFF0000FF1C0FFFFFFF0000FF1CD0
+:106280000FFFFFFF0000FF1C0FFFFFFF0000FF1CC0
+:106290000FFFFFFF0000FF1C0FFFFFFF0000FF1CB0
+:1062A0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA0
+:1062B0000FFFFFFF0000FF1C0FFFFFFF0000FF1C90
+:1062C0000FFFFFFF0000FF1C0FFFFFFF0000FF1C80
+:1062D0000FFFFFFF0000FF1C0FFFFFFF0000FF1C70
+:1062E0000FFFFFFF0000FF1C0FFFFFFF0000FF1C60
+:1062F0000FFFFFFF0000FF1C0FFFFFFF0000FF1C50
+:106300000FFFFFFF0000FF1C0FFFFFFF0000FF1C3F
+:106310000FFFFFFF0000FF1C0FFFFFFF0000FF1C2F
+:106320000FFFFFFF0000FF1C0FFFFFFF0000FF1C1F
+:106330000FFFFFFF0000FF1C0FFFFFFF0000FF1C0F
+:106340000FFFFFFF0000FF1C0FFFFFFF0000FF1CFF
+:106350000FFFFFFF0000FF1C0FFFFFFF0000FF1CEF
+:106360000FFFFFFF0000FF1C0FFFFFFF0000FF1CDF
+:106370000FFFFFFF0000FF1C0FFFFFFF0000FF1CCF
+:106380000FFFFFFF0000FF1C0FFFFFFF0000FF1CBF
+:106390000FFFFFFF0000FF1C0FFFFFFF0000FF1CAF
+:1063A0000FFFFFFF0000FF1C0FFFFFFF0000FF1C9F
+:1063B0000FFFFFFF000000020000150000000001B9
+:1063C00000000002000000030000000000000004C4
+:1063D00000000001000000000000000100000004B7
+:1063E00000000000000000010000000300000000A9
+:1063F0000000000100000004000000000000000197
+:106400000000000300000000000000010000000484
+:106410000000000000000004000000030000000075
+:106420000000000000007FFF000003FF00000000EC
+:106430000000000100000001000000010000000059
+:10644000000000020000009000000090008000901A
+:1064500008100000000009FF0000076C0000008A1F
+:106460000000008000000081000000800000008A21
+:106470000000008000000081000000800000008A11
+:106480000000008000000081000000800000008A01
+:106490000000008000000081000000800000008AF1
+:1064A000000000800000008100000080000000016A
+:1064B00000000001000000010000000100000001D8
+:1064C00000000001000025E4000025E400004BC8A6
+:1064D00000004BC8000000180000111A00543210D0
+:1064E000000000000021054300000000000025E43A
+:1064F000000025E400004BC800004BC80000001855
+:106500000000111A00543210000000000021054361
+:106510000000000000000001000000010000000178
+:106520000000000000000000000000010000000268
+:10653000000000000000000600000003000000044E
+:106540000000000500000001000000010000000143
+:106550000000000100000001000000010000000137
+:106560000000000100000001000000010000000127
+:106570000000000100000001000000010000000117
+:1065800000000001000000030000600000000003A4
+:106590000000600000000003000040000000030055
+:1065A00000000300000003000000030000000300DF
+:1065B00000000300000003000003F00800000000DA
+:1065C00000000000000000000000000100000001C9
+:1065D00000000001000000010000000100000001B7
+:1065E00000000001000000010000000100000001A7
+:1065F0000000000100000001000000010000000197
+:106600000000000100000001000000010000000186
+:106610000000000100000001000000010000000176
+:106620000000000100000001000000010000000166
+:106630000000000100000001000000010000000156
+:1066400000000001000000FF000000FF000000FF4C
+:10665000000000FF0000007F000000FF000000FFBE
+:10666000000000FF0000003E000000000000003FAE
+:106670000000003F0000003F0000003F0000003F1E
+:106680000000003F0000003F0000000F000000007D
+:106690001217000022170000321700001215000028
+:1066A000221500003215000002100000001000004A
+:1066B00010100000201000003010000040100000FA
+:1066C00000000000000000000000000000100000BA
+:1066D00012140000221400003214000042140000C2
+:1066E000000000000000000000000000000089061B
+:1066F0000000892600000036000000360810000067
+:1067000008100000FFFFFFFFFFFFFFFFFFFFFFFF7D
+:10671000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89
+:10672000FFFFFFFFF000C000FFFFFFFFFFFFFFFFC5
+:10673000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69
+:10674000FFFFFFFFF800C000FFFFFFFFFFFFFFFF9D
+:10675000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49
+:10676000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39
+:10677000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29
+:10678000FFFFFFFF00003C100000000800000008B1
+:1067900000000002000000040000000500000004EA
+:1067A0000000004000001808000008030000080373
+:1067B0000000004000000003000008030000080380
+:1067C00000000803000100030000080300000803A4
+:1067D00000000003000000030000000300000003AD
+:1067E000000000030000000300000003000000039D
+:1067F000000000030000000300000003000000038D
+:106800000000000300000003000000030000240358
+:106810000000002F000000090000001900000184A2
+:1068200000000183000003060000001900000006BC
+:1068300000000306000003060000030600000C86AB
+:10684000000003060000030600000006000000062A
+:106850000000000600000006000000060000000620
+:106860000000000600000006000000060000000610
+:106870000000000600000006000000060000000600
+:1068800000000006000003060000001300000006E0
+:106890000000100400001004001064400010644068
+:1068A000000000400000001900000001000000008E
+:1068B00000000000000000000000000000002000B8
+:1068C00000000000000000000000000000000000C8
+:1068D0000400200000000000000000000000000094
+:1068E0000000000041002000000000000000000047
+:1068F0000000000000000000000020000000007CFC
+:106900000000003D0000003F0000009C0000000C63
+:10691000000000050000000A000000050000005310
+:10692000000025E3000000540000005400000004B3
+:106930000000000400000004000000040000000447
+:10694000000000040000000400000004000000003B
+:106950000000000100000002000000000000000133
+:1069600000000002000000090000000B0000000A07
+:106970000000000000000001000000020000000014
+:106980000000000100000002000000090000000BF0
+:106990000000000A000000090000000B0000000ACF
+:1069A000000000090000000B0000000A00000000C9
+:1069B00000000800000002000000040000000000C9
+:1069C000000000001FFF1FFF1FFF1FFF1FFF1FFF13
+:1069D0001FFF1FFF000025E40000800020002000B2
+:1069E00020002000800080008000800040004000E7
+:1069F000400040000000000000000002000001789C
+:106A00000000017800000000000000000000017894
+:106A10000000000000000000000000000000000175
+:106A20000000000200000000000000000000000064
+:106A3000000000040000000000000001000000024F
+:106A40000000000000000000000000000000000442
+:106A50000000000000000001000000020000000033
+:106A60000000000100000002000000000000000122
+:106A70000000000200000000000000000000000014
+:106A800000000004000000000000000100000002FF
+:106A900000000000000000010000000200000000F3
+:106AA00000000001000000020000000000000000E3
+:106AB0000000000000000004000000130E490E4911
+:106AC0000E490E4900920092009200920124012486
+:106AD000012401240000000000000000100010004C
+:106AE000100010002001012001011001010101012D
+:106AF00020010120010110012001012001011001EC
+:106B00000101010120010120010110010101010128
+:106B100000000004000000060200410402004104DD
+:106B2000020041040200410400000204000002CE01
+:106B3000000002CE0000000000000000000002CCB7
+:106B40000000000000000000000000000000000144
+:106B50000000000200000000000000000000000033
+:106B6000000000040000000000000001000000021E
+:106B70000000000000000000000000000000000411
+:106B8000000000130E490E49000000000000000044
+:106B90001000100010001000200101200101100160
+:106BA000010101012001012001011001200101204A
+:106BB0000101100101010101200101200101100169
+:106BC0000101010102004104020041040000000231
+:106BD00000000000000000020000000000000002B1
+:106BE00000000000000000000000000000000002A3
+:106BF0000000000000000002000000000000000291
+:106C00000000000000000000000000000000000480
+:106C100000000006020041040200410400000001DF
+:106C20000000000100000001000000010000000160
+:106C30000000000100000001000000010000000150
+:106C40000000000100000001000000010000000140
+:106C50000000000100000001000000010000000130
+:106C6000000000030255555502555555000002CE4F
+:106C7000000002CE000002CE000002CE000002CED4
+:106C8000000002CE000002CC0000005400000054BE
+:106C9000000000540000005400000000000000014B
+:106CA00000000002000000000000000600000003D9
+:106CB00000000004000000050000000000000001CA
+:106CC00000000002000000000000000000000000C2
+:106CD00000000006000000000000000100000002AB
+:106CE000000000000000000000000000000000069E
+:106CF0000000000000000001000000020000000091
+:106D0000000000010000000200000000000000017F
+:106D10000000000200000000000000000000000071
+:106D2000000000060000000000000001000000025A
+:106D30000000000000000001000000020000000050
+:106D40000000000100000002000000000000000040
+:106D500000000000000000060E490E490E490E49D1
+:106D60000092009200920092012401240124012447
+:106D7000100010001000100020010120010110017E
+:106D80000101010120010120010110012001012068
+:106D90000101100101010101200101200101100187
+:106DA00001010101000000040000000600000000D5
+:106DB00000000001000000020000000000000000D0
+:106DC00000000000000000060000000000000001BC
+:106DD00000000002000000000000000000000000B1
+:106DE0000000000600000003000000040000000591
+:106DF0000000000300000004000000050000000384
+:106E00000000000400000005000000030000000373
+:106E10000000000300000006000000030000000462
+:106E20000000000500000003000000040000000551
+:106E30000000000300000004000000050000000343
+:106E40000000000300000003000000060E490E4988
+:106E500000000000009200920000000001240124C4
+:106E600000000000000000000E490E490000000074
+:106E70000092009200000000012401241000100084
+:106E80001000100020010120010110010101010189
+:106E90002001012001011001200101200101100148
+:106EA0000101010120010120010110010101010185
+:106EB00000000001000000030000000400000003C7
+:106EC00000000004000000050000000300000006B0
+:106ED00000000005000000040000000300000004A2
+:106EE000000000050000000300000006000000058F
+:106EF0000000000400000003000000040000000087
+:106F0000000000010000000200000000000000017D
+:106F10000000000200000005000000030000000661
+:106F20000000000500000004000000030000000451
+:106F3000000000000000000100000002000000004E
+:106F40000000000100000002000000050000000336
+:106F50000000000600000005004800480048004806
+:106F6000009000900090009001200120012001205D
+:106F700004020402040204020005000500050005E5
+:106F80001200120012001200080008000800080099
+:106F90000120012001011020010101200120012018
+:106FA0000101102001200120010110200101012018
+:106FB0000120012001011020010101200000000436
+:106FC000000000060000012300000123000001234F
+:106FD0000000012300000123000001230000012321
+:106FE0000000012300000123000001230000012311
+:106FF0000000012300000123000001230000012301
+:1070000000000123000001230000012300000123F0
+:1070100000000123000000200000003200000007F3
+:107020000000000700000000000000080000000150
+:107030000000000000000000000000000215002019
+:10704000021500200000003008100000000000368B
+:1070500000000030000000310000000400000005C6
+:107060000000000000000004000000010000000615
+:10707000000000010000000200000040000000408D
+:107080000000001C000000200001000000020700BA
+:1070900000030E000004150000051C00000623007C
+:1070A00000072A000008310000093800000A3F00EC
+:1070B000000B4600000C4D00000D5400000E5B005C
+:1070C000000F6200001069000011700000127700CC
+:1070D00000137E000014850000158C00001693003C
+:1070E00000179A000018A1000019A800001AAF00AC
+:1070F000001BB600001CBD00001DC400001ECB001C
+:10710000001FD2000000D9000000001E0000001D7A
+:10711000000100000002078000030F000004168039
+:1071200000051E000006258000072D0000083480A1
+:1071300000093C00000A4380000B4B00000C528009
+:10714000000D5A00000E6180000F69000010708071
+:107150000011780000127F800013870000148E80D9
+:107160000015960000169D800017A5000018AC8041
+:107170000019B400001ABB80001BC300001CCA80A9
+:107180000000D2000000000100000001000000012A
+:1071900000000001000000010000000100000001EB
+:1071A00000000001000000010000000100000001DB
+:1071B00000000001000000010000000100000001CB
+:1071C00000000001000000280000002C000000303A
+:1071D0000000000100000001000000010000021199
+:1071E0000000020000000204000002190000FFFF7E
+:1071F0000000FFFF0000FFFF0000FFFF0000002075
+:1072000000000021000000010000000107FFFFFF57
+:107210000000007F07FFFFFF0000003F0000FFFFAE
+:107220000000FFFF0000FFFF0000FFFF00007FF8ED
+:1072300000007FF800000000000000010000FF00D7
+:10724000000000000000FF00000000000000FF0040
+:10725000000000000000FF00000000000000FF0030
+:10726000000000000000FF00000000000000FF0020
+:10727000000000000000FF00000000000000FF0010
+:10728000000000000000FF00000000000000FF0000
+:10729000000000000000FF00000000000000FF00F0
+:1072A000000000000000FF00000000000000FF00E0
+:1072B000000000000000FF00000000000000FF00D0
+:1072C000000000000000FF00000000000000FF00C0
+:1072D000000000000000FF00000000000000FF00B0
+:1072E000000000000000FF00000000000000FF00A0
+:1072F000000000000000FF00000000000000FF0090
+:10730000000000000000FF00000000000000FF007F
+:10731000000000000000FF00000000000000FF006F
+:10732000000000000000FF00000000000000FF005F
+:10733000000000000000FF00000000000000FF004F
+:10734000000000000000FF00000000000000FF003F
+:10735000000000000000FF00000000000000FF002F
+:10736000000000000000FF00000000000000FF001F
+:10737000000000000000FF00000000000000FF000F
+:10738000000000000000FF00000000000000FF00FF
+:10739000000000000000FF00000000000000FF00EF
+:1073A000000000000000FF00000000000000FF00DF
+:1073B000000000000000FF00000000000000FF00CF
+:1073C000000000000000FF00000000000000FF00BF
+:1073D000000000000000FF00000000000000FF00AF
+:1073E000000000000000FF00000000000000FF009F
+:1073F000000000000000FF00000000000000FF008F
+:10740000000000000000FF00000000000000FF007E
+:10741000000000000000FF00000000000000FF006E
+:10742000000000000000FF00000000000000FF005E
+:10743000000000000000FF00000000000000FF004E
+:10744000000000000000FF00000000000000FF003E
+:10745000000000000000FF00000000000000FF002E
+:10746000000000000000FF00000000000000FF001E
+:10747000000000000000FF000000000000201001DC
+:107480000000000001009000000001000000000169
+:107490000000000000000000140AFF00000090023D
+:1074A0000000000000000000000000000000900448
+:1074B0000000000000000000000000000000900636
+:1074C0000000000000000000000000000000900824
+:1074D0000000000000000000000000000000900A12
+:1074E0000000000000000000000000000000900C00
+:1074F0000000000000000000000000000000900EEE
+:1075000000000000000000000000000000009010DB
+:1075100000000000000000000000000000009012C9
+:1075200000000000000000000000000000009014B7
+:1075300000000000000000000000000000009016A5
+:107540000000000000000000000000000000901893
+:107550000000000000000000000000000000901A81
+:107560000000000000000000000000000000901C6F
+:107570000000000000000000000000000000901E5D
+:10758000000000000000000000000000000090204B
+:107590000000000000000000000000000000902239
+:1075A0000000000000000000000000000000902427
+:1075B0000000000000000000000000000000902615
+:1075C0000000000000000000000000000000902803
+:1075D0000000000000000000000000000000902AF1
+:1075E0000000000000000000000000000000902CDF
+:1075F0000000000000000000000000000000902ECD
+:1076000000000000000000000000000000009030BA
+:1076100000000000000000000000000000009032A8
+:107620000000000000000000000000000000903496
+:107630000000000000000000000000000000903684
+:107640000000000000000000000000000000903872
+:107650000000000000000000000000000000903A60
+:107660000000000000000000000000000000903C4E
+:107670000000000000000000000000000000903E3C
+:10768000000000000000000000000000000090402A
+:107690000000000000000000000000000000904218
+:1076A0000000000000000000000000000000904406
+:1076B00000000000000000000000000000009046F4
+:1076C00000000000000000000000000000009048E2
+:1076D0000000000000000000000000000000904AD0
+:1076E0000000000000000000000000000000904CBE
+:1076F0000000000000000000000000000000904EAC
+:107700000000000000000000000000000000905099
+:107710000000000000000000000000000000905287
+:107720000000000000000000000000000000905475
+:107730000000000000000000000000000000905663
+:107740000000000000000000000000000000905851
+:107750000000000000000000000000000000905A3F
+:107760000000000000000000000000000000905C2D
+:107770000000000000000000000000000000905E1B
+:107780000000000000000000000000000000906009
+:1077900000000000000000000000000000009062F7
+:1077A00000000000000000000000000000009064E5
+:1077B00000000000000000000000000000009066D3
+:1077C00000000000000000000000000000009068C1
+:1077D0000000000000000000000000000000906AAF
+:1077E0000000000000000000000000000000906C9D
+:1077F0000000000000000000000000000000906E8B
+:107800000000000000000000000000000000907078
+:107810000000000000000000000000000000907266
+:107820000000000000000000000000000000907454
+:107830000000000000000000000000000000907642
+:107840000000000000000000000000000000907830
+:107850000000000000000000000000000000907A1E
+:107860000000000000000000000000000000907C0C
+:107870000000000000000000000000000000907EFA
+:1078800000000000000000000000000000009080E8
+:1078900000000000000000000000000000009082D6
+:1078A00000000000000000000000000000009084C4
+:1078B00000000000000000000000000000009086B2
+:1078C00000000000000000000000000000009088A0
+:1078D0000000000000000000000000000000908A8E
+:1078E0000000000000000000000000000000908C7C
+:1078F0000000000000000000000000000000908E6A
+:107900000000000000000000000000000000909057
+:107910000000000000000000000000000000909245
+:107920000000000000000000000000000000909433
+:107930000000000000000000000000000000909621
+:10794000000000000000000000000000000090980F
+:107950000000000000000000000000000000909AFD
+:107960000000000000000000000000000000909CEB
+:107970000000000000000000000000000000909ED9
+:10798000000000000000000000000000000090A0C7
+:10799000000000000000000000000000000090A2B5
+:1079A000000000000000000000000000000090A4A3
+:1079B000000000000000000000000000000090A691
+:1079C000000000000000000000000000000090A87F
+:1079D000000000000000000000000000000090AA6D
+:1079E000000000000000000000000000000090AC5B
+:1079F000000000000000000000000000000090AE49
+:107A0000000000000000000000000000000090B036
+:107A1000000000000000000000000000000090B224
+:107A2000000000000000000000000000000090B412
+:107A3000000000000000000000000000000090B600
+:107A4000000000000000000000000000000090B8EE
+:107A5000000000000000000000000000000090BADC
+:107A6000000000000000000000000000000090BCCA
+:107A7000000000000000000000000000000090BEB8
+:107A8000000000000000000000000000000090C0A6
+:107A9000000000000000000000000000000090C294
+:107AA000000000000000000000000000000090C482
+:107AB000000000000000000000000000000090C670
+:107AC000000000000000000000000000000090C85E
+:107AD000000000000000000000000000000090CA4C
+:107AE000000000000000000000000000000090CC3A
+:107AF000000000000000000000000000000090CE28
+:107B0000000000000000000000000000000090D015
+:107B1000000000000000000000000000000090D203
+:107B2000000000000000000000000000000090D4F1
+:107B3000000000000000000000000000000090D6DF
+:107B4000000000000000000000000000000090D8CD
+:107B5000000000000000000000000000000090DABB
+:107B6000000000000000000000000000000090DCA9
+:107B7000000000000000000000000000000090DE97
+:107B8000000000000000000000000000000090E085
+:107B9000000000000000000000000000000090E273
+:107BA000000000000000000000000000000090E461
+:107BB000000000000000000000000000000090E64F
+:107BC000000000000000000000000000000090E83D
+:107BD000000000000000000000000000000090EA2B
+:107BE000000000000000000000000000000090EC19
+:107BF000000000000000000000000000000090EE07
+:107C0000000000000000000000000000000090F0F4
+:107C1000000000000000000000000000000090F2E2
+:107C2000000000000000000000000000000090F4D0
+:107C3000000000000000000000000000000090F6BE
+:107C4000000000000000000000000000000090F8AC
+:107C5000000000000000000000000000000090FA9A
+:107C6000000000000000000000000000000090FC88
+:107C7000000000000000000000000000000090FE76
+:107C80000000000000000000000000000000910063
+:107C90000000000000000000000000000000910251
+:107CA000000000000000000000000000000091043F
+:107CB000000000000000000000000000000091062D
+:107CC000000000000000000000000000000091081B
+:107CD0000000000000000000000000000000910A09
+:107CE0000000000000000000000000000000910CF7
+:107CF0000000000000000000000000000000910EE5
+:107D000000000000000000000000000000009110D2
+:107D100000000000000000000000000000009112C0
+:107D200000000000000000000000000000009114AE
+:107D3000000000000000000000000000000091169C
+:107D4000000000000000000000000000000091188A
+:107D50000000000000000000000000000000911A78
+:107D60000000000000000000000000000000911C66
+:107D70000000000000000000000000000000911E54
+:107D80000000000000000000000000000000912042
+:107D90000000000000000000000000000000912230
+:107DA000000000000000000000000000000091241E
+:107DB000000000000000000000000000000091260C
+:107DC00000000000000000000000000000009128FA
+:107DD0000000000000000000000000000000912AE8
+:107DE0000000000000000000000000000000912CD6
+:107DF0000000000000000000000000000000912EC4
+:107E000000000000000000000000000000009130B1
+:107E1000000000000000000000000000000091329F
+:107E2000000000000000000000000000000091348D
+:107E3000000000000000000000000000000091367B
+:107E40000000000000000000000000000000913869
+:107E50000000000000000000000000000000913A57
+:107E60000000000000000000000000000000913C45
+:107E70000000000000000000000000000000913E33
+:107E80000000000000000000000000000000914021
+:107E9000000000000000000000000000000091420F
+:107EA00000000000000000000000000000009144FD
+:107EB00000000000000000000000000000009146EB
+:107EC00000000000000000000000000000009148D9
+:107ED0000000000000000000000000000000914AC7
+:107EE0000000000000000000000000000000914CB5
+:107EF0000000000000000000000000000000914EA3
+:107F00000000000000000000000000000000915090
+:107F1000000000000000000000000000000091527E
+:107F2000000000000000000000000000000091546C
+:107F3000000000000000000000000000000091565A
+:107F40000000000000000000000000000000915848
+:107F50000000000000000000000000000000915A36
+:107F60000000000000000000000000000000915C24
+:107F70000000000000000000000000000000915E12
+:107F80000000000000000000000000000000916000
+:107F900000000000000000000000000000009162EE
+:107FA00000000000000000000000000000009164DC
+:107FB00000000000000000000000000000009166CA
+:107FC00000000000000000000000000000009168B8
+:107FD0000000000000000000000000000000916AA6
+:107FE0000000000000000000000000000000916C94
+:107FF0000000000000000000000000000000916E82
+:10800000000000000000000000000000000091706F
+:10801000000000000000000000000000000091725D
+:10802000000000000000000000000000000091744B
+:108030000000000000000000000000000000917639
+:108040000000000000000000000000000000917827
+:108050000000000000000000000000000000917A15
+:108060000000000000000000000000000000917C03
+:108070000000000000000000000000000000917EF1
+:1080800000000000000000000000000000009180DF
+:1080900000000000000000000000000000009182CD
+:1080A00000000000000000000000000000009184BB
+:1080B00000000000000000000000000000009186A9
+:1080C0000000000000000000000000000000918897
+:1080D0000000000000000000000000000000918A85
+:1080E0000000000000000000000000000000918C73
+:1080F0000000000000000000000000000000918E61
+:10810000000000000000000000000000000091904E
+:10811000000000000000000000000000000091923C
+:10812000000000000000000000000000000091942A
+:108130000000000000000000000000000000919618
+:108140000000000000000000000000000000919806
+:108150000000000000000000000000000000919AF4
+:108160000000000000000000000000000000919CE2
+:108170000000000000000000000000000000919ED0
+:10818000000000000000000000000000000091A0BE
+:10819000000000000000000000000000000091A2AC
+:1081A000000000000000000000000000000091A49A
+:1081B000000000000000000000000000000091A688
+:1081C000000000000000000000000000000091A876
+:1081D000000000000000000000000000000091AA64
+:1081E000000000000000000000000000000091AC52
+:1081F000000000000000000000000000000091AE40
+:10820000000000000000000000000000000091B02D
+:10821000000000000000000000000000000091B21B
+:10822000000000000000000000000000000091B409
+:10823000000000000000000000000000000091B6F7
+:10824000000000000000000000000000000091B8E5
+:10825000000000000000000000000000000091BAD3
+:10826000000000000000000000000000000091BCC1
+:10827000000000000000000000000000000091BEAF
+:10828000000000000000000000000000000091C09D
+:10829000000000000000000000000000000091C28B
+:1082A000000000000000000000000000000091C479
+:1082B000000000000000000000000000000091C667
+:1082C000000000000000000000000000000091C855
+:1082D000000000000000000000000000000091CA43
+:1082E000000000000000000000000000000091CC31
+:1082F000000000000000000000000000000091CE1F
+:10830000000000000000000000000000000091D00C
+:10831000000000000000000000000000000091D2FA
+:10832000000000000000000000000000000091D4E8
+:10833000000000000000000000000000000091D6D6
+:10834000000000000000000000000000000091D8C4
+:10835000000000000000000000000000000091DAB2
+:10836000000000000000000000000000000091DCA0
+:10837000000000000000000000000000000091DE8E
+:10838000000000000000000000000000000091E07C
+:10839000000000000000000000000000000091E26A
+:1083A000000000000000000000000000000091E458
+:1083B000000000000000000000000000000091E646
+:1083C000000000000000000000000000000091E834
+:1083D000000000000000000000000000000091EA22
+:1083E000000000000000000000000000000091EC10
+:1083F000000000000000000000000000000091EEFE
+:10840000000000000000000000000000000091F0EB
+:10841000000000000000000000000000000091F2D9
+:10842000000000000000000000000000000091F4C7
+:10843000000000000000000000000000000091F6B5
+:10844000000000000000000000000000000091F8A3
+:10845000000000000000000000000000000091FA91
+:10846000000000000000000000000000000091FC7F
+:10847000000000000000000000000000000091FE6D
+:10848000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC
+:10849000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC
+:1084A0000000FFFF00000000FFFFFFFFFFFFFFFFD6
+:1084B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC
+:1084C000FFFFFFFFFFFFFFFF0000FFFF00000000B6
+:1084D0000000000200001500000000010000000282
+:1084E0000000000300000000000000040000000184
+:1084F0000000000000000001000000040000000077
+:108500000000000100000003000000000000000166
+:108510000000000400000000000000010000000353
+:108520000000000000000001000000040000000046
+:108530000000000400000003000000000000000034
+:1085400000007FFF000003FFFFFFFFFFFFFFFFFFB3
+:10855000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B
+:10856000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B
+:10857000FFFFFFFFFFFFFFFF0000000300BEBC2066
+:1085800000000000000000050000000300BEBC2049
+:1085900000000000000000050000000300BEBC2039
+:1085A00000000000000000050000000300BEBC2029
+:1085B00000000000000000050000000300BEBC2019
+:1085C00000000000000000050000000300BEBC2009
+:1085D00000000000000000050000000300BEBC20F9
+:1085E00000000000000000050000000300BEBC20E9
+:1085F00000000000000000050000000D0000000C5D
+:1086000000000000000000100000000F000000004B
+:1086100000000000000000000215002002150020EC
+:10862000000000300810000000000036000000309C
+:108630000000003100000003000000000000000105
+:1086400000000003000000010000000200000040E4
+:108650000000004000000004000000200000000FA7
+:108660000000001B00008000000103C000018780A3
+:1086700000020B4000028F00000312C0000396802E
+:1086800000041A4000049E00000521C00005A580DA
+:10869000000629400006AD00000730C00007B48086
+:1086A000000838400008BC0000093FC00009C38032
+:1086B000000A4740000ACB00000B4EC0000BD280DE
+:1086C000000C5640000CDA00000D5DC00000618017
+:1086D0000000000100000001000000010000000196
+:1086E0000000000100000001000000010000000186
+:1086F0000000000100000001000000010000000176
+:108700000000000100000001000000010000000165
+:10871000000000010000050E000004FD000005013E
+:108720000000051E0000FFFF0000FFFF0000FFFF2C
+:108730000000FFFF000000460000000C00000000E9
+:10874000000000000000001C000000F40000000118
+:108750000000000000000000000000000000000118
+:108760000000000107FFFFFF0000007F07FFFFFF81
+:108770000000003F0000FFFF0000FFFF0000FFFFC0
+:108780000000FFFF00007FF800007FF80000FF00FE
+:10879000000000000000FF00000000000000FF00DB
+:1087A000000000000000FF00000000000000FF00CB
+:1087B000000000000000FF00000000000000FF00BB
+:1087C000000000000000FF00000000000000FF00AB
+:1087D000000000000000FF00000000000000FF009B
+:1087E000000000000000FF00000000000000FF008B
+:1087F000000000000000FF00000000000000FF007B
+:10880000000000000000FF00000000000000FF006A
+:10881000000000000000FF00000000000000FF005A
+:10882000000000000000FF00000000000000FF004A
+:10883000000000000000FF00000000000000FF003A
+:10884000000000000000FF00000000000000FF002A
+:10885000000000000000FF00000000000000FF001A
+:10886000000000000000FF00000000000000FF000A
+:10887000000000000000FF00000000000000FF00FA
+:10888000000000000000FF00000000000000FF00EA
+:10889000000000000000FF00000000000000FF00DA
+:1088A000000000000000FF00000000000000FF00CA
+:1088B000000000000000FF00000000000000FF00BA
+:1088C000000000000000FF00000000000000FF00AA
+:1088D000000000000000FF00000000000000FF009A
+:1088E000000000000000FF00000000000000FF008A
+:1088F000000000000000FF00000000000000FF007A
+:10890000000000000000FF00000000000000FF0069
+:10891000000000000000FF00000000000000FF0059
+:10892000000000000000FF00000000000000FF0049
+:10893000000000000000FF00000000000000FF0039
+:10894000000000000000FF00000000000000FF0029
+:10895000000000000000FF00000000000000FF0019
+:10896000000000000000FF00000000000000FF0009
+:10897000000000000000FF00000000000000FF00F9
+:10898000000000000000FF00000000000000FF00E9
+:10899000000000000000FF00000000000000FF00D9
+:1089A000000000000000FF00000000000000FF00C9
+:1089B000000000000000FF00000000000000FF00B9
+:1089C000000000000000FF0000000000FFFFFFFFAC
+:1089D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7
+:1089E000FFFFFFFFFFFFFFFFFFFFFFFF000019007A
+:1089F0000000000000000001000000000000000076
+:108A0000000000000000000200001500000000014E
+:108A1000000000020000000300000000000000044D
+:108A20000000000100000000000000010000000440
+:108A30000000000000000001000000030000000032
+:108A40000000000100000004000000000000000120
+:108A5000000000030000000000000001000000040E
+:108A600000000000000000040000000300000000FF
+:108A70000000000000007FFF000003FF0000000076
+:108A800003938700000000000000000000000000C9
+:108A90000393870000000000000000000000000FAA
+:108AA00000000007000000000000000E0000000EA3
+:108AB000000000000000000000000000031500207E
+:108AC00003150020010000300810000000000036EF
+:108AD000000000300000003100000002000000052E
+:108AE000000000020000000200000000000000057D
+:108AF000000000030000000100000004000000016D
+:108B000000000002000000400000004000000004DF
+:108B10000000002000000002000000200000100003
+:108B20000000208000003100000041800000520061
+:108B30000000628000007300000083800000940049
+:108B40000000A4800000B5000000C5800000D60031
+:108B50000000E6800000F700000107800001180017
+:108B600000012880000139000001498000015A00FD
+:108B700000016A8000017B0000018B8000019C00E5
+:108B80000001AC800001BD000001CD800001DE00CD
+:108B90000001EE800001FF0000000F8000000001D6
+:108BA00000000001000000010000000100000001C1
+:108BB00000000001000000010000000100000001B1
+:108BC00000000001000000010000000100000001A1
+:108BD0000000000100000001000000010000000191
+:108BE000000000010000000100000001000012145C
+:108BF00000001200000012040000FFFF0000FFFF51
+:108C00000000FFFF0000FFFF000000200000003810
+:108C1000000000000000000000000023000000240D
+:108C20000000002500000026000000270000003999
+:108C30000000003A0000002B0000002C00000000A3
+:108C4000000000EC00000000000000290000002AE5
+:108C50000000000100000001000000010000000110
+:108C60000000000000000000000000000000000103
+:108C700007FFFFFF0000007F07FFFFFF0000003F2E
+:108C80000000FFFF0000FFFF0000FFFF0000FFFFEC
+:108C900000007FF800007FF80000000000000001E5
+:108CA000CCCC0201CCCCCCCCCCCC0201CCCCCCCC2E
+:108CB000CCCC0201CCCCCCCCCCCC0201CCCCCCCC1E
+:108CC000CCCC0201CCCCCCCCCCCC0201CCCCCCCC0E
+:108CD000CCCC0201CCCCCCCCCCCC0201CCCCCCCCFE
+:108CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94
+:108CF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84
+:108D00000000000000010001001E0C07CCCCCCC903
+:108D100010000000000028AD0000291800002919EB
+:108D20000000000000000000000000050000000638
+:108D30007058103C000000000000FF000000000020
+:108D40000000FF00000000000000FF000000000025
+:108D50000000FF00000000000000FF000000000015
+:108D60000000FF00000000000000FF000000000005
+:108D70000000FF00000000000000FF0000000000F5
+:108D80000000FF00000000000000FF0000000000E5
+:108D90000000FF00000000000000FF0000000000D5
+:108DA0000000FF00000000000000FF0000000000C5
+:108DB0000000FF00000000000000FF0000000000B5
+:108DC0000000FF00000000000000FF0000000000A5
+:108DD0000000FF00000000000000FF000000000095
+:108DE0000000FF00000000000000FF000000000085
+:108DF0000000FF00000000000000FF000000000075
+:108E00000000FF00000000000000FF000000000064
+:108E10000000FF00000000000000FF000000000054
+:108E20000000FF00000000000000FF000000000044
+:108E30000000FF00000000000000FF000000000034
+:108E40000000FF00000000000000FF000000000024
+:108E50000000FF00000000000000FF000000000014
+:108E60000000FF00000000000000FF000000000004
+:108E70000000FF00000000000000FF0000000000F4
+:108E80000000FF00000000000000FF0000000000E4
+:108E90000000FF00000000000000FF0000000000D4
+:108EA0000000FF00000000000000FF0000000000C4
+:108EB0000000FF00000000000000FF0000000000B4
+:108EC0000000FF00000000000000FF0000000000A4
+:108ED0000000FF00000000000000FF000000000094
+:108EE0000000FF00000000000000FF000000000084
+:108EF0000000FF00000000000000FF000000000074
+:108F00000000FF00000000000000FF000000000063
+:108F10000000FF00000000000000FF000000000053
+:108F20000000FF00000000000000FF000000000043
+:108F30000000FF00000000000000FF000000000033
+:108F40000000FF00000000000000FF000000000023
+:108F50000000FF00000000000000FF000000000013
+:108F60000000FF00000000000000FF000000000003
+:108F70000000FF0000000000FFFFFFFFFFFFFFFFFA
+:108F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1
+:108F9000FFFFFFFFFFFFFFFF0000FFFF00000000DB
+:108FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1
+:108FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1
+:108FC0000000FFFF0000000003231303130323131B
+:108FD00003030323A0B0904302000200060406042A
+:108FE000032313031303231303030323A0B09043AA
+:108FF000131313131313131313131313A0B090436A
+:109000000301020000000000000000020000150043
+:10901000000000010000000200000003000000004A
+:10902000000000040000000100000000000000013A
+:109030000000000400000000000000010000000328
+:10904000000000000000000100000004000000001B
+:10905000000000010000000300000000000000010B
+:1090600000000004000000000000000400000003F5
+:10907000000000000000000000007FFF000003FF70
+:10908000002625A000000000002625A0000000000A
+:10909000002625A000000000002625A000000000FA
+:1090A000000E0000011600D6002625A000000000DA
+:1090B000002625A000000000002625A000000000DA
+:1090C000002625A00000000000720000012300F32C
+:1090D0000000FFFF000000000000FFFF0000000094
+:1090E0000000FFFF000000000000FFFF0000000084
+:1090F0000000FFFF000000000000FFFF0000000074
+:1091000000000000000000000000FFFF0000000061
+:109110000000FFFF000000000000FFFF0000000053
+:109120000000FFFF000000000000FFFF0000000043
+:109130000000FFFF000000000000FFFF0000000033
+:1091400000000000000000000000FFFF0000000021
+:109150000000FFFF000000000000FFFF0000000013
+:109160000000FFFF000000000000FFFF0000000003
+:109170000000FFFF000000000000FFFF00000000F3
+:1091800000000000000000000000FFFF00000000E1
+:109190000000FFFF000000000000FFFF00000000D3
+:1091A0000000FFFF000000000000FFFF00000000C3
+:1091B0000000FFFF000000000000FFFF00000000B3
+:1091C00000000000000000000000FFFF00000000A1
+:1091D0000000FFFF000000000000FFFF0000000093
+:1091E0000000FFFF000000000000FFFF0000000083
+:1091F0000000FFFF000000000000FFFF0000000073
+:1092000000000000000000000000FFFF0000000060
+:109210000000FFFF000000000000FFFF0000000052
+:109220000000FFFF000000000000FFFF0000000042
+:109230000000FFFF000000000000FFFF0000000032
+:1092400000000000000000000000FFFF0000000020
+:109250000000FFFF000000000000FFFF0000000012
+:109260000000FFFF000000000000FFFF0000000002
+:109270000000FFFF000000000000FFFF00000000F2
+:1092800000000000000000000000FFFF00000000E0
+:109290000000FFFF000000000000FFFF00000000D2
+:1092A0000000FFFF000000000000FFFF00000000C2
+:1092B0000000FFFF000000000000FFFF00000000B2
+:1092C00000000000000000000000FFFF00000000A0
+:1092D000555400005555555500005555F0000000F7
+:1092E000555400005555555500005555F0000000E7
+:1092F0000000000000010000000050140000000009
+:10930000FFF55FFF0000FFFFF00003E0000000003A
+:109310000000A000000004000000000000000000A9
+:10932000000000000000100000000000000000002D
+:1093300000000000000040000000000000000000ED
+:109340000000000000010000FF5C0000FFF55FFF6F
+:109350000000FFFFF00003E0000000000000A0009C
+:1093600000000800000000000000000000000000F5
+:1093700000002000000000000000000000000000CD
+:10938000000080000000000000000000000000005D
+:1093900000020000000000001F8B08000000000019
+:1093A000000BFB51CFC0F003099F9240E57FE145E0
+:1093B000E5A3E345FCF8E509611E06A01DDCE4EB2E
+:1093C0008F011A9006C4F379D0DCCD08A10FB23317
+:1093D00030E4B33130F403E9ED2C08F9340608ED3C
+:1093E0006788105BAEC7C0C0AC03619BE850E6AFB6
+:1093F000513C34B0B60D2A5FC50A42AFB486D03AAC
+:1094000068F2AA50F95B66105AD706BBB9B7CD8887
+:10941000B37F82332A5FDC19BF7A260F080D002A3A
+:1094200039881AB8030000000000000000000000A6
+:109430001F8B080000000000000BCD7D0D781CD5AF
+:1094400075E89DBFDDD9DDD9DDB1B49257B224CF27
+:10945000CAB2BD0619C6B66C6462C248982012D161
+:109460002CC64D0575D3B5318E92989785B889680D
+:109470000C1A593F9625FFC88606FFB3363F2529AB
+:109480004D1742F2685E9AB7226E63FA68A3380EEF
+:1094900031AD49D6409CA4CDF7AA902626EF23F5FE
+:1094A000BBE7DC3BD2CC6A25630869D43AC39D9FF5
+:1094B0007BCF3DF7FC9F73EFFAB53AB2E07A422ECC
+:1094C000C21FBD5AD97B3B488C9032229A43F4DAB2
+:1094D0005BF32B9B18846C27F46F25210370ADA2DE
+:1094E000FFE265D8CE68F4E172426C61453E41DF2F
+:1094F000D72C755C320991B41C49371262747DEE29
+:109500009102BDFF4B5B26434DF4BDD6CC5F42DBE1
+:10951000DEE6D77BE9F5E1D0038F14E8FD2E59D5BF
+:10952000FD26749EB926B5988EDB4D487E21B6AFD8
+:1095300086B64C41CB354EC2E95CE71091900A7873
+:10954000AF463F1F22F8775182FFED2239DAAF7C18
+:109550005ACA0E2568F36CBA855452B8D82BF4DA7F
+:109560009EFF9FF479FC0632EE5F39D99FA4FB4839
+:109570005EE5FDE08BEBA2696DEAB8CEB5EBECFAE7
+:10958000EC09D7FB8D241C43386422031CF4919909
+:10959000A7E3F84F4BE61099BE9F0BDDE9EC89F984
+:1095A00080AF3F8EC27CA77BCFC14B7FB74AF27E94
+:1095B0004286BA75BC2A3574E9289C0AC5D333148F
+:1095C0004F4ACC26848E3B58537F3C2410E2030044
+:1095D000611D1A8CE343B4FD0122E0BA0DD6EC53B1
+:1095E000AD19E6471A283E927C7EF5D00FEB97D452
+:1095F00090ECE3D02F1DF7381DCF172F1E4FC5B6A7
+:1096000033DEDA77389E9FDC164D85E9322C2264F2
+:109610004C03BCD2715CDF1383AD976CB0F72F8520
+:109620003F591327FBA7FF7CB1A0A71D4A9679D706
+:10963000BF98AEE2242937019E8326CCEB7621BD6C
+:1096400019E8CF38F1C7561FC5EF1B16191FAA001E
+:10965000FCA709D00D017C217D120BE80FBBA2B045
+:10966000B6BC29E37A044D92857EC2A480C4192534
+:109670001451F30899450C8111AB29C0FC0959A577
+:109680009FBF927E1270E8FBDDF6B70EFB13ACBDF8
+:10969000E462E86DF427D3FEE6FD16FBBB047C0113
+:1096A0007218FBA3DC1DBB584EC80E4AEF9418E895
+:1096B000FF07185D3512E4EB5E4AFF707F7B771C75
+:1096C000AF44FE8A25821C327DC61095279AFE4C37
+:1096D0001EDED7BFE127D138F4CFE84B84F59C07D5
+:1096E000EB4DCE8957D1ABE9E57BB5C6E7A18B62DF
+:1096F0003AE8AF58303B5D421E4DD0251500097544
+:10970000F2FDE9DE7BAFAF202F128A9BFEEB5128E2
+:109710004D372FA931CD904352C4CD47B248D22006
+:109720007F7BB50D2ACC9BBC75F1A2B4C2254FB589
+:109730005473297C9C2209E47BA7ADE803F7081148
+:109740007A8D6FB40A2E384EC37F2C87FB9BADC237
+:109750000C7897E454C77A903F4DC47C9CD2D5DEF8
+:10976000D047C9B946D0231FC5751EA8A84CF841DB
+:10977000DE936DD81F5135A2AE98A4C3D18A8FC491
+:109780000BF4FDFEAA8FC4418EF42BA9788AB64F44
+:10979000567CD5827E07DE8A12D04303F1FA28CCAC
+:1097A00067E0AD79B33325E61502894AE10F025C23
+:1097B000094657243909A74DD28309DA5FE8249571
+:1097C000FB08E7372C89B67D869C81FE7D1A1D97A4
+:1097D0008EDFD694B3D6537AF5A5B5B45F9FDA8FF2
+:1097E000330EFD132E52BE21F08EC35782E7794906
+:1097F000388ADBBE0611F9478E916C6F89F71535F3
+:109800006287AE02F936715F87711B5E5C8C7215E0
+:10981000DE3754185AB0807F26E93DEB5967A28B9A
+:1098200093FDD60337D88302E841A266802F8BF1DF
+:1098300039E0239D405F44B63A00BE3EA16C29D872
+:109840000BD3CAF1F8E0CFA5ABA67FEED77D79A008
+:10985000333996B101BF141EF32614113BC784ABF4
+:10986000F0FA732902EFC9FFE6A6C30681EBEF6B9E
+:10987000C835808F5E8DD1C174E3F453FE220BA7EF
+:109880007FAEF8CC740AF540E68C10033C5C85F39F
+:10989000926BFEE14C82C2B15C607A518EF96C9899
+:1098A0000FD1E59F155C786B96ACE502E89320EB51
+:1098B000A7B8FF9BA5D69502FDFE25927A1FBC375F
+:1098C0009858C1F58E976FF4B4C9F9DA8A08958C67
+:1098D0006ED95F362F823E4B6B16AC8BD2749C4890
+:1098E000144EBD5A62F23229BF0AF058F4FF001E2E
+:1098F000C9FAC95942E18CACA2F75D7893AC20CA91
+:109900005185B0F71D7A9400CF57C1D57BFF56C063
+:10991000F3952E3C773F475E9BEFB2C3C0DE2B3101
+:109920005F22B5FE11CCB7787E7EE00D6AC7112D9F
+:10993000330878A65A627C88F2CA01581FAA171EFB
+:10994000EC4EE2F5E16E13D7EB507733B6FBBA2D50
+:109950006C0F77B761FB48770ADBBEAA3E15F0783B
+:10996000A06AE4800076A97DDA7A91E2E34078E4A7
+:10997000658276EA29EB45DAC5012A5BC9B584DC44
+:10998000DBF34F964DE9E4C02CD6FE5CCF77597BD4
+:10999000FEC8ED22BEFF75F67D2D7BDED7F33DF6CA
+:1099A0007C316B8FF4FC0B6B074807CC9BD4ACC5A8
+:1099B000F94C47578E7C0B0B06B32F6A6268974BA6
+:1099C000C60602B70E54D07E1A27FBA1E8546F0DCD
+:1099D0004FDFCF97041DFB71ECC4377419F5EB8191
+:1099E000C4E5C11390472CC48FFD23EB34C54F0051
+:1099F00068A49A90AF09E72C5BE3FA82CEF784F073
+:109A00009ACDE7CFFAA7FAE60F5DFAE6AB8282FDC0
+:109A10001D58E29DC7A5C67F0EE880CE23DA5E0002
+:109A20005B985C27A41F01BE08AFCBE77D142FDB3A
+:109A30006B9E41BFC4C1D7F4FDD9D8CFF3A03496F3
+:109A40004FBEAF99167EDF03F8A2F78F6C69453AD7
+:109A500079AAA80DF80679E9D8C10E3EA71D4F775F
+:109A6000C9F1FAA9F44D64AA8FE9FAFD25D13DF0B8
+:109A7000FC05D13DEB1FD018DFBC5D7C0D177DFFD1
+:109A8000D9A2F6DD45E3553D2592E6A57449378A0E
+:109A900033DA113D45FD9473FE74C6AFBC63451ABD
+:109AA000D7A1BD09EFFFC55AD1023C6D7C7CE171A5
+:109AB000A9049EA04780E3A8687D9FF13F9327A259
+:109AC0002DA01DF7792175EB8DE05F5E47ED020259
+:109AD00076A557DE10775B9ADAFE3197C3A49DC155
+:109AE0007BFD5BD7AB80EF60584C815F1554B27A39
+:109AF00059E3245D54727BC8817F1519FFE6C518B0
+:109B0000DA57E8EF7CFE8E0FC6376853E177FA1F0D
+:109B1000D6C4B62C7C5F24EF87E59CEA1E67BE9115
+:109B2000B94CFF3945409E7FF6C322DAD93BB9BF15
+:109B300038C4FDC541F017697B80DACB70EDB98E72
+:109B4000207D46CE86B2DBE8FB9158C1027957B141
+:109B50006D6E4B92CE2B12B7E271DAFE9BE552CFBF
+:109B6000EA5A30A10A8897079BD7444909F9EC5C67
+:109B7000C3A658E457053DF675C0F0FA59FE78F5CE
+:109B80008CF67684FA1F66235C197D4BD19FC5370E
+:109B9000B9F4B24F94105F92746B06F4E46E81C90D
+:109BA0000DE7F92DA288F81F12557C2F39B15E0CF4
+:109BB0004F5AB8D5CE839D2090CC7C7DEABA684AB6
+:109BC0001ED7FFBF6BFEBB679971B09FEC5E6AB496
+:109BD000BC9FEA598DDA0B60DF94AFB3EFA4F77B3B
+:109BE000A95D09711745D5CEC17D85EBDD7F12D208
+:109BF0009F13993F2A00BF513B9D5DA525E3109718
+:109C000050DEE7338F93A9F8FA538E2F1FE00BEC49
+:109C100013C057D324BE8634862F4AA525F1B540FC
+:109C200064FC3F2467558637F6FD6EF89EF2E34EDE
+:109C30006DE98E79F0FD698950B54F76CA797CEF70
+:109C40007785CF6278C2610A0FF815DF63F08495DB
+:109C500031FD7709CFB4EB5BD6F18ED6F7BF8B4ED3
+:109C6000A550AA03F86F12BF541E26181C22C489DF
+:109C70004426677771F9B74B1EFB9DAEFB1B23FD96
+:109C8000036007FF5449D581DFD7F9D0C2D560CF33
+:109C90006EE0FAE9DFBA4FEA3225808D7BFB2B4B71
+:109CA000C5FD3E29910CCA7D69E707309E46ECA4AC
+:109CB000B404DB0B3AE9FD6F89018F1F3421FFB338
+:109CC000CAF884BD5C3F356EF865D16B0FFF9234E6
+:109CD000466F37A6C78B03A713379C164E35E7038D
+:109CE000383BB78E048696B0F98ED0F9FE33978351
+:109CF00064B002F5D1279F7C41975D78EB1C51CE73
+:109D0000F9AF9A0AF7443CCBF98EAA177FD9D4EF62
+:109D1000A7FB2EA3A54F89143F966C55DE0E71E666
+:109D20005504FDE3D053A3763599EC77126E2A43A0
+:109D3000964CAED3E5C2A9C633162C6D10FEC7658E
+:109D4000EF7548E95745D73AF9EB9E8BBBFD3CD9F7
+:109D500047F53BD851C9B54C5F2FFE8CB19E3E4FA5
+:109D600050FD7CABCB4E75ECA8FEEE2CFA2FFE1A04
+:109D700016F7538D0CDA896A9764BCBE0CFA8921F8
+:109D80007D0D36327E54D51CD1E93534F2741EE295
+:109D9000559461309E0170AF5D0CAE08A3FBBFA26D
+:109DA0005766BF64797CC41BAF54BB7CD8FF50B7E7
+:109DB00021B8FDA7E034FED3AF39FF39F8F92CD034
+:109DC000097DEFC20363F21A7ABD25FFB25C4FC76B
+:109DD000AF91D87BA7BADFC4795D7880F9E7B7B4D3
+:109DE0007F47BEC185A7B9920FFBB9858F47C89839
+:109DF000ECF6331CBBE7FAB7A27958CF7F3A29A11A
+:109E0000FE988EAED7C46FC8CAE593ED534D12B31A
+:109E10009364E316F8FE9636492C654717C71FD69C
+:109E2000C43F80FD5CB87F4C063E3FD5AD0AAF29EC
+:109E30006C7E4618FAF98E0C71E84BC11D065BB1B9
+:109E400002ED27C4EF85FB7304E45B28FFB704FA37
+:109E50000925B39605F0411FE037258D6300DFF536
+:109E60006FFD8DBA66F1643F4EBFA1A2F90D27B90F
+:109E70001D28E7DA303EDA28BEADF985F8FC1CBCB7
+:109E8000EEB9045EF3DD56562E21279CAB751DB549
+:109E900073291C964262A5E471F1F82DA4252BBB11
+:109EA000E4D73B856374159D3FC5DDA8AC6BEF64BB
+:109EB0005C7F9DC0E29284F137FD3B21835DD766D4
+:109EC0003E0A785CCFE993CA9DF512D2BD95EF6941
+:109ED000C2E5C2385454CF11027986BA24C67988B3
+:109EE0005656D26FEAEF2ECC9695A970F52BDC3F33
+:109EF0007DEB8634C677C4E43D107718AA15D0AF41
+:109F00009D0EAE2D00D772846B8B84F901CBDE5091
+:109F100002AEA1450BDE2D5C9D6057F4898D08973C
+:109F2000038F1227685F38DF0D70788BE11CA8F271
+:109F3000215DF72D311F059130CCE1262487FE28C5
+:109F4000857F18E077FA91F571947FFD159B6CC0C1
+:109F5000F31BF415B05BA683DFA79E9F0D74ECC8BE
+:109F6000A33EF8CF95203F297C57533A6F647C3548
+:109F70005441B28D74FC40037DD604EDB1BF8636EA
+:109F80007D8FE8AEB6D3EF504536AEB9E45FFFA2A1
+:109F900027CEF821FE1A23C642FA9E92BF1DF9571A
+:109FA00089A5481AFC743967C1FA9146920039ECC8
+:109FB00053472CC01B69A06D7A19FA4D2FB6ED04DA
+:109FC0007B4EF4A59EF93C25B13CE4E43AD83CEF45
+:109FD000C3E2E84A92D9730F48E907810E959A8146
+:109FE00031B4E3789E684D917FEC5CBF3BCDBA7C89
+:109FF000F716BF675DBE31755DBE516A5DBE7BCB36
+:10A0000042464F6D1525E31F6BD4D766CBCBDCF0F2
+:10A01000B33C4E0D411D45F670FAF1C5F5DB015F0D
+:10A0200012AC2FA5ABC3B1FD49B0ABF6C59E044F32
+:10A030009A3E1F413BB4DB487F5B72F16F4D86E077
+:10A04000FD214E9F374AAB02AFD2EB83EDF551F0C5
+:10A0500097FF93EB9D62B876513F16E81CF29E7015
+:10A06000BDF0CAC219E3B2C7BB8947CE1C6F92517B
+:10A07000CE1E1F3C95BA81C2DD1F6B580AA2DDEAD5
+:10A08000FC4E07D8D765A6B114EC90F37C7C8ABF50
+:10A09000F3920B9F4A6C9CC755291C2E7CC8549C7C
+:10A0A00034C4301E3F9ED5011F39D4E7719D987985
+:10A0B00003E7FF1FB00ED58D4480F45455DA241009
+:10A0C0008772E64F88F9027CBFFF85F94BDDF9E125
+:10A0D0000FC83CAFBD8AF10D91CD78AA64FC8EAD5E
+:10A0E000D3518A9FC6F9C8FF983F1B86B64B2E3CBA
+:10A0F0002DA5890C70740531CE5CDD692A309F5323
+:10A10000DCEF13887AA20AE94B47FD75F4CF839CF4
+:10A11000BEF4638092A02C16D357505E3E95BEB617
+:10A12000CAE930DC0F366630D657D795C7FB0191A8
+:10A13000D95375F7B13CE070A7711CFAA5E09F02F6
+:10A14000FAAA15183E9B6401E7E3AF196BD90871B1
+:10A15000E8B46681FC30C643F8DD769E3F1CAE292C
+:10A160007C27C1FD47E0C79AA6C7466F007EB5D4DD
+:10A1700071885B0793F91668CFE1F50855A490F74D
+:10A1800025189E20EE519319174AD14F9D2F83F920
+:10A19000A0DA9A4DED606F0A7F7EA605E4C6F61E32
+:10A1A00062FA0DC05B3E0F79A2DA66BF0E743F6C97
+:10A1B0001011E4D1F6BB89D903B2C862CF43969A95
+:10A1C000923035991D85D874ED1682F12DBD863CEF
+:10A1D000EA8E6F6935E9BB619C4FCBE926C09B666F
+:10A1E00032BB315893CF43B87EBF42ED44DA0EAD57
+:10A1F0002A5800D7AEE59F21EB5D72ED464E27FE53
+:10A200004662A11DC1E9F3304FCCED6B7B3EF031CE
+:10A21000E03339C8FDF82D16F447CDBE3CF06F0889
+:10A22000E894209DAE06FAD033D95134951BCDBCAD
+:10A2300068205F629E73BF625781BDBA7FB9AF036A
+:10A24000F4355DB797C80A6A1F8964F20FEC971A54
+:10A25000EB31A09F5F4B2C7E1B5EFD44FE08F0C3DC
+:10A26000FBFCBA4CD76547E518A9A378288F4BC4E7
+:10A27000A0EB126ECAE6FF8E3EAF76F015378692DF
+:10A28000C08F31625A88EF6CFE15FA7C4E4788C049
+:10A290003AEA741D814428BEEE0078B5B6911601E5
+:10A2A000E4713DA3FBE372E687F7D3F78F9F944CED
+:10A2B000DB70F10FA1FCE3B2DBE70D52F9E0F11323
+:10A2C000191FB540A5091DBF7A0BCB2F3BF26F0EAE
+:10A2D0009F620D2908013AFE5C4244853E4FAC3531
+:10A2E000B6419C79DEBAECCB597AED0DBF54C5E48A
+:10A2F000C46AFD7C12F2E1E5C2C52BA79753B022D8
+:10A30000E73D71490647F5666F7E45DFE88A57D21B
+:10A310007F5AB3F779704ABC93F5338BFB3DC41871
+:10A3200049BAE5C7CE407E3F8BD3B7B5421E63A77F
+:10A3300090EF8090ADEFC1D6D6368AAF9DE17C1C00
+:10A3400042DA81E10FB6B641DCBB8E5AC868A7D2AB
+:10A3500051E9F50928B800795018C9435E33DCC2C9
+:10A36000E242BBAD3774783E5A7810E961A459CC0B
+:10A3700002FD4FBC9F2681F7C3FB8B4502F276B8E6
+:10A3800099BD3FF1DC18B105F61CFBBBB0983DBF91
+:10A3900030DF193F87E3132341FAE0BD95EC3DA779
+:10A3A0009F60A160019D3AFD5199DB036DBF95B59A
+:10A3B000257A2B68A5C93721DED92866B3022F1963
+:10A3C0000039D32467F320E79A33584B32FA8A3F97
+:10A3D0005070C9879146D63F591DE3F278C428557D
+:10A3E00067E2E0DD1A6921A857B83D076404F1DA95
+:10A3F000902167C00EA3F2F319E077D994CFF92327
+:10A4000060F78D13549CBCFFE9E985F5EFC8C3C321
+:10A4100067059C7F455D2AB110E4DF4B4C1EDAAD29
+:10A42000A904E821FB07211DF3BC72E69ADB5CEB73
+:10A43000DFCFE5602CC5EC8FE271145F2ADD13835A
+:10A440003885DFA41E2E392BA64F02BC4265D742A9
+:10A45000C04BC5DA147ED7452786FE6B8388F5404E
+:10A4600038510AC78EC766235C72793BC651763471
+:10A47000D4CF582FB1BB9B980D2E7DBD9BD219AC6C
+:10A48000DBEEE66D7A29F822719FD90075216DC641
+:10A490006CFD9DF5ABBAFB3D2AA65F972BA6F65F38
+:10A4A0009C67086AAB45B073A6F2DBCCF985FDEB7F
+:10A4B0003F1F87F162B3AD25C057091FC9A7A83C4C
+:10A4C0008C85ACA7810F0BFDE75A35BAEE31BF750D
+:10A4D0000F844E97F8B6B6EEA47C17A38206F267F7
+:10A4E000C9816F893D749E3188115D4BC8E28178C6
+:10A4F0002FE4CFBAB8FFBAB7DBA87E5D81787FB210
+:10A50000FA753A5F49617A611697CB24E3C3F5097E
+:10A510002806B32B64BD05E9E7469DC03A95ADA674
+:10A52000DFBBE54BD17744CE5BF8FE12F67ED84C0C
+:10A530007ADE27719227AE7A10AA4F220AC8B18E0E
+:10A5400091511852D28AED3E8DE5C5E2C67156AFE3
+:10A5500091AB5A43E97387E2B5FFF680DD379FE59B
+:10A560002FC0EE837A1FB8EEEA8EE3F5CDC29DF9D7
+:10A570003B63937EC61E259D073EB31372E6711D95
+:10A58000E54595275E132F54CAAE38D148EB27987E
+:10A590005D174F55BFEEBA7FF8EE4D1D70BF4F6F80
+:10A5A000D55B687FFBD2F54BD9DC8C1D60AF45F4E1
+:10A5B0007AB4D76EE5F01E12ECC0021877968CF9CB
+:10A5C000A7FEEEB1CAD7D14EDD1E7D7F0CF5E81295
+:10A5D000F8BE576078B5A93FF3389DF71BED6BCEF9
+:10A5E000DC49F1534E52D9F550CFA410C4B37D0BC2
+:10A5F000390ECF0F098C9FEC95E4D8E32EBB41694F
+:10A6000027EBC16E50B4F89DEC7AC55D84CA91D534
+:10A610000AABB7519ACD8FC17D29BACE9CA97E9144
+:10A62000CABE036E3DB84B60F4765BFFD75BED1995
+:10A63000F8AAF8BB3D81B138D0B1FAF0E3ADAB5721
+:10A64000C273FD80DB4F97634651DB2C392EB1BFBF
+:10A65000DE9A77C1BB87D34B57211175DB3D5F5322
+:10A66000440F9DF4772797B8FDE07EC1C92BDBFE30
+:10A670003ACCF32CC0F5BAF0CA8533402F52E48AA5
+:10A68000A5A00F3EA1307BB3A5529543F4FEA19B3C
+:10A6900009EA2BA0C73AB48F7CA8A7A4D800AB6363
+:10A6A000D0989D4BE5F727148F7FC5EC5C5FD35A9C
+:10A6B0005C2FE09CB9140FCAD91DCCCF6B52CFC10F
+:10A6C000F7BE1885D335EF370BF366F4637ABB29F1
+:10A6D0009EDD7511D43C692E83F978F13FB4D2A97F
+:10A6E0008F3404827C66E816D0D17A4667438B0C9F
+:10A6F000C107FC3BCB84881489DBBDC20AFADE7635
+:10A70000A592C5B7D6E7041FFDFE30AF1B100F188A
+:10A71000BAAF09EC64F309773C67E89E1CF63F4743
+:10A720001FF4CA8BD505F09D27F273C5F338A9B77E
+:10A73000EC56E87AED98BF1FE3AC137A23CDF5060B
+:10A740009D17E0EDE07AF1983BFEB53F7D797A63A5
+:10A750008F3C12007D70C078E866E4C755A2399F2F
+:10A76000AE9F9A60EDA1E68625B0EE13723EDC7ACC
+:10A77000CCBD8ED166DA9F8B4EF75FA67ED923E7DC
+:10A7800002A05F0E19CFBCB0A06972FC4168971E91
+:10A79000FF6905FD2AF233B0337D5C7EEE98BF0978
+:10A7A000EBEC8AE171BEDB20A7AFF5B9E8DF173724
+:10A7B0001DFF14E9586E73EC570BED6D6DD20EC989
+:10A7C000DFDFE4B143EE83F1E55504F34A8E1F77F2
+:10A7D00029BAECA7FAC64D978A9CC2FCAC2F46EF6B
+:10A7E000BBE0BD347D7BF9B697F3ED04BDFF20904F
+:10A7F000CEBADAFFCAF9F55FB97E03990AF508B255
+:10A8000046FB718DAB4CC4755349775CF74DB5E58C
+:10A8100087B0DE7BC068073D1827D922BDF5A39914
+:10A82000F55663F455173C737D5E7DE5E8A901AEEE
+:10A83000A78AE71BE2799981AA4D59B0AF0EAF5CA8
+:10A84000807A65A0FA13B951B0976F5E8072C9E93A
+:10A85000B78B307D41790BF9A44F7DADF2756A97C6
+:10A86000C8817FAF84B8BFA3670ECDFA08D6771D25
+:10A8700052722F6F02BAABF0A11E1AA8FA0CFA435B
+:10A88000CA2611F5CF9B854F8F813E3BA03798306C
+:10A89000CE61217312EA14ED5922BE4FEDDA9B818D
+:10A8A0006E4327E761BDFA6185EBABBB08E7D314C4
+:10A8B000C637AAAC3801FA39A4A46C90A7F6DFAB6E
+:10A8C000E471C84F5A0BEE427DB491E99F98AF0CEA
+:10A8D000E7B1EFE68F94D443732118E28E2314E995
+:10A8E0009543016F5EBAF8F95C9FC8EBE72E4FDF26
+:10A8F000EC51585D8B238F0E534349B81AE69BEEFB
+:10A90000483532F9BFC645371FE5EBE17CB7FF6E2E
+:10A9100066CF9D90D257FA28BDC81DE93CA06AB405
+:10A92000B103E32313FD87D97B6FAAA9AB7D6877B9
+:10A93000A5929EE7F30FE27350FB50071DBBADDD00
+:10A94000EAA7F8EFE7F68CD5C1F05FC6EB9D1D3D99
+:10A9500043F9768FE2C29B139F9A6A8F8F78F255E4
+:10A96000976B87175FA30249015FA989C754777D59
+:10A97000CB877C8C2F5FD0AC0FC13C8BE5D6E5DA62
+:10A98000E9D38D3B681CF78C7BC7E4B877941A77C2
+:10A990004A7E1AF271E590C7CB577D0CF2D3311184
+:10A9A000E9BCB779CDED77D1F62F63B209712849AB
+:10A9B0004D931FC5B0DC363302718791F5E4EF513A
+:10A9C0005F6968571E524C2227405E8B987FAE9875
+:10A9D000C8D399642D5DDF059CAE897B7F01D44F80
+:10A9E00042BEAE1CFC2EB6AE018364210EA6E66FFD
+:10A9F0006F51E8F86A8C98F41EFDB3D10EA4DDE81F
+:10AA00005F4CB03837B4D506C2F657C896C0D69951
+:10AA1000C5A72BF87325A63F2A025C6ABA07FA235A
+:10AA2000352CAF58C99FFB6BD87388A3635CBD8A74
+:10AA3000C5D595188FAB57B138BABF86C7D5799BA6
+:10AA400010B6EF6158089A40874355DEF8FA5082F5
+:10AA5000C7A9DF7A34BED6C53743BFF9721C90B898
+:10AA6000A8F6A65EB00B9D7CC690928DEB25E441C6
+:10AA7000713E63CA739174E238722E0EFC194B65F5
+:10AA800031AE4F7166405CAD188FFD8B0626F0B875
+:10AA9000F03DC4636F111E7B8BF0E8B427F45C9526
+:10AAA000E9C15FEF04FE9679F0D71B7E02E5432FE4
+:10AAB000C7E3491FC5E3B540BFA63AD33E178DD3C0
+:10AAC000F9445BCD9F3440AE9F9620823099773613
+:10AAD00059BD1CA1EE9B7BDC18A7EB8540D714EE7B
+:10AAE000CAB5DEBCB3C6E9F8A898FA47B04336CE7B
+:10AAF0003AFC51827977AFBF3C9B9863608792663E
+:10AB000086BF0871C5ADDE86DFFC1A97EFFBA4F4A3
+:10AB100019E0EF506AC40239EBD76C1B4C8158CA5C
+:10AB20006EF9E718C6E7C625747659BC0E536E3821
+:10AB30009E4DCEABA81A4DD84752B1D66E013BB34D
+:10AB4000868A5B78BFB2634C28552F3DCCF5C1B0E7
+:10AB500092E2FA80D385CEE2E3DB42DF38B301F242
+:10AB600008E56568CF9DF339FBD0A80B067E03B7D7
+:10AB7000BFA89C3EE773D9979A3E6E09205F785C28
+:10AB8000EE485BFA97F0FCD072B303EAAEE95FC619
+:10AB90001FA7E336991F9E68D7D176E3D292FBD0E8
+:10ABA00036B459BFF6A1FF49F53EE8E17302AEE7BE
+:10ABB000412577B3380F3ECF05DCF2FFD0E6CBB5A9
+:10ABC000A7732AC8ED61E3D993F51E7B9AB54BD8DC
+:10ABD000B321BF4B2F15CBE343976F4FF3F19FF199
+:10ABE0008C3FC8DB25C69FE3AF70E9C14611FD1F4E
+:10ABF0008A07AC7F2E8667B8F1BDD1878BFDCC5E0E
+:10AC0000A07A6931E063CAB8808719FCF277AA0F8D
+:10AC1000574D8EBB0AC6251A8B274EE74738572754
+:10AC2000AE08BA10E832DA96BA11BEFF4513B1A5E4
+:10AC300028C567D38005710A95EFC3240DB6CAF6FF
+:10AC400083D88857926471F641E3BD89F30D5E267F
+:10AC5000BE9C7EA7CE33EBB1379DFEFB801FC10E9D
+:10AC6000DECBFCE57D1C0F352427825DF6098ED7EF
+:10AC7000567FAAD38F7C3E8676DE63C6891DF32875
+:10AC80005E828B9E0DC2BC9D7D52441E236EFBF1E5
+:10AC90009E89EFAD4FC1F70D89137BF97765F01DE4
+:10ACA00095A39FF6CF2047FB042A47591CE81DC9EE
+:10ACB000D11E3EFE7FF8D23D308EBA779BBAD0804F
+:10ACC0007D78D9B12B0417DC6D4B71DE0D7B4FCC39
+:10ACD000BA09745982C7BDE4DCA90F42BC3DD980D2
+:10ACE00079D2497CF6F07EAD21A4B7B6D279FE6266
+:10ACF0003AB35B39BECBC42CC4C402291BE57A65C8
+:10AD000007CB7F51BD89F9FF093B85E7FF417FBB39
+:10AD1000F3FF1376CABBCEFF7BF3FD3ED566F5008D
+:10AD200006CBF70FFDE6D32CFF5FCBDAC5F3FA2B8A
+:10AD30003F93FFEBFDD6DFC2FA7E52B29EF2BBE438
+:10AD40007EDF7F499DA5F62F3FCBD7A5CFC7F58CDA
+:10AD5000CCE27F72D902D433026175FFCEFB503F43
+:10AD600000FD3AF50493FB4CBD7ACFFA098BAFC6D0
+:10AD70003B991E9A93CAB730FC3AFA8EEFD724AFAC
+:10AD800011C84FCD5EC7F5DB843DBA4380F88F4ACA
+:10AD9000ED9E00763F8D3D1A73ECA80CB3A3620CB8
+:10ADA0007F7183ADAF6327F9D49116E88FFADBA8E2
+:10ADB0009FAAF8F7BE387BAEB06FC930AC7382ADD6
+:10ADC0002BACF330AC2B7C1F67EBECB409B7471FFF
+:10ADD000E4F6E87045CEB3DEC3604F013EDFFA72A1
+:10ADE0007CAD4BFF0DFF665915C42917D58EA33DC9
+:10ADF0003ABC98D9A3C34AEE5DDAA326FA8BB3D73F
+:10AE0000E5CEF8191EB93DEAC563FFE2018C0F4E8D
+:10AE1000B1477FCB7874F8C5C1A3C31F0E1E2FC5E1
+:10AE20002FD3DAF38BBE8AFEF210E091DAA3D52A93
+:10AE3000C56335D8A3D9CBB54707EB291CE5DC1E84
+:10AE40002D1F59322ACF608FCEE6F6E802EE675505
+:10AE5000A5BD75C08E3D4AEDC45A95F25368DD0814
+:10AE6000D659F8291F43DE7F594DDA5041EEAE33F3
+:10AE700005B8EFD3D8FDBB6FB6122AC6DFD8BEE344
+:10AE800087FFE409E4A7F264CE2650DF276731EF9D
+:10AE90005EDE9E251B5CFCFB23A33509FD95CBA63E
+:10AEA0000074536E948E7BD6ABCC7EA572E12A18CB
+:10AEB000E749C3BA5A45FD9115FE00EC509B8C43FF
+:10AEC0007D2B29CA3353BF06F333B516B515E9F305
+:10AED000BAB5E33D108F32D6E922C03F8F18ADBE20
+:10AEE000848B8F799E79DE4EB6FE8FAC24D9CDF45B
+:10AEF000F9FC87C6AB5468DFFF92D64EDB573EC5E0
+:10AF00009E7F71397BDE98CB56C3F32F7E813D77D0
+:10AF1000E07EE40BBFAA3234F86EFCE58F81DDF5EC
+:10AF200005A6771EE9498BCB281E16E4BF20CEA3C9
+:10AF3000F8F9B0CAEA8E16E472A211E6C0AF8075C5
+:10AF4000227CBF615E04BC5E01FF49E9A477707199
+:10AF50001FEC037B64F4E3F8FE23BCFE84D8793154
+:10AF600044F151B7D5C038FD15B9424F90B61BBB5F
+:10AF70008C32E09BBAADE38208FD3C9515A13E758D
+:10AF8000EE93397103DAE5594FFFC46E599DA7F767
+:10AF90001339F23CEC719CFB50611478ECCA9DECC7
+:10AFA0007C04A38B5D135BD9B5539510FE3BF93A36
+:10AFB00039EDF9B96C2BD8DF754DC44C1850C76208
+:10AFC0003E0FF0CCDF4A74480BCEDD6A8AC00742E0
+:10AFD0002EF77C10DEDB4A4CC825FF298513F2A32F
+:10AFE000C2938551D03757E458DD88F0544E2C6811
+:10AFF00053F1F076E1BC5F65FB5BBA389C4E7B7E1B
+:10B000002EBD0DE16C2E82F34906E7154F7AE19CC7
+:10B01000DBC5E1ECCA223CC2FEF11EB8BFA008CEDF
+:10B0200005D39CB791511D3F87E9712565A37C2A03
+:10B03000B7585D0EBDB278A549B2F369FB3B84AE4B
+:10B040001A6D87ADCC17414E97379902F079797B0D
+:10B0500026087A4A85121E7CCEBED79BF236D413C0
+:10B06000400FCB4DD7F74DECFB967613F15BAE92CC
+:10B07000169877C24248488B6558E06752D986F9DE
+:10B080009BF0D99B4EC23E5FAD49FE95BB4EA29C44
+:10B09000B0766D9AD94D0968BBF2B80FB8DB58206D
+:10B0A000E6FA9ED965F81CCC45B0CB14EEC71179F1
+:10B0B000D9736B56F0BCA904D76C16F22379ED4B0B
+:10B0C000A771DF3679323B915FC4E7639685FED97D
+:10B0D00048B5E7FEAA318CCFC37EE51B9AA7C25FB5
+:10B0E0003CBE1CCBA37D7010EACF41C14B2F629CAC
+:10B0F00055EF4C45F3A4841C26F279E80FBF17A640
+:10B10000EE4338A16A9EFDCFE1AEBFCA62FD3A3F71
+:10B1100007854AD2E7D654021E09C62BC3EDACEE12
+:10B12000C819DFD98FF0BF389D567766D97A3711A5
+:10B130001DFCB4708CFB0FB1D368275E7865FBDC17
+:10B1400007E8F3DD2B9B97E1F3A6827EA706F31AAF
+:10B1500023B7A17F318074E6E88FB0B4B30796A51A
+:10B16000BCBD80766242360330FF9DED6BA2640663
+:10B17000BF23CEF5470DD71F11AB289EA11201FCAE
+:10B180004C7D441066D2438E9E71F011067C2631B0
+:10B19000DF80FD168F5B8CDF71C0AFB3CF6321F40E
+:10B1A000F760B5BB3F4D2ECD770E5E7FCCF1FA0533
+:10B1B000E8B302EA6C24E4B7A30DC12CE4D1FBC5CB
+:10B1C0004200F2CDF63FB23A907EC2E833C8E3CBFC
+:10B1D00084A47BC046903A09DAF17BBB3B308F33C5
+:10B1E000D09DAE063BE7787727B63F156071D56EE8
+:10B1F00023AD06589EC4729F9FA36B23A330E72103
+:10B2000025BB1FEA96EDF94186AF18F31F8AF32498
+:10B2100093F63FF3178AF3FACE73A9D1B2416D4486
+:10B2200083E305C8E3934D3EBE0ED432A6E3443417
+:10B2300056FFEAE4711DBAA90F303D64759AF96FA3
+:10B24000C626EB6E74CBCC3F4ADB1AEC9F62F9AE9C
+:10B250007A988FA415B06E2964B17D559166163F1A
+:10B260000FD6E46CE08D3DCA7807DBE77D70F5E929
+:10B2700038E4B709CAED4581A7516E4745D6BE6D82
+:10B28000C797FA204FBE7722DF4C50FF812D077EF3
+:10B290009C33AFCF04D8BA45791DA48327E7F9DDE5
+:10B2A000016F3E7BA2FEF6CD8B17FD2B26ED025DD6
+:10B2B000CE0B9067ABD9CCF442F4FA9F556D72E196
+:10B2C000D90A30BD10ED6679A6A3B563E857143FDF
+:10B2D000FF5060225E85785534267F95B3D720FED7
+:10B2E000088F4329AB18FED4848C6DAB339507B916
+:10B2F0005B46F106F8A5F8FC10E053B372206E3CF3
+:10B3000075B2C43977037025E708D8EB4705621F8B
+:10B31000A4EBD005C159CC87E470BCC33FD22CC884
+:10B32000278556FDDBFD9037BA5CB8281C7F12C01C
+:10B33000F527C8BF6526DF57A4B1789B33DE5EA72B
+:10B34000FEE23E1F8B0BC9FAED1B01AE7B16E0FB44
+:10B35000BF057CDC0D7014E3E3B301BE1F9A14AA91
+:10B36000C04E9EA0174E07C57443F542D59AC553EB
+:10B37000F986C8F47BB4B3F278DDDD9DC5BA1FE76A
+:10B380003D671F675741C079EE5CCEEA6C23D7FE5C
+:10B39000E449E483A5ACEEE130E7EF78F3C9DC37AC
+:10B3A0000D288BF939F21369F2995046BC5B241EC3
+:10B3B0007F753B7F7F674070EAA30FE3BA9BE4048D
+:10B3C000F823D136EA3726405FB17D0B87815F00D5
+:10B3D0005EE967E837FED222E360C7460A3F27B03E
+:10B3E000EF342E317C469BB39E3A82E9E4E6C301FA
+:10B3F000EFB91CBB45AADF84E9E5BD232F2332ED5D
+:10B40000AB0CC6DD8E7518D38DB7BB7B10F138A899
+:10B410005A8FC2FABD79EEA619F3D640263D2EBD4D
+:10B420003DDD7BEFF515E4688F027A24A4839E3E10
+:10B4300042C6883D0FF6D38EE54F837F4CF16E43B5
+:10B440005C9CDB11F2064BB8E8924BCE7713EDF61D
+:10B4500057D13FFE49E0B53E957E774060722E3D64
+:10B46000FC831B41EE1D91C7B0BEE188EA6B63F51A
+:10B47000EBB1568C5734971D6372F95B787E48DFC9
+:10B48000AC18C665FF37976B8EFEA67FAACFA5477F
+:10B4900076363F6F73FA40A3441F69211877E1FEA7
+:10B4A0002DC86FB00F3527BEAF31FEDDB194609D62
+:10B4B000B1937F6BE0790A8930BD2E6F60FAD8D1E5
+:10B4C000D7604F60BC523A6BE2FE8769CE752BD6CF
+:10B4D000E7C574F82F21977D44F5F72262451F4098
+:10B4E0003F6C641BC487E8A728DF9CF6C28D04E587
+:10B4F000DAA278A185C9352FDD2C8A8FB790C87F55
+:10B500001FFDEC858982FE5EC2E29E7FCDE9090CBB
+:10B510007338374983F5A7F41408B1755C3C38D605
+:10B5200003EB331F3EA1DF5DB533D51AA0D77959A0
+:10B5300062B6D0F5AE5599FDF26055F600BC5720C5
+:10B54000F7F8E5F7831F9AC3B66E67FC401F5F0FDD
+:10B5500006519ED4FE52E0754B055CDB23FF39D1CA
+:10B56000C63AA354738180BD1FE962CF0FDECDEAD6
+:10B57000CFC13646BFA08B1CC3FA7AFE5E5D90E950
+:10B5800035236820BC0F2ECFB7C27775CDB96D704B
+:10B590000DB7FF43AB01FD91DC3613FC9C9C8EFE86
+:10B5A00057E4A1310C2738FE57A2895D173433FBCD
+:10B5B0003619647EE11541915FD9BEB2C6A0EEECAA
+:10B5C000A7443BF45AD5BA32B81CE3D901A0B379E9
+:10B5D00084E187EC67FEF382C3518F7DB794F7F760
+:10B5E000B920B35FAE55534DF0FD95D46FFE7F1477
+:10B5F000EF912D05E60F51BF0DF21EC5EBD7166476
+:10B6000075F6912D0C5EC0CF31DAFF7E99E1677F30
+:10B61000977ECC66F1B23EF047E53603F763B70597
+:10B62000993CD72DCB82FBF453BB1CED202B0FFB99
+:10B630002E42AFB37D1772E7F9FB813EA9BC6F0BB9
+:10B64000429DC3E65F75031D3B7542FBDB7D24EF26
+:10B650005A3F677DEA9B0B36C41522CD8620B8E0A1
+:10B660008E3C4BE513852F5C3366B1739158DD64D6
+:10B67000C2AE477BF4F88ECA56889F6545635B3936
+:10B6800045EDC7399CB5B2FE3CC0554BE1EAA1F788
+:10B69000EBB6E8DB36215EA204CE1F58FCACFE3CC4
+:10B6A000E4BF8C8B5102769E33DE27397E1DB82293
+:10B6B000EDE7717E25E01240BED5025C143E6BAB17
+:10B6C000DE0AF097AD62FB82EABA8808ED9069A0C5
+:10B6D000FEFC1C872BA3591F87F5DACAE9A0AE8BA5
+:10B6E000C557EBA6D97F7B747A7866110F3C590158
+:10B6F000F054CDF1742978B6061DBD6C7D2E88F40A
+:10B700003826B0FCCCEF879E7A04E48A2B3F33F7CF
+:10B71000D98205F125E3B931DB403F8AC90DB1F08B
+:10B720007F91DECBBBF425EEFD5007395F47B8BFF4
+:10B7300059DCFF63C1897D9EC761FE96CDE8BF6C71
+:10B7400015B3E3421057A078EAE47261129FDC4E11
+:10B75000ECCAE371365F9AE06766A709ABFE03F5B2
+:10B76000465D33E32FA215AA6E73D9655F0A4A9E20
+:10B770007D7F75C0DFF09ECAED346AAF7DC4E53FC2
+:10B780001EBDEF25CC3F5753F905F652A4EBAB286D
+:10B79000E722D416D2AEC6734E04904B73BAD83C8F
+:10B7A000176F25429F8B8ECE717ED7395D54CBE3C8
+:10B7B000A3C02F739E3596DA2EFAF94550F4D89B24
+:10B7C00047B9BD1937BB44C06F1D31B6313D951126
+:10B7D000411ED76E345AD1FE0E31BA0E835D503EF3
+:10B7E000595F1EEF3CD30670D76DAEC7FA6FF853A2
+:10B7F00056E0BA61BEE1D0E65336C8116A2A9820F5
+:10B8000047C23CCE22884C8F12D3155771D91FCE18
+:10B810003813ED4E36EF5A794C70EF0776E0AA55A3
+:10B820007D2C7E404E109887AC313AB9F0CAF72D86
+:10B83000B7DDF16D3E7FEBA1428FDFE50F50FA08D7
+:10B84000852A26CFA775E4582D9FE7E2ADB6B0ADA7
+:10B85000D18D476E2773B940CD10C4B7AC3179B5DF
+:10B86000F859CB86712581C92BE77DABCFB241DF7B
+:10B870009571FD5FBBC5C27D2D1A45A8C4FC845FD0
+:10B8800004110E763FB495DD77E099B3B980F71FC8
+:10B89000EC91AC76940F850336ACE37DE7F1FE4185
+:10B8A000EA4795833FDC6C1E00B9B7FBCF7CA49DB3
+:10B8B0004CE58B232B5FC238EE11BEFE67FECC67D2
+:10B8C00031BD99F922E8CD7853A1E7C7F4BE1262E1
+:10B8D000FAB82EFF5301E2B24778DD5D1DA5C7D946
+:10B8E000F4AA517F53837D2A5D239F8673DE34B093
+:10B8F00067A00DF60B6DFF5D90FB3713FE49E1F776
+:10B900004AFE1C2C923F8BA99F08F2D5E12398E7B1
+:10B910002CD7BA27B9BD5367F94AC66334C71EEAA4
+:10B92000B4516F38F4616D196985F86BD92A4A975B
+:10B93000943E161EB6C520CA691DE972494874F4C2
+:10B940008619427CB17D5993FC660BBD4CDFA33D4B
+:10B95000B64BB67B06800EBAC871AEC73D7C57DDCC
+:10B9600039867C570F7CA74FE5BB60A3377E584BC9
+:10B97000CCE7A1646E0ADFB58B28DF8AF9EEC30E2F
+:10B98000DF3509BC9E565E1D689ADC275ACC77D7F6
+:10B990003B78EB9AA853FC70C8251F1DFA3E20E89F
+:10B9A00002E6150482F574A3852F633DD2E1388B3E
+:10B9B00043079379DC27E63F29A1AF30DDBA96AD86
+:10B9C000EEF0D41BFF5D2881F0061BD39EFBF3062F
+:10B9D0003BABE5127E9FE3FF50BCF76C73E13D9EED
+:10B9E0007EF3229C5F53B7C5E075D42751FE859B3B
+:10B9F0004532E45A0727D451B785F95B35D4DF12B5
+:10BA0000319F9327B02E47E8BA809C2D8EE3168F86
+:10BA10003FD16E1651FE819FE55E876D21A6DF8FB7
+:10BA200034096DB00ED608FD07F285D7236926DBF1
+:10BA3000F728CFAAC475F854C8D9AF4B9A04577DDC
+:10BA4000335D8F6D215C1FAF5F15D2C631267C4000
+:10BA5000617262A87BBF27AEB087D3AD9CCC5AF091
+:10BA6000D15EC1C4732341267DA5C4FA3CCCE9E66E
+:10BA7000E190C1BE1B34D00E97769ADB709F9E9EDC
+:10BA8000B50C8C9BE5F0DC56DA8FFE1563FA7EEA86
+:10BA90007503EDF6799AB90DED054EBF8E9DB30B8A
+:10BAA000EAFEB5A9FC11CE907CE0AAA97C114A96C9
+:10BAB0005E8F297CB1B1345F3CC3D7E3EDF2C53171
+:10BAC0008EBF50326FFB991E7A26B47C2A5F8C168B
+:10BAD0001EC57D87070BF3663CB7A998EEFDF1B74D
+:10BAE00047EF128F374FB4A78937BF32111FFCFDC4
+:10BAF00090DFBDDC2FA5787B25C0E2967D90D776C0
+:10BB0000EAEC248DC99BCB8DA7FF90C7277A218EA5
+:10BB1000E63D7F94EF2B281D2F9A80CBC9FFF33889
+:10BB20005EDFE8CDA4BEE4BE501EBF8BF1FDC8941D
+:10BB3000585F2B610F4DBE6F23FE7BBB73C887CE52
+:10BB40007ECF7ED8EF9980F3B09FC4FB7BBB9F6311
+:10BB5000FBFDEACC34EC8777F67FEEECCEE37DBAE2
+:10BB60007C4988877E56BA16CF2BEF154DC3D9175F
+:10BB70000AF5E1CE3ED0E9F07E879660FBC98AF6F1
+:10BB8000833AFB40618073BF07F4A1C4B32D70B446
+:10BB9000515532359626701E38B5955DEBD96DA49A
+:10BBA0000DCDA5879418DBD7F1FB023FACC339BAA2
+:10BBB0009EFBB8DFBE4F2359D0F73E839FEB5F93C8
+:10BBC000C983DDE78BEBCF082E3AF4C5D24474D19C
+:10BBD000B7CFCC5B205FF71213E58F4DBF01B9BA29
+:10BBE00077F51A4FFDC26A8DC955255EDA9FBA51A5
+:10BBF00063FE141D0FE318B378BDE1AC1B9B3CFD45
+:10BC0000DCC2FB91A6E9E70F2803F27E66413FFB09
+:10BC100074760EC7543A6B403A2B5BFDDC643E945D
+:10BC2000C03ED3BC87FFFA267E07C062CA5767F1C1
+:10BC30003A8A27A1D4B9A9766B06CFC7B4B7C9048D
+:10BC4000ECAA87430FE0F9995DB65F073B9EC4D825
+:10BC5000F99AFB6455073BFDB392712B1E6AC27FB4
+:10BC6000D7E282386E8362D448CE42AEBC447F179E
+:10BC7000027559B08B9DDFB1707EBF625F9CF60B81
+:10BC8000E7E7AB79D44B829CF39C0F96902D3CAFA9
+:10BC90004F556D15F85882BA18FA9E34B204F52340
+:10BCA00099381F8C201DA8BA857220484CF44FA3E8
+:10BCB0006DA2A71E26647AEB6364CD6679BFD3526A
+:10BCC000168E6477CE0D83B2131857D6A89E44B84B
+:10BCD000D9B9F74E7E795FDBBD24C7BF2B752EAB7C
+:10BCE0007395093B3F1FF6B0837EF593997F87A13B
+:10BCF000789CF8DA54B4D4F926D3BD4F05BB71DE75
+:10BD000095979FFE3BEFF90A4781662A609DFEA04A
+:10BD100012E49941ED4F386FF152E7AA1E15D34F47
+:10BD200082FCF8A992B986E551D9BA52F3E903F831
+:10BD3000FB1E24620EE195D56562DDA60061D491FB
+:10BD4000BC9580FD09DEF31A4250874AFBF914F7CF
+:10BD50003B4349EFF3E2FACDAF69CCDE58450AB870
+:10BD60005E1155CBE379E1CDDE73379D79DF1BF7AB
+:10BD7000D65B155F45A21A1AC478793E5CE06D6700
+:10BD8000FC3746048CEFDF4B39AC6BA9BB5F9EFFE1
+:10BD90002EE2B368228BE797911691805E1952C903
+:10BDA0000B207FF65A9B0C9063706687BB2EF4378E
+:10BDB000DA3C760EA4E513A1CE7ED7C91B67033FFC
+:10BDC0008F28FACDB89F62B9A81F2F416FFFAE31FF
+:10BDD000BB24D815321F5B36FDFC823E56CFBAAB72
+:10BDE000E98D14F417B92E360BE87768B4EA053CF0
+:10BDF000AFC2AA4C402A2B10E6767293571FEFE58C
+:10BE000072786F92C9E1605704C7BB147CDFE7F218
+:10BE100030D815301F9B01FFBF6DF81C3C9EE772A8
+:10BE20002BD8A5E1F80E5E212206E7E128FC5C7420
+:10BE300068C379A792A5625B295C93C7F34FE97346
+:10BE40007F33DA59FE30C4315EB708C89BE27CEA22
+:10BE5000298D9FEFAAEACCEED663AC6E3C2D633DF4
+:10BE60007524CDEAAA27F9D066EF275F4D813CDB28
+:10BE7000D5C8F6408492CCDF0973FA882AD993306A
+:10BE8000FF68CB827A98D7EA30A3FB1125A7429EA0
+:10BE900076A8276A1C47389F1D5C47870C8ECDC744
+:10BEA000FDD9CEB85698E39F68581FEBE0E1A0603B
+:10BEB0003CBC0EE4760BDBE7B8F0E4FAE7E10CA754
+:10BEC000F9634B5A6BE9F71FE4DFCD2A2C1985F68D
+:10BED000FC303F8F73195906F47DEFE1CCB7E05C7D
+:10BEE000907B5BB6DD04D74FEFB76E8294F2A33B35
+:10BEF000D778F24853F72F10DC8FBCCB1203706E4B
+:10BF000080B37F8134355DA24E9ADB8B53D62D45AD
+:10BF1000A05E46E2F50D72F31ACCA7EAF572264A46
+:10BF2000D7CD3A6B1218A7CC79BF89AD8BA3CF269A
+:10BF3000F69FF0F817218FA13CA90D73BA99C01B89
+:10BF4000A377F2CD9FDAB0CF2244E90452D8A4D12E
+:10BF50004B87B561162F75D69B0E68BF0A725A5073
+:10BF6000502E38F89C6E9EEFF47AA49BD8AF523CCA
+:10BF70001FE3D7DD705530CE8CD7217EDF79FF4FA0
+:10BF8000C33C7FCCD793328FFD2AE8ABB94C7E39C6
+:10BF9000EB5BB785DD77E4A0B3DEF57DDEFBD1E6B4
+:10BFA00018CED3691B5BBDCF4349EF73875E1CFA84
+:10BFB00070E8E6DDD2471338BA2E3F32CFED0129C3
+:10BFC000CEEAC3A5F820E6BD1DF97BAE3A65873100
+:10BFD000EE98C6BAC0D1AA05D1828B7F8BC719E86B
+:10BFE000CE2D71EFF376F64FF86492579682DF9973
+:10BFF000F39C673075FFA9953C46DB3B6295283F73
+:10C00000FCDAFF389327B03FC9F8A3FA19EC89DFAF
+:10C01000C23EA4C36197BDFF6EF7A3BE837D484FA8
+:10C02000C1F87DBC1EA3787C4B6FC4BC777586E5D8
+:10C0300073BEC1E55C2D29F4282CBE9E525DF5C06F
+:10C0400073D78D55FDBD01E72ABE94C07301481F0B
+:10C050009E2F45B543D3C519F460B1FDE3ECF368F9
+:10C06000496FDC0FE79455671A97F2BA17361E8CA2
+:10C070004DDB635C1ED692FCAFC1A6AB23E3F83B5D
+:10C080004D464A6F85F4707D87F93C5C293C8BDE18
+:10C09000CD7957D3EDD372DE7FAFF6679DE3F87E9F
+:10C0A00041B3CE8597FFEEF6678D4F8E3B5E6ADC1F
+:10C0B00062BB6AEF6D11B6DF94FAFD50DFF7F06DE9
+:10C0C0000FA03F103C1B30207E6FB75A02EC4FB5DB
+:10C0D000AB89D94BD7AD2B99B2A04EFCAC98FE2FB3
+:10C0E000E8BFE5072FC781BF772DCACC05BF700217
+:10C0F000DF9AF7BCA6DEA2F39A7AB5F7661F57EF70
+:10C100006FEFBCA6EAC8F2A9FD17EF9B92C20FB170
+:10C11000F3072FF3BCA658B9B5047FF785FCE34DB0
+:10C120002FBACE695A1C19BC49837399A088BA9A50
+:10C130009025BB5FDC0EF1FFD81CEB6978FFD5C8FA
+:10C14000FFB92906E738CD63CF57EE61CF25356BB0
+:10C150004190FEE1A8C1F46CDA87E7C10493ECF7E3
+:10C1600044489C14204EEB9CFFD16DA457442A26D2
+:10C17000CFA1F0C559BC62E2DC246AF7F967909F51
+:10C18000C7785D25FCFE0D5C8FF2F32886F9B9496E
+:10C19000C13E15CF81DCD56D601D26FC0E0E5C0FF7
+:10C1A0007777E0F569297523E0379864E744EEE78F
+:10C1B000E75F04B8DD7A8AC7895F8A30393179E56B
+:10C1C00071622E67765F7B47D41D2FF8C388E0D15C
+:10C1D0005703DDE6FB4EB8E2CCBE8DEC7790FC71E8
+:10C1E0007ADFC51755FCDC8C03F767C91A881FE78F
+:10C1F000BF8071B6BBF9B87BBA33D7413CACFFAE58
+:10C20000CF5B1097DADBDD751DC4BF02F2B80D718C
+:10C210006AEA382D01FF39A0921EA47F8BB609FC73
+:10C220005E8ACEDAABF973DDE8C1F7DB587BA0DBC1
+:10C23000BECE1D07D757D1715C70F99269B2BE119D
+:10C24000E2165D9EFBFEB8ED69275E7CB20DEAE466
+:10C25000B693B00E7EE250CDBE97213FF0460395D7
+:10C26000B6E01FE60FBC1C05BB5FF31901DAEEBD9B
+:10C27000DF7BEEC50EBA8EEEDF990A378CD90077D8
+:10C2800020995E06E4EBE89920FCBE976BDCC8FBC6
+:10C2900034762E759CD501F6727C39789E90CBF160
+:10C2A00091EB64975D27931CCA7BB9F1EB3D90A796
+:10C2B000A1F625D02839265878AE9D73DE87BCF1CB
+:10C2C0006B985F5DB3000E26A2F4FAF1D5F96FD139
+:10C2D00076F6C500E63313036D79D8276DDC16C4F6
+:10C2E000BA8CAA3A277E63AAE09744DED79E87BC21
+:10C2F0004BF625F6FC8B1196BFA9DAD4963F4EBFBC
+:10C300003B743B3BF771D12A13F7AF0F6C6EF0FC17
+:10C310008E666FBC7EC6BA6FD490AEF81E9E8CEE51
+:10C32000E1FBB2A27675D1FBF545CFAF287ABED43A
+:10C33000D31EBD8BDA538D989FE5E7BB3E46A08E9A
+:10C34000F3C05D4FC4810FBE1261F15443CF79CE6B
+:10C35000AB99A33EE769DF174E7D85F11FDBDF1741
+:10C360009247D0E80FF5EDC7DF8B53E932829F1675
+:10C37000DAF879DCA7083F1F04F594A1C6116C8791
+:10C3800055964F0EC44C0BE251819865419E361074
+:10C390004BF1761AAFF795A5BF09E3041AD8797E59
+:10C3A0004A8CF905878B7E0FC4B99EE6FCEB9C3B5B
+:10C3B000E3DC57F8EF0E250606B19EBF6F56E70A7D
+:10C3C000B0870EDCF51184A7AF6CF30A40D7E908FB
+:10C3D000AB97B0E0879A62E857A2DEA1FEE6E908D3
+:10C3E000FA3BEC7C59271FE29CDB396F8E7506E423
+:10C3F000E1F7224E9E999D871BA6FE10D0A9B2D1CF
+:10C4000087E7175D3F37FD0AF4A3C4B2AC9E3BC972
+:10C41000FAF9F81CEB07D8BFFC18DAC71372586397
+:10C4200072585259DD39A571DB7D0E1395C33F86D5
+:10C4300071831DACDEBD3A497A406DBE5D393CCC9E
+:10C44000E56F7F519DBB737D5A4AFF02FB6F549984
+:10C45000DF35216F47D2B0BF2EB4A7FF267925C89C
+:10C46000DB9401EDB776F76F5F8D3F9490C579044B
+:10C470001B191F076303634C9F307AB92F6CBD05EE
+:10C48000F31D5DEC63706A3E84D3397FA8188E3E3D
+:10C49000B0F35DF069A295473FBB551581CF9DFB79
+:10C4A000B25979A701797FC09F3B9EAE7BFD0067A3
+:10C4B0007D1CFF723A7C8F76886F0B8F01EBE9252C
+:10C4C000F20CF1148AC79A28E0B141F3E291D73D0A
+:10C4D00038FACA79BF29CAE22ACE95CAE741C523EC
+:10C4E0009F3714C9E78F17C9E731FC3D477B3EC929
+:10C4F000819EC8F3F5E80339ED077A61EB12D0D9D4
+:10C50000BE6239969E07E7E99EAB4E2F8D32BE463E
+:10C51000FF4B71FF4E22FDB73CEAD48933BA7FBB93
+:10C5200078A4749B265EFBE1FDD112745BACC71D41
+:10C530007CEC8932BE76AEB07FA330835C057DE4AF
+:10C54000F60B030DB630D33983A31BAE403FD3198E
+:10C550007F2AFD3DE7F1339DEBFA68C24B67BE349D
+:10C56000B9957EBF3F50BA9F7494D91F8A2FCB7E56
+:10C5700077919F2B1788EBC7DCE7D86DE0F3840336
+:10C5800069591C7704AF718E17AAD3CAF4E8E4FB8B
+:10C5900019FE7E3CE8C59B73FD94336ED03B6EB0B4
+:10C5A00046F79C67774F54E0EB9B216C5D19DD04E7
+:10C5B000E28C6FFDF10CBB26B316D2EFFA81C400FA
+:10C5C000CAD324D6F9D1793179BAED4A11F4663754
+:10C5D00087CBFA19F1C853D739DDDD406F72D2FE2F
+:10C5E000B9FB7C37671D14B296DCE39A4F3FEFCF5F
+:10C5F000C1AF02A65CD9245EE8679EF787F97C1C70
+:10C60000BCD0F7578B54258E70F9E0D0B1A27BF5E2
+:10C61000DBDBA5EB87A32CBE44DB96558F57EAC026
+:10C6200050FE0C5BFBA3B87E368E3390DA9CBA8B3F
+:10C6300076619DB66C888795A535E7BC3B1BE2F813
+:10C64000D4A5CA1C647557C7101FCE798D7147CF0A
+:10C65000D89E73757B799EB5A22E75CE70E555DF99
+:10C66000837375BF0C7C3AEDB9BA19C72F667EDAB1
+:10C6700061F0D312937EDAE1CC7BE3A71D7E87E7DE
+:10C680006D94F0D3BE1D7D1B7E5A403B51B5895C35
+:10C69000BE9F066802FA8A5D6DFD9CFDCEA6D68619
+:10C6A000FEDA42EB6968F76EF7B7C179D6B165D6A5
+:10C6B0003D605FD6E991B6B66BA79FD7049F9659A8
+:10C6C000AFC3BA4CF1979D732AC3DE732A2FD75F8D
+:10C6D000DE235B184FEA335663BE6F329EC5DA2500
+:10C6E000E249BF72E3B1386E70B97EB533FEFF0721
+:10C6F0006350C6C7008000001F8B080000000000C8
+:10C70000000BCD7D0D7854D599F099DF4C2633C9B7
+:10C710009DC9249949267033804C30E0240C103593
+:10C72000E84D0892406C478A3576D9DDE1C78AFB2F
+:10C73000D167A3628BBBD8B90921094990801182C6
+:10C74000603BFC8A6EED0EAC9FB55DBB9DE04F6318
+:10C750006BBF6F64ADABAEDD461679F6D9F5B15956
+:10C760003F6B691F5CBEF77DCFB9C9DC9B04B1EE9E
+:10C770003E8F791E9EC37BCFB9E7BCE73DEFFF3903
+:10C78000F74CA7DCE0A8F031A6D699237364C67AEB
+:10C7900004DC5B3BBBDA02F065FCBB99B17C7783C0
+:10C7A0005D2A62F8A7B062C6EC8CFF1DBAF7EB8E6B
+:10C7B00078156305B52C32DBC19F5D6613EFADB70D
+:10C7C000C6E7E27B1A6CF74758DCC55891049DC355
+:10C7D000738B2BA5DA2A182B599BA4E78A2BDE6EC4
+:10C7E0008BC2F32A16E96513CFF7CC548AB19FF3B5
+:10C7F0000512BD77283012C071B57ED469DEBBD575
+:10C80000A39C2FA0F7E0E122C66C803E9BC598EF69
+:10C810002B2DCA0E68BF83B1364B04C66D857A983E
+:10C82000B7B78A257B011FAB94A6F7DB5C717A5FF3
+:10C83000C3DFE61BA3E75BE11533B4676DE6E4F104
+:10C840000A9C753AF736F744BB436DA112C44F8377
+:10C850008DE5C309A0D79CE9EB0B4C2C9682711C8B
+:10C8600015C71CEB5D13CF6B2513CDF71597528BB6
+:10C87000F430D2FD50935C22B93EFFB83DF211DD99
+:10C88000B82B70DC4534EE0A69D1E471190B4A17F4
+:10C89000F2046C614C4AAB67907FAE7B9ED36B6FAA
+:10C8A0001DAB355D0765D33907C28C25A9BFBD49CE
+:10C8B000666605F8FC4309E9E56D4AB1A9E876C466
+:10C8C000936C8DC17BB3AA223F33C3BA3173F85442
+:10C8D000DE0C28ADF00FE0BEAAD0E15E13EF377B8F
+:10C8E0001D8EF61F511DB04E9EF619A72D50B68411
+:10C8F00093EC1CF4EFEC4FB2F559781CAD62372184
+:10C900001E47FBCF491CBF017A5EBE4531233CFC6C
+:10C91000F8E282D12BACA77BEBDF57372E8452395C
+:10C9200055DD58387D3B6DBCFD4BFEA5ED05C0BB0C
+:10C9300040724672E0698175548E5DA1FF3C16B964
+:10C94000E308CC2F6FB659CD5930B9BFF1765B2FC4
+:10C9500004EEBAC2F83BE72C2E895F813FDC5BFF17
+:10C9600095DE0789223EABFAA4E3CCB588A7C2E5E1
+:10C97000A2E0907DF81E80EFFF3FB9AAC38FCF7D64
+:10C98000EAB9F0041F541CF2BF720FD07937734B11
+:10C99000BD50FAB6DDFB760EB4977A988CEBB3A750
+:10C9A000CE4CEF7FF86AAECA22A84DB2DE0F311628
+:10C9B0004A3FF87601BC2735D9E55C186FEF43CCC8
+:10C9C0006485F6EA4E963A0EFCF454021A02C12A25
+:10C9D0004E5E74C4609D4327E5334EA89FF7BDF8B3
+:10C9E0002CB34CED5B5340C76B4F9A19CBC26B4FC6
+:10C9F0005DA880C1F38A67E0BDF993E7ADF5ABC1EF
+:10CA00009FB5DFE9E869EC573AC98645BF0B2DD4DD
+:10CA1000AF64EE47FD5BCFF5C8A4FE15E8FF0AEB57
+:10CA20003509EFEFC91DD8FFB52723D720DE46FE15
+:10CA300030F68FF5480F67A7F95D5B3E94B51F256B
+:10CA40001896ACAE7D7C5D48BFC13A81BCFF3264B4
+:10CA500026F9D6F803F520EA8B4EC7BF169F07BE0E
+:10CA6000B1E6FE47F1799083EDD82400CF6D4037D1
+:10CA7000922776E9E6C50CBB06D945E8B2250D70CC
+:10CA800017C2C017EF491EC2139E5FBE0CCF3BF109
+:10CA900079C5F4F3EE34F1F5E8CC65ADA7A7A0FFB6
+:10CAA000BB425F75BA793BFA033A5BFDF291DEACAB
+:10CAB0007EDF93CC340FC447C9B26B8847A298ABD2
+:10CAC00017067474B18CA282DDF8A1E9459606FAC6
+:10CAD000E6C55D6DBD608ADCEFFC348D7600F08DBF
+:10CAE00014D642BBA8F5E3D16CBD68795EC5717FF1
+:10CAF0000B38584CD83FD487C5F88087AB0A0C4711
+:10CB0000FEE4F7F21C29867ADCCAF8F34F6D0FF6C3
+:10CB10000AE5244F616DAA07E99C554FEF6514D4CF
+:10CB2000933097B6658129F014788518D7DF5BDFDD
+:10CB300059977C31AB3EC7E3F6917E5FC296D0FA3F
+:10CB40005BD616909E747919BB7E32FD7F9788273D
+:10CB50005F9C33C1277D82FEEA2013F63266467C55
+:10CB6000420E36DC5B4D446E68047896E238D50B95
+:10CB70007A21E8E1EB67B9F4E70DF85ED2C1D2BDE6
+:10CB8000302FA7EA752A306E48F0AB2B2C99B3F5FD
+:10CB900072856A762A00CF516B5EC6FA59AC95C68B
+:10CBA000011E93860308C7CE5C86FE0AD305633D4B
+:10CBB0004B016EBAE6CC2CBE7E63163FC2AD0DB300
+:10CBC000A28207082E35CF8E122B8E996B11AEEAFA
+:10CBD000C07AE9BE7C9921DCF8D533CB00AEEE12E9
+:10CBE000ED1BFDE646E8EFFE06C79803EB07833A28
+:10CBF000FD1812F215EAD43F9F44A717353A49169B
+:10CC0000C47F1ED2C943F2DA80FD47904EC07FF543
+:10CC10001EEE0F582ECD5C86EFED453A013D9D4D41
+:10CC20001D44877949A0D302A493AAA353B8299499
+:10CC30008BF5D54D4027A8DF5DE7A5719EC201E1C8
+:10CC4000FD9B2F152C5B06FD559B988AEBA1C9A572
+:10CC500097781AEC7AFD47CED9F0DF79B5671E34A4
+:10CC6000E54FE89979B5BE65484FE211A047759D3B
+:10CC7000AF8184DECF46CD8BE955FA1B12FA212114
+:10CC8000C7BFE281F74A5B07866D32FA83CC84F630
+:10CC9000BFD726E4365E43ED965BAA0ACE4DA107C8
+:10CCA000196BE77E04E8412BF0DB40C241E58E843E
+:10CCB000C4AC36C69E4DF8097E2A2153793211A69E
+:10CCC000F2442242F58713B5547E37A1D0F3C7133F
+:10CCD0004D543E9388D1F3D389568253893895DFDA
+:10CCE0004F6CA2E7DF4BB411BC3DB195CA7F48A899
+:10CCF000543E9FE8A1F24789012A9F4B0C51F970DD
+:10CD00002249EFF5274E52B93391A2D2EB940F6C22
+:10CD1000443FF26796C87128F6960E905F79744F7B
+:10CD20003CD2214F9EEF81C4C0526B96FF367CD718
+:10CD30003557F44B609CEAECF6B94D0ED5B2004B7A
+:10CD4000D587EB92DB3450CACBA497D1F3941FE183
+:10CD5000FD9E5944D7DCA6575BC91ECC867EB2F433
+:10CD6000C1510FD7EB7B3B4E0556678DBF5FC8EDBA
+:10CD7000419389D66FEFBC48E96AD7E4FAA315DA84
+:10CD8000FBABA7AC3F6E3253BD713E4F7BCC543FE3
+:10CD9000AB29D58EFA6ED404C6EF26F0CBFB631D0B
+:10CDA00056A4A36A633975A45FD276802DB2B50DFF
+:10CDB000F9D736C8DB4B1D76AA9FD3A450BD6C6251
+:10CDC0006DAC14786730D281F50E13BC1F8475C921
+:10CDD00089285F47BD60666D1DF0BEA5A9358D7EB3
+:10CDE000A4639DAB2D07F83ACF35A698B2D607E2DB
+:10CDF00084A7918FAD4D5DFF69C9C7F881BD58000B
+:10CE0000FDB99A58D282F1048B107E07D582782F13
+:10CE1000E9B9D56609E8D33018738E4E31CFE39B5C
+:10CE20006B9C2807124BE5A27D3EBAF9CA7E0059D9
+:10CE30002E4D9F8090FDDEAC3CEF01BDE0CD6B6BD5
+:10CE400043BFF24082A9E788EFA0047EB820E86CD7
+:10CE5000B58266047C0EF69BC9BFDB6B8BFDEC1ABA
+:10CE6000C0B3FB5173E408F475BCFF8C05FDB10F32
+:10CE700037B26AB483C3CD6F2C43F8F826569D238E
+:10CE8000E3FB69AA3F389BD5F4027C66F0EC329C48
+:10CE9000F7D130AB41BFB674A35DE76F1CDD7C4EAC
+:10CEA000B544C9DF8EA0FFE39CADAF97586C25EA6F
+:10CEB000B183836686F81CDDFC611ADB7F18066F80
+:10CEC00011DAE7440748879C196C207B761CF0CE6A
+:10CED0003161B9DA89F6C85905FD65DBADD97AF853
+:10CEE000F8A7D0F1C67FD3B7BF7E540F5B594CACC7
+:10CEF00063BE82EB382773235FC7FEC894EB787458
+:10CF0000F36ADD3A1EDFBCFA8AFE22AE635ABF8E98
+:10CF1000BF45BEDA5BDE467601966EACA37A621D33
+:10CF2000E748DCFFEA13EBDBDD6227F99EAEFF9CEE
+:10CF3000A6DE18CA794ED380C4CB24E981E9DACFC2
+:10CF4000F656109F7437A5A85D77F0B4635DD5C41D
+:10CF5000B8C6F645DE1C6A3FC7C1EBBB83474064D9
+:10CF6000B2FBE3F62AAB5EBA5B579FC3EBD1F1BAD3
+:10CF700001E464AFB453C5F1FCD0BE0ADB9F99BA9B
+:10CF8000BFF1FAD3D23DBAFA5C8E4F501BEF8C340E
+:10CF9000D5FBB3BD3CAFD01DDC4BF90C28291EB529
+:10CFA0005A61DDDCB88E53CBE30BCD8B69DD8F6628
+:10CFB000563B910FA6E34B4902B942BE7FDDC27AD0
+:10CFC000A7E07B97816F0FCAA95CF4FF3C0AF0438E
+:10CFD000D673BB2F8B3F483E57131E47E58813DBA4
+:10CFE000B3B8DE1F5BF2A6FEFD6B4FEA618D1FB585
+:10CFF000F18CEB5999D4B79F3B6478DF30BEF1FDDB
+:10D0000050A71E5F799B01FF4F197FC6167DFB4518
+:10D0100099A9C79F8E7F178EE8DB57A7A79EFF5160
+:10D020001C7F0AB9BCEE397DFBF9A9A9DF9F6E7C94
+:10D03000AB4BDFFEE68B7A58F3FB76C4D6C6EE0226
+:10D04000BE505E57548C2FBC185FA0DFC5147514FA
+:10D05000FD7A30318F45D0CEC85C6F8BFC94968FB3
+:10D060001A9A1F790BF322A3A81CC11E7E77FE28F3
+:10D07000C18AA580E083F3930427D138011C7EFE8A
+:10D080002CC1B9AA9BA11EABBA749A7D1DCA7C7033
+:10D090008471DCBC967D0CED1F6BCA253F2E6FDBC7
+:10D0A0008534FA292F6BF0D67DCA51801B308E074C
+:10D0B0003F373FFAA334BE7FFFC326867E6FFE6CE8
+:10D0C0007D5EC0B7ED948AFDE542BC857E6BEE3691
+:10D0D000FB9DA8D75777007E606F772F1AA0FE18A8
+:10D0E000F607F698CDE6F126BD0F4149DF035F5DF7
+:10D0F00089FA0A6328F407FB02A937D7C3FB3B9BD5
+:10D10000ED912332DAAD01CA0F6974FFBE97DB37A8
+:10D11000AD84BF463FFA03608F799E2892DEE0C35C
+:10D12000B88E113E00B38D98E7E8E4B025DA93415C
+:10D130003D6A893ADF4592595ABAEEA5F1E3FBEE12
+:10D14000473D68D97AE2012A373FFB2D2A37BDFCDB
+:10D1500020D56F79E3AF11067FE0FB5E8C5FB65D93
+:10D1600078889EBB785E6B2B93CEECC4F8A20EE25F
+:10D170007DC0E33BA6CCBFA1BD541FB2CBE8EFEF0F
+:10D18000FAF66833D2C1CFCAA50E78FE9DBAB3FFB6
+:10D190009683F65781D00CEAFDE95CB2037E453AEE
+:10D1A0009C8BF3107EB91FFF3F0BF36E810E5C4F1B
+:10D1B000A92594C4FCC94ECC0FCC057E784835A176
+:10D1C000BFA3AE63A7D0CF94C2AC1EFD4C49892C3F
+:10D1D000269FDCE523BD21C519B5CB0DC767619836
+:10D1E000FE98496AE8A3F738BECED9669D9EFA4EEE
+:10D1F0000BE087F679136007E395A6DF22B8B451F8
+:10D200000AE1F81A7EA5881F0CE411F87B1AE5C321
+:10D210007AFC92ED84DF3D801FACA7272C117E9E07
+:10D22000468E9FB6AE9E4D527B367E074DDC8F9C60
+:10D2300084575CD06D3360056397215E00976DD293
+:10D24000E35526E8568A7821DE9B8C78A58609AFBF
+:10D250006F70BA9586938457E9263D5EA59B93C36C
+:10D26000D9783D6E92CCFDB8AEDF98866E9B057E78
+:10D270002AA79B2CE8266FD1E3270BBA950BBA950A
+:10D280006F31E2C7CCE897AAED9C6EE5E10CE1575F
+:10D29000BE458F5FB99A31613BE7ECC83566C22263
+:10D2A000A9CB0B19F1DB73C777CE60BED419E47636
+:10D2B000CCE98ABF86FB027DAFD95807D40FCFFFD8
+:10D2C000A61FE38EFD777CA7C304CF7BE7F376DD53
+:10D2D000956FF851A8DEB3675A37C07C7A17994921
+:10D2E0003E2D985841F90ED98F203D8C7AB2A4B0CA
+:10D2F00082F4E0AEF935A44F993543795C8B53BC89
+:10D30000B758C4C3E2799FC464EB7550CAB8288487
+:10D31000B6827A88C6B9812B5607E89F47421AFC25
+:10D32000BDE64DE0F793ECDF20DAC338FDF6F1F708
+:10D33000559CFF230D5AFD096ADFEF34D49B4DA2A3
+:10D34000FE49AA77B394039C0216291C6A7680FCD6
+:10D35000FCBD3952E90078011BDAD9583E7DFD9FAA
+:10D36000150EED6C9A3131FFC1B5D6A6E494F16D7E
+:10D3700027AD93F362802517C2F8DEB64DA8E79C6F
+:10D38000D624EE554CACDFC5A0AE7E10F843015755
+:10D390002AD6FC3AE5BB1B0BB91E94A26D2AAEDB64
+:10D3A000CC688ACA9C5852C1F57286538A0DF3B56F
+:10D3B000B06698FE754763148777D99434F265D7C1
+:10D3C00022966C47572966664A169FB89B6AEFB645
+:10D3D000827E63517D1E57B36BCE8BB92C593819A1
+:10D3E000EF1B0A653DFF5D7451BBFFF9F69553D203
+:10D3F0007172FB2A6A373C6A5191BFBB7C2C99033E
+:10D40000FC67F30CA515985DB525EEB809F578997C
+:10D4100099A1DC4D5A379F756C54470FEB3984CD79
+:10D42000AA895D067D53C9629487CE15CFA95D0593
+:10D430008ED35042FC9FFDDC3219F6AFBD9BDD89D7
+:10D44000F271B190F0D4C6ED2A0CF3BC993542F9D3
+:10D4500043CBC562AADFCA841CB9B81CF9B7DCCDBE
+:10D460005667E5C12D7E96CE453B25F280261313E7
+:10D47000795F0E63020DF19E6E5FAAAF707C7FA88C
+:10D48000AFF02AF687C6F7CFAA78DEFBF40C8E5FE2
+:10D49000F77CF3E10E80BB3D1C56DD76AA6F5AFC8B
+:10D4A0005C0FC6E743556613EA994CBCE14D5C97A7
+:10D4B0001CBF5D46B8AF8AEFB7F983C0D780D7DC11
+:10D4C00085225FCDCCECF25CCC27A59809F571B331
+:10D4D00095A1FE7929C4EB5FF2707CF2AA640FC6B5
+:10D4E000055DB9F12113C8E7D247955556F033AC25
+:10D4F000CB92438CF2936F348F807E719A853E502D
+:10D5000037AC525C82AEA00FBAFC2DFDAA8BF2564E
+:10D5100054BFD3FFF64E8487DFED0EA09C0DFDEACD
+:10D52000413FFA69DD817800FD4CC9DAC66259FBDA
+:10D530005439AD5D19CAA305F572B4CB047A0AE972
+:10D540001070901DD1F6EFF69A143FDAAD87C5FE44
+:10D55000D7C3EFD8922AD0A9C714A7E761C7680F2D
+:10D56000E629F7C93EDA0F7DA738A4E3EF7CBF3D7B
+:10D57000327B8A7DA25E11576AF982E1F06907E287
+:10D580003FBCF1744F08D7276EC6ED06D66B6F6BA4
+:10D59000C278A67B8199619EA0AFB563E71C803FEE
+:10D5A0007AD546F972ADBF578B79BE6687ADAD357A
+:10D5B000467CCDE97E3BE08DFCA4B55B53C4E3B073
+:10D5C00003762197173D4C05BEB53EC44CAB814E4A
+:10D5D000AE62A1BFC28BEFB6623E6AC691B809D6F1
+:10D5E0006EC1BE0F9A1DA0679D4EA1B7D5DF342B2B
+:10D5F000A0978B849E5FB0EF37143F1AF7994ABC0F
+:10D600001C0F1BAE3FF0C75C8F80E7E9F11A48D4CE
+:10D61000569F077AEC4F28D5E7616A8F269AA89C17
+:10D62000CEDFBFDA52A3F3B4F5F99C0E95757CFDFD
+:10D63000EDCDD7E8F62D5E2ED2FC5A8E77A08CEF7A
+:10D64000CB5CEDF856EFC543D7C17A6DA9B4CB9842
+:10D650009FEA3575BC52827C6672A48E4339F48E83
+:10D6600085E2D86ED9CEE551E17CA6B672793C9FB1
+:10D6700018918E21AF3BF8F342D94EF859BDB51E33
+:10D68000E473E3FC7A2F1DED0941BBBE2607E535A7
+:10D6900087AB8E10DCED7346308FD49B9FDC44E368
+:10D6A000FD855D3E4276BE6DA402F9F7B542E2DF2C
+:10D6B000BB2C00A3BEF8BF36CA933E76CFD7DF8A15
+:10D6C00043FDFE225704D5A3ABE639FF3DB0CE4F54
+:10D6D000143B888F5C6616A77DA716D0C3597104CA
+:10D6E00070A4742C4B8FE617F1FD9FDDD69403E5F3
+:10D6F000B24F7E6604F95C3B0FE1A8E0F014E7212D
+:10D70000C23E3C4F6051EF0C205E961C761CF5D358
+:10D71000BA5BF25F0078DF9F5A255477DE3DDB87E6
+:10D72000EEC278AEC22EA35CF409791848A4AA3BD5
+:10D73000697F24E2473BF008C01B89BF9EABDE38FF
+:10D7400007ED6ECA4176C7E4505578BFC4145B003C
+:10D750002A9DDDBE2FB2CAB114FCAB505B00F5D2DE
+:10D760004F7CC77AADD7A35F92FABB4ED05BCF0C8C
+:10D77000CECDB3E7A2FFA5BCB21CEA4FFBEEECF5A1
+:10D7800055E2BC52D7320F87B1FD7ED413D0DF579C
+:10D790001EBD7115C20336213F2CDA877ACDA5E96B
+:10D7A00039F493807E5283A6F7DA56A2DF63B1C7BD
+:10D7B000FC128CF7868FA94D75597E941A5E89FBF1
+:10D7C0000A9ADF74D6F7BF7A51FE2CCEF426F48382
+:10D7D000868AE7D3F85ABD5CD2D1A7D2FE6086F420
+:10D7E000A1BBD149F92B375BC3E551D845B6E976E2
+:10D7F0009DFCB66EBE5DBF7F62053AC2FB7126D945
+:10D8000099F0610E81FECEF96990E0EE5BC11D8258
+:10D81000F9EFF0795F5E07741D8D399945CAF24BB7
+:10D82000BFA6F997AA09E95ECCC22AC651DD926467
+:10D8300047BF9E9DB133C70D98173277E139930DDD
+:10D8400077E6D1FB1B4D918C82F53B2C11F403E064
+:10D85000CFBE2E8A7E9593E26866655D1857E6BC5A
+:10D860005E4A71E576133361FE50BD9551FB7850E9
+:10D87000B2631CFABB379CB49F047F31473163AB62
+:10D88000F8D430FEB10EA35F16362531F6FDC5C8BB
+:10D89000595F3B3CFF72F347FDEBE0FD6B8A797EFD
+:10D8A000EE5C26B4E069781E5FB8ED967C19F988C5
+:10D8B000EBEF015176D9F8F918F57A13C9CF70BD9D
+:10D8C000DD8EF6F7FE7A1641BAC41BEDEB4C0B2643
+:10D8D000ECBBC6E73FF759483E5EF2713931DAF5E5
+:10D8E000AEC0B3FE38F9D140779CD72D4C3A0E7CB0
+:10D8F000B7CE920C9A664DF0F3BFC6D6DF822CB538
+:10D90000EF569002F0DBF705FC2F231DBA5F019F55
+:10D9100008E8521CF0BD8C74DBF212321BC94512B0
+:10D92000CFE774975F5381F2DF2FE2BCEEF2C5744C
+:10D93000EE0746923BF0FDF262CA3B3F22F683BB04
+:10D94000CBED0CF31AEBAFCD3982F4EAA9E8B2E4DF
+:10D9500043BB75072B6A507E1FF12A0B7F81EFF5C1
+:10D96000BA6BD06EED023F3909066D77C241E5937F
+:10D970003E6E8762CD1F91FE2B06DE46BF4F6A5575
+:10D98000DBD1AF98D9CAFD677F3443F1434EEDA890
+:10D990008AFE739F2D568FFEB35A6DA275CD8F9A56
+:10D9A00071CF729C4E529D5307FFA3D03B8CAD9517
+:10D9B0002E5C0BDE9572BDE532949642E566D42B63
+:10D9C00037234F2D42BF480DA01D18F268F255DED7
+:10D9D0009B764DF6CBDDEFD7911F3EC90F35F8E5AD
+:10D9E0005ABF9D6BE6AEC3F57207799EDD1DAC2173
+:10D9F000BB6A6C7FBD68FF8A2BF6535F11F7FB9003
+:10DA0000FE3B7D323D9F8E1F3AD7DC41FA3C07FC3E
+:10DA1000058CB972E2353C4E30F83705263EAF979B
+:10DA20007CCB56A29E90ECE956D4536F0C867B318A
+:10DA30005E92BC9A1E5AD2970E82FCD832140F6B9B
+:10DA40007AC2385F4D6F60B7974D9FAE37BE26E6FE
+:10DA5000B7DC72297D19F9EF5633F9F9329B4D760F
+:10DA60006D5798EF8B546CF9FBDCEC7323E01FB11E
+:10DA700063B47FE8A0727F42A2F2F1849F1D9B8372
+:10DA80007C2F53F9DD44989E1F4D44A874D9933BD5
+:10DA900043C4DF223EEDD97BAF07E4A5D89FD7EF83
+:10DAA00080791F2E95FE02F57CB1BF7DA52380F401
+:10DAB00048BE728D87E0DE4ED0EB8F015FA19EF6EF
+:10DAC000FBE7F7AA8062A8545E8FED6F1B2A6921DD
+:10DAD0007A09BD0A70BF0ABCEB72CA47D09FBDCE9F
+:10DAE000BF7525FAB3A15BC6F5743FEA69637B375E
+:10DAF0008BD59B2C787E2EA31C8BE23910D6867A90
+:10DB0000CEBD668D5EDF6E5DA3A3AB3FDE46F9AD95
+:10DB10009CF09A89BC1DD197E7D535FDDC6753F29F
+:10DB2000516ED572B38472E298A7CAE897F7557917
+:10DB3000BDE8BF764B6D3D28BFDDC19007E1F355D1
+:10DB4000668A8BBBD7B2A667C84EB43109F3766735
+:10DB5000EF3ACAF3785C7F7B6A2347699D7C76BE87
+:10DB60005F312A0DA37FA12A8EB1E348EF51D0D3B4
+:10DB7000D8AF12217FE2317C17EB2BB9DE2F0C1EC0
+:10DB8000A1731D2CEE6A039E66F78D540FA3FF51FF
+:10DB90000CEFE3FC975BEA7E1AC4F7D7303AAFD5B7
+:10DBA0000DE6A41CC6CDBF8D455419ED8D9DE4DB5B
+:10DBB00034504F7C2735DA75F2FEC0EBF7FE14DBEC
+:10DBC000E76C64A487F259567D05D219E0AC387031
+:10DBD000AC84EBA1ADA3ED26F4A79614B97DA827DC
+:10DBE000D842B610FD96FB5ADB56A0E9DA1A8FAC84
+:10DBF000401BF9DB60430ED94AC19F5A9C5021F863
+:10DC0000FB91442C897EECCD971214773E12340B95
+:10DC10007B7FB6390DBEF823D6C894F9F763181781
+:10DC2000679D7FF4B5403F59F31A1E7D84CE57F4AB
+:10DC3000C5B9DCF48D6EC845BDB82F0E71EC15F278
+:10DC4000F239172DBAB83507E2211C3FE7A29D9E95
+:10DC50006F2C54D6141521BE3F217C6DF3CDB12419
+:10DC6000F49B427EC8CA7B7CAD88FB53FB45FC30ED
+:10DC70009088917F9E499B0B5B60EE795146FEA593
+:10DC8000A4C43268EF7C41DC1386F56A041581FE7A
+:10DC9000603043E766240C356594E356E1E7C775C9
+:10DCA0007EFE40FD371DD8EEFEF67CC542FCD95005
+:10DCB00010CF8A674C3378DC5018D3E7BDFD6B7DFD
+:10DCC0003A7980782680FE4061DC4E7C087EF21036
+:10DCD000FA81431E1E1F39C3293A4F9413946AD008
+:10DCE000AF2D5EA37FFF8575CF32B43F79F1B809C0
+:10DCF000ED42715035B1F964E707D07FF45F3ACA5D
+:10DD000062AE09BCE83DCCBB3632B5E03AA403971D
+:10DD100097BE7296AC32D173E6C0F52BCF3C5D95C1
+:10DD20009597EB2B4FF95D5974DE31FF9B0ADABFF3
+:10DD3000BE87206E45394F3FC86437E209720FA590
+:10DD4000149486518EA5462984E7CEFA3EB1903DC3
+:10DD5000EEAB48F931BFD2377F71C97A289F16EBF5
+:10DD600034891F1C0B6FDC98C50F85C1C5DC5EB400
+:10DD7000E8EDC543A84BE05F44F04365A3888F3CC2
+:10DD8000C574FED3C817030995E2B747133DB49E87
+:10DD9000858D8AC9CA26E8639B619E72DD8C749F5B
+:10DDA000D0FB033ABE28DDA86F67A4FB27855CFE85
+:10DDB0007A2B4FD03E8D33CC54CB75B4CEAD2AEAFE
+:10DDC000C3E1075995A0E366843F399A46FF13F4EF
+:10DDD00052D55479A585220EEE9B7F42453EF90827
+:10DDE000F5B36FA2BFA9E8DA593899AEC6718D7440
+:10DDF000760693ACC545EB48F6E1078F0656A19F22
+:10DE0000AEC5CDCBD1F68222F429917AA4E7A7F151
+:10DE1000BD919E93E9C4ED44655D5C4279DF25FCCC
+:10DE20005690F8565CDFEDF3ED12AEEF70B4A664D9
+:10DE3000AA7D76ADD4E2A871783CAEF9C994714D53
+:10DE4000A116D7B033ABB2E39ADB4A0C710DFB7865
+:10DE500025BEAFC52D2BF79FA4B8458B6BBE56F2E0
+:10DE6000075D5C73CFFE67FBD09F19F757627F6435
+:10DE70005CC31AA50BE109FF70BA7963A071212B6D
+:10DE8000AEED13E72E8DED569458887FB60B7F7A52
+:10DE9000E1AB8CFCF62F2952359EFBD2DAEDF47102
+:10DEA0003E33C611C5ADCC8EF6F94B0A8B607B882C
+:10DEB000236E417D767FBD43CE8964BFCFE5F4807C
+:10DEC000B34DB72FA795BF2E3489FCF0449E07D7DA
+:10DED0007DFC9CE9420BC9A531DF337BBF9BE2DFB0
+:10DEE000897C4FFE2A253891EF99BD3FBF6FAA7CF0
+:10DEF0008F366ED811A7FD7C2DBFA53D1FDE78DAC9
+:10DF000041FA6DE37D0EB45BDDAD0DB40F71209F62
+:10DF1000AFA7B4EF37CDE81F7DE9D548C9D229E4D2
+:10DF2000320ECD8235E8970B7E51EFFA19F28BE66F
+:10DF3000DF760DAEA73858C25C4D0D2FCBBC1378E1
+:10DF4000CE015FEEB219E9C284DEDA24F4561B95E5
+:10DF50009A9C8DEB2D91B71CCFFFCCE0F91FA31C31
+:10DF6000DA760C9C41BBC50256F273F627B6527F97
+:10DF7000B65C163BED9A2C9746B99D2CA73C6E8952
+:10DF8000B0E7E8FCB5D11E6BA5D6EE13E13F444CDB
+:10DF9000F6183F071C976F9B3F45FC32CD3E82161B
+:10DFA000AF687E46B7F033BA47FFCE81EBD3F7298F
+:10DFB0007E86F3629ECECFD858185F57BC88E7FDA7
+:10DFC00025CA33E653BDD5EBE8CC8FF2FD61CC8793
+:10DFD000B5B9E25FC776058E34BB5E9ED8BFDD2F34
+:10DFE000F8EC2783415ACF815C885750FE7DF32996
+:10DFF0005EB1D8598589F2224BFA3A815FA4105F4D
+:10E000007F6B494B9F1AC4597DBE3CC79D821E5AE7
+:10E010007EAD4BC8F170F808E567EF6F76907FEA48
+:10E020005D59FB4F6B01DE71B690F256D53E2FADB8
+:10E0300043AFBD2D80F67B40E8C96A21A79DE5EA84
+:10E040009D48DF4E668EE0BEB375DD57E930B0F215
+:10E05000514C1DF5D1B9CFB6C7605E05BE149DDF2A
+:10E0600006FA1C2BCCB2E3DA79846385FAF5DA2759
+:10E07000F60FDF6B88E7DE8471F77A33C3FDC0A14A
+:10E08000A07EDD3E16764D836D93D76D08D7C366AF
+:10E090008DD1BAD9C4BA19E3418D9EF6ABA4E75726
+:10E0A00037EAE1356BF5F0EA35B71BE2193EBFC739
+:10E0B000B4BCBC881F9C9E4DEDB8BC45AFD69BCA76
+:10E0C000D9647F1FFD78F47F9CAC9FCE15B0B07EE5
+:10E0D0007FE84FFD7CFECF148B73D6C2CFDF129347
+:10E0E000BBF15CECB736AA397619FDFC9A15D97EDE
+:10E0F000BE96879DEEBB9EBB2CAC6D2A3B70BB9F32
+:10E10000E7493F2D3F8A7955E47BCD6EE63F2AAD46
+:10E1100054691F83CBE9DD2BB8DFFB92C89FAFA802
+:10E12000E7EF3D53C8843F0E120F0CF918C4C9F134
+:10E13000B9C00F102763A9F961362BEFE78E7C3643
+:10E14000A5FE2ADBA48759AB719F51AF9F7608FDCE
+:10E150007BB6F0A995286FA15827C5EDCDEBB8BFC8
+:10E16000A8C98D5616969884BE6D5BCAF3FC5B9762
+:10E1700072BDAB2E9D4AEF2E9FC6CFDF616B1BC6D3
+:10E18000FC5AF77246E726FD8D9FCDFFA92C993AE0
+:10E190009F6FF48B34BB3D49DF09F9B189FDD02C69
+:10E1A000B9B95C5C942D377C1FD476D164942F6B05
+:10E1B00089AE9DF58AF285EC7035F9953F56BED053
+:10E1C0003E61FC60B7C6736FCBCABBBC2BF2E7A93C
+:10E1D000566E77607574F94AAD5E2B252699703FAF
+:10E1E000EC7CB14C30B875269C4F318B5129397974
+:10E1F000BE09F533E55B0CFAFAD3EC757931E7F338
+:10E200009B2FED26BFC2867C06F8A4E266DD7EFE6B
+:10E2100075251C1F659CDFB87D7F6C1AFB3E9D3DFC
+:10E2200037CA43650BF0851BF975AB2E2EF9747F49
+:10E230009BD33922F0AD6C8C4BD9DFCD69F88EFBC6
+:10E24000631EB3EEBD89E7DC4FBB2CE2B2427BE438
+:10E25000DD4ECCFBCDB0931CF48B73FCDD1EEE07C2
+:10E26000BE2FF29EB789FE35783A3FF96AF3781FE0
+:10E270001571BCA6EBE77FCA1E68E3160A3EFA4694
+:10E28000C9D3C44785828F20E2D5E72D6357CE5B83
+:10E29000FE4FC99586E723C25FF9A8E80FC25F89E0
+:10E2A00090BFF2FEA327FB7AEA26F0FEDAFE67575C
+:10E2B00021FF8FE745EFD5E7450F625ED48479D122
+:10E2C0007F7664EF63FF77E5450F89BCE8A9FD6FB2
+:10E2D000F665E7454FED3FBB0AF12EB4279B67512A
+:10E2E000FDD9BECE4A90A3CD66C2FBEF200E53AD42
+:10E2F0001379D17F2F796F15AD8788CB0026B9D6DA
+:10E30000F2A23FDBFF0AED7F8DE745D96FFB302F8F
+:10E310006A6C9F9517A57DBECF9B17FDA8489F17D8
+:10E320003D51C2611C07F5D581F099E630E0FF014F
+:10E33000C6A1389F92F62711DFE192DFF5611E77C3
+:10E3400008F1A5B8F67714D7168A38F583FDA384AB
+:10E35000EF81A897E6F76B8C4B814E15E3F3FB58E2
+:10E3600037BFF7F7FFA62F3BEF3B63EBA7CC6F8BD5
+:10E370007E7E4F23DEA857D7F279BAD9403BF653B9
+:10E38000B486F7532ABEAF766FD4F713684D991C45
+:10E3900032FC675B165D30EF106F53F079D1D64CCD
+:10E3A0001A4D79F996389D432ADDACA75FB1A13F9C
+:10E3B000239E9F466F0DCF99DB389E65DA7C8D7862
+:10E3C000AE499AA89B7E3D9EBF2C91F9B92C9837F7
+:10E3D000FA65455B322AFADD3F17F4C0FE711D472E
+:10E3E0000DF0997198AF3308138D6732D9F8B99E43
+:10E3F000D13DC3E5F2F4F1CC1F5B6AFECE6E513E17
+:10E400002E4A2DCF72D0B05F6FF3EBF3CDE379CE10
+:10E4100099DC7EE485F57648AAD3C35A7E7AC6167F
+:10E42000BD1DCA8FEAE1E066FD7B5A3E7B227FCDAF
+:10E43000D74DCB6F5B8AF4F43B10AE213969F4EB16
+:10E44000E5E41A7FA85F2F27A17E941349C849A34A
+:10E45000BFB09FE46433C809BC7F8B7FBE5E4ED4DF
+:10E460004ADE5EC8C957FCB3FAB3F500C8C995F7D0
+:10E47000470C72E22C9A564EA89F2F8A9C18F76B75
+:10E48000E6FAF57A294B6E08EFCF2A3737F8659E02
+:10E49000F731C84D647C1C2E272B0C30C4E78D1837
+:10E4A0006FD926E2F3AFF9F19CC7C029059679FC34
+:10E4B0001CBC319E3983FED9A22FAE9CDD67903300
+:10E4C0002DDEFBACF2F659E54C8B278DF1A331BE66
+:10E4D000BCCBC2E5E7767F7C5547D6BE8216F7698E
+:10E4E00071DEC5D16557BCEFA22B11AE3E96E59FFC
+:10E4F0007619E2982E33DB84707339F747F7F97990
+:10E500007EF0A0888BB5F299422E471A7F6AF87484
+:10E5100037EBF1D9E18927DB311EFB552E9D3FAE4C
+:10E520002F0D7B30AF3ED46CA5F38376B39A3303C3
+:10E53000F3620B189D87187AF7948A47E07F676229
+:10E54000A791CFF2AA621E8CD77F2CF0E8D2F22DD1
+:10E55000A2A4BFC5E27B71E0337B7A8B521FA5A7D3
+:10E5600063057E80DFF916AB827E0E2D73D077C3F4
+:10E570004A2428D6C3C2CF3F8EAE535D51FC5EDB2A
+:10E580009142B9B70783BAF5B207EB74EB159383E1
+:10E59000C21FBE9CC0F78DED8DE71D8DE71BEBAB59
+:10E5A000583DEDD355F273AC7DBFDA19A0EF4602AA
+:10E5B0006D7ECA8305BB3226CA4BE8BFBBD0E839A3
+:10E5C000DD77DE5AA99DF7F58D4807908E491370C7
+:10E5D00017C4CA7B6E534C782E62E05D137DEFB793
+:10E5E000631D7B0BD761CF6B3619CF95EDA9E0FB8F
+:10E5F00061EAAF72681D068BA4B78AA2F89D8AB53E
+:10E60000DA7413C8EFF25B0277617BB79FF6F1DA39
+:10E61000EB3FAEC2FB0DBEB5DA6EC675DCB334EFB0
+:10E620004EEC6FB03D28E1FC40FE0EA07FA9625E7B
+:10E630001FFBADB127216666B92C2DA31E71DDFC31
+:10E64000CF7EDAF763B27939D4BB4BF9FEBE63F5FE
+:10E65000CBE18DD0BFCDFCC86005D0AC2570A2DF6A
+:10E660009ACBD897FF811D407FF9DF87522DE8476D
+:10E67000BECD523D8B61BD96973ED06205BF33EF54
+:10E680001E8BF0AB122DE9D99F9D2FA49138F1017B
+:10E69000033EC8BB61329F7C5EBE9094189DC7DB71
+:10E6A0005DA8FC971FE426109F43FB7F0F5771FF67
+:10E6B000FDC7B5DE861F209D82E6E41CA0C3D2CB39
+:10E6C0004CC17DBCEDD5F6C31D585FD521D3FD1BD4
+:10E6D0008D7686F567DC763A0F3D00F548FF1F071B
+:10E6E0001B32659807F39B65AC778C4901FC4E287B
+:10E6F0005776305C2F164CFB317E5F6AD9E0C0F84C
+:10E7000068EE6385BBD07FEF2F4A86D14EFFF8C0FD
+:10E71000BFF45BCBF19C6DAC15CFB369F076D3D869
+:10E72000FD8CEAF7F5F750FC1419A2FB4280445621
+:10E73000A0E37677C46F92B2E0A2C89029BBBE3C3A
+:10E74000E23703FCE300539A005E411FA36212F319
+:10E750005FC88E370A780BC2E0FF2ECFE17AEE2138
+:10E76000013788FA2ED17E99A8DF2D6045C043027B
+:10E77000AE17ED0F0BF82651FF94E84FC69B24907F
+:10E780004F6BF9F747CA6D66E24F369F25E7007C6D
+:10E79000D3EF1B73F15C43378434B89F97F3C9FA06
+:10E7A000912FCB349D5C3CA79D6F4D31A43BCC3960
+:10E7B000B20BCFEBC5CEA5E9DC9AC2C6F2C0083BCE
+:10E7C0002DA934F5B710F419D07940594FE315D578
+:10E7D000B3314B11F2DD4F1F44F9CEABD5DF3B60B7
+:10E7E00057F8FD0057CB6716E4B35993DB7F22F44B
+:10E7F00033B3A665CC5301BFB50460DC73CB945B27
+:10E8000003459F5F5F1AE5E4F3CAC5277E6E473470
+:10E81000F908C497DF897CDF0D1E07DE5BF37630D5
+:10E82000C4CF9FD772B9A8D8B22A80E738FB64BE9C
+:10E830006FCF1CEC4031D4F7B74BF4FDDCDBB50DEA
+:10E84000078A514E40FFE23968E652486FF5BB8BAC
+:10E85000A9FDDB555E5EAF9AD81C1F0966A60CE0C9
+:10E86000FE805746FD3320CEAFAD6D7B6D399EC324
+:10E87000F5C5E46A34BD7B4C12D78FF576FACE60CD
+:10E88000C07D8B09F38CDBE708696003F43DCCDBCA
+:10E8900066D58FF2A2C957174B93BCBC750060D0E8
+:10E8A0005BBD4E2582FEED5B07DE6FC1F3D23B6C94
+:10E8B000113F9D6B57DF6F1901FAFF694E84E4EF3A
+:10E8C000AD032FB6F440FBB539206F1E845F6BE9B2
+:10E8D000BC1EE56DF401EC6F89FA7E7F13BCFFE787
+:10E8E00082DF6F7CEC7DC1DF5BD81DA8A7613DF1A5
+:10E8F000DCE39F2DBF4F5982F3AC778CCD894C5E02
+:10E900007F58C89D38CF41269F42FA39BC71E50E29
+:10E910002CCD6C4C95901F7272918E872C2C65AE0D
+:10E920009BE00733E3F926E4EFD9C4DF603FA5CFCE
+:10E93000CFBF4EE1E7AC3CF0ED16DCD781F9A4EF98
+:10E9400020FCF87CD6DD761F5B12BDE27C9AFDD9F7
+:10E95000F309C5891E5F94F938C53E407F11F7BBA6
+:10E96000FA03BCFC7721B79702BC3C2FCAFEF2AC7D
+:10E970007B733E87DCDA47583BCAAD6466A9BCBAF4
+:10E98000FF4EB965A4FF8AAA1D872D6497BAE81CBB
+:10E99000D9C06D763AAF3958DF25339A37C88184AC
+:10E9A000F3037B8D76C7CD443CF8614B3ACBFFEC4B
+:10E9B000F7F0F96AF08B18542CFAE2CEBFA83E8D1E
+:10E9C00037A78DAFABD11FD3D6F50B8C7F1CF1775A
+:10E9D000083FCD7103A3EF57F2585B532BA0DEB570
+:10E9E000F5818125F264BB97EF4AD1BA4B1116D954
+:10E9F0007DFD647B463BF1C2EEF52E9AB07BFFDDD8
+:10EA0000F2F405A6AB1FE92AB34E19FD8841F0C305
+:10EA1000D0BEC4D1DF407D7C3DF737D0AFF047E9B1
+:10EA2000BBF25368EF1605647E6E72EB0319A43BCC
+:10EA30004CE397A4FFFC21B25FD61F9BE83C745FB8
+:10EA4000C49EEC203F4F0958353FCF84E39DA77308
+:10EA50007A7D2CB310FDAE5F97B6ED423FAED7CEB8
+:10EA6000EDCEC5C0256177C0AFF34CC0BD2136885F
+:10EA700079DC753756EE6AACA4E9F4E37ADB6BF91E
+:10EA80007D73964B7F99FE7274C2AEE45C3CCFBF3F
+:10EA90001BEBCF4BE139CD9D8DEBD30FA13FDA9628
+:10EAA0002FE3B8AC96D345C1B32830E59C4B5CAF9F
+:10EAB0004A0D0E6A3F795D4715BC0F8ABD503086FE
+:10EAC0007E93F67E9CF1F8271F3765A03E7F8D353B
+:10EAD000B9BD62F2FBCC3A9AC6F75D67AE1BA37B69
+:10EAE000ACC4FB31998F3F9D9FB40AF54B119E0337
+:10EAF0004DD1BE80AF54D0DFFF40A61AFEBBA2FCB2
+:10EB00002E3A676DF41B9BB475147EE38AF2E5B967
+:10EB1000DEE884DFA8AD638E6783E33699AF33FA0E
+:10EB20008FC67E6E31F89F8D9EE53B3DBE29FA294A
+:10EB3000DAD074A57E5618F0595EB4FC15CF54F89F
+:10EB4000E46EE8895DA19F46433F0DB9CB73A7EC06
+:10EB5000C7BD61E44AFD2C37CC6B997B79F394F304
+:10EB6000326D705CA99F06033E8A69F94E692A7C62
+:10EB70006C1B9AAED4CF32033EF5B6E5AF4853E1F5
+:10EB8000F3FBF53DD9FEBE51BFE45CDC98FEB26FED
+:10EB900042BF18FD07E0739203BC976C2A3E37EA28
+:10EBA00013D267D8DF1DFC5CD0D5FAF7AB0292CE4A
+:10EBB000CF37E269BFB445CDC613F460FABA29F481
+:10EBC000A086B7D312674857B6CC913AFE47F83DB6
+:10EBD000CC2A99E83CB8594EA11E9B8CB787E4CC4F
+:10EBE000D3C8FD7C4DEEE696EA4B37EAC429F21B0A
+:10EBF000279C3C2FA5DD73A83D1F2BE5FB97FF51FC
+:10EC0000CAE9226DE5F71EBE8FFD11CCEF43FC086B
+:10EC1000E53AEB9CCC40FD35018CA7779B5C9437A3
+:10EC2000C57E893F9AF87775BBF11E45E8A700EFCE
+:10EC300051CCDAC7DF9DCBFD93BD86BC597119C796
+:10EC4000A3B88CE3710DFA0355F8DDE9DC00DE971B
+:10EC5000B6372007BCAE89FA82ADAFE9FA2D10F3C2
+:10EC600002854EE7929834C6305E2F28D3E35DD0FC
+:10EC7000F4315D96B177294B23DFEED9C592981F09
+:10EC8000D86B8B3460BCBFD7638EA09F3BABF1E5E4
+:10EC900037D1DECE1A0ADFC5A814E778FBF5E736D0
+:10ECA000F63617D3B9764F1D53701F9F457DA66C5E
+:10ECB000FADBCB7275E781B4FCD2F0BB3934FE00CD
+:10ECC0008C8F7667E05701CA63ED8179E2F77B7B31
+:10ECD000978EF9E99ED8BA5B464CFC3C19DD173299
+:10ECE000ABEEEAF0D2C619CFBF1630DDF7A0BD8972
+:10ECF00081C07B36CCE70E51B92791A432993849AF
+:10ED0000E591442AF05E567ED798B735E665BD8614
+:10ED1000732215AABEFDAC1EC3F917435E581BE74C
+:10ED200048E23981579AC64F264608EE4D6408DE00
+:10ED300093789360ADBDB15F235E463C8CF330E2C7
+:10ED4000ADD16DBAFCA09B49BD2113DABBCC40A864
+:10ED5000826E9F2079F3A0FD03FAD678E26BCAE8B1
+:10ED6000BCC618C14E363AF250059D0BCDD0F9669F
+:10ED7000712FF3E14BFFE4A0EF83A3A715FCBE596D
+:10ED8000BB8776B8F32C7DA7BCABD3EB443E8DBCE0
+:10ED9000B84D875FD891A17DEA79CF6FD3CDE3706D
+:10EDA000B481EE0FF232FE9CF0C57302AA97F8C64A
+:10EDB0005965A4BFB82FF5A28FCEAD6AF336991668
+:10EDC00009FFCCC62E835385671FF0FDDF9B956F2F
+:10EDD0009441FD7191FF7F52944F1BCE2169FB033B
+:10EDE0004951FE8D78BE4794E191B50588FF1386A1
+:10EDF000FD05D6C3F3B2D70C9A75F70ACD3BE6D41E
+:10EE0000DD9BB4E019AF0ECE0B97EAE0FC68480733
+:10EE100087DFE1E34DB79E15AA59D7BEEA7B4EDDE9
+:10EE2000F8DE46FD78DA7D23E143A5BA76525D48E7
+:10EE3000074F37DEC052D6B408D6FB61B0A3E87FD7
+:10EE4000E6D5F2EFE5F36A41AEF18C6E955E8E7316
+:10EE5000843E07FA3F8EF4D7E8CC825C1FE456D696
+:10EE6000C8E8278FCB757E7213FF3E7D40DB5F9035
+:10EE7000575F61FEC3E18E0EFA3EAC8A9F6FEC0DC8
+:10EE80009FA5EF997F1835D3F725BBAAF8F9E11DA7
+:10EE9000F37EA4205FF67E3B49DF4D38D34FD27717
+:10EEA000134712C03939786E3FC9E2F3F13E490782
+:10EEB000C17956B983FCDB1E5681F9F03C47A48327
+:10EEC000EEBBEE0758C67B07D3BC3E256029C3E1E5
+:10EED0006778FB6442A27EE688F9CB6166AE77A1D3
+:10EEE000698E98310EFEEDC13F507EA88A6574B0E0
+:10EEF0008C53A77DCF3FEC4A039EEA9A65193C9F4D
+:10EF0000ABC9DD0F2F9598D15FD8057137DE3F670C
+:10EF1000943F8D2E467901FAFF229BFE5ABB1F8635
+:10EF2000F9F928FA837E3D55D2611C47839D0A87F3
+:10EF30007F2DEC1BE88737CB683F90EB07F77BE72B
+:10EF4000C8DF30CAB951BE8D72FDDB3226E26221C4
+:10EF5000C751B38276C0C9B64CF45341789F477D00
+:10EF6000F403218F6E718E2C25E6A18D7FFD3B2948
+:10EF70002ABF2F9E2F81B01CF96A9514FF00F12D36
+:10EF8000383FD680D35CF20EB3A09DAAF128BFC152
+:10EF9000E79117D7EAF09CF7FC5ABD5D601C1ED7BD
+:10EFA0004783C28EF598999AD56E7ECAC9D4AC7E35
+:10EFB0002A406FA93AB953AFA89787A3C0C7D075A5
+:10EFC0006F153FDFB32B7AA409D7F5E408E763E0B8
+:10EFD0008C9FE3B96267C6C2300E9C338D9F744A22
+:10EFE000F0DDAE4B73F388CF47A6A56B4110F0A9B7
+:10EFF00059C6FD88DAEBCC49FADEBF4AE1DF258548
+:10F0000043E437FFADA0FBB382AE7D61EE47F74529
+:10F01000197D077DDDF3FCDECA856133C1CF68DF72
+:10F020008B887B93686B6016DA97512A6FBE947851
+:10F03000C1ED433F8645F07BE1D5523C8478B80F63
+:10F0400087CEE0956A302E9D4786F5991544FE5887
+:10F050009A22FE88BC6847191AA767DE08FF4E7619
+:10F06000DEF3F03CDBFE89F5A981FF6EADC1F5E36F
+:10F07000F5DAFAD5E09641CD643DA5E945A84AE721
+:10F08000802AAF41BB5288F7D40ED179BE642249A1
+:10F09000656FE22495E1A46CE2F7D33313EA67E5E8
+:10F0A000CC810627FAFDE23B37F8AB473A16284CED
+:10F0B0007AAA62E27B2FA9891DC933E13DF3AA999F
+:10F0C000EE496DE2FAA252D4BBA3D25173059E77EA
+:10F0D0006766FC1E0CF40FEDC7C9A23ED423EA5D9F
+:10F0E0001049E3FB8DBCBE02EBA3E85F8B7A29A934
+:10F0F0000A7D45DF413B45FDAC7E5EEF6DE2FD3DA7
+:10F10000B1947F7FE68EF2EFCF9E58CABF3F0BF5DA
+:10F11000D05CC661FC3ECDEF9B8067F5034E59F590
+:10F12000C7031786DA65EA8FF75B0D02583171FF66
+:10F13000F813EB38DFA873C4F7FD972CBC5DB94218
+:10F140007C66C3DB8CE87C4B9CD6FB09FCDE89BE6D
+:10F150002BD9F0A5F415F6B3B5F22E49B907F96825
+:10F1600087F7AFE8FCAF54C7227365BCDF25338651
+:10F17000F77BC1D874AF9B3BBDD364877A771DAB57
+:10F1800006CF96CE9352FC3564A77B5D021BC7D891
+:10F19000BAACF10AA2630A9ED362D67869B61D3A68
+:10F1A00021F6099E7828C3F0DE5D77FA2D1602BCA1
+:10F1B0000F06F93E753EDE7B41EFF1F3E99D1E3F00
+:10F1C000DDCBB1E3F18FE9FBBD026B5A41B96311AD
+:10F1D000568DEB53E018E0F06C01BBDA381C049854
+:10F1E000E17AC639ECE7F53B1EFF2A7DFF58E06364
+:10F1F000D5384FC403FD31C403ED9A3B9AA1EF010A
+:10F2000081CF1AE8BD24E73318A701DF63C7B8DD53
+:10F210002A70315EAF0A589238DCC9DB3BA349DC67
+:10F22000B366E3DF4B1CE2F79ABA07EDEF62F96EC3
+:10F2300069FC319453776DD77FD2F368DC4CDF9D46
+:10F240004BCA417CFE84ADAD14F7B535797902BF68
+:10F250002FC2F33C6990972897175C871D8FDBC7F7
+:10F26000E565EE17585E4EA0BC544CC8CB09E4FFD0
+:10F270008A0979D1604D5E345893170D1EE7A3A516
+:10F28000F15257561C79621DBF6F995DDA50BA264C
+:10F29000EBBCF58903DF2C45FA9DF844DBE7AE793A
+:10F2A000F84A72519904BD95A5176795C55FC3F5D6
+:10F2B000A850418FE9FCCF93BA76C008E44F3D31A6
+:10F2C000C4F7E34F0C850AAE749E04FC67BAFFEEE8
+:10F2D0006FC06FC20B899E4C48044FD77EDEF64C40
+:10F2E0001BFF2E36F936CAE5C3957208E5DF997E15
+:10F2F00085517C5127D7203FFC21C8E3E41D4F3EB8
+:10F300004BF29267E5F1719E83DFCBCDEAB81CE446
+:10F31000B9DAD2B8DF300E4B71DA17D7603C8FA460
+:10F3200093E730C8338E6F1DF567CBF3C3429EE77A
+:10F330007933F1ECEFE4343C66979B443CAAC90175
+:10F34000FFFD8F9565F13F10FF0B797047F9EFDDF9
+:10F35000CC8F8C9A713E8B5F67329E25BE36983E6D
+:10F360008378465F0518F0AAF4C916D42B35234CD0
+:10F37000CD83D876F19B9CBF1EAEE4FCB5E875CE7C
+:10F380005F0F57727E017126FED2E085AF72FED20A
+:10F3900060E887F84B83C7E75539EACFE6AF1DD75A
+:10F3A0005F7813FDC9BC309351CE343F58F37FF3DF
+:10F3B000ACF1ED44DF3735BF37C6E1D705EC523845
+:10F3C0009CD1FCDE08875FE5F50F7F328B60F51579
+:10F3D0005E7FC2D546F7489F38E435A959785D531A
+:10F3E000CEFDC927146BD354FB26FF18E4E7D1EFF9
+:10F3F0002953AE2D87F293B218D1F9894367E97783
+:10F400006B34FABB6B39DD8F95C52FF375D0F410D3
+:10F410005F87637B6E09E13790C797DA537988EF8E
+:10F42000E009057FF704FEF8FDE1027654587530D7
+:10F43000680B1DECDFC0EF1B3FB67765CD2BA8A78F
+:10F440006E72527F8FDCBAF8DD4E8497F0FE1FF9A2
+:10F45000D20DFFF922EAA5C5BCBEA7C2CEF5D4CF16
+:10F460006D49D46373D9681AF58933CCF5E45C6BC4
+:10F470009B19F5237E7F8EE7BEE6AAFCFEE4FC70B6
+:10F48000FC8C99FBFDC42FB05E435559727A7339D9
+:10F49000A7CF5C2697A05FA5F5339759E97DE6E2F3
+:10F4A000F7F543BF03B3B3F20D4DE5217E6EB36AAA
+:10F4B0008CBE5B463E10FD0F544DE1AF0E579D1EB6
+:10F4C000C178AAB7C7CCEF87AAE2767CD7AB8CEC21
+:10F4D0007BD811D91E46BF155EC07B757685F7AE09
+:10F4E0009C07F51F3D47BB006CF89868DFC8F344E4
+:10F4F000BB8E9DA5EF3A7785F9776735F8DD69E131
+:10F50000845CD15DAA8077053CC7EF63BEFFDC5900
+:10F51000FA1DA08593FDD7BBCBB3E2192DAE3FA258
+:10F52000C5E9E1B6865CC0D73B249B9D32C5017F0F
+:10F5300089EDC387C6C86D8F24C73AACF07CE173F0
+:10F54000E01FE74FD9FFFD57EA1FFCD607B1DE3BAE
+:10F5500034DA81F45BF09C6C1671C55FE1F38A11BB
+:10F560006E272B46520AE6BB8C71066D865C8FF5C2
+:10F570003D31963F39EEA8181950303F3629FE101C
+:10F580007E6AC5C8A882EF55809F8A74FAE542EE6C
+:10F59000CFDAF0DB61D0C3D689B8BB3F7B1ED3E99D
+:10F5A000E5F1B85B5A43EFC138F41DA314F4D560FC
+:10F5B000BC616CCFF0F651C0636F993284FDEF2DC2
+:10F5C0008B1F2C0778B77BA897DC692BFF8E78B749
+:10F5D00089F7A3CE3793DDB5805F749AC689D23898
+:10F5E000100FD0F72EBDE1FBA4F555D9FDB753FFA1
+:10F5F0005F29578E61BF74D908E68CEB52C4277916
+:10F60000C7C43D3993FC7875CA38CBD913D9391B97
+:10F61000D6C92EF8CBDB7C2C17D7ABA73C7EBA3CE7
+:10F620002BBFD93BEF4794C7D4EEBBC899CFCF418E
+:10F6300032DCA4C3F159E4155C3ACB2D3EBAEF6835
+:10F64000C683AF37CFC53CA8329BEE89287FE0FC4C
+:10F650004E8477D771589B473ECB2822BF96467A77
+:10F66000F56D3A92467972979F1F79085AD5977728
+:10F6700076F0B84BDCDF11DC9249609CD509DC8563
+:10F68000EB6E4D111D2D67F9BDE51859A98BE9DC0D
+:10F6900033FFAB4BA6F15E67BC9F1AE530AFF308B2
+:10F6A000ED43DCFF7D9B8C790123FF395BF87923E7
+:10F6B00023DF39B79E5B3B15DF39379D7B88FF7EA3
+:10F6C00008E75B2DEF66DDA6FD6E115F8FC9793A05
+:10F6D000BE1E2E874A7E3780E45F69F747BB9BC614
+:10F6E0001494C30BE5FCBBD8D24DAC1387C86B6236
+:10F6F00087C5F9E20BB83E05F1B438DFC1D7DF8327
+:10F70000E728CD78AF88B51E7FE704C207BE1FC3C8
+:10F7100052698C9BBD00231D9E2A8F7F80EF87E25C
+:10F7200063F5384E79D5287DEF68D1EEA573AD111C
+:10F73000EB0A732916BF7784DD6D33913FE9AD93F2
+:10F74000AA39BD15DAFFCE8B00CC26F8BFCDA55C5B
+:10F750002CA77399BEAB3A9799DF32A6E0795F4D3B
+:10F760003E8F57C57F46F69301FEB52447D61994C0
+:10F770007F6DE379DAEB3BE9BE7B0D5FC08BE2097D
+:10F780006F4412BFB396A27D02E70C6E0F001F27D5
+:10F79000BEAFE5C576D7727ECAFDE477C43F4FD6CB
+:10F7A000995907CD678CEEA5D4F209CE633C4F6022
+:10F7B000C4BB50E8E77118DAB6C15215823F8671B2
+:10F7C000F2EE9B6EA07BC08CF98549FD44F7AE46F6
+:10F7D000BEFABD392E237E85EFFCE0AB982F2CAC12
+:10F7E0003D4FFCA6E9552DEF3A307896F237726717
+:10F7F000AC03BBFD8EA8F730B6A712F7670E7D28C5
+:10F80000CD63A487E7CD28C27B37FF29D600F30A52
+:10F810000DCA74DE1DF4F0B538CEA7E5778C7AC535
+:10F82000C8F7D3EB199E9F2C1479823C13BFD71BCA
+:10F83000C49DEB39C1DFA59B3214B749C04798C7B7
+:10F840005921D6291F7F070AFAF9A43CDE80F80760
+:10F85000D408F1A5B3369526BD7195FCC4D8A88A05
+:10F86000BF7B24897DF9FCA879B8C147E719481EF8
+:10F870006435A3607D087F57892C72268DF67C261F
+:10F88000CA4784E463358E3FA356A6F1216EA4389F
+:10F89000CD281F93E501347C94E4E170F67D9859FE
+:10F8A00072F127333E835C78965BF7605C3A20F018
+:10F8B000DCD3F8610FD2ADC0E410788F1E4039C997
+:10F8C000670EBA8FDF631DAB475DAEC99197BD4E22
+:10F8D000FA35E0C8DCB602D7A18ADB1BE7E651D2D5
+:10F8E000AF8F6FF17A904F67BAB87FA58D7FEF0C1D
+:10F8F000EED7DF27D685F9E400EA33B747D987FC8E
+:10F9000033E9FECCF0878EEC78A8377FE01E1ECF5F
+:10F9100044E83E05CDAE7D5BF437DD7C8D79EB5D53
+:10F92000E1B3748F8296AF9E8E5EDA3D1DE3E33FB6
+:10F93000686FC57DBBDD75FADFF7D83383FBD72B46
+:10F94000CB947E5A07C1E7167B92CE3968FADB88E2
+:10F95000D76EABDAF4BFD17E55B1A40A78E5D5896C
+:10F96000FBE20CFC8FFE11F6EB74A419E513367262
+:10F97000BDAED9D7D2386B477E4F8EEBA57812DB60
+:10F980002B3D87E9DE786F1DCFFFE5B134E505F348
+:10F99000AD4915DF55D8A882FABC5CE8EFFC5ACE19
+:10F9A000BF1EC117F119F127493F2A9C8FCB14CEF6
+:10F9B0001FEEE828CBD693CC3F8D5E5761FCABD2CF
+:10F9C000EB627F5DD83BB04BC3962C3CA4BA8166FA
+:10F9D000FA3D45C6ED0E78BC3D58EF453994C8DE7A
+:10F9E000139D0B963F437A4CE3D3720C6E913FF11B
+:10F9F000BE02CCAB59813FA13CE0624DBA736F337C
+:10FA000078DCF992C69712F0A59BF8F2BD1953F86D
+:10FA100073BD611E1765F973C4978A7A6A583F5F90
+:10FA2000BECFADC9ED6B1376E3356E37F83DC37DC0
+:10FA300050221F861D497E9E28DC70C5DFF798C4C2
+:10FA400097DF70125F3E0E2107FD2E8033B90EFD49
+:10FA5000CB51C19717C4FC2E087817F21DC9833803
+:10FA60007F169D5AEF02DFBD3C43B76FC0D49C7C2C
+:10FA70008C0FE3FF41FCB8C54ABF13E10C67881F38
+:10FA800034BEFF34FDE36C6426E4574D6FFBE31195
+:10FA900053B69C3BC57D9C9A3E477AA29ECEABE274
+:10FAA000F4CC8F4AE4AF5866F2F93C3323FE5F880A
+:10FAB0004F614B8661DE4AE3D3F268B2DDFA47E874
+:10FAC000F771BE8A86DAB3F5BB513E40BFAB213138
+:10FAD0001EB60779C99F09F804940C8D9B1F4DA68B
+:10FAE000D10F9AA4DFD5EA61EB67D3EF25333F83CB
+:10FAF0007ED7F83F2DC566E27B20E7B47EB09EF24C
+:10FB0000CC2C3D3BDD7AF5DA2332D7B3EA947AD5B3
+:10FB1000CD32EDF89300057599744394F6D1E8BEA3
+:10FB2000406D3D8333630B705C77543267DB374540
+:10FB30009D64D7989235EF45623D61BE8BE8FD30FC
+:10FB4000E737B7EAD4F20E3720FEEE2D2AFDDE9815
+:10FB50009677B85ABA38A391611E270C9851BE35D2
+:10FB60007CB576C199F11538AEB372B003D7FDA854
+:10FB700058E78A63F2DBC718CE2349FB9D6C9F9937
+:10FB8000DF7B0B7157F6FD01F70AFC214EBB15FB1D
+:10FB900031B657B64D5A77DDFC6F9F98FFEDF87E72
+:10FBA000EE2739A4BF0E87F9B91367278F9FA7D80F
+:10FBB0005FFA13A4CB77853F77607CFF6EE00CDAA9
+:10FBC000BBB91BE31DE8073F259E2BF822CA511540
+:10FBD0003FAFE5D97544DBBFFB3AD177CE470AC6C4
+:10FBE0003AD70DB1175085827F77F7CCABF0EFACE9
+:10FBF000DBA6F1EB3AA7B66BC38321CA4B1E6E623C
+:10FC0000749FFD8E9DC52B2BA398573233CCB37BAD
+:10FC1000D33BC96E7B3BCD49CC551CEFE4BF3F3590
+:10FC2000DD7A3F8CF9D11CFE7B889817755B4755B0
+:10FC3000BA07AA96E7F5DD8E31D59A95AF74BB5811
+:10FC40003BC18AA897240E37F2FA5ECCAF66FDCE90
+:10FC5000ACB3294574732ADE34DE0356506BD6FDEF
+:10FC60009E555E3FFF7D4E2D6FE0412A66D1272FC6
+:10FC7000ECD5C136C17F3B5CF78D28884F555AC5FE
+:10FC8000FC65428E0F21BDEDE6E430CA192BE5F983
+:10FC9000726923B7E3DAEF442EB7D415E0EF5CE0E6
+:10FCA0006F13A1DDC59FFD41613C3993FB596E592E
+:10FCB000A6F9E42A2C9284E7B9B3D3C44FA5C0D3E4
+:10FCC000F8D323DB815E8D361C2F760CC773450677
+:10FCD00074BF4369A4EFD33335BF8DD39F59E3F28B
+:10FCE00054BF2BACC9DB062996423E5E6E69A1DF8C
+:10FCF00021F87F5BF87E5D37D3DB5FAD9C5556FF07
+:10FD0000CC4CB237B1919BA17D5735A3EF44765CC3
+:10FD10005AE6407BD6E5B68B73EC374AC3D6E9E5A5
+:10FD20005D2B87607E2DFCBC09953B5CEA9DF83D10
+:10FD30004754666A6310F0B0B63521FC8BEF96C568
+:10FD40007CB00EDDB836A530845C3A80E79D772024
+:10FD5000ACFD6E0AFC7F289789FD80D2D8D5BC0FF8
+:10FD6000F681F232A72CF1D7900EE571FE3B94E5B7
+:10FD70005B2236D45B67C77F2738437A6468FDDB34
+:10FD800001CC9F4765BD3FFBD752FCAD995970F937
+:10FD90009601D27BBBA21F529CBF93154868276770
+:10FDA0008ADF97D3FCEE99228F5F2673FB1F16E53F
+:10FDB0001F66F232B0712C80EFE38F61E2FBDF153A
+:10FDC000F868F7717A1BB9DDC51BF2D18F943672D2
+:10FDD000BDF591E003F0D34C785F6CA1B82F16E22B
+:10FDE000AB0F70FDF29A92946700BF51F7BBE61A11
+:10FDF0003DCA6733CA27DF27C5A332D185EB776DAC
+:10FE00005E124B99D03F05BBFE01E9E3301FA740CE
+:10FE1000B3EBCA681AF3801FCC6484873FCE681E98
+:10FE200065380F8C6B6C1C7FEDBE71235FFC7F34DB
+:10FE3000ED1E2C00800000001F8B08000000000059
+:10FE4000000BED7D0B7854D5B9E8DAB367269364DF
+:10FE5000924CC2E409849D770249D8092180E5B11A
+:10FE60004388C642754878040C748000510367F0DB
+:10FE70005A0F5A2C130218A96254C4F414E80451FE
+:10FE8000B9AD8F80E9F9B0B5DE8060F5D4B69104E4
+:10FE9000C54A353E78D4524F8E2D2DEDE5D4FBFF6B
+:10FEA000FF5A3BB3F76442B0B5E7FBEEBD27FDEA6E
+:10FEB00066EDF5FAD7FFFEFFB5F69AEFAEFF4BAA57
+:10FEC000B790B1FB19ABEE7432F639FECD622C5609
+:10FED000B13096C858143E27C353ED640CFE19DDAB
+:10FEE00014F5811CCB58EE386F9402F5D18503CC04
+:10FEF0000BFD18EB649E18C6668DF33815681F332A
+:10FF00006FA0DB0E6F3F1DE7A2FEF75BDB1C2E2709
+:10FF1000F6F3B8141A8FD7C3FB6AD530AFFEFC7462
+:10FF20001C9F376BB49648E3C1F84CC6F1BDA934A9
+:10FF3000EF26FB07727170FE5B476B9F8E9B8CFDFB
+:10FF400018C19DDA30906A2F632C8DC532D9CDD877
+:10FF5000F76CAC0ED717951F68B6433966AAAB0489
+:10FF6000861B9C2F5BAC736A3A8C93181C6720DD50
+:10FF70004BE5D846D7518B82FD7B18E26BA479A262
+:10FF80000B037E0B94E3ABCDF39408BC9E196B9EE0
+:10FF9000E7719C6732CED3E3C7799C6A80D6B5DD22
+:10FFA000E64D41BC6D8F016C5DC7D85D813337373D
+:10FFB0005B19BB3BC153467868E86176685F06FF12
+:10FFC00047F819EB913C458C1D92BD33116F63BD11
+:10FFD0000E3FE269EC9DAA0DC73B29E00BC577995E
+:10FFE000802B651CF375C2FAB2596B09C2FF70769B
+:10FFF000F9A81D1263EDD77FE690A1DF2D8A9DE65B
+:020000021000EC
+:10000000698F77DDB812EA774A31AEFDF07C68CEB1
+:1000100023A723000F9F6D6219F03F76FFBD6DA7E8
+:10002000E3A0EC9A9EAB6C81FEE3BA236112786A7E
+:10003000AE8E48A8675760DE7228431DD275C7662A
+:1000400078E641FBEE3F1FC5715C9B944391B0A6DF
+:1000500087EE0578011E57216BB6E07B4D2D477C5E
+:10006000DEA12804870EBF6B133B1A017044E7AB77
+:10007000B988BF6C362612E9F290DFAEED80F7ED5D
+:10008000E9AED7B3A0DCF6BACCB640FF572AFE984B
+:10009000DAEFC4750CA4BE8AEBA8B0B3FDD0AFED07
+:1000A0005EF60E8E13B9C995B9252308576477E417
+:1000B0003BB89E482D49899482F0D3BFB30CEBDB4B
+:1000C000A4D0FADAEE6DD3107FFE1C76E8496832D0
+:1000D000AE7080E01FB789C3AFC33D2E7BA0C26264
+:1000E00080BB0CD79518AC8FCE07BAE433FAFB1C53
+:1000F000FE7F1FCA69E150FADD3ABAE21EA43773E7
+:10010000C360D386D6EB4F8088C6674C8B95921818
+:10011000928AFE2258BC251DBA5E4A91D90E10D98A
+:100120002A2436C01BBD910522A091A2B92DD95019
+:1001300006A6D4E2A6C27BD00673A07D7A8563C0F2
+:10014000AFE2082EEA3F5AF457B6DA59B7230877D8
+:100150006A23940DEB18CD1EF80FE4CB7466780F6C
+:10016000F38C3EF39B33204A506F7ECFE4FA38E4A1
+:10017000DF9DF822CCFA369E5911386E986FAF1277
+:10018000E33E3701FE31854DF95C0EF61F0E2F7FE1
+:10019000DAEC0D1CCF612C47D69E40B96253130098
+:1001A00068A07FC16EC51B06DF413C06A456C0CBCC
+:1001B0005850153B4A187B49D00FFE3C8E245C07F3
+:1001C000FF4B0399B596327634BE3CAEFF2A70C819
+:1001D0001B7F5C326794A1ECEC96707EC6E6B8CECD
+:1001E000013E24ED23F679F4D5E86B65E774BCC1D4
+:1001F000BA6D6EE68F8E437D82BCC1D8D6181628A4
+:10020000047C466633E628C372CFB3588E180314B5
+:100210003494ED29A00BDCC1328CC31443BD3EDF06
+:10022000D6182DC56958CFB6F8EB490FC80A53F256
+:10023000A09DA3FB7EA6805D70287EE685A76CED61
+:1002400066C8EF4C65192817B2A38D97B345D9E955
+:10025000E3E531500654CA2E2F2FA7F0FAADFF590F
+:100260004B657F222F87AEFF39A1C774FA54B97C42
+:100270005B918FAB60792D409FE47ACF56C443B534
+:100280008BB9E478A21FD79B576AE7E0FB9B6F64AA
+:10029000AE1DF1C1F20DF7000FC423785C9FB74D7E
+:1002A00065EA0EA86ED36AAECA4F0F83DEE8CE436E
+:1002B000FDE160DD1143EB1364D0B3D0FFE1B9EF92
+:1002C000B10F81BE31CE81941A285F512482E7E8B4
+:1002D0008CB752904F1E9FFBD7947EA87F70C6F6B6
+:1002E0001406E5D68C3F32E3BC208B5A200C1CDE72
+:1002F0000C89D69F7DF93E07DA8336C5521DAE1DA7
+:1003000063CD345F9B8345A29DF947AD2B59C0F364
+:10031000F7AEEB850C49C03BE0009BC01E9AFE6522
+:10032000C1BB93E07D7CEECE6EE497073372335110
+:10033000EF150BB8F5F64733B613DCAD93DF4A6122
+:1003400008FFE4EDCCA81F1C0877187D714687DBF9
+:10035000F55F03F7F562BEE1E17E8B85D36B31C3B8
+:10036000C06FCBE478684B19203FEE1F0DFFF22FD2
+:1003700019FE1D62BCF30AF747DB149DDF6161685B
+:10038000F7BCCC27970C2F2F09732C267B169D1FAB
+:10039000652A67667BE2B0DF70F8B880F888185984
+:1003A000BE7E27DAFD16F19687E3F6D8AF03BC5C74
+:1003B00042FB02A0376A167F44ECF0FD1B6DFE2461
+:1003C000D755C6BF35209BECF048F048199944F743
+:1003D000F55DB269BD4DCF449BCABABE7D68BA19FE
+:1003E0009F3A9E87D0FF4BC2E7487C38223EA70346
+:1003F0003E8BBF3C7C8E04CF79E1B78E84CF50BE5C
+:100400001C6EBCFF5FF9323943B926BE0CE5C77FCD
+:10041000341EFF6FE3C7E2FFC6E39782C7EB33AE3C
+:100420004DAE0FDA5923C66F797BEF3C7923E0B3E9
+:10043000B77AD224F095C16DD78A6A012FB766F2D8
+:10044000F83A4F629E7071FAADC20E9FACAE5C4737
+:10045000F4F04433195EF559D49F97C1FAFD35B2D3
+:100460001ACE2F3E29F0559D194FE3F779648A077C
+:100470002E55E704B0FF70EB62D5063C64E27FA323
+:10048000826518E2245366933FDE27079E9410AEE0
+:100490004931E1ECB24ED73E4FEDDF47578FFCA517
+:1004A000EA9991E0999279ADF6AF4DE45F34929379
+:1004B00083DFE27103444D36CC8BD59C89A03CCCC4
+:1004C000297C958AF919CF864C685F535D62CACB47
+:1004D00040F8A661FF8FEE2FD88F7917B6A096DA75
+:1004E000DF9D69F68706E923ECEE410BF015FAD99A
+:1004F000F57EDB0AC37A8E665A045CBEB108479764
+:100500005D9BF02C8C7FF2A608753FBC8DA89DF7F3
+:10051000ED18C06FDF927829C2C037BBC47CE5F507
+:10052000DC9FEA3AEDB5590C743D24F810FA2F0B14
+:1005300017CFB689FA455E89FC78E0EFB13531C155
+:10054000FA1F87D487F6EFC88CE57C2AF1FC4F6848
+:10055000FD1ED1BFAEEEEAFDD98251942F808033CB
+:100560003D9CDED1F1579CE97D12E9F1B6E4FBF543
+:1005700037508EF646A84F925CFA726B8A8278608A
+:10058000560FC59337CF551230DE8775C9482FBB3C
+:10059000AC7C86651D2E7DDE04A8B742FB291AF3CC
+:1005A0003543FD47362517F34561E6FF6166E2F006
+:1005B000F30FAEC3AA55E07C0DEB81BF4A86AE6B4C
+:1005C000302F21DAF7FEB9722EB6EF3A69716DC994
+:1005D00018BEBDAE9772DBCDFCF396E01FB7F0D727
+:1005E000019EB175063AF6644652FF2FCA575B5119
+:1005F00097C0337797CFA6C0B88B81EFF5F18D7C8C
+:1006000072AFC0E7EBA2BD5BF6478DC77CC0DB5C79
+:10061000CF1DDC7FCFD870FAE6A4D01FDFCACC375D
+:10062000C94D6D75C9097719F2DDC32A8A57D7C933
+:10063000EBC6A2FC2DC2F991CFEDFEDB90BE279751
+:1006400047C4EF97AE7D1D5DA73D368C630B1770D9
+:100650007EECB078AA12512F1E663310CE0F10D543
+:1006600086BC55419624F0EE6D895419FBCFCC7BA6
+:100670001E6E75901C539E37FD896F3DEC477C6C58
+:100680001D45F2BF70C17CCA5BE456F3BC45971DA3
+:10069000F404C0756A464C00F3ABCCA15520DFAC26
+:1006A000FD3C8EED5083FA68A5C5B71EF3ABBA1EAC
+:1006B0003A247BA5ACC9417D3444FF6CAD157CA6C2
+:1006C00010DF0D95972D34AECE2F07033571AB0C8F
+:1006D000FC725D96DD142FF76EE671E05B2171E030
+:1006E000E2D33CBEEFB2F37CCCAF6E74C56FE1F2E7
+:1006F000D47C17CAD7E7E3245CC775599CFF2E0545
+:10070000EEF857DC7FD0F101EB2AFEBEC16E2D98CA
+:1007100067D6EBFAFA17D6459BDF8BFEF9B2763B2C
+:10072000CECBE646284F825CB8AB17935C7F3E97F2
+:10073000B9B0FEA0DDB32506DEE72EF88F3B695E7B
+:1007400091275A1B21F06965941FCDFF766A6007D7
+:10075000B44B6CE9FF8607D6F307A7272EC1C08FDD
+:1007600093B3CC7A5BB7C3D80EED548D55B185B336
+:1007700057B5D57258B857C67A7D46FD112AC79924
+:10078000D98CDBF53D1104D712E6B761FBC54C9B54
+:10079000814F30A33694FF33822E7AFF33AC3B6611
+:1007A0000AEA9D6A99F4CE195F6DDC4A5847BDADDF
+:1007B00033A6149E370B7E7DF74E99E262DD9E8351
+:1007C0007D3E51CEEDF325B4CFF50199FCAEFA266E
+:1007D000F903A39D5EE633AF276F6FD93AC4DFFB01
+:1007E0006098909F0FDA393EFD35D1E44700BF3E57
+:1007F0005806EB783F9050B203E0E9B5F0B27F0DB8
+:10080000870FFFAC498C79F93FD9A27AF541DC0317
+:10081000599D954170AEDEE5DD0E9A09FC91AC2341
+:10082000FD880FFF44D598770F7D7A3799ED7BEEE1
+:10083000AE2813BCE5686748FF778F5D6E908B7FAD
+:10084000CD89E6766C811436EFF0C31C27D1BFF753
+:10085000AF7263387FEE67391CAF0B7785EFFFB35C
+:100860009C185EDF1EBE7E34CE8F76CEDA3916E956
+:10087000BAB02E7CBB8AEC58BEEFB4EEFC32CD8908
+:10088000FE22975FBD7E52368723319BCB5BEFFE06
+:10089000DBAE4F457CAF975C3980D7B5A37CC5C82C
+:1008A0003FB73495503E3A369BF3F519C5F3ED2C1E
+:1008B000E8B7A67DFEF622A05F728FC585FEACAEBE
+:1008C0001F42E178342BD49EE8F6AC2D12ED19FCD2
+:1008D000F3E3885202C51F978074E7FAD8BF3FCA76
+:1008E000857CD13B4FF8ADFE2293DFFABD10390B6A
+:1008F000A5E79A5D663DF03EFAAD6541BFF5FD4D59
+:1009000093881FDF9917ED92697F6A52D17C831D0E
+:10091000D2F9BDD7CEFDECDEB7B254FF55F869442D
+:100920003F769EFCA5C627BDF3B81F0BEB8859196F
+:10093000A6DF6B2817D7109FBCBFE9EAFEF0FB4289
+:100940006F9C15FA5CE723F4A3571AE8FD66083D8F
+:10095000EA1ACCF02EAA37CFABCB479FA7250AFDCA
+:100960000F90FF5CE467DDAF655B278DB0AFC5F32B
+:10097000D83A3C1AEA0FC0776D5F5629EA0F8C4BC4
+:10098000102F1F86C015BA9E5ECBC0CFA720DFEF09
+:10099000B3929EC9D9B5624B2A1BCA779F868C73C6
+:1009A000AD7CA7C7BFBA3E0FED3FC867F3FECE3898
+:1009B000E91FC45FC3E33F704DFCA5CBFD2DD64EB0
+:1009C000DBB442AE4F6EC5BC6E9683FAB76629F4AF
+:1009D000BC85717F0CCC43F9FC22D447514C427941
+:1009E000DD1713C80156EEABF966B1D1EF9B20F4C9
+:1009F000D72DBBE66F4B55900F026DE47FDD25339D
+:100A0000F4BF7E7DFAF0362C47BD69714958EF5925
+:100A100045E54BA71515F5557E368F8B172E58617A
+:100A200033AE33946F1786F0EDAE2C17F7B707E3AC
+:100A300002E6223D26D6097A91F4E8C2A687A7E10C
+:100A40003C6B761DB51500DC69D97CBDA3B315EAF6
+:100A50005F2FFC4FE680F582DE79176D20AEF76ED2
+:100A600089DB436BBFCDA88F96FBCE5785D3E34B75
+:100A7000051EAA841E3FA3787BB328FEF34838DE08
+:100A8000DA6F72F8162ED820E13A7BD12740B911DF
+:100A900078D7D7619FCBF7C16E8E509E42BD3F88FD
+:100AA000CFF51C9FEF9EAED99658363C3E6BB2C335
+:100AB000CBC748F8ECDBBF94E6F77F95B9724C7E64
+:100AC000EED800C62FBD591C5F067F57427ED7F96E
+:100AD000E1DD0DE797794D719A2B1ED79BA978E23E
+:100AE000908FD6E6F0FDC14F62CCE7207E25F4C0A2
+:100AF00070F9A9A5B7BD4E71C2AF6EFBD9D81585E7
+:100B0000C1F6C3C9C35291BF39784744E3FE30727E
+:100B1000F303811F988FE2844BED928A7A0AFF8C4F
+:100B20007E4D7FF4F2ED318AC14F1BCE6F5BC0E387
+:100B3000A1A0DF1688298579B78B797E857E5BA198
+:100B4000C96FDB56EE0EE3B73582DF66D01BA17EA0
+:100B5000DB29E6F9DA649C6F1E9FEF9D069E877A7B
+:100B60007FDE040BEAC5530B1E253DBB4FCCDB2BB0
+:100B7000F4F7A90566FBF058B6795F6D88DE3C6D29
+:100B8000F6BF86B333FBB2BF989D01BF7E2CEABD92
+:100B9000531DF5CBBE81FCDC11A5E62843E9737734
+:100BA0008E2CFCA028E23F5DEFE8FCD765577FD78D
+:100BB00005FD4FED1DAD6E21FD585981E31DBC3281
+:100BC0004E92019F076BA21BD14F3E28FAAFDD97D3
+:100BD000B71FF1A331885FA17C0BDA25E8F790F00D
+:100BE000FF747D116A0774BBF423A12FD6ECFA8041
+:100BF000E2E5E57ABC8C7F30EFF9BDA91DE8EFBFD7
+:100C00006B117AE3A99800C635189F19F1753C0459
+:100C10005FA17A3ED45EBD13C81CCCEFE56404E747
+:100C20005BDD9EC1F353A25C7F279433901FB89D78
+:100C30003CBB7122AD7730EF57F36D8ADBDF03BF2A
+:100C4000E96A7EF888762DF0E5E675113F57DDFFFD
+:100C5000CAB936BFE9AC383FC7AED4DE340DD77958
+:100C6000CF28A2EFD95D9C5F3F13787FCFDE5F6412
+:100C700084EFAC90E73382CE67037CDF11F475EC30
+:100C80007C831EFA8DD0E7EF0939786FA3590E3EA9
+:100C90000F91A735BBCCF02EF399E175E6F07DD02E
+:100CA000F736B644A1BEECD3F9660DF787FB3C9549
+:100CB0003193513F04324DF472E67C31795B2A69FD
+:100CC0006477D8BD8C3D09FA3C339FFBF3970269EA
+:100CD000AE1D06FFFDE7422F0FD1C7F95C1FA3BF72
+:100CE00060C49B0FEDA6018E5B1A43FC158B62C19D
+:100CF000F378FEB7649283DE9BBEB91CF972EDBE39
+:100D000008CA97430DC1E17D22CAB52323CCBC2A72
+:100D10009F77A935609AB754F0C3B0F38EE027FDF2
+:100D2000775C626E7FCB35CAD797159734E498E528
+:100D30006424FE5D27F47D687CD28B7E8A3BE8A725
+:100D4000DC1CE1FBB40BF9CAE92BC73CDB7D424E4E
+:100D500056EF9A4FFE64AFC5B32D06DB9FB4B83093
+:100D6000AEE89DB7AA05CB97766590BFA4C3D39B89
+:100D700065864FB73723D9C7530BF3B6A09ECE7FF6
+:100D80005B0E209F9C5AB8D8160E5F8B2E8F66DDA7
+:100D900086F3657ABE00E5ACD6A06F0E64F33CDE48
+:100DA0008110395B78399DFA0FFAB7BBB87F5BBF0A
+:100DB000E0E16992611D4D39DC5EADCB51CCFEADF9
+:100DC00095FBB7C3E5CBBE1B429F5382AE7ABE6C88
+:100DD000A1D513365FB668811CA277B8FF85EB32C8
+:100DE000CACBFFCCB198D6A38FAFEB996B1DBF2FA9
+:100DF0008BEB4F3D1F975908FD6386E7CFC17944C0
+:100E0000BBD0799E16781A6EBEBB859F3E5C1EE9EC
+:100E10005DC16FE5228FD47BD3577E8EF9B2BE9A27
+:100E200057A6237FBDBFE9F7A716BBD13E9F988E7B
+:100E3000FAFC5DCC2B4DA6FC9B3D05F58D57227F22
+:100E40006EF1AE15143F417B8A837BC14FC1FEEF2B
+:100E500008BA809E31D9AF50B95B8D7042BB7BF42C
+:100E6000B88875D2BED348F8F955087EBEA8BE5FD3
+:100E70002DE881FA11E978AB5E66DD94178338E2DC
+:100E8000EBC86F1B993697EC518FC582FAF59CE33E
+:100E9000A3A48F27011F47FE36E963E0EB9528C323
+:100EA000D3E07D4CF873D209051CCFE0C7E51E07DF
+:100EB000FCAC62B12A9E2FDE16EF5F83FA60A0239E
+:100EC000D285FB06193B9BA9BC2A10E1C2F3C06581
+:100ED000BD0F9463FB2889A932CC5FDE33FB07B8D2
+:100EE000AFB03A10ADE021DC7D797C9F31E181E645
+:100EF0007332F58B5424787F61863F1DE13E7C7010
+:100F0000652CEE071C6F5F158BFB6DDFC7A55D477A
+:100F1000CBF733E09373F8AF34FC4FC5A373A07ED7
+:100F20007C6297C50928D8925BF1A803C6D9D6EC94
+:100F30004971E139C6DCF8471D63194B4AD27A661C
+:100F4000A9E047E68EAAC57249963E9EBB561B0392
+:100F5000F8FA1751F6A73E8AE51F5BBC1912B4DFF9
+:100F60009D3BB5D69A0A622CCD29B1C078ED4F6D64
+:100F70007FD43103ECC213F797DF03F3BDF8547D40
+:100F8000AD3583F6CB44FF15B5955658E774BDBC17
+:100F90007A1496DDD11EC50271595A6E4CAD15E614
+:100FA000EF4AD0363028F7E6C6107C53BDDE576CCA
+:100FB000305EDA534DB5734164A7F6FBA5ABE9FF8C
+:100FC000D48D95EC23A0DF85D9BE4A2BF48B787A9B
+:100FD000FDA385918C4D79A0229A4139EEE96DB53A
+:100FE0001125B44F55A2C033FEE9569AA7BCDE3F87
+:100FF0009EC1BAECEC8147AB693F4DECE38E517278
+:10100000910F07CBF93C1F35584EE1E5375FBFAD77
+:1010100081F8C9C15C96AF4039DE5B28A19E4F8D37
+:1010200056296E777897BF01E53725D7861DD8CE2C
+:10103000EA7D0FDBBFF99DBC0CF47FE45CCED7C723
+:10104000BEB336FD0327BE4FA6F8B26B0BE7D7D071
+:10105000753E9BC7F5575754F8FABA5C2EA7FA7E2F
+:1010600065DC69A63D03CF13510377223F5A58CF61
+:10107000BDCDB8BFE350729701FCB3739DA6F3B228
+:1010800083FB9C0E2DE132C0B9B294FBF5837A2923
+:1010900097F37F96CAF54CA26C217F7FA0447A0219
+:1010A000F93E5196BE3E1FDE274531EF21AC1FC5EC
+:1010B000A83C0F44E6104C5595E53940E771935331
+:1010C0004B5A30552FCF4EB8CCFB77ECA7F82240C7
+:1010D000E307E1756D407813E59A920D8506FC17DC
+:1010E00072FA7425703C74FD85C71D5D2733F7E3E4
+:1010F0007E982DD7AC2FCA7B6AECB83F975809630E
+:10110000C2FC03F74706683E875735EAA5B5027F5C
+:101110004D972359C060279BACDD76D4474D979DF2
+:10112000F43EB1253CFEF53C64D3E578E69F647C53
+:10113000CFD7151CC74DF5000FC587C3C173F72066
+:101140003C052C30291C3C85F4FE1F054F0132065E
+:10115000E0F5CED4C280D15FD7C7DDC8781C7A67EE
+:101160008C969C7015F96CBA2C0D03BF95DE678CBC
+:1011700003954CFB01DD76561884AF60BA968C72ED
+:1011800076E7A18A64E634D0DF2AE82FF43AD2D792
+:10119000783EE16981B7D583FBF6FC5CC5CAB442F1
+:1011A0008A5BBBFE5239613E8DC7F733BBAC3C7ED8
+:1011B0002BB76AB45F5EDE93E0F24BE8D7799EA16D
+:1011C0007D42872BFEBE69413EEA4AF055109EBE25
+:1011D0002391BE0F5DEF73BA1C8A7D9BE47AAFBC8E
+:1011E000C2009F2E67C3C925630F72B8C4F71E4C97
+:1011F00055728DFBE23ADC91B9DCDE02FD39DD523D
+:101200009D9C8F047E86F2C1E811F8209DEACB7B7D
+:101210008ED13A9B049CC9A7BB63278875DC0ECF8F
+:10122000EFE4F1FDA4985C6EE7CB5EA88CFE8AC863
+:1012300007E2A8E583FAFE8DDED9D9D04F2F233FF0
+:1012400029846F61AFC0CD7104DB3FF0F41BB55B47
+:10125000B3113F5A09E11DFE72C29C374B14F84D81
+:10126000CB65C2CE87EA0DE6D3F169D4133ADEF539
+:1012700071FE24C6F9BDD06B41BD27D1FEE997A709
+:10128000E72AAE51CFCD177A8ED733B7A709EB93A4
+:101290002CE2BB04175FCFCAD76B7319B80C77A4C5
+:1012A000C80AFA2DAB25EF76F42356DAD5ED3106D0
+:1012B0007E5C030870829FB40166F81CDEAFEE8985
+:1012C000A27DFF55BB22E9BDEE3F7DD626119FDDF5
+:1012D00001336C2C1DCA1F77A4D8699E95F7E7C40B
+:1012E000798DF059413E30CF1A2DE07384D84DAB43
+:1012F000B9BC32D7BB42920DF54E6E479B32B584D6
+:101300003CA0C347923887D09A68DA1F5172CD71DA
+:10131000816EAF7E93A9A562BFD0F643F5A0B06FF2
+:101320003D35948F48DE04AFF07B904E46790FB682
+:1013300087E7F792EBBB2D4D06FE389857C4E54B77
+:10134000667E09F07276210037D190BF91387DFC1E
+:1013500091CC85F98D13F19E3217944F24C6A82D98
+:10136000A83F64FF711B3CA7E589FDD568CE8727A0
+:10137000227D7B705E2B5312884F857EFA653A3F43
+:10138000F7A5EBB5E0F72972F72C43FD0969FE18C4
+:101390003E4F72698B64E0A7C171990BC7BDE1AF85
+:1013A000BFBF380BBF03CAE4E3B961FE1A831C4C0C
+:1013B000A9E6E7306E10F0DD90C7F7B34F6478BA56
+:1013C000109E13F1CCD502EB7A15D82616CAAFE6DB
+:1013D0004A6A8B12D44FC8FF482FE04F2FF24F922A
+:1013E0009D97B7E57379FA493E1F5713E5A458DE78
+:1013F0002E943E8F897674D4029E8FCCCB9C8F71B5
+:1014000095CFC9ED789CA35B54F2EF4C7754C07A2A
+:10141000C28C539BC7F34860C768BD43ED8A6EB763
+:10142000FA5BB350BFE4F37DBED03820B4DF395B44
+:10143000DB31CA279DE2F9A49D2E4FDC68D477A743
+:10144000B2981FFADBA3F97793A1F0DC2BF06A17AF
+:10145000F1F256917F89BD1C4D71F44601AF35FF05
+:1014600063A2BF752AF03AFA2FCCE37719E86F73BD
+:10147000594CF14EECE558EADF747992C94F19AA3C
+:10148000CFCBA9BE2085C75597CE2C8E6361F012B5
+:101490000A77B780532F6BF9D639CC004F05736D9F
+:1014A000C5F12B58E8B99BE92EFAEE0E7C6F3C1F74
+:1014B0000A7A9DDB0F787638B99D457DA9C75928F2
+:1014C0004FAE38C6F2F22A1EC94B34D81DD14F9701
+:1014D000EBAEBFFCDE1FC3FDBB04CCB7C7097D1D4F
+:1014E00027EC9FAEDF43CF2DBD23F4862EFFBABF7E
+:1014F000124A6FBDFD39A17F0E1DAF49417A1C769E
+:10150000B8243CEFBC2DD293827AF992C81F5CCAF2
+:10151000E1F3563B2A3563FFBC3C85DEBFA6EB31C9
+:10152000E64947BB5D3EDD2B1721BF3D20310CF561
+:10153000A7CC317FDF7424CF49E31E11F2A7CBE79C
+:10154000AA107BF5521EF7D75FCA8BBE26BB37A801
+:101550007793B8DEEDF8CFCA009E871968B632FCE3
+:101560006E774AB516E82F437E8185421C54B164DC
+:101570008ED20C65DB1B363502E5FC4878BDEADC13
+:1015800028690DB0EE9FE5713A34B9399C4DEE6E85
+:101590007B368098D6C4D737A6F3A86435C03FA65B
+:1015A00091B7EBCBB351BFB43A2BE9DF349F760050
+:1015B000EDD769F1FEAD3C36F87D25CA19F463B864
+:1015C0003F96A6F2719D6A405A05E3AC177CD46A37
+:1015D000995F88FAB035299AF4EEB202EF7B790868
+:1015E000D799EE6E44C394333D568C1F371568EF80
+:1015F000E37B7D5D8AEC4A433D137D86C3D59660CF
+:10160000F6A319FBB6C0F37E0E8FD35382F026C526
+:101610002A167EFE9265227D9312841E4C62DEC3E2
+:1016200048778787FC97A4286867FCCE9079CA30F2
+:101630004F17482C2A453D9EF500F713E6B90B4A93
+:10164000312FFDA33DE1BFD3BB22F408C0FF272308
+:10165000FC23D93BBD9D6D987851D787D1C20E54DC
+:101660002C712F45B89BB6FE6B74044C99D6D921CA
+:101670004593DEDCC9F3B402DF0087231FE9D759A5
+:1016800041FC93E6B7328C7BAD51E901FC7ED79AE1
+:10169000303599EE051806CEA68DB2D6608C07B609
+:1016A000DA09FF1D21E786743F37239FEBC9C30585
+:1016B0009E947C78AE3FF2B09DBEFB3FF0813DDC56
+:1016C000F9CFC1FED78827A991DBF1261773619E58
+:1016D000A0624903D9D1DB21AE8F88C77CB444FA1C
+:1016E00099D53902980A6BEA3CF46A1A944737692B
+:1016F00093313F96043CD05318D4A7694DC0571678
+:10170000C4CFA16E8C37D336313A95A9E30FB46BB1
+:10171000FA71E46BF0EC317F74D1E66DC2F92EA65C
+:1017200046AB7E90839F1E7A5BF926BCDF0AF5727A
+:101730000AF2F7FE14FC5EB775BC5D457F725381FB
+:10174000F72B8887042BD869781FEF8E519B616C2B
+:10175000258295BAAE82F7D075EBF65F7F3F6513B1
+:10176000978375F9E2FC34F366E0BA15996DA273BC
+:1017700003F9FC3CDAAB36E67724601E88AFE72736
+:10178000F9DA57911F180A612AAE2B70D49E317472
+:101790005E03FF78F213BF089C9D7605E0BA5DE812
+:1017A0008F8A2507A48F0C74FF7A3EDFAF4D7BA68E
+:1017B0004352888F0F3457B9A93D433D96F60CF735
+:1017C000E36F87FAD526BDB1A21ED7D71AC5FD1C77
+:1017D000D01B6B701D272C1B5E417B73A294A92D1F
+:1017E0000CF548CF7152A702DE1376EF1EB2D7C0B8
+:1017F0001FCD50BE239FEBFD57ED5ECA07BD9AC6B5
+:10180000BF376EB56CC9F73983721D2A877708BE5A
+:101810004EAB3B2059C81FEBA175AEABB3125D8E2A
+:101820002D5EDE80F3AC73A796E07791D7F96FBC9D
+:101830001BF5E1DCAE7809F71737E7737BB4AE4DE3
+:10184000E2FBC16D6FDA171AECDFEE1FBE69578A33
+:10185000B03D3F97BCAEEB9015CFEB667C728CF839
+:101860006F1DF0576419D283C37FD1D69D8EFC13B0
+:1018700073F89FC720FF319785F82FBA9AEB33CCC6
+:1018800035E6C4737B4FFA6D4B2EE50574BDF91335
+:10189000B11ED093A4E792928A4A308E7A44C0A9AE
+:1018A000CF5315A51E437EAE2A9508BF199F9C24D1
+:1018B000381FCBD7F3C65CCF2AB1FC9CBB3EFE5091
+:1018C0007D3F81FCDF97847F09F4DB8B7C15AAF7D1
+:1018D000F5F133F6D5D0F7E883F4403C1BF8E899EE
+:1018E0007CFEFDCD33F9560187A6209E140BC82936
+:1018F000FAD5764F217E076F4D12721A7F5A6936DC
+:10190000C9E94AD223AD69DC0E019F3F8BFC746CA0
+:10191000F173723BEA974229807A75D70BF3099FDE
+:101920004D4833D42FDE06A2334B813802ED8A971F
+:10193000DBC5A6BA4514870EDAABC312E1BDC9EF09
+:101940000CE0DD13733BE7F3FCA33B52157A89E807
+:101950001BBC9FC09B81F1952EE73AFE747C7C9660
+:10196000C7E5FC97F9DACBE87FE9F1A4B37E80E222
+:10197000F450798C13F1A40FE349CCF3AA8EABC6D3
+:1019800091BADD1BE4771147DEBEF167E477DD969F
+:10199000F23A3D312E417F5E8F5306FD3741D763CA
+:1019A000E2D98F7206CFDBCB3A49CFDEFEB18FE4AE
+:1019B000C559CDF582F38C599FE9710A385E848F41
+:1019C000DBCB785CB316F4A514266FA33FD7E2FEF9
+:1019D000118C37EBCA2F638DFEE4BF0B3E3E7F10A8
+:1019E000FC5ED2F73EF257871FC7F70B3C0FC00EC5
+:1019F000F1F332FA7863BBE74C3B0B74FBEDC13873
+:101A0000BA4FE0E233B57763D97F208ECEA38CED59
+:101A10005E40FC70D13D4D45FABB5B387E2E76565C
+:101A200012DF7C92AC58D02F6DEE7C74E687C8C76D
+:101A3000051CAE4F5E9037E2FA3F79E1959D7F71CC
+:101A4000E37989922424F996A7FF971DBF9FB604D6
+:101A50001EFE2BDAADC603712EFC9EA1E507DF9BAF
+:101A600089E5DB0FC4919E6CE97C82D71FE4F59F6A
+:101A70003CD13113F17CECE9E7E5F6B220FF7EF2D0
+:101A800042C7CB7FC1B22756453E69F2EEFA1696A1
+:101A9000D982585A27F31EB72F34E49F761F3A4A4B
+:101AA000FCA6F3C3DC4ECEC7ACCE4E71B7CEB76743
+:101AB0005F8F6212C40367E3F9773FAB640BAD7BC2
+:101AC000952CD1F3BCD8E79A20F6618AC4BA2F6C62
+:101AD00056D33EB6A17FEFF9451DCF1BF53C598685
+:101AE000EF2BE83DBB3289BE7BB9B08B9F83C2EF41
+:101AF00060705FB0F131D983E5DFEC92F9399F076F
+:101B0000223A708A5B1F93FD24570FF232389CE90A
+:101B1000C67DC48F7E1D5917CE4FD3E11BF4BBED9C
+:101B2000DE4EFC5E6095C5C2E3932BB5BF980AF00C
+:101B30009DB52887D1EEEBFD2A0BB87F175C078F88
+:101B40005374F8F57641F83DC561E1DF156D86FF08
+:101B5000B168013F6FAF8F73F6BDC8C670F0EB7808
+:101B6000B5221ECB30AFC47A50EF9DDD65E3E7525E
+:101B70001A789EE291EA390750EFAF7A80D3314E5E
+:101B8000D50EE0BEF3D70A6CB40E9F53DF7FE3F1AE
+:101B90007ACBAEDA5FA07FF8D903910ADAB15509A2
+:101BA000EA39826F27FFFEE29507A7A41BBF233BFC
+:101BB000BB9969B61C03BEBF5392CB609C8F1E2B92
+:101BC000C9B5C1F34F47A7A5A31E5FB533E2EBDA52
+:101BD00055D6715EC46935B30BC7A21EF7CBA0A75B
+:101BE000673276F2464EBFF5E2BB83F54BE33B30FE
+:101BF000DF6B71B89806702EA88EEFC0F5DC5DC063
+:101C0000ED19E684709F94CD93C8FF6BB5FB0F92DE
+:101C1000FD7775A6A3FD8F2EECB68F86F2E2FA4310
+:101C20003331BD5504FA17EF6181DE073E073FB738
+:101C3000B66DED326CBF47662E3915DB3553FF7438
+:101C4000877E0F89D5754EDFEF95AFE60F99EF7759
+:101C500031DC43C3CFCFDAB95F06FE0C8B8467F962
+:101C60009D22CF2CADA4F30627BED13D1DEDED8FF7
+:101C70002EDC11D55468D48FBC7F5A17F793D675D4
+:101C800075D03D595FCD2FA1FB8AD689FD35B79020
+:101C9000C3F57EA7C96E3E22F837C9E5A17B531C68
+:101CA0009A27F13EB457111E2BD9F1AF7B6CCDF4BE
+:101CB0007DCF40FA4272A49E34D985DD366FEA6446
+:101CC0009CB755F83F0738DCD09FC6532A3537F606
+:101CD00087F1693C47BD66C5F1090150FEF79F2CAD
+:101CE0003E60DCA70AB53B387E9913FD187F1DF1D5
+:101CF0009D625751EF7C824D691C7FB131EF1E9A76
+:101D0000CF423B8AF273B8A0E2D982C4E053CF7FBE
+:101D100085D2E9DFB11EC6C91FAFD1931D1C754D19
+:101D2000F732E97EC2FA6AE127FCF803B273EBBD31
+:101D300056EEDF793F26FFEEB79B35F611F0F6EE53
+:101D4000173F20BD5A7384D36DB7D4BF1DFD43FF29
+:101D50008DD2A4270DF67BFDEC8BE946FEBFBDFAC4
+:101D600083358887CC23A92EB483EB67F6E7A27E60
+:101D7000FAF4452E17272C16C2EB89FD133AD08FA3
+:101D8000911AB9BFB7DEA7EC8FA07C238F1B214E21
+:101D90007AB80AFDC84646F982F55D1D64275821C8
+:101DA00097938C7D1F6E47B98887E806EFF33AB6A4
+:101DB000F8BDEB11BEF54D6C32DA97B439DA8B58B9
+:101DC00066472486A29AB4C45D6125BE5B3109F9D9
+:101DD0006EF7D8CEEDE827FAAB189D9BD96D6B9BBB
+:101DE0008DDF53EEAE525C8031C04B5FFA71AEEFC7
+:101DF000D527F1E95D3006FDB3F5EEC52AEAA72A3D
+:101E00003B8F8FAA9262286EDAFD6207C551EBF311
+:101E1000ED2AF94F475650DCC552A2891FD61F69DB
+:101E2000CE57609CB9CA752A9D13B3822B83766402
+:101E30008B93E17873E7F40FCE9703EF3FB5F5D0BE
+:101E4000B9B24F7F18C1FC863C6CFC1CDF9E6FA2B0
+:101E50009FEE2A556515E3B41E2FFAD320EA6A33A4
+:101E600094DB6C9E0815EA076E9402B89F102FFC55
+:101E700097AC6A4EC7CB429E2E0BFD73B9C06EB2B3
+:101E80002BCCE52F467BF63BC107F8A724015DE983
+:101E90001F408F866E92238C5B919EEE08ADE47F8F
+:101EA00018F8D45DC9FD097D1F2311EC2CED672CBA
+:101EB000B1129DD380CEA8FFC05F1E83F8F8AA3B65
+:101EC000AF14CF31A48CE77A352D5FA23C01F3DB50
+:101ED00019E22D7194F7618CB7060AA4F2FDCA507D
+:101EE000FE1E335EE4654779CAD00E2426F3FC78E3
+:101EF000A25C618974D3BE888AFD12E51ACA870C78
+:101F000024A6AAFB0DF8D4F32617808E74EE34F0C5
+:101F10004B6B8DC19F08EEB744129D2F58BAAD91FF
+:101F2000197C7DC8D7FAFA02CD517546BD9529D6E0
+:101F30001328E0FE067379881F922CEA28CCDB5424
+:101F40008D62DDB8CEAA276E7F82E7D95B681DB1AE
+:101F5000E319F54BCCF250DE6D203186E04DCC62BA
+:101F60002BB17F624B8A847004F1E9227B7258F8AE
+:101F70002B83728EFE5406CA39F7E3D7831FCF2412
+:101F80002EEFC497E0E7D3390221F783FA4CC8FD5E
+:101F9000DC239CBED1D55CEE41EE26A1FF88FA0C75
+:101FA000CF8F7E5A713117E59EB1E252947B5D6E00
+:101FB000D7DBFB73D5C291E5BE2A3A40F2523521F8
+:101FC000B7B42523D8FF539B42FB9F9F825C22DF3F
+:101FD000FFF4C5B703C67C854E9757ED7E92A75791
+:101FE00033A3548E3FE0DB98A03E5CFFA3FB73C39A
+:101FF0009DEB08DA353FF91B173219A7BB1817F705
+:102000000C634AE9E97796D23D75FC3BF36A8BF0A5
+:102010004FFA9EC5F6D1850AED5F3BA7F7CC407D10
+:10202000B2623CCFB3EAFE49FAC64EBA4728096C01
+:1020300025E17B7F34E5F7F53C5E285C0BC673B980
+:10204000D4F3657A5C8AFB1AD8FE5BE3397D3708E6
+:10205000BEBA6FBC64B2AFA1712D73F2F86C383B9D
+:10206000A2F7FFB2F28BFA3CBA3D0BE2BBD9B43F08
+:1020700083EB9A5F387CBBB6A35C7FD01FD2E74767
+:10208000FCFCF927A87C80AEFB84DE5A56E0B979C7
+:102090003CB44FA8EEA67CDD73222F9EE95D12575B
+:1020A00013665CBDFCD0E6AB7F5FE1FAAB4C70E23F
+:1020B000B6198EE39A5DADE2F9D2EF097C85B6B729
+:1020C00032EB1FFA0DF709667AFFCCF4FB4C107F58
+:1020D00043F92F601AC735DDBCFF82F05FED1E9318
+:1020E000D690FD93D6AC9789CFA21DB1C437B3303B
+:1020F0006884F9EF57C674209D70BCF9E4176D3100
+:10210000CD1B0A47A4628663247CB65A0E35227F13
+:102110003E27F099B9E7EA70FF50B4DBA99F0F6E34
+:10212000789DE179B54BA7199D676FB528CD687F7C
+:10213000FDBF6225688F6366B2FFC0FAD8A96DF94A
+:10214000745F6673671DD9158F19CEE43AF33D307D
+:10215000A9DE04537974639AA9FD585FA6A97EDCB1
+:10216000C6F1A6FA0C7FA9A99CD57A9DA97D4EDB64
+:102170006C5339AFFDABA6F605811A5379C2C1A5E0
+:10218000A6F6459D2BCDF4DE736B259D5BEF63F1C9
+:1021900048AF8982FF98A3BFD4784EFF8FE3F93907
+:1021A000BEF23EF33D38715343EEC119867F42E9DA
+:1021B0003DF14828DFDD487AEA5221A3BC50F44BB8
+:1021C00017B6201FA5AC62BE8869782FA799CF47A4
+:1021D0001A6F4B74B16537DAB73E99BE6B7C192B19
+:1021E000C2F8A9FA77EB7AB9AA3A8EEBDBCB3523A2
+:1021F000F8B59C9F6B22F8FE674DB4F93B974913E5
+:10220000B83E9D3081EB8B91F8F3FC66F37731CECD
+:102210003D19B3117E86DFA74898EF902A52013FFF
+:10222000095E27F95D8DD66E5662B0F7BB047FEF6D
+:1022300016FCDDBED945E3FCCBE6147AEED9ACD072
+:10224000FB7D9BF3E919D8ACD2FBFD9BA7D2F30031
+:10225000F85BF87C6A73353D0F6EF650BBEF6FAEDE
+:10226000A3E7339BBDFCFB2A2F04C26541FDC22EB0
+:102270002784CD730FF9CE5FFF8EDF3BCDD68DFA6D
+:1022800049B1FAF01E84E1F031A4FF08F79C86DE24
+:10229000933A7BC2DF764FEA48FA4FE717766552EA
+:1022A0004EB873BFC00774DE27E1078F3DE627FDF8
+:1022B00055C0BFD377F0EFE08AD1D6535CD69F6686
+:1022C0009C27745F7A368B0BFBBDFB8B13B81DD636
+:1022D00004DF69217CF7DD09DC4EDC23DAFDBFC2B7
+:1022E00077476D31E4DF1EB5B9C6241AD67BD41604
+:1022F0004DEF59BE8B617CC512B439C89798BAB7F7
+:1023000083FFF4D30936E16F65D33DB3FAFEFDF0E8
+:10231000726DCE4364EE4925BFEB928B69E8D768B6
+:10232000780817F091320F7C18A4A3D7C5F7CF6EA9
+:10233000137E8F15E88AF64E35E8C930F74B0DC786
+:1023400067BF9EA098CE03859E43C8F4A65AAF45AA
+:102350007E869C5FF882F2F3FD7F90FCE87CCEAE37
+:102360008CCA0E273F9A909F15137E42F2A3F379F1
+:1023700005DA25C3FC6F0BFDFAB6D0AF4707FD8524
+:10238000D47AD24FD6BC0463DEE497A2FDC8F88DA0
+:10239000B49AF45B889C8ED41F7754507E34901F7F
+:1023A0009C5F73C4FAA363BF087DAF8EBF21F31D8A
+:1023B000715F53FEC5CDFCB7209FAE6116DA975D05
+:1023C000E370D27939D66EBBD86FE0D3E24CEDC260
+:1023D0000494178D29AE2492238ABB99B8F7B94487
+:1023E0002FFB37901C4C6112DD0F2DF527C9EB3107
+:1023F0000FF83F62294E9AD2BF8689BCA02AE3BE5D
+:10240000F01C702992F4A39228373E1E97CC76F4E4
+:10241000637F07C6FF59204392DA2A23BFB9A5E399
+:1024200027A1BFFC0AA37DB85287DAE2B660178FF6
+:102430008CED24C6E3CFF28F79FD74D6D3E2867E8D
+:1024400033D900D54F7574B65801CE71EC8AEB1CA8
+:10245000F254F253EB3E87D0CC3FDBF73DDCD7F7AD
+:102460006FB1B216783E1EFDADA7513F6FF447B86D
+:10247000F07E7466E5F5BFB1395C285FFB2C5E67C2
+:1024800021E0A3217ED3147E4ECB37919F97B77E58
+:1024900088FE880582C4CF61BED9CEB2BAD5B81C39
+:1024A000F19EF099116CA7CB7D68F9B16D3C3E6F40
+:1024B000B99FF36F4B332FE714727E1D5D28F6032F
+:1024C0000AF5FBCE80324978AFB94E175FB71FE0EF
+:1024D0008EF4C5AAF89D9B965F4471A15DE1F73922
+:1024E00047E1EF0B007C918BDA093EC6EAE91C93C9
+:1024F000D4EDA1FBB643C7D3F2EFA5F1EC623C8764
+:10250000A34D73005F44D707FCB6F0FD8F6700BE94
+:10251000ACD5DC6FF339BD930A094E4D5B8DF97371
+:1025200078857874BA008ECC203FFE0D749881E3D4
+:102530008E44073966CE69CCC3CC0E4428989708E0
+:10254000A5C705D4D938EF9FEDE23E9EABD3A75E79
+:10255000E07DF6C61B03B89F37EBCAE6589CB772FE
+:10256000E3DC80F17CD4ECBD7CBF62B64D71278486
+:10257000B1DB83ED9C308EF17E3D6BFF681CEFE597
+:1025800061EE836B147CC0D818CEC7022EDB6CCFF3
+:102590006A7E8ED27B3DAED7CED224DCCF9063ABA9
+:1025A00069FDDB53533270FD8B04FC9A2793F822AC
+:1025B000613A13DFE3F3FD0BA0D742C4ABBD5DA2CC
+:1025C000DF9DB0A774D37DD587BE16FFAE1B4F76B7
+:1025D000F89F5BF406C8F3A18AF85BDCC00FE38BBD
+:1025E000A62DB2823C1F7A9391304716DDFCB81FAE
+:1025F000E03EB430FEBB89D0BEB9F8E26E1BDE030C
+:10260000B84CA27A6B31D4C3784F8FF7DE85F34C88
+:102610007A431B8B767A29B3D2F742274F5C770235
+:102620007F1FC05DE97BFF5E282FEC95E99E35FD9D
+:1026300077089EC07FCBBC3CAB1CF597F813F50721
+:10264000F0DF40F7ACF68CA378FF196B905C9836FE
+:102650005CD3CEF76FB2F64CA1EF06B3DB4BFA7149
+:102660003EE68D50D0AF59D3CEF557365307709F05
+:10267000A213F38D36BC2F4C6971423F7F11A3F337
+:1026800093E31AF8F998737B233A303F7C6A33D38B
+:10269000B6E6B061F5E314BD0CFC88F71DCC08A9C3
+:1026A000D7F5E739C9C5EEC27936C4AA4F02DEA60E
+:1026B00078DF96EF32E84F88CCA97C839043B595BC
+:1026C00055E2EF3E643630BA97C2CE7CDCDFD11CD7
+:1026D000FD2DA85F51F6CBE918833E1FE9DB2ABD2B
+:1026E000ECF559F15E099600FA5F45372890E2A0B3
+:1026F0007BB332E89E22F90646DF0BA757771FB35C
+:1027000041FB495A05E9D1C9CCFB4A0F3CA769876F
+:10271000845E0DB4E011770BC6F930DEF42B5CFF5C
+:102720006ACC65C5FAD94CB5F2FBB818D9D13929AC
+:10273000FCBC79356BA3F75F659DF49CC77AE8799B
+:10274000131BA0A787B9E83EAF990ED0FFA0278E34
+:10275000E165FC9371DF8A9FFF2FAD8EE8C0386E74
+:10276000E102B00B50AEEB6614D7D5562B746F80D8
+:102770002E2F3583F70728F47D1EB32A631719EC33
+:10278000E9C9BD8BE99E28C5623EAFFB5A21F723FC
+:102790007A85BCED96849EB855A2BCD9EE2576828A
+:1027A000A3EF5689F2C7504FF77AFB973878BDCD23
+:1027B000D39C84F5BF2B629807978B14939DEF9B56
+:1027C000BF967E8FA6635BAE0D9F355E71EF16F3ED
+:1027D0000B38FD638D79D0732B004E91A732E63F05
+:1027E0007E2DEC818CBA6F32F2E5E265741ECDC1AC
+:1027F000E14DBA299EF22E55ACCE8AE73A2F8A7562
+:102800000524CF1C82771DFF5E5D97A7469D3FACD8
+:102810007E7B1AD4D7AA19A41F74F89706781E765F
+:1028200069E37C92AF798DEB18DE0351B164018DC1
+:1028300057E7E1E7CAA4462F7D37BCC4C1CBC173BB
+:1028400063FC1C415D43C532B2F7ED110CE5AFCE20
+:10285000BBE23D3C77BCA4FE0605E9E8B0F2FDB062
+:10286000E4068011CF77D7AFA5F1B76A000BEA6C09
+:102870006B4F37F26F52A695E461DC3CF0F8C89ECE
+:1028800004E8F71E3A0A781E3541EC6BC483D2C1C6
+:1028900073634BF63C5C8574496B62B49FAF30AF99
+:1028A0001DF13D9CFFB3F7BE2BF1E4F7A2BF300E44
+:1028B000E0DA282B789E36C3AA50FEF8EDE3DCAEB2
+:1028C000B6D6B7903EBD344FA21F1BA96DE3F72FBC
+:1028D000C204E21EB76E0BEDE7B557907CB0D9DEAF
+:1028E000EDDD65A42F7C087F09E3F98A3BC4F70B73
+:1028F000A1F141A8BE706CB4131CF24C2FD1B94F9A
+:10290000622ADD2B1802BFE4F967AA07BFAB7F1468
+:10291000EA857C978CF777B03B6207E51EF5A956F0
+:102920005844EB515FE3EB99D4A3C9F8DE21FC2BAB
+:10293000C636717B13F9948476BED2E55FEE86F1DC
+:102940004F1E6FD88E47D76D6EC56A8C075E89990A
+:102950007206ED4EEFEA08A2E73BA9DC9F9975E508
+:10296000F918631E492BE2F6A814ED29ACA764639D
+:102970002DD95175E37C933D2DBD95DBD3129B6B17
+:1029800054387B5A85FC69C8FFA8C73D26BB3A5B13
+:10299000D8C7DE0ACF32E3B99BAA222E3FD78B27B6
+:1029A0007BC39F8EFC70E1E74CA1FC9F8D09BFC0EB
+:1029B0008C7FDA6380FAF33F67742F25EA5FE26762
+:1029C00008101E05FE94F624BF72B7517F8FF7934F
+:1029D000DD1A0EDF8B8B783EADAC7DBE8CFECC0B52
+:1029E0001D531EA56D8E11F833942E6C82B6BC0853
+:1029F000F789E479C46F9FB5F37D974327D610BF5D
+:102A00009D96980FE3F6D0714A1128A85FD2C302B1
+:102A1000012968FF3E0310B15FD92959F5A30AF0D7
+:102A2000E019FE205E93EB1C783670B0AC36B01621
+:102A300094BFD4566E9752BD2E53FDE8C61453FF73
+:102A4000B13EC5543F6E63BEA93EC3AF9ACA59ADED
+:102A5000534DED73DA345339AFBDDAD4BE20E031D3
+:102A600095271CAC33B5677EED64A1C14E17757A0E
+:102A70004DEDF1DAC674A493F8BD9F89471ACDFDD8
+:102A8000CF807FE8C073623EC26319E365AA07BCCA
+:102A9000034BBFB217FA2F9D1AE1EA86FE4B1B6C5F
+:102AA000417F12E5EC0D2663FC5EEB75FA508FAAB0
+:102AB00021FE69681CBEF635FFAB286FA5AF7969AA
+:102AC0009F616F11C4E54877119757C94EA2D76728
+:102AD0007DB28A3EFC5AF4E4DD41BA7EC638DF9608
+:102AE0001D6501DAC70D59BF1EB7370ABA2F8571A8
+:102AF000BAA12A22C54CF748C54CF7E87C339D6340
+:102B000054339DE3A69AE91CAF99E9AC9EB95BC624
+:102B1000DF55FA45AACCA4A98C8DAA36D35DC7F39C
+:102B200054F85F383C87E25515BFBB34123E4F1452
+:102B300085E6359C0AFA5197ACDC9F80BF058EF282
+:102B4000A172DF378CDCEBF8933CC9A46787957FD3
+:102B5000E7BAED789F84DAC3E57FF2BC0C3CAEC2E5
+:102B60004EAF98321AE99AC65ED2BF2FF1E2B91A77
+:102B700090EB7750AEA337AAFD7E6E37E9FCDCA15F
+:102B800013F6ADD9A8676F64CFCA61F6013F2CD2A6
+:102B9000F7013D1F162506F701CFCDF0D1399DD3A2
+:102BA0009245DDE246BF97119FAC7983FB6F2C34D1
+:102BB000BE0FF56FFD2B489F4C11F68B6EF2729392
+:102BC0007FAB529E2444BF947843EC5048FC2FD5F1
+:102BD000FFB3D9DF5D69C657CB546F869435546F08
+:102BE0000E1FFFF7D3FB59CCDF82F6F82BD5EABBDB
+:102BF0007702DCBD5F7B7B34AE3F340F00F8B51548
+:102C00002706F757B56A3D3EEA9981FE4F74613752
+:102C10005B07FD9CC583F874161BF0793852A578C4
+:102C2000E2D4DE0805F7C7CBDE6CE0E7862545C5B4
+:102C3000F38B87E3399F9C9258FF61284FEEE37135
+:102C400045566306DD3B7438437D05CBA7D6491452
+:102C5000EF949FD6643CC794EDE3F7A6946EF154CD
+:102C6000E23D0A0BEFE2E7077EFCBB3574CE29702C
+:102C70000FAF3F5CE1A373DCA7EEE5F553CEF0EFB9
+:102C8000D80AFC627CA9AD3216EDD93689FB234304
+:102C9000E8C9E393593A3DF6FCE995BBCB82F45879
+:102CA00079417D3516DE370C78AE8F6343E9A3FB9F
+:102CB000FF33ADDCBFD7FDFE39CC43CFEB998F9E00
+:102CC000D7EAF72F2ECEE7E7D9984A654DC401D150
+:102CD000D55AC573C8FFBE5886573B85FA016D09A2
+:102CE0009E75B82FE7AEF4D0BD2B8B8BB97F117CCE
+:102CF000EAFBCCDA5815EAFBF4FBA01D1EBACF3E66
+:102D0000E93655E6793E9F15E52C30B66412AE677C
+:102D10006E313F9792F5808FFCD09B9A60F9D0AED0
+:102D2000FB716B3C9E67A3BBA3C2C4F7C1BC5BC86D
+:102D30007936AB9FCE6996CACA04FC62624371F1D0
+:102D4000E31847236FE0F7C2AB9E9BBAD88FDF0A28
+:102D500033EE8F8CD4AE4F9C8F392CEE035AE0C9E2
+:102D6000B0A01E395C62F6773614F378467F4EEEDB
+:102D7000E3EBBC698CA4621C73839575639EFC6F46
+:102D80005D57E916FF72C4CFC2FD118C9F6B61695C
+:102D9000C673C5BA5E59C8F43FCF09E4B33522AE55
+:102DA0003D5FE4237A9FEFC83B5E03EFCFCD9702F0
+:102DB000783FC82207786240FFB74FECA6A73EDEF7
+:102DC0009AF69F9E9662AFC13F7A7CBCFCF904FAEA
+:102DD0008941D2EF6BAC3C3FA5C39338A8DFC12F2C
+:102DE00087FA93E0276D51D1BF3924A5C843C70D99
+:102DF000D5FB204F0CED44BA2E3FD58B9BEF34EA28
+:102E0000B3FCCEE63BB1BDF0BBF5FC26FC51FCBAF1
+:102E1000633ED75B490EBF8863F8F9CCD446FE7E8B
+:102E20002C1B90B0BDC25C5B12F11E1EDC50806793
+:102E3000F289E3CD08773CEA33B417F71F2B237DE3
+:102E4000C63C7ECC9F8156F4FD0BCC6773CCD39AE5
+:102E5000601E588B0F6DB9CFE97D0AF597368692C3
+:102E6000A82C41ECB33A5D039AA410DF115222362C
+:102E70004627A35F1E9A9F8BB0FA9EC632F347B8CF
+:102E8000F0FCF1E3D1DFA2FA8D56872B82BE00F26F
+:102E90004D41FEFE657182C853F2FC9CEC70257FAB
+:102EA0006CB0D336574AB2D14F2FE9564CF5935EEA
+:102EB000CB37D54FEE514DE529A7A79ADA4FEBD77F
+:102EC0004CE5AF5CA836B59F31E03195675DAE3318
+:102ED000B5AF602B4CF5958E5B4DF555AE0DA6F25A
+:102EE0000D29779BDADFA8349BEA99575B8EFCC4E7
+:102EF0002CB1F45DC5903C50881E9ED196CC8C714F
+:102F0000C3605E25C54E7C10817431DAC569AA4262
+:102F1000BF172B819E85E7FC09DEFEE2C9A46FC7BF
+:102F2000207FACCAFFA005C7CDD42E1C44FA3CEFCD
+:102F3000B732846367D4FAC615187F6E897549A0C5
+:102F40003F76E6EADFC9029783FE787EEA23C7D0A0
+:102F50009E3D7FC41A40E082DFD1F2FAED518CE74A
+:102F600043C63B283E7A1C3735A01C3BC14AE73993
+:102F7000D7CA1AFDFEC3798B8F3F255542F8565AA2
+:102F8000BC2A3EF759BC7F2CA6FC6D7B3AF2FBF3C2
+:102F9000AEFE47F03BE5E78FB8E93BE3E75FFAB009
+:102FA00015EF6BFB036303084757CFC5834FC0730F
+:102FB000E26B3C189E38F5C347E6223E7B6C2AA69E
+:102FC000DF7E6B670F30C3F7FCBFBD8B9FDBF13A31
+:102FD000648F15FD276B201DE3CE032AB703FD5236
+:102FE000F87B8F7E9D53A14EC4FAD4F0DF118E9AE8
+:102FF00068317DB79A99AF26DF62CCC7E4DC44FD27
+:10300000F5B2ED723CF31AE2589B152C9C13DFBB12
+:10301000E93D2CCF8F717225DE4B07F6242E3EDF63
+:103020008AF15F85F30F16C44B227A85503F20F159
+:10303000F393CCCAEF4D61D3AD03837E6D26F6E7E3
+:10304000FE30E5BDA15D85C3EC0F4F64E672685E9E
+:10305000BB6022B707B6907B3382F0F2FB3280C6AA
+:103060005BD1EF6BB180DF0770B58C9F9A8FF9361B
+:10307000CDF96FA725D4BF0CF4A401AE9DE3B547ED
+:10308000D5C9C1EFFC575AC4BD54272D09C837D63E
+:103090000407AD3F6E46029D1BD4E76D9A6831DD93
+:1030A0000B721EE885F74D84AEBBC25F5187F255A7
+:1030B000CF8A4B119E451325F37D2242BF2F13F279
+:1030C000B5CCF5EA9FD15E5C5425914F74253D0B3C
+:1030D000F02CF7C7D2F99FAFD7B3584C25780BDC4B
+:1030E000BFD0E0F9E1DEA2732FE2735FC11FEF866C
+:1030F0006783453D4A79D69DC28FD27FAFD43F9A30
+:10310000ECCBB5DAC919792B66AA80EFA8D88082F2
+:10311000BF931835FE029D0F5C3D91111D2AC14CD5
+:10312000A1DC0CA1ABE08B50FAE204C81723D1B9A3
+:1031300041E43981C3738DE7DD66E455CC443AB58B
+:10314000D9587702F2DB4F22F8FD2AAF0169A1FCC2
+:103150004F2F17501EF1B2EA9D8E70EBDF75B3E36F
+:1031600003745FCB4A719E8EA568F49DD843D3DD6E
+:1031700025FA3DBFC8BF958E783A37B743C88FBE92
+:103180008E2FCAC7EE2CAE7774791869BDB01E9326
+:103190001C4F57399FEB4F7D1DA1DF874E572DA246
+:1031A0001DBFFFE5B2EAA175FF53CDC07BF159F811
+:1031B000BD8B385F38C27AF7FE9DEBBD56BA16203C
+:1031C000DF00FD56465D1B5C9DFF4570E1DD6B0435
+:1031D00057F1B5C175FCEF844B639C3E23C105F4E8
+:1031E0009C85F4647306F83D3309D706DF05A19783
+:1031F000FE1EF812AE0DBED368475837876F11C454
+:1032000041E88786F9DEA68AF6D557815B007141D1
+:10321000949DC7FF513512E5EB24966DE3F723FC2F
+:103220006DDFDD0CD22F8975C7A3DE7B3982E743C2
+:10323000D5815C631EF7538197CBAAF6FB89897809
+:10324000FF8DD007D5E676BF0F69A7DF6FC2E659BD
+:10325000683FE591EA6CBAF7C5E260E27B2B7E3EFF
+:10326000FF7F0BFB14FABD956E8FB60B7BB47D7C94
+:1032700035DDEBB0FDDF6CF4BB475A0AB74BFF07F7
+:103280006AFCA102008000001F8B08000000000003
+:10329000000BED7D0B7854D5B5F03E73E695649246
+:1032A0009C249330E1E5998447C0104E92C90B02EB
+:1032B0009C3CC060431D1E6A10D401290F790D6823
+:1032C000356DFD9B09091153AB51BC152BDA81AA51
+:1032D000A5ADB746457F44A0830AC55EA51111B1CF
+:1032E000A21D9122CA232368D1BFDCCBBFD6DAE767
+:1032F00024732609F1D1FB7FBDFFD7F8E9769FBD86
+:10330000CF3E7BAFF75A7BED3D8C594E857318FD50
+:103310005DCC827FF16F12639F34EC938659BAEBD8
+:10332000B1E552F19962BFA3E7F36DA37D494A511C
+:1033300054BF2DAF4AC3ECDAF8F0EF18163631114E
+:103340006B11933711CB61D271FCFE006817FBFE45
+:103350001E6366765C9F27F4B3EDF36D7078180BEF
+:103360000A56990D65AC7E7028F22CB4B50C81FF1D
+:10337000C0F33B8BAC41D18DBD7D758293B1C4351B
+:1033800049522B94E2C0DBFE320F9E360E5948CFD5
+:103390006F5FE3906C50B664DE7618EB771FB0C8B1
+:1033A000FC3DF82B66CC8A6516FEC7AF5660BBC0E5
+:1033B00022AD123C0FDDCA72E13B4CB547925DF481
+:1033C0009DD0FF82F6387F92DCAAC0636570E0284A
+:1033D000AD5BA4F9427B00E76BAFB4B763BB75B0DC
+:1033E000DECEE1621D5C1E389AD35DF7CABC5D601B
+:1033F000171BF0FDD8FE309F8003BEE730B1F656B4
+:103400001837DE253EF4581A63F7A679F7B800FEA0
+:10341000B6C1DE141FE067C248EF44C447FCE8139E
+:1034200023B0BE62FBAF655F2E63E94D3033783F5A
+:1034300092181FDC0CEB6D1A5D9A2347E1739622FC
+:103440003006EF59BE1059A0B0FBB9C5EC65920328
+:103450009F5B0DCF430D7616B075D7D513E66A0680
+:10346000FD2A98D42C5199C00251EBEB1AEF0B8135
+:1034700005D27A1BDF4CCF7F27B0E610CC3320304B
+:10348000FFE3B04ED5F1C7C3421E8ED23BDD861A94
+:1034900042338E01DD363794CEC4F2A50675E6B10F
+:1034A000E18C5D3BB2E25E8443BA77DF8C6351709E
+:1034B0001C50D761A867FA0ECF381635CF418BC3A1
+:1034C00086F621FE1386F6CBEA2386BA3BF085A169
+:1034D0007FF63A3633BA3EBCCD3E33BAFF3A93BBA1
+:1034E000BA09F1203065339423374886768722372E
+:1034F0009AE1B9C529E78BD4DFD4CCB0FF3CE6DF35
+:103500009CCFD8A8A0CB307E6BA36C7E858F97BF55
+:1035100019E075F916D9305EC57FCD54F17D96CA94
+:10352000521E07BC8F69CF31BC6F914A0DFDAF1D94
+:1035300039EF5E259DB12A7B85711CB6DBB06E33F9
+:1035400053597D2A94E6BB3E15F3B0CE58790196C7
+:10355000E6CFBAF0E4C6F1541A2F560E04EE2C4F03
+:10356000397E39E3726012D2A7A4201F47E218C344
+:1035700075B21C26633F1DCFBF44FA847196C5D037
+:10358000E73273C88AF4B3EC5BD2E79C916AEB48EC
+:10359000183FBD8ADDE8ED45CEFD51FBFE496BEFDE
+:1035A000EDED5DFC13C782BDD2B7839E9FACE4EF07
+:1035B0008F62EA801951EBDBA98D9F24327F3BF0AB
+:1035C000EBAD89EA80D45EBED3CD47092CD82B9FC2
+:1035D00026D1F39359BD7FE78F5FFB3B621FEBB1B1
+:1035E000D273902BBDC2E35D1D5EA9BDB7BFADB563
+:1035F0005BBEC834C8837715993FEFFACE606AB7CF
+:103600007C91D2875C72D273A09C00CAF32AF89F87
+:10361000D614C6925372CCCC0478767C6642796E0E
+:103620004D00D28CD237ACDC1C89962755CC7C342B
+:103630000C7C6102C17311A65661B71C0D47D1C73E
+:103640005866AC33EC1FA59F468D6584FF2A269BE8
+:1036500059762FE369F3881D77D1003EAFFEC67718
+:10366000E6AB55638BE8B974DCDEFDFCABEACF78E2
+:103670009803CBA471847C184765CB16A39C9DCB83
+:103680009214D493F0E7B56730763DFE9F8CFC072B
+:103690000FCBE0BDA48EB59BE07FE357272901D077
+:1036A00063379A22E938DF792CBC169415FBCBCE10
+:1036B000382BC2B973E71F86A0BE61AC9AF4BB1069
+:1036C00048102F267CF5F98144E0788FE7F4C2AAF0
+:1036D000237521900763C5BC02D4BFC9A60B2E94E5
+:1036E0000F4C920BC44CECDF48F0CE7BE3EAE410C5
+:1036F000E2C79E144848827E208806811C4A4614F0
+:10370000A7627937C9A7E41DE64FA2E19B84F08048
+:10371000F5D51F99177C254A1E7ED6712E1ED731EE
+:10372000323FD1791CE6CF4A5809CEEF2C9B9B1C27
+:1037300042B8943A098E4FEDA84C46BD9AF742F52F
+:10374000002C5F6A58279941FF9C6FF0055F19DED6
+:1037500073BD957DC80D4F3EE7835251F5205E2A1B
+:10376000E37BEF5796CFE5CB54512DCB4FEF1E0F98
+:10377000FB4FCFED451EE59B685C1DAE807059CABE
+:1037800040FB42C32FD0A519EA13B4BAD0F6B6F85D
+:103790000358DAC65B921411ED1B9FCC10FEB0F0FB
+:1037A000602BC8F116C1CF90AEEDAC8DCA5641D991
+:1037B0002042299A22695CAE07697E93998FE87945
+:1037C000A2DD3F18E93D50E9FF4518C609AC31B309
+:1037D00026281F4CF8F1AFC2F09DFA808DECB0F3B3
+:1037E0007143830CF0C62EF75D934FF3F59778C7BE
+:1037F0005039164BEB4BEA0D388F8890A4A07E838E
+:103800009146E0737D9D7335B81CBD5C9D8BF09B2C
+:1038100094AF5E8FE581B8A12AD28B9CCF143688F5
+:10382000EA4106747060EA15C90CE0F5195393A5D6
+:103830005EE0A6973EBBE86D8E924BE11480772F39
+:10384000FDEBB5EF770EE9B0E2BA5B2B22437F8E3A
+:10385000F3DD699336239C6B0FECFD11D4EF5746D3
+:103860002848C7CCDCD182EB4915643FDA856CABC4
+:10387000D1AEF99D460F7E874CE326DB81BA4DD849
+:10388000DACE501FCE1EADFE00D777C2CA16B703E0
+:10389000FE4FC46B65129430BF666D3E4BB5711E12
+:1038A000D2EA274CBCFD442AEFAFCF5FEFF7B0560A
+:1038B0001E6BB07B9BA3FC00F9419B3F08FDD3B37B
+:1038C000399D11E7C2FC57EC18B009E96241DB07EA
+:1038D000D6F9D0FE487EC5529C17F643BA5C600EFE
+:1038E0005B53A1FFDA51BEFBF0F90A99A9CFE0FBC7
+:1038F00072D83A13F0D729B03A9C47A7054A78DE28
+:1039000019C74B7D3E8FE44F5F8AF4D039216C4557
+:103910007AD3EB2B58E40651C4BA97BE07F5476338
+:10392000EAEF9BA1AE0EFECF8508E7BEE49BC9DEA1
+:10393000B1E761787E831FE81DF0E2DBF6E99E1FA8
+:10394000C1F3C5488BF07C718B100CB8BFBD3C8BAC
+:10395000B573468D95383F9A7D0AF943FDF1E58EA2
+:10396000B75FFE51345FEE7A7510F255F9AED7D3DA
+:10397000B0EC852F0FBFE8EE9F2F9DD99C9E57A4DA
+:103980004FD980FC196C720AC244707DD41AAA7F88
+:103990006676A520BD7E897204DE6F0699D6817297
+:1039A000D91C94D08E5A11A7DE5B89FCF886C81EFC
+:1039B00087C27D99DE1EB232F237D464D4C7913704
+:1039C0004401FD8D51E5EA00E4DB5B9FAE1880EF1A
+:1039D000BFA7D1E57F973DB795B11AA4A715296672
+:1039E000E64CEE7E4F5FCF0A8179DB7BE167BDFD60
+:1039F000C5FF127BE5F7BA022E57FBB2133FD5E89D
+:103A000077C517A30C76D30AE0079CE78A2F722F9D
+:103A100069377DA9C16505DA3BBDBEEFA4E78F9A82
+:103A2000BC9717101DA9198D80878FC15F423A97E7
+:103A3000997719CABDC5A0295BC18E5E6CAFCD68F0
+:103A4000E4F4EFB795233918E58D59D383309E05FB
+:103A5000C7FBD8E2730BA4DF652BD7F3463B86493F
+:103A60005CFFDDE498457AFFA675166AD7E10E98EB
+:103A7000B1225D7FAF2DF6B9D19ED1F903BE5B5A5D
+:103A800050D4731DCBE36BF7A9D8CDD33114E966BD
+:103A9000056B23390092780AF2C3CD8A95E469B3A5
+:103AA0007474CAC3F0DE52589F88F2749B717D4BC8
+:103AB000B4EFEAF35FBAC538AF65AC83C65DDEDE4E
+:103AC000CF7C73B87FC2E281C7D03F61E512F17548
+:103AD0001C6F1F50C0E5F5E9A28E2742F01D31B1E1
+:103AE000DA8E76C4996D1F1F12319EE0E2F614CC77
+:103AF000FF67E351BE6C13A55699E0D0321EC6EDA8
+:103B0000CCE7EB596C7784D05E89C5930EAF93B741
+:103B1000F5AE87D235BADC52A84E40785AB2DAF701
+:103B20000E44FEFBBEA0901E626A3ECAB566331309
+:103B300070FEA5E1C82DB81E978B4922D49D097C43
+:103B40005CA6A876F41732EBABD8874067EF4995AF
+:103B500076199E67A498BCA8079AA5F9293745D17C
+:103B60006D8660F2A21CBF1E785346BD37DBFC3861
+:103B7000F2BBFBB6BF2F25783139D55686E3FBEE75
+:103B80009B8CED2922CDA762F667857698CFC00B76
+:103B90008E029BD03DDEA4AA48A19FE218BE3C5CE9
+:103BA000C790C3E1E302EA3F873A14E9EA371A5FB4
+:103BB000FF669FA966732F70B8BD80F3EFE874B3FA
+:103BC0003708ED978798BAA9173ED3FB65A4325FF3
+:103BD000FB25F8706B65F806E4D3926AA6F6F6BD8D
+:103BE0006505BCDF97481300FFADA9E18508C7ADA7
+:103BF0005782EC86F59DD93960F39AA8F55DD0E43B
+:103C0000CB99A95CDF159BBD37EC71A27A9084003B
+:103C1000C067C0DC90699EA35B0E8D1CA9A6221C08
+:103C20007479F360C2A326C2E31BC33747C34D9F19
+:103C30006FB3C0C7D5FDBA58B91C3BFF155F080666
+:103C400039F5653EA7E36E7963A6F6C962AED50A7B
+:103C5000DFFD18506803FFEAC1371F4DC2797CFCB5
+:103C600084C86CA427D5242103E505D75B1F3F96A4
+:103C700036653BAC6761A6C850BFCEF7492D080F2B
+:103C8000C9C7FCF782FC98DF1CEBEFB4E59D46BE8C
+:103C9000089819F2FF82234A0B850BC56556FCCEA6
+:103CA000E7F05D11BEBBE06E239F7E7CE01E2BEA39
+:103CB0007961BEC32F505C2E40DFFDDE36AB84F64B
+:103CC000D5C2078CDF59ACC933AABB917E59AF7EF0
+:103CD000C0AF0AC0FE47FE2E66C5C8DFDB1BB6B10B
+:103CE0000F87E37CE626235F8F8305B793BFD361FD
+:103CF0009E1EE55FEBF63F132B7F87789B66867EE3
+:103D0000B9088FEC01F3A3E8EC4F1E8E2FBDFE091E
+:103D1000E8B761F0DEA90689CA970AD4E7511EBF49
+:103D200051E0DBCEE57C64E86958D7CA351C3E9D7E
+:103D30006F6876731D97C73671D56284936D109343
+:103D40009A483EF9FD58CF30811E00B889E22D62B5
+:103D500012E1A98DD3FD5F3D2E94DFAD15EAD33F6F
+:103D600084715B534CAC09F0E46C924623DF3A4516
+:103D7000E66F82F76EFECD5D344E3095CB89EC2731
+:103D80002B4C604EB3515B05013F5F1A0EE4A04A15
+:103D900070C8F18A084B4A0E87E9B96E77A42704E8
+:103DA0005D26182FFD72ABD2E4C6712BF291BF6570
+:103DB00016243A3E83FE3A8CFBF0B6EC64D4E767F7
+:103DC000778CA4925D00B8143334DD81887BD2ED0A
+:103DD000A906783EB2BB3EBA7DBA3008F59CCFCA80
+:103DE000124A419E6F7DDAC4FD513E8F656B4219C8
+:103DF00073501EFEDAAC6C86A7CEDF4FCDC775BA06
+:103E0000CDB280F09B23485CBF68F6D76CA6FFB5A7
+:103E1000ED417D331FEC44A4A70F8520F9BD26B6E4
+:103E2000E3397CBFCEC5F5EC9C2A7806F5394D62A6
+:103E3000B009696AA92505ED41541DBDD98BFDD98D
+:103E40008DB1FD3EB18417FED9D31D373C234446C6
+:103E500070FBCE1FC47974A6B054C4B3AD50B31F69
+:103E600046805C43793E0CF439DAEB267935B6B3FB
+:103E700083601F20FD0812F5D7E1C3A4B6E7518F78
+:103E8000AE3449A487C03E0C24221DFC7EE4665C4F
+:103E9000CF194B7828C903906F02B4CB85ADB3CD51
+:103EA00000B71503413E43FD3B850FCE36031FADE2
+:103EB000C80A2F34417DF5B34FF1FAE8F071ACDF59
+:103EC00051B89DF72F082F4479F060E13E5E074618
+:103ED0006203197BACF04FB30330FE279A9F75C67F
+:103EE000C2E3D5675E18B5391085FFB642AEE73E2E
+:103EF00089E3FD3E71B31B67209E73C223A2E35C7E
+:103F0000B716EAFE2FA7F7252FC6859030F5F76084
+:103F10007C8A17C58E9FA7BDB7A44AD387E6C8B3CE
+:103F200008AF575C722AE9FD13206B10DEF05E2BA0
+:103F3000C0C55998CAE539C02735B7E7F76E463B83
+:103F4000D341DFAB8BD633E3353CB15C3EFE8A8197
+:103F5000520AE2232395DB6F8090943B29CEB189EE
+:103F6000E6E3CCE6F8718A523EF2E9A42AAE5F2677
+:103F7000A5A56D42BEEA6BBEFAF7A668DF5BD2A4C8
+:103F8000C10BC612912EB68FDAD4AAE1372517F1EC
+:103F9000C2F54E5B21B763B13F8D3B18E03BA69B5A
+:103FA0005EF471FB5B67DDFFA375320F7F0FE83CAA
+:103FB000BF55EA5E871E27FAA4517BAF549F874CFA
+:103FC000F4BFE4C51F6CA0F8B824A78A649FDDCFB6
+:103FD000E9C61E29C438FC2B17720BD0CF5DAED9B1
+:103FE0004382FA272BDAA3CBD77558D12E5ADE2E6F
+:103FF000A8681775F3997A6B345F39B3F93A9DA2C3
+:10400000EA6C22FE837912FFA9244F62E9A50BDE38
+:10401000B17CDB633C39D5389E4CE3F58587BBFE2C
+:10402000D17868EA1D9EFA3CA17F8051FFECCDD487
+:104030005FE73F7717FF85505EC6F2DF1D5D788B27
+:10404000E15BF737FC5E057F6FF90F007F1827965D
+:104050008D74BC7CABDB343FB7BBFFFD5BB2A6A36A
+:104060001EE88ABF6CDD1D401DB472C7D30CE37C13
+:1040700096352017518FEC14839B01A49DD0AD057C
+:10408000E5C1936E8A17ACD5E4CBDA9448924071BF
+:1040900020D184F67024DDDA8241C9481C3C87F7C0
+:1040A00003F0FCF1A875D7B3489205F1B04314F0C2
+:1040B00079B3FDC38C63406FE6B89319C7A2FCE0E7
+:1040C000E6442D5EE28A24A544E1D7F37B3109F76B
+:1040D000F3C241B08F7BB167196B22BC86196F9F09
+:1040E0002C5EF81DFAF96703C34C18873B6B8FFCF5
+:1040F0000EE37267CD39A901A99B6F8E05AEC8A8E2
+:1041000087DA5F99F7D078D46B01D59A09FAF1264E
+:104110004D3B2E7EB52909ED0831D1B3F745787FA7
+:10412000A10BEC3DA5A79D7633F32687DC3DED3151
+:10413000C08315E3D08B7C0E3FF93F1B8DED37EF2D
+:1041400038F9678CDBDD1CED8FC1383E2D9E1D6B71
+:10415000B7BD5FA8D96DF92C1FF529A04741FBF029
+:10416000EC4151696564C7DE4BFA721FD8AD02DAC3
+:104170001B22E1EFEC934210ED0C1648277B50B761
+:10418000E356321E7F8AB5377AD823CFBD57FC233A
+:10419000E8B2ECF977F31E86F2D4F3EF8C7811EBEA
+:1041A000FFFBEDA1EFB29EFDAB767D7903E9E15D0A
+:1041B000369A47E7AE3F0C453BA373BB4DC14977E9
+:1041C000AEB151FC32B02B31381CDB8770BC37EDFF
+:1041D0003C9F17263DD34CF889F35809AF6777FC0D
+:1041E000FD7DA4ABB33B6C32AE63E5AE0492F12B24
+:1041F000B7C705D15EE9DC79BED8174517DF763D34
+:104200002BACDC6FEA047A7C86CBE3A1F8FD15BB0E
+:1042100026A491BCDCBADB8A7E62D5EFFF332F8CFB
+:10422000FD9ED96D656348CF3CCA803E9C5BCF3F05
+:104230006401FC9D49E4FABF7D6BE97581DC9E70E9
+:104240008171CF60FC74E5EF13582B87CB62F4EBE0
+:10425000FA82C7E5FFA4F0E8B4744C198474F7B48B
+:10426000501890A3E122109E97ED480CDA055CFFF0
+:104270000B49D42FCBEC074A00389CCF437BB8BF07
+:10428000755F89EB2EFAFF60DD26F6B5D6BDE49F9B
+:1042900014DF3AFD7716723D12CB073DF9FF7FDF41
+:1042A00046F5DF252A34DFAFC8FF77FDCFC77B1E79
+:1042B000FA6D5F17EF5BFE49D7DD3FDE5FD5F09EFD
+:1042C0002861DCA473E77F0EA5F57EC575FFE17F4D
+:1042D000E8BA3D2C7203EA79A7B61FE3B40FA67DB6
+:1042E0002486F124B23B25667262D884B5935DE7DB
+:1042F000359FEAB21F28FE2985500F34AD4AE2FBF4
+:10430000685A7E486C1C76FD4EAF05E1EB03300920
+:10431000E3C15E9B760DD5A739982AC0B8D398D74C
+:1043200042F17000E7E3647F7B3B1640FD75CF7A76
+:1043300017EA178B203753FB5421F838C54B94DD0F
+:104340000950BF7A4D662ACE3BAD96599C589FE1E5
+:104350005644E8BF9F450ECE443EAD1395C7F97451
+:1043600067ED2B666C26FF7F764DE2AD9313A0DFE1
+:10437000790FF713AF2E6AB2A0BDF4DD26AF1FE3AD
+:1043800079570D8D0C4B898ACBFDDDE3E6FDCC5EC4
+:10439000CB2A787E35CE34B527BEAEC6C1E1F9D57D
+:1043A00092D7E2A73887B64FA58EFE46FB5463AD81
+:1043B000DCBE5F5A6B0B62BC72A9A2BCB714E1569B
+:1043C0006B93A007ABF4CC1B827438592C7FE4FBB1
+:1043D000B0DE034F82DC82E7271F7A7330FA418A0E
+:1043E000E7F62948BF0B0549247F6A9AC09E83A53A
+:1043F000CCAC9DB71FC79DF6A420609E9D45B3DB46
+:10440000B28A383CC42757EDCDF4205C53942BA0DE
+:10441000A971828DF6DF4E3E2404913FAA6A7D7B0E
+:10442000313EB5BED426D9085F6A12DA9F376BF0E9
+:10443000FD9345797518F6FF778BB246C62741EA9A
+:10444000BF18EC50F4874ED6DE6FC5FDAEBC229986
+:10445000D699E699571C92715D8D3F23F20BA80700
+:10446000720DE3F9EE298B1AAF71C2AF68BC4399A4
+:10447000602F02DD9DDCD03405CC72B6902902DAC3
+:10448000858B36CE6BF93EF45F02F3C3B8C634A613
+:10449000DC872864E232E2BFD8FD063D7E98E63133
+:1044A0003E5FFC98B1BE10FA2414E0778C766FACB6
+:1044B000BD5B5EE4E8CE5318D93D3E43222DEB8927
+:1044C000FFAEF8A49E6FA1E1635BA9588372676C8D
+:1044D000AAEA8BDE975A5AC4FD31BDDCB6E36F7F82
+:1044E0005E8AF4EEB129388CCA52AA31FE377B714C
+:1044F0008507C9A9D29EFF0AD6E7F8A12E23BD5B86
+:10450000E8BDEBA50F26A740FD4697B017CB79B2C3
+:104510007B4A2A948B8BB8BCB829A7622F5004AB76
+:1045200055A65B7DDC3FA944797616D68EF1E66D03
+:10453000E10383A3E5995E5680B03347F90B55F646
+:1045400038668E82CF6429C550BFC29569E83F5551
+:10455000761BDABF9333CAD05EABE41BDA9F28E246
+:10456000FBB74F157D547B0BACF3A932514210EED3
+:1045700047B838BBE1B2BFEC7C25D2F1EBA3BC1647
+:104580008C5BEBF35D5564D6F67FB91FB5A48BEE5B
+:104590003AE6E278EB37894477AF173DB87701D236
+:1045A0007126F7A7268B0E92EFEBBD9C2F1631DFFD
+:1045B0005E15CAF5CCBF17E5CFAC0A7B04FDB65833
+:1045C0003A9A817E9780740CF3C5F761BEC8B70B29
+:1045D000371AFB3D5534720F7EEFA9329B84F1BC34
+:1045E000593171F21998479384A5F1792C3DDE5326
+:1045F000A4F95F5ADECC5302F7BF026F71F9D89766
+:104600005CD2E93296FE9E28E2F138BD04FF2D19F6
+:10461000E5D058ABB19F5EBE037ACE0CE3BCDB6045
+:10462000A7F2BD0689CABF34B8A8FCA041A6F2C350
+:10463000861C2A9F28E271AEB47AC073D43E485AD1
+:10464000ADD77A293EEA96A7014D7E468E207CD3CF
+:10465000F6F3FD2D9DAFF438761AD6A3F2B5A6D5A4
+:10466000BFECAB06BF7E7F91169759B0690FEA4346
+:1046700098422011DE67CB76EFC1F85357FDD60F75
+:104680008CED77087B0DF566B7B17E77C5DEE8F770
+:10469000FB9A7F5AAD6CF1811E9DF1008F63C5B608
+:1046A000EBF37BBD51994DF117A72AE37E07737A8F
+:1046B000687DFB35B9D0175C66639E218C3BAD529B
+:1046C0009917BD6F795883FB610DAF3A9C99A2CAC7
+:1046D000D1F93DB1E3BDB368AC05E3303318DF5722
+:1046E00099B583A5CA63BBFB7DA48DFB4EB26F3227
+:1046F000E591311EAF3D342D63736B2FFB087AB902
+:104700007EF6BC2159305EA5375F40FA4A5B709552
+:1047100005F7CB0E4DFFC084E5D82C983F8C77DD94
+:104720004579C8F428387DAECDFFC04F8DF136BD38
+:104730001C54CCDBFF6CE279377F4EF20D996D781B
+:10474000DF4EED8712F9FB63CDCC2C1644D10D2E34
+:1047500000F4CC0DB54C45F97CDD4575C88CA8F747
+:10476000C562BEDE836BB9BD88F09917D53EA198AE
+:10477000E3478757ECFC261473FCEA7AF7D034162B
+:10478000E4FB794A23EAF919A0D7D0DE02F9437C89
+:104790007CE8A0A8D808AA5C0F2FC2FF05FA3A044B
+:1047A000FA10EDBB19F31C7ECC13043D3A04E1B5BD
+:1047B000A86E512DC66F98266FECF00FDA73F921B1
+:1047C000738C9C32CA95B47EE44C56B151EF4DCBFC
+:1047D000E2F4C572813EC774D3A78E9FBEE8E9009C
+:1047E000EEEB59BAD777565B5F5FF0D2E59404F6EB
+:1047F0008519F857D1E0CF4435B718F944CB671A7B
+:104800006B6171D1769DA2D1C1D80ABE8F3ED6C24E
+:10481000E5C5817DC30B6026EC40CDB9548C43EADD
+:10482000F8ECE2CFFA26DFB0A8F8DFFAA9B63AA48E
+:104830000399A989B8CE03DEC2B80A47379ED77B51
+:10484000CFA5B228B905CBB8243FED0F9B48EFEFB9
+:104850009FF839E9AB13399249C8EFCE0B995A9CAE
+:1048600042FD4E947EE81072510F1F7520FFCD66F9
+:10487000410BCAB3392C6441FABC9E85A97E231E24
+:10488000A188CA1FB989A9143F4B96BC54EEC74FE3
+:104890000FC4CF17CE0945D1699EB69F3A1653DE95
+:1048A000A3ECDD7B34B85516A97508DFB1A91D4707
+:1048B00050DFA54DB43094B32AD01DEEFBBC5E543E
+:1048C0001237BF177C8945F3E71547C9A7B45A9F2C
+:1048D00015FB3DA5ED9353E23A8C67CE1866900F19
+:1048E000CB343C1CF1A88B8A697FCCC9E539F3BA7B
+:1048F0002E05CFB1A95C4E609E3B8E9B96239B5AA2
+:10490000A3F47F4BB171DF77ACD56745BA5DA8F8EA
+:1049100069BFBD72637E5CB817392216F97E589C58
+:104920006E5C07B793B83EEC4BAEE97AEDEBEA4527
+:104930005DFFFDB648BD13D76F36F1FD44736A9D28
+:104940000BE1C7A459441FF7C4D06B2C3CF24A3F7B
+:10495000BCBB100DED5A93321CF095B74D7E0FFD88
+:10496000A9F581D912EEEFE9FDF7D71E7D6918F49C
+:10497000DBBF8D4902F45B5F5312877277BD233032
+:1049800014E1734250E27E88F6D5E3A2C4FDACC8C0
+:104990005CA4D745B5195988B7AB261475A850FF44
+:1049A000A8D65D8076E86BDABC3E661CBF012FF7A7
+:1049B000E74E4CBD73288EF37AD18002FC0E132F84
+:1049C0003C702BB47FBE514CC5F70E79165D7D0B44
+:1049D000941F3D26D27B1FD5B8292E3C593CE2209E
+:1049E0003F5CB3DBAED5E4DEEB4CDD83FEC20CCD29
+:1049F000FE6A9C70FB1EF4273F427F01E4E03573A2
+:104A000063F38A1401FDD6995EE3F3B48D1F1D4153
+:104A100026E82907B9DDD59F3CDC596CB4BB62E5BB
+:104A2000D9C70E1EF79FB183FDDC970C76728DDB24
+:104A3000721CFD907A81E843976B336A95DD683785
+:104A4000CCA899576887F525074B04F4EFAA6AE5C7
+:104A5000C90930DEB41AA118C7D3F136AD6615F90D
+:104A6000F7D336AEB2CA89C82FDEFD48A76693D702
+:104A70003B0EEDD48DF9AFE27B63027184EFABA600
+:104A80009D3521FCD76FB54A02C0677D706422E274
+:104A9000F9C063E79CD1F929DD7CD166C53CDDCA4C
+:104AA000C73E1D887CA1CB8F45C5A31EC6FDE24035
+:104AB00025CBF1131FBC3694FC85C1E02F80FCFA96
+:104AC0006EE9EEA168CFDE047E3EDACFA7861C3702
+:104AD000EF87EF86AAEC7E56CAEB791E3AEA15619B
+:104AE0002EA8677EB111F73F9A9A4020C018DBAC20
+:104AF000A1F7E779305FC9C436C3FB1322CCE017B6
+:104B00004CFAC26EF00B2A98D1CF58163EBA15C790
+:104B100093D6D8A4E4C1E89718FD8EC9923BC62F5E
+:104B200031FA1DA75EBDD08CEF0F37DB259CDF541B
+:104B300039DFD0FE9D9C32C3FBD359C44C7EB7CC29
+:104B4000F36BA62915C6F930C982F0B1A85224002A
+:104B5000ED57954E358C57F85A88F26CD2E07DCCE3
+:104B6000F3986EF71ADFAFFF1BD1C9F8FA0BA4F761
+:104B7000F243ED86F6C27DDB0CE3291D52159A89BE
+:104B800005879597B13C1FF75D17E6F7C902F3B3A8
+:104B900089C05A616F15E689149FF0BF8C65A0D259
+:104BA0004F79E10180179E8F7A30E1C794375E0F0D
+:104BB000EB473EBA5D64947771DEE45B8C7A4432F5
+:104BC000C98FCC13305F50CDC0F251936F68493A12
+:104BD0006E0FB65561EEFFF80BC1262CB77694AF79
+:104BE0001B87F146C4338CBBCC61223B77B2B82320
+:104BF0000FEDC2B34F261446E751E9F975CCA5BABB
+:104C0000E641FFB5CE61051817F25625AAB85FBE7A
+:104C1000FCF9919B31CFE55C59451E7E4FCFF36384
+:104C20004EE379927365EA00CCFF395021925D150D
+:104C3000986C21F9136F0A4A3C6F83511CD47A8512
+:104C400085F2A89F2DE1F2EAC0AB002298F881140A
+:104C50006E0F16776459A2F9628666074E29D1EC69
+:104C6000664D7F4D4F3FF824EEE33F5B9248CF8B7C
+:104C70006BE53D16A407C92CA13F9A76D82B8D81F0
+:104C8000F1B63A3DBBD14FD87AB86302CABF674B81
+:104C900064EA3FA0A6E2960A94D3396686FDB74A35
+:104CA000D509D83F6DAE628AC771F65982C3619E3D
+:104CB000AB27F0B8F4EA0AFBBFA35C4C3BCC089EE0
+:104CC0005BF1E024F2F5343BC58F9859715F3F06E4
+:104CD000F3C901E797883B1E6B4B4F47F932BD4242
+:104CE0004A57B0FC3791DB07948903E363EE1FE674
+:104CF00088B067DFAD86F62D5D751662006FC9CA94
+:104D0000F4FE2C0EEAD385AEFE73AAD19EC8EA6AE1
+:104D10000F20DFAF17F4FA73D49E16335EF7F8CF87
+:104D2000BD7B82E4BD941E7D0E4D2F9F2D61A4C7D7
+:104D30001798FCC5488F1F99FC23A814642ADF1B11
+:104D4000EE5B5582768323B2FB22C0EB9337443A65
+:104D50004771D985AB280F1AF4F6131B90FEAA2DC4
+:104D6000249FB75AFD7F7BC789FBC4F1949F64F9E8
+:104D7000C5D2C843809AAD66FFFB3F407CD58E50BC
+:104D80001AE1F90289F3A1AEF717895DEB53C1B4BB
+:104D9000668BBAD7A3223F7E64EA6EC773B952D43A
+:104DA0007AED509FAFD70307E71C0378C80BB6E432
+:104DB00060BCEE1C73501EEEB99C2BAF417C9F6B08
+:104DC000B3501ED656C6F11C70C5071F0758EEEF2C
+:104DD00030A9C8470167FCA6E154DF2C65C138ED56
+:104DE00080771516961D507F8279E2E73A4C26DCD3
+:104DF0007F3D573EA08AC6BB83E11E2D5B10B632B5
+:104E000019D6539CB340CC8AF60FF17DA01B719C40
+:104E1000FA6009E5F1E8F1CD1F7EBDF8A6396225FB
+:104E20003ECB667ECC135959DA988B7A7665B5F00D
+:104E3000810DCBFACF489E596DC1E01AA4FF17E34C
+:104E4000781CD7A10E9D1E65E7E594717E9B3052BC
+:104E5000CD29C37CB2FA7384073D8FFF94965F021D
+:104E600060A27312CBFE4BBC11FD44903BEB84025D
+:104E70002C5FB2AE8E5A1F6BFFB44B7E8E35F56F32
+:104E8000C7C5FB6A699ED305E96A067686F4C2F057
+:104E9000B9985F353D4EBA1AE33547B6A5F0FA101A
+:104EA000E96ACCB73A5FB2722EE6574DCF94FECD89
+:104EB00004F233B36C1D6F774B6F615D2A5DC7DB06
+:104EC000F3A5B7703FD65CB6666EF540B21BE8BC82
+:104ED000E8D99A38F203FB9ACFCCFA170DF1921E5B
+:104EE000EDA2C0E5681D974FA7A766929CD3F35A21
+:104EF000969B24CA6B39A4C9BDEEBC1626615ECB55
+:104F0000E9BF762C3451BEB73219F35B96F91C1405
+:104F1000F79F59BF8BBE7BC0240F41399A58EE7B57
+:104F20000FF96CB929FC3EF2DD9BB56F66903C969B
+:104F300022C3102F93C5B90192F35ADEAA25E56763
+:104F40001654FAD780DD86F1B3158A4C7ECB4C24FB
+:104F50009CEC9E72FCB20B9D7BD7C3F76F7D41909A
+:104F6000907EDB1B40EF012B3C037E2396EAB6DDEF
+:104F700087316F64764C9EF9ACBA98385CEDA5F336
+:104F8000CB553DEF3BE69CF3B523D58D486FB399E8
+:104F90008FE6D9E33B8E61B49F10FBBD992C44FE94
+:104FA000577FDF3D93D87103F006B368F85C9EEA43
+:104FB0001EAEC1D55E8AFA4890C760DDE2ECC8E05B
+:104FC000FEC69332C133C74EFB96F1A30FE7F97AC1
+:104FD000A1DB5838DD5EC6E5E50073D8AAC0382BE2
+:104FE00034BD31595C268EC1F1B6B959B45D9955BD
+:104FF000CAFDA4E46D3C2EE5CC06BA71227D84EE98
+:10500000A0BCA75C4E2FCB4DA1C1484759A589D460
+:105010005FA74BC0BF961F06EDF9981F047404FDEF
+:1050200027DDF49AD2144547EFA31C87756E8DE7F0
+:10503000722DF25C1C9D8F8F9D6769A9A0C51F8D85
+:10504000F32DD19E7FD579969472FDFC4DE7A9CBC7
+:105050001D1D4EBADC619A5C9E5DE7A6BC44BD3E58
+:10506000A3D64D7EAD3ECF9EF4F398DC1BFDF447F6
+:1050700037BF2C9178DC52937FFABC7439B655CB8C
+:10508000D3EF9E57CA26E3BC52481E24D7BF4072B6
+:105090004D4C34D3F35939AE4DB84F94DC7196EC86
+:1050A000D16499AD423DB1B0348BC3B9FDCB9634D8
+:1050B0000F3EB70828B792EB77D0FBDF96FF7E89CB
+:1050C0007650514FBD30010418C969D43902DAFD58
+:1050D0003E839D5B81274CA2C6ADB2AF8AD97FF8D3
+:1050E00081A1FF15AE4643FB54F9AE18BBFE3E430B
+:1050F0007D9AF290A1FF55A59B0CEDD3ED5B0CF5CD
+:10510000F27007D9D5FB1B6AC88F9F782242F675CB
+:1051100048F3F75FD2FCFD57D0DF07BEDC8BFE3EC5
+:1051200094FB1A147AFEC786522A5F6B50A9EC686A
+:10513000F05219CBCF9E8EB007F3954A9DC994DFEC
+:105140005F59EC7B06E545D9C1C83094AFE38F04C5
+:105150009BD0EE5FBBBBCC64C538C86B62300EED34
+:10516000E6F292E4DECE21E865F2172253A3E25D77
+:10517000C9B511A63AE83C2FC587A63B8E5553BE4C
+:1051800062BD2424834CB19915E681FA509FB42A5C
+:105190005086FB583C0EE6551BC9DFB906BAE2FE45
+:1051A0004B9D1DEC3B986FDD6221D844F1CD00B5DD
+:1051B000CFB1EBE779F8F9C0AB3512AD63DE3D94C2
+:1051C00023EB67CADD30EE33FB52ABF3918EBD4269
+:1051D00010EDFFBA3B03CBE7D138FAF9C03F9B2E65
+:1051E0005EFED5ED926D608B223DAF15148A5B0497
+:1051F00052CC6477C4DA01F7941AE3EB57A11D90FF
+:1052000086FBC7DCAE89B8997F734A37FF4D97009C
+:105210003E68AFD7CB2684CF32D62826A1FFD32134
+:105220002B4D40E265C7222D69D05E846A4FEAF6B5
+:10523000EBC69D884CC19069B16A8FA0BFACD33FCB
+:10524000F8492FE3FB678F30C506EFC74FBC4B44CF
+:10525000BFAAEC33EE5F4DBAD02EA2FCEFCF1FD425
+:10526000E7BFA3A18EE86757838FCA50C3628D2E14
+:10527000FD547FA5A19EEA7B1B0254EE6B58A7D17B
+:10528000651BB5BFD6B081EAFB1B821A7D6EA1E714
+:10529000BFD4E4E35F4AB5F395F60A8A7B32332F35
+:1052A0004DF6402C3DB0687A58E6E2F2383E95F76C
+:1052B0008B077D10F80A7401029CE8620ED005CAC3
+:1052C000B7D9ED4D63D04E670B0245FC1CF337A3F5
+:1052D0008FAFABEFC14E52900FC08EF1A39EF9AAD3
+:1052E000F2DB86C4ECC473230E82C3D7FDAED5A611
+:1052F00050FCB7FFEF71FC9812E652DEFD72133FCF
+:10530000CF73BAC82B211FE97E740FB8C4D86303CA
+:105310000A98A6C7BE367C2C888FFEE6F95E993ABD
+:105320001CEDAD2EFDC68232CED77AB99DB5521C8A
+:10533000F0C2EE8B681F77588268FFACD8FE4EAF84
+:10534000F68FCE8FB17273A5748EF8EA9460EAF589
+:105350001CDF4A13F3617E4D818DD98554C61E2D05
+:10536000AB2CC1F94C16CB3B54E443C9AC44DB49EC
+:105370003DDEAFFF94C6EFB3DDC4F37856EE2C925A
+:10538000A2CF23DD5EA6ED637CC3FB252644EA0C99
+:10539000FCFF4FA727D55F1BDA190B7B90EEAF738D
+:1053A00072F97F956F2AE16B366B277A9ECB3AA80C
+:1053B000BC8145A8F4317E3E683E53A85CC0F87EAF
+:1053C000C6118F6F7919C63BAD5E8AEB5CF5FC495F
+:1053D00007EA3F31E5E099F5ACA7BCFBAAF24D978F
+:1053E0006BBA9C6BB16AE7FB53ACC43F96F454B202
+:1053F00093747C349419F5442CDF74E673FFA6F3A0
+:10540000B9F126BC47AAF3753128707BEC15CAABFD
+:105410002AE0E74F0BE7F2FB97E0CF3F9CF26D8C61
+:10542000FEC8B9F26B49FF9EC3842D948F6625E7B1
+:10543000FA283FB949DBE7DC02E5D330DFA4B961E4
+:1054400073F43D530F697E74C5EC6A867ACE3C577F
+:1054500065B85F9524F1B8D6643BF3C4D1FEE7B9D3
+:105460005C1CF7BB9A3DD06A6121E48701A5F90273
+:10547000DA0FE017FD1CF9A2EB7C3DF8B2172FEB19
+:10548000592F1079BE61642AB7EB63E9F837DA7CEB
+:1054900096697CC17C7221C2B753900B34BB80E407
+:1054A000E3CA2B47911DFD52997E3E21A0F903E5E9
+:1054B0006B1FE6FEA51FF3834EC5F57E3EF7F9325E
+:1054C000BE8F36D3FE99C17E5F51FFA5815F57E441
+:1054D00072381434C98598FF758BB60FF77981F748
+:1054E000055CEF92FF78D23A48C6EF6EBC0DCF83D1
+:1054F0009DDDE720BDCC5E4BA735EBF72AE8E3CD79
+:10550000B47FCAFD0CED5C87FEFCCD696F93DC4275
+:10551000FFFA450FFA798CF2EFF5F91D30751C7F13
+:10552000D8DD2DC7C04F7CFF476E945BEE9FE03DFA
+:105530006891E72C14A75A86F34F437FD1BBBF8CE9
+:10554000FC0146F18303578E243F44B7673A3FEE90
+:105550007D7F5C9F9FFE1D7D5EA704C100C77735E0
+:105560003C959471B97C3A49B91EBF73FAF9412848
+:10557000FABB9EBF99D29187E722BEAABEFFBA7638
+:105580006085F3E5243CBF3D6B8140E709EA1605E1
+:10559000C64814CFFD667AFEABDECF02C674D00AD1
+:1055A000FD05C7A1977DCEEEFB204CC83C30BF72F5
+:1055B0009795EC0F1B8E27623A64D085A57E0F84E9
+:1055C0007EFF837EEEE50F42B889CE3BA88A0BFDB5
+:1055D000B7B5CE4AF2EB4F30871FE3DC57A7D44C68
+:1055E00080CFB3D90BA7FA901F663525D1FE8DD990
+:1055F000AA9877A3FD7D25DF4F7B66DF1AB243DFD4
+:1056000052F9BE810E3F3DFFD19C129842F6FA75C9
+:10561000809241B8CFA0503EE635004FECFFB6D99E
+:105620009F9EEBC6FDA907F2F09CF7123198340655
+:10563000D6F1C981DF14BF0EAF9D6421AB03F34BDC
+:105640005F09D37D032BBFE6BEF3F7301354C43C90
+:1056500085B64776C3B8EF64FCFCFBBB59371CEA40
+:10566000D45FFC7501D496A63417E3F8FA7ED2F91C
+:10567000B8EF66EC8EDAAFE86F7FE251932F6F5C84
+:1056800011DE9FE02FE1F714F0FB6B805386E23EC2
+:10569000D278180AEFEDEB4CE77418F89411FC3A45
+:1056A0002D0AE9F5C0E732D9FF9E2A13E1935D94F4
+:1056B00029BE3A3EE6FE05CFE5267A9FFD5DA6F7B8
+:1056C00027448C79149EB1F78BF4BE28B3C7319E62
+:1056D000F085F992F6CEE9719CAF3C69267FB4BFA4
+:1056E000DEE4CAE0F13AAD6E9325F2DFBFA7F767BB
+:1056F0009133B213EF6570F8715DF037CB5E4CEB10
+:10570000247A1DBFE324DD73B35104BA405F87B52B
+:1057100057E138E58077CCCB14543FBF97AE9E312C
+:10572000DCAF8ABDB741CF078E53593BF265ABD092
+:1057300021225C2782D988A5CA24D267954CA1B2C0
+:105740009A79A99CC2FC54D6B0362AAF64ED54D6DF
+:10575000B20EDEDF9510C07367E3989DE2F1E57647
+:105760004529A0EFDD21513EC9D445268C2F7BAEC3
+:10577000E5794BFDC1E34E0D1E2E8487E79BC303E5
+:10578000D78BFBAE53B4FBCBFE51F0B8820588EF4C
+:10579000A7B22095DF61211EE764F22B98E73CED6C
+:1057A0000423B9C14687481E94867D66AE1762E021
+:1057B00051A5D315638FA790DEDBC0CF8F0D48B105
+:1057C00079901F92E83CF7D657D337A15DFCC238D9
+:1057D000AE278B59CE83E5D05EB4CF0296349EA31C
+:1057E0005729DFE66CD4B92C90586CDC8260931D8D
+:1057F000EA99EBF8FEBFCD65627214DDC6C9F14CC3
+:105800008EB2E71272520DF512166C2AC77804F8A0
+:10581000AF21500589CA40C3FBC9A55986FEDB5993
+:10582000BB48F250CBFFD5E56C8A3ADAF01E5862DD
+:10583000E272C4B7964F9C5653606CFF8CF35729A5
+:10584000FC83781A77CAC86FA5613FDDA315E7030B
+:10585000B90AF38A3B68369C6FB3398E1FC173FC5B
+:10586000B67EF6F7E78CD7F6F707B3C15C6FB45195
+:105870009E758BC0F5962EF75B85362A3D0995E718
+:1058800064F8DE5BDBE75F8F717E4F61E52DD950F9
+:105890000F6F5FCEEBE32B9FCD82FAD1EDFEEB7164
+:1058A0005FC033B6B2D002EB6B6C5C757D35B4670C
+:1058B000CB8A0BEF6338ABDDC7D0F4C68FE97E012E
+:1058C000B0C12401DACF3A6E5324C4DF60878274FA
+:1058D00063B7011F79683BD2DF5886268B9FFA0396
+:1058E0006348189749ADE1F7110C65FC1E81ED0D79
+:1058F0008CCE236C1A2F13FF140C08BD648171D257
+:105900004F0466E3FECC9D05DEC3E3707F558671D0
+:1059100060DC87257E8FC1A6F19A7FEFBCEF659F83
+:1059200007ED3B4678F9B0C0FB1ECADFCE447B00D2
+:105930000314FAB85B347BB4CCDC26DEE2C0E78C1F
+:10594000E8B2AFD2315EFD2B7E37F63953253AAF40
+:10595000D0A4F3E76289CEFBB397383F769D4340EE
+:10596000BB13F8AB6C812A0299B3E23AFFCB58AE75
+:1059700014230B112F9F8FF39DC3792EF79E199A35
+:105980008F76F95FADFCB23A3698F31BE37279E596
+:10599000AE2FCFE07D203B4D202FB83DEE6551F27C
+:1059A00064E5AE3833D2D5CA4F5830C18DF2E5D751
+:1059B0004D68C797817C61FCFE8397D1AEDB710B8C
+:1059C000BFDF6AE5EF77BE8CFB28E5DF89A37C8823
+:1059D000096F1EC9463F65D29130C5E93A77BE3D91
+:1059E00088F3BDBECF765EF82676CC64F18E7B5010
+:1059F0002EAC6E34333C57BA5AF0F3BAC52EF1735D
+:105A0000A51D2D73D19E063EA5731C5A1EE1626D25
+:105A10005D30CEDE32E87F1AF90DDB83DC5F97E183
+:105A20001F9283E2053A2FFAB9C64F258763F55BCB
+:105A3000642FE6E32CD3EEFF88BDD767653FF9F40A
+:105A400023743E1BC2867CC37B3FC68C4FEFBEF7E0
+:105A500063B2E820B9B8FA91ECCDB89FB6FA915B81
+:105A6000886F560FC92D40BED1EF0161216934F610
+:105A70007B4AE0FB94EC81938C617EA536B725EBE5
+:105A80000426639C3C5B64A5E0076D7AE2FC7CCA5B
+:105A900087429B10ECC0A6B5FF87EAC880B6717438
+:105AA0009E83ECE7A7522259346E8ACC0240B74D50
+:105AB00071912CD423819D7685CEB76C4C239ACDE1
+:105AC0000E281BD0BE59DDE81490DFAF1BCFE5B721
+:105AD000FB702997F360E7203E56278EA0FBBBFAA8
+:105AE000A20B0FCE33CABFD9FDC6350968FF3F6789
+:105AF000F626607EDBD98359978CFF168560419727
+:105B0000885F780EDEDD81F9509E0D66824737DDB5
+:105B100019F39DBAF5118FD314B361063D74165F66
+:105B200025F9C582E83F749F8B003D82F61AD2A703
+:105B300082F7071BF5D0803AA31ECAF419F5D0A04E
+:105B4000C546BD33C46FD43B97D51BF58B3B60D4A2
+:105B500027D9EBC619FA0F6FAB34D4476EB8D2D041
+:105B60007F547086A17EF996EB0CFDC7B4CF37B495
+:105B70008FDD76B3A11DAFCD42386C0F33F673A421
+:105B800087187D981F5A6DEC2F1E217DF8B976CEAF
+:105B9000BB70DF0F7BD58701F8A7377DD814F7637B
+:105BA000D287E1790EBF308EF46308E5789C767E6B
+:105BB000A6877EEC472F6E1CAFDDD3A9E9C5CFC108
+:105BC000B343B916AB0F63F9B42FFA32255CB86151
+:105BD00005CA2791DF3F02F2FA2394D72B4DE1A1AA
+:105BE00085F06C4DC2FB561FE7EBB5B91E6D5F1912
+:105BF000E0E075B8F6A01D2F55DA23B652A4BFA178
+:105C0000E4E778B3991FF3D1CEC7E55990EFE446A6
+:105C1000214297DAC4F87B82A3FE57C8671B9B001A
+:105C20000E83315E653CD732B3C678AEA5BF787BB4
+:105C30005147C850CF3FC84494F345C7E4A644F841
+:105C40005EE1119E2715EB677AC2BE26DC2F1A7F14
+:105C5000AAE3E500CCB744BB1FB134A2C7FBFDBF2C
+:105C60004039311EE401DDB7E6EB24396595F8FBD8
+:105C7000C0773968C7D6B37805F9EE7691FBADE702
+:105C80004D3EF24763FDD3A60A2FD9A560B70F4654
+:105C9000BB7477BEEFF0F8743E19A41351BB7F7448
+:105CA00012FAAB042C7E0F66A710198A790F26F61C
+:105CB000E9F53598DFE26452B818E374FCEFA8C048
+:105CC000E376672A06593D72377ECF8C573F1C0F0B
+:105CD000F8FC50D3EB03E6B6D3BD0ED78E548F8DB0
+:105CE0004FEF3F0F23369EBBB521446542AE22A243
+:105CF0007E888D3F9DC4C994D1B849246FECACC354
+:105D000046F75618EFA30C9B3AD6E27E5A6075927E
+:105D100082E7122B9CD9749FC5DC7A1E6758EA3A39
+:105D200045F18AF98242FE2C53B91E112FE3F793F5
+:105D300074C71F06895F476FF7B7DEA5AE8F0DF1F9
+:105D40002AF624D7177D8F1FE0F7D475AFFBD15B00
+:105D5000399F503EECD1A9832AD1DEEDF99D331451
+:105D600007BBDEFF8681AE6FAC7FC740C7F3021F63
+:105D700018DAC3CE886510D045F8F9CC2973008EA7
+:105D8000A79FB3D1B9BB33E37D7279543C343C75E2
+:105D900054357EB7FFF59EA4791C69E820BCEAEB78
+:105DA0007DBFE130D5C30D612A63D7ABC70DF4D2F7
+:105DB000FA12BFF736027610DED7D45FFCE0C5F2E8
+:105DC0002CA2C7DB45F57DEE9F858660FEEAF916BD
+:105DD0002670FF3042F7E0CE159214F42F5B32F7B5
+:105DE000BE877185B74CC92487D9E2D07B98AFB8FC
+:105DF000B295DBC34C0D3D82FE5D675212D59FC943
+:105E0000F75597235FE56AFDD24CDCBE728686D0DB
+:105E10003D5CE9780718DE2FEBBD82FAE14D6D306D
+:105E2000FEE254F04F53F0FED8401EF2DBCFCABF63
+:105E30007303FA0B27E20367300FE99E1D53781DA9
+:105E4000F3F028AF6CD2A321B423D530DD93F396C1
+:105E50004924FBBBCDC2F75F232F089B300ECB1C20
+:105E6000612BDEC3B276943A13BFD7D77DB0379497
+:105E700073FBE8C672BE3FA197CBED3C1E74FFC614
+:105E8000ACE9C80FFA7D2D092CA20EC2BC9E6DBBD9
+:105E900019D2C18FCB399F4F16EF1E41E7A56B6D0D
+:105EA000745F1DCC4B253B68978DE228DDF7E03011
+:105EB00009EFC17166CBE7901F9D22A33C8C55E58D
+:105EC0006E9E5FA2C5475998C7394F4FCD24FF1921
+:105ED000F3BE28EFFF20CFEB3C3D95C78B1112B8E6
+:105EE000FF3DE3797E5FEEAA721E2F58FEEAD1F7DE
+:105EF00071FE89E5BEEF239DEA7936CB58C771293B
+:105F0000BB1B6E36913563DCBB3FBAD5E3A87AFD87
+:105F1000CD6977D2EF3F14601E562FF6DA83E5DCA9
+:105F2000BE3B626131795AFABCF53C2D7EFFD0331D
+:105F30001ADC1F2BE770DE63956F31717829E8EF6B
+:105F400039B3FD418487338DDF3FD717DC4F7FAFF7
+:105F5000E36718EF3B93280F473AD7D70D70B8BDCA
+:105F60003C2A3EAEC3411F479F27DED788FB0A0568
+:105F7000FFF19A65008CBBE4B73CDF5F5F973ECFD3
+:105F8000CF0BD447CBA3E2DD405FFC3E85A97184F3
+:105F9000EFE5BBDE791FCFBB2FF9D5984294FFFA0E
+:105FA0007BB1F38579529ED9015388E28930CFDFE6
+:105FB00022BE9ED97780F2A1F4F97E53FCE8F74621
+:105FC000776EFA01BFC72D13FC6B80F7F21D7FA01F
+:105FD000DFBD58AEE785C5DC131DAB6724E69B83A8
+:105FE0007E918D71F960D3DF1B6C36BC9797A5EE5F
+:105FF0002EA7FD0B26A39EB699B5F88FA68F8A34DF
+:10600000FD291CBEA669B927EADEE1D1A0BF795CF3
+:1060100093E669B7737FBC4B8F0B8A4CED3EF195CD
+:10602000B330AEF826D7DB25E8A188A80A7CA4BF48
+:106030006DE22A859F57D7E24B77ED253F13F90490
+:10604000ED8821DAF71F4D38F37408CA2CAF528956
+:106050006278589DF7250BB5046992BF98F737779A
+:106060000BD42A02FCDCDAE03BE20DEBD043756B8B
+:106070001286BE847EF466CD0FCE4A5866425135F4
+:106080007241600D96A396290317C9DDE366AF2E12
+:106090001D3D0FC76DB399507E5954EEC7ADEBBA95
+:1060A000FFD86FA7FBC335FE19649FF82737EB1B9A
+:1060B000EF7735B80E5547D99BF1E620FD6E81FE8E
+:1060C000BDF8FAC187F01CE8A0FA11545AAAB97FAA
+:1060D000B926E1C7FBDCB0AEC4D7D2F3F11CB5FEE4
+:1060E0007EE204E37936C0FCA10551FBB58CB90E04
+:1060F0002D88D2EFE08D19EACC93D3DD9FE28A8A16
+:10610000B19D95C68CA7C6D4831A91D4C4BCE7357B
+:10611000D42D35C675585E4BCB8FE6536831EC579E
+:10612000FEB421E75075945E4D32870D704AAACFB8
+:106130003D548DBF03515F4C25CD0CF09CA2E1393D
+:10614000A556FD18FDC214B06F8E46F90B2CBA2E61
+:10615000F252CEA06B7CC90E8DEF6E5731BEDE17AA
+:106160001EBF6AF9D306B071A2F09DC6A6137DFECC
+:10617000C4C7FC8D201777E76EB6A39CF86983FA35
+:1061800026FE4E4D6B6E01F9C389E60E86F9EF4986
+:106190001E786EF0CF82063859D4591DB87E2BABCD
+:1061A000B3237D6666CCB7A33F2E03D963BDC53943
+:1061B00083EECFD4CFEFC5CE6F2DCC2F14958F6F3C
+:1061C000D1E319684C9675C3957E2F02FFBD7051BF
+:1061D000443FC5A6E7EE69F0B3EAEDDA3D6109E5B3
+:1061E0004F046EE2712ABFCD85F52D01B473EC6EBC
+:1061F00033D5AD0BB6857E099F7055D9FD266AE76C
+:10620000E79AE27301FE467F8FEA343FC49FAB0BEF
+:106210003F7F8AFEDD9FFFEEB205F17889DFC36A1A
+:10622000B17A17A35E6DC92C16A2F3283227542E1B
+:106230009F80FCA19D17ECEBFDAE7D3FE6CEE4F721
+:106240009870B853484C86B2660AD1B3C4A2E0D362
+:10625000073D635CF0BF8B9E5B63E070BF45CE443F
+:10626000BEBCBF51E8753FF79609FABD9B7C7D9790
+:106270006F64740ED2D26C0ABA05F4A96513D27F8A
+:10628000A635D086F1FEB57799D81A9975C51DC681
+:106290006AEB1FEB5CC8CF0D33F94AFC2912CB41E6
+:1062A00091EEFF1216BA06E2FB96E6E34778BB973B
+:1062B000A1DE73E3FD7160E7E66D35B150947F8038
+:1062C000F7C247D74B0EA71AEA55F6412C64C83BD4
+:1062D000C936B44FFA62B4A17DB25468A84F888C15
+:1062E00033F4B7B1943539B0AECFB5F8665F7CC83A
+:1062F0007658E93D502F2487DDC0D1A1283CE73EE8
+:1063000069358C6B8969D7E3917DE12D364EB27B7F
+:1063100082F17C60D73D217DD069EC3D21A0D82B56
+:10632000374257ABD3447A3D336306C9ADAA1A2F1F
+:10633000C37379B1F8C39D539447419437B66E380F
+:106340005802AC12DFB33673BA70C378AA9BC74940
+:10635000911E5AD6318ADFE9722CD3EA75A1DDA7E6
+:10636000D383B0B0CE85F85F12140D78B0317705C5
+:10637000FA359FE37975857F1FE9C2A2D185C5658E
+:10638000A2BCDE58F8EBE7D163E1EB5E67358C9F8A
+:10639000FA2DE1FFE9B784BF5565BB9309FE4C4672
+:1063A000BB74F2C20D943F631DA6109C6A50F66246
+:1063B000FB3046F1CE58BA033C84A2ED10AB868781
+:1063C000C9E24695E0DECCD8001951D7C6F5C8B071
+:1063D0001964E7B0601B9D775E0BF8C0F9AE95DAE3
+:1063E000EAE6C377D61EB62901E87F97BBCD85F2D2
+:1063F000E0AE4D02F96BC2C20DF310AF77A567B8DE
+:10640000F93D026CA089EEE50EC59968DF3310C72F
+:10641000EB013BAF87CC581F19834F6837637BD69E
+:106420008678031FE0B1267C9E5A6BE463DBC42CA4
+:10643000DD78A5F1A4EA8131E3F909D4D2417E0ED9
+:106440000BC07A2017E4E6088D5EA5610B2B917EC8
+:10645000F6678A4CA0793101FD6D9D7ED8064E2FDE
+:106460007A5C53A7A71E741330F2ADCE17FA776487
+:10647000763FC147765AE5A01BE57B547FEE775502
+:10648000A25F2F69FB8DC2C27A9AF7DAB744C22B9A
+:1064900074A9C07637D07948EA39CF16D52B91DD6B
+:1064A0001433DF58FAEA6FDE3DE6F535E9FDAA89D7
+:1064B000DF8EDE9B125B6CD8BF5EB34F9AF03E540A
+:1064C000DCFFC0FB50C1FEC1B4551CA7498B13D0E3
+:1064D0001FF107DF97678E59DA797DC984FB34F79E
+:1064E0004EF85B18ED914D6B5D644FDF3B71E0E85A
+:1064F00079F41EB743F5FB36647C94CD7ADCBF811A
+:10650000E3209F40BB8AF1533788AF89E097BB17E0
+:10651000AC5B2546C5B3E461B2D006E3A65E18299C
+:10652000A0DC4AAD61261F95CA25E1D7D6C0DAABFB
+:106530002F616F48DAEFB5C53EFFC9443BCD5F6AB6
+:1065400066BDDEDF72DF44AE8F6DDA7D163A5C80A9
+:10655000745EB115F4669768F0C024C132DC0F8711
+:106560007945F151CFFE1C5F3ABCE2F011E03B6D82
+:10657000189F8F1C902AE81E1AA744707737FB18C3
+:10658000C23D45BB172676BCC7B5F5A434F33CB86D
+:10659000D8F6DFF6B19E145C4F2FF7A4FDE3D7C306
+:1065A000045A8F4B5F8F97D6936A9605E4BB546667
+:1065B000E7F302FD13BD3F981AE81D3F2B27723FFA
+:1065C000D266D6EC706D3D69B54AF2BC5ED61FBB93
+:1065D0001E8B0BD663EF7F3DFDF90BF6AFEB2FC89B
+:1065E0009E7EEE45E27E419BE6E774D1F11DFC7D87
+:1065F000C9CC848C2878FC7DA2C8F1AE427F83BCD4
+:10660000E77631E1C18D65AC7F07636568BFDBCAA2
+:10661000B0ECD98EFE8A59E36373B73DFD0FB18F9D
+:10662000BF6AD9DC60F40B7BB45B95C5DA39AEC1C7
+:1066300099C59467C085CD633C1F2CB59CCB35CBE9
+:106640002493F6FB605ECB2428131C21FA7D3029AD
+:1066500060C40BFCF95C48BF42EC3832E565C60DFE
+:10666000E3F2324191E93CBB8E2FBF433D34B10888
+:106670007F4724A511E3D50057FF7DB81FE16A537A
+:10668000AB500F69FB5DF867D6E10AE3AF75A9ACC3
+:10669000CA4379C1113A4F9A735B00FB4B2646FB04
+:1066A0006196DCD446D4530CF45432D51F50B39DBC
+:1066B0007CBF8CFF9EAEE6776A784C28BF8D656301
+:1066C0007F95EFA7B16AB5A38B6F419FC5973E1F1A
+:1066D000C2DF936332F72F6DC36A3AA2F93ABE94D0
+:1066E000FB9BF60A3BF73FD9D3A197E17B2DDAFD5F
+:1066F0004466A7D7D8DF05FE565E4F7F54A71F8B91
+:10670000467F172F72FA22BC619C03E43FFD3EAD29
+:10671000F31FEBA7C6D20B93B9DE6466F592F7CFF1
+:10672000801DBD06E3DAF7E498E8FCEE3D39058705
+:10673000717FF5A7B926C2DA4F3D9BD721DE3FCF47
+:1067400031910E6D4A3CBE2E0BF156CA7F9E35210B
+:10675000460EE0FE77B41D85FBDFD176C23DA53342
+:106760002EA9D7327DC6F7072D36BE9F5CE3BB1638
+:10677000E97888DF68CF5D566FB4DF1EA951EBB0B2
+:10678000DF4F720B7AFDDEFC1A75EEA4225C1F9FB0
+:106790000FCBEDDDCE784093673F6BB053D9DFFC74
+:1067A0003768FD7FAEF5DFD82051F968838B4A1D2D
+:1067B000EEC0BFC9F3017663FB90A309F5FFF16654
+:1067C0007554FC3741D75F3B747E5573A6F78A57E3
+:1067D000CE97E593BC4C253F6CDF9B5D747B89F3C2
+:1067E00019FF2AFF55FEABFC57195BFE5F5FF1B145
+:1067F00031008000000000001F8B08000000000036
+:10680000000BC57C0D7854D5B5E89A3367CECCE43F
+:106810006F4E420293887A2609219040070C187B1C
+:10682000839C4CFE2614BD0345A4DAF71C1069B402
+:10683000F635D77EF5C5D7F666F2FB420409142A71
+:1068400022DA49088A26DAD1AAD5EFA3BD03484B3C
+:106850005BDAC6162D6DFDEE45F4F9F5DDEBFB9A1E
+:10686000AB786B7BF1F2D65AFB9CCC99933FC4EF8B
+:10687000BB77FAD5C33A7B9FBDD75EFF6BEDBD53A7
+:1068800076E19EE3CFE603EC4C4AF1FE0040D7B13F
+:10689000F733A0129F2BDEFF5905BE4F9C710641B6
+:1068A00003B844BFD5939F0FB50324DDD82FB9DEBD
+:1068B00017CD9ABE5F3FF55B9882FB16299BE2D805
+:1068C0001F2E22BC12DBF19F50926A9FA73B0056FD
+:1068D00060BF25D8AF32D5EF41EAE74CCDB7003CD9
+:1068E0009991ECC9F365964B902C07FE5D82CBC75E
+:1068F000CFEC97902153B5F4CFB8F41A4410CED60C
+:10690000149DF181C4F8B5489F8C2A5523BAA5DEA1
+:106910004725A8C2F9ABF2E2FD8ED4F7892A294CAB
+:10692000ED76BCBE77F4BC0E38CE87D56AAE13C701
+:10693000B95A9778DD39007A02FBBF9ABD2DF4046D
+:10694000F1A12A6FD08DEDBEEAF4EFB752FF0280BD
+:10695000B27B3FBBA904E7FDDE1927F4CFC02F00AF
+:10696000FCDE637C4F743CBADE47FCBEDCFEB8E262
+:10697000D4FC0CE7D9E0225BFF625BFB625BFB723D
+:106980001BFC595BFF900D5E63EBBFDE06DF66EB21
+:10699000BFC5D67E8FADFD3E1BFCBFD2FA97C9B7EF
+:1069A000FBA6922FBBDC98FD32E438042B894AC841
+:1069B0003F8BFCD8F97EDFAADA569DF876B1DFBFAF
+:1069C00005F99638ED0A920E741D13FC80A3C8F4E5
+:1069D000429890FB0CFA90F183B1AD167C8F05566E
+:1069E000CE3B37835CA33C9EDD9AB6FE38CB174086
+:1069F000CB59EB3819069FF93B94B3BA583474104D
+:106A00005150F2A538C95DE15C9433C4F3C3180E4C
+:106A1000E020AE460C7CF49B0B113F167D0D40C66A
+:106A200036B801E019832E6E58E78B2CC1715E18C1
+:106A30000B5127C7B64DB14C1CB7F715D471ECDA22
+:106A4000E8CCEADC8C704FB55B75AB388F12F16423
+:106A5000E33CBDDB65E874D090A7B9DD7F9513DC1E
+:106A6000D5F84142613C3DF8BF4BC5004B5F50D269
+:106A7000E85A0C163840DF2B297E0688865F9CD1A9
+:106A80000EB4BDB939FEAA2735DE137A76FEBB995E
+:106A9000F88FEBA0EA5249EA7B50057FECDFFFB9A3
+:106AA0003D1A7F7501766B06D64B258C4FA623C405
+:106AB000DDB89E866D6DFC69EE1927C3C81F5D4663
+:106AC000B8F8B4D0DB4667E5311FAE7FB71F346A34
+:106AD0000FFBA370AE3245676369106F87643DCECC
+:106AE000B33BA2E5A9D8AEC4C0A4AFEE21FAF60824
+:106AF000FA02F289E8EFF2BFFB262C65FA4292E82F
+:106B0000BB39ABB513E95DEEDFB6968C0DC40DBA9B
+:106B100039C041740DC42C749B82AE2E1B6CD2C53F
+:106B2000E4FF6C747DCDA4EB1CB8EE4AE8DA11509A
+:106B300098AEBD0B045DDDB03BB699EDA85BED0FE3
+:106B4000229D9D592CAFBD9560D059CF299CCB7605
+:106B500095E5B4CF35A6CBD8DEE380F14EECDF0B64
+:106B600063CC87CC5ACF780CE9E285F7F4CD552970
+:106B7000B9CBAE4E97339F9E4E9F4C9B9C793F2541
+:106B80007D3E34E9733D5CCF7AFB09E9E331E6F9F8
+:106B9000AD1EBDA4A3BEE7C6A0C385EFE67D711CF4
+:106BA000681CA48F44F4DB592EF41BCD4A5F31AE30
+:106BB000D76BF80F88E9BFAE447A6519F256BBF17E
+:106BC000ACC76A674CBBD7DBEE61FF9FA9473613A2
+:106BD000BD5DE58A16C77970F5B12D38BED3EF8457
+:106BE00024D2D7B1B13A49F3F51742D0AD91E98833
+:106BF000F8922447F941EEE746BE61A4014AB00687
+:106C000092D42F9AD5DAAF127E7B544622289F3F2A
+:106C100087F454F17F249FF6F57B41B49BF456E64C
+:106C2000236CA1A7D3D66EA777496D3ABD5D61816C
+:106C3000DF7476C2A4F7BB35FAA2DA0292A9A9F9E9
+:106C400092B2C331E68B93F852C87C595E4B7C8973
+:106C5000438782F35C756F3A5F76774B2CB7F864A5
+:106C600039FFB014ED2EF69B4FB28074863A881F20
+:106C7000764C9EC7E44B9CF882CFDDED2AF3A7A7A4
+:106C8000DDCFF0AEE627489961FB556363C5C807C1
+:106C9000DF9AB3A742A4FEB1622FD98D1C8727E1EA
+:106CA000C4E78EFAF75B37E3FB3D6B0E241D38DF3C
+:106CB000AEFFF001F1A7BFF968B81CBF7BA8E08F59
+:106CC000D1416CCF6A7E3E124638CF09AD567FF770
+:106CD000F95A07AFF7F3B5223EC1DF68F65CD385FA
+:106CE00001B466453F4F74D387855FC9AB018E976A
+:106CF00032B3921472A03F2DF2923F2D6C34FCA15E
+:106D0000E107E7D0C7642FAAC793A4AF08C7B2B5FD
+:106D1000D4BCB91FA1BCCD999E0FBB8F2F72683810
+:106D2000EEEE9BB55AA26BC00FAA07E91A58AB3A10
+:106D30006288FFA81EBD8BF052EA41D211CE8B05AE
+:106D40001D1E1C7FB05665BF39E8D0BE40F30F163C
+:106D50008044F1615D4C2B24FBBCA779DBB5D119D4
+:106D6000E328DD21557FF2A7FD7BFBB86E68D55186
+:106D700025E0915AD0C3D8EE724682807CCAEF3F9C
+:106D8000A90D1521DFE75DE320B9CA2DCDD129DE9C
+:106D9000263C375BF8F45D833F26ACD5B00E8046C9
+:106DA00038A003D1AA8C67D0785F69C0E5027EB8AD
+:106DB0005663BA68BAF1BE54BC9F8D1E9F741EFB09
+:106DC000F871E207CB955648FE0D7F0773D2E5EBCD
+:106DD000BB33C917C8F81DCAC1A04B2D223E0E5E99
+:106DE0002DF42AD6A1B05E810C451B97A4F0DDD30B
+:106DF000B171934E7C76C026AB9C7FA956C4EB370D
+:106E00008584BC37382BBD2C0F1053695C933FB77A
+:106E1000ACF96D348C7A5FBBAD2534447E2B26EC07
+:106E20006E6F6CF931F243BBC3C079D687F592839C
+:106E3000F4F36F20EE2439BB0162FC5C013A3F138E
+:106E4000867E9F32ECEE75A0F1FB851097E8D9A500
+:106E5000477F48766511C418D6C2411EAF65789D3C
+:106E60001E15C67C830BE9D4C5A4B3D2471D24FAF2
+:106E70009C34E4A1352B7292E867D2AB301CF9093F
+:106E80008D5B39FC9C5444F6B4593F45ED277C5F3B
+:106E900065BBA518F28514548A707D7B06B5651C08
+:106EA000CFF8773712DC52AA2E7322FC8FC6F83F38
+:106EB0005915798DC66B9ABF5BA1EF3F32F4ABE9F0
+:106EC000D5A84CC3CC19054726F6FF9B17E25DF405
+:106ED000BC013AEAB007AC38AB9FC826131A8EFE45
+:106EE0009EBEBFCE133841EF2BE73FD7992BF0FA68
+:106EF00003BD3FE1F349247F1AE15529F8BD0EF99E
+:106F0000197744FD4417938F8DF31D9C7FB9FCCAFC
+:106F1000604940F07DBD25DEEF9D86EFBF31F8FE74
+:106F200027E3495F2AE9F2F727C2633AF92B1F1DCD
+:106F3000005AD792F7CE75E6101FDE51658A4D567E
+:106F40009E6975D2FA1E5A15FD37A26FE874B09B80
+:106F5000E851A9278ECB44CF646B3DC3A509298393
+:106F6000ECF02AFD2F344F58569B4B719E30E6EBC8
+:106F7000318D0C73FE947186372EA5C52D00038CC0
+:106F80007FB39699F61EE5541FC2F1E27E21A73821
+:106F9000647F00871C0C4B1C1FCC59AB35978B387A
+:106FA00096D7BC27BCDC3B555CFDBC591F30E4D5F3
+:106FB0007C1F34F223FC9D73CE208FF34213F238F2
+:106FC0002F6491478BBC5F15B2C87B2EDA6DE2BB94
+:106FD00029EF2D71217F15096D39C9DFF253C113D6
+:106FE000449A96E15C96C7B290E01FCA63098D9FF0
+:106FF0005BAFB1BD44795F4A70E5E944679645BE31
+:107000000AC3FA429A0FE5AC9C9E8DF3C53CD79D0E
+:10701000D6BA68DC26BF18D75CE702637CE4138F1E
+:107020008FDF7D869E1A7970F2F34950699DDFAE3D
+:107030007F3FE9A4FCEA05220DE635D5504FE3D4A5
+:1070400006A327247C5E5FAEC9B4EE268AA72C7106
+:10705000E8B264461ADF506E56115E75A55199F478
+:107060001E2927B37D9C461EECF109FEDECB599903
+:1070700026C7E1D04C76F432C7FDF3AAC8DFD23878
+:1070800073D68283F873B9DF99F1D29757EB1B69F6
+:107090005D180EB524F8FBAAB478EB7683CEFF4CCE
+:1070A000F95601C56591FF46FDA15EE43F9F743E20
+:1070B000FCFE2EC21774FC3E9BE3B5161A2FF79CFC
+:1070C000A3C315981C47EFA9918C3C43FB6909D9D0
+:1070D00013238E5640F34E553FD861C4650F515C63
+:1070E000E6A6385AE3E7F6F672B6EF03ED41861FDF
+:1070F00069AF66F8C1F630C3545F8A519E82F311BE
+:107100001F76B8226FD17C0ACED789AD0D1B3FE226
+:10711000387D57F87D8F48CA2187F24633EF01BF8B
+:1071200045FF593E44DCAE8415AE632955E7635BE9
+:10713000C917A39CF9FC1487DD933C447982EE695E
+:10714000A5BCAA60E5F3499AEF43DD330E1CD7B71F
+:10715000840E50FB2AB1FEB25717F17A5D55986F35
+:10716000E64C9ECF0DEB38BEFF90E27BFCBEACF44C
+:10717000F79EA9E803D5463E65E4A3DEF933E75B55
+:10718000F67CB4E046113796BDF7D729C7576DF5A1
+:10719000988235A27FEDC672F6DFF6FE85F5E9FD31
+:1071A000F75419E35FF8EC59AABBED24BB085C3730
+:1071B000F558EB69F679A025238D1E7BC233D725C0
+:1071C0007B0C7FBFAB46F4739976D38887B349E6CF
+:1071D0009CA9FEDB8DFEBF0805843EDBEAAB051BE8
+:1071E000F7C366AA4F5501FBEB828D4718B68FF7A0
+:1071F0008B90A8BF7A27FA79EA17537E1856879C96
+:107200009C2F42B57BA5A12F5AAA3FDA8B5F909E97
+:10721000F820C9E338B31240FAEE92C74F119D5CD3
+:10722000867F9A6EBD19A5E9FE6936FA28F9E9FD4F
+:1072300067ABD799F434FBB9E408509CE69245BD9E
+:107240007501947B294EB08FFB27C3BE9481B69DF8
+:10725000FCEC2E5C07D1748FAC79E97BD4FF70DC39
+:1072600082A7BD6EFAAEF1FD7DABF43F915DF139C1
+:10727000A3A1C749CF564B1C6F2A176F7B8BE5C85C
+:10728000CCBF0D7EB840F0C3841559F0D15757CE0E
+:10729000FCD520C875DF5DE13DFC9DCB56C7DB8387
+:1072A0007203567931E460121D6D799362F09D2C62
+:1072B00028F15D0E6B43FDCCF768CC81FAEB534BA4
+:1072C00097D37C39750ED36F947AD2E39F9CBA82A0
+:1072D00014FF6535C9F6B260630B3F351863BD34E2
+:1072E000F5683AFB6CDA0F86D95EC578BE47725BEB
+:1072F000BF7B2E9FE275190EE3F3E1CCBF7F92E0D6
+:107300008A985B75D3FB10B6533CAF78D4AE20B5EA
+:10731000E7B0FF6A7B339BEDD49FA5D8A65E7C2E99
+:10732000AE0B305FBA1DBA4674A99071BDF87D5797
+:10733000330C75B23D8751C9B2AE2C186700D7B770
+:10734000B8CE923799EB3C487162A5D55F22DDC477
+:107350003809C9A22FCB0DBA615CB3BCCE12D73CA1
+:107360002E45AAEA109FADB907FFBBF0DFA26E2140
+:10737000C51C407532FFEDC1319DE4A602828781B4
+:10738000EAB6E9750DB0C2CEC9F0DFD68978AAB0E9
+:107390000C608CE3E238EFF7B83C37EE5A0CD3EBD5
+:1073A0004D6F7BF51BF52E4BDE29B7B2DEB8DB6ADD
+:1073B000DEA8BF0EE395DAE85AC2DBD5D6C8306046
+:1073C0003BF9DD5B6ED46FA2F5FDC38DFACDD4FE23
+:1073D000668DFE003DFD77887A0112E365E29B1B16
+:1073E000F3837ECBFC77D6097D49E199C820391E0D
+:1073F000195D3E8BBDD4D3F054E428E389F84509E8
+:107400000FA5ADFE8D7A94736FDBCDFCBC6195BE8C
+:1074100099F0A9592DF0BBB90E983EFE5B113F9C27
+:10742000B733F3EFC19A2F7F6D1AFA3D7D6436BCF6
+:10743000826F50BDD68ED7CD751AAF5369AB62BA85
+:10744000B9DB6E64BCF05725A7C7618CDF747198F7
+:10745000FF8EE0398A0B6044091ED6C8CFEAC6C742
+:10746000AD22BF89406EFF328A4762ACFF5EDA0709
+:1074700070921F4D329C0DE718F691C745F8C13A3E
+:10748000E13F724173B01D8720BF37E9E2C9C77180
+:10749000118FFC36D5D1790349B793E7715E27E2A6
+:1074A0007628078DEA333821E3E938F2E3BF38382C
+:1074B00008F9A6CA75366FBDE352A6454F3B65E88D
+:1074C000AA4AE9719BA1C7058A68EF727954AA5745
+:1074D000FF4F676C538F83F4247A80F8F967498FE4
+:1074E000125ED3E98B337B98EDCD27D5138CD387F0
+:1074F00089DEFB1DFAB293644F0A15D6373B5FFF56
+:10750000C19087FC2621CFBDCD224FECAD1576E092
+:10751000B93AE117BF6FE8FB8B46FF2D213D41E3F0
+:10752000FFA6463F4DEBD860C009923F7CFEBB8E64
+:1075300070410A4ED961E07D5A1FE8EA49E1878F20
+:10754000382C7262DA21949784D53E99F6D71C2F95
+:10755000BF4EF091E2DB75963AC7CF0D3CCDF550AA
+:10756000FCBC2E7B8AF6CF19EDE1F4F684B1BE7730
+:107570006BC47A00BEA8BE5B81FC8F95382EE1F308
+:107580007FD32B9497C7C291D7A8FDC14AA137E6F4
+:10759000D34EDF2D61FD75EAD77775CC4F75E2DEEE
+:1075A0005F388314E776659775517DBE2D92A139BA
+:1075B000512E7AB3B7F9E9FBDEC2FBAFA56747E10D
+:1075C000FD0B298E53DA7EFE1BB647F3F338AE5718
+:1075D00026F2CE31BF75DDA65F793873A9D480F36A
+:1075E0008C0464F613238EC4EFEF21FE670BFE1F9D
+:1075F000F0BC3DF71DD4CF22EFBFCC7D07C77DC8BF
+:1076000058CF0107B0FCC75688FA516475E42B2F98
+:1076100022FCD09A8C60A746F8BEC4E3F42DC90BB7
+:1076200012AFCE370AFBD617E83D4BFEF46BFB14C6
+:107630008DE2AAC36F2DACBB1BD735BC4EAC6BEF34
+:10764000171B72898CFB22B7AC5BA189F56CC5F95D
+:10765000BFB3F5AEDDF4FEE14D5F7F8DDEEFBFB76A
+:107660002717C5001E89EE5BB712E10B6AF5AFA8BC
+:10767000BEAB805E7437E9E19B6EC6BF63B7A04BBB
+:1076800073408E58E3958F1B055F3F329E452D2238
+:107690008F9ECE9EC55D42CEE53AB82F621927ABCC
+:1076A000DEC9EBEA6832F6A5FD3F3F43F47FB4FD47
+:1076B00094DA4DC18C1C5D4374D2F662BC8CEBCD68
+:1076C000D8271527114F39CF93477C9BEF1472B9F8
+:1076D000C0FF4BFECE1CD7D7E81571464C1E3F6746
+:1076E000899F8BEA8DBA7D1082A4B7725ED837135A
+:1076F000DE261EE1957FACBD0BF1409AB4BA8362E1
+:107700003C1DFD3C9501A9CE7ECD86B38E9E2ADE22
+:10771000476975FB09FEBDE330C26AB1CCF0D8DE23
+:10772000F38EBB102EC53C86BEBFBA4D86F3D6BACB
+:10773000CAC54B4E752ED9CFD44F9BCBF695C7CF2C
+:1077400005D1DF8CD37CDA4B6B480EFC5D3E90A8F4
+:10775000365A3331DEAF689DFE81C44FCB28EEF23E
+:107760004BC126A4D7F1D12D1EEA3FD22701C9690A
+:107770004F6EA29FEA07F19B2418C2F146C2416FE7
+:107780001ED261A8E6D72AD5526BEBF3982FD9B950
+:1077900063EA72A4F3816C619F4622416F2EC52D6E
+:1077A0005BE09E083EBFFD42F414C5B7BEBE3C156B
+:1077B0003502865E567383D87FB521AF383FC785C3
+:1077C000BD9E604621F63FB4767DC6A24A6AF77038
+:1077D000FB61D5114E541A0B46FCAEB9377848C43C
+:1077E0003FC1EDE538AE7B74B993E2C6AF3629DC14
+:1077F000BFC1793443A2F8B54D56A9CEB43BF33F8F
+:107800003CF45DF1BD3210EC01B18FE318A8854B5B
+:1078100073C89E971EA7F6AB77087D41BAA7EC36D2
+:10782000903EDD9F6CC1F60BC67ED25536BBEF860F
+:107830001DFFEACCA1A7657FC8B2CF136F87319235
+:107840008F5ECC13CE5BE2882FA5E46C19F9950608
+:10785000E79BB7DC4A78B748414ACB77417CE74A97
+:10786000842FB4C841A2DBA32D2FBE467A78F09BAB
+:107870002773AF47F8B1D6D7D75D8F709EEE846E71
+:107880005CC7E3DDFF6737BDBFF65B1F6CBF15DF6D
+:10789000F73A9E3B45FB6FC368DF3AF0FD70B619BF
+:1078A0005FE81CBF6BC679905E45F069C2DED60BFF
+:1078B000FF623E9F683F75A69EF10F8F752FA0F562
+:1078C00044783D6A5BDD18CD7BF854E236DACF812F
+:1078D000980F32AF499D1F78488A86A9049BA8DF7C
+:1078E00034E44155538EDDE7596BC2489FF819695E
+:1078F000FD4DC114EC5EF0FDDB8E58E01147644D88
+:1079000039F57FB5614B3883ECCFFE9843227D6C0F
+:10791000594F7182F719098CBC31E2B1E84128EE68
+:1079200066BB991356D8AFF5B447CF6EA57DEDACC5
+:10793000ADBF5EAC515E363640F8BA50E7286F54A2
+:10794000F22DE719F8BFA8CF563F5E8AF6C18451E1
+:107950006F46CA65CECB163A2062ADDFDE65C8F34E
+:1079600013F5C24E2D1C95626E948B85FB917ED6CD
+:107970007CDDF45FC97F05F25F23A3F7654C655F8B
+:10798000CCF1EDDF9BED3B1BCD3A71FA787D816D3B
+:107990003AD9910FD00E91BD77475AF41EB2D79ABB
+:1079A000B033EEC83D3AE5379E5A0FC3661E5746C0
+:1079B00043A11CBA935B81EC98BA25ABD5578D9F38
+:1079C000B5659E11FE2E1AF3E6733FDE1F33F7BF37
+:1079D00017B121C2F96599E3C8CCC7447C163FFEB4
+:1079E0000589F6C5E2072221E247E9A8D8173B1925
+:1079F00068ECF462BF053B402739AFD8310EB42F95
+:107A0000A6D48C277DA4A703A0919E8607B410F569
+:107A10002B39ED04EAB700A2C789DF0DCECA0CF2FC
+:107A2000371D81FB3B49FF77D57AC6E99C87797E74
+:107A3000C1A44F099D5F60BF1C0979689C6EB45159
+:107A40001AEDD3078FDF89F0E11BDC2AEDD397C055
+:107A5000C110F9C789F320C3861E4F9C5B48DFF72E
+:107A60005D68D3FF129BDE9F27BDAE8009FFA14159
+:107A70002283F29621CC33089F78FBCBF0B6C50E5B
+:107A8000987A48E75B8820C9760F3F5F6A57415F65
+:107A90008876B9DDCFF086E6D07BF505A46FC1DB33
+:107AA000C84E9BFA76C2E7BB81FC5C9D73ACD38168
+:107AB000745872F23BC519A86FCFCE9736D4061909
+:107AC000667D4A26CFE7AD5553F04B67B67CFE2660
+:107AD0004BFBB1D2B7CBC184D1C9FC60A74247A749
+:107AE000709EEF0C254B53F8FEC0C8476BF74991C9
+:107AF000A12CF6B39CBF5F285507291795F3105F9B
+:107B000084BD4BF2195ED220E4548EAC137553BB86
+:107B10007E9108AEE4388A7F4AD61D5CCF43790D4A
+:107B200036F927EB9F8BECED52D25FF99FAD7CC904
+:107B30006D48F7DB17A086E39529EC03CBA9691FF5
+:107B40009CD9F95ED2BF9EF63EB5DB223F3D05CA09
+:107B500032AB5EBA72608B352E319FEB9AC4FA1E3F
+:107B60000BEB5AC38A94FD9B2EFE34ED512A1E8DD9
+:107B700056D077D98511CE7F947C81E764BB94AED3
+:107B8000E75A0C24A2FBB051B71DAA799EF3C6A1F7
+:107B900081627E8E8C86FAA904F2016552A42705C3
+:107BA00098D57D66323EB3C99DD9CF94331336E55F
+:107BB000ED1B277F98266F08A7C99B099BF266C219
+:107BC000A6BC314CF2B64AA1A37E286F3F9C5ADE78
+:107BD00076A3BC55CE2E6FDFF84F92B73BFE8BE4F9
+:107BE000ADBC7142DEFEC715CADB030D059F5CDE2E
+:107BF00046D44406D517303E64FF679E871A3EA8D8
+:107C0000F239D261FA84E2DBA7D4C118C2CB1A845C
+:107C10001FACDB2FCEFD95EC15FB7E7DFB8C737FBF
+:107C20007DE2FC498373C72682476A143E9F669EA5
+:107C3000C31AEE00E31C1148649F17D1392C94A796
+:107C4000D17630F62D40A27367E546DDBF2491342E
+:107C5000ECBD16A2F380252F087B3F025A865A9965
+:107C6000F2571506DF4BFA9E3F7E27F9B922B12F56
+:107C700001A3C2AE9BE7009724D2EDBEDDCE6B36EA
+:107C800078B021DDEE4F67E7EDFC41BBFE24F151FA
+:107C9000035DF88901515F9D2EDF18694F3FF75C46
+:107CA0009180D094F9498388DF0AC3FAF769FC4FC1
+:107CB00080CF2BD47F363FF3D7868FD3F41EE134A9
+:107CC000BD376153EF4DD8D47B86AD7E063EFE5462
+:107CD0007EE6AFFF497AFF8FFF457AAF360A7D42D5
+:107CE000BDFF7FA4BF57A0F71F5D89DE57F88F1D2A
+:107CF000A79CB391E46C8A799E37E8FE90B18F8A95
+:107D000078659CA73C4E0ECEA37CD1DB28E4D0FE48
+:107D10009DD276E7D9ADD6FD01A37EA9B46DE3F778
+:107D2000BFACD3331A29BEADCEBBAC7370D7D6036C
+:107D30003F5D0ADC3615FD7E6BD84D5706D2770ABB
+:107D4000B96F7686FC34DFF2E64811CF0B8920ED5F
+:107D50002720BDAF6ABC327A97355E01BDA7C3FF4D
+:107D6000B6D9F10F1AF86FB5E27F0578AFBA12BC39
+:107D70008F053666D03C07439135F45DFC972EAEF7
+:107D80001B98796F1FCE3146F6590EA6DD0F50DADB
+:107D9000369FDD7ADD5472B035EDFDAE7695EBF0B1
+:107DA000FBDAFDFC3C580C7CDE2E1E0289E6299095
+:107DB000230E92B75FD6456F21FCD51AEC6FC177C1
+:107DC000EE067F1A7CB97255EDD46F6F147467BFDD
+:107DD000A47D16E2345F4EE5E9B3547FCEC9576205
+:107DE0006427A05A7ECF6A3F901F5B080F3B3F502D
+:107DF0009E96133C22B772DDAA0CFD6107D5E928D7
+:107E0000AFACA4FB194FFC91CE4B1EEA2B2E267F64
+:107E1000B8903668919E0B0BB421F2AB270D7D1AFA
+:107E2000DA2105C9FF5D30EED3B8202BE69C22DFB6
+:107E30009C584FFED933DD16FCECE7551F68CC4A41
+:107E4000B36B1F54AEF725617AFA98E755CDFAC0A7
+:107E500074FDCA5C118E1B0E976F58B388EAF2FB53
+:107E6000E5E00231EDA9ACB9A9FD2BFBFED653F537
+:107E700013FB594FD55BF6B39E223D5FC1748A1048
+:107E8000FD0E8F4A5CD719A9091691DE1CDA179AE4
+:107E9000D17FF6B4231D66C017F52F3A955FFC918C
+:107EA000A17F23A3EB590E9ED430BF5E46FC493020
+:107EB0001F173E23F83852A315917E1EDA2EEE23AB
+:107EC000F51C6B068DFC1112E16D0BFD9F6F14FB11
+:107ED000218A952FF8FF21C27F867AE365E0CFFEE5
+:107EE000F460E31D87621C0FC15876FABECFCB8DBC
+:107EF00033ECFB5CEEF80037DF999C81CEB3D53DC7
+:107F0000E0843748FE97F6EFBDD49C8FF4B1D4617E
+:107F100017EE9562EEA593C7B1CBEDD8A794DBF62B
+:107F200046214FA8E767495FAF40CFFFC9D0F33480
+:107F3000BF51648C7BC01BFF1D9DD704D873E7AB7A
+:107F40001867F4D06231CFF96363C7A1580D409729
+:107F500043D0D3F593470FC52AA9AEBF529CCB3768
+:107F6000EA321C4F3827AF4369FBF7D7ADF56CA554
+:107F700006F85CA2E2573F5749FB023F2DE6F36942
+:107F8000AE7C9DF9FCD6D73489EC9DD424ECC7781F
+:107F90009D381F096A84DBB371DDFDB9976F17CD7A
+:107FA0007EB4EF31E5791BA3DFB8B11F597C0ACA53
+:107FB0001DB898E2BE989FE29DBDEDC1A277165014
+:107FC0003DCD11577CA9F52EA058AC84EAC822CF2C
+:107FD0001889C8CC8FD85E657001E9D706494F87EC
+:107FE000E5981586AC4891751F665E93B023873F70
+:107FF000766E9A4AAFAF32DA6F2E81FB486F8FED03
+:10800000DB58749EEC5576AF5FAA24FC85DEEF74D6
+:10801000057F150D4C4F1FA56DDDD9FA39D6F5C773
+:10802000C53EEC843FDBC0ED267FA7A3AFAFED0FCD
+:10803000AF533F77DBBF307F7DF2389FE38351B191
+:108040003FAFB4FD5F7EEF9E1F91681F798D517F1A
+:1080500030E95761C88B7B549CB750FC09698B652C
+:10806000DD3718EB35F95F313FE6D7991F7AD13B01
+:10807000A80F4A13A48D576A8CA70C88731A84C75B
+:10808000026D32DE2B9A26CEE527ADE71B503193E9
+:1080900019F9740C16C6294FD387433AD5F5F274F3
+:1080A000CF38E573688FC6693FCE078924DD033377
+:1080B000F715C78D7D739F47E42915B6FB6FBD8605
+:1080C0001C9BFB4C7A93B11E7FE438A9D47471D405
+:1080D000EDC677A8EF1B9B585FCFF179BCD9F47C34
+:1080E00086B8EB8E26A1FF9B9B0A52FA8F7E7E4BB1
+:1080F000D395C58D5F69BA827A50E7DE4EDECF1C1C
+:108100001E73F27D986179EC965B293E6A918243F9
+:10811000047BE23B57527B4B3EEF079871D9B03E50
+:10812000B86F23CEF36F5F91F81C95B95F71D55787
+:108130004EFCF456EC37FFEF7EE3A5FD04D430AFE0
+:1081400084BA79F5D7DF6EDE84D0350F887D86BF9F
+:10815000ABD798FEFFF4CD0F72697D6507CA97B162
+:10816000FDBA4C3BD2F7F19DACEF4A2493E9AE4403
+:10817000768E511C63AF4B2B1BDC6F315F201A23B3
+:10818000F9C1F77AF61472683ECB4A23D200E2B105
+:10819000E0E20F2492838AD128EF3F568C0667D401
+:1081A000BFBDED90B0D691EDCF7CE35E0AE1E74430
+:1081B000FC76C98227F93541A999EC469387D755B2
+:1081C000E217FA977FA9C3BFCE22372F19F2576063
+:1081D000EC4B9AE30C1BE3140C683CCEB34D62FFEE
+:1081E000ABD82FEC7A018D9335799C8AFDC6B9AA5C
+:1081F000EAE5BC6F5C2127A4BC29E414A043F40782
+:108200008F2EF6D31212EDB3F77DEC647F345EF758
+:10821000B33B295ED89D99235F44397146C53DB76C
+:1082200087336F4C921C3E9EAD686ECB7E0B9B7E5F
+:1082300087C0D93197EA26C071DCB1EC32B6C75D90
+:108240007703EF63753D20EA398F17887A4F999C41
+:10825000C170975F9C3B70D379F1121ADFA80B9520
+:108260008B7ED7548EF1BDA26B882EF83EAB1AE2FE
+:10827000B140EA3C4957BBA883A0FE7E81DA734136
+:108280000AF6D3B8B2AED1FD872E19E2148F755518
+:10829000AAB12F21FC686B4E500AD2ED6271EE0438
+:1082A00016EBC67995A0B8FF33718EE46DA07324E8
+:1082B0004807207B57FC4DC9A0C3D2E3344FD7F603
+:1082C00029E8407ED6F3EC2BE7F09FC7B697252828
+:1082D000AE19BA3B8BD73F94ADE874956BE8812C0F
+:1082E0005ED7D002731F2EE8A138F56BD9EF0FB619
+:1082F000B07E69B7D1F88F3AC43A78D0B9C07B1F45
+:1083000082CEAAFC00B56F11F15A577BF88DADAE45
+:10831000D4F91B590E721D4D463AC4E8D9B6F60D74
+:10832000CA9F2034702C8AB003D74FF6D7D5B651E8
+:10833000BC270F65C685FC1F35D642FB6AD44FA506
+:10834000F32D091E370BC6F89943E7D44AF8BE1C33
+:10835000D3CF4E47F35E688A8E4E3E8FA31C17E73D
+:108360006D9C9D32D03D9558A895CFE3C43ADD6A07
+:10837000573E9FCFE1F636D9A3D2BE7776B8D8F074
+:1083800023ADD78BF15A3F43CF979BF4AC7041CAD2
+:108390006EFCAE49CFB1C293F4DF382760C24FC83C
+:1083A000E31EAA03EEAA1952ADF516D34F4FF85F9C
+:1083B0003A2780FEF71035A13E7D661424BA571186
+:1083C00038A875D2FD88C509A18FC531A17781A3D1
+:1083D000E2B928EC643C8AC3C20F9A70D9B0265126
+:1083E00048599E10FDCCEFCA8E8A7116855DDC6FF0
+:1083F0005D58F8F17561599C0B1DF6B29EC4F70BE0
+:108400003DE908F4FA69BFEB7BAF8BFD30361C2BDE
+:10841000411C5112F7A6B9BEB954B016CA34F92D91
+:108420008A9F9F34F5C4B8EF5971500D69F8AC8C30
+:10843000AB9DB42FA67583560BB4BE56BEEFABC52D
+:1084400085BE2DEE86B84EF55A977AFCCB94CF1B9D
+:10845000FB654B6373B9EEFAE368562BD07ED9CB3C
+:10846000C67E98B15FB6F8607ADDB4CC56270DD8D9
+:10847000F6CF165EFC7688F8628FEB17A384D0FBEC
+:10848000B5E1A9EFAD4E679FCDF8BEE220F0DF4D1C
+:10849000D0FAA47880EA6FB1D800DD2F091CC57C22
+:1084A00011F9F8BDEE8838C7BA636A3F65DE374F09
+:1084B0001AF71E5F32CED71F37EE3DFE98CED7E3B8
+:1084C000F34774BE1EDFBF4AE7EB113E4AE7EBDD20
+:1084D00029B97CD090A3D9F2E4858EE87AE2373CC2
+:1084E0002203DF17AB14F6DCCC739F79B958223B1B
+:1084F000F46C4DB2687DE554F995B0EFA32FCE9C96
+:108500003F1E9925BF2B9FC8EF3E379CC4719E7DAF
+:10851000B9534ACF77CF897CF71591EF3E6BE4BB17
+:1085200043CF897CF7C8312F9F2B5B1C86412FD905
+:10853000C923E979EF4ED26FC473511CF1B0F07BBF
+:10854000E84561FF2FD4C020D9498C0B770AFD86FE
+:10855000F92E4B3C69E6A99F7E7DABB65AF357A82E
+:108560001472305DFDC41EB798F6C1DE3E7B3D241B
+:10857000CEF590A78D7ACFD347EECBD8CC7228F822
+:10858000FD8C610726E462129FC5FC4FCAC1B3513E
+:10859000E4C3D3A75D1CB73D3D513FBA9FE5E8E971
+:1085A00083A512FB29D4178AFF8FB44738CEECBFBE
+:1085B000712083E4E767E100CFF3D491CE10D33D7F
+:1085C000AE719C59DEB691EBAF743386E258FBFC7A
+:1085D000E5469D09E233D7934E843F5D5EFE07BAC0
+:1085E0007743F1B951272837EB04715B9DE0C8E56B
+:1085F000D5095E277C2AAE1C9FE9F939C0FC7CCAEC
+:10860000A0BFC947FC5D74AE9CBEBE45DB67C4A776
+:10861000CCA036C47D0CFD6DCD32F272C32EC9D212
+:10862000D4F5A8F1B0C3F093F385BFA5B538698A36
+:10863000E039F2FF391185EF1340E85C8CE887BD23
+:10864000F9FEBB3DAF218F4EE74564333E80A8C89D
+:108650001F49CE9C539DEB9D2E0E30E328914F0178
+:10866000D4707E8203305E3DB4FF6489ABCD7B273E
+:108670007DDF8A4AEB2D7A186816716D4FBBC741B2
+:10868000FDCB927773FD4CC9D724CA538B8DEF5C19
+:108690001AF0B9AD217F31D373F5C5AF66D03D4B2C
+:1086A000F37B7C2FF6C3FB2EEF3E8CD9AF67BF2444
+:1086B000EA0B7D4A9CEA093D72C433553C5DDCAC53
+:1086C000A5E9A9FD7E0732BD88E296BE40D98CE7B8
+:1086D000075D9EB7E7C996BA418F375A44E7E39ED4
+:1086E00070A5DF0F359FCB9AC539B721C7D4EDA64A
+:1086F0001C99F7D61E34EFB7F975AD03D7E51E2BDD
+:10870000E17B16725E9B4A76A1A6397D7F66D2BE5A
+:10871000D9FCF4F3918F85233736E3B81F64BD7419
+:108720000A2565A673B6A16696CFF4F3D3994EE3F6
+:10873000BE4109F0B9728F2D3E98ED1CF5FA6653D3
+:10874000EE6D79BB6ED8A549F29DAE1F71922BDA02
+:108750008FF8D638FFFD255FF22F40E7947C3195E6
+:10876000EFE7070CF9D2B2222021BD76750BF9B2E2
+:10877000D377B0268FE56BF5C56BD7505C61DEDF34
+:10878000994DCE06BB0D3933EEF74C275FCB49BE72
+:108790000AA6972FF3EF7120BEC7EFC27F0792BFE3
+:1087A000633DC98EC5755E47B7CA76BD2FBBAC9811
+:1087B000CE4D99E37C7975E8EBC49780ACF2DF1B72
+:1087C0000868A09BE72BD52A5A973AD86FE9FFD5BE
+:1087D00066E18F06BB67BE8FD0DF1E19A3BC79A0F0
+:1087E0005D1F9B2A7FCE34F2DDDD753F02AAAF3DCF
+:1087F0005CF723FEFB1D3B979415939F7AD8E0AB63
+:10880000D9FFD89297FC74CEEBC1156FF889CE3B97
+:108810008FBDC27C9A18CF58A7AF26C676754EB5C5
+:10882000C6F7C8D4BAF7FC5BB2268F37C13F9B7C32
+:1088300014AED21F267AF864F567848FAF5B02CA44
+:108840003307638E30E7F9F487042C7EFE1BCD924C
+:108850004D5F6269F3FC7FFDD039E3004D000000FD
+:1088600000000000000000001F8B08000000000056
+:10887000000BFB51CFC0F003092FE440E59F914569
+:10888000E5CF9346E5F3A2F14DD0F83B2550F966CC
+:1088900068E615A3A92715E7B33230540271332BCC
+:1088A000AA781303849684D2DC405A19498D283360
+:1088B00076F3224C20F45F6306067D203B1288A7E6
+:1088C00068333034EA32303C07D28BB529732F3A03
+:1088D0009EA1495DF3463169D8D31C951FE8C0C0FD
+:1088E000D0E6084CF74E10BE0392FC13A05890033C
+:1088F000846D66C5C09008E49B9B6337D71C289F96
+:108900000494FFEA84DFFE5A0F54FE5F7754BE667C
+:10891000082A7F039AFCE22454BE722A2A3F270DBC
+:10892000420300C47CA5ECE8030000000000000046
+:108930001F8B080000000000000BE57D0B7815D5AB
+:10894000B5F09EC7792439E764124EC201923027F0
+:1089500009104A80138810103F27E121F8231E11C7
+:10896000687C5C7A788A081AABB5A1B5CD843C0CDA
+:108970002160B0FC3658A507048B4ADBD457ED6D57
+:10898000ED3D28A568AD4645AB96FE3D0408A8E838
+:108990000D58ABF7BF78F9D75A7B26999924807D7B
+:1089A0005CEFF7FDF1C3C99EBD673FD65EEFB5F63C
+:1089B0008EC797C7D4CB193B873FF0D4E25FAF6433
+:1089C00041C65298186986A7D71B39B88431760FEB
+:1089D000FC6353186BC4E710F817CAA4F22697CAB1
+:1089E000581663528E78C413604CF655B11854EB88
+:1089F0001591042B85E72416A983B224C6147609A1
+:108A0000633EA55D13B00F25CEA27E78EF8BE9AF54
+:108A1000D078AC5BCAC00AA6B16CC63CF81B742DFA
+:108A20002B310DFB49D5A06D0963AE603B8B15C39F
+:108A3000933DA8748D614C842ECF0D622C5006EDB1
+:108A4000A19FD41C169760004FE23F12127CE729C9
+:108A5000649114153BABD2B0DE9DC394C7C2F03E07
+:108A600087B7F714B19D69D0DE2D271302B467458F
+:108A70002CBC1B1EE9580FE59442E56111DABBBD21
+:108A80004C904B694E91DDD09F627CEF55797D6AA9
+:108A9000112FB70C61F16201BF83BA522C77FC1819
+:108AA000CB5EFCC652C691B0BF4D426AA4398CEF72
+:108AB00013219FAF771F5AC242653B94D9D9174201
+:108AC0000BFC96F79FBF11620A638FE6E6E833005E
+:108AD000FE2D2523D3111E2DAE4448B17C6F3E1BC5
+:108AE0006BAA8AE5117DDFF7D48B6C158D23778413
+:108AF000E6FB118E89B73DA50447550AF785634308
+:108B0000C95D3D701CF54F84E3468463B8178E1B26
+:108B1000116EE15E389A65731D1B87B4DBE0B711F7
+:108B2000E1578CF07B32B460ACE5FDD803A118B4FA
+:108B3000DB88708C30760703380E652C2C27755C2B
+:108B4000E7465867338CE1D1F484A4F68597BB5A85
+:108B5000528F0DB294BDB183F9305FFF2189E930A6
+:108B60009CBFF5354D0A227DC0FA689B63CCBA7F65
+:108B700040572CE1656C243CCF21FCD4549628A2AC
+:108B800086EC1CC3FEDDD43FD0CB5D482FFEB24443
+:108B90004282F7A9DE76260B482FAA300FFACFD2F1
+:108BA000EDF432A8875ED472847736D20BD40F0EE0
+:108BB000EAB5B88E5FDF14D3B1BF21D3E2820CE5F2
+:108BC000CD539E213AF2231DA5111D15221D852B83
+:108BD000BFF9C324F4FF892EB366E8A7F6B2AA1F33
+:108BE0006159D63DCAFA20D275D50F9348D76EAFDA
+:108BF0005207F0FB7E5A80F6B7FAB03FEE81F9B526
+:108C0000D4309618C558738D972580889B6A142A8E
+:108C100037D684E809BBA77F03DA7F3A558C374300
+:108C20007B39C834DCA79E67217FBECBA012E6BB90
+:108C30009BA5D2F33758CE22B4F146613F37FBE60D
+:108C4000A7B3E281F1DA1F116D704D2B4A25B89B55
+:108C5000E51435D356F68486DADA33964370A132BA
+:108C60006C802C6B2C82F393617E803F52FADCD0B7
+:108C70004ACBF8F73389E62949E55551785F2F301B
+:108C8000C23FB37EA820D2FC8B052F3D83ACFB8571
+:108C900073004F970FE00078E0F3CFD71348170227
+:108CA000AB1AA1200DC8A792E6FCF2A1DE955032C6
+:108CB0008BBFBCF59BEBBAFCECE5DEF9167AFABF8C
+:108CC000C6BEA4FAC5681CE092EA025442FEE1CF97
+:108CD0008FEBE12F639E25DD084779903BB253ED82
+:108CE000BB0F2719DF87FB19DF0719F7A1B4771F1F
+:108CF0009A7D7C1F8096FBDD876790F9C23E37CB5B
+:108D0000716FA6010F94637E5C3FD213AE1FF90111
+:108D1000AE5FF812D65F575119F5E1BA22040797F2
+:108D200032724233C3F7F9ED0998575DD6C809EBA3
+:108D300019AE9FEF5B5DAD4872C69C8F73BD4EF858
+:108D40005D2B70BA2C473CBEA477FD1B7DE26C5CAA
+:108D5000FF4699AF7FA3EFCB59BF399F169C0FAC4D
+:108D6000AB45E6F8D8E2FB92F0314DABEC8F6E4CA0
+:108D7000F86F32E0B6C980DBA62F196E69061EA710
+:108D800019789CF625E1B1399F26033E4D067C9A61
+:108D9000BE24F884516703BDF78F42F46601F03EAC
+:108DA000AF5ABD5E40BD87F9AAA448EFB82E378BF5
+:108DB00091DE51BF80DAEFDCB0485DE243FD424D09
+:108DC000BDC6A20730B69EE8677B4D9C1D1D817A0B
+:108DD00054B7407A6DB08AE4725E7594A19EE2C980
+:108DE000490AF834DFBB0CFD83D50749FF6E6802E2
+:108DF0003860BD571551FFCB6F0DAF477D096065DA
+:108E0000E81F51D23F86330E8FC70DBD83B1388D19
+:108E1000EFA9B6C3C565E81FDF945815F2854FBFAB
+:108E2000ABB9E7C3B8CB1373DCF980BF3F34E8BFFD
+:108E3000B3E6339AF7A7DF05FD11EB5BCADDD32D4F
+:108E4000FBB1537053BBE58CCB73905CEE6BC65A91
+:108E5000D75F6BF08FF404EE6BE74189F8EF40FBCE
+:108E6000B92CF4E43879626FF968934478C1E4C8A6
+:108E70003CA4EFA52D92D8DFF7E63A7BFB7986FA82
+:108E8000F9F43B9A1BF964678D5738EAE2EB53011A
+:108E90004ECB9BCADD9AEFC2F36E457CC8C2FD8300
+:108EA000EF110EDFE916B0BFE189FF10B09FE1D5E9
+:108EB000C9720DBFF7D15EB033D5EA0E9CDFE5670E
+:108EC000FF3D05F980D98FD9EF705C9F45AFFC61FC
+:108ED000B568ACAF7B0E7E9F77B77851EB1B8EEBFE
+:108EE0001BD40BD70D08576160B8DE53D33EEE7C20
+:108EF000F6816704E7071E5715E91F171ADF9B0362
+:108F0000FD59E8C89CC73D17D8DF26C73C36E4F0BA
+:108F1000F56F905BBD17336E8A0ADF5BF1384F88BF
+:108F200021FEA2ED49F62A63FB65D4630B230FE310
+:108F30003C8E1BF809DBACD5121DB3AA6605EDD932
+:108F4000D871A46F59D189DE50BD463EE4CA2E22A5
+:108F50003B8BF9B8DDEB9CCF76879D65CE6FBB8BE5
+:108F60001976C8B571B4AB5C62D1EDCD915E3B1A98
+:108F7000EC2A5D1A675977AE61F7318E371E05E628
+:108F80000BFBB761C4ACD032E8E72CCE1BF04E9B94
+:108F9000DBCAA216BC84799F15B2FACEFB9EDCFB1D
+:108FA000B5F530EE19581FF229D36E77CE3FC57B49
+:108FB0005731D205693EA8CF19FC2EAD18E6371EF1
+:108FC000F829E7296C4B2EB7CB7C116E976DC9E55C
+:108FD0007618B423BBCC2C9BFD6EC95586F82CFBB0
+:108FE000D73033FB1D84430AD897643F26D631A47B
+:108FF000174F0EF03778A6C81DDC7E2C05FB51C537
+:10900000792512C867C156237B72CBE74F52591F8F
+:10901000CBEB595129CDD3EC3F57146D7861AE0796
+:10902000964FF0F0CC7013BCFF5D88C922F2BFA24E
+:10903000C60E2980E3B712BF2D34D6ED84CF63B9B5
+:10904000863DE9C023D8E70756D33E4D9A8876631C
+:1090500044E4FBE3FC1EF62722F6B33F8F3DCAED46
+:1090600077D61AEC775F467BEF289607F5C5F7476A
+:1090700077CFCAE7FD70FB8F501CC6F719F3F7E4F2
+:1090800044B7211C25DC77C0EB6DA13D2A037DEEA2
+:10909000FE50598588F22E471571BDFF392C365D7B
+:1090A000B4CC77C87285DE9B783B53BA3BA513CA14
+:1090B000DFBF313F7D293C578942BFEBBB0FEC3E00
+:1090C000C4FF46B0FB64E0A79FFE6914AD6B207A35
+:1090D0007FBC861563BB9EF26C99F4B5C7F7E66F4B
+:1090E0009901A06808164E40BB575B15DEB69CF090
+:1090F00045253DF67A91CB1F80E7F56296853E8344
+:10910000265C611E1678A468ADB523508F61AC3B18
+:10911000AE203CDA13229443201F138CD6BF0CF1EF
+:10912000A0A058A97043FBFC5884C10EF6D22DAB09
+:109130007A11BF6F7B71048D6FCEF797069EB108D1
+:10914000DF379043A1A8BF3F3EA51B72026CBF1141
+:10915000586E17906E9B8DB2D92E5F8CDD89F318F7
+:10916000569DAA233E0E5B1317713D8F1AFAB7C0A6
+:10917000BCFB8710DE293B38DE251FFD11E15D7643
+:1091800009E25D8D280E847735623FFCCC5BDCAA5A
+:10919000231EFC458ED5617DA610CD6005A8777095
+:1091A000FF5A338EEBA3E9BF8EF8952B70789A7C2B
+:1091B0006968A9BA13F9D2A3C67E04D5D672EC2F7A
+:1091C0005CF656F90AD4D3623E0DF95C5E6E32232A
+:1091D0001FE9F94D8921BDE6CCDE553E13CB9AB788
+:1091E0003B3D04DF4513B5B8DF6950463C053640CA
+:1091F000EB6E02F8A0FF60C8F204E94583AA40E2E2
+:109200008A1639E3D643286F73D5957319D0B39076
+:10921000FF76B907C76D6011F41D0E5DD5C196428A
+:1092200039B7CCA360BF7961A5C28BF56B59A41681
+:10923000E6A1EABC7EA8E68D627DF04E9D9C204CA6
+:10924000D6D9B516BEEA57636B5900F91F87DF31CF
+:1092500039F628C22BADB883CA99739EA2679BAB1F
+:109260009D29A8374FEBD050DFBF6F4E235B62B113
+:10927000ABFED5D81F6F31D3E2163CDD26F1DFEF10
+:10928000AFBC2FE5A6626CC7FD1D2E56AFA13E8771
+:109290005E25C4D734C45795F0F51788F7E1E5117A
+:1092A00051447C2D8E2470DA409F83F93CF421F8E0
+:1092B0005DDB1C77258DA3B3B7D82498A768DFBFE3
+:1092C0001455DB8578B45674D178298747D3BEBD51
+:1092D000B2C4A709B02FA9435B13CFC13E0D06F856
+:1092E000A80AD68F15F2A0FEADA112FAB640CEB7ED
+:1092F0006A38AF6C1F8B68D8677EFB4B5F41782E56
+:10930000E7FEB3206B67A244F07A15E135E8C6F6B4
+:109310005AF43B797D1D3ABA8C1F97ABFEFC1D6851
+:10932000FFF84129A2AB163A62404716F817EF053D
+:109330003E6191EB3DFC5CD75E2884755DC5CC9F9A
+:109340000E19E737372431C43B56EA3A9634F59084
+:109350007C82766F19E6F5E1BA17F63F8476FE1443
+:109360008FB25BE95B3F17CBE6B800A7B3069E3F21
+:10937000FFF41F46A2FC7935E251D1DFF5B2D0D11E
+:10938000457EEE7249DD1DE6F3F34EC2EF19122D54
+:10939000E718580698217DBDAA491AE27B47A91013
+:1093A000C77A0F3B527F29F607F88FFA47C7B4A355
+:1093B000F597427F5709AC1B5D0D73CF32B96C42F4
+:1093C0002F3CE63EE53982F26B2EAECF029779BF95
+:1093D000B2AC17B718F10AE7FBA7C157FD00FB674E
+:1093E000E95194BB6CC69DEC19ECBF8CEB636B032D
+:1093F000DD734BA13E3A4D428B84BD5AF646107543
+:10940000D6724D20BD6DDE3421EEE9675DF0DEA53C
+:10941000C23ECDD54ED3FCE1A7DB53067CFF085FEF
+:10942000CFCB22EBAE85F9CF7BF6635A0F501FD11D
+:10943000BB933FF559C7347BB967BF67707FB9CC21
+:10944000B8BFDC2BC78649B0BEF0DE2BF4E9A85FBD
+:1094500027587733F1B918C9F15EB9CFE52399726E
+:109460008067E59FC93C4E1061A417FB5992846444
+:109470003AAE0AF62783A902239A8C08C827199BBB
+:10948000467186600AC78BBFBFBF1BA93F41DBC2C5
+:10949000CEA55D447F7292F0E61FD6DF05E697D237
+:1094A0001B5709A23F7803C873548E3D18A101F8D9
+:1094B0007F52CC086FEA6A147A7F4F4D88076BE4BD
+:1094C000A7891FF8226E15E9CFA73C41F11FE5D708
+:1094D0001E86FBCE40AAA2FD896CE85C01DAE3ECB3
+:1094E0008808789C1671DBEC4F6F8EFBBC76784356
+:1094F000D6C8C1E7D32B1043C2DEDEF603B5FB6747
+:109500003FEB407E852DFA8DEC0326E41D785D52FD
+:10951000718C0307EC752BFF9345EE4FA8F32DF5E7
+:1095200092FC3E7BEE9C348931436C30C9172DEBA5
+:109530000F1EB518BCB1E88B2EA5F17601E4982B6F
+:10954000B45CB3D2571D769485EFD768C9F3C05D7C
+:1095500092A3954BB85E4E719B2D698BD99162F4A5
+:10956000FF2FA67D6ECCCA0E733EC1FD1AC0E889DE
+:109570005F9878B82F6B512809ED1B862C0A217F44
+:109580006970454328270F663DA361BF8D67D39956
+:1095900007EDA2503EE98D8D670B0657F5B3AE344B
+:1095A000D4CE60FEA98C197E0C37C69A7AE6095291
+:1095B000BA290CFDA5815C69A679FE5AC3B88E5BF9
+:1095C00095ABB07FB72F4A7AC3ECD2766D09C6B19E
+:1095D00062BE9847E9DB8F390EFC08E7908F631B6A
+:1095E00093AE045B7DBFF37096DD8522D10FD80E5C
+:1095F000F1BA7EDABBBC013D6D1CCAFD9EF70A8E36
+:109600005BF8F2D8F4E858DE5EF5E2D08286F4D357
+:109610008BEF71BBBDA388BDFDE62335C4DBD00E47
+:10962000F0306F5573A42F3C1BDDDC7FC364AD129B
+:10963000E7572F644EC0B8CF40782D879A4E5BED28
+:1096400055E7D3A3B813886772B04A47F8C27C22A3
+:1096500057108B68E910C6D1F334D95B8AFCBE156C
+:109660000FDF90FC41C2B7C96C32C2A3CE977F5EB8
+:10967000FBA101E88B8D1AB8DEE58EC4A22407AAEF
+:10968000DE46792DB371B42E39E7C0DB6198C7315E
+:1096900089DB317290DB834C914F59F5855F0ADA93
+:1096A00031942FAE54DE8FB3FF97858A93127CDFFF
+:1096B0002045DFC776CDA3271972C74E370AD813C6
+:1096C0009CAEB58090CDF196FFC41322FA030C3DF9
+:1096D000D955BA9361DC5001FD8AF86591DC89F3B4
+:1096E000D1E03F9C8FA49D3C8C7A6E601ABCB7C0C1
+:1096F0004DD252898FBA186F6FE2A384701E874FC4
+:10970000FB7B263BE05CF32CF9F1CC75498CC7B7A9
+:10971000FAF033A1C22D67F55D1FEA405C6FAB6ABA
+:109720004238631C1FF5986DB83F2017BE5753444D
+:10973000CFEFD74468BF7E505346E5FA1A8DCA1B57
+:109740006B6653F9A19A2895DD43EABD08C76D43BE
+:109750005AB709A8C7B1E28A97E1936DFED6773070
+:109760005ECBF4D1152F037CB6016F6553D1AF3AB0
+:10977000A242073CD996C1CB5F91C7F0F288D6EBE5
+:10978000446A3F88B7CFE5F513E5B1153AF63F9641
+:10979000972F9727F0F62986BD93B3A05F3BBC9720
+:1097A000DE387FFB15065591CFE504C9D894D4A5C2
+:1097B0004C8057DBB20CBBD1E8070D9D6BFAB50BA3
+:1097C000793FFF222B84876873929F509149BE6E28
+:1097D0000B7FB1F9A4C8AD1AC1875D5671A80CFD05
+:1097E00026F0EB50C66EAE2FA3F5124B82F5DE517C
+:1097F0003F75BDB17EC3CF14650B2DF266051AE52A
+:10980000309F6D25F6755C68FC9B40CDC067FADC27
+:1098100024C3AD3925C5E6C918BFBE319140BBFA96
+:109820009E9C27B8FD69C06BE0FE741AFF76846FBA
+:10983000566F7B1F5819F87D44E6F1B787EEAC20D0
+:109840003CB9C1809F59467823BF7423732EED85A0
+:10985000E780E329163E9EDF17BF991C257B79918F
+:10986000A4D8E633C3514EF171BAB958784D757C1E
+:109870003F52526CF894E3280FD92B32B403862E52
+:1098800017CFAB47441CFD7AEA6F6711F48F1F9224
+:10989000488FAF66EAAC10F2E52681EC7184B7021E
+:1098A000721A737C504E8B4D19B3100F9732F675A8
+:1098B0000FD0D4525975A33DB9A4C9E3D0CBF83E1B
+:1098C000ED4B0E5A8F76F4E17ADEFFE1FA17FC28B1
+:1098D000DF17AF7BC13F19FDFA87A40882B1D3C05F
+:1098E0006FBD5A88A39DD4D974D4CFF74BCD43F81C
+:1098F000FEB986E70DBC6BE40D2C34FC584C56F3D6
+:10990000302FE55D57FC5F38FD2F22FC7E3745CDBB
+:10991000C372ADBEBCA27E2AF6D3D27885651DB1D6
+:109920007A41437F921665EE10FA8FD4C8C46666FA
+:10993000FCA03CC8E17ED59DB2DBF027693B91BF1E
+:10994000850AA3E956FDCBF93C62F825CCF2DD721D
+:10995000EC71C4F358FD6917C6A3627A861BF1F453
+:1099600025034F991CCFC5F5751A7E9C50211FFF0A
+:109970009355A37658FDF22FC9824D8E3BC7F95AF5
+:109980007DC62C5C075B2344C88DE48DE72EB6CCE6
+:10999000F3453940DFEBB7F371F421822D6EFB6F95
+:1099A0003297772FC9DC6FF537ACF325844FDF751D
+:1099B00032C3CE4AFA39DD2568DF8F1CE2FAD78B35
+:1099C000477EEB4AE23E2FC8B2D145EC6EC9A6F7FE
+:1099D000DFB02ACD56BEB1FEDAF4583F72A8878EAA
+:1099E000AA3DBDEDF37BF1B11C243DD27DE6026EB4
+:1099F000A730477E4C90C50401DE0F667A2DAA0081
+:109A0000663E8CA9470D9BA1BE03BFB13AFFA221C0
+:109A1000863F519501AF304D89CB71594F9A7A21CC
+:109A2000C027A798692901AC87F716393B748D6C5C
+:109A3000B36383CBED65FF5CD966AF7B1DFE067318
+:109A40003DE67AB34D39ABC55584F3467F7B48007C
+:109A5000146BDD7CF7FA39F07EA3CBE0E7955B79F8
+:109A6000BB24E37018BD68577FF11F90C05C6E2463
+:109A700023E548DF83E6EA3C4F0BC4F020D46FF3C4
+:109A800018EBC0FEE40E2FEE7730CAFD5F1946BE1C
+:109A90009FB8574BC1796C8ACECFC0FA143DC69A95
+:109AA000E0FB4151311E0F731685FE36FF6C399E67
+:109AB000C03CAEB9BA862CFDF93FFDC19BB4E0A510
+:109AC000F93DAB0C1AF41E3FAF1F556B2D4F2CE523
+:109AD0007A06E9B3F02681F10D0FE8F7A877C8C53B
+:109AE000F211CF38F27BE6B9FAF17B9AE35C48FEDB
+:109AF00084CBDC048F86C302E1517A5E772C8C7CA8
+:109B0000F32DEEC7D42B226FC7D0EF33C11DA9535D
+:109B1000316FAE5B45FB37EF709A8278C5E4AAC916
+:109B2000D7FAB99E9A38AF9E1A8D61FCA9FAB02770
+:109B300082FE971542EC12178C2F64578F4238A57E
+:109B40004FE371E0C0185685F45C79690EFBF7208D
+:109B5000E6ABC41E41DD2B041BD385F14A97C4ED4F
+:109B6000B8C475144F7181C0C438A68B9568A8BF5E
+:109B7000BABC117A7ED5C5E9FF6B2EEE8F5CEEE2A2
+:109B80007C07C093403A31EDCAFF1C169B85F02B31
+:109B9000D0D40A2471C9E78C0BF8B87C0DAA3B3DE0
+:109BA00016F9BAC8658F0FDC03EB4795E2B3640181
+:109BB000E9F3AE1CAE6FBB72F484D58E60C1EE319A
+:109BC000B2859E9BF2AFE7FA74B07DFC318B5EDE0E
+:109BD000B28EE7EFC1CF299CAFDB986F4BC94A6FBC
+:109BE0007FF6C2BB726CADCB321F772842FD9689DF
+:109BF000B1A5F83E45ABD2707D72618CF0E3AB2E1F
+:109C0000CEB75BFC7C1C170006FD24814BE726EADF
+:109C1000302E61C4D1B44A8D91BE9BC322CDAC1706
+:109C2000BF00EFBE6A1DCF8C4B38F3EC7AF2E8D65A
+:109C3000CBACAE14EDE8EF529E5DB5EE51D08FCDBA
+:109C400082559487B741F62A88D7DF945AA3B8394A
+:109C500066BEEDA7A2AE338C9F314D63EA45F41783
+:109C6000FAC7F6F7694A5E1CFDE2008EC9DC3EAD1C
+:109C70001A8FCF0D39BC5FAFB78AF8AD206BB6BC79
+:109C800085B01C23FDCCE58D929D2E61DE24B4931E
+:109C90005A4BC88FD09BB700B042FB28A411FDA53A
+:109CA00082B0C7EFBC85F6BC0E39C79E3F19AA8C9F
+:109CB000513F9FC0DEA1FC31F319CCFD917D2C9169
+:109CC00042F3E67E262455B4A737147E9DB5076976
+:109CD0003E71E93CFAA2CCB8BF0AD320287F93DDBD
+:109CE000705E39EA1C27B400E46E3FFC6DA0F6CC30
+:109CF00027AB5D16BA18F83B997559FC09BF442586
+:109D00001CE9FAEC39F23F935E84FD19FEF54E43EF
+:109D1000BE7F224728DFFB139F9B615E4D5D86D28D
+:109D2000887A86DE20A8B80F4B5AAE49473C5F724E
+:109D3000480A8A61636382281F6753FCE0DF5CDCAA
+:109D40005E607252C6752D290BCF42BE237D37420D
+:109D5000FE0416700BA8EF959795C4C89FECAB74E2
+:109D600021BFF8EDDE8934EE6ADF2C19F9D84B2ECD
+:109D70001E87F8F0B19F4D6230BFBA1FFB5982FCBD
+:109D8000127137CA87D54F491437B9E5A77ECA077C
+:109D90005FFDC4DA87E7423FC2CFFD341FE9899BEC
+:109DA0001EE1FEA73A9ACFEA67AE7D55C779BE2974
+:109DB00051CE705D2DE75B6B3D3C6EDDED773FBCBA
+:109DC000D3B2CF263CCCF2B2967023EAC9ABF7846B
+:109DD0004B90279AEF57CBEC6BE8B75A02CFF9FDBF
+:109DE000F09B6E83AF9EF2F3F88BB067DF625A6729
+:109DF000FB575DB84EA13EC37D1CE073DC801BB4F5
+:109E0000A3F5E88F0AF111507FEA5181AFAF7DECE5
+:109E10008E94308EBFC3BD94FCBC3C5F04E6FF351E
+:109E2000E4E3CBF6841B8742BB654DE130C681A6D7
+:109E3000FFF4C78124B77FC8CF702BFE0AEF6FDB1A
+:109E40007374D61F711F42DCAF70CB4F3F6F9C0AFB
+:109E5000E55BA67BBBE746F07BC9463FB73C79C2D2
+:109E6000FD4B98EFFB315F550AD4DFF6ACCBE66FC4
+:109E700078BFE3B81BE7F73E2C5501FBA0F465BBA8
+:109E80003F824967A9FF4F346F02FD19CEEFE133DE
+:109E900037E2DF6DED1BC80F74DB531FBE8B7CE414
+:109EA00036879FE27DFC6508CAC5D7C6EDB7D2B735
+:109EB000DB1F44FFB4E9BF582345D351BF607B0685
+:109EC000F56B777D5AD3316E3FD28221D73F7AF638
+:109ED000E3ED3A8C7FEA890FB6EB00D7839F7FBC16
+:109EE000FDDB08FFE75214C4F7DB1E3BBEFD5B50F1
+:109EF000FEF0598F8878B3FAB1F7FE0FD6FFF51749
+:109F0000A332517F99E0E6F2F2A3F0A7D92867EFD8
+:109F10007C6EE660C4CF3B9F9E3E989D475FFD08E8
+:109F2000F02BEEB1D26B9CFA519F15501965EC578E
+:109F3000C6D3B17FECE56E37F2C1BF0AACBB19E006
+:109F40007D6BD5A76ED4330E68AC1BE1F3C25347CB
+:109F50000F7C0BCA1FC27E79FAD92F58D93091FCD9
+:109F6000EF896118B7BBF5A96BAFBEAC149FAE0803
+:109F7000767F1BEB6E44FDCFF9DD6D878ED23E2BD5
+:109F800022EBCEB9B49F7AC6E17E9BE167BAADEA17
+:109F9000C4BBE89F72EEE387F8CB94BEFB788DDB01
+:109FA000EE87FAEBA3D7A527B0F2A941FDEA67E651
+:109FB0003EAE7D7AE179ED828F1C743C109C57197E
+:109FC000FA749E5B5BE2BE04F1E1F1471E00387E4D
+:109FD000F48E27321700F3D18F3FC903A1CD4EBABB
+:109FE000BA17231CBA9FF3283BE19BD5CFFDC18D47
+:109FF000795D1F3DFD9A5B25B9C70202F0D78F58E6
+:10A00000CFCFEB186FBD55E085B56AF7AC77A1DF10
+:10A01000B5D0858EFBB3EB43F7374B7BFD7CB7C6E2
+:10A02000AF99ADA23C8A67D1BA6F8D73BAB835BE0D
+:10A030006F01FA4B9D70DFE6160D7BAB775F8532C3
+:10A04000DCCF23B310FF06DA4F73FD0AAE7F32CEAA
+:10A0500003F63738F0FEF6D069EFFEE6219EFD44A8
+:10A0600048578569B05E57B71BF98FFE3349D91D34
+:10A07000E9BBEF4CBA317D09E9DDEB6D76ADF974E2
+:10A08000E2C3F71C748DDF939E67C0E542747DE1E7
+:10A09000F57C3178D5A1D3EA92BE70AB9DE921FE63
+:10A0A000FC4AD843E71D5E73A9DFBF03F1E3451700
+:10A0B000C37CF379F92764B51F7DE055C04BD562A9
+:10A0C0000744CB4ED70F2AC5B82BC817B5174F7BFF
+:10A0D000EAA749E4EF37E723292F68C7260E8CF754
+:10A0E000526036E589B2A8DC85EB0099209C137B91
+:10A0F000E183FA01DAB137E1AF2AEA173E36A394D9
+:10A10000FC24A45F2D639A1BF503D4855DF07E4586
+:10A110009B40F1C255AC95DEAF66EDF45CC33AE806
+:10A12000E9C951DDDCAE9AA17491BEB246C2F8E332
+:10A13000C5EA27E6BC32E72CD051BF3883E7BF40E1
+:10A140002FFDDD90E48394EF25CA559E90357F4F17
+:10A150001531FEFBCE8B2E9A2F9E336174AE84C7D1
+:10A16000219B8C38E49B08678C47EE79ECB1C7B231
+:10A170000D954744BD3DF61BB447F52AAED7BC50FC
+:10A18000E3A57642D53EF24FFC4E48CCCCC2FADB7A
+:10A190008509DC2F16D9AF40B9A04599807AE42B08
+:10A1A000463E4C8152222EB5C8FD1B5B122ED47741
+:10A1B0006EAC2A198A72E5E1CF259BDFC57C52B2CD
+:10A1C00000ACB776D322CA47DFDE20F2B8BA2F79C7
+:10A1D000DD5D308EAA7918DA11FBCB3DB97742F9F3
+:10A1E000DD3512E5B1BC5BBFD38FF265DFBA473610
+:10A1F0004D82F7E143F05E1D18CE3B0D7B7397E176
+:10A20000477BC4387FB3C7387FF3588D4ACFBD35FD
+:10A210004554FF939A0895DB6BCAA8FC448D46E52C
+:10A22000A76A6653F9999A28959FADA9A4E7AF6AE2
+:10A2300056D1FB40B33786FACDAF6BAAE87D588F75
+:10A2400088280F1335D5547FC29D49F85CD0C228A9
+:10A250001FB900D8645AD042FF3A23FFDC4E57F2B0
+:10A260003A6B7CE584C1DF4679B89DFA3B21B23E6A
+:10A270000BF9CC75B06FB0EE025F490596A72F08B9
+:10A28000AB88DEBDFB522E57145FFC7E7C648CB322
+:10A290006881C48A2C7436C307650B5F7AA7BC3506
+:10A2A00017F9C33BA8F00F65EC7EEFDA3AF49F3F55
+:10A2B000D20DB639E24BC815DF8D7EC49458F368D1
+:10A2C000DCD72118C9817249EBD0F99675DDE6E13A
+:10A2D0007AC3A3197CBE935F90C87E8E378CDCB99D
+:10A2E0009E64C57F9D3B07F89A87BF03D2BE6EB4BC
+:10A2F0006745ADA956FB22BE0EF44AF2CB30FA7E7A
+:10A30000C73A85E8212EF0731CF024BB49DF2DEEFF
+:10A31000C4793155A0EF1FF5F1F96E5F2FEEC473CC
+:10A32000103B0CB8C59556316299671EEBF16F4929
+:10A33000C4C755A6BA27E17BF8C9EFAD87E113E79B
+:10A340000C1987794C540F4BCADBC5B49471B67E97
+:10A35000481E14C52D65F837668FC55F06FFC6B663
+:10A36000DBCBE39FB5974B12F6F2C483F6F2251DC3
+:10A37000F6F2E4B7EDE5FFF21872534DF2BC099D19
+:10A38000BD85F943C30D7E383C7944C054D2039A4D
+:10A39000B71BF524008988EDF2EEB6FBEDD4C3EFD0
+:10A3A000511CCE992FA41E4EA338DC94A4B3FDDA21
+:10A3B000B5D85E75F8F7F2AB3B66939D5A2A62AE4C
+:10A3C0001DBBDA979029F8B63576DF1CD8A7AB42CB
+:10A3D00052448079BDFCD05F8BEF846FF2DA404F3E
+:10A3E000B7E487CF5AC7F3B267859329B8DF5E35E4
+:10A3F00062B8427AE02C9E9B3CF0FE69C052701E0F
+:10A400009B3EE7F4973987E7899CD1D59D68FFAAE1
+:10A410008747D3798B5704551480FF06BD1C1FAFA7
+:10A420009AE6B2C1756EC865DBD7CBBAED70BFFCDA
+:10A43000337BD9323F430E7CB1F2BBABA4E79FE341
+:10A44000F64514FD30DB8DFC9414377BFE4FE8BFDE
+:10A45000BC3E8DA19E95C74EEFC37CA7682B8BC4D5
+:10A4600019EE73B216CBA3B7F2BCCFD15A9A3D8E78
+:10A4700062E0C368031FFE7877AB9847F42D31CABA
+:10A480000FDBC5F7CF6BC4639DFB5FB8D5B1EF7D24
+:10A49000FCB9F063D987FC26B0F3419EE72F4FEE5D
+:10A4A0009B84EB89A6B6A25F06F68775DABEB394E5
+:10A4B000619C3FAE79F2F728076E58533209C133D9
+:10A4C000FC3389FAB92131BAC28DEF0F2D8BA7C0A9
+:10A4D00056DD7077B7D088F131BDDD35B118EB7F2F
+:10A4E000E12A407CFE4C30C6E57E881BAA93425D83
+:10A4F0003FFAF4F0CFDCB67603C99BBCCF646A6741
+:10A500009631CFB5D37561BE3D148558565FFE3D7B
+:10A51000EE395144E2FB899E4415858D5FA750B901
+:10A52000BDBE959E91DD20CD8BF15CC1F0412857D9
+:10A53000465733929B4F562BF47E6203A376EAAEC6
+:10A54000A4807ABAA2B78A28DFA11DBD57744544FA
+:10A55000BFAA5A9F4C619C0F533E791CE4F17AE2EA
+:10A56000A39D1B46E1BEFF466C273D20C8FFEDA81A
+:10A5700056491F32F92CEB509A897F57A712FD22BA
+:10A580003F4F457E5C2B1AFC9CF345E22F05C86FBC
+:10A59000CF0845D8AFC0D4A72336FE28121FBD9BD5
+:10A5A000D3899735D5A2DEF68FE67F8B9DFC8F7120
+:10A5B0003A4EF50A5C4FBC003F2C67767EFECFE634
+:10A5C0008FB7A1F283FAA14BCD20FD501719CAAD68
+:10A5D000B83E9FDB05865FCB943B4EBCDC5563F7F2
+:10A5E000BB8FA8E6FA86B35D93C1D72436FEDE6939
+:10A5F00030CE688C5B419785BB18C9D770358BAB63
+:10A60000D0245CDF9DC0F3BA23778974BF0063C98F
+:10A610007D983F1A2EF3281487D059A07C524FEA18
+:10A620000D8BEF5A4FFC233C4462988730A2D5EE45
+:10A63000B764716E2F79E13FE42723A03FE46B51AB
+:10A64000E06B09681F6DB3FB55E27AE7BE3FA19F3F
+:10A65000AE328D21DF0B3BECAD3CA7FDE5804F9E7C
+:10A6600071EEFCBF70DDC23F9F8F9F992D8B8E785E
+:10A67000D980FCFC215C9791A76DF273F5F018D19D
+:10A68000F03F30D794BF9F9F8F4E0ACF23FC0E0020
+:10A69000FC109FFFC7F0F3BB410F40BE007A00EAF9
+:10A6A0006B263FCF5FDEFE7BEA678D3009F1F186D6
+:10A6B000C4B618C2E386C2550CFD823DFC7D8DA058
+:10A6C0004F4EEFE5EB37E86A851BDB1D9A18AF1597
+:10A6D0007AF9BE93CFFFDDFC1DE913F5D3CFCE9100
+:10A6E000DE4A702E20BA213A839F1968DF9AE71557
+:10A6F00002539B867F17D6599F11227B37EC35CEAC
+:10A700004F18E772CCFE37B962616F56DFB81DE5AE
+:10A710007492BD5878DE735878EE93D9F034CECF6A
+:10A7200039E2B927CB7EA6A8436DEDDE9A26537E8B
+:10A73000B1CE52232370BE83AAEEB2DA258B5379B1
+:10A740007C6D712A9FF7277367DC3B03BE0BD485B2
+:10A75000B7A01D7DD3EF243A6F1E1ACFE87C49675E
+:10A7600053C10EDD12776D36F811DAAD3AE6D37EBD
+:10A7700036069838BC2FCD0CA8304E67FD1DFC5C0A
+:10A78000D3611EDF1F683F3E75E91EF43F6FAA4884
+:10A790005D15B7D8356B32F9FD03EB32383F1BE757
+:10A7A0006B9D87E8262B4CC5F92D9119C53560E8BE
+:10A7B000A4508071AD8817F7EBE8B30B368FE1DB5F
+:10A7C00065D8F131F645ECF8372A545AFF89B7605D
+:10A7D000FDF02ED3AF3562BEE5191610D1FFBE1CB9
+:10A7E0000F4AC2F3ADEBC7ECC0F1EBA7B8A97C6C84
+:10A7F000E1981D68FFFADB04D26B8FB95AE74DC5AB
+:10A80000F759F9917A15CB9157CAA0FC66A090E24E
+:10A81000A2EFC90AE5ADE80A8F0FE1F9107E490CF5
+:10A82000237F8C6BD15892CF53732BFE88F8B36F74
+:10A83000522AF1EFAECB78FE7AD7BA6E99713FAA61
+:10A84000A29730F607372F9F083065279437B9BB9A
+:10A85000F7A3FDBF29E0C531E0A77BFF5350BF52EE
+:10A86000C9A4F304A7BC61035F6161E447D202623B
+:10A8700019636F5F9946EB59D2C6C759629E1B9503
+:10A8800063EE4AB0BB1ED8FAB18CF5EFA34F06C6F3
+:10A89000797FF95FA8AC07D3BB47407FB7CC3DBDFC
+:10A8A0001FF333E30B015187811DD0B6A53118C4C6
+:10A8B0007B2F80A8A741B9F296034194C3B8D81C56
+:10A8C000984FDBE97AF4ABA7374B0CF9E5D5B36FBA
+:10A8D00069C47A6F6D3A13B1FDEC1D07F0FBB43A11
+:10A8E00010F8D3787B2A4FF4517B59E9A6F255A58D
+:10A8F000BC7C7CEBC7543E50C6CBAFCFE6E5B997E6
+:10A90000F948CE5CC95AC92E99CDAAE8796AE17393
+:10A91000278172D869644200E79B77ED681C8AFD45
+:10A920008F73D379AD956D3F8B2CF5D9F8BCFB1C9B
+:10A93000AC8B682F9B9BAD2817368AED11CCDF912D
+:10A9400053993603E0B951685731C736BD79537D05
+:10A950003DD81BE946FD58AC2FA37A2A278B3EAE83
+:10A96000DF3FA5B7FC8CCBDFC0CB8CECF3FFD8303E
+:10A970007C26DAE7E9535894EE13615C6EC12B9D97
+:10A98000F42CF87DFDA4DE7954A6BA8D7B20783BAB
+:10A9900078F5336CF756E5B24D68577535490AE1DD
+:10A9A000ED682D20E30263D100F2A37BF74D09A0EF
+:10A9B0009F2F7DC3443A7F0CCC5BC1F8CDCDC9D667
+:10A9C00059E8175DAD0BED28773A6546719A0FEAA5
+:10A9D000CB551D9A4DCE184178B42419DB3C05E0C7
+:10A9E000B64AE776DE2A6F77079E63B8FA07FC3C23
+:10A9F000CC51B97D1EC2B5EB4149AD85EF925B9755
+:10AA0000BD3205E97897A4E0323A9B9605900F1E77
+:10AA1000655B886EF42689F2B229CE87F36992B815
+:10AA2000FD6FE4AFD0794E58DCF19CB886F1BDA340
+:10AA3000829A7F1FEEAFC12F525B7EFE4DF437F737
+:10AA4000E46915B3F86E8B9CC3BB7D70FFD39A2469
+:10AA50006D7400F02185FBB3528BBF985EB02AC99C
+:10AA6000FB5FB24B88ABD0FFB1AAD6590198CFB2E9
+:10AA7000AD02BB4FEDDB7E59FD0E867CE016204813
+:10AA800035D2B79E62A3485FD01FEA87A784F8E655
+:10AA900032E4E3A36523BFCD311F3941F0B939AAB0
+:10AAA00018F9418E7A9D1D28B49C9F70D6A7ED2A77
+:10AAB000DF87FA0A037D4508F5AD7F63EE932C0F1F
+:10AAC000FACF05BB11E907E063D32372AD7A06F92B
+:10AAD00001B47DCF05B93D8BFAC28A7AFBF997AEF6
+:10AAE000B6E9A4F7CDBA8EEB7D41C7F75DA7B81FD5
+:10AAF000C1D41F82869FA00B9EE8EF7939E47A04C7
+:10AB0000F19775277C8B005F675D63FA0D349BDFDF
+:10AB10002050C0E55D85B784FC9E571686899E67E8
+:10AB200028D7CCC880F2EC1C5EDEF479D5E268B19F
+:10AB30006DDD363F038206F5A120B3FB19AECAE0F6
+:10AB4000F8F2C67A89F8D9895A97BA33D8570F8557
+:10AB50002F2EC1BCF1CE0D833351EF39817887EBB5
+:10AB60002BE779834E3D156A5CD9D0FEA60733C822
+:10AB70004F3BA7C85E7FD383820BE5C61AE31CEC6C
+:10AB800015AABD3E738EDC508DF24A9529AF638DB8
+:10AB9000E6ECFF8BF927E857E82F4FE7F967070D39
+:10ABA0007D36431448CFCDBBD443F726CD66C2F3E0
+:10ABB000B8EFCB60DFE3643F687F407DF50ADE15C8
+:10ABC0009B03FC16F16805E011DA039BBF7554780E
+:10ABD00004E120B22AF447AC6849B3EB3939FCFCF4
+:10ABE00097A9CF7E7A64CB8C4CF4F7CD5722B51C55
+:10ABF0008F6DFAED6C55207F4936DA1378FEB1D2AD
+:10AC000081A7A55F2F2FA0CD544E533EFA8C63B57C
+:10AC10000F4379B8E6FD3ACAC3CC3977523DE0ED2F
+:10AC200019FCDEA91F9BDF2B1521FADEAB76D716A8
+:10AC30004239572B223F7FA6BFAABC80F40430EDD7
+:10AC400094BE76E4420FCF771A7CA73D4FCE79AF02
+:10AC5000C79F520CBB3614A578D50A1FCFFF625B85
+:10AC60005DDDD67CFE378D7BCECE1CBC96E252A637
+:10AC70003E332DC37E6E364515CF7F0F1473C81338
+:10AC800080ED7A8B5CB3C891B82147FCA80F9A720B
+:10AC900064548A4AE31DD3A29B5D189C5035CAC7F1
+:10ACA000084CE7F4B7726EC94CC49FE44CB03A410B
+:10ACB0006EA6617BD23B12A4AF1C98A108CD2528BB
+:10ACC00067799EC0C6B12349AFEA332F8069E3A4F8
+:10ACD0007EE7A5E3FEE0BC04CBBCEA3340BE15E052
+:10ACE000FC8CFCE1D95CCEF5E93764979F967E5BDE
+:10ACF0004DB92994F6BBDE00A6A8B19016FA22FD44
+:10AD00000273DA72DE7EA3D180BBA06FBFB08A5A15
+:10AD1000130E62FFF3EDD91F271C709E3D70A8042F
+:10AD2000388CEDFD2E60C0AF8F1CAA2CD87C896AB0
+:10AD3000DF5F89824F03ACF702FB23A6F27D1F6819
+:10AD40009FCCF699667F03CCA75E80F59C675F0772
+:10AD5000FAFE32637C673F17BB0EB7515F709E757A
+:10AD6000B82CF4947DB1708D01DD487DE10A43B7C4
+:10AD7000E3F723537AC6EB577FEBB5DB96E4A11CD0
+:10AD8000EB32FC8FA6DDD6D5C6ED36D35E433B4D08
+:10AD90001F64B1DB72AA3CE87F6A2ECDE7765B1BAD
+:10ADA000BF8746997C635EA1AFD73EBB2E93E73346
+:10ADB0001D5FC2F3809CF6DA421FAF3F3488EB5F21
+:10ADC000D7FB62F3CA615E9DC1FBDCB41D153C8FED
+:10ADD00059C8E1E736591EB7D75C4CD9BC4840BFCB
+:10ADE000C9C4803DFEFA45ED36D03F510E67CB64B5
+:10ADF000B7D2CF24CA53A0E4B395651D8D98EFA8B0
+:10AE00004B6A15EAD52BDB5E737F17DABF955F4877
+:10AE1000723273CE5FCEA13FEC2FBA40FE30D3AE7C
+:10AE2000EBDA12A6B8F85AC5E2E7807F5D2ECD8D29
+:10AE300072B84B50235B2378BF0ED41719F333F548
+:10AE40004CB413170DA3BCF82E974A7ADC9BD9F9A2
+:10AE500064FF75CA600FA2FCF38964FFA1DDA883BB
+:10AE6000FD2C354CD7D01E999A3BFFC1548A73F7FD
+:10AE7000D883E477D837E92BAF61BFC77FEFA2B3A0
+:10AE80004AE5938BB760FDD1D7A01CC6F28DDBD10C
+:10AE90008FD4F98E87EA8FFE02442CB4BF2BDB4D92
+:10AEA000F74C75EE8332DA8D0F7848BF6C70A9DBF2
+:10AEB0007D08B777FC0CF341D00E8D79300E0D0C68
+:10AEC00085EE37D445B40B811D66733B511DCC9F75
+:10AED000EDF4FC1EFA4F28813F21F2F71DD9BC7D0D
+:10AEE0006C307F76D3B32B85EB59E6FE950EE2727C
+:10AEF000EA33C5CCFF6079C8971A5218E1C989AB0B
+:10AF0000C4B8359FAD479E05B8BFA221C3D4DB228C
+:10AF1000D791FE3D375B44381F8A2E4BBD04CA755E
+:10AF20006DF922FA6546A6713DEDB51905B9E847F8
+:10AF3000FA79BD87EE013D126E9F877A9B2E78DBF2
+:10AF40007743FB7C6F6C3EF693DF26B33AF8448B75
+:10AF500065CC001A66F3CA76BCE20FE294BCEDE859
+:10AF60000728F471BBF9833DD37F7F25BC3FB557DC
+:10AF7000A671165CFB1D09CF891FD18ADA119F1EAD
+:10AF8000CFF2703D6F9387F2E07E93F5F3A1CB8013
+:10AF90009E76312D15E3AAFA2E89F6DDB9BED15978
+:10AFA0007CBEF9BB97113D7619F7BEDDBB6FDB2B7D
+:10AFB0002AF47FB4B54246101D95397EADD953BEF3
+:10AFC000AB16A674D2A0CF859E4423DA1FEC0712DD
+:10AFD000E5057421FE20DEEF1176A2BE79B46D592D
+:10AFE000201FE0F6DEA3E5DB87C2BCD719F0A9433A
+:10AFF000BAA7386CA409E9E8BD0D130759EF075942
+:10B000009766DE2F64D85FF81BFA190DFB2297991B
+:10B010003F8EF3046D0FEBD81F7E371CF02377D7DC
+:10B020006F6BD14EC4FB32306F25D5CA1F896E3A83
+:10B03000E85E866178EF81827CB9BD1CED2505EF65
+:10B040001300B8E6DC69D7ABDE982B91FD3214FD16
+:10B05000AD91BEE714C0FE233FB40E7A29EA99975A
+:10B060009E941DE7F1D93ED41B57578E21BF88E22D
+:10B07000D0FBC26942BFEBEEAA7FA116E735CCB880
+:10B08000D7C0B9EE63AEB88EF5CBE03BB44B9DEBC9
+:10B09000CC697A631FDAAD80FE4A7A59DF75759DF7
+:10B0A0004C503E8F733DAB4F451BF1FD8A76FBFD47
+:10B0B00008CE79EF6AE2F7CF4CF5F173BA535BC56E
+:10B0C0001DE8F7BF94B5D761FCDF9515A47C978682
+:10B0D00030A7A3CC3933D2ADF77BB4A471BA2C68B6
+:10B0E0001261AB7AC719D19ACA34CBB8A3DA326DE0
+:10B0F000E5D1F1A1B6F663F6E4DBEAC7B67FC55643
+:10B100003FFED909B6724962AAADFDC48315B6F2F5
+:10B11000251D57DADA4F7E7BBEAD3C2579BDADFDEE
+:10B12000A52797DAEA2FEB5E6DABBFFCB3AFDBCAA6
+:10B13000E5ECDBB6F6A6DE6EEADB267C1A0DBAF984
+:10B14000769A68F8634516B7F41348E3FA2FEAF7DE
+:10B15000BACD4F2BB298A5DD370DFCCA98B9E0BC2B
+:10B1600079807586FCBED7C883D964E4C134187968
+:10B1700030F71B79301B8D3C980D461E4CC6CCD247
+:10B180007730FFE9931BF95908B015B6D3FD2B456D
+:10B19000DC1D306824E3F7A780DCC37CF95824A1C8
+:10B1A00063DC51F6D9ED06659AFD5EBD4069A6FDEA
+:10B1B0009EDFE0505BFDE0CA7C5BD957FC155BFB72
+:10B1C000D4C209B67AA75D722A959F5BE864B1572D
+:10B1D000D0AF52CDF47D78CF2EDB2A187E1CBD1C5B
+:10B1E000F30E5D5B859DD6F390504EA4F0F3C37FC4
+:10B1F00045FA30F3DA9951466500F3D0AFC6B19005
+:10B20000AE2F6C67D139D36F6FFCD14C3C573B509C
+:10B210009ECC09CC9351314F46CFB3E6C9BC6EECFE
+:10B22000EF49479E4CD7A6513BD7D3BC789E8C6C38
+:10B23000F8A37E19E478B59C556D16C99EE27E0888
+:10B24000D263602E5D193C5FA64B10395FDFE4D9F5
+:10B2500081F3E8C23C192C3F64F8C9D425A4179F98
+:10B2600030F2648E3D20519ECC51433FEC52A26E91
+:10B270006B9E0CE82FA6DF82F264D61A65675E0C1F
+:10B28000CD03E6B576AB4079316B7BBFFB1F9117E1
+:10B29000732268E8138EF82F53BB49AEE4F5C895C6
+:10B2A000642DCA25D5902BFF5D7931F0332305FD40
+:10B2B000D1A58282FE9D971F5AD93247EDDD87A026
+:10B2C000332F6600FFD6DFEAB71AEDE3F87895F181
+:10B2D0005E82D99FEBC70FF5DF152F6533E4E731A9
+:10B2E000EE3C1CE3CE4AAF7FC9E93F32FD4B371B32
+:10B2F000FEA539986F09E5D5D58CCEE3ADDE65F7AF
+:10B300001F5D91E4FE20333EDA3965F5BC0280F31F
+:10B31000F03915E56023B2CDDFAA9333512FB89EE3
+:10B32000DFFF9121D68E7E04F1E3DBFCFC9B576DA1
+:10B3300075535CBE8F1FEA35C29BEDA272BA36D23E
+:10B34000173F9C7EA7C16D7718FA4EE80CFA8DF274
+:10B350009AFE4065A5A2E834DE2FE4C417B3BD22EF
+:10B360002AD43E73CED659E837FFCB9D8CFC954E40
+:10B370003C75FA9316D26561587A6126E60D9AFCFF
+:10B38000EBEA8DCF3520FF2A197FD5EFC7201FFDAF
+:10B3900037918D80751E427B16E8E548F4320CA982
+:10B3A000B3FF353E7722DECBD893A700F8887643EB
+:10B3B00057DBB5B63C851538443F790AF7D7D8F343
+:10B3C000D507039FB0DA89E6734726C7C33307273B
+:10B3D000B26EF4BB015F47BD3C7BEBE904DE5F7DF1
+:10B3E000CB2E89F214CC3C843C66FE24898E871BCC
+:10B3F000F7620DAE74FAB7BA491FCC36F0A96BD715
+:10B400001D02E249F60E81E190ACDA9EA7D0D5F696
+:10B41000F13E6BFED5AABDAE4E2B3CB399256F21F4
+:10B420008CF71A7793FF7A13E015FAF9863BEA8FC7
+:10B43000A771789A700A1A700A3AF21536462A48A5
+:10B44000BF3F96C366233F9E29F96E7F01FD87DAD1
+:10B45000B441B885E593D7E41D85F7BFF0F1788E48
+:10B4600022C5B6A7E1BEFDD1437EF1AE7DB15199B3
+:10B4700016FEBDDA279879F4647F291E7EDF2DEC55
+:10B48000868076996795C07C563DD267EAF3A65DC3
+:10B49000D721E077CE76181744F8930AAF52594275
+:10B4A0003FAEC7BC978C5531BC977B7CCC47E755EA
+:10B4B0005907878779CF0793EE4E58F3210657DA5D
+:10B4C000F340C61FBC83EE65532ABC51C4F7F10E8E
+:10B4D0007866B3DB135C3F4F6348F71E473D1D3171
+:10B4E000417F79A98FF880330FBF458D533CAFA5BD
+:10B4F00092511CEAA6076FA7BCF27B7C467E7E3188
+:10B500002B46BA05F847701D670EF13C65A520E192
+:10B510004579AAFC545210FF3F38FBDB00EA73A7C1
+:10B52000921EDA2F335FFF2780EF784F64BB714F95
+:10B53000E413A09761F929D0CBB0FC0CE865F87C46
+:10B5400016F4327CFE2BE86558FFAB9A322AFFBA1C
+:10B5500046A372A266369577FAB83EA9A4697978AF
+:10B560003FFFBE2D57E4AD83791D2FF7D1BC8EFF71
+:10B570002236BCBFBF8BD1EB17D15DC6B90017EE29
+:10B58000A7E9A7692ECDDF82F49C8C1788785EFC32
+:10B5900064FCDA74CCFBF6F9857ECF33BC5B63CFF9
+:10B5A000374AAEE2F6616AC9FE40A1859E7F6EF819
+:10B5B0007D4EAD7251FDC6C813FDD67FB0867FEFBC
+:10B5C0001C67B15F26BC9D90135DEC877637ACFDA0
+:10B5D00006DD7B51CD629BD08E676D3C0E58E7FD3A
+:10B5E000780C9E179052FE738CF5EF55D419E777BF
+:10B5F000DF526201EBBDBAFB0D3957E737F49D50BE
+:10B600002C5052DCAB97E7EFD503F32D791A7F3638
+:10B61000DAA7E339718A77B300DA5900AF00EAC3D9
+:10B62000AFA3FF06E673E2459E17D1E98BA65BE95F
+:10B630006FAD5FB0F9DD9F37E087EDF01EC50A59A9
+:10B6400095FBDBB7E95EFB79B5CE26CE67F17BEBE8
+:10B650007D40156D0533703ED359A41EFB717ED716
+:10B6600020C7284EAE3337DB5D4AF327FD70E1601B
+:10B670002FDD6BB9B2ED9AB1D8EFD4DC8AE3BEAC62
+:10B680005EBBC6399FCF0D3838ED1DF3F9A951DFE8
+:10B69000A38FEF15E23C2E6BE8E37B859DD6F3F993
+:10B6A00050A6F3A917D2C79926AB786F8760F01917
+:10B6B00017F015D433EB56B19897FCCEC6BD70A8E1
+:10B6C000E720DD5E406F37E5B2A8F3FEDF983B5D13
+:10B6D000C6F5CF70C41B9DF2DB5936E5E7872DDF39
+:10B6E0009EA55BE8E8C41E89211DBDBFE7FCF73AB3
+:10B6F00038E9E8C42AEE5F4D2D596EA313D5CFE982
+:10B70000A4AB878EF2FBADEF1C808EF2918E2E21C2
+:10B710003ACAF767F5D2D11643DFFF5E0EE02BE29F
+:10B72000B591DFB412010D7079CA41FFDB1DF3CD75
+:10B730006BEB5F7E3718F8BE6548E4458C83E96F94
+:10B74000727F566A49F0BAE5E8A7D252290FC09431
+:10B750008394DA5280F3E928C2A7394E1CEDD951FF
+:10B7600078CE4321BD619761CF3E62D8B37BD09E36
+:10B77000A5731E11AADF8BE73A46E17ADA9FC7FC70
+:10B78000D44F16B012E4EB4773E2EB53711E5156DF
+:10B79000629CB70E9467A3B6C00BE967D3B93F7735
+:10B7A0004D09DD93B2D89F4DF3F718F7C89B72F996
+:10B7B0007B6D921BE5DB0D98E7487E9D44470D7C31
+:10B7C000E7D92AA9145FD75DB67BAC82209F507F52
+:10B7D0008D817CC3FB78B3A28EF3A36A5502F5D6A4
+:10B7E0002DE53C1E7E83437E65B1AA04EA13CB415E
+:10B7F000BE25307F25F95B85CE3B44648676AE530B
+:10B80000DE05F56B043A3E145286E03D4C7DFCECBF
+:10B810000E3A0290C58055001D45490F39BA6AD0CD
+:10B82000E645B82F3D7E764E4F03CB13BB9FBD063A
+:10B830001D6000B7D72BAA6EA5FBE6158E573D7C81
+:10B8400074203E08ED906F5D341FF4F2F603CDAB2B
+:10B85000A75FA39D933FFED9A7DAF0DAD9BF8997F6
+:10B860004B0DBC1CDED43F9E8FF373792C33F579DE
+:10B87000BC27C07388DF33CA0657F5FBF7A94CBC59
+:10B88000CEBF1BF422D47B502FE27A4B57B2C8387C
+:10B89000070FFFCB939382F5FBE1D50E3DD6382FF2
+:10B8A00038D0FA9D7ACE0EBF5D9FE9396F68D0FB24
+:10B8B000CDD4673FFCDCD063903F9C0FDE7DF8C2A7
+:10B8C0002E0E2F138E471CFD9B701B5E2F10FFDC6E
+:10B8D000E8FF7EA35E88FC612BE9BDEFA1DE4BF69D
+:10B8E0002BD72F7739E8F4FDBBF97D467FF573FD43
+:10B8F000F77B7BB8DF64782E8BE3B9FDC2E4EDA45F
+:10B90000571E00BA63186768B5DF2F877AA755AF4F
+:10B9100077D2A5AFE44ED22B8F1AF9024E3D1EE826
+:10B920009AF66F39EC1FEA9D47CF7AE81CD291193D
+:10B930006ECAAB77D26516502FD6AF00BA4DC0BCD9
+:10B940008F24AF700FE1FC88F417E77E81FC9A85A5
+:10B95000F55B162A74AFD03B03ECDF40FB61EEDBF6
+:10B96000383FA74753CFB820BD18EDA6CB918BA386
+:10B9700043F922E950FEDBE8F0EFD5F3848011BFF4
+:10B980001850CF6301EBDFA9E9ABE769A4DFFDCE77
+:10B99000C7FD8DC774AEEFF5E4538A3C9FF26AA6EB
+:10B9A00052FEB60462B67608C6993EA6FCCA4E3070
+:10B9B00096107F165CFB39E5571E55442A4F29D651
+:10B9C000EB5075D884DE1AB417EF1329FE364A4CB3
+:10B9D00048C86F72038434EC3296947A2EA981762B
+:10B9E00097B70914E733F330971B79983D7FBFC3AE
+:10B9F000CCC3F49DA1BCCB93808362063C310FB3D2
+:10BA0000B4370F7335E66106AD7998B7535EA52557
+:10BA10000F93F2320FE8E9948779755982F4C74E93
+:10BA2000232FF3EAD91B0FF03C4C8F285AF32EC773
+:10BA3000F33CCA9EBCCB082FD7F9CEF0BCCB524703
+:10BA4000DEE5145E06BB9CCA574EF391DDF8C1C219
+:10BA5000E7F6A09BA23C904F7048DB7E5AC5B4CA63
+:10BA6000956DB56ECABF1C3F92FC1D03E5915C2825
+:10BA70007FE462F335DF507AF231295FB3AD75F4BC
+:10BA80003DF5537AF335958C9E7C4E2A6FDB7157CA
+:10BA9000D3FE21BDF999C3B66C9D8D7A619AC4CB52
+:10BAA0004CAFBE12CFE998F5F919775D89F503E639
+:10BAB0006FA20D6D892BED54B85D9E0AF36D9D400C
+:10BAC000EF357F263C61E2D999F45E4F4707565126
+:10BAD0009CF0A3FE2AA6E03D0A6F6119FDCA370259
+:10BAE0007E96205B0574437EB586A958CF8A383C84
+:10BAF00052991EA7F331B15623EFF366A2BF939A72
+:10BB00001CC1B862FAB63A9EFFB94550306F7C79D5
+:10BB100052233EB6BA9DE77F76C909B2A74F6C2D76
+:10BB20005751EF3A98CEF33F5724F579FC5E102930
+:10BB3000887AF16A6FEC2ABC37E3EAEF0B411DBA51
+:10BB40003BD15A1ED0B83F224071FA2D12F93F4F17
+:10BB50003281ECE91506FEB3D6FEF33CDFCB896BF0
+:10BB6000388F9398E709FBF4D5744EC7A9F19F7FEE
+:10BB700013EF673D667C3F609E672BCFF36C30F818
+:10BB8000C5EA242378AD88F3BCCDBE799F3AE57130
+:10BB9000BEF733813D00A5155BAFA17BFBDF73B51D
+:10BBA000E6215F7B2F6CFE3D05A77F530960FCFDFE
+:10BBB000E6784618E5574B80FBA3576DDD41E7D388
+:10BBC0005763DE27CCFFE6F6259B71BEABB64A4C29
+:10BBD00043FF82C0E7A3EFE6F18DE3305FBAE77A77
+:10BBE000B7B08391DE69CFE3F4B1760DF370D14540
+:10BBF00081F49496E4799CA63C74E66982FD4379CD
+:10BC000099B9863C74E66D9E1012EE6138FEBFF065
+:10BC10007CF4C10BE42F94B7F9725B5D1DA2FFBFEA
+:10BC2000223DC3BEAC8A0B19782FFC941689E8B864
+:10BC30002123E6A7BF83B1A12013CFC09BE711DC6E
+:10BC4000430E55E1225E2A2D1631EFC2EDAA5A4A63
+:10BC50007F8FF3A12234DDD803EED8D66B10DF1E20
+:10BC600010291F1F16FF0DC4D759DB0689189F6EB8
+:10BC700008C7026F9652FC2513EB2B63D76C47BEA7
+:10BC8000A5E9791998577EDDF292391A3CCBE7661F
+:10BC90000AC817DE48E77AC971975A41F8B201D647
+:10BCA0008B7E7AE04F58865A65D314BAAF773DF64B
+:10BCB00053B8219DE2CAF9532BC56C80FB4857D578
+:10BCC000503A847FF6E362A49F57D3C336F9967F38
+:10BCD000F88A83888FF3F3AB56E2FA86ADDD9F7165
+:10BCE00005F49BBFA190EEDDD9247778159F0D6FE9
+:10BCF0002ECA6F6FFAFB9DF2F7FAF41EBF1FF1EB2D
+:10BD0000A8EE52F15EE037D64B2EA4D3F70456B519
+:10BD100093FC743C0FF5E40E9E87EACC5385762E97
+:10BD2000BC27460FCB948F39505EEAAA38CF4B65BB
+:10BD30004596EFF3FBD2C19A78F8DE19EADF9F7FD0
+:10BD40006AC671CC38404F7C00F349613EAAE18756
+:10BD5000C4F800DA6137A11D46F10146F18295C6AB
+:10BD6000F9B3950F3ACE5339FCFA7DFCF8854B04B4
+:10BD700064B34E7F3E282C145738037A238EEBF49D
+:10BD8000DFBF1CB92313F984E4E5F75B34D7E81A65
+:10BD9000FAF7EA0C3BFCFE9A26CDFA77958618F85E
+:10BDA000F8B45B0BA5A33FD6F8BB2BC75DD16839B0
+:10BDB000EE4783407A91A967AF61961FF3FE0BA10E
+:10BDC000B74C76BD80E31FA0F1D3DA7724906FA63D
+:10BDD00015313C49C406B72DD987E5C1952A9D5B2D
+:10BDE0004A2B82F959F0607025CCCFB25E33CFC6B2
+:10BDF00089776F1AF336F3079CF58D46FDFFEFF94F
+:10BE000003985781F870A1B84C4DC0C86794391F8A
+:10BE100030F5810BC561081F2E260ED3DEBF7DFBDA
+:10BE20000D85F38F9E38CC1E230EB387C761D6C411
+:10BE3000FF417198F81D02FD1DDF872E2E0E7353F2
+:10BE4000BBFDFE9A2F1A87F97340BDA8384C7E358A
+:10BE50008F8F7F1272515EE223DDF6F3078FB42DD0
+:10BE60000D2EB7C0ED9F1D9FFD91B11F6FAC5F46BA
+:10BE7000FCFCA471AE807EE0196DF1907DB0609005
+:10BE8000BB01E9F8A8A056E1BDA9173AFF7A5260B4
+:10BE9000BFA9B6F077677CD7E4EFCB5A387F77C677
+:10BEA0007B975D808FFFB3E2BD3761BC57413C6932
+:10BEB000257B276F2FE86342DFF8EE2D0FDAE3BF13
+:10BEC0009D531E708BB08EAED2335BE88A62839F27
+:10BED000A7FA385E6CFED6A030FE7D37FD5B3E9241
+:10BEE000FF6D4BDF1F8274557FD95FE8DCD231B024
+:10BEF0004751CF3AD63A7D1EEAB1CAFF1614E497ED
+:10BF0000771978F58150B5985FC6A3513EF5217C2D
+:10BF10007F49AFDCFFC19AE7534659E4FE57D2B9D7
+:10BF20007DB984A9998561B4B3D4CDA351FF6813B9
+:10BF30008D733D5A9EF5DCE83843AE5F285FB0CE86
+:10BF4000C0979E7C41E3EF48DEBB6F34CDFBB891D8
+:10BF50002F78DCC8175CB98BE70B4E54F87D7D0B4E
+:10BF60003DF18D884766BE20935BDD682F77311EDB
+:10BF7000973CB5BB7631E6091E37F206CF187AB783
+:10BF80009927CC6495CE7D9DDC6DCF17FC389D9FA5
+:10BF9000DF7C8FC53697717DFCEFCB1B8CFF96E263
+:10BFA000EE17CA1BFC7F8D10CFA700800000000099
+:10BFB0001F8B080000000000000BED7D0D7814D5EC
+:10BFC000BDF799D9D98F249BCD24D9249B908FC9B3
+:10BFD0000712BE3721E14B6E9D8448510117448DF5
+:10BFE0008876415444BD77A154A9C5664202040C29
+:10BFF00061116C438BB8C46003177B534BEBC7C50F
+:10C00000DB25A0B5B6FA868ADFD06E225082DCE747
+:10C01000467BB5DC7B6D79CFFF7FCE24339BCD078C
+:10C020006A9FE7BDCFF3A6D5F1EC9973E69CFFF7C5
+:10C03000FF77CE9C19E5B190AD32214ED27E747A55
+:10C040001921B2EAE8DDEA25247BAD7426E220F866
+:10C050007799FEF3D63CCBD127DD84644DB7CB1660
+:10C060005A9FF580B9BE8790A32FD37A4D75F8F605
+:10C07000D3FEAE3E6FAEA77F474FD3FE57558F27F7
+:10C08000D0BF4C0CF5F98414CB0221E55854A4A977
+:10C0900084C4C37F151072AEF158C54CDAEF288105
+:10C0A000F4D246F44FD2783BE1B29D908BD6900A01
+:10C0B000F577D3768F7BA15D5F3DF69BDDFA564524
+:10C0C00026AD974522274D1F38AF73E7B53964C2B7
+:10C0D000C0F9ACBA18D804BFDF1BB29E8914F7FFB1
+:10C0E0001E3DEEEE86BB5CFE09386C976F2221ADDB
+:10C0F0000D654D33800E8D16325A216466B385105E
+:10C100003AEF9941719F42A7783569AF939DB41D6D
+:10C11000349909FFFAF7CD2A6DBF91F645B2082987
+:10C120004D3AB6599B45C8F6A3F72D80799D0D8AE7
+:10C13000248E567537DFB400FAE96E176481DEFB92
+:10C1400052FB0E17B4A3749FDB4EFB3BDBBAD355F7
+:10C1500040CB97E1EF1A4254A0671A9D5FAB656E22
+:10C16000C809D79B5C85CEFEFA0AD982F56749B02B
+:10C1700069863090EED17426F5E4D5225A9FC3A685
+:10C180004EE9FAB43AB38CB5CBF30CA47B4EE42859
+:10C19000F2ED552A4FC403BF8609013EAA24B435E7
+:10C1A0007F201F463552F902F99B69473E81BCBD8D
+:10C1B0004CCB59549E2CF240FE9C0579023A5727ED
+:10C1C0009058F216CDA7719C1ED1F3ECA1F2356305
+:10C1D00008F98ADFF556058C1BBAACCC1C38CF9E0B
+:10C1E000F3E18A19749C0FD0792AF2C0791112B246
+:10C1F000815C0C942F0DE56B65BB75987113A617C8
+:10C200009728DFD2095906158584A4D70B6A08E55B
+:10C210008E54A5D2E74B45F23EA0AB6B6643DEF7EA
+:10C22000E978EB933D25162A7FF726895CAF02C497
+:10C2300097D8CFFF6D56FFBD49941E92AC1126BF13
+:10C240002AD6DF9B44904E47773C9F1BA1BF8FB1FE
+:10C25000B5EF4DA7FDDFFB411C69A12414F656E79D
+:10C260004640DE3EF1E7C906793A2DE773FA065DEE
+:10C2700022F2BBD325523E2A991221D308B1593B51
+:10C280000340C70B654EA2D17E2E7CF1F07228DFF1
+:10C29000B7C74136D0F27D97BE7927D2396827FBE0
+:10C2A00069B935B8BC13E4BDA7CD225868F98F49E8
+:10C2B0000ACE437FDE85B6BB6418B704FC2806FBB4
+:10C2C00045B4CB20C7F4D91BA6C2EFF44FECAFB7EF
+:10C2D00011B203EAEF76B17EDEA1F75969FFE7EA12
+:10C2E0002DA15A6CA77A60FEF194F6C152940F35D5
+:10C2F0003185903BE0FE34262FE9A558AF25D1DFEC
+:10C3000053AC4AB240C7FB29D56F98CFB9E69B9290
+:10C31000FC7410E40B3A3EFAFC159C4FFA78F5EBEE
+:10C320000F6AA826D8FBCB1941CA47E7C0FBFEC855
+:10C33000E5F5D3D7A6905EFA9CCF1A859085923802
+:10C34000BDF193F0E532A09B2504F68468C4554105
+:10C350009F974BF4BF88904BEFCF03BB4EED6146E8
+:10C36000B548C206FB45482FDAF1746AC7C1EE9F93
+:10C37000DBF36D01E89CFE844052C006AD93BA81A8
+:10C380005E0EFABFCB607F9BFF8C7AF819E821ED37
+:10C39000EFEE566BB7D11EA6137ABF415EB749BD0B
+:10C3A000A897DBA85E6AB4FFBCA8FADD498C9E3A68
+:10C3B0009D50B52C70A5E3A4F7FD0DE62F8C9CAF26
+:10C3C000F43F83507F8F81AF92BB9FAFF599419728
+:10C3D00095F6BF4D96B13EE461F2A8EBD34A5D9F5E
+:10C3E0004223D3A7C3F2A0FA74588EA14F8765A643
+:10C3F0004F03E643FBDA901E733E21A87F87D64B9E
+:10C4000046F954A87C4E8479B27990EA20FA9B8D43
+:10C41000F9813B7DF479958E92E3321D6771AB8C87
+:10C42000E3AC92175625D3F2B843ACFC7CBC88E34E
+:10C4300098E039D1914C9B4F523EA9A4624CBCC5A7
+:10C44000C9C7E05AEA2D999D4AAF65D3171E83EB01
+:10C450000BF18C4F53D5D5B399F923B9F0BC01F347
+:10C46000A0C3D9145BDFB0FE7399F185C8FE448187
+:10C47000CEA77EB74506BA129FECBA92FE44A8CF6B
+:10C480008FD18F4AFB4934D0656E10CB7A3BFA6B63
+:10C49000ADDEAF18BB5FA4B73399D9D92B1D4F7A46
+:10C4A000B299BFE9FA3889C14F58FAE970AE3AD566
+:10C4B0006543FFCAEC8DDE2E457F5E54BBCC64D64F
+:10C4C000AE5EF037950BFD749B1EC77FFF07099585
+:10C4D00028D26E0F115A1FD985CA4496B55A420206
+:10C4E0002DAF23DAD1EF809F6E104260573D6BED88
+:10C4F000188F2C772BA1AD02D81766B7AC0D423838
+:10C50000CE45AF44FA1CC6036DF93C3E67FA2E9047
+:10C51000CB544FE294687B922D9F4BE81F6F659C34
+:10C52000CCF45B228ACDE06787B397CBB91E0E6B44
+:10C530002F1B62DBCB8E14163FF6D9CB7A6A2F0500
+:10C54000F093D45ED2F25DBBA8BD84F97C557BB973
+:10C550008BDA4B286FA1F612F8318CBD5CDE68EDEA
+:10C5600036FAF72BB5974D71CA88ECE5D6B2821D25
+:10C5700040DFF3872CC8BB8F0F31FA46D349BF7E0B
+:10C5800000741DD35F3EBF92C689D48EC49714B980
+:10C590008A0CEDB6255B91AEDD2BAD58FF98B73414
+:10C5A00066FD470FB0F6D1CFD99E2C617D69B66F7D
+:10C5B0007B329DC7ED0F7EC701E3DA21906A885B6D
+:10C5C0007766FB9252C05E727B7CB7C0E4C099C2B2
+:10C5D000FC9FDECFDEA8F1E6EE62F63AFA79A79389
+:10C5E00059BB1D99DEDF14417CF8B6C5BB9FC0BCAA
+:10C5F000DCB7ADA0E53FA9F15E54334E4F3B97BB8E
+:10C600006D62D0355BE87F4EA8C681D7961A19E5D2
+:10C61000AFB5C683E5676A14BCB6D514E3F5608D83
+:10C6200017EB0FD54CC7F2CEECF68E78E0FF6252D6
+:10C63000A251D68D6B23C83477553ACAE39FB259BD
+:10C64000BC4EFF5C15E9207D8CD776C2E44EE7E74F
+:10C650009BC9361E4FF5A2FCDA9B2DA8AFD4EF8400
+:10C66000411E6FE7F2683F9560CB85B839CB42AC8D
+:10C67000D4F7A52D0E8421CFBA83CA13C4CD3B9B1A
+:10C68000670B10E7DCFE5DC12B42738DF96F95FEE1
+:10C690000FE4F58E75667FEE263BDEAC01FBD06ABB
+:10C6A0005142F479B747C923517C28FF3B9E15C8F6
+:10C6B0008F687D4FE4D7B248EFD7BC12D99F0FF3F4
+:10C6C00030DFEF6E5878348BD28178E4CC85D4DEBD
+:10C6D0004D720617A0595125459E0A5685A02F5C1C
+:10C6E0002607D0A8923BBD0EA910EC90AF693CBDC7
+:10C6F00071D28B653CBFAA92CF815D227EE1F2F8B8
+:10C70000C1E51A0CCF397D3E544F5E83B194F7F3E7
+:10C71000DBCFF5274F8B6D477E9C2C723FA074D8E2
+:10C7200081EE272D98AF908C80478E71BF2E2F05FC
+:10C73000EB03240C76C7EF0C801DA17438877614A8
+:10C74000C641FF952B450463FBBC755176C6B27498
+:10C75000487D5D77EAC4A4E386FBFF2B39D17D8E4B
+:10C76000D281E61013609E7A7B5D8F068B3FFF526D
+:10C77000D339E9B895E95DACF90CAA6F3C4ED5E91F
+:10C78000D8C5E9184DB7BC7A01F3DA8F76BCD1A0D1
+:10C790001581DE2D7629902F80DCB3B808ED6F2B44
+:10C7A00097FBA42F92503F7AD67B9F06F9FE9714F1
+:10C7B0001BF6B3B395E5CD7939242452FA174556C3
+:10C7C000A3DCBF4AE59ED0BC820425931C13CBFAA0
+:10C7D000B0D1EEA6F92493DD7596AC45BD38CBF506
+:10C7E00022DACEBAC96AE4DF0ACABF106D7FF60B3F
+:10C7F000AA91F4FE8FAA6C21C84FA2E53A8D84510C
+:10C80000EEFD54EEC3B4FEA3C8376D99A0073EE217
+:10C81000DDAF0CE4178D5F6D1ED09B9B65EF565A04
+:10C820005F9242F997D0CFBF1D99C41B8E61AFBAFA
+:10C8300087B1573A3F7708BEFF53943F3C3FBF2E26
+:10C84000BBD69D1DDA10CFE65BB29F0CB467698B37
+:10C8500055C1EA06FB523205C4F3CDE474E46BB46F
+:10C860009DEBB36F8DB1EDDBBF41FC9336D0CEEDC8
+:10C870006CFC7618FCE6EDB72510518638C7BFADC5
+:10C880001C9C63B305E95FE7F8F3F83353A858C479
+:10C89000FDCFF833A9FD74A8B352BF43E5F01DD90D
+:10C8A000EF4A31F88F153C7EA84B647EE99CC7EFB8
+:10C8B0002AA1F5AE84C0433E5A2E38E4752D9A68FD
+:10C8C000C8CF9CECFE241A4874825C4BB20BF2F980
+:10C8D000DF3A591CDAD55888E5AF3AAE87B91F1C44
+:10C8E0007C5C41D3B81E4F891E57C805C1EC85D664
+:10C8F00042BCFEDEAA344D073FF81B8BB705F8E8B3
+:10C90000A4FED760073A797BBDDCC1E506EE932132
+:10C91000CF90142996DD98EDB098EC5977038B3FB2
+:10C92000A03D31D891CAE6C22A18C76CE2AD877E15
+:10C93000A2DB6D94FCAFBA410F6806B1BF0CCDB954
+:10C940000AF6E1E60C470BC8C73DCD0B2742BF33C3
+:10C95000732A9B53285D6EB69300DA154FC4B690C8
+:10C96000D2C19278267D19E0624ED1348F3EFFF01D
+:10C9700082B5B74F8FA9DD101289095FD1ED667AB4
+:10C980007064F9E054A7C8FDF4807C70AAB37C60A1
+:10C990003E38D5C99EF755E5E2A561E555752D4AA6
+:10C9A0001C4A2E08CAC3F75358BC1E093279D5E970
+:10C9B000A0FBC974EE2787A3C392E441E9B02439F0
+:10C9C000061D96F07CEBF795817F84F176CB2C0EDB
+:10C9D000D4DB7D23CD1CFFF5C9A1CCFCD688E5D0E6
+:10C9E00031B49FEBEB97DF172D9F8FA72826398A4D
+:10C9F000EEBFAEF92EC469EB82221114C06D77BB75
+:10CA0000142A873D52C0E6A5F379694F3EE2B4DDB2
+:10CA100084F9BF9E8642134EFB19D7EF730D2C7E0F
+:10CA20003ED7B0D35568A8FF3CC582CFEF214AD38B
+:10CA30000C0C9CAE10A76D785A9B3E344E5B0BF5E8
+:10CA400023C669EBD93AC04871DA9E2BC469C7A6E0
+:10CA5000C6C669BBEB875E07886F1D1AA7ED3E1F30
+:10CA6000C6F62B00A78DB1BE41E5D60672193DFE74
+:10CA70007B2FFA10A7BD3B38344EDBDA2021CE1EC7
+:10CA80008DF7D791760B8C4BBB48C82F10D74C69CC
+:10CA900002BCB8A7BE5004BDD1F93C3A81CDBB154C
+:10CAA0003ACCA27478E2818D1A7D6E4B1CC3775A02
+:10CAB0004AE4DC4506397E3895E9735732D3FF697D
+:10CAC000C7D8732FD68E69D98072F237D463B80D68
+:10CAD000F4F8929BDDFF71B16A03FB3636A4B852BD
+:10CAE000A8CA5E9C6FAB86715F1444B4B35AAD7D27
+:10CAF0001FE004B44C44283F6B69D9CFF02ACCE73F
+:10CB00001F84AE69BB8F699B245A7F66ABA505F273
+:10CB1000F908CFE7BA65D9E6358C730561F8068C5C
+:10CB200002E8F4202FD3AC307C99C70A523AEF9731
+:10CB30008EEBC17A41051CE2C1FE766C7D2864E073
+:10CB400027FD677C9BA19EFE33B1DD5C9EFC82B914
+:10CB50005C123697A7BC662E97779ACBD3DE3397B5
+:10CB60008BD238EEA7917740BFF25042E19F5EC46E
+:10CB70000F72FBD6D122B5E05F15BE8E96BBDE2CC0
+:10CB80004FCAA99E536412CEBA7F5DC902BF2774F3
+:10CB900089F4F71991E8FB1F7C10EE57A2E46DE3CE
+:10CBA000587F2ED8CD7371CC3F0C87FFD5A7B2F13B
+:10CBB0008F14FF9B56B5CC02EA54B08EF1F9338F37
+:10CBC00015E3B3677A3BE7829C696522E2F4CF34D0
+:10CBD0008B682FE69454203EADEEF23F7E1D2DCFA4
+:10CBE000F758BC027DAE9BEA439876F893275FCD59
+:10CBF00006FB3F67A1E8033B37275F8D83F8D9A188
+:10CC0000786D30A76D7F65726ED06BF1F2B47EB92E
+:10CC100043D52E802BAB57A95D013A6CE7723D9F3F
+:10CC2000FF6EA15483DFE779AC2679F9875E333F45
+:10CC3000AFB9642E47E36ED1E594EBEA51BF3E5D98
+:10CC400047308F1FEEFE6451C041E7D691501D1D45
+:10CC5000CF6B34EEC6E05D53DF05F9F926BB95CC0A
+:10CC600025AB25886BEFA5F213A2F2731DD5A4673F
+:10CC7000603D0902615A7E604F02804B7DE36C7A11
+:10CC8000C4D201EB641AB5BF604F49365B9F74F0A4
+:10CC90003CE82F5D4207D8E3BD951E5FAD3C50CE0A
+:10CCA000DC45CB04E0B7BBDA2C6739656B2A0A9107
+:10CCB000C8F22749D40FE44E8FEF00BB2D2F194F38
+:10CCC000ECE017AAD65614423EA63A3E05398F9696
+:10CCD00047BDBD5CE9C1F60EA5B716F0971CB5B807
+:10CCE00017FC029102D89EDA894F63E945C65AC9FA
+:10CCF000B4CEFA0218FEF27E5CAB9BE683B0EED9AE
+:10CD0000D37A65B856771FAEE536E156E753AD687E
+:10CD10006FBB06C1B5F4FAC170AD0BA912D6976608
+:10CD2000FB2EA4960F8F6BADE2B8D60AB739BE1EA4
+:10CD30009067B7C5C6B5CADD43E35A5D83E4893B56
+:10CD400084CE62B87EDDF95FD730F99F9ED75F78D9
+:10CD5000A004F3FAABDCB1F3BF9D6D16CCEB6ECF44
+:10CD6000B4601EE706C484965764935008F15A33A2
+:10CD70005EE5FCEBC3981F7E44F3C30D31F27CA249
+:10CD800004C2B00F614785C307721A8D5FA551B504
+:10CD900002B9BE9BC623612FE4EDC3E057C18515E0
+:10CDA0009950E0F8D512A77F41052D76BB1FB7E15A
+:10CDB00054A3702C4AB208AC37D5A93EF4BB1FADC2
+:10CDC0004C6DBA4581CA2F875FD5801E18F05F1D54
+:10CDD00027CF6B882D279FA7FEEFC0AF16BACDF8DF
+:10CDE00047347E750FF6F935E257CD3C9FE374EC7E
+:10CDF000E1748CA65B1E005334FEBADAFD3F5BAED5
+:10CE000004BFFA13E05794CE9F2732DC76E71EB6B4
+:10CE10000EF375E3575D805F7907C7AFEE06FC8AB6
+:10CE2000CA7D17E05780AB0D835FDDC5F1AB9EC8AF
+:10CE3000AD7386C6AFBCAF1AF1AB2D83F06F307EF9
+:10CE4000E87CFB3C95C9F370EB41FE41F83F603D47
+:10CE5000488BAD07B7F2FCB16F3D68175F3FDFF558
+:10CE6000775A3F3F30B2F5F3555F75FD3C5531E1E0
+:10CE7000D983AD074D7AF9D36330CFE57B8410C1F8
+:10CE80007C20B215F8977B48205B6969F2B3B53610
+:10CE9000C873DB433BF0EADDBFCF06794EC981A3FF
+:10CEA00058FE79FB322C4FD95D81E5157B564F99A1
+:10CEB00005F2D26C57409EE5A0108675D8BB291D9F
+:10CEC000EDC03F61D1AB1E909F670502F2231F1298
+:10CED00054E0EFF23D961656FFDC26ACDF6721E00A
+:10CEE0002FFE44C79A48EBF7FEC812D2607C21CDD2
+:10CEF00005F9D9B9E305ED5B3927202FF847AEA72F
+:10CF0000D38E7DB409F2A68F05A23C2E03BF0C710F
+:10CF100022F0F105ABC6E8DE507B59BCF2F8FF63A6
+:10CF20004144BF3D5C1E703441C739D8F3E21D82D5
+:10CF300000CFAB209229DF3C0ABA513EFCFA6E5971
+:10CF4000D4FAB16B90F5637D7F03AC1F4B22AC0725
+:10CF5000079B2C85FD7C5ED12E8498138AC4C37EEA
+:10CF6000B7DC5D94CFB4C9E4274A189F1B77203FF4
+:10CF7000BDFBF3B15CB285F17BDAB1298F65417CF1
+:10CF8000F5A44036005D9E647CBDBFCD8272D32D7A
+:10CF90003C671B057CDB2828C0379DAF2BDB285F57
+:10CFA000B17EC31C902B6D07E3FB05E02BC49F5B98
+:10CFB000295F059413124FEBFD0DECFE69C7662344
+:10CFC0000E7EFE090B3E2F9ACF67777DB409F0885D
+:10CFD0009F516F3AEAEFC0E7F323E4F33DA9FA3E2D
+:10CFE0008FA1F97C0FB76747B78DC17D51636CCABC
+:10CFF00088F64BDD9C963FA2FD526760BF14BDF5DD
+:10D000000CEC972A33EE979A76279449A31DE39662
+:10D01000BEFD52418B0076EEFD78C514679E09B2C5
+:10D02000FD523A8E3B989D8EC67B674BDE91E16C3C
+:10D03000D2087136E9CBE16C53D262EFDF59C6E515
+:10D0400066A4FBE1F6B807C529F7B863E0947BDC7A
+:10D050004C8FEBE0A74C4C4155901FCF4C87DFE83D
+:10D0600077EE4F63FDFE8D5F53AE2B4AC27E78FE96
+:10D070006A85F60503E9D248E902F878038DC321F1
+:10D0800078DC26753A64A749FF310FB61273DEDBF0
+:10D0900037EEBFFAAA0107E8F3A7F52902E8DDBEDB
+:10D0A000FA454980833FA7E316DC5F289C5E7AFB44
+:10D0B00096A838A950238C8E9CBE1BA3EE7F9CCFD4
+:10D0C000AFC04D46446FFDFE18F47E3C2D06BDFBFF
+:10D0D000FCB59BA0BF2E7033BC21AF4C24B07FA306
+:10D0E00090FA5F3B2D2B41E20DE364D8FA9175BDB8
+:10D0F00088F8446183D95F2B9A2F0CF97221DFB72E
+:10D100004C880FF30385FA63F0EFBAFFBF8A20AFB4
+:10D11000C8BEF5CB45F0FF0ACF474833F3BFBA3F4F
+:10D120002F0C9AE3324A67CC273EE3719912E5AFA0
+:10D13000AD44EAF7F7F9FD7C4079B0C0D5ECB7E72C
+:10D14000CFB29AEC50348E418A0DF566FC37260E2C
+:10D150003110C7E072395C3B8E538C613F91673967
+:10D160007E3126B26C1E38A989A46B4302F0A181DE
+:10D170007843946E9348676502F0A191F1C5AAC502
+:10D180009B708BCD60BBC18FD412DC8744AA24C4B2
+:10D1900031F2A68F91810FF4D60EE08B552D46BE4D
+:10D1A000FC475A32CA6DB2287440DC6BBD7D3CA985
+:10D1B000F302FEF1E7DA22E8A7D2D1BB1FF8B747A6
+:10D1C00032E11FD17887D5FF7A6521C3BF3F011CAB
+:10D1D000E32F5D3FAB049C62A3287F524BDB1734E7
+:10D1E0009A7188F1651D78BF5C598C384634CE61E0
+:10D1F0009DFE525FBD7D3AE01C6171B913DA89DA98
+:10D2000018D83F15856B8C6F37972F812E9433BAC2
+:10D21000A6960E3FFEE8F1458F47E7E760763711A7
+:10D22000767D18E449B75BC4598AF62CE5BAB5BFD8
+:10D23000CE8138AC552905B6CF5EDE60877CFCA96F
+:10D2400090526A57A05550F4D1F2C3EE8216CC2307
+:10D25000492D8EFF29B7180FF1434A6D4112743FD3
+:10D26000D8F375FBB6A94646F9D1EDDC8EBC3FCCB0
+:10D27000C5FC88EA35C4053FCCFBDB51285B4FC5B4
+:10D2800029102F56FCE1368C33425D8217B08C504A
+:10D290005A208F0C810FEAF635DA4E0E671F6F4E5B
+:10D2A000FF6AF6F129B8DF90A74CE5FD15AC2723FE
+:10D2B0005A37D3EF8FB57E981E633FE908EC23E61B
+:10D2C000378A5B0C85113F31DBB781F6D12F02BF66
+:10D2D0000B69BE63415C4FED007EECAB4FB93E1F66
+:10D2E0009EA3498A0589E223B0EF30DA1E5A01CFA6
+:10D2F000760DB48B56C0B35D31EC21E0D9AEFFCDD5
+:10D300007691E1FF23B58B130F4744906BB039A999
+:10D31000F903ED22C831F035DA0E0CB74E30C02ECD
+:10D320000CB24EF0B24D7D341DF645CE5DFB4D087E
+:10D33000098993662233E87CBFBBC10ED0D26076E8
+:10D3400062EFBA8221ED4AB45E0361709F46766F48
+:10D3500015CCF77A6A222DD48477245C96403EDF80
+:10D3600048222A94EF4EF3EF00B99E9F30710334A8
+:10D37000BB51085403BFE9B41539BD1F47A3CDB550
+:10D3800055600F1409D7550057B3C07D8AD78172F5
+:10D390004896CAB0FF49201102789A1E9FE9E3DB44
+:10D3A000CCD75B67D17C1ED6C1C5848B99CB69F97C
+:10D3B000E97433FEAA5F69DE7ED1B82FC02EF4E295
+:10D3C000B8E1E59BFD74DC378AA14A1C275125583A
+:10D3D00057C9F508A5905F5DEB6638FF3C4FFE3EF0
+:10D3E000D0C7ADE9FE9FA69773E100FCCD2BA0DE70
+:10D3F000DFE81C5785FCE4F41F8CAE3A1D293D2262
+:10D40000423AD707FA67779788B015469FE7FF8CAF
+:10D41000F2BD08742CC8962B051887C5C9D6275AA3
+:10D4200009E6E383F5FF1B2AAFD26866D7E07A8C62
+:10D43000F20FAE3FA37659A20F1B5B14A759E83831
+:10D44000FFB946C1F2DE9A62AC7FB6C68BD7576A87
+:10D45000A6E3757F8D8AD7976BE6E27DBFAAF1615F
+:10D460003954538DD702D1F7068C6F6C6B48043951
+:10D47000AAB39195C08F56BE9F411FCF3BE90CA721
+:10D48000D1AFEFA62BC89F0356463FEDDF6D2C5E54
+:10D4900090DA47011FE10AFC4F7A4DAD0376A5CA29
+:10D4A00025AF409836FE90FF43D83702B758C09E4C
+:10D4B00035063E74D36BB9968465458B849F2EC325
+:10D4C0007DE95E88D35CBF3F77BE8E3EEAC5139F81
+:10D4D0002BDB689B44D187ED899884FB4EA6141DF5
+:10D4E0002509C886AE30E0EB76BF13EDA3EBBD6730
+:10D4F000EE7B90965F065980759275913094DDEBC6
+:10D5000092182EB73E429EA5E5B433EC7E2AB6E1D2
+:10D510005DB45CB63211F1242245C287A17C31078B
+:10D52000E57A93C0E226ED3686BB4D7A2182B84873
+:10D5300046C085FDA52E38AF2DA3E379295914A146
+:10D54000BF1FD9BC5DF5B4FE97CB6DB87F67FBFC00
+:10D550006DABEFA2D7A4F2FA65DBE875F7C95D1FE2
+:10D560003C401F13F4762414D272664ECB6F00AF8A
+:10D570002ECD60F966A3B7C301B668CF0329E87F53
+:10D58000CADF3E8EE5C381A21298527989E803BFB3
+:10D59000757896645AF7B067B0F7C592336CDC5F64
+:10D5A000A968D3289B7A611E52D962F5C1327CCF1B
+:10D5B0002E00FB0224D9A7CEA765BBEAC0F51FEA5F
+:10D5C000CF9233683BB575A10AF8429C42BC0CE788
+:10D5D000617E2D2D83EFDF27BE54585738922DCA18
+:10D5E00010CF1FC9EE48803CF148F622C01A89D5F9
+:10D5F0002BA25F2D3F114E984C9FBF39B0665A2D1C
+:10D60000F6134EB895CA853B231EFBC9C920781D69
+:10D61000B4FD27B43D7DCEE607687BA5BF7D36B45B
+:10D62000A7F31C0DEDD386689F7F94B50FAC353DF5
+:10D63000BF883F7FE230CF8FD6CB09FCB9477A9FB6
+:10D640004B067D3920784713CAFF053FFCF1631272
+:10D65000D5F754D1DB0565B2E95F6EA89E61DCC7E2
+:10D6600013C438EC2651C1F519F2B818023CE04059
+:10D67000B020890C918FE322BEC9CFC5F7DB7F2C88
+:10D68000A74495B3A2EE2F30D52FC928E0FC1B1775
+:10D69000755FA9A97CD3C9ABAAC04FDE742ABD129D
+:10D6A000ECE160E37BEB7D9B0AF7BD050A8DEF495A
+:10D6B00052C3381DE8C0CBDABFDC5045E79DEA62B3
+:10D6C000E56FFDF0178FD53AB1DE0FF6E525BE2FD9
+:10D6D0004AEFEF5B19CCBEDC9FA1EFABF6861BCB0C
+:10D6E000701F4200E4D772660EEAB1432001C813EE
+:10D6F0002CF3E6A2DECA05129625D9AB3DC8EC4054
+:10D7000000F492CAF3FD196900069484490C793E2D
+:10D7100076F607A28FDEFF8B88188278EA5F055FB6
+:10D72000C224D0F3F745C4C93A16AC7A6C226D779F
+:10D73000F0350BC6B786FD7A282F854413A1DF9FED
+:10D740009F1271FDA6E090FFB189B4FD8B7325C4D3
+:10D75000DFA3FDEF351E46FF83BF5BF45BB82F757B
+:10D760003EEEF6262F9DA9447F955C2E94A01F695E
+:10D770000E6E8057FC6E782D5409AF62157DA16C3A
+:10D780004777CAE3BBB2ECC5B3AF67F9522FE43FAA
+:10D7900053DA2AEBB04CF518CA37587C96EBA03C0C
+:10D7A0009BE55FD660E9EC7186FAF2CE52531CD14C
+:10D7B0000E7241E964FDDD4CD3EF2FB53EFE1895A6
+:10D7C0001472295238649C71A0469D00FE452F1F9B
+:10D7D000E47EBD63EAD5489FC3342F01FA1E762F3D
+:10D7E0004A1201E7CC88EDDF0FF0758317B928A343
+:10D7F0003C51B97CB155E4E59309D716F5EFBFD19B
+:10D80000EB5BDBCCF52F91D00DD77BE139EFDDB0B1
+:10D8100098AA8CD4BA581D67A097145CA48D03B93C
+:10D82000A964F49064522F831D2C62FB062487A602
+:10D830000A0AC88FDA0EF6D057D4751CDCC484F6F9
+:10D84000801DFCDD2C85045229A7A6EC925F71286F
+:10D8500020079D12BCD2E0CB95673BC13F950AB82B
+:10D86000EE4B24A5CE0979D9E41294873713DB3B1C
+:10D870000067FDA55540BFE02B087C0BE8F3976ED1
+:10D880004181F7C76A4FFF1AEDD5C3DD22CADB8994
+:10D890000C965F1F8B94BE358FB69BDA5880BFF70E
+:10D8A000E531BF5B5107382E1D9317DE639EF2C62C
+:10D8B0006272AF814FD62A2BE64153DEA847B9DE0C
+:10D8C000E86E9D89615C235BBF8D934307416E4F7A
+:10D8D00064D819BE5D65D5EC2ED49B13306F873BA1
+:10D8E00040800EBABECCB3100D379CFC5964FE7E4E
+:10D8F0006E3861A1615FEB11C98AFBAB2AACAF94B2
+:10D90000BD05F9933C730AF8AFDF4EB44BC9A0C70D
+:10D9100063BC4F037D237DFA3D209F8A64C4CAA760
+:10D92000E64A22BE77F005A9FC39F81D6E0F92BEBB
+:10D9300048AA0CD0F20B8A84EBA13482489E44CBD7
+:10D94000F34F8ACA561CB7D97ECE712798E45B6C18
+:10D950004C319515102263BE13653FC9A9F1FDFD39
+:10D9600015C0B80E4BB8BF4F53715D7D110E81DAF3
+:10D9700013B9FD38E026F367D8650DE30BC50AF946
+:10D98000DB34BE5EB58FDB85BD3C2F39D2F0DC7158
+:10D99000C0557EA93A7C02AD7FF53DD11B2EC375E3
+:10D9A00061E4B77D5DFB71C057A6542710787F995D
+:10D9B000CCB59AF2BB69EBDB2558571C47ED9E4A64
+:10D9C000EBC7FDCE9CE7CD8FCAE36E882A47AF2315
+:10D9D000CA1EBE6E388D4C8379373D62C1F168EF47
+:10D9E000B0FD0C4766047F8C72402DB3E51B606F61
+:10D9F0006F4FF827B083242F792BC8A323FC21C8AD
+:10DA000057F239391FE2037D5DB1C0C370C68ED3B2
+:10DA1000F630E8D1C1F32C0EAE38137A7D4219AC42
+:10DA2000BF8A04F08CC91E05E5BEE8BC7603D8DFCA
+:10DA3000B173D9FBF5635BB5B1B85F79E6EBA300D1
+:10DA400027D8E8B4210E51270408ECABD272985FB6
+:10DA50003D92E87B2D1FECCE2991AD5F505A786145
+:10DA60003CCBE3717FF2644F0A93BF702001EC70EE
+:10DA7000F3F529B80EF322DF1742BED0C6421CEBE5
+:10DA80007ADA3F0AF63BFD721FFB5D9504EE4718FC
+:10DA90004E203A50F788942D635E31CDC370026AF0
+:10DAA00037A679E8D5557814DB1FC91746D4FE1A76
+:10DAB0004E1FDAFE1A4F1A842234BF813C86DEB72D
+:10DAC00015D6A048A416F870238DDF50DEA3F2A16E
+:10DAD00039242C41FE43F39BEBA1BD9DD07CA810C3
+:10DAE000CDDEF17FC47E048C67AF20BFD1C8D4FEE9
+:10DAF000FC264F5EAD9AF31BFF2DF09C7CB7B7035D
+:10DB0000E5345B11813FD75A26244586F01721C89A
+:10DB10006B306F91F14AC727809E1F87FC6634BC2B
+:10DB2000F7E3C0FC661FE44156CC5396033DF3D6A1
+:10DB3000EB798ABA04E2AC4D9ED9F3A419908744DC
+:10DB40004AA0FC80677663D54C886E823BE6527AA9
+:10DB5000EE15235BC6805CAC12B93D0E890B0DF649
+:10DB6000C6D516FE2EC42F55108FD071E78B11B27B
+:10DB70001AE43A4514C16F468F7B1F970F57DD2774
+:10DB8000AB81AF8F78981F7B84F35D2F77DAFC8FA2
+:10DB9000C07861C110D6CDF2B85DC85BEF27B87E02
+:10DBA0004E425930DF5984E5AF57CADF5C125093BB
+:10DBB000591EDB00CFB9B18DC56B303F880FBEE772
+:10DBC000D1DFEFA4CF9938727EE712657B55FEC096
+:10DBD0003CBDCF9F5CA2F62F75F07EAC161200FA0A
+:10DBE0006C4CBBA518F62D6CCE49172D867590028E
+:10DBF000D1BF07E42537DB86FCCD5DC7F929D2BC50
+:10DC000093B62BB2B1B850BFBF8DD355BFBAEA1689
+:10DC1000060027D4E99A2B30BAE6AEF313C00D3ACA
+:10DC20006D95CF40FF07F4F99300BEBF4BA400BE33
+:10DC300097FDE5E91D12418F28BD0F23BDB339BD06
+:10DC4000B9FF1A297D67E7069E8A807DDC2061FE88
+:10DC5000AA55B2B26673C8809B5B9D5DB5F00A722F
+:10DC600074FB8769939768C836BB2030D98BF167FE
+:10DC700060DA4D89F01EA6FFD71E431C557BFAE1E2
+:10DC80006F81BD7898C61360176F247E89E121618A
+:10DC900009C65999AA9409B89EB26ADEEF68DC53A6
+:10DCA000094A0B719376DF3CD8FF5E99C0CA96CCC7
+:10DCB0008DDB605F7325E44718C76F60F585ACDEC8
+:10DCC0000EF5B0FF205D3DE94933D98B1031E021DD
+:10DCD000D43E7C00E32B94F32B81DC56B7CCED8350
+:10DCE000B36F9FA63D7F283BC1709067B8BD88AEDB
+:10DCF000A7F2740EFACF057BE132C8D32038C67F75
+:10DD000070FDD4AFBDE067D20C38C6133A8EE1CBBC
+:10DD10006238860FF567383BDC9F177831CF8B96DA
+:10DD2000A363BB7F80F87C4BBD88FEAEE0506FD50F
+:10DD30007DB4BF56B0C78073FCADAE6B4B7EBFBC2D
+:10DD4000D941DEE8F5F52C85E76BCAF5C5F0FCB9DD
+:10DD500012EE0B793A98920CF9C7368F2A651AE8B9
+:10DD60007FA347B5659AF9E18FE287337304FCC856
+:10DD700075C699E8A9D3EF5DCE87B7B85D3EC1718E
+:10DD8000A902514D837EEB6CCA8E2A90E7D7D9FB4E
+:10DD90003283F175B0F5069D5FBA1D3892C5F2C1A8
+:10DDA000FE2BF38FEF5A991D2E984E66CA49FDFD42
+:10DDB0007A33195FDF8D33E795FA7572266BEFAA18
+:10DDC000F305701F331C1840C79BDF40FDB1018F66
+:10DDD0002BC914B8FD50448663CA78BDD5C6FC442F
+:10DDE000E174324B9EDC7FFF35FCB9B7C6B3FAE86D
+:10DDF000E77E437FAE65A1E9B9458D2C0ED0EF5388
+:10DE0000FB9EEB65783351F1B9F90DBD02F0A170BD
+:10DE10003D417E28419F0A7C7BF78E87CF3E017172
+:10DE2000505A7129C3FF23B580A3495ABEB895FE45
+:10DE3000BE90F7F7239B5783DFEB05816CA0BFAB48
+:10DE4000D90B35589F8D531D28BF56A7F609D863A7
+:10DE5000AB9BC5DD340E5F9889EBBE01531CAED37E
+:10DE6000DD25912A7B69FFB853B2CCEF71E9F3BC91
+:10DE70007569AD359D3E6FD2611971AB9BE6311C62
+:10DE8000769C9A8DF14E0FA7CBFE36794902CBCF07
+:10DE900010979A68EF5CF35B5A0E6DB379217E3B65
+:10DEA000D8D63276256D17A4FF0D79FD8F6CAA3573
+:10DEB0000DE64DA38016FA5B4655ED6DF7D3F94F8D
+:10DEC000FAD7435B21AFF37C5B64FB0832199E46B3
+:10DED000DBE3EF3F0EB8F1F7836DCF252FA3F3D827
+:10DEE000BDEBF1EBAE02BD6F13BDA3E1395178DAA2
+:10DEF000EA4C86A77D2F53CF5754756C99014F9BE1
+:10DF0000B598AC8CC2D3A03F039EF63DD0C7C1F0FC
+:10DF1000B49A4CDD4F05E3202F3CE86478DA416782
+:10DF20000BDA91834E8E47A922E671BB3B435B21FE
+:10DF30008FAD0BE8785828FE56DACFF733192EB597
+:10DF40001936C1A619DB770B70CDD5DBF786900E9D
+:10DF5000750FE8781C6BBF2993E161DBA17DF91097
+:10DF6000CF57F6B1F680A7199EDFC49FFFC301ED1E
+:10DF7000CDCF07BADF6BD08F1FF076935E085502C6
+:10DF80005DC752BA02DDC6B4F931756B249D5EE3FC
+:10DF9000BADD53FB9BFDAF2B80BB057E0FF8869649
+:10DFA00029A29D794A30DBF9362E57CF73BD3CB696
+:10DFB000671181FD3DD63D8B910F643D417E8F7988
+:10DFC000F23F05E378F25630DC6FCC936B5F1F3B7A
+:10DFD00044BEFC7CA69DED1B5B21EAF9F2F3C0E791
+:10DFE000E87C39E5BA939520B79F52B906B95D34FC
+:10DFF000F74407C8CB551C9F9A7858138DFB319571
+:10E000004B53689247C771A904E3ACDC4B5763D903
+:10E010007A690696DBC4DE5AA093261286EB344B4F
+:10E020009A7D12C4CBA5A6F5AA9ECC141C9F759D03
+:10E0300019CF190EC7D90B38CE6803BD398E534896
+:10E04000985D6F7DAD10D753F4FA1E6E5FAE1288E7
+:10E050000FEEDB0B76DCB00EDBF1E855F19007B488
+:10E0600004170D8973EAFB80FBFA7B94E1DBF80768
+:10E07000F8B5ACB602DD9F5ABF1CDF5BB1265795E1
+:10E08000811EF764B2732D54C78E681CA127D380FC
+:10E090005F880E15ED986EBFA9FDAA37DAAFDF7263
+:10E0A000BFD267BFB87FD0EDD7D8107B3F47B75FEF
+:10E0B00063C07E09FDFE68DF3E6F16E2BA3430832E
+:10E0C000FD06C576F29B38B05F02E9DD40E579B127
+:10E0D0006F1FDAAF74B05FB83E205F0BEB181BEF19
+:10E0E00024880335EFDBB41AE4FA277BD6A0DCE9F9
+:10E0F000B8FF3F652563FFFAEFD90F32FBB57B0F01
+:10E10000B55B6583DB2D47167B1F7141569FDD0A8A
+:10E1100043FB2BB05B0BB286B05BBA7F85D4C99E44
+:10E12000629487283AEAFE8EF33158CDFC9D5ECE8C
+:10E13000F0A7A3DF9DC7E9F8E9DC93222C2D792C09
+:10E14000E10DEE1871E170FAF1ACD82B8C37EA478B
+:10E150007B6CFD9897F5F5EA07AC4B2F37C8F73C79
+:10E160001EAF4C88D28B421289037FDEF1A82D1E90
+:10E17000EC51681DD58B219FC7F4A2AFBF41F5A21A
+:10E1800023E506835ECCCB1A542FE665C5D08B4EB3
+:10E190009BAF07FD94E4477C7951D608FDD21E66FB
+:10E1A0002F07F34B0BB3985F599235885FD2DB0F83
+:10E1B000E2976ECB62FE6179D6207E496F3F885F21
+:10E1C0005AC69FBF6A98E747FBA5FBF87327B58639
+:10E1D0003A0077B2811F421C25EC30D2F3A9179B7D
+:10E1E00043BFA5CFFBA9C0C6AFD5329C61DC81156A
+:10E1F0000EA06BB45FFA1E8F93B6727E1ED3A85F1B
+:10E200008279B42DC67D34BA5F1A7720B65F1A774B
+:10E21000408A2F1EC22F6DCDE2386EBF5FDA6AE4EE
+:10E2200077BF5FAA8FF24BB5E8972670BF541CEA00
+:10E23000BC22BF3452BD3BF235EBDD607EE9C82025
+:10E24000FAF765FD92DEDF53EDECFDE17EFDF33F75
+:10E2500063D6BF155341FF8E70FB1B43FF8EC4D2A4
+:10E26000BF94EB8EE3FBC77DEF2D4A34BF74E32AE6
+:10E270001DE2DCD1F964F5F21E01F813BD1FC40ED6
+:10E28000B8A681DE714A96A95EC72BB6A6AB71A36C
+:10E29000D2FAF3152A2AF5463B7E64107F389C1D7E
+:10E2A000B78ED2ED783DB7E3FE2F65C7471AE75822
+:10E2B00047FD7DEDB87554ECF8E6CBDA71BDBFA72C
+:10E2C0009ACD7234E9309523A13FBE99F40B2A47C9
+:10E2D000383F2647A283AD4F497C7D8ACA91759409
+:10E2E00021DFB21FD634806E3A6D54BE10F7A3FF03
+:10E2F00037BC2F03F818C31D357CFEEE749F7314D2
+:10E30000DA7B8E5FF1DFF3A7DBD09E6C3A25E07AF3
+:10E3100066526E6F08F69791772CB81EAA55463054
+:10E320008FD41E215ED89791047814E2710C8FDA95
+:10E33000C8E75997788F27D67B46569BCF5FEB86E9
+:10E34000F5063BE675770BFE5C188790BE6E0CE811
+:10E3500063D22C1F8ED335C6EB019CAB2E99D9CF3F
+:10E360007E7D63EF6FB9AEFE22520776509E8AE73C
+:10E37000D68C1BC5E21CB53A88FECBA06FE346C520
+:10E3800088CBF13F0CB8C8A6CC5B1CB1E4E503C94F
+:10E390005F3ACAA00756B717C79748F6E0797A548C
+:10E3A000DA8B2EA7A2DCEC01FBBD46B0C8B02ED2A2
+:10E3B00021906238175213E2BDB01EA1E7FB377AF5
+:10E3C000F25BD8F9393496A3CF9FCFF14BC05515E6
+:10E3D0002AFFD5A3F2F57315D87EA56276BFD5EDD9
+:10E3E000AB86F60F470405F87F779AFF5AE0FF1BCC
+:10E3F00009DFAFC675318E537408618663E5F0FDA1
+:10E40000BB24A0811DA9241CDFE4E3A874CBEC7D10
+:10E41000C36C6A570CFBF12AF97349366F1FB5DFDD
+:10E420004B70ACD6A07D633E49B140AEA7045428E2
+:10E43000D7F9490AE262B388C2E86BDEF745E572B4
+:10E44000E928362F4932AC2758DD4C2EDF15FD7EEA
+:10E45000A86F9A79E13D90AF7FFF459C02F8C03FDD
+:10E46000299105B03FE6FFD5797D3AB78A1D32592B
+:10E47000A96A208FD45E0500C795642627BADC6C94
+:10E48000AD2946BBF1C79AF7D433D4EE9CAA89A82C
+:10E4900067ACF01EF4792C1765FBBE0FF38F2F0EBF
+:10E4A000C01626E25FFFBE7AC660E76ECEF66F0446
+:10E4B0007EDF11E832FD7EFBCA1EF58CC1EEE9ED70
+:10E4C000757C5CE2F393644667CA8746A3DDF88BEC
+:10E4D00055B3FBD0EEB909E0999F3AD8798C946096
+:10E4E0009A8D9667BB05DCAF3F870424887FE69250
+:10E4F000205EAFD4EF5C4FDAB1DD3CD289D7058026
+:10E50000A716A2FF93985DE27455D78997A95E5923
+:10E510001CC754386747AB24C50167FFF93A6A1135
+:10E52000CBBFE214A5C5E87FA46C05F5E427A304DE
+:10E530007DFDED2730CF0295C9C59AD136940B8762
+:10E54000D38FFB8649DBC18307297DF0484CD1601E
+:10E550002FA8FD52289FEA6B1C44A1A154E2F400AD
+:10E56000C699F6EC4018DED374151305EC8D501CDB
+:10E57000423C21BEB8DDA351BD7BECAF16539CA736
+:10E580005F7BF8786A27DE82FB201E4B64F82F2120
+:10E59000EDD5CB419FB36D88E71ECF79C811896156
+:10E5A0002F373BD738E0F9F9D31FC2F5CCBA931611
+:10E5B000CCC306F333CEA0858429DD36672F1AF24B
+:10E5C0003D4F6703BB6FB0FACD5ED2204C86E73378
+:10E5D000BF36D6516E8A7B3797D0FA2458DF097838
+:10E5E000F0FC91D30932E8D5766EFF67973AF09C3C
+:10E5F00092CDA7127F0278B2DE8FDE3EC9D68BF6AF
+:10E600005BF703C23798FDB75F12F01C8A976DEA7B
+:10E610001F817F47274E453A5B9476A2D0E7274C6F
+:10E6200008103FBDDACB42F8FE5B22E587A80CCF8D
+:10E630008717785CE22A1349B1414E6D65410F9C02
+:10E64000436C2BB211B037569A10171BE4768B200F
+:10E65000607F36FE3E91DEDF41DEDFA5512C9E0756
+:10E6600099985E0A72FB2ACA2DA530CA33F6432B4D
+:10E670007F6153FF6B54F9C0DFE13D65D83F3A96A7
+:10E68000EBA99DECC07DDE9FF1734A745C3EAF99AF
+:10E69000AD9317D7EFAA2C069CC1EF54216FCFA3DF
+:10E6A0001A32978EFFAA0A472FDB6710C4F645BCC3
+:10E6B0007D71AB0DF767EBF3296834978B4823E244
+:10E6C000BE5711C3EF940E457CBF7811FC6EDC0F72
+:10E6D000C1DF1F0EC10F31D6BBA2F7116466F3F381
+:10E6E0000FF93E8291BE7FDC26A879D9E02FB414C1
+:10E6F0005C87DCFBDD3959B1DAE971CBC6C4392A54
+:10E70000C84FDDA35E02F6CC129E81F26271523BCD
+:10E710000CE7174BBDAFA0FD5F2FE4437E2639C841
+:10E72000AB58D678D9197E05F711077859EE64E50C
+:10E73000B5B4AC205D591EEB0C592BE8382E757D15
+:10E7400073C8F8F20F34BEAC37C4977FE4E7FFBB61
+:10E75000BE1F7903F478D9BAC2D20DB4DF65E14C9B
+:10E760005B01AE2FD462FFBA7FB0CE5CA782DCEB38
+:10E770007EC22EF55EEB41DC522881F1D81D640E7D
+:10E7800096355E7686AF85F735E9F85959EE64E53A
+:10E79000B5029EFBA0FB197D3CD1FE6549FD3E2BD9
+:10E7A000E0E1C3F9973B3D7326D4C3BB9444FA6FB1
+:10E7B0007E3E109E37DC00FF9186FBF2502E06F362
+:10E7C00073DF5ABF8CC7A12C0E533BE2F03D532997
+:10E7D0009B78D97B2CAACAE23C221FCCC77D59CC9E
+:10E7E000BE7B480B1CBD64957AAD98277B08F2C9A7
+:10E7F0002F33FB6ECF969F86F79DAD8EB035A30C61
+:10E80000051BF3F0A5BC3EAE88D73B3BAFCD80F6F1
+:10E810004E567F07EFDFE2E4F5726823BC170AFB70
+:10E82000A9A07E096F6F75B37A9B87DDBF2D998490
+:10E83000686E499F4BE75C06E5CE67A11C5744888C
+:10E840006C2883FA7ADCFD65386B5131D43F41E5A1
+:10E8500004E8B22D99F79BFF2ABECFBBB366EE0446
+:10E86000A0DBB665228B7B6E66FB5AE85FF81A5A0E
+:10E87000DE59666B35AE576D1BC4EE7D90CD71864B
+:10E8800072B6FEB8259BED73DC923D74BE52C7EDA7
+:10E89000F86370FEC818B0EBECFC914D70DE08BD5B
+:10E8A000FE10CE1BA1FEF18753BE817E6D5D36F357
+:10E8B0006B1D153F70801EAE2341F457E4247B8FFF
+:10E8C0007C976FF996D1E00FB20B701DA8CF8F48DF
+:10E8D0004C2FF4BC41FFFDBFB399DFDC58FECE7B6B
+:10E8E000B04E2539A95BCE07BD7EBF1AF955662308
+:10E8F00071C2D7A7DFBA5EEBF2B9ED5115ED8814FE
+:10E90000A6F259C6E41370A08DE573302E04F91CED
+:10E91000F355E47302DB47AECB67C284AF573EB713
+:10E92000807CE6F7CBE71690B77C780E934FBDACB2
+:10E93000CBA75ED6E5532FEBFCD8921CF4380DF232
+:10E94000B26599C8F2B22F767A161BE2822D7FDD6E
+:10E9500059BD1CE4B5DC1673FDB7219BF94B69B1B9
+:10E9600066877D73D1766838FBD320F9CF825FA8A4
+:10E9700027BE0A18ABB68EEDB36CB06A9E35C0AF39
+:10E9800079DA37219E4B9D17B1C6B2CFB4FD45D67B
+:10E990009EE5FB7ABB06BEAE4994C568BFD217534D
+:10E9A000BD343CD73D6FAEA9DCEF7F36B0F579C5FD
+:10E9B0008D7E2ADA2E0EEAAFE4350E38AF64F352BC
+:10E9C00011717B6BE25A87F15C237B0E3BD768F3B6
+:10E9D0005286EB6FA27160CC7ABF18F3DCA3A7B2AA
+:10E9E000257E7E6527EA0BA1FA02F1997DFE1A1FAA
+:10E9F000E8E1CEC54C0FFFBFBC7F45791FFD8E07F8
+:10EA0000E46CCB5F2DB84FE683ECAA26D83773733E
+:10EA1000B66F7A4E797FFE121DF789896B9B21CFE5
+:10EA20005D23B808D8374B62E834BC07F3A16023F4
+:10EA30001BCA06F2F3540D4D7D460FFCFD436BFBE4
+:10EA400093F8BE019CC044E3C1D38005D0D46BFED3
+:10EA5000936D388ED3427B0ED4D7E784173450B9E8
+:10EA60003E05FE998EF3AE277F8EF5A7F83EFD2773
+:10EA70009FEC6C82FD3C1F0804F360ED3B09FA3EFD
+:10EA8000986A78AFE5F443399877DC616FCF015C21
+:10EA9000E6747CFBE98740FF1E4AF4B2F888F1E196
+:10EAA000ED25E35B8C7E69470EB3E37758D8F9AF69
+:10EAB000D1E35F9FA3BF57D93991EDD3F2951BF3F3
+:10EAC0000C8C340DF9EA1D01412D32E861DF7857D5
+:10EAD000DB997FE4E33DB53A13F75B2FB5B1F19EC7
+:10EAE0008AA3E3C5FBE2861CEFBA1C16D76FE6B813
+:10EAF0003DEDCF5F0B7CB9797C29AE7F49ED774046
+:10EB0000F9D46DE353A0ACDFFFA1C0E452BB3921BF
+:10EB100064C47BDE5E320AF3CEA57C7F21F57239B8
+:10EB2000C6FD877770FA1042E78D71208B33079D01
+:10EB3000E777EC66BE7C87CDF30E9827EDFF741C5B
+:10EB4000E7CB77E2BCFCBCAF98F3FCA9CE17FE1E66
+:10EB500006A57F8E711FB73EAE4773F4752036BE93
+:10EB6000E1E8727A09A50B1D4F35E7EB7074C17AA5
+:10EB70002AAF4B73FE0DE5B19F9F09667EAE61F231
+:10EB8000B7D4CEE6792A9EF3734DE290F37C3987B1
+:10EB9000C53F4BF9BE444AFF89B1E87FC5F3BC8D40
+:10EBA000CDF3B111F2FF43BDBF41E8BC1D0E821D84
+:10EBB00089DC2D6172D73672FAF2E7C69EF72178AA
+:10EBC0002EBD7E36AF6A7B15417CD78BE7C46CB215
+:10EBD0002B75F4962EDEDE339920FED1555FB80FEB
+:10EBE000DECBDECAE335FBA5F1444B65FBB9A84794
+:10EBF000079C04F1A7AD6505781E57773DFBAE99DC
+:10EC00003C6D5E6ED1847EBCE94C1EF35F6796B1AD
+:10EC1000734DB755C6AF34FAB1F50A5BBF1CA508F2
+:10EC20003CEF92175428709E5B0B3BCFAD52C279DC
+:10EC30000AD9849D479EEB7500AE6325FEA65BE86E
+:10EC4000BC3F587953F4F70808E04A83C5BB24EA6F
+:10EC50003CB7B72AE50570BECDF97409D7E7F16F67
+:10EC60002A2E4D2068B86CBAB7B60EE86E51022055
+:10EC7000BFCBEA4B84EFD3F23B0545B87E9672DDFD
+:10EC80007F5E86F32EFE5363785AFD0C1BCA67D74E
+:10EC9000FE7C8C93536589741BE29C2E6B10F3A051
+:10ECA0002E41F1EEA2A2781F61F5383E03CEF5CEDB
+:10ECB0002DA3709DA58B9F0FFE767A01E227DD9232
+:10ECC0006F019CBBA439D9FA636233552438A77A03
+:10ECD000F76C0DB610CECC5994908B7686307F7E33
+:10ECE000CB445CBF4949547640F9DB27AC787ECDF4
+:10ECF000D1A9D7E3F7C42AA6CDDB0BE7D29D7DDFF0
+:10ED00008EEFFD574C5BBA17F66775BF1F87E50698
+:10ED1000CA6FBF1DF2016AA1E1DC417AEDA6FEA92E
+:10ED2000FBA87F329C47D3FD1BF94DC0BF1FB2909B
+:10ED3000A006FE9D68229C9BB3D326BF09F9CBF9A0
+:10ED4000745169C17905D3D9B93A4A06BBB6F36B98
+:10ED500058E4E7EDA443BB9E7C1D17F767409990EC
+:10ED60005EBC6EFCC282F9C371F722CC43CE060BA7
+:10ED7000F13D23AAC72EA047D3814211F4F44C3EA3
+:10ED8000B3033759424D707E157997BDC770A18D79
+:10ED90009DFFF6E7598E16C07F16DD5AB709F66556
+:10EDA0007CAC4D4A81FE3EF66DB365D1EBAEAAABAD
+:10EDB0004A41CCF473065AE17C463BEC4B95F97919
+:10EDC0008C1E7E1E233B9FF1109CCF48EB7FCAF325
+:10EDD000A5769E2F3D57A362F970CD5C2CFFB2C67D
+:10EDE00087E5176AAAF1FA528D9FAD37D6ACC4FAFF
+:10EDF0007FAB0960395CB30ECB7FE0F398BDA56AA9
+:10EE00001BAC8FADDA63C1F725C61C38FA07781F33
+:10EE1000F51E227A61DCF7781EBF13DF93A56588A3
+:10EE2000F73679440278D93DD3A7A23C2EE854DFC7
+:10EE30004885FA7984C07AF33D8B2D9877DF35CBFE
+:10EE4000B10FBE4B73D79E63B9DF837A55C2F78A81
+:10EE5000883778E723B4DCB47031FA9B16AB628153
+:10EE6000F79FDECABBE873D040718795D4A578A11F
+:10EE70004CB4B9546EA7947DB2EA395AAE79AA67F8
+:10EE8000BB83D2555E58D6912A43F957582E4AACC7
+:10EE90004CC4B845FBD5F6E3B07F568C4889707FEB
+:10EEA000DED4EDEEB1D47F8092CD84F277E53A09DD
+:10EEB000C6CBFCC47F857EB55D93E07B7B273A9211
+:10EEC000697F6FF1FE27783EA9C4E7F3F22425F9A4
+:10EED000588AA1DE5B2CF07DCE3DDBD522181FEBDE
+:10EEE000FF4CA807FB53FD1589A3E9FDEBF2A66FC4
+:10EEF0006F50063EFF6481F728E084E79BD87E1DB3
+:10EF000038E60BE8E5D2C684EA8481F6A46B06C134
+:10EF1000FDB37AB9C9AADD09FBD6BBE2D855FF7D9E
+:10EF20007921F31FF7E7B16B531CEBF73CCDF75B8F
+:10EF3000F207F6AB1430BBDF94CCFAA1727E1BDC77
+:10EF4000BF6C71BA0876E1A4EFAE7838AFBEAEB947
+:10EF500000CFADBE98CBECE789AAC21CC0F39FAF2F
+:10EF6000B7E3BA4A57BEB200E24D4D70B4EFA7F70F
+:10EF70001738FC8BA09F826689C07C547F7215EC89
+:10EF8000555A307DC79B205765C4D10EF1EA4D79A3
+:10EF90004C0FBB5B67BF713DD88743123E67F14D95
+:10EFA0008FCE86EF339E518BDBC1FEFD739A9DF9A8
+:10EFB000A5DDF6D068DADF2B69CF67DDE584F7F6EB
+:10EFC000D4785CD7AD8FBD3FB83A8FC977C1C6A79B
+:10EFD0005D0AB523179C22FA8FED4733DF5450BFEB
+:10EFE0002B2520D15989D1E9BEE68AD65A3AA47A8E
+:10EFF000EE4F6EB60737B9205FD86C51A0FF2E6E6A
+:10F00000EFB466A105FCE3D9FA543CD7FDC2EE92F9
+:10F01000BD90AEA9FC7975F5ECFC582279E7825DCC
+:10F02000BDB0654AAA116757F3F4F7A9A3CE75D707
+:10F03000C8AB45E9FDE7B81BCEA1C0F3CEB3EB9F4B
+:10F04000568DE7BAE7B4FDBA02CBAAA357983EF0B3
+:10F05000FC736AEFF05CC351FDDF7B1580AE5FF699
+:10F060007BAFDDF0BD5798FF20DF7B9D799E7DEF64
+:10F0700035937F6F25FABCF43FE50A31CF79EF0A6B
+:10F080001EC3F3E8073BE7FD236B08CFB31FF47BF8
+:10F09000AF0D6F55C03996837DEFB50B3EF050062E
+:10F0A000FC15F0FCC7E879DD73B11DCF7BBFBF75E0
+:10F0B00084E7BDC3F71FCA067EDFD59AE6B6419C3A
+:10F0C000D0946FD64BFD2AE7337D83F35854C37336
+:10F0D0004607E3896A88CFC734A798CA634359A60D
+:10F0E000FBC7B71598EA27B68F33D54F7EA1D45406
+:10F0F0002E09CF34DD3FE5B54A53B9BCF37AD3FDD1
+:10F10000D3DE5B642ACF882C31DD7FF5F9E5A6FAE2
+:10F110007FE85D65AABFE6D21A53B9827CCF74FF3F
+:10F12000CD76B6CF86BCC5F4F66DFEBE8E4EA7F981
+:10F1300079CCCE54E6317AD9A9BF0919FA7325687A
+:10F14000F8BD0B5837D44CEB84340131DCF70DAEED
+:10F150008FC9D72E1E729D40C727B7733FBC8DFB4A
+:10F16000E18DDC0FFF80FBE1C7B81FDEC2FD30ED93
+:10F17000F77DF8CED6674BD99ACDB209642FC4B5C6
+:10F1800009C5EC38933438808796E334761EA7DFC0
+:10F190001BD640CE24A7F93C1E7956BC691DC55527
+:10F1A0009662AAB7B9B34CF519D505A6B273C238A1
+:10F1B000D3FDF145A5A6FAE8EFF5FD2C97E527DD8F
+:10F1C000447E13E4B7EF7B81BB048E0B6B150F43BA
+:10F1D0005CB74B6831BE4F40CBE1B849C37F2F309D
+:10F1E0003D8F30FBE65105C87FDC4EA90BF6DB10E6
+:10F1F0009FD46B5C477F9BE30595798FDD08F95AB7
+:10F20000C9E4F96FC0BE2FF22B11BFA3BC3B5761FD
+:10F2100071BDEFC15CC0E16E989C33E52E7ADFD101
+:10F22000DDCFF37317D9776A57F69DBBF85E00BF41
+:10F230008750EE14212EBEF84900BF37FBF9930E1C
+:10F2400011E2519BD58FE7277ED43C06CBEF83FF9D
+:10F25000413B6C3E8FB13558FA660DC4CF6D6C7F63
+:10F26000C4AA4B765CAFB3257A5DC9F4BA17C6550C
+:10F27000DE7F6EE3478DEC9C455DEF873B97FFD1CA
+:10F280005CE69F873B97FF513EFFE8F3F97F6433CD
+:10F29000C70F8444F0BC938840D66CA571D45ADE65
+:10F2A000EE648186DF5971291102B8E4C98208E64B
+:10F2B0005DE745126831DC57388FE4821DD6EFDBFD
+:10F2C0007EF400E62BDDF01D6A7A4B5D5B217E87C4
+:10F2D000BAAE9E7F87BA3E19BF6F32204EE13868C2
+:10F2E00037F84583BE9DE0FA7C81FBC50BF585A60A
+:10F2F000EF529FC8B3C5F40BD17E60C0774EA2FC1D
+:10F3000061ACEF515FD1774E8257F69D936EFE7DD3
+:10F31000F3917EE7E4D53C21A6DF1FCEFFC553FF66
+:10F3200046D83C637EE7A4EB7C18DBAF1CF43B279C
+:10F33000E198DFA37E00BE7342F9707768847E0F88
+:10F34000F29BB2A1BE7352D904DF07EF0A168AC638
+:10F3500075998FB9DFD7CF59A8CEBB713BE8FBCEEB
+:10F360003C76FE0BB5434D3305944F0DDEF38C9682
+:10F37000CF8D5F4CE990848171B27E5EEA47FCFBE1
+:10F38000D21FF1EF4BAFE2E7A5AEBA742F3B2FB51A
+:10F39000D97C5E6A57233B2F55D763FD7C515D8F27
+:10F3A000FBBED354CFF2BAE1BFD324BB8CDFD3FA78
+:10F3B0000F3D0EE4E791747964FE9D268D7FA7C909
+:10F3C00067FA7E573CC725FADFFBF3E3779ACEED69
+:10F3D000327FBFEBFC20DFEFBA61AC7045DFEFFAA4
+:10F3E000BFDE1509DC008000000000001F8B080054
+:10F3F00000000000000BED7D0B7855D595F03EF731
+:10F40000DC5792CBCDC9930B8470F280843CC80D3D
+:10F410000409887812220D0CE24504636BE526A0EE
+:10F4200006411B506BDA32E58424185EF182D8A1C4
+:10F430008AF486878D2DF54FAB33E3CC57DB1B4029
+:10F440004A67B4C6173AFDB5FF4D4004E49F89886A
+:10F45000959962F9D75AFB9CE49E736F48A83AFFCE
+:10F46000CCF74DF8F4649DBDCFDE6BADBDF67AED03
+:10F4700047AE5C819F1B199BEB1459289FD1CF1578
+:10F48000F8AFAF6D49A2DFC5D8E10D00E4C13BADD7
+:10F490005E654B4E152B82FACCDB22B9A2BF6BB551
+:10F4A0004AC752CB1853999D1D8427B33285A53284
+:10F4B000B674B473DF1681B1DA96C5C5D8EEACF177
+:10F4C00095923C1DDE3B584317B4F7B685D577B906
+:10F4D00006FBF9651E5486F213932C8CA5413B8ADA
+:10F4E0005596AE634CC08E64C66CAC81B11CC69A96
+:10F4F000EB99DF99832FEF944E1752B9E50A3CB789
+:10F500009465EF10A0DFBE4E9109598C9DEBE4F499
+:10F51000E8ED9B9FBF073A431174F6D58BD541C0E8
+:10F520002BBE74A53BB768F07D896C23BC4ED7DB3E
+:10F53000AA83D0DE56EFADEE5C5774F9076BF8F78F
+:10F54000E67E4A652BD13335C3578AF47FE3FE87C5
+:10F550009D88D70E81D520FD8F67F81293E13B7609
+:10F5600009EAA7335687048B40F26481BED3DBD906
+:10F570006BC237B34D508231E8FB389FF371C71827
+:10F58000EF6F73811FEADBA2F72043BA52EF5809ED
+:10F59000F0074ABC57007EB2CB501FF8EB4056E64E
+:10F5A000203E3DF9F8D4FB096E70D273DF068985E1
+:10F5B000A0D2810D1E829FD920D3B373433E3D7FDD
+:10F5C000B2C14BE587369413FC7846D7E178908337
+:10F5D0004F6F63A52AF4F3414670633CE2E163A5F3
+:10F5E00007B9D8B82B80CEB0C081C4CB890CE5A5B3
+:10F5F0006F4DE9FE2D306EF7CBE944B7835948CE05
+:10F60000FE8C7441DDC7DB447B26D4FBC6189159C0
+:10F6100024FC32D4B3016047409451CE986AEB0B7E
+:10F62000437D05FE5DC9C626D7869E063CFCE50ED9
+:10F630002908F5D37CD6BEB073506E99DC107A09D8
+:10F64000BEDF51E1F46D81F26FB088F22C44A1214C
+:10F65000F43E94AFA84960212F63A7C2BF912C4804
+:10F6600087D7CA0E66217EC6FAA9EAE26E0FF2D5E6
+:10F67000238D593C8AB1AFBBA4451500F7A5EEB365
+:10F6800013A926790696856D30CECD8A8FC6FB8369
+:10F69000FA15EDCBA8B52AE9743ED6F30B28D7436B
+:10F6A000C92F4EB4D3FA3C84EFFF753CA371DFEA57
+:10F6B0009DEA96419E4E66B06A9C673789AEB54713
+:10F6C000800F1794D92938D6153332324FC2FB2D0B
+:10F6D000F976E2B3244A7B13802EF6BF1DEC20207E
+:10F6E000D7DBEDCF4B8E90E3ED329727A03CDD5278
+:10F6F0000EF571FEBA88FF82C50374D40BCC15C118
+:10F70000D7CE7C91CF5FA6B82B80DE328D5E80C5D0
+:10F710004C001C1E916DF122DCC0420097F85D0D7B
+:10F72000C87FD6C3F9A98F1F13D7879E06BC3E8515
+:10F73000F113A17C748D71FC4A8E3F187A09BE9733
+:10F740002A9DBE44C0A3C4341EE930FEEF43F96ACB
+:10F75000183F1C7FF3788DC65FA0FDFA3257300446
+:10F7600070E37BAF4F391AA1D7B6C95DC7C642F95E
+:10F77000B61AE64539AE0FAE1570DEFE441E957A18
+:10F780003A012A14B122E43BF0D78B745C784BF435
+:10F79000227FA59C9013E5447A5E945468F7FCE5BB
+:10F7A000BF71FB809F67C38E6AE4DB671B7AA61C70
+:10F7B0000595F11CCC33EB44C6BA609E5901FE0599
+:10F7C000CC33845F807986F0DFC13CC3E78B30CFD8
+:10F7D000F0F98F30CFB0FC9730CF10FED50685E022
+:10F7E000D0866A82B757C6D747EA9FA7353D707162
+:10F7F00012D723BA7E0CEFE1FAF1C33DD7A61FC39F
+:10F80000A81F5DA8477619F4E39B9AFE3B3BA01F17
+:10F810000F1BF4A35E7E7E08FDF8F6A07E7C3B52B3
+:10F820003F8E60FEF89D387FEA879A3FDC2E5CEBC6
+:10F83000FCB9DB59618F27A165DE25998CADDCC54C
+:10F84000F5ECC9382193F49890BED69139D8CE867C
+:10F8500009DC5E85B73B6A90BE0FE37664C6933DD4
+:10F860004C2E1563D43BFB34603E96B19ABDBF7EEF
+:10F870004C05D29FB47BBBADD0EE9976E6DD47F365
+:10F88000241CC24903FA71DD9652C61ECA94E9BB14
+:10F89000B7B2D5077C80875B0EB375D0CFEBEF2571
+:10F8A000DF5C86F8B4885E108301BB3AD81F1FF76F
+:10F8B000B82CCD9E32EB29D48F1655605740CF8F90
+:10F8C0005F98B2A80C9A1EAFBDD7E7058B84C568B8
+:10F8D00038DB295B1A5C884F9826F7190B6BD80721
+:10F8E00078F6B6E46C44F8EFDB9857CC1AC43B6763
+:10F8F00021CB64D983783FD30F3A1FF1F6D882A881
+:10F900006FF6C5F9B74CC676C6D8CA90FE7DA50D70
+:10F9100099B746C8CFB22C4EC78749DC5ECE382295
+:10F9200052BF273BF2F66D2461F833D94DAB6637F1
+:10F930000F4EE272FF51BE57407BC6E42CB7AF18A2
+:10F94000EA27D96B681C050BF9276A87A303F538EA
+:10F95000C08CF4FACFC47D880FC8966C07395B85DC
+:10F960004D03DE1FB938BE8F6F11F701EBD819B404
+:10F97000DB40479FE4B37B23F89DC2ACAAC62711A6
+:10F98000F9B80A61274A190B5DD16C9D355D6B177B
+:10F99000F05C057215E71EACA7F33F3F1801C37F6B
+:10F9A000859D03ED125CDC65844B5E34C2A521238A
+:10F9B0003CEDB8119EDE638467BC6B845F47FF0B30
+:10F9C000F5BDCA4EE4021F2668F38DC9FD02DADFD9
+:10F9D0004CD4DFA04F5D2CDC540EB0AC38FB519FF3
+:10F9E00067AE073989C05B7EEFEC7B6C4AB4FCC81C
+:10F9F000EF25F45AE0FDCCB0B9FEFDF7637D9945E3
+:10FA0000BC077E6437F654E3787F5A666168E76F17
+:10FA10007185ACC83F65977FE77CE8FF668F48FE3D
+:10FA2000CC2B4FFF714D163C5377837F9A32382E83
+:10FA3000F3165B7C382FE76529711668C7297BEDC3
+:10FA4000D8F6F6CFD5BB502FB341FE5BAECC181C19
+:10FA5000FF546DFC53B57285B16EC4E73B9A3EBD51
+:10FA600079B6CDC0B7851E9B61DC6EE837F2F5C66E
+:10FA70004B4638A25F7D9E19E0E4F92D24E7171A62
+:10FA800059501486AF9F641108E9CC66166C063C89
+:10FA90008F835D21E74E55DEC171FC1AAFCAAAD92A
+:10FAA0005A2BDAE17A1847B48BF341D33C534672B0
+:10FAB000D910027855108C5B041DEDDF150FA31FC4
+:10FAC000A5CE724807D14E67D8683C9D9A9DFEAC82
+:10FAD00057388C76786FA5C7D724458F776A6EAD77
+:10FAE000900CBFA7D618C77B7CD9BA8A1C62B2F427
+:10FAF00031DAEFCCF2F8C3E86F495F2F041F015EE3
+:10FB0000573D549103ED4E509C1750DECC72A17FAF
+:10FB10002F557AE87BA7DCDF84FEEE7825BF1FFD3A
+:10FB200085D6CB0FD2F72AB0F0600CF91CFD50043B
+:10FB30009E8885A62FE9E73A9CCF281120022BBD8D
+:10FB40001559287FBEF800E201F39CF519F525EB65
+:10FB50008B1887D6F5EA22B4B32A7337603C147F3A
+:10FB600089CB636B6872A51DDED7BDB52218075D12
+:10FB7000D5E5FB9C4E2C6FAB4D41DD5517BAA31A52
+:10FB8000FBA93B30CD1B076D75071FFF9D08F52FA7
+:10FB9000740AB203CAAD97046A277B2523FBF06978
+:10FBA0004008A2BF5CD19965C7FEEE95D85C1CEEFB
+:10FBB0007B03A0F0D16F85DFE392E0B96D871FE191
+:10FBC000BA5C274B10101F3BB5933C3FB7D20EEDEC
+:10FBD0005C7C4B24F91ACA4E5A2F590DF3690BF865
+:10FBE000057D367CAA0AFA1F2D1BDAE859972F1FCC
+:10FBF000C3F9155FC4640BCCC3847C288FE06F5DB0
+:10FC0000AA6C17A0DC26F1729B04DF458C47769B1B
+:10FC10009D292964C7C83E32F5995B141E2742F01E
+:10FC200008FEDC848EC7D422B23B2AD2A3DB9D5DC2
+:10FC30001A3E43D91B6685FADC9E4A5B92F87BB478
+:10FC40005F7A7D779B5D41BD832E270341DD04ED07
+:10FC500005F306CB59BE4CFC6C071EE1F730DC996E
+:10FC60003EF0EFDFA855A64F87F71FB68A6C2354E6
+:10FC7000FD308B856EC4714FB3905DDB34A970AFDE
+:10FC800084718D90BECE5136C8BF4D9BF332FBA020
+:10FC9000FFDE6D02F9E72079F665A306CBFF3DCBC9
+:10FCA0004EFA57877B6BB8DF84F5B05F6695EC182A
+:10FCB0005FF48DE27668C9A34DDF56A0BD380BF323
+:10FCC000A37D5CA2D93FF333ADF19F9553C0DFD440
+:10FCD000C6DFD233EDB690DD0F76714DD7628F0A55
+:10FCE000EDB57E2ED644C6E3FAF366EDFBA1E4A3A0
+:10FCF000952DAECE42BADB20CE043EB4A6EE2479DA
+:10FD00003B3DB13E5DA4F911B02F2B463C785CD051
+:10FD1000F7D7814DCDE447B106D427A7BB5765E29D
+:10FD20003CA8DD5D9B1207F56B6F0BD8BF0FE56933
+:10FD3000F2CA0611E6ED3DA11FCEC379718F6F5651
+:10FD4000200E619F22AC003C574911F390217DBFEA
+:10FD500023BACCF331275322FC531B5FA1F277EC7B
+:10FD6000FD56CD6F91507E6E017144580443DD34D1
+:10FD700006E4CBF7C9D1341C37086A508FDCB6E4EF
+:10FD8000F3A32F40F9079285E099456A338AE47618
+:10FD9000B422506FFB4E4B10FD823C4B48447FA376
+:10FDA0002C9B824776030B8B4CD4F409D4ABBD2C2F
+:10FDB00005D17EBDBB609C3D0CF8D78249E9328DF0
+:10FDC0006B0D3C9F745DB062FDB3408305F03BBB9F
+:10FDD000F222C16A6A62FF44A0E3BE851F1FC5F913
+:10FDE0001E5CCA826C1CE0DF52B12915E0830CE274
+:10FDF000E8D900D78CDB84F998632AC0190097777B
+:10FE0000517EA60F8D01C2D54F1DC3FACE2687C5E0
+:10FE1000321BF3331FB7209C50E262C86FABD44F44
+:10FE2000F0CD5E0E37BB2E107CACCC45F4BF51FD3F
+:10FE300009C10B677298315E7FC16C17C575E79772
+:10FE4000BED43916E4C091CFF990B0F3E330C2B517
+:10FE50002D3BE68DA57E264DE56C19B05FF62B4057
+:10FE600007D99C74F29748EF6EB5747919B4B772DC
+:10FE70001253AA20EEDC2A74C90CFAFBFA33A53B14
+:10FE80005A66824FA695BF95A79773BDF1C0A40F80
+:10FE900096A8C0DF0451D323EC3F96A01E81EFA9A2
+:10FEA0007E7BE0DF1E3F3A73B0FEE91F7F4EF51305
+:10FEB00067321F8E8795713B0DAF54F2DBBCDC1EA1
+:10FEC000C46353A024964EE271733CE01B984AEF42
+:10FED0009551A037E201F1F4647AAF26A2C1CB0FAD
+:10FEE000D2B8B7DCCCF5CE0984611C7AEF04394373
+:10FEF0003DA280D8007C7A0D93D1CF67F99C1FF189
+:10FF00004C0D5E4101F307DD28178F75AFDA4E7A8D
+:10FF100046B1925D486C7D70113927DB056922E09E
+:10FF2000B722EC3DE6C138F780D08528F65A031495
+:10FF3000B79E0954C82ACE8B491309DF95E186453F
+:10FF40008CEA89A9027CB7DAE9DF3E0BEADDF2B878
+:10FF5000908AF1ED996DA56E85E2FAC0EFD0AF3BC6
+:10FF6000B35D94B600F42113286E5D894518176DB2
+:10FF7000033F99E63593ADC817818FD7B98C201B05
+:10FF800003E51F0A72F64E1827ABE627C5EFF9FB0B
+:10FF90004704F0734F6ADF830E0F6ADF135F133479
+:10FFA000BF3D619BA84C063DFC4436FF6E7598CF63
+:10FFB0009B957B8420A620E28BCCFE53C33C37B4B8
+:10FFC000770E94ED9300AD0C54507C7ECE16CCC4CD
+:10FFD0003CE5B92CAE1FA3FD26BFDB01EDDEB72744
+:10FFE000290BE7E39E6C1E1FDD1BE86055F07E3594
+:10FFF00008B40C637EDF81A476C4F7DE80C8148C5D
+:020000022000DC
+:10000000E3058E8FFAAC40F89F027C118E7F56E894
+:1000100060488FCA8EE582FC261067A0AAAF4B1DF0
+:100020000BDF8FC1148B17E5A98BA1DF95AAF9CF40
+:10003000408FC11F7973E1DC6EF4B3C66BF90E73A8
+:100040005C764650BAD1CF522B9C3EF46756AD3405
+:100050007EDFDB32B71BFDA7797724D0BC4D357D21
+:10006000FF4A4BF3119C0EFF949D4DFAF0DE3D428A
+:1000700012D23B739748F3B13DC93FAA0ADA6FDF4A
+:100080009C93DC0CF8BB53D46F63BC691FF356031D
+:10009000D2F94F654516F413ECB6863A84ED4FE776
+:1000A000632809F1AB7FD7629497272DDE7D5C2C06
+:1000B0001E46799DD79A62D902EDB46749EEB779A9
+:1000C0007C978CE535FE8ABDA82F14353309FD9B3E
+:1000D0003B562E9EAFC0B3E2B66401EDC50713F9DF
+:1000E000789CB2C995242F9B9917F99D0D7A06FB30
+:1000F000855269FB4CD44BD91B51AFE56E4E24FEA3
+:1001000066CFAAB1A4437F936C0D63510F6FB7FA0A
+:100110006A6AA17CFBEC42CADF9C9B98C5E31ADDAE
+:10012000BFD7E436FBBDAF1D47F9BC355BBD07E962
+:10013000CD58FBC2EBF3A09FECCDA9C497A1E2047C
+:10014000735CD03491DBC93737AE207D7BA6C926DE
+:10015000EF4B1DD4FFBE3D8E0E94B7DB52ECAD636A
+:1001600052699E3408DEE83802E2CB97BF8372966C
+:100170006525FB688E2B30D1998EFEDE9EA4A9C822
+:100180005F961FF17D76B4BCAFD993F55815D45B5B
+:10019000A398DBB97A3C11056BF1A01E470CC4177C
+:1001A000ACC18A71A1ACE5F5AA9940F1C21A2DEF54
+:1001B0003A9FB1C39867BD4771FA308F7A4F17CC19
+:1001C00090C8796C8A27461A3FC8EFFD8CFCEC1367
+:1001D00016B717ED9A393EE8EE3CE29A86FEF31E1A
+:1001E000ABD701F48BCE23CAA969E09FA4A567FA17
+:1001F000613C9BB5FCBBEEC7FE40F3639FCFE5E3DC
+:10020000D87B03F7B36B41FF6C443FBBE5E7F630A7
+:100210007CB77ACF625F05EA8F16C11B27A39C06C5
+:1002200037A1BE550F0A5DE8FFAC0EFDF018E613CE
+:10023000D6801F8CFA7A4D7E68930DFDE21A568A9D
+:100240006C5C736783505714ED1F8FAE31FAC3EDAA
+:1002500049207731FCB13FE7F0F9D19E15BBFC375F
+:10026000B93C7ECF69B33025A2BD898178A644F41C
+:1002700097B73BD9004F0E8E35D42FECCC36941760
+:10028000771518CA4B5E9C6A804B43B30CF5A71DCB
+:10029000AF34C0D37B1618EACF78F756033C33FC53
+:1002A0007543FDEBCFD419CA6FE8BFCF507EE3A5ED
+:1002B0007506B8827DCF503F797E55228EF370F15E
+:1002C000C4BE383EBFF795AA86BCD333395C0ECE88
+:1002D00098F24E7DCF1AF34E299AFDCAD0ECDD87F5
+:1002E000F9013BC2F9C18005FBEFBBD94E79C13E94
+:1002F000CC3BA13E7BD6D181F1411FE69D107E5AB9
+:10030000CF3BF13CD5875ABEE92CE69BD0AE68FACC
+:100310004A8F47CF09B21BFD06758720A15ED4F135
+:100320008DC82351FE49CF4799F34FD40EE8C794A7
+:1003300000CF3F45E4ADFE4BE49FAAFF8BE59FDA7B
+:10034000274B9938CF7AE3B81CCCEEEF998BE3B307
+:1003500020378BECC39C4BFD4710AECEE070623E65
+:100360009783EC463E8E9F7A6CE4F73FD3CFF358E9
+:100370006A9985D6599ED96D09A15D9877434590B4
+:10038000C749AC2A0EFDEA324142BDAEE7B18EED5F
+:10039000BEB8068BE72D5EF7FB55E87F953ABC1398
+:1003A000E52F2F9FB52C6F64F9ACF9F946F86BF285
+:1003B000B5D993AF3A9FB5DA94CFAAC77C16C84592
+:1003C000FD21A3BDF9EF9ACF0ADB1AE8FBB0C02EDE
+:1003D000A823C867FD7526A379D4C7E4F6C9689F2A
+:1003E0007683DCC958EACD443DA3EB8D999A9E3BB8
+:1003F000C09478CCC3ABBBF97AB1D9AEECD5EC6282
+:10040000F60FF7BB65F4AFDB785EE2B1EEC9ED3312
+:10041000E1BB53814A2BD9430CE000BE6F77C58105
+:1004200026A0EBCE5CBEFEB3D411DC8A7692FD54DE
+:1004300094691DD8EAB7DF0A789C8321C47975F6E0
+:10044000876BF78EC1EF3BF7BBB3011E97CBE5B2CD
+:10045000AF53CB7F58E5768C573EFCE1B4942D1119
+:10046000F865E4F2BCC269166C2F8F8C4B3479D7D7
+:10047000FDF2F14CFF199033E10A86C49DFBD5597A
+:1004800065FCBB09C0F7F17B7ED34430E815A11CA5
+:10049000DB31E6E719EB213D346E400F755520FD49
+:1004A00092A687321E32FBF56237AE638E45BF1EC1
+:1004B000CAC7AE31969F867988FE910AFE11CAE3BB
+:1004C000F5678CE5F0D38DEB98F53585D49F649274
+:1004D0009BC5DAB898E93EB7EB48D34CC45360FDEE
+:1004E0004C8AA6FBAC2DA86239C47532C66B663A3D
+:1004F0003376BF29603C27599894581E4DD7B9339D
+:100500000DF3705F88999EFAF35D9B30785EBDC7EE
+:1005100066CCAF9AF0EE6BDBEFF693BE92C9EE1DA0
+:1005200068BB8DC657DD2532D46FB33AB9BD9D1572
+:10053000B07460FC773DEB6AC6B8AE0F3F9985E3B7
+:100540002AECC478B53D8BC337EC5FB153CD40790D
+:100550007CB61DE93A15B03094C7BECEB9142FF75A
+:100560001D10245CF7FCC703B56EF4034E6B727765
+:100570006AF70A92B7013BAAC9DDB9DD7CBDF3DC9D
+:10058000EEB9EE9C88759EFB50DE80DFA798BF7D9C
+:10059000562C7933F199B580FC5D37287F19BBF76C
+:1005A000AB3323E4CDCCF7F1E16E1AB763204F0CE7
+:1005B000F506B8A188FF388551BED73C0EE3768991
+:1005C00014374AA0CF709C50DE507F8D057942BD14
+:1005D000611E9F539A3CA935092C96BC99C769495D
+:1005E000EE405EDC40E7E95D4704A46328F98A0F2A
+:1005F000BC59C117FF41A58D89A6F3F49990807469
+:10060000AE023A65299A2EC090F262D1F2D540F23C
+:1006100075EF01DB3078331AA7EEED8F6662BE2DE1
+:10062000CFAEEE4DC779F4FB38B60F4812F65667D9
+:10063000A23F7FEA63FF0429627C974CCCD2E80D8D
+:10064000B82DC4FF1E37EE7B90C780629B81F16F8F
+:100650000FC5C3E7CB5C98C364E72F3F42F1F0EAD4
+:100660003D4E8671C2EA4B33EE2263BBCD41FB4463
+:100670000E04EA7A900FA7BB4401ED9E335736E48F
+:1006800053CF77AD90701EFCAD5D79213766DC519C
+:100690004A7986D560CF1CA5D71E7F88CE6314F714
+:1006A0000C15874CCFE1F80C178F0CEFCFD4A5AE0B
+:1006B0008CE0E357BD0EB77420DE6EA67CE6598C45
+:1006C000B7CBB44986F176DB40BC6DC33C4CDF1040
+:1006D000F1B6D9CF392BB0D6C6B2C1F8DBBC8EA7E4
+:1006E000C7DF756D3CFE36AFEBD529B6ABAEF37DFB
+:1006F000D57ED04A931F748FB6AE774FE07FD6F584
+:10070000BED8BA5E7011C55D7FE9BADE9E69345FFE
+:10071000BB3B1FE4EB7ADB8659D7DBC6D7F5EEC1CE
+:10072000753D19C72F8BD629400FB038D40387F8F1
+:10073000BADE1A5CD7CBFAEAD6F5406F5C755D6F0E
+:100740004D6AE84B59D7EBCCE5EB34410FD7B3C931
+:10075000363909E9BFD02632356B707FAABE6F11DA
+:10076000D73731CE36D3F503A003F723EAF0E86D8F
+:1007700082126BDFD11F35FD71E1F834D68F7A6DAF
+:1007800097407158FAAE8F435770DE74894199E7EC
+:1007900075691F5B26D37FC2E4FF4DD0F25DA36B6A
+:1007A0002C86FDB08CF593BF970EFE1ECA555FD701
+:1007B00083028E5BFACF04968CF3BDD1DAC7E7993A
+:1007C00093E6595FDB2764AF3F457B0DEDADDE6DF2
+:1007D00033EC734B37ED5BDB6EEDA73CEF76B0DFB0
+:1007E000AA84F1B1B1FCF79A7DD1F994AAF1291547
+:1007F000F7533A07F7530EF0B785F3B7B7C5C85F9D
+:100800007D9FCAB0FC3D109BBF0E2D1F32C0DF0381
+:100810001A7F0F68FCDD23525EFF8BF2B7770FF073
+:1008200017E18ED8FCED6D31F2B77E18FEBEB9F13E
+:1008300013E2EF993B12D83E6F347FCD7C65CC4FED
+:10084000F6C7A7DAE42D647F94E9B518A73C3D3AD2
+:1008500019E31433DFCF807D41BF5A5FFF34DBA340
+:10086000E4F9D697BF83F641B6D2FAE717CFFF0A6D
+:1008700016B49F5F55FEF76B61E1308EC731180FDC
+:10088000568E76A883F2B26B98DB1B2CFBEAF2BF84
+:10089000DD9DE261F4632FC03C7078A3EDC8766BF8
+:1008A000C8350DCAB7EFB17A553698FF35E77B23C7
+:1008B000F2C1A48F9E3FB07307EAA35A2627E762CE
+:1008C000FE2789BF87567728B3A3E38D5BB3C10F9B
+:1008D00002FAEAAFB3905F79AD7ECC536B0EC7E5F9
+:1008E000A5E27A436E295F6F60A4279B267E7B87F3
+:1008F0000AFDE9FBC2EFD3E42DBD93EF47849FAA25
+:1009000014A0CF9A2B75A0BD70CF6A9B80EBE62D0B
+:10091000499E5211E4A26EA2BEEFAF81F922F617F2
+:100920006CB7F9EB701DD92AA98CC75F0A95D7E17E
+:10093000264278FF5836D7C360FE08EF81B846C319
+:10094000E31E1D8FDD23C3A37DA296CF8BC6A37D9F
+:10095000625A341EED8807BC6FB9E162CF5C68E76C
+:10096000640BCC0268E7E4B669141F4A3B0409F93A
+:10097000B4295BE6FB4A05F52E3E0FBDB45E3AE5B1
+:10098000A50B4750BFDCBD4D08D2BA1C0B2FC0F9D8
+:1009900096794860381F4B7ED664C7F8A12BD84D96
+:1009A0004FEFCF77D8318E2D3DB8969ECFEFC9A2AD
+:1009B000E7B4CD15F45CB96DEDB4D9D0EFDD6D0EB3
+:1009C000195D31292084D0DEDDB74D0C3AD02E09D7
+:1009D000FBE6E17A8E0AFA07FD6F29282828FFAB8B
+:1009E000B789FB78F9465A8F557F2E52F94918FB83
+:1009F00051E8576D1169DF000B86DCD7637C7A34D0
+:100A0000BB8BE633E3795A5DBFCC3832B7A91CEA19
+:100A10007F24F0383D3352BEF07B1F879DACAD097B
+:100A2000D78DAF351FFB9160A1BCE67079D92772D5
+:100A3000F471E4FA26DE2908D85F0533C6754FE461
+:100A4000F0F14BF5C9763FCA555B6D26EE2F716804
+:100A5000E375FAF315B4DF434DB3537CC42E2FF185
+:100A6000E07E167D9F068CC874CC0798D7D7EFD749
+:100A7000BE47794C9F3AB8CE1EB55E0F3EE3C6EB3B
+:100A800006F711E8E5106CECC0F287B5764E403DF4
+:100A90008C877A778BC126FA4EF1A0FC8CB43DF896
+:100AA0003580E5DF8E680FF7F1EAEDB58C09BA7194
+:100AB0007F7F547B507D637ACCF682587E02CAAD2C
+:100AC0009178C9805731F6A3F1A72648F992E1FC45
+:100AD000A3BB35F919D67EEF8A6DBF4F9BEDB7C921
+:100AE0003F5A15F872EC775F40B3DFCF82FD46794D
+:100AF00018C63FBAEF003FE7A1B777ADFED1AA2CE9
+:100B000099EBC561FC235D8FACEA1AD423184766C4
+:100B100076821E81264A9EE5FAA12BC0F586F769EA
+:100B2000AE374A3797D293F578FFD983F35AD33B40
+:100B3000D350EF14A17E68B28F43FD7400FC7F4652
+:100B4000EB4A211CC7F31D22C5FBE7855BE7613F2C
+:100B5000EA0E4D9F04B83EB92FC8F5C979A192C7D6
+:100B6000FB4F833E81EFCF00CEF15C9FF0F5224D2D
+:100B70007F609C80EB3C1FEE797E13EA8F9F83247D
+:100B80008D93B0BFFD99186F47E991437C5EFFA537
+:100B90007AE41CEA91A2E1F5C84D5923D3233765C5
+:100BA000713DD2C8D4EE87D1AFEAE4FB2E3C0F39B9
+:100BB000787E3955A638C97C2E003D31E40FD4F239
+:100BC0003E29E1B931EB1FB11FDCF3A2C5757FE40B
+:100BD000F8F07DF06C93B7CD4EE7C97C0CE795F942
+:100BE0005C996EF7D6687292DE3532BBB769D290E7
+:100BF000F677D3A418F677D324467CD1CF699C39F5
+:100C00002412CE1F1DBAB6731A6706CEB1A51ACE2E
+:100C10006138F36C844F2F9ED3C0FD50DE6CC33916
+:100C20000EBDBC6F0DCF7B9AFB89CF1B38A7119FE0
+:100C30003782736CB502E7D7726D3D4C6F27EA1CA3
+:100C40005B4BEC736C5EEDBBFF6EE7D87AB5736CF3
+:100C50006F0F758EADC5788ECDC1822F93F09ACE71
+:100C6000AFB93E7F84CE3F9D023DB931C6F9353CD8
+:100C7000DF867EB51FF462D01B7D7E0DCFB7A11E2F
+:100C8000DC0171CC9618E79FFA52931755D0145394
+:100C900018FA332B3A056F88E1393787E2443A99DD
+:100CA00093EFD332CFAFFA9084F98066AF95F6E335
+:100CB0009FAE5FDA7E1DE2A3AE25236663BE6E0F94
+:100CC000D94D7E0EEE8B9EC7192E4E5DA98DFBB0C1
+:100CD000762E105BCE564F36D9B94ECDCE75723BBF
+:100CE000B7BAEB4B8A53F53CC048E3D44357B773CC
+:100CF000C9F32F76EBF18F18C3CE0D67DFBEEAF58F
+:100D0000DEE160FA15EDA9CAD735F47832C9C2E33D
+:100D1000C9CCEB1D52B3B69F08E57C35CA39E62134
+:100D20004D79CFF9B8FFA88C9F67C03C67FB774F20
+:100D300052DE53B5F0F8DABCFE1B9DE77C9DF2D87D
+:100D40007BAF4B664D3C7E1BE1FEA3FFDBB41FF087
+:100D50003A51E95C873EA239EFC9AADED2F39C1F63
+:100D6000E3F88F1EC86BE653B9395E9D50AD955BB5
+:100D7000D8055CC709DB54DA1F127E984D55D9C8D7
+:100D8000D77BAB163EBF4900BA56BBACBD0E37434E
+:100D9000BBDE3FF05D447CAD9F03ABBAC6F35F7A28
+:100DA000DEEEC433F13EDC371BE5DF02AD9B62FBB8
+:100DB000DF54FEC82499DB7FC93F0AF54E4BAB28B0
+:100DC000D1F95D9FDF1DD3FF1EA23D0B9667C5685D
+:100DD00047F1BB0DFE7275D0D02EBC6DD2DBB5C411
+:100DE0006E97FCF01EB001A817AE159FDF9BBE4B9F
+:100DF000D7F134C9BFCE87DE9A156E3B8D8B31FE9D
+:100E000048D6FB337DF77E9ECCE363416A9F9E15F7
+:100E1000CDB7A1BEBB64C2CB3D045E7A3C8378599A
+:100E20002DD84FB05D043971CFE5FB416B1796DECD
+:100E3000844A257C1368C5718C2DD6EA83B6A57DBE
+:100E4000F5C7AA2401F733D7825D47786BF1A40E6A
+:100E5000D4A7D98DFE9624D4AF5DCC8BFEB0F91CFF
+:100E6000E033BBDFA079386F7A25C3BCF554EFE2DD
+:100E70002329F2E03A527146AF05E7E1BCC53BAB2E
+:100E800092D11F7C89D13E985D72B02519DA7186A6
+:100E9000FC5EEEFF5D3DFF32ADACDB8A83758B4BB4
+:100EA000DD2809D1F998C9AE0E4B12B453989A7443
+:100EB00004FB2B2BAF1553019E5155BB6D3EC05FFC
+:100EC000BBACB624CAB88ED53337B10CD7F34A7150
+:100ED00087389BDDCFF7EF2C28E3F989D7D20FBFF6
+:100EE000B74A1ECCE72CFB71EF0ECC17E97AB90E8E
+:100EF0003F02BE4E688B1D7FA5E7713FD9CAE4C390
+:100F0000B85FD9F196C8FDDDD10D1E29861DD3FD30
+:100F10009DECF50D2C847CC673D55EB2FBA7C3DCBB
+:100F2000FE32948B4C6B5888FC7E42A3C96E897745
+:100F30005ED5DF349F935E986F3C0FAD7F6FCE5BC5
+:100F400099DBD1CF41A3DF188B9E21FDC54ECE2F5B
+:100F50009D8FA7353E9AF93661B7407CBF2E7FEB57
+:100F6000E378CE36BEF400DFB7A29D8BD7CFA71FA4
+:100F700030F96F1FADF792FFF6877C7E0EE7F143E5
+:100F8000643CD984F12C6881F7B9E1B5A1C87C270C
+:100F90000B580D7E1B9E5B8FB4E366BFCD55FA10D8
+:100FA0009D4BFF6008BB0D7E1D8DDF0A183FB47797
+:100FB0001F5C76901D385D650FE2BE43B31F97C678
+:100FC000B83FB612FC313CC77E3A3C83CE03809FCB
+:100FD0004AE771CCE3C53C8A1DF3553B964A5E8CCB
+:100FE000635B70FC0AA3C76FA8F1D0C72D5DD32740
+:100FF0008DCC4FE713580BF7CF9B9D9F14629E55E6
+:101000008CFB53E1A988F5A5661BDF8F7F4292DC3C
+:10101000C911ED3FA1F9F9CDA3781CD1EB91DCA565
+:1010200050CF9DC0F54DF6A106F7AD11F153BC763A
+:101030001F4122D8BB1EDA1704AA0CEAFD7102D7A1
+:10104000F7E13D396E8AB313BC995E17AEFFCFF856
+:101050004323FAD1152EDA077CEA1F8CEBFDD17EF3
+:10106000A86AE3EBFE211BAEFB6FAF8C277BF76B0F
+:10107000F9BB4B54DC53C002E9DABE0001CBCDF71B
+:101080001F0C7BEF81B89EEE3DC0F949E767CCF7B6
+:101090001EB00692AF12CD6F34DF7BE078EF4F1BAE
+:1010A0006797D1BD07FDB6FFC47B0F7E6B9293910E
+:1010B000DE7B60969B2FFBDE83B36187B6AEB8E81C
+:1010C000365C57348FD71795CFB3DA3D0A43CB2719
+:1010D00073DF5A7C35F9F41AE4F3A49A43B0AEBF37
+:1010E0006A753BD012DB0EDC205B34BBFD5FDB0E90
+:1010F0008C9A1C5B8FFCFFB2033ADF743BF059679C
+:101100006680DB812ABA1FE55406DFFFF53F768053
+:10111000DB819B8618BFE1ECC00DA8E3803F6F54D4
+:10112000F2FB2998557663BCBEF49D1C0BFAE37A5A
+:10113000FDEF98EE333AAC8D679FC4C7BDD22A5BF2
+:10114000638D7FD43D55CEABCBC940BB5ABDC1FBEF
+:10115000AB245AA79D0B9108EAAD56AB340FF3B3FD
+:10116000EA6D09C41F733FCCEA93D1EECC1A5F79C4
+:10117000EFE4E911FB17D81F9644EE5F4893573F01
+:10118000AE46C8B9BE2F217DDBC8F2842BF286CCD7
+:1011900013AEC88B91275C91C7B4F539F9776864B1
+:1011A00096BE23B2483E0FC90F17F003F960F58EC3
+:1011B0008CCFD611F2D9FAA5F179D748F82CBA1A02
+:1011C0007E1486F63C3099711F8D5AD9F06384D510
+:1011D0008D0E09CF15FF4DC2F77F142EC3F48A532D
+:1011E000C275E14744BF1FC7E3338B5FC2AB447E88
+:1011F00034D5BF1FFBD9221DA8EF90F1BCF254DA01
+:101200007F7767E3F742556017A414B63CD6B99AC6
+:101210003BB5F3D5CF6972FC9E2D343E09BE7B6D84
+:101220006AE57393D362D46FFC3EB5374734DECBA7
+:10123000A23F5F9ECCEDC453DA3D68B7DFFF8BB3AE
+:1012400098B748908BA60A80574251287509D0D389
+:10125000F65A0E9D2B7849ABCF3CAC0CE5607989F2
+:10126000FF9791FD3A65C94AFA9675CDC4F2397F68
+:101270002AFAF96BD05EDB5FB924943325C79BB89B
+:10128000242B1A0F68E765E487F3D2968FC529836C
+:10129000EDFC2A2EFC149D7D55E72D7D17FC8C5FFF
+:1012A0002585C7E1FEB9579F9DB4347526C069E115
+:1012B00071587E54FD6CD7D13100DBF838A5FCE4C1
+:1012C000B35D384E73169CDFFF18DADD4976BA9F9E
+:1012D00066B39627D6FB2D2BE0FB68CB0A383F750B
+:1012E0003EBCBA06F8903A341FDE8FE6C3FB93A7E4
+:1012F00047F3E1DE69CA1F903F8024D1DDB68185C6
+:1013000056028ECAE8AEF9D3A0893172D7B38FA145
+:10131000A8E5AA1417423BA7B1BEF352DBC7A27BD4
+:10132000B09D17A72A1FE2FB57D71C263CE25EE1BF
+:10133000F78DB05455417DABC0F83EE9A5EFFF9560
+:10134000F3D1F8BD3E1E37212FA19D6491DF9FB5DB
+:10135000C51EF02C86E7A62C565107ED6EFDC02564
+:10136000EC93A2C7E76C01D70F49785E1CEAB74837
+:10137000BF70D645C8D3288D7F55A5CA65C43341F3
+:10138000E0E798B79603DF003FF72B2953C90FCD4D
+:101390006565E8A7C8859C7F80AFB500EBCF0CA042
+:1013A000CE6771B91CDFAD9E5D0CE3A4B82278D284
+:1013B000FB30E99F38E69730F791F453FB132DE5A6
+:1013C0004847301FC7BFA8F0074F58411E3A92F94F
+:1013D000BC9D0430EE5BD80B6613E37475AC3D78AE
+:1013E0003086DCB90A39DEC525CA4D5EE48B23BCE4
+:1013F000FF31A8BFB9D8EE851161732C811AE40BB7
+:101400005BE022BD01EF6B22F3B78A46B752C0CF33
+:10141000176CFE77279DB3D2F90AF2545187FD9FCE
+:10142000760998071C4EAEF20BA2E42ABF20B65CE8
+:101430004DC6F751729538A45C9516C4962BA25BE5
+:10144000970BFD892763F1DC2AE0447E9BF5D2757A
+:10145000EAFFC23C83C01A70FFA4F552B9FA1AFA27
+:10146000D9D95682154FA57A14CAE3343F0FECC67A
+:101470009B2487CE06F2F5449742E3F7E664CD6EEF
+:101480005C63FB16A7A2201F9D18AFF0F6C7213D95
+:10149000D02F433B1F97C1F3397A3FE30A381D73BE
+:1014A00016B8FC385E73506F46C8EB470556C2E36A
+:1014B0001F35B9DE94D555E38BA11FC7175E5DEECE
+:1014C000AD9A1C83DC7F03C76338B99FAEC91B8C00
+:1014D000C70AAA3FA4DCBF40CF84222EF70928F711
+:1014E000C8A742A6567B68BE929CAF2B78EC09CC6D
+:1014F000E7E8F3A0B2B0C3300FAE0718CB87A22F36
+:1015000053A3CFADDD03B1B0D4A662FCF4092BDE4A
+:1015100087F92F77B964457ABF53A0E3AD341690AD
+:101520007C84C90FE860FDDD78AF88AA08343F6E7F
+:10153000517B1427D2CB020CD75D9A3479DE8BF61F
+:1015400013EDE324EDDCBD35C0901FE6F919971BC0
+:10155000F246FA7BC91ABF1616FADA0AA81D291E26
+:10156000FD6B7D3CCCF49CD1FAFB5329C8F5F4E12A
+:10157000F5FF739AFE7F4EA32FF94FCE86C8F93B35
+:10158000E781789ABF0CE6EF4498BF4F3DF0A4077F
+:10159000F133B77348EB77BFF6D4F57402EA69F21A
+:1015A00073D510F235424FEF477A9C6BB618E6239D
+:1015B000CCEB0331E7750ACCEBAC98F3FA50410C55
+:1015C0007D6F9ED75FC27C7E9CF487693E3F3E3034
+:1015D000CFAECEE74B1A9F2F7D413EFF8BF67D8F1E
+:1015E000F61C019F7B08EF683EBF5E10CB2E0FCD2F
+:1015F000E77F19427FFEBE607A0CBBEC89B2CBBD9F
+:10160000B1C6DB89FD0BDCEED3BCCA5055E4A3B2F6
+:1016100082DF47A9D74B467F14DA4BFE969BF6E351
+:10162000E8E3AADBAD2F719CFF186B9CE768FEEF27
+:10163000AD05DF7C42757D29FD8462F513D2E46936
+:1016400038BB9DAEE95DA03FBE707AB43EECD0CE13
+:10165000551597F8930AB9BE9A8FFA67EF779305F5
+:101660003ABFA48404F49B75BE6D2A90E9A97F97C4
+:10167000A1F0FA198DC902EE8F8B686FDCD5DA33D1
+:10168000E301F865227E0B0B953348EF990293FF37
+:10169000A5F99B1DC95DF5A89F8B0A79DEB848A303
+:1016A0004F875F2A55F20AB9BF5480CF4FBCB68727
+:1016B0002C16AE9FB97FC7F5715221B7AF165F17D1
+:1016C000C3734509E58CF213837AFD9B0775BD7ED4
+:1016D000B70BEB5B75BD3E0DDB2D2C943439E2ED81
+:1016E0000D8567A566372A35FDACC380E76C0DCF45
+:1016F0001B914F43E169E6D348F17DA06000DFF91B
+:10170000856943B7A78F175DDA0971C1AB2DBA9E02
+:10171000C8998AAF6E1BF03F7D4BB09D8A22F602BE
+:10172000AEC780C4C6637B4FD981DE22DC17BBB352
+:1017300002CF5574AC974AF97D41C126849F6A96C1
+:101740004A315F7197D68E593E07BEB7774D9E5688
+:1017500044FCA843BEDC389BFB7B89AF88B45E5356
+:10176000C1D84501CFE338540FE689DB04D543FEE9
+:10177000E27C17E50999E736C27FA8F897B18DD4C6
+:10178000BF4E2FC364CB55EB37517D29416DF05DC2
+:101790004B7D875A83F507F998528A7C4C286274EE
+:1017A000AF59051BDF81E3B4519303189FBF2E246B
+:1017B0003F162ACF1CE46B74FB2AD5AFF03508C85E
+:1017C000D7B87CBCDA179E3E95FC228B1C20B988CA
+:1017D000CFE572C13C6F517B83784C9B66C4E38636
+:1017E000FD91E74D4032747C1E237919213E10CFC4
+:1017F00053FCAE6EB4B2E6328AE729BE6F541D12B6
+:10180000E63F3F8BCB0CA2D30471FC1E2E870D3319
+:10181000F8BEAD86127CBA9844E7E56EF4825F5A52
+:101820000A4FA74BC5B8965DB69E37AE83EBFBBC9F
+:10183000C2C295846BEAF7A7C45F53BF23CD1FFCD8
+:101840009D26B711F983BF2B8C21C77AFEC0CDC26C
+:10185000AA88F659E2793C5A8046FFD62B137D7A46
+:10186000FDC39ABE4A1CC23F3BACF5ABCBEBEDAD22
+:10187000952C9BF44203DDA7D751C3EFA982F972DF
+:101880009CF466E9C3F4FE93462689D04F85C45E76
+:1018900048B50CD2A7D3ABB7FFB6693EDE69E77E89
+:1018A000FF7B3656F37317A7776A045EA7A756BC6B
+:1018B0005D98164DAF19EFE31B1A4355E01FA43492
+:1018C000CE65275330EFE427D8E1E4E36CAFE1F7CE
+:1018D000B65959CF5DEB0085772CFE5E6C37253FFE
+:1018E000B07227F029E585388A277B9C39DBBC500C
+:1018F000FF5B2F8AB40EE462FD228EDB97251FCD9D
+:10190000A3BE4D79A96E9B53E2F7A219E5A3F9A6F0
+:10191000D29A54CAA7C8CB5E01BBDCFCAAF75D17FC
+:10192000C0FFFE53799907EF337ADD5B9306DF152D
+:101930001CBAF2C436841797EEC6FA49FFF0E7B432
+:101940009B10BE43E0F99543F2323C9FD0DCCD6260
+:10195000DED78737F2E13CFAD154DF8C629453AB87
+:101960005FA6FE2B8421EA733DD6882100FA919769
+:101970002C7C9D44E9FB678CEFBA673B64DC772ADB
+:10198000BC98A6DE0EF0AFCB73E85C25CC034F11FC
+:101990007C77E40607C5178105F1B41FBEBB3CE5A3
+:1019A0009512849564D2EACD37F37E6DA961B1D6E4
+:1019B00015DDEF8FA62ADFC5769ABF29D4C4CA9356
+:1019C00045D45B8AF438AC3EDA57900CBC69427D52
+:1019D00022AF2539D87407C86F29C9AF5C847A4112
+:1019E000E1EF95EFF1F720B9D6C87B0F74B9D2E5D6
+:1019F000E9B713DFA17320203FF9888F595EE64FC6
+:101A0000FA9749DC8E1AE5229A6FC9C4A7D7CAC5CE
+:101A10000E3CDF27BCF8E936BC87E8D74AB68071B0
+:101A2000F26B97395F03E57932EE2B063E4E2F8A33
+:101A3000983747663A2687C96EF966201D60A7CA9F
+:101A4000468923C2FBC66BC3DBFBAE1FF1BE6C270E
+:101A5000BCF5F1FD9D36BEE2A88B2EC403E8884399
+:101A60007B00782E407CC4F1E10C9CFF3A9E23D58C
+:101A70007B4B8BA2F4DED2A2ABE83D18C79A22EED4
+:101A8000C75CFC968C7970EEC70CA57FEE2EBA660B
+:101A9000FD7377D135E89F18FCBE1FBF1F29BF9982
+:101AA000C264291DFC792C223DAE901E07DD41EB5E
+:101AB00079C2A5069257084CA4BF42B95EEFE3F085
+:101AC000547EEFE8A6D252A75D8C6E77A4FC6F2DF2
+:101AD0008ACA5BB746D26FE6C34DE2F966DCDF72B5
+:101AE00061B640742997980DE33195C98988D71C50
+:101AF000C546EB0E5629DC8CEB5437E37935D05FC5
+:101B0000B8772DF27C6892E26491E74153AA2503ED
+:101B10009CE6F330E3B973D9503EC69F6F281F5738
+:101B2000EF35C0E31BCA0DF527342A06384BAD3616
+:101B3000D4CF69F319E089811A43FDBCDD7E43F9F6
+:101B4000E460BDA1BCB0B3C1001777351AEA97BCF9
+:101B5000A81ACA4B436D86F269C70306787ACF6E1E
+:101B600043FD19EF060DE533C39D86F2EBCF7419E3
+:101B7000E01BFA5F34D49FC306F6DB0BB40F4C6551
+:101B80006FE0FD274B98FE6391ADBA1C5A0CF5B57A
+:101B9000FD7F5E1BEE6B9DA3EF5758C8F74BAAF075
+:101BA0000FEDA2CFB45F502933DEC300F27004D72B
+:101BB000452BB47B0CE798F63956B0EC4419E46A2F
+:101BC000CE71910501BE19E5CA122D570CE48FD6CE
+:101BD000AF35B98AA64B7903F7810ED2255C95AE55
+:101BE0005B902EE87711EE138DA04B5FAF55CA7B4B
+:101BF000451683BE39DA3D52663AE7B06D944F30F0
+:101C0000D3675E67ED2FD2F647813F1A6BDF848A78
+:101C100015911F0A3FF77D81C17C02D897656D50F1
+:101C2000A5683AF575D70AD5E945FE54403B412CE5
+:101C3000C0D83FC27F89938DF32E21DF38EF4679DC
+:101C40003DC3C9CD5F242732FC8B2527B730908B4D
+:101C500032BC8FD62121FF6FB1FE65FC1C5B6CE4AA
+:101C6000E7A76C7622F206E3B9D418FBC0757E4173
+:101C70001C2217A70D6D3F8A8B8DEBD323B01FC598
+:101C8000C591F6E6DAEDC7F4E26BB01F23D5F39504
+:101C9000C5517ABEB2F82A7A7E20BE98CDF3C82C00
+:101CA0007731F7A7C067E27E5398F2C58B8A797CBB
+:101CB00039547CB148EB7730BEB860C5F8A2DBF68A
+:101CC00008C511CA37781C01767D9597C76D3CEE23
+:101CD00068E4FE59C5ECD2C425D0FF2A94A5E923B7
+:101CE000A7D71F4DAFFF6AF4FEAA89E7017EF5AAC8
+:101CF00048F795BE9C2A86D280FE9DAC98EE4BD0CC
+:101D0000D72BAAFD8CFCDA0AEB8E4EC6F384F76162
+:101D1000BBD57285B0CA85EFD7D27328797AE4DA59
+:101D2000E5E9912F284F1B8AAFC1FF1B693CF328BF
+:101D3000C6333026CDAD9C1FEAFBA3B4FB7B795C98
+:101D4000F3E866BE6FEAD1261E8F0435BA1F2BD684
+:101D5000D667A670B9A9709793BFD92A8C22BD0700
+:101D60001AC283FB202A3C763A4F07FCFD01F2F7AA
+:101D7000E898EB12D1AFFCE49523A991EB11EF6940
+:101D8000749FD0E87EFFE101BAF712DD352B689F22
+:101D9000974EF737BFADD39D2191BE40FD01FAC2EA
+:101DA0002E75515E799EE822BDDB92CB820E4A6091
+:101DB0002B8B6EBA4E3B9700DFB764A80CF55BC265
+:101DC0001891CE118236A4FD366DF08FEFEFD94316
+:101DD0007F5F4AFFFB44368FD5705E230EF5D91422
+:101DE0005C3F32EED389437BE2C6F288FA31F4DC01
+:101DF000DF176BFB71EC6C34E2DDB2E1457612D794
+:101E0000D8B57D39566DDD68287DF7B2360ECD82A6
+:101E1000F26BE44F9FF6774BCCF5F57A663E1D0DDD
+:101E20009FDC5208F4AF1B6FD1C6CBEF898C9FF4B7
+:101E30006762797F41AEC1DFBB54906BF0F75861A8
+:101E4000249CE6731646D61F5D2319E0317E8FA1D0
+:101E5000FEB87AD9503EBE21DF503EA1D16B80B38F
+:101E6000D47243FD9C36C5004F0C541BEAE7EDF6D7
+:101E700019E0C9C11A43FDC24EBFA1BCB8ABDE50C8
+:101E8000FE1C0B2FC0948CE339FBED55602C37F50D
+:101E9000DEEEC1FD7DAD69CB9CFE18FCD69F47D31D
+:101EA000B89C0F55AECFF3A1CAAB35FD6771FAE808
+:101EB000FE7DA7943D95F679A4F6D1B8C549B974CD
+:101EC0003F84754AEC3CE9769BDF3A250DFDB5066B
+:101ED000C3FEA26A10AC591073CC97BF13AA8AA094
+:101EE000BB29A36E37CE974761BEE27C79140BE81D
+:101EF0001E36FBEDB84FE7513C103196B1F33F135E
+:101F00006FC7F5FF4D42431BA68474FECC9E92A57D
+:101F1000F1E76B1E8C278F2601FD31F4FA507AEE23
+:101F2000E886FA50D544C68E6D6820F8B8B63E559E
+:101F30006D37AE2FCFD2F48DFE04BD9285742E7C0A
+:101F400055BCE89711E911E701264FB98A3EBD6EED
+:101F50000ACFD7B70A6A2EAE8B56DB82D568071C2C
+:101F60006C01E9C94F25791FFA73AD69F3BC75A8F7
+:101F70006A8618072BEE938AD00F42D6D21AFCBE7F
+:101F80003A0DF80C7035AE6BC7E053A146DF88C739
+:101F90008965DD8EF7E5E9E3244DC9BC9DCE239824
+:101FA000E63DFC1CC5FB8AACB93C2E05B908F9CB53
+:101FB000482FD2BA18C8CD5F215FCC72A3E76F1B40
+:101FC000F105FA132EBE7E440A15FDDDE33CAF3069
+:101FD000D4783FBA01027CE0FF0549A6FD648F0A70
+:101FE000FAFDED5E4FE4FEEFAFAA9E0E8305A371EE
+:101FF00032D76FC45F311EF7B8882E3AFF3306FF21
+:10200000E7CFC7F5F6466D3CC67A95FBA7D0D3F768
+:102010002D7C32A73F9FEEB1F3FAD6122C0DC00FE4
+:102020004EA13C3DC098279424CA8F0FC51F9DBF69
+:10203000F0DD77A7F0BC9EDECE7A825DBC1D80BF4E
+:102040004FFDA40EC02A9567F0FA23ED6780DE1ECF
+:1020500091CEE75CB42A74BE7759E30AF24BEE687E
+:102060005C45CFB60D52D229E0DF1F3628452D3012
+:102070003F97DD314DC2FD1377DCBD829E7ABBCB2D
+:102080003539B66759E91E3831CBE23B40F699AF96
+:1020900073884250E3678BB64F254CE78C9C0AEB64
+:1020A000A7BC5E6345518B619F7D80CE6BC7C9D64F
+:1020B000FF888C23DAACCAD344BF2BF52FA4132698
+:1020C00000C8EB45576E909FA7AF9462AD57E8F4F8
+:1020D0000ED5FEF221E6AD4EAFCE37FDFDE65CBE7D
+:1020E0000F51973FFD7DDCC42A09F5CD7281CF23C6
+:1020F000364A3B97ABD5BB0BFAF905F2D1EAA57D81
+:10210000947769FB60446DFDED2E60E1FAA911FD45
+:102110005A7D47903F51FC1C21BFDE453D6C433F3B
+:10212000BF2B8EDFBB220991FAB446D0FF8E06A3E7
+:102130007B12FF4F5E8105F5C8E6BABF755A00BF36
+:10214000F7A7707F636BD185E9782FC856D6FF302B
+:10215000DE93AFAE1F45F71DD4D47E3ABD29A2BD94
+:10216000E5477E28C900D74C6C49C3F5EFE5CC7A2A
+:1021700031D29F32E359D3F800C9A5DAC4F3CE4C6B
+:102180001BDFE56A12E91F1D5ED19644FB7157798A
+:10219000353BA1F963742E92F29FA9761C8F5AD514
+:1021A000785FD48A3623CC22FD3871307E5171B3EA
+:1021B00000D2D5CAFF1ED053C027B413992C44CFE8
+:1021C00055DE64FDDE56AA377EBD40F8F899740CE2
+:1021D000FFDE84191F331E75CC6BC776468ACF2A63
+:1021E0002FB7570E275313A0EB54E07D0FC90DDF17
+:1021F00007B5CBA5C32A1D76F4E5F2F5BF3899974C
+:10220000EBEBB9A3FD5D0CEF978B2F038260BC2C29
+:10221000580FE3A0841E05FF5E4D7EC9AEDB3D93E3
+:1022200071DDD0EFC1F3ED00BF63A575770E434FAD
+:10223000EF1C9D8DF22315E07ED2ADADEDEF1C1F9E
+:102240004FFBA0B4731CEDEFA09DEAD061BC00155C
+:10225000E8E9881F8015A707E0EC01584578AFB67C
+:102260004F02DB3F85F3C8D9B3301FF0541CFC3E4E
+:10227000ED21E769899253720DEBA57ABDE1E6493C
+:1022800087676500EFE954650BDF97C39861BDF779
+:1022900096127EAEE079AF7F3AF63F6A7D3FA56742
+:1022A000EC634EB950EE06C7A787C663707CBAF8D8
+:1022B000F894F5D0F88C2AEAA1F199205F60D94012
+:1022C000EF84D95A7A393799F0EC90D709385E1DE6
+:1022D000E5021FAF3246F7088E02344767E13E2021
+:1022E000BE5EBEA88CD17E75C9C1E3D9EA12BE9E7E
+:1022F000787B89A83DF9BC4D9437D2FE3867B58507
+:10230000D68513F16958D769D1EA5BB5B882F3E392
+:10231000DE69FE252511EB8FAFB65848EE9D59B901
+:102320001D78CF45856C7D08E3B21F69FB819697C8
+:10233000F8A696C077AF96A5C4FBF97AC8D7699C72
+:102340004CE3AAD339DCB80D355E7A3C3954F9B286
+:102350003B445F90FC6CFF134B01DFFB5F4CA17DA6
+:10236000FB276AC4B21E801F786934ED4F58A7F16D
+:10237000EB5B96FE74D48B9B5D3B7DF874BCD8A45C
+:10238000E09F37DA6E930D787CEB9715E43F6D4C48
+:1023900070CF46FD6EC6E3C4E5DFB8701C5EB9E4DD
+:1023A000E0E715659E8F233B606103F7B1DDA5E98A
+:1023B000B41F9470FFF2AD0D353C4EB68629DF791F
+:1023C000C203F12BED7830DECFBB9C590DF7ADB0D9
+:1023D000469E8FD3EF23F0B3A479385D41EF18F216
+:1023E000747733D99E06F597DEB6F818C6BF2BB4BE
+:1023F000F817F490A99E31FF777B4DED809FFA0985
+:10240000FD3FA89D63506CB85FEB95C502E57D97D5
+:10241000FAEE085545C457EF7C2E2EC77D2F27F0C6
+:102420005BE0F7893BF3E8EF709AF9D13B40BF8F4F
+:10243000E28401FE30A64D88ABD31FC5AFFF647E9A
+:10244000CC1317121F56001F1C31F8A0E727747A0F
+:10245000DED0E964DE13F8F79B4F6EE3797331F455
+:102460006F03796EFABBCA8DDC3EE0E66DBEAE2D21
+:10247000B7E27994BB557E8FD112D578CF04681618
+:102480003BE695EBB4BFCB1C655FC43B8F45E63D97
+:10249000EE36E531CC789BE9BC59B32351E791ACDA
+:1024A000A10CF4234E9468798F293CBFFB8977698E
+:1024B0006208CBCBD262EA5D3DDF3138DFB95C2DFB
+:1024C0006F5C6C888B04E61F8025B09BEB3CA28C74
+:1024D000E7FFDEA899F8048AE11267D8CACFF33380
+:1024E000CACF2F7F4BA473514B985376019EDF8345
+:1024F00042B4C38BAAE3E4C8F39E17021FDBC8CE25
+:10250000FB5903DE47BB0E9A6F9C3A48E73A8F9D12
+:10251000FA31FB2D66FA3F2DD1F2DA53D8946BA134
+:10252000FBC112C6F709A5F07D21FDABF06F990C38
+:10253000E6235986C2FDDB741ECFFD3FDD0C35FB63
+:10254000008000001F8B080000000000000BED7DE4
+:10255000797C54D5D9F0B973EF6CC924B9D9030487
+:102560009809448340982413B21060C22656C001D3
+:102570005C820930615F02195C47C5322124028602
+:10258000EF8D4B2BB69877A0D0D2DA252AADB405C3
+:102590003B11A5D8BA846A15D1C208A820A8514415
+:1025A000C7A5E57B9EE7DC9BB97748006DDFF7F7B1
+:1025B000FDF1A5BF7A38E79EF5D9CF739E73C6EAC1
+:1025C0004C66AC98C19F8F791218AB31316FFB30DC
+:1025D000C6DE36B2AA276C9886FA17427A1EFFC664
+:1025E00032F65E61A5D5591CCDD7F8BF1F9A50C4ED
+:1025F000988D858DD87E8EC51612F3A13BBFF14C08
+:10260000388FD1DFF91CFC6F8DFCDE50C604E66507
+:10261000E7E3196BEEBBCCE9857E9BE312F359121D
+:1026200063EBB14A19637D9D9E34673A960F08B2F9
+:102630004428B3A730D687312B0B3226429A277D08
+:10264000D5DD2F8BCE83B10063D08E3DB760E7D64A
+:1026500034C6BC36896D84AC815902CC05F9BB8483
+:10266000E04601EBD99B3B203F1716BCD109A9DFFF
+:10267000F8A9B63F6FC26013D57700400A709E5725
+:10268000515EAC645D0C40C5F2BC799EE19A710369
+:10269000D0DE125DA717D23E85F01F8B2503E1C166
+:1026A000D66BFACFE9693C29830D8BF6179BC6F6EA
+:1026B0001FDB5FB3812D6907388A090B96E03C3F29
+:1026C000CDEA2B8B029FE77418BFD46920FCAAFDCA
+:1026D000CDB3A4CA526A347FAC8FAD2A68BB705C9C
+:1026E000B59D0AD714D19B659031EF3CF45C3663FD
+:1026F0005B997C9500F0DBD43CE4D081D18C50C553
+:10270000FA62F52187DCC3F0BB92672CC460BE5B24
+:10271000E3BAF36E4B16E473BAF301CCB7C170ACF5
+:102720009CF77F02E6F3C53FAE7633C0E3A73E26B3
+:10273000231E2426BB717D03AA186B007A60927D4C
+:1027400008C2579D6FAA7F3C3B0EEBB2F8FBE9D65F
+:10275000B7D469A7F9A7DADDCC00FDC1A77619D6F1
+:10276000912A390527CCF34113C06F18D17F00C7D8
+:102770007BB0AF9CBC11F18CE3415EAA92858D05C4
+:10278000D88F81F7A38CD33D6E9E5390A1BD9CCA78
+:10279000E67A6CC80FF7103FA8DF6F770A3AF85F48
+:1027A000067FDD8EF41FCB5F2F0ABEA3F7C2FA03AC
+:1027B0002F886C072C6976D65D547EA37F3EA5B327
+:1027C000FC4B295DA38CF786C1BB06F9B4B3EAD5EF
+:1027D000D977C23AEA77999D6658D54755AF2E7A90
+:1027E000C48E70023AC0F6B31EBA61247CDF6093D7
+:1027F00064249BF5FD5915D15383E0C17483DD3406
+:102800007917A44DF995BFC479D927FB8FDE8B7852
+:10281000C9F31891BF9AF22750F9A77981AC79448E
+:102820007F714E668FB66F8E03B8C07A9B4D3C6D3C
+:10283000734A34BF3685BE7EA8C075BDD19BE78381
+:10284000EF9688404852D76F91024CB661B944E583
+:10285000A200FD627F71DEBCDB357053FBB54440E6
+:102860004814F5D4DE44E5B81E6A9FC2E7A3D6FB40
+:1028700099D2FE67CABC2C91781AAF3905E665D3A8
+:10288000F693C8CB15BE8BE59B24E7F8C711EE4D38
+:10289000F9EE5F3A897F14B99875E090907839F233
+:1028A000312CA07C7C394BB220BD07560BC15C0794
+:1028B000631BF33E6DE272C9E213516E3129A0C869
+:1028C00005E13CC935669746925C638CFAEB6A2A4F
+:1028D00082FA6128FF91BE3E3B0FFD1D2D3DFB831B
+:1028E00022CCAC63FB0743BB39BC0F64F7FD8333D9
+:1028F000183BA2646B6D83270144D97515EF180747
+:10290000407FF3B3442672B979A2BB3FAC17D0E73E
+:102910006DCCDB5A0474B2304B9237023DCC5FAFC2
+:10292000FFBEB174E6FEC75C989A6506FD2D64D2C1
+:10293000896E7838A272A7C56F606EA89750260678
+:1029400005284F18127E612CE459B1D1BE83E45C96
+:1029500078CACC34FC5E44E36CC2A665549F21BCAB
+:10296000588195E0F772E9ABF27C0DBE128A4F0CEC
+:1029700041FDD3A6E011C452E2C40C0D1C006FB897
+:10298000DE8559830C1B49EE35105D3C77779C0141
+:10299000FB3DEA8A0B9AA1EE44D146E3CCDF2452F8
+:1029A0007E7EF1E14A33CC677E134A47C097CF93CE
+:1029B000148279CD5D3DD314827AF23C9B2FA99489
+:1029C000E0772C067EBA3C631E82CF3C800F8E0FD0
+:1029D000F0D37D07781DD3C2CBFFF6C1FCE7347A74
+:1029E000E59FCE84B4F7808E58212B3C0FA07865EC
+:1029F000CD6E76DCC8D859E70D4921C4272C98CB79
+:102A00003DBB69BA469F7DB1A633FF39A8D7288C54
+:102A1000930A60BDF324A887F071CD20B84E14CF7F
+:102A2000BC3016F9DF959383EBFD305F203C6DF2EF
+:102A30001FB600D2D9A66F44E22F268597A2FC9C30
+:102A4000727779EA46985FC7DD57651E87EF99056B
+:102A500026AADF66B03F5201DF037F31923CEB4D87
+:102A6000FF59FC221B0CFC66F50B94AA7848F05B1E
+:102A700099A4E1F304653DE9AE2E2147C3D7B9051A
+:102A80007C7EC9AB991BF55CBA8BB9ED30EECAC13F
+:102A900039DB04C4B56427FBC0EAB01722FDA8F5F2
+:102AA0003719654AA509BE403F281F08F3C0F1EC5D
+:102AB000300FD42F0E7F3CE573FCA9940EF2275300
+:102AC0003AD8DF8FBEE7FA07517A85DF41E557FA3A
+:102AD00087523ECF5F44E9107F01A557F947513A2D
+:102AE00014F40AD61BE6AFA474B8FF5A2ACFF7CF66
+:102AF000A474847F3AA54E7F357D2FF0CFA7B4D044
+:102B00005F4BE545FEE59477F96FA57CB17F15A590
+:102B100023FDF7505AE26FA4B4D4DF40F5CAFCF7A6
+:102B200053BEDCFF10A5A3FC0F505AE1FF317D57C7
+:102B3000F9CF8630027D3B2DF94999A18E66A1C15E
+:102B400068FFB4F522FF16147079FE9AD33DA520D4
+:102B50003D5A6F8A81EBBDD87ADE022E6F9319A79A
+:102B6000338325641904F859B17B50A108706F03B1
+:102B7000FEB7037E56E6E66C43BBA65AC18FD51856
+:102B800070F773209EEC1CBF13DCCC0BFDAFDCBDDB
+:102B90008A52E64C237AEDD5AE52D6776D819DEB05
+:102BA000232940F6419B8F390350641DDC29A07C0A
+:102BB000D89A254D46BA31F5F9AC03F97A6AB1DBFA
+:102BC00085F2D0D447325820FF724525E51F2A30C0
+:102BD000527F4F39DDCB916F06BAD2BF877269E061
+:102BE0003A830CDDB16497D180FC900CC3260B6452
+:102BF0001F4DC6F56E8DD3EBA116052E207F1EC688
+:102C0000F66DF983892E217F0DE7A71C86766C9BD4
+:102C1000292448A81F6E616C872AB3B07EF3BC9F3D
+:102C200022BFE5AC773E8BF31B187016E1FC5A907F
+:102C3000EF605E8E56FB382BF43768B3FB592B944C
+:102C4000E706BDE3E2207FE5CEC0B3980E690F8EA4
+:102C50008B8774E8EED0B3283E8687C2E36C901F62
+:102C60007180ED433150D0691F9F00F9A243EE7D82
+:102C700068DE1687BDE313114FA6606322CCA7ED73
+:102C800008733640BEAC2BB08F6C42050FDD74006C
+:102C9000F6CF13A8E7EDAD6E8477F66D728148EB41
+:102CA0006B55F010B62693FD08EBC5F501FE77C015
+:102CB0007AB2DD5D04FF6C172B0410B2ADEB0C0A89
+:102CC000FC1D85B8BEA70BB8DD03F0FF31C27F6BDA
+:102CD0009C5C9907DFBB2632791BF43FAD8F44F033
+:102CE000896FCA0922DFABF406701D323D410B7FAC
+:102CF0004E5F6DDD76E1C5E1FAB422CFFEB7E11A91
+:102D00000BCFAB153A8E85AB0ACF690A1F5F8A7F5E
+:102D10000F44F9F7392DFFC6D6FB5081772C9CDB89
+:102D200024F92A82978D19020588B7908076D349B5
+:102D300085CF2F17AEC7FE1F81EB9F0AB87CE90D28
+:102D4000AEAC345DA16F398E0DEA5DCE607FBDC93A
+:102D50003784C3CABD8E6D22C0E10B85FE36441E8A
+:102D6000F0607FAA7C93F634B8510FA9F26DDFA50D
+:102D7000E4160E8DFC33C11A44F960EAC67FE714ED
+:102D8000C4D741A39082F6BBB190E371EE088F588F
+:102D900088F62A589D481F2C8BF32D582C7168BF3C
+:102DA000DA44B95282223694397740E2717FF25C7C
+:102DB0002AE1CB4EFC077FB43F9B7277DC36C4A779
+:102DC00003EC0609F6C1F0CF10A649ACD32D62FB87
+:102DD00075AC10F53D936BB3B47CA7EAF5285FAAF8
+:102DE000F491B275A383D32DD6BFA690C32749AD66
+:102DF00087BB16A8D77C57DFAD1B357270ABB30FFE
+:102E0000B5BBA690FB37A64FEAD3BFD6D63B3DDF76
+:102E1000A9C061EBBABF117C132AB8BD90B42E854E
+:102E2000E83B69823703BBCF7673399CED9F670A15
+:102E300040C1785C7D71548EC3BE76EE74847F0A87
+:102E40004F61E34A7880F1B771B97D79F49F52F808
+:102E50003F4BFF29850AFDF4C207032BE40E11CA7C
+:102E6000074E60B21DCAB756A00E437D68223B9C38
+:102E7000A16B05F24940DE3F1208AE2103D29B212F
+:102E800081E86D8A29E846FDC44CC932E27BEE0830
+:102E9000EFF4C28BF0D141A3BD00F701B73C39621A
+:102EA000960DE8B4D901FC04A89B5B5836AB05FD30
+:102EB000052961A6E41FC5EFDFDDBF50F6E6098DE9
+:102EC000BE95E3F9BE1DFED57F86C60E5EACD0D999
+:102ED000DE02F7429C37F0C72DC81F958CDD6618BF
+:102EE00074A17F42F50BF4E6A788F54BF4E68F500A
+:102EF000F9EE52768B2A4FA2FC2F17A8FC5F3B8C71
+:102F0000E4F76A9CB7DA5F6F76584E2197CB2D8530
+:102F10005CEEF76E87A510FF839C52F89DF3EB06DD
+:102F2000F6A007FD72BDC9A97B543AEB454E255862
+:102F30005A376F87DE6EC912ED27C87FA3F7AF58E7
+:102F4000B39A3B71BF9C00946383FDCF6A203BDC46
+:102F5000EF58A7B077CC506E19CCCBF10FF73D9F4F
+:102F6000B60AB4FF00B348F6A31F0EFD861AFFCBC6
+:102F70002D59261AA7752DA7DFC0CB6210ED8BB394
+:102F80006EC329B42FCEBA043B13489AD965D80F23
+:102F90004EC12EEC441F0CE59D19F085FB69F67DB2
+:102FA000A7C5047430E52B81B9A1BF17BF122995BD
+:102FB0009887FCA8539D1DD90CE8A9A3E0CFD9613F
+:102FC00098CF8BEF401ED6FB5C414952D886FE9CC1
+:102FD000D06B15C285F8BDC95BABF31F45F1AE5F81
+:102FE000C74DB3FF6E43F8FE581E6771E03AEC061A
+:102FF000672E437C7039AFD6DBAFC891A79CDE103B
+:10300000D26FC282AE752614C3F2316ACF06A71002
+:103010007DF4B13F69CD81F5F5A9E3F66A5F166CE1
+:10302000906D17D2DDE222EF5FB09F1F2BF6EB4BC6
+:10303000755C7F591C83B7A25D5559DFB7621C745C
+:10304000F0E81A165A6024BEDF8BF5DDA9ED0548BD
+:10305000273FFE6AF735B8BD38C75E5C40FB89A2E2
+:1030600037D3EC00A79AE2E7D3713E5305FDFCD5B8
+:1030700054F583C5EE730F17C23E7728FC239FE5F6
+:10308000E33EF71CAB489A891F5DE93DF291EA9F48
+:1030900053F7B9E87F937BD007B1F056C7AF0174FF
+:1030A000E37A99512039F792026F900F6788DF2CED
+:1030B000207F5C28278693BF798AC1993413E5A5C0
+:1030C0002BF5A2F3013196ABF567767F1798A7270A
+:1030D0007D6528E2FAAAC6C8E597B0EAF90538AFD7
+:1030E0009A02AB80FB72897519519E7DAAC8B1B94D
+:1030F000CE0D9F201FCD65D2675A3FD0A785B22243
+:103100004F428365C51FE9ECC11FDD1B3CDE940205
+:10311000B371DC37BD663900FD4DA92DC9BC983FA0
+:10312000FB30D20510EA6BB8E6620DBE06F72CF74D
+:103130000EAD59129A608CE2EB82EFB556F25F57F2
+:10314000219C34E3E617F175D72B2933B7E6E1FA72
+:1031500036CCFBAD05F9F2FE619F160700DEF7B332
+:10316000AEDBB7A11F627502F921AA6ACF15370C31
+:10317000EF7DFE7301FDBB0B2F84636CBDFA222E25
+:103180000FE7EE7B5446FAAECA5D971E80F15F46AC
+:103190003F4C2E8ECB68BDD3BAED1DBD1FA6511876
+:1031A000E72A4AD7F85F8671FF0BDB67350460BEFC
+:1031B000D683B9DBAC30EE817C4E074C6CB9611C18
+:1031C000D0DD39AFD189F2D9DA0B1F55F957EAE4CE
+:1031D0004B7C4460418DBC8D97DAC9CF191F91A8F3
+:1031E0003C96DFE422C5AFA4F0DBEBDF3C22A3DD9D
+:1031F00063FDD2ECE17AC3FB831B607ED35C2905BF
+:10320000388FD7AB44D28709C3E5ADB87F5F5DC4C3
+:10321000F58D2AEFC13C72A25F6CEE6BA213F7B979
+:103220007359A003E9549DFF3494FB30FE3D28F709
+:10323000A12CDEC5F3BDC9FB58391F8BA7D8F5CC2F
+:103240008B598FEA1FEB8D1E553A54E9B2373A512C
+:10325000E932B65CA5CB68BD47F3EC489771DC2E2C
+:103260008CADDF58A43F3F787D8D5737EE1BFF14A0
+:1032700075FE03359DAC8C73D65B96897AA7CA140C
+:10328000C8BD1C39A7D247EC38B1E94D8AFD115BA6
+:103290007EBB32DFB3DE47E95CE1D6624946FD9989
+:1032A000E0687D698DD66F6B0FF4FF21FA6D6B4B73
+:1032B00064EEDF50FCAF8ABEED04395167447EE115
+:1032C000F2020FC2908E8EDB990FCF67A6BB85D01E
+:1032D000048DDEBFAED41A9AA0C12BEC388D03D07A
+:1032E0003F9025323CE70BD5BE4F7EE2F965A28CBC
+:1032F000E720096545199807C385E5DAD13F2C9287
+:103300001E4BF8414110F7612A1CE24AAE277A7839
+:1033100033AF86FCB7D65A9B0FED54EB3FCD54DF4D
+:10332000BA41086E83F5C499BD64E7C75D99166C10
+:1033300040792F78BBE767073B61FCD08A1B913F40
+:103340008FB6189919C60BAFF18526C0BA16BE7D87
+:10335000EA6D3C3C53E97DEE6A91EC9A4BF987BFEC
+:10336000AD3FF84F3174AECA2195DE7B93431A7F8F
+:10337000F0FE22AD3F78F0F534DFF143F7B063B6ED
+:10338000A81C52F9E2B0B2BE4343B66C7A16E074A0
+:103390006821B71A6F1EC6E9E0E6C1921D378700A3
+:1033A000474F4F746F51E888316F375E118EB3BC51
+:1033B0004BBBF348BED54B56E9F01EAB377AE7CF8F
+:1033C0008BF3DDFD45DC5FA6EA15667613BE377C20
+:1033D0007FC436D4731BE619490EDFDF99BBCDE2FB
+:1033E00088D2FDE5EA9558BD5055FB0327B6837496
+:1033F0006700CAAD57C6F982C37AD733EA78F111AC
+:103400009105B5E78DA8778AB572DC44DFE12F0F0F
+:10341000F7637E16E744BB645BBE9B4CA4A7F3DD59
+:1034200002A653F2DD0697460E341A5915AE5B34E8
+:10343000703F08ECF8B36668EC13878B8FDF54C9D4
+:10344000EB75A48FCC7A17D2C6770AB28C30EE9582
+:103450002E7E9EF65CC2C8A4F045EC81FF52E8E4E3
+:103460007E9437906E52F0A6EEEFC13A71E339695F
+:1034700093D19385FBC4C4B2273BD14E6D940DB25A
+:10348000004BB5B8B89C6B94A5C908AF753669F206
+:1034900076AACF881F9B12DC3B02B45F75B31B700A
+:1034A0001F86F3C27D8A4DFA4ACB3F7E296046785B
+:1034B000F92DFC1C21769EC395F59E57EC1675DD03
+:1034C000B1F51C2EAEDFF6E4BB87213C17E7BB1D30
+:1034D0002EF2E7DAE87C8FC60356088CF3FD7718E6
+:1034E000EDF6B5126B84F491F8EFFF2C0CEBF2C300
+:1034F00034701F22C9F01DED6AC922E379DB7F1702
+:103500007A4BB19FC6C43B4AF8F99E6F04FA6954DE
+:10351000FB513D7F8E9D4F8D81CBE9F10A9CD0BE42
+:103520004338BE52386EBC2BBD87FA8A5D0776FBE6
+:10353000523CD7ADB4B3CF82389CE4B5E3786A9CF3
+:1035400006D8BBDFA375597C37A07FC46D16B81CA5
+:1035500057E2351EBC843F4C3D5780FDF57417F78C
+:103560003FCDC4B4B214F6D7B83EC56FFCA021CC91
+:103570002ED64F601CA3F3D94BC193D9383C4D26AE
+:103580000B9DA7013CE771BCF84AC8DFF52DE1B9F6
+:10359000E24278AEB8183CBFF84726F71738417BAF
+:1035A00014F4CE0FEAB9BC9A5F9FAC9F477321CF4A
+:1035B000DFA58CFFF508BE6FDFA4D0A7BA7F365B0E
+:1035C00058C00AF690650A73235FA8710E6A3F9B84
+:1035D0005C0954BFB570DC26847BB343A073FFE65F
+:1035E000649EAAF526B92A37E1BAEE53FADF843A87
+:1035F0003C9DFBB9D0EE50FD056AFDEB94FAD7B9BE
+:10360000C66DE2F0B50F41B89A44B147783EE8E2A2
+:10361000F35FEAE47C3529E63C15BA9F367164D441
+:103620002E98BF979FCBCEEF23B200B651F4A40CD7
+:10363000FFC373F48578340FFC5E3BCC437AAD87CF
+:1036400073555308F030CF6BF3F578AEFAF65D742E
+:103650001EF8721993853E97D6ABBF7075EB55E790
+:10366000773C677DC2A5B5F359284F2B67CF2BE771
+:10367000ABE1987322353DA0D0418BB21F47B98989
+:10368000F23A45643E92DB12DFAF3E58C8FDA3DD3F
+:103690007458250B88BC032E7D5C8B04E2312925F0
+:1036A000EAAF826C00F3BDF9ABC2A6705326C0AB83
+:1036B0006B3873A2FF3F79F5AA0E239E730D63E466
+:1036C0007D6976B0C452FC5E60E0DFAF979B8D9061
+:1036D0004FB6B314446F383093F6072D554C16810E
+:1036E0002FFEE9E2FEDAB9AB3F61E84F4CAF80A5AF
+:1036F000D829DE685216F27715F73FBFB46E2DD386
+:103700009EF3BEA3D067929DFB6D31EC0BDBBBCD6E
+:10371000C9051B99B69E41F177BBC32EB22FB87F66
+:103720009B427E504E386DE40FF2B02E09E5CE413B
+:10373000A193E2CEBE2E18FF1EE249E5A316035B5D
+:10374000C2F5A2EFA271435DCA78BDC50D3DA8F8D0
+:10375000E50E623C10E18BC7F93CF8975401E72D68
+:1037600049BCBF6CE8AFA10CE1A3C7D7E5E229BE15
+:1037700086C325967E328A39DC84116E4331C2E3DA
+:103780009BF3E7C591E8C6E0FC165FE35C82FC6250
+:1037900065894E0153BB4CF118CC22047305F4E744
+:1037A000FA885FADA5CE5411D7BFC0C024B0E3C71F
+:1037B0002BEDDD554C782F8F40C8B8DC96D87B2A8E
+:1037C000FF60A1DBF95C10FA9D786BA213ED74D851
+:1037D0003F7A71BD13B240EF011E3207737F7166ED
+:1037E0005A12C5533CD88BFF5E8DCFEA8E530BFC2B
+:1037F000E8B02E4ECDF4F0615D9C1A7BF8F0BF1559
+:10380000A706FDFF6FC6A9A9F21128D388E7E187B3
+:1038100044D685F4F5F1DE9B8C888FE64AD68EF08F
+:103820000F7C05F0B644E16D1CE779FEC7F0DD784A
+:103830004BA2B39120C8FD3547E2998CEDD5FD9F91
+:10384000C0F2888EAFAF129C48771F9BB8DCF87827
+:103850009140FB99154FFFEA7768972EFBCD0F1229
+:1038600031D8E294D49A81F3AADBD19488703C29B0
+:103870000512D17E3A1514C90E8BC5CF9A62D59E1A
+:1038800077270A401F2B15FA600BBA9AEF86F97D4D
+:103890002EC07A607E2B777D49F9FD6E4B17CBC227
+:1038A0007EC393EE81FC52D87735C0F7FADD7A7982
+:1038B000BDEC673FC8B027D0BAFA19B2088DFDB089
+:1038C000DDCAED4627D2EDCAD744842CAB675DCD67
+:1038D00038BFD8F6F5EDC74DB84ED9C0BAB2475D7E
+:1038E000F81D38D884FAAB9EB590FFAC7ED7A9C33B
+:1038F0000CD318BDB0048559D985FA6165B1A21FF2
+:103900004A5809D23BC087FC1D0198176D6B83E9AB
+:10391000640735FEDCEC3641F9A9C3995BCDD0DFF5
+:1039200099ED7F4D148645F504636B097E67DA07D0
+:1039300025792F624F7FB48691933A6A2771FCDA1A
+:1039400077C3043321BB87A775C650E2285877DDBB
+:1039500056A33300C575BF12DD36947F6F9A89AFC9
+:10396000EB7E75D684745827B8BB04A21396288CB6
+:103970008CE26DF9AFDE9D8474B51CF4F014A0D315
+:10398000654F9DE3F5DDACCB0AF5973FF1CEA47B07
+:10399000300F7AD6D203DEC6B77798C2B61EF0D6FD
+:1039A000FECE24F41F36FEFC0BC2CBA9670496E9B9
+:1039B000B8B0FD921DA7292EF70C20484E463C8A30
+:1039C000B5A6A40BEB9DD91E4FF2E9CC1E81CEAD5E
+:1039D0002E85C769C59CCF80DE7FFD07187FC96132
+:1039E000B313CF0096FCFAD644F41BBE2FF938DD92
+:1039F0003FD694E186F92F310632644A79F992B6BE
+:103A0000DB891E171FBC9DE27A81DEFB184A699D87
+:103A10007D707D0BB7DC40EB5BF2D87C5A1F7B548A
+:103A200060C81AE72436F9891EF0FA99C23766B6DB
+:103A30002AFFEE34F49732B611D6F33E3AF1717F95
+:103A4000F93791FCD066B6ED8880FEBFCE7401CF09
+:103A500013C583468A1FBC6D6F32D1D38162AE8796
+:103A6000C61F3C3709F9EB3687E433CBB4FE1EE3BF
+:103A700008EBF15F39D8EFA7A6D950FF33258E5058
+:103A8000539FE0F5FE36739C3002D28CEE73CDBFAF
+:103A900031A413E52CB67EE7FB44272C6B9021095B
+:103AA000D63F68245F0F96FF282D1A0FF7D96BC7F2
+:103AB0004D7D912FD20C2C17E6B532F8098D3B4580
+:103AC000609F207DA8F0A8DF6D66212DFF6E7F37F7
+:103AD000867FF5DF413F13DCEAC132D8988670EB70
+:103AE0009AF4471C07C6DD01E32C7A18EA6BF83517
+:103AF0004A17A668B923CA7F4CAC49C273ABC50A42
+:103B0000BFC7E22B96FF3F2A56CE2714FE57DBB3E2
+:103B10002DE93DFA67A3FC1E207D50670CFE14E1E1
+:103B200054F7A699CECDEA7EC5F90C0476572ED06F
+:103B3000FDE95FEE7BFD6658CFE976631A9D55C5BA
+:103B4000C8D7254F029F427D6396C8AC245FBF3023
+:103B5000A15D94359E759961FEA7D33C0CE9FA02EC
+:103B6000FE84F21EF9338DFB6BFF637275D7FD9FE8
+:103B70008889BDF3E3E25EE46A9F917AB97A8E0D9B
+:103B80004B8261D807BF583E90CEB562E0ABC235DC
+:103B9000563EFEB6D8DEA37C84BFD799068ECB1ED8
+:103BA000FF90E8F8739077A21CA55FE6E5F40B7927
+:103BB000535F5C6F8681617E65B0E37A21BFA77534
+:103BC000EBE119FBFD6DA43198BAD1E024D7C6CD45
+:103BD000E9DB13F09CAC51B1EF1B6D06E2EBCE6C50
+:103BE0003BC58BE0BD8D3B60DC1BEC836F41FD3939
+:103BF0006FA4AA67391F4EE35D43FB5B18C63D8285
+:103C0000DE51E405F03187A7C2F706D2F79D69A51A
+:103C10003FC57DC20DDE5335B590CFEA273233C99B
+:103C20002F2E17CC5415F635EE5B992B8D970FCCB4
+:103C3000D2F5C7E5A8FB9F127ECF1A6FE9C2F68DB9
+:103C4000EE99C65DE8B72935CB827C21DDBFDC105B
+:103C5000CEF6F560D7A9E9B4B40355183F7D5DA948
+:103C60009EBF6F8EE1D39BAAF4DF6F64DBD2D1EFEE
+:103C700075E312230BE2BA62EA178FE4E75F37318C
+:103C80005F936C8BF2DD30D63507ED8744B07B5106
+:103C9000DE265AB299C4D7DB65A6381A99EC34717E
+:103CA0001C6B27BBBF548A89E7964368B734AE8242
+:103CB000F6688F66333BF733E8EFC14C146D141789
+:103CC000F84A29EC771D9492BE7A65BB1044FFE850
+:103CD000B98AA79A31D4070DF200C07F99824F1696
+:103CE00008D7603B91199C28D798DB6D9747323AEB
+:103CF000BA467A4D2A35E8E45AB23B4E0797D4C902
+:103D000029BA7CBAA7AFAE7E66558EEE7B1FEF5503
+:103D1000BAEFFD9614EAF2FD7DE5BAFA03FDE3740D
+:103D20007947E07BBAFA83D6CFD0E5735B6FD6D5FF
+:103D3000BF72F33CDDF721C165BAEF4377DEA2CB5A
+:103D40000F6FBF5B577FC4EEB5BAEF05A18DBAEF19
+:103D500045071ED4E58B3B7FA4AB5F72689BEE7B6F
+:103D600059F817BAEFA34E3EA9CB8FEEFA83AEFEF9
+:103D7000D8C8B3BA7C25FBABAEFE78CBABBAFC445B
+:103D8000F92D5DFDABB38EC7E8313970AB0BB7874A
+:103D90007C9F748DFDB4AE3EECA46B906E8C0A3D9E
+:103DA0005C9B7756F77DAAF36B5D7F26901BB8BFAF
+:103DB000B560DC25A471AC9D521BEBA474F038EF08
+:103DC000FE912847DA02CD48542F977D3100F5D671
+:103DD0002B15B7D23EE15C16DFAF4BB04F46BABEF3
+:103DE000CE620BA01C57F9353122B25011D061447C
+:103DF000A0548EC4B3106C6A9223564A5322A9541D
+:103E00009E1A49A6342DD28FCAD3237D28CD880C83
+:103E1000A23433E2A0342B3294D23E912194F68D19
+:103E20001451BB7E91024AB323A3A8BC7FA48CD2B9
+:103E30000191F1543E305249A93D722DA58EC835ED
+:103E400094E6446652BD4191E9940E8E5453796EC6
+:103E50006416A55744E6537A65A496D2BCC8724A44
+:103E6000874496527A55E4566A3734B28AD26191C1
+:103E70007BA87C78E42E4AF3238D948E883450EA14
+:103E80008CDC4FF50A221B282D8C3C44E54591071C
+:103E90002875457E4CE5C59147291D19F909A525C9
+:103EA00091AD9496461EA7B42CF2734ACB234F5182
+:103EB000BB51912728AD88FC91CA47477E4FE998AE
+:103EC000C83E2A1F1BE9A0D41DF92B9557465EA0BA
+:103ED000745CE4552A1F1F3948E984C85B543E319D
+:103EE000F226A59322C729BD3AF20EA59323A7294E
+:103EF000BD26728AD2EF45CE52BB6B239F503A2526
+:103F0000F235954F8D7C4969F7FEA3A2D77B808659
+:103F1000F3903E10DFC6F01C659A4F207FDF23F13F
+:103F20001F3D47F2AFCC6CC77C1336E9C3DB633C63
+:103F3000CE6CFC879DB18E327EFEF6F2BDBC5D7309
+:103F4000E5F1B76F45FDB6CACCD03F142B57D5F974
+:103F5000BC52BA2F1DCF439B0BC375E84FDBE4085F
+:103F6000D7607A5509F7A30D2EE1FA33AF84DBCB86
+:103F7000DF2FF5968D83F29A553B5EC7389B4F41F4
+:103F800045521CA32D7805EEEB7DA83F904FD278CB
+:103F90001C0DB3750DE0725E267D01F64317EA87AE
+:103FA000957B32C91FD582FB748AAB0C37A37E3157
+:103FB0002AF710D96E3D9CCCCC69B1001FF6A6370C
+:103FC0002EE5EFFEC2CAEF4FCA25DEB1253DF8B996
+:103FD000A3FEF3CBEE67F27FA89FE925C5BDF7737B
+:103FE0005FDA1D9E5ACC4A6ED354D067D50ABE996B
+:103FF000F8E26CA48B7301B39DEE0104164F417B74
+:10400000D15C678CDA8B0CEBFB58A503F1BF6762C0
+:10401000098C1B7683FDE1BCB01EFC25227EAAB371
+:104020000D8CC797B63F8FF8F5427DD4D7D56887FA
+:104030006AF6390DAB9EEE8FE758F3147BD45BF72D
+:104040003E9DDB7A95FDA4F7127EE2FA12BDBDCA51
+:10405000903E713D75229D37EF4BBFE3C048C88746
+:104060005F12E97C98C9EDFD092EEBB91DABDAAF03
+:10407000B5204FDDC06F6FA5FFAEBF1DE6B36FC5A6
+:104080009D5968A7DFD7F48411FD32E1FEABE83219
+:104090004CECFE3FDC9F99F0BCB13AB04A42FBD8F1
+:1040A00068605B681F318091BFD310BFDA8EF25D0C
+:1040B00034E8CFF5CF2A7CA0A647D1FF857CB69205
+:1040C000C73F190D3EBA77CA06C419F83D84401D92
+:1040D000E617B45C998376E4648959244D5C86C6FE
+:1040E0004E8CA37D9504636BECCA583BF2B112FD74
+:1040F000FDE4E302BF9F887FB8CFA176C82792CFA7
+:10410000DD80E332D9FE238D7D696E9DBE1CF17486
+:10411000B4FB9E17AC11E90AE70A78A85E1DEF1EF2
+:1041200002DFB729FC6F54E2AD805E025ABB1CE986
+:104130000AEB4BA54A3C91B24E6F8BD98EF4735C5F
+:10414000084CA078C24AC67614C4CCCFC0E75789C1
+:10415000F5717E408FC6FE1C8E273609C16D04079F
+:104160001F856ACE7FAD2FC52BCCCD3499504E79AB
+:10417000D7AD0A61B9179063877599252699009E76
+:10418000B58A3F9CB508E40FD7AD0BE4C789A627D5
+:104190009EC7EF61C19E23437F7F56D617C671B17C
+:1041A0007C138F5B68BA37C1CDD7216C453DAFC258
+:1041B000ADBAA5611523BA6E37DE85747226C18E3D
+:1041C000FBE56A65FCB922F35D0C4EE74ABAFD7D5A
+:1041D00047DE80FEE707CC0CCF0761FC391E0D1EC1
+:1041E00034F009BD81EB57E0D3A4E0D9ACCCA329CE
+:1041F000FD0E86F338FE61821DF75FE74B52F87AB9
+:104200001AEEA47DCB895ABB206ACED562E745322F
+:1042100044432FB174663470B8A8FCA0F2814A37C9
+:104220001F29F4AFA6A7BBD7A7F18788513A8DED18
+:104230005F956F576BEB43F9D5D93C4EF6A8E25723
+:104240003EF9F4B96A8C07682EE1FB1266F7D17D5E
+:1042500073753E0850E217857ECD368B7B08C0E72C
+:104260002B653E4D82A70AF76D814D66A28BD87DE6
+:10427000D45BDDF3665E932A5F0D586EA7F2EA16F3
+:10428000B3DB0AFD55B73E7D27EE5F8F09FC9C1B13
+:10429000861D80E75778204F7054E8EC69A5BFA7CA
+:1042A00095F68037867EA8C00366BECF54E8E52821
+:1042B0007601722CBDD42397E2F8923B9FE4DB6A2F
+:1042C0001E175963E8C8C5FD5FCDDA50AE761FA84A
+:1042D000C26D725F50BCB87EC999817CE1F09527B0
+:1042E000219CCFB61427A13FCD9BC8BF0B92B7042A
+:1042F000F393FF35BFC484747B3881EE0FCD1EC4A9
+:10430000E6CEC0780AE5DC7976E33593717D579681
+:10431000F2F9BFB2065678256307D758981B88E490
+:10432000D53532E5FFBE268BF26FACB153FAE69A73
+:104330003C4A4F98385DCC4EED8E1F37E17C869716
+:1043400072FA185EAAC2F9B62CDCE74FFED7ABC5ED
+:10435000782E31617766CD3563A2EB0B2B7116D7C2
+:10436000B901991A7D51757DBC7208C3F3B59E5190
+:10437000BAEF2CAF289ACFE17481F43B6FBD83CEA6
+:10438000F9664D49D5D5BF717D3F5D7E62A99DE03F
+:104390003A7DF2205DF9CD354375F95AE5DEB483F7
+:1043A0006519D642FFB71E148328EF6E5D7575D26E
+:1043B0009D3C4FBC150BFF3BE607E6E07CEEF88921
+:1043C000D989F724E66F16582095E0C6F5C7EB3C6F
+:1043D000EE7AC1669179A1FF0F92DD9949D0D54956
+:1043E0002B5FC7C9BF8B5B1B517FFCAB91FA810D63
+:1043F0008A9DCB5581F8F48383B974CF64F6A0C04D
+:10440000003C97EA4A67F66DF07D7E988FC3844240
+:10441000F2AF9CB2BE7DC59D30BF0FA7B62EC2B80D
+:104420007DB023D251EF7DF8A4C850EF2E5DF5F793
+:104430009132C06FD9FEF6D71165275A4526A33FA2
+:104440006DA799E21501AC9948F7D1F505F391FEF6
+:104450007E52EC598A577F3E5814CC27BFC1EA746C
+:104460006E17C4C001D6BB08E55AC09068DF81F260
+:10447000CDE82D413FFFFC37FBB306414BE78A7F78
+:1044800051E927C05C7D18F95D9E24FA39D1923B31
+:1044900089F4CB7A81A17F1EF8671AC9BDD654036F
+:1044A000E27B5E8B48E7FCEA39B3AAF7D903A2178F
+:1044B0006C0E6CE7E57E2DD910807EEE7BD9A8E0EE
+:1044C000B184E203E7F4E2CFFC0878C5ABF1972DA5
+:1044D000DB2B7AE87CD5251B9AD16EEF9CB803C7FD
+:1044E000FFF4C0A024B4A74EBD36D3C8E1B68EC633
+:1044F0005FDAD8918F715BA7A706DE93209D6BF2E0
+:104500003E80FC7FB24FFB0F4741BD8FF7FC64003C
+:10451000C63D85957834751C6FEF71B18F90FCF0B6
+:1045200073BB483D375FF60B2BD1CDE7FDAFDA2AE1
+:104530003AB4706DE07050EAC35F16F7C787320473
+:1045400080ABD7CE26E1396C356B57FC3F1C6E76BD
+:10455000245A809B5CC7FD81F30DCE39AF221DAE7E
+:104560004D90118F6AFFC715FEFDA5C2EFAA9C3BB7
+:10457000A9E4E7AB7AE5196E2F01625FC7FBF64B42
+:104580006869741E61423E52FD6C7F2C4D51EC8B6C
+:104590002E13BEDBB07CB789E2551629F79CEA766C
+:1045A0009A834158DFE7A55CDE2E33FDEA8778D099
+:1045B000BE18110BFDACD82E044302D6DF4AF452CC
+:1045C000070A295880DF83933AF1BB1D142DEE377B
+:1045D00082FC3EBE050C30941F01166C4E81FE1706
+:1045E0002AF62FDB693CA1DD8FAC68D7DFDFAFBFD8
+:1045F000E0BEBEA719FDC20BA07F6CBF90C59C2B6F
+:10460000B41A491F5A98A501FBF3C427901F73D908
+:10461000C37CFF169D8FC8CE03CC167983FBA7D130
+:104620007A0567905D389FC5385E5A743D979A5FEA
+:10463000EC7C1639B91CA96B1582C11EE6A7C237DE
+:10464000A982D9515E2C07B8225DC3B813F01ED4DD
+:104650000A985708AA2C0A78126F82FC2220A820F8
+:10466000F9073DD350FFD53F2CF27D4580FD0DDF8E
+:104670005350F1BD18F08A705AECB5D1BC97F8BE12
+:1046800020FCEF073C23BF2F7D226842BD7E9AB5F8
+:1046900026DA805FEA363F716319B6DB72D0847622
+:1046A000424D4A28D70026B1AD6CF5960963B07B20
+:1046B0000FE99D8596964EADFF454D9706F57059CD
+:1046C000BE539FFFB670638A1F7821FE0BE36DB661
+:1046D0008B642F68EAE9EC9D25812E8AB75902EB9D
+:1046E0006D94B1344074B9D0C9ECB82FFE77E7C7E8
+:1046F000C41AA2BB734007624F747799F38DDDAF84
+:10470000E59629FB35278FEBF9D4A7C485AFEEF9E1
+:104710001E47ECB9CDDB4699F46517E84BB4B33FBF
+:1047200093B8DCFDECC5DC208A96DEE4EE22454F32
+:104730002E44BD08E97B9B9F4AC47DD9BB0F3F95A2
+:1047400041E74EA85F8669F56CA83FD2CF1D4F5B4D
+:104750009D3032AB79CC1C427FF7995D66F21FC762
+:10476000CE7362B1B7B20CE58BA21F3F100E8E94D0
+:10477000512FFA7B3E8F8AB5C3BEEBBAE6E1BA8A07
+:10478000D00EE0EB3AB69EAFE7780B5FDF820BD638
+:10479000A5B71F4E5A43A4B74F3E21B246BECF9C89
+:1047A000437E480BD05101EE5F5BC80E38057600A2
+:1047B000EE03D4F5ADB8E58D2312E07DE9159DF942
+:1047C000218047CD0366D2EF4B7F9B40F0F940A894
+:1047D000CC447E3BD36A76DB106E3BAD541E9D4FBE
+:1047E000B7BE5F5CA6D5F797092FB685FB81C0C61B
+:1047F000263F90009BB89A427E2E83F78498CD4046
+:104800007A21B6FD63655C7FAC100D645FD699B804
+:104810009DF9B1B22F5AAD7C5F5DC6EDCDB565B2E5
+:10482000AA37DA106E07F79A65BA0F2BB11508A7E9
+:10483000838281CE31FA957B1BCAA0FEBA37CDB9EF
+:1048400028BF66581267235FAC4B5E44E766735817
+:10485000A711E131AD74D54E8A13E9CB648AEBC15F
+:1048600090288D3FE665E3DB136F437B04EA8A60A3
+:104870009B5797BEDF1FEB6FC13CE0FD88B57DE223
+:104880006DD8DE21318C3B09EC35931E358E831DAE
+:1048900020FAA9E34097E3FB5A95FB9A10DEFBB39D
+:1048A00052F364A83F578A7372FB814DF804FDDD13
+:1048B0004B04B253D8BA7031CAB9116C9D8CF12D2A
+:1048C000B0EA5DE7532F067F7D9C51DD38A6DCFF03
+:1048D00004C494125C75F93A93F23DF066CD67D941
+:1048E000044709CFCBFEC6789C4D5D4E97E4463B0E
+:1048F000B392B56F0378DC50EA330E7351FB4FAFC0
+:10490000033A0BBDA08F73BA4EB2D37D856C37F3DB
+:10491000896477D827227C0E81798DFD092C8FF24E
+:10492000D326B314CCCF600EF2ABCF703B9C8D007E
+:10493000DFBAB5973BDFF794F9B61B71BF3F47F17C
+:1049400037D6199EA4F1D5F9564B611A2FBB8209AF
+:10495000889FFA14D8DFE07A9672FF83C1C2BFD76E
+:104960002C6129C83F750681E86DB3F718957B1D4A
+:10497000F614EDFEFAAF2A7DAAFB1F294CEF131D9A
+:10498000AFE2717005304D2D9EEA4DDDFB243BF604
+:10499000B71CD42AD65BBEE7E95C8AFF13EC069C01
+:1049A000D71B65DC4FB15C7D27E9977ABFE897E8B4
+:1049B0003BBD085F7CAEB4FFBC8CC7831D2B53FD91
+:1049C00035EDA42797EFF9F321DCF7F5D6FF0A338D
+:1049D0000BE1FCBAF69A092E82A16B30C569308AC8
+:1049E000E0C07E7231BF0836C238FFCFCAB8BDA65C
+:1049F000D2F722453F1940689D277B21602A837E9C
+:104A0000966CD1D82FF0FFA58CEBF965DBF5E54C62
+:104A1000ABDFC89FA0F7970BA62EBAE7278CB13A59
+:104A2000510E569BDA69BF2CC08600E96F512FEDFD
+:104A30008CADDCDE31B608643F921FC485FE31B018
+:104A400017215F9BDD351CE5C0BC341F7F3F4AB199
+:104A50005317F1A9B045BE3B19EAD9FDA0C791FE95
+:104A6000CCBEF70F5330DD663E7F49B123E7B7C6B2
+:104A7000BC0BB55EBFBEA32630B160FE473318E95C
+:104A80000B33AE57A3878F1AA607D05E08E44814ED
+:104A90009F6164B1FADCC3C86F90C6CB25C55EB315
+:104AA000941B55BF9CEE7ED539F68D8444A8E63D17
+:104AB00013181B53D8BBDCB8CE1D1F42FAB8CE7DED
+:104AC000F5019E6EE8A473670964670AC5F3B28AAC
+:104AD000422A27BFAF67B21088C7EF6EE307DA75C7
+:104AE000BE82FFE8216EC159DE4B3C4845EA65C5F0
+:104AF00083A8F1EE3528A70745CF396A5EE0F1D2E9
+:104B00005F58FF35E035C8DB0500D400F2CB931FBA
+:104B10003EB0D62C37A6A11DF3FC6398AF69900870
+:104B2000FF5F585F7ED7EB423A4F6202E07576D264
+:104B3000FEC7D08FFFBE64217BF4115C9C0BD79124
+:104B4000C0FB378469DCB92C7C1AEF555C9DD69983
+:104B500080E2B966552EC5A53557166DC6FB51378F
+:104B6000970F9F6DE98F4E09A6BC0B58FA0F8C1357
+:104B7000BCFE1B5817E5CB66BB4700DF3EDF3507A1
+:104B80004662DF2F2F9F2D01BC3EFE41571BE67F63
+:104B9000583E81E737750DB052FE5A9E6F50FA634A
+:104BA000D7CEC6F8AB8F1FE5F93AF81E20F912CA26
+:104BB000457D3BCD6775A2DE50FD4935866729C529
+:104BC0008D33CA25954F3ECFFD64CE2D44575D747D
+:104BD0009E531F17326622FF3F2138B741E98ADB17
+:104BE0002A132B19D2213F2FAD53E4493D1AE590EA
+:104BF0000A6E1FC9ED809DC9FF85B2690B8F0B60DE
+:104C0000CFB2768AAF1C06F37145E733A7DCCEEF4F
+:104C1000EDC6CC2B58EE99539E8EEF389E48407AC5
+:104C2000F8EF0AF79C723A7FF2DC89E5ECB5604652
+:104C30003AF4BBCCC03A518FABF7B5EE33E8E3FAA8
+:104C4000E794737B404DD78DF2503F2A7EA0BF86FC
+:104C50007FA7BFD4517C9E6A7F2A3C172AF084FE2E
+:104C600037FD3BFDAB724CEDEF1F17CEFFD17FA799
+:104C7000FF9915FAF9AB76AABA8EE1688B019EA767
+:104C80008F61BAF9A8E54D4228FDA6347A87D1890B
+:104C9000F7BA1C9EEAAA5A18FF6CA9A300FDDB67AD
+:104CA0007D254906E8F70FE58A3FF65EEE1F684A64
+:104CB000BF310BEDBDD3BF5A9C8AF6CDCA087F2FFA
+:104CC000A03EC2DF0F38DDF1A609E306EB77BD3366
+:104CD000A91FEE4BDB0BAEA0E7B6143BB32EFA5E7A
+:104CE0009184F7039AD2DF936A691CF59D4EEEE733
+:104CF000388271423DC4111E28EFF657D33AF3951E
+:104D0000F5748E7677946BD6A996ABF7BF62FBB13C
+:104D10008DE2FD6C45DB233DDADF0881E3AB268EB7
+:104D2000EBE3E2D79C8B5EA57D71BE01DF111979A3
+:104D3000C8679A07E53B4AC7BD82F057C753DB45B2
+:104D4000FDBB5D7AFFEE1EEEDF55C7712AF3AB495E
+:104D5000E9BC0DE3AD6D7FAC7F0CE5CCB58FB0EE5B
+:104D6000B86DF49B4E36ABF9E6D9132AD08F285292
+:104D7000FEE33FAC792C00FD1D88EBBCFD55E4F350
+:104D80000D096C1BC897B0E3ADDB71BEE1FF4A268D
+:104D9000BBAAD29C7005BE1793505A691B45EB64A1
+:104DA000241F124A3D27115E6147BC018C51A0238C
+:104DB000E3228AFF0E58C99FE8CD8FF7A21FEE802D
+:104DC000814D602951B8BDA7E0C9368AC3ED807214
+:104DD0009F03FE063C897EBCB50305A46375DCF425
+:104DE000D2CAF851C5D171D34B3D91F2746DFD24F7
+:104DF0008A03ED6DFC58BC9D2BE7F650FC284ED77E
+:104E00009E0AA03F8D9E9E31215E97BF7E4A2A73E7
+:104E10006BFDC7D7F7D3E5AB6A06E9EADFBC60A84C
+:104E2000EEFB5473A74B6B97A878BBDC7D53678769
+:104E3000372D1DF71702EBFAAD0BE1D5EE7A0D53C6
+:104E400083EC413DB67CFD35E4974E8A54535AD7E6
+:104E50007A0D05CDAF88CCA4FC4AE5FDCE57C4CE73
+:104E60005D07B19F479264B42756489D9F61FCEB54
+:104E70000AD940F787000FC37761BF39A3C9EE5E37
+:104E8000B9ABE30A8C9764528213EF054F15FFE626
+:104E900042FD3775A06C68C438E38895FA9D4A8F47
+:104EA000F4009F14276C443AE88D5F8A147E3186A3
+:104EB000F97C2746A6EBDE372D1B95A3B3578CE96B
+:104EC000DB25E413751DC6B040E9F7224329ADDFA9
+:104ED000355DC273DFBFE4FD240DF504D4B761EA8C
+:104EE000F08CE2FC02F2875D248ECEACC89D6AE5B0
+:104EF0001C79EC68F734A4EF69ABC312BE3FC46CF5
+:104F00002619F7A3D34A0BB21669FA69EC98C55073
+:104F10003E99D39809F56E35A4E335DFBD31F7C06E
+:104F2000D4F4FA51EA7B765C3E75DF33F69FA273C8
+:104F3000A43932A719952E2A471974F7D13B513E4F
+:104F4000A3BCFD2D3F4FAA1AED5D8C7CD159C9AA97
+:104F50009E2479D13900DF85FA4FCD1F7A76D1BEF4
+:104F60004CE6FB934429CC5200DE75A35439CBE9BF
+:104F7000F352EB98A5D47F45647EA48B57C68EED83
+:104F8000C4FD56C73D4545F4DE9DDCF50DD255FD0B
+:104F900033A306E13E7DF5287EDFB8FE191EAF5E25
+:104FA000FF8C99E2D5A7A676BDC7F723563B9D1384
+:104FB000433BA4CF8FE123EA9B8431DED5A3A8DD58
+:104FC000A922D467EE3D5F1CC1B843B72D816E7B2B
+:104FD00004CBDDF7921CE9659E97E2438767791A57
+:104FE000EAD9B330058C773DEB7BDAF51ACF7B68D5
+:104FF0005FB89EF39D57E1BF5A856EE729FC674471
+:105000007A2B42BAE3F4561749E6F524CE97731F7C
+:105010004E9203C89711076FB75A207E046411FFA0
+:10502000CD53E83E960F574652A91F951F1F1AED04
+:105030007D9CCBE94E971FE6F53DE06F3C47F7AE10
+:10504000EDE342FEB8347D7C29617C84B14230229C
+:105050007D98211DAFE1678F82EFDA057C1F555BDC
+:10506000EAD8A63D2F6FFF9674FE98527F9E0DF4EE
+:10507000641ADA97890CFD6A35E976F28FDEB2415F
+:10508000A0C7D36E318672D19EBC659595FC608BAE
+:105090000F792725D82FC4D7AC483EB3039C66466A
+:1050A0000653BAA3D4FB0CE2BD3672A3828F7C7E7A
+:1050B0008E67CF52FC75FCFCE7335F49E69D3C4FA1
+:1050C0007E9D6237F7BB198366E75607FADDBC227F
+:1050D000E2F9647F263F44FE24FE5DF5BBA13F0F4D
+:1050E000FD7AEA391ED04DB71F0EF9C79C66D09DD8
+:1050F000275EE08FABE4F6D499ED461EDFDEF1B714
+:105100009178FFF703879BFC723F29F6BE81785D9B
+:105110003623F86B23FAC55B9F7A1D5DF32A1C6B5F
+:10512000C6B16B69FFF3AC81FC82ED2D22BDD709BE
+:105130007FF1D3357145AAFDF002E3F6462C5D2FD1
+:105140008B0C22F8A87A4595D74FAFA1E0E66EB94F
+:105150007D297D73D6F706D1F559A06BDC07C5EA2A
+:105160009B95BB9E20FE813F4FAE4BAB4FF4F41D91
+:105170002BA73BC7BD45726932FAD7E0FB3EB1FDB4
+:105180002134E9C63DFEF55387A1B3BA2767113F25
+:10519000560E1598D8833F51D5C3EAFA5578FC4589
+:1051A000C9FFABC29D54517C397C62253BD51C980C
+:1051B000CE488E42AA95A3C6183B552D4FABF87624
+:1051C000FC61A8D0EF07D479769A54BB89CFFFAFA2
+:1051D0008CDB15EA3855A3670CAD48E77A01C77731
+:1051E00056F0FDDA7F6E5D3DEB0767F7FA2E4F3F15
+:1051F000F457EAABEB53D7A1AEEB4565BD97AB3F98
+:105200002656F077BEBEADFE205F2BCA5B6B129DAB
+:10521000C78FF953D967F7D8518F9825B4233A47E8
+:105220008F9F58A1C1833A2F759E2F29F3063DF316
+:105230003D6D3DB5FC7F4AEFC4F26B2C9FC6F2A5D5
+:10524000CAAFD7DECFF50E437BB007FE8CDA83FD05
+:105250009D8D0CF9959FBBB23CFE0E7B2C9FC6EA40
+:1052600037953EF689DCCF7BACC2BB1AE971D4CF4F
+:1052700007EDFA03C0B5F2A92F9F3A6CBF1C7AFC68
+:10528000BD91F4519D40F68A1952AD3EF2F6C267C7
+:105290000DDF92CFEA95FAAF204ED1CE4A32919DE2
+:1052A00075297A7BA8E2BBD92B97416F0F21BC7A75
+:1052B000B3A73757707B1AE86D73C5BF65D7FC91EC
+:1052C000F613484FB88FBAF6AF4E8A67414060DC9C
+:1052D000D45471ED2F711D5307C51734C23CAF3D37
+:1052E000CFF723A093683F122B8FAB1579ED55F6BE
+:1052F000F37B467BFE88F33B10C7D77BC0D43F8847
+:10530000FD5CAE9D5A9DE663E82FF342AA9543E605
+:10531000EEF704F4780F7D4BBCFFBAE2DBD9A79D12
+:10532000DF51BE807D7AB822BD77FBD469940DEB46
+:10533000A0BEF3253188FEC44BED5FC4CD1CBEDD9D
+:10534000F00A49AABE4F457D0F74F116C9FFEF4818
+:105350001753C7B77F66017C7E5D71F71CF437DE9B
+:1053600088B122E447B8A7CD3D18E50753CF61C8FF
+:10537000CF407C43F9D54726C0FAAE7D8845CF693A
+:105380002C289793BAFD1202D3D6BFF7C819C4A32D
+:10539000372C697F4F26763EEABBD8CC05F5123410
+:1053A000F9D298FC16DE0FEA231EC7A29477EB2BE6
+:1053B000C6F8FB045D93307E61DA2EFE5ECBCD1520
+:1053C0001F9BD0BF32757C787F3F8C2BD8BB768EED
+:1053D0006D0894A3DC8379678FDED816A0376C0341
+:1053E000241FA6B5F3DFD131B7774C72F7C09FD930
+:1053F000A3F57A10FFF03D803A050DE6768161FC59
+:10540000535DA910CCE9E17CBAA7F678EE48ED73BC
+:10541000A87D08E3C92FB7FD4D153DBF7B70955A98
+:105420000FFDD16AFF809B99ED82BB27FF49A152F6
+:10543000BFD36058818F45948F6E6B43BFD344C6F2
+:10544000E9A362F46373B8FF19101DB3DE8BCDD7E7
+:10545000DEC37AEDFAF6A18BC1EB8A0BDA2B785F0B
+:10546000A2A78F8915E7294E766205E868E867A547
+:10547000C7DA828F854C1DAFD2F7CE39EE6C589FBC
+:1054800095E9FC68517AFDF91CA4EF954CFDFE7876
+:105490001BE2DF63E8AECFE97D8FD0DD3E4FA2F7A0
+:1054A00048A8FD8DA37FD1867E37C0077DA7BC7439
+:1054B00011FA6E8FC95770FA8ED235CF137FA25C66
+:1054C0002EE5EF51C4C267D5682EE73E54E2583B43
+:1054D000C771FBB15379BFA67534D7277EA55E404F
+:1054E000C5B3E61D08961DC53353DE89D0AC9BE0DD
+:1054F000342B4D5DF7813953605D9D296CB8007484
+:10550000B271F4736DEB884E3C12EE0724B6BFED1A
+:1055100045902BB314B8B48EFEF311840B2B05D336
+:10552000298DF892F665E65D077BE4AFD917D24B7B
+:1055300000E5DC0A221C6C27B8F17D9515482F3D4B
+:10554000C063FE68BD1F83E6AF6FCFF0FD96CB6FE3
+:10555000AFE0634A0CBE26C7E06B424CBE469F4F8D
+:1055600094B89C4AC41821B09B662D7134F7433B14
+:10557000EF9702497090CB267C8760C7DE8373F07B
+:10558000FDE75744BBB11F7CF9F9DE578F588066A1
+:10559000A7A3BCA2F3F0D7DADC00FF99C8D794FF29
+:1055A000FB1C7712D289AF290BEAFF66EFEB6D1671
+:1055B000A87AF3BA078C18CBFCD4DE436D128EE7C1
+:1055C000FACD7EEC4F6A387C648A7011BA6C8D59C2
+:1055D000C796987C20A6FEC39790DBEB62DAAF8E6D
+:1055E000F9DE1293DF1C935F1FCB17F2A40C94EF2C
+:1055F000EB04FAFDB34BF1C7F3A3553BA0DD85E700
+:105600006E2F8E7EBFAD09DA5CDBC8E9FBE5BDEF2E
+:10561000CFD1D1671A23F95F9DE671F7449F1DBD75
+:10562000C9A3BC58FDC4BF8F8D1F9E84F33B51CCD2
+:10563000ECC82F27ACF6243C2FA0DFB9423C583AE7
+:105640009B2BF07B6529BD0F82F7DBA76AE2279FC2
+:105650007BC04CEB5BB88B9F7F4E887F6C529F3436
+:105660003ADFEBC2F70D96F81E99D4C7157D4F644B
+:10567000D1DB1C1E8BF60841BB40F167FAFBD962F7
+:105680008B48FE8D2D024B053E5CBCF9C27BEB784E
+:105690003E8DEF5A6CE47187177CC7B8CDC6DF9B8F
+:1056A000E48DCE0BEFB31FC57FF4B9F05CF8EC6866
+:1056B0007DBC991A0FAB9E0F7B2FFD3EE357A311C4
+:1056C000DE4A7C5AF77B5252281DE3131B5F482D9C
+:1056D000447AF893815930C4B43B2E56A97F660DA5
+:1056E0008C7025DE8F5F4269F9AE07447CC7FB638F
+:1056F000E19DFF330ADA777D68A0F3D0336B7C64D9
+:10570000847E74C655817EE88FD6F8956002257E2A
+:1057100059899F1DBDAB43EC07B98F761F8F27FFBB
+:10572000341E16E0FEED8C44F473D6F7C5BEF39438
+:105730003750BC958345F69D87716E4D48527EA7C4
+:10574000CF998970FCD3CB46B22355B87D7017A38F
+:10575000F87B75DE8B15BF53C7E3A97BCA71FF12B7
+:105760009F2423D83ED8C9DFF33C6949FAE914F4F1
+:10577000636D999981F7A2161ABB4C4E988F73EFFF
+:10578000747AB7E65DA81722380545B483CA27B3F3
+:1057900099D8AE3C24313BB47B57720A480F1F9D09
+:1057A000004A86FCE9107F6770E1EFF93D6DD62174
+:1057B0006DC57DE1FB5B9E9A86F953DBD39371BC8B
+:1057C0008FB6FF3D03FD5ACB98DC8171B99E319CA9
+:1057D000CF4EEEE4FBC96540AFF87EEFA99DDC9F9C
+:1057E000B80CE8D1225C48DFE37736103D2DCB12B0
+:1057F00019D2F332377F7F6119BEBF60477073FAE9
+:10580000B3C0FF300E2259A1CFE54A7CE9F29D3D9D
+:10581000D367DD6E4E9FB1F41B4BAFB1743A798CF8
+:10582000FE77A52E372EF2CC1A4674A596A7EE72F7
+:1058300008FD98564E78B2503ED0EF8E91DCEEEBDC
+:1058400045FCECEBB63FB89EED1099124FD037FCFB
+:10585000DC45F609513B9AFB291E54CE199F51CEC7
+:1058600087F19CF4891EDAA7BBB9BF68DFD71F3C5C
+:10587000FE1B9443034DE487068AF9A60BE076AC41
+:10588000BFA918E9B15BDE0D34F9D1BEEC30AFC968
+:105890005AA89187FB06667C83E7C2FB32E9172A88
+:1058A000D8BE7B8AA87DA09EBFFBF3CC80F736E1F3
+:1058B000FDC467568AF89267D4CF54C7E3F88D6960
+:1058C000ED090B35F3DB575F44FCA6AEE79C729EF7
+:1058D000F656F61D32D26DC7C0DB3AF17E59205321
+:1058E000A2F99ABFAC91F1FDA0F1784F0BCF9FC701
+:1058F00070B97C24727327C68137D972E878B96988
+:105900000C5F6F53F68D167A7727CD40FB2963C263
+:105910006CD9A4598F3B4DE2F372E8DFD94E1CCB12
+:10592000E9FAF018EE0F78569469DD300FFEBB0FE0
+:105930005FD71CEA84718C0346DA310EE7CB3183E2
+:10594000947B847205C6538C17C3454CE34F9A650C
+:10595000E0EB8ABD9F88EFAC215D373A2492BB9A79
+:10596000FB55168A0BBAC43DC29F8E71F0FB6206CE
+:105970001EC7817F827A8F49C4FD39B707274B3E06
+:10598000E24FF97A1EEF654EB3B8AD89748F698224
+:1059900031257A3FD0D89FAD9C41F2B89D7EDFEF94
+:1059A000B70A1CD57ED57B55E1B57F9C5889F31687
+:1059B000983D95EEF5FD8EE2E9C25E26D835F1748C
+:1059C000074CED13295EAF9609DB34E5D5CAB873F1
+:1059D000457EBF101F56C37B30B1F7DB1AEF4DA0D9
+:1059E000798707D8499EEE1FA39EF7EBEFD985076D
+:1059F000F07B766103B33F29633C838FF605011882
+:105A00007787F6FE9CED777762DC5378ED3DF4BD49
+:105A100011BE63FC5F937A1EB742B9CF00A461CA7E
+:105A200088DE3BAC4E33D17DCA6A68EFC8D7F4F745
+:105A30002DEFE35D704F2E26AFFA19557AB9117923
+:105A4000BD18F9206335F159A685F8E099AFEE3E0F
+:105A500084F7E18E6658C8AFD1CDB7995915F8FED5
+:105A60006F477DEAEA2E0DDF3CF3D59E97F0DDEA25
+:105A7000408654847C3AE6EB6F86E3EF067664A6B4
+:105A800051FD316B4E9F7E3A0DE93A4E16A87EB914
+:105A90001DFD1AA2214CF2827D1547743F3EA92AB2
+:105AA000CBAEE1934F14FA9851E2FE780CA4620653
+:105AB000F0832D2AF7C48C1BBDC8BF8DFD892DD95D
+:105AC0007D4A1C47A312D7A8F6F3A5A247BE54F1FE
+:105AD0002BD9E9BEF9B3C843B88EFB04E21763FAC9
+:105AE000EE04AD1F256E2C1FBF233E89CBABFAD42D
+:105AF0006F709DB5D95E9360D7D613F97B5396240A
+:105B0000E2F70EF3582FF273ADED4623F98560BC32
+:105B10001BF07DE2B1FC1DDDC664BEAF3A6AF0D871
+:105B2000118F6B4ABC33C642F931239FB75BEE4CF1
+:105B3000C0FB10EEDB5293F1FC6A8C228F3A064ACE
+:105B40007EED3E3B47995FCE582EA73A06DE417860
+:105B500053F1D861FE13E1C598713DBD6F3F06E575
+:105B600033E2614DBC13E7DF91C9ED8B8E4CFEFB38
+:105B7000341DF55C3F07922C64F70247135D8CC916
+:105B800094487E7F39C6AE3B6756F1FBACE83BC418
+:105B9000E59785EE4FBE5597FA0DE2C5684C9271B8
+:105BA000FD470D5DC5282FBE1CC3E33E4583278BF3
+:105BB00069FCF63747E5D766D4FBAAFC32E3FD8CD7
+:105BC0007C1D9D9B2EE7FEF3E8B10E45AEF07BA554
+:105BD000DF556EE19F5173DF13E50DAEAB0BE4D2E1
+:105BE000934E6CDF6ED4B657E5CEFF34FFDE1CC398
+:105BF000BF6AB9AADF54B87EAEE41B56FD99C7ADA3
+:105C0000D6F17B43C784F6E7E9BE699999E23BD8B0
+:105C1000BAACFDDAB855E3BD2BE87ECD7D603FE13F
+:105C2000FEFBBEB44593F0775CEEDB62A23CFCB5B4
+:105C3000E0FD90F94AFD77419CE1FB01BF1DCBE3FC
+:105C400032BC27E549F87B4947B267781AD23095CC
+:105C500018D2DB9FFEC5DFB3ADE8EA1C9F847C143D
+:105C600070146AE58BF78C44EFBCD53299DEC73AE5
+:105C70009AE89F8CED1B1F130876C704DF7E2FD296
+:105C800037E4515E8CEAEFAAC27BD2A31AB2098F25
+:105C90004758E754B40F020F1B890E1B8D3EAEDF31
+:105CA00037A552DEBDE5E04B8E34E42B91DEFCA936
+:105CB000B6D4D1B9311B260BF8AE5740D1CBD59213
+:105CC00097DEE10210CA8D80D7178C9DA47F5EA855
+:105CD000055816507C26F9930F1880120BD19FABF4
+:105CE000FC5EAFD29E89BCDFEA227B0EFAB955B9C1
+:105CF0002425BBC85FFCD1EE8523911F8DE9D77B9E
+:105D0000717D1FEF593E12E1F000CA1180DF8696C7
+:105D100007E977CCCCBB1B02085FF57782EAD7DFB7
+:105D2000C7DFFDDA5349F79FCDCA3BEB97EA778B84
+:105D3000229F36B4F2DF1DBA64BF9BF5F1C88D8F88
+:105D40005A2DF85EDD828763CA95F386D8DFB1AD40
+:105D50006ED1E7995B850BDF97F56677C6DACDBF25
+:105D6000196B8B79FFE1E2EDBBE37E0141745EE1EB
+:105D7000BC47C673F5B3407F7CFF74A705E9FE6C92
+:105D8000B681E204405327F4E4470EAFE1FBA515CA
+:105D900063992ECEE8FFA7FF3FC5F4FF0299D441D7
+:105DA00038008000000000001F8B08000000000089
+:105DB000000BD57D7B7C54D5D5E83EE7CC2BC924A0
+:105DC0004C1EE004024E428C012778081183523D9C
+:105DD0007912F280E1210D4A618251828F76A4F618
+:105DE00033B6D89C3C89091F8D088A7EA80382524D
+:105DF0000B18107BA1B5ED109422BEA2558B564B0B
+:105E0000A04A5FB68D583FE9BDB6DCB5D6DE273374
+:105E1000E79044ED77FFB9E1A73BFBECF7DAEBBD88
+:105E2000D7DE91984D3B93CBD87F4B8C9D9FCCD8A0
+:105E3000118535F6FA193B2DB1DA7D6EC67EE1F09B
+:105E4000DDC9D2208D9F28E95087B1DED405898C29
+:105E50008DD164C6AEC072D680F51953672FCA8340
+:105E6000BC0C7937962B8C8D65ECA71FE5CF0E42C5
+:105E7000FEE7E7F267AF847AE7F1E75A1C67E0478D
+:105E8000571630A68F91D94E68DDCA58C533EE68D3
+:105E9000B991DE780DEF4712F3DC88F354703CC8FB
+:105EA000BB18BB5FCCBB2695AD08F82F6CEFD72491
+:105EB0006A3FD0D4C87E7749F47B90310DE739F33F
+:105EC00044A02411D6E74CF3E52BBE68F93F6715D3
+:105ED000676BB03E0DEBE1FA8E2C6599B03EB6765D
+:105EE0000663E9D8AF4CFD06D358B906FD306FC044
+:105EF000BB3031DA7EC7551C3EC6BC8D793216F0F8
+:105F000006A09FDFE2AF57C17FFAF8A0E627B8F3FB
+:105F10003C0E09EB3A8CF9F1985DF8FE07C3ACCB67
+:105F20009A1AF0B84FC047638347CE037C995B0E43
+:105F3000EF846FCB6456CAF2A3F56BC4FE9527CAF3
+:105F40008130F45FF5606427C3FADF8ECBDF9909F7
+:105F50009BE1642B16C0BA96A5442E59E38F6D279A
+:105F600051BBAA1FB010C2A5AA95A7D8CF3677B447
+:105F70007C59316F67E40D3818F3DB719587BEB338
+:105F8000B5A98CCD023014B3DC10B46F75841E1B20
+:105F900040BC68B1B19D69F83DF4E400A62D4E4FB8
+:105FA0002BA40F267C9FCA1B6D2E8F5365EC2EC52C
+:105FB000F30274CEDED232A9BFCF649F5D825F1739
+:105FC000A50D9422BA2A25B226A7218239C3B8AEDC
+:105FD00032C5ED427C3EAB256F73421EB6BC3D021E
+:105FE000F93599697774C194D68B7D7D3061DA83F8
+:105FF000B3619CD617EDCC89BBC66CFA808BF64793
+:106000003A4F74E01B83F00A1C53585726EE9A9DB2
+:10601000CA7DCCD57C3E0B76435FDA8EEDED9A6B74
+:10602000300CF3747A65E6E3EDD979F82FCE17CF0B
+:106030007CB9D1FC5B2C6867881FBAF646F64CC663
+:106040006A6908C61272534CF598B2FE8520F4FBBB
+:10605000A957610AF49BA88E37F50BDD7CC0E7E1F8
+:1060600063380FC07C1BAE37305B620FC3BCAFAB75
+:1060700085F298FE026CED1684A7B7D5E971CE863D
+:10608000F9CEFE98E0669FCDFB19AA9771E63D9682
+:10609000447088B6877537BEF7FAB4E763FAF3142D
+:1060A00025A69D49805FA6B029B8CFADD819EEDFEF
+:1060B0005846F0672CC4023174B249D0E7ED453E32
+:1060C000DA3F65864CF834606793A6235D31CF4490
+:1060D000ACBF2021E5531FEC4F38322F6803FA5B29
+:1060E0007075CA7726C3FA7FA85D17B401FE2C9895
+:1060F00091F26C16E47F1459C4F397A75C61877C16
+:10610000B3B424580AF57B35ED518DC6117827FAC2
+:1061100085EFDBF0FBCC2B823B31656CF066C487EE
+:10612000BF49496A17E24DF6E034A457A3DDC0CF5A
+:10613000264C64724C1EE6A9FA31CFC43A864FDF72
+:10614000D7B4BDC84FACDFA5E0891F23FCEF6CB608
+:10615000311C2F33F82EE53F05FCEE82F9AF79F6BE
+:10616000FD241F8CB71AE108EBF8685E2427027043
+:106170003C96F9CB49C8577FDFC4D46CE06BCFD9CC
+:10618000833FC3FE0DB8FE7E6B6BD255D0DF5FF64A
+:106190002A6A3534BD4D013A45787EAE44AE85EF6E
+:1061A0001559976E47BCFD68DFBA8C3A98FF0B8291
+:1061B0001F7C94C96A11FE1FED738A7A4B772830D1
+:1061C000F6AB4D074DFC739EE09F80698E0579D13B
+:1061D000EFAD52F14B388F953651BEE33A9AF75CEA
+:1061E000774823FE52EB4B5907FB73E34CBEEF4E4F
+:1061F0005B80BE7B71AF66617F3D7C7F7CDFA6EFFD
+:106200001DAB99A76B3AA15780015DCC1774A1A96A
+:10621000E74BB17C5E88A90827D93568237AAC00A2
+:106220001C4A46F4DBEA413C84556D3D9F8A74BFAD
+:106230007603C2750DC0D989F42E8578DEEEF2E8BA
+:106240001EECB4BF63197CFF16D06B17E5B5A41A1A
+:1062500018AF418C07187C7416D4FF0BD01D95879E
+:10626000EDA74D74A67CEE40BCF934E80E29503EF3
+:10627000CF633B1D4B3F8057476741F96D071DB406
+:10628000AFB7F7DA4DE5DF62507F14BAFA4C03BAC4
+:10629000BA0C7E99CEA6235D19FBC1946563100FDD
+:1062A00046DA8FCF9AFAA73D6FA77DF957ECBE006B
+:1062B0001F94912ED73C32793BF2C1358F2CF2D905
+:1062C000101E6373F35966747FD8415942B8AF12F8
+:1062D00073655B53693F6B0E4E603EF875F54189FF
+:1062E000F94024561F4CA57CD2B974CA0380681F9C
+:1062F0006B9E5CE5CD877E3391F0A1DD1F9FF8CDCD
+:106300009DDF8571ABBB61EA1E9A871A81F2B36F7C
+:106310002AAA93401DD862EC13D2838DF9880F2FDF
+:1063200039666761D887B38CEDC1F2B3BAD3A317CE
+:1063300044D7C7B2A11DF23927A79B3185667E9B42
+:10634000AC99F96D6A8599AF8E0D98F9E845B55904
+:10635000A6F2F4E05453F984867C537E62E82A5313
+:10636000FD8B1B8B4DF94CBDD2547F72E74253FE1F
+:10637000929EEB4DF52FDDB2D2543E257C8BA9FCCD
+:10638000B25D6B4CF9BCDEEF9AEA5F7EB0C5543E5D
+:106390003DD2652A9F716CA3297F45FFC3A6FA579A
+:1063A0009ED86E2A9F35F094A9FCEA3FEC37E5BFF2
+:1063B00036F81353FD6BCFF599F245EC2553FD12DA
+:1063C000D7AF4CF932CF6F4CF5E7787F672A9FEB58
+:1063D000FBB3A9BC2AF71353BE46FD3FA6FAFDAC9A
+:1063E000ED12E4933366068345808772C247240723
+:1063F0004F7C4362A980DA678F2DF20451AF13F40A
+:1064000033925E65A5C3068B7CFB94B997CB40FFA6
+:106410004E604F28BFADED87F01350F913C0D795EC
+:10642000855218F9AEECF2391A915FA90E15E538CC
+:10643000FC045CE3A2FC6DBECDD781FC2403E846DE
+:10644000F1C2B74EFB4743FC210B876FF3A0BE6739
+:10645000F0B751F44276C668873AA53EB81CFB6D8A
+:106460006520DF901F6FF5301BCA39990D7601DF6B
+:106470009440C82E033D517AEE97FF90A661AB651C
+:106480001EE43B120BCAE72F437AAD6612D25FAF10
+:1064900044F4FA37FB5AAEAFB5DA98720D80D3CD1B
+:1064A000FBFB26303C05F8B63DCDC350FFBA3DC2DC
+:1064B0007A912F8F298419C5C0335973315BCC3E33
+:1064C000A656784CF9B101AFA9FE45B53E53797A8D
+:1064D00030D7543EA14135E527860A4DF52F6ED4BD
+:1064E0004CF94CBDC2547F7267C094BFA4A7D65468
+:1064F000FFD22D4153F9947083A9FCB25D21533E24
+:10650000AFB7D154FFF283BAA97C7AA4D3543EE347
+:10651000588F297F45FF1653FD2B4F844DE5B30659
+:106520007699CAAFFE43AF29FFB5C183A6FAD79EBD
+:106530008B98F245EC4553FD12D7EBA67C99E71DED
+:1065400053FD39DE53A6F2B9BE3F9ACA6FFB33E85A
+:10655000EB8857A04FEE2C403AFDD854FE59DCA4EE
+:10656000C8F7E0BBB42649950A916EFF61EAEFC116
+:1065700084A45CC49F4616AF3A25D4EF4344577FAA
+:1065800028CA12FA3D1B88837CAB0EF44676E020C5
+:10659000F342FD14F805F50489FD9DF4CD248DF535
+:1065A000223E835E407A8407F404A433832E52E4AF
+:1065B000CC4CB43712A27494717EC697A7A3FF4641
+:1065C000FD0DE6935D1CFC33F2975B7AF7954F80E7
+:1065D0004F0DAE1E07CB423AF18F1900FEF26ADC76
+:1065E000F076E95C17C02D66BC17E37A32F247E11A
+:1065F00043735D1F51FDA17EEDBC5F09161B6B9FB0
+:106600006D68829902BFE96902BA02FD60639387EF
+:10661000F29B9ABC947FA0C947E996A65C4A1F6E7C
+:1066200052A97C6B5321E51F6DD2281F6EAAA0745E
+:106630007B5380BEEF68AAA5FC134D414A773535E0
+:1066400050FA545388CA77837D8DF9BD4D3AA5BD64
+:106650004D9DF47D7F530FE50F346DA1FC8F9BC2E0
+:10666000941E6CDA45E94F9A7AA9FC39D06730FF5D
+:10667000F3A608E5234DC728DFD7D44FF9E79B4E93
+:1066800050FE68D300A5C79AFE40E9F1A6412A7FD3
+:10669000B9E91CE53F12FE87AC62A1BF286EDAFFA4
+:1066A00040F1A5DB518F35BE4FB82A90550CFBD673
+:1066B0009290743B962F64B2AA201FB4F03BEB3E3D
+:1066C000FC49F46F2F66AC00EDBBF139DB5B819FB9
+:1066D00037839A8478D79CE2DB8E364F9E18675DAD
+:1066E0003CD3E3F2096D487F5D85BFF940594B6BA0
+:1066F0003AFA3DA87F7308F83099128087B98487E9
+:106700002F7F257ECE741A676761707631A437BB00
+:10671000430E324F999A83F64D8D3332F6EB30CFDC
+:10672000C1171575BB6FE47EBFD5331798EF28E509
+:106730003FFF6306CAC98A7F29415CFFABF6C45A92
+:10674000F41BCC13EB9C572C9BD2CB66056A10BE76
+:10675000AB7E7E37C9C765775C3206E52DC837B298
+:106760007317309F1DE97711D35EC844BB14ED5FEA
+:10677000C87F9DE9942616069760FBA5A068637EF6
+:1067800040624F7C5BC2F570BCB7CE637931F733A2
+:106790002C2F964D69F9ACC072ECA7FEAA39CB65D7
+:1067A000F8B4F22A1F7D9FC7061FC5797C6B52F093
+:1067B000E484C951FF03C32D00782D3BA6909C06AD
+:1067C000FD9451FE3B5218F95147D1B7B9BC6BE665
+:1067D000FE89BBE27F5B86E503AB016780019C0D10
+:1067E000BDF008EAA1CBA09CDADDC1F367C19E43EE
+:1067F000FEF3591CD487BCB412FE4B1F8EDF0DB8BC
+:10680000C7929D1CA17E3F9BCA18F2B5CBAECC248B
+:10681000B82E43E710F6BB560A73DB3A62C7FEFE9A
+:10682000768587EA7DBF30F8FD62B263C30FCC8006
+:10683000EFAFCAAC9FEC584F3807EDD87532C70799
+:10684000FDB8A2EE0450D83C014D423CDC9A3C1D00
+:10685000FD5F8837683F1C15FB68E0C5373B218D1D
+:10686000E157806F5D08D7BF1EBA3217F1E25B3F78
+:106870009FE5C3FD6DC5FED3A2FD337445C178CA43
+:1068800018FFB62EBE7F34FFC15989E1ED99E4E7C8
+:106890006ADC370C7F7C5AE0D5AB5E7B4598FAE525
+:1068A000746794EF12FBBB4BEC7B4DDF8B13EF82D5
+:1068B0007EBF79CCAE3A71DC82017FAC9F61088FDC
+:1068C0001B1F9F991DB38E6F1D3C45FE3B1BE3F3C1
+:1068D000B2174ED88EF3B4BBDC91D469D171589AFB
+:1068E000EDA3217B2D0BE1C3F9BF81878A2331B84A
+:1068F000CD1D3BFF213AD88BFBB12AA991E8E06C72
+:10690000E8C33B91C8070074111827F898C781782D
+:10691000B892A994D6B300A5AB98EE40BC5FCDC2A7
+:1069200094DECA063A6640FD805E3709E5CBB7D8EB
+:1069300060A917E0775D67F30BA81E2EEAB9AF2CAC
+:106940001DD6BD646BA67D3CA40B76DCD18EEE43D8
+:10695000A0A35FE0F8D7EF2E6A9FE0233A3AA34363
+:10696000BB790AC72F7625EC25E08D92E4223F59AA
+:10697000FD46CE278D751C15FB503E4B3B8AFBBD5B
+:10698000AC8511BE0CFECC49FB37444F85B79E9CAD
+:1069900020A33E08FB8DF8F8B329E166C263AE0F71
+:1069A000DE22E433E6711C3BCA67CA871E43FAB88D
+:1069B00055E7F69ED5DFF7273BF707FE09ECF456BF
+:1069C00015FBDF3D09E7AD031E2913887E68DF1A3A
+:1069D000DF4B24FAFC4CE6FA029B14F4E64F46F82F
+:1069E000E91D687CFE490ECF4C9A4CF2FA34AEE3B6
+:1069F000A817EC5D1C37CDA52A589E1C9EC4E97FC4
+:106A000088FFB3F309C8AC787F1B50CF4D8BEAB930
+:106A100077C54F62682F033C07A5AB49AFA1754905
+:106A2000C5AC17E95A2AFC8F20CE6B6B02F328B352
+:106A300086A3F3A077A682F3555DD83FC89308EAF2
+:106A4000D576D9C5E9DA320F20A35AD4DB9D426F3F
+:106A50003FF6CF5482AB0EE3EF4C8E8EEF2B62BD30
+:106A60000CE02279FE83F4B0ADA087291958FEFD11
+:106A700030CE478A671E9C1FC07917C1713CF3B4A2
+:106A8000260F0747AE5F259570BF6A2B2E95FCD762
+:106A90009E5C0FDAE5B67815E9E4094730B1E40AFF
+:106AA000F45B8D7F24D66E3F967911E5E73938DFA8
+:106AB000639FB76620FF71339F8EF8314F93D42EBA
+:106AC000E20F036D68FF2F004420BF4AA1DD446739
+:106AD000CCE2F701342AC5F60BD1EF03F5B5D96343
+:106AE00068DEF3AAC1AE92D02E7ACF801BD9453F83
+:106AF000107C03E64D7E91BAC59113C964D7B4D01A
+:106B0000BAEA5C6E5D81A5B336B37D65C855D09099
+:106B1000491E3CF9904CFDD34E809D96CC7F65C9B3
+:106B20005BCBFFA84CC3BC8D9D36E69DC9E5F450F8
+:106B30005E1195611DF46932A650CEC7D3CE4B23AA
+:106B4000CBDD2F9BA2DE773AC63FF7A43DD83505B3
+:106B5000E7FD96A2EA00B7278BEA2AEDB8DF0FC956
+:106B60000CFDB017EA15328B98E61BCF22263D2389
+:106B7000C5921F6FA99F65299F6A29CFB7E4AFB25D
+:106B8000D42FB6E42B2DF5175AF2D75BEAAFB494A5
+:106B9000DF62295F63C97FD752BFC552DE6529DF37
+:106BA00068CAE79464093FF2C39676DB2DED74C2A0
+:106BB000A3DD5318EB473CB481C941F2C64578F5D3
+:106BC000F40732E919BDCFF54DFD11E4F70624F2C3
+:106BD00006ECFDE074D765E84FECB5517E916BB9DA
+:106BE000BDCCC7FB1D1847FE3E72AACDEB759D427A
+:106BF000FC7B0EF63F7229EACF2E4AF780DE1F019A
+:106C00001EB90FF47E4C9F01BD1FD3A741EFC7D41F
+:106C1000FFE1C2316C9473A5AF0DCAD17531B41BBD
+:106C2000E3A3EB82FFA61D483195E73F3FDE545EAC
+:106C3000F0729629AF3E37D5547F77A2191E8B1775
+:106C4000CF3095E768FF8C47F9CDAAAF8E7ECF4253
+:106C500038E5D3BCADF8322F165F62F0FB38C04583
+:106C6000BB349A7FE96EA516F941DFFB77B11F03AC
+:106C70007CF71E48D986FCEE697F425B0AB0921F02
+:106C80009570B9BDF7B98D34AF97927AAA701F2E5F
+:106C9000FF40468EC18A9E6311DC37F520233EF902
+:106CA0006C898FEAAB07FB651FCC37EF40FFF820FC
+:106CB000B50B31E493870ECAE116984F5FDE83DD92
+:106CC000D8CF1EE807F5934307F6FB91DF1F723B11
+:106CD0007C8CF805CC0FF8431E0A737E6E52CBFDF8
+:106CE000F5FDE3F1BC350AAF81789C570E7369A5B9
+:106CF000D0BE7736E77B7B23674BA741FF9F68AE0B
+:106D00004146181394DF44BB27C2F16B6FA498C3AC
+:106D1000CDC77C8E99483D0C49969D12F061BAF61C
+:106D20006B3C77BA918390E0A6C3F713804F286B32
+:106D30005F067CC2F4A5BB8F5C4FE739871DBE9D03
+:106D4000C40F87CEC5E4F39763BF36710EC60EE35A
+:106D50003E2C5E6CD763CF9B58B55D37F3775B34C1
+:106D60004FFB189387F6ED6D331CB7219CBC0A735B
+:106D7000AA9C9E5C33A3F87FDC36507A2BC201E4D8
+:106D800007FAF16F8A143BFCA8D730CFC76310967F
+:106D9000EBF979974BF8E9EB230BA9DC539C4BE516
+:106DA0009F9D2A72F8494FF69C6DA6FE63CEB76090
+:106DB0003ECDFBCAA97C6F91EB631CFF906DE0A3F5
+:106DC0007C3EDE9A66186F69D07C4ED69BABB4E3EE
+:106DD0007CF6143A3DB2E7C2F3B23D11999F876D3C
+:106DE00092B65F02F09B673967ABDF64CE9F2BE101
+:106DF000FA577229C7B35A5D2FF3F8D12EEA69F713
+:106E0000E079AB2DACB7407F79B0CFA8D7E5A9AF7B
+:106E10001727E0FA0B24F5121FF612A1FDAA39E894
+:106E2000F1219E141DE4F6CDACE764C25F2BDDBFFB
+:106E30001279231EF164D641C042E85FED7D40C166
+:106E4000BCF4016B1D18855FF486CDF8B9E720D03E
+:106E50000FD43F24E875A4762704FE1DB785DD9E78
+:106E600051FC1F55B90AD34DE72961E2BF4B830995
+:106E70004C8FC1AF1A35D5946FDEE720781F3804E8
+:106E8000F44A74C6CF7566083CDF6D1F906F0778B3
+:106E9000EC9FE5F4B4E0392D9BDE8AF8F6A938E7DB
+:106EA00031ECBF03114EEF07D8808C7A985AE72651
+:106EB0007CCB3F00649144E92927F0E1FC971D2633
+:106EC000BEE754CD799539A27C0BE633CD9237FCE1
+:106ED000D105485BB32E8483D51F7D55A93817BAD9
+:106EE000925D89F8BAC7722E94679C0BF517507F94
+:106EF000BBEFF1290BDD51BF7454FE37133CF7345F
+:106F0000B9246C9F1FF9A3ECCB433E3F20637CC2A6
+:106F10003436D0928076E401A662BC86D19FCFED54
+:106F2000D1BF03DFF71FCCA2F3C4BDC7B21264E820
+:106F3000FFDACF2FEF26BA7973727E178BF6CFFA6E
+:106F4000D3E8FC68C84E42B9057C65FFB18534DFE3
+:106F5000A70FCA64EF3D6D1B8C4F19066F8C7D37F0
+:106F6000F2EA736639D58ABF40FF19A5C1E5A55776
+:106F7000E0FAFB582ACCABA6E00E86F6E9103CDC22
+:106F80000BA95ED5B4B9329E236D9E94B20DED9ED1
+:106F9000968479F2A3904F55210FEDD27485F63F78
+:106FA000AD70D236AE9773BDB16AAA19DFF766BC71
+:106FB000116F4779AD2712BE552599CBABA61DAAF7
+:106FC000C7EF3F5AECF261BFD2B4A5E9484F0F8832
+:106FD000F5BF76604DFC70F475913D943C1A5D5C94
+:106FE0003460631140E6D473192C02FA6E553EC822
+:106FF000F551EA3BCF2954DFC8AF8B1BF0A23FC548
+:10700000E9FDAFDF7C10FB3D23250EE195A3DDE319
+:107010004239BC3763747DC15887917F7048CE3A3E
+:107020007584DFFA5D192467D72D8B2739FB50292A
+:1070300097B3EB016E8CF62344F2D8A9723D7B8F97
+:10704000DA427CE8C1A47E3900E5458087089F1DAF
+:10705000C80701FED332220CF1D3AD06A607A91E44
+:1070600097B7EB3340DE42FBBE6FFCC71494AF7B97
+:10707000BC0E1F8ECB22916399901F3B43666877AD
+:1070800074488CE6A5FFD01DE6728CCBDFB1689307
+:10709000C296AF3FC0C7CF61B7CB3ACAED0C2E47FF
+:1070A00073D8A1FACB703D6F027F6017EEB3CFD3D8
+:1070B000CFF516770AD1C746A19719F033CE5DF701
+:1070C000427FCE183D6563E5535988FF061C37A201
+:1070D0001E07E983CBF6A7E0FAEE57F35FCC46BE76
+:1070E000B4CC4D52AA4CF1DF8BF9F53B6C740EF326
+:1070F000C0A4D0143566DF871B5786FAEB0EF271F9
+:107100005322BE22C4AB54A63663BA45D47F48E8A6
+:107110008FFF25F4C747507F84FC96605F05EA2FF8
+:10712000696F290CFD443E75E0DE4B11BE5B64B512
+:107130008B5D880F467FDBC53AC2D81FE4D3EB7561
+:1071400009D7F9A8E877DDC1AC1617AEAB1E58A376
+:107150000FE739BB0FF37B3B193F0FD65519D79F6C
+:10716000D9C6289DD4E891797BDEEF0ED1CFDE031E
+:107170001CEF776E5A998CE5698D6E0DE355B2EF71
+:107180002B6DC6F3FE076C368A97D9F94025E51FAB
+:1071900074D9E8FC39AD515581B9819ECCE19ED6B8
+:1071A000A8A9D8EE51B1FE3DA2FF9CFEBF343B71B1
+:1071B0009E3D8CECD64907027D38BF690707A56064
+:1071C0000C5DEC11EB7E5AC031A77FE20D88679F02
+:1071D0001E70B3AE51EC3C83AF4D3B205BF466B305
+:1071E000DEDDC9B85C00FEF6BF4B817EFC95FDB2CA
+:1071F0000BEC496769847C5843FCCDB790EA19F8D9
+:10720000D69ACDF5DC6C56589145F89B2A115F163D
+:10721000F146DDCCF86931F1D756B19E3143FC4ED1
+:1072200075219CEF15F0B7E9AA6B32D22DD0039EE1
+:10723000CFB7243C4AFC0FCF2CF19CB5F89A06D668
+:10724000897499CDF58DF5D97D2EC4C736016FE9C6
+:107250009A2DDE01E8AFDD16708DC6E7EC5B389F36
+:1072600053CE4D223EA7B3A08EF4ADA4F1FD7066BF
+:10727000A83AFA111C3E1BC55F282C462F45FAD6AA
+:1072800099CF364E1C196599CA49EE8E013581E0B9
+:10729000349111FF60CA5A86EBFA14F469C49B0456
+:1072A000F7CDD58827CC6FB3C457A90CFD1A4E660D
+:1072B000FB20B63F25FBCC7B58DFEEB599E2AD1441
+:1072C000B6FE63B4D7942F88A3BAA24C9C330BB9F3
+:1072D0006EC873E64B31C94F238D9E33EBC457A75D
+:1072E000BA0AC94E59E763449F18669109EBD9AEB3
+:1072F000CB44BF619DCBDBF5425E5AFB33F6DDC864
+:107300002B065EA9F9541F7EE273A1BF9EB75249B6
+:10731000BE1FEE94C9CFBB4ECBA178921CD6D89994
+:107320000BF90E3D4B36C97F8B9F212792D8857C68
+:10733000799DCEF9329025F5DBF1A6A2B6209FCE3D
+:1073400068710D27771E15F3DB25F0F02541AF9D01
+:10735000BE85A39EE71BEB32EA29605EABC3F46FE8
+:10736000739BF58A9C63DF18339C3FD948B70A7C2E
+:1073700036EA65D82212F69B21E2478D7A1343E65E
+:107380007EEF2CE3FEE5EC126D4DD9D8283E298D19
+:107390008E07501E2BF794CA8FA6E13E72FA713207
+:1073A0005F7C16870FC99F8BEFB9B313E1D7E9E66E
+:1073B000FBFAD8DA3B5DB1F2DF0AEF8B27CA22CEA7
+:1073C000F485ACC336840323FED0E9E5F643AB97DE
+:1073D000F3D156A0F3E1E8D1DA5F6786D15F64E5C7
+:1073E000E16C90BB9D2B89DE8DF9FA58C885FC664F
+:1073F000BB6AA3FD052DA507F182C1FC518F1C9925
+:107400001F8EEE8FDA5166F85F46F74BE5F48FBEBC
+:107410006F5F344E583F2B11FFC6780674FAA95C93
+:10742000AE4F815FD7A644FBB9B8D1BCAF063F9F32
+:107430001236F3EF6A7FAA296FD523B359EE41F4D0
+:107440009BEEE9E57C8DD50E54A2BEC1DEE6FBFDC8
+:1074500034361CC62ED823E8C0C8EF85FE46E3A705
+:10746000D3B6B8898FEEB5B38312E8634C03D56504
+:107470001CFA4D1919EF8F55048F223EFACF4D2378
+:10748000BE2B1D3C4AF120004FF2EF7FAAF2732978
+:10749000363BC0F9660DE4113EBD8BA8BCE33BCC86
+:1074A00043795B783CE2F36E411FC63C776746AE9A
+:1074B00047BD6EEF4F7F2BC7C685FFBA8C9FE7E4B1
+:1074C000B992B4F030747942943B6D4C8FC773D548
+:1074D000E7383FF4328F03F7F90BFDB9B5915A9CA9
+:1074E0001F93651EFF6259F71E4CD371FD810FCBB0
+:1074F000306E59E5EB5E1F08E8A83F054161625711
+:10750000439D031C0FFC2C40EBAD53F9FA5F53175E
+:1075100052DE0DF0704EC7F92C13718FCCE34CC7BF
+:107520007E781C64F056E6413FFD85F3E478330431
+:107530005701C7D754995D8372D4EBE0766CAE5A8D
+:107540004BFD8EB08E4D621D1F5404FE45EB70F353
+:1075500075FC00D094FC0F490E8AC7CD2809DACA01
+:10756000898E98A6403F3F58E2233B8EF90312FADA
+:107570009D582065587C8BD28F806BAE362A5C5B21
+:1075800093C6B33A28FFC19A248AC388995F4A39BF
+:10759000C6C1BABB02245FC578CC1D213F456B3BF9
+:1075A0008F97FAA27D8DEA2741572C1DB507B9FCAC
+:1075B0006B95821528FFF4B738DFD928C687B969DB
+:1075C000788ED3B1CF4BE35CC8172411B76FE60BAD
+:1075D000DE58BE437E85FFB7FEF015E599E2FC61FB
+:1075E00074BFB8E26041BA9F50C1EDD91C56EB8A16
+:1075F0008DFF8CAE87EB75513F22875347DA4A9255
+:10760000AF1D5E2E0F59C5F0FBBD4ED0AFA1F7B533
+:107610000A79DBE16D61B1FC71243C716598F55A22
+:1076200003CFE3B3E34D7CD30676536C3DB0D3D4A4
+:1076300008DF37EE77C01FC8D7AF4EDF4678CAD80D
+:107640006D09806727059E19E319FAD0F2726E67FB
+:107650001EAAD496239E75D8835E94CB8EFEDBE55E
+:10766000F761DEF6B714D3BE8FA42FAC13FA7C6B90
+:107670005CA036300C5F5DB7DFD110CBAFF472EE9B
+:10768000B7D3C5F830358A736DCFE0F692E20904BE
+:10769000506E2B20075B7D238F6FD5435C19667876
+:1076A0007DD5F8C5C5E5667FD1D565811684CBEE5D
+:1076B0007D3359ECFEF7483C0E7C247A475F89F015
+:1076C000B37423FFF017F7CB9386B343DC8BA99EEB
+:1076D0006187DC9F9B42F72EEE17FBD81DF26C43AF
+:1076E000BDA33B57E678D4E0D9C662FC2C137026C4
+:1076F000D0EF4578D209F3ED10FBF198D88FF50261
+:107700000FDBC439C786268DBE6F6BAAA0F491A685
+:1077100020A58F373550DAE13DADA1DDF05F60C8BF
+:1077200060BC4F526456318E9B52CD3C71308FD429
+:10773000AD033AF241168AA7F885CEA610B54BA93B
+:10774000E0F3DDDA10F738AE7D77B943E0557077B6
+:1077500039D1291BB0031EAE30709469E348EED9CD
+:1077600079BB84526E5714F943CC03FD27BDA91091
+:107770001F4FF287F1501494DE5DEC56A8B701C696
+:1077800041B92F55F4EA03746EC9FD95E3047E37C1
+:10779000EF7BC21BEB27EA86E6FD48FF36358E9F5E
+:1077A0008BA8F7A2DD9250C1F5E98D1529CDE82708
+:1077B0007014811D0376D191F57DE40FBEBF90FB5F
+:1077C0004512726F6EBE11CA5F4D5718C6E3253061
+:1077D000FF61ACEF55D8A0B310E1229F42FF664A8B
+:1077E000ADD98F39E94E87090F932D7ECC04E63051
+:1077F0009DC77C553C7DCB82A70CF107F123570E2A
+:1078000013FCA3E721C4BF1C1AF7BB6DF47379B155
+:10781000A162BFADB880F08CCE430C7EE09822F31D
+:107820007E0AE5303F77E92D5D09ED2A35179D3F4A
+:1078300067B35D36D4AFBBC53D80E8B95D98F8E568
+:1078400009C1075B250E67439E38C279246F36FA5B
+:107850003C44DFBBE7E6C74931FB84FEEB5878A127
+:10786000DFDAC40FD7C7F03D906B5DFED1FD6D5DD3
+:1078700016FBAC0BE6379ABE179EC3F5E5F82D0E46
+:10788000D2FB5CE7C6519A13F91AADA34BD813BBD0
+:10789000ED6A1CF2B7FB73B3E262ED88CCD966FEE9
+:1078A000BDB162743BAB53C0C9A8E7B2E96CB8F98B
+:1078B000C5F9BE9A9D75AF58B7512FCED643FDC6B8
+:1078C000D9CC76567CB679BE97CEE17C58F17E72E3
+:1078D000E907C3C479669704B3E78C8DB177BD8F90
+:1078E000FEE603800FFBFC3CF90587CEEDD12E832D
+:1078F000EFD903531E26FE95CB7C886FF1AE63EF64
+:10790000A29DB301E10874B77B16879FFDDA01865B
+:10791000FE556B3F2C5736EDB78F855DC82F36E689
+:1079200072FBEB97DE2C09E93CA902083C11F943F4
+:10793000642EE94385CC83F89F54D1AB61DCD22F10
+:10794000ABB793BEB9D12DCBC84F5EAE4E213E7AB8
+:107950007F2EF7F375E466DD9B8D785A2FAB782C7C
+:10796000E0621CDEB44EE4C3D5FB5D785E35A179E0
+:10797000CCCDC80F2BE7F0FB96DD2877FC51BCEF90
+:10798000F61A794E6F8BE678A8DE86EAED9DD8FF71
+:10799000849B64E24F32EB257F71879FFBF1E33ECE
+:1079A000FF9B6B1CA4470BF7BBCE503B85F0306EA2
+:1079B0006D2FB5DB502F338C4F78A9302B0ED7BBF2
+:1079C000B17A7F328EE76089242F361672BFEBEED4
+:1079D000B90B497FEB6EE0E7E1DD856B221887F498
+:1079E00069909F76E2F5922294E718670453731624
+:1079F0002C267DD353EC0A61CCB9C3773BEB2840EE
+:107A0000BAE2FDD933CC78B77B4A1FEDDFFD5E1BB0
+:107A1000ADE3FE42CE273FAD70F8501E39581CF141
+:107A200097FB3D8CDA3F54FD46C5649A8F4CE31FAB
+:107A3000719F3D8CFEC1FB97318A3F73EBE6FE1DC3
+:107A4000B3B647B2859E24669C54338E583FFDC41E
+:107A500057F7E9F538DFF10AC37349E3DC6A43BA43
+:107A6000716E65B6539DAC2E9225FC53B85E5B21BA
+:107A7000F737D9D0BF94144307AA994F5F1C34F34A
+:107A80007187856FDB2C7CDBD0931C5FA02719FEF0
+:107A90003C434F6AB3F7929E04F28BF0739DE299D8
+:107AA0004EF622D0693AF4674BC920FD2D3CC7D071
+:107AB0008F428528FFEE473E0CF071D4B4D0FA0116
+:107AC0005E21CF287AA5DDF305FA91476769334532
+:107AD0007C9F0F53DB19B41F3A31D6D524477A095E
+:107AE000AF7D2CC87492C31C4FBA2BB613FE77150A
+:107AF000727ECCDC69C3EAC71342C3DBFFE90DE643
+:107B0000F95C1434C74DDC27EEB3E6E93686F8F3AA
+:107B100060C26FFB907E9F7916E473E617DF7F3DAE
+:107B2000FC2CC7933DEFF3B82D58CDBBB741FEB346
+:107B3000FD0EE2E7AD89FDD723FF79CAAE4E980E60
+:107B4000E933AF3C31BE0ED6F3FC1CEE777A46C467
+:107B50001958D7736C0EB7B341BF393687EB371F4F
+:107B60002931FA4DBD14BE84F858AD7A43ACDDF727
+:107B70005845F055AA6FB1FFA497B9FDE9501631E9
+:107B8000B4A3F3C08EDE4E4154218A07CB6B10F7AD
+:107B9000FC5C01E25F79D53EF22F38857D3DE94EF0
+:107BA000E669063DF2F692E0BBD4BF6D8D86E7DC58
+:107BB000FEEF8EA1FB5E807D5391EFB85990F0B53A
+:107BC000EE4D8EAF8EFE89748FA6D7882FB3D88FD7
+:107BD000C67AF70AB9B24FE0EFDECC7EF24FEC7F07
+:107BE000C9EC9FF8DB1CB37F025AC9686FEDFDC971
+:107BF000F1F8BA61E4F59F2BEAFE3627C69FEEEF57
+:107C000055953AC2B301D243F0CE3BF94966AB7405
+:107C10002FDCA8D7FBF2E8E778971F34E35BFEF38D
+:107C200016BC1F8A1F0C4818C7FE5272C814B7FC36
+:107C30004578955061D89F8CF0EBAE5BE3B61BF1B5
+:107C40006F647FBD7F19C1F7506520A182D773C9CA
+:107C500033A3F83114BF62D45F3D65BBB0D7DC32CB
+:107C6000E291C4F122A54232ECB314ECE7C0AAE0E1
+:107C7000D80AB427A6BE3215FDF455D35E1C1F7B6F
+:107C8000BE62D81556789455707CAEBC217CC04E2F
+:107C9000F830AEFE65E0A3955F0FFFDD0EFB7E774B
+:107CA00045727D1BD06DA553A67BF5A163B377E824
+:107CB000D0CF069C07E4E71C9B5A8FF9EB4BB5C964
+:107CC00038FE6FCBB4EC0AF28B94525CBE01C791C4
+:107CD000F6C31A975F8AF682E99C98DBDB78BE8C44
+:107CE000E7CD60D785F11CB8C33DFA3E7758FC7AE2
+:107CF0001DD0CF687A5E5C79F06B386FC79624F23E
+:107D0000DBD9CEE5909E175D470FC5937ED975DC14
+:107D10005EA295713864D07D5AE37BC9B4B97218FC
+:107D2000FD266EEEE7FDA27528E7AE369D3B2B42A1
+:107D30005F63A577DD75D74C716E1F737FEEBA0A4E
+:107D4000A1AF9DBB86DAFD4FE1D86E81E30572C419
+:107D50001EF08C06D7CFCA820D889FF60103AED9DC
+:107D600094FEBB7035F0A3B74CBB83D3CFBF8767FE
+:107D700065D80FB743CB041DDEA6C4D061FD943D8A
+:107D800097201D01BD0FBDABD04A72E6FB44FF8DAD
+:107D9000BAD383E7A14957F3F8663FC6EB7A880E5A
+:107DA0003B70DFEF522253715F767FADF17216C3E5
+:107DB0002FF398EA453D66FDB1793BF0BEBDE21870
+:107DC000506D942FDB5181E70136E0C740AC497319
+:107DD000067A8FA03D9DEA207BBA6D2EF72BB41555
+:107DE00071FEB059D0FF83159CAF3E24F67D5DB97E
+:107DF000B609D703F8F708CE231DF3906E12EBFDFA
+:107E0000EF52731ED6BF49ACBF538A9553B376D396
+:107E1000FAADF8CB1A857FD5E0BF8CE79D19C2AFCC
+:107E20002DE4375E45BA2A855256960F2C2B574FB4
+:107E30004439E3AC5B342CBE59E3535C7E335FDEE4
+:107E40003CCEC0639DF48D6C6D35E9FD9DDED1EDBA
+:107E5000BDE34DE6F80A639C2A5BAF0DF1B6EA9CE0
+:107E6000CD445FD6B4E88E675DA85F7787AE18759E
+:107E70009C934DAEFE523BC505526A2D0FDAD938A0
+:107E8000F49FBDD7F9ECB0E772C1B571FDA5B1F1B2
+:107E900038FE3524E706D62AC427BA33D8ABF8EE25
+:107EA0004BF7EB0AC5537627727C609F3F7302ED58
+:107EB000F0A03F688A27C0F8448C43FC4D05B71BEF
+:107EC0004AFCBD0CFD2209FAC7768CFF3855E1A3A8
+:107ED000FD5FB1567204211F6C4B7668BC3F265182
+:107EE0007FA05748D86ED08EEB5FA1EFA3B8910466
+:107EF000C863FD159D99BCBE787760659B628A1F3B
+:107F000053F005188CCFC7176348EFD6298D43F877
+:107F10002BD17D006B9EDB75AC9F8D66BF3E1379C8
+:107F200091E2441920FFEF86F163372F89273CEC5B
+:107F3000BA5B127AFF40FB4A3C2F28740A3D87FB4C
+:107F400083EAF15758FA6647A81FE38EBA9AED0CF8
+:107F5000FD4BCB597507C2D13B4161E8BF613DFC88
+:107F60009D0117FCC3713275F3BB0441CBBB03CB3E
+:107F7000594C39EA4FC2CFE79C2BFC31F92C1FE951
+:107F8000C7B78CDBABCE29422FF60EAF1727887808
+:107F9000232B5D74FB57C6C7FA0F7A34D98578F264
+:107FA0000918C268DF6E76E83AEA6D1D99B6500B83
+:107FB000EA6D224E61A55837FCAFA30EEAAF1071EF
+:107FC0007A57FF41665ACCBABE3618CFB4987DBCFA
+:107FD000F65C8A295FC42698EA97B8269BCACB3CF0
+:107FE0009799CAE7786798F2737D579BEABB80A0A0
+:107FF000051C79BC019328DE809AC8A672EE0FEBAF
+:10800000E4719E1AFCC37D49D106ED18CFBB4CBC70
+:108010001763E0414726B7FF5658E2055299AEA3D1
+:108020007D7B03E04504EADF1032C78DBA841DE88A
+:10803000B2C42518FB5934D7125F30C2FE45F90D82
+:10804000C7CF91F9178FF3CCF1FD27D9FFB05F6F40
+:108050006743DD72B15FE58B1B287EC2712E996983
+:10806000880FCF5DF9740E949708F8386C41F2E3ED
+:1080700038CEA551F9E62C99DEE9F9C4CBC84FE713
+:1080800070ADEFC7F5389825AEC3C7E33A307C032F
+:10809000F97C4C39AD17EC013A4FAF003CC47EE798
+:1080A0009C939806FA9063317FCF867939DC0CFA7D
+:1080B0002811F05A553659C2F6737CE6F7721C2225
+:1080C0007EC361D98FFB1887EB6D56B8967EB9F3E6
+:1080D000B344795B3DDA1BEB972915B1E7086FCC08
+:1080E000E572F12E915EB80F9E24BE0F7149B8CE95
+:1080F00053FAA251F97BE5B9C9A40F0EC9952F888F
+:10810000BBAD14FAE3E624F37839AC22B90CF6E7F8
+:10811000DDC512F1EB530D93C9FFF94935BFBF908F
+:1081200083FE58C8BFAB717FECA906A5EC26A8FF5B
+:1081300077C057F27F8C14870E0B8CC4DC6F182924
+:108140000EDD1AAFFE4571E86CB125EEFC2BC6A121
+:10815000BB985ADE0EEB9927F8CD4B773F9E8FF1F7
+:1081600086FAAC4495DE35B2C499B7B73D5E8DF85A
+:10817000FB5E03F061E207E6B8F2F76C03A52F405F
+:108180007FEF83298271E49F9D5AD031B380E2D082
+:108190003FC638746B5C797D4349C74CB4B335EF47
+:1081A000598A6B2FFDE0A3FC34BA17B506E5C2FB74
+:1081B000B98BA8FD6F35D7C7E891B2C69D1BED3DC1
+:1081C000B287B76783B6A990BF49CB1DA4F68D4788
+:1081D000288E4BDF2A53DCF817C5A5BF29F0B1560E
+:1081E0000F57E33ED7E62A2C2C45E3D247D28BAC7F
+:1081F00071DCD6F8EDF6B9DCAF6807FB604C0AC657
+:10820000B7075663FF756B251FBE3F57A7269723F9
+:10821000AB32E2DB8BD64AC42797B74974AEB47948
+:10822000C9537A0BF2515D2139B27C6DB2A310F2C1
+:10823000D7DFC92F615D1F92481FB9A15109A373F0
+:1082400042BA8DB70F1648DBD0B41F890E06C2069E
+:10825000FE471251EF3B6EEB4FBC12DA1D5FAB20B5
+:1082600045B2938D33BE549CBB91FF77E3D973180D
+:108270003FE7786931A7ABB75B027FC4FB08F7BE65
+:10828000AA30BCDF7D1D0BD07D60C6724F6D00BE75
+:108290005334FDEF47CEA7A1BEC3F589EB7217B6E5
+:1082A0005F81E5AECC7D898007FD382F27729580F0
+:1082B0001DEF87C5CFB6137E27F8B791FCADF4D973
+:1082C00042788F219E59F8AEE0EF43F7F25C9C0FA5
+:1082D000C70B7A5ECC7A6DA80F5506074BDBA19FC2
+:1082E0004540373E733F9C3FDBB5B2EFA03E18746C
+:1082F0008774C0C3AAFAC1C338DF85B952189F0674
+:1083000063020F65F88774E5665AD966288F177E71
+:10831000C2EEDC6D1AF2952ABC6FA1D27D13139EBA
+:1083200056698F333C7765D0FF2550BEB0DA5C1EAE
+:108330006FA193A995FC9CC49093DDFE8514AF8139
+:10834000F11C78BEFDD202683206527BAFB707F04F
+:10835000E0B5BCF2C3A89FB937CB743FC55F29F421
+:10836000243FF37F15B9EAFC46A4390EFDC9CC358C
+:108370008076EDBB7730E29F4B75298CAE98927A70
+:1083800089F2198DFC1EFAC5217614FDBF4B415FA1
+:108390009803E3663444CAF8F91FD70F0D3D69E925
+:1083A0006D403FA827841C3E7C22AF79C954C72A60
+:1083B000C8BF930E7C09F5AA4EB37E087A84493F64
+:1083C0005C5EFF7B929317EA895CBFB0EA8BF10297
+:1083D0006E3595420E0EE98B3D89A42FDE34BA7CB2
+:1083E00032E2E84E5ADE1B5B619C2763F018C51F22
+:1083F000F6B2857948EF3F71C5FAE78C38C39757D5
+:10840000059757C69CE724F83D0E7AEF27F74BEA0D
+:108410003943F28E25F2FB567F70A35ED35FC8ED21
+:10842000BE6839FCDF4DCDDE407A5828E06E433817
+:10843000CC8A9ED3E5B00619AF3E74E772BFF2E670
+:10844000A9DC5FD1B585F99C632E9C47BF6857A610
+:10845000BCF732EE73FF9B0ABD4368ADD7557EB5BE
+:10846000DDE746B9C8E1B628326BA26F18FBE3E539
+:10847000F23FDB7CB0FE799143DCFEB1F57A63E339
+:108480001E5F15F3E89EF50CC373A5D7A771BC4911
+:108490002874FAF05CFC627F7F1BDA5D197E5FFB5B
+:1084A000B7610BAA919E01EF261648A4B757F95958
+:1084B00098E3D74F886FBC027A3BF91199452F0E8C
+:1084C000039F9889DF19E97D31E5228EA697ECA7F5
+:1084D00084028E779847FAAD01FA457AEFCFED4FD7
+:1084E000C3FB4FAC82D3712EFC8BF5E31A698D85EB
+:1084F000AEAB5433DD2758F4E28B3FFF4527D2DF84
+:108500002B407F787FB91BF61DC7E92F78C685F60B
+:1085100061206F651FEE032B720D5C0274F32B7BE1
+:10852000AF6B31D6CF93C735C37EBF328597F71770
+:10853000B9CE201FFA55D195137DB1E7F40FB16B79
+:1085400082A09774E7FDD87B7322B60FF621DFD0A7
+:10855000FF39C6B11363C7CA7F343133A6FEF4CAEC
+:10856000A20388BF74A901F07DAA239C355C9CAA54
+:1085700081AFD7F7FD90FC61E8F78E1B458E9D1605
+:10858000787242F8B9EB3A93CBB561FBE574747D30
+:108590000EA3F70DEAEFB33B62FDDBEF54723FCD64
+:1085A000907C5CCB2AD08EAF3F1CE7C889C1BF3717
+:1085B0002AF9796230984CEF2C58C7395569D66B37
+:1085C000EB9B9903D7198CA43B104FEBEABF5CBB24
+:1085D000EBA78A791E4E776426C6D6E37EE1BAF50C
+:1085E000C3F763C499683B8A1D88EF71E29D82FFDF
+:1085F000B4FBA85F17D32217A1FED4C3EF0F45F534
+:108600006EEE8774A99ABC09F1228DBFB3DA9196F8
+:108610004F74ED8AAC96310ED601DF87DB8FF542C1
+:10862000EE76813E8B7A81DB1621FBC77DCE4176CB
+:108630008A23374CF138F1E7C691BDD2B7E416F280
+:10864000DF18FD8FB4BF0F083DA35DF42B55713FBC
+:10865000FE385B504AF647ED2C978BF3D38B6C2199
+:10866000FA0E3FEEB1317EB38B6ACDF6F4A14A0E1D
+:108670000F475A8AE97B7D6678A74CEF1DB95BF0FE
+:10868000FD013C5F453DA3CBBF527EB700E33514EF
+:108690001167C12464DD8152AEB718FC714160706E
+:1086A00031DA852F097EB779EAE8F2C11AF710EFBF
+:1086B000DFA60DB7AFBE2ABEEF092A2F5F80CF8C91
+:1086C000C5C4EB665671BFE3021BC0221FF883903E
+:1086D0002FD59678EDA9A21F233D54199C5AC5FDAC
+:1086E0008C11CF30E76186BE159FCBF52D48CBEEC0
+:1086F000443E0AFC0BF528C0D6B24D0551FDC5EB32
+:108700000F13BF5C047A16F2D3AFAA675DA04F3196
+:10871000D0B7B07FE39D4A8BFE142835F3C1746057
+:10872000DBA83F2D147E840BF5236EEF5AF5A4B918
+:1087300055663B3787BD1220BF552E7F0F77F3D488
+:10874000B387F1FDE14F412EA09E7D3C7791498F8B
+:108750003AEE0FDBC8EF26F85BBF655F2B3585CEA1
+:10876000D78E83BEE501B974DC1ECEB80FF6272D77
+:10877000F7EB956081B2E3539E74D711DE864D7E90
+:10878000A5D7728F784EC1F727B6ECD0111F751F91
+:10879000233B214EE82547B6F8B6229F67BA574AD1
+:1087A000BA0612B1AF39EC67E4C7D83C6D743FAC80
+:1087B00031CFB3155A03E2C1887A0ACC0BDF8306A6
+:1087C0007BC4B512F26B04BE0DC9E355C1355531FA
+:1087D000F9F85CAE9F809C9884FA655F9EA3363C56
+:1087E0000C5E776FE9253905C8702A6952F4FB13CE
+:1087F0005B6C7F41F9A3FB1D32C679B06CAE277567
+:10880000FF303703D7D397F87856AC3C32F8FB8D5E
+:10881000955A7315C66354692D55C4EFC4B98C6855
+:10882000BFC4C69EB7A75C380FA3FD1D73C57BBA36
+:10883000D95CAFBA57622D78BEABD729145FEC5321
+:10884000431EB44B4FBE3999E2629CF7CC18230FFC
+:10885000B32E432E3D2CE084F6512C9FA951134C8E
+:10886000FEB6F985A9A6FC8DCC47EFE6C4F8A712A1
+:10887000853E2C23BDDD7B0F3F0F3EB196DB69713A
+:1088800097AEB70747D9E713F7F0F389B823FFB0DE
+:10889000A33C83B4DD8B766E67DD4C90116C4F1575
+:1088A000976B4BCF25107F36DA3D5BE5E3763108D9
+:1088B0004CEC7FE9B9242A8F6B1DB4A35C5B11B922
+:1088C00097FCD64BCFC5119F8F6BD55F401361C509
+:1088D0007A4905880E9547DBBBA9DE8D9DE6F83108
+:1088E000831FC34FC01D7BDE73C9EE9BF09DAB2180
+:1088F000FDB34AFB19EEAF2F97C7E538F3B8DE6931
+:10890000D09D75DDAEDC784B9CAE3E740E8CEF9E38
+:10891000E0710BE7E7FAF3886F73515ED2FB2EE745
+:10892000CFE3B993A1FF32D6D386FEA0398C851E42
+:108930000614A9C8B61BEF9D887EA11AF45786BFFE
+:10894000C05CCB5CDF6E4B2BA0B8C3500AFAAD33D2
+:10895000ECF47ECAF9F3CC761ED6C3D286DABF1603
+:10896000EB2FF721CAC23C5EF3F3B89CD55A2FDD3A
+:10897000035B0DFC34ECA177875EC1A5DEC25C838E
+:1089800011C897C8EA9BF82E16DEA7C0F328C3CEFD
+:108990006B4EFC7D466C5CE5CD9B14131C96DF99F9
+:1089A0006082FF7501F33D8E86AD134CF932CF64C2
+:1089B000537E8EF73253FBB93EF37B178B2AAE36CC
+:1089C000D5BF406F66DC9F3C92DE9C549D2CF42109
+:1089D0007519C2A3CC9F43F7FD0DBF7985807985BA
+:1089E0007F890DDFAD3B8AEF44A01F48F8370D3F6C
+:1089F00074C9AE7D2457CA2CFA714221D7C74B7671
+:108A000058F5686E075AF5E9C46A73FCE6C5205844
+:108A1000697EC24E32E68378847A7019CA2BF5C219
+:108A2000F9007ADB0A507E629C937AE1BC6ED9B57C
+:108A30004F477BA404E417DE2BF8B2F3FBB2767940
+:108A400051761DE9D547BCFCFCEA48F67DA5299086
+:108A5000EF4BE37ECE3E6F893B05FDD4805F0CF08B
+:108A60004B4A6B76A35FEE857489E2C00C7BD8E835
+:108A7000B74FE87D6F80FE8D690E9BE246B9837625
+:108A80007B598CFDD837299481FCE297E9D3DBD060
+:108A9000E5F3ABC4E919C3E97D47E266F078C1C3E9
+:108AA000B36CC8374A6C211BDE039EE39B6C43BD4D
+:108AB000E78F62BC392EEEE72AF171BDA46407F797
+:108AC00027AC7649611FFC3A373BB36D3C941FF9E4
+:108AD000A184CFBDB1D51146F5B13C0CF58FD8C3FB
+:108AE000A41F1F85F28D905FE85D679B1E8B471565
+:108AF000DC6F10807FB86FB7ECB09F8EF59B17A727
+:108B000071FCA9B0F8118A857E516CF97E5DB5596A
+:108B1000BFF0B110C1E9F90C6E7F8F64C7F709F996
+:108B2000FC6761DF7C28E2C3DF17F1E16FE23B38CD
+:108B300097E2BBE9FC1D9CE79B54CA1F6D2AA4F475
+:108B400018C68FD3FE54506AE081D1FF0689395090
+:108B50000EE8F748741F61C84FE49AB13E00BFFEAB
+:108B60004AD0E10AE197EC2BCCA5F88417AAB46FA0
+:108B7000568F1D19DFFEDDF47958EFE961CE698764
+:108B8000CA1DEC9B78AE90CDB40C8C3B3FE9BE3453
+:108B900025368EEF57D55CDE1EB9CE8823E771707F
+:108BA000DD6B9FE1A93F7FD438DF84F022924F2311
+:108BB0009577CBE2EF83286EBA6FFF7E9E7FBB1264
+:108BC00033FE23D566BD2821B284FAFB46E76292C4
+:108BD0009B0F549BFD483DDA7EC2DB4F822C84EF15
+:108BE0000B8F382FD18F95EEFE2CE8EE43611F21BD
+:108BF0005E608A7881DF112F308F788179C40B4CC9
+:108C0000112FF03BE205A6279B6A29DD20ABAF655B
+:108C1000491C6F513E46CF27B97C237E0D7AC92D62
+:108C2000FA7D472F825FEB7A4687575DC7DD5E94FA
+:108C3000FBEBA4CCA378BE7772413C9D0FAC8CBEFD
+:108C40001736ECFB620996F7C490930CE947E2BD36
+:108C50002C2DA6FEC9C3DC0F146C541E888D87868C
+:108C6000B1490F0D8AFBA7FF53FC3C69C1CF2FCB45
+:108C700077B3AB83BFAE263ADA175161BFE76AFC20
+:108C8000FE42825FB7213E8EA8777B0DFF20737076
+:108C9000FD3B3E69A53BB67FC33FE8E3F248CC27E6
+:108CA000A827D3BA7BB416BAC7F609BE070B5D7501
+:108CB000304EDFD678C6234BC6333C67BF3794A40B
+:108CC000A29F2B1B4FB2D2F01E2E8F1FB9D7B79287
+:108CD000DF93D458081F8B738497103E4B9E255406
+:108CE000CF3551F46BC49DA82C8871282E8C9342EB
+:108CF00006BC89C741C236EA148FD2A8537F785781
+:108D000008E5BA0BE3A24C715D9AFC55E28F98F727
+:108D1000CB9D4BB6897B4043EFE7F9BEDAFB798404
+:108D200072B80EB087D13FB2D9C1DF03ED98226D82
+:108D3000C777B10C7D20C09BB2CA5CA91DE5EBEBE7
+:108D4000D31D3E859F83B7231D1C4FE7EF3FBD2EEC
+:108D5000F1FEF474FEF7441CB95CAE18FA2E7AAA40
+:108D6000E9DC02FD8568FF6A167D029920C6016A6A
+:108D7000367AAFA7D2A21758CFD1ADE7BC06FE4CCA
+:108D8000A9117CC9F0F38FA04F5BE169C4397CEA7B
+:108D900065241752B420D9FFCB84BE9ACA7A4DE716
+:108DA0006718D710AB27625C43AC9E88710DB17910
+:108DB0008C6B88AD8F710D66BDD4AC87625C8359B6
+:108DC0002FBDDA121F6EF1473069D4F376639D39F7
+:108DD000BE57689F36A571BD7CF3C285DA4DC8B712
+:108DE000F1FC97E239D8DBA897260A7AD259BF86D8
+:108DF000E744E9437A20F7735C24C61987E7F780D4
+:108E0000EF69E2FCDE881F30FC20CE40408D403F01
+:108E10009BA49E6DF8AEEA26BB968E70DC2449A614
+:108E20007B6CE9CCAC575F649D7F81CD140F60F8FB
+:108E30003D8C780067ADF93D07BB053F6EA8914DAD
+:108E40007EC91CDF7F52BCD8E69533C4BB75B0FA2F
+:108E5000183D5EA9E3F64A2DEC3FBE2765CC739919
+:108E60008857B801D71BC38763F47E1BCEBF36A3D8
+:108E700057E371F64C771AEF78209E4BBD6C1CFAC5
+:108E8000839927F36180E74335DC5F6BB4B7316FBB
+:108E900033DF4F95E2FF826D0AF115925D3172ABBF
+:108EA000D5BDB013EF85ACC06799A561FCF57AED2F
+:108EB000D1D8B81C29B65CA1F73EE9DC3C41EC6B8B
+:108EC0005DA7399E02FA35E51316F37B0C563AB4CA
+:108ED000EAF136180CC7FF5F354CC01BE829E65C89
+:108EE00021BA7EE67B5835AD7B1BC7D3FFBFD73D8C
+:108EF00064978B79AF10FBFE767CE0D1B130EEEF5A
+:108F000024276B83F495C4C1171A611D67F02D7770
+:108F1000BC2FB0F9EB8F225DFEEE5E27E3F165BE5C
+:108F2000E577433EB8C949FE99E518290FF33F5E3E
+:108F300093497095136653FD152D8904870F377F6C
+:108F40009687F2F7ED94E072C4BB0FEDEA248CB380
+:108F50003BD99227E3F9FCDBF103F4AEF0199979E0
+:108F600030BEFFEDDADFD9D10FF78ECAD4587D0DB0
+:108F7000D6AFC7AED33B8FEB81D7CBDC8F0FDBB93E
+:108F800013CFA93FB869B2CCDF89E5F81D94F8FE8C
+:108F90002E98C7FDFFC186D576922FA560438C22FF
+:108FA000CF60BEDF1CEEDEEE4431EEDB1983DF481E
+:108FB0004D43B8314F0BC14FFDED5DE84F0338D144
+:108FC0003BD6788104BE3B268CDFC6E3E07DB46EE1
+:108FD0004713CC0F40F5971ADECF49AC8BEDBCF1AF
+:108FE000FC5D295B307749225FA714B34FB02FEDAA
+:108FF00057209C24E6DB0F74BFA2E7F7746EFF2CAA
+:10900000C00DE5C83B9EC1F6C390FF10808DE7E21E
+:109010002BBC7FA277C3BF9D0F3B9E8E719666F8D7
+:10902000CD9A9742F0F870D3FD8974CEE96141C7BB
+:1090300038FA3B77345E70FDFFBA0BEF5F0419E737
+:10904000772E111763C5DBA5B05F688F7BE259CF20
+:10905000181827A1E1C3B26ACC174B836366215E5F
+:109060000F94215E1B71774B1BCDF8DAEA3E5B86CD
+:109070007CBE5ED8E3F57E33BF849FF578FE17E4AF
+:10908000BF5F80EF2B98BBE38A82E8FD532B9DBC2A
+:10909000D3B0732CE7A31CFFDF4EE1FB72A6450A99
+:1090A0006FA77DD126C5C65F9E127C0F37CC1E03ED
+:1090B000FF15629D00889EE274827F5935C21FD6DB
+:1090C00049FAA005BE009732944FC6FDAC0BD7BD40
+:1090D0005F5F02E5F5424F75B3413BDAAB5FB4FE2B
+:1090E000158B1D1D88E7AFE23BD28517C2E39D8635
+:1090F0004FEDA81F5C5FE70E61DC94151E1761A0A1
+:1091000014ECFBE9898335A905F4771B3DDBD1CE4F
+:10911000DB54528EF9771013C85F1C70703F0390B8
+:10912000F7CC285EE085AF7428BF8979884F1A781C
+:109130003304A74E6739DED7FADE8D6E26C3FC8274
+:10914000DEAB56513C80814F1638213FB219FE48A4
+:1091500085E2164DF2D58A6F32CE9FF62748F81F6A
+:109160002C15F1D736D8C761DE31A0FD1E0FFBFAF2
+:109170004AD22A7D36EAE1F171E87A6E7D99FFFDE7
+:10918000A86CD0E848BF04BD1BF569E33D1BA3BD37
+:109190002D6CB60B2FBC97C0DF0332EE1D0CB58BC8
+:1091A00070BBCDDEB96058FBCDA6F0BF83D87E780A
+:1091B00029CBCAC3795DE53A4D78CAF5459B53ED95
+:1091C000C4FB8BEC357E5F98A5B9D9EF0CB8009C39
+:1091D0006DA9B3BDC8575BE3CCF7EE9B049F6B133F
+:1091E0007CCA36868F73A17EC9F57145F895A3DFD9
+:1091F000C3FC3BAC0BF52145F89315A1478D5CCF23
+:1092000046E58AC5BF7D613DEEDFF6956A05FB0A3E
+:10921000F0DEB4D383F180FD71EC75BC4F69DC8F57
+:1092200036EEBF2E157861E40D79EB29D30EE0BE42
+:109230009DD69CA9F81EC05271DF91C645FF238BB5
+:1092400037E5978AF7378CFC4FE6E58838ECF1A6CE
+:10925000EFA06F4FDC877698DF918AC31A71B50350
+:1092600075DC0FD66DD7DB313E4C2F720DE239FC29
+:10927000F3790EE682F20565373DCEE3F68264AF00
+:1092800024087CDAECE865F8779B4E8BF742E127FF
+:10929000A9681CE91984FBC1D2B11D286F918121F5
+:1092A0009F708417939D56ACB3F2C5C837457C6F49
+:1092B000B0CD1C675382710ED06E39D82D780EB7A1
+:1092C0007CADB9BCD612679360C91BFC10F5F2D90E
+:1092D0002917EE979137E6D3A371BF8E613759F105
+:1092E000E92BF875E83D19AB5FE7C4BCD1FD3AAF97
+:1092F000CF33C793FFBB7E1DA57391093F8D7B675D
+:10930000479654CAE1343C2FCFDA1EFBCEED5FC442
+:10931000BC7E22FC3FCFA1FFC789EF6673FF4F449D
+:10932000F87FFA84FFE779F4FF907F50137EA00A5C
+:109330004A8D73F86BFFB998C5FAC73C73837F9960
+:1093400017036FFBB91C9ADF06035EC2FEECD1F86F
+:109350003BC09FA899F4F716F007FD4755862E4AA3
+:109360003C02EC53BF4FDCBB6B36F45C7A479EEC9F
+:109370009E4C9EF51971E6404755B3ABE93DFA2A7C
+:10938000D57CDE92906B8FFA8B189EF3D82CE73148
+:10939000A3FB8BC6280B285E4811FEA2F6C3AB19AF
+:1093A000C619295E95D6AF58FC455DC2EFF365ED51
+:1093B000E25FCCD352E6237FAB09A4CDC775BA7563
+:1093C0008A036A4B2E5F8A78F18024FE3E8FF55E19
+:1093D00069E00C7F9763320BA5A23FC5EDD1F13C4C
+:1093E0005BF1D9483F19E9DE86715F038608CBB48B
+:1093F0005E8DC68BDE9BE4F7B9DAC5DF0D6647E20A
+:1094000048CE3840CEE0F99FF1CEAC232D40F10597
+:10941000CC2DDEC5B3A9EAC261DFDFE1FB573B2FEC
+:10942000A0E2FA94C862C2E3AA1A6D3AAE7B085F62
+:1094300087EED38D1EE7D12EF0F25A7B90A1BFDFCD
+:109440006EDCA75375163B7EC97C8EEF672A03D767
+:10945000E2388E73D9342EC0B92816CE17DC8F6A45
+:10946000FBE94F7F3A93DF7B4278D9411E221E9F52
+:10947000A90CCEC576463F381EB687FEAA46EB0F2E
+:10948000DA05E6C7F0038757A7789A0DC2BF64AC28
+:10949000FF814016BD1FF84060219D13AF982F99A2
+:1094A000F85794AECC727B68FDCFFFF5AF7F05FC1B
+:1094B00068C781E5187B633EB7CBED42AEFFDA119A
+:1094C000BA1DF5A95B5F7B6E551AECDBAFD1874502
+:1094D0007F6FF9E74FE27EFE006DC898BFC7DC26BC
+:1094E00089723DF264039E1FCB46FEF82ACD1FBD54
+:1094F000477ADF6BC757E9E83F75A9C77C80B78912
+:10950000B9FCFD2986FE8D027C0F52C46514C4F897
+:109510009DB22E8CAFB0C68BDBC57D05ABBFE146DF
+:109520000C0C01B87E6FBEF9BCC4F87EA83278E39B
+:109530007CAEFF7A2F19265EC5A81713D744EFC853
+:10954000C4C922AE69A14C7E36DC8FD1E222DAC5D5
+:10955000DF1718DADFA1FB1CD9246F3658DE13DAC7
+:109560002CF6D5480DFE68ED37797EF166C42BC028
+:10957000AF07691D23F18562467C4072737F132A11
+:10958000B26887D8C5DFD7C28700902F38045F182C
+:10959000851F88BF7362E50741E2075D517E407217
+:1095A000CFB52C218CF191C639902B57E7FC40F8B0
+:1095B000A147E67B9C1F00FDEFC3F5D5CC0F3C43D4
+:1095C000EB53F97D952FEB27473ECBE73397E20628
+:1095D000168BF18DF930EF624A0F0B3EC002634DDE
+:1095E000F7CE9E10FB7F64BEDB248F9F98EF31F98E
+:1095F000C7D9A6D0A8EFCD3D26EEE1491947FF21F6
+:1096000025A19FBB23C0922E9CB74BE81B5D555AEA
+:109610003FAEDB4AFFEFB4F1BF47FB4EDB22A2FFB8
+:1096200093F3CD7A8491D60A3FF950DEF87BC36D6F
+:109630004F3DF514F0AD1338AF98B8D093F3B91D82
+:10964000582BFCE639E147427D30DE897AFE7768A7
+:1096500036AF1C3EEEEC9D7BF8FCF01C03CF07E31D
+:109660008E3C44F1207F9BCFEF232E5D2BF1BFFF7B
+:10967000EE2BF882FDE2FBFD19C2FB0A8AFBB02348
+:10968000DFAEC538477CB75097280EF3CBF663F0B2
+:10969000AF7FCE3FCFF957BCC1AFE21B703E063F54
+:1096A0003B3F3F6117DE6BBFAD46FB17E2D7C1F909
+:1096B000DA7992B32512D911FF17A17C379B00806C
+:1096C000000000001F8B080000000000000BE57D7B
+:1096D0000B7C54D599F8B9F34E66920C098F414131
+:1096E0006FC2C311079CF01210E586248A40CAE4B9
+:1096F0004198BCC80441431A746CB1655D2B373C7A
+:10970000624CAC46572AB5AF01818288468B96BA27
+:10971000FDDB11D0B22DD4442D06151B7C06DA7565
+:10972000E3A35DB64BCB7EDF77CECDDC7B3321DA96
+:10973000F6DFDDFDFFA7BF7A39F79C7B1EDFF9DE80
+:10974000DF774E988BC5D974C61CD5176F6BCD6665
+:10975000EC3CFEE631961592189BC1D8A637587D91
+:109760004720F15E7BA669F5CFF17AE6837E8663BA
+:109770003F576C37F663A17636A714C57636377F28
+:109780006AF517897EB4A7634CF45F9995B1A22559
+:10979000CA45A1118CED5AA29C5F02CFF34B600C1D
+:1097A00078FE646184CAF02BF0CC64AC96F1DF4A99
+:1097B0002936818D63EC8905CAC521E827A5964520
+:1097C0003B3CF0FC318B3E9D64FEE3713CE827A5F9
+:1097D00094B733D74FC17943FDC1F2064B0BACEBC5
+:1097E000C4266BCC998DCF69192C497FDAD371D6F9
+:1097F000CD942C5DD916615E0FBE4FA7F7291616C2
+:10980000C1F1EEB318E11A15EBAF15F36A57A6666E
+:109810004492CC4B7BBA63A54C9936787D9BE89FEC
+:10982000593DB42F272707B65B75FBB2488CD3DFB1
+:109830005FBC9CFAAB6929A3791686D2867FE08645
+:10984000EFA7B2A9E7AD389FA719E2C9A71116B5CE
+:10985000E65E605EA29F43E5A929E361DCEE4E6B04
+:10986000D009DD8C678FA485D206B67F6EBD97A91F
+:109870009731F6D3F53EA642C3E7D7CBF48CAFF7CA
+:10988000D3FB83EB83543EBC7E16955F5AAF50F9F1
+:10989000C8FA05F49CF7A74D4533615EA99D56664D
+:1098A0009507F6DF10920DEB4C3D3B85A9303FD973
+:1098B000E34DC7F93837E75F703F7FBA9E8979B9C2
+:1098C000C4BCBCF43C28E67B18E74BF3E2F3DDB5FF
+:1098D00020720BE2EDB567E35609E6E5969982F052
+:1098E0009A7BCD46C50B70F0DEA0DC1A22FCED9110
+:1098F000439319BBC7C2E9465DEE8EED842D29B4B2
+:109900007A0E5A116E2BC76D477CEB5E599A610136
+:109910003C50057E98E7D70AF38B5FA6DBF7C93783
+:109920006DB0C0B893E6B31E6B90B189FEBE3C9695
+:10993000CE58EEC2888AE34EF433C5994EEF153601
+:1099400005E6BBD5B62006FD9FD8AA7E2F05C665C5
+:10995000AA4F4ABF16EAD9D8F46280CF6E41BF5BE6
+:109960009A4B2F08A74E318F4F16286D487FBF594D
+:109970007F80BD3B21510F74AA20DEC300AC04D60A
+:10998000BDA5BCD5B502FADB62C2C3A33747B68416
+:10999000746597EC7544A0DDA96FB34B5806C0639E
+:1099A000B3331C4B328F535BBDF7D1FC997C2AFD3E
+:1099B00092C47B58DF9A5908DF4D4ECB04AC0E445D
+:1099C00058318C7F6A4FCB58E6C1F565D2F8DDABD4
+:1099D0001ECD9103C4771EC5F933193E1A3DF87A9E
+:1099E000711DC43F043DD30F3E49BFDA6FE07F478E
+:1099F000C5FA347A871FD1C57DBF1A37B59525BE04
+:109A00005BECCFDEDE2A25DAE34F190974CA743F16
+:109A1000E077A9F8CCE64519EA5DF88F71F89F8EDA
+:109A2000C387A01F772835DA0A88B6286867EFF859
+:109A300079BBF3F07FB71FCAAE44D9E5B719EA196D
+:109A40002B618A56B6E27F2B99E24A9433AC4D6380
+:109A500083C8C7D659BFF51ED04FF70BDFB6CB0072
+:109A600047C7CA3A16A1F70E7AAFC7CB77EC8CDDA1
+:109A7000B8503986FB99B248F915C2F5070B94978F
+:109A800009FFD7A935B8EE8DCC126C9D8E8B65B2CF
+:109A900017D623D1C218BBED86C8EBD4EE212FFB1D
+:109AA0001AD67F253DD80AF82C799B4388CFB6A2D9
+:109AB000D009DA278FCA908E19ABF67E70057EAF7B
+:109AC00058CE03DF726047A3891E7F43E35BDA83CE
+:109AD0004D12C2AB83A17C39BAC44B78CD7C30899E
+:109AE000D989F6250B9E62886F20D7402831BED1D8
+:109AF0002E925BFD6517AC779EA3336001BACEED65
+:109B0000FAC16EDB358037E3447BF55BBB15F87E2D
+:109B10005EA155B47F70B76263ECB843D7DF2CC643
+:109B20005EEEB389F27DF5F5E3617F9453055E98AF
+:109B3000D2F950DB6E17ECAFB5C222EAEFE955A0BF
+:109B40007E8E5FD9ED867A77F146FF3DC3707C65E6
+:109B5000771A8CFFDB3DDBEA8F8CC672DFC5AF4224
+:109B6000B9BDF848BD2B05E79B17F502BC9E2DDE5D
+:109B700051EF82FA63397CFC5D5DBBEAD5B9B8FE72
+:109B800090548CF00DB507910FC17821A4AB39C06A
+:109B90001FF4F495596C257C7417DB095EF3EC71A6
+:109BA0002BEEDBBC6CA6A8308F3C3FDB6481FD7ADA
+:109BB00079EEA12C84DBB16246EDA0FF34EA3F0CC4
+:109BC000FDA70DFC2EB558A676E6EFE1BBE1C5B8C2
+:109BD0002F65FCBB39889373F8BA9B6C54EFA3FADA
+:109BE00028AFFF922DB77D02C025B36BFD6E4F7677
+:109BF000A2BDA36B737DD3786A7F09B5EFE0ED87D3
+:109C000086B3F17B4DBF39CAD8027C3E344C0D87F8
+:109C1000E0A91673FDC0FC64AC2F0BC739EEE8F366
+:109C20002C81755EA1AEDB5D9042F3B892E071804D
+:109C3000C35BC38FF15D5FAB57F9BAA6D13CEBF9BB
+:109C40003C07E33B7FE953C3CFC95DB7D7AB1CCE1D
+:109C500079345E359F8F861FB95D6B77AB63107F5C
+:109C60003EB62AC84FAD4CDD0978B578DA9F2ED6BE
+:109C7000EB23DBC47A8FE5A8F5088F547F1FEDAF87
+:109C800022CB4CAF1F3C5FCCE516D2B465A6E057A3
+:109C900032978B8867302F833EF89CE8F7A0781EB8
+:109CA00077F0FE01655DD6A91C4F56C03CAA44BDA5
+:109CB000F65D3F3DA9EF10BDCDCB7D97F6B9AEEB7C
+:109CC000A0699F9FEFC57A6D9FEBBB0E68787223EA
+:109CD000C163087AB813E901DADD86F440EBEF2BB3
+:109CE00045BDA8E5CF36B69D9817C773585FB03508
+:109CF00017E1029C0DEAF3026C9B5EFF9A17E828BD
+:109D000047F9ABA397AFEAE9E58BF61B457A1A3121
+:109D1000B07FE8F7AE64F4745BF17E8D9E3650FD43
+:109D20007EBEEEC1F077303AF8BED807F353EB476A
+:109D3000A3CF3BBB3A767BA4A4707F90D61DE1E312
+:109D40000FC5B7982FC2B01DC8E9ADC549F0AA44E8
+:109D5000E6FD83C6BB1BE959C3FBB2E253BB550FFB
+:109D60008DD7A65F6F1BC27F44C23ED1F05983E3FB
+:109D7000B3623D45028FE1FBDD34DF951C9E49F067
+:109D80007AA8F13BE87B4177F3988D299909FA1A73
+:109D90006AFD0F8B7DB6E5F3F9B231204FD0EEF2BC
+:109DA000C9DB487F5812FA29F52FF8A336FEC1E225
+:109DB000C7EAC5F8713D9F292AE67210F0C926F856
+:109DC0006F999E4F9525F0F3E7F45EF0D12F4A5F2F
+:109DD0009A9C1D4A9F72C48BC97E68662CA9FEE5B9
+:109DE000B0727B8DF9A6523DD819A43F75F9C69380
+:109DF000BE3C9EA5125DB4F965D2A76C99BE6339CD
+:109E000050FFFA2BE32CA4D6B0265ACFB3A09F283C
+:109E1000A0BF1F00BD1E9F688728C20E51841DA2CF
+:109E2000083B4411768822EC1045D8218AB043F0D3
+:109E300069B53FA5640D273CF0D27EC4CB681D8E6A
+:109E4000187FA69E9D4976872B1063A86732F9C8B4
+:109E5000612BE83B6E8137C7AEF4DA155857B1DC99
+:109E6000C1A2F03C158AFCBB1EBF438CFF8A83E372
+:109E70005E447909BF9FA68E4CD8BF3F59C8F18276
+:109E8000F93209CE9A3D9C802F3B68457BC46F898F
+:109E9000215C9C973FADA640F9F70AEB6141ACEE1F
+:109EA00050517F76DD09BA1BEA195B5595F432C033
+:109EB000A4741F632F943F47ED3B01079D415C074E
+:109EC000182E3A7D72227315ED443B59B630D46B8F
+:109ED0005B56DE68E9447B51B1C648A9B3852E9F25
+:109EE0000EE57B5EB1527D377EA8C38737713F2E6A
+:109EF000E37604DA5563A2717B32FBB7EBE04FD611
+:109F0000EC477BAFDEE94D812557ADED6841789C8C
+:109F10005CFB28E9A15D935495017E968F6B1F0B26
+:109F200018C9DA6C2A43BDD5B5F6470AC2F7F886D8
+:109F300076D23BDB2AD32CC8571376C2E18DBF46BD
+:109F40003BC16BC999101C386E5D09D7CBDF7861B6
+:109F50004F0BC2A95372F5E073D263AE1AE2D3ABD2
+:109F60009C5EE4C3272E7F702C8E535E9556F3358E
+:109F7000A86FCD83F730BFCE3D2EB25B3AF3EEF63D
+:109F8000DDA4E32FE5E31C51B4BFBA726E2AC47E90
+:109F90005217041D29A81FF93BBF6981EF8FAF9DA0
+:109FA000968578DB92BDCB7723B6BBE9F5A2ABA053
+:109FB0009D2B6C9D096C19ECA37682D3A5B2AAF6F1
+:109FC00040BF078A22D79400DE54445F28447BCDEB
+:109FD000D5F8D466B4732E3D773FCDFB0473F5B44A
+:109FE000E2BCB237B8F07DCBCA8D2E9C6F287B8542
+:109FF00005E984E5B97A905FB7289B5D13E1FD44DC
+:10A00000D9527773FA4078B47C9B5D1BB912E7D5BF
+:10A01000ECBB290DD779B36505C2EF4F190EFCDEF5
+:10A02000DC3E2CE03769D24DCF60BB49390EAF041E
+:10A0300070699154DF0A588F5A9116DCC9067EF771
+:10A040005409E7BB556BE376F423803D477CA5AE0E
+:10A05000246B8F0A7CE5786607F1EB721B73D933AA
+:10A0600013DFE52ECCAB2EA1F176915D577E45B383
+:10A070004FC6F566DF3403E1D52271BEF8D42B93C9
+:10A08000F6205FFC64416825B687757D13E104689E
+:10A09000DCC3AE1DDC8E3D01F6A83723F1FE3B2567
+:10A0A0005C4E001E84C99E0E3C487CC76C8FB681F6
+:10A0B0003D8AFE0A7525D8A348C7C80B74FEB7139E
+:10A0C0007B5A7C8CECD0E2DB711F5BF2B85DFABF8F
+:10A0D00000EFEEFDEFC0BB89F21FD647D269BD8409
+:10A0E00017E192CBF6A03EAD809D17223FC373AE21
+:10A0F000647CE4E8CD91ED257AFF5780FB19705F11
+:10A10000D995897D347F77626BFB3707F3337CCE3B
+:10A110007DEDD0EFEBED255CBEB248D6E7F237DC43
+:10A120006751A63F85E3AC707A915E42C26E950B93
+:10A13000A29D76947BCA3809C7FBA5A0376F216C16
+:10A1400031E2CD6B56EC81B173D01FC89308FEDBB2
+:10A150009A28931CD2C98B08E3FC9DCAD9589F6AE0
+:10A16000284758268BFBF5F51719CADD76752CE2C2
+:10A17000A1FA8C2BB813E101DFBAA03CF9A2E98F58
+:10A18000B6EAF8EE67250E5A7F9390E3DD9359CC3B
+:10A1900009F5EEC8551BF3603DBF92589F340B275D
+:10A1A000A7A4E7CD2490924CDCE208527D779EABC9
+:10A1B0006F8397EAAD38DE953E902FC0BFA775DA62
+:10A1C000DEE9D1C9A77C97DD5076B373169447BEFC
+:10A1D0007C579F13FABF92E9DAD37A8CE50F4B8C48
+:10A1E000FED0C1F882CC7AD2D0BFD4B9AE3443828B
+:10A1F000F21F4B2C49FD764F087F5907E81F71402D
+:10A20000DDA741FFC0F27ED03FB09C5ACAF1A25BED
+:10A210006261D4F30ED7DD5C487A4511939CC3701C
+:10A22000B93368DFBB44FF8D45BCFDE7C07BA97433
+:10A23000C640BCC779A35E87F3BE909F6FA87933F1
+:10A2400065C4E7D2F3E69DCB203F18E065B0350941
+:10A25000DF4F8CD722C66BA7E7D3EBB78AF1623406
+:10A260009ED6EE19C54A7ECC82AC7FF66507F4E334
+:10A270006D20B8B4D9018E1ED417175A62386E609B
+:10A28000EAA3A82FC233C30AED2F2F7518ECA77EBF
+:10A29000F89CB51AFCF9CF96703DCB6DEB20BFBE94
+:10A2A000FBAC83EA9F127651A2FF9CED5AFF164F3A
+:10A2B00042EFFC4BFB4FB7B61765717BDCBB73BA43
+:10A2C00050FA909EFCDE18D27B97D0A75CCCEB4076
+:10A2D000BA5E5C9A4DFD84596C02E8CCCCBA2ADF98
+:10A2E000938B7180FDB65C94BBFBD222BE10F47FD1
+:10A2F00070B4632CF2EFCE9F442EF55E20DE001B7F
+:10A30000EBB3F868D491E239DC427419B760D9DC58
+:10A31000BE73FF6B2390BFED7BC64544AB8EB6C4C6
+:10A3200026640F6CD756CAF9D4E467F613BEB64557
+:10A33000BA48CE5487AD41641B9D6BB7D881158157
+:10A340007EB7A5D087FD344AC42E4FAE7D95E4EB91
+:10A3500089FD365C1EABB9FD4692633537441C124D
+:10A36000D8C7F5A52309DECD8A95E0D4BC76DA2ED0
+:10A37000D4436B6E5F9586F8DEECE1FCB979AD14E1
+:10A38000433DF084F26A9AACC39BFA52AE77ECB3C9
+:10A3900073FA33CFFB5D517F1CF73D09DC0E14CD02
+:10A3A0006F443AAB913AD350BF6E2E3DB0DA361BB4
+:10A3B000E1D1EBC7F2F31FECDE538074CC3A2B7182
+:10A3C0001E93417EE13E76E6394FE27CF7AD72CADC
+:10A3D0005618E2E0AA1FFB7A102EB83F17A0CB2F29
+:10A3E000BC3FCAAB2310DE079ABA2ADB601E296580
+:10A3F000EE06DBE50057984F1BF0D3E2D243ABD11A
+:10A400008F789F85EB49F7976634A09E0404467CBD
+:10A4100027DDA92C5E94643F13722A79DCF0923216
+:10A420000EB7A1E25B8E58F105E35BCDD87F92EFCA
+:10A43000BF27F625A354F96E29CCE39E2F293FC0F0
+:10A440007D78B644F93E3EB5F2F11CAE37B282D209
+:10A4500021F815E71FA1B8B7196DFB7D92FAA23B51
+:10A46000C9BA3B051E00DE972C82FDAB999C3315C3
+:10A47000E94CABCF10EB6E16ED34FA8DACCBA67871
+:10A4800001306017FAF7499E03CC4B34FC4A8DEC3F
+:10A49000237B658A43D90EED4201C7755896D0CE0D
+:10A4A0008479875C1E07EA6BAE5C16748E463BD1DE
+:10A4B000A60AB965390F8D4E970EA3FD68F67D4249
+:10A4C000785F29E21595175968FCDFACBC6C3B77C7
+:10A4D000BA83D9857A00FE3B8731BB98AFBB7EB586
+:10A4E0001DDBB102C6E6CFA676B27DA4B047A15D62
+:10A4F000C86771A03E0FB36F9F8FE3AF745EB7184C
+:10A50000CACFCC97FA707E6EC5AEF6E8E20CB53EC7
+:10A51000CB759B01DFBD17595906E065AD6A7F4FCA
+:10A520005FBFD1F3CEE672F8BE5A71F561FCCA8303
+:10A53000F20CE452F53A68A793DFF0BBD7A6B38BD1
+:10A54000DD658ECDD93A7DC1E5B719DAFFA6FE19D2
+:10A550001687FACA3A4F14E90FE665A82F29E57E57
+:10A56000108D0FC1EF9BD9E86F53AC5E944FF5A5EA
+:10A5700032D57746A534D41B52057F723736A9CC25
+:10A5800033345C22876D04C75019D012C211E1A286
+:10A590008D9F33345C3CAC87E0E206B8A07EB3D13B
+:10A5A000F3B4B20AE1340BF47CEFD0F031C3C3CD85
+:10A5B0003C9B717DA02E91FE6386C7298407E24DE6
+:10A5C000FDCE11A80FBC84EB27BF5E84D6E1067CCC
+:10A5D0006845FE656B1F8BFB7352C83F56308DE894
+:10A5E000092035A238891F5B93838D45A1616523BE
+:10A5F000C86E8BDB32137C65703AE47C65BEC28822
+:10A600006FCFF75A633140D17CA634E27CF2BD6E45
+:10A61000169706E75F4CFDF99EF805F88DF6043EA7
+:10A62000310EE735187FD8596A8C576AF39A18713A
+:10A63000113DB5D64B248FF7FA417F86F2A76318F8
+:10A64000F93F0AADD52DE87F395D6F674E4E6F2D0E
+:10A6500048EFE5627F5A6634BD9D8976A76409A2FA
+:10A66000DDB9FCACC4FD60938BA95F06FA9DF56271
+:10A670008C5BB7A7133F186363A847877D9F5EF67F
+:10A680001E804E9D1FE272F66BCCBB11F6A586C5EF
+:10A69000EDA8CF57B1685A3ECC27C5B6760DEA056E
+:10A6A000A9AEBB66AC80EEEEDE76F33375F0744E89
+:10A6B0009E9A81F8BBCCDAF7DA42C0AB8AF0F71A7F
+:10A6C000BD2007D22D6AD17880A3651953D7C2D295
+:10A6D000EE93FACA0AA0FE97BF9EF8D826A8EF2EDE
+:10A6E0007887E4D83FBE71E31A672ED6733817BD5A
+:10A6F000F63EC9090DEE474FB99FC27218E3863086
+:10A700004FCDDED0E2966111070847242EA74FB047
+:10A71000ED1E0E1F8A7F66E1BF61FECF2FE570CF71
+:10A720009ABB6A638FF04B5DEAE3FD59A1BF7AA241
+:10A7300040FA8F84FA6F56B739BEC9E3A564E7A023
+:10A740007D513649BA683AE17F3413E5E4021BC50E
+:10A7500047CF9F67B6F338F740FFF72F237D0E856D
+:10A76000377FABE783EB79DC74D07A87BA06F1F2F6
+:10A77000C11B268EF6C2FC33C64DCC44FBDF86528D
+:10A7800003E0D70B7A27E2C52101AF96A5A8831273
+:10A790009DA6E33EDF2DB5A7CF41BB6C8F95A15D94
+:10A7A0007626F08E82719E6699F531C09B25D7BCC6
+:10A7B000AF603FC3EA58D40A657739D723BD7BAC75
+:10A7C000F7A0986AF6FD8DF2525C1DC1121D7F182C
+:10A7D000556E31F87F07FB5EF3FF9ADFEF28E3EB5E
+:10A7E000D5F4EFE6DD56B223E149FEE0CFDE023AD2
+:10A7F000A4B8798F21BE8661D93BA73276D5D9001E
+:10A80000F967CD7EDB7EBEB0FE6FEB2F7E707D984C
+:10A81000DE4F3E5B47FAFD13EBEBA9DCB13E4ACFBE
+:10A82000A7D7AFA3E7FEF52AB59F750723FA38B37C
+:10A83000CA19DB00EB3893127F17F344D4D10E7999
+:10A8400027F957239333609D27A44964FF364BBCF7
+:10A85000BD5AE7A4BC92E6B49E8E43D4DE4F7E364A
+:10A8600066537D19686F37F919FA798F3BD44BD24B
+:10A87000D19E0663653BBC3FFD718CCA110B30D184
+:10A880006B89CFBD29C1FBF42CBF8CFC6D637A743E
+:10A890000603BA3FF9FA771E47BDB665DB0FE31F23
+:10A8A000C1B8D34F94AEC178C009491D0B1A0A7BB9
+:10A8B000E0F5237B5D50BFFCBD7800F9C5D72BB711
+:10A8C00036BA01AF8E61EC640E27738C876B710E04
+:10A8D000A636ECAD1F03EBDBC9FD394CADFF32C62C
+:10A8E000516CA9511FF9A9D59F341E81F6E59746F1
+:10A8F0006EC7F243DDB736E0F8E5A3787F996F8540
+:10A900009E447E73774AD4079C949DABBC6B0DD656
+:10A91000DF9DCBFB3FBEECAE35586FAD63A10E7A29
+:10A92000462CAFA05DED5FB14B85796F993435C38F
+:10A9300001EF2361AB9687E1651ADF001475BBEE6A
+:10A94000EDB44E01798B761BE04795E0D3FDF80F0F
+:10A95000801572DB86FAD7EDA33BC8EFD836565D7B
+:10A960001EE27A02E9592DF82F5CB3A4AA08D76237
+:10A97000E6CD7E04E6FB58A5889F795904E5B743E8
+:10A980006BC722EC0ED88FD0EFD264DC5F97CF6616
+:10A99000D0AB88F78D14EDADF8B4A97AFF0553C399
+:10A9A0002F8D9F89F6206FEB616A21EA1B0EF497C9
+:10A9B000789125EAFA437BF1B688B20AEABB40BF38
+:10A9C0005061BC42CFF6F848F86EF3ACB87D14EA9B
+:10A9D0003193595095719C7B3F467898E9B1386224
+:10A9E000D45F0A4DFA456AC0A88FC07CA9BD0D2668
+:10A9F00087F3B539822F0E473E3F52E2F8CA8EC424
+:10AA0000305E92CAFA7F32C645968BF5A4940F2326
+:10AA1000BDE2D815DE02E48B35312917D9F82CD4E4
+:10AA200077318EDB1BDB980EF3AEF7B5CFD6E78917
+:10AA3000B9CA5D3CEF30D6D43D1CF10046C0BCAD78
+:10AA40004DCF291D18873B52BE92F0779E43C3D746
+:10AA5000F57B15C0CF9A7592287F632FE2E7B1F995
+:10AA60001AFEAEFB32D627F241BEB217F34106CD35
+:10AA7000FF50A35FC6FC8F79B9225F446DDC8BF178
+:10AA8000336B4D7002E2F7DC13698FA7607E0A0B0F
+:10AA90008EC5F2AF8E7FA7A100DA152CB8AD600489
+:10AAA000ACA32C5447713B33FCAF59EA198EF930F3
+:10AAB0009ABFEAF87C1EAF6D05BE827E2B76E81E3B
+:10AAC00007E6EFB896717C2B9DAFAEC27AB3DDA6D8
+:10AAD000D56BCF7A7F4CC5FCB23050630E8C3FD71C
+:10AAE000C2ED88B9737CDB9A486E472C9DC827F667
+:10AAF00066513C326519F74F857DDF7913F3833258
+:10AB000095F88DC88FAB190BC660CBBA6DF1712E5D
+:10AB1000D48BFA5C8ACAED20D9A1C77B95BD3E1EB5
+:10AB2000F6BD4EECF396C7B2484FFE14F016E1B1F5
+:10AB3000DAF7FD3749AF603ABBE7AA04FE2B8CBDBC
+:10AB400080F87475AF915EAEE93396E79D3596F364
+:10AB500098D16EC97719CB855E63F97A9FB17C83F2
+:10AB60006C2CB34D1CFF417A90BECF04BE6BF446F3
+:10AB70006F34FA855F168B907E5F05F417877556E4
+:10AB8000458DF493976B23B8A76E92282FD5A1EF2C
+:10AB90002F1BC1E6BDAE00E05401E21FF9C5E91D5F
+:10ABA000590EF40F3F30D7CED05EE814F26CDEB908
+:10ABB0001F6C46BBC821DBA2D82E15752AE8777515
+:10ABC00080C52CD9F8BDD19E848E8F231F592CF6B9
+:10ABD000031624F7CF3B6720DF716FFA7901EE97F8
+:10ABE000EF622B433B8305F93A2CF03F0E870E654D
+:10ABF0002BC6151417E5ADAD8EC469FC5A1F8BC961
+:10AC0000A8A76D32F211D74ACE9722001705E61B8E
+:10AC1000B9D3586F8683C7DEF7C27968DF0AEB5174
+:10AC2000257C86481F70C0022C807F0EE5D1961CC3
+:10AC3000E433415B90F2033D119F5E2FF96DB9241F
+:10AC4000F2805BC394FFCA2C4127EAE30F717D1B9E
+:10AC500073D1C80E32E5AF497239ADE3BB97022D0F
+:10AC6000835DE35C7771179A389297BF077B3D82CB
+:10AC70007685D316A2B233C4543597F2DE9E593A84
+:10AC800003DB5F42ED9D2CD8E204FCD824FCC020FD
+:10AC9000181CE85FAEF3BDD43D0CC6FEE9524E5F12
+:10ACA000752E8F6A4D273CFB5DFFFA09BEC6BC3886
+:10ACB0002D8FC39C877D6829A7EFFBCB252DAF5B2C
+:10ACC000E3578A21FF4D7DBFA180F4482E7F7FF995
+:10ACD000EBF71F43FED87C0D13F27AF8DE17A0DFE6
+:10ACE000870FFEC76BA5C86F7748418CD33EBCEB7E
+:10ACF000632ABB0A6CC105D06CD438F53AF2BFEDBB
+:10AD000091BC08B4E6D1231F407DFCD30093911C75
+:10AD1000AE0F845663FDEA9853E6F692925E38527F
+:10AD20005319F017B3A23CBC4AF8FB416F7EA5C093
+:10AD30008EA08F1ECA43FB08ED64CC0B8B473BB142
+:10AD4000EC526CC1988C7415EDC4FD762898780B84
+:10AD5000EF7764E7A15EDC54DE40FBD00276D628B4
+:10AD6000E443BDB677108E21F8DF79217FC9AE5854
+:10AD7000608C2B38E40FDE421CB8CA142FD0E4A23A
+:10AD800083F17EB4F77D4BD3385FBE8A5DC5F3AAED
+:10AD9000DF217DFB33987816F2438C2BE8F4FF30EB
+:10ADA000C615025CFF5485FEA93AFFFABCE9678428
+:10ADB000BE3C54BCA05FAF117182A3372BCF94CDA2
+:10ADC000C0EF19E1C9CC6E95DE672FE5FE8239BD73
+:10ADD000118AC3973B8D795DDAF3EE328EAF9FDB3C
+:10ADE0004EB019ED8407C5BC6B18E0FB948179EB7C
+:10ADF00063CA8D719A66DF17CB5BEFB70B86B643DC
+:10AE000008191F292B69C07CBA25D7ACF2A1DEB185
+:10AE10007AAE87A13DA6E1BB5BE0FBC307FFE16320
+:10AE2000949B0DB283213DB464EF22FCFFD4C7BCD8
+:10AE3000569DBD3B5360F7B0D17DAF95427D7DB748
+:10AE40002588F90DD7A3B303FB073B06F9BD86EFB1
+:10AE50003F76A74BA89766C62387B4FCDF18FAB7DE
+:10AE600076E44A885799F06D50423E7F3F7DEF0669
+:10AE7000BEF708E2B7B09B57B3C4AF3F9F58CC674B
+:10AE8000EECC843EB97A479382F91DED377A646B34
+:10AE900092F8FECCB78CF6B65BB119F28D41BE18B4
+:10AEA000EA33AC79DC9EC9B6C49AD09E413B15F515
+:10AEB000635B84E2C3328BB8D0BFDF1603FA96D14E
+:10AEC000AEE57AC6E96EEE4F39BDE3465AEFA720EC
+:10AED000B7703E675EA8584DF1B180434E41FAF31A
+:10AEE000A964E722DDBB5912FED12DF29D3116690E
+:10AEF00041BAAE4CE43F73FE7268854E3FAE1579A1
+:10AF0000CFCF0AFBBCA9FC8F76DCCFDE6F48B253F3
+:10AF1000C67A9EFF9C8C6F109F027985FD98F9C7B9
+:10AF200055CA4AF24B7A5778A219B392F11123FF0E
+:10AF300038BDE35D4581F6EDC82F009FEFD0F05D91
+:10AF4000F093C1E292A777F038C8A75E1FE50B9E89
+:10AF5000DE919F5107EFBFB4C2189FB4B59719E3B4
+:10AF6000517F73BEC3F986261F5C26F9A0D1CBA8FA
+:10AF70002B5592D3674633920F67F68C7A00F5F221
+:10AF80004F6312970F267A18281F400E109FE77202
+:10AF900040A317E7589B05BFF36EB3C6100E201FE2
+:10AFA000BC73C8AF6A61281FFAE966B7C482680F2C
+:10AFB0003A620EC23B900B0F66E3BE3F967F07E2FC
+:10AFC000E5682BE54199F77B807C087C31F9B0BFBF
+:10AFD000FCC2F261B0FDFDBCFB84FC1EF9A9B65FAA
+:10AFE000C8F7F11CC650FBE628CFE47C1BE400E662
+:10AFF000DF6AFB58B42472B45C9F8F381C34C4E9F8
+:10B00000897C44CD6EFAF3F17F6AC0BCE2A34B4267
+:10B0100057A17EC3023C8FF02AA07BE4E747974408
+:10B020007E8D7ED7F48BD74D467EC61EE7F987BF4F
+:10B0300016E30CA8DFCDBFD7EA93E4A7D6A03D73F3
+:10B04000BC92E3B7F9394DC82B2D4F15E6F56E3993
+:10B05000CEAB3FBF91DB63278E7FBB41E4677F5858
+:10B06000AECB8BECB7E7D4AD8FA1BDA7D973A78EBC
+:10B070006FA5F6CCD3E1437DBBB9298DFC2B3B9763
+:10B08000CA345E9B3DE66B07F8BD7CF9754DC85F21
+:10B090003C5B2C84475A3E1253B73C1647382EE08F
+:10B0A000E30C267F8E2E51CEE27C343BF3FDE3DFB2
+:10B0B0006A1079DDE7689E0522AF5BD8A51F1FDF08
+:10B0C000F298803F5B86EB54F83A353BF68FC71F0A
+:10B0D000A2795F778362C5FA5AB4D7747CE0377778
+:10B0E00066A5A09C37FB7953FD5CDED7FBF839C21F
+:10B0F00070B53B9693243EF6621D877B8B943C9EF5
+:10B100009ABB707EE632B243E3E3F0E84DF8139762
+:10B1100057E43DDF48E76AAC2C887AF6DC0DDCBEEC
+:10B120009C3BC9B20D7462F6C708D75B35FBD26C85
+:10B130003F662A6A117E5F0D7224467E10933D3968
+:10B1400029D3604FE6E54E97701DAE4689F4C07A6C
+:10B15000B42FB15FF6FF967D69B62719E376559D4A
+:10B16000905343D993BDB1CF674FBAD09E443D06AB
+:10B17000ED49E9EF674FAE467B12C6AF477B72FAE7
+:10B18000E0F6E4EA95DCCEFEBCF6E4A5E75E0E311F
+:10B19000D2E32C147F69D95D6CB22737BA2E644F85
+:10B1A000EEAEE5F615C547A09D3AC715DB992D36DD
+:10B1B00005F1FCEA548A07B72B5CDFF93498BD1D12
+:10B1C000F5C39DC29F8FBFBFE45CD842712E8C89AE
+:10B1D00078EADFFE7CD8533ECCB3AD13719EB61730
+:10B1E000F630F42FD5F9C16EA0F78E6FE9F98976A4
+:10B1F0003E6C27F27F8C8B8FE6F939CD931FA038F8
+:10B2000018933273ADBAFCBAC3826F9FCEE6FCA32B
+:10B210007958C497ABB3573A457DB3C8D7607E0E13
+:10B220004F47F5D58FEACFE36D5BE610724B892D62
+:10B230002378AA04D7C622653B9635BB589327DAF4
+:10B24000773F14FEAF3DCB24F17D680FF1D1E1DCF7
+:10B250002E649E78CC32521F87E2FE49CD5F79EC96
+:10B26000D16D0EF4033688F324ECA1F660898EBF0D
+:10B27000FF689924E4A0F223ECF7C012653FCE6783
+:10B28000AE6503F9DDE7E63864F4AFB5D8FB4AC92B
+:10B29000AFFF271BDB2925F066BE4FE41188F2F5CE
+:10B2A000323F4F08FCF310EA4D37C832F1CFB7EA0E
+:10B2B000B269FE8BAE3C46E7490ECE9019C6794284
+:10B2C000CA0B56F4F7E7EFBF9261DC7D4A51E845BF
+:10B2D0001CBF70415EC170588FA728F4735A2FD3DA
+:10B2E000CEDB713CFAC30D915F623BD0DB5427DAB1
+:10B2F000638118C98381F86D8CBBFC41C8831797A3
+:10B30000285DF8FD6D3728AF10FC8B42AFD1389E19
+:10B31000E4E7FA407E75637DCA6FA39311BF7FB2E5
+:10B3200030F2169F176B1F9BE43CB8B6BF47853DB4
+:10B33000792C0DF4021DDEFCB68ACFE326A1075B53
+:10B34000EB620B30CFAA0D5444159EE78A23BDD87B
+:10B350007F9B7F859DFC15A06F607ED149DFF6093C
+:10B36000C89FEA03D20129039E480BE4FFF80FF2BD
+:10B37000F79AFD279BDED0CAB7AFA90FE8FD295F7A
+:10B380005B8379B036272FFF6BE5EDFB508ED7CB73
+:10B39000E2BCEC5B8AACC7134798E3DF9B21E53F37
+:10B3A0002B67905F774D28B93C3D87F03C8EF6AF18
+:10B3B00085F68985670CDC2780BF84EF01FE167C4B
+:10B3C00002FC6DE11183C37F30FF913BCCE9E34C7C
+:10B3D000A49F3E7E57A9A38F0BCC7358D838CF11AA
+:10B3E000E124F804F31C29E6392ACCF164F485E65B
+:10B3F000E99EFEC0DB143F505364E95A4C5F89DA82
+:10B40000D08E7507395EBA7D12F9034F4BDABEBD97
+:10B41000F224EE83DB33FD7D9467E5E1118FBB46BB
+:10B4200024FCEEB397AE5DD3320BF597CE462CFFDE
+:10B43000C33BDF6DB08D0532CEE6FB7ACB3BDF7DC3
+:10B440000CCFE794E6042748486795631E775D2391
+:10B45000E4D89C041EBCAA8DC76EDB570FE3956A27
+:10B46000710535E77105BF4F557D18572BEE9EF0DE
+:10B47000B80DCFFFF4C70DEE8CA29EA98DF7618F9A
+:10B48000FF711C0FCFAB227F2800D8A29C28E95562
+:10B490009BD3617EF3C32C8E47DF1D0B049EB1EC62
+:10B4A000C731AE509AC9C77BA3D2D748F335959917
+:10B4B0009FEB8DC0878208DF20068C46609C818FC1
+:10B4C000731D8E037328F31AD75526F3F25B91D1BF
+:10B4D0008D2DB0AEA565BCFDF5625E4B19AC0BF3CE
+:10B4E00032BA6F8DF27529A3515E7E18B9335A00B6
+:10B4F0007CDE9AB689CEDDBA02C6F376DA73B6265A
+:10B50000FF6671BD15E6371BED88D9427EBC190A6E
+:10B510005511FEBE047CC14A7C81FC54C8A8468DEE
+:10B520001CC81734FBA5345D5D15D2C7016359DB18
+:10B53000548ADB852E9F837189635992046B3BAFDC
+:10B54000C5E54CF1C0D3633B54D4777AB36DD1EDEC
+:10B55000DE817141668AF799E3839F54897EFBE31C
+:10B56000804CC638E07F77FC6FA36705E983859838
+:10B570005F847181C6A718865837CF0A7AD1FF1D1C
+:10B580002AB4325567C79AF7EBAF8DFF6509BBD078
+:10B59000E6E0F96A804314AF3DD0D444769DA79A83
+:10B5A000C3ADB196E345C7724D3F529767C1BC4BDF
+:10B5B000018278DEC0BAEDC72ECCEB6C0B3C7D046B
+:10B5C000E5E0719F4346FC6D1E7D930FE199F27596
+:10B5D00027DD1B7172989C86F9956DDE8D97F0388A
+:10B5E000F3D5FF76448BA3035EEFEEB63D897CF97D
+:10B5F0001599D3DFECE50FFF1BE543CAB053BA7DC5
+:10B6000072B8E6529E962B8FE795EBF681F61B7F7C
+:10B61000765D7B80B33A633AE90972168EEBE3ED0F
+:10B620007DACA789F250000F1CFAF8B3D82797B069
+:10B630003BACB729F7CE4079E5B57A311EABED7357
+:10B6400089D867F3BE7A986CD87777F846CA53D210
+:10B65000FC4FEE05C67D4B5D6C2C839D62D8B7F91F
+:10B66000E11B497F9E0F7822D339329E77E612E3A1
+:10B67000E73395D6970F86761CC63B8CFC02F59770
+:10B68000591ED20B0A862D2D1806E5C3AE61B9B836
+:10B690000F603798ED924D585F90362C17FD80DD86
+:10B6A00061635C533B47A7D935C72EEEA07378A0E2
+:10B6B0008779D13FD785F14E3B9ECF6B72603915AC
+:10B6C000B308789CD170AE8E1D4AA17B381AC07E1B
+:10B6D0004D817D3A1A7C344EFE3D3FA373340D05F7
+:10B6E0009ABCB63C89FEB7CF7B3F4055CDB34F18CF
+:10B6F000EF07D8FB04CA99DE73DAF9FF5D4F60FCEF
+:10B7000078F0FB01B6DF526F43BBE25401C6A3AD34
+:10B7100015C33A8CE72DBFF53BFDFD00132A360714
+:10B72000F4F70358AE3FF084FE7E80B335E76ED168
+:10B73000DF0F20BDFDCFB7E8CF99FEBEE667B78823
+:10B74000FB01EC15484F439C870E54F03C890915CA
+:10B75000FC3CF450F703FCBDE2685AFC0CF450D5F5
+:10B76000897A68BA25C6F5E528E90B9B4C7E88B82E
+:10B77000F023BC12D1F8C800BDF33282C720F719FC
+:10B78000A457C883DD673085BE339DBFC67DE2E721
+:10B79000AF4D7EAD2346BF16E85133F17B8787EB73
+:10B7A000BB9A3E0BEF67D37B99CB3BEDFD33659A9C
+:10B7B0005FAB5DC67ECA588CEB4140F9E8BF2FF302
+:10B7C000C628CF81A993A87C66CFC36F63F9EEA684
+:10B7D00014D94AED3AE87E94EB2B381C48AE637BD3
+:10B7E000B0DF799E11F71F9E299232F13E9684FEBA
+:10B7F00094D1817A6FAB1DF41F98C2F2131BD6B897
+:10B80000C626F4A7FA0AA614F8601C3BD3F406A2D5
+:10B810001BE26B441733492F3E6337D2158A01DE92
+:10B82000FFB47D58AFE95FBF38F51DA3FE75E23B5D
+:10B83000A47F0DD6FF9ACA3D8D2D81847E04F389A5
+:10B840002F407EB3E0B630EA252515FB1F770D3378
+:10B85000B6A73CA2FEFEF63C8EEB33D7C3FE36D035
+:10B86000FE0A7FE650EDD9E27EFD258ADFCD167E09
+:10B8700041733E8726EFCC72F5D54AAE5FCF28558F
+:10B88000D6E1F78B0E6DBC3D94A45D5305C7E7452B
+:10B89000F33A7C282FDBC672FBDADCCE53C9F719EA
+:10B8A000FAB904DBF536256FB7AB426BF7289D1B61
+:10B8B000697D81B7C3FE8B75EDEFAFE076545B5ABF
+:10B8C000723F9FBF52B373430F54A07E762F8707FA
+:10B8D000D8BB0FE27AC0EEDC82EFFBE90B6819E916
+:10B8E0000BECCF8709CE3695EC89363BA777CAE5B6
+:10B8F000BA3A09DF0818F986995FF4F39D12A6E2B7
+:10B900007D0AB6A2C80E1C77E3BA283F1737885DB8
+:10B91000B1681E3F37D39CC6D76FF613348BF5172B
+:10B920000A3B48BB3F0DEF2DD0FB819E17FBA3F1D7
+:10B93000E503156F35EAF9F23F9FF047F57C99A9C9
+:10B94000133BD03E2872F2F2A113EF68F8F734C12E
+:10B95000E54E0EC7A72B38DF18EC7E80A225CACF94
+:10B96000B07DD120F1D9172BFAF7E745EA77ADE69C
+:10B97000EFE6F69BF91E8E972B06DCC3B180FC1B0D
+:10B980001D46FFC6CBFDFD2A2FD3FEE65A43C9F460
+:10B99000FC276A39FC58E048DCAA9D4B94899E1527
+:10B9A000833FE5CA98D19FD2D26E88139F4C8C7783
+:10B9B000B282DB010AEAC75ABCF3D80F9B0A510EC8
+:10B9C000334BCCA19FE703157CDF8EEDE5F5F31C2F
+:10B9D0003C2FCA5C3F5DE8ED80B7A72BB8DC1B8726
+:10B9E000F8340F7015E5CF5CCBD44E85FC3652B0E1
+:10B9F00009E6BFD0FF02F9B1E7834985FE96FC4016
+:10BA00009E0DD3960AA7D76DC2E794A2C867D8CF78
+:10BA1000F5734F05512F9CBB213EAE3D4078FF870B
+:10BA20000A9DDF45A377C4C362DDBCFE2CF0AE796E
+:10BA30006C72BABBAA4A936BFD7E1B4B65127FC02A
+:10BA400000BF8D87F3FFE6D96362FA739B7E212FD7
+:10BA5000C12E4FA9E476F98AAA1903E945CBDBD3B5
+:10BA6000FC62A58BBBE65E04FD15AE93642BDF572D
+:10BA7000F293D5887AADFFDE22C987E770B53CBC6A
+:10BA8000E76A4F3E4979A46B25C15FDF7C12EDD98F
+:10BA900044DE5DDFAD441FFD7AD66FC99E1F5CAFEB
+:10BAA000FAF0D67ABA27665AA71DFA5FD673EA4922
+:10BAB0001FEC4BA9765E80FDFEC90B9D17E815743F
+:10BAC00066A67FED394EC07B30FABF56F82B35FAAB
+:10BAD0009F5539668D9EFEAF7E63CB1A5C6F82FEEA
+:10BAE000EFDFA75F5FFE1B396B04FD4F253F8BA087
+:10BAF000FFA995EC82F78300FDCFC3F6E67B77B410
+:10BB000067A1902FD06F21F53B04FD2FA934C68F7C
+:10BB100007A3FF25FDFD2A4B2A470C4EFFA3AA8C45
+:10BB2000F4DFC0FA7F44FFFDF4BBB789E8BF7E872E
+:10BB3000A4E0B94F33FDD724C6ABA91C91A07FCD9B
+:10BB40002E39364E2DC4EF994575E8BFEBA7FF4758
+:10BB5000059EA9471A51DFD7E298BD158FEC13FA5D
+:10BB6000F16AEA773A87FB507A09B4BF95DA073968
+:10BB70003CFF5A3D6780DE1837C64BB5F8DDC0780C
+:10BB8000585F11E55F062C49E36159CC7BDD66C047
+:10BB9000972AB00FD15E6B0B6452DCCFFDFF491CBE
+:10BBA000CC51C6E3F5E6B88F39EE89FEFFCA247A98
+:10BBB00039C3C434CDFEC57DF91FEED771A1FE395E
+:10BBC0006370FF0EACF3255AA7D76867786F88FCBF
+:10BBD00012DFF7E753645B289FC2996D494199F1E1
+:10BBE00079E3C7D0FF2BD4FF78231C1B8B94D72A73
+:10BBF00049DFB4125DDC7922FEB8885F77131D89B6
+:10BC0000FB9BCC71FCFCB0280B3FE640FF28D3E83F
+:10BC10002E8EFFA9EF2FFB1A8F60DC3E70E1FBD761
+:10BC2000CC7ED165DA78E23BB3DF1BF48334F44B8E
+:10BC30006AFA163BAAC87A7EF36668FEC7B41E95F8
+:10BC4000A9D24803BF530DFC4AE377E2BC147BCD75
+:10BC5000D8CF7F561AE30230EED9659C8FFF19CBFF
+:10BC6000291F1AE17BAE389285FE536B9DFA25F4AD
+:10BC70009761BCA3693ACFB7F200BC4ED6A7C424E3
+:10BC80009D1F4EB39B8655697EE55CB2F386BDD998
+:10BC9000B2CF356368BBA734331AC6F3452527A056
+:10BCA000FDECA4765456956EDF86EA6FB07C8F5C0F
+:10BCB000A197999FA595463C616ABF1D968DE39A11
+:10BCC000E5AAA6F7B17546B9E2AFEA972B7EFC6EFE
+:10BCD0006A25A71FF33D5EC772FAAC4817DD40E343
+:10BCE000DBF1ECC9A6F6A0FE3CE43CE14F96AB9834
+:10BCF000266FC792FE24F07A6C1587BB96A701E3E6
+:10BD0000F5A21EA8E91D5ABE3EC697F5FDAE14EB7E
+:10BD1000FDA2F1E56AB12EFCFDCF8C2F37517C5985
+:10BD20003B47D822E2CB61BF4AF7D08407892FEB8B
+:10BD3000F4DD4855127D17F4D7BA2A9DFE6A2B0A06
+:10BD4000A5223D368F6EA678C496742D2F31467984
+:10BD50008913D9D6859360BD2D3BA420FA2381DDBC
+:10BD600053BC7FE16BFC5E2BCC432B9A49FC9EE8D5
+:10BD7000D659A3BAD0AFBC50B69CC271B5FB7A9964
+:10BD8000B53AE939BAD6F408DD57E5D8B1AD19EFBF
+:10BD9000B1CADF2D897815CF73BB34D0DE8CF701A3
+:10BDA000B8D77516F0BCE5475E42FFD6995C898D21
+:10BDB00092315F2DA2627EDAE9D94EEF06CAE3180E
+:10BDC0005378873E5FA280DF83E282FFA17C5C3CE8
+:10BDD000DD782FCAC221F20FD7BDD535E5B06EDFB1
+:10BDE0005AABD20CFE582D3F4D5B5F6DFFBDBF1DA2
+:10BDF000E2DE5F9E6FF6EFEB3BA71C86FD7948E81D
+:10BE0000C9476F8E3C54A5B32313F792C47AE93E19
+:10BE1000371FF322DEB6043E39741ED6F7FB984472
+:10BE200079A08E788A8BF200574A31CCFB5C1D7B5F
+:10BE30006033FAB31B645B14CF7F35D8781EB93BEF
+:10BE4000E6A4F8F951843FD8D072B8FD17E8DF3D79
+:10BE500003FA11EE5BBE1C6DC7784F2AEC23E67324
+:10BE6000A6069BE2988FB8181806FAB59D156A7C4D
+:10BE70001A945B15571F9E8742BD4A9FA7F225D98A
+:10BE800042F7DF687031E7B998E5B676DF4DCB68E9
+:10BE900091BFA82AAFA01CD7E8CE213F6BC37DFC81
+:10BEA000D5682BA3F3ECACDD41F416E0FE786DFF12
+:10BEB00098F55E15F3647F2FCECBBB98CE7F8EF0C6
+:10BEC000985E47FEFDA288278AF92D45417BD2B8AE
+:10BED000CB60FBFB5295319F7A8F8D0531DED5F615
+:10BEE0009A95CE7FB5EDD87F04C757775878BE0BAB
+:10BEF0008B907F3782F7FAA2DF300E1AC84C3C874E
+:10BF0000CCE9A1ADB863731DBC97BF7A4910F97B2A
+:10BF1000DBE467ED586ECB1ECED07FCD2CCA0B78FC
+:10BF20006EBEE6BB5689F31346706A5B372CC6F3C8
+:10BF300019620EFB703C1FEF61D8BF86474B049D12
+:10BF4000D4E37918F8E70A162478AD64217ADEC4C0
+:10BF5000A2F4945880F2132BA39C7EDB441E69CF7D
+:10BF60000E0BE5C52A57DB877DE0E22EA064F25F69
+:10BF70007B62A4EA031DBFBABA4AC81757C487FC3C
+:10BF8000E6CD50E4A32A837EAED07DDF89738F1F78
+:10BF9000D33931CDBE6B58F1F15E8ABFFE2FD31F6E
+:10BFA0005BC2F205F547906BE9D5A87FDCCAF50FB7
+:10BFB000ABD0FF187BF65685E2793C6EF248387CB0
+:10BFC0002BEA77D65C5648FEE91B2446E7FE3C4741
+:10BFD000DEB31AF5A2F19867A3F90BBEBF3C87FB4D
+:10BFE0003DCE6D4A47F3E4D8DE3A8AE32E0F58B6C9
+:10BFF00061BE59D8F3A01DE1B47956E834F2E98A5C
+:10C0000063E21EAC41CE756AF0A81683A58A78AEAD
+:10C010004BC473ABCBEA17A37D608EE3B276BE6FE1
+:10C02000E6389D8DF9B69DCF4EEC8376CF96EE7BAC
+:10C03000DA07339C5994D3B91F7AC038A0760F46DB
+:10C0400078A5917EDD68AF4C4976BFC3BD1F5BF913
+:10C050003CE9BD1657D5FC29BB9797913FC566D1E2
+:10C06000F0D14F71A97EFF8A7A39C5A5488EE9ECD7
+:10C07000549D3F45C1DCBE502FEBF7B7BBE8BE5324
+:10C08000F5BE6CE8DFB1F48A27165C8EE5C81AB4F9
+:10C0900063334E6E7A02E3019AFF25EFE4DDB7A821
+:10C0A000FCFED7F9D54837C3B9DE331F01CFF5A160
+:10C0B000027A2F73FDA720F13E8CF8A4E5E1F6FA91
+:10C0C0002C0B92F911580DF723CC85CD9E047A598B
+:10C0D0006DB5C7C0C7EE1671412DEEE710713FC7B1
+:10C0E0001895FC7EE6FE56570BFF779172338E0F44
+:10C0F0007AFE6A9A5F90EBF9B287DFD78B713D9435
+:10C1000053DE6D22DF7E3C3F773E77EE3F29983F3E
+:10C11000E9B5B01E8CB3AA8030983FE9F8A98DE844
+:10C12000ACB8A08EF208AEC5F30C00AF509FC5703E
+:10C130001E615E81DB50D6D1B1218F52D33BCC79C9
+:10C140009478131CD2B5539C9732F381BCEFAD5554
+:10C15000301F3915E404E5B51798F32AA3CA86E120
+:10C1600089BCCAD49638ADAF42E4553AC71BF16FCB
+:10C17000F5BD3CAF328C7995DE8178AB02DFC2F53C
+:10C18000BA61BC64F9A6DE149E57D102F04079ABC7
+:10C19000A317B15EA3BC6C2AAFA4F31F67263BC4F0
+:10C1A0007931C9B0FE4CA5E330CA956A587F2CC9D5
+:10C1B000FADD78239E4EBE2AC27FE09657A8C85F5C
+:10C1C000BD739C5E8A8F9BE46B96584715AC23D950
+:10C1D000394DF3BA424A9715F59AA7AA85DE14603D
+:10C1E00001C4C783E57794505CD46F61A80FB4EEA7
+:10C1F000D841E712D5EFDA82749F206B5F8EF597F6
+:10C2000049995CAEAA12F931B4F5B7167714A0BEFD
+:10C21000A008B9DA7A79F3C5785F56EBCE51328649
+:10C22000A6434A5E13AEDFE5B34A885F5A1C15E5A4
+:10C2300007CAD3563696E4E9E926C6ED86A592B03C
+:10C240001B9430C2B506F427C4EB25BE28E5BBBA63
+:10C250008157139CD1661E89714646C197A505FB7F
+:10C26000496FF1E6D858FAAC441C36DDD21344F8D5
+:10C2700016B11ECAC35AC2BC767C96B020DD53529A
+:10C280000E0C8FEE0361EDF4AC641DF4AC663D76EC
+:10C290006E67C804E75A3FBF5FA5AF3A9BE87BB122
+:10C2A0008B117F6F0D74A6D1BD9E43C48536493C6A
+:10C2B000EEA3022FC27BCDFBE3CBD358C40AFC50C4
+:10C2C000F90F26E9E5BF145BC6E346C580B2A319A2
+:10C2D000FBA89ACB1BF6AD608B739C90D3D05FDD2F
+:10C2E000187E0F9BC62F3EEF79CC39BD32BF277227
+:10C2F0008744FE9339E8CF0C50DEB4A2BF7FF28DA5
+:10C300006A1E677FA39AF3B5525B88EE03C40BDF06
+:10C310009A6663BE4B09954BEF04198D79F21F4F56
+:10C32000A7FBD0DE0E934C85EF64FAEEADCF0E8EF8
+:10C33000403157E569DAEC9507DACFDA7876C13F14
+:10C340009D35FDF120678DCEEF525D3DE0FC849B75
+:10C35000EA0F18FDC5663E7A8DE86F5EEE21CF3498
+:10C360008CBF8DB6107E9BDBCD10E3972CE07F5FFA
+:10C37000E2B803F005D635BEE6A15B506E8598BCE9
+:10C38000391DF9C6A67B6F095F4EE35F5C83FBE254
+:10C39000E2F2C2D19B3C8F2CBBC6A1AD279BDA7BBE
+:10C3A000F87C6B047CE6C2B0726622FE0274A7E5DC
+:10C3B000C34DC4F6211651D10FA28D5B8C17199372
+:10C3C0003CDCFA04C6230E20CD68F167C0FFAE3412
+:10C3D00051AF7EFB16BCD7C2FC3DCC6312C14D8C65
+:10C3E0003309151B1867428D80AF8DAF47F377680F
+:10C3F000F78769FBB56F39B7F7CDCFE1F8FD8CC48E
+:10C40000FE687E79333C326AFAFDFD19040F71FE35
+:10C410002503E7C1E1741DCD4FBC1F3A0F85AF3F27
+:10C42000F5C4838D4DC9FF7E02CD7BB5D85FF33354
+:10C4300071FFBC06B73B1ED79FAF29387947A3D001
+:10C440001B2A6AF47A80C8A7597C729D565F43F311
+:10C45000FEBFFCF714969DFCBAE6BF2AD1D34789EC
+:10C46000D847787F0BBD37FD9D85AA935FD3FC9994
+:10C470005FA175546BF7DF5FF8EF2EF409381DCB21
+:10C48000E1F4C5EAB99F29659C97B5EACEB77E432A
+:10C49000B403BCFD068EAFDDEF8E3CD0A28BAB3873
+:10C4A00076737E83F7C5EBE3359BFBE95ED95CA32E
+:10C4B0008B1721BCF5FEB0D644BB566C37589CE8B0
+:10C4C000819A017162B1BFBF20BAD1EE93DF5A7376
+:10C4D000E209978478B57DA305E9DBF6F247782772
+:10C4E0001EE60BE8F1F081047C1F21F899F294CC50
+:10C4F000FB154BD07D8CDA27F27192F2895D3536CF
+:10C50000ADFF5DD4BEFFEF32C435BF5E10FD7AF3E0
+:10C51000EC3115EFDF9B6797822A43FFC645C505BF
+:10C5200050764FCE998A32E4FF08FAD2FA7D6E41F6
+:10C53000249DE2DF7831E354F473F07BCED32B38C3
+:10C54000BD0D462FEF89FD343FCD7F67E1FB3547B9
+:10C550009FD0FF9D851D35AF4EC13CA3841F4B75F9
+:10C56000E17D6E9B9E8B58549483532C24E75B0291
+:10C570009FE493FE817B7C8173D277AFE7F7B4FFB2
+:10C5800042DC83A4BD7FA526C7B0BFAEC295E42F11
+:10C590005B64EF187EA17B4517F98D7AED46DF5776
+:10C5A000E81EABD3DAFD4D63DAEFC3F399CD5D56E8
+:10C5B000B641C6F1636FBE3721917F7168B4233EE7
+:10C5C0006F3A9E23ADDB857AD32F607E787EF1C3F0
+:10C5D0001A2E2F5D3B9E6232C0C735E600E5F33967
+:10C5E000625207DE5F5DEFDFC6D0AF9CEA8B115D64
+:10C5F000A457707EB9C80F84A7D3DF60FF0FD4E8BB
+:10C60000FCB207045F64E76EF4613EE9EADD12F90B
+:10C61000A5F2773731BC4775B0F14ED570F9521F8E
+:10C6200080713D386E878DFEDE43E2EF4E18E4A543
+:10C6300024F8F85D09FE7C17CD43FCDD89BB12FCB4
+:10C64000F98FF4DEF4F73306CBEBD3FDFD8CBB6A38
+:10C650004624FA392FE63758DC18EC1EC7726EF7FD
+:10C660007C88F10CCDEEF950C441D817CF839525C5
+:10C67000BD1FC394E7EA08FF4839887CF07769F268
+:10C680007CF45B9AF26207E6C1068FE0B9C1363FDF
+:10C69000BF9768A83CD8C3E171640F1D067B400AB0
+:10C6A000927DAD621EAD765EF82FC88325FD743E87
+:10C6B000D801C9F360B93D942FEE73392CF2628131
+:10C6C00067F4EDF4621EAC9DF4EAC3B3C6C4D04770
+:10C6D00062CE833D8E7E168073E1F03ACA879DEF6D
+:10C6E000E1F9B2408DC3315F0FC618CE74F6CEC9E2
+:10C6F000B1116E3F89BC741DFC1DE7B393C0DF16FA
+:10C70000A1F5DB2C4C7EC43B10DEB0E19BCBA72710
+:10C71000E0833FBDBF03F302D14E72302FF7539930
+:10C72000E0EFF6C9851857463F34748AF757328CC4
+:10C7300037A51E4DA1F346DAFE6BF3718F6F646867
+:10C74000AFFCE3BFA5C9787FADDBE4D71A90F70C47
+:10C75000FFEFF78B25F1730DCC83FEDFBDDF8785FF
+:10C760001E58306C956B8578E279FEF5826F140C5B
+:10C77000923FF86571FE90FEBE0ACE673FCFEB9CFC
+:10C780009CDA1345B85DE93A7510B7B7C33B2D7F06
+:10C79000988C798691BB97639CCB97D7968DE3DB7A
+:10C7A0003A7330DE34F936EE37ADF673FB1F246C86
+:10C7B0007C24940B1A25F6888CE77565DB28789F16
+:10C7C000DF98B7781994EF5F6EF4BFFCBDF3B6ED58
+:10C7D0006F7FB511CF7301BFBC96FC91593C9E7D14
+:10C7E0002DFA95381F7D14F95BCABBFDE7477EB86B
+:10C7F0009CC7C30263939C1F49E4E146946A3DDFF2
+:10C80000349D7F5712FD5FADD70FAF16FACB8C5218
+:10C81000E5291CA7FFEF036AEB93F8BFADF63A05D5
+:10C82000E3B3A968954C47BC9004BFE5F04BE4B373
+:10C83000C4C84FDCE0471713FDFD989F61BF000F90
+:10C84000825F718005D1BE7407643BCABBA1EF5FF4
+:10C850002E35DC03617E0E76FFB25F9CC73866DA48
+:10C86000EFBFE1DF3325BA31FF3DD3F7C5F98FFEC6
+:10C87000FE4CF7C2FC66B9314EF545FF9EE92BC56B
+:10C88000A10F091F5C0AE555BFB358995C3BE34211
+:10C89000E700BEFE647D20217F2FADFD19F9B701B1
+:10C8A0000E0ACF7FBFF0B8D696729AF755DD964440
+:10C8B0001C14FE3FBB27D5A02F5DDD9B69285FD3ED
+:10C8C0007791A1FDBCB33986FA3C7685A13EDF3570
+:10C8D000CD502EF45E6D687FBD2FDF50BE415E648B
+:10C8E000683FF9EC4A9AE795071A0CED72E35F315D
+:10C8F00094C35F8A64D6C2FE4C3B7287E1FB199DEC
+:10C900001B0CED0E96CFC9C0F8A6969FEF11F75DF0
+:10C9100059DC632E41FEA6F9AD34388DADE5FE1825
+:10C92000A72D4AF7E56BFEA6817E9731DE0FDCA2CC
+:10C930008CE7000B3EB38ABC7696319AE292DE64B5
+:10C94000F809FAFA47CB75FABBA6AF7FB49CD3358A
+:10C95000E0C524C40366EBC78B2BB03CB9D688FF77
+:10C96000E39728BDCBB99E94544EB7A29C0E0E946B
+:10C97000D3A065CB9CDF98E42DFC24BD7F57C85F16
+:10C9800017CA5F94F7E169A47F01B0FBE6E3197C65
+:10C99000933C3F1CFE1143BBE5302C464A267FBD2D
+:10C9A000F52AFA83BFFA519A8C7E0CBC6FFA20F2FA
+:10C9B00021D0C7F07CA4591E335BD08B71E8F42BD7
+:10C9C0002D4CDC677E41793C947EE616FA99761F01
+:10C9D000F61797CF87F83DD13E4D3E0D90CF24BF3F
+:10C9E000F385DF76A07C5E4571AEC3B346D1FDDA38
+:10C9F0005F543E6BF75A3716296B101F6EADFD9FC3
+:10CA000021FF74F90C741FB0D90E3C8376E0F0BF9F
+:10CA1000DC0EFC27418F7FBD1DB8DD857CA0DFDEED
+:10CA20001B1325BBB039DB42F7DF36A7F1BC0BB5D2
+:10CA30008BDF63ACD9810DFEC82EB41B1BFC1D6CB3
+:10CA400022EC4303DA61A8E7C5EA9E453B4CB30FED
+:10CA5000A32BACDC1EF33F407955AB851DF8D1F21A
+:10CA600041EDC01CB27BC673F99DA3D93D9ED8256C
+:10CA7000E83FD7EE79B915959D1998DFA9F27B5E4D
+:10CA8000B2AF93F4F7BC0C66DFC76BB9DE667EBE4F
+:10CA90005A61F4E3A13D8A7CD47CBFCBA9DAB47D92
+:10CAA000285F401F791EEB07D347B4F8DEB3B59E6D
+:10CAB00035E25E9BFDB53ABD643F2A3A33069FE7F7
+:10CAC0006B625EE6A7363F6B0D137E9D2B3AF23C00
+:10CAD000897CEAF195BF7F52DC4FD359ABF3330E1B
+:10CAE000967FAD6BFF2FFAF9FD8B981FBC3F51ABC2
+:10CAF000F3FFFDA579DEDA38BDFD71E9B47D98F765
+:10CB0000FD39EEDFE9AD9D91F003BE5E9BBE06FBF5
+:10CB10002963AA385F95CAF0EFB494793BBAF93922
+:10CB2000F4CB65FE775BDADFE6F7CC8EA1780BC637
+:10CB30005FD09FF699D0CBCBB473FFB608E5CBB4EA
+:10CB40008A73566DDAFC544B8742718EE004E4DB45
+:10CB5000AE9ED428C6554F9BF289FBCF9DABD551D5
+:10CB6000D4435A07C937FE2FEE36CF2E008000007F
+:10CB70001F8B080000000000000BE55B0D7454D50E
+:10CB8000B5DEF767666E92497213020E18F426043A
+:10CB9000186A0243083F02CA0502E40F99408080E8
+:10CBA000A037214050FB1C405A9ECF3E2E24867455
+:10CBB000821A2BF6476D1D28BEDA2EAD23DA56AD4C
+:10CBC000AF6F00A52E126AEAA34AFD798D1411B544
+:10CBD000B55045F1952EDEDEE7DC9B993B9904FBD1
+:10CBE000DAAED5F55E5CE17AEE39779FB3F7FECE2B
+:10CBF000FE3B2760AE883617039C167A6E8100C014
+:10CC0000F346EE17E56B00761700C008805C23F74B
+:10CC100071732640F7A2E0A7374EC677459D816025
+:10CC200009C0A737E2FF0F05587C3A22810AE0EDE0
+:10CC3000BDF0076522B6817F07E6855B6348178AEA
+:10CC4000717C26C045FA99D5FFD9BD48FF8CE87E96
+:10CC500046F4887E0D1F8FEF4FAFC0F6E915FCBD7F
+:10CC60003DCFE506C4CA0389F36446752FC092DC44
+:10CC7000C0682107A010E76DBD16DFFBF93A93E706
+:10CC8000CB34F8BA919FAA1509FC54ADE87B5F64D8
+:10CC9000E013427C1DD7C9133B47E3BCC5BFDEFE92
+:10CCA00098176532DD8F7DD301D27FFDB55BB61756
+:10CCB00001FBD187015443C2CF14ECA767016F6A0F
+:10CCC000D8AFD0FF8CA27FA22F1CCA03B87B717A89
+:10CCD000288C743FD20FCA20026440440609E9043C
+:10CCE0005C70C2CFBFBB88BF197E6C2BF1B6E297D8
+:10CCF0001DFD2409DD6E4BF4EF4AD095783B5BDADD
+:10CD00007E4500E553BF55FAFAC92128CF03DF72EB
+:10CD10006BC86FFDBEED2E83BD77B3F7B67CC2DB6B
+:10CD2000004EB8709E952AD787D7F0917C66B9CD12
+:10CD3000B541D2E7D6CEC0E2047D5619021B87FA70
+:10CD4000AA22B9ED5FA13139CE0219F45C54E7A4EF
+:10CD50003F5F4EF380D9A7D745346EA187EBEFD064
+:10CD6000AF4FDC6262FFD1C2331294011C2F04D892
+:10CD70008B3882D6CE406DC23CFFB14264F35C6713
+:10CD8000703CB8CBEEFDAFBC3CA29BA609A8EF72ED
+:10CD90000831F9B9111B80EFDD3E2162A2FCDF13DF
+:10CDA000B8BE004AA33AAEDFED2D7B47C231BB7B54
+:10CDB000274595C971DC3F697C7C8B3C328EFBC773
+:10CDC0008D8F1F33F3191E6E3012707283859F256D
+:10CDD000851C6F7B7AA74515DC2F4BDCD63CE635EE
+:10CDE000511DF7CB9274F30A403EEEE9D5A3F270E1
+:10CDF000E4CF6DE3757988FAED79BED3BB204AFBA9
+:10CE00006B71450308C87FB90F402A88E3FD67C9E5
+:10CE100078871B2DBCF3F9361837B2EF93DB7541D9
+:10CE20004E6F3ED14319D4A9B61C402730D669BCF9
+:10CE3000FDF5DEC9A176A4B7B48E8F5F60CDBF14B7
+:10CE400070FD2AADBF3C245F7DE9F5A39C3AD8BEB6
+:10CE500029E37A3E2D407DB4B8FFFEFB962132F9DE
+:10CE60004999AD6060BFE2033DE2ED3FEEF40A8117
+:10CE70008D9B7CBD85C369367E8237337D04B83E89
+:10CE80006EB6F471D46D7E91F0B9BBC05C1D4C9848
+:10CE9000F70983D3B9C71093EDCB3D067B6FD9B1AA
+:10CEA0007EF2B7E50D31B045C7F45B167AC9FBB920
+:10CEB000ECDA065AE7060BAF7D7C58F33F6CA86CA2
+:10CEC0005E28E77CF4F55B6DE4F3478CCF3E795E3A
+:10CED000D23EFFF9C604B9FCD9B2CF430C27DD47D7
+:10CEE000EDB6651F3BF5469DF6DD4768F1A4890365
+:10CEF000F373CD991171BB82BFB3CE17C6ED0EFE91
+:10CF0000CE86AB1CFD7395498EF63C758663FC029C
+:10CF1000DF5C47DBDDBE0C74B443AD166EBCA0BA5B
+:10CF20006B717D6246FE150D28EFD72DFD25AF0BE9
+:10CF30005A5DBFEBB5E914D2BFABD453570108A07B
+:10CF40008B1733985C4AEB87C6E5525A0F96BD0A99
+:10CF5000BE9D88D7766BDE641CD5D673FC9CB7EC7F
+:10CF60005C6D3DC76F028E6AEBD97B4E77A104A141
+:10CF700028E1A347D71627F89F3782733E64FA0447
+:10CF80006812A658FE00F7E0D1515044F62ABD18A9
+:10CF90002262017BB2FD00C7F1FB047CFD69259F85
+:10CFA000FF8DA0FEA79593A9CDF57B3A0947E3171E
+:10CFB000EA7F62F398F04A11FA9D855C3470BF9B5A
+:10CFC000DBC5F7C609911D486AE1BEEFC9E5A8F7C0
+:10CFD000C3BA720610F3F767E192695ED95480EC28
+:10CFE0007C99EB24C955C7FF48AEDB97A5B3EFDFAB
+:10CFF0001F0E110F7E3F069ACDDBB11D9EE651C973
+:10D000008F55817CB2D7D637F2D1EE6F8418D23FDC
+:10D010006778436447AE0FB9E2FDA46F1AEF8F8FB4
+:10D02000FFFEBEC51B887EF3A31E8DF61FF9A1D897
+:10D030005866AEB216A2BC6A2D7901A877DE8E744E
+:10D04000AB7C1284C9D697BB4E105D05FFA37586D5
+:10D05000B3423D2EB2FF9A08DB918E3B2204681D3D
+:10D060001B8E49810AC2E5BE3D7221F66720DF1E94
+:10D07000FCFECA62C3EC45BE33B6F69423E890CFFB
+:10D080009B621E1C7F7AA20097B1D5194072AD2910
+:10D09000E3F3F4AD3FF2EE9B90C5F83E91C8B71BA9
+:10D0A000769D95C633FE4E24F2B7F5CD5F8E7F2177
+:10D0B00001EF131B32F308A7500AA5E4A77FB3EDD5
+:10D0C00019F8ED686C4BABB2C95FE2F6D5198E204A
+:10D0D0000A84A3FB973DA734A25E3EDDD633FE054E
+:10D0E000F4CF331A382EBBD71B331A86C671925130
+:10D0F000ACBAC9AE6A70E6D045E4E37D1F44C238DD
+:10D10000BF6785D93E9DF4754C4268909C4C089051
+:10D11000FD8D7DD5AD21CE9A7D9D6EF22B1B64D801
+:10D12000E1C2EF322252643B4ED14D7A405FFDFDA9
+:10D13000E2903A1DDFDF84DF8BA887B98F62671921
+:10D14000B3DF110FD257028242ED1AC4B1865DCA15
+:10D15000CC1F992477D0E450F634F2D7DB6393B038
+:10D16000BD10E5AE231EAE43FDC412E31C049E2594
+:10D170002FF122F96C537FA5684A425CA521A56175
+:10D180002457FC294CC07301303CBBE9FB043D54DF
+:10D19000EFDB69929E6D7C4331C7B38D13C473205E
+:10D1A0004678FE9514F068713D2B4938763F8A7AAF
+:10D1B000467D2E0C24E3B74FCF2707D3F33F25E955
+:10D1C000F9FB32303C76201E4D9CB763DFD32FD164
+:10D1D0003ACD7D626034FBCAAC27BE0C1003618A75
+:10D1E0006F6202C82887EB2DFC77D4465D8DF8BDB1
+:10D1F000B6F98A00F9A38E921FBB1A705C47411ED4
+:10D2000064908F17F5038DD85EFD9024D0BE643FE7
+:10D21000D4BF35271216187D37E9F7460CBA88BEF9
+:10D220008DA74511818DDBD02A307D3642C04DF16E
+:10D230006A1304D9731D84D853806293F4BC3224DA
+:10D2400004C26CFDFCBBDE7DE21EDAB7FA0C57CEE1
+:10D2500029941385A2A9FC489FDDC6F8F05442DC4E
+:10D260003A0632B97D3104B6CEFB7FD032AF3C8F67
+:10D27000F9A51EB21FB327B6BA68DDCA4C17D0BED7
+:10D280009D75219BE1CD5DCCF1ADF8A20C6FCD88F1
+:10D290003711C7F7206E750FC3D1AB4509F1793F40
+:10D2A0009C294E5CE17E2BBF13E75D41F645ED8F77
+:10D2B0002BF498AE2F913D41BBC6EC8F852B11FF0F
+:10D2C000235C351B9DAEAF937C7525A405C88F7577
+:10D2D000CE77D33A4D011EC0E12B0C278EAEBC7029
+:10D2E000ABBE96EC3FD9511C6FDCE18AE3097FBDF0
+:10D2F0002E0C00B1BF1DE73303FDF1D6EE0F32FF58
+:10D30000EDAEC135603CEAD65B9442DA770199E133
+:10D31000E9BD5A485727E0D315F5DD8BFBFD4003E7
+:10D32000F75F2F97CC3F4038F2DE2F32791E229CD8
+:10D3300066C4717AEB722B4E5030FE47D5542FD411
+:10D340000F37907F5B147CA981F953BE5FB296734F
+:10D35000FFF3EA1CD31744FB71EB0AA73FBAE68C34
+:10D36000981437A427C50D431CEDB9CAE54971C30C
+:10D370002847BF67A42C12BFEA1E2942785BE073DE
+:10D38000C61D9E3D521AD9F11FD5015BFFAC319DE0
+:10D3900057901F7F6F34FA77B2F3E5B2795916B31D
+:10D3A000A76A438AF8F4B98A86771A2627DAD398C7
+:10D3B0008BC6CD014326FC2F0093E5199528E0BCD0
+:10D3C00002F2B7C607248FF2F2DAD63CDC0FD5138F
+:10D3D0004AF2C97E7B17067FCFE484D696E447766F
+:10D3E0009C9E9F541A67E93DADC3339EE84780C6B3
+:10D3F000DF8D6A21BECCE94AE41186B35E477CD951
+:10D40000B39CDB7BFAF9C7CE37F75C417EC5CE37DC
+:10D41000DF3FB001C8BFD4FBCC41F3CD1717E9B94A
+:10D420008DC8DFC64A7D4823CA5F5E181C4A6DF06E
+:10D43000DAF273C6753B05482B22791D95028F6081
+:10D44000EF320FC65D09FA1CD9C8E3C5D2462EB724
+:10D450008CC812D0270D6C8F3A4468A6EF41F23287
+:10D46000FBF65649F15EC297DD6FD3E9C3456C19EF
+:10D47000A3B7BABD8EC5AD57353AF74FA7BE9FE9E2
+:10D48000F32363F0B8DAA663B7DDB1DA41D7E9B6C2
+:10D49000E2CB43CBAAC408D9755FE15EB2D71D3E8B
+:10D4A0005127FBF9F19BDA5EC2C11B0D3C5EB471E2
+:10D4B00044F6ED8E5280A9E78BC14CA0FF63CB4EA2
+:10D4C0003EB34D61CFE7B6A9A063DCF5FC361F6B18
+:10D4D000FF6C9BC69EB16D7EF6FEE0B6006BBFB0E2
+:10D4E0006D1A6B1FDEA6B3F64BDB2AD8B32FDE6DA9
+:10D4F000D0789E1EAB63FCB823FCA9D33EB0E219E2
+:10D500002345DE87F1CCD246C7FEE3F1CC47FBE6EC
+:10D510002E9AAE91D7C034ACB4FF777227D743228E
+:10D520005FA6C59769F1655A7C99165FA6C597698C
+:10D53000F1655A7C99165FA6C5173DEF5EC6EDC929
+:10D54000D1429E1F24CF7F62B968C5E7C689E588AE
+:10D5500093ACCBB796D03E8347758DE47F6239306C
+:10D56000FC2CAF571DF9035C58E3A3BC335D039556
+:10D57000FCDE5C2DE2EE45FA37F9A340759A9BF28A
+:10D580009F8989792C8E8DA6E1F0BD3772B9361747
+:10D59000DFCBE3355F542639F6D1B5ECEEA12D058E
+:10D5A000BB448A1344384371824CBE0EF3F88EC7D5
+:10D5B000B7B7133D90302EC2FCB123D3531F21DCEB
+:10D5C000AB65AC7FF5B551DFE2147AC18889CDDB5C
+:10D5D000E1E276D41E7FC8D5338FE6E928D04A5BD6
+:10D5E000D1FF7C30B2C745B83F748D26EE40DCAF2A
+:10D5F0002EFEE4066D7CFCFB43D6F74BC704F26BB2
+:10D6000013E4F86023F74B8746F33CAC5D5BEC22F8
+:10D610003C878B5541CA21BCFC40A53CD01E17B7A6
+:10D62000D7C6838D09ED747F8CD9198008C3597AC8
+:10D630005DBA4971DAF16A2342E3D215E96DB2BBF2
+:10D64000E9FE804CB8FAA492CB13549C6C38CDBB45
+:10D6500057A1F7F3A43B1EEE453E8EA2B9F76057E3
+:10D66000961864F1095C07F0480ED1473F846D8F2E
+:10D670005F62F1C751087DAF97D66B7A54B38CECDB
+:10D68000DD4763C9CE310780F6789965AA3F4DBB67
+:10D6900081D111BE04AA80F2FB4646965FC6F656BB
+:10D6A000480F505EF56529544276FB53B153A3E70A
+:10D6B000EF1B0B18BFAF056EEBA4F024ECFF6E3B25
+:10D6C000F9F74E5DA6E8038E978B15911478FC59F7
+:10D6D000A3977DA756EA6789EFB38D1CBF77DB76EA
+:10D6E0000EE36937FA8D362222B255BE4671D2DB7F
+:10D6F000D63ACF5A72BECEF7E01BC447AEAECEA725
+:10D70000B86815C645119C7908F4D6909EAF0F48AD
+:10D7100014A20E68AF6A7CDF79E3E424262F3B8EE7
+:10D72000122F4E8DC7553A862414C7CC38DD179773
+:10D73000313F73CD19677BD679677B36B81CEDB95D
+:10D740008AB33D4F75B617F89CED4ACDD986561E63
+:10D75000972956BE0B897196C49F7D7122A4C86714
+:10D76000EB4EB17C30393EB3E53E909EE6572E3C01
+:10D770004BF6CE96F3DD42A86736F9B5E162E011CB
+:10D7800084E62FA60D493312BE73ADE17EA8CFFE0D
+:10D79000FB4516AF77F81767430AFAF653393F038C
+:10D7A0006209F65191ADFC529E346912F2D54E0BCE
+:10D7B0009612E7E1FA57CE5FCBBE9BB3E736B6458C
+:10D7C0006A8E496C3E3B2F9F0F0C4B7DF9D8918D93
+:10D7D000BCBE50D369B46E62F5340934CA437C1EB2
+:10D7E0008825E4E91994854A94871D999786E3BAB8
+:10D7F0003231DF463A73553ECE96AB52FC93D86C2D
+:10D80000A4FB8BD9CA19611A7DE78EF753DC4F79D7
+:10D8100058163D9DEFED3C7A207924E769A3D65850
+:10D82000FE7B2A4C257D9F83992FCF86785E6E7F65
+:10D8300067E7E514B794BBE2F953E99A1C2B3E8BDA
+:10D8400098645F33342D108641FD5CE99A147E6E36
+:10D850006D8D31650DD269F3157A89CE1C01CE48E4
+:10D860002AD14977131D0CCF783E374D89604A1174
+:10D87000CF1F2318EF6B8C9D67D2A7B075B29F673F
+:10D88000AB0C9DE8B55BFA59F93517AB8BE317B9CB
+:10D89000545F6BCF324F535D11CCFFDCD8EDB3C674
+:10D8A000B162E7F736927FB1DB556BBACE529DBEBF
+:10D8B0007D98D92CE0F89CA6599BF2C85E528D1435
+:10D8C0007F1F3C69EC37AD7A05F9B58C268DC75DB5
+:10D8D0009A687AB2E2712EF2574B7C1FD10E1E9DD0
+:10D8E0008D438CBA2F1C2339773D7E60D56594B764
+:10D8F000B4A012AFC0FDFD6D99D7F18B78BDA96BB7
+:10D90000E23780EC1EF2DC3B1AE74F0BF6B8483EDC
+:10D91000130A30E2BA9AEA879CBF15F910D10A803F
+:10D92000D538585EE4072BEF6D32634C2F722829EF
+:10D93000AFB3EA0DF06A51629D29292F4CCE033D09
+:10D9400045C3E6913DF45D2E810771896060F6C0A4
+:10D95000CE03BD10D277D0FA310FA4BCCE53243BF6
+:10D96000EC4546DD4DFA5AE217F33E0FCA3D7D57AE
+:10D9700014A692DFA0FA088EAF6F72DA978C629EBF
+:10D9800007CEC53C504A91071EAFD66F27B98E759A
+:10D99000F5AC22BEBB400C901FEADAF7747729C9B8
+:10D9A000EDA13E7C30398D7D47B5E422B2FAC254F8
+:10D9B0008BEFAEDAD0DCCD385EB7EA0B5D251E36D4
+:10D9C000BEEB3D3592C1F7FD814DD89EE1B3EA0B28
+:10D9D000182E52FEA1DB7243BF4BF5B79998CF5377
+:10D9E0007D6191DFD2C3C7BC4E1473834079BF5DA4
+:10D9F0001FB816E14D7EEE0E0B2F02F84D9A6F4ABE
+:10DA00002FB0FD3376786417ADFF80EC0A7033DCFD
+:10DA100097473DB02605BE3C2B8C792C6E58853C33
+:10DA2000E730BC3DCCF0AF48F3294F08FB0BF3685F
+:10DA30009F6560D847DFFD4BA3F15D8BCEDB89F995
+:10DA4000580BA6477C1FACDDA4CB649739CE3F3D75
+:10DA5000B16323E15C839E79C457B786EBC4793CFC
+:10DA6000133777527DA2AB4C6279D8B9E243770580
+:10DA700090A5EBEA9E7C11B709AC8CDCEBCAC176B1
+:10DA80007D5ECE9D143ECC552447FDEB96C7321CDF
+:10DA9000766FDDEE218EFE1B6EBBDCD1BF3438CA43
+:10DAA000D16E7EE82A477B9E3AC9F1FD02DF0C4722
+:10DAB0007FA536D7D15E5251ED181FCC3F2BE76AB8
+:10DAC0004C7E3F275C55ED1398FCE64C3ED43A4221
+:10DAD000E37122C5C11D99511F9D2FDA71A11DFF50
+:10DAE0007514185376E4C4EDDBB93592237E4CB639
+:10DAF00087BF5DC3E3E7A5855123557CDD672743D9
+:10DB00008239763CCFDF1B53E6EF8D6F39ED6ACC5F
+:10DB100045E3964EDB787818E9A1B996C59574E689
+:10DB20004D716579532D6D73985FBE91C230583435
+:10DB300073BB6C24DA318A1FB358FC789AE8669478
+:10DB400061FCC8F0C6E3C7AEE22583FA997730EFEF
+:10DB5000A0FAE95B9877D0F318E61D54D77E17F347
+:10DB60008E18CB3702AC7D18F30E7ABE847907BDD0
+:10DB70007F05F30E7A8A4DC0E4F2F79E6735F232E4
+:10DB8000A294D505DC4310BF55FE27F547A81E48D3
+:10DB9000E7422AE35F6922FEF3656B9F70FEFBE4B8
+:10DBA00094B40F3FA9D4BD4DB8AF96C91073955E1C
+:10DBB0007A3F21CEF2887E98FC02C4FD42DB965F5C
+:10DBC000BE39228FF2182FF30B4787BB79BE62D97B
+:10DBD000B1B47C6D2FC5DFB3BFBD1BC80FBA413BCD
+:10DBE000C1EA834D3CFF75B777327BB4E27999C5C2
+:10DBF000212658F62820B0B8FD1FDD2FD4905FC82D
+:10DC00001BD82FB8E1CD79943FFA4641C073752AED
+:10DC1000BF106C607AB3F4D560E189714272C8E7D5
+:10DC2000F553B7B689C981EAF559542F0783C94D11
+:10DC300046B9B17542BFFA3CABAB5E6DA9C2968BDB
+:10DC4000878D708C67EBB8BAAEC26CC0F90ED37911
+:10DC5000D034D257B9B99DE249948387FCC849D9D9
+:10DC6000514765C7AED85F6DADAFA63DC4E4320382
+:10DC7000E5427A947D4EB955EF0A31FF381DE9939C
+:10DC80009CA6FFCED9EF49AAEB37345975792BDE24
+:10DC90001BEB8AAD26791CB5FCE6D17DC76A26FD53
+:10DCA000057EF3686D48FA7282DF3C3A99FBCDA39A
+:10DCB00071BF397BF3A07ED370FA4D1FC769C6C709
+:10DCC0003CFE19C86FF6F397259176DA07B6BFECDC
+:10DCD0006AB2EA027911768F63B52832BAABC7030C
+:10DCE0003BDF39A83CC5F6B922F07DEE19F9748CFA
+:10DCF000F20F19E36D8A3370DFEFA47D6CE367B533
+:10DD0000CCED44821FEE60F8EA1FE7DD4DEF0F6AAD
+:10DD10004579B48FEDF835BCE549C77EEE1A67EF5B
+:10DD2000E763770A3C6E2E0D4FC4F973EA36D0BA1A
+:10DD3000324AC6944A281FAFB59F6D7B87EB62F6C7
+:10DD4000256EE7F9FABC846FE217D7F931CA37CDEF
+:10DD5000525DF796278F27CEDB3171AA5285FC1DC5
+:10DD60003959BB5F2EE86F8F565FDB934FF5ECA3FD
+:10DD70003901A50AE572A4A96EBF3CAEFFB89B6F3E
+:10DD80008FB0BA777878C0A2B72CE5B876ED951742
+:10DD900049EE8B0A2040F54086A084F3D92A88B248
+:10DDA000FA720DF4B2E74FAB8D1F93FCD283DB8187
+:10DDB000F9DB2DE7BC03F8A59F32FD24D9E5EBABD9
+:10DDC00083FFDEC4F639AF835CCAFEE28F3F6398FF
+:10DDD000236F384C74578AFAB0BD74CEA0FD3193CE
+:10DDE000E85E928E8FE30CEA0D768E05A21808236A
+:10DDF000DF0F5718BF247A08784D1D46B8E5B817CD
+:10DE00007C873F1370DDAF8A1093288FC972B3FAF5
+:10DE100077B27FDB5859F92AE7477513FF0DFEC328
+:10DE2000C7E9BB06C5CBE430F03D80A070119F452B
+:10DE3000BDEFBD44F8C23D7286EC99E27FE525B2A4
+:10DE40009B1F817286CE975AB2FE1B52F957CF792B
+:10DE5000C95157F450FE67F91FAAC3E71023F47B9A
+:10DE6000E1A2447CA5099CAF116B395E73A689AC15
+:10DE7000CE9F83803C91607F18FB769D5E209C3A0C
+:10DE8000FB9599E64681F8D2FAEAEF2F135F03F982
+:10DE9000FFBFF57327D5E5470FD2EF0E3513EE8B95
+:10DEA00020E4A3BAC057FD6372C30975209BFFF03D
+:10DEB00052FB5E4144A17399705169360C12C72818
+:10DEC0009DB50E79F7EB17C14875AFE84A6BBEEC0C
+:10DED00099217354199DCFF0BCB9A84663EF3D65F5
+:10DEE0003CBEF7E49B2CBEFBC0AA77BF63D5BB2921
+:10DEF0006ED2D97D0393D98F313D5F61F5BF732613
+:10DF0000FA3FF20373787DCFDCE1515BF2A86EF744
+:10DF1000AFAC7FABACA81E56890B4D25DCB76FE3C9
+:10DF2000E7E5D89EC0DAAE503DC9C903ABB313EFE5
+:10DF3000B34D5E6BD557D47FB3EA636E167F537AC9
+:10DF4000CFEB4DF92AAB47586DC5AD9A5B08BF239F
+:10DF50004596F7838A667F0AF707F4132E78EC9BC1
+:10DF6000749E670E4D67FE4A02F914F9BB7692253E
+:10DF70008ED7BC0698F47D8DC8E31E99FB973BB302
+:10DF800046B0F64EFF1C76EF4383A042EBBE2F6FE8
+:10DF9000F07AD23DDBF8FD8C369463CCD3BF5F9D25
+:10DFA0002DA7D1F96D4B9EC8D6883E2C487A936632
+:10DFB000DFC6FC629BBF702FF9B536BF9826E2FB27
+:10DFC0002D96FEEEF48A15A9EE83D9FD1A8414DA93
+:10DFD000FF9DF98B07C55187A5873EFF1008E9CC47
+:10DFE0007E69080DE4BB45CF15781DC4F0D13D9B7B
+:10DFF000C516FDB64C9E9F78035156770F8F9B3206
+:10E0000085D6AF1447E19497EE39C4E0B7F8BCF376
+:10E010000BEE66F25B6DAE4005D16BCB2C14CD04DC
+:10E02000BB75BB4DAF20F53DB8C6B5A2CD2F5B8FFC
+:10E03000A98B303A85DD5B66E1E43E6FA099C6DDD1
+:10E04000E773530D04DA864FF1138EDB4672FBBB88
+:10E0500066DD9EFDDB8B09B75F84B708B73E99E9A3
+:10E06000B545E7756A799C181152D0B7F17A17E96E
+:10E0700011F5A9284627C50FCA31095A80EAE06F71
+:10E08000C6A8CE18B6E2B4E4EFD392EE71B4643D04
+:10E090000054AF53ACFD17864E55C5756595A53B2D
+:10E0A000C6D9DFBFD564DCB736C18FA7158580DF41
+:10E0B0005FE17A768F1C1C87C9EB6F17D0C3E4E24F
+:10E0C0003387EFBB96AC74765E1C1E99BB27F13C80
+:10E0D000EFA025FF4BD14FE66F203E1E4FAA1396AF
+:10E0E0005875C2647A81755C9FE12D1B8F8F288BD8
+:10E0F000C7233B290E627147C4B738613DCFD9763B
+:10E1000054E0B80C233EF7A758EFABD6B881E6DD54
+:10E1100062F11BC7AB0884D7B6028E9FD0DA27AD59
+:10E12000FA9DC9EC42362A90EA1A1F54183F27FD7F
+:10E130006497713F963D3320190EB98AEC1CFEEFAF
+:10E140002847166F044EBDB689D75D4CA0F3A69D37
+:10E15000547761F3EE6071FF39C427F971B9B3D711
+:10E16000FCAC8CF9E9D0038144BFBDAB87E2854BA1
+:10E17000ADC3035B383DFB7E07B9F684FB7ACA3733
+:10E18000B3CD8CF1097435B7E3FBBFB4EEFCC7B572
+:10E19000CEBA73C13499DD4BDA794C62F76B06A2C3
+:10E1A00063D79DE1CAC1EDE05D497630F99999D513
+:10E1B00023627002C3D6894FB5625E9669DDF3AD06
+:10E1C00038356633DD2B4DB6271A449454F7EA935D
+:10E1D000F7A17BDC0E86A37384A99CFF3D2E6CFD0A
+:10E1E0006F59FB9B4D263B9FCFE7F70A83C07047D3
+:10E1F0000125E5458229B2388F2554C3AC523C0B2A
+:10E2000032F1CD3076B4C7F4972CFFCBC89A3227C1
+:10E21000AAB2F58EB885E79BF9D02B501C7E252538
+:10E220007AACA4673CFB19D21BA9366D5C83A3C7EB
+:10E23000AD73EAED527AB7F595CCCFE3DB1481F0FC
+:10E240001EFE0AC6E9D84E8FFD333BF7F53C1D0193
+:10E25000AABFA75BE709F034B07B0EB32E2C520A9D
+:10E26000183E469526E2E389B5CEFB094F58FA6879
+:10E270005517B3753D91CFFD6A099CA9223EE179FE
+:10E28000517C24C5B9DD136B0B1C7956E0797150B4
+:10E290007DFC54D02BD7511C437139763694B95339
+:10E2A000C6E399E9212398EA1C449853BB6E727F18
+:10E2B0009C01DD52413E4BFC3C5EF95BE12D6F9DC4
+:10E2C000C6E474693B7097BE87E8515D28108FD310
+:10E2D00092E95D2A6EC3B891C589E60E195ACA58EB
+:10E2E000DCC8E2C8ADA647A57365EFC4DB1EA67601
+:10E2F0000DC691946F7F590A65CE45BDBC26862612
+:10E3000010FEFAF6A9784099847C7DF5DD999B5B37
+:10E3100071BE5D94DDB3FBF85F7B2A86B15C97101C
+:10E32000CBA7F1EE49B085FD9D861CCB4F8C37BB4A
+:10E33000267A56A7C2E7B7D7737F344FF232F97502
+:10E34000E55BE72D60885407F18C9358BC19BF1F1B
+:10E350008CDE059F5DFE255CDE35F80EF3D9B1C07D
+:10E36000CFC78FDC066A989D8F3BCFBD29DE3C333B
+:10E370002C9E8F3F6EC58F03E929FCCC0B6C9E96BB
+:10E38000C0535EBA0FD19D1FDD558AF4BB7F25C1F6
+:10E390008E04DC7767F2F8EAD0C49FC8A7F0F9983A
+:10E3A000858B2BD7F37A737514A543F77703B335B1
+:10E3B000E25F1E207FF8781DF79F595480A2FD313F
+:10E3C0005E6279A87D8EEF29D9CCCE65ED73F769B1
+:10E3D000EBF97E1BE85C77FFFA4CE7797BD2F97AA0
+:10E3E000435D738D8A327D7D9D1587F49DB3C7E6AD
+:10E3F00051BC34040CE6A7AF2F962056007DE7F5FC
+:10E4000076DD3179BE6A3A6767F70DFE7F9EB3DB32
+:10E4100072B0E568D79BDA7CB98EF373B79FD7A942
+:10E42000D6D61827C86EB9A96E42F47C1ACB0B1544
+:10E430003F8F73EE5F165653ED97E72A8CF7D6257C
+:10E44000D84745E3F74DBAB7EC71D4B58E4CE4F735
+:10E450006A565F1BCD4F8CE76C9C7559F15CD700F9
+:10E46000F1DC3516BEFAECA257B4FC6F7415EDB3AF
+:10E470006EFB7EB0AE6BEA94783D05EAD5189DCF71
+:10E48000C1A6AC00D9AD366B9FF9E46076AABF5740
+:10E49000693BC8EFE7812F218E29A47957A71CDF9C
+:10E4A000F79D45B7DDB2BF2D81359FCBFE3E5C6148
+:10E4B0000C594FF9B8CF697FD3B474C779D4ABB4D2
+:10E4C0006F52C87F6365E565EB87B23A3AAB7B363E
+:10E4D000F8D1DE503D6DA6DA4671538B003C6EBB21
+:10E4E000443DA83B2722D33DC5B9FE2765B22FD5B1
+:10E4F0004FA39DC874D809E6E7F6AEBB7D33C59D32
+:10E50000BB1E3AC8EC9BD92A44460B5477EA667A7C
+:10E51000C06D56EAC9EF3FDF63EBB99E617790C9E2
+:10E520008530CBEC6292BE84C07246F7210C34A4D5
+:10E53000E1C49F3185E4035BB93D6D0980F600B30A
+:10E54000A7A194F72007B9573293E4F4FA3AE0F917
+:10E5500086FF1517D5BFE2F5C7203B07ABC26FC3D7
+:10E5600029EA91D510B3EB900B88CE7568C0462090
+:10E57000FE5EBEED11184A38B3EEB52AF13A640DCD
+:10E58000AD5BB1EA908AC6EB900797DD24B6135EC7
+:10E59000FD12F32B881A66C7B35E96A81637204E75
+:10E5A000A2549F415CFDD0AACF4C945549453D4CA7
+:10E5B0008C39EF0FFFB0C25845F38E977B45EA9F29
+:10E5C000F04CAEA3FFFAEAE00DEBF9BD0C5607FDE7
+:10E5D0003FB89FBE42FCFD15FB69FBDF623FDD3F9C
+:10E5E000ACAFCEE7A53CD03D491777E3FA8313A43F
+:10E5F00008D58F8FA01F63FC043C11265C19D87DC1
+:10E60000D5EE92CBD8798A0BD59D9D1B8F533CE7D5
+:10E610004739EE2B253F3DAE90AAA6E067FB3A674F
+:10E62000FCEA393F86D139E2E2FB89F6B23483F85D
+:10E63000E5ED867C0BFF497A6F5056F1FB7EB8FF03
+:10E640002E1B9E82FFDDAA49F79B6C5C7820D0EEE2
+:10E6500091FAEFCF67AB8CE87A7EDEF69890505F48
+:10E660006F4233C2EF673BE345B5527F9DFC8BBDE4
+:10E670006F4B20907D738A38BDCF9F299B8BCB1326
+:10E68000E4D4961662E7F1847792C34EFBBEA6DC13
+:10E69000232E43FCA9C4203BB4EB61FB3733763512
+:10E6A000CB37A4E2804E7F1F9B591680C473F519A7
+:10E6B000F3E6BC48F8C8947B80E49DA959F7C6F4FA
+:10E6C0003246C71E175BEFFCFB3CBB8E9ABCDEDFFD
+:10E6D00058F9CEDB774481F2818CD8B36CBF64DC0F
+:10E6E00021B0FBAC6E5ADF703A0DB3E6F195B1B6CE
+:10E6F000E6E5F5CF0E73143BEFED2D16B3A86E389B
+:10E70000EB4276D6347A6FE543F63DD3E479ED7C7F
+:10E71000A8D7E4E7E84F14F37CE809F94C7AEE2037
+:10E72000758BE4FCC7931EEAA554F1FDF5FFBD9976
+:10E73000FE2ED663E5CB7F78577D9AF2A1858B8C30
+:10E740000F49DF6F8BA0B3F38C11C0E2C8869D5FC9
+:10E7500029A12B99272BF4D1CD28179F7D8E31C06D
+:10E76000F9C587EBC1F2FF992C0F3A67F27BA61D22
+:10E770002E83D96D7315C7713F7B056A8CFEFE270A
+:10E780008B70A926DA2BC3CAAFACFA6F3D688979C2
+:10E790007CDBC14A86035C56DC6E7C0EBBD562D145
+:10E7A000DF69D9AD36BA5C9EF7B9EC561EC941F6A1
+:10E7B0003AE5ABE43BF33094D7501A3788FD1ADEC4
+:10E7C0003CF9AFB75FB84F3FE47E024C614A8A7DA7
+:10E7D0009AEF9457870B9E1126E0FB392ADB4742BC
+:10E7E000F1E1CFD8794D1F5D0368FFFF0FA1ACAEFB
+:10E7F0006460410000000000000000000000000014
+:10E800001F8B080000000000000B53E16360F8510B
+:10E810008FC035BCA87C42F82989EAD1F17526065B
+:10E82000066666CACC00610334779C636760D0E4F7
+:10E830006660B8C2C6C06009C45C40BC8B07212FAB
+:10E84000C201A1BD041062FBF82877C7281EDA5860
+:10E850004D9881415104C19F27822AAF2E8C602F91
+:10E8600094A0CCAE4D40FD00C0E9C2CD80030000B5
+:10E8700000000000000000001F8B080000000000E6
+:10E88000000BDD7D0F7C54D599E8B977EECCDC998F
+:10E89000CC2437C9244C4212EE840402049DD0805B
+:10E8A000C1E27A13A3A6FEE83A5AEAC616BB03B23F
+:10E8B000D66E591D2DAB54D1DC90FF21C08808C104
+:10E8C000BF03A8F55FDB68ABB55BDB37A03F97F60E
+:10E8D000F9DAAC6B5975695F2CAEAFEEF60FAD4B44
+:10E8E00049DF6279DFF79D7333F7DE4C825BDBF73C
+:10E8F0005E174B2FE79E73CFF9CE77BEFFE73B67DE
+:10E90000FCA11A563B8FB133F8E742C68CCCCD9DA3
+:10E910002CC25880C9F16178AA6AFCC83AC6D800EE
+:10E92000FC652B19EBC76705FC8D9650F9F680CE78
+:10E930005819639E2AF92D7F2163DE508A25E1D57F
+:10E94000435F7CEFAD8166C6CC7DBEF82350FED21E
+:10E950001D57BD897D1C7EE0D1BB2E817E1FDE52FE
+:10E96000BBCC0FE5CB99C4D872C61E0DA7640DDED3
+:10E970009B7D72E61178F570EF956F32F8FEE1DD60
+:10E98000B2CE62F8AC2D6221C63EC27CD4BEEF810D
+:10E990005BDEF443FDBC34D317427D5DF663B21EEB
+:10E9A00066AC724261AC34379F47BAB2A7DEF6322A
+:10E9B00096E93A72EAED7A68AF24E4007CC776B350
+:10E9C000A647E0314F4DF2F2A82887981C003898EE
+:10E9D00029CA9AC6CBBD5086793CDE354EFD600310
+:10E9E0007505D4E33FE1FD82DD308ECAE8CF19F82A
+:10E9F000BB289D96D7353216338F38DE2F7E18BE52
+:10EA00006FC895E731E5DF27AC32CC6302FF01F830
+:10EA10009C37CAE7B168D287939E365F6B5ED6BCDF
+:10EA2000FFD4E677F84773BE87F4F1302B4AF891AC
+:10EA30001E7AD7D37A3F32CA68BDFDC927399D985F
+:10EA40004087F0C9A9B7F653F94B77C8F16E282F64
+:10EA50005013C145344F99E13C1684983106F02C8F
+:10EA600050E00974D225E82A8B4F18EF21F1D459D0
+:10EA7000EA4D1CEFD12D4C1F9610AF570D2F82720F
+:10EA8000DD6B1EB610E1CDFE56427C5AF4633DF5B7
+:10EA9000511FCB7E6466BAAA531287FD36BCD7A934
+:10EAA000495E1678AF0BB1C37E1BDEEB348D975DEC
+:10EAB00078B7FA9F86EF2D80EFD0747CBBD7E983BF
+:10EAC000E25F674630B114E691BEB28835221E2E51
+:10EAD000699B084D9F37D261B614F17E424A847219
+:10EAE000F3B6F0F4A73B7F4E07FB910E6244079705
+:10EAF00035349F9D0E2A27FEABD1C1EFC70F286783
+:10EB0000B3B3C8D93F153C607BC4837B7ED67347C3
+:10EB1000977EB20EE6E537830CF5E2B6975806E924
+:10EB20006587A2FF532D9477C465EC01BA31FE319D
+:10EB30005ACE5084D1B84B99563A5FCAF553D40295
+:10EB4000FDD8E0B0DEEFEA029D0B8A706797CA8CB1
+:10EB500085B9F7696F268AFCD6DC70DD6A760E947B
+:10EB60007FC7DEC2CE879B7CFA56E87769FC9D633F
+:10EB7000F85EF38F6F5D0F708CB4AA89AD717C7FE6
+:10EB8000DDDF30D0C3A1CD9F2E7EDBB63E235ED627
+:10EB900089F291295E02B2F17A6D3FAEB7C4943723
+:10EBA00024FCBEAE3C86E5B9924C72938D2B3F9906
+:10EBB00000BC36C07F676A196B62BC6CE16D67D3BD
+:10EBC00081561CB711E0611AC2C1DE2DB2C157DAFD
+:10EBD000616BCF1F2CB2829B0E889FCA863DDDF3EE
+:10EBE000E1FB5F4A2CAEB520BEA0BD6D5D8A6A32E6
+:10EBF000D2B5D0DF909857E598AD1EFE56D45DF59E
+:10EC00007909E6C936D8C64138616C84FF7BAD3ED0
+:10EC10002301DF8F8CB18C5F9A3E9F1165F275A442
+:10EC2000B7C6453EDD8C4D9F9F1B5EF77C8A6AD23E
+:10EC3000DDF3A1FF41899DD8AA4D87BFA2C1B74E80
+:10EC400046F8C69CF055E800F739D3E1B6E8F0BFC6
+:10EC50007569440787BA1A882EF6415987E7A1F7E4
+:10EC60003D9DA8D7746C0AE3DEF5927E00D76B8ACF
+:10EC7000EE24DE574AE27AEEB097B7339F659947A4
+:10EC8000009E811A4EBFA3EB16ECF7C47274312AB2
+:10EC900031EAF7E68B777D0CDB8FAE952554951521
+:10ECA0005E6D2DB6DFDBBE80F0339ADC75A81ECA20
+:10ECB0004DADEAAF3D30DFD642E3A20DD85F858788
+:10ECC000E1FA54AC7D55BE0EF9B7658E5614857ABF
+:10ECD000BFF633A487D18B393D544C96331DE4E6FF
+:10ECE000D276DF5B8897A5494EA751179D8ECE48F7
+:10ECF000A7916312F6D7CEE9F426179D1AF01FE20A
+:10ED0000F19BEB0FB46EB0D1A57B5DA7E06A05B8AF
+:10ED1000A06C9C3E0B9D26F71CAA6F9E994E57CE69
+:10ED2000CB481BA07E0FD2A996874E3B675F6FEB47
+:10ED3000F93DAFDF48203E5DF43A35AF3BCD8F99CA
+:10ED4000509F7E5A6188CFB3D1AB7B5E156B65D384
+:10ED50007F4E3EF8D304FFDE56D540F8A7D1EBDA5C
+:10ED6000FC7C66C17D7757861DF7A29C8C12DD0E58
+:10ED700077E9F41C11F4BB0B9B564C97ABDB657623
+:10ED80003DAEF3F620BBFE195CEF8E6579DB594F83
+:10ED9000C6BA69BD77205D9F4F60180CD6A3683551
+:10EDA000FCAB92CAD9601D8CEF9D2A1BAC0AFA9766
+:10EDB000A6CAA018182B583DF5BD5900ED77047868
+:10EDC000F9C7DDD156B32A579EEC2E6A35574DAFA1
+:10EDD0001FF68E6595264093F4BAD11870F46F60D3
+:10EDE000FF76F8D455D3FB1B0EF0F621B980FA1B41
+:10EDF00092B251E6114FE0A36F48CC688F62BF50CA
+:10EE000086F57861F49FCD9756DAC6317F6E6481BE
+:10EE10005F07E4748F9D8FDDCF6592F1825486F099
+:10EE2000643A8158D82BD82F8C5FB08AF773587A00
+:10EE300087F5D8F075B4FBDF4D840FD114027982C9
+:10EE4000A480728075703F0FF076E8B3407F211484
+:10EE50003100A71C8732D04DB1A1A6FC50D6DA955F
+:10EE600077EC746FA7EF7CFD15ADE6DFABD81F54D0
+:10EE7000829747FD9FB53FF1FDCC74C2DB2D931205
+:10EE80002F48402F03BE748F0C787A41E885B6F383
+:10EE90005B7EB00AC60D8C7BE3E87F06564F905C24
+:10EEA0002C02770BF1049651F642D41B31961A8648
+:10EEB000F2D392CEE58C928E26C2A8C72B59C606F5
+:10EEC00097D5EF1F1A6F00FF495C3F6B9DCF361F30
+:10EED00015E703A0AA389F66DB7C14980F8C3F24AB
+:10EEE000E693B3479CF3180E989D09E0C3B6C52D71
+:10EEF0009733EAAF5E2639A464A8BF11AF2E0F176F
+:10EF000083FE94B95F65E1455D9DA1FE0BC090C491
+:10EF1000F10A1A9CFD5AFD01BE993F86F8E6FD15DF
+:10EF2000207CC5D47F7E7C33C0F7D2E9FDBD27E0CD
+:10EF3000D9046098F83DE3E35BDF5BDF59FD58F3EC
+:10EF40009DD6CF2BC7A7FAF1D8D6DD8D270908D3D8
+:10EF50006E1FBAF1763678ACEF7E5F78CE362F37FB
+:10EF60003CC5938B9801FAF46E7C01F427DFA9125B
+:10EF70007D0F7772BD327CE462F2F7EE92334790F8
+:10EF80006ECC57BD0CEDEDBB500E0391B2D5CBE866
+:10EF9000BB798599E8958D33CBE1BD60B79AC040C8
+:10EFA000697866E0392CEC88B4717337FAE97B989C
+:10EFB000F62B4F9CE40BE973AD75137F6F44F9FB9F
+:10EFC000007F7F57FB5667FB30EFA7F8E25E477B79
+:10EFD0006BFCE85AB0B7F3D8D1E53EB62E91C77FA7
+:10EFE000DD22CBB47EDF44FD04708E0AFD541E4C3E
+:10EFF000AE43BC683541FD00E065CFD52B2AD7C3B1
+:10F00000F707B72F90D7035CBB646E47A5857E3B9F
+:10F01000BCBD5C42FFB8D8609282FCBB16A535F43B
+:10F02000EB4D7517C2FAA46466A400AEE29F9A572E
+:10F03000A310E8925B243F7C5FD10E6568F9E5E19F
+:10F040000BA5BF5F8E6546F276B77C792BCADF8150
+:10F05000EFDFDD83706CFA17680543AE54D29E145F
+:10F06000AD43495E7D78F05FD4CE0CC0B772A47F0B
+:10F07000FC1385446F0E7A38FF6DA0079BDEFFA658
+:10F0800098EFA898FF5F023AF2C9E5952A974BB02E
+:10F09000F4A91E80B7B89DCBADF3414EA1BDA70D1D
+:10F0A0003AE514C07D911DEE3F14BCCB501994E598
+:10F0B000FA03B9B7575E8EF0A43D38DEF98AC51F52
+:10F0C0004EF8B52D3ED35348CFB73CE7E48157CC3B
+:10F0D0001BFADB9FAFBF3FD67CA0DF1789AF3F6431
+:10F0E000BFC5AE7E2FBAED7A19E1DD6FCA1994ABB8
+:10F0F0000FFAB46003C64F8F7A281E06261AC5770A
+:10F10000DCE354A71739FC76F7B3ED966810E97C79
+:10F11000BFC9E3420FDE565999B4F1D57EC1CFFB8A
+:10F1200005FFFEA3E0937F90BDF4FCA1283F5808A3
+:10F13000F65D1E7E646CAB25DFE9D93819A2784AEA
+:10F14000AEEC7395799C21572EA4B2D9C6F9D0ACF8
+:10F1500064F11E1DD733C592008FBF8A999E7361DB
+:10F160004D9187B8DECB34027E14201495E4FBF871
+:10F1700097B1EC45DEB7957D60734523B932F4C392
+:10F18000745BBD05FF502C1D0DD9E4625FFD9ED759
+:10F1900031AE11D4795C56CDEEEB5C8FFA738B2FC8
+:10F1A0008EA69EAA9B2C09764350893319FDA31085
+:10F1B0008BE1FA045583C9182CD0A00CF007430941
+:10F1C0005E8E887A2DC9DB477979E8FD2F50D9AC5E
+:10F1D000E6ED5FACBF8ED67F48AF3D80EB3FA42FFE
+:10F1E0002B9211DF423F0F4AC937E532F4774D15B4
+:10F1F000E900DACD4123E44DE403C2BFF2BF913F01
+:10F200003C484FF87F2CA4BDB344D09707EDF82CB1
+:10F21000C55F06453C6704E3315EC47B264B7E65D3
+:10F2200021C73B98DDB9F80BF57324176FA1F2B82D
+:10F23000A35CA09906FA714A84C53DF07DA83DCD36
+:10F24000701DFD515EC6F5F317E5D66FAF6BFDF689
+:10F25000BAD66FAF6BFDF6BAD66FAF6BFDF6C6527E
+:10F26000158EF5BBE696379CEBF7C537FEEA8FB0F7
+:10F270007E7B5DEBE7E68B1F287CDD1EAA5E4FEBF5
+:10F280006A5E2D93DFFEE21DFD541E5E2B93FE3E53
+:10F290007CC72DB44F72770B2F6F50E613BF0D77DD
+:10F2A0001E38827EEA7B47BCE4FFD5B2F810C65711
+:10F2B000B6BFF2576C38CF784F60DC89FC35EEA7CB
+:10F2C00059EF5F5CB4A068C2869F6DC24FDB26FC1D
+:10F2D000B4B6737EAAA27CD8D17C25EDC7947838C9
+:10F2E000BF0F437F18A718EC52E98971AD24F47F52
+:10F2F0001F9493507EB84BA3E7B3A087F0FD035053
+:10F300009F85E7DD0D7207CABD47A11D961FEB0261
+:10F31000930AE86D7797FA9E427EA546E56F75459C
+:10F32000A99CE9D2A90CFE253DBFDD15A7F7DFE8B2
+:10F330006AA1F2F9F295D778D02F5D2D13FD54DE36
+:10F34000D17000EDE7D2989CC800BCA51F5718D219
+:10F350009FF57E4A6ECB6DEB3D80FFFB1B1482E771
+:10F36000FE946CB0FCED3E8BEDAA620AF5577593E6
+:10F37000624891BCED36221C8F34C2FC306EBE5BFD
+:10F380003667E8EF266C575F0FF0C1B8F5F728E64F
+:10F390000CFDDD82E33ED7C8E17BEE7539CBF2B7D9
+:10F3A000BB1DFB5B51CFE15BF186929D61BE26F6F2
+:10F3B000B7B884DB4DB07AAD180F9BB3562BC1FDA7
+:10F3C00096C5A5EC26FE7EAC1BDF17B7F3F74BB056
+:10F3D0003DFAEBCCD88AFB4A251DE23DB6A7F7895A
+:10F3E00017713FA974B5E847D865F75CC3C8BE2D4F
+:10F3F000EFD40EA84032DB4579CE5A7D3F9617FBFD
+:10F40000F9786597689204FC56DE9E9424E82F0CE8
+:10F410006519CA4B7CA9560579FE334C3E009FDE28
+:10F4200073992E4920D7CA3B78BBED5096A1BCC436
+:10F430009FEA4679A2FD25B403BA2FBB3C4EED8668
+:10F4400085FD13BE3C7908FB29EDD42555477AD5B7
+:10F45000E9FD9CD52909E567F9C3492908B2A60346
+:10F46000D40E860A866F6264AF3DD6F33AF9EBE5B7
+:10F47000095EF6294B0E9B603B2CAECC109DB12053
+:10F48000D31F013B62F1DC89518C5BB2277D14D71D
+:10F490005E523991E9C1F213418A6B2F993BF1D841
+:10F4A000416CFF551F950B3FFAC262DC477BEF951D
+:10F4B0008BE624F3D8DB4B1E03C3D2A6F7DD7EC355
+:10F4C0009CDE94A402BC1101EF20C27B3E63DFE905
+:10F4D000394EF0CE89F3F2CF3C7338BC35A613DE3B
+:10F4E00079E39FBE316283B766FCDA9D111BBCF3E2
+:10F4F000C63FFFD5E61CBC179C12F02AC61CED03C4
+:10F50000C01BD09DF0FE5795EF7E3DC55A1B51CED6
+:10F510007B08DF3F50F6759B219A9F22813DB257B1
+:10F52000D84BEF2926C9814D01BD16FD450BCEBF35
+:10F53000F770F9BFB88625D16E5A7CCC67969E339A
+:10F54000B39DB6781E4B61BB253599C3DB11AE3632
+:10F55000F5A64700874B8E05CDD2C299BF5B82DFEF
+:10F560003562BBD05BF6FEBF8FCA77F9D9D76FC7BC
+:10F57000223E9F1D01EEA7055536A895D8FC5CA13B
+:10F580000F1657C23C1A911FC6FEF906073F8C1D85
+:10F59000DF61E387A771DC32E48BB17FFB8A8D2FBB
+:10F5A0003EFA4B4E67C3027F961F09F8333E10FEAA
+:10F5B000263F30FEB6EEB4E36FF203E26FF2F7C31C
+:10F5C000DF1E9C0FD0FF9EF0D47C488E9F753E13AB
+:10F5D0001F783EF20EFB7C263EE07C267EBFF9DCE7
+:10F5E0002DE8E16EAFA007E56CF470E275A77C3CF6
+:10F5F00031D193971E4EFCD42E278B2EE4F4B05DB0
+:10F600008CB75DE02F1882F196CD365E76EE8D8E4A
+:10F61000F1B2F377E61D2FBBE4ABB6F156BDC7C719
+:10F620005BA8FF47454D33DA293E8C71B061683BDA
+:10F630004EFB133AD9D387173D3A8AFB605FA80E79
+:10F64000523CF1D0A2A32ADA4FDB572F23FB68B03C
+:10F650008B9DAC237B25FB9B8DDE1C9CC3AEFD3EAE
+:10F66000F77358E6FED3B088CBB8EB2DBB6B30CE2A
+:10F67000ED2777FD6185D73325558171CB709C9D32
+:10F680006CCC1337B1E0B2E0FCB0703D2FECD8C1C8
+:10F69000F856ED22D03D3B7B2FDDAAA27FD2BC2BBA
+:10F6A00081E5EF98976E6D97FEDFC37540B9C20193
+:10F6B000D7E3EC8AFF2FE07AB6F7530EB8B6999FDE
+:10F6C0009A15AEBD22EE36137DBCC5922568E70DB6
+:10F6D0009403DD8672745B82BE19DA938AE6A01306
+:10F6E000B549213B74A8D949575B141E47B39E778F
+:10F6F000285C3E84EB15BEE97D8D2F531FE3FD5C36
+:10F7000009F6D641EC7779AEDFB4AB6CF99FE88EA1
+:10F710009E998F65A7FFA94E16D07E616832404F33
+:10F72000F7FC06855F32D2E4137EFE820338654F14
+:10F73000284BFE7871A35EEBA17D311EAFEC6B7A96
+:10F74000D498E0F289F28450BFA35DCCDA79BE414F
+:10F7500041F66AF24B8350C694366B9CE206ADD5F7
+:10F7600020BC99D12B6D79108312973F961D53AC15
+:10F7700097EFC7F1ADFADF093C853C5C2E8FD4A62C
+:10F78000A325367C0EDD9161682FF7D5EF21B802F5
+:10F7900002AE800BAE20C205FD07DC70D5CD0E9702
+:10F7A0001B5F161EACFD85F0E412A697227E17D1D2
+:10F7B0007326FA1D11F4BB7D39C773FA020BCFE330
+:10F7C000B47F5EDC0178966C785EFE0ECDA750E4C7
+:10F7D0006115E27C22B9F99488F914E27C6C7C55BD
+:10F7E000DC02F321B97A227AA52D6EB553D0F71435
+:10F7F0009E57953BF6AF9778399EC31EAEC7B6D7D6
+:10F80000B20A3B9EFB5A7D64FF157670FBEF0F0D2D
+:10F81000D7CC78CED03304BA7315E8A750F362A6DC
+:10F82000DBF46889D8F72E42DC5580BF2CFA6318C8
+:10F8300094B7C507CFF3CA8E38E0D4FAE13F914EB2
+:10F84000127C7F1FFCB1EE1E80BF3CEED3873128B7
+:10F85000AA5CDC8DFAB3EC053F1B8E6388B4BDFB5C
+:10F8600045687F97A126B0FC296FAD8013D674053B
+:10F87000A51A32867CE8F959671DF6F3170AA378B2
+:10F880000C5B2921DE4F6EC6DC0E842F9277FFAD14
+:10F890009CF9585615FC0C738AACE1656BBE0CEBF9
+:10F8A000B9DC7A1BF9DBCFAE2E4AE4C92BFAC0FDD6
+:10F8B000ADB6956DFBD16E78A7F50BE26A6EC97F88
+:10F8C000BEFFCF7AC391770AA0701E3B8FE25A33F6
+:10F8D000E0C1BD4EB1490FC92F7D52A2E73C21D7EF
+:10F8E0006A845CAB9E2C25FEAB9A2CA6E7DCC9B9DA
+:10F8F000F4BE72B2829E1593F3E9199D8C0979B812
+:10F90000849E05C8B7F0F409FA094E7E84CA81C9FD
+:10F9100026EAC78ADBB028A72775F2A354EF9F5CBD
+:10F9200049F58C7139B96BA55E3B6CE7DFA61564B0
+:10F930008F86DB597C21AC7F58F04BD8C52F854290
+:10F940005E86DDFCD26CF18B5E61E7975D6E3E6E8C
+:10F9500071CACB2F093ACFC9CB6C14EDC45D1F5BC4
+:10F96000D064DAE45EDFC716103F87139C9F67827E
+:10F970002F22F87966F8261C727387909B16BE6654
+:10F980005E578EA791A6E788CE7C20163D60B76BA8
+:10F99000CB36460F426DE1B2771A5E84F1CFF52681
+:10F9A000BFE245FDC826E20701CEFB6EF8D768929C
+:10F9B000F4D51E09F9B6D0C7F71D762CFB59FC20EB
+:10F9C00051D938437E80EF9EF5DAF87DC75F05AFE9
+:10F9D0007E146AF55ED9213F6AB680036FB303AA2D
+:10F9E000369538CA951B2B1DED9174510E91130D50
+:10F9F000741BDD50EB685F1077CAA740C33247BD68
+:10FA0000157FF7EBE73BDA55207D97227D4A429F31
+:10FA100014D0D3A2CB02A4737B1E9AD027169E19B2
+:10FA20001B233D3214E374E80969D2FAC6E9F8EE03
+:10FA30005B7A0BE915BF586FBF6BBD55418F7EF7E1
+:10FA40007A5759EB9D76C8EF21373DBAF4F76F85A9
+:10FA50005E29107A655BEDD8EB68E70FD5BBE851FE
+:10FA6000C4FFE1AFBE509A19BEF059E1CBAFC73F1A
+:10FA7000383DF633E497B4C452B85FBA6D697F1667
+:10FA8000E1F5D52A542E3877247B18632A6D7C3F04
+:10FA90000FE8CCE383F96D3B67387B00DEF7AF0BF3
+:10FAA000D1FB427D9C0B454127A4924A905E9CF479
+:10FAB00057100FBAE883CB3BB32DCEF70796F1FD75
+:10FAC0008160648CB6BD820D7C5F2614E7F8DE5E33
+:10FAD000C1E33E058D3CEEB3BD82C771A01DC57D5F
+:10FAE000ACB2354F284743367DDBB7FC28E13D30CB
+:10FAF00015D7196298A76AC573024A96C767E23C90
+:10FB00003E1350C778FCA691C773B6BF7F90C7E37A
+:10FB100017F17A4F88AF57A8516B42BDC7B404ADF7
+:10FB200057A0416BC2F8F9421FA787CEA0711EE211
+:10FB30004D7F8DEFABF7AFE5F9A0DB2B5E8D627FDC
+:10FB400027759F86F9EBDBABF93CCD1F49A49FA33A
+:10FB500075498951A83EB5AE1B10D2DFC5E3DF7BE6
+:10FB600063B79CBB1ED1A7A4CEFB846DFD8F16246A
+:10FB7000C3388ECF97CC74433F9B8FF9E35BA19939
+:10FB800054B979E104C559AB34D2478CDBCB161D8F
+:10FB9000AB752C83741CC87E8CE613A86271B41BF1
+:10FBA00071671ED7C557C7B427B0BE8EB787BA03D3
+:10FBB0000512C633E306E147E7F851B01EE9B54A3E
+:10FBC0003B88F9263E95E38345591CF1E515DFFB9B
+:10FBD000A2BC1E63A9581E11F13C8CCFE1BA8ED88D
+:10FBE000E2779AAD0C7F1A304EBB530AC691EF47AD
+:10FBF0006259C7BEDA484CE2F6D0E917A36B6C78BD
+:10FC00001979FF3DCA937ABCBAB1A77D25D2FD828E
+:10FC10002292ABDE6C54CB638FF5773D56AC7867A0
+:10FC2000E69F7E4B1E09FBCEF21F008F3ADA996EDB
+:10FC30003CF635ED99C2E3C23F221EB7211EA51C3A
+:10FC40001EB721DEA41C1EADB2358F6DB13107FE8B
+:10FC5000B621FE904E4E7F2DBAC626F7B62D7D39C1
+:10FC60008AFBB9DB108FC0EF77FB008FE7839DA283
+:10FC700070BEDD56C7E248EF8A66B27CF168FF6667
+:10FC80008FFEB6CD1FF3ABA92398075DF49A87A129
+:10FC90005C2C4AFF2AEBC1F901BE1E21BA4B31FB95
+:10FCA000F801102E68572D8427DA5D5E3DE8B0BB61
+:10FCB000FC9B7DD47FFAFD6B75DC9CD4E424E5C706
+:10FCC000750693A33EB40F425C9E04421943223A48
+:10FCD0004ACA08F7CE23DE0CD2D146AF711FB6BB9D
+:10FCE0003976A203F178F3053233E1FD4E5DEEA0E3
+:10FCF000756629F99908B62FA3BC520BAE7B057F18
+:10FD00001FF11A07E9FB80FB7BD691CFAF3AE0E306
+:10FD1000764B1AF373A13EDD7A1DF1EB4075C332C9
+:10FD200094235ADBF5A3EBB05CD3B80CCDC6AFF986
+:10FD300024E10783BE5F4A72F86B3E9BBEF7574DC6
+:10FD400010DEBFE5D3091E9F92CA328A87C719AE5B
+:10FD5000DBCE0B38BDCF44CFBECD4F152BA5240F26
+:10FD600048DE22FDE03C7696717AB2E2EC3BCB387D
+:10FD7000FDA0DCD06C65AB9F9D65279CF2F682DF11
+:10FD80009C45DEA6B87CADE2741F70C5CF77BEFF80
+:10FD9000112A9B612E6FDD703F27F0E8966B9A2148
+:10FDA000F8AB01E41AEA876C05ED0305754BAE6507
+:10FDB000881FFD0D20D784FEC0F6C13AE0C718E9C0
+:10FDC000E36E82A38E8F5B2CEA559DF39B5FD5BBC0
+:10FDD000B13F8B5E4B44BDC5AF167F0F2DE2F8439C
+:10FDE000FEA43C82451C5F885FCD56B6E4DA00CAAB
+:10FDF000358CE32C4A3BF0383425D7EE76C8B5A1D4
+:10FE0000F7BF40FCF8F8FD5F24B9067606ADF39025
+:10FE1000379D57AE0D9F45AE0D4FC9B514D9159AF4
+:10FE200091E672AD11E49A84F10EC06333EE2709B6
+:10FE3000B956FF9C41786E04B926F432960B748E45
+:10FE4000C780C20ED9E55A7123976BC1068127C4BA
+:10FE500023C733C9B512511FA873CAB5C1A51C8FDA
+:10FE6000B84E88C7C1A51C6F8867CD569EB28396D1
+:10FE70009A0EB9363825D77A1C726D30B687E4DA17
+:10FE800020E211F443E300E0B112E51ACF13198C1C
+:10FE900073B916EC183330747536B936A0F3FD6DAE
+:10FEA000906F0CF1EF4F4B86901F24CF42428E2D66
+:10FEB00040398674D7985F8E81DC3A17F3C0A6E488
+:10FEC000960A720BFE71999FF3B7F5DE1BC9107F7E
+:10FED0000F548B3880CEF1175D1B3FC8FD338EBFAA
+:10FEE000F235BC7C999F9F831C88B1B6ED643FCBF3
+:10FEF000996EA4B7FA5BA2B5F0DDDE1F7A28B7834E
+:10FF00004C8B72C66E15FF86FA73EDF93C03688759
+:10FF1000F867A623FFEFBE3081F28CFDD84FFC219D
+:10FF2000D56C4E225CB7FE44D2FDB6753A5AD076F7
+:10FF3000997FF9743B6F40E831CBCE1B107ACBB27E
+:10FF4000F3065C7A6C209672E6D754DFF2A1ECBC23
+:10FF500001979D67E98B0194FF36FB72999FCBFF58
+:10FF6000338A712DAED7CDB15407B6BBB91AE47F31
+:10FF70000CE94126F96FE90FF7F7EBC5F7FFA81871
+:10FF80009FA7EF03EEEF99D03F1C2F458646DF2356
+:10FF9000257B5680BD28AAFEDACFE5A0FE4A675130
+:10FFA000BEFC2DEBC904FD5972123774797CE50C47
+:10FFB00095F5E767FF7E08F32D60DDB77569648707
+:10FFC000EA1B3E356B7B8B4EFCECD3D4CEAF9B064D
+:10FFD000D251B0216DC8242FF526416F062B473D25
+:10FFE0006FFDD99D45FB29082B746F1CDF3F658E83
+:10FFF00040397A113BE15F89727D2A2EC4FD08CF1A
+:020000023000CC
+:10000000DAA2641E79673D371F7BB7F4255BFB7B63
+:10001000FDCEB8CC49F614CB523C28931D41BA31E1
+:10002000D889E1E2E9FD9CEAFA69E94B982A73A4D0
+:1000300073D638941FFC5BCC47B3E62D57990CFD63
+:1000400050359E22E708ECC26CA070FA3CB6A30FB4
+:1000500045E7028E5D84F9FA675BCF9DC21FD82EFB
+:10006000F260666A37D5AF79B427DB88703D49FA0C
+:10007000EF24E017E35D45212621BEC197A37CAAAA
+:100080007024E1B0E3DC705AF39A693C25E48C8B70
+:100090009DADBD2FE25A4F973ED7C7A2AF7BD04F41
+:1000A000D2F8794345493D341141F717147533951A
+:1000B000BF3481FC6BFAB547D05E68837A7CFA5412
+:1000C0000DF3522D3AEC13F47BDCCFF39FF61614AC
+:1000D00092BCDC7C2C4C7951A7E4B4BA0DAA3C4507
+:1000E000AB29EEE2F134A530BFE4C2D317AAF6384B
+:1000F000C02FFCDC1E1B08F1FD8E0125A5A2EED24F
+:1001000099A1225D0C693C0F72A6F9AA55B2033F72
+:10011000BE4870D6F9F70ABFBE3710A77C7BAB1F6D
+:10012000490D101CC7FD92389779E2C533309FDE28
+:10013000904CFEE56068971A43390676361ECF1E4E
+:10014000544CB5E40F08D785A72FA778568FC6C89B
+:100150008EF687DBCC2CAE83C452F5184FD6949F15
+:100160004DE5D3027FF9BD8CF2D2FCC5B519D3267B
+:1001700007FFD0F862496E4F298CDB53FE40B25224
+:1001800045FCB45C66F4C2F8BF46FE2E43BB36495C
+:10019000FA3377EE84CB21EA0AF8A07552E1766152
+:1001A0009CCF2F8C2760A1FF229CE17C3C8AA04B36
+:1001B0005C61C625BE3FB58AF6A322014BBE7ED840
+:1001C000FED6527F9271173B53F001FA5326281E38
+:1001D000FF07EBEF2CF005D8FDD41F66CD9D29E578
+:1001E000FA8191BC0F105F9D6CE4718E1ED017F8E0
+:1001F0007EA02B4A4FA63C4BF23F84FB0E71DCC520
+:100200007B86FC48ED3B7E86E700ADB8BFB5CF07E7
+:10021000F6E65BF239183F72CA15B56A76B9D1575E
+:10022000B6206F7E544E1F2A2C66D38733B5FB63EE
+:100230003F7B403EC56C76B912AAA5434E33CDCB69
+:10024000D398E4C861096697AB8ACCF3177A42EB7E
+:10025000D524D9BB67CEA09D60D9749E50A2251F1E
+:100260003E4CDC3CB6F9935EADFF263CBFE78D6E9D
+:1002700030ECE701B7E2BFCBF0FD46636216BC7B12
+:1002800094E4E83A9403CDDC3FBAABE033ECAD46FE
+:1002900094B79FA175EE2F2B8FF9C98E1179DD6A66
+:1002A00088CE5F5B7478A8ECAA28C6ABFA2AAE8A1F
+:1002B000A2BEECF326A228F78E943D6760BFFDA78F
+:1002C0008B189E83EA8FD692BFD37F7AFE9C549E72
+:1002D0007915E0BD1F2AD911E2BCA30F939BA7E0BB
+:1002E000046B703086FECC110FD9F977157CC7C02E
+:1002F00038844F57E89C952F94A0F3D41DCD630606
+:10030000FAE3BE6428E9D7A6F7638D037F248C4FF8
+:10031000D001038BAF24477D5E38DC655F9D4CFCCC
+:10032000033E66A6274F7BAF5A6816003F7873EFEF
+:10033000351CB7EE95A5A467B13DC65D25E074E414
+:100340009F1CBD679CFB829A9CEBB716B9C11CA48D
+:10035000F8255353B81FE8C667BF4FEC0F2946274F
+:10036000C2D72B952C1B6E9EC50E880EFECA334B32
+:10037000FE5140F365F19CAB12499B442F9A1CBF80
+:10038000348AE38F8C23FDC193BE0F68CABFDAE9BC
+:10039000ED55D569BFF5846A678D6F60DC94CD62D9
+:1003A0001FF97CF124CF5B4D75CAA437CEA1792902
+:1003B000552FBF1E83F18FAB5CBF2A519F89F0B8C8
+:1003C000F59A1C348EAB80575F90F7E3EEBF34D8BC
+:1003D000F6BFB0BE574DBC8B7A6830B642E81D57A9
+:1003E000DC2219177C6D144AE59C6EF99F4C16E1CE
+:1003F000F2264306CA4B6FF30186F69056E9E1F206
+:10040000B2819FCFB5CEFD7A8C9FD239FFC255CE37
+:10041000F3BC1E234872D4EB3ACFEB1178F6B8DE6A
+:100420009F71E3B9EB7976DC76BF02BC32F2ED67FF
+:100430007F2FD0E60DE489CBD0D9C095483F294124
+:1004400067A087353CAFCE482FDCDDD540CFBD5D02
+:10045000715AAFFBBA5AA8DCDB6550795B57079538
+:100460001FE84A50D957D1AB221EF755A4F7E139FE
+:1004700049663ED9FE0AE0635F38FD063F69F538FC
+:100480002F8BF3B5FAD0C3ED985FB9AF9897170DDE
+:100490003DD16E02DDECAB4F5F2D53FBBB79FB6AA8
+:1004A0005EBF6CE8295EBF9497FF6CE8695E1679C1
+:1004B0008CAC6ACD59F673B97CFB160632101F5509
+:1004C00011DA97F1E8EB9904AFF69589FD1AD10F8F
+:1004D0001EFFBD228F5F61F5B336C0F36E7CF80A54
+:1004E000ED184D21FDBA2FF69F8327A0A40DC28FD2
+:1004F000F942FB6BC86F4823E01F5C1F789EF043F6
+:1005000022E97CF447FFAE97F0B554F40FFAE69376
+:10051000367DB321C0CFEFEC6B72CEE36CE35F8727
+:100520008EDE723CCF3BC17069FE4D4D7E3C80F942
+:10053000096BB3590C610E543D43FE8785AF99FB9F
+:100540003369FC14E2B72CD73E1437E8FB73033C45
+:100550007FE8814D6D44279F12F8B3CA886F949746
+:100560003E14CECD397CCE389E6693E3B5D3E99B5D
+:100570002909DA8FFDA4AA39D6FB225573C01708C2
+:1005800071BEF9A0F85AE9EAAFDED5DF5C577DC548
+:1005900053326B59064BBA419ED58E38D7D58F0F43
+:1005A000E359A518FFE27E8C4F4D92FFE011717A5E
+:1005B0004FBA89F4B7B50F8108443BCEA719642F11
+:1005C0000681A8109F2AE82FBB5DE6AD72C6B994DC
+:1005D00090D9EDE5FD66304EEDC3B817E5171884E8
+:1005E0003F25C4FD63CB0E44B1817A6CA8EE66361C
+:1005F00026BE9BED1CBB22F23430668672EC6CFE8C
+:10060000A77B9CE89AC4ACFEBDBB3D0B29FA3B36E8
+:10061000BA98F93B85BD63D3E38F0B3E281072D1A6
+:100620005F9566F638862F9A7F3FA52998FC5AC0B9
+:10063000A6C7D5DA2351FB77FDD67D188D9CBE4623
+:100640009AFA75BA774BC93AE48B455FFD785E1527
+:100650001DC4464107517E2ECEA287A97EE33CBE33
+:10066000E953B314DF0CA50F318F831E926C4D3804
+:10067000B75FF3A488735A76875F77FA6DD6BADFCF
+:100680002AF2374EDD7942C1F3C397677FABD4C2FC
+:100690007ABD13E07EF62B5D9304DFA93BB9FD71B3
+:1006A00079F3AF948B6C787937E0233ABE9CF17C78
+:1006B00038F0F6952B96DAE7C9F7BB2F3C5D44710D
+:1006C0008F578E7866E5F38F47AFA5FD10ABFC3FE3
+:1006D000E21EF2F39932BE1ABF5FDDEC91F37DEFBB
+:1006E000B6AF3E1EBD8EFA3975C70905ED8257BA01
+:1006F0005409CF05E3FC301E7979FC570AE6E39DE7
+:100700000DEE7F1274D287DF231EEE48521EA02FFB
+:10071000FB398A6BFA220983E7F5312EC7223AC5E5
+:10072000092F3CFD9714B7B0FAC9D195737EFD111E
+:100730007EDE8829498A3F7AA3B26CDFE79A697E18
+:100740003E313F0BAF7D88D73CDF59CF9EAE64B1C1
+:10075000523F73BDA78C9FB7F278E35ABE38857BB2
+:100760007C2504FDD9E8C982A3E72C70F4221C364D
+:100770007FAB2FC4E7DFA724F2C647DCE37A35E777
+:10078000B8A8871ACA855E467AEFDD742EC537A3EE
+:1007900041C6E3B5CAAF27D49C3FEB57FF9C6DB170
+:1007A000E59FFBAAA0DED15F8AE4A05FE7E793990B
+:1007B000BDDE96B7A6D648E4EF512E25E5C5B09725
+:1007C000705F4AA98B1FC471CF0FF278FFED81E4EF
+:1007D000F9C1E55CBE125C2C44F6BDAA25E8D0AF99
+:1007E0005ADB40F6330B45F2EA23F77EB8858F29B2
+:1007F0003973FADA518C1FF64B0D37E5F31BACE772
+:1008000060757714CFB99AD5FC7EC7297BD005F7E0
+:100810001541CECF00F715C1323BDCCC01F7407556
+:100820003FDB8AF4CE78FECA4CF682AA7EA558F940
+:10083000480E6F0181AF69F925D5CE7D87EDD5CE04
+:100840007D07AB6CF50B65E7BE83C82F51AB445EEB
+:100850004FF68BC49FFEAA14ED3BA84A96CED559FD
+:10086000FB0EAA3A46716E5B7E0995A7F61DEA9AC1
+:100870001DF3B939283BEE95C8C5AD04BD34737A74
+:10088000690F26AFC6F5F6D7F58F63D95FE5D42398
+:100890001502EF56F9DE6AB13FE65A877B3FC7F390
+:1008A000777BABE30751DFF60A7AB2E20EB03EBDCA
+:1008B000413B3F6A7C9C7B3FC7F721D986FCEB51CB
+:1008C000A13EE9588F99E8A5B663FCF5A4CE38019E
+:1008D000007F95701660BB42D1C3B81FB78DF17908
+:1008E000F8E58923B8DF7E4F61720FD24B50CB1AE7
+:1008F000928EE70C393C7D824E2FF69C567F82FB10
+:10090000E1AB6A8BF0DE8617829283AFADE710F819
+:100910002328A77ABA54BA52EAD48F16CEEA5F3E99
+:10092000D4A53AE4DA4375FCBCE5435B7625DA00EE
+:10093000057D913ADAC71FAABF84E1B85F11E32AA7
+:100940001AEB2D6FC675E2F93780CFAF20FCDE08B9
+:1009500087DBC2334910DBFC6B0D9DEE11039172F6
+:1009600022A3A1C831893FB44116CFEA84876F60C2
+:100970003F215D935125A81D19520D161EE0B3238A
+:1009800078CE37FDDDFA65F673BEE1024E5FAC91BD
+:10099000DF37C09478349F1D64ADDB7D80A746BAF5
+:1009A000F7D390104E8CB337DAE4C4ADC1E41184B0
+:1009B00023B2314874194964249CD73E11CF9698CC
+:1009C000FA5205D11BDFD7BAEF86A0A0378DF2B55A
+:1009D0005F15F46EA3B757F3D19B574F6691A4F7F9
+:1009E000869247B13E208D6918AF9CBB91D70F58B6
+:1009F0007971267B15E9A8D2DA1B659CEF4B1BF4B5
+:100A00000338FE7F8875298EE8986EC5F4D71E6B73
+:100A1000BD16D70FFD6EC0F3DCEAB12BD01E663FCA
+:100A2000F4D0FD271575CD87DA909F0DF504FAE116
+:100A3000C5EDE9565C6F15CA981757B1615C42BBAA
+:100A4000ACAF8BEFD39474A469FEA10DBA84CA60D5
+:100A50004A9FF8789CA932C2EFED93CA1FEBF6A12A
+:100A60003EFD22A3FB794A576728FE54D9E2D750AE
+:100A7000CECD8D4DD0F9DABE2B18DD6B5ABD89D79E
+:100A80009782D98EE3165F9FE0CA06FC117B7E58E1
+:100A90003092A4FBD38643C9FF08D2BE6B82EC4DD3
+:100AA0005F24837729B1B4D724BB4E5D9531109E66
+:100AB000A1FAABD83A1BDD870AF83EA35767462652
+:100AC00094A3CB5D48DCF0FD8E96DAC067D12E2C66
+:100AD00008D2BAD5B235069EF78CB104E5D5AA394D
+:100AE000FA2C28C03C673D4360AA1D9C5F812F29DA
+:100AF0005E9BF6B20A84235DEFEBA4714C7694AD55
+:100B0000C0FBAF98B8CC8EAF9B1A311EC6753B1494
+:100B1000E47EA87AECBB06E6337E7F5DC89030D4D5
+:100B20005C6866BFDD8CFBA66A4207BC8426BAB34C
+:100B30003F82F2CB9D0568B3821ECF92FD5A98602A
+:100B4000E031A25F9EC862FE32EA16A28B761EBF1B
+:100B5000067CC50A105F2DD92CEE8F95449259045E
+:100B6000E12125F53FEF80EF1F3AE2899BCCC637A4
+:100B70002C1EB5FB1BFA16759ABD40F71F87F83877
+:100B8000DE28CF53F189BC31DF549E4A92E7A94455
+:100B9000799E0AE67151DE57C4CA5389D3B96FEB07
+:100BA0007CA982F5CDB93C152FAF637D15CE3C9461
+:100BB000BE0AAEC7CC36D680F7C6F455249C793B26
+:100BC00092952FF10947BE499FB84FD02D0FBE5FB8
+:100BD000C0E3637D985700FD6FAB9033288FE149E8
+:100BE000E39F3C26919FB7AD3AD189746AFEA880F5
+:100BF000FC8543653E9ADFB663E183F6BC002BCFEC
+:100C00007126793B537E63ADF939F2E7B7450FABF7
+:100C1000E8A78C80BF32DBBEF09018A75FEC0B4ECC
+:100C20008D3FC3398DDB847CC47834D2A7279420D0
+:100C30007DEFABE2797F7E5C3F5C2F5C3F94B765D4
+:100C4000B7507E8CB78AE7C7587955B09E94F7E7BE
+:100C500055E25CFF8BF3C08AA8B7D6CF5AEF91322A
+:100C6000E7FA8DB8F2AE46CAB28EF51B995A3F57D5
+:100C70001E64D355E4278E88F3C6DFDFB6BFCF24CA
+:100C80003ED6E5E771DCA84C76735F2C318A726E34
+:100C90007029BFA7745B637E3CAA3A97E7D67ADDDA
+:100CA0001A347A914FF689739D3E999F43B5F09916
+:100CB00014F2E39902493C79795BE37A6B3F3A8518
+:100CC000F9ED73307B0E402CAF4B7423CB1F2D48B6
+:100CD000EEC27E4FFDF8F60A84C31F75C617226266
+:100CE0001C8082F2EFFA7F389FFC175C27B4E793F1
+:100CF000054E3DEF1BE4F7C558EB07EBA1E7E3BF5B
+:100D0000BEB2EB0CEE0FF1BCCD29FEAB9A5A3F936D
+:100D1000EC3991BFE6E63F6BBDFFD8EB571B4C7C2F
+:100D20001DE529534CD2936EFAFC539D1F33F7F700
+:100D3000F17C856BFE53F19B69713996A6FDCA8AD9
+:100D4000637E8ADF4784FD7F6B30F1CF88B78A0DE1
+:100D5000C22E1174CB126BA8BE16910BF37924111D
+:100D60003D90DFDFE7F1935361EB7C6F3288FBD876
+:100D70008FEE5E1F44F9F3E8E8ECF207E3DE287734
+:100D8000F60BF9731FE6D5D8E4D07D42DEDEEF3AEC
+:100D90009FD711E272A824C4E5EEA36A2288EBCDA6
+:100DA0005EBCFA32710F33C99FB9778D15CF367E8D
+:100DB000D546F943E5D17842E1089DBFB4CE379DD1
+:100DC000E57B2B7FE6C3E2E57E5CBF4AC0C3C86F0C
+:100DD000FB301EEFC916111DD66EE2FBD61583C976
+:100DE00061C6F1803BD6ACE8F457E9FCCC8111F048
+:100DF0004DC81F370AD781DD42A62BD0ECA38357FD
+:100E0000CA35D0BEBAC2C3681F6037DF3751E13F71
+:100E1000EE6F675B197765E85EBDF969D73DA9B8E4
+:100E20007F027655B5FB3EDF63EFD23E4C85EBDEAD
+:100E3000D50F8BF76521D7B9B2FF4B78BF4F190B90
+:100E4000D8F34AE74A2C81F439F76FDE769CBFB9B4
+:100E500054D025DB1C62C76D71D1B952B602E5FAD8
+:100E6000FE8D22DE04A63EE66978EB26BE82EB36D6
+:100E7000BAEE965F7E1BED95B29FFE19DA599F0878
+:100E800015703F63E3CD0EFF15FC804F8496E7FCA1
+:100E9000A4FDBD578AFD347614EF35D6C5BADE778A
+:100EA000DA43EB5A1FF530BCA7B67DB729A15D5DCB
+:100EB000BB99DBD5CC74AE73F5DAB88C0669ED0658
+:100EC0002EE7EAD7B28C0EEB55BDD9793FEFFCEB9C
+:100ED00053871E80FA3AB0C70DA097BADD4E7A98B4
+:100EE000E3A283BA346B23FA89831C2E9E3EEEA3C1
+:100EF000EA18DDA37C7223CFFBABD7535216E93738
+:100F0000194AA17F57D6E9BA1F98C5B7E23AB8E99E
+:100F1000D03DEE87A5B3AE903B4FEEF4D58F01DE0A
+:100F2000E6F53FF50F0B08C969D9EE1F5A7456C094
+:100F30008CBE10AE7F2222F6FB8C583EF99D3B7F83
+:100F400079C5ACF2BD34E1CCFB28EE70E67D04E35C
+:100F5000CEB28FD9CAB1DC38612BDE944CE9F6F100
+:100F600006C3E6EBB81FF658E8F24B22C0E48362F2
+:100F70007FF0B191ABFA5105482C48FEF5709D42C7
+:100F8000F2853547847F9C7A08CF310C2C55D830B8
+:100F90008D7B80FC1DF4AB488F429FA5E46BF27300
+:100FA00070A138F7B7A6BE67A959FD6B23DD4AE3E8
+:100FB0000650EED0FEA48883E9BC0C7CF06CC81609
+:100FC0001FF3625E533CE7175BE3CC84576B1CEB6B
+:100FD0005C522FD8E938BFE21A2D867911EC28F738
+:100FE00073A7EECDAB61F11E46F73AC568DFE7584F
+:100FF0008146B147710EA9B76BF6BCE02702C9FF65
+:101000008EF02A3E43C7BCBD29FBBD04ECF7109A05
+:10101000C1296EF7B1043DB539ACE92584A394C765
+:101020000B7BC2FD319C576F99531FCE0973FBEEAA
+:1010300058C843F3D10AF87E0253CD0A7B3C5D0EBB
+:101040004B56FD4DB8DE75DBFFF6E5C1162817B12E
+:1010500026BC427257BAFB920EA00F6DBEF8BE6A54
+:1010600086EFE7B3A7B17D65F8E69715C0AF368F79
+:10107000D38B1EDED58FFA485BC8CFFFB1667D7F6C
+:101080002FC03F7A4D399D072BFDF3CD31FCFD81FB
+:10109000A97E5077821EABC5EF70BC24CB325BBEFD
+:1010A0000EF8C927105FA18E4C16E35D9E105FD726
+:1010B000FEA9785648EC5BEA07ECFE130B3BEDDD2E
+:1010C0007E11CF9A9C984F712C2B8F41899A597B16
+:1010D0007E06D33A727E2AC6576B2EE374A41D890E
+:1010E000BC6D7BDFB74E25BF26BADE4771ABA305CB
+:1010F000C639E1E5047FC605BF1ACE037F2E1ED791
+:1011000058F4139B3C2A71C1DD8BF1B759F60BFAE9
+:10111000CA6F237F400EF37DCCFE752AF9F3165C6F
+:10112000D1B0D8170D99151447D34CBA47C26A9F4E
+:10113000BEE84E8ACF0C0793D508BFB7C3C8629CE0
+:10114000EC92689CD9DBF5C07C255BBFD67B16E5AD
+:10115000FD4E953B78D90BFC88F127EDA2D5946F15
+:10116000D827E2D318EF439FDC8AF7B9E703FC2CBA
+:101170008797E78BFF39EDD9A9FCD6AD0AC37B7001
+:10118000F616DCF925CC87DD6CFA358C0B9D0AD47C
+:101190006418ED9FA6CEE3DFA7CEA5FB1CABD2095A
+:1011A0005C1CEBF7975435457A5252B85CFAFC97C1
+:1011B0004F3E6842BB9F3DF36F0F9A30FF8DBF7B60
+:1011C000EFC1DBD13FFD4E4043FEBBF1897F79F09B
+:1011D0003618EFE7CFFB65B4F5FFFA89777F7C3BE4
+:1011E000947FF3CD8525A8AF2F1774FD8BA77F5B68
+:1011F000AE433F9BBE7DF11CB487373D7B11DD1FA5
+:1012000032D33AFEA28BDF079C934B199ECFFEBCD4
+:10121000844A8D5F5C3D87E41CE5C5DC80FF44FDAE
+:10122000933EE1C3BC98DF483C5FFB86B1F77D2865
+:10123000975E06398872EFC5AF1F7FF93628FF1C0D
+:10124000F428E673DDF8BCD7756FBF3957A67CC3A9
+:10125000EC5C8C07DDF0F54F5C7E41333EBD71ECFC
+:10126000FE4676A21FF5ACFBBB1B5F3BEEA37C45A5
+:10127000999DA8FA689E7A9628CA82DEB9F1A921BA
+:10128000CAABB971ECE76FA21D78A34B3FFF9C710D
+:101290007DE4D6BB37849D76F56F1EBFBA288B954B
+:1012A0005F2FCD2BCF2DBDFB37CF7E7256FDFE0BB2
+:1012B000977C9E09CFA702779A485F603BA734BA14
+:1012C000979EE75BFB145543FD726BF0CE6C12CA20
+:1012D00013EB4229E97CCAA36EC07D83CDA089515E
+:1012E0000E819C1F40BEBFD563BC9144BFF3C7B7FE
+:1012F0009E8B76D56EC1F7BBC3CEF8CA2E4137D6CA
+:101300007337EA5FA4EF4F32FA5D2FA62424FBBEA9
+:1013100035A93C909BF76C9FB8C46CE4F548DFD6C8
+:101320007B664E5C92B5E9076B5C6F849FD70DEAD4
+:10133000E2BC6E924D482BF0E763F89F47C33C1E1A
+:101340000172EB21E44355CF125F58FA14E595FD85
+:101350009E4BF77340C8ABDEAE24ED1B3C8339B720
+:10136000B81F01FC4C6680908F8AA05F18E7A90F18
+:10137000378E464FD4E328AF6E0D269FA3FEAA58A2
+:101380001AE9CE8ACF787C3C2FD4D21B563F592104
+:101390006FADA7E5FF2A251D0DFB717FA035CAF1B2
+:1013A000C412A4070F89F5017C939CBB4762269D5C
+:1013B000CF9354BE4E06D3B572EE87E3FC3CA02615
+:1013C00050DE7861E28CEEEF30E91940BAA3BCC977
+:1013D0002CC9C9E3617EAF88956F0C1D917E298A67
+:1013E0003309F97A77384EF7DF99EB98F64853AE20
+:1013F000BEFF0271BF48032F47131AC3F63F0A9777
+:101400000862304C7C3F27A969D8EE6841E20DC4E0
+:101410004F194B927DD10C4F9C47B91AE2FBAC9D02
+:10142000CEBCBE297A2D76E2ED27025FC7C3DC0F62
+:1014300047DAAF2C71E44333CC87B6ECAA3EB4ABA9
+:10144000626457ADA3FD8399ECAADAD4B971B403F1
+:10145000843D65ED1B14B727593EBE063E3B897C93
+:10146000E6F525928E7868398F8746193F3F1E2D05
+:10147000BC4AC298B6762EFB15CF73532E7DA58538
+:10148000EC94A7B1DCD32B5D4A76CF4704FF30EF55
+:10149000A559DB78DA79C21E6A71DA43A142CE2FF0
+:1014A0000AE20EF5EC2AAEFF142D457A15EC82F215
+:1014B00042C44FA1D08F06D7BF53E576D1DE2A377D
+:1014C000F2FA0FA13FBD8579F7CF5C7996617E6F07
+:1014D000AAFB7BC646B8BE17E7207B4272056E6149
+:1014E0006A779437F173B92D477428CFFBEB8838AE
+:1014F000B7C4E33F054CB3EEA7267FE89EEAE43E7F
+:10150000B4170C39A04935C4275C9E5DE3A373FD75
+:101510007BA4CCF87CA2E75AD2ABA34999E72DACC7
+:10152000F5D17DABA318FFC4FA04BFCF7767C326FC
+:1015300092BFA3E66E925FA0FF49DF9B5BFD1ADEC0
+:10154000DFB33B7933D59B209FF1DCC5F4732D9934
+:10155000EFE2EF4AED28ACE1F97A0DED47304CB6F9
+:1015600033AE901F1E5CD4AEDAF7796E29E47C6E40
+:10157000D5BBF1345218E6726D657E3C5ADF5BF5DF
+:10158000C1450AF16F6FF2D52FE3BAED5C7558BB18
+:1015900008D735F2D22AC4E31AD19FB1B97510F732
+:1015A000D3ACBC50AB3FF77AA2FF4F74D522BF85B6
+:1015B000BF4F03F446F5A378EB20D17BF22FB07E2A
+:1015C000378BAB31C0DFDE6B5634509E68C3C3DF50
+:1015D0009DCFC9A0CD218725832DA0F5086978FF6F
+:1015E00021530D8217D6BC04E5C91E6BFD164DDDD7
+:1015F0009B4472A5B081D7EF95E2ACDEFEBD61E8F9
+:10160000DA8A9C1CC484706305A35C47FAB338492A
+:10161000F49D938763540EB1717ADE5E584BF828BF
+:1016200062998E0512BECF0C2D80F1CA5A2271FB31
+:101630007E6D9925B7D638E5965B0EED56CD211C0B
+:10164000275A98F822E2A5E7332BD418F4D329F8C7
+:10165000CEC28B8A748CE3E0B9D762847F6D379EEB
+:10166000E78958FEA76B1C9C17CE73AE989615B7EA
+:1016700047BC7AE1BB8AEB793CAE8A8D931CAA61A8
+:1016800027E8A9A3E58447B08C6437EE0B05D83171
+:10169000E24FD994A53300F7AD859C9F00EE00B6CC
+:1016A000EB410587F49D9405FE1901B53B293F8662
+:1016B00072B5B350E77CCBC47949D50874D2791799
+:1016C0006E2FD6884FFCEC2D09E34127A31E86F42C
+:1016D00065F94FBE8DFC772EAAF5B725F4E741D802
+:1016E0001A452DE8CF8F4BB89F3BB7553D6192DC33
+:1016F0009CA0EF2BF0FB38C685668F435871C1B9AB
+:10170000AE78442E2E688B6BE0BC447CC6CA8B71CD
+:10171000F395DB4EFC5AE1EF177FFD65C0F86621BB
+:10172000CA2B912FD357765D34DF77B9FB597E3FB3
+:101730007FA3A7B5E9F508E0A9EC9BD7927E39F421
+:10174000C9729273F78678FC0DEC9D37701DE732F5
+:10175000394E79842EFB61F27325EC3A78FF60AA4A
+:1017600030CE7FB481F391754E84694637AEAFC5F4
+:10177000C76C5982F8C707EE3DD2A18A76868DAF35
+:101780000AC12DC0A7474B67F14A85C39BDB8A314D
+:10179000EE50C0461CFC32E5576F62F43B090A5B11
+:1017A0005244E7AA37292C83C099C6ABD1153CD542
+:1017B0000BFF44939A6CD105EDBF1BF08D6D9D4AD4
+:1017C0003BC05EB3F9076560A7D8CB733AA38EF62A
+:1017D000AC97FB093AFC877C76928D90FE76C79792
+:1017E000BDCCA438E4DC16BF96A57C0393E28655F5
+:1017F000E0EF509E40CA191F8CBABE77D3D3FB16B8
+:101800003D015B233D011EE2C8FFBF7ECD43F7943F
+:101810002A137EC24B25E005F1F06BFC10CAD5EB14
+:10182000189DE773E3C5A237F85F1CE1AA817EB279
+:101830008CF6A31CF30DE84EFC143438F1138E3BE8
+:10184000F1139BE8A679BF0CF3A6DFF36AD11DED77
+:101850002DFC59BFDBE7C65BD5F563DD389FE9F8A2
+:10186000E1E720CE86A7DA22279E4EB2170E619DB1
+:10187000A464AE467AF658F40C0A4B2DCFFDBEDABE
+:1018800083E17437FEDE9D09F4ECA9CCE1C74DF786
+:1018900055DA782B99D38DD526FE9E4A14DAD3FDDE
+:1018A0007CCB922EBD9171D8D1B9F37A603843B90F
+:1018B00012ED6FDB39B10294B344E7C7D919BA37D7
+:1018C0003361D2395A60583C67ED5557935F0764CE
+:1018D0009CC235023DDB5A44F108F612C603AD7BCB
+:1018E00082BC2CC5245B5C5552B2248F3DF7F33C7F
+:1018F00006A52DB515D75B12F97AEC7ED01BF6BC88
+:10190000F95A83DF1BC8E2AFD3FEB8F8DD68406840
+:101910003689F258CCF76CF3F46827043EEEE7FA08
+:101920008371FE05ABB91BE5D55C9C17C90DE32897
+:10193000D2A5B5DF53B53941FC1A9DEB617EA09F5E
+:101940009A143B4CFB01AE7D9F9ACD63446731CC2A
+:10195000BBD1F03E3527BDCC1F74FD0EA0E705E2DC
+:10196000BF93497E2FD65C171D557B7519FDA5CCFD
+:1019700020A3FB61E66D1997F0F75716887CA1F953
+:10198000832CBEC14667D5C9C2F806B0C91FC317AC
+:1019900015D3E9F00B45CEF8FC17AE585394857972
+:1019A00064CC0379F7FD1EE852E31B80DE9EEC8ACF
+:1019B000C637D4D3FE0E95178C8D67830057632FDF
+:1019C000C74FAC73623FFECE726C8B2F8E74988BB8
+:1019D000EB27B716C17ACFBBEDEFDA70DA8B7A93CB
+:1019E000AD68177F43367AF03DCBF0DF2F6BDC5CC0
+:1019F00015DF00EBB064730D3DDDFAA4FA6F5FFBF9
+:101A000087AE08FE9E37BF5764DEA49FF29FEFC5E6
+:101A100026F0BD6E6A6D2ADAD99B75BA0FE79E2251
+:101A20006E4FAE2932D2488FEC7A9E6763E167260B
+:101A3000BDF5A0C83B7860D3AB575C8AF16D8DDBF8
+:101A4000ED31C508623CE1B122EEBF4CCB734F5B78
+:101A500079EE868CF19FBA742BFF3D6C579E3B6EDE
+:101A600016A15EBF55DC4BD45694FC12E1410B3AF3
+:101A7000EE81B4F2DCABFFB63D8876EAC3EA049DA2
+:101A80009BAE9658CA6CC27D1AE7BAD76E8CCB282B
+:101A90009F74F304F9EFD63CD714259FC1FE6BD495
+:101AA000109563BD13E46759FB9FF346B9BD0574F8
+:101AB0007808F7FD4FA6B93B3D2F3D2661C8EF12D0
+:101AC000CFEA20BF07CCF8F3753639FD30EA2F682E
+:101AD000BFA0C2C34CE417213F41BC093BCF90518A
+:101AE0007E546D71EE43D50979B9C0B5BF5987F6FB
+:101AF0004D21D6BBF7A380DE6CFC62CDCB9A8F9BC9
+:101B0000BE7F60C9D939AC02F7F54FB255732ED6F6
+:101B100073EB5F0382ABC5766FB845A7EEF896D539
+:101B20007F53D639BE84F7C24778FE03ED63C4CD38
+:101B3000AB291F47067944F688D38E97922FFF165C
+:101B4000CF2BFA3A4C4947FF7A7592F223A21D2C0B
+:101B5000AE43BDF15ACCE4F77A8D5F80FB41A5AB73
+:101B60004DC987FD578D5F8074FC6E5148E4351B6D
+:101B7000EF221D97A29C267BD9B25B52F45471BF11
+:101B8000683E9EA71963A62767BF0C16257F8DEBBD
+:101B90006FD9313AAC1BA60284588AD66721FA0362
+:101BA000783ED1256F0B5CF2D1AF24B3EBF5E9F3AE
+:101BB000037074FB7ED440357B1EEF4D97AA60DE28
+:101BC00085C8470AED73FC1FE344020E0080000045
+:101BD0001F8B080000000000000BE57C7B7C54D5C7
+:101BE000BDEF6F3FE69584644F32498657DC490864
+:101BF0000408382480E1D1BA0988885407B48A8F50
+:101C00008F0E88CA2324315AE5686FD92134C5E084
+:101C100095F8AAB107BD0315D42BF13340C0D40603
+:101C2000CE801403853628025ADBC67AEA41053293
+:101C3000C42ADA728FF7F7FBADBDCDCC2408FD9C2A
+:101C40007BFEBAC94757D6ECB5D7E3B7BEBFEFEFB7
+:101C5000B1D600A63ACB5001D6FE70AB3F5B03FA7B
+:101C6000896AE558BF4602980C50AC0D59639660DE
+:101C70007DAEA84FD07244FD16AC0F0228A7E769CD
+:101C800000B25B93C33E00B74F0E2BF900E7B26B77
+:101C9000DD80ED7E36645E46089F7F433F57F62D1C
+:101CA000EB57E280237ADBE5AB0103B09F9FE1DFD6
+:101CB0008D52DFF66A9A0CD1629E277C83FFAD1DA0
+:101CC00033D31881ED158098120070AE50F47FCF99
+:101CD000C2760FA81FBAD2011AB05F9A87D35D03EC
+:101CE0001A96AEA6FBA212B6073F0436712F21B892
+:101CF0007100CE1B44BF0F62F90DCEBF22232469B1
+:101D000013B05F2D05A2EEDEF19C2B9CDCBF44B22C
+:101D1000C2E725E3F18FF1D86F0002300E4B3D2A68
+:101D2000EB38F7921543028BB09D5B0D4200EB8EB2
+:101D30005935409FBBE6040D1ADF350B023A769108
+:101D40003507660CC5BA6318B42812C9D184E5D822
+:101D50006EA286FFCB0678C4634CA4799458E34DF9
+:101D6000D2342E0102527000953540E59A8CE01471
+:101D70006AA70FD1566137806F8384F31A91066189
+:101D80009223B65B15C53A6E754D23F5B55E3DD50C
+:101D900065AFAB40943011E74125AEDF89FD4221AC
+:101DA000C9A589CB14887099069D5C66401797A9D0
+:101DB000B05EFB3815E74DFDE07A1F771ADEAB7099
+:101DC0003D0DBF730436E202CD8A9AFFD585E39AB2
+:101DD000AB54A8C7F2D9D49FBCD485CF57982ECD89
+:101DE00085E5394F5E18709F36AE84C0A22280E729
+:101DF00057BA038B7012FFBA52E3F2D5957EFEFC00
+:101E0000612DDF5A77CD15C131D8EE015C09BEBF17
+:101E1000EE83D161290E27EB16C1AC4809E108F128
+:101E200088E3AD2D5EB8B991F03872618A133FFF37
+:101E3000174DE17E36375F1A2EED768A1A00AD9F78
+:101E4000F6C978541F904DD7D8BE3874BA431D05D3
+:101E500038DF11471530512E239AEEDBEB19DF17CF
+:101E60008776BF725F3CFE0BED2FC4E3B1A0178FE6
+:101E7000EF65180FD3F3C74B438B83FDCCB3C92B4E
+:101E8000339E9E7FE0698F8E72788EE494D62BA766
+:101E9000E6124B4E636A594E2F58727A69FDA5C9F6
+:101EA000C96EF7FF404EEEE1389F0C4B4E194D675F
+:101EB000A3CA3F27A717BE4B4E8DC18D6B681FCCA1
+:101EC000901C28C2FE9F0ECAD12BB1FEDC62790B9A
+:101ED000F1D6D3C18DEE22C255F3DE21A9F8FC0D57
+:101EE000EF0081172DD641EDCC61B2BE09F1F6A805
+:101EF0002AF4ABB159FEA599DF3B9FCDC5F2AC30BA
+:101F0000CAAFB17861CA5D7172D8DCDCE38F97E348
+:101F10006609E6134E93E5B4D02BF178BF5824330D
+:101F2000BE3D2108CBF8D18C61C0F5814320ECC2C5
+:101F3000FA4043D491FBC23AD6F77DAF619A8AF555
+:101F4000C64500B9F868A672C8A47536232F223793
+:101F5000E18F71DD02D4EF74FA13D7D51C8AF273C6
+:101F6000D73477CC443E48EF9A1B7D1EEBFBCB5D0C
+:101F70001A20FFA795AB7FE98AE33D506E87283E84
+:101F8000FF229456A360FB81EB139FBB20AE8EF221
+:101F9000D08C60F479E21BEC8F78D941CF8B7B9F9A
+:101FA000AFF8E093AC7D7178F0CE0800C9E7A836B1
+:101FB000C0477C828BB8EC1BE4979FAE6C838F8A02
+:101FC000787CC617528211E9075FE7569ECCDA8704
+:101FD0000FFF4A3827F905574906B65BB7A04922D3
+:101FE000FE1F785E3148DEA809FE5BC7F4BED783CA
+:101FF00038A1F6EB1C623FC6ED03258DEC89A68D5A
+:1020000053F4DE76314DECCB3A8F6837E1A8A10C62
+:10201000F8AE7603B01D8E3FE9DF4D25BD9F769D5E
+:10202000D63C418DCDA77D7CF47B4E8DF46F9D24F5
+:10203000F8D33CECB0F02EF679F3DDDA06E2F16D80
+:102040001D056B4B080721BD94FADBA687E482B41B
+:102050000BF3E7310B4FC367850C360ADFF617DD4C
+:1020600022EC42CC7F3BCAE3436F1AB7DB9682FC7B
+:10207000C1720A0D9A1B27A7DB2DFEB0E5B4530FE2
+:10208000AD1D83FDA4E03C249C47667118E492DEFC
+:10209000F1B615E37858DF7642667B3E70EAB12DE3
+:1020A00010A727F6783B53FAE7AB3B2CF9D8F27E22
+:1020B000430FAF1D1B375ECAACC4F1521689F50D34
+:1020C0003C299B648F2F34DE1B17182F64AFCFDAA7
+:1020D000B7DD7AD7DACBB19F541A0FA5914AE3A5A1
+:1020E000F533DE574F4A03E2F4B8CB2BECF66E5BC8
+:1020F0008E6A68D0BC38BEBADC7AFFA5E0B68EBB6B
+:10210000F0F1A3450D9E5009F141C43D9CF6FD7BC5
+:10211000326CC2F5AD5B5F01E427BC64006BAF3786
+:10212000CD9C4646F6496F26F7FFD2FA0A7E4F52FB
+:102130009BEA549CA7828A4E7800089F2079E78109
+:102140001C68243FC730740DF55EB2F47EE01CCDF0
+:102150005C88EDB36AD291A891569B6B0E8EC4BA7F
+:1021600067851CA0E7109540C5F603ADF66E306F8D
+:10217000619EB1FA1B187A7015F1C07A056A14E4F1
+:10218000897EFC8800F91183E92FAA971A201592FD
+:10219000DE86D8497381C9652A44D97F18407E8478
+:1021A00042FE44741A959711A52BF4C890E9791151
+:1021B00084EB68F2F9865EA1E27C8637872A683E66
+:1021C000990FE06BF9A45761EE4782C7D81F4A2DDB
+:1021D0007CDEFBF168CB1F9982BCEFD5585EB40F53
+:1021E000E437F892EA054975E3D034A07DF0A062A7
+:1021F000909FF48827B4D89B4D7E9961905D721BA7
+:10220000EE18F19F4B0BF2FA7E1194D9FFFBFF8D74
+:10221000A71FF526F2B4CDCF365F5F889FD9BFC424
+:1022200038E2AF4F2C9F4571C35719C64F3494EF16
+:102230004FC827CD263F36F4732FF1E28D4D7B0832
+:10224000D7F91407A01C943490FBC3BBBF19F14EFF
+:10225000F2477C52998C773720DE49FE8877F67BEF
+:1022600093F0DDECA8613C232A6B94C96C1FA47B1E
+:10227000B09F3CBBFD45F08D2E85AE205E55C283E0
+:1022800012EF3747B86EFBCBE910E372881A93A8B8
+:10229000D421C0381F0641C6F9208C9F08DF0533C2
+:1022A000F43A0FE1DCF22F86A2FF6EF2623420FFD7
+:1022B0003D2524FCF9A7837F61FD4FC6BBD139CDF5
+:1022C0002C189F80DF28C913F10BE4D724E3B73122
+:1022D00058E1A1CF374F9523C4AB9BB5F01A7A9F35
+:1022E000FC23B23FEBCE2BCC438FA29FB38AFD1EC3
+:1022F00083DB372E92032833F277A25752FBC57245
+:10230000B828FF92FC1E8E1B173E710BC791EBBCC9
+:10231000C0F6C12C728637E5933DD6190753639DED
+:10232000D3337CE4370ABBB9CE11F307B87D6C3EDA
+:10233000F197F9BCE0C99782C93C19615E1DE7F5C8
+:10234000723F4FAF5F75CD42E235D5647EB0C72F87
+:10235000F71EE0B815D2627ED2FB75736B5388CF3F
+:102360006D5E4D6E77D0637C4C723C7401BFED3373
+:102370006FC5A7C4137FB0702CA951D67B650670BA
+:102380003CAC5668758433C98EBF6624E14AC747A2
+:10239000C4D79976BC16601E77D83C0E5A3484EBAD
+:1023A000765AB8B479D403E17EF95421BC31DF26E2
+:1023B000C667DDBB8E0F3571BD7FBCFBF301D8183E
+:1023C000FEACC606905C4FFEF89D01E42FFDF1C700
+:1023D0000AFBAF77D01C2601DCB9F2FF4C5C88F514
+:1023E0008C4C89D7B52CD37065125FAEC866255A60
+:1023F00012C641E2F861D9CBA904FE6FEBCB235999
+:102400000975D6347C75B90B6AC8CE2EDBB2C739D4
+:1024100018D7B7E465EF38EC094E22EE498F4FB676
+:102420000EDD407EF5D599B2356E3097C6A5F91010
+:102430009EFEDCEE8228DBD74E87F06B8CEBA48906
+:10244000141D889FE479EDDF3DD82963BF774BC821
+:10245000B35EFEB861278EFB57BF028D81BEF3BE0F
+:10246000FB8F9A53C6E7774F8398398EE629353C20
+:1024700084EF2F245E0DF45DD702D391C0B377456E
+:10248000EE73B2D0959299B9C4C76B24E6ABBBD6B4
+:1024900024B64338ECFF35F6BB08FBA57DBDBB2950
+:1024A000F1794FC7FD0D3BF1F9B636A7467A7B6F40
+:1024B000127F27F3F3D44CE465E403E4A82B889758
+:1024C0007B3AE66544F50BC76F362F9FC4380EC1C3
+:1024D000029FAE7473796A25830C5C993AFB2BCB0F
+:1024E000DAF6EC67CE533B2792BE6CEBF828F55634
+:1024F0007C54EB17F1DBF7377C5EBF131F9741303D
+:10250000234A7887A883F4ED4A70EB6938BF4D14ED
+:102510009F2184CABEC27AFCFA9AF6FCE6D71C8FC9
+:10252000A5D56C42B9D622D05794F6CEAFD62FE2BD
+:10253000B6DB41FDDB77ADFBB64CCB1E5D81EB56C8
+:10254000FEEBEBBED07BCBD1EFE94FFF6DFD7065AD
+:102550000ABFB57ED7B33307E1BACE3C21055C385C
+:102560008F338E7003D79F9102753A4FFB18E4F4B6
+:10257000E21597CD78BB97781BF1195AFC08E362F6
+:102580003FCA85EC7CA87D283FF74F47FCA25EDE62
+:10259000BBF8B3F7859360FA653F9551BF5CDE0FDA
+:1025A0000E93F0968CAF338EAE3CD2FF645C9DB937
+:1025B00000CF556716F0FA16E9C64CCAA7DD0DC163
+:1025C000064DE8DFF1FF8EF5EC6DBD1F34C27F874D
+:1025D000CAFE54E9011117971E7686C9BF3F8DEFD9
+:1025E000A4D1F37D6961B24FDB1DFA5325641F0E40
+:1025F000A8C0F1D379E07860DCEFFD618AAF4E6767
+:102600009ACC2FDBBE82F0C67C6A5056A8617FE36D
+:10261000FE5112E0E72B146306BD7F1EC214E78F44
+:102620007BEBB1EBA8FDEE0D0A507E2E59BEA5073F
+:102630001EB88CFCB32BBF4E91E879B2BCCBC28ADA
+:102640003A99FD12772C03D7551AFE68D914E67310
+:10265000A8A57AF27ED8ED3519B83DB917542F33B5
+:102660008A63C453C9FBB4A4DDA5D2FC9774402986
+:102670007DF6FDF389FE5EE9A124FFD0E6DFD75B9E
+:1026800076921D58FA8727D301CB4FD4A61CC2419E
+:10269000CB8B3F4D37C81EA8663AEDEB2761610F23
+:1026A0009271F0B585775C58BA84FB5EC553C5FF5F
+:1026B000D6C41A1EC6F97C893C4BF3ADDAF777AE67
+:1026C000EFC7F5839FFAED9AF908AE67C982B49A0D
+:1026D0003A7C5EDD96B8FEA52F3D93A3735ED31CB6
+:1026E0006CE16030BD57F5A22340F6B3EAA8C27989
+:1026F000D36A8831EE92DFAF8E7CE4247C90FC8636
+:102700004CE9FB1CE1E824FEAA86C7CE2A63B1DCB3
+:10271000F729E3AE3AC9EF5D6CD9BF649E3969F31E
+:10272000ABC533289F00F96526CE8BD214101676E0
+:10273000B1FE1597E9C6797CF27EEE0617F677EAC8
+:10274000C5DFA64B25BDBC03B08AF5E854A43023F1
+:10275000D48F7CEDF28CC54F761DC8DE539EB74DED
+:10276000120144BB285BD06EBA711E95EFB9D85FD9
+:10277000AC3CD2C3FA855E45AC08F56FE789BD393C
+:1027800063F0F9B2AD0EDF1CB19C74B297F6BE2DAA
+:10279000DDFED7995BE87DB4871EDAB7D6736C2F60
+:1027A0006DFD5CB6554AA5BC4365D81170EB7DE55F
+:1027B0003A3DB2C7D995D6CFBE453E9C497980FAFD
+:1027C00057CEF1BE7CB25B82DCFCBEEF2FDEF4990B
+:1027D00093F4EC14A550BCB48FCA026746DF76A709
+:1027E0005E4C65FD3DD52E85A5FC8BEF630786CB42
+:1027F00002A7B13B689F1419FD27D247F4A7290E01
+:10280000AB279C8E23196840EB850A88105F49ED41
+:102810006F7D2D8DEDEB3F9915505C83EBAC77F61A
+:10282000E6B537F938CFCD796D73954BABF7719E1F
+:102830009B9FAF50DD1AC575FF9A65E7AF035192B4
+:10284000C3436F426923CFD260FFF5DC7EACA35C4B
+:102850001D3E5D89C74360BACC7ED255CAD430F5DF
+:10286000DF63E67A5DE3A9FF7499FA597D207B0363
+:10287000F1E29D59C2EE8CEB2A7E762A3E777438BF
+:1028800030E0C4F63404D67B4E621CC17C17AAA784
+:10289000E713501FC9DFD849F61ADF77F965D0E38F
+:1028A000E4ECD153408FC37D6A7166421D4CE36DE9
+:1028B000FF44B2F7E267406050C2FBA5105016E03B
+:1028C000FC0288A728AE3FA3BC20F1FD43629F8A8B
+:1028D000F197FCDF8947E3F60D480E6185F4FD0AA8
+:1028E000CBDF0A44C36F9A38EF722B4E2DFF20B115
+:1028F000FDE48BC4AD47B32CFF60100C22BDAD27A7
+:10290000FDA6FDF2A673DCE1B0CE3768C673917FF9
+:1029100006F9843C03A9F2E7080DF851D6CE6B54B2
+:10292000D4EB40997C7F21D6573FB547D4A7C8DB6D
+:102930000BB0DEF0D4DE6B54D493C0E5729903E79C
+:102940001736DFBC6606D65579EB6292BF2A8356EE
+:102950008FB85A9D1EA9A1BAC30FDAAA81348E2E50
+:1029600070A16F0FD17C1A068246F8532BC4BEA902
+:10297000E9CE30CD5595A7CD8FEF67ADD338C9F1EE
+:10298000AE0FF43AEC27D5150951DD89FD521DF43F
+:10299000C2E9546F188A3119AEAF54D5A7733E19E6
+:1029A000974938F8765C30FC84BF7AAF93ED9F5A34
+:1029B00061E8846FF255486F2EB544FDCA235E5519
+:1029C000948D2D84FB589D0A1B7D146FBCD442B896
+:1029D0003DEE74F3BEDD9CF19863140E5DEACEBB50
+:1029E0009F94EA7D69CB8FA8BCDA177A268BFBC14E
+:1029F000081DDFBFF50E6523C741693503683FC079
+:102A0000407DC5CFEB2D7F0242A8AF34F65ED4D710
+:102A1000714481A8A7A37BF534791E4AC6169EC7C8
+:102A2000CD2E318FF9E182FA2E9CC738577828F9DC
+:102A3000AB38FE261AFF5657B888E2268CF93A685A
+:102A40001EC7EFBC4CCC0386300F309E14D2C75348
+:102A5000AF517FD5D8BF8BEDB991BE2087B78CF928
+:102A6000F44CCA0B0A5524B44312271B8C7AF27318
+:102A7000A758F106740ABBACE32FC77FCAF91C6ADA
+:102A8000FFC52199FD8CD27D89F89E74681BEB836C
+:102A9000B630AD26A39C4C5322DEA7B4A1FF847CA4
+:102AA00035E522F14134490F2249F9F580955FC798
+:102AB000966A7CFED7B65B073D156F65216EE6A86A
+:102AC000A29D0E86C1FC12D065DA979E430BA1949D
+:102AD000EAA0D702D68766897C67B25D6B4DB26B80
+:102AE000361EC71CD5EE221E1F7314EEA4F55CA57E
+:102AF000A4B17DED41FB8ACDE378CFC1FEE038186B
+:102B0000FBEC54DF85F9AED7DE26F29ED748E4BB56
+:102B1000AC59897C971D4CE4BBDCF989FC363094B8
+:102B2000C86783178F4A783EB4A634A17ED98AC974
+:102B300009EDF3D190C4D70BD7CC4E685FD4342FB6
+:102B4000A13EA2F9D684F623C30B139E8F7E79692A
+:102B500022BFA2DF4872D81905F805E13789AFC74F
+:102B6000446A13DB2B539505843FC427E9C7E56D01
+:102B70000F27F46FF3B589BFFDF1B592F29A42FBCE
+:102B8000D4857E9D341979DB672A04A33E3C9D766B
+:102B9000F203DADF8BF175B62F11A75FC09C72CA02
+:102BA00057A5429079FA42F15CBD753EA1A40ABBDB
+:102BB000A964C8355B295F9925F2088D5956BE571F
+:102BC0001338E9DE3582CF55CE79F224E2171DFDA8
+:102BD000014AEE753B8648C42FE6748828E8473ED4
+:102BE0009492B787FCD6AEFBD203D2A0B8736DE443
+:102BF000B5FA00E392FB5BF1C100C6E53959E7BCC9
+:102C0000F5D34A50223EC12EF3659CF76A1916D3BC
+:102C1000FC1E97E53BE3CF2126F8843F3DC127E624
+:102C2000393835B284702E6B82CF57CB2C0BFA31EA
+:102C300028EF909E059C47057368E38CA9F8DCDBC0
+:102C400055ACA3BE4D7F7A68E3ACEFA37799FA1A2F
+:102C5000F35DA9A9029F9F4298EBE390FF08FFB79D
+:102C6000CAC87B38E47C5F8D43D289FF8C0A1F8DF4
+:102C7000EB0633BD94E578279D5F78C127D552FEDA
+:102C8000A7975FF56FCAFACAFFCDA55364F29F7A82
+:102C90001629BCFE9EC5CF9DFEC217A78FB8D64E83
+:102CA0000284AA6750BEE63DA77EFD4492DF4185BF
+:102CB000F378BFA37603FBF67BB1F87CF186A70619
+:102CC000D0BD8AF78AC579B6FDF93D963CEFF1890A
+:102CD00073ECEA459F396F6539A03F8BFC5915FEAF
+:102CE0009CFD4DAD006A32D04EC3EA1EAE3F6A086D
+:102CF0007FF0114AC2E2FB1E8769A6917FD07E9FBA
+:102D000049F98F9B8F8BF8FFE67F88FC953DDE436A
+:102D10003E078FF390355E69476802EDDFF5A488C2
+:102D20009C6F0A4D207B12D440A7FEE78716FCE873
+:102D300010D6E73E86F0D0C4736A3F6F0862149FD6
+:102D4000BF03817777E01256FBC43C6E84A083708A
+:102D50007F0C42A7DFC5F91CF78AF63109F48D71A3
+:102D6000FD5D6FF577FC8E653BC8AED378343ECD04
+:102D700087C69FAB4101D5ED7E92C7BD010C87F0A0
+:102D800083820EB2E7856432F0792DC615A427B58B
+:102D90004B5281E29ADA5DAE30E1BB7BE9B9969F96
+:102DA000E314FFB420B6438AD3CB5B9A15D0112726
+:102DB000FFE935FEA78FFC8CF22C8EA72E14E7D8E6
+:102DC000712961DB449EBA99290CE0B0858BF9ED3D
+:102DD0005965969FF01CF5F7FEEE96A1486D707050
+:102DE000E44B45E42FC3F84BEB1FF5FC55D25B1DBC
+:102DF000ED36E4B17D617BD21D9519B7A8E7AF929E
+:102E00009E7439DC1AF1D8C5F5DC6021D9FEA32205
+:102E100007FC2AD9D5762595E29E7472DE6CBD45F5
+:102E2000DCA52BB2D05BCA08607C34DAD66BF3EE3B
+:102E3000D9FBF8DC35D18FC0FAF42DF17E83B25E78
+:102E4000A1FCC617863BAAD0E714FF50DEC4F227C8
+:102E500082F84BFC3CA23931EEEFE32F50BC7409F1
+:102E6000FEC27E9F15EF5A3C6CFB0917CBAB6D235E
+:102E7000BF02CB48B1D0FF483485ED71A9C507101A
+:102E80004D63BF3BD9CF40FFE21DE221DBBF48EEDF
+:102E9000FF3D9FF027FE6CF99DAF648B52552326B2
+:102EA000ED63FA7CD04CF2BB21C2799F6C43F8D918
+:102EB000A9C86B1938F82C8A4DF17DA774A6D88D56
+:102EC0007AF091AFB2710DF2A77B98CDAF958D6F6F
+:102ED0002234AE3C7FA55C8AFD8D3FA070DEA867E2
+:102EE000DF28BE4776A1758F47BC93718DEE9F2C6E
+:102EF000B35DE9103CD892A9FF7E0AF9A10714A09E
+:102F0000FB501EB5CBE9ED675D3B89E746A05DCE82
+:102F1000167187BB4D3228EFE2D6457CE8A1FB0352
+:102F200064C743C071F8E9AD851C2FBE922DE4F152
+:102F30006F99C17F905E7C2A1D99A815F6CADFEEB5
+:102F4000BF94FCBA927EE52D65C7F97391E8DB1555
+:102F5000CCD7B3745919D757EE76BDBAB98C0FBF19
+:102F6000AA9AB3B81C49F908FCA83A2AE470A6AD9D
+:102F70003EB3BFBC46756EE75E9207FCDE0394EF7E
+:102F8000ADFEB73FB2FEBD3A17A185FBF1BFBF1A38
+:102F9000CDFD0DCAF65AF14927CF67545097C8BFE7
+:102FA000AC7609FE3DF395C2EDEC7EC7B44D5334CB
+:102FB000D4839268D35E8E73DA5D3AE1CDF3220852
+:102FC000F9B57B98AF542DF631D971B51DE37494E2
+:102FD0005F4B4AEC4FD47F6C974BDF48FBE56CE2CC
+:102FE000F6B12290A93E12E5B62D8DE4DF04997169
+:102FF000EBF1B43FCB97EC103746989EAB4DF0BD4C
+:10300000B87D7D255BDC1B9A922DF0D6921295D36C
+:1030100044BFB091E7D53B4F9A9747B3E73992F356
+:10302000372D4E9CA78FE7A5116E46829827B48F47
+:10303000D0496F549C0FF1B93A0C64A298E47955C9
+:103040008F85301A6D787C157CCB37C43FD529BD70
+:103050007537EA664B818DFB5F36CE18125F47C22B
+:103060002CEF7D7FEE339B1A57A39E9CB0EC11EAA8
+:103070009B11AF6F1ED510F7956E446AF592BE197D
+:10308000FC3C07FBA89BC4F528DBDB1B45BC5ABCFA
+:1030900041FD9C9E6F8DA605E87C2CE37C06BF5FFE
+:1030A000D5E9603B53F99F37649450DE4CDEFBE07A
+:1030B000162C3F5B10194EFECA9401A1DB08AFAF7E
+:1030C0007FB090EF9F7CDAE208CCC12915FF4A82DD
+:1030D00074EC7FE92B1E3E87FFD9899EE837A487D1
+:1030E000BF92C2947FEB76984F0E167574CC709C8D
+:1030F000F6FF70529EF3EAB60F9D5D58FE3D3BB45D
+:10310000281BD755DE56379DE437099AEA29BF8830
+:10311000FC1C62BDF05B7ECCD1E11BEB480F63A1D0
+:10312000CBE6A11E3D912DFC0C5BFEED961EEF261D
+:103130007F05CB1D961FB563CF2D857A9CDE99B098
+:1031400097F363AB60DF6092B3FD7977589D457864
+:103150001A7DCC7DA71187B7B5162FACB5F47D4885
+:103160004EE86192C3B23D7F71A6E3FA3F936233AA
+:10317000D3A57F4AEFCD04BD47BF2C1EDF7DF43DB4
+:1031800049DFAAD59893F3AF278179EAD5636D1CFF
+:1031900007BEFAB0E625DE8058F036AA7FF9AE9376
+:1031A000F30F3B2CBFBCEEDD2FC7529EF0CB5DCBA7
+:1031B0002E233957663B587EA81F1529A4875B81AB
+:1031C00079D2D6E312D26349DC7F25BC97907EE4A6
+:1031D000937E74CE66BDDD2183D053A12FA81F1A24
+:1031E000E5FD4B34D4177E7F04F3404BE7DBA3A807
+:1031F000BD89DB5244F3538D1BE879E46D95EF5D97
+:1032000095B41F4F213C95B47256E15BBD1E2F4112
+:1032100030FE1CE4842F9DE77BC2F22F3FB5EC50BB
+:103220002A5D0288D39B383B2FEAB61F609E6FFC55
+:103230001BEA59A1512693FF5B7B58D897DADF4CE4
+:10324000BE7E8BA8B3DD9F68D44CA7A3D0F2594DA6
+:10325000648E607230329DC258B2333AEEC3042C91
+:103260000DE4D9A9F33BDF7408751E4DE76DAD7B06
+:10327000AF194D714CF77B2EF0907FD632FB553A4B
+:1032800047EF7ECF03B2D4978F295F1B8FBFE4B285
+:103290005BEA4AA77C5767F6C9D9AA07F56692B5D3
+:1032A0002EF3E3D951F5C2EFD9E5DC1CA393F4AAC0
+:1032B0002A37C465F791BFE7200C61C7D1BFA4933B
+:1032C0001FD1EA34466B5C625CD48F5D7C235BF873
+:1032D000D5E3ADF362D243CADB9E6ECEDAC07A6824
+:1032E000745E47F6E41E49DB43E7E467B345FC64DC
+:1032F000C7BB770B570616B7DE3093FC286D9002DC
+:1033000074AE72CFD38E84B874B869B2FF5F859003
+:103310000A233E2AAD73CCC549FED108883A290F4D
+:10332000531D4AAB896A7DF3D395561EBAF222F13A
+:10333000EDD96CCBAF2A8442F2AB101F9CE788BD5D
+:10334000AB0436E2C7AFCA41D627F327206F623EEF
+:1033500085D519997DFDAC5FE41AB3FCB8DE3FF961
+:103360002C3B63E50D632D5298F5E265E07E269FC8
+:10337000D437D07919CAE5983F87D6058CB3C9AA46
+:10338000C979FFC9FE423029AF8A344E7A714FBBEA
+:10339000140E53FBB0589F8ABFE4577E015B1AC8D6
+:1033A000DD9C043196C3BD24073E3F4F9243F39109
+:1033B000FD94F65A1E493A9FB9409E7E1B40BFE7D6
+:1033C0002D3939969CF2202FDEFFE4C47E3FF16256
+:1033D0006FBEC7641C7CE610F7F9DEB6FAC79F74AF
+:1033E000BA5FF591B5FED21C0B2F1060399C243FBB
+:1033F0001BF7B5CA9243E5CB961C1E137871E32FD9
+:10340000C9A11AC2BCFEE5D6FA93D789E3EFA77823
+:10341000F35EF4D309978BD727E26DA92587A549D9
+:1034200072A80A4962DCB022C6B5E281BBC0FE11B7
+:10343000F35C6ACD33795ECB1CC0385A863832F5DE
+:10344000FFBE7926EFD3B53956BE66148C4AD8A78D
+:10345000595997B44F85A06750BC69FBD9361E9265
+:10346000DF9B69F9D957370B7FB3B573EF1AD2FFDA
+:10347000D25D8A467E406B674F3A9D7395ED522828
+:10348000ED02DDED656B4DE4C5ED1DC36EA07BEF78
+:10349000A54764D687B2C3A5610FC523874B530BDD
+:1034A000F9BC51CFA2F1BB0F09FBDB7D68D83B25EE
+:1034B000ECC7CF184F345377A83495FC84ED20F235
+:1034C0000CD2E1BFFD8EC62D3BA04EA4BC6403EE22
+:1034D00007F57BF5730B3693BFB13047E401F67700
+:1034E000D6DE48FBB9FC90ACD1E7670E89FB82952C
+:1034F000CF2B6199F657F9B1EF367CFE45BB4313EC
+:10350000F375F0F8D5BB8AB2EE4AEBDDFF85365E87
+:10351000BDFA5373C80F1C98CAF7B3AE1EEA60BB5E
+:10352000786A50EA2FE7607FC38DFC6FF111C6FD0A
+:103530003EF5C6FD22BE6D91C08F0BD9EFBFDF49AE
+:10354000F1C3A90A7794FA39B5F38893CE7FA7B768
+:103550001E11E777D6F9B58DA764F99FEE4CB1EE51
+:10356000DD3439699F961FB1EB5D4EB2E741CB9FC9
+:10357000AA7AF143AE2FA5B880E6F3A2C4F71FDF05
+:10358000DCF53A9F03566D11E7804BDB9E70125EAF
+:1035900097223E75E21168629E5ED6E6D4FAE39504
+:1035A0007B9B13EB4B2E82CB176CFE1809230997DC
+:1035B0005F4E13BC1E892EBCAC85F253275C8C93E6
+:1035C000EFC027DBC743561EAA272A1BCECB7BDBC7
+:1035D0009D39D4E3A47B5333DBCFB2FCE6B4EF993F
+:1035E0004172F901842A699D3F684FD5C86F9DD308
+:1035F00025F86476BB2B1C96E87964B5B83721F8BA
+:10360000E85E6B7FBB773FC4EB37D14E15A17E5789
+:1036100076DC3F93FDE652C8A73CD5294039D384D8
+:10362000D727EED3B5C58972990D67EFA0F7703C27
+:1036300008F3F94517CB799975CFE85AE8E271AEEE
+:10364000253963BD7BE0E8EBD9DE609C4AF7F82AB8
+:10365000B724F6579564072339C22E5F2C1F90BC00
+:103660001F9D49FB312726F86AF6512540F9FB8E4C
+:10367000E8AA12CAF3DAF249DE8F0EFDBBCFCB7F88
+:1036800067F9DF76FD7ACBFF8D68E19F97E17A0FCE
+:103690008076C4640F0FF87B1F0F6C1DC8F9DFA97B
+:1036A000B9C20E7C31ECCDB13AFE59F9D61B79CEB8
+:1036B000028E374EE6D0FD33B9FDE7E436BE354421
+:1036C000011FC51D186790BEFDCCFFD1E365E389DE
+:1036D00067A193CE81AAD5A63974FE51BDC511A0AC
+:1036E0003803D45803F1C467BB249DE2F5AB092726
+:1036F000389F60BB7415E104FDF8BFE5A01C83860C
+:10370000D7C1FEC70C09E8C864EE8CB34E92EBA19A
+:10371000247F7ECE85FDF9BFE7C4E54D0E0C2BCC92
+:103720005848A5AAE766A65DD89FAFFA4AF893F66F
+:10373000E755A8C724F7AA7689FDDF5E7F32576276
+:103740007F72D7434E8A53BB25ED6C2A0A6464AE60
+:10375000F53D06F42BE8FECF3DB6999256B3DEB4A4
+:10376000EEFDE426CE53FECA010584432CE10AE4B3
+:10377000D3B797324F9D419CD3F9F8BD5AA881FA2F
+:10378000D54250B30EEDC519223C8A1F76481C0F56
+:1037900027EB3D281F309EED7BCECB4A3634D051EF
+:1037A0007F1DACB2E2AAD55C8EDE7D9CC719FD867A
+:1037B000539335CE4B38395F188EEBAFA02FCF2CFB
+:1037C000BFD83DBBDC441CD7BD9DB29678B8FB800A
+:1037D000A251DEA775EFD72F0C223F0CFDF002E2BD
+:1037E00079CB5F69DDEBE1B8B8FB485A98E4F9A9F9
+:1037F00085D753567EBBAE5C61F9C89344397AF7DE
+:10380000EB058483EE5DE7F242B8DFAFEE7E7D9498
+:10381000C1FB1F16F7F25E4EBCE7B83C92788F11E1
+:10382000E7C5F766AA8F89F3339CD770A7AF775E99
+:103830003BD4AEF4403F7A26497B79FF6429313E80
+:10384000ADFE95128CBF0F84EBB993F8EF3A4B7F26
+:1038500010EF396447E7E5EA3CBFBA76B1DFF22EF4
+:1038600051E2F837897C8B83C7EFF3BCC2ACE47DAF
+:10387000CF4FE573EA0E15CC0CAC779CF070DCF7FB
+:10388000E0DB4B47C4E7E140127174B52396C3F106
+:10389000E81199E787FCC7F75D66B73B7C2829D814
+:1038A0005FF06B95F96DAC0413B01F93C6CDA53CCA
+:1038B000E03E7EFF9865AFAB2789F75759386A7DA0
+:1038C0007B762AC585DDBBB2F91EF27CCB5FACCA24
+:1038D0000D2EC9CDEE8D632EE48FC6C559FC5E3525
+:1038E000AE93F469FB0957788E4471F0B963B7D190
+:1038F0007A0FA8FCFD8BBA5D2E93E2B5EAF73D9CEA
+:10390000B78050E8728AEB1EDC7DEF08F1A5CE553A
+:10391000BC1F5FEE3EB086DFDBE9E0D383E5BBDEB4
+:10392000CD617BBC63C253E4EFA07F732DF93BDB19
+:10393000DB1DECEF941E1ECF78DB7E687C562105E4
+:10394000601048A57E971F5083A4E7CB0F8CFFED36
+:103950001CF2530E57B0BF231D1E9F453C5546F128
+:103960002FF93B078671DD5E8F99ABF07ABAF77855
+:10397000384F214181C00B0C4BC04B65EB6FD80F0A
+:10398000A86C538C78DCD8EF3D9DABB2DC9B6DBC52
+:10399000442483F1B05594956DDB73681DCB1C11E5
+:1039A000DEDFBA2D0EF1BC459440DF4FC5F7CC8069
+:1039B000CCFBF95BFA08F7E1A0145E4476F2A0E5CF
+:1039C000FF1F7C2F7419F1E0C169A1115416F9137E
+:1039D000F9D0840A9E3748F378DF4FB70A3F2C7935
+:1039E0001FF3FC22EE4FCF8284F33BBBF4FA053E7B
+:1039F000663B45DE88FCB78139D6F996CE767806E7
+:103A0000F1D13C7F9644F9FC3F587AF38E75BE03A2
+:103A1000E5C2FFB6F3F8685F1DF1DFE748CEEBFFC4
+:103A200070DF64B61BAF49E29E41A438901DE86781
+:103A30005E37FCC091E0B7F4793E2B91FF7E7811A0
+:103A4000BFEA80CD7FC361B8F0F7D35289BFBFE82A
+:103A5000403F96E396F0B0E098BEE3D8FCB21F7901
+:103A60004F47DEEB40DEA3F29FC85B1DCF9D70F198
+:103A7000F381BA91C739CF7470CF7BAF7999873D05
+:103A80006C7FAE3CFFE79CFEE65507F378FF57C11D
+:103A90008D09F8B571701AC4F78A937170D6B67F24
+:103AA000D0D5504B7A6BB86BF8DEA3D2B4A6B85021
+:103AB0009C1F52DC5DDD3E97BF37639F2B7E6B6F93
+:103AC000DBEE03B2477523CFAD26BB70DABA9F8E0B
+:103AD000F3CE73C5D98FD303CFF2F3072B2066E261
+:103AE000F33D235D6C1F97CF90F89C01017C8CBE49
+:103AF00097729D657E97471167A4CF1807505C3F6A
+:103B0000BCF5C3D5B43F37A17D35BC2407916F5DAB
+:103B10007EA3C4F9A7EBCB13F7BF0E324DC1FF3E16
+:103B20002E4740E74CBAA77FB321B19F36D7486CE8
+:103B30007FD3FCB98CD379D67DAD9B6F9F7B15E18C
+:103B4000FC06EBDEFAC5F035CA1FF2511EA3BBB36B
+:103B5000E7A6313A9DEBFD471EC9A5CAD2A3C0080E
+:103B6000BD8DCEE502BFD5C6D5E33B2F877B765210
+:103B7000BDDBF44974BEADFBC53E3CE90BE5F98500
+:103B80001DDA49E776554EB746FB61F7B73E579CBD
+:103B9000FF1F748487109FD87A1CC885B2FBD2E2BD
+:103BA000F757E8659E755E04259776BE5837F2ADE7
+:103BB000B1C49307F71C18EB8CDBBF53B5A1116C94
+:103BC0009F76BD99A3A7C5E34EB670A7722949F3A6
+:103BD0002CBB9B88C35384C3122ADFCDA1FBC3A790
+:103BE0005BA7674B7A9C5DDEF14E7A515CBFA7DB29
+:103BF000C5BD5D8CCB86FF7040FC3C7FCAF33C1D8D
+:103C000011FDA1E4F8DCAC6AE7B889E23E229894A1
+:103C100001AD1AB670B3B8F7546FFD3B04BA7D1E00
+:103C20006E0CCEA7F3CE1A93CA8813F87D73B78BA8
+:103C3000CFF3BAD11C4539DFA86D10DF5BAA5186DE
+:103C400060BD1CB4B3747E7397DFCEB7D428067EF4
+:103C50003EC910F7B790C7F9BEDA9439E21C1A9F33
+:103C6000F37DB5A93510E0734FEBF9E459E2F9F7AC
+:103C7000A08B03FC2B2935857A360D7495EAD3C1C8
+:103C8000ACA7F394F6D66D0AA523A239AAF7633739
+:103C90008818EF3BF294D4CDC7361EB1313A4B9C15
+:103CA000B797E0C70AD9EB89A0F758F3E27B35E56F
+:103CB00086BE8DD6D368D99129D0C9F309D0A0B4D6
+:103CC000EF5F03E7DFA6A89DBC8E01BA9E49E724FB
+:103CD0005BF7D5727D3746BB7CAF31CB6AFF89B8C5
+:103CE0008F7E851AE675E6D488F69320DAEF3AFFE0
+:103CF000873F9FC7B5D7DBED88B09DEF5E828A8B8B
+:103D0000F3AAF78B7F276272930427904C03856296
+:103D10003DD8BFC2E73256FFA96E511F04FAB6273D
+:103D2000E8DEB2B51E80191AC9438AE6C8DFA45E70
+:103D3000BADCBA7380E79B7E57ECCC23E37BCFAF32
+:103D400002EDB99CB77D4C92630ADD9B740F11F7AD
+:103D50006DA310A1FBC548F309DF877AD63FEF19A1
+:103D60003FCD23043AF929C9F7FB5E0E6FE4FB2C23
+:103D7000F3EDFB2D43004EE6F4DE1B701488FB2EA2
+:103D80000E3AB7D7F8BE6119C59574CF90FA7D5F2A
+:103D9000DA52C49DA9E109D4FF6A459CDF9FF3E490
+:103DA000F13CED7B400FA5E4F13CBBA641449AD227
+:103DB000F73E40AA2BB298BFB7E5068DCEB9FADE22
+:103DC0000F10DF0B442DD2E9FE8F5A01D12BB0BD6D
+:103DD0003A48DCEB4CBE5F7CCE23EEEDD8F7131EE9
+:103DE0004A798DEF31DAF711689D53ED75CA9772F4
+:103DF0003FC1748CCAEFBD6F89EBDF43FC68DFBB4A
+:103E0000443B5D24FE1D9128DB8354437CFF4CC35F
+:103E1000FD51459C1C735122D7C0FD29EEDD1FBA10
+:103E200040453CB17ABAADBF9197F9FB6A2807AE1D
+:103E30001704DC24CFE4F5FD5F7E40836A70460002
+:103E400000000000000000001F8B080000000000C0
+:103E5000000B93906760F8518FC04DC2A87C74EC42
+:103E60002A8ACADF2C825F3D213C9F05C1BE22C049
+:103E7000C0A0CA01C1CFD821782A103742B10707A4
+:103E800004877022F438F33330F80271383FAAB94E
+:103E90001E4C10DA879181A18B01682610EF45D264
+:103EA000A7C80CA1EF3B32302C774388F75B313049
+:103EB0005C03E29BD694F96B140F0DEC1B8ECA9F2A
+:103EC0001080CA5F14C4C0F00949CDC400D2CC6FC1
+:103ED0008800A6DD08DCF20F6250F9A969A8FC0889
+:103EE00034F96D05A8FCA5B1101A0022F46663C868
+:103EF00003000000000000001F8B0800000000000D
+:103F0000000BC57D0D8014C59968F5744F4FCF6CBB
+:103F1000CF4CEF320BB3EB823DCB02AB2ED2C08A3B
+:103F20008BC1D82C3F21892F19D1E8E219AF010F9D
+:103F300057451D09A79B4433CDFEB1BBEEC21038D7
+:103F40005C08EA80A06834593C4DF0DD253708F163
+:103F5000F0E2DDEDE5793EF30ECDE25FD433C9EA60
+:103F60000B81BCE0F9EAFBAA7AB7BB995DF4E25D8C
+:103F700036E735D5555DF5D5F77DF5FDD5573521B6
+:103F8000750AA93997908FE0EF3242CCFCBA26929D
+:103F900020442101A3A79E902099777425216423B2
+:103FA000FD8FCC27A4139E15F4BF64199657C675D0
+:103FB000422E2244AC0A1C0FC50891D48C4D746863
+:103FC000641608FDFE7C42323B1304FFDE9847482E
+:103FD0002D19FD932612721EFC2340C824CD7E1697
+:103FE000DAB70B2433C92064B3330EC90556D2EFB8
+:103FF0002F38A2901E8D903A3218205309B9900C98
+:10400000E3D3209A08CF39C4C0673D49E3F3370BA7
+:1040100087EE8467A7669D4BCA0959AB5AE746E805
+:104020003877BE36F8AA40DF7749A60EEFC90236C8
+:104030000F67FEFE272136817635CAF5A640E138A6
+:1040400031408C1E78DB68E0FCECC788D146CB8A17
+:104050003A1010C8E8779D59420A33E81CB50CB1F4
+:10406000EA28DC497B50A4F8A91BB088A5122227B6
+:10407000892DCEA2DF01AE68BF6DA5245F972224F3
+:104080005445DFD54379F00928D3764473959DFED6
+:10409000DB4A8DA45A375AEE88CE7B3904F4D28895
+:1040A0003E83B6930A9F277A14C63789459F41C934
+:1040B0002602ADA7B449EDA36306950C2B57B17248
+:1040C000DB87ABB16C57D03239130F6B8148140FBB
+:1040D000E7EF67F04A2AC98B74C262E1996723B49B
+:1040E0002C26891146AA1A26E025A812ED31A857D8
+:1040F000597B51237B4A048023FF2C9489C6C6BD7B
+:1041000080D7CB49EDA1400AE02A044AEAF19D019B
+:1041100070D4413DF49760F592E6C517E0C78DAFC6
+:1041200060E2E3E1AB2D25340D40DFA7E726AF8A3F
+:10413000BADE7F28B2F7F4EF6DE0570171867F2A6F
+:104140002D9F27B07FB71201F1E1E2B30DB00ED67B
+:1041500012CA67B47CE76383D7C37BBA0E489AF66A
+:10416000BF5DB632D05E52655BBC10E6312C031FDA
+:10417000FCBA94E0787E7C7F8BE3BB23BAD41CA28C
+:1041800070B7DD6390741DE07B3ED255540D62CD57
+:10419000A4FD003E015FFB193E256580E1F77146F5
+:1041A000C75914D100579D5A082CA4E3AC94AD59BB
+:1041B0005016002EFA7D5B746912F893AE8756781C
+:1041C0001F225F8DC3FBB1D7834C0A741147804710
+:1041D00044C48AF6D6050C27506E50F38B041DE9B3
+:1041E000542BD5C3D28A18626A940F64E01B2853FB
+:1041F000FE84F52426BC7C2301DFB8DA53BEDA53F3
+:10420000027497ECC338CF249BD77C5E3FC2174A19
+:10421000BE2DC6F8CA003C5CC2EB258DD5039F407D
+:10422000794B94F28DC0F804F8664B94F289C0F88B
+:104230004A739529D12B000F5BA25A85EAA2CF962B
+:1042400011BE9950E1E69B2D1F4EADA0C28818BB50
+:10425000BF622FA6F264CB92E971AB6E6C3CB6657F
+:10426000D33BA469AEB2C0F8A02D4C9A9EA44F7364
+:10427000AFB6E20680B14A9FD383FC67BC6CC17CB9
+:1042800012B44C4BCF00FF5D04F2D77C06F8A42D8E
+:10429000A0AD4079B45426FB52205CF58AE514FEAB
+:1042A0008621EDE7201728DE75B65E772C8AB9F0F7
+:1042B000DEB164DE08DE67FC17E2BDDB87F76E1F48
+:1042C000DE9DB2838FEE682EE9C67BF708DEB77AF3
+:1042D000D66BF7B48915B08EBA39FE7F6553FC5F93
+:1042E00042484AB2C518EDB78BCA25C09FF476DAAA
+:1042F0008CE967D2416C11F53726B8CA8AA15453AC
+:1043000018CB5E14894DDB97E5521B808F89CAE478
+:1043100011681CF7F8325DA705859019F4F911CCE6
+:104320002711C132AE0702FDCBD8FF67A8FC8D5123
+:104330007CDC255BEF03BD426F5836C043D434AEFE
+:104340004314141341DF72DD282C43BC9556917C35
+:104350000FFD6E89789D0970505D634CA2389B08F3
+:104360004B98AEB7A058150651D146329AA6C2FA5C
+:10437000FD33CFFA5512C40EC7E9D3D4058DF263CD
+:10438000B04AF6C0175C460A612A8F44219A78AB7E
+:1043900084BEB8985CCCD6B52E403F65928EF3179C
+:1043A0006B02C61E260A0584A3690AF2A133CE0455
+:1043B00081C9AB50B455A14A9A6CA899A380DCEA94
+:1043C0005297C7C938EB403C259202C58F764AC048
+:1043D000A7A85AF3819EDB43D6336FC2B83AC171A6
+:1043E000A94CD1810F1555DFF339019E39D248FB15
+:1043F0003504B60E16D730F911A67C1C4A41BD4DC6
+:104400004C5A1FD60DD4BFA5AA7508BF27CCBE989D
+:10441000A4DAA8BFBB53B21E12CE84EB50AA3389D4
+:10442000F04F9B9704F8DB0E85D9BAD0E57CB848ED
+:10443000FB0675C834813F253BB9DCC51F5DB0AEB6
+:10444000E9F7139B0CB2CA858712D2680817217E40
+:1044500005A05B99494C68B745D2C2A5AE7612C794
+:10446000EB16932C1B2882C7FFC7F5C4A3E5E625EE
+:104470004239A32BD859F3C8E81FE8AD8B0923DED6
+:1044800067C8F01489D2F7B650A13328A0DE5A04C9
+:1044900070FCEEE75C5F0D5933405F517DB018FA58
+:1044A000FBB8FA203CA20FAA34E4235EF6DB4917DE
+:1044B00068854610AF33D5A100E889CED470A340FB
+:1044C000E9F53F6473398C37220F0F7527753A6E03
+:1044D000D7A3F39A00AF5D071A9A4CD7FC57005E3A
+:1044E00040FE094C0F7754AC41FB87CA31B47F1CA6
+:1044F0003D2949834C1F3E456633FD38C4CA0759E0
+:1045000079963A1C5849FBED0C5A49A043A72367FA
+:10451000889DBCC235EF2B381D663EE5D763EFB4EE
+:10452000967C223DC6E1E1F2F4C233E4E9F0B32522
+:104530002E793A8BDB3F7E79DAE993A79D3E79DAD3
+:10454000E993A79D51CB234F47E6797AB5479E76ED
+:104550007ED8960493E1D005CFDA8BA9FDDD5931E1
+:10456000BE1EEBF5E9B1DE20E3F7CEC9ECE9BC7F76
+:1045700088AFD36D828CCFDE5256DF4BD7C79345C1
+:10458000FA77DA3BF2392559FD2BE9BC36D6327978
+:10459000DE5635C7063C9C005C81DD97BBC2143CEF
+:1045A00072BA905C0D78AF310DB79C8A70795DCB93
+:1045B000E535A98920FF22BF568FCAEBDE80D5845E
+:1045C0007C5BE9E853B6AE673E65313B7B449F7246
+:1045D000FA5751FAEBC08763E8D3848FFE092FFDA9
+:1045E00043551F8FFE41F62DB50B19FD1D7FA1C34D
+:1045F00047FF0E1FFD3BA2690FFD3B46E87FA587E5
+:10460000FE1DE56B92207F3B381FFC9B40F9A0927A
+:10461000C2F1B75A23C041FD3CE4FB994F19E45E57
+:104620005807BA94A1B63D091EA4FE9E4BBFFAF5E9
+:104630006A5BD5F87AC0D1A3D3812EA9227A5449D6
+:1046400013589F67D2D9AB8F1DFA513DFB2AC8136F
+:10465000E5A98C0DE228A85805C0FF2BE5E62F4000
+:10466000DEDDB02E7D1C9E4F3CFD16EA07B2DF203A
+:10467000432AEA9F269BAEFB4EC14A56D5B9D70BBB
+:10468000E3D733D70B15729780B8F8D02C8C333F13
+:10469000E7B92E9C1E06B83A2BB6A31F3822771E08
+:1046A000A54A09ED7ABBC906F95BD1E9A157578A3A
+:1046B000707AB525AF9AE97ECFE8D5057054023EF1
+:1046C0004ED80007FC0D4DF4FADBE8BF703DF09BBF
+:1046D00095D46F1147FD954E2D2D06CA47FD162A1C
+:1046E000FFA5C027F007D0F7457FC7EB0F4CB757A2
+:1046F000BD0C7C738228560FC8AD4B334A5A457E99
+:1047000040FB6063152D83BC48CA8A40FDE14E958D
+:10471000EA39C0477255570AFD426B2EA89536EE0E
+:104720004F2F4A5AE837D0F713422EFF0EDEBF0E46
+:104730007EB56625458A3F39D3A800DC1DDA72852F
+:10474000B8F028AB5652A6EF37AA4C9F76063347EF
+:1047500053202FABC8DC563A4E88FAEB73E9FB4383
+:10476000C94684AF435B57007EEBA42A12E6B1A88A
+:104770008A32287D8612ABF260377426285FABF050
+:104780003E83E3FBF1E3C0ED94436A86C82E7CC20E
+:1047900078A28B9F4252A620707F7A0FA513C9DDA5
+:1047A000672A6017723F34A0A76D8C4398D3E7F453
+:1047B0005096B934C0F4DF197449C81EB9D61936F9
+:1047C0009A00EF242D1065DED8FD51CB0DE5EED912
+:1047D000FA73E222D3AD750F0EC1F7B644205EB472
+:1047E000E1D2CC235096EC90D69A00FD9F797008C8
+:1047F000E4A8AC686DB4FFFB4A6228CF5A8E45111D
+:104800007F9B003F21D0230A3E7BB21A3EBBB249B8
+:104810007C126291E9B4FDC9C640BE07ED6B662704
+:104820008D3C6BD8F3A100D317B70422F8BC87974F
+:10483000A9F9887C903B8B1D1A6F088CCE8FFE17D0
+:1048400035BCF2A7A4B6CC530EEB959EF67EBB47C3
+:10485000924C62007C12850FE44AFCF2E41AD7F80D
+:10486000D70544C49F285E9101BAB40B5E7DF95A06
+:1048700080D93727020A3E0D327CF823B013D400CA
+:10488000FA03B1E872BB00BA40209969181391DEAF
+:104890001B72E0A3F45103E9B7603DC782435A1984
+:1048A000C40DC4D9C305D05B1364B4A7DB372C4750
+:1048B0007E70C61B0C30FBE63A8E37316418B5A803
+:1048C00047647D4F0AC637791C46DF0D7468DB30BC
+:1048D0006718C6B74B65D4534E3F416A78437CC3D3
+:1048E0000F8F7F7E7191F1ED87303FFABCECF4655C
+:1048F0000AD89D7D6A60599EB6EB93E83A4B40B961
+:104900003A6F0BFFFDF43B035F3EF87FCCE9731D6C
+:10491000A78F04F4A91FA54FAF4AE9538FAB04E951
+:10492000D32B31B9D10BF3498DCEC78FA7FFEA79CD
+:1049300039788E4703E93CA57F3CC8E08A47BD70C3
+:10494000FD77E1D98147E5F0A81C1EF54F0D4FC05A
+:10495000C2F5B389F3E32669488175F4A79227620B
+:10496000491AD72BC0B7DCA53F9CF5EAC0BB19E0BC
+:10497000A5ED364BC308EF5B944DA1DE995714F0BB
+:104980004CDF47836C7D45A37F9AF5E5C0D3C3E137
+:10499000EDE1EBA347FDD3D09D8E5D2B817C2511EE
+:1049A00003E45B42B2668810F77FE1ABA483BEFFED
+:1049B000C00C0CF75C04F28FC5EF1DFD4778DC06D8
+:1049C000BBD20959784A42FB3C6210D45751324459
+:1049D000C0CE8A83A4A6F65129D1316E03910B98DB
+:1049E0003F210BD05E4A841DFFF98FEDEF3AEC4F6B
+:1049F00030B7908F4A3E467F12ED6FEAA7D8DF5955
+:104A0000E00B935DD81F65CBC447D44EEFA67A9FC9
+:104A10001A99F4FFC2A85F4ED4B178571BB503E0D2
+:104A2000FD466A07C093484F9B013A8E6AC83AD840
+:104A300029AAF624C615B41F87481C7C626E87021B
+:104A4000BB831D5A524B8E07A81E2A31BCF12EA5DE
+:104A50004A1E970F3ACAA74F1ACFDF05499F524601
+:104A6000DB8FD5EEBFFA0976652A385A96D46A0CE0
+:104A70006E8D352FB1CE62C8212CDE38F25D8058A4
+:104A8000A0D7DAD4550AFA41A73FFA489C4718C97B
+:104A900008F823E98662F8E80327D0652706B5CE33
+:104AA0003B046ADA05933798432E38364347E5F0DE
+:104AB0007EAD39349E7C93D24DE0DF539AA23DB156
+:104AC000A5E47A72BC0EECC5EB91CE9DE513536064
+:104AD000EFC3CE0B8C4B1415ED58870F0F955F8DE0
+:104AE000F1BA8E8AAB93608F7704D349F02B8E9600
+:104AF000FFC0847E3B4FC749C800BFA21AE3199D7F
+:104B0000A7A74ECA14995709E523C023EE6FA4182E
+:104B10005F394E14C6B388D505FE42C95111E31062
+:104B20005B4A7E6C8AF5CC0F86FE65958E4BC75F1F
+:104B3000563F60C2BEA56CA956483BB31F671CFA1E
+:104B400027601C02DA38EB4AF0D41785C35F966BF6
+:104B5000022C4E9020F9B622ED834ACC2EB910E4F7
+:104B6000DBC87B0DC6AD7961669CC59F65A22B3005
+:104B7000B460C2FA19E5F7BC87CE440B8CF65B0D26
+:104B8000ABC1EE02FF2844940CAC4B3F3E3B65D2D8
+:104B90008C7EB36436B1FDDDB239E0278CC5D752C7
+:104BA000B2EB7DB01FC7AA0F697201F84C4A64ECE2
+:104BB00095182709189F4311D13B285C88CFF761CE
+:104BC0009F35A449EFBAF9F017A237BEDDA6568F7C
+:104BD0001BD7EAA0EB8BCC18BB3E281B16FA53243C
+:104BE000F332F84F12B910E725553DF7728AC231FA
+:104BF000CCED5B29C1F6FB8846ED3C17DE04D91CE1
+:104C000016419F44583FFEFECBE4C6DF82FED92208
+:104C1000A67F07CFAED43CAE77BCEB46B30CBEAE9E
+:104C2000CD983091F12DFBCB1702608F5AAA0974F1
+:104C300009D6EF811814D12A45262F6BA5D7001E5F
+:104C400093FE0FE35EE6DBC7088533B680BE77C709
+:104C50005DCC08CAD12061ED1D7E1401CFB06FE09C
+:104C60007BAF4A3E3C670F92D75DF141FACA2CB642
+:104C7000DFF97CB0B14C2A3F737EE023C2FE3C6575
+:104C80002FE433AA2586210F6007D087EA85ADD9A6
+:104C90005A7CDE9735905EDFC93660B93D6B62F9AC
+:104CA000DEEC322CDF9F4D6359AE6857008F3B2AF4
+:104CB000723B04F477E734BE403FD911CDFD1CF6BA
+:104CC0008F883DABF1058A9F1DB01173092133A573
+:104CD0000B1A6D685FCACAF3A4D98D36E59B1DD344
+:104CE000722B02D8BE82B59FCCEA2F93E6B2F63380
+:104CF00059F98B52036B1FE6F19BAAABCE926FC0A2
+:104D0000E4DB51516772AE2A817910A2BE8A08F4A1
+:104D1000D58E721E87E2FD50742A5744C7EEE726EF
+:104D200089EDFFCAF00AEC184D42FDBA23F5C9E03F
+:104D3000094B3913F1431635BE48F115061EA92457
+:104D4000E42FDB3F8BF3439144E79B6D375B71BEF0
+:104D50003379FF54DF7CC5A56FEE9082B82E76CCF8
+:104D6000F6CEE36CE37F8D9A19F08C5F3E847B6412
+:104D7000A744EB5A8996A3D7150AB20E71A42759F6
+:104D80001C8FE36BECFE6C1CFF1EC06FF9687BD5BB
+:104D900030F1FB051C5FF7AF6F443EB911CAE5A3C4
+:104DA00065C037C84B198473FD283EC71C4F73C9B3
+:104DB000F1EA33F99B4869CC0F58256A1E7AA7455A
+:104DC000CD035F5865EBE6E3E26BA9AFBF39BE7276
+:104DD000ADAFFF8AC703A4610E25E90D8171ED888F
+:104DE00005BEEF60A399CB0B9BC5FF46CA5C4F9DE8
+:104DF000AD7C7A86B7CCE81322D7C699FDC9ECCD35
+:104E00003F27BC8D7FBE86CB9E13A11D2BEBD42FDD
+:104E100042BD4ABCF54EFF2371A95689B4D5839D86
+:104E2000F12D8C5BB5D8212D449F27C353F22486E6
+:104E3000F1D947985CCA5CCCF4646616E64D08C5A7
+:104E4000F3361CFC77658DAD6FB8E49E52B581805A
+:104E50003C260B58DCDAE4717DA5CA78A807E11C72
+:104E60002E807C9612C65CD8AF785A929DFDFDA725
+:104E700081CFFFA7C4F815F6255701DF2D900D301F
+:104E80008BA3449FB40AE268F37F8771E0A834885B
+:104E900071F2688D80FC02F15BB77C382C05BCFA9E
+:104EA000DC879FC6205B671BB3E91D3514FECD93DD
+:104EB000539B17409CE71F451E6F1F463DBE69FE72
+:104EC000C400C0BD31C8F040F56501F681DAB24AD0
+:104ED0000196F8335235F6B3693EB3A70FCD9F1E46
+:104EE000C73C9668A409FCCFD094160BFA39397BDD
+:104EF000E00250959B53050276D4C9D70E7C660319
+:104F000081EF6338DF4DA93B703FC3FE57318FFB04
+:104F10003064A81FF675620D1AE6456C9ECCF068E9
+:104F20005F44F2FB683FE1068A7717FFC648CE84EC
+:104F3000ADA4C55189E525359087981D69C62A5CC1
+:104F40007E0CA5EB46185FB2D40CE89760CD00C28A
+:104F5000134E8A44A76561CA3202F19CBB56A91957
+:104F6000B0E7C4DFFF2F1BF721685F4FC3F775CC95
+:104F7000CFD0E8FFD83A370BF783FDD710D240FFE8
+:104F80002A355E3F443A760BD901FE4B63603838D0
+:104F90001FA8E0A203EC7F3458B702FF49C4F51DF7
+:104FA000E8DD0FE7A611FF0DEB221B806FC4EBE2DB
+:104FB0004077B181E5DF8956ACB0D8B5EFA21E0BC2
+:104FC000FFE488DBEE0E52FD0CF1799F7E1EE9674F
+:104FD0000CFD7C32ABFCE408A5EBD54166D73C1F49
+:104FE000349520A5EFBB416F5CCC795E1D64F1C4A4
+:104FF000AD92D908ED1CBE12671492868AFB7FA879
+:105000003F2A8203CF82BE14DBD249889776047D83
+:10501000EF17F1F7E1E2E3584111FBDD1C1C4C12E4
+:1050200097FF1CE274DD2C6408D889F61D31639F5C
+:1050300001EF33C80765CB74C1AE80C60DA760DD34
+:105040002BC918DAF34E7DC50DACBE3D35D804FC36
+:105050006657A88CFFDF3393E04F74CD9FE8D95794
+:105060006C08B2384C3B5F0F9B825EF9B098E3ED61
+:10507000A26090B58B72FDA7B525DDEB73A41F6E02
+:105080006F2C0B3ED20A78D84C5F637E5E4A463E58
+:105090002726DB8F74E4E498FAC0271F43BACFFFBA
+:1050A0004DFAE3FA5E79DF10D4197E056297BAC72C
+:1050B000D73624210E45A5FE471F4D04FC118C2335
+:1050C000B8DA33FD5FA0F5D44F5340578830AF3581
+:1050D0000590BBD4AECB4C30202EBED65C4DCB1B46
+:1050E000E9BA03D5B2326E3500BF983CCF4FD158E4
+:1050F0005C414EA6D1FEADC9AD18773FCABFDFD225
+:105100009E32711F33D6D1DB28CD07FA9849B0FB08
+:10511000121D5D8DB0AFD97EA94992B09F5A41F260
+:10512000AD29C0E75FA0BF7882620EE400B9AC9001
+:1051300064763E957CF3385FC1BEAB7A1B01BE201E
+:10514000BA84FE87CCED61D9975FE3ACABB1E06D7B
+:10515000F1ADCFF5BEF55993560C903B7D2F327FC4
+:1051600073AC7E9CF5492E66FB5163B5DB9865FBFD
+:105170002D5D41D3063C4B72E665F4BBE7C98E7CDE
+:10518000F7F063235FC795D037EAC11CB32388913A
+:10519000043A84E4B4057EB6C4ED74E7BB5DFCBBA1
+:1051A0005084D5FBE1A0FE4D0EC60FC5D2CC8F02B8
+:1051B000210FF6AC64EA5714A1AFB32F45E5C97DC2
+:1051C00041804373EC0F532FC60F8E9E4F120BE39B
+:1051D0001D942ECC0F4B7AE3EDD40FDB1D1C1FCE9C
+:1051E0007DFF1938B77379276BE902D32F06C241C7
+:1051F000757C0EE000D901F0CF93D34F42FFDDE57F
+:10520000CB0AC4254FDA1CBFB97639B6EB9E76B50A
+:10521000BE52853C889CC7DE77EC8DB66C9EC9F18A
+:105220005A96CF2CAACC9E3D631FBE86F187A8E478
+:10523000D04E08E7B6988122FBE9CE7EFC77F97E56
+:10524000BC1307182BBFED2E916460BD9FFC565E0A
+:105250005E4E9F37171E95ABE97CDFE4F2EC57D921
+:105260005308DFC96FB179DD7C70B7BCC8C5A76FC3
+:105270000799BD7333D73F743CD93BCF0D3C8E1D8E
+:105280002F805C78F7A88872612C3E6F4E1E3E22FC
+:10529000B9E6FDF67E11E3F844B2BF04DFDF9C17E8
+:1052A00003C5EC767FBCA339F91CF673F29EBC0CE7
+:1052B000FCF1ABAC22BC1E64F383FCA29B9FDA2DF5
+:1052C000832D7736B85FE2EB27CFBF3F79CF30E64B
+:1052D000F3C60BBFC73CA5B83D6C427E13D006FD9C
+:1052E000B405FA6E80EFB2D31F61BCDFBF2F1B86FF
+:1052F000F9CD1D2D772F60717422E596E17E4E4D1C
+:1053000020500C3FFEF985617E7347F1BA09F03AEF
+:105310008E3FD39B2D1C918263D7ABF3D9FE821AAB
+:105320002CE0BEE3D9C68F1AB43F173F3970F49E04
+:1053300085BE7D0087CBBEDE6478F769CE366EAC65
+:105340009E7EEF8947DAA47622C80B82361D695FFC
+:105350003F0BE2CD155684F420FF4B1F80DC70E23A
+:10536000CB15CA97C8DD7346FB4BDE40EB3DFDE530
+:1053700030DE5DD144E50EB5CB88BBDEB57FAE80B7
+:105380005C80BC0FBD13E356A21E413925D6486F81
+:105390000D295EF830CF97CB8D8DA504FB6D9F2C2A
+:1053A000303B829023B07F21E98E3F41E53AEC67A4
+:1053B00068F3D09F5824CB45F304A8BE5D245F3426
+:1053C0007A4EC1C9576F2F65795F442D7E3E02FC2E
+:1053D00003371F38F875FC01727AEEDB60AFB40555
+:1053E0006AEF003DDA3979653FDA61E54CCF80CD6F
+:1053F0000FF3302F275CCF33B8AFE1703A71330A27
+:10540000DF35005F906488901A85CFC94B236AA26C
+:10541000287CED63C0D73E0A5F12E113EAEE70C745
+:105420002D1DB846FA99BC10ED3D3BEAE84786E7EA
+:1054300020E019E171F2B2199E3363E33983F34836
+:1054400038784E3BF9F76403F873F453D1187B3E78
+:105450009272F50E90430E1F04399CFE7324DDBE3C
+:10546000BC3027AFDA394772B63CEB8E69DB8BE68E
+:10547000518E9E376079B34477CE1B6458999F2331
+:10548000E9FE7035AE5FE71C0949D47BF0B945F6FB
+:10549000FB9F36B72BB87EAC61EB65A56CB5C890A9
+:1054A0001F91E81CC4F5C0F5D96D3E3BC379FE667B
+:1054B000B293B7E95F07C3AF7ED3B50EF68E4D9FAB
+:1054C000BDC5D6C16F7E3483F1D9C1F2A271A5DB0F
+:1054D000942B3D74199D17F34330258BE265674289
+:1054E00059B192FEB38F30F87B04EDF31B287EFF99
+:1054F000EE42EBAF61DCDBAE1A9401DCCA661280CF
+:10550000F13673BF6A89D81B7E8DCEABDFAA8EAF12
+:10551000A2CF9FCB42D1FC9C7BA95D07FCDE9155BD
+:10552000F079F29519E3C6B7F7646D8FFCDC532769
+:10553000A1FCDCD3F5E46023D8C3899A397C0FA899
+:105540007D22F083AEEF017CFED4373EC5DB4FDD1C
+:105550007C7DEFCCAB799C9A9DEF72E62F99F98513
+:10556000350916BFCD1B80AA1CDA1D151A310A0495
+:10557000F1F022D0FBD61AD20AF1BCDB6E304C78A7
+:105580003A78A0F80D4FA7DFEF787EDA1CB71D7CC4
+:105590004188F113A92F63F6A044EDD2A2F1504641
+:1055A0009F07299EEA30C9BE80F2B91BCA2E3C6C07
+:1055B00097AD37018EAABB23C88755197E4E87E762
+:1055C0007F0844395281FCA5EDE6FCF5CE23C85F87
+:1055D0001367037F0DCB81B1F86B18FAF5F397527F
+:1055E00093B141A7F484ADDF021E4B84410DFCA4AE
+:1055F00073EF2E201EBB1D3FCA263F037E9AC2F3C7
+:10560000B6F08F8E7B8EC1E8521162FE65BC2A2FE8
+:1056100004687DCDFEF704383FB291C7FFCF9D3CB3
+:10562000FC2FB06F45FE5524B04E27D73DB5701105
+:10563000F82FA6320CFB01F105838780EE615A0634
+:10564000393479BD1680F11D7FA1B2795080726C1A
+:105650007D5E20AE3C95909C41FF684AD59ACB6117
+:10566000FF4098F2F606889F6DDC42303E75CEDA38
+:105670004201E4E794869006FEDDB9293310067FE7
+:10568000EF0E62409C27D5CEEACF3195348C1B6F4C
+:10569000C930252B65C8952EFB5AADB26E85FE57D5
+:1056A00087AD8A10E43B180C8F4A55C184E63B82D3
+:1056B000D49EA5E5F0828299463EBC93AC74C9B5F0
+:1056C000F343DC1FA92166DEC59F3B39936F59BCAC
+:1056D000277C631DB48BF07C9EF5A686716D968F3A
+:1056E00017063ED5914FCF0BD17EF4E6C1E780146B
+:1056F000B7D51826E09BAE4F8C7351382A348CFFF7
+:10570000CB18E7A2747B0992F1D580976E4A95B9C0
+:1057100017E8F6AACCE2013DE5057203C54392D233
+:105720004B8778D1B1E7C914DAEE9F2A4422C0969C
+:1057300046D22EFC88964B299EC037560DBBF00AE8
+:10574000F8D14D2570B68E906ABDA716F8A1999D27
+:105750004FA478FA2CE0294E86082C597571E11077
+:10576000C0BB47CAFCE21EDA6ECF51D1B075D7BAC2
+:10577000E1FE9C83AFA95DF619F61193D3A604ED63
+:10578000162B25B83E0E7379B65D4E7F11F0B258D8
+:105790007B1FD70B51277CAC38BCFFFD29C3880386
+:1057A000FE5627576EABA176E9AA962DDB6A68579D
+:1057B000CD2D8F6E053BF5B5DED531B73FFD56D704
+:1057C0005FC6D87ACAC4AEA5F35AD5CFFCE49341DC
+:1057D0002B76092DFFB25B345A619E7C5F7B0D27CF
+:1057E000C1A1FB431837FCE56E01F3109BFB051BC1
+:1057F00052134F965A53807F7EB9E3AE29C5FCE819
+:1058000035C784009905F52BA714CB4F69EEDF88C7
+:10581000FBE0CDD4C1368BD86F77058CA400790618
+:10582000D9FDBB203EECD81BDF08E9582F3B7E8416
+:1058300062607C65E1AB9F4F425E723A647D1DF011
+:10584000DB7EFC73B8BF7DB8746912ECA975AF84B8
+:10585000709DDD256766682E78EF8AC916F29FBABB
+:10586000CD4387F5A1A04F4FD93C1E4E9AE01CA70F
+:105870001D231AEC1F2F560DD4E31F0C09D87F07E8
+:10588000F72FFDF3955ABEBBD5ED67490983E8AE06
+:1058900038A258EB8D27E6607D415C30C4F21F6F63
+:1058A0000B595B615EB00C5BCA20EFF5F1AD4C9F0C
+:1058B0007AF388ED46ED65888FDBE7CB3AC0D733C6
+:1058C000D3D10B79B41B5A252A50619DD6923D90B5
+:1058D000AFB811E0A5535D5C9BB703AE798CC58F63
+:1058E0003DD996ADA00F5B816610F7AD0DECDE23C0
+:1058F00080BF93D90AFAB42F6B637D4FED9197C1A6
+:105900006EECA9D2E16C1269D57226C8BF563D7FF4
+:10591000B41AC70FCC81BCDDB66C17EBCFCC1F6DB2
+:1059200074BDEFC8E6D87B3BBF6CAAEB7DA8E57BD6
+:1059300038EF56B27BD922D77B07BE56AA99A71655
+:105940007DBFB70BDA77C37BE27EBFFFA85E7FE641
+:10595000FB1E75AF027684C0FD8E5635B70CFCCEAB
+:105960001EAD1AE5528FAA637EFFE8FBC5C5DF278F
+:105970005A09CBD7F2BF9784A2EF938140F1F70C7D
+:105980001E3F3D285FBC1472D91911CE1754B66161
+:105990007EB8641870B68D14A6EA1F043F33DAEEA1
+:1059A0008D10B34F5A1CFED30D94DF54F8DEB1D1E5
+:1059B000B50EC4C5069150DEFADE6BD4EFF2C83DD9
+:1059C0003F1F92FE30F0E144BE4E12693C177E3616
+:1059D000FEA2FCB895D9674DF80C1196B7EC6F771D
+:1059E000C2B1677CE3B6507A29CCEE1EDE371BECE1
+:1059F00062C366F3D2D66D44F99D99C1FC4836DF87
+:105A000033E695F0FA93CEFB76BE4E9CF26470249A
+:105A100040FFE973141DE27A9A8D7A76E1AB2B5838
+:105A20007E0DC89FBA33E5CF58F3BE37DBB40DF611
+:105A300091BAB3163EDB8C391AC8B3365522058CA1
+:105A400057A4E1503F09D6E4D9B9516A42113A3F0F
+:105A5000B9CEC47877B086ED3A4B89CC8DE8671C17
+:105A60000B936929B03773E44617FEC29CDE91D3CD
+:105A7000D99A16EA97875BD6A0DE88246F403D72DC
+:105A8000578C58C5F635828ACCE5507AAA42E7ADE4
+:105A9000B4EC2D2E7FB6B0F3CC2289181B503E32C9
+:105AA0003DFEC1B130EA0F51B543C5E2BC52CB6AED
+:105AB000D45B0B01F7E580C7F988C7BB6423F9AD58
+:105AC00004CA6990C0E47074DECB56FDD9F1196C3C
+:105AD000D98AF3125BBE89CF51FA1A183B12357678
+:105AE000DE0ECECF4FD3817E063B5F666686C55203
+:105AF000773FDB593FD6B671F173E1087ECCA54AFA
+:105B00007911BC3C415E06BD71324A34D88F3AFCF3
+:105B1000CAC538FEBAE36C3D2C566DB64F4EE91A35
+:105B20002AC5F5539B718DD39BB5B7D504415E361D
+:105B3000E3330CF802B80C3E9F1AA6872817E07CC6
+:105B40007AB2196CD791ED427E0AD79826E80555AE
+:105B5000CDA03C1E695F4FDB13A8CFE3FA8C423D1A
+:105B600071D573FC846B06701F2FE8FF3EE9D45B90
+:105B7000C8675183C2E95A3F541FDF02F890135D92
+:105B80009EF74A721BE2D58FA723C767C487C689D1
+:105B9000CBE7B2FDA8171C7D934B194D608774733A
+:105BA000BDB491EB9F4DA03F82B0AEBAF0B94F4962
+:105BB00071BB4CC37C388C2B53B831E103F5456283
+:105BC0000FC429FA82AC2C56913CE847850CA0D230
+:105BD00055215F732A1D4762F5DD0BF47C1BA5631D
+:105BE0005FD8403B9AEA096579117FAA5BFD36CA06
+:105BF000EDBE52D6AE2F9553EC049E139EB3C7153F
+:105C00005F88CA2C1EE9BC8F4672695696B03C5616
+:105C1000FFE1E8B735E83F5A66A07E8D56E734DBF2
+:105C2000F59DD3AE4FA6FD2546DFF745F2CBB05C20
+:105C30001B18B7FF1E750F83BF8CC35F9D67F0D71E
+:105C40007AE1EF91F2CABA71FCE8480DA58F27BF3F
+:105C500094D2C9A33FF22C3FBBAECBF33EDE90F310
+:105C6000940FBF3263D2906B9C234353C7E597B721
+:105C7000805F5C72FBADB0753DA1EBEB64D7F58B3B
+:105C8000DB17D072D09A22D0F214CD6E5F3699DA3B
+:105C9000AD5C6EDCD8B212D7D79ADED532D869ABFC
+:105CA0005A6E61E55D02FA456BB85C20C49241DF33
+:105CB000BC93CA9CECA1FDFC5261769BA357D768AC
+:105CC000D67328677C7A754DD25A5A4CFFACE90AD4
+:105CD0007AF4AAF37E55CB6A943F23E5DEA90C2E15
+:105CE000AE1F57811C9F8BE34C69A276DEAB4A182E
+:105CF000E1786DDF7D53402FBD23E4AEFF06E8E37E
+:105D00009B229E7328CED3899BA7434CFE12C97A4F
+:105D10000ECE69BCB6411CEE993D763F6BB8DEF005
+:105D2000F7F30A97E36B381E42A7E328DF56EDBB73
+:105D30006F3FC603A5DC941594DFFE59513C719268
+:105D400055D6368FBCFEA4F3FEDFBCBF57F9F81F53
+:105D5000F77BA77E4238ECDBBFCB9F07F6C27F966E
+:105D60002F765653BEA0F89B148E78ECAD3F962F3D
+:105D70001C7F64CDE92C013DEED0211DE2F94B12D0
+:105D8000857BA61BFFB326AE70ADEFFF50D879A27E
+:105D900072388C5B04FFFEF9BFD31C0940FCF49DF4
+:105DA000A34BF0BC4133C7C34E39777DBA6E140F95
+:105DB0006F513DD5EE5A6F37F6AE7EAE81CEF3A66B
+:105DC000BDA952C1C5CF37EDDDB2B43201782B9DEC
+:105DD00003FAA4792FC3DF8DFD1BB6B57BFC410709
+:105DE0008FB9DF031E178415EFFAAAB596068AD875
+:105DF000AD6B0CEBB94011BB752C3CDEC4FBDB1961
+:105E0000CB6D7A987EF73A7970452BACEBA38BE299
+:105E1000E1BA517CAD4A323FFB756E5FBF45F58EEE
+:105E20007BBEAF4BFAA6F91007EF1267BBEF077AFC
+:105E30005DD137AD28F65ED5FFA958FBD7764D8BDF
+:105E4000AD2C224FCFA017D7A376A3F1761EFA79F7
+:105E50003564B4D1260714EBDA30857743EC9266CB
+:105E600090F377BD26E0FD0DAFAB7BDE81F88C5F54
+:105E7000EFEECDEA82DB6FAD1923BFE5BAB0C0D734
+:105E800007C3DB39196F1E6CBCD95B561BBC65851B
+:105E9000B8CAA9D17E10A279A3F77A38FA00FEDE3B
+:105EA0009B88F62EEAEBE050E96AC8F7595893C38D
+:105EB000FC930FD480EE3EDF7AA65C238511BD8370
+:105EC000312CA530A24F3E467E737BB669BB3BFEAC
+:105ED0003B725E91CB0FA9E5FAEDC0F747683FC76B
+:105EE000D1CF6E75F6FDF97D25790FBDC49687710A
+:105EF0009D684EBE2EC97BE249BDE1C2CB9087B101
+:105F0000BBFB687BB06234FFE791F0CBED90DFE242
+:105F1000DC1B40CC6DEC7BDA3DD0B764DAD57B8BF3
+:105F2000EFD3B6E3F84AE138C6E9620D19964F4758
+:105F300075DF04C843A6B81D44FF2287E77FE30B43
+:105F400058BCF0BB9CCFC2CA293C7FD4BDE0671AC5
+:105F5000D49F9CEC6DEFB42343BA09EBA5E45276D1
+:105F6000AECF697FE8956B4817D84B0D813CD0893F
+:105F70003E21F79E44674A79DC3F34133C1E9D1B4B
+:105F8000371E6DE61612C87FA1A4C4BC33880BB7B8
+:105F900081BDAE4B984F2F1912E675AD8C5B07C3D0
+:105FA00045E2C7CE3863F3091BE7DB591DF3116BDC
+:105FB000F6AB88A7B66302CE675BB676EB1B41B43F
+:105FC000CB591EDDB5ECFCC08429C6711DE4CF4B56
+:105FD0002C5E4CE99E02B933E95889C6F45CE6E2CE
+:105FE0002BDDF7666559DE4DD932B64FE387439412
+:105FF0008D21B0AF5A8E850C3867FD78D0FA59984C
+:10600000E25788B5CC00BB67C2E506C6BBCB26E924
+:10601000B3058A87EE1252482769B9443F001E60D3
+:10602000EEDEE796A8749E6521C63743DD133A215C
+:10603000CFB86CAA3E9BE561972C853CEEB273F419
+:10604000F7E1FB8E1265E932CA47651426763EFFFA
+:10605000C812D8A72FBB80952B7BD9F78EBCCDD18A
+:10606000F50078D898B5B6039EDE0EB378B1261940
+:106070001857FE77E0078853D175F106DE534304C5
+:10608000986788D78B2D6BB6BF3117DE73FA24491A
+:1060900081B8D6FDDF5D680D03FD6E4D0F2D8514B3
+:1060A000A960C2D9E7197E19E8EF9CA35D22D6C585
+:1060B0005F73C9A76F46985C1225B62EFBB249DC08
+:1060C000DFE9A7F8C67814DFEFE9CAEA84F90FB56B
+:1060D000F894222C8E5042F4F8144AAF128BEDA79C
+:1060E00096585D83EEF315A4AED03F2247AAF1BEC9
+:1060F0001AC4EF9448CD1258972D63C8CB0887ABCC
+:10610000A4E5A7FD808F281C3CC0F2E1FE37E68E97
+:10611000CD8FF7AEFC81DE49E95516097780EBE2B9
+:106120001F4F2216FA23D2E5CD8556B423482644C4
+:10613000F940AA5B433A6959AB96B06C3E6E923512
+:106140001047E7F99A747D5445601F2A99C1BB082E
+:106150009CF5E1F44F397F09DC8B10AE1F403FF016
+:1061600064B478FE6E47F614C66517454AD9FE7CBE
+:10617000759301FA6AACF673222C8E7992CB2FDAE2
+:106180005E77EF3B2C8AB07894ABBE76B5A79E7D48
+:106190006F72FC9D2C67E328D5CDC5FB19AD4FFE72
+:1061A00085A79EC5754F568CD4D7BAF5ECC8F79322
+:1061B000193E1A7B521DC0FF8B22CCAEA27061FE2D
+:1061C00030FDCE70C7312E8FE81E392F27287E3C38
+:1061D000768CA4A8AE7358444B24ABE6B1FB80E0A8
+:1061E000EFF0D0D77E710FA5DBE6A3A20121EE2050
+:1061F000D1032C4F536F7CAE1EDD54CFB9A170DD9F
+:10620000C15D6EBF6833F583C63B071AD4A6EF02A3
+:10621000BD43FB8D7F763C7DD945EE1FE997F27932
+:106220007FD05E0172A5B367CE92049513FD61879E
+:106230004F162D81B8647F94C989AE4803E2A94BFB
+:106240004893A5E01F0864601F459932656818F3FC
+:1062500007A2D353AD14B59B08CFCF4C06304F796E
+:10626000D325D716202F40FEA1ACC3FECCA686E5D1
+:106270001A93DBD27F403E6407C87A8A874820831E
+:10628000F821FFC0F2AB3B21045536CE7C9383FD51
+:106290006E7F73C79A6BD97E6BE2D477DE70CD2F99
+:1062A00064F2F809971BB646ECCFC27AA9D176BB47
+:1062B000F5E9F3117ECF607619EA01E7BD215B9B1A
+:1062C0002310DF48068E8720AFD1BA7C2BACF30CAD
+:1062D000E7176ABF2A3C3F1FED1BC78EA1EBB2D068
+:1062E0009E18D56790F7102992BFF150B619E52D89
+:1062F000E1FBE429CE2FD5E4AA784180B84706E532
+:106300007047D6C667F5B1490188BB52AD6F4C687E
+:1063100080F675CF1E013B7851603844F542AA4B98
+:10632000FA9DDBFEF5E7553E18F1E65512B12EF069
+:106330009304DC7B11C0B8D8C62CC5DFB433E109A7
+:10634000E96623D0CDC9AF0CD7B0FD0451D5D8FE36
+:1063500038CFEF4CA9EC1EB514CF033D1B3C077C96
+:10636000F09C20758D26A55BACE521949FA196EF4E
+:10637000A05C0D3410B48362ED04ED0C078E405523
+:10638000DA86FC745853F05FACE561FC0EF0047AD9
+:10639000DAC153A8E501ECC70F8FDC50C0B82BA5BC
+:1063A0001CBE471F86CADD94C1E7E16BEFB43B72A8
+:1063B000C3446C77F72CF305E08F17406E41DE4F36
+:1063C000B6BFFF0D8C4FE5FB81AE0E7D0FBF32894E
+:1063D000DDD75947304E2A5DFE3705D87FDCA7054B
+:1063E00030BFB66DDB6B782EA26421DC088AFA869A
+:1063F000F0F81CAEA3A049E189B9F8BF8EC2E1E272
+:10640000FF7FE3FCDB95ED423E39C6E568573687F2
+:106410006522FE2DEE0B9DD0496602F5B3BAAB06A0
+:106420004CA07B0DA53B71C54395C9E900AC97E035
+:1064300036369E7F1C872F1C7D1ECC0DD8D00FA119
+:10644000FD2CAA80F78CEEFEEFFC741FF6D1FDB296
+:10645000D37103EED1A8E1F9BDA485FEB9CEDFFA70
+:10646000D7BF437FA77CF89519F1A171E46347B6C4
+:106470007F3BD8070F67F3F8EC48ACC3734CD4FEEE
+:10648000C8835D19E4F7F606550BEFDBA165038EB3
+:106490009AC849562FF37A59B57ACE4B6019EB83D7
+:1064A000E537B486719DB37C818EC4AA6721BFA0F5
+:1064B0009AE70F3CB26B15DE4BBAB19F98309760EC
+:1064C000F9FA67A1BDCEDB7726D73D0BE3A9A6F38A
+:1064D000FD3ABC172BB48BB50FE5ACDC42908B0DAD
+:1064E0002C8EEB9CBBAD6ED1707F5B71EA3323F5D4
+:1064F0003DE7D1B26EB27A35677DFBF3409F052C44
+:106500008EEBD44F69D610CF31A887EF2DA73EF37D
+:106510000F505FB58D7DAFE5323FC37AD55B5FC964
+:10652000FB8F43BD2B2E3D2D475191C0FE76C3FE00
+:106530008408E57AE49ADDD304E46B5636C86EC865
+:106540009F6F530EE3BA14C33FC575EBAC9F8EEC3F
+:1065500000AE9F87B307F1B937BB1F9FCE79A39ACF
+:106560007E96BF30356136829E5A52C2F8DFFF0CEC
+:106570004F1E40BE8FC388E06B41BCB71ED7D3709F
+:106580000F96D378DEA88AD6EFD48AF13B5BEF531F
+:10659000E81FF0A9C367478E5F8C4F7FBC92745190
+:1065A0003E73E737DA796FB965BFB79C19D8EEB695
+:1065B0003B49F3416FBD55F0D69B47BD6563D0D3D2
+:1065C000DE816367B67FEB62B487D9BED3CE7252E9
+:1065D00001F1E31C3F37D907FB50B87F90C3FA7E27
+:1065E000BE9FF040B605CBBB603F621AC6D7F17DB7
+:1065F00077B669EB62946BCDF85E6E7968EB624AB0
+:10660000AFB525FCFEC1B8B5B6E422C8732147403A
+:106610001E53DB1EEF459648C686BC8B9D61F35A20
+:10662000882345F4411270E1EBEB258277BF5FB21E
+:10663000883B9FFCEB9C8E8EFD6D4EB609E415DB0E
+:10664000299B403CBBA584D973866C7EBDA41CE607
+:1066500049C751C10F66E7C8AAD6EB187F92A95F58
+:106660000EF026E97291C19F36D8FBC919EF7EC69C
+:10667000CED221CCDBD95B4E70BF58ADA3F377C926
+:106680002D67BFE856657917CC37CAE38BEDA56B4C
+:106690002A985D93C3B8C076D93254F0AF8F853055
+:1066A0003F245CC3F2A7D685D3DDF0DDC957EE6386
+:1066B000794D6030821D41E58CCF4FFA2B6837A6AB
+:1066C0009F148DA09DE4F79362AA77DFB72FCBF2DA
+:1066D000E1BAB97FD4097ED334887B303FC9C98FF2
+:1066E000F3AFC33E9E1F7A6F96DA59B0EEA29D7843
+:1066F0003F72B73C60C3FEBBDDA81CD857E49CFBCF
+:10670000939C1FC221CAD9D06F5D81E9B180F62F59
+:10671000259F8173D1943FCA609F2A5098E8F2BFA9
+:10672000C0E46E2EC3E751710E9CCB28EE67FC844B
+:10673000F7DFC9FD08B9F2A8BD1BE8F9C3892990A4
+:106740009F321F570E150A2817458270B66BCF6A05
+:106750006E3FC2E9A79DB0FBCF1C7BB497DBA36360
+:10676000E911B58EE2C3C50F51D96BB78EF55D7BCC
+:1067700056F3DC0FD9279BF622A06380BC0F76B4BA
+:10678000F33E1A324D38D748162977B8F11BD4E8B2
+:10679000F72E3E3D45FD81F1E25AD42FBE1FE8267B
+:1067A000A89C1EAB781E0CC90460FFA8EDAFAAF729
+:1067B000B8F3CA05CE37FBB68D1F2F83FBDCE1FC97
+:1067C000783BDC573203E4B5E6B91F6023CF0FBC3A
+:1067D000EF9C7F22C75DF8FE035FC7EA9060021C52
+:1067E000C1AF99EBD245EAFF50E2C41F89549960CA
+:1067F0007284E517A7D1CF95B83D1DACE9C27BE403
+:1068000083AA7C9CE747FF01D6BF3FAF789F6AE031
+:1068100039CD7DAA0C3E0B695B1940F8C2D3BB2A67
+:10682000DC7EE171CE0F3D821D07FFC07E5EC43865
+:1068300044E4FC65C62ACFFA4A79F2862A2C8A6794
+:10684000175DCE966F2A992C7FB9BB849D1F6E8BE6
+:10685000DD8C72E331393D41A5E5445AEB027F1FDF
+:10686000EEAF00F939D22ECAE4CB3FC6CC6E98A762
+:106870002337BE1235932067FCEDDA785E9533AE90
+:10688000E89C9B863F3ABFEA76EB61A07FD9171759
+:106890001C073F654FFB9A79200FBB4B44272E7B8B
+:1068A000240870E8ECDCD92C55F7DE73D29EB121B8
+:1068B00045A2EC8B9717DA69BB0E9EB76D36D9A44B
+:1068C000589CCFA18BA4B1F36B4E1EF3CAB889F2CA
+:1068D000F0D77CBD974DC82467BBF07715E7DF91F3
+:1068E0007C7AC2E3C5601CE97C3E2037A14CF5DF11
+:1068F0009754067FD9A4742BCA1D91649EA6CF49D4
+:10690000DB08DE93BA372AA3FD0DF91637C13AF832
+:10691000492D61F7FD99580F7EF84E8C3FA6D16F37
+:106920000D59AA0EFCA6C07EC954B85762009F2A12
+:1069300019C4678C0CE3538388EFD4D1FB243B3517
+:10694000EB4AA0CB5AC53A17AECCBDF30B83AF428E
+:10695000BEDB952AA3DBDAB0F965A81FA7FDF5F029
+:10696000BE4B32AF02BED82A995F51912EDE738999
+:1069700063F159E9146D25D0B5D39631CED8A96A03
+:106980002B20AFD2BE9BE5EF379FD06EDA0B71871D
+:10699000F532BBBF65C94B6CDD48D24EF0DF4BD73B
+:1069A000D2B580F8D50E819F22733F455ECBFC2285
+:1069B00079B1CF2FAA77D94D940EF70B832B20CE28
+:1069C000BD41FDCC5289FA05F787077F0EE5FBD460
+:1069D000A54BE1FCE1FDA5832B203EF9847A0596C9
+:1069E0001F1486B17D41BD8E95C3C3D87E50BD8135
+:1069F000954B87B17D57682DC633F3F7307EC81F9E
+:106A00000A57C2FED1E4F5D604F77DD4930B3F5F5D
+:106A1000087A7CF27AE30710B274DE67381F4FAE53
+:106A20001DC4FAC87AEBAF21257572DD005954F701
+:106A300029F45B45FB057F14FA05FB42B73F9D7EB9
+:106A40000759BFF54EBF2FA6C54FA5DFA3ACDF3951
+:106A50004EBF2F189F4EBF7B59BFE739FDEECF07C2
+:106A60003E957E7B59BF539D7E7366D17E53EDDE8E
+:106A70007E7F09DFD375942A54B442DC22556BCC57
+:106A80008350578AD21DE2909FE0FB67617DA4AAE4
+:106A9000E8F7F4558AD2F7137E1F8842FD20FF9E47
+:106AA000D2F1137EDFAA42FD51FE3DA5D727FCBEE1
+:106AB0003102F57BF9F7942E1FE77B9837BEEFE59F
+:106AC000DF51BCC377951AD32B8736C8956E3BD45C
+:106AD000C91378D0775FA4F394A34CAE8F8E5B116B
+:106AE000983E13C6D5026B705F6D3BD6A7766502E4
+:106AF0004B81BE1FB27EF21B0685792AF0C9EF05D5
+:106B000068FF0755E4F6421EDB9F7B37B593A9FE6D
+:106B1000D1F376C0C47909FC3BA112CEFD9CB3D65B
+:106B200098B8C135AF730ACF08D3A3F07E40807107
+:106B3000CF510D02E3C1FBA9D1D17EA17E35D46B2B
+:106B4000A66F3D73B8299C6B503F75B2F38D23F04F
+:106B50006A018017E83E3DEA9A17856F4D11F8E407
+:106B6000A4173EB9701381EF640A17EB9FC103EFBE
+:106B7000013E99C2E38EA33BCFC34322FAB91D5510
+:106B80002CDED431F4353CFFDFD12BE810EF6D9FC4
+:106B9000B8CE396F85E5B6E89D76733D9C2713091D
+:106BA000E8F1F640861C027DF18048C00EDDD37D01
+:106BB00035BB0FDB77DFC797381D9D670FDF3718B1
+:106BC0006B9FE0CBD1526C17B9E06E7DBCFD8405A4
+:106BD00051EF7E42E4FC16DD6DAF7D392A78EA7B09
+:106BE000CEFF86EEC6C397A3CC0EF8429478F60B80
+:106BF0004A2E1CA31F5E7FEFCC3BF5BFF0F4C3CE43
+:106C00002538FB09F75EF88DE2DFF3FD84CBFB1E30
+:106C1000E984FD9B2F47993DD673DE9DBAE52A97FF
+:106C2000CCBA1BCB9D15ECBD7FDE67DC3356A5EFE0
+:106C3000F2F8FBBEFDB407E0FF55A0BFF867D1A294
+:106C4000FB6A7C3F1992482AC05F54311EF2813A98
+:106C50007D37C451814F603FF2F12A7D0F949788B0
+:106C600077635CF27B5AF59C90EB1EE44DDC8FDC85
+:106C7000057EE4343837A573BF92EDB33D3EF47A18
+:106C800004FBAD923088BA13EC4F5ADFBCB0757B71
+:106C90000DE523E37166472E117B274EA3ED9E3849
+:106CA000C8E2B81DD9DA5DF07D2EABE3735FD6D8AC
+:106CB00005FD2E810BE3E9770F2719FF2E11D7125F
+:106CC000907B07E0773FC0CFABF2C66942A419FDC5
+:106CD000B6D0B11B0B1157DC977EF705BC3F97C2AE
+:106CE00005FD546AF676189FF4B37B529688A72365
+:106CF000EEFC327FBF32C9101BEE953B9829A09F56
+:106D000047EDA045B4DF27948C06FB9DCD2B7F1665
+:106D10002866EF8ED94F7F06F1EBF47340E5FDDC7A
+:106D200054267EA27E9EF2C2D3A7B1DF3DF17F3F03
+:106D3000563F7444138E588678DCEBBB51764F0D6A
+:106D4000C51FF2477B9A1C1021FF403CFD05BC6724
+:106D5000FCDC049ED1F8B8FDFF04D61DC4E1C4F7E5
+:106D6000B6DF46E1FC5E81D19B9627DE0E747D9CEA
+:106D7000D175E47BDAFCAB73C6996FC13BDFEF25BD
+:106D80003FE97C5BD01F0C1DFBDC51B81FEFE12AF3
+:106D9000F63DE1F16C99AF27F9716EDF8EDC63E1AE
+:106DA000EBE713DE63F18F516F9C9BF235DE63F1ED
+:106DB000C18B22E6053BFAD3DF8F13DFEEC9B2FDAC
+:106DC000ED8D7CDD3D45FD6D783EC9F7BF1FE5715A
+:106DD0009C87601DD2F2312E8F1EC91A84DD43D4E8
+:106DE00080EF170E6D08C139AAEF3ECFC63D870C64
+:106DF0005442991C9131AFE1FBC24025F827441958
+:106E0000A884F336BD3C7EE0C0D33BFBB94A902753
+:106E10008F07AD4AC8EFB037C4F47D741E877E3447
+:106E2000F13B90A731F0B48CFB2F0776C8E7403ECA
+:106E3000F7F70E318C9EE2F06C8032D07D36E38322
+:106E400043C7FFDEBC05D6A540F01EA1872F7A09F7
+:106E5000E34B472E7A4E1F2F8E7F8D6A9D0239A7F6
+:106E60001E647EBF6A68781EEFE3F7FF12E69DF7A7
+:106E7000450BBA36FE38C1D845678E73E87808FDF1
+:106E8000E73E3E8EFA143BA74BFBAF84FA234FBF7D
+:106E900084E794FA2ACEDA7FE978FD3F319BAD8F03
+:106EA0000397365F7B0B9D57EF33324AE323CFBC0A
+:106EB000742DACC73E8A7FB083FBCED3FE0CE6A90F
+:106EC000CE8960FE7C9171A6C45CFA64749C49E72B
+:106ED0006C84EF816E4829EB5AB8C745AD9731AE47
+:106EE0004FE960C2B80EFEFAA60D5D0BFB166A6B89
+:106EF0004C87F8D18167DEAA2CB61F4DC7AB8B1526
+:106F0000A18F1F6F0F43FFC037B47FD8173E72E8C1
+:106F1000A54AA0CB1333CF8AB78662FD7F3F385C8A
+:106F200009EBF9FB4FC84DECFE87AE8970CE563E9B
+:106F300062EE65F1230BE56E506BAC073FF64DAE8C
+:106F4000D7672B6913F40A65792307F743267DFB7E
+:106F5000835213EA95925A9F5C3A768D09BF4FE2AD
+:106F6000E819FF77331562029EA653FD657BC6675D
+:106F70007EB452E56D3F5D49DB701EF482B3C07193
+:106F8000D1E019701422E3C071018763D61870CC68
+:106F90003DEAEDAF524B17F07707697F4F6B67F60D
+:106FA00047A4531857918F10BC0FE2FCBDDEFAAF17
+:106FB000C5CA987D4AF1A3BAF470909A055F2D7303
+:106FC000ED0FFAFAADE9F5C2716F8CE98FDBDEB92E
+:106FD0001AF9667A9A0C407EE85878F17F4FC747D5
+:106FE0007C8E8517E2DBC72452339BD7E310033C2A
+:106FF00013AFD44AF17C3FD63C24F58FD3175B63A3
+:10700000DE7B434F901730AEB5A7FB39BB8DC73F32
+:10701000F17E0452B0611F40E6F97172CD73F67EC5
+:1070200090E7968A79418EFEA0FE04C6DB0E0F4DD6
+:107030002801B97400F248C6812719B5F681BC2031
+:107040005A72977B5FC9B91712A6087256E6F75CA9
+:10705000CB35470B0017E1F94972B250C0DF1BE294
+:10706000BF8743FBFB1EAED7AE9EF7D97A1DE9471B
+:10707000F1F6F30F64A3B71F7263BDA79F1FA2BCF5
+:10708000F4F57304FC1CB467995C115BE45D987FB4
+:10709000463B827B496E0B593F8EB9E2B5A2C5CE05
+:1070A000CF39F97F7D90FF27609EDFCAA9C0F74ED8
+:1070B0009E5F0BBBEF634275669681713196E7E781
+:1070C000E4F7F9CF093B4FC77EF7E7F939F97D4778
+:1070D00086E616E0F72B3E2888780EC8B193BBE011
+:1070E000D3F908EF8BE3C1EBE42BFAF312FD703A0E
+:1070F000DFFBEF01F33FC7829348FC3E168ECF16AD
+:1071000032F4D2ED305E15B39B910928926F7BE289
+:1071100073284F425A35CA13C7BE69E3F60DF527E7
+:10712000308FB703EE264EC1BD2DA6C76E13ABBC84
+:10713000790DA2E65D3F22DCCC0BF762274D8FFD77
+:10714000B744BC0ECFD3746A12F61B82DF452AA265
+:1071500037FCFD11B218ED4089DB819D8A89F6B7B5
+:10716000230F46EEFB4EF0DF0374EEF7F5F5E35F19
+:10717000B791F8F876DE58F8EFE4F65D1BDF9FD3A1
+:10718000A9BD0BF039EBB79DDB7B7215DBEF16F970
+:10719000D3F9FE8D18F3BB9DA704F5301F7DCE59A2
+:1071A000EE47657E5DA5CAF2A288FE334FFEEC1B5A
+:1071B00031B1E8F9E82D253119E4C87D25313CDFEE
+:1071C000F0DA8610E69D1FF7C5790E517313F86843
+:1071D000A87B069E1F3FDC1D8AC1779D774F8DB926
+:1071E000EDBBA1AEF1E5D12F78DEC6FC38DB1F5A2E
+:1071F00008BFB34C9F96444507EDC7BA7BC776F7E7
+:107200007E9C7537DB5FB2F83968EBEE6BF6DA29F6
+:10721000F73CDA3DFEB5FFFBD17311C393810E67D6
+:10722000BB1F952432F8BB3F5D9282F75BDE25DA07
+:1072300069D807707E0FFA642063E3EFB211D3447C
+:107240002C9EADBFE4A7DB9F737FABFFDED6AE2ADB
+:10725000DAAFC8D60DFC0992F79EB49464E1FDBE86
+:107260006D49764F1AA9356C94D72AD38F624E6038
+:107270007CC3EF490BE901EFBD9EBEFBD1C063C0EB
+:10728000FDA417D9BD5ACE7D69119E470FF12D1C63
+:10729000C7F73B5A21F2C502FBDD2CEAA7D2265DD7
+:1072A00094AF8B9E2FE5F783C21DA770EEC0FFFB46
+:1072B0009F67F2BF779CE455E9F1EF8FF4FFBE972B
+:1072C0002AE96FB9E232637F2791B75CE711FAE2EE
+:1072D00084F1D7E98FF03E482422DE17CCF4C9E1CF
+:1072E0002CBB67E48464E0EF8F9F70F62D4BC911CF
+:1072F000BCFF551074D8BF31B52BE2E007982F8A38
+:10730000898093A4978038DE32B477B7C483FC9C1D
+:10731000D7A008FD9ABFD516433C54FC16DB0F25B9
+:10732000315980BCB285BF35F0FED94BD5A620AC13
+:10733000E3BF7F7C2E8E7BB3BA5482F2AE38B39318
+:107340007FF5D881796024B73D112505D40F7919CF
+:10735000ECFF9B9F1271BDDDF2FD28CAF99B9FBC1B
+:10736000F5A1CB69BFC20FA3EC9CE593373ECCEEF1
+:10737000996D43786EFEC195FF0CFAA6ED5F45BC92
+:10738000ABA96D03931BB786D83D4DC351F9A13D01
+:10739000AEF5EAE0C3292FD6661F812B0F6FDE9F63
+:1073A0009A2DBAE4EACD12F973C82F31E973791135
+:1073B0003DF06C9CC9C7F7A2EC3E1261FFA1EB71D6
+:1073C0009E03D7E0BC05BA02DEA4F8F9219F2F6D19
+:1073D00087F3B11F15F290B7F4DEA3029BDFC0CC98
+:1073E000DDE1148CBF5B5E151D95A314FE3F87FD88
+:1073F000ECC5FB67B757D6C379DF540AF627167D6D
+:10740000FF09947BCEBDF4B7C13FE9FBDBF7BFBEFC
+:10741000F4DF800E49760FFD2DDFFFB0F3125ABE68
+:107420006591327CB901DF8B9EFB496FF9EB5FCA36
+:107430007F43E17D97DA77615A7FFBC1A0E7DCCD1E
+:10744000BB836FCA00DFBB14851AB52B2E3BE53D0D
+:107450009743C4D3D8FF0953C1BC18FFF770630F1B
+:10746000F0C9ED03DD78FFDAED4FFDEAFF80DCB80F
+:10747000DD77AFFDBBF08F8A33F5DFBB71AFDDBACF
+:10748000564CC70B40F7FD138AEAA1917B3AB95ECF
+:10749000B9E589130FC0EF0DBEF7E4BF3F00BFFB96
+:1074A000B7F63FFEEF03705F15F9715803FBE6F680
+:1074B000C7DE7CE01B14FE5F1D0C05806F6E7EEC4A
+:1074C0009D57BF49CBBF7B664619EC5B4B1A8B338C
+:1074D000FCFAC0EF27C2EFA5AEFFD19249C09FEBE7
+:1074E0009F5E34693CFDF26BCA5F79CA5FFF1F562D
+:1074F0005AAAC100800000001F8B08000000000095
+:10750000000BDD7D6B7854D5B9F0DA7B6E7B924948
+:1075100066274C864932849D9040B00177202AB678
+:10752000D14E225250D411B10D16ED10EE081A2C86
+:1075300047D3A3363B096008131935843B0E682CEA
+:107540008AD4E8A796D3D6AF03528A9EB64FF07876
+:10755000A8F6501B526B6D1FABA3F5D6F3E8E17B89
+:10756000DF77AD9DEC994CC05ECE9F2F3F58ACBDF0
+:10757000D65E97F7B6DEDBDA73F62CFC7D95C15F3D
+:107580009CB18B18D30E4B8C8D85EA8F45C942B9BF
+:10759000929FB1DBF0BF1A63EF3CFD8953AE61EC03
+:1075A0006389256DD5F0BCEF73A7EC63EC78882573
+:1075B0005921632F3EFBBBE3FF0AF53F473C4D2EAD
+:1075C0009DB1DB0F3B060714467F67E95FA3580EAA
+:1075D0006099286650DEF6EC0DD75D5683A543878B
+:1075E000E1D9ED2CB951F58C7CEFF6577FE764D0EB
+:1075F0004F955932F8950CED2CEC4D9442F9E4A6D8
+:10760000F76D53A1ECFBF3AF1996CC3E385029FA35
+:1076100041FB9FF13F9732D67CDAFDD36395C3EFF0
+:107620004F50737C6F7D09FE7309BBE4AC0DF6F718
+:10763000F8026F021B9F1DC3705F67059CCCF2931D
+:1076400016E5A7C71C8CAD79EE466FC433B2DD2CAE
+:10765000DF6D819DBA86EBA3C17985C4D795F48689
+:10766000A6ABD0FECE33D94600F6FBEEEBAEF85C0F
+:10767000687B77C35F4A580E636F3B92B7201C92BA
+:107680002FB8D4FDF07CD10BBF728660FE779F3B94
+:10769000E9D4A6D07672A58BA1CE86FE5E6150BFDE
+:1076A0004DE295DB1FCD49B872B1FCF3F1FB109EA2
+:1076B0004536E6453CC4AF9FADE5E2F20A68BFB788
+:1076C000C5018EB9581E992F4D1D09EF558008DC54
+:1076D00087159FD20CC4E39959CC333A1ECD7DABAC
+:1076E000B8EF4BA0DDF8BD93F946C72BECD4199E3B
+:1076F00082E345395EEF79BB04E9EBFB9257936A6D
+:10770000619F8EA4B308F6613C6D537BF591F866DA
+:10771000B685DE4555586BA3F5A6E3279D0E96A4C6
+:10772000D101BE8FF835E1321A1DC00A182BF8229C
+:10773000FBF9DBE0355FD568DC74B8B56E70859019
+:107740000EDEA876C55DF0E88C43DB7617CC9B7C1B
+:10775000C9C1F6C32BB74CFB8343CB19B9DEDF029B
+:107760003D6A167A8C34BFBF612CBC17B9A7B4DA56
+:10777000C686E973A8FD1E1BD32CF0796F1C93708D
+:107780007FB7EF75C40D80AFEDFFBA13BCEE8EBBB3
+:10779000A0BEEDFF9C7D0CEBEFED7531ACFFE1B9C8
+:1077A0001F10DFFE41624D2C8FB1E57BEFFAF847E9
+:1077B000D0BE6C37CC06F8BACDD547ED6C316BEA4C
+:1077C0000579B23C3B49EF2F7FAA98B5C3FB2F3E0A
+:1077D000F7AB5BEE86FABB3FC9D15DB0AFF7FEED0C
+:1077E000F65B24A8AFDC0EBB96B0FD07B751FB5388
+:1077F000D90CB605FDFE7039B3F0E3F2ED0E6DC0A5
+:10780000B2FE95CCAE0DC117E9C35A8725DDDAD794
+:10781000D58F747F2B3EE7EF496705EF201FDD8A88
+:10782000E504280F7B43EEA929FD68BCDB5DC93B5D
+:10783000750FE1B9489E41782E427CDF7A20751D94
+:107840004F08FEB9DD995CC6FBC78A385DF4D37B6F
+:107850003F50A594F6F4F7CDFECFA96569E3F0F7A4
+:107860006F73B1A6BE0C72E9288E5B80E37D3E2962
+:10787000753C433C4F9F873F7F3717FE03705EF395
+:107880007C0EE17DCDF3BFFAF8BFA0FE0EC206F07C
+:10789000F84E41FFC777031EDFD96363860AEDAE5A
+:1078A00044C92E94534FBBD87EE8F28E2351925F89
+:1078B00035BC8E353F769F417E1EAAF701F6949126
+:1078C000F3B6B734F4BC59C1D8FA96089536D6F455
+:1078D000F0800F9BEDAC174A3B6BFA1EAF8F55B192
+:1078E0006ED4433BCA03A7A2B6C3BAB66503326BD4
+:1078F00090CF73884FFEAAE6D1B88C355D8872654B
+:1079000043CBEC87DE44FE550CA6FA713C46E79C5F
+:107910009DD9DF4238FCB7C0ABB94EA723A2EAB06D
+:107920000FA7C4C2085F873DD2510AE33B02BE6A7B
+:107930005831DB18981742FA8C56A9C44F9F209EE5
+:10794000613E178C8F74C38E75339C5709DA3FB034
+:10795000F2B987C542CFA3DC8073740BC819566E89
+:107960006907147BAAA06EC18BD307EB4EC1934766
+:1079700025B925E8F847921EF818E1D0EA527BA114
+:107980005CC0620EC41FB355BEBF05F6B16DF1D920
+:10799000890355F8BCFBCA109E0357043FD8327EBA
+:1079A000789F0B7E7C5FBF948B65E1623C471778C4
+:1079B00026FE1E4B40B69205FD5F94585F27943318
+:1079C00095BFEC7A733AD41DAC01E1710CEB638680
+:1079D000C73986CF619E76C6663F0DE58F1CB10D17
+:1079E000880F63A954DD0BF8B8F0C7E11BAE8175B1
+:1079F000DDBCA2621AC2ABAA2F7CF514A82F5C31A1
+:107A0000619A0DF0302E8FD3EB31475FC105885F4F
+:107A10009817F7730B4B3A109E11A63A09AE426EB7
+:107A200035325DD4E10FFA7F73CD847867E9C8F70A
+:107A30001726E2375E035D6E3E16BF068FCD5B4EA6
+:107A4000247F8AEC13E953676533CB7887F5E3D954
+:107A50006CE47800DFED0399E0CB7C1F207C75A6F9
+:107A60005C61E0F3A505FB3BA5D1F58305DE86ABA4
+:107A7000D8D473B40FC19DAF271D2FB0023901F3C5
+:107A8000BEBEC411C779DAB22FDF8EFCF05ABB4BF1
+:107A9000B5C1FC7FC12EA057DCC4FA085EAFE7F683
+:107AA0008CC375D603034897921CB93981F060B92D
+:107AB0007A27F0CBCD6CC0014CC6BE052486E522EA
+:107AC000A651B9988508AE4B596223CADD8D6AE488
+:107AD000AA3CC0CB6DB6C8783FC23BD85F8274CD9C
+:107AE0007E9E595F1AD67F385F9BF576411F4C0901
+:107AF0005D7C7D0EF2DE85751E90B3DB051FBAEB53
+:107B000039FF0412CA19D44396C61ED89542F7917C
+:107B100099A121BE284330C9CC037C1C102833DF37
+:107B20004BEF67CE1F68BE82FD0EE877535EA8312B
+:107B30002FC3BAD2D7BF268FCBED467CCF42E78D7D
+:107B400011CDA941FFC6CFBC217CCF5DEFA07E8BBC
+:107B500040DC7079133A8E74DF18614D9DD508F6BC
+:107B60006D21DCA7B9CEF47D3576DF2745919E42A5
+:107B70008A5EA1FEFDFBFC6E9E9DE637D7CBFA8E9A
+:107B8000D729179FFF3D1672B02FD2CF0D8484FBEB
+:107B9000EC916301A48FC6E6769A470730D1B99E6F
+:107BA000EB8CF766A0FF41A73615ED869E89FED2C5
+:107BB00036E027E0DA08C26D304B9B6AB73ECF173C
+:107BC000CFF3B5A98AE5B939CE2689CB1D933F7A83
+:107BD00064B6E219ACDBF5C03CA4479FF6C62FE1C2
+:107BE000BD25720EEB847250C8A9CA772FB8E55F25
+:107BF000516E1B53353908E7839D11DEFEDC726040
+:107C0000379D072C34711ED0E31A159E43FF259D26
+:107C10005F9BC8A0BDB9E36B131B2DF399EBF8D1A3
+:107C20008385F5C897CD8CF71F545EDC8E72B1D179
+:107C3000FDEFDBADF2703087D3D527BFF99AFF0295
+:107C4000E24FF569E453B33D91C7E97D099E2FD01A
+:107C5000EF8F2DEA8E9970EEFDA89E7D6B1EF28946
+:107C60003D3491F6D13AA50CE5EF92CEFBEA51FFF7
+:107C70001D94B4A7DDC0BF83BD9B79BD5A9364A892
+:107C8000573EFAF497100F39AA2AC985D88F3520A4
+:107C90007C2A1F3D19CA9B3A921F15A8A37DC78253
+:107CA0004CEFD5D098E0F2A3E0EB0702A8479F1471
+:107CB000EB2B982A135EB602BCB1EC1478F8459E03
+:107CC0008DDACD7E2785FC5EE48D9C44FE0A85C25C
+:107CD0008B36F8F0FC637AA786E76C98CEC5AD4E7C
+:107CE0001051F07CCB64A7D626215EFB8F2E4679FF
+:107CF000FD9F590CF57AF7F8FEB646B48740BF6889
+:107D0000037EA8DB182892A09E55EBD4F15C7F2F50
+:107D1000AF94E659113FD9867AC844901E361DC7E4
+:107D20008BCD2A82719ED8C3743C4F0A8067FA09B2
+:107D30008E03B988CFC9CA0105E5D6BB95F55EAB00
+:107D4000DE38526EC9CC30E99E14E52C6628D67A0E
+:107D50007E5ABD28AD7F594A7BB1AF9FF4683BF492
+:107D60006907F806EC7D47104F81854C6D079971C6
+:107D7000A8ADAF8EE0B18AB1FD79288C13545714A9
+:107D8000A6B6021EC7316887FE9E66A61AF0FE23BD
+:107D900072DF6C94D3723E87836A4FCE413806D827
+:107DA000617A0FF838BFBDDABAFFA482FB9DACBC84
+:107DB0009D1B063ADF7278BA8AF5312E7D25F67F53
+:107DC00017F10043753B126D8DB88E175CAC4D47B3
+:107DD000FAEE27F8B230C74BB713F004F5CE396E80
+:107DE0006AF7390DDEBFD44EF54DC80740FF6EE48B
+:107DF00003E08729B5C7EB15E85F2D2B7DB8289FD9
+:107E00002BDE908D786D85F1A1AC5A6FB4A13EFF49
+:107E10004EAF9DA11EDB29C51A703CA3D449F4D8EE
+:107E200091932A974BF3397D95E6CB42CE7ED6903F
+:107E30000DFD57182EE2F7D081D6E3484700FAA689
+:107E40004E95E8B0341FFA395888E86E457C2D8B82
+:107E5000C0782F0E7CFB67E3701F1A233BC35D12B3
+:107E6000572E47F9FB431BC3790F8D8B11BC3B1B6E
+:107E700098DA568DF4F28A8CF5FB55A6A25D035074
+:107E800095116EB7417B27D6EDFD47510FBCAD7BF9
+:107E90001AC37375CAE97F233C9CFA3A181497A257
+:107EA0003F65606331C251F3D0BEDC654DBFBD1785
+:107EB000E1DE5BA6B7C263B465487EC6417E021EA2
+:107EC0000E32E3C0DD12CA8DBBBE85CFBD41ADCC45
+:107ED00006CF678BFDD705078EDBE0FD2CC3CB5C9F
+:107EE000581E3E42EB7501BD3058EF27B0265ACFE1
+:107EF000935971A40BD76129F155EC1775C6F13C64
+:107F000067337C746ECFAC64F47CCBA62CD297B76D
+:107F1000540F94A05DFAEEE74D8130B75348EE95CB
+:107F2000079D0919E4C78703D38B4E30848FA05770
+:107F30003753F7C37C5B6F3C4EF5FD8D4C453F914D
+:107F400089AF780BDBB39EE42B2B42F93CF4DC01C8
+:107F5000FC0F70BA31FFE2393E5847DC0D3DBECC14
+:107F6000D89EFC459B0C98B7F33958FF85509AFA78
+:107F700042655CB9DEF2FE2DF9528A3CEE748B7ECE
+:107F8000E57105E91B465470BE4F1C0067F437D5F8
+:107F900032BD0DE0DE097844FD7702B0A70D6054D4
+:107FA00077781F1BF050BBCCBC08C7B5A89C03FC5E
+:107FB000E22C0CE3B92A930CE5C6CCDAA600F6BB9A
+:107FC000AFEB4000EBB17C8DF0D0F97992E0545EDC
+:107FD0000BF081F36093B35FC673CE781EE429E0A3
+:107FE0006BCAC4271AD03E77351FDC8DFCD09E2F7C
+:107FF000EC117B3C80FBD9E414F254ACDF25CE9F1E
+:10800000B67CAE4F7C57D0F93D62BF40CFF7E4431A
+:1080100019AA02C15D437295F440BB724BA88DE171
+:10802000F82AF7D328F100C201FAB721FD87AA6226
+:108030002BF65BE5B0E80F700AA03CEC9C7C27D1E6
+:10804000D9841F4A1AD259DDE1B504B7AC5ACE1F04
+:10805000E7874F3C3060E1D3CEAE4F03D86F0BD2F1
+:1080600051D530FD94CFBFDF5502EBF8A892AF6336
+:10807000CAF3CD814806BD6BC5A73696986EA90B8D
+:10808000B8D40F9C2C2B41F971A8681AD9FF67F658
+:108090000524787E349FEB6947F219C10BF0508FAD
+:1080A000F4685CCB18FA1998472FBBDEE21FF9BEC3
+:1080B00080A7097FD03CCA6E9C626D77F071B24494
+:1080C0007BE528EFE7423BF249797A3B5F8FC9BFF6
+:1080D000594146702D9FFFEE463C6F3F02BE4579E9
+:1080E000551704BC207F3FABE8B81FEF107C93040A
+:1080F0005F130EAEDA01273E9F79781FD1E10A3572
+:10810000FE5A07CAAB5A27EB65086783E07ADFA1FE
+:10811000AC6988D7E681BAA38B705E90DC782E9A22
+:10812000F0A91F58CBE97872DF0588B71E89D35DA7
+:10813000D09E684578C98A9687E74DA3F0276C855D
+:108140003DF5937E15A2F37250D063C5F637AF5D4F
+:108150008AFC0F9A06EEE3DD5A99E4D707CF4A71FD
+:1081600006FBDC7A6FF8752FCAA34A7EAEFCB9E134
+:10817000D5DB705DAE849BFAB90E4871B744F281CD
+:10818000845FE7BD5CFE19FB24D21F5D465308CF18
+:108190000D6D7D643A9EE348B176BF9093C84FF36E
+:1081A0004F1DDF83FB8F7854179C2BA506CC9FE2D5
+:1081B000F749901D337861441E837E0E16BFE52873
+:1081C0008E1B1C7022BDC963B81EBBF1C6AFB7CDF4
+:1081D000C1F55F2693FCDB7AEFC01B137C282F418F
+:1081E000EFC079120B5EF762BDD6A9B92D7AE8BB54
+:1081F00087277833D1AD45EED162B7DC4BAA01FCBD
+:10820000FDEB4B094B7F97910C852CFAC747F97C06
+:108210003DAEF5F09CE831497C09E776C02A37B7D6
+:1082200008BD2B54A31D1E207E56AB918F1A37DF3D
+:10823000BC00F161F7A9D508AFB3024F8BBCA1B365
+:10824000282FDE6E61C9F5A057BED3A250F9A7163C
+:10825000954A93FE65A57F16E27FE56A5542B9B857
+:10826000C6CED6BBA631963726954FCC7E2B5684EC
+:108270001DA2DF7C573EF64BE517B3DFEA2618AFA9
+:108280009AFA1DE3FD841F599C3F2BE35272BDC532
+:108290002FB2A6CF9D5C6FC1E3AD07F252EAA6FEF6
+:1082A0000ABA441CFD736EDE84FE191AEF275323AD
+:1082B000E311DFAEDA7E6721C0412B1F9885EE9572
+:1082C0002B6D73BD289F5C8CEBFDE9F8DA0AF82270
+:1082D00078B42854C65B5486E7D6DB2D01AA3FD478
+:1082E000A251FD923142FF90C14E013CEC13F83097
+:1082F000C7992AF667F6430C3A6BD0EBC8E5346AA7
+:10830000C4C8B70ED44F802FEDEB3792FFD16E3833
+:10831000C93F06F2FA125CBF5D6D223D05FA33716A
+:108320009E915FBCC719F9CA18187F55B96260FFE2
+:108330005507DE77A2BFFA7E279743EF3A52D773ED
+:108340008558C71563383D1CC9D338FC033ED2F3AA
+:108350005D4183CF23EACC1E290967F0235BE03E11
+:1083600080F106DF48B85F8BEB5A133B330BE1EE2D
+:108370000B3319C7BDD2E621BEFEB09691BF78344B
+:108380007E31E16EE221DE12A1F2ED96150477AFA7
+:10839000D8EF432D4D54EF7186BF89F3796B93E786
+:1083A000DC7F44D0EF52517ED17D0EE913D0732C87
+:1083B000DA8D9AFE4827F98FE3DB1B89CF2E9EDEEC
+:1083C00009B5A631CE8C7106C06313E2D1E133F159
+:1083D00018263FE091BCF01DB86E85C59E6984F1FA
+:1083E0007C4A9CF4525FF981C412E4E70D8013D0FB
+:1083F000837DF31F4BA05DAC3E2831946FBE703C73
+:10840000618775ACEE9618CAF3ACB99159E80FAA1A
+:10841000BF30722F8E9755A94B38CF98B97D4E2B10
+:108420003E47B76FF83E075B34F2870EF951DBEC3D
+:10843000AC1DCA375B2A1F42FFEBB6ECEF92BFB50B
+:10844000D970A92E423AF7C72EB32B2AD2EF938EBA
+:108450004817EEF3AE87E61AE83BB045D75EF8382A
+:108460009EA605E12DF87CDF868D25B89E46AFF6E9
+:1084700031EA7BB082393F9F41E70BE97BCCF8F9C9
+:108480001C94778DD9BC3EB13BD469607DAC76A796
+:1084900004FD3F1C736A8E0FF6D1389EB72BA27D68
+:1084A000F698D0CE31C45F8EBCB714F413C3C8198C
+:1084B000F639BC5F3B7BCB629F393BD62602746C9E
+:1084C000477A711C25F64008E544368B1B85402A07
+:1084D000B9682F403F7B47D619E4CF8935912738BB
+:1084E0005F72BAD60C46F05EA68736FBE0F9661FCF
+:1084F00013F405808573CA2BF803F8E2692B5F78C3
+:108500006BD3F8C26074EE8CB6EE74B9F490904BF5
+:10851000663BC88317705DDA7CCE1F9A716E7E3819
+:108520002AE4C1BF9BF249F0C1DF0BC70EB16FB7A0
+:108530009087E9FD5F31CF0F2127830AB76B65452F
+:10854000CD473DC36F033D03E071E4A6276EFA2AD1
+:10855000C063CC81896528277CB6F8AF91FED941EC
+:10856000E734D46FCCF19EF8EB2345F3609C2C39B3
+:108570005E84FE7FF604B46B6827E885E82FA99A2D
+:10858000FBF12D1AC0A1AA9CC52BA0F4C9897AD4ED
+:10859000C7D933AEB25E15ED5B384F3D6897FA1719
+:1085A00063BF17C5FA9A596801DA910CEC481C3779
+:1085B000DD8EED16EBDF547127E9ABF7A5D9A5E603
+:1085C000382F9AE71BDB4D76A97DC82EAD0B35A65B
+:1085D000DAA52F225D385813934A87E57CE198F09D
+:1085E000C79CAE93242FFE51BCC078CC87EBB1273B
+:1085F000D93F03CF6FA7E983539C1C9FAC9EA9A4CE
+:1086000067EBDC4FF14823E0246F78BC6EA1771450
+:10861000FB4A53E425BAFA9DF9380EF7FB15A08BF7
+:10862000217FB8BDD8C7EDA0295943ED76D44B863C
+:10863000DBF9B9165498A1C07B0561254D5FF8C7D9
+:10864000F67B17BE88FF6F67A497823E7F21EAEF13
+:108650000F5DE3976DA5297C3815E1ACCD751A281F
+:108660002F4C3E34F90FE0E52C84F7DEBA66623514
+:108670009E1BCE58F5EB2EA86FBA4C2D457AFF8E77
+:108680008FD38D37B1A06D0ED9FB721CF5CD4DE3A4
+:108690001E54504F7FE8F3D8EC32787EDF4B36BD66
+:1086A0008D8DBE0F53EFBCEF5E53BE96BE6CD53BB7
+:1086B000BD06D72FCDFA4CB14FEF7AAE8F02020B29
+:1086C000894EECC04F96F3F12161278CD43BAF71FA
+:1086D000165AF4CE6B7D437AE7B5088F8AED1F2AD0
+:1086E000B8EF4DC24E78F3DEE4EC32D4A74FD81881
+:1086F000B707E6BC81FAB5AF1CF46B09CF39382F48
+:1087000061DE4DF7F2F9BA713F93082D8AFD62528E
+:10871000FDB9FE1F6E0A396AF09C8C4C90A1AEC563
+:108720005C0477D0F723288F0BC2A9F6806670BD52
+:10873000FFCD34FA1D0D8E9B04BD0EED7F72723B92
+:10874000E23D8E945402F5CB66EDC0FA2689DB3DFE
+:108750009BAEBF93FC02F739D2F5736D5A2A9C3455
+:108760008A737DDB67DAF3A16FFBB89E384CB7E400
+:108770003F5486F562AAAB69F57F8CAEFFD17333A7
+:10878000FDBC843F19E906F8600BEE473BED4A3922
+:108790008F4C3E708EE7F2DE1CFF31412F8FF98641
+:1087A000F465A6F9C99F2B90CD58D42F4800E31447
+:1087B000AC49463BB7F298C2508E4EC6C008ACEBEF
+:1087C0004B2C21A31E35850D50FD42DC1AD4ABC1C4
+:1087D000ECC6FA74962C71DA307E95D888F6E946A4
+:1087E00035F228AEF3E31DFD6F48F0FCB1ECDBBEC3
+:1087F00027C1F8DFF371FF8987E9A46FAB58C2BEC8
+:10880000162B1EDA0F8B3ADEB1C6691FB2870E72C5
+:10881000FC05D5B7B2ADF881312E263D5FFCC5050C
+:10882000DC81362C7167C740DE625036D883A8875A
+:1088300001BD951FE07A41FB6989E28EDDA8879131
+:108840007EC6B87D7C138B639EC49812FD8C86B85F
+:108850003CC5FD95C0B7A5488F634F67ABA4A7DAA9
+:108860009B2EB9C1C2BFEDC047090062FEEC10CB20
+:1088700064B7DA9CFA80817ADE6917C917D0EB4EAB
+:10888000E0BEA4DCE64903A457EA0CF1987FA1F608
+:10889000BE4C7ADC9AAB7E8E4EE649DAD358B729C5
+:1088A000CBAF9A0D04917F09237BF794EFF697D114
+:1088B0008FF7AA4F23BCDA40CF75208AE7C7689CA0
+:1088C0009012921C3E0C4F733F90F9FCCE9AD07FD1
+:1088D000A2DC7016AD28E47A73131374F5077CEEEE
+:1088E0001274E50A72BA32C73746192FFFEAB989FE
+:1088F000F5001750AB9B506F0E35182C93DE6FEAC6
+:10890000E9702E9FC279EC6A98DEB77938BCD2F54F
+:1089100028B37C5FC8ED43BED03B08AFF7160DDC33
+:1089200089F406F495C471562B91F12822EEBCAA65
+:10893000FF167CDE610FBD8FFD806E3EC84437435D
+:108940007CA778281EB778887EA639D1EFB5E433A6
+:108950002FF997173327D314F2EF88BC96D0F1176D
+:108960006AA87F18F962F1E939C77F03F078A3D8C4
+:10897000C630EFC8ECCF447F838566A17EB278AE67
+:108980008BF868B132F7F81EF427D629E44F61312D
+:10899000D7701E5059CAFB29F931B4BED291E333C6
+:1089A0006BDD96A9CEF92BFDF96225D7C89E9A6991
+:1089B0003C5833F0CD9221B9C0DF1F94FA2E403BD2
+:1089C000A1BC20765507ACFB607E7F9102F589053E
+:1089D000DD9DEB6B012FAD9C1EA17E9511C4BA7677
+:1089E0000BFAD596D8D93187458F9852C0E5F194C6
+:1089F00002CEFFD06E60FB64AC039E30A610843ABA
+:108A0000DA6841D033DE7C72DA2F2FD046979B8B09
+:108A100063675D5A26BF4588693E809B64EEE3B874
+:108A20006EB86CC3713127D03B960AFADD27207EE1
+:108A3000FBA8F4B07E2A73412FC45265AA84653E18
+:108A4000D3A9F4B130957ED6446580C5A82C627D4B
+:108A50005406593F95252C49A586196B963C8A32B8
+:108A60008CE042BD8285A83C54CAEDC1C1563B434F
+:108A7000BF31D88764071A6D2EB5DD477621B5372B
+:108A8000831D88799FAB0BCA687F636FB693BEF472
+:108A9000E1E971711BE18DE7DD8C9037CA84DDEB74
+:108AA0002DFEDDF6C7958678D5307ECCE7AB055E2A
+:108AB0005617083E6BD55F8BE0BA1E5774CC333A1D
+:108AC00098CFFD4DC3FD79BF55E2BDF2F997BF8147
+:108AD000EBF9C8C8D550FF180D5FA3FB9BAB4BF05B
+:108AE000BC1914FEE6C133752512EA115D3FB800CA
+:108AF000FDCEA04F382530F6DE7CE0576524AF125E
+:108B00004E867E4A13BF36661FB0239C35386F2BC6
+:108B1000C5795BFCC5CF5BBD20745701C0F5C4F7B8
+:108B2000B328FE744797447E14D0CF36621E48A304
+:108B3000B027D2CFA50F7DA1EFE27B267CCAE7E765
+:108B4000328C9F7EF464514A7E4AB4809FBF87CAAC
+:108B5000B4DBACFEE629CF2B84C7DF758DDD8F78C3
+:108B60003C1F3C7EF70087C787BEC89602B22B35F4
+:108B7000E2CF13DFBF602CFA9BCFB78E3DFFE475C9
+:108B8000203BA0FC34E5C5C1CBF5128CD32C89BAAF
+:108B9000785E43ECCA90155E4B62DB58733EF13D44
+:108BA00073E48F6CC7CC2494D3A6BEE41271720018
+:108BB0003FC5933F0C0EB25C2E970299E87D9BD087
+:108BC00027D70B3F6C7AFB86C6CE3FA23DE0D698F6
+:108BD0003609F6E9B61B931F833A0B3875B47F95B7
+:108BE000C48E2B72513ECF60D5D087B915EEC7FC2D
+:108BF000F2DB036C91E55CCAD506B8FF58E4430C80
+:108C0000F197B05F378E4BB55B4F1570BDABBF8032
+:108C1000FBB102ED7A13C2C9AEEAACD1D22F9BD51B
+:108C20009F40BC066CD5D4EEF08D68FF7901BE6F15
+:108C3000E37183B10B75B6D2636D9FD35FC0F59FAF
+:108C4000BF49CFBDCFD3A4A8A8576BAED9E48F0B33
+:108C5000D6A4F8B50E0ABA19E61F2E6701CE3AE57A
+:108C60000F0AFF243CA77858475E049544E60CE8B9
+:108C70000D0694EDA517073C967DB4E709BFDF67A5
+:108C8000D303F3ADFAD3E7D35F8BF886E3D2C77390
+:108C90004ED5631CFBC319DA3497C03BDA4BB97E5F
+:108CA00029653D1B5B545DF86FF44C78DFF85DD0AF
+:108CB0006F004E1B8A5685904F9C222FC5A90CB47D
+:108CC000E1F80CF08DF87725FE7A14EB4EC43FB333
+:108CD000E03B30C0EDB651F0DD71E4F1583DBEE748
+:108CE000299B8674E3C4B31DF6E1ACD4F667C35286
+:108CF000DD7E2E27ED817802F5497B4849A23E971B
+:108D0000C560BD29E7AFAA5BF1D2E130021827EEBA
+:108D1000F8DC96316F6A40E0C5010AF49B16FFFE4D
+:108D2000E4EAC8183FEA77CF1A069C34CCFEE3B0D9
+:108D300041EA8FE78BF92B0BBEDE70550E74BD5FD9
+:108D40006671CCA3F1B9FA67E740D9B3295BC7389C
+:108D5000DA91EE79A5948F39234B46397948EA5751
+:108D600026A0DE7CA54C7A7296A087FB670D523E4A
+:108D7000C49C809BC675C77E3007C7DDCC947ECC73
+:108D8000B3B97F75FE9C722863B5DC6B19AB920991
+:108D90006EC642395E01638CB9EEB342AB1E3D092B
+:108DA000081FE178FFA77F59B014E76B66345F7D39
+:108DB000B34EEBDD2329A790BFB7DE7B6A07EA5DE0
+:108DC000BB5F5F4E7AD3CA20CF9FD9BDCFD910F7F2
+:108DD0007038E13C7BD6847B3BA5E17A49E5BC5EFB
+:108DE000D4EBCB033CBF2B169AF7AB4A78AE553188
+:108DF00095C7C742369E4F3C54BAADF57478568835
+:108E00007CA3F4E7AE20A7DF1DCCA89B03F3757607
+:108E1000CF97114E15CDFD1497CC89CA215CE70E72
+:108E20007B7F02E7DF5113F219307F4E5558B6C3EE
+:108E3000F39BFC3C0E54112DA37865A3E89F3E8F55
+:108E4000D96F873D5CEFAEC171980E186615300E74
+:108E5000DAD1E77B7F9EDF2ED6C9482EEC710C4815
+:108E60001867D9F31D55A2F5D4C415CCDB5A25E8F3
+:108E70003BB6446609E2938884E33E32541F907007
+:108E8000BE87FFE56303F1F3F065FCBCD8B1F09950
+:108E900056B427B6ADE6F5871D1C0F0FFF8B93F276
+:108EA000A181C22594F37DF644E172789ED3CD284A
+:108EB0008FA3A28685508FF9971B4F2D585E83CFC5
+:108EC00063974AB89EB9A7D96498EF81B10AAD27D4
+:108ED000A7A69F21FF98FDD3F777AA98AF1BE8526A
+:108EE000423A847E98AB82F350FFDD8E44A1DF02CC
+:108EF0009717C672FA33E9287DBCAFF8B91FAD7871
+:108F000075BF8847F4913CC4A465F2EB7F9BE7ED05
+:108F1000C11E0DF49746D73A0F20FD6D167E9F6D4A
+:108F2000F80AD2B5EEDC87790DF7055F0961FEC955
+:108F3000604D19E5F10EE91363F9BAEFAB9167E300
+:108F40003A1E76241720DC2A9A67D95BA149EED60F
+:108F5000DBDEF4603F8EFFBD5DE122C4476F1E2B58
+:108F60004478C4D61E2F447CECAE3E4EFE94688EF0
+:108F700087F442DBF43B67635CD636BE11316A99F5
+:108F80008FF34FB71C2F423BE0A99EEB36AF0FA2E9
+:108F9000139191DEFFC9AE6F6C463BB4E016C0374B
+:108FA0009D8B861BE73BBA70DE741DC68B879C1AAF
+:108FB0009EE53149CA9A88FBDB6453916F076BA623
+:108FC00065613F7F54362681BEB02D62FA8DFAE985
+:108FD000FD87A28D472AE0FD8742810F48429434E5
+:108FE0003E85722DFFE657664F8271F2E7E413DD8E
+:108FF000F81B98D428F81AF54254D5F039C05D42D0
+:109000007AC30477F29B32D68AF63B746946BF690D
+:109010006F4E44429B03B4F42603C6DFEC881C4128
+:1090200079D75BA724311F6E77EDC0EBB6321A8774
+:10903000FC2930B0847EEBBD1FDD4FF6E1FD9FDAE9
+:10904000E87D23A434F5920463752B11AFBFF7902C
+:10905000BDA70EBCDF82F123B5C162670971837EB3
+:109060000B337E817E68BADFC2D87F601EABDAFC2C
+:1090700031D181B2884DB0811C55677E1C42F9AA5E
+:10908000CA91FF7059E48CF755165F3615D797349F
+:10909000B09D5DA1DC89FE77E0B71D28AFF7B676FD
+:1090A000B9511FF7097D81D99306F24BF48549B474
+:1090B000FE0299FB7BA19DEEBDB0E9CEFD489FF875
+:1090C0001CF319BDFA5B0BD16F020A37E95BD5D8E7
+:1090D000CF37DC6F681DFAA9BBB19FF7F41F3FA71C
+:1090E00032E44CB9DF7273A15BF86564E267F57432
+:1090F00036E5A9A8A7D7CC25F83CABDF4CE569F746
+:1091000019CABFB6BE0FF07F3F187E07F1FEF0BD53
+:109110004E8A07F94C7FF115DC5F8C7F7A0A3C059B
+:109120001D605B196673F3FEFE191E8A0FDFFF5C7C
+:1091300092E01992C05003FA7DFA58632BEAF93194
+:10914000AD9CFC17A01E850E407BEE1595143F3E8E
+:1091500024455A09CF8B3C11C4B3BF36757F2568AF
+:10916000F7C19A2E0E169AFE27F2D3F9B205DD004A
+:10917000CE12B0BE658CAF07EBB25FD8F5F0DE154E
+:10918000C152F19EEA46FA5BD231219FCE25B59FAE
+:10919000F41D134F40D2CAF66954CE9E026520C01A
+:1091A000CF11CDC30C6F3EC5A7E8FE4CAE8D51DE8E
+:1091B0001CBB81789ED6437947AB35AD334F000851
+:1091C000D6B35CE2F3FF612C1FE78160D3C617E1E1
+:1091D000BD1E18EA1975B89FD75C37D0CF0C1C8715
+:1091E000A9DA4E6CDFEE22BA0631609C95D11E776B
+:1091F000A5C065F7CC0F12985FDC18F130941BDA2C
+:109200006E571A1F244398E7E879274743387B3382
+:10921000F823ECFEE1F91F0826E9FE5E97C4B407C7
+:10922000617E6FCDF1D978EEDF6D53FA31DF18F33F
+:1092300074B4147B22D5EF31AE39950F1D6A2A1E06
+:109240005566A9C3FC4F8B7C6BE30E2EB7A307ECCE
+:1092500042BE313ADF88334CF890BD9864184FDB3A
+:109260002D19E19DB09F8BE4F88357215F4D93C981
+:10927000BEF0366D5C8BF4EDED7EFE2E2C4DB96F9D
+:10928000F2515790EB49BF18CBED6B4FEDFFB8ACE7
+:10929000EBF5E58617FC3BE2B58DE723B53BD8AF90
+:1092A000919FDB9FF3303C179FC88B17DD01E3CD07
+:1092B0000EF2F3C11C9F55CE17FA39CFA7BC204F31
+:1092C00093793E65F8F563680F4D0C4A182F19F332
+:1092D000E22B32C6BF373FAB56D37EC4FDBE4ED65F
+:1092E0007702CF5FA3465671DEAE9A7974DEF475CD
+:1092F000B37CB417BBECE1A3B88EBEA826A35ED0A6
+:109300002CE8A93EAAAF453D6DF0329E53545FABA9
+:10931000ED45FDBAEB7517D9766E57FF76D4D3DCE1
+:10932000FFE5C63B2499F4D1347D2B218BD295499E
+:10933000DFCA9E2C4B785F607CA8CFC0F84731E82D
+:10934000D95F033CE4860642882F6D06B0CE2570B7
+:10935000BEAFEE37F0DCD36A781DDEE1E53DBCBC84
+:10936000E0E6FDF92C83BE30740E54FA2484E78CB9
+:109370009B07499F7D986D7F9D65F07B80E64EF051
+:10938000EB6A09F1FB50955CFFDEBBD0D48B1294E5
+:10939000D7D755F38A722D3475AE9335EB3D19CF7F
+:1093A0009BC94D188FBA7486AC21D3DFBFAE6D4C0C
+:1093B000A46A781C668F6999ECE0A1FC8A666D56F8
+:1093C000A67D04039C3ECCFD148BFC7AB37D27EA7A
+:1093D0004FF07E5980DB1725AB073A701DC12A4E2E
+:1093E0008BC1AA18FB0EEA5D06A33C3428495FDA5C
+:1093F00073EF9D73905F1EBEB9D189CF1B6BF97956
+:10940000E1AD5AF6183A6BCA84FE8E79A314FF6A4E
+:109410005A71F6ECC5343FC9A19CD5E17AD24B43D1
+:10942000F3C6923EB6BAAF58D286D7D5E6CFA5F7E7
+:109430002B40BF2AF791BEA6225C2A42FB4F204850
+:10944000FC9532D3A0BECD9E24BD795B2D53912FC8
+:1094500072447B4EE533D938DEF0384DB4DE8A8570
+:10946000B28AEBAB087D90A844FD00DED3B49170C6
+:109470007B726C36C1A30D6412F919C5FA49544EBA
+:10948000407A13EB37C26331AFAEA2E3E962AB1EA1
+:1094900065E0BC05F45C526A86D7AF75C74FD0BC97
+:1094A000A3ADBFA64FBA15C66D15EB3E3696CFEFEE
+:1094B000A94DD72BCEED0F3E982FE4D93446F9CFE6
+:1094C00023DAED0903FD8F076167311D4D91547952
+:1094D0007CC1D039C5FDC414EAD6881F298EEECBD5
+:1094E000EDA77B7AAC9EE978EE789E3CCAAE46F951
+:1094F000C7D40FF03E74CE93B2E102B9E7A9F99F49
+:1095000014BFEDD5B89F8B50BE333AA77BA22CBEBB
+:109510005FC8FF7FEAF923E4BBC28C043F5FFEFF14
+:109520003E7F2E78FC9882F222FDDCB908C7C57C0C
+:109530004963D6B5F51E3A27A83E67DB5BA4C7236F
+:109540000DA29EA18ED5F8BD7A958550DF30F50C21
+:1095500077EC5784EF62B4AB488EF51D41BB70F3D6
+:1095600045918B3B2D7CD33B96FBBB7AC772FFFEAC
+:1095700066A93FE12C45FED1C4F91457C8D9C7FAF2
+:10958000295E7497AD9FE0C9009EA8677F52C6F31D
+:10959000CAA3D513ABF15C39C46D27664C19D2FB55
+:1095A00062DBFCA4CF131D062E6D9B836EE0CF8A79
+:1095B00003347EF6F465EE72785E6A8F2B99E4A42C
+:1095C000BF2141F1277FB34D7BD3E297EEA99CE702
+:1095D000CD2437CD3200EA5402F0380F4AC453B6D6
+:1095E0009E45F5213EAC89B4D2BD139DEEF0304FBF
+:1095F000EC0843BD8E35F0FB3F8C45A4F9B09EFCD2
+:10960000F1912ABFC58FE56F76D23AAAFC9C1F0E56
+:10961000D54516A09F563F623710AFD1CAFC7D7862
+:10962000DE1EBDF154E00CAC7B829FCBE77DB9E63A
+:10963000FD131E6FF765F76FF7E07CFFE56204A787
+:10964000195C0E77D64CA47867D735DCDE1B1F700B
+:1096500027D75BEE51B509BF078E9476DEDAC4BD1D
+:109660006B39D3B9EB9592FD57E07C5B65B13F8ECA
+:10967000277F48DD87FBD78FBCDA8079B33DA122F5
+:1096800009FD28F704E4D4BC8FAF727964E27B70E3
+:10969000D324C2B7BF211942FD2180714575184FEF
+:1096A0006AE203A3199F4FB037515EB25DA3FB3648
+:1096B0003D1D37D0FEFD8AE6542DE75963AC742377
+:1096C000A6EA99F037F1779DC01FDD91C6F11AD84F
+:1096D000A3B85EC0CB3D01CCD708A5E2D5C44F9757
+:1096E00023317B32CA816A99E13A019E63F010D836
+:1096F00018A89AEB00FB2D3A53A6BC90DE4064AE4E
+:1097000051CE307A14CE14D7DC970E870B45FE8BE2
+:109710008043D7459CEE41B30A21FCFC220E915DAB
+:10972000B34CAAF2A17DE8A1FDFB1BD47ABA8FD677
+:109730002C533CC88413530C89E0D27C6E7A665655
+:1097400078D8707CD8B7452EF915EE47C9899D2485
+:109750007F44063ADE17B868241D031C6667F2933F
+:109760002484DD7297AD4FF03BEC9BF83D992823A4
+:10977000F9AA25F1BEFB27BF71115CBAA6A871F446
+:1097800031FB13C716A05DCB8C2CDD0BF2367BEEC4
+:109790006A09FD150CF43CCCE72CB5F7913C8F6AB7
+:1097A0007682534E43525DCE2CF00818647FFA95B2
+:1097B000889BECE9576DA82931352649F60CFB1A30
+:1097C000A26F019FEB05BDC07E1381820C7012FB5E
+:1097D00046BBDC0942F9815AE1CFAB3C8A3A26F319
+:1097E000DC2367F443790A5D4407517CEF4228D1BA
+:1097F000DFE641FFA94C7E4DAF143889F88D1BDCA4
+:109800003FBAA54A2539F0B6D0CFEEB271FCB3BB52
+:10981000E414FA31E566BA9C64357D146B0D443C62
+:1098200064DF8E2A07D79D9B6EBCE791837E25C19E
+:1098300030AE700EF9F7762083FC33F5D2C19FB2BB
+:1098400005682F68C66E37E6030D6EFA465B16EEA6
+:10985000BFF561B29327F8B99E6AAE7B080E8B4DB7
+:109860003824436E949BA5E54D9C9E96BBD1FF1476
+:10987000FDCF318CFCB93392146B0E841482835764
+:10988000DF48DF4331F519737FB78AFD79E276034C
+:10989000BFF3C2740BDECBBED03E1D8519F8E38149
+:1098A00099CFCC417AF632A51FF96A1B4BBE7E0CCC
+:1098B000FD13AB1F64DFF1913F9CF46BF28B7F19BA
+:1098C000FDDFFECDAD76D4E35489F48255FCDE8D08
+:1098D0002F3FB412F54F73FC9F09FDFE7CF1C0F1E0
+:1098E00085663C30B212CF192FC603C70CC703A33D
+:1098F000D57E8A077A551E2F397AE66781EF223F97
+:109900008A7860D7995F05301E18BDE8798A07DE2E
+:1099100027F7BD8CF76F8D67EC64EF9EF87E16F924
+:1099200095EE1897B5CF9A977E4D21977B01BCAFE6
+:1099300005F3ED6831D8EF2AA0AE66BE37707D2101
+:1099400097170765710F88251A306E176D9D2A7558
+:10995000927E19A3FB95202F4BF17C3B28EE51EC16
+:1099600058F632C3FBB55DD54C562F1C39EEC1FC01
+:109970004400F165C8B9E4D733FBA7F783F7EDF8E6
+:109980007EB49A6559C7E9AA5EB6206489276C0C33
+:1099900006E9BCC3B828DE23F74A9CDFAE2914F8D9
+:1099A000B89CDB4D9D8532DD1764E1F70DBC7FEB84
+:1099B000BA42A1EF04B0DAD47BE05E8C9782DEE598
+:1099C000C578E9B491ED0FE79C3E51AA21BE351A46
+:1099D000DF36FE9E0E3CCE5C2DCB664FD0ACF0E267
+:1099E000EB8B5E34713FC2678723B688D1F9C5EF30
+:1099F0007D9BF0EA5A9A68403D6EA01DCC96CB61E3
+:109A0000BA422D858EA24BFBA9DD904BA8FDF9CB68
+:109A1000816E383EB6A39C5259E5B44E923BCE9926
+:109A2000F8FD9B58A946F4B35CE0CFCCBF58E48D59
+:109A30002C2FB4F0BD1AE279413E5778D106C4E725
+:109A4000361EFF4BC7C3ABC57C1C9F57F833814FF5
+:109A5000ADF993663B00B614F9496D46DF056352D4
+:109A6000333BF2828F447118FD0177FD36E7C86FF2
+:109A700050CF28B431D42B54DD08E3BDC2F3F92113
+:109A800093E3C2F7E2BA4D3F24FE75A4FA1D9B98FA
+:109A900045CEC6D2FC8C7EE5B3D0011FE5FFD0B920
+:109AA0008DF201E54F61C413E9CCE057AC71B19D73
+:109AB000281FFC36A6637E48DBF359214EE7EA7E79
+:109AC000F49F1C697592DEB2678687F2DBF7281C6B
+:109AD000CF8F6C97E2E84F598A291213505FE1CF7C
+:109AE000BB2E53E3EB4B87EB39EBD438E27FC83F17
+:109AF000CCB8BD5328FCA64C55AFAE82F1739797F6
+:109B00004D43381E12F1CEBA9A7E05E3A88FD41CBD
+:109B1000A5BCD9AB8BDD665E3ED92324FA6436E45E
+:109B2000E7A4ADDA2CFE5090AAC877E3D0CF09F3B2
+:109B300047438CE4D360B77F3FC62F9E14F28174F5
+:109B4000AA8BF15EB6580F0B17852DFE502FFA43E6
+:109B5000F3A99C3D05CA5F88788E17ED14E41BF4C9
+:109B600087E6A23F34C9EFFD0A7FA8CA447DB5A6A7
+:109B7000BD78294D43FED49704FDA8C2CE51677825
+:109B8000E8FDA8B04BFD68970A7F33F94FCD7DDA29
+:109B9000F9F79B26845546DFA130381E4DBB7479FA
+:109BA000878DDAD96AA6D517023CD6A5DA8187F265
+:109BB0009B8EA33FA0A7D1C3F6EB23FDE751FD8EFB
+:109BC000591857C8013B15FDD3CBD3ECC4E7C4BE2D
+:109BD000A302FF81758CF01F08868B887E60811838
+:109BE000B765F6C40984F3B81ABFD629F45EF962E2
+:109BF0005C16876FAF949885F112639187F1784670
+:109C00006216EA532B857DBC8235D17DBFBEE27CD6
+:109C1000C167890E8A9BEA32233C2ABCEE5D077A33
+:109C20007129C733FA03D46EDEEE0DF66F42B8FB2E
+:109C3000238C71FB3EDC497A6B87447612256CA23B
+:109C40005ED6AC929F3E10E4EBF51B4E6DBFA9A70C
+:109C5000FBF1DEA1A0077BCC897A5B4E2448F1960C
+:109C600046134F2181277BF8659CBFA416F62B0D68
+:109C7000BFBF42E02D1A3436E27E7B40F9D9AFF205
+:109C8000F156E07ADF1947FB35E1338467512F1134
+:109C9000F347034DB3285E04EFA37EB1273820A11C
+:109CA000FFF411801FC68F7A8306DD938FFF39473B
+:109CB0006BD387E75F25F8C1AC9BFCB13CFA96B447
+:109CC00002DEBFFBBD1C0DEDACA8965050EF667DCB
+:109CD000DCCF014B48203DAD3C90EA475F1E4FADC5
+:109CE00007D2FC0C51FD1592AFCF0BFE3DF246168C
+:109CF000C179B036F638CA8D6850CB4538C7B63E04
+:109D0000E8C673E9F162AE57F5EA7216D8FC2CAEDC
+:109D1000CB57A13C8D3673B9561204BCA6E0318DE9
+:109D20001F188F27E5D4B27D1C8F4DCE4A6EBF68B9
+:109D3000CFE8C37498B34ED0A1CAE16ACA8DE5B525
+:109D4000AC1EE11A58EC21E044D52627CAC928D018
+:109D500021C2991C6E261E27E0FEE47A8A030BFEC0
+:109D6000785AE6E31B773A35D4034DB9D9BBD57899
+:109D70001CF59023AF5C908BF26B501970A3DEB68C
+:109D80005797DDA89FF73AC2728367243CEBBA93DA
+:109D90000AE6E7C66AA765A1BC7B449FC6E111E15C
+:109DA000F0080439DDFA6B52E583C56F457EC51CAA
+:109DB000E1B73A942FF4AD9AF04D68A707DAED12A7
+:109DC000C3315832847EF695487FD04F4B3B0FB657
+:109DD00016737D6D88CF613EE4B3213E59077C62E6
+:109DE000E1A39C785E7C343EC7F55BF91CE75D8E91
+:109DF0007CAE8EE4EBD8D0BCE2792495BFBD1D3695
+:109E0000E2DF92A0C1F9DB00BA203868F7D33ABA92
+:109E1000590A7F7BA39CBF355C37F1ABE06FBBF683
+:109E20004BACE73473BAA8081A2F51BBB9AF91FCF9
+:109E30007F9CEC00C1FF19F8FB387DDFC6E46F168C
+:109E4000732EC1F9853C63766323EEDB2BE0FD4581
+:109E5000F93D26F83D161CA078715CF0FB79F97B82
+:109E60001DF0B7EF9FCFDF8C71BFD9B8F52C8EFAFC
+:109E70005797CAE9A117EC0CC453AFCEEF4F3C5231
+:109E8000CBE212F27B94D7917E9864A1DFDD520A77
+:109E9000FD9AF402FC7A1CE9771CD2AFCE691EF75A
+:109EA00075EB10BFC3B901F32F8EF0B837D409AEEC
+:109EB000E3049C1FD107299EBF571D70233E1B0D35
+:109EC0004E3F8DC101B2E3FCB01E8E7F46F2DADB5D
+:109ED000CDF11F0FEA9DE40F8E087A32E9DA50E3E4
+:109EE00056B9B14AACF3D69A387DAFC3941BB77656
+:109EF0007F4C794B776FCED6E55ADC67B203CF0B38
+:109F00007FB74CDFF9DC3B83CBA9EDEBD83EC3B286
+:109F10006F55EC6B7BF7E04B24A7803E114E394127
+:109F2000FD65E2B30E97A05783DA359DAF5705F371
+:109F30007D89CF425F827E4C7A55BB1FA4F3158D7D
+:109F4000ED7A589F6AC436921F0BE881CD40787332
+:109F5000BCDA910E24D44B275E4BEB17FEE5554F30
+:109F6000A6FAB7F1CF6EEA9B32FABBDBE64C46B9F4
+:109F700004E7AF84387A3495AEA21D8B25CAD3820C
+:109F8000255FA48FF437EF0926085E8F48CAAB6DB2
+:109F9000304EDD6F571FC1F3682FECC70540393CC9
+:109FA00070B46312EAF53532CBC6F11B52F5E358B3
+:109FB0006DF2C5B3D0AE45385DA5FBBFBB0C46F610
+:109FC0006E10035C502EDD9E4AD76A5382F28B2AB4
+:109FD000D6310DF3FDD2FDE35D35F24B87A07D79DF
+:109FE000AB4CF95815EB0C8ABF357664EB482785E6
+:109FF00069FB3924E21D3D8F49144F386270BAEF76
+:10A000005AC2EF49AB1D2715F4074C6892293ED977
+:10A010001835C6601C6EEF12BB8E34DE5E5C3A747F
+:10A020005F06E9622996F0686FF351F21F2DEE7515
+:10A03000101CD2F5B1A5697104D33E49CFB75F9921
+:10A04000564F5F3FA08DF6874730F2F5A569FD0FAB
+:10A05000E527D814DC5FBD92DC9F215ED3FAE52CA6
+:10A060006EF7D53191CF0C5831BF3F06F8BA1BF7C8
+:10A07000877AE3C99703984F33781129D96CF0F3A5
+:10A08000D63AF4AB6DD9A02550AE0DD9BBB5CE23D1
+:10A09000E45FDB00860B3CEFFA2993B0AEF5DA43C0
+:10A0A000183F1861374B89C41A1F7D1FB0A997CB81
+:10A0B000055ACF383B53494FC6F827CA159FAA61A6
+:10A0C000FDFE4F5F4CE07E8D6E2F9D4BA0C7D6A14D
+:10A0D000FE7429CA5258B4E735A30EE5CCA4662F06
+:10A0E000D5D716DBCC38F7118A0B5CCA54D4EF03F2
+:10A0F000EC18D723C1ACE8B814FDE87C9E9E1C2662
+:10A10000EDB77C37C7834BCB1FB96EB3043BB61A90
+:10A11000F526328DF2A94CB073F6DF3819FD689E32
+:10A12000D31159CDC5520BA918EF3AAD5269C6E308
+:10A1300063D39861FD4EE7378AE594FB9A6A2473EE
+:10A140007C0CF77CD49F6A5F0DE11340B1EC17F3F0
+:10A1500073A74063CDC9F9FEA13C19BA9FF8DC355D
+:10A16000098B1FD6B4C3CCFAA3857C7C35E24C9313
+:10A170002FE78927A23C06B81FD499C8D74B6DF7A3
+:10A18000887B26E974897F99E287149FA4B8D47BE1
+:10A190009B31BFDABC573275F77B9B0D90DF284FA0
+:10A1A00031F66ADA834F0AFF0403BD04CF91DCCD98
+:10A1B0003615F58ADEC2D8F55512C19BEEC9E2B755
+:10A1C000BCD04FE6410E98760E7A1078BBA2988FDD
+:10A1D0009B8EBF11F47D726007F9AF25A6A33F6483
+:10A1E0006FF5C545A81F96E2FB684746FDF5785F09
+:10A1F000527D2D562F67783F9DDFD3E5C1F9E44AA4
+:10A20000BA3C7117733C6E2CE2F39BE78F551F919C
+:10A210002DF402C0BF05538255C3CEBFE367E68B62
+:10A2200008BD650B769930FC5E4CC0FD90A057537D
+:10A230000F1DD7CDF13FCED443A35C9F83763A5F09
+:10A24000A3DD70BE5AE4A0DA6DACC53C3135FAFC32
+:10A250005D784F20DDDEBD1F6900D6AF1769437EF4
+:10A26000009CDFD4F73561873E56ACA6ECD32BF6C5
+:10A270009565BE77DEFD837D8CFB07B240F9DAFB86
+:10A2800005F77F324D0F9FD0C1FD2D134C7DB69940
+:10A29000EBAB43FBEF9068FFA61DA676B4F2FD374B
+:10A2A000C3FE33E4CB8D2912FCA8F138EC0F0B056B
+:10A2B0003D8938ACE99FF0623B94CF083E403F2D8A
+:10A2C000FA414CFFC7F151E0D354289EAB091177F6
+:10A2D000E5FB60DFCC1C7F3A24E92FA3FD66ACE4EC
+:10A2E000794C45DF096755C1F38A6B56AF5C0AA507
+:10A2F0001CE4F15616EC6FC0F320D0B05B477F51E1
+:10A30000A9BD5FC9740FD0DFA0D13DE111F1869ADC
+:10A3100079E7BC2F5C84FEF84A74E3C80CF5A3C649
+:10A32000EEF438158FFBA5C7FB2C7EF83B33C55BDD
+:10A33000EF14F156F5D352161AC3D8B68565B4BEDC
+:10A34000A7449C5A5D2853FEB2FA6939B507226CBE
+:10A35000BD0FC6071D85E26D8BBCA9715C7B55D80E
+:10A360007068C3715C68A7794373F7B5A27E33F454
+:10A370007DB08670C8AD0DCF3F8487C5A9F1D0618F
+:10A380003CF0766329C7939F196EFC8EFD8E3B7A55
+:10A39000AA916C2B041E7A6E5CB668B1361C171D30
+:10A3A00009FFB89409FE7E25B2093F199423E262A1
+:10A3B000A3C5FBCCFEE971D4A225A9F800785FE91A
+:10A3C0002F1886B3198FBC72182ED41EAA6D959CB7
+:10A3D000BE54B880C63DD4EF502B8F83A7EFE3B7B0
+:10A3E000224FCE979B08A1DC31F34E729E7C25252F
+:10A3F000EFC4837927B9A3E79DF86CFA7FCCC57DBC
+:10A40000DE6DE7FB14E7AC355F73E81E26E0A83B82
+:10A410009847EF8D3BF9AA9B3E873AE4D7CC9CBF87
+:10A42000993596CB8BACB19AE03BEED7A47B5332F7
+:10A430007F0FED92AE4DFCFC3A981FFFF5E5786E6C
+:10A440003DE1D4284FC79EA4FB0EEE891EF267A7FC
+:10A45000C7731604C5BD3D11C71911BF11711D1376
+:10A460006EFFAC780EFD211F14E7939F675190EFAC
+:10A47000D38CE798796A0F07F7BF9660781EF3EFE1
+:10A480007A1BE3B81C718DFFF155F8BEED29399F99
+:10A49000EE1089EF20BABEB4EC04DE45DF7AEF633C
+:10A4A000648FF44A4A3FC9D1C42BDCAE8F7FFDA62E
+:10A4B00095384E87A45700480FEC3BAEA0BEEAD1BA
+:10A4C0004317A15D60EEB3516719EF35940714533C
+:10A4D000AF17790D6699705AEBE9EF158F12C7FF28
+:10A4E000A5B8CFF1B0A3EF7AE49787610FC8AF3971
+:10A4F000953CDEDB6767D918AF0FEAF32E4295C6AD
+:10A500007CEF4890E75B04BB9DD40F7494947CD09F
+:10A51000E78259048F9D229F737590DF9BED7584B0
+:10A520008B50CEB57EF94F644FED9140BFC7F23BE3
+:10A530001F2418D9FDFCFB949E6E79913377647EBD
+:10A540008FA94799F43744978ABAC9AA4775153233
+:10A55000D2A3EEB2F5D33CE97939669EC6905CAAE7
+:10A56000E6722B7051C48DE783FF9AE89C4950FE38
+:10A5700050C825CFE69FAD586AD97F5124D68A723C
+:10A58000D29443A576C36DC6E7D12E2B413904ED95
+:10A5900025B133AD64379B7248F82BCC7C8DD1CE7E
+:10A5A00007903F3F09629EDC92CC791CDE1A919F96
+:10A5B000B850267B75282FC91157F0DCBFBF86C75E
+:10A5C000EF43735B25ABDC06B945E3FA1BF8FD7579
+:10A5D000A03B3AD7370BFCF4258E52DE15E6AB6173
+:10A5E0001EEAB65A1E87CAA9DCAFA03F15FEEFC609
+:10A5F000FC46A386111FF4D9C372B585AE5AFD9CE3
+:10A600009F2B3A24A20B66EF0BD077BC591FDD3F7E
+:10A610006B13F76DCC3CC4A1736339CB18FF1FC219
+:10A62000CF4AF3DC88B9E7029E76F63C46E7C63BA4
+:10A63000C3E74629C93845A5EF3A060C399EE93BE0
+:10A64000EBFE86C468E7871B59DE23F0365A3C7C54
+:10A6500058FFE5F832CF0FC0570BC235B822735EF2
+:10A66000454B70E8DCA07EA1DA07EAD2CE0D03CF1D
+:10A670000DB39F3FF1A142791DF81330E86F492EC9
+:10A6800091AEC5F58414AA6F017B385C43F737920D
+:10A69000689FA6DFD3B8F070BA3DD44AE36E51424A
+:10A6A000BEEB119E0D3CDFE992D752FBCD2EFDA9EA
+:10A6B000EF06D403EBE469FCDE9878CFC30AE6D357
+:10A6C0007CFC9CF9CADBA9EF997019EAAFF27B57C1
+:10A6D0005FFDF43CFD7C3C5F247DFD5728E9FE22B4
+:10A6E000D13F102AB8B16678FD5F0BA4F66B58F421
+:10A6F000D3826F645A7F1050EF1B5EFFD595AE7307
+:10A70000AF4BE3EBBF6EC679FA95675EFF0DB347BB
+:10A71000597F657236FE5EC4371ACE33AE9DCFFFC9
+:10A72000CD15E7EEF7ADE6F4790C71FFAF5142BD00
+:10A7300000EC8024C589D952E9BA34FA213AF89B51
+:10A74000E9C7F0CDB3D04F3A1DCCAD7614CCCF488D
+:10A750003F026F02FEE7A50B413FE974F045E92790
+:10A760009D2E86E9C728F8BA857ED2E900CE51A28F
+:10A770001FB5A19CF87224FDF0F7CE4B17827ED254
+:10A78000E96024FD707A485F7F3A7DFCAFD185BADD
+:10A7900094E488952EE6FD5D749120B961C2351D63
+:10A7A000BFE1BA2B0B6ECC4817021F822ECE8B6FE7
+:10A7B0004117E9F8FDA2743112DF265D00DE2D7429
+:10A7C000918EDF48EBD23CFADDA7617AF862F8D5CA
+:10A7D00000BF9E2FCEEFE97EE9743CFFCDF8D59601
+:10A7E000129F5BF17BC3DF756E30E26B133EE9783D
+:10A7F0009A7FFD8682AF67C4AF80ABC0EF79F12648
+:10A80000F07B5EF93C0A7ED3F1368C5FC6F3D11B38
+:10A81000B89E978E37C0AF3B15BF7F1BDECEC78F6C
+:10A82000E9781D0D7F5B47F98ED047E3B87DF2BE16
+:10A83000D00FB6BA33F7FB6FD1EFD271A25FDA77E0
+:10A8400008874AD1EF1EEC07E561D1FF505BDF0AB4
+:10A85000B4C32EB2B5D3F712D3F7B15D92C5774F1B
+:10A860000DC99ABFE42BE176C49E1630D0260D3F69
+:10A870008FADEBAF43FF43A079A015CB9275F940A4
+:10A880008A23E1E4FF74020B4DB7CE17E7FE8B0578
+:10A89000FC3EB6FFD389D4BEA745A1F1717ED4B7E3
+:10A8A000478E9F35CAF885E7193F98DA6E9B4BDFD4
+:10A8B0006FC6CF5F64FAEEC0F69678CCFA9DCDF401
+:10A8C00032F0C1E245619197A4F8E91E3AFD1DBC42
+:10A8D0005C4FE27DCD9D4BF3ABF1FBD1EA788E87E7
+:10A8E000402EF71304B2B8DFCD9F9BB51FFD90ED4E
+:10A8F00039DB5B9741BDBD2EA053706FC9CC94EF7F
+:10A900008EDC27F3DF2130E699F7256347D04EB57B
+:10A91000C92C4971BCB4FEAF94F0F9DA457E5DA054
+:10A92000D946DF9DAFDCB744C2EF843C23DA95B84B
+:10A930009DFBDF9130619D531E718AFA822D2BCAD7
+:10A94000F1BB76067A8E59B464D675B333C44F46DC
+:10A95000C24B977E67815720EDDE9659464BFEB677
+:10A96000FCCAA325DC9E30F3057B96AEA2FCD2B8D0
+:10A970004DBD837D85E041F9953B57A6E757AEA2D3
+:10A98000FDEE5CC064D53B72DC83F9911DF8FDC01F
+:10A99000E1FC4ADE3FBD1FBC6FC7F77B16A4E6573C
+:10A9A0008EEC175910CAB0FEA858BF997749571DA9
+:10A9B00035A413A6239DF49CE4DF7374B1ADADE818
+:10A9C00047F928A4E89D19E880CD8E499877DBD314
+:10A9D0006A4FE2FDC89E9C1EA28B9DD73326E5657B
+:10A9E000E8FFD959BAFF45F157FA2E14D0B322D651
+:10A9F00085FE1114F6B018DB2A27D95FB69BF87DC7
+:10AA000039FC4B9A7E68B49795DB5A97E1F9A2CA54
+:10AA1000FAD7309F9F45FBD12FEE8F3853EF950823
+:10AA2000F9B6D311791D386EE8FB233D97A5CAA767
+:10AA30006D021ECF95D8CC7C488AAF381A8EBF865F
+:10AA4000E33ACCEFECF9EC29DF336A17F7A48D3B3E
+:10AA5000B89DD85391A07B2C0937CB7714C3BC1277
+:10AA60000B61BCC09094A17BD7F8FB6EC5822F7B95
+:10AA70008EF0DFABD8792F93F0F73C0EE687DA70D3
+:10AA80005F86CCC218CFDBF940BCD04DF69876BDBE
+:10AA900003932A4221CD67F98ED3CE0D4F16DA38B3
+:10AAA0009D55A3DFAABD997F676BE7E78CCE9D9D7F
+:10AAB0008B34CA57DC83DFDD82AD95AFE0BF779082
+:10AAC000FEDDA074FAE8C979AC10FD78ED92FE1AAB
+:10AAD000E6073DB8F7EAEB1A800FDB2F4BD870BDC5
+:10AAE000ED052CDE5A3A0C97F4F7D3E134044F0FFE
+:10AAF000C0337774786EC33D1658F37023C4573B48
+:10AB000025ED0E8C779A79B83B17F84B31EFCAE4F4
+:10AB1000AB9D4B393F01FF2CA07CDBB66C097F0F4E
+:10AB20000D9E2BC4274B8195CFC9278CE4CCED20FB
+:10AB300057F0F7D2CCFC5DA6F65D306FCAB03C157D
+:10AB4000DF94646F097A718DFFF19F10FE3B5638D8
+:10AB5000E97714D2DF33C72F5CE13C83FB4EE787F4
+:10AB600042F15DA7C200BFE737825FC6F3792E2BA3
+:10AB7000E17E12F3BB5587CA42F5BF8775F69CB2DA
+:10AB8000519CDEF45FF62CE0FECBA1F50A3A718D04
+:10AB9000DF4D7A4620CDAF1918F26B2E2FFC2EC256
+:10ABA0004BF835779EF95E21FA357B563E7F81540E
+:10ABB00065954F7D7FA2FCEF55C2CFAAC6E89C38B1
+:10ABC000585FA96792FBE7DBDF9B25663EFDB9F77F
+:10ABD00033E29CFB3BF771598996123736E1699E47
+:10ABE000AB1305FD99E76FA9335C301ECF85488410
+:10ABF000FC379A78DF9453CCAE57D2BD5CDB3D0C6A
+:10AC0000ED990F5FB5D1BD9B7439972EBF8C7AA398
+:10AC100095BE6B2EB3A687D49172D0CFEAB7CC463F
+:10AC2000F8564624FC5DBCF6523BC9DF74F9B6C940
+:10AC3000D1E4C2EFD3AE6F09EFC0EF383D0A7BC05D
+:10AC4000EFA4347B14CA975F2FF2968D9C2CD23FD1
+:10AC5000D3E1B8B88CC3FF89BCD802D41B0E490F0E
+:10AC6000A4C40D7A354E7F5B84BEC06A226EFEBDE1
+:10AC7000E6F5AFE0EFF36CAC95298FA723BEE404B3
+:10AC8000E677EC0AC8F409895D8146F72A9C779D2E
+:10AC9000AC56509DDFC3315446DF29DA18687B0576
+:10ACA000BFABBD6BC934E29B634B641DF7B943F581
+:10ACB000D0EF8DEC5A27FA0779FF59B6D37330DFFE
+:10ACC00062F76AE774FE5DABD0B5D5963CF2636B74
+:10ACD0006625F077371E99E1A2EFFE75455FE947DB
+:10ACE0003577E292FA04E6B14F0829614DC7EFB516
+:10ACF00026197E9F2D1000FA81FA2E493FAA703F37
+:10AD00002CF9158FECDB48719547AA18AD63F7C293
+:10AD10005002F3DEB7376433FCDEC9EDE3F9EFE44C
+:10AD2000ECDAB7FE25F4DB558E2BA7F90FECBBB898
+:10AD300008E963D7BE8DF4DD989C5A7BCAEFE71E05
+:10AD4000E97ABE10E92C5B4F7DBE6B41A210F3295E
+:10AD50005DCCF25CF02FE6851709FE3DB1F6943428
+:10AD600040C1F8D47EE356E832D90F510FFD5EF0B2
+:10AD70002A9017C85707E4908CE786F18644FB7A3F
+:10AD8000D461B8AC78BD722AC7ABF93DB2CA5239AA
+:10AD90008C7ED30DE27CB47B383F99F84F2FCB36B5
+:10ADA000CD3CE7EF8C142A37ECB07E477187B02F8B
+:10ADB000EC6ABFAC023C8B9F55ABF13B5FC5ABF976
+:10ADC000F788775F5982EEDC217ADC7DE4A542CCFE
+:10ADD0004FF53FE9D131DE777CED3209E3C477E40A
+:10ADE000F1DFFDB9CBA6B622BDB0C51ECA9331BFF7
+:10ADF0007F0DF222E5FBD779CD3EBD7C3AD96BF4CD
+:10AE00003B16AAE6D7CB416ED89B9D3AEA79B39E12
+:10AE1000AA1A3B708E7DC45A54BDDC817052A88C36
+:10AE20008978F7979E9AEB6DB4E8658F8E9752BE3E
+:10AE3000AFE66ACE8E59F7EF18C7E10B7F85D6DFF4
+:10AE40008B5A28E0199332DB4B663BAB0905EA606D
+:10AE5000FFBBD63A55F40FD5E53D5BB80AE317AB17
+:10AE60009D2AC263F79A539B16A23C396963C86F47
+:10AE7000BBD73E5FB8CCB2BE5D5266BBED4571BE7E
+:10AE80001C2834764A94D77AE006FC1D84036E634E
+:10AE9000277D3FC87882D72526F4F04337E0FD9D13
+:10AEA000032857803813E3AFBD01E32307F28C9BDF
+:10AEB00064157FB76DF743C7402E1EA8307E8DF90D
+:10AEC0004E759358622608BD03A5BCFFE449035B99
+:10AED000A8FF145E9F3AE9E91BF0771376E17E60E4
+:10AEE0007FF67D4E0212F0573EF2D1FABC470B318D
+:10AEF000CF786735485B584F5C0BF72B30BE5D8AC7
+:10AF000017A25DB2285E1D9EF9658447F936DCFF05
+:10AF10009E7E07D1C74E47FFA685082F80472BD4BA
+:10AF2000778DEB2FCC140F8DB604F42800AC53941E
+:10AF3000E6F31C3DA03F69E1D3ECCAD4FA2EA99FE9
+:10AF4000D65314D7C3F64BF13B5FFD3BB09EA5B97A
+:10AF5000793DA7BF10F7FFDFE3A5B0BD10BF23D930
+:10AF6000BF03E1FBC7F17FBD6E26EC7B97A3AF501B
+:10AF70003F07DDFDDDEB12E3FEBDEF8F36BF39EE9F
+:10AF8000FFD6FBFF0F9C21913D00800000000000D8
+:10AF90001F8B080000000000000BED7D0B7854D5DE
+:10AFA000B9F6DA7BEE6132B3139338930C30937BAE
+:10AFB000C2244C22A5811F7588FC16909E0E089A0B
+:10AFC000684F9FE122241A74D028D8A36527041063
+:10AFD0001B61C090E6DA0E097082800EFE8A97DA55
+:10AFE0007326882D5ADAA6E8B1470B16ACF51CFB80
+:10AFF0001F7BA2F5F67BD49EEF5B6BEDB9ECCC2406
+:10B0000020B61E9FE7CFF3F06CD65E97BD2EDFFA19
+:10B01000BEF7BBAC358410F217FC877F5712D2BE47
+:10B02000D1E6692F22E47EFEECD585ED1E3721E9BD
+:10B030001E9BE79091D03F2C3FA93431FD57AC5F68
+:10B04000EF314F5C7FB95320247B9C765CE7D74E71
+:10B05000AAFACAFBFF5FFFCBAD9FEBCC27E46BE7FF
+:10B06000430F84969344E20F03FD6DCEAA352E77ED
+:10B07000C7DA71578A347FEF54568E102FF1A5131B
+:10B08000D2D378B5D10F74D277CF88C95B4048E965
+:10B090009EBD264C97661C33B96610D21D10250242
+:10B0A0006D777FB2C9E8CA8267BB28B542BA4D3A0C
+:10B0B000B5A018F27BEB444903ADF5D555A72D8417
+:10B0C000B4DC2C4AD07DD25977CCB4D21CFB7E5F45
+:10B0D000B3383F04FDE90B9CB2AF8E7BDF2F90BAF3
+:10B0E000B019FBA38D18A0FDEDFEFC81FB5DB1FC4A
+:10B0F000536E81F6B7ADE1D42BF8BD1D4D221B3444
+:10B10000193D7125A40D734427963F7EE7D1DB09D5
+:10B11000A4FB1D6662802AC7E79C5A5002EDED9899
+:10B120002F7A0CD0DF629E76CCD77A9C90EE6DB8E9
+:10B130005DC4F25B9A61CEA0BE23E0A7ED596DA27B
+:10B140005303E9C9CD81483F944FAF31481A0F21CD
+:10B15000C35266449E41C7113240FE161288FC0459
+:10B16000F265AFD1B74FA21DB256E5107209FE0FBE
+:10B17000DABFFA111814941F74135ABEAFF9F6C847
+:10B18000992C9CA74984407BBD6E171D576F53B502
+:10B190003005CA6DB6698806DAE96B7F54225035EE
+:10B1A0007391F6F5B371EB9B3E27314DB43E1FB65C
+:10B1B0001FCCD692FB61BC93485C3E346D50A59584
+:10B1C000F9D449464F6169AC9D0CAF949056CA2999
+:10B1D000CFB68D4F92DFEB62692D104ED83DB65C35
+:10B1E00011A72F42C2765F05211B48E077F7C2788E
+:10B1F000C988C6B30FE9C5F86CD71B97417DD3CF7B
+:10B20000BBDE8049B26F98D487E9B68C99FFBE1A2D
+:10B21000CA75A4A779908EDA368E74B50101BDF790
+:10B22000ED198DAB217D18FA8EE3ECFEA6181AC03D
+:10B23000FF9320B91BD29993C510AEBBE6DA9D4EA1
+:10B240000215B3A582BE3668D7A4099412A0E35DA7
+:10B25000C45B86CF9FF1FD93413C3BE6C23C9D78A9
+:10B26000B8FCD2B330BFD946565EE9FFEE03C6BA8A
+:10B270009079ECB87A2A44CA670F6A23F566E867C2
+:10B2800027314848079DE1C7EACDF0EC215AA700D5
+:10B29000CFAC3B66BE83FDDDDE00E5719FD4E943A4
+:10B2A0002502611B0DF749BD7E00D7290B0789F3E5
+:10B2B000728B3EB40FF3B59E1BB09DDE960CE97EFB
+:10B2C000781E397CDDF2CDB88FF6A5798A68F5F065
+:10B2D0001F1F82F2BD8B6D9EFB611E0F0B9E1BB06C
+:10B2E000BEBC4C4F58FD90BD2E3DD6DFDEC6EB5C9C
+:10B2F0005E184707AC19C9A50DC804E840AB89A57D
+:10B300008D909F35C9BB0EE9B0E3B0E97AE32C68B4
+:10B31000378DE55F52F942A73C8790A165334B0911
+:10B32000D0635DBE7BA7A90AC62B046FC7744759BB
+:10B3300049A70DCA1F11E1E3B3F9F86AA0977BF49E
+:10B340002C2D9F7C691E1049366E539A3FDCE10517
+:10B350007AA98A7D9F88D09F874C4A7E786983032B
+:10B36000E67F58CFF26543F65CA87FA496E7CBAFA3
+:10B370002DF53AF07B89F58FE895FC8FAF6D80FE57
+:10B38000565DA5A43705B1BC3BFA7D56BEAA40C99F
+:10B39000FFE74EFC9E325EA5FF590625FD93CE06C3
+:10B3A00037D263285F82F1BE56665B36FF0AA4D3AC
+:10B3B000EB5CC817AB0A82EB7C945FF95C4BD2C79D
+:10B3C000D2CB4319CA771F3F85EB707089918FEB01
+:10B3D000BBBBBC8574DEAED1409945FB7EB8CB6C5F
+:10B3E0008F9B37F2D829AF16D797D5CFDD73E9B544
+:10B3F000AD669AA6FC51FD9DE9C5264AD730AF5EE1
+:10B400004D3C3D39C93537215DAE95A5FB2199A746
+:10B4100065FBB5A7517FC92228B773AD385B0374AC
+:10B42000448C11FB0DB04FCB5C6994BE77EBD877A1
+:10B430009E3C2B7E1FE9AB37206568A03D3110692B
+:10B440003907EF371767D2EF3922C7EC02A47B1D0B
+:10B4500003F522D261839E1441B99E75AB4DCF4155
+:10B46000BAC724D0FDDA937EBADA8DF98F379122EC
+:10B47000F8DE56C7EB54CE28FDFF41B186B6B7BD06
+:10B48000A93A8CFB7FABD92C61F737E9C20BB1FE2F
+:10B49000A6C3226981171D622857003ABDDAD51F5D
+:10B4A0006C8375EED0B375FA59C96050C67E484EAC
+:10B4B000930ECA77D58844067ED055B7644F01EE07
+:10B4C000CF76262706EB965CE681F677D5E89D4495
+:10B4D000887D7FBB20D0F166EA3CDB8A203FF39B6E
+:10B4E00099821CC7FFEEC957F81921E69984A4B1C7
+:10B4F000FF92ECEB86BCAB504E8924807221CB10BE
+:10B5000022FB903FBD6F210390EE4BF7B904C84F6B
+:10B510009B9D26CA945F9DAD43BE31091AC7FDBDF0
+:10B52000FDEF9E9671BC7D8404705C84449E47B997
+:10B53000666E1609AE575AC3D108A6A55AE3A8A14C
+:10B5400006DF0F10940FE4132BC822EC7784CA2572
+:10B55000F96EAB847227CDAD27CE38FE6D26908E66
+:10B56000E3FB7DF9997C1C308F28CF86F41EE443E1
+:10B5700061A03527B46BF39210CEB3747A5244AC09
+:10B58000C4E7DA45049F8F79FE9E3E4F9BCEE19340
+:10B5900078E3BE032CF51D87EF1617D08DCD4F0431
+:10B5A000BF9BBD7782FCB3F2792262A87E127C2F0A
+:10B5B00007240E8EDBDAB4A22582E3706A035618E4
+:10B5C00087B5EDE6169C076985D98FE3CC9993384A
+:10B5D0008E289FBC9284F6B9D87B2DB68F444297B3
+:10B5E00056BA06E9CB72A5587D3F4D124A77963B75
+:10B5F0009C542EF47A585A5EC5EAABF74F73899E75
+:10B60000CE8BB2BF880D5602D67905CC0BC96769BF
+:10B610003107BB0BFF87BEAC2E61FB2D6B1209847B
+:10B62000E978C3260DB45FD0949F89DF2352C88E7A
+:10B63000FCA0319FE1F26CD1B77C33F6FF2E3D9533
+:10B640007FEAEFDFC6CBD13FF8EE14C2BE63D19CD8
+:10B650009DBB6606FDBFF3711883E57F9DB6C7EFFE
+:10B660009B3BF385285D623D847328E7A636EBBDDE
+:10B67000A6CAD83C4D266C1C939B44FA7E72C3D15B
+:10B68000F58205DEDD67A0F30CA397FF02F3E86CFB
+:10B690008FA317F837E59EC47598ACA2277B20B11D
+:10B6A000BC4E4A2C6F55953F92C6D6B1BB968406C8
+:10B6B000983C9C8BFBC1EA07DC02E393B4E43E2B8D
+:10B6C00090E8932E361F5F43FC9A84DF3971FEB3F6
+:10B6D000C7D22189FF9E666CFA6026A783D984F1C0
+:10B6E0004755BEC5689127C1BC58485CBBD0EF55D3
+:10B6F00085AEE8FAC8F1744DCE52DC9C6519F5A20E
+:10B70000DC27B5C4B30FF8B9E5D0EBE49A1994106F
+:10B71000DFB5DA687EA43C8BD2EA28EE53CB9CCF0F
+:10B720000CCE2438EBB602B69E438F3F6377BA51F6
+:10B73000FF037A84A749350F95F98C5E2BF3191E08
+:10B74000D9793CB3EC39A0ABDA279E2132F2DD5730
+:10B75000341467F63CE5DC8478E283B9C42343BE45
+:10B76000F5E45902DD85F61D73F1BDC32F10418A42
+:10B770009B57600CA26DE267E773618A77FC807F5C
+:10B78000842B92E4EBC2AFE07EDEBDD8EC9149ECB5
+:10B790007D38F2A809F983232246F1026EDF38FCD6
+:10B7A000201B81AF9745F1C1C225E3E20579D6128E
+:10B7B0008A17D672BC406EC94CC40B372EF1CE1915
+:10B7C000072F90BF5B928017101F8D8B17B63D38E7
+:10B7D0003E5EB8E7C106C45BE94AF97BAF45B95F95
+:10B7E0002E0ADF27809BF206D63C689E8578CCEB3C
+:10B7F00041BC65D8B32988784BC15FC5F9B3AF8B1D
+:10B80000C75FCDEE4B7622FE0A1B47AA31BF7DA74C
+:10B8100061E7F398DFCAF2E70F942D66F9CAF70CD7
+:10B820003B87917F19C326C4DDEA7D73BEEBDCAB99
+:10B830000D9B2494A77C9DACF996C52D80570EECEA
+:10B840007FDACE708FD7B61CD6D77EBDD13340A756
+:10B850002111FFE89A5EBE41A88CE19F9B8BB60642
+:10B860005B601D2B34C02F93ECE7799CFF550CEAED
+:10B8700003A817D69698299FE85F7BDD5EA4E3DADC
+:10B88000274E77A3FCE87DA55E87FA5C6DBE969691
+:10B89000EF7DCA3F55A2F88BE919686FA1FD7EFCC8
+:10B8A000A440DC63C7E508E9BD88EBD5EF67E73363
+:10B8B0007EDE5BC4BE3BF4B839445C38CFC1465F22
+:10B8C00012FDE65ADEDFB68D400025F87DBF807C94
+:10B8D000E041C9EBC5EFE664F964D4DB74A0807B7A
+:10B8E00093E8F7DA8FF288374EDFC8CCF012ACA7B6
+:10B8F000FD680A7D7FC4E85B960FEDFF7EFE40E3A6
+:10B90000F7A15E8FC8F956B19EC93F6DD0B618C673
+:10B91000EB9CE2ADCF877E6F12BD3BE627916B318A
+:10B92000BDCDD7DD16674768D325C7919EA95CBFFB
+:10B93000E67A1EE823A5382E147B8CBEAFF3E17E99
+:10B94000DCC4F74759E5751477658B619316F9DB0D
+:10B95000ADA244F92AF0942D33A928A2F2B97FD9D7
+:10B96000901D9FBB5C0C47815C0B3F8BFC713DC8FD
+:10B9700043C218841827F794FE74BBC428DF4D26F1
+:10B98000C7422E27CBE7F515F9A7C8372F91E9BA9B
+:10B9900090297E19E7D35627CA86CA184EE958F26D
+:10B9A0002AA567FC9B00D779D7FC0FC675CB5D191C
+:10B9B0007C9E12711DF0A54032FD7C4B095BE72C8B
+:10B9C0002BDB8F543FCB42FCE71CC0F1087E328C4E
+:10B9D000F68C02E25CF20D29563EBC543F7C0671A7
+:10B9E000A24D43E586D42EFBC4F3C087A3937D8F7D
+:10B9F000209DC6E3C39A3839EAD58C8F0F67184665
+:10BA0000BD43C86FAE320606E0BB390D5BD6692C6C
+:10BA10006371E28F4A18BD94A60597E3BE25819015
+:10BA200069491C1FFC5109DBB751DCE687FCF48B2C
+:10BA3000C0979B18BEA47A1AAED7BD0C5714118FAD
+:10BA400088746CCB3A2B08409B8F73BC12FD2EC7B9
+:10BA50009737717A56F0E50A4EBFC74A14BC1132C7
+:10BA6000A13EB732A0E0CA113B8E279BDBF5A0A810
+:10BA7000B1AB9A3EE757C0F3B77C7C056622238EB4
+:10BA80002A586AA4FBC4A281FEE0F8AE2504F1099D
+:10BA9000ED1FA69B9CCE6767619AD5FF0DAF5FC473
+:10BAA000EB17D598BD260B5F24E8EF6ADEDF1E8713
+:10BAB0005F5F02E30795D5F928A56F1FB59F397C15
+:10BAC00040FFC8F3B53EDABEA34972D2748781D273
+:10BAD000AB823357B41B12D66D86C1AF37607B2B58
+:10BAE000CD747F157424E2CAD5CDB09F2BF1FB89AC
+:10BAF00074AFACB3B2BE23258CBF8C9428B838B4D5
+:10BB00000DFB35B90EFA05E5731CC1B9A8AF030EDC
+:10BB1000A57698EEBBC81E8A438D8C7FACE4E35BB0
+:10BB2000D9EC5F908EFB414306100F105BE879C49F
+:10BB30007783CDC54EDC573D46CFD5C80F7AFE235F
+:10BB4000DD29437F330BF87A61DFE2D671F8D4AB9D
+:10BB500026D4978FA01C81E7709D48904FF6B78B35
+:10BB60007B508EF5371C3339D1DEDA7ECA84FCBFB8
+:10BB7000C7C1E86A701D09B5227E6B5E21A01CC991
+:10BB8000718C6C437E616F10C90089AD07B509895E
+:10BB900074BE6B713D1C4472F648383EF6BDA280FF
+:10BBA000BC0EC02C296A67F357AA4F9CAF937CBD8B
+:10BBB000956774BE026CBE1C7CBE8876444079A337
+:10BBC000CC93C2D70B9AA1FD4AECF7889DEE373E85
+:10BBD000FE557CFC304FB56BB262F3A4EC2BBBD2AC
+:10BBE0006F12A6E3CA6912A97D424D173D8EE0305F
+:10BBF000E6F708C4B90BC655143424D045CEC90E97
+:10BC0000A637FE29DD897CA2605522DD4C9513D331
+:10BC1000B60D89E994FAC91584DA1773547A8075D8
+:10BC2000443C67B024A9A767F3ADCCEB370B181DD4
+:10BC30003EEC6274D832FB214A4FBD020919A85E5E
+:10BC400010EE2E46BD07D613ED78C021654C5BDAA9
+:10BC50004804F5A0DE5F7FEC4579D2F79485DA875A
+:10BC6000FB3E3D47D3832D5AD20AF3603D7E36D248
+:10BC700000ED7C6B2B407018774FFB0734BFF30F40
+:10BC80005ACA972D759D4B902F5B54FC7122FD482D
+:10BC9000D167CE572FC2BF64FA10D5B3A89DEB8DE4
+:10BCA00020E2DFC32D2CDDB0F78DA0EC18ABCF2840
+:10BCB000CF17393E80FA0DC8DF0A975A08EEBBF756
+:10BCC0000FE5527BA952AE85CFEFE17C86CF6C1F8A
+:10BCD0006948047053C551235DBFDEB5390368B7A9
+:10BCE000B749CCDE75ECDC13F6EF211D1ECEAD4658
+:10BCF000A8DE73EE1FED02EA578D47CBD17EB55516
+:10BD00000CBF508EF8EA512DC523271E4EA3FCE12F
+:10BD1000F6C9697B0C71B8EA11FE5DDB86837D682C
+:10BD2000B7EEDE2893DF17C5BEA31ECFC3956CFD0B
+:10BD30000F8A301E8653EBF753FB6EA5703FA58329
+:10BD40006023F6B7A7B1D885FBEDA09E8DBB7BF530
+:10BD5000D302FA6B7AD612519A3EB6DD8399E15737
+:10BD6000F4D85FD122ECCB8A95579783FA5AACDF8F
+:10BD7000BB96A4C5B7D3B3B6B3DECB710F7E7F8BB2
+:10BD8000C3B107E797F880DDE0FE64BA398C97F716
+:10BD9000FF0A6667DF6E17295F22BE9D2D2B216D7E
+:10BDA000B8CAE8417A25ABE679A3FE05E09FF6E044
+:10BDB0000FC806A0013B00475DE6D8FCF0D2BB4EA1
+:10BDC000A0FF28AF41F4084EB44B7A46A9BCF73324
+:10BDD0003CD8693BF6CA30BCDF6AAB1E1D86F43F17
+:10BDE000179453FEE419D6CAD47EDEBCFF21B447B3
+:10BDF0001A56AEBEAF9824B15736707B65C348CB98
+:10BE0000399897FF3B8DD9BD26474E517B65671307
+:10BE1000F33FA9E7EBCD693AA64F1785A81ED1736A
+:10BE2000E77E3BF2DFBE467D1D96EF6C3AD6BD7ACB
+:10BE300006DA27176531FB24B3D76F6AF16A5B66B0
+:10BE4000C4EAE3DF85D809FB114FCE88E1C9492454
+:10BE500042F9A78223FB1147C2BEEE6F7A34827C7F
+:10BE6000A2CF6B1C45BE90D6F053827C1FD48C11A0
+:10BE700003608841214471A4FCA995ECF38CC58D25
+:10BE8000803A22FD909FBEC12ADD2F8DC591EF948F
+:10BE900033FCF405D803DF2EF80AD9030BC8A840F9
+:10BEA00018FF13508F7CAB7CAC3D3041DEAAEC8395
+:10BEB000BF29E7F628C54E88E50A26B60F66177231
+:10BEC000BBB24A5FC2F288137AD6825C74C5F0DED8
+:10BED00014C47B99F439BF029E2F9633B93D05F106
+:10BEE0001AE0B72988F72C54BF12707C0ADE9B4AEF
+:10BEF000789AE3BDA91CEFFD8CD79FCAF1DED43838
+:10BF0000BC97A86FBD2BD0F9067C573B0BF5AB0F48
+:10BF100068FA1F6E234E11F1E37D8972F97F8A1D45
+:10BF2000717E61A21DB165765A0BE5B77707ED8684
+:10BF30002AE4BB4717A423BE20C10388B3E7171A1E
+:10BF400013E22862FC728509F980B54E5CAE47F9B0
+:10BF50007F7C6431E22AABF7C2E4EBE7B53FFEBC7D
+:10BF6000DC15B5F39E8FFDF1E0A1475F407BE38ECA
+:10BF70001A919ACE0E1E7ADDB82209BF539E6A7BB3
+:10BF8000E48B48A3D928B783F5C9EC1FCF73BD3C18
+:10BF9000CB72D68BFAA6F25DEBA17713EC9E96439B
+:10BFA0004CDF56B79F853446F1C15B412FB36FD24A
+:10BFB000F41D836F056548AFD730FF2AD944289F09
+:10BFC000FC303FF0BB7B91EFAF2DAE423BE6610111
+:10BFD000F807CE638B99E68364684D43BC2E5BC93A
+:10BFE000FD4817EB3ADF590DE53ADCA574DEBA6F70
+:10BFF000EE3C6784B44B2B67625C42AF7F17F59FC2
+:10C00000AAC7655F15A1FCCABE41E3447F74F4BDB5
+:10C010003148F5F79C97344486AFE50497B7E8B00C
+:10C020007FAB08B5E7831C1796C6E9990ED8C411F3
+:10C03000F8F42DF0A438C99F46D374FCB09F32A702
+:10C04000FA77157E0DBFA3A7DF2135CC4EA1F83DB1
+:10C050005FDEFBA90FA01E9A0C2386CCD4EB16B58D
+:10C060008BCA9F48B5E6985DF48EBD9FF81067AD0A
+:10C07000D748B71CC27EAE49A3FD1C3B8F6412F5A6
+:10C08000CBDD2452B90BB8A916E9D3BE5E3C80F8CB
+:10C0900089B865A11EFAF574A591CE636C9ECE0A8F
+:10C0A000683749324F0B501EE5E13C41FB79C12313
+:10C0B000C3885352CD5325CE13347D19CE9340E718
+:10C0C00045403BC19467D2E87B855E947912F219B2
+:10C0D0005D46C775E304E3AA4F1C57CE0E1817EE52
+:10C0E000BBC2B3AD287F6C4DC15948077F2861E3BF
+:10C0F000538FA7BB7D899524C1A9CA338FF7BF820F
+:10C10000F7DF6E0C0B923BF5B8617CA70AA1FF39F3
+:10C11000CFC4D143DCF8A2766A9964D4BA6376EAD4
+:10C12000BEBD6431AE6778A9E257FF742402F4D132
+:10C130001959D178C889F3C1EC3849E681CAAFDE14
+:10C14000B56FD2F1E6DC416621C9B8B4A3C770FF70
+:10C1500074E1F8219D51CAF8DE98F1FB61FC28BF1B
+:10C160009C8C3ED5E357E8DCC3C79FD3A45AB7895C
+:10C17000E7E3CF8571FC363A0FDC7EFFC4DECFA843
+:10C18000BE10E517E43E5F246E3D26D213F4455FF2
+:10C190008E9E30A388F1C7F3D5137E5CFED5D613EF
+:10C1A00066143139ABE809BDA827D0723B8711C7A7
+:10C1B0007D5E3DA137FDD0F3C8863453EFB90F9FA4
+:10C1C00086DB18DEBFD0B889CEE7C8D304C675C9F0
+:10C1D0008DFBA95F2097FB01D4F35099CFF6812DF9
+:10C1E000C73BAF287B623FDCC22286135FE17A7EC9
+:10C1F0008566A4DC0858AE53B2EF9C7739DD97947E
+:10C200000F912BC5147C8AF131F9F2B4043E65DD3F
+:10C21000C1F9AF83F1DFB74B12F7A7750EC3D5286D
+:10C22000974AB3CE9FDF4A7CBFDEC8E512ECBF550C
+:10C2300045545F89E3479AD83E8479AD4BA627E5FC
+:10C24000B8F4CC5FA31A6F872855A19EB2CBBD3539
+:10C25000A885F4CE2566BE2E0B3A31DE85E2762522
+:10C260004EC8887E4B91EFEB05D73540BE746234E3
+:10C2700062063AB9ABE8C7BB8CD03FCB88527EABE5
+:10C280002F02F9441BB6FBE2EDB577F038178EF7B5
+:10C290007B1A32AB919F5B7FD1D642E75D20A345ED
+:10C2A000E8371F096D43BD89CCCBF41439393DCF34
+:10C2B000A4A62A6E3FF3B750BD6AAE2D4CE994F8A0
+:10C2C00087B13E746D94DA63D6E959DCD903FA502C
+:10C2D0003EF5BFC82D8B209DEBB58DA21EB5E3E4C6
+:10C2E0008A615C5739607116A15DFCC4484B1AAE77
+:10C2F000833C9514C1D3EB75C8AFD3F985F983BEE0
+:10C30000E736C3F851AF7B40BF075D9F397EC88FCA
+:10C31000E39B3E1F2B2F6079500A7A1F60FB505D14
+:10C320000E5688EA2B39FE39BC7DFE1EC683DFCF50
+:10C330008315473C049345EBFD0BAE3B7C3FAF2E92
+:10C340006447DCD57367673DD2D173192CFFFA7946
+:10C350002CBFD468D4523BA4D749E32FFF9EEB09EE
+:10C36000A9E4E017FDECDD48E4D7815F6EC727A89C
+:10C37000D4C34DAD268CD3EB6A3A467178AF5E6E6E
+:10C38000C5B8BBEE1522C5FFC335C74CB87EBD2767
+:10C390007504F9766FCDA3B45C537926F313B6D741
+:10C3A0005E8AE91E81ED63653E84498CDEA3745D7F
+:10C3B000CCF505CD65B9282F06795C90BA7FBF2AE8
+:10C3C00065FC7DBB45912B192444833D2302DAE7AC
+:10C3D0005F2F1212F0926D4AEB7201EDE0F2DB4B2F
+:10C3E0004E803CB3A5C5ED03D06F771245BE111941
+:10C3F0004571D7E6342EE797EC9E0774BF9D977F73
+:10C40000BDA87637FA7BE3F391DFA9F31DF778C96E
+:10C4100006D0EF1C5A222FCA443FFFCC355A94A1B4
+:10C4200081AC189DE4C7EA0180DF1D817AC3E70C67
+:10C43000C397E03CD6B338D5DE338D73D1EFD2F756
+:10C440000B938C768B3EBB4CED22ED2F4528DDE91E
+:10C4500016B2F6740054914E1DFE2D236867CE0966
+:10C460006425D0E9F0B935765CBFCE334F517F5BA0
+:10C4700030EB4837CAEB9C263D898FEFCD6962F5DA
+:10C48000CF974E14FA4899CFD78768897D711C7E63
+:10C49000D9C8ED1C39246E3EC6F19F7E51CFF3ED15
+:10C4A000AFFABDD25F253E3A2832F9AFE43B4A19D4
+:10C4B000CEB9BE94D15D0FF244E4478BD3A87D433F
+:10C4C000890357CABB399D4B65ACDDC2A5DFB18E70
+:10C4D000172FA0E0A6683A8A977E93FF3DD49F1756
+:10C4E000DBAA31AE5AC14B3D8FCF77215ECA00FA2D
+:10C4F000D367C6E21EDF2FBCCF2703BDEE015A1C57
+:10C50000A1EBE2A5F8FAD8B2EBEAB1BF5D77EA6930
+:10C51000BC76D624B99BEA7FBF35D0B8D6EDF3E51B
+:10C52000056B704C35E412E4BBDB9BF2A9FED6151B
+:10C5300011691CA35C27D2F8D82936D3681BC8AD73
+:10C540009EC831D322E4A3C55A456F36A29F1FD59A
+:10C5500029F6247AB1866E371DA6FBEF84EF233EC1
+:10C560006E00ACE1A24F2FCABD2EFFA3A6AB91FE79
+:10C570009B32A979C826101FCE7F38728AF6B7A7DA
+:10C58000B958C4F2FD77AE36A17EBD8DDB7B3B236F
+:10C59000C9ED8B9717EB68BE6778158DABEF2464F8
+:10C5A0003ECEE36E1D934F93DB9DD53289956FACE4
+:10C5B000E4FEBCE6187F4071D51B50E466C9F5283F
+:10C5C00037B73729E9A197514E02FF13D0AF94B77F
+:10C5D000414C8A738C1506E6FF4D118FF1368FB3EF
+:10C5E000AFD224F71FE7BA12F5A5BEE798BC738255
+:10C5F000FE8DC629C03D02FA7D60D202E8BF766991
+:10C600003D37A0FEB15D365379F4613E998BF1FD63
+:10C61000BDAEC2800CF91F9EF9C1B6024CFFCB25FE
+:10C6200044C3E4F37003DA73BCC600CA5FBB910C69
+:10C63000A3DD35D76FA6E525EF28413D1EE4F72899
+:10C64000C6C9E706F7B4E8E3F4F11C95FE0D788956
+:10C65000E2056915D94BF53F6F9C9EC2F4F15C571A
+:10C66000127D3C97DB41769BD8BE7B6654BCE626A8
+:10C67000EC675D4E06F633ACF553BAB1B4E7082D5E
+:10C6800050F6F76EB69F2C4B7F4AE75F0C9C95CF18
+:10C69000A21C9915B123EEBCD838D96A8EBB4CCFF9
+:10C6A000EEF2236E99C88ED2BB76BF1DE57B8F2E2E
+:10C6B00044CFFF3C8AE74980041FE3CF088FF7503F
+:10C6C000F28FF2F3264FA6C87F9AE73FC39FEAFC9A
+:10C6D0007F52EAA5A87F8CD73B9EA2FE4F79BD135F
+:10C6E00029F25FE0F92753B4FF4B5E6F2445FD53F9
+:10C6F000BCDE4B29EABFCCEBFDEB987CB6FEAFF27B
+:10C70000FCD3AAF65FE3E5CFF2F7CF4E75B278A27D
+:10C710008CC7EC37C37A6A513FC17DBBA72D13F993
+:10C720005D1C0E96912EE2E2F3292E8EC69B415A95
+:10C730006B4B48D3F8B8F229A17C340EFDE7FEF527
+:10C740000F3A317E4CE3AD471BF2FBC5C43B3FA122
+:10C75000BCD0E98D8B0FCB1B30ECC438ACB0D15BB7
+:10C7600085FE034C6FA6F168D26522D4170F7DF7C2
+:10C7700041E3E5C9CA27A62FFC7BAAFA5669527C79
+:10C780009C8FFA596526B219E4C6BF15B3FD57351B
+:10C7900034B210E379D4EDC0F454A1DC8AC5DBE9EE
+:10C7A00077A27DE0C333DFB0FADD31FE46CCD2B3F1
+:10C7B000B8BFB2AE9132301E41F94ED74689C64558
+:10C7C000D9F35D09F8B6CB9F39295E4FEE3C2E4672
+:10C7D00074D618BFAEF29348761C4E711C27B982EE
+:10C7E00015E31A9F129CD09FAE5B838DB81F0FD7A5
+:10C7F00026CA7389C725D879DC6E957FC48B786784
+:10C80000ECFC26E7CB3A37F71798250D1D8F06F479
+:10C8100093AAD87C558549445789CF915A6C371AC9
+:10C82000A728EB16E33908254EF1A3FDBA9DC81FD2
+:10C830005A66BF90E097EE5D2752FBF8E006585D20
+:10C8400068D7DA3EBEBDFB69CE1F7B71FFB853EFE0
+:10C85000BF9FF0751CAA60F81BF9D24D71F332CC62
+:10C86000E5E25015B75745F74DB1A8EC1B11CA3F8B
+:10C870005FCCDA7B762A6F2F23D6DECAB8F60EF3AA
+:10C88000F3044ABF52F1AD03C589FD4FC55F9EC297
+:10C890007271EDA5E223C3AA72A9F8E16155B954FA
+:10C8A0007CEF7155B954FC799F6A1C0FF37261FEDD
+:10C8B000EC2F66726922BEA4E66FBD9C2F457EB444
+:10C8C000EA4199F22DCF8B8BA8DECDEC5FE8EF3AF1
+:10C8D000A6C4BB70BF18EAD55484034FF85D09D3D2
+:10C8E000BFBA4776657C93A230425A73627EAE0728
+:10C8F0005C4E1E3713DE86FE31CB6DCCDFD5631F59
+:10C90000F5B9A95F6FA27885443F953A3F1AEFAE1B
+:10C91000F21FA9CB4DE46F7A98D37936F7DFA05F89
+:10C9200034314E8EF8304EEE22E2E31E2CF91BC459
+:10C93000C7FD98C7AD2AF141C3A7662F64FE2F69D2
+:10C9400000F7FF70BB280B14D7E60FA0FE37CCF919
+:10C95000D4118C37CE8AC5C58094A2F3D05FE3A0F2
+:10C96000FED4A83D6693E2D752F96325E91A37AEA3
+:10C97000EF95F9D5ECDC1A491A2F374592E70A9062
+:10C98000FFCB7C1BD3771A06685C5494EE3625D215
+:10C990005D7CFC1CD29D12773554C9E221A7FEFABA
+:10C9A0003D13862DC5FCB0C9E3E97EC3E3E87F9360
+:10C9B000CFE991FB63957830ACA7C5F1AE63F499EC
+:10C9C000F6918B782F8BC58FB6F07A69DA1041FD1E
+:10C9D00038EDA3429A5F59C0F69B1237A5C4458132
+:10C9E0000620D2381BFE5EE937CC831E9F47A27A11
+:10C9F000F99BD7A23C2DE57E80FC8237AF457B3882
+:10CA000062438CFBFB433E6BBF08F431F4E72A71B1
+:10CA10007B053CFF0CEF5701CF57E20227F24B3F5B
+:10CA2000C0FD7B8D3876687FB9D5FF16D2A7F7B1E8
+:10CA3000B3ADE837303A08D5BFB475BEC824E7C4F3
+:10CA40007E0BA8FF0EADDFF44E04E73F5A1F1DCA50
+:10CA50000513DB6F2FDADFE366FD56FC3D97A6F288
+:10CA6000779CA7BFE7B2F3F7F7FC97731C7FCF7FE4
+:10CA700039A3F39B5D8AF3134931BF2A7F0894A73A
+:10CA8000ED7A4F262FAFB40B9C2582FAB285DB31AD
+:10CA90008DE49CB710F988D71846BBA565E43D52D4
+:10CAA00081FDF61A47D15FEB7526DA29E1EF93BFD6
+:10CAB000CC64DB8B9E473ABD662EFA7BFB2E0102CF
+:10CAC0009E857EDD447BA44DEB1FA671C41EE2D97A
+:10CAD0005435D65EA92E2F2FFD3341FC666D9BBDCC
+:10CAE000468B7C710EB31B7D1DF623F2C5F3B5ABEF
+:10CAF0005CE8F3BCED46244CED46F8C47DB180DB28
+:10CB000057B6B7A5CD47BD1AEDD11817A9B4576AC6
+:10CB10006CA0E72ED01E89F6AEBE1A16D7D95F5785
+:10CB20003B2E5DE57C9441E438FBCA76BDBF1EB068
+:10CB300010393C346D699B31CE4E277FBB03ED74B9
+:10CB4000442BD1788E8E9B79BCADE4758D67BF89FF
+:10CB5000C6E3A11DFD02FC67B7967E39FEB3BED2C7
+:10CB60000BF39FED29FD6AFBCFFA4A13FD673D7178
+:10CB7000717668F7F8A2FD670A3D507B9C3B7EDE2C
+:10CB8000583F7B1B8BA9DDBF5B175C4EED126B73AF
+:10CB90005CAD71F3D67353B81EE7E5ECA63C815C3F
+:10CBA00041C8F74B999C51E8A9F7A6503D9BB7297E
+:10CBB000343F2787C4F45DE05F39B1F353B2CAFE56
+:10CBC000EDC5101C057712795AC73C66EFA4E9BC85
+:10CBD000FDD396CA49D2EAFD13F577E46BA85DBA96
+:10CBE00073735AD2F3FC17CB3FB2CA38EEAF693534
+:10CBF000A19DA7ABA63A0DF77BA9F13E13CAF74159
+:10CC00003FDBF7DBB99DE629D8CF32DDBFBECB3C99
+:10CC1000303FC17A3DBDAFA253D0503D66F8DC37FE
+:10CC2000E6237FEDBDDC39807650DFF38FBD82E7F0
+:10CC30004072DA8BA97D757A19A393416E87B7A2EA
+:10CC4000BDDD12E39BCABA2BE3CFBE42A4E357FA81
+:10CC5000DDB5911C784387FE15E38137A87F45A297
+:10CC6000699B7F94F913EF49B4DBDB893CAC17D0A7
+:10CC7000AE9F95E05F7AB4EEAC8CB8C1D1443C086D
+:10CC8000F6AD4D89F5FECFC977093D571318F5A2CA
+:10CC90005DCE0E2B99EE8CF58B964BA2FF77DFF4D1
+:10CCA000D3057ABA6F2D5E6CFFBD40F5F578E6A02E
+:10CCB0003B23588F78B58BFB8594F23FDC4886DAAE
+:10CCC000989F28B40AC6D1B5E2E361B42B76AE23AF
+:10CCD000D5689FEB4A3BDB82B8B6FB76528571F391
+:10CCE0009D3AD68E52BFB08CF13727B783ABDB5756
+:10CCF0003FBBD2E44602FCD67CE0CADD6827E917D8
+:10CD000014BAB6D07B0DD474D9D5F6AA1DB1A463DC
+:10CD100008CA578DCD7717B37D13144884D9EB8D8E
+:10CD20000C3F033F47B9F3F9F7CDAA8E7949FA339F
+:10CD3000B67F6949EDD422A7B367D71E15508EE59B
+:10CD4000F901AF42B98240C48E0748FBB81FCDC27B
+:10CD5000EFFFB0E213CA55F0F9549E4A3B6299C402
+:10CD600070B596B8705FF46EB451BAEBDAE8A4749B
+:10CD700098D734CAF51E461F3AE019D49F1408D339
+:10CD800038A3ED1B4B6939253E2BEF9E447A54D3D3
+:10CD9000E7F0B97F931167F6DE443C2887ACAB120D
+:10CDA000F37BCF3C3F1FED1E7DB34808E5579F3D09
+:10CDB00012B122DD5D0E7A9D30964E2D4D1F788783
+:10CDC0001067A11FAC06714C627B5F145FF9BC7CDD
+:10CDD0002865BE65C48E761C4A7FF6B1EBFF79E309
+:10CDE000EC7230CE0EFD35EBB6D038BBA3652CCE41
+:10CDF000AEEBE62D34CEAE740FF36FA8F1B5CDCF08
+:10CE0000D62FA74EA2F83CCF2F86109F47E38C6AFF
+:10CE1000C68F338AC6D33525C6D39D070E97CB92CE
+:10CE2000C41929F176D687BE4BE3EDD66B7C5E1A2A
+:10CE30003770957114E3A7B54E5FA49C8E9B507C10
+:10CE4000AC9E1F54841742790DE067C4D3BA2C4FAF
+:10CE500084C6BB1016E70D383D5886B8FEDB730953
+:10CE6000F2756316E074A8A5317B09CE432C7EEFE2
+:10CE70006E09F526257ECF7FE06E9F4CCF414B7F1C
+:10CE8000A6F7797CCBEC443F1EC603EAABE9F3B8C6
+:10CE9000019E6F611F109F09026FE7AE20E2431BE6
+:10CEA000099A30AE60BD46CEC4FE91350C6FA5D454
+:10CEB0009B96B3F894DEB55BCA70DD5CDAE05CCAC1
+:10CEC00087EF61FA5279790A7DA989ADDB44F33F96
+:10CED00095AF5F75EA78C8C7CAE2FD2F0E4607CA4C
+:10CEE000BD31AD07D6539CA27C17E6F5C7745E0F23
+:10CEF000B508FA447D52D6B992ADEB85E98F954FCE
+:10CF0000B2F3EB8EBA3E7A0FD1F467C24223CCCB98
+:10CF1000B754F39053270B6CBEFC54DE77D78DAF1C
+:10CF20003F2A74ACC40BDA9A12F5425218A4F65791
+:10CF30005B13A1F7388D43CFAF26A3E7981E7E2F52
+:10CF40008D0755F4F0F7FFF15E4A4F5F94DFE1BDC6
+:10CF5000B28F3BE2FD0E9F1ED8E443FEA2944F7BAE
+:10CF6000E8B30E1AB777B1F9DC4F90CA1EAED8BD40
+:10CF70003B787C96F2DEC0E3B1F43CAEAE2D236785
+:10CF800013F2ADECA3A213F765AAF551DFE7A33EB8
+:10CF9000BFAEE4ABEB7DCAF143AA73F1EA766271EE
+:10CFA0009CDFBDA8384EE2043E4AE965D701C49132
+:10CFB000D75FE43E55C773029D95967F6D9C78556B
+:10CFC0006E97F8C9817F50EC129558DE7B02F88786
+:10CFD000CACE833852BD9FB334FC5EB017D9BD6052
+:10CFE000A9FC3451FCC5FD3506D7F8FE9A3EEEAFDC
+:10CFF000E94BE1AF998CFE9AE9781EE829C1999E28
+:10D00000DA5F73358F7B52E809E84883F3963D93E6
+:10D010005C141DC13C5D5B7E5EF6B4E4FB18EADF88
+:10D02000589E3DB1BD485997BF36FE509EEA380F15
+:10D0300005473D61216A3D84F84BA81E42FC06C4A9
+:10D04000F1127D46F9990ACF399A12D36443727D61
+:10D0500087A63518FF32C271F7B95D789F861AF737
+:10D0600028387422FC3E3C87C79DCD6171678A5E7B
+:10D07000D7E767F16418EF950CAF28F1604A3AAA38
+:10D080008FCED324CC83121776B47CE132E3648C48
+:10D090000B934CC85F27CB8B96CD9F75FE715CCAF6
+:10D0A000FD17A9D6276697AA4EC3F10CD6B0F1F4A6
+:10D0B000D5C138DC685F0ADB51AFB9EFA125CBDA07
+:10D0C0006AA83F90CFCB3B4B22DCCE85742FB5A610
+:10D0D0003911F7B5AC3DFA0AB503FE5AE344BB4D2E
+:10D0E0004560F5DBA80C8CFD7EE2BD13EAA7C5C048
+:10D0F000FDB30075D08E36A13E857ABC9BF527FE28
+:10D100005C7F4F39D337BACB09B3435CA43DA3004E
+:10D110000DECE3D833D08D46CFDD173AE977A7720F
+:10D12000FBBA728E4A393763C9225A47353B7F832F
+:10D13000FCA9BE90C989EFF07A5916164F1C3DAF75
+:10D1400033279F42C229D83EB49357C8FA3105DB32
+:10D15000CF8C9DF39AC8EFE6F84587A9C28971592B
+:10D160007D19DF74C6C97D79DDB2481C7F53FC0090
+:10D170004A3ABD9044CFB1C7FBE9B2797F53FBE98E
+:10D18000D47EB8117A6E1BFAE7ECF1C4FC3B65BCA7
+:10D190001DA7EABC5D96C147EF3954EE0351D3C9D0
+:10D1A000C7D3181F56EEAB202424C4AFBF920FFC88
+:10D1B000760FA5D37642CF550BED64F82733E8F40C
+:10D1C000F8BE01FDF8F0B549D43FD76767F76B4A61
+:10D1D0007ED9275AA83C9E4BFD038B0CCC6F97DA67
+:10D1E0004F679C96FDF9FD74139D6B9C61607243C3
+:10D1F0007DAFC16FA731BAF9AD320F934026A1DCE4
+:10D20000BC4564E71FFF4AF758ACC47B1DE2FC55E0
+:10D21000BF9AC6EEC999E8FE8A54FEB61E2FA17ABF
+:10D22000505F73CE00C64BCD989678FE31E66F1BEB
+:10D23000A1FC2CD53D173F9FC6E4F1E7BDE7E267AF
+:10D24000BCFE57F59E8B08A7874894EEFF36F75C27
+:10D25000DC36CD15F5677E95EEB97886AFB7F2EC82
+:10D2600031B2EFE70498BD27C7C1C66D6FD63B0743
+:10D27000E8B8597C7E4F80EC91E3E62D7AEF05FF0C
+:10D280009EFABE8B82667EAF1EF972EFB938EFF35D
+:10D29000B31779CFC5439C0EBF5E2824DC73D189B8
+:10D2A000F144B8EF88BF1BC795EA9E8B4EBCE7627E
+:10D2B000C6D87B2EFAF19E0B0FBDE7C28B71A4D1AD
+:10D2C0007B2E9A3FA0E507957B2EDA93DF73B19012
+:10D2D000CBB1EF4F7346E5D9E7F3BFBFB60CE3A67A
+:10D2E00014FFFBC669AF2D43FCADF8DF6B79FBA9DA
+:10D2F000FCEFB379BEDAFF3E51FC82F317EF51F930
+:10D30000DDBFF8131A3713D3DB3F1B577EBBA79142
+:10D310000B8AEFC89DA6C477B0F2C43B6242BB73D0
+:10D320002EF6FB6BB17695388C175DECFD412DB375
+:10D33000971C2C347B5A705DB5A157AF80764D0F8A
+:10D34000317F462C5EF651D3F2387A79977F6F772A
+:10D350003AD3D78F4B1A33DEC7DADBC4700FC8E17C
+:10D360006BE8B9984622A149AB5F179A8BF7D7F6BD
+:10D370003F4024D483C5F6500BFA59FA1B47683C4A
+:10D380006D278F7B7EB6E0CFCBD0CEF371B9C4E5ED
+:10D390004988E20A05C728FC6E061F173186B6A128
+:10D3A0005CB2DC01FB11BF833846481D6718C51D00
+:10D3B00051BFAB5354FCAE28772FE5F7E7287851DF
+:10D3C0008D5FD4F9A9FCAD0E1E3FFCB7F6B72E74E5
+:10D3D0005F98BF758B5B50E1ECAF96BF75A1D2FF34
+:10D3E000BF92BFF5D212B6EFD57ED7F7B27C3E37EB
+:10D3F0008DCB70EAF93D39E3D2C377BE607A782FDE
+:10D40000CBBFDC9D1DFBBE72FFF944FDB8CDFDC551
+:10D41000C6011C3C54DD8574E84ED74B68FF57FAB3
+:10D42000516660FBAEE340F308DA87728722D4FFCF
+:10D43000E0C54B3841EFCA6DF0DC80E9C9B285D058
+:10D440006760BF807A626E7BE75CB4C31ED85B7D89
+:10D4500003CA8FF7E4B27CD45306D3FDC21237DE81
+:10D46000ABC9F8CE20E73B5D1B9FEC6B03BDF8AA70
+:10D47000BA10F56FD9FCCC5E95D7E4BF0CF9500912
+:10D480008F9B52C69FDB1416D0EF75B17AE52CB78F
+:10D4900033E17E23B55EB9BE484AB8371FFE8EE73A
+:10D4A00066A11F8284E2D763B995DF1FB02A40FDD1
+:10D4B0000836BF8FFA5B7771B9D73B83E13ED9CB92
+:10D4C000FD899A3973B1BF86CBFCC59A38BBDA6E39
+:10D4D000A786969FE8F70526FA3D81897E47E011E9
+:10D4E000777AD69B9350EC120FDA67AE7EC4BD6B91
+:10D4F0003EF2A15F6BE8EF31ECD5794513A4379C80
+:10D50000163C186AA8DEEF76E3B5DD78AEA76D238A
+:10D510007C4787F3CDCF416D94681A36EE7C7ABE96
+:10D52000E386CC0C5C8F739C5E87EB5AE97DDE3D15
+:10D53000EDA244E9F0C44DDBF03CE67B592245F313
+:10D54000A53A3FCB6F123D32E6D7B5DE87F824F619
+:10D550003B172B697EB724D27EF534BC3E1FF34BBC
+:10D56000EF1425F42F0FF2DFB1E86FAE4E5B49EDFB
+:10D5700029A728CE55DE0FB6B3DFB7C0DFF1407A5A
+:10D5800053CE6F95B8FDAD62DC38D73B597F7BD168
+:10D590005E09F9BAEC97A85E316893045CAF69CF75
+:10D5A0009A28BDE565497B4C30BE102F6FD8A0F19D
+:10D5B00020BFD6B533BC96E70810DC37860D7AFA63
+:10D5C0007E9F93D19B8EC0BC25C4BF4AB1B406CB0D
+:10D5D00071BAE3F77D827CBE86D2CF2C22A11E19C0
+:10D5E0005EFAA617CFBD74AE23F45E7631A09C7BA5
+:10D5F000D1936F40FEF662F69D08B9CA5C45E579A5
+:10D600006635EE23E5DC8B93BC44ED6647F8BC1C25
+:10D61000399E49FD313BE6E456D1F33E59B280B81C
+:10D6200063158F538EDAC1CFAC9F2E523B780E3DDF
+:10D6300067153DFFDCB4E51D4D259EEB617E44A9D9
+:10D6400049A47E5CB59D5B995FB5BD5B39075DA75D
+:10D65000F8A3627E157D05E58FC9CF432BFEBA8600
+:10D66000E207A45637EE638607E49B610EAB6018B1
+:10D6700099DE461267DFF3F378F589F86B5EC5979C
+:10D6800023F717548817749FD9AD15C2573ACE6A3D
+:10D6900081D2FF2FF83EB3DEF4392F603371F2FEF2
+:10D6A00004924FCCEE76D775F1F7582BF4A3D0F354
+:10D6B0007A95DDC6A50D4CC77362830D7A11C7F14B
+:10D6C000E1990FBDF4771C04298076ABEEF61502C4
+:10D6D000C643BF0F0A15A19C6C5446DC2239B50124
+:10D6E000F443DB8DFE61E453B95EE328EAEDB94112
+:10D6F000A1A580AE0FA17EEDDC0622207EB7FBCD7A
+:10D70000D44FAD9C975BAAEC0733EB8F6D15D97B9B
+:10D710003FF30335E2BEB07A93DFCB123B6F585B29
+:10D7200085B69CB7DD6D2FEB3292EC978B949F35CD
+:10D7300015CE71E5E798F340C4B60CE7BD5C64FE16
+:10D740007183EB3F3BB81F34A93FF105BE0F2FF8A3
+:10D750007C4DCADF0D19BF1F5A8DF708AEDF250FAC
+:10D76000DF1ED4DAB1FEC843345DF942E7BC2B6258
+:10D77000F76DABFBF907E4EB71F844B96F5BB13BB4
+:10D78000EF5EB63F3F7EFFFCCC2926DCE7A4D653F4
+:10D790008EF0713F5221F0F3C0FF548FBFA3F1BE52
+:10D7A0006C71E2794DF5F79567EA73C1C9F953CF0A
+:10D7B0005AC69F0697113DFADF061F78391FF1CB35
+:10D7C00097F57B3AC01769F9DBD7EAA99DEAB0C0A3
+:10D7D0007E5F475E6CA4726250C7DADFDDA81F92DD
+:10D7E000E3F8A6FA777582876FA7F7604FA4276ED4
+:10D7F000AA489407EAF954E7A79217E7BE2479618B
+:10D80000ADBC303D7156E5575B4FB42AFDFF82F544
+:10D81000C44D9C8F29F202DA2377233ECF1329CE01
+:10D820002F180A533F82A2F714B48FD0742EEA3D0A
+:10D83000F86CE27A4F33E83D6ED47B4ED1FDA2E81E
+:10D840003DFDE91101AF5EE9E0F4D49FCE7067546D
+:10D85000EF0924D77B76573893EA3D9BF8FAA9E77E
+:10D86000F710C7A1CFEBBCE595A81F3A599CDF1F65
+:10D870000F3C41F9D666ADBC04E7B733A4A5BFDFC2
+:10D8800083766176AF883184FB6D5085C73BEB6A48
+:10D890008DC9F89D829FF74E4DEC9F82A32F56AE07
+:10D8A0007C36815C19D2C9B978AEEED89E2D761A35
+:10D8B000E7CB7F7720155F9CC9CFD9410B267EEF40
+:10D8C0008009EF1B50E43DDEFC4E71AB9FAD77B796
+:10D8D0005FA4F65F459E031E68C13459690EB0DF30
+:10D8E00093F353796FC5731C54BE07282ECE6DD6A3
+:10D8F0008B32C5076B04B48BF7CFB5B1F3F00DA332
+:10D90000142FD8791C5A6EF01D6A47453F14B6A7EC
+:10D91000C87B1F8FF320DC1E1E27EFD7E07AA6926C
+:10D92000F7CA7D03BEC3150FA2DD4D19974B4BF807
+:10D93000FA12EA4FEA6E17E938DE079C81B8208AAE
+:10D94000736E54CE89B178276B03F35B28712FFD7A
+:10D9500077B2B8979CC0BB54EF904442FD67A9CE04
+:10D96000F97F2B8AE347E938EDCE79F4DE0075FFC5
+:10D97000615C2D95D9717166461667D613A916514B
+:10D9800035DFAD1BA17AC3F9DEB77063F1D0CB32BE
+:10D990008D2F63EB43340C5FE17AE17A58795C6058
+:10D9A0002C5E8CAD9B0D701DF2E70FCF5C4AE9A099
+:10D9B000A73E93E92F75EFD275033AA0F33516D73A
+:10D9C00011FA7B4080EBE83D08EAF9803F8EEB16C8
+:10D9D000D1F1DBF87925657E92CCC760B2F988DD9C
+:10D9E0006FA127CAFD16F4BE8A081BF7B7F64FB918
+:10D9F00016D75D6D5F8D9E9F4B615FBDD87DFAC36D
+:10DA000002E7B87EF9E556767FE0987351AB585C33
+:10DA10008C727F2094B008D0EF26DE150319D64F04
+:10DA2000413C6DD3109CE7FFAD31533AB6EE15285B
+:10DA30009FBA453EAE2FC5FDE8377BA91F9784F5F9
+:10DA400068BF689CCBF0358665627D17AF7F4BD889
+:10DA50009030CFB73E6648889F729176AABF361243
+:10DA60007DEC3DE2FED36F9D46BF924BF59E68BEB6
+:10DA70006DC5F9C76B227053ABF9CD86D3A6E78E7F
+:10DA8000C7B57FA6323DEB4DF4057C9D7C9D9EE3A2
+:10DA9000E2F553F1AB0F371A9F3B0EFCF54F3AEF0F
+:10DAA000EF71DF133C24360BF4F3CBDF2CF5279119
+:10DAB000AB183E88F368F68E12933375BBD2E5DA65
+:10DAC000E7D1DDD2EE79D7C8FCE521CA17DB3DA44A
+:10DAD00006F15FBB87DD6F91312F42C6EB1F94BF0C
+:10DAE00002991F949792958B6B37A4A3ED6666B04D
+:10DAF000EFB17E6E059A1EA1B8CC3B6E7CA6C1C963
+:10DB0000EE8F51EAA52A176BCF43E36752F67BA34A
+:10DB100034BA4A771EED592EAC3DF5B8CD0E66FFEE
+:10DB200049F7407E1CDDA9EBBB3F693D360D96D61B
+:10DB300054CAEC8926C7FE08C62BDEF14B936CB4A1
+:10DB4000E1FBC4731C5BEF3D7B6239D0B989A44B08
+:10DB5000AD582F72F7BF629C7CDA1CBD1369B148C7
+:10DB6000DE2B233FDB564AC2B8CF76DCCBECABDBF7
+:10DB70000BF3E93C17B5771893C525F56CA49B2EDC
+:10DB80009A4E6B0845701FE736F90BC4B876F21051
+:10DB9000EFC7D1B5D26EAAF919D36E5348C676F342
+:10DBA0001A3CC5A233365F4ABEBA7D6B785D04D994
+:10DBB000FC1F274BAF629CC2594D3ABDCFA6F4194A
+:10DBC00091A64DB039511F0A0941F9BBC877169883
+:10DBD000E83DDB3B2607238390F6FFCA24237F74AE
+:10DBE0007FF2EEBFA3BFCD3024505C6B68D3BF8003
+:10DBF000F94BC4748980DEB7E37B81C820B4D37845
+:10DC0000B24C463FA7A13031BEEDE648BD88FCE5E9
+:10DC100066476608E779C7678C5FEED927ECC17B5A
+:10DC200015438E812D68177E77483882764AF2092F
+:10DC30008C67269447FE001BAE31527F8CF2A750B2
+:10DC400001ADBF87CFE7369C9F92D8F81B4B835717
+:10DC5000A39DA1716FD54C4D1CBD340EEDA4ED9B61
+:10DC60004AFD78E33DD9C1ED966918BF14471FA15D
+:10DC7000D09FE938A11F2EFC3DC59B23FF8FA66FC7
+:10DC8000DE9B914F79D5987E313B66E35E17B56395
+:10DC90002AFDD9736F684B2ECEE701E108EA1F1306
+:10DCA000F52BADD0C32E8650ADA7BA7F1BF8B99423
+:10DCB000CDF87BB36827C5DF9BBD8C1E77A07C7435
+:10DCC000738ADFD3DC399DE1FECD3CAE18C6A1C11D
+:10DCD00078171A331337AECD3CBD7BBA90D00FE521
+:10DCE000B9D9A4DC37C7D64F57EA4CD0E3764FE713
+:10DCF000F12FD0BE3727765F3CB6BF3107EDB6ECCB
+:10DD0000CF48825E19E6EF29B18D44A01D33E0298A
+:10DD100094EFA6D35B09E2FD36423C97805C321655
+:10DD20006A3F48F85D60CD497A5FFEFB1E76AF55CD
+:10DD30001A81FC52FE7D481B3D004C2D63EB996D12
+:10DD4000328DDF307B4940AEC27EA8EB05697C0492
+:10DD5000D05EE02A7B92EFF2F2286E51FEA8E5D366
+:10DD600091E9DC1FA0924F048D2CB352CB27858FF5
+:10DD7000A2A519F98A39209E437B8CB9E6BD8D286E
+:10DD800037CD644E4BFC7D6EB1738022BF2F42A90C
+:10DD90002FD3DFC93337333E689E734A409C05401A
+:10DDA000D383E73CCCF35E12B630DC4926E1EF3397
+:10DDB000D59C12F643BA6F2B71229E37D7BC24FC38
+:10DDC00014ED225719F9E168764E9AB218F4DFCFB4
+:10DDD00038357715B6779CE54F9E5743E33627CB0A
+:10DDE00089E79FCD5EF57D8E72829C2844F809FDFF
+:10DDF0000E7A6B6BE7417BFBBCC630E2FB1D735AAE
+:10DE00006BAF82EFEF850A1A4FECFB65FCFB0A7DD6
+:10DE100052A805F5A5B91DB568FFC33BA75879B64B
+:10DE20006F0A6B8EDD8D76A3423E7F63E421D23A8A
+:10DE3000ACC79FD2186E53F69392FFCE74660FF85C
+:10DE40000FBE5FAC1BD8FE7A1B64304BB37DF7FE70
+:10DE50007467C2FED871F9EA57906EB709666ACF47
+:10DE6000DCC0ED38A48ED96DB6F1FD6AE2FB55A990
+:10DE7000B78DEFA74E2131DEFF520FEBC7A51ED69F
+:10DE80008F5BF9BD6578EFE0EB58DEEEB7679A631C
+:10DE9000F9691B0ED0DF9BFE6FF1D576C0008000C4
+:10DEA000000000001F8B080000000000000BED7D4B
+:10DEB0007B7C54D5B5F03EF39EC94C721212924051
+:10DEC000126620C084063809939040C09310300A2F
+:10DED000DE3B2862783A11842841068B1A5A349323
+:10DEE000109EF2088A08147112C522ADDEE093225A
+:10DEF000DE3B04A568BD365A04B5A8812A2A524CD7
+:10DF0000B516FA7D58BFB5D63E2773CE9000DE7B9E
+:10DF1000FBFBDD3FBEF4670FEBEC7DF65E7BBDD710
+:10DF2000DAFB9CF9E107F8BB8631076372AB9331EA
+:10DF3000660B33BF0BAE62984D1E0A17C9CD580150
+:10DF4000633FA8FD2A9F622C97B12D6358C4E863F4
+:10DF50006CF30A166EF0006C160DB727C335D1208E
+:10DF60008524C63CFEC3EF0BF170DD97733BA3EB3A
+:10DF7000C8F926B8B2C6E4D0291BA3BF1FFA43FFD5
+:10DF800069138400CC9BEC657218C66519C9022B15
+:10DF90008ECE6795EC8CA54461C642041F3C698D0A
+:10DFA0001861BE8D30BF5580EB47D7A507E0F9CD8E
+:10DFB000E98174D189F885D3FC007BBC138E201EC7
+:10DFC000302E63E9085F1D5EEA3CEABCEBEA9A7218
+:10DFD0003E3333B6A16E2B5DB7D685E9BABD6E3739
+:10DFE0005D77D6B5E67C36508B271F4F48807B0384
+:10DFF000187349007B95F1E1BF84223D9C1ED0C37C
+:10E000007DABF570BF5A3DDC357E3F808DD1797791
+:10E01000D6ED53F08C103EDBEB8E10BCAEAE9DE027
+:10E02000AD75EF13ACF68F1D3716AF583C62D711A4
+:10E030008BB74AB778D6CE18E06502DE203FB77BB3
+:10E0400093046660EC0FC303932568175927634850
+:10E05000979C5347EE0711F33EB92C4A7FF82F7B6C
+:10E06000B31E76B265340FE10DF266BA3FFC461D71
+:10E07000B0D4E133B8D702CCC684E501208FCEB747
+:10E08000ECA1B5207F4E5FFE7CD3309093EA776D94
+:10E090001D200FEBAB5BEC3008F3DADEB7F941AED5
+:10E0A000B7FBCA12508E99C8E5C22125EBE6630C76
+:10E0B000F400FA392E24B3D088E8BA04A180D39DA5
+:10E0C00099D90F71D1F5CDB4CB77E2BA76D4B1D06E
+:10E0D00029A06F58B93E89D781487F7EDDA0DCDF5B
+:10E0E000AE5C5B94FB5B956BCE912909A87F3B15D9
+:10E0F000B849E9A7E2991934B08886DE9E90834535
+:10E1000034780F6C4AD2C12EA98FAE7F42517F5D09
+:10E110007BCE093E9F2A0FB1D7BED5FAF906ACD601
+:10E12000CF971ED0CF8774437BD1AF563F6FA2AC41
+:10E130009FB7A7F9368D611505A8D7C5605780B67A
+:10E14000F1252BDB85617805BD852BD3CA27E869CE
+:10E1500002D23F9DE8BF1DE9BF5EA5574932F18558
+:10E1600031C9AD5DDFFAF8F66AB40B4059C2939934
+:10E1700024F78D9759FF41A9A12104436DF019C8D7
+:10E18000CEAC934ED950CE9E2F3230A31BEF7339B5
+:10E190005A91FFA1DC01D7750F44188EEF8CBCC1DA
+:10E1A000DC30EE2FEA4072AC004B111600797AAAEF
+:10E1B000CE46B0CBD42AA0FD6235CCB30BF9648B2C
+:10E1C00008684F59106018D7E50C18A87DAB028B72
+:10E1D000410EEFE0FDB7D589348E2A7FE952935086
+:10E1E0000AF2DD974504502ED629D56EB5C1FD4102
+:10E1F0000C044603A7E3D2FBE0FFD56E8D009EA181
+:10E2000029E3DAADA8373E16463D7AFEE22F050631
+:10E21000F00699451AF2E07ED1BB215CEF4FDFB6E4
+:10E22000876C6951BA387D7ABD07FABF89F457E522
+:10E230005CEDF7BC64A8083B793F968C722036935E
+:10E24000BE2A704211874F4806E207D887F7701C34
+:10E2500006F603F9F6FC5BEF8AE81F7EAC7DE80466
+:10E260001B40FC6511D263679141467BE0644BA281
+:10E27000CF7908EF9338DF5E456E762BF8AB7AEBFB
+:10E2800062A2D101FD125907D9AB2F8605BE24FB2E
+:10E29000F5647B7B2EF025EF35D980F8FD61B87CE5
+:10E2A000462A403C67EAE892BD590F3BD94C9A5F39
+:10E2B000C553D5EB8C1A030B69D63378AB83853401
+:10E2C000CFF5999BA46BEFF2835E2E9FEB503E61DE
+:10E2D000BCB5DEB6D5FD017E02D86EA47E91EB06FC
+:10E2E000A09D6C37B2B52C2A2FB172FE0B94A7C13A
+:10E2F000F0DCC5DFDA517E1D414E2FC7A5F4B2E632
+:10E30000C1BC19E318F9DF9C9186700BAE23572628
+:10E310007EAE97FA87D70A28E79C9EEB91AF203F05
+:10E32000EB8B58D808F7AFB99840F295201948DE22
+:10E33000543AC373A9689F133783DF00BD6E55EE4F
+:10E34000FF6558202D0FF97811F02C44BFC1880FBC
+:10E350004FACE37201744F477CBC4F5A985B4777D0
+:10E360003DEC64006BE93E2642F2E50C723FD1C5FC
+:10E3700007D48C7CBACAD67C341FB1714198E40AA8
+:10E38000DA23D624B8A27FE885F65B7AFA5333DA2B
+:10E39000EB22BA3E5827D3352DD0C9024EFE1CCAF7
+:10E3A000A1DCB6ADD482FCC8609295460DCB480F77
+:10E3B000BB97897B803E0E2FD70B47096B89033CA7
+:10E3C000EDA650BD01ED4209D7FB746C07D89A2128
+:10E3D0003E61C0761B134CD8EE6712B68B4A7BB2F7
+:10E3E0005F69778AA526B41B45D00EF29AA88C1FC8
+:10E3F0005FA4B48BAD111ABF92B7C729CFF7AEE4B3
+:10E40000ED0925BCFFCE812C9C2BE0BC1022FA101C
+:10E410006E7F06E1643FCCA981E38B60CDC951B822
+:10E420007725636E4DFB639E63690D8CC6E3E3CE77
+:10E430008A8419CCB31C4901F4DF59C5E52574332E
+:10E440000BEF4259BD68E4FD6E9049AE9258BB9BFC
+:10E450000B7688F8B7F37B004621FC496544436797
+:10E4600047AD25648C477A0619C685AA9C7F3F4C28
+:10E47000BE15E56545D6876571308F03E83218D63D
+:10E48000ED3005BF403BC8B2991BE7B547BE6C886D
+:10E490008379ED452C0F2250E6B071BAB00C0BE138
+:10E4A00035FC4007AB7246C78DCFEE90659CDF14FC
+:10E4B0004CD3FA935502AB6C257FD3F1018EEFC894
+:10E4C00070F7C77558235F6E9B8F7CF40ECAB7C375
+:10E4D000FC0FE509A4CF2E030B60FF154BB7C8183E
+:10E4E000B7D84DC18302F26F26CB43FED86DFE83B1
+:10E4F00002E231056086FC9578FB240516DD1CAE32
+:10E50000E0FD6D1961793EC036392D681471DCD398
+:10E5100084873D83B9077B108FA7E539D06E0D380E
+:10E52000837689E815C1E7EFCA60ADE8DF40FEF801
+:10E5300078012E7F765B139F7F2EF74B7627E3EDD6
+:10E54000B2028B2287CB79FF53C3FD1B507FE3328E
+:10E550005A59696E943F19C3030FE1FD583EED34DB
+:10E560007750FCAEEACDCEFBC3E44F1D11456FB230
+:10E57000196604B08EA7486FACA037B88E58BDB1ED
+:10E58000A2DE245FAA37F66C2ED756D49BE49EF504
+:10E59000C68A7AE3EB596FACA837C957D69B553971
+:10E5A000A037A867D95C6F56E5801E78A27AA3C20F
+:10E5B000AADEA8B0AA372ADC254F39C134A746EE17
+:10E5C0005655192A296FBBF8D3B4294335F7334F71
+:10E5D000A723FD56A17E90BF7F666BC4D9739C9321
+:10E5E0001E00FBA5F5AF52E008F22751067BA6B549
+:10E5F000A3B9B20E063D24FFB33383DBF35519FDF7
+:10E6000013B4FA167B6D867888819F791CE220BC52
+:10E61000AE01BFC3AC3DF7772C0F07FD5CAFDF4702
+:10E62000B95D3F14F407E6898B2C3D680638AEC807
+:10E630009D8FF2700EF507F05D917398F4C66982B4
+:10E640007C16E3309BBFD4CCF948FAE1047D51EC51
+:10E6500021874577BD49D36E73C7E8752EE835CA63
+:10E66000ADA95DA7D7EB15BD762485037E4D7F153B
+:10E670008FB47C7E9D28F9CFA1BDD959DB6243BA06
+:10E680007866BADBCC30BF54C9DC06909B7E9358C9
+:10E690001BE2939CCB61BBBB89A11D017909C541DC
+:10E6A000EE086123F7AB8A1CA15CA01CAD8F9123FF
+:10E6B000158ECBE572A4C228776E4D7B17FE39ED1F
+:10E6C0003A395A51708CE8EBF4825D403F14799AE4
+:10E6D000E25787374C712BD07339F98908D727A7B0
+:10E6E0002D50AFC83FE9BDD32973D8AFB48BAD214E
+:10E6F000827379FBFAEF1F0EE1F3A181BC7D95B324
+:10E70000E33AD28FDA2421A4C1AB4FBE81ECE04EB4
+:10E71000D954D1DA8DBCBE99C7E3C47992DC2F1FDE
+:10E72000FA5D40FA1644E9EBA83584AC684F7C9654
+:10E730009368579AA5C0B7646796ACFC8B11E31930
+:10E740006F84ECCACA740BD1F5B137CC61B417969B
+:10E750003EAB65B4C72B05168C033BB8B2CF5A82CB
+:10E760002DFD4DC13810514BDF75BCBDCC46ED2B96
+:10E770005256F2F6394E82CDBD6D34DE8AA52C1C80
+:10E7800007F45BD1FBC3696877CD5916290ED66FA4
+:10E790004E3D41F08A2C1BC1ABEEBD37381FE8D08F
+:10E7A00098B892219DCC239904E9245B5DC77667D4
+:10E7B00043DC9065EA10D00E6685DA19D1DD0D7E56
+:10E7C00089F42D28239C952DBAD792BCB0DDB91AB7
+:10E7D000BDCD57E8674D76A7621CD5350E33913E07
+:10E7E00030673EF9D9C63A16CED6C4E925F9FD956B
+:10E7F000E7020CEDB759E4F208D7706E37F9FDC1A6
+:10E80000A253AB312F581734501CB3AE88FBED0D1B
+:10E810001146FEDC6BB31907635C0A0FAC05FA6D99
+:10E8200090F2DFF442FB5F771B24580B3BB84EE9B4
+:10E830000F7907C6AD7B769F3AE285FEAE621EB7C2
+:10E840006E90CA281E1C7E2191E22B5B4CDC9A053F
+:10E85000F7C3BDA2B074699C3A33BF209A8F372B9F
+:10E86000F1E4E30A0C71FC6DD89EDD28D6E36389E0
+:10E87000E54C40F99176F3B8B79BF1E65D6EBCBF0D
+:10E880000CF32F4079ECBF5A1494B8B406FB671D03
+:10E8900000FF360CAFAD32E6AFB1F90173F3B83318
+:10E8A000EBC06A3FD6A362F385AC034D321BD64D55
+:10E8B000DEA0C4A159073A647C2E0BE250A4C77BAA
+:10E8C00023785E6686DCED07ABAE3EF100E2A3E6A0
+:10E8D000C73DD9DBAEFC589CA2E4CFED15983F2490
+:10E8E0006624E7A3BCC5F667AC81F0D828C96BF3F2
+:10E8F000E91A588FD72657D1F503B0D9240A18A79B
+:10E900003509300EEA7FB181FCAD11E29CE7681E4B
+:10E910001FCD73CDC53A7132F45BEFBB5BBC2D5795
+:10E920003B7E3D8D7F6DBEBC05E9ABC6E9ACA483E3
+:10E93000E2BFF875F9BC7E17531788ADDFC55E9D41
+:10E940004B5A1D83A09745A91FA4551D7520FF7F15
+:10E95000961FD895AFADFBE59FE983FCBCE6E227A7
+:10E960005437B21618FC94CFA6F99464BAF5CD21A9
+:10E9700080927102A74FFAED4F52FED52467E7A3AC
+:10E980001C3B724C64173616B95B8C9EE87A20CF1C
+:10E990007D0EE7D970E2B88C7A6ACD3CAAE4B93F23
+:10E9A000327F848C285448F55BFA2BCD7C32B4003E
+:10E9B000ED3D180AAB44F5AE23A53C3FA4FC6FBD6A
+:10E9C000D412B91FF5F0D766370839B37EFFCB08EC
+:10E9D000E2BF43B6B5366072551296072563BE6C2A
+:10E9E00065A8B78E17DAD860E8FFF1EFED21F09156
+:10E9F000DCB9146BEA622639827EC33884D70F1CD7
+:10EA00004A3E75693D8DF343B435C9065EF7E07241
+:10EA1000A0D0DFB5A413C300763C9FDBF7AA84C067
+:10EA20007194237975733DC67D36C89790BE267064
+:10EA30003098FFC13F4C485731C0E7ED53CD4A51A4
+:10EA4000BE32655BA711D625CAEDF238CEA24E8C38
+:10EA50007B77E4073A90DEAE12C349F40F2E5F983D
+:10EA6000FC00CA21C54FCE290A3F61E8DE601F15B0
+:10EA70007ACACBF61EB4F8707E318FE617FDAC2A49
+:10EA8000372AF75509FE332497100053DDDC99DC53
+:10EA90006D7E1D95674E877839546A6251FD7CC240
+:10EAA00077DBF5E318E9CF77B8EE4416740CC0B8FD
+:10EAB000B0B891E4D268E0FAC39E3250BC292FABC3
+:10EAC00017B4781102009B92793DE57BC50F542560
+:10EAD000C8DFE378077D0D0D211FCA21AF13ACBF3E
+:10EAE000789EF47A4F898135B8F17E5902BB5C7CFF
+:10EAF000A8D8E12E18260C42FE9B0E7116E6C15BCB
+:10EB00006FDB9E7EB9B82FDDFBD08D68A740330E3A
+:10EB1000A2FC3940FEB04E9B1E6E09A1FCBD2D30FB
+:10EB200092AF6EEA0D29230A2EB5B740EA37BC40F2
+:10EB3000BB7E21B62907FA3E16AD17648E80756F2D
+:10EB4000DC71EAC8FD68D797B5FB87B8C91E678D29
+:10EB500048F9AFD76758895247DAADD40B2EA90BC5
+:10EB6000F07A62BA520F50E53AA1A495FC81536045
+:10EB70007E94B384928E10D64D1265310FF32B889C
+:10EB80002B4B292FF4011F011C3582F3EDEB7C7F09
+:10EB900001AE3B23C8E395AB952BC8334328F75808
+:10EBA000F243FAC6FB0C02C106D69990C6D85ADFCA
+:10EBB00093E20037E94319D223B3A6A91EED9428A6
+:10EBC0008784EEF42156FE49F3347216EB0740DEDB
+:10EBD0002622DE578B6FE278D326AC7B36A19E626D
+:10EBE000CDCED4B91AE14466E3F8B3CE7AB4D156A7
+:10EBF000454F76E6AC156420511F1B9777F88FF2CE
+:10EC0000F10D275227433AC1FA3979DCAFCE337B75
+:10EC1000048FC36F55E8CA9243E9C8C7FF182E2F67
+:10EC2000473C63EB95EBA46F6C5A395E171F56EAAD
+:10EC3000C5921BF7C35806F7570B461874FB62B111
+:10EC4000EB3A28BD6BC37AF07AB8627DD86B3B6231
+:10EC500043FBB05EBABC9E3950CF4644E1B54B2D64
+:10EC600095B82FB6B1A4C5A6CD4B1E50D633519240
+:10EC70009712BD95FD2DA3254CFB2EAA7D8EC56B4D
+:10EC8000A32954F122FA23898531EE769628FE33A2
+:10EC9000469E41EF02281F0E9B521FAAE679AEA5A1
+:10ECA0004BAE5923BA82BE6ED68C7E6DFD08D5DE82
+:10ECB00004D6E373D61AB0D386A85D8C37852316A5
+:10ECC0000F421D32DA1DB4D3E85FE28BB89D4E547B
+:10ECD000F8EF1F117804D7E392543BDDC1B8FD5320
+:10ECE000E432AD073B1DBA929D76F37AB0E2BFBA2B
+:10ECF000F02A0F33B4C3EABA329784EDA88F7D416E
+:10ED0000FED06FA4B1A344CFA622C326B4CF1976F8
+:10ED1000C6EB40C5207758170679ED0FCF9EFFE868
+:10ED2000731BEACF7627ABD0CADFB38AFCFD9B2AE0
+:10ED30007F22C89F8BE4EFF723BAA997AF03790925
+:10ED4000382F95BFD8F5C5DAFB57BAE82FBF82F444
+:10ED500053F72DD679957D0B5F9B0DE56E9D97EF53
+:10ED6000575CB5FC2D7490FCED607C5D0E07CF7791
+:10ED7000DF54E66B57D6D7AEE8C37A942F8C3F505A
+:10ED8000BE84E83E5C37F2D58A7842FEF62ED26128
+:10ED9000BD8FE76F2A7FAE64371C417610F393A8CE
+:10EDA0009D6D12B47AEB50ECAD6A5F5D25DCBE8AD6
+:10EDB0007213D5915CF780FD05F88C82B7E8150FCA
+:10EDC000A23D0E8F087C364213FFB97C111AF7C79B
+:10EDD000DADF34B4BF28DFBE86FAB2E4A8FD8D9531
+:10EDE00077885342182FF691B9BC81FC7F8774C98C
+:10EDF0000C84658BBB1BF957ED726853E98FB4CB5C
+:10EE0000FFC0755DED3AD4B8E4E5E17E8BAF80F4E8
+:10EE100096FC1FD6FF7D1AB955FD63EC38EB2C929A
+:10EE20009BD76D42DDC6E1F19011A0DD10E50EA289
+:10EE3000475F851E2A3F8D3E7F0ACE135FC4E9AF30
+:10EE4000AEBF1B3D60B266DD19BE2E3DC840BCE3BF
+:10EE50002546F580F81A875A0FF0D0FDB921AA0788
+:10EE6000C0F83FCABF3A8B9A0413CD1B34203D54DF
+:10EE70007CD57E465F60188EEFCC5B62C0753DA18D
+:10EE8000AC2B63877BFA530CD711A1FD43B69DC70A
+:10EE900071981F4DD6D4EDA6FA0C6A3EE5C371BA3F
+:10EEA000E2BEED6ADC7709DF75EB2FF1A9F1B35C07
+:10EEB00082F47BEAA295EC55B3C4F7539D8D90DFA5
+:10EEC000C677BB0F5686F3A9F1D536751F55912B22
+:10EED0005711A3FABBBB5A7CC7EB8EEE93411E3D84
+:10EEE00011E7C99EDBDE9403F7DD219E4743BC3565
+:10EEF000C97715F1966919DFE78B8DBB5C8D8ADDCB
+:10EF0000F0E9F3BA835BFB7F68055635973337DA50
+:10EF1000B5156B7AAFCD01FCE2B71A18D6F1132301
+:10EF20006BC8EE25361AC276DC876AEC4FFEB62730
+:10EF3000FE6E54EA915BB11E69453FD529537DB001
+:10EF400084D7CFE36D8CD781655E1F8C7786381CA4
+:10EF500050DAC5260ECFE5EDEB62EA99CEF276A245
+:10EF6000BF534E8A1821271721DE66DAF314EB0C03
+:10EF700027CD14178779FC18804C4EB77F9FA48348
+:10EF8000AD5EFF1137CC6B56E46EB573AE1BF3C7A5
+:10EF9000FF1816B81FF967CF6661ACCFDF15626145
+:10EFA000D4AF8519610C97D84633AF578E37962466
+:10EFB0009C223BCBFDA74BE063AFF7713B6E75B76F
+:10EFC000CB189F5A434C0AE37C1961CA5F17C233BE
+:10EFD000BDA0CB72A057B919E7F3AF41FEC6E576E5
+:10EFE0005890DFEAF8B1F47DC8A7C65D8ADF350521
+:10EFF000DCFEA13DEBD7C561FECDB80EC413EBB866
+:10F00000AB99DE9FAAD76CA974AB8FF677FD47AE9C
+:10F01000C1BADC50E646F95C71719C0DFDE54A977A
+:10F0200045D9177AAECFC1EC9EF55ABDAE81754D6C
+:10F03000E2E72DD82458DF0A675325E6C7FD0A58B2
+:10F04000A8BC04F000BF86F05EDFA6E9C9B08ED58B
+:10F05000C8933E8C0D7A71E3F610E0B902E1515C81
+:10F060001D915F6BECBC9D85364EBF9AE719E3F5A9
+:10F070008C2D96C08B649FB26DB42F125FD4694102
+:10F08000FB740EE9ABF4437BB166D099348C07FB7B
+:10F0900015E8E350D3F0C0AB3E8DBD8D2FE2FB2AC7
+:10F0A000CEBC27CB308E5BC512448CAF87D8F879A5
+:10F0B000AF214ABC3CC4C4616301DF87EA55C0E5A7
+:10F0C000E1131F871DDEF074AA3B82E5C6E7F798BF
+:10F0D000F9BE622847D93F9119C989AB466C469B56
+:10F0E000D8283E44797EDFF13CCF795FB14B626D29
+:10F0F00024847EFBEBFCC0BB5A3CFBD6F07C3C2A54
+:10F100000F4A7D2703EC37DAE9E1817E05E80FB28B
+:10F11000B91D57D7D597B53313D5B95B054F7234A1
+:10F12000FF073F4EE327FA583DCA7FDF1AEE47DE5E
+:10F13000455D4DC1FE9D95885F3F5C0FC6C366BEB1
+:10F14000DFA3AE27563E1E7F604F1F7C7E558C3C52
+:10F150007EABACEB6B45CE9DB97CFFDAB50CF01CF9
+:10F1600086FE3BF035F253F5E3B0A47AA4CF209F9E
+:10F17000FF2FC4672F3B6875235E228DB3CA14B47A
+:10F1800061BD169EFB1BE22F2E6B97D1DFC4E5728B
+:10F190003F05ED155237F9C3BB0A1ED992FC7F7D9E
+:10F1A0001487A8F92AAF833B253EFF205F40203A11
+:10F1B00016713BADD2799E24BF8BF8A8F4B994DFC9
+:10F1C0007CBF2C748FCA6FCE7F5790C751F6EC8EE0
+:10F1D0007AB4CB09459CDF09059C1E3F19E1E77C09
+:10F1E00028E7F8ABE31F57F8E39223A5B8BEF8DA97
+:10F1F0004ED9E08EB68B329F3F333A3FC97F62399A
+:10F20000AF1F6554F379E37299807A90A1E8C1DB6E
+:10F21000F9FA753476CDD34976D0911B217AAE3484
+:10F2200007D290CEAA9D98FBE2BF4CAF073B518618
+:10F230007206CF2FF0B6537F88FF48FFFA1530359E
+:10F24000BE53F5740897C7EEF534963FAA9EDAFBD5
+:10F25000B120CACF40D624E13A9A320A7BA1DD52CE
+:10F26000FB5D5760A179D6247654A21D5B5376F7D7
+:10F27000FB48D70DBB998741BF55F7B337AA606DDF
+:10F28000096CA8D8807A1CB1937F19522236A3BF8B
+:10F290001BB2BBC3960DFD871CE9C5703F2121B28F
+:10F2A000F4FD04EC5F34C86DA7FDF41FE81CC51025
+:10F2B000FC371070C3FD1CDF358A1F54F148F0760F
+:10F2C000129D134AA442A473A0C0AD8BE3127677BB
+:10F2D000861CC9B81F2B0D423AAD4964D721BF36F1
+:10F2E000D45BE416B8BF26CB6FC0B86463B181CEDF
+:10F2F000871E1AF3541FCC87F70CBC9886F9475326
+:10F30000D137B4DFF44D06AC8BF6A1FF4EEBB4EE73
+:10F3100016FB239E1BBFE7F664E3D3AC199F57F19E
+:10F32000B62A78ABF80E892C8DA0BF1B92E1DE8B3C
+:10F33000FBE81BEFE77E6888375C86F80FD9CDF1D4
+:10F3400057F11E92116E133478F7C37569ECA72339
+:10F35000DBA0F3B73DF99F7952697581C6AF5D298E
+:10F360006E9C533B8EFD09F2AA972C9D877E403BF5
+:10F37000B345A0FCF1E5CD7913508F6EFF02640315
+:10F380007ACF593AF1E14F7BC1909F72FD9AB32336
+:10F390005142FCEF6A0F4E407AB0209306827D4BBB
+:10F3A000357AF675C038A94FBC232D87253CD2C6C7
+:10F3B0006E4579396B0EE661481E9AE5CCA3F313CE
+:10F3C0004ED9ED04BA55212A6E7C2E7102EE87A625
+:10F3D000DE64911AA59EF1AE9AE92EC27A5D55EBD4
+:10F3E000D22A9A57849405E28D2A93B812619BDB46
+:10F3F0009D580F706143B019E1CE4496D49247FBFB
+:10F40000E3877F0EE3DF5E9D29523D47896BAA0E9D
+:10F41000BCF177DCC7B85DF65B90FF3FD96DD1D109
+:10F420007968AB1E1EBE4F0FE745F4F088237A18AB
+:10F43000D788F3D4B2E027F723BE6F19C94EBDF2C7
+:10F44000FDF316B4EF9D552C88F8BD34047255DADF
+:10F45000CF0D67D1F94F3FF01CDACFEC71B560FCEE
+:10F460007CAEAE7D6B39C4016D5F1818EED32ED81B
+:10F47000E36AC67AE94BFFF8D386D138CE337152AE
+:10F480000BD071DC825F3FBB14E0AF9E8E4BC4BAE1
+:10F49000F5996D2FEF443A9C7966301380EE5F1931
+:10F4A000021FBF8D7C30B8D82EA0C7C10FF79FDEDA
+:10F4B0000EF09DCFC6E561FFAF9E797910D627EE9D
+:10F4C000FCD5AB5968BFCEECF95521C17B9E1E8699
+:10F4D000D7334FFF7210DEFF0A8514E5658FB5192B
+:10F4E000F9B9E0D7F693BD86F5CCB7AB1D7781812E
+:10F4F000EB17C3713D38EEAAF65EC0EF05BB5D2188
+:10F50000BCAAE3DDB9FBC1BF68E1D8EB9DBB2F8F7F
+:10F51000CF9DBBF9B8A7CD610BAD43608B7741F2AE
+:10F52000BBE85CE5F589C3703EAB8E8F83B7EAF923
+:10F530009A13D6C3FB21ED781BC7D9DCDFB30BE4EC
+:10F54000EB1CEB3CBD01E164A1FFAE6EE4F91325B9
+:10F550008E59B44F3FCF7E53F77AFD9962A7BDCC49
+:10F56000128DD3717FC10A76BB1BBBFE95E2E7F615
+:10F57000ECE9EA6FFC811FBC636E88AF17287AF74D
+:10F580004AD73920B6A42FC8EA02D4CDFED1FB0B4E
+:10F5900098669D30DFB7B6F8163101EC9982CF79C5
+:10F5A00033D7EF3375F2C39F827C9EAE93E572CD65
+:10F5B0003EDEFC1D552BD3819F357B07E669ED5D53
+:10F5C000CDD34F1866C0FDB3101719803E67761F64
+:10F5D000DA82E7F4CFB49A19EE43D73C7DA8379E80
+:10F5E0003738DBFA7A3CF69BBFD543FEBB6BDCAD0C
+:10F5F000E3E5724DBEF263F5F6E5226EEF16B49ABE
+:10F60000C3B887BBA0F5BD097D51EEB60AD24098BC
+:10F61000A7D01430527EE993CD21DA07FC8FC37D49
+:10F62000A07DD1AB058598DFAE35F86FBA01F568DE
+:10F6300027D7E7178FDE6644B99D3F94198C204782
+:10F640006DDE872CA7D03F17723EAF9DEAACC6FD9A
+:10F65000B9F827ABC6917C437C30302FBA9E421359
+:10F660007BDF002915939B6647A0FD0B43BCB416B6
+:10F67000E6FFD2C5F521F48C91ECF2C88FFE6ABC8E
+:10F6800088FABFCB48E716E76FD5CB4FF50133C5F6
+:10F69000A52FFDE3DBA9A3D02E341B3D2D8CEA4B17
+:10F6A000166D1C5B6DC4B32040EF66D76A7C17E013
+:10F6B0004C4A384BCCC5E79EF898ECE6D356438BC2
+:10F6C000C6FF57EFFEEDDF719FF88EB07EBE58F992
+:10F6D00018AFAC17FEBC5A398BED8796CE54186D17
+:10F6E000AFA905FFA2A9EFD57CDA64C1FCF88E4969
+:10F6F00096CBCEF7ED899707B90D24AFB47F11DA19
+:10F700006BA4BAFB577F7EE929DACF33B152A52E1D
+:10F710002BD860BE33F8AF01E0B7D2FEB0B5BC174E
+:10F7200002AD83D09E7E6561656BF3783F0678DF1E
+:10F73000897A80F57C6384EC2B7BDEC830AFDECF2A
+:10F7400022F1745EA4D56820BBF7C5BABF609C7572
+:10F75000560C6F7816EE9F85C584C4E83AEA5B0FB5
+:10F76000C5637CB1A0B55799F132F66AFF33768351
+:10F7700001F870F68BA7E2BAABC3DFF9455299A541
+:10F780001BBBA4FAF193F84F90D38585727521FACB
+:10F79000FFC65E9487A7F60AE605BB194F7D2EC902
+:10F7A000F6F02F90EE554A5DED21F0D36EEEA7A551
+:10F7B0005D9E4B9F5B52C8EDCA8345FEFB701E9752
+:10F7C0002FE4C17820296093501EFF6494EE1581C8
+:10F7D000BEB7B380850E4C34A6101EF319F09336D5
+:10F7E000DEA509A857774E029D003D9933A589E211
+:10F7F00087CD8B99642C02D814263F3E07228A8736
+:10F8000045AC435899ACD1F3799B01D6AE7F87A61E
+:10F810001DECD69D4FEADB17B008CD5BF3EB1FACB8
+:10F82000DA71BACED933D98271F3770AFD1E2C92E0
+:10F830009B0AE1BE70A38DFCDB4F9F11685F32D93C
+:10F84000D24A7876029E2D80D774256EFACCE8A72E
+:10F85000F52E5A5A25CF05F8EBDA39F2DC5E8C4AE0
+:10F860003BA4E7AD3C9E5A50DE7A98EC0B139F9B6D
+:10F870009106F8D8FC3C6E7233F15A9877D4AF27D2
+:10F88000D3BA59351327F605B87A32D16954902284
+:10F890001C365DE1133BCAF9FA21D6C0500EB7F110
+:10F8A000F1E7B310D1FB0ED64EEB7DA63089F8748C
+:10F8B000E4203F4FF4EDBE44AAB7AB7CFC96490967
+:10F8C000A8EFA90E88EF92BA892363E85CBD23866E
+:10F8D000EE5A3AF747FAEAF974D70B40EF6EE4F4C0
+:10F8E00011C5AF7CCC645D7D523D7FF048BD40EDDD
+:10F8F0008FDC6CA192FB9669F39EC07AD146A00181
+:10F900003F2FC8F763D7629CC0EB1A111BCCE318DA
+:10F91000D105537B618302876E9F712103DF03E36F
+:10F92000EF5FA9F36D996C61111E6FD931DE6A2901
+:10F930000EBC83F23CC7E83F6C003ACD35C859266F
+:10F9400094DF5A4EEF47F38339C16EFCB2BAAE2D45
+:10F9500042BB8CF960E87E81FC41DC81BD11E4F79B
+:10F96000C20AB04E6037526E59574AE7CDF3DD06F2
+:10F97000ACB77DA9D8C904253EDE266C4AC7F66D12
+:10F98000E96E6139ACD5F78240EF9D6D4C6C9FD02C
+:10F9900017EE77BEC3C6A01D4F8D0B36A35D4BBDC2
+:10F9A000D59BBF1CE3C24237CF8B47341DC4E73B16
+:10F9B00017BB458C27D31A429EBB7371FC603DC9AF
+:10F9C000ED6446F7536E59568FFD1EECC392108FAF
+:10F9D00034562F60BF95299CEE2BAB58259E7F3166
+:10F9E00061E504FA65548A423DC867AA492639B2DE
+:10F9F00031712F60CA1E89E770E75296D802F8A6C7
+:10FA0000188CB74E46BEE5F3F5242D13E41652824A
+:10FA10004D845FAA95550849FC3EAE0B5826EFA5CC
+:10FA2000F630D121755C300FF1481DC0AF39B623D7
+:10FA30004E8C9F96082C887EF0AD64353E8E3891B2
+:10FA40005F5F9BE5D41168A7DE31935D4ECED2B7E0
+:10FA5000F7CFAE48C03AC35FA5715467DD67967FA4
+:10FA60004FF479C728B47463D7FA8CE4F5A445172A
+:10FA7000FAEACE6F2DAAFC1BE5058B2E64E9EE9FFA
+:10FA8000853C2FACC94B6BAADB2660BF85AC7D25BE
+:10FA9000CAD9C256230B6BF4619F1DE842EBE5798E
+:10FAA000C0A9B706EACE2DA9F2BFE88291F6B96ADD
+:10FAB00095F71EA3F35B74FB5F8B2EF4D29D7B88BE
+:10FAC000F6EBADBF7F41D0C3FBCE2BFD4C749F1531
+:10FAD00075C4A3FDFBD276682BE67777D87FB71580
+:10FAE000EDCC68A381F01DDD8FEFE775AE31366395
+:10FAF0003C30DA28A8700BC25F9A415E685DEE78F0
+:10FB00003C273509FC2ADAC15318C762DD411A10B7
+:10FB10003FC487F1307B0EE5E52CBE6704743BA53E
+:10FB2000E4AFCCE48EBF51537755EFF73176C4D3B1
+:10FB300079ED57B89F55DBCFB93BE293347A784ED5
+:10FB4000EC88477A9FAB54F53962427E6F970E9AE4
+:10FB5000DC00D7480727308D9C45F913A77B8FA57C
+:10FB6000F7F2F68801E43830F2DF7E919B03A2D0F1
+:10FB7000A6DA93BDBF904BA0DD68D0D9173CA3AFE8
+:10FB8000D655D1CC3D6250CF333FF78BF20C2DCC04
+:10FB9000FB479F7F7E06D65D7DB9FCF93B47BEF0F3
+:10FBA000C70693C61F993AB3E8BC8E0ADB6260278A
+:10FBB000C04335B018D39E1CD39E160367F0FEB326
+:10FBC000133A0A300FBE67E4BE1926D0EFD97D3B49
+:10FBD000EE11005EB77CFF8CF262F4EBD204B467E6
+:10FBE0008BF609224F1B38FDEE92988C71AC53EACC
+:10FBF000B0CCC9453A4887311EAA817E829BD70383
+:10FC0000D1EE2D6A85E7DC9AE75A057AAEA6F5248F
+:10FC10003DD7E3F85E03D987B5DE53D46F61ED9F1E
+:10FC20002D1887ADAE69F0A37F53F7CB4D2C28F785
+:10FC300005B9B86BDF64AADFFD71E881F7F0B84B56
+:10FC4000DC92BFD4631DEDA3859F17E0737FC4A131
+:10FC50008BD13E8773F0F999D5B7E5E0FDA4DCF6CA
+:10FC6000F7A642BF8FCD1D8F61FDFBD997DF9A614B
+:10FC700002BBF6B1AB235300FFDEFAF2710EA7749C
+:10FC80003C8674C9D9F73E87333B32315F79F1E561
+:10FC9000E49948B78F07763C86F0B997CFF3F6A181
+:10FCA0001D99B85F3A2274614639C0BB446E0F7724
+:10FCB0001A5835DAD53FC6F8BD2715BBF3C4F5F29F
+:10FCC000E323316EABE1FE66F6F6F669A82FB30DBD
+:10FCD0004C0C815CEE3AFBA767305FDF551BC75ABF
+:10FCE000B858F9317E4EE5220C7EA289EC7AA7073E
+:10FCF000EC3CF477813DA4FC659889EA5C2A7DD5CB
+:10FD00007963FDC8BC427948514AF43A723CBF0E4F
+:10FD100029722BF545880B61BC99339D12D6059944
+:10FD2000A9A300E56AA39DAF0FF481F8E644FE01A4
+:10FD30003F5E19C9FDDB2B23799EB8A1703C8DF77E
+:10FD4000D38FAEDD66E3F9258F5F169A297ED93C05
+:10FD5000594EC77AC7E6C9BD0DB83FFFD23FF8FB81
+:10FD6000359D9BECF41ED774B42BBDD02EC8E9F49E
+:10FD70003EE24D169D5DD87CC7B874B46BB54C4E51
+:10FD8000A773217EDE7E45BBB6D0ACB76B0BCD3101
+:10FD900076AD3565B2E67CFD0C33DFBF9FD16C08D4
+:10FDA0000D1CAEB98FFBFA647F5A53B4F6EC4AF7D8
+:10FDB0001FC997D305F2CF16CAB75297B7121EA91B
+:10FDC0008F7A92902F780804E3EB2D9B06B720DD05
+:10FDD0005B8A6F1C525480747ACA7E5B6E54BE8FED
+:10FDE0005F2F7F8EF233DDC8EB01AA1CE11FEE1FEF
+:10FDF000CC793895F6618714F1F81DE29B611827DC
+:10FE00003E50ACF299119F861489D43EDB1A31A37F
+:10FE1000BEFC7F7EFDD3F89559F4DFE0D7C2DACF80
+:10FE2000AFCA2EAA7ABA45889853917FAFF2F814D8
+:10FE3000EFE37B23C70A035291C62ECCFEF9423A68
+:10FE40002FA9E21377DFCB15B700F8F1F433BB9E8F
+:10FE500082E73FFE999DF2F5D8F8372EB7E399F582
+:10FE6000980732978879F8C7968EA112C6F986C08E
+:10FE7000132FE3BC7D8C22D84288FB99B2DFDA4194
+:10FE8000EBFCA438D01BE3A05545461A07E42D5DD2
+:10FE9000A93F85F07D92D064CBE5E5ED556318F977
+:10FEA0006057E46D735E78DB3CEC7773AE1472A33D
+:10FEB000FC81DC601C3183BF1FB779A02144F9E6C7
+:10FEC000344718F72D367BB85C6F9EE6A57367B58F
+:10FED000881FE561069AB71B79E4F30E34D0BC5D48
+:10FEE00072F92AC4471E8D5CBE0AF191472B979D7B
+:10FEF000F1DAF3145F2B75BEAFC32097099AFB8C20
+:10FF0000C74D1007C46BDFEBB9D2FDDECB412E7DB0
+:10FF100051B954E5F0D387408E682F5D1E847AB1C5
+:10FF2000A488DB63D55E3F501C588CF2148DC7F952
+:10FF30007AE66C1C4ACFAD7271FBBE43886CC3FB82
+:10FF4000069B9884F575C893EF41B969888BB720F3
+:10FF50003D3E0739EE057E671E63F70A9ABC292EDF
+:10FF6000374079ECEC20E4F7E027E783FB1B8BEFCD
+:10FF7000AF86F4F9236396286CBC14C63A973E7F8B
+:10FF8000FF8755DF3FA4F829EEE7B60A8BB7215E5D
+:10FF90005BD39988F9D4ECDCCE4C94ABDB308F0684
+:10FFA000D4BE3DEB3008600F4E29FB6247DE1A419C
+:10FFB000FBFA6A5EFCB042A723070B13B07EA3DEF8
+:10FFC0005F64EBA0F502953A57C1FA16C5770C426B
+:10FFD000BD043BC6F723422E7A4F53AD1F9C5E6390
+:10FFE000A4BC9B21897D18770A742EBCC67691EF3C
+:10FFF0005754B1A015BF4331A87302DAC1ED652C87
+:020000024000BC
+:1000000088FE9E5E28C63A143EE9A17DBD1C6DFEA9
+:10001000BAC8D19145716F4A27D5AFCF55C1D458D1
+:10002000BF0E7D5FC7BAA933619D594BBF7328E2EC
+:10003000F93DDB5BD0CF4138EEA93491EA3420E7BB
+:10004000DC0E5F21FEEF8AE395F8FF54586F77AF1F
+:1000500022EE1F2452DC6FCFD7FA8BD8EB5D0CDF7A
+:100060000DA2EB6B46AC9BB28EC2EEBE177197E150
+:10007000D4A0BBBBC9DBBBDAB77EFE3DD2EBAE176B
+:1000800062EA1B31F2571385851F04E48BA6DD134A
+:1000900095BF454A5D88F2035C47390B0F1430DE8B
+:1000A000E5705C453B9D7F4969EB9880F45CF40505
+:1000B0003FD702BE301FEBCEA30E341FC2F839A9C2
+:1000C000BC3D13C5669152178D8DDF8A0F6C32F2DD
+:1000D000BCA6F527E88FCA2CCC8D7C2A4BE2EFE931
+:1000E000963A72723F836BDB294FAE19FAFD9F225D
+:1000F000133D3FC12A9F457DEF693FF882E26FCAF9
+:100100003EB607308E2B73D8C94E6F7C68708B95C6
+:10011000D6D94AF674EE164F12CAF185221EBFB622
+:1001200014FB2F1491FE4985E86F3E2FE2E706CAC3
+:100130002CEE6C94D3571C8F96A3DC78C00E18D28B
+:10014000905CA5D9C920DF65694CF96B6A0C42FB4C
+:100150006498603BD8896D65ED69189F6E2BB44833
+:10016000CB618A1B9994897A36510837A2DD36B162
+:100170001D4B70BC8A6C978478BC232466629D9367
+:10018000DD614E3C6DA3AD5876B9733538C2695503
+:100190001FA0F316477B1A8EB7C502A8611D58E24F
+:1001A000701BCCC5EBC21C9E64E370DBB40FD39014
+:1001B0000E6D407301E36D036FA75A7D3AF6BBAF36
+:1001C00019E17502138DE9D176210DDF35C2F626CE
+:1001D000B24F2C9189A8FF4C329FEDD0D431531DE2
+:1001E000ED6E6C37C07C587F592FB08840729E915D
+:1001F00078FA27D1F5C52975DB078BFCDE62A03FB5
+:100200006E53D9492F0263A993E924D99979F7311B
+:1002100011E5235A270CF3FA6C6E32AFCFC6D8D74C
+:1002200073580483A673CF09618C6BB0EEAFB7BF70
+:1002300011B2EB0B819F789E94ED8EB5E7ED34EF14
+:1002400022481CB68B68F7F4CF2FDAD77D3DF61520
+:10025000ACEBE547FD93C62F113EB757F7A1FDD094
+:100260000E0C42E8BC343F478AF5276EB7E4F4DB56
+:10027000918F77F4CFC773B571261E4FDDDE34B88A
+:10028000A55EF183E83F1F89E77E4D95D796E2B2E0
+:100290009B917E334795F98B314FC6E2C8D59CAB15
+:1002A00055FA61DDEA7275F6514AFDF6EE3F83DFDD
+:1002B000017FBF5F399756F1C6C054F43B770BEE10
+:1002C00054F42FB715AB7E6790EEFE696380EACCDD
+:1002D00051FE4538FF143EDC897CA07DEDC04AE22A
+:1002E0004B35E7774D39F7BF2CC8C489C59CCFDAA9
+:1002F000EF4F205FB530F2D1DD0D1FEF423E4A9C3B
+:100300008F6E3DDF488E1789305F1EE7ABAE7D33C1
+:10031000A74F15DA454D1D2AB1B1D948FBDC0A7D3E
+:1003200012F265CF0AF42B6F98691FFB336CA27829
+:10033000582EC4B8E9C1A2B2E9C81F07FA2778EE5F
+:1003400053C8A7512E3626B25B6F443F58C7647C12
+:100350003F15F85FD8DD7773D6EEB757A33C6D280D
+:1003600036E8CE8BC8C56682A95E8C71DD1A2BC5B6
+:100370007585FDD5BA9795E2B8B956E5BD8E07F9F2
+:10038000BEF45D539D011CEF9452CFDE5ECCEDE0D8
+:10039000F6620BF14F85D5F5C1F8249F8E11FCAAAA
+:1003A000CE1FEEEAC7EBA4CC14A0F740B698C3F674
+:1003B000DB3D183FF969DF4E959F2D16F7EF9FC57E
+:1003C000FCA221C18DE74955393A726400C52F73EB
+:1003D000157BF0EBE224C2E31BE6A6B805E489DA5C
+:1003E00055B82BCEFDC210EE3EEFBA9BEA949DFFAE
+:1003F0006994A8DE80352A58FFFE2FFAD0795B88F1
+:1004000007E83DEACEBDF6B0126FCA187FEE7F61F5
+:1004100030C537D138D815E67170601BEA6568EFD2
+:10042000409E7FB0F0D34F21FE07D225D4D3D3789E
+:10043000BEC14CFBDFDC86EE8BA3F8BBB6A3390E46
+:10044000DFC3FA5A60CFA19F54E9B65F897B4F336F
+:100450001EDF87BE30B4D0B91253F8273769F8BF12
+:100460001FE404FBED67917994BFB6DA7579681FD4
+:100470002BDC473A3C0FF73575E157CCFC7E68AF73
+:100480005DD0DE7FC912798AC6798EDF7F5D0CBCB4
+:100490005FAC91A79AF8C8A044E7D5D0F79B78A4A1
+:1004A00047A7C0DA713F09E92B103D3215FA821DCA
+:1004B000E3F248FA00F124ADF3F49786162BCF7FD0
+:1004C000B9BCFE4608F338AC73E552C46BE97071F1
+:1004D00017D9814E2FD20BF845DF216B38E3E0FCB2
+:1004E0007B4AA07874BFA9E9F063D85FB6499897B2
+:1004F000ED57F21062756F8AE3E94FA5F316339753
+:10050000FF10CC8FEB7EC922537D2AB4D6DA4B4B39
+:100510009F45ABAD272FB7CFB9E8CC6D93BA8B4FC2
+:10052000BBDAAB2FCEC6F338B1E722CE557F938529
+:10053000F13BEE3B318D9FBCE479DB590BBE4F683C
+:100540003BC83AAD683F923B7B5FEE3B628BBE5847
+:10055000BB18F18D9D8FF2A742F25FE46C17C59C2A
+:10056000BB605AD878299C314A50F617F5F7B3B0DA
+:10057000065C80F4D58FF7A9D93F01CF4974BE2816
+:1005800010BF4F9BC32396C2FDED058181A352147A
+:1005900066407BF5570E9ECF819C63FCCC9AF8FE9B
+:1005A000EAA7667936DA95C4F28845FB9EF2E851EF
+:1005B000DC9FCCB1F2F37DE02F2C5AFBA8B6179646
+:1005C000E9ED927A1D358ADB27573BF7C7F7B0274D
+:1005D0008CDA3C76D4286E4F478F72F3EFAB7DC137
+:1005E000EBC3FD96F9AD920FEBBD55B47FD76F19F4
+:1005F0003FAFF8A93940F9D3A78221F81CC655EBC3
+:10060000F8398C79BF1248EE5FDE5D6A7441FB9D5C
+:100610003B0409CFCD8D52E2E979E0FFB4F927AE72
+:1006200083E8817E0FC619D5EAD9D701F0A817044F
+:100630007A8FBFC6D46ED9067046C01934A621BDC4
+:100640000387B19E0089D5DDABD2A3F6788EB523A2
+:1006500044F5A95F09746E7E9E8935C683E9BC5353
+:100660000ED33E49ECF90AA63DFF80F2B85B2F8F0E
+:10067000E81FF5FBF3FFB0EAE5247455F180EAFFCB
+:100680006E1FC5EDB81A07C4C6059087CF1BC5F904
+:10069000C7EDC15E817FF72A363E53FCB0EACFE753
+:1006A0002BFEFCB491C713F3AC9BE8FAB3511EC206
+:1006B000EF4ED6A1ECD7775AD01FF5C4FF9F29F291
+:1006C000F373E47F4A94FF35CB222BE389DE81E785
+:1006D00069BF7B198BB886217D835588571F881782
+:1006E000908FA9E302844FEA4F214F073ECEC3BD4E
+:1006F000DCFC1F1FA7C4C625B1714897BC2AF214A1
+:100700009B4F8D5A16A678E4709DFB61FC3E56A85F
+:100710002CF8389E630C3598D872B83E1AF7C02F63
+:1007200051BE6A435611CF839EB76785D18EDD6770
+:1007300094B6BE03723B6115E3EFDF7DC2FDD6F2D6
+:10074000353CBF5A5ECFF9FA92620F1E53AE6F2B43
+:10075000746BC3F90642125BE7A579CB6C79211C57
+:100760006702F0A717E61B629E09ED1EFA148C6360
+:100770008D07ACBC9E00F6C90976FA5AC5344CE820
+:100780003B2682743CE4B2B8F9FBFC20E9BD691C4D
+:100790003CD1C2AE75CE6BC4F61B0D2C985804F13B
+:1007A0008B35B212EFFF2DFD9DD9C8F77B1D934D00
+:1007B000C8EF9562E03994A7329B6CC2FAE25B798C
+:1007C00023B3516F579BE4E7D10E3D6C925F184500
+:1007D000762D433C1D17956B751D104F13FEE3508E
+:1007E000BE92116F7723E6F3C634817F572C066FD4
+:1007F000A3B2AEE5AF5A699F42A5C384BEF7BF1648
+:10080000C0F55C6757CE6BEAD703715223CE73975E
+:1008100091CB718D2DF078A281F07F13F1FBB3396C
+:10082000F04BDC5832D8DC2605FFDF29F8BFD51D98
+:10083000FEF0F79AC7876509FE3E11BED1D5EEA33B
+:10084000576682A83F550981F7F0397C7F937F373F
+:100850004D79AF5ED1E747E3E2BD586FAB650E0956
+:10086000F9932D3EF038CACBEB2113C3FDEBFB1CF3
+:10087000F12D2C212A371706AAFBD501DAAF3E9CB1
+:10088000CCEB99874FB8E83B25F885DB1278EE7CF6
+:100890006F2BBD3FF27A69F7F9FA578A7D7EFDA08A
+:1008A0007A8E2FB08EF2D63E0304EDF9ED0BAABC82
+:1008B00019FC1BF33C3DFBC347EBC07268F6B54720
+:1008C000DF6A09D277254CC10F305E693B974B79BF
+:1008D000554FCF8F9EB9DAEF89C77978DC953DE522
+:1008E000AE13F1B0AEEF42FDFBAFD5C46FD6D11C55
+:1008F000EFD146CF128CE7AFBD6064113051DEB34B
+:10090000ED62223C7FADC8DFFF28EBA8CAC8827920
+:100910000FD953F3517E0E9DF46408306E5BFA607C
+:10092000BA76CD6B4B9D83DFCFCD3E72C309B43B0E
+:10093000DF85806E283FE626FAAE1F70A9BDD76816
+:10094000621BD51D88C560B258A31809629C7677D2
+:100950003CE54FBF55D68F67FE911FDFCDE4F2F027
+:100960005B81C3A12AFE7EADD46623F8B5856E3ABD
+:1009700087C7F681D9D7C8752D0B9A16E3B8185FCB
+:10098000A1FC6658A3DF1DA5BC4A3E81CF6700A32A
+:10099000513EDA94F8B04C890F59513BE1BD7C09C6
+:1009A0007F7FA8CDC5F99FBDBAC68975F0434CDCE1
+:1009B0008BEB3BEFBA2941003A158DE67EF870CCFF
+:1009C000B970753DAF94B96BFC9AFBC346733B3469
+:1009D00062B472AE34632F9D77C473C771E9381E59
+:1009E000B7E7DE8C83F41D176FC63B32D2F7B759D9
+:1009F0000B4C0ED4EF90DD8D7E7382D3D3882F8F76
+:100A00009499DCE5E84FB11F9E9F8DCAB7DB8975CD
+:100A1000AA6C71AC13FD489B730EC9BB7068448609
+:100A200036DE38D4837C5FABE079E80AF23D455D81
+:100A30007FDA4D09816EC651AF6D0A3D80F9B988E4
+:100A4000CFE838AB22DFEE1DC1AB916FDB9A18F90E
+:100A50001EDBAD7CCF51F0BEB27CE7917CB7A573B5
+:100A6000F96E3B5945727DD8355F2FDF6920DF4035
+:100A7000D7D75C0137DAD3B674ABDCC28578C762EE
+:100A800078FE35C1C5707EC87F33B4FEF935FBE012
+:100A900099788ED68BE779A07D9CE4CEC7BA802169
+:100AA0002E97F4E450FDE0FE9827AC57F08DD51F4B
+:100AB000751CE6D4D7A7D4FBAF233DADA82F7E3A53
+:100AC0006FF3BA920F4B6DDE0C8C4359D3A332EA0D
+:100AD000C57845DFC6DBAC27E97BB9C9D6E87777AF
+:100AE000FBE3BCB312BA7BFFEECAF354F079B682D3
+:100AF000FE156AE611BB9F27B67E565814D8343AC5
+:100B000005CF31073FC1EF7F744EB651FC9D54D1E4
+:100B100049EF217D2270B9F432B9E104D2EF682F98
+:100B2000DA9733C44D52E897EA41FABD305AFFBE16
+:100B30005B4F743BF467D61FF71D7A5E4F51C66D4D
+:100B4000CE6EE8E684F5C4FFEFA1DBC004FF4B489E
+:100B5000B79342A78BBEEBA09E4F448B07E3DDA665
+:100B60008CB7D6DCC4F07D84D0ABFC5CEED7D5DF8F
+:100B7000C4E3B91CC7391EF74A6DBBDDDAEF47DCA9
+:100B8000E6B5D13A1DE7861CC673B71D46D669C0C7
+:100B90009C69F578B943870FB7B7EA3C5DF36FED11
+:100BA0008CC775AE35776EC0FD4A9857C47AC37648
+:100BB000C606AC433CBC368AF363E7BBED803182AA
+:100BC000EF63C7CE7354D18BB6697FA373BCDB0FC1
+:100BD0003C41E705B74C06FB4676438A47FBB6D750
+:100BE000E6FF661CD0E34FD5068A03FF54ED203F95
+:100BF000DE533CF916C639037B8E2B21EC18C9CF86
+:100C0000ED0487E375C2BF56FD3599E2A09B6E7D6A
+:100C10000BE2E909D7562D4178D3D801B73AC15E26
+:100C20004F1827D079A373AFCC0FE37B9B136EA92A
+:100C30005A9202EDE5D7B000BED7396186A09C4735
+:100C40009A12407B30E15681CE1FE544A07F2ED61C
+:100C50005B0366E4CB54F5FB84CAF9B3AEF861B428
+:100C600091E87041B1B37F47FF50A0A43AE8372A1A
+:100C7000F939548867CC9497B28019F13E3E06A2A8
+:100C8000C8041C3790D9A4F13FC7665967C9DC9ED8
+:100C90009BB5FB46CE121E17A8F5DF58798E2BE1C7
+:100CA0007AA69E33C1E76F1EAA6DE7FB1CCE12EE3B
+:100CB000BF9C6E9E8F205EF81D4ABC6AEB01C7A7E1
+:100CC0004D36E331B8329BB4E31D37CA7520A90411
+:100CD0009EFB8489B3311EBEC15765467FF2895998
+:100CE000A2EF3A853C2CF822E429E545FE462C5536
+:100CF0007D72FF7DB3C8AEC6C7C91877CB0A7E9B8D
+:100D0000E29E9D897499C60C12F215FFD6A9F101D5
+:100D1000C8D59B398FBE8ECFFDF60EABDBC8F7076B
+:100D2000595A6134BE3DF40E048E40F2EB58AB8943
+:100D3000E761C1C67BA1FFA40ABB88F1E80DAC83C3
+:100D4000DAFF953133B64F666E3AAF7113EBCC32A2
+:100D5000E1F97623C4F71E8AEF3FC6FD58888B87DA
+:100D60009614609CDF4CE335C4DD5542DFFF61AD76
+:100D70003379BC6EA0F70D62E3A371B61D1487C072
+:100D80005F7B6AFAA5F68CD0ED1D3D8784F1D4DD3A
+:100D9000D85F89A71E3605C6E0BC69AC5540FC3259
+:100DA000B14F327E2F9EBFF7CF8A241B9773BD7D34
+:100DB0007945901B3E417D798FBFF700F135C9D948
+:100DC000070BF979EC4D71F1E4CF26D6082DCAFE58
+:100DD000AAB1B150A12F0C7244F1F3139DC1D77A7F
+:100DE000C373474B6D0CBF2376EDDC55C4AF3C831A
+:100DF00041C2E0AB02E2B47B105FA0EB2EF1523EA9
+:100E000000DD4DF7621EE63629F5753EDE0D2F58E2
+:100E1000E83B64FFC23A899E7E26121F6697F0FC6B
+:100E200039A572AF90E4263ABB305E3A6CD4D72F26
+:100E30008F2975B56B6D1027E662BD51796F79B258
+:100E400040DF539022E238FC34C0F5B989F4DE4B20
+:100E5000FE11E910C2937C1CCE6D6D2FC3EF00FF15
+:100E60004B098787EDEB6C43D85FCEE1E1072206A3
+:100E700084277A3DF908F765FC7D151013FE7D0780
+:100E800026115ED709E273E8E7DFAFAB207BF4877A
+:100E900049374D1C0AF0759E01F47E5FE24C13D772
+:100EA000EF6CCE879BA76C32E2FA6FFC94D1B9BD90
+:100EB0009429402B806FF20B4FA11CFFBC84D7BF3D
+:100EC00047857E43FA9F58C3CFFD8D0A5D67BE09F3
+:100ED000E0AF4B3BEE55F2CC3AD433356FBBD7C1C4
+:100EE000E5F425E5FDAFD074D59EF0FAEED46A5E48
+:100EF00057260BD69BF24B92CFE378582F392A27EF
+:100F0000EF7D2035A6A0DC38B87D6336A9FC1E68CD
+:100F1000FFF091FE8CF34F9A85EB49437947BDADC5
+:100F20005E25A424D3771C5B312F66CE18BFF7A9AA
+:100F300025266E0F1D5C82F58A603CAFAB304D3BC1
+:100F4000E09F6A8B0FC581FF4C0D5874BF338075CD
+:100F5000206D3FC8431FC3F59BFBD80C328CF7BBF9
+:100F60006613C9F5EFCC8111FE6EECDEE87088F8EF
+:100F70009502781A4A805F4A9C7FFEA3F966CC07E7
+:100F8000BE09E5F4C7785CEDDF5E22E8E291DEB5EC
+:100F9000AFEC30817F4CA9FDCD0E1318BCA962C007
+:100FA0002C103DE6CE3E01EB9EAABCF7FF5CC99C2F
+:100FB000D9E83FA6E2BE2CD0EF3725B7CF46FF30A9
+:100FC000D5C6FD42EF193599F335F8BD5D62D5CD33
+:100FD00033D5C4C779ADA46AA7320EF99194A9D5C7
+:100FE000997738B5CFE97F3F656A86FEFB58EAF509
+:100FF0003F9575FCAE84EF276F99363513EDD6DB40
+:101000000ADC7B7A35C15DEDD3A7EBE0476EE6FDE8
+:101010001F99CAEFB72BF7474F79792AFAFD945BEE
+:101020006AE8FEE84A0EF71447BD22F0F34AA11B16
+:101030000411F5E79A8BFF5AF619D07DDA5123AFE8
+:101040005B4EDADB80F5FB8941966FCBA3E31B7225
+:1010500022C07B7E9DC1EBB5692C84EDCFEC49A30A
+:10106000736113E7EE7D2D09F5B18849543651DEE1
+:1010700023A652EF00FA1E3DC9F5C4401EC9BD9A11
+:101080003FBC94DF553730631C02F935BD77F65D00
+:101090002E7F9FE677530C7C3FA4C24AE70EA6FA48
+:1010A00079DDFEE680D08CE7A68E0BFCBDB610D0B5
+:1010B0006017E0699822D079A8E915D666B4A3D75D
+:1010C0008AB219F5874DE1DFD52ABB10C72223303C
+:1010D0004F695ED11BFA1DFFA0B784DF05387EB2D1
+:1010E000F4238C7FDFAC072B87F6F5E45ED2AB37B9
+:1010F00085FE12D55399603269FCC29B938F0B38E1
+:10110000CF9BF56298E561BE18FE88F74B60BB92F5
+:101110002FF53B98C8B042650B906040B3377D8F88
+:1011200087CEC3140616D7A31E3E936711F17CF534
+:10113000682F1F3F0FE863C087026204FD659AA213
+:10114000A7197E6908EE9F5AD8D9E5D8CFE2338433
+:10115000F15C41FA98FE4A9D9ED7ABFB4DE3DF6DF3
+:10116000648D015A1F6B3078B479D03121300B99DE
+:101170003BE8D575B3F1FCEF317B60169AA0B16303
+:10118000B671383DF011C20FC6ED9A5D518CFA79F7
+:10119000DFAD4897CA4A81EA72E7132533D2714618
+:1011A00028813568C62DADDC64C6F872DAA452E237
+:1011B000EB941A0F5DCB2B1667E2FDC01837E1796F
+:1011C0003C3DF811E27F2CC78AB108CBF65A238642
+:1011D0006197CE535A9967463B3D0DE6C1F863DAF5
+:1011E000A4C5FD707F6E4A8DE04622F7387E6630DA
+:1011F00053F8678EEF09CEC27EFFB4F17382248765
+:101200003D8E3F49197FD2261A7F0A8E8FD7B9307B
+:101210003EF2A5828F3FA302E2241CDF5B9589F595
+:101220007675FC63F66026D6DDB367FECF8C7B6CEB
+:10123000208C87D73CB90DE3906302F3E3FB83D99D
+:1012400095ABDA0D58CF12B3A80E78DCCFEB809AAD
+:10125000BAA10B83F4A3A581FF2C407D9EC6DF4F6E
+:101260008CB55B8BC670FB79345A3F594FE756A655
+:101270000F10B4DFE35A3686C7F5581F2C107AB624
+:10128000836A5CD5E59706A8F5935006C67D57ACF2
+:101290009FB863EB27FFFE5177F59307C7A8F513B7
+:1012A000E19ECBD74FF66662FDE4F875A9F9DC2E16
+:1012B0007932B11EF6EEC2C199BAFA4905AF9F9CC8
+:1012C00037BB0D18677DE03752FCF9817F39C5B710
+:1012D000DF4100C7F27AC6BB2D66DD654A7E349ACF
+:1012E000854AE97BAFB5EEA410FFEE6E3DF27BC3FD
+:1012F000DDEE7CDC97DAA3ACE3432148E7F34379E6
+:101300004C44BB9B9ADC4EF62A096282E5B80F6218
+:101310006AA2F7C3D244FC121FFEEE4E90BE5BEEF3
+:1013200072B37C3CBF08D104BDC765B3F17D934C5B
+:10133000D64430E437D4FF1994CF141CA79DFC4643
+:101340007AAE5B56F011310E4B33B58EC3F1B364F8
+:10135000C668FFCCD4E1C5FB57AA1FC4AEBB4DE89D
+:10136000BE4E37662CCFDBA438760FD6F554BD9829
+:1013700036C9D31FE3C2D249CDE3D1EE4D090D37B3
+:10138000A05EBCA1D0654A35D78F4A45AFEB3F5A26
+:10139000F53AEACF1FAE13E8BBBBE515CD19A8DFC0
+:1013A0006D37FC3203FDC57BB3AC0CE3A4F7ECC195
+:1013B0008F1290CED3AD6EF46B63C6F2F567578291
+:1013C0005EC647F547EAC566F949CE662768F73D28
+:1013D000557CBBF87941203FD7EA60BFC2F741DEB8
+:1013E0007BF5AFB3D3804EAD7DD85768CFDD638D2D
+:1013F000B7E2FB1DADBD795CF4D5AB598F635CD40E
+:10140000AAC831C661559AF8A553591FBE86CEBFEA
+:10141000B794F57824574B17C1CDE9523A1ED73B04
+:101420005DB173D3FD7A7A54D6549951CFCB2B3D0D
+:10143000642FF08AEDEFE5703A948CE576E9BDCC47
+:10144000F009A407E4D5440FD53E0D1CCBCFF32300
+:101450007E18E79499789D0BF2F56EBF27F47F15FF
+:101460003B30D5145A817131DA5FFC9E4BE9DC2A9E
+:1014700033DADF195EC18DF3CE0870FB7BA37731C1
+:10148000B7C333B93D53F139E6F2939D3C962E979D
+:1014900061FCADDAB5F3E670238E7BA3E2FF4A2B45
+:1014A000605CB8DE02761FE38F5BBC9369BD378357
+:1014B000FDA7754F6A26FBAE8EFB614E98DBF7C920
+:1014C0008A7DF7F375C6AEEBBC5926FC6F09F513A0
+:1014D000689E997C9E9BAB133DF43EEF589EA7DF20
+:1014E000ECCF23FC6FAADEC4E79B5B4FEB783FB1E8
+:1014F00095ECB23AEF1FBF0F64A21D52E5EBBC5949
+:101500005A8171D2CD2A7DA670FA4C0FF0754C9F8E
+:10151000C4C79B16A8E2F4A9DCABF06FEF63E4BF8D
+:10152000AFE3FC9394F1DFFD7B3883C6F776BF9E73
+:10153000583EE58F55F9D444784C57F1A8E67854D5
+:101540002AF4AC9CBB97F09851B998AF6FA687E886
+:1015500009D759488FA32847D0EFA8476EB85BE357
+:101560007F4AC6F238F918AE1BE5DBDC4AF4AC540E
+:10157000F916E0727AE34C2E0F37D670BF76FD4C29
+:101580001EBF94FBF368BD7FC89366A11D3B76B375
+:1015900095915C4ED1EB675B9DCCFE84E7B68A22C9
+:1015A00094672E77F2730065E552237E0761149DE0
+:1015B0005C63DDD41DF4F582D4B3A1151827665FF2
+:1015C00070F17D9B4A41D9C76386D5BDA37501568D
+:1015D000BE89D76B947AC7A342C449EF91BACC4471
+:1015E000E747E72450FC7C741AAF2BA8FE6ED39C0F
+:1015F0003ACA2B6F926DCC0AF8DCE4E475830F5F76
+:10160000B7B10689EA08549FE9A98E60B005CBB14D
+:10161000BDCC6D92F87E6690F4A05CA9238C67ED3A
+:10162000544788AD27548FF5101F26B1562109C69F
+:10163000797F4E9D0BF3BDD87AC271251F8CD613CE
+:1016400094EF5378CCFFAC7A02D50998DBA8D41379
+:10165000DC84D71B9042225DDFADE0FB99D7DDE053
+:10166000A1FD31C8FB0B91FE9A7DDAD058DCA7CDE5
+:10167000E4FBB4F487F2946DA67C09F2E3FAB15866
+:10168000BF63E1995A7EFDE8FA54A318BA1BF154DE
+:10169000EA51A9288546E5F7E8B0AE16B3CF162B78
+:1016A00057220BCCFA6FCDCFF879AABE4CFD13446C
+:1016B000DCC7CE509E172AE7533EB26334138D78B1
+:1016C0003E636590F07AD81478722C25833C4E489E
+:1016D00043FC40149EE89DB7DA68BC14CFE345F2A2
+:1016E0002F919EE38D4E2902F87C73D448FBED9335
+:1016F000E4A7C7A31DBB8135ADD0BE3F30782BE03A
+:10170000A5A94FE4846DCCA439B7F293DDA20E1ED7
+:10171000DA9AA6EB3F7C9F5BD79E17F1EADA471C6B
+:10172000917470417B91AEFFC8F7651D5CDC51A1DF
+:10173000EB3FFA0BBF0E1EC4C2F4031C633A2B75B9
+:10174000CF7DC3026D788E6D48B155C4DF776521BA
+:10175000F95D2FE8DD5085DAD75C08C48C73C28050
+:10176000F1625A5F23B342DE58CAEED08DC75E30B5
+:101770009D42FE05E17FC8BF210C60CD39FF69D5D0
+:10178000E6531DBAF1F4EDB527ECAFBFA669FFE350
+:101790005857329D33F0311FD67D2EE10F3393DD44
+:1017A0009BB19B85C31E5C0FE3DF4DDBC6BF831D72
+:1017B000BB9EF375B6D75F33233F41A5515F609C55
+:1017C00008C891354DCF4FBB5BCFCF38AF9E9F2E12
+:1017D00049CFCF84223D3F13653D3F7B55E8F999C2
+:1017E000E2D7F333B552CFCFF4809E9F7DABF5FCAB
+:1017F000CC0CEAF9D8AF56CF274FA85AD73E607520
+:1018000050070F3AF181210BD6FF76BA910945F8BE
+:10181000FBA2B5BAE7553E86E07FDDF1F1C69A58E6
+:101820003EF2EFB85C899F29D7E8F9C98C332FBB0A
+:10183000DFACF20BEC59DF6B789D6196AEDECEF437
+:10184000FB029BE266CF42BF72538695EA2C87D299
+:101850006F30F572F37E5A7F72832F8FF60FC65763
+:101860005BF9791FA57E84C7C0F8B970EE8F2A7026
+:10187000BF40C27D8430ED174CEC61DF20D63EAB1B
+:101880007619ECB4EF9A1494D3C0810E01F717DAED
+:10189000E979276BD2AF03EC229E97BC6ABB38492B
+:1018A00094EFFD3176D99D19B5777DA379F1D129D2
+:1018B00056B28BD1BC58A2BCF8BD52C985BFD7DA8D
+:1018C000535E7CE3353C3E7FEFA0FAFDD2EEF3E2BF
+:1018D0005BAFB9BABCF87FFEDCCCB3DD9E2BB8EBB6
+:1018E0009AABCD8B9BE95CC1D1593C2F3E7A7231CA
+:1018F000E5C5C773EED3E7C533795E5CFFD1B50D9F
+:1019000027A07FD951FEBEDA38DB628A3FCBDE32B8
+:10191000F37ADF9A701C7F9FA49AF83E5EE1FB2168
+:10192000657F795CED383FEEBF8E3FF128F92BD112
+:10193000C0F97E5DB210B00109CBC791CE30FF1C5B
+:10194000C6CF8BB39023D147DFB37F0EF97F5EF90B
+:101950009E4D67223FBF386E69298DD7F5DEF16253
+:10196000FE7B0A65CEC599F8BDA67133AD82CDC3A5
+:101970002EF1C7C79BC510E61BC7170F93308E7D8E
+:10198000E91F7F207C3AEF616E9CB7CD75CB474154
+:10199000E83A4EF94EC5F13CFEDDA8E3AEFE646FB9
+:1019A000DBB0CE9B4CEFE8D0BEF171D7F3F43B0334
+:1019B000C71FE1E74A8F431F8CAF8F6F1AAC7F5F61
+:1019C000749DEBF2EF8B2AEF453313FF5DB7FDCB30
+:1019D000443AF73EBA5FD34C8C4F3AA759E8DC0142
+:1019E0003335CD7D08DB2B87F076E3A625EF62FB50
+:1019F0001D0E6AFFD2DC54F31CD263B2573D471F61
+:101A00003759710EDA7D38F53B72EAB96E95DFFB16
+:101A1000BBDE230DC769F3E12BDD3F9E18CCD47EDE
+:101A200077E3F8AC6B330314E7AF6A47BB593EC5A5
+:101A30004ADF1B2D17EB4D97B3872DC5817F477B61
+:101A4000B2D9F374DEDD305D8567979D9FA78BD992
+:101A500087BCC42EFEFB09CC4F2AD12E323C1FB8C6
+:101A6000FE75EC7F6861F7FBA7EAF945DCAFC3FDC3
+:101A7000BBF1CABE69056BA2F8FA7A16213BF65F84
+:101A8000D8473D86F8DFEBD84BCFA9FBA860DF8FA6
+:101A9000A37D1F7D56A6BC00E27CFA5DCBA3892105
+:101AA00092DF729740BF3B006E9BF29A73023F57E2
+:101AB000186B17DBECE7B370BC2BD1938D0C7C7EDD
+:101AC0008DA67E519114B68B54DFD3C7853DF1E1CD
+:101AD0007FFBF5FF01CB627F220080000000000049
+:101AE0001F8B080000000000000BDDBD0B7854D5F3
+:101AF000B937BEF69E3DB76492EC84900B04B213E6
+:101B00006E0183EE048C80A893AB51020C880A5EB0
+:101B100070128206484284D6C616CB84C410103494
+:101B2000D48840512751F052B5034645C57640440C
+:101B3000CEE7A5B1B6FDACB59E44BC211747506AAF
+:101B40003FEDF1BF7EEFDA3B991982D8EFF23CE727
+:101B5000F9E71CBB597BADBD2EEF7AEFEFBBD66C1E
+:101B60008A7DF04696CCD80C26EB76FEC4DF861430
+:101B7000C62EC73FB219FBEBE2E70FA0FEB51BED87
+:101B80009A254BD4A7153056867F488C1539F49288
+:101B9000A1BC5D09F3286C145E361CF8E964C6CA62
+:101BA000CB9DEA7A9DB12B985F6116C62A580FD556
+:101BB000CF62217A7A986AC5732ED3E9F945616FAD
+:101BC00001DAD53ABC0F25CA8CB5AADE14F7858C8C
+:101BD0001D1FE17D54E5EF0FC6FE4EC17CEE55DCC6
+:101BE000A9EEA18CB998E746C6C729E6F35ECF9F58
+:101BF000CCCD4627A7D09418D3F87BC77609F5FC3F
+:101C0000AF27359DFFAFCB7AAC3747CCFFFB6CF1EC
+:101C10009478FB5466FCB5A86ECC9BAD88D731EFA9
+:101C2000341690301FFEB984F567FC8469EBD1F956
+:101C300014DDE19988F719899F9CC7A8C9F79771A6
+:101C400078585C0CE3BDA34A7E3BC1C93D2BBD0067
+:101C5000EB17F379A7AD5D19C9FB2949B7301FEF21
+:101C60009F8DB67ED8EB604CE7FF87F914314F4269
+:101C7000907F375317EF699EFCBFA2F7C7D33ADFB7
+:101C800092645D9A0E382B1FF6AF230BDF8975A681
+:101C900059C43A8BA2EAA3E1D2F8BEF3D5033903C3
+:101CA000FDF375FB7E923CB0EE54E6A3750F6741E1
+:101CB00089F6734A0FF5DF6CACBFDC1D97FC492C2D
+:101CC000F535EE7B5EBF7FF51E76780C2F5B6E4898
+:101CD000F0BA303E7307F8F37BFC5D36F0FCC76A60
+:101CE000C7AB07AC8C5DEFE69DF0FDFB0FABDB8374
+:101CF000FDFD5C62F3D15E65BA32378E3139767A9A
+:101D000046956BA05D743FD1FBC8F16101F0217A6B
+:101D10003FF858377A783FAF0EBDB67A135FDFB819
+:101D20008726E4A3EED594EB7FF236CA0F8ECDB7AB
+:101D300070785419E3EC1CB664F7ADBC5C224B8B95
+:101D4000F1DD01A7AFE85EDEAEE7595B76970A7C6E
+:101D5000A8E9980338E766E737A39D8D51BB1917AB
+:101D6000D44DAACA1D98DF0AF4C7D735C3C21AB02A
+:101D7000AEE18A80DFC81C55F2F1FD19C19862C935
+:101D8000E7CF34BFA29ECF984D614A4C127FA6B5D3
+:101D9000BBD478DE6F8CE8B7243B98B1928FEF7993
+:101DA000CE95DFC5C73B20ED929FC17C0A1D2B302D
+:101DB0001F73BC92A4C09A24DEBF4766F9BBF9FE2C
+:101DC0009514054763DE9E276CF95D0CEB09C8EF9F
+:101DD000607FE7C6ACD8C1BFBBECBB2F98C2CBD7E6
+:101DE000CFDF94BE9EF7FB7C6DA1753C87FB06B7E9
+:101DF00083E0708D4772FBF9F869BEDE962158EFDB
+:101E0000FCC2C958AF39DE5D6E2BB59B3745B49B1C
+:101E1000E7A9B45687ADFF1A7788315EBE667E9F0C
+:101E2000027CD814BB90F8CB3CF097C903FC650E3C
+:101E3000FEC1E9FCCF575FFE2AE0F37625E72FD2FB
+:101E4000007FF1E01F59C45F0E0C9507F804C7141A
+:101E5000EB6DBCBF6B0CFE722D6BA7F7D7B1003DCD
+:101E60006F603D829FF4F5F393CCE4EC013EC2F940
+:101E70004A27F0EE6AE6A676F3197BB9370BFC44E5
+:101E8000573C71E01B2E9F257E503CDB39189E6D20
+:101E90008ABD94D677DD59F8E76B332F6AC1FCAF62
+:101EA00073055D9378FDEB71567D0D1B8C8FBA1514
+:101EB000C003FC73056F578AF5F1FD2A67EDC42F47
+:101EC000AF3C2BFF0C8D54F864EA2DC156C0EB7467
+:101ED000FADB1F48BC7C5B4C9E9589F5FE1EEBAD82
+:101EE00060DEBDBD04DF8002FEC5D713147CB48163
+:101EF000E61FCE4795827F838F56A8C170BE19CD4D
+:101F00003F4670FE097C66DA8801B80DA7CF0F64E2
+:101F1000F1EF148DF989AF32B7AF8797ED1C0058F8
+:101F2000776582F72F989FA27A18F00813C3FE30C6
+:101F3000E623FCBB94339AF0E7DD05EE85A5FC199A
+:101F40003B99B9FDB978865A37F2FEACEC7C59E280
+:101F5000EB7BC0C9DA9C9CEE6E2E28DC5CC6DB2DC8
+:101F600057389FE2EDD6946944AFB13DCCDDC9C787
+:101F7000B12ABE4AACD7EA50139B12192B28EA09A2
+:101F8000CAFCFBD050A6820EE37A44FF0FC4311F77
+:101F9000FA5B5326E87D4D994A4FFE7D13E069CDEB
+:101FA000E1DFE7F17DBD5EC885D3EBEC7E3BD6A9D2
+:101FB000783313797DCADFEC0CEB3EBCDE5E033A6E
+:101FC000AAB2312FF845B2C137F8CED1BABE716787
+:101FD00051BF3E5694CE9910DF98F569F4646BE8D2
+:101FE0007D5522BBC9C3E7733A515B88714FAF4B34
+:101FF00095F80EB02AABBB6C2A1FF7F0A644698D8A
+:1020000036D03EE416EBADCA727FD9C8EB43735CA1
+:102010007A176D87376F0EC70BBB65F42C8705F2F7
+:102020006C55600FAFAF1BE152EDE07799EF6F9EFB
+:10203000C2CB47BAADD823B664C75509417CA6B810
+:10204000D3804FD17C7A893F528E2D7B2CB25C1786
+:10205000882C2F8F925BD1722AB590CB9DF30827E5
+:1020600075C89D8F2077382B32E54E3513FBC99804
+:10207000DF3627EE4CB9F31FD6A291857CDD4B8D60
+:102080007DB7DB1B3EEBE4F0B2DF353EBF89E013EA
+:10209000DA07FA4DB9372B1F7CF15D838F1F737BF5
+:1020A000C616F27DB0674E3F9FE45B6605E1C7E967
+:1020B000AD4E0D72FEB45312FBFBB2E4F7F172C7E2
+:1020C000C8EF5AB7F27E3AA6D9554927BC9D75216B
+:1020D000E70735063D25DBDC4BD0FE933931EA1AA4
+:1020E000C1EF1C32ED2767C0FC59DDDED47A3BAF6F
+:1020F000CFE402DDC251AA96F5C48368EA0AC5BEE0
+:10210000314BC5F826DEFFF2AB62889696B5F86DC6
+:1021100000A3F22FC503BC5C8BAEA672D6EA70ABEF
+:1021200085BC5DDD9EC43CB42B2A94099FDAA6AF22
+:10213000F1E0C3CA04D19FBD7B8E6F38FFE765FF16
+:102140002A615EFEFD2D8D17DFFBD124CC3334A434
+:1021500010F8B1CE42787FCBED53E9BD34B7BCE780
+:1021600032CC7F5DAC067C7E65AB9DD6FF095F3FC0
+:10217000CA9F3C20E0714B86CBEF90CE5C7F8B14E6
+:10218000B4093EDE130FBCF9F4819FC503AE9F7204
+:102190005647FBA736C4139D6B0DF173C3F0EAC31A
+:1021A000ED9672D0C9A7DB47DD3D05F09D7BE58547
+:1021B00090DF97258E8ED75C03F54C6134BE923448
+:1021C0006527E8EBB27F59883E0EAC3F2FBE97D70C
+:1021D0002B32F3EEE24FADAD7809E865A927265121
+:1021E00093685DB4AF1FAE73D2BA96B7AD6DDDC262
+:1021F000EBDFE2FA9A3485BF9F3B4CA6FA2725A66F
+:1022000042AFB27C5780797FA8E6C4333C99523EF6
+:1022100098DE23175A08EE07E6C6E841DEDF913F55
+:102220005974D04F61E6AAD03EF4B7C142F4546667
+:10223000C99DE500BDADE365F0055FCF66ACF33049
+:10224000A7371FC87EEE96B269BCFC61A12364D794
+:10225000FF7DFA3AB4E1542BE8FDF014BB6A57CF86
+:10226000A437FC0539DFAF32F6299AFEAA368CB2C4
+:1022700041AEB33641876D8512FB5EFEDFA2C37BA4
+:10228000404F261DB28CB984AF663B93EEFAF53D04
+:1022900083DFBB7264D2371C3A73EFE0CF543B73D9
+:1022A0004B9CFF76172A54DF5D68A3EF947FAE78CE
+:1022B000EC4D3EFFA985DE07314E2673E701DFB204
+:1022C000BE62720283BCE38204F26AB4CDBF83AF04
+:1022D0007BB3956B4EC047C5FBCC9BE0FB6D4B269B
+:1022E00081FE7719FD1D737B1F453FD5ABBC5FEEAB
+:1022F00063C0BB69C407AABF99276B7CFEAE0E46BC
+:10230000F372E99E2227F87EB26732F0D2E4E363EB
+:10231000F87C3B73CFC48B3F165AA9FF31C91EEA24
+:10232000E7A96295D6D1011D83F7B3AD31C60F7908
+:102330007ED97799B2CCE775372745C845C794B998
+:10234000B245E819A131BCBC22CDA27D34848F3FB7
+:102350002569FFF778EF4BF86A0CC941CFFEEFF91A
+:10236000772E5E968652BDF8CEEDA0EFC6E488F6D5
+:10237000EAFE84AF122E812AE6D05C1C5F36F07F25
+:10238000011FB23A44D9DCFF93ED12D1A7836976DD
+:10239000431FF86A479E90B7909B2BD26C340F7303
+:1023A0007D374C2B7C03FC96B9DDA3930B08EEF430
+:1023B000F7DCC51AAD93DB1DCC827E6416D8C6F15E
+:1023C0003936B7D70AFE63AE675A87BB1578180D42
+:1023D000B76A639E1B314F8E2AD3745ECE39739ECB
+:1023E0002BF8D21A397E040CBED9AF9F1BF3E4F24E
+:1023F000AEF7201FFF0196C0D6139FF6FAC157878C
+:102400002B710C70B638EEFD35F85DECE486877AFA
+:1024100009AE0A1BC3DB8F1856DED9CB9FFB9B3955
+:10242000DE65F0B2ECD5B05F4A32D7EF391E0FB798
+:10243000DCFA28DA0F6F4E559B613759F9F7FCE942
+:10244000E30A05F46F5F91BB13F53E9B436DE6E332
+:10245000DE1F1B4FFCAAF1FD38E29FFF903DA42434
+:10246000398BB269DEE9AC81F4A8A1CB0E4A127FA8
+:10247000A58F12F2FE0CBBA848D8311FAD6EFFF538
+:1024800047D681F7EB12BDB313793FD57CBA97726B
+:10249000782C6EDFF4EB8FC2E0A5178BFED64A3A9C
+:1024A000AD8313BFDC44EB984BF31A6ED14EDE9B29
+:1024B00088F988FE4128FD7C83CFF301CE9E9C499C
+:1024C000678E1BFD5C6C8C93D321F9C7C40FBC4F86
+:1024D00034FA7D22D19D54C49FA3D54BE707F9B8A8
+:1024E0002B25AE4FF2F9341AFC9CB5D9FD3B24C024
+:1024F00053BF16F4E07BD32AA16CF6D31CA7A762C6
+:10250000FED1EF573AF5D4C441E0D5AFA7B45998FE
+:1025100097EFF39276F13C5BBB8B1FB53708F9124E
+:1025200058B40D7C58D2B2812747763C3F09F6EA71
+:10253000875661C7467FB73DB1706211877F9A8128
+:102540004F1CE2EF3ECDE7BFCD97A041DFDE621525
+:10255000EBF32D89A1F5E9FB1D44FFCD6392FCE46B
+:102560006FD9C3692E65802FA7346B07BD90CB85CB
+:102570000EBD0B78DB56EAEEE7F3D0C71DBD4CE18C
+:10258000F59BA731753D2FDE529448F06D9EEA13FE
+:10259000F6BC418FCB0D7A94F64AC1B8F3617F88BF
+:1025A000F939DB6FE9C5FC629BC4FCF69BF3FBA920
+:1025B000C398DFA1AD989F2D46552D89D485DB1199
+:1025C0002637588BD60A3A82E106BAAACAADA6FEC9
+:1025D000385FD212A60F325F16B93E731EB15B3957
+:1025E0003E5A307EA07D27F675A2A2EED0047CD2A2
+:1025F000307E7D86800FEBC982BE5095E6E893E27F
+:10260000A99383457C3C9BCCF9E520F079BCD47D33
+:102610005311D9435A8605FE8B051332A03F543817
+:102620005E7B573A1F4F1620FB4F8FF61745DA7D1A
+:10263000F58DC51EA12735FCE71DB00FDEB4921E37
+:102640005D7F7BA147E8490E1FE4F9728F8DE8BAE0
+:10265000786F960CBB7BF91B16610718FB60AEFB0D
+:102660002549F5A501CE120B3CCBE7BD7C4F61BAE5
+:102670009597EB3D36097A5455DA3B5BAA79BF1D35
+:102680009D423E74AC1B43FAE673FF75D5073EE0EE
+:10269000036FD385F7795A13C6E9B843D37DBCDFFE
+:1026A000131267D980DF827892771DEB0E3FF80B0B
+:1026B000D42F71E918B7234BEC6F475C8E1F76431C
+:1026C000230B90BDC30D4F7D077F1C71BCB205FC71
+:1026D0007289F3F52D58D7C516F926D87317670AEE
+:1026E000391A5A67EDEC92F05E32CB5D281FE1F4A7
+:1026F000B09B98BE9612AE07545999077452D529CB
+:10270000FBC65C10F65EE2EFA10F285A4AB8DE77EE
+:10271000AEF71D89EDEC7682479698BFA1579C5283
+:10272000F4841FA2FBEA6F2CCC1D26AFAA15E1B7DB
+:10273000BA275E2F9813F6DDCC6299F8F022439EFB
+:102740003BDB1FFDDBD37CBCA2A6CCACF5C903F8F8
+:10275000FFA1414F6F1589F629C063DE7FD189DC67
+:10276000F781FFFEE6044DBE14FA0623FAF46DB2BB
+:1027700047D0FB8B9BD2FDF07FC42A627F176F8806
+:10278000F337F1BDA9FACCD607BC7CF1F884560F1B
+:10279000FFAED7C242F2B473D391393EDBA22543D8
+:1027A000CFDE6CF0273E1EEDD38B0B52887E4C782B
+:1027B00099E35439AC417BFC20FD276B93D1CFF1D9
+:1027C000D58F6D079FE7834C86BFAE4E15702B8A61
+:1027D0001D3F19FA61A363FC64F0C3AEA9DE8FA7A5
+:1027E00084F9EF5E8A195104FA7CC9C6087F9CED12
+:1027F000E33E025CCE064777B1B0574C7E60F6B33D
+:102800001FEBC8C53A72465786F1DB2A8793E8BFAB
+:10281000E8048753F28F8793D9BF09A773F57F36F2
+:10282000F81C2C757F0EF9C5EDBB4EECDF7EA7536F
+:102830005BC3E1BBCF79B9518E237B518A7112BD45
+:1028400015C5C4929F588A9DB8BD1DF814EB243B52
+:102850006091DD9D25815FC6DA35E0C77EE70B79A3
+:10286000F05F14D5737A95E01FBCA212FD15C5D890
+:10287000C94ED9E77C2D1DF4BEFF569B8EFEF63B5C
+:10288000277E44FDF3FED03E39C9BDAD1D7C5C62A0
+:1028900073D6A8A2FE2D7CDF1C9F857EC61567130C
+:1028A0009C4B62E308EF8A62859FA268B8C0C3A20E
+:1028B000BBEC9D82AEDC5D3D629F3C3B74C8E97819
+:1028C00037E6B5D21947FE9B73E285E25B8B753222
+:1028D000475C3EF8F8CA315A35ECA195D2481DFC48
+:1028E000ABC816F80DFC3F8C6B7DE8BF289ECB7300
+:1028F00094DFE2F23CEBBF953C1F57CCE1B528B624
+:10290000278DF425BE69D083374A3D1AE60BF900BE
+:102910003FEF4629701EEDA3C2B2A017E630DE7E5F
+:1029200032C917B63EACBDA288F6158EF7A91E7D3A
+:10293000DAE9FBF6AD28DB54A6A23E5A1E3DE29C26
+:10294000D1D5407AB83AC79AC6589C2CFA973344E6
+:102950007F5B8B7CE3555EDE5A15A3376781EE0201
+:10296000E735B8CE94638BECFA07E0678CF3A71DCC
+:10297000B0371305FE9BEB2D33E87046B1B0CB1694
+:10298000C5723E987B663B934FCE34DA8D99EA2E22
+:10299000849C2D847F8E3FE3723D591C83D97BEE4E
+:1029A00015BD31BCBF140B6F3F8D96E36353C88ECA
+:1029B00030CBF044B3FB643EC36128FEBAAB647A0B
+:1029C0007859B4EFFFDEF755554906D985FDF51066
+:1029D000AFDC5E34CB6E27C7B7B57103F50A8797B6
+:1029E000A34D32C6DB5D553A9AB18F25637CDF0B70
+:1029F0009D6EC801278B182F7C7E4A54FF56DEBF80
+:102A00004B33DAFB6ABDE8EFBE7CB3FC3FFC6E3EA5
+:102A1000FF7BAC91FD11EB30BE47C11CEF9D57D73A
+:102A2000766DC818B05BB91DFB33E09B16528B6006
+:102A3000BF9AF66DAC7A151955D66FE631D88FD698
+:102A400064E18FB7F23D1C0D3D43CBEE22FD48D132
+:102A50007CC00BC7082D1FFA6093B13F9509C25F78
+:102A6000A9EC9DE3861A6765DACE37B3C8DEBDB33D
+:102A700018F22BB3E220F8D180BDABB8819B63B8CC
+:102A8000DD2CF1768E0E2E7701930CD93F4612CBBA
+:102A900082DEB0EE3ECF8518E7EFC5DEBB8BC3EC20
+:102AA000AE311D6E1BECBBC3067FED58922D4B6102
+:102AB000F8F3B0813F6360E7E7A2BDBF2D1B7655F9
+:102AC000E23CB2A7CD76D9EA6819EBCECE10ED6222
+:102AD000B9FD0C3F5776873705B3C856BC0BB0DE3F
+:102AE000ECF937DBA01F3D5C2CFC2F93DBFC4EF890
+:102AF000B3588DCCC6F0FEEE2AD684BF56AD16FE76
+:102B0000DEF90E17ECED6D9E9D4EF43F26A78BC6A9
+:102B100067AAA2A33D53B87DCFDB3D98A45CB83E25
+:102B20006C3EEB55A51CF328B0786F257E30649A77
+:102B30001BFC6AB8E5EDAC4ED84F43F22DCD1CD44A
+:102B40009BA5487A319FC34BC57EB4481EDF6CE815
+:102B5000059C3740EF32EB3375E15F78B158F823CD
+:102B6000349F5AE4E0E34CFFCA43FEAF178B85FF66
+:102B7000E3774A6FAC8A7933F7AD5558A7C7A5817B
+:102B8000CF32439F4B5EADE998B723B9F7AE0B50F8
+:102B9000AFCB3AC276A6BFECC40BA95DE0E3134A03
+:102BA000BCAF01DF0A2CBDF7CEC67AEE5274F473C7
+:102BB000E2053BE90DC9BFC8253DC59ADC43705EFF
+:102BC00097C6C80EB874DD47B1302F1CC91E067DEC
+:102BD0003A966F13F474974BF2430E4DD6F512E20A
+:102BE0006F0D4C1FA3C35FC20504AFBFD2F1B6D0B7
+:102BF000E3A3FC0463383E7DE2A01051CBF7D06321
+:102C000074E12F2863C25F70E8BB79142F911D5EB9
+:102C1000F2E395CC8F619857BF7FA1B5F75519E3C3
+:102C2000F6F8955A0EF7383D40F26A31E89E37A91A
+:102C3000CAA9B261B09B3B24C2A36A03EF98A28FDA
+:102C4000843DF17171AC61EFB610DCAB998013DBA0
+:102C500060273DBAAABD90FC61E63E71CA12ED3A0A
+:102C6000041DDAD6083DA7CA884770400AFFBB4159
+:102C70007FA63F9EB176F134C6DD2CF5B82D020F4C
+:102C800048FF5E387AEEADAFF279274D9E908F798E
+:102C9000A729CC61E1F6B6B544D8CD09FB855DBD69
+:102CA00055DA948EF96D4DD7A466BE1F93CB05DE21
+:102CB000DC93C8ED01E8E56FB34B609FA4C63674A2
+:102CC000021F526FCAC9875C882911F08A99D4BE45
+:102CD0008FF4F75B35B58BE360DA9ADE52E07FDA8A
+:102CE000951A43FC2F617F03C535427318D50FBD7C
+:102CF000765513DADF358C2559D09E35492BF83CB3
+:102D00005A874A84E7AD955CFFCF057AA9843719C5
+:102D1000F355097E8554CE46D08F83A9BBF88CD954
+:102D20007DF1A21CBA9D2576C154952D3741FFE651
+:102D3000FC93D695C4F1BF0B71D492448253AA9DE3
+:102D4000954B49E2BD9FFC51CC0D7F6E6A71431ECD
+:102D5000C64F1D259EEBF3821427DBC6FC5B760075
+:102D60009E393615F07CE9F8C116D0C7177936DDE3
+:102D7000C2F128E5BA432D18FF84A434C0DF7E8653
+:102D8000DD7751F198120E9FFB9AE62C588C7E2627
+:102D9000BA881E986F977E15C5A322E5A962E8DD63
+:102DA000278FC5C81267D82D861E71E8D0A804F8F1
+:102DB0009F29D6C2D73DA92489D6739269092A9F33
+:102DC000EFA17D63A9DE2C37A21DE84F57C84E380E
+:102DD000D30E5B61D89D1611BF31E8D89598E25F9C
+:102DE0009F45F6998FE256BB9CFE2E8A3BB120D5BB
+:102DF0003F3B4ED45BE6103D847671BB550BB7D795
+:102E0000822AE2402756F76C291983709FE12F7DB3
+:102E1000398EE6916C0BAA13F8775F486CF71AC0ED
+:102E20006D42682C16EF92845D77C2F0AFFA74A5FC
+:102E30006B078DEB4EBB2ACC6E6B31F8A04B0ADED4
+:102E40004CFDEE72CAE1FE9A6176FE1EEB7E86BFF5
+:102E50000FD3FB5EB28AF7BE5DCE087DF0395B70A2
+:102E6000278DB75BBC7F55F5DE581226776AE38362
+:102E700063135D3F069EF97703DFB91DDD83F83AE2
+:102E800087970FED5D1B47907ECBE129F0749D4441
+:102E9000F0E4F63DC9C34FF2942EBBB07F89DE8FBC
+:102EA00058758ADFF86EBF40DD417E45DDB618FDFE
+:102EB00014A635C01F61CECB6515F6AB0B767042FC
+:102EC000D87B038E4C09AA73C3ECE645F9D5152CC3
+:102ED000FEECFAECA29AEF16326EBF2D6AB31BCA53
+:102EE00085F0EF99F5265EF6EF8381979CFF44F815
+:102EF000E9D7950839EC8FF2E72DF1B17DE45F79E0
+:102F0000C40E65B69F3E369630938FD9603F2D79BB
+:102F1000DF49766474BBD34ECE2F1197FED51C8A41
+:102F2000FFDCCC1AE859C3BF13F1A0813898CCF567
+:102F3000A3A52C40EFB53685FC22DABBB17EC4696F
+:102F4000B836A3B18B901AE021FCCDCA90F5203E93
+:102F50009338B7E7DF692DBC3E95AF779D42F4D03B
+:102F6000D926F925FEDDDA1659F8B13648FE311CAE
+:102F70004F7C2DB21BFDF0F1D2C0779F2A117AC28F
+:102F8000AB25869CE520C07CCCA7D93F871BED7381
+:102F900013938328CB9278AE851E3088BD60F6D718
+:102FA000626D70404F098D90299ED662F52E07FE06
+:102FB000B4FC3556869ED212D7D0562EEA89479C4D
+:102FC0007606CB299E9B270B85166C037ACD5F9DD9
+:102FD0009DC0C7874B845E1EBDDF8BDB23CBB76CE8
+:102FE000892C2FF147961731EF6FD32C881F45BEE0
+:102FF0007FB844C42316318DF6A1C5AAFD318BFCE0
+:103000003B0AC3FC9B3204FCE411E2999D58329FB9
+:10301000E839D1C6A00F6E30FC181BDA92C97E6C5D
+:103020004914F8F67F3ADFE879BE593256C0375175
+:103030008CD7C2E9D38017F1A1454FDA1F06BFD361
+:103040000CFC3F2A093EE95B672139CE5CFE7563C3
+:10305000F9778BD65928EEEBB786721027F16D8C75
+:1030600023FBFBB0A4EF445E96C4B414E0C95183C3
+:103070006FCBF75C52007EFD46149D54E9D2DB16FF
+:103080008EFFC5576D28C07CA60D61BA9DCFED455A
+:103090009B3F16A23F7AFDFC4F534C3F20DFD2CC22
+:1030A000555A19ECC63AFE7E08F850787BF25FD884
+:1030B00006E88AEFDBB60B3DDF423E4D2B16EB9A5E
+:1030C000F66BBBBF5982BD7478D76B9389FF137FB2
+:1030D000AF5F15DA897C94BA0BBD32F2248EDDFE27
+:1030E0005E99A4B17EB9F1C5CB42FF9BDC1246B715
+:1030F000F89F0D9174CCDA92285EC73A22DFD76C24
+:103100008FFA8EFD973D7C9EA69EB3D9E61D0F3D9E
+:10311000759BA7A000F3D96C6D2F075FE89AEA4D65
+:103120002EE5F51F957A0ECAE4D7758F053FF9DDB8
+:1031300077CDA467F87298BA83F2317A67A05CF011
+:10314000BF6409EB7C1D7A7C989FC9D4834DFD2B0D
+:103150009A1EB552A1374D2C75EF829E7BD977BF51
+:103160007763BF9BF74A2AE9C7AEFDC1E19013BC64
+:103170000CFDB85EEB3D88389ABA7FF9A984115CE2
+:103180002F7565935C60198CF4E7FA0E51CF7CBC07
+:10319000FE9281B8BAB2B7A93C9BAFCFBAA7C98398
+:1031A00075C24E811CB0D650920FE28E849F9BF95F
+:1031B0001C40FF939385BEC63150F80F6DC2DE48A8
+:1031C0004909921F17195EC0BF8B4ADDF3B17F1FFB
+:1031D000E315D723EE9AE29E8AB2D7F0637D0DBD48
+:1031E000E302C67A0D3BEBD09FAE22BDE26BE62137
+:1031F000BDA2B054F0F743FBAE49E8CD1D78FF897E
+:10320000C57B9BCAE9FC16E6233EBD84F9E9C93AB1
+:103210008688FD66DE32CCB7B682EB5689A20CFFFB
+:10322000749DC7467E7ED06D308A6EC3CB8CD36DC5
+:10323000300C5F6A959E56D20BB94530640AE2D5D0
+:1032400091EDEB5988F8CEF23DDFDB23FA31F0281F
+:10325000D5B2228FFC19FF667CF1DF6D7F446B4F86
+:1032600081EB81CB7BA293FD469E4399C5E536E277
+:10327000F5C29F7F469E47A8B581EF77D134BBBA90
+:1032800086F40011CF3FDE6D65C03366D9D00A7F6A
+:10329000D8F2E1166619249EBF94ED424611AB3573
+:1032A000F242FF4FF3675697F6E7CF64FD6FE6CF24
+:1032B000B49686E5CF44D3D5FF34E2F6AFB84E0DD1
+:1032C000F186D517E5FAC83F515034383D7618F4E9
+:1032D000186BE45539141F0BF7EF9DEDBBED061E7F
+:1032E000BF620BBD1B986CC43F90B72B8BFC2DD9D4
+:1032F000A12635A5C30FE17910F4E1D04CFF03B747
+:103300005B93C947A6C26FE7D002791AECFF5A97C0
+:103310000E3B3436972B20BC7E21CB21FFC9CA62DD
+:1033200031BF7E3C89C21F4967143F83BD8F7E87B2
+:1033300073B311F6974D0EEC425982FF8ED3CF76C0
+:10334000674F16CD8B6FAA88AF7AC9FF071F0BEAAC
+:10335000EF4934ECAB3C615F713CA73237AA554171
+:103360006F3DBD900B771538280FD78443AA2CE208
+:10337000AF67D30B53B91EEB4AA2278B4BA27C67D6
+:103380005FDC0FB437F94FEA8406F267A4CADCFEAB
+:10339000CB23BB91ECAAE1965B0B699D8B18BD1FFB
+:1033A0009114B815EB1891C4545A774C7081880F5A
+:1033B0008A72BAD25048FE279DA94D5307FA8FFB57
+:1033C000F0993CBC8F1B69C0CBD693053FB6ED3658
+:1033D000870EBEFEB752CF9F4BC9FE769F4FF94076
+:1033E00006DCEB0DFA0AA35B1FF1EB28BA85BF0ED2
+:1033F000762F6BB793BE47A442E574D2FF3F409946
+:10340000CFE797533D874B497F35F4857B26927EE6
+:10341000C51A87107F5D1B27ECD0ED52706B385EAC
+:103420000DC0CB47F32828EA217B207407C7C3B01F
+:10343000FDC934F03A64F879FAF1DA28EB65EE2F39
+:1034400031FEE4C9C10791AF58CF957CEC737DE0A4
+:10345000678FBD994CEB6DA032FC8D58A7C745FE18
+:10346000B6A985DE6FC5BC7B5BB1FECC645600BFE0
+:10347000DBFA9CB96C918BFC78DF037E5C9FD8896A
+:103480007E387D3740CE1D9EBB94F2580ABE2F6E0B
+:103490002D17F355A16F26DB855FD79CDFC832411E
+:1034A0005FE673B891E7788C73E9C22C8CE75E40D5
+:1034B000FE6DC39F16ABF5B8699EDD42F92A80EC1C
+:1034C000C07C7F9141F0AEEF2ECC831F83059C79A9
+:1034D000685FF03717C1FBD8EDC3C89F34A1C49B08
+:1034E0005C06BC981C92B07FC7765D913718BF4EC2
+:1034F000B52431AC23D5C202F7AA03789062F32E2B
+:1035000080BC5898CB45219FB2CDC8EBCC34E46A3F
+:10351000E62A0F5BEC1A28BB92C5BEF0F732C699BB
+:10352000585A6A435EA8AD4CA1EFCC3C148DA96BF0
+:1035300058D6997492C544DEC95D461E0AF385E5E6
+:10354000CB649F998762CEC7FCDECC4389FD46D809
+:1035500029D9AAF0ABC6B51978BA8A11DE4E0FF593
+:103560001427F0F58EEE084E87BF0FE986C04BBEDC
+:10357000EF775DC0DF270F51A6439E3CD898BF1F51
+:103580007C4B59D77309409FD5C164B894CDBC40DA
+:10359000FA4B86BF2B51E0B7D29003FBF2FA32C14F
+:1035A000DFA616BA8B00FFA23F5B453EE346119FA4
+:1035B0003A9D5878641FEC908D7194877636BEE101
+:1035C00063FB292F351B79622EAC43F8D5D8688E62
+:1035D000107CBECAC6BF513C5C59F7A71198CA4FB0
+:1035E000CA5C342EBE83BD17B7C12263FE8BDB24B9
+:1035F0008A4B834323EF6E715B7211BE5BDC2EE955
+:1036000098F6E22D8532F2ACF887A47F8DE95065FB
+:103610006F987C5866ACE7F7DF59281F4F76087F14
+:10362000789D96D469117E10A2D3BA51C99DB00B72
+:10363000161BF8AD74CCF1A56B03FA9BD95F5DF74F
+:10364000AD2C1C0FA3F9CFEF15C17F7ECF31BB5D31
+:103650001FC0BF16AB80B7EF5F32E17FA6215F0FBF
+:10366000DFFD6D3AF5D7EFFF13FC50B16AADB073D3
+:1036700095A6DE4B01E7EAF644B93E17FDE8F5A44E
+:10368000FF6E8C65B05732378CDA8F3CDCCC3695C8
+:10369000491AFAABCB841DEC7BCFCE802FCAC6581B
+:1036A00082A3B2C90D2C624A620AC14FB98F9779C1
+:1036B000FBB232917736DDC0C71629649C7371E77F
+:1036C00041DFD6CBBC6B810714EF009C1B63847F6A
+:1036D0005FE9217A7DB0A06704F0E7411BABC17AB6
+:1036E000F6DF7DDE5C9177AC48C09738E43783AF76
+:1036F000BF9B4A7AEDBD067C07C197E1842F2F5B03
+:103700003CA047C5C83351D6717B310B79DA5ECA0C
+:10371000D39EEEEB290659C1BF5CA8FDFB72A03F0A
+:10372000BEEBF645E4BDECB7AAA4E79BF916D1F3CE
+:10373000DB69CC5B97455E36DF2727E8C58C67DD04
+:103740000FBB6F0CF2B98CFCAE350A43BED7FDB18E
+:10375000BFA4FCAF469F5D453EF13F9C23FDF0DBDF
+:10376000A419F659E8EF71FE2EB26F7CB20DF5B2D6
+:103770006377B85FE819037F1B158DF245D81BC22C
+:103780004E3DA5083FEEA9552AD903C9316F515EB8
+:1037900081D6C4117624D6EFA6BC346673D0B901A5
+:1037A000B3BF24E43984C541930CFDEDA52456A292
+:1037B000E60FBC7FC558EF5183CF232F80F8BB4B5A
+:1037C000E4FD0CC477F577DFE2EF2D6BCED710B7B1
+:1037D00037E3BC96F8020D74DFE82AD0103F7D2253
+:1037E000D1FB5659D8BEBF149F5604BFD0FF0FF36C
+:1037F000BB8E609D6F18FE8D378EC7C859DCFE4AA0
+:10380000427ED010D801FEAD3743CE5EED223B3C68
+:1038100009F94143604F34FEE71D7C9DC3DEB05281
+:103820003E70710D9720BCDD30E40B65211F48C050
+:10383000C5F7B285E032ACDC4DF94049C807E2F586
+:1038400016E4030D413E5090F2283A9A2ED07CC9DE
+:10385000C8071A2593BFFF4D0BE159479EB6B53AED
+:1038600019F1B65CC29B5F49065FAA64221F284E0D
+:10387000F8C53A16338AD3F4E703D569945F04BFD9
+:1038800029E141033B8BDF54E825A11B99C06B451F
+:10389000E49F7D3145257BBADF6FBAC066FAA1850A
+:1038A000BF617E8EF0AB5A248A4F8616C4F88DBC59
+:1038B00021B1EE31D9C23F63C8AD2F7E92447E6BF9
+:1038C000939EBF30FC4BBE9A18A35D281E7EE96D07
+:1038D0008CED46DE5AF3146D1FE23F5F20AF9CF67D
+:1038E00035141FEE4F3DD7FBFD56773AF1D53936EB
+:1038F000F24F733C1DB50170D09D79E4FF37F2F2B1
+:103900008A8C2972FA54EE057DBAD3743ADFE7281F
+:103910007587C711A2F16666145DCE34E8323AFFAE
+:1039200068F6E591F94766FE8C593FEF7241AFE6C4
+:103930007391A1C799F868B6BBEC72E12FEC6F17D1
+:103940003B78BB92FE76C6B8768E5FE043467E40FB
+:103950004592E08766FB2B8D769551FD46B79BDD42
+:10396000DFCEC88F6A3E8B5D67F0A1970ADC4D976A
+:10397000F3796CCCEAA1BCD48D92B013CCBC09E035
+:1039800011ECA68D52FB02C3AE5245D9C8AB70985C
+:103990007910222F626B8AF93D67F9F9F40C228EB7
+:1039A000B4D1D993063FC240FEE345C4578BFBF325
+:1039B0001F755ABFAF49AC5FDFBFE73C9CCB7BE5CF
+:1039C0004E55A3789191B764E2410ED30E202FA3F8
+:1039D000C22DF21FD916ED00F2B65E918C7CC42880
+:1039E000BC30E552743E92D4B6AF05F931A0BC1993
+:1039F00053C2F392A68CAE34F4B970FC2B7219F951
+:103A00004F2E7BD07EFE20E39C239FD19C47B45C4D
+:103A10007D293F95E42A27B140D29401FDE61DB4EB
+:103A2000E3F0FDF872CFFACBA1375E3BB585F4B673
+:103A30000AE12FDA2F73FD007E389BB0AB6CD70CF8
+:103A4000EF6A0ED3A34DFDE725231EC4D202BB416E
+:103A50006F1392B47CD8BB489506DF79A27B18E936
+:103A6000ABF71B7833410AAC481CF5EFC827B7DC2D
+:103A70004772D46AF009BD17F9B31FC639C80FD30E
+:103A8000A8F85EF38A7EF2111F5C394637E493C8CA
+:103A90004B6AB6068EE2E9BB9369C8DFFE6F2C87DE
+:103AA0005E04BD34FB659F95CB9F66838FFDE3EF7E
+:103AB000D72A80C349DFC46CD84D66FB4306BD9648
+:103AC0001AF2FB95D57BB62B617EEC6257A1027B87
+:103AD000A9D4A52BA0D362D71C057EC452354F6153
+:103AE0005C4FBC383EAF8CE24151FBCD14CFC4F0EB
+:103AF0003C4D739FDFB9DCFD16E667B63FDBFA4D40
+:103B00007BDA66D397E25C21D74E1B108FFB13AA9A
+:103B1000E037B18716822E865BE2F566FE7C37764B
+:103B2000E1C1A17C1FBF55BDEFA3FFF9D75ED18ACC
+:103B3000B2B47F88B682CFE78BCADE02D885ADAA41
+:103B4000B717F5380F9AC251E9B6933D744E927982
+:103B50008618F69467E260E7D8CCF91C30F07D4C0B
+:103B600082F708F07DBF1C8AD3E9DC883A92CE83C5
+:103B7000AB625DFF69D0E93EABFE5D88CF7FDFA61B
+:103B8000CC3CC4CF8B62FF7EFD72D8E1F7A7E6C1C3
+:103B90008E33E15264D8738B654F4AD01231DFD334
+:103BA00018A7D65599992EE6BB9088D53154F8635D
+:103BB000152DD71377F6F9364BC1C799D06FC9CFFA
+:103BC00075130207E23C3BF1CBE71997CFFCBD5DD3
+:103BD0006EA6FCC450A54387FCFD830167C6C4F7ED
+:103BE0003B1C2C09F4E8297A81FC3C0FD7BB74D824
+:103BF0005195880B59101F72939FF6E3C26F5FEEC9
+:103C0000E5EB4A2AF7C695F3F16F1A228FFC13D120
+:103C10009BF73CF813D97401E773ED7B0E94483E93
+:103C2000EEDC9912E9078B0DF8CC631E3AEF7A0DA2
+:103C30006B30CE016BC7EB93E9FCAE717E439B8882
+:103C4000F92D6022BF2EFA3CF042A6BE8CF3AF7F66
+:103C50006C4AFDE9EDBCCD5C3934D216766E96C364
+:103C60007B743987F7E952717E96ADAA1C47FBDA5F
+:103C700031F447E1EB1C49C08DF3C35CF453346469
+:103C8000520B1DA24570263D9C3E7A9B13F83CE7E3
+:103C9000A464E5C15F73D9776A06D65BC654C9923E
+:103CA0003780179C21C7A79BE788F9DFFDA7E2595A
+:103CB000326FD7936D21FDB0BC709F0BEB2AB5D44A
+:103CC0000EFB82F7D7037B832CBE868C6EDE6E568E
+:103CD0009A85CEB1BCD6E46D813DF6DA7849E73CF1
+:103CE000815D913C87CE6DF6B0CF5A96E0BB2976C8
+:103CF000D547722CA84CE6DFCD703BE89C51798605
+:103D000075C09FCCFFBB727464B92237D2FFCC5808
+:103D1000AF02BA9CEA75519C7BD639FCD173CA8D2F
+:103D20007B0426B009880FBD12E58F2E3EB73F7A7F
+:103D30003EF0ACFF1C99CA2D3F3EFECE4B8674412F
+:103D40004FEC99FECAC580CBA9BD59C8C46337548E
+:103D5000087E7757B9C78BFDA9B7F52E04FC3E5CEA
+:103D6000CD071A077FB883B9B922FEC96A95CA9FE1
+:103D7000AD4EA3E7E7AB357A1E5B9D43F52756EBC7
+:103D800054FEB8DC5D83F135D6B005F6DECA268573
+:103D9000415F5819B74294AD0E15426CED8883729D
+:103DA0002C2FAFF50BBFC6926E7F2B96BD6CAFDB91
+:103DB000869CC19523928A5D687F9F382D7AF3A1F6
+:103DC00086834093FA3F7F340BE867AEBBEE1B89D6
+:103DD0007939090DA970FF0CE37EBA7A0ACDE7C8DC
+:103DE0006A37CDE7E8EA727ACA577856A1BEBE4D67
+:103DF0003A80739D339FEC53F02C754BE4F7B8D4A5
+:103E0000CDFCFE2C9C3BF17A412F5BD21D941F5AB6
+:103E10003871EE033F61E0D3DE56C0E7EAA445A562
+:103E200043B28097E21E80CB6E90F4A03680CFE73D
+:103E3000A2078DF59C80DE70DC27E0F24EF73B5444
+:103E40003EA970B8F0959EEC8E25BDE0E4BB3164D0
+:103E500077B064FDEA8B79D9FEBA888F8C567FF9EA
+:103E6000D95B04D77892E35CEF25BEF0D27A11DFFC
+:103E70003CCAF70DCE7373DCA34FFD2C2D3CEE70C6
+:103E8000342970FA3DF0B5BFCBE6F9E6C32FF2F264
+:103E9000F32D2AF18B13D6C02790AFBE110ECAB3F3
+:103EA000AA47FFA09F0FE42EE8094763C478A1BF8B
+:103EB000C6D079867E3BF5DD98CE487DA34187BC90
+:103EC00033ED607BE6CF7523DFF9B54EE81D192E83
+:103ED00043AF68A809CF775E6B0B1C855FCDD72AEF
+:103EE000F48AB546BEB3EF2DA157D80D7EF2DF4060
+:103EF000AF7815F8D088FDC4FAF97E420F3EFEBBBC
+:103F0000A624789824998BE84B185BF1EC79A97476
+:103F10003E34237950FCC07E69E306CAE377DFF2C2
+:103F2000E1CFB581B27DD7B3E7FD2D9960AEC54E27
+:103F3000C3FAC5FEB0AD36DA9FF1BFFDF5E7EFF18C
+:103F4000E7E3BBD6C55CCF9F1F950B3FC93FFE9EE5
+:103F50002A4D001EF99C1AE27789EAE0F1A97BA0BC
+:103F6000DF8C1928274C67D262DE2ED11562A4DFC0
+:103F70004C5725E83789B8BF82F39B8B2FD5CB28C8
+:103F80008FC5C0E7C31B9F1F8EFD19C7ED30F0E939
+:103F90004577BF30FC053EBF47B96C46FCEE25AB0C
+:103FA0007E620FF6F30107E5873DBAB12E1F72A6B8
+:103FB000FA570BCAD2C1979E63740EFBDB72A1C77E
+:103FC000DEBC65D7AFA0BFE6EA4C477F176CEF9326
+:103FD00087F1EFF21E919AF19CF4649685AE494800
+:103FE0000BFC1C743341663AFC5AECBB878785CBCB
+:103FF0007D768516E15F3B6F44F9219C5FCAEDF841
+:10400000B268180BD7A363489E9E97DA9904BE370F
+:1040100031F3B9CF9B40CF463CF5C297AF7EFD62EE
+:10402000067DDC97EE20FF00873BE4B75FE4141FBA
+:10403000EF1E457AF873B28FF4055F155F27E8C06D
+:10404000E3A3B8481D6F8FBC8BBABC9E3E9CC7A92A
+:104050004BCCA67B6E3EF3AF247DE322AE87609D02
+:10406000F5DDF7950DE3E5E3D3992EF1F16B9E3D78
+:104070004571655C8C023FE3F1EEE694EBF8F7776F
+:10408000E516517EABC712A0F1D87231DEF2BDBB8E
+:10409000E83C13520091779AB8B7F095E1B40EBF9F
+:1040A000C8CBE8BD3B0BFE87A15E6E7FF1F65BB22D
+:1040B0007CE9B0EF4CBD26A9DC937505F450F55EA4
+:1040C0003A47F1B164C4D77EA47E62931B28DF9483
+:1040D000A5097BD3EC77841CA473FD9C4D50BEFED8
+:1040E0000E55C41931D23D34AE37EF0AC4512C9568
+:1040F00064CF0EB70B7B94A95751DEE78F1DFFFEEF
+:10410000D8FF22FD77B91C4FF7A998FAE3FC21CD1F
+:10411000748FC9B844EF251867B1A1973145D7A06E
+:10412000C7D812DD975E41FA2FD77B64D2778A50C9
+:10413000AEB7707D7854983EECF871FA8EC6F42DC7
+:10414000F037F6CBBDAFF323E41E5327BD0BBBEA1C
+:10415000E3389941CF6107E4DA83DCBEBC04FF9603
+:10416000C3ECA6B87CE21BD04D065BFFEF38DFF056
+:10417000725805B97CF68E43A39E66C443DCFCFFEF
+:10418000E3F8BE5FFA8DCC0DD201BD22FA7B0E772B
+:104190002FD659C86223DAB95922C583992BE9472A
+:1041A000AE37F870A49CDFFF70F87AA79F7C3716B3
+:1041B000AA2B87432A9E675BCFCBC67AAEAEF0AE02
+:1041C000B8228C6E2FF94AA5FB72F87C6FC3FB4BAB
+:1041D00015CECFC3F3694C3CF991F3FDA924F23F0E
+:1041E000D99736B28FF71A7EB5BD4B72293FEA399F
+:1041F0009C5B14F286F8EBDE38E17FDC3B2785FC24
+:104200007E2F99F18B4AE17FDEEB14F8BC375D55C8
+:1042100091A33ECCCE3EE906DD5A12481EF4F73F8C
+:104220005415DF9BFECB0562FC8E39EEF498643C9E
+:1042300053641AFFBF2CEE70BF5FBF3F332F78DE91
+:104240006FA95D0EF92B8759441E266BB61BFECA5B
+:1042500015AF4F9C0C7F672CE94B1D59FEB66C9433
+:10426000EF1845ED1B59F0D794C711B251BCE49C2F
+:10427000E7172B2D91E7172B2D51E7177D71D03FB5
+:10428000FF6AECE7BB8AB0ABDFF5479E5F7CD7BC2B
+:10429000BF42F1C585DBBFE77AFF5E949FD1ACEFEB
+:1042A000486C1F8ABC9CE015DEE7810F0B16EF708F
+:1042B0007AC3E210BB1C9E1780D7DB62F459D7800B
+:1042C0004F570BFBF33DAB886FF9FE2913BC7E57AC
+:1042D000FDEA22ACEB77A134161EC734F1A43F2FC0
+:1042E000769568FF63F38C1F720D9E675C3E579C4A
+:1042F0002F3CB94A36F362459EF1B376D3BF2BE625
+:10430000F7F244C20B66C4DD1F0A0C25F91434F21F
+:104310008E1F5282C397037FF63A093F790F4EC82A
+:10432000F91332DB0D7DF02683EF3DC4B404C2B334
+:104330004316DAEFFB63E3A9FF2FEEE0E3F372B07D
+:104340001FFE7ADA556172B3D9B877EC2166E415AD
+:1043500007FEAFE7219F08A7EF33F290CF0A6F99CE
+:10436000FCEDA1DB2D863F9DEB58BCFD430D230CDE
+:10437000788B384F88F3219CF7658AB84FE0212568
+:1043800087E23E17C33807BCEB2403DEFE756331BA
+:10439000AF97C7101CCD3CA64FEE903B019F13ABCF
+:1043A0000E176CD1F03D3B1FF7FDF8BAEDD4EEA12E
+:1043B00028FC7EC880A3D7F0E7B15F0A3DF903B5BA
+:1043C000372E5C3FFDC0F3491CF8DFFB8D96A0ED56
+:1043D00007F2956FD8F2E9BF90AF7C83C7D6877C90
+:1043E000C9B3B6FB655505FBA17A23EFF986DAE878
+:1043F000BCCAC83CC9E22BDD23AFBC300CFE9FC950
+:10440000678D6710FCE364335E41F8F4E267C3CC68
+:104410003C7011AF38E232F6271044BCEAC5EE2CEE
+:104420001D72AE1FFE5BED543FC047FCB173C2E886
+:10443000FF4545C0F3457F64FEF78B86DFAE1FCE98
+:104440009FCB9447DFACEA8E70386FBBD03BED4A10
+:104450004EBF6B5CF90EE4F1D524141D823FCE7B78
+:10446000A5F752BC977B4F94C18FB99C89385B5D8F
+:104470006E7021DD2FB6EAC7C9F765317BEB71DFBE
+:10448000C4E77B773C87279F8F8803ED16F2C02B0C
+:1044900007E38D32D92BCBF83F2F4DC2D36FA379D1
+:1044A000BB59C3DAA967E6EB120B4911ED851F274B
+:1044B00060BB3819F96E4CDBA6E2BD6DA03DF98FEB
+:1044C000FCA41FF2F62BA0A72D4BDC73F7C5FCFD57
+:1044D0005297CBB12AE9CC7D5EDABDB667D4F967D5
+:1044E000BE3F731E629D4A7C4F19F6ABEF2E898149
+:1044F000BEA63516B3C39306FC5AEA948683B07BF6
+:1045000016F389AA5CE254FA7ED68AF28E86781D6A
+:10451000F1EB35B123CBEEE4E51A4F8C8E7840E514
+:104520003D9BE8BB697B051E4C7B4CF20F963F52CE
+:104530001978F46BC485ABA2F26DAB3744CDF31C94
+:1045400079B64B1FF9DE1E99772BD6B5D85887C59B
+:10455000378BF8C534C30EFF084DA6226FD4B306BF
+:10456000F430ADA350D42B428FA963220FB4CEE117
+:10457000BD8DF6D1C1D4CB79FB4371365ACFA92D6D
+:1045800009E47F3A65D0D1A9EDE2DE2B338FBF6E0F
+:1045900088785FF78CE4875FA1CE5249FB57B7520A
+:1045A000E483214FD41D365FE489869759BBE98F98
+:1045B0000DD2774B1B9888A3F0FD7347E441076D3C
+:1045C0009FF171EA7D52605BA2C81F8DE8C7F0734E
+:1045D0002E6742BF471E6964BD9FEC8587ACC2CF82
+:1045E000C9C95E1567EF428FEFE4F35EF9F7CBB709
+:1045F0003AB2C3F49825D6B3E93182DE373989DE81
+:10460000ADFD7A8C7B2CCEDF766C1AAF033EC32CCB
+:10461000863D305CF8633B86EE7F9CE2ACDCFE605E
+:10462000791477F521AFA563C904E31E0683FEE77D
+:10463000DBCEC2A7768B7BE9EE93FAE532E4C47554
+:104640009B524DB92CE6B5D1C83750DC631D543FA1
+:104650005E37E2AEA27E288BE65343C1A7606B6350
+:104660001FAE33CEA95C17754EE5BAFE732AFEA1C4
+:10467000E1F1D373BDEF4874A727E552BEF71FAF32
+:104680000C938F1D897E27F2B659CD8F8B0FEC309E
+:10469000F41013EE1F49226FBC3AC6B3FE32BEAE11
+:1046A000EACDD9D9C0BF0FAF147EBF8222B11FBCE3
+:1046B000BD4EF0708BFDF808F61F877F75B67B2C1A
+:1046C000F21BCD7CD30FF2841FDFBC4FF0A8D1CFFB
+:1046D000D12BE588272B11F6F0474E81678B2707F2
+:1046E000ADE0B33B349137586DF3FC8F4BC2E6F32A
+:1046F00000F00DFBCA34CA23FCDAE8B75A96DCB0E6
+:104700005BAB7F6527BAE1F3A0FD2F582175C1DFB0
+:10471000F591112733F7853171EFC8757F184AE796
+:1047200016CCF3871C5F29CF8AEB93425F3E1BBEFA
+:10473000727C867C4BECC757315EC782B1847FC3E5
+:104740002C02BEEC9E38D14F69513AEC34E407FCA0
+:104750002FB42BEDCF0F20BFD739F5EC25D64EC0A7
+:10476000BD5FCF5E62ED1A0CEFFAF1E5FF1DDE656D
+:10477000CD187A76BCE3DF5FF8437195BAE79F7A8C
+:10478000CEC7E7B9F4B7F7C5C34F7444694FD179C1
+:10479000BFB53BEE8C77F3E7678A2F1EFD1DF15BFB
+:1047A000E85C70743FDE199271AED41D8FFB87CD2B
+:1047B00078EBE74F7CDBFA73BE2FA72516821CA986
+:1047C000EFFE67EBCF399C0EBA1D21C899CF94DE5E
+:1047D000B25FF0F2924A574313DD0F13952FFEE8B4
+:1047E0007D299AB81F73B8384715A4FCAAFA47ACBC
+:1047F00074EF5CFD9F2C3AD064390BB5627ED1DF3B
+:104800002F0F1CB6012F549985322E3EB31E06156C
+:10481000FC08CBBBEFFA12FEA5E5DD47DE83DE1513
+:104820009D775E63F82DA3FDFDB36718FEFE8BD860
+:104830004590C71C3E3AF4131F9FD718B1FD84D78B
+:10484000CD8F3FFA34FCB447DE4BCD435ECCB1474D
+:104850005E8FC73971D3EF6FC6478E05462578073F
+:1048600081AFF93C11E51F36F9BDB64712973EEF0F
+:1048700015CF5A6B301EFA476DA755E73BCC6A9FA0
+:104880007A78E736E0FD5FED74EEBBF6A95336F0BB
+:10489000D95AC91D92283EC3E2A5B038F9B2A73E45
+:1048A0002EFB35F493740BABE0FBB6F499AF457B6C
+:1048B00037375878FB65BBFACA70DF4EADD7D5E005
+:1048C0001864DF8A03FB6CBDAE41F62DD057467EDF
+:1048D00091C7FF41FB72E477124BCD3AF3FB9A1D6F
+:1048E0004749DF3AC63748859C0B582A6D0967B699
+:1048F0003BF6482CD1F3B1BD12E5999E6B1F2F9862
+:10490000C10C7C8F63B8AFB4E63DBBBF02FB7BF745
+:104910004AC2FB4F950681F70FDC9982FB126AAC05
+:10492000BE14959EE27DCD833F35F0D19D8EFC4E29
+:10493000CAC6E0EB5ABCFD6A5A57CD038B685D6C62
+:10494000ABC42EE45BF135D787770DB29F7F32E899
+:10495000C5CE6E3D1FF4F135FF047ACCA7463CC0AE
+:10496000F747911F65675D1F401FFDBA67A804F9EF
+:104970006779DBEAC07A7FF27222D9398FCD10FCD9
+:10498000BAF8EDAFCB40573FC9521A8C7B107D0669
+:104990009CA4EF853D4AE7B1284F301BFD9EB4DD56
+:1049A000C8DB7F05FD548F684F70FAB4CB1E83F3CC
+:1049B000369FA6887C48FEF74706FC107DB1E58F40
+:1049C0007D7A702DF0296D949C9086EB3B05BFE7B6
+:1049D000EFCBE0DF56AB5C0D091C3E5FFDE9B00D8F
+:1049E0007E515FB2CC703F5FBDFF4B1A9737FF120D
+:1049F0007861C263F99EC87332CB1FF9388A6EA3FF
+:104A0000CEDDB00682DB72964071944F6D211BF8AB
+:104A1000818F8F8BB8C3CD1D61E772D0DFAACF0C19
+:104A20007CB00DBCCF1AA03B333E778B41E7D1FB66
+:104A3000154DF76F45D1BDF93DDB3E781C6980CE41
+:104A40007DB4EFB556E653413F7FB5935CAADD24B4
+:104A5000E891713E3986E3FBE10DAFA4E09EDBA354
+:104A6000016B72058D1AC9576B767F7C702D6F3F75
+:104A70002CCDC29CC457FF6183BD9656CC42763E76
+:104A8000FFA3357E09F90C67D0257F3F285DD6B09E
+:104A9000FFBBFC946DF812F6EF00DC23E9F096B34F
+:104AA000F0D37FCE30CEF31870FD9AE526C07FCFCD
+:104AB000D4CA4CF21346C1D7846B345FBC6F8626D0
+:104AC000FC9B517C91FFFD8585C191B15EC2E3D312
+:104AD0009CCF411F37F1977905FEF2B26D18D69B36
+:104AE000223394EBFDFBE6217E72E6BA23E1195DE9
+:104AF000BFD7E03B9E17441E7AED5EC9385FE523C1
+:104B00003B6C39FCBED4BAFDE0F0E4F0B23FAA1C25
+:104B1000886AEF8E2A7BA2DA7BA3CA0D11ED6BF7B0
+:104B2000BC621387108211EDEC8D33C8CE3A535F0F
+:104B3000F00B3AEFFED2E6037E6484E8BE88228B57
+:104B40007E288FEFEB8CB8675CE02F669E4EB34BF0
+:104B5000E451BE9696D565FCCE02F19162838FCC6E
+:104B6000AB107CB099E5B7E0BC938FE333E8D78E08
+:104B700093A9E07B19163AE7CA14AFB292978B1645
+:104B8000D5521CBE2463D1815DD8A7297615FB526E
+:104B90009C31F3405E32F0DF11B2F37273C62487AA
+:104BA0003648DCEF95263DA36190F7E6B3D8F1E6F1
+:104BB0007CF81B4A5C91FC664614DFB8428BAC2F34
+:104BC00067BB93A1E796E75A19A73C5686F661FCA6
+:104BD00054AF10F7D25CC1DA5B54417FB4EE4B0C9A
+:104BE000386728790AFC1D25CADBAFC0DE29FC8A9C
+:104BF00069023F04BC8BBFD215C0BBD095A8883CCE
+:104C0000FBD042E81916395EDC6FCECD2DE4553766
+:104C1000231F2F0FF7A07BAB2B282F49654580530F
+:104C2000110B408F97F6BEF64F11FF6B9041A7E333
+:104C3000B61CA4FB01C7395C41BA1F70BB722CE2E1
+:104C40005EB1A8FBCD6705769D801E336B5E2CC5DB
+:104C5000B966B1C05BB8BF97CDB3507CB0EFE9384F
+:104C60001BE27B33035F2AC0B399D3250A83F7394C
+:104C7000D591B7F279575A441EE5CF0C79D1EC148F
+:104C80007A7265EB88B1D9FCFDCCB3FCCEC2630669
+:104C90009E6436EB69C81709494EB56BF2407BF448
+:104CA000837E9FAE10799E6B2A845C34CB99C5C2FB
+:104CB000FEA96EB3F78D8AC7D31A1CC79F936617D8
+:104CC000B5024E15D9ECA0B0BB240DFA7B9F53F86A
+:104CD00085421BB3C89EF0F22DC5BDC9AC7114A3AB
+:104CE0007516EA369C5BEFDB94A5220F2A36D74D6A
+:104CF000DFDFDC2ED1EF89F41532618FC4D9C88E85
+:104D0000FB405547A2FD0769A3282F25D3B26F3476
+:104D1000D96D79C26E3B39D3BBAD0272E83BBEDEC2
+:104D200002E40332017416C801DFBBEBBA18162483
+:104D30003B40A77B9977393C0FA1FDE1460BC5119C
+:104D40000ED7887B75FF5221F85EA625389AE27649
+:104D5000AAC8177DD0D6BB00FDFDD223EA2B92D482
+:104D600002E46784EE74328C5F99A42E44FBCAD6A9
+:104D70007114EFAC5823ECBC754A80CEB9F9DD9ABA
+:104D8000ECE3F8F30BF4CFC7BDA149F1E07EDC0CF6
+:104D9000075370EEAE76B6770DE63333D0F401CE1E
+:104DA000072CF2093B7CD1864D36C8C5524B2E9D4F
+:104DB000CB35EF01391BFDED5C2DCE4C3CB6DA4115
+:104DC000CF275673BCE68AF493ABD3A8FCF46A8D64
+:104DD0009E81D539F47EF76A9DCADDABA750F9B93B
+:104DE000D56E2AEF595D4ECF17577BE8FD6826D662
+:104DF00031B2519C5334CBB66A5E4E473948E71204
+:104E0000531C4C4539DBF87D1495D3FCDA74DC9FD8
+:104E1000EBA67BB2152FD3F0BD0DBFE4C0EB6380D2
+:104E200032E9808346793A195ED680FA11801B2FC9
+:104E3000DB4AC478E6BE30A39F07EB9846F159A53C
+:104E4000773CF6B7D4726CE345FCFDC91A99F2E6DB
+:104E50004FB2DEA79EA7B28BE23F236DEC04CEBD1E
+:104E600073AEA1594682EEF5343BDFCFCC5F966737
+:104E7000811F5CCF0D14254C8EDED8E0A45C61B39D
+:104E80007C53636244B9F522EFA7C0FB1B57F53D85
+:104E9000F03F79FF1FFCF2938F1FD5681E3BEEC7D2
+:104EA000B8AB6274DC8F7F12628BAFE3648B95ECDE
+:104EB00062FC85DF335879C7041BF203FADC0E5D10
+:104EC0005281675A19CE03FBB87E807B42DEC37ED7
+:104ED00072F8BF6FECA7B3FD1FE497EB33FC76D1FC
+:104EE000F70D4A33B3094E1FFCFC5BE1FFB73A54A0
+:104EF000E421F4D524C56B420F8DB897B5CA172BA2
+:104F0000EE776CB188FCE0E87B1175C1173F045F58
+:104F10004C147C12F7A87A83821F7E78478A0F7A16
+:104F2000D487B7C6EBC854F2B6A5FA6EE1E50DB862
+:104F30004707F27C2F6BA57C6559FC7E03F3592350
+:104F4000F9636F4622F44033DF3876B29FF4738EF4
+:104F5000562AECAAAA9CFD74BF056B9754D85DB87D
+:104F60006FC99104FE639C2353BCE3E7E1FCCD4C85
+:104F70000BD1D5EC99E29C5EA691473E73B2F02B23
+:104F80002CF18FEBB284C5716A67178D9819CED753
+:104F9000E67D99477687AAC909B877AFC85D867D4F
+:104FA000AB28D256E09E2ECEE746CD445EAC652FB0
+:104FB000E1E5494E07B8BFE124EB11E534E127B440
+:104FC000B16E81B7D5228E9FE1307E2748177432AB
+:104FD0001C9C909795D1A2FCFF8A5E176A821ED313
+:104FE000383DAE15F444BFD7115322F81933E6917A
+:104FF0003D5EF8B94CFAB2B615CAF05399FCCEC969
+:1050000074D247AB3788FBABAADBF36C3787C99701
+:105010002AE3FDA21C710FBBF97E81B11F9B6DFEBF
+:10502000A634F8398D7BB450C67D3A9B97BA937DF0
+:105030006CA0FD95C6BE353B3D75CF824E9F8A253F
+:105040007958D97AE3CC0BC1579F1E42E7FC3E9FAB
+:10505000B58BF260AB5A16FCF4CFC0C3C79CF4BE4C
+:105060007AA67719E8F173495BF82CEC015FD63525
+:1050700017F2EFD3B0C9E45711F7C66D5E5F48F77A
+:10508000D071E4B7816F98F3AECAC96F45BCB86AF6
+:105090004361B220522FE56D342FB84E815FF44644
+:1050A000637EB36732617F187213F7DBC0AFF41908
+:1050B000320F08AEC2DFF6F913BFF90472FEF4E353
+:1050C00071F87919B6F40221B759AEBF40DC0F155B
+:1050D000698F94FCE638E9D1C7B9FE46F667F761F7
+:1050E0001BC5AB393F043E2EEFB6F4E17ED168BD5F
+:1050F000F8C0D37F8B1FD41EE9167E9473D923A5E5
+:10510000C6EF532D7F41E8D3FDF6A4F40DD9EDCBC6
+:105110005FBE33C53B883E013BB83169B0DF0BF859
+:1051200071F64BB4DDD23E33D26E31EDC1B3C93925
+:10513000D36E31CB358DE78F827F716963C128F8DB
+:105140001BEB1B2F1D157EAFD171238FD42CD79D48
+:10515000258FF43FAC457ED0B9993F5AD3789ED184
+:10516000EF24EA6FB7A177698A9600FC39E91F93AB
+:10517000C07E609ECBB7F0C5E0DE2FDE1EFE8FB096
+:10518000F345A4F72DFBFDA824E0E392BDF7DA6414
+:10519000FEFEB399424F3B1E658FD53F7998FC23A5
+:1051A00075AC87F691EF2F7384DBE75B6C344EF4BC
+:1051B000BC96FD268EF2FB960424F70EFEFD32BB54
+:1051C000760FE87ED9EB57597D61FB7DC0C0EFE8D3
+:1051D00079BF30538B788F7932EA2770027994EC5B
+:1051E000B7B1A4CF7DB157F88F3F7DD2F230F4B77D
+:1051F00025815DF5C44F9F8C5591BFF5B935F29E61
+:10520000C31E63BC9E9986BF9C05A8FDD127632958
+:10521000DE86F9825F98BF03667EF717E3BBBFCCDB
+:1052200014FB5063D0A3D97E89ABDD46F9A52F5E70
+:1052300095BC06F3DAF34EFC68FEBED7F8EE8BEEB3
+:1052400058BA8F6949F7B7B35E821DD95D9C2C852A
+:10525000F1A1E333C53958E617F1A6E37B85BFB664
+:105260000EF0E57870D4F02F1D7D7A48A790E7FE08
+:1052700008F81CED7E265ECE1DD8BFE50E5FDBB8BC
+:10528000EC81F3C30E6B830F0ABDB2778E0F7A3EAB
+:10529000D13F1FA72DC7E7015FEBFFFD15879BF2ED
+:1052A000A1EAF7CC6142FF73917EB4E2592BC5D9D4
+:1052B000165EA05D7B3DF8C3EB5682FF8AF12C0899
+:1052C000BBE754631CDDABF4816B6C2AFC21DBDE95
+:1052D000B4D27DBF0B2709FED388BC3FD2C3E33ACB
+:1052E000E1BFAF6D93E8BC595F967B0D7EF7C03C84
+:1052F0001FC805FF1F20D76BDF1A4579B7B57E9110
+:1053000047CAA604C786D3CBC82DE2BC5ACA2CB163
+:105310008F1FD8443E7BA665FF5823FF43EA0A8BC4
+:10532000731E93826329AF655764FE44EDDCE05839
+:10533000C4236A77A7533CE298718E18EFA1EFD689
+:10534000E68B3C89FEF63FDF3F1678585B15C84177
+:105350007D5F967A82EC8F67E3E89E05F979716F3D
+:1053600071DDA3CE2EF1BB7BFEB7A1FF35376548BB
+:10537000F0775D60CCF741A85A90378F38C539A0D7
+:10538000B3E4830C93DA45DEC78EC87C900F6CE2E1
+:10539000BD6F67E47A8E59DBE91E3BDF8EC87C90D7
+:1053A00063B676910FB233F2FD92F8765A5F9F950D
+:1053B00089BC98C7459E0073F59CA678E76F9C440E
+:1053C000179FA7FB4F635F3E7F6014E551F665B5FD
+:1053D000DB709F66A8D011C23D274B5B7F43F74B24
+:1053E0002D8514E7FAC7D2271E2DC0F747ACA2DCE3
+:1053F0007C878BE1FEC143719BC95E39F9885D02F0
+:10540000DF3FC9DA174A4619F03F22F9857F7989CB
+:105410004A768BD78CE7ECD83A12703FB2E3D132A0
+:10542000F80F1F2A723458063927BDF491C87874D2
+:105430005F56E4B93ECF2CC1E73CB38C7385B3848F
+:105440007DBF6CFC1F9F03DEF765093AE3FB49F65D
+:10545000E3B65D4E2A2F7B6A6817ECB44C4B970D70
+:10546000FE75BE6E3A0724FD728B0D79C7B0DFED75
+:1054700079A097EDE4FF3EC5E527F4348D1DA2DF4A
+:105480000F3A1578F82DE4919EC2510795EE834F9F
+:105490005507E1DF7D56FF5895F6C199DF65E8EDC8
+:1054A000B0F78EEC1C4EF7615524B19BE6021E4905
+:1054B000EDE7237EB4B4F1DB853F948FB2F4F93885
+:1054C000B7F81D02FF6DF8BD9DBA7B12E81C46DDE2
+:1054D0005AB15FE0B5F05B2EE5E424FDC03D2C4BF6
+:1054E0005D9F507E4C347CA3F31A76CE12F7BFD664
+:1054F000D9051C97ED14F79FD5727AC5798165ADF2
+:10550000C2EFCF9E10F7DEAD7406E39167BF7287DE
+:1055100045F7F1D7CB6C81B143F9FA36CD127C93C4
+:10552000B7F7820FF67F6FD3EFA77EDFBA9AEEA1AF
+:10553000DB342B99C63B16B83705F654747BE4ABC5
+:10554000ABAEF0760FC787C769CC76FDEB0C707DEC
+:10555000E77CEC53CF6DC8FFFEEA4927CD8BCB0922
+:10556000CA778C5E3F9F2FE1F3B2A7ED74BFC051A5
+:10557000E3FCEAA79C0FFBC6613E33EEA1F5FEF10A
+:105580002ACA27BEC51FF9FD29ADA700F87FAA7B4F
+:10559000A682EF37CF1272A06EEDC5B3E9BB3F58BC
+:1055A000E9BBE8FDB87D96F8DDC37EBA7D2A56E4F6
+:1055B00007B1C0D3E8EFE853B132E8B62FD16F435B
+:1055C0007E7F681F0BE13ED3A3D6C048D855479FC6
+:1055D0001A978738EED2460BDD1F7F343130520DDB
+:1055E0007BDF67DC2B888435FC2E602DFA1E35307E
+:1055F000FE32C7861EE859C89B29C8A767D09E748B
+:10560000665E0BF015FE8884D9426E522E2EF26D26
+:10561000D01FE177C08638AB49E7B54F46E7C5886C
+:10562000FAD76719DF73924A36F37540AFD6800D0B
+:10563000F7548424A6E1F72697B5DCBA04792CCB7D
+:105640001A365D0F7C5DA6B0721B9F579F247E7734
+:10565000ABCFC9E907FA57F838D9E2A9A60CACF3E1
+:10566000CFC6787F9D25E422D7BB593BFC252DD2A0
+:1056700006F46BF215CA3F0CFB0E792090537D8522
+:10568000467DD47AFB8C3CD6D0535267B87C8A5E78
+:1056900077E26C2127FAB2B47BA6270FE43BF2F243
+:1056A0001F2E13F252C67E3743899F2AFAC47F9B6E
+:1056B0009764505E7C8D8529E9F9823EFBF3542C7A
+:1056C00091FE1A9C7F80FD8727EC3FCD2EEC3F9406
+:1056D00061FFE109FB0FEF61FFA10CFB0F65D87FB4
+:1056E00028C3FEC313F61FDEE7CD9623F3387F20D1
+:1056F000AF8DEE05E8CF5B3B23AF4DC4EBCDF8FC9F
+:1057000011393A3E4FF96B9F483DADE9D2B9F3D715
+:10571000B65DE81D397B28ED7F447FD346F927210C
+:10572000CFE2F7861CA835EEF91CBBDD16B11F3998
+:105730008F4496273C1959CEED8E2C9FBF37B2ACC3
+:105740001F882C7F388B89FDBDF3B5B138A7DF2BBF
+:10575000C5D17D6F75177A47619EF55BBE5C087F8A
+:10576000FC316B6827E6D3DBC4F75DE081F0FBF129
+:10577000DE80D766FEF539EF493CE7FD8891786217
+:105780009EC378C81A4A57490F9CFE20FC3E2BA4A2
+:1057900038BA47E4B093ADB913FAC77F8878E7C940
+:1057A0004356DAEF931BA4AEF0FCB2CB6647DEB7EC
+:1057B000B2E89B492473FACB1B24995D007FB61C89
+:1057C000319FF1FE9808789DF758524479626058ED
+:1057D00044FB0BF66447D48FF6BACB861A72187165
+:1057E00087BCE08448BEBBAA4DC869BCE07CF1AA76
+:1057F0000D9322BFC74928BE9E959D920E3E5AED3D
+:10580000B938E2FB9577B4519EDE4A272740FE7DEA
+:10581000F516F1FB2D2325B686E2ABBB445EA299BB
+:1058200077BFC890334CF1D9282E9C2CFC8847A414
+:105830009E91F8DD9F2513DA374F97909FD6391246
+:10584000F96E2D33BC37CF167919B3286EBCCB9ABD
+:1058500008BA3876E8E33918F758C09A44FCD3D828
+:10586000FF9156E117ED9CC2E8CEF6CE76613F740B
+:10587000B60F89191D16B7E0EB4A811FFE24D743E6
+:10588000B09FA5965CD2B74F1D12BFFBA73596D32C
+:105890007DEE2BDEB6121D9AF3AFCD7FEDC124193C
+:1058A000E71219D917C7E4FDA7D7F2FAA37981B196
+:1058B00041C8916D9D29D7F1F98412BCAB66F3FD07
+:1058C0005EF166713CE2A05F3F69A5BCF88F3B1EAC
+:1058D0007E10792A6BDB1FB6C19FBC54F1DB282EEA
+:1058E000FF78A70D792A973FD649EF6F7EAC92ECEF
+:1058F000CDCFAC0DB43FBE0724F66CD83A4B2D1B70
+:10590000C626D3BEA527020FDF37F84D4D8CB8DF72
+:10591000E1AA8A422BFC674B9F4CA473CD57CF93CF
+:10592000D6201FB2F6D010BA6FE93E031F4FBE61FA
+:10593000213DE4E43C8B5FC8A1C1CF5B5FF54D1610
+:10594000E1EBBC6FCE233BECEAE07861EFE6864802
+:105950004F3DC9847FF2E41BA76C57A13FE4C77099
+:1059600056A2CD17799C2B258E7FBC7EE59BEFD070
+:105970007A5666B106E04B8DAD47E41B14B110EECC
+:1059800011F54CB744E0D7F292D8087C9CCF922214
+:10599000F250AFC18F338495E7558C8A687FEDBC98
+:1059A000F3A2E83B7FA09EE87B5A84DE463737446B
+:1059B00094AF8C685FC7E60ED4C34E7E44C409EA38
+:1059C000BA13293E58837B89F8BECDF78AF7F57B59
+:1059D000128DB8614CFFB991048BF01F849F7B61DD
+:1059E000465CB10EFFD2E017ED217F5428DD42F76F
+:1059F00027D6B7BFDD2A1BFE289C5BAAF3F5DA7019
+:105A00007EADCECD42B8EFAF4EE921B8BA74357B4A
+:105A10004DFA001ED477479E0FAE3F24E06FC6BFFD
+:105A2000A3EBB93C6945BCB8BE42CA83DDB9ECC939
+:105A30003E1BFC58F3BC19740FFB2D5B22FD57B5C0
+:105A4000813E9AE7D57B52C8CF5D0F3F53D87E6425
+:105A500078843C31E34238172ECE47BBF6633D9C39
+:105A6000DEC89E3EF9C6C39289472CEF4C78D4AD70
+:105A7000FACC06397910F57CFDC3F43FB7C2BE55A8
+:105A8000AB847F2E1A6F001F250C3EC3804761F543
+:105A9000373301AF9BB938F7E7FDFB70D2903B83FA
+:105AA000F9EE11E7E14FBE7198F2374E7A5D0D388D
+:105AB000477B0BE2F2BC7CCB1E9B1AD4CF845BF4F9
+:105AC000FAA2E1F6FF01116C07D30080000000008C
+:105AD0001F8B080000000000000BED7D0B7854D5F3
+:105AE000B5FF3E671E992493E42424904008272F95
+:105AF0000812C2040282501C928051A27708AF049F
+:105B00004298404040E086686BB4D84C48801840CA
+:105B1000C34BD14B25E0A3D6521A1F556AB51D10B1
+:105B2000110BB6687D560A017AADDAF69A62A9F1D0
+:105B3000DEB6FED76FED7392394380F6FE1FF77E17
+:105B4000F7FBC7AFDDECB3F7D98FB5D77BAD7D667B
+:105B5000A9FFE4D18D05422C4DB689768F1065DD05
+:105B60004E21C60871AB38B9414DA4D22F6A83F1DA
+:105B700042CCE9B6F3F32145279D2E7ADEF543C5E5
+:105B8000B34F1162B5EFE43441EF0B8F48BF3F458F
+:105B90008859A5D142B804FF7D25B8DD29A8BFE604
+:105BA0001119F74F106276777F1E67F5738E739D1C
+:105BB0003921FD8EFDD28971345574A54EBCB45D7A
+:105BC000884EA72F869E8BCD7FB4C5D2BA76517BE7
+:105BD000E83C6B3FFE958845BBBDF7793AD62B165E
+:105BE000FADC4234E101AD4FD82AE3AA73515927B8
+:105BF000C458EA83BFEB7BCBFA5391AF1E09997768
+:105C0000A82F26F123DA12F51DFB954DBEEFA7F163
+:105C1000843B41880997BEFF4583EBD5230EBC1D0D
+:105C200010224988A9B652D549FBAA7EDDD61E416D
+:105C3000EBD1CB737EB191E0E17FDD265A752AD797
+:105C40004F55B16FFFEB8E7641ED75F7E40C10EE1A
+:105C5000DEF1FCBB68D27EBDF5B4C67EFDD15E4DE3
+:105C6000CFF590E71B9A33D33A737BEBD5915A7FEC
+:105C70000FD5AB1B6DBE762ACFDD3BA0FF789AE730
+:105C8000DC7A476229ADEEDC5D05696224EA53B92E
+:105C90003CBF35A2BC9DC61DF22D97B0D1FA563D32
+:105CA0003F60AF4DC17EDDFDCBA9FE8767FAE5639E
+:105CB000FB8D3E95F7B572FD0F63C753FDB6F5BF7B
+:105CC0001CA765109CA6FB4B7D04CF4F95BD4F686C
+:105CD000E8A8EDCDF3D1B8CBEAF3327F43E7BDAA14
+:105CE0007E1C97FEC6EC383FADA7B3E1A0389F1DE0
+:105CF000B24F21BC1D80AB6877CE88E97DFEBAA388
+:105D00007036C65D61A7F65C8C3782C731DB0F97B2
+:105D10002ABC9E271AE8D508219E6C7071F954831D
+:105D200026C43021F6372473FD4083CE6547430EE9
+:105D30003FFFE75D632C70FD4C8812CC3FC4F6C773
+:105D4000FC3AE087D63105785BFD4D215A09FF6F9B
+:105D50007107B9FE9B48A1ADCB1762B09D564CF0C0
+:105D600074E608AD91F0AA7AFB0B5350AFBE55080C
+:105D700085DA53ED2715F44F259A42BB533CA770A3
+:105D80007F4D684DD45E1D1794FD17D378F112DF57
+:105D9000C43821B250123C078B0E7E3FAA983009BE
+:105DA000780B08513D235BAEC721B434C506FCD641
+:105DB000BEF13EE8717DA4671FF52A2D247C0FC13A
+:105DC00083474B55C673B38CBB5967783DA07A9215
+:105DD0004526EDAB79B853004FD6AF4FC37A561076
+:105DE000386DF98CBF5598EF8E48A163BE8F23455F
+:105DF000F07AAA7FFC74647B13F0C2D5C8FD7F9F44
+:105E00002434B4FB097735AA5F7C2CA63D40EDBF56
+:105E1000570FFD792395BFCB0F0CB5D13CF91AE193
+:105E200007CD7B9BFAD21CE0CD8AD6BD6982D61FF6
+:105E3000281439B56E49270FD1FBB7131D804E6E5C
+:105E4000576AF774D27CB737DA45A000FD6ABF8382
+:105E50007A605D84D644E583D1DFDAD349CFEBEDB8
+:105E60002E2DC283F5D65E0B7CFB5A97103521F49C
+:105E70007B7DB74BD484F0892922DE522F72A5583E
+:105E8000FA4FD5D22DED37240FB7B4DFA8E75BEA80
+:105E9000D3732658FADFEC9962A9FFD3F81B2DFDC6
+:105EA00067786758EA334B2A2CFD67FBAA2DED7300
+:105EB000CB975BDA2BFC6B2CF5F9CBEEB2F45F5091
+:105EC000DB6869FF4215769CF34B441F3AE1FF4FB4
+:105ED000883E501E3E9164176A2F9E4C2A526B3B9F
+:105EE000DC97F2B3A306BD47977977978DC5A827AE
+:105EF000D371EE83E85FADF9BDF5547B4F3D05E707
+:105F00003029FAF0E73A91E0756FDEB3CC4E7C723F
+:105F1000D2B587C76452FD5B330EC9FAC4C3CF66DE
+:105F2000507DC38CAF647DD4E1CFD1FED59BAFCA89
+:105F3000FA4C1AEA3A8C77ECC920ADEBB06BCC0086
+:105F4000F0DD49D7D33A095FDD240FCA689ED52E0C
+:105F500077303356EEAB86682348748FF230D13DEC
+:105F6000CA2344F735C48F8F12DDA33CD6E0E1E7A6
+:105F70003F6B18CFE589062F973F6F28E1F26483C6
+:105F80008FCBB71ACAB97CBBC1CFEFBDDBB08CCB0E
+:105F9000F71B6AF9F9AF1AEAB93CD510E0E7802F90
+:105FA000EA7FF0497E240E3A7EDF23BF32809E9A3C
+:105FB000B017B01CEA02BD8897345148782C0E8B7C
+:105FC0000E865BA73DFE233A37B0CE50F887978206
+:105FD0008EF323735CEABCDDEEFDD2C7E792AAB173
+:105FE0009C329E6FBCC1FF37D0DB3BE933B3C75057
+:105FF0007DEE5FFCEBE3A8ED1D552CEBEB9CDFF198
+:1060000049FE706686D73683CAAFB94E5780FEF513
+:1060100014A18989A8FF84F99F7237FD8FF8D1D721
+:10602000EC279B506FFA52E8EB885E0FC51CE5FE2B
+:106030004DC41F23683F4A7707F3B7C935C476F3C9
+:10604000D1AF83F9DF64E27F225FAE3394DF7D4D11
+:1060500093FC12BC11FCB0A73FF13FF42FEE3E5968
+:10606000C475B7538F5030DF47456A01CF2FC02F1B
+:106070001EFB52F253512B34C704AC578E37996034
+:10608000B58ED773D2CBF55C733DB2FF643FAD27BD
+:106090001EF3D772BDA9DA9C9FFAA31D63C6837F46
+:1060A00077AC413D8AC449238D3FC02EDB9D1E59EC
+:1060B000A7F555737F971CDF6C17E37BF87FBE4213
+:1060C000F33B57BA3DE09F93734FA6F07A92851643
+:1060D00008E9EF9E24C7CBFA773FF37B0008FBC9A2
+:1060E000507C0274FC8E4FE773DA3DE5643AC6DB00
+:1060F000FD75178F37C8F6743EF8A8DDEB15D0DBB9
+:1061000066DE6C6B6FA5E7C34BFCDE198407F644B3
+:1061100095C76FF2C6B4B712BCDE52FAFD3A9AC602
+:106120009BA10A7F47EE15F1612ADEFFFFF8F0DF41
+:10613000131F0AEC1D7BF13C62A5CB03B97B35FC38
+:1061400058D825A6C55197C137FADF01DFA8EED68A
+:106150008FA25E63CF27D5A4B77D28DA932E6DF783
+:10616000FFA9CB81BAF9FC06639CC562CA34B4DBD3
+:1061700013DF8A06FF37C731FB2DB9A4DF6817F498
+:10618000F9DBA776EC865C2F819CC7FE8437369FAF
+:106190004C8422FC53C7FFC9F69B48CEB7E245DBCF
+:1061A000A42375D033C85EB141EEBBA51DA0D37F3B
+:1061B000E0B3D777DB2D76C14D62B31D70A4EE5DE1
+:1061C0001104F712D80726FF243CB929F7B76C371A
+:1061D000DC14663784DB01DF994176C008FA47BAE0
+:1061E00048077F7D05FA2BF47CC31E2812523F0D11
+:1061F000D75F4D7B80F4D8033342F45853BF7CA261
+:106200005A53591E088F3A9AEA53BD7A1DEA95D01F
+:106210006BA97F0E947D7A5E9CA2303DDF200276D2
+:1062200008891B453B97D34590E53B4DFFFBD5B413
+:10623000CF9B2197094EB7882E7EEE139E973A6921
+:106240003F472E8E2B1843F02956831B60677C56E0
+:10625000DD390EED1B34FF2BA0EF3FC7BC791AFAD6
+:10626000A4E8F20FC3F91D2E96EBAB9B4D3A573EB7
+:10627000E46F26EBEDE17CE215927B5924F75E2575
+:10628000F99B45FB7C8DE42FEAAF93FCCD0AD1EF5F
+:10629000A7E98AB087C0F3A69C4681F1A66B45C2E8
+:1062A000DEEFF2F26E7ADE8F5201DFE3F1C38A7124
+:1062B0004EC7E3AF2D16792807A8B28C70A2BCDCBC
+:1062C000FB263D4CCFDD78D29687F9A6F17C875D21
+:1062D000BF7C1EFAE3058093CAACE6935CBFC32182
+:1062E000F16CD50B3717EAD8FF3BB676D8419F60E3
+:1062F000E1843F93EB27F2FBD7D74FE0F2B70D22B3
+:10630000807DAF74C97DFC217028CF4670BC2FCE34
+:10631000FF19CEFBB7BB6D9E20DB4F919E525ACA30
+:10632000C7EDCFC6623F26FEACB4E99B3DC0FBE3A0
+:1063300036CFE33AE351F07AF0898E887D8F2B9740
+:10634000E213E1D117163C72FB07CEA0F3128FCDFA
+:10635000E4F59978B3D235CD0257D31E1D77A397B4
+:10636000E95A1341E65FABE99FD03F56BB4E2C671D
+:10637000FE42F5880997EA2FE3A2A83FF8958BEC37
+:106380009D09BD701D14115CCEFA60B4B46B847F9E
+:10639000CC35A0EBF7C67BDD656CFFE6EE37E11C84
+:1063A00001FE161C1187FE25C76CA29D96FA5A5451
+:1063B000DE7ED07727C15D217DEF8611B5EE0CC260
+:1063C000CBBC52FF00D6376D7FB161DE13D98AE8AE
+:1063D00047FD2F1C1BE366FBDBA0BBCB9D7B38FD81
+:1063E0000E2933E8374FE4817EA7DADC9E20D6F50C
+:1063F000B6CD43EA30D913B12ACB1BC3FE982C8605
+:106400003E3889DA8B8E39443BB55FC040E89FAC9B
+:10641000B07D63D2F5F5C2D73C09F4E975750589FD
+:106420001F4524AB420FE13F917A94D043D6119D92
+:106430009360A9C778065AFAC78DCFB0B4C77BAFAF
+:10644000B1B4F72B196DA927F9AEB3F41F505E68EC
+:10645000A9A7F86FB2F41FB4ACCC521F5C3BCFD2EB
+:106460007F48FD224B7B7A6085A5FD55E18B0BA60D
+:10647000039DBC6FE58C033F957F992D75967ED467
+:10648000E1889FE03288182FE829BBED6ECBB84237
+:1064900097FE9D00FD07FC9A9A6CF5F70C1293DAB3
+:1064A0008137C94D115A04C9C0226DCA11B0FF22EB
+:1064B000CDEAF719E4FEF814F8C2A030BE1E7EFE45
+:1064C0000BCB0C3FCEDF7BFEFE6BFA3EFF95A23D71
+:1064D000901EEAE791E73F8DCEBF95CE7FD82EEB99
+:1064E000F90F6FB79EFF8827ADE73FB2C37AFEA3CF
+:1064F0000E5ACF3F3F683DFF31C7ACE73FF6A4F5EA
+:10650000FCAF7DBF30EC1CBA987E5ED514F1701FD5
+:10651000E736A1D38A1FC2B699CFCD94AF133F2ED1
+:10652000EBF3DCCAE9BFFF17E7F640D8B95D149B6F
+:10653000C7E6D3BCDFB8D095E6B45DDEFF363E9E3D
+:10654000EC55D86161F6AAC9B72E67B77E11F9B7C5
+:10655000BDE0473AE923224D883BA3A85ED0CB9FFC
+:106560000285B5EC7708385D5A9387F186F1A2FE73
+:10657000544C3BF4D02FD4CE18C8E5D36A9B82F29A
+:10658000966BFD3F001F5B985BABC0DE4EBA6D8320
+:1065900002FDF6B3C15DA7BF8971EE8A61BE0F1F10
+:1065A0000CC6A96A1AC072DEDC4FD520C1F6EEC156
+:1065B00032C9D785A7732CF8FD8FCBA47E1EE3D1FB
+:1065C0009CEC0FCC155EF8F9C83C4CABA2F6A7E2E8
+:1065D000FD41C97F27EDDA9208FC8D151105217860
+:1065E000BCD6CE789CA54DF6433EDDAEC47A5A1398
+:1065F000E14F91EDA225A21DF2C7E6F4CC853D2125
+:106600007EEE501E4FEF5D972DD63380FB853DBF4C
+:106610003DD23320BE0F3DC12C97B7D8484450D946
+:1066200026CBCBF59BF89D885AF82385BD63F1C333
+:1066300034FF3945CF001FF9E4F117C62CA2E7E774
+:106640001CA2BC2F3B7677FC940FB1EF7AEC13EBD6
+:106650005EA6B6637D9FB85ED9F51B9287CB238F6C
+:10666000EF82FF70A2ED2DB607BAA86D1FCE1FFEF8
+:106670003ADACFC3591AFBD7260E09460E43FB4E12
+:1066800095FD6AC280CBC32B75B69F26DA9400EACB
+:106690005DF738DBE1071FB64B58F49B4F1CB27F08
+:1066A000E0EB43198EC3DB5DC21E4A47C6FA529720
+:1066B000A97B71DE239ED42CED233B922DE33D6C10
+:1066C00097FEC95107754BBF87DBD540F628F08987
+:1066D0001C4BFF31C73CD6F7E1DFCC05BF186F7903
+:1066E000BFD321D80E0A2C5759DFB8F67DAF759D60
+:1066F0007AD7D343A9BD6A4F3FE6E3133A4B2CE365
+:10670000A6CECC60BD62C8672FB2BDD4F94DA1A89A
+:1067100029E01B3E4BBF41F693AC4FA6C0BE61FBC8
+:10672000E74823DB4BB5526F1824A47D66EFF19741
+:10673000061B518F74C9FED4CEE3C7E784F94387A3
+:106740004BFDE55D2857B40E87DDAB42AF7DC4D964
+:106750005901FAAB8A10ECD7A2F3E37D3E7277FFC2
+:10676000BDA1F4953153FAB7DE85539CE8E97197E2
+:10677000F49FD242DE7F0DFD817789BDFDAF99295F
+:10678000E9F09B377973668EC57B1ABFFF88B3EB40
+:1067900003E80555A3E47C95AABA70068D43B65765
+:1067A000F93321F43076A6F40FFDC72CC59857AE07
+:1067B000BB2A4EAE4F7CD3C9F82AEC01B61F1F8905
+:1067C00012F1C0C7059B3BB60CA3AE95CE36073B76
+:1067D0008944BB03FCAAB4B0D30E7B78B1AFFF935E
+:1067E0006ED2CB1E0101C36F16787679906CC552BC
+:1067F000D1C57073D7D2A3096C1F78FBA29BFB672E
+:10680000D9785FA5EBE4FEF5350EDF3EEA57AA8A9C
+:106810001265746FBF7DB324BCDAB3D412F09B8DC4
+:1068200031567FF3B333255FFA96B1CFA9B654271B
+:10683000ECF2250AD95FB48F257775F3BE96C4387C
+:1068400075C08BE4516CFE383E4DFEF3BBFB3BC183
+:106850006F8E7A4517EBDB5ECF2EF0E34581086D36
+:106860002FBD571DB0CA915BA18F28AC87719C6961
+:106870003191E421C0A325AC9FFB2396374BC2E4A2
+:10688000CDAD663CE92AF6DFA3330DFD71941825E2
+:10689000F58797189F2F10A3C1BE2E005FC157091F
+:1068A0009F03F1ECBF67B847D548B80B039F1D2E77
+:1068B00089AF74947CDE59F54EE6F7885FD81D32B7
+:1068C0007E8112F10B7BB68C5FA08EF8054AC42F37
+:1068D000F0FC99060FD79F6B18CFF5E71BBC5C3F08
+:1068E000D850C2E58B0D3E7E6EE2A7B0770E875E74
+:1068F0008E73C5B94DB59DC8E2F5266AAA5CBF1E68
+:1069000017EFEE3DDF70FCF8BFB5BE4176E9774981
+:1069100033E83C3CAE62B6A700AE137AE3226EAD1C
+:10692000878F70BBD34F7CE43F1147E9E11B82F8AE
+:1069300045662F9C84CDBD0E71BA8BED64FFA58793
+:106940009CB7C738EFF667657DAD607F50B8FE61D4
+:10695000D675C4EF42E41CD14D540EE442B3DD932E
+:10696000AD5F0A67936E68FDEBD6B3DD24FD7864F6
+:106970004771DCF0F7643745D07BBF0F7C7E96EB28
+:10698000CF457A804C7FC83F9907BD7C956D6F9A43
+:1069900096D91B37CCF28B401CC6793292C7B9B05E
+:1069A00096008D753F19DD2EA8DE1978B67F5F76CB
+:1069B00094BFD31A770C2F874EF71F07FFF3373A90
+:1069C000E6000EBF73AB1AE074AFFB707FAFFB1F26
+:1069D0008AEFBD3933C49E2DB577315C63EED05557
+:1069E0009C37E9E9EBD663BD81CC7DD0AFCC781F75
+:1069F000C185CFF1C22485E3A665C2C77AD73BAA79
+:106A0000E690FE906022F8E33F1A179CD99DCFE7ED
+:106A100035AB7B22EFDFDF3281EB438704D428F0F4
+:106A2000E7F98AE7712AE63E26D647D1AB9D8D73FA
+:106A3000C7027EFF61C885A186BC0987D7EC599241
+:106A40002F3EA12A1C8F7E82F86C19ED77C47EAF91
+:106A50001A49E3963FA7E5DB74ACBB7634E0D36A12
+:106A6000D0A1D99F565288FD7E67A16EF88B04EFA6
+:106A7000FF9682F47D38D7BA5972FEC53E29C70801
+:106A80006E4C47758D0ADB3375E0B5A86F5158EF32
+:106A900033EB9FB719F5A9B27EFB7A59A7BF2AD865
+:106AA000478B04E98505128EF0E7008E280147F830
+:106AB0003DF61B7E1EC01125E088E7A07FD441FF74
+:106AC000A883FE5107FDA304FDE3798DF0A521B055
+:106AD0008CB85D7108BF46DCAE3884FF226E175A51
+:106AE00047DC2EB43FE276A1ED88DB85B6236E1736
+:106AF0005A47DC2EB43FE276A17531FEC6DE3AE29B
+:106B000037DE1996FA4CB27F8A43E405E276A1E3B8
+:106B1000236E6719CFBFC6F2FE7CD25043DFCFACE5
+:106B20006DB4F45F58AF58E27A24D658DE2FDED524
+:106B30008FF131A1C4376116E1C7C2B95D2F774A21
+:106B4000FEC4FE9BBA55511E79DE6D25F2FC5581BF
+:106B5000F3DCE3D0595FDFF3864DC8F3F60CD0FACF
+:106B6000C053C4B18A1D329E8612F1349488A7A105
+:106B7000443CAD385BC6D350229E86E788A7A1442B
+:106B80003C0D25E26928114F4389781A4AC4D3F095
+:106B90001EE26928114FC373C4D350229E86E7A713
+:106BA000691D88ABB5CD94F83CB22DF02A7C70B746
+:106BB000EC3E7D04E5D0B8EA671422E5C56F8F5C32
+:106BC0006127BE3E34BA7A743CF16687326645313D
+:106BD000D5FDDD32BE9F27BA581FF46B12BFFD41B1
+:106BE000C1FAFAC82F53B87DB1CF908F063D8D3CC6
+:106BF000A2319F5C0C3B31A9F7FD7C84E6327BFB24
+:106C0000F7D6FBEE173EBFD9CFEFB2AE63089C8B31
+:106C100034EF90D7F4F6A674A6032FEC9E495D27B7
+:106C20008BE2E8B93F30652CF842A9D3D04B45ED53
+:106C300075B0FF460414EFBE90F35B6BE89323F648
+:106C40000B6732F8C49EAA027E2FAAE7BD7FFF849D
+:106C50009E578F4FF720EF64D27EE1DD4BEFAF37C9
+:106C6000F8CCA4AE8EC3E06FD5CD33F83D73DCEA2B
+:106C7000DD694EDDDDBBFE6A517B7732ECBE02453D
+:106C8000800F0E055FA2FA804A5D817C5D8DA9A808
+:106C90006CC909F8B0EF6A38FFE9FC225C5E01FBC1
+:106CA00077F5C11902FCF26B05F1531331CE4BC2DB
+:106CB000930DFA2B78D3B25F3E8E71185FB0B2E4B9
+:106CC0000FAC51B1AF5B6823FDE89C6FA63AE0E6DC
+:106CD000F78BDA7402FA9CF26AE68F39954241FE2C
+:106CE000C2F0CABD6A22BD37C27F48851E30B2AD30
+:106CF000934B731F9E49F136D467D883B3B0FE1906
+:106D00001E07D305C94B96FB179A1D6CE7212F81EF
+:106D1000F9E431E917BAB076FC3F9517703BAFAB99
+:106D2000EE9EEEB3C89FAAFBA1550EAF5CF3CE3822
+:106D300035037258617A35F3753E4D6F7F229EE0C0
+:106D4000F269C6D3B1E31596A3CF828ECF364B3905
+:106D50005CBDFED558F8C53F6FFEA113F032E321AC
+:106D600035061C44AEF728D6579D22FD6AC2F6921E
+:106D7000137CFAA2DF5D6BA3FA39A21BEF30E607A2
+:106D8000DCEFF3834E991FD126F561D36F53FD8657
+:106D9000CC230AD79397373BAA9D644F2E0FD393EA
+:106DA0006FBB8A7E7C7C96A11F7B8407FAF1B9B009
+:106DB000F8C8A2ABC747DE021C4C3D4017C1D90C36
+:106DC000F7DA6C15E750FD8621EF3BF47D90F7A6CE
+:106DD0001E50D958C4F253FC50E25165A3EC57F948
+:106DE000236FBB425D7E61C8FFB2EE417C0EBF34B3
+:106DF000E4FDECEE114C9FA59D91FC7C4E770A972B
+:106E000073BB87F3F332B7A4D3CE9745FB3AE84D73
+:106E10008108E937392258DF08C7CF19F67635518E
+:106E2000015E35AE4BA2FACDD01F68BC72E813FDEF
+:106E300080EF8766B17D477896AD5C8AEF732BD380
+:106E4000A7A27D788922A0475D09DF95F8107E22F0
+:106E5000028EFE1877BF60BD64A85D1C7190BD56A0
+:106E6000156DD8BD6EE92FEAF127D15AA47DD8BAA5
+:106E7000C29BCB76A71003793B5EE4EDC5E4CAF66E
+:106E800001EFB4AE68CE821E2AED98B47A230E6963
+:106E9000D49D35D24ECF32EC9AFE2EA9AF6718762C
+:106EA000BC46B8B191F5772FD30FA9F53ADE770A32
+:106EB0001F9F4F1409B4ADD49EEAD2795FA9B42FB5
+:106EC000B40FB6CBB893B3D89C4F04FB8F0EB5B3B9
+:106ED000A55D0FFB1A7AD1823B141E7F714BF65EC3
+:106EE000A9A7E70E384BCF8FCE299C3F9BFAD7DD61
+:106EF0009B6DC9A70B2F17D339812EABE23ABFAEDA
+:106F0000109CF3670B6F31A98615C28013CD2F68D3
+:106F10002FF38CBAE79DEF7EDAE266F81A707CE018
+:106F2000A920C1AC65ED3AE677112E9F17E7199DB0
+:106F3000EBE5F85635E09B7479FB7DE5B5DE1AACE0
+:106F40007371AEE4FB7C0E05C8D7FBEDF742FD1470
+:106F5000A6BF8BC0C67AFF0365C9F9AD7AAFDC7AEC
+:106F600078452AFB356E99ADF6E4C3E9C3A4BE8625
+:106F700012FA1AF27EA0AFA10E7D0D25F4353C87E2
+:106F8000BE863AF435D4A1AFA10E7D0D25F4353C73
+:106F9000BF76AAAF6436FB4FDB387E2B72BA1E7AFF
+:106FA0001CFEA10627E7339AF6D49E1551BC8F3DEF
+:106FB000773BD9CE30EDAA4AE7C9575D744E9ED9CA
+:106FC000B2DF87F5DB1CE073749E926E57282C07A6
+:106FD0008FCEF1CDC63CD1B91E27F8873FB75DD122
+:106FE000099E03356947946674E5ABEC7F738FDDCA
+:106FF0001702A72136714424D038196D3C5ED7564C
+:10700000A53DB4BDC7EF3347F28FEC39523ECD6B8F
+:107010005318FE91A27D3DE869514BFE38ECE7E83C
+:107020001CFFAD7C3E2FA51F1DA4437EC53B71AE4A
+:107030005503A45F9666482B0BE16777CF967AF8E5
+:10704000357305979FE1DCB89FA49B8A7A4D69CD83
+:10705000EFF567A5E4680AEC9CBB674BFBC029DE33
+:1070600096F89F2CEDD954236F4135FC62267C5B4A
+:107070007316F1FE1C4420B6F810BA706A47D92F77
+:1070800019E3D4B1EF6AF7D06903E03769531214FA
+:107090007AB5C62DD89EAAD991B90F791ADF33D601
+:1070A0004B74E34C811CBB57D1100F294DD0E74ED8
+:1070B000C038AF3BC43E7A6FD11D87B299CE84CC25
+:1070C0006F0C8767CDAE094C4735ED545EC1AF7B81
+:1070D0006AEB8F9326006F835ECEE7ADD1BCCE8482
+:1070E00010FFD162E31CC2EBFF32DB26F9BD38E6AC
+:1070F000C03A2AB374057EC3EFCD96E7B7E08E742D
+:1071000027FCC29534B23A1AF821241CB62ADABEFA
+:107110007439CFE890711761DC9079A93FEB498F02
+:10712000CF8EE17916B5C53B15C8494DE3F5D1FEC3
+:107130001DEC5FCA92FB2F4DF038DD187F398D4F63
+:10714000209CA705997FCFCBD54523DB67FA34F088
+:10715000EF9ACD8A68A59A7FB39CCFDF12EF1C8986
+:10716000754669D3183FD72B31585F6982D7E966D6
+:107170007C4D5743F1351C3ED5C6BA6B687D4B2C10
+:10718000CFB73A401F15869DBDA87946DA83B4BEB5
+:107190009AC0C804CC536397FB7FD7386FBF01D721
+:1071A000CA84B6A97781EE96C6C737E9BDE3BD6646
+:1071B000E0E3BB067C4DF854686D8ED1EE10F8EE1E
+:1071C00094FB5FA205B331CF1297DC7FCFFA77C86B
+:1071D000796A76543B73A95C6AF7A53D48FD96062B
+:1071E000DE4845BEC7BB80F7585EC7FA145E87A26B
+:1071F000611D42F3A7013F3EDA39378DF7B5E34110
+:1072000087E07DBDC9F17AC01572D7C48FAA3192CB
+:107210001ECD793F9DEDE673FCD4D8872957A2EAAD
+:10722000A51FA866F39B5C5F4C74A6C487F8A35D9A
+:10723000567F748AC7F4DFF999DE2AB264BCC8A409
+:10724000C3471C9DCB41778B374BBDD6E40B2457EE
+:107250006B9FE943EECC37D633CF38A74A55F22B94
+:10726000B33DDEE04B9519326FBD476EC719FB9BEE
+:107270006DB41706B3D7E4F6F637E7AD4C90EFE1FF
+:10728000BCA0C37C65C803F4AFE3FEAAE197957E7A
+:1072900095BA2D368E5BD56D7994F95EDDD30AEB08
+:1072A000B1BFAB7BE1E7608D9F3ADA57A764F6AEDA
+:1072B0006309E933A0F3A586DCAC09F64DEF353759
+:1072C000FB63E784E4D7D76CFFFE50F0CDDF1D38B9
+:1072D000CE7CE4548CE45BF344C73BD7A5F7AE7F88
+:1072E00051CBDE968C44C8CBF8D190A366DC202D20
+:1072F0004757716EF30DFC5DDC2CCF4FD0F965C79D
+:10730000C36EA9165EF0A7648F077AC020432F4989
+:1073100071997E43797EEE2C79FE973BBF8A1E39A8
+:10732000D03635540EF4F8A1363B185E1736676F29
+:1073300048667D54C2EB365B47DE9D34EFEF563E28
+:10734000BE3A2583E57B1AE4FB12C39FB4D4D00771
+:107350006F2578F5E55723781584C2EBD63D125E8C
+:1073600095191DFFF622F8C29A088E43FD6EFF188C
+:10737000F673CF57442DEC9C791D5B1D83C0776A53
+:10738000D2E32166BD73D22DFEDBC5B5F91AFCDE52
+:107390005E53CE85E19D59AF10DE01A04B1148151B
+:1073A00090E7BDEFC727687942AC9AA35AF880D915
+:1073B0007E7E4DF57DC8BF391F29F16D258D8778FB
+:1073C00047A53A3A0DF9AE5D5B2246833F88C4205B
+:1073D0009F7BD5105D65F917EDD7B18F41D17A024A
+:1073E000E86DB181C75959FA35781EAB929E8B3C36
+:1073F000373A9BF1A381077426A32F2F57FE25AAA6
+:107400006378ED15F4BCAC959D7FC43A71FC180708
+:10741000650CED7FD31CDDF4B78AFEA37BF5CD7040
+:107420007E71A95C967E65B546EAA9E638E178D614
+:107430009A53C67865EAABB4EF76992F23F74DEBF4
+:10744000E63CC97F4990F5C01C89DFE7D3BD85AC18
+:10745000DF4C7069FB48F5DDA7EA751C6F257B00E2
+:107460007AB5C8F11E7642EFFA66AE86BC0391E5A6
+:10747000653DBA6A90C6F9F8E71BA5DE7DBE42F20B
+:10748000B3BF779FE7D325BD75A5080D71D1ABF1CB
+:10749000C58A9A6A8B1E22723AC7222FBB875EDA90
+:1074A000E4BD970B6D63F8BEC005D89058DF9A48CD
+:1074B000CEDF3A9F6EFA27BCB19057A70323E311A2
+:1074C0006FFB47FDB6DF31F0B3324AF23FD2DA79D3
+:1074D0005DA7EB33592F369F9726483CAD4CE88C7F
+:1074E0005100DFBB6C2C6F4DBC3DDD71360672E682
+:1074F000FC94CE9809667B885C3CAD75C6401EDF67
+:10750000E190E38B1827C77717DC31C3897B450BE4
+:10751000EA7FE950A87CC6C0E721991DDE0189AC4D
+:107520008F6918A729C693CCF791E23DC9A1723D96
+:10753000DA3D87FD2CE7D38359F0CF77E5477AA072
+:10754000179C76CF9906B9787A57BC07647487E29E
+:10755000395D0F3C581FC1F6DECA8E43596C1726A1
+:107560000B15FCE07C7AC79F7F8575AF8FF660BEF8
+:107570000B37FB0F81AF0CB1C97E74AE2AC7BBFFBE
+:1075800042F392FD7A0D06B5F5F243619772FC1154
+:10759000878C8FF4D413647D88D3CBF799BA5EB708
+:1075A000B15E6DC629EAF6DA0C7F898C532C795DC1
+:1075B000C62996ECCD7C4FD63959A6E71E56AFDECC
+:1075C00028E3234BE01F0991231B7614F5C77DA602
+:1075D0009AAD531F08103EA529C2073E95E6F0DE7E
+:1075E000023CFA78EFB0F8C6103DE9C3F6088E47C2
+:1075F0007EBCF78537C6D17CFF763089EF2B89803A
+:10760000CA76488B9EC87870CE907FA65FCA7EC728
+:107610009A00BA997EA99ABD1BF93E54CDAAA6A19B
+:10762000283FDE1BC9F7A28AB519C5F1D05B76C722
+:10763000B39FFEC395D2CFB0E2CDEC7D90377F36BD
+:10764000CE7BE5DF5E7904F19725E9C67D988E68EB
+:10765000CE175BD97030CD465377C5F9FF3827492F
+:10766000DE83811EBCE2E1BD6982FBEB7DFA63CD66
+:10767000F2A306797F63D5B7DEE771FEA09EB8A5B9
+:1076800082DE5FB9EAD9588C73DBCE5F8ED354F6B5
+:1076900027FD15E7DD730F6B97BC87F569583C66CE
+:1076A000C5E5E331B6B9217E98F075D80DF95B9A3E
+:1076B000E09B5321F1C0134A1FE1E5B2838A25FE06
+:1076C000B5A03D8EEF1BF983C2A9E1BC6CC2093A9B
+:1076D0000C34292AE2DEA6DEE2D704EBBD03E74A3A
+:1076E000B87E1CD79606BA59FEC48369A0934F6230
+:1076F00064DDFFD86B4BEEA6F7FD3B5464920BBFE5
+:107700005D3871EF6D7140EAC9E1F7F4B2E646F316
+:10771000FA9787DDFF12C8F2A2E79FD8659E04EEB4
+:107720008141BFFAD01E5C02FCF9B036D213E0737F
+:1077300036ECD6361BDF7B0CDCA1B03FE7C3B66767
+:1077400063B2DCCCF7980FD7FD48FA0BABE2F40735
+:10775000E7834F1C7708E4F944E79EF4F2FDBAE7AB
+:10776000D2193FCDF9FDCF1D62FA5F61E8552BEDCF
+:107770004127F061C5734F3BA1FFAEDCBF55E6E585
+:107780003CA7B467C31FB7FF9013727FF5C1FC71AC
+:10779000A1E3AC7E4EEE3B52743A67869C6B754E0D
+:1077A000C28641C4B3A7CE7D7EC54E5A4735CE852D
+:1077B000FD1BCF5F7308B92DF62ED6B7C3CF6FE58B
+:1077C0006C69C7B6E6BCC576EFAA6639FEAA9CB757
+:1077D0003664F03EF21D4AC8F94F9BEB90F9A7B30F
+:1077E000A5BF66D573D25EEEC99B5A67174D057C5F
+:1077F0007F8BEF73D5072234E4853EBCFC1B7CDF16
+:107800002B29C2A521EFECA978FF9CB9EC9797F73B
+:10781000BAA81C85324B9B5C0E7FE7E5F2959A1C5B
+:107820009EB9909B81371CCAE321FC81F8EE00CE03
+:1078300073097BFEDF205F690DF6195CF5B3118CCF
+:107840004F36D27B4855F4AE9EF4FE511A27D8E449
+:107850004632AAD85D7BF87707A8DDDB18A7033E80
+:10786000DF1632BFEC7A23AFEC966BFD6B314E32F4
+:10787000E2DDCCF8820ACEF3B3977F3B06F047BE39
+:1078800019E8C3D1F8D3DB8A891E9AE76A329F2CA4
+:10789000B7730CE09A74D8909BF693AC8F3892F53E
+:1078A00004F0FBA011270C7C29F3A85E52828FF212
+:1078B000F89AEDEBC81B3BA9E68DC639FC78AEE41F
+:1078C0000BFF71836F339F9B6ECBC6B89F394EA55C
+:1078D00033DC89EC6C83488F18389EF339A634D199
+:1078E000C14D22FD49491276AA6F122AE7870C364C
+:1078F000DA7F437880BB12939C9A28A4F9271D163F
+:107900001D9C879EBB486FE3FE24FEE1FFAED7823D
+:10791000C8A31375840F1EDC73F8E32B88770FBAA6
+:1079200053F140D6545DF86839E073FACBFD91F01D
+:10793000F76FB8D6BF6F2EAD73A0CD7B1677163715
+:1079400069C1CCFBA9FFA6FA684FA3CE224AB8FAB8
+:107950000B5128FF295EBAEBCBD824E4EB750DB5AB
+:10796000FF80FA7DE67579E0273C7DF7882313B127
+:107970002E5574C1EF2E5C53BD96FB5E7454AE71F0
+:10798000BDE344B60DEB799FF5B55CFDC8C444E397
+:107990003E98E7D2F70B45572CEE4D7ED6D51D0B02
+:1079A000BE50F8D22BEF2BA42F15BADC41E4AB0864
+:1079B00097E3F73DFE78CC7772703CFCEFCC0B0878
+:1079C000CEFD9BE4794E8EB3DAC527E64A3DE984C5
+:1079D000715E765DE6D7203F1BE7A80BAA639DE6A4
+:1079E0007D0BA1FFC24FF55FE1BE32D52EBC9419CD
+:1079F00027AE402FBF84DE46FAD8376FF49E001EB4
+:107A00007CE698C4E305E8BC6D93711F288DCF5BBD
+:107A100051D52EE8F7747E7CBEE63DB8EBFF22CF51
+:107A200073416DAC0770A5F31B79BF60FFD6B77FBC
+:107A3000A1F0F97D80F37BB89BB41815743D2DDD62
+:107A40009FFB3FE7DCBE888C7D02F0EACD3FA57A44
+:107A5000E23F927FEA8B1A96CEFCF36F80538AE85E
+:107A60007A554D075FA865BEF03F907FA6948F0DB5
+:107A7000C9F774ABBC8FBF37DFB309F99EF9C8F7FC
+:107A8000244D11ED77C5B05E4B84D1C8F735D7EAE8
+:107A90001EE0FD44234EDB755734B7F7E477DE95DF
+:107AA000D92EEF6908CE076D0AC8FCDD4E55F2618C
+:107AB000B039865BAD90797DC2E3BA86EADF56C401
+:107AC00033C8ABE881AF71FF9CE8D62BFDB7EA3E27
+:107AD000E8FFC24EF614F1717F5CDD2DB097A694DD
+:107AE000C7B35C8D6C8BF8F301E06160940E386D68
+:107AF0005A172394B85EFCE5900EF1B381B9516733
+:107B0000154291816E351801FC5B56EC0DC5BF7BAB
+:107B1000CA058F77FBAF6F78C845F51F9BFCFE65E4
+:107B20001BEF6BC70C6F0AE2C23B66F457A1C73E5E
+:107B3000FFB7471F5A0A38CC76B3DE674BFEE5AE77
+:107B40001A82F38E7CB9CF1D154359DF3DAD123C2F
+:107B5000B0EF7951729C1895C7DDB13C8AE3013BC7
+:107B6000D2E53C3BB233B83F9DDFD05D383F9F8BC1
+:107B7000F3A12F3D3F191FE85AEE36CE47BEFFD97D
+:107B8000E6C10C6F3A3FA35D6D07DCE8BC241C5FC7
+:107B9000B6311CE9BCCA9F91F193D8D078D86786DA
+:107BA000BEF719F268E3429E1BE7417A516CA87F49
+:107BB000FF72CF7F3CCEBFB23CA9B77D47BC370533
+:107BC000FA6B64DB0B39EF4B7EA1E3BC7736E6B78B
+:107BD000209F3610A36A8F8B4BCF6BE7EC270EEDFF
+:107BE000A3F6E82217F33F11D87B08F790A26D1E89
+:107BF000E6370F28FEEF3E8EF36994F65FF879764C
+:107C00001AF9E72255E28DB93ED3BE1B1238FB901C
+:107C1000603ED7391CF2D9BC7F7FDA718AE92390A4
+:107C200029E5F417069FD615D185E4F9C142F2E99A
+:107C3000C820C9E109E04B69813BA9DEB926D6A37A
+:107C40000CFC7BF892A487547A05F74E893F6D03AC
+:107C5000DDDA544F7204EB2B32FF3E4BCBABB81244
+:107C60007FDA7619FEB4EDBF2F7FFA3EF6396EBC8F
+:107C7000FF99728E9B79F93EC1C026296FCDFAC358
+:107C80004E296FCDF7CE2872BC1CD1E5807DB69011
+:107C9000E4473FDC772B97F6AB581B26470C3CAAF2
+:107CA00032F028B2ED8B5F833F2C247D11F354AD6D
+:107CB0008D380B3954B5D621F940FD546FD8FB2CC3
+:107CC0003FCDF785EFECAB77E2FD2952EE2D5CFE60
+:107CD000EF499067977DBF33351EF734CCFBEBD966
+:107CE00071BE37400F6795AE180F3D3CF1571BC76B
+:107CF000C1B2EC098F60BF758D592AD675227F00FD
+:107D0000D7AB9C3909C0F777CAA5BD77A7E67D1B1D
+:107D1000EF8BBFBC920A3DF6DD71BEF700BF7BB3AF
+:107D20002E703C70A1E81C0C397BBAE2D3C158D745
+:107D3000C2FAD758CE2E34E5ECD5E193C4F7549768
+:107D40005FE88193F25F00A7A2A184F9B9CC4FD874
+:107D5000EF945DFE1337D6752677661CD7C541773D
+:107D60005F76D999068F08929EB52E3A56C2C3DE29
+:107D7000E580BDB8B07B9C0812DF2C8AB58EEBEF96
+:107D80002E10C131BDE35E0ECFCF90FE8671C39F32
+:107D90009BF6B1595FD8B0AA007A57EFFAFD2E8C46
+:107DA0006BD77CEBFE95CE332551E5BCD914AFBF24
+:107DB000241D78FEB68DF3852E376F7383C6F33E90
+:107DC000DCA073995221F5D475D1B7709EB483703D
+:107DD00083BF4763ACC3DEDD9FF7E9E84EE432A51D
+:107DE00058FA2BD645E729D521F4EEA930E8859439
+:107DF000C5A0790ECC6FA2443027B49E60A927108D
+:107E000047467F4CF915CF9B11D6FF9AB0F14687B4
+:107E1000D5DB8D7B46D785BD5768A9A79498EB3EE7
+:107E2000C07ED741CB34C5A684C27D9D318E1C6FE8
+:107E300060F750DEEFA0EE2C2EF1B7B93FEE01F364
+:107E400012C52B3137B0DC3DAE88DA7E54C61B79C3
+:107E50006F768FC27C187F6DE370DF59F0FD71BBC8
+:107E6000BBBD19EDCDD47F9B16F29D24D161AFA689
+:107E7000E7379744B27FB9F73EB1CCAF2D43220B21
+:107E800095B3848FCB39A296CBCF1A3BC701B937B4
+:107E900068FE5B2AE00770F9F724D0117C23CAB88A
+:107EA0005F7C99EF26F5EE37D067FE399F7D8A5CBF
+:107EB0007FA07FEFFAF1E71E67EC5FF0FCDF30EEAA
+:107EC0003557552459E6AF9276B15D37E831F05514
+:107ED000A6A52ECF0741D8097D3CBFA4FE9761D649
+:107EE000BA5C7776FD3F09F8B35AB204E7D9D935C1
+:107EF000AFC8A07A2BE17F685E5D78D914467736EB
+:107F0000C33F1769C8BF7BDD43F7220F29BB74B29B
+:107F10000B725D8846032FAC787DAFBBEC8AF47D95
+:107F2000C93C768F80BFCCEE567BF192FE973DAB7D
+:107F30002AAE2FBE73B571CC755F32DE91CA38C8D8
+:107F4000B19D157DDF2FB81A7D1ECA2953112FDE72
+:107F500098A5B25F6DA8A86F015C9B7495EDD29651
+:107F6000AC752ED8A52D7AD915EF05DF6FAC7B73D4
+:107F7000834B042384580FBE1311B28F29F6F8E205
+:107F8000029E87EF856E043C69DC36EF1DCCDFB4C2
+:107F9000C1AAE1377B3FF75016C15B6F7385FA6D5D
+:107FA000C3F771D1EE8B0B6DBF37553594BDB75705
+:107FB000C2EFD6A2AB6C875CC445CD78B9CF16E0D2
+:107FC0000BD931117DE4AD6893AC708DF144F5CEE1
+:107FD00047FF73262658DA5B0D7C200690DCD779A4
+:107FE000F6F2A92BC35F898D64FDFA070F09838F11
+:107FF000F80FDF46F5E1E323586F996A5BCBFEEE9D
+:108000001FBC6D33DA65DEA2C7A0CB1F64796AB0EE
+:10801000CFE14FCB7B3F3FD82F6CB741AF4BB689F9
+:10802000B8649CA7BC879363D0B9B9BE51FBC5D9CE
+:108030000892C7A3824ECB3EA76A1196FA7011D25E
+:10804000CEF861ADFFA3F7C5FFB5C2B8777AADB87A
+:1080500016FB7F222C9F71A899CFD85EC0EB2DFA1A
+:108060005650453E7FF8FD0F934E9F687029783F2C
+:10807000377897AA8FC47DC15A15F7248689DAC349
+:108080009CBFB84BC87BA0C678BADB2F6027ECDF5B
+:108090009DB10F7195EF741C8E52DDF08FFC226A3A
+:1080A000043DFFCEDB99A35B45081F684FB4F0D5B4
+:1080B000EF02CF91EFD521E9E1BBBBE57DADEFDA72
+:1080C000DBA242E34EE17860D6AF794CB5C077B31E
+:1080D00090E7F26A85CF350FF234D0A1029F7AE0A3
+:1080E000E029B39C5BCC3CE95F8AAE1366BE4121BC
+:1080F000ECEB66B7A4DF6683AE2E771EEB0D3A6D10
+:1081000032E8D455E14FC6BCF6127FA3928EEB390C
+:108110003E85FD3EC67D66FEF411C1AFC829985F5D
+:1081200036258976E4374D89FD5110F7999B09CFA3
+:10813000E02F34F1B829DBC0635B25B75F243C86B0
+:10814000FEE908940BF8359BFCEE5AF67FE5CABCB5
+:10815000570417A0BF35BB494A5E018F22C3F266A0
+:1081600093CAED96FBD18EABDC772E9867C5BB9E8C
+:10817000EF0D7AAEFCBDC19948581C7B757DF22687
+:10818000ECB98F71CE347819CEE1FAE41F57F86F4D
+:1081900000DC17764F63FDD1DF5DCC7AC7C618F9D6
+:1081A0003D9EE3F0A770BE938C874FF7C8FC9841C3
+:1081B00022C0F558AFCCBF18047F35F5D796C9FA61
+:1081C00074977C3F7996CC139D6EE4C725FB35AE42
+:1081D0001FBDCD3F771EE3F5B33CCEA3DF92E34E48
+:1081E000CF55787D9027BE91973F87B306FE9F318C
+:1081F000F0E76C7A4725E2CC9D4D3FB52F0AC1BB15
+:108200005B0D3C9DEE8A95F1A29CB157D14F0C7A43
+:10821000CB49627CC7FD7177425FFD028CF7A63EB9
+:108220004574F3CFBC1FF18C856EC2DFD3EB0A6FB0
+:1082300047BFADD13F51BC80E74AE1019E3E18FDEA
+:10824000932380CF9991113AE8E7CC3DF27B837973
+:108250006364DC5D17328E9F3E5EC6690F8D7CE1E4
+:10826000541DFC862F3B598EF5E2054967825FA7B6
+:10827000F1FE01383A09AE875E9CC77A7BF93D3240
+:108280005E7F7CEDF9A7BE07BAF0DB4C16CEF7EAAD
+:1082900074292A445E600DE7BBE57911CBA6F10E87
+:1082A00006787E7F1111CA20926B0D390C77E1722E
+:1082B000B9EC2179D2BF0834B15FE638FD1BFB72FF
+:1082C00075E7315EAD8B7E84DF8F24FCB0C9FB4D3A
+:1082D000AAE8CF79C242FA2B247E5CB358EE2FB2C3
+:1082E0003B97DF1B31C873CD844CC697DDC0D3F4F8
+:1082F00091B69F8DD6E14C128C2745B11358EE4CA8
+:108300005FABE8D021A7AC558E26C05E0BC4F1F759
+:10831000488A12BA1CC9B21D9AB658987BF630EF3B
+:10832000E320BE682A44716006EB1DC70DB8247BAC
+:108330003A39BE97ACC97D1F1F2EEB9D83E9C4E37C
+:1083400043ED2E09E7E36B8BD4FA4496EF3E0843E6
+:10835000930F9E09483999EC95E7965C22BF759575
+:108360006A37E86099CCF7DC6EE0710BF07818BFE3
+:10837000C7FCEB628BCA7E348C877C3873BCE337D6
+:108380009F48C8D0A1FF07347C5F2EF0B29DFD440A
+:108390003B0C7EBABD679C99531C18C7274534C651
+:1083A000B187ACAB5FA9CEDF114BAA95F71F933114
+:1083B00019D67587CCCF7D226C5D2F1A7AD499C0DF
+:1083C000762FDEBB582E382FEABA8F05AFB7DFDA2B
+:1083D000088E933FB1EB7054A81C6E31C679D1A0C2
+:1083E000D30E639CBC8FBBBE1D4BEFD91B69E2490A
+:1083F000D84F5BED61EC6781FC5EC2BDD91B54F8C0
+:10840000819E52440730F4C54F64FD7BB88043F52C
+:10841000BC1F6FE67A7D81E078D9DCB5DF7144510D
+:108420003D7F5DA44E9BA13F39FE99465D613F9320
+:10843000687F3509FA883B523C4EFDEF35FC8F9141
+:1084400086FF71C4A7079F3A40CDF73ABA7E0DBFA9
+:1084500057604D0CC3F58CA3AD7C11D52B7F9AECE6
+:10846000218A174F0D7D6A11F02865BED4738F2BBA
+:108470007DFB8594F9D2CF719DCDC8D3171D6EC0F9
+:10848000EDB808FC08EB319FCFCBB59D75C4727B6E
+:108490006A7988FE769DAD2315FB134D91C343F396
+:1084A000B5E6E5BEF74DF82FD01FEDC795D6C856F7
+:1084B0004BFB6B77211FEC3D1016E9B1D1F337AFC1
+:1084C0000AA40A91B5EC25961307F2665E512E9B1D
+:1084D000E765D6EFCDDA9704396C8E479AC2AA20A9
+:1084E0009DD717BFFEC201BFF1E781481DF1EE85A0
+:1084F000EEAE57D93F1F5074F8E78A027F74745A62
+:10850000F0E0E0EEE290FC0497DEC678343D77EFD1
+:10851000B5A176D342E2FFC8CB98177893F7396FAD
+:10852000D994D1F06F037F1DD8EF5A89BFA3623B66
+:108530004E5C8BF9DEB571DC3D6F98952E75F1DCE4
+:1085400021BE2F345B7EBF345C6E5C82D70DC95C6C
+:10855000CF3E92FB08D3F3634E8E0B0CDFF4EDA7F6
+:108560000EA26C5DBE6211CD336CE8DA79F08B9FA0
+:1085700033C6891C9A7C1A79C24337C5F0BD8EC8B0
+:1085800040F5C045D43FCB7D9FBE0EFED35D2E1E71
+:10859000E778A0C903FCFE7CB79BE971718BCDA283
+:1085A000C71F78B135077EE18BBB077A008F856BDB
+:1085B000E5F7B3B05EDCF73943EB4439677E86C537
+:1085C000BE3A73CF9DD9A0B7730D2777414F782F4F
+:1085D000AA93F9FAF17765DE469E786633F85F9ED6
+:1085E00048EEC077558FE7DE2EF398A70AC526F32D
+:1085F0007FF8FEC8B906EDA123743EBEB0F1735AF0
+:10860000DEF4E21CB0547F02E0DA9C7025BB31A797
+:108610004509029F735A0E7911CFA816FEC054E087
+:10862000718D83FDBBB5F375C35FD371047953A717
+:10863000D6A5F1F717A6E71E1A09B95DDD738F48B5
+:108640009CE67655E3F679818D87517FF985A119EE
+:108650002AD1F73283BE463985BF2FFA5B325FCA13
+:10866000FDF7A23A56422FC811B5BC6F51AC299BF9
+:10867000A17F8B235F07BFCB59335881FE6DBE4767
+:1086800072C2A98C92EBE1BC3E5BF022BFD7A0087E
+:10869000C4770A498E202FEF83A5317B212F444DCB
+:1086A0001BE7C3D51AEBA98C30EE0DF8DBC6C21E52
+:1086B000566EF3AE994FEB3810E6AF3B56375FCAB4
+:1086C0001D831F9F093C7B02DF87FBBCC6C67CD590
+:1086D000F4A37C50F8F4097C2F6CFE2A1B7FFFEF7B
+:1086E00083B40E3BF436F8F1BCD07B088F5176068C
+:1086F0006C49324EDACEFBB6E5A6DF371E72AED439
+:10870000E1B941C7FD8AAE3FBC40E3BCB73CD213E0
+:10871000A0FA36E31C1067677F88EE63FB71BD2209
+:10872000F87B6681776C1E237EE18A1E27FD99F80F
+:10873000F33E26E33CAE548DF3AD700D19F0B12736
+:108740006AFC3D69535FDD3ADFCCC3F26EC5FED7EC
+:108750003B7CC9F01F5C4DAFDB1066176C88F4944E
+:10876000FBFA38DFA66B229785E6F7FFC038EF1FCC
+:10877000CC37EE596882BFFFE474AB9C2780EF765C
+:1087800085D25BF87876B7D5CEFE47EDC90DF38D6F
+:10879000FB71865EBFA2C2F7F4FC24E80B37321DE2
+:1087A00037197242E48EB6E89FCF1B7032ED28571E
+:1087B00085EF20E0258ABDB8F14E7ABF717F35374D
+:1087C00081F5CC107DF3658C2F3A9F5601CFCBE914
+:1087D0009BD1758587E6CB715FC1B8766F3B1FA6CD
+:1087E000A9A76C1B2FEDB5ECD2BC7B33A97EFFDBB8
+:1087F000320FE06AE763F2CF4D865F779BC13F8B14
+:108800009C7A24CE6BDBA42BFBA99AC3E48CDDAE4F
+:1088100029C8178B7769531097252D53DACB765FCC
+:10882000E08B027C2F64F413C0B77ED777E4CCA131
+:1088300071CB2AE57D1147B1D58E2D2A2C2B849E34
+:10884000BBF56D1BEB4FFDAE170AE7BD18F9909C09
+:10885000A568EB9D774BD83A62EC2705E82BB6C0AC
+:108860003AAE2E4EBA42F9DED60269DFBE967CE100
+:1088700095AF086EF10582E1A81577D12042DC376B
+:10888000C97F127C5C0B7E1984DEA591F2003F400B
+:10889000F4F51D2EB8FCB402A1C03F009515F4B448
+:1088A0006512C9297A3FAEB8CD8BE7AF959CE3FB43
+:1088B000DD5B93ED2AC6DD5090706316F4921C9533
+:1088C000BF2BE130FC39BC1E6A3F51B2A8259DDAAE
+:1088D000B725AA1EE4654655F663F86C2BB970AC53
+:1088E000AD007941714B6D217AC2FDC9761194F9C1
+:1088F00040EC57BB1FF4C1F54EAEF7AB94F943F70C
+:1089000095BC559245EF3986F365559AB593E1B01C
+:1089100061BCF437D8D77A835FD1F86DE31739C1DA
+:108920009F8E8E7FCBF511BF2FCF674BF13EF6ABFD
+:108930001DF7264422DF736B499986F17BF5683D6C
+:1089400012ED0EE1623D7BAB57E53CD36DC5850270
+:10895000F8781F2972D060EFF31606B1FF8B5E170F
+:10896000D71DFE72B119F85AAC727CB828A5E03751
+:10897000E8BFC56D47DAB0682DAE0B22DE735F9697
+:10898000D47F1DB956FA8FD2ACF4EE4AB5FAD56C45
+:1089900053F679330BA4DFCE7072F1776C7AFD1049
+:1089A000EDDCDE36C5D5B58EFD0E3F1235A0A71421
+:1089B000E98708F7B74508995F703159F07A710374
+:1089C00014EBB51BDF95B397C8EFD7D80D3F5954BB
+:1089D000AED51FE6CAB2D69DF07F85F819EC61FED0
+:1089E000B0ABF15993FE36187CB699F45C234F9BDB
+:1089F000E3311B6C5ABECC0F16C16CAC3321752F02
+:108A0000CEA5AC52F257C0F86048BEFE8EDBFC65C6
+:108A100095A047CD0AE788642B9C67567867A2DF4C
+:108A2000DF1B27B85A5EE1179169ED805BAFFEA7A7
+:108A3000C702BFCE197EF5CF4FC9EFD59BF985E1AF
+:108A4000F354D567EE2E0E890B9F5E20F381C3FB96
+:108A5000BD7D5BE10AACDBFC2ED223F5F612F4DB24
+:108A6000E193E5370CB8849743FE1217053EEB6F90
+:108A700051BC88172C0A28D3BC7DF0E9B5958AE152
+:108A8000A7154F3AFAF7CADBEA38FFDACAB1A17282
+:108A900057E28FDDED633BFDC1E8476E1E073D9356
+:108AA000E435E85EB8DC3988832E35DEFFA066B198
+:108AB00013FAEC85BFC409F8BFB646E755F1F709CC
+:108AC00004F18944F493781465E0CD0735B6A38C9E
+:108AD000A781085DC6E3A4DF67A92EEDF2A5811783
+:108AE000B87E7A22E1FC048C771FFB79FC5EF91DCD
+:108AF000E8A5617849E3B9D8FFBD4B613BD3EFF6F8
+:108B00006F805CEE4CB7D7AE633A714AE5D2A09362
+:108B1000A58107A5DFE836A1392758C65310A7BBA2
+:108B2000586393F7E6F16E7F639FE9F27D6F7FC430
+:108B30008DE59FDFDEB51E78938AFBD5E3FB5A9760
+:108B4000F43B5DF41ABF8790A308C0ED5683BE8541
+:108B500057E8B8FFAD98F597B400E7E51B79882290
+:108B6000745D9996BAE15FB7D61706222C74716AC4
+:108B700072DB1BD71BE7063FE6AD011997BE940ECB
+:108B8000ACE3A8BAEF8A742D7687F8CD337AFB8BE5
+:108B9000B607BD886B9BFB0B9F2FFCBD3FAEF01E45
+:108BA00003BE1FBDCD77BC92F152DEB7F2FB850745
+:108BB0007EBAEC23A5CCAF2F362BCCAFAB5DEE004D
+:108BC000C7E59BADDF9535C73F6FE80DA70DBDE14C
+:108BD0007CBAA8F2B11E1BE70CF5D77D58A918DFA7
+:108BE000D190FEBAF3F7453B43E3BD93574EF910DE
+:108BF000EB5A8C1B2009B8E767B5A3C2E3EF66BE4A
+:108C0000F6E9B5D2BF4325D3D145B7BCE77F35FEE2
+:108C100042E8C379CB76235FB2C8659D6FAA166D13
+:108C2000E16F3724F7B3D46FD40759FA4FCFC9B4E3
+:108C3000B467B5497FF545E253AD9C47E3E3C53BD7
+:108C4000452DC73F5DA28DCBC306FC8E18FC3A4A6A
+:108C500074F073B738C9E505F727EC478B03CA668C
+:108C6000E20A8ECEF938FD8497EB36D7CC87EC63D9
+:108C7000005ABFCC5BA369D9DFB840B437C2DF6804
+:108C8000E6BB55CB3CB6147CBDD7C6F7ECF8FDC1AE
+:108C9000A293EB43C0756C20399DCB4C21BFC7A775
+:108CA000D72DD516203E8A0C7D7A7E3AF2FBA7B0EE
+:108CB0009EC2F9FA730ED04B60EBEA1344878573BA
+:108CC000F53F21D6BF2762D3EA23A4C71646C8784A
+:108CD000DBE85F3F7C2040E7BC729E77C002C6B7EE
+:108CE000AE05584F35F129E455895A6D03BE0BDEA8
+:108CF000E4714AFA0BA3CF6A576AF04EEE17EB897C
+:108D0000187F291E6EB7FB26627DE225B274881E8D
+:108D1000BACA691EAA0F582018DFAEE657BF1CBD9D
+:108D20009D6918DFA75F7DC0029DF9F9C2EEC98673
+:108D30005F7D12FBD5AF9BE71D83FD0D5820F5AB82
+:108D40009F39DA5335F60F898F6DE32C7C9FE170E4
+:108D500039BE0FFD1DFACD995CC37E34D669E2BBE6
+:108D6000F93C7CBD57C35F118ABFEC971D68D16386
+:108D7000AE068F703C3D6AD807C70CFBE06746FE25
+:108D8000470FDFF94FFE2E46F8FE4FCFEE7A03F67F
+:108D9000F3E9776CA25107FEF5ED97BBDAFAC657F7
+:108DA0004CBB55E29FF5F7367AE83459F23BF33B7A
+:108DB000EDC458EDA17641F8F8E1F3DF143BFC1760
+:108DC0006DFAE5F769D2A9596F8AF4267BDC40E792
+:108DD000BEF7135D37ED9E05D2CE3CFC5CE2DF1F93
+:108DE0007FDB00FF7DC839387BEE0B910248E31C26
+:108DF0004DC9DC1BEA17092F8F2AFA1D7642E1873D
+:108E00007E7DEC00BECF5488040DFE5EC61BAB61B8
+:108E1000BF141631EA88077FFDF3030137C7F776E1
+:108E200002AEF45CFA478A05FF5E8A5DD3D98F40B3
+:108E30007AE10368DF6EF73E8AFDBC385FD61F30EB
+:108E4000E8B329ACEE9867AD4382A956BDE9812B02
+:108E5000D14FF8F96E6BD0B7FF269BCEF949B78C8E
+:108E60002F9E92E76CE64F9AFBEE97E639AB87F8B8
+:108E70001DFB65D48EF230DFA8BD36F43E8E993FDF
+:108E8000915022BF1372C9393B3D9DF0FFD49F8A98
+:108E9000F0C09FBCDFE13F887D2BB1F5C36027F5B3
+:108EA0002BF5F07DB584220FFB4D9A22E57726C283
+:108EB000C7F9E9029BBCEFB4C0FB13E66F86DE9CEA
+:108EC00030BD34D84CFB584F1C11FE716F7940F403
+:108ED000E5B77324D61ADF31F11FC3FB76CDC7F394
+:108EE000DADC72DDE678F883FEE032F8ADF0A50B4F
+:108EF000F89FD7BF2DEF05AED7B6097C67A02555E3
+:108F0000E5EFF29C9ADC510E7A59AFA81EF84109A0
+:108F1000ABF4C4FEBDFC7A94530B2E32F4A9C709FE
+:108F20008F0A635BBCC847DAE47579D87ED29D614D
+:108F30007C48E6F799F36F7467F1FC2D343FE6DB6C
+:108F4000E4B607A313E1CF72B1DD9FE7EE3886FBED
+:108F50004B796E3BFB7F4ED57D6F38F2385D894E85
+:108F6000D67B2E19BF4AEADFD9818F9F398E7D7556
+:108F70002AECB73DF062EB6CD8D55FBC6163DCB224
+:108F800095919C603BB996EDE48DEE82D8507EB809
+:108F9000CDF0CB99F5A75DFE8BC043DB4D9E93C012
+:108FA000F78452B9FE7E252A6DA897EF6E1AAE3966
+:108FB00031C1A698631C2FDA1229BF5B505DF03CCB
+:108FC000EBA99B97D018C88F223908FD99F624E3A6
+:108FD000D761722E5CFFB9BEEBB3678E27F6EEC782
+:108FE000D6DFB4F3E5FAB303078F617FEBC96E8672
+:108FF0007D529E74EEA9EFB1DD247F75EBD2FD1E8C
+:1090000019093FE2F96551DC7E857D2756FD17EE93
+:10901000DBE694BF7B4374A6877E17647895D42FD4
+:109020005F5FE0CDAA025EE3326ECAE5F99C89FF7C
+:109030003F1B2CEF0F6CBA2B9AF30E36C1364EE461
+:10904000EF7BB73FDE879C2DA8927EBD27FFD99B83
+:109050000F384CACD20D3AD2F8BB28D5F5C7DF4754
+:109060005C635352DF74ED35DE5F5AEB9D50D5C71C
+:109070007B97D3B7C3F9DA076FB5A7E23B068FFA40
+:109080009C3AEE378EDA72C1067FD5C65249A71BCD
+:109090003BEA8E217F33906AE7EF6BEDEF38C7FA3A
+:1090A0004344A487EDA21D8DFE07700F343058FE97
+:1090B0007E45C4CD657C5F798BAE7854AA3FBA7982
+:1090C000DBB481C02F8FC2DF7398B230C1FCFE7A4F
+:1090D00009FC1B6FA466719EDCA1820C05F1A0E562
+:1090E00025F23BE6CB1F93DF752A4D1DFD04ECCC2A
+:1090F000D3A9876DF85ED69FB2FCE3048F23F95A9B
+:10910000B6BF9BFD6B7B0A04F399F7D796CDC57C60
+:109110009F973835F43B94B86D1AE2A33B370B1D8B
+:10912000F6EFA105736F1C083E3256651FC5A4CD2E
+:10913000278B705F6C922E3C605BF66E9BF0921EEC
+:1091400066EB56B8B4DB651CB41FF111C0079F83F2
+:109150000BC5CF05A51D47A88BD816D3F13EE6D980
+:109160007E8F53E0FCB7943EC0FC6ECB66D5FC5EB0
+:1091700018F327BBC19FB6E827F9BBFC1BFF443699
+:1091800032B56F07E3031C47CAFBE48FA6AA1C276E
+:109190006FCE75EE93FCB2733AF6F5E897AA0679AE
+:1091A000B067E41359C8B7DA393CD2CBE3FBB6DA7F
+:1091B00031DE1EDC4BA27359BE634A7019D54B8851
+:1091C0005FB27F4ABB845F32BF36D7B367D650E603
+:1091D00097CD06BF34F36A6E33DA0F386B8FE2FB3C
+:1091E000407B9E563CEB0028D171F4561A7F157EC9
+:1091F000DF01FEA9CDEF6EB896DAB54257972DF98B
+:10920000D2F9BED6A58A4008DCAEEF8E1281103DA1
+:10921000730A5922A1F522D7204BFFA95AA6A5FD12
+:1092200086E41196F61BF53196FA829C89963A09E6
+:1092300050CEE3F1D27F584FE38B510CEF9DDF9678
+:1092400079B1ABC2BE6FB7AC7DCDB425F06B1879E8
+:10925000414B3BACBF73B0FDE66FF077F7B6E1BBB7
+:109260007B9E4BBF1FFDFD2AABBF3F2249EA193B46
+:10927000939D8C0FEF2DB87301F244370C74735C1F
+:10928000B06299FF39F081E6D4E21CE81F3B359FBC
+:10929000E691FA5672D6B89E1466FEB3F7EFBD2F6C
+:1092A0002244FB21DC274AC3B97328C029BC217E94
+:1092B0008CED377FD488F60D8AE8B2197E09E02F4D
+:1092C000441CD63570FFA78D4F25F2B9D546705C8A
+:1092D000BCE3FDAF53BDFF5AF93DAF4F5267B9B084
+:1092E000CE474B550D795703EB43C6A7FFD952170D
+:1092F000376E829C2638C4915DB57DF3E8C06C2939
+:10930000A7A55FB45CF6A7295D807B4476470BFC7C
+:10931000B49189765EBE6D4784859EF0500FA1138F
+:1093200073BFBC7F560E7C47A7D0FA120282E310AF
+:10933000D86F2064BF7BEEF9F343AA15AE67C01F58
+:109340009B37172E83BD99A0070222B717AE307343
+:10935000F13CD2808B398E37C3CF7EF77EE6EFF5B6
+:1093600019EDE30CB86D50FCEF436E0566CB384445
+:10937000385CECB344209A806C2F775AF6670B5810
+:10938000FB5DAC8AB7E84F1C7F48EF9D4F18F3395F
+:10939000FD4FFAB09E4767A9027AAA236CBDF80B6D
+:1093A00098F44CED07EEBB70087EF74D25324F2444
+:1093B0007CBC5772E57DAA665DC625C2DB09CEF787
+:1093C000E29C1CC9765D7E67CEDAEEB2FB02F07BD2
+:1093D00098FEB3DC94DFCCE33828F13FDC8777E8F4
+:1093E000D67DEE8991792EDB6F94BFBFB680F843AE
+:1093F000287DE6953E207FAF6D19C9777C077C619B
+:1094000006F3F70C677009DECBA88B14F043ECA4CD
+:10941000FDE37CA3D644CADFA7159E87A2A99EA11F
+:10942000C608F801B63BF49436A29B5FDCF8D1BACB
+:109430001AF483BF9DF0B0FE60ED1EE87F42213C30
+:10944000BF4EEA7BA17A779EB32B0576F69E057F09
+:10945000FD007C2DF02317CBBB51463EA178D1B542
+:10946000177C7963EA5BAE6AD68BEA39CEB1A53D4B
+:10947000F00EE4E3F91336680297D513FAD07F0AA9
+:1094800016D2FE125C278F21FE03FD07EF87EB3F0C
+:10949000BAF0F27DEC1E3F47989E5CED3A21BF8307
+:1094A000E4121A7EDF2C5CDE2BBEE7D95FBAFB56D6
+:1094B000A92735D58ACE689C6F983EF49B65528F5C
+:1094C000B0AD768820DB2BED1C97A9887319751F2A
+:1094D000D74D3C0DD7F321378097CD89563D7F94EA
+:1094E00033F807C84591E0E4BC8FC2D88F597F5844
+:1094F0002FA43FF8545D7410E7F7B09AC3BFB3E5EB
+:10950000D29C7C5FF1AAFA7D4E8645BF5F9F738E29
+:10951000F5D8D64EFC5A01F4F2BB8784FA0D2F37EA
+:109520006EF839B538C441C4F71B16A64BBA0C8384
+:10953000B7A21FFD12E364075AF8FCCBD347B3BFB1
+:10954000235C0F6E4D1D7D35BDFF8E8580F74DED83
+:10955000C7AEA4FF361BFA6FB3A1FFB642FFCDC75B
+:10956000F71CE4B9FE9FD7FB0372FDBAD4F35BA1ED
+:10957000E7EB38A7F99C97FE7086CAE7F4BFB1EF16
+:10958000EDFF95FBCE50838F231F47FC2A82F335D6
+:10959000EC38D80988C3FCD4853C9721D592EFB428
+:1095A000E696454E91F12E4525FE1635F21917FC2B
+:1095B000163B73558EE7E48E2C7B1DF6E3A6DCB2DA
+:1095C0004445EFDDDFA659CFB05DB9735659810828
+:1095D00079BED3F8FD96707CCBAA9676E58BCBFC52
+:1095E000CF032E9BB2A45D4AE825F32B74C9373311
+:1095F0006EF272FE6BE5CFFC43AEF49D1873BD9B1B
+:109600001249DF8DC3FA162585F2B97969FE9DB33B
+:1096100069BC1D2385A75147E94D5942F088488D03
+:10962000F094503D3B38FE0F90F73B7D52FEBF76E5
+:10963000E8C60AC4F7A289BF45523DDAB8CF1CD1AB
+:109640002DFDC27306CB7A529768C73DF31B66495E
+:109650007E99982AE5CA6F1B647E12EE038C1DD793
+:10966000FBBB8E89BBCF36213FEB56D213747CDB1C
+:10967000F2C5BB05F4F29D7B153100F4EB0C1641ED
+:10968000FFDA3821425BE7C1A722261DA9A67AF29C
+:1096900020E2E7F0DFBAADDF335EB6DBAA9F4D0E06
+:1096A000D3C72685E55D9F5D68E867E3C438C833A6
+:1096B000F3FB38A2ED41DF5FC7E1774204238DF968
+:1096C0009D9C70388FAC2BFC18FCFB74FD982BE62E
+:1096D0008198DF4537BFABFEB36F4F49415C6347AD
+:1096E000A3B4EBFED1EFAC2FAD9F2E108F5C5E7F4D
+:1096F000A32826E56449FD4CAE972C92F1C40FDEF9
+:10970000EAB241EEEF98A5B2BD326A46616436F422
+:10971000804495BF1FB5A943E2A769CFFD2F7DD92E
+:1097200057250080000000001F8B0800000000008B
+:10973000000BDD7D0B5C14579AEFA9EAEEEA6E6828
+:10974000A07806086A21302113C456D1681EA6C02D
+:1097500047D03099D6A083B91A9B87808A064D32AC
+:109760006BB2B816823C1412A28D41AFABAD4876F5
+:109770003633E3258FC9FB664167DD3C1DF2B81324
+:109780009D710D4A2471EECC0EC6987176DD5FEEA8
+:10979000F77DA70ABA0B50636666F70EF925955355
+:1097A000E7D4797EE7FBFEDFE39CFE49E71991C52C
+:1097B000306677BA99651263B9BE754D4B18A41718
+:1097C000E5385517632B3DA2EA87A7C2BA2C115979
+:1097D0008CF952BDD3B642FE29CF07B330FDA5E2C6
+:1097E0009D0649965B64612C96B1BB2E2FFF4122EA
+:1097F000D4179B21C9586E657EE771AC3F26435252
+:109800004481B13B3C9DC78B207D47BCE45614C6C8
+:10981000D2BCC72D0CEBFD92B1DDC98C6D135AE69D
+:1098200026405A4B1658077C7FDC73205586F2176A
+:10983000D29D2A83EFDF3808FF81F41BA916BF00F1
+:10984000FFFB35FEDD35F44CBC64616A346371970F
+:1098500004A64E81B4D523C8D0FFB87C91A9E98C69
+:10986000FEBE867FEFC9EF996383F6B7C81EA71BBC
+:10987000F25B0F2E70327C662C76B20CC66C8B9E1F
+:109880008B67E319AB816AB07FDA04E94007F44FD4
+:1098900054DC9E34485F74A50A38BE6DCBEE4EC0D2
+:1098A000EF66799369FCBE05737789D0BFBA4C899E
+:1098B00059A07FDB26BC189F0CE5A56851B028D4C1
+:1098C000BCEA80194BC4FF83F4C9992DEC51C8DF61
+:1098D000B640F46F862A7CF9079C0AD4C73C0B9CDF
+:1098E0009EB011C697219D16C221BF5C625D0E7DA0
+:1098F0003CE3F9D3113754AFA8781ABBA11F17CB9B
+:10990000455A07733D57ABEFCE019169461AFEBD2C
+:10991000EB5208D302E62F9B4507A567396E0C2A48
+:109920003F474E09CABF3BFE96A07CA6A91FA4C311
+:109930003CACD6FB3B4F9912947F48AA3C8A74D02A
+:10994000FAACE0DE0CF9CBD26F0FFE9E75CE5D0156
+:10995000E35B136F615BDD90FC89ED4C2FE4ABF0B2
+:109960000FF6BFFAD55FD5DD0AF9DBB21D0376C865
+:109970002FF5AF93703DD7302B95A37A60BECB32D5
+:10998000FA4FB24CC8EF84EF03FA5BC69ACE5BC2C3
+:10999000F1195CBEDC1B16D31F0A895BD9AD5F5B76
+:1099A000F06D0CCD7B0C2FC24E94CCAADE8FF4CA86
+:1099B00058A545A6E5AE7E07F7C3E508EA67ECC102
+:1099C00059D5B82E728EA332623A96BFAFBA1BC673
+:1099D000F9059687FC987C29884EEB046A82690B0E
+:1099E000981FE9EFD715B3B2B371DF31D643E55F06
+:1099F000EFFF4F168E45E0BB807E02C53166D483F3
+:109A0000FD3C681FCA877970A406B7437FB01E5417
+:109A100044E44905C6E5D4B39C31B51A8E0B2AA19E
+:109A20007E3B1C4D3D96CCABD493C2AB8931EA81D1
+:109A3000769D07ABD517B3F8FB85F1588E7F0F5392
+:109A4000D5F5358E35958F03B28E623FC717C2CBE1
+:109A5000A9BC5A396EA85E47BCA43A3387BE1F1C06
+:109A600037CEB9514E18CAB7EAF54F7CE365E685A3
+:109A7000FD7D535B70BF435D4CED84F7A15678BA12
+:109A800086F6C7BD45BCFD654522EDEF8F43D4CDBD
+:109A900047A1FFF50B45FF01C83AB4706104F28B92
+:109AA000D1F657FF2668F8A6A17459B94DB343BF44
+:109AB0006FDE13B01EF0EF0B5E81EA4FDF2305BDB2
+:109AC00087BFF8D4693A7DE9FBDC1AA74FAD82FF66
+:109AD000711FFE2E64A6313680F465A60375BC673F
+:109AE00033E6C7EAF94CCFCF34E8425FE7B1FAD2A8
+:109AF000A5FCE4FECDCF6471FAB4C7E31B6F810D02
+:109B0000D2E332987B2BB497E20BEE5F5CD285EA0E
+:109B10006DD839AF8BE8A24EE8ED16915F0AACF232
+:109B200067D0DED8AAE0798E2BB09DB603BDC6F90A
+:109B3000EC41EF7FE98DA44EE29F2360FD58E07871
+:109B4000A0BF92F7F3FB71327C1912DB2AF0F79A6F
+:109B5000415FC9B81EB04EC837CA991FBF3F92FFB8
+:109B600045F7D7906EF4887EBB309C5EB6018FA51A
+:109B7000F24B18F15F737B21367F36B6B7AD92B9E1
+:109B800035F7F0FC6D9EA2EA5EC89760BC5123E4F5
+:109B90006724BC40DFB379B04630C4B8F2E0F95B6B
+:109BA00006F41EC82733F37766637F58399385041C
+:109BB000C6A61471B9325EEA5A81F58C5FEF64D59E
+:109BC000D8EF8C0332D271A6D4198FF26DDBB2FFBD
+:109BD0004D72557BC5E1065A40B9C5F9C62B8EFDBD
+:109BE0001DB42FA0D219A3D329704CA2F334ADC059
+:109BF00083FCC59721BA516E4C94B4D834ECFF3134
+:109C00000BEB80F5B745F63E87FCCC765A706B0CB3
+:109C1000FB71E6991F63FA5F6F7023399D5CFFE368
+:109C20009BB15FDB81EE553BBC5FE00E9721FDAC45
+:109C3000C31B5508F547593D3D56A83F2A0FFA0664
+:109C4000E5A373C5A0F948659505D8EF4206EDE395
+:109C50003CA82AF10F41A7F742C7BB7C3E1D4CB67A
+:109C6000C3FCB05ADB6F07F936EC0F21E94501F36D
+:109C7000F794316681FC9A4AD61B8A1DEB4D8A44C3
+:109C8000BE8DFF8BE37D63B942F3DA1AC3147B0404
+:109C90003CF38B62B1DF6D5E59E7371A43F96B9184
+:109CA0009817F902B37652BB35F36461EB244CC3C9
+:109CB0007A64E17A24446E85F97D7639E70FE1A272
+:109CC000DA68C1FE89ACB703E9D473E0AC00CFC554
+:109CD0008BA404C4033ECF42B109F150D2F67FB445
+:109CE00024633F1CBC1F0B1486FB26F4238B3F17F9
+:109CF000CAB576CFF81DE288588FC49CD055DF983E
+:109D000085D4FE850CE070F0DDE2099007E5EDF901
+:109D1000A25F84F4DD499C8E633298DF0EE9131F45
+:109D2000F48A98AE87EA35A0BBCF703D800FD52767
+:109D30001DF8F92CA8670BF003944F317BF6D7621E
+:109D4000B9B2E94C56A05CA89FE3AB7217F3AB50D5
+:109D5000CFC4315FBC9982F47F50700BD08F6D9D62
+:109D60000BC53AA4AB24D19F06F9C793167E9C92EB
+:109D700085FD9248DA3D11F3C57B2877EB93403A95
+:109D800041F9B02CC07F90EF00FC47784800FC8779
+:109D9000FC21417223BE1B8ED75401E925CE134C02
+:109DA00017F7787A6C88D7EA6595F09A2FE3870ED3
+:109DB000C45DB631390928AFCA7A394E2BF348074A
+:109DC000FCB48F83715639534F3C82E302BED105F8
+:109DD000AF9C2D2FB5E1FCFAE25D0CD76FDB84B9A7
+:109DE0006F214EAB5B25CA88D30E495DBFB3E03E01
+:109DF000182329C81786E1A6A4EBC361807B7E994E
+:109E00001EA7B33A24414F691E32E3ABD69BCF71F4
+:109E10008803FEE1F8E6B1F8DE0CC445C1B8C5928E
+:109E2000047806BE2FDF637A8F7826139FD6A1F7BA
+:109E300030AECD857F2578C6FDFF079E995B240C4B
+:109E4000CAB93F0D9E291046C233B13A9E8935E109
+:109E500019AF8E6776229E99FAE7C333C70AAF0D12
+:109E6000CF0C5FE72BE31B03CFC4605AE674F10D00
+:109E7000F14CBC0D3E1E973F0A9EA91A8667B26D33
+:109E8000D782674CEB3650F80DF14CD29F06CFD4F9
+:109E90005F239EA91F05CFD4FF99F1CC83A3E0993E
+:109EA000FAA4859E6C48872C102723FF4DD33E2FA4
+:109EB000A271E0BC407EC1A2F5C70B910FBDEC20A2
+:109EC000B952BF6C998C725503024FA371725C92A8
+:109ED000792692D675A2D4FBCC8FB1DD537637E2CA
+:109EE00016038F9C5C7F8F13F1CCEE38EB246C272C
+:109EF000CAAA907D00F0C9778A6211AF707CD287C0
+:109F0000F84419099F747E3B7C92716DF88429EAAC
+:109F1000AE50A87FA918C6A81DA62E21BCB15852C4
+:109F2000713E7EB1A83F6705A443122C0CF5DBD12E
+:109F3000F6EBF5E243B190E399217CA851FAB9C25E
+:109F4000607C34EE01751ECE1B43234DC295F0A5F7
+:109F5000A6EF07EFDC5528A7413EE0FE2DF37BE797
+:109F6000E2F8E4F1D6CAD0789E7E06AA4A82FDCAFB
+:109F7000A6F3F4DB901E53E4AA14215D3A488FDF68
+:109F800069447A575889E4012C545A6E3B6D837D9D
+:109F900058BA2758AF78C1CBA8BF37FBA511DFFF50
+:109FA000A5FB73AC90B7BB74BC321E999C81978D96
+:109FB00079F2BD02A806F0A8CFE64968710D5F6787
+:109FC0005B6CBED880B804701FE2295BA447C6F55D
+:109FD0002D58343902F150A6C4F741BD8ECFEB970E
+:109FE0006DA47D63AC3B101AE1F5CC5337E8FB045C
+:109FF000F0AD6B687F003E950B5D41FBA2F1BFD3D6
+:10A00000BE30AFA3319FDDDA1747902FAA031CFFA4
+:10A01000C29F15ED9333AD8282E394AD02F1C5B9D1
+:10A0200090AF24237E4A1430DD152BB01B203DD782
+:10A03000F2AEA512DAEF9E6E97ED1CE7DC3B09E469
+:10A04000D42CBDFF8724F95D17E477FDD1CA36A370
+:10A050001D93DD61C5F2F137C2BA001D3017B73F5D
+:10A06000C9F00F8E674E7C30FE9A69B223DD61C263
+:10A07000613FC7FF8171BF50A4E3B1C92C0BF9ED5B
+:10A080006F36BDCCFA70E15A9EF2FC27F467059654
+:10A0900083F7AB58B05C379E13D6E7BC86EB35EE42
+:10A0A000F23FD17C77E732B615F874B2CD32DF0DCE
+:10A0B000E37DEE5D5111157AD27C689576C2F14C44
+:10A0C0008EA6FDFFDCBB873FC880EF9E7B73721CB2
+:10A0D000AEDD0B7BEE7B67099657946D1958BE4138
+:10A0E000227EFAA2FFA1D0FBE1F9F2C11DF7E093B5
+:10A0F0008178C27528DD65233DE6F906A91DE9B31F
+:10A10000BF2D25D4EB1AD2A31EC04A6760DAAD4C2E
+:10A1100086F71FEA782867B9CCF9C386589A87B7BB
+:10A12000C7300DF1F9F20DA17E9CEFE5F2804D40B4
+:10A1300079A4AD5B7712F6E572C7C01C013E09DF5A
+:10A14000B266D251A86F39CAF6DB40CF39F3F0B30B
+:10A150001AB4D3F4A07AB288F6B72C219F2ADCF087
+:10A16000CE71C4D5850E9786763D33FDC10E9769B5
+:10A17000DE199773F64AF81EBA72B288D3D793A63F
+:10A180007496290D7F5DCE699C4EF1AF30C24BF9BC
+:10A19000EA413ECF8E24E647F96E7579088F1E108E
+:10A1A000BAFEDE85F379C2CE3AE0FD27FAFA1BEB60
+:10A1B000F87449B289FFB208E437F78F6D0947BADE
+:10A1C0003E2BB0DE6A78161F2C5E741BCCFFD9E6DE
+:10A1D00005A457966A5C7F3CDB3DE3A709905E01CE
+:10A1E0003819B1C4B9EAFBE692FED804B306F98B7C
+:10A1F0009BF97E28F5097EB4CBDFDDC6F53EEF2561
+:10A2000063FFA8E15303E8DFD01FAB5F0DA1EFFAB6
+:10A21000CE33C21FDE3DA76B50DF2B531D038A1BBD
+:10A22000F7894742FB7FEF7E816D874FEF68BAD594
+:10A23000BA01CA1F03FE2504EC9302F807E7DDAC60
+:10A24000A70CDF275C6F31EF9784627D9F4C63D34F
+:10A25000AE739F28C5B12807DD4FDC3A827E673C8C
+:10A26000DFDE349DCDB631F63A8C1F9F6F8F697952
+:10A27000C003F475CE06FA26F2D530693FAEDF1B77
+:10A280009B1C94DFB549A6E7E14DF1F4FCF9268566
+:10A29000CD867E1DDD944ECF3737B9E9FDAA0DB3CB
+:10A2A000D86CD872A51BEE61B341EFFD698985DBDF
+:10A2B0005FBC8EBDA1506F1F2841C8477B05EDBD17
+:10A2C000E94827EF59C81F32FFE5CAB9A81F0DE2B8
+:10A2D000F9029B7613CC4F89AE47CFD771CFFCCD17
+:10A2E000B6C9B550BE18F56A785F62F54AA8571727
+:10A2F000B75982F8E79CD545B38AD1BED9F66C6DC3
+:10A3000002ACB3579B241565E0BCB4CC8EC2F16D92
+:10A310001168BFCF17ABAD5158EF56C15DABE844E4
+:10A320008EEB9C1A4D741D5AC2F1C2850D478E6288
+:10A330003D66FBFE20DDFC4CD0E9ABA7EED62C4EF3
+:10A340003788EB4BD367B0D901FD42FBFF06A8BFAE
+:10A350007F865DDE2C23DC84790BB4DBB3D7EB1E68
+:10A360000DE4BF26FBBFD9CE5FEE2F94900F0DB743
+:10A37000F307972B290ED68727862B75F128B7C6AA
+:10A38000F37998575BB8F71DDC4F2553BE3F0DD2CC
+:10A39000D9251CE7831E1B81727CA9BD6BEAC728E7
+:10A3A000FF9EB0937DA34F600581F45757C2F95DBE
+:10A3B000BE3E5F4C7579D14E51A4CFD3B983297578
+:10A3C000E80FFA02F46BD2B72B2325B4431443EE03
+:10A3D000EE49588ECBBF78BDBFC5BABE5C3C5C8F22
+:10A3E00052516FA47A49FF0DD69F8B747DD7A86F09
+:10A3F0002914C0EF26BE112FE13AADCCB374A13FB2
+:10A40000B0D0ACCFF642DB71D41FDA5F46BBA08F71
+:10A41000AA81FA2AB59B3254BFD12FB39EBAD2C5B6
+:10A42000F7E74A2BD7578D797A5E9FA7AF4B82F516
+:10A43000D4DE9D16FF01D48B76DEF727D153DB8B5C
+:10A44000AFACA7D238C78F34BFC3F4CE8338EE5237
+:10A4500036F4877A68A1BEAE303175E8CF8279A92B
+:10A46000DC0DF47ECB8F82E7E1AECB13EB50EF2C0B
+:10A4700006BD13F7436143703F332577DD22F8FEB5
+:10A480005CB663409387F76796231867CE9183D3B2
+:10A4900077C707A7E729F661760E87B1AEC9C3EB88
+:10A4A00097BC97BABF46BED466F107EAA9B4CE6896
+:10A4B00037787CC7038FA15C42FD8C0DCD8F416F37
+:10A4C000477C96F9C82FCE34C17E1D412F3DB7EC95
+:10A4D000CEC767209FDB6853D294E1F98C75921E3A
+:10A4E000999923139EC9D8F8B3203DD45C7E19CC2A
+:10A4F0005FA0BF70972E4F4FDA14D2B74F364AB2D3
+:10A5000006AFFA9A2C21C8176AF47DCAAAA65C4540
+:10A510008FE176F28952CB03D4BE28BA3BC88E14A1
+:10A520008C7773C23F27BF7A1F2CBC1DF65119B61A
+:10A530008F38E175597D0CCBAF0F77E33AF736DDF5
+:10A540004778BEF7A0E5007EBCE1E5AA7D3F66A89E
+:10A55000176C5B741BBCDF7DCCC2504FB52C048ED6
+:10A5600089FDB37AC211E7F7FAA68407D2BF81DF6B
+:10A570008D34E0765602EDC1AC1F33ECEDD82F33AD
+:10A580006EEFBF5996709FF687BD49F3DBEB043D34
+:10A590001DF7BDF612E1E3A6151C8FB34AB9AE0B49
+:10A5A000D235BA9E340C3F9970BA65AD8D7591DD88
+:10A5B0009C517F974438F4B49BD206BD9518FBC3D9
+:10A5C000934CB8B1FF23A02F98AAFEA623BF433B0C
+:10A5D000FAA73EBB2224A3BDF6B3669417E7DEB507
+:10A5E000B8753B6A907C31FCC5FDE82F865725BEC7
+:10A5F00097483EC889307FC82C5BEC663B2DD987D5
+:10A600008DF6CF69290CF1E6A71FF1B882ABC9AB73
+:10A6100072FFBAA3886B4A415F403E5DC6F2E69284
+:10A620003C9AE570933C32B5B70CE55BC0BC9BE54A
+:10A63000D9D5E4D7D5E4D6ED2520B76E61D72CB7B0
+:10A64000561547113D1A728BCD76955C510EB54566
+:10A65000D6A1DDCC2C879034502E5C410ECD66D334
+:10A66000AE5D0E95EA72683332A2A957EF97B91F13
+:10A67000AC2552C27E16613F812F1461BF3287CB59
+:10A6800021A35F067F37F7AB18FB15309E12EC97BE
+:10A6900030D4AFBB067E4F7A765FAF40F46879DC8A
+:10A6A000C2BA687FB6F0FD79B08FF4ECDE9376B273
+:10A6B000579D5CFF3F689FEF7EDAE247BF4F41C77F
+:10A6C00014925FD7B1AFFFF6BF725F5F0DAF98F125
+:10A6D00009D32225EBB5AD07E1956B5D0FAF894E30
+:10A6E00000C7136ED6AAC318F2E33EC0D8B89FCFF6
+:10A6F000AEB3FB6BB97D3007F7E7815691E1383F88
+:10A70000D3E9FF17ADF6905EE2FBD157F18F6A24D3
+:10A710003F7615A9FF80F37FF22DEF387904FCF125
+:10A72000559142F59AF5B6F78AD44325B1D7DE8E16
+:10A73000D92E557A708314827A64B6A313EDD8A506
+:10A74000071F934290BFAD7710FE2D3D5845E9F8A5
+:10A75000BF7128F611ED5256C2EBA50D02F1D7D20A
+:10A76000F2B4BA6D68E72A72919DCB6CA762DF1CC8
+:10A77000FF98F04E301E1A8E77C6111E2A463C24D2
+:10A78000FF77C43B2F13BEE85319237F2F33E39D7C
+:10A790000B8487CE021E6223E099233E8E87CE0073
+:10A7A0001EB2B3E1F9574B9F5B164678496BB690E2
+:10A7B0007DDB8C674EDAB83FFA24E01F0DFA770094
+:10A7C000E81DF7F581571CFBD19EDED736E5D8741E
+:10A7D000B49F548B6E64BB191B6DE494DCF5E9C027
+:10A7E000B39A75B81DED3AD6FBAF1CEFFE75AFFFFF
+:10A7F00021E0A53D84C7A0D50CF4AF5D22BF524334
+:10A800008648F8BE5639F3FE78485F8C116935F7F3
+:10A8100066703B966D09237BD1A98CDE551417A376
+:10A82000488A4678E9378D3741FE27D556B75DE12E
+:10A83000720BF5AF0C5B25B916A2015755A3FD4B62
+:10A84000B7FF8D7D342684E244C25B18FAF39D790C
+:10A850009E5CF4BF17E532772E7CEFCC756B2C0C29
+:10A860009E5DF31C0A3C6BADBADF3F66A15345FB0E
+:10A8700044A39DDB2F17307F1AD499119B938B71C2
+:10A8800099B57254143671243FA77B3CF46F9CCA6F
+:10A89000E3FF6A5DAA2319E7D325925EBE25C6CAE7
+:10A8A000842C4AB7E3F7B6D885F23D906ECE2AB233
+:10A8B00008CA103F6E8EF9C09112A0BF37BBC45CAE
+:10A8C0003FB43FAEAB2717E31E9C2E711A4D10F319
+:10A8D00066A37D382C09643CB6EFFAA0EB6F20BD6F
+:10A8E0007DC89E1C3E298E5463DA1FA1B94502FA29
+:10A8F0006358BC854500FF0D63AF6BA959841F07E2
+:10A90000907F871648AC2B805EEDA901F1008CFB8F
+:10A910004D07F393F1FB807C486F5CA1E3C1EBB77B
+:10A920008FD5AE003976626CCB04B453C664490C43
+:10A93000F5258B871D46B91ADD60F1DF0DF3169DF5
+:10A94000CEE96E5B9AE8473AD8BE605D3CD6DB3C08
+:10A950007527C5B5367BB89F223AABB719E971C7E1
+:10A960001291E27EEA975CD9CF3CF612E02910956D
+:10A9700053567B9F5A11204FF76EE0713A174ADA0F
+:10A98000852EC209FEEA77A09DB1188F20633C6B2B
+:10A990007F7749164D03F97B4F1CF67797A0DE9918
+:10A9A000EDA8443E92B821980F9D69F807C188AB85
+:10A9B0008B9F36E4373E51D25E8D76B72FF4B88444
+:10A9C0005F57B477AF867ABEDC1021633AD1845FDB
+:10A9D0004E49CAA9BBA0FCA9C744A55AD78F991153
+:10A9E0007F22F2385BC4B9665C93A8E35F73BF82D1
+:10A9F000BE071C9758124AF10146BB83F6182FEF89
+:10AA0000F760B9A1F880207B8C39DFE8F757159EF5
+:10AA1000C32B62D1EEF3238A23286403362CA76468
+:10AA2000C875DFCD22BBB41E37C8E5C3387D3CE313
+:10AA3000CCE3AF8AAE433FFB19D551896DD6375E63
+:10AA4000B0215D5C84EF59807E1E88175CD3A8FB23
+:10AA5000F4B7FC65C751F4EBC37620FADFABF30F14
+:10AA6000DA2E01F100DE9F3C537D530CF9F3A95C13
+:10AA7000E206E647BBCEB8AA5EC1CBF5CA121CEF10
+:10AA800038A37C6D30DF4FA9625A68263E83DF8F82
+:10AA900034FF83713C029F372D60BCBB56AB9F23B4
+:10AAA0005DD6DB9413486FF5F3245983F6EAC7CCDF
+:10AAB0009D877C21C5C3E388525CDB894FB05491EC
+:10AAC00071FF1BD73BB7E96DF83C8749CFDD961F77
+:10AAD000978C7AC1132BB8BDABC6359EF06B18F0BE
+:10AAE0004DDC3F06FD87E6F3F8A041BC983172FCCF
+:10AAF00051A83E7E51517621FD5FC4783E65F4FD3C
+:10AB000066D46BAE6FEC6AD5564AF60EF79B77911A
+:10AB10003E292AE82F3EAC7C614179B13357DC8F66
+:10AB20007E80C682ED148F155ECAFBDF00FA08D75F
+:10AB3000F77B48BE3466F1FC9B57AB11A5406F0D07
+:10AB40001E43FE54523EE835B1D88E61FF684C3A40
+:10AB50003CE125D4BFCB4388FA6A629E233D660B55
+:10AB6000EAD6404F5B3AADC487B774D61EC738B833
+:10AB70002D2CD78AFCBC21B92EBE64029497D74FE6
+:10AB8000A0383368214D1E926FBE5C793FE2DF8FA3
+:10AB9000611BA2FC8A76B1FD1827B1B0743CE1EECE
+:10ABA000EFE7815C43BE2E4BC9A8F757BF7A7F2ED3
+:10ABB000AE43FB962892E34372D34DE7047678A226
+:10ABC000B6A27E73315F47BD3A9F8FD2D7D7D2F4FA
+:10ABD0001D01FDAF86FFC388C3AA47FA860AED6C44
+:10ABE0004104FA8BCDEB511FDE4372312C9FF733BA
+:10ABF0002E89F97311F714546A688728D2E5DAB8F8
+:10AC000086F35B507F296AE954B13F2C97CB05232B
+:10AC10004E6CB9AF45C379776604CB0FBB495E581C
+:10AC20004CF2644E69B07F45616E07F6F3948BF386
+:10AC30006DFCBB1C2047CCFDEFD4F7AF21778CF720
+:10AC40005790370B892E6C5D846B00EBC896DBD96F
+:10AC500030BB9AA08CE627B646F63B86F4D4D1F5F5
+:10AC60002B2BEB0FE0BFD71AB730C752714A423CCB
+:10AC7000CA24D94E4F4672EF540523B9571FD6AB9D
+:10AC8000A19DFEDC9DCC7D00FA79A3B593F46C9771
+:10AC90005B1134A8BF411143D2A1A9E42DA993B0FF
+:10ACA000D9782FB7672EAF62A22512ED3595EFCF79
+:10ACB000C1FD759B48F61A2DA785C6A989AC670703
+:10ACC000E24FB987EA4B7A982988CFB67A0EC873D3
+:10ACD000E0F584326ED73CA059E7E3F6BF01239537
+:10ACE000A081CC9B0C3AE5F688735677C448FAAA43
+:10ACF000F12CDC90B207FD5046FAF43267817F8474
+:10AD000075FA68754E3DAE134B6F217DFB94C86498
+:10AD1000F453F50BBD89E88F3D58F6FCF38E3B519B
+:10AD20004EFB4E31DAB9FFEBF937E1999C96E39C83
+:10AD300003CFEE7F9AF7FCEC64E47B56F2D70282F5
+:10AD40007D5EB562BE48E92FCB1A1F427CFAFB221A
+:10AD50004F2BF203D8670AD25D72B5E8C1FD8E7E33
+:10AD6000E3A880712C291388DFFCBE48DD8DFDBA75
+:10AD70008672FBB0DC232B2670FB00DAFBA03F675A
+:10AD80004BDEA378CFB307ED8A200CF1D1E5FA3E74
+:10AD9000CE5EB3281CF94CBFCFC290DF9D2D5973F6
+:10ADA0006C317CFF491BEC6B85EC93146F7B165662
+:10ADB0000AF5858952178F7B0A617207AEDFEB9C1B
+:10ADC0001E5061227DA272600EEA0735AA83ECC094
+:10ADD0000CE4D1E0FE0BB04F1AED9F6DE3F6C94FC6
+:10ADE000F4FEF6BB3D647FEE67E3DD5ACCF07D7286
+:10ADF00072FD8D2AE2AFDDEBC3DD6897C97CEDF211
+:10AE00001CB43B6F80F610BFA4699F939FF0DC4990
+:10AE10003BD9AFFA07B445B7A1BEF3AE85F099B9F7
+:10AE20003F663A18C12E750CD72BCAE53D86FC70DB
+:10AE3000B4F8EE24F4C74FB8821FDE6C6FB2F2385C
+:10AE4000668BC8E775EF72EF89526EEF9139285023
+:10AE5000892F6D4D0779E01ABEEE779671FFCEDE31
+:10AE6000E5EA29FCEE1ACAF59506C4ED19F36FD888
+:10AE7000A7CFE9F6E973F261A2974FDA38BDC0FABD
+:10AE80001F263BDBCBCC8DF9E6F53F67E3EBAF95B7
+:10AE900040DB37223D0C6CC1F56139D7B6FEBDAE43
+:10AEA000D4A0F54F0306698FC1F75C5F2BA83E4223
+:10AEB000F2F202CA4B65383D2C6FBB41457A939143
+:10AEC0001EE287B7D7EFAAAD47FBF0A1576F93718A
+:10AED0005C7F08B3D2F935639DFBDBA6F0B8209701
+:10AEE00022E8F1FCAE32B4439E775F312EE89BAE90
+:10AEF000B7A874111EBA08FB10E711F41535701DC0
+:10AF0000961FB43F80F3288BA2DB9284509ACB8BA0
+:10AF1000429017E817328F4B54E4BAAE18C2A164BE
+:10AF200067601E8105CEEBF2832F119F954B757BD9
+:10AF3000A869DE86AD8BB9FFAFCB0CFDD4863F8709
+:10AF4000557239691ED72181C75D69EF5948FF1CC9
+:10AF50008D0FF76EEA69C3F800588708C4B36735E8
+:10AF6000C16F9B084F5F7B6C609C58EF2679D7ECD4
+:10AF700000B99AAEBDAF227EFBDB5285FB3335A113
+:10AF8000AB35139FDD2A4800F6D6327526AED75F63
+:10AF9000EBFCE62C57EF2F9B3A7C3E61BF935CF9AC
+:10AFA000A894CB95BB56A8CBCBBE455CD03795AB10
+:10AFB00056935CAD1D5DAEAEC77EA5FDBCA27511FE
+:10AFC000CEA78FFBB9341BDF3FE6F2359B82FDDB5A
+:10AFD000C6F3E10AEFC6B280B8216B6409D14DAF68
+:10AFE000AD4BB812AEBA917555637E82CA646D06D8
+:10AFF000D25B3443FFD6E2755C7E7C5B9C6593AD8F
+:10B00000E47F3FF4EAFDB27784F99AB3DAEB0B5CA4
+:10B010003F5B8C9BE23566567876E2FB9AF0104AED
+:10B02000E754A84F95C55EFBFA19F56DD9D4F0CA5F
+:10B03000A701FB05437510A44B31F03EC8EF1FBCC0
+:10B04000DE5356AB1DD8DEDB63BC14F773D7C0BE2E
+:10B05000096188030E460BC8772776ECB817FDB454
+:10B060006763A22609308F93CB795CC7D9CE85F769
+:10B07000923F3BC94A71973FE95C2F1743FF3F2D31
+:10B08000F73E1B384EFBAE8764D575FDF408F2F031
+:10B0900035E2C3929BEC2EB58CCBC5D1E4DC6DE5DB
+:10B0A0001C07819CEBC2715D43B97F2EBB823C1CA7
+:10B0B000F4D71AF2F0E0B5C9C3FEE1F290F0D05F28
+:10B0C0004C1E1EBC417BF40AF2F0DC55E4E1B9836E
+:10B0D000C3E4E1BFFD39E421E0E03F10BFB2F6D2A6
+:10B0E0007C5A5EE5F3391ACEBDB39CE318C0B9971C
+:10B0F000F1BB6B282794FF15E0E134AD3C1CE5DA89
+:10B10000D9368B48E7055A83D7DFB02BF40FF0769A
+:10B11000FAA01D6D8476CED9D8CB42C4D03A9BE933
+:10B12000A63F4FE926BB412EA397B0EE19387FC248
+:10B13000C17FF9A390F9EDD7BBDFE91DEBCEC0FDD0
+:10B14000C10A3A47E093331E9C7B2BB6F77C99A249
+:10B15000FB0983F906C8F9DBCBF9BA93F1CAD0A78A
+:10B16000403ECEC4EFFE5AE5BFC07CDF9B06E562E1
+:10B170008DF810E8089EEF1AF7A98B9F538BFF7785
+:10B180002199F4246E378C7DF9329D5B031E4A7140
+:10B19000FD83E7D654079D5B8BAD0A8E078B650355
+:10B1A0004272329E07F264E33915D0B27B3A64B43E
+:10B1B0000BDF1764178E1DE6D7369D5B0B3C3FA453
+:10B1C000DBEBD0CE4B4B19704ECDB05F8E8BC9AF41
+:10B1D000DE9FC586CEA999CEA7C5EAF663737F83A5
+:10B1E000EA0D38B73668BF951766BF18C3DFE3B9F5
+:10B1F000B558B35DB96AD08F4FE7D69ED6E50151F9
+:10B200005CDC50BDB1FAB9B561E3D6EDCE544E1851
+:10B21000CA1F3AB7365D1CE9DC5A8A7E6E2DC574AA
+:10B220006EED473ABF7AA93C381EB076B1C8E3014B
+:10B23000172FA4F30FA3E1916B8D0734E2BB86C7F0
+:10B24000036AD47E63B91EA70EF485FBEE2F7D7EC4
+:10B25000C4E8C770FF2D7F9F7DF39747D02F694BC0
+:10B26000E271DC36FD5CB0B380D13961672EB76F17
+:10B270008626490A9E83986B71517EA3C2E3B98DDD
+:10B28000730F861FA4F1DDDE6EB45FC6255818FA71
+:10B290004FD8061E876D9C7330E2A4B62CE0DF3BCE
+:10B2A000F2D46C2CEF986E975519CFFD5A83E29625
+:10B2B000E24C714B31BA3D34C614DF2D615F805FC3
+:10B2C000FCB25CF7635DFF79887F45BEC730180A22
+:10B2D00070EDE45D5376E07986ACBFBFEF437C4E02
+:10B2E000DBFF5074E0F985E91D3BEEE3E9AE345C29
+:10B2F000DFB7ABCF2778A0DE7DD53C3ED0A2F7CB21
+:10B30000A8FFE82A4E97B7AE557F83EDBC5D9D9DA3
+:10B310008038D1573D32FFAE5AC5F751AD6DA01AF6
+:10B32000CF77B5B208561D83E7DCAC7AFC905F207E
+:10B330007BADB2CE817EA93CE617300E1BE718ED3F
+:10B34000820DA90F1D47B1949BA5F5A0D8DCBE8A3C
+:10B35000DBFF6AD38E58A3A1CC5B558CE49D7DAAFC
+:10B360006615F13CD0AB0514EFF88005F839F243CF
+:10B37000C6ED29782091E4B0991FBF2EAB2B315F29
+:10B38000E7B7892BA3A8FE4C99FB9B337315A166E5
+:10B39000129E231C207B7A33E02DF40B36BBB69330
+:10B3A0007C975682E8C0F8CC84543ABFC71A1D3245
+:10B3B000FAAF0FD9F879F9DDEB9CC83B5973D68108
+:10B3C00013980E795452D0EFF1FEAA489A97CC0DFB
+:10B3D0005257E07968F333537227E2B9A4F66577E0
+:10B3E000FEAA3C26E85CD3F805B06F92D0EE0AEFD7
+:10B3F00045C095D5B0DE43F2E2FAF4960B25B37E54
+:10B4000081171C7DBCECB330C4BB3B22390E6C668B
+:10B41000BD0958598DA024F0431F6A02B67364C158
+:10B420005763D01E7F28D2733FD2C12713D4043C68
+:10B43000BF75B6954D7228B8EE953D283F12ABA268
+:10B44000DDD5909EBA92EB0B69E54CF58F402FB796
+:10B45000EBF4027441F56FC13D08DF77A4333FFA86
+:10B46000F93BAADABBF0FC453BC835B4B79E0DD317
+:10B47000F31318ADCB76C1ABA1FF473BEB621D9038
+:10B48000BFA3B5B40BFD55FB04907B900EA92A55C4
+:10B4900057227D2956F297EE8BF56AE84FDDFA9F29
+:10B4A0001319E2A376D74E92ABED6FF2F3FCCD4DBC
+:10B4B0001F901FE7ACE06FA3F3841BA5C968CF38CA
+:10B4C0006BF3244E86FEEFDD58DA5506EFF7667310
+:10B4D0003FA0946EE6A39E5F119DF8A4F15B89DF07
+:10B4E00079BBD2B13F4CE941FE69DD58D4B51AD2DF
+:10B4F00017374C94B17FD255CE81EF5DC9E7E77124
+:10B50000DD9FC2ACAA07C73F4EB6D2B9D188E9C108
+:10B510007C12FB89F556AFFCC5C356D8C71D36CF84
+:10B520006E4C57AC7CEDE1D9B7617F06E8DE25EBC8
+:10B53000462E4F9823B83EF3FA18ED1A69737BE351
+:10B54000AC8CF6DB381FDF27D6565EAFD5A6D2B956
+:10B55000BD3F577D67374A6467B85A7DC6FC8D93F7
+:10B56000AFAF5EA39CB95EF3777FA9F2A38DB35A08
+:10B57000DF67F4370DD51036789F0EE22D49CF0ADC
+:10B58000C92B257A9445EE87AE11FC1AC6476AC9C5
+:10B59000D64AC47B21F123E32CFA9EFBB5899F1A7E
+:10B5A000F54B253FEE427F1DD3719641CF83382B5B
+:10B5B0003DF87E8039C67E671C6719F5D68495767E
+:10B5C00079897F33255A1E615FE8788BCA270FE59A
+:10B5D00007DC1340F61333DE5AA19FBF58613A7F50
+:10B5E0007146976B9FAC0AC65B1D7F67E1F704FC51
+:10B5F000DD9FE6FCC5873AFD99F1563DCE0DCEFBA9
+:10B60000CDFC9E0890CF5A580CFAB70067450EAD96
+:10B610005B84BE0437FCE88016CAF1ECBA08E0FB94
+:10B62000BB8DEFB3E17BAEBF52FC822B60DDF19EA0
+:10B630008148630D15968AFAE4137765EE47FB811E
+:10B64000CB34BF913F595FFD0CD71F0887B340BE75
+:10B6500006F5C94A54F73301389DB181EE3E282FD3
+:10B660009533D2472297068FCFA558AB3FC6FAF441
+:10B670007B0698F5BC86FE45C9A250BC1C73746B52
+:10B6800018FF26CD8AA7F88B1AA145C5FE69331885
+:10B69000F90723D4E0757499E89DE9F2D49EC6EFCA
+:10B6A00045712649FE91EE1FD8AE9F7B68B0AA4B2C
+:10B6B00090CF3578E20494CFC6BADDBD8AEF1B5F28
+:10B6C00024DFF748575AC0BC18E5BEBBD21674DF5A
+:10B6D000412C9FD3413BD1CE8FF8B9919D1B8E92C7
+:10B6E000FED99A27915D61A2D4C2302E973D26D211
+:10B6F0003A1F8E5C2C3640DA57653980F8B56063A6
+:10B70000DF73288F2EF4264FC62A0FBD7A3FC5F36C
+:10B71000FC213B9DEC922C7F58FC03D9098CF6F759
+:10B72000668DA7F65BF5B8FE93EB7FEDC038B1DD13
+:10B73000D3C6732C60A2DBD83C3D0EC254AF57DF9A
+:10B740000F31FA79BADA05C171DBCF3ABC13564131
+:10B750007EB3EF4307DE17D1E7E1EDC75CB252F9E4
+:10B76000346D3AE19082B0C957DC37B1FA39BEC1C5
+:10B77000B4BC58C0F2B197247ACF5C31D7143FFCE7
+:10B7800048AC95E8BF669E44E3AE09F3D0FD0A35A8
+:10B790001B2DEE037C584417BBE74907B606ACF7F0
+:10B7A000B4950A7DBF63DE34BAD7D03E363D01F989
+:10B7B000C64B2BB9DE330E237652303ED2C131E96F
+:10B7C0007446F6BFE1729AC74B121F44FCB753246C
+:10B7D0005CB2CFCD468E97AC3A43E729B7022AB187
+:10B7E000CBC3F3CD699FAD4BEB85F67D80635AE407
+:10B7F000E1F4BF2C3DF81E8A06ABE6407901744C9B
+:10B8000076919055AD0F57A7A23D7739C5E56FAF3B
+:10B81000E2F4593B4FD471B887E23B0A367E487157
+:10B820008517B2B8726E5E77C3AED4EC3B1214AF1C
+:10B8300062D08931AF401F95ABA6623C9C4AF8FEAE
+:10B84000DBD2C5B4557C9DCCF471B99CDFCF90E7B9
+:10B850003E4FF15CB536E5F189B8DF1A2C72B5328E
+:10B860005CCF78A345A0752CC9E5E7E27395F3A4F6
+:10B87000973881B3D23D56A87F40BA1E3121A4A289
+:10B880009A9ECC9B0CEF8B15D1AD2AA89F0C7463AC
+:10B890003C044BE2E7C273B30666A13955D5AA4909
+:10B8A0003FB9A3E5744DBC82FDE2F135C54DD90524
+:10B8B00093A1FC9DA9FC5C937D6A17E92DB9550AFB
+:10B8C000CD5B9AD74138E4933C91E8EA78557BD038
+:10B8D000FD9FB6E427AD4827B9465CD928E780CE5E
+:10B8E000EAE7808C7933D623D6DA3917EDBE51F1E9
+:10B8F0005C9F8DC90DBE17F4541EA7D30B2F08C42F
+:10B900002F8D7B24DBF57B24CB98574A44FAB55620
+:10B910001E2D877AECB7D965E4CF785F66207FC7A4
+:10B92000FB3203EBC5FB3203D3785F666079BC2F33
+:10B9300033387EF996A07CBC1F33301D957E7B305A
+:10B94000BFFF86E787A2722B25C435CB40FE58DCAB
+:10B95000C3CF1345E5765A71DF3FB62AF83C6CCF6A
+:10B96000A5F175110A15B35AA7E1796D3EEFDF63B2
+:10B970005F5A23E0BB7BBF542594C9B7AEF51E4385
+:10B980007E58FCA57C14D3B078843F02F463DA8738
+:10B9900055BFF99B17F0BC3E530676A1FC1EBAEFCB
+:10B9A0006480E4D137BFEF84EB8789C8C7A68EAE29
+:10B9B000279AED271FAE64FF25F79318EDFE4F4140
+:10B9C00073929D4EE6713F7B186BC1F332C0DD2848
+:10B9D0005D53C9EDAF6388B9C07329BFDF279E717E
+:10B9E0007D372A9529CD09686FE67675DCB398BE58
+:10B9F000116098258A9EAA9582D2FC342FF83E5574
+:10BA00007F9F09923535FF8111E3D08C67B11E8F7E
+:10BA10003B9896395ECC79EDDD9FE239A877D6DD8B
+:10BA200038D9AE0CD5FFCE2BAF2709907F32F35F0C
+:10BA300026E0D3B0176C91B97EB1457E8EEC09B586
+:10BA4000B091456014B59D3E1EF755CE643CCFB90C
+:10BA500054528A30BD74AB83CE696E8911498E878A
+:10BA6000AC73EE271B0CDBACE3644F1BD2CDF8416B
+:10BA7000BAE1ED6FB1A9F1747F4A64BF581840373D
+:10BA8000DDAFDE4FFC7E5B12BF3F695BD2E42BDA99
+:10BA90000DED26BE6BD46FCFAA64C877ED3ADF4DAB
+:10BAA000D33638506F2C1873B5FAF83D77C3EA4B8C
+:10BAB0005DAFD767A5FCC54B3AE8DEC0E507ED32C0
+:10BAC0008EF75CC70F3271FF9CDBF8641D0BB81753
+:10BAD000F8C3A7CF8FC1F6D2BADAC2B1FD4FF47363
+:10BAE00065670FEF929480722BAD2D12FA158C7B47
+:10BAF0001C16779CB7A1DFF1EEAA27A5DE8CA17EEC
+:10BB0000ACDCC3E541599540F260B9BFBA8E9F0FD6
+:10BB100028081FE93EE2ECE6D870FCFE74531A9D3B
+:10BB20005B3BE39B724539765A6FBF57F7C77E87F9
+:10BB3000C58707D25D5F03AFA7A6E13EAAF74C9287
+:10BB4000E75E8C1B3FF3BE05577C483F09E3F635A3
+:10BB50007639652FFA070A1B0A29BEB50FEAD740C6
+:10BB60000F2C5E6DA17D35AB2159A2F8C8DA48498A
+:10BB700081768AB484B9680A2CAA153A9D507EF55C
+:10BB80006A85CA1536454A78AEA0B06112F129A877
+:10BB90005712A85E4146FE73B57A0A5BE07B1796A2
+:10BBA000CF96E83C256BA1F92C69B2049DDB486374
+:10BBB000E923DEEB9CBDE023078EB7D99345B8E3BC
+:10BBC0003B6C7A239E07687ED7C2AE14B76B8EC3D8
+:10BBD000323F7D79BCBE9ABCF14EAC7F4792320FAA
+:10BBE000EF73DC619ACF1D83F339E504E2EBA83CE7
+:10BBF0002FE92D18A7AAC17A6D33E633CF2DE03C8B
+:10BC000044E7F630A4AF27F5F90BCB720B5E48473B
+:10BC1000275532F2675F9E2208540FF02D01BFEBCB
+:10BC200061F85D58AE5BC0EFA2218DE5C3148D971E
+:10BC3000D7E7CB912406E13696A1B1E971A4C7926A
+:10BC40009CB1326B3FCAB106DC93C407346E9F943B
+:10BC5000FC09B26B888E772FFBE9AED211F8BE8D4E
+:10BC600055EAFE10BF6E87EDA4F4890F7AD7901DB8
+:10BC70007B4328F19B7A5B2F9DDF86DA65F24F9B31
+:10BC8000ECA4861DF8FC2ACF8F57A3DC785DEE422A
+:10BC90003E63D84D4FCE54C83F59FF7F2C747F8DE3
+:10BCA000E167B3F1A1311BDEF31860E7643192C99B
+:10BCB000AFE6217E6CF8D3AEF5BBEB8E83BD46BDFF
+:10BCC000022682E665793C9747A9A80F403A3C9D39
+:10BCD000C9686F4DD5CFE9C79530D69880F797A83A
+:10BCE00022EE4FEDD10819ED27CCAA8A6DF8FDF4AC
+:10BCF0001B647E7F1F5F8754ED1DE1387CF7B7A181
+:10BD0000822C829CCDAC9A44F79C0CC5DBB889AFE1
+:10BD10008C26A7CE6C8ADF83F150BD9BD2F760FCE6
+:10BD2000D4A09CD204499888B8B37B02EEEBABC98F
+:10BD3000B13E5D8EF5BD72C758925F8F73F9659401
+:10BD40007F73FDEDE148C77D97A71CC3F321BF2E8C
+:10BD5000B1B86B189E0B1B38433698DF7EF5482D23
+:10BD6000F4FF0778480AF0CD1F57B31F6AE847D59C
+:10BD7000FEC1D606E57F7A315CC1F119F76E7D1CF4
+:10BD800032B0C613503FABE07A26ABD0ED55157CF0
+:10BD90007FA5B3CA3974DFC06CC69A1290047FFEC7
+:10BDA00008CE73FABA30C6E32BB4CD3F44FA7B51C8
+:10BDB00052D0CE7B7FF9FB0FA11EFB83F2C8BD7171
+:10BDC000F0DDFBD5E1080ED8E92DFF3215E7E1B42F
+:10BDD000AD6B6AA40BE38ED958F2AF3EE024FCCEE3
+:10BDE0007ABB2E92DEB82599FCE839B593C69E2120
+:10BDF0007EC6FD624B2DEE7809CBD75B18EAEB7D52
+:10BE0000CD7686E913A5615C2E97C8C7306E68C9E8
+:10BE10008369A42F44E8E3596A6795C45FBC2D5336
+:10BE20001784E1B92299EEA331D6DF523BA90EF96E
+:10BE3000537146E5187CEFB70ED0F9BAE654DDBF72
+:10BE400090CAF182351BF606D09DF5D917783C8152
+:10BE50007EFF83F95E87E62C8E17FC9576135EE8ED
+:10BE60006943FDE64075305E68B6B570BC90D69FFC
+:10BE700083E706FC3E91A11E7A087004F6A7364CB3
+:10BE80008D473FD016C6F77D7485E7E60AF457C89C
+:10BE90005217D269D86ADD2F181345FBA8D1C6FD09
+:10BEA0002CA3F10FF4B3D0F92F9D5F18FEAE4CA96F
+:10BEB000F7009E8B6C7C34CC0DDF423BDEE9D84E24
+:10BEC000E3B2BF2FA0F30C267E66F8B546F37B984D
+:10BED000F7AFB7CB49B8806961AC2FC86EC2F32FFA
+:10BEE00094A4D0FD00CCE14A47BE13ADF7F7C4E5FA
+:10BEF0002974EFEB979723588D1BDD4795C464A2F7
+:10BF000075BF2EEAF95CEFE77C2F5A8F0B8A7EBD56
+:10BF10008EF4FA530F31B7103F549EE9E53556A918
+:10BF2000E17D93D1FA3951B37DFFE44C7735C617E3
+:10BF3000D4265B2B37BB83BE1788FFEB764FEAA76F
+:10BF400030BCFE093A1E87ACECAF47B07F99D37680
+:10BF5000C564DF4DE7FC3786197F01F62F0B9EFB8A
+:10BF60005205E4FBA7721CEE6AEC8B67143EAEF33D
+:10BF70007FA39E18D9C4C74DDF19EBE15862233C5B
+:10BF8000D6BF5120BC9A61F3EE45FDB5B82AD48DD9
+:10BF90002A54F10B8C2A2DD204F2EFE63470FC56B1
+:10BFA000DAC4CB977EEEA578C2A2AA30372E6BF109
+:10BFB0006FE5C50590BFB6CA49FAFB69BC0D19F912
+:10BFC0003394273BA9C67E89FAF41A7DDD8B5FFF87
+:10BFD000651DAEBB717EA546A7FFA72AB8DFB1B726
+:10BFE000C0B6B600DF594ED2FD62C553D8783CCFFB
+:10BFF0003038AE17B85E0A729B9F47D182F5D0B534
+:10C000000DC1E962931F786745F0BD16FB2B58D030
+:10C01000BD68D8CFE8A86FDF0E73F17D3BC1DA238E
+:10C020008EE49731D6C3F077B74E35FCE53D2AFE56
+:10C030000E45F474BB2ECFF8BD6986FFFC90E4AECC
+:10C0400046FB416BB66300EFB10A63BFCDC6F28316
+:10C05000F756E9FEF4D1EE438B36E9E561A6B4C1AB
+:10C06000375EAB083EEF796AC3148A1F36F88379CE
+:10C070003CC67D66DFF4DE32E33E34E3DE32635EEF
+:10C0800090B6705E4EEBF70B9CAAEDA338830B5570
+:10C09000204DC98EF218D9654EEF12F87968DD6E21
+:10C0A000E3D5E7C95B75D35C944347611E51AFFE8E
+:10C0B0004BDB53EE31DB539842F691423C9F8EEBC3
+:10C0C000AAD393615F29DC60398DFE8C42F33D6316
+:10C0D0006DB6A134435C109C6FEC9FF315A67BB743
+:10C0E00075FABB1AFE4AD4E363CC7E9C7FECD85928
+:10C0F000B415E6AF7F5702DD6BEB5C23EAF2AE923C
+:10C10000E2C3CAFC8CEC0F7FAE789444EBC8F11705
+:10C11000F21AE18AF12A865FA9EE313D8EE7B13F3E
+:10C12000CDFDD3578BE33931B6E57BD3A0DD1BDEE4
+:10C13000B5B835982FCBD2CEF7D0CF1DD76371DFEE
+:10C14000CD86D6E994C2E9DA1AE9A0735EADAC27D0
+:10C150009EEB0FDE6EBA3F7E09BF9F18E659F7FFD0
+:10C160002F4E441C7328B27709E2850EF4FF43B9C1
+:10C17000DDCD4290FF3FCA17E5AE86F49C351CE743
+:10C1800015E772FFFF23B1F9F4FB0BFDAD3C9EB840
+:10C190003FAC326141C65039BB68FC1E81222C9CE9
+:10C1A0008071C90AE5CFD4F307F542A7AECF314578
+:10C1B00020F9A3977F0AF905F2FB663BF95BA272AF
+:10C1C000B91FC0FAB8FD00E2A4B96B14C37942E309
+:10C1D000D9D95C467E00F83E01E9C8883FE86BE2A9
+:10C1E000F1078094288E636C9B9DEEAFEEF34DCEED
+:10C1F000B919F54B3D1E61E7AECF04BCA7B2EF2CD9
+:10C20000540269ABD85B8D763C26B24AC4A97DCD79
+:10C210009F55A3FFA71DE43BDA21FB627B0967B4AE
+:10C2200063FC818C717953DEC2F9FB224F247B3190
+:10C23000489C6EB4BB16AB0E8A376CCDFBE038DA87
+:10C24000F75AB3246242639BCC74D64BE31F9B27FF
+:10C250007649402763F57B8AC65E25AE6037E05A93
+:10C260003AFCABBDFCC3AE54680FFDEE31747F22C7
+:10C27000F78FEFE2FECFD1FCF89F98E8D45B154C26
+:10C280009F43F53FF722D64F331E706F39FD059C53
+:10C290001F1F9B77A01AE761C8BFC8F309F7003DCD
+:10C2A00076C072204ED2142BCDABF93C73B47E7E97
+:10C2B000DCC04786FF798BBE3FEB06D79DFBAF07FF
+:10C2C000CFADFB44FA0EFD00B8FE4F19F7A4950759
+:10C2D000C707E21FFAABA391BE60FE1E5FC3FDBAA3
+:10C2E0004FACE1B8387AA9A4D7E3A67ACC386D343C
+:10C2F0001C67F8AFBFAAF03CB566EAD03975E8CF45
+:10C3000049B42F2436D9E93C64BDE0AF46FF30EC98
+:10C31000D14A8C6BEA73FAABD12E0898665D35BFB3
+:10C32000BF83FCBF34BFD0DF0EA7BE0F5A05DA07AC
+:10C33000C3E8A13C384EB304E4018EAB100905E616
+:10C34000FBD09A141AD772FCBD12C2914A2DFA2959
+:10C35000C6FA846968AF2971254B91F02C8C11EADB
+:10C36000F07977D2791BD9BFC7680EBC97A2A3D149
+:10C3700042BF6BD511D6FB33BC2F526B0C23FDCBC8
+:10C380004C476FE87CDCF0D3220588308E34619016
+:10C390004ABC22CCDB0E3DD1B386FB7DA3F33C39F6
+:10C3A0004E68E774FDB8C9D8BDB71128C5D2B80B1F
+:10C3B00046E2D3EF0E6F87EE77E9A7A101DF6F8B1F
+:10C3C0009C599881F50B069D682CE09C7354AE3CFB
+:10C3D00013C7F7FE1A598F573A3D09F75D4724AF47
+:10C3E0004F15E5990B02EC5EEF1BF2C9C1CB3D2561
+:10C3F000542EB984EB01F800E3894A4CBF0F54D89E
+:10C400002668A1E1C3EF8959AE05A7FF55A73B33C5
+:10C41000AEB71A7C93F1752FAA4D3E60DC6388E9B4
+:10C42000C43C85D2E25A637C9CBEA29A789C749FDD
+:10C43000CE4F87F30D8570EFD80661327EFF6F46D1
+:10C44000FBD6D3A49F1681DE83F8A1F005FF2BBD98
+:10C450004A00FF66DC3F4AFB05719C77BA13F9F38B
+:10C460001FF4F935E6E9D0BDE3C97E772477B2132E
+:10C47000ED0ECB1E4EA67B0ECCF37035BDC6CC0F99
+:10C48000A2F282FDA3D6B58CFA3DD6E4DF1F8A0B5B
+:10C4900090286ECF880330FCFAFB3E9A75D09847FF
+:10C4A000D46FEC7A0CF377D7D8A8BE7D593BC9BFBF
+:10C4B0005F0F7ABC40760AFEBB2A6C9AA4A0BE71BC
+:10C4C00038F22BBA47C0D766D98FFE7E63DCF62CD4
+:10C4D000DD0F9F34B27FDFAED3A5A8B4907FF662A4
+:10C4E00012FF7D9556CF42E748F861B4FA52D772F1
+:10C4F0003AACDD65DCDFE6A5EF5B0B16D2EF01A6FB
+:10C50000699F53FCC16EBCE70DDA2B58C97FEFE879
+:10C5100002DEEBC602FDC195FCF7039706DF5B6008
+:10C52000B46F1BEE0F9EBC36167F7FC84341293681
+:10C53000DD1F7CAD38B07BEA5374BFCACE4522C53F
+:10C54000F9EE9CFA03D2FFDBC788E4B76C9FB1AE6B
+:10C550000771C457B156C237CE96CFB64D84744AD0
+:10C56000968DC6C1F4FBEF0C7D34AFA9CB12818947
+:10C570003CA6DB1734BB4872469344FADD0CCD86EB
+:10C58000CF3CB7A045A3BC4D2A7FDA128067ED8B64
+:10C590003E9845DFCFE3DF875DD2487E3899AAE336
+:10C5A000A55E8A9F0CD5E3E85AF38B1AD12F6D5BF9
+:10C5B0003099EEC9786F2A3F17678BCD8FF406F05C
+:10C5C000A74E7D3FD6DBD495146FB091D3A1FDEF7C
+:10C5D000BE3A518674B43084DAEB68FD617CE0B910
+:10C5E00032E14189F3BB657CDF9E1259796750BE09
+:10C5F0009DD65D7890EFD7EFADE47C601CE01A0526
+:10C60000E93C3F6B339E27D20AF87656ACEABC3938
+:10C61000D05EBB478C413A8B9DBA681EE2B8EF2DC5
+:10C62000CAA129B4361F9E8DE90E37700D184F87A9
+:10C63000278FFA7BD11362C5F53825F1DFB53A357E
+:10C6400076AEB53A80CEA507D382F67B5C95187C92
+:10C65000CF8F5D5D478BB489D1BD1BB3AB783A05F5
+:10C66000C025AE7B4AFE6C4AC7F924E684B4A3A079
+:10C6700045C3F81347AA770ACEEB914889EC5029B5
+:10C68000059C4E7C5831CA1B8F8BF4FD14DFDC16E1
+:10C69000FC3D8C948F2C0CFD18B5364F22D24D6D7D
+:10C6A000A495CE6FA764F07909CDB2EDC771BC2116
+:10C6B000F52CC5EFDF789CC709ED59CBFDFA4E4547
+:10C6C0000CBAAFC881F67C58F7EEE669BF42BCD61B
+:10C6D00031D54E7ADF1DAA87D277144830D1A0E732
+:10C6E00031EF2EA4A73B8FDB5957F215E97E447A30
+:10C6F0001CADFCCE821C27D203E0F5FCFB701D2F85
+:10C70000F17B15EE18E8213A8DCE55E877467C731B
+:10C710003D89782E2A4BA783D6984F6BF07E752DD6
+:10C720000BE818D7B175F13C9C1F5F9C752A967F6A
+:10C730006491A8A15CD8D7BCB803E36A16ACB5D2A3
+:10C74000F8F78579E6211FDAB7C8CAE36B62DC899E
+:10C750000B02EC6FEDAD736FC67D0E74AEE3BEEFF2
+:10C76000BE84B86FE67F84D0FCB6AF6414A7D3EE66
+:10C7700074737FF5546E8F457B03DEBFB42FC1DA2F
+:10C780008EF6869F373FDD8D742FCD28E3F74ADD87
+:10C7900068D8C739DF32EC0F0B74FE687BF7722D57
+:10C7A000D265BBFE7B3987A4815A5CDF7DBA3D62CE
+:10C7B0006753D43F63BCEECE780BE1F3EFCF0EB6F8
+:10C7C0003F20EE433D3845D783EF1CB006E9B7CC98
+:10C7D000E5DE8CE3FE5ECE748A534B31E9BB89A65D
+:10C7E00074CFDA6F7D2FD5C76B39FE20BA7E6F23E9
+:10C7F0003FEFB7CFE17D0BEF1F6BF78974EE6E67EC
+:10C80000D3C2F9A887B47F6409E2C3E6E7311DA764
+:10C8100077F81692BD44917B6B911E3B36F0DF0793
+:10C82000FAFE1D85F3B09EC42AAE7FD4C3FE40BC81
+:10C830001FD316CABAA640BA75F12F70BA3C1E5162
+:10C84000C3DF01F2A88542201F7A7F138F4B6D6FE3
+:10C85000E2F58FD60FA3BE7D55BC9CCF33396CA4B7
+:10C8600073B21FE9F50D96930612D03E6DE687E68A
+:10C870007A8DF4D2B52944E73E4F11D5BF336B8E84
+:10C8800053C918923B77E4F5D4A0AFED3DD63B2BCE
+:10C89000F0DE2143EE0CF2A327747ED4C4D3E36010
+:10C8A0003F237D8EF32C8C447A48CBB7CA08B11D48
+:10C8B000BE16D519C08F76867977A1FEB76F818BAA
+:10C8C000F6C94E9DAFEF5C9028A05E7524F287C438
+:10C8D00027C725C509589FF22097CF503FE7633EF1
+:10C8E000D1EF14302E98C7E95C043E86F86967647E
+:10C8F000D661942FD6099CEECDF366E64F4E1C4FC1
+:10C900000AF223E067313A3F827ABB979452FF0CD8
+:10C910007ED501FA3DEDCFA9366AA77DC6E9D5D807
+:10C920008FAFFE184272E84ED653338ABDF0BAF884
+:10C9300095C11F3AFFEDBB2FE1B93D635D1E89BD77
+:10C940002D117F17B83D6C604990BF485F973CC67A
+:10C95000ED42E6F3298B1EE47681BDABD5990F62DB
+:10C960005C186BD1D0FF8191B3784F6A3DD37227A9
+:10C97000C3B89CA92AC565D5A7F1B8AC7C7DDEDF1C
+:10C980001ED3427E8F461DFFA6791D642F684C8AF8
+:10C99000A77B94E68BFB539F84FCE57A3BC753AFA0
+:10C9A0001CC7E6C2780AA0C7101D0FB9AC2D0CE752
+:10C9B0002F24D5F4FBCCA93D73F0E6C1B72AD435BA
+:10C9C000D8EF131FB43890CE1B53173A709E26A68B
+:10C9D0006D7720DD36766ECFC57B0A8D73D6770DE9
+:10C9E000FC22E49618EC9F750ACAE95BD77A673E89
+:10C9F00018205FED69EBE9BC756398A1E7F84B700F
+:10CA00003C85E909D981719065FAF81FAEF0E4E33D
+:10CA1000F7F3E300C84CC6796186FE532906FFDEB2
+:10CA2000473EF673B4DFFBC8339DBB31CFCBC3FAAF
+:10CA3000FCDD52A16EC4F636623BE45F6AA1FD9054
+:10CA4000C944770DE9FFC17EA4617E1F935FE98130
+:10CA5000D7A63BECDFC22F3C6E8DBA05C73576B545
+:10CA6000A71EFB551BF94BFAFDDC6BF517BF3D46C6
+:10CA70008D477A357062ADAE7F1ECA560B02E978DB
+:10CA8000BF3EDFFB75396C2DB0E9F705CC9747E267
+:10CA90009B73567B7763BF8CB455E6F705CC97F84C
+:10CAA0003C0B30D69A84A1FDF316AB6C5A928CE7FE
+:10CAB0006715BE5F7EF4BE0BED00F3257F6A4BC6A3
+:10CAC000D5DB5B3BAC3D95F4302583FB576A64FEB8
+:10CAD0007BA9AAADF73D05D28580A7E85E68D37E25
+:10CAE000349E68DF0EE44768DF0EC47D68DF0E4CBD
+:10CAF000A37D3BB03CDAB703F3D1BE1D98FF708530
+:10CB0000B70BFB8B76EEC0F768E70EFC6ECA6ACFF8
+:10CB1000612C77F79815744FC4D315EA115CE7EBD5
+:10CB200090CB6F633DA5333DB4DE5B62F5757E75DA
+:10CB300015CD8F2D366A5260BCF5459DDE615E3F96
+:10CB40000CDC9FB6183EAFB5B248F74C2E0E13E979
+:10CB5000BE6CE3DEB1D1E8ED0EDDAF7F27F0157CD2
+:10CB6000CEBC144ACFBB2E39E9A95E8AA667F6A5CA
+:10CB7000487AE65CBA919EB32E25D073F6A514923E
+:10CB800093732E25D373EEA55BE879F7A59BE999FE
+:10CB90007B690A959B7769123DE75FBA9D9EF75CBA
+:10CBA0009A41CFBDAB3DFF97C6BFEB1117CEE3B89F
+:10CBB000359EDF61BA5E006D3A85F6CFEF1F24BB6C
+:10CBC000400F237BECEB6A01F10391FF5ED6F95530
+:10CBD000DEAF701E86DD77261FFD23EAAD39152AEC
+:10CBE0007D7F74B5F7DFA99CC3E1B006C685C4306C
+:10CBF000A2FFD40AF53FA89D6BDCEFFF0F9076747F
+:10CC0000D0008000000000001F8B08000000000022
+:10CC1000000BB5587B4C1CE7119F7DDCDD5E728FED
+:10CC200085C33604701703C6AE215E6CC010616701
+:10CC3000C158B622FEB8D22A3A2A5B5E886D55707A
+:10CC4000B50E14B554757CEBE0D4801F1C21ADFDEE
+:10CC50004F95935BBBB594BAB46A555CA5D2963A2E
+:10CC600029F48F0A5556AB4A5173562895822D41A7
+:10CC7000AB287195C89DF976973BEE78B8A97A965E
+:10CC80003D3BDF63BE99DF3CBEF90C20C2FC0E6069
+:10CC9000BFC702FEE32B0068C26FFA3D9F4B010C39
+:10CCA000804D00B7CB168F857D007FA7A12280CA5B
+:10CCB000C8596F871F60738CB3E6B703CC56E39CEB
+:10CCC000B8E8075CF7FED18E20517823B4AA7CE146
+:10CCD0001301CC509AFF41AF02508FE3A20AB28FEA
+:10CCE000E6DD6CFE70E98D13500730BDC3AB0965FE
+:10CCF000B972F6F6EAA5B1FA34FF8202DA33F90026
+:10CD000033516D2B8DBF1C0D2B44C125BBC3A8EF28
+:10CD1000FBAE144FF2D02A59280658EAD1ABD8BC42
+:10CD2000A629059B0138B20F5581B765F39B080D05
+:10CD3000F407D41115E0DD5E7D175B079224E1BA9C
+:10CD4000E3168470FC0CE7D6C9CE9498372FA1DE89
+:10CD500084EB2A38A6F15C897F6B5466F839380970
+:10CD60009C852FEABD8FCE3345D4BB066050F9A514
+:10CD700086668177D1D082C0EC6EA679CF27619389
+:10CD8000F817CB0E024A829B516D7F0CE57D189FF0
+:10CD9000840F2A71207135FC5903C0493A10CFEB3A
+:10CDA000414B277CB97AD5F4B7B6D1BE5307660B91
+:10CDB000C9CF97FDB3852A51174468FD1F4A6723E1
+:10CDC000E18C7D9198C0FC158EF18CCEF85EBD8B08
+:10CDD0005FD05C312B109D89EA619277A064F120CD
+:10CDE0009924CA20EA181FB75B500E5231E232AACA
+:10CDF00002C8FFFA05B9BB3A579F43BDDD11DAEF10
+:10CE0000F0A2ACBA69DDAEA8D6C9FCF0B9F1D6BAC9
+:10CE100048EE93C67D863F7A689F211ABE3DB8B51D
+:10CE20004BE6D511E6877094F499565EDA44F62104
+:10CE3000FE5FFF9CF8BF6CE1AF16123E8365887BF6
+:10CE400035852D6F6C61387D55EE5A65DFE9DEAEB4
+:10CE50005732E3DF55A0715D94876F6B118A73E0E1
+:10CE600051CF3A16E783CCEEAC38E7E4771F710177
+:10CE700016DF1718AE18DE22EAEBB2E3DB55002C02
+:10CE8000BE2BA2DAD0FF86BB1DE736EE4E3DF91B66
+:10CE90002D684AD79324D593FA75EAC94088F923B7
+:10CEA000B79E7060EE5DAF9E886C1EFD789DECD0E5
+:10CEB000C435EBC1AD27AC073F6178FEBFEA816D99
+:10CEC00067E5DD336FA6F0DC8F0C11C88F466BEC85
+:10CED00047C41BAF7AE441A4579F3EFB660AC707CD
+:10CEE0004449F6A82425B68FEAC5781C6B8787F1DC
+:10CEF000BB19EF824EC2DB03C7825FF2A7CF9FA6AA
+:10CF0000FCC5F342F2953B73215A8F7517F50990D2
+:10CF10003EE5C497C8F34FA7F57BA3579B217C42FE
+:10CF20006E1DB6E3F9633BF9A4817559F1C99D27DC
+:10CF3000508F0B1512CB8BD0E117C120BC827CB275
+:10CF4000B28C7627A7CB707E78270F23CCEC844257
+:10CF50007A0C97E2F73334C03D32ABE9748907921B
+:10CF60005BC2274770DF6009FA7D95FAE0D0D7C829
+:10CF7000CEAAB5E785A21389169497F0892AC191A4
+:10CF800068EB1E6A413DBC453CB3C94DF439FAFA21
+:10CF90006CC014C9D58B12E1E5DD6FC5DB5A72CFC9
+:10CFA000DBF82ED7A70268A1FC0750651ECFBBE8AF
+:10CFB000AFE046B8F4FCC77D565C5FF4DB795DA05A
+:10CFC0000187EB2E943634508C48B206F3789E5489
+:10CFD00010860F905EA89422495C7748684E90BEF8
+:10CFE000634A7E9E87E210B4403DE6E777ED785BCA
+:10CFF000EAB3EAEF787CE8CE1C26EDE5788251D4DE
+:10D00000E31CE1E86B079570F457B8EF0BE8D482A6
+:10D01000765CE7C41BFE0DD4E17A29CD0FFB97F3B4
+:10D020004E22FB87940E30F07C7F239FA45A38DA7F
+:10D03000F84F36AE404AA2FC196D5CDF3F576C9C3E
+:10D040005E8F4B2BF05A9EDF9A2A5471FF95FAD4CB
+:10D05000B59750DF6089A41EA1BA6336FE5540FE25
+:10D060004AB31B4698DD2A47E785DAF8FB1EB4630E
+:10D07000B409F5A8CED5C333F50814E483E22290B1
+:10D08000DCA0F227D050DFEFD97A1CAE8B818CF672
+:10D0900004EF09490FDA138CA068E437D7415241F5
+:10D0A000FE5CE59F4DAC79307A0C600BE1E1B2EEAD
+:10D0B000435FF3FC7BF02C5238DA427A16160BE011
+:10D0C00069C4055FC17C41FC22F8E7F136DC13B18D
+:10D0D0007807CF1064F065B4DFCA2F8707E1685086
+:10D0E0005F27CE06DEF3BE7337C35FCFF5F90BE6DD
+:10D0F00077E1470334B0FE6D83FD1FC7A577EE626D
+:10D100003C8C6DE0A74BF14686CF585C6374347E4F
+:10D1100084E5D54DBAC75CE975DBE9FE4239C3AF9A
+:10D12000CC420752BFF92DD886F9A2F7597DE0CD40
+:10D13000B8C465AEF75C038EF0C7AAC689741F5DDC
+:10D1400003F506FAF3F94F7F3AB48DF2FC5EF91E4F
+:10D15000AA07CE7A478EC3DFB2FD36B2A383D97950
+:10D16000AB8D3F4279714B4C3C95BF8E3D5FFC21AE
+:10D17000BFC20FCE78769E8C73A0013656E37956E7
+:10D180007DBC6C0EB7503CC8F7CAAF7B33F2B7D743
+:10D19000CEDF105D15D48869197E45BF8FD6A28970
+:10D1A000BB37CE2F47DED87ED80AD8B88D1E72B3D3
+:10D1B0003C0F1E908B3A32FC38659F379667D58BB3
+:10D1C0004BA550D4519D3B9FC8B3FAB38417223F5F
+:10D1D0005F058FA93E81E17989B3D639FE4BCF4BEC
+:10D1E0004CCE945D47428AC6915F429AB438A89269
+:10D1F000BD0F8C39C28387D896C65CFBC4440CC271
+:10D200005467309FA8DE65DBEB834BB3D45FD0EF70
+:10D2100053AC5B7E56EA911EF92398743FE8BED862
+:10D220006194EBAB5B9937FF6D5E7C9FF282EE29D8
+:10D230002F78ADBC68E75F43BD3FAAC3BAC5EE1FF8
+:10D240009D0FFBD7CE0FD8B77EBD1FDDE09E090630
+:10D250001675A805F8C5D25F06CE97309CD9BDF6E5
+:10D260009BA5B90103E5726E6DA20FFD2081D5CF9C
+:10D270007735BB0D01EB099C773D483976601C057D
+:10D280009F82AEF02A7ECC77B74EF6515F22A21D68
+:10D2900035B97E74E88C9D3F4E9C3BE318B726EC75
+:10D2A000C9F59F47E10DAAA7C395DF9057C3FB744B
+:10D2B000AFFEB02FA3BFF494681CEB6F84763009E7
+:10D2C000DF30307C8D298E5BEE778A293F50D50682
+:10D2D000AB95217F6F0183A3C96CBF1541928D1758
+:10D2E00083C901F61BA59062FC17B073255A060A84
+:10D2F000A3E5A0F1345F897E24BE0A0C46774292F2
+:10D30000D15D60B2F91A48319E90A23CDE6D02EB0D
+:10D31000236A4111687C2F6802ADAB079DF1FBC009
+:10D3200060B409F43B7374BFED3F554BF7F83F9C75
+:10D330003ABB1C4F4F566797FA8019BD967FFEDDAA
+:10D3400067F55B826B2242F7B350E32664E0629993
+:10D35000959FD9EB17EDF795D79590591FBBDCAF8B
+:10D36000F44F9A156BEBE3D061973A4DE70CFB79DC
+:10D37000A03E2DDD6FF54CFE36433FEA0B59DF43EF
+:10D380007DE0DE5C391BF585E3A2E6EBAFCF1DBF88
+:10D39000491F4DD4576B72FF26F2335A8BFA481A45
+:10D3A000C84613F1098EFCE4FB1AF2452C0E58DF37
+:10D3B00012D041A579ECB38BFB59104DB07D831889
+:10D3C0005723B5695ED76DFE5AFEAAEF82B4FE867A
+:10D3D000158CEDB14EDAE7BC8B02FDFA76A6B706E6
+:10D3E0008A98F92E3A8AEFA267995D55342F3B79D6
+:10D3F0002BF90CEAA3B2F31694D23C8A1727FE3F0E
+:10D40000A47B10DF7FB7CF9A6ECAE7A839E3A6BE28
+:10D4100024FAE39FB9E93E3C6EBF2B7BED388133A4
+:10D42000F58C77EBFC14E9B730517E9DE2766142D2
+:10D4300060FDC9C2F9B2EBA4DCC25BFFFADD637A1E
+:10D440000FE03C7B9BC239161F6481D440416FE9D9
+:10D450000FED9AD6C4DE7FB048EF15E71E5D78EB7E
+:10D46000CBD63D3A21D8F7A8F950A823BE4AA13817
+:10D470003CF9F8207C9BF61D94D41BB8EFE4D587CB
+:10D4800035DD1971997DAFF28AFC9D5F913EAA5BF3
+:10D490001D91D3F8E4E02FAFBC2FE947EF26475F9B
+:10D4A0005E099FBE4372E85DADACED4771C2739FEC
+:10D4B000FCF2C005935C7015B9597ECCF653A03FC1
+:10D4C000DC4DFEE4267ECFFC9BEDB78B76BCA260E4
+:10D4D0008EFC9D6736B17E526854350DF1CA6BD310
+:10D4E00020138F9ECED65E8ACF3C51E6283FF314A0
+:10D4F000DB9FD57B56FCFFC2A97E7E455FE3C4E37C
+:10D500007F00F33D945E90130000000000000000D7
+:10D51000000000400000000000000000000000408B
+:10D5200000000000000000000000002800000000D3
+:10D5300000000000000000100000000000000000DB
+:10D54000000000400000000000000000000000108B
+:10D5500000000000000000000000000800000000C3
+:10D5600000000000000000000000000000000000BB
+:10D570000000003D00000000000000000000003C32
+:10D58000000000000000000000000000000000009B
+:10D590000000000000000008000000000000000083
+:10D5A0000000000000000000000000000000000C6F
+:10D5B00000000000000000000000000E000000005D
+:10D5C0000000000000000004000000000000000057
+:10D5D0000000001800000000000000000000001C17
+:10D5E00000000000000000000000001C000000001F
+:10D5F0000000000000000013000000000000000018
+:10D600000000003E000000000000000000000001DB
+:10D610000000000000000000000000020000000008
+:10D6200000000000000000010000000000000000F9
+:10D63000000000100000000000000000000000508A
+:10D6400000000000000000000000000000000000DA
+:10D6500000000000000000030000000000000000C7
+:10D66000000000AB00000000000000000000000807
+:10D6700000000000000000000000C00000100000DA
+:10D68000000000080000C0080010000000000002B8
+:10D690000000C000001000000000001000009C0806
+:10D6A00000040000000000040000C0800010000022
+:10D6B000000000040000C08800100000000000020C
+:10D6C0000000C0800010000000000010000093382F
+:10D6D0000001000400000001000093400000000071
+:10D6E0000000000200009348000000000000000855
+:10D6F0000000934C00000000000000020000935066
+:10D7000000000000000000080000969800400000A3
+:10D710000000004000009358008000000000004816
+:10D7200000009458004000000000000800009468C9
+:10D730000040000000000018000630100028000023
+:10D7400000000028000099500008000000000001BF
+:10D7500000009951000800000000000100009952EB
+:10D760000008000000000001000020080010000078
+:10D770000000001000002000000000000000000871
+:10D7800000009BB80000000000000008000000013D
+:10D790000000000000000000000000020000000087
+:10D7A0000000000000000003000000000000000076
+:10D7B0000000000400000000000000000000000560
+:10D7C0000000000000000000000000060000000053
+:10D7D0000000000000000007000000000000000042
+:10D7E0000000000800000000000000000000000928
+:10D7F00000000000000000000000000A000000001F
+:10D80000000000000000000B00000000000000000D
+:10D810000000000C000000000000000000000001FB
+:10D8200000000000000000000000000900000000EF
+:10D8300000000000000000020000000000000000E6
+:10D840000000C4C000000000000000200000C4E68A
+:10D850000000000000000001000060000020000047
+:10D860000000002000007300000800000000000815
+:10D8700000009BF0000000000000000100009B90F1
+:10D88000000000000000000800009B930000000062
+:10D890000000000100009B9100000000000000015A
+:10D8A00000009B96000000000000000100009B9714
+:10D8B00000000000000000008000000000000000E8
+:10D8C00000000000800000000000000000000000D8
+:10D8D0000000000000000000000000000000000048
+:10D8E0000000000000000000000000000000000038
+:10D8F0000000000000000000000000000000000028
+:10D900000000000000000000000000000006000011
+:10D91000000000000000002000009B9800000000B4
+:10D920000000000100009BD800000000000000087B
+:10D9300000000053000000000000000000009BE019
+:10D94000000000000000000200009BE40000000056
+:10D950000000000100009BE5000000000000000145
+:10D9600000000009000000000000000000000001AD
+:10D970000000000000000000000000440000000063
+:10D980000000000000000001000000000000000096
+:10D9900000000050000000000000000000000089AE
+:10D9A00000000000000000008000000000000000F7
+:10D9B0000000000000000000000000000000000067
+:10D9C000000016C800000000000000080000200849
+:10D9D0000010000000000010000020000000000007
+:10D9E0000000000800001AA800000000000000105D
+:10D9F00000001AB800000000000000100000000144
+:10DA00000000000000000000000000020000000014
+:10DA100000000000000017E0000800000000000106
+:10DA2000000017E10008000000000001000017E2FC
+:10DA30000008000000000001000620780038000007
+:10DA400000000038000016F0000000000000000296
+:10DA5000000016F200000000000000020000A040DC
+:10DA60000000000000000020800000000000000016
+:10DA7000000000000000E000002000000000002086
+:10DA80000000F30000080000000000080000170874
+:10DA900000000000000000D80000174F0000000048
+:10DAA0000000000100001727000000000000000136
+:10DAB0008000000000000000000000008000000066
+:10DAC0000000000000000000000000000000000056
+:10DAD0000000000000000000000000000000000046
+:10DAE0000000000000000000000000000000000036
+:10DAF0000000000000000000000000000000000026
+:10DB00000000000000001788000000000000000175
+:10DB1000000017C8000000000000000800000051CD
+:10DB20000000000000000000000017B0000000002E
+:10DB300000000004000017B4000000000000000412
+:10DB4000000017B80000000000000004000017BC2F
+:10DB50000000000000000008000017A800000000FE
+:10DB600000000008000017D80000000000000002BC
+:10DB70000006000000400000000000400000C0005F
+:10DB800000400000000000400000C02E00400000E7
+:10DB9000000000010000C000004000020000000181
+:10DBA0000000C00100400002000000000000E20090
+:10DBB00000200000000000200000E2040002000835
+:10DBC00000200002800000000000000000000000B3
+:10DBD0000000E20000080020000000040000F50042
+:10DBE00000280000000000280000F640001000009F
+:10DBF000000000100000F64A0010000000000001C4
+:10DC00000000F6C000200000000000200000F6C068
+:10DC100000020020000000020000F30000400000AD
+:10DC2000000000400000200800100000000000106C
+:10DC3000000020000000000000000008000011A803
+:10DC40000008000000000001000011A90008000009
+:10DC500000000001000011AA0008000000000001FF
+:10DC600000004000002000040000001000005900E7
+:10DC700000300018000000100000590800300018A3
+:10DC80000000000200005700000800000000000132
+:10DC900000005701000800000000000100001158BA
+:10DCA0000000000000000001000011600000000002
+:10DCB00000000010000011AC00080000000000048B
+:10DCC0000000400000200000000000200000530081
+:10DCD0000010000000000010000000000000000024
+:10DCE0000000000000000000000000000000000034
+:10DCF0000000000000000000000000000000000024
+:10DD0000000000000000000000001470000000008F
+:10DD100000000001000014B0000000000000000836
+:10DD20000000005000000000000000000000147817
+:10DD300000000000000000040000147C000000004F
+:10DD40000000000400001480000000000000000437
+:10DD5000000014840000000000000004000014888B
+:10DD6000000000000000000800002AF00080000011
+:10DD70000000008000000001000000000000000022
+:10DD8000000020080010000000000010000020002B
+:10DD9000000000000000000800002C7000080000D7
+:10DDA0000000000100002C710008000000000001CC
+:10DDB00000002C7200080000000000010000415823
+:10DDC0000038000000000038800000000000000063
+:10DDD0000000000000002C440008000000000002C9
+:10DDE00000002C46000800000000000200002C5437
+:10DDF000001000000000000400002EB00000000031
+:10DE00000000002000006000002000000000002052
+:10DE1000000073000008000000000008000000007F
+:10DE200000000000000000000000000000000000F2
+:10DE300000000000000000000000000000000000E2
+:10DE400000000000000000000000000000002F584B
+:10DE5000000000000000000100002F9800000000FA
+:10DE6000000000080000005000000000000000005A
+:10DE700000002F80000000000000000400002F843C
+:10DE8000000000000000000400002F8800000000D7
+:10DE90000000000400002F8C0000000000000008BB
+:10DEA00000002FA800000000000000028000000019
+:10DEB00000000000000000008000000000000000E2
+:10DEC00000000000800000000000000000000000D2
+:10DED0008000000000000000000000000000312869
+:10DEE00000080000000000010000312900080000C7
+:10DEF0000000000100062A20260000400000000863
+:10DF00000000A0000000000000002000000040C150
+:10DF10000000000000000001000040F000000000D0
+:10DF2000000000028000000000000000000000006F
+:10DF30000000600000200000000000080000400019
+:10DF4000000800000000000100004001000800007F
+:10DF50000000000100004040000800040000000232
+:10DF60000000406000080004000000040000408041
+:10DF7000000800000000000400004000000800004D
+:10DF8000000000040000400400080000000000043D
+:10DF90000000404000000000000000080000404871
+:10DFA00000000000000000080000800000000000E9
+:10DFB00000000010000050400001000400000001BB
+:10DFC0000000500000000000000000200000500889
+:10DFD00000100000000000040000500C00100000C1
+:10DFE00000000001000052C7000000000000000116
+:10DFF000000052C6000000000000000100003000D8
+:10E000000040002000000004000030040040002018
+:10E010000000000400003008004000200000000262
+:10E020000000300A00400020000000020000300C18
+:10E0300000400020000000010000300D00400020E2
+:10E04000000000010000300E004000200000000130
+:10E0500000003010004000200000000400003014D8
+:10E0600000400020000000040000301800400020A4
+:10E07000000000040000301C0040002000000004EC
+:10E080000000C00001000080000800040000C0047F
+:10E0900001000080000800040000000A00000000E9
+:10E0A000000000000000C0680100008000000001C6
+:10E0B0000000C06901000080000000010000C06C89
+:10E0C00001000080000000020000C06E010000801E
+:10E0D000000000020000C070010000800000000489
+:10E0E0000000C07401000080000000040000C06651
+:10E0F00001000080000000020000C06401000080F8
+:10E10000000000010000C06001000080000000026B
+:10E110000000C06201000080000000020000C0504A
+:10E1200001000080000000040000C05401000080D5
+:10E13000000000040000C05801000080000000043E
+:10E140000000C05C01000080000000040000C07CF2
+:10E1500001000080000000010000C07D010000807F
+:10E160000000000100001018001000000000000472
+:10E170000000109000100000000000040000109843
+:10E18000001000000000000400001110000000005A
+:10E190000000000200001112000000000000000258
+:10E1A0000000111400000000000000020000111621
+:10E1B00000000000000000020000604000080000B5
+:10E1C00000000002000060420008000000000002A1
+:10E1D00000006044000800000000000200006046EB
+:10E1E000000800000000000200006080000800003D
+:10E1F00000000008000060000008000000000002AD
+:10E20000000060020008000000000001000060043F
+:10E210000008000000000002000060C000080000CC
+:10E220000000000800006100000800000000000479
+:10E2300000006104000800000000000100006140CF
+:10E240000008000000000002000061440008000017
+:10E25000000000020000614200080000000000020F
+:10E260000000618000080000000000040000300091
+:10E27000000800000000000200003002000800005A
+:10E28000000000010000300400080000000000024F
+:10E290000000304000080000000000020000304490
+:10E2A00000080000000000020000304600080000E6
+:10E2B00000000002000036600008000000000008B6
+:10E2C00000003080000800000000000200003084E0
+:10E2D0000008000000000002000036A00008000056
+:10E2E000000000080000804000080000000000015D
+:10E2F0000000804100080000000000010000804292
+:10E300000008000000000001000080430008000039
+:10E310000000000100008000000800000000000272
+:10E3200000008002000800000000000100008004DE
+:10E330000008000000000002000080C0000800008B
+:10E3400000000002000080C200080000000000027F
+:10E35000000080C40008000000000002000080806F
+:10E36000000800000000000100008081000800009B
+:10E370000000000100008082000800000000000191
+:10E38000000080830008000000000001000080847D
+:10E390000008000000000001000080850008000067
+:10E3A000000000010000808600080000000000015D
+:10E3B0000000600000080000000000020000600291
+:10E3C00000080000000000010000600400080000D8
+:10E3D000000000020000604200C0001800000002BF
+:10E3E0000000604000C00018000000020000604C07
+:10E3F00000C00018000000080000604400C00018C1
+:10E40000000000080000605700C000180000000174
+:10E410000000605400C000180000000200006056B8
+:10E4200000C0001800000001000066400008000065
+:10E4300000000008000066800008000000000008DE
+:10E44000000066C000080000000000080000DA823A
+:10E4500000180000000000020000DBA00000000027
+:10E46000000000000000E0000000000000000004C8
+:10E470000000D10000000000000000040000D104F2
+:10E4800000000000000000040000D10800000000AF
+:10E49000000000040000D10C000000000000000497
+:10E4A0000000D11000000000000000040000D114A2
+:10E4B00000000000000000040000D118000000006F
+:10E4C000000000040000D100000000000000002057
+:10E4D0000000928000000000000000040000928014
+:10E4E00000000000000000280000805000A800008C
+:10E4F000000000010000805400A80000000000019E
+:10E50000000080000000000000000050000080506B
+:10E510000000000000000010000096000000000055
+:10E52000000000040000940000000000000000044F
+:10E5300000009404000000000000000400009408A3
+:10E5400000000000000000040000940C0000000027
+:10E55000000000040000941000000000000000040F
+:10E560000000941400000000000000040000941853
+:10E570000000000000000004000094000000000003
+:10E580000000004000009420000000000000000493
+:10E590000000942400000000000000040000942803
+:10E5A00000000000000000040000941C00000000B7
+:10E5B000000000040000943000000000000000048F
+:10E5C0000000942C000000000000000400009434BF
+:10E5D0000000000000000004000092840000000021
+:10E5E0000000000400009280000000000000000411
+:10E5F000000092900000000000000004000092A4BF
+:10E60000000000000000000400009438000000003A
+:10E61000000000040000943C000000000000000422
+:10E620000000B98800000000000000000000D000D9
+:10E6300000000000000000040000B1000000000025
+:10E64000000000040000B10400000000000000040D
+:10E650000000B10800000000000000040000B1004C
+:10E6600000000000000000100000BCB0000000002E
+:10E67000000000040000BCB4000000000000000422
+:10E680000000BCB000000000000000480000D86896
+:10E6900000000000000000040000D860000000003E
+:10E6A000000000040000D864000000000000000426
+:10E6B0000000D86C00000000000000040000D860DA
+:10E6C00000000000000000100000D8500000000012
+:10E6D000000000040000D854000000000000000406
+:10E6E0000000D85000000000000000080000D4C85E
+:10E6F00000000000000000080000D4D80000000066
+:10E700000000008000000010000000000000000079
+:10E710000000D4D800000000000000080000000045
+:08E72000070C1E0000000000C0
+:00000001FF
--- linux-4.4.0.orig/fs/9p/acl.c
+++ linux-4.4.0/fs/9p/acl.c
@@ -272,7 +272,7 @@
 		if (IS_ERR(acl))
 			return PTR_ERR(acl);
 		else if (acl) {
-			retval = posix_acl_valid(acl);
+			retval = posix_acl_valid(inode->i_sb->s_user_ns, acl);
 			if (retval)
 				goto err_out;
 		}
@@ -282,32 +282,28 @@
 	switch (handler->flags) {
 	case ACL_TYPE_ACCESS:
 		if (acl) {
-			umode_t mode = inode->i_mode;
-			retval = posix_acl_equiv_mode(acl, &mode);
-			if (retval < 0)
+			struct iattr iattr = { 0 };
+			struct posix_acl *old_acl = acl;
+
+			retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
+			if (retval)
 				goto err_out;
-			else {
-				struct iattr iattr;
-				if (retval == 0) {
-					/*
-					 * ACL can be represented
-					 * by the mode bits. So don't
-					 * update ACL.
-					 */
-					acl = NULL;
-					value = NULL;
-					size = 0;
-				}
-				/* Updte the mode bits */
-				iattr.ia_mode = ((mode & S_IALLUGO) |
-						 (inode->i_mode & ~S_IALLUGO));
-				iattr.ia_valid = ATTR_MODE;
-				/* FIXME should we update ctime ?
-				 * What is the following setxattr update the
-				 * mode ?
+			if (!acl) {
+				/*
+				 * ACL can be represented
+				 * by the mode bits. So don't
+				 * update ACL.
 				 */
-				v9fs_vfs_setattr_dotl(dentry, &iattr);
+				posix_acl_release(old_acl);
+				value = NULL;
+				size = 0;
 			}
+			iattr.ia_valid = ATTR_MODE;
+			/* FIXME should we update ctime ?
+			 * What is the following setxattr update the
+			 * mode ?
+			 */
+			v9fs_vfs_setattr_dotl(dentry, &iattr);
 		}
 		break;
 	case ACL_TYPE_DEFAULT:
--- linux-4.4.0.orig/fs/9p/cache.c
+++ linux-4.4.0/fs/9p/cache.c
@@ -243,14 +243,14 @@
 	if (!v9inode->fscache)
 		return;
 
-	spin_lock(&v9inode->fscache_lock);
+	mutex_lock(&v9inode->fscache_lock);
 
 	if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
 		v9fs_cache_inode_flush_cookie(inode);
 	else
 		v9fs_cache_inode_get_cookie(inode);
 
-	spin_unlock(&v9inode->fscache_lock);
+	mutex_unlock(&v9inode->fscache_lock);
 }
 
 void v9fs_cache_inode_reset_cookie(struct inode *inode)
@@ -264,7 +264,7 @@
 
 	old = v9inode->fscache;
 
-	spin_lock(&v9inode->fscache_lock);
+	mutex_lock(&v9inode->fscache_lock);
 	fscache_relinquish_cookie(v9inode->fscache, 1);
 
 	v9ses = v9fs_inode2v9ses(inode);
@@ -274,7 +274,7 @@
 	p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n",
 		 inode, old, v9inode->fscache);
 
-	spin_unlock(&v9inode->fscache_lock);
+	mutex_unlock(&v9inode->fscache_lock);
 }
 
 int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
--- linux-4.4.0.orig/fs/9p/v9fs.c
+++ linux-4.4.0/fs/9p/v9fs.c
@@ -59,6 +59,8 @@
 	Opt_cache_loose, Opt_fscache, Opt_mmap,
 	/* Access options */
 	Opt_access, Opt_posixacl,
+	/* Lock timeout option */
+	Opt_locktimeout,
 	/* Error token */
 	Opt_err
 };
@@ -78,6 +80,7 @@
 	{Opt_cachetag, "cachetag=%s"},
 	{Opt_access, "access=%s"},
 	{Opt_posixacl, "posixacl"},
+	{Opt_locktimeout, "locktimeout=%u"},
 	{Opt_err, NULL}
 };
 
@@ -126,6 +129,7 @@
 #ifdef CONFIG_9P_FSCACHE
 	v9ses->cachetag = NULL;
 #endif
+	v9ses->session_lock_timeout = P9_LOCK_TIMEOUT;
 
 	if (!opts)
 		return 0;
@@ -298,6 +302,23 @@
 #endif
 			break;
 
+		case Opt_locktimeout:
+			r = match_int(&args[0], &option);
+			if (r < 0) {
+				p9_debug(P9_DEBUG_ERROR,
+					 "integer field, but no integer?\n");
+				ret = r;
+				continue;
+			}
+			if (option < 1) {
+				p9_debug(P9_DEBUG_ERROR,
+					 "locktimeout must be a greater than zero integer.\n");
+				ret = -EINVAL;
+				continue;
+			}
+			v9ses->session_lock_timeout = (long)option * HZ;
+			break;
+
 		default:
 			continue;
 		}
@@ -436,10 +457,9 @@
 	}
 
 #ifdef CONFIG_9P_FSCACHE
-	if (v9ses->fscache) {
+	if (v9ses->fscache)
 		v9fs_cache_session_put_cookie(v9ses);
-		kfree(v9ses->cachetag);
-	}
+	kfree(v9ses->cachetag);
 #endif
 	kfree(v9ses->uname);
 	kfree(v9ses->aname);
--- linux-4.4.0.orig/fs/9p/v9fs.h
+++ linux-4.4.0/fs/9p/v9fs.h
@@ -116,6 +116,7 @@
 	struct list_head slist; /* list of sessions registered with v9fs */
 	struct backing_dev_info bdi;
 	struct rw_semaphore rename_sem;
+	long session_lock_timeout; /* retry interval for blocking locks */
 };
 
 /* cache_validity flags */
@@ -123,7 +124,7 @@
 
 struct v9fs_inode {
 #ifdef CONFIG_9P_FSCACHE
-	spinlock_t fscache_lock;
+	struct mutex fscache_lock;
 	struct fscache_cookie *fscache;
 #endif
 	struct p9_qid qid;
--- linux-4.4.0.orig/fs/9p/v9fs_vfs.h
+++ linux-4.4.0/fs/9p/v9fs_vfs.h
@@ -40,6 +40,9 @@
  */
 #define P9_LOCK_TIMEOUT (30*HZ)
 
+/* flags for v9fs_stat2inode() & v9fs_stat2inode_dotl() */
+#define V9FS_STAT2INODE_KEEP_ISIZE 1
+
 extern struct file_system_type v9fs_fs_type;
 extern const struct address_space_operations v9fs_addr_operations;
 extern const struct file_operations v9fs_file_operations;
@@ -61,8 +64,10 @@
 		    struct inode *inode, umode_t mode, dev_t);
 void v9fs_evict_inode(struct inode *inode);
 ino_t v9fs_qid2ino(struct p9_qid *qid);
-void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
-void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *);
+void v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
+		      struct super_block *sb, unsigned int flags);
+void v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
+			   unsigned int flags);
 int v9fs_dir_release(struct inode *inode, struct file *filp);
 int v9fs_file_open(struct inode *inode, struct file *file);
 void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
@@ -83,4 +88,18 @@
 }
 
 int v9fs_open_to_dotl_flags(int flags);
+
+static inline void v9fs_i_size_write(struct inode *inode, loff_t i_size)
+{
+	/*
+	 * 32-bit need the lock, concurrent updates could break the
+	 * sequences and make i_size_read() loop forever.
+	 * 64-bit updates are atomic and can skip the locking.
+	 */
+	if (sizeof(i_size) > sizeof(long))
+		spin_lock(&inode->i_lock);
+	i_size_write(inode, i_size);
+	if (sizeof(i_size) > sizeof(long))
+		spin_unlock(&inode->i_lock);
+}
 #endif
--- linux-4.4.0.orig/fs/9p/vfs_addr.c
+++ linux-4.4.0/fs/9p/vfs_addr.c
@@ -49,8 +49,9 @@
  * @page: structure to page
  *
  */
-static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
+static int v9fs_fid_readpage(void *data, struct page *page)
 {
+	struct p9_fid *fid = data;
 	struct inode *inode = page->mapping->host;
 	struct bio_vec bvec = {.bv_page = page, .bv_len = PAGE_SIZE};
 	struct iov_iter to;
@@ -121,7 +122,8 @@
 	if (ret == 0)
 		return ret;
 
-	ret = read_cache_pages(mapping, pages, (void *)v9fs_vfs_readpage, filp);
+	ret = read_cache_pages(mapping, pages, v9fs_fid_readpage,
+			filp->private_data);
 	p9_debug(P9_DEBUG_VFS, "  = %d\n", ret);
 	return ret;
 }
--- linux-4.4.0.orig/fs/9p/vfs_dir.c
+++ linux-4.4.0/fs/9p/vfs_dir.c
@@ -76,15 +76,6 @@
 	return rettype;
 }
 
-static void p9stat_init(struct p9_wstat *stbuf)
-{
-	stbuf->name  = NULL;
-	stbuf->uid   = NULL;
-	stbuf->gid   = NULL;
-	stbuf->muid  = NULL;
-	stbuf->extension = NULL;
-}
-
 /**
  * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
  * @filp: opened file structure
@@ -114,7 +105,6 @@
 	int err = 0;
 	struct p9_fid *fid;
 	int buflen;
-	int reclen = 0;
 	struct p9_rdir *rdir;
 	struct kvec kvec;
 
@@ -145,15 +135,12 @@
 			rdir->tail = n;
 		}
 		while (rdir->head < rdir->tail) {
-			p9stat_init(&st);
 			err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
 					  rdir->tail - rdir->head, &st);
-			if (err) {
+			if (err <= 0) {
 				p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
-				p9stat_free(&st);
 				return -EIO;
 			}
-			reclen = st.size+2;
 
 			over = !dir_emit(ctx, st.name, strlen(st.name),
 					 v9fs_qid2ino(&st.qid), dt_type(&st));
@@ -161,8 +148,8 @@
 			if (over)
 				return 0;
 
-			rdir->head += reclen;
-			ctx->pos += reclen;
+			rdir->head += err;
+			ctx->pos += err;
 		}
 	}
 }
--- linux-4.4.0.orig/fs/9p/vfs_file.c
+++ linux-4.4.0/fs/9p/vfs_file.c
@@ -74,7 +74,7 @@
 					v9fs_proto_dotu(v9ses));
 	fid = file->private_data;
 	if (!fid) {
-		fid = v9fs_fid_clone(file->f_path.dentry);
+		fid = v9fs_fid_clone(file_dentry(file));
 		if (IS_ERR(fid))
 			return PTR_ERR(fid);
 
@@ -100,7 +100,7 @@
 		 * because we want write after unlink usecase
 		 * to work.
 		 */
-		fid = v9fs_writeback_fid(file->f_path.dentry);
+		fid = v9fs_writeback_fid(file_dentry(file));
 		if (IS_ERR(fid)) {
 			err = PTR_ERR(fid);
 			mutex_unlock(&v9inode->v_mutex);
@@ -154,6 +154,7 @@
 	uint8_t status = P9_LOCK_ERROR;
 	int res = 0;
 	unsigned char fl_type;
+	struct v9fs_session_info *v9ses;
 
 	fid = filp->private_data;
 	BUG_ON(fid == NULL);
@@ -189,6 +190,8 @@
 	if (IS_SETLKW(cmd))
 		flock.flags = P9_LOCK_FLAGS_BLOCK;
 
+	v9ses = v9fs_inode2v9ses(file_inode(filp));
+
 	/*
 	 * if its a blocked request and we get P9_LOCK_BLOCKED as the status
 	 * for lock request, keep on trying
@@ -202,8 +205,17 @@
 			break;
 		if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
 			break;
-		if (schedule_timeout_interruptible(P9_LOCK_TIMEOUT) != 0)
+		if (schedule_timeout_interruptible(v9ses->session_lock_timeout)
+				!= 0)
 			break;
+		/*
+		 * p9_client_lock_dotl overwrites flock.client_id with the
+		 * server message, free and reuse the client name
+		 */
+		if (flock.client_id != fid->clnt->name) {
+			kfree(flock.client_id);
+			flock.client_id = fid->clnt->name;
+		}
 	}
 
 	/* map 9p status to VFS status */
@@ -235,6 +247,8 @@
 		locks_lock_file_wait(filp, fl);
 		fl->fl_type = fl_type;
 	}
+	if (flock.client_id != fid->clnt->name)
+		kfree(flock.client_id);
 out:
 	return res;
 }
@@ -269,7 +283,7 @@
 
 	res = p9_client_getlock_dotl(fid, &glock);
 	if (res < 0)
-		return res;
+		goto out;
 	/* map 9p lock type to os lock type */
 	switch (glock.type) {
 	case P9_LOCK_TYPE_RDLCK:
@@ -290,7 +304,9 @@
 			fl->fl_end = glock.start + glock.length - 1;
 		fl->fl_pid = glock.proc_id;
 	}
-	kfree(glock.client_id);
+out:
+	if (glock.client_id != fid->clnt->name)
+		kfree(glock.client_id);
 	return res;
 }
 
@@ -430,7 +446,11 @@
 		i_size = i_size_read(inode);
 		if (iocb->ki_pos > i_size) {
 			inode_add_bytes(inode, iocb->ki_pos - i_size);
-			i_size_write(inode, iocb->ki_pos);
+			/*
+			 * Need to serialize against i_size_write() in
+			 * v9fs_stat2inode()
+			 */
+			v9fs_i_size_write(inode, iocb->ki_pos);
 		}
 		return retval;
 	}
@@ -508,6 +528,7 @@
 	v9inode = V9FS_I(inode);
 	mutex_lock(&v9inode->v_mutex);
 	if (!v9inode->writeback_fid &&
+	    (vma->vm_flags & VM_SHARED) &&
 	    (vma->vm_flags & VM_WRITE)) {
 		/*
 		 * clone a fid and add it to writeback_fid
@@ -516,7 +537,7 @@
 		 * because we want write after unlink usecase
 		 * to work.
 		 */
-		fid = v9fs_writeback_fid(filp->f_path.dentry);
+		fid = v9fs_writeback_fid(file_dentry(filp));
 		if (IS_ERR(fid)) {
 			retval = PTR_ERR(fid);
 			mutex_unlock(&v9inode->v_mutex);
@@ -603,12 +624,14 @@
 	struct writeback_control wbc = {
 		.nr_to_write = LONG_MAX,
 		.sync_mode = WB_SYNC_ALL,
-		.range_start = vma->vm_pgoff * PAGE_SIZE,
+		.range_start = (loff_t)vma->vm_pgoff * PAGE_SIZE,
 		 /* absolute end, byte at end included */
-		.range_end = vma->vm_pgoff * PAGE_SIZE +
+		.range_end = (loff_t)vma->vm_pgoff * PAGE_SIZE +
 			(vma->vm_end - vma->vm_start - 1),
 	};
 
+	if (!(vma->vm_flags & VM_SHARED))
+		return;
 
 	p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma);
 
--- linux-4.4.0.orig/fs/9p/vfs_inode.c
+++ linux-4.4.0/fs/9p/vfs_inode.c
@@ -101,7 +101,7 @@
 	int res;
 	int mode = stat->mode;
 
-	res = mode & S_IALLUGO;
+	res = mode & 0777; /* S_IRWXUGO */
 	if (v9fs_proto_dotu(v9ses)) {
 		if ((mode & P9_DMSETUID) == P9_DMSETUID)
 			res |= S_ISUID;
@@ -244,7 +244,7 @@
 		return NULL;
 #ifdef CONFIG_9P_FSCACHE
 	v9inode->fscache = NULL;
-	spin_lock_init(&v9inode->fscache_lock);
+	mutex_init(&v9inode->fscache_lock);
 #endif
 	v9inode->writeback_fid = NULL;
 	v9inode->cache_validity = 0;
@@ -483,6 +483,9 @@
 
 	if (v9inode->qid.type != st->qid.type)
 		return 0;
+
+	if (v9inode->qid.path != st->qid.path)
+		return 0;
 	return 1;
 }
 
@@ -535,7 +538,7 @@
 	if (retval)
 		goto error;
 
-	v9fs_stat2inode(st, inode, sb);
+	v9fs_stat2inode(st, inode, sb, 0);
 	v9fs_cache_inode_get_cookie(inode);
 	unlock_new_inode(inode);
 	return inode;
@@ -1071,7 +1074,7 @@
 	if (IS_ERR(st))
 		return PTR_ERR(st);
 
-	v9fs_stat2inode(st, d_inode(dentry), d_inode(dentry)->i_sb);
+	v9fs_stat2inode(st, d_inode(dentry), d_inode(dentry)->i_sb, 0);
 	generic_fillattr(d_inode(dentry), stat);
 
 	p9stat_free(st);
@@ -1094,7 +1097,7 @@
 	struct p9_wstat wstat;
 
 	p9_debug(P9_DEBUG_VFS, "\n");
-	retval = inode_change_ok(d_inode(dentry), iattr);
+	retval = setattr_prepare(dentry, iattr);
 	if (retval)
 		return retval;
 
@@ -1149,12 +1152,13 @@
  * @stat: Plan 9 metadata (mistat) structure
  * @inode: inode to populate
  * @sb: superblock of filesystem
+ * @flags: control flags (e.g. V9FS_STAT2INODE_KEEP_ISIZE)
  *
  */
 
 void
 v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
-	struct super_block *sb)
+		 struct super_block *sb, unsigned int flags)
 {
 	umode_t mode;
 	char ext[32];
@@ -1195,10 +1199,11 @@
 	mode = p9mode2perm(v9ses, stat);
 	mode |= inode->i_mode & ~S_IALLUGO;
 	inode->i_mode = mode;
-	i_size_write(inode, stat->length);
 
+	if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))
+		v9fs_i_size_write(inode, stat->length);
 	/* not real number of blocks, but 512 byte ones ... */
-	inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
+	inode->i_blocks = (stat->length + 512 - 1) >> 9;
 	v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
 }
 
@@ -1386,9 +1391,9 @@
 {
 	int umode;
 	dev_t rdev;
-	loff_t i_size;
 	struct p9_wstat *st;
 	struct v9fs_session_info *v9ses;
+	unsigned int flags;
 
 	v9ses = v9fs_inode2v9ses(inode);
 	st = p9_client_stat(fid);
@@ -1401,16 +1406,13 @@
 	if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
 		goto out;
 
-	spin_lock(&inode->i_lock);
 	/*
 	 * We don't want to refresh inode->i_size,
 	 * because we may have cached data
 	 */
-	i_size = inode->i_size;
-	v9fs_stat2inode(st, inode, inode->i_sb);
-	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
-		inode->i_size = i_size;
-	spin_unlock(&inode->i_lock);
+	flags = (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) ?
+		V9FS_STAT2INODE_KEEP_ISIZE : 0;
+	v9fs_stat2inode(st, inode, inode->i_sb, flags);
 out:
 	p9stat_free(st);
 	kfree(st);
--- linux-4.4.0.orig/fs/9p/vfs_inode_dotl.c
+++ linux-4.4.0/fs/9p/vfs_inode_dotl.c
@@ -87,6 +87,9 @@
 
 	if (v9inode->qid.type != st->qid.type)
 		return 0;
+
+	if (v9inode->qid.path != st->qid.path)
+		return 0;
 	return 1;
 }
 
@@ -140,7 +143,7 @@
 	if (retval)
 		goto error;
 
-	v9fs_stat2inode_dotl(st, inode);
+	v9fs_stat2inode_dotl(st, inode, 0);
 	v9fs_cache_inode_get_cookie(inode);
 	retval = v9fs_get_acl(inode, fid);
 	if (retval)
@@ -495,7 +498,7 @@
 	if (IS_ERR(st))
 		return PTR_ERR(st);
 
-	v9fs_stat2inode_dotl(st, d_inode(dentry));
+	v9fs_stat2inode_dotl(st, d_inode(dentry), 0);
 	generic_fillattr(d_inode(dentry), stat);
 	/* Change block size to what the server returned */
 	stat->blksize = st->st_blksize;
@@ -560,7 +563,7 @@
 
 	p9_debug(P9_DEBUG_VFS, "\n");
 
-	retval = inode_change_ok(inode, iattr);
+	retval = setattr_prepare(dentry, iattr);
 	if (retval)
 		return retval;
 
@@ -606,11 +609,13 @@
  * v9fs_stat2inode_dotl - populate an inode structure with stat info
  * @stat: stat structure
  * @inode: inode to populate
+ * @flags: ctrl flags (e.g. V9FS_STAT2INODE_KEEP_ISIZE)
  *
  */
 
 void
-v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
+v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
+		      unsigned int flags)
 {
 	umode_t mode;
 	struct v9fs_inode *v9inode = V9FS_I(inode);
@@ -630,7 +635,8 @@
 		mode |= inode->i_mode & ~S_IALLUGO;
 		inode->i_mode = mode;
 
-		i_size_write(inode, stat->st_size);
+		if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))
+			v9fs_i_size_write(inode, stat->st_size);
 		inode->i_blocks = stat->st_blocks;
 	} else {
 		if (stat->st_result_mask & P9_STATS_ATIME) {
@@ -660,8 +666,9 @@
 		}
 		if (stat->st_result_mask & P9_STATS_RDEV)
 			inode->i_rdev = new_decode_dev(stat->st_rdev);
-		if (stat->st_result_mask & P9_STATS_SIZE)
-			i_size_write(inode, stat->st_size);
+		if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) &&
+		    stat->st_result_mask & P9_STATS_SIZE)
+			v9fs_i_size_write(inode, stat->st_size);
 		if (stat->st_result_mask & P9_STATS_BLOCKS)
 			inode->i_blocks = stat->st_blocks;
 	}
@@ -923,9 +930,9 @@
 
 int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
 {
-	loff_t i_size;
 	struct p9_stat_dotl *st;
 	struct v9fs_session_info *v9ses;
+	unsigned int flags;
 
 	v9ses = v9fs_inode2v9ses(inode);
 	st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
@@ -937,16 +944,13 @@
 	if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
 		goto out;
 
-	spin_lock(&inode->i_lock);
 	/*
 	 * We don't want to refresh inode->i_size,
 	 * because we may have cached data
 	 */
-	i_size = inode->i_size;
-	v9fs_stat2inode_dotl(st, inode);
-	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
-		inode->i_size = i_size;
-	spin_unlock(&inode->i_lock);
+	flags = (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) ?
+		V9FS_STAT2INODE_KEEP_ISIZE : 0;
+	v9fs_stat2inode_dotl(st, inode, flags);
 out:
 	kfree(st);
 	return 0;
--- linux-4.4.0.orig/fs/9p/vfs_super.c
+++ linux-4.4.0/fs/9p/vfs_super.c
@@ -165,7 +165,7 @@
 			goto release_sb;
 		}
 		d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
-		v9fs_stat2inode_dotl(st, d_inode(root));
+		v9fs_stat2inode_dotl(st, d_inode(root), 0);
 		kfree(st);
 	} else {
 		struct p9_wstat *st = NULL;
@@ -176,7 +176,7 @@
 		}
 
 		d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
-		v9fs_stat2inode(st, d_inode(root), sb);
+		v9fs_stat2inode(st, d_inode(root), sb, 0);
 
 		p9stat_free(st);
 		kfree(st);
--- linux-4.4.0.orig/fs/9p/xattr.c
+++ linux-4.4.0/fs/9p/xattr.c
@@ -107,7 +107,7 @@
 {
 	struct kvec kvec = {.iov_base = (void *)value, .iov_len = value_len};
 	struct iov_iter from;
-	int retval;
+	int retval, err;
 
 	iov_iter_kvec(&from, WRITE | ITER_KVEC, &kvec, 1, value_len);
 
@@ -128,7 +128,9 @@
 			 retval);
 	else
 		p9_client_write(fid, 0, &from, &retval);
-	p9_client_clunk(fid);
+	err = p9_client_clunk(fid);
+	if (!retval && err)
+		retval = err;
 	return retval;
 }
 
--- linux-4.4.0.orig/fs/Kconfig
+++ linux-4.4.0/fs/Kconfig
@@ -221,6 +221,7 @@
 source "fs/sysv/Kconfig"
 source "fs/ufs/Kconfig"
 source "fs/exofs/Kconfig"
+source "fs/aufs/Kconfig"
 
 endif # MISC_FILESYSTEMS
 
--- linux-4.4.0.orig/fs/Kconfig.binfmt
+++ linux-4.4.0/fs/Kconfig.binfmt
@@ -1,6 +1,7 @@
 config BINFMT_ELF
 	bool "Kernel support for ELF binaries"
 	depends on MMU && (BROKEN || !FRV)
+	select ELFCORE
 	default y
 	---help---
 	  ELF (Executable and Linkable Format) is a format for libraries and
@@ -26,6 +27,7 @@
 config COMPAT_BINFMT_ELF
 	bool
 	depends on COMPAT && BINFMT_ELF
+	select ELFCORE
 
 config ARCH_BINFMT_ELF_STATE
 	bool
@@ -34,6 +36,7 @@
 	bool "Kernel support for FDPIC ELF binaries"
 	default y
 	depends on (FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X)
+	select ELFCORE
 	help
 	  ELF FDPIC binaries are based on ELF, but allow the individual load
 	  segments of a binary to be located in memory independently of each
@@ -43,6 +46,11 @@
 
 	  It is also possible to run FDPIC ELF binaries on MMU linux also.
 
+config ELFCORE
+	bool
+	help
+	  This option enables kernel/elfcore.o.
+
 config CORE_DUMP_DEFAULT_ELF_HEADERS
 	bool "Write ELF core dumps with partial segments"
 	default y
--- linux-4.4.0.orig/fs/Makefile
+++ linux-4.4.0/fs/Makefile
@@ -126,3 +126,4 @@
 obj-$(CONFIG_CEPH_FS)		+= ceph/
 obj-$(CONFIG_PSTORE)		+= pstore/
 obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
+obj-$(CONFIG_AUFS_FS)           += aufs/
--- linux-4.4.0.orig/fs/adfs/inode.c
+++ linux-4.4.0/fs/adfs/inode.c
@@ -303,7 +303,7 @@
 	unsigned int ia_valid = attr->ia_valid;
 	int error;
 	
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 
 	/*
 	 * we can't change the UID or GID of any file -
--- linux-4.4.0.orig/fs/adfs/super.c
+++ linux-4.4.0/fs/adfs/super.c
@@ -368,6 +368,7 @@
 	struct buffer_head *bh;
 	struct object_info root_obj;
 	unsigned char *b_data;
+	unsigned int blocksize;
 	struct adfs_sb_info *asb;
 	struct inode *root;
 	int ret = -EINVAL;
@@ -419,8 +420,10 @@
 		goto error_free_bh;
 	}
 
+	blocksize = 1 << dr->log2secsize;
 	brelse(bh);
-	if (sb_set_blocksize(sb, 1 << dr->log2secsize)) {
+
+	if (sb_set_blocksize(sb, blocksize)) {
 		bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
 		if (!bh) {
 			adfs_error(sb, "couldn't read superblock on "
--- linux-4.4.0.orig/fs/affs/amigaffs.c
+++ linux-4.4.0/fs/affs/amigaffs.c
@@ -390,23 +390,23 @@
 	umode_t mode = 0;
 
 	if (!(prot & FIBF_NOWRITE))
-		mode |= S_IWUSR;
+		mode |= 0200;
 	if (!(prot & FIBF_NOREAD))
-		mode |= S_IRUSR;
+		mode |= 0400;
 	if (!(prot & FIBF_NOEXECUTE))
-		mode |= S_IXUSR;
+		mode |= 0100;
 	if (prot & FIBF_GRP_WRITE)
-		mode |= S_IWGRP;
+		mode |= 0020;
 	if (prot & FIBF_GRP_READ)
-		mode |= S_IRGRP;
+		mode |= 0040;
 	if (prot & FIBF_GRP_EXECUTE)
-		mode |= S_IXGRP;
+		mode |= 0010;
 	if (prot & FIBF_OTR_WRITE)
-		mode |= S_IWOTH;
+		mode |= 0002;
 	if (prot & FIBF_OTR_READ)
-		mode |= S_IROTH;
+		mode |= 0004;
 	if (prot & FIBF_OTR_EXECUTE)
-		mode |= S_IXOTH;
+		mode |= 0001;
 
 	return mode;
 }
@@ -417,24 +417,51 @@
 	u32 prot = AFFS_I(inode)->i_protect;
 	umode_t mode = inode->i_mode;
 
-	if (!(mode & S_IXUSR))
+	/*
+	 * First, clear all RWED bits for owner, group, other.
+	 * Then, recalculate them afresh.
+	 *
+	 * We'll always clear the delete-inhibit bit for the owner, as that is
+	 * the classic single-user mode AmigaOS protection bit and we need to
+	 * stay compatible with all scenarios.
+	 *
+	 * Since multi-user AmigaOS is an extension, we'll only set the
+	 * delete-allow bit if any of the other bits in the same user class
+	 * (group/other) are used.
+	 */
+	prot &= ~(FIBF_NOEXECUTE | FIBF_NOREAD
+		  | FIBF_NOWRITE | FIBF_NODELETE
+		  | FIBF_GRP_EXECUTE | FIBF_GRP_READ
+		  | FIBF_GRP_WRITE   | FIBF_GRP_DELETE
+		  | FIBF_OTR_EXECUTE | FIBF_OTR_READ
+		  | FIBF_OTR_WRITE   | FIBF_OTR_DELETE);
+
+	/* Classic single-user AmigaOS flags. These are inverted. */
+	if (!(mode & 0100))
 		prot |= FIBF_NOEXECUTE;
-	if (!(mode & S_IRUSR))
+	if (!(mode & 0400))
 		prot |= FIBF_NOREAD;
-	if (!(mode & S_IWUSR))
+	if (!(mode & 0200))
 		prot |= FIBF_NOWRITE;
-	if (mode & S_IXGRP)
+
+	/* Multi-user extended flags. Not inverted. */
+	if (mode & 0010)
 		prot |= FIBF_GRP_EXECUTE;
-	if (mode & S_IRGRP)
+	if (mode & 0040)
 		prot |= FIBF_GRP_READ;
-	if (mode & S_IWGRP)
+	if (mode & 0020)
 		prot |= FIBF_GRP_WRITE;
-	if (mode & S_IXOTH)
+	if (mode & 0070)
+		prot |= FIBF_GRP_DELETE;
+
+	if (mode & 0001)
 		prot |= FIBF_OTR_EXECUTE;
-	if (mode & S_IROTH)
+	if (mode & 0004)
 		prot |= FIBF_OTR_READ;
-	if (mode & S_IWOTH)
+	if (mode & 0002)
 		prot |= FIBF_OTR_WRITE;
+	if (mode & 0007)
+		prot |= FIBF_OTR_DELETE;
 
 	AFFS_I(inode)->i_protect = prot;
 }
--- linux-4.4.0.orig/fs/affs/file.c
+++ linux-4.4.0/fs/affs/file.c
@@ -426,6 +426,24 @@
 	return ret;
 }
 
+static int affs_write_end(struct file *file, struct address_space *mapping,
+			  loff_t pos, unsigned int len, unsigned int copied,
+			  struct page *page, void *fsdata)
+{
+	struct inode *inode = mapping->host;
+	int ret;
+
+	ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+
+	/* Clear Archived bit on file writes, as AmigaOS would do */
+	if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
+		AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
+		mark_inode_dirty(inode);
+	}
+
+	return ret;
+}
+
 static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,affs_get_block);
@@ -435,7 +453,7 @@
 	.readpage = affs_readpage,
 	.writepage = affs_writepage,
 	.write_begin = affs_write_begin,
-	.write_end = generic_write_end,
+	.write_end = affs_write_end,
 	.direct_IO = affs_direct_IO,
 	.bmap = _affs_bmap
 };
@@ -793,6 +811,12 @@
 	if (tmp > inode->i_size)
 		inode->i_size = AFFS_I(inode)->mmu_private = tmp;
 
+	/* Clear Archived bit on file writes, as AmigaOS would do */
+	if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
+		AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
+		mark_inode_dirty(inode);
+	}
+
 err_first_bh:
 	unlock_page(page);
 	page_cache_release(page);
--- linux-4.4.0.orig/fs/affs/inode.c
+++ linux-4.4.0/fs/affs/inode.c
@@ -218,7 +218,7 @@
 
 	pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid);
 
-	error = inode_change_ok(inode,attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		goto out;
 
--- linux-4.4.0.orig/fs/affs/namei.c
+++ linux-4.4.0/fs/affs/namei.c
@@ -224,9 +224,10 @@
 
 	affs_lock_dir(dir);
 	bh = affs_find_entry(dir, dentry);
-	affs_unlock_dir(dir);
-	if (IS_ERR(bh))
+	if (IS_ERR(bh)) {
+		affs_unlock_dir(dir);
 		return ERR_CAST(bh);
+	}
 	if (bh) {
 		u32 ino = bh->b_blocknr;
 
@@ -240,10 +241,13 @@
 		}
 		affs_brelse(bh);
 		inode = affs_iget(sb, ino);
-		if (IS_ERR(inode))
+		if (IS_ERR(inode)) {
+			affs_unlock_dir(dir);
 			return ERR_CAST(inode);
+		}
 	}
 	d_add(dentry, inode);
+	affs_unlock_dir(dir);
 	return NULL;
 }
 
--- linux-4.4.0.orig/fs/affs/super.c
+++ linux-4.4.0/fs/affs/super.c
@@ -528,7 +528,7 @@
 	char			*prefix = NULL;
 
 	new_opts = kstrdup(data, GFP_KERNEL);
-	if (!new_opts)
+	if (data && !new_opts)
 		return -ENOMEM;
 
 	pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data);
@@ -546,7 +546,8 @@
 	}
 
 	flush_delayed_work(&sbi->sb_work);
-	replace_mount_options(sb, new_opts);
+	if (new_opts)
+		replace_mount_options(sb, new_opts);
 
 	sbi->s_flags = mount_flags;
 	sbi->s_mode  = mode;
--- linux-4.4.0.orig/fs/afs/callback.c
+++ linux-4.4.0/fs/afs/callback.c
@@ -362,7 +362,7 @@
 {
 	struct afs_server *server;
 	struct afs_vnode *vnode, *xvnode;
-	time_t now;
+	time64_t now;
 	long timeout;
 	int ret;
 
@@ -370,7 +370,7 @@
 
 	_enter("");
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	/* find the first vnode to update */
 	spin_lock(&server->cb_lock);
@@ -424,7 +424,8 @@
 
 	/* and then reschedule */
 	_debug("reschedule");
-	vnode->update_at = get_seconds() + afs_vnode_update_timeout;
+	vnode->update_at = ktime_get_real_seconds() +
+			afs_vnode_update_timeout;
 
 	spin_lock(&server->cb_lock);
 
--- linux-4.4.0.orig/fs/afs/cmservice.c
+++ linux-4.4.0/fs/afs/cmservice.c
@@ -115,6 +115,9 @@
 	case CBProbe:
 		call->type = &afs_SRXCBProbe;
 		return true;
+	case CBProbeUuid:
+		call->type = &afs_SRXCBProbeUuid;
+		return true;
 	case CBTellMeAboutYourself:
 		call->type = &afs_SRXCBTellMeAboutYourself;
 		return true;
--- linux-4.4.0.orig/fs/afs/dir.c
+++ linux-4.4.0/fs/afs/dir.c
@@ -128,7 +128,7 @@
 /*
  * check that a directory page is valid
  */
-static inline void afs_dir_check_page(struct inode *dir, struct page *page)
+static inline bool afs_dir_check_page(struct inode *dir, struct page *page)
 {
 	struct afs_dir_page *dbuf;
 	loff_t latter;
@@ -168,11 +168,11 @@
 	}
 
 	SetPageChecked(page);
-	return;
+	return true;
 
 error:
-	SetPageChecked(page);
 	SetPageError(page);
+	return false;
 }
 
 /*
@@ -196,10 +196,10 @@
 	page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
 	if (!IS_ERR(page)) {
 		kmap(page);
-		if (!PageChecked(page))
-			afs_dir_check_page(dir, page);
-		if (PageError(page))
-			goto fail;
+		if (unlikely(!PageChecked(page))) {
+			if (PageError(page) || !afs_dir_check_page(dir, page))
+				goto fail;
+		}
 	}
 	return page;
 
--- linux-4.4.0.orig/fs/afs/file.c
+++ linux-4.4.0/fs/afs/file.c
@@ -29,6 +29,7 @@
 
 const struct file_operations afs_file_operations = {
 	.open		= afs_open,
+	.flush		= afs_flush,
 	.release	= afs_release,
 	.llseek		= generic_file_llseek,
 	.read_iter	= generic_file_read_iter,
--- linux-4.4.0.orig/fs/afs/fsclient.c
+++ linux-4.4.0/fs/afs/fsclient.c
@@ -105,7 +105,7 @@
 			vnode->vfs_inode.i_mode = mode;
 		}
 
-		vnode->vfs_inode.i_ctime.tv_sec	= status->mtime_server;
+		vnode->vfs_inode.i_ctime.tv_sec	= status->mtime_client;
 		vnode->vfs_inode.i_mtime	= vnode->vfs_inode.i_ctime;
 		vnode->vfs_inode.i_atime	= vnode->vfs_inode.i_ctime;
 		vnode->vfs_inode.i_version	= data_version;
@@ -139,7 +139,7 @@
 	vnode->cb_version	= ntohl(*bp++);
 	vnode->cb_expiry	= ntohl(*bp++);
 	vnode->cb_type		= ntohl(*bp++);
-	vnode->cb_expires	= vnode->cb_expiry + get_seconds();
+	vnode->cb_expires	= vnode->cb_expiry + ktime_get_real_seconds();
 	*_bp = bp;
 }
 
@@ -703,8 +703,8 @@
 		memset(bp, 0, padsz);
 		bp = (void *) bp + padsz;
 	}
-	*bp++ = htonl(AFS_SET_MODE);
-	*bp++ = 0; /* mtime */
+	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
+	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
 	*bp++ = 0; /* owner */
 	*bp++ = 0; /* group */
 	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
@@ -981,8 +981,8 @@
 		memset(bp, 0, c_padsz);
 		bp = (void *) bp + c_padsz;
 	}
-	*bp++ = htonl(AFS_SET_MODE);
-	*bp++ = 0; /* mtime */
+	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
+	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
 	*bp++ = 0; /* owner */
 	*bp++ = 0; /* group */
 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
@@ -1192,8 +1192,8 @@
 	*bp++ = htonl(vnode->fid.vnode);
 	*bp++ = htonl(vnode->fid.unique);
 
-	*bp++ = 0; /* mask */
-	*bp++ = 0; /* mtime */
+	*bp++ = htonl(AFS_SET_MTIME); /* mask */
+	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
 	*bp++ = 0; /* owner */
 	*bp++ = 0; /* group */
 	*bp++ = 0; /* unix mode */
@@ -1225,7 +1225,7 @@
 	_enter(",%x,{%x:%u},,",
 	       key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
 
-	size = to - offset;
+	size = (loff_t)to - (loff_t)offset;
 	if (first != last)
 		size += (loff_t)(last - first) << PAGE_SHIFT;
 	pos = (loff_t)first << PAGE_SHIFT;
@@ -1269,8 +1269,8 @@
 	*bp++ = htonl(vnode->fid.vnode);
 	*bp++ = htonl(vnode->fid.unique);
 
-	*bp++ = 0; /* mask */
-	*bp++ = 0; /* mtime */
+	*bp++ = htonl(AFS_SET_MTIME); /* mask */
+	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
 	*bp++ = 0; /* owner */
 	*bp++ = 0; /* group */
 	*bp++ = 0; /* unix mode */
--- linux-4.4.0.orig/fs/afs/inode.c
+++ linux-4.4.0/fs/afs/inode.c
@@ -69,9 +69,9 @@
 
 	set_nlink(inode, vnode->status.nlink);
 	inode->i_uid		= vnode->status.owner;
-	inode->i_gid		= GLOBAL_ROOT_GID;
+	inode->i_gid            = vnode->status.group;
 	inode->i_size		= vnode->status.size;
-	inode->i_ctime.tv_sec	= vnode->status.mtime_server;
+	inode->i_ctime.tv_sec	= vnode->status.mtime_client;
 	inode->i_ctime.tv_nsec	= 0;
 	inode->i_atime		= inode->i_mtime = inode->i_ctime;
 	inode->i_blocks		= 0;
@@ -244,12 +244,13 @@
 			vnode->cb_version = 0;
 			vnode->cb_expiry = 0;
 			vnode->cb_type = 0;
-			vnode->cb_expires = get_seconds();
+			vnode->cb_expires = ktime_get_real_seconds();
 		} else {
 			vnode->cb_version = cb->version;
 			vnode->cb_expiry = cb->expiry;
 			vnode->cb_type = cb->type;
-			vnode->cb_expires = vnode->cb_expiry + get_seconds();
+			vnode->cb_expires = vnode->cb_expiry +
+				ktime_get_real_seconds();
 		}
 	}
 
@@ -322,7 +323,7 @@
 	    !test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
 	    !test_bit(AFS_VNODE_MODIFIED, &vnode->flags) &&
 	    !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
-		if (vnode->cb_expires < get_seconds() + 10) {
+		if (vnode->cb_expires < ktime_get_real_seconds() + 10) {
 			_debug("callback expired");
 			set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
 		} else {
--- linux-4.4.0.orig/fs/afs/internal.h
+++ linux-4.4.0/fs/afs/internal.h
@@ -11,6 +11,7 @@
 
 #include <linux/compiler.h>
 #include <linux/kernel.h>
+#include <linux/ktime.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/skbuff.h>
@@ -247,7 +248,7 @@
  */
 struct afs_vlocation {
 	atomic_t		usage;
-	time_t			time_of_death;	/* time at which put reduced usage to 0 */
+	time64_t		time_of_death;	/* time at which put reduced usage to 0 */
 	struct list_head	link;		/* link in cell volume location list */
 	struct list_head	grave;		/* link in master graveyard list */
 	struct list_head	update;		/* link in master update list */
@@ -258,7 +259,7 @@
 	struct afs_cache_vlocation vldb;	/* volume information DB record */
 	struct afs_volume	*vols[3];	/* volume access record pointer (index by type) */
 	wait_queue_head_t	waitq;		/* status change waitqueue */
-	time_t			update_at;	/* time at which record should be updated */
+	time64_t		update_at;	/* time at which record should be updated */
 	spinlock_t		lock;		/* access lock */
 	afs_vlocation_state_t	state;		/* volume location state */
 	unsigned short		upd_rej_cnt;	/* ENOMEDIUM count during update */
@@ -271,7 +272,7 @@
  */
 struct afs_server {
 	atomic_t		usage;
-	time_t			time_of_death;	/* time at which put reduced usage to 0 */
+	time64_t		time_of_death;	/* time at which put reduced usage to 0 */
 	struct in_addr		addr;		/* server address */
 	struct afs_cell		*cell;		/* cell in which server resides */
 	struct list_head	link;		/* link in cell's server list */
@@ -374,8 +375,8 @@
 	struct rb_node		server_rb;	/* link in server->fs_vnodes */
 	struct rb_node		cb_promise;	/* link in server->cb_promises */
 	struct work_struct	cb_broken_work;	/* work to be done on callback break */
-	time_t			cb_expires;	/* time at which callback expires */
-	time_t			cb_expires_at;	/* time used to order cb_promise */
+	time64_t		cb_expires;	/* time at which callback expires */
+	time64_t		cb_expires_at;	/* time used to order cb_promise */
 	unsigned		cb_version;	/* callback version */
 	unsigned		cb_expiry;	/* callback expiry time */
 	afs_callback_type_t	cb_type;	/* type of callback */
@@ -749,6 +750,7 @@
 extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
 extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *);
 extern int afs_writeback_all(struct afs_vnode *);
+extern int afs_flush(struct file *, fl_owner_t);
 extern int afs_fsync(struct file *, loff_t, loff_t, int);
 
 
--- linux-4.4.0.orig/fs/afs/mntpt.c
+++ linux-4.4.0/fs/afs/mntpt.c
@@ -202,7 +202,7 @@
 
 	/* try and do the mount */
 	_debug("--- attempting mount %s -o %s ---", devname, options);
-	mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
+	mnt = vfs_submount(mntpt, &afs_fs_type, devname, options);
 	_debug("--- mount result %p ---", mnt);
 
 	free_page((unsigned long) devname);
--- linux-4.4.0.orig/fs/afs/security.c
+++ linux-4.4.0/fs/afs/security.c
@@ -340,17 +340,22 @@
 	} else {
 		if (!(access & AFS_ACE_LOOKUP))
 			goto permission_denied;
+		if ((mask & MAY_EXEC) && !(inode->i_mode & S_IXUSR))
+			goto permission_denied;
 		if (mask & (MAY_EXEC | MAY_READ)) {
 			if (!(access & AFS_ACE_READ))
 				goto permission_denied;
+			if (!(inode->i_mode & S_IRUSR))
+				goto permission_denied;
 		} else if (mask & MAY_WRITE) {
 			if (!(access & AFS_ACE_WRITE))
 				goto permission_denied;
+			if (!(inode->i_mode & S_IWUSR))
+				goto permission_denied;
 		}
 	}
 
 	key_put(key);
-	ret = generic_permission(inode, mask);
 	_leave(" = %d", ret);
 	return ret;
 
--- linux-4.4.0.orig/fs/afs/server.c
+++ linux-4.4.0/fs/afs/server.c
@@ -237,7 +237,7 @@
 	spin_lock(&afs_server_graveyard_lock);
 	if (atomic_read(&server->usage) == 0) {
 		list_move_tail(&server->grave, &afs_server_graveyard);
-		server->time_of_death = get_seconds();
+		server->time_of_death = ktime_get_real_seconds();
 		queue_delayed_work(afs_wq, &afs_server_reaper,
 				   afs_server_timeout * HZ);
 	}
@@ -272,9 +272,9 @@
 	LIST_HEAD(corpses);
 	struct afs_server *server;
 	unsigned long delay, expiry;
-	time_t now;
+	time64_t now;
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 	spin_lock(&afs_server_graveyard_lock);
 
 	while (!list_empty(&afs_server_graveyard)) {
--- linux-4.4.0.orig/fs/afs/vlocation.c
+++ linux-4.4.0/fs/afs/vlocation.c
@@ -340,7 +340,8 @@
 	struct afs_vlocation *xvl;
 
 	/* wait at least 10 minutes before updating... */
-	vl->update_at = get_seconds() + afs_vlocation_update_timeout;
+	vl->update_at = ktime_get_real_seconds() +
+			afs_vlocation_update_timeout;
 
 	spin_lock(&afs_vlocation_updates_lock);
 
@@ -506,7 +507,7 @@
 	if (atomic_read(&vl->usage) == 0) {
 		_debug("buried");
 		list_move_tail(&vl->grave, &afs_vlocation_graveyard);
-		vl->time_of_death = get_seconds();
+		vl->time_of_death = ktime_get_real_seconds();
 		queue_delayed_work(afs_wq, &afs_vlocation_reap,
 				   afs_vlocation_timeout * HZ);
 
@@ -543,11 +544,11 @@
 	LIST_HEAD(corpses);
 	struct afs_vlocation *vl;
 	unsigned long delay, expiry;
-	time_t now;
+	time64_t now;
 
 	_enter("");
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 	spin_lock(&afs_vlocation_graveyard_lock);
 
 	while (!list_empty(&afs_vlocation_graveyard)) {
@@ -622,13 +623,13 @@
 {
 	struct afs_cache_vlocation vldb;
 	struct afs_vlocation *vl, *xvl;
-	time_t now;
+	time64_t now;
 	long timeout;
 	int ret;
 
 	_enter("");
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	/* find a record to update */
 	spin_lock(&afs_vlocation_updates_lock);
@@ -684,7 +685,8 @@
 
 	/* and then reschedule */
 	_debug("reschedule");
-	vl->update_at = get_seconds() + afs_vlocation_update_timeout;
+	vl->update_at = ktime_get_real_seconds() +
+			afs_vlocation_update_timeout;
 
 	spin_lock(&afs_vlocation_updates_lock);
 
--- linux-4.4.0.orig/fs/afs/write.c
+++ linux-4.4.0/fs/afs/write.c
@@ -148,12 +148,12 @@
 		kfree(candidate);
 		return -ENOMEM;
 	}
-	*pagep = page;
-	/* page won't leak in error case: it eventually gets cleaned off LRU */
 
 	if (!PageUptodate(page) && len != PAGE_CACHE_SIZE) {
 		ret = afs_fill_page(vnode, key, index << PAGE_CACHE_SHIFT, page);
 		if (ret < 0) {
+			unlock_page(page);
+			put_page(page);
 			kfree(candidate);
 			_leave(" = %d [prep]", ret);
 			return ret;
@@ -161,6 +161,9 @@
 		SetPageUptodate(page);
 	}
 
+	/* page won't leak in error case: it eventually gets cleaned off LRU */
+	*pagep = page;
+
 try_again:
 	spin_lock(&vnode->writeback_lock);
 
@@ -296,10 +299,14 @@
 		ASSERTCMP(pv.nr, ==, count);
 
 		for (loop = 0; loop < count; loop++) {
-			ClearPageUptodate(pv.pages[loop]);
+			struct page *page = pv.pages[loop];
+			ClearPageUptodate(page);
 			if (error)
-				SetPageError(pv.pages[loop]);
-			end_page_writeback(pv.pages[loop]);
+				SetPageError(page);
+			if (PageWriteback(page))
+				end_page_writeback(page);
+			if (page->index >= first)
+				first = page->index + 1;
 		}
 
 		__pagevec_release(&pv);
@@ -503,6 +510,7 @@
 
 		if (PageWriteback(page) || !PageDirty(page)) {
 			unlock_page(page);
+			put_page(page);
 			continue;
 		}
 
@@ -740,6 +748,20 @@
 }
 
 /*
+ * Flush out all outstanding writes on a file opened for writing when it is
+ * closed.
+ */
+int afs_flush(struct file *file, fl_owner_t id)
+{
+	_enter("");
+
+	if ((file->f_mode & FMODE_WRITE) == 0)
+		return 0;
+
+	return vfs_fsync(file, 0);
+}
+
+/*
  * notification that a previously read-only page is about to become writable
  * - if it returns an error, the caller will deliver a bus error signal
  */
--- linux-4.4.0.orig/fs/aio.c
+++ linux-4.4.0/fs/aio.c
@@ -40,6 +40,7 @@
 #include <linux/ramfs.h>
 #include <linux/percpu-refcount.h>
 #include <linux/mount.h>
+#include <linux/nospec.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
@@ -68,9 +69,9 @@
 #define AIO_RING_PAGES	8
 
 struct kioctx_table {
-	struct rcu_head	rcu;
-	unsigned	nr;
-	struct kioctx	*table[];
+	struct rcu_head		rcu;
+	unsigned		nr;
+	struct kioctx __rcu	*table[];
 };
 
 struct kioctx_cpu {
@@ -115,7 +116,8 @@
 	struct page		**ring_pages;
 	long			nr_pages;
 
-	struct work_struct	free_work;
+	struct rcu_head		free_rcu;
+	struct work_struct	free_work;	/* see free_ioctx() */
 
 	/*
 	 * signals when all in-flight requests are done
@@ -239,7 +241,12 @@
 	static const struct dentry_operations ops = {
 		.d_dname	= simple_dname,
 	};
-	return mount_pseudo(fs_type, "aio:", NULL, &ops, AIO_RING_MAGIC);
+	struct dentry *root = mount_pseudo(fs_type, "aio:", NULL, &ops,
+					   AIO_RING_MAGIC);
+
+	if (!IS_ERR(root))
+		root->d_sb->s_iflags |= SB_I_NOEXEC;
+	return root;
 }
 
 /* aio_setup
@@ -321,7 +328,7 @@
 	for (i = 0; i < table->nr; i++) {
 		struct kioctx *ctx;
 
-		ctx = table->table[i];
+		ctx = rcu_dereference(table->table[i]);
 		if (ctx && ctx->aio_ring_file == file) {
 			if (!atomic_read(&ctx->dead)) {
 				ctx->user_id = ctx->mmap_base = vma->vm_start;
@@ -433,10 +440,9 @@
 #endif
 };
 
-static int aio_setup_ring(struct kioctx *ctx)
+static int aio_setup_ring(struct kioctx *ctx, unsigned int nr_events)
 {
 	struct aio_ring *ring;
-	unsigned nr_events = ctx->max_reqs;
 	struct mm_struct *mm = current->mm;
 	unsigned long size, unused;
 	int nr_pages;
@@ -568,6 +574,12 @@
 	return cancel(&kiocb->common);
 }
 
+/*
+ * free_ioctx() should be RCU delayed to synchronize against the RCU
+ * protected lookup_ioctx() and also needs process context to call
+ * aio_free_ring(), so the double bouncing through kioctx->free_rcu and
+ * ->free_work.
+ */
 static void free_ioctx(struct work_struct *work)
 {
 	struct kioctx *ctx = container_of(work, struct kioctx, free_work);
@@ -581,6 +593,14 @@
 	kmem_cache_free(kioctx_cachep, ctx);
 }
 
+static void free_ioctx_rcufn(struct rcu_head *head)
+{
+	struct kioctx *ctx = container_of(head, struct kioctx, free_rcu);
+
+	INIT_WORK(&ctx->free_work, free_ioctx);
+	schedule_work(&ctx->free_work);
+}
+
 static void free_ioctx_reqs(struct percpu_ref *ref)
 {
 	struct kioctx *ctx = container_of(ref, struct kioctx, reqs);
@@ -589,8 +609,8 @@
 	if (ctx->rq_wait && atomic_dec_and_test(&ctx->rq_wait->count))
 		complete(&ctx->rq_wait->comp);
 
-	INIT_WORK(&ctx->free_work, free_ioctx);
-	schedule_work(&ctx->free_work);
+	/* Synchronize against RCU protected table->table[] dereferences */
+	call_rcu(&ctx->free_rcu, free_ioctx_rcufn);
 }
 
 /*
@@ -608,9 +628,8 @@
 	while (!list_empty(&ctx->active_reqs)) {
 		req = list_first_entry(&ctx->active_reqs,
 				       struct aio_kiocb, ki_list);
-
-		list_del_init(&req->ki_list);
 		kiocb_cancel(req);
+		list_del_init(&req->ki_list);
 	}
 
 	spin_unlock_irq(&ctx->ctx_lock);
@@ -631,9 +650,9 @@
 	while (1) {
 		if (table)
 			for (i = 0; i < table->nr; i++)
-				if (!table->table[i]) {
+				if (!rcu_access_pointer(table->table[i])) {
 					ctx->id = i;
-					table->table[i] = ctx;
+					rcu_assign_pointer(table->table[i], ctx);
 					spin_unlock(&mm->ioctx_lock);
 
 					/* While kioctx setup is in progress,
@@ -694,6 +713,12 @@
 	int err = -ENOMEM;
 
 	/*
+	 * Store the original nr_events -- what userspace passed to io_setup(),
+	 * for counting against the global limit -- before it changes.
+	 */
+	unsigned int max_reqs = nr_events;
+
+	/*
 	 * We keep track of the number of available ringbuffer slots, to prevent
 	 * overflow (reqs_available), and we also use percpu counters for this.
 	 *
@@ -711,14 +736,14 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	if (!nr_events || (unsigned long)nr_events > (aio_max_nr * 2UL))
+	if (!nr_events || (unsigned long)max_reqs > aio_max_nr)
 		return ERR_PTR(-EAGAIN);
 
 	ctx = kmem_cache_zalloc(kioctx_cachep, GFP_KERNEL);
 	if (!ctx)
 		return ERR_PTR(-ENOMEM);
 
-	ctx->max_reqs = nr_events;
+	ctx->max_reqs = max_reqs;
 
 	spin_lock_init(&ctx->ctx_lock);
 	spin_lock_init(&ctx->completion_lock);
@@ -740,7 +765,7 @@
 	if (!ctx->cpu)
 		goto err;
 
-	err = aio_setup_ring(ctx);
+	err = aio_setup_ring(ctx, nr_events);
 	if (err < 0)
 		goto err;
 
@@ -751,8 +776,8 @@
 
 	/* limit the number of system wide aios */
 	spin_lock(&aio_nr_lock);
-	if (aio_nr + nr_events > (aio_max_nr * 2UL) ||
-	    aio_nr + nr_events < aio_nr) {
+	if (aio_nr + ctx->max_reqs > aio_max_nr ||
+	    aio_nr + ctx->max_reqs < aio_nr) {
 		spin_unlock(&aio_nr_lock);
 		err = -EAGAIN;
 		goto err_ctx;
@@ -808,11 +833,11 @@
 	}
 
 	table = rcu_dereference_raw(mm->ioctx_table);
-	WARN_ON(ctx != table->table[ctx->id]);
-	table->table[ctx->id] = NULL;
+	WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id]));
+	RCU_INIT_POINTER(table->table[ctx->id], NULL);
 	spin_unlock(&mm->ioctx_lock);
 
-	/* percpu_ref_kill() will do the necessary call_rcu() */
+	/* free_ioctx_reqs() will do the necessary RCU synchronization */
 	wake_up_all(&ctx->wait);
 
 	/*
@@ -854,7 +879,8 @@
 
 	skipped = 0;
 	for (i = 0; i < table->nr; ++i) {
-		struct kioctx *ctx = table->table[i];
+		struct kioctx *ctx =
+			rcu_dereference_protected(table->table[i], true);
 
 		if (!ctx) {
 			skipped++;
@@ -1043,10 +1069,11 @@
 	if (!table || id >= table->nr)
 		goto out;
 
-	ctx = table->table[id];
+	id = array_index_nospec(id, table->nr);
+	ctx = rcu_dereference(table->table[id]);
 	if (ctx && ctx->user_id == ctx_id) {
-		percpu_ref_get(&ctx->users);
-		ret = ctx;
+		if (percpu_ref_tryget_live(&ctx->users))
+			ret = ctx;
 	}
 out:
 	rcu_read_unlock();
--- linux-4.4.0.orig/fs/attr.c
+++ linux-4.4.0/fs/attr.c
@@ -16,20 +16,47 @@
 #include <linux/evm.h>
 #include <linux/ima.h>
 
+static bool chown_ok(const struct inode *inode, kuid_t uid)
+{
+	if (uid_eq(current_fsuid(), inode->i_uid) &&
+	    uid_eq(uid, inode->i_uid))
+		return true;
+	if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+		return true;
+	if (ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
+		return true;
+	return false;
+}
+
+static bool chgrp_ok(const struct inode *inode, kgid_t gid)
+{
+	if (uid_eq(current_fsuid(), inode->i_uid) &&
+	    (in_group_p(gid) || gid_eq(gid, inode->i_gid)))
+		return true;
+	if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+		return true;
+	if (ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
+		return true;
+	return false;
+}
+
 /**
- * inode_change_ok - check if attribute changes to an inode are allowed
- * @inode:	inode to check
+ * setattr_prepare - check if attribute changes to a dentry are allowed
+ * @dentry:	dentry to check
  * @attr:	attributes to change
  *
  * Check if we are allowed to change the attributes contained in @attr
- * in the given inode.  This includes the normal unix access permission
- * checks, as well as checks for rlimits and others.
+ * in the given dentry.  This includes the normal unix access permission
+ * checks, as well as checks for rlimits and others. The function also clears
+ * SGID bit from mode if user is not allowed to set it. Also file capabilities
+ * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
  *
  * Should be called as the first thing in ->setattr implementations,
  * possibly after taking additional locks.
  */
-int inode_change_ok(const struct inode *inode, struct iattr *attr)
+int setattr_prepare(struct dentry *dentry, struct iattr *attr)
 {
+	struct inode *inode = d_inode(dentry);
 	unsigned int ia_valid = attr->ia_valid;
 
 	/*
@@ -44,20 +71,14 @@
 
 	/* If force is set do it anyway. */
 	if (ia_valid & ATTR_FORCE)
-		return 0;
+		goto kill_priv;
 
 	/* Make sure a caller can chown. */
-	if ((ia_valid & ATTR_UID) &&
-	    (!uid_eq(current_fsuid(), inode->i_uid) ||
-	     !uid_eq(attr->ia_uid, inode->i_uid)) &&
-	    !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+	if ((ia_valid & ATTR_UID) && !chown_ok(inode, attr->ia_uid))
 		return -EPERM;
 
 	/* Make sure caller can chgrp. */
-	if ((ia_valid & ATTR_GID) &&
-	    (!uid_eq(current_fsuid(), inode->i_uid) ||
-	    (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
-	    !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+	if ((ia_valid & ATTR_GID) && !chgrp_ok(inode, attr->ia_gid))
 		return -EPERM;
 
 	/* Make sure a caller can chmod. */
@@ -77,9 +98,19 @@
 			return -EPERM;
 	}
 
+kill_priv:
+	/* User has permission for the change */
+	if (ia_valid & ATTR_KILL_PRIV) {
+		int error;
+
+		error = security_inode_killpriv(dentry);
+		if (error)
+			return error;
+	}
+
 	return 0;
 }
-EXPORT_SYMBOL(inode_change_ok);
+EXPORT_SYMBOL(setattr_prepare);
 
 /**
  * inode_newsize_ok - may this inode be truncated to a given size
@@ -202,6 +233,21 @@
 			return -EPERM;
 	}
 
+	/*
+	 * If utimes(2) and friends are called with times == NULL (or both
+	 * times are UTIME_NOW), then we need to check for write permission
+	 */
+	if (ia_valid & ATTR_TOUCH) {
+		if (IS_IMMUTABLE(inode))
+			return -EPERM;
+
+		if (!inode_owner_or_capable(inode)) {
+			error = inode_permission(inode, MAY_WRITE);
+			if (error)
+				return error;
+		}
+	}
+
 	if ((ia_valid & ATTR_MODE)) {
 		umode_t amode = attr->ia_mode;
 		/* Flag setting protected by i_mutex */
@@ -217,13 +263,11 @@
 	if (!(ia_valid & ATTR_MTIME_SET))
 		attr->ia_mtime = now;
 	if (ia_valid & ATTR_KILL_PRIV) {
-		attr->ia_valid &= ~ATTR_KILL_PRIV;
-		ia_valid &= ~ATTR_KILL_PRIV;
 		error = security_inode_need_killpriv(dentry);
-		if (error > 0)
-			error = security_inode_killpriv(dentry);
-		if (error)
+		if (error < 0)
 			return error;
+		if (error == 0)
+			ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
 	}
 
 	/*
@@ -255,6 +299,25 @@
 	if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
 		return 0;
 
+	/*
+	 * Verify that uid/gid changes are valid in the target
+	 * namespace of the superblock.
+	 */
+	if (ia_valid & ATTR_UID &&
+	    !kuid_has_mapping(inode->i_sb->s_user_ns, attr->ia_uid))
+		return -EOVERFLOW;
+	if (ia_valid & ATTR_GID &&
+	    !kgid_has_mapping(inode->i_sb->s_user_ns, attr->ia_gid))
+		return -EOVERFLOW;
+
+	/* Don't allow modifications of files with invalid uids or
+	 * gids unless those uids & gids are being made valid.
+	 */
+	if (!(ia_valid & ATTR_UID) && !uid_valid(inode->i_uid))
+		return -EOVERFLOW;
+	if (!(ia_valid & ATTR_GID) && !gid_valid(inode->i_gid))
+		return -EOVERFLOW;
+
 	error = security_inode_setattr(dentry, attr);
 	if (error)
 		return error;
--- linux-4.4.0.orig/fs/aufs/Kconfig
+++ linux-4.4.0/fs/aufs/Kconfig
@@ -0,0 +1,185 @@
+config AUFS_FS
+	tristate "Aufs (Advanced multi layered unification filesystem) support"
+	help
+	Aufs is a stackable unification filesystem such as Unionfs,
+	which unifies several directories and provides a merged single
+	directory.
+	In the early days, aufs was entirely re-designed and
+	re-implemented Unionfs Version 1.x series. Introducing many
+	original ideas, approaches and improvements, it becomes totally
+	different from Unionfs while keeping the basic features.
+
+if AUFS_FS
+choice
+	prompt "Maximum number of branches"
+	default AUFS_BRANCH_MAX_127
+	help
+	Specifies the maximum number of branches (or member directories)
+	in a single aufs. The larger value consumes more system
+	resources and has a minor impact to performance.
+config AUFS_BRANCH_MAX_127
+	bool "127"
+	help
+	Specifies the maximum number of branches (or member directories)
+	in a single aufs. The larger value consumes more system
+	resources and has a minor impact to performance.
+config AUFS_BRANCH_MAX_511
+	bool "511"
+	help
+	Specifies the maximum number of branches (or member directories)
+	in a single aufs. The larger value consumes more system
+	resources and has a minor impact to performance.
+config AUFS_BRANCH_MAX_1023
+	bool "1023"
+	help
+	Specifies the maximum number of branches (or member directories)
+	in a single aufs. The larger value consumes more system
+	resources and has a minor impact to performance.
+config AUFS_BRANCH_MAX_32767
+	bool "32767"
+	help
+	Specifies the maximum number of branches (or member directories)
+	in a single aufs. The larger value consumes more system
+	resources and has a minor impact to performance.
+endchoice
+
+config AUFS_SBILIST
+	bool
+	depends on AUFS_MAGIC_SYSRQ || PROC_FS
+	default y
+	help
+	Automatic configuration for internal use.
+	When aufs supports Magic SysRq or /proc, enabled automatically.
+
+config AUFS_HNOTIFY
+	bool "Detect direct branch access (bypassing aufs)"
+	help
+	If you want to modify files on branches directly, eg. bypassing aufs,
+	and want aufs to detect the changes of them fully, then enable this
+	option and use 'udba=notify' mount option.
+	Currently there is only one available configuration, "fsnotify".
+	It will have a negative impact to the performance.
+	See detail in aufs.5.
+
+choice
+	prompt "method" if AUFS_HNOTIFY
+	default AUFS_HFSNOTIFY
+config AUFS_HFSNOTIFY
+	bool "fsnotify"
+	select FSNOTIFY
+endchoice
+
+config AUFS_EXPORT
+	bool "NFS-exportable aufs"
+	depends on EXPORTFS
+	help
+	If you want to export your mounted aufs via NFS, then enable this
+	option. There are several requirements for this configuration.
+	See detail in aufs.5.
+
+config AUFS_INO_T_64
+	bool
+	depends on AUFS_EXPORT
+	depends on 64BIT && !(ALPHA || S390)
+	default y
+	help
+	Automatic configuration for internal use.
+	/* typedef unsigned long/int __kernel_ino_t */
+	/* alpha and s390x are int */
+
+config AUFS_XATTR
+	bool "support for XATTR/EA (including Security Labels)"
+	help
+	If your branch fs supports XATTR/EA and you want to make them
+	available in aufs too, then enable this opsion and specify the
+	branch attributes for EA.
+	See detail in aufs.5.
+
+config AUFS_FHSM
+	bool "File-based Hierarchical Storage Management"
+	help
+	Hierarchical Storage Management (or HSM) is a well-known feature
+	in the storage world. Aufs provides this feature as file-based.
+	with multiple branches.
+	These multiple branches are prioritized, ie. the topmost one
+	should be the fastest drive and be used heavily.
+
+config AUFS_RDU
+	bool "Readdir in userspace"
+	help
+	Aufs has two methods to provide a merged view for a directory,
+	by a user-space library and by kernel-space natively. The latter
+	is always enabled but sometimes large and slow.
+	If you enable this option, install the library in aufs2-util
+	package, and set some environment variables for your readdir(3),
+	then the work will be handled in user-space which generally
+	shows better performance in most cases.
+	See detail in aufs.5.
+
+config AUFS_SHWH
+	bool "Show whiteouts"
+	help
+	If you want to make the whiteouts in aufs visible, then enable
+	this option and specify 'shwh' mount option. Although it may
+	sounds like philosophy or something, but in technically it
+	simply shows the name of whiteout with keeping its behaviour.
+
+config AUFS_BR_RAMFS
+	bool "Ramfs (initramfs/rootfs) as an aufs branch"
+	help
+	If you want to use ramfs as an aufs branch fs, then enable this
+	option. Generally tmpfs is recommended.
+	Aufs prohibited them to be a branch fs by default, because
+	initramfs becomes unusable after switch_root or something
+	generally. If you sets initramfs as an aufs branch and boot your
+	system by switch_root, you will meet a problem easily since the
+	files in initramfs may be inaccessible.
+	Unless you are going to use ramfs as an aufs branch fs without
+	switch_root or something, leave it N.
+
+config AUFS_BR_FUSE
+	bool "Fuse fs as an aufs branch"
+	depends on FUSE_FS
+	select AUFS_POLL
+	help
+	If you want to use fuse-based userspace filesystem as an aufs
+	branch fs, then enable this option.
+	It implements the internal poll(2) operation which is
+	implemented by fuse only (curretnly).
+
+config AUFS_POLL
+	bool
+	help
+	Automatic configuration for internal use.
+
+config AUFS_BR_HFSPLUS
+	bool "Hfsplus as an aufs branch"
+	depends on HFSPLUS_FS
+	default y
+	help
+	If you want to use hfsplus fs as an aufs branch fs, then enable
+	this option. This option introduces a small overhead at
+	copying-up a file on hfsplus.
+
+config AUFS_BDEV_LOOP
+	bool
+	depends on BLK_DEV_LOOP
+	default y
+	help
+	Automatic configuration for internal use.
+	Convert =[ym] into =y.
+
+config AUFS_DEBUG
+	bool "Debug aufs"
+	help
+	Enable this to compile aufs internal debug code.
+	It will have a negative impact to the performance.
+
+config AUFS_MAGIC_SYSRQ
+	bool
+	depends on AUFS_DEBUG && MAGIC_SYSRQ
+	default y
+	help
+	Automatic configuration for internal use.
+	When aufs supports Magic SysRq, enabled automatically.
+endif
--- linux-4.4.0.orig/fs/aufs/Makefile
+++ linux-4.4.0/fs/aufs/Makefile
@@ -0,0 +1,44 @@
+
+include ${src}/magic.mk
+ifeq (${CONFIG_AUFS_FS},m)
+include ${src}/conf.mk
+endif
+-include ${src}/priv_def.mk
+
+# cf. include/linux/kernel.h
+# enable pr_debug
+ccflags-y += -DDEBUG
+# sparse requires the full pathname
+ifdef M
+ccflags-y += -include ${M}/../../include/uapi/linux/aufs_type.h
+else
+ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h
+endif
+
+obj-$(CONFIG_AUFS_FS) += aufs.o
+aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
+	wkq.o vfsub.o dcsub.o \
+	cpup.o whout.o wbr_policy.o \
+	dinfo.o dentry.o \
+	dynop.o \
+	finfo.o file.o f_op.o \
+	dir.o vdir.o \
+	iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \
+	mvdown.o ioctl.o
+
+# all are boolean
+aufs-$(CONFIG_PROC_FS) += procfs.o plink.o
+aufs-$(CONFIG_SYSFS) += sysfs.o
+aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o
+aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o
+aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o
+aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o
+aufs-$(CONFIG_AUFS_EXPORT) += export.o
+aufs-$(CONFIG_AUFS_XATTR) += xattr.o
+aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o
+aufs-$(CONFIG_AUFS_FHSM) += fhsm.o
+aufs-$(CONFIG_AUFS_POLL) += poll.o
+aufs-$(CONFIG_AUFS_RDU) += rdu.o
+aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o
+aufs-$(CONFIG_AUFS_DEBUG) += debug.o
+aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o
--- linux-4.4.0.orig/fs/aufs/aufs.h
+++ linux-4.4.0/fs/aufs/aufs.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * all header files
+ */
+
+#ifndef __AUFS_H__
+#define __AUFS_H__
+
+#ifdef __KERNEL__
+
+#define AuStub(type, name, body, ...) \
+	static inline type name(__VA_ARGS__) { body; }
+
+#define AuStubVoid(name, ...) \
+	AuStub(void, name, , __VA_ARGS__)
+#define AuStubInt0(name, ...) \
+	AuStub(int, name, return 0, __VA_ARGS__)
+
+#include "debug.h"
+
+#include "branch.h"
+#include "cpup.h"
+#include "dcsub.h"
+#include "dbgaufs.h"
+#include "dentry.h"
+#include "dir.h"
+#include "dynop.h"
+#include "file.h"
+#include "fstype.h"
+#include "inode.h"
+#include "loop.h"
+#include "module.h"
+#include "opts.h"
+#include "rwsem.h"
+#include "spl.h"
+#include "super.h"
+#include "sysaufs.h"
+#include "vfsub.h"
+#include "whout.h"
+#include "wkq.h"
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_H__ */
--- linux-4.4.0.orig/fs/aufs/branch.c
+++ linux-4.4.0/fs/aufs/branch.c
@@ -0,0 +1,1411 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * branch management
+ */
+
+#include <linux/compat.h>
+#include <linux/statfs.h>
+#include "aufs.h"
+
+/*
+ * free a single branch
+ */
+static void au_br_do_free(struct au_branch *br)
+{
+	int i;
+	struct au_wbr *wbr;
+	struct au_dykey **key;
+
+	au_hnotify_fin_br(br);
+
+	if (br->br_xino.xi_file)
+		fput(br->br_xino.xi_file);
+	mutex_destroy(&br->br_xino.xi_nondir_mtx);
+
+	AuDebugOn(atomic_read(&br->br_count));
+
+	wbr = br->br_wbr;
+	if (wbr) {
+		for (i = 0; i < AuBrWh_Last; i++)
+			dput(wbr->wbr_wh[i]);
+		AuDebugOn(atomic_read(&wbr->wbr_wh_running));
+		AuRwDestroy(&wbr->wbr_wh_rwsem);
+	}
+
+	if (br->br_fhsm) {
+		au_br_fhsm_fin(br->br_fhsm);
+		kfree(br->br_fhsm);
+	}
+
+	key = br->br_dykey;
+	for (i = 0; i < AuBrDynOp; i++, key++)
+		if (*key)
+			au_dy_put(*key);
+		else
+			break;
+
+	/* recursive lock, s_umount of branch's */
+	lockdep_off();
+	path_put(&br->br_path);
+	lockdep_on();
+	kfree(wbr);
+	kfree(br);
+}
+
+/*
+ * frees all branches
+ */
+void au_br_free(struct au_sbinfo *sbinfo)
+{
+	aufs_bindex_t bmax;
+	struct au_branch **br;
+
+	AuRwMustWriteLock(&sbinfo->si_rwsem);
+
+	bmax = sbinfo->si_bend + 1;
+	br = sbinfo->si_branch;
+	while (bmax--)
+		au_br_do_free(*br++);
+}
+
+/*
+ * find the index of a branch which is specified by @br_id.
+ */
+int au_br_index(struct super_block *sb, aufs_bindex_t br_id)
+{
+	aufs_bindex_t bindex, bend;
+
+	bend = au_sbend(sb);
+	for (bindex = 0; bindex <= bend; bindex++)
+		if (au_sbr_id(sb, bindex) == br_id)
+			return bindex;
+	return -1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * add a branch
+ */
+
+static int test_overlap(struct super_block *sb, struct dentry *h_adding,
+			struct dentry *h_root)
+{
+	if (unlikely(h_adding == h_root
+		     || au_test_loopback_overlap(sb, h_adding)))
+		return 1;
+	if (h_adding->d_sb != h_root->d_sb)
+		return 0;
+	return au_test_subdir(h_adding, h_root)
+		|| au_test_subdir(h_root, h_adding);
+}
+
+/*
+ * returns a newly allocated branch. @new_nbranch is a number of branches
+ * after adding a branch.
+ */
+static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
+				     int perm)
+{
+	struct au_branch *add_branch;
+	struct dentry *root;
+	struct inode *inode;
+	int err;
+
+	err = -ENOMEM;
+	root = sb->s_root;
+	add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS);
+	if (unlikely(!add_branch))
+		goto out;
+
+	err = au_hnotify_init_br(add_branch, perm);
+	if (unlikely(err))
+		goto out_br;
+
+	if (au_br_writable(perm)) {
+		/* may be freed separately at changing the branch permission */
+		add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr),
+					     GFP_NOFS);
+		if (unlikely(!add_branch->br_wbr))
+			goto out_hnotify;
+	}
+
+	if (au_br_fhsm(perm)) {
+		err = au_fhsm_br_alloc(add_branch);
+		if (unlikely(err))
+			goto out_wbr;
+	}
+
+	err = au_sbr_realloc(au_sbi(sb), new_nbranch);
+	if (!err)
+		err = au_di_realloc(au_di(root), new_nbranch);
+	if (!err) {
+		inode = d_inode(root);
+		err = au_ii_realloc(au_ii(inode), new_nbranch);
+	}
+	if (!err)
+		return add_branch; /* success */
+
+out_wbr:
+	kfree(add_branch->br_wbr);
+out_hnotify:
+	au_hnotify_fin_br(add_branch);
+out_br:
+	kfree(add_branch);
+out:
+	return ERR_PTR(err);
+}
+
+/*
+ * test if the branch permission is legal or not.
+ */
+static int test_br(struct inode *inode, int brperm, char *path)
+{
+	int err;
+
+	err = (au_br_writable(brperm) && IS_RDONLY(inode));
+	if (!err)
+		goto out;
+
+	err = -EINVAL;
+	pr_err("write permission for readonly mount or inode, %s\n", path);
+
+out:
+	return err;
+}
+
+/*
+ * returns:
+ * 0: success, the caller will add it
+ * plus: success, it is already unified, the caller should ignore it
+ * minus: error
+ */
+static int test_add(struct super_block *sb, struct au_opt_add *add, int remount)
+{
+	int err;
+	aufs_bindex_t bend, bindex;
+	struct dentry *root, *h_dentry;
+	struct inode *inode, *h_inode;
+
+	root = sb->s_root;
+	bend = au_sbend(sb);
+	if (unlikely(bend >= 0
+		     && au_find_dbindex(root, add->path.dentry) >= 0)) {
+		err = 1;
+		if (!remount) {
+			err = -EINVAL;
+			pr_err("%s duplicated\n", add->pathname);
+		}
+		goto out;
+	}
+
+	err = -ENOSPC; /* -E2BIG; */
+	if (unlikely(AUFS_BRANCH_MAX <= add->bindex
+		     || AUFS_BRANCH_MAX - 1 <= bend)) {
+		pr_err("number of branches exceeded %s\n", add->pathname);
+		goto out;
+	}
+
+	err = -EDOM;
+	if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) {
+		pr_err("bad index %d\n", add->bindex);
+		goto out;
+	}
+
+	inode = d_inode(add->path.dentry);
+	err = -ENOENT;
+	if (unlikely(!inode->i_nlink)) {
+		pr_err("no existence %s\n", add->pathname);
+		goto out;
+	}
+
+	err = -EINVAL;
+	if (unlikely(inode->i_sb == sb)) {
+		pr_err("%s must be outside\n", add->pathname);
+		goto out;
+	}
+
+	if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) {
+		pr_err("unsupported filesystem, %s (%s)\n",
+		       add->pathname, au_sbtype(inode->i_sb));
+		goto out;
+	}
+
+	if (unlikely(inode->i_sb->s_stack_depth)) {
+		pr_err("already stacked, %s (%s)\n",
+		       add->pathname, au_sbtype(inode->i_sb));
+		goto out;
+	}
+
+	err = test_br(d_inode(add->path.dentry), add->perm, add->pathname);
+	if (unlikely(err))
+		goto out;
+
+	if (bend < 0)
+		return 0; /* success */
+
+	err = -EINVAL;
+	for (bindex = 0; bindex <= bend; bindex++)
+		if (unlikely(test_overlap(sb, add->path.dentry,
+					  au_h_dptr(root, bindex)))) {
+			pr_err("%s is overlapped\n", add->pathname);
+			goto out;
+		}
+
+	err = 0;
+	if (au_opt_test(au_mntflags(sb), WARN_PERM)) {
+		h_dentry = au_h_dptr(root, 0);
+		h_inode = d_inode(h_dentry);
+		if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO)
+		    || !uid_eq(h_inode->i_uid, inode->i_uid)
+		    || !gid_eq(h_inode->i_gid, inode->i_gid))
+			pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n",
+				add->pathname,
+				i_uid_read(inode), i_gid_read(inode),
+				(inode->i_mode & S_IALLUGO),
+				i_uid_read(h_inode), i_gid_read(h_inode),
+				(h_inode->i_mode & S_IALLUGO));
+	}
+
+out:
+	return err;
+}
+
+/*
+ * initialize or clean the whiteouts for an adding branch
+ */
+static int au_br_init_wh(struct super_block *sb, struct au_branch *br,
+			 int new_perm)
+{
+	int err, old_perm;
+	aufs_bindex_t bindex;
+	struct mutex *h_mtx;
+	struct au_wbr *wbr;
+	struct au_hinode *hdir;
+	struct dentry *h_dentry;
+
+	err = vfsub_mnt_want_write(au_br_mnt(br));
+	if (unlikely(err))
+		goto out;
+
+	wbr = br->br_wbr;
+	old_perm = br->br_perm;
+	br->br_perm = new_perm;
+	hdir = NULL;
+	h_mtx = NULL;
+	bindex = au_br_index(sb, br->br_id);
+	if (0 <= bindex) {
+		hdir = au_hi(d_inode(sb->s_root), bindex);
+		au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+	} else {
+		h_dentry = au_br_dentry(br);
+		h_mtx = &d_inode(h_dentry)->i_mutex;
+		mutex_lock_nested(h_mtx, AuLsc_I_PARENT);
+	}
+	if (!wbr)
+		err = au_wh_init(br, sb);
+	else {
+		wbr_wh_write_lock(wbr);
+		err = au_wh_init(br, sb);
+		wbr_wh_write_unlock(wbr);
+	}
+	if (hdir)
+		au_hn_imtx_unlock(hdir);
+	else
+		mutex_unlock(h_mtx);
+	vfsub_mnt_drop_write(au_br_mnt(br));
+	br->br_perm = old_perm;
+
+	if (!err && wbr && !au_br_writable(new_perm)) {
+		kfree(wbr);
+		br->br_wbr = NULL;
+	}
+
+out:
+	return err;
+}
+
+static int au_wbr_init(struct au_branch *br, struct super_block *sb,
+		       int perm)
+{
+	int err;
+	struct kstatfs kst;
+	struct au_wbr *wbr;
+
+	wbr = br->br_wbr;
+	au_rw_init(&wbr->wbr_wh_rwsem);
+	atomic_set(&wbr->wbr_wh_running, 0);
+
+	/*
+	 * a limit for rmdir/rename a dir
+	 * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h
+	 */
+	err = vfs_statfs(&br->br_path, &kst);
+	if (unlikely(err))
+		goto out;
+	err = -EINVAL;
+	if (kst.f_namelen >= NAME_MAX)
+		err = au_br_init_wh(sb, br, perm);
+	else
+		pr_err("%pd(%s), unsupported namelen %ld\n",
+		       au_br_dentry(br),
+		       au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen);
+
+out:
+	return err;
+}
+
+/* initialize a new branch */
+static int au_br_init(struct au_branch *br, struct super_block *sb,
+		      struct au_opt_add *add)
+{
+	int err;
+	struct inode *h_inode;
+
+	err = 0;
+	mutex_init(&br->br_xino.xi_nondir_mtx);
+	br->br_perm = add->perm;
+	br->br_path = add->path; /* set first, path_get() later */
+	spin_lock_init(&br->br_dykey_lock);
+	atomic_set(&br->br_count, 0);
+	atomic_set(&br->br_xino_running, 0);
+	br->br_id = au_new_br_id(sb);
+	AuDebugOn(br->br_id < 0);
+
+	if (au_br_writable(add->perm)) {
+		err = au_wbr_init(br, sb, add->perm);
+		if (unlikely(err))
+			goto out_err;
+	}
+
+	if (au_opt_test(au_mntflags(sb), XINO)) {
+		h_inode = d_inode(add->path.dentry);
+		err = au_xino_br(sb, br, h_inode->i_ino,
+				 au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1);
+		if (unlikely(err)) {
+			AuDebugOn(br->br_xino.xi_file);
+			goto out_err;
+		}
+	}
+
+	sysaufs_br_init(br);
+	path_get(&br->br_path);
+	goto out; /* success */
+
+out_err:
+	memset(&br->br_path, 0, sizeof(br->br_path));
+out:
+	return err;
+}
+
+static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex,
+			     struct au_branch *br, aufs_bindex_t bend,
+			     aufs_bindex_t amount)
+{
+	struct au_branch **brp;
+
+	AuRwMustWriteLock(&sbinfo->si_rwsem);
+
+	brp = sbinfo->si_branch + bindex;
+	memmove(brp + 1, brp, sizeof(*brp) * amount);
+	*brp = br;
+	sbinfo->si_bend++;
+	if (unlikely(bend < 0))
+		sbinfo->si_bend = 0;
+}
+
+static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex,
+			     aufs_bindex_t bend, aufs_bindex_t amount)
+{
+	struct au_hdentry *hdp;
+
+	AuRwMustWriteLock(&dinfo->di_rwsem);
+
+	hdp = dinfo->di_hdentry + bindex;
+	memmove(hdp + 1, hdp, sizeof(*hdp) * amount);
+	au_h_dentry_init(hdp);
+	dinfo->di_bend++;
+	if (unlikely(bend < 0))
+		dinfo->di_bstart = 0;
+}
+
+static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex,
+			     aufs_bindex_t bend, aufs_bindex_t amount)
+{
+	struct au_hinode *hip;
+
+	AuRwMustWriteLock(&iinfo->ii_rwsem);
+
+	hip = iinfo->ii_hinode + bindex;
+	memmove(hip + 1, hip, sizeof(*hip) * amount);
+	hip->hi_inode = NULL;
+	au_hn_init(hip);
+	iinfo->ii_bend++;
+	if (unlikely(bend < 0))
+		iinfo->ii_bstart = 0;
+}
+
+static void au_br_do_add(struct super_block *sb, struct au_branch *br,
+			 aufs_bindex_t bindex)
+{
+	struct dentry *root, *h_dentry;
+	struct inode *root_inode, *h_inode;
+	aufs_bindex_t bend, amount;
+
+	root = sb->s_root;
+	root_inode = d_inode(root);
+	bend = au_sbend(sb);
+	amount = bend + 1 - bindex;
+	h_dentry = au_br_dentry(br);
+	au_sbilist_lock();
+	au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount);
+	au_br_do_add_hdp(au_di(root), bindex, bend, amount);
+	au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount);
+	au_set_h_dptr(root, bindex, dget(h_dentry));
+	h_inode = d_inode(h_dentry);
+	au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0);
+	au_sbilist_unlock();
+}
+
+int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount)
+{
+	int err;
+	aufs_bindex_t bend, add_bindex;
+	struct dentry *root, *h_dentry;
+	struct inode *root_inode;
+	struct au_branch *add_branch;
+
+	root = sb->s_root;
+	root_inode = d_inode(root);
+	IMustLock(root_inode);
+	err = test_add(sb, add, remount);
+	if (unlikely(err < 0))
+		goto out;
+	if (err) {
+		err = 0;
+		goto out; /* success */
+	}
+
+	bend = au_sbend(sb);
+	add_branch = au_br_alloc(sb, bend + 2, add->perm);
+	err = PTR_ERR(add_branch);
+	if (IS_ERR(add_branch))
+		goto out;
+
+	err = au_br_init(add_branch, sb, add);
+	if (unlikely(err)) {
+		au_br_do_free(add_branch);
+		goto out;
+	}
+
+	add_bindex = add->bindex;
+	if (!remount)
+		au_br_do_add(sb, add_branch, add_bindex);
+	else {
+		sysaufs_brs_del(sb, add_bindex);
+		au_br_do_add(sb, add_branch, add_bindex);
+		sysaufs_brs_add(sb, add_bindex);
+	}
+
+	h_dentry = add->path.dentry;
+	if (!add_bindex) {
+		au_cpup_attr_all(root_inode, /*force*/1);
+		sb->s_maxbytes = h_dentry->d_sb->s_maxbytes;
+	} else
+		au_add_nlink(root_inode, d_inode(h_dentry));
+
+	/*
+	 * this test/set prevents aufs from handling unnecesary notify events
+	 * of xino files, in case of re-adding a writable branch which was
+	 * once detached from aufs.
+	 */
+	if (au_xino_brid(sb) < 0
+	    && au_br_writable(add_branch->br_perm)
+	    && !au_test_fs_bad_xino(h_dentry->d_sb)
+	    && add_branch->br_xino.xi_file
+	    && add_branch->br_xino.xi_file->f_path.dentry->d_parent == h_dentry)
+		au_xino_brid_set(sb, add_branch->br_id);
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned long long au_farray_cb(struct super_block *sb, void *a,
+				       unsigned long long max __maybe_unused,
+				       void *arg)
+{
+	unsigned long long n;
+	struct file **p, *f;
+	struct au_sphlhead *files;
+	struct au_finfo *finfo;
+
+	n = 0;
+	p = a;
+	files = &au_sbi(sb)->si_files;
+	spin_lock(&files->spin);
+	hlist_for_each_entry(finfo, &files->head, fi_hlist) {
+		f = finfo->fi_file;
+		if (file_count(f)
+		    && !special_file(file_inode(f)->i_mode)) {
+			get_file(f);
+			*p++ = f;
+			n++;
+			AuDebugOn(n > max);
+		}
+	}
+	spin_unlock(&files->spin);
+
+	return n;
+}
+
+static struct file **au_farray_alloc(struct super_block *sb,
+				     unsigned long long *max)
+{
+	*max = atomic_long_read(&au_sbi(sb)->si_nfiles);
+	return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL);
+}
+
+static void au_farray_free(struct file **a, unsigned long long max)
+{
+	unsigned long long ull;
+
+	for (ull = 0; ull < max; ull++)
+		if (a[ull])
+			fput(a[ull]);
+	kvfree(a);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * delete a branch
+ */
+
+/* to show the line number, do not make it inlined function */
+#define AuVerbose(do_info, fmt, ...) do { \
+	if (do_info) \
+		pr_info(fmt, ##__VA_ARGS__); \
+} while (0)
+
+static int au_test_ibusy(struct inode *inode, aufs_bindex_t bstart,
+			 aufs_bindex_t bend)
+{
+	return (inode && !S_ISDIR(inode->i_mode)) || bstart == bend;
+}
+
+static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t bstart,
+			 aufs_bindex_t bend)
+{
+	return au_test_ibusy(d_inode(dentry), bstart, bend);
+}
+
+/*
+ * test if the branch is deletable or not.
+ */
+static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
+			    unsigned int sigen, const unsigned int verbose)
+{
+	int err, i, j, ndentry;
+	aufs_bindex_t bstart, bend;
+	struct au_dcsub_pages dpages;
+	struct au_dpage *dpage;
+	struct dentry *d;
+
+	err = au_dpages_init(&dpages, GFP_NOFS);
+	if (unlikely(err))
+		goto out;
+	err = au_dcsub_pages(&dpages, root, NULL, NULL);
+	if (unlikely(err))
+		goto out_dpages;
+
+	for (i = 0; !err && i < dpages.ndpage; i++) {
+		dpage = dpages.dpages + i;
+		ndentry = dpage->ndentry;
+		for (j = 0; !err && j < ndentry; j++) {
+			d = dpage->dentries[j];
+			AuDebugOn(au_dcount(d) <= 0);
+			if (!au_digen_test(d, sigen)) {
+				di_read_lock_child(d, AuLock_IR);
+				if (unlikely(au_dbrange_test(d))) {
+					di_read_unlock(d, AuLock_IR);
+					continue;
+				}
+			} else {
+				di_write_lock_child(d);
+				if (unlikely(au_dbrange_test(d))) {
+					di_write_unlock(d);
+					continue;
+				}
+				err = au_reval_dpath(d, sigen);
+				if (!err)
+					di_downgrade_lock(d, AuLock_IR);
+				else {
+					di_write_unlock(d);
+					break;
+				}
+			}
+
+			/* AuDbgDentry(d); */
+			bstart = au_dbstart(d);
+			bend = au_dbend(d);
+			if (bstart <= bindex
+			    && bindex <= bend
+			    && au_h_dptr(d, bindex)
+			    && au_test_dbusy(d, bstart, bend)) {
+				err = -EBUSY;
+				AuVerbose(verbose, "busy %pd\n", d);
+				AuDbgDentry(d);
+			}
+			di_read_unlock(d, AuLock_IR);
+		}
+	}
+
+out_dpages:
+	au_dpages_free(&dpages);
+out:
+	return err;
+}
+
+static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
+			   unsigned int sigen, const unsigned int verbose)
+{
+	int err;
+	unsigned long long max, ull;
+	struct inode *i, **array;
+	aufs_bindex_t bstart, bend;
+
+	array = au_iarray_alloc(sb, &max);
+	err = PTR_ERR(array);
+	if (IS_ERR(array))
+		goto out;
+
+	err = 0;
+	AuDbg("b%d\n", bindex);
+	for (ull = 0; !err && ull < max; ull++) {
+		i = array[ull];
+		if (unlikely(!i))
+			break;
+		if (i->i_ino == AUFS_ROOT_INO)
+			continue;
+
+		/* AuDbgInode(i); */
+		if (au_iigen(i, NULL) == sigen)
+			ii_read_lock_child(i);
+		else {
+			ii_write_lock_child(i);
+			err = au_refresh_hinode_self(i);
+			au_iigen_dec(i);
+			if (!err)
+				ii_downgrade_lock(i);
+			else {
+				ii_write_unlock(i);
+				break;
+			}
+		}
+
+		bstart = au_ibstart(i);
+		bend = au_ibend(i);
+		if (bstart <= bindex
+		    && bindex <= bend
+		    && au_h_iptr(i, bindex)
+		    && au_test_ibusy(i, bstart, bend)) {
+			err = -EBUSY;
+			AuVerbose(verbose, "busy i%lu\n", i->i_ino);
+			AuDbgInode(i);
+		}
+		ii_read_unlock(i);
+	}
+	au_iarray_free(array, max);
+
+out:
+	return err;
+}
+
+static int test_children_busy(struct dentry *root, aufs_bindex_t bindex,
+			      const unsigned int verbose)
+{
+	int err;
+	unsigned int sigen;
+
+	sigen = au_sigen(root->d_sb);
+	DiMustNoWaiters(root);
+	IiMustNoWaiters(d_inode(root));
+	di_write_unlock(root);
+	err = test_dentry_busy(root, bindex, sigen, verbose);
+	if (!err)
+		err = test_inode_busy(root->d_sb, bindex, sigen, verbose);
+	di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */
+
+	return err;
+}
+
+static int test_dir_busy(struct file *file, aufs_bindex_t br_id,
+			 struct file **to_free, int *idx)
+{
+	int err;
+	unsigned char matched, root;
+	aufs_bindex_t bindex, bend;
+	struct au_fidir *fidir;
+	struct au_hfile *hfile;
+
+	err = 0;
+	root = IS_ROOT(file->f_path.dentry);
+	if (root) {
+		get_file(file);
+		to_free[*idx] = file;
+		(*idx)++;
+		goto out;
+	}
+
+	matched = 0;
+	fidir = au_fi(file)->fi_hdir;
+	AuDebugOn(!fidir);
+	bend = au_fbend_dir(file);
+	for (bindex = au_fbstart(file); bindex <= bend; bindex++) {
+		hfile = fidir->fd_hfile + bindex;
+		if (!hfile->hf_file)
+			continue;
+
+		if (hfile->hf_br->br_id == br_id) {
+			matched = 1;
+			break;
+		}
+	}
+	if (matched)
+		err = -EBUSY;
+
+out:
+	return err;
+}
+
+static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id,
+			  struct file **to_free, int opened)
+{
+	int err, idx;
+	unsigned long long ull, max;
+	aufs_bindex_t bstart;
+	struct file *file, **array;
+	struct dentry *root;
+	struct au_hfile *hfile;
+
+	array = au_farray_alloc(sb, &max);
+	err = PTR_ERR(array);
+	if (IS_ERR(array))
+		goto out;
+
+	err = 0;
+	idx = 0;
+	root = sb->s_root;
+	di_write_unlock(root);
+	for (ull = 0; ull < max; ull++) {
+		file = array[ull];
+		if (unlikely(!file))
+			break;
+
+		/* AuDbg("%pD\n", file); */
+		fi_read_lock(file);
+		bstart = au_fbstart(file);
+		if (!d_is_dir(file->f_path.dentry)) {
+			hfile = &au_fi(file)->fi_htop;
+			if (hfile->hf_br->br_id == br_id)
+				err = -EBUSY;
+		} else
+			err = test_dir_busy(file, br_id, to_free, &idx);
+		fi_read_unlock(file);
+		if (unlikely(err))
+			break;
+	}
+	di_write_lock_child(root);
+	au_farray_free(array, max);
+	AuDebugOn(idx > opened);
+
+out:
+	return err;
+}
+
+static void br_del_file(struct file **to_free, unsigned long long opened,
+			  aufs_bindex_t br_id)
+{
+	unsigned long long ull;
+	aufs_bindex_t bindex, bstart, bend, bfound;
+	struct file *file;
+	struct au_fidir *fidir;
+	struct au_hfile *hfile;
+
+	for (ull = 0; ull < opened; ull++) {
+		file = to_free[ull];
+		if (unlikely(!file))
+			break;
+
+		/* AuDbg("%pD\n", file); */
+		AuDebugOn(!d_is_dir(file->f_path.dentry));
+		bfound = -1;
+		fidir = au_fi(file)->fi_hdir;
+		AuDebugOn(!fidir);
+		fi_write_lock(file);
+		bstart = au_fbstart(file);
+		bend = au_fbend_dir(file);
+		for (bindex = bstart; bindex <= bend; bindex++) {
+			hfile = fidir->fd_hfile + bindex;
+			if (!hfile->hf_file)
+				continue;
+
+			if (hfile->hf_br->br_id == br_id) {
+				bfound = bindex;
+				break;
+			}
+		}
+		AuDebugOn(bfound < 0);
+		au_set_h_fptr(file, bfound, NULL);
+		if (bfound == bstart) {
+			for (bstart++; bstart <= bend; bstart++)
+				if (au_hf_dir(file, bstart)) {
+					au_set_fbstart(file, bstart);
+					break;
+				}
+		}
+		fi_write_unlock(file);
+	}
+}
+
+static void au_br_do_del_brp(struct au_sbinfo *sbinfo,
+			     const aufs_bindex_t bindex,
+			     const aufs_bindex_t bend)
+{
+	struct au_branch **brp, **p;
+
+	AuRwMustWriteLock(&sbinfo->si_rwsem);
+
+	brp = sbinfo->si_branch + bindex;
+	if (bindex < bend)
+		memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex));
+	sbinfo->si_branch[0 + bend] = NULL;
+	sbinfo->si_bend--;
+
+	p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, AuGFP_SBILIST);
+	if (p)
+		sbinfo->si_branch = p;
+	/* harmless error */
+}
+
+static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex,
+			     const aufs_bindex_t bend)
+{
+	struct au_hdentry *hdp, *p;
+
+	AuRwMustWriteLock(&dinfo->di_rwsem);
+
+	hdp = dinfo->di_hdentry;
+	if (bindex < bend)
+		memmove(hdp + bindex, hdp + bindex + 1,
+			sizeof(*hdp) * (bend - bindex));
+	hdp[0 + bend].hd_dentry = NULL;
+	dinfo->di_bend--;
+
+	p = krealloc(hdp, sizeof(*p) * bend, AuGFP_SBILIST);
+	if (p)
+		dinfo->di_hdentry = p;
+	/* harmless error */
+}
+
+static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex,
+			     const aufs_bindex_t bend)
+{
+	struct au_hinode *hip, *p;
+
+	AuRwMustWriteLock(&iinfo->ii_rwsem);
+
+	hip = iinfo->ii_hinode + bindex;
+	if (bindex < bend)
+		memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex));
+	iinfo->ii_hinode[0 + bend].hi_inode = NULL;
+	au_hn_init(iinfo->ii_hinode + bend);
+	iinfo->ii_bend--;
+
+	p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, AuGFP_SBILIST);
+	if (p)
+		iinfo->ii_hinode = p;
+	/* harmless error */
+}
+
+static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex,
+			 struct au_branch *br)
+{
+	aufs_bindex_t bend;
+	struct au_sbinfo *sbinfo;
+	struct dentry *root, *h_root;
+	struct inode *inode, *h_inode;
+	struct au_hinode *hinode;
+
+	SiMustWriteLock(sb);
+
+	root = sb->s_root;
+	inode = d_inode(root);
+	sbinfo = au_sbi(sb);
+	bend = sbinfo->si_bend;
+
+	h_root = au_h_dptr(root, bindex);
+	hinode = au_hi(inode, bindex);
+	h_inode = au_igrab(hinode->hi_inode);
+	au_hiput(hinode);
+
+	au_sbilist_lock();
+	au_br_do_del_brp(sbinfo, bindex, bend);
+	au_br_do_del_hdp(au_di(root), bindex, bend);
+	au_br_do_del_hip(au_ii(inode), bindex, bend);
+	au_sbilist_unlock();
+
+	dput(h_root);
+	iput(h_inode);
+	au_br_do_free(br);
+}
+
+static unsigned long long empty_cb(struct super_block *sb, void *array,
+				   unsigned long long max, void *arg)
+{
+	return max;
+}
+
+int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
+{
+	int err, rerr, i;
+	unsigned long long opened;
+	unsigned int mnt_flags;
+	aufs_bindex_t bindex, bend, br_id;
+	unsigned char do_wh, verbose;
+	struct au_branch *br;
+	struct au_wbr *wbr;
+	struct dentry *root;
+	struct file **to_free;
+
+	err = 0;
+	opened = 0;
+	to_free = NULL;
+	root = sb->s_root;
+	bindex = au_find_dbindex(root, del->h_path.dentry);
+	if (bindex < 0) {
+		if (remount)
+			goto out; /* success */
+		err = -ENOENT;
+		pr_err("%s no such branch\n", del->pathname);
+		goto out;
+	}
+	AuDbg("bindex b%d\n", bindex);
+
+	err = -EBUSY;
+	mnt_flags = au_mntflags(sb);
+	verbose = !!au_opt_test(mnt_flags, VERBOSE);
+	bend = au_sbend(sb);
+	if (unlikely(!bend)) {
+		AuVerbose(verbose, "no more branches left\n");
+		goto out;
+	}
+	br = au_sbr(sb, bindex);
+	AuDebugOn(!path_equal(&br->br_path, &del->h_path));
+
+	br_id = br->br_id;
+	opened = atomic_read(&br->br_count);
+	if (unlikely(opened)) {
+		to_free = au_array_alloc(&opened, empty_cb, sb, NULL);
+		err = PTR_ERR(to_free);
+		if (IS_ERR(to_free))
+			goto out;
+
+		err = test_file_busy(sb, br_id, to_free, opened);
+		if (unlikely(err)) {
+			AuVerbose(verbose, "%llu file(s) opened\n", opened);
+			goto out;
+		}
+	}
+
+	wbr = br->br_wbr;
+	do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph);
+	if (do_wh) {
+		/* instead of WbrWhMustWriteLock(wbr) */
+		SiMustWriteLock(sb);
+		for (i = 0; i < AuBrWh_Last; i++) {
+			dput(wbr->wbr_wh[i]);
+			wbr->wbr_wh[i] = NULL;
+		}
+	}
+
+	err = test_children_busy(root, bindex, verbose);
+	if (unlikely(err)) {
+		if (do_wh)
+			goto out_wh;
+		goto out;
+	}
+
+	err = 0;
+	if (to_free) {
+		/*
+		 * now we confirmed the branch is deletable.
+		 * let's free the remaining opened dirs on the branch.
+		 */
+		di_write_unlock(root);
+		br_del_file(to_free, opened, br_id);
+		di_write_lock_child(root);
+	}
+
+	if (!remount)
+		au_br_do_del(sb, bindex, br);
+	else {
+		sysaufs_brs_del(sb, bindex);
+		au_br_do_del(sb, bindex, br);
+		sysaufs_brs_add(sb, bindex);
+	}
+
+	if (!bindex) {
+		au_cpup_attr_all(d_inode(root), /*force*/1);
+		sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes;
+	} else
+		au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry));
+	if (au_opt_test(mnt_flags, PLINK))
+		au_plink_half_refresh(sb, br_id);
+
+	if (au_xino_brid(sb) == br_id)
+		au_xino_brid_set(sb, -1);
+	goto out; /* success */
+
+out_wh:
+	/* revert */
+	rerr = au_br_init_wh(sb, br, br->br_perm);
+	if (rerr)
+		pr_warn("failed re-creating base whiteout, %s. (%d)\n",
+			del->pathname, rerr);
+out:
+	if (to_free)
+		au_farray_free(to_free, opened);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg)
+{
+	int err;
+	aufs_bindex_t bstart, bend;
+	struct aufs_ibusy ibusy;
+	struct inode *inode, *h_inode;
+
+	err = -EPERM;
+	if (unlikely(!capable(CAP_SYS_ADMIN)))
+		goto out;
+
+	err = copy_from_user(&ibusy, arg, sizeof(ibusy));
+	if (!err)
+		err = !access_ok(VERIFY_WRITE, &arg->h_ino, sizeof(arg->h_ino));
+	if (unlikely(err)) {
+		err = -EFAULT;
+		AuTraceErr(err);
+		goto out;
+	}
+
+	err = -EINVAL;
+	si_read_lock(sb, AuLock_FLUSH);
+	if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbend(sb)))
+		goto out_unlock;
+
+	err = 0;
+	ibusy.h_ino = 0; /* invalid */
+	inode = ilookup(sb, ibusy.ino);
+	if (!inode
+	    || inode->i_ino == AUFS_ROOT_INO
+	    || is_bad_inode(inode))
+		goto out_unlock;
+
+	ii_read_lock_child(inode);
+	bstart = au_ibstart(inode);
+	bend = au_ibend(inode);
+	if (bstart <= ibusy.bindex && ibusy.bindex <= bend) {
+		h_inode = au_h_iptr(inode, ibusy.bindex);
+		if (h_inode && au_test_ibusy(inode, bstart, bend))
+			ibusy.h_ino = h_inode->i_ino;
+	}
+	ii_read_unlock(inode);
+	iput(inode);
+
+out_unlock:
+	si_read_unlock(sb);
+	if (!err) {
+		err = __put_user(ibusy.h_ino, &arg->h_ino);
+		if (unlikely(err)) {
+			err = -EFAULT;
+			AuTraceErr(err);
+		}
+	}
+out:
+	return err;
+}
+
+long au_ibusy_ioctl(struct file *file, unsigned long arg)
+{
+	return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+long au_ibusy_compat_ioctl(struct file *file, unsigned long arg)
+{
+	return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg));
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * change a branch permission
+ */
+
+static void au_warn_ima(void)
+{
+#ifdef CONFIG_IMA
+	/* since it doesn't support mark_files_ro() */
+	AuWarn1("RW -> RO makes IMA to produce wrong message\n");
+#endif
+}
+
+static int do_need_sigen_inc(int a, int b)
+{
+	return au_br_whable(a) && !au_br_whable(b);
+}
+
+static int need_sigen_inc(int old, int new)
+{
+	return do_need_sigen_inc(old, new)
+		|| do_need_sigen_inc(new, old);
+}
+
+static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
+{
+	int err, do_warn;
+	unsigned int mnt_flags;
+	unsigned long long ull, max;
+	aufs_bindex_t br_id;
+	unsigned char verbose, writer;
+	struct file *file, *hf, **array;
+	struct au_hfile *hfile;
+	struct inode *h_inode;
+
+	mnt_flags = au_mntflags(sb);
+	verbose = !!au_opt_test(mnt_flags, VERBOSE);
+
+	array = au_farray_alloc(sb, &max);
+	err = PTR_ERR(array);
+	if (IS_ERR(array))
+		goto out;
+
+	do_warn = 0;
+	br_id = au_sbr_id(sb, bindex);
+	for (ull = 0; ull < max; ull++) {
+		file = array[ull];
+		if (unlikely(!file))
+			break;
+
+		/* AuDbg("%pD\n", file); */
+		fi_read_lock(file);
+		if (unlikely(au_test_mmapped(file))) {
+			err = -EBUSY;
+			AuVerbose(verbose, "mmapped %pD\n", file);
+			AuDbgFile(file);
+			FiMustNoWaiters(file);
+			fi_read_unlock(file);
+			goto out_array;
+		}
+
+		hfile = &au_fi(file)->fi_htop;
+		hf = hfile->hf_file;
+		if (!d_is_reg(file->f_path.dentry)
+		    || !(file->f_mode & FMODE_WRITE)
+		    || hfile->hf_br->br_id != br_id
+		    || !(hf->f_mode & FMODE_WRITE))
+			array[ull] = NULL;
+		else {
+			do_warn = 1;
+			get_file(file);
+		}
+
+		FiMustNoWaiters(file);
+		fi_read_unlock(file);
+		fput(file);
+	}
+
+	err = 0;
+	if (do_warn)
+		au_warn_ima();
+
+	for (ull = 0; ull < max; ull++) {
+		file = array[ull];
+		if (!file)
+			continue;
+
+		/* todo: already flushed? */
+		/*
+		 * fs/super.c:mark_files_ro() is gone, but aufs keeps its
+		 * approach which resets f_mode and calls mnt_drop_write() and
+		 * file_release_write() for each file, because the branch
+		 * attribute in aufs world is totally different from the native
+		 * fs rw/ro mode.
+		*/
+		/* fi_read_lock(file); */
+		hfile = &au_fi(file)->fi_htop;
+		hf = hfile->hf_file;
+		/* fi_read_unlock(file); */
+		spin_lock(&hf->f_lock);
+		writer = !!(hf->f_mode & FMODE_WRITER);
+		hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER);
+		spin_unlock(&hf->f_lock);
+		if (writer) {
+			h_inode = file_inode(hf);
+			if (hf->f_mode & FMODE_READ)
+				i_readcount_inc(h_inode);
+			put_write_access(h_inode);
+			__mnt_drop_write(hf->f_path.mnt);
+		}
+	}
+
+out_array:
+	au_farray_free(array, max);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
+	      int *do_refresh)
+{
+	int err, rerr;
+	aufs_bindex_t bindex;
+	struct dentry *root;
+	struct au_branch *br;
+	struct au_br_fhsm *bf;
+
+	root = sb->s_root;
+	bindex = au_find_dbindex(root, mod->h_root);
+	if (bindex < 0) {
+		if (remount)
+			return 0; /* success */
+		err = -ENOENT;
+		pr_err("%s no such branch\n", mod->path);
+		goto out;
+	}
+	AuDbg("bindex b%d\n", bindex);
+
+	err = test_br(d_inode(mod->h_root), mod->perm, mod->path);
+	if (unlikely(err))
+		goto out;
+
+	br = au_sbr(sb, bindex);
+	AuDebugOn(mod->h_root != au_br_dentry(br));
+	if (br->br_perm == mod->perm)
+		return 0; /* success */
+
+	/* pre-allocate for non-fhsm --> fhsm */
+	bf = NULL;
+	if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) {
+		err = au_fhsm_br_alloc(br);
+		if (unlikely(err))
+			goto out;
+		bf = br->br_fhsm;
+		br->br_fhsm = NULL;
+	}
+
+	if (au_br_writable(br->br_perm)) {
+		/* remove whiteout base */
+		err = au_br_init_wh(sb, br, mod->perm);
+		if (unlikely(err))
+			goto out_bf;
+
+		if (!au_br_writable(mod->perm)) {
+			/* rw --> ro, file might be mmapped */
+			DiMustNoWaiters(root);
+			IiMustNoWaiters(d_inode(root));
+			di_write_unlock(root);
+			err = au_br_mod_files_ro(sb, bindex);
+			/* aufs_write_lock() calls ..._child() */
+			di_write_lock_child(root);
+
+			if (unlikely(err)) {
+				rerr = -ENOMEM;
+				br->br_wbr = kzalloc(sizeof(*br->br_wbr),
+						     GFP_NOFS);
+				if (br->br_wbr)
+					rerr = au_wbr_init(br, sb, br->br_perm);
+				if (unlikely(rerr)) {
+					AuIOErr("nested error %d (%d)\n",
+						rerr, err);
+					br->br_perm = mod->perm;
+				}
+			}
+		}
+	} else if (au_br_writable(mod->perm)) {
+		/* ro --> rw */
+		err = -ENOMEM;
+		br->br_wbr = kzalloc(sizeof(*br->br_wbr), GFP_NOFS);
+		if (br->br_wbr) {
+			err = au_wbr_init(br, sb, mod->perm);
+			if (unlikely(err)) {
+				kfree(br->br_wbr);
+				br->br_wbr = NULL;
+			}
+		}
+	}
+	if (unlikely(err))
+		goto out_bf;
+
+	if (au_br_fhsm(br->br_perm)) {
+		if (!au_br_fhsm(mod->perm)) {
+			/* fhsm --> non-fhsm */
+			au_br_fhsm_fin(br->br_fhsm);
+			kfree(br->br_fhsm);
+			br->br_fhsm = NULL;
+		}
+	} else if (au_br_fhsm(mod->perm))
+		/* non-fhsm --> fhsm */
+		br->br_fhsm = bf;
+
+	*do_refresh |= need_sigen_inc(br->br_perm, mod->perm);
+	br->br_perm = mod->perm;
+	goto out; /* success */
+
+out_bf:
+	kfree(bf);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs)
+{
+	int err;
+	struct kstatfs kstfs;
+
+	err = vfs_statfs(&br->br_path, &kstfs);
+	if (!err) {
+		stfs->f_blocks = kstfs.f_blocks;
+		stfs->f_bavail = kstfs.f_bavail;
+		stfs->f_files = kstfs.f_files;
+		stfs->f_ffree = kstfs.f_ffree;
+	}
+
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/branch.h
+++ linux-4.4.0/fs/aufs/branch.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * branch filesystems and xino for them
+ */
+
+#ifndef __AUFS_BRANCH_H__
+#define __AUFS_BRANCH_H__
+
+#ifdef __KERNEL__
+
+#include <linux/mount.h>
+#include "dynop.h"
+#include "rwsem.h"
+#include "super.h"
+
+/* ---------------------------------------------------------------------- */
+
+/* a xino file */
+struct au_xino_file {
+	struct file		*xi_file;
+	struct mutex		xi_nondir_mtx;
+
+	/* todo: make xino files an array to support huge inode number */
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry		 *xi_dbgaufs;
+#endif
+};
+
+/* File-based Hierarchical Storage Management */
+struct au_br_fhsm {
+#ifdef CONFIG_AUFS_FHSM
+	struct mutex		bf_lock;
+	unsigned long		bf_jiffy;
+	struct aufs_stfs	bf_stfs;
+	int			bf_readable;
+#endif
+};
+
+/* members for writable branch only */
+enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last};
+struct au_wbr {
+	struct au_rwsem		wbr_wh_rwsem;
+	struct dentry		*wbr_wh[AuBrWh_Last];
+	atomic_t		wbr_wh_running;
+#define wbr_whbase		wbr_wh[AuBrWh_BASE]	/* whiteout base */
+#define wbr_plink		wbr_wh[AuBrWh_PLINK]	/* pseudo-link dir */
+#define wbr_orph		wbr_wh[AuBrWh_ORPH]	/* dir for orphans */
+
+	/* mfs mode */
+	unsigned long long	wbr_bytes;
+};
+
+/* ext2 has 3 types of operations at least, ext3 has 4 */
+#define AuBrDynOp (AuDyLast * 4)
+
+#ifdef CONFIG_AUFS_HFSNOTIFY
+/* support for asynchronous destruction */
+struct au_br_hfsnotify {
+	struct fsnotify_group	*hfsn_group;
+};
+#endif
+
+/* sysfs entries */
+struct au_brsysfs {
+	char			name[16];
+	struct attribute	attr;
+};
+
+enum {
+	AuBrSysfs_BR,
+	AuBrSysfs_BRID,
+	AuBrSysfs_Last
+};
+
+/* protected by superblock rwsem */
+struct au_branch {
+	struct au_xino_file	br_xino;
+
+	aufs_bindex_t		br_id;
+
+	int			br_perm;
+	struct path		br_path;
+	spinlock_t		br_dykey_lock;
+	struct au_dykey		*br_dykey[AuBrDynOp];
+	atomic_t		br_count;
+
+	struct au_wbr		*br_wbr;
+	struct au_br_fhsm	*br_fhsm;
+
+	/* xino truncation */
+	atomic_t		br_xino_running;
+
+#ifdef CONFIG_AUFS_HFSNOTIFY
+	struct au_br_hfsnotify	*br_hfsn;
+#endif
+
+#ifdef CONFIG_SYSFS
+	/* entries under sysfs per mount-point */
+	struct au_brsysfs	br_sysfs[AuBrSysfs_Last];
+#endif
+};
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct vfsmount *au_br_mnt(struct au_branch *br)
+{
+	return br->br_path.mnt;
+}
+
+static inline struct dentry *au_br_dentry(struct au_branch *br)
+{
+	return br->br_path.dentry;
+}
+
+static inline struct super_block *au_br_sb(struct au_branch *br)
+{
+	return au_br_mnt(br)->mnt_sb;
+}
+
+static inline int au_br_rdonly(struct au_branch *br)
+{
+	return ((au_br_sb(br)->s_flags & MS_RDONLY)
+		|| !au_br_writable(br->br_perm))
+		? -EROFS : 0;
+}
+
+static inline int au_br_hnotifyable(int brperm __maybe_unused)
+{
+#ifdef CONFIG_AUFS_HNOTIFY
+	return !(brperm & AuBrPerm_RR);
+#else
+	return 0;
+#endif
+}
+
+static inline int au_br_test_oflag(int oflag, struct au_branch *br)
+{
+	int err, exec_flag;
+
+	err = 0;
+	exec_flag = oflag & __FMODE_EXEC;
+	if (unlikely(exec_flag && path_noexec(&br->br_path)))
+		err = -EACCES;
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* branch.c */
+struct au_sbinfo;
+void au_br_free(struct au_sbinfo *sinfo);
+int au_br_index(struct super_block *sb, aufs_bindex_t br_id);
+struct au_opt_add;
+int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount);
+struct au_opt_del;
+int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount);
+long au_ibusy_ioctl(struct file *file, unsigned long arg);
+#ifdef CONFIG_COMPAT
+long au_ibusy_compat_ioctl(struct file *file, unsigned long arg);
+#endif
+struct au_opt_mod;
+int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
+	      int *do_refresh);
+struct aufs_stfs;
+int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs);
+
+/* xino.c */
+static const loff_t au_loff_max = LLONG_MAX;
+
+int au_xib_trunc(struct super_block *sb);
+ssize_t xino_fread(vfs_readf_t func, struct file *file, void *buf, size_t size,
+		   loff_t *pos);
+ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf,
+		    size_t size, loff_t *pos);
+struct file *au_xino_create2(struct file *base_file, struct file *copy_src);
+struct file *au_xino_create(struct super_block *sb, char *fname, int silent);
+ino_t au_xino_new_ino(struct super_block *sb);
+void au_xino_delete_inode(struct inode *inode, const int unlinked);
+int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
+		  ino_t ino);
+int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
+		 ino_t *ino);
+int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino,
+	       struct file *base_file, int do_test);
+int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex);
+
+struct au_opt_xino;
+int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount);
+void au_xino_clr(struct super_block *sb);
+struct file *au_xino_def(struct super_block *sb);
+int au_xino_path(struct seq_file *seq, struct file *file);
+
+/* ---------------------------------------------------------------------- */
+
+/* Superblock to branch */
+static inline
+aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex)
+{
+	return au_sbr(sb, bindex)->br_id;
+}
+
+static inline
+struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex)
+{
+	return au_br_mnt(au_sbr(sb, bindex));
+}
+
+static inline
+struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex)
+{
+	return au_br_sb(au_sbr(sb, bindex));
+}
+
+static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex)
+{
+	atomic_dec(&au_sbr(sb, bindex)->br_count);
+}
+
+static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex)
+{
+	return au_sbr(sb, bindex)->br_perm;
+}
+
+static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex)
+{
+	return au_br_whable(au_sbr_perm(sb, bindex));
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * wbr_wh_read_lock, wbr_wh_write_lock
+ * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock
+ */
+AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem);
+
+#define WbrWhMustNoWaiters(wbr)	AuRwMustNoWaiters(&wbr->wbr_wh_rwsem)
+#define WbrWhMustAnyLock(wbr)	AuRwMustAnyLock(&wbr->wbr_wh_rwsem)
+#define WbrWhMustWriteLock(wbr)	AuRwMustWriteLock(&wbr->wbr_wh_rwsem)
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef CONFIG_AUFS_FHSM
+static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm)
+{
+	mutex_init(&brfhsm->bf_lock);
+	brfhsm->bf_jiffy = 0;
+	brfhsm->bf_readable = 0;
+}
+
+static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm)
+{
+	mutex_destroy(&brfhsm->bf_lock);
+}
+#else
+AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm)
+AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm)
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_BRANCH_H__ */
--- linux-4.4.0.orig/fs/aufs/conf.mk
+++ linux-4.4.0/fs/aufs/conf.mk
@@ -0,0 +1,38 @@
+
+AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS}
+
+define AuConf
+ifdef ${1}
+AuConfStr += ${1}=${${1}}
+endif
+endef
+
+AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \
+	SBILIST \
+	HNOTIFY HFSNOTIFY \
+	EXPORT INO_T_64 \
+	XATTR \
+	FHSM \
+	RDU \
+	SHWH \
+	BR_RAMFS \
+	BR_FUSE POLL \
+	BR_HFSPLUS \
+	BDEV_LOOP \
+	DEBUG MAGIC_SYSRQ
+$(foreach i, ${AuConfAll}, \
+	$(eval $(call AuConf,CONFIG_AUFS_${i})))
+
+AuConfName = ${obj}/conf.str
+${AuConfName}.tmp: FORCE
+	@echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@
+${AuConfName}: ${AuConfName}.tmp
+	@diff -q $< $@ > /dev/null 2>&1 || { \
+	echo '  GEN    ' $@; \
+	cp -p $< $@; \
+	}
+FORCE:
+clean-files += ${AuConfName} ${AuConfName}.tmp
+${obj}/sysfs.o: ${AuConfName}
+
+-include ${srctree}/${src}/conf_priv.mk
--- linux-4.4.0.orig/fs/aufs/cpup.c
+++ linux-4.4.0/fs/aufs/cpup.c
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * copy-up functions, see wbr_policy.c for copy-down
+ */
+
+#include <linux/fs_stack.h>
+#include <linux/mm.h>
+#include "aufs.h"
+
+void au_cpup_attr_flags(struct inode *dst, unsigned int iflags)
+{
+	const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE
+		| S_NOATIME | S_NOCMTIME | S_AUTOMOUNT;
+
+	BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags));
+
+	dst->i_flags |= iflags & ~mask;
+	if (au_test_fs_notime(dst->i_sb))
+		dst->i_flags |= S_NOATIME | S_NOCMTIME;
+}
+
+void au_cpup_attr_timesizes(struct inode *inode)
+{
+	struct inode *h_inode;
+
+	h_inode = au_h_iptr(inode, au_ibstart(inode));
+	fsstack_copy_attr_times(inode, h_inode);
+	fsstack_copy_inode_size(inode, h_inode);
+}
+
+void au_cpup_attr_nlink(struct inode *inode, int force)
+{
+	struct inode *h_inode;
+	struct super_block *sb;
+	aufs_bindex_t bindex, bend;
+
+	sb = inode->i_sb;
+	bindex = au_ibstart(inode);
+	h_inode = au_h_iptr(inode, bindex);
+	if (!force
+	    && !S_ISDIR(h_inode->i_mode)
+	    && au_opt_test(au_mntflags(sb), PLINK)
+	    && au_plink_test(inode))
+		return;
+
+	/*
+	 * 0 can happen in revalidating.
+	 * h_inode->i_mutex may not be held here, but it is harmless since once
+	 * i_nlink reaches 0, it will never become positive except O_TMPFILE
+	 * case.
+	 * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause
+	 *	 the incorrect link count.
+	 */
+	set_nlink(inode, h_inode->i_nlink);
+
+	/*
+	 * fewer nlink makes find(1) noisy, but larger nlink doesn't.
+	 * it may includes whplink directory.
+	 */
+	if (S_ISDIR(h_inode->i_mode)) {
+		bend = au_ibend(inode);
+		for (bindex++; bindex <= bend; bindex++) {
+			h_inode = au_h_iptr(inode, bindex);
+			if (h_inode)
+				au_add_nlink(inode, h_inode);
+		}
+	}
+}
+
+void au_cpup_attr_changeable(struct inode *inode)
+{
+	struct inode *h_inode;
+
+	h_inode = au_h_iptr(inode, au_ibstart(inode));
+	inode->i_mode = h_inode->i_mode;
+	inode->i_uid = h_inode->i_uid;
+	inode->i_gid = h_inode->i_gid;
+	au_cpup_attr_timesizes(inode);
+	au_cpup_attr_flags(inode, h_inode->i_flags);
+}
+
+void au_cpup_igen(struct inode *inode, struct inode *h_inode)
+{
+	struct au_iinfo *iinfo = au_ii(inode);
+
+	IiMustWriteLock(inode);
+
+	iinfo->ii_higen = h_inode->i_generation;
+	iinfo->ii_hsb1 = h_inode->i_sb;
+}
+
+void au_cpup_attr_all(struct inode *inode, int force)
+{
+	struct inode *h_inode;
+
+	h_inode = au_h_iptr(inode, au_ibstart(inode));
+	au_cpup_attr_changeable(inode);
+	if (inode->i_nlink > 0)
+		au_cpup_attr_nlink(inode, force);
+	inode->i_rdev = h_inode->i_rdev;
+	inode->i_blkbits = h_inode->i_blkbits;
+	au_cpup_igen(inode, h_inode);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */
+
+/* keep the timestamps of the parent dir when cpup */
+void au_dtime_store(struct au_dtime *dt, struct dentry *dentry,
+		    struct path *h_path)
+{
+	struct inode *h_inode;
+
+	dt->dt_dentry = dentry;
+	dt->dt_h_path = *h_path;
+	h_inode = d_inode(h_path->dentry);
+	dt->dt_atime = h_inode->i_atime;
+	dt->dt_mtime = h_inode->i_mtime;
+	/* smp_mb(); */
+}
+
+void au_dtime_revert(struct au_dtime *dt)
+{
+	struct iattr attr;
+	int err;
+
+	attr.ia_atime = dt->dt_atime;
+	attr.ia_mtime = dt->dt_mtime;
+	attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET
+		| ATTR_ATIME | ATTR_ATIME_SET;
+
+	/* no delegation since this is a directory */
+	err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL);
+	if (unlikely(err))
+		pr_warn("restoring timestamps failed(%d). ignored\n", err);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* internal use only */
+struct au_cpup_reg_attr {
+	int		valid;
+	struct kstat	st;
+	unsigned int	iflags; /* inode->i_flags */
+};
+
+static noinline_for_stack
+int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
+	       struct au_cpup_reg_attr *h_src_attr)
+{
+	int err, sbits, icex;
+	unsigned int mnt_flags;
+	unsigned char verbose;
+	struct iattr ia;
+	struct path h_path;
+	struct inode *h_isrc, *h_idst;
+	struct kstat *h_st;
+	struct au_branch *br;
+
+	h_path.dentry = au_h_dptr(dst, bindex);
+	h_idst = d_inode(h_path.dentry);
+	br = au_sbr(dst->d_sb, bindex);
+	h_path.mnt = au_br_mnt(br);
+	h_isrc = d_inode(h_src);
+	ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID
+		| ATTR_ATIME | ATTR_MTIME
+		| ATTR_ATIME_SET | ATTR_MTIME_SET;
+	if (h_src_attr && h_src_attr->valid) {
+		h_st = &h_src_attr->st;
+		ia.ia_uid = h_st->uid;
+		ia.ia_gid = h_st->gid;
+		ia.ia_atime = h_st->atime;
+		ia.ia_mtime = h_st->mtime;
+		if (h_idst->i_mode != h_st->mode
+		    && !S_ISLNK(h_idst->i_mode)) {
+			ia.ia_valid |= ATTR_MODE;
+			ia.ia_mode = h_st->mode;
+		}
+		sbits = !!(h_st->mode & (S_ISUID | S_ISGID));
+		au_cpup_attr_flags(h_idst, h_src_attr->iflags);
+	} else {
+		ia.ia_uid = h_isrc->i_uid;
+		ia.ia_gid = h_isrc->i_gid;
+		ia.ia_atime = h_isrc->i_atime;
+		ia.ia_mtime = h_isrc->i_mtime;
+		if (h_idst->i_mode != h_isrc->i_mode
+		    && !S_ISLNK(h_idst->i_mode)) {
+			ia.ia_valid |= ATTR_MODE;
+			ia.ia_mode = h_isrc->i_mode;
+		}
+		sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID));
+		au_cpup_attr_flags(h_idst, h_isrc->i_flags);
+	}
+	/* no delegation since it is just created */
+	err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL);
+
+	/* is this nfs only? */
+	if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) {
+		ia.ia_valid = ATTR_FORCE | ATTR_MODE;
+		ia.ia_mode = h_isrc->i_mode;
+		err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL);
+	}
+
+	icex = br->br_perm & AuBrAttr_ICEX;
+	if (!err) {
+		mnt_flags = au_mntflags(dst->d_sb);
+		verbose = !!au_opt_test(mnt_flags, VERBOSE);
+		err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose);
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_do_copy_file(struct file *dst, struct file *src, loff_t len,
+			   char *buf, unsigned long blksize)
+{
+	int err;
+	size_t sz, rbytes, wbytes;
+	unsigned char all_zero;
+	char *p, *zp;
+	struct mutex *h_mtx;
+	/* reduce stack usage */
+	struct iattr *ia;
+
+	zp = page_address(ZERO_PAGE(0));
+	if (unlikely(!zp))
+		return -ENOMEM; /* possible? */
+
+	err = 0;
+	all_zero = 0;
+	while (len) {
+		AuDbg("len %lld\n", len);
+		sz = blksize;
+		if (len < blksize)
+			sz = len;
+
+		rbytes = 0;
+		/* todo: signal_pending? */
+		while (!rbytes || err == -EAGAIN || err == -EINTR) {
+			rbytes = vfsub_read_k(src, buf, sz, &src->f_pos);
+			err = rbytes;
+		}
+		if (unlikely(err < 0))
+			break;
+
+		all_zero = 0;
+		if (len >= rbytes && rbytes == blksize)
+			all_zero = !memcmp(buf, zp, rbytes);
+		if (!all_zero) {
+			wbytes = rbytes;
+			p = buf;
+			while (wbytes) {
+				size_t b;
+
+				b = vfsub_write_k(dst, p, wbytes, &dst->f_pos);
+				err = b;
+				/* todo: signal_pending? */
+				if (unlikely(err == -EAGAIN || err == -EINTR))
+					continue;
+				if (unlikely(err < 0))
+					break;
+				wbytes -= b;
+				p += b;
+			}
+			if (unlikely(err < 0))
+				break;
+		} else {
+			loff_t res;
+
+			AuLabel(hole);
+			res = vfsub_llseek(dst, rbytes, SEEK_CUR);
+			err = res;
+			if (unlikely(res < 0))
+				break;
+		}
+		len -= rbytes;
+		err = 0;
+	}
+
+	/* the last block may be a hole */
+	if (!err && all_zero) {
+		AuLabel(last hole);
+
+		err = 1;
+		if (au_test_nfs(dst->f_path.dentry->d_sb)) {
+			/* nfs requires this step to make last hole */
+			/* is this only nfs? */
+			do {
+				/* todo: signal_pending? */
+				err = vfsub_write_k(dst, "\0", 1, &dst->f_pos);
+			} while (err == -EAGAIN || err == -EINTR);
+			if (err == 1)
+				dst->f_pos--;
+		}
+
+		if (err == 1) {
+			ia = (void *)buf;
+			ia->ia_size = dst->f_pos;
+			ia->ia_valid = ATTR_SIZE | ATTR_FILE;
+			ia->ia_file = dst;
+			h_mtx = &file_inode(dst)->i_mutex;
+			mutex_lock_nested(h_mtx, AuLsc_I_CHILD2);
+			/* no delegation since it is just created */
+			err = vfsub_notify_change(&dst->f_path, ia,
+						  /*delegated*/NULL);
+			mutex_unlock(h_mtx);
+		}
+	}
+
+	return err;
+}
+
+int au_copy_file(struct file *dst, struct file *src, loff_t len)
+{
+	int err;
+	unsigned long blksize;
+	unsigned char do_kfree;
+	char *buf;
+
+	err = -ENOMEM;
+	blksize = dst->f_path.dentry->d_sb->s_blocksize;
+	if (!blksize || PAGE_SIZE < blksize)
+		blksize = PAGE_SIZE;
+	AuDbg("blksize %lu\n", blksize);
+	do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *));
+	if (do_kfree)
+		buf = kmalloc(blksize, GFP_NOFS);
+	else
+		buf = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!buf))
+		goto out;
+
+	if (len > (1 << 22))
+		AuDbg("copying a large file %lld\n", (long long)len);
+
+	src->f_pos = 0;
+	dst->f_pos = 0;
+	err = au_do_copy_file(dst, src, len, buf, blksize);
+	if (do_kfree)
+		kfree(buf);
+	else
+		free_page((unsigned long)buf);
+
+out:
+	return err;
+}
+
+/*
+ * to support a sparse file which is opened with O_APPEND,
+ * we need to close the file.
+ */
+static int au_cp_regular(struct au_cp_generic *cpg)
+{
+	int err, i;
+	enum { SRC, DST };
+	struct {
+		aufs_bindex_t bindex;
+		unsigned int flags;
+		struct dentry *dentry;
+		int force_wr;
+		struct file *file;
+		void *label;
+	} *f, file[] = {
+		{
+			.bindex = cpg->bsrc,
+			.flags = O_RDONLY | O_NOATIME | O_LARGEFILE,
+			.label = &&out
+		},
+		{
+			.bindex = cpg->bdst,
+			.flags = O_WRONLY | O_NOATIME | O_LARGEFILE,
+			.force_wr = !!au_ftest_cpup(cpg->flags, RWDST),
+			.label = &&out_src
+		}
+	};
+	struct super_block *sb;
+
+	/* bsrc branch can be ro/rw. */
+	sb = cpg->dentry->d_sb;
+	f = file;
+	for (i = 0; i < 2; i++, f++) {
+		f->dentry = au_h_dptr(cpg->dentry, f->bindex);
+		f->file = au_h_open(cpg->dentry, f->bindex, f->flags,
+				    /*file*/NULL, f->force_wr);
+		err = PTR_ERR(f->file);
+		if (IS_ERR(f->file))
+			goto *f->label;
+	}
+
+	/* try stopping to update while we copyup */
+	IMustLock(d_inode(file[SRC].dentry));
+	err = au_copy_file(file[DST].file, file[SRC].file, cpg->len);
+
+	fput(file[DST].file);
+	au_sbr_put(sb, file[DST].bindex);
+
+out_src:
+	fput(file[SRC].file);
+	au_sbr_put(sb, file[SRC].bindex);
+out:
+	return err;
+}
+
+static int au_do_cpup_regular(struct au_cp_generic *cpg,
+			      struct au_cpup_reg_attr *h_src_attr)
+{
+	int err, rerr;
+	loff_t l;
+	struct path h_path;
+	struct inode *h_src_inode, *h_dst_inode;
+
+	err = 0;
+	h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc);
+	l = i_size_read(h_src_inode);
+	if (cpg->len == -1 || l < cpg->len)
+		cpg->len = l;
+	if (cpg->len) {
+		/* try stopping to update while we are referencing */
+		mutex_lock_nested(&h_src_inode->i_mutex, AuLsc_I_CHILD);
+		au_pin_hdir_unlock(cpg->pin);
+
+		h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc);
+		h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc);
+		h_src_attr->iflags = h_src_inode->i_flags;
+		if (!au_test_nfs(h_src_inode->i_sb))
+			err = vfs_getattr(&h_path, &h_src_attr->st);
+		else {
+			mutex_unlock(&h_src_inode->i_mutex);
+			err = vfs_getattr(&h_path, &h_src_attr->st);
+			mutex_lock_nested(&h_src_inode->i_mutex, AuLsc_I_CHILD);
+		}
+		if (unlikely(err)) {
+			mutex_unlock(&h_src_inode->i_mutex);
+			goto out;
+		}
+		h_src_attr->valid = 1;
+		err = au_cp_regular(cpg);
+		mutex_unlock(&h_src_inode->i_mutex);
+		rerr = au_pin_hdir_relock(cpg->pin);
+		if (!err && rerr)
+			err = rerr;
+	}
+	if (!err && (h_src_inode->i_state & I_LINKABLE)) {
+		h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst);
+		h_dst_inode = d_inode(h_path.dentry);
+		spin_lock(&h_dst_inode->i_lock);
+		h_dst_inode->i_state |= I_LINKABLE;
+		spin_unlock(&h_dst_inode->i_lock);
+	}
+
+out:
+	return err;
+}
+
+static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src,
+			      struct inode *h_dir)
+{
+	int err, symlen;
+	mm_segment_t old_fs;
+	union {
+		char *k;
+		char __user *u;
+	} sym;
+	struct inode *h_inode = d_inode(h_src);
+	const struct inode_operations *h_iop = h_inode->i_op;
+
+	err = -ENOSYS;
+	if (unlikely(!h_iop->readlink))
+		goto out;
+
+	err = -ENOMEM;
+	sym.k = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!sym.k))
+		goto out;
+
+	/* unnecessary to support mmap_sem since symlink is not mmap-able */
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	symlen = h_iop->readlink(h_src, sym.u, PATH_MAX);
+	err = symlen;
+	set_fs(old_fs);
+
+	if (symlen > 0) {
+		sym.k[symlen] = 0;
+		err = vfsub_symlink(h_dir, h_path, sym.k);
+	}
+	free_page((unsigned long)sym.k);
+
+out:
+	return err;
+}
+
+/*
+ * regardless 'acl' option, reset all ACL.
+ * All ACL will be copied up later from the original entry on the lower branch.
+ */
+static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode)
+{
+	int err;
+	struct dentry *h_dentry;
+	struct inode *h_inode;
+
+	h_dentry = h_path->dentry;
+	h_inode = h_dentry->d_inode;
+	/* forget_all_cached_acls(h_inode)); */
+	err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS);
+	AuTraceErr(err);
+	if (!err)
+		err = vfsub_acl_chmod(h_inode, mode);
+	if (err == -EOPNOTSUPP)
+		err = 0;
+
+	AuTraceErr(err);
+	return err;
+}
+
+static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent,
+			  struct inode *h_dir, struct path *h_path)
+{
+	int err;
+	struct inode *dir, *inode;
+
+	err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT);
+	AuTraceErr(err);
+	if (err == -EOPNOTSUPP)
+		err = 0;
+	if (unlikely(err))
+		goto out;
+
+	/*
+	 * strange behaviour from the users view,
+	 * particularry setattr case
+	 */
+	dir = d_inode(dst_parent);
+	if (au_ibstart(dir) == cpg->bdst)
+		au_cpup_attr_nlink(dir, /*force*/1);
+	inode = d_inode(cpg->dentry);
+	au_cpup_attr_nlink(inode, /*force*/1);
+
+out:
+	return err;
+}
+
+static noinline_for_stack
+int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent,
+	       struct au_cpup_reg_attr *h_src_attr)
+{
+	int err;
+	umode_t mode;
+	unsigned int mnt_flags;
+	unsigned char isdir, isreg, force;
+	const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME);
+	struct au_dtime dt;
+	struct path h_path;
+	struct dentry *h_src, *h_dst, *h_parent;
+	struct inode *h_inode, *h_dir;
+	struct super_block *sb;
+
+	/* bsrc branch can be ro/rw. */
+	h_src = au_h_dptr(cpg->dentry, cpg->bsrc);
+	h_inode = d_inode(h_src);
+	AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc));
+
+	/* try stopping to be referenced while we are creating */
+	h_dst = au_h_dptr(cpg->dentry, cpg->bdst);
+	if (au_ftest_cpup(cpg->flags, RENAME))
+		AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX,
+				  AUFS_WH_PFX_LEN));
+	h_parent = h_dst->d_parent; /* dir inode is locked */
+	h_dir = d_inode(h_parent);
+	IMustLock(h_dir);
+	AuDebugOn(h_parent != h_dst->d_parent);
+
+	sb = cpg->dentry->d_sb;
+	h_path.mnt = au_sbr_mnt(sb, cpg->bdst);
+	if (do_dt) {
+		h_path.dentry = h_parent;
+		au_dtime_store(&dt, dst_parent, &h_path);
+	}
+	h_path.dentry = h_dst;
+
+	isreg = 0;
+	isdir = 0;
+	mode = h_inode->i_mode;
+	switch (mode & S_IFMT) {
+	case S_IFREG:
+		isreg = 1;
+		err = vfsub_create(h_dir, &h_path, mode | S_IWUSR,
+				   /*want_excl*/true);
+		if (!err)
+			err = au_do_cpup_regular(cpg, h_src_attr);
+		break;
+	case S_IFDIR:
+		isdir = 1;
+		err = vfsub_mkdir(h_dir, &h_path, mode);
+		if (!err)
+			err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path);
+		break;
+	case S_IFLNK:
+		err = au_do_cpup_symlink(&h_path, h_src, h_dir);
+		break;
+	case S_IFCHR:
+	case S_IFBLK:
+		AuDebugOn(!capable(CAP_MKNOD));
+		/*FALLTHROUGH*/
+	case S_IFIFO:
+	case S_IFSOCK:
+		err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev);
+		break;
+	default:
+		AuIOErr("Unknown inode type 0%o\n", mode);
+		err = -EIO;
+	}
+	if (!err)
+		err = au_reset_acl(h_dir, &h_path, mode);
+
+	mnt_flags = au_mntflags(sb);
+	if (!au_opt_test(mnt_flags, UDBA_NONE)
+	    && !isdir
+	    && au_opt_test(mnt_flags, XINO)
+	    && (h_inode->i_nlink == 1
+		|| (h_inode->i_state & I_LINKABLE))
+	    /* todo: unnecessary? */
+	    /* && d_inode(cpg->dentry)->i_nlink == 1 */
+	    && cpg->bdst < cpg->bsrc
+	    && !au_ftest_cpup(cpg->flags, KEEPLINO))
+		au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0);
+		/* ignore this error */
+
+	if (!err) {
+		force = 0;
+		if (isreg) {
+			force = !!cpg->len;
+			if (cpg->len == -1)
+				force = !!i_size_read(h_inode);
+		}
+		au_fhsm_wrote(sb, cpg->bdst, force);
+	}
+
+	if (do_dt)
+		au_dtime_revert(&dt);
+	return err;
+}
+
+static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path)
+{
+	int err;
+	struct dentry *dentry, *h_dentry, *h_parent, *parent;
+	struct inode *h_dir;
+	aufs_bindex_t bdst;
+
+	dentry = cpg->dentry;
+	bdst = cpg->bdst;
+	h_dentry = au_h_dptr(dentry, bdst);
+	if (!au_ftest_cpup(cpg->flags, OVERWRITE)) {
+		dget(h_dentry);
+		au_set_h_dptr(dentry, bdst, NULL);
+		err = au_lkup_neg(dentry, bdst, /*wh*/0);
+		if (!err)
+			h_path->dentry = dget(au_h_dptr(dentry, bdst));
+		au_set_h_dptr(dentry, bdst, h_dentry);
+	} else {
+		err = 0;
+		parent = dget_parent(dentry);
+		h_parent = au_h_dptr(parent, bdst);
+		dput(parent);
+		h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent);
+		if (IS_ERR(h_path->dentry))
+			err = PTR_ERR(h_path->dentry);
+	}
+	if (unlikely(err))
+		goto out;
+
+	h_parent = h_dentry->d_parent; /* dir inode is locked */
+	h_dir = d_inode(h_parent);
+	IMustLock(h_dir);
+	AuDbg("%pd %pd\n", h_dentry, h_path->dentry);
+	/* no delegation since it is just created */
+	err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL);
+	dput(h_path->dentry);
+
+out:
+	return err;
+}
+
+/*
+ * copyup the @dentry from @bsrc to @bdst.
+ * the caller must set the both of lower dentries.
+ * @len is for truncating when it is -1 copyup the entire file.
+ * in link/rename cases, @dst_parent may be different from the real one.
+ * basic->bsrc can be larger than basic->bdst.
+ */
+static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent)
+{
+	int err, rerr;
+	aufs_bindex_t old_ibstart;
+	unsigned char isdir, plink;
+	struct dentry *h_src, *h_dst, *h_parent;
+	struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode;
+	struct super_block *sb;
+	struct au_branch *br;
+	/* to reuduce stack size */
+	struct {
+		struct au_dtime dt;
+		struct path h_path;
+		struct au_cpup_reg_attr h_src_attr;
+	} *a;
+
+	err = -ENOMEM;
+	a = kmalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+	a->h_src_attr.valid = 0;
+
+	sb = cpg->dentry->d_sb;
+	br = au_sbr(sb, cpg->bdst);
+	a->h_path.mnt = au_br_mnt(br);
+	h_dst = au_h_dptr(cpg->dentry, cpg->bdst);
+	h_parent = h_dst->d_parent; /* dir inode is locked */
+	h_dir = d_inode(h_parent);
+	IMustLock(h_dir);
+
+	h_src = au_h_dptr(cpg->dentry, cpg->bsrc);
+	inode = d_inode(cpg->dentry);
+
+	if (!dst_parent)
+		dst_parent = dget_parent(cpg->dentry);
+	else
+		dget(dst_parent);
+
+	plink = !!au_opt_test(au_mntflags(sb), PLINK);
+	dst_inode = au_h_iptr(inode, cpg->bdst);
+	if (dst_inode) {
+		if (unlikely(!plink)) {
+			err = -EIO;
+			AuIOErr("hi%lu(i%lu) exists on b%d "
+				"but plink is disabled\n",
+				dst_inode->i_ino, inode->i_ino, cpg->bdst);
+			goto out_parent;
+		}
+
+		if (dst_inode->i_nlink) {
+			const int do_dt = au_ftest_cpup(cpg->flags, DTIME);
+
+			h_src = au_plink_lkup(inode, cpg->bdst);
+			err = PTR_ERR(h_src);
+			if (IS_ERR(h_src))
+				goto out_parent;
+			if (unlikely(d_is_negative(h_src))) {
+				err = -EIO;
+				AuIOErr("i%lu exists on b%d "
+					"but not pseudo-linked\n",
+					inode->i_ino, cpg->bdst);
+				dput(h_src);
+				goto out_parent;
+			}
+
+			if (do_dt) {
+				a->h_path.dentry = h_parent;
+				au_dtime_store(&a->dt, dst_parent, &a->h_path);
+			}
+
+			a->h_path.dentry = h_dst;
+			delegated = NULL;
+			err = vfsub_link(h_src, h_dir, &a->h_path, &delegated);
+			if (!err && au_ftest_cpup(cpg->flags, RENAME))
+				err = au_do_ren_after_cpup(cpg, &a->h_path);
+			if (do_dt)
+				au_dtime_revert(&a->dt);
+			if (unlikely(err == -EWOULDBLOCK)) {
+				pr_warn("cannot retry for NFSv4 delegation"
+					" for an internal link\n");
+				iput(delegated);
+			}
+			dput(h_src);
+			goto out_parent;
+		} else
+			/* todo: cpup_wh_file? */
+			/* udba work */
+			au_update_ibrange(inode, /*do_put_zero*/1);
+	}
+
+	isdir = S_ISDIR(inode->i_mode);
+	old_ibstart = au_ibstart(inode);
+	err = cpup_entry(cpg, dst_parent, &a->h_src_attr);
+	if (unlikely(err))
+		goto out_rev;
+	dst_inode = d_inode(h_dst);
+	mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2);
+	/* todo: necessary? */
+	/* au_pin_hdir_unlock(cpg->pin); */
+
+	err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr);
+	if (unlikely(err)) {
+		/* todo: necessary? */
+		/* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */
+		mutex_unlock(&dst_inode->i_mutex);
+		goto out_rev;
+	}
+
+	if (cpg->bdst < old_ibstart) {
+		if (S_ISREG(inode->i_mode)) {
+			err = au_dy_iaop(inode, cpg->bdst, dst_inode);
+			if (unlikely(err)) {
+				/* ignore an error */
+				/* au_pin_hdir_relock(cpg->pin); */
+				mutex_unlock(&dst_inode->i_mutex);
+				goto out_rev;
+			}
+		}
+		au_set_ibstart(inode, cpg->bdst);
+	} else
+		au_set_ibend(inode, cpg->bdst);
+	au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode),
+		      au_hi_flags(inode, isdir));
+
+	/* todo: necessary? */
+	/* err = au_pin_hdir_relock(cpg->pin); */
+	mutex_unlock(&dst_inode->i_mutex);
+	if (unlikely(err))
+		goto out_rev;
+
+	src_inode = d_inode(h_src);
+	if (!isdir
+	    && (src_inode->i_nlink > 1
+		|| src_inode->i_state & I_LINKABLE)
+	    && plink)
+		au_plink_append(inode, cpg->bdst, h_dst);
+
+	if (au_ftest_cpup(cpg->flags, RENAME)) {
+		a->h_path.dentry = h_dst;
+		err = au_do_ren_after_cpup(cpg, &a->h_path);
+	}
+	if (!err)
+		goto out_parent; /* success */
+
+	/* revert */
+out_rev:
+	a->h_path.dentry = h_parent;
+	au_dtime_store(&a->dt, dst_parent, &a->h_path);
+	a->h_path.dentry = h_dst;
+	rerr = 0;
+	if (d_is_positive(h_dst)) {
+		if (!isdir) {
+			/* no delegation since it is just created */
+			rerr = vfsub_unlink(h_dir, &a->h_path,
+					    /*delegated*/NULL, /*force*/0);
+		} else
+			rerr = vfsub_rmdir(h_dir, &a->h_path);
+	}
+	au_dtime_revert(&a->dt);
+	if (rerr) {
+		AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr);
+		err = -EIO;
+	}
+out_parent:
+	dput(dst_parent);
+	kfree(a);
+out:
+	return err;
+}
+
+#if 0 /* reserved */
+struct au_cpup_single_args {
+	int *errp;
+	struct au_cp_generic *cpg;
+	struct dentry *dst_parent;
+};
+
+static void au_call_cpup_single(void *args)
+{
+	struct au_cpup_single_args *a = args;
+
+	au_pin_hdir_acquire_nest(a->cpg->pin);
+	*a->errp = au_cpup_single(a->cpg, a->dst_parent);
+	au_pin_hdir_release(a->cpg->pin);
+}
+#endif
+
+/*
+ * prevent SIGXFSZ in copy-up.
+ * testing CAP_MKNOD is for generic fs,
+ * but CAP_FSETID is for xfs only, currently.
+ */
+static int au_cpup_sio_test(struct au_pin *pin, umode_t mode)
+{
+	int do_sio;
+	struct super_block *sb;
+	struct inode *h_dir;
+
+	do_sio = 0;
+	sb = au_pinned_parent(pin)->d_sb;
+	if (!au_wkq_test()
+	    && (!au_sbi(sb)->si_plink_maint_pid
+		|| au_plink_maint(sb, AuLock_NOPLM))) {
+		switch (mode & S_IFMT) {
+		case S_IFREG:
+			/* no condition about RLIMIT_FSIZE and the file size */
+			do_sio = 1;
+			break;
+		case S_IFCHR:
+		case S_IFBLK:
+			do_sio = !capable(CAP_MKNOD);
+			break;
+		}
+		if (!do_sio)
+			do_sio = ((mode & (S_ISUID | S_ISGID))
+				  && !capable(CAP_FSETID));
+		/* this workaround may be removed in the future */
+		if (!do_sio) {
+			h_dir = au_pinned_h_dir(pin);
+			do_sio = h_dir->i_mode & S_ISVTX;
+		}
+	}
+
+	return do_sio;
+}
+
+#if 0 /* reserved */
+int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent)
+{
+	int err, wkq_err;
+	struct dentry *h_dentry;
+
+	h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc);
+	if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode))
+		err = au_cpup_single(cpg, dst_parent);
+	else {
+		struct au_cpup_single_args args = {
+			.errp		= &err,
+			.cpg		= cpg,
+			.dst_parent	= dst_parent
+		};
+		wkq_err = au_wkq_wait(au_call_cpup_single, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+	}
+
+	return err;
+}
+#endif
+
+/*
+ * copyup the @dentry from the first active lower branch to @bdst,
+ * using au_cpup_single().
+ */
+static int au_cpup_simple(struct au_cp_generic *cpg)
+{
+	int err;
+	unsigned int flags_orig;
+	struct dentry *dentry;
+
+	AuDebugOn(cpg->bsrc < 0);
+
+	dentry = cpg->dentry;
+	DiMustWriteLock(dentry);
+
+	err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1);
+	if (!err) {
+		flags_orig = cpg->flags;
+		au_fset_cpup(cpg->flags, RENAME);
+		err = au_cpup_single(cpg, NULL);
+		cpg->flags = flags_orig;
+		if (!err)
+			return 0; /* success */
+
+		/* revert */
+		au_set_h_dptr(dentry, cpg->bdst, NULL);
+		au_set_dbstart(dentry, cpg->bsrc);
+	}
+
+	return err;
+}
+
+struct au_cpup_simple_args {
+	int *errp;
+	struct au_cp_generic *cpg;
+};
+
+static void au_call_cpup_simple(void *args)
+{
+	struct au_cpup_simple_args *a = args;
+
+	au_pin_hdir_acquire_nest(a->cpg->pin);
+	*a->errp = au_cpup_simple(a->cpg);
+	au_pin_hdir_release(a->cpg->pin);
+}
+
+static int au_do_sio_cpup_simple(struct au_cp_generic *cpg)
+{
+	int err, wkq_err;
+	struct dentry *dentry, *parent;
+	struct file *h_file;
+	struct inode *h_dir;
+
+	dentry = cpg->dentry;
+	h_file = NULL;
+	if (au_ftest_cpup(cpg->flags, HOPEN)) {
+		AuDebugOn(cpg->bsrc < 0);
+		h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0);
+		err = PTR_ERR(h_file);
+		if (IS_ERR(h_file))
+			goto out;
+	}
+
+	parent = dget_parent(dentry);
+	h_dir = au_h_iptr(d_inode(parent), cpg->bdst);
+	if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE)
+	    && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode))
+		err = au_cpup_simple(cpg);
+	else {
+		struct au_cpup_simple_args args = {
+			.errp		= &err,
+			.cpg		= cpg
+		};
+		wkq_err = au_wkq_wait(au_call_cpup_simple, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+	}
+
+	dput(parent);
+	if (h_file)
+		au_h_open_post(dentry, cpg->bsrc, h_file);
+
+out:
+	return err;
+}
+
+int au_sio_cpup_simple(struct au_cp_generic *cpg)
+{
+	aufs_bindex_t bsrc, bend;
+	struct dentry *dentry, *h_dentry;
+
+	if (cpg->bsrc < 0) {
+		dentry = cpg->dentry;
+		bend = au_dbend(dentry);
+		for (bsrc = cpg->bdst + 1; bsrc <= bend; bsrc++) {
+			h_dentry = au_h_dptr(dentry, bsrc);
+			if (h_dentry) {
+				AuDebugOn(d_is_negative(h_dentry));
+				break;
+			}
+		}
+		AuDebugOn(bsrc > bend);
+		cpg->bsrc = bsrc;
+	}
+	AuDebugOn(cpg->bsrc <= cpg->bdst);
+	return au_do_sio_cpup_simple(cpg);
+}
+
+int au_sio_cpdown_simple(struct au_cp_generic *cpg)
+{
+	AuDebugOn(cpg->bdst <= cpg->bsrc);
+	return au_do_sio_cpup_simple(cpg);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * copyup the deleted file for writing.
+ */
+static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry,
+			 struct file *file)
+{
+	int err;
+	unsigned int flags_orig;
+	aufs_bindex_t bsrc_orig;
+	struct dentry *h_d_dst, *h_d_start;
+	struct au_dinfo *dinfo;
+	struct au_hdentry *hdp;
+
+	dinfo = au_di(cpg->dentry);
+	AuRwMustWriteLock(&dinfo->di_rwsem);
+
+	bsrc_orig = cpg->bsrc;
+	cpg->bsrc = dinfo->di_bstart;
+	hdp = dinfo->di_hdentry;
+	h_d_dst = hdp[0 + cpg->bdst].hd_dentry;
+	dinfo->di_bstart = cpg->bdst;
+	hdp[0 + cpg->bdst].hd_dentry = wh_dentry;
+	h_d_start = NULL;
+	if (file) {
+		h_d_start = hdp[0 + cpg->bsrc].hd_dentry;
+		hdp[0 + cpg->bsrc].hd_dentry = au_hf_top(file)->f_path.dentry;
+	}
+	flags_orig = cpg->flags;
+	cpg->flags = !AuCpup_DTIME;
+	err = au_cpup_single(cpg, /*h_parent*/NULL);
+	cpg->flags = flags_orig;
+	if (file) {
+		if (!err)
+			err = au_reopen_nondir(file);
+		hdp[0 + cpg->bsrc].hd_dentry = h_d_start;
+	}
+	hdp[0 + cpg->bdst].hd_dentry = h_d_dst;
+	dinfo->di_bstart = cpg->bsrc;
+	cpg->bsrc = bsrc_orig;
+
+	return err;
+}
+
+static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file)
+{
+	int err;
+	aufs_bindex_t bdst;
+	struct au_dtime dt;
+	struct dentry *dentry, *parent, *h_parent, *wh_dentry;
+	struct au_branch *br;
+	struct path h_path;
+
+	dentry = cpg->dentry;
+	bdst = cpg->bdst;
+	br = au_sbr(dentry->d_sb, bdst);
+	parent = dget_parent(dentry);
+	h_parent = au_h_dptr(parent, bdst);
+	wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
+	err = PTR_ERR(wh_dentry);
+	if (IS_ERR(wh_dentry))
+		goto out;
+
+	h_path.dentry = h_parent;
+	h_path.mnt = au_br_mnt(br);
+	au_dtime_store(&dt, parent, &h_path);
+	err = au_do_cpup_wh(cpg, wh_dentry, file);
+	if (unlikely(err))
+		goto out_wh;
+
+	dget(wh_dentry);
+	h_path.dentry = wh_dentry;
+	if (!d_is_dir(wh_dentry)) {
+		/* no delegation since it is just created */
+		err = vfsub_unlink(d_inode(h_parent), &h_path,
+				   /*delegated*/NULL, /*force*/0);
+	} else
+		err = vfsub_rmdir(d_inode(h_parent), &h_path);
+	if (unlikely(err)) {
+		AuIOErr("failed remove copied-up tmp file %pd(%d)\n",
+			wh_dentry, err);
+		err = -EIO;
+	}
+	au_dtime_revert(&dt);
+	au_set_hi_wh(d_inode(dentry), bdst, wh_dentry);
+
+out_wh:
+	dput(wh_dentry);
+out:
+	dput(parent);
+	return err;
+}
+
+struct au_cpup_wh_args {
+	int *errp;
+	struct au_cp_generic *cpg;
+	struct file *file;
+};
+
+static void au_call_cpup_wh(void *args)
+{
+	struct au_cpup_wh_args *a = args;
+
+	au_pin_hdir_acquire_nest(a->cpg->pin);
+	*a->errp = au_cpup_wh(a->cpg, a->file);
+	au_pin_hdir_release(a->cpg->pin);
+}
+
+int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file)
+{
+	int err, wkq_err;
+	aufs_bindex_t bdst;
+	struct dentry *dentry, *parent, *h_orph, *h_parent;
+	struct inode *dir, *h_dir, *h_tmpdir;
+	struct au_wbr *wbr;
+	struct au_pin wh_pin, *pin_orig;
+
+	dentry = cpg->dentry;
+	bdst = cpg->bdst;
+	parent = dget_parent(dentry);
+	dir = d_inode(parent);
+	h_orph = NULL;
+	h_parent = NULL;
+	h_dir = au_igrab(au_h_iptr(dir, bdst));
+	h_tmpdir = h_dir;
+	pin_orig = NULL;
+	if (!h_dir->i_nlink) {
+		wbr = au_sbr(dentry->d_sb, bdst)->br_wbr;
+		h_orph = wbr->wbr_orph;
+
+		h_parent = dget(au_h_dptr(parent, bdst));
+		au_set_h_dptr(parent, bdst, dget(h_orph));
+		h_tmpdir = d_inode(h_orph);
+		au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0);
+
+		mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3);
+		/* todo: au_h_open_pre()? */
+
+		pin_orig = cpg->pin;
+		au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT,
+			    AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED);
+		cpg->pin = &wh_pin;
+	}
+
+	if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE)
+	    && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode))
+		err = au_cpup_wh(cpg, file);
+	else {
+		struct au_cpup_wh_args args = {
+			.errp	= &err,
+			.cpg	= cpg,
+			.file	= file
+		};
+		wkq_err = au_wkq_wait(au_call_cpup_wh, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+	}
+
+	if (h_orph) {
+		mutex_unlock(&h_tmpdir->i_mutex);
+		/* todo: au_h_open_post()? */
+		au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0);
+		au_set_h_dptr(parent, bdst, h_parent);
+		AuDebugOn(!pin_orig);
+		cpg->pin = pin_orig;
+	}
+	iput(h_dir);
+	dput(parent);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * generic routine for both of copy-up and copy-down.
+ */
+/* cf. revalidate function in file.c */
+int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
+	       int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
+			 struct au_pin *pin,
+			 struct dentry *h_parent, void *arg),
+	       void *arg)
+{
+	int err;
+	struct au_pin pin;
+	struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry;
+
+	err = 0;
+	parent = dget_parent(dentry);
+	if (IS_ROOT(parent))
+		goto out;
+
+	au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2,
+		    au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE);
+
+	/* do not use au_dpage */
+	real_parent = parent;
+	while (1) {
+		dput(parent);
+		parent = dget_parent(dentry);
+		h_parent = au_h_dptr(parent, bdst);
+		if (h_parent)
+			goto out; /* success */
+
+		/* find top dir which is necessary to cpup */
+		do {
+			d = parent;
+			dput(parent);
+			parent = dget_parent(d);
+			di_read_lock_parent3(parent, !AuLock_IR);
+			h_parent = au_h_dptr(parent, bdst);
+			di_read_unlock(parent, !AuLock_IR);
+		} while (!h_parent);
+
+		if (d != real_parent)
+			di_write_lock_child3(d);
+
+		/* somebody else might create while we were sleeping */
+		h_dentry = au_h_dptr(d, bdst);
+		if (!h_dentry || d_is_negative(h_dentry)) {
+			if (h_dentry)
+				au_update_dbstart(d);
+
+			au_pin_set_dentry(&pin, d);
+			err = au_do_pin(&pin);
+			if (!err) {
+				err = cp(d, bdst, &pin, h_parent, arg);
+				au_unpin(&pin);
+			}
+		}
+
+		if (d != real_parent)
+			di_write_unlock(d);
+		if (unlikely(err))
+			break;
+	}
+
+out:
+	dput(parent);
+	return err;
+}
+
+static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst,
+		       struct au_pin *pin,
+		       struct dentry *h_parent __maybe_unused,
+		       void *arg __maybe_unused)
+{
+	struct au_cp_generic cpg = {
+		.dentry	= dentry,
+		.bdst	= bdst,
+		.bsrc	= -1,
+		.len	= 0,
+		.pin	= pin,
+		.flags	= AuCpup_DTIME
+	};
+	return au_sio_cpup_simple(&cpg);
+}
+
+int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
+{
+	return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL);
+}
+
+int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
+{
+	int err;
+	struct dentry *parent;
+	struct inode *dir;
+
+	parent = dget_parent(dentry);
+	dir = d_inode(parent);
+	err = 0;
+	if (au_h_iptr(dir, bdst))
+		goto out;
+
+	di_read_unlock(parent, AuLock_IR);
+	di_write_lock_parent(parent);
+	/* someone else might change our inode while we were sleeping */
+	if (!au_h_iptr(dir, bdst))
+		err = au_cpup_dirs(dentry, bdst);
+	di_downgrade_lock(parent, AuLock_IR);
+
+out:
+	dput(parent);
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/cpup.h
+++ linux-4.4.0/fs/aufs/cpup.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * copy-up/down functions
+ */
+
+#ifndef __AUFS_CPUP_H__
+#define __AUFS_CPUP_H__
+
+#ifdef __KERNEL__
+
+#include <linux/path.h>
+
+struct inode;
+struct file;
+struct au_pin;
+
+void au_cpup_attr_flags(struct inode *dst, unsigned int iflags);
+void au_cpup_attr_timesizes(struct inode *inode);
+void au_cpup_attr_nlink(struct inode *inode, int force);
+void au_cpup_attr_changeable(struct inode *inode);
+void au_cpup_igen(struct inode *inode, struct inode *h_inode);
+void au_cpup_attr_all(struct inode *inode, int force);
+
+/* ---------------------------------------------------------------------- */
+
+struct au_cp_generic {
+	struct dentry	*dentry;
+	aufs_bindex_t	bdst, bsrc;
+	loff_t		len;
+	struct au_pin	*pin;
+	unsigned int	flags;
+};
+
+/* cpup flags */
+#define AuCpup_DTIME		1		/* do dtime_store/revert */
+#define AuCpup_KEEPLINO		(1 << 1)	/* do not clear the lower xino,
+						   for link(2) */
+#define AuCpup_RENAME		(1 << 2)	/* rename after cpup */
+#define AuCpup_HOPEN		(1 << 3)	/* call h_open_pre/post() in
+						   cpup */
+#define AuCpup_OVERWRITE	(1 << 4)	/* allow overwriting the
+						   existing entry */
+#define AuCpup_RWDST		(1 << 5)	/* force write target even if
+						   the branch is marked as RO */
+
+#define au_ftest_cpup(flags, name)	((flags) & AuCpup_##name)
+#define au_fset_cpup(flags, name) \
+	do { (flags) |= AuCpup_##name; } while (0)
+#define au_fclr_cpup(flags, name) \
+	do { (flags) &= ~AuCpup_##name; } while (0)
+
+int au_copy_file(struct file *dst, struct file *src, loff_t len);
+int au_sio_cpup_simple(struct au_cp_generic *cpg);
+int au_sio_cpdown_simple(struct au_cp_generic *cpg);
+int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file);
+
+int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
+	       int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
+			 struct au_pin *pin,
+			 struct dentry *h_parent, void *arg),
+	       void *arg);
+int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst);
+int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst);
+
+/* ---------------------------------------------------------------------- */
+
+/* keep timestamps when copyup */
+struct au_dtime {
+	struct dentry *dt_dentry;
+	struct path dt_h_path;
+	struct timespec dt_atime, dt_mtime;
+};
+void au_dtime_store(struct au_dtime *dt, struct dentry *dentry,
+		    struct path *h_path);
+void au_dtime_revert(struct au_dtime *dt);
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_CPUP_H__ */
--- linux-4.4.0.orig/fs/aufs/dbgaufs.c
+++ linux-4.4.0/fs/aufs/dbgaufs.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * debugfs interface
+ */
+
+#include <linux/debugfs.h>
+#include "aufs.h"
+
+#ifndef CONFIG_SYSFS
+#error DEBUG_FS depends upon SYSFS
+#endif
+
+static struct dentry *dbgaufs;
+static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH;
+
+/* 20 is max digits length of ulong 64 */
+struct dbgaufs_arg {
+	int n;
+	char a[20 * 4];
+};
+
+/*
+ * common function for all XINO files
+ */
+static int dbgaufs_xi_release(struct inode *inode __maybe_unused,
+			      struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt)
+{
+	int err;
+	struct kstat st;
+	struct dbgaufs_arg *p;
+
+	err = -ENOMEM;
+	p = kmalloc(sizeof(*p), GFP_NOFS);
+	if (unlikely(!p))
+		goto out;
+
+	err = 0;
+	p->n = 0;
+	file->private_data = p;
+	if (!xf)
+		goto out;
+
+	err = vfs_getattr(&xf->f_path, &st);
+	if (!err) {
+		if (do_fcnt)
+			p->n = snprintf
+				(p->a, sizeof(p->a), "%ld, %llux%lu %lld\n",
+				 (long)file_count(xf), st.blocks, st.blksize,
+				 (long long)st.size);
+		else
+			p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n",
+					st.blocks, st.blksize,
+					(long long)st.size);
+		AuDebugOn(p->n >= sizeof(p->a));
+	} else {
+		p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err);
+		err = 0;
+	}
+
+out:
+	return err;
+
+}
+
+static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf,
+			       size_t count, loff_t *ppos)
+{
+	struct dbgaufs_arg *p;
+
+	p = file->private_data;
+	return simple_read_from_buffer(buf, count, ppos, p->a, p->n);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct dbgaufs_plink_arg {
+	int n;
+	char a[];
+};
+
+static int dbgaufs_plink_release(struct inode *inode __maybe_unused,
+				 struct file *file)
+{
+	free_page((unsigned long)file->private_data);
+	return 0;
+}
+
+static int dbgaufs_plink_open(struct inode *inode, struct file *file)
+{
+	int err, i, limit;
+	unsigned long n, sum;
+	struct dbgaufs_plink_arg *p;
+	struct au_sbinfo *sbinfo;
+	struct super_block *sb;
+	struct au_sphlhead *sphl;
+
+	err = -ENOMEM;
+	p = (void *)get_zeroed_page(GFP_NOFS);
+	if (unlikely(!p))
+		goto out;
+
+	err = -EFBIG;
+	sbinfo = inode->i_private;
+	sb = sbinfo->si_sb;
+	si_noflush_read_lock(sb);
+	if (au_opt_test(au_mntflags(sb), PLINK)) {
+		limit = PAGE_SIZE - sizeof(p->n);
+
+		/* the number of buckets */
+		n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH);
+		p->n += n;
+		limit -= n;
+
+		sum = 0;
+		for (i = 0, sphl = sbinfo->si_plink;
+		     i < AuPlink_NHASH;
+		     i++, sphl++) {
+			n = au_sphl_count(sphl);
+			sum += n;
+
+			n = snprintf(p->a + p->n, limit, "%lu ", n);
+			p->n += n;
+			limit -= n;
+			if (unlikely(limit <= 0))
+				goto out_free;
+		}
+		p->a[p->n - 1] = '\n';
+
+		/* the sum of plinks */
+		n = snprintf(p->a + p->n, limit, "%lu\n", sum);
+		p->n += n;
+		limit -= n;
+		if (unlikely(limit <= 0))
+			goto out_free;
+	} else {
+#define str "1\n0\n0\n"
+		p->n = sizeof(str) - 1;
+		strcpy(p->a, str);
+#undef str
+	}
+	si_read_unlock(sb);
+
+	err = 0;
+	file->private_data = p;
+	goto out; /* success */
+
+out_free:
+	free_page((unsigned long)p);
+out:
+	return err;
+}
+
+static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf,
+				  size_t count, loff_t *ppos)
+{
+	struct dbgaufs_plink_arg *p;
+
+	p = file->private_data;
+	return simple_read_from_buffer(buf, count, ppos, p->a, p->n);
+}
+
+static const struct file_operations dbgaufs_plink_fop = {
+	.owner		= THIS_MODULE,
+	.open		= dbgaufs_plink_open,
+	.release	= dbgaufs_plink_release,
+	.read		= dbgaufs_plink_read
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int dbgaufs_xib_open(struct inode *inode, struct file *file)
+{
+	int err;
+	struct au_sbinfo *sbinfo;
+	struct super_block *sb;
+
+	sbinfo = inode->i_private;
+	sb = sbinfo->si_sb;
+	si_noflush_read_lock(sb);
+	err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0);
+	si_read_unlock(sb);
+	return err;
+}
+
+static const struct file_operations dbgaufs_xib_fop = {
+	.owner		= THIS_MODULE,
+	.open		= dbgaufs_xib_open,
+	.release	= dbgaufs_xi_release,
+	.read		= dbgaufs_xi_read
+};
+
+/* ---------------------------------------------------------------------- */
+
+#define DbgaufsXi_PREFIX "xi"
+
+static int dbgaufs_xino_open(struct inode *inode, struct file *file)
+{
+	int err;
+	long l;
+	struct au_sbinfo *sbinfo;
+	struct super_block *sb;
+	struct file *xf;
+	struct qstr *name;
+
+	err = -ENOENT;
+	xf = NULL;
+	name = &file->f_path.dentry->d_name;
+	if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX)
+		     || memcmp(name->name, DbgaufsXi_PREFIX,
+			       sizeof(DbgaufsXi_PREFIX) - 1)))
+		goto out;
+	err = kstrtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l);
+	if (unlikely(err))
+		goto out;
+
+	sbinfo = inode->i_private;
+	sb = sbinfo->si_sb;
+	si_noflush_read_lock(sb);
+	if (l <= au_sbend(sb)) {
+		xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file;
+		err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1);
+	} else
+		err = -ENOENT;
+	si_read_unlock(sb);
+
+out:
+	return err;
+}
+
+static const struct file_operations dbgaufs_xino_fop = {
+	.owner		= THIS_MODULE,
+	.open		= dbgaufs_xino_open,
+	.release	= dbgaufs_xi_release,
+	.read		= dbgaufs_xi_read
+};
+
+void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
+{
+	aufs_bindex_t bend;
+	struct au_branch *br;
+	struct au_xino_file *xi;
+
+	if (!au_sbi(sb)->si_dbgaufs)
+		return;
+
+	bend = au_sbend(sb);
+	for (; bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		xi = &br->br_xino;
+		debugfs_remove(xi->xi_dbgaufs);
+		xi->xi_dbgaufs = NULL;
+	}
+}
+
+void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
+{
+	struct au_sbinfo *sbinfo;
+	struct dentry *parent;
+	struct au_branch *br;
+	struct au_xino_file *xi;
+	aufs_bindex_t bend;
+	char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */
+
+	sbinfo = au_sbi(sb);
+	parent = sbinfo->si_dbgaufs;
+	if (!parent)
+		return;
+
+	bend = au_sbend(sb);
+	for (; bindex <= bend; bindex++) {
+		snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex);
+		br = au_sbr(sb, bindex);
+		xi = &br->br_xino;
+		AuDebugOn(xi->xi_dbgaufs);
+		xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent,
+						     sbinfo, &dbgaufs_xino_fop);
+		/* ignore an error */
+		if (unlikely(!xi->xi_dbgaufs))
+			AuWarn1("failed %s under debugfs\n", name);
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef CONFIG_AUFS_EXPORT
+static int dbgaufs_xigen_open(struct inode *inode, struct file *file)
+{
+	int err;
+	struct au_sbinfo *sbinfo;
+	struct super_block *sb;
+
+	sbinfo = inode->i_private;
+	sb = sbinfo->si_sb;
+	si_noflush_read_lock(sb);
+	err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0);
+	si_read_unlock(sb);
+	return err;
+}
+
+static const struct file_operations dbgaufs_xigen_fop = {
+	.owner		= THIS_MODULE,
+	.open		= dbgaufs_xigen_open,
+	.release	= dbgaufs_xi_release,
+	.read		= dbgaufs_xi_read
+};
+
+static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
+{
+	int err;
+
+	/*
+	 * This function is a dynamic '__init' function actually,
+	 * so the tiny check for si_rwsem is unnecessary.
+	 */
+	/* AuRwMustWriteLock(&sbinfo->si_rwsem); */
+
+	err = -EIO;
+	sbinfo->si_dbgaufs_xigen = debugfs_create_file
+		("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
+		 &dbgaufs_xigen_fop);
+	if (sbinfo->si_dbgaufs_xigen)
+		err = 0;
+
+	return err;
+}
+#else
+static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
+{
+	return 0;
+}
+#endif /* CONFIG_AUFS_EXPORT */
+
+/* ---------------------------------------------------------------------- */
+
+void dbgaufs_si_fin(struct au_sbinfo *sbinfo)
+{
+	/*
+	 * This function is a dynamic '__fin' function actually,
+	 * so the tiny check for si_rwsem is unnecessary.
+	 */
+	/* AuRwMustWriteLock(&sbinfo->si_rwsem); */
+
+	debugfs_remove_recursive(sbinfo->si_dbgaufs);
+	sbinfo->si_dbgaufs = NULL;
+	kobject_put(&sbinfo->si_kobj);
+}
+
+int dbgaufs_si_init(struct au_sbinfo *sbinfo)
+{
+	int err;
+	char name[SysaufsSiNameLen];
+
+	/*
+	 * This function is a dynamic '__init' function actually,
+	 * so the tiny check for si_rwsem is unnecessary.
+	 */
+	/* AuRwMustWriteLock(&sbinfo->si_rwsem); */
+
+	err = -ENOENT;
+	if (!dbgaufs) {
+		AuErr1("/debug/aufs is uninitialized\n");
+		goto out;
+	}
+
+	err = -EIO;
+	sysaufs_name(sbinfo, name);
+	sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs);
+	if (unlikely(!sbinfo->si_dbgaufs))
+		goto out;
+	kobject_get(&sbinfo->si_kobj);
+
+	sbinfo->si_dbgaufs_xib = debugfs_create_file
+		("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
+		 &dbgaufs_xib_fop);
+	if (unlikely(!sbinfo->si_dbgaufs_xib))
+		goto out_dir;
+
+	sbinfo->si_dbgaufs_plink = debugfs_create_file
+		("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
+		 &dbgaufs_plink_fop);
+	if (unlikely(!sbinfo->si_dbgaufs_plink))
+		goto out_dir;
+
+	err = dbgaufs_xigen_init(sbinfo);
+	if (!err)
+		goto out; /* success */
+
+out_dir:
+	dbgaufs_si_fin(sbinfo);
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void dbgaufs_fin(void)
+{
+	debugfs_remove(dbgaufs);
+}
+
+int __init dbgaufs_init(void)
+{
+	int err;
+
+	err = -EIO;
+	dbgaufs = debugfs_create_dir(AUFS_NAME, NULL);
+	if (dbgaufs)
+		err = 0;
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/dbgaufs.h
+++ linux-4.4.0/fs/aufs/dbgaufs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * debugfs interface
+ */
+
+#ifndef __DBGAUFS_H__
+#define __DBGAUFS_H__
+
+#ifdef __KERNEL__
+
+struct super_block;
+struct au_sbinfo;
+
+#ifdef CONFIG_DEBUG_FS
+/* dbgaufs.c */
+void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex);
+void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
+void dbgaufs_si_fin(struct au_sbinfo *sbinfo);
+int dbgaufs_si_init(struct au_sbinfo *sbinfo);
+void dbgaufs_fin(void);
+int __init dbgaufs_init(void);
+#else
+AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
+AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
+AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo)
+AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo)
+AuStubVoid(dbgaufs_fin, void)
+AuStubInt0(__init dbgaufs_init, void)
+#endif /* CONFIG_DEBUG_FS */
+
+#endif /* __KERNEL__ */
+#endif /* __DBGAUFS_H__ */
--- linux-4.4.0.orig/fs/aufs/dcsub.c
+++ linux-4.4.0/fs/aufs/dcsub.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * sub-routines for dentry cache
+ */
+
+#include "aufs.h"
+
+static void au_dpage_free(struct au_dpage *dpage)
+{
+	int i;
+	struct dentry **p;
+
+	p = dpage->dentries;
+	for (i = 0; i < dpage->ndentry; i++)
+		dput(*p++);
+	free_page((unsigned long)dpage->dentries);
+}
+
+int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp)
+{
+	int err;
+	void *p;
+
+	err = -ENOMEM;
+	dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp);
+	if (unlikely(!dpages->dpages))
+		goto out;
+
+	p = (void *)__get_free_page(gfp);
+	if (unlikely(!p))
+		goto out_dpages;
+
+	dpages->dpages[0].ndentry = 0;
+	dpages->dpages[0].dentries = p;
+	dpages->ndpage = 1;
+	return 0; /* success */
+
+out_dpages:
+	kfree(dpages->dpages);
+out:
+	return err;
+}
+
+void au_dpages_free(struct au_dcsub_pages *dpages)
+{
+	int i;
+	struct au_dpage *p;
+
+	p = dpages->dpages;
+	for (i = 0; i < dpages->ndpage; i++)
+		au_dpage_free(p++);
+	kfree(dpages->dpages);
+}
+
+static int au_dpages_append(struct au_dcsub_pages *dpages,
+			    struct dentry *dentry, gfp_t gfp)
+{
+	int err, sz;
+	struct au_dpage *dpage;
+	void *p;
+
+	dpage = dpages->dpages + dpages->ndpage - 1;
+	sz = PAGE_SIZE / sizeof(dentry);
+	if (unlikely(dpage->ndentry >= sz)) {
+		AuLabel(new dpage);
+		err = -ENOMEM;
+		sz = dpages->ndpage * sizeof(*dpages->dpages);
+		p = au_kzrealloc(dpages->dpages, sz,
+				 sz + sizeof(*dpages->dpages), gfp);
+		if (unlikely(!p))
+			goto out;
+
+		dpages->dpages = p;
+		dpage = dpages->dpages + dpages->ndpage;
+		p = (void *)__get_free_page(gfp);
+		if (unlikely(!p))
+			goto out;
+
+		dpage->ndentry = 0;
+		dpage->dentries = p;
+		dpages->ndpage++;
+	}
+
+	AuDebugOn(au_dcount(dentry) <= 0);
+	dpage->dentries[dpage->ndentry++] = dget_dlock(dentry);
+	return 0; /* success */
+
+out:
+	return err;
+}
+
+/* todo: BAD approach */
+/* copied from linux/fs/dcache.c */
+enum d_walk_ret {
+	D_WALK_CONTINUE,
+	D_WALK_QUIT,
+	D_WALK_NORETRY,
+	D_WALK_SKIP,
+};
+
+extern void d_walk(struct dentry *parent, void *data,
+		   enum d_walk_ret (*enter)(void *, struct dentry *),
+		   void (*finish)(void *));
+
+struct ac_dpages_arg {
+	int err;
+	struct au_dcsub_pages *dpages;
+	struct super_block *sb;
+	au_dpages_test test;
+	void *arg;
+};
+
+static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry)
+{
+	enum d_walk_ret ret;
+	struct ac_dpages_arg *arg = _arg;
+
+	ret = D_WALK_CONTINUE;
+	if (dentry->d_sb == arg->sb
+	    && !IS_ROOT(dentry)
+	    && au_dcount(dentry) > 0
+	    && au_di(dentry)
+	    && (!arg->test || arg->test(dentry, arg->arg))) {
+		arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC);
+		if (unlikely(arg->err))
+			ret = D_WALK_QUIT;
+	}
+
+	return ret;
+}
+
+int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
+		   au_dpages_test test, void *arg)
+{
+	struct ac_dpages_arg args = {
+		.err	= 0,
+		.dpages	= dpages,
+		.sb	= root->d_sb,
+		.test	= test,
+		.arg	= arg
+	};
+
+	d_walk(root, &args, au_call_dpages_append, NULL);
+
+	return args.err;
+}
+
+int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
+		       int do_include, au_dpages_test test, void *arg)
+{
+	int err;
+
+	err = 0;
+	write_seqlock(&rename_lock);
+	spin_lock(&dentry->d_lock);
+	if (do_include
+	    && au_dcount(dentry) > 0
+	    && (!test || test(dentry, arg)))
+		err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
+	spin_unlock(&dentry->d_lock);
+	if (unlikely(err))
+		goto out;
+
+	/*
+	 * RCU for vfsmount is unnecessary since this is a traverse in a single
+	 * mount
+	 */
+	while (!IS_ROOT(dentry)) {
+		dentry = dentry->d_parent; /* rename_lock is locked */
+		spin_lock(&dentry->d_lock);
+		if (au_dcount(dentry) > 0
+		    && (!test || test(dentry, arg)))
+			err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
+		spin_unlock(&dentry->d_lock);
+		if (unlikely(err))
+			break;
+	}
+
+out:
+	write_sequnlock(&rename_lock);
+	return err;
+}
+
+static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg)
+{
+	return au_di(dentry) && dentry->d_sb == arg;
+}
+
+int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
+			    struct dentry *dentry, int do_include)
+{
+	return au_dcsub_pages_rev(dpages, dentry, do_include,
+				  au_dcsub_dpages_aufs, dentry->d_sb);
+}
+
+int au_test_subdir(struct dentry *d1, struct dentry *d2)
+{
+	struct path path[2] = {
+		{
+			.dentry = d1
+		},
+		{
+			.dentry = d2
+		}
+	};
+
+	return path_is_under(path + 0, path + 1);
+}
--- linux-4.4.0.orig/fs/aufs/dcsub.h
+++ linux-4.4.0/fs/aufs/dcsub.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * sub-routines for dentry cache
+ */
+
+#ifndef __AUFS_DCSUB_H__
+#define __AUFS_DCSUB_H__
+
+#ifdef __KERNEL__
+
+#include <linux/dcache.h>
+#include <linux/fs.h>
+
+struct au_dpage {
+	int ndentry;
+	struct dentry **dentries;
+};
+
+struct au_dcsub_pages {
+	int ndpage;
+	struct au_dpage *dpages;
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* dcsub.c */
+int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp);
+void au_dpages_free(struct au_dcsub_pages *dpages);
+typedef int (*au_dpages_test)(struct dentry *dentry, void *arg);
+int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
+		   au_dpages_test test, void *arg);
+int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
+		       int do_include, au_dpages_test test, void *arg);
+int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
+			    struct dentry *dentry, int do_include);
+int au_test_subdir(struct dentry *d1, struct dentry *d2);
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * todo: in linux-3.13, several similar (but faster) helpers are added to
+ * include/linux/dcache.h. Try them (in the future).
+ */
+
+static inline int au_d_hashed_positive(struct dentry *d)
+{
+	int err;
+	struct inode *inode = d_inode(d);
+
+	err = 0;
+	if (unlikely(d_unhashed(d)
+		     || d_is_negative(d)
+		     || !inode->i_nlink))
+		err = -ENOENT;
+	return err;
+}
+
+static inline int au_d_linkable(struct dentry *d)
+{
+	int err;
+	struct inode *inode = d_inode(d);
+
+	err = au_d_hashed_positive(d);
+	if (err
+	    && d_is_positive(d)
+	    && (inode->i_state & I_LINKABLE))
+		err = 0;
+	return err;
+}
+
+static inline int au_d_alive(struct dentry *d)
+{
+	int err;
+	struct inode *inode;
+
+	err = 0;
+	if (!IS_ROOT(d))
+		err = au_d_hashed_positive(d);
+	else {
+		inode = d_inode(d);
+		if (unlikely(d_unlinked(d)
+			     || d_is_negative(d)
+			     || !inode->i_nlink))
+			err = -ENOENT;
+	}
+	return err;
+}
+
+static inline int au_alive_dir(struct dentry *d)
+{
+	int err;
+
+	err = au_d_alive(d);
+	if (unlikely(err || IS_DEADDIR(d_inode(d))))
+		err = -ENOENT;
+	return err;
+}
+
+static inline int au_qstreq(struct qstr *a, struct qstr *b)
+{
+	return a->len == b->len
+		&& !memcmp(a->name, b->name, a->len);
+}
+
+/*
+ * by the commit
+ * 360f547 2015-01-25 dcache: let the dentry count go down to zero without
+ *			taking d_lock
+ * the type of d_lockref.count became int, but the inlined function d_count()
+ * still returns unsigned int.
+ * I don't know why. Maybe it is for every d_count() users?
+ * Anyway au_dcount() lives on.
+ */
+static inline int au_dcount(struct dentry *d)
+{
+	return (int)d_count(d);
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DCSUB_H__ */
--- linux-4.4.0.orig/fs/aufs/debug.c
+++ linux-4.4.0/fs/aufs/debug.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * debug print functions
+ */
+
+#include "aufs.h"
+
+/* Returns 0, or -errno.  arg is in kp->arg. */
+static int param_atomic_t_set(const char *val, const struct kernel_param *kp)
+{
+	int err, n;
+
+	err = kstrtoint(val, 0, &n);
+	if (!err) {
+		if (n > 0)
+			au_debug_on();
+		else
+			au_debug_off();
+	}
+	return err;
+}
+
+/* Returns length written or -errno.  Buffer is 4k (ie. be short!) */
+static int param_atomic_t_get(char *buffer, const struct kernel_param *kp)
+{
+	atomic_t *a;
+
+	a = kp->arg;
+	return sprintf(buffer, "%d", atomic_read(a));
+}
+
+static struct kernel_param_ops param_ops_atomic_t = {
+	.set = param_atomic_t_set,
+	.get = param_atomic_t_get
+	/* void (*free)(void *arg) */
+};
+
+atomic_t aufs_debug = ATOMIC_INIT(0);
+MODULE_PARM_DESC(debug, "debug print");
+module_param_named(debug, aufs_debug, atomic_t, S_IRUGO | S_IWUSR | S_IWGRP);
+
+DEFINE_MUTEX(au_dbg_mtx);	/* just to serialize the dbg msgs */
+char *au_plevel = KERN_DEBUG;
+#define dpri(fmt, ...) do {					\
+	if ((au_plevel						\
+	     && strcmp(au_plevel, KERN_DEBUG))			\
+	    || au_debug_test())					\
+		printk("%s" fmt, au_plevel, ##__VA_ARGS__);	\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+
+void au_dpri_whlist(struct au_nhash *whlist)
+{
+	unsigned long ul, n;
+	struct hlist_head *head;
+	struct au_vdir_wh *pos;
+
+	n = whlist->nh_num;
+	head = whlist->nh_head;
+	for (ul = 0; ul < n; ul++) {
+		hlist_for_each_entry(pos, head, wh_hash)
+			dpri("b%d, %.*s, %d\n",
+			     pos->wh_bindex,
+			     pos->wh_str.len, pos->wh_str.name,
+			     pos->wh_str.len);
+		head++;
+	}
+}
+
+void au_dpri_vdir(struct au_vdir *vdir)
+{
+	unsigned long ul;
+	union au_vdir_deblk_p p;
+	unsigned char *o;
+
+	if (!vdir || IS_ERR(vdir)) {
+		dpri("err %ld\n", PTR_ERR(vdir));
+		return;
+	}
+
+	dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n",
+	     vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk,
+	     vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version);
+	for (ul = 0; ul < vdir->vd_nblk; ul++) {
+		p.deblk = vdir->vd_deblk[ul];
+		o = p.deblk;
+		dpri("[%lu]: %p\n", ul, o);
+	}
+}
+
+static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn,
+			struct dentry *wh)
+{
+	char *n = NULL;
+	int l = 0;
+
+	if (!inode || IS_ERR(inode)) {
+		dpri("i%d: err %ld\n", bindex, PTR_ERR(inode));
+		return -1;
+	}
+
+	/* the type of i_blocks depends upon CONFIG_LBDAF */
+	BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long)
+		     && sizeof(inode->i_blocks) != sizeof(u64));
+	if (wh) {
+		n = (void *)wh->d_name.name;
+		l = wh->d_name.len;
+	}
+
+	dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu,"
+	     " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n",
+	     bindex, inode,
+	     inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??",
+	     atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode,
+	     i_size_read(inode), (unsigned long long)inode->i_blocks,
+	     hn, (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff,
+	     inode->i_mapping ? inode->i_mapping->nrpages : 0,
+	     inode->i_state, inode->i_flags, inode->i_version,
+	     inode->i_generation,
+	     l ? ", wh " : "", l, n);
+	return 0;
+}
+
+void au_dpri_inode(struct inode *inode)
+{
+	struct au_iinfo *iinfo;
+	aufs_bindex_t bindex;
+	int err, hn;
+
+	err = do_pri_inode(-1, inode, -1, NULL);
+	if (err || !au_test_aufs(inode->i_sb))
+		return;
+
+	iinfo = au_ii(inode);
+	if (!iinfo)
+		return;
+	dpri("i-1: bstart %d, bend %d, gen %d\n",
+	     iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode, NULL));
+	if (iinfo->ii_bstart < 0)
+		return;
+	hn = 0;
+	for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) {
+		hn = !!au_hn(iinfo->ii_hinode + bindex);
+		do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode, hn,
+			     iinfo->ii_hinode[0 + bindex].hi_whdentry);
+	}
+}
+
+void au_dpri_dalias(struct inode *inode)
+{
+	struct dentry *d;
+
+	spin_lock(&inode->i_lock);
+	hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias)
+		au_dpri_dentry(d);
+	spin_unlock(&inode->i_lock);
+}
+
+static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry)
+{
+	struct dentry *wh = NULL;
+	int hn;
+	struct au_iinfo *iinfo;
+
+	if (!dentry || IS_ERR(dentry)) {
+		dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry));
+		return -1;
+	}
+	/* do not call dget_parent() here */
+	/* note: access d_xxx without d_lock */
+	dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n",
+	     bindex, dentry, dentry,
+	     dentry->d_sb ? au_sbtype(dentry->d_sb) : "??",
+	     au_dcount(dentry), dentry->d_flags,
+	     d_unhashed(dentry) ? "un" : "");
+	hn = -1;
+	if (bindex >= 0
+	    && d_is_positive(dentry)
+	    && au_test_aufs(dentry->d_sb)) {
+		iinfo = au_ii(d_inode(dentry));
+		if (iinfo) {
+			hn = !!au_hn(iinfo->ii_hinode + bindex);
+			wh = iinfo->ii_hinode[0 + bindex].hi_whdentry;
+		}
+	}
+	do_pri_inode(bindex, d_inode(dentry), hn, wh);
+	return 0;
+}
+
+void au_dpri_dentry(struct dentry *dentry)
+{
+	struct au_dinfo *dinfo;
+	aufs_bindex_t bindex;
+	int err;
+	struct au_hdentry *hdp;
+
+	err = do_pri_dentry(-1, dentry);
+	if (err || !au_test_aufs(dentry->d_sb))
+		return;
+
+	dinfo = au_di(dentry);
+	if (!dinfo)
+		return;
+	dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d, tmp %d\n",
+	     dinfo->di_bstart, dinfo->di_bend,
+	     dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry),
+	     dinfo->di_tmpfile);
+	if (dinfo->di_bstart < 0)
+		return;
+	hdp = dinfo->di_hdentry;
+	for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++)
+		do_pri_dentry(bindex, hdp[0 + bindex].hd_dentry);
+}
+
+static int do_pri_file(aufs_bindex_t bindex, struct file *file)
+{
+	char a[32];
+
+	if (!file || IS_ERR(file)) {
+		dpri("f%d: err %ld\n", bindex, PTR_ERR(file));
+		return -1;
+	}
+	a[0] = 0;
+	if (bindex < 0
+	    && !IS_ERR_OR_NULL(file->f_path.dentry)
+	    && au_test_aufs(file->f_path.dentry->d_sb)
+	    && au_fi(file))
+		snprintf(a, sizeof(a), ", gen %d, mmapped %d",
+			 au_figen(file), atomic_read(&au_fi(file)->fi_mmapped));
+	dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n",
+	     bindex, file->f_mode, file->f_flags, (long)file_count(file),
+	     file->f_version, file->f_pos, a);
+	if (!IS_ERR_OR_NULL(file->f_path.dentry))
+		do_pri_dentry(bindex, file->f_path.dentry);
+	return 0;
+}
+
+void au_dpri_file(struct file *file)
+{
+	struct au_finfo *finfo;
+	struct au_fidir *fidir;
+	struct au_hfile *hfile;
+	aufs_bindex_t bindex;
+	int err;
+
+	err = do_pri_file(-1, file);
+	if (err
+	    || IS_ERR_OR_NULL(file->f_path.dentry)
+	    || !au_test_aufs(file->f_path.dentry->d_sb))
+		return;
+
+	finfo = au_fi(file);
+	if (!finfo)
+		return;
+	if (finfo->fi_btop < 0)
+		return;
+	fidir = finfo->fi_hdir;
+	if (!fidir)
+		do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file);
+	else
+		for (bindex = finfo->fi_btop;
+		     bindex >= 0 && bindex <= fidir->fd_bbot;
+		     bindex++) {
+			hfile = fidir->fd_hfile + bindex;
+			do_pri_file(bindex, hfile ? hfile->hf_file : NULL);
+		}
+}
+
+static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br)
+{
+	struct vfsmount *mnt;
+	struct super_block *sb;
+
+	if (!br || IS_ERR(br))
+		goto out;
+	mnt = au_br_mnt(br);
+	if (!mnt || IS_ERR(mnt))
+		goto out;
+	sb = mnt->mnt_sb;
+	if (!sb || IS_ERR(sb))
+		goto out;
+
+	dpri("s%d: {perm 0x%x, id %d, cnt %d, wbr %p}, "
+	     "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, "
+	     "xino %d\n",
+	     bindex, br->br_perm, br->br_id, atomic_read(&br->br_count),
+	     br->br_wbr, au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev),
+	     sb->s_flags, sb->s_count,
+	     atomic_read(&sb->s_active), !!br->br_xino.xi_file);
+	return 0;
+
+out:
+	dpri("s%d: err %ld\n", bindex, PTR_ERR(br));
+	return -1;
+}
+
+void au_dpri_sb(struct super_block *sb)
+{
+	struct au_sbinfo *sbinfo;
+	aufs_bindex_t bindex;
+	int err;
+	/* to reuduce stack size */
+	struct {
+		struct vfsmount mnt;
+		struct au_branch fake;
+	} *a;
+
+	/* this function can be called from magic sysrq */
+	a = kzalloc(sizeof(*a), GFP_ATOMIC);
+	if (unlikely(!a)) {
+		dpri("no memory\n");
+		return;
+	}
+
+	a->mnt.mnt_sb = sb;
+	a->fake.br_path.mnt = &a->mnt;
+	atomic_set(&a->fake.br_count, 0);
+	smp_mb(); /* atomic_set */
+	err = do_pri_br(-1, &a->fake);
+	kfree(a);
+	dpri("dev 0x%x\n", sb->s_dev);
+	if (err || !au_test_aufs(sb))
+		return;
+
+	sbinfo = au_sbi(sb);
+	if (!sbinfo)
+		return;
+	dpri("nw %d, gen %u, kobj %d\n",
+	     atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation,
+	     atomic_read(&sbinfo->si_kobj.kref.refcount));
+	for (bindex = 0; bindex <= sbinfo->si_bend; bindex++)
+		do_pri_br(bindex, sbinfo->si_branch[0 + bindex]);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line)
+{
+	struct inode *h_inode, *inode = d_inode(dentry);
+	struct dentry *h_dentry;
+	aufs_bindex_t bindex, bend, bi;
+
+	if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */)
+		return;
+
+	bend = au_dbend(dentry);
+	bi = au_ibend(inode);
+	if (bi < bend)
+		bend = bi;
+	bindex = au_dbstart(dentry);
+	bi = au_ibstart(inode);
+	if (bi > bindex)
+		bindex = bi;
+
+	for (; bindex <= bend; bindex++) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (!h_dentry)
+			continue;
+		h_inode = au_h_iptr(inode, bindex);
+		if (unlikely(h_inode != d_inode(h_dentry))) {
+			au_debug_on();
+			AuDbg("b%d, %s:%d\n", bindex, func, line);
+			AuDbgDentry(dentry);
+			AuDbgInode(inode);
+			au_debug_off();
+			BUG();
+		}
+	}
+}
+
+void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
+{
+	int err, i, j;
+	struct au_dcsub_pages dpages;
+	struct au_dpage *dpage;
+	struct dentry **dentries;
+
+	err = au_dpages_init(&dpages, GFP_NOFS);
+	AuDebugOn(err);
+	err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1);
+	AuDebugOn(err);
+	for (i = dpages.ndpage - 1; !err && i >= 0; i--) {
+		dpage = dpages.dpages + i;
+		dentries = dpage->dentries;
+		for (j = dpage->ndentry - 1; !err && j >= 0; j--)
+			AuDebugOn(au_digen_test(dentries[j], sigen));
+	}
+	au_dpages_free(&dpages);
+}
+
+void au_dbg_verify_kthread(void)
+{
+	if (au_wkq_test()) {
+		au_dbg_blocked();
+		/*
+		 * It may be recursive, but udba=notify between two aufs mounts,
+		 * where a single ro branch is shared, is not a problem.
+		 */
+		/* WARN_ON(1); */
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+int __init au_debug_init(void)
+{
+	aufs_bindex_t bindex;
+	struct au_vdir_destr destr;
+
+	bindex = -1;
+	AuDebugOn(bindex >= 0);
+
+	destr.len = -1;
+	AuDebugOn(destr.len < NAME_MAX);
+
+#ifdef CONFIG_4KSTACKS
+	pr_warn("CONFIG_4KSTACKS is defined.\n");
+#endif
+
+	return 0;
+}
--- linux-4.4.0.orig/fs/aufs/debug.h
+++ linux-4.4.0/fs/aufs/debug.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * debug print functions
+ */
+
+#ifndef __AUFS_DEBUG_H__
+#define __AUFS_DEBUG_H__
+
+#ifdef __KERNEL__
+
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/sysrq.h>
+
+#ifdef CONFIG_AUFS_DEBUG
+#define AuDebugOn(a)		BUG_ON(a)
+
+/* module parameter */
+extern atomic_t aufs_debug;
+static inline void au_debug_on(void)
+{
+	atomic_inc(&aufs_debug);
+}
+static inline void au_debug_off(void)
+{
+	atomic_dec_if_positive(&aufs_debug);
+}
+
+static inline int au_debug_test(void)
+{
+	return atomic_read(&aufs_debug) > 0;
+}
+#else
+#define AuDebugOn(a)		do {} while (0)
+AuStubVoid(au_debug_on, void)
+AuStubVoid(au_debug_off, void)
+AuStubInt0(au_debug_test, void)
+#endif /* CONFIG_AUFS_DEBUG */
+
+#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t)
+
+/* ---------------------------------------------------------------------- */
+
+/* debug print */
+
+#define AuDbg(fmt, ...) do { \
+	if (au_debug_test()) \
+		pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \
+} while (0)
+#define AuLabel(l)		AuDbg(#l "\n")
+#define AuIOErr(fmt, ...)	pr_err("I/O Error, " fmt, ##__VA_ARGS__)
+#define AuWarn1(fmt, ...) do { \
+	static unsigned char _c; \
+	if (!_c++) \
+		pr_warn(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define AuErr1(fmt, ...) do { \
+	static unsigned char _c; \
+	if (!_c++) \
+		pr_err(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define AuIOErr1(fmt, ...) do { \
+	static unsigned char _c; \
+	if (!_c++) \
+		AuIOErr(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define AuUnsupportMsg	"This operation is not supported." \
+			" Please report this application to aufs-users ML."
+#define AuUnsupport(fmt, ...) do { \
+	pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \
+	dump_stack(); \
+} while (0)
+
+#define AuTraceErr(e) do { \
+	if (unlikely((e) < 0)) \
+		AuDbg("err %d\n", (int)(e)); \
+} while (0)
+
+#define AuTraceErrPtr(p) do { \
+	if (IS_ERR(p)) \
+		AuDbg("err %ld\n", PTR_ERR(p)); \
+} while (0)
+
+/* dirty macros for debug print, use with "%.*s" and caution */
+#define AuLNPair(qstr)		(qstr)->len, (qstr)->name
+
+/* ---------------------------------------------------------------------- */
+
+struct dentry;
+#ifdef CONFIG_AUFS_DEBUG
+extern struct mutex au_dbg_mtx;
+extern char *au_plevel;
+struct au_nhash;
+void au_dpri_whlist(struct au_nhash *whlist);
+struct au_vdir;
+void au_dpri_vdir(struct au_vdir *vdir);
+struct inode;
+void au_dpri_inode(struct inode *inode);
+void au_dpri_dalias(struct inode *inode);
+void au_dpri_dentry(struct dentry *dentry);
+struct file;
+void au_dpri_file(struct file *filp);
+struct super_block;
+void au_dpri_sb(struct super_block *sb);
+
+#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__)
+void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line);
+void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen);
+void au_dbg_verify_kthread(void);
+
+int __init au_debug_init(void);
+
+#define AuDbgWhlist(w) do { \
+	mutex_lock(&au_dbg_mtx); \
+	AuDbg(#w "\n"); \
+	au_dpri_whlist(w); \
+	mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgVdir(v) do { \
+	mutex_lock(&au_dbg_mtx); \
+	AuDbg(#v "\n"); \
+	au_dpri_vdir(v); \
+	mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgInode(i) do { \
+	mutex_lock(&au_dbg_mtx); \
+	AuDbg(#i "\n"); \
+	au_dpri_inode(i); \
+	mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgDAlias(i) do { \
+	mutex_lock(&au_dbg_mtx); \
+	AuDbg(#i "\n"); \
+	au_dpri_dalias(i); \
+	mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgDentry(d) do { \
+	mutex_lock(&au_dbg_mtx); \
+	AuDbg(#d "\n"); \
+	au_dpri_dentry(d); \
+	mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgFile(f) do { \
+	mutex_lock(&au_dbg_mtx); \
+	AuDbg(#f "\n"); \
+	au_dpri_file(f); \
+	mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgSb(sb) do { \
+	mutex_lock(&au_dbg_mtx); \
+	AuDbg(#sb "\n"); \
+	au_dpri_sb(sb); \
+	mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgSym(addr) do {				\
+	char sym[KSYM_SYMBOL_LEN];			\
+	sprint_symbol(sym, (unsigned long)addr);	\
+	AuDbg("%s\n", sym);				\
+} while (0)
+#else
+AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry)
+AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen)
+AuStubVoid(au_dbg_verify_kthread, void)
+AuStubInt0(__init au_debug_init, void)
+
+#define AuDbgWhlist(w)		do {} while (0)
+#define AuDbgVdir(v)		do {} while (0)
+#define AuDbgInode(i)		do {} while (0)
+#define AuDbgDAlias(i)		do {} while (0)
+#define AuDbgDentry(d)		do {} while (0)
+#define AuDbgFile(f)		do {} while (0)
+#define AuDbgSb(sb)		do {} while (0)
+#define AuDbgSym(addr)		do {} while (0)
+#endif /* CONFIG_AUFS_DEBUG */
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef CONFIG_AUFS_MAGIC_SYSRQ
+int __init au_sysrq_init(void);
+void au_sysrq_fin(void);
+
+#ifdef CONFIG_HW_CONSOLE
+#define au_dbg_blocked() do { \
+	WARN_ON(1); \
+	handle_sysrq('w'); \
+} while (0)
+#else
+AuStubVoid(au_dbg_blocked, void)
+#endif
+
+#else
+AuStubInt0(__init au_sysrq_init, void)
+AuStubVoid(au_sysrq_fin, void)
+AuStubVoid(au_dbg_blocked, void)
+#endif /* CONFIG_AUFS_MAGIC_SYSRQ */
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DEBUG_H__ */
--- linux-4.4.0.orig/fs/aufs/dentry.c
+++ linux-4.4.0/fs/aufs/dentry.c
@@ -0,0 +1,1136 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * lookup and dentry operations
+ */
+
+#include <linux/namei.h>
+#include "aufs.h"
+
+#define AuLkup_ALLOW_NEG	1
+#define AuLkup_IGNORE_PERM	(1 << 1)
+#define au_ftest_lkup(flags, name)	((flags) & AuLkup_##name)
+#define au_fset_lkup(flags, name) \
+	do { (flags) |= AuLkup_##name; } while (0)
+#define au_fclr_lkup(flags, name) \
+	do { (flags) &= ~AuLkup_##name; } while (0)
+
+struct au_do_lookup_args {
+	unsigned int		flags;
+	mode_t			type;
+};
+
+/*
+ * returns positive/negative dentry, NULL or an error.
+ * NULL means whiteout-ed or not-found.
+ */
+static struct dentry*
+au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
+	     aufs_bindex_t bindex, struct qstr *wh_name,
+	     struct au_do_lookup_args *args)
+{
+	struct dentry *h_dentry;
+	struct inode *h_inode;
+	struct au_branch *br;
+	int wh_found, opq;
+	unsigned char wh_able;
+	const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG);
+	const unsigned char ignore_perm = !!au_ftest_lkup(args->flags,
+							  IGNORE_PERM);
+
+	wh_found = 0;
+	br = au_sbr(dentry->d_sb, bindex);
+	wh_able = !!au_br_whable(br->br_perm);
+	if (wh_able)
+		wh_found = au_wh_test(h_parent, wh_name, /*try_sio*/0);
+	h_dentry = ERR_PTR(wh_found);
+	if (!wh_found)
+		goto real_lookup;
+	if (unlikely(wh_found < 0))
+		goto out;
+
+	/* We found a whiteout */
+	/* au_set_dbend(dentry, bindex); */
+	au_set_dbwh(dentry, bindex);
+	if (!allow_neg)
+		return NULL; /* success */
+
+real_lookup:
+	if (!ignore_perm)
+		h_dentry = vfsub_lkup_one(&dentry->d_name, h_parent);
+	else
+		h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent);
+	if (IS_ERR(h_dentry)) {
+		if (PTR_ERR(h_dentry) == -ENAMETOOLONG
+		    && !allow_neg)
+			h_dentry = NULL;
+		goto out;
+	}
+
+	h_inode = d_inode(h_dentry);
+	if (d_is_negative(h_dentry)) {
+		if (!allow_neg)
+			goto out_neg;
+	} else if (wh_found
+		   || (args->type && args->type != (h_inode->i_mode & S_IFMT)))
+		goto out_neg;
+
+	if (au_dbend(dentry) <= bindex)
+		au_set_dbend(dentry, bindex);
+	if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
+		au_set_dbstart(dentry, bindex);
+	au_set_h_dptr(dentry, bindex, h_dentry);
+
+	if (!d_is_dir(h_dentry)
+	    || !wh_able
+	    || (d_really_is_positive(dentry) && !d_is_dir(dentry)))
+		goto out; /* success */
+
+	mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
+	opq = au_diropq_test(h_dentry);
+	mutex_unlock(&h_inode->i_mutex);
+	if (opq > 0)
+		au_set_dbdiropq(dentry, bindex);
+	else if (unlikely(opq < 0)) {
+		au_set_h_dptr(dentry, bindex, NULL);
+		h_dentry = ERR_PTR(opq);
+	}
+	goto out;
+
+out_neg:
+	dput(h_dentry);
+	h_dentry = NULL;
+out:
+	return h_dentry;
+}
+
+static int au_test_shwh(struct super_block *sb, const struct qstr *name)
+{
+	if (unlikely(!au_opt_test(au_mntflags(sb), SHWH)
+		     && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)))
+		return -EPERM;
+	return 0;
+}
+
+/*
+ * returns the number of lower positive dentries,
+ * otherwise an error.
+ * can be called at unlinking with @type is zero.
+ */
+int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type)
+{
+	int npositive, err;
+	aufs_bindex_t bindex, btail, bdiropq;
+	unsigned char isdir, dirperm1;
+	struct qstr whname;
+	struct au_do_lookup_args args = {
+		.flags		= 0,
+		.type		= type
+	};
+	const struct qstr *name = &dentry->d_name;
+	struct dentry *parent;
+	struct super_block *sb;
+
+	sb = dentry->d_sb;
+	err = au_test_shwh(sb, name);
+	if (unlikely(err))
+		goto out;
+
+	err = au_wh_name_alloc(&whname, name);
+	if (unlikely(err))
+		goto out;
+
+	isdir = !!d_is_dir(dentry);
+	if (!type)
+		au_fset_lkup(args.flags, ALLOW_NEG);
+	dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1);
+
+	npositive = 0;
+	parent = dget_parent(dentry);
+	btail = au_dbtaildir(parent);
+	for (bindex = bstart; bindex <= btail; bindex++) {
+		struct dentry *h_parent, *h_dentry;
+		struct inode *h_inode, *h_dir;
+
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (h_dentry) {
+			if (d_is_positive(h_dentry))
+				npositive++;
+			if (type != S_IFDIR)
+				break;
+			continue;
+		}
+		h_parent = au_h_dptr(parent, bindex);
+		if (!h_parent || !d_is_dir(h_parent))
+			continue;
+
+		h_dir = d_inode(h_parent);
+		mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
+		h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname,
+					&args);
+		mutex_unlock(&h_dir->i_mutex);
+		err = PTR_ERR(h_dentry);
+		if (IS_ERR(h_dentry))
+			goto out_parent;
+		if (h_dentry)
+			au_fclr_lkup(args.flags, ALLOW_NEG);
+		if (dirperm1)
+			au_fset_lkup(args.flags, IGNORE_PERM);
+
+		if (au_dbwh(dentry) == bindex)
+			break;
+		if (!h_dentry)
+			continue;
+		if (d_is_negative(h_dentry))
+			continue;
+		h_inode = d_inode(h_dentry);
+		npositive++;
+		if (!args.type)
+			args.type = h_inode->i_mode & S_IFMT;
+		if (args.type != S_IFDIR)
+			break;
+		else if (isdir) {
+			/* the type of lower may be different */
+			bdiropq = au_dbdiropq(dentry);
+			if (bdiropq >= 0 && bdiropq <= bindex)
+				break;
+		}
+	}
+
+	if (npositive) {
+		AuLabel(positive);
+		au_update_dbstart(dentry);
+	}
+	err = npositive;
+	if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE)
+		     && au_dbstart(dentry) < 0)) {
+		err = -EIO;
+		AuIOErr("both of real entry and whiteout found, %pd, err %d\n",
+			dentry, err);
+	}
+
+out_parent:
+	dput(parent);
+	kfree(whname.name);
+out:
+	return err;
+}
+
+struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent)
+{
+	struct dentry *dentry;
+	int wkq_err;
+
+	if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC))
+		dentry = vfsub_lkup_one(name, parent);
+	else {
+		struct vfsub_lkup_one_args args = {
+			.errp	= &dentry,
+			.name	= name,
+			.parent	= parent
+		};
+
+		wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args);
+		if (unlikely(wkq_err))
+			dentry = ERR_PTR(wkq_err);
+	}
+
+	return dentry;
+}
+
+/*
+ * lookup @dentry on @bindex which should be negative.
+ */
+int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh)
+{
+	int err;
+	struct dentry *parent, *h_parent, *h_dentry;
+	struct au_branch *br;
+
+	parent = dget_parent(dentry);
+	h_parent = au_h_dptr(parent, bindex);
+	br = au_sbr(dentry->d_sb, bindex);
+	if (wh)
+		h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
+	else
+		h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent);
+	err = PTR_ERR(h_dentry);
+	if (IS_ERR(h_dentry))
+		goto out;
+	if (unlikely(d_is_positive(h_dentry))) {
+		err = -EIO;
+		AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex);
+		dput(h_dentry);
+		goto out;
+	}
+
+	err = 0;
+	if (bindex < au_dbstart(dentry))
+		au_set_dbstart(dentry, bindex);
+	if (au_dbend(dentry) < bindex)
+		au_set_dbend(dentry, bindex);
+	au_set_h_dptr(dentry, bindex, h_dentry);
+
+out:
+	dput(parent);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* subset of struct inode */
+struct au_iattr {
+	unsigned long		i_ino;
+	/* unsigned int		i_nlink; */
+	kuid_t			i_uid;
+	kgid_t			i_gid;
+	u64			i_version;
+/*
+	loff_t			i_size;
+	blkcnt_t		i_blocks;
+*/
+	umode_t			i_mode;
+};
+
+static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode)
+{
+	ia->i_ino = h_inode->i_ino;
+	/* ia->i_nlink = h_inode->i_nlink; */
+	ia->i_uid = h_inode->i_uid;
+	ia->i_gid = h_inode->i_gid;
+	ia->i_version = h_inode->i_version;
+/*
+	ia->i_size = h_inode->i_size;
+	ia->i_blocks = h_inode->i_blocks;
+*/
+	ia->i_mode = (h_inode->i_mode & S_IFMT);
+}
+
+static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode)
+{
+	return ia->i_ino != h_inode->i_ino
+		/* || ia->i_nlink != h_inode->i_nlink */
+		|| !uid_eq(ia->i_uid, h_inode->i_uid)
+		|| !gid_eq(ia->i_gid, h_inode->i_gid)
+		|| ia->i_version != h_inode->i_version
+/*
+		|| ia->i_size != h_inode->i_size
+		|| ia->i_blocks != h_inode->i_blocks
+*/
+		|| ia->i_mode != (h_inode->i_mode & S_IFMT);
+}
+
+static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent,
+			      struct au_branch *br)
+{
+	int err;
+	struct au_iattr ia;
+	struct inode *h_inode;
+	struct dentry *h_d;
+	struct super_block *h_sb;
+
+	err = 0;
+	memset(&ia, -1, sizeof(ia));
+	h_sb = h_dentry->d_sb;
+	h_inode = NULL;
+	if (d_is_positive(h_dentry)) {
+		h_inode = d_inode(h_dentry);
+		au_iattr_save(&ia, h_inode);
+	} else if (au_test_nfs(h_sb) || au_test_fuse(h_sb))
+		/* nfs d_revalidate may return 0 for negative dentry */
+		/* fuse d_revalidate always return 0 for negative dentry */
+		goto out;
+
+	/* main purpose is namei.c:cached_lookup() and d_revalidate */
+	h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent);
+	err = PTR_ERR(h_d);
+	if (IS_ERR(h_d))
+		goto out;
+
+	err = 0;
+	if (unlikely(h_d != h_dentry
+		     || d_inode(h_d) != h_inode
+		     || (h_inode && au_iattr_test(&ia, h_inode))))
+		err = au_busy_or_stale();
+	dput(h_d);
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
+		struct dentry *h_parent, struct au_branch *br)
+{
+	int err;
+
+	err = 0;
+	if (udba == AuOpt_UDBA_REVAL
+	    && !au_test_fs_remote(h_dentry->d_sb)) {
+		IMustLock(h_dir);
+		err = (d_inode(h_dentry->d_parent) != h_dir);
+	} else if (udba != AuOpt_UDBA_NONE)
+		err = au_h_verify_dentry(h_dentry, h_parent, br);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent)
+{
+	int err;
+	aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq;
+	struct au_hdentry tmp, *p, *q;
+	struct au_dinfo *dinfo;
+	struct super_block *sb;
+
+	DiMustWriteLock(dentry);
+
+	sb = dentry->d_sb;
+	dinfo = au_di(dentry);
+	bend = dinfo->di_bend;
+	bwh = dinfo->di_bwh;
+	bdiropq = dinfo->di_bdiropq;
+	p = dinfo->di_hdentry + dinfo->di_bstart;
+	for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) {
+		if (!p->hd_dentry)
+			continue;
+
+		new_bindex = au_br_index(sb, p->hd_id);
+		if (new_bindex == bindex)
+			continue;
+
+		if (dinfo->di_bwh == bindex)
+			bwh = new_bindex;
+		if (dinfo->di_bdiropq == bindex)
+			bdiropq = new_bindex;
+		if (new_bindex < 0) {
+			au_hdput(p);
+			p->hd_dentry = NULL;
+			continue;
+		}
+
+		/* swap two lower dentries, and loop again */
+		q = dinfo->di_hdentry + new_bindex;
+		tmp = *q;
+		*q = *p;
+		*p = tmp;
+		if (tmp.hd_dentry) {
+			bindex--;
+			p--;
+		}
+	}
+
+	dinfo->di_bwh = -1;
+	if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh))
+		dinfo->di_bwh = bwh;
+
+	dinfo->di_bdiropq = -1;
+	if (bdiropq >= 0
+	    && bdiropq <= au_sbend(sb)
+	    && au_sbr_whable(sb, bdiropq))
+		dinfo->di_bdiropq = bdiropq;
+
+	err = -EIO;
+	dinfo->di_bstart = -1;
+	dinfo->di_bend = -1;
+	bend = au_dbend(parent);
+	p = dinfo->di_hdentry;
+	for (bindex = 0; bindex <= bend; bindex++, p++)
+		if (p->hd_dentry) {
+			dinfo->di_bstart = bindex;
+			break;
+		}
+
+	if (dinfo->di_bstart >= 0) {
+		p = dinfo->di_hdentry + bend;
+		for (bindex = bend; bindex >= 0; bindex--, p--)
+			if (p->hd_dentry) {
+				dinfo->di_bend = bindex;
+				err = 0;
+				break;
+			}
+	}
+
+	return err;
+}
+
+static void au_do_hide(struct dentry *dentry)
+{
+	struct inode *inode;
+
+	if (d_really_is_positive(dentry)) {
+		inode = d_inode(dentry);
+		if (!d_is_dir(dentry)) {
+			if (inode->i_nlink && !d_unhashed(dentry))
+				drop_nlink(inode);
+		} else {
+			clear_nlink(inode);
+			/* stop next lookup */
+			inode->i_flags |= S_DEAD;
+		}
+		smp_mb(); /* necessary? */
+	}
+	d_drop(dentry);
+}
+
+static int au_hide_children(struct dentry *parent)
+{
+	int err, i, j, ndentry;
+	struct au_dcsub_pages dpages;
+	struct au_dpage *dpage;
+	struct dentry *dentry;
+
+	err = au_dpages_init(&dpages, GFP_NOFS);
+	if (unlikely(err))
+		goto out;
+	err = au_dcsub_pages(&dpages, parent, NULL, NULL);
+	if (unlikely(err))
+		goto out_dpages;
+
+	/* in reverse order */
+	for (i = dpages.ndpage - 1; i >= 0; i--) {
+		dpage = dpages.dpages + i;
+		ndentry = dpage->ndentry;
+		for (j = ndentry - 1; j >= 0; j--) {
+			dentry = dpage->dentries[j];
+			if (dentry != parent)
+				au_do_hide(dentry);
+		}
+	}
+
+out_dpages:
+	au_dpages_free(&dpages);
+out:
+	return err;
+}
+
+static void au_hide(struct dentry *dentry)
+{
+	int err;
+
+	AuDbgDentry(dentry);
+	if (d_is_dir(dentry)) {
+		/* shrink_dcache_parent(dentry); */
+		err = au_hide_children(dentry);
+		if (unlikely(err))
+			AuIOErr("%pd, failed hiding children, ignored %d\n",
+				dentry, err);
+	}
+	au_do_hide(dentry);
+}
+
+/*
+ * By adding a dirty branch, a cached dentry may be affected in various ways.
+ *
+ * a dirty branch is added
+ * - on the top of layers
+ * - in the middle of layers
+ * - to the bottom of layers
+ *
+ * on the added branch there exists
+ * - a whiteout
+ * - a diropq
+ * - a same named entry
+ *   + exist
+ *     * negative --> positive
+ *     * positive --> positive
+ *	 - type is unchanged
+ *	 - type is changed
+ *   + doesn't exist
+ *     * negative --> negative
+ *     * positive --> negative (rejected by au_br_del() for non-dir case)
+ * - none
+ */
+static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo,
+			       struct au_dinfo *tmp)
+{
+	int err;
+	aufs_bindex_t bindex, bend;
+	struct {
+		struct dentry *dentry;
+		struct inode *inode;
+		mode_t mode;
+	} orig_h, tmp_h = {
+		.dentry = NULL
+	};
+	struct au_hdentry *hd;
+	struct inode *inode, *h_inode;
+	struct dentry *h_dentry;
+
+	err = 0;
+	AuDebugOn(dinfo->di_bstart < 0);
+	orig_h.mode = 0;
+	orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry;
+	orig_h.inode = NULL;
+	if (d_is_positive(orig_h.dentry)) {
+		orig_h.inode = d_inode(orig_h.dentry);
+		orig_h.mode = orig_h.inode->i_mode & S_IFMT;
+	}
+	if (tmp->di_bstart >= 0) {
+		tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry;
+		if (d_is_positive(tmp_h.dentry)) {
+			tmp_h.inode = d_inode(tmp_h.dentry);
+			tmp_h.mode = tmp_h.inode->i_mode & S_IFMT;
+		}
+	}
+
+	inode = NULL;
+	if (d_really_is_positive(dentry))
+		inode = d_inode(dentry);
+	if (!orig_h.inode) {
+		AuDbg("nagative originally\n");
+		if (inode) {
+			au_hide(dentry);
+			goto out;
+		}
+		AuDebugOn(inode);
+		AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
+		AuDebugOn(dinfo->di_bdiropq != -1);
+
+		if (!tmp_h.inode) {
+			AuDbg("negative --> negative\n");
+			/* should have only one negative lower */
+			if (tmp->di_bstart >= 0
+			    && tmp->di_bstart < dinfo->di_bstart) {
+				AuDebugOn(tmp->di_bstart != tmp->di_bend);
+				AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
+				au_set_h_dptr(dentry, dinfo->di_bstart, NULL);
+				au_di_cp(dinfo, tmp);
+				hd = tmp->di_hdentry + tmp->di_bstart;
+				au_set_h_dptr(dentry, tmp->di_bstart,
+					      dget(hd->hd_dentry));
+			}
+			au_dbg_verify_dinode(dentry);
+		} else {
+			AuDbg("negative --> positive\n");
+			/*
+			 * similar to the behaviour of creating with bypassing
+			 * aufs.
+			 * unhash it in order to force an error in the
+			 * succeeding create operation.
+			 * we should not set S_DEAD here.
+			 */
+			d_drop(dentry);
+			/* au_di_swap(tmp, dinfo); */
+			au_dbg_verify_dinode(dentry);
+		}
+	} else {
+		AuDbg("positive originally\n");
+		/* inode may be NULL */
+		AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode);
+		if (!tmp_h.inode) {
+			AuDbg("positive --> negative\n");
+			/* or bypassing aufs */
+			au_hide(dentry);
+			if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart)
+				dinfo->di_bwh = tmp->di_bwh;
+			if (inode)
+				err = au_refresh_hinode_self(inode);
+			au_dbg_verify_dinode(dentry);
+		} else if (orig_h.mode == tmp_h.mode) {
+			AuDbg("positive --> positive, same type\n");
+			if (!S_ISDIR(orig_h.mode)
+			    && dinfo->di_bstart > tmp->di_bstart) {
+				/*
+				 * similar to the behaviour of removing and
+				 * creating.
+				 */
+				au_hide(dentry);
+				if (inode)
+					err = au_refresh_hinode_self(inode);
+				au_dbg_verify_dinode(dentry);
+			} else {
+				/* fill empty slots */
+				if (dinfo->di_bstart > tmp->di_bstart)
+					dinfo->di_bstart = tmp->di_bstart;
+				if (dinfo->di_bend < tmp->di_bend)
+					dinfo->di_bend = tmp->di_bend;
+				dinfo->di_bwh = tmp->di_bwh;
+				dinfo->di_bdiropq = tmp->di_bdiropq;
+				hd = tmp->di_hdentry;
+				bend = dinfo->di_bend;
+				for (bindex = tmp->di_bstart; bindex <= bend;
+				     bindex++) {
+					if (au_h_dptr(dentry, bindex))
+						continue;
+					h_dentry = hd[bindex].hd_dentry;
+					if (!h_dentry)
+						continue;
+					AuDebugOn(d_is_negative(h_dentry));
+					h_inode = d_inode(h_dentry);
+					AuDebugOn(orig_h.mode
+						  != (h_inode->i_mode
+						      & S_IFMT));
+					au_set_h_dptr(dentry, bindex,
+						      dget(h_dentry));
+				}
+				err = au_refresh_hinode(inode, dentry);
+				au_dbg_verify_dinode(dentry);
+			}
+		} else {
+			AuDbg("positive --> positive, different type\n");
+			/* similar to the behaviour of removing and creating */
+			au_hide(dentry);
+			if (inode)
+				err = au_refresh_hinode_self(inode);
+			au_dbg_verify_dinode(dentry);
+		}
+	}
+
+out:
+	return err;
+}
+
+void au_refresh_dop(struct dentry *dentry, int force_reval)
+{
+	const struct dentry_operations *dop
+		= force_reval ? &aufs_dop : dentry->d_sb->s_d_op;
+	static const unsigned int mask
+		= DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE;
+
+	BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags));
+
+	if (dentry->d_op == dop)
+		return;
+
+	AuDbg("%pd\n", dentry);
+	spin_lock(&dentry->d_lock);
+	if (dop == &aufs_dop)
+		dentry->d_flags |= mask;
+	else
+		dentry->d_flags &= ~mask;
+	dentry->d_op = dop;
+	spin_unlock(&dentry->d_lock);
+}
+
+int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
+{
+	int err, ebrange;
+	unsigned int sigen;
+	struct au_dinfo *dinfo, *tmp;
+	struct super_block *sb;
+	struct inode *inode;
+
+	DiMustWriteLock(dentry);
+	AuDebugOn(IS_ROOT(dentry));
+	AuDebugOn(d_really_is_negative(parent));
+
+	sb = dentry->d_sb;
+	sigen = au_sigen(sb);
+	err = au_digen_test(parent, sigen);
+	if (unlikely(err))
+		goto out;
+
+	dinfo = au_di(dentry);
+	err = au_di_realloc(dinfo, au_sbend(sb) + 1);
+	if (unlikely(err))
+		goto out;
+	ebrange = au_dbrange_test(dentry);
+	if (!ebrange)
+		ebrange = au_do_refresh_hdentry(dentry, parent);
+
+	if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) {
+		AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0);
+		if (d_really_is_positive(dentry)) {
+			inode = d_inode(dentry);
+			err = au_refresh_hinode_self(inode);
+		}
+		au_dbg_verify_dinode(dentry);
+		if (!err)
+			goto out_dgen; /* success */
+		goto out;
+	}
+
+	/* temporary dinfo */
+	AuDbgDentry(dentry);
+	err = -ENOMEM;
+	tmp = au_di_alloc(sb, AuLsc_DI_TMP);
+	if (unlikely(!tmp))
+		goto out;
+	au_di_swap(tmp, dinfo);
+	/* returns the number of positive dentries */
+	/*
+	 * if current working dir is removed, it returns an error.
+	 * but the dentry is legal.
+	 */
+	err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0);
+	AuDbgDentry(dentry);
+	au_di_swap(tmp, dinfo);
+	if (err == -ENOENT)
+		err = 0;
+	if (err >= 0) {
+		/* compare/refresh by dinfo */
+		AuDbgDentry(dentry);
+		err = au_refresh_by_dinfo(dentry, dinfo, tmp);
+		au_dbg_verify_dinode(dentry);
+		AuTraceErr(err);
+	}
+	au_rw_write_unlock(&tmp->di_rwsem);
+	au_di_free(tmp);
+	if (unlikely(err))
+		goto out;
+
+out_dgen:
+	au_update_digen(dentry);
+out:
+	if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) {
+		AuIOErr("failed refreshing %pd, %d\n", dentry, err);
+		AuDbgDentry(dentry);
+	}
+	AuTraceErr(err);
+	return err;
+}
+
+static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags,
+			   struct dentry *dentry, aufs_bindex_t bindex)
+{
+	int err, valid;
+
+	err = 0;
+	if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE))
+		goto out;
+
+	AuDbg("b%d\n", bindex);
+	/*
+	 * gave up supporting LOOKUP_CREATE/OPEN for lower fs,
+	 * due to whiteout and branch permission.
+	 */
+	flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE
+		   | LOOKUP_FOLLOW | LOOKUP_EXCL);
+	/* it may return tri-state */
+	valid = h_dentry->d_op->d_revalidate(h_dentry, flags);
+
+	if (unlikely(valid < 0))
+		err = valid;
+	else if (!valid)
+		err = -EINVAL;
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* todo: remove this */
+static int h_d_revalidate(struct dentry *dentry, struct inode *inode,
+			  unsigned int flags, int do_udba)
+{
+	int err;
+	umode_t mode, h_mode;
+	aufs_bindex_t bindex, btail, bstart, ibs, ibe;
+	unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile;
+	struct inode *h_inode, *h_cached_inode;
+	struct dentry *h_dentry;
+	struct qstr *name, *h_name;
+
+	err = 0;
+	plus = 0;
+	mode = 0;
+	ibs = -1;
+	ibe = -1;
+	unhashed = !!d_unhashed(dentry);
+	is_root = !!IS_ROOT(dentry);
+	name = &dentry->d_name;
+	tmpfile = au_di(dentry)->di_tmpfile;
+
+	/*
+	 * Theoretically, REVAL test should be unnecessary in case of
+	 * {FS,I}NOTIFY.
+	 * But {fs,i}notify doesn't fire some necessary events,
+	 *	IN_ATTRIB for atime/nlink/pageio
+	 * Let's do REVAL test too.
+	 */
+	if (do_udba && inode) {
+		mode = (inode->i_mode & S_IFMT);
+		plus = (inode->i_nlink > 0);
+		ibs = au_ibstart(inode);
+		ibe = au_ibend(inode);
+	}
+
+	bstart = au_dbstart(dentry);
+	btail = bstart;
+	if (inode && S_ISDIR(inode->i_mode))
+		btail = au_dbtaildir(dentry);
+	for (bindex = bstart; bindex <= btail; bindex++) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (!h_dentry)
+			continue;
+
+		AuDbg("b%d, %pd\n", bindex, h_dentry);
+		h_nfs = !!au_test_nfs(h_dentry->d_sb);
+		spin_lock(&h_dentry->d_lock);
+		h_name = &h_dentry->d_name;
+		if (unlikely(do_udba
+			     && !is_root
+			     && ((!h_nfs
+				  && (unhashed != !!d_unhashed(h_dentry)
+				      || (!tmpfile
+					  && !au_qstreq(name, h_name))
+					  ))
+				 || (h_nfs
+				     && !(flags & LOOKUP_OPEN)
+				     && (h_dentry->d_flags
+					 & DCACHE_NFSFS_RENAMED)))
+			    )) {
+			int h_unhashed;
+
+			h_unhashed = d_unhashed(h_dentry);
+			spin_unlock(&h_dentry->d_lock);
+			AuDbg("unhash 0x%x 0x%x, %pd %pd\n",
+			      unhashed, h_unhashed, dentry, h_dentry);
+			goto err;
+		}
+		spin_unlock(&h_dentry->d_lock);
+
+		err = au_do_h_d_reval(h_dentry, flags, dentry, bindex);
+		if (unlikely(err))
+			/* do not goto err, to keep the errno */
+			break;
+
+		/* todo: plink too? */
+		if (!do_udba)
+			continue;
+
+		/* UDBA tests */
+		if (unlikely(!!inode != d_is_positive(h_dentry)))
+			goto err;
+
+		h_inode = NULL;
+		if (d_is_positive(h_dentry))
+			h_inode = d_inode(h_dentry);
+		h_plus = plus;
+		h_mode = mode;
+		h_cached_inode = h_inode;
+		if (h_inode) {
+			h_mode = (h_inode->i_mode & S_IFMT);
+			h_plus = (h_inode->i_nlink > 0);
+		}
+		if (inode && ibs <= bindex && bindex <= ibe)
+			h_cached_inode = au_h_iptr(inode, bindex);
+
+		if (!h_nfs) {
+			if (unlikely(plus != h_plus && !tmpfile))
+				goto err;
+		} else {
+			if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED)
+				     && !is_root
+				     && !IS_ROOT(h_dentry)
+				     && unhashed != d_unhashed(h_dentry)))
+				goto err;
+		}
+		if (unlikely(mode != h_mode
+			     || h_cached_inode != h_inode))
+			goto err;
+		continue;
+
+err:
+		err = -EINVAL;
+		break;
+	}
+
+	AuTraceErr(err);
+	return err;
+}
+
+/* todo: consolidate with do_refresh() and au_reval_for_attr() */
+static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen)
+{
+	int err;
+	struct dentry *parent;
+
+	if (!au_digen_test(dentry, sigen))
+		return 0;
+
+	parent = dget_parent(dentry);
+	di_read_lock_parent(parent, AuLock_IR);
+	AuDebugOn(au_digen_test(parent, sigen));
+	au_dbg_verify_gen(parent, sigen);
+	err = au_refresh_dentry(dentry, parent);
+	di_read_unlock(parent, AuLock_IR);
+	dput(parent);
+	AuTraceErr(err);
+	return err;
+}
+
+int au_reval_dpath(struct dentry *dentry, unsigned int sigen)
+{
+	int err;
+	struct dentry *d, *parent;
+
+	if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR))
+		return simple_reval_dpath(dentry, sigen);
+
+	/* slow loop, keep it simple and stupid */
+	/* cf: au_cpup_dirs() */
+	err = 0;
+	parent = NULL;
+	while (au_digen_test(dentry, sigen)) {
+		d = dentry;
+		while (1) {
+			dput(parent);
+			parent = dget_parent(d);
+			if (!au_digen_test(parent, sigen))
+				break;
+			d = parent;
+		}
+
+		if (d != dentry)
+			di_write_lock_child2(d);
+
+		/* someone might update our dentry while we were sleeping */
+		if (au_digen_test(d, sigen)) {
+			/*
+			 * todo: consolidate with simple_reval_dpath(),
+			 * do_refresh() and au_reval_for_attr().
+			 */
+			di_read_lock_parent(parent, AuLock_IR);
+			err = au_refresh_dentry(d, parent);
+			di_read_unlock(parent, AuLock_IR);
+		}
+
+		if (d != dentry)
+			di_write_unlock(d);
+		dput(parent);
+		if (unlikely(err))
+			break;
+	}
+
+	return err;
+}
+
+/*
+ * if valid returns 1, otherwise 0.
+ */
+static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+	int valid, err;
+	unsigned int sigen;
+	unsigned char do_udba;
+	struct super_block *sb;
+	struct inode *inode;
+
+	/* todo: support rcu-walk? */
+	if (flags & LOOKUP_RCU)
+		return -ECHILD;
+
+	valid = 0;
+	if (unlikely(!au_di(dentry)))
+		goto out;
+
+	valid = 1;
+	sb = dentry->d_sb;
+	/*
+	 * todo: very ugly
+	 * i_mutex of parent dir may be held,
+	 * but we should not return 'invalid' due to busy.
+	 */
+	err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM);
+	if (unlikely(err)) {
+		valid = err;
+		AuTraceErr(err);
+		goto out;
+	}
+	inode = NULL;
+	if (d_really_is_positive(dentry))
+		inode = d_inode(dentry);
+	if (unlikely(inode && is_bad_inode(inode))) {
+		err = -EINVAL;
+		AuTraceErr(err);
+		goto out_dgrade;
+	}
+	if (unlikely(au_dbrange_test(dentry))) {
+		err = -EINVAL;
+		AuTraceErr(err);
+		goto out_dgrade;
+	}
+
+	sigen = au_sigen(sb);
+	if (au_digen_test(dentry, sigen)) {
+		AuDebugOn(IS_ROOT(dentry));
+		err = au_reval_dpath(dentry, sigen);
+		if (unlikely(err)) {
+			AuTraceErr(err);
+			goto out_dgrade;
+		}
+	}
+	di_downgrade_lock(dentry, AuLock_IR);
+
+	err = -EINVAL;
+	if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY))
+	    && inode
+	    && !(inode->i_state && I_LINKABLE)
+	    && (IS_DEADDIR(inode) || !inode->i_nlink)) {
+		AuTraceErr(err);
+		goto out_inval;
+	}
+
+	do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE);
+	if (do_udba && inode) {
+		aufs_bindex_t bstart = au_ibstart(inode);
+		struct inode *h_inode;
+
+		if (bstart >= 0) {
+			h_inode = au_h_iptr(inode, bstart);
+			if (h_inode && au_test_higen(inode, h_inode)) {
+				AuTraceErr(err);
+				goto out_inval;
+			}
+		}
+	}
+
+	err = h_d_revalidate(dentry, inode, flags, do_udba);
+	if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) {
+		err = -EIO;
+		AuDbg("both of real entry and whiteout found, %p, err %d\n",
+		      dentry, err);
+	}
+	goto out_inval;
+
+out_dgrade:
+	di_downgrade_lock(dentry, AuLock_IR);
+out_inval:
+	aufs_read_unlock(dentry, AuLock_IR);
+	AuTraceErr(err);
+	valid = !err;
+out:
+	if (!valid) {
+		AuDbg("%pd invalid, %d\n", dentry, valid);
+		d_drop(dentry);
+	}
+	return valid;
+}
+
+static void aufs_d_release(struct dentry *dentry)
+{
+	if (au_di(dentry)) {
+		au_di_fin(dentry);
+		au_hn_di_reinit(dentry);
+	}
+}
+
+const struct dentry_operations aufs_dop = {
+	.d_revalidate		= aufs_d_revalidate,
+	.d_weak_revalidate	= aufs_d_revalidate,
+	.d_release		= aufs_d_release
+};
+
+/* aufs_dop without d_revalidate */
+const struct dentry_operations aufs_dop_noreval = {
+	.d_release		= aufs_d_release
+};
--- linux-4.4.0.orig/fs/aufs/dentry.h
+++ linux-4.4.0/fs/aufs/dentry.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * lookup and dentry operations
+ */
+
+#ifndef __AUFS_DENTRY_H__
+#define __AUFS_DENTRY_H__
+
+#ifdef __KERNEL__
+
+#include <linux/dcache.h>
+#include "rwsem.h"
+
+struct au_hdentry {
+	struct dentry		*hd_dentry;
+	aufs_bindex_t		hd_id;
+};
+
+struct au_dinfo {
+	atomic_t		di_generation;
+
+	struct au_rwsem		di_rwsem;
+	aufs_bindex_t		di_bstart, di_bend, di_bwh, di_bdiropq;
+	unsigned char		di_tmpfile; /* to allow the different name */
+	struct au_hdentry	*di_hdentry;
+} ____cacheline_aligned_in_smp;
+
+/* ---------------------------------------------------------------------- */
+
+/* dentry.c */
+extern const struct dentry_operations aufs_dop, aufs_dop_noreval;
+struct au_branch;
+struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent);
+int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
+		struct dentry *h_parent, struct au_branch *br);
+
+int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type);
+int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh);
+int au_refresh_dentry(struct dentry *dentry, struct dentry *parent);
+int au_reval_dpath(struct dentry *dentry, unsigned int sigen);
+void au_refresh_dop(struct dentry *dentry, int force_reval);
+
+/* dinfo.c */
+void au_di_init_once(void *_di);
+struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc);
+void au_di_free(struct au_dinfo *dinfo);
+void au_di_swap(struct au_dinfo *a, struct au_dinfo *b);
+void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src);
+int au_di_init(struct dentry *dentry);
+void au_di_fin(struct dentry *dentry);
+int au_di_realloc(struct au_dinfo *dinfo, int nbr);
+
+void di_read_lock(struct dentry *d, int flags, unsigned int lsc);
+void di_read_unlock(struct dentry *d, int flags);
+void di_downgrade_lock(struct dentry *d, int flags);
+void di_write_lock(struct dentry *d, unsigned int lsc);
+void di_write_unlock(struct dentry *d);
+void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir);
+void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir);
+void di_write_unlock2(struct dentry *d1, struct dentry *d2);
+
+struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex);
+struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex);
+aufs_bindex_t au_dbtail(struct dentry *dentry);
+aufs_bindex_t au_dbtaildir(struct dentry *dentry);
+
+void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
+		   struct dentry *h_dentry);
+int au_digen_test(struct dentry *dentry, unsigned int sigen);
+int au_dbrange_test(struct dentry *dentry);
+void au_update_digen(struct dentry *dentry);
+void au_update_dbrange(struct dentry *dentry, int do_put_zero);
+void au_update_dbstart(struct dentry *dentry);
+void au_update_dbend(struct dentry *dentry);
+int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry);
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct au_dinfo *au_di(struct dentry *dentry)
+{
+	return dentry->d_fsdata;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* lock subclass for dinfo */
+enum {
+	AuLsc_DI_CHILD,		/* child first */
+	AuLsc_DI_CHILD2,	/* rename(2), link(2), and cpup at hnotify */
+	AuLsc_DI_CHILD3,	/* copyup dirs */
+	AuLsc_DI_PARENT,
+	AuLsc_DI_PARENT2,
+	AuLsc_DI_PARENT3,
+	AuLsc_DI_TMP		/* temp for replacing dinfo */
+};
+
+/*
+ * di_read_lock_child, di_write_lock_child,
+ * di_read_lock_child2, di_write_lock_child2,
+ * di_read_lock_child3, di_write_lock_child3,
+ * di_read_lock_parent, di_write_lock_parent,
+ * di_read_lock_parent2, di_write_lock_parent2,
+ * di_read_lock_parent3, di_write_lock_parent3,
+ */
+#define AuReadLockFunc(name, lsc) \
+static inline void di_read_lock_##name(struct dentry *d, int flags) \
+{ di_read_lock(d, flags, AuLsc_DI_##lsc); }
+
+#define AuWriteLockFunc(name, lsc) \
+static inline void di_write_lock_##name(struct dentry *d) \
+{ di_write_lock(d, AuLsc_DI_##lsc); }
+
+#define AuRWLockFuncs(name, lsc) \
+	AuReadLockFunc(name, lsc) \
+	AuWriteLockFunc(name, lsc)
+
+AuRWLockFuncs(child, CHILD);
+AuRWLockFuncs(child2, CHILD2);
+AuRWLockFuncs(child3, CHILD3);
+AuRWLockFuncs(parent, PARENT);
+AuRWLockFuncs(parent2, PARENT2);
+AuRWLockFuncs(parent3, PARENT3);
+
+#undef AuReadLockFunc
+#undef AuWriteLockFunc
+#undef AuRWLockFuncs
+
+#define DiMustNoWaiters(d)	AuRwMustNoWaiters(&au_di(d)->di_rwsem)
+#define DiMustAnyLock(d)	AuRwMustAnyLock(&au_di(d)->di_rwsem)
+#define DiMustWriteLock(d)	AuRwMustWriteLock(&au_di(d)->di_rwsem)
+
+/* ---------------------------------------------------------------------- */
+
+/* todo: memory barrier? */
+static inline unsigned int au_digen(struct dentry *d)
+{
+	return atomic_read(&au_di(d)->di_generation);
+}
+
+static inline void au_h_dentry_init(struct au_hdentry *hdentry)
+{
+	hdentry->hd_dentry = NULL;
+}
+
+static inline void au_hdput(struct au_hdentry *hd)
+{
+	if (hd)
+		dput(hd->hd_dentry);
+}
+
+static inline aufs_bindex_t au_dbstart(struct dentry *dentry)
+{
+	DiMustAnyLock(dentry);
+	return au_di(dentry)->di_bstart;
+}
+
+static inline aufs_bindex_t au_dbend(struct dentry *dentry)
+{
+	DiMustAnyLock(dentry);
+	return au_di(dentry)->di_bend;
+}
+
+static inline aufs_bindex_t au_dbwh(struct dentry *dentry)
+{
+	DiMustAnyLock(dentry);
+	return au_di(dentry)->di_bwh;
+}
+
+static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry)
+{
+	DiMustAnyLock(dentry);
+	return au_di(dentry)->di_bdiropq;
+}
+
+/* todo: hard/soft set? */
+static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex)
+{
+	DiMustWriteLock(dentry);
+	au_di(dentry)->di_bstart = bindex;
+}
+
+static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex)
+{
+	DiMustWriteLock(dentry);
+	au_di(dentry)->di_bend = bindex;
+}
+
+static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex)
+{
+	DiMustWriteLock(dentry);
+	/* dbwh can be outside of bstart - bend range */
+	au_di(dentry)->di_bwh = bindex;
+}
+
+static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex)
+{
+	DiMustWriteLock(dentry);
+	au_di(dentry)->di_bdiropq = bindex;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef CONFIG_AUFS_HNOTIFY
+static inline void au_digen_dec(struct dentry *d)
+{
+	atomic_dec(&au_di(d)->di_generation);
+}
+
+static inline void au_hn_di_reinit(struct dentry *dentry)
+{
+	dentry->d_fsdata = NULL;
+}
+#else
+AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused)
+#endif /* CONFIG_AUFS_HNOTIFY */
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DENTRY_H__ */
--- linux-4.4.0.orig/fs/aufs/dinfo.c
+++ linux-4.4.0/fs/aufs/dinfo.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * dentry private data
+ */
+
+#include "aufs.h"
+
+void au_di_init_once(void *_dinfo)
+{
+	struct au_dinfo *dinfo = _dinfo;
+	static struct lock_class_key aufs_di;
+
+	au_rw_init(&dinfo->di_rwsem);
+	au_rw_class(&dinfo->di_rwsem, &aufs_di);
+}
+
+struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc)
+{
+	struct au_dinfo *dinfo;
+	int nbr, i;
+
+	dinfo = au_cache_alloc_dinfo();
+	if (unlikely(!dinfo))
+		goto out;
+
+	nbr = au_sbend(sb) + 1;
+	if (nbr <= 0)
+		nbr = 1;
+	dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS);
+	if (dinfo->di_hdentry) {
+		au_rw_write_lock_nested(&dinfo->di_rwsem, lsc);
+		dinfo->di_bstart = -1;
+		dinfo->di_bend = -1;
+		dinfo->di_bwh = -1;
+		dinfo->di_bdiropq = -1;
+		dinfo->di_tmpfile = 0;
+		for (i = 0; i < nbr; i++)
+			dinfo->di_hdentry[i].hd_id = -1;
+		goto out;
+	}
+
+	au_cache_free_dinfo(dinfo);
+	dinfo = NULL;
+
+out:
+	return dinfo;
+}
+
+void au_di_free(struct au_dinfo *dinfo)
+{
+	struct au_hdentry *p;
+	aufs_bindex_t bend, bindex;
+
+	/* dentry may not be revalidated */
+	bindex = dinfo->di_bstart;
+	if (bindex >= 0) {
+		bend = dinfo->di_bend;
+		p = dinfo->di_hdentry + bindex;
+		while (bindex++ <= bend)
+			au_hdput(p++);
+	}
+	kfree(dinfo->di_hdentry);
+	au_cache_free_dinfo(dinfo);
+}
+
+void au_di_swap(struct au_dinfo *a, struct au_dinfo *b)
+{
+	struct au_hdentry *p;
+	aufs_bindex_t bi;
+
+	AuRwMustWriteLock(&a->di_rwsem);
+	AuRwMustWriteLock(&b->di_rwsem);
+
+#define DiSwap(v, name)				\
+	do {					\
+		v = a->di_##name;		\
+		a->di_##name = b->di_##name;	\
+		b->di_##name = v;		\
+	} while (0)
+
+	DiSwap(p, hdentry);
+	DiSwap(bi, bstart);
+	DiSwap(bi, bend);
+	DiSwap(bi, bwh);
+	DiSwap(bi, bdiropq);
+	/* smp_mb(); */
+
+#undef DiSwap
+}
+
+void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src)
+{
+	AuRwMustWriteLock(&dst->di_rwsem);
+	AuRwMustWriteLock(&src->di_rwsem);
+
+	dst->di_bstart = src->di_bstart;
+	dst->di_bend = src->di_bend;
+	dst->di_bwh = src->di_bwh;
+	dst->di_bdiropq = src->di_bdiropq;
+	/* smp_mb(); */
+}
+
+int au_di_init(struct dentry *dentry)
+{
+	int err;
+	struct super_block *sb;
+	struct au_dinfo *dinfo;
+
+	err = 0;
+	sb = dentry->d_sb;
+	dinfo = au_di_alloc(sb, AuLsc_DI_CHILD);
+	if (dinfo) {
+		atomic_set(&dinfo->di_generation, au_sigen(sb));
+		/* smp_mb(); */ /* atomic_set */
+		dentry->d_fsdata = dinfo;
+	} else
+		err = -ENOMEM;
+
+	return err;
+}
+
+void au_di_fin(struct dentry *dentry)
+{
+	struct au_dinfo *dinfo;
+
+	dinfo = au_di(dentry);
+	AuRwDestroy(&dinfo->di_rwsem);
+	au_di_free(dinfo);
+}
+
+int au_di_realloc(struct au_dinfo *dinfo, int nbr)
+{
+	int err, sz;
+	struct au_hdentry *hdp;
+
+	AuRwMustWriteLock(&dinfo->di_rwsem);
+
+	err = -ENOMEM;
+	sz = sizeof(*hdp) * (dinfo->di_bend + 1);
+	if (!sz)
+		sz = sizeof(*hdp);
+	hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS);
+	if (hdp) {
+		dinfo->di_hdentry = hdp;
+		err = 0;
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void do_ii_write_lock(struct inode *inode, unsigned int lsc)
+{
+	switch (lsc) {
+	case AuLsc_DI_CHILD:
+		ii_write_lock_child(inode);
+		break;
+	case AuLsc_DI_CHILD2:
+		ii_write_lock_child2(inode);
+		break;
+	case AuLsc_DI_CHILD3:
+		ii_write_lock_child3(inode);
+		break;
+	case AuLsc_DI_PARENT:
+		ii_write_lock_parent(inode);
+		break;
+	case AuLsc_DI_PARENT2:
+		ii_write_lock_parent2(inode);
+		break;
+	case AuLsc_DI_PARENT3:
+		ii_write_lock_parent3(inode);
+		break;
+	default:
+		BUG();
+	}
+}
+
+static void do_ii_read_lock(struct inode *inode, unsigned int lsc)
+{
+	switch (lsc) {
+	case AuLsc_DI_CHILD:
+		ii_read_lock_child(inode);
+		break;
+	case AuLsc_DI_CHILD2:
+		ii_read_lock_child2(inode);
+		break;
+	case AuLsc_DI_CHILD3:
+		ii_read_lock_child3(inode);
+		break;
+	case AuLsc_DI_PARENT:
+		ii_read_lock_parent(inode);
+		break;
+	case AuLsc_DI_PARENT2:
+		ii_read_lock_parent2(inode);
+		break;
+	case AuLsc_DI_PARENT3:
+		ii_read_lock_parent3(inode);
+		break;
+	default:
+		BUG();
+	}
+}
+
+void di_read_lock(struct dentry *d, int flags, unsigned int lsc)
+{
+	struct inode *inode;
+
+	au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc);
+	if (d_really_is_positive(d)) {
+		inode = d_inode(d);
+		if (au_ftest_lock(flags, IW))
+			do_ii_write_lock(inode, lsc);
+		else if (au_ftest_lock(flags, IR))
+			do_ii_read_lock(inode, lsc);
+	}
+}
+
+void di_read_unlock(struct dentry *d, int flags)
+{
+	struct inode *inode;
+
+	if (d_really_is_positive(d)) {
+		inode = d_inode(d);
+		if (au_ftest_lock(flags, IW)) {
+			au_dbg_verify_dinode(d);
+			ii_write_unlock(inode);
+		} else if (au_ftest_lock(flags, IR)) {
+			au_dbg_verify_dinode(d);
+			ii_read_unlock(inode);
+		}
+	}
+	au_rw_read_unlock(&au_di(d)->di_rwsem);
+}
+
+void di_downgrade_lock(struct dentry *d, int flags)
+{
+	if (d_really_is_positive(d) && au_ftest_lock(flags, IR))
+		ii_downgrade_lock(d_inode(d));
+	au_rw_dgrade_lock(&au_di(d)->di_rwsem);
+}
+
+void di_write_lock(struct dentry *d, unsigned int lsc)
+{
+	au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc);
+	if (d_really_is_positive(d))
+		do_ii_write_lock(d_inode(d), lsc);
+}
+
+void di_write_unlock(struct dentry *d)
+{
+	au_dbg_verify_dinode(d);
+	if (d_really_is_positive(d))
+		ii_write_unlock(d_inode(d));
+	au_rw_write_unlock(&au_di(d)->di_rwsem);
+}
+
+void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir)
+{
+	AuDebugOn(d1 == d2
+		  || d_inode(d1) == d_inode(d2)
+		  || d1->d_sb != d2->d_sb);
+
+	if (isdir && au_test_subdir(d1, d2)) {
+		di_write_lock_child(d1);
+		di_write_lock_child2(d2);
+	} else {
+		/* there should be no races */
+		di_write_lock_child(d2);
+		di_write_lock_child2(d1);
+	}
+}
+
+void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir)
+{
+	AuDebugOn(d1 == d2
+		  || d_inode(d1) == d_inode(d2)
+		  || d1->d_sb != d2->d_sb);
+
+	if (isdir && au_test_subdir(d1, d2)) {
+		di_write_lock_parent(d1);
+		di_write_lock_parent2(d2);
+	} else {
+		/* there should be no races */
+		di_write_lock_parent(d2);
+		di_write_lock_parent2(d1);
+	}
+}
+
+void di_write_unlock2(struct dentry *d1, struct dentry *d2)
+{
+	di_write_unlock(d1);
+	if (d_inode(d1) == d_inode(d2))
+		au_rw_write_unlock(&au_di(d2)->di_rwsem);
+	else
+		di_write_unlock(d2);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex)
+{
+	struct dentry *d;
+
+	DiMustAnyLock(dentry);
+
+	if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
+		return NULL;
+	AuDebugOn(bindex < 0);
+	d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry;
+	AuDebugOn(d && au_dcount(d) <= 0);
+	return d;
+}
+
+/*
+ * extended version of au_h_dptr().
+ * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or
+ * error.
+ */
+struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex)
+{
+	struct dentry *h_dentry;
+	struct inode *inode, *h_inode;
+
+	AuDebugOn(d_really_is_negative(dentry));
+
+	h_dentry = NULL;
+	if (au_dbstart(dentry) <= bindex
+	    && bindex <= au_dbend(dentry))
+		h_dentry = au_h_dptr(dentry, bindex);
+	if (h_dentry && !au_d_linkable(h_dentry)) {
+		dget(h_dentry);
+		goto out; /* success */
+	}
+
+	inode = d_inode(dentry);
+	AuDebugOn(bindex < au_ibstart(inode));
+	AuDebugOn(au_ibend(inode) < bindex);
+	h_inode = au_h_iptr(inode, bindex);
+	h_dentry = d_find_alias(h_inode);
+	if (h_dentry) {
+		if (!IS_ERR(h_dentry)) {
+			if (!au_d_linkable(h_dentry))
+				goto out; /* success */
+			dput(h_dentry);
+		} else
+			goto out;
+	}
+
+	if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) {
+		h_dentry = au_plink_lkup(inode, bindex);
+		AuDebugOn(!h_dentry);
+		if (!IS_ERR(h_dentry)) {
+			if (!au_d_hashed_positive(h_dentry))
+				goto out; /* success */
+			dput(h_dentry);
+			h_dentry = NULL;
+		}
+	}
+
+out:
+	AuDbgDentry(h_dentry);
+	return h_dentry;
+}
+
+aufs_bindex_t au_dbtail(struct dentry *dentry)
+{
+	aufs_bindex_t bend, bwh;
+
+	bend = au_dbend(dentry);
+	if (0 <= bend) {
+		bwh = au_dbwh(dentry);
+		if (!bwh)
+			return bwh;
+		if (0 < bwh && bwh < bend)
+			return bwh - 1;
+	}
+	return bend;
+}
+
+aufs_bindex_t au_dbtaildir(struct dentry *dentry)
+{
+	aufs_bindex_t bend, bopq;
+
+	bend = au_dbtail(dentry);
+	if (0 <= bend) {
+		bopq = au_dbdiropq(dentry);
+		if (0 <= bopq && bopq < bend)
+			bend = bopq;
+	}
+	return bend;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
+		   struct dentry *h_dentry)
+{
+	struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
+	struct au_branch *br;
+
+	DiMustWriteLock(dentry);
+
+	au_hdput(hd);
+	hd->hd_dentry = h_dentry;
+	if (h_dentry) {
+		br = au_sbr(dentry->d_sb, bindex);
+		hd->hd_id = br->br_id;
+	}
+}
+
+int au_dbrange_test(struct dentry *dentry)
+{
+	int err;
+	aufs_bindex_t bstart, bend;
+
+	err = 0;
+	bstart = au_dbstart(dentry);
+	bend = au_dbend(dentry);
+	if (bstart >= 0)
+		AuDebugOn(bend < 0 && bstart > bend);
+	else {
+		err = -EIO;
+		AuDebugOn(bend >= 0);
+	}
+
+	return err;
+}
+
+int au_digen_test(struct dentry *dentry, unsigned int sigen)
+{
+	int err;
+
+	err = 0;
+	if (unlikely(au_digen(dentry) != sigen
+		     || au_iigen_test(d_inode(dentry), sigen)))
+		err = -EIO;
+
+	return err;
+}
+
+void au_update_digen(struct dentry *dentry)
+{
+	atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb));
+	/* smp_mb(); */ /* atomic_set */
+}
+
+void au_update_dbrange(struct dentry *dentry, int do_put_zero)
+{
+	struct au_dinfo *dinfo;
+	struct dentry *h_d;
+	struct au_hdentry *hdp;
+
+	DiMustWriteLock(dentry);
+
+	dinfo = au_di(dentry);
+	if (!dinfo || dinfo->di_bstart < 0)
+		return;
+
+	hdp = dinfo->di_hdentry;
+	if (do_put_zero) {
+		aufs_bindex_t bindex, bend;
+
+		bend = dinfo->di_bend;
+		for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) {
+			h_d = hdp[0 + bindex].hd_dentry;
+			if (h_d && d_is_negative(h_d))
+				au_set_h_dptr(dentry, bindex, NULL);
+		}
+	}
+
+	dinfo->di_bstart = -1;
+	while (++dinfo->di_bstart <= dinfo->di_bend)
+		if (hdp[0 + dinfo->di_bstart].hd_dentry)
+			break;
+	if (dinfo->di_bstart > dinfo->di_bend) {
+		dinfo->di_bstart = -1;
+		dinfo->di_bend = -1;
+		return;
+	}
+
+	dinfo->di_bend++;
+	while (0 <= --dinfo->di_bend)
+		if (hdp[0 + dinfo->di_bend].hd_dentry)
+			break;
+	AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0);
+}
+
+void au_update_dbstart(struct dentry *dentry)
+{
+	aufs_bindex_t bindex, bend;
+	struct dentry *h_dentry;
+
+	bend = au_dbend(dentry);
+	for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (!h_dentry)
+			continue;
+		if (d_is_positive(h_dentry)) {
+			au_set_dbstart(dentry, bindex);
+			return;
+		}
+		au_set_h_dptr(dentry, bindex, NULL);
+	}
+}
+
+void au_update_dbend(struct dentry *dentry)
+{
+	aufs_bindex_t bindex, bstart;
+	struct dentry *h_dentry;
+
+	bstart = au_dbstart(dentry);
+	for (bindex = au_dbend(dentry); bindex >= bstart; bindex--) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (!h_dentry)
+			continue;
+		if (d_is_positive(h_dentry)) {
+			au_set_dbend(dentry, bindex);
+			return;
+		}
+		au_set_h_dptr(dentry, bindex, NULL);
+	}
+}
+
+int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry)
+{
+	aufs_bindex_t bindex, bend;
+
+	bend = au_dbend(dentry);
+	for (bindex = au_dbstart(dentry); bindex <= bend; bindex++)
+		if (au_h_dptr(dentry, bindex) == h_dentry)
+			return bindex;
+	return -1;
+}
--- linux-4.4.0.orig/fs/aufs/dir.c
+++ linux-4.4.0/fs/aufs/dir.c
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * directory operations
+ */
+
+#include <linux/fs_stack.h>
+#include "aufs.h"
+
+void au_add_nlink(struct inode *dir, struct inode *h_dir)
+{
+	unsigned int nlink;
+
+	AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
+
+	nlink = dir->i_nlink;
+	nlink += h_dir->i_nlink - 2;
+	if (h_dir->i_nlink < 2)
+		nlink += 2;
+	smp_mb(); /* for i_nlink */
+	/* 0 can happen in revaliding */
+	set_nlink(dir, nlink);
+}
+
+void au_sub_nlink(struct inode *dir, struct inode *h_dir)
+{
+	unsigned int nlink;
+
+	AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
+
+	nlink = dir->i_nlink;
+	nlink -= h_dir->i_nlink - 2;
+	if (h_dir->i_nlink < 2)
+		nlink -= 2;
+	smp_mb(); /* for i_nlink */
+	/* nlink == 0 means the branch-fs is broken */
+	set_nlink(dir, nlink);
+}
+
+loff_t au_dir_size(struct file *file, struct dentry *dentry)
+{
+	loff_t sz;
+	aufs_bindex_t bindex, bend;
+	struct file *h_file;
+	struct dentry *h_dentry;
+
+	sz = 0;
+	if (file) {
+		AuDebugOn(!d_is_dir(file->f_path.dentry));
+
+		bend = au_fbend_dir(file);
+		for (bindex = au_fbstart(file);
+		     bindex <= bend && sz < KMALLOC_MAX_SIZE;
+		     bindex++) {
+			h_file = au_hf_dir(file, bindex);
+			if (h_file && file_inode(h_file))
+				sz += vfsub_f_size_read(h_file);
+		}
+	} else {
+		AuDebugOn(!dentry);
+		AuDebugOn(!d_is_dir(dentry));
+
+		bend = au_dbtaildir(dentry);
+		for (bindex = au_dbstart(dentry);
+		     bindex <= bend && sz < KMALLOC_MAX_SIZE;
+		     bindex++) {
+			h_dentry = au_h_dptr(dentry, bindex);
+			if (h_dentry && d_is_positive(h_dentry))
+				sz += i_size_read(d_inode(h_dentry));
+		}
+	}
+	if (sz < KMALLOC_MAX_SIZE)
+		sz = roundup_pow_of_two(sz);
+	if (sz > KMALLOC_MAX_SIZE)
+		sz = KMALLOC_MAX_SIZE;
+	else if (sz < NAME_MAX) {
+		BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX);
+		sz = AUFS_RDBLK_DEF;
+	}
+	return sz;
+}
+
+struct au_dir_ts_arg {
+	struct dentry *dentry;
+	aufs_bindex_t brid;
+};
+
+static void au_do_dir_ts(void *arg)
+{
+	struct au_dir_ts_arg *a = arg;
+	struct au_dtime dt;
+	struct path h_path;
+	struct inode *dir, *h_dir;
+	struct super_block *sb;
+	struct au_branch *br;
+	struct au_hinode *hdir;
+	int err;
+	aufs_bindex_t bstart, bindex;
+
+	sb = a->dentry->d_sb;
+	if (d_really_is_negative(a->dentry))
+		goto out;
+	/* no dir->i_mutex lock */
+	aufs_read_lock(a->dentry, AuLock_DW); /* noflush */
+
+	dir = d_inode(a->dentry);
+	bstart = au_ibstart(dir);
+	bindex = au_br_index(sb, a->brid);
+	if (bindex < bstart)
+		goto out_unlock;
+
+	br = au_sbr(sb, bindex);
+	h_path.dentry = au_h_dptr(a->dentry, bindex);
+	if (!h_path.dentry)
+		goto out_unlock;
+	h_path.mnt = au_br_mnt(br);
+	au_dtime_store(&dt, a->dentry, &h_path);
+
+	br = au_sbr(sb, bstart);
+	if (!au_br_writable(br->br_perm))
+		goto out_unlock;
+	h_path.dentry = au_h_dptr(a->dentry, bstart);
+	h_path.mnt = au_br_mnt(br);
+	err = vfsub_mnt_want_write(h_path.mnt);
+	if (err)
+		goto out_unlock;
+	hdir = au_hi(dir, bstart);
+	au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+	h_dir = au_h_iptr(dir, bstart);
+	if (h_dir->i_nlink
+	    && timespec_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) {
+		dt.dt_h_path = h_path;
+		au_dtime_revert(&dt);
+	}
+	au_hn_imtx_unlock(hdir);
+	vfsub_mnt_drop_write(h_path.mnt);
+	au_cpup_attr_timesizes(dir);
+
+out_unlock:
+	aufs_read_unlock(a->dentry, AuLock_DW);
+out:
+	dput(a->dentry);
+	au_nwt_done(&au_sbi(sb)->si_nowait);
+	kfree(arg);
+}
+
+void au_dir_ts(struct inode *dir, aufs_bindex_t bindex)
+{
+	int perm, wkq_err;
+	aufs_bindex_t bstart;
+	struct au_dir_ts_arg *arg;
+	struct dentry *dentry;
+	struct super_block *sb;
+
+	IMustLock(dir);
+
+	dentry = d_find_any_alias(dir);
+	AuDebugOn(!dentry);
+	sb = dentry->d_sb;
+	bstart = au_ibstart(dir);
+	if (bstart == bindex) {
+		au_cpup_attr_timesizes(dir);
+		goto out;
+	}
+
+	perm = au_sbr_perm(sb, bstart);
+	if (!au_br_writable(perm))
+		goto out;
+
+	arg = kmalloc(sizeof(*arg), GFP_NOFS);
+	if (!arg)
+		goto out;
+
+	arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */
+	arg->brid = au_sbr_id(sb, bindex);
+	wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0);
+	if (unlikely(wkq_err)) {
+		pr_err("wkq %d\n", wkq_err);
+		dput(dentry);
+		kfree(arg);
+	}
+
+out:
+	dput(dentry);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int reopen_dir(struct file *file)
+{
+	int err;
+	unsigned int flags;
+	aufs_bindex_t bindex, btail, bstart;
+	struct dentry *dentry, *h_dentry;
+	struct file *h_file;
+
+	/* open all lower dirs */
+	dentry = file->f_path.dentry;
+	bstart = au_dbstart(dentry);
+	for (bindex = au_fbstart(file); bindex < bstart; bindex++)
+		au_set_h_fptr(file, bindex, NULL);
+	au_set_fbstart(file, bstart);
+
+	btail = au_dbtaildir(dentry);
+	for (bindex = au_fbend_dir(file); btail < bindex; bindex--)
+		au_set_h_fptr(file, bindex, NULL);
+	au_set_fbend_dir(file, btail);
+
+	flags = vfsub_file_flags(file);
+	for (bindex = bstart; bindex <= btail; bindex++) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (!h_dentry)
+			continue;
+		h_file = au_hf_dir(file, bindex);
+		if (h_file)
+			continue;
+
+		h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0);
+		err = PTR_ERR(h_file);
+		if (IS_ERR(h_file))
+			goto out; /* close all? */
+		au_set_h_fptr(file, bindex, h_file);
+	}
+	au_update_figen(file);
+	/* todo: necessary? */
+	/* file->f_ra = h_file->f_ra; */
+	err = 0;
+
+out:
+	return err;
+}
+
+static int do_open_dir(struct file *file, int flags, struct file *h_file)
+{
+	int err;
+	aufs_bindex_t bindex, btail;
+	struct dentry *dentry, *h_dentry;
+	struct vfsmount *mnt;
+
+	FiMustWriteLock(file);
+	AuDebugOn(h_file);
+
+	err = 0;
+	mnt = file->f_path.mnt;
+	dentry = file->f_path.dentry;
+	file->f_version = d_inode(dentry)->i_version;
+	bindex = au_dbstart(dentry);
+	au_set_fbstart(file, bindex);
+	btail = au_dbtaildir(dentry);
+	au_set_fbend_dir(file, btail);
+	for (; !err && bindex <= btail; bindex++) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (!h_dentry)
+			continue;
+
+		err = vfsub_test_mntns(mnt, h_dentry->d_sb);
+		if (unlikely(err))
+			break;
+		h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0);
+		if (IS_ERR(h_file)) {
+			err = PTR_ERR(h_file);
+			break;
+		}
+		au_set_h_fptr(file, bindex, h_file);
+	}
+	au_update_figen(file);
+	/* todo: necessary? */
+	/* file->f_ra = h_file->f_ra; */
+	if (!err)
+		return 0; /* success */
+
+	/* close all */
+	for (bindex = au_fbstart(file); bindex <= btail; bindex++)
+		au_set_h_fptr(file, bindex, NULL);
+	au_set_fbstart(file, -1);
+	au_set_fbend_dir(file, -1);
+
+	return err;
+}
+
+static int aufs_open_dir(struct inode *inode __maybe_unused,
+			 struct file *file)
+{
+	int err;
+	struct super_block *sb;
+	struct au_fidir *fidir;
+
+	err = -ENOMEM;
+	sb = file->f_path.dentry->d_sb;
+	si_read_lock(sb, AuLock_FLUSH);
+	fidir = au_fidir_alloc(sb);
+	if (fidir) {
+		struct au_do_open_args args = {
+			.open	= do_open_dir,
+			.fidir	= fidir
+		};
+		err = au_do_open(file, &args);
+		if (unlikely(err))
+			kfree(fidir);
+	}
+	si_read_unlock(sb);
+	return err;
+}
+
+static int aufs_release_dir(struct inode *inode __maybe_unused,
+			    struct file *file)
+{
+	struct au_vdir *vdir_cache;
+	struct au_finfo *finfo;
+	struct au_fidir *fidir;
+	aufs_bindex_t bindex, bend;
+
+	finfo = au_fi(file);
+	fidir = finfo->fi_hdir;
+	if (fidir) {
+		au_sphl_del(&finfo->fi_hlist,
+			    &au_sbi(file->f_path.dentry->d_sb)->si_files);
+		vdir_cache = fidir->fd_vdir_cache; /* lock-free */
+		if (vdir_cache)
+			au_vdir_free(vdir_cache);
+
+		bindex = finfo->fi_btop;
+		if (bindex >= 0) {
+			/*
+			 * calls fput() instead of filp_close(),
+			 * since no dnotify or lock for the lower file.
+			 */
+			bend = fidir->fd_bbot;
+			for (; bindex <= bend; bindex++)
+				au_set_h_fptr(file, bindex, NULL);
+		}
+		kfree(fidir);
+		finfo->fi_hdir = NULL;
+	}
+	au_finfo_fin(file);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_do_flush_dir(struct file *file, fl_owner_t id)
+{
+	int err;
+	aufs_bindex_t bindex, bend;
+	struct file *h_file;
+
+	err = 0;
+	bend = au_fbend_dir(file);
+	for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) {
+		h_file = au_hf_dir(file, bindex);
+		if (h_file)
+			err = vfsub_flush(h_file, id);
+	}
+	return err;
+}
+
+static int aufs_flush_dir(struct file *file, fl_owner_t id)
+{
+	return au_do_flush(file, id, au_do_flush_dir);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync)
+{
+	int err;
+	aufs_bindex_t bend, bindex;
+	struct inode *inode;
+	struct super_block *sb;
+
+	err = 0;
+	sb = dentry->d_sb;
+	inode = d_inode(dentry);
+	IMustLock(inode);
+	bend = au_dbend(dentry);
+	for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) {
+		struct path h_path;
+
+		if (au_test_ro(sb, bindex, inode))
+			continue;
+		h_path.dentry = au_h_dptr(dentry, bindex);
+		if (!h_path.dentry)
+			continue;
+
+		h_path.mnt = au_sbr_mnt(sb, bindex);
+		err = vfsub_fsync(NULL, &h_path, datasync);
+	}
+
+	return err;
+}
+
+static int au_do_fsync_dir(struct file *file, int datasync)
+{
+	int err;
+	aufs_bindex_t bend, bindex;
+	struct file *h_file;
+	struct super_block *sb;
+	struct inode *inode;
+
+	err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
+	if (unlikely(err))
+		goto out;
+
+	inode = file_inode(file);
+	sb = inode->i_sb;
+	bend = au_fbend_dir(file);
+	for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) {
+		h_file = au_hf_dir(file, bindex);
+		if (!h_file || au_test_ro(sb, bindex, inode))
+			continue;
+
+		err = vfsub_fsync(h_file, &h_file->f_path, datasync);
+	}
+
+out:
+	return err;
+}
+
+/*
+ * @file may be NULL
+ */
+static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end,
+			  int datasync)
+{
+	int err;
+	struct dentry *dentry;
+	struct inode *inode;
+	struct super_block *sb;
+	struct mutex *mtx;
+
+	err = 0;
+	dentry = file->f_path.dentry;
+	inode = d_inode(dentry);
+	mtx = &inode->i_mutex;
+	mutex_lock(mtx);
+	sb = dentry->d_sb;
+	si_noflush_read_lock(sb);
+	if (file)
+		err = au_do_fsync_dir(file, datasync);
+	else {
+		di_write_lock_child(dentry);
+		err = au_do_fsync_dir_no_file(dentry, datasync);
+	}
+	au_cpup_attr_timesizes(inode);
+	di_write_unlock(dentry);
+	if (file)
+		fi_write_unlock(file);
+
+	si_read_unlock(sb);
+	mutex_unlock(mtx);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int aufs_iterate(struct file *file, struct dir_context *ctx)
+{
+	int err;
+	struct dentry *dentry;
+	struct inode *inode, *h_inode;
+	struct super_block *sb;
+
+	AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos);
+
+	dentry = file->f_path.dentry;
+	inode = d_inode(dentry);
+	IMustLock(inode);
+
+	sb = dentry->d_sb;
+	si_read_lock(sb, AuLock_FLUSH);
+	err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
+	if (unlikely(err))
+		goto out;
+	err = au_alive_dir(dentry);
+	if (!err)
+		err = au_vdir_init(file);
+	di_downgrade_lock(dentry, AuLock_IR);
+	if (unlikely(err))
+		goto out_unlock;
+
+	h_inode = au_h_iptr(inode, au_ibstart(inode));
+	if (!au_test_nfsd()) {
+		err = au_vdir_fill_de(file, ctx);
+		fsstack_copy_attr_atime(inode, h_inode);
+	} else {
+		/*
+		 * nfsd filldir may call lookup_one_len(), vfs_getattr(),
+		 * encode_fh() and others.
+		 */
+		atomic_inc(&h_inode->i_count);
+		di_read_unlock(dentry, AuLock_IR);
+		si_read_unlock(sb);
+		err = au_vdir_fill_de(file, ctx);
+		fsstack_copy_attr_atime(inode, h_inode);
+		fi_write_unlock(file);
+		iput(h_inode);
+
+		AuTraceErr(err);
+		return err;
+	}
+
+out_unlock:
+	di_read_unlock(dentry, AuLock_IR);
+	fi_write_unlock(file);
+out:
+	si_read_unlock(sb);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#define AuTestEmpty_WHONLY	1
+#define AuTestEmpty_CALLED	(1 << 1)
+#define AuTestEmpty_SHWH	(1 << 2)
+#define au_ftest_testempty(flags, name)	((flags) & AuTestEmpty_##name)
+#define au_fset_testempty(flags, name) \
+	do { (flags) |= AuTestEmpty_##name; } while (0)
+#define au_fclr_testempty(flags, name) \
+	do { (flags) &= ~AuTestEmpty_##name; } while (0)
+
+#ifndef CONFIG_AUFS_SHWH
+#undef AuTestEmpty_SHWH
+#define AuTestEmpty_SHWH	0
+#endif
+
+struct test_empty_arg {
+	struct dir_context ctx;
+	struct au_nhash *whlist;
+	unsigned int flags;
+	int err;
+	aufs_bindex_t bindex;
+};
+
+static int test_empty_cb(struct dir_context *ctx, const char *__name,
+			 int namelen, loff_t offset __maybe_unused, u64 ino,
+			 unsigned int d_type)
+{
+	struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg,
+						  ctx);
+	char *name = (void *)__name;
+
+	arg->err = 0;
+	au_fset_testempty(arg->flags, CALLED);
+	/* smp_mb(); */
+	if (name[0] == '.'
+	    && (namelen == 1 || (name[1] == '.' && namelen == 2)))
+		goto out; /* success */
+
+	if (namelen <= AUFS_WH_PFX_LEN
+	    || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
+		if (au_ftest_testempty(arg->flags, WHONLY)
+		    && !au_nhash_test_known_wh(arg->whlist, name, namelen))
+			arg->err = -ENOTEMPTY;
+		goto out;
+	}
+
+	name += AUFS_WH_PFX_LEN;
+	namelen -= AUFS_WH_PFX_LEN;
+	if (!au_nhash_test_known_wh(arg->whlist, name, namelen))
+		arg->err = au_nhash_append_wh
+			(arg->whlist, name, namelen, ino, d_type, arg->bindex,
+			 au_ftest_testempty(arg->flags, SHWH));
+
+out:
+	/* smp_mb(); */
+	AuTraceErr(arg->err);
+	return arg->err;
+}
+
+static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
+{
+	int err;
+	struct file *h_file;
+
+	h_file = au_h_open(dentry, arg->bindex,
+			   O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE,
+			   /*file*/NULL, /*force_wr*/0);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	err = 0;
+	if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
+	    && !file_inode(h_file)->i_nlink)
+		goto out_put;
+
+	do {
+		arg->err = 0;
+		au_fclr_testempty(arg->flags, CALLED);
+		/* smp_mb(); */
+		err = vfsub_iterate_dir(h_file, &arg->ctx);
+		if (err >= 0)
+			err = arg->err;
+	} while (!err && au_ftest_testempty(arg->flags, CALLED));
+
+out_put:
+	fput(h_file);
+	au_sbr_put(dentry->d_sb, arg->bindex);
+out:
+	return err;
+}
+
+struct do_test_empty_args {
+	int *errp;
+	struct dentry *dentry;
+	struct test_empty_arg *arg;
+};
+
+static void call_do_test_empty(void *args)
+{
+	struct do_test_empty_args *a = args;
+	*a->errp = do_test_empty(a->dentry, a->arg);
+}
+
+static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
+{
+	int err, wkq_err;
+	struct dentry *h_dentry;
+	struct inode *h_inode;
+
+	h_dentry = au_h_dptr(dentry, arg->bindex);
+	h_inode = d_inode(h_dentry);
+	/* todo: i_mode changes anytime? */
+	mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
+	err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ);
+	mutex_unlock(&h_inode->i_mutex);
+	if (!err)
+		err = do_test_empty(dentry, arg);
+	else {
+		struct do_test_empty_args args = {
+			.errp	= &err,
+			.dentry	= dentry,
+			.arg	= arg
+		};
+		unsigned int flags = arg->flags;
+
+		wkq_err = au_wkq_wait(call_do_test_empty, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+		arg->flags = flags;
+	}
+
+	return err;
+}
+
+int au_test_empty_lower(struct dentry *dentry)
+{
+	int err;
+	unsigned int rdhash;
+	aufs_bindex_t bindex, bstart, btail;
+	struct au_nhash whlist;
+	struct test_empty_arg arg = {
+		.ctx = {
+			.actor = test_empty_cb
+		}
+	};
+	int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg);
+
+	SiMustAnyLock(dentry->d_sb);
+
+	rdhash = au_sbi(dentry->d_sb)->si_rdhash;
+	if (!rdhash)
+		rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry));
+	err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
+	if (unlikely(err))
+		goto out;
+
+	arg.flags = 0;
+	arg.whlist = &whlist;
+	bstart = au_dbstart(dentry);
+	if (au_opt_test(au_mntflags(dentry->d_sb), SHWH))
+		au_fset_testempty(arg.flags, SHWH);
+	test_empty = do_test_empty;
+	if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1))
+		test_empty = sio_test_empty;
+	arg.bindex = bstart;
+	err = test_empty(dentry, &arg);
+	if (unlikely(err))
+		goto out_whlist;
+
+	au_fset_testempty(arg.flags, WHONLY);
+	btail = au_dbtaildir(dentry);
+	for (bindex = bstart + 1; !err && bindex <= btail; bindex++) {
+		struct dentry *h_dentry;
+
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (h_dentry && d_is_positive(h_dentry)) {
+			arg.bindex = bindex;
+			err = test_empty(dentry, &arg);
+		}
+	}
+
+out_whlist:
+	au_nhash_wh_free(&whlist);
+out:
+	return err;
+}
+
+int au_test_empty(struct dentry *dentry, struct au_nhash *whlist)
+{
+	int err;
+	struct test_empty_arg arg = {
+		.ctx = {
+			.actor = test_empty_cb
+		}
+	};
+	aufs_bindex_t bindex, btail;
+
+	err = 0;
+	arg.whlist = whlist;
+	arg.flags = AuTestEmpty_WHONLY;
+	if (au_opt_test(au_mntflags(dentry->d_sb), SHWH))
+		au_fset_testempty(arg.flags, SHWH);
+	btail = au_dbtaildir(dentry);
+	for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) {
+		struct dentry *h_dentry;
+
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (h_dentry && d_is_positive(h_dentry)) {
+			arg.bindex = bindex;
+			err = sio_test_empty(dentry, &arg);
+		}
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+const struct file_operations aufs_dir_fop = {
+	.owner		= THIS_MODULE,
+	.llseek		= default_llseek,
+	.read		= generic_read_dir,
+	.iterate	= aufs_iterate,
+	.unlocked_ioctl	= aufs_ioctl_dir,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= aufs_compat_ioctl_dir,
+#endif
+	.open		= aufs_open_dir,
+	.release	= aufs_release_dir,
+	.flush		= aufs_flush_dir,
+	.fsync		= aufs_fsync_dir
+};
--- linux-4.4.0.orig/fs/aufs/dir.h
+++ linux-4.4.0/fs/aufs/dir.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * directory operations
+ */
+
+#ifndef __AUFS_DIR_H__
+#define __AUFS_DIR_H__
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+
+/* ---------------------------------------------------------------------- */
+
+/* need to be faster and smaller */
+
+struct au_nhash {
+	unsigned int		nh_num;
+	struct hlist_head	*nh_head;
+};
+
+struct au_vdir_destr {
+	unsigned char	len;
+	unsigned char	name[0];
+} __packed;
+
+struct au_vdir_dehstr {
+	struct hlist_node	hash;
+	struct au_vdir_destr	*str;
+} ____cacheline_aligned_in_smp;
+
+struct au_vdir_de {
+	ino_t			de_ino;
+	unsigned char		de_type;
+	/* caution: packed */
+	struct au_vdir_destr	de_str;
+} __packed;
+
+struct au_vdir_wh {
+	struct hlist_node	wh_hash;
+#ifdef CONFIG_AUFS_SHWH
+	ino_t			wh_ino;
+	aufs_bindex_t		wh_bindex;
+	unsigned char		wh_type;
+#else
+	aufs_bindex_t		wh_bindex;
+#endif
+	/* caution: packed */
+	struct au_vdir_destr	wh_str;
+} __packed;
+
+union au_vdir_deblk_p {
+	unsigned char		*deblk;
+	struct au_vdir_de	*de;
+};
+
+struct au_vdir {
+	unsigned char	**vd_deblk;
+	unsigned long	vd_nblk;
+	struct {
+		unsigned long		ul;
+		union au_vdir_deblk_p	p;
+	} vd_last;
+
+	unsigned long	vd_version;
+	unsigned int	vd_deblk_sz;
+	unsigned long	vd_jiffy;
+} ____cacheline_aligned_in_smp;
+
+/* ---------------------------------------------------------------------- */
+
+/* dir.c */
+extern const struct file_operations aufs_dir_fop;
+void au_add_nlink(struct inode *dir, struct inode *h_dir);
+void au_sub_nlink(struct inode *dir, struct inode *h_dir);
+loff_t au_dir_size(struct file *file, struct dentry *dentry);
+void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc);
+int au_test_empty_lower(struct dentry *dentry);
+int au_test_empty(struct dentry *dentry, struct au_nhash *whlist);
+
+/* vdir.c */
+unsigned int au_rdhash_est(loff_t sz);
+int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp);
+void au_nhash_wh_free(struct au_nhash *whlist);
+int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
+			    int limit);
+int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen);
+int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
+		       unsigned int d_type, aufs_bindex_t bindex,
+		       unsigned char shwh);
+void au_vdir_free(struct au_vdir *vdir);
+int au_vdir_init(struct file *file);
+int au_vdir_fill_de(struct file *file, struct dir_context *ctx);
+
+/* ioctl.c */
+long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg);
+
+#ifdef CONFIG_AUFS_RDU
+/* rdu.c */
+long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+long au_rdu_compat_ioctl(struct file *file, unsigned int cmd,
+			 unsigned long arg);
+#endif
+#else
+AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file,
+       unsigned int cmd, unsigned long arg)
+#ifdef CONFIG_COMPAT
+AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file,
+       unsigned int cmd, unsigned long arg)
+#endif
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DIR_H__ */
--- linux-4.4.0.orig/fs/aufs/dynop.c
+++ linux-4.4.0/fs/aufs/dynop.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2010-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * dynamically customizable operations for regular files
+ */
+
+#include "aufs.h"
+
+#define DyPrSym(key)	AuDbgSym(key->dk_op.dy_hop)
+
+/*
+ * How large will these lists be?
+ * Usually just a few elements, 20-30 at most for each, I guess.
+ */
+static struct au_splhead dynop[AuDyLast];
+
+static struct au_dykey *dy_gfind_get(struct au_splhead *spl, const void *h_op)
+{
+	struct au_dykey *key, *tmp;
+	struct list_head *head;
+
+	key = NULL;
+	head = &spl->head;
+	rcu_read_lock();
+	list_for_each_entry_rcu(tmp, head, dk_list)
+		if (tmp->dk_op.dy_hop == h_op) {
+			key = tmp;
+			kref_get(&key->dk_kref);
+			break;
+		}
+	rcu_read_unlock();
+
+	return key;
+}
+
+static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key)
+{
+	struct au_dykey **k, *found;
+	const void *h_op = key->dk_op.dy_hop;
+	int i;
+
+	found = NULL;
+	k = br->br_dykey;
+	for (i = 0; i < AuBrDynOp; i++)
+		if (k[i]) {
+			if (k[i]->dk_op.dy_hop == h_op) {
+				found = k[i];
+				break;
+			}
+		} else
+			break;
+	if (!found) {
+		spin_lock(&br->br_dykey_lock);
+		for (; i < AuBrDynOp; i++)
+			if (k[i]) {
+				if (k[i]->dk_op.dy_hop == h_op) {
+					found = k[i];
+					break;
+				}
+			} else {
+				k[i] = key;
+				break;
+			}
+		spin_unlock(&br->br_dykey_lock);
+		BUG_ON(i == AuBrDynOp); /* expand the array */
+	}
+
+	return found;
+}
+
+/* kref_get() if @key is already added */
+static struct au_dykey *dy_gadd(struct au_splhead *spl, struct au_dykey *key)
+{
+	struct au_dykey *tmp, *found;
+	struct list_head *head;
+	const void *h_op = key->dk_op.dy_hop;
+
+	found = NULL;
+	head = &spl->head;
+	spin_lock(&spl->spin);
+	list_for_each_entry(tmp, head, dk_list)
+		if (tmp->dk_op.dy_hop == h_op) {
+			kref_get(&tmp->dk_kref);
+			found = tmp;
+			break;
+		}
+	if (!found)
+		list_add_rcu(&key->dk_list, head);
+	spin_unlock(&spl->spin);
+
+	if (!found)
+		DyPrSym(key);
+	return found;
+}
+
+static void dy_free_rcu(struct rcu_head *rcu)
+{
+	struct au_dykey *key;
+
+	key = container_of(rcu, struct au_dykey, dk_rcu);
+	DyPrSym(key);
+	kfree(key);
+}
+
+static void dy_free(struct kref *kref)
+{
+	struct au_dykey *key;
+	struct au_splhead *spl;
+
+	key = container_of(kref, struct au_dykey, dk_kref);
+	spl = dynop + key->dk_op.dy_type;
+	au_spl_del_rcu(&key->dk_list, spl);
+	call_rcu(&key->dk_rcu, dy_free_rcu);
+}
+
+void au_dy_put(struct au_dykey *key)
+{
+	kref_put(&key->dk_kref, dy_free);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#define DyDbgSize(cnt, op)	AuDebugOn(cnt != sizeof(op)/sizeof(void *))
+
+#ifdef CONFIG_AUFS_DEBUG
+#define DyDbgDeclare(cnt)	unsigned int cnt = 0
+#define DyDbgInc(cnt)		do { cnt++; } while (0)
+#else
+#define DyDbgDeclare(cnt)	do {} while (0)
+#define DyDbgInc(cnt)		do {} while (0)
+#endif
+
+#define DySet(func, dst, src, h_op, h_sb) do {				\
+	DyDbgInc(cnt);							\
+	if (h_op->func) {						\
+		if (src.func)						\
+			dst.func = src.func;				\
+		else							\
+			AuDbg("%s %s\n", au_sbtype(h_sb), #func);	\
+	}								\
+} while (0)
+
+#define DySetForce(func, dst, src) do {		\
+	AuDebugOn(!src.func);			\
+	DyDbgInc(cnt);				\
+	dst.func = src.func;			\
+} while (0)
+
+#define DySetAop(func) \
+	DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb)
+#define DySetAopForce(func) \
+	DySetForce(func, dyaop->da_op, aufs_aop)
+
+static void dy_aop(struct au_dykey *key, const void *h_op,
+		   struct super_block *h_sb __maybe_unused)
+{
+	struct au_dyaop *dyaop = (void *)key;
+	const struct address_space_operations *h_aop = h_op;
+	DyDbgDeclare(cnt);
+
+	AuDbg("%s\n", au_sbtype(h_sb));
+
+	DySetAop(writepage);
+	DySetAopForce(readpage);	/* force */
+	DySetAop(writepages);
+	DySetAop(set_page_dirty);
+	DySetAop(readpages);
+	DySetAop(write_begin);
+	DySetAop(write_end);
+	DySetAop(bmap);
+	DySetAop(invalidatepage);
+	DySetAop(releasepage);
+	DySetAop(freepage);
+	/* this one will be changed according to an aufs mount option */
+	DySetAop(direct_IO);
+	DySetAop(migratepage);
+	DySetAop(launder_page);
+	DySetAop(is_partially_uptodate);
+	DySetAop(is_dirty_writeback);
+	DySetAop(error_remove_page);
+	DySetAop(swap_activate);
+	DySetAop(swap_deactivate);
+
+	DyDbgSize(cnt, *h_aop);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void dy_bug(struct kref *kref)
+{
+	BUG();
+}
+
+static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br)
+{
+	struct au_dykey *key, *old;
+	struct au_splhead *spl;
+	struct op {
+		unsigned int sz;
+		void (*set)(struct au_dykey *key, const void *h_op,
+			    struct super_block *h_sb __maybe_unused);
+	};
+	static const struct op a[] = {
+		[AuDy_AOP] = {
+			.sz	= sizeof(struct au_dyaop),
+			.set	= dy_aop
+		}
+	};
+	const struct op *p;
+
+	spl = dynop + op->dy_type;
+	key = dy_gfind_get(spl, op->dy_hop);
+	if (key)
+		goto out_add; /* success */
+
+	p = a + op->dy_type;
+	key = kzalloc(p->sz, GFP_NOFS);
+	if (unlikely(!key)) {
+		key = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	key->dk_op.dy_hop = op->dy_hop;
+	kref_init(&key->dk_kref);
+	p->set(key, op->dy_hop, au_br_sb(br));
+	old = dy_gadd(spl, key);
+	if (old) {
+		kfree(key);
+		key = old;
+	}
+
+out_add:
+	old = dy_bradd(br, key);
+	if (old)
+		/* its ref-count should never be zero here */
+		kref_put(&key->dk_kref, dy_bug);
+out:
+	return key;
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Aufs prohibits O_DIRECT by defaut even if the branch supports it.
+ * This behaviour is necessary to return an error from open(O_DIRECT) instead
+ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes
+ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error.
+ * See the aufs manual in detail.
+ */
+static void dy_adx(struct au_dyaop *dyaop, int do_dx)
+{
+	if (!do_dx)
+		dyaop->da_op.direct_IO = NULL;
+	else
+		dyaop->da_op.direct_IO = aufs_aop.direct_IO;
+}
+
+static struct au_dyaop *dy_aget(struct au_branch *br,
+				const struct address_space_operations *h_aop,
+				int do_dx)
+{
+	struct au_dyaop *dyaop;
+	struct au_dynop op;
+
+	op.dy_type = AuDy_AOP;
+	op.dy_haop = h_aop;
+	dyaop = (void *)dy_get(&op, br);
+	if (IS_ERR(dyaop))
+		goto out;
+	dy_adx(dyaop, do_dx);
+
+out:
+	return dyaop;
+}
+
+int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex,
+		struct inode *h_inode)
+{
+	int err, do_dx;
+	struct super_block *sb;
+	struct au_branch *br;
+	struct au_dyaop *dyaop;
+
+	AuDebugOn(!S_ISREG(h_inode->i_mode));
+	IiMustWriteLock(inode);
+
+	sb = inode->i_sb;
+	br = au_sbr(sb, bindex);
+	do_dx = !!au_opt_test(au_mntflags(sb), DIO);
+	dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx);
+	err = PTR_ERR(dyaop);
+	if (IS_ERR(dyaop))
+		/* unnecessary to call dy_fput() */
+		goto out;
+
+	err = 0;
+	inode->i_mapping->a_ops = &dyaop->da_op;
+
+out:
+	return err;
+}
+
+/*
+ * Is it safe to replace a_ops during the inode/file is in operation?
+ * Yes, I hope so.
+ */
+int au_dy_irefresh(struct inode *inode)
+{
+	int err;
+	aufs_bindex_t bstart;
+	struct inode *h_inode;
+
+	err = 0;
+	if (S_ISREG(inode->i_mode)) {
+		bstart = au_ibstart(inode);
+		h_inode = au_h_iptr(inode, bstart);
+		err = au_dy_iaop(inode, bstart, h_inode);
+	}
+	return err;
+}
+
+void au_dy_arefresh(int do_dx)
+{
+	struct au_splhead *spl;
+	struct list_head *head;
+	struct au_dykey *key;
+
+	spl = dynop + AuDy_AOP;
+	head = &spl->head;
+	spin_lock(&spl->spin);
+	list_for_each_entry(key, head, dk_list)
+		dy_adx((void *)key, do_dx);
+	spin_unlock(&spl->spin);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void __init au_dy_init(void)
+{
+	int i;
+
+	/* make sure that 'struct au_dykey *' can be any type */
+	BUILD_BUG_ON(offsetof(struct au_dyaop, da_key));
+
+	for (i = 0; i < AuDyLast; i++)
+		au_spl_init(dynop + i);
+}
+
+void au_dy_fin(void)
+{
+	int i;
+
+	for (i = 0; i < AuDyLast; i++)
+		WARN_ON(!list_empty(&dynop[i].head));
+}
--- linux-4.4.0.orig/fs/aufs/dynop.h
+++ linux-4.4.0/fs/aufs/dynop.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * dynamically customizable operations (for regular files only)
+ */
+
+#ifndef __AUFS_DYNOP_H__
+#define __AUFS_DYNOP_H__
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+#include <linux/kref.h>
+
+enum {AuDy_AOP, AuDyLast};
+
+struct au_dynop {
+	int						dy_type;
+	union {
+		const void				*dy_hop;
+		const struct address_space_operations	*dy_haop;
+	};
+};
+
+struct au_dykey {
+	union {
+		struct list_head	dk_list;
+		struct rcu_head		dk_rcu;
+	};
+	struct au_dynop		dk_op;
+
+	/*
+	 * during I am in the branch local array, kref is gotten. when the
+	 * branch is removed, kref is put.
+	 */
+	struct kref		dk_kref;
+};
+
+/* stop unioning since their sizes are very different from each other */
+struct au_dyaop {
+	struct au_dykey			da_key;
+	struct address_space_operations	da_op; /* not const */
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* dynop.c */
+struct au_branch;
+void au_dy_put(struct au_dykey *key);
+int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex,
+		struct inode *h_inode);
+int au_dy_irefresh(struct inode *inode);
+void au_dy_arefresh(int do_dio);
+
+void __init au_dy_init(void);
+void au_dy_fin(void);
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DYNOP_H__ */
--- linux-4.4.0.orig/fs/aufs/export.c
+++ linux-4.4.0/fs/aufs/export.c
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * export via nfs
+ */
+
+#include <linux/exportfs.h>
+#include <linux/fs_struct.h>
+#include <linux/namei.h>
+#include <linux/nsproxy.h>
+#include <linux/random.h>
+#include <linux/writeback.h>
+#include "../fs/mount.h"
+#include "aufs.h"
+
+union conv {
+#ifdef CONFIG_AUFS_INO_T_64
+	__u32 a[2];
+#else
+	__u32 a[1];
+#endif
+	ino_t ino;
+};
+
+static ino_t decode_ino(__u32 *a)
+{
+	union conv u;
+
+	BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a));
+	u.a[0] = a[0];
+#ifdef CONFIG_AUFS_INO_T_64
+	u.a[1] = a[1];
+#endif
+	return u.ino;
+}
+
+static void encode_ino(__u32 *a, ino_t ino)
+{
+	union conv u;
+
+	u.ino = ino;
+	a[0] = u.a[0];
+#ifdef CONFIG_AUFS_INO_T_64
+	a[1] = u.a[1];
+#endif
+}
+
+/* NFS file handle */
+enum {
+	Fh_br_id,
+	Fh_sigen,
+#ifdef CONFIG_AUFS_INO_T_64
+	/* support 64bit inode number */
+	Fh_ino1,
+	Fh_ino2,
+	Fh_dir_ino1,
+	Fh_dir_ino2,
+#else
+	Fh_ino1,
+	Fh_dir_ino1,
+#endif
+	Fh_igen,
+	Fh_h_type,
+	Fh_tail,
+
+	Fh_ino = Fh_ino1,
+	Fh_dir_ino = Fh_dir_ino1
+};
+
+static int au_test_anon(struct dentry *dentry)
+{
+	/* note: read d_flags without d_lock */
+	return !!(dentry->d_flags & DCACHE_DISCONNECTED);
+}
+
+int au_test_nfsd(void)
+{
+	int ret;
+	struct task_struct *tsk = current;
+	char comm[sizeof(tsk->comm)];
+
+	ret = 0;
+	if (tsk->flags & PF_KTHREAD) {
+		get_task_comm(comm, tsk);
+		ret = !strcmp(comm, "nfsd");
+	}
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------------- */
+/* inode generation external table */
+
+void au_xigen_inc(struct inode *inode)
+{
+	loff_t pos;
+	ssize_t sz;
+	__u32 igen;
+	struct super_block *sb;
+	struct au_sbinfo *sbinfo;
+
+	sb = inode->i_sb;
+	AuDebugOn(!au_opt_test(au_mntflags(sb), XINO));
+
+	sbinfo = au_sbi(sb);
+	pos = inode->i_ino;
+	pos *= sizeof(igen);
+	igen = inode->i_generation + 1;
+	sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen,
+			 sizeof(igen), &pos);
+	if (sz == sizeof(igen))
+		return; /* success */
+
+	if (unlikely(sz >= 0))
+		AuIOErr("xigen error (%zd)\n", sz);
+}
+
+int au_xigen_new(struct inode *inode)
+{
+	int err;
+	loff_t pos;
+	ssize_t sz;
+	struct super_block *sb;
+	struct au_sbinfo *sbinfo;
+	struct file *file;
+
+	err = 0;
+	/* todo: dirty, at mount time */
+	if (inode->i_ino == AUFS_ROOT_INO)
+		goto out;
+	sb = inode->i_sb;
+	SiMustAnyLock(sb);
+	if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
+		goto out;
+
+	err = -EFBIG;
+	pos = inode->i_ino;
+	if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) {
+		AuIOErr1("too large i%lld\n", pos);
+		goto out;
+	}
+	pos *= sizeof(inode->i_generation);
+
+	err = 0;
+	sbinfo = au_sbi(sb);
+	file = sbinfo->si_xigen;
+	BUG_ON(!file);
+
+	if (vfsub_f_size_read(file)
+	    < pos + sizeof(inode->i_generation)) {
+		inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next);
+		sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation,
+				 sizeof(inode->i_generation), &pos);
+	} else
+		sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation,
+				sizeof(inode->i_generation), &pos);
+	if (sz == sizeof(inode->i_generation))
+		goto out; /* success */
+
+	err = sz;
+	if (unlikely(sz >= 0)) {
+		err = -EIO;
+		AuIOErr("xigen error (%zd)\n", sz);
+	}
+
+out:
+	return err;
+}
+
+int au_xigen_set(struct super_block *sb, struct file *base)
+{
+	int err;
+	struct au_sbinfo *sbinfo;
+	struct file *file;
+
+	SiMustWriteLock(sb);
+
+	sbinfo = au_sbi(sb);
+	file = au_xino_create2(base, sbinfo->si_xigen);
+	err = PTR_ERR(file);
+	if (IS_ERR(file))
+		goto out;
+	err = 0;
+	if (sbinfo->si_xigen)
+		fput(sbinfo->si_xigen);
+	sbinfo->si_xigen = file;
+
+out:
+	return err;
+}
+
+void au_xigen_clr(struct super_block *sb)
+{
+	struct au_sbinfo *sbinfo;
+
+	SiMustWriteLock(sb);
+
+	sbinfo = au_sbi(sb);
+	if (sbinfo->si_xigen) {
+		fput(sbinfo->si_xigen);
+		sbinfo->si_xigen = NULL;
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino,
+				    ino_t dir_ino)
+{
+	struct dentry *dentry, *d;
+	struct inode *inode;
+	unsigned int sigen;
+
+	dentry = NULL;
+	inode = ilookup(sb, ino);
+	if (!inode)
+		goto out;
+
+	dentry = ERR_PTR(-ESTALE);
+	sigen = au_sigen(sb);
+	if (unlikely(is_bad_inode(inode)
+		     || IS_DEADDIR(inode)
+		     || sigen != au_iigen(inode, NULL)))
+		goto out_iput;
+
+	dentry = NULL;
+	if (!dir_ino || S_ISDIR(inode->i_mode))
+		dentry = d_find_alias(inode);
+	else {
+		spin_lock(&inode->i_lock);
+		hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) {
+			spin_lock(&d->d_lock);
+			if (!au_test_anon(d)
+			    && d_inode(d->d_parent)->i_ino == dir_ino) {
+				dentry = dget_dlock(d);
+				spin_unlock(&d->d_lock);
+				break;
+			}
+			spin_unlock(&d->d_lock);
+		}
+		spin_unlock(&inode->i_lock);
+	}
+	if (unlikely(dentry && au_digen_test(dentry, sigen))) {
+		/* need to refresh */
+		dput(dentry);
+		dentry = NULL;
+	}
+
+out_iput:
+	iput(inode);
+out:
+	AuTraceErrPtr(dentry);
+	return dentry;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* todo: dirty? */
+/* if exportfs_decode_fh() passed vfsmount*, we could be happy */
+
+struct au_compare_mnt_args {
+	/* input */
+	struct super_block *sb;
+
+	/* output */
+	struct vfsmount *mnt;
+};
+
+static int au_compare_mnt(struct vfsmount *mnt, void *arg)
+{
+	struct au_compare_mnt_args *a = arg;
+
+	if (mnt->mnt_sb != a->sb)
+		return 0;
+	a->mnt = mntget(mnt);
+	return 1;
+}
+
+static struct vfsmount *au_mnt_get(struct super_block *sb)
+{
+	int err;
+	struct path root;
+	struct au_compare_mnt_args args = {
+		.sb = sb
+	};
+
+	get_fs_root(current->fs, &root);
+	rcu_read_lock();
+	err = iterate_mounts(au_compare_mnt, &args, root.mnt);
+	rcu_read_unlock();
+	path_put(&root);
+	AuDebugOn(!err);
+	AuDebugOn(!args.mnt);
+	return args.mnt;
+}
+
+struct au_nfsd_si_lock {
+	unsigned int sigen;
+	aufs_bindex_t bindex, br_id;
+	unsigned char force_lock;
+};
+
+static int si_nfsd_read_lock(struct super_block *sb,
+			     struct au_nfsd_si_lock *nsi_lock)
+{
+	int err;
+	aufs_bindex_t bindex;
+
+	si_read_lock(sb, AuLock_FLUSH);
+
+	/* branch id may be wrapped around */
+	err = 0;
+	bindex = au_br_index(sb, nsi_lock->br_id);
+	if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb))
+		goto out; /* success */
+
+	err = -ESTALE;
+	bindex = -1;
+	if (!nsi_lock->force_lock)
+		si_read_unlock(sb);
+
+out:
+	nsi_lock->bindex = bindex;
+	return err;
+}
+
+struct find_name_by_ino {
+	struct dir_context ctx;
+	int called, found;
+	ino_t ino;
+	char *name;
+	int namelen;
+};
+
+static int
+find_name_by_ino(struct dir_context *ctx, const char *name, int namelen,
+		 loff_t offset, u64 ino, unsigned int d_type)
+{
+	struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino,
+						  ctx);
+
+	a->called++;
+	if (a->ino != ino)
+		return 0;
+
+	memcpy(a->name, name, namelen);
+	a->namelen = namelen;
+	a->found = 1;
+	return 1;
+}
+
+static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino,
+				     struct au_nfsd_si_lock *nsi_lock)
+{
+	struct dentry *dentry, *parent;
+	struct file *file;
+	struct inode *dir;
+	struct find_name_by_ino arg = {
+		.ctx = {
+			.actor = find_name_by_ino
+		}
+	};
+	int err;
+
+	parent = path->dentry;
+	if (nsi_lock)
+		si_read_unlock(parent->d_sb);
+	file = vfsub_dentry_open(path, au_dir_roflags);
+	dentry = (void *)file;
+	if (IS_ERR(file))
+		goto out;
+
+	dentry = ERR_PTR(-ENOMEM);
+	arg.name = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!arg.name))
+		goto out_file;
+	arg.ino = ino;
+	arg.found = 0;
+	do {
+		arg.called = 0;
+		/* smp_mb(); */
+		err = vfsub_iterate_dir(file, &arg.ctx);
+	} while (!err && !arg.found && arg.called);
+	dentry = ERR_PTR(err);
+	if (unlikely(err))
+		goto out_name;
+	/* instead of ENOENT */
+	dentry = ERR_PTR(-ESTALE);
+	if (!arg.found)
+		goto out_name;
+
+	/* do not call vfsub_lkup_one() */
+	dir = d_inode(parent);
+	mutex_lock(&dir->i_mutex);
+	dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen);
+	mutex_unlock(&dir->i_mutex);
+	AuTraceErrPtr(dentry);
+	if (IS_ERR(dentry))
+		goto out_name;
+	AuDebugOn(au_test_anon(dentry));
+	if (unlikely(d_really_is_negative(dentry))) {
+		dput(dentry);
+		dentry = ERR_PTR(-ENOENT);
+	}
+
+out_name:
+	free_page((unsigned long)arg.name);
+out_file:
+	fput(file);
+out:
+	if (unlikely(nsi_lock
+		     && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0))
+		if (!IS_ERR(dentry)) {
+			dput(dentry);
+			dentry = ERR_PTR(-ESTALE);
+		}
+	AuTraceErrPtr(dentry);
+	return dentry;
+}
+
+static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino,
+					ino_t dir_ino,
+					struct au_nfsd_si_lock *nsi_lock)
+{
+	struct dentry *dentry;
+	struct path path;
+
+	if (dir_ino != AUFS_ROOT_INO) {
+		path.dentry = decode_by_ino(sb, dir_ino, 0);
+		dentry = path.dentry;
+		if (!path.dentry || IS_ERR(path.dentry))
+			goto out;
+		AuDebugOn(au_test_anon(path.dentry));
+	} else
+		path.dentry = dget(sb->s_root);
+
+	path.mnt = au_mnt_get(sb);
+	dentry = au_lkup_by_ino(&path, ino, nsi_lock);
+	path_put(&path);
+
+out:
+	AuTraceErrPtr(dentry);
+	return dentry;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int h_acceptable(void *expv, struct dentry *dentry)
+{
+	return 1;
+}
+
+static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath,
+			   char *buf, int len, struct super_block *sb)
+{
+	char *p;
+	int n;
+	struct path path;
+
+	p = d_path(h_rootpath, buf, len);
+	if (IS_ERR(p))
+		goto out;
+	n = strlen(p);
+
+	path.mnt = h_rootpath->mnt;
+	path.dentry = h_parent;
+	p = d_path(&path, buf, len);
+	if (IS_ERR(p))
+		goto out;
+	if (n != 1)
+		p += n;
+
+	path.mnt = au_mnt_get(sb);
+	path.dentry = sb->s_root;
+	p = d_path(&path, buf, len - strlen(p));
+	mntput(path.mnt);
+	if (IS_ERR(p))
+		goto out;
+	if (n != 1)
+		p[strlen(p)] = '/';
+
+out:
+	AuTraceErrPtr(p);
+	return p;
+}
+
+static
+struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh,
+			      int fh_len, struct au_nfsd_si_lock *nsi_lock)
+{
+	struct dentry *dentry, *h_parent, *root;
+	struct super_block *h_sb;
+	char *pathname, *p;
+	struct vfsmount *h_mnt;
+	struct au_branch *br;
+	int err;
+	struct path path;
+
+	br = au_sbr(sb, nsi_lock->bindex);
+	h_mnt = au_br_mnt(br);
+	h_sb = h_mnt->mnt_sb;
+	/* todo: call lower fh_to_dentry()? fh_to_parent()? */
+	h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail),
+				      fh_len - Fh_tail, fh[Fh_h_type],
+				      h_acceptable, /*context*/NULL);
+	dentry = h_parent;
+	if (unlikely(!h_parent || IS_ERR(h_parent))) {
+		AuWarn1("%s decode_fh failed, %ld\n",
+			au_sbtype(h_sb), PTR_ERR(h_parent));
+		goto out;
+	}
+	dentry = NULL;
+	if (unlikely(au_test_anon(h_parent))) {
+		AuWarn1("%s decode_fh returned a disconnected dentry\n",
+			au_sbtype(h_sb));
+		goto out_h_parent;
+	}
+
+	dentry = ERR_PTR(-ENOMEM);
+	pathname = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!pathname))
+		goto out_h_parent;
+
+	root = sb->s_root;
+	path.mnt = h_mnt;
+	di_read_lock_parent(root, !AuLock_IR);
+	path.dentry = au_h_dptr(root, nsi_lock->bindex);
+	di_read_unlock(root, !AuLock_IR);
+	p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb);
+	dentry = (void *)p;
+	if (IS_ERR(p))
+		goto out_pathname;
+
+	si_read_unlock(sb);
+	err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
+	dentry = ERR_PTR(err);
+	if (unlikely(err))
+		goto out_relock;
+
+	dentry = ERR_PTR(-ENOENT);
+	AuDebugOn(au_test_anon(path.dentry));
+	if (unlikely(d_really_is_negative(path.dentry)))
+		goto out_path;
+
+	if (ino != d_inode(path.dentry)->i_ino)
+		dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL);
+	else
+		dentry = dget(path.dentry);
+
+out_path:
+	path_put(&path);
+out_relock:
+	if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0))
+		if (!IS_ERR(dentry)) {
+			dput(dentry);
+			dentry = ERR_PTR(-ESTALE);
+		}
+out_pathname:
+	free_page((unsigned long)pathname);
+out_h_parent:
+	dput(h_parent);
+out:
+	AuTraceErrPtr(dentry);
+	return dentry;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct dentry *
+aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
+		  int fh_type)
+{
+	struct dentry *dentry;
+	__u32 *fh = fid->raw;
+	struct au_branch *br;
+	ino_t ino, dir_ino;
+	struct au_nfsd_si_lock nsi_lock = {
+		.force_lock	= 0
+	};
+
+	dentry = ERR_PTR(-ESTALE);
+	/* it should never happen, but the file handle is unreliable */
+	if (unlikely(fh_len < Fh_tail))
+		goto out;
+	nsi_lock.sigen = fh[Fh_sigen];
+	nsi_lock.br_id = fh[Fh_br_id];
+
+	/* branch id may be wrapped around */
+	br = NULL;
+	if (unlikely(si_nfsd_read_lock(sb, &nsi_lock)))
+		goto out;
+	nsi_lock.force_lock = 1;
+
+	/* is this inode still cached? */
+	ino = decode_ino(fh + Fh_ino);
+	/* it should never happen */
+	if (unlikely(ino == AUFS_ROOT_INO))
+		goto out;
+
+	dir_ino = decode_ino(fh + Fh_dir_ino);
+	dentry = decode_by_ino(sb, ino, dir_ino);
+	if (IS_ERR(dentry))
+		goto out_unlock;
+	if (dentry)
+		goto accept;
+
+	/* is the parent dir cached? */
+	br = au_sbr(sb, nsi_lock.bindex);
+	atomic_inc(&br->br_count);
+	dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
+	if (IS_ERR(dentry))
+		goto out_unlock;
+	if (dentry)
+		goto accept;
+
+	/* lookup path */
+	dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock);
+	if (IS_ERR(dentry))
+		goto out_unlock;
+	if (unlikely(!dentry))
+		/* todo?: make it ESTALE */
+		goto out_unlock;
+
+accept:
+	if (!au_digen_test(dentry, au_sigen(sb))
+	    && d_inode(dentry)->i_generation == fh[Fh_igen])
+		goto out_unlock; /* success */
+
+	dput(dentry);
+	dentry = ERR_PTR(-ESTALE);
+out_unlock:
+	if (br)
+		atomic_dec(&br->br_count);
+	si_read_unlock(sb);
+out:
+	AuTraceErrPtr(dentry);
+	return dentry;
+}
+
+#if 0 /* reserved for future use */
+/* support subtreecheck option */
+static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid,
+					int fh_len, int fh_type)
+{
+	struct dentry *parent;
+	__u32 *fh = fid->raw;
+	ino_t dir_ino;
+
+	dir_ino = decode_ino(fh + Fh_dir_ino);
+	parent = decode_by_ino(sb, dir_ino, 0);
+	if (IS_ERR(parent))
+		goto out;
+	if (!parent)
+		parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]),
+					dir_ino, fh, fh_len);
+
+out:
+	AuTraceErrPtr(parent);
+	return parent;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len,
+			  struct inode *dir)
+{
+	int err;
+	aufs_bindex_t bindex;
+	struct super_block *sb, *h_sb;
+	struct dentry *dentry, *parent, *h_parent;
+	struct inode *h_dir;
+	struct au_branch *br;
+
+	err = -ENOSPC;
+	if (unlikely(*max_len <= Fh_tail)) {
+		AuWarn1("NFSv2 client (max_len %d)?\n", *max_len);
+		goto out;
+	}
+
+	err = FILEID_ROOT;
+	if (inode->i_ino == AUFS_ROOT_INO) {
+		AuDebugOn(inode->i_ino != AUFS_ROOT_INO);
+		goto out;
+	}
+
+	h_parent = NULL;
+	sb = inode->i_sb;
+	err = si_read_lock(sb, AuLock_FLUSH);
+	if (unlikely(err))
+		goto out;
+
+#ifdef CONFIG_AUFS_DEBUG
+	if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
+		AuWarn1("NFS-exporting requires xino\n");
+#endif
+	err = -EIO;
+	parent = NULL;
+	ii_read_lock_child(inode);
+	bindex = au_ibstart(inode);
+	if (!dir) {
+		dentry = d_find_any_alias(inode);
+		if (unlikely(!dentry))
+			goto out_unlock;
+		AuDebugOn(au_test_anon(dentry));
+		parent = dget_parent(dentry);
+		dput(dentry);
+		if (unlikely(!parent))
+			goto out_unlock;
+		if (d_really_is_positive(parent))
+			dir = d_inode(parent);
+	}
+
+	ii_read_lock_parent(dir);
+	h_dir = au_h_iptr(dir, bindex);
+	ii_read_unlock(dir);
+	if (unlikely(!h_dir))
+		goto out_parent;
+	h_parent = d_find_any_alias(h_dir);
+	if (unlikely(!h_parent))
+		goto out_hparent;
+
+	err = -EPERM;
+	br = au_sbr(sb, bindex);
+	h_sb = au_br_sb(br);
+	if (unlikely(!h_sb->s_export_op)) {
+		AuErr1("%s branch is not exportable\n", au_sbtype(h_sb));
+		goto out_hparent;
+	}
+
+	fh[Fh_br_id] = br->br_id;
+	fh[Fh_sigen] = au_sigen(sb);
+	encode_ino(fh + Fh_ino, inode->i_ino);
+	encode_ino(fh + Fh_dir_ino, dir->i_ino);
+	fh[Fh_igen] = inode->i_generation;
+
+	*max_len -= Fh_tail;
+	fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail),
+					   max_len,
+					   /*connectable or subtreecheck*/0);
+	err = fh[Fh_h_type];
+	*max_len += Fh_tail;
+	/* todo: macros? */
+	if (err != FILEID_INVALID)
+		err = 99;
+	else
+		AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));
+
+out_hparent:
+	dput(h_parent);
+out_parent:
+	dput(parent);
+out_unlock:
+	ii_read_unlock(inode);
+	si_read_unlock(sb);
+out:
+	if (unlikely(err < 0))
+		err = FILEID_INVALID;
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int aufs_commit_metadata(struct inode *inode)
+{
+	int err;
+	aufs_bindex_t bindex;
+	struct super_block *sb;
+	struct inode *h_inode;
+	int (*f)(struct inode *inode);
+
+	sb = inode->i_sb;
+	si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+	ii_write_lock_child(inode);
+	bindex = au_ibstart(inode);
+	AuDebugOn(bindex < 0);
+	h_inode = au_h_iptr(inode, bindex);
+
+	f = h_inode->i_sb->s_export_op->commit_metadata;
+	if (f)
+		err = f(h_inode);
+	else {
+		struct writeback_control wbc = {
+			.sync_mode	= WB_SYNC_ALL,
+			.nr_to_write	= 0 /* metadata only */
+		};
+
+		err = sync_inode(h_inode, &wbc);
+	}
+
+	au_cpup_attr_timesizes(inode);
+	ii_write_unlock(inode);
+	si_read_unlock(sb);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct export_operations aufs_export_op = {
+	.fh_to_dentry		= aufs_fh_to_dentry,
+	/* .fh_to_parent	= aufs_fh_to_parent, */
+	.encode_fh		= aufs_encode_fh,
+	.commit_metadata	= aufs_commit_metadata
+};
+
+void au_export_init(struct super_block *sb)
+{
+	struct au_sbinfo *sbinfo;
+	__u32 u;
+
+	sb->s_export_op = &aufs_export_op;
+	sbinfo = au_sbi(sb);
+	sbinfo->si_xigen = NULL;
+	get_random_bytes(&u, sizeof(u));
+	BUILD_BUG_ON(sizeof(u) != sizeof(int));
+	atomic_set(&sbinfo->si_xigen_next, u);
+}
--- linux-4.4.0.orig/fs/aufs/f_op.c
+++ linux-4.4.0/fs/aufs/f_op.c
@@ -0,0 +1,748 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * file and vm operations
+ */
+
+#include <linux/aio.h>
+#include <linux/fs_stack.h>
+#include <linux/mman.h>
+#include <linux/security.h>
+#include "aufs.h"
+
+int au_do_open_nondir(struct file *file, int flags, struct file *h_file)
+{
+	int err;
+	aufs_bindex_t bindex;
+	struct dentry *dentry, *h_dentry;
+	struct au_finfo *finfo;
+	struct inode *h_inode;
+
+	FiMustWriteLock(file);
+
+	err = 0;
+	dentry = file->f_path.dentry;
+	AuDebugOn(IS_ERR_OR_NULL(dentry));
+	finfo = au_fi(file);
+	memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop));
+	atomic_set(&finfo->fi_mmapped, 0);
+	bindex = au_dbstart(dentry);
+	if (!h_file) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb);
+		if (unlikely(err))
+			goto out;
+		h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0);
+	} else {
+		h_dentry = h_file->f_path.dentry;
+		err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb);
+		if (unlikely(err))
+			goto out;
+		get_file(h_file);
+	}
+	if (IS_ERR(h_file))
+		err = PTR_ERR(h_file);
+	else {
+		if ((flags & __O_TMPFILE)
+		    && !(flags & O_EXCL)) {
+			h_inode = file_inode(h_file);
+			spin_lock(&h_inode->i_lock);
+			h_inode->i_state |= I_LINKABLE;
+			spin_unlock(&h_inode->i_lock);
+		}
+		au_set_fbstart(file, bindex);
+		au_set_h_fptr(file, bindex, h_file);
+		au_update_figen(file);
+		/* todo: necessary? */
+		/* file->f_ra = h_file->f_ra; */
+	}
+
+out:
+	return err;
+}
+
+static int aufs_open_nondir(struct inode *inode __maybe_unused,
+			    struct file *file)
+{
+	int err;
+	struct super_block *sb;
+	struct au_do_open_args args = {
+		.open	= au_do_open_nondir
+	};
+
+	AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n",
+	      file, vfsub_file_flags(file), file->f_mode);
+
+	sb = file->f_path.dentry->d_sb;
+	si_read_lock(sb, AuLock_FLUSH);
+	err = au_do_open(file, &args);
+	si_read_unlock(sb);
+	return err;
+}
+
+int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file)
+{
+	struct au_finfo *finfo;
+	aufs_bindex_t bindex;
+
+	finfo = au_fi(file);
+	au_sphl_del(&finfo->fi_hlist,
+		    &au_sbi(file->f_path.dentry->d_sb)->si_files);
+	bindex = finfo->fi_btop;
+	if (bindex >= 0)
+		au_set_h_fptr(file, bindex, NULL);
+
+	au_finfo_fin(file);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_do_flush_nondir(struct file *file, fl_owner_t id)
+{
+	int err;
+	struct file *h_file;
+
+	err = 0;
+	h_file = au_hf_top(file);
+	if (h_file)
+		err = vfsub_flush(h_file, id);
+	return err;
+}
+
+static int aufs_flush_nondir(struct file *file, fl_owner_t id)
+{
+	return au_do_flush(file, id, au_do_flush_nondir);
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * read and write functions acquire [fdi]_rwsem once, but release before
+ * mmap_sem. This is because to stop a race condition between mmap(2).
+ * Releasing these aufs-rwsem should be safe, no branch-mamagement (by keeping
+ * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in
+ * read functions after [fdi]_rwsem are released, but it should be harmless.
+ */
+
+/* Callers should call au_read_post() or fput() in the end */
+struct file *au_read_pre(struct file *file, int keep_fi)
+{
+	struct file *h_file;
+	int err;
+
+	err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
+	if (!err) {
+		di_read_unlock(file->f_path.dentry, AuLock_IR);
+		h_file = au_hf_top(file);
+		get_file(h_file);
+		if (!keep_fi)
+			fi_read_unlock(file);
+	} else
+		h_file = ERR_PTR(err);
+
+	return h_file;
+}
+
+static void au_read_post(struct inode *inode, struct file *h_file)
+{
+	/* update without lock, I don't think it a problem */
+	fsstack_copy_attr_atime(inode, file_inode(h_file));
+	fput(h_file);
+}
+
+struct au_write_pre {
+	blkcnt_t blks;
+	aufs_bindex_t bstart;
+};
+
+/*
+ * return with iinfo is write-locked
+ * callers should call au_write_post() or iinfo_write_unlock() + fput() in the
+ * end
+ */
+static struct file *au_write_pre(struct file *file, int do_ready,
+				 struct au_write_pre *wpre)
+{
+	struct file *h_file;
+	struct dentry *dentry;
+	int err;
+	struct au_pin pin;
+
+	err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+	h_file = ERR_PTR(err);
+	if (unlikely(err))
+		goto out;
+
+	dentry = file->f_path.dentry;
+	if (do_ready) {
+		err = au_ready_to_write(file, -1, &pin);
+		if (unlikely(err)) {
+			h_file = ERR_PTR(err);
+			di_write_unlock(dentry);
+			goto out_fi;
+		}
+	}
+
+	di_downgrade_lock(dentry, /*flags*/0);
+	if (wpre)
+		wpre->bstart = au_fbstart(file);
+	h_file = au_hf_top(file);
+	get_file(h_file);
+	if (wpre)
+		wpre->blks = file_inode(h_file)->i_blocks;
+	if (do_ready)
+		au_unpin(&pin);
+	di_read_unlock(dentry, /*flags*/0);
+
+out_fi:
+	fi_write_unlock(file);
+out:
+	return h_file;
+}
+
+static void au_write_post(struct inode *inode, struct file *h_file,
+			  struct au_write_pre *wpre, ssize_t written)
+{
+	struct inode *h_inode;
+
+	au_cpup_attr_timesizes(inode);
+	AuDebugOn(au_ibstart(inode) != wpre->bstart);
+	h_inode = file_inode(h_file);
+	inode->i_mode = h_inode->i_mode;
+	ii_write_unlock(inode);
+	fput(h_file);
+
+	/* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */
+	if (written > 0)
+		au_fhsm_wrote(inode->i_sb, wpre->bstart,
+			      /*force*/h_inode->i_blocks > wpre->blks);
+}
+
+static ssize_t aufs_read(struct file *file, char __user *buf, size_t count,
+			 loff_t *ppos)
+{
+	ssize_t err;
+	struct inode *inode;
+	struct file *h_file;
+	struct super_block *sb;
+
+	inode = file_inode(file);
+	sb = inode->i_sb;
+	si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+
+	h_file = au_read_pre(file, /*keep_fi*/0);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	/* filedata may be obsoleted by concurrent copyup, but no problem */
+	err = vfsub_read_u(h_file, buf, count, ppos);
+	/* todo: necessary? */
+	/* file->f_ra = h_file->f_ra; */
+	au_read_post(inode, h_file);
+
+out:
+	si_read_unlock(sb);
+	return err;
+}
+
+/*
+ * todo: very ugly
+ * it locks both of i_mutex and si_rwsem for read in safe.
+ * if the plink maintenance mode continues forever (that is the problem),
+ * may loop forever.
+ */
+static void au_mtx_and_read_lock(struct inode *inode)
+{
+	int err;
+	struct super_block *sb = inode->i_sb;
+
+	while (1) {
+		mutex_lock(&inode->i_mutex);
+		err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+		if (!err)
+			break;
+		mutex_unlock(&inode->i_mutex);
+		si_read_lock(sb, AuLock_NOPLMW);
+		si_read_unlock(sb);
+	}
+}
+
+static ssize_t aufs_write(struct file *file, const char __user *ubuf,
+			  size_t count, loff_t *ppos)
+{
+	ssize_t err;
+	struct au_write_pre wpre;
+	struct inode *inode;
+	struct file *h_file;
+	char __user *buf = (char __user *)ubuf;
+
+	inode = file_inode(file);
+	au_mtx_and_read_lock(inode);
+
+	h_file = au_write_pre(file, /*do_ready*/1, &wpre);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	err = vfsub_write_u(h_file, buf, count, ppos);
+	au_write_post(inode, h_file, &wpre, err);
+
+out:
+	si_read_unlock(inode->i_sb);
+	mutex_unlock(&inode->i_mutex);
+	return err;
+}
+
+static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio,
+			  struct iov_iter *iov_iter)
+{
+	ssize_t err;
+	struct file *file;
+	ssize_t (*iter)(struct kiocb *, struct iov_iter *);
+
+	err = security_file_permission(h_file, rw);
+	if (unlikely(err))
+		goto out;
+
+	err = -ENOSYS;
+	iter = NULL;
+	if (rw == MAY_READ)
+		iter = h_file->f_op->read_iter;
+	else if (rw == MAY_WRITE)
+		iter = h_file->f_op->write_iter;
+
+	file = kio->ki_filp;
+	kio->ki_filp = h_file;
+	if (iter) {
+		lockdep_off();
+		err = iter(kio, iov_iter);
+		lockdep_on();
+	} else
+		/* currently there is no such fs */
+		WARN_ON_ONCE(1);
+	kio->ki_filp = file;
+
+out:
+	return err;
+}
+
+static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter)
+{
+	ssize_t err;
+	struct file *file, *h_file;
+	struct inode *inode;
+	struct super_block *sb;
+
+	file = kio->ki_filp;
+	inode = file_inode(file);
+	sb = inode->i_sb;
+	si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+
+	h_file = au_read_pre(file, /*keep_fi*/0);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	err = au_do_iter(h_file, MAY_READ, kio, iov_iter);
+	/* todo: necessary? */
+	/* file->f_ra = h_file->f_ra; */
+	au_read_post(inode, h_file);
+
+out:
+	si_read_unlock(sb);
+	return err;
+}
+
+static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter)
+{
+	ssize_t err;
+	struct au_write_pre wpre;
+	struct inode *inode;
+	struct file *file, *h_file;
+
+	file = kio->ki_filp;
+	inode = file_inode(file);
+	au_mtx_and_read_lock(inode);
+
+	h_file = au_write_pre(file, /*do_ready*/1, &wpre);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter);
+	au_write_post(inode, h_file, &wpre, err);
+
+out:
+	si_read_unlock(inode->i_sb);
+	mutex_unlock(&inode->i_mutex);
+	return err;
+}
+
+static ssize_t aufs_splice_read(struct file *file, loff_t *ppos,
+				struct pipe_inode_info *pipe, size_t len,
+				unsigned int flags)
+{
+	ssize_t err;
+	struct file *h_file;
+	struct inode *inode;
+	struct super_block *sb;
+
+	inode = file_inode(file);
+	sb = inode->i_sb;
+	si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+
+	h_file = au_read_pre(file, /*keep_fi*/1);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	if (0 && au_test_loopback_kthread()) {
+		au_warn_loopback(h_file->f_path.dentry->d_sb);
+		if (file->f_mapping != h_file->f_mapping) {
+			file->f_mapping = h_file->f_mapping;
+			smp_mb(); /* unnecessary? */
+		}
+	}
+	fi_read_unlock(file);
+
+	err = vfsub_splice_to(h_file, ppos, pipe, len, flags);
+	/* todo: necessasry? */
+	/* file->f_ra = h_file->f_ra; */
+	au_read_post(inode, h_file);
+
+out:
+	si_read_unlock(sb);
+	return err;
+}
+
+static ssize_t
+aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos,
+		  size_t len, unsigned int flags)
+{
+	ssize_t err;
+	struct au_write_pre wpre;
+	struct inode *inode;
+	struct file *h_file;
+
+	inode = file_inode(file);
+	au_mtx_and_read_lock(inode);
+
+	h_file = au_write_pre(file, /*do_ready*/1, &wpre);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	err = vfsub_splice_from(pipe, h_file, ppos, len, flags);
+	au_write_post(inode, h_file, &wpre, err);
+
+out:
+	si_read_unlock(inode->i_sb);
+	mutex_unlock(&inode->i_mutex);
+	return err;
+}
+
+static long aufs_fallocate(struct file *file, int mode, loff_t offset,
+			   loff_t len)
+{
+	long err;
+	struct au_write_pre wpre;
+	struct inode *inode;
+	struct file *h_file;
+
+	inode = file_inode(file);
+	au_mtx_and_read_lock(inode);
+
+	h_file = au_write_pre(file, /*do_ready*/1, &wpre);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	lockdep_off();
+	err = vfs_fallocate(h_file, mode, offset, len);
+	lockdep_on();
+	au_write_post(inode, h_file, &wpre, /*written*/1);
+
+out:
+	si_read_unlock(inode->i_sb);
+	mutex_unlock(&inode->i_mutex);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * The locking order around current->mmap_sem.
+ * - in most and regular cases
+ *   file I/O syscall -- aufs_read() or something
+ *	-- si_rwsem for read -- mmap_sem
+ *	(Note that [fdi]i_rwsem are released before mmap_sem).
+ * - in mmap case
+ *   mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem
+ * This AB-BA order is definitly bad, but is not a problem since "si_rwsem for
+ * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in
+ * file I/O. Aufs needs to stop lockdep in aufs_mmap() though.
+ * It means that when aufs acquires si_rwsem for write, the process should never
+ * acquire mmap_sem.
+ *
+ * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a
+ * problem either since any directory is not able to be mmap-ed.
+ * The similar scenario is applied to aufs_readlink() too.
+ */
+
+#if 0 /* stop calling security_file_mmap() */
+/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */
+#define AuConv_VM_PROT(f, b)	_calc_vm_trans(f, VM_##b, PROT_##b)
+
+static unsigned long au_arch_prot_conv(unsigned long flags)
+{
+	/* currently ppc64 only */
+#ifdef CONFIG_PPC64
+	/* cf. linux/arch/powerpc/include/asm/mman.h */
+	AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO);
+	return AuConv_VM_PROT(flags, SAO);
+#else
+	AuDebugOn(arch_calc_vm_prot_bits(-1));
+	return 0;
+#endif
+}
+
+static unsigned long au_prot_conv(unsigned long flags)
+{
+	return AuConv_VM_PROT(flags, READ)
+		| AuConv_VM_PROT(flags, WRITE)
+		| AuConv_VM_PROT(flags, EXEC)
+		| au_arch_prot_conv(flags);
+}
+
+/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */
+#define AuConv_VM_MAP(f, b)	_calc_vm_trans(f, VM_##b, MAP_##b)
+
+static unsigned long au_flag_conv(unsigned long flags)
+{
+	return AuConv_VM_MAP(flags, GROWSDOWN)
+		| AuConv_VM_MAP(flags, DENYWRITE)
+		| AuConv_VM_MAP(flags, LOCKED);
+}
+#endif
+
+static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int err;
+	const unsigned char wlock
+		= (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
+	struct super_block *sb;
+	struct file *h_file;
+	struct inode *inode;
+
+	AuDbgVmRegion(file, vma);
+
+	inode = file_inode(file);
+	sb = inode->i_sb;
+	lockdep_off();
+	si_read_lock(sb, AuLock_NOPLMW);
+
+	h_file = au_write_pre(file, wlock, /*wpre*/NULL);
+	lockdep_on();
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	err = 0;
+	au_set_mmapped(file);
+	au_vm_file_reset(vma, h_file);
+	/*
+	 * we cannot call security_mmap_file() here since it may acquire
+	 * mmap_sem or i_mutex.
+	 *
+	 * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags),
+	 *			 au_flag_conv(vma->vm_flags));
+	 */
+	if (!err)
+		err = h_file->f_op->mmap(h_file, vma);
+	if (!err) {
+		au_vm_prfile_set(vma, file);
+		fsstack_copy_attr_atime(inode, file_inode(h_file));
+		goto out_fput; /* success */
+	}
+	au_unset_mmapped(file);
+	au_vm_file_reset(vma, file);
+
+out_fput:
+	lockdep_off();
+	ii_write_unlock(inode);
+	lockdep_on();
+	fput(h_file);
+out:
+	lockdep_off();
+	si_read_unlock(sb);
+	lockdep_on();
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end,
+			     int datasync)
+{
+	int err;
+	struct au_write_pre wpre;
+	struct inode *inode;
+	struct file *h_file;
+
+	err = 0; /* -EBADF; */ /* posix? */
+	if (unlikely(!(file->f_mode & FMODE_WRITE)))
+		goto out;
+
+	inode = file_inode(file);
+	au_mtx_and_read_lock(inode);
+
+	h_file = au_write_pre(file, /*do_ready*/1, &wpre);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out_unlock;
+
+	err = vfsub_fsync(h_file, &h_file->f_path, datasync);
+	au_write_post(inode, h_file, &wpre, /*written*/0);
+
+out_unlock:
+	si_read_unlock(inode->i_sb);
+	mutex_unlock(&inode->i_mutex);
+out:
+	return err;
+}
+
+/* no one supports this operation, currently */
+#if 0
+static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync)
+{
+	int err;
+	struct au_write_pre wpre;
+	struct inode *inode;
+	struct file *file, *h_file;
+
+	err = 0; /* -EBADF; */ /* posix? */
+	if (unlikely(!(file->f_mode & FMODE_WRITE)))
+		goto out;
+
+	file = kio->ki_filp;
+	inode = file_inode(file);
+	au_mtx_and_read_lock(inode);
+
+	h_file = au_write_pre(file, /*do_ready*/1, &wpre);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out_unlock;
+
+	err = -ENOSYS;
+	h_file = au_hf_top(file);
+	if (h_file->f_op->aio_fsync) {
+		struct mutex *h_mtx;
+
+		h_mtx = &file_inode(h_file)->i_mutex;
+		if (!is_sync_kiocb(kio)) {
+			get_file(h_file);
+			fput(file);
+		}
+		kio->ki_filp = h_file;
+		err = h_file->f_op->aio_fsync(kio, datasync);
+		mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
+		if (!err)
+			vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
+		/*ignore*/
+		mutex_unlock(h_mtx);
+	}
+	au_write_post(inode, h_file, &wpre, /*written*/0);
+
+out_unlock:
+	si_read_unlock(inode->sb);
+	mutex_unlock(&inode->i_mutex);
+out:
+	return err;
+}
+#endif
+
+static int aufs_fasync(int fd, struct file *file, int flag)
+{
+	int err;
+	struct file *h_file;
+	struct super_block *sb;
+
+	sb = file->f_path.dentry->d_sb;
+	si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+
+	h_file = au_read_pre(file, /*keep_fi*/0);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	if (h_file->f_op->fasync)
+		err = h_file->f_op->fasync(fd, h_file, flag);
+	fput(h_file); /* instead of au_read_post() */
+
+out:
+	si_read_unlock(sb);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* no one supports this operation, currently */
+#if 0
+static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset,
+			     size_t len, loff_t *pos, int more)
+{
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+const struct file_operations aufs_file_fop = {
+	.owner		= THIS_MODULE,
+
+	.llseek		= default_llseek,
+
+	.read		= aufs_read,
+	.write		= aufs_write,
+	.read_iter	= aufs_read_iter,
+	.write_iter	= aufs_write_iter,
+
+#ifdef CONFIG_AUFS_POLL
+	.poll		= aufs_poll,
+#endif
+	.unlocked_ioctl	= aufs_ioctl_nondir,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= aufs_compat_ioctl_nondir,
+#endif
+	.mmap		= aufs_mmap,
+	.open		= aufs_open_nondir,
+	.flush		= aufs_flush_nondir,
+	.release	= aufs_release_nondir,
+	.fsync		= aufs_fsync_nondir,
+	/* .aio_fsync	= aufs_aio_fsync_nondir, */
+	.fasync		= aufs_fasync,
+	/* .sendpage	= aufs_sendpage, */
+	.splice_write	= aufs_splice_write,
+	.splice_read	= aufs_splice_read,
+#if 0
+	.aio_splice_write = aufs_aio_splice_write,
+	.aio_splice_read  = aufs_aio_splice_read,
+#endif
+	.fallocate	= aufs_fallocate
+};
--- linux-4.4.0.orig/fs/aufs/fhsm.c
+++ linux-4.4.0/fs/aufs/fhsm.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2011-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ */
+
+/*
+ * File-based Hierarchy Storage Management
+ */
+
+#include <linux/anon_inodes.h>
+#include <linux/poll.h>
+#include <linux/seq_file.h>
+#include <linux/statfs.h>
+#include "aufs.h"
+
+static aufs_bindex_t au_fhsm_bottom(struct super_block *sb)
+{
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+
+	SiMustAnyLock(sb);
+
+	sbinfo = au_sbi(sb);
+	fhsm = &sbinfo->si_fhsm;
+	AuDebugOn(!fhsm);
+	return fhsm->fhsm_bottom;
+}
+
+void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex)
+{
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+
+	SiMustWriteLock(sb);
+
+	sbinfo = au_sbi(sb);
+	fhsm = &sbinfo->si_fhsm;
+	AuDebugOn(!fhsm);
+	fhsm->fhsm_bottom = bindex;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br)
+{
+	struct au_br_fhsm *bf;
+
+	bf = br->br_fhsm;
+	MtxMustLock(&bf->bf_lock);
+
+	return !bf->bf_readable
+		|| time_after(jiffies,
+			      bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void au_fhsm_notify(struct super_block *sb, int val)
+{
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+
+	SiMustAnyLock(sb);
+
+	sbinfo = au_sbi(sb);
+	fhsm = &sbinfo->si_fhsm;
+	if (au_fhsm_pid(fhsm)
+	    && atomic_read(&fhsm->fhsm_readable) != -1) {
+		atomic_set(&fhsm->fhsm_readable, val);
+		if (val)
+			wake_up(&fhsm->fhsm_wqh);
+	}
+}
+
+static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex,
+			struct aufs_stfs *rstfs, int do_lock, int do_notify)
+{
+	int err;
+	struct au_branch *br;
+	struct au_br_fhsm *bf;
+
+	br = au_sbr(sb, bindex);
+	AuDebugOn(au_br_rdonly(br));
+	bf = br->br_fhsm;
+	AuDebugOn(!bf);
+
+	if (do_lock)
+		mutex_lock(&bf->bf_lock);
+	else
+		MtxMustLock(&bf->bf_lock);
+
+	/* sb->s_root for NFS is unreliable */
+	err = au_br_stfs(br, &bf->bf_stfs);
+	if (unlikely(err)) {
+		AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err);
+		goto out;
+	}
+
+	bf->bf_jiffy = jiffies;
+	bf->bf_readable = 1;
+	if (do_notify)
+		au_fhsm_notify(sb, /*val*/1);
+	if (rstfs)
+		*rstfs = bf->bf_stfs;
+
+out:
+	if (do_lock)
+		mutex_unlock(&bf->bf_lock);
+	au_fhsm_notify(sb, /*val*/1);
+
+	return err;
+}
+
+void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force)
+{
+	int err;
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+	struct au_branch *br;
+	struct au_br_fhsm *bf;
+
+	AuDbg("b%d, force %d\n", bindex, force);
+	SiMustAnyLock(sb);
+
+	sbinfo = au_sbi(sb);
+	fhsm = &sbinfo->si_fhsm;
+	if (!au_ftest_si(sbinfo, FHSM)
+	    || fhsm->fhsm_bottom == bindex)
+		return;
+
+	br = au_sbr(sb, bindex);
+	bf = br->br_fhsm;
+	AuDebugOn(!bf);
+	mutex_lock(&bf->bf_lock);
+	if (force
+	    || au_fhsm_pid(fhsm)
+	    || au_fhsm_test_jiffy(sbinfo, br))
+		err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0,
+				  /*do_notify*/1);
+	mutex_unlock(&bf->bf_lock);
+}
+
+void au_fhsm_wrote_all(struct super_block *sb, int force)
+{
+	aufs_bindex_t bindex, bend;
+	struct au_branch *br;
+
+	/* exclude the bottom */
+	bend = au_fhsm_bottom(sb);
+	for (bindex = 0; bindex < bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		if (au_br_fhsm(br->br_perm))
+			au_fhsm_wrote(sb, bindex, force);
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned int au_fhsm_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	unsigned int mask;
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+
+	mask = 0;
+	sbinfo = file->private_data;
+	fhsm = &sbinfo->si_fhsm;
+	poll_wait(file, &fhsm->fhsm_wqh, wait);
+	if (atomic_read(&fhsm->fhsm_readable))
+		mask = POLLIN /* | POLLRDNORM */;
+
+	AuTraceErr((int)mask);
+	return mask;
+}
+
+static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr,
+			      struct aufs_stfs *stfs, __s16 brid)
+{
+	int err;
+
+	err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs));
+	if (!err)
+		err = __put_user(brid, &stbr->brid);
+	if (unlikely(err))
+		err = -EFAULT;
+
+	return err;
+}
+
+static ssize_t au_fhsm_do_read(struct super_block *sb,
+			       struct aufs_stbr __user *stbr, size_t count)
+{
+	ssize_t err;
+	int nstbr;
+	aufs_bindex_t bindex, bend;
+	struct au_branch *br;
+	struct au_br_fhsm *bf;
+
+	/* except the bottom branch */
+	err = 0;
+	nstbr = 0;
+	bend = au_fhsm_bottom(sb);
+	for (bindex = 0; !err && bindex < bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		if (!au_br_fhsm(br->br_perm))
+			continue;
+
+		bf = br->br_fhsm;
+		mutex_lock(&bf->bf_lock);
+		if (bf->bf_readable) {
+			err = -EFAULT;
+			if (count >= sizeof(*stbr))
+				err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs,
+							  br->br_id);
+			if (!err) {
+				bf->bf_readable = 0;
+				count -= sizeof(*stbr);
+				nstbr++;
+			}
+		}
+		mutex_unlock(&bf->bf_lock);
+	}
+	if (!err)
+		err = sizeof(*stbr) * nstbr;
+
+	return err;
+}
+
+static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count,
+			   loff_t *pos)
+{
+	ssize_t err;
+	int readable;
+	aufs_bindex_t nfhsm, bindex, bend;
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+	struct au_branch *br;
+	struct super_block *sb;
+
+	err = 0;
+	sbinfo = file->private_data;
+	fhsm = &sbinfo->si_fhsm;
+need_data:
+	spin_lock_irq(&fhsm->fhsm_wqh.lock);
+	if (!atomic_read(&fhsm->fhsm_readable)) {
+		if (vfsub_file_flags(file) & O_NONBLOCK)
+			err = -EAGAIN;
+		else
+			err = wait_event_interruptible_locked_irq
+				(fhsm->fhsm_wqh,
+				 atomic_read(&fhsm->fhsm_readable));
+	}
+	spin_unlock_irq(&fhsm->fhsm_wqh.lock);
+	if (unlikely(err))
+		goto out;
+
+	/* sb may already be dead */
+	au_rw_read_lock(&sbinfo->si_rwsem);
+	readable = atomic_read(&fhsm->fhsm_readable);
+	if (readable > 0) {
+		sb = sbinfo->si_sb;
+		AuDebugOn(!sb);
+		/* exclude the bottom branch */
+		nfhsm = 0;
+		bend = au_fhsm_bottom(sb);
+		for (bindex = 0; bindex < bend; bindex++) {
+			br = au_sbr(sb, bindex);
+			if (au_br_fhsm(br->br_perm))
+				nfhsm++;
+		}
+		err = -EMSGSIZE;
+		if (nfhsm * sizeof(struct aufs_stbr) <= count) {
+			atomic_set(&fhsm->fhsm_readable, 0);
+			err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf,
+					     count);
+		}
+	}
+	au_rw_read_unlock(&sbinfo->si_rwsem);
+	if (!readable)
+		goto need_data;
+
+out:
+	return err;
+}
+
+static int au_fhsm_release(struct inode *inode, struct file *file)
+{
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+
+	/* sb may already be dead */
+	sbinfo = file->private_data;
+	fhsm = &sbinfo->si_fhsm;
+	spin_lock(&fhsm->fhsm_spin);
+	fhsm->fhsm_pid = 0;
+	spin_unlock(&fhsm->fhsm_spin);
+	kobject_put(&sbinfo->si_kobj);
+
+	return 0;
+}
+
+static const struct file_operations au_fhsm_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= noop_llseek,
+	.read		= au_fhsm_read,
+	.poll		= au_fhsm_poll,
+	.release	= au_fhsm_release
+};
+
+int au_fhsm_fd(struct super_block *sb, int oflags)
+{
+	int err, fd;
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+
+	err = -EPERM;
+	if (unlikely(!capable(CAP_SYS_ADMIN)))
+		goto out;
+
+	err = -EINVAL;
+	if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK)))
+		goto out;
+
+	err = 0;
+	sbinfo = au_sbi(sb);
+	fhsm = &sbinfo->si_fhsm;
+	spin_lock(&fhsm->fhsm_spin);
+	if (!fhsm->fhsm_pid)
+		fhsm->fhsm_pid = current->pid;
+	else
+		err = -EBUSY;
+	spin_unlock(&fhsm->fhsm_spin);
+	if (unlikely(err))
+		goto out;
+
+	oflags |= O_RDONLY;
+	/* oflags |= FMODE_NONOTIFY; */
+	fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags);
+	err = fd;
+	if (unlikely(fd < 0))
+		goto out_pid;
+
+	/* succeed reglardless 'fhsm' status */
+	kobject_get(&sbinfo->si_kobj);
+	si_noflush_read_lock(sb);
+	if (au_ftest_si(sbinfo, FHSM))
+		au_fhsm_wrote_all(sb, /*force*/0);
+	si_read_unlock(sb);
+	goto out; /* success */
+
+out_pid:
+	spin_lock(&fhsm->fhsm_spin);
+	fhsm->fhsm_pid = 0;
+	spin_unlock(&fhsm->fhsm_spin);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_fhsm_br_alloc(struct au_branch *br)
+{
+	int err;
+
+	err = 0;
+	br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS);
+	if (br->br_fhsm)
+		au_br_fhsm_init(br->br_fhsm);
+	else
+		err = -ENOMEM;
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void au_fhsm_fin(struct super_block *sb)
+{
+	au_fhsm_notify(sb, /*val*/-1);
+}
+
+void au_fhsm_init(struct au_sbinfo *sbinfo)
+{
+	struct au_fhsm *fhsm;
+
+	fhsm = &sbinfo->si_fhsm;
+	spin_lock_init(&fhsm->fhsm_spin);
+	init_waitqueue_head(&fhsm->fhsm_wqh);
+	atomic_set(&fhsm->fhsm_readable, 0);
+	fhsm->fhsm_expire
+		= msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC);
+	fhsm->fhsm_bottom = -1;
+}
+
+void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec)
+{
+	sbinfo->si_fhsm.fhsm_expire
+		= msecs_to_jiffies(sec * MSEC_PER_SEC);
+}
+
+void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo)
+{
+	unsigned int u;
+
+	if (!au_ftest_si(sbinfo, FHSM))
+		return;
+
+	u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC;
+	if (u != AUFS_FHSM_CACHE_DEF_SEC)
+		seq_printf(seq, ",fhsm_sec=%u", u);
+}
--- linux-4.4.0.orig/fs/aufs/file.c
+++ linux-4.4.0/fs/aufs/file.c
@@ -0,0 +1,844 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * handling file/dir, and address_space operation
+ */
+
+#ifdef CONFIG_AUFS_DEBUG
+#include <linux/migrate.h>
+#endif
+#include <linux/pagemap.h>
+#include "aufs.h"
+
+/* drop flags for writing */
+unsigned int au_file_roflags(unsigned int flags)
+{
+	flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC);
+	flags |= O_RDONLY | O_NOATIME;
+	return flags;
+}
+
+/* common functions to regular file and dir */
+struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
+		       struct file *file, int force_wr)
+{
+	struct file *h_file;
+	struct dentry *h_dentry;
+	struct inode *h_inode;
+	struct super_block *sb;
+	struct au_branch *br;
+	struct path h_path;
+	int err;
+
+	/* a race condition can happen between open and unlink/rmdir */
+	h_file = ERR_PTR(-ENOENT);
+	h_dentry = au_h_dptr(dentry, bindex);
+	if (au_test_nfsd() && (!h_dentry || d_is_negative(h_dentry)))
+		goto out;
+	h_inode = d_inode(h_dentry);
+	spin_lock(&h_dentry->d_lock);
+	err = (!d_unhashed(dentry) && d_unlinked(h_dentry))
+		/* || !d_inode(dentry)->i_nlink */
+		;
+	spin_unlock(&h_dentry->d_lock);
+	if (unlikely(err))
+		goto out;
+
+	sb = dentry->d_sb;
+	br = au_sbr(sb, bindex);
+	err = au_br_test_oflag(flags, br);
+	h_file = ERR_PTR(err);
+	if (unlikely(err))
+		goto out;
+
+	/* drop flags for writing */
+	if (au_test_ro(sb, bindex, d_inode(dentry))) {
+		if (force_wr && !(flags & O_WRONLY))
+			force_wr = 0;
+		flags = au_file_roflags(flags);
+		if (force_wr) {
+			h_file = ERR_PTR(-EROFS);
+			flags = au_file_roflags(flags);
+			if (unlikely(vfsub_native_ro(h_inode)
+				     || IS_APPEND(h_inode)))
+				goto out;
+			flags &= ~O_ACCMODE;
+			flags |= O_WRONLY;
+		}
+	}
+	flags &= ~O_CREAT;
+	atomic_inc(&br->br_count);
+	h_path.dentry = h_dentry;
+	h_path.mnt = au_br_mnt(br);
+	h_file = vfsub_dentry_open(&h_path, flags);
+	if (IS_ERR(h_file))
+		goto out_br;
+
+	if (flags & __FMODE_EXEC) {
+		err = deny_write_access(h_file);
+		if (unlikely(err)) {
+			fput(h_file);
+			h_file = ERR_PTR(err);
+			goto out_br;
+		}
+	}
+	fsnotify_open(h_file);
+	goto out; /* success */
+
+out_br:
+	atomic_dec(&br->br_count);
+out:
+	return h_file;
+}
+
+static int au_cmoo(struct dentry *dentry)
+{
+	int err, cmoo;
+	unsigned int udba;
+	struct path h_path;
+	struct au_pin pin;
+	struct au_cp_generic cpg = {
+		.dentry	= dentry,
+		.bdst	= -1,
+		.bsrc	= -1,
+		.len	= -1,
+		.pin	= &pin,
+		.flags	= AuCpup_DTIME | AuCpup_HOPEN
+	};
+	struct inode *delegated;
+	struct super_block *sb;
+	struct au_sbinfo *sbinfo;
+	struct au_fhsm *fhsm;
+	pid_t pid;
+	struct au_branch *br;
+	struct dentry *parent;
+	struct au_hinode *hdir;
+
+	DiMustWriteLock(dentry);
+	IiMustWriteLock(d_inode(dentry));
+
+	err = 0;
+	if (IS_ROOT(dentry))
+		goto out;
+	cpg.bsrc = au_dbstart(dentry);
+	if (!cpg.bsrc)
+		goto out;
+
+	sb = dentry->d_sb;
+	sbinfo = au_sbi(sb);
+	fhsm = &sbinfo->si_fhsm;
+	pid = au_fhsm_pid(fhsm);
+	if (pid
+	    && (current->pid == pid
+		|| current->real_parent->pid == pid))
+		goto out;
+
+	br = au_sbr(sb, cpg.bsrc);
+	cmoo = au_br_cmoo(br->br_perm);
+	if (!cmoo)
+		goto out;
+	if (!d_is_reg(dentry))
+		cmoo &= AuBrAttr_COO_ALL;
+	if (!cmoo)
+		goto out;
+
+	parent = dget_parent(dentry);
+	di_write_lock_parent(parent);
+	err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1);
+	cpg.bdst = err;
+	if (unlikely(err < 0)) {
+		err = 0;	/* there is no upper writable branch */
+		goto out_dgrade;
+	}
+	AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst);
+
+	/* do not respect the coo attrib for the target branch */
+	err = au_cpup_dirs(dentry, cpg.bdst);
+	if (unlikely(err))
+		goto out_dgrade;
+
+	di_downgrade_lock(parent, AuLock_IR);
+	udba = au_opt_udba(sb);
+	err = au_pin(&pin, dentry, cpg.bdst, udba,
+		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+	if (unlikely(err))
+		goto out_parent;
+
+	err = au_sio_cpup_simple(&cpg);
+	au_unpin(&pin);
+	if (unlikely(err))
+		goto out_parent;
+	if (!(cmoo & AuBrWAttr_MOO))
+		goto out_parent; /* success */
+
+	err = au_pin(&pin, dentry, cpg.bsrc, udba,
+		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+	if (unlikely(err))
+		goto out_parent;
+
+	h_path.mnt = au_br_mnt(br);
+	h_path.dentry = au_h_dptr(dentry, cpg.bsrc);
+	hdir = au_hi(d_inode(parent), cpg.bsrc);
+	delegated = NULL;
+	err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1);
+	au_unpin(&pin);
+	/* todo: keep h_dentry or not? */
+	if (unlikely(err == -EWOULDBLOCK)) {
+		pr_warn("cannot retry for NFSv4 delegation"
+			" for an internal unlink\n");
+		iput(delegated);
+	}
+	if (unlikely(err)) {
+		pr_err("unlink %pd after coo failed (%d), ignored\n",
+		       dentry, err);
+		err = 0;
+	}
+	goto out_parent; /* success */
+
+out_dgrade:
+	di_downgrade_lock(parent, AuLock_IR);
+out_parent:
+	di_read_unlock(parent, AuLock_IR);
+	dput(parent);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+int au_do_open(struct file *file, struct au_do_open_args *args)
+{
+	int err, no_lock = args->no_lock;
+	struct dentry *dentry;
+	struct au_finfo *finfo;
+
+	if (!no_lock)
+		err = au_finfo_init(file, args->fidir);
+	else {
+		lockdep_off();
+		err = au_finfo_init(file, args->fidir);
+		lockdep_on();
+	}
+	if (unlikely(err))
+		goto out;
+
+	dentry = file->f_path.dentry;
+	AuDebugOn(IS_ERR_OR_NULL(dentry));
+	if (!no_lock) {
+		di_write_lock_child(dentry);
+		err = au_cmoo(dentry);
+		di_downgrade_lock(dentry, AuLock_IR);
+		if (!err)
+			err = args->open(file, vfsub_file_flags(file), NULL);
+		di_read_unlock(dentry, AuLock_IR);
+	} else {
+		err = au_cmoo(dentry);
+		if (!err)
+			err = args->open(file, vfsub_file_flags(file),
+					 args->h_file);
+		if (!err && au_fbstart(file) != au_dbstart(dentry))
+			/*
+			 * cmoo happens after h_file was opened.
+			 * need to refresh file later.
+			 */
+			atomic_dec(&au_fi(file)->fi_generation);
+	}
+
+	finfo = au_fi(file);
+	if (!err) {
+		finfo->fi_file = file;
+		au_sphl_add(&finfo->fi_hlist,
+			    &au_sbi(file->f_path.dentry->d_sb)->si_files);
+	}
+	if (!no_lock)
+		fi_write_unlock(file);
+	else {
+		lockdep_off();
+		fi_write_unlock(file);
+		lockdep_on();
+	}
+	if (unlikely(err)) {
+		finfo->fi_hdir = NULL;
+		au_finfo_fin(file);
+	}
+
+out:
+	return err;
+}
+
+int au_reopen_nondir(struct file *file)
+{
+	int err;
+	aufs_bindex_t bstart;
+	struct dentry *dentry;
+	struct file *h_file, *h_file_tmp;
+
+	dentry = file->f_path.dentry;
+	bstart = au_dbstart(dentry);
+	h_file_tmp = NULL;
+	if (au_fbstart(file) == bstart) {
+		h_file = au_hf_top(file);
+		if (file->f_mode == h_file->f_mode)
+			return 0; /* success */
+		h_file_tmp = h_file;
+		get_file(h_file_tmp);
+		au_set_h_fptr(file, bstart, NULL);
+	}
+	AuDebugOn(au_fi(file)->fi_hdir);
+	/*
+	 * it can happen
+	 * file exists on both of rw and ro
+	 * open --> dbstart and fbstart are both 0
+	 * prepend a branch as rw, "rw" become ro
+	 * remove rw/file
+	 * delete the top branch, "rw" becomes rw again
+	 *	--> dbstart is 1, fbstart is still 0
+	 * write --> fbstart is 0 but dbstart is 1
+	 */
+	/* AuDebugOn(au_fbstart(file) < bstart); */
+
+	h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC,
+			   file, /*force_wr*/0);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file)) {
+		if (h_file_tmp) {
+			atomic_inc(&au_sbr(dentry->d_sb, bstart)->br_count);
+			au_set_h_fptr(file, bstart, h_file_tmp);
+			h_file_tmp = NULL;
+		}
+		goto out; /* todo: close all? */
+	}
+
+	err = 0;
+	au_set_fbstart(file, bstart);
+	au_set_h_fptr(file, bstart, h_file);
+	au_update_figen(file);
+	/* todo: necessary? */
+	/* file->f_ra = h_file->f_ra; */
+
+out:
+	if (h_file_tmp)
+		fput(h_file_tmp);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_reopen_wh(struct file *file, aufs_bindex_t btgt,
+			struct dentry *hi_wh)
+{
+	int err;
+	aufs_bindex_t bstart;
+	struct au_dinfo *dinfo;
+	struct dentry *h_dentry;
+	struct au_hdentry *hdp;
+
+	dinfo = au_di(file->f_path.dentry);
+	AuRwMustWriteLock(&dinfo->di_rwsem);
+
+	bstart = dinfo->di_bstart;
+	dinfo->di_bstart = btgt;
+	hdp = dinfo->di_hdentry;
+	h_dentry = hdp[0 + btgt].hd_dentry;
+	hdp[0 + btgt].hd_dentry = hi_wh;
+	err = au_reopen_nondir(file);
+	hdp[0 + btgt].hd_dentry = h_dentry;
+	dinfo->di_bstart = bstart;
+
+	return err;
+}
+
+static int au_ready_to_write_wh(struct file *file, loff_t len,
+				aufs_bindex_t bcpup, struct au_pin *pin)
+{
+	int err;
+	struct inode *inode, *h_inode;
+	struct dentry *h_dentry, *hi_wh;
+	struct au_cp_generic cpg = {
+		.dentry	= file->f_path.dentry,
+		.bdst	= bcpup,
+		.bsrc	= -1,
+		.len	= len,
+		.pin	= pin
+	};
+
+	au_update_dbstart(cpg.dentry);
+	inode = d_inode(cpg.dentry);
+	h_inode = NULL;
+	if (au_dbstart(cpg.dentry) <= bcpup
+	    && au_dbend(cpg.dentry) >= bcpup) {
+		h_dentry = au_h_dptr(cpg.dentry, bcpup);
+		if (h_dentry && d_is_positive(h_dentry))
+			h_inode = d_inode(h_dentry);
+	}
+	hi_wh = au_hi_wh(inode, bcpup);
+	if (!hi_wh && !h_inode)
+		err = au_sio_cpup_wh(&cpg, file);
+	else
+		/* already copied-up after unlink */
+		err = au_reopen_wh(file, bcpup, hi_wh);
+
+	if (!err
+	    && (inode->i_nlink > 1
+		|| (inode->i_state & I_LINKABLE))
+	    && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK))
+		au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup));
+
+	return err;
+}
+
+/*
+ * prepare the @file for writing.
+ */
+int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
+{
+	int err;
+	aufs_bindex_t dbstart;
+	struct dentry *parent;
+	struct inode *inode;
+	struct super_block *sb;
+	struct file *h_file;
+	struct au_cp_generic cpg = {
+		.dentry	= file->f_path.dentry,
+		.bdst	= -1,
+		.bsrc	= -1,
+		.len	= len,
+		.pin	= pin,
+		.flags	= AuCpup_DTIME
+	};
+
+	sb = cpg.dentry->d_sb;
+	inode = d_inode(cpg.dentry);
+	cpg.bsrc = au_fbstart(file);
+	err = au_test_ro(sb, cpg.bsrc, inode);
+	if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) {
+		err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE,
+			     /*flags*/0);
+		goto out;
+	}
+
+	/* need to cpup or reopen */
+	parent = dget_parent(cpg.dentry);
+	di_write_lock_parent(parent);
+	err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
+	cpg.bdst = err;
+	if (unlikely(err < 0))
+		goto out_dgrade;
+	err = 0;
+
+	if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) {
+		err = au_cpup_dirs(cpg.dentry, cpg.bdst);
+		if (unlikely(err))
+			goto out_dgrade;
+	}
+
+	err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
+		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+	if (unlikely(err))
+		goto out_dgrade;
+
+	dbstart = au_dbstart(cpg.dentry);
+	if (dbstart <= cpg.bdst)
+		cpg.bsrc = cpg.bdst;
+
+	if (dbstart <= cpg.bdst		/* just reopen */
+	    || !d_unhashed(cpg.dentry)	/* copyup and reopen */
+		) {
+		h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0);
+		if (IS_ERR(h_file))
+			err = PTR_ERR(h_file);
+		else {
+			di_downgrade_lock(parent, AuLock_IR);
+			if (dbstart > cpg.bdst)
+				err = au_sio_cpup_simple(&cpg);
+			if (!err)
+				err = au_reopen_nondir(file);
+			au_h_open_post(cpg.dentry, cpg.bsrc, h_file);
+		}
+	} else {			/* copyup as wh and reopen */
+		/*
+		 * since writable hfsplus branch is not supported,
+		 * h_open_pre/post() are unnecessary.
+		 */
+		err = au_ready_to_write_wh(file, len, cpg.bdst, pin);
+		di_downgrade_lock(parent, AuLock_IR);
+	}
+
+	if (!err) {
+		au_pin_set_parent_lflag(pin, /*lflag*/0);
+		goto out_dput; /* success */
+	}
+	au_unpin(pin);
+	goto out_unlock;
+
+out_dgrade:
+	di_downgrade_lock(parent, AuLock_IR);
+out_unlock:
+	di_read_unlock(parent, AuLock_IR);
+out_dput:
+	dput(parent);
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_do_flush(struct file *file, fl_owner_t id,
+		int (*flush)(struct file *file, fl_owner_t id))
+{
+	int err;
+	struct super_block *sb;
+	struct inode *inode;
+
+	inode = file_inode(file);
+	sb = inode->i_sb;
+	si_noflush_read_lock(sb);
+	fi_read_lock(file);
+	ii_read_lock_child(inode);
+
+	err = flush(file, id);
+	au_cpup_attr_timesizes(inode);
+
+	ii_read_unlock(inode);
+	fi_read_unlock(file);
+	si_read_unlock(sb);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
+{
+	int err;
+	struct au_pin pin;
+	struct au_finfo *finfo;
+	struct dentry *parent, *hi_wh;
+	struct inode *inode;
+	struct super_block *sb;
+	struct au_cp_generic cpg = {
+		.dentry	= file->f_path.dentry,
+		.bdst	= -1,
+		.bsrc	= -1,
+		.len	= -1,
+		.pin	= &pin,
+		.flags	= AuCpup_DTIME
+	};
+
+	FiMustWriteLock(file);
+
+	err = 0;
+	finfo = au_fi(file);
+	sb = cpg.dentry->d_sb;
+	inode = d_inode(cpg.dentry);
+	cpg.bdst = au_ibstart(inode);
+	if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry))
+		goto out;
+
+	parent = dget_parent(cpg.dentry);
+	if (au_test_ro(sb, cpg.bdst, inode)) {
+		di_read_lock_parent(parent, !AuLock_IR);
+		err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
+		cpg.bdst = err;
+		di_read_unlock(parent, !AuLock_IR);
+		if (unlikely(err < 0))
+			goto out_parent;
+		err = 0;
+	}
+
+	di_read_lock_parent(parent, AuLock_IR);
+	hi_wh = au_hi_wh(inode, cpg.bdst);
+	if (!S_ISDIR(inode->i_mode)
+	    && au_opt_test(au_mntflags(sb), PLINK)
+	    && au_plink_test(inode)
+	    && !d_unhashed(cpg.dentry)
+	    && cpg.bdst < au_dbstart(cpg.dentry)) {
+		err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst);
+		if (unlikely(err))
+			goto out_unlock;
+
+		/* always superio. */
+		err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
+			     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+		if (!err) {
+			err = au_sio_cpup_simple(&cpg);
+			au_unpin(&pin);
+		}
+	} else if (hi_wh) {
+		/* already copied-up after unlink */
+		err = au_reopen_wh(file, cpg.bdst, hi_wh);
+		*need_reopen = 0;
+	}
+
+out_unlock:
+	di_read_unlock(parent, AuLock_IR);
+out_parent:
+	dput(parent);
+out:
+	return err;
+}
+
+static void au_do_refresh_dir(struct file *file)
+{
+	aufs_bindex_t bindex, bend, new_bindex, brid;
+	struct au_hfile *p, tmp, *q;
+	struct au_finfo *finfo;
+	struct super_block *sb;
+	struct au_fidir *fidir;
+
+	FiMustWriteLock(file);
+
+	sb = file->f_path.dentry->d_sb;
+	finfo = au_fi(file);
+	fidir = finfo->fi_hdir;
+	AuDebugOn(!fidir);
+	p = fidir->fd_hfile + finfo->fi_btop;
+	brid = p->hf_br->br_id;
+	bend = fidir->fd_bbot;
+	for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) {
+		if (!p->hf_file)
+			continue;
+
+		new_bindex = au_br_index(sb, p->hf_br->br_id);
+		if (new_bindex == bindex)
+			continue;
+		if (new_bindex < 0) {
+			au_set_h_fptr(file, bindex, NULL);
+			continue;
+		}
+
+		/* swap two lower inode, and loop again */
+		q = fidir->fd_hfile + new_bindex;
+		tmp = *q;
+		*q = *p;
+		*p = tmp;
+		if (tmp.hf_file) {
+			bindex--;
+			p--;
+		}
+	}
+
+	p = fidir->fd_hfile;
+	if (!au_test_mmapped(file) && !d_unlinked(file->f_path.dentry)) {
+		bend = au_sbend(sb);
+		for (finfo->fi_btop = 0; finfo->fi_btop <= bend;
+		     finfo->fi_btop++, p++)
+			if (p->hf_file) {
+				if (file_inode(p->hf_file))
+					break;
+				au_hfput(p, file);
+			}
+	} else {
+		bend = au_br_index(sb, brid);
+		for (finfo->fi_btop = 0; finfo->fi_btop < bend;
+		     finfo->fi_btop++, p++)
+			if (p->hf_file)
+				au_hfput(p, file);
+		bend = au_sbend(sb);
+	}
+
+	p = fidir->fd_hfile + bend;
+	for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop;
+	     fidir->fd_bbot--, p--)
+		if (p->hf_file) {
+			if (file_inode(p->hf_file))
+				break;
+			au_hfput(p, file);
+		}
+	AuDebugOn(fidir->fd_bbot < finfo->fi_btop);
+}
+
+/*
+ * after branch manipulating, refresh the file.
+ */
+static int refresh_file(struct file *file, int (*reopen)(struct file *file))
+{
+	int err, need_reopen;
+	aufs_bindex_t bend, bindex;
+	struct dentry *dentry;
+	struct au_finfo *finfo;
+	struct au_hfile *hfile;
+
+	dentry = file->f_path.dentry;
+	finfo = au_fi(file);
+	if (!finfo->fi_hdir) {
+		hfile = &finfo->fi_htop;
+		AuDebugOn(!hfile->hf_file);
+		bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id);
+		AuDebugOn(bindex < 0);
+		if (bindex != finfo->fi_btop)
+			au_set_fbstart(file, bindex);
+	} else {
+		err = au_fidir_realloc(finfo, au_sbend(dentry->d_sb) + 1);
+		if (unlikely(err))
+			goto out;
+		au_do_refresh_dir(file);
+	}
+
+	err = 0;
+	need_reopen = 1;
+	if (!au_test_mmapped(file))
+		err = au_file_refresh_by_inode(file, &need_reopen);
+	if (!err && need_reopen && !d_unlinked(dentry))
+		err = reopen(file);
+	if (!err) {
+		au_update_figen(file);
+		goto out; /* success */
+	}
+
+	/* error, close all lower files */
+	if (finfo->fi_hdir) {
+		bend = au_fbend_dir(file);
+		for (bindex = au_fbstart(file); bindex <= bend; bindex++)
+			au_set_h_fptr(file, bindex, NULL);
+	}
+
+out:
+	return err;
+}
+
+/* common function to regular file and dir */
+int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
+			  int wlock)
+{
+	int err;
+	unsigned int sigen, figen;
+	aufs_bindex_t bstart;
+	unsigned char pseudo_link;
+	struct dentry *dentry;
+	struct inode *inode;
+
+	err = 0;
+	dentry = file->f_path.dentry;
+	inode = d_inode(dentry);
+	sigen = au_sigen(dentry->d_sb);
+	fi_write_lock(file);
+	figen = au_figen(file);
+	di_write_lock_child(dentry);
+	bstart = au_dbstart(dentry);
+	pseudo_link = (bstart != au_ibstart(inode));
+	if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) {
+		if (!wlock) {
+			di_downgrade_lock(dentry, AuLock_IR);
+			fi_downgrade_lock(file);
+		}
+		goto out; /* success */
+	}
+
+	AuDbg("sigen %d, figen %d\n", sigen, figen);
+	if (au_digen_test(dentry, sigen)) {
+		err = au_reval_dpath(dentry, sigen);
+		AuDebugOn(!err && au_digen_test(dentry, sigen));
+	}
+
+	if (!err)
+		err = refresh_file(file, reopen);
+	if (!err) {
+		if (!wlock) {
+			di_downgrade_lock(dentry, AuLock_IR);
+			fi_downgrade_lock(file);
+		}
+	} else {
+		di_write_unlock(dentry);
+		fi_write_unlock(file);
+	}
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* cf. aufs_nopage() */
+/* for madvise(2) */
+static int aufs_readpage(struct file *file __maybe_unused, struct page *page)
+{
+	unlock_page(page);
+	return 0;
+}
+
+/* it will never be called, but necessary to support O_DIRECT */
+static ssize_t aufs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
+			      loff_t offset)
+{ BUG(); return 0; }
+
+/* they will never be called. */
+#ifdef CONFIG_AUFS_DEBUG
+static int aufs_write_begin(struct file *file, struct address_space *mapping,
+			    loff_t pos, unsigned len, unsigned flags,
+			    struct page **pagep, void **fsdata)
+{ AuUnsupport(); return 0; }
+static int aufs_write_end(struct file *file, struct address_space *mapping,
+			  loff_t pos, unsigned len, unsigned copied,
+			  struct page *page, void *fsdata)
+{ AuUnsupport(); return 0; }
+static int aufs_writepage(struct page *page, struct writeback_control *wbc)
+{ AuUnsupport(); return 0; }
+
+static int aufs_set_page_dirty(struct page *page)
+{ AuUnsupport(); return 0; }
+static void aufs_invalidatepage(struct page *page, unsigned int offset,
+				unsigned int length)
+{ AuUnsupport(); }
+static int aufs_releasepage(struct page *page, gfp_t gfp)
+{ AuUnsupport(); return 0; }
+#if 0 /* called by memory compaction regardless file */
+static int aufs_migratepage(struct address_space *mapping, struct page *newpage,
+			    struct page *page, enum migrate_mode mode)
+{ AuUnsupport(); return 0; }
+#endif
+static int aufs_launder_page(struct page *page)
+{ AuUnsupport(); return 0; }
+static int aufs_is_partially_uptodate(struct page *page,
+				      unsigned long from,
+				      unsigned long count)
+{ AuUnsupport(); return 0; }
+static void aufs_is_dirty_writeback(struct page *page, bool *dirty,
+				    bool *writeback)
+{ AuUnsupport(); }
+static int aufs_error_remove_page(struct address_space *mapping,
+				  struct page *page)
+{ AuUnsupport(); return 0; }
+static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file,
+			      sector_t *span)
+{ AuUnsupport(); return 0; }
+static void aufs_swap_deactivate(struct file *file)
+{ AuUnsupport(); }
+#endif /* CONFIG_AUFS_DEBUG */
+
+const struct address_space_operations aufs_aop = {
+	.readpage		= aufs_readpage,
+	.direct_IO		= aufs_direct_IO,
+#ifdef CONFIG_AUFS_DEBUG
+	.writepage		= aufs_writepage,
+	/* no writepages, because of writepage */
+	.set_page_dirty		= aufs_set_page_dirty,
+	/* no readpages, because of readpage */
+	.write_begin		= aufs_write_begin,
+	.write_end		= aufs_write_end,
+	/* no bmap, no block device */
+	.invalidatepage		= aufs_invalidatepage,
+	.releasepage		= aufs_releasepage,
+	/* is fallback_migrate_page ok? */
+	/* .migratepage		= aufs_migratepage, */
+	.launder_page		= aufs_launder_page,
+	.is_partially_uptodate	= aufs_is_partially_uptodate,
+	.is_dirty_writeback	= aufs_is_dirty_writeback,
+	.error_remove_page	= aufs_error_remove_page,
+	.swap_activate		= aufs_swap_activate,
+	.swap_deactivate	= aufs_swap_deactivate
+#endif /* CONFIG_AUFS_DEBUG */
+};
--- linux-4.4.0.orig/fs/aufs/file.h
+++ linux-4.4.0/fs/aufs/file.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * file operations
+ */
+
+#ifndef __AUFS_FILE_H__
+#define __AUFS_FILE_H__
+
+#ifdef __KERNEL__
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include "rwsem.h"
+
+struct au_branch;
+struct au_hfile {
+	struct file		*hf_file;
+	struct au_branch	*hf_br;
+};
+
+struct au_vdir;
+struct au_fidir {
+	aufs_bindex_t		fd_bbot;
+	aufs_bindex_t		fd_nent;
+	struct au_vdir		*fd_vdir_cache;
+	struct au_hfile		fd_hfile[];
+};
+
+static inline int au_fidir_sz(int nent)
+{
+	AuDebugOn(nent < 0);
+	return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent;
+}
+
+struct au_finfo {
+	atomic_t		fi_generation;
+
+	struct au_rwsem		fi_rwsem;
+	aufs_bindex_t		fi_btop;
+
+	/* do not union them */
+	struct {				/* for non-dir */
+		struct au_hfile			fi_htop;
+		atomic_t			fi_mmapped;
+	};
+	struct au_fidir		*fi_hdir;	/* for dir only */
+
+	struct hlist_node	fi_hlist;
+	struct file		*fi_file;	/* very ugly */
+} ____cacheline_aligned_in_smp;
+
+/* ---------------------------------------------------------------------- */
+
+/* file.c */
+extern const struct address_space_operations aufs_aop;
+unsigned int au_file_roflags(unsigned int flags);
+struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
+		       struct file *file, int force_wr);
+struct au_do_open_args {
+	int		no_lock;
+	int		(*open)(struct file *file, int flags,
+				struct file *h_file);
+	struct au_fidir	*fidir;
+	struct file	*h_file;
+};
+int au_do_open(struct file *file, struct au_do_open_args *args);
+int au_reopen_nondir(struct file *file);
+struct au_pin;
+int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin);
+int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
+			  int wlock);
+int au_do_flush(struct file *file, fl_owner_t id,
+		int (*flush)(struct file *file, fl_owner_t id));
+
+/* poll.c */
+#ifdef CONFIG_AUFS_POLL
+unsigned int aufs_poll(struct file *file, poll_table *wait);
+#endif
+
+#ifdef CONFIG_AUFS_BR_HFSPLUS
+/* hfsplus.c */
+struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex,
+			   int force_wr);
+void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
+		    struct file *h_file);
+#else
+AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry,
+       aufs_bindex_t bindex, int force_wr)
+AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex,
+	   struct file *h_file);
+#endif
+
+/* f_op.c */
+extern const struct file_operations aufs_file_fop;
+int au_do_open_nondir(struct file *file, int flags, struct file *h_file);
+int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file);
+struct file *au_read_pre(struct file *file, int keep_fi);
+
+/* finfo.c */
+void au_hfput(struct au_hfile *hf, struct file *file);
+void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
+		   struct file *h_file);
+
+void au_update_figen(struct file *file);
+struct au_fidir *au_fidir_alloc(struct super_block *sb);
+int au_fidir_realloc(struct au_finfo *finfo, int nbr);
+
+void au_fi_init_once(void *_fi);
+void au_finfo_fin(struct file *file);
+int au_finfo_init(struct file *file, struct au_fidir *fidir);
+
+/* ioctl.c */
+long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
+			   unsigned long arg);
+long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
+			      unsigned long arg);
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct au_finfo *au_fi(struct file *file)
+{
+	return file->private_data;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * fi_read_lock, fi_write_lock,
+ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock
+ */
+AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem);
+
+#define FiMustNoWaiters(f)	AuRwMustNoWaiters(&au_fi(f)->fi_rwsem)
+#define FiMustAnyLock(f)	AuRwMustAnyLock(&au_fi(f)->fi_rwsem)
+#define FiMustWriteLock(f)	AuRwMustWriteLock(&au_fi(f)->fi_rwsem)
+
+/* ---------------------------------------------------------------------- */
+
+/* todo: hard/soft set? */
+static inline aufs_bindex_t au_fbstart(struct file *file)
+{
+	FiMustAnyLock(file);
+	return au_fi(file)->fi_btop;
+}
+
+static inline aufs_bindex_t au_fbend_dir(struct file *file)
+{
+	FiMustAnyLock(file);
+	AuDebugOn(!au_fi(file)->fi_hdir);
+	return au_fi(file)->fi_hdir->fd_bbot;
+}
+
+static inline struct au_vdir *au_fvdir_cache(struct file *file)
+{
+	FiMustAnyLock(file);
+	AuDebugOn(!au_fi(file)->fi_hdir);
+	return au_fi(file)->fi_hdir->fd_vdir_cache;
+}
+
+static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex)
+{
+	FiMustWriteLock(file);
+	au_fi(file)->fi_btop = bindex;
+}
+
+static inline void au_set_fbend_dir(struct file *file, aufs_bindex_t bindex)
+{
+	FiMustWriteLock(file);
+	AuDebugOn(!au_fi(file)->fi_hdir);
+	au_fi(file)->fi_hdir->fd_bbot = bindex;
+}
+
+static inline void au_set_fvdir_cache(struct file *file,
+				      struct au_vdir *vdir_cache)
+{
+	FiMustWriteLock(file);
+	AuDebugOn(!au_fi(file)->fi_hdir);
+	au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache;
+}
+
+static inline struct file *au_hf_top(struct file *file)
+{
+	FiMustAnyLock(file);
+	AuDebugOn(au_fi(file)->fi_hdir);
+	return au_fi(file)->fi_htop.hf_file;
+}
+
+static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex)
+{
+	FiMustAnyLock(file);
+	AuDebugOn(!au_fi(file)->fi_hdir);
+	return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file;
+}
+
+/* todo: memory barrier? */
+static inline unsigned int au_figen(struct file *f)
+{
+	return atomic_read(&au_fi(f)->fi_generation);
+}
+
+static inline void au_set_mmapped(struct file *f)
+{
+	if (atomic_inc_return(&au_fi(f)->fi_mmapped))
+		return;
+	pr_warn("fi_mmapped wrapped around\n");
+	while (!atomic_inc_return(&au_fi(f)->fi_mmapped))
+		;
+}
+
+static inline void au_unset_mmapped(struct file *f)
+{
+	atomic_dec(&au_fi(f)->fi_mmapped);
+}
+
+static inline int au_test_mmapped(struct file *f)
+{
+	return atomic_read(&au_fi(f)->fi_mmapped);
+}
+
+/* customize vma->vm_file */
+
+static inline void au_do_vm_file_reset(struct vm_area_struct *vma,
+				       struct file *file)
+{
+	struct file *f;
+
+	f = vma->vm_file;
+	get_file(file);
+	vma->vm_file = file;
+	fput(f);
+}
+
+#ifdef CONFIG_MMU
+#define AuDbgVmRegion(file, vma) do {} while (0)
+
+static inline void au_vm_file_reset(struct vm_area_struct *vma,
+				    struct file *file)
+{
+	au_do_vm_file_reset(vma, file);
+}
+#else
+#define AuDbgVmRegion(file, vma) \
+	AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file))
+
+static inline void au_vm_file_reset(struct vm_area_struct *vma,
+				    struct file *file)
+{
+	struct file *f;
+
+	au_do_vm_file_reset(vma, file);
+	f = vma->vm_region->vm_file;
+	get_file(file);
+	vma->vm_region->vm_file = file;
+	fput(f);
+}
+#endif /* CONFIG_MMU */
+
+/* handle vma->vm_prfile */
+static inline void au_vm_prfile_set(struct vm_area_struct *vma,
+				    struct file *file)
+{
+	get_file(file);
+	vma->vm_prfile = file;
+#ifndef CONFIG_MMU
+	get_file(file);
+	vma->vm_region->vm_prfile = file;
+#endif
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_FILE_H__ */
--- linux-4.4.0.orig/fs/aufs/finfo.c
+++ linux-4.4.0/fs/aufs/finfo.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * file private data
+ */
+
+#include "aufs.h"
+
+void au_hfput(struct au_hfile *hf, struct file *file)
+{
+	/* todo: direct access f_flags */
+	if (vfsub_file_flags(file) & __FMODE_EXEC)
+		allow_write_access(hf->hf_file);
+	fput(hf->hf_file);
+	hf->hf_file = NULL;
+	atomic_dec(&hf->hf_br->br_count);
+	hf->hf_br = NULL;
+}
+
+void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val)
+{
+	struct au_finfo *finfo = au_fi(file);
+	struct au_hfile *hf;
+	struct au_fidir *fidir;
+
+	fidir = finfo->fi_hdir;
+	if (!fidir) {
+		AuDebugOn(finfo->fi_btop != bindex);
+		hf = &finfo->fi_htop;
+	} else
+		hf = fidir->fd_hfile + bindex;
+
+	if (hf && hf->hf_file)
+		au_hfput(hf, file);
+	if (val) {
+		FiMustWriteLock(file);
+		AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry));
+		hf->hf_file = val;
+		hf->hf_br = au_sbr(file->f_path.dentry->d_sb, bindex);
+	}
+}
+
+void au_update_figen(struct file *file)
+{
+	atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_path.dentry));
+	/* smp_mb(); */ /* atomic_set */
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct au_fidir *au_fidir_alloc(struct super_block *sb)
+{
+	struct au_fidir *fidir;
+	int nbr;
+
+	nbr = au_sbend(sb) + 1;
+	if (nbr < 2)
+		nbr = 2; /* initial allocate for 2 branches */
+	fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS);
+	if (fidir) {
+		fidir->fd_bbot = -1;
+		fidir->fd_nent = nbr;
+	}
+
+	return fidir;
+}
+
+int au_fidir_realloc(struct au_finfo *finfo, int nbr)
+{
+	int err;
+	struct au_fidir *fidir, *p;
+
+	AuRwMustWriteLock(&finfo->fi_rwsem);
+	fidir = finfo->fi_hdir;
+	AuDebugOn(!fidir);
+
+	err = -ENOMEM;
+	p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr),
+			 GFP_NOFS);
+	if (p) {
+		p->fd_nent = nbr;
+		finfo->fi_hdir = p;
+		err = 0;
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void au_finfo_fin(struct file *file)
+{
+	struct au_finfo *finfo;
+
+	au_nfiles_dec(file->f_path.dentry->d_sb);
+
+	finfo = au_fi(file);
+	AuDebugOn(finfo->fi_hdir);
+	AuRwDestroy(&finfo->fi_rwsem);
+	au_cache_free_finfo(finfo);
+}
+
+void au_fi_init_once(void *_finfo)
+{
+	struct au_finfo *finfo = _finfo;
+	static struct lock_class_key aufs_fi;
+
+	au_rw_init(&finfo->fi_rwsem);
+	au_rw_class(&finfo->fi_rwsem, &aufs_fi);
+}
+
+int au_finfo_init(struct file *file, struct au_fidir *fidir)
+{
+	int err;
+	struct au_finfo *finfo;
+	struct dentry *dentry;
+
+	err = -ENOMEM;
+	dentry = file->f_path.dentry;
+	finfo = au_cache_alloc_finfo();
+	if (unlikely(!finfo))
+		goto out;
+
+	err = 0;
+	au_nfiles_inc(dentry->d_sb);
+	/* verbose coding for lock class name */
+	if (!fidir)
+		au_rw_class(&finfo->fi_rwsem, au_lc_key + AuLcNonDir_FIINFO);
+	else
+		au_rw_class(&finfo->fi_rwsem, au_lc_key + AuLcDir_FIINFO);
+	au_rw_write_lock(&finfo->fi_rwsem);
+	finfo->fi_btop = -1;
+	finfo->fi_hdir = fidir;
+	atomic_set(&finfo->fi_generation, au_digen(dentry));
+	/* smp_mb(); */ /* atomic_set */
+
+	file->private_data = finfo;
+
+out:
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/fstype.h
+++ linux-4.4.0/fs/aufs/fstype.h
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * judging filesystem type
+ */
+
+#ifndef __AUFS_FSTYPE_H__
+#define __AUFS_FSTYPE_H__
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+#include <linux/magic.h>
+#include <linux/nfs_fs.h>
+#include <linux/romfs_fs.h>
+
+static inline int au_test_aufs(struct super_block *sb)
+{
+	return sb->s_magic == AUFS_SUPER_MAGIC;
+}
+
+static inline const char *au_sbtype(struct super_block *sb)
+{
+	return sb->s_type->name;
+}
+
+static inline int au_test_iso9660(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE)
+	return sb->s_magic == ISOFS_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_romfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE)
+	return sb->s_magic == ROMFS_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_cramfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE)
+	return sb->s_magic == CRAMFS_MAGIC;
+#endif
+	return 0;
+}
+
+static inline int au_test_nfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE)
+	return sb->s_magic == NFS_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_fuse(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE)
+	return sb->s_magic == FUSE_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_xfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE)
+	return sb->s_magic == XFS_SB_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_tmpfs(struct super_block *sb __maybe_unused)
+{
+#ifdef CONFIG_TMPFS
+	return sb->s_magic == TMPFS_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE)
+	return !strcmp(au_sbtype(sb), "ecryptfs");
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_ramfs(struct super_block *sb)
+{
+	return sb->s_magic == RAMFS_MAGIC;
+}
+
+static inline int au_test_ubifs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE)
+	return sb->s_magic == UBIFS_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_procfs(struct super_block *sb __maybe_unused)
+{
+#ifdef CONFIG_PROC_FS
+	return sb->s_magic == PROC_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_sysfs(struct super_block *sb __maybe_unused)
+{
+#ifdef CONFIG_SYSFS
+	return sb->s_magic == SYSFS_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_configfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE)
+	return sb->s_magic == CONFIGFS_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_minix(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE)
+	return sb->s_magic == MINIX3_SUPER_MAGIC
+		|| sb->s_magic == MINIX2_SUPER_MAGIC
+		|| sb->s_magic == MINIX2_SUPER_MAGIC2
+		|| sb->s_magic == MINIX_SUPER_MAGIC
+		|| sb->s_magic == MINIX_SUPER_MAGIC2;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_fat(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE)
+	return sb->s_magic == MSDOS_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_msdos(struct super_block *sb)
+{
+	return au_test_fat(sb);
+}
+
+static inline int au_test_vfat(struct super_block *sb)
+{
+	return au_test_fat(sb);
+}
+
+static inline int au_test_securityfs(struct super_block *sb __maybe_unused)
+{
+#ifdef CONFIG_SECURITYFS
+	return sb->s_magic == SECURITYFS_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_squashfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE)
+	return sb->s_magic == SQUASHFS_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_btrfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE)
+	return sb->s_magic == BTRFS_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_xenfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE)
+	return sb->s_magic == XENFS_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_debugfs(struct super_block *sb __maybe_unused)
+{
+#ifdef CONFIG_DEBUG_FS
+	return sb->s_magic == DEBUGFS_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_nilfs(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE)
+	return sb->s_magic == NILFS_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+static inline int au_test_hfsplus(struct super_block *sb __maybe_unused)
+{
+#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE)
+	return sb->s_magic == HFSPLUS_SUPER_MAGIC;
+#else
+	return 0;
+#endif
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * they can't be an aufs branch.
+ */
+static inline int au_test_fs_unsuppoted(struct super_block *sb)
+{
+	return
+#ifndef CONFIG_AUFS_BR_RAMFS
+		au_test_ramfs(sb) ||
+#endif
+		au_test_procfs(sb)
+		|| au_test_sysfs(sb)
+		|| au_test_configfs(sb)
+		|| au_test_debugfs(sb)
+		|| au_test_securityfs(sb)
+		|| au_test_xenfs(sb)
+		|| au_test_ecryptfs(sb)
+		/* || !strcmp(au_sbtype(sb), "unionfs") */
+		|| au_test_aufs(sb); /* will be supported in next version */
+}
+
+static inline int au_test_fs_remote(struct super_block *sb)
+{
+	return !au_test_tmpfs(sb)
+#ifdef CONFIG_AUFS_BR_RAMFS
+		&& !au_test_ramfs(sb)
+#endif
+		&& !(sb->s_type->fs_flags & FS_REQUIRES_DEV);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Note: these functions (below) are created after reading ->getattr() in all
+ * filesystems under linux/fs. it means we have to do so in every update...
+ */
+
+/*
+ * some filesystems require getattr to refresh the inode attributes before
+ * referencing.
+ * in most cases, we can rely on the inode attribute in NFS (or every remote fs)
+ * and leave the work for d_revalidate()
+ */
+static inline int au_test_fs_refresh_iattr(struct super_block *sb)
+{
+	return au_test_nfs(sb)
+		|| au_test_fuse(sb)
+		/* || au_test_btrfs(sb) */	/* untested */
+		;
+}
+
+/*
+ * filesystems which don't maintain i_size or i_blocks.
+ */
+static inline int au_test_fs_bad_iattr_size(struct super_block *sb)
+{
+	return au_test_xfs(sb)
+		|| au_test_btrfs(sb)
+		|| au_test_ubifs(sb)
+		|| au_test_hfsplus(sb)	/* maintained, but incorrect */
+		/* || au_test_minix(sb) */	/* untested */
+		;
+}
+
+/*
+ * filesystems which don't store the correct value in some of their inode
+ * attributes.
+ */
+static inline int au_test_fs_bad_iattr(struct super_block *sb)
+{
+	return au_test_fs_bad_iattr_size(sb)
+		|| au_test_fat(sb)
+		|| au_test_msdos(sb)
+		|| au_test_vfat(sb);
+}
+
+/* they don't check i_nlink in link(2) */
+static inline int au_test_fs_no_limit_nlink(struct super_block *sb)
+{
+	return au_test_tmpfs(sb)
+#ifdef CONFIG_AUFS_BR_RAMFS
+		|| au_test_ramfs(sb)
+#endif
+		|| au_test_ubifs(sb)
+		|| au_test_hfsplus(sb);
+}
+
+/*
+ * filesystems which sets S_NOATIME and S_NOCMTIME.
+ */
+static inline int au_test_fs_notime(struct super_block *sb)
+{
+	return au_test_nfs(sb)
+		|| au_test_fuse(sb)
+		|| au_test_ubifs(sb)
+		;
+}
+
+/* temporary support for i#1 in cramfs */
+static inline int au_test_fs_unique_ino(struct inode *inode)
+{
+	if (au_test_cramfs(inode->i_sb))
+		return inode->i_ino != 1;
+	return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * the filesystem where the xino files placed must support i/o after unlink and
+ * maintain i_size and i_blocks.
+ */
+static inline int au_test_fs_bad_xino(struct super_block *sb)
+{
+	return au_test_fs_remote(sb)
+		|| au_test_fs_bad_iattr_size(sb)
+		/* don't want unnecessary work for xino */
+		|| au_test_aufs(sb)
+		|| au_test_ecryptfs(sb)
+		|| au_test_nilfs(sb);
+}
+
+static inline int au_test_fs_trunc_xino(struct super_block *sb)
+{
+	return au_test_tmpfs(sb)
+		|| au_test_ramfs(sb);
+}
+
+/*
+ * test if the @sb is real-readonly.
+ */
+static inline int au_test_fs_rr(struct super_block *sb)
+{
+	return au_test_squashfs(sb)
+		|| au_test_iso9660(sb)
+		|| au_test_cramfs(sb)
+		|| au_test_romfs(sb);
+}
+
+/*
+ * test if the @inode is nfs with 'noacl' option
+ * NFS always sets MS_POSIXACL regardless its mount option 'noacl.'
+ */
+static inline int au_test_nfs_noacl(struct inode *inode)
+{
+	return au_test_nfs(inode->i_sb)
+		/* && IS_POSIXACL(inode) */
+		&& !nfs_server_capable(inode, NFS_CAP_ACLS);
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_FSTYPE_H__ */
--- linux-4.4.0.orig/fs/aufs/hfsnotify.c
+++ linux-4.4.0/fs/aufs/hfsnotify.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * fsnotify for the lower directories
+ */
+
+#include "aufs.h"
+
+/* FS_IN_IGNORED is unnecessary */
+static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE
+				 | FS_CREATE | FS_EVENT_ON_CHILD);
+static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq);
+static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0);
+
+static void au_hfsn_free_mark(struct fsnotify_mark *mark)
+{
+	struct au_hnotify *hn = container_of(mark, struct au_hnotify,
+					     hn_mark);
+	AuDbg("here\n");
+	au_cache_free_hnotify(hn);
+	smp_mb__before_atomic();
+	if (atomic64_dec_and_test(&au_hfsn_ifree))
+		wake_up(&au_hfsn_wq);
+}
+
+static int au_hfsn_alloc(struct au_hinode *hinode)
+{
+	int err;
+	struct au_hnotify *hn;
+	struct super_block *sb;
+	struct au_branch *br;
+	struct fsnotify_mark *mark;
+	aufs_bindex_t bindex;
+
+	hn = hinode->hi_notify;
+	sb = hn->hn_aufs_inode->i_sb;
+	bindex = au_br_index(sb, hinode->hi_id);
+	br = au_sbr(sb, bindex);
+	AuDebugOn(!br->br_hfsn);
+
+	mark = &hn->hn_mark;
+	fsnotify_init_mark(mark, au_hfsn_free_mark);
+	mark->mask = AuHfsnMask;
+	/*
+	 * by udba rename or rmdir, aufs assign a new inode to the known
+	 * h_inode, so specify 1 to allow dups.
+	 */
+	lockdep_off();
+	err = fsnotify_add_mark(mark, br->br_hfsn->hfsn_group, hinode->hi_inode,
+				 /*mnt*/NULL, /*allow_dups*/1);
+	/* even if err */
+	fsnotify_put_mark(mark);
+	lockdep_on();
+
+	return err;
+}
+
+static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn)
+{
+	struct fsnotify_mark *mark;
+	unsigned long long ull;
+	struct fsnotify_group *group;
+
+	ull = atomic64_inc_return(&au_hfsn_ifree);
+	BUG_ON(!ull);
+
+	mark = &hn->hn_mark;
+	spin_lock(&mark->lock);
+	group = mark->group;
+	fsnotify_get_group(group);
+	spin_unlock(&mark->lock);
+	lockdep_off();
+	fsnotify_destroy_mark(mark, group);
+	fsnotify_put_group(group);
+	lockdep_on();
+
+	/* free hn by myself */
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void au_hfsn_ctl(struct au_hinode *hinode, int do_set)
+{
+	struct fsnotify_mark *mark;
+
+	mark = &hinode->hi_notify->hn_mark;
+	spin_lock(&mark->lock);
+	if (do_set) {
+		AuDebugOn(mark->mask & AuHfsnMask);
+		mark->mask |= AuHfsnMask;
+	} else {
+		AuDebugOn(!(mark->mask & AuHfsnMask));
+		mark->mask &= ~AuHfsnMask;
+	}
+	spin_unlock(&mark->lock);
+	/* fsnotify_recalc_inode_mask(hinode->hi_inode); */
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* #define AuDbgHnotify */
+#ifdef AuDbgHnotify
+static char *au_hfsn_name(u32 mask)
+{
+#ifdef CONFIG_AUFS_DEBUG
+#define test_ret(flag)				\
+	do {					\
+		if (mask & flag)		\
+			return #flag;		\
+	} while (0)
+	test_ret(FS_ACCESS);
+	test_ret(FS_MODIFY);
+	test_ret(FS_ATTRIB);
+	test_ret(FS_CLOSE_WRITE);
+	test_ret(FS_CLOSE_NOWRITE);
+	test_ret(FS_OPEN);
+	test_ret(FS_MOVED_FROM);
+	test_ret(FS_MOVED_TO);
+	test_ret(FS_CREATE);
+	test_ret(FS_DELETE);
+	test_ret(FS_DELETE_SELF);
+	test_ret(FS_MOVE_SELF);
+	test_ret(FS_UNMOUNT);
+	test_ret(FS_Q_OVERFLOW);
+	test_ret(FS_IN_IGNORED);
+	test_ret(FS_ISDIR);
+	test_ret(FS_IN_ONESHOT);
+	test_ret(FS_EVENT_ON_CHILD);
+	return "";
+#undef test_ret
+#else
+	return "??";
+#endif
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static void au_hfsn_free_group(struct fsnotify_group *group)
+{
+	struct au_br_hfsnotify *hfsn = group->private;
+
+	AuDbg("here\n");
+	kfree(hfsn);
+}
+
+static int au_hfsn_handle_event(struct fsnotify_group *group,
+				struct inode *inode,
+				struct fsnotify_mark *inode_mark,
+				struct fsnotify_mark *vfsmount_mark,
+				u32 mask, void *data, int data_type,
+				const unsigned char *file_name, u32 cookie)
+{
+	int err;
+	struct au_hnotify *hnotify;
+	struct inode *h_dir, *h_inode;
+	struct qstr h_child_qstr = QSTR_INIT(file_name, strlen(file_name));
+
+	AuDebugOn(data_type != FSNOTIFY_EVENT_INODE);
+
+	err = 0;
+	/* if FS_UNMOUNT happens, there must be another bug */
+	AuDebugOn(mask & FS_UNMOUNT);
+	if (mask & (FS_IN_IGNORED | FS_UNMOUNT))
+		goto out;
+
+	h_dir = inode;
+	h_inode = NULL;
+#ifdef AuDbgHnotify
+	au_debug_on();
+	if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1
+	    || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) {
+		AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n",
+		      h_dir->i_ino, mask, au_hfsn_name(mask),
+		      AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0);
+		/* WARN_ON(1); */
+	}
+	au_debug_off();
+#endif
+
+	AuDebugOn(!inode_mark);
+	hnotify = container_of(inode_mark, struct au_hnotify, hn_mark);
+	err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode);
+
+out:
+	return err;
+}
+
+static struct fsnotify_ops au_hfsn_ops = {
+	.handle_event		= au_hfsn_handle_event,
+	.free_group_priv	= au_hfsn_free_group
+};
+
+/* ---------------------------------------------------------------------- */
+
+static void au_hfsn_fin_br(struct au_branch *br)
+{
+	struct au_br_hfsnotify *hfsn;
+
+	hfsn = br->br_hfsn;
+	if (hfsn) {
+		lockdep_off();
+		fsnotify_put_group(hfsn->hfsn_group);
+		lockdep_on();
+	}
+}
+
+static int au_hfsn_init_br(struct au_branch *br, int perm)
+{
+	int err;
+	struct fsnotify_group *group;
+	struct au_br_hfsnotify *hfsn;
+
+	err = 0;
+	br->br_hfsn = NULL;
+	if (!au_br_hnotifyable(perm))
+		goto out;
+
+	err = -ENOMEM;
+	hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS);
+	if (unlikely(!hfsn))
+		goto out;
+
+	err = 0;
+	group = fsnotify_alloc_group(&au_hfsn_ops);
+	if (IS_ERR(group)) {
+		err = PTR_ERR(group);
+		pr_err("fsnotify_alloc_group() failed, %d\n", err);
+		goto out_hfsn;
+	}
+
+	group->private = hfsn;
+	hfsn->hfsn_group = group;
+	br->br_hfsn = hfsn;
+	goto out; /* success */
+
+out_hfsn:
+	kfree(hfsn);
+out:
+	return err;
+}
+
+static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm)
+{
+	int err;
+
+	err = 0;
+	if (!br->br_hfsn)
+		err = au_hfsn_init_br(br, perm);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void au_hfsn_fin(void)
+{
+	AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree));
+	wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree));
+}
+
+const struct au_hnotify_op au_hnotify_op = {
+	.ctl		= au_hfsn_ctl,
+	.alloc		= au_hfsn_alloc,
+	.free		= au_hfsn_free,
+
+	.fin		= au_hfsn_fin,
+
+	.reset_br	= au_hfsn_reset_br,
+	.fin_br		= au_hfsn_fin_br,
+	.init_br	= au_hfsn_init_br
+};
--- linux-4.4.0.orig/fs/aufs/hfsplus.c
+++ linux-4.4.0/fs/aufs/hfsplus.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * special support for filesystems which aqucires an inode mutex
+ * at final closing a file, eg, hfsplus.
+ *
+ * This trick is very simple and stupid, just to open the file before really
+ * neceeary open to tell hfsplus that this is not the final closing.
+ * The caller should call au_h_open_pre() after acquiring the inode mutex,
+ * and au_h_open_post() after releasing it.
+ */
+
+#include "aufs.h"
+
+struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex,
+			   int force_wr)
+{
+	struct file *h_file;
+	struct dentry *h_dentry;
+
+	h_dentry = au_h_dptr(dentry, bindex);
+	AuDebugOn(!h_dentry);
+	AuDebugOn(d_is_negative(h_dentry));
+
+	h_file = NULL;
+	if (au_test_hfsplus(h_dentry->d_sb)
+	    && d_is_reg(h_dentry))
+		h_file = au_h_open(dentry, bindex,
+				   O_RDONLY | O_NOATIME | O_LARGEFILE,
+				   /*file*/NULL, force_wr);
+	return h_file;
+}
+
+void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
+		    struct file *h_file)
+{
+	if (h_file) {
+		fput(h_file);
+		au_sbr_put(dentry->d_sb, bindex);
+	}
+}
--- linux-4.4.0.orig/fs/aufs/hnotify.c
+++ linux-4.4.0/fs/aufs/hnotify.c
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * abstraction to notify the direct changes on lower directories
+ */
+
+#include "aufs.h"
+
+int au_hn_alloc(struct au_hinode *hinode, struct inode *inode)
+{
+	int err;
+	struct au_hnotify *hn;
+
+	err = -ENOMEM;
+	hn = au_cache_alloc_hnotify();
+	if (hn) {
+		hn->hn_aufs_inode = inode;
+		hinode->hi_notify = hn;
+		err = au_hnotify_op.alloc(hinode);
+		AuTraceErr(err);
+		if (unlikely(err)) {
+			hinode->hi_notify = NULL;
+			au_cache_free_hnotify(hn);
+			/*
+			 * The upper dir was removed by udba, but the same named
+			 * dir left. In this case, aufs assignes a new inode
+			 * number and set the monitor again.
+			 * For the lower dir, the old monitnor is still left.
+			 */
+			if (err == -EEXIST)
+				err = 0;
+		}
+	}
+
+	AuTraceErr(err);
+	return err;
+}
+
+void au_hn_free(struct au_hinode *hinode)
+{
+	struct au_hnotify *hn;
+
+	hn = hinode->hi_notify;
+	if (hn) {
+		hinode->hi_notify = NULL;
+		if (au_hnotify_op.free(hinode, hn))
+			au_cache_free_hnotify(hn);
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+void au_hn_ctl(struct au_hinode *hinode, int do_set)
+{
+	if (hinode->hi_notify)
+		au_hnotify_op.ctl(hinode, do_set);
+}
+
+void au_hn_reset(struct inode *inode, unsigned int flags)
+{
+	aufs_bindex_t bindex, bend;
+	struct inode *hi;
+	struct dentry *iwhdentry;
+
+	bend = au_ibend(inode);
+	for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
+		hi = au_h_iptr(inode, bindex);
+		if (!hi)
+			continue;
+
+		/* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */
+		iwhdentry = au_hi_wh(inode, bindex);
+		if (iwhdentry)
+			dget(iwhdentry);
+		au_igrab(hi);
+		au_set_h_iptr(inode, bindex, NULL, 0);
+		au_set_h_iptr(inode, bindex, au_igrab(hi),
+			      flags & ~AuHi_XINO);
+		iput(hi);
+		dput(iwhdentry);
+		/* mutex_unlock(&hi->i_mutex); */
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int hn_xino(struct inode *inode, struct inode *h_inode)
+{
+	int err;
+	aufs_bindex_t bindex, bend, bfound, bstart;
+	struct inode *h_i;
+
+	err = 0;
+	if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
+		pr_warn("branch root dir was changed\n");
+		goto out;
+	}
+
+	bfound = -1;
+	bend = au_ibend(inode);
+	bstart = au_ibstart(inode);
+#if 0 /* reserved for future use */
+	if (bindex == bend) {
+		/* keep this ino in rename case */
+		goto out;
+	}
+#endif
+	for (bindex = bstart; bindex <= bend; bindex++)
+		if (au_h_iptr(inode, bindex) == h_inode) {
+			bfound = bindex;
+			break;
+		}
+	if (bfound < 0)
+		goto out;
+
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		h_i = au_h_iptr(inode, bindex);
+		if (!h_i)
+			continue;
+
+		err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0);
+		/* ignore this error */
+		/* bad action? */
+	}
+
+	/* children inode number will be broken */
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+static int hn_gen_tree(struct dentry *dentry)
+{
+	int err, i, j, ndentry;
+	struct au_dcsub_pages dpages;
+	struct au_dpage *dpage;
+	struct dentry **dentries;
+
+	err = au_dpages_init(&dpages, GFP_NOFS);
+	if (unlikely(err))
+		goto out;
+	err = au_dcsub_pages(&dpages, dentry, NULL, NULL);
+	if (unlikely(err))
+		goto out_dpages;
+
+	for (i = 0; i < dpages.ndpage; i++) {
+		dpage = dpages.dpages + i;
+		dentries = dpage->dentries;
+		ndentry = dpage->ndentry;
+		for (j = 0; j < ndentry; j++) {
+			struct dentry *d;
+
+			d = dentries[j];
+			if (IS_ROOT(d))
+				continue;
+
+			au_digen_dec(d);
+			if (d_really_is_positive(d))
+				/* todo: reset children xino?
+				   cached children only? */
+				au_iigen_dec(d_inode(d));
+		}
+	}
+
+out_dpages:
+	au_dpages_free(&dpages);
+
+#if 0
+	/* discard children */
+	dentry_unhash(dentry);
+	dput(dentry);
+#endif
+out:
+	return err;
+}
+
+/*
+ * return 0 if processed.
+ */
+static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
+			   const unsigned int isdir)
+{
+	int err;
+	struct dentry *d;
+	struct qstr *dname;
+
+	err = 1;
+	if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
+		pr_warn("branch root dir was changed\n");
+		err = 0;
+		goto out;
+	}
+
+	if (!isdir) {
+		AuDebugOn(!name);
+		au_iigen_dec(inode);
+		spin_lock(&inode->i_lock);
+		hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) {
+			spin_lock(&d->d_lock);
+			dname = &d->d_name;
+			if (dname->len != nlen
+			    && memcmp(dname->name, name, nlen)) {
+				spin_unlock(&d->d_lock);
+				continue;
+			}
+			err = 0;
+			au_digen_dec(d);
+			spin_unlock(&d->d_lock);
+			break;
+		}
+		spin_unlock(&inode->i_lock);
+	} else {
+		au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR);
+		d = d_find_any_alias(inode);
+		if (!d) {
+			au_iigen_dec(inode);
+			goto out;
+		}
+
+		spin_lock(&d->d_lock);
+		dname = &d->d_name;
+		if (dname->len == nlen && !memcmp(dname->name, name, nlen)) {
+			spin_unlock(&d->d_lock);
+			err = hn_gen_tree(d);
+			spin_lock(&d->d_lock);
+		}
+		spin_unlock(&d->d_lock);
+		dput(d);
+	}
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir)
+{
+	int err;
+
+	if (IS_ROOT(dentry)) {
+		pr_warn("branch root dir was changed\n");
+		return 0;
+	}
+
+	err = 0;
+	if (!isdir) {
+		au_digen_dec(dentry);
+		if (d_really_is_positive(dentry))
+			au_iigen_dec(d_inode(dentry));
+	} else {
+		au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR);
+		if (d_really_is_positive(dentry))
+			err = hn_gen_tree(dentry);
+	}
+
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* hnotify job flags */
+#define AuHnJob_XINO0		1
+#define AuHnJob_GEN		(1 << 1)
+#define AuHnJob_DIRENT		(1 << 2)
+#define AuHnJob_ISDIR		(1 << 3)
+#define AuHnJob_TRYXINO0	(1 << 4)
+#define AuHnJob_MNTPNT		(1 << 5)
+#define au_ftest_hnjob(flags, name)	((flags) & AuHnJob_##name)
+#define au_fset_hnjob(flags, name) \
+	do { (flags) |= AuHnJob_##name; } while (0)
+#define au_fclr_hnjob(flags, name) \
+	do { (flags) &= ~AuHnJob_##name; } while (0)
+
+enum {
+	AuHn_CHILD,
+	AuHn_PARENT,
+	AuHnLast
+};
+
+struct au_hnotify_args {
+	struct inode *h_dir, *dir, *h_child_inode;
+	u32 mask;
+	unsigned int flags[AuHnLast];
+	unsigned int h_child_nlen;
+	char h_child_name[];
+};
+
+struct hn_job_args {
+	unsigned int flags;
+	struct inode *inode, *h_inode, *dir, *h_dir;
+	struct dentry *dentry;
+	char *h_name;
+	int h_nlen;
+};
+
+static int hn_job(struct hn_job_args *a)
+{
+	const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR);
+	int e;
+
+	/* reset xino */
+	if (au_ftest_hnjob(a->flags, XINO0) && a->inode)
+		hn_xino(a->inode, a->h_inode); /* ignore this error */
+
+	if (au_ftest_hnjob(a->flags, TRYXINO0)
+	    && a->inode
+	    && a->h_inode) {
+		mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
+		if (!a->h_inode->i_nlink
+		    && !(a->h_inode->i_state & I_LINKABLE))
+			hn_xino(a->inode, a->h_inode); /* ignore this error */
+		mutex_unlock(&a->h_inode->i_mutex);
+	}
+
+	/* make the generation obsolete */
+	if (au_ftest_hnjob(a->flags, GEN)) {
+		e = -1;
+		if (a->inode)
+			e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode,
+					      isdir);
+		if (e && a->dentry)
+			hn_gen_by_name(a->dentry, isdir);
+		/* ignore this error */
+	}
+
+	/* make dir entries obsolete */
+	if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) {
+		struct au_vdir *vdir;
+
+		vdir = au_ivdir(a->inode);
+		if (vdir)
+			vdir->vd_jiffy = 0;
+		/* IMustLock(a->inode); */
+		/* a->inode->i_version++; */
+	}
+
+	/* can do nothing but warn */
+	if (au_ftest_hnjob(a->flags, MNTPNT)
+	    && a->dentry
+	    && d_mountpoint(a->dentry))
+		pr_warn("mount-point %pd is removed or renamed\n", a->dentry);
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen,
+					   struct inode *dir)
+{
+	struct dentry *dentry, *d, *parent;
+	struct qstr *dname;
+
+	parent = d_find_any_alias(dir);
+	if (!parent)
+		return NULL;
+
+	dentry = NULL;
+	spin_lock(&parent->d_lock);
+	list_for_each_entry(d, &parent->d_subdirs, d_child) {
+		/* AuDbg("%pd\n", d); */
+		spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
+		dname = &d->d_name;
+		if (dname->len != nlen || memcmp(dname->name, name, nlen))
+			goto cont_unlock;
+		if (au_di(d))
+			au_digen_dec(d);
+		else
+			goto cont_unlock;
+		if (au_dcount(d) > 0) {
+			dentry = dget_dlock(d);
+			spin_unlock(&d->d_lock);
+			break;
+		}
+
+cont_unlock:
+		spin_unlock(&d->d_lock);
+	}
+	spin_unlock(&parent->d_lock);
+	dput(parent);
+
+	if (dentry)
+		di_write_lock_child(dentry);
+
+	return dentry;
+}
+
+static struct inode *lookup_wlock_by_ino(struct super_block *sb,
+					 aufs_bindex_t bindex, ino_t h_ino)
+{
+	struct inode *inode;
+	ino_t ino;
+	int err;
+
+	inode = NULL;
+	err = au_xino_read(sb, bindex, h_ino, &ino);
+	if (!err && ino)
+		inode = ilookup(sb, ino);
+	if (!inode)
+		goto out;
+
+	if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
+		pr_warn("wrong root branch\n");
+		iput(inode);
+		inode = NULL;
+		goto out;
+	}
+
+	ii_write_lock_child(inode);
+
+out:
+	return inode;
+}
+
+static void au_hn_bh(void *_args)
+{
+	struct au_hnotify_args *a = _args;
+	struct super_block *sb;
+	aufs_bindex_t bindex, bend, bfound;
+	unsigned char xino, try_iput;
+	int err;
+	struct inode *inode;
+	ino_t h_ino;
+	struct hn_job_args args;
+	struct dentry *dentry;
+	struct au_sbinfo *sbinfo;
+
+	AuDebugOn(!_args);
+	AuDebugOn(!a->h_dir);
+	AuDebugOn(!a->dir);
+	AuDebugOn(!a->mask);
+	AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n",
+	      a->mask, a->dir->i_ino, a->h_dir->i_ino,
+	      a->h_child_inode ? a->h_child_inode->i_ino : 0);
+
+	inode = NULL;
+	dentry = NULL;
+	/*
+	 * do not lock a->dir->i_mutex here
+	 * because of d_revalidate() may cause a deadlock.
+	 */
+	sb = a->dir->i_sb;
+	AuDebugOn(!sb);
+	sbinfo = au_sbi(sb);
+	AuDebugOn(!sbinfo);
+	si_write_lock(sb, AuLock_NOPLMW);
+
+	ii_read_lock_parent(a->dir);
+	bfound = -1;
+	bend = au_ibend(a->dir);
+	for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++)
+		if (au_h_iptr(a->dir, bindex) == a->h_dir) {
+			bfound = bindex;
+			break;
+		}
+	ii_read_unlock(a->dir);
+	if (unlikely(bfound < 0))
+		goto out;
+
+	xino = !!au_opt_test(au_mntflags(sb), XINO);
+	h_ino = 0;
+	if (a->h_child_inode)
+		h_ino = a->h_child_inode->i_ino;
+
+	if (a->h_child_nlen
+	    && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN)
+		|| au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT)))
+		dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen,
+					      a->dir);
+	try_iput = 0;
+	if (dentry && d_really_is_positive(dentry))
+		inode = d_inode(dentry);
+	if (xino && !inode && h_ino
+	    && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0)
+		|| au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0)
+		|| au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) {
+		inode = lookup_wlock_by_ino(sb, bfound, h_ino);
+		try_iput = 1;
+	    }
+
+	args.flags = a->flags[AuHn_CHILD];
+	args.dentry = dentry;
+	args.inode = inode;
+	args.h_inode = a->h_child_inode;
+	args.dir = a->dir;
+	args.h_dir = a->h_dir;
+	args.h_name = a->h_child_name;
+	args.h_nlen = a->h_child_nlen;
+	err = hn_job(&args);
+	if (dentry) {
+		if (au_di(dentry))
+			di_write_unlock(dentry);
+		dput(dentry);
+	}
+	if (inode && try_iput) {
+		ii_write_unlock(inode);
+		iput(inode);
+	}
+
+	ii_write_lock_parent(a->dir);
+	args.flags = a->flags[AuHn_PARENT];
+	args.dentry = NULL;
+	args.inode = a->dir;
+	args.h_inode = a->h_dir;
+	args.dir = NULL;
+	args.h_dir = NULL;
+	args.h_name = NULL;
+	args.h_nlen = 0;
+	err = hn_job(&args);
+	ii_write_unlock(a->dir);
+
+out:
+	iput(a->h_child_inode);
+	iput(a->h_dir);
+	iput(a->dir);
+	si_write_unlock(sb);
+	au_nwt_done(&sbinfo->si_nowait);
+	kfree(a);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
+	       struct qstr *h_child_qstr, struct inode *h_child_inode)
+{
+	int err, len;
+	unsigned int flags[AuHnLast], f;
+	unsigned char isdir, isroot, wh;
+	struct inode *dir;
+	struct au_hnotify_args *args;
+	char *p, *h_child_name;
+
+	err = 0;
+	AuDebugOn(!hnotify || !hnotify->hn_aufs_inode);
+	dir = igrab(hnotify->hn_aufs_inode);
+	if (!dir)
+		goto out;
+
+	isroot = (dir->i_ino == AUFS_ROOT_INO);
+	wh = 0;
+	h_child_name = (void *)h_child_qstr->name;
+	len = h_child_qstr->len;
+	if (h_child_name) {
+		if (len > AUFS_WH_PFX_LEN
+		    && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
+			h_child_name += AUFS_WH_PFX_LEN;
+			len -= AUFS_WH_PFX_LEN;
+			wh = 1;
+		}
+	}
+
+	isdir = 0;
+	if (h_child_inode)
+		isdir = !!S_ISDIR(h_child_inode->i_mode);
+	flags[AuHn_PARENT] = AuHnJob_ISDIR;
+	flags[AuHn_CHILD] = 0;
+	if (isdir)
+		flags[AuHn_CHILD] = AuHnJob_ISDIR;
+	au_fset_hnjob(flags[AuHn_PARENT], DIRENT);
+	au_fset_hnjob(flags[AuHn_CHILD], GEN);
+	switch (mask & FS_EVENTS_POSS_ON_CHILD) {
+	case FS_MOVED_FROM:
+	case FS_MOVED_TO:
+		au_fset_hnjob(flags[AuHn_CHILD], XINO0);
+		au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
+		/*FALLTHROUGH*/
+	case FS_CREATE:
+		AuDebugOn(!h_child_name);
+		break;
+
+	case FS_DELETE:
+		/*
+		 * aufs never be able to get this child inode.
+		 * revalidation should be in d_revalidate()
+		 * by checking i_nlink, i_generation or d_unhashed().
+		 */
+		AuDebugOn(!h_child_name);
+		au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0);
+		au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
+		break;
+
+	default:
+		AuDebugOn(1);
+	}
+
+	if (wh)
+		h_child_inode = NULL;
+
+	err = -ENOMEM;
+	/* iput() and kfree() will be called in au_hnotify() */
+	args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS);
+	if (unlikely(!args)) {
+		AuErr1("no memory\n");
+		iput(dir);
+		goto out;
+	}
+	args->flags[AuHn_PARENT] = flags[AuHn_PARENT];
+	args->flags[AuHn_CHILD] = flags[AuHn_CHILD];
+	args->mask = mask;
+	args->dir = dir;
+	args->h_dir = igrab(h_dir);
+	if (h_child_inode)
+		h_child_inode = igrab(h_child_inode); /* can be NULL */
+	args->h_child_inode = h_child_inode;
+	args->h_child_nlen = len;
+	if (len) {
+		p = (void *)args;
+		p += sizeof(*args);
+		memcpy(p, h_child_name, len);
+		p[len] = 0;
+	}
+
+	/* NFS fires the event for silly-renamed one from kworker */
+	f = 0;
+	if (!dir->i_nlink
+	    || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE)))
+		f = AuWkq_NEST;
+	err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f);
+	if (unlikely(err)) {
+		pr_err("wkq %d\n", err);
+		iput(args->h_child_inode);
+		iput(args->h_dir);
+		iput(args->dir);
+		kfree(args);
+	}
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm)
+{
+	int err;
+
+	AuDebugOn(!(udba & AuOptMask_UDBA));
+
+	err = 0;
+	if (au_hnotify_op.reset_br)
+		err = au_hnotify_op.reset_br(udba, br, perm);
+
+	return err;
+}
+
+int au_hnotify_init_br(struct au_branch *br, int perm)
+{
+	int err;
+
+	err = 0;
+	if (au_hnotify_op.init_br)
+		err = au_hnotify_op.init_br(br, perm);
+
+	return err;
+}
+
+void au_hnotify_fin_br(struct au_branch *br)
+{
+	if (au_hnotify_op.fin_br)
+		au_hnotify_op.fin_br(br);
+}
+
+static void au_hn_destroy_cache(void)
+{
+	kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]);
+	au_cachep[AuCache_HNOTIFY] = NULL;
+}
+
+int __init au_hnotify_init(void)
+{
+	int err;
+
+	err = -ENOMEM;
+	au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify);
+	if (au_cachep[AuCache_HNOTIFY]) {
+		err = 0;
+		if (au_hnotify_op.init)
+			err = au_hnotify_op.init();
+		if (unlikely(err))
+			au_hn_destroy_cache();
+	}
+	AuTraceErr(err);
+	return err;
+}
+
+void au_hnotify_fin(void)
+{
+	if (au_hnotify_op.fin)
+		au_hnotify_op.fin();
+	/* cf. au_cache_fin() */
+	if (au_cachep[AuCache_HNOTIFY])
+		au_hn_destroy_cache();
+}
--- linux-4.4.0.orig/fs/aufs/i_op.c
+++ linux-4.4.0/fs/aufs/i_op.c
@@ -0,0 +1,1490 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * inode operations (except add/del/rename)
+ */
+
+#include <linux/device_cgroup.h>
+#include <linux/fs_stack.h>
+#include <linux/namei.h>
+#include <linux/security.h>
+#include "aufs.h"
+
+static int h_permission(struct inode *h_inode, int mask,
+			struct path *h_path, int brperm)
+{
+	int err;
+	const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
+
+	err = -EACCES;
+	if ((write_mask && IS_IMMUTABLE(h_inode))
+	    || ((mask & MAY_EXEC)
+		&& S_ISREG(h_inode->i_mode)
+		&& (path_noexec(h_path)
+		    || !(h_inode->i_mode & S_IXUGO))))
+		goto out;
+
+	/*
+	 * - skip the lower fs test in the case of write to ro branch.
+	 * - nfs dir permission write check is optimized, but a policy for
+	 *   link/rename requires a real check.
+	 * - nfs always sets MS_POSIXACL regardless its mount option 'noacl.'
+	 *   in this case, generic_permission() returns -EOPNOTSUPP.
+	 */
+	if ((write_mask && !au_br_writable(brperm))
+	    || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode)
+		&& write_mask && !(mask & MAY_READ))
+	    || !h_inode->i_op->permission) {
+		/* AuLabel(generic_permission); */
+		/* AuDbg("get_acl %pf\n", h_inode->i_op->get_acl); */
+		err = generic_permission(h_inode, mask);
+		if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode))
+			err = h_inode->i_op->permission(h_inode, mask);
+		AuTraceErr(err);
+	} else {
+		/* AuLabel(h_inode->permission); */
+		err = h_inode->i_op->permission(h_inode, mask);
+		AuTraceErr(err);
+	}
+
+	if (!err)
+		err = devcgroup_inode_permission(h_inode, mask);
+	if (!err)
+		err = security_inode_permission(h_inode, mask);
+
+#if 0
+	if (!err) {
+		/* todo: do we need to call ima_path_check()? */
+		struct path h_path = {
+			.dentry	=
+			.mnt	= h_mnt
+		};
+		err = ima_path_check(&h_path,
+				     mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
+				     IMA_COUNT_LEAVE);
+	}
+#endif
+
+out:
+	return err;
+}
+
+static int aufs_permission(struct inode *inode, int mask)
+{
+	int err;
+	aufs_bindex_t bindex, bend;
+	const unsigned char isdir = !!S_ISDIR(inode->i_mode),
+		write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
+	struct inode *h_inode;
+	struct super_block *sb;
+	struct au_branch *br;
+
+	/* todo: support rcu-walk? */
+	if (mask & MAY_NOT_BLOCK)
+		return -ECHILD;
+
+	sb = inode->i_sb;
+	si_read_lock(sb, AuLock_FLUSH);
+	ii_read_lock_child(inode);
+#if 0
+	err = au_iigen_test(inode, au_sigen(sb));
+	if (unlikely(err))
+		goto out;
+#endif
+
+	if (!isdir
+	    || write_mask
+	    || au_opt_test(au_mntflags(sb), DIRPERM1)) {
+		err = au_busy_or_stale();
+		h_inode = au_h_iptr(inode, au_ibstart(inode));
+		if (unlikely(!h_inode
+			     || (h_inode->i_mode & S_IFMT)
+			     != (inode->i_mode & S_IFMT)))
+			goto out;
+
+		err = 0;
+		bindex = au_ibstart(inode);
+		br = au_sbr(sb, bindex);
+		err = h_permission(h_inode, mask, &br->br_path, br->br_perm);
+		if (write_mask
+		    && !err
+		    && !special_file(h_inode->i_mode)) {
+			/* test whether the upper writable branch exists */
+			err = -EROFS;
+			for (; bindex >= 0; bindex--)
+				if (!au_br_rdonly(au_sbr(sb, bindex))) {
+					err = 0;
+					break;
+				}
+		}
+		goto out;
+	}
+
+	/* non-write to dir */
+	err = 0;
+	bend = au_ibend(inode);
+	for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) {
+		h_inode = au_h_iptr(inode, bindex);
+		if (h_inode) {
+			err = au_busy_or_stale();
+			if (unlikely(!S_ISDIR(h_inode->i_mode)))
+				break;
+
+			br = au_sbr(sb, bindex);
+			err = h_permission(h_inode, mask, &br->br_path,
+					   br->br_perm);
+		}
+	}
+
+out:
+	ii_read_unlock(inode);
+	si_read_unlock(sb);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry,
+				  unsigned int flags)
+{
+	struct dentry *ret, *parent;
+	struct inode *inode;
+	struct super_block *sb;
+	int err, npositive;
+
+	IMustLock(dir);
+
+	/* todo: support rcu-walk? */
+	ret = ERR_PTR(-ECHILD);
+	if (flags & LOOKUP_RCU)
+		goto out;
+
+	ret = ERR_PTR(-ENAMETOOLONG);
+	if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
+		goto out;
+
+	sb = dir->i_sb;
+	err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+	ret = ERR_PTR(err);
+	if (unlikely(err))
+		goto out;
+
+	err = au_di_init(dentry);
+	ret = ERR_PTR(err);
+	if (unlikely(err))
+		goto out_si;
+
+	inode = NULL;
+	npositive = 0; /* suppress a warning */
+	parent = dentry->d_parent; /* dir inode is locked */
+	di_read_lock_parent(parent, AuLock_IR);
+	err = au_alive_dir(parent);
+	if (!err)
+		err = au_digen_test(parent, au_sigen(sb));
+	if (!err) {
+		npositive = au_lkup_dentry(dentry, au_dbstart(parent),
+					   /*type*/0);
+		err = npositive;
+	}
+	di_read_unlock(parent, AuLock_IR);
+	ret = ERR_PTR(err);
+	if (unlikely(err < 0))
+		goto out_unlock;
+
+	if (npositive) {
+		inode = au_new_inode(dentry, /*must_new*/0);
+		if (IS_ERR(inode)) {
+			ret = (void *)inode;
+			inode = NULL;
+			goto out_unlock;
+		}
+	}
+
+	if (inode)
+		atomic_inc(&inode->i_count);
+	ret = d_splice_alias(inode, dentry);
+#if 0
+	if (unlikely(d_need_lookup(dentry))) {
+		spin_lock(&dentry->d_lock);
+		dentry->d_flags &= ~DCACHE_NEED_LOOKUP;
+		spin_unlock(&dentry->d_lock);
+	} else
+#endif
+	if (inode) {
+		if (!IS_ERR(ret)) {
+			iput(inode);
+			if (ret && ret != dentry)
+				ii_write_unlock(inode);
+		} else {
+			ii_write_unlock(inode);
+			iput(inode);
+			inode = NULL;
+		}
+	}
+
+out_unlock:
+	di_write_unlock(dentry);
+	if (inode) {
+		/* verbose coding for lock class name */
+		if (unlikely(S_ISLNK(inode->i_mode)))
+			au_rw_class(&au_di(dentry)->di_rwsem,
+				    au_lc_key + AuLcSymlink_DIINFO);
+		else if (unlikely(S_ISDIR(inode->i_mode)))
+			au_rw_class(&au_di(dentry)->di_rwsem,
+				    au_lc_key + AuLcDir_DIINFO);
+		else /* likely */
+			au_rw_class(&au_di(dentry)->di_rwsem,
+				    au_lc_key + AuLcNonDir_DIINFO);
+	}
+out_si:
+	si_read_unlock(sb);
+out:
+	return ret;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct aopen_node {
+	struct hlist_node hlist;
+	struct file *file, *h_file;
+};
+
+static int au_do_aopen(struct inode *inode, struct file *file)
+{
+	struct au_sphlhead *aopen;
+	struct aopen_node *node;
+	struct au_do_open_args args = {
+		.no_lock	= 1,
+		.open		= au_do_open_nondir
+	};
+
+	aopen = &au_sbi(inode->i_sb)->si_aopen;
+	spin_lock(&aopen->spin);
+	hlist_for_each_entry(node, &aopen->head, hlist)
+		if (node->file == file) {
+			args.h_file = node->h_file;
+			break;
+		}
+	spin_unlock(&aopen->spin);
+	/* AuDebugOn(!args.h_file); */
+
+	return au_do_open(file, &args);
+}
+
+static int aufs_atomic_open(struct inode *dir, struct dentry *dentry,
+			    struct file *file, unsigned int open_flag,
+			    umode_t create_mode, int *opened)
+{
+	int err, h_opened = *opened;
+	struct dentry *parent;
+	struct dentry *d;
+	struct au_sphlhead *aopen;
+	struct vfsub_aopen_args args = {
+		.open_flag	= open_flag,
+		.create_mode	= create_mode,
+		.opened		= &h_opened
+	};
+	struct aopen_node aopen_node = {
+		.file	= file
+	};
+
+	IMustLock(dir);
+	AuDbg("open_flag 0x%x\n", open_flag);
+	AuDbgDentry(dentry);
+
+	err = 0;
+	if (!au_di(dentry)) {
+		d = aufs_lookup(dir, dentry, /*flags*/0);
+		if (IS_ERR(d)) {
+			err = PTR_ERR(d);
+			goto out;
+		} else if (d) {
+			/*
+			 * obsoleted dentry found.
+			 * another error will be returned later.
+			 */
+			d_drop(d);
+			dput(d);
+			AuDbgDentry(d);
+		}
+		AuDbgDentry(dentry);
+	}
+
+	if (d_is_positive(dentry)
+	    || d_unhashed(dentry)
+	    || d_unlinked(dentry)
+	    || !(open_flag & O_CREAT))
+		goto out_no_open;
+
+	err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN);
+	if (unlikely(err))
+		goto out;
+
+	parent = dentry->d_parent;	/* dir is locked */
+	di_write_lock_parent(parent);
+	err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0);
+	if (unlikely(err))
+		goto out_unlock;
+
+	AuDbgDentry(dentry);
+	if (d_is_positive(dentry))
+		goto out_unlock;
+
+	args.file = get_empty_filp();
+	err = PTR_ERR(args.file);
+	if (IS_ERR(args.file))
+		goto out_unlock;
+
+	args.file->f_flags = file->f_flags;
+	err = au_aopen_or_create(dir, dentry, &args);
+	AuTraceErr(err);
+	AuDbgFile(args.file);
+	if (unlikely(err < 0)) {
+		if (h_opened & FILE_OPENED)
+			fput(args.file);
+		else
+			put_filp(args.file);
+		goto out_unlock;
+	}
+
+	/* some filesystems don't set FILE_CREATED while succeeded? */
+	*opened |= FILE_CREATED;
+	if (h_opened & FILE_OPENED)
+		aopen_node.h_file = args.file;
+	else {
+		put_filp(args.file);
+		args.file = NULL;
+	}
+	aopen = &au_sbi(dir->i_sb)->si_aopen;
+	au_sphl_add(&aopen_node.hlist, aopen);
+	err = finish_open(file, dentry, au_do_aopen, opened);
+	au_sphl_del(&aopen_node.hlist, aopen);
+	AuTraceErr(err);
+	AuDbgFile(file);
+	if (aopen_node.h_file)
+		fput(aopen_node.h_file);
+
+out_unlock:
+	di_write_unlock(parent);
+	aufs_read_unlock(dentry, AuLock_DW);
+	AuDbgDentry(dentry);
+	if (unlikely(err))
+		goto out;
+out_no_open:
+	if (!err && !(*opened & FILE_CREATED)) {
+		AuLabel(out_no_open);
+		dget(dentry);
+		err = finish_no_open(file, dentry);
+	}
+out:
+	AuDbg("%pd%s%s\n", dentry,
+	      (*opened & FILE_CREATED) ? " created" : "",
+	      (*opened & FILE_OPENED) ? " opened" : "");
+	AuTraceErr(err);
+	return err;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
+			  const unsigned char add_entry, aufs_bindex_t bcpup,
+			  aufs_bindex_t bstart)
+{
+	int err;
+	struct dentry *h_parent;
+	struct inode *h_dir;
+
+	if (add_entry)
+		IMustLock(d_inode(parent));
+	else
+		di_write_lock_parent(parent);
+
+	err = 0;
+	if (!au_h_dptr(parent, bcpup)) {
+		if (bstart > bcpup)
+			err = au_cpup_dirs(dentry, bcpup);
+		else if (bstart < bcpup)
+			err = au_cpdown_dirs(dentry, bcpup);
+		else
+			BUG();
+	}
+	if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) {
+		h_parent = au_h_dptr(parent, bcpup);
+		h_dir = d_inode(h_parent);
+		mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
+		err = au_lkup_neg(dentry, bcpup, /*wh*/0);
+		/* todo: no unlock here */
+		mutex_unlock(&h_dir->i_mutex);
+
+		AuDbg("bcpup %d\n", bcpup);
+		if (!err) {
+			if (d_really_is_negative(dentry))
+				au_set_h_dptr(dentry, bstart, NULL);
+			au_update_dbrange(dentry, /*do_put_zero*/0);
+		}
+	}
+
+	if (!add_entry)
+		di_write_unlock(parent);
+	if (!err)
+		err = bcpup; /* success */
+
+	AuTraceErr(err);
+	return err;
+}
+
+/*
+ * decide the branch and the parent dir where we will create a new entry.
+ * returns new bindex or an error.
+ * copyup the parent dir if needed.
+ */
+int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
+	      struct au_wr_dir_args *args)
+{
+	int err;
+	unsigned int flags;
+	aufs_bindex_t bcpup, bstart, src_bstart;
+	const unsigned char add_entry
+		= au_ftest_wrdir(args->flags, ADD_ENTRY)
+		| au_ftest_wrdir(args->flags, TMPFILE);
+	struct super_block *sb;
+	struct dentry *parent;
+	struct au_sbinfo *sbinfo;
+
+	sb = dentry->d_sb;
+	sbinfo = au_sbi(sb);
+	parent = dget_parent(dentry);
+	bstart = au_dbstart(dentry);
+	bcpup = bstart;
+	if (args->force_btgt < 0) {
+		if (src_dentry) {
+			src_bstart = au_dbstart(src_dentry);
+			if (src_bstart < bstart)
+				bcpup = src_bstart;
+		} else if (add_entry) {
+			flags = 0;
+			if (au_ftest_wrdir(args->flags, ISDIR))
+				au_fset_wbr(flags, DIR);
+			err = AuWbrCreate(sbinfo, dentry, flags);
+			bcpup = err;
+		}
+
+		if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) {
+			if (add_entry)
+				err = AuWbrCopyup(sbinfo, dentry);
+			else {
+				if (!IS_ROOT(dentry)) {
+					di_read_lock_parent(parent, !AuLock_IR);
+					err = AuWbrCopyup(sbinfo, dentry);
+					di_read_unlock(parent, !AuLock_IR);
+				} else
+					err = AuWbrCopyup(sbinfo, dentry);
+			}
+			bcpup = err;
+			if (unlikely(err < 0))
+				goto out;
+		}
+	} else {
+		bcpup = args->force_btgt;
+		AuDebugOn(au_test_ro(sb, bcpup, d_inode(dentry)));
+	}
+
+	AuDbg("bstart %d, bcpup %d\n", bstart, bcpup);
+	err = bcpup;
+	if (bcpup == bstart)
+		goto out; /* success */
+
+	/* copyup the new parent into the branch we process */
+	err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart);
+	if (err >= 0) {
+		if (d_really_is_negative(dentry)) {
+			au_set_h_dptr(dentry, bstart, NULL);
+			au_set_dbstart(dentry, bcpup);
+			au_set_dbend(dentry, bcpup);
+		}
+		AuDebugOn(add_entry
+			  && !au_ftest_wrdir(args->flags, TMPFILE)
+			  && !au_h_dptr(dentry, bcpup));
+	}
+
+out:
+	dput(parent);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void au_pin_hdir_unlock(struct au_pin *p)
+{
+	if (p->hdir)
+		au_hn_imtx_unlock(p->hdir);
+}
+
+int au_pin_hdir_lock(struct au_pin *p)
+{
+	int err;
+
+	err = 0;
+	if (!p->hdir)
+		goto out;
+
+	/* even if an error happens later, keep this lock */
+	au_hn_imtx_lock_nested(p->hdir, p->lsc_hi);
+
+	err = -EBUSY;
+	if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent)))
+		goto out;
+
+	err = 0;
+	if (p->h_dentry)
+		err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode,
+				  p->h_parent, p->br);
+
+out:
+	return err;
+}
+
+int au_pin_hdir_relock(struct au_pin *p)
+{
+	int err, i;
+	struct inode *h_i;
+	struct dentry *h_d[] = {
+		p->h_dentry,
+		p->h_parent
+	};
+
+	err = au_pin_hdir_lock(p);
+	if (unlikely(err))
+		goto out;
+
+	for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) {
+		if (!h_d[i])
+			continue;
+		if (d_is_positive(h_d[i])) {
+			h_i = d_inode(h_d[i]);
+			err = !h_i->i_nlink;
+		}
+	}
+
+out:
+	return err;
+}
+
+void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task)
+{
+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
+	p->hdir->hi_inode->i_mutex.owner = task;
+#endif
+}
+
+void au_pin_hdir_acquire_nest(struct au_pin *p)
+{
+	if (p->hdir) {
+		mutex_acquire_nest(&p->hdir->hi_inode->i_mutex.dep_map,
+				   p->lsc_hi, 0, NULL, _RET_IP_);
+		au_pin_hdir_set_owner(p, current);
+	}
+}
+
+void au_pin_hdir_release(struct au_pin *p)
+{
+	if (p->hdir) {
+		au_pin_hdir_set_owner(p, p->task);
+		mutex_release(&p->hdir->hi_inode->i_mutex.dep_map, 1, _RET_IP_);
+	}
+}
+
+struct dentry *au_pinned_h_parent(struct au_pin *pin)
+{
+	if (pin && pin->parent)
+		return au_h_dptr(pin->parent, pin->bindex);
+	return NULL;
+}
+
+void au_unpin(struct au_pin *p)
+{
+	if (p->hdir)
+		au_pin_hdir_unlock(p);
+	if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE))
+		vfsub_mnt_drop_write(p->h_mnt);
+	if (!p->hdir)
+		return;
+
+	if (!au_ftest_pin(p->flags, DI_LOCKED))
+		di_read_unlock(p->parent, AuLock_IR);
+	iput(p->hdir->hi_inode);
+	dput(p->parent);
+	p->parent = NULL;
+	p->hdir = NULL;
+	p->h_mnt = NULL;
+	/* do not clear p->task */
+}
+
+int au_do_pin(struct au_pin *p)
+{
+	int err;
+	struct super_block *sb;
+	struct inode *h_dir;
+
+	err = 0;
+	sb = p->dentry->d_sb;
+	p->br = au_sbr(sb, p->bindex);
+	if (IS_ROOT(p->dentry)) {
+		if (au_ftest_pin(p->flags, MNT_WRITE)) {
+			p->h_mnt = au_br_mnt(p->br);
+			err = vfsub_mnt_want_write(p->h_mnt);
+			if (unlikely(err)) {
+				au_fclr_pin(p->flags, MNT_WRITE);
+				goto out_err;
+			}
+		}
+		goto out;
+	}
+
+	p->h_dentry = NULL;
+	if (p->bindex <= au_dbend(p->dentry))
+		p->h_dentry = au_h_dptr(p->dentry, p->bindex);
+
+	p->parent = dget_parent(p->dentry);
+	if (!au_ftest_pin(p->flags, DI_LOCKED))
+		di_read_lock(p->parent, AuLock_IR, p->lsc_di);
+
+	h_dir = NULL;
+	p->h_parent = au_h_dptr(p->parent, p->bindex);
+	p->hdir = au_hi(d_inode(p->parent), p->bindex);
+	if (p->hdir)
+		h_dir = p->hdir->hi_inode;
+
+	/*
+	 * udba case, or
+	 * if DI_LOCKED is not set, then p->parent may be different
+	 * and h_parent can be NULL.
+	 */
+	if (unlikely(!p->hdir || !h_dir || !p->h_parent)) {
+		err = -EBUSY;
+		if (!au_ftest_pin(p->flags, DI_LOCKED))
+			di_read_unlock(p->parent, AuLock_IR);
+		dput(p->parent);
+		p->parent = NULL;
+		goto out_err;
+	}
+
+	if (au_ftest_pin(p->flags, MNT_WRITE)) {
+		p->h_mnt = au_br_mnt(p->br);
+		err = vfsub_mnt_want_write(p->h_mnt);
+		if (unlikely(err)) {
+			au_fclr_pin(p->flags, MNT_WRITE);
+			if (!au_ftest_pin(p->flags, DI_LOCKED))
+				di_read_unlock(p->parent, AuLock_IR);
+			dput(p->parent);
+			p->parent = NULL;
+			goto out_err;
+		}
+	}
+
+	au_igrab(h_dir);
+	err = au_pin_hdir_lock(p);
+	if (!err)
+		goto out; /* success */
+
+	au_unpin(p);
+
+out_err:
+	pr_err("err %d\n", err);
+	err = au_busy_or_stale();
+out:
+	return err;
+}
+
+void au_pin_init(struct au_pin *p, struct dentry *dentry,
+		 aufs_bindex_t bindex, int lsc_di, int lsc_hi,
+		 unsigned int udba, unsigned char flags)
+{
+	p->dentry = dentry;
+	p->udba = udba;
+	p->lsc_di = lsc_di;
+	p->lsc_hi = lsc_hi;
+	p->flags = flags;
+	p->bindex = bindex;
+
+	p->parent = NULL;
+	p->hdir = NULL;
+	p->h_mnt = NULL;
+
+	p->h_dentry = NULL;
+	p->h_parent = NULL;
+	p->br = NULL;
+	p->task = current;
+}
+
+int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
+	   unsigned int udba, unsigned char flags)
+{
+	au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2,
+		    udba, flags);
+	return au_do_pin(pin);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * ->setattr() and ->getattr() are called in various cases.
+ * chmod, stat: dentry is revalidated.
+ * fchmod, fstat: file and dentry are not revalidated, additionally they may be
+ *		  unhashed.
+ * for ->setattr(), ia->ia_file is passed from ftruncate only.
+ */
+/* todo: consolidate with do_refresh() and simple_reval_dpath() */
+int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
+{
+	int err;
+	struct dentry *parent;
+
+	err = 0;
+	if (au_digen_test(dentry, sigen)) {
+		parent = dget_parent(dentry);
+		di_read_lock_parent(parent, AuLock_IR);
+		err = au_refresh_dentry(dentry, parent);
+		di_read_unlock(parent, AuLock_IR);
+		dput(parent);
+	}
+
+	AuTraceErr(err);
+	return err;
+}
+
+int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
+		     struct au_icpup_args *a)
+{
+	int err;
+	loff_t sz;
+	aufs_bindex_t bstart, ibstart;
+	struct dentry *hi_wh, *parent;
+	struct inode *inode;
+	struct au_wr_dir_args wr_dir_args = {
+		.force_btgt	= -1,
+		.flags		= 0
+	};
+
+	if (d_is_dir(dentry))
+		au_fset_wrdir(wr_dir_args.flags, ISDIR);
+	/* plink or hi_wh() case */
+	bstart = au_dbstart(dentry);
+	inode = d_inode(dentry);
+	ibstart = au_ibstart(inode);
+	if (bstart != ibstart && !au_test_ro(inode->i_sb, ibstart, inode))
+		wr_dir_args.force_btgt = ibstart;
+	err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
+	if (unlikely(err < 0))
+		goto out;
+	a->btgt = err;
+	if (err != bstart)
+		au_fset_icpup(a->flags, DID_CPUP);
+
+	err = 0;
+	a->pin_flags = AuPin_MNT_WRITE;
+	parent = NULL;
+	if (!IS_ROOT(dentry)) {
+		au_fset_pin(a->pin_flags, DI_LOCKED);
+		parent = dget_parent(dentry);
+		di_write_lock_parent(parent);
+	}
+
+	err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags);
+	if (unlikely(err))
+		goto out_parent;
+
+	a->h_path.dentry = au_h_dptr(dentry, bstart);
+	sz = -1;
+	a->h_inode = d_inode(a->h_path.dentry);
+	if (ia && (ia->ia_valid & ATTR_SIZE)) {
+		mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
+		if (ia->ia_size < i_size_read(a->h_inode))
+			sz = ia->ia_size;
+		mutex_unlock(&a->h_inode->i_mutex);
+	}
+
+	hi_wh = NULL;
+	if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) {
+		hi_wh = au_hi_wh(inode, a->btgt);
+		if (!hi_wh) {
+			struct au_cp_generic cpg = {
+				.dentry	= dentry,
+				.bdst	= a->btgt,
+				.bsrc	= -1,
+				.len	= sz,
+				.pin	= &a->pin
+			};
+			err = au_sio_cpup_wh(&cpg, /*file*/NULL);
+			if (unlikely(err))
+				goto out_unlock;
+			hi_wh = au_hi_wh(inode, a->btgt);
+			/* todo: revalidate hi_wh? */
+		}
+	}
+
+	if (parent) {
+		au_pin_set_parent_lflag(&a->pin, /*lflag*/0);
+		di_downgrade_lock(parent, AuLock_IR);
+		dput(parent);
+		parent = NULL;
+	}
+	if (!au_ftest_icpup(a->flags, DID_CPUP))
+		goto out; /* success */
+
+	if (!d_unhashed(dentry)) {
+		struct au_cp_generic cpg = {
+			.dentry	= dentry,
+			.bdst	= a->btgt,
+			.bsrc	= bstart,
+			.len	= sz,
+			.pin	= &a->pin,
+			.flags	= AuCpup_DTIME | AuCpup_HOPEN
+		};
+		err = au_sio_cpup_simple(&cpg);
+		if (!err)
+			a->h_path.dentry = au_h_dptr(dentry, a->btgt);
+	} else if (!hi_wh)
+		a->h_path.dentry = au_h_dptr(dentry, a->btgt);
+	else
+		a->h_path.dentry = hi_wh; /* do not dget here */
+
+out_unlock:
+	a->h_inode = d_inode(a->h_path.dentry);
+	if (!err)
+		goto out; /* success */
+	au_unpin(&a->pin);
+out_parent:
+	if (parent) {
+		di_write_unlock(parent);
+		dput(parent);
+	}
+out:
+	if (!err)
+		mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
+	return err;
+}
+
+static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
+{
+	int err;
+	struct inode *inode, *delegated;
+	struct super_block *sb;
+	struct file *file;
+	struct au_icpup_args *a;
+
+	inode = d_inode(dentry);
+	IMustLock(inode);
+
+	err = -ENOMEM;
+	a = kzalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+
+	if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
+		ia->ia_valid &= ~ATTR_MODE;
+
+	file = NULL;
+	sb = dentry->d_sb;
+	err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+	if (unlikely(err))
+		goto out_kfree;
+
+	if (ia->ia_valid & ATTR_FILE) {
+		/* currently ftruncate(2) only */
+		AuDebugOn(!d_is_reg(dentry));
+		file = ia->ia_file;
+		err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+		if (unlikely(err))
+			goto out_si;
+		ia->ia_file = au_hf_top(file);
+		a->udba = AuOpt_UDBA_NONE;
+	} else {
+		/* fchmod() doesn't pass ia_file */
+		a->udba = au_opt_udba(sb);
+		di_write_lock_child(dentry);
+		/* no d_unlinked(), to set UDBA_NONE for root */
+		if (d_unhashed(dentry))
+			a->udba = AuOpt_UDBA_NONE;
+		if (a->udba != AuOpt_UDBA_NONE) {
+			AuDebugOn(IS_ROOT(dentry));
+			err = au_reval_for_attr(dentry, au_sigen(sb));
+			if (unlikely(err))
+				goto out_dentry;
+		}
+	}
+
+	err = au_pin_and_icpup(dentry, ia, a);
+	if (unlikely(err < 0))
+		goto out_dentry;
+	if (au_ftest_icpup(a->flags, DID_CPUP)) {
+		ia->ia_file = NULL;
+		ia->ia_valid &= ~ATTR_FILE;
+	}
+
+	a->h_path.mnt = au_sbr_mnt(sb, a->btgt);
+	if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME))
+	    == (ATTR_MODE | ATTR_CTIME)) {
+		err = security_path_chmod(&a->h_path, ia->ia_mode);
+		if (unlikely(err))
+			goto out_unlock;
+	} else if ((ia->ia_valid & (ATTR_UID | ATTR_GID))
+		   && (ia->ia_valid & ATTR_CTIME)) {
+		err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid);
+		if (unlikely(err))
+			goto out_unlock;
+	}
+
+	if (ia->ia_valid & ATTR_SIZE) {
+		struct file *f;
+
+		if (ia->ia_size < i_size_read(inode))
+			/* unmap only */
+			truncate_setsize(inode, ia->ia_size);
+
+		f = NULL;
+		if (ia->ia_valid & ATTR_FILE)
+			f = ia->ia_file;
+		mutex_unlock(&a->h_inode->i_mutex);
+		err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f);
+		mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
+	} else {
+		delegated = NULL;
+		while (1) {
+			err = vfsub_notify_change(&a->h_path, ia, &delegated);
+			if (delegated) {
+				err = break_deleg_wait(&delegated);
+				if (!err)
+					continue;
+			}
+			break;
+		}
+	}
+	/*
+	 * regardless aufs 'acl' option setting.
+	 * why don't all acl-aware fs call this func from their ->setattr()?
+	 */
+	if (!err && (ia->ia_valid & ATTR_MODE))
+		err = vfsub_acl_chmod(a->h_inode, ia->ia_mode);
+	if (!err)
+		au_cpup_attr_changeable(inode);
+
+out_unlock:
+	mutex_unlock(&a->h_inode->i_mutex);
+	au_unpin(&a->pin);
+	if (unlikely(err))
+		au_update_dbstart(dentry);
+out_dentry:
+	di_write_unlock(dentry);
+	if (file) {
+		fi_write_unlock(file);
+		ia->ia_file = file;
+		ia->ia_valid |= ATTR_FILE;
+	}
+out_si:
+	si_read_unlock(sb);
+out_kfree:
+	kfree(a);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL)
+static int au_h_path_to_set_attr(struct dentry *dentry,
+				 struct au_icpup_args *a, struct path *h_path)
+{
+	int err;
+	struct super_block *sb;
+
+	sb = dentry->d_sb;
+	a->udba = au_opt_udba(sb);
+	/* no d_unlinked(), to set UDBA_NONE for root */
+	if (d_unhashed(dentry))
+		a->udba = AuOpt_UDBA_NONE;
+	if (a->udba != AuOpt_UDBA_NONE) {
+		AuDebugOn(IS_ROOT(dentry));
+		err = au_reval_for_attr(dentry, au_sigen(sb));
+		if (unlikely(err))
+			goto out;
+	}
+	err = au_pin_and_icpup(dentry, /*ia*/NULL, a);
+	if (unlikely(err < 0))
+		goto out;
+
+	h_path->dentry = a->h_path.dentry;
+	h_path->mnt = au_sbr_mnt(sb, a->btgt);
+
+out:
+	return err;
+}
+
+ssize_t au_srxattr(struct dentry *dentry, struct au_srxattr *arg)
+{
+	int err;
+	struct path h_path;
+	struct super_block *sb;
+	struct au_icpup_args *a;
+	struct inode *inode, *h_inode;
+
+	inode = d_inode(dentry);
+	IMustLock(inode);
+
+	err = -ENOMEM;
+	a = kzalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+
+	sb = dentry->d_sb;
+	err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+	if (unlikely(err))
+		goto out_kfree;
+
+	h_path.dentry = NULL;	/* silence gcc */
+	di_write_lock_child(dentry);
+	err = au_h_path_to_set_attr(dentry, a, &h_path);
+	if (unlikely(err))
+		goto out_di;
+
+	mutex_unlock(&a->h_inode->i_mutex);
+	switch (arg->type) {
+	case AU_XATTR_SET:
+		err = vfsub_setxattr(h_path.dentry,
+				     arg->u.set.name, arg->u.set.value,
+				     arg->u.set.size, arg->u.set.flags);
+		break;
+	case AU_XATTR_REMOVE:
+		err = vfsub_removexattr(h_path.dentry, arg->u.remove.name);
+		break;
+	case AU_ACL_SET:
+		err = -EOPNOTSUPP;
+		h_inode = d_inode(h_path.dentry);
+		if (h_inode->i_op->set_acl)
+			err = h_inode->i_op->set_acl(h_inode,
+						     arg->u.acl_set.acl,
+						     arg->u.acl_set.type);
+		break;
+	}
+	if (!err)
+		au_cpup_attr_timesizes(inode);
+
+	au_unpin(&a->pin);
+	if (unlikely(err))
+		au_update_dbstart(dentry);
+
+out_di:
+	di_write_unlock(dentry);
+	si_read_unlock(sb);
+out_kfree:
+	kfree(a);
+out:
+	AuTraceErr(err);
+	return err;
+}
+#endif
+
+static void au_refresh_iattr(struct inode *inode, struct kstat *st,
+			     unsigned int nlink)
+{
+	unsigned int n;
+
+	inode->i_mode = st->mode;
+	/* don't i_[ug]id_write() here */
+	inode->i_uid = st->uid;
+	inode->i_gid = st->gid;
+	inode->i_atime = st->atime;
+	inode->i_mtime = st->mtime;
+	inode->i_ctime = st->ctime;
+
+	au_cpup_attr_nlink(inode, /*force*/0);
+	if (S_ISDIR(inode->i_mode)) {
+		n = inode->i_nlink;
+		n -= nlink;
+		n += st->nlink;
+		smp_mb(); /* for i_nlink */
+		/* 0 can happen */
+		set_nlink(inode, n);
+	}
+
+	spin_lock(&inode->i_lock);
+	inode->i_blocks = st->blocks;
+	i_size_write(inode, st->size);
+	spin_unlock(&inode->i_lock);
+}
+
+/*
+ * common routine for aufs_getattr() and aufs_getxattr().
+ * returns zero or negative (an error).
+ * @dentry will be read-locked in success.
+ */
+int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path)
+{
+	int err;
+	unsigned int mnt_flags, sigen;
+	unsigned char udba_none;
+	aufs_bindex_t bindex;
+	struct super_block *sb, *h_sb;
+	struct inode *inode;
+
+	h_path->mnt = NULL;
+	h_path->dentry = NULL;
+
+	err = 0;
+	sb = dentry->d_sb;
+	mnt_flags = au_mntflags(sb);
+	udba_none = !!au_opt_test(mnt_flags, UDBA_NONE);
+
+	/* support fstat(2) */
+	if (!d_unlinked(dentry) && !udba_none) {
+		sigen = au_sigen(sb);
+		err = au_digen_test(dentry, sigen);
+		if (!err) {
+			di_read_lock_child(dentry, AuLock_IR);
+			err = au_dbrange_test(dentry);
+			if (unlikely(err)) {
+				di_read_unlock(dentry, AuLock_IR);
+				goto out;
+			}
+		} else {
+			AuDebugOn(IS_ROOT(dentry));
+			di_write_lock_child(dentry);
+			err = au_dbrange_test(dentry);
+			if (!err)
+				err = au_reval_for_attr(dentry, sigen);
+			if (!err)
+				di_downgrade_lock(dentry, AuLock_IR);
+			else {
+				di_write_unlock(dentry);
+				goto out;
+			}
+		}
+	} else
+		di_read_lock_child(dentry, AuLock_IR);
+
+	inode = d_inode(dentry);
+	bindex = au_ibstart(inode);
+	h_path->mnt = au_sbr_mnt(sb, bindex);
+	h_sb = h_path->mnt->mnt_sb;
+	if (!force
+	    && !au_test_fs_bad_iattr(h_sb)
+	    && udba_none)
+		goto out; /* success */
+
+	if (au_dbstart(dentry) == bindex)
+		h_path->dentry = au_h_dptr(dentry, bindex);
+	else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) {
+		h_path->dentry = au_plink_lkup(inode, bindex);
+		if (IS_ERR(h_path->dentry))
+			/* pretending success */
+			h_path->dentry = NULL;
+		else
+			dput(h_path->dentry);
+	}
+
+out:
+	return err;
+}
+
+static int aufs_getattr(struct vfsmount *mnt __maybe_unused,
+			struct dentry *dentry, struct kstat *st)
+{
+	int err;
+	unsigned char positive;
+	struct path h_path;
+	struct inode *inode;
+	struct super_block *sb;
+
+	inode = d_inode(dentry);
+	sb = dentry->d_sb;
+	err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+	if (unlikely(err))
+		goto out;
+	err = au_h_path_getattr(dentry, /*force*/0, &h_path);
+	if (unlikely(err))
+		goto out_si;
+	if (unlikely(!h_path.dentry))
+		/* illegally overlapped or something */
+		goto out_fill; /* pretending success */
+
+	positive = d_is_positive(h_path.dentry);
+	if (positive)
+		err = vfs_getattr(&h_path, st);
+	if (!err) {
+		if (positive)
+			au_refresh_iattr(inode, st,
+					 d_inode(h_path.dentry)->i_nlink);
+		goto out_fill; /* success */
+	}
+	AuTraceErr(err);
+	goto out_di;
+
+out_fill:
+	generic_fillattr(inode, st);
+out_di:
+	di_read_unlock(dentry, AuLock_IR);
+out_si:
+	si_read_unlock(sb);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Assumption:
+ * - the number of symlinks is not so many.
+ *
+ * Structure:
+ * - sbinfo (instead of iinfo) contains an hlist of struct au_symlink.
+ *   If iinfo contained the hlist, then it would be rather large waste of memory
+ *   I am afraid.
+ * - struct au_symlink contains the necessary info for h_inode follow_link() and
+ *   put_link().
+ */
+
+struct au_symlink {
+	union {
+		struct hlist_node hlist;
+		struct rcu_head rcu;
+	};
+
+	struct inode *h_inode;
+	void *h_cookie;
+};
+
+static void au_symlink_add(struct super_block *sb, struct au_symlink *slink,
+			   struct inode *h_inode, void *cookie)
+{
+	struct au_sbinfo *sbinfo;
+
+	ihold(h_inode);
+	slink->h_inode = h_inode;
+	slink->h_cookie = cookie;
+	sbinfo = au_sbi(sb);
+	au_sphl_add(&slink->hlist, &sbinfo->si_symlink);
+}
+
+static void au_symlink_del(struct super_block *sb, struct au_symlink *slink)
+{
+	struct au_sbinfo *sbinfo;
+
+	/* do not iput() within rcu */
+	iput(slink->h_inode);
+	slink->h_inode = NULL;
+	sbinfo = au_sbi(sb);
+	au_sphl_del_rcu(&slink->hlist, &sbinfo->si_symlink);
+	kfree_rcu(slink, rcu);
+}
+
+static const char *aufs_follow_link(struct dentry *dentry, void **cookie)
+{
+	const char *ret;
+	struct inode *inode, *h_inode;
+	struct dentry *h_dentry;
+	struct au_symlink *slink;
+	int err;
+	aufs_bindex_t bindex;
+
+	ret = NULL; /* suppress a warning */
+	err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
+	if (unlikely(err))
+		goto out;
+
+	err = au_d_hashed_positive(dentry);
+	if (unlikely(err))
+		goto out_unlock;
+
+	err = -EINVAL;
+	inode = d_inode(dentry);
+	bindex = au_ibstart(inode);
+	h_inode = au_h_iptr(inode, bindex);
+	if (unlikely(!h_inode->i_op->follow_link))
+		goto out_unlock;
+
+	err = -ENOMEM;
+	slink = kmalloc(sizeof(*slink), GFP_NOFS);
+	if (unlikely(!slink))
+		goto out_unlock;
+
+	err = -EBUSY;
+	h_dentry = NULL;
+	if (au_dbstart(dentry) <= bindex) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (h_dentry)
+			dget(h_dentry);
+	}
+	if (!h_dentry) {
+		h_dentry = d_find_any_alias(h_inode);
+		if (IS_ERR(h_dentry)) {
+			err = PTR_ERR(h_dentry);
+			goto out_free;
+		}
+	}
+	if (unlikely(!h_dentry))
+		goto out_free;
+
+	err = 0;
+	AuDbg("%pf\n", h_inode->i_op->follow_link);
+	AuDbgDentry(h_dentry);
+	ret = h_inode->i_op->follow_link(h_dentry, cookie);
+	dput(h_dentry);
+
+	if (!IS_ERR_OR_NULL(ret)) {
+		au_symlink_add(inode->i_sb, slink, h_inode, *cookie);
+		*cookie = slink;
+		AuDbg("slink %p\n", slink);
+		goto out_unlock; /* success */
+	}
+
+out_free:
+	slink->h_inode = NULL;
+	kfree_rcu(slink, rcu);
+out_unlock:
+	aufs_read_unlock(dentry, AuLock_IR);
+out:
+	if (unlikely(err))
+		ret = ERR_PTR(err);
+	AuTraceErrPtr(ret);
+	return ret;
+}
+
+static void aufs_put_link(struct inode *inode, void *cookie)
+{
+	struct au_symlink *slink;
+	struct inode *h_inode;
+
+	slink = cookie;
+	AuDbg("slink %p\n", slink);
+	h_inode = slink->h_inode;
+	AuDbg("%pf\n", h_inode->i_op->put_link);
+	AuDbgInode(h_inode);
+	if (h_inode->i_op->put_link)
+		h_inode->i_op->put_link(h_inode, slink->h_cookie);
+	au_symlink_del(inode->i_sb, slink);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int aufs_update_time(struct inode *inode, struct timespec *ts, int flags)
+{
+	int err;
+	struct super_block *sb;
+	struct inode *h_inode;
+
+	sb = inode->i_sb;
+	/* mmap_sem might be acquired already, cf. aufs_mmap() */
+	lockdep_off();
+	si_read_lock(sb, AuLock_FLUSH);
+	ii_write_lock_child(inode);
+	lockdep_on();
+	h_inode = au_h_iptr(inode, au_ibstart(inode));
+	err = vfsub_update_time(h_inode, ts, flags);
+	lockdep_off();
+	if (!err)
+		au_cpup_attr_timesizes(inode);
+	ii_write_unlock(inode);
+	si_read_unlock(sb);
+	lockdep_on();
+
+	if (!err && (flags & S_VERSION))
+		inode_inc_iversion(inode);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* no getattr version will be set by module.c:aufs_init() */
+struct inode_operations aufs_iop_nogetattr[AuIop_Last],
+	aufs_iop[] = {
+	[AuIop_SYMLINK] = {
+		.permission	= aufs_permission,
+#ifdef CONFIG_FS_POSIX_ACL
+		.get_acl	= aufs_get_acl,
+		.set_acl	= aufs_set_acl, /* unsupport for symlink? */
+#endif
+
+		.setattr	= aufs_setattr,
+		.getattr	= aufs_getattr,
+
+#ifdef CONFIG_AUFS_XATTR
+		.setxattr	= aufs_setxattr,
+		.getxattr	= aufs_getxattr,
+		.listxattr	= aufs_listxattr,
+		.removexattr	= aufs_removexattr,
+#endif
+
+		.readlink	= generic_readlink,
+		.follow_link	= aufs_follow_link,
+		.put_link	= aufs_put_link,
+
+		/* .update_time	= aufs_update_time */
+	},
+	[AuIop_DIR] = {
+		.create		= aufs_create,
+		.lookup		= aufs_lookup,
+		.link		= aufs_link,
+		.unlink		= aufs_unlink,
+		.symlink	= aufs_symlink,
+		.mkdir		= aufs_mkdir,
+		.rmdir		= aufs_rmdir,
+		.mknod		= aufs_mknod,
+		.rename		= aufs_rename,
+
+		.permission	= aufs_permission,
+#ifdef CONFIG_FS_POSIX_ACL
+		.get_acl	= aufs_get_acl,
+		.set_acl	= aufs_set_acl,
+#endif
+
+		.setattr	= aufs_setattr,
+		.getattr	= aufs_getattr,
+
+#ifdef CONFIG_AUFS_XATTR
+		.setxattr	= aufs_setxattr,
+		.getxattr	= aufs_getxattr,
+		.listxattr	= aufs_listxattr,
+		.removexattr	= aufs_removexattr,
+#endif
+
+		.update_time	= aufs_update_time,
+		.atomic_open	= aufs_atomic_open,
+		.tmpfile	= aufs_tmpfile
+	},
+	[AuIop_OTHER] = {
+		.permission	= aufs_permission,
+#ifdef CONFIG_FS_POSIX_ACL
+		.get_acl	= aufs_get_acl,
+		.set_acl	= aufs_set_acl,
+#endif
+
+		.setattr	= aufs_setattr,
+		.getattr	= aufs_getattr,
+
+#ifdef CONFIG_AUFS_XATTR
+		.setxattr	= aufs_setxattr,
+		.getxattr	= aufs_getxattr,
+		.listxattr	= aufs_listxattr,
+		.removexattr	= aufs_removexattr,
+#endif
+
+		.update_time	= aufs_update_time
+	}
+};
--- linux-4.4.0.orig/fs/aufs/i_op_add.c
+++ linux-4.4.0/fs/aufs/i_op_add.c
@@ -0,0 +1,932 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * inode operations (add entry)
+ */
+
+#include "aufs.h"
+
+/*
+ * final procedure of adding a new entry, except link(2).
+ * remove whiteout, instantiate, copyup the parent dir's times and size
+ * and update version.
+ * if it failed, re-create the removed whiteout.
+ */
+static int epilog(struct inode *dir, aufs_bindex_t bindex,
+		  struct dentry *wh_dentry, struct dentry *dentry)
+{
+	int err, rerr;
+	aufs_bindex_t bwh;
+	struct path h_path;
+	struct super_block *sb;
+	struct inode *inode, *h_dir;
+	struct dentry *wh;
+
+	bwh = -1;
+	sb = dir->i_sb;
+	if (wh_dentry) {
+		h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */
+		IMustLock(h_dir);
+		AuDebugOn(au_h_iptr(dir, bindex) != h_dir);
+		bwh = au_dbwh(dentry);
+		h_path.dentry = wh_dentry;
+		h_path.mnt = au_sbr_mnt(sb, bindex);
+		err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path,
+					  dentry);
+		if (unlikely(err))
+			goto out;
+	}
+
+	inode = au_new_inode(dentry, /*must_new*/1);
+	if (!IS_ERR(inode)) {
+		d_instantiate(dentry, inode);
+		dir = d_inode(dentry->d_parent); /* dir inode is locked */
+		IMustLock(dir);
+		au_dir_ts(dir, bindex);
+		dir->i_version++;
+		au_fhsm_wrote(sb, bindex, /*force*/0);
+		return 0; /* success */
+	}
+
+	err = PTR_ERR(inode);
+	if (!wh_dentry)
+		goto out;
+
+	/* revert */
+	/* dir inode is locked */
+	wh = au_wh_create(dentry, bwh, wh_dentry->d_parent);
+	rerr = PTR_ERR(wh);
+	if (IS_ERR(wh)) {
+		AuIOErr("%pd reverting whiteout failed(%d, %d)\n",
+			dentry, err, rerr);
+		err = -EIO;
+	} else
+		dput(wh);
+
+out:
+	return err;
+}
+
+static int au_d_may_add(struct dentry *dentry)
+{
+	int err;
+
+	err = 0;
+	if (unlikely(d_unhashed(dentry)))
+		err = -ENOENT;
+	if (unlikely(d_really_is_positive(dentry)))
+		err = -EEXIST;
+	return err;
+}
+
+/*
+ * simple tests for the adding inode operations.
+ * following the checks in vfs, plus the parent-child relationship.
+ */
+int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
+	       struct dentry *h_parent, int isdir)
+{
+	int err;
+	umode_t h_mode;
+	struct dentry *h_dentry;
+	struct inode *h_inode;
+
+	err = -ENAMETOOLONG;
+	if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
+		goto out;
+
+	h_dentry = au_h_dptr(dentry, bindex);
+	if (d_really_is_negative(dentry)) {
+		err = -EEXIST;
+		if (unlikely(d_is_positive(h_dentry)))
+			goto out;
+	} else {
+		/* rename(2) case */
+		err = -EIO;
+		if (unlikely(d_is_negative(h_dentry)))
+			goto out;
+		h_inode = d_inode(h_dentry);
+		if (unlikely(!h_inode->i_nlink))
+			goto out;
+
+		h_mode = h_inode->i_mode;
+		if (!isdir) {
+			err = -EISDIR;
+			if (unlikely(S_ISDIR(h_mode)))
+				goto out;
+		} else if (unlikely(!S_ISDIR(h_mode))) {
+			err = -ENOTDIR;
+			goto out;
+		}
+	}
+
+	err = 0;
+	/* expected parent dir is locked */
+	if (unlikely(h_parent != h_dentry->d_parent))
+		err = -EIO;
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/*
+ * initial procedure of adding a new entry.
+ * prepare writable branch and the parent dir, lock it,
+ * and lookup whiteout for the new entry.
+ */
+static struct dentry*
+lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt,
+		  struct dentry *src_dentry, struct au_pin *pin,
+		  struct au_wr_dir_args *wr_dir_args)
+{
+	struct dentry *wh_dentry, *h_parent;
+	struct super_block *sb;
+	struct au_branch *br;
+	int err;
+	unsigned int udba;
+	aufs_bindex_t bcpup;
+
+	AuDbg("%pd\n", dentry);
+
+	err = au_wr_dir(dentry, src_dentry, wr_dir_args);
+	bcpup = err;
+	wh_dentry = ERR_PTR(err);
+	if (unlikely(err < 0))
+		goto out;
+
+	sb = dentry->d_sb;
+	udba = au_opt_udba(sb);
+	err = au_pin(pin, dentry, bcpup, udba,
+		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+	wh_dentry = ERR_PTR(err);
+	if (unlikely(err))
+		goto out;
+
+	h_parent = au_pinned_h_parent(pin);
+	if (udba != AuOpt_UDBA_NONE
+	    && au_dbstart(dentry) == bcpup)
+		err = au_may_add(dentry, bcpup, h_parent,
+				 au_ftest_wrdir(wr_dir_args->flags, ISDIR));
+	else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
+		err = -ENAMETOOLONG;
+	wh_dentry = ERR_PTR(err);
+	if (unlikely(err))
+		goto out_unpin;
+
+	br = au_sbr(sb, bcpup);
+	if (dt) {
+		struct path tmp = {
+			.dentry	= h_parent,
+			.mnt	= au_br_mnt(br)
+		};
+		au_dtime_store(dt, au_pinned_parent(pin), &tmp);
+	}
+
+	wh_dentry = NULL;
+	if (bcpup != au_dbwh(dentry))
+		goto out; /* success */
+
+	/*
+	 * ENAMETOOLONG here means that if we allowed create such name, then it
+	 * would not be able to removed in the future. So we don't allow such
+	 * name here and we don't handle ENAMETOOLONG differently here.
+	 */
+	wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
+
+out_unpin:
+	if (IS_ERR(wh_dentry))
+		au_unpin(pin);
+out:
+	return wh_dentry;
+}
+
+/* ---------------------------------------------------------------------- */
+
+enum { Mknod, Symlink, Creat };
+struct simple_arg {
+	int type;
+	union {
+		struct {
+			umode_t			mode;
+			bool			want_excl;
+			bool			try_aopen;
+			struct vfsub_aopen_args	*aopen;
+		} c;
+		struct {
+			const char *symname;
+		} s;
+		struct {
+			umode_t mode;
+			dev_t dev;
+		} m;
+	} u;
+};
+
+static int add_simple(struct inode *dir, struct dentry *dentry,
+		      struct simple_arg *arg)
+{
+	int err, rerr;
+	aufs_bindex_t bstart;
+	unsigned char created;
+	const unsigned char try_aopen
+		= (arg->type == Creat && arg->u.c.try_aopen);
+	struct dentry *wh_dentry, *parent;
+	struct inode *h_dir;
+	struct super_block *sb;
+	struct au_branch *br;
+	/* to reuduce stack size */
+	struct {
+		struct au_dtime dt;
+		struct au_pin pin;
+		struct path h_path;
+		struct au_wr_dir_args wr_dir_args;
+	} *a;
+
+	AuDbg("%pd\n", dentry);
+	IMustLock(dir);
+
+	err = -ENOMEM;
+	a = kmalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+	a->wr_dir_args.force_btgt = -1;
+	a->wr_dir_args.flags = AuWrDir_ADD_ENTRY;
+
+	parent = dentry->d_parent; /* dir inode is locked */
+	if (!try_aopen) {
+		err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+		if (unlikely(err))
+			goto out_free;
+	}
+	err = au_d_may_add(dentry);
+	if (unlikely(err))
+		goto out_unlock;
+	if (!try_aopen)
+		di_write_lock_parent(parent);
+	wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
+				      &a->pin, &a->wr_dir_args);
+	err = PTR_ERR(wh_dentry);
+	if (IS_ERR(wh_dentry))
+		goto out_parent;
+
+	bstart = au_dbstart(dentry);
+	sb = dentry->d_sb;
+	br = au_sbr(sb, bstart);
+	a->h_path.dentry = au_h_dptr(dentry, bstart);
+	a->h_path.mnt = au_br_mnt(br);
+	h_dir = au_pinned_h_dir(&a->pin);
+	switch (arg->type) {
+	case Creat:
+		err = 0;
+		if (!try_aopen || !h_dir->i_op->atomic_open)
+			err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode,
+					   arg->u.c.want_excl);
+		else
+			err = vfsub_atomic_open(h_dir, a->h_path.dentry,
+						arg->u.c.aopen, br);
+		break;
+	case Symlink:
+		err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname);
+		break;
+	case Mknod:
+		err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode,
+				  arg->u.m.dev);
+		break;
+	default:
+		BUG();
+	}
+	created = !err;
+	if (!err)
+		err = epilog(dir, bstart, wh_dentry, dentry);
+
+	/* revert */
+	if (unlikely(created && err && d_is_positive(a->h_path.dentry))) {
+		/* no delegation since it is just created */
+		rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL,
+				    /*force*/0);
+		if (rerr) {
+			AuIOErr("%pd revert failure(%d, %d)\n",
+				dentry, err, rerr);
+			err = -EIO;
+		}
+		au_dtime_revert(&a->dt);
+	}
+
+	if (!err && try_aopen && !h_dir->i_op->atomic_open)
+		*arg->u.c.aopen->opened |= FILE_CREATED;
+
+	au_unpin(&a->pin);
+	dput(wh_dentry);
+
+out_parent:
+	if (!try_aopen)
+		di_write_unlock(parent);
+out_unlock:
+	if (unlikely(err)) {
+		au_update_dbstart(dentry);
+		d_drop(dentry);
+	}
+	if (!try_aopen)
+		aufs_read_unlock(dentry, AuLock_DW);
+out_free:
+	kfree(a);
+out:
+	return err;
+}
+
+int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+	       dev_t dev)
+{
+	struct simple_arg arg = {
+		.type = Mknod,
+		.u.m = {
+			.mode	= mode,
+			.dev	= dev
+		}
+	};
+	return add_simple(dir, dentry, &arg);
+}
+
+int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+{
+	struct simple_arg arg = {
+		.type = Symlink,
+		.u.s.symname = symname
+	};
+	return add_simple(dir, dentry, &arg);
+}
+
+int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+		bool want_excl)
+{
+	struct simple_arg arg = {
+		.type = Creat,
+		.u.c = {
+			.mode		= mode,
+			.want_excl	= want_excl
+		}
+	};
+	return add_simple(dir, dentry, &arg);
+}
+
+int au_aopen_or_create(struct inode *dir, struct dentry *dentry,
+		       struct vfsub_aopen_args *aopen_args)
+{
+	struct simple_arg arg = {
+		.type = Creat,
+		.u.c = {
+			.mode		= aopen_args->create_mode,
+			.want_excl	= aopen_args->open_flag & O_EXCL,
+			.try_aopen	= true,
+			.aopen		= aopen_args
+		}
+	};
+	return add_simple(dir, dentry, &arg);
+}
+
+int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+	int err;
+	aufs_bindex_t bindex;
+	struct super_block *sb;
+	struct dentry *parent, *h_parent, *h_dentry;
+	struct inode *h_dir, *inode;
+	struct vfsmount *h_mnt;
+	struct au_wr_dir_args wr_dir_args = {
+		.force_btgt	= -1,
+		.flags		= AuWrDir_TMPFILE
+	};
+
+	/* copy-up may happen */
+	mutex_lock(&dir->i_mutex);
+
+	sb = dir->i_sb;
+	err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+	if (unlikely(err))
+		goto out;
+
+	err = au_di_init(dentry);
+	if (unlikely(err))
+		goto out_si;
+
+	err = -EBUSY;
+	parent = d_find_any_alias(dir);
+	AuDebugOn(!parent);
+	di_write_lock_parent(parent);
+	if (unlikely(d_inode(parent) != dir))
+		goto out_parent;
+
+	err = au_digen_test(parent, au_sigen(sb));
+	if (unlikely(err))
+		goto out_parent;
+
+	bindex = au_dbstart(parent);
+	au_set_dbstart(dentry, bindex);
+	au_set_dbend(dentry, bindex);
+	err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
+	bindex = err;
+	if (unlikely(err < 0))
+		goto out_parent;
+
+	err = -EOPNOTSUPP;
+	h_dir = au_h_iptr(dir, bindex);
+	if (unlikely(!h_dir->i_op->tmpfile))
+		goto out_parent;
+
+	h_mnt = au_sbr_mnt(sb, bindex);
+	err = vfsub_mnt_want_write(h_mnt);
+	if (unlikely(err))
+		goto out_parent;
+
+	h_parent = au_h_dptr(parent, bindex);
+	err = inode_permission(d_inode(h_parent), MAY_WRITE | MAY_EXEC);
+	if (unlikely(err))
+		goto out_mnt;
+
+	err = -ENOMEM;
+	h_dentry = d_alloc(h_parent, &dentry->d_name);
+	if (unlikely(!h_dentry))
+		goto out_mnt;
+
+	err = h_dir->i_op->tmpfile(h_dir, h_dentry, mode);
+	if (unlikely(err))
+		goto out_dentry;
+
+	au_set_dbstart(dentry, bindex);
+	au_set_dbend(dentry, bindex);
+	au_set_h_dptr(dentry, bindex, dget(h_dentry));
+	inode = au_new_inode(dentry, /*must_new*/1);
+	if (IS_ERR(inode)) {
+		err = PTR_ERR(inode);
+		au_set_h_dptr(dentry, bindex, NULL);
+		au_set_dbstart(dentry, -1);
+		au_set_dbend(dentry, -1);
+	} else {
+		if (!inode->i_nlink)
+			set_nlink(inode, 1);
+		d_tmpfile(dentry, inode);
+		au_di(dentry)->di_tmpfile = 1;
+
+		/* update without i_mutex */
+		if (au_ibstart(dir) == au_dbstart(dentry))
+			au_cpup_attr_timesizes(dir);
+	}
+
+out_dentry:
+	dput(h_dentry);
+out_mnt:
+	vfsub_mnt_drop_write(h_mnt);
+out_parent:
+	di_write_unlock(parent);
+	dput(parent);
+	di_write_unlock(dentry);
+	if (!err)
+#if 0
+		/* verbose coding for lock class name */
+		au_rw_class(&au_di(dentry)->di_rwsem,
+			    au_lc_key + AuLcNonDir_DIINFO);
+#else
+		;
+#endif
+	else {
+		au_di_fin(dentry);
+		dentry->d_fsdata = NULL;
+	}
+out_si:
+	si_read_unlock(sb);
+out:
+	mutex_unlock(&dir->i_mutex);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct au_link_args {
+	aufs_bindex_t bdst, bsrc;
+	struct au_pin pin;
+	struct path h_path;
+	struct dentry *src_parent, *parent;
+};
+
+static int au_cpup_before_link(struct dentry *src_dentry,
+			       struct au_link_args *a)
+{
+	int err;
+	struct dentry *h_src_dentry;
+	struct au_cp_generic cpg = {
+		.dentry	= src_dentry,
+		.bdst	= a->bdst,
+		.bsrc	= a->bsrc,
+		.len	= -1,
+		.pin	= &a->pin,
+		.flags	= AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */
+	};
+
+	di_read_lock_parent(a->src_parent, AuLock_IR);
+	err = au_test_and_cpup_dirs(src_dentry, a->bdst);
+	if (unlikely(err))
+		goto out;
+
+	h_src_dentry = au_h_dptr(src_dentry, a->bsrc);
+	err = au_pin(&a->pin, src_dentry, a->bdst,
+		     au_opt_udba(src_dentry->d_sb),
+		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+	if (unlikely(err))
+		goto out;
+
+	err = au_sio_cpup_simple(&cpg);
+	au_unpin(&a->pin);
+
+out:
+	di_read_unlock(a->src_parent, AuLock_IR);
+	return err;
+}
+
+static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry,
+			   struct au_link_args *a)
+{
+	int err;
+	unsigned char plink;
+	aufs_bindex_t bend;
+	struct dentry *h_src_dentry;
+	struct inode *h_inode, *inode, *delegated;
+	struct super_block *sb;
+	struct file *h_file;
+
+	plink = 0;
+	h_inode = NULL;
+	sb = src_dentry->d_sb;
+	inode = d_inode(src_dentry);
+	if (au_ibstart(inode) <= a->bdst)
+		h_inode = au_h_iptr(inode, a->bdst);
+	if (!h_inode || !h_inode->i_nlink) {
+		/* copyup src_dentry as the name of dentry. */
+		bend = au_dbend(dentry);
+		if (bend < a->bsrc)
+			au_set_dbend(dentry, a->bsrc);
+		au_set_h_dptr(dentry, a->bsrc,
+			      dget(au_h_dptr(src_dentry, a->bsrc)));
+		dget(a->h_path.dentry);
+		au_set_h_dptr(dentry, a->bdst, NULL);
+		AuDbg("temporary d_inode...\n");
+		spin_lock(&dentry->d_lock);
+		dentry->d_inode = d_inode(src_dentry); /* tmp */
+		spin_unlock(&dentry->d_lock);
+		h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0);
+		if (IS_ERR(h_file))
+			err = PTR_ERR(h_file);
+		else {
+			struct au_cp_generic cpg = {
+				.dentry	= dentry,
+				.bdst	= a->bdst,
+				.bsrc	= -1,
+				.len	= -1,
+				.pin	= &a->pin,
+				.flags	= AuCpup_KEEPLINO
+			};
+			err = au_sio_cpup_simple(&cpg);
+			au_h_open_post(dentry, a->bsrc, h_file);
+			if (!err) {
+				dput(a->h_path.dentry);
+				a->h_path.dentry = au_h_dptr(dentry, a->bdst);
+			} else
+				au_set_h_dptr(dentry, a->bdst,
+					      a->h_path.dentry);
+		}
+		spin_lock(&dentry->d_lock);
+		dentry->d_inode = NULL; /* restore */
+		spin_unlock(&dentry->d_lock);
+		AuDbg("temporary d_inode...done\n");
+		au_set_h_dptr(dentry, a->bsrc, NULL);
+		au_set_dbend(dentry, bend);
+	} else {
+		/* the inode of src_dentry already exists on a.bdst branch */
+		h_src_dentry = d_find_alias(h_inode);
+		if (!h_src_dentry && au_plink_test(inode)) {
+			plink = 1;
+			h_src_dentry = au_plink_lkup(inode, a->bdst);
+			err = PTR_ERR(h_src_dentry);
+			if (IS_ERR(h_src_dentry))
+				goto out;
+
+			if (unlikely(d_is_negative(h_src_dentry))) {
+				dput(h_src_dentry);
+				h_src_dentry = NULL;
+			}
+
+		}
+		if (h_src_dentry) {
+			delegated = NULL;
+			err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
+					 &a->h_path, &delegated);
+			if (unlikely(err == -EWOULDBLOCK)) {
+				pr_warn("cannot retry for NFSv4 delegation"
+					" for an internal link\n");
+				iput(delegated);
+			}
+			dput(h_src_dentry);
+		} else {
+			AuIOErr("no dentry found for hi%lu on b%d\n",
+				h_inode->i_ino, a->bdst);
+			err = -EIO;
+		}
+	}
+
+	if (!err && !plink)
+		au_plink_append(inode, a->bdst, a->h_path.dentry);
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+int aufs_link(struct dentry *src_dentry, struct inode *dir,
+	      struct dentry *dentry)
+{
+	int err, rerr;
+	struct au_dtime dt;
+	struct au_link_args *a;
+	struct dentry *wh_dentry, *h_src_dentry;
+	struct inode *inode, *delegated;
+	struct super_block *sb;
+	struct au_wr_dir_args wr_dir_args = {
+		/* .force_btgt	= -1, */
+		.flags		= AuWrDir_ADD_ENTRY
+	};
+
+	IMustLock(dir);
+	inode = d_inode(src_dentry);
+	IMustLock(inode);
+
+	err = -ENOMEM;
+	a = kzalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+
+	a->parent = dentry->d_parent; /* dir inode is locked */
+	err = aufs_read_and_write_lock2(dentry, src_dentry,
+					AuLock_NOPLM | AuLock_GEN);
+	if (unlikely(err))
+		goto out_kfree;
+	err = au_d_linkable(src_dentry);
+	if (unlikely(err))
+		goto out_unlock;
+	err = au_d_may_add(dentry);
+	if (unlikely(err))
+		goto out_unlock;
+
+	a->src_parent = dget_parent(src_dentry);
+	wr_dir_args.force_btgt = au_ibstart(inode);
+
+	di_write_lock_parent(a->parent);
+	wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt);
+	wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin,
+				      &wr_dir_args);
+	err = PTR_ERR(wh_dentry);
+	if (IS_ERR(wh_dentry))
+		goto out_parent;
+
+	err = 0;
+	sb = dentry->d_sb;
+	a->bdst = au_dbstart(dentry);
+	a->h_path.dentry = au_h_dptr(dentry, a->bdst);
+	a->h_path.mnt = au_sbr_mnt(sb, a->bdst);
+	a->bsrc = au_ibstart(inode);
+	h_src_dentry = au_h_d_alias(src_dentry, a->bsrc);
+	if (!h_src_dentry && au_di(src_dentry)->di_tmpfile)
+		h_src_dentry = dget(au_hi_wh(inode, a->bsrc));
+	if (!h_src_dentry) {
+		a->bsrc = au_dbstart(src_dentry);
+		h_src_dentry = au_h_d_alias(src_dentry, a->bsrc);
+		AuDebugOn(!h_src_dentry);
+	} else if (IS_ERR(h_src_dentry)) {
+		err = PTR_ERR(h_src_dentry);
+		goto out_parent;
+	}
+
+	if (au_opt_test(au_mntflags(sb), PLINK)) {
+		if (a->bdst < a->bsrc
+		    /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */)
+			err = au_cpup_or_link(src_dentry, dentry, a);
+		else {
+			delegated = NULL;
+			err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
+					 &a->h_path, &delegated);
+			if (unlikely(err == -EWOULDBLOCK)) {
+				pr_warn("cannot retry for NFSv4 delegation"
+					" for an internal link\n");
+				iput(delegated);
+			}
+		}
+		dput(h_src_dentry);
+	} else {
+		/*
+		 * copyup src_dentry to the branch we process,
+		 * and then link(2) to it.
+		 */
+		dput(h_src_dentry);
+		if (a->bdst < a->bsrc
+		    /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) {
+			au_unpin(&a->pin);
+			di_write_unlock(a->parent);
+			err = au_cpup_before_link(src_dentry, a);
+			di_write_lock_parent(a->parent);
+			if (!err)
+				err = au_pin(&a->pin, dentry, a->bdst,
+					     au_opt_udba(sb),
+					     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+			if (unlikely(err))
+				goto out_wh;
+		}
+		if (!err) {
+			h_src_dentry = au_h_dptr(src_dentry, a->bdst);
+			err = -ENOENT;
+			if (h_src_dentry && d_is_positive(h_src_dentry)) {
+				delegated = NULL;
+				err = vfsub_link(h_src_dentry,
+						 au_pinned_h_dir(&a->pin),
+						 &a->h_path, &delegated);
+				if (unlikely(err == -EWOULDBLOCK)) {
+					pr_warn("cannot retry"
+						" for NFSv4 delegation"
+						" for an internal link\n");
+					iput(delegated);
+				}
+			}
+		}
+	}
+	if (unlikely(err))
+		goto out_unpin;
+
+	if (wh_dentry) {
+		a->h_path.dentry = wh_dentry;
+		err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path,
+					  dentry);
+		if (unlikely(err))
+			goto out_revert;
+	}
+
+	au_dir_ts(dir, a->bdst);
+	dir->i_version++;
+	inc_nlink(inode);
+	inode->i_ctime = dir->i_ctime;
+	d_instantiate(dentry, au_igrab(inode));
+	if (d_unhashed(a->h_path.dentry))
+		/* some filesystem calls d_drop() */
+		d_drop(dentry);
+	/* some filesystems consume an inode even hardlink */
+	au_fhsm_wrote(sb, a->bdst, /*force*/0);
+	goto out_unpin; /* success */
+
+out_revert:
+	/* no delegation since it is just created */
+	rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path,
+			    /*delegated*/NULL, /*force*/0);
+	if (unlikely(rerr)) {
+		AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr);
+		err = -EIO;
+	}
+	au_dtime_revert(&dt);
+out_unpin:
+	au_unpin(&a->pin);
+out_wh:
+	dput(wh_dentry);
+out_parent:
+	di_write_unlock(a->parent);
+	dput(a->src_parent);
+out_unlock:
+	if (unlikely(err)) {
+		au_update_dbstart(dentry);
+		d_drop(dentry);
+	}
+	aufs_read_and_write_unlock2(dentry, src_dentry);
+out_kfree:
+	kfree(a);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+	int err, rerr;
+	aufs_bindex_t bindex;
+	unsigned char diropq;
+	struct path h_path;
+	struct dentry *wh_dentry, *parent, *opq_dentry;
+	struct mutex *h_mtx;
+	struct super_block *sb;
+	struct {
+		struct au_pin pin;
+		struct au_dtime dt;
+	} *a; /* reduce the stack usage */
+	struct au_wr_dir_args wr_dir_args = {
+		.force_btgt	= -1,
+		.flags		= AuWrDir_ADD_ENTRY | AuWrDir_ISDIR
+	};
+
+	IMustLock(dir);
+
+	err = -ENOMEM;
+	a = kmalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+
+	err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+	if (unlikely(err))
+		goto out_free;
+	err = au_d_may_add(dentry);
+	if (unlikely(err))
+		goto out_unlock;
+
+	parent = dentry->d_parent; /* dir inode is locked */
+	di_write_lock_parent(parent);
+	wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
+				      &a->pin, &wr_dir_args);
+	err = PTR_ERR(wh_dentry);
+	if (IS_ERR(wh_dentry))
+		goto out_parent;
+
+	sb = dentry->d_sb;
+	bindex = au_dbstart(dentry);
+	h_path.dentry = au_h_dptr(dentry, bindex);
+	h_path.mnt = au_sbr_mnt(sb, bindex);
+	err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode);
+	if (unlikely(err))
+		goto out_unpin;
+
+	/* make the dir opaque */
+	diropq = 0;
+	h_mtx = &d_inode(h_path.dentry)->i_mutex;
+	if (wh_dentry
+	    || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) {
+		mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
+		opq_dentry = au_diropq_create(dentry, bindex);
+		mutex_unlock(h_mtx);
+		err = PTR_ERR(opq_dentry);
+		if (IS_ERR(opq_dentry))
+			goto out_dir;
+		dput(opq_dentry);
+		diropq = 1;
+	}
+
+	err = epilog(dir, bindex, wh_dentry, dentry);
+	if (!err) {
+		inc_nlink(dir);
+		goto out_unpin; /* success */
+	}
+
+	/* revert */
+	if (diropq) {
+		AuLabel(revert opq);
+		mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
+		rerr = au_diropq_remove(dentry, bindex);
+		mutex_unlock(h_mtx);
+		if (rerr) {
+			AuIOErr("%pd reverting diropq failed(%d, %d)\n",
+				dentry, err, rerr);
+			err = -EIO;
+		}
+	}
+
+out_dir:
+	AuLabel(revert dir);
+	rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path);
+	if (rerr) {
+		AuIOErr("%pd reverting dir failed(%d, %d)\n",
+			dentry, err, rerr);
+		err = -EIO;
+	}
+	au_dtime_revert(&a->dt);
+out_unpin:
+	au_unpin(&a->pin);
+	dput(wh_dentry);
+out_parent:
+	di_write_unlock(parent);
+out_unlock:
+	if (unlikely(err)) {
+		au_update_dbstart(dentry);
+		d_drop(dentry);
+	}
+	aufs_read_unlock(dentry, AuLock_DW);
+out_free:
+	kfree(a);
+out:
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/i_op_del.c
+++ linux-4.4.0/fs/aufs/i_op_del.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * inode operations (del entry)
+ */
+
+#include "aufs.h"
+
+/*
+ * decide if a new whiteout for @dentry is necessary or not.
+ * when it is necessary, prepare the parent dir for the upper branch whose
+ * branch index is @bcpup for creation. the actual creation of the whiteout will
+ * be done by caller.
+ * return value:
+ * 0: wh is unnecessary
+ * plus: wh is necessary
+ * minus: error
+ */
+int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
+{
+	int need_wh, err;
+	aufs_bindex_t bstart;
+	struct super_block *sb;
+
+	sb = dentry->d_sb;
+	bstart = au_dbstart(dentry);
+	if (*bcpup < 0) {
+		*bcpup = bstart;
+		if (au_test_ro(sb, bstart, d_inode(dentry))) {
+			err = AuWbrCopyup(au_sbi(sb), dentry);
+			*bcpup = err;
+			if (unlikely(err < 0))
+				goto out;
+		}
+	} else
+		AuDebugOn(bstart < *bcpup
+			  || au_test_ro(sb, *bcpup, d_inode(dentry)));
+	AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart);
+
+	if (*bcpup != bstart) {
+		err = au_cpup_dirs(dentry, *bcpup);
+		if (unlikely(err))
+			goto out;
+		need_wh = 1;
+	} else {
+		struct au_dinfo *dinfo, *tmp;
+
+		need_wh = -ENOMEM;
+		dinfo = au_di(dentry);
+		tmp = au_di_alloc(sb, AuLsc_DI_TMP);
+		if (tmp) {
+			au_di_cp(tmp, dinfo);
+			au_di_swap(tmp, dinfo);
+			/* returns the number of positive dentries */
+			need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0);
+			au_di_swap(tmp, dinfo);
+			au_rw_write_unlock(&tmp->di_rwsem);
+			au_di_free(tmp);
+		}
+	}
+	AuDbg("need_wh %d\n", need_wh);
+	err = need_wh;
+
+out:
+	return err;
+}
+
+/*
+ * simple tests for the del-entry operations.
+ * following the checks in vfs, plus the parent-child relationship.
+ */
+int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
+	       struct dentry *h_parent, int isdir)
+{
+	int err;
+	umode_t h_mode;
+	struct dentry *h_dentry, *h_latest;
+	struct inode *h_inode;
+
+	h_dentry = au_h_dptr(dentry, bindex);
+	if (d_really_is_positive(dentry)) {
+		err = -ENOENT;
+		if (unlikely(d_is_negative(h_dentry)))
+			goto out;
+		h_inode = d_inode(h_dentry);
+		if (unlikely(!h_inode->i_nlink))
+			goto out;
+
+		h_mode = h_inode->i_mode;
+		if (!isdir) {
+			err = -EISDIR;
+			if (unlikely(S_ISDIR(h_mode)))
+				goto out;
+		} else if (unlikely(!S_ISDIR(h_mode))) {
+			err = -ENOTDIR;
+			goto out;
+		}
+	} else {
+		/* rename(2) case */
+		err = -EIO;
+		if (unlikely(d_is_positive(h_dentry)))
+			goto out;
+	}
+
+	err = -ENOENT;
+	/* expected parent dir is locked */
+	if (unlikely(h_parent != h_dentry->d_parent))
+		goto out;
+	err = 0;
+
+	/*
+	 * rmdir a dir may break the consistency on some filesystem.
+	 * let's try heavy test.
+	 */
+	err = -EACCES;
+	if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)
+		     && au_test_h_perm(d_inode(h_parent),
+				       MAY_EXEC | MAY_WRITE)))
+		goto out;
+
+	h_latest = au_sio_lkup_one(&dentry->d_name, h_parent);
+	err = -EIO;
+	if (IS_ERR(h_latest))
+		goto out;
+	if (h_latest == h_dentry)
+		err = 0;
+	dput(h_latest);
+
+out:
+	return err;
+}
+
+/*
+ * decide the branch where we operate for @dentry. the branch index will be set
+ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent
+ * dir for reverting.
+ * when a new whiteout is necessary, create it.
+ */
+static struct dentry*
+lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup,
+		    struct au_dtime *dt, struct au_pin *pin)
+{
+	struct dentry *wh_dentry;
+	struct super_block *sb;
+	struct path h_path;
+	int err, need_wh;
+	unsigned int udba;
+	aufs_bindex_t bcpup;
+
+	need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup);
+	wh_dentry = ERR_PTR(need_wh);
+	if (unlikely(need_wh < 0))
+		goto out;
+
+	sb = dentry->d_sb;
+	udba = au_opt_udba(sb);
+	bcpup = *rbcpup;
+	err = au_pin(pin, dentry, bcpup, udba,
+		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+	wh_dentry = ERR_PTR(err);
+	if (unlikely(err))
+		goto out;
+
+	h_path.dentry = au_pinned_h_parent(pin);
+	if (udba != AuOpt_UDBA_NONE
+	    && au_dbstart(dentry) == bcpup) {
+		err = au_may_del(dentry, bcpup, h_path.dentry, isdir);
+		wh_dentry = ERR_PTR(err);
+		if (unlikely(err))
+			goto out_unpin;
+	}
+
+	h_path.mnt = au_sbr_mnt(sb, bcpup);
+	au_dtime_store(dt, au_pinned_parent(pin), &h_path);
+	wh_dentry = NULL;
+	if (!need_wh)
+		goto out; /* success, no need to create whiteout */
+
+	wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry);
+	if (IS_ERR(wh_dentry))
+		goto out_unpin;
+
+	/* returns with the parent is locked and wh_dentry is dget-ed */
+	goto out; /* success */
+
+out_unpin:
+	au_unpin(pin);
+out:
+	return wh_dentry;
+}
+
+/*
+ * when removing a dir, rename it to a unique temporary whiteout-ed name first
+ * in order to be revertible and save time for removing many child whiteouts
+ * under the dir.
+ * returns 1 when there are too many child whiteout and caller should remove
+ * them asynchronously. returns 0 when the number of children is enough small to
+ * remove now or the branch fs is a remote fs.
+ * otherwise return an error.
+ */
+static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex,
+			   struct au_nhash *whlist, struct inode *dir)
+{
+	int rmdir_later, err, dirwh;
+	struct dentry *h_dentry;
+	struct super_block *sb;
+	struct inode *inode;
+
+	sb = dentry->d_sb;
+	SiMustAnyLock(sb);
+	h_dentry = au_h_dptr(dentry, bindex);
+	err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex));
+	if (unlikely(err))
+		goto out;
+
+	/* stop monitoring */
+	inode = d_inode(dentry);
+	au_hn_free(au_hi(inode, bindex));
+
+	if (!au_test_fs_remote(h_dentry->d_sb)) {
+		dirwh = au_sbi(sb)->si_dirwh;
+		rmdir_later = (dirwh <= 1);
+		if (!rmdir_later)
+			rmdir_later = au_nhash_test_longer_wh(whlist, bindex,
+							      dirwh);
+		if (rmdir_later)
+			return rmdir_later;
+	}
+
+	err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist);
+	if (unlikely(err)) {
+		AuIOErr("rmdir %pd, b%d failed, %d. ignored\n",
+			h_dentry, bindex, err);
+		err = 0;
+	}
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/*
+ * final procedure for deleting a entry.
+ * maintain dentry and iattr.
+ */
+static void epilog(struct inode *dir, struct dentry *dentry,
+		   aufs_bindex_t bindex)
+{
+	struct inode *inode;
+
+	inode = d_inode(dentry);
+	d_drop(dentry);
+	inode->i_ctime = dir->i_ctime;
+
+	au_dir_ts(dir, bindex);
+	dir->i_version++;
+}
+
+/*
+ * when an error happened, remove the created whiteout and revert everything.
+ */
+static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex,
+		     aufs_bindex_t bwh, struct dentry *wh_dentry,
+		     struct dentry *dentry, struct au_dtime *dt)
+{
+	int rerr;
+	struct path h_path = {
+		.dentry	= wh_dentry,
+		.mnt	= au_sbr_mnt(dir->i_sb, bindex)
+	};
+
+	rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry);
+	if (!rerr) {
+		au_set_dbwh(dentry, bwh);
+		au_dtime_revert(dt);
+		return 0;
+	}
+
+	AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr);
+	return -EIO;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int aufs_unlink(struct inode *dir, struct dentry *dentry)
+{
+	int err;
+	aufs_bindex_t bwh, bindex, bstart;
+	struct inode *inode, *h_dir, *delegated;
+	struct dentry *parent, *wh_dentry;
+	/* to reuduce stack size */
+	struct {
+		struct au_dtime dt;
+		struct au_pin pin;
+		struct path h_path;
+	} *a;
+
+	IMustLock(dir);
+
+	err = -ENOMEM;
+	a = kmalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+
+	err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+	if (unlikely(err))
+		goto out_free;
+	err = au_d_hashed_positive(dentry);
+	if (unlikely(err))
+		goto out_unlock;
+	inode = d_inode(dentry);
+	IMustLock(inode);
+	err = -EISDIR;
+	if (unlikely(d_is_dir(dentry)))
+		goto out_unlock; /* possible? */
+
+	bstart = au_dbstart(dentry);
+	bwh = au_dbwh(dentry);
+	bindex = -1;
+	parent = dentry->d_parent; /* dir inode is locked */
+	di_write_lock_parent(parent);
+	wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt,
+					&a->pin);
+	err = PTR_ERR(wh_dentry);
+	if (IS_ERR(wh_dentry))
+		goto out_parent;
+
+	a->h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
+	a->h_path.dentry = au_h_dptr(dentry, bstart);
+	dget(a->h_path.dentry);
+	if (bindex == bstart) {
+		h_dir = au_pinned_h_dir(&a->pin);
+		delegated = NULL;
+		err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0);
+		if (unlikely(err == -EWOULDBLOCK)) {
+			pr_warn("cannot retry for NFSv4 delegation"
+				" for an internal unlink\n");
+			iput(delegated);
+		}
+	} else {
+		/* dir inode is locked */
+		h_dir = d_inode(wh_dentry->d_parent);
+		IMustLock(h_dir);
+		err = 0;
+	}
+
+	if (!err) {
+		vfsub_drop_nlink(inode);
+		epilog(dir, dentry, bindex);
+
+		/* update target timestamps */
+		if (bindex == bstart) {
+			vfsub_update_h_iattr(&a->h_path, /*did*/NULL);
+			/*ignore*/
+			inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime;
+		} else
+			/* todo: this timestamp may be reverted later */
+			inode->i_ctime = h_dir->i_ctime;
+		goto out_unpin; /* success */
+	}
+
+	/* revert */
+	if (wh_dentry) {
+		int rerr;
+
+		rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry,
+				 &a->dt);
+		if (rerr)
+			err = rerr;
+	}
+
+out_unpin:
+	au_unpin(&a->pin);
+	dput(wh_dentry);
+	dput(a->h_path.dentry);
+out_parent:
+	di_write_unlock(parent);
+out_unlock:
+	aufs_read_unlock(dentry, AuLock_DW);
+out_free:
+	kfree(a);
+out:
+	return err;
+}
+
+int aufs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	int err, rmdir_later;
+	aufs_bindex_t bwh, bindex, bstart;
+	struct inode *inode;
+	struct dentry *parent, *wh_dentry, *h_dentry;
+	struct au_whtmp_rmdir *args;
+	/* to reuduce stack size */
+	struct {
+		struct au_dtime dt;
+		struct au_pin pin;
+	} *a;
+
+	IMustLock(dir);
+
+	err = -ENOMEM;
+	a = kmalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+
+	err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN);
+	if (unlikely(err))
+		goto out_free;
+	err = au_alive_dir(dentry);
+	if (unlikely(err))
+		goto out_unlock;
+	inode = d_inode(dentry);
+	IMustLock(inode);
+	err = -ENOTDIR;
+	if (unlikely(!d_is_dir(dentry)))
+		goto out_unlock; /* possible? */
+
+	err = -ENOMEM;
+	args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS);
+	if (unlikely(!args))
+		goto out_unlock;
+
+	parent = dentry->d_parent; /* dir inode is locked */
+	di_write_lock_parent(parent);
+	err = au_test_empty(dentry, &args->whlist);
+	if (unlikely(err))
+		goto out_parent;
+
+	bstart = au_dbstart(dentry);
+	bwh = au_dbwh(dentry);
+	bindex = -1;
+	wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt,
+					&a->pin);
+	err = PTR_ERR(wh_dentry);
+	if (IS_ERR(wh_dentry))
+		goto out_parent;
+
+	h_dentry = au_h_dptr(dentry, bstart);
+	dget(h_dentry);
+	rmdir_later = 0;
+	if (bindex == bstart) {
+		err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir);
+		if (err > 0) {
+			rmdir_later = err;
+			err = 0;
+		}
+	} else {
+		/* stop monitoring */
+		au_hn_free(au_hi(inode, bstart));
+
+		/* dir inode is locked */
+		IMustLock(d_inode(wh_dentry->d_parent));
+		err = 0;
+	}
+
+	if (!err) {
+		vfsub_dead_dir(inode);
+		au_set_dbdiropq(dentry, -1);
+		epilog(dir, dentry, bindex);
+
+		if (rmdir_later) {
+			au_whtmp_kick_rmdir(dir, bstart, h_dentry, args);
+			args = NULL;
+		}
+
+		goto out_unpin; /* success */
+	}
+
+	/* revert */
+	AuLabel(revert);
+	if (wh_dentry) {
+		int rerr;
+
+		rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry,
+				 &a->dt);
+		if (rerr)
+			err = rerr;
+	}
+
+out_unpin:
+	au_unpin(&a->pin);
+	dput(wh_dentry);
+	dput(h_dentry);
+out_parent:
+	di_write_unlock(parent);
+	if (args)
+		au_whtmp_rmdir_free(args);
+out_unlock:
+	aufs_read_unlock(dentry, AuLock_DW);
+out_free:
+	kfree(a);
+out:
+	AuTraceErr(err);
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/i_op_ren.c
+++ linux-4.4.0/fs/aufs/i_op_ren.c
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * inode operation (rename entry)
+ * todo: this is crazy monster
+ */
+
+#include "aufs.h"
+
+enum { AuSRC, AuDST, AuSrcDst };
+enum { AuPARENT, AuCHILD, AuParentChild };
+
+#define AuRen_ISDIR	1
+#define AuRen_ISSAMEDIR	(1 << 1)
+#define AuRen_WHSRC	(1 << 2)
+#define AuRen_WHDST	(1 << 3)
+#define AuRen_MNT_WRITE	(1 << 4)
+#define AuRen_DT_DSTDIR	(1 << 5)
+#define AuRen_DIROPQ	(1 << 6)
+#define au_ftest_ren(flags, name)	((flags) & AuRen_##name)
+#define au_fset_ren(flags, name) \
+	do { (flags) |= AuRen_##name; } while (0)
+#define au_fclr_ren(flags, name) \
+	do { (flags) &= ~AuRen_##name; } while (0)
+
+struct au_ren_args {
+	struct {
+		struct dentry *dentry, *h_dentry, *parent, *h_parent,
+			*wh_dentry;
+		struct inode *dir, *inode;
+		struct au_hinode *hdir;
+		struct au_dtime dt[AuParentChild];
+		aufs_bindex_t bstart;
+	} sd[AuSrcDst];
+
+#define src_dentry	sd[AuSRC].dentry
+#define src_dir		sd[AuSRC].dir
+#define src_inode	sd[AuSRC].inode
+#define src_h_dentry	sd[AuSRC].h_dentry
+#define src_parent	sd[AuSRC].parent
+#define src_h_parent	sd[AuSRC].h_parent
+#define src_wh_dentry	sd[AuSRC].wh_dentry
+#define src_hdir	sd[AuSRC].hdir
+#define src_h_dir	sd[AuSRC].hdir->hi_inode
+#define src_dt		sd[AuSRC].dt
+#define src_bstart	sd[AuSRC].bstart
+
+#define dst_dentry	sd[AuDST].dentry
+#define dst_dir		sd[AuDST].dir
+#define dst_inode	sd[AuDST].inode
+#define dst_h_dentry	sd[AuDST].h_dentry
+#define dst_parent	sd[AuDST].parent
+#define dst_h_parent	sd[AuDST].h_parent
+#define dst_wh_dentry	sd[AuDST].wh_dentry
+#define dst_hdir	sd[AuDST].hdir
+#define dst_h_dir	sd[AuDST].hdir->hi_inode
+#define dst_dt		sd[AuDST].dt
+#define dst_bstart	sd[AuDST].bstart
+
+	struct dentry *h_trap;
+	struct au_branch *br;
+	struct au_hinode *src_hinode;
+	struct path h_path;
+	struct au_nhash whlist;
+	aufs_bindex_t btgt, src_bwh, src_bdiropq;
+
+	unsigned int flags;
+
+	struct au_whtmp_rmdir *thargs;
+	struct dentry *h_dst;
+};
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * functions for reverting.
+ * when an error happened in a single rename systemcall, we should revert
+ * everything as if nothing happened.
+ * we don't need to revert the copied-up/down the parent dir since they are
+ * harmless.
+ */
+
+#define RevertFailure(fmt, ...) do { \
+	AuIOErr("revert failure: " fmt " (%d, %d)\n", \
+		##__VA_ARGS__, err, rerr); \
+	err = -EIO; \
+} while (0)
+
+static void au_ren_rev_diropq(int err, struct au_ren_args *a)
+{
+	int rerr;
+
+	au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
+	rerr = au_diropq_remove(a->src_dentry, a->btgt);
+	au_hn_imtx_unlock(a->src_hinode);
+	au_set_dbdiropq(a->src_dentry, a->src_bdiropq);
+	if (rerr)
+		RevertFailure("remove diropq %pd", a->src_dentry);
+}
+
+static void au_ren_rev_rename(int err, struct au_ren_args *a)
+{
+	int rerr;
+	struct inode *delegated;
+
+	a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name,
+					  a->src_h_parent);
+	rerr = PTR_ERR(a->h_path.dentry);
+	if (IS_ERR(a->h_path.dentry)) {
+		RevertFailure("lkup one %pd", a->src_dentry);
+		return;
+	}
+
+	delegated = NULL;
+	rerr = vfsub_rename(a->dst_h_dir,
+			    au_h_dptr(a->src_dentry, a->btgt),
+			    a->src_h_dir, &a->h_path, &delegated);
+	if (unlikely(rerr == -EWOULDBLOCK)) {
+		pr_warn("cannot retry for NFSv4 delegation"
+			" for an internal rename\n");
+		iput(delegated);
+	}
+	d_drop(a->h_path.dentry);
+	dput(a->h_path.dentry);
+	/* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */
+	if (rerr)
+		RevertFailure("rename %pd", a->src_dentry);
+}
+
+static void au_ren_rev_whtmp(int err, struct au_ren_args *a)
+{
+	int rerr;
+	struct inode *delegated;
+
+	a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name,
+					  a->dst_h_parent);
+	rerr = PTR_ERR(a->h_path.dentry);
+	if (IS_ERR(a->h_path.dentry)) {
+		RevertFailure("lkup one %pd", a->dst_dentry);
+		return;
+	}
+	if (d_is_positive(a->h_path.dentry)) {
+		d_drop(a->h_path.dentry);
+		dput(a->h_path.dentry);
+		return;
+	}
+
+	delegated = NULL;
+	rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path,
+			    &delegated);
+	if (unlikely(rerr == -EWOULDBLOCK)) {
+		pr_warn("cannot retry for NFSv4 delegation"
+			" for an internal rename\n");
+		iput(delegated);
+	}
+	d_drop(a->h_path.dentry);
+	dput(a->h_path.dentry);
+	if (!rerr)
+		au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst));
+	else
+		RevertFailure("rename %pd", a->h_dst);
+}
+
+static void au_ren_rev_whsrc(int err, struct au_ren_args *a)
+{
+	int rerr;
+
+	a->h_path.dentry = a->src_wh_dentry;
+	rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry);
+	au_set_dbwh(a->src_dentry, a->src_bwh);
+	if (rerr)
+		RevertFailure("unlink %pd", a->src_wh_dentry);
+}
+#undef RevertFailure
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * when we have to copyup the renaming entry, do it with the rename-target name
+ * in order to minimize the cost (the later actual rename is unnecessary).
+ * otherwise rename it on the target branch.
+ */
+static int au_ren_or_cpup(struct au_ren_args *a)
+{
+	int err;
+	struct dentry *d;
+	struct inode *delegated;
+
+	d = a->src_dentry;
+	if (au_dbstart(d) == a->btgt) {
+		a->h_path.dentry = a->dst_h_dentry;
+		if (au_ftest_ren(a->flags, DIROPQ)
+		    && au_dbdiropq(d) == a->btgt)
+			au_fclr_ren(a->flags, DIROPQ);
+		AuDebugOn(au_dbstart(d) != a->btgt);
+		delegated = NULL;
+		err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt),
+				   a->dst_h_dir, &a->h_path, &delegated);
+		if (unlikely(err == -EWOULDBLOCK)) {
+			pr_warn("cannot retry for NFSv4 delegation"
+				" for an internal rename\n");
+			iput(delegated);
+		}
+	} else
+		BUG();
+
+	if (!err && a->h_dst)
+		/* it will be set to dinfo later */
+		dget(a->h_dst);
+
+	return err;
+}
+
+/* cf. aufs_rmdir() */
+static int au_ren_del_whtmp(struct au_ren_args *a)
+{
+	int err;
+	struct inode *dir;
+
+	dir = a->dst_dir;
+	SiMustAnyLock(dir->i_sb);
+	if (!au_nhash_test_longer_wh(&a->whlist, a->btgt,
+				     au_sbi(dir->i_sb)->si_dirwh)
+	    || au_test_fs_remote(a->h_dst->d_sb)) {
+		err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist);
+		if (unlikely(err))
+			pr_warn("failed removing whtmp dir %pd (%d), "
+				"ignored.\n", a->h_dst, err);
+	} else {
+		au_nhash_wh_free(&a->thargs->whlist);
+		a->thargs->whlist = a->whlist;
+		a->whlist.nh_num = 0;
+		au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs);
+		dput(a->h_dst);
+		a->thargs = NULL;
+	}
+
+	return 0;
+}
+
+/* make it 'opaque' dir. */
+static int au_ren_diropq(struct au_ren_args *a)
+{
+	int err;
+	struct dentry *diropq;
+
+	err = 0;
+	a->src_bdiropq = au_dbdiropq(a->src_dentry);
+	a->src_hinode = au_hi(a->src_inode, a->btgt);
+	au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
+	diropq = au_diropq_create(a->src_dentry, a->btgt);
+	au_hn_imtx_unlock(a->src_hinode);
+	if (IS_ERR(diropq))
+		err = PTR_ERR(diropq);
+	else
+		dput(diropq);
+
+	return err;
+}
+
+static int do_rename(struct au_ren_args *a)
+{
+	int err;
+	struct dentry *d, *h_d;
+
+	/* prepare workqueue args for asynchronous rmdir */
+	h_d = a->dst_h_dentry;
+	if (au_ftest_ren(a->flags, ISDIR) && d_is_positive(h_d)) {
+		err = -ENOMEM;
+		a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS);
+		if (unlikely(!a->thargs))
+			goto out;
+		a->h_dst = dget(h_d);
+	}
+
+	/* create whiteout for src_dentry */
+	if (au_ftest_ren(a->flags, WHSRC)) {
+		a->src_bwh = au_dbwh(a->src_dentry);
+		AuDebugOn(a->src_bwh >= 0);
+		a->src_wh_dentry
+			= au_wh_create(a->src_dentry, a->btgt, a->src_h_parent);
+		err = PTR_ERR(a->src_wh_dentry);
+		if (IS_ERR(a->src_wh_dentry))
+			goto out_thargs;
+	}
+
+	/* lookup whiteout for dentry */
+	if (au_ftest_ren(a->flags, WHDST)) {
+		h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name,
+				 a->br);
+		err = PTR_ERR(h_d);
+		if (IS_ERR(h_d))
+			goto out_whsrc;
+		if (d_is_negative(h_d))
+			dput(h_d);
+		else
+			a->dst_wh_dentry = h_d;
+	}
+
+	/* rename dentry to tmpwh */
+	if (a->thargs) {
+		err = au_whtmp_ren(a->dst_h_dentry, a->br);
+		if (unlikely(err))
+			goto out_whdst;
+
+		d = a->dst_dentry;
+		au_set_h_dptr(d, a->btgt, NULL);
+		err = au_lkup_neg(d, a->btgt, /*wh*/0);
+		if (unlikely(err))
+			goto out_whtmp;
+		a->dst_h_dentry = au_h_dptr(d, a->btgt);
+	}
+
+	BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_bstart != a->btgt);
+
+	/* rename by vfs_rename or cpup */
+	d = a->dst_dentry;
+	if (au_ftest_ren(a->flags, ISDIR)
+	    && (a->dst_wh_dentry
+		|| au_dbdiropq(d) == a->btgt
+		/* hide the lower to keep xino */
+		|| a->btgt < au_dbend(d)
+		|| au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ)))
+		au_fset_ren(a->flags, DIROPQ);
+	err = au_ren_or_cpup(a);
+	if (unlikely(err))
+		/* leave the copied-up one */
+		goto out_whtmp;
+
+	/* make dir opaque */
+	if (au_ftest_ren(a->flags, DIROPQ)) {
+		err = au_ren_diropq(a);
+		if (unlikely(err))
+			goto out_rename;
+	}
+
+	/* update target timestamps */
+	AuDebugOn(au_dbstart(a->src_dentry) != a->btgt);
+	a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt);
+	vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/
+	a->src_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime;
+
+	/* remove whiteout for dentry */
+	if (a->dst_wh_dentry) {
+		a->h_path.dentry = a->dst_wh_dentry;
+		err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path,
+					  a->dst_dentry);
+		if (unlikely(err))
+			goto out_diropq;
+	}
+
+	/* remove whtmp */
+	if (a->thargs)
+		au_ren_del_whtmp(a); /* ignore this error */
+
+	au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0);
+	err = 0;
+	goto out_success;
+
+out_diropq:
+	if (au_ftest_ren(a->flags, DIROPQ))
+		au_ren_rev_diropq(err, a);
+out_rename:
+	au_ren_rev_rename(err, a);
+	dput(a->h_dst);
+out_whtmp:
+	if (a->thargs)
+		au_ren_rev_whtmp(err, a);
+out_whdst:
+	dput(a->dst_wh_dentry);
+	a->dst_wh_dentry = NULL;
+out_whsrc:
+	if (a->src_wh_dentry)
+		au_ren_rev_whsrc(err, a);
+out_success:
+	dput(a->src_wh_dentry);
+	dput(a->dst_wh_dentry);
+out_thargs:
+	if (a->thargs) {
+		dput(a->h_dst);
+		au_whtmp_rmdir_free(a->thargs);
+		a->thargs = NULL;
+	}
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * test if @dentry dir can be rename destination or not.
+ * success means, it is a logically empty dir.
+ */
+static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist)
+{
+	return au_test_empty(dentry, whlist);
+}
+
+/*
+ * test if @dentry dir can be rename source or not.
+ * if it can, return 0 and @children is filled.
+ * success means,
+ * - it is a logically empty dir.
+ * - or, it exists on writable branch and has no children including whiteouts
+ *       on the lower branch.
+ */
+static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt)
+{
+	int err;
+	unsigned int rdhash;
+	aufs_bindex_t bstart;
+
+	bstart = au_dbstart(dentry);
+	if (bstart != btgt) {
+		struct au_nhash whlist;
+
+		SiMustAnyLock(dentry->d_sb);
+		rdhash = au_sbi(dentry->d_sb)->si_rdhash;
+		if (!rdhash)
+			rdhash = au_rdhash_est(au_dir_size(/*file*/NULL,
+							   dentry));
+		err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
+		if (unlikely(err))
+			goto out;
+		err = au_test_empty(dentry, &whlist);
+		au_nhash_wh_free(&whlist);
+		goto out;
+	}
+
+	if (bstart == au_dbtaildir(dentry))
+		return 0; /* success */
+
+	err = au_test_empty_lower(dentry);
+
+out:
+	if (err == -ENOTEMPTY) {
+		AuWarn1("renaming dir who has child(ren) on multiple branches,"
+			" is not supported\n");
+		err = -EXDEV;
+	}
+	return err;
+}
+
+/* side effect: sets whlist and h_dentry */
+static int au_ren_may_dir(struct au_ren_args *a)
+{
+	int err;
+	unsigned int rdhash;
+	struct dentry *d;
+
+	d = a->dst_dentry;
+	SiMustAnyLock(d->d_sb);
+
+	err = 0;
+	if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) {
+		rdhash = au_sbi(d->d_sb)->si_rdhash;
+		if (!rdhash)
+			rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d));
+		err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS);
+		if (unlikely(err))
+			goto out;
+
+		au_set_dbstart(d, a->dst_bstart);
+		err = may_rename_dstdir(d, &a->whlist);
+		au_set_dbstart(d, a->btgt);
+	}
+	a->dst_h_dentry = au_h_dptr(d, au_dbstart(d));
+	if (unlikely(err))
+		goto out;
+
+	d = a->src_dentry;
+	a->src_h_dentry = au_h_dptr(d, au_dbstart(d));
+	if (au_ftest_ren(a->flags, ISDIR)) {
+		err = may_rename_srcdir(d, a->btgt);
+		if (unlikely(err)) {
+			au_nhash_wh_free(&a->whlist);
+			a->whlist.nh_num = 0;
+		}
+	}
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * simple tests for rename.
+ * following the checks in vfs, plus the parent-child relationship.
+ */
+static int au_may_ren(struct au_ren_args *a)
+{
+	int err, isdir;
+	struct inode *h_inode;
+
+	if (a->src_bstart == a->btgt) {
+		err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent,
+				 au_ftest_ren(a->flags, ISDIR));
+		if (unlikely(err))
+			goto out;
+		err = -EINVAL;
+		if (unlikely(a->src_h_dentry == a->h_trap))
+			goto out;
+	}
+
+	err = 0;
+	if (a->dst_bstart != a->btgt)
+		goto out;
+
+	err = -ENOTEMPTY;
+	if (unlikely(a->dst_h_dentry == a->h_trap))
+		goto out;
+
+	err = -EIO;
+	isdir = !!au_ftest_ren(a->flags, ISDIR);
+	if (d_really_is_negative(a->dst_dentry)) {
+		if (d_is_negative(a->dst_h_dentry))
+			err = au_may_add(a->dst_dentry, a->btgt,
+					 a->dst_h_parent, isdir);
+	} else {
+		if (unlikely(d_is_negative(a->dst_h_dentry)))
+			goto out;
+		h_inode = d_inode(a->dst_h_dentry);
+		if (h_inode->i_nlink)
+			err = au_may_del(a->dst_dentry, a->btgt,
+					 a->dst_h_parent, isdir);
+	}
+
+out:
+	if (unlikely(err == -ENOENT || err == -EEXIST))
+		err = -EIO;
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * locking order
+ * (VFS)
+ * - src_dir and dir by lock_rename()
+ * - inode if exitsts
+ * (aufs)
+ * - lock all
+ *   + src_dentry and dentry by aufs_read_and_write_lock2() which calls,
+ *     + si_read_lock
+ *     + di_write_lock2_child()
+ *       + di_write_lock_child()
+ *	   + ii_write_lock_child()
+ *       + di_write_lock_child2()
+ *	   + ii_write_lock_child2()
+ *     + src_parent and parent
+ *       + di_write_lock_parent()
+ *	   + ii_write_lock_parent()
+ *       + di_write_lock_parent2()
+ *	   + ii_write_lock_parent2()
+ *   + lower src_dir and dir by vfsub_lock_rename()
+ *   + verify the every relationships between child and parent. if any
+ *     of them failed, unlock all and return -EBUSY.
+ */
+static void au_ren_unlock(struct au_ren_args *a)
+{
+	vfsub_unlock_rename(a->src_h_parent, a->src_hdir,
+			    a->dst_h_parent, a->dst_hdir);
+	if (au_ftest_ren(a->flags, MNT_WRITE))
+		vfsub_mnt_drop_write(au_br_mnt(a->br));
+}
+
+static int au_ren_lock(struct au_ren_args *a)
+{
+	int err;
+	unsigned int udba;
+
+	err = 0;
+	a->src_h_parent = au_h_dptr(a->src_parent, a->btgt);
+	a->src_hdir = au_hi(a->src_dir, a->btgt);
+	a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt);
+	a->dst_hdir = au_hi(a->dst_dir, a->btgt);
+
+	err = vfsub_mnt_want_write(au_br_mnt(a->br));
+	if (unlikely(err))
+		goto out;
+	au_fset_ren(a->flags, MNT_WRITE);
+	a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir,
+				      a->dst_h_parent, a->dst_hdir);
+	udba = au_opt_udba(a->src_dentry->d_sb);
+	if (unlikely(a->src_hdir->hi_inode != d_inode(a->src_h_parent)
+		     || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent)))
+		err = au_busy_or_stale();
+	if (!err && au_dbstart(a->src_dentry) == a->btgt)
+		err = au_h_verify(a->src_h_dentry, udba,
+				  d_inode(a->src_h_parent), a->src_h_parent,
+				  a->br);
+	if (!err && au_dbstart(a->dst_dentry) == a->btgt)
+		err = au_h_verify(a->dst_h_dentry, udba,
+				  d_inode(a->dst_h_parent), a->dst_h_parent,
+				  a->br);
+	if (!err)
+		goto out; /* success */
+
+	err = au_busy_or_stale();
+	au_ren_unlock(a);
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void au_ren_refresh_dir(struct au_ren_args *a)
+{
+	struct inode *dir;
+
+	dir = a->dst_dir;
+	dir->i_version++;
+	if (au_ftest_ren(a->flags, ISDIR)) {
+		/* is this updating defined in POSIX? */
+		au_cpup_attr_timesizes(a->src_inode);
+		au_cpup_attr_nlink(dir, /*force*/1);
+	}
+
+	au_dir_ts(dir, a->btgt);
+
+	if (au_ftest_ren(a->flags, ISSAMEDIR))
+		return;
+
+	dir = a->src_dir;
+	dir->i_version++;
+	if (au_ftest_ren(a->flags, ISDIR))
+		au_cpup_attr_nlink(dir, /*force*/1);
+	au_dir_ts(dir, a->btgt);
+}
+
+static void au_ren_refresh(struct au_ren_args *a)
+{
+	aufs_bindex_t bend, bindex;
+	struct dentry *d, *h_d;
+	struct inode *i, *h_i;
+	struct super_block *sb;
+
+	d = a->dst_dentry;
+	d_drop(d);
+	if (a->h_dst)
+		/* already dget-ed by au_ren_or_cpup() */
+		au_set_h_dptr(d, a->btgt, a->h_dst);
+
+	i = a->dst_inode;
+	if (i) {
+		if (!au_ftest_ren(a->flags, ISDIR))
+			vfsub_drop_nlink(i);
+		else {
+			vfsub_dead_dir(i);
+			au_cpup_attr_timesizes(i);
+		}
+		au_update_dbrange(d, /*do_put_zero*/1);
+	} else {
+		bend = a->btgt;
+		for (bindex = au_dbstart(d); bindex < bend; bindex++)
+			au_set_h_dptr(d, bindex, NULL);
+		bend = au_dbend(d);
+		for (bindex = a->btgt + 1; bindex <= bend; bindex++)
+			au_set_h_dptr(d, bindex, NULL);
+		au_update_dbrange(d, /*do_put_zero*/0);
+	}
+
+	d = a->src_dentry;
+	au_set_dbwh(d, -1);
+	bend = au_dbend(d);
+	for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
+		h_d = au_h_dptr(d, bindex);
+		if (h_d)
+			au_set_h_dptr(d, bindex, NULL);
+	}
+	au_set_dbend(d, a->btgt);
+
+	sb = d->d_sb;
+	i = a->src_inode;
+	if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i))
+		return; /* success */
+
+	bend = au_ibend(i);
+	for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
+		h_i = au_h_iptr(i, bindex);
+		if (h_i) {
+			au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0);
+			/* ignore this error */
+			au_set_h_iptr(i, bindex, NULL, 0);
+		}
+	}
+	au_set_ibend(i, a->btgt);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* mainly for link(2) and rename(2) */
+int au_wbr(struct dentry *dentry, aufs_bindex_t btgt)
+{
+	aufs_bindex_t bdiropq, bwh;
+	struct dentry *parent;
+	struct au_branch *br;
+
+	parent = dentry->d_parent;
+	IMustLock(d_inode(parent)); /* dir is locked */
+
+	bdiropq = au_dbdiropq(parent);
+	bwh = au_dbwh(dentry);
+	br = au_sbr(dentry->d_sb, btgt);
+	if (au_br_rdonly(br)
+	    || (0 <= bdiropq && bdiropq < btgt)
+	    || (0 <= bwh && bwh < btgt))
+		btgt = -1;
+
+	AuDbg("btgt %d\n", btgt);
+	return btgt;
+}
+
+/* sets src_bstart, dst_bstart and btgt */
+static int au_ren_wbr(struct au_ren_args *a)
+{
+	int err;
+	struct au_wr_dir_args wr_dir_args = {
+		/* .force_btgt	= -1, */
+		.flags		= AuWrDir_ADD_ENTRY
+	};
+
+	a->src_bstart = au_dbstart(a->src_dentry);
+	a->dst_bstart = au_dbstart(a->dst_dentry);
+	if (au_ftest_ren(a->flags, ISDIR))
+		au_fset_wrdir(wr_dir_args.flags, ISDIR);
+	wr_dir_args.force_btgt = a->src_bstart;
+	if (a->dst_inode && a->dst_bstart < a->src_bstart)
+		wr_dir_args.force_btgt = a->dst_bstart;
+	wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt);
+	err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args);
+	a->btgt = err;
+
+	return err;
+}
+
+static void au_ren_dt(struct au_ren_args *a)
+{
+	a->h_path.dentry = a->src_h_parent;
+	au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path);
+	if (!au_ftest_ren(a->flags, ISSAMEDIR)) {
+		a->h_path.dentry = a->dst_h_parent;
+		au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path);
+	}
+
+	au_fclr_ren(a->flags, DT_DSTDIR);
+	if (!au_ftest_ren(a->flags, ISDIR))
+		return;
+
+	a->h_path.dentry = a->src_h_dentry;
+	au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path);
+	if (d_is_positive(a->dst_h_dentry)) {
+		au_fset_ren(a->flags, DT_DSTDIR);
+		a->h_path.dentry = a->dst_h_dentry;
+		au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path);
+	}
+}
+
+static void au_ren_rev_dt(int err, struct au_ren_args *a)
+{
+	struct dentry *h_d;
+	struct mutex *h_mtx;
+
+	au_dtime_revert(a->src_dt + AuPARENT);
+	if (!au_ftest_ren(a->flags, ISSAMEDIR))
+		au_dtime_revert(a->dst_dt + AuPARENT);
+
+	if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) {
+		h_d = a->src_dt[AuCHILD].dt_h_path.dentry;
+		h_mtx = &d_inode(h_d)->i_mutex;
+		mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
+		au_dtime_revert(a->src_dt + AuCHILD);
+		mutex_unlock(h_mtx);
+
+		if (au_ftest_ren(a->flags, DT_DSTDIR)) {
+			h_d = a->dst_dt[AuCHILD].dt_h_path.dentry;
+			h_mtx = &d_inode(h_d)->i_mutex;
+			mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
+			au_dtime_revert(a->dst_dt + AuCHILD);
+			mutex_unlock(h_mtx);
+		}
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
+		struct inode *_dst_dir, struct dentry *_dst_dentry)
+{
+	int err, flags;
+	/* reduce stack space */
+	struct au_ren_args *a;
+
+	AuDbg("%pd, %pd\n", _src_dentry, _dst_dentry);
+	IMustLock(_src_dir);
+	IMustLock(_dst_dir);
+
+	err = -ENOMEM;
+	BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE);
+	a = kzalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+
+	a->src_dir = _src_dir;
+	a->src_dentry = _src_dentry;
+	a->src_inode = NULL;
+	if (d_really_is_positive(a->src_dentry))
+		a->src_inode = d_inode(a->src_dentry);
+	a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */
+	a->dst_dir = _dst_dir;
+	a->dst_dentry = _dst_dentry;
+	a->dst_inode = NULL;
+	if (d_really_is_positive(a->dst_dentry))
+		a->dst_inode = d_inode(a->dst_dentry);
+	a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */
+	if (a->dst_inode) {
+		IMustLock(a->dst_inode);
+		au_igrab(a->dst_inode);
+	}
+
+	err = -ENOTDIR;
+	flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN;
+	if (d_is_dir(a->src_dentry)) {
+		au_fset_ren(a->flags, ISDIR);
+		if (unlikely(d_really_is_positive(a->dst_dentry)
+			     && !d_is_dir(a->dst_dentry)))
+			goto out_free;
+		flags |= AuLock_DIRS;
+	}
+	err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, flags);
+	if (unlikely(err))
+		goto out_free;
+
+	err = au_d_hashed_positive(a->src_dentry);
+	if (unlikely(err))
+		goto out_unlock;
+	err = -ENOENT;
+	if (a->dst_inode) {
+		/*
+		 * If it is a dir, VFS unhash dst_dentry before this
+		 * function. It means we cannot rely upon d_unhashed().
+		 */
+		if (unlikely(!a->dst_inode->i_nlink))
+			goto out_unlock;
+		if (!S_ISDIR(a->dst_inode->i_mode)) {
+			err = au_d_hashed_positive(a->dst_dentry);
+			if (unlikely(err))
+				goto out_unlock;
+		} else if (unlikely(IS_DEADDIR(a->dst_inode)))
+			goto out_unlock;
+	} else if (unlikely(d_unhashed(a->dst_dentry)))
+		goto out_unlock;
+
+	/*
+	 * is it possible?
+	 * yes, it happened (in linux-3.3-rcN) but I don't know why.
+	 * there may exist a problem somewhere else.
+	 */
+	err = -EINVAL;
+	if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry)))
+		goto out_unlock;
+
+	au_fset_ren(a->flags, ISSAMEDIR); /* temporary */
+	di_write_lock_parent(a->dst_parent);
+
+	/* which branch we process */
+	err = au_ren_wbr(a);
+	if (unlikely(err < 0))
+		goto out_parent;
+	a->br = au_sbr(a->dst_dentry->d_sb, a->btgt);
+	a->h_path.mnt = au_br_mnt(a->br);
+
+	/* are they available to be renamed */
+	err = au_ren_may_dir(a);
+	if (unlikely(err))
+		goto out_children;
+
+	/* prepare the writable parent dir on the same branch */
+	if (a->dst_bstart == a->btgt) {
+		au_fset_ren(a->flags, WHDST);
+	} else {
+		err = au_cpup_dirs(a->dst_dentry, a->btgt);
+		if (unlikely(err))
+			goto out_children;
+	}
+
+	if (a->src_dir != a->dst_dir) {
+		/*
+		 * this temporary unlock is safe,
+		 * because both dir->i_mutex are locked.
+		 */
+		di_write_unlock(a->dst_parent);
+		di_write_lock_parent(a->src_parent);
+		err = au_wr_dir_need_wh(a->src_dentry,
+					au_ftest_ren(a->flags, ISDIR),
+					&a->btgt);
+		di_write_unlock(a->src_parent);
+		di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1);
+		au_fclr_ren(a->flags, ISSAMEDIR);
+	} else
+		err = au_wr_dir_need_wh(a->src_dentry,
+					au_ftest_ren(a->flags, ISDIR),
+					&a->btgt);
+	if (unlikely(err < 0))
+		goto out_children;
+	if (err)
+		au_fset_ren(a->flags, WHSRC);
+
+	/* cpup src */
+	if (a->src_bstart != a->btgt) {
+		struct au_pin pin;
+
+		err = au_pin(&pin, a->src_dentry, a->btgt,
+			     au_opt_udba(a->src_dentry->d_sb),
+			     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
+		if (!err) {
+			struct au_cp_generic cpg = {
+				.dentry	= a->src_dentry,
+				.bdst	= a->btgt,
+				.bsrc	= a->src_bstart,
+				.len	= -1,
+				.pin	= &pin,
+				.flags	= AuCpup_DTIME | AuCpup_HOPEN
+			};
+			AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart);
+			err = au_sio_cpup_simple(&cpg);
+			au_unpin(&pin);
+		}
+		if (unlikely(err))
+			goto out_children;
+		a->src_bstart = a->btgt;
+		a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt);
+		au_fset_ren(a->flags, WHSRC);
+	}
+
+	/* lock them all */
+	err = au_ren_lock(a);
+	if (unlikely(err))
+		/* leave the copied-up one */
+		goto out_children;
+
+	if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE))
+		err = au_may_ren(a);
+	else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN))
+		err = -ENAMETOOLONG;
+	if (unlikely(err))
+		goto out_hdir;
+
+	/* store timestamps to be revertible */
+	au_ren_dt(a);
+
+	/* here we go */
+	err = do_rename(a);
+	if (unlikely(err))
+		goto out_dt;
+
+	/* update dir attributes */
+	au_ren_refresh_dir(a);
+
+	/* dput/iput all lower dentries */
+	au_ren_refresh(a);
+
+	goto out_hdir; /* success */
+
+out_dt:
+	au_ren_rev_dt(err, a);
+out_hdir:
+	au_ren_unlock(a);
+out_children:
+	au_nhash_wh_free(&a->whlist);
+	if (err && a->dst_inode && a->dst_bstart != a->btgt) {
+		AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt);
+		au_set_h_dptr(a->dst_dentry, a->btgt, NULL);
+		au_set_dbstart(a->dst_dentry, a->dst_bstart);
+	}
+out_parent:
+	if (!err)
+		d_move(a->src_dentry, a->dst_dentry);
+	else {
+		au_update_dbstart(a->dst_dentry);
+		if (!a->dst_inode)
+			d_drop(a->dst_dentry);
+	}
+	if (au_ftest_ren(a->flags, ISSAMEDIR))
+		di_write_unlock(a->dst_parent);
+	else
+		di_write_unlock2(a->src_parent, a->dst_parent);
+out_unlock:
+	aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry);
+out_free:
+	iput(a->dst_inode);
+	if (a->thargs)
+		au_whtmp_rmdir_free(a->thargs);
+	kfree(a);
+out:
+	AuTraceErr(err);
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/iinfo.c
+++ linux-4.4.0/fs/aufs/iinfo.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * inode private data
+ */
+
+#include "aufs.h"
+
+struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex)
+{
+	struct inode *h_inode;
+
+	IiMustAnyLock(inode);
+
+	h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode;
+	AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
+	return h_inode;
+}
+
+/* todo: hard/soft set? */
+void au_hiput(struct au_hinode *hinode)
+{
+	au_hn_free(hinode);
+	dput(hinode->hi_whdentry);
+	iput(hinode->hi_inode);
+}
+
+unsigned int au_hi_flags(struct inode *inode, int isdir)
+{
+	unsigned int flags;
+	const unsigned int mnt_flags = au_mntflags(inode->i_sb);
+
+	flags = 0;
+	if (au_opt_test(mnt_flags, XINO))
+		au_fset_hi(flags, XINO);
+	if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY))
+		au_fset_hi(flags, HNOTIFY);
+	return flags;
+}
+
+void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
+		   struct inode *h_inode, unsigned int flags)
+{
+	struct au_hinode *hinode;
+	struct inode *hi;
+	struct au_iinfo *iinfo = au_ii(inode);
+
+	IiMustWriteLock(inode);
+
+	hinode = iinfo->ii_hinode + bindex;
+	hi = hinode->hi_inode;
+	AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
+
+	if (hi)
+		au_hiput(hinode);
+	hinode->hi_inode = h_inode;
+	if (h_inode) {
+		int err;
+		struct super_block *sb = inode->i_sb;
+		struct au_branch *br;
+
+		AuDebugOn(inode->i_mode
+			  && (h_inode->i_mode & S_IFMT)
+			  != (inode->i_mode & S_IFMT));
+		if (bindex == iinfo->ii_bstart)
+			au_cpup_igen(inode, h_inode);
+		br = au_sbr(sb, bindex);
+		hinode->hi_id = br->br_id;
+		if (au_ftest_hi(flags, XINO)) {
+			err = au_xino_write(sb, bindex, h_inode->i_ino,
+					    inode->i_ino);
+			if (unlikely(err))
+				AuIOErr1("failed au_xino_write() %d\n", err);
+		}
+
+		if (au_ftest_hi(flags, HNOTIFY)
+		    && au_br_hnotifyable(br->br_perm)) {
+			err = au_hn_alloc(hinode, inode);
+			if (unlikely(err))
+				AuIOErr1("au_hn_alloc() %d\n", err);
+		}
+	}
+}
+
+void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex,
+		  struct dentry *h_wh)
+{
+	struct au_hinode *hinode;
+
+	IiMustWriteLock(inode);
+
+	hinode = au_ii(inode)->ii_hinode + bindex;
+	AuDebugOn(hinode->hi_whdentry);
+	hinode->hi_whdentry = h_wh;
+}
+
+void au_update_iigen(struct inode *inode, int half)
+{
+	struct au_iinfo *iinfo;
+	struct au_iigen *iigen;
+	unsigned int sigen;
+
+	sigen = au_sigen(inode->i_sb);
+	iinfo = au_ii(inode);
+	iigen = &iinfo->ii_generation;
+	spin_lock(&iigen->ig_spin);
+	iigen->ig_generation = sigen;
+	if (half)
+		au_ig_fset(iigen->ig_flags, HALF_REFRESHED);
+	else
+		au_ig_fclr(iigen->ig_flags, HALF_REFRESHED);
+	spin_unlock(&iigen->ig_spin);
+}
+
+/* it may be called at remount time, too */
+void au_update_ibrange(struct inode *inode, int do_put_zero)
+{
+	struct au_iinfo *iinfo;
+	aufs_bindex_t bindex, bend;
+
+	iinfo = au_ii(inode);
+	if (!iinfo)
+		return;
+
+	IiMustWriteLock(inode);
+
+	if (do_put_zero && iinfo->ii_bstart >= 0) {
+		for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
+		     bindex++) {
+			struct inode *h_i;
+
+			h_i = iinfo->ii_hinode[0 + bindex].hi_inode;
+			if (h_i
+			    && !h_i->i_nlink
+			    && !(h_i->i_state & I_LINKABLE))
+				au_set_h_iptr(inode, bindex, NULL, 0);
+		}
+	}
+
+	iinfo->ii_bstart = -1;
+	iinfo->ii_bend = -1;
+	bend = au_sbend(inode->i_sb);
+	for (bindex = 0; bindex <= bend; bindex++)
+		if (iinfo->ii_hinode[0 + bindex].hi_inode) {
+			iinfo->ii_bstart = bindex;
+			break;
+		}
+	if (iinfo->ii_bstart >= 0)
+		for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--)
+			if (iinfo->ii_hinode[0 + bindex].hi_inode) {
+				iinfo->ii_bend = bindex;
+				break;
+			}
+	AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void au_icntnr_init_once(void *_c)
+{
+	struct au_icntnr *c = _c;
+	struct au_iinfo *iinfo = &c->iinfo;
+	static struct lock_class_key aufs_ii;
+
+	spin_lock_init(&iinfo->ii_generation.ig_spin);
+	au_rw_init(&iinfo->ii_rwsem);
+	au_rw_class(&iinfo->ii_rwsem, &aufs_ii);
+	inode_init_once(&c->vfs_inode);
+}
+
+int au_iinfo_init(struct inode *inode)
+{
+	struct au_iinfo *iinfo;
+	struct super_block *sb;
+	int nbr, i;
+
+	sb = inode->i_sb;
+	iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
+	nbr = au_sbend(sb) + 1;
+	if (unlikely(nbr <= 0))
+		nbr = 1;
+	iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS);
+	if (iinfo->ii_hinode) {
+		au_ninodes_inc(sb);
+		for (i = 0; i < nbr; i++)
+			iinfo->ii_hinode[i].hi_id = -1;
+
+		iinfo->ii_generation.ig_generation = au_sigen(sb);
+		iinfo->ii_bstart = -1;
+		iinfo->ii_bend = -1;
+		iinfo->ii_vdir = NULL;
+		return 0;
+	}
+	return -ENOMEM;
+}
+
+int au_ii_realloc(struct au_iinfo *iinfo, int nbr)
+{
+	int err, sz;
+	struct au_hinode *hip;
+
+	AuRwMustWriteLock(&iinfo->ii_rwsem);
+
+	err = -ENOMEM;
+	sz = sizeof(*hip) * (iinfo->ii_bend + 1);
+	if (!sz)
+		sz = sizeof(*hip);
+	hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS);
+	if (hip) {
+		iinfo->ii_hinode = hip;
+		err = 0;
+	}
+
+	return err;
+}
+
+void au_iinfo_fin(struct inode *inode)
+{
+	struct au_iinfo *iinfo;
+	struct au_hinode *hi;
+	struct super_block *sb;
+	aufs_bindex_t bindex, bend;
+	const unsigned char unlinked = !inode->i_nlink;
+
+	iinfo = au_ii(inode);
+	/* bad_inode case */
+	if (!iinfo)
+		return;
+
+	sb = inode->i_sb;
+	au_ninodes_dec(sb);
+	if (si_pid_test(sb))
+		au_xino_delete_inode(inode, unlinked);
+	else {
+		/*
+		 * it is safe to hide the dependency between sbinfo and
+		 * sb->s_umount.
+		 */
+		lockdep_off();
+		si_noflush_read_lock(sb);
+		au_xino_delete_inode(inode, unlinked);
+		si_read_unlock(sb);
+		lockdep_on();
+	}
+
+	if (iinfo->ii_vdir)
+		au_vdir_free(iinfo->ii_vdir);
+
+	bindex = iinfo->ii_bstart;
+	if (bindex >= 0) {
+		hi = iinfo->ii_hinode + bindex;
+		bend = iinfo->ii_bend;
+		while (bindex++ <= bend) {
+			if (hi->hi_inode)
+				au_hiput(hi);
+			hi++;
+		}
+	}
+	kfree(iinfo->ii_hinode);
+	iinfo->ii_hinode = NULL;
+	AuRwDestroy(&iinfo->ii_rwsem);
+}
--- linux-4.4.0.orig/fs/aufs/inode.c
+++ linux-4.4.0/fs/aufs/inode.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * inode functions
+ */
+
+#include "aufs.h"
+
+struct inode *au_igrab(struct inode *inode)
+{
+	if (inode) {
+		AuDebugOn(!atomic_read(&inode->i_count));
+		ihold(inode);
+	}
+	return inode;
+}
+
+static void au_refresh_hinode_attr(struct inode *inode, int do_version)
+{
+	au_cpup_attr_all(inode, /*force*/0);
+	au_update_iigen(inode, /*half*/1);
+	if (do_version)
+		inode->i_version++;
+}
+
+static int au_ii_refresh(struct inode *inode, int *update)
+{
+	int err, e;
+	umode_t type;
+	aufs_bindex_t bindex, new_bindex;
+	struct super_block *sb;
+	struct au_iinfo *iinfo;
+	struct au_hinode *p, *q, tmp;
+
+	IiMustWriteLock(inode);
+
+	*update = 0;
+	sb = inode->i_sb;
+	type = inode->i_mode & S_IFMT;
+	iinfo = au_ii(inode);
+	err = au_ii_realloc(iinfo, au_sbend(sb) + 1);
+	if (unlikely(err))
+		goto out;
+
+	AuDebugOn(iinfo->ii_bstart < 0);
+	p = iinfo->ii_hinode + iinfo->ii_bstart;
+	for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
+	     bindex++, p++) {
+		if (!p->hi_inode)
+			continue;
+
+		AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT));
+		new_bindex = au_br_index(sb, p->hi_id);
+		if (new_bindex == bindex)
+			continue;
+
+		if (new_bindex < 0) {
+			*update = 1;
+			au_hiput(p);
+			p->hi_inode = NULL;
+			continue;
+		}
+
+		if (new_bindex < iinfo->ii_bstart)
+			iinfo->ii_bstart = new_bindex;
+		if (iinfo->ii_bend < new_bindex)
+			iinfo->ii_bend = new_bindex;
+		/* swap two lower inode, and loop again */
+		q = iinfo->ii_hinode + new_bindex;
+		tmp = *q;
+		*q = *p;
+		*p = tmp;
+		if (tmp.hi_inode) {
+			bindex--;
+			p--;
+		}
+	}
+	au_update_ibrange(inode, /*do_put_zero*/0);
+	e = au_dy_irefresh(inode);
+	if (unlikely(e && !err))
+		err = e;
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+void au_refresh_iop(struct inode *inode, int force_getattr)
+{
+	int type;
+	struct au_sbinfo *sbi = au_sbi(inode->i_sb);
+	const struct inode_operations *iop
+		= force_getattr ? aufs_iop : sbi->si_iop_array;
+
+	if (inode->i_op == iop)
+		return;
+
+	switch (inode->i_mode & S_IFMT) {
+	case S_IFDIR:
+		type = AuIop_DIR;
+		break;
+	case S_IFLNK:
+		type = AuIop_SYMLINK;
+		break;
+	default:
+		type = AuIop_OTHER;
+		break;
+	}
+
+	inode->i_op = iop + type;
+	/* unnecessary smp_wmb() */
+}
+
+int au_refresh_hinode_self(struct inode *inode)
+{
+	int err, update;
+
+	err = au_ii_refresh(inode, &update);
+	if (!err)
+		au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
+
+	AuTraceErr(err);
+	return err;
+}
+
+int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
+{
+	int err, e, update;
+	unsigned int flags;
+	umode_t mode;
+	aufs_bindex_t bindex, bend;
+	unsigned char isdir;
+	struct au_hinode *p;
+	struct au_iinfo *iinfo;
+
+	err = au_ii_refresh(inode, &update);
+	if (unlikely(err))
+		goto out;
+
+	update = 0;
+	iinfo = au_ii(inode);
+	p = iinfo->ii_hinode + iinfo->ii_bstart;
+	mode = (inode->i_mode & S_IFMT);
+	isdir = S_ISDIR(mode);
+	flags = au_hi_flags(inode, isdir);
+	bend = au_dbend(dentry);
+	for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
+		struct inode *h_i, *h_inode;
+		struct dentry *h_d;
+
+		h_d = au_h_dptr(dentry, bindex);
+		if (!h_d || d_is_negative(h_d))
+			continue;
+
+		h_inode = d_inode(h_d);
+		AuDebugOn(mode != (h_inode->i_mode & S_IFMT));
+		if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
+			h_i = au_h_iptr(inode, bindex);
+			if (h_i) {
+				if (h_i == h_inode)
+					continue;
+				err = -EIO;
+				break;
+			}
+		}
+		if (bindex < iinfo->ii_bstart)
+			iinfo->ii_bstart = bindex;
+		if (iinfo->ii_bend < bindex)
+			iinfo->ii_bend = bindex;
+		au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags);
+		update = 1;
+	}
+	au_update_ibrange(inode, /*do_put_zero*/0);
+	e = au_dy_irefresh(inode);
+	if (unlikely(e && !err))
+		err = e;
+	if (!err)
+		au_refresh_hinode_attr(inode, update && isdir);
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+static int set_inode(struct inode *inode, struct dentry *dentry)
+{
+	int err;
+	unsigned int flags;
+	umode_t mode;
+	aufs_bindex_t bindex, bstart, btail;
+	unsigned char isdir;
+	struct dentry *h_dentry;
+	struct inode *h_inode;
+	struct au_iinfo *iinfo;
+	struct inode_operations *iop;
+
+	IiMustWriteLock(inode);
+
+	err = 0;
+	isdir = 0;
+	iop = au_sbi(inode->i_sb)->si_iop_array;
+	bstart = au_dbstart(dentry);
+	h_dentry = au_h_dptr(dentry, bstart);
+	h_inode = d_inode(h_dentry);
+	mode = h_inode->i_mode;
+	switch (mode & S_IFMT) {
+	case S_IFREG:
+		btail = au_dbtail(dentry);
+		inode->i_op = iop + AuIop_OTHER;
+		inode->i_fop = &aufs_file_fop;
+		err = au_dy_iaop(inode, bstart, h_inode);
+		if (unlikely(err))
+			goto out;
+		break;
+	case S_IFDIR:
+		isdir = 1;
+		btail = au_dbtaildir(dentry);
+		inode->i_op = iop + AuIop_DIR;
+		inode->i_fop = &aufs_dir_fop;
+		break;
+	case S_IFLNK:
+		btail = au_dbtail(dentry);
+		inode->i_op = iop + AuIop_SYMLINK;
+		break;
+	case S_IFBLK:
+	case S_IFCHR:
+	case S_IFIFO:
+	case S_IFSOCK:
+		btail = au_dbtail(dentry);
+		inode->i_op = iop + AuIop_OTHER;
+		init_special_inode(inode, mode, h_inode->i_rdev);
+		break;
+	default:
+		AuIOErr("Unknown file type 0%o\n", mode);
+		err = -EIO;
+		goto out;
+	}
+
+	/* do not set hnotify for whiteouted dirs (SHWH mode) */
+	flags = au_hi_flags(inode, isdir);
+	if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)
+	    && au_ftest_hi(flags, HNOTIFY)
+	    && dentry->d_name.len > AUFS_WH_PFX_LEN
+	    && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
+		au_fclr_hi(flags, HNOTIFY);
+	iinfo = au_ii(inode);
+	iinfo->ii_bstart = bstart;
+	iinfo->ii_bend = btail;
+	for (bindex = bstart; bindex <= btail; bindex++) {
+		h_dentry = au_h_dptr(dentry, bindex);
+		if (h_dentry)
+			au_set_h_iptr(inode, bindex,
+				      au_igrab(d_inode(h_dentry)), flags);
+	}
+	au_cpup_attr_all(inode, /*force*/1);
+	/*
+	 * to force calling aufs_get_acl() every time,
+	 * do not call cache_no_acl() for aufs inode.
+	 */
+
+out:
+	return err;
+}
+
+/*
+ * successful returns with iinfo write_locked
+ * minus: errno
+ * zero: success, matched
+ * plus: no error, but unmatched
+ */
+static int reval_inode(struct inode *inode, struct dentry *dentry)
+{
+	int err;
+	unsigned int gen;
+	struct au_iigen iigen;
+	aufs_bindex_t bindex, bend;
+	struct inode *h_inode, *h_dinode;
+	struct dentry *h_dentry;
+
+	/*
+	 * before this function, if aufs got any iinfo lock, it must be only
+	 * one, the parent dir.
+	 * it can happen by UDBA and the obsoleted inode number.
+	 */
+	err = -EIO;
+	if (unlikely(inode->i_ino == parent_ino(dentry)))
+		goto out;
+
+	err = 1;
+	ii_write_lock_new_child(inode);
+	h_dentry = au_h_dptr(dentry, au_dbstart(dentry));
+	h_dinode = d_inode(h_dentry);
+	bend = au_ibend(inode);
+	for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
+		h_inode = au_h_iptr(inode, bindex);
+		if (!h_inode || h_inode != h_dinode)
+			continue;
+
+		err = 0;
+		gen = au_iigen(inode, &iigen);
+		if (gen == au_digen(dentry)
+		    && !au_ig_ftest(iigen.ig_flags, HALF_REFRESHED))
+			break;
+
+		/* fully refresh inode using dentry */
+		err = au_refresh_hinode(inode, dentry);
+		if (!err)
+			au_update_iigen(inode, /*half*/0);
+		break;
+	}
+
+	if (unlikely(err))
+		ii_write_unlock(inode);
+out:
+	return err;
+}
+
+int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
+	   unsigned int d_type, ino_t *ino)
+{
+	int err;
+	struct mutex *mtx;
+
+	/* prevent hardlinked inode number from race condition */
+	mtx = NULL;
+	if (d_type != DT_DIR) {
+		mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx;
+		mutex_lock(mtx);
+	}
+	err = au_xino_read(sb, bindex, h_ino, ino);
+	if (unlikely(err))
+		goto out;
+
+	if (!*ino) {
+		err = -EIO;
+		*ino = au_xino_new_ino(sb);
+		if (unlikely(!*ino))
+			goto out;
+		err = au_xino_write(sb, bindex, h_ino, *ino);
+		if (unlikely(err))
+			goto out;
+	}
+
+out:
+	if (mtx)
+		mutex_unlock(mtx);
+	return err;
+}
+
+/* successful returns with iinfo write_locked */
+/* todo: return with unlocked? */
+struct inode *au_new_inode(struct dentry *dentry, int must_new)
+{
+	struct inode *inode, *h_inode;
+	struct dentry *h_dentry;
+	struct super_block *sb;
+	struct mutex *mtx;
+	ino_t h_ino, ino;
+	int err;
+	aufs_bindex_t bstart;
+
+	sb = dentry->d_sb;
+	bstart = au_dbstart(dentry);
+	h_dentry = au_h_dptr(dentry, bstart);
+	h_inode = d_inode(h_dentry);
+	h_ino = h_inode->i_ino;
+
+	/*
+	 * stop 'race'-ing between hardlinks under different
+	 * parents.
+	 */
+	mtx = NULL;
+	if (!d_is_dir(h_dentry))
+		mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx;
+
+new_ino:
+	if (mtx)
+		mutex_lock(mtx);
+	err = au_xino_read(sb, bstart, h_ino, &ino);
+	inode = ERR_PTR(err);
+	if (unlikely(err))
+		goto out;
+
+	if (!ino) {
+		ino = au_xino_new_ino(sb);
+		if (unlikely(!ino)) {
+			inode = ERR_PTR(-EIO);
+			goto out;
+		}
+	}
+
+	AuDbg("i%lu\n", (unsigned long)ino);
+	inode = au_iget_locked(sb, ino);
+	err = PTR_ERR(inode);
+	if (IS_ERR(inode))
+		goto out;
+
+	AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW));
+	if (inode->i_state & I_NEW) {
+		/* verbose coding for lock class name */
+		if (unlikely(d_is_symlink(h_dentry)))
+			au_rw_class(&au_ii(inode)->ii_rwsem,
+				    au_lc_key + AuLcSymlink_IIINFO);
+		else if (unlikely(d_is_dir(h_dentry)))
+			au_rw_class(&au_ii(inode)->ii_rwsem,
+				    au_lc_key + AuLcDir_IIINFO);
+		else /* likely */
+			au_rw_class(&au_ii(inode)->ii_rwsem,
+				    au_lc_key + AuLcNonDir_IIINFO);
+
+		ii_write_lock_new_child(inode);
+		err = set_inode(inode, dentry);
+		if (!err) {
+			unlock_new_inode(inode);
+			goto out; /* success */
+		}
+
+		/*
+		 * iget_failed() calls iput(), but we need to call
+		 * ii_write_unlock() after iget_failed(). so dirty hack for
+		 * i_count.
+		 */
+		atomic_inc(&inode->i_count);
+		iget_failed(inode);
+		ii_write_unlock(inode);
+		au_xino_write(sb, bstart, h_ino, /*ino*/0);
+		/* ignore this error */
+		goto out_iput;
+	} else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) {
+		/*
+		 * horrible race condition between lookup, readdir and copyup
+		 * (or something).
+		 */
+		if (mtx)
+			mutex_unlock(mtx);
+		err = reval_inode(inode, dentry);
+		if (unlikely(err < 0)) {
+			mtx = NULL;
+			goto out_iput;
+		}
+
+		if (!err) {
+			mtx = NULL;
+			goto out; /* success */
+		} else if (mtx)
+			mutex_lock(mtx);
+	}
+
+	if (unlikely(au_test_fs_unique_ino(h_inode)))
+		AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir,"
+			" b%d, %s, %pd, hi%lu, i%lu.\n",
+			bstart, au_sbtype(h_dentry->d_sb), dentry,
+			(unsigned long)h_ino, (unsigned long)ino);
+	ino = 0;
+	err = au_xino_write(sb, bstart, h_ino, /*ino*/0);
+	if (!err) {
+		iput(inode);
+		if (mtx)
+			mutex_unlock(mtx);
+		goto new_ino;
+	}
+
+out_iput:
+	iput(inode);
+	inode = ERR_PTR(err);
+out:
+	if (mtx)
+		mutex_unlock(mtx);
+	return inode;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
+	       struct inode *inode)
+{
+	int err;
+	struct inode *hi;
+
+	err = au_br_rdonly(au_sbr(sb, bindex));
+
+	/* pseudo-link after flushed may happen out of bounds */
+	if (!err
+	    && inode
+	    && au_ibstart(inode) <= bindex
+	    && bindex <= au_ibend(inode)) {
+		/*
+		 * permission check is unnecessary since vfsub routine
+		 * will be called later
+		 */
+		hi = au_h_iptr(inode, bindex);
+		if (hi)
+			err = IS_IMMUTABLE(hi) ? -EROFS : 0;
+	}
+
+	return err;
+}
+
+int au_test_h_perm(struct inode *h_inode, int mask)
+{
+	if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID))
+		return 0;
+	return inode_permission(h_inode, mask);
+}
+
+int au_test_h_perm_sio(struct inode *h_inode, int mask)
+{
+	if (au_test_nfs(h_inode->i_sb)
+	    && (mask & MAY_WRITE)
+	    && S_ISDIR(h_inode->i_mode))
+		mask |= MAY_READ; /* force permission check */
+	return au_test_h_perm(h_inode, mask);
+}
--- linux-4.4.0.orig/fs/aufs/inode.h
+++ linux-4.4.0/fs/aufs/inode.h
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * inode operations
+ */
+
+#ifndef __AUFS_INODE_H__
+#define __AUFS_INODE_H__
+
+#ifdef __KERNEL__
+
+#include <linux/fsnotify.h>
+#include "rwsem.h"
+
+struct vfsmount;
+
+struct au_hnotify {
+#ifdef CONFIG_AUFS_HNOTIFY
+#ifdef CONFIG_AUFS_HFSNOTIFY
+	/* never use fsnotify_add_vfsmount_mark() */
+	struct fsnotify_mark		hn_mark;
+#endif
+	struct inode			*hn_aufs_inode;	/* no get/put */
+#endif
+} ____cacheline_aligned_in_smp;
+
+struct au_hinode {
+	struct inode		*hi_inode;
+	aufs_bindex_t		hi_id;
+#ifdef CONFIG_AUFS_HNOTIFY
+	struct au_hnotify	*hi_notify;
+#endif
+
+	/* reference to the copied-up whiteout with get/put */
+	struct dentry		*hi_whdentry;
+};
+
+/* ig_flags */
+#define AuIG_HALF_REFRESHED		1
+#define au_ig_ftest(flags, name)	((flags) & AuIG_##name)
+#define au_ig_fset(flags, name) \
+	do { (flags) |= AuIG_##name; } while (0)
+#define au_ig_fclr(flags, name) \
+	do { (flags) &= ~AuIG_##name; } while (0)
+
+struct au_iigen {
+	spinlock_t	ig_spin;
+	__u32		ig_generation, ig_flags;
+};
+
+struct au_vdir;
+struct au_iinfo {
+	struct au_iigen		ii_generation;
+	struct super_block	*ii_hsb1;	/* no get/put */
+
+	struct au_rwsem		ii_rwsem;
+	aufs_bindex_t		ii_bstart, ii_bend;
+	__u32			ii_higen;
+	struct au_hinode	*ii_hinode;
+	struct au_vdir		*ii_vdir;
+};
+
+struct au_icntnr {
+	struct au_iinfo iinfo;
+	struct inode vfs_inode;
+} ____cacheline_aligned_in_smp;
+
+/* au_pin flags */
+#define AuPin_DI_LOCKED		1
+#define AuPin_MNT_WRITE		(1 << 1)
+#define au_ftest_pin(flags, name)	((flags) & AuPin_##name)
+#define au_fset_pin(flags, name) \
+	do { (flags) |= AuPin_##name; } while (0)
+#define au_fclr_pin(flags, name) \
+	do { (flags) &= ~AuPin_##name; } while (0)
+
+struct au_pin {
+	/* input */
+	struct dentry *dentry;
+	unsigned int udba;
+	unsigned char lsc_di, lsc_hi, flags;
+	aufs_bindex_t bindex;
+
+	/* output */
+	struct dentry *parent;
+	struct au_hinode *hdir;
+	struct vfsmount *h_mnt;
+
+	/* temporary unlock/relock for copyup */
+	struct dentry *h_dentry, *h_parent;
+	struct au_branch *br;
+	struct task_struct *task;
+};
+
+void au_pin_hdir_unlock(struct au_pin *p);
+int au_pin_hdir_lock(struct au_pin *p);
+int au_pin_hdir_relock(struct au_pin *p);
+void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task);
+void au_pin_hdir_acquire_nest(struct au_pin *p);
+void au_pin_hdir_release(struct au_pin *p);
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct au_iinfo *au_ii(struct inode *inode)
+{
+	struct au_iinfo *iinfo;
+
+	iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
+	if (iinfo->ii_hinode)
+		return iinfo;
+	return NULL; /* debugging bad_inode case */
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* inode.c */
+struct inode *au_igrab(struct inode *inode);
+void au_refresh_iop(struct inode *inode, int force_getattr);
+int au_refresh_hinode_self(struct inode *inode);
+int au_refresh_hinode(struct inode *inode, struct dentry *dentry);
+int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
+	   unsigned int d_type, ino_t *ino);
+struct inode *au_new_inode(struct dentry *dentry, int must_new);
+int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
+	       struct inode *inode);
+int au_test_h_perm(struct inode *h_inode, int mask);
+int au_test_h_perm_sio(struct inode *h_inode, int mask);
+
+static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex,
+			    ino_t h_ino, unsigned int d_type, ino_t *ino)
+{
+#ifdef CONFIG_AUFS_SHWH
+	return au_ino(sb, bindex, h_ino, d_type, ino);
+#else
+	return 0;
+#endif
+}
+
+/* i_op.c */
+enum {
+	AuIop_SYMLINK,
+	AuIop_DIR,
+	AuIop_OTHER,
+	AuIop_Last
+};
+extern struct inode_operations aufs_iop[AuIop_Last],
+	aufs_iop_nogetattr[AuIop_Last];
+
+/* au_wr_dir flags */
+#define AuWrDir_ADD_ENTRY	1
+#define AuWrDir_ISDIR		(1 << 1)
+#define AuWrDir_TMPFILE		(1 << 2)
+#define au_ftest_wrdir(flags, name)	((flags) & AuWrDir_##name)
+#define au_fset_wrdir(flags, name) \
+	do { (flags) |= AuWrDir_##name; } while (0)
+#define au_fclr_wrdir(flags, name) \
+	do { (flags) &= ~AuWrDir_##name; } while (0)
+
+struct au_wr_dir_args {
+	aufs_bindex_t force_btgt;
+	unsigned char flags;
+};
+int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
+	      struct au_wr_dir_args *args);
+
+struct dentry *au_pinned_h_parent(struct au_pin *pin);
+void au_pin_init(struct au_pin *pin, struct dentry *dentry,
+		 aufs_bindex_t bindex, int lsc_di, int lsc_hi,
+		 unsigned int udba, unsigned char flags);
+int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
+	   unsigned int udba, unsigned char flags) __must_check;
+int au_do_pin(struct au_pin *pin) __must_check;
+void au_unpin(struct au_pin *pin);
+int au_reval_for_attr(struct dentry *dentry, unsigned int sigen);
+
+#define AuIcpup_DID_CPUP	1
+#define au_ftest_icpup(flags, name)	((flags) & AuIcpup_##name)
+#define au_fset_icpup(flags, name) \
+	do { (flags) |= AuIcpup_##name; } while (0)
+#define au_fclr_icpup(flags, name) \
+	do { (flags) &= ~AuIcpup_##name; } while (0)
+
+struct au_icpup_args {
+	unsigned char flags;
+	unsigned char pin_flags;
+	aufs_bindex_t btgt;
+	unsigned int udba;
+	struct au_pin pin;
+	struct path h_path;
+	struct inode *h_inode;
+};
+
+int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
+		     struct au_icpup_args *a);
+
+int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path);
+
+/* i_op_add.c */
+int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
+	       struct dentry *h_parent, int isdir);
+int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+	       dev_t dev);
+int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
+int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+		bool want_excl);
+struct vfsub_aopen_args;
+int au_aopen_or_create(struct inode *dir, struct dentry *dentry,
+		       struct vfsub_aopen_args *args);
+int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode);
+int aufs_link(struct dentry *src_dentry, struct inode *dir,
+	      struct dentry *dentry);
+int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
+
+/* i_op_del.c */
+int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup);
+int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
+	       struct dentry *h_parent, int isdir);
+int aufs_unlink(struct inode *dir, struct dentry *dentry);
+int aufs_rmdir(struct inode *dir, struct dentry *dentry);
+
+/* i_op_ren.c */
+int au_wbr(struct dentry *dentry, aufs_bindex_t btgt);
+int aufs_rename(struct inode *src_dir, struct dentry *src_dentry,
+		struct inode *dir, struct dentry *dentry);
+
+/* iinfo.c */
+struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex);
+void au_hiput(struct au_hinode *hinode);
+void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex,
+		  struct dentry *h_wh);
+unsigned int au_hi_flags(struct inode *inode, int isdir);
+
+/* hinode flags */
+#define AuHi_XINO	1
+#define AuHi_HNOTIFY	(1 << 1)
+#define au_ftest_hi(flags, name)	((flags) & AuHi_##name)
+#define au_fset_hi(flags, name) \
+	do { (flags) |= AuHi_##name; } while (0)
+#define au_fclr_hi(flags, name) \
+	do { (flags) &= ~AuHi_##name; } while (0)
+
+#ifndef CONFIG_AUFS_HNOTIFY
+#undef AuHi_HNOTIFY
+#define AuHi_HNOTIFY	0
+#endif
+
+void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
+		   struct inode *h_inode, unsigned int flags);
+
+void au_update_iigen(struct inode *inode, int half);
+void au_update_ibrange(struct inode *inode, int do_put_zero);
+
+void au_icntnr_init_once(void *_c);
+int au_iinfo_init(struct inode *inode);
+void au_iinfo_fin(struct inode *inode);
+int au_ii_realloc(struct au_iinfo *iinfo, int nbr);
+
+#ifdef CONFIG_PROC_FS
+/* plink.c */
+int au_plink_maint(struct super_block *sb, int flags);
+struct au_sbinfo;
+void au_plink_maint_leave(struct au_sbinfo *sbinfo);
+int au_plink_maint_enter(struct super_block *sb);
+#ifdef CONFIG_AUFS_DEBUG
+void au_plink_list(struct super_block *sb);
+#else
+AuStubVoid(au_plink_list, struct super_block *sb)
+#endif
+int au_plink_test(struct inode *inode);
+struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex);
+void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
+		     struct dentry *h_dentry);
+void au_plink_put(struct super_block *sb, int verbose);
+void au_plink_clean(struct super_block *sb, int verbose);
+void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id);
+#else
+AuStubInt0(au_plink_maint, struct super_block *sb, int flags);
+AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo);
+AuStubInt0(au_plink_maint_enter, struct super_block *sb);
+AuStubVoid(au_plink_list, struct super_block *sb);
+AuStubInt0(au_plink_test, struct inode *inode);
+AuStub(struct dentry *, au_plink_lkup, return NULL,
+       struct inode *inode, aufs_bindex_t bindex);
+AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex,
+	   struct dentry *h_dentry);
+AuStubVoid(au_plink_put, struct super_block *sb, int verbose);
+AuStubVoid(au_plink_clean, struct super_block *sb, int verbose);
+AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id);
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_AUFS_XATTR
+/* xattr.c */
+int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
+		  unsigned int verbose);
+ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size);
+ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value,
+		      size_t size);
+int aufs_setxattr(struct dentry *dentry, const char *name, const void *value,
+		  size_t size, int flags);
+int aufs_removexattr(struct dentry *dentry, const char *name);
+
+/* void au_xattr_init(struct super_block *sb); */
+#else
+AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src,
+	   int ignore_flags, unsigned int verbose);
+/* AuStubVoid(au_xattr_init, struct super_block *sb); */
+#endif
+
+#ifdef CONFIG_FS_POSIX_ACL
+struct posix_acl *aufs_get_acl(struct inode *inode, int type);
+int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+#endif
+
+#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL)
+enum {
+	AU_XATTR_SET,
+	AU_XATTR_REMOVE,
+	AU_ACL_SET
+};
+
+struct au_srxattr {
+	int type;
+	union {
+		struct {
+			const char	*name;
+			const void	*value;
+			size_t		size;
+			int		flags;
+		} set;
+		struct {
+			const char	*name;
+		} remove;
+		struct {
+			struct posix_acl *acl;
+			int		type;
+		} acl_set;
+	} u;
+};
+ssize_t au_srxattr(struct dentry *dentry, struct au_srxattr *arg);
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+/* lock subclass for iinfo */
+enum {
+	AuLsc_II_CHILD,		/* child first */
+	AuLsc_II_CHILD2,	/* rename(2), link(2), and cpup at hnotify */
+	AuLsc_II_CHILD3,	/* copyup dirs */
+	AuLsc_II_PARENT,	/* see AuLsc_I_PARENT in vfsub.h */
+	AuLsc_II_PARENT2,
+	AuLsc_II_PARENT3,	/* copyup dirs */
+	AuLsc_II_NEW_CHILD
+};
+
+/*
+ * ii_read_lock_child, ii_write_lock_child,
+ * ii_read_lock_child2, ii_write_lock_child2,
+ * ii_read_lock_child3, ii_write_lock_child3,
+ * ii_read_lock_parent, ii_write_lock_parent,
+ * ii_read_lock_parent2, ii_write_lock_parent2,
+ * ii_read_lock_parent3, ii_write_lock_parent3,
+ * ii_read_lock_new_child, ii_write_lock_new_child,
+ */
+#define AuReadLockFunc(name, lsc) \
+static inline void ii_read_lock_##name(struct inode *i) \
+{ \
+	au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \
+}
+
+#define AuWriteLockFunc(name, lsc) \
+static inline void ii_write_lock_##name(struct inode *i) \
+{ \
+	au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \
+}
+
+#define AuRWLockFuncs(name, lsc) \
+	AuReadLockFunc(name, lsc) \
+	AuWriteLockFunc(name, lsc)
+
+AuRWLockFuncs(child, CHILD);
+AuRWLockFuncs(child2, CHILD2);
+AuRWLockFuncs(child3, CHILD3);
+AuRWLockFuncs(parent, PARENT);
+AuRWLockFuncs(parent2, PARENT2);
+AuRWLockFuncs(parent3, PARENT3);
+AuRWLockFuncs(new_child, NEW_CHILD);
+
+#undef AuReadLockFunc
+#undef AuWriteLockFunc
+#undef AuRWLockFuncs
+
+/*
+ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock
+ */
+AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem);
+
+#define IiMustNoWaiters(i)	AuRwMustNoWaiters(&au_ii(i)->ii_rwsem)
+#define IiMustAnyLock(i)	AuRwMustAnyLock(&au_ii(i)->ii_rwsem)
+#define IiMustWriteLock(i)	AuRwMustWriteLock(&au_ii(i)->ii_rwsem)
+
+/* ---------------------------------------------------------------------- */
+
+static inline void au_icntnr_init(struct au_icntnr *c)
+{
+#ifdef CONFIG_AUFS_DEBUG
+	c->vfs_inode.i_mode = 0;
+#endif
+}
+
+static inline unsigned int au_iigen(struct inode *inode, struct au_iigen *iigen_arg)
+{
+	unsigned int gen;
+	struct au_iinfo *iinfo;
+	struct au_iigen *iigen;
+
+	iinfo = au_ii(inode);
+	iigen = &iinfo->ii_generation;
+	spin_lock(&iigen->ig_spin);
+	if (iigen_arg)
+		*iigen_arg = *iigen;
+	gen = iigen->ig_generation;
+	spin_unlock(&iigen->ig_spin);
+
+	return gen;
+}
+
+/* tiny test for inode number */
+/* tmpfs generation is too rough */
+static inline int au_test_higen(struct inode *inode, struct inode *h_inode)
+{
+	struct au_iinfo *iinfo;
+
+	iinfo = au_ii(inode);
+	AuRwMustAnyLock(&iinfo->ii_rwsem);
+	return !(iinfo->ii_hsb1 == h_inode->i_sb
+		 && iinfo->ii_higen == h_inode->i_generation);
+}
+
+static inline void au_iigen_dec(struct inode *inode)
+{
+	struct au_iinfo *iinfo;
+	struct au_iigen *iigen;
+
+	iinfo = au_ii(inode);
+	iigen = &iinfo->ii_generation;
+	spin_lock(&iigen->ig_spin);
+	iigen->ig_generation--;
+	spin_unlock(&iigen->ig_spin);
+}
+
+static inline int au_iigen_test(struct inode *inode, unsigned int sigen)
+{
+	int err;
+
+	err = 0;
+	if (unlikely(inode && au_iigen(inode, NULL) != sigen))
+		err = -EIO;
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static inline aufs_bindex_t au_ii_br_id(struct inode *inode,
+					aufs_bindex_t bindex)
+{
+	IiMustAnyLock(inode);
+	return au_ii(inode)->ii_hinode[0 + bindex].hi_id;
+}
+
+static inline aufs_bindex_t au_ibstart(struct inode *inode)
+{
+	IiMustAnyLock(inode);
+	return au_ii(inode)->ii_bstart;
+}
+
+static inline aufs_bindex_t au_ibend(struct inode *inode)
+{
+	IiMustAnyLock(inode);
+	return au_ii(inode)->ii_bend;
+}
+
+static inline struct au_vdir *au_ivdir(struct inode *inode)
+{
+	IiMustAnyLock(inode);
+	return au_ii(inode)->ii_vdir;
+}
+
+static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex)
+{
+	IiMustAnyLock(inode);
+	return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry;
+}
+
+static inline void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex)
+{
+	IiMustWriteLock(inode);
+	au_ii(inode)->ii_bstart = bindex;
+}
+
+static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex)
+{
+	IiMustWriteLock(inode);
+	au_ii(inode)->ii_bend = bindex;
+}
+
+static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir)
+{
+	IiMustWriteLock(inode);
+	au_ii(inode)->ii_vdir = vdir;
+}
+
+static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex)
+{
+	IiMustAnyLock(inode);
+	return au_ii(inode)->ii_hinode + bindex;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct dentry *au_pinned_parent(struct au_pin *pin)
+{
+	if (pin)
+		return pin->parent;
+	return NULL;
+}
+
+static inline struct inode *au_pinned_h_dir(struct au_pin *pin)
+{
+	if (pin && pin->hdir)
+		return pin->hdir->hi_inode;
+	return NULL;
+}
+
+static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin)
+{
+	if (pin)
+		return pin->hdir;
+	return NULL;
+}
+
+static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry)
+{
+	if (pin)
+		pin->dentry = dentry;
+}
+
+static inline void au_pin_set_parent_lflag(struct au_pin *pin,
+					   unsigned char lflag)
+{
+	if (pin) {
+		if (lflag)
+			au_fset_pin(pin->flags, DI_LOCKED);
+		else
+			au_fclr_pin(pin->flags, DI_LOCKED);
+	}
+}
+
+#if 0 /* reserved */
+static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent)
+{
+	if (pin) {
+		dput(pin->parent);
+		pin->parent = dget(parent);
+	}
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+struct au_branch;
+#ifdef CONFIG_AUFS_HNOTIFY
+struct au_hnotify_op {
+	void (*ctl)(struct au_hinode *hinode, int do_set);
+	int (*alloc)(struct au_hinode *hinode);
+
+	/*
+	 * if it returns true, the the caller should free hinode->hi_notify,
+	 * otherwise ->free() frees it.
+	 */
+	int (*free)(struct au_hinode *hinode,
+		    struct au_hnotify *hn) __must_check;
+
+	void (*fin)(void);
+	int (*init)(void);
+
+	int (*reset_br)(unsigned int udba, struct au_branch *br, int perm);
+	void (*fin_br)(struct au_branch *br);
+	int (*init_br)(struct au_branch *br, int perm);
+};
+
+/* hnotify.c */
+int au_hn_alloc(struct au_hinode *hinode, struct inode *inode);
+void au_hn_free(struct au_hinode *hinode);
+void au_hn_ctl(struct au_hinode *hinode, int do_set);
+void au_hn_reset(struct inode *inode, unsigned int flags);
+int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
+	       struct qstr *h_child_qstr, struct inode *h_child_inode);
+int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm);
+int au_hnotify_init_br(struct au_branch *br, int perm);
+void au_hnotify_fin_br(struct au_branch *br);
+int __init au_hnotify_init(void);
+void au_hnotify_fin(void);
+
+/* hfsnotify.c */
+extern const struct au_hnotify_op au_hnotify_op;
+
+static inline
+void au_hn_init(struct au_hinode *hinode)
+{
+	hinode->hi_notify = NULL;
+}
+
+static inline struct au_hnotify *au_hn(struct au_hinode *hinode)
+{
+	return hinode->hi_notify;
+}
+
+#else
+AuStub(int, au_hn_alloc, return -EOPNOTSUPP,
+       struct au_hinode *hinode __maybe_unused,
+       struct inode *inode __maybe_unused)
+AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode)
+AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused)
+AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused,
+	   int do_set __maybe_unused)
+AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused,
+	   unsigned int flags __maybe_unused)
+AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused,
+	   struct au_branch *br __maybe_unused,
+	   int perm __maybe_unused)
+AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused,
+	   int perm __maybe_unused)
+AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused)
+AuStubInt0(__init au_hnotify_init, void)
+AuStubVoid(au_hnotify_fin, void)
+AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused)
+#endif /* CONFIG_AUFS_HNOTIFY */
+
+static inline void au_hn_suspend(struct au_hinode *hdir)
+{
+	au_hn_ctl(hdir, /*do_set*/0);
+}
+
+static inline void au_hn_resume(struct au_hinode *hdir)
+{
+	au_hn_ctl(hdir, /*do_set*/1);
+}
+
+static inline void au_hn_imtx_lock(struct au_hinode *hdir)
+{
+	mutex_lock(&hdir->hi_inode->i_mutex);
+	au_hn_suspend(hdir);
+}
+
+static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir,
+					  unsigned int sc __maybe_unused)
+{
+	mutex_lock_nested(&hdir->hi_inode->i_mutex, sc);
+	au_hn_suspend(hdir);
+}
+
+static inline void au_hn_imtx_unlock(struct au_hinode *hdir)
+{
+	au_hn_resume(hdir);
+	mutex_unlock(&hdir->hi_inode->i_mutex);
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_INODE_H__ */
--- linux-4.4.0.orig/fs/aufs/ioctl.c
+++ linux-4.4.0/fs/aufs/ioctl.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * ioctl
+ * plink-management and readdir in userspace.
+ * assist the pathconf(3) wrapper library.
+ * move-down
+ * File-based Hierarchical Storage Management.
+ */
+
+#include <linux/compat.h>
+#include <linux/file.h>
+#include "aufs.h"
+
+static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg)
+{
+	int err, fd;
+	aufs_bindex_t wbi, bindex, bend;
+	struct file *h_file;
+	struct super_block *sb;
+	struct dentry *root;
+	struct au_branch *br;
+	struct aufs_wbr_fd wbrfd = {
+		.oflags	= au_dir_roflags,
+		.brid	= -1
+	};
+	const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY
+		| O_NOATIME | O_CLOEXEC;
+
+	AuDebugOn(wbrfd.oflags & ~valid);
+
+	if (arg) {
+		err = copy_from_user(&wbrfd, arg, sizeof(wbrfd));
+		if (unlikely(err)) {
+			err = -EFAULT;
+			goto out;
+		}
+
+		err = -EINVAL;
+		AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid);
+		wbrfd.oflags |= au_dir_roflags;
+		AuDbg("0%o\n", wbrfd.oflags);
+		if (unlikely(wbrfd.oflags & ~valid))
+			goto out;
+	}
+
+	fd = get_unused_fd_flags(0);
+	err = fd;
+	if (unlikely(fd < 0))
+		goto out;
+
+	h_file = ERR_PTR(-EINVAL);
+	wbi = 0;
+	br = NULL;
+	sb = path->dentry->d_sb;
+	root = sb->s_root;
+	aufs_read_lock(root, AuLock_IR);
+	bend = au_sbend(sb);
+	if (wbrfd.brid >= 0) {
+		wbi = au_br_index(sb, wbrfd.brid);
+		if (unlikely(wbi < 0 || wbi > bend))
+			goto out_unlock;
+	}
+
+	h_file = ERR_PTR(-ENOENT);
+	br = au_sbr(sb, wbi);
+	if (!au_br_writable(br->br_perm)) {
+		if (arg)
+			goto out_unlock;
+
+		bindex = wbi + 1;
+		wbi = -1;
+		for (; bindex <= bend; bindex++) {
+			br = au_sbr(sb, bindex);
+			if (au_br_writable(br->br_perm)) {
+				wbi = bindex;
+				br = au_sbr(sb, wbi);
+				break;
+			}
+		}
+	}
+	AuDbg("wbi %d\n", wbi);
+	if (wbi >= 0)
+		h_file = au_h_open(root, wbi, wbrfd.oflags, NULL,
+				   /*force_wr*/0);
+
+out_unlock:
+	aufs_read_unlock(root, AuLock_IR);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out_fd;
+
+	atomic_dec(&br->br_count); /* cf. au_h_open() */
+	fd_install(fd, h_file);
+	err = fd;
+	goto out; /* success */
+
+out_fd:
+	put_unused_fd(fd);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long err;
+	struct dentry *dentry;
+
+	switch (cmd) {
+	case AUFS_CTL_RDU:
+	case AUFS_CTL_RDU_INO:
+		err = au_rdu_ioctl(file, cmd, arg);
+		break;
+
+	case AUFS_CTL_WBR_FD:
+		err = au_wbr_fd(&file->f_path, (void __user *)arg);
+		break;
+
+	case AUFS_CTL_IBUSY:
+		err = au_ibusy_ioctl(file, arg);
+		break;
+
+	case AUFS_CTL_BRINFO:
+		err = au_brinfo_ioctl(file, arg);
+		break;
+
+	case AUFS_CTL_FHSM_FD:
+		dentry = file->f_path.dentry;
+		if (IS_ROOT(dentry))
+			err = au_fhsm_fd(dentry->d_sb, arg);
+		else
+			err = -ENOTTY;
+		break;
+
+	default:
+		/* do not call the lower */
+		AuDbg("0x%x\n", cmd);
+		err = -ENOTTY;
+	}
+
+	AuTraceErr(err);
+	return err;
+}
+
+long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long err;
+
+	switch (cmd) {
+	case AUFS_CTL_MVDOWN:
+		err = au_mvdown(file->f_path.dentry, (void __user *)arg);
+		break;
+
+	case AUFS_CTL_WBR_FD:
+		err = au_wbr_fd(&file->f_path, (void __user *)arg);
+		break;
+
+	default:
+		/* do not call the lower */
+		AuDbg("0x%x\n", cmd);
+		err = -ENOTTY;
+	}
+
+	AuTraceErr(err);
+	return err;
+}
+
+#ifdef CONFIG_COMPAT
+long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	long err;
+
+	switch (cmd) {
+	case AUFS_CTL_RDU:
+	case AUFS_CTL_RDU_INO:
+		err = au_rdu_compat_ioctl(file, cmd, arg);
+		break;
+
+	case AUFS_CTL_IBUSY:
+		err = au_ibusy_compat_ioctl(file, arg);
+		break;
+
+	case AUFS_CTL_BRINFO:
+		err = au_brinfo_compat_ioctl(file, arg);
+		break;
+
+	default:
+		err = aufs_ioctl_dir(file, cmd, arg);
+	}
+
+	AuTraceErr(err);
+	return err;
+}
+
+long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
+			      unsigned long arg)
+{
+	return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
--- linux-4.4.0.orig/fs/aufs/loop.c
+++ linux-4.4.0/fs/aufs/loop.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * support for loopback block device as a branch
+ */
+
+#include "aufs.h"
+
+/* added into drivers/block/loop.c */
+static struct file *(*backing_file_func)(struct super_block *sb);
+
+/*
+ * test if two lower dentries have overlapping branches.
+ */
+int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding)
+{
+	struct super_block *h_sb;
+	struct file *backing_file;
+
+	if (unlikely(!backing_file_func)) {
+		/* don't load "loop" module here */
+		backing_file_func = symbol_get(loop_backing_file);
+		if (unlikely(!backing_file_func))
+			/* "loop" module is not loaded */
+			return 0;
+	}
+
+	h_sb = h_adding->d_sb;
+	backing_file = backing_file_func(h_sb);
+	if (!backing_file)
+		return 0;
+
+	h_adding = backing_file->f_path.dentry;
+	/*
+	 * h_adding can be local NFS.
+	 * in this case aufs cannot detect the loop.
+	 */
+	if (unlikely(h_adding->d_sb == sb))
+		return 1;
+	return !!au_test_subdir(h_adding, sb->s_root);
+}
+
+/* true if a kernel thread named 'loop[0-9].*' accesses a file */
+int au_test_loopback_kthread(void)
+{
+	int ret;
+	struct task_struct *tsk = current;
+	char c, comm[sizeof(tsk->comm)];
+
+	ret = 0;
+	if (tsk->flags & PF_KTHREAD) {
+		get_task_comm(comm, tsk);
+		c = comm[4];
+		ret = ('0' <= c && c <= '9'
+		       && !strncmp(comm, "loop", 4));
+	}
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#define au_warn_loopback_step	16
+static int au_warn_loopback_nelem = au_warn_loopback_step;
+static unsigned long *au_warn_loopback_array;
+
+void au_warn_loopback(struct super_block *h_sb)
+{
+	int i, new_nelem;
+	unsigned long *a, magic;
+	static DEFINE_SPINLOCK(spin);
+
+	magic = h_sb->s_magic;
+	spin_lock(&spin);
+	a = au_warn_loopback_array;
+	for (i = 0; i < au_warn_loopback_nelem && *a; i++)
+		if (a[i] == magic) {
+			spin_unlock(&spin);
+			return;
+		}
+
+	/* h_sb is new to us, print it */
+	if (i < au_warn_loopback_nelem) {
+		a[i] = magic;
+		goto pr;
+	}
+
+	/* expand the array */
+	new_nelem = au_warn_loopback_nelem + au_warn_loopback_step;
+	a = au_kzrealloc(au_warn_loopback_array,
+			 au_warn_loopback_nelem * sizeof(unsigned long),
+			 new_nelem * sizeof(unsigned long), GFP_ATOMIC);
+	if (a) {
+		au_warn_loopback_nelem = new_nelem;
+		au_warn_loopback_array = a;
+		a[i] = magic;
+		goto pr;
+	}
+
+	spin_unlock(&spin);
+	AuWarn1("realloc failed, ignored\n");
+	return;
+
+pr:
+	spin_unlock(&spin);
+	pr_warn("you may want to try another patch for loopback file "
+		"on %s(0x%lx) branch\n", au_sbtype(h_sb), magic);
+}
+
+int au_loopback_init(void)
+{
+	int err;
+	struct super_block *sb __maybe_unused;
+
+	BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(unsigned long));
+
+	err = 0;
+	au_warn_loopback_array = kcalloc(au_warn_loopback_step,
+					 sizeof(unsigned long), GFP_NOFS);
+	if (unlikely(!au_warn_loopback_array))
+		err = -ENOMEM;
+
+	return err;
+}
+
+void au_loopback_fin(void)
+{
+	if (backing_file_func)
+		symbol_put(loop_backing_file);
+	kfree(au_warn_loopback_array);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* support the loopback block device insude aufs */
+
+struct file *aufs_real_loop(struct file *file)
+{
+	struct file *f;
+
+	BUG_ON(!au_test_aufs(file->f_path.dentry->d_sb));
+	fi_read_lock(file);
+	f = au_hf_top(file);
+	fi_read_unlock(file);
+	AuDebugOn(!f);
+	return f;
+}
--- linux-4.4.0.orig/fs/aufs/loop.h
+++ linux-4.4.0/fs/aufs/loop.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * support for loopback mount as a branch
+ */
+
+#ifndef __AUFS_LOOP_H__
+#define __AUFS_LOOP_H__
+
+#ifdef __KERNEL__
+
+struct dentry;
+struct super_block;
+
+#ifdef CONFIG_AUFS_BDEV_LOOP
+/* drivers/block/loop.c */
+struct file *loop_backing_file(struct super_block *sb);
+
+/* loop.c */
+int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding);
+int au_test_loopback_kthread(void);
+void au_warn_loopback(struct super_block *h_sb);
+
+int au_loopback_init(void);
+void au_loopback_fin(void);
+
+struct file *aufs_real_loop(struct file *file);
+#else
+AuStub(struct file *, loop_backing_file, return NULL)
+
+AuStubInt0(au_test_loopback_overlap, struct super_block *sb,
+	   struct dentry *h_adding)
+AuStubInt0(au_test_loopback_kthread, void)
+AuStubVoid(au_warn_loopback, struct super_block *h_sb)
+
+AuStubInt0(au_loopback_init, void)
+AuStubVoid(au_loopback_fin, void)
+
+AuStub(struct file *, aufs_real_loop, return NULL, struct file *file)
+#endif /* BLK_DEV_LOOP */
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_LOOP_H__ */
--- linux-4.4.0.orig/fs/aufs/magic.mk
+++ linux-4.4.0/fs/aufs/magic.mk
@@ -0,0 +1,30 @@
+
+# defined in ${srctree}/fs/fuse/inode.c
+# tristate
+ifdef CONFIG_FUSE_FS
+ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546
+endif
+
+# defined in ${srctree}/fs/xfs/xfs_sb.h
+# tristate
+ifdef CONFIG_XFS_FS
+ccflags-y += -DXFS_SB_MAGIC=0x58465342
+endif
+
+# defined in ${srctree}/fs/configfs/mount.c
+# tristate
+ifdef CONFIG_CONFIGFS_FS
+ccflags-y += -DCONFIGFS_MAGIC=0x62656570
+endif
+
+# defined in ${srctree}/fs/ubifs/ubifs.h
+# tristate
+ifdef CONFIG_UBIFS_FS
+ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905
+endif
+
+# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h
+# tristate
+ifdef CONFIG_HFSPLUS_FS
+ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b
+endif
--- linux-4.4.0.orig/fs/aufs/module.c
+++ linux-4.4.0/fs/aufs/module.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * module global variables and operations
+ */
+
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include "aufs.h"
+
+void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp)
+{
+	if (new_sz <= nused)
+		return p;
+
+	p = krealloc(p, new_sz, gfp);
+	if (p)
+		memset(p + nused, 0, new_sz - nused);
+	return p;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * aufs caches
+ */
+struct kmem_cache *au_cachep[AuCache_Last];
+static int __init au_cache_init(void)
+{
+	au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once);
+	if (au_cachep[AuCache_DINFO])
+		/* SLAB_DESTROY_BY_RCU */
+		au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr,
+							au_icntnr_init_once);
+	if (au_cachep[AuCache_ICNTNR])
+		au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo,
+						       au_fi_init_once);
+	if (au_cachep[AuCache_FINFO])
+		au_cachep[AuCache_VDIR] = AuCache(au_vdir);
+	if (au_cachep[AuCache_VDIR])
+		au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr);
+	if (au_cachep[AuCache_DEHSTR])
+		return 0;
+
+	return -ENOMEM;
+}
+
+static void au_cache_fin(void)
+{
+	int i;
+
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
+
+	/* excluding AuCache_HNOTIFY */
+	BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last);
+	for (i = 0; i < AuCache_HNOTIFY; i++) {
+		kmem_cache_destroy(au_cachep[i]);
+		au_cachep[i] = NULL;
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_dir_roflags;
+
+#ifdef CONFIG_AUFS_SBILIST
+/*
+ * iterate_supers_type() doesn't protect us from
+ * remounting (branch management)
+ */
+struct au_splhead au_sbilist;
+#endif
+
+struct lock_class_key au_lc_key[AuLcKey_Last];
+
+/*
+ * functions for module interface.
+ */
+MODULE_LICENSE("GPL");
+/* MODULE_LICENSE("GPL v2"); */
+MODULE_AUTHOR("Junjiro R. Okajima <aufs-users@lists.sourceforge.net>");
+MODULE_DESCRIPTION(AUFS_NAME
+	" -- Advanced multi layered unification filesystem");
+MODULE_VERSION(AUFS_VERSION);
+MODULE_ALIAS_FS(AUFS_NAME);
+
+/* this module parameter has no meaning when SYSFS is disabled */
+int sysaufs_brs = 1;
+MODULE_PARM_DESC(brs, "use <sysfs>/fs/aufs/si_*/brN");
+module_param_named(brs, sysaufs_brs, int, S_IRUGO);
+
+/* this module parameter has no meaning when USER_NS is disabled */
+bool au_userns;
+MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns");
+module_param_named(allow_userns, au_userns, bool, S_IRUGO);
+
+/* ---------------------------------------------------------------------- */
+
+static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */
+
+int au_seq_path(struct seq_file *seq, struct path *path)
+{
+	int err;
+
+	err = seq_path(seq, path, au_esc_chars);
+	if (err > 0)
+		err = 0;
+	else if (err < 0)
+		err = -ENOMEM;
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int __init aufs_init(void)
+{
+	int err, i;
+	char *p;
+
+	p = au_esc_chars;
+	for (i = 1; i <= ' '; i++)
+		*p++ = i;
+	*p++ = '\\';
+	*p++ = '\x7f';
+	*p = 0;
+
+	au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE);
+
+	memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop));
+	for (i = 0; i < AuIop_Last; i++)
+		aufs_iop_nogetattr[i].getattr = NULL;
+
+	au_sbilist_init();
+	sysaufs_brs_init();
+	au_debug_init();
+	au_dy_init();
+	err = sysaufs_init();
+	if (unlikely(err))
+		goto out;
+	err = au_procfs_init();
+	if (unlikely(err))
+		goto out_sysaufs;
+	err = au_wkq_init();
+	if (unlikely(err))
+		goto out_procfs;
+	err = au_loopback_init();
+	if (unlikely(err))
+		goto out_wkq;
+	err = au_hnotify_init();
+	if (unlikely(err))
+		goto out_loopback;
+	err = au_sysrq_init();
+	if (unlikely(err))
+		goto out_hin;
+	err = au_cache_init();
+	if (unlikely(err))
+		goto out_sysrq;
+
+	aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0;
+	err = register_filesystem(&aufs_fs_type);
+	if (unlikely(err))
+		goto out_cache;
+
+	/* since we define pr_fmt, call printk directly */
+	printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n");
+	goto out; /* success */
+
+out_cache:
+	au_cache_fin();
+out_sysrq:
+	au_sysrq_fin();
+out_hin:
+	au_hnotify_fin();
+out_loopback:
+	au_loopback_fin();
+out_wkq:
+	au_wkq_fin();
+out_procfs:
+	au_procfs_fin();
+out_sysaufs:
+	sysaufs_fin();
+	au_dy_fin();
+out:
+	return err;
+}
+
+static void __exit aufs_exit(void)
+{
+	unregister_filesystem(&aufs_fs_type);
+	au_cache_fin();
+	au_sysrq_fin();
+	au_hnotify_fin();
+	au_loopback_fin();
+	au_wkq_fin();
+	au_procfs_fin();
+	sysaufs_fin();
+	au_dy_fin();
+}
+
+module_init(aufs_init);
+module_exit(aufs_exit);
--- linux-4.4.0.orig/fs/aufs/module.h
+++ linux-4.4.0/fs/aufs/module.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * module initialization and module-global
+ */
+
+#ifndef __AUFS_MODULE_H__
+#define __AUFS_MODULE_H__
+
+#ifdef __KERNEL__
+
+#include <linux/slab.h>
+
+struct path;
+struct seq_file;
+
+/* module parameters */
+extern int sysaufs_brs;
+extern bool au_userns;
+
+/* ---------------------------------------------------------------------- */
+
+extern int au_dir_roflags;
+
+enum {
+	AuLcNonDir_FIINFO,
+	AuLcNonDir_DIINFO,
+	AuLcNonDir_IIINFO,
+
+	AuLcDir_FIINFO,
+	AuLcDir_DIINFO,
+	AuLcDir_IIINFO,
+
+	AuLcSymlink_DIINFO,
+	AuLcSymlink_IIINFO,
+
+	AuLcKey_Last
+};
+extern struct lock_class_key au_lc_key[AuLcKey_Last];
+
+void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp);
+int au_seq_path(struct seq_file *seq, struct path *path);
+
+#ifdef CONFIG_PROC_FS
+/* procfs.c */
+int __init au_procfs_init(void);
+void au_procfs_fin(void);
+#else
+AuStubInt0(au_procfs_init, void);
+AuStubVoid(au_procfs_fin, void);
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+/* kmem cache */
+enum {
+	AuCache_DINFO,
+	AuCache_ICNTNR,
+	AuCache_FINFO,
+	AuCache_VDIR,
+	AuCache_DEHSTR,
+	AuCache_HNOTIFY, /* must be last */
+	AuCache_Last
+};
+
+#define AuCacheFlags		(SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD)
+#define AuCache(type)		KMEM_CACHE(type, AuCacheFlags)
+#define AuCacheCtor(type, ctor)	\
+	kmem_cache_create(#type, sizeof(struct type), \
+			  __alignof__(struct type), AuCacheFlags, ctor)
+
+extern struct kmem_cache *au_cachep[];
+
+#define AuCacheFuncs(name, index) \
+static inline struct au_##name *au_cache_alloc_##name(void) \
+{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \
+static inline void au_cache_free_##name(struct au_##name *p) \
+{ kmem_cache_free(au_cachep[AuCache_##index], p); }
+
+AuCacheFuncs(dinfo, DINFO);
+AuCacheFuncs(icntnr, ICNTNR);
+AuCacheFuncs(finfo, FINFO);
+AuCacheFuncs(vdir, VDIR);
+AuCacheFuncs(vdir_dehstr, DEHSTR);
+#ifdef CONFIG_AUFS_HNOTIFY
+AuCacheFuncs(hnotify, HNOTIFY);
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_MODULE_H__ */
--- linux-4.4.0.orig/fs/aufs/mvdown.c
+++ linux-4.4.0/fs/aufs/mvdown.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2011-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * move-down, opposite of copy-up
+ */
+
+#include "aufs.h"
+
+struct au_mvd_args {
+	struct {
+		struct super_block *h_sb;
+		struct dentry *h_parent;
+		struct au_hinode *hdir;
+		struct inode *h_dir, *h_inode;
+		struct au_pin pin;
+	} info[AUFS_MVDOWN_NARRAY];
+
+	struct aufs_mvdown mvdown;
+	struct dentry *dentry, *parent;
+	struct inode *inode, *dir;
+	struct super_block *sb;
+	aufs_bindex_t bopq, bwh, bfound;
+	unsigned char rename_lock;
+};
+
+#define mvd_errno		mvdown.au_errno
+#define mvd_bsrc		mvdown.stbr[AUFS_MVDOWN_UPPER].bindex
+#define mvd_src_brid		mvdown.stbr[AUFS_MVDOWN_UPPER].brid
+#define mvd_bdst		mvdown.stbr[AUFS_MVDOWN_LOWER].bindex
+#define mvd_dst_brid		mvdown.stbr[AUFS_MVDOWN_LOWER].brid
+
+#define mvd_h_src_sb		info[AUFS_MVDOWN_UPPER].h_sb
+#define mvd_h_src_parent	info[AUFS_MVDOWN_UPPER].h_parent
+#define mvd_hdir_src		info[AUFS_MVDOWN_UPPER].hdir
+#define mvd_h_src_dir		info[AUFS_MVDOWN_UPPER].h_dir
+#define mvd_h_src_inode		info[AUFS_MVDOWN_UPPER].h_inode
+#define mvd_pin_src		info[AUFS_MVDOWN_UPPER].pin
+
+#define mvd_h_dst_sb		info[AUFS_MVDOWN_LOWER].h_sb
+#define mvd_h_dst_parent	info[AUFS_MVDOWN_LOWER].h_parent
+#define mvd_hdir_dst		info[AUFS_MVDOWN_LOWER].hdir
+#define mvd_h_dst_dir		info[AUFS_MVDOWN_LOWER].h_dir
+#define mvd_h_dst_inode		info[AUFS_MVDOWN_LOWER].h_inode
+#define mvd_pin_dst		info[AUFS_MVDOWN_LOWER].pin
+
+#define AU_MVD_PR(flag, ...) do {			\
+		if (flag)				\
+			pr_err(__VA_ARGS__);		\
+	} while (0)
+
+static int find_lower_writable(struct au_mvd_args *a)
+{
+	struct super_block *sb;
+	aufs_bindex_t bindex, bend;
+	struct au_branch *br;
+
+	sb = a->sb;
+	bindex = a->mvd_bsrc;
+	bend = au_sbend(sb);
+	if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER)
+		for (bindex++; bindex <= bend; bindex++) {
+			br = au_sbr(sb, bindex);
+			if (au_br_fhsm(br->br_perm)
+			    && (!(au_br_sb(br)->s_flags & MS_RDONLY)))
+				return bindex;
+		}
+	else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER))
+		for (bindex++; bindex <= bend; bindex++) {
+			br = au_sbr(sb, bindex);
+			if (!au_br_rdonly(br))
+				return bindex;
+		}
+	else
+		for (bindex++; bindex <= bend; bindex++) {
+			br = au_sbr(sb, bindex);
+			if (!(au_br_sb(br)->s_flags & MS_RDONLY)) {
+				if (au_br_rdonly(br))
+					a->mvdown.flags
+						|= AUFS_MVDOWN_ROLOWER_R;
+				return bindex;
+			}
+		}
+
+	return -1;
+}
+
+/* make the parent dir on bdst */
+static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+
+	err = 0;
+	a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc);
+	a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst);
+	a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc);
+	a->mvd_h_dst_parent = NULL;
+	if (au_dbend(a->parent) >= a->mvd_bdst)
+		a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst);
+	if (!a->mvd_h_dst_parent) {
+		err = au_cpdown_dirs(a->dentry, a->mvd_bdst);
+		if (unlikely(err)) {
+			AU_MVD_PR(dmsg, "cpdown_dirs failed\n");
+			goto out;
+		}
+		a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst);
+	}
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* lock them all */
+static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+	struct dentry *h_trap;
+
+	a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc);
+	a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst);
+	err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst,
+		     au_opt_udba(a->sb),
+		     AuPin_MNT_WRITE | AuPin_DI_LOCKED);
+	AuTraceErr(err);
+	if (unlikely(err)) {
+		AU_MVD_PR(dmsg, "pin_dst failed\n");
+		goto out;
+	}
+
+	if (a->mvd_h_src_sb != a->mvd_h_dst_sb) {
+		a->rename_lock = 0;
+		au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc,
+			    AuLsc_DI_PARENT, AuLsc_I_PARENT3,
+			    au_opt_udba(a->sb),
+			    AuPin_MNT_WRITE | AuPin_DI_LOCKED);
+		err = au_do_pin(&a->mvd_pin_src);
+		AuTraceErr(err);
+		a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent);
+		if (unlikely(err)) {
+			AU_MVD_PR(dmsg, "pin_src failed\n");
+			goto out_dst;
+		}
+		goto out; /* success */
+	}
+
+	a->rename_lock = 1;
+	au_pin_hdir_unlock(&a->mvd_pin_dst);
+	err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc,
+		     au_opt_udba(a->sb),
+		     AuPin_MNT_WRITE | AuPin_DI_LOCKED);
+	AuTraceErr(err);
+	a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent);
+	if (unlikely(err)) {
+		AU_MVD_PR(dmsg, "pin_src failed\n");
+		au_pin_hdir_lock(&a->mvd_pin_dst);
+		goto out_dst;
+	}
+	au_pin_hdir_unlock(&a->mvd_pin_src);
+	h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
+				   a->mvd_h_dst_parent, a->mvd_hdir_dst);
+	if (h_trap) {
+		err = (h_trap != a->mvd_h_src_parent);
+		if (err)
+			err = (h_trap != a->mvd_h_dst_parent);
+	}
+	BUG_ON(err); /* it should never happen */
+	if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) {
+		err = -EBUSY;
+		AuTraceErr(err);
+		vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
+				    a->mvd_h_dst_parent, a->mvd_hdir_dst);
+		au_pin_hdir_lock(&a->mvd_pin_src);
+		au_unpin(&a->mvd_pin_src);
+		au_pin_hdir_lock(&a->mvd_pin_dst);
+		goto out_dst;
+	}
+	goto out; /* success */
+
+out_dst:
+	au_unpin(&a->mvd_pin_dst);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	if (!a->rename_lock)
+		au_unpin(&a->mvd_pin_src);
+	else {
+		vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
+				    a->mvd_h_dst_parent, a->mvd_hdir_dst);
+		au_pin_hdir_lock(&a->mvd_pin_src);
+		au_unpin(&a->mvd_pin_src);
+		au_pin_hdir_lock(&a->mvd_pin_dst);
+	}
+	au_unpin(&a->mvd_pin_dst);
+}
+
+/* copy-down the file */
+static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+	struct au_cp_generic cpg = {
+		.dentry	= a->dentry,
+		.bdst	= a->mvd_bdst,
+		.bsrc	= a->mvd_bsrc,
+		.len	= -1,
+		.pin	= &a->mvd_pin_dst,
+		.flags	= AuCpup_DTIME | AuCpup_HOPEN
+	};
+
+	AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst);
+	if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER)
+		au_fset_cpup(cpg.flags, OVERWRITE);
+	if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER)
+		au_fset_cpup(cpg.flags, RWDST);
+	err = au_sio_cpdown_simple(&cpg);
+	if (unlikely(err))
+		AU_MVD_PR(dmsg, "cpdown failed\n");
+
+	AuTraceErr(err);
+	return err;
+}
+
+/*
+ * unlink the whiteout on bdst if exist which may be created by UDBA while we
+ * were sleeping
+ */
+static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+	struct path h_path;
+	struct au_branch *br;
+	struct inode *delegated;
+
+	br = au_sbr(a->sb, a->mvd_bdst);
+	h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br);
+	err = PTR_ERR(h_path.dentry);
+	if (IS_ERR(h_path.dentry)) {
+		AU_MVD_PR(dmsg, "wh_lkup failed\n");
+		goto out;
+	}
+
+	err = 0;
+	if (d_is_positive(h_path.dentry)) {
+		h_path.mnt = au_br_mnt(br);
+		delegated = NULL;
+		err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path,
+				   &delegated, /*force*/0);
+		if (unlikely(err == -EWOULDBLOCK)) {
+			pr_warn("cannot retry for NFSv4 delegation"
+				" for an internal unlink\n");
+			iput(delegated);
+		}
+		if (unlikely(err))
+			AU_MVD_PR(dmsg, "wh_unlink failed\n");
+	}
+	dput(h_path.dentry);
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/*
+ * unlink the topmost h_dentry
+ */
+static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+	struct path h_path;
+	struct inode *delegated;
+
+	h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc);
+	h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc);
+	delegated = NULL;
+	err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0);
+	if (unlikely(err == -EWOULDBLOCK)) {
+		pr_warn("cannot retry for NFSv4 delegation"
+			" for an internal unlink\n");
+		iput(delegated);
+	}
+	if (unlikely(err))
+		AU_MVD_PR(dmsg, "unlink failed\n");
+
+	AuTraceErr(err);
+	return err;
+}
+
+/* Since mvdown succeeded, we ignore an error of this function */
+static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+	struct au_branch *br;
+
+	a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED;
+	br = au_sbr(a->sb, a->mvd_bsrc);
+	err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs);
+	if (!err) {
+		br = au_sbr(a->sb, a->mvd_bdst);
+		a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id;
+		err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs);
+	}
+	if (!err)
+		a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED;
+	else
+		AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err);
+}
+
+/*
+ * copy-down the file and unlink the bsrc file.
+ * - unlink the bdst whout if exist
+ * - copy-down the file (with whtmp name and rename)
+ * - unlink the bsrc file
+ */
+static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+
+	err = au_do_mkdir(dmsg, a);
+	if (!err)
+		err = au_do_lock(dmsg, a);
+	if (unlikely(err))
+		goto out;
+
+	/*
+	 * do not revert the activities we made on bdst since they should be
+	 * harmless in aufs.
+	 */
+
+	err = au_do_cpdown(dmsg, a);
+	if (!err)
+		err = au_do_unlink_wh(dmsg, a);
+	if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER))
+		err = au_do_unlink(dmsg, a);
+	if (unlikely(err))
+		goto out_unlock;
+
+	AuDbg("%pd2, 0x%x, %d --> %d\n",
+	      a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst);
+	if (find_lower_writable(a) < 0)
+		a->mvdown.flags |= AUFS_MVDOWN_BOTTOM;
+
+	if (a->mvdown.flags & AUFS_MVDOWN_STFS)
+		au_do_stfs(dmsg, a);
+
+	/* maintain internal array */
+	if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) {
+		au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL);
+		au_set_dbstart(a->dentry, a->mvd_bdst);
+		au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0);
+		au_set_ibstart(a->inode, a->mvd_bdst);
+	} else {
+		/* hide the lower */
+		au_set_h_dptr(a->dentry, a->mvd_bdst, NULL);
+		au_set_dbend(a->dentry, a->mvd_bsrc);
+		au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0);
+		au_set_ibend(a->inode, a->mvd_bsrc);
+	}
+	if (au_dbend(a->dentry) < a->mvd_bdst)
+		au_set_dbend(a->dentry, a->mvd_bdst);
+	if (au_ibend(a->inode) < a->mvd_bdst)
+		au_set_ibend(a->inode, a->mvd_bdst);
+
+out_unlock:
+	au_do_unlock(dmsg, a);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* make sure the file is idle */
+static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err, plinked;
+
+	err = 0;
+	plinked = !!au_opt_test(au_mntflags(a->sb), PLINK);
+	if (au_dbstart(a->dentry) == a->mvd_bsrc
+	    && au_dcount(a->dentry) == 1
+	    && atomic_read(&a->inode->i_count) == 1
+	    /* && a->mvd_h_src_inode->i_nlink == 1 */
+	    && (!plinked || !au_plink_test(a->inode))
+	    && a->inode->i_nlink == 1)
+		goto out;
+
+	err = -EBUSY;
+	AU_MVD_PR(dmsg,
+		  "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n",
+		  a->mvd_bsrc, au_dbstart(a->dentry), au_dcount(a->dentry),
+		  atomic_read(&a->inode->i_count), a->inode->i_nlink,
+		  a->mvd_h_src_inode->i_nlink,
+		  plinked, plinked ? au_plink_test(a->inode) : 0);
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* make sure the parent dir is fine */
+static int au_mvd_args_parent(const unsigned char dmsg,
+			      struct au_mvd_args *a)
+{
+	int err;
+	aufs_bindex_t bindex;
+
+	err = 0;
+	if (unlikely(au_alive_dir(a->parent))) {
+		err = -ENOENT;
+		AU_MVD_PR(dmsg, "parent dir is dead\n");
+		goto out;
+	}
+
+	a->bopq = au_dbdiropq(a->parent);
+	bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst);
+	AuDbg("b%d\n", bindex);
+	if (unlikely((bindex >= 0 && bindex < a->mvd_bdst)
+		     || (a->bopq != -1 && a->bopq < a->mvd_bdst))) {
+		err = -EINVAL;
+		a->mvd_errno = EAU_MVDOWN_OPAQUE;
+		AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n",
+			  a->bopq, a->mvd_bdst);
+	}
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+static int au_mvd_args_intermediate(const unsigned char dmsg,
+				    struct au_mvd_args *a)
+{
+	int err;
+	struct au_dinfo *dinfo, *tmp;
+
+	/* lookup the next lower positive entry */
+	err = -ENOMEM;
+	tmp = au_di_alloc(a->sb, AuLsc_DI_TMP);
+	if (unlikely(!tmp))
+		goto out;
+
+	a->bfound = -1;
+	a->bwh = -1;
+	dinfo = au_di(a->dentry);
+	au_di_cp(tmp, dinfo);
+	au_di_swap(tmp, dinfo);
+
+	/* returns the number of positive dentries */
+	err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, /*type*/0);
+	if (!err)
+		a->bwh = au_dbwh(a->dentry);
+	else if (err > 0)
+		a->bfound = au_dbstart(a->dentry);
+
+	au_di_swap(tmp, dinfo);
+	au_rw_write_unlock(&tmp->di_rwsem);
+	au_di_free(tmp);
+	if (unlikely(err < 0))
+		AU_MVD_PR(dmsg, "failed look-up lower\n");
+
+	/*
+	 * here, we have these cases.
+	 * bfound == -1
+	 *	no positive dentry under bsrc. there are more sub-cases.
+	 *	bwh < 0
+	 *		there no whiteout, we can safely move-down.
+	 *	bwh <= bsrc
+	 *		impossible
+	 *	bsrc < bwh && bwh < bdst
+	 *		there is a whiteout on RO branch. cannot proceed.
+	 *	bwh == bdst
+	 *		there is a whiteout on the RW target branch. it should
+	 *		be removed.
+	 *	bdst < bwh
+	 *		there is a whiteout somewhere unrelated branch.
+	 * -1 < bfound && bfound <= bsrc
+	 *	impossible.
+	 * bfound < bdst
+	 *	found, but it is on RO branch between bsrc and bdst. cannot
+	 *	proceed.
+	 * bfound == bdst
+	 *	found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return
+	 *	error.
+	 * bdst < bfound
+	 *	found, after we create the file on bdst, it will be hidden.
+	 */
+
+	AuDebugOn(a->bfound == -1
+		  && a->bwh != -1
+		  && a->bwh <= a->mvd_bsrc);
+	AuDebugOn(-1 < a->bfound
+		  && a->bfound <= a->mvd_bsrc);
+
+	err = -EINVAL;
+	if (a->bfound == -1
+	    && a->mvd_bsrc < a->bwh
+	    && a->bwh != -1
+	    && a->bwh < a->mvd_bdst) {
+		a->mvd_errno = EAU_MVDOWN_WHITEOUT;
+		AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n",
+			  a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh);
+		goto out;
+	} else if (a->bfound != -1 && a->bfound < a->mvd_bdst) {
+		a->mvd_errno = EAU_MVDOWN_UPPER;
+		AU_MVD_PR(dmsg, "bdst %d, bfound %d\n",
+			  a->mvd_bdst, a->bfound);
+		goto out;
+	}
+
+	err = 0; /* success */
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+
+	err = 0;
+	if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER)
+	    && a->bfound == a->mvd_bdst)
+		err = -EEXIST;
+	AuTraceErr(err);
+	return err;
+}
+
+static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a)
+{
+	int err;
+	struct au_branch *br;
+
+	err = -EISDIR;
+	if (unlikely(S_ISDIR(a->inode->i_mode)))
+		goto out;
+
+	err = -EINVAL;
+	if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER))
+		a->mvd_bsrc = au_ibstart(a->inode);
+	else {
+		a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid);
+		if (unlikely(a->mvd_bsrc < 0
+			     || (a->mvd_bsrc < au_dbstart(a->dentry)
+				 || au_dbend(a->dentry) < a->mvd_bsrc
+				 || !au_h_dptr(a->dentry, a->mvd_bsrc))
+			     || (a->mvd_bsrc < au_ibstart(a->inode)
+				 || au_ibend(a->inode) < a->mvd_bsrc
+				 || !au_h_iptr(a->inode, a->mvd_bsrc)))) {
+			a->mvd_errno = EAU_MVDOWN_NOUPPER;
+			AU_MVD_PR(dmsg, "no upper\n");
+			goto out;
+		}
+	}
+	if (unlikely(a->mvd_bsrc == au_sbend(a->sb))) {
+		a->mvd_errno = EAU_MVDOWN_BOTTOM;
+		AU_MVD_PR(dmsg, "on the bottom\n");
+		goto out;
+	}
+	a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc);
+	br = au_sbr(a->sb, a->mvd_bsrc);
+	err = au_br_rdonly(br);
+	if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) {
+		if (unlikely(err))
+			goto out;
+	} else if (!(vfsub_native_ro(a->mvd_h_src_inode)
+		     || IS_APPEND(a->mvd_h_src_inode))) {
+		if (err)
+			a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R;
+		/* go on */
+	} else
+		goto out;
+
+	err = -EINVAL;
+	if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) {
+		a->mvd_bdst = find_lower_writable(a);
+		if (unlikely(a->mvd_bdst < 0)) {
+			a->mvd_errno = EAU_MVDOWN_BOTTOM;
+			AU_MVD_PR(dmsg, "no writable lower branch\n");
+			goto out;
+		}
+	} else {
+		a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid);
+		if (unlikely(a->mvd_bdst < 0
+			     || au_sbend(a->sb) < a->mvd_bdst)) {
+			a->mvd_errno = EAU_MVDOWN_NOLOWERBR;
+			AU_MVD_PR(dmsg, "no lower brid\n");
+			goto out;
+		}
+	}
+
+	err = au_mvd_args_busy(dmsg, a);
+	if (!err)
+		err = au_mvd_args_parent(dmsg, a);
+	if (!err)
+		err = au_mvd_args_intermediate(dmsg, a);
+	if (!err)
+		err = au_mvd_args_exist(dmsg, a);
+	if (!err)
+		AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst);
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg)
+{
+	int err, e;
+	unsigned char dmsg;
+	struct au_mvd_args *args;
+	struct inode *inode;
+
+	inode = d_inode(dentry);
+	err = -EPERM;
+	if (unlikely(!capable(CAP_SYS_ADMIN)))
+		goto out;
+
+	err = -ENOMEM;
+	args = kmalloc(sizeof(*args), GFP_NOFS);
+	if (unlikely(!args))
+		goto out;
+
+	err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown));
+	if (!err)
+		err = !access_ok(VERIFY_WRITE, uarg, sizeof(*uarg));
+	if (unlikely(err)) {
+		err = -EFAULT;
+		AuTraceErr(err);
+		goto out_free;
+	}
+	AuDbg("flags 0x%x\n", args->mvdown.flags);
+	args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R);
+	args->mvdown.au_errno = 0;
+	args->dentry = dentry;
+	args->inode = inode;
+	args->sb = dentry->d_sb;
+
+	err = -ENOENT;
+	dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG);
+	args->parent = dget_parent(dentry);
+	args->dir = d_inode(args->parent);
+	mutex_lock_nested(&args->dir->i_mutex, I_MUTEX_PARENT);
+	dput(args->parent);
+	if (unlikely(args->parent != dentry->d_parent)) {
+		AU_MVD_PR(dmsg, "parent dir is moved\n");
+		goto out_dir;
+	}
+
+	mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
+	err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW);
+	if (unlikely(err))
+		goto out_inode;
+
+	di_write_lock_parent(args->parent);
+	err = au_mvd_args(dmsg, args);
+	if (unlikely(err))
+		goto out_parent;
+
+	err = au_do_mvdown(dmsg, args);
+	if (unlikely(err))
+		goto out_parent;
+
+	au_cpup_attr_timesizes(args->dir);
+	au_cpup_attr_timesizes(inode);
+	if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER))
+		au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst));
+	/* au_digen_dec(dentry); */
+
+out_parent:
+	di_write_unlock(args->parent);
+	aufs_read_unlock(dentry, AuLock_DW);
+out_inode:
+	mutex_unlock(&inode->i_mutex);
+out_dir:
+	mutex_unlock(&args->dir->i_mutex);
+out_free:
+	e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown));
+	if (unlikely(e))
+		err = -EFAULT;
+	kfree(args);
+out:
+	AuTraceErr(err);
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/opts.c
+++ linux-4.4.0/fs/aufs/opts.c
@@ -0,0 +1,1859 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * mount options/flags
+ */
+
+#include <linux/namei.h>
+#include <linux/types.h> /* a distribution requires */
+#include <linux/parser.h>
+#include "aufs.h"
+
+/* ---------------------------------------------------------------------- */
+
+enum {
+	Opt_br,
+	Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend,
+	Opt_idel, Opt_imod,
+	Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash,
+	Opt_rdblk_def, Opt_rdhash_def,
+	Opt_xino, Opt_noxino,
+	Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino,
+	Opt_trunc_xino_path, Opt_itrunc_xino,
+	Opt_trunc_xib, Opt_notrunc_xib,
+	Opt_shwh, Opt_noshwh,
+	Opt_plink, Opt_noplink, Opt_list_plink,
+	Opt_udba,
+	Opt_dio, Opt_nodio,
+	Opt_diropq_a, Opt_diropq_w,
+	Opt_warn_perm, Opt_nowarn_perm,
+	Opt_wbr_copyup, Opt_wbr_create,
+	Opt_fhsm_sec,
+	Opt_verbose, Opt_noverbose,
+	Opt_sum, Opt_nosum, Opt_wsum,
+	Opt_dirperm1, Opt_nodirperm1,
+	Opt_acl, Opt_noacl,
+	Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
+};
+
+static match_table_t options = {
+	{Opt_br, "br=%s"},
+	{Opt_br, "br:%s"},
+
+	{Opt_add, "add=%d:%s"},
+	{Opt_add, "add:%d:%s"},
+	{Opt_add, "ins=%d:%s"},
+	{Opt_add, "ins:%d:%s"},
+	{Opt_append, "append=%s"},
+	{Opt_append, "append:%s"},
+	{Opt_prepend, "prepend=%s"},
+	{Opt_prepend, "prepend:%s"},
+
+	{Opt_del, "del=%s"},
+	{Opt_del, "del:%s"},
+	/* {Opt_idel, "idel:%d"}, */
+	{Opt_mod, "mod=%s"},
+	{Opt_mod, "mod:%s"},
+	/* {Opt_imod, "imod:%d:%s"}, */
+
+	{Opt_dirwh, "dirwh=%d"},
+
+	{Opt_xino, "xino=%s"},
+	{Opt_noxino, "noxino"},
+	{Opt_trunc_xino, "trunc_xino"},
+	{Opt_trunc_xino_v, "trunc_xino_v=%d:%d"},
+	{Opt_notrunc_xino, "notrunc_xino"},
+	{Opt_trunc_xino_path, "trunc_xino=%s"},
+	{Opt_itrunc_xino, "itrunc_xino=%d"},
+	/* {Opt_zxino, "zxino=%s"}, */
+	{Opt_trunc_xib, "trunc_xib"},
+	{Opt_notrunc_xib, "notrunc_xib"},
+
+#ifdef CONFIG_PROC_FS
+	{Opt_plink, "plink"},
+#else
+	{Opt_ignore_silent, "plink"},
+#endif
+
+	{Opt_noplink, "noplink"},
+
+#ifdef CONFIG_AUFS_DEBUG
+	{Opt_list_plink, "list_plink"},
+#endif
+
+	{Opt_udba, "udba=%s"},
+
+	{Opt_dio, "dio"},
+	{Opt_nodio, "nodio"},
+
+#ifdef CONFIG_AUFS_FHSM
+	{Opt_fhsm_sec, "fhsm_sec=%d"},
+#else
+	{Opt_ignore_silent, "fhsm_sec=%d"},
+#endif
+
+	{Opt_diropq_a, "diropq=always"},
+	{Opt_diropq_a, "diropq=a"},
+	{Opt_diropq_w, "diropq=whiteouted"},
+	{Opt_diropq_w, "diropq=w"},
+
+	{Opt_warn_perm, "warn_perm"},
+	{Opt_nowarn_perm, "nowarn_perm"},
+
+	/* keep them temporary */
+	{Opt_ignore_silent, "nodlgt"},
+	{Opt_ignore_silent, "clean_plink"},
+
+#ifdef CONFIG_AUFS_SHWH
+	{Opt_shwh, "shwh"},
+#endif
+	{Opt_noshwh, "noshwh"},
+
+	{Opt_dirperm1, "dirperm1"},
+	{Opt_nodirperm1, "nodirperm1"},
+
+	{Opt_verbose, "verbose"},
+	{Opt_verbose, "v"},
+	{Opt_noverbose, "noverbose"},
+	{Opt_noverbose, "quiet"},
+	{Opt_noverbose, "q"},
+	{Opt_noverbose, "silent"},
+
+	{Opt_sum, "sum"},
+	{Opt_nosum, "nosum"},
+	{Opt_wsum, "wsum"},
+
+	{Opt_rdcache, "rdcache=%d"},
+	{Opt_rdblk, "rdblk=%d"},
+	{Opt_rdblk_def, "rdblk=def"},
+	{Opt_rdhash, "rdhash=%d"},
+	{Opt_rdhash_def, "rdhash=def"},
+
+	{Opt_wbr_create, "create=%s"},
+	{Opt_wbr_create, "create_policy=%s"},
+	{Opt_wbr_copyup, "cpup=%s"},
+	{Opt_wbr_copyup, "copyup=%s"},
+	{Opt_wbr_copyup, "copyup_policy=%s"},
+
+	/* generic VFS flag */
+#ifdef CONFIG_FS_POSIX_ACL
+	{Opt_acl, "acl"},
+	{Opt_noacl, "noacl"},
+#else
+	{Opt_ignore_silent, "acl"},
+	{Opt_ignore_silent, "noacl"},
+#endif
+
+	/* internal use for the scripts */
+	{Opt_ignore_silent, "si=%s"},
+
+	{Opt_br, "dirs=%s"},
+	{Opt_ignore, "debug=%d"},
+	{Opt_ignore, "delete=whiteout"},
+	{Opt_ignore, "delete=all"},
+	{Opt_ignore, "imap=%s"},
+
+	/* temporary workaround, due to old mount(8)? */
+	{Opt_ignore_silent, "relatime"},
+
+	{Opt_err, NULL}
+};
+
+/* ---------------------------------------------------------------------- */
+
+static const char *au_parser_pattern(int val, match_table_t tbl)
+{
+	struct match_token *p;
+
+	p = tbl;
+	while (p->pattern) {
+		if (p->token == val)
+			return p->pattern;
+		p++;
+	}
+	BUG();
+	return "??";
+}
+
+static const char *au_optstr(int *val, match_table_t tbl)
+{
+	struct match_token *p;
+	int v;
+
+	v = *val;
+	if (!v)
+		goto out;
+	p = tbl;
+	while (p->pattern) {
+		if (p->token
+		    && (v & p->token) == p->token) {
+			*val &= ~p->token;
+			return p->pattern;
+		}
+		p++;
+	}
+
+out:
+	return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static match_table_t brperm = {
+	{AuBrPerm_RO, AUFS_BRPERM_RO},
+	{AuBrPerm_RR, AUFS_BRPERM_RR},
+	{AuBrPerm_RW, AUFS_BRPERM_RW},
+	{0, NULL}
+};
+
+static match_table_t brattr = {
+	/* general */
+	{AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG},
+	{AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL},
+	/* 'unpin' attrib is meaningless since linux-3.18-rc1 */
+	{AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN},
+#ifdef CONFIG_AUFS_FHSM
+	{AuBrAttr_FHSM, AUFS_BRATTR_FHSM},
+#endif
+#ifdef CONFIG_AUFS_XATTR
+	{AuBrAttr_ICEX, AUFS_BRATTR_ICEX},
+	{AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC},
+	{AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS},
+	{AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR},
+	{AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR},
+	{AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH},
+#endif
+
+	/* ro/rr branch */
+	{AuBrRAttr_WH, AUFS_BRRATTR_WH},
+
+	/* rw branch */
+	{AuBrWAttr_MOO, AUFS_BRWATTR_MOO},
+	{AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH},
+
+	{0, NULL}
+};
+
+static int br_attr_val(char *str, match_table_t table, substring_t args[])
+{
+	int attr, v;
+	char *p;
+
+	attr = 0;
+	do {
+		p = strchr(str, '+');
+		if (p)
+			*p = 0;
+		v = match_token(str, table, args);
+		if (v) {
+			if (v & AuBrAttr_CMOO_Mask)
+				attr &= ~AuBrAttr_CMOO_Mask;
+			attr |= v;
+		} else {
+			if (p)
+				*p = '+';
+			pr_warn("ignored branch attribute %s\n", str);
+			break;
+		}
+		if (p)
+			str = p + 1;
+	} while (p);
+
+	return attr;
+}
+
+static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm)
+{
+	int sz;
+	const char *p;
+	char *q;
+
+	q = str->a;
+	*q = 0;
+	p = au_optstr(&perm, brattr);
+	if (p) {
+		sz = strlen(p);
+		memcpy(q, p, sz + 1);
+		q += sz;
+	} else
+		goto out;
+
+	do {
+		p = au_optstr(&perm, brattr);
+		if (p) {
+			*q++ = '+';
+			sz = strlen(p);
+			memcpy(q, p, sz + 1);
+			q += sz;
+		}
+	} while (p);
+
+out:
+	return q - str->a;
+}
+
+static int noinline_for_stack br_perm_val(char *perm)
+{
+	int val, bad, sz;
+	char *p;
+	substring_t args[MAX_OPT_ARGS];
+	au_br_perm_str_t attr;
+
+	p = strchr(perm, '+');
+	if (p)
+		*p = 0;
+	val = match_token(perm, brperm, args);
+	if (!val) {
+		if (p)
+			*p = '+';
+		pr_warn("ignored branch permission %s\n", perm);
+		val = AuBrPerm_RO;
+		goto out;
+	}
+	if (!p)
+		goto out;
+
+	val |= br_attr_val(p + 1, brattr, args);
+
+	bad = 0;
+	switch (val & AuBrPerm_Mask) {
+	case AuBrPerm_RO:
+	case AuBrPerm_RR:
+		bad = val & AuBrWAttr_Mask;
+		val &= ~AuBrWAttr_Mask;
+		break;
+	case AuBrPerm_RW:
+		bad = val & AuBrRAttr_Mask;
+		val &= ~AuBrRAttr_Mask;
+		break;
+	}
+
+	/*
+	 * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs
+	 * does not treat it as an error, just warning.
+	 * this is a tiny guard for the user operation.
+	 */
+	if (val & AuBrAttr_UNPIN) {
+		bad |= AuBrAttr_UNPIN;
+		val &= ~AuBrAttr_UNPIN;
+	}
+
+	if (unlikely(bad)) {
+		sz = au_do_optstr_br_attr(&attr, bad);
+		AuDebugOn(!sz);
+		pr_warn("ignored branch attribute %s\n", attr.a);
+	}
+
+out:
+	return val;
+}
+
+void au_optstr_br_perm(au_br_perm_str_t *str, int perm)
+{
+	au_br_perm_str_t attr;
+	const char *p;
+	char *q;
+	int sz;
+
+	q = str->a;
+	p = au_optstr(&perm, brperm);
+	AuDebugOn(!p || !*p);
+	sz = strlen(p);
+	memcpy(q, p, sz + 1);
+	q += sz;
+
+	sz = au_do_optstr_br_attr(&attr, perm);
+	if (sz) {
+		*q++ = '+';
+		memcpy(q, attr.a, sz + 1);
+	}
+
+	AuDebugOn(strlen(str->a) >= sizeof(str->a));
+}
+
+/* ---------------------------------------------------------------------- */
+
+static match_table_t udbalevel = {
+	{AuOpt_UDBA_REVAL, "reval"},
+	{AuOpt_UDBA_NONE, "none"},
+#ifdef CONFIG_AUFS_HNOTIFY
+	{AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */
+#ifdef CONFIG_AUFS_HFSNOTIFY
+	{AuOpt_UDBA_HNOTIFY, "fsnotify"},
+#endif
+#endif
+	{-1, NULL}
+};
+
+static int noinline_for_stack udba_val(char *str)
+{
+	substring_t args[MAX_OPT_ARGS];
+
+	return match_token(str, udbalevel, args);
+}
+
+const char *au_optstr_udba(int udba)
+{
+	return au_parser_pattern(udba, udbalevel);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static match_table_t au_wbr_create_policy = {
+	{AuWbrCreate_TDP, "tdp"},
+	{AuWbrCreate_TDP, "top-down-parent"},
+	{AuWbrCreate_RR, "rr"},
+	{AuWbrCreate_RR, "round-robin"},
+	{AuWbrCreate_MFS, "mfs"},
+	{AuWbrCreate_MFS, "most-free-space"},
+	{AuWbrCreate_MFSV, "mfs:%d"},
+	{AuWbrCreate_MFSV, "most-free-space:%d"},
+
+	{AuWbrCreate_MFSRR, "mfsrr:%d"},
+	{AuWbrCreate_MFSRRV, "mfsrr:%d:%d"},
+	{AuWbrCreate_PMFS, "pmfs"},
+	{AuWbrCreate_PMFSV, "pmfs:%d"},
+	{AuWbrCreate_PMFSRR, "pmfsrr:%d"},
+	{AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"},
+
+	{-1, NULL}
+};
+
+/*
+ * cf. linux/lib/parser.c and cmdline.c
+ * gave up calling memparse() since it uses simple_strtoull() instead of
+ * kstrto...().
+ */
+static int noinline_for_stack
+au_match_ull(substring_t *s, unsigned long long *result)
+{
+	int err;
+	unsigned int len;
+	char a[32];
+
+	err = -ERANGE;
+	len = s->to - s->from;
+	if (len + 1 <= sizeof(a)) {
+		memcpy(a, s->from, len);
+		a[len] = '\0';
+		err = kstrtoull(a, 0, result);
+	}
+	return err;
+}
+
+static int au_wbr_mfs_wmark(substring_t *arg, char *str,
+			    struct au_opt_wbr_create *create)
+{
+	int err;
+	unsigned long long ull;
+
+	err = 0;
+	if (!au_match_ull(arg, &ull))
+		create->mfsrr_watermark = ull;
+	else {
+		pr_err("bad integer in %s\n", str);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+static int au_wbr_mfs_sec(substring_t *arg, char *str,
+			  struct au_opt_wbr_create *create)
+{
+	int n, err;
+
+	err = 0;
+	if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC)
+		create->mfs_second = n;
+	else {
+		pr_err("bad integer in %s\n", str);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+static int noinline_for_stack
+au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
+{
+	int err, e;
+	substring_t args[MAX_OPT_ARGS];
+
+	err = match_token(str, au_wbr_create_policy, args);
+	create->wbr_create = err;
+	switch (err) {
+	case AuWbrCreate_MFSRRV:
+	case AuWbrCreate_PMFSRRV:
+		e = au_wbr_mfs_wmark(&args[0], str, create);
+		if (!e)
+			e = au_wbr_mfs_sec(&args[1], str, create);
+		if (unlikely(e))
+			err = e;
+		break;
+	case AuWbrCreate_MFSRR:
+	case AuWbrCreate_PMFSRR:
+		e = au_wbr_mfs_wmark(&args[0], str, create);
+		if (unlikely(e)) {
+			err = e;
+			break;
+		}
+		/*FALLTHROUGH*/
+	case AuWbrCreate_MFS:
+	case AuWbrCreate_PMFS:
+		create->mfs_second = AUFS_MFS_DEF_SEC;
+		break;
+	case AuWbrCreate_MFSV:
+	case AuWbrCreate_PMFSV:
+		e = au_wbr_mfs_sec(&args[0], str, create);
+		if (unlikely(e))
+			err = e;
+		break;
+	}
+
+	return err;
+}
+
+const char *au_optstr_wbr_create(int wbr_create)
+{
+	return au_parser_pattern(wbr_create, au_wbr_create_policy);
+}
+
+static match_table_t au_wbr_copyup_policy = {
+	{AuWbrCopyup_TDP, "tdp"},
+	{AuWbrCopyup_TDP, "top-down-parent"},
+	{AuWbrCopyup_BUP, "bup"},
+	{AuWbrCopyup_BUP, "bottom-up-parent"},
+	{AuWbrCopyup_BU, "bu"},
+	{AuWbrCopyup_BU, "bottom-up"},
+	{-1, NULL}
+};
+
+static int noinline_for_stack au_wbr_copyup_val(char *str)
+{
+	substring_t args[MAX_OPT_ARGS];
+
+	return match_token(str, au_wbr_copyup_policy, args);
+}
+
+const char *au_optstr_wbr_copyup(int wbr_copyup)
+{
+	return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+
+static void dump_opts(struct au_opts *opts)
+{
+#ifdef CONFIG_AUFS_DEBUG
+	/* reduce stack space */
+	union {
+		struct au_opt_add *add;
+		struct au_opt_del *del;
+		struct au_opt_mod *mod;
+		struct au_opt_xino *xino;
+		struct au_opt_xino_itrunc *xino_itrunc;
+		struct au_opt_wbr_create *create;
+	} u;
+	struct au_opt *opt;
+
+	opt = opts->opt;
+	while (opt->type != Opt_tail) {
+		switch (opt->type) {
+		case Opt_add:
+			u.add = &opt->add;
+			AuDbg("add {b%d, %s, 0x%x, %p}\n",
+				  u.add->bindex, u.add->pathname, u.add->perm,
+				  u.add->path.dentry);
+			break;
+		case Opt_del:
+		case Opt_idel:
+			u.del = &opt->del;
+			AuDbg("del {%s, %p}\n",
+			      u.del->pathname, u.del->h_path.dentry);
+			break;
+		case Opt_mod:
+		case Opt_imod:
+			u.mod = &opt->mod;
+			AuDbg("mod {%s, 0x%x, %p}\n",
+				  u.mod->path, u.mod->perm, u.mod->h_root);
+			break;
+		case Opt_append:
+			u.add = &opt->add;
+			AuDbg("append {b%d, %s, 0x%x, %p}\n",
+				  u.add->bindex, u.add->pathname, u.add->perm,
+				  u.add->path.dentry);
+			break;
+		case Opt_prepend:
+			u.add = &opt->add;
+			AuDbg("prepend {b%d, %s, 0x%x, %p}\n",
+				  u.add->bindex, u.add->pathname, u.add->perm,
+				  u.add->path.dentry);
+			break;
+		case Opt_dirwh:
+			AuDbg("dirwh %d\n", opt->dirwh);
+			break;
+		case Opt_rdcache:
+			AuDbg("rdcache %d\n", opt->rdcache);
+			break;
+		case Opt_rdblk:
+			AuDbg("rdblk %u\n", opt->rdblk);
+			break;
+		case Opt_rdblk_def:
+			AuDbg("rdblk_def\n");
+			break;
+		case Opt_rdhash:
+			AuDbg("rdhash %u\n", opt->rdhash);
+			break;
+		case Opt_rdhash_def:
+			AuDbg("rdhash_def\n");
+			break;
+		case Opt_xino:
+			u.xino = &opt->xino;
+			AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file);
+			break;
+		case Opt_trunc_xino:
+			AuLabel(trunc_xino);
+			break;
+		case Opt_notrunc_xino:
+			AuLabel(notrunc_xino);
+			break;
+		case Opt_trunc_xino_path:
+		case Opt_itrunc_xino:
+			u.xino_itrunc = &opt->xino_itrunc;
+			AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex);
+			break;
+		case Opt_noxino:
+			AuLabel(noxino);
+			break;
+		case Opt_trunc_xib:
+			AuLabel(trunc_xib);
+			break;
+		case Opt_notrunc_xib:
+			AuLabel(notrunc_xib);
+			break;
+		case Opt_shwh:
+			AuLabel(shwh);
+			break;
+		case Opt_noshwh:
+			AuLabel(noshwh);
+			break;
+		case Opt_dirperm1:
+			AuLabel(dirperm1);
+			break;
+		case Opt_nodirperm1:
+			AuLabel(nodirperm1);
+			break;
+		case Opt_plink:
+			AuLabel(plink);
+			break;
+		case Opt_noplink:
+			AuLabel(noplink);
+			break;
+		case Opt_list_plink:
+			AuLabel(list_plink);
+			break;
+		case Opt_udba:
+			AuDbg("udba %d, %s\n",
+				  opt->udba, au_optstr_udba(opt->udba));
+			break;
+		case Opt_dio:
+			AuLabel(dio);
+			break;
+		case Opt_nodio:
+			AuLabel(nodio);
+			break;
+		case Opt_diropq_a:
+			AuLabel(diropq_a);
+			break;
+		case Opt_diropq_w:
+			AuLabel(diropq_w);
+			break;
+		case Opt_warn_perm:
+			AuLabel(warn_perm);
+			break;
+		case Opt_nowarn_perm:
+			AuLabel(nowarn_perm);
+			break;
+		case Opt_verbose:
+			AuLabel(verbose);
+			break;
+		case Opt_noverbose:
+			AuLabel(noverbose);
+			break;
+		case Opt_sum:
+			AuLabel(sum);
+			break;
+		case Opt_nosum:
+			AuLabel(nosum);
+			break;
+		case Opt_wsum:
+			AuLabel(wsum);
+			break;
+		case Opt_wbr_create:
+			u.create = &opt->wbr_create;
+			AuDbg("create %d, %s\n", u.create->wbr_create,
+				  au_optstr_wbr_create(u.create->wbr_create));
+			switch (u.create->wbr_create) {
+			case AuWbrCreate_MFSV:
+			case AuWbrCreate_PMFSV:
+				AuDbg("%d sec\n", u.create->mfs_second);
+				break;
+			case AuWbrCreate_MFSRR:
+				AuDbg("%llu watermark\n",
+					  u.create->mfsrr_watermark);
+				break;
+			case AuWbrCreate_MFSRRV:
+			case AuWbrCreate_PMFSRRV:
+				AuDbg("%llu watermark, %d sec\n",
+					  u.create->mfsrr_watermark,
+					  u.create->mfs_second);
+				break;
+			}
+			break;
+		case Opt_wbr_copyup:
+			AuDbg("copyup %d, %s\n", opt->wbr_copyup,
+				  au_optstr_wbr_copyup(opt->wbr_copyup));
+			break;
+		case Opt_fhsm_sec:
+			AuDbg("fhsm_sec %u\n", opt->fhsm_second);
+			break;
+		case Opt_acl:
+			AuLabel(acl);
+			break;
+		case Opt_noacl:
+			AuLabel(noacl);
+			break;
+		default:
+			BUG();
+		}
+		opt++;
+	}
+#endif
+}
+
+void au_opts_free(struct au_opts *opts)
+{
+	struct au_opt *opt;
+
+	opt = opts->opt;
+	while (opt->type != Opt_tail) {
+		switch (opt->type) {
+		case Opt_add:
+		case Opt_append:
+		case Opt_prepend:
+			path_put(&opt->add.path);
+			break;
+		case Opt_del:
+		case Opt_idel:
+			path_put(&opt->del.h_path);
+			break;
+		case Opt_mod:
+		case Opt_imod:
+			dput(opt->mod.h_root);
+			break;
+		case Opt_xino:
+			fput(opt->xino.file);
+			break;
+		}
+		opt++;
+	}
+}
+
+static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags,
+		   aufs_bindex_t bindex)
+{
+	int err;
+	struct au_opt_add *add = &opt->add;
+	char *p;
+
+	add->bindex = bindex;
+	add->perm = AuBrPerm_RO;
+	add->pathname = opt_str;
+	p = strchr(opt_str, '=');
+	if (p) {
+		*p++ = 0;
+		if (*p)
+			add->perm = br_perm_val(p);
+	}
+
+	err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path);
+	if (!err) {
+		if (!p) {
+			add->perm = AuBrPerm_RO;
+			if (au_test_fs_rr(add->path.dentry->d_sb))
+				add->perm = AuBrPerm_RR;
+			else if (!bindex && !(sb_flags & MS_RDONLY))
+				add->perm = AuBrPerm_RW;
+		}
+		opt->type = Opt_add;
+		goto out;
+	}
+	pr_err("lookup failed %s (%d)\n", add->pathname, err);
+	err = -EINVAL;
+
+out:
+	return err;
+}
+
+static int au_opts_parse_del(struct au_opt_del *del, substring_t args[])
+{
+	int err;
+
+	del->pathname = args[0].from;
+	AuDbg("del path %s\n", del->pathname);
+
+	err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path);
+	if (unlikely(err))
+		pr_err("lookup failed %s (%d)\n", del->pathname, err);
+
+	return err;
+}
+
+#if 0 /* reserved for future use */
+static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex,
+			      struct au_opt_del *del, substring_t args[])
+{
+	int err;
+	struct dentry *root;
+
+	err = -EINVAL;
+	root = sb->s_root;
+	aufs_read_lock(root, AuLock_FLUSH);
+	if (bindex < 0 || au_sbend(sb) < bindex) {
+		pr_err("out of bounds, %d\n", bindex);
+		goto out;
+	}
+
+	err = 0;
+	del->h_path.dentry = dget(au_h_dptr(root, bindex));
+	del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex));
+
+out:
+	aufs_read_unlock(root, !AuLock_IR);
+	return err;
+}
+#endif
+
+static int noinline_for_stack
+au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[])
+{
+	int err;
+	struct path path;
+	char *p;
+
+	err = -EINVAL;
+	mod->path = args[0].from;
+	p = strchr(mod->path, '=');
+	if (unlikely(!p)) {
+		pr_err("no permssion %s\n", args[0].from);
+		goto out;
+	}
+
+	*p++ = 0;
+	err = vfsub_kern_path(mod->path, lkup_dirflags, &path);
+	if (unlikely(err)) {
+		pr_err("lookup failed %s (%d)\n", mod->path, err);
+		goto out;
+	}
+
+	mod->perm = br_perm_val(p);
+	AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p);
+	mod->h_root = dget(path.dentry);
+	path_put(&path);
+
+out:
+	return err;
+}
+
+#if 0 /* reserved for future use */
+static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex,
+			      struct au_opt_mod *mod, substring_t args[])
+{
+	int err;
+	struct dentry *root;
+
+	err = -EINVAL;
+	root = sb->s_root;
+	aufs_read_lock(root, AuLock_FLUSH);
+	if (bindex < 0 || au_sbend(sb) < bindex) {
+		pr_err("out of bounds, %d\n", bindex);
+		goto out;
+	}
+
+	err = 0;
+	mod->perm = br_perm_val(args[1].from);
+	AuDbg("mod path %s, perm 0x%x, %s\n",
+	      mod->path, mod->perm, args[1].from);
+	mod->h_root = dget(au_h_dptr(root, bindex));
+
+out:
+	aufs_read_unlock(root, !AuLock_IR);
+	return err;
+}
+#endif
+
+static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino,
+			      substring_t args[])
+{
+	int err;
+	struct file *file;
+
+	file = au_xino_create(sb, args[0].from, /*silent*/0);
+	err = PTR_ERR(file);
+	if (IS_ERR(file))
+		goto out;
+
+	err = -EINVAL;
+	if (unlikely(file->f_path.dentry->d_sb == sb)) {
+		fput(file);
+		pr_err("%s must be outside\n", args[0].from);
+		goto out;
+	}
+
+	err = 0;
+	xino->file = file;
+	xino->path = args[0].from;
+
+out:
+	return err;
+}
+
+static int noinline_for_stack
+au_opts_parse_xino_itrunc_path(struct super_block *sb,
+			       struct au_opt_xino_itrunc *xino_itrunc,
+			       substring_t args[])
+{
+	int err;
+	aufs_bindex_t bend, bindex;
+	struct path path;
+	struct dentry *root;
+
+	err = vfsub_kern_path(args[0].from, lkup_dirflags, &path);
+	if (unlikely(err)) {
+		pr_err("lookup failed %s (%d)\n", args[0].from, err);
+		goto out;
+	}
+
+	xino_itrunc->bindex = -1;
+	root = sb->s_root;
+	aufs_read_lock(root, AuLock_FLUSH);
+	bend = au_sbend(sb);
+	for (bindex = 0; bindex <= bend; bindex++) {
+		if (au_h_dptr(root, bindex) == path.dentry) {
+			xino_itrunc->bindex = bindex;
+			break;
+		}
+	}
+	aufs_read_unlock(root, !AuLock_IR);
+	path_put(&path);
+
+	if (unlikely(xino_itrunc->bindex < 0)) {
+		pr_err("no such branch %s\n", args[0].from);
+		err = -EINVAL;
+	}
+
+out:
+	return err;
+}
+
+/* called without aufs lock */
+int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
+{
+	int err, n, token;
+	aufs_bindex_t bindex;
+	unsigned char skipped;
+	struct dentry *root;
+	struct au_opt *opt, *opt_tail;
+	char *opt_str;
+	/* reduce the stack space */
+	union {
+		struct au_opt_xino_itrunc *xino_itrunc;
+		struct au_opt_wbr_create *create;
+	} u;
+	struct {
+		substring_t args[MAX_OPT_ARGS];
+	} *a;
+
+	err = -ENOMEM;
+	a = kmalloc(sizeof(*a), GFP_NOFS);
+	if (unlikely(!a))
+		goto out;
+
+	root = sb->s_root;
+	err = 0;
+	bindex = 0;
+	opt = opts->opt;
+	opt_tail = opt + opts->max_opt - 1;
+	opt->type = Opt_tail;
+	while (!err && (opt_str = strsep(&str, ",")) && *opt_str) {
+		err = -EINVAL;
+		skipped = 0;
+		token = match_token(opt_str, options, a->args);
+		switch (token) {
+		case Opt_br:
+			err = 0;
+			while (!err && (opt_str = strsep(&a->args[0].from, ":"))
+			       && *opt_str) {
+				err = opt_add(opt, opt_str, opts->sb_flags,
+					      bindex++);
+				if (unlikely(!err && ++opt > opt_tail)) {
+					err = -E2BIG;
+					break;
+				}
+				opt->type = Opt_tail;
+				skipped = 1;
+			}
+			break;
+		case Opt_add:
+			if (unlikely(match_int(&a->args[0], &n))) {
+				pr_err("bad integer in %s\n", opt_str);
+				break;
+			}
+			bindex = n;
+			err = opt_add(opt, a->args[1].from, opts->sb_flags,
+				      bindex);
+			if (!err)
+				opt->type = token;
+			break;
+		case Opt_append:
+			err = opt_add(opt, a->args[0].from, opts->sb_flags,
+				      /*dummy bindex*/1);
+			if (!err)
+				opt->type = token;
+			break;
+		case Opt_prepend:
+			err = opt_add(opt, a->args[0].from, opts->sb_flags,
+				      /*bindex*/0);
+			if (!err)
+				opt->type = token;
+			break;
+		case Opt_del:
+			err = au_opts_parse_del(&opt->del, a->args);
+			if (!err)
+				opt->type = token;
+			break;
+#if 0 /* reserved for future use */
+		case Opt_idel:
+			del->pathname = "(indexed)";
+			if (unlikely(match_int(&args[0], &n))) {
+				pr_err("bad integer in %s\n", opt_str);
+				break;
+			}
+			err = au_opts_parse_idel(sb, n, &opt->del, a->args);
+			if (!err)
+				opt->type = token;
+			break;
+#endif
+		case Opt_mod:
+			err = au_opts_parse_mod(&opt->mod, a->args);
+			if (!err)
+				opt->type = token;
+			break;
+#ifdef IMOD /* reserved for future use */
+		case Opt_imod:
+			u.mod->path = "(indexed)";
+			if (unlikely(match_int(&a->args[0], &n))) {
+				pr_err("bad integer in %s\n", opt_str);
+				break;
+			}
+			err = au_opts_parse_imod(sb, n, &opt->mod, a->args);
+			if (!err)
+				opt->type = token;
+			break;
+#endif
+		case Opt_xino:
+			err = au_opts_parse_xino(sb, &opt->xino, a->args);
+			if (!err)
+				opt->type = token;
+			break;
+
+		case Opt_trunc_xino_path:
+			err = au_opts_parse_xino_itrunc_path
+				(sb, &opt->xino_itrunc, a->args);
+			if (!err)
+				opt->type = token;
+			break;
+
+		case Opt_itrunc_xino:
+			u.xino_itrunc = &opt->xino_itrunc;
+			if (unlikely(match_int(&a->args[0], &n))) {
+				pr_err("bad integer in %s\n", opt_str);
+				break;
+			}
+			u.xino_itrunc->bindex = n;
+			aufs_read_lock(root, AuLock_FLUSH);
+			if (n < 0 || au_sbend(sb) < n) {
+				pr_err("out of bounds, %d\n", n);
+				aufs_read_unlock(root, !AuLock_IR);
+				break;
+			}
+			aufs_read_unlock(root, !AuLock_IR);
+			err = 0;
+			opt->type = token;
+			break;
+
+		case Opt_dirwh:
+			if (unlikely(match_int(&a->args[0], &opt->dirwh)))
+				break;
+			err = 0;
+			opt->type = token;
+			break;
+
+		case Opt_rdcache:
+			if (unlikely(match_int(&a->args[0], &n))) {
+				pr_err("bad integer in %s\n", opt_str);
+				break;
+			}
+			if (unlikely(n > AUFS_RDCACHE_MAX)) {
+				pr_err("rdcache must be smaller than %d\n",
+				       AUFS_RDCACHE_MAX);
+				break;
+			}
+			opt->rdcache = n;
+			err = 0;
+			opt->type = token;
+			break;
+		case Opt_rdblk:
+			if (unlikely(match_int(&a->args[0], &n)
+				     || n < 0
+				     || n > KMALLOC_MAX_SIZE)) {
+				pr_err("bad integer in %s\n", opt_str);
+				break;
+			}
+			if (unlikely(n && n < NAME_MAX)) {
+				pr_err("rdblk must be larger than %d\n",
+				       NAME_MAX);
+				break;
+			}
+			opt->rdblk = n;
+			err = 0;
+			opt->type = token;
+			break;
+		case Opt_rdhash:
+			if (unlikely(match_int(&a->args[0], &n)
+				     || n < 0
+				     || n * sizeof(struct hlist_head)
+				     > KMALLOC_MAX_SIZE)) {
+				pr_err("bad integer in %s\n", opt_str);
+				break;
+			}
+			opt->rdhash = n;
+			err = 0;
+			opt->type = token;
+			break;
+
+		case Opt_trunc_xino:
+		case Opt_notrunc_xino:
+		case Opt_noxino:
+		case Opt_trunc_xib:
+		case Opt_notrunc_xib:
+		case Opt_shwh:
+		case Opt_noshwh:
+		case Opt_dirperm1:
+		case Opt_nodirperm1:
+		case Opt_plink:
+		case Opt_noplink:
+		case Opt_list_plink:
+		case Opt_dio:
+		case Opt_nodio:
+		case Opt_diropq_a:
+		case Opt_diropq_w:
+		case Opt_warn_perm:
+		case Opt_nowarn_perm:
+		case Opt_verbose:
+		case Opt_noverbose:
+		case Opt_sum:
+		case Opt_nosum:
+		case Opt_wsum:
+		case Opt_rdblk_def:
+		case Opt_rdhash_def:
+		case Opt_acl:
+		case Opt_noacl:
+			err = 0;
+			opt->type = token;
+			break;
+
+		case Opt_udba:
+			opt->udba = udba_val(a->args[0].from);
+			if (opt->udba >= 0) {
+				err = 0;
+				opt->type = token;
+			} else
+				pr_err("wrong value, %s\n", opt_str);
+			break;
+
+		case Opt_wbr_create:
+			u.create = &opt->wbr_create;
+			u.create->wbr_create
+				= au_wbr_create_val(a->args[0].from, u.create);
+			if (u.create->wbr_create >= 0) {
+				err = 0;
+				opt->type = token;
+			} else
+				pr_err("wrong value, %s\n", opt_str);
+			break;
+		case Opt_wbr_copyup:
+			opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from);
+			if (opt->wbr_copyup >= 0) {
+				err = 0;
+				opt->type = token;
+			} else
+				pr_err("wrong value, %s\n", opt_str);
+			break;
+
+		case Opt_fhsm_sec:
+			if (unlikely(match_int(&a->args[0], &n)
+				     || n < 0)) {
+				pr_err("bad integer in %s\n", opt_str);
+				break;
+			}
+			if (sysaufs_brs) {
+				opt->fhsm_second = n;
+				opt->type = token;
+			} else
+				pr_warn("ignored %s\n", opt_str);
+			err = 0;
+			break;
+
+		case Opt_ignore:
+			pr_warn("ignored %s\n", opt_str);
+			/*FALLTHROUGH*/
+		case Opt_ignore_silent:
+			skipped = 1;
+			err = 0;
+			break;
+		case Opt_err:
+			pr_err("unknown option %s\n", opt_str);
+			break;
+		}
+
+		if (!err && !skipped) {
+			if (unlikely(++opt > opt_tail)) {
+				err = -E2BIG;
+				opt--;
+				opt->type = Opt_tail;
+				break;
+			}
+			opt->type = Opt_tail;
+		}
+	}
+
+	kfree(a);
+	dump_opts(opts);
+	if (unlikely(err))
+		au_opts_free(opts);
+
+out:
+	return err;
+}
+
+static int au_opt_wbr_create(struct super_block *sb,
+			     struct au_opt_wbr_create *create)
+{
+	int err;
+	struct au_sbinfo *sbinfo;
+
+	SiMustWriteLock(sb);
+
+	err = 1; /* handled */
+	sbinfo = au_sbi(sb);
+	if (sbinfo->si_wbr_create_ops->fin) {
+		err = sbinfo->si_wbr_create_ops->fin(sb);
+		if (!err)
+			err = 1;
+	}
+
+	sbinfo->si_wbr_create = create->wbr_create;
+	sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create;
+	switch (create->wbr_create) {
+	case AuWbrCreate_MFSRRV:
+	case AuWbrCreate_MFSRR:
+	case AuWbrCreate_PMFSRR:
+	case AuWbrCreate_PMFSRRV:
+		sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark;
+		/*FALLTHROUGH*/
+	case AuWbrCreate_MFS:
+	case AuWbrCreate_MFSV:
+	case AuWbrCreate_PMFS:
+	case AuWbrCreate_PMFSV:
+		sbinfo->si_wbr_mfs.mfs_expire
+			= msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC);
+		break;
+	}
+
+	if (sbinfo->si_wbr_create_ops->init)
+		sbinfo->si_wbr_create_ops->init(sb); /* ignore */
+
+	return err;
+}
+
+/*
+ * returns,
+ * plus: processed without an error
+ * zero: unprocessed
+ */
+static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
+			 struct au_opts *opts)
+{
+	int err;
+	struct au_sbinfo *sbinfo;
+
+	SiMustWriteLock(sb);
+
+	err = 1; /* handled */
+	sbinfo = au_sbi(sb);
+	switch (opt->type) {
+	case Opt_udba:
+		sbinfo->si_mntflags &= ~AuOptMask_UDBA;
+		sbinfo->si_mntflags |= opt->udba;
+		opts->given_udba |= opt->udba;
+		break;
+
+	case Opt_plink:
+		au_opt_set(sbinfo->si_mntflags, PLINK);
+		break;
+	case Opt_noplink:
+		if (au_opt_test(sbinfo->si_mntflags, PLINK))
+			au_plink_put(sb, /*verbose*/1);
+		au_opt_clr(sbinfo->si_mntflags, PLINK);
+		break;
+	case Opt_list_plink:
+		if (au_opt_test(sbinfo->si_mntflags, PLINK))
+			au_plink_list(sb);
+		break;
+
+	case Opt_dio:
+		au_opt_set(sbinfo->si_mntflags, DIO);
+		au_fset_opts(opts->flags, REFRESH_DYAOP);
+		break;
+	case Opt_nodio:
+		au_opt_clr(sbinfo->si_mntflags, DIO);
+		au_fset_opts(opts->flags, REFRESH_DYAOP);
+		break;
+
+	case Opt_fhsm_sec:
+		au_fhsm_set(sbinfo, opt->fhsm_second);
+		break;
+
+	case Opt_diropq_a:
+		au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ);
+		break;
+	case Opt_diropq_w:
+		au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ);
+		break;
+
+	case Opt_warn_perm:
+		au_opt_set(sbinfo->si_mntflags, WARN_PERM);
+		break;
+	case Opt_nowarn_perm:
+		au_opt_clr(sbinfo->si_mntflags, WARN_PERM);
+		break;
+
+	case Opt_verbose:
+		au_opt_set(sbinfo->si_mntflags, VERBOSE);
+		break;
+	case Opt_noverbose:
+		au_opt_clr(sbinfo->si_mntflags, VERBOSE);
+		break;
+
+	case Opt_sum:
+		au_opt_set(sbinfo->si_mntflags, SUM);
+		break;
+	case Opt_wsum:
+		au_opt_clr(sbinfo->si_mntflags, SUM);
+		au_opt_set(sbinfo->si_mntflags, SUM_W);
+	case Opt_nosum:
+		au_opt_clr(sbinfo->si_mntflags, SUM);
+		au_opt_clr(sbinfo->si_mntflags, SUM_W);
+		break;
+
+	case Opt_wbr_create:
+		err = au_opt_wbr_create(sb, &opt->wbr_create);
+		break;
+	case Opt_wbr_copyup:
+		sbinfo->si_wbr_copyup = opt->wbr_copyup;
+		sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup;
+		break;
+
+	case Opt_dirwh:
+		sbinfo->si_dirwh = opt->dirwh;
+		break;
+
+	case Opt_rdcache:
+		sbinfo->si_rdcache
+			= msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC);
+		break;
+	case Opt_rdblk:
+		sbinfo->si_rdblk = opt->rdblk;
+		break;
+	case Opt_rdblk_def:
+		sbinfo->si_rdblk = AUFS_RDBLK_DEF;
+		break;
+	case Opt_rdhash:
+		sbinfo->si_rdhash = opt->rdhash;
+		break;
+	case Opt_rdhash_def:
+		sbinfo->si_rdhash = AUFS_RDHASH_DEF;
+		break;
+
+	case Opt_shwh:
+		au_opt_set(sbinfo->si_mntflags, SHWH);
+		break;
+	case Opt_noshwh:
+		au_opt_clr(sbinfo->si_mntflags, SHWH);
+		break;
+
+	case Opt_dirperm1:
+		au_opt_set(sbinfo->si_mntflags, DIRPERM1);
+		break;
+	case Opt_nodirperm1:
+		au_opt_clr(sbinfo->si_mntflags, DIRPERM1);
+		break;
+
+	case Opt_trunc_xino:
+		au_opt_set(sbinfo->si_mntflags, TRUNC_XINO);
+		break;
+	case Opt_notrunc_xino:
+		au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO);
+		break;
+
+	case Opt_trunc_xino_path:
+	case Opt_itrunc_xino:
+		err = au_xino_trunc(sb, opt->xino_itrunc.bindex);
+		if (!err)
+			err = 1;
+		break;
+
+	case Opt_trunc_xib:
+		au_fset_opts(opts->flags, TRUNC_XIB);
+		break;
+	case Opt_notrunc_xib:
+		au_fclr_opts(opts->flags, TRUNC_XIB);
+		break;
+
+	case Opt_acl:
+		sb->s_flags |= MS_POSIXACL;
+		break;
+	case Opt_noacl:
+		sb->s_flags &= ~MS_POSIXACL;
+		break;
+
+	default:
+		err = 0;
+		break;
+	}
+
+	return err;
+}
+
+/*
+ * returns tri-state.
+ * plus: processed without an error
+ * zero: unprocessed
+ * minus: error
+ */
+static int au_opt_br(struct super_block *sb, struct au_opt *opt,
+		     struct au_opts *opts)
+{
+	int err, do_refresh;
+
+	err = 0;
+	switch (opt->type) {
+	case Opt_append:
+		opt->add.bindex = au_sbend(sb) + 1;
+		if (opt->add.bindex < 0)
+			opt->add.bindex = 0;
+		goto add;
+	case Opt_prepend:
+		opt->add.bindex = 0;
+	add: /* indented label */
+	case Opt_add:
+		err = au_br_add(sb, &opt->add,
+				au_ftest_opts(opts->flags, REMOUNT));
+		if (!err) {
+			err = 1;
+			au_fset_opts(opts->flags, REFRESH);
+		}
+		break;
+
+	case Opt_del:
+	case Opt_idel:
+		err = au_br_del(sb, &opt->del,
+				au_ftest_opts(opts->flags, REMOUNT));
+		if (!err) {
+			err = 1;
+			au_fset_opts(opts->flags, TRUNC_XIB);
+			au_fset_opts(opts->flags, REFRESH);
+		}
+		break;
+
+	case Opt_mod:
+	case Opt_imod:
+		err = au_br_mod(sb, &opt->mod,
+				au_ftest_opts(opts->flags, REMOUNT),
+				&do_refresh);
+		if (!err) {
+			err = 1;
+			if (do_refresh)
+				au_fset_opts(opts->flags, REFRESH);
+		}
+		break;
+	}
+
+	return err;
+}
+
+static int au_opt_xino(struct super_block *sb, struct au_opt *opt,
+		       struct au_opt_xino **opt_xino,
+		       struct au_opts *opts)
+{
+	int err;
+	aufs_bindex_t bend, bindex;
+	struct dentry *root, *parent, *h_root;
+
+	err = 0;
+	switch (opt->type) {
+	case Opt_xino:
+		err = au_xino_set(sb, &opt->xino,
+				  !!au_ftest_opts(opts->flags, REMOUNT));
+		if (unlikely(err))
+			break;
+
+		*opt_xino = &opt->xino;
+		au_xino_brid_set(sb, -1);
+
+		/* safe d_parent access */
+		parent = opt->xino.file->f_path.dentry->d_parent;
+		root = sb->s_root;
+		bend = au_sbend(sb);
+		for (bindex = 0; bindex <= bend; bindex++) {
+			h_root = au_h_dptr(root, bindex);
+			if (h_root == parent) {
+				au_xino_brid_set(sb, au_sbr_id(sb, bindex));
+				break;
+			}
+		}
+		break;
+
+	case Opt_noxino:
+		au_xino_clr(sb);
+		au_xino_brid_set(sb, -1);
+		*opt_xino = (void *)-1;
+		break;
+	}
+
+	return err;
+}
+
+int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
+		   unsigned int pending)
+{
+	int err, fhsm;
+	aufs_bindex_t bindex, bend;
+	unsigned char do_plink, skip, do_free, can_no_dreval;
+	struct au_branch *br;
+	struct au_wbr *wbr;
+	struct dentry *root, *dentry;
+	struct inode *dir, *h_dir;
+	struct au_sbinfo *sbinfo;
+	struct au_hinode *hdir;
+
+	SiMustAnyLock(sb);
+
+	sbinfo = au_sbi(sb);
+	AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA));
+
+	if (!(sb_flags & MS_RDONLY)) {
+		if (unlikely(!au_br_writable(au_sbr_perm(sb, 0))))
+			pr_warn("first branch should be rw\n");
+		if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH)))
+			pr_warn("shwh should be used with ro\n");
+	}
+
+	if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY)
+	    && !au_opt_test(sbinfo->si_mntflags, XINO))
+		pr_warn("udba=*notify requires xino\n");
+
+	if (au_opt_test(sbinfo->si_mntflags, DIRPERM1))
+		pr_warn("dirperm1 breaks the protection"
+			" by the permission bits on the lower branch\n");
+
+	err = 0;
+	fhsm = 0;
+	root = sb->s_root;
+	dir = d_inode(root);
+	do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK);
+	can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending),
+				      UDBA_NONE);
+	bend = au_sbend(sb);
+	for (bindex = 0; !err && bindex <= bend; bindex++) {
+		skip = 0;
+		h_dir = au_h_iptr(dir, bindex);
+		br = au_sbr(sb, bindex);
+
+		if ((br->br_perm & AuBrAttr_ICEX)
+		    && !h_dir->i_op->listxattr)
+			br->br_perm &= ~AuBrAttr_ICEX;
+#if 0
+		if ((br->br_perm & AuBrAttr_ICEX_SEC)
+		    && (au_br_sb(br)->s_flags & MS_NOSEC))
+			br->br_perm &= ~AuBrAttr_ICEX_SEC;
+#endif
+
+		do_free = 0;
+		wbr = br->br_wbr;
+		if (wbr)
+			wbr_wh_read_lock(wbr);
+
+		if (!au_br_writable(br->br_perm)) {
+			do_free = !!wbr;
+			skip = (!wbr
+				|| (!wbr->wbr_whbase
+				    && !wbr->wbr_plink
+				    && !wbr->wbr_orph));
+		} else if (!au_br_wh_linkable(br->br_perm)) {
+			/* skip = (!br->br_whbase && !br->br_orph); */
+			skip = (!wbr || !wbr->wbr_whbase);
+			if (skip && wbr) {
+				if (do_plink)
+					skip = !!wbr->wbr_plink;
+				else
+					skip = !wbr->wbr_plink;
+			}
+		} else {
+			/* skip = (br->br_whbase && br->br_ohph); */
+			skip = (wbr && wbr->wbr_whbase);
+			if (skip) {
+				if (do_plink)
+					skip = !!wbr->wbr_plink;
+				else
+					skip = !wbr->wbr_plink;
+			}
+		}
+		if (wbr)
+			wbr_wh_read_unlock(wbr);
+
+		if (can_no_dreval) {
+			dentry = br->br_path.dentry;
+			spin_lock(&dentry->d_lock);
+			if (dentry->d_flags &
+			    (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE))
+				can_no_dreval = 0;
+			spin_unlock(&dentry->d_lock);
+		}
+
+		if (au_br_fhsm(br->br_perm)) {
+			fhsm++;
+			AuDebugOn(!br->br_fhsm);
+		}
+
+		if (skip)
+			continue;
+
+		hdir = au_hi(dir, bindex);
+		au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+		if (wbr)
+			wbr_wh_write_lock(wbr);
+		err = au_wh_init(br, sb);
+		if (wbr)
+			wbr_wh_write_unlock(wbr);
+		au_hn_imtx_unlock(hdir);
+
+		if (!err && do_free) {
+			kfree(wbr);
+			br->br_wbr = NULL;
+		}
+	}
+
+	if (can_no_dreval)
+		au_fset_si(sbinfo, NO_DREVAL);
+	else
+		au_fclr_si(sbinfo, NO_DREVAL);
+
+	if (fhsm >= 2) {
+		au_fset_si(sbinfo, FHSM);
+		for (bindex = bend; bindex >= 0; bindex--) {
+			br = au_sbr(sb, bindex);
+			if (au_br_fhsm(br->br_perm)) {
+				au_fhsm_set_bottom(sb, bindex);
+				break;
+			}
+		}
+	} else {
+		au_fclr_si(sbinfo, FHSM);
+		au_fhsm_set_bottom(sb, -1);
+	}
+
+	return err;
+}
+
+int au_opts_mount(struct super_block *sb, struct au_opts *opts)
+{
+	int err;
+	unsigned int tmp;
+	aufs_bindex_t bindex, bend;
+	struct au_opt *opt;
+	struct au_opt_xino *opt_xino, xino;
+	struct au_sbinfo *sbinfo;
+	struct au_branch *br;
+	struct inode *dir;
+
+	SiMustWriteLock(sb);
+
+	err = 0;
+	opt_xino = NULL;
+	opt = opts->opt;
+	while (err >= 0 && opt->type != Opt_tail)
+		err = au_opt_simple(sb, opt++, opts);
+	if (err > 0)
+		err = 0;
+	else if (unlikely(err < 0))
+		goto out;
+
+	/* disable xino and udba temporary */
+	sbinfo = au_sbi(sb);
+	tmp = sbinfo->si_mntflags;
+	au_opt_clr(sbinfo->si_mntflags, XINO);
+	au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL);
+
+	opt = opts->opt;
+	while (err >= 0 && opt->type != Opt_tail)
+		err = au_opt_br(sb, opt++, opts);
+	if (err > 0)
+		err = 0;
+	else if (unlikely(err < 0))
+		goto out;
+
+	bend = au_sbend(sb);
+	if (unlikely(bend < 0)) {
+		err = -EINVAL;
+		pr_err("no branches\n");
+		goto out;
+	}
+
+	if (au_opt_test(tmp, XINO))
+		au_opt_set(sbinfo->si_mntflags, XINO);
+	opt = opts->opt;
+	while (!err && opt->type != Opt_tail)
+		err = au_opt_xino(sb, opt++, &opt_xino, opts);
+	if (unlikely(err))
+		goto out;
+
+	err = au_opts_verify(sb, sb->s_flags, tmp);
+	if (unlikely(err))
+		goto out;
+
+	/* restore xino */
+	if (au_opt_test(tmp, XINO) && !opt_xino) {
+		xino.file = au_xino_def(sb);
+		err = PTR_ERR(xino.file);
+		if (IS_ERR(xino.file))
+			goto out;
+
+		err = au_xino_set(sb, &xino, /*remount*/0);
+		fput(xino.file);
+		if (unlikely(err))
+			goto out;
+	}
+
+	/* restore udba */
+	tmp &= AuOptMask_UDBA;
+	sbinfo->si_mntflags &= ~AuOptMask_UDBA;
+	sbinfo->si_mntflags |= tmp;
+	bend = au_sbend(sb);
+	for (bindex = 0; bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		err = au_hnotify_reset_br(tmp, br, br->br_perm);
+		if (unlikely(err))
+			AuIOErr("hnotify failed on br %d, %d, ignored\n",
+				bindex, err);
+		/* go on even if err */
+	}
+	if (au_opt_test(tmp, UDBA_HNOTIFY)) {
+		dir = d_inode(sb->s_root);
+		au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
+	}
+
+out:
+	return err;
+}
+
+int au_opts_remount(struct super_block *sb, struct au_opts *opts)
+{
+	int err, rerr;
+	unsigned char no_dreval;
+	struct inode *dir;
+	struct au_opt_xino *opt_xino;
+	struct au_opt *opt;
+	struct au_sbinfo *sbinfo;
+
+	SiMustWriteLock(sb);
+
+	err = 0;
+	dir = d_inode(sb->s_root);
+	sbinfo = au_sbi(sb);
+	opt_xino = NULL;
+	opt = opts->opt;
+	while (err >= 0 && opt->type != Opt_tail) {
+		err = au_opt_simple(sb, opt, opts);
+		if (!err)
+			err = au_opt_br(sb, opt, opts);
+		if (!err)
+			err = au_opt_xino(sb, opt, &opt_xino, opts);
+		opt++;
+	}
+	if (err > 0)
+		err = 0;
+	AuTraceErr(err);
+	/* go on even err */
+
+	no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL);
+	rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0);
+	if (unlikely(rerr && !err))
+		err = rerr;
+
+	if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL))
+		au_fset_opts(opts->flags, REFRESH_IDOP);
+
+	if (au_ftest_opts(opts->flags, TRUNC_XIB)) {
+		rerr = au_xib_trunc(sb);
+		if (unlikely(rerr && !err))
+			err = rerr;
+	}
+
+	/* will be handled by the caller */
+	if (!au_ftest_opts(opts->flags, REFRESH)
+	    && (opts->given_udba
+		|| au_opt_test(sbinfo->si_mntflags, XINO)
+		|| au_ftest_opts(opts->flags, REFRESH_IDOP)
+		    ))
+		au_fset_opts(opts->flags, REFRESH);
+
+	AuDbg("status 0x%x\n", opts->flags);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+unsigned int au_opt_udba(struct super_block *sb)
+{
+	return au_mntflags(sb) & AuOptMask_UDBA;
+}
--- linux-4.4.0.orig/fs/aufs/opts.h
+++ linux-4.4.0/fs/aufs/opts.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * mount options/flags
+ */
+
+#ifndef __AUFS_OPTS_H__
+#define __AUFS_OPTS_H__
+
+#ifdef __KERNEL__
+
+#include <linux/path.h>
+
+struct file;
+struct super_block;
+
+/* ---------------------------------------------------------------------- */
+
+/* mount flags */
+#define AuOpt_XINO		1		/* external inode number bitmap
+						   and translation table */
+#define AuOpt_TRUNC_XINO	(1 << 1)	/* truncate xino files */
+#define AuOpt_UDBA_NONE		(1 << 2)	/* users direct branch access */
+#define AuOpt_UDBA_REVAL	(1 << 3)
+#define AuOpt_UDBA_HNOTIFY	(1 << 4)
+#define AuOpt_SHWH		(1 << 5)	/* show whiteout */
+#define AuOpt_PLINK		(1 << 6)	/* pseudo-link */
+#define AuOpt_DIRPERM1		(1 << 7)	/* ignore the lower dir's perm
+						   bits */
+#define AuOpt_ALWAYS_DIROPQ	(1 << 9)	/* policy to creating diropq */
+#define AuOpt_SUM		(1 << 10)	/* summation for statfs(2) */
+#define AuOpt_SUM_W		(1 << 11)	/* unimplemented */
+#define AuOpt_WARN_PERM		(1 << 12)	/* warn when add-branch */
+#define AuOpt_VERBOSE		(1 << 13)	/* busy inode when del-branch */
+#define AuOpt_DIO		(1 << 14)	/* direct io */
+
+#ifndef CONFIG_AUFS_HNOTIFY
+#undef AuOpt_UDBA_HNOTIFY
+#define AuOpt_UDBA_HNOTIFY	0
+#endif
+#ifndef CONFIG_AUFS_SHWH
+#undef AuOpt_SHWH
+#define AuOpt_SHWH		0
+#endif
+
+#define AuOpt_Def	(AuOpt_XINO \
+			 | AuOpt_UDBA_REVAL \
+			 | AuOpt_PLINK \
+			 /* | AuOpt_DIRPERM1 */ \
+			 | AuOpt_WARN_PERM)
+#define AuOptMask_UDBA	(AuOpt_UDBA_NONE \
+			 | AuOpt_UDBA_REVAL \
+			 | AuOpt_UDBA_HNOTIFY)
+
+#define au_opt_test(flags, name)	(flags & AuOpt_##name)
+#define au_opt_set(flags, name) do { \
+	BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \
+	((flags) |= AuOpt_##name); \
+} while (0)
+#define au_opt_set_udba(flags, name) do { \
+	(flags) &= ~AuOptMask_UDBA; \
+	((flags) |= AuOpt_##name); \
+} while (0)
+#define au_opt_clr(flags, name) do { \
+	((flags) &= ~AuOpt_##name); \
+} while (0)
+
+static inline unsigned int au_opts_plink(unsigned int mntflags)
+{
+#ifdef CONFIG_PROC_FS
+	return mntflags;
+#else
+	return mntflags & ~AuOpt_PLINK;
+#endif
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* policies to select one among multiple writable branches */
+enum {
+	AuWbrCreate_TDP,	/* top down parent */
+	AuWbrCreate_RR,		/* round robin */
+	AuWbrCreate_MFS,	/* most free space */
+	AuWbrCreate_MFSV,	/* mfs with seconds */
+	AuWbrCreate_MFSRR,	/* mfs then rr */
+	AuWbrCreate_MFSRRV,	/* mfs then rr with seconds */
+	AuWbrCreate_PMFS,	/* parent and mfs */
+	AuWbrCreate_PMFSV,	/* parent and mfs with seconds */
+	AuWbrCreate_PMFSRR,	/* parent, mfs and round-robin */
+	AuWbrCreate_PMFSRRV,	/* plus seconds */
+
+	AuWbrCreate_Def = AuWbrCreate_TDP
+};
+
+enum {
+	AuWbrCopyup_TDP,	/* top down parent */
+	AuWbrCopyup_BUP,	/* bottom up parent */
+	AuWbrCopyup_BU,		/* bottom up */
+
+	AuWbrCopyup_Def = AuWbrCopyup_TDP
+};
+
+/* ---------------------------------------------------------------------- */
+
+struct au_opt_add {
+	aufs_bindex_t	bindex;
+	char		*pathname;
+	int		perm;
+	struct path	path;
+};
+
+struct au_opt_del {
+	char		*pathname;
+	struct path	h_path;
+};
+
+struct au_opt_mod {
+	char		*path;
+	int		perm;
+	struct dentry	*h_root;
+};
+
+struct au_opt_xino {
+	char		*path;
+	struct file	*file;
+};
+
+struct au_opt_xino_itrunc {
+	aufs_bindex_t	bindex;
+};
+
+struct au_opt_wbr_create {
+	int			wbr_create;
+	int			mfs_second;
+	unsigned long long	mfsrr_watermark;
+};
+
+struct au_opt {
+	int type;
+	union {
+		struct au_opt_xino	xino;
+		struct au_opt_xino_itrunc xino_itrunc;
+		struct au_opt_add	add;
+		struct au_opt_del	del;
+		struct au_opt_mod	mod;
+		int			dirwh;
+		int			rdcache;
+		unsigned int		rdblk;
+		unsigned int		rdhash;
+		int			udba;
+		struct au_opt_wbr_create wbr_create;
+		int			wbr_copyup;
+		unsigned int		fhsm_second;
+	};
+};
+
+/* opts flags */
+#define AuOpts_REMOUNT		1
+#define AuOpts_REFRESH		(1 << 1)
+#define AuOpts_TRUNC_XIB	(1 << 2)
+#define AuOpts_REFRESH_DYAOP	(1 << 3)
+#define AuOpts_REFRESH_IDOP	(1 << 4)
+#define au_ftest_opts(flags, name)	((flags) & AuOpts_##name)
+#define au_fset_opts(flags, name) \
+	do { (flags) |= AuOpts_##name; } while (0)
+#define au_fclr_opts(flags, name) \
+	do { (flags) &= ~AuOpts_##name; } while (0)
+
+struct au_opts {
+	struct au_opt	*opt;
+	int		max_opt;
+
+	unsigned int	given_udba;
+	unsigned int	flags;
+	unsigned long	sb_flags;
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* opts.c */
+void au_optstr_br_perm(au_br_perm_str_t *str, int perm);
+const char *au_optstr_udba(int udba);
+const char *au_optstr_wbr_copyup(int wbr_copyup);
+const char *au_optstr_wbr_create(int wbr_create);
+
+void au_opts_free(struct au_opts *opts);
+int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts);
+int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
+		   unsigned int pending);
+int au_opts_mount(struct super_block *sb, struct au_opts *opts);
+int au_opts_remount(struct super_block *sb, struct au_opts *opts);
+
+unsigned int au_opt_udba(struct super_block *sb);
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_OPTS_H__ */
--- linux-4.4.0.orig/fs/aufs/plink.c
+++ linux-4.4.0/fs/aufs/plink.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * pseudo-link
+ */
+
+#include "aufs.h"
+
+/*
+ * the pseudo-link maintenance mode.
+ * during a user process maintains the pseudo-links,
+ * prohibit adding a new plink and branch manipulation.
+ *
+ * Flags
+ * NOPLM:
+ *	For entry functions which will handle plink, and i_mutex is already held
+ *	in VFS.
+ *	They cannot wait and should return an error at once.
+ *	Callers has to check the error.
+ * NOPLMW:
+ *	For entry functions which will handle plink, but i_mutex is not held
+ *	in VFS.
+ *	They can wait the plink maintenance mode to finish.
+ *
+ * They behave like F_SETLK and F_SETLKW.
+ * If the caller never handle plink, then both flags are unnecessary.
+ */
+
+int au_plink_maint(struct super_block *sb, int flags)
+{
+	int err;
+	pid_t pid, ppid;
+	struct au_sbinfo *sbi;
+
+	SiMustAnyLock(sb);
+
+	err = 0;
+	if (!au_opt_test(au_mntflags(sb), PLINK))
+		goto out;
+
+	sbi = au_sbi(sb);
+	pid = sbi->si_plink_maint_pid;
+	if (!pid || pid == current->pid)
+		goto out;
+
+	/* todo: it highly depends upon /sbin/mount.aufs */
+	rcu_read_lock();
+	ppid = task_pid_vnr(rcu_dereference(current->real_parent));
+	rcu_read_unlock();
+	if (pid == ppid)
+		goto out;
+
+	if (au_ftest_lock(flags, NOPLMW)) {
+		/* if there is no i_mutex lock in VFS, we don't need to wait */
+		/* AuDebugOn(!lockdep_depth(current)); */
+		while (sbi->si_plink_maint_pid) {
+			si_read_unlock(sb);
+			/* gave up wake_up_bit() */
+			wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid);
+
+			if (au_ftest_lock(flags, FLUSH))
+				au_nwt_flush(&sbi->si_nowait);
+			si_noflush_read_lock(sb);
+		}
+	} else if (au_ftest_lock(flags, NOPLM)) {
+		AuDbg("ppid %d, pid %d\n", ppid, pid);
+		err = -EAGAIN;
+	}
+
+out:
+	return err;
+}
+
+void au_plink_maint_leave(struct au_sbinfo *sbinfo)
+{
+	spin_lock(&sbinfo->si_plink_maint_lock);
+	sbinfo->si_plink_maint_pid = 0;
+	spin_unlock(&sbinfo->si_plink_maint_lock);
+	wake_up_all(&sbinfo->si_plink_wq);
+}
+
+int au_plink_maint_enter(struct super_block *sb)
+{
+	int err;
+	struct au_sbinfo *sbinfo;
+
+	err = 0;
+	sbinfo = au_sbi(sb);
+	/* make sure i am the only one in this fs */
+	si_write_lock(sb, AuLock_FLUSH);
+	if (au_opt_test(au_mntflags(sb), PLINK)) {
+		spin_lock(&sbinfo->si_plink_maint_lock);
+		if (!sbinfo->si_plink_maint_pid)
+			sbinfo->si_plink_maint_pid = current->pid;
+		else
+			err = -EBUSY;
+		spin_unlock(&sbinfo->si_plink_maint_lock);
+	}
+	si_write_unlock(sb);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef CONFIG_AUFS_DEBUG
+void au_plink_list(struct super_block *sb)
+{
+	int i;
+	struct au_sbinfo *sbinfo;
+	struct hlist_head *plink_hlist;
+	struct pseudo_link *plink;
+
+	SiMustAnyLock(sb);
+
+	sbinfo = au_sbi(sb);
+	AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
+	AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
+
+	for (i = 0; i < AuPlink_NHASH; i++) {
+		plink_hlist = &sbinfo->si_plink[i].head;
+		rcu_read_lock();
+		hlist_for_each_entry_rcu(plink, plink_hlist, hlist)
+			AuDbg("%lu\n", plink->inode->i_ino);
+		rcu_read_unlock();
+	}
+}
+#endif
+
+/* is the inode pseudo-linked? */
+int au_plink_test(struct inode *inode)
+{
+	int found, i;
+	struct au_sbinfo *sbinfo;
+	struct hlist_head *plink_hlist;
+	struct pseudo_link *plink;
+
+	sbinfo = au_sbi(inode->i_sb);
+	AuRwMustAnyLock(&sbinfo->si_rwsem);
+	AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK));
+	AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM));
+
+	found = 0;
+	i = au_plink_hash(inode->i_ino);
+	plink_hlist = &sbinfo->si_plink[i].head;
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(plink, plink_hlist, hlist)
+		if (plink->inode == inode) {
+			found = 1;
+			break;
+		}
+	rcu_read_unlock();
+	return found;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * generate a name for plink.
+ * the file will be stored under AUFS_WH_PLINKDIR.
+ */
+/* 20 is max digits length of ulong 64 */
+#define PLINK_NAME_LEN	((20 + 1) * 2)
+
+static int plink_name(char *name, int len, struct inode *inode,
+		      aufs_bindex_t bindex)
+{
+	int rlen;
+	struct inode *h_inode;
+
+	h_inode = au_h_iptr(inode, bindex);
+	rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino);
+	return rlen;
+}
+
+struct au_do_plink_lkup_args {
+	struct dentry **errp;
+	struct qstr *tgtname;
+	struct dentry *h_parent;
+	struct au_branch *br;
+};
+
+static struct dentry *au_do_plink_lkup(struct qstr *tgtname,
+				       struct dentry *h_parent,
+				       struct au_branch *br)
+{
+	struct dentry *h_dentry;
+	struct mutex *h_mtx;
+
+	h_mtx = &d_inode(h_parent)->i_mutex;
+	mutex_lock_nested(h_mtx, AuLsc_I_CHILD2);
+	h_dentry = vfsub_lkup_one(tgtname, h_parent);
+	mutex_unlock(h_mtx);
+	return h_dentry;
+}
+
+static void au_call_do_plink_lkup(void *args)
+{
+	struct au_do_plink_lkup_args *a = args;
+	*a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br);
+}
+
+/* lookup the plink-ed @inode under the branch at @bindex */
+struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex)
+{
+	struct dentry *h_dentry, *h_parent;
+	struct au_branch *br;
+	int wkq_err;
+	char a[PLINK_NAME_LEN];
+	struct qstr tgtname = QSTR_INIT(a, 0);
+
+	AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM));
+
+	br = au_sbr(inode->i_sb, bindex);
+	h_parent = br->br_wbr->wbr_plink;
+	tgtname.len = plink_name(a, sizeof(a), inode, bindex);
+
+	if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) {
+		struct au_do_plink_lkup_args args = {
+			.errp		= &h_dentry,
+			.tgtname	= &tgtname,
+			.h_parent	= h_parent,
+			.br		= br
+		};
+
+		wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args);
+		if (unlikely(wkq_err))
+			h_dentry = ERR_PTR(wkq_err);
+	} else
+		h_dentry = au_do_plink_lkup(&tgtname, h_parent, br);
+
+	return h_dentry;
+}
+
+/* create a pseudo-link */
+static int do_whplink(struct qstr *tgt, struct dentry *h_parent,
+		      struct dentry *h_dentry, struct au_branch *br)
+{
+	int err;
+	struct path h_path = {
+		.mnt = au_br_mnt(br)
+	};
+	struct inode *h_dir, *delegated;
+
+	h_dir = d_inode(h_parent);
+	mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2);
+again:
+	h_path.dentry = vfsub_lkup_one(tgt, h_parent);
+	err = PTR_ERR(h_path.dentry);
+	if (IS_ERR(h_path.dentry))
+		goto out;
+
+	err = 0;
+	/* wh.plink dir is not monitored */
+	/* todo: is it really safe? */
+	if (d_is_positive(h_path.dentry)
+	    && d_inode(h_path.dentry) != d_inode(h_dentry)) {
+		delegated = NULL;
+		err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0);
+		if (unlikely(err == -EWOULDBLOCK)) {
+			pr_warn("cannot retry for NFSv4 delegation"
+				" for an internal unlink\n");
+			iput(delegated);
+		}
+		dput(h_path.dentry);
+		h_path.dentry = NULL;
+		if (!err)
+			goto again;
+	}
+	if (!err && d_is_negative(h_path.dentry)) {
+		delegated = NULL;
+		err = vfsub_link(h_dentry, h_dir, &h_path, &delegated);
+		if (unlikely(err == -EWOULDBLOCK)) {
+			pr_warn("cannot retry for NFSv4 delegation"
+				" for an internal link\n");
+			iput(delegated);
+		}
+	}
+	dput(h_path.dentry);
+
+out:
+	mutex_unlock(&h_dir->i_mutex);
+	return err;
+}
+
+struct do_whplink_args {
+	int *errp;
+	struct qstr *tgt;
+	struct dentry *h_parent;
+	struct dentry *h_dentry;
+	struct au_branch *br;
+};
+
+static void call_do_whplink(void *args)
+{
+	struct do_whplink_args *a = args;
+	*a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br);
+}
+
+static int whplink(struct dentry *h_dentry, struct inode *inode,
+		   aufs_bindex_t bindex, struct au_branch *br)
+{
+	int err, wkq_err;
+	struct au_wbr *wbr;
+	struct dentry *h_parent;
+	char a[PLINK_NAME_LEN];
+	struct qstr tgtname = QSTR_INIT(a, 0);
+
+	wbr = au_sbr(inode->i_sb, bindex)->br_wbr;
+	h_parent = wbr->wbr_plink;
+	tgtname.len = plink_name(a, sizeof(a), inode, bindex);
+
+	/* always superio. */
+	if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) {
+		struct do_whplink_args args = {
+			.errp		= &err,
+			.tgt		= &tgtname,
+			.h_parent	= h_parent,
+			.h_dentry	= h_dentry,
+			.br		= br
+		};
+		wkq_err = au_wkq_wait(call_do_whplink, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+	} else
+		err = do_whplink(&tgtname, h_parent, h_dentry, br);
+
+	return err;
+}
+
+/* free a single plink */
+static void do_put_plink(struct pseudo_link *plink, int do_del)
+{
+	if (do_del)
+		hlist_del(&plink->hlist);
+	iput(plink->inode);
+	kfree(plink);
+}
+
+static void do_put_plink_rcu(struct rcu_head *rcu)
+{
+	struct pseudo_link *plink;
+
+	plink = container_of(rcu, struct pseudo_link, rcu);
+	iput(plink->inode);
+	kfree(plink);
+}
+
+/*
+ * create a new pseudo-link for @h_dentry on @bindex.
+ * the linked inode is held in aufs @inode.
+ */
+void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
+		     struct dentry *h_dentry)
+{
+	struct super_block *sb;
+	struct au_sbinfo *sbinfo;
+	struct hlist_head *plink_hlist;
+	struct pseudo_link *plink, *tmp;
+	struct au_sphlhead *sphl;
+	int found, err, cnt, i;
+
+	sb = inode->i_sb;
+	sbinfo = au_sbi(sb);
+	AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
+	AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
+
+	found = au_plink_test(inode);
+	if (found)
+		return;
+
+	i = au_plink_hash(inode->i_ino);
+	sphl = sbinfo->si_plink + i;
+	plink_hlist = &sphl->head;
+	tmp = kmalloc(sizeof(*plink), GFP_NOFS);
+	if (tmp)
+		tmp->inode = au_igrab(inode);
+	else {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	spin_lock(&sphl->spin);
+	hlist_for_each_entry(plink, plink_hlist, hlist) {
+		if (plink->inode == inode) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found)
+		hlist_add_head_rcu(&tmp->hlist, plink_hlist);
+	spin_unlock(&sphl->spin);
+	if (!found) {
+		cnt = au_sphl_count(sphl);
+#define msg "unexpectedly unblanced or too many pseudo-links"
+		if (cnt > AUFS_PLINK_WARN)
+			AuWarn1(msg ", %d\n", cnt);
+#undef msg
+		err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex));
+	} else {
+		do_put_plink(tmp, 0);
+		return;
+	}
+
+out:
+	if (unlikely(err)) {
+		pr_warn("err %d, damaged pseudo link.\n", err);
+		if (tmp) {
+			au_sphl_del_rcu(&tmp->hlist, sphl);
+			call_rcu(&tmp->rcu, do_put_plink_rcu);
+		}
+	}
+}
+
+/* free all plinks */
+void au_plink_put(struct super_block *sb, int verbose)
+{
+	int i, warned;
+	struct au_sbinfo *sbinfo;
+	struct hlist_head *plink_hlist;
+	struct hlist_node *tmp;
+	struct pseudo_link *plink;
+
+	SiMustWriteLock(sb);
+
+	sbinfo = au_sbi(sb);
+	AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
+	AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
+
+	/* no spin_lock since sbinfo is write-locked */
+	warned = 0;
+	for (i = 0; i < AuPlink_NHASH; i++) {
+		plink_hlist = &sbinfo->si_plink[i].head;
+		if (!warned && verbose && !hlist_empty(plink_hlist)) {
+			pr_warn("pseudo-link is not flushed");
+			warned = 1;
+		}
+		hlist_for_each_entry_safe(plink, tmp, plink_hlist, hlist)
+			do_put_plink(plink, 0);
+		INIT_HLIST_HEAD(plink_hlist);
+	}
+}
+
+void au_plink_clean(struct super_block *sb, int verbose)
+{
+	struct dentry *root;
+
+	root = sb->s_root;
+	aufs_write_lock(root);
+	if (au_opt_test(au_mntflags(sb), PLINK))
+		au_plink_put(sb, verbose);
+	aufs_write_unlock(root);
+}
+
+static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id)
+{
+	int do_put;
+	aufs_bindex_t bstart, bend, bindex;
+
+	do_put = 0;
+	bstart = au_ibstart(inode);
+	bend = au_ibend(inode);
+	if (bstart >= 0) {
+		for (bindex = bstart; bindex <= bend; bindex++) {
+			if (!au_h_iptr(inode, bindex)
+			    || au_ii_br_id(inode, bindex) != br_id)
+				continue;
+			au_set_h_iptr(inode, bindex, NULL, 0);
+			do_put = 1;
+			break;
+		}
+		if (do_put)
+			for (bindex = bstart; bindex <= bend; bindex++)
+				if (au_h_iptr(inode, bindex)) {
+					do_put = 0;
+					break;
+				}
+	} else
+		do_put = 1;
+
+	return do_put;
+}
+
+/* free the plinks on a branch specified by @br_id */
+void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id)
+{
+	struct au_sbinfo *sbinfo;
+	struct hlist_head *plink_hlist;
+	struct hlist_node *tmp;
+	struct pseudo_link *plink;
+	struct inode *inode;
+	int i, do_put;
+
+	SiMustWriteLock(sb);
+
+	sbinfo = au_sbi(sb);
+	AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
+	AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
+
+	/* no spin_lock since sbinfo is write-locked */
+	for (i = 0; i < AuPlink_NHASH; i++) {
+		plink_hlist = &sbinfo->si_plink[i].head;
+		hlist_for_each_entry_safe(plink, tmp, plink_hlist, hlist) {
+			inode = au_igrab(plink->inode);
+			ii_write_lock_child(inode);
+			do_put = au_plink_do_half_refresh(inode, br_id);
+			if (do_put)
+				do_put_plink(plink, 1);
+			ii_write_unlock(inode);
+			iput(inode);
+		}
+	}
+}
--- linux-4.4.0.orig/fs/aufs/poll.c
+++ linux-4.4.0/fs/aufs/poll.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * poll operation
+ * There is only one filesystem which implements ->poll operation, currently.
+ */
+
+#include "aufs.h"
+
+unsigned int aufs_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask;
+	int err;
+	struct file *h_file;
+	struct super_block *sb;
+
+	/* We should pretend an error happened. */
+	mask = POLLERR /* | POLLIN | POLLOUT */;
+	sb = file->f_path.dentry->d_sb;
+	si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+
+	h_file = au_read_pre(file, /*keep_fi*/0);
+	err = PTR_ERR(h_file);
+	if (IS_ERR(h_file))
+		goto out;
+
+	/* it is not an error if h_file has no operation */
+	mask = DEFAULT_POLLMASK;
+	if (h_file->f_op->poll)
+		mask = h_file->f_op->poll(h_file, wait);
+	fput(h_file); /* instead of au_read_post() */
+
+out:
+	si_read_unlock(sb);
+	AuTraceErr((int)mask);
+	return mask;
+}
--- linux-4.4.0.orig/fs/aufs/posix_acl.c
+++ linux-4.4.0/fs/aufs/posix_acl.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * posix acl operations
+ */
+
+#include <linux/fs.h>
+#include "aufs.h"
+
+struct posix_acl *aufs_get_acl(struct inode *inode, int type)
+{
+	struct posix_acl *acl;
+	int err;
+	aufs_bindex_t bindex;
+	struct inode *h_inode;
+	struct super_block *sb;
+
+	acl = NULL;
+	sb = inode->i_sb;
+	si_read_lock(sb, AuLock_FLUSH);
+	ii_read_lock_child(inode);
+	if (!(sb->s_flags & MS_POSIXACL))
+		goto out;
+
+	bindex = au_ibstart(inode);
+	h_inode = au_h_iptr(inode, bindex);
+	if (unlikely(!h_inode
+		     || ((h_inode->i_mode & S_IFMT)
+			 != (inode->i_mode & S_IFMT)))) {
+		err = au_busy_or_stale();
+		acl = ERR_PTR(err);
+		goto out;
+	}
+
+	/* always topmost only */
+	acl = get_acl(h_inode, type);
+
+out:
+	ii_read_unlock(inode);
+	si_read_unlock(sb);
+
+	AuTraceErrPtr(acl);
+	return acl;
+}
+
+int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+	int err;
+	ssize_t ssz;
+	struct dentry *dentry;
+	struct au_srxattr arg = {
+		.type = AU_ACL_SET,
+		.u.acl_set = {
+			.acl	= acl,
+			.type	= type
+		},
+	};
+
+	mutex_lock(&inode->i_mutex);
+	if (inode->i_ino == AUFS_ROOT_INO)
+		dentry = dget(inode->i_sb->s_root);
+	else {
+		dentry = d_find_alias(inode);
+		if (!dentry)
+			dentry = d_find_any_alias(inode);
+		if (!dentry) {
+			pr_warn("cannot handle this inode, "
+				"please report to aufs-users ML\n");
+			err = -ENOENT;
+			goto out;
+		}
+	}
+
+	ssz = au_srxattr(dentry, &arg);
+	dput(dentry);
+	err = ssz;
+	if (ssz >= 0)
+		err = 0;
+
+out:
+	mutex_unlock(&inode->i_mutex);
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/procfs.c
+++ linux-4.4.0/fs/aufs/procfs.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2010-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * procfs interfaces
+ */
+
+#include <linux/proc_fs.h>
+#include "aufs.h"
+
+static int au_procfs_plm_release(struct inode *inode, struct file *file)
+{
+	struct au_sbinfo *sbinfo;
+
+	sbinfo = file->private_data;
+	if (sbinfo) {
+		au_plink_maint_leave(sbinfo);
+		kobject_put(&sbinfo->si_kobj);
+	}
+
+	return 0;
+}
+
+static void au_procfs_plm_write_clean(struct file *file)
+{
+	struct au_sbinfo *sbinfo;
+
+	sbinfo = file->private_data;
+	if (sbinfo)
+		au_plink_clean(sbinfo->si_sb, /*verbose*/0);
+}
+
+static int au_procfs_plm_write_si(struct file *file, unsigned long id)
+{
+	int err;
+	struct super_block *sb;
+	struct au_sbinfo *sbinfo;
+
+	err = -EBUSY;
+	if (unlikely(file->private_data))
+		goto out;
+
+	sb = NULL;
+	/* don't use au_sbilist_lock() here */
+	spin_lock(&au_sbilist.spin);
+	list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
+		if (id == sysaufs_si_id(sbinfo)) {
+			kobject_get(&sbinfo->si_kobj);
+			sb = sbinfo->si_sb;
+			break;
+		}
+	spin_unlock(&au_sbilist.spin);
+
+	err = -EINVAL;
+	if (unlikely(!sb))
+		goto out;
+
+	err = au_plink_maint_enter(sb);
+	if (!err)
+		/* keep kobject_get() */
+		file->private_data = sbinfo;
+	else
+		kobject_put(&sbinfo->si_kobj);
+out:
+	return err;
+}
+
+/*
+ * Accept a valid "si=xxxx" only.
+ * Once it is accepted successfully, accept "clean" too.
+ */
+static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf,
+				   size_t count, loff_t *ppos)
+{
+	ssize_t err;
+	unsigned long id;
+	/* last newline is allowed */
+	char buf[3 + sizeof(unsigned long) * 2 + 1];
+
+	err = -EACCES;
+	if (unlikely(!capable(CAP_SYS_ADMIN)))
+		goto out;
+
+	err = -EINVAL;
+	if (unlikely(count > sizeof(buf)))
+		goto out;
+
+	err = copy_from_user(buf, ubuf, count);
+	if (unlikely(err)) {
+		err = -EFAULT;
+		goto out;
+	}
+	buf[count] = 0;
+
+	err = -EINVAL;
+	if (!strcmp("clean", buf)) {
+		au_procfs_plm_write_clean(file);
+		goto out_success;
+	} else if (unlikely(strncmp("si=", buf, 3)))
+		goto out;
+
+	err = kstrtoul(buf + 3, 16, &id);
+	if (unlikely(err))
+		goto out;
+
+	err = au_procfs_plm_write_si(file, id);
+	if (unlikely(err))
+		goto out;
+
+out_success:
+	err = count; /* success */
+out:
+	return err;
+}
+
+static const struct file_operations au_procfs_plm_fop = {
+	.write		= au_procfs_plm_write,
+	.release	= au_procfs_plm_release,
+	.owner		= THIS_MODULE
+};
+
+/* ---------------------------------------------------------------------- */
+
+static struct proc_dir_entry *au_procfs_dir;
+
+void au_procfs_fin(void)
+{
+	remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir);
+	remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
+}
+
+int __init au_procfs_init(void)
+{
+	int err;
+	struct proc_dir_entry *entry;
+
+	err = -ENOMEM;
+	au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL);
+	if (unlikely(!au_procfs_dir))
+		goto out;
+
+	entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR,
+			    au_procfs_dir, &au_procfs_plm_fop);
+	if (unlikely(!entry))
+		goto out_dir;
+
+	err = 0;
+	goto out; /* success */
+
+
+out_dir:
+	remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
+out:
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/rdu.c
+++ linux-4.4.0/fs/aufs/rdu.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * readdir in userspace.
+ */
+
+#include <linux/compat.h>
+#include <linux/fs_stack.h>
+#include <linux/security.h>
+#include "aufs.h"
+
+/* bits for struct aufs_rdu.flags */
+#define	AuRdu_CALLED	1
+#define	AuRdu_CONT	(1 << 1)
+#define	AuRdu_FULL	(1 << 2)
+#define au_ftest_rdu(flags, name)	((flags) & AuRdu_##name)
+#define au_fset_rdu(flags, name) \
+	do { (flags) |= AuRdu_##name; } while (0)
+#define au_fclr_rdu(flags, name) \
+	do { (flags) &= ~AuRdu_##name; } while (0)
+
+struct au_rdu_arg {
+	struct dir_context		ctx;
+	struct aufs_rdu			*rdu;
+	union au_rdu_ent_ul		ent;
+	unsigned long			end;
+
+	struct super_block		*sb;
+	int				err;
+};
+
+static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen,
+		       loff_t offset, u64 h_ino, unsigned int d_type)
+{
+	int err, len;
+	struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx);
+	struct aufs_rdu *rdu = arg->rdu;
+	struct au_rdu_ent ent;
+
+	err = 0;
+	arg->err = 0;
+	au_fset_rdu(rdu->cookie.flags, CALLED);
+	len = au_rdu_len(nlen);
+	if (arg->ent.ul + len  < arg->end) {
+		ent.ino = h_ino;
+		ent.bindex = rdu->cookie.bindex;
+		ent.type = d_type;
+		ent.nlen = nlen;
+		if (unlikely(nlen > AUFS_MAX_NAMELEN))
+			ent.type = DT_UNKNOWN;
+
+		/* unnecessary to support mmap_sem since this is a dir */
+		err = -EFAULT;
+		if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
+			goto out;
+		if (copy_to_user(arg->ent.e->name, name, nlen))
+			goto out;
+		/* the terminating NULL */
+		if (__put_user(0, arg->ent.e->name + nlen))
+			goto out;
+		err = 0;
+		/* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */
+		arg->ent.ul += len;
+		rdu->rent++;
+	} else {
+		err = -EFAULT;
+		au_fset_rdu(rdu->cookie.flags, FULL);
+		rdu->full = 1;
+		rdu->tail = arg->ent;
+	}
+
+out:
+	/* AuTraceErr(err); */
+	return err;
+}
+
+static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg)
+{
+	int err;
+	loff_t offset;
+	struct au_rdu_cookie *cookie = &arg->rdu->cookie;
+
+	/* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */
+	offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
+	err = offset;
+	if (unlikely(offset != cookie->h_pos))
+		goto out;
+
+	err = 0;
+	do {
+		arg->err = 0;
+		au_fclr_rdu(cookie->flags, CALLED);
+		/* smp_mb(); */
+		err = vfsub_iterate_dir(h_file, &arg->ctx);
+		if (err >= 0)
+			err = arg->err;
+	} while (!err
+		 && au_ftest_rdu(cookie->flags, CALLED)
+		 && !au_ftest_rdu(cookie->flags, FULL));
+	cookie->h_pos = h_file->f_pos;
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+static int au_rdu(struct file *file, struct aufs_rdu *rdu)
+{
+	int err;
+	aufs_bindex_t bend;
+	struct au_rdu_arg arg = {
+		.ctx = {
+			.actor = au_rdu_fill
+		}
+	};
+	struct dentry *dentry;
+	struct inode *inode;
+	struct file *h_file;
+	struct au_rdu_cookie *cookie = &rdu->cookie;
+
+	err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz);
+	if (unlikely(err)) {
+		err = -EFAULT;
+		AuTraceErr(err);
+		goto out;
+	}
+	rdu->rent = 0;
+	rdu->tail = rdu->ent;
+	rdu->full = 0;
+	arg.rdu = rdu;
+	arg.ent = rdu->ent;
+	arg.end = arg.ent.ul;
+	arg.end += rdu->sz;
+
+	err = -ENOTDIR;
+	if (unlikely(!file->f_op->iterate))
+		goto out;
+
+	err = security_file_permission(file, MAY_READ);
+	AuTraceErr(err);
+	if (unlikely(err))
+		goto out;
+
+	dentry = file->f_path.dentry;
+	inode = d_inode(dentry);
+#if 1
+	mutex_lock(&inode->i_mutex);
+#else
+	err = mutex_lock_killable(&inode->i_mutex);
+	AuTraceErr(err);
+	if (unlikely(err))
+		goto out;
+#endif
+
+	arg.sb = inode->i_sb;
+	err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
+	if (unlikely(err))
+		goto out_mtx;
+	err = au_alive_dir(dentry);
+	if (unlikely(err))
+		goto out_si;
+	/* todo: reval? */
+	fi_read_lock(file);
+
+	err = -EAGAIN;
+	if (unlikely(au_ftest_rdu(cookie->flags, CONT)
+		     && cookie->generation != au_figen(file)))
+		goto out_unlock;
+
+	err = 0;
+	if (!rdu->blk) {
+		rdu->blk = au_sbi(arg.sb)->si_rdblk;
+		if (!rdu->blk)
+			rdu->blk = au_dir_size(file, /*dentry*/NULL);
+	}
+	bend = au_fbstart(file);
+	if (cookie->bindex < bend)
+		cookie->bindex = bend;
+	bend = au_fbend_dir(file);
+	/* AuDbg("b%d, b%d\n", cookie->bindex, bend); */
+	for (; !err && cookie->bindex <= bend;
+	     cookie->bindex++, cookie->h_pos = 0) {
+		h_file = au_hf_dir(file, cookie->bindex);
+		if (!h_file)
+			continue;
+
+		au_fclr_rdu(cookie->flags, FULL);
+		err = au_rdu_do(h_file, &arg);
+		AuTraceErr(err);
+		if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
+			break;
+	}
+	AuDbg("rent %llu\n", rdu->rent);
+
+	if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
+		rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
+		au_fset_rdu(cookie->flags, CONT);
+		cookie->generation = au_figen(file);
+	}
+
+	ii_read_lock_child(inode);
+	fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode)));
+	ii_read_unlock(inode);
+
+out_unlock:
+	fi_read_unlock(file);
+out_si:
+	si_read_unlock(arg.sb);
+out_mtx:
+	mutex_unlock(&inode->i_mutex);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu)
+{
+	int err;
+	ino_t ino;
+	unsigned long long nent;
+	union au_rdu_ent_ul *u;
+	struct au_rdu_ent ent;
+	struct super_block *sb;
+
+	err = 0;
+	nent = rdu->nent;
+	u = &rdu->ent;
+	sb = file->f_path.dentry->d_sb;
+	si_read_lock(sb, AuLock_FLUSH);
+	while (nent-- > 0) {
+		/* unnecessary to support mmap_sem since this is a dir */
+		err = copy_from_user(&ent, u->e, sizeof(ent));
+		if (!err)
+			err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino));
+		if (unlikely(err)) {
+			err = -EFAULT;
+			AuTraceErr(err);
+			break;
+		}
+
+		/* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */
+		if (!ent.wh)
+			err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino);
+		else
+			err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type,
+					&ino);
+		if (unlikely(err)) {
+			AuTraceErr(err);
+			break;
+		}
+
+		err = __put_user(ino, &u->e->ino);
+		if (unlikely(err)) {
+			err = -EFAULT;
+			AuTraceErr(err);
+			break;
+		}
+		u->ul += au_rdu_len(ent.nlen);
+	}
+	si_read_unlock(sb);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_rdu_verify(struct aufs_rdu *rdu)
+{
+	AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | "
+	      "%llu, b%d, 0x%x, g%u}\n",
+	      rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ],
+	      rdu->blk,
+	      rdu->rent, rdu->shwh, rdu->full,
+	      rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
+	      rdu->cookie.generation);
+
+	if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu))
+		return 0;
+
+	AuDbg("%u:%u\n",
+	      rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu));
+	return -EINVAL;
+}
+
+long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long err, e;
+	struct aufs_rdu rdu;
+	void __user *p = (void __user *)arg;
+
+	err = copy_from_user(&rdu, p, sizeof(rdu));
+	if (unlikely(err)) {
+		err = -EFAULT;
+		AuTraceErr(err);
+		goto out;
+	}
+	err = au_rdu_verify(&rdu);
+	if (unlikely(err))
+		goto out;
+
+	switch (cmd) {
+	case AUFS_CTL_RDU:
+		err = au_rdu(file, &rdu);
+		if (unlikely(err))
+			break;
+
+		e = copy_to_user(p, &rdu, sizeof(rdu));
+		if (unlikely(e)) {
+			err = -EFAULT;
+			AuTraceErr(err);
+		}
+		break;
+	case AUFS_CTL_RDU_INO:
+		err = au_rdu_ino(file, &rdu);
+		break;
+
+	default:
+		/* err = -ENOTTY; */
+		err = -EINVAL;
+	}
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+#ifdef CONFIG_COMPAT
+long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long err, e;
+	struct aufs_rdu rdu;
+	void __user *p = compat_ptr(arg);
+
+	/* todo: get_user()? */
+	err = copy_from_user(&rdu, p, sizeof(rdu));
+	if (unlikely(err)) {
+		err = -EFAULT;
+		AuTraceErr(err);
+		goto out;
+	}
+	rdu.ent.e = compat_ptr(rdu.ent.ul);
+	err = au_rdu_verify(&rdu);
+	if (unlikely(err))
+		goto out;
+
+	switch (cmd) {
+	case AUFS_CTL_RDU:
+		err = au_rdu(file, &rdu);
+		if (unlikely(err))
+			break;
+
+		rdu.ent.ul = ptr_to_compat(rdu.ent.e);
+		rdu.tail.ul = ptr_to_compat(rdu.tail.e);
+		e = copy_to_user(p, &rdu, sizeof(rdu));
+		if (unlikely(e)) {
+			err = -EFAULT;
+			AuTraceErr(err);
+		}
+		break;
+	case AUFS_CTL_RDU_INO:
+		err = au_rdu_ino(file, &rdu);
+		break;
+
+	default:
+		/* err = -ENOTTY; */
+		err = -EINVAL;
+	}
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+#endif
--- linux-4.4.0.orig/fs/aufs/rwsem.h
+++ linux-4.4.0/fs/aufs/rwsem.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * simple read-write semaphore wrappers
+ */
+
+#ifndef __AUFS_RWSEM_H__
+#define __AUFS_RWSEM_H__
+
+#ifdef __KERNEL__
+
+#include "debug.h"
+
+struct au_rwsem {
+	struct rw_semaphore	rwsem;
+#ifdef CONFIG_AUFS_DEBUG
+	/* just for debugging, not almighty counter */
+	atomic_t		rcnt, wcnt;
+#endif
+};
+
+#ifdef CONFIG_AUFS_DEBUG
+#define AuDbgCntInit(rw) do { \
+	atomic_set(&(rw)->rcnt, 0); \
+	atomic_set(&(rw)->wcnt, 0); \
+	smp_mb(); /* atomic set */ \
+} while (0)
+
+#define AuDbgRcntInc(rw)	atomic_inc(&(rw)->rcnt)
+#define AuDbgRcntDec(rw)	WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0)
+#define AuDbgWcntInc(rw)	atomic_inc(&(rw)->wcnt)
+#define AuDbgWcntDec(rw)	WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0)
+#else
+#define AuDbgCntInit(rw)	do {} while (0)
+#define AuDbgRcntInc(rw)	do {} while (0)
+#define AuDbgRcntDec(rw)	do {} while (0)
+#define AuDbgWcntInc(rw)	do {} while (0)
+#define AuDbgWcntDec(rw)	do {} while (0)
+#endif /* CONFIG_AUFS_DEBUG */
+
+/* to debug easier, do not make them inlined functions */
+#define AuRwMustNoWaiters(rw)	AuDebugOn(!list_empty(&(rw)->rwsem.wait_list))
+/* rwsem_is_locked() is unusable */
+#define AuRwMustReadLock(rw)	AuDebugOn(atomic_read(&(rw)->rcnt) <= 0)
+#define AuRwMustWriteLock(rw)	AuDebugOn(atomic_read(&(rw)->wcnt) <= 0)
+#define AuRwMustAnyLock(rw)	AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \
+					&& atomic_read(&(rw)->wcnt) <= 0)
+#define AuRwDestroy(rw)		AuDebugOn(atomic_read(&(rw)->rcnt) \
+					|| atomic_read(&(rw)->wcnt))
+
+#define au_rw_class(rw, key)	lockdep_set_class(&(rw)->rwsem, key)
+
+static inline void au_rw_init(struct au_rwsem *rw)
+{
+	AuDbgCntInit(rw);
+	init_rwsem(&rw->rwsem);
+}
+
+static inline void au_rw_init_wlock(struct au_rwsem *rw)
+{
+	au_rw_init(rw);
+	down_write(&rw->rwsem);
+	AuDbgWcntInc(rw);
+}
+
+static inline void au_rw_init_wlock_nested(struct au_rwsem *rw,
+					   unsigned int lsc)
+{
+	au_rw_init(rw);
+	down_write_nested(&rw->rwsem, lsc);
+	AuDbgWcntInc(rw);
+}
+
+static inline void au_rw_read_lock(struct au_rwsem *rw)
+{
+	down_read(&rw->rwsem);
+	AuDbgRcntInc(rw);
+}
+
+static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc)
+{
+	down_read_nested(&rw->rwsem, lsc);
+	AuDbgRcntInc(rw);
+}
+
+static inline void au_rw_read_unlock(struct au_rwsem *rw)
+{
+	AuRwMustReadLock(rw);
+	AuDbgRcntDec(rw);
+	up_read(&rw->rwsem);
+}
+
+static inline void au_rw_dgrade_lock(struct au_rwsem *rw)
+{
+	AuRwMustWriteLock(rw);
+	AuDbgRcntInc(rw);
+	AuDbgWcntDec(rw);
+	downgrade_write(&rw->rwsem);
+}
+
+static inline void au_rw_write_lock(struct au_rwsem *rw)
+{
+	down_write(&rw->rwsem);
+	AuDbgWcntInc(rw);
+}
+
+static inline void au_rw_write_lock_nested(struct au_rwsem *rw,
+					   unsigned int lsc)
+{
+	down_write_nested(&rw->rwsem, lsc);
+	AuDbgWcntInc(rw);
+}
+
+static inline void au_rw_write_unlock(struct au_rwsem *rw)
+{
+	AuRwMustWriteLock(rw);
+	AuDbgWcntDec(rw);
+	up_write(&rw->rwsem);
+}
+
+/* why is not _nested version defined */
+static inline int au_rw_read_trylock(struct au_rwsem *rw)
+{
+	int ret;
+
+	ret = down_read_trylock(&rw->rwsem);
+	if (ret)
+		AuDbgRcntInc(rw);
+	return ret;
+}
+
+static inline int au_rw_write_trylock(struct au_rwsem *rw)
+{
+	int ret;
+
+	ret = down_write_trylock(&rw->rwsem);
+	if (ret)
+		AuDbgWcntInc(rw);
+	return ret;
+}
+
+#undef AuDbgCntInit
+#undef AuDbgRcntInc
+#undef AuDbgRcntDec
+#undef AuDbgWcntInc
+#undef AuDbgWcntDec
+
+#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
+static inline void prefix##_read_lock(param) \
+{ au_rw_read_lock(rwsem); } \
+static inline void prefix##_write_lock(param) \
+{ au_rw_write_lock(rwsem); } \
+static inline int prefix##_read_trylock(param) \
+{ return au_rw_read_trylock(rwsem); } \
+static inline int prefix##_write_trylock(param) \
+{ return au_rw_write_trylock(rwsem); }
+/* why is not _nested version defined */
+/* static inline void prefix##_read_trylock_nested(param, lsc)
+{ au_rw_read_trylock_nested(rwsem, lsc)); }
+static inline void prefix##_write_trylock_nestd(param, lsc)
+{ au_rw_write_trylock_nested(rwsem, lsc); } */
+
+#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \
+static inline void prefix##_read_unlock(param) \
+{ au_rw_read_unlock(rwsem); } \
+static inline void prefix##_write_unlock(param) \
+{ au_rw_write_unlock(rwsem); } \
+static inline void prefix##_downgrade_lock(param) \
+{ au_rw_dgrade_lock(rwsem); }
+
+#define AuSimpleRwsemFuncs(prefix, param, rwsem) \
+	AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
+	AuSimpleUnlockRwsemFuncs(prefix, param, rwsem)
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_RWSEM_H__ */
--- linux-4.4.0.orig/fs/aufs/sbinfo.c
+++ linux-4.4.0/fs/aufs/sbinfo.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * superblock private data
+ */
+
+#include "aufs.h"
+
+/*
+ * they are necessary regardless sysfs is disabled.
+ */
+void au_si_free(struct kobject *kobj)
+{
+	int i;
+	struct au_sbinfo *sbinfo;
+	char *locked __maybe_unused; /* debug only */
+
+	sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
+	for (i = 0; i < AuPlink_NHASH; i++)
+		AuDebugOn(!hlist_empty(&sbinfo->si_plink[i].head));
+	AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len));
+
+	AuDebugOn(!hlist_empty(&sbinfo->si_symlink.head));
+
+	au_rw_write_lock(&sbinfo->si_rwsem);
+	au_br_free(sbinfo);
+	au_rw_write_unlock(&sbinfo->si_rwsem);
+
+	AuDebugOn(radix_tree_gang_lookup
+		  (&sbinfo->au_si_pid.tree, (void **)&locked,
+		   /*first_index*/PID_MAX_DEFAULT - 1,
+		   /*max_items*/sizeof(locked)/sizeof(*locked)));
+
+	kfree(sbinfo->si_branch);
+	kfree(sbinfo->au_si_pid.bitmap);
+	mutex_destroy(&sbinfo->si_xib_mtx);
+	AuRwDestroy(&sbinfo->si_rwsem);
+
+	kfree(sbinfo);
+}
+
+int au_si_alloc(struct super_block *sb)
+{
+	int err, i;
+	struct au_sbinfo *sbinfo;
+	static struct lock_class_key aufs_si;
+
+	err = -ENOMEM;
+	sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS);
+	if (unlikely(!sbinfo))
+		goto out;
+
+	BUILD_BUG_ON(sizeof(unsigned long) !=
+		     sizeof(*sbinfo->au_si_pid.bitmap));
+	sbinfo->au_si_pid.bitmap = kcalloc(BITS_TO_LONGS(PID_MAX_DEFAULT),
+					sizeof(*sbinfo->au_si_pid.bitmap),
+					GFP_NOFS);
+	if (unlikely(!sbinfo->au_si_pid.bitmap))
+		goto out_sbinfo;
+
+	/* will be reallocated separately */
+	sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS);
+	if (unlikely(!sbinfo->si_branch))
+		goto out_pidmap;
+
+	err = sysaufs_si_init(sbinfo);
+	if (unlikely(err))
+		goto out_br;
+
+	au_nwt_init(&sbinfo->si_nowait);
+	au_rw_init_wlock(&sbinfo->si_rwsem);
+	au_rw_class(&sbinfo->si_rwsem, &aufs_si);
+	spin_lock_init(&sbinfo->au_si_pid.tree_lock);
+	INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL);
+
+	atomic_long_set(&sbinfo->si_ninodes, 0);
+	atomic_long_set(&sbinfo->si_nfiles, 0);
+
+	sbinfo->si_bend = -1;
+	sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2;
+
+	sbinfo->si_wbr_copyup = AuWbrCopyup_Def;
+	sbinfo->si_wbr_create = AuWbrCreate_Def;
+	sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup;
+	sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create;
+
+	au_fhsm_init(sbinfo);
+
+	sbinfo->si_mntflags = au_opts_plink(AuOpt_Def);
+
+	au_sphl_init(&sbinfo->si_symlink);
+
+	sbinfo->si_xino_jiffy = jiffies;
+	sbinfo->si_xino_expire
+		= msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC);
+	mutex_init(&sbinfo->si_xib_mtx);
+	sbinfo->si_xino_brid = -1;
+	/* leave si_xib_last_pindex and si_xib_next_bit */
+
+	au_sphl_init(&sbinfo->si_aopen);
+
+	sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC);
+	sbinfo->si_rdblk = AUFS_RDBLK_DEF;
+	sbinfo->si_rdhash = AUFS_RDHASH_DEF;
+	sbinfo->si_dirwh = AUFS_DIRWH_DEF;
+
+	for (i = 0; i < AuPlink_NHASH; i++)
+		au_sphl_init(sbinfo->si_plink + i);
+	init_waitqueue_head(&sbinfo->si_plink_wq);
+	spin_lock_init(&sbinfo->si_plink_maint_lock);
+
+	au_sphl_init(&sbinfo->si_files);
+
+	/* with getattr by default */
+	sbinfo->si_iop_array = aufs_iop;
+
+	/* leave other members for sysaufs and si_mnt. */
+	sbinfo->si_sb = sb;
+	sb->s_fs_info = sbinfo;
+	si_pid_set(sb);
+	return 0; /* success */
+
+out_br:
+	kfree(sbinfo->si_branch);
+out_pidmap:
+	kfree(sbinfo->au_si_pid.bitmap);
+out_sbinfo:
+	kfree(sbinfo);
+out:
+	return err;
+}
+
+int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr)
+{
+	int err, sz;
+	struct au_branch **brp;
+
+	AuRwMustWriteLock(&sbinfo->si_rwsem);
+
+	err = -ENOMEM;
+	sz = sizeof(*brp) * (sbinfo->si_bend + 1);
+	if (unlikely(!sz))
+		sz = sizeof(*brp);
+	brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS);
+	if (brp) {
+		sbinfo->si_branch = brp;
+		err = 0;
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+unsigned int au_sigen_inc(struct super_block *sb)
+{
+	unsigned int gen;
+	struct inode *inode;
+
+	SiMustWriteLock(sb);
+
+	gen = ++au_sbi(sb)->si_generation;
+	au_update_digen(sb->s_root);
+	inode = d_inode(sb->s_root);
+	au_update_iigen(inode, /*half*/0);
+	inode->i_version++;
+	return gen;
+}
+
+aufs_bindex_t au_new_br_id(struct super_block *sb)
+{
+	aufs_bindex_t br_id;
+	int i;
+	struct au_sbinfo *sbinfo;
+
+	SiMustWriteLock(sb);
+
+	sbinfo = au_sbi(sb);
+	for (i = 0; i <= AUFS_BRANCH_MAX; i++) {
+		br_id = ++sbinfo->si_last_br_id;
+		AuDebugOn(br_id < 0);
+		if (br_id && au_br_index(sb, br_id) < 0)
+			return br_id;
+	}
+
+	return -1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* it is ok that new 'nwt' tasks are appended while we are sleeping */
+int si_read_lock(struct super_block *sb, int flags)
+{
+	int err;
+
+	err = 0;
+	if (au_ftest_lock(flags, FLUSH))
+		au_nwt_flush(&au_sbi(sb)->si_nowait);
+
+	si_noflush_read_lock(sb);
+	err = au_plink_maint(sb, flags);
+	if (unlikely(err))
+		si_read_unlock(sb);
+
+	return err;
+}
+
+int si_write_lock(struct super_block *sb, int flags)
+{
+	int err;
+
+	if (au_ftest_lock(flags, FLUSH))
+		au_nwt_flush(&au_sbi(sb)->si_nowait);
+
+	si_noflush_write_lock(sb);
+	err = au_plink_maint(sb, flags);
+	if (unlikely(err))
+		si_write_unlock(sb);
+
+	return err;
+}
+
+/* dentry and super_block lock. call at entry point */
+int aufs_read_lock(struct dentry *dentry, int flags)
+{
+	int err;
+	struct super_block *sb;
+
+	sb = dentry->d_sb;
+	err = si_read_lock(sb, flags);
+	if (unlikely(err))
+		goto out;
+
+	if (au_ftest_lock(flags, DW))
+		di_write_lock_child(dentry);
+	else
+		di_read_lock_child(dentry, flags);
+
+	if (au_ftest_lock(flags, GEN)) {
+		err = au_digen_test(dentry, au_sigen(sb));
+		if (!au_opt_test(au_mntflags(sb), UDBA_NONE))
+			AuDebugOn(!err && au_dbrange_test(dentry));
+		else if (!err)
+			err = au_dbrange_test(dentry);
+		if (unlikely(err))
+			aufs_read_unlock(dentry, flags);
+	}
+
+out:
+	return err;
+}
+
+void aufs_read_unlock(struct dentry *dentry, int flags)
+{
+	if (au_ftest_lock(flags, DW))
+		di_write_unlock(dentry);
+	else
+		di_read_unlock(dentry, flags);
+	si_read_unlock(dentry->d_sb);
+}
+
+void aufs_write_lock(struct dentry *dentry)
+{
+	si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW);
+	di_write_lock_child(dentry);
+}
+
+void aufs_write_unlock(struct dentry *dentry)
+{
+	di_write_unlock(dentry);
+	si_write_unlock(dentry->d_sb);
+}
+
+int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags)
+{
+	int err;
+	unsigned int sigen;
+	struct super_block *sb;
+
+	sb = d1->d_sb;
+	err = si_read_lock(sb, flags);
+	if (unlikely(err))
+		goto out;
+
+	di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS));
+
+	if (au_ftest_lock(flags, GEN)) {
+		sigen = au_sigen(sb);
+		err = au_digen_test(d1, sigen);
+		AuDebugOn(!err && au_dbrange_test(d1));
+		if (!err) {
+			err = au_digen_test(d2, sigen);
+			AuDebugOn(!err && au_dbrange_test(d2));
+		}
+		if (unlikely(err))
+			aufs_read_and_write_unlock2(d1, d2);
+	}
+
+out:
+	return err;
+}
+
+void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2)
+{
+	di_write_unlock2(d1, d2);
+	si_read_unlock(d1->d_sb);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int si_pid_test_slow(struct super_block *sb)
+{
+	void *p;
+
+	rcu_read_lock();
+	p = radix_tree_lookup(&au_sbi(sb)->au_si_pid.tree, current->pid);
+	rcu_read_unlock();
+
+	return (long)!!p;
+}
+
+void si_pid_set_slow(struct super_block *sb)
+{
+	int err;
+	struct au_sbinfo *sbinfo;
+
+	AuDebugOn(si_pid_test_slow(sb));
+
+	sbinfo = au_sbi(sb);
+	err = radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
+	AuDebugOn(err);
+	spin_lock(&sbinfo->au_si_pid.tree_lock);
+	err = radix_tree_insert(&sbinfo->au_si_pid.tree, current->pid,
+				/*any valid ptr*/sb);
+	spin_unlock(&sbinfo->au_si_pid.tree_lock);
+	AuDebugOn(err);
+	radix_tree_preload_end();
+}
+
+void si_pid_clr_slow(struct super_block *sb)
+{
+	void *p;
+	struct au_sbinfo *sbinfo;
+
+	AuDebugOn(!si_pid_test_slow(sb));
+
+	sbinfo = au_sbi(sb);
+	spin_lock(&sbinfo->au_si_pid.tree_lock);
+	p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid);
+	spin_unlock(&sbinfo->au_si_pid.tree_lock);
+}
--- linux-4.4.0.orig/fs/aufs/spl.h
+++ linux-4.4.0/fs/aufs/spl.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * simple list protected by a spinlock
+ */
+
+#ifndef __AUFS_SPL_H__
+#define __AUFS_SPL_H__
+
+#ifdef __KERNEL__
+
+struct au_splhead {
+	spinlock_t		spin;
+	struct list_head	head;
+};
+
+static inline void au_spl_init(struct au_splhead *spl)
+{
+	spin_lock_init(&spl->spin);
+	INIT_LIST_HEAD(&spl->head);
+}
+
+static inline void au_spl_add(struct list_head *list, struct au_splhead *spl)
+{
+	spin_lock(&spl->spin);
+	list_add(list, &spl->head);
+	spin_unlock(&spl->spin);
+}
+
+static inline void au_spl_del(struct list_head *list, struct au_splhead *spl)
+{
+	spin_lock(&spl->spin);
+	list_del(list);
+	spin_unlock(&spl->spin);
+}
+
+static inline void au_spl_del_rcu(struct list_head *list,
+				  struct au_splhead *spl)
+{
+	spin_lock(&spl->spin);
+	list_del_rcu(list);
+	spin_unlock(&spl->spin);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct au_sphlhead {
+	spinlock_t		spin;
+	struct hlist_head	head;
+};
+
+static inline void au_sphl_init(struct au_sphlhead *sphl)
+{
+	spin_lock_init(&sphl->spin);
+	INIT_HLIST_HEAD(&sphl->head);
+}
+
+static inline void au_sphl_add(struct hlist_node *hlist,
+			       struct au_sphlhead *sphl)
+{
+	spin_lock(&sphl->spin);
+	hlist_add_head(hlist, &sphl->head);
+	spin_unlock(&sphl->spin);
+}
+
+static inline void au_sphl_del(struct hlist_node *hlist,
+			       struct au_sphlhead *sphl)
+{
+	spin_lock(&sphl->spin);
+	hlist_del(hlist);
+	spin_unlock(&sphl->spin);
+}
+
+static inline void au_sphl_del_rcu(struct hlist_node *hlist,
+				   struct au_sphlhead *sphl)
+{
+	spin_lock(&sphl->spin);
+	hlist_del_rcu(hlist);
+	spin_unlock(&sphl->spin);
+}
+
+static inline unsigned long au_sphl_count(struct au_sphlhead *sphl)
+{
+	unsigned long cnt;
+	struct hlist_node *pos;
+
+	cnt = 0;
+	spin_lock(&sphl->spin);
+	hlist_for_each(pos, &sphl->head)
+		cnt++;
+	spin_unlock(&sphl->spin);
+	return cnt;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_SPL_H__ */
--- linux-4.4.0.orig/fs/aufs/super.c
+++ linux-4.4.0/fs/aufs/super.c
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * mount and super_block operations
+ */
+
+#include <linux/mm.h>
+#include <linux/seq_file.h>
+#include <linux/statfs.h>
+#include <linux/vmalloc.h>
+#include "aufs.h"
+
+/*
+ * super_operations
+ */
+static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused)
+{
+	struct au_icntnr *c;
+
+	c = au_cache_alloc_icntnr();
+	if (c) {
+		au_icntnr_init(c);
+		c->vfs_inode.i_version = 1; /* sigen(sb); */
+		c->iinfo.ii_hinode = NULL;
+		return &c->vfs_inode;
+	}
+	return NULL;
+}
+
+static void aufs_destroy_inode_cb(struct rcu_head *head)
+{
+	struct inode *inode = container_of(head, struct inode, i_rcu);
+
+	INIT_HLIST_HEAD(&inode->i_dentry);
+	au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode));
+}
+
+static void aufs_destroy_inode(struct inode *inode)
+{
+	au_iinfo_fin(inode);
+	call_rcu(&inode->i_rcu, aufs_destroy_inode_cb);
+}
+
+struct inode *au_iget_locked(struct super_block *sb, ino_t ino)
+{
+	struct inode *inode;
+	int err;
+
+	inode = iget_locked(sb, ino);
+	if (unlikely(!inode)) {
+		inode = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+	if (!(inode->i_state & I_NEW))
+		goto out;
+
+	err = au_xigen_new(inode);
+	if (!err)
+		err = au_iinfo_init(inode);
+	if (!err)
+		inode->i_version++;
+	else {
+		iget_failed(inode);
+		inode = ERR_PTR(err);
+	}
+
+out:
+	/* never return NULL */
+	AuDebugOn(!inode);
+	AuTraceErrPtr(inode);
+	return inode;
+}
+
+/* lock free root dinfo */
+static int au_show_brs(struct seq_file *seq, struct super_block *sb)
+{
+	int err;
+	aufs_bindex_t bindex, bend;
+	struct path path;
+	struct au_hdentry *hdp;
+	struct au_branch *br;
+	au_br_perm_str_t perm;
+
+	err = 0;
+	bend = au_sbend(sb);
+	hdp = au_di(sb->s_root)->di_hdentry;
+	for (bindex = 0; !err && bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		path.mnt = au_br_mnt(br);
+		path.dentry = hdp[bindex].hd_dentry;
+		err = au_seq_path(seq, &path);
+		if (!err) {
+			au_optstr_br_perm(&perm, br->br_perm);
+			seq_printf(seq, "=%s", perm.a);
+			if (bindex != bend)
+				seq_putc(seq, ':');
+		}
+	}
+	if (unlikely(err || seq_has_overflowed(seq)))
+		err = -E2BIG;
+
+	return err;
+}
+
+static void au_show_wbr_create(struct seq_file *m, int v,
+			       struct au_sbinfo *sbinfo)
+{
+	const char *pat;
+
+	AuRwMustAnyLock(&sbinfo->si_rwsem);
+
+	seq_puts(m, ",create=");
+	pat = au_optstr_wbr_create(v);
+	switch (v) {
+	case AuWbrCreate_TDP:
+	case AuWbrCreate_RR:
+	case AuWbrCreate_MFS:
+	case AuWbrCreate_PMFS:
+		seq_puts(m, pat);
+		break;
+	case AuWbrCreate_MFSV:
+		seq_printf(m, /*pat*/"mfs:%lu",
+			   jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
+			   / MSEC_PER_SEC);
+		break;
+	case AuWbrCreate_PMFSV:
+		seq_printf(m, /*pat*/"pmfs:%lu",
+			   jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
+			   / MSEC_PER_SEC);
+		break;
+	case AuWbrCreate_MFSRR:
+		seq_printf(m, /*pat*/"mfsrr:%llu",
+			   sbinfo->si_wbr_mfs.mfsrr_watermark);
+		break;
+	case AuWbrCreate_MFSRRV:
+		seq_printf(m, /*pat*/"mfsrr:%llu:%lu",
+			   sbinfo->si_wbr_mfs.mfsrr_watermark,
+			   jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
+			   / MSEC_PER_SEC);
+		break;
+	case AuWbrCreate_PMFSRR:
+		seq_printf(m, /*pat*/"pmfsrr:%llu",
+			   sbinfo->si_wbr_mfs.mfsrr_watermark);
+		break;
+	case AuWbrCreate_PMFSRRV:
+		seq_printf(m, /*pat*/"pmfsrr:%llu:%lu",
+			   sbinfo->si_wbr_mfs.mfsrr_watermark,
+			   jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
+			   / MSEC_PER_SEC);
+		break;
+	}
+}
+
+static int au_show_xino(struct seq_file *seq, struct super_block *sb)
+{
+#ifdef CONFIG_SYSFS
+	return 0;
+#else
+	int err;
+	const int len = sizeof(AUFS_XINO_FNAME) - 1;
+	aufs_bindex_t bindex, brid;
+	struct qstr *name;
+	struct file *f;
+	struct dentry *d, *h_root;
+	struct au_hdentry *hdp;
+
+	AuRwMustAnyLock(&sbinfo->si_rwsem);
+
+	err = 0;
+	f = au_sbi(sb)->si_xib;
+	if (!f)
+		goto out;
+
+	/* stop printing the default xino path on the first writable branch */
+	h_root = NULL;
+	brid = au_xino_brid(sb);
+	if (brid >= 0) {
+		bindex = au_br_index(sb, brid);
+		hdp = au_di(sb->s_root)->di_hdentry;
+		h_root = hdp[0 + bindex].hd_dentry;
+	}
+	d = f->f_path.dentry;
+	name = &d->d_name;
+	/* safe ->d_parent because the file is unlinked */
+	if (d->d_parent == h_root
+	    && name->len == len
+	    && !memcmp(name->name, AUFS_XINO_FNAME, len))
+		goto out;
+
+	seq_puts(seq, ",xino=");
+	err = au_xino_path(seq, f);
+
+out:
+	return err;
+#endif
+}
+
+/* seq_file will re-call me in case of too long string */
+static int aufs_show_options(struct seq_file *m, struct dentry *dentry)
+{
+	int err;
+	unsigned int mnt_flags, v;
+	struct super_block *sb;
+	struct au_sbinfo *sbinfo;
+
+#define AuBool(name, str) do { \
+	v = au_opt_test(mnt_flags, name); \
+	if (v != au_opt_test(AuOpt_Def, name)) \
+		seq_printf(m, ",%s" #str, v ? "" : "no"); \
+} while (0)
+
+#define AuStr(name, str) do { \
+	v = mnt_flags & AuOptMask_##name; \
+	if (v != (AuOpt_Def & AuOptMask_##name)) \
+		seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \
+} while (0)
+
+#define AuUInt(name, str, val) do { \
+	if (val != AUFS_##name##_DEF) \
+		seq_printf(m, "," #str "=%u", val); \
+} while (0)
+
+	sb = dentry->d_sb;
+	if (sb->s_flags & MS_POSIXACL)
+		seq_puts(m, ",acl");
+
+	/* lock free root dinfo */
+	si_noflush_read_lock(sb);
+	sbinfo = au_sbi(sb);
+	seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo));
+
+	mnt_flags = au_mntflags(sb);
+	if (au_opt_test(mnt_flags, XINO)) {
+		err = au_show_xino(m, sb);
+		if (unlikely(err))
+			goto out;
+	} else
+		seq_puts(m, ",noxino");
+
+	AuBool(TRUNC_XINO, trunc_xino);
+	AuStr(UDBA, udba);
+	AuBool(SHWH, shwh);
+	AuBool(PLINK, plink);
+	AuBool(DIO, dio);
+	AuBool(DIRPERM1, dirperm1);
+
+	v = sbinfo->si_wbr_create;
+	if (v != AuWbrCreate_Def)
+		au_show_wbr_create(m, v, sbinfo);
+
+	v = sbinfo->si_wbr_copyup;
+	if (v != AuWbrCopyup_Def)
+		seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v));
+
+	v = au_opt_test(mnt_flags, ALWAYS_DIROPQ);
+	if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ))
+		seq_printf(m, ",diropq=%c", v ? 'a' : 'w');
+
+	AuUInt(DIRWH, dirwh, sbinfo->si_dirwh);
+
+	v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
+	AuUInt(RDCACHE, rdcache, v);
+
+	AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
+	AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
+
+	au_fhsm_show(m, sbinfo);
+
+	AuBool(SUM, sum);
+	/* AuBool(SUM_W, wsum); */
+	AuBool(WARN_PERM, warn_perm);
+	AuBool(VERBOSE, verbose);
+
+out:
+	/* be sure to print "br:" last */
+	if (!sysaufs_brs) {
+		seq_puts(m, ",br:");
+		au_show_brs(m, sb);
+	}
+	si_read_unlock(sb);
+	return 0;
+
+#undef AuBool
+#undef AuStr
+#undef AuUInt
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* sum mode which returns the summation for statfs(2) */
+
+static u64 au_add_till_max(u64 a, u64 b)
+{
+	u64 old;
+
+	old = a;
+	a += b;
+	if (old <= a)
+		return a;
+	return ULLONG_MAX;
+}
+
+static u64 au_mul_till_max(u64 a, long mul)
+{
+	u64 old;
+
+	old = a;
+	a *= mul;
+	if (old <= a)
+		return a;
+	return ULLONG_MAX;
+}
+
+static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf)
+{
+	int err;
+	long bsize, factor;
+	u64 blocks, bfree, bavail, files, ffree;
+	aufs_bindex_t bend, bindex, i;
+	unsigned char shared;
+	struct path h_path;
+	struct super_block *h_sb;
+
+	err = 0;
+	bsize = LONG_MAX;
+	files = 0;
+	ffree = 0;
+	blocks = 0;
+	bfree = 0;
+	bavail = 0;
+	bend = au_sbend(sb);
+	for (bindex = 0; bindex <= bend; bindex++) {
+		h_path.mnt = au_sbr_mnt(sb, bindex);
+		h_sb = h_path.mnt->mnt_sb;
+		shared = 0;
+		for (i = 0; !shared && i < bindex; i++)
+			shared = (au_sbr_sb(sb, i) == h_sb);
+		if (shared)
+			continue;
+
+		/* sb->s_root for NFS is unreliable */
+		h_path.dentry = h_path.mnt->mnt_root;
+		err = vfs_statfs(&h_path, buf);
+		if (unlikely(err))
+			goto out;
+
+		if (bsize > buf->f_bsize) {
+			/*
+			 * we will reduce bsize, so we have to expand blocks
+			 * etc. to match them again
+			 */
+			factor = (bsize / buf->f_bsize);
+			blocks = au_mul_till_max(blocks, factor);
+			bfree = au_mul_till_max(bfree, factor);
+			bavail = au_mul_till_max(bavail, factor);
+			bsize = buf->f_bsize;
+		}
+
+		factor = (buf->f_bsize / bsize);
+		blocks = au_add_till_max(blocks,
+				au_mul_till_max(buf->f_blocks, factor));
+		bfree = au_add_till_max(bfree,
+				au_mul_till_max(buf->f_bfree, factor));
+		bavail = au_add_till_max(bavail,
+				au_mul_till_max(buf->f_bavail, factor));
+		files = au_add_till_max(files, buf->f_files);
+		ffree = au_add_till_max(ffree, buf->f_ffree);
+	}
+
+	buf->f_bsize = bsize;
+	buf->f_blocks = blocks;
+	buf->f_bfree = bfree;
+	buf->f_bavail = bavail;
+	buf->f_files = files;
+	buf->f_ffree = ffree;
+	buf->f_frsize = 0;
+
+out:
+	return err;
+}
+
+static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	int err;
+	struct path h_path;
+	struct super_block *sb;
+
+	/* lock free root dinfo */
+	sb = dentry->d_sb;
+	si_noflush_read_lock(sb);
+	if (!au_opt_test(au_mntflags(sb), SUM)) {
+		/* sb->s_root for NFS is unreliable */
+		h_path.mnt = au_sbr_mnt(sb, 0);
+		h_path.dentry = h_path.mnt->mnt_root;
+		err = vfs_statfs(&h_path, buf);
+	} else
+		err = au_statfs_sum(sb, buf);
+	si_read_unlock(sb);
+
+	if (!err) {
+		buf->f_type = AUFS_SUPER_MAGIC;
+		buf->f_namelen = AUFS_MAX_NAMELEN;
+		memset(&buf->f_fsid, 0, sizeof(buf->f_fsid));
+	}
+	/* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int aufs_sync_fs(struct super_block *sb, int wait)
+{
+	int err, e;
+	aufs_bindex_t bend, bindex;
+	struct au_branch *br;
+	struct super_block *h_sb;
+
+	err = 0;
+	si_noflush_read_lock(sb);
+	bend = au_sbend(sb);
+	for (bindex = 0; bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		if (!au_br_writable(br->br_perm))
+			continue;
+
+		h_sb = au_sbr_sb(sb, bindex);
+		if (h_sb->s_op->sync_fs) {
+			e = h_sb->s_op->sync_fs(h_sb, wait);
+			if (unlikely(e && !err))
+				err = e;
+			/* go on even if an error happens */
+		}
+	}
+	si_read_unlock(sb);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* final actions when unmounting a file system */
+static void aufs_put_super(struct super_block *sb)
+{
+	struct au_sbinfo *sbinfo;
+
+	sbinfo = au_sbi(sb);
+	if (!sbinfo)
+		return;
+
+	dbgaufs_si_fin(sbinfo);
+	kobject_put(&sbinfo->si_kobj);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb,
+		     struct super_block *sb, void *arg)
+{
+	void *array;
+	unsigned long long n, sz;
+
+	array = NULL;
+	n = 0;
+	if (!*hint)
+		goto out;
+
+	if (*hint > ULLONG_MAX / sizeof(array)) {
+		array = ERR_PTR(-EMFILE);
+		pr_err("hint %llu\n", *hint);
+		goto out;
+	}
+
+	sz = sizeof(array) * *hint;
+	array = kzalloc(sz, GFP_NOFS);
+	if (unlikely(!array))
+		array = vzalloc(sz);
+	if (unlikely(!array)) {
+		array = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	n = cb(sb, array, *hint, arg);
+	AuDebugOn(n > *hint);
+
+out:
+	*hint = n;
+	return array;
+}
+
+static unsigned long long au_iarray_cb(struct super_block *sb, void *a,
+				       unsigned long long max __maybe_unused,
+				       void *arg)
+{
+	unsigned long long n;
+	struct inode **p, *inode;
+	struct list_head *head;
+
+	n = 0;
+	p = a;
+	head = arg;
+	spin_lock(&sb->s_inode_list_lock);
+	list_for_each_entry(inode, head, i_sb_list) {
+		if (!is_bad_inode(inode)
+		    && au_ii(inode)->ii_bstart >= 0) {
+			spin_lock(&inode->i_lock);
+			if (atomic_read(&inode->i_count)) {
+				au_igrab(inode);
+				*p++ = inode;
+				n++;
+				AuDebugOn(n > max);
+			}
+			spin_unlock(&inode->i_lock);
+		}
+	}
+	spin_unlock(&sb->s_inode_list_lock);
+
+	return n;
+}
+
+struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max)
+{
+	*max = atomic_long_read(&au_sbi(sb)->si_ninodes);
+	return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes);
+}
+
+void au_iarray_free(struct inode **a, unsigned long long max)
+{
+	unsigned long long ull;
+
+	for (ull = 0; ull < max; ull++)
+		iput(a[ull]);
+	kvfree(a);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * refresh dentry and inode at remount time.
+ */
+/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */
+static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags,
+		      struct dentry *parent)
+{
+	int err;
+
+	di_write_lock_child(dentry);
+	di_read_lock_parent(parent, AuLock_IR);
+	err = au_refresh_dentry(dentry, parent);
+	if (!err && dir_flags)
+		au_hn_reset(d_inode(dentry), dir_flags);
+	di_read_unlock(parent, AuLock_IR);
+	di_write_unlock(dentry);
+
+	return err;
+}
+
+static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen,
+			   struct au_sbinfo *sbinfo,
+			   const unsigned int dir_flags, unsigned int do_idop)
+{
+	int err;
+	struct dentry *parent;
+
+	err = 0;
+	parent = dget_parent(dentry);
+	if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) {
+		if (d_really_is_positive(dentry)) {
+			if (!d_is_dir(dentry))
+				err = au_do_refresh(dentry, /*dir_flags*/0,
+						 parent);
+			else {
+				err = au_do_refresh(dentry, dir_flags, parent);
+				if (unlikely(err))
+					au_fset_si(sbinfo, FAILED_REFRESH_DIR);
+			}
+		} else
+			err = au_do_refresh(dentry, /*dir_flags*/0, parent);
+		AuDbgDentry(dentry);
+	}
+	dput(parent);
+
+	if (!err) {
+		if (do_idop)
+			au_refresh_dop(dentry, /*force_reval*/0);
+	} else
+		au_refresh_dop(dentry, /*force_reval*/1);
+
+	AuTraceErr(err);
+	return err;
+}
+
+static int au_refresh_d(struct super_block *sb, unsigned int do_idop)
+{
+	int err, i, j, ndentry, e;
+	unsigned int sigen;
+	struct au_dcsub_pages dpages;
+	struct au_dpage *dpage;
+	struct dentry **dentries, *d;
+	struct au_sbinfo *sbinfo;
+	struct dentry *root = sb->s_root;
+	const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1);
+
+	if (do_idop)
+		au_refresh_dop(root, /*force_reval*/0);
+
+	err = au_dpages_init(&dpages, GFP_NOFS);
+	if (unlikely(err))
+		goto out;
+	err = au_dcsub_pages(&dpages, root, NULL, NULL);
+	if (unlikely(err))
+		goto out_dpages;
+
+	sigen = au_sigen(sb);
+	sbinfo = au_sbi(sb);
+	for (i = 0; i < dpages.ndpage; i++) {
+		dpage = dpages.dpages + i;
+		dentries = dpage->dentries;
+		ndentry = dpage->ndentry;
+		for (j = 0; j < ndentry; j++) {
+			d = dentries[j];
+			e = au_do_refresh_d(d, sigen, sbinfo, dir_flags,
+					    do_idop);
+			if (unlikely(e && !err))
+				err = e;
+			/* go on even err */
+		}
+	}
+
+out_dpages:
+	au_dpages_free(&dpages);
+out:
+	return err;
+}
+
+static int au_refresh_i(struct super_block *sb, unsigned int do_idop)
+{
+	int err, e;
+	unsigned int sigen;
+	unsigned long long max, ull;
+	struct inode *inode, **array;
+
+	array = au_iarray_alloc(sb, &max);
+	err = PTR_ERR(array);
+	if (IS_ERR(array))
+		goto out;
+
+	err = 0;
+	sigen = au_sigen(sb);
+	for (ull = 0; ull < max; ull++) {
+		inode = array[ull];
+		if (unlikely(!inode))
+			break;
+
+		e = 0;
+		ii_write_lock_child(inode);
+		if (au_iigen(inode, NULL) != sigen) {
+			e = au_refresh_hinode_self(inode);
+			if (unlikely(e)) {
+				au_refresh_iop(inode, /*force_getattr*/1);
+				pr_err("error %d, i%lu\n", e, inode->i_ino);
+				if (!err)
+					err = e;
+				/* go on even if err */
+			}
+		}
+		if (!e && do_idop)
+			au_refresh_iop(inode, /*force_getattr*/0);
+		ii_write_unlock(inode);
+	}
+
+	au_iarray_free(array, max);
+
+out:
+	return err;
+}
+
+static void au_remount_refresh(struct super_block *sb, unsigned int do_idop)
+{
+	int err, e;
+	unsigned int udba;
+	aufs_bindex_t bindex, bend;
+	struct dentry *root;
+	struct inode *inode;
+	struct au_branch *br;
+	struct au_sbinfo *sbi;
+
+	au_sigen_inc(sb);
+	sbi = au_sbi(sb);
+	au_fclr_si(sbi, FAILED_REFRESH_DIR);
+
+	root = sb->s_root;
+	DiMustNoWaiters(root);
+	inode = d_inode(root);
+	IiMustNoWaiters(inode);
+
+	udba = au_opt_udba(sb);
+	bend = au_sbend(sb);
+	for (bindex = 0; bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		err = au_hnotify_reset_br(udba, br, br->br_perm);
+		if (unlikely(err))
+			AuIOErr("hnotify failed on br %d, %d, ignored\n",
+				bindex, err);
+		/* go on even if err */
+	}
+	au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1));
+
+	if (do_idop) {
+		if (au_ftest_si(sbi, NO_DREVAL)) {
+			AuDebugOn(sb->s_d_op == &aufs_dop_noreval);
+			sb->s_d_op = &aufs_dop_noreval;
+			AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr);
+			sbi->si_iop_array = aufs_iop_nogetattr;
+		} else {
+			AuDebugOn(sb->s_d_op == &aufs_dop);
+			sb->s_d_op = &aufs_dop;
+			AuDebugOn(sbi->si_iop_array == aufs_iop);
+			sbi->si_iop_array = aufs_iop;
+		}
+		pr_info("reset to %pf and %pf\n",
+			sb->s_d_op, sbi->si_iop_array);
+	}
+
+	di_write_unlock(root);
+	err = au_refresh_d(sb, do_idop);
+	e = au_refresh_i(sb, do_idop);
+	if (unlikely(e && !err))
+		err = e;
+	/* aufs_write_lock() calls ..._child() */
+	di_write_lock_child(root);
+
+	au_cpup_attr_all(inode, /*force*/1);
+
+	if (unlikely(err))
+		AuIOErr("refresh failed, ignored, %d\n", err);
+}
+
+/* stop extra interpretation of errno in mount(8), and strange error messages */
+static int cvt_err(int err)
+{
+	AuTraceErr(err);
+
+	switch (err) {
+	case -ENOENT:
+	case -ENOTDIR:
+	case -EEXIST:
+	case -EIO:
+		err = -EINVAL;
+	}
+	return err;
+}
+
+static int aufs_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+	int err, do_dx;
+	unsigned int mntflags;
+	struct au_opts opts = {
+		.opt = NULL
+	};
+	struct dentry *root;
+	struct inode *inode;
+	struct au_sbinfo *sbinfo;
+
+	err = 0;
+	root = sb->s_root;
+	if (!data || !*data) {
+		err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+		if (!err) {
+			di_write_lock_child(root);
+			err = au_opts_verify(sb, *flags, /*pending*/0);
+			aufs_write_unlock(root);
+		}
+		goto out;
+	}
+
+	err = -ENOMEM;
+	opts.opt = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!opts.opt))
+		goto out;
+	opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
+	opts.flags = AuOpts_REMOUNT;
+	opts.sb_flags = *flags;
+
+	/* parse it before aufs lock */
+	err = au_opts_parse(sb, data, &opts);
+	if (unlikely(err))
+		goto out_opts;
+
+	sbinfo = au_sbi(sb);
+	inode = d_inode(root);
+	mutex_lock(&inode->i_mutex);
+	err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+	if (unlikely(err))
+		goto out_mtx;
+	di_write_lock_child(root);
+
+	/* au_opts_remount() may return an error */
+	err = au_opts_remount(sb, &opts);
+	au_opts_free(&opts);
+
+	if (au_ftest_opts(opts.flags, REFRESH))
+		au_remount_refresh(sb, au_ftest_opts(opts.flags, REFRESH_IDOP));
+
+	if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) {
+		mntflags = au_mntflags(sb);
+		do_dx = !!au_opt_test(mntflags, DIO);
+		au_dy_arefresh(do_dx);
+	}
+
+	au_fhsm_wrote_all(sb, /*force*/1); /* ?? */
+	aufs_write_unlock(root);
+
+out_mtx:
+	mutex_unlock(&inode->i_mutex);
+out_opts:
+	free_page((unsigned long)opts.opt);
+out:
+	err = cvt_err(err);
+	AuTraceErr(err);
+	return err;
+}
+
+static const struct super_operations aufs_sop = {
+	.alloc_inode	= aufs_alloc_inode,
+	.destroy_inode	= aufs_destroy_inode,
+	/* always deleting, no clearing */
+	.drop_inode	= generic_delete_inode,
+	.show_options	= aufs_show_options,
+	.statfs		= aufs_statfs,
+	.put_super	= aufs_put_super,
+	.sync_fs	= aufs_sync_fs,
+	.remount_fs	= aufs_remount_fs,
+#ifdef CONFIG_AUFS_BDEV_LOOP
+	.real_loop	= aufs_real_loop
+#endif
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int alloc_root(struct super_block *sb)
+{
+	int err;
+	struct inode *inode;
+	struct dentry *root;
+
+	err = -ENOMEM;
+	inode = au_iget_locked(sb, AUFS_ROOT_INO);
+	err = PTR_ERR(inode);
+	if (IS_ERR(inode))
+		goto out;
+
+	inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */
+	inode->i_fop = &aufs_dir_fop;
+	inode->i_mode = S_IFDIR;
+	set_nlink(inode, 2);
+	unlock_new_inode(inode);
+
+	root = d_make_root(inode);
+	if (unlikely(!root))
+		goto out;
+	err = PTR_ERR(root);
+	if (IS_ERR(root))
+		goto out;
+
+	err = au_di_init(root);
+	if (!err) {
+		sb->s_root = root;
+		return 0; /* success */
+	}
+	dput(root);
+
+out:
+	return err;
+}
+
+static int aufs_fill_super(struct super_block *sb, void *raw_data,
+			   int silent __maybe_unused)
+{
+	int err;
+	struct au_opts opts = {
+		.opt = NULL
+	};
+	struct au_sbinfo *sbinfo;
+	struct dentry *root;
+	struct inode *inode;
+	char *arg = raw_data;
+
+	if (unlikely(!arg || !*arg)) {
+		err = -EINVAL;
+		pr_err("no arg\n");
+		goto out;
+	}
+
+	err = -ENOMEM;
+	opts.opt = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!opts.opt))
+		goto out;
+	opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
+	opts.sb_flags = sb->s_flags;
+
+	err = au_si_alloc(sb);
+	if (unlikely(err))
+		goto out_opts;
+	sbinfo = au_sbi(sb);
+
+	/* all timestamps always follow the ones on the branch */
+	sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
+	sb->s_op = &aufs_sop;
+	sb->s_d_op = &aufs_dop;
+	sb->s_magic = AUFS_SUPER_MAGIC;
+	sb->s_maxbytes = 0;
+	sb->s_stack_depth = 1;
+	au_export_init(sb);
+	/* au_xattr_init(sb); */
+
+	err = alloc_root(sb);
+	if (unlikely(err)) {
+		si_write_unlock(sb);
+		goto out_info;
+	}
+	root = sb->s_root;
+	inode = d_inode(root);
+
+	/*
+	 * actually we can parse options regardless aufs lock here.
+	 * but at remount time, parsing must be done before aufs lock.
+	 * so we follow the same rule.
+	 */
+	ii_write_lock_parent(inode);
+	aufs_write_unlock(root);
+	err = au_opts_parse(sb, arg, &opts);
+	if (unlikely(err))
+		goto out_root;
+
+	/* lock vfs_inode first, then aufs. */
+	mutex_lock(&inode->i_mutex);
+	aufs_write_lock(root);
+	err = au_opts_mount(sb, &opts);
+	au_opts_free(&opts);
+	if (!err && au_ftest_si(sbinfo, NO_DREVAL)) {
+		sb->s_d_op = &aufs_dop_noreval;
+		pr_info("%pf\n", sb->s_d_op);
+		au_refresh_dop(root, /*force_reval*/0);
+		sbinfo->si_iop_array = aufs_iop_nogetattr;
+		au_refresh_iop(inode, /*force_getattr*/0);
+	}
+	aufs_write_unlock(root);
+	mutex_unlock(&inode->i_mutex);
+	if (!err)
+		goto out_opts; /* success */
+
+out_root:
+	dput(root);
+	sb->s_root = NULL;
+out_info:
+	dbgaufs_si_fin(sbinfo);
+	kobject_put(&sbinfo->si_kobj);
+	sb->s_fs_info = NULL;
+out_opts:
+	free_page((unsigned long)opts.opt);
+out:
+	AuTraceErr(err);
+	err = cvt_err(err);
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags,
+				 const char *dev_name __maybe_unused,
+				 void *raw_data)
+{
+	struct dentry *root;
+	struct super_block *sb;
+
+	/* all timestamps always follow the ones on the branch */
+	/* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */
+	root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super);
+	if (IS_ERR(root))
+		goto out;
+
+	sb = root->d_sb;
+	si_write_lock(sb, !AuLock_FLUSH);
+	sysaufs_brs_add(sb, 0);
+	si_write_unlock(sb);
+	au_sbilist_add(sb);
+
+out:
+	return root;
+}
+
+static void aufs_kill_sb(struct super_block *sb)
+{
+	struct au_sbinfo *sbinfo;
+
+	sbinfo = au_sbi(sb);
+	if (sbinfo) {
+		au_sbilist_del(sb);
+		aufs_write_lock(sb->s_root);
+		au_fhsm_fin(sb);
+		if (sbinfo->si_wbr_create_ops->fin)
+			sbinfo->si_wbr_create_ops->fin(sb);
+		if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) {
+			au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE);
+			au_remount_refresh(sb, /*do_idop*/0);
+		}
+		if (au_opt_test(sbinfo->si_mntflags, PLINK))
+			au_plink_put(sb, /*verbose*/1);
+		au_xino_clr(sb);
+		sbinfo->si_sb = NULL;
+		aufs_write_unlock(sb->s_root);
+		au_nwt_flush(&sbinfo->si_nowait);
+	}
+	kill_anon_super(sb);
+}
+
+struct file_system_type aufs_fs_type = {
+	.name		= AUFS_FSTYPE,
+	/* a race between rename and others */
+	.fs_flags	= FS_RENAME_DOES_D_MOVE,
+	.mount		= aufs_mount,
+	.kill_sb	= aufs_kill_sb,
+	/* no need to __module_get() and module_put(). */
+	.owner		= THIS_MODULE,
+};
--- linux-4.4.0.orig/fs/aufs/super.h
+++ linux-4.4.0/fs/aufs/super.h
@@ -0,0 +1,641 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * super_block operations
+ */
+
+#ifndef __AUFS_SUPER_H__
+#define __AUFS_SUPER_H__
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+#include <linux/kobject.h>
+#include "rwsem.h"
+#include "spl.h"
+#include "wkq.h"
+
+/* policies to select one among multiple writable branches */
+struct au_wbr_copyup_operations {
+	int (*copyup)(struct dentry *dentry);
+};
+
+#define AuWbr_DIR	1		/* target is a dir */
+#define AuWbr_PARENT	(1 << 1)	/* always require a parent */
+
+#define au_ftest_wbr(flags, name)	((flags) & AuWbr_##name)
+#define au_fset_wbr(flags, name)	{ (flags) |= AuWbr_##name; }
+#define au_fclr_wbr(flags, name)	{ (flags) &= ~AuWbr_##name; }
+
+struct au_wbr_create_operations {
+	int (*create)(struct dentry *dentry, unsigned int flags);
+	int (*init)(struct super_block *sb);
+	int (*fin)(struct super_block *sb);
+};
+
+struct au_wbr_mfs {
+	struct mutex	mfs_lock; /* protect this structure */
+	unsigned long	mfs_jiffy;
+	unsigned long	mfs_expire;
+	aufs_bindex_t	mfs_bindex;
+
+	unsigned long long	mfsrr_bytes;
+	unsigned long long	mfsrr_watermark;
+};
+
+struct pseudo_link {
+	union {
+		struct hlist_node hlist;
+		struct rcu_head rcu;
+	};
+	struct inode *inode;
+};
+
+#define AuPlink_NHASH 100
+static inline int au_plink_hash(ino_t ino)
+{
+	return ino % AuPlink_NHASH;
+}
+
+/* File-based Hierarchical Storage Management */
+struct au_fhsm {
+#ifdef CONFIG_AUFS_FHSM
+	/* allow only one process who can receive the notification */
+	spinlock_t		fhsm_spin;
+	pid_t			fhsm_pid;
+	wait_queue_head_t	fhsm_wqh;
+	atomic_t		fhsm_readable;
+
+	/* these are protected by si_rwsem */
+	unsigned long		fhsm_expire;
+	aufs_bindex_t		fhsm_bottom;
+#endif
+};
+
+struct au_branch;
+struct au_sbinfo {
+	/* nowait tasks in the system-wide workqueue */
+	struct au_nowait_tasks	si_nowait;
+
+	/*
+	 * tried sb->s_umount, but failed due to the dependecy between i_mutex.
+	 * rwsem for au_sbinfo is necessary.
+	 */
+	struct au_rwsem		si_rwsem;
+
+	/* prevent recursive locking in deleting inode */
+	struct {
+		unsigned long		*bitmap;
+		spinlock_t		tree_lock;
+		struct radix_tree_root	tree;
+	} au_si_pid;
+
+	/*
+	 * dirty approach to protect sb->sb_inodes and ->s_files (gone) from
+	 * remount.
+	 */
+	atomic_long_t		si_ninodes, si_nfiles;
+
+	/* branch management */
+	unsigned int		si_generation;
+
+	/* see AuSi_ flags */
+	unsigned char		au_si_status;
+
+	aufs_bindex_t		si_bend;
+
+	/* dirty trick to keep br_id plus */
+	unsigned int		si_last_br_id :
+				sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1;
+	struct au_branch	**si_branch;
+
+	/* policy to select a writable branch */
+	unsigned char		si_wbr_copyup;
+	unsigned char		si_wbr_create;
+	struct au_wbr_copyup_operations *si_wbr_copyup_ops;
+	struct au_wbr_create_operations *si_wbr_create_ops;
+
+	/* round robin */
+	atomic_t		si_wbr_rr_next;
+
+	/* most free space */
+	struct au_wbr_mfs	si_wbr_mfs;
+
+	/* File-based Hierarchical Storage Management */
+	struct au_fhsm		si_fhsm;
+
+	/* mount flags */
+	/* include/asm-ia64/siginfo.h defines a macro named si_flags */
+	unsigned int		si_mntflags;
+
+	/* symlink to follow_link() and put_link() */
+	struct au_sphlhead	si_symlink;
+
+	/* external inode number (bitmap and translation table) */
+	vfs_readf_t		si_xread;
+	vfs_writef_t		si_xwrite;
+	struct file		*si_xib;
+	struct mutex		si_xib_mtx; /* protect xib members */
+	unsigned long		*si_xib_buf;
+	unsigned long		si_xib_last_pindex;
+	int			si_xib_next_bit;
+	aufs_bindex_t		si_xino_brid;
+	unsigned long		si_xino_jiffy;
+	unsigned long		si_xino_expire;
+	/* reserved for future use */
+	/* unsigned long long	si_xib_limit; */	/* Max xib file size */
+
+#ifdef CONFIG_AUFS_EXPORT
+	/* i_generation */
+	struct file		*si_xigen;
+	atomic_t		si_xigen_next;
+#endif
+
+	/* dirty trick to suppoer atomic_open */
+	struct au_sphlhead	si_aopen;
+
+	/* vdir parameters */
+	unsigned long		si_rdcache;	/* max cache time in jiffies */
+	unsigned int		si_rdblk;	/* deblk size */
+	unsigned int		si_rdhash;	/* hash size */
+
+	/*
+	 * If the number of whiteouts are larger than si_dirwh, leave all of
+	 * them after au_whtmp_ren to reduce the cost of rmdir(2).
+	 * future fsck.aufs or kernel thread will remove them later.
+	 * Otherwise, remove all whiteouts and the dir in rmdir(2).
+	 */
+	unsigned int		si_dirwh;
+
+	/* pseudo_link list */
+	struct au_sphlhead	si_plink[AuPlink_NHASH];
+	wait_queue_head_t	si_plink_wq;
+	spinlock_t		si_plink_maint_lock;
+	pid_t			si_plink_maint_pid;
+
+	/* file list */
+	struct au_sphlhead	si_files;
+
+	/* with/without getattr, brother of sb->s_d_op */
+	struct inode_operations *si_iop_array;
+
+	/*
+	 * sysfs and lifetime management.
+	 * this is not a small structure and it may be a waste of memory in case
+	 * of sysfs is disabled, particulary when many aufs-es are mounted.
+	 * but using sysfs is majority.
+	 */
+	struct kobject		si_kobj;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry		 *si_dbgaufs;
+	struct dentry		 *si_dbgaufs_plink;
+	struct dentry		 *si_dbgaufs_xib;
+#ifdef CONFIG_AUFS_EXPORT
+	struct dentry		 *si_dbgaufs_xigen;
+#endif
+#endif
+
+#ifdef CONFIG_AUFS_SBILIST
+	struct list_head	si_list;
+#endif
+
+	/* dirty, necessary for unmounting, sysfs and sysrq */
+	struct super_block	*si_sb;
+};
+
+/* sbinfo status flags */
+/*
+ * set true when refresh_dirs() failed at remount time.
+ * then try refreshing dirs at access time again.
+ * if it is false, refreshing dirs at access time is unnecesary
+ */
+#define AuSi_FAILED_REFRESH_DIR	1
+#define AuSi_FHSM		(1 << 1)	/* fhsm is active now */
+#define AuSi_NO_DREVAL		(1 << 2)	/* disable all d_revalidate */
+
+#ifndef CONFIG_AUFS_FHSM
+#undef AuSi_FHSM
+#define AuSi_FHSM		0
+#endif
+
+static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
+					   unsigned int flag)
+{
+	AuRwMustAnyLock(&sbi->si_rwsem);
+	return sbi->au_si_status & flag;
+}
+#define au_ftest_si(sbinfo, name)	au_do_ftest_si(sbinfo, AuSi_##name)
+#define au_fset_si(sbinfo, name) do { \
+	AuRwMustWriteLock(&(sbinfo)->si_rwsem); \
+	(sbinfo)->au_si_status |= AuSi_##name; \
+} while (0)
+#define au_fclr_si(sbinfo, name) do { \
+	AuRwMustWriteLock(&(sbinfo)->si_rwsem); \
+	(sbinfo)->au_si_status &= ~AuSi_##name; \
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+
+/* policy to select one among writable branches */
+#define AuWbrCopyup(sbinfo, ...) \
+	((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__))
+#define AuWbrCreate(sbinfo, ...) \
+	((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__))
+
+/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */
+#define AuLock_DW		1		/* write-lock dentry */
+#define AuLock_IR		(1 << 1)	/* read-lock inode */
+#define AuLock_IW		(1 << 2)	/* write-lock inode */
+#define AuLock_FLUSH		(1 << 3)	/* wait for 'nowait' tasks */
+#define AuLock_DIRS		(1 << 4)	/* target is a pair of dirs */
+#define AuLock_NOPLM		(1 << 5)	/* return err in plm mode */
+#define AuLock_NOPLMW		(1 << 6)	/* wait for plm mode ends */
+#define AuLock_GEN		(1 << 7)	/* test digen/iigen */
+#define au_ftest_lock(flags, name)	((flags) & AuLock_##name)
+#define au_fset_lock(flags, name) \
+	do { (flags) |= AuLock_##name; } while (0)
+#define au_fclr_lock(flags, name) \
+	do { (flags) &= ~AuLock_##name; } while (0)
+
+/* ---------------------------------------------------------------------- */
+
+/* super.c */
+extern struct file_system_type aufs_fs_type;
+struct inode *au_iget_locked(struct super_block *sb, ino_t ino);
+typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array,
+					   unsigned long long max, void *arg);
+void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb,
+		     struct super_block *sb, void *arg);
+struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max);
+void au_iarray_free(struct inode **a, unsigned long long max);
+
+/* sbinfo.c */
+void au_si_free(struct kobject *kobj);
+int au_si_alloc(struct super_block *sb);
+int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr);
+
+unsigned int au_sigen_inc(struct super_block *sb);
+aufs_bindex_t au_new_br_id(struct super_block *sb);
+
+int si_read_lock(struct super_block *sb, int flags);
+int si_write_lock(struct super_block *sb, int flags);
+int aufs_read_lock(struct dentry *dentry, int flags);
+void aufs_read_unlock(struct dentry *dentry, int flags);
+void aufs_write_lock(struct dentry *dentry);
+void aufs_write_unlock(struct dentry *dentry);
+int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags);
+void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2);
+
+int si_pid_test_slow(struct super_block *sb);
+void si_pid_set_slow(struct super_block *sb);
+void si_pid_clr_slow(struct super_block *sb);
+
+/* wbr_policy.c */
+extern struct au_wbr_copyup_operations au_wbr_copyup_ops[];
+extern struct au_wbr_create_operations au_wbr_create_ops[];
+int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst);
+int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex);
+int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t bstart);
+
+/* mvdown.c */
+int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg);
+
+#ifdef CONFIG_AUFS_FHSM
+/* fhsm.c */
+
+static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm)
+{
+	pid_t pid;
+
+	spin_lock(&fhsm->fhsm_spin);
+	pid = fhsm->fhsm_pid;
+	spin_unlock(&fhsm->fhsm_spin);
+
+	return pid;
+}
+
+void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force);
+void au_fhsm_wrote_all(struct super_block *sb, int force);
+int au_fhsm_fd(struct super_block *sb, int oflags);
+int au_fhsm_br_alloc(struct au_branch *br);
+void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex);
+void au_fhsm_fin(struct super_block *sb);
+void au_fhsm_init(struct au_sbinfo *sbinfo);
+void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec);
+void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo);
+#else
+AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex,
+	   int force)
+AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force)
+AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags)
+AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm)
+AuStubInt0(au_fhsm_br_alloc, struct au_branch *br)
+AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex)
+AuStubVoid(au_fhsm_fin, struct super_block *sb)
+AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo)
+AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec)
+AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo)
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct au_sbinfo *au_sbi(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef CONFIG_AUFS_EXPORT
+int au_test_nfsd(void);
+void au_export_init(struct super_block *sb);
+void au_xigen_inc(struct inode *inode);
+int au_xigen_new(struct inode *inode);
+int au_xigen_set(struct super_block *sb, struct file *base);
+void au_xigen_clr(struct super_block *sb);
+
+static inline int au_busy_or_stale(void)
+{
+	if (!au_test_nfsd())
+		return -EBUSY;
+	return -ESTALE;
+}
+#else
+AuStubInt0(au_test_nfsd, void)
+AuStubVoid(au_export_init, struct super_block *sb)
+AuStubVoid(au_xigen_inc, struct inode *inode)
+AuStubInt0(au_xigen_new, struct inode *inode)
+AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base)
+AuStubVoid(au_xigen_clr, struct super_block *sb)
+AuStub(int, au_busy_or_stale, return -EBUSY, void)
+#endif /* CONFIG_AUFS_EXPORT */
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef CONFIG_AUFS_SBILIST
+/* module.c */
+extern struct au_splhead au_sbilist;
+
+static inline void au_sbilist_init(void)
+{
+	au_spl_init(&au_sbilist);
+}
+
+static inline void au_sbilist_add(struct super_block *sb)
+{
+	au_spl_add(&au_sbi(sb)->si_list, &au_sbilist);
+}
+
+static inline void au_sbilist_del(struct super_block *sb)
+{
+	au_spl_del(&au_sbi(sb)->si_list, &au_sbilist);
+}
+
+#ifdef CONFIG_AUFS_MAGIC_SYSRQ
+static inline void au_sbilist_lock(void)
+{
+	spin_lock(&au_sbilist.spin);
+}
+
+static inline void au_sbilist_unlock(void)
+{
+	spin_unlock(&au_sbilist.spin);
+}
+#define AuGFP_SBILIST	GFP_ATOMIC
+#else
+AuStubVoid(au_sbilist_lock, void)
+AuStubVoid(au_sbilist_unlock, void)
+#define AuGFP_SBILIST	GFP_NOFS
+#endif /* CONFIG_AUFS_MAGIC_SYSRQ */
+#else
+AuStubVoid(au_sbilist_init, void)
+AuStubVoid(au_sbilist_add, struct super_block *sb)
+AuStubVoid(au_sbilist_del, struct super_block *sb)
+AuStubVoid(au_sbilist_lock, void)
+AuStubVoid(au_sbilist_unlock, void)
+#define AuGFP_SBILIST	GFP_NOFS
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo)
+{
+	/*
+	 * This function is a dynamic '__init' function actually,
+	 * so the tiny check for si_rwsem is unnecessary.
+	 */
+	/* AuRwMustWriteLock(&sbinfo->si_rwsem); */
+#ifdef CONFIG_DEBUG_FS
+	sbinfo->si_dbgaufs = NULL;
+	sbinfo->si_dbgaufs_plink = NULL;
+	sbinfo->si_dbgaufs_xib = NULL;
+#ifdef CONFIG_AUFS_EXPORT
+	sbinfo->si_dbgaufs_xigen = NULL;
+#endif
+#endif
+}
+
+/* ---------------------------------------------------------------------- */
+
+static inline pid_t si_pid_bit(void)
+{
+	/* the origin of pid is 1, but the bitmap's is 0 */
+	return current->pid - 1;
+}
+
+static inline int si_pid_test(struct super_block *sb)
+{
+	pid_t bit;
+
+	bit = si_pid_bit();
+	if (bit < PID_MAX_DEFAULT)
+		return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
+	return si_pid_test_slow(sb);
+}
+
+static inline void si_pid_set(struct super_block *sb)
+{
+	pid_t bit;
+
+	bit = si_pid_bit();
+	if (bit < PID_MAX_DEFAULT) {
+		AuDebugOn(test_bit(bit, au_sbi(sb)->au_si_pid.bitmap));
+		set_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
+		/* smp_mb(); */
+	} else
+		si_pid_set_slow(sb);
+}
+
+static inline void si_pid_clr(struct super_block *sb)
+{
+	pid_t bit;
+
+	bit = si_pid_bit();
+	if (bit < PID_MAX_DEFAULT) {
+		AuDebugOn(!test_bit(bit, au_sbi(sb)->au_si_pid.bitmap));
+		clear_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
+		/* smp_mb(); */
+	} else
+		si_pid_clr_slow(sb);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* lock superblock. mainly for entry point functions */
+/*
+ * __si_read_lock, __si_write_lock,
+ * __si_read_unlock, __si_write_unlock, __si_downgrade_lock
+ */
+AuSimpleRwsemFuncs(__si, struct super_block *sb, &au_sbi(sb)->si_rwsem);
+
+#define SiMustNoWaiters(sb)	AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem)
+#define SiMustAnyLock(sb)	AuRwMustAnyLock(&au_sbi(sb)->si_rwsem)
+#define SiMustWriteLock(sb)	AuRwMustWriteLock(&au_sbi(sb)->si_rwsem)
+
+static inline void si_noflush_read_lock(struct super_block *sb)
+{
+	__si_read_lock(sb);
+	si_pid_set(sb);
+}
+
+static inline int si_noflush_read_trylock(struct super_block *sb)
+{
+	int locked;
+
+	locked = __si_read_trylock(sb);
+	if (locked)
+		si_pid_set(sb);
+	return locked;
+}
+
+static inline void si_noflush_write_lock(struct super_block *sb)
+{
+	__si_write_lock(sb);
+	si_pid_set(sb);
+}
+
+static inline int si_noflush_write_trylock(struct super_block *sb)
+{
+	int locked;
+
+	locked = __si_write_trylock(sb);
+	if (locked)
+		si_pid_set(sb);
+	return locked;
+}
+
+#if 0 /* reserved */
+static inline int si_read_trylock(struct super_block *sb, int flags)
+{
+	if (au_ftest_lock(flags, FLUSH))
+		au_nwt_flush(&au_sbi(sb)->si_nowait);
+	return si_noflush_read_trylock(sb);
+}
+#endif
+
+static inline void si_read_unlock(struct super_block *sb)
+{
+	si_pid_clr(sb);
+	__si_read_unlock(sb);
+}
+
+#if 0 /* reserved */
+static inline int si_write_trylock(struct super_block *sb, int flags)
+{
+	if (au_ftest_lock(flags, FLUSH))
+		au_nwt_flush(&au_sbi(sb)->si_nowait);
+	return si_noflush_write_trylock(sb);
+}
+#endif
+
+static inline void si_write_unlock(struct super_block *sb)
+{
+	si_pid_clr(sb);
+	__si_write_unlock(sb);
+}
+
+#if 0 /* reserved */
+static inline void si_downgrade_lock(struct super_block *sb)
+{
+	__si_downgrade_lock(sb);
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static inline aufs_bindex_t au_sbend(struct super_block *sb)
+{
+	SiMustAnyLock(sb);
+	return au_sbi(sb)->si_bend;
+}
+
+static inline unsigned int au_mntflags(struct super_block *sb)
+{
+	SiMustAnyLock(sb);
+	return au_sbi(sb)->si_mntflags;
+}
+
+static inline unsigned int au_sigen(struct super_block *sb)
+{
+	SiMustAnyLock(sb);
+	return au_sbi(sb)->si_generation;
+}
+
+static inline void au_ninodes_inc(struct super_block *sb)
+{
+	atomic_long_inc(&au_sbi(sb)->si_ninodes);
+}
+
+static inline void au_ninodes_dec(struct super_block *sb)
+{
+	AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_ninodes));
+	atomic_long_dec(&au_sbi(sb)->si_ninodes);
+}
+
+static inline void au_nfiles_inc(struct super_block *sb)
+{
+	atomic_long_inc(&au_sbi(sb)->si_nfiles);
+}
+
+static inline void au_nfiles_dec(struct super_block *sb)
+{
+	AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_nfiles));
+	atomic_long_dec(&au_sbi(sb)->si_nfiles);
+}
+
+static inline struct au_branch *au_sbr(struct super_block *sb,
+				       aufs_bindex_t bindex)
+{
+	SiMustAnyLock(sb);
+	return au_sbi(sb)->si_branch[0 + bindex];
+}
+
+static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid)
+{
+	SiMustWriteLock(sb);
+	au_sbi(sb)->si_xino_brid = brid;
+}
+
+static inline aufs_bindex_t au_xino_brid(struct super_block *sb)
+{
+	SiMustAnyLock(sb);
+	return au_sbi(sb)->si_xino_brid;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_SUPER_H__ */
--- linux-4.4.0.orig/fs/aufs/sysaufs.c
+++ linux-4.4.0/fs/aufs/sysaufs.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * sysfs interface and lifetime management
+ * they are necessary regardless sysfs is disabled.
+ */
+
+#include <linux/random.h>
+#include "aufs.h"
+
+unsigned long sysaufs_si_mask;
+struct kset *sysaufs_kset;
+
+#define AuSiAttr(_name) { \
+	.attr   = { .name = __stringify(_name), .mode = 0444 },	\
+	.show   = sysaufs_si_##_name,				\
+}
+
+static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path);
+struct attribute *sysaufs_si_attrs[] = {
+	&sysaufs_si_attr_xi_path.attr,
+	NULL,
+};
+
+static const struct sysfs_ops au_sbi_ops = {
+	.show   = sysaufs_si_show
+};
+
+static struct kobj_type au_sbi_ktype = {
+	.release	= au_si_free,
+	.sysfs_ops	= &au_sbi_ops,
+	.default_attrs	= sysaufs_si_attrs
+};
+
+/* ---------------------------------------------------------------------- */
+
+int sysaufs_si_init(struct au_sbinfo *sbinfo)
+{
+	int err;
+
+	sbinfo->si_kobj.kset = sysaufs_kset;
+	/* cf. sysaufs_name() */
+	err = kobject_init_and_add
+		(&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL,
+		 SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo));
+
+	dbgaufs_si_null(sbinfo);
+	if (!err) {
+		err = dbgaufs_si_init(sbinfo);
+		if (unlikely(err))
+			kobject_put(&sbinfo->si_kobj);
+	}
+	return err;
+}
+
+void sysaufs_fin(void)
+{
+	dbgaufs_fin();
+	sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group);
+	kset_unregister(sysaufs_kset);
+}
+
+int __init sysaufs_init(void)
+{
+	int err;
+
+	do {
+		get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask));
+	} while (!sysaufs_si_mask);
+
+	err = -EINVAL;
+	sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj);
+	if (unlikely(!sysaufs_kset))
+		goto out;
+	err = PTR_ERR(sysaufs_kset);
+	if (IS_ERR(sysaufs_kset))
+		goto out;
+	err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group);
+	if (unlikely(err)) {
+		kset_unregister(sysaufs_kset);
+		goto out;
+	}
+
+	err = dbgaufs_init();
+	if (unlikely(err))
+		sysaufs_fin();
+out:
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/sysaufs.h
+++ linux-4.4.0/fs/aufs/sysaufs.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * sysfs interface and mount lifetime management
+ */
+
+#ifndef __SYSAUFS_H__
+#define __SYSAUFS_H__
+
+#ifdef __KERNEL__
+
+#include <linux/sysfs.h>
+#include "module.h"
+
+struct super_block;
+struct au_sbinfo;
+
+struct sysaufs_si_attr {
+	struct attribute attr;
+	int (*show)(struct seq_file *seq, struct super_block *sb);
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* sysaufs.c */
+extern unsigned long sysaufs_si_mask;
+extern struct kset *sysaufs_kset;
+extern struct attribute *sysaufs_si_attrs[];
+int sysaufs_si_init(struct au_sbinfo *sbinfo);
+int __init sysaufs_init(void);
+void sysaufs_fin(void);
+
+/* ---------------------------------------------------------------------- */
+
+/* some people doesn't like to show a pointer in kernel */
+static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo)
+{
+	return sysaufs_si_mask ^ (unsigned long)sbinfo;
+}
+
+#define SysaufsSiNamePrefix	"si_"
+#define SysaufsSiNameLen	(sizeof(SysaufsSiNamePrefix) + 16)
+static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name)
+{
+	snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx",
+		 sysaufs_si_id(sbinfo));
+}
+
+struct au_branch;
+#ifdef CONFIG_SYSFS
+/* sysfs.c */
+extern struct attribute_group *sysaufs_attr_group;
+
+int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb);
+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
+			 char *buf);
+long au_brinfo_ioctl(struct file *file, unsigned long arg);
+#ifdef CONFIG_COMPAT
+long au_brinfo_compat_ioctl(struct file *file, unsigned long arg);
+#endif
+
+void sysaufs_br_init(struct au_branch *br);
+void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
+void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex);
+
+#define sysaufs_brs_init()	do {} while (0)
+
+#else
+#define sysaufs_attr_group	NULL
+
+AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb)
+AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj,
+       struct attribute *attr, char *buf)
+AuStubVoid(sysaufs_br_init, struct au_branch *br)
+AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
+AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
+
+static inline void sysaufs_brs_init(void)
+{
+	sysaufs_brs = 0;
+}
+
+#endif /* CONFIG_SYSFS */
+
+#endif /* __KERNEL__ */
+#endif /* __SYSAUFS_H__ */
--- linux-4.4.0.orig/fs/aufs/sysfs.c
+++ linux-4.4.0/fs/aufs/sysfs.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * sysfs interface
+ */
+
+#include <linux/compat.h>
+#include <linux/seq_file.h>
+#include "aufs.h"
+
+#ifdef CONFIG_AUFS_FS_MODULE
+/* this entry violates the "one line per file" policy of sysfs */
+static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr,
+			   char *buf)
+{
+	ssize_t err;
+	static char *conf =
+/* this file is generated at compiling */
+#include "conf.str"
+		;
+
+	err = snprintf(buf, PAGE_SIZE, conf);
+	if (unlikely(err >= PAGE_SIZE))
+		err = -EFBIG;
+	return err;
+}
+
+static struct kobj_attribute au_config_attr = __ATTR_RO(config);
+#endif
+
+static struct attribute *au_attr[] = {
+#ifdef CONFIG_AUFS_FS_MODULE
+	&au_config_attr.attr,
+#endif
+	NULL,	/* need to NULL terminate the list of attributes */
+};
+
+static struct attribute_group sysaufs_attr_group_body = {
+	.attrs = au_attr
+};
+
+struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body;
+
+/* ---------------------------------------------------------------------- */
+
+int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
+{
+	int err;
+
+	SiMustAnyLock(sb);
+
+	err = 0;
+	if (au_opt_test(au_mntflags(sb), XINO)) {
+		err = au_xino_path(seq, au_sbi(sb)->si_xib);
+		seq_putc(seq, '\n');
+	}
+	return err;
+}
+
+/*
+ * the lifetime of branch is independent from the entry under sysfs.
+ * sysfs handles the lifetime of the entry, and never call ->show() after it is
+ * unlinked.
+ */
+static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
+			 aufs_bindex_t bindex, int idx)
+{
+	int err;
+	struct path path;
+	struct dentry *root;
+	struct au_branch *br;
+	au_br_perm_str_t perm;
+
+	AuDbg("b%d\n", bindex);
+
+	err = 0;
+	root = sb->s_root;
+	di_read_lock_parent(root, !AuLock_IR);
+	br = au_sbr(sb, bindex);
+
+	switch (idx) {
+	case AuBrSysfs_BR:
+		path.mnt = au_br_mnt(br);
+		path.dentry = au_h_dptr(root, bindex);
+		err = au_seq_path(seq, &path);
+		if (!err) {
+			au_optstr_br_perm(&perm, br->br_perm);
+			seq_printf(seq, "=%s\n", perm.a);
+		}
+		break;
+	case AuBrSysfs_BRID:
+		seq_printf(seq, "%d\n", br->br_id);
+		break;
+	}
+	di_read_unlock(root, !AuLock_IR);
+	if (unlikely(err || seq_has_overflowed(seq)))
+		err = -E2BIG;
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct seq_file *au_seq(char *p, ssize_t len)
+{
+	struct seq_file *seq;
+
+	seq = kzalloc(sizeof(*seq), GFP_NOFS);
+	if (seq) {
+		/* mutex_init(&seq.lock); */
+		seq->buf = p;
+		seq->size = len;
+		return seq; /* success */
+	}
+
+	seq = ERR_PTR(-ENOMEM);
+	return seq;
+}
+
+#define SysaufsBr_PREFIX	"br"
+#define SysaufsBrid_PREFIX	"brid"
+
+/* todo: file size may exceed PAGE_SIZE */
+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
+			char *buf)
+{
+	ssize_t err;
+	int idx;
+	long l;
+	aufs_bindex_t bend;
+	struct au_sbinfo *sbinfo;
+	struct super_block *sb;
+	struct seq_file *seq;
+	char *name;
+	struct attribute **cattr;
+
+	sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
+	sb = sbinfo->si_sb;
+
+	/*
+	 * prevent a race condition between sysfs and aufs.
+	 * for instance, sysfs_file_read() calls sysfs_get_active_two() which
+	 * prohibits maintaining the sysfs entries.
+	 * hew we acquire read lock after sysfs_get_active_two().
+	 * on the other hand, the remount process may maintain the sysfs/aufs
+	 * entries after acquiring write lock.
+	 * it can cause a deadlock.
+	 * simply we gave up processing read here.
+	 */
+	err = -EBUSY;
+	if (unlikely(!si_noflush_read_trylock(sb)))
+		goto out;
+
+	seq = au_seq(buf, PAGE_SIZE);
+	err = PTR_ERR(seq);
+	if (IS_ERR(seq))
+		goto out_unlock;
+
+	name = (void *)attr->name;
+	cattr = sysaufs_si_attrs;
+	while (*cattr) {
+		if (!strcmp(name, (*cattr)->name)) {
+			err = container_of(*cattr, struct sysaufs_si_attr, attr)
+				->show(seq, sb);
+			goto out_seq;
+		}
+		cattr++;
+	}
+
+	if (!strncmp(name, SysaufsBrid_PREFIX,
+		     sizeof(SysaufsBrid_PREFIX) - 1)) {
+		idx = AuBrSysfs_BRID;
+		name += sizeof(SysaufsBrid_PREFIX) - 1;
+	} else if (!strncmp(name, SysaufsBr_PREFIX,
+			    sizeof(SysaufsBr_PREFIX) - 1)) {
+		idx = AuBrSysfs_BR;
+		name += sizeof(SysaufsBr_PREFIX) - 1;
+	} else
+		  BUG();
+
+	err = kstrtol(name, 10, &l);
+	if (!err) {
+		bend = au_sbend(sb);
+		if (l <= bend)
+			err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx);
+		else
+			err = -ENOENT;
+	}
+
+out_seq:
+	if (!err) {
+		err = seq->count;
+		/* sysfs limit */
+		if (unlikely(err == PAGE_SIZE))
+			err = -EFBIG;
+	}
+	kfree(seq);
+out_unlock:
+	si_read_unlock(sb);
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg)
+{
+	int err;
+	int16_t brid;
+	aufs_bindex_t bindex, bend;
+	size_t sz;
+	char *buf;
+	struct seq_file *seq;
+	struct au_branch *br;
+
+	si_read_lock(sb, AuLock_FLUSH);
+	bend = au_sbend(sb);
+	err = bend + 1;
+	if (!arg)
+		goto out;
+
+	err = -ENOMEM;
+	buf = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!buf))
+		goto out;
+
+	seq = au_seq(buf, PAGE_SIZE);
+	err = PTR_ERR(seq);
+	if (IS_ERR(seq))
+		goto out_buf;
+
+	sz = sizeof(*arg) - offsetof(union aufs_brinfo, path);
+	for (bindex = 0; bindex <= bend; bindex++, arg++) {
+		err = !access_ok(VERIFY_WRITE, arg, sizeof(*arg));
+		if (unlikely(err))
+			break;
+
+		br = au_sbr(sb, bindex);
+		brid = br->br_id;
+		BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id));
+		err = __put_user(brid, &arg->id);
+		if (unlikely(err))
+			break;
+
+		BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm));
+		err = __put_user(br->br_perm, &arg->perm);
+		if (unlikely(err))
+			break;
+
+		err = au_seq_path(seq, &br->br_path);
+		if (unlikely(err))
+			break;
+		seq_putc(seq, '\0');
+		if (!seq_has_overflowed(seq)) {
+			err = copy_to_user(arg->path, seq->buf, seq->count);
+			seq->count = 0;
+			if (unlikely(err))
+				break;
+		} else {
+			err = -E2BIG;
+			goto out_seq;
+		}
+	}
+	if (unlikely(err))
+		err = -EFAULT;
+
+out_seq:
+	kfree(seq);
+out_buf:
+	free_page((unsigned long)buf);
+out:
+	si_read_unlock(sb);
+	return err;
+}
+
+long au_brinfo_ioctl(struct file *file, unsigned long arg)
+{
+	return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+long au_brinfo_compat_ioctl(struct file *file, unsigned long arg)
+{
+	return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg));
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+void sysaufs_br_init(struct au_branch *br)
+{
+	int i;
+	struct au_brsysfs *br_sysfs;
+	struct attribute *attr;
+
+	br_sysfs = br->br_sysfs;
+	for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
+		attr = &br_sysfs->attr;
+		sysfs_attr_init(attr);
+		attr->name = br_sysfs->name;
+		attr->mode = S_IRUGO;
+		br_sysfs++;
+	}
+}
+
+void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
+{
+	struct au_branch *br;
+	struct kobject *kobj;
+	struct au_brsysfs *br_sysfs;
+	int i;
+	aufs_bindex_t bend;
+
+	dbgaufs_brs_del(sb, bindex);
+
+	if (!sysaufs_brs)
+		return;
+
+	kobj = &au_sbi(sb)->si_kobj;
+	bend = au_sbend(sb);
+	for (; bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		br_sysfs = br->br_sysfs;
+		for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
+			sysfs_remove_file(kobj, &br_sysfs->attr);
+			br_sysfs++;
+		}
+	}
+}
+
+void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
+{
+	int err, i;
+	aufs_bindex_t bend;
+	struct kobject *kobj;
+	struct au_branch *br;
+	struct au_brsysfs *br_sysfs;
+
+	dbgaufs_brs_add(sb, bindex);
+
+	if (!sysaufs_brs)
+		return;
+
+	kobj = &au_sbi(sb)->si_kobj;
+	bend = au_sbend(sb);
+	for (; bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		br_sysfs = br->br_sysfs;
+		snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name),
+			 SysaufsBr_PREFIX "%d", bindex);
+		snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name),
+			 SysaufsBrid_PREFIX "%d", bindex);
+		for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
+			err = sysfs_create_file(kobj, &br_sysfs->attr);
+			if (unlikely(err))
+				pr_warn("failed %s under sysfs(%d)\n",
+					br_sysfs->name, err);
+			br_sysfs++;
+		}
+	}
+}
--- linux-4.4.0.orig/fs/aufs/sysrq.c
+++ linux-4.4.0/fs/aufs/sysrq.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * magic sysrq hanlder
+ */
+
+/* #include <linux/sysrq.h> */
+#include <linux/writeback.h>
+#include "aufs.h"
+
+/* ---------------------------------------------------------------------- */
+
+static void sysrq_sb(struct super_block *sb)
+{
+	char *plevel;
+	struct au_sbinfo *sbinfo;
+	struct file *file;
+	struct au_sphlhead *files;
+	struct au_finfo *finfo;
+
+	plevel = au_plevel;
+	au_plevel = KERN_WARNING;
+
+	/* since we define pr_fmt, call printk directly */
+#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str)
+
+	sbinfo = au_sbi(sb);
+	printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo));
+	pr("superblock\n");
+	au_dpri_sb(sb);
+
+#if 0
+	pr("root dentry\n");
+	au_dpri_dentry(sb->s_root);
+	pr("root inode\n");
+	au_dpri_inode(d_inode(sb->s_root));
+#endif
+
+#if 0
+	do {
+		int err, i, j, ndentry;
+		struct au_dcsub_pages dpages;
+		struct au_dpage *dpage;
+
+		err = au_dpages_init(&dpages, GFP_ATOMIC);
+		if (unlikely(err))
+			break;
+		err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL);
+		if (!err)
+			for (i = 0; i < dpages.ndpage; i++) {
+				dpage = dpages.dpages + i;
+				ndentry = dpage->ndentry;
+				for (j = 0; j < ndentry; j++)
+					au_dpri_dentry(dpage->dentries[j]);
+			}
+		au_dpages_free(&dpages);
+	} while (0);
+#endif
+
+#if 1
+	{
+		struct inode *i;
+
+		pr("isolated inode\n");
+		spin_lock(&sb->s_inode_list_lock);
+		list_for_each_entry(i, &sb->s_inodes, i_sb_list) {
+			spin_lock(&i->i_lock);
+			if (1 || hlist_empty(&i->i_dentry))
+				au_dpri_inode(i);
+			spin_unlock(&i->i_lock);
+		}
+		spin_unlock(&sb->s_inode_list_lock);
+	}
+#endif
+	pr("files\n");
+	files = &au_sbi(sb)->si_files;
+	spin_lock(&files->spin);
+	hlist_for_each_entry(finfo, &files->head, fi_hlist) {
+		umode_t mode;
+
+		file = finfo->fi_file;
+		mode = file_inode(file)->i_mode;
+		if (!special_file(mode))
+			au_dpri_file(file);
+	}
+	spin_unlock(&files->spin);
+	pr("done\n");
+
+#undef pr
+	au_plevel = plevel;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* module parameter */
+static char *aufs_sysrq_key = "a";
+module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO);
+MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME);
+
+static void au_sysrq(int key __maybe_unused)
+{
+	struct au_sbinfo *sbinfo;
+
+	lockdep_off();
+	au_sbilist_lock();
+	list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
+		sysrq_sb(sbinfo->si_sb);
+	au_sbilist_unlock();
+	lockdep_on();
+}
+
+static struct sysrq_key_op au_sysrq_op = {
+	.handler	= au_sysrq,
+	.help_msg	= "Aufs",
+	.action_msg	= "Aufs",
+	.enable_mask	= SYSRQ_ENABLE_DUMP
+};
+
+/* ---------------------------------------------------------------------- */
+
+int __init au_sysrq_init(void)
+{
+	int err;
+	char key;
+
+	err = -1;
+	key = *aufs_sysrq_key;
+	if ('a' <= key && key <= 'z')
+		err = register_sysrq_key(key, &au_sysrq_op);
+	if (unlikely(err))
+		pr_err("err %d, sysrq=%c\n", err, key);
+	return err;
+}
+
+void au_sysrq_fin(void)
+{
+	int err;
+
+	err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op);
+	if (unlikely(err))
+		pr_err("err %d (ignored)\n", err);
+}
--- linux-4.4.0.orig/fs/aufs/vdir.c
+++ linux-4.4.0/fs/aufs/vdir.c
@@ -0,0 +1,888 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * virtual or vertical directory
+ */
+
+#include "aufs.h"
+
+static unsigned int calc_size(int nlen)
+{
+	return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t));
+}
+
+static int set_deblk_end(union au_vdir_deblk_p *p,
+			 union au_vdir_deblk_p *deblk_end)
+{
+	if (calc_size(0) <= deblk_end->deblk - p->deblk) {
+		p->de->de_str.len = 0;
+		/* smp_mb(); */
+		return 0;
+	}
+	return -1; /* error */
+}
+
+/* returns true or false */
+static int is_deblk_end(union au_vdir_deblk_p *p,
+			union au_vdir_deblk_p *deblk_end)
+{
+	if (calc_size(0) <= deblk_end->deblk - p->deblk)
+		return !p->de->de_str.len;
+	return 1;
+}
+
+static unsigned char *last_deblk(struct au_vdir *vdir)
+{
+	return vdir->vd_deblk[vdir->vd_nblk - 1];
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* estimate the appropriate size for name hash table */
+unsigned int au_rdhash_est(loff_t sz)
+{
+	unsigned int n;
+
+	n = UINT_MAX;
+	sz >>= 10;
+	if (sz < n)
+		n = sz;
+	if (sz < AUFS_RDHASH_DEF)
+		n = AUFS_RDHASH_DEF;
+	/* pr_info("n %u\n", n); */
+	return n;
+}
+
+/*
+ * the allocated memory has to be freed by
+ * au_nhash_wh_free() or au_nhash_de_free().
+ */
+int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp)
+{
+	struct hlist_head *head;
+	unsigned int u;
+	size_t sz;
+
+	sz = sizeof(*nhash->nh_head) * num_hash;
+	head = kmalloc(sz, gfp);
+	if (head) {
+		nhash->nh_num = num_hash;
+		nhash->nh_head = head;
+		for (u = 0; u < num_hash; u++)
+			INIT_HLIST_HEAD(head++);
+		return 0; /* success */
+	}
+
+	return -ENOMEM;
+}
+
+static void nhash_count(struct hlist_head *head)
+{
+#if 0
+	unsigned long n;
+	struct hlist_node *pos;
+
+	n = 0;
+	hlist_for_each(pos, head)
+		n++;
+	pr_info("%lu\n", n);
+#endif
+}
+
+static void au_nhash_wh_do_free(struct hlist_head *head)
+{
+	struct au_vdir_wh *pos;
+	struct hlist_node *node;
+
+	hlist_for_each_entry_safe(pos, node, head, wh_hash)
+		kfree(pos);
+}
+
+static void au_nhash_de_do_free(struct hlist_head *head)
+{
+	struct au_vdir_dehstr *pos;
+	struct hlist_node *node;
+
+	hlist_for_each_entry_safe(pos, node, head, hash)
+		au_cache_free_vdir_dehstr(pos);
+}
+
+static void au_nhash_do_free(struct au_nhash *nhash,
+			     void (*free)(struct hlist_head *head))
+{
+	unsigned int n;
+	struct hlist_head *head;
+
+	n = nhash->nh_num;
+	if (!n)
+		return;
+
+	head = nhash->nh_head;
+	while (n-- > 0) {
+		nhash_count(head);
+		free(head++);
+	}
+	kfree(nhash->nh_head);
+}
+
+void au_nhash_wh_free(struct au_nhash *whlist)
+{
+	au_nhash_do_free(whlist, au_nhash_wh_do_free);
+}
+
+static void au_nhash_de_free(struct au_nhash *delist)
+{
+	au_nhash_do_free(delist, au_nhash_de_do_free);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
+			    int limit)
+{
+	int num;
+	unsigned int u, n;
+	struct hlist_head *head;
+	struct au_vdir_wh *pos;
+
+	num = 0;
+	n = whlist->nh_num;
+	head = whlist->nh_head;
+	for (u = 0; u < n; u++, head++)
+		hlist_for_each_entry(pos, head, wh_hash)
+			if (pos->wh_bindex == btgt && ++num > limit)
+				return 1;
+	return 0;
+}
+
+static struct hlist_head *au_name_hash(struct au_nhash *nhash,
+				       unsigned char *name,
+				       unsigned int len)
+{
+	unsigned int v;
+	/* const unsigned int magic_bit = 12; */
+
+	AuDebugOn(!nhash->nh_num || !nhash->nh_head);
+
+	v = 0;
+	while (len--)
+		v += *name++;
+	/* v = hash_long(v, magic_bit); */
+	v %= nhash->nh_num;
+	return nhash->nh_head + v;
+}
+
+static int au_nhash_test_name(struct au_vdir_destr *str, const char *name,
+			      int nlen)
+{
+	return str->len == nlen && !memcmp(str->name, name, nlen);
+}
+
+/* returns found or not */
+int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen)
+{
+	struct hlist_head *head;
+	struct au_vdir_wh *pos;
+	struct au_vdir_destr *str;
+
+	head = au_name_hash(whlist, name, nlen);
+	hlist_for_each_entry(pos, head, wh_hash) {
+		str = &pos->wh_str;
+		AuDbg("%.*s\n", str->len, str->name);
+		if (au_nhash_test_name(str, name, nlen))
+			return 1;
+	}
+	return 0;
+}
+
+/* returns found(true) or not */
+static int test_known(struct au_nhash *delist, char *name, int nlen)
+{
+	struct hlist_head *head;
+	struct au_vdir_dehstr *pos;
+	struct au_vdir_destr *str;
+
+	head = au_name_hash(delist, name, nlen);
+	hlist_for_each_entry(pos, head, hash) {
+		str = pos->str;
+		AuDbg("%.*s\n", str->len, str->name);
+		if (au_nhash_test_name(str, name, nlen))
+			return 1;
+	}
+	return 0;
+}
+
+static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino,
+			    unsigned char d_type)
+{
+#ifdef CONFIG_AUFS_SHWH
+	wh->wh_ino = ino;
+	wh->wh_type = d_type;
+#endif
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
+		       unsigned int d_type, aufs_bindex_t bindex,
+		       unsigned char shwh)
+{
+	int err;
+	struct au_vdir_destr *str;
+	struct au_vdir_wh *wh;
+
+	AuDbg("%.*s\n", nlen, name);
+	AuDebugOn(!whlist->nh_num || !whlist->nh_head);
+
+	err = -ENOMEM;
+	wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS);
+	if (unlikely(!wh))
+		goto out;
+
+	err = 0;
+	wh->wh_bindex = bindex;
+	if (shwh)
+		au_shwh_init_wh(wh, ino, d_type);
+	str = &wh->wh_str;
+	str->len = nlen;
+	memcpy(str->name, name, nlen);
+	hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen));
+	/* smp_mb(); */
+
+out:
+	return err;
+}
+
+static int append_deblk(struct au_vdir *vdir)
+{
+	int err;
+	unsigned long ul;
+	const unsigned int deblk_sz = vdir->vd_deblk_sz;
+	union au_vdir_deblk_p p, deblk_end;
+	unsigned char **o;
+
+	err = -ENOMEM;
+	o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1),
+		     GFP_NOFS);
+	if (unlikely(!o))
+		goto out;
+
+	vdir->vd_deblk = o;
+	p.deblk = kmalloc(deblk_sz, GFP_NOFS);
+	if (p.deblk) {
+		ul = vdir->vd_nblk++;
+		vdir->vd_deblk[ul] = p.deblk;
+		vdir->vd_last.ul = ul;
+		vdir->vd_last.p.deblk = p.deblk;
+		deblk_end.deblk = p.deblk + deblk_sz;
+		err = set_deblk_end(&p, &deblk_end);
+	}
+
+out:
+	return err;
+}
+
+static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino,
+		     unsigned int d_type, struct au_nhash *delist)
+{
+	int err;
+	unsigned int sz;
+	const unsigned int deblk_sz = vdir->vd_deblk_sz;
+	union au_vdir_deblk_p p, *room, deblk_end;
+	struct au_vdir_dehstr *dehstr;
+
+	p.deblk = last_deblk(vdir);
+	deblk_end.deblk = p.deblk + deblk_sz;
+	room = &vdir->vd_last.p;
+	AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk
+		  || !is_deblk_end(room, &deblk_end));
+
+	sz = calc_size(nlen);
+	if (unlikely(sz > deblk_end.deblk - room->deblk)) {
+		err = append_deblk(vdir);
+		if (unlikely(err))
+			goto out;
+
+		p.deblk = last_deblk(vdir);
+		deblk_end.deblk = p.deblk + deblk_sz;
+		/* smp_mb(); */
+		AuDebugOn(room->deblk != p.deblk);
+	}
+
+	err = -ENOMEM;
+	dehstr = au_cache_alloc_vdir_dehstr();
+	if (unlikely(!dehstr))
+		goto out;
+
+	dehstr->str = &room->de->de_str;
+	hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen));
+	room->de->de_ino = ino;
+	room->de->de_type = d_type;
+	room->de->de_str.len = nlen;
+	memcpy(room->de->de_str.name, name, nlen);
+
+	err = 0;
+	room->deblk += sz;
+	if (unlikely(set_deblk_end(room, &deblk_end)))
+		err = append_deblk(vdir);
+	/* smp_mb(); */
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void au_vdir_free(struct au_vdir *vdir)
+{
+	unsigned char **deblk;
+
+	deblk = vdir->vd_deblk;
+	while (vdir->vd_nblk--)
+		kfree(*deblk++);
+	kfree(vdir->vd_deblk);
+	au_cache_free_vdir(vdir);
+}
+
+static struct au_vdir *alloc_vdir(struct file *file)
+{
+	struct au_vdir *vdir;
+	struct super_block *sb;
+	int err;
+
+	sb = file->f_path.dentry->d_sb;
+	SiMustAnyLock(sb);
+
+	err = -ENOMEM;
+	vdir = au_cache_alloc_vdir();
+	if (unlikely(!vdir))
+		goto out;
+
+	vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS);
+	if (unlikely(!vdir->vd_deblk))
+		goto out_free;
+
+	vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk;
+	if (!vdir->vd_deblk_sz) {
+		/* estimate the appropriate size for deblk */
+		vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL);
+		/* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */
+	}
+	vdir->vd_nblk = 0;
+	vdir->vd_version = 0;
+	vdir->vd_jiffy = 0;
+	err = append_deblk(vdir);
+	if (!err)
+		return vdir; /* success */
+
+	kfree(vdir->vd_deblk);
+
+out_free:
+	au_cache_free_vdir(vdir);
+out:
+	vdir = ERR_PTR(err);
+	return vdir;
+}
+
+static int reinit_vdir(struct au_vdir *vdir)
+{
+	int err;
+	union au_vdir_deblk_p p, deblk_end;
+
+	while (vdir->vd_nblk > 1) {
+		kfree(vdir->vd_deblk[vdir->vd_nblk - 1]);
+		/* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */
+		vdir->vd_nblk--;
+	}
+	p.deblk = vdir->vd_deblk[0];
+	deblk_end.deblk = p.deblk + vdir->vd_deblk_sz;
+	err = set_deblk_end(&p, &deblk_end);
+	/* keep vd_dblk_sz */
+	vdir->vd_last.ul = 0;
+	vdir->vd_last.p.deblk = vdir->vd_deblk[0];
+	vdir->vd_version = 0;
+	vdir->vd_jiffy = 0;
+	/* smp_mb(); */
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#define AuFillVdir_CALLED	1
+#define AuFillVdir_WHABLE	(1 << 1)
+#define AuFillVdir_SHWH		(1 << 2)
+#define au_ftest_fillvdir(flags, name)	((flags) & AuFillVdir_##name)
+#define au_fset_fillvdir(flags, name) \
+	do { (flags) |= AuFillVdir_##name; } while (0)
+#define au_fclr_fillvdir(flags, name) \
+	do { (flags) &= ~AuFillVdir_##name; } while (0)
+
+#ifndef CONFIG_AUFS_SHWH
+#undef AuFillVdir_SHWH
+#define AuFillVdir_SHWH		0
+#endif
+
+struct fillvdir_arg {
+	struct dir_context	ctx;
+	struct file		*file;
+	struct au_vdir		*vdir;
+	struct au_nhash		delist;
+	struct au_nhash		whlist;
+	aufs_bindex_t		bindex;
+	unsigned int		flags;
+	int			err;
+};
+
+static int fillvdir(struct dir_context *ctx, const char *__name, int nlen,
+		    loff_t offset __maybe_unused, u64 h_ino,
+		    unsigned int d_type)
+{
+	struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx);
+	char *name = (void *)__name;
+	struct super_block *sb;
+	ino_t ino;
+	const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH);
+
+	arg->err = 0;
+	sb = arg->file->f_path.dentry->d_sb;
+	au_fset_fillvdir(arg->flags, CALLED);
+	/* smp_mb(); */
+	if (nlen <= AUFS_WH_PFX_LEN
+	    || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
+		if (test_known(&arg->delist, name, nlen)
+		    || au_nhash_test_known_wh(&arg->whlist, name, nlen))
+			goto out; /* already exists or whiteouted */
+
+		arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino);
+		if (!arg->err) {
+			if (unlikely(nlen > AUFS_MAX_NAMELEN))
+				d_type = DT_UNKNOWN;
+			arg->err = append_de(arg->vdir, name, nlen, ino,
+					     d_type, &arg->delist);
+		}
+	} else if (au_ftest_fillvdir(arg->flags, WHABLE)) {
+		name += AUFS_WH_PFX_LEN;
+		nlen -= AUFS_WH_PFX_LEN;
+		if (au_nhash_test_known_wh(&arg->whlist, name, nlen))
+			goto out; /* already whiteouted */
+
+		if (shwh)
+			arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type,
+					     &ino);
+		if (!arg->err) {
+			if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN)
+				d_type = DT_UNKNOWN;
+			arg->err = au_nhash_append_wh
+				(&arg->whlist, name, nlen, ino, d_type,
+				 arg->bindex, shwh);
+		}
+	}
+
+out:
+	if (!arg->err)
+		arg->vdir->vd_jiffy = jiffies;
+	/* smp_mb(); */
+	AuTraceErr(arg->err);
+	return arg->err;
+}
+
+static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir,
+			  struct au_nhash *whlist, struct au_nhash *delist)
+{
+#ifdef CONFIG_AUFS_SHWH
+	int err;
+	unsigned int nh, u;
+	struct hlist_head *head;
+	struct au_vdir_wh *pos;
+	struct hlist_node *n;
+	char *p, *o;
+	struct au_vdir_destr *destr;
+
+	AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH));
+
+	err = -ENOMEM;
+	o = p = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!p))
+		goto out;
+
+	err = 0;
+	nh = whlist->nh_num;
+	memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
+	p += AUFS_WH_PFX_LEN;
+	for (u = 0; u < nh; u++) {
+		head = whlist->nh_head + u;
+		hlist_for_each_entry_safe(pos, n, head, wh_hash) {
+			destr = &pos->wh_str;
+			memcpy(p, destr->name, destr->len);
+			err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN,
+					pos->wh_ino, pos->wh_type, delist);
+			if (unlikely(err))
+				break;
+		}
+	}
+
+	free_page((unsigned long)o);
+
+out:
+	AuTraceErr(err);
+	return err;
+#else
+	return 0;
+#endif
+}
+
+static int au_do_read_vdir(struct fillvdir_arg *arg)
+{
+	int err;
+	unsigned int rdhash;
+	loff_t offset;
+	aufs_bindex_t bend, bindex, bstart;
+	unsigned char shwh;
+	struct file *hf, *file;
+	struct super_block *sb;
+
+	file = arg->file;
+	sb = file->f_path.dentry->d_sb;
+	SiMustAnyLock(sb);
+
+	rdhash = au_sbi(sb)->si_rdhash;
+	if (!rdhash)
+		rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL));
+	err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS);
+	if (unlikely(err))
+		goto out;
+	err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS);
+	if (unlikely(err))
+		goto out_delist;
+
+	err = 0;
+	arg->flags = 0;
+	shwh = 0;
+	if (au_opt_test(au_mntflags(sb), SHWH)) {
+		shwh = 1;
+		au_fset_fillvdir(arg->flags, SHWH);
+	}
+	bstart = au_fbstart(file);
+	bend = au_fbend_dir(file);
+	for (bindex = bstart; !err && bindex <= bend; bindex++) {
+		hf = au_hf_dir(file, bindex);
+		if (!hf)
+			continue;
+
+		offset = vfsub_llseek(hf, 0, SEEK_SET);
+		err = offset;
+		if (unlikely(offset))
+			break;
+
+		arg->bindex = bindex;
+		au_fclr_fillvdir(arg->flags, WHABLE);
+		if (shwh
+		    || (bindex != bend
+			&& au_br_whable(au_sbr_perm(sb, bindex))))
+			au_fset_fillvdir(arg->flags, WHABLE);
+		do {
+			arg->err = 0;
+			au_fclr_fillvdir(arg->flags, CALLED);
+			/* smp_mb(); */
+			err = vfsub_iterate_dir(hf, &arg->ctx);
+			if (err >= 0)
+				err = arg->err;
+		} while (!err && au_ftest_fillvdir(arg->flags, CALLED));
+
+		/*
+		 * dir_relax() may be good for concurrency, but aufs should not
+		 * use it since it will cause a lockdep problem.
+		 */
+	}
+
+	if (!err && shwh)
+		err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist);
+
+	au_nhash_wh_free(&arg->whlist);
+
+out_delist:
+	au_nhash_de_free(&arg->delist);
+out:
+	return err;
+}
+
+static int read_vdir(struct file *file, int may_read)
+{
+	int err;
+	unsigned long expire;
+	unsigned char do_read;
+	struct fillvdir_arg arg = {
+		.ctx = {
+			.actor = fillvdir
+		}
+	};
+	struct inode *inode;
+	struct au_vdir *vdir, *allocated;
+
+	err = 0;
+	inode = file_inode(file);
+	IMustLock(inode);
+	SiMustAnyLock(inode->i_sb);
+
+	allocated = NULL;
+	do_read = 0;
+	expire = au_sbi(inode->i_sb)->si_rdcache;
+	vdir = au_ivdir(inode);
+	if (!vdir) {
+		do_read = 1;
+		vdir = alloc_vdir(file);
+		err = PTR_ERR(vdir);
+		if (IS_ERR(vdir))
+			goto out;
+		err = 0;
+		allocated = vdir;
+	} else if (may_read
+		   && (inode->i_version != vdir->vd_version
+		       || time_after(jiffies, vdir->vd_jiffy + expire))) {
+		do_read = 1;
+		err = reinit_vdir(vdir);
+		if (unlikely(err))
+			goto out;
+	}
+
+	if (!do_read)
+		return 0; /* success */
+
+	arg.file = file;
+	arg.vdir = vdir;
+	err = au_do_read_vdir(&arg);
+	if (!err) {
+		/* file->f_pos = 0; */ /* todo: ctx->pos? */
+		vdir->vd_version = inode->i_version;
+		vdir->vd_last.ul = 0;
+		vdir->vd_last.p.deblk = vdir->vd_deblk[0];
+		if (allocated)
+			au_set_ivdir(inode, allocated);
+	} else if (allocated)
+		au_vdir_free(allocated);
+
+out:
+	return err;
+}
+
+static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src)
+{
+	int err, rerr;
+	unsigned long ul, n;
+	const unsigned int deblk_sz = src->vd_deblk_sz;
+
+	AuDebugOn(tgt->vd_nblk != 1);
+
+	err = -ENOMEM;
+	if (tgt->vd_nblk < src->vd_nblk) {
+		unsigned char **p;
+
+		p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk,
+			     GFP_NOFS);
+		if (unlikely(!p))
+			goto out;
+		tgt->vd_deblk = p;
+	}
+
+	if (tgt->vd_deblk_sz != deblk_sz) {
+		unsigned char *p;
+
+		tgt->vd_deblk_sz = deblk_sz;
+		p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS);
+		if (unlikely(!p))
+			goto out;
+		tgt->vd_deblk[0] = p;
+	}
+	memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz);
+	tgt->vd_version = src->vd_version;
+	tgt->vd_jiffy = src->vd_jiffy;
+
+	n = src->vd_nblk;
+	for (ul = 1; ul < n; ul++) {
+		tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz,
+					    GFP_NOFS);
+		if (unlikely(!tgt->vd_deblk[ul]))
+			goto out;
+		tgt->vd_nblk++;
+	}
+	tgt->vd_nblk = n;
+	tgt->vd_last.ul = tgt->vd_last.ul;
+	tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul];
+	tgt->vd_last.p.deblk += src->vd_last.p.deblk
+		- src->vd_deblk[src->vd_last.ul];
+	/* smp_mb(); */
+	return 0; /* success */
+
+out:
+	rerr = reinit_vdir(tgt);
+	BUG_ON(rerr);
+	return err;
+}
+
+int au_vdir_init(struct file *file)
+{
+	int err;
+	struct inode *inode;
+	struct au_vdir *vdir_cache, *allocated;
+
+	/* test file->f_pos here instead of ctx->pos */
+	err = read_vdir(file, !file->f_pos);
+	if (unlikely(err))
+		goto out;
+
+	allocated = NULL;
+	vdir_cache = au_fvdir_cache(file);
+	if (!vdir_cache) {
+		vdir_cache = alloc_vdir(file);
+		err = PTR_ERR(vdir_cache);
+		if (IS_ERR(vdir_cache))
+			goto out;
+		allocated = vdir_cache;
+	} else if (!file->f_pos && vdir_cache->vd_version != file->f_version) {
+		/* test file->f_pos here instead of ctx->pos */
+		err = reinit_vdir(vdir_cache);
+		if (unlikely(err))
+			goto out;
+	} else
+		return 0; /* success */
+
+	inode = file_inode(file);
+	err = copy_vdir(vdir_cache, au_ivdir(inode));
+	if (!err) {
+		file->f_version = inode->i_version;
+		if (allocated)
+			au_set_fvdir_cache(file, allocated);
+	} else if (allocated)
+		au_vdir_free(allocated);
+
+out:
+	return err;
+}
+
+static loff_t calc_offset(struct au_vdir *vdir)
+{
+	loff_t offset;
+	union au_vdir_deblk_p p;
+
+	p.deblk = vdir->vd_deblk[vdir->vd_last.ul];
+	offset = vdir->vd_last.p.deblk - p.deblk;
+	offset += vdir->vd_deblk_sz * vdir->vd_last.ul;
+	return offset;
+}
+
+/* returns true or false */
+static int seek_vdir(struct file *file, struct dir_context *ctx)
+{
+	int valid;
+	unsigned int deblk_sz;
+	unsigned long ul, n;
+	loff_t offset;
+	union au_vdir_deblk_p p, deblk_end;
+	struct au_vdir *vdir_cache;
+
+	valid = 1;
+	vdir_cache = au_fvdir_cache(file);
+	offset = calc_offset(vdir_cache);
+	AuDbg("offset %lld\n", offset);
+	if (ctx->pos == offset)
+		goto out;
+
+	vdir_cache->vd_last.ul = 0;
+	vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0];
+	if (!ctx->pos)
+		goto out;
+
+	valid = 0;
+	deblk_sz = vdir_cache->vd_deblk_sz;
+	ul = div64_u64(ctx->pos, deblk_sz);
+	AuDbg("ul %lu\n", ul);
+	if (ul >= vdir_cache->vd_nblk)
+		goto out;
+
+	n = vdir_cache->vd_nblk;
+	for (; ul < n; ul++) {
+		p.deblk = vdir_cache->vd_deblk[ul];
+		deblk_end.deblk = p.deblk + deblk_sz;
+		offset = ul;
+		offset *= deblk_sz;
+		while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) {
+			unsigned int l;
+
+			l = calc_size(p.de->de_str.len);
+			offset += l;
+			p.deblk += l;
+		}
+		if (!is_deblk_end(&p, &deblk_end)) {
+			valid = 1;
+			vdir_cache->vd_last.ul = ul;
+			vdir_cache->vd_last.p = p;
+			break;
+		}
+	}
+
+out:
+	/* smp_mb(); */
+	AuTraceErr(!valid);
+	return valid;
+}
+
+int au_vdir_fill_de(struct file *file, struct dir_context *ctx)
+{
+	unsigned int l, deblk_sz;
+	union au_vdir_deblk_p deblk_end;
+	struct au_vdir *vdir_cache;
+	struct au_vdir_de *de;
+
+	vdir_cache = au_fvdir_cache(file);
+	if (!seek_vdir(file, ctx))
+		return 0;
+
+	deblk_sz = vdir_cache->vd_deblk_sz;
+	while (1) {
+		deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
+		deblk_end.deblk += deblk_sz;
+		while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) {
+			de = vdir_cache->vd_last.p.de;
+			AuDbg("%.*s, off%lld, i%lu, dt%d\n",
+			      de->de_str.len, de->de_str.name, ctx->pos,
+			      (unsigned long)de->de_ino, de->de_type);
+			if (unlikely(!dir_emit(ctx, de->de_str.name,
+					       de->de_str.len, de->de_ino,
+					       de->de_type))) {
+				/* todo: ignore the error caused by udba? */
+				/* return err; */
+				return 0;
+			}
+
+			l = calc_size(de->de_str.len);
+			vdir_cache->vd_last.p.deblk += l;
+			ctx->pos += l;
+		}
+		if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) {
+			vdir_cache->vd_last.ul++;
+			vdir_cache->vd_last.p.deblk
+				= vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
+			ctx->pos = deblk_sz * vdir_cache->vd_last.ul;
+			continue;
+		}
+		break;
+	}
+
+	/* smp_mb(); */
+	return 0;
+}
--- linux-4.4.0.orig/fs/aufs/vfsub.c
+++ linux-4.4.0/fs/aufs/vfsub.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * sub-routines for VFS
+ */
+
+#include <linux/namei.h>
+#include <linux/nsproxy.h>
+#include <linux/security.h>
+#include <linux/splice.h>
+#include "../fs/mount.h"
+#include "aufs.h"
+
+#ifdef CONFIG_AUFS_BR_FUSE
+int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb)
+{
+	struct nsproxy *ns;
+
+	if (!au_test_fuse(h_sb) || !au_userns)
+		return 0;
+
+	ns = current->nsproxy;
+	/* no {get,put}_nsproxy(ns) */
+	return real_mount(mnt)->mnt_ns == ns->mnt_ns ? 0 : -EACCES;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+int vfsub_update_h_iattr(struct path *h_path, int *did)
+{
+	int err;
+	struct kstat st;
+	struct super_block *h_sb;
+
+	/* for remote fs, leave work for its getattr or d_revalidate */
+	/* for bad i_attr fs, handle them in aufs_getattr() */
+	/* still some fs may acquire i_mutex. we need to skip them */
+	err = 0;
+	if (!did)
+		did = &err;
+	h_sb = h_path->dentry->d_sb;
+	*did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb));
+	if (*did)
+		err = vfs_getattr(h_path, &st);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct file *vfsub_dentry_open(struct path *path, int flags)
+{
+	return dentry_open(path, flags /* | __FMODE_NONOTIFY */,
+			   current_cred());
+}
+
+struct file *vfsub_filp_open(const char *path, int oflags, int mode)
+{
+	struct file *file;
+
+	lockdep_off();
+	file = filp_open(path,
+			 oflags /* | __FMODE_NONOTIFY */,
+			 mode);
+	lockdep_on();
+	if (IS_ERR(file))
+		goto out;
+	vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
+
+out:
+	return file;
+}
+
+/*
+ * Ideally this function should call VFS:do_last() in order to keep all its
+ * checkings. But it is very hard for aufs to regenerate several VFS internal
+ * structure such as nameidata. This is a second (or third) best approach.
+ * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open().
+ */
+int vfsub_atomic_open(struct inode *dir, struct dentry *dentry,
+		      struct vfsub_aopen_args *args, struct au_branch *br)
+{
+	int err;
+	struct file *file = args->file;
+	/* copied from linux/fs/namei.c:atomic_open() */
+	struct dentry *const DENTRY_NOT_SET = (void *)-1UL;
+
+	IMustLock(dir);
+	AuDebugOn(!dir->i_op->atomic_open);
+
+	err = au_br_test_oflag(args->open_flag, br);
+	if (unlikely(err))
+		goto out;
+
+	args->file->f_path.dentry = DENTRY_NOT_SET;
+	args->file->f_path.mnt = au_br_mnt(br);
+	err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag,
+				     args->create_mode, args->opened);
+	if (err >= 0) {
+		/* some filesystems don't set FILE_CREATED while succeeded? */
+		if (*args->opened & FILE_CREATED)
+			fsnotify_create(dir, dentry);
+	} else
+		goto out;
+
+
+	if (!err) {
+		/* todo: call VFS:may_open() here */
+		err = open_check_o_direct(file);
+		/* todo: ima_file_check() too? */
+		if (!err && (args->open_flag & __FMODE_EXEC))
+			err = deny_write_access(file);
+		if (unlikely(err))
+			/* note that the file is created and still opened */
+			goto out;
+	}
+
+	atomic_inc(&br->br_count);
+	fsnotify_open(file);
+
+out:
+	return err;
+}
+
+int vfsub_kern_path(const char *name, unsigned int flags, struct path *path)
+{
+	int err;
+
+	err = kern_path(name, flags, path);
+	if (!err && d_is_positive(path->dentry))
+		vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/
+	return err;
+}
+
+struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
+				    int len)
+{
+	struct path path = {
+		.mnt = NULL
+	};
+
+	/* VFS checks it too, but by WARN_ON_ONCE() */
+	IMustLock(d_inode(parent));
+
+	path.dentry = lookup_one_len(name, parent, len);
+	if (IS_ERR(path.dentry))
+		goto out;
+	if (d_is_positive(path.dentry))
+		vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
+
+out:
+	AuTraceErrPtr(path.dentry);
+	return path.dentry;
+}
+
+void vfsub_call_lkup_one(void *args)
+{
+	struct vfsub_lkup_one_args *a = args;
+	*a->errp = vfsub_lkup_one(a->name, a->parent);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
+				 struct dentry *d2, struct au_hinode *hdir2)
+{
+	struct dentry *d;
+
+	lockdep_off();
+	d = lock_rename(d1, d2);
+	lockdep_on();
+	au_hn_suspend(hdir1);
+	if (hdir1 != hdir2)
+		au_hn_suspend(hdir2);
+
+	return d;
+}
+
+void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
+			 struct dentry *d2, struct au_hinode *hdir2)
+{
+	au_hn_resume(hdir1);
+	if (hdir1 != hdir2)
+		au_hn_resume(hdir2);
+	lockdep_off();
+	unlock_rename(d1, d2);
+	lockdep_on();
+}
+
+/* ---------------------------------------------------------------------- */
+
+int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl)
+{
+	int err;
+	struct dentry *d;
+
+	IMustLock(dir);
+
+	d = path->dentry;
+	path->dentry = d->d_parent;
+	err = security_path_mknod(path, d, mode, 0);
+	path->dentry = d;
+	if (unlikely(err))
+		goto out;
+
+	lockdep_off();
+	err = vfs_create(dir, path->dentry, mode, want_excl);
+	lockdep_on();
+	if (!err) {
+		struct path tmp = *path;
+		int did;
+
+		vfsub_update_h_iattr(&tmp, &did);
+		if (did) {
+			tmp.dentry = path->dentry->d_parent;
+			vfsub_update_h_iattr(&tmp, /*did*/NULL);
+		}
+		/*ignore*/
+	}
+
+out:
+	return err;
+}
+
+int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
+{
+	int err;
+	struct dentry *d;
+
+	IMustLock(dir);
+
+	d = path->dentry;
+	path->dentry = d->d_parent;
+	err = security_path_symlink(path, d, symname);
+	path->dentry = d;
+	if (unlikely(err))
+		goto out;
+
+	lockdep_off();
+	err = vfs_symlink(dir, path->dentry, symname);
+	lockdep_on();
+	if (!err) {
+		struct path tmp = *path;
+		int did;
+
+		vfsub_update_h_iattr(&tmp, &did);
+		if (did) {
+			tmp.dentry = path->dentry->d_parent;
+			vfsub_update_h_iattr(&tmp, /*did*/NULL);
+		}
+		/*ignore*/
+	}
+
+out:
+	return err;
+}
+
+int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev)
+{
+	int err;
+	struct dentry *d;
+
+	IMustLock(dir);
+
+	d = path->dentry;
+	path->dentry = d->d_parent;
+	err = security_path_mknod(path, d, mode, new_encode_dev(dev));
+	path->dentry = d;
+	if (unlikely(err))
+		goto out;
+
+	lockdep_off();
+	err = vfs_mknod(dir, path->dentry, mode, dev);
+	lockdep_on();
+	if (!err) {
+		struct path tmp = *path;
+		int did;
+
+		vfsub_update_h_iattr(&tmp, &did);
+		if (did) {
+			tmp.dentry = path->dentry->d_parent;
+			vfsub_update_h_iattr(&tmp, /*did*/NULL);
+		}
+		/*ignore*/
+	}
+
+out:
+	return err;
+}
+
+static int au_test_nlink(struct inode *inode)
+{
+	const unsigned int link_max = UINT_MAX >> 1; /* rough margin */
+
+	if (!au_test_fs_no_limit_nlink(inode->i_sb)
+	    || inode->i_nlink < link_max)
+		return 0;
+	return -EMLINK;
+}
+
+int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path,
+	       struct inode **delegated_inode)
+{
+	int err;
+	struct dentry *d;
+
+	IMustLock(dir);
+
+	err = au_test_nlink(d_inode(src_dentry));
+	if (unlikely(err))
+		return err;
+
+	/* we don't call may_linkat() */
+	d = path->dentry;
+	path->dentry = d->d_parent;
+	err = security_path_link(src_dentry, path, d);
+	path->dentry = d;
+	if (unlikely(err))
+		goto out;
+
+	lockdep_off();
+	err = vfs_link(src_dentry, dir, path->dentry, delegated_inode);
+	lockdep_on();
+	if (!err) {
+		struct path tmp = *path;
+		int did;
+
+		/* fuse has different memory inode for the same inumber */
+		vfsub_update_h_iattr(&tmp, &did);
+		if (did) {
+			tmp.dentry = path->dentry->d_parent;
+			vfsub_update_h_iattr(&tmp, /*did*/NULL);
+			tmp.dentry = src_dentry;
+			vfsub_update_h_iattr(&tmp, /*did*/NULL);
+		}
+		/*ignore*/
+	}
+
+out:
+	return err;
+}
+
+int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
+		 struct inode *dir, struct path *path,
+		 struct inode **delegated_inode)
+{
+	int err;
+	struct path tmp = {
+		.mnt	= path->mnt
+	};
+	struct dentry *d;
+
+	IMustLock(dir);
+	IMustLock(src_dir);
+
+	d = path->dentry;
+	path->dentry = d->d_parent;
+	tmp.dentry = src_dentry->d_parent;
+	err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0);
+	path->dentry = d;
+	if (unlikely(err))
+		goto out;
+
+	lockdep_off();
+	err = vfs_rename(src_dir, src_dentry, dir, path->dentry,
+			 delegated_inode, /*flags*/0);
+	lockdep_on();
+	if (!err) {
+		int did;
+
+		tmp.dentry = d->d_parent;
+		vfsub_update_h_iattr(&tmp, &did);
+		if (did) {
+			tmp.dentry = src_dentry;
+			vfsub_update_h_iattr(&tmp, /*did*/NULL);
+			tmp.dentry = src_dentry->d_parent;
+			vfsub_update_h_iattr(&tmp, /*did*/NULL);
+		}
+		/*ignore*/
+	}
+
+out:
+	return err;
+}
+
+int vfsub_mkdir(struct inode *dir, struct path *path, int mode)
+{
+	int err;
+	struct dentry *d;
+
+	IMustLock(dir);
+
+	d = path->dentry;
+	path->dentry = d->d_parent;
+	err = security_path_mkdir(path, d, mode);
+	path->dentry = d;
+	if (unlikely(err))
+		goto out;
+
+	lockdep_off();
+	err = vfs_mkdir(dir, path->dentry, mode);
+	lockdep_on();
+	if (!err) {
+		struct path tmp = *path;
+		int did;
+
+		vfsub_update_h_iattr(&tmp, &did);
+		if (did) {
+			tmp.dentry = path->dentry->d_parent;
+			vfsub_update_h_iattr(&tmp, /*did*/NULL);
+		}
+		/*ignore*/
+	}
+
+out:
+	return err;
+}
+
+int vfsub_rmdir(struct inode *dir, struct path *path)
+{
+	int err;
+	struct dentry *d;
+
+	IMustLock(dir);
+
+	d = path->dentry;
+	path->dentry = d->d_parent;
+	err = security_path_rmdir(path, d);
+	path->dentry = d;
+	if (unlikely(err))
+		goto out;
+
+	lockdep_off();
+	err = vfs_rmdir(dir, path->dentry);
+	lockdep_on();
+	if (!err) {
+		struct path tmp = {
+			.dentry	= path->dentry->d_parent,
+			.mnt	= path->mnt
+		};
+
+		vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
+	}
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* todo: support mmap_sem? */
+ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
+		     loff_t *ppos)
+{
+	ssize_t err;
+
+	lockdep_off();
+	err = vfs_read(file, ubuf, count, ppos);
+	lockdep_on();
+	if (err >= 0)
+		vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
+	return err;
+}
+
+/* todo: kernel_read()? */
+ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
+		     loff_t *ppos)
+{
+	ssize_t err;
+	mm_segment_t oldfs;
+	union {
+		void *k;
+		char __user *u;
+	} buf;
+
+	buf.k = kbuf;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = vfsub_read_u(file, buf.u, count, ppos);
+	set_fs(oldfs);
+	return err;
+}
+
+ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
+		      loff_t *ppos)
+{
+	ssize_t err;
+
+	lockdep_off();
+	err = vfs_write(file, ubuf, count, ppos);
+	lockdep_on();
+	if (err >= 0)
+		vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
+	return err;
+}
+
+ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos)
+{
+	ssize_t err;
+	mm_segment_t oldfs;
+	union {
+		void *k;
+		const char __user *u;
+	} buf;
+
+	buf.k = kbuf;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = vfsub_write_u(file, buf.u, count, ppos);
+	set_fs(oldfs);
+	return err;
+}
+
+int vfsub_flush(struct file *file, fl_owner_t id)
+{
+	int err;
+
+	err = 0;
+	if (file->f_op->flush) {
+		if (!au_test_nfs(file->f_path.dentry->d_sb))
+			err = file->f_op->flush(file, id);
+		else {
+			lockdep_off();
+			err = file->f_op->flush(file, id);
+			lockdep_on();
+		}
+		if (!err)
+			vfsub_update_h_iattr(&file->f_path, /*did*/NULL);
+		/*ignore*/
+	}
+	return err;
+}
+
+int vfsub_iterate_dir(struct file *file, struct dir_context *ctx)
+{
+	int err;
+
+	AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos);
+
+	lockdep_off();
+	err = iterate_dir(file, ctx);
+	lockdep_on();
+	if (err >= 0)
+		vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
+	return err;
+}
+
+long vfsub_splice_to(struct file *in, loff_t *ppos,
+		     struct pipe_inode_info *pipe, size_t len,
+		     unsigned int flags)
+{
+	long err;
+
+	lockdep_off();
+	err = do_splice_to(in, ppos, pipe, len, flags);
+	lockdep_on();
+	file_accessed(in);
+	if (err >= 0)
+		vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/
+	return err;
+}
+
+long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
+		       loff_t *ppos, size_t len, unsigned int flags)
+{
+	long err;
+
+	lockdep_off();
+	err = do_splice_from(pipe, out, ppos, len, flags);
+	lockdep_on();
+	if (err >= 0)
+		vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/
+	return err;
+}
+
+int vfsub_fsync(struct file *file, struct path *path, int datasync)
+{
+	int err;
+
+	/* file can be NULL */
+	lockdep_off();
+	err = vfs_fsync(file, datasync);
+	lockdep_on();
+	if (!err) {
+		if (!path) {
+			AuDebugOn(!file);
+			path = &file->f_path;
+		}
+		vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/
+	}
+	return err;
+}
+
+/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */
+int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
+		struct file *h_file)
+{
+	int err;
+	struct inode *h_inode;
+	struct super_block *h_sb;
+
+	if (!h_file) {
+		err = vfsub_truncate(h_path, length);
+		goto out;
+	}
+
+	h_inode = d_inode(h_path->dentry);
+	h_sb = h_inode->i_sb;
+	lockdep_off();
+	sb_start_write(h_sb);
+	lockdep_on();
+	err = locks_verify_truncate(h_inode, h_file, length);
+	if (!err)
+		err = security_path_truncate(h_path);
+	if (!err) {
+		lockdep_off();
+		err = do_truncate(h_path->dentry, length, attr, h_file);
+		lockdep_on();
+	}
+	lockdep_off();
+	sb_end_write(h_sb);
+	lockdep_on();
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct au_vfsub_mkdir_args {
+	int *errp;
+	struct inode *dir;
+	struct path *path;
+	int mode;
+};
+
+static void au_call_vfsub_mkdir(void *args)
+{
+	struct au_vfsub_mkdir_args *a = args;
+	*a->errp = vfsub_mkdir(a->dir, a->path, a->mode);
+}
+
+int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode)
+{
+	int err, do_sio, wkq_err;
+
+	do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
+	if (!do_sio) {
+		lockdep_off();
+		err = vfsub_mkdir(dir, path, mode);
+		lockdep_on();
+	} else {
+		struct au_vfsub_mkdir_args args = {
+			.errp	= &err,
+			.dir	= dir,
+			.path	= path,
+			.mode	= mode
+		};
+		wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+	}
+
+	return err;
+}
+
+struct au_vfsub_rmdir_args {
+	int *errp;
+	struct inode *dir;
+	struct path *path;
+};
+
+static void au_call_vfsub_rmdir(void *args)
+{
+	struct au_vfsub_rmdir_args *a = args;
+	*a->errp = vfsub_rmdir(a->dir, a->path);
+}
+
+int vfsub_sio_rmdir(struct inode *dir, struct path *path)
+{
+	int err, do_sio, wkq_err;
+
+	do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
+	if (!do_sio) {
+		lockdep_off();
+		err = vfsub_rmdir(dir, path);
+		lockdep_on();
+	} else {
+		struct au_vfsub_rmdir_args args = {
+			.errp	= &err,
+			.dir	= dir,
+			.path	= path
+		};
+		wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct notify_change_args {
+	int *errp;
+	struct path *path;
+	struct iattr *ia;
+	struct inode **delegated_inode;
+};
+
+static void call_notify_change(void *args)
+{
+	struct notify_change_args *a = args;
+	struct inode *h_inode;
+
+	h_inode = d_inode(a->path->dentry);
+	IMustLock(h_inode);
+
+	*a->errp = -EPERM;
+	if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
+		lockdep_off();
+		*a->errp = notify_change(a->path->dentry, a->ia,
+					 a->delegated_inode);
+		lockdep_on();
+		if (!*a->errp)
+			vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
+	}
+	AuTraceErr(*a->errp);
+}
+
+int vfsub_notify_change(struct path *path, struct iattr *ia,
+			struct inode **delegated_inode)
+{
+	int err;
+	struct notify_change_args args = {
+		.errp			= &err,
+		.path			= path,
+		.ia			= ia,
+		.delegated_inode	= delegated_inode
+	};
+
+	call_notify_change(&args);
+
+	return err;
+}
+
+int vfsub_sio_notify_change(struct path *path, struct iattr *ia,
+			    struct inode **delegated_inode)
+{
+	int err, wkq_err;
+	struct notify_change_args args = {
+		.errp			= &err,
+		.path			= path,
+		.ia			= ia,
+		.delegated_inode	= delegated_inode
+	};
+
+	wkq_err = au_wkq_wait(call_notify_change, &args);
+	if (unlikely(wkq_err))
+		err = wkq_err;
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct unlink_args {
+	int *errp;
+	struct inode *dir;
+	struct path *path;
+	struct inode **delegated_inode;
+};
+
+static void call_unlink(void *args)
+{
+	struct unlink_args *a = args;
+	struct dentry *d = a->path->dentry;
+	struct inode *h_inode;
+	const int stop_sillyrename = (au_test_nfs(d->d_sb)
+				      && au_dcount(d) == 1);
+
+	IMustLock(a->dir);
+
+	a->path->dentry = d->d_parent;
+	*a->errp = security_path_unlink(a->path, d);
+	a->path->dentry = d;
+	if (unlikely(*a->errp))
+		return;
+
+	if (!stop_sillyrename)
+		dget(d);
+	h_inode = NULL;
+	if (d_is_positive(d)) {
+		h_inode = d_inode(d);
+		ihold(h_inode);
+	}
+
+	lockdep_off();
+	*a->errp = vfs_unlink(a->dir, d, a->delegated_inode);
+	lockdep_on();
+	if (!*a->errp) {
+		struct path tmp = {
+			.dentry = d->d_parent,
+			.mnt	= a->path->mnt
+		};
+		vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
+	}
+
+	if (!stop_sillyrename)
+		dput(d);
+	if (h_inode)
+		iput(h_inode);
+
+	AuTraceErr(*a->errp);
+}
+
+/*
+ * @dir: must be locked.
+ * @dentry: target dentry.
+ */
+int vfsub_unlink(struct inode *dir, struct path *path,
+		 struct inode **delegated_inode, int force)
+{
+	int err;
+	struct unlink_args args = {
+		.errp			= &err,
+		.dir			= dir,
+		.path			= path,
+		.delegated_inode	= delegated_inode
+	};
+
+	if (!force)
+		call_unlink(&args);
+	else {
+		int wkq_err;
+
+		wkq_err = au_wkq_wait(call_unlink, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+	}
+
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/vfsub.h
+++ linux-4.4.0/fs/aufs/vfsub.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * sub-routines for VFS
+ */
+
+#ifndef __AUFS_VFSUB_H__
+#define __AUFS_VFSUB_H__
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/posix_acl.h>
+#include <linux/xattr.h>
+#include "debug.h"
+
+/* copied from linux/fs/internal.h */
+/* todo: BAD approach!! */
+extern void __mnt_drop_write(struct vfsmount *);
+extern int open_check_o_direct(struct file *f);
+
+/* ---------------------------------------------------------------------- */
+
+/* lock subclass for lower inode */
+/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */
+/* reduce? gave up. */
+enum {
+	AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */
+	AuLsc_I_PARENT,		/* lower inode, parent first */
+	AuLsc_I_PARENT2,	/* copyup dirs */
+	AuLsc_I_PARENT3,	/* copyup wh */
+	AuLsc_I_CHILD,
+	AuLsc_I_CHILD2,
+	AuLsc_I_End
+};
+
+/* to debug easier, do not make them inlined functions */
+#define MtxMustLock(mtx)	AuDebugOn(!mutex_is_locked(mtx))
+#define IMustLock(i)		MtxMustLock(&(i)->i_mutex)
+
+/* ---------------------------------------------------------------------- */
+
+static inline void vfsub_drop_nlink(struct inode *inode)
+{
+	AuDebugOn(!inode->i_nlink);
+	drop_nlink(inode);
+}
+
+static inline void vfsub_dead_dir(struct inode *inode)
+{
+	AuDebugOn(!S_ISDIR(inode->i_mode));
+	inode->i_flags |= S_DEAD;
+	clear_nlink(inode);
+}
+
+static inline int vfsub_native_ro(struct inode *inode)
+{
+	return (inode->i_sb->s_flags & MS_RDONLY)
+		|| IS_RDONLY(inode)
+		/* || IS_APPEND(inode) */
+		|| IS_IMMUTABLE(inode);
+}
+
+#ifdef CONFIG_AUFS_BR_FUSE
+int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb);
+#else
+AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb);
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+int vfsub_update_h_iattr(struct path *h_path, int *did);
+struct file *vfsub_dentry_open(struct path *path, int flags);
+struct file *vfsub_filp_open(const char *path, int oflags, int mode);
+struct vfsub_aopen_args {
+	struct file	*file;
+	unsigned int	open_flag;
+	umode_t		create_mode;
+	int		*opened;
+};
+struct au_branch;
+int vfsub_atomic_open(struct inode *dir, struct dentry *dentry,
+		      struct vfsub_aopen_args *args, struct au_branch *br);
+int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
+
+struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
+				    int len);
+
+struct vfsub_lkup_one_args {
+	struct dentry **errp;
+	struct qstr *name;
+	struct dentry *parent;
+};
+
+static inline struct dentry *vfsub_lkup_one(struct qstr *name,
+					    struct dentry *parent)
+{
+	return vfsub_lookup_one_len(name->name, parent, name->len);
+}
+
+void vfsub_call_lkup_one(void *args);
+
+/* ---------------------------------------------------------------------- */
+
+static inline int vfsub_mnt_want_write(struct vfsmount *mnt)
+{
+	int err;
+
+	lockdep_off();
+	err = mnt_want_write(mnt);
+	lockdep_on();
+	return err;
+}
+
+static inline void vfsub_mnt_drop_write(struct vfsmount *mnt)
+{
+	lockdep_off();
+	mnt_drop_write(mnt);
+	lockdep_on();
+}
+
+#if 0 /* reserved */
+static inline void vfsub_mnt_drop_write_file(struct file *file)
+{
+	lockdep_off();
+	mnt_drop_write_file(file);
+	lockdep_on();
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+struct au_hinode;
+struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
+				 struct dentry *d2, struct au_hinode *hdir2);
+void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
+			 struct dentry *d2, struct au_hinode *hdir2);
+
+int vfsub_create(struct inode *dir, struct path *path, int mode,
+		 bool want_excl);
+int vfsub_symlink(struct inode *dir, struct path *path,
+		  const char *symname);
+int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev);
+int vfsub_link(struct dentry *src_dentry, struct inode *dir,
+	       struct path *path, struct inode **delegated_inode);
+int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry,
+		 struct inode *hdir, struct path *path,
+		 struct inode **delegated_inode);
+int vfsub_mkdir(struct inode *dir, struct path *path, int mode);
+int vfsub_rmdir(struct inode *dir, struct path *path);
+
+/* ---------------------------------------------------------------------- */
+
+ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
+		     loff_t *ppos);
+ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
+			loff_t *ppos);
+ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
+		      loff_t *ppos);
+ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count,
+		      loff_t *ppos);
+int vfsub_flush(struct file *file, fl_owner_t id);
+int vfsub_iterate_dir(struct file *file, struct dir_context *ctx);
+
+static inline loff_t vfsub_f_size_read(struct file *file)
+{
+	return i_size_read(file_inode(file));
+}
+
+static inline unsigned int vfsub_file_flags(struct file *file)
+{
+	unsigned int flags;
+
+	spin_lock(&file->f_lock);
+	flags = file->f_flags;
+	spin_unlock(&file->f_lock);
+
+	return flags;
+}
+
+#if 0 /* reserved */
+static inline void vfsub_file_accessed(struct file *h_file)
+{
+	file_accessed(h_file);
+	vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/
+}
+#endif
+
+#if 0 /* reserved */
+static inline void vfsub_touch_atime(struct vfsmount *h_mnt,
+				     struct dentry *h_dentry)
+{
+	struct path h_path = {
+		.dentry	= h_dentry,
+		.mnt	= h_mnt
+	};
+	touch_atime(&h_path);
+	vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
+}
+#endif
+
+static inline int vfsub_update_time(struct inode *h_inode, struct timespec *ts,
+				    int flags)
+{
+	return generic_update_time(h_inode, ts, flags);
+	/* no vfsub_update_h_iattr() since we don't have struct path */
+}
+
+#ifdef CONFIG_FS_POSIX_ACL
+static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode)
+{
+	int err;
+
+	err = posix_acl_chmod(h_inode, h_mode);
+	if (err == -EOPNOTSUPP)
+		err = 0;
+	return err;
+}
+#else
+AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode);
+#endif
+
+long vfsub_splice_to(struct file *in, loff_t *ppos,
+		     struct pipe_inode_info *pipe, size_t len,
+		     unsigned int flags);
+long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
+		       loff_t *ppos, size_t len, unsigned int flags);
+
+static inline long vfsub_truncate(struct path *path, loff_t length)
+{
+	long err;
+
+	lockdep_off();
+	err = vfs_truncate(path, length);
+	lockdep_on();
+	return err;
+}
+
+int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
+		struct file *h_file);
+int vfsub_fsync(struct file *file, struct path *path, int datasync);
+
+/* ---------------------------------------------------------------------- */
+
+static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin)
+{
+	loff_t err;
+
+	lockdep_off();
+	err = vfs_llseek(file, offset, origin);
+	lockdep_on();
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode);
+int vfsub_sio_rmdir(struct inode *dir, struct path *path);
+int vfsub_sio_notify_change(struct path *path, struct iattr *ia,
+			    struct inode **delegated_inode);
+int vfsub_notify_change(struct path *path, struct iattr *ia,
+			struct inode **delegated_inode);
+int vfsub_unlink(struct inode *dir, struct path *path,
+		 struct inode **delegated_inode, int force);
+
+/* ---------------------------------------------------------------------- */
+
+static inline int vfsub_setxattr(struct dentry *dentry, const char *name,
+				 const void *value, size_t size, int flags)
+{
+	int err;
+
+	lockdep_off();
+	err = vfs_setxattr(dentry, name, value, size, flags);
+	lockdep_on();
+
+	return err;
+}
+
+static inline int vfsub_removexattr(struct dentry *dentry, const char *name)
+{
+	int err;
+
+	lockdep_off();
+	err = vfs_removexattr(dentry, name);
+	lockdep_on();
+
+	return err;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_VFSUB_H__ */
--- linux-4.4.0.orig/fs/aufs/wbr_policy.c
+++ linux-4.4.0/fs/aufs/wbr_policy.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * policies for selecting one among multiple writable branches
+ */
+
+#include <linux/statfs.h>
+#include "aufs.h"
+
+/* subset of cpup_attr() */
+static noinline_for_stack
+int au_cpdown_attr(struct path *h_path, struct dentry *h_src)
+{
+	int err, sbits;
+	struct iattr ia;
+	struct inode *h_isrc;
+
+	h_isrc = d_inode(h_src);
+	ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID;
+	ia.ia_mode = h_isrc->i_mode;
+	ia.ia_uid = h_isrc->i_uid;
+	ia.ia_gid = h_isrc->i_gid;
+	sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
+	au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags);
+	/* no delegation since it is just created */
+	err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL);
+
+	/* is this nfs only? */
+	if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) {
+		ia.ia_valid = ATTR_FORCE | ATTR_MODE;
+		ia.ia_mode = h_isrc->i_mode;
+		err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL);
+	}
+
+	return err;
+}
+
+#define AuCpdown_PARENT_OPQ	1
+#define AuCpdown_WHED		(1 << 1)
+#define AuCpdown_MADE_DIR	(1 << 2)
+#define AuCpdown_DIROPQ		(1 << 3)
+#define au_ftest_cpdown(flags, name)	((flags) & AuCpdown_##name)
+#define au_fset_cpdown(flags, name) \
+	do { (flags) |= AuCpdown_##name; } while (0)
+#define au_fclr_cpdown(flags, name) \
+	do { (flags) &= ~AuCpdown_##name; } while (0)
+
+static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst,
+			     unsigned int *flags)
+{
+	int err;
+	struct dentry *opq_dentry;
+
+	opq_dentry = au_diropq_create(dentry, bdst);
+	err = PTR_ERR(opq_dentry);
+	if (IS_ERR(opq_dentry))
+		goto out;
+	dput(opq_dentry);
+	au_fset_cpdown(*flags, DIROPQ);
+
+out:
+	return err;
+}
+
+static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent,
+			    struct inode *dir, aufs_bindex_t bdst)
+{
+	int err;
+	struct path h_path;
+	struct au_branch *br;
+
+	br = au_sbr(dentry->d_sb, bdst);
+	h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
+	err = PTR_ERR(h_path.dentry);
+	if (IS_ERR(h_path.dentry))
+		goto out;
+
+	err = 0;
+	if (d_is_positive(h_path.dentry)) {
+		h_path.mnt = au_br_mnt(br);
+		err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path,
+					  dentry);
+	}
+	dput(h_path.dentry);
+
+out:
+	return err;
+}
+
+static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst,
+			 struct au_pin *pin,
+			 struct dentry *h_parent, void *arg)
+{
+	int err, rerr;
+	aufs_bindex_t bopq, bstart;
+	struct path h_path;
+	struct dentry *parent;
+	struct inode *h_dir, *h_inode, *inode, *dir;
+	unsigned int *flags = arg;
+
+	bstart = au_dbstart(dentry);
+	/* dentry is di-locked */
+	parent = dget_parent(dentry);
+	dir = d_inode(parent);
+	h_dir = d_inode(h_parent);
+	AuDebugOn(h_dir != au_h_iptr(dir, bdst));
+	IMustLock(h_dir);
+
+	err = au_lkup_neg(dentry, bdst, /*wh*/0);
+	if (unlikely(err < 0))
+		goto out;
+	h_path.dentry = au_h_dptr(dentry, bdst);
+	h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst);
+	err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path,
+			      S_IRWXU | S_IRUGO | S_IXUGO);
+	if (unlikely(err))
+		goto out_put;
+	au_fset_cpdown(*flags, MADE_DIR);
+
+	bopq = au_dbdiropq(dentry);
+	au_fclr_cpdown(*flags, WHED);
+	au_fclr_cpdown(*flags, DIROPQ);
+	if (au_dbwh(dentry) == bdst)
+		au_fset_cpdown(*flags, WHED);
+	if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst)
+		au_fset_cpdown(*flags, PARENT_OPQ);
+	h_inode = d_inode(h_path.dentry);
+	mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
+	if (au_ftest_cpdown(*flags, WHED)) {
+		err = au_cpdown_dir_opq(dentry, bdst, flags);
+		if (unlikely(err)) {
+			mutex_unlock(&h_inode->i_mutex);
+			goto out_dir;
+		}
+	}
+
+	err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart));
+	mutex_unlock(&h_inode->i_mutex);
+	if (unlikely(err))
+		goto out_opq;
+
+	if (au_ftest_cpdown(*flags, WHED)) {
+		err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst);
+		if (unlikely(err))
+			goto out_opq;
+	}
+
+	inode = d_inode(dentry);
+	if (au_ibend(inode) < bdst)
+		au_set_ibend(inode, bdst);
+	au_set_h_iptr(inode, bdst, au_igrab(h_inode),
+		      au_hi_flags(inode, /*isdir*/1));
+	au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0);
+	goto out; /* success */
+
+	/* revert */
+out_opq:
+	if (au_ftest_cpdown(*flags, DIROPQ)) {
+		mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
+		rerr = au_diropq_remove(dentry, bdst);
+		mutex_unlock(&h_inode->i_mutex);
+		if (unlikely(rerr)) {
+			AuIOErr("failed removing diropq for %pd b%d (%d)\n",
+				dentry, bdst, rerr);
+			err = -EIO;
+			goto out;
+		}
+	}
+out_dir:
+	if (au_ftest_cpdown(*flags, MADE_DIR)) {
+		rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
+		if (unlikely(rerr)) {
+			AuIOErr("failed removing %pd b%d (%d)\n",
+				dentry, bdst, rerr);
+			err = -EIO;
+		}
+	}
+out_put:
+	au_set_h_dptr(dentry, bdst, NULL);
+	if (au_dbend(dentry) == bdst)
+		au_update_dbend(dentry);
+out:
+	dput(parent);
+	return err;
+}
+
+int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
+{
+	int err;
+	unsigned int flags;
+
+	flags = 0;
+	err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* policies for create */
+
+int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
+{
+	int err, i, j, ndentry;
+	aufs_bindex_t bopq;
+	struct au_dcsub_pages dpages;
+	struct au_dpage *dpage;
+	struct dentry **dentries, *parent, *d;
+
+	err = au_dpages_init(&dpages, GFP_NOFS);
+	if (unlikely(err))
+		goto out;
+	parent = dget_parent(dentry);
+	err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0);
+	if (unlikely(err))
+		goto out_free;
+
+	err = bindex;
+	for (i = 0; i < dpages.ndpage; i++) {
+		dpage = dpages.dpages + i;
+		dentries = dpage->dentries;
+		ndentry = dpage->ndentry;
+		for (j = 0; j < ndentry; j++) {
+			d = dentries[j];
+			di_read_lock_parent2(d, !AuLock_IR);
+			bopq = au_dbdiropq(d);
+			di_read_unlock(d, !AuLock_IR);
+			if (bopq >= 0 && bopq < err)
+				err = bopq;
+		}
+	}
+
+out_free:
+	dput(parent);
+	au_dpages_free(&dpages);
+out:
+	return err;
+}
+
+static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex)
+{
+	for (; bindex >= 0; bindex--)
+		if (!au_br_rdonly(au_sbr(sb, bindex)))
+			return bindex;
+	return -EROFS;
+}
+
+/* top down parent */
+static int au_wbr_create_tdp(struct dentry *dentry,
+			     unsigned int flags __maybe_unused)
+{
+	int err;
+	aufs_bindex_t bstart, bindex;
+	struct super_block *sb;
+	struct dentry *parent, *h_parent;
+
+	sb = dentry->d_sb;
+	bstart = au_dbstart(dentry);
+	err = bstart;
+	if (!au_br_rdonly(au_sbr(sb, bstart)))
+		goto out;
+
+	err = -EROFS;
+	parent = dget_parent(dentry);
+	for (bindex = au_dbstart(parent); bindex < bstart; bindex++) {
+		h_parent = au_h_dptr(parent, bindex);
+		if (!h_parent || d_is_negative(h_parent))
+			continue;
+
+		if (!au_br_rdonly(au_sbr(sb, bindex))) {
+			err = bindex;
+			break;
+		}
+	}
+	dput(parent);
+
+	/* bottom up here */
+	if (unlikely(err < 0)) {
+		err = au_wbr_bu(sb, bstart - 1);
+		if (err >= 0)
+			err = au_wbr_nonopq(dentry, err);
+	}
+
+out:
+	AuDbg("b%d\n", err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* an exception for the policy other than tdp */
+static int au_wbr_create_exp(struct dentry *dentry)
+{
+	int err;
+	aufs_bindex_t bwh, bdiropq;
+	struct dentry *parent;
+
+	err = -1;
+	bwh = au_dbwh(dentry);
+	parent = dget_parent(dentry);
+	bdiropq = au_dbdiropq(parent);
+	if (bwh >= 0) {
+		if (bdiropq >= 0)
+			err = min(bdiropq, bwh);
+		else
+			err = bwh;
+		AuDbg("%d\n", err);
+	} else if (bdiropq >= 0) {
+		err = bdiropq;
+		AuDbg("%d\n", err);
+	}
+	dput(parent);
+
+	if (err >= 0)
+		err = au_wbr_nonopq(dentry, err);
+
+	if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err)))
+		err = -1;
+
+	AuDbg("%d\n", err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* round robin */
+static int au_wbr_create_init_rr(struct super_block *sb)
+{
+	int err;
+
+	err = au_wbr_bu(sb, au_sbend(sb));
+	atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
+	/* smp_mb(); */
+
+	AuDbg("b%d\n", err);
+	return err;
+}
+
+static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags)
+{
+	int err, nbr;
+	unsigned int u;
+	aufs_bindex_t bindex, bend;
+	struct super_block *sb;
+	atomic_t *next;
+
+	err = au_wbr_create_exp(dentry);
+	if (err >= 0)
+		goto out;
+
+	sb = dentry->d_sb;
+	next = &au_sbi(sb)->si_wbr_rr_next;
+	bend = au_sbend(sb);
+	nbr = bend + 1;
+	for (bindex = 0; bindex <= bend; bindex++) {
+		if (!au_ftest_wbr(flags, DIR)) {
+			err = atomic_dec_return(next) + 1;
+			/* modulo for 0 is meaningless */
+			if (unlikely(!err))
+				err = atomic_dec_return(next) + 1;
+		} else
+			err = atomic_read(next);
+		AuDbg("%d\n", err);
+		u = err;
+		err = u % nbr;
+		AuDbg("%d\n", err);
+		if (!au_br_rdonly(au_sbr(sb, err)))
+			break;
+		err = -EROFS;
+	}
+
+	if (err >= 0)
+		err = au_wbr_nonopq(dentry, err);
+
+out:
+	AuDbg("%d\n", err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* most free space */
+static void au_mfs(struct dentry *dentry, struct dentry *parent)
+{
+	struct super_block *sb;
+	struct au_branch *br;
+	struct au_wbr_mfs *mfs;
+	struct dentry *h_parent;
+	aufs_bindex_t bindex, bend;
+	int err;
+	unsigned long long b, bavail;
+	struct path h_path;
+	/* reduce the stack usage */
+	struct kstatfs *st;
+
+	st = kmalloc(sizeof(*st), GFP_NOFS);
+	if (unlikely(!st)) {
+		AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
+		return;
+	}
+
+	bavail = 0;
+	sb = dentry->d_sb;
+	mfs = &au_sbi(sb)->si_wbr_mfs;
+	MtxMustLock(&mfs->mfs_lock);
+	mfs->mfs_bindex = -EROFS;
+	mfs->mfsrr_bytes = 0;
+	if (!parent) {
+		bindex = 0;
+		bend = au_sbend(sb);
+	} else {
+		bindex = au_dbstart(parent);
+		bend = au_dbtaildir(parent);
+	}
+
+	for (; bindex <= bend; bindex++) {
+		if (parent) {
+			h_parent = au_h_dptr(parent, bindex);
+			if (!h_parent || d_is_negative(h_parent))
+				continue;
+		}
+		br = au_sbr(sb, bindex);
+		if (au_br_rdonly(br))
+			continue;
+
+		/* sb->s_root for NFS is unreliable */
+		h_path.mnt = au_br_mnt(br);
+		h_path.dentry = h_path.mnt->mnt_root;
+		err = vfs_statfs(&h_path, st);
+		if (unlikely(err)) {
+			AuWarn1("failed statfs, b%d, %d\n", bindex, err);
+			continue;
+		}
+
+		/* when the available size is equal, select the lower one */
+		BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
+			     || sizeof(b) < sizeof(st->f_bsize));
+		b = st->f_bavail * st->f_bsize;
+		br->br_wbr->wbr_bytes = b;
+		if (b >= bavail) {
+			bavail = b;
+			mfs->mfs_bindex = bindex;
+			mfs->mfs_jiffy = jiffies;
+		}
+	}
+
+	mfs->mfsrr_bytes = bavail;
+	AuDbg("b%d\n", mfs->mfs_bindex);
+	kfree(st);
+}
+
+static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags)
+{
+	int err;
+	struct dentry *parent;
+	struct super_block *sb;
+	struct au_wbr_mfs *mfs;
+
+	err = au_wbr_create_exp(dentry);
+	if (err >= 0)
+		goto out;
+
+	sb = dentry->d_sb;
+	parent = NULL;
+	if (au_ftest_wbr(flags, PARENT))
+		parent = dget_parent(dentry);
+	mfs = &au_sbi(sb)->si_wbr_mfs;
+	mutex_lock(&mfs->mfs_lock);
+	if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
+	    || mfs->mfs_bindex < 0
+	    || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
+		au_mfs(dentry, parent);
+	mutex_unlock(&mfs->mfs_lock);
+	err = mfs->mfs_bindex;
+	dput(parent);
+
+	if (err >= 0)
+		err = au_wbr_nonopq(dentry, err);
+
+out:
+	AuDbg("b%d\n", err);
+	return err;
+}
+
+static int au_wbr_create_init_mfs(struct super_block *sb)
+{
+	struct au_wbr_mfs *mfs;
+
+	mfs = &au_sbi(sb)->si_wbr_mfs;
+	mutex_init(&mfs->mfs_lock);
+	mfs->mfs_jiffy = 0;
+	mfs->mfs_bindex = -EROFS;
+
+	return 0;
+}
+
+static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused)
+{
+	mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* most free space and then round robin */
+static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags)
+{
+	int err;
+	struct au_wbr_mfs *mfs;
+
+	err = au_wbr_create_mfs(dentry, flags);
+	if (err >= 0) {
+		mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs;
+		mutex_lock(&mfs->mfs_lock);
+		if (mfs->mfsrr_bytes < mfs->mfsrr_watermark)
+			err = au_wbr_create_rr(dentry, flags);
+		mutex_unlock(&mfs->mfs_lock);
+	}
+
+	AuDbg("b%d\n", err);
+	return err;
+}
+
+static int au_wbr_create_init_mfsrr(struct super_block *sb)
+{
+	int err;
+
+	au_wbr_create_init_mfs(sb); /* ignore */
+	err = au_wbr_create_init_rr(sb);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* top down parent and most free space */
+static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags)
+{
+	int err, e2;
+	unsigned long long b;
+	aufs_bindex_t bindex, bstart, bend;
+	struct super_block *sb;
+	struct dentry *parent, *h_parent;
+	struct au_branch *br;
+
+	err = au_wbr_create_tdp(dentry, flags);
+	if (unlikely(err < 0))
+		goto out;
+	parent = dget_parent(dentry);
+	bstart = au_dbstart(parent);
+	bend = au_dbtaildir(parent);
+	if (bstart == bend)
+		goto out_parent; /* success */
+
+	e2 = au_wbr_create_mfs(dentry, flags);
+	if (e2 < 0)
+		goto out_parent; /* success */
+
+	/* when the available size is equal, select upper one */
+	sb = dentry->d_sb;
+	br = au_sbr(sb, err);
+	b = br->br_wbr->wbr_bytes;
+	AuDbg("b%d, %llu\n", err, b);
+
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		h_parent = au_h_dptr(parent, bindex);
+		if (!h_parent || d_is_negative(h_parent))
+			continue;
+
+		br = au_sbr(sb, bindex);
+		if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) {
+			b = br->br_wbr->wbr_bytes;
+			err = bindex;
+			AuDbg("b%d, %llu\n", err, b);
+		}
+	}
+
+	if (err >= 0)
+		err = au_wbr_nonopq(dentry, err);
+
+out_parent:
+	dput(parent);
+out:
+	AuDbg("b%d\n", err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * - top down parent
+ * - most free space with parent
+ * - most free space round-robin regardless parent
+ */
+static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags)
+{
+	int err;
+	unsigned long long watermark;
+	struct super_block *sb;
+	struct au_branch *br;
+	struct au_wbr_mfs *mfs;
+
+	err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT);
+	if (unlikely(err < 0))
+		goto out;
+
+	sb = dentry->d_sb;
+	br = au_sbr(sb, err);
+	mfs = &au_sbi(sb)->si_wbr_mfs;
+	mutex_lock(&mfs->mfs_lock);
+	watermark = mfs->mfsrr_watermark;
+	mutex_unlock(&mfs->mfs_lock);
+	if (br->br_wbr->wbr_bytes < watermark)
+		/* regardless the parent dir */
+		err = au_wbr_create_mfsrr(dentry, flags);
+
+out:
+	AuDbg("b%d\n", err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* policies for copyup */
+
+/* top down parent */
+static int au_wbr_copyup_tdp(struct dentry *dentry)
+{
+	return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0);
+}
+
+/* bottom up parent */
+static int au_wbr_copyup_bup(struct dentry *dentry)
+{
+	int err;
+	aufs_bindex_t bindex, bstart;
+	struct dentry *parent, *h_parent;
+	struct super_block *sb;
+
+	err = -EROFS;
+	sb = dentry->d_sb;
+	parent = dget_parent(dentry);
+	bstart = au_dbstart(parent);
+	for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) {
+		h_parent = au_h_dptr(parent, bindex);
+		if (!h_parent || d_is_negative(h_parent))
+			continue;
+
+		if (!au_br_rdonly(au_sbr(sb, bindex))) {
+			err = bindex;
+			break;
+		}
+	}
+	dput(parent);
+
+	/* bottom up here */
+	if (unlikely(err < 0))
+		err = au_wbr_bu(sb, bstart - 1);
+
+	AuDbg("b%d\n", err);
+	return err;
+}
+
+/* bottom up */
+int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t bstart)
+{
+	int err;
+
+	err = au_wbr_bu(dentry->d_sb, bstart);
+	AuDbg("b%d\n", err);
+	if (err > bstart)
+		err = au_wbr_nonopq(dentry, err);
+
+	AuDbg("b%d\n", err);
+	return err;
+}
+
+static int au_wbr_copyup_bu(struct dentry *dentry)
+{
+	int err;
+	aufs_bindex_t bstart;
+
+	bstart = au_dbstart(dentry);
+	err = au_wbr_do_copyup_bu(dentry, bstart);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct au_wbr_copyup_operations au_wbr_copyup_ops[] = {
+	[AuWbrCopyup_TDP] = {
+		.copyup	= au_wbr_copyup_tdp
+	},
+	[AuWbrCopyup_BUP] = {
+		.copyup	= au_wbr_copyup_bup
+	},
+	[AuWbrCopyup_BU] = {
+		.copyup	= au_wbr_copyup_bu
+	}
+};
+
+struct au_wbr_create_operations au_wbr_create_ops[] = {
+	[AuWbrCreate_TDP] = {
+		.create	= au_wbr_create_tdp
+	},
+	[AuWbrCreate_RR] = {
+		.create	= au_wbr_create_rr,
+		.init	= au_wbr_create_init_rr
+	},
+	[AuWbrCreate_MFS] = {
+		.create	= au_wbr_create_mfs,
+		.init	= au_wbr_create_init_mfs,
+		.fin	= au_wbr_create_fin_mfs
+	},
+	[AuWbrCreate_MFSV] = {
+		.create	= au_wbr_create_mfs,
+		.init	= au_wbr_create_init_mfs,
+		.fin	= au_wbr_create_fin_mfs
+	},
+	[AuWbrCreate_MFSRR] = {
+		.create	= au_wbr_create_mfsrr,
+		.init	= au_wbr_create_init_mfsrr,
+		.fin	= au_wbr_create_fin_mfs
+	},
+	[AuWbrCreate_MFSRRV] = {
+		.create	= au_wbr_create_mfsrr,
+		.init	= au_wbr_create_init_mfsrr,
+		.fin	= au_wbr_create_fin_mfs
+	},
+	[AuWbrCreate_PMFS] = {
+		.create	= au_wbr_create_pmfs,
+		.init	= au_wbr_create_init_mfs,
+		.fin	= au_wbr_create_fin_mfs
+	},
+	[AuWbrCreate_PMFSV] = {
+		.create	= au_wbr_create_pmfs,
+		.init	= au_wbr_create_init_mfs,
+		.fin	= au_wbr_create_fin_mfs
+	},
+	[AuWbrCreate_PMFSRR] = {
+		.create	= au_wbr_create_pmfsrr,
+		.init	= au_wbr_create_init_mfsrr,
+		.fin	= au_wbr_create_fin_mfs
+	},
+	[AuWbrCreate_PMFSRRV] = {
+		.create	= au_wbr_create_pmfsrr,
+		.init	= au_wbr_create_init_mfsrr,
+		.fin	= au_wbr_create_fin_mfs
+	}
+};
--- linux-4.4.0.orig/fs/aufs/whout.c
+++ linux-4.4.0/fs/aufs/whout.c
@@ -0,0 +1,1060 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * whiteout for logical deletion and opaque directory
+ */
+
+#include "aufs.h"
+
+#define WH_MASK			S_IRUGO
+
+/*
+ * If a directory contains this file, then it is opaque.  We start with the
+ * .wh. flag so that it is blocked by lookup.
+ */
+static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ,
+					   sizeof(AUFS_WH_DIROPQ) - 1);
+
+/*
+ * generate whiteout name, which is NOT terminated by NULL.
+ * @name: original d_name.name
+ * @len: original d_name.len
+ * @wh: whiteout qstr
+ * returns zero when succeeds, otherwise error.
+ * succeeded value as wh->name should be freed by kfree().
+ */
+int au_wh_name_alloc(struct qstr *wh, const struct qstr *name)
+{
+	char *p;
+
+	if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN))
+		return -ENAMETOOLONG;
+
+	wh->len = name->len + AUFS_WH_PFX_LEN;
+	p = kmalloc(wh->len, GFP_NOFS);
+	wh->name = p;
+	if (p) {
+		memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
+		memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len);
+		/* smp_mb(); */
+		return 0;
+	}
+	return -ENOMEM;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * test if the @wh_name exists under @h_parent.
+ * @try_sio specifies the necessary of super-io.
+ */
+int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio)
+{
+	int err;
+	struct dentry *wh_dentry;
+
+	if (!try_sio)
+		wh_dentry = vfsub_lkup_one(wh_name, h_parent);
+	else
+		wh_dentry = au_sio_lkup_one(wh_name, h_parent);
+	err = PTR_ERR(wh_dentry);
+	if (IS_ERR(wh_dentry)) {
+		if (err == -ENAMETOOLONG)
+			err = 0;
+		goto out;
+	}
+
+	err = 0;
+	if (d_is_negative(wh_dentry))
+		goto out_wh; /* success */
+
+	err = 1;
+	if (d_is_reg(wh_dentry))
+		goto out_wh; /* success */
+
+	err = -EIO;
+	AuIOErr("%pd Invalid whiteout entry type 0%o.\n",
+		wh_dentry, d_inode(wh_dentry)->i_mode);
+
+out_wh:
+	dput(wh_dentry);
+out:
+	return err;
+}
+
+/*
+ * test if the @h_dentry sets opaque or not.
+ */
+int au_diropq_test(struct dentry *h_dentry)
+{
+	int err;
+	struct inode *h_dir;
+
+	h_dir = d_inode(h_dentry);
+	err = au_wh_test(h_dentry, &diropq_name,
+			 au_test_h_perm_sio(h_dir, MAY_EXEC));
+	return err;
+}
+
+/*
+ * returns a negative dentry whose name is unique and temporary.
+ */
+struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
+			     struct qstr *prefix)
+{
+	struct dentry *dentry;
+	int i;
+	char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1],
+		*name, *p;
+	/* strict atomic_t is unnecessary here */
+	static unsigned short cnt;
+	struct qstr qs;
+
+	BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN);
+
+	name = defname;
+	qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1;
+	if (unlikely(prefix->len > DNAME_INLINE_LEN)) {
+		dentry = ERR_PTR(-ENAMETOOLONG);
+		if (unlikely(qs.len > NAME_MAX))
+			goto out;
+		dentry = ERR_PTR(-ENOMEM);
+		name = kmalloc(qs.len + 1, GFP_NOFS);
+		if (unlikely(!name))
+			goto out;
+	}
+
+	/* doubly whiteout-ed */
+	memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2);
+	p = name + AUFS_WH_PFX_LEN * 2;
+	memcpy(p, prefix->name, prefix->len);
+	p += prefix->len;
+	*p++ = '.';
+	AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN);
+
+	qs.name = name;
+	for (i = 0; i < 3; i++) {
+		sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++);
+		dentry = au_sio_lkup_one(&qs, h_parent);
+		if (IS_ERR(dentry) || d_is_negative(dentry))
+			goto out_name;
+		dput(dentry);
+	}
+	/* pr_warn("could not get random name\n"); */
+	dentry = ERR_PTR(-EEXIST);
+	AuDbg("%.*s\n", AuLNPair(&qs));
+	BUG();
+
+out_name:
+	if (name != defname)
+		kfree(name);
+out:
+	AuTraceErrPtr(dentry);
+	return dentry;
+}
+
+/*
+ * rename the @h_dentry on @br to the whiteouted temporary name.
+ */
+int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br)
+{
+	int err;
+	struct path h_path = {
+		.mnt = au_br_mnt(br)
+	};
+	struct inode *h_dir, *delegated;
+	struct dentry *h_parent;
+
+	h_parent = h_dentry->d_parent; /* dir inode is locked */
+	h_dir = d_inode(h_parent);
+	IMustLock(h_dir);
+
+	h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name);
+	err = PTR_ERR(h_path.dentry);
+	if (IS_ERR(h_path.dentry))
+		goto out;
+
+	/* under the same dir, no need to lock_rename() */
+	delegated = NULL;
+	err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated);
+	AuTraceErr(err);
+	if (unlikely(err == -EWOULDBLOCK)) {
+		pr_warn("cannot retry for NFSv4 delegation"
+			" for an internal rename\n");
+		iput(delegated);
+	}
+	dput(h_path.dentry);
+
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * functions for removing a whiteout
+ */
+
+static int do_unlink_wh(struct inode *h_dir, struct path *h_path)
+{
+	int err, force;
+	struct inode *delegated;
+
+	/*
+	 * forces superio when the dir has a sticky bit.
+	 * this may be a violation of unix fs semantics.
+	 */
+	force = (h_dir->i_mode & S_ISVTX)
+		&& !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid);
+	delegated = NULL;
+	err = vfsub_unlink(h_dir, h_path, &delegated, force);
+	if (unlikely(err == -EWOULDBLOCK)) {
+		pr_warn("cannot retry for NFSv4 delegation"
+			" for an internal unlink\n");
+		iput(delegated);
+	}
+	return err;
+}
+
+int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path,
+			struct dentry *dentry)
+{
+	int err;
+
+	err = do_unlink_wh(h_dir, h_path);
+	if (!err && dentry)
+		au_set_dbwh(dentry, -1);
+
+	return err;
+}
+
+static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh,
+			  struct au_branch *br)
+{
+	int err;
+	struct path h_path = {
+		.mnt = au_br_mnt(br)
+	};
+
+	err = 0;
+	h_path.dentry = vfsub_lkup_one(wh, h_parent);
+	if (IS_ERR(h_path.dentry))
+		err = PTR_ERR(h_path.dentry);
+	else {
+		if (d_is_reg(h_path.dentry))
+			err = do_unlink_wh(d_inode(h_parent), &h_path);
+		dput(h_path.dentry);
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * initialize/clean whiteout for a branch
+ */
+
+static void au_wh_clean(struct inode *h_dir, struct path *whpath,
+			const int isdir)
+{
+	int err;
+	struct inode *delegated;
+
+	if (d_is_negative(whpath->dentry))
+		return;
+
+	if (isdir)
+		err = vfsub_rmdir(h_dir, whpath);
+	else {
+		delegated = NULL;
+		err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0);
+		if (unlikely(err == -EWOULDBLOCK)) {
+			pr_warn("cannot retry for NFSv4 delegation"
+				" for an internal unlink\n");
+			iput(delegated);
+		}
+	}
+	if (unlikely(err))
+		pr_warn("failed removing %pd (%d), ignored.\n",
+			whpath->dentry, err);
+}
+
+static int test_linkable(struct dentry *h_root)
+{
+	struct inode *h_dir = d_inode(h_root);
+
+	if (h_dir->i_op->link)
+		return 0;
+
+	pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n",
+	       h_root, au_sbtype(h_root->d_sb));
+	return -ENOSYS;
+}
+
+/* todo: should this mkdir be done in /sbin/mount.aufs helper? */
+static int au_whdir(struct inode *h_dir, struct path *path)
+{
+	int err;
+
+	err = -EEXIST;
+	if (d_is_negative(path->dentry)) {
+		int mode = S_IRWXU;
+
+		if (au_test_nfs(path->dentry->d_sb))
+			mode |= S_IXUGO;
+		err = vfsub_mkdir(h_dir, path, mode);
+	} else if (d_is_dir(path->dentry))
+		err = 0;
+	else
+		pr_err("unknown %pd exists\n", path->dentry);
+
+	return err;
+}
+
+struct au_wh_base {
+	const struct qstr *name;
+	struct dentry *dentry;
+};
+
+static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[],
+			  struct path *h_path)
+{
+	h_path->dentry = base[AuBrWh_BASE].dentry;
+	au_wh_clean(h_dir, h_path, /*isdir*/0);
+	h_path->dentry = base[AuBrWh_PLINK].dentry;
+	au_wh_clean(h_dir, h_path, /*isdir*/1);
+	h_path->dentry = base[AuBrWh_ORPH].dentry;
+	au_wh_clean(h_dir, h_path, /*isdir*/1);
+}
+
+/*
+ * returns tri-state,
+ * minus: error, caller should print the message
+ * zero: succuess
+ * plus: error, caller should NOT print the message
+ */
+static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr,
+				int do_plink, struct au_wh_base base[],
+				struct path *h_path)
+{
+	int err;
+	struct inode *h_dir;
+
+	h_dir = d_inode(h_root);
+	h_path->dentry = base[AuBrWh_BASE].dentry;
+	au_wh_clean(h_dir, h_path, /*isdir*/0);
+	h_path->dentry = base[AuBrWh_PLINK].dentry;
+	if (do_plink) {
+		err = test_linkable(h_root);
+		if (unlikely(err)) {
+			err = 1;
+			goto out;
+		}
+
+		err = au_whdir(h_dir, h_path);
+		if (unlikely(err))
+			goto out;
+		wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry);
+	} else
+		au_wh_clean(h_dir, h_path, /*isdir*/1);
+	h_path->dentry = base[AuBrWh_ORPH].dentry;
+	err = au_whdir(h_dir, h_path);
+	if (unlikely(err))
+		goto out;
+	wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
+
+out:
+	return err;
+}
+
+/*
+ * for the moment, aufs supports the branch filesystem which does not support
+ * link(2). testing on FAT which does not support i_op->setattr() fully either,
+ * copyup failed. finally, such filesystem will not be used as the writable
+ * branch.
+ *
+ * returns tri-state, see above.
+ */
+static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr,
+			 int do_plink, struct au_wh_base base[],
+			 struct path *h_path)
+{
+	int err;
+	struct inode *h_dir;
+
+	WbrWhMustWriteLock(wbr);
+
+	err = test_linkable(h_root);
+	if (unlikely(err)) {
+		err = 1;
+		goto out;
+	}
+
+	/*
+	 * todo: should this create be done in /sbin/mount.aufs helper?
+	 */
+	err = -EEXIST;
+	h_dir = d_inode(h_root);
+	if (d_is_negative(base[AuBrWh_BASE].dentry)) {
+		h_path->dentry = base[AuBrWh_BASE].dentry;
+		err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true);
+	} else if (d_is_reg(base[AuBrWh_BASE].dentry))
+		err = 0;
+	else
+		pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry);
+	if (unlikely(err))
+		goto out;
+
+	h_path->dentry = base[AuBrWh_PLINK].dentry;
+	if (do_plink) {
+		err = au_whdir(h_dir, h_path);
+		if (unlikely(err))
+			goto out;
+		wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry);
+	} else
+		au_wh_clean(h_dir, h_path, /*isdir*/1);
+	wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry);
+
+	h_path->dentry = base[AuBrWh_ORPH].dentry;
+	err = au_whdir(h_dir, h_path);
+	if (unlikely(err))
+		goto out;
+	wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
+
+out:
+	return err;
+}
+
+/*
+ * initialize the whiteout base file/dir for @br.
+ */
+int au_wh_init(struct au_branch *br, struct super_block *sb)
+{
+	int err, i;
+	const unsigned char do_plink
+		= !!au_opt_test(au_mntflags(sb), PLINK);
+	struct inode *h_dir;
+	struct path path = br->br_path;
+	struct dentry *h_root = path.dentry;
+	struct au_wbr *wbr = br->br_wbr;
+	static const struct qstr base_name[] = {
+		[AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME,
+					  sizeof(AUFS_BASE_NAME) - 1),
+		[AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME,
+					   sizeof(AUFS_PLINKDIR_NAME) - 1),
+		[AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME,
+					  sizeof(AUFS_ORPHDIR_NAME) - 1)
+	};
+	struct au_wh_base base[] = {
+		[AuBrWh_BASE] = {
+			.name	= base_name + AuBrWh_BASE,
+			.dentry	= NULL
+		},
+		[AuBrWh_PLINK] = {
+			.name	= base_name + AuBrWh_PLINK,
+			.dentry	= NULL
+		},
+		[AuBrWh_ORPH] = {
+			.name	= base_name + AuBrWh_ORPH,
+			.dentry	= NULL
+		}
+	};
+
+	if (wbr)
+		WbrWhMustWriteLock(wbr);
+
+	for (i = 0; i < AuBrWh_Last; i++) {
+		/* doubly whiteouted */
+		struct dentry *d;
+
+		d = au_wh_lkup(h_root, (void *)base[i].name, br);
+		err = PTR_ERR(d);
+		if (IS_ERR(d))
+			goto out;
+
+		base[i].dentry = d;
+		AuDebugOn(wbr
+			  && wbr->wbr_wh[i]
+			  && wbr->wbr_wh[i] != base[i].dentry);
+	}
+
+	if (wbr)
+		for (i = 0; i < AuBrWh_Last; i++) {
+			dput(wbr->wbr_wh[i]);
+			wbr->wbr_wh[i] = NULL;
+		}
+
+	err = 0;
+	if (!au_br_writable(br->br_perm)) {
+		h_dir = d_inode(h_root);
+		au_wh_init_ro(h_dir, base, &path);
+	} else if (!au_br_wh_linkable(br->br_perm)) {
+		err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path);
+		if (err > 0)
+			goto out;
+		else if (err)
+			goto out_err;
+	} else {
+		err = au_wh_init_rw(h_root, wbr, do_plink, base, &path);
+		if (err > 0)
+			goto out;
+		else if (err)
+			goto out_err;
+	}
+	goto out; /* success */
+
+out_err:
+	pr_err("an error(%d) on the writable branch %pd(%s)\n",
+	       err, h_root, au_sbtype(h_root->d_sb));
+out:
+	for (i = 0; i < AuBrWh_Last; i++)
+		dput(base[i].dentry);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * whiteouts are all hard-linked usually.
+ * when its link count reaches a ceiling, we create a new whiteout base
+ * asynchronously.
+ */
+
+struct reinit_br_wh {
+	struct super_block *sb;
+	struct au_branch *br;
+};
+
+static void reinit_br_wh(void *arg)
+{
+	int err;
+	aufs_bindex_t bindex;
+	struct path h_path;
+	struct reinit_br_wh *a = arg;
+	struct au_wbr *wbr;
+	struct inode *dir, *delegated;
+	struct dentry *h_root;
+	struct au_hinode *hdir;
+
+	err = 0;
+	wbr = a->br->br_wbr;
+	/* big aufs lock */
+	si_noflush_write_lock(a->sb);
+	if (!au_br_writable(a->br->br_perm))
+		goto out;
+	bindex = au_br_index(a->sb, a->br->br_id);
+	if (unlikely(bindex < 0))
+		goto out;
+
+	di_read_lock_parent(a->sb->s_root, AuLock_IR);
+	dir = d_inode(a->sb->s_root);
+	hdir = au_hi(dir, bindex);
+	h_root = au_h_dptr(a->sb->s_root, bindex);
+	AuDebugOn(h_root != au_br_dentry(a->br));
+
+	au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+	wbr_wh_write_lock(wbr);
+	err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode,
+			  h_root, a->br);
+	if (!err) {
+		h_path.dentry = wbr->wbr_whbase;
+		h_path.mnt = au_br_mnt(a->br);
+		delegated = NULL;
+		err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated,
+				   /*force*/0);
+		if (unlikely(err == -EWOULDBLOCK)) {
+			pr_warn("cannot retry for NFSv4 delegation"
+				" for an internal unlink\n");
+			iput(delegated);
+		}
+	} else {
+		pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase);
+		err = 0;
+	}
+	dput(wbr->wbr_whbase);
+	wbr->wbr_whbase = NULL;
+	if (!err)
+		err = au_wh_init(a->br, a->sb);
+	wbr_wh_write_unlock(wbr);
+	au_hn_imtx_unlock(hdir);
+	di_read_unlock(a->sb->s_root, AuLock_IR);
+	if (!err)
+		au_fhsm_wrote(a->sb, bindex, /*force*/0);
+
+out:
+	if (wbr)
+		atomic_dec(&wbr->wbr_wh_running);
+	atomic_dec(&a->br->br_count);
+	si_write_unlock(a->sb);
+	au_nwt_done(&au_sbi(a->sb)->si_nowait);
+	kfree(arg);
+	if (unlikely(err))
+		AuIOErr("err %d\n", err);
+}
+
+static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br)
+{
+	int do_dec, wkq_err;
+	struct reinit_br_wh *arg;
+
+	do_dec = 1;
+	if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1)
+		goto out;
+
+	/* ignore ENOMEM */
+	arg = kmalloc(sizeof(*arg), GFP_NOFS);
+	if (arg) {
+		/*
+		 * dec(wh_running), kfree(arg) and dec(br_count)
+		 * in reinit function
+		 */
+		arg->sb = sb;
+		arg->br = br;
+		atomic_inc(&br->br_count);
+		wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0);
+		if (unlikely(wkq_err)) {
+			atomic_dec(&br->br_wbr->wbr_wh_running);
+			atomic_dec(&br->br_count);
+			kfree(arg);
+		}
+		do_dec = 0;
+	}
+
+out:
+	if (do_dec)
+		atomic_dec(&br->br_wbr->wbr_wh_running);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * create the whiteout @wh.
+ */
+static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex,
+			     struct dentry *wh)
+{
+	int err;
+	struct path h_path = {
+		.dentry = wh
+	};
+	struct au_branch *br;
+	struct au_wbr *wbr;
+	struct dentry *h_parent;
+	struct inode *h_dir, *delegated;
+
+	h_parent = wh->d_parent; /* dir inode is locked */
+	h_dir = d_inode(h_parent);
+	IMustLock(h_dir);
+
+	br = au_sbr(sb, bindex);
+	h_path.mnt = au_br_mnt(br);
+	wbr = br->br_wbr;
+	wbr_wh_read_lock(wbr);
+	if (wbr->wbr_whbase) {
+		delegated = NULL;
+		err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated);
+		if (unlikely(err == -EWOULDBLOCK)) {
+			pr_warn("cannot retry for NFSv4 delegation"
+				" for an internal link\n");
+			iput(delegated);
+		}
+		if (!err || err != -EMLINK)
+			goto out;
+
+		/* link count full. re-initialize br_whbase. */
+		kick_reinit_br_wh(sb, br);
+	}
+
+	/* return this error in this context */
+	err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true);
+	if (!err)
+		au_fhsm_wrote(sb, bindex, /*force*/0);
+
+out:
+	wbr_wh_read_unlock(wbr);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * create or remove the diropq.
+ */
+static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex,
+				unsigned int flags)
+{
+	struct dentry *opq_dentry, *h_dentry;
+	struct super_block *sb;
+	struct au_branch *br;
+	int err;
+
+	sb = dentry->d_sb;
+	br = au_sbr(sb, bindex);
+	h_dentry = au_h_dptr(dentry, bindex);
+	opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry);
+	if (IS_ERR(opq_dentry))
+		goto out;
+
+	if (au_ftest_diropq(flags, CREATE)) {
+		err = link_or_create_wh(sb, bindex, opq_dentry);
+		if (!err) {
+			au_set_dbdiropq(dentry, bindex);
+			goto out; /* success */
+		}
+	} else {
+		struct path tmp = {
+			.dentry = opq_dentry,
+			.mnt	= au_br_mnt(br)
+		};
+		err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &tmp);
+		if (!err)
+			au_set_dbdiropq(dentry, -1);
+	}
+	dput(opq_dentry);
+	opq_dentry = ERR_PTR(err);
+
+out:
+	return opq_dentry;
+}
+
+struct do_diropq_args {
+	struct dentry **errp;
+	struct dentry *dentry;
+	aufs_bindex_t bindex;
+	unsigned int flags;
+};
+
+static void call_do_diropq(void *args)
+{
+	struct do_diropq_args *a = args;
+	*a->errp = do_diropq(a->dentry, a->bindex, a->flags);
+}
+
+struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
+			     unsigned int flags)
+{
+	struct dentry *diropq, *h_dentry;
+
+	h_dentry = au_h_dptr(dentry, bindex);
+	if (!au_test_h_perm_sio(d_inode(h_dentry), MAY_EXEC | MAY_WRITE))
+		diropq = do_diropq(dentry, bindex, flags);
+	else {
+		int wkq_err;
+		struct do_diropq_args args = {
+			.errp		= &diropq,
+			.dentry		= dentry,
+			.bindex		= bindex,
+			.flags		= flags
+		};
+
+		wkq_err = au_wkq_wait(call_do_diropq, &args);
+		if (unlikely(wkq_err))
+			diropq = ERR_PTR(wkq_err);
+	}
+
+	return diropq;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * lookup whiteout dentry.
+ * @h_parent: lower parent dentry which must exist and be locked
+ * @base_name: name of dentry which will be whiteouted
+ * returns dentry for whiteout.
+ */
+struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
+			  struct au_branch *br)
+{
+	int err;
+	struct qstr wh_name;
+	struct dentry *wh_dentry;
+
+	err = au_wh_name_alloc(&wh_name, base_name);
+	wh_dentry = ERR_PTR(err);
+	if (!err) {
+		wh_dentry = vfsub_lkup_one(&wh_name, h_parent);
+		kfree(wh_name.name);
+	}
+	return wh_dentry;
+}
+
+/*
+ * link/create a whiteout for @dentry on @bindex.
+ */
+struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
+			    struct dentry *h_parent)
+{
+	struct dentry *wh_dentry;
+	struct super_block *sb;
+	int err;
+
+	sb = dentry->d_sb;
+	wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex));
+	if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) {
+		err = link_or_create_wh(sb, bindex, wh_dentry);
+		if (!err) {
+			au_set_dbwh(dentry, bindex);
+			au_fhsm_wrote(sb, bindex, /*force*/0);
+		} else {
+			dput(wh_dentry);
+			wh_dentry = ERR_PTR(err);
+		}
+	}
+
+	return wh_dentry;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* Delete all whiteouts in this directory on branch bindex. */
+static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist,
+			   aufs_bindex_t bindex, struct au_branch *br)
+{
+	int err;
+	unsigned long ul, n;
+	struct qstr wh_name;
+	char *p;
+	struct hlist_head *head;
+	struct au_vdir_wh *pos;
+	struct au_vdir_destr *str;
+
+	err = -ENOMEM;
+	p = (void *)__get_free_page(GFP_NOFS);
+	wh_name.name = p;
+	if (unlikely(!wh_name.name))
+		goto out;
+
+	err = 0;
+	memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
+	p += AUFS_WH_PFX_LEN;
+	n = whlist->nh_num;
+	head = whlist->nh_head;
+	for (ul = 0; !err && ul < n; ul++, head++) {
+		hlist_for_each_entry(pos, head, wh_hash) {
+			if (pos->wh_bindex != bindex)
+				continue;
+
+			str = &pos->wh_str;
+			if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) {
+				memcpy(p, str->name, str->len);
+				wh_name.len = AUFS_WH_PFX_LEN + str->len;
+				err = unlink_wh_name(h_dentry, &wh_name, br);
+				if (!err)
+					continue;
+				break;
+			}
+			AuIOErr("whiteout name too long %.*s\n",
+				str->len, str->name);
+			err = -EIO;
+			break;
+		}
+	}
+	free_page((unsigned long)wh_name.name);
+
+out:
+	return err;
+}
+
+struct del_wh_children_args {
+	int *errp;
+	struct dentry *h_dentry;
+	struct au_nhash *whlist;
+	aufs_bindex_t bindex;
+	struct au_branch *br;
+};
+
+static void call_del_wh_children(void *args)
+{
+	struct del_wh_children_args *a = args;
+	*a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp)
+{
+	struct au_whtmp_rmdir *whtmp;
+	int err;
+	unsigned int rdhash;
+
+	SiMustAnyLock(sb);
+
+	whtmp = kzalloc(sizeof(*whtmp), gfp);
+	if (unlikely(!whtmp)) {
+		whtmp = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	/* no estimation for dir size */
+	rdhash = au_sbi(sb)->si_rdhash;
+	if (!rdhash)
+		rdhash = AUFS_RDHASH_DEF;
+	err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp);
+	if (unlikely(err)) {
+		kfree(whtmp);
+		whtmp = ERR_PTR(err);
+	}
+
+out:
+	return whtmp;
+}
+
+void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp)
+{
+	if (whtmp->br)
+		atomic_dec(&whtmp->br->br_count);
+	dput(whtmp->wh_dentry);
+	iput(whtmp->dir);
+	au_nhash_wh_free(&whtmp->whlist);
+	kfree(whtmp);
+}
+
+/*
+ * rmdir the whiteouted temporary named dir @h_dentry.
+ * @whlist: whiteouted children.
+ */
+int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
+		   struct dentry *wh_dentry, struct au_nhash *whlist)
+{
+	int err;
+	unsigned int h_nlink;
+	struct path h_tmp;
+	struct inode *wh_inode, *h_dir;
+	struct au_branch *br;
+
+	h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */
+	IMustLock(h_dir);
+
+	br = au_sbr(dir->i_sb, bindex);
+	wh_inode = d_inode(wh_dentry);
+	mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD);
+
+	/*
+	 * someone else might change some whiteouts while we were sleeping.
+	 * it means this whlist may have an obsoleted entry.
+	 */
+	if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE))
+		err = del_wh_children(wh_dentry, whlist, bindex, br);
+	else {
+		int wkq_err;
+		struct del_wh_children_args args = {
+			.errp		= &err,
+			.h_dentry	= wh_dentry,
+			.whlist		= whlist,
+			.bindex		= bindex,
+			.br		= br
+		};
+
+		wkq_err = au_wkq_wait(call_del_wh_children, &args);
+		if (unlikely(wkq_err))
+			err = wkq_err;
+	}
+	mutex_unlock(&wh_inode->i_mutex);
+
+	if (!err) {
+		h_tmp.dentry = wh_dentry;
+		h_tmp.mnt = au_br_mnt(br);
+		h_nlink = h_dir->i_nlink;
+		err = vfsub_rmdir(h_dir, &h_tmp);
+		/* some fs doesn't change the parent nlink in some cases */
+		h_nlink -= h_dir->i_nlink;
+	}
+
+	if (!err) {
+		if (au_ibstart(dir) == bindex) {
+			/* todo: dir->i_mutex is necessary */
+			au_cpup_attr_timesizes(dir);
+			if (h_nlink)
+				vfsub_drop_nlink(dir);
+		}
+		return 0; /* success */
+	}
+
+	pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err);
+	return err;
+}
+
+static void call_rmdir_whtmp(void *args)
+{
+	int err;
+	aufs_bindex_t bindex;
+	struct au_whtmp_rmdir *a = args;
+	struct super_block *sb;
+	struct dentry *h_parent;
+	struct inode *h_dir;
+	struct au_hinode *hdir;
+
+	/* rmdir by nfsd may cause deadlock with this i_mutex */
+	/* mutex_lock(&a->dir->i_mutex); */
+	err = -EROFS;
+	sb = a->dir->i_sb;
+	si_read_lock(sb, !AuLock_FLUSH);
+	if (!au_br_writable(a->br->br_perm))
+		goto out;
+	bindex = au_br_index(sb, a->br->br_id);
+	if (unlikely(bindex < 0))
+		goto out;
+
+	err = -EIO;
+	ii_write_lock_parent(a->dir);
+	h_parent = dget_parent(a->wh_dentry);
+	h_dir = d_inode(h_parent);
+	hdir = au_hi(a->dir, bindex);
+	err = vfsub_mnt_want_write(au_br_mnt(a->br));
+	if (unlikely(err))
+		goto out_mnt;
+	au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+	err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent,
+			  a->br);
+	if (!err)
+		err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist);
+	au_hn_imtx_unlock(hdir);
+	vfsub_mnt_drop_write(au_br_mnt(a->br));
+
+out_mnt:
+	dput(h_parent);
+	ii_write_unlock(a->dir);
+out:
+	/* mutex_unlock(&a->dir->i_mutex); */
+	au_whtmp_rmdir_free(a);
+	si_read_unlock(sb);
+	au_nwt_done(&au_sbi(sb)->si_nowait);
+	if (unlikely(err))
+		AuIOErr("err %d\n", err);
+}
+
+void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
+			 struct dentry *wh_dentry, struct au_whtmp_rmdir *args)
+{
+	int wkq_err;
+	struct super_block *sb;
+
+	IMustLock(dir);
+
+	/* all post-process will be done in do_rmdir_whtmp(). */
+	sb = dir->i_sb;
+	args->dir = au_igrab(dir);
+	args->br = au_sbr(sb, bindex);
+	atomic_inc(&args->br->br_count);
+	args->wh_dentry = dget(wh_dentry);
+	wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0);
+	if (unlikely(wkq_err)) {
+		pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err);
+		au_whtmp_rmdir_free(args);
+	}
+}
--- linux-4.4.0.orig/fs/aufs/whout.h
+++ linux-4.4.0/fs/aufs/whout.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * whiteout for logical deletion and opaque directory
+ */
+
+#ifndef __AUFS_WHOUT_H__
+#define __AUFS_WHOUT_H__
+
+#ifdef __KERNEL__
+
+#include "dir.h"
+
+/* whout.c */
+int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
+int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio);
+int au_diropq_test(struct dentry *h_dentry);
+struct au_branch;
+struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
+			     struct qstr *prefix);
+int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br);
+int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path,
+			struct dentry *dentry);
+int au_wh_init(struct au_branch *br, struct super_block *sb);
+
+/* diropq flags */
+#define AuDiropq_CREATE	1
+#define au_ftest_diropq(flags, name)	((flags) & AuDiropq_##name)
+#define au_fset_diropq(flags, name) \
+	do { (flags) |= AuDiropq_##name; } while (0)
+#define au_fclr_diropq(flags, name) \
+	do { (flags) &= ~AuDiropq_##name; } while (0)
+
+struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
+			     unsigned int flags);
+struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
+			  struct au_branch *br);
+struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
+			    struct dentry *h_parent);
+
+/* real rmdir for the whiteout-ed dir */
+struct au_whtmp_rmdir {
+	struct inode *dir;
+	struct au_branch *br;
+	struct dentry *wh_dentry;
+	struct au_nhash whlist;
+};
+
+struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp);
+void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp);
+int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
+		   struct dentry *wh_dentry, struct au_nhash *whlist);
+void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
+			 struct dentry *wh_dentry, struct au_whtmp_rmdir *args);
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct dentry *au_diropq_create(struct dentry *dentry,
+					      aufs_bindex_t bindex)
+{
+	return au_diropq_sio(dentry, bindex, AuDiropq_CREATE);
+}
+
+static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex)
+{
+	return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE));
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_WHOUT_H__ */
--- linux-4.4.0.orig/fs/aufs/wkq.c
+++ linux-4.4.0/fs/aufs/wkq.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * workqueue for asynchronous/super-io operations
+ * todo: try new dredential scheme
+ */
+
+#include <linux/module.h>
+#include "aufs.h"
+
+/* internal workqueue named AUFS_WKQ_NAME */
+
+static struct workqueue_struct *au_wkq;
+
+struct au_wkinfo {
+	struct work_struct wk;
+	struct kobject *kobj;
+
+	unsigned int flags; /* see wkq.h */
+
+	au_wkq_func_t func;
+	void *args;
+
+	struct completion *comp;
+};
+
+/* ---------------------------------------------------------------------- */
+
+static void wkq_func(struct work_struct *wk)
+{
+	struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk);
+
+	AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID));
+	AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY);
+
+	wkinfo->func(wkinfo->args);
+	if (au_ftest_wkq(wkinfo->flags, WAIT))
+		complete(wkinfo->comp);
+	else {
+		kobject_put(wkinfo->kobj);
+		module_put(THIS_MODULE); /* todo: ?? */
+		kfree(wkinfo);
+	}
+}
+
+/*
+ * Since struct completion is large, try allocating it dynamically.
+ */
+#if 1 /* defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) */
+#define AuWkqCompDeclare(name)	struct completion *comp = NULL
+
+static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
+{
+	*comp = kmalloc(sizeof(**comp), GFP_NOFS);
+	if (*comp) {
+		init_completion(*comp);
+		wkinfo->comp = *comp;
+		return 0;
+	}
+	return -ENOMEM;
+}
+
+static void au_wkq_comp_free(struct completion *comp)
+{
+	kfree(comp);
+}
+
+#else
+
+/* no braces */
+#define AuWkqCompDeclare(name) \
+	DECLARE_COMPLETION_ONSTACK(_ ## name); \
+	struct completion *comp = &_ ## name
+
+static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
+{
+	wkinfo->comp = *comp;
+	return 0;
+}
+
+static void au_wkq_comp_free(struct completion *comp __maybe_unused)
+{
+	/* empty */
+}
+#endif /* 4KSTACKS */
+
+static void au_wkq_run(struct au_wkinfo *wkinfo)
+{
+	if (au_ftest_wkq(wkinfo->flags, NEST)) {
+		if (au_wkq_test()) {
+			AuWarn1("wkq from wkq, unless silly-rename on NFS,"
+				" due to a dead dir by UDBA?\n");
+			AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT));
+		}
+	} else
+		au_dbg_verify_kthread();
+
+	if (au_ftest_wkq(wkinfo->flags, WAIT)) {
+		INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func);
+		queue_work(au_wkq, &wkinfo->wk);
+	} else {
+		INIT_WORK(&wkinfo->wk, wkq_func);
+		schedule_work(&wkinfo->wk);
+	}
+}
+
+/*
+ * Be careful. It is easy to make deadlock happen.
+ * processA: lock, wkq and wait
+ * processB: wkq and wait, lock in wkq
+ * --> deadlock
+ */
+int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args)
+{
+	int err;
+	AuWkqCompDeclare(comp);
+	struct au_wkinfo wkinfo = {
+		.flags	= flags,
+		.func	= func,
+		.args	= args
+	};
+
+	err = au_wkq_comp_alloc(&wkinfo, &comp);
+	if (!err) {
+		au_wkq_run(&wkinfo);
+		/* no timeout, no interrupt */
+		wait_for_completion(wkinfo.comp);
+		au_wkq_comp_free(comp);
+		destroy_work_on_stack(&wkinfo.wk);
+	}
+
+	return err;
+
+}
+
+/*
+ * Note: dget/dput() in func for aufs dentries are not supported. It will be a
+ * problem in a concurrent umounting.
+ */
+int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb,
+		  unsigned int flags)
+{
+	int err;
+	struct au_wkinfo *wkinfo;
+
+	atomic_inc(&au_sbi(sb)->si_nowait.nw_len);
+
+	/*
+	 * wkq_func() must free this wkinfo.
+	 * it highly depends upon the implementation of workqueue.
+	 */
+	err = 0;
+	wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS);
+	if (wkinfo) {
+		wkinfo->kobj = &au_sbi(sb)->si_kobj;
+		wkinfo->flags = flags & ~AuWkq_WAIT;
+		wkinfo->func = func;
+		wkinfo->args = args;
+		wkinfo->comp = NULL;
+		kobject_get(wkinfo->kobj);
+		__module_get(THIS_MODULE); /* todo: ?? */
+
+		au_wkq_run(wkinfo);
+	} else {
+		err = -ENOMEM;
+		au_nwt_done(&au_sbi(sb)->si_nowait);
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void au_nwt_init(struct au_nowait_tasks *nwt)
+{
+	atomic_set(&nwt->nw_len, 0);
+	/* smp_mb(); */ /* atomic_set */
+	init_waitqueue_head(&nwt->nw_wq);
+}
+
+void au_wkq_fin(void)
+{
+	destroy_workqueue(au_wkq);
+}
+
+int __init au_wkq_init(void)
+{
+	int err;
+
+	err = 0;
+	au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE);
+	if (IS_ERR(au_wkq))
+		err = PTR_ERR(au_wkq);
+	else if (!au_wkq)
+		err = -ENOMEM;
+
+	return err;
+}
--- linux-4.4.0.orig/fs/aufs/wkq.h
+++ linux-4.4.0/fs/aufs/wkq.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * workqueue for asynchronous/super-io operations
+ * todo: try new credentials management scheme
+ */
+
+#ifndef __AUFS_WKQ_H__
+#define __AUFS_WKQ_H__
+
+#ifdef __KERNEL__
+
+struct super_block;
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue
+ */
+struct au_nowait_tasks {
+	atomic_t		nw_len;
+	wait_queue_head_t	nw_wq;
+};
+
+/* ---------------------------------------------------------------------- */
+
+typedef void (*au_wkq_func_t)(void *args);
+
+/* wkq flags */
+#define AuWkq_WAIT	1
+#define AuWkq_NEST	(1 << 1)
+#define au_ftest_wkq(flags, name)	((flags) & AuWkq_##name)
+#define au_fset_wkq(flags, name) \
+	do { (flags) |= AuWkq_##name; } while (0)
+#define au_fclr_wkq(flags, name) \
+	do { (flags) &= ~AuWkq_##name; } while (0)
+
+#ifndef CONFIG_AUFS_HNOTIFY
+#undef AuWkq_NEST
+#define AuWkq_NEST	0
+#endif
+
+/* wkq.c */
+int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args);
+int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb,
+		  unsigned int flags);
+void au_nwt_init(struct au_nowait_tasks *nwt);
+int __init au_wkq_init(void);
+void au_wkq_fin(void);
+
+/* ---------------------------------------------------------------------- */
+
+static inline int au_wkq_test(void)
+{
+	return current->flags & PF_WQ_WORKER;
+}
+
+static inline int au_wkq_wait(au_wkq_func_t func, void *args)
+{
+	return au_wkq_do_wait(AuWkq_WAIT, func, args);
+}
+
+static inline void au_nwt_done(struct au_nowait_tasks *nwt)
+{
+	if (atomic_dec_and_test(&nwt->nw_len))
+		wake_up_all(&nwt->nw_wq);
+}
+
+static inline int au_nwt_flush(struct au_nowait_tasks *nwt)
+{
+	wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len));
+	return 0;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_WKQ_H__ */
--- linux-4.4.0.orig/fs/aufs/xattr.c
+++ linux-4.4.0/fs/aufs/xattr.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2014-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * handling xattr functions
+ */
+
+#include <linux/xattr.h>
+#include "aufs.h"
+
+static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags)
+{
+	if (!ignore_flags)
+		goto out;
+	switch (err) {
+	case -ENOMEM:
+	case -EDQUOT:
+		goto out;
+	}
+
+	if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) {
+		err = 0;
+		goto out;
+	}
+
+#define cmp(brattr, prefix) do {					\
+		if (!strncmp(name, XATTR_##prefix##_PREFIX,		\
+			     XATTR_##prefix##_PREFIX_LEN)) {		\
+			if (ignore_flags & AuBrAttr_ICEX_##brattr)	\
+				err = 0;				\
+			goto out;					\
+		}							\
+	} while (0)
+
+	cmp(SEC, SECURITY);
+	cmp(SYS, SYSTEM);
+	cmp(TR, TRUSTED);
+	cmp(USR, USER);
+#undef cmp
+
+	if (ignore_flags & AuBrAttr_ICEX_OTH)
+		err = 0;
+
+out:
+	return err;
+}
+
+static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1;
+
+static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src,
+			    char *name, char **buf, unsigned int ignore_flags,
+			    unsigned int verbose)
+{
+	int err;
+	ssize_t ssz;
+	struct inode *h_idst;
+
+	ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS);
+	err = ssz;
+	if (unlikely(err <= 0)) {
+		if (err == -ENODATA
+		    || (err == -EOPNOTSUPP
+			&& ((ignore_flags & au_xattr_out_of_list)
+			    || (au_test_nfs_noacl(d_inode(h_src))
+				&& (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS)
+				    || !strcmp(name,
+					       XATTR_NAME_POSIX_ACL_DEFAULT))))
+			    ))
+			err = 0;
+		if (err && (verbose || au_debug_test()))
+			pr_err("%s, err %d\n", name, err);
+		goto out;
+	}
+
+	/* unlock it temporary */
+	h_idst = d_inode(h_dst);
+	mutex_unlock(&h_idst->i_mutex);
+	err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0);
+	mutex_lock_nested(&h_idst->i_mutex, AuLsc_I_CHILD2);
+	if (unlikely(err)) {
+		if (verbose || au_debug_test())
+			pr_err("%s, err %d\n", name, err);
+		err = au_xattr_ignore(err, name, ignore_flags);
+	}
+
+out:
+	return err;
+}
+
+int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
+		  unsigned int verbose)
+{
+	int err, unlocked, acl_access, acl_default;
+	ssize_t ssz;
+	struct inode *h_isrc, *h_idst;
+	char *value, *p, *o, *e;
+
+	/* try stopping to update the source inode while we are referencing */
+	/* there should not be the parent-child relationship between them */
+	h_isrc = d_inode(h_src);
+	h_idst = d_inode(h_dst);
+	mutex_unlock(&h_idst->i_mutex);
+	mutex_lock_nested(&h_isrc->i_mutex, AuLsc_I_CHILD);
+	mutex_lock_nested(&h_idst->i_mutex, AuLsc_I_CHILD2);
+	unlocked = 0;
+
+	/* some filesystems don't list POSIX ACL, for example tmpfs */
+	ssz = vfs_listxattr(h_src, NULL, 0);
+	err = ssz;
+	if (unlikely(err < 0)) {
+		AuTraceErr(err);
+		if (err == -ENODATA
+		    || err == -EOPNOTSUPP)
+			err = 0;	/* ignore */
+		goto out;
+	}
+
+	err = 0;
+	p = NULL;
+	o = NULL;
+	if (ssz) {
+		err = -ENOMEM;
+		p = kmalloc(ssz, GFP_NOFS);
+		o = p;
+		if (unlikely(!p))
+			goto out;
+		err = vfs_listxattr(h_src, p, ssz);
+	}
+	mutex_unlock(&h_isrc->i_mutex);
+	unlocked = 1;
+	AuDbg("err %d, ssz %zd\n", err, ssz);
+	if (unlikely(err < 0))
+		goto out_free;
+
+	err = 0;
+	e = p + ssz;
+	value = NULL;
+	acl_access = 0;
+	acl_default = 0;
+	while (!err && p < e) {
+		acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS,
+				       sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1);
+		acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT,
+					sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)
+					- 1);
+		err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags,
+				       verbose);
+		p += strlen(p) + 1;
+	}
+	AuTraceErr(err);
+	ignore_flags |= au_xattr_out_of_list;
+	if (!err && !acl_access) {
+		err = au_do_cpup_xattr(h_dst, h_src,
+				       XATTR_NAME_POSIX_ACL_ACCESS, &value,
+				       ignore_flags, verbose);
+		AuTraceErr(err);
+	}
+	if (!err && !acl_default) {
+		err = au_do_cpup_xattr(h_dst, h_src,
+				       XATTR_NAME_POSIX_ACL_DEFAULT, &value,
+				       ignore_flags, verbose);
+		AuTraceErr(err);
+	}
+
+	kfree(value);
+
+out_free:
+	kfree(o);
+out:
+	if (!unlocked)
+		mutex_unlock(&h_isrc->i_mutex);
+	AuTraceErr(err);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+enum {
+	AU_XATTR_LIST,
+	AU_XATTR_GET
+};
+
+struct au_lgxattr {
+	int type;
+	union {
+		struct {
+			char	*list;
+			size_t	size;
+		} list;
+		struct {
+			const char	*name;
+			void		*value;
+			size_t		size;
+		} get;
+	} u;
+};
+
+static ssize_t au_lgxattr(struct dentry *dentry, struct au_lgxattr *arg)
+{
+	ssize_t err;
+	struct path h_path;
+	struct super_block *sb;
+
+	sb = dentry->d_sb;
+	err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
+	if (unlikely(err))
+		goto out;
+	err = au_h_path_getattr(dentry, /*force*/1, &h_path);
+	if (unlikely(err))
+		goto out_si;
+	if (unlikely(!h_path.dentry))
+		/* illegally overlapped or something */
+		goto out_di; /* pretending success */
+
+	/* always topmost entry only */
+	switch (arg->type) {
+	case AU_XATTR_LIST:
+		err = vfs_listxattr(h_path.dentry,
+				    arg->u.list.list, arg->u.list.size);
+		break;
+	case AU_XATTR_GET:
+		err = vfs_getxattr(h_path.dentry,
+				   arg->u.get.name, arg->u.get.value,
+				   arg->u.get.size);
+		break;
+	}
+
+out_di:
+	di_read_unlock(dentry, AuLock_IR);
+out_si:
+	si_read_unlock(sb);
+out:
+	AuTraceErr(err);
+	return err;
+}
+
+ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+	struct au_lgxattr arg = {
+		.type = AU_XATTR_LIST,
+		.u.list = {
+			.list	= list,
+			.size	= size
+		},
+	};
+
+	return au_lgxattr(dentry, &arg);
+}
+
+ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value,
+		      size_t size)
+{
+	struct au_lgxattr arg = {
+		.type = AU_XATTR_GET,
+		.u.get = {
+			.name	= name,
+			.value	= value,
+			.size	= size
+		},
+	};
+
+	return au_lgxattr(dentry, &arg);
+}
+
+int aufs_setxattr(struct dentry *dentry, const char *name, const void *value,
+		  size_t size, int flags)
+{
+	struct au_srxattr arg = {
+		.type = AU_XATTR_SET,
+		.u.set = {
+			.name	= name,
+			.value	= value,
+			.size	= size,
+			.flags	= flags
+		},
+	};
+
+	return au_srxattr(dentry, &arg);
+}
+
+int aufs_removexattr(struct dentry *dentry, const char *name)
+{
+	struct au_srxattr arg = {
+		.type = AU_XATTR_REMOVE,
+		.u.remove = {
+			.name	= name
+		},
+	};
+
+	return au_srxattr(dentry, &arg);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+static size_t au_xattr_list(struct dentry *dentry, char *list, size_t list_size,
+			    const char *name, size_t name_len, int type)
+{
+	return aufs_listxattr(dentry, list, list_size);
+}
+
+static int au_xattr_get(struct dentry *dentry, const char *name, void *buffer,
+			size_t size, int type)
+{
+	return aufs_getxattr(dentry, name, buffer, size);
+}
+
+static int au_xattr_set(struct dentry *dentry, const char *name,
+			const void *value, size_t size, int flags, int type)
+{
+	return aufs_setxattr(dentry, name, value, size, flags);
+}
+
+static const struct xattr_handler au_xattr_handler = {
+	/* no prefix, no flags */
+	.list	= au_xattr_list,
+	.get	= au_xattr_get,
+	.set	= au_xattr_set
+	/* why no remove? */
+};
+
+static const struct xattr_handler *au_xattr_handlers[] = {
+	&au_xattr_handler
+};
+
+void au_xattr_init(struct super_block *sb)
+{
+	/* sb->s_xattr = au_xattr_handlers; */
+}
+#endif
--- linux-4.4.0.orig/fs/aufs/xino.c
+++ linux-4.4.0/fs/aufs/xino.c
@@ -0,0 +1,1318 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/>.
+ */
+
+/*
+ * external inode number translation table and bitmap
+ */
+
+#include <linux/seq_file.h>
+#include <linux/statfs.h>
+#include "aufs.h"
+
+/* todo: unnecessary to support mmap_sem since kernel-space? */
+ssize_t xino_fread(vfs_readf_t func, struct file *file, void *kbuf, size_t size,
+		   loff_t *pos)
+{
+	ssize_t err;
+	mm_segment_t oldfs;
+	union {
+		void *k;
+		char __user *u;
+	} buf;
+
+	buf.k = kbuf;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	do {
+		/* todo: signal_pending? */
+		err = func(file, buf.u, size, pos);
+	} while (err == -EAGAIN || err == -EINTR);
+	set_fs(oldfs);
+
+#if 0 /* reserved for future use */
+	if (err > 0)
+		fsnotify_access(file->f_path.dentry);
+#endif
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf,
+			       size_t size, loff_t *pos);
+
+static ssize_t do_xino_fwrite(vfs_writef_t func, struct file *file, void *kbuf,
+			      size_t size, loff_t *pos)
+{
+	ssize_t err;
+	mm_segment_t oldfs;
+	union {
+		void *k;
+		const char __user *u;
+	} buf;
+	int i;
+	const int prevent_endless = 10;
+
+	i = 0;
+	buf.k = kbuf;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	do {
+		err = func(file, buf.u, size, pos);
+		if (err == -EINTR
+		    && !au_wkq_test()
+		    && fatal_signal_pending(current)) {
+			set_fs(oldfs);
+			err = xino_fwrite_wkq(func, file, kbuf, size, pos);
+			BUG_ON(err == -EINTR);
+			oldfs = get_fs();
+			set_fs(KERNEL_DS);
+		}
+	} while (i++ < prevent_endless
+		 && (err == -EAGAIN || err == -EINTR));
+	set_fs(oldfs);
+
+#if 0 /* reserved for future use */
+	if (err > 0)
+		fsnotify_modify(file->f_path.dentry);
+#endif
+
+	return err;
+}
+
+struct do_xino_fwrite_args {
+	ssize_t *errp;
+	vfs_writef_t func;
+	struct file *file;
+	void *buf;
+	size_t size;
+	loff_t *pos;
+};
+
+static void call_do_xino_fwrite(void *args)
+{
+	struct do_xino_fwrite_args *a = args;
+	*a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos);
+}
+
+static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf,
+			       size_t size, loff_t *pos)
+{
+	ssize_t err;
+	int wkq_err;
+	struct do_xino_fwrite_args args = {
+		.errp	= &err,
+		.func	= func,
+		.file	= file,
+		.buf	= buf,
+		.size	= size,
+		.pos	= pos
+	};
+
+	/*
+	 * it breaks RLIMIT_FSIZE and normal user's limit,
+	 * users should care about quota and real 'filesystem full.'
+	 */
+	wkq_err = au_wkq_wait(call_do_xino_fwrite, &args);
+	if (unlikely(wkq_err))
+		err = wkq_err;
+
+	return err;
+}
+
+ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf,
+		    size_t size, loff_t *pos)
+{
+	ssize_t err;
+
+	if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) {
+		lockdep_off();
+		err = do_xino_fwrite(func, file, buf, size, pos);
+		lockdep_on();
+	} else
+		err = xino_fwrite_wkq(func, file, buf, size, pos);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * create a new xinofile at the same place/path as @base_file.
+ */
+struct file *au_xino_create2(struct file *base_file, struct file *copy_src)
+{
+	struct file *file;
+	struct dentry *base, *parent;
+	struct inode *dir, *delegated;
+	struct qstr *name;
+	struct path path;
+	int err;
+
+	base = base_file->f_path.dentry;
+	parent = base->d_parent; /* dir inode is locked */
+	dir = d_inode(parent);
+	IMustLock(dir);
+
+	file = ERR_PTR(-EINVAL);
+	name = &base->d_name;
+	path.dentry = vfsub_lookup_one_len(name->name, parent, name->len);
+	if (IS_ERR(path.dentry)) {
+		file = (void *)path.dentry;
+		pr_err("%pd lookup err %ld\n",
+		       base, PTR_ERR(path.dentry));
+		goto out;
+	}
+
+	/* no need to mnt_want_write() since we call dentry_open() later */
+	err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL);
+	if (unlikely(err)) {
+		file = ERR_PTR(err);
+		pr_err("%pd create err %d\n", base, err);
+		goto out_dput;
+	}
+
+	path.mnt = base_file->f_path.mnt;
+	file = vfsub_dentry_open(&path,
+				 O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
+				 /* | __FMODE_NONOTIFY */);
+	if (IS_ERR(file)) {
+		pr_err("%pd open err %ld\n", base, PTR_ERR(file));
+		goto out_dput;
+	}
+
+	delegated = NULL;
+	err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0);
+	if (unlikely(err == -EWOULDBLOCK)) {
+		pr_warn("cannot retry for NFSv4 delegation"
+			" for an internal unlink\n");
+		iput(delegated);
+	}
+	if (unlikely(err)) {
+		pr_err("%pd unlink err %d\n", base, err);
+		goto out_fput;
+	}
+
+	if (copy_src) {
+		/* no one can touch copy_src xino */
+		err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src));
+		if (unlikely(err)) {
+			pr_err("%pd copy err %d\n", base, err);
+			goto out_fput;
+		}
+	}
+	goto out_dput; /* success */
+
+out_fput:
+	fput(file);
+	file = ERR_PTR(err);
+out_dput:
+	dput(path.dentry);
+out:
+	return file;
+}
+
+struct au_xino_lock_dir {
+	struct au_hinode *hdir;
+	struct dentry *parent;
+	struct mutex *mtx;
+};
+
+static void au_xino_lock_dir(struct super_block *sb, struct file *xino,
+			     struct au_xino_lock_dir *ldir)
+{
+	aufs_bindex_t brid, bindex;
+
+	ldir->hdir = NULL;
+	bindex = -1;
+	brid = au_xino_brid(sb);
+	if (brid >= 0)
+		bindex = au_br_index(sb, brid);
+	if (bindex >= 0) {
+		ldir->hdir = au_hi(d_inode(sb->s_root), bindex);
+		au_hn_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT);
+	} else {
+		ldir->parent = dget_parent(xino->f_path.dentry);
+		ldir->mtx = &d_inode(ldir->parent)->i_mutex;
+		mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT);
+	}
+}
+
+static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir)
+{
+	if (ldir->hdir)
+		au_hn_imtx_unlock(ldir->hdir);
+	else {
+		mutex_unlock(ldir->mtx);
+		dput(ldir->parent);
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* trucate xino files asynchronously */
+
+int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex)
+{
+	int err;
+	unsigned long jiffy;
+	blkcnt_t blocks;
+	aufs_bindex_t bi, bend;
+	struct kstatfs *st;
+	struct au_branch *br;
+	struct file *new_xino, *file;
+	struct super_block *h_sb;
+	struct au_xino_lock_dir ldir;
+
+	err = -ENOMEM;
+	st = kmalloc(sizeof(*st), GFP_NOFS);
+	if (unlikely(!st))
+		goto out;
+
+	err = -EINVAL;
+	bend = au_sbend(sb);
+	if (unlikely(bindex < 0 || bend < bindex))
+		goto out_st;
+	br = au_sbr(sb, bindex);
+	file = br->br_xino.xi_file;
+	if (!file)
+		goto out_st;
+
+	err = vfs_statfs(&file->f_path, st);
+	if (unlikely(err))
+		AuErr1("statfs err %d, ignored\n", err);
+	jiffy = jiffies;
+	blocks = file_inode(file)->i_blocks;
+	pr_info("begin truncating xino(b%d), ib%llu, %llu/%llu free blks\n",
+		bindex, (u64)blocks, st->f_bfree, st->f_blocks);
+
+	au_xino_lock_dir(sb, file, &ldir);
+	/* mnt_want_write() is unnecessary here */
+	new_xino = au_xino_create2(file, file);
+	au_xino_unlock_dir(&ldir);
+	err = PTR_ERR(new_xino);
+	if (IS_ERR(new_xino)) {
+		pr_err("err %d, ignored\n", err);
+		goto out_st;
+	}
+	err = 0;
+	fput(file);
+	br->br_xino.xi_file = new_xino;
+
+	h_sb = au_br_sb(br);
+	for (bi = 0; bi <= bend; bi++) {
+		if (unlikely(bi == bindex))
+			continue;
+		br = au_sbr(sb, bi);
+		if (au_br_sb(br) != h_sb)
+			continue;
+
+		fput(br->br_xino.xi_file);
+		br->br_xino.xi_file = new_xino;
+		get_file(new_xino);
+	}
+
+	err = vfs_statfs(&new_xino->f_path, st);
+	if (!err) {
+		pr_info("end truncating xino(b%d), ib%llu, %llu/%llu free blks\n",
+			bindex, (u64)file_inode(new_xino)->i_blocks,
+			st->f_bfree, st->f_blocks);
+		if (file_inode(new_xino)->i_blocks < blocks)
+			au_sbi(sb)->si_xino_jiffy = jiffy;
+	} else
+		AuErr1("statfs err %d, ignored\n", err);
+
+out_st:
+	kfree(st);
+out:
+	return err;
+}
+
+struct xino_do_trunc_args {
+	struct super_block *sb;
+	struct au_branch *br;
+};
+
+static void xino_do_trunc(void *_args)
+{
+	struct xino_do_trunc_args *args = _args;
+	struct super_block *sb;
+	struct au_branch *br;
+	struct inode *dir;
+	int err;
+	aufs_bindex_t bindex;
+
+	err = 0;
+	sb = args->sb;
+	dir = d_inode(sb->s_root);
+	br = args->br;
+
+	si_noflush_write_lock(sb);
+	ii_read_lock_parent(dir);
+	bindex = au_br_index(sb, br->br_id);
+	err = au_xino_trunc(sb, bindex);
+	ii_read_unlock(dir);
+	if (unlikely(err))
+		pr_warn("err b%d, (%d)\n", bindex, err);
+	atomic_dec(&br->br_xino_running);
+	atomic_dec(&br->br_count);
+	si_write_unlock(sb);
+	au_nwt_done(&au_sbi(sb)->si_nowait);
+	kfree(args);
+}
+
+static int xino_trunc_test(struct super_block *sb, struct au_branch *br)
+{
+	int err;
+	struct kstatfs st;
+	struct au_sbinfo *sbinfo;
+
+	/* todo: si_xino_expire and the ratio should be customizable */
+	sbinfo = au_sbi(sb);
+	if (time_before(jiffies,
+			sbinfo->si_xino_jiffy + sbinfo->si_xino_expire))
+		return 0;
+
+	/* truncation border */
+	err = vfs_statfs(&br->br_xino.xi_file->f_path, &st);
+	if (unlikely(err)) {
+		AuErr1("statfs err %d, ignored\n", err);
+		return 0;
+	}
+	if (div64_u64(st.f_bfree * 100, st.f_blocks) >= AUFS_XINO_DEF_TRUNC)
+		return 0;
+
+	return 1;
+}
+
+static void xino_try_trunc(struct super_block *sb, struct au_branch *br)
+{
+	struct xino_do_trunc_args *args;
+	int wkq_err;
+
+	if (!xino_trunc_test(sb, br))
+		return;
+
+	if (atomic_inc_return(&br->br_xino_running) > 1)
+		goto out;
+
+	/* lock and kfree() will be called in trunc_xino() */
+	args = kmalloc(sizeof(*args), GFP_NOFS);
+	if (unlikely(!args)) {
+		AuErr1("no memory\n");
+		goto out_args;
+	}
+
+	atomic_inc(&br->br_count);
+	args->sb = sb;
+	args->br = br;
+	wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0);
+	if (!wkq_err)
+		return; /* success */
+
+	pr_err("wkq %d\n", wkq_err);
+	atomic_dec(&br->br_count);
+
+out_args:
+	kfree(args);
+out:
+	atomic_dec(&br->br_xino_running);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_xino_do_write(vfs_writef_t write, struct file *file,
+			    ino_t h_ino, ino_t ino)
+{
+	loff_t pos;
+	ssize_t sz;
+
+	pos = h_ino;
+	if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) {
+		AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
+		return -EFBIG;
+	}
+	pos *= sizeof(ino);
+	sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos);
+	if (sz == sizeof(ino))
+		return 0; /* success */
+
+	AuIOErr("write failed (%zd)\n", sz);
+	return -EIO;
+}
+
+/*
+ * write @ino to the xinofile for the specified branch{@sb, @bindex}
+ * at the position of @h_ino.
+ * even if @ino is zero, it is written to the xinofile and means no entry.
+ * if the size of the xino file on a specific filesystem exceeds the watermark,
+ * try truncating it.
+ */
+int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
+		  ino_t ino)
+{
+	int err;
+	unsigned int mnt_flags;
+	struct au_branch *br;
+
+	BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max)
+		     || ((loff_t)-1) > 0);
+	SiMustAnyLock(sb);
+
+	mnt_flags = au_mntflags(sb);
+	if (!au_opt_test(mnt_flags, XINO))
+		return 0;
+
+	br = au_sbr(sb, bindex);
+	err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file,
+			       h_ino, ino);
+	if (!err) {
+		if (au_opt_test(mnt_flags, TRUNC_XINO)
+		    && au_test_fs_trunc_xino(au_br_sb(br)))
+			xino_try_trunc(sb, br);
+		return 0; /* success */
+	}
+
+	AuIOErr("write failed (%d)\n", err);
+	return -EIO;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* aufs inode number bitmap */
+
+static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE;
+static ino_t xib_calc_ino(unsigned long pindex, int bit)
+{
+	ino_t ino;
+
+	AuDebugOn(bit < 0 || page_bits <= bit);
+	ino = AUFS_FIRST_INO + pindex * page_bits + bit;
+	return ino;
+}
+
+static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit)
+{
+	AuDebugOn(ino < AUFS_FIRST_INO);
+	ino -= AUFS_FIRST_INO;
+	*pindex = ino / page_bits;
+	*bit = ino % page_bits;
+}
+
+static int xib_pindex(struct super_block *sb, unsigned long pindex)
+{
+	int err;
+	loff_t pos;
+	ssize_t sz;
+	struct au_sbinfo *sbinfo;
+	struct file *xib;
+	unsigned long *p;
+
+	sbinfo = au_sbi(sb);
+	MtxMustLock(&sbinfo->si_xib_mtx);
+	AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE
+		  || !au_opt_test(sbinfo->si_mntflags, XINO));
+
+	if (pindex == sbinfo->si_xib_last_pindex)
+		return 0;
+
+	xib = sbinfo->si_xib;
+	p = sbinfo->si_xib_buf;
+	pos = sbinfo->si_xib_last_pindex;
+	pos *= PAGE_SIZE;
+	sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos);
+	if (unlikely(sz != PAGE_SIZE))
+		goto out;
+
+	pos = pindex;
+	pos *= PAGE_SIZE;
+	if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE)
+		sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos);
+	else {
+		memset(p, 0, PAGE_SIZE);
+		sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos);
+	}
+	if (sz == PAGE_SIZE) {
+		sbinfo->si_xib_last_pindex = pindex;
+		return 0; /* success */
+	}
+
+out:
+	AuIOErr1("write failed (%zd)\n", sz);
+	err = sz;
+	if (sz >= 0)
+		err = -EIO;
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void au_xib_clear_bit(struct inode *inode)
+{
+	int err, bit;
+	unsigned long pindex;
+	struct super_block *sb;
+	struct au_sbinfo *sbinfo;
+
+	AuDebugOn(inode->i_nlink);
+
+	sb = inode->i_sb;
+	xib_calc_bit(inode->i_ino, &pindex, &bit);
+	AuDebugOn(page_bits <= bit);
+	sbinfo = au_sbi(sb);
+	mutex_lock(&sbinfo->si_xib_mtx);
+	err = xib_pindex(sb, pindex);
+	if (!err) {
+		clear_bit(bit, sbinfo->si_xib_buf);
+		sbinfo->si_xib_next_bit = bit;
+	}
+	mutex_unlock(&sbinfo->si_xib_mtx);
+}
+
+/* for s_op->delete_inode() */
+void au_xino_delete_inode(struct inode *inode, const int unlinked)
+{
+	int err;
+	unsigned int mnt_flags;
+	aufs_bindex_t bindex, bend, bi;
+	unsigned char try_trunc;
+	struct au_iinfo *iinfo;
+	struct super_block *sb;
+	struct au_hinode *hi;
+	struct inode *h_inode;
+	struct au_branch *br;
+	vfs_writef_t xwrite;
+
+	sb = inode->i_sb;
+	mnt_flags = au_mntflags(sb);
+	if (!au_opt_test(mnt_flags, XINO)
+	    || inode->i_ino == AUFS_ROOT_INO)
+		return;
+
+	if (unlinked) {
+		au_xigen_inc(inode);
+		au_xib_clear_bit(inode);
+	}
+
+	iinfo = au_ii(inode);
+	if (!iinfo)
+		return;
+
+	bindex = iinfo->ii_bstart;
+	if (bindex < 0)
+		return;
+
+	xwrite = au_sbi(sb)->si_xwrite;
+	try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO);
+	hi = iinfo->ii_hinode + bindex;
+	bend = iinfo->ii_bend;
+	for (; bindex <= bend; bindex++, hi++) {
+		h_inode = hi->hi_inode;
+		if (!h_inode
+		    || (!unlinked && h_inode->i_nlink))
+			continue;
+
+		/* inode may not be revalidated */
+		bi = au_br_index(sb, hi->hi_id);
+		if (bi < 0)
+			continue;
+
+		br = au_sbr(sb, bi);
+		err = au_xino_do_write(xwrite, br->br_xino.xi_file,
+				       h_inode->i_ino, /*ino*/0);
+		if (!err && try_trunc
+		    && au_test_fs_trunc_xino(au_br_sb(br)))
+			xino_try_trunc(sb, br);
+	}
+}
+
+/* get an unused inode number from bitmap */
+ino_t au_xino_new_ino(struct super_block *sb)
+{
+	ino_t ino;
+	unsigned long *p, pindex, ul, pend;
+	struct au_sbinfo *sbinfo;
+	struct file *file;
+	int free_bit, err;
+
+	if (!au_opt_test(au_mntflags(sb), XINO))
+		return iunique(sb, AUFS_FIRST_INO);
+
+	sbinfo = au_sbi(sb);
+	mutex_lock(&sbinfo->si_xib_mtx);
+	p = sbinfo->si_xib_buf;
+	free_bit = sbinfo->si_xib_next_bit;
+	if (free_bit < page_bits && !test_bit(free_bit, p))
+		goto out; /* success */
+	free_bit = find_first_zero_bit(p, page_bits);
+	if (free_bit < page_bits)
+		goto out; /* success */
+
+	pindex = sbinfo->si_xib_last_pindex;
+	for (ul = pindex - 1; ul < ULONG_MAX; ul--) {
+		err = xib_pindex(sb, ul);
+		if (unlikely(err))
+			goto out_err;
+		free_bit = find_first_zero_bit(p, page_bits);
+		if (free_bit < page_bits)
+			goto out; /* success */
+	}
+
+	file = sbinfo->si_xib;
+	pend = vfsub_f_size_read(file) / PAGE_SIZE;
+	for (ul = pindex + 1; ul <= pend; ul++) {
+		err = xib_pindex(sb, ul);
+		if (unlikely(err))
+			goto out_err;
+		free_bit = find_first_zero_bit(p, page_bits);
+		if (free_bit < page_bits)
+			goto out; /* success */
+	}
+	BUG();
+
+out:
+	set_bit(free_bit, p);
+	sbinfo->si_xib_next_bit = free_bit + 1;
+	pindex = sbinfo->si_xib_last_pindex;
+	mutex_unlock(&sbinfo->si_xib_mtx);
+	ino = xib_calc_ino(pindex, free_bit);
+	AuDbg("i%lu\n", (unsigned long)ino);
+	return ino;
+out_err:
+	mutex_unlock(&sbinfo->si_xib_mtx);
+	AuDbg("i0\n");
+	return 0;
+}
+
+/*
+ * read @ino from xinofile for the specified branch{@sb, @bindex}
+ * at the position of @h_ino.
+ * if @ino does not exist and @do_new is true, get new one.
+ */
+int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
+		 ino_t *ino)
+{
+	int err;
+	ssize_t sz;
+	loff_t pos;
+	struct file *file;
+	struct au_sbinfo *sbinfo;
+
+	*ino = 0;
+	if (!au_opt_test(au_mntflags(sb), XINO))
+		return 0; /* no xino */
+
+	err = 0;
+	sbinfo = au_sbi(sb);
+	pos = h_ino;
+	if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) {
+		AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
+		return -EFBIG;
+	}
+	pos *= sizeof(*ino);
+
+	file = au_sbr(sb, bindex)->br_xino.xi_file;
+	if (vfsub_f_size_read(file) < pos + sizeof(*ino))
+		return 0; /* no ino */
+
+	sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos);
+	if (sz == sizeof(*ino))
+		return 0; /* success */
+
+	err = sz;
+	if (unlikely(sz >= 0)) {
+		err = -EIO;
+		AuIOErr("xino read error (%zd)\n", sz);
+	}
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* create and set a new xino file */
+
+struct file *au_xino_create(struct super_block *sb, char *fname, int silent)
+{
+	struct file *file;
+	struct dentry *h_parent, *d;
+	struct inode *h_dir, *inode;
+	int err;
+
+	/*
+	 * at mount-time, and the xino file is the default path,
+	 * hnotify is disabled so we have no notify events to ignore.
+	 * when a user specified the xino, we cannot get au_hdir to be ignored.
+	 */
+	file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
+			       /* | __FMODE_NONOTIFY */,
+			       S_IRUGO | S_IWUGO);
+	if (IS_ERR(file)) {
+		if (!silent)
+			pr_err("open %s(%ld)\n", fname, PTR_ERR(file));
+		return file;
+	}
+
+	/* keep file count */
+	err = 0;
+	inode = file_inode(file);
+	h_parent = dget_parent(file->f_path.dentry);
+	h_dir = d_inode(h_parent);
+	mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
+	/* mnt_want_write() is unnecessary here */
+	/* no delegation since it is just created */
+	if (inode->i_nlink)
+		err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL,
+				   /*force*/0);
+	mutex_unlock(&h_dir->i_mutex);
+	dput(h_parent);
+	if (unlikely(err)) {
+		if (!silent)
+			pr_err("unlink %s(%d)\n", fname, err);
+		goto out;
+	}
+
+	err = -EINVAL;
+	d = file->f_path.dentry;
+	if (unlikely(sb == d->d_sb)) {
+		if (!silent)
+			pr_err("%s must be outside\n", fname);
+		goto out;
+	}
+	if (unlikely(au_test_fs_bad_xino(d->d_sb))) {
+		if (!silent)
+			pr_err("xino doesn't support %s(%s)\n",
+			       fname, au_sbtype(d->d_sb));
+		goto out;
+	}
+	return file; /* success */
+
+out:
+	fput(file);
+	file = ERR_PTR(err);
+	return file;
+}
+
+/*
+ * find another branch who is on the same filesystem of the specified
+ * branch{@btgt}. search until @bend.
+ */
+static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt,
+			aufs_bindex_t bend)
+{
+	aufs_bindex_t bindex;
+	struct super_block *tgt_sb = au_sbr_sb(sb, btgt);
+
+	for (bindex = 0; bindex < btgt; bindex++)
+		if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
+			return bindex;
+	for (bindex++; bindex <= bend; bindex++)
+		if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
+			return bindex;
+	return -1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * initialize the xinofile for the specified branch @br
+ * at the place/path where @base_file indicates.
+ * test whether another branch is on the same filesystem or not,
+ * if @do_test is true.
+ */
+int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino,
+	       struct file *base_file, int do_test)
+{
+	int err;
+	ino_t ino;
+	aufs_bindex_t bend, bindex;
+	struct au_branch *shared_br, *b;
+	struct file *file;
+	struct super_block *tgt_sb;
+
+	shared_br = NULL;
+	bend = au_sbend(sb);
+	if (do_test) {
+		tgt_sb = au_br_sb(br);
+		for (bindex = 0; bindex <= bend; bindex++) {
+			b = au_sbr(sb, bindex);
+			if (tgt_sb == au_br_sb(b)) {
+				shared_br = b;
+				break;
+			}
+		}
+	}
+
+	if (!shared_br || !shared_br->br_xino.xi_file) {
+		struct au_xino_lock_dir ldir;
+
+		au_xino_lock_dir(sb, base_file, &ldir);
+		/* mnt_want_write() is unnecessary here */
+		file = au_xino_create2(base_file, NULL);
+		au_xino_unlock_dir(&ldir);
+		err = PTR_ERR(file);
+		if (IS_ERR(file))
+			goto out;
+		br->br_xino.xi_file = file;
+	} else {
+		br->br_xino.xi_file = shared_br->br_xino.xi_file;
+		get_file(br->br_xino.xi_file);
+	}
+
+	ino = AUFS_ROOT_INO;
+	err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file,
+			       h_ino, ino);
+	if (unlikely(err)) {
+		fput(br->br_xino.xi_file);
+		br->br_xino.xi_file = NULL;
+	}
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* trucate a xino bitmap file */
+
+/* todo: slow */
+static int do_xib_restore(struct super_block *sb, struct file *file, void *page)
+{
+	int err, bit;
+	ssize_t sz;
+	unsigned long pindex;
+	loff_t pos, pend;
+	struct au_sbinfo *sbinfo;
+	vfs_readf_t func;
+	ino_t *ino;
+	unsigned long *p;
+
+	err = 0;
+	sbinfo = au_sbi(sb);
+	MtxMustLock(&sbinfo->si_xib_mtx);
+	p = sbinfo->si_xib_buf;
+	func = sbinfo->si_xread;
+	pend = vfsub_f_size_read(file);
+	pos = 0;
+	while (pos < pend) {
+		sz = xino_fread(func, file, page, PAGE_SIZE, &pos);
+		err = sz;
+		if (unlikely(sz <= 0))
+			goto out;
+
+		err = 0;
+		for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) {
+			if (unlikely(*ino < AUFS_FIRST_INO))
+				continue;
+
+			xib_calc_bit(*ino, &pindex, &bit);
+			AuDebugOn(page_bits <= bit);
+			err = xib_pindex(sb, pindex);
+			if (!err)
+				set_bit(bit, p);
+			else
+				goto out;
+		}
+	}
+
+out:
+	return err;
+}
+
+static int xib_restore(struct super_block *sb)
+{
+	int err;
+	aufs_bindex_t bindex, bend;
+	void *page;
+
+	err = -ENOMEM;
+	page = (void *)__get_free_page(GFP_NOFS);
+	if (unlikely(!page))
+		goto out;
+
+	err = 0;
+	bend = au_sbend(sb);
+	for (bindex = 0; !err && bindex <= bend; bindex++)
+		if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0)
+			err = do_xib_restore
+				(sb, au_sbr(sb, bindex)->br_xino.xi_file, page);
+		else
+			AuDbg("b%d\n", bindex);
+	free_page((unsigned long)page);
+
+out:
+	return err;
+}
+
+int au_xib_trunc(struct super_block *sb)
+{
+	int err;
+	ssize_t sz;
+	loff_t pos;
+	struct au_xino_lock_dir ldir;
+	struct au_sbinfo *sbinfo;
+	unsigned long *p;
+	struct file *file;
+
+	SiMustWriteLock(sb);
+
+	err = 0;
+	sbinfo = au_sbi(sb);
+	if (!au_opt_test(sbinfo->si_mntflags, XINO))
+		goto out;
+
+	file = sbinfo->si_xib;
+	if (vfsub_f_size_read(file) <= PAGE_SIZE)
+		goto out;
+
+	au_xino_lock_dir(sb, file, &ldir);
+	/* mnt_want_write() is unnecessary here */
+	file = au_xino_create2(sbinfo->si_xib, NULL);
+	au_xino_unlock_dir(&ldir);
+	err = PTR_ERR(file);
+	if (IS_ERR(file))
+		goto out;
+	fput(sbinfo->si_xib);
+	sbinfo->si_xib = file;
+
+	p = sbinfo->si_xib_buf;
+	memset(p, 0, PAGE_SIZE);
+	pos = 0;
+	sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos);
+	if (unlikely(sz != PAGE_SIZE)) {
+		err = sz;
+		AuIOErr("err %d\n", err);
+		if (sz >= 0)
+			err = -EIO;
+		goto out;
+	}
+
+	mutex_lock(&sbinfo->si_xib_mtx);
+	/* mnt_want_write() is unnecessary here */
+	err = xib_restore(sb);
+	mutex_unlock(&sbinfo->si_xib_mtx);
+
+out:
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * xino mount option handlers
+ */
+
+/* xino bitmap */
+static void xino_clear_xib(struct super_block *sb)
+{
+	struct au_sbinfo *sbinfo;
+
+	SiMustWriteLock(sb);
+
+	sbinfo = au_sbi(sb);
+	sbinfo->si_xread = NULL;
+	sbinfo->si_xwrite = NULL;
+	if (sbinfo->si_xib)
+		fput(sbinfo->si_xib);
+	sbinfo->si_xib = NULL;
+	free_page((unsigned long)sbinfo->si_xib_buf);
+	sbinfo->si_xib_buf = NULL;
+}
+
+static int au_xino_set_xib(struct super_block *sb, struct file *base)
+{
+	int err;
+	loff_t pos;
+	struct au_sbinfo *sbinfo;
+	struct file *file;
+
+	SiMustWriteLock(sb);
+
+	sbinfo = au_sbi(sb);
+	file = au_xino_create2(base, sbinfo->si_xib);
+	err = PTR_ERR(file);
+	if (IS_ERR(file))
+		goto out;
+	if (sbinfo->si_xib)
+		fput(sbinfo->si_xib);
+	sbinfo->si_xib = file;
+	sbinfo->si_xread = vfs_readf(file);
+	sbinfo->si_xwrite = vfs_writef(file);
+
+	err = -ENOMEM;
+	if (!sbinfo->si_xib_buf)
+		sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS);
+	if (unlikely(!sbinfo->si_xib_buf))
+		goto out_unset;
+
+	sbinfo->si_xib_last_pindex = 0;
+	sbinfo->si_xib_next_bit = 0;
+	if (vfsub_f_size_read(file) < PAGE_SIZE) {
+		pos = 0;
+		err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf,
+				  PAGE_SIZE, &pos);
+		if (unlikely(err != PAGE_SIZE))
+			goto out_free;
+	}
+	err = 0;
+	goto out; /* success */
+
+out_free:
+	free_page((unsigned long)sbinfo->si_xib_buf);
+	sbinfo->si_xib_buf = NULL;
+	if (err >= 0)
+		err = -EIO;
+out_unset:
+	fput(sbinfo->si_xib);
+	sbinfo->si_xib = NULL;
+	sbinfo->si_xread = NULL;
+	sbinfo->si_xwrite = NULL;
+out:
+	return err;
+}
+
+/* xino for each branch */
+static void xino_clear_br(struct super_block *sb)
+{
+	aufs_bindex_t bindex, bend;
+	struct au_branch *br;
+
+	bend = au_sbend(sb);
+	for (bindex = 0; bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		if (!br || !br->br_xino.xi_file)
+			continue;
+
+		fput(br->br_xino.xi_file);
+		br->br_xino.xi_file = NULL;
+	}
+}
+
+static int au_xino_set_br(struct super_block *sb, struct file *base)
+{
+	int err;
+	ino_t ino;
+	aufs_bindex_t bindex, bend, bshared;
+	struct {
+		struct file *old, *new;
+	} *fpair, *p;
+	struct au_branch *br;
+	struct inode *inode;
+	vfs_writef_t writef;
+
+	SiMustWriteLock(sb);
+
+	err = -ENOMEM;
+	bend = au_sbend(sb);
+	fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS);
+	if (unlikely(!fpair))
+		goto out;
+
+	inode = d_inode(sb->s_root);
+	ino = AUFS_ROOT_INO;
+	writef = au_sbi(sb)->si_xwrite;
+	for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) {
+		br = au_sbr(sb, bindex);
+		bshared = is_sb_shared(sb, bindex, bindex - 1);
+		if (bshared >= 0) {
+			/* shared xino */
+			*p = fpair[bshared];
+			get_file(p->new);
+		}
+
+		if (!p->new) {
+			/* new xino */
+			p->old = br->br_xino.xi_file;
+			p->new = au_xino_create2(base, br->br_xino.xi_file);
+			err = PTR_ERR(p->new);
+			if (IS_ERR(p->new)) {
+				p->new = NULL;
+				goto out_pair;
+			}
+		}
+
+		err = au_xino_do_write(writef, p->new,
+				       au_h_iptr(inode, bindex)->i_ino, ino);
+		if (unlikely(err))
+			goto out_pair;
+	}
+
+	for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) {
+		br = au_sbr(sb, bindex);
+		if (br->br_xino.xi_file)
+			fput(br->br_xino.xi_file);
+		get_file(p->new);
+		br->br_xino.xi_file = p->new;
+	}
+
+out_pair:
+	for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++)
+		if (p->new)
+			fput(p->new);
+		else
+			break;
+	kfree(fpair);
+out:
+	return err;
+}
+
+void au_xino_clr(struct super_block *sb)
+{
+	struct au_sbinfo *sbinfo;
+
+	au_xigen_clr(sb);
+	xino_clear_xib(sb);
+	xino_clear_br(sb);
+	sbinfo = au_sbi(sb);
+	/* lvalue, do not call au_mntflags() */
+	au_opt_clr(sbinfo->si_mntflags, XINO);
+}
+
+int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount)
+{
+	int err, skip;
+	struct dentry *parent, *cur_parent;
+	struct qstr *dname, *cur_name;
+	struct file *cur_xino;
+	struct inode *dir;
+	struct au_sbinfo *sbinfo;
+
+	SiMustWriteLock(sb);
+
+	err = 0;
+	sbinfo = au_sbi(sb);
+	parent = dget_parent(xino->file->f_path.dentry);
+	if (remount) {
+		skip = 0;
+		dname = &xino->file->f_path.dentry->d_name;
+		cur_xino = sbinfo->si_xib;
+		if (cur_xino) {
+			cur_parent = dget_parent(cur_xino->f_path.dentry);
+			cur_name = &cur_xino->f_path.dentry->d_name;
+			skip = (cur_parent == parent
+				&& au_qstreq(dname, cur_name));
+			dput(cur_parent);
+		}
+		if (skip)
+			goto out;
+	}
+
+	au_opt_set(sbinfo->si_mntflags, XINO);
+	dir = d_inode(parent);
+	mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT);
+	/* mnt_want_write() is unnecessary here */
+	err = au_xino_set_xib(sb, xino->file);
+	if (!err)
+		err = au_xigen_set(sb, xino->file);
+	if (!err)
+		err = au_xino_set_br(sb, xino->file);
+	mutex_unlock(&dir->i_mutex);
+	if (!err)
+		goto out; /* success */
+
+	/* reset all */
+	AuIOErr("failed creating xino(%d).\n", err);
+	au_xigen_clr(sb);
+	xino_clear_xib(sb);
+
+out:
+	dput(parent);
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * create a xinofile at the default place/path.
+ */
+struct file *au_xino_def(struct super_block *sb)
+{
+	struct file *file;
+	char *page, *p;
+	struct au_branch *br;
+	struct super_block *h_sb;
+	struct path path;
+	aufs_bindex_t bend, bindex, bwr;
+
+	br = NULL;
+	bend = au_sbend(sb);
+	bwr = -1;
+	for (bindex = 0; bindex <= bend; bindex++) {
+		br = au_sbr(sb, bindex);
+		if (au_br_writable(br->br_perm)
+		    && !au_test_fs_bad_xino(au_br_sb(br))) {
+			bwr = bindex;
+			break;
+		}
+	}
+
+	if (bwr >= 0) {
+		file = ERR_PTR(-ENOMEM);
+		page = (void *)__get_free_page(GFP_NOFS);
+		if (unlikely(!page))
+			goto out;
+		path.mnt = au_br_mnt(br);
+		path.dentry = au_h_dptr(sb->s_root, bwr);
+		p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME));
+		file = (void *)p;
+		if (!IS_ERR(p)) {
+			strcat(p, "/" AUFS_XINO_FNAME);
+			AuDbg("%s\n", p);
+			file = au_xino_create(sb, p, /*silent*/0);
+			if (!IS_ERR(file))
+				au_xino_brid_set(sb, br->br_id);
+		}
+		free_page((unsigned long)page);
+	} else {
+		file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0);
+		if (IS_ERR(file))
+			goto out;
+		h_sb = file->f_path.dentry->d_sb;
+		if (unlikely(au_test_fs_bad_xino(h_sb))) {
+			pr_err("xino doesn't support %s(%s)\n",
+			       AUFS_XINO_DEFPATH, au_sbtype(h_sb));
+			fput(file);
+			file = ERR_PTR(-EINVAL);
+		}
+		if (!IS_ERR(file))
+			au_xino_brid_set(sb, -1);
+	}
+
+out:
+	return file;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_xino_path(struct seq_file *seq, struct file *file)
+{
+	int err;
+
+	err = au_seq_path(seq, &file->f_path);
+	if (unlikely(err))
+		goto out;
+
+#define Deleted "\\040(deleted)"
+	seq->count -= sizeof(Deleted) - 1;
+	AuDebugOn(memcmp(seq->buf + seq->count, Deleted,
+			 sizeof(Deleted) - 1));
+#undef Deleted
+
+out:
+	return err;
+}
--- linux-4.4.0.orig/fs/autofs4/autofs_i.h
+++ linux-4.4.0/fs/autofs4/autofs_i.h
@@ -18,6 +18,7 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/magic.h>
 
 /* This is the range of ioctl() numbers we claim as ours */
 #define AUTOFS_IOC_FIRST     AUTOFS_IOC_READY
@@ -79,9 +80,13 @@
 };
 
 #define AUTOFS_INF_EXPIRING	(1<<0) /* dentry is in the process of expiring */
-#define AUTOFS_INF_NO_RCU	(1<<1) /* the dentry is being considered
+#define AUTOFS_INF_WANT_EXPIRE	(1<<1) /* the dentry is being considered
 					* for expiry, so RCU_walk is
-					* not permitted
+					* not permitted.  If it progresses to
+					* actual expiry attempt, the flag is
+					* not cleared when EXPIRING is set -
+					* in that case it gets cleared only
+					* when it comes to clearing EXPIRING.
 					*/
 #define AUTOFS_INF_PENDING	(1<<2) /* dentry pending mount */
 
@@ -131,7 +136,8 @@
 
 static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb)
 {
-	return (struct autofs_sb_info *)(sb->s_fs_info);
+	return sb->s_magic != AUTOFS_SUPER_MAGIC ?
+		NULL : (struct autofs_sb_info *)(sb->s_fs_info);
 }
 
 static inline struct autofs_info *autofs4_dentry_ino(struct dentry *dentry)
--- linux-4.4.0.orig/fs/autofs4/dev-ioctl.c
+++ linux-4.4.0/fs/autofs4/dev-ioctl.c
@@ -331,7 +331,7 @@
 	int status;
 
 	token = (autofs_wqt_t) param->fail.token;
-	status = param->fail.status ? param->fail.status : -ENOENT;
+	status = param->fail.status < 0 ? param->fail.status : -ENOENT;
 	return autofs4_wait_release(sbi, token, status);
 }
 
--- linux-4.4.0.orig/fs/autofs4/expire.c
+++ linux-4.4.0/fs/autofs4/expire.c
@@ -315,19 +315,17 @@
 	if (ino->flags & AUTOFS_INF_PENDING)
 		goto out;
 	if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
-		ino->flags |= AUTOFS_INF_NO_RCU;
+		ino->flags |= AUTOFS_INF_WANT_EXPIRE;
 		spin_unlock(&sbi->fs_lock);
 		synchronize_rcu();
 		spin_lock(&sbi->fs_lock);
 		if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
 			ino->flags |= AUTOFS_INF_EXPIRING;
-			smp_mb();
-			ino->flags &= ~AUTOFS_INF_NO_RCU;
 			init_completion(&ino->expire_complete);
 			spin_unlock(&sbi->fs_lock);
 			return root;
 		}
-		ino->flags &= ~AUTOFS_INF_NO_RCU;
+		ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
 	}
 out:
 	spin_unlock(&sbi->fs_lock);
@@ -417,6 +415,7 @@
 	}
 	return NULL;
 }
+
 /*
  * Find an eligible tree to time-out
  * A tree is eligible if :-
@@ -432,6 +431,7 @@
 	struct dentry *root = sb->s_root;
 	struct dentry *dentry;
 	struct dentry *expired;
+	struct dentry *found;
 	struct autofs_info *ino;
 
 	if (!root)
@@ -442,48 +442,55 @@
 
 	dentry = NULL;
 	while ((dentry = get_next_positive_subdir(dentry, root))) {
+		int flags = how;
+
 		spin_lock(&sbi->fs_lock);
 		ino = autofs4_dentry_ino(dentry);
-		if (ino->flags & AUTOFS_INF_NO_RCU)
-			expired = NULL;
-		else
-			expired = should_expire(dentry, mnt, timeout, how);
-		if (!expired) {
+		if (ino->flags & AUTOFS_INF_WANT_EXPIRE) {
 			spin_unlock(&sbi->fs_lock);
 			continue;
 		}
+		spin_unlock(&sbi->fs_lock);
+
+		expired = should_expire(dentry, mnt, timeout, flags);
+		if (!expired)
+			continue;
+
+		spin_lock(&sbi->fs_lock);
 		ino = autofs4_dentry_ino(expired);
-		ino->flags |= AUTOFS_INF_NO_RCU;
+		ino->flags |= AUTOFS_INF_WANT_EXPIRE;
 		spin_unlock(&sbi->fs_lock);
 		synchronize_rcu();
-		spin_lock(&sbi->fs_lock);
-		if (should_expire(expired, mnt, timeout, how)) {
-			if (expired != dentry)
-				dput(dentry);
-			goto found;
+
+		/* Make sure a reference is not taken on found if
+		 * things have changed.
+		 */
+		flags &= ~AUTOFS_EXP_LEAVES;
+		found = should_expire(expired, mnt, timeout, how);
+		if (found != expired) { // something has changed, continue
+			dput(found);
+			goto next;
 		}
 
-		ino->flags &= ~AUTOFS_INF_NO_RCU;
 		if (expired != dentry)
-			dput(expired);
+			dput(dentry);
+
+		spin_lock(&sbi->fs_lock);
+		goto found;
+next:
+		spin_lock(&sbi->fs_lock);
+		ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
 		spin_unlock(&sbi->fs_lock);
+		if (expired != dentry)
+			dput(expired);
 	}
 	return NULL;
 
 found:
 	DPRINTK("returning %p %pd", expired, expired);
 	ino->flags |= AUTOFS_INF_EXPIRING;
-	smp_mb();
-	ino->flags &= ~AUTOFS_INF_NO_RCU;
 	init_completion(&ino->expire_complete);
 	spin_unlock(&sbi->fs_lock);
-	spin_lock(&sbi->lookup_lock);
-	spin_lock(&expired->d_parent->d_lock);
-	spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
-	list_move(&expired->d_parent->d_subdirs, &expired->d_child);
-	spin_unlock(&expired->d_lock);
-	spin_unlock(&expired->d_parent->d_lock);
-	spin_unlock(&sbi->lookup_lock);
 	return expired;
 }
 
@@ -492,15 +499,27 @@
 	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
 	int status;
+	int state;
 
 	/* Block on any pending expire */
-	if (!(ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU)))
+	if (!(ino->flags & AUTOFS_INF_WANT_EXPIRE))
 		return 0;
 	if (rcu_walk)
 		return -ECHILD;
 
+retry:
 	spin_lock(&sbi->fs_lock);
-	if (ino->flags & AUTOFS_INF_EXPIRING) {
+	state = ino->flags & (AUTOFS_INF_WANT_EXPIRE | AUTOFS_INF_EXPIRING);
+	if (state == AUTOFS_INF_WANT_EXPIRE) {
+		spin_unlock(&sbi->fs_lock);
+		/*
+		 * Possibly being selected for expire, wait until
+		 * it's selected or not.
+		 */
+		schedule_timeout_uninterruptible(HZ/10);
+		goto retry;
+	}
+	if (state & AUTOFS_INF_EXPIRING) {
 		spin_unlock(&sbi->fs_lock);
 
 		DPRINTK("waiting for expire %p name=%pd", dentry, dentry);
@@ -542,7 +561,6 @@
 	pkt.len = dentry->d_name.len;
 	memcpy(pkt.name, dentry->d_name.name, pkt.len);
 	pkt.name[pkt.len] = '\0';
-	dput(dentry);
 
 	if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
 		ret = -EFAULT;
@@ -551,10 +569,12 @@
 	ino = autofs4_dentry_ino(dentry);
 	/* avoid rapid-fire expire attempts if expiry fails */
 	ino->last_used = now;
-	ino->flags &= ~AUTOFS_INF_EXPIRING;
+	ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
 	complete_all(&ino->expire_complete);
 	spin_unlock(&sbi->fs_lock);
 
+	dput(dentry);
+
 	return ret;
 }
 
@@ -579,7 +599,7 @@
 		spin_lock(&sbi->fs_lock);
 		/* avoid rapid-fire expire attempts if expiry fails */
 		ino->last_used = now;
-		ino->flags &= ~AUTOFS_INF_EXPIRING;
+		ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
 		complete_all(&ino->expire_complete);
 		spin_unlock(&sbi->fs_lock);
 		dput(dentry);
--- linux-4.4.0.orig/fs/autofs4/inode.c
+++ linux-4.4.0/fs/autofs4/inode.c
@@ -18,7 +18,6 @@
 #include <linux/pagemap.h>
 #include <linux/parser.h>
 #include <linux/bitops.h>
-#include <linux/magic.h>
 #include "autofs_i.h"
 #include <linux/module.h>
 
@@ -256,8 +255,10 @@
 	}
 	root_inode = autofs4_get_inode(s, S_IFDIR | 0755);
 	root = d_make_root(root_inode);
-	if (!root)
+	if (!root) {
+		ret = -ENOMEM;
 		goto fail_ino;
+	}
 	pipe = NULL;
 
 	root->d_fsdata = ino;
--- linux-4.4.0.orig/fs/autofs4/root.c
+++ linux-4.4.0/fs/autofs4/root.c
@@ -455,7 +455,7 @@
 		 * a mount-trap.
 		 */
 		struct inode *inode;
-		if (ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU))
+		if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
 			return 0;
 		if (d_mountpoint(dentry))
 			return 0;
@@ -746,7 +746,7 @@
 
 	autofs4_del_active(dentry);
 
-	inode = autofs4_get_inode(dir->i_sb, S_IFDIR | 0555);
+	inode = autofs4_get_inode(dir->i_sb, S_IFDIR | mode);
 	if (!inode)
 		return -ENOMEM;
 	d_add(dentry, inode);
--- linux-4.4.0.orig/fs/autofs4/waitq.c
+++ linux-4.4.0/fs/autofs4/waitq.c
@@ -87,7 +87,8 @@
 		spin_unlock_irqrestore(&current->sighand->siglock, flags);
 	}
 
-	return (bytes > 0);
+	/* if 'wr' returned 0 (impossible) we assume -EIO (safe) */
+	return bytes == 0 ? 0 : wr < 0 ? wr : -EIO;
 }
 	
 static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
@@ -101,6 +102,7 @@
 	} pkt;
 	struct file *pipe = NULL;
 	size_t pktsz;
+	int ret;
 
 	DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d",
 		(unsigned long) wq->wait_queue_token, wq->name.len, wq->name.name, type);
@@ -172,8 +174,18 @@
 
 	mutex_unlock(&sbi->wq_mutex);
 
-	if (autofs4_write(sbi, pipe, &pkt, pktsz))
+	switch (ret = autofs4_write(sbi, pipe, &pkt, pktsz)) {
+	case 0:
+		break;
+	case -ENOMEM:
+	case -ERESTARTSYS:
+		/* Just fail this one */
+		autofs4_wait_release(sbi, wq->wait_queue_token, ret);
+		break;
+	default:
 		autofs4_catatonic_mode(sbi);
+		break;
+	}
 	fput(pipe);
 }
 
@@ -427,8 +439,8 @@
 		memcpy(&wq->name, &qstr, sizeof(struct qstr));
 		wq->dev = autofs4_get_dev(sbi);
 		wq->ino = autofs4_get_ino(sbi);
-		wq->uid = current_uid();
-		wq->gid = current_gid();
+		wq->uid = current_cred()->uid;
+		wq->gid = current_cred()->gid;
 		wq->pid = pid;
 		wq->tgid = tgid;
 		wq->status = -EINTR; /* Status return if interrupted */
--- linux-4.4.0.orig/fs/bfs/inode.c
+++ linux-4.4.0/fs/bfs/inode.c
@@ -350,7 +350,8 @@
 
 	s->s_magic = BFS_MAGIC;
 
-	if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end)) {
+	if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) ||
+	    le32_to_cpu(bfs_sb->s_start) < BFS_BSIZE) {
 		printf("Superblock is corrupted\n");
 		goto out1;
 	}
@@ -359,9 +360,11 @@
 					sizeof(struct bfs_inode)
 					+ BFS_ROOT_INO - 1;
 	imap_len = (info->si_lasti / 8) + 1;
-	info->si_imap = kzalloc(imap_len, GFP_KERNEL);
-	if (!info->si_imap)
+	info->si_imap = kzalloc(imap_len, GFP_KERNEL | __GFP_NOWARN);
+	if (!info->si_imap) {
+		printf("Cannot allocate %u bytes\n", imap_len);
 		goto out1;
+	}
 	for (i = 0; i < BFS_ROOT_INO; i++)
 		set_bit(i, info->si_imap);
 
--- linux-4.4.0.orig/fs/binfmt_elf.c
+++ linux-4.4.0/fs/binfmt_elf.c
@@ -604,28 +604,30 @@
 			 * Do the same thing for the memory mapping - between
 			 * elf_bss and last_bss is the bss section.
 			 */
-			k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+			k = load_addr + eppnt->p_vaddr + eppnt->p_memsz;
 			if (k > last_bss)
 				last_bss = k;
 		}
 	}
 
+	/*
+	 * Now fill out the bss section: first pad the last page from
+	 * the file up to the page boundary, and zero it from elf_bss
+	 * up to the end of the page.
+	 */
+	if (padzero(elf_bss)) {
+		error = -EFAULT;
+		goto out;
+	}
+	/*
+	 * Next, align both the file and mem bss up to the page size,
+	 * since this is where elf_bss was just zeroed up to, and where
+	 * last_bss will end after the vm_brk() below.
+	 */
+	elf_bss = ELF_PAGEALIGN(elf_bss);
+	last_bss = ELF_PAGEALIGN(last_bss);
+	/* Finally, if there is still more bss to allocate, do it. */
 	if (last_bss > elf_bss) {
-		/*
-		 * Now fill out the bss section.  First pad the last page up
-		 * to the page boundary, and then perform a mmap to make sure
-		 * that there are zero-mapped pages up to and including the
-		 * last bss page.
-		 */
-		if (padzero(elf_bss)) {
-			error = -EFAULT;
-			goto out;
-		}
-
-		/* What we have mapped so far */
-		elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);
-
-		/* Map the last of the bss segment */
 		error = vm_brk(elf_bss, last_bss - elf_bss);
 		if (BAD_ADDR(error))
 			goto out;
@@ -844,10 +846,12 @@
 	if (elf_read_implies_exec(loc->elf_ex, executable_stack))
 		current->personality |= READ_IMPLIES_EXEC;
 
-	if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+	const int snapshot_randomize_va_space = READ_ONCE(randomize_va_space);
+	if (!(current->personality & ADDR_NO_RANDOMIZE) && snapshot_randomize_va_space)
 		current->flags |= PF_RANDOMIZE;
 
 	setup_new_exec(bprm);
+	install_exec_creds(bprm);
 
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
@@ -905,17 +909,60 @@
 		elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
 
 		vaddr = elf_ppnt->p_vaddr;
+		/*
+		 * If we are loading ET_EXEC or we have already performed
+		 * the ET_DYN load_addr calculations, proceed normally.
+		 */
 		if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
 			elf_flags |= MAP_FIXED;
 		} else if (loc->elf_ex.e_type == ET_DYN) {
-			/* Try and get dynamic programs out of the way of the
-			 * default mmap base, as well as whatever program they
-			 * might try to exec.  This is because the brk will
-			 * follow the loader, and is not movable.  */
-			load_bias = ELF_ET_DYN_BASE - vaddr;
-			if (current->flags & PF_RANDOMIZE)
-				load_bias += arch_mmap_rnd();
-			load_bias = ELF_PAGESTART(load_bias);
+			/*
+			 * This logic is run once for the first LOAD Program
+			 * Header for ET_DYN binaries to calculate the
+			 * randomization (load_bias) for all the LOAD
+			 * Program Headers, and to calculate the entire
+			 * size of the ELF mapping (total_size). (Note that
+			 * load_addr_set is set to true later once the
+			 * initial mapping is performed.)
+			 *
+			 * There are effectively two types of ET_DYN
+			 * binaries: programs (i.e. PIE: ET_DYN with INTERP)
+			 * and loaders (ET_DYN without INTERP, since they
+			 * _are_ the ELF interpreter). The loaders must
+			 * be loaded away from programs since the program
+			 * may otherwise collide with the loader (especially
+			 * for ET_EXEC which does not have a randomized
+			 * position). For example to handle invocations of
+			 * "./ld.so someprog" to test out a new version of
+			 * the loader, the subsequent program that the
+			 * loader loads must avoid the loader itself, so
+			 * they cannot share the same load range. Sufficient
+			 * room for the brk must be allocated with the
+			 * loader as well, since brk must be available with
+			 * the loader.
+			 *
+			 * Therefore, programs are loaded offset from
+			 * ELF_ET_DYN_BASE and loaders are loaded into the
+			 * independently randomized mmap region (0 load_bias
+			 * without MAP_FIXED).
+			 */
+			if (elf_interpreter) {
+				load_bias = ELF_ET_DYN_BASE;
+				if (current->flags & PF_RANDOMIZE)
+					load_bias += arch_mmap_rnd();
+				elf_flags |= MAP_FIXED;
+			} else
+				load_bias = 0;
+
+			/*
+			 * Since load_bias is used for all subsequent loading
+			 * calculations, we must lower it by the first vaddr
+			 * so that the remaining calculations based on the
+			 * ELF vaddrs will be correctly offset. The result
+			 * is then page aligned.
+			 */
+			load_bias = ELF_PAGESTART(load_bias - vaddr);
+
 			total_size = total_mapping_size(elf_phdata,
 							loc->elf_ex.e_phnum);
 			if (!total_size) {
@@ -1039,7 +1086,6 @@
 		goto out;
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
-	install_exec_creds(bprm);
 	retval = create_elf_tables(bprm, &loc->elf_ex,
 			  load_addr, interp_load_addr);
 	if (retval < 0)
@@ -1051,7 +1097,19 @@
 	current->mm->end_data = end_data;
 	current->mm->start_stack = bprm->p;
 
-	if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) {
+	if ((current->flags & PF_RANDOMIZE) && (snapshot_randomize_va_space > 1)) {
+		/*
+		 * For architectures with ELF randomization, when executing
+		 * a loader directly (i.e. no interpreter listed in ELF
+		 * headers), move the brk area out of the mmap region
+		 * (since it grows up, and may collide early with the stack
+		 * growing down), and into the unused ELF_ET_DYN_BASE region.
+		 */
+		if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) &&
+		    loc->elf_ex.e_type == ET_DYN && !interpreter)
+			current->mm->brk = current->mm->start_brk =
+				ELF_ET_DYN_BASE;
+
 		current->mm->brk = current->mm->start_brk =
 			arch_randomize_brk(current->mm);
 #ifdef compat_brk_randomized
@@ -1169,11 +1227,13 @@
 		goto out_free_ph;
 	}
 
-	len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr +
-			    ELF_MIN_ALIGN - 1);
-	bss = eppnt->p_memsz + eppnt->p_vaddr;
-	if (bss > len)
-		vm_brk(len, bss - len);
+	len = ELF_PAGEALIGN(eppnt->p_filesz + eppnt->p_vaddr);
+	bss = ELF_PAGEALIGN(eppnt->p_memsz + eppnt->p_vaddr);
+	if (bss > len) {
+		error = vm_brk(len, bss - len);
+		if (BAD_ADDR(error))
+			goto out_free_ph;
+	}
 	error = 0;
 
 out_free_ph:
@@ -1664,10 +1724,10 @@
 		const struct user_regset *regset = &view->regsets[i];
 		do_thread_regset_writeback(t->task, regset);
 		if (regset->core_note_type && regset->get &&
-		    (!regset->active || regset->active(t->task, regset))) {
+		    (!regset->active || regset->active(t->task, regset) > 0)) {
 			int ret;
 			size_t size = regset->n * regset->size;
-			void *data = kmalloc(size, GFP_KERNEL);
+			void *data = kzalloc(size, GFP_KERNEL);
 			if (unlikely(!data))
 				return 0;
 			ret = regset->get(t->task, regset,
@@ -2295,6 +2355,7 @@
 				goto end_coredump;
 		}
 	}
+	dump_truncate(cprm);
 
 	if (!elf_core_write_extra_data(cprm))
 		goto end_coredump;
--- linux-4.4.0.orig/fs/binfmt_flat.c
+++ linux-4.4.0/fs/binfmt_flat.c
@@ -808,9 +808,14 @@
 
 static int load_flat_shared_library(int id, struct lib_info *libs)
 {
+	/*
+	 * This is a fake bprm struct; only the members "buf", "file" and
+	 * "filename" are actually used.
+	 */
 	struct linux_binprm bprm;
 	int res;
 	char buf[16];
+	loff_t pos = 0;
 
 	memset(&bprm, 0, sizeof(bprm));
 
@@ -824,25 +829,10 @@
 	if (IS_ERR(bprm.file))
 		return res;
 
-	bprm.cred = prepare_exec_creds();
-	res = -ENOMEM;
-	if (!bprm.cred)
-		goto out;
-
-	/* We don't really care about recalculating credentials at this point
-	 * as we're past the point of no return and are dealing with shared
-	 * libraries.
-	 */
-	bprm.cred_prepared = 1;
-
-	res = prepare_binprm(&bprm);
-
-	if (!IS_ERR_VALUE(res))
+	res = kernel_read(bprm.file, pos, bprm.buf, BINPRM_BUF_SIZE);
+	if (res >= 0)
 		res = load_flat_file(&bprm, libs, id, NULL);
 
-	abort_creds(bprm.cred);
-
-out:
 	allow_write_access(bprm.file);
 	fput(bprm.file);
 
--- linux-4.4.0.orig/fs/binfmt_misc.c
+++ linux-4.4.0/fs/binfmt_misc.c
@@ -369,8 +369,13 @@
 		s = strchr(p, del);
 		if (!s)
 			goto einval;
-		*s++ = '\0';
-		e->offset = simple_strtoul(p, &p, 10);
+		*s = '\0';
+		if (p != s) {
+			int r = kstrtoint(p, 10, &e->offset);
+			if (r != 0 || e->offset < 0)
+				goto einval;
+		}
+		p = s;
 		if (*p++)
 			goto einval;
 		pr_debug("register: offset: %#x\n", e->offset);
@@ -410,7 +415,8 @@
 		if (e->mask &&
 		    string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size)
 			goto einval;
-		if (e->size + e->offset > BINPRM_BUF_SIZE)
+		if (e->size > BINPRM_BUF_SIZE ||
+		    BINPRM_BUF_SIZE - e->size < e->offset)
 			goto einval;
 		pr_debug("register: magic/mask length: %i\n", e->size);
 		if (USE_DEBUG) {
--- linux-4.4.0.orig/fs/binfmt_script.c
+++ linux-4.4.0/fs/binfmt_script.c
@@ -14,14 +14,31 @@
 #include <linux/err.h>
 #include <linux/fs.h>
 
+static inline bool spacetab(char c) { return c == ' ' || c == '\t'; }
+static inline char *next_non_spacetab(char *first, const char *last)
+{
+	for (; first <= last; first++)
+		if (!spacetab(*first))
+			return first;
+	return NULL;
+}
+static inline char *next_terminator(char *first, const char *last)
+{
+	for (; first <= last; first++)
+		if (spacetab(*first) || !*first)
+			return first;
+	return NULL;
+}
+
 static int load_script(struct linux_binprm *bprm)
 {
 	const char *i_arg, *i_name;
-	char *cp;
+	char *cp, *buf_end;
 	struct file *file;
 	char interp[BINPRM_BUF_SIZE];
 	int retval;
 
+	/* Not ours to exec if we don't start with "#!". */
 	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
 		return -ENOEXEC;
 
@@ -34,18 +51,40 @@
 	if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE)
 		return -ENOENT;
 
-	/*
-	 * This section does the #! interpretation.
-	 * Sorta complicated, but hopefully it will work.  -TYT
-	 */
-
+	/* Release since we are not mapping a binary into memory. */
 	allow_write_access(bprm->file);
 	fput(bprm->file);
 	bprm->file = NULL;
 
-	bprm->buf[BINPRM_BUF_SIZE - 1] = '\0';
-	if ((cp = strchr(bprm->buf, '\n')) == NULL)
-		cp = bprm->buf+BINPRM_BUF_SIZE-1;
+	/*
+	 * This section handles parsing the #! line into separate
+	 * interpreter path and argument strings. We must be careful
+	 * because bprm->buf is not yet guaranteed to be NUL-terminated
+	 * (though the buffer will have trailing NUL padding when the
+	 * file size was smaller than the buffer size).
+	 *
+	 * We do not want to exec a truncated interpreter path, so either
+	 * we find a newline (which indicates nothing is truncated), or
+	 * we find a space/tab/NUL after the interpreter path (which
+	 * itself may be preceded by spaces/tabs). Truncating the
+	 * arguments is fine: the interpreter can re-read the script to
+	 * parse them on its own.
+	 */
+	buf_end = bprm->buf + sizeof(bprm->buf) - 1;
+	cp = strnchr(bprm->buf, sizeof(bprm->buf), '\n');
+	if (!cp) {
+		cp = next_non_spacetab(bprm->buf + 2, buf_end);
+		if (!cp)
+			return -ENOEXEC; /* Entire buf is spaces/tabs */
+		/*
+		 * If there is no later space/tab/NUL we must assume the
+		 * interpreter path is truncated.
+		 */
+		if (!next_terminator(cp, buf_end))
+			return -ENOEXEC;
+		cp = buf_end;
+	}
+	/* NUL-terminate the buffer and any trailing spaces/tabs. */
 	*cp = '\0';
 	while (cp > bprm->buf) {
 		cp--;
--- linux-4.4.0.orig/fs/block_dev.c
+++ linux-4.4.0/fs/block_dev.c
@@ -88,12 +88,11 @@
 {
 	struct address_space *mapping = bdev->bd_inode->i_mapping;
 
-	if (mapping->nrpages == 0)
-		return;
-
-	invalidate_bh_lrus();
-	lru_add_drain_all();	/* make sure all lru add caches are flushed */
-	invalidate_mapping_pages(mapping, 0, -1);
+	if (mapping->nrpages) {
+		invalidate_bh_lrus();
+		lru_add_drain_all();	/* make sure all lru add caches are flushed */
+		invalidate_mapping_pages(mapping, 0, -1);
+	}
 	/* 99% of the time, we don't need to flush the cleancache on the bdev.
 	 * But, for the strange corners, lets be cautious
 	 */
@@ -395,7 +394,7 @@
 	if (!ops->rw_page || bdev_get_integrity(bdev))
 		return result;
 
-	result = blk_queue_enter(bdev->bd_queue, GFP_KERNEL);
+	result = blk_queue_enter(bdev->bd_queue, false);
 	if (result)
 		return result;
 	result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ);
@@ -432,7 +431,7 @@
 
 	if (!ops->rw_page || bdev_get_integrity(bdev))
 		return -EOPNOTSUPP;
-	result = blk_queue_enter(bdev->bd_queue, GFP_KERNEL);
+	result = blk_queue_enter(bdev->bd_queue, false);
 	if (result)
 		return result;
 
@@ -533,6 +532,7 @@
 #ifdef CONFIG_SYSFS
 	INIT_LIST_HEAD(&bdev->bd_holder_disks);
 #endif
+	bdev->bd_bdi = &noop_backing_dev_info;
 	inode_init_once(&ei->vfs_inode);
 	/* Initialize mutex for freeze. */
 	mutex_init(&bdev->bd_fsfreeze_mutex);
@@ -558,6 +558,12 @@
 	}
 	list_del_init(&bdev->bd_list);
 	spin_unlock(&bdev_lock);
+	/* Detach inode from wb early as bdi_put() may free bdi->wb */
+	inode_detach_wb(inode);
+	if (bdev->bd_bdi != &noop_backing_dev_info) {
+		bdi_put(bdev->bd_bdi);
+		bdev->bd_bdi = &noop_backing_dev_info;
+	}
 }
 
 static const struct super_operations bdev_sops = {
@@ -624,6 +630,21 @@
 
 static LIST_HEAD(all_bdevs);
 
+/*
+ * If there is a bdev inode for this device, unhash it so that it gets evicted
+ * as soon as last inode reference is dropped.
+ */
+void bdev_unhash_inode(dev_t dev)
+{
+	struct inode *inode;
+
+	inode = ilookup5(blockdev_superblock, hash(dev), bdev_test, &dev);
+	if (inode) {
+		remove_inode_hash(inode);
+		iput(inode);
+	}
+}
+
 struct block_device *bdget(dev_t dev)
 {
 	struct block_device *bdev;
@@ -695,13 +716,22 @@
 
 	spin_lock(&bdev_lock);
 	bdev = inode->i_bdev;
-	if (bdev) {
+	if (bdev && !inode_unhashed(bdev->bd_inode)) {
 		ihold(bdev->bd_inode);
 		spin_unlock(&bdev_lock);
 		return bdev;
 	}
 	spin_unlock(&bdev_lock);
 
+	/*
+	 * i_bdev references block device inode that was already shut down
+	 * (corresponding device got removed).  Remove the reference and look
+	 * up block device inode again just in case new device got
+	 * reestablished under the same device number.
+	 */
+	if (bdev)
+		bd_forget(inode);
+
 	bdev = bdget(inode->i_rdev);
 	if (bdev) {
 		spin_lock(&bdev_lock);
@@ -759,7 +789,7 @@
 		return true;	 /* already a holder */
 	else if (bdev->bd_holder != NULL)
 		return false; 	 /* held by someone else */
-	else if (bdev->bd_contains == bdev)
+	else if (whole == bdev)
 		return true;  	 /* is a whole device which isn't held */
 
 	else if (whole->bd_holder == bd_may_claim)
@@ -1098,7 +1128,6 @@
 
 	if (disk->fops->revalidate_disk)
 		ret = disk->fops->revalidate_disk(disk);
-	blk_integrity_revalidate(disk);
 	bdev = bdget_disk(disk, 0);
 	if (!bdev)
 		return ret;
@@ -1183,10 +1212,8 @@
 	 */
 	if (!for_part) {
 		ret = devcgroup_inode_permission(bdev->bd_inode, perm);
-		if (ret != 0) {
-			bdput(bdev);
+		if (ret != 0)
 			return ret;
-		}
 	}
 
  restart:
@@ -1204,6 +1231,7 @@
 		bdev->bd_queue = disk->queue;
 		bdev->bd_contains = bdev;
 		bdev->bd_inode->i_flags = disk->fops->direct_access ? S_DAX : 0;
+
 		if (!partno) {
 			ret = -ENXIO;
 			bdev->bd_part = disk_get_part(disk, partno);
@@ -1255,8 +1283,10 @@
 				goto out_clear;
 			BUG_ON(for_part);
 			ret = __blkdev_get(whole, mode, 1);
-			if (ret)
+			if (ret) {
+				bdput(whole);
 				goto out_clear;
+			}
 			bdev->bd_contains = whole;
 			bdev->bd_part = disk_get_part(disk, partno);
 			if (!(disk->flags & GENHD_FL_UP) ||
@@ -1273,6 +1303,9 @@
 			    (bdev->bd_part->nr_sects % (PAGE_SIZE / 512)))
 				bdev->bd_inode->i_flags &= ~S_DAX;
 		}
+
+		if (bdev->bd_bdi == &noop_backing_dev_info)
+			bdev->bd_bdi = bdi_get(disk->queue->backing_dev_info);
 	} else {
 		if (bdev->bd_contains == bdev) {
 			ret = 0;
@@ -1313,7 +1346,6 @@
 	put_disk(disk);
 	module_put(owner);
  out:
-	bdput(bdev);
 
 	return ret;
 }
@@ -1399,6 +1431,9 @@
 		bdput(whole);
 	}
 
+	if (res)
+		bdput(bdev);
+
 	return res;
 }
 EXPORT_SYMBOL(blkdev_get);
@@ -1424,9 +1459,14 @@
 					void *holder)
 {
 	struct block_device *bdev;
+	int perm = 0;
 	int err;
 
-	bdev = lookup_bdev(path);
+	if (mode & FMODE_READ)
+		perm |= MAY_READ;
+	if (mode & FMODE_WRITE)
+		perm |= MAY_WRITE;
+	bdev = lookup_bdev(path, perm);
 	if (IS_ERR(bdev))
 		return bdev;
 
@@ -1505,6 +1545,20 @@
 	if (bdev == NULL)
 		return -ENOMEM;
 
+	/*
+	 * A negative i_writecount for bdev->bd_inode means that the bdev
+	 * or one of its paritions is mounted in a user namespace. Deny
+	 * writing for non-root in this case, otherwise an unprivileged
+	 * user can attack the kernel by modifying the backing store of a
+	 * mounted filesystem.
+	 */
+	if ((filp->f_mode & FMODE_WRITE) &&
+	    !file_ns_capable(filp, &init_user_ns, CAP_SYS_ADMIN) &&
+	    !atomic_inc_unless_negative(&bdev->bd_inode->i_writecount)) {
+		bdput(bdev);
+		return -EBUSY;
+	}
+
 	filp->f_mapping = bdev->bd_inode->i_mapping;
 
 	return blkdev_get(bdev, filp->f_mode, filp);
@@ -1515,6 +1569,16 @@
 	struct gendisk *disk = bdev->bd_disk;
 	struct block_device *victim = NULL;
 
+	/*
+	 * Sync early if it looks like we're the last one.  If someone else
+	 * opens the block device between now and the decrement of bd_openers
+	 * then we did a sync that we didn't need to, but that's not the end
+	 * of the world and we want to avoid long (could be several minute)
+	 * syncs while holding the mutex.
+	 */
+	if (bdev->bd_openers == 1)
+		sync_blockdev(bdev);
+
 	mutex_lock_nested(&bdev->bd_mutex, for_part);
 	if (for_part)
 		bdev->bd_part_count--;
@@ -1525,12 +1589,6 @@
 		kill_bdev(bdev);
 
 		bdev_write_inode(bdev);
-		/*
-		 * Detaching bdev inode from its wb in __destroy_inode()
-		 * is too late: the queue which embeds its bdi (along with
-		 * root wb) can be gone as soon as we put_disk() below.
-		 */
-		inode_detach_wb(bdev->bd_inode);
 	}
 	if (bdev->bd_contains == bdev) {
 		if (disk->fops->release)
@@ -1606,6 +1664,9 @@
 static int blkdev_close(struct inode * inode, struct file * filp)
 {
 	struct block_device *bdev = I_BDEV(filp->f_mapping->host);
+	if (filp->f_mode & FMODE_WRITE &&
+	    !file_ns_capable(filp, &init_user_ns, CAP_SYS_ADMIN))
+		atomic_dec(&bdev->bd_inode->i_writecount);
 	blkdev_put(bdev, filp->f_mode);
 	return 0;
 }
@@ -1739,12 +1800,14 @@
 /**
  * lookup_bdev  - lookup a struct block_device by name
  * @pathname:	special file representing the block device
+ * @mask:	rights to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
  *
  * Get a reference to the blockdevice at @pathname in the current
  * namespace if possible and return it.  Return ERR_PTR(error)
- * otherwise.
+ * otherwise.  If @mask is non-zero, check for access rights to the
+ * inode at @pathname.
  */
-struct block_device *lookup_bdev(const char *pathname)
+struct block_device *lookup_bdev(const char *pathname, int mask)
 {
 	struct block_device *bdev;
 	struct inode *inode;
@@ -1759,6 +1822,11 @@
 		return ERR_PTR(error);
 
 	inode = d_backing_inode(path.dentry);
+	if (mask != 0 && !capable(CAP_SYS_ADMIN)) {
+		error = __inode_permission(inode, mask);
+		if (error)
+			goto fail;
+	}
 	error = -ENOTBLK;
 	if (!S_ISBLK(inode->i_mode))
 		goto fail;
@@ -1806,6 +1874,7 @@
 	spin_lock(&blockdev_superblock->s_inode_list_lock);
 	list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list) {
 		struct address_space *mapping = inode->i_mapping;
+		struct block_device *bdev;
 
 		spin_lock(&inode->i_lock);
 		if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) ||
@@ -1826,8 +1895,12 @@
 		 */
 		iput(old_inode);
 		old_inode = inode;
+		bdev = I_BDEV(inode);
 
-		func(I_BDEV(inode), arg);
+		mutex_lock(&bdev->bd_mutex);
+		if (bdev->bd_openers)
+			func(bdev, arg);
+		mutex_unlock(&bdev->bd_mutex);
 
 		spin_lock(&blockdev_superblock->s_inode_list_lock);
 	}
--- linux-4.4.0.orig/fs/btrfs/Makefile
+++ linux-4.4.0/fs/btrfs/Makefile
@@ -9,7 +9,7 @@
 	   export.o tree-log.o free-space-cache.o zlib.o lzo.o \
 	   compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
 	   reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
-	   uuid-tree.o props.o hash.o
+	   uuid-tree.o props.o hash.o tree-checker.o
 
 btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
 btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
--- linux-4.4.0.orig/fs/btrfs/acl.c
+++ linux-4.4.0/fs/btrfs/acl.c
@@ -82,14 +82,6 @@
 	switch (type) {
 	case ACL_TYPE_ACCESS:
 		name = POSIX_ACL_XATTR_ACCESS;
-		if (acl) {
-			ret = posix_acl_equiv_mode(acl, &inode->i_mode);
-			if (ret < 0)
-				return ret;
-			if (ret == 0)
-				acl = NULL;
-		}
-		ret = 0;
 		break;
 	case ACL_TYPE_DEFAULT:
 		if (!S_ISDIR(inode->i_mode))
@@ -125,7 +117,18 @@
 
 int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
-	return __btrfs_set_acl(NULL, inode, acl, type);
+	int ret;
+	umode_t old_mode = inode->i_mode;
+
+	if (type == ACL_TYPE_ACCESS && acl) {
+		ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+		if (ret)
+			return ret;
+	}
+	ret = __btrfs_set_acl(NULL, inode, acl, type);
+	if (ret)
+		inode->i_mode = old_mode;
+	return ret;
 }
 
 /*
--- linux-4.4.0.orig/fs/btrfs/async-thread.c
+++ linux-4.4.0/fs/btrfs/async-thread.c
@@ -70,6 +70,20 @@
 	normal_work_helper(work);					\
 }
 
+bool btrfs_workqueue_normal_congested(struct btrfs_workqueue *wq)
+{
+	/*
+	 * We could compare wq->normal->pending with num_online_cpus()
+	 * to support "thresh == NO_THRESHOLD" case, but it requires
+	 * moving up atomic_inc/dec in thresh_queue/exec_hook. Let's
+	 * postpone it until someone needs the support of that case.
+	 */
+	if (wq->normal->thresh == NO_THRESHOLD)
+		return false;
+
+	return atomic_read(&wq->normal->pending) > wq->normal->thresh * 2;
+}
+
 BTRFS_WORK_HELPER(worker_helper);
 BTRFS_WORK_HELPER(delalloc_helper);
 BTRFS_WORK_HELPER(flush_delalloc_helper);
@@ -328,8 +342,8 @@
 		list_add_tail(&work->ordered_list, &wq->ordered_list);
 		spin_unlock_irqrestore(&wq->list_lock, flags);
 	}
-	queue_work(wq->normal_wq, &work->normal_work);
 	trace_btrfs_work_queued(work);
+	queue_work(wq->normal_wq, &work->normal_work);
 }
 
 void btrfs_queue_work(struct btrfs_workqueue *wq,
@@ -375,3 +389,11 @@
 {
 	set_bit(WORK_HIGH_PRIO_BIT, &work->flags);
 }
+
+void btrfs_flush_workqueue(struct btrfs_workqueue *wq)
+{
+	if (wq->high)
+		flush_workqueue(wq->high->normal_wq);
+
+	flush_workqueue(wq->normal->normal_wq);
+}
--- linux-4.4.0.orig/fs/btrfs/async-thread.h
+++ linux-4.4.0/fs/btrfs/async-thread.h
@@ -80,4 +80,7 @@
 void btrfs_destroy_workqueue(struct btrfs_workqueue *wq);
 void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max);
 void btrfs_set_work_high_priority(struct btrfs_work *work);
+bool btrfs_workqueue_normal_congested(struct btrfs_workqueue *wq);
+void btrfs_flush_workqueue(struct btrfs_workqueue *wq);
+
 #endif
--- linux-4.4.0.orig/fs/btrfs/backref.c
+++ linux-4.4.0/fs/btrfs/backref.c
@@ -1221,6 +1221,7 @@
 		if (ret < 0 && ret != -ENOENT) {
 			ulist_free(tmp);
 			ulist_free(*roots);
+			*roots = NULL;
 			return ret;
 		}
 		node = ulist_next(tmp, &uiter);
@@ -1417,7 +1418,8 @@
 			read_extent_buffer(eb, dest + bytes_left,
 					   name_off, name_len);
 		if (eb != eb_in) {
-			btrfs_tree_read_unlock_blocking(eb);
+			if (!path->skip_locking)
+				btrfs_tree_read_unlock_blocking(eb);
 			free_extent_buffer(eb);
 		}
 		ret = btrfs_find_item(fs_root, path, parent, 0,
@@ -1437,9 +1439,10 @@
 		eb = path->nodes[0];
 		/* make sure we can use eb after releasing the path */
 		if (eb != eb_in) {
-			atomic_inc(&eb->refs);
-			btrfs_tree_read_lock(eb);
-			btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
+			if (!path->skip_locking)
+				btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
+			path->nodes[0] = NULL;
+			path->locks[0] = 0;
 		}
 		btrfs_release_path(path);
 		iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
@@ -1683,13 +1686,19 @@
 			extent_item_objectid);
 
 	if (!search_commit_root) {
-		trans = btrfs_join_transaction(fs_info->extent_root);
-		if (IS_ERR(trans))
-			return PTR_ERR(trans);
+		trans = btrfs_attach_transaction(fs_info->extent_root);
+		if (IS_ERR(trans)) {
+			if (PTR_ERR(trans) != -ENOENT &&
+			    PTR_ERR(trans) != -EROFS)
+				return PTR_ERR(trans);
+			trans = NULL;
+		}
+	}
+
+	if (trans)
 		btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
-	} else {
+	else
 		down_read(&fs_info->commit_root_sem);
-	}
 
 	ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
 				   tree_mod_seq_elem.seq, &refs,
@@ -1719,7 +1728,7 @@
 
 	free_leaf_list(refs);
 out:
-	if (!search_commit_root) {
+	if (trans) {
 		btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
 		btrfs_end_transaction(trans, fs_info->extent_root);
 	} else {
@@ -1968,20 +1977,14 @@
 	size_t alloc_bytes;
 
 	alloc_bytes = max_t(size_t, total_bytes, sizeof(*data));
-	data = vmalloc(alloc_bytes);
+	data = vzalloc(alloc_bytes);
 	if (!data)
 		return ERR_PTR(-ENOMEM);
 
-	if (total_bytes >= sizeof(*data)) {
+	if (total_bytes >= sizeof(*data))
 		data->bytes_left = total_bytes - sizeof(*data);
-		data->bytes_missing = 0;
-	} else {
+	else
 		data->bytes_missing = sizeof(*data) - total_bytes;
-		data->bytes_left = 0;
-	}
-
-	data->elem_cnt = 0;
-	data->elem_missed = 0;
 
 	return data;
 }
--- linux-4.4.0.orig/fs/btrfs/compression.c
+++ linux-4.4.0/fs/btrfs/compression.c
@@ -356,7 +356,7 @@
 	cb->orig_bio = NULL;
 	cb->nr_pages = nr_pages;
 
-	bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
+	bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_dev->bdev;
 
 	bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS);
 	if (!bio) {
@@ -623,7 +623,7 @@
 	if (!cb->compressed_pages)
 		goto fail1;
 
-	bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
+	bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_dev->bdev;
 
 	for (pg_index = 0; pg_index < nr_pages; pg_index++) {
 		cb->compressed_pages[pg_index] = alloc_page(GFP_NOFS |
@@ -694,7 +694,7 @@
 			ret = btrfs_map_bio(root, READ, comp_bio,
 					    mirror_num, 0);
 			if (ret) {
-				bio->bi_error = ret;
+				comp_bio->bi_error = ret;
 				bio_endio(comp_bio);
 			}
 
@@ -723,7 +723,7 @@
 
 	ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
 	if (ret) {
-		bio->bi_error = ret;
+		comp_bio->bi_error = ret;
 		bio_endio(comp_bio);
 	}
 
--- linux-4.4.0.orig/fs/btrfs/ctree.c
+++ linux-4.4.0/fs/btrfs/ctree.c
@@ -332,26 +332,6 @@
 	struct tree_mod_root old_root;
 };
 
-static inline void tree_mod_log_read_lock(struct btrfs_fs_info *fs_info)
-{
-	read_lock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_read_unlock(struct btrfs_fs_info *fs_info)
-{
-	read_unlock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_write_lock(struct btrfs_fs_info *fs_info)
-{
-	write_lock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_write_unlock(struct btrfs_fs_info *fs_info)
-{
-	write_unlock(&fs_info->tree_mod_log_lock);
-}
-
 /*
  * Pull a new tree mod seq number for our operation.
  */
@@ -371,14 +351,12 @@
 u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info,
 			   struct seq_list *elem)
 {
-	tree_mod_log_write_lock(fs_info);
-	spin_lock(&fs_info->tree_mod_seq_lock);
+	write_lock(&fs_info->tree_mod_log_lock);
 	if (!elem->seq) {
 		elem->seq = btrfs_inc_tree_mod_seq(fs_info);
 		list_add_tail(&elem->list, &fs_info->tree_mod_seq_list);
 	}
-	spin_unlock(&fs_info->tree_mod_seq_lock);
-	tree_mod_log_write_unlock(fs_info);
+	write_unlock(&fs_info->tree_mod_log_lock);
 
 	return elem->seq;
 }
@@ -397,7 +375,7 @@
 	if (!seq_putting)
 		return;
 
-	spin_lock(&fs_info->tree_mod_seq_lock);
+	write_lock(&fs_info->tree_mod_log_lock);
 	list_del(&elem->list);
 	elem->seq = 0;
 
@@ -408,29 +386,27 @@
 				 * blocker with lower sequence number exists, we
 				 * cannot remove anything from the log
 				 */
-				spin_unlock(&fs_info->tree_mod_seq_lock);
+				write_unlock(&fs_info->tree_mod_log_lock);
 				return;
 			}
 			min_seq = cur_elem->seq;
 		}
 	}
-	spin_unlock(&fs_info->tree_mod_seq_lock);
 
 	/*
 	 * anything that's lower than the lowest existing (read: blocked)
 	 * sequence number can be removed from the tree.
 	 */
-	tree_mod_log_write_lock(fs_info);
 	tm_root = &fs_info->tree_mod_log;
 	for (node = rb_first(tm_root); node; node = next) {
 		next = rb_next(node);
 		tm = container_of(node, struct tree_mod_elem, node);
-		if (tm->seq > min_seq)
+		if (tm->seq >= min_seq)
 			continue;
 		rb_erase(node, tm_root);
 		kfree(tm);
 	}
-	tree_mod_log_write_unlock(fs_info);
+	write_unlock(&fs_info->tree_mod_log_lock);
 }
 
 /*
@@ -441,7 +417,7 @@
  * operations, or the shifted logical of the affected block for all other
  * operations.
  *
- * Note: must be called with write lock (tree_mod_log_write_lock).
+ * Note: must be called with write lock for fs_info::tree_mod_log_lock.
  */
 static noinline int
 __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
@@ -481,7 +457,7 @@
  * Determines if logging can be omitted. Returns 1 if it can. Otherwise, it
  * returns zero with the tree_mod_log_lock acquired. The caller must hold
  * this until all tree mod log insertions are recorded in the rb tree and then
- * call tree_mod_log_write_unlock() to release.
+ * write unlock fs_info::tree_mod_log_lock.
  */
 static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,
 				    struct extent_buffer *eb) {
@@ -491,9 +467,9 @@
 	if (eb && btrfs_header_level(eb) == 0)
 		return 1;
 
-	tree_mod_log_write_lock(fs_info);
+	write_lock(&fs_info->tree_mod_log_lock);
 	if (list_empty(&(fs_info)->tree_mod_seq_list)) {
-		tree_mod_log_write_unlock(fs_info);
+		write_unlock(&fs_info->tree_mod_log_lock);
 		return 1;
 	}
 
@@ -557,7 +533,7 @@
 	}
 
 	ret = __tree_mod_log_insert(fs_info, tm);
-	tree_mod_log_write_unlock(fs_info);
+	write_unlock(&eb->fs_info->tree_mod_log_lock);
 	if (ret)
 		kfree(tm);
 
@@ -621,7 +597,7 @@
 	ret = __tree_mod_log_insert(fs_info, tm);
 	if (ret)
 		goto free_tms;
-	tree_mod_log_write_unlock(fs_info);
+	write_unlock(&eb->fs_info->tree_mod_log_lock);
 	kfree(tm_list);
 
 	return 0;
@@ -632,7 +608,7 @@
 		kfree(tm_list[i]);
 	}
 	if (locked)
-		tree_mod_log_write_unlock(fs_info);
+		write_unlock(&eb->fs_info->tree_mod_log_lock);
 	kfree(tm_list);
 	kfree(tm);
 
@@ -713,7 +689,7 @@
 	if (!ret)
 		ret = __tree_mod_log_insert(fs_info, tm);
 
-	tree_mod_log_write_unlock(fs_info);
+	write_unlock(&fs_info->tree_mod_log_lock);
 	if (ret)
 		goto free_tms;
 	kfree(tm_list);
@@ -741,7 +717,7 @@
 	struct tree_mod_elem *found = NULL;
 	u64 index = start >> PAGE_CACHE_SHIFT;
 
-	tree_mod_log_read_lock(fs_info);
+	read_lock(&fs_info->tree_mod_log_lock);
 	tm_root = &fs_info->tree_mod_log;
 	node = tm_root->rb_node;
 	while (node) {
@@ -769,7 +745,7 @@
 			break;
 		}
 	}
-	tree_mod_log_read_unlock(fs_info);
+	read_unlock(&fs_info->tree_mod_log_lock);
 
 	return found;
 }
@@ -850,7 +826,7 @@
 			goto free_tms;
 	}
 
-	tree_mod_log_write_unlock(fs_info);
+	write_unlock(&fs_info->tree_mod_log_lock);
 	kfree(tm_list);
 
 	return 0;
@@ -862,7 +838,7 @@
 		kfree(tm_list[i]);
 	}
 	if (locked)
-		tree_mod_log_write_unlock(fs_info);
+		write_unlock(&fs_info->tree_mod_log_lock);
 	kfree(tm_list);
 
 	return ret;
@@ -922,7 +898,7 @@
 		goto free_tms;
 
 	ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems);
-	tree_mod_log_write_unlock(fs_info);
+	write_unlock(&eb->fs_info->tree_mod_log_lock);
 	if (ret)
 		goto free_tms;
 	kfree(tm_list);
@@ -1153,6 +1129,8 @@
 
 	ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
 	if (ret) {
+		btrfs_tree_unlock(cow);
+		free_extent_buffer(cow);
 		btrfs_abort_transaction(trans, root, ret);
 		return ret;
 	}
@@ -1160,6 +1138,8 @@
 	if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) {
 		ret = btrfs_reloc_cow_block(trans, root, buf, cow);
 		if (ret) {
+			btrfs_tree_unlock(cow);
+			free_extent_buffer(cow);
 			btrfs_abort_transaction(trans, root, ret);
 			return ret;
 		}
@@ -1198,6 +1178,8 @@
 		if (last_ref) {
 			ret = tree_mod_log_free_eb(root->fs_info, buf);
 			if (ret) {
+				btrfs_tree_unlock(cow);
+				free_extent_buffer(cow);
 				btrfs_abort_transaction(trans, root, ret);
 				return ret;
 			}
@@ -1284,7 +1266,7 @@
 	unsigned long p_size = sizeof(struct btrfs_key_ptr);
 
 	n = btrfs_header_nritems(eb);
-	tree_mod_log_read_lock(fs_info);
+	read_lock(&fs_info->tree_mod_log_lock);
 	while (tm && tm->seq >= time_seq) {
 		/*
 		 * all the operations are recorded with the operator used for
@@ -1339,7 +1321,7 @@
 		if (tm->index != first_tm->index)
 			break;
 	}
-	tree_mod_log_read_unlock(fs_info);
+	read_unlock(&fs_info->tree_mod_log_lock);
 	btrfs_set_header_nritems(eb, n);
 }
 
@@ -1396,7 +1378,8 @@
 	btrfs_tree_read_unlock_blocking(eb);
 	free_extent_buffer(eb);
 
-	extent_buffer_get(eb_rewin);
+	btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb_rewin),
+				       eb_rewin, btrfs_header_level(eb_rewin));
 	btrfs_tree_read_lock(eb_rewin);
 	__tree_mod_log_rewind(fs_info, eb_rewin, time_seq, tm);
 	WARN_ON(btrfs_header_nritems(eb_rewin) >
@@ -1418,6 +1401,7 @@
 	struct tree_mod_elem *tm;
 	struct extent_buffer *eb = NULL;
 	struct extent_buffer *eb_root;
+	u64 eb_root_owner = 0;
 	struct extent_buffer *old;
 	struct tree_mod_root *old_root = NULL;
 	u64 old_generation = 0;
@@ -1447,10 +1431,33 @@
 			btrfs_warn(root->fs_info,
 				"failed to read tree block %llu from get_old_root", logical);
 		} else {
+			struct tree_mod_elem *tm2;
+
+			btrfs_tree_read_lock(old);
 			eb = btrfs_clone_extent_buffer(old);
+			/*
+			 * After the lookup for the most recent tree mod operation
+			 * above and before we locked and cloned the extent buffer
+			 * 'old', a new tree mod log operation may have been added.
+			 * So lookup for a more recent one to make sure the number
+			 * of mod log operations we replay is consistent with the
+			 * number of items we have in the cloned extent buffer,
+			 * otherwise we can hit a BUG_ON when rewinding the extent
+			 * buffer.
+			 */
+			tm2 = tree_mod_log_search(root->fs_info, logical, time_seq);
+			btrfs_tree_read_unlock(old);
 			free_extent_buffer(old);
+			ASSERT(tm2);
+			ASSERT(tm2 == tm || tm2->seq > tm->seq);
+			if (!tm2 || tm2->seq < tm->seq) {
+				free_extent_buffer(eb);
+				return NULL;
+			}
+			tm = tm2;
 		}
 	} else if (old_root) {
+		eb_root_owner = btrfs_header_owner(eb_root);
 		btrfs_tree_read_unlock(eb_root);
 		free_extent_buffer(eb_root);
 		eb = alloc_dummy_extent_buffer(root->fs_info, logical);
@@ -1463,15 +1470,16 @@
 
 	if (!eb)
 		return NULL;
-	extent_buffer_get(eb);
-	btrfs_tree_read_lock(eb);
 	if (old_root) {
 		btrfs_set_header_bytenr(eb, eb->start);
 		btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV);
-		btrfs_set_header_owner(eb, btrfs_header_owner(eb_root));
+		btrfs_set_header_owner(eb, eb_root_owner);
 		btrfs_set_header_level(eb, old_root->level);
 		btrfs_set_header_generation(eb, old_generation);
 	}
+	btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb), eb,
+				       btrfs_header_level(eb));
+	btrfs_tree_read_lock(eb);
 	if (tm)
 		__tree_mod_log_rewind(root->fs_info, eb, time_seq, tm);
 	else
@@ -1551,6 +1559,7 @@
 		       trans->transid, root->fs_info->generation);
 
 	if (!should_cow_block(trans, root, buf)) {
+		trans->dirty = true;
 		*cow_ret = buf;
 		return 0;
 	}
@@ -1725,20 +1734,6 @@
 	return err;
 }
 
-/*
- * The leaf data grows from end-to-front in the node.
- * this returns the address of the start of the last item,
- * which is the stop of the leaf data stack
- */
-static inline unsigned int leaf_data_end(struct btrfs_root *root,
-					 struct extent_buffer *leaf)
-{
-	u32 nr = btrfs_header_nritems(leaf);
-	if (nr == 0)
-		return BTRFS_LEAF_DATA_SIZE(root);
-	return btrfs_item_offset_nr(leaf, nr - 1);
-}
-
 
 /*
  * search for key in the extent_buffer.  The items start at offset p,
@@ -2496,10 +2491,8 @@
 	if (p->reada)
 		reada_for_search(root, p, level, slot, key->objectid);
 
-	btrfs_release_path(p);
-
 	ret = -EAGAIN;
-	tmp = read_tree_block(root, blocknr, 0);
+	tmp = read_tree_block(root, blocknr, gen);
 	if (!IS_ERR(tmp)) {
 		/*
 		 * If the read above didn't mark this buffer up to date,
@@ -2511,6 +2504,8 @@
 			ret = -EIO;
 		free_extent_buffer(tmp);
 	}
+
+	btrfs_release_path(p);
 	return ret;
 }
 
@@ -2768,13 +2763,17 @@
 		 * contention with the cow code
 		 */
 		if (cow) {
+			bool last_level = (level == (BTRFS_MAX_LEVEL - 1));
+
 			/*
 			 * if we don't really need to cow this block
 			 * then we don't want to set the path blocking,
 			 * so we test it here
 			 */
-			if (!should_cow_block(trans, root, b))
+			if (!should_cow_block(trans, root, b)) {
+				trans->dirty = true;
 				goto cow_done;
+			}
 
 			/*
 			 * must have write locks on this node and the
@@ -2790,9 +2789,13 @@
 			}
 
 			btrfs_set_path_blocking(p);
-			err = btrfs_cow_block(trans, root, b,
-					      p->nodes[level + 1],
-					      p->slots[level + 1], &b);
+			if (last_level)
+				err = btrfs_cow_block(trans, root, b, NULL, 0,
+						      &b);
+			else
+				err = btrfs_cow_block(trans, root, b,
+						      p->nodes[level + 1],
+						      p->slots[level + 1], &b);
 			if (err) {
 				ret = err;
 				goto done;
@@ -2969,6 +2972,10 @@
 
 again:
 	b = get_old_root(root, time_seq);
+	if (!b) {
+		ret = -EIO;
+		goto done;
+	}
 	level = btrfs_header_level(b);
 	p->locks[level] = BTRFS_READ_LOCK;
 
@@ -5438,6 +5445,7 @@
 	advance_left = advance_right = 0;
 
 	while (1) {
+		cond_resched();
 		if (advance_left && !left_end_reached) {
 			ret = tree_advance(left_root, left_path, &left_level,
 					left_root_level,
--- linux-4.4.0.orig/fs/btrfs/ctree.h
+++ linux-4.4.0/fs/btrfs/ctree.h
@@ -35,6 +35,7 @@
 #include <linux/btrfs.h>
 #include <linux/workqueue.h>
 #include <linux/security.h>
+#include <linux/sizes.h>
 #include "extent_io.h"
 #include "extent_map.h"
 #include "async-thread.h"
@@ -897,6 +898,7 @@
 #define BTRFS_FILE_EXTENT_INLINE 0
 #define BTRFS_FILE_EXTENT_REG 1
 #define BTRFS_FILE_EXTENT_PREALLOC 2
+#define BTRFS_FILE_EXTENT_TYPES	2
 
 struct btrfs_file_extent_item {
 	/*
@@ -1572,16 +1574,14 @@
 
 	spinlock_t delayed_iput_lock;
 	struct list_head delayed_iputs;
-	struct rw_semaphore delayed_iput_sem;
+	struct mutex cleaner_delayed_iput_mutex;
 
-	/* this protects tree_mod_seq_list */
-	spinlock_t tree_mod_seq_lock;
 	atomic64_t tree_mod_seq;
-	struct list_head tree_mod_seq_list;
 
-	/* this protects tree_mod_log */
+	/* this protects tree_mod_log and tree_mod_seq_list */
 	rwlock_t tree_mod_log_lock;
 	struct rb_root tree_mod_log;
+	struct list_head tree_mod_seq_list;
 
 	atomic_t nr_async_submits;
 	atomic_t async_submit_draining;
@@ -1770,6 +1770,7 @@
 	struct btrfs_workqueue *qgroup_rescan_workers;
 	struct completion qgroup_rescan_completion;
 	struct btrfs_work qgroup_rescan_work;
+	bool qgroup_rescan_running;	/* protected by qgroup_rescan_lock */
 
 	/* filesystem state */
 	unsigned long fs_state;
@@ -2282,7 +2283,7 @@
 #define BTRFS_INODE_ROOT_ITEM_INIT	(1 << 31)
 
 struct btrfs_map_token {
-	struct extent_buffer *eb;
+	const struct extent_buffer *eb;
 	char *kaddr;
 	unsigned long offset;
 };
@@ -2313,18 +2314,19 @@
 			   sizeof(((type *)0)->member)))
 
 #define DECLARE_BTRFS_SETGET_BITS(bits)					\
-u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr,	\
-			       unsigned long off,			\
-                              struct btrfs_map_token *token);		\
-void btrfs_set_token_##bits(struct extent_buffer *eb, void *ptr,	\
+u##bits btrfs_get_token_##bits(const struct extent_buffer *eb,		\
+			       const void *ptr, unsigned long off,	\
+			       struct btrfs_map_token *token);		\
+void btrfs_set_token_##bits(struct extent_buffer *eb, const void *ptr,	\
 			    unsigned long off, u##bits val,		\
 			    struct btrfs_map_token *token);		\
-static inline u##bits btrfs_get_##bits(struct extent_buffer *eb, void *ptr, \
+static inline u##bits btrfs_get_##bits(const struct extent_buffer *eb,	\
+				       const void *ptr,			\
 				       unsigned long off)		\
 {									\
 	return btrfs_get_token_##bits(eb, ptr, off, NULL);		\
 }									\
-static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr, \
+static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr,\
 				    unsigned long off, u##bits val)	\
 {									\
        btrfs_set_token_##bits(eb, ptr, off, val, NULL);			\
@@ -2336,7 +2338,8 @@
 DECLARE_BTRFS_SETGET_BITS(64)
 
 #define BTRFS_SETGET_FUNCS(name, type, member, bits)			\
-static inline u##bits btrfs_##name(struct extent_buffer *eb, type *s)	\
+static inline u##bits btrfs_##name(const struct extent_buffer *eb,	\
+				   const type *s)			\
 {									\
 	BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member);	\
 	return btrfs_get_##bits(eb, s, offsetof(type, member));		\
@@ -2347,7 +2350,8 @@
 	BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member);	\
 	btrfs_set_##bits(eb, s, offsetof(type, member), val);		\
 }									\
-static inline u##bits btrfs_token_##name(struct extent_buffer *eb, type *s, \
+static inline u##bits btrfs_token_##name(const struct extent_buffer *eb,\
+					 const type *s,			\
 					 struct btrfs_map_token *token)	\
 {									\
 	BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member);	\
@@ -2362,9 +2366,9 @@
 }
 
 #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits)		\
-static inline u##bits btrfs_##name(struct extent_buffer *eb)		\
+static inline u##bits btrfs_##name(const struct extent_buffer *eb)	\
 {									\
-	type *p = page_address(eb->pages[0]);				\
+	const type *p = page_address(eb->pages[0]);			\
 	u##bits res = le##bits##_to_cpu(p->member);			\
 	return res;							\
 }									\
@@ -2376,7 +2380,7 @@
 }
 
 #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)		\
-static inline u##bits btrfs_##name(type *s)				\
+static inline u##bits btrfs_##name(const type *s)			\
 {									\
 	return le##bits##_to_cpu(s->member);				\
 }									\
@@ -2677,7 +2681,7 @@
 		sizeof(struct btrfs_key_ptr) * nr;
 }
 
-void btrfs_node_key(struct extent_buffer *eb,
+void btrfs_node_key(const struct extent_buffer *eb,
 		    struct btrfs_disk_key *disk_key, int nr);
 
 static inline void btrfs_set_node_key(struct extent_buffer *eb,
@@ -2706,28 +2710,28 @@
 	return (struct btrfs_item *)btrfs_item_nr_offset(nr);
 }
 
-static inline u32 btrfs_item_end(struct extent_buffer *eb,
+static inline u32 btrfs_item_end(const struct extent_buffer *eb,
 				 struct btrfs_item *item)
 {
 	return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item);
 }
 
-static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)
+static inline u32 btrfs_item_end_nr(const struct extent_buffer *eb, int nr)
 {
 	return btrfs_item_end(eb, btrfs_item_nr(nr));
 }
 
-static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
+static inline u32 btrfs_item_offset_nr(const struct extent_buffer *eb, int nr)
 {
 	return btrfs_item_offset(eb, btrfs_item_nr(nr));
 }
 
-static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)
+static inline u32 btrfs_item_size_nr(const struct extent_buffer *eb, int nr)
 {
 	return btrfs_item_size(eb, btrfs_item_nr(nr));
 }
 
-static inline void btrfs_item_key(struct extent_buffer *eb,
+static inline void btrfs_item_key(const struct extent_buffer *eb,
 			   struct btrfs_disk_key *disk_key, int nr)
 {
 	struct btrfs_item *item = btrfs_item_nr(nr);
@@ -2763,8 +2767,8 @@
 BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item,
 			 transid, 64);
 
-static inline void btrfs_dir_item_key(struct extent_buffer *eb,
-				      struct btrfs_dir_item *item,
+static inline void btrfs_dir_item_key(const struct extent_buffer *eb,
+				      const struct btrfs_dir_item *item,
 				      struct btrfs_disk_key *key)
 {
 	read_eb_member(eb, item, struct btrfs_dir_item, location, key);
@@ -2772,7 +2776,7 @@
 
 static inline void btrfs_set_dir_item_key(struct extent_buffer *eb,
 					  struct btrfs_dir_item *item,
-					  struct btrfs_disk_key *key)
+					  const struct btrfs_disk_key *key)
 {
 	write_eb_member(eb, item, struct btrfs_dir_item, location, key);
 }
@@ -2784,8 +2788,8 @@
 BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header,
 		   generation, 64);
 
-static inline void btrfs_free_space_key(struct extent_buffer *eb,
-					struct btrfs_free_space_header *h,
+static inline void btrfs_free_space_key(const struct extent_buffer *eb,
+					const struct btrfs_free_space_header *h,
 					struct btrfs_disk_key *key)
 {
 	read_eb_member(eb, h, struct btrfs_free_space_header, location, key);
@@ -2793,7 +2797,7 @@
 
 static inline void btrfs_set_free_space_key(struct extent_buffer *eb,
 					    struct btrfs_free_space_header *h,
-					    struct btrfs_disk_key *key)
+					    const struct btrfs_disk_key *key)
 {
 	write_eb_member(eb, h, struct btrfs_free_space_header, location, key);
 }
@@ -2820,25 +2824,25 @@
 	disk->objectid = cpu_to_le64(cpu->objectid);
 }
 
-static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb,
-				  struct btrfs_key *key, int nr)
+static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb,
+					 struct btrfs_key *key, int nr)
 {
 	struct btrfs_disk_key disk_key;
 	btrfs_node_key(eb, &disk_key, nr);
 	btrfs_disk_key_to_cpu(key, &disk_key);
 }
 
-static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb,
-				  struct btrfs_key *key, int nr)
+static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb,
+					 struct btrfs_key *key, int nr)
 {
 	struct btrfs_disk_key disk_key;
 	btrfs_item_key(eb, &disk_key, nr);
 	btrfs_disk_key_to_cpu(key, &disk_key);
 }
 
-static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb,
-				      struct btrfs_dir_item *item,
-				      struct btrfs_key *key)
+static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb,
+					     const struct btrfs_dir_item *item,
+					     struct btrfs_key *key)
 {
 	struct btrfs_disk_key disk_key;
 	btrfs_dir_item_key(eb, item, &disk_key);
@@ -2871,7 +2875,7 @@
 			 nritems, 32);
 BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);
 
-static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)
+static inline int btrfs_header_flag(const struct extent_buffer *eb, u64 flag)
 {
 	return (btrfs_header_flags(eb) & flag) == flag;
 }
@@ -2890,7 +2894,7 @@
 	return (flags & flag) == flag;
 }
 
-static inline int btrfs_header_backref_rev(struct extent_buffer *eb)
+static inline int btrfs_header_backref_rev(const struct extent_buffer *eb)
 {
 	u64 flags = btrfs_header_flags(eb);
 	return flags >> BTRFS_BACKREF_REV_SHIFT;
@@ -2910,12 +2914,12 @@
 	return offsetof(struct btrfs_header, fsid);
 }
 
-static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
+static inline unsigned long btrfs_header_chunk_tree_uuid(const struct extent_buffer *eb)
 {
 	return offsetof(struct btrfs_header, chunk_tree_uuid);
 }
 
-static inline int btrfs_is_leaf(struct extent_buffer *eb)
+static inline int btrfs_is_leaf(const struct extent_buffer *eb)
 {
 	return btrfs_header_level(eb) == 0;
 }
@@ -2949,12 +2953,12 @@
 BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
 			 rtransid, 64);
 
-static inline bool btrfs_root_readonly(struct btrfs_root *root)
+static inline bool btrfs_root_readonly(const struct btrfs_root *root)
 {
 	return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0;
 }
 
-static inline bool btrfs_root_dead(struct btrfs_root *root)
+static inline bool btrfs_root_dead(const struct btrfs_root *root)
 {
 	return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
 }
@@ -3011,51 +3015,51 @@
 /* struct btrfs_balance_item */
 BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64);
 
-static inline void btrfs_balance_data(struct extent_buffer *eb,
-				      struct btrfs_balance_item *bi,
+static inline void btrfs_balance_data(const struct extent_buffer *eb,
+				      const struct btrfs_balance_item *bi,
 				      struct btrfs_disk_balance_args *ba)
 {
 	read_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
 }
 
 static inline void btrfs_set_balance_data(struct extent_buffer *eb,
-					  struct btrfs_balance_item *bi,
-					  struct btrfs_disk_balance_args *ba)
+				  struct btrfs_balance_item *bi,
+				  const struct btrfs_disk_balance_args *ba)
 {
 	write_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
 }
 
-static inline void btrfs_balance_meta(struct extent_buffer *eb,
-				      struct btrfs_balance_item *bi,
+static inline void btrfs_balance_meta(const struct extent_buffer *eb,
+				      const struct btrfs_balance_item *bi,
 				      struct btrfs_disk_balance_args *ba)
 {
 	read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
 }
 
 static inline void btrfs_set_balance_meta(struct extent_buffer *eb,
-					  struct btrfs_balance_item *bi,
-					  struct btrfs_disk_balance_args *ba)
+				  struct btrfs_balance_item *bi,
+				  const struct btrfs_disk_balance_args *ba)
 {
 	write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
 }
 
-static inline void btrfs_balance_sys(struct extent_buffer *eb,
-				     struct btrfs_balance_item *bi,
+static inline void btrfs_balance_sys(const struct extent_buffer *eb,
+				     const struct btrfs_balance_item *bi,
 				     struct btrfs_disk_balance_args *ba)
 {
 	read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
 }
 
 static inline void btrfs_set_balance_sys(struct extent_buffer *eb,
-					 struct btrfs_balance_item *bi,
-					 struct btrfs_disk_balance_args *ba)
+				 struct btrfs_balance_item *bi,
+				 const struct btrfs_disk_balance_args *ba)
 {
 	write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
 }
 
 static inline void
 btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu,
-			       struct btrfs_disk_balance_args *disk)
+			       const struct btrfs_disk_balance_args *disk)
 {
 	memset(cpu, 0, sizeof(*cpu));
 
@@ -3069,11 +3073,13 @@
 	cpu->target = le64_to_cpu(disk->target);
 	cpu->flags = le64_to_cpu(disk->flags);
 	cpu->limit = le64_to_cpu(disk->limit);
+	cpu->stripes_min = le32_to_cpu(disk->stripes_min);
+	cpu->stripes_max = le32_to_cpu(disk->stripes_max);
 }
 
 static inline void
 btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk,
-			       struct btrfs_balance_args *cpu)
+			       const struct btrfs_balance_args *cpu)
 {
 	memset(disk, 0, sizeof(*disk));
 
@@ -3087,6 +3093,8 @@
 	disk->target = cpu_to_le64(cpu->target);
 	disk->flags = cpu_to_le64(cpu->flags);
 	disk->limit = cpu_to_le64(cpu->limit);
+	disk->stripes_min = cpu_to_le32(cpu->stripes_min);
+	disk->stripes_max = cpu_to_le32(cpu->stripes_max);
 }
 
 /* struct btrfs_super_block */
@@ -3139,7 +3147,7 @@
 BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
 			 uuid_tree_generation, 64);
 
-static inline int btrfs_super_csum_size(struct btrfs_super_block *s)
+static inline int btrfs_super_csum_size(const struct btrfs_super_block *s)
 {
 	u16 t = btrfs_super_csum_type(s);
 	/*
@@ -3153,6 +3161,21 @@
 	return offsetof(struct btrfs_leaf, items);
 }
 
+/*
+ * The leaf data grows from end-to-front in the node.
+ * this returns the address of the start of the last item,
+ * which is the stop of the leaf data stack
+ */
+static inline unsigned int leaf_data_end(const struct btrfs_root *root,
+					 const struct extent_buffer *leaf)
+{
+	u32 nr = btrfs_header_nritems(leaf);
+
+	if (nr == 0)
+		return BTRFS_LEAF_DATA_SIZE(root);
+	return btrfs_item_offset_nr(leaf, nr - 1);
+}
+
 /* struct btrfs_file_extent_item */
 BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
 BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr,
@@ -3169,7 +3192,7 @@
 			 struct btrfs_file_extent_item, compression, 8);
 
 static inline unsigned long
-btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e)
+btrfs_file_extent_inline_start(const struct btrfs_file_extent_item *e)
 {
 	return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START;
 }
@@ -3203,8 +3226,9 @@
  * size of any extent headers.  If a file is compressed on disk, this is
  * the compressed size
  */
-static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
-						    struct btrfs_item *e)
+static inline u32 btrfs_file_extent_inline_item_len(
+						const struct extent_buffer *eb,
+						struct btrfs_item *e)
 {
 	return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
 }
@@ -3212,9 +3236,9 @@
 /* this returns the number of file bytes represented by the inline item.
  * If an item is compressed, this is the uncompressed size
  */
-static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
-					       int slot,
-					       struct btrfs_file_extent_item *fi)
+static inline u32 btrfs_file_extent_inline_len(const struct extent_buffer *eb,
+					int slot,
+					const struct btrfs_file_extent_item *fi)
 {
 	struct btrfs_map_token token;
 
@@ -3236,8 +3260,8 @@
 
 
 /* btrfs_dev_stats_item */
-static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb,
-					struct btrfs_dev_stats_item *ptr,
+static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb,
+					const struct btrfs_dev_stats_item *ptr,
 					int index)
 {
 	u64 val;
@@ -4014,6 +4038,7 @@
 
 /* ioctl.c */
 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 void btrfs_update_iflags(struct inode *inode);
 void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
 int btrfs_is_empty_uuid(u8 *uuid);
@@ -4072,6 +4097,8 @@
 /* super.c */
 int btrfs_parse_options(struct btrfs_root *root, char *options);
 int btrfs_sync_fs(struct super_block *sb, int wait);
+char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
+					  u64 subvol_objectid);
 
 #ifdef CONFIG_PRINTK
 __printf(2, 3)
--- linux-4.4.0.orig/fs/btrfs/delayed-inode.c
+++ linux-4.4.0/fs/btrfs/delayed-inode.c
@@ -1375,7 +1375,8 @@
 	total_done++;
 
 	btrfs_release_prepared_delayed_node(delayed_node);
-	if (async_work->nr == 0 || total_done < async_work->nr)
+	if ((async_work->nr == 0 && total_done < BTRFS_DELAYED_WRITEBACK) ||
+	    total_done < async_work->nr)
 		goto again;
 
 free_path:
@@ -1391,7 +1392,8 @@
 {
 	struct btrfs_async_delayed_work *async_work;
 
-	if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND)
+	if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND ||
+	    btrfs_workqueue_normal_congested(fs_info->delayed_workers))
 		return 0;
 
 	async_work = kmalloc(sizeof(*async_work), GFP_NOFS);
@@ -1694,7 +1696,7 @@
  *
  */
 int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
-				    struct list_head *ins_list)
+				    struct list_head *ins_list, bool *emitted)
 {
 	struct btrfs_dir_item *di;
 	struct btrfs_delayed_item *curr, *next;
@@ -1738,6 +1740,7 @@
 
 		if (over)
 			return 1;
+		*emitted = true;
 	}
 	return 0;
 }
--- linux-4.4.0.orig/fs/btrfs/delayed-inode.h
+++ linux-4.4.0/fs/btrfs/delayed-inode.h
@@ -144,7 +144,7 @@
 int btrfs_should_delete_dir_index(struct list_head *del_list,
 				  u64 index);
 int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
-				    struct list_head *ins_list);
+				    struct list_head *ins_list, bool *emitted);
 
 /* for init */
 int __init btrfs_delayed_inode_init(void);
--- linux-4.4.0.orig/fs/btrfs/delayed-ref.c
+++ linux-4.4.0/fs/btrfs/delayed-ref.c
@@ -193,8 +193,6 @@
 	ref->in_tree = 0;
 	btrfs_put_delayed_ref(ref);
 	atomic_dec(&delayed_refs->num_entries);
-	if (trans->delayed_ref_updates)
-		trans->delayed_ref_updates--;
 }
 
 static bool merge_ref(struct btrfs_trans_handle *trans,
@@ -281,7 +279,7 @@
 	if (head->is_data)
 		return;
 
-	spin_lock(&fs_info->tree_mod_seq_lock);
+	read_lock(&fs_info->tree_mod_log_lock);
 	if (!list_empty(&fs_info->tree_mod_seq_list)) {
 		struct seq_list *elem;
 
@@ -289,7 +287,7 @@
 					struct seq_list, list);
 		seq = elem->seq;
 	}
-	spin_unlock(&fs_info->tree_mod_seq_lock);
+	read_unlock(&fs_info->tree_mod_log_lock);
 
 	ref = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node,
 			       list);
@@ -317,7 +315,7 @@
 	struct seq_list *elem;
 	int ret = 0;
 
-	spin_lock(&fs_info->tree_mod_seq_lock);
+	read_lock(&fs_info->tree_mod_log_lock);
 	if (!list_empty(&fs_info->tree_mod_seq_list)) {
 		elem = list_first_entry(&fs_info->tree_mod_seq_list,
 					struct seq_list, list);
@@ -330,7 +328,7 @@
 		}
 	}
 
-	spin_unlock(&fs_info->tree_mod_seq_lock);
+	read_unlock(&fs_info->tree_mod_log_lock);
 	return ret;
 }
 
@@ -444,7 +442,6 @@
 add_tail:
 	list_add_tail(&ref->list, &href->ref_list);
 	atomic_inc(&root->num_entries);
-	trans->delayed_ref_updates++;
 	spin_unlock(&href->lock);
 	return ret;
 }
--- linux-4.4.0.orig/fs/btrfs/dev-replace.c
+++ linux-4.4.0/fs/btrfs/dev-replace.c
@@ -135,11 +135,11 @@
 		break;
 	case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
 	case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
-		dev_replace->srcdev = btrfs_find_device(fs_info, src_devid,
-							NULL, NULL);
-		dev_replace->tgtdev = btrfs_find_device(fs_info,
+		dev_replace->srcdev = btrfs_find_device(fs_info->fs_devices,
+						src_devid, NULL, NULL, true);
+		dev_replace->tgtdev = btrfs_find_device(fs_info->fs_devices,
 							BTRFS_DEV_REPLACE_DEVID,
-							NULL, NULL);
+							NULL, NULL, true);
 		/*
 		 * allow 'btrfs dev replace_cancel' if src/tgt device is
 		 * missing
@@ -495,18 +495,27 @@
 	}
 	btrfs_wait_ordered_roots(root->fs_info, -1);
 
-	trans = btrfs_start_transaction(root, 0);
-	if (IS_ERR(trans)) {
-		mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
-		return PTR_ERR(trans);
+	while (1) {
+		trans = btrfs_start_transaction(root, 0);
+		if (IS_ERR(trans)) {
+			mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+			return PTR_ERR(trans);
+		}
+		ret = btrfs_commit_transaction(trans, root);
+		WARN_ON(ret);
+		mutex_lock(&uuid_mutex);
+		/* keep away write_all_supers() during the finishing procedure */
+		mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+		mutex_lock(&root->fs_info->chunk_mutex);
+		if (src_device->has_pending_chunks) {
+			mutex_unlock(&root->fs_info->chunk_mutex);
+			mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+			mutex_unlock(&uuid_mutex);
+		} else {
+			break;
+		}
 	}
-	ret = btrfs_commit_transaction(trans, root);
-	WARN_ON(ret);
 
-	mutex_lock(&uuid_mutex);
-	/* keep away write_all_supers() during the finishing procedure */
-	mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
-	mutex_lock(&root->fs_info->chunk_mutex);
 	btrfs_dev_replace_lock(dev_replace);
 	dev_replace->replace_state =
 		scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED
@@ -560,8 +569,8 @@
 	tgt_device->commit_bytes_used = src_device->bytes_used;
 	if (fs_info->sb->s_bdev == src_device->bdev)
 		fs_info->sb->s_bdev = tgt_device->bdev;
-	if (fs_info->fs_devices->latest_bdev == src_device->bdev)
-		fs_info->fs_devices->latest_bdev = tgt_device->bdev;
+	if (fs_info->fs_devices->latest_dev->bdev == src_device->bdev)
+		fs_info->fs_devices->latest_dev->bdev = tgt_device->bdev;
 	list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
 	fs_info->fs_devices->rw_devices++;
 
@@ -574,6 +583,12 @@
 	btrfs_rm_dev_replace_unblocked(fs_info);
 
 	/*
+	 * Increment dev_stats_ccnt so that btrfs_run_dev_stats() will
+	 * update on-disk dev stats value during commit transaction
+	 */
+	atomic_inc(&tgt_device->dev_stats_ccnt);
+
+	/*
 	 * this is again a consistent state where no dev_replace procedure
 	 * is running, the target device is part of the filesystem, the
 	 * source device is not part of the filesystem anymore and its 1st
@@ -614,7 +629,7 @@
 		em = lookup_extent_mapping(em_tree, start, (u64)-1);
 		if (!em)
 			break;
-		map = (struct map_lookup *)em->bdev;
+		map = em->map_lookup;
 		for (i = 0; i < map->num_stripes; i++)
 			if (srcdev == map->stripes[i].dev)
 				map->stripes[i].dev = tgtdev;
@@ -632,8 +647,8 @@
 
 	if (srcdevid) {
 		ret = 0;
-		*device = btrfs_find_device(root->fs_info, srcdevid, NULL,
-					    NULL);
+		*device = btrfs_find_device(root->fs_info->fs_devices, srcdevid,
+				NULL, NULL, false);
 		if (!*device)
 			ret = -ENOENT;
 	} else {
--- linux-4.4.0.orig/fs/btrfs/disk-io.c
+++ linux-4.4.0/fs/btrfs/disk-io.c
@@ -49,6 +49,7 @@
 #include "raid56.h"
 #include "sysfs.h"
 #include "qgroup.h"
+#include "tree-checker.h"
 
 #ifdef CONFIG_X86
 #include <asm/cpufeature.h>
@@ -226,7 +227,7 @@
 	em = lookup_extent_mapping(em_tree, start, len);
 	if (em) {
 		em->bdev =
-			BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
+			BTRFS_I(inode)->root->fs_info->fs_devices->latest_dev->bdev;
 		read_unlock(&em_tree->lock);
 		goto out;
 	}
@@ -241,7 +242,7 @@
 	em->len = (u64)-1;
 	em->block_len = (u64)-1;
 	em->block_start = 0;
-	em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
+	em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_dev->bdev;
 
 	write_lock(&em_tree->lock);
 	ret = add_extent_mapping(em_tree, em, 0);
@@ -445,9 +446,9 @@
 	int mirror_num = 0;
 	int failed_mirror = 0;
 
-	clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
 	io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree;
 	while (1) {
+		clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
 		ret = read_extent_buffer_pages(io_tree, eb, start,
 					       WAIT_COMPLETE,
 					       btree_get_extent, mirror_num);
@@ -459,14 +460,6 @@
 				ret = -EIO;
 		}
 
-		/*
-		 * This buffer's crc is fine, but its contents are corrupted, so
-		 * there is no reason to read the other copies, they won't be
-		 * any less wrong.
-		 */
-		if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags))
-			break;
-
 		num_copies = btrfs_num_copies(root->fs_info,
 					      eb->start, eb->len);
 		if (num_copies == 1)
@@ -530,72 +523,6 @@
 	return ret;
 }
 
-#define CORRUPT(reason, eb, root, slot)				\
-	btrfs_crit(root->fs_info, "corrupt leaf, %s: block=%llu,"	\
-		   "root=%llu, slot=%d", reason,			\
-	       btrfs_header_bytenr(eb),	root->objectid, slot)
-
-static noinline int check_leaf(struct btrfs_root *root,
-			       struct extent_buffer *leaf)
-{
-	struct btrfs_key key;
-	struct btrfs_key leaf_key;
-	u32 nritems = btrfs_header_nritems(leaf);
-	int slot;
-
-	if (nritems == 0)
-		return 0;
-
-	/* Check the 0 item */
-	if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
-	    BTRFS_LEAF_DATA_SIZE(root)) {
-		CORRUPT("invalid item offset size pair", leaf, root, 0);
-		return -EIO;
-	}
-
-	/*
-	 * Check to make sure each items keys are in the correct order and their
-	 * offsets make sense.  We only have to loop through nritems-1 because
-	 * we check the current slot against the next slot, which verifies the
-	 * next slot's offset+size makes sense and that the current's slot
-	 * offset is correct.
-	 */
-	for (slot = 0; slot < nritems - 1; slot++) {
-		btrfs_item_key_to_cpu(leaf, &leaf_key, slot);
-		btrfs_item_key_to_cpu(leaf, &key, slot + 1);
-
-		/* Make sure the keys are in the right order */
-		if (btrfs_comp_cpu_keys(&leaf_key, &key) >= 0) {
-			CORRUPT("bad key order", leaf, root, slot);
-			return -EIO;
-		}
-
-		/*
-		 * Make sure the offset and ends are right, remember that the
-		 * item data starts at the end of the leaf and grows towards the
-		 * front.
-		 */
-		if (btrfs_item_offset_nr(leaf, slot) !=
-			btrfs_item_end_nr(leaf, slot + 1)) {
-			CORRUPT("slot offset bad", leaf, root, slot);
-			return -EIO;
-		}
-
-		/*
-		 * Check to make sure that we don't point outside of the leaf,
-		 * just incase all the items are consistent to eachother, but
-		 * all point outside of the leaf.
-		 */
-		if (btrfs_item_end_nr(leaf, slot) >
-		    BTRFS_LEAF_DATA_SIZE(root)) {
-			CORRUPT("slot end outside of leaf", leaf, root, slot);
-			return -EIO;
-		}
-	}
-
-	return 0;
-}
-
 static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
 				      u64 phy_offset, struct page *page,
 				      u64 start, u64 end, int mirror)
@@ -662,11 +589,14 @@
 	 * that we don't try and read the other copies of this block, just
 	 * return -EIO.
 	 */
-	if (found_level == 0 && check_leaf(root, eb)) {
+	if (found_level == 0 && btrfs_check_leaf_full(root, eb)) {
 		set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
 		ret = -EIO;
 	}
 
+	if (found_level > 0 && btrfs_check_node(root, eb))
+		ret = -EIO;
+
 	if (!ret)
 		set_extent_buffer_uptodate(eb);
 err:
@@ -923,7 +853,7 @@
 	if (bio_flags & EXTENT_BIO_TREE_LOG)
 		return 0;
 #ifdef CONFIG_X86
-	if (cpu_has_xmm4_2)
+	if (static_cpu_has(X86_FEATURE_XMM4_2))
 		return 0;
 #endif
 	return 1;
@@ -1011,8 +941,9 @@
 
 		fs_info = BTRFS_I(mapping->host)->root->fs_info;
 		/* this is a bit racy, but that's ok */
-		ret = percpu_counter_compare(&fs_info->dirty_metadata_bytes,
-					     BTRFS_DIRTY_METADATA_THRESH);
+		ret = __percpu_counter_compare(&fs_info->dirty_metadata_bytes,
+					     BTRFS_DIRTY_METADATA_THRESH,
+					     fs_info->dirty_metadata_batch);
 		if (ret < 0)
 			return 0;
 	}
@@ -1196,7 +1127,7 @@
 	if (!writers)
 		return ERR_PTR(-ENOMEM);
 
-	ret = percpu_counter_init(&writers->counter, 0, GFP_KERNEL);
+	ret = percpu_counter_init(&writers->counter, 0, GFP_NOFS);
 	if (ret < 0) {
 		kfree(writers);
 		return ERR_PTR(ret);
@@ -1582,8 +1513,23 @@
 	ret = get_anon_bdev(&root->anon_dev);
 	if (ret)
 		goto free_writers;
+
+	mutex_lock(&root->objectid_mutex);
+	ret = btrfs_find_highest_objectid(root,
+					&root->highest_objectid);
+	if (ret) {
+		mutex_unlock(&root->objectid_mutex);
+		goto free_root_dev;
+	}
+
+	ASSERT(root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID);
+
+	mutex_unlock(&root->objectid_mutex);
+
 	return 0;
 
+free_root_dev:
+	free_anon_bdev(root->anon_dev);
 free_writers:
 	btrfs_free_subvolume_writers(root->subv_writers);
 fail:
@@ -1592,8 +1538,8 @@
 	return ret;
 }
 
-static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
-					       u64 root_id)
+struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
+					u64 root_id)
 {
 	struct btrfs_root *root;
 
@@ -1712,7 +1658,7 @@
 	list_for_each_entry_rcu(device, &info->fs_devices->devices, dev_list) {
 		if (!device->bdev)
 			continue;
-		bdi = blk_get_backing_dev_info(device->bdev);
+		bdi = device->bdev->bd_bdi;
 		if (bdi_congested(bdi, bdi_bits)) {
 			ret = 1;
 			break;
@@ -1752,8 +1698,8 @@
 	bio->bi_error = end_io_wq->error;
 	bio->bi_private = end_io_wq->private;
 	bio->bi_end_io = end_io_wq->end_io;
-	kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq);
 	bio_endio(bio);
+	kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq);
 }
 
 static int cleaner_kthread(void *arg)
@@ -1762,7 +1708,6 @@
 	int again;
 	struct btrfs_trans_handle *trans;
 
-	set_freezable();
 	do {
 		again = 0;
 
@@ -1782,7 +1727,10 @@
 			goto sleep;
 		}
 
+		mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex);
 		btrfs_run_delayed_iputs(root);
+		mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex);
+
 		again = btrfs_clean_one_deleted_snapshot(root);
 		mutex_unlock(&root->fs_info->cleaner_mutex);
 
@@ -1802,7 +1750,7 @@
 		 */
 		btrfs_delete_unused_bgs(root->fs_info);
 sleep:
-		if (!try_to_freeze() && !again) {
+		if (!again) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			if (!kthread_should_stop())
 				schedule();
@@ -2259,6 +2207,7 @@
 	fs_info->quota_enabled = 0;
 	fs_info->pending_quota_state = 0;
 	fs_info->qgroup_ulist = NULL;
+	fs_info->qgroup_rescan_running = false;
 	mutex_init(&fs_info->qgroup_rescan_lock);
 }
 
@@ -2532,7 +2481,6 @@
 	spin_lock_init(&fs_info->delayed_iput_lock);
 	spin_lock_init(&fs_info->defrag_inodes_lock);
 	spin_lock_init(&fs_info->free_chunk_lock);
-	spin_lock_init(&fs_info->tree_mod_seq_lock);
 	spin_lock_init(&fs_info->super_lock);
 	spin_lock_init(&fs_info->qgroup_op_lock);
 	spin_lock_init(&fs_info->buffer_lock);
@@ -2542,8 +2490,8 @@
 	mutex_init(&fs_info->delete_unused_bgs_mutex);
 	mutex_init(&fs_info->reloc_mutex);
 	mutex_init(&fs_info->delalloc_root_mutex);
+	mutex_init(&fs_info->cleaner_delayed_iput_mutex);
 	seqlock_init(&fs_info->profiles_lock);
-	init_rwsem(&fs_info->delayed_iput_sem);
 
 	INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
 	INIT_LIST_HEAD(&fs_info->space_info);
@@ -2650,12 +2598,12 @@
 	__setup_root(4096, 4096, 4096, tree_root,
 		     fs_info, BTRFS_ROOT_TREE_OBJECTID);
 
-	invalidate_bdev(fs_devices->latest_bdev);
+	invalidate_bdev(fs_devices->latest_dev->bdev);
 
 	/*
 	 * Read super block and check the signature bytes only
 	 */
-	bh = btrfs_read_dev_super(fs_devices->latest_bdev);
+	bh = btrfs_read_dev_super(fs_devices->latest_dev->bdev);
 	if (IS_ERR(bh)) {
 		err = PTR_ERR(bh);
 		goto fail_alloc;
@@ -2668,6 +2616,7 @@
 	if (btrfs_check_super_csum(bh->b_data)) {
 		printk(KERN_ERR "BTRFS: superblock checksum mismatch\n");
 		err = -EINVAL;
+		brelse(bh);
 		goto fail_alloc;
 	}
 
@@ -2874,7 +2823,7 @@
 	 */
 	btrfs_close_extra_devices(fs_devices, 0);
 
-	if (!fs_devices->latest_bdev) {
+	if (!fs_devices->latest_dev->bdev) {
 		printk(KERN_ERR "BTRFS: failed to read devices on %s\n",
 		       sb->s_id);
 		goto fail_tree_roots;
@@ -2900,6 +2849,18 @@
 	tree_root->commit_root = btrfs_root_node(tree_root);
 	btrfs_set_root_refs(&tree_root->root_item, 1);
 
+	mutex_lock(&tree_root->objectid_mutex);
+	ret = btrfs_find_highest_objectid(tree_root,
+					&tree_root->highest_objectid);
+	if (ret) {
+		mutex_unlock(&tree_root->objectid_mutex);
+		goto recovery_tree_root;
+	}
+
+	ASSERT(tree_root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID);
+
+	mutex_unlock(&tree_root->objectid_mutex);
+
 	ret = btrfs_read_roots(fs_info, tree_root);
 	if (ret)
 		goto recovery_tree_root;
@@ -3011,6 +2972,7 @@
 
 	/* do not make disk changes in broken FS */
 	if (btrfs_super_log_root(disk_super) != 0) {
+		btrfs_info(fs_info, "start tree-log replay");
 		ret = btrfs_replay_log(fs_info, fs_devices);
 		if (ret) {
 			err = ret;
@@ -3781,7 +3743,7 @@
 	smp_mb();
 
 	/* wait for the qgroup rescan worker to stop */
-	btrfs_qgroup_wait_for_completion(fs_info);
+	btrfs_qgroup_wait_for_completion(fs_info, false);
 
 	/* wait for the uuid_scan task to finish */
 	down(&fs_info->uuid_tree_rescan_sem);
@@ -3812,6 +3774,19 @@
 		 */
 		btrfs_delete_unused_bgs(root->fs_info);
 
+		/*
+		 * There might be existing delayed inode workers still running
+		 * and holding an empty delayed inode item. We must wait for
+		 * them to complete first because they can create a transaction.
+		 * This happens when someone calls btrfs_balance_delayed_items()
+		 * and then a transaction commit runs the same delayed nodes
+		 * before any delayed worker has done something with the nodes.
+		 * We must wait for any worker here and not at transaction
+		 * commit time since that could cause a deadlock.
+		 * This is a very rare case.
+		 */
+		btrfs_flush_workqueue(fs_info->delayed_workers);
+
 		ret = btrfs_commit_super(root);
 		if (ret)
 			btrfs_err(fs_info, "commit super ret %d", ret);
@@ -3934,7 +3909,13 @@
 				     buf->len,
 				     root->fs_info->dirty_metadata_batch);
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-	if (btrfs_header_level(buf) == 0 && check_leaf(root, buf)) {
+	/*
+	 * Since btrfs_mark_buffer_dirty() can be called with item pointer set
+	 * but item data not updated.
+	 * So here we should only check item pointers, not item data.
+	 */
+	if (btrfs_header_level(buf) == 0 &&
+	    btrfs_check_leaf_relaxed(root, buf)) {
 		btrfs_print_leaf(root, buf);
 		ASSERT(0);
 	}
@@ -3956,8 +3937,9 @@
 	if (flush_delayed)
 		btrfs_balance_delayed_items(root);
 
-	ret = percpu_counter_compare(&root->fs_info->dirty_metadata_bytes,
-				     BTRFS_DIRTY_METADATA_THRESH);
+	ret = __percpu_counter_compare(&root->fs_info->dirty_metadata_bytes,
+				     BTRFS_DIRTY_METADATA_THRESH,
+				     root->fs_info->dirty_metadata_batch);
 	if (ret > 0) {
 		balance_dirty_pages_ratelimited(
 				   root->fs_info->btree_inode->i_mapping);
@@ -4142,6 +4124,14 @@
 		spin_lock(&fs_info->ordered_root_lock);
 	}
 	spin_unlock(&fs_info->ordered_root_lock);
+
+	/*
+	 * We need this here because if we've been flipped read-only we won't
+	 * get sync() from the umount, so we need to make sure any ordered
+	 * extents that haven't had their dirty pages IO start writeout yet
+	 * actually get run and error out properly.
+	 */
+	btrfs_wait_ordered_roots(fs_info, -1);
 }
 
 static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
@@ -4300,6 +4290,7 @@
 static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
 				       struct extent_io_tree *pinned_extents)
 {
+	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct extent_io_tree *unpin;
 	u64 start;
 	u64 end;
@@ -4309,21 +4300,31 @@
 	unpin = pinned_extents;
 again:
 	while (1) {
+		/*
+		 * The btrfs_finish_extent_commit() may get the same range as
+		 * ours between find_first_extent_bit and clear_extent_dirty.
+		 * Hence, hold the unused_bg_unpin_mutex to avoid double unpin
+		 * the same extent range.
+		 */
+		mutex_lock(&fs_info->unused_bg_unpin_mutex);
 		ret = find_first_extent_bit(unpin, 0, &start, &end,
 					    EXTENT_DIRTY, NULL);
-		if (ret)
+		if (ret) {
+			mutex_unlock(&fs_info->unused_bg_unpin_mutex);
 			break;
+		}
 
 		clear_extent_dirty(unpin, start, end, GFP_NOFS);
 		btrfs_error_unpin_extent_range(root, start, end);
+		mutex_unlock(&fs_info->unused_bg_unpin_mutex);
 		cond_resched();
 	}
 
 	if (loop) {
-		if (unpin == &root->fs_info->freed_extents[0])
-			unpin = &root->fs_info->freed_extents[1];
+		if (unpin == &fs_info->freed_extents[0])
+			unpin = &fs_info->freed_extents[1];
 		else
-			unpin = &root->fs_info->freed_extents[0];
+			unpin = &fs_info->freed_extents[0];
 		loop = false;
 		goto again;
 	}
--- linux-4.4.0.orig/fs/btrfs/disk-io.h
+++ linux-4.4.0/fs/btrfs/disk-io.h
@@ -68,6 +68,8 @@
 struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
 				      struct btrfs_key *location);
 int btrfs_init_fs_root(struct btrfs_root *root);
+struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
+					u64 root_id);
 int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
 			 struct btrfs_root *root);
 void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info);
--- linux-4.4.0.orig/fs/btrfs/export.c
+++ linux-4.4.0/fs/btrfs/export.c
@@ -55,9 +55,9 @@
 	return type;
 }
 
-static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
-				       u64 root_objectid, u32 generation,
-				       int check_generation)
+struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
+				u64 root_objectid, u32 generation,
+				int check_generation)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
 	struct btrfs_root *root;
@@ -150,7 +150,7 @@
 	return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
 }
 
-static struct dentry *btrfs_get_parent(struct dentry *child)
+struct dentry *btrfs_get_parent(struct dentry *child)
 {
 	struct inode *dir = d_inode(child);
 	struct btrfs_root *root = BTRFS_I(dir)->root;
--- linux-4.4.0.orig/fs/btrfs/export.h
+++ linux-4.4.0/fs/btrfs/export.h
@@ -16,4 +16,9 @@
 	u64 parent_root_objectid;
 } __attribute__ ((packed));
 
+struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
+				u64 root_objectid, u32 generation,
+				int check_generation);
+struct dentry *btrfs_get_parent(struct dentry *child);
+
 #endif
--- linux-4.4.0.orig/fs/btrfs/extent-tree.c
+++ linux-4.4.0/fs/btrfs/extent-tree.c
@@ -2342,7 +2342,13 @@
 		ins.type = BTRFS_EXTENT_ITEM_KEY;
 	}
 
-	BUG_ON(node->ref_mod != 1);
+	if (node->ref_mod != 1) {
+		btrfs_err(root->fs_info,
+	"btree block(%llu) has %d references rather than 1: action %d ref_root %llu parent %llu",
+			  node->bytenr, node->ref_mod, node->action, ref_root,
+			  parent);
+		return -EIO;
+	}
 	if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) {
 		BUG_ON(!extent_op || !extent_op->update_flags);
 		ret = alloc_reserved_tree_block(trans, root,
@@ -2520,11 +2526,11 @@
 		if (ref && ref->seq &&
 		    btrfs_check_delayed_seq(fs_info, delayed_refs, ref->seq)) {
 			spin_unlock(&locked_ref->lock);
-			btrfs_delayed_ref_unlock(locked_ref);
 			spin_lock(&delayed_refs->lock);
 			locked_ref->processing = 0;
 			delayed_refs->num_heads_ready++;
 			spin_unlock(&delayed_refs->lock);
+			btrfs_delayed_ref_unlock(locked_ref);
 			locked_ref = NULL;
 			cond_resched();
 			count++;
@@ -2570,7 +2576,10 @@
 					 */
 					if (must_insert_reserved)
 						locked_ref->must_insert_reserved = 1;
+					spin_lock(&delayed_refs->lock);
 					locked_ref->processing = 0;
+					delayed_refs->num_heads_ready++;
+					spin_unlock(&delayed_refs->lock);
 					btrfs_debug(fs_info, "run_delayed_extent_op returned %d", ret);
 					btrfs_delayed_ref_unlock(locked_ref);
 					return ret;
@@ -3358,13 +3367,6 @@
 		goto again;
 	}
 
-	/* We've already setup this transaction, go ahead and exit */
-	if (block_group->cache_generation == trans->transid &&
-	    i_size_read(inode)) {
-		dcs = BTRFS_DC_SETUP;
-		goto out_put;
-	}
-
 	/*
 	 * We want to set the generation to 0, that way if anything goes wrong
 	 * from here on out we know not to trust this cache when we load up next
@@ -3388,6 +3390,13 @@
 	}
 	WARN_ON(ret);
 
+	/* We've already setup this transaction, go ahead and exit */
+	if (block_group->cache_generation == trans->transid &&
+	    i_size_read(inode)) {
+		dcs = BTRFS_DC_SETUP;
+		goto out_put;
+	}
+
 	if (i_size_read(inode) > 0) {
 		ret = btrfs_check_trunc_cache_free_space(root,
 					&root->fs_info->global_block_rsv);
@@ -3851,6 +3860,7 @@
 				    info->space_info_kobj, "%s",
 				    alloc_name(found->flags));
 	if (ret) {
+		percpu_counter_destroy(&found->total_bytes_pinned);
 		kfree(found);
 		return ret;
 	}
@@ -4086,8 +4096,10 @@
 		    !atomic_read(&root->fs_info->open_ioctl_trans)) {
 			need_commit--;
 
-			if (need_commit > 0)
+			if (need_commit > 0) {
+				btrfs_start_delalloc_roots(fs_info, 0, -1);
 				btrfs_wait_ordered_roots(fs_info, -1);
+			}
 
 			trans = btrfs_join_transaction(root);
 			if (IS_ERR(trans))
@@ -4100,11 +4112,12 @@
 				if (ret)
 					return ret;
 				/*
-				 * make sure that all running delayed iput are
-				 * done
+				 * The cleaner kthread might still be doing iput
+				 * operations. Wait for it to finish so that
+				 * more space is released.
 				 */
-				down_write(&root->fs_info->delayed_iput_sem);
-				up_write(&root->fs_info->delayed_iput_sem);
+				mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex);
+				mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex);
 				goto again;
 			} else {
 				btrfs_end_transaction(trans, root);
@@ -4121,7 +4134,7 @@
 				      data_sinfo->flags, bytes, 1);
 	spin_unlock(&data_sinfo->lock);
 
-	return ret;
+	return 0;
 }
 
 /*
@@ -4385,6 +4398,7 @@
 	if (wait_for_alloc) {
 		mutex_unlock(&fs_info->chunk_mutex);
 		wait_for_alloc = 0;
+		cond_resched();
 		goto again;
 	}
 
@@ -7154,6 +7168,14 @@
 			 */
 			if ((flags & extra) && !(block_group->flags & extra))
 				goto loop;
+
+			/*
+			 * This block group has different flags than we want.
+			 * It's possible that we have MIXED_GROUP flag but no
+			 * block group is mixed.  Just skip such block group.
+			 */
+			btrfs_release_block_group(block_group, delalloc);
+			continue;
 		}
 
 have_block_group:
@@ -7827,6 +7849,20 @@
 	buf = btrfs_find_create_tree_block(root, bytenr);
 	if (!buf)
 		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * Extra safety check in case the extent tree is corrupted and extent
+	 * allocator chooses to use a tree block which is already used and
+	 * locked.
+	 */
+	if (buf->lock_owner == current->pid) {
+		btrfs_err_rl(root->fs_info,
+"tree block %llu owner %llu already locked by pid=%d, extent tree corruption detected",
+			buf->start, btrfs_header_owner(buf), current->pid);
+		free_extent_buffer(buf);
+		return ERR_PTR(-EUCLEAN);
+	}
+
 	btrfs_set_header_generation(buf, trans->transid);
 	btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level);
 	btrfs_tree_lock(buf);
@@ -7853,7 +7889,7 @@
 		set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
 			 buf->start + buf->len - 1, GFP_NOFS);
 	}
-	trans->blocks_used++;
+	trans->dirty = true;
 	/* this returns a buffer locked for blocking */
 	return buf;
 }
@@ -8001,6 +8037,7 @@
 out_free_delayed:
 	btrfs_free_delayed_extent_op(extent_op);
 out_free_buf:
+	btrfs_tree_unlock(buf);
 	free_extent_buffer(buf);
 out_free_reserved:
 	btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 0);
@@ -8483,14 +8520,13 @@
 	ret = btrfs_lookup_extent_info(trans, root, bytenr, level - 1, 1,
 				       &wc->refs[level - 1],
 				       &wc->flags[level - 1]);
-	if (ret < 0) {
-		btrfs_tree_unlock(next);
-		return ret;
-	}
+	if (ret < 0)
+		goto out_unlock;
 
 	if (unlikely(wc->refs[level - 1] == 0)) {
 		btrfs_err(root->fs_info, "Missing references.");
-		BUG();
+		ret = -EIO;
+		goto out_unlock;
 	}
 	*lookup_info = 0;
 
@@ -8542,7 +8578,12 @@
 	}
 
 	level--;
-	BUG_ON(level != btrfs_header_level(next));
+	ASSERT(level == btrfs_header_level(next));
+	if (level != btrfs_header_level(next)) {
+		btrfs_err(root->fs_info, "mismatched level");
+		ret = -EIO;
+		goto out_unlock;
+	}
 	path->nodes[level] = next;
 	path->slots[level] = 0;
 	path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
@@ -8557,8 +8598,15 @@
 		if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
 			parent = path->nodes[level]->start;
 		} else {
-			BUG_ON(root->root_key.objectid !=
+			ASSERT(root->root_key.objectid ==
 			       btrfs_header_owner(path->nodes[level]));
+			if (root->root_key.objectid !=
+			    btrfs_header_owner(path->nodes[level])) {
+				btrfs_err(root->fs_info,
+						"mismatched block owner");
+				ret = -EIO;
+				goto out_unlock;
+			}
 			parent = 0;
 		}
 
@@ -8575,12 +8623,18 @@
 		}
 		ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
 				root->root_key.objectid, level - 1, 0);
-		BUG_ON(ret); /* -ENOMEM */
+		if (ret)
+			goto out_unlock;
 	}
+
+	*lookup_info = 1;
+	ret = 1;
+
+out_unlock:
 	btrfs_tree_unlock(next);
 	free_extent_buffer(next);
-	*lookup_info = 1;
-	return 1;
+
+	return ret;
 }
 
 /*
@@ -8679,15 +8733,14 @@
 	if (eb == root->node) {
 		if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
 			parent = eb->start;
-		else
-			BUG_ON(root->root_key.objectid !=
-			       btrfs_header_owner(eb));
+		else if (root->root_key.objectid != btrfs_header_owner(eb))
+			goto owner_mismatch;
 	} else {
 		if (wc->flags[level + 1] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
 			parent = path->nodes[level + 1]->start;
-		else
-			BUG_ON(root->root_key.objectid !=
-			       btrfs_header_owner(path->nodes[level + 1]));
+		else if (root->root_key.objectid !=
+			 btrfs_header_owner(path->nodes[level + 1]))
+			goto owner_mismatch;
 	}
 
 	btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1);
@@ -8695,6 +8748,11 @@
 	wc->refs[level] = 0;
 	wc->flags[level] = 0;
 	return 0;
+
+owner_mismatch:
+	btrfs_err_rl(root->fs_info, "unexpected tree owner, have %llu expect %llu",
+		     btrfs_header_owner(eb), root->root_key.objectid);
+	return -EUCLEAN;
 }
 
 static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
@@ -8748,6 +8806,8 @@
 			ret = walk_up_proc(trans, root, path, wc);
 			if (ret > 0)
 				return 0;
+			if (ret < 0)
+				return ret;
 
 			if (path->locks[level]) {
 				btrfs_tree_unlock_rw(path->nodes[level],
@@ -9436,6 +9496,8 @@
 	int ret = 0;
 	struct btrfs_key found_key;
 	struct extent_buffer *leaf;
+	struct btrfs_block_group_item bg;
+	u64 flags;
 	int slot;
 
 	ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
@@ -9457,7 +9519,47 @@
 
 		if (found_key.objectid >= key->objectid &&
 		    found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {
-			ret = 0;
+			struct extent_map_tree *em_tree;
+			struct extent_map *em;
+
+			em_tree = &root->fs_info->mapping_tree.map_tree;
+			read_lock(&em_tree->lock);
+			em = lookup_extent_mapping(em_tree, found_key.objectid,
+						   found_key.offset);
+			read_unlock(&em_tree->lock);
+			if (!em) {
+				btrfs_err(root->fs_info,
+			"logical %llu len %llu found bg but no related chunk",
+					  found_key.objectid, found_key.offset);
+				ret = -ENOENT;
+			} else if (em->start != found_key.objectid ||
+				   em->len != found_key.offset) {
+				btrfs_err(root->fs_info,
+		"block group %llu len %llu mismatch with chunk %llu len %llu",
+					  found_key.objectid, found_key.offset,
+					  em->start, em->len);
+				ret = -EUCLEAN;
+			} else {
+				read_extent_buffer(leaf, &bg,
+					btrfs_item_ptr_offset(leaf, slot),
+					sizeof(bg));
+				flags = btrfs_block_group_flags(&bg) &
+					BTRFS_BLOCK_GROUP_TYPE_MASK;
+
+				if (flags != (em->map_lookup->type &
+					      BTRFS_BLOCK_GROUP_TYPE_MASK)) {
+					btrfs_err(root->fs_info,
+"block group %llu len %llu type flags 0x%llx mismatch with chunk type flags 0x%llx",
+						found_key.objectid,
+						found_key.offset, flags,
+						(BTRFS_BLOCK_GROUP_TYPE_MASK &
+						 em->map_lookup->type));
+					ret = -EUCLEAN;
+				} else {
+					ret = 0;
+				}
+			}
+			free_extent_map(em);
 			goto out;
 		}
 		path->slots[0]++;
@@ -9476,6 +9578,7 @@
 
 		block_group = btrfs_lookup_first_block_group(info, last);
 		while (block_group) {
+			wait_block_group_cache_done(block_group);
 			spin_lock(&block_group->lock);
 			if (block_group->iref)
 				break;
@@ -9671,6 +9774,62 @@
 	return cache;
 }
 
+
+/*
+ * Iterate all chunks and verify that each of them has the corresponding block
+ * group
+ */
+static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
+{
+	struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+	struct extent_map *em;
+	struct btrfs_block_group_cache *bg;
+	u64 start = 0;
+	int ret = 0;
+
+	while (1) {
+		read_lock(&map_tree->map_tree.lock);
+		/*
+		 * lookup_extent_mapping will return the first extent map
+		 * intersecting the range, so setting @len to 1 is enough to
+		 * get the first chunk.
+		 */
+		em = lookup_extent_mapping(&map_tree->map_tree, start, 1);
+		read_unlock(&map_tree->map_tree.lock);
+		if (!em)
+			break;
+
+		bg = btrfs_lookup_block_group(fs_info, em->start);
+		if (!bg) {
+			btrfs_err(fs_info,
+	"chunk start=%llu len=%llu doesn't have corresponding block group",
+				     em->start, em->len);
+			ret = -EUCLEAN;
+			free_extent_map(em);
+			break;
+		}
+		if (bg->key.objectid != em->start ||
+		    bg->key.offset != em->len ||
+		    (bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) !=
+		    (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
+			btrfs_err(fs_info,
+"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx",
+				em->start, em->len,
+				em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK,
+				bg->key.objectid, bg->key.offset,
+				bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK);
+			ret = -EUCLEAN;
+			free_extent_map(em);
+			btrfs_put_block_group(bg);
+			break;
+		}
+		start = em->start + em->len;
+		free_extent_map(em);
+		btrfs_put_block_group(bg);
+	}
+	return ret;
+}
+
 int btrfs_read_block_groups(struct btrfs_root *root)
 {
 	struct btrfs_path *path;
@@ -9683,6 +9842,11 @@
 	struct extent_buffer *leaf;
 	int need_clear = 0;
 	u64 cache_gen;
+	u64 feature;
+	int mixed;
+
+	feature = btrfs_super_incompat_flags(info->super_copy);
+	mixed = !!(feature & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS);
 
 	root = info->extent_root;
 	key.objectid = 0;
@@ -9736,6 +9900,16 @@
 				   btrfs_item_ptr_offset(leaf, path->slots[0]),
 				   sizeof(cache->item));
 		cache->flags = btrfs_block_group_flags(&cache->item);
+		if (!mixed &&
+		    ((cache->flags & BTRFS_BLOCK_GROUP_METADATA) &&
+		    (cache->flags & BTRFS_BLOCK_GROUP_DATA))) {
+			btrfs_err(info,
+"bg %llu is a mixed block group but filesystem hasn't enabled mixed block groups",
+				  cache->key.objectid);
+			btrfs_put_block_group(cache);
+			ret = -EINVAL;
+			goto error;
+		}
 
 		key.objectid = found_key.objectid + found_key.offset;
 		btrfs_release_path(path);
@@ -9843,7 +10017,7 @@
 	}
 
 	init_global_block_rsv(info);
-	ret = 0;
+	ret = check_chunk_block_group_mappings(info);
 error:
 	btrfs_free_path(path);
 	return ret;
@@ -9852,7 +10026,7 @@
 void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
 				       struct btrfs_root *root)
 {
-	struct btrfs_block_group_cache *block_group, *tmp;
+	struct btrfs_block_group_cache *block_group;
 	struct btrfs_root *extent_root = root->fs_info->extent_root;
 	struct btrfs_block_group_item item;
 	struct btrfs_key key;
@@ -9860,7 +10034,10 @@
 	bool can_flush_pending_bgs = trans->can_flush_pending_bgs;
 
 	trans->can_flush_pending_bgs = false;
-	list_for_each_entry_safe(block_group, tmp, &trans->new_bgs, bg_list) {
+	while (!list_empty(&trans->new_bgs)) {
+		block_group = list_first_entry(&trans->new_bgs,
+					       struct btrfs_block_group_cache,
+					       bg_list);
 		if (ret)
 			goto next;
 
@@ -10325,7 +10502,7 @@
 	 * more device items and remove one chunk item), but this is done at
 	 * btrfs_remove_chunk() through a call to check_system_chunk().
 	 */
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	num_items = 3 + map->num_stripes;
 	free_extent_map(em);
 
@@ -10371,7 +10548,7 @@
 		/* Don't want to race with allocators so take the groups_sem */
 		down_write(&space_info->groups_sem);
 		spin_lock(&block_group->lock);
-		if (block_group->reserved ||
+		if (block_group->reserved || block_group->pinned ||
 		    btrfs_block_group_used(&block_group->item) ||
 		    block_group->ro ||
 		    list_is_singular(&block_group->list)) {
@@ -10512,7 +10689,7 @@
 
 	disk_super = fs_info->super_copy;
 	if (!btrfs_super_root(disk_super))
-		return 1;
+		return -EINVAL;
 
 	features = btrfs_super_incompat_flags(disk_super);
 	if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
@@ -10563,13 +10740,17 @@
  * transaction.
  */
 static int btrfs_trim_free_extents(struct btrfs_device *device,
-				   u64 minlen, u64 *trimmed)
+				   struct fstrim_range *range, u64 *trimmed)
 {
-	u64 start = 0, len = 0;
+	u64 start = range->start, len = 0;
 	int ret;
 
 	*trimmed = 0;
 
+	/* Discard not supported = nothing to do. */
+	if (!blk_queue_discard(bdev_get_queue(device->bdev)))
+		return 0;
+
 	/* Not writeable = nothing to do. */
 	if (!device->writeable)
 		return 0;
@@ -10597,8 +10778,8 @@
 			atomic_inc(&trans->use_count);
 		spin_unlock(&fs_info->trans_lock);
 
-		ret = find_free_dev_extent_start(trans, device, minlen, start,
-						 &start, &len);
+		ret = find_free_dev_extent_start(trans, device, range->minlen,
+						 start, &start, &len);
 		if (trans)
 			btrfs_put_transaction(trans);
 
@@ -10610,6 +10791,16 @@
 			break;
 		}
 
+		/* If we are out of the passed range break */
+		if (start > range->start + range->len - 1) {
+			mutex_unlock(&fs_info->chunk_mutex);
+			ret = 0;
+			break;
+		}
+
+		start = max(range->start, start);
+		len = min(range->len, len);
+
 		ret = btrfs_issue_discard(device->bdev, start, len, &bytes);
 		up_read(&fs_info->commit_root_sem);
 		mutex_unlock(&fs_info->chunk_mutex);
@@ -10620,6 +10811,10 @@
 		start += len;
 		*trimmed += bytes;
 
+		/* We've trimmed enough */
+		if (*trimmed >= range->len)
+			break;
+
 		if (fatal_signal_pending(current)) {
 			ret = -ERESTARTSYS;
 			break;
@@ -10641,17 +10836,9 @@
 	u64 start;
 	u64 end;
 	u64 trimmed = 0;
-	u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
 	int ret = 0;
 
-	/*
-	 * try to trim all FS space, our block group may start from non-zero.
-	 */
-	if (range->len == total_bytes)
-		cache = btrfs_lookup_first_block_group(fs_info, range->start);
-	else
-		cache = btrfs_lookup_block_group(fs_info, range->start);
-
+	cache = btrfs_lookup_first_block_group(fs_info, range->start);
 	while (cache) {
 		if (cache->key.objectid >= (range->start + range->len)) {
 			btrfs_put_block_group(cache);
@@ -10692,10 +10879,9 @@
 	}
 
 	mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
-	devices = &root->fs_info->fs_devices->alloc_list;
-	list_for_each_entry(device, devices, dev_alloc_list) {
-		ret = btrfs_trim_free_extents(device, range->minlen,
-					      &group_trimmed);
+	devices = &root->fs_info->fs_devices->devices;
+	list_for_each_entry(device, devices, dev_list) {
+		ret = btrfs_trim_free_extents(device, range, &group_trimmed);
 		if (ret)
 			break;
 
--- linux-4.4.0.orig/fs/btrfs/extent_io.c
+++ linux-4.4.0/fs/btrfs/extent_io.c
@@ -2433,7 +2433,7 @@
 
 	bio->bi_end_io = endio_func;
 	bio->bi_iter.bi_sector = failrec->logical >> 9;
-	bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
+	bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_dev->bdev;
 	bio->bi_iter.bi_size = 0;
 	bio->bi_private = data;
 
@@ -2534,7 +2534,7 @@
 	if (!uptodate) {
 		ClearPageUptodate(page);
 		SetPageError(page);
-		ret = ret < 0 ? ret : -EIO;
+		ret = err < 0 ? err : -EIO;
 		mapping_set_error(page->mapping, ret);
 	}
 	return 0;
@@ -2786,12 +2786,6 @@
 		btrfs_bio->csum = NULL;
 		btrfs_bio->csum_allocated = NULL;
 		btrfs_bio->end_io = NULL;
-
-#ifdef CONFIG_BLK_CGROUP
-		/* FIXME, put this into bio_clone_bioset */
-		if (bio->bi_css)
-			bio_associate_blkcg(new, bio->bi_css);
-#endif
 	}
 	return new;
 }
@@ -3112,11 +3106,11 @@
 		 */
 		if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) &&
 		    prev_em_start && *prev_em_start != (u64)-1 &&
-		    *prev_em_start != em->orig_start)
+		    *prev_em_start != em->start)
 			force_bio_submit = true;
 
 		if (prev_em_start)
-			*prev_em_start = em->orig_start;
+			*prev_em_start = em->start;
 
 		free_extent_map(em);
 		em = NULL;
@@ -3850,11 +3844,13 @@
 			struct writeback_control *wbc,
 			struct extent_page_data *epd)
 {
-	struct block_device *bdev = fs_info->fs_devices->latest_bdev;
+	struct block_device *bdev = fs_info->fs_devices->latest_dev->bdev;
 	struct extent_io_tree *tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
 	u64 offset = eb->start;
+	u32 nritems;
 	unsigned long i, num_pages;
 	unsigned long bio_flags = 0;
+	unsigned long start, end;
 	int rw = (epd->sync_io ? WRITE_SYNC : WRITE) | REQ_META;
 	int ret = 0;
 
@@ -3864,6 +3860,23 @@
 	if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID)
 		bio_flags = EXTENT_BIO_TREE_LOG;
 
+	/* set btree blocks beyond nritems with 0 to avoid stale content. */
+	nritems = btrfs_header_nritems(eb);
+	if (btrfs_header_level(eb) > 0) {
+		end = btrfs_node_key_ptr_offset(nritems);
+
+		memset_extent_buffer(eb, 0, end, eb->len - end);
+	} else {
+		/*
+		 * leaf:
+		 * header 0 1 2 .. N ... data_N .. data_2 data_1 data_0
+		 */
+		start = btrfs_item_nr_offset(nritems);
+		end = btrfs_leaf_data(eb) +
+		      leaf_data_end(fs_info->tree_root, eb);
+		memset_extent_buffer(eb, 0, start, end - start);
+	}
+
 	for (i = 0; i < num_pages; i++) {
 		struct page *p = eb->pages[i];
 
@@ -3987,6 +4000,10 @@
 			if (!ret) {
 				free_extent_buffer(eb);
 				continue;
+			} else if (ret < 0) {
+				done = 1;
+				free_extent_buffer(eb);
+				break;
 			}
 
 			ret = write_one_eb(eb, fs_info, wbc, &epd);
@@ -4151,6 +4168,14 @@
 		 */
 		scanned = 1;
 		index = 0;
+
+		/*
+		 * If we're looping we could run into a page that is locked by a
+		 * writer and that writer could be waiting on writeback for a
+		 * page in our current bio, and thus deadlock, so flush the
+		 * write bio here.
+		 */
+		flush_write_bio(data);
 		goto retry;
 	}
 	btrfs_add_delayed_iput(inode);
@@ -4416,6 +4441,8 @@
 
 			/* once for us */
 			free_extent_map(em);
+
+			cond_resched(); /* Allow large-extent preemption. */
 		}
 	}
 	return try_release_extent_state(map, tree, page, mask);
@@ -4840,25 +4867,28 @@
 static void check_buffer_tree_ref(struct extent_buffer *eb)
 {
 	int refs;
-	/* the ref bit is tricky.  We have to make sure it is set
-	 * if we have the buffer dirty.   Otherwise the
-	 * code to free a buffer can end up dropping a dirty
-	 * page
+	/*
+	 * The TREE_REF bit is first set when the extent_buffer is added
+	 * to the radix tree. It is also reset, if unset, when a new reference
+	 * is created by find_extent_buffer.
 	 *
-	 * Once the ref bit is set, it won't go away while the
-	 * buffer is dirty or in writeback, and it also won't
-	 * go away while we have the reference count on the
-	 * eb bumped.
+	 * It is only cleared in two cases: freeing the last non-tree
+	 * reference to the extent_buffer when its STALE bit is set or
+	 * calling releasepage when the tree reference is the only reference.
 	 *
-	 * We can't just set the ref bit without bumping the
-	 * ref on the eb because free_extent_buffer might
-	 * see the ref bit and try to clear it.  If this happens
-	 * free_extent_buffer might end up dropping our original
-	 * ref by mistake and freeing the page before we are able
-	 * to add one more ref.
+	 * In both cases, care is taken to ensure that the extent_buffer's
+	 * pages are not under io. However, releasepage can be concurrently
+	 * called with creating new references, which is prone to race
+	 * conditions between the calls to check_buffer_tree_ref in those
+	 * codepaths and clearing TREE_REF in try_release_extent_buffer.
 	 *
-	 * So bump the ref count first, then set the bit.  If someone
-	 * beat us to it, drop the ref we added.
+	 * The actual lifetime of the extent_buffer in the radix tree is
+	 * adequately protected by the refcount, but the TREE_REF bit and
+	 * its corresponding reference are not. To protect against this
+	 * class of races, we call check_buffer_tree_ref from the codepaths
+	 * which trigger io after they set eb->io_pages. Note that once io is
+	 * initiated, TREE_REF can no longer be cleared, so that is the
+	 * moment at which any such race is best fixed.
 	 */
 	refs = atomic_read(&eb->refs);
 	if (refs >= 2 && test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
@@ -4935,12 +4965,14 @@
 		return eb;
 	eb = alloc_dummy_extent_buffer(fs_info, start);
 	if (!eb)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	eb->fs_info = fs_info;
 again:
 	ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
-	if (ret)
+	if (ret) {
+		exists = ERR_PTR(ret);
 		goto free_eb;
+	}
 	spin_lock(&fs_info->buffer_lock);
 	ret = radix_tree_insert(&fs_info->buffer_radix,
 				start >> PAGE_CACHE_SHIFT, eb);
@@ -5300,11 +5332,20 @@
 			lock_page(page);
 		}
 		locked_pages++;
+	}
+	/*
+	 * We need to firstly lock all pages to make sure that
+	 * the uptodate bit of our pages won't be affected by
+	 * clear_extent_buffer_uptodate().
+	 */
+	for (i = start_i; i < num_pages; i++) {
+		page = eb->pages[i];
 		if (!PageUptodate(page)) {
 			num_reads++;
 			all_uptodate = 0;
 		}
 	}
+
 	if (all_uptodate) {
 		if (start_i == 0)
 			set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
@@ -5314,6 +5355,11 @@
 	clear_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
 	eb->read_mirror = 0;
 	atomic_set(&eb->io_pages, num_reads);
+	/*
+	 * It is possible for releasepage to clear the TREE_REF bit before we
+	 * set io_pages. See check_buffer_tree_ref for a more detailed comment.
+	 */
+	check_buffer_tree_ref(eb);
 	for (i = start_i; i < num_pages; i++) {
 		page = eb->pages[i];
 		if (!PageUptodate(page)) {
@@ -5359,9 +5405,8 @@
 	return ret;
 }
 
-void read_extent_buffer(struct extent_buffer *eb, void *dstv,
-			unsigned long start,
-			unsigned long len)
+void read_extent_buffer(const struct extent_buffer *eb, void *dstv,
+			unsigned long start, unsigned long len)
 {
 	size_t cur;
 	size_t offset;
@@ -5390,9 +5435,9 @@
 	}
 }
 
-int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv,
-			unsigned long start,
-			unsigned long len)
+int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
+				       void __user *dstv,
+				       unsigned long start, unsigned long len)
 {
 	size_t cur;
 	size_t offset;
@@ -5413,7 +5458,7 @@
 
 		cur = min(len, (PAGE_CACHE_SIZE - offset));
 		kaddr = page_address(page);
-		if (copy_to_user(dst, kaddr + offset, cur)) {
+		if (probe_user_write(dst, kaddr + offset, cur)) {
 			ret = -EFAULT;
 			break;
 		}
@@ -5427,10 +5472,10 @@
 	return ret;
 }
 
-int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
-			       unsigned long min_len, char **map,
-			       unsigned long *map_start,
-			       unsigned long *map_len)
+int map_private_extent_buffer(const struct extent_buffer *eb,
+			      unsigned long start, unsigned long min_len,
+			      char **map, unsigned long *map_start,
+			      unsigned long *map_len)
 {
 	size_t offset = start & (PAGE_CACHE_SIZE - 1);
 	char *kaddr;
@@ -5465,9 +5510,8 @@
 	return 0;
 }
 
-int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
-			  unsigned long start,
-			  unsigned long len)
+int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
+			 unsigned long start, unsigned long len)
 {
 	size_t cur;
 	size_t offset;
--- linux-4.4.0.orig/fs/btrfs/extent_io.h
+++ linux-4.4.0/fs/btrfs/extent_io.h
@@ -308,15 +308,14 @@
 	atomic_inc(&eb->refs);
 }
 
-int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
-			  unsigned long start,
-			  unsigned long len);
-void read_extent_buffer(struct extent_buffer *eb, void *dst,
+int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
+			 unsigned long start, unsigned long len);
+void read_extent_buffer(const struct extent_buffer *eb, void *dst,
 			unsigned long start,
 			unsigned long len);
-int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dst,
-			       unsigned long start,
-			       unsigned long len);
+int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
+				       void __user *dst, unsigned long start,
+				       unsigned long len);
 void write_extent_buffer(struct extent_buffer *eb, const void *src,
 			 unsigned long start, unsigned long len);
 void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
@@ -334,10 +333,10 @@
 int clear_extent_buffer_uptodate(struct extent_buffer *eb);
 int extent_buffer_uptodate(struct extent_buffer *eb);
 int extent_buffer_under_io(struct extent_buffer *eb);
-int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
-		      unsigned long min_len, char **map,
-		      unsigned long *map_start,
-		      unsigned long *map_len);
+int map_private_extent_buffer(const struct extent_buffer *eb,
+			      unsigned long offset, unsigned long min_len,
+			      char **map, unsigned long *map_start,
+			      unsigned long *map_len);
 int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
 int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
 int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
--- linux-4.4.0.orig/fs/btrfs/extent_map.c
+++ linux-4.4.0/fs/btrfs/extent_map.c
@@ -76,7 +76,7 @@
 		WARN_ON(extent_map_in_tree(em));
 		WARN_ON(!list_empty(&em->list));
 		if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags))
-			kfree(em->bdev);
+			kfree(em->map_lookup);
 		kmem_cache_free(extent_map_cache, em);
 	}
 }
@@ -227,6 +227,17 @@
 	struct extent_map *merge = NULL;
 	struct rb_node *rb;
 
+	/*
+	 * We can't modify an extent map that is in the tree and that is being
+	 * used by another task, as it can cause that other task to see it in
+	 * inconsistent state during the merging. We always have 1 reference for
+	 * the tree and 1 for this task (which is unpinning the extent map or
+	 * clearing the logging flag), so anything > 2 means it's being used by
+	 * other tasks too.
+	 */
+	if (atomic_read(&em->refs) > 2)
+		return;
+
 	if (em->start != 0) {
 		rb = rb_prev(&em->rb_node);
 		if (rb)
--- linux-4.4.0.orig/fs/btrfs/extent_map.h
+++ linux-4.4.0/fs/btrfs/extent_map.h
@@ -32,7 +32,15 @@
 	u64 block_len;
 	u64 generation;
 	unsigned long flags;
-	struct block_device *bdev;
+	union {
+		struct block_device *bdev;
+
+		/*
+		 * used for chunk mappings
+		 * flags & EXTENT_FLAG_FS_MAPPING must be set
+		 */
+		struct map_lookup *map_lookup;
+	};
 	atomic_t refs;
 	unsigned int compress_type;
 	struct list_head list;
--- linux-4.4.0.orig/fs/btrfs/file-item.c
+++ linux-4.4.0/fs/btrfs/file-item.c
@@ -742,10 +742,12 @@
 		nritems = btrfs_header_nritems(path->nodes[0]);
 		if (!nritems || (path->slots[0] >= nritems - 1)) {
 			ret = btrfs_next_leaf(root, path);
-			if (ret == 1)
+			if (ret < 0) {
+				goto out;
+			} else if (ret > 0) {
 				found_next = 1;
-			if (ret != 0)
 				goto insert;
+			}
 			slot = path->slots[0];
 		}
 		btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
@@ -891,7 +893,7 @@
 	u8 type = btrfs_file_extent_type(leaf, fi);
 	int compress_type = btrfs_file_extent_compression(leaf, fi);
 
-	em->bdev = root->fs_info->fs_devices->latest_bdev;
+	em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 	btrfs_item_key_to_cpu(leaf, &key, slot);
 	extent_start = key.offset;
 
--- linux-4.4.0.orig/fs/btrfs/file.c
+++ linux-4.4.0/fs/btrfs/file.c
@@ -1525,28 +1525,26 @@
 		}
 
 		reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
+		only_release_metadata = false;
 
-		if (BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
-					     BTRFS_INODE_PREALLOC)) {
-			ret = check_can_nocow(inode, pos, &write_bytes);
-			if (ret < 0)
-				break;
-			if (ret > 0) {
-				/*
-				 * For nodata cow case, no need to reserve
-				 * data space.
-				 */
-				only_release_metadata = true;
-				/*
-				 * our prealloc extent may be smaller than
-				 * write_bytes, so scale down.
-				 */
-				num_pages = DIV_ROUND_UP(write_bytes + offset,
-							 PAGE_CACHE_SIZE);
-				reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
-				goto reserve_metadata;
-			}
+		if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
+					      BTRFS_INODE_PREALLOC)) &&
+		    check_can_nocow(inode, pos, &write_bytes) > 0) {
+			/*
+			 * For nodata cow case, no need to reserve
+			 * data space.
+			 */
+			only_release_metadata = true;
+			/*
+			 * our prealloc extent may be smaller than
+			 * write_bytes, so scale down.
+			 */
+			num_pages = DIV_ROUND_UP(write_bytes + offset,
+						 PAGE_CACHE_SIZE);
+			reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
+			goto reserve_metadata;
 		}
+
 		ret = btrfs_check_data_free_space(inode, pos, write_bytes);
 		if (ret < 0)
 			break;
@@ -1662,7 +1660,6 @@
 			set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart,
 				       lockend, EXTENT_NORESERVE, NULL,
 				       NULL, GFP_NOFS);
-			only_release_metadata = false;
 		}
 
 		btrfs_drop_pages(pages, num_pages);
@@ -1864,10 +1861,19 @@
 static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end)
 {
 	int ret;
+	struct blk_plug plug;
 
+	/*
+	 * This is only called in fsync, which would do synchronous writes, so
+	 * a plug can merge adjacent IOs as much as possible.  Esp. in case of
+	 * multiple disks using raid profile, a large IO can be split to
+	 * several segments of stripe length (currently 64K).
+	 */
+	blk_start_plug(&plug);
 	atomic_inc(&BTRFS_I(inode)->sync_writers);
 	ret = btrfs_fdatawrite_range(inode, start, end);
 	atomic_dec(&BTRFS_I(inode)->sync_writers);
+	blk_finish_plug(&plug);
 
 	return ret;
 }
@@ -1885,7 +1891,7 @@
  */
 int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
-	struct dentry *dentry = file->f_path.dentry;
+	struct dentry *dentry = file_dentry(file);
 	struct inode *inode = d_inode(dentry);
 	struct btrfs_root *root = BTRFS_I(inode)->root;
 	struct btrfs_trans_handle *trans;
@@ -1895,6 +1901,18 @@
 	u64 len;
 
 	/*
+	 * If the inode needs a full sync, make sure we use a full range to
+	 * avoid log tree corruption, due to hole detection racing with ordered
+	 * extent completion for adjacent ranges, and assertion failures during
+	 * hole detection.
+	 */
+	if (test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+		     &BTRFS_I(inode)->runtime_flags)) {
+		start = 0;
+		end = LLONG_MAX;
+	}
+
+	/*
 	 * The range length can be represented by u64, we have to do the typecasts
 	 * to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync()
 	 */
@@ -2227,7 +2245,7 @@
 		hole_em->block_start = EXTENT_MAP_HOLE;
 		hole_em->block_len = 0;
 		hole_em->orig_block_len = 0;
-		hole_em->bdev = root->fs_info->fs_devices->latest_bdev;
+		hole_em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 		hole_em->compress_type = BTRFS_COMPRESS_NONE;
 		hole_em->generation = trans->transid;
 
@@ -2757,8 +2775,10 @@
 			}
 			ret = btrfs_qgroup_reserve_data(inode, cur_offset,
 					last_byte - cur_offset);
-			if (ret < 0)
+			if (ret < 0) {
+				free_extent_map(em);
 				break;
+			}
 		}
 		free_extent_map(em);
 		cur_offset = last_byte;
@@ -2774,7 +2794,7 @@
 		if (!ret)
 			ret = btrfs_prealloc_file_range(inode, mode,
 					range->start,
-					range->len, 1 << inode->i_blkbits,
+					range->len, i_blocksize(inode),
 					offset + len, &alloc_hint);
 		list_del(&range->list);
 		kfree(range);
@@ -2932,7 +2952,7 @@
 	.fallocate	= btrfs_fallocate,
 	.unlocked_ioctl	= btrfs_ioctl,
 #ifdef CONFIG_COMPAT
-	.compat_ioctl	= btrfs_ioctl,
+	.compat_ioctl	= btrfs_compat_ioctl,
 #endif
 };
 
--- linux-4.4.0.orig/fs/btrfs/free-space-cache.c
+++ linux-4.4.0/fs/btrfs/free-space-cache.c
@@ -391,6 +391,12 @@
 		if (uptodate && !PageUptodate(page)) {
 			btrfs_readpage(NULL, page);
 			lock_page(page);
+			if (page->mapping != inode->i_mapping) {
+				btrfs_err(BTRFS_I(inode)->root->fs_info,
+					  "free space cache page truncated");
+				io_ctl_drop_pages(io_ctl);
+				return -EIO;
+			}
 			if (!PageUptodate(page)) {
 				btrfs_err(BTRFS_I(inode)->root->fs_info,
 					   "error reading free space cache");
@@ -748,8 +754,10 @@
 	while (num_entries) {
 		e = kmem_cache_zalloc(btrfs_free_space_cachep,
 				      GFP_NOFS);
-		if (!e)
+		if (!e) {
+			ret = -ENOMEM;
 			goto free_cache;
+		}
 
 		ret = io_ctl_read_entry(&io_ctl, e, &type);
 		if (ret) {
@@ -758,6 +766,7 @@
 		}
 
 		if (!e->bytes) {
+			ret = -1;
 			kmem_cache_free(btrfs_free_space_cachep, e);
 			goto free_cache;
 		}
@@ -777,6 +786,7 @@
 			num_bitmaps--;
 			e->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
 			if (!e->bitmap) {
+				ret = -ENOMEM;
 				kmem_cache_free(
 					btrfs_free_space_cachep, e);
 				goto free_cache;
@@ -1258,7 +1268,7 @@
 	/* Lock all pages first so we can lock the extent safely. */
 	ret = io_ctl_prepare_pages(io_ctl, inode, 0);
 	if (ret)
-		goto out;
+		goto out_unlock;
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
 			 0, &cached_state);
@@ -1351,6 +1361,7 @@
 out_nospc:
 	cleanup_write_cache_enospc(inode, io_ctl, &cached_state, &bitmap_list);
 
+out_unlock:
 	if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))
 		up_write(&block_group->data_rwsem);
 
@@ -1698,6 +1709,8 @@
 	bitmap_clear(info->bitmap, start, count);
 
 	info->bytes -= bytes;
+	if (info->max_extent_size > ctl->unit)
+		info->max_extent_size = 0;
 }
 
 static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
@@ -1781,6 +1794,13 @@
 	return -1;
 }
 
+static inline u64 get_max_extent_size(struct btrfs_free_space *entry)
+{
+	if (entry->bitmap)
+		return entry->max_extent_size;
+	return entry->bytes;
+}
+
 /* Cache the size of the max extent in bytes */
 static struct btrfs_free_space *
 find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes,
@@ -1802,8 +1822,8 @@
 	for (node = &entry->offset_index; node; node = rb_next(node)) {
 		entry = rb_entry(node, struct btrfs_free_space, offset_index);
 		if (entry->bytes < *bytes) {
-			if (entry->bytes > *max_extent_size)
-				*max_extent_size = entry->bytes;
+			*max_extent_size = max(get_max_extent_size(entry),
+					       *max_extent_size);
 			continue;
 		}
 
@@ -1821,8 +1841,8 @@
 		}
 
 		if (entry->bytes < *bytes + align_off) {
-			if (entry->bytes > *max_extent_size)
-				*max_extent_size = entry->bytes;
+			*max_extent_size = max(get_max_extent_size(entry),
+					       *max_extent_size);
 			continue;
 		}
 
@@ -1834,8 +1854,10 @@
 				*offset = tmp;
 				*bytes = size;
 				return entry;
-			} else if (size > *max_extent_size) {
-				*max_extent_size = size;
+			} else {
+				*max_extent_size =
+					max(get_max_extent_size(entry),
+					    *max_extent_size);
 			}
 			continue;
 		}
@@ -2140,7 +2162,7 @@
 static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl,
 			  struct btrfs_free_space *info, bool update_stat)
 {
-	struct btrfs_free_space *left_info;
+	struct btrfs_free_space *left_info = NULL;
 	struct btrfs_free_space *right_info;
 	bool merged = false;
 	u64 offset = info->offset;
@@ -2155,7 +2177,7 @@
 	if (right_info && rb_prev(&right_info->offset_index))
 		left_info = rb_entry(rb_prev(&right_info->offset_index),
 				     struct btrfs_free_space, offset_index);
-	else
+	else if (!right_info)
 		left_info = tree_search_offset(ctl, offset - 1, 0, 0);
 
 	if (right_info && !right_info->bitmap) {
@@ -2457,6 +2479,7 @@
 	struct rb_node *n;
 	int count = 0;
 
+	spin_lock(&ctl->tree_lock);
 	for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) {
 		info = rb_entry(n, struct btrfs_free_space, offset_index);
 		if (info->bytes >= bytes && !block_group->ro)
@@ -2466,6 +2489,7 @@
 			   info->offset, info->bytes,
 		       (info->bitmap) ? "yes" : "no");
 	}
+	spin_unlock(&ctl->tree_lock);
 	btrfs_info(block_group->fs_info, "block group has cluster?: %s",
 	       list_empty(&block_group->cluster_list) ? "no" : "yes");
 	btrfs_info(block_group->fs_info,
@@ -2693,8 +2717,8 @@
 
 	err = search_bitmap(ctl, entry, &search_start, &search_bytes, true);
 	if (err) {
-		if (search_bytes > *max_extent_size)
-			*max_extent_size = search_bytes;
+		*max_extent_size = max(get_max_extent_size(entry),
+				       *max_extent_size);
 		return 0;
 	}
 
@@ -2731,8 +2755,9 @@
 
 	entry = rb_entry(node, struct btrfs_free_space, offset_index);
 	while (1) {
-		if (entry->bytes < bytes && entry->bytes > *max_extent_size)
-			*max_extent_size = entry->bytes;
+		if (entry->bytes < bytes)
+			*max_extent_size = max(get_max_extent_size(entry),
+					       *max_extent_size);
 
 		if (entry->bytes < bytes ||
 		    (!entry->bitmap && entry->offset < min_start)) {
--- linux-4.4.0.orig/fs/btrfs/inode-map.c
+++ linux-4.4.0/fs/btrfs/inode-map.c
@@ -158,6 +158,7 @@
 		spin_lock(&root->ino_cache_lock);
 		root->ino_cache_state = BTRFS_CACHE_FINISHED;
 		spin_unlock(&root->ino_cache_lock);
+		wake_up(&root->ino_cache_wait);
 		return;
 	}
 
@@ -515,7 +516,7 @@
 	return ret;
 }
 
-static int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid)
+int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid)
 {
 	struct btrfs_path *path;
 	int ret;
@@ -555,13 +556,6 @@
 	int ret;
 	mutex_lock(&root->objectid_mutex);
 
-	if (unlikely(root->highest_objectid < BTRFS_FIRST_FREE_OBJECTID)) {
-		ret = btrfs_find_highest_objectid(root,
-						  &root->highest_objectid);
-		if (ret)
-			goto out;
-	}
-
 	if (unlikely(root->highest_objectid >= BTRFS_LAST_FREE_OBJECTID)) {
 		ret = -ENOSPC;
 		goto out;
--- linux-4.4.0.orig/fs/btrfs/inode-map.h
+++ linux-4.4.0/fs/btrfs/inode-map.h
@@ -9,5 +9,6 @@
 			 struct btrfs_trans_handle *trans);
 
 int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid);
+int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid);
 
 #endif
--- linux-4.4.0.orig/fs/btrfs/inode.c
+++ linux-4.4.0/fs/btrfs/inode.c
@@ -481,6 +481,7 @@
 		pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
 		if (!pages) {
 			/* just bail out to the uncompressed code */
+			nr_pages = 0;
 			goto cont;
 		}
 
@@ -783,7 +784,7 @@
 		em->block_len = ins.offset;
 		em->orig_block_len = ins.offset;
 		em->ram_bytes = async_extent->ram_size;
-		em->bdev = root->fs_info->fs_devices->latest_bdev;
+		em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 		em->compress_type = async_extent->compress_type;
 		set_bit(EXTENT_FLAG_PINNED, &em->flags);
 		set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
@@ -925,7 +926,7 @@
 	u64 alloc_hint = 0;
 	u64 num_bytes;
 	unsigned long ram_size;
-	u64 disk_num_bytes;
+	u64 min_alloc_size;
 	u64 cur_alloc_size;
 	u64 blocksize = root->sectorsize;
 	struct btrfs_key ins;
@@ -941,7 +942,6 @@
 
 	num_bytes = ALIGN(end - start + 1, blocksize);
 	num_bytes = max(blocksize,  num_bytes);
-	disk_num_bytes = num_bytes;
 
 	/* if this is a small write inside eof, kick off defrag */
 	if (num_bytes < 64 * 1024 &&
@@ -968,18 +968,33 @@
 		}
 	}
 
-	BUG_ON(disk_num_bytes >
-	       btrfs_super_total_bytes(root->fs_info->super_copy));
+	BUG_ON(num_bytes > btrfs_super_total_bytes(root->fs_info->super_copy));
 
 	alloc_hint = get_extent_allocation_hint(inode, start, num_bytes);
 	btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0);
 
-	while (disk_num_bytes > 0) {
+	/*
+	 * Relocation relies on the relocated extents to have exactly the same
+	 * size as the original extents. Normally writeback for relocation data
+	 * extents follows a NOCOW path because relocation preallocates the
+	 * extents. However, due to an operation such as scrub turning a block
+	 * group to RO mode, it may fallback to COW mode, so we must make sure
+	 * an extent allocated during COW has exactly the requested size and can
+	 * not be split into smaller extents, otherwise relocation breaks and
+	 * fails during the stage where it updates the bytenr of file extent
+	 * items.
+	 */
+	if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
+		min_alloc_size = num_bytes;
+	else
+		min_alloc_size = root->sectorsize;
+
+	while (num_bytes > 0) {
 		unsigned long op;
 
-		cur_alloc_size = disk_num_bytes;
+		cur_alloc_size = num_bytes;
 		ret = btrfs_reserve_extent(root, cur_alloc_size,
-					   root->sectorsize, 0, alloc_hint,
+					   min_alloc_size, 0, alloc_hint,
 					   &ins, 1, 1);
 		if (ret < 0)
 			goto out_unlock;
@@ -1000,7 +1015,7 @@
 		em->block_len = ins.offset;
 		em->orig_block_len = ins.offset;
 		em->ram_bytes = ram_size;
-		em->bdev = root->fs_info->fs_devices->latest_bdev;
+		em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 		set_bit(EXTENT_FLAG_PINNED, &em->flags);
 		em->generation = -1;
 
@@ -1032,7 +1047,7 @@
 				goto out_drop_extent_cache;
 		}
 
-		if (disk_num_bytes < cur_alloc_size)
+		if (num_bytes < cur_alloc_size)
 			break;
 
 		/* we're not doing compressed IO, don't unlock the first
@@ -1049,8 +1064,10 @@
 					     start + ram_size - 1, locked_page,
 					     EXTENT_LOCKED | EXTENT_DELALLOC,
 					     op);
-		disk_num_bytes -= cur_alloc_size;
-		num_bytes -= cur_alloc_size;
+		if (num_bytes < cur_alloc_size)
+			num_bytes = 0;
+		else
+			num_bytes -= cur_alloc_size;
 		alloc_hint = ins.objectid + ins.offset;
 		start += cur_alloc_size;
 	}
@@ -1202,6 +1219,8 @@
 		list_del(&sums->list);
 		kfree(sums);
 	}
+	if (ret < 0)
+		return ret;
 	return 1;
 }
 
@@ -1292,8 +1311,11 @@
 		leaf = path->nodes[0];
 		if (path->slots[0] >= btrfs_header_nritems(leaf)) {
 			ret = btrfs_next_leaf(root, path);
-			if (ret < 0)
+			if (ret < 0) {
+				if (cow_start != (u64)-1)
+					cur_offset = cow_start;
 				goto error;
+			}
 			if (ret > 0)
 				break;
 			leaf = path->nodes[0];
@@ -1348,10 +1370,23 @@
 				goto out_check;
 			if (btrfs_extent_readonly(root, disk_bytenr))
 				goto out_check;
-			if (btrfs_cross_ref_exist(trans, root, ino,
+			ret = btrfs_cross_ref_exist(trans, root, ino,
 						  found_key.offset -
-						  extent_offset, disk_bytenr))
+						  extent_offset, disk_bytenr);
+			if (ret) {
+				/*
+				 * ret could be -EIO if the above fails to read
+				 * metadata.
+				 */
+				if (ret < 0) {
+					if (cow_start != (u64)-1)
+						cur_offset = cow_start;
+					goto error;
+				}
+
+				WARN_ON_ONCE(nolock);
 				goto out_check;
+			}
 			disk_bytenr += extent_offset;
 			disk_bytenr += cur_offset - found_key.offset;
 			num_bytes = min(end + 1, extent_end) - cur_offset;
@@ -1369,8 +1404,20 @@
 			 * this ensure that csum for a given extent are
 			 * either valid or do not exist.
 			 */
-			if (csum_exist_in_range(root, disk_bytenr, num_bytes))
+			ret = csum_exist_in_range(root, disk_bytenr, num_bytes);
+			if (ret) {
+				/*
+				 * ret could be -EIO if the above fails to read
+				 * metadata.
+				 */
+				if (ret < 0) {
+					if (cow_start != (u64)-1)
+						cur_offset = cow_start;
+					goto error;
+				}
+				WARN_ON_ONCE(nolock);
 				goto out_check;
+			}
 			nocow = 1;
 		} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
 			extent_end = found_key.offset +
@@ -1423,7 +1470,7 @@
 			em->block_start = disk_bytenr;
 			em->orig_block_len = disk_num_bytes;
 			em->ram_bytes = ram_bytes;
-			em->bdev = root->fs_info->fs_devices->latest_bdev;
+			em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 			em->mod_start = em->start;
 			em->mod_len = em->len;
 			set_bit(EXTENT_FLAG_PINNED, &em->flags);
@@ -2015,7 +2062,15 @@
 		goto out;
 	 }
 
-	btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state);
+	ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
+					&cached_state);
+	if (ret) {
+		mapping_set_error(page->mapping, ret);
+		end_extent_writepage(page, ret, page_start, page_end);
+		ClearPageChecked(page);
+		goto out;
+	}
+
 	ClearPageChecked(page);
 	set_page_dirty(page);
 out:
@@ -3142,8 +3197,6 @@
 	if (empty)
 		return;
 
-	down_read(&fs_info->delayed_iput_sem);
-
 	spin_lock(&fs_info->delayed_iput_lock);
 	list_splice_init(&fs_info->delayed_iputs, &list);
 	spin_unlock(&fs_info->delayed_iput_lock);
@@ -3154,8 +3207,6 @@
 		iput(delayed->inode);
 		kfree(delayed);
 	}
-
-	up_read(&root->fs_info->delayed_iput_sem);
 }
 
 /*
@@ -4401,8 +4452,19 @@
 		if (found_type > min_type) {
 			del_item = 1;
 		} else {
-			if (item_end < new_size)
+			if (item_end < new_size) {
+				/*
+				 * With NO_HOLES mode, for the following mapping
+				 *
+				 * [0-4k][hole][8k-12k]
+				 *
+				 * if truncating isize down to 6k, it ends up
+				 * isize being 8k.
+				 */
+				if (btrfs_fs_incompat(root->fs_info, NO_HOLES))
+					last_size = new_size;
 				break;
+			}
 			if (found_key.offset >= new_size)
 				del_item = 1;
 			else
@@ -4846,7 +4908,7 @@
 			hole_em->block_len = 0;
 			hole_em->orig_block_len = 0;
 			hole_em->ram_bytes = hole_size;
-			hole_em->bdev = root->fs_info->fs_devices->latest_bdev;
+			hole_em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 			hole_em->compress_type = BTRFS_COMPRESS_NONE;
 			hole_em->generation = root->fs_info->generation;
 
@@ -5021,7 +5083,7 @@
 	if (btrfs_root_readonly(root))
 		return -EROFS;
 
-	err = inode_change_ok(inode, attr);
+	err = setattr_prepare(dentry, attr);
 	if (err)
 		return err;
 
@@ -5308,11 +5370,13 @@
 }
 
 /*
- * this returns the key found in the dir entry in the location pointer.
+ * Return the key found in the dir entry in the location pointer, fill @type
+ * with BTRFS_FT_*, and return 0.
+ *
  * If no dir entries were found, location->objectid is 0.
  */
 static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
-			       struct btrfs_key *location)
+			       struct btrfs_key *location, u8 *type)
 {
 	const char *name = dentry->d_name.name;
 	int namelen = dentry->d_name.len;
@@ -5334,6 +5398,8 @@
 		goto out_err;
 
 	btrfs_dir_item_key_to_cpu(path->nodes[0], di, location);
+	if (!ret)
+		*type = btrfs_dir_type(path->nodes[0], di);
 out:
 	btrfs_free_path(path);
 	return ret;
@@ -5460,7 +5526,6 @@
 	spin_unlock(&root->inode_lock);
 
 	if (empty && btrfs_root_refs(&root->root_item) == 0) {
-		synchronize_srcu(&root->fs_info->subvol_srcu);
 		spin_lock(&root->inode_lock);
 		empty = RB_EMPTY_ROOT(&root->inode_tree);
 		spin_unlock(&root->inode_lock);
@@ -5620,19 +5685,25 @@
 	return inode;
 }
 
+static inline u8 btrfs_inode_type(struct inode *inode)
+{
+	return btrfs_type_by_mode[(inode->i_mode & S_IFMT) >> S_SHIFT];
+}
+
 struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct btrfs_root *sub_root = root;
 	struct btrfs_key location;
+	u8 di_type = 0;
 	int index;
 	int ret = 0;
 
 	if (dentry->d_name.len > BTRFS_NAME_LEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
-	ret = btrfs_inode_by_name(dir, dentry, &location);
+	ret = btrfs_inode_by_name(dir, dentry, &location, &di_type);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
@@ -5641,6 +5712,18 @@
 
 	if (location.type == BTRFS_INODE_ITEM_KEY) {
 		inode = btrfs_iget(dir->i_sb, &location, root, NULL);
+		if (IS_ERR(inode))
+			return inode;
+
+		/* Do extra check against inode mode with di_type */
+		if (btrfs_inode_type(inode) != di_type) {
+			btrfs_crit(root->fs_info,
+"inode mode mismatch with dir: inode mode=0%o btrfs type=%u dir type=%u",
+				  inode->i_mode, btrfs_inode_type(inode),
+				  di_type);
+			iput(inode);
+			return ERR_PTR(-EUCLEAN);
+		}
 		return inode;
 	}
 
@@ -5741,6 +5824,7 @@
 	char *name_ptr;
 	int name_len;
 	int is_curr = 0;	/* ctx->pos points to the current index? */
+	bool emitted;
 
 	/* FIXME, use a real flag for deciding about the key type */
 	if (root->fs_info->tree_root == root)
@@ -5769,6 +5853,7 @@
 	if (ret < 0)
 		goto err;
 
+	emitted = false;
 	while (1) {
 		leaf = path->nodes[0];
 		slot = path->slots[0];
@@ -5848,6 +5933,7 @@
 
 			if (over)
 				goto nopos;
+			emitted = true;
 			di_len = btrfs_dir_name_len(leaf, di) +
 				 btrfs_dir_data_len(leaf, di) + sizeof(*di);
 			di_cur += di_len;
@@ -5860,11 +5946,20 @@
 	if (key_type == BTRFS_DIR_INDEX_KEY) {
 		if (is_curr)
 			ctx->pos++;
-		ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list);
+		ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list, &emitted);
 		if (ret)
 			goto nopos;
 	}
 
+	/*
+	 * If we haven't emitted any dir entry, we must not touch ctx->pos as
+	 * it was was set to the termination value in previous call. We assume
+	 * that "." and ".." were emitted if we reach this point and set the
+	 * termination value as well for an empty directory.
+	 */
+	if (ctx->pos > 2 && !emitted)
+		goto nopos;
+
 	/* Reached end of directory/root. Bump pos past the last item. */
 	ctx->pos++;
 
@@ -6242,11 +6337,6 @@
 	return ERR_PTR(ret);
 }
 
-static inline u8 btrfs_inode_type(struct inode *inode)
-{
-	return btrfs_type_by_mode[(inode->i_mode & S_IFMT) >> S_SHIFT];
-}
-
 /*
  * utility function to add 'inode' into 'parent_inode' with
  * a give name and a given sequence number.
@@ -6383,8 +6473,7 @@
 		goto out_unlock_inode;
 	} else {
 		btrfs_update_inode(trans, root, inode);
-		unlock_new_inode(inode);
-		d_instantiate(dentry, inode);
+		d_instantiate_new(dentry, inode);
 	}
 
 out_unlock:
@@ -6459,8 +6548,7 @@
 		goto out_unlock_inode;
 
 	BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 
 out_unlock:
 	btrfs_end_transaction(trans, root);
@@ -6481,7 +6569,7 @@
 static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 		      struct dentry *dentry)
 {
-	struct btrfs_trans_handle *trans;
+	struct btrfs_trans_handle *trans = NULL;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct inode *inode = d_inode(old_dentry);
 	u64 index;
@@ -6507,6 +6595,7 @@
 	trans = btrfs_start_transaction(root, 5);
 	if (IS_ERR(trans)) {
 		err = PTR_ERR(trans);
+		trans = NULL;
 		goto fail;
 	}
 
@@ -6540,9 +6629,10 @@
 		btrfs_log_new_name(trans, inode, NULL, parent);
 	}
 
-	btrfs_end_transaction(trans, root);
 	btrfs_balance_delayed_items(root);
 fail:
+	if (trans)
+		btrfs_end_transaction(trans, root);
 	if (drop_inode) {
 		inode_dec_link_count(inode);
 		iput(inode);
@@ -6601,12 +6691,7 @@
 	if (err)
 		goto out_fail_inode;
 
-	d_instantiate(dentry, inode);
-	/*
-	 * mkdir is special.  We're unlocking after we call d_instantiate
-	 * to avoid a race with nfsd calling d_instantiate.
-	 */
-	unlock_new_inode(inode);
+	d_instantiate_new(dentry, inode);
 	drop_on_err = 0;
 
 out_fail:
@@ -6714,6 +6799,20 @@
 	max_size = min_t(unsigned long, PAGE_CACHE_SIZE, max_size);
 	ret = btrfs_decompress(compress_type, tmp, page,
 			       extent_offset, inline_size, max_size);
+
+	/*
+	 * decompression code contains a memset to fill in any space between the end
+	 * of the uncompressed data and the end of max_size in case the decompressed
+	 * data ends up shorter than ram_bytes.  That doesn't cover the hole between
+	 * the end of an inline extent and the beginning of the next block, so we
+	 * cover that region here.
+	 */
+
+	if (max_size + pg_offset < PAGE_SIZE) {
+		char *map = kmap(page);
+		memset(map + pg_offset + max_size, 0, PAGE_SIZE - max_size - pg_offset);
+		kunmap(page);
+	}
 	kfree(tmp);
 	return ret;
 }
@@ -6752,7 +6851,7 @@
 	read_lock(&em_tree->lock);
 	em = lookup_extent_mapping(em_tree, start, len);
 	if (em)
-		em->bdev = root->fs_info->fs_devices->latest_bdev;
+		em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 	read_unlock(&em_tree->lock);
 
 	if (em) {
@@ -6768,7 +6867,7 @@
 		err = -ENOMEM;
 		goto out;
 	}
-	em->bdev = root->fs_info->fs_devices->latest_bdev;
+	em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 	em->start = EXTENT_MAP_HOLE;
 	em->orig_start = EXTENT_MAP_HOLE;
 	em->len = (u64)-1;
@@ -6822,6 +6921,14 @@
 	extent_start = found_key.offset;
 	if (found_type == BTRFS_FILE_EXTENT_REG ||
 	    found_type == BTRFS_FILE_EXTENT_PREALLOC) {
+		/* Only regular file could have regular/prealloc extent */
+		if (!S_ISREG(inode->i_mode)) {
+			err = -EUCLEAN;
+			btrfs_crit(root->fs_info,
+		"regular/prealloc extent found for non-regular inode %llu",
+				   btrfs_ino(inode));
+			goto out;
+		}
 		extent_end = extent_start +
 		       btrfs_file_extent_num_bytes(leaf, item);
 	} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
@@ -7308,8 +7415,8 @@
 	int found = false;
 	void **pagep = NULL;
 	struct page *page = NULL;
-	int start_idx;
-	int end_idx;
+	unsigned long start_idx;
+	unsigned long end_idx;
 
 	start_idx = start >> PAGE_CACHE_SHIFT;
 
@@ -7458,7 +7565,7 @@
 	em->len = len;
 	em->block_len = block_len;
 	em->block_start = block_start;
-	em->bdev = root->fs_info->fs_devices->latest_bdev;
+	em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 	em->orig_block_len = orig_block_len;
 	em->ram_bytes = ram_bytes;
 	em->generation = -1;
@@ -7500,11 +7607,18 @@
 	 * within our reservation, otherwise we need to adjust our inode
 	 * counter appropriately.
 	 */
-	if (dio_data->outstanding_extents) {
+	if (dio_data->outstanding_extents >= num_extents) {
 		dio_data->outstanding_extents -= num_extents;
 	} else {
+		/*
+		 * If dio write length has been split due to no large enough
+		 * contiguous space, we need to compensate our inode counter
+		 * appropriately.
+		 */
+		u64 num_needed = num_extents - dio_data->outstanding_extents;
+
 		spin_lock(&BTRFS_I(inode)->lock);
-		BTRFS_I(inode)->outstanding_extents += num_extents;
+		BTRFS_I(inode)->outstanding_extents += num_needed;
 		spin_unlock(&BTRFS_I(inode)->lock);
 	}
 }
@@ -7985,6 +8099,7 @@
 
 	kfree(dip);
 
+	dio_bio->bi_error = bio->bi_error;
 	dio_end_io(dio_bio, bio->bi_error);
 
 	if (io_bio->end_io)
@@ -8030,6 +8145,7 @@
 
 	kfree(dip);
 
+	dio_bio->bi_error = bio->bi_error;
 	dio_end_io(dio_bio, bio->bi_error);
 	bio_put(bio);
 }
@@ -8219,7 +8335,6 @@
 	bio->bi_private = dip;
 	bio->bi_end_io = btrfs_end_dio_bio;
 	btrfs_io_bio(bio)->logical = file_offset;
-	atomic_inc(&dip->pending_bios);
 
 	while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
 		if (map_length < submit_len + bvec->bv_len ||
@@ -8276,7 +8391,8 @@
 	if (!ret)
 		return 0;
 
-	bio_put(bio);
+	if (bio != orig_bio)
+		bio_put(bio);
 out_err:
 	dip->errors = 1;
 	/*
@@ -8323,7 +8439,7 @@
 	io_bio->bi_private = dip;
 	dip->orig_bio = io_bio;
 	dip->dio_bio = dio_bio;
-	atomic_set(&dip->pending_bios, 0);
+	atomic_set(&dip->pending_bios, 1);
 	btrfs_bio = btrfs_io_bio(io_bio);
 	btrfs_bio->logical = file_offset;
 
@@ -8488,7 +8604,7 @@
 	}
 
 	ret = __blockdev_direct_IO(iocb, inode,
-				   BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev,
+				   BTRFS_I(inode)->root->fs_info->fs_devices->latest_dev->bdev,
 				   iter, offset, btrfs_get_blocks_direct, NULL,
 				   btrfs_submit_direct, flags);
 	if (iov_iter_rw(iter) == WRITE) {
@@ -8534,15 +8650,28 @@
 static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
 {
 	struct extent_io_tree *tree;
-
+	struct inode *inode = page->mapping->host;
+	int ret;
 
 	if (current->flags & PF_MEMALLOC) {
 		redirty_page_for_writepage(wbc, page);
 		unlock_page(page);
 		return 0;
 	}
+
+	/*
+	 * If we are under memory pressure we will call this directly from the
+	 * VM, we need to make sure we have the inode referenced for the ordered
+	 * extent.  If not just return like we didn't do anything.
+	 */
+	if (!igrab(inode)) {
+		redirty_page_for_writepage(wbc, page);
+		return AOP_WRITEPAGE_ACTIVATE;
+	}
 	tree = &BTRFS_I(page->mapping->host)->io_tree;
-	return extent_write_full_page(tree, page, btrfs_get_extent, wbc);
+	ret = extent_write_full_page(tree, page, btrfs_get_extent, wbc);
+	btrfs_add_delayed_iput(inode);
+	return ret;
 }
 
 static int btrfs_writepages(struct address_space *mapping,
@@ -8666,9 +8795,14 @@
 	 *    So even we call qgroup_free_data(), it won't decrease reserved
 	 *    space.
 	 * 2) Not written to disk
-	 *    This means the reserved space should be freed here.
+	 *    This means the reserved space should be freed here. However,
+	 *    if a truncate invalidates the page (by clearing PageDirty)
+	 *    and the page is accounted for while allocating extent
+	 *    in btrfs_check_data_free_space() we let delayed_ref to
+	 *    free the entire extent.
 	 */
-	btrfs_qgroup_free_data(inode, page_start, PAGE_CACHE_SIZE);
+	if (PageDirty(page))
+		btrfs_qgroup_free_data(inode, page_start, PAGE_SIZE);
 	if (!inode_evicting) {
 		clear_extent_bit(tree, page_start, page_end,
 				 EXTENT_LOCKED | EXTENT_DIRTY |
@@ -9636,9 +9770,11 @@
 	/*
 	 * 2 items for inode item and ref
 	 * 2 items for dir items
+	 * 1 item for updating parent inode item
+	 * 1 item for the inline extent item
 	 * 1 item for xattr if selinux is on
 	 */
-	trans = btrfs_start_transaction(root, 5);
+	trans = btrfs_start_transaction(root, 7);
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
 
@@ -9714,8 +9850,7 @@
 		goto out_unlock_inode;
 	}
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 
 out_unlock:
 	btrfs_end_transaction(trans, root);
@@ -9808,7 +9943,7 @@
 		em->block_len = ins.offset;
 		em->orig_block_len = ins.offset;
 		em->ram_bytes = ins.offset;
-		em->bdev = root->fs_info->fs_devices->latest_bdev;
+		em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 		set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
 		em->generation = trans->transid;
 
@@ -10017,7 +10152,7 @@
 	.iterate	= btrfs_real_readdir,
 	.unlocked_ioctl	= btrfs_ioctl,
 #ifdef CONFIG_COMPAT
-	.compat_ioctl	= btrfs_ioctl,
+	.compat_ioctl	= btrfs_compat_ioctl,
 #endif
 	.release        = btrfs_release_file,
 	.fsync		= btrfs_sync_file,
--- linux-4.4.0.orig/fs/btrfs/ioctl.c
+++ linux-4.4.0/fs/btrfs/ioctl.c
@@ -59,6 +59,7 @@
 #include "props.h"
 #include "sysfs.h"
 #include "qgroup.h"
+#include "tree-log.h"
 
 #ifdef CONFIG_64BIT
 /* If we have a 32-bit userspace and 64-bit kernel, then the UAPI
@@ -378,7 +379,6 @@
 	struct fstrim_range range;
 	u64 minlen = ULLONG_MAX;
 	u64 num_devices = 0;
-	u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
 	int ret;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -402,11 +402,15 @@
 		return -EOPNOTSUPP;
 	if (copy_from_user(&range, arg, sizeof(range)))
 		return -EFAULT;
-	if (range.start > total_bytes ||
-	    range.len < fs_info->sb->s_blocksize)
+
+	/*
+	 * NOTE: Don't truncate the range using super->total_bytes.  Bytenr of
+	 * block group is in the logical address space, which can be any
+	 * sectorsize aligned bytenr in  the range [0, U64_MAX].
+	 */
+	if (range.len < fs_info->sb->s_blocksize)
 		return -EINVAL;
 
-	range.len = min(range.len, total_bytes - range.start);
 	range.minlen = max(range.minlen, minlen);
 	ret = btrfs_trim_fs(fs_info->tree_root, &range);
 	if (ret < 0)
@@ -568,6 +572,10 @@
 		goto fail;
 	}
 
+	mutex_lock(&new_root->objectid_mutex);
+	new_root->highest_objectid = new_dirid;
+	mutex_unlock(&new_root->objectid_mutex);
+
 	/*
 	 * insert the directory item
 	 */
@@ -587,12 +595,18 @@
 
 	btrfs_i_size_write(dir, dir->i_size + namelen * 2);
 	ret = btrfs_update_inode(trans, root, dir);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto fail;
+	}
 
 	ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
 				 objectid, root->root_key.objectid,
 				 btrfs_ino(dir), index, name, namelen);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto fail;
+	}
 
 	ret = btrfs_uuid_tree_add(trans, root->fs_info->uuid_root,
 				  root_item.uuid, BTRFS_UUID_KEY_SUBVOL,
@@ -700,10 +714,7 @@
 		goto fail;
 	}
 
-	spin_lock(&root->fs_info->trans_lock);
-	list_add(&pending_snapshot->list,
-		 &trans->transaction->pending_snapshots);
-	spin_unlock(&root->fs_info->trans_lock);
+	trans->pending_snapshot = pending_snapshot;
 	if (async_transid) {
 		*async_transid = trans->transid;
 		ret = btrfs_commit_transaction_async(trans,
@@ -1517,7 +1528,7 @@
 		btrfs_info(root->fs_info, "resizing devid %llu", devid);
 	}
 
-	device = btrfs_find_device(root->fs_info, devid, NULL, NULL);
+	device = btrfs_find_device(root->fs_info->fs_devices, devid, NULL, NULL, true);
 	if (!device) {
 		btrfs_info(root->fs_info, "resizer unable to find device %llu",
 		       devid);
@@ -1615,6 +1626,9 @@
 	int namelen;
 	int ret = 0;
 
+	if (!S_ISDIR(file_inode(file)->i_mode))
+		return -ENOTDIR;
+
 	ret = mnt_want_write_file(file);
 	if (ret)
 		goto out;
@@ -1644,7 +1658,7 @@
 
 		src_inode = file_inode(src.file);
 		if (src_inode->i_sb != file_inode(file)->i_sb) {
-			btrfs_info(BTRFS_I(src_inode)->root->fs_info,
+			btrfs_info(BTRFS_I(file_inode(file))->root->fs_info,
 				   "Snapshot src from another FS");
 			ret = -EXDEV;
 		} else if (!inode_owner_or_capable(src_inode)) {
@@ -1672,6 +1686,9 @@
 	struct btrfs_ioctl_vol_args *vol_args;
 	int ret;
 
+	if (!S_ISDIR(file_inode(file)->i_mode))
+		return -ENOTDIR;
+
 	vol_args = memdup_user(arg, sizeof(*vol_args));
 	if (IS_ERR(vol_args))
 		return PTR_ERR(vol_args);
@@ -1695,6 +1712,9 @@
 	bool readonly = false;
 	struct btrfs_qgroup_inherit *inherit = NULL;
 
+	if (!S_ISDIR(file_inode(file)->i_mode))
+		return -ENOTDIR;
+
 	vol_args = memdup_user(arg, sizeof(*vol_args));
 	if (IS_ERR(vol_args))
 		return PTR_ERR(vol_args);
@@ -1994,9 +2014,14 @@
 		sh.len = item_len;
 		sh.transid = found_transid;
 
-		/* copy search result header */
-		if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) {
-			ret = -EFAULT;
+		/*
+		 * Copy search result header. If we fault then loop again so we
+		 * can fault in the pages and -EFAULT there if there's a
+		 * problem. Otherwise we'll fault and then copy the buffer in
+		 * properly this next time through
+		 */
+		if (probe_user_write(ubuf + *sk_offset, &sh, sizeof(sh))) {
+			ret = 0;
 			goto out;
 		}
 
@@ -2004,10 +2029,14 @@
 
 		if (item_len) {
 			char __user *up = ubuf + *sk_offset;
-			/* copy the item */
-			if (read_extent_buffer_to_user(leaf, up,
-						       item_off, item_len)) {
-				ret = -EFAULT;
+			/*
+			 * Copy the item, same behavior as above, but reset the
+			 * * sk_offset so we copy the full thing again.
+			 */
+			if (read_extent_buffer_to_user_nofault(leaf, up,
+						item_off, item_len)) {
+				ret = 0;
+				*sk_offset -= sizeof(sh);
 				goto out;
 			}
 
@@ -2097,6 +2126,11 @@
 	key.offset = sk->min_offset;
 
 	while (1) {
+		ret = fault_in_pages_writeable(ubuf + sk_offset,
+					       *buf_size - sk_offset);
+		if (ret)
+			break;
+
 		ret = btrfs_search_forward(root, &key, path, sk->min_transid);
 		if (ret != 0) {
 			if (ret > 0)
@@ -2218,7 +2252,7 @@
 	if (!path)
 		return -ENOMEM;
 
-	ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX];
+	ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX - 1];
 
 	key.objectid = tree_id;
 	key.type = BTRFS_ROOT_ITEM_KEY;
@@ -2341,6 +2375,9 @@
 	int ret;
 	int err = 0;
 
+	if (!S_ISDIR(dir->i_mode))
+		return -ENOTDIR;
+
 	vol_args = memdup_user(arg, sizeof(*vol_args));
 	if (IS_ERR(vol_args))
 		return PTR_ERR(vol_args);
@@ -2515,6 +2552,8 @@
 out_end_trans:
 	trans->block_rsv = NULL;
 	trans->bytes_reserved = 0;
+	if (!err)
+		btrfs_record_snapshot_destroy(trans, dir);
 	ret = btrfs_end_transaction(trans, root);
 	if (ret && !err)
 		err = ret;
@@ -2747,7 +2786,8 @@
 		s_uuid = di_args->uuid;
 
 	mutex_lock(&fs_devices->device_list_mutex);
-	dev = btrfs_find_device(root->fs_info, di_args->devid, s_uuid, NULL);
+	dev = btrfs_find_device(fs_devices, di_args->devid, s_uuid,
+				NULL, true);
 
 	if (!dev) {
 		ret = -ENODEV;
@@ -2782,24 +2822,29 @@
 static struct page *extent_same_get_page(struct inode *inode, pgoff_t index)
 {
 	struct page *page;
-	struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
 
 	page = grab_cache_page(inode->i_mapping, index);
 	if (!page)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	if (!PageUptodate(page)) {
-		if (extent_read_full_page_nolock(tree, page, btrfs_get_extent,
-						 0))
-			return NULL;
+		int ret;
+
+		ret = btrfs_readpage(NULL, page);
+		if (ret)
+			return ERR_PTR(ret);
 		lock_page(page);
 		if (!PageUptodate(page)) {
 			unlock_page(page);
 			page_cache_release(page);
-			return NULL;
+			return ERR_PTR(-EIO);
+		}
+		if (page->mapping != inode->i_mapping) {
+			unlock_page(page);
+			page_cache_release(page);
+			return ERR_PTR(-EAGAIN);
 		}
 	}
-	unlock_page(page);
 
 	return page;
 }
@@ -2811,17 +2856,31 @@
 	pgoff_t index = off >> PAGE_CACHE_SHIFT;
 
 	for (i = 0; i < num_pages; i++) {
+again:
 		pages[i] = extent_same_get_page(inode, index + i);
-		if (!pages[i])
-			return -ENOMEM;
+		if (IS_ERR(pages[i])) {
+			int err = PTR_ERR(pages[i]);
+
+			if (err == -EAGAIN)
+				goto again;
+			pages[i] = NULL;
+			return err;
+		}
 	}
 	return 0;
 }
 
-static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
+static int lock_extent_range(struct inode *inode, u64 off, u64 len,
+			     bool retry_range_locking)
 {
-	/* do any pending delalloc/csum calc on src, one way or
-	   another, and lock file content */
+	/*
+	 * Do any pending delalloc/csum calculations on inode, one way or
+	 * another, and lock file content.
+	 * The locking order is:
+	 *
+	 *   1) pages
+	 *   2) range in the inode's io tree
+	 */
 	while (1) {
 		struct btrfs_ordered_extent *ordered;
 		lock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1);
@@ -2839,8 +2898,11 @@
 		unlock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1);
 		if (ordered)
 			btrfs_put_ordered_extent(ordered);
+		if (!retry_range_locking)
+			return -EAGAIN;
 		btrfs_wait_ordered_range(inode, off, len);
 	}
+	return 0;
 }
 
 static void btrfs_double_inode_unlock(struct inode *inode1, struct inode *inode2)
@@ -2865,15 +2927,24 @@
 	unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1);
 }
 
-static void btrfs_double_extent_lock(struct inode *inode1, u64 loff1,
-				     struct inode *inode2, u64 loff2, u64 len)
+static int btrfs_double_extent_lock(struct inode *inode1, u64 loff1,
+				    struct inode *inode2, u64 loff2, u64 len,
+				    bool retry_range_locking)
 {
+	int ret;
+
 	if (inode1 < inode2) {
 		swap(inode1, inode2);
 		swap(loff1, loff2);
 	}
-	lock_extent_range(inode1, loff1, len);
-	lock_extent_range(inode2, loff2, len);
+	ret = lock_extent_range(inode1, loff1, len, retry_range_locking);
+	if (ret)
+		return ret;
+	ret = lock_extent_range(inode2, loff2, len, retry_range_locking);
+	if (ret)
+		unlock_extent(&BTRFS_I(inode1)->io_tree, loff1,
+			      loff1 + len - 1);
+	return ret;
 }
 
 struct cmp_pages {
@@ -2889,11 +2960,15 @@
 
 	for (i = 0; i < cmp->num_pages; i++) {
 		pg = cmp->src_pages[i];
-		if (pg)
+		if (pg) {
+			unlock_page(pg);
 			page_cache_release(pg);
+		}
 		pg = cmp->dst_pages[i];
-		if (pg)
+		if (pg) {
+			unlock_page(pg);
 			page_cache_release(pg);
+		}
 	}
 	kfree(cmp->src_pages);
 	kfree(cmp->dst_pages);
@@ -2933,7 +3008,7 @@
 out:
 	if (ret)
 		btrfs_cmp_data_free(cmp);
-	return 0;
+	return ret;
 }
 
 static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst,
@@ -2954,6 +3029,8 @@
 
 		src_page = cmp->src_pages[i];
 		dst_page = cmp->dst_pages[i];
+		ASSERT(PageLocked(src_page));
+		ASSERT(PageLocked(dst_page));
 
 		addr = kmap_atomic(src_page);
 		dst_addr = kmap_atomic(dst_page);
@@ -3066,14 +3143,46 @@
 		goto out_unlock;
 	}
 
+again:
 	ret = btrfs_cmp_data_prepare(src, loff, dst, dst_loff, olen, &cmp);
 	if (ret)
 		goto out_unlock;
 
 	if (same_inode)
-		lock_extent_range(src, same_lock_start, same_lock_len);
+		ret = lock_extent_range(src, same_lock_start, same_lock_len,
+					false);
 	else
-		btrfs_double_extent_lock(src, loff, dst, dst_loff, len);
+		ret = btrfs_double_extent_lock(src, loff, dst, dst_loff, len,
+					       false);
+	/*
+	 * If one of the inodes has dirty pages in the respective range or
+	 * ordered extents, we need to flush dellaloc and wait for all ordered
+	 * extents in the range. We must unlock the pages and the ranges in the
+	 * io trees to avoid deadlocks when flushing delalloc (requires locking
+	 * pages) and when waiting for ordered extents to complete (they require
+	 * range locking).
+	 */
+	if (ret == -EAGAIN) {
+		/*
+		 * Ranges in the io trees already unlocked. Now unlock all
+		 * pages before waiting for all IO to complete.
+		 */
+		btrfs_cmp_data_free(&cmp);
+		if (same_inode) {
+			btrfs_wait_ordered_range(src, same_lock_start,
+						 same_lock_len);
+		} else {
+			btrfs_wait_ordered_range(src, loff, len);
+			btrfs_wait_ordered_range(dst, dst_loff, len);
+		}
+		goto again;
+	}
+	ASSERT(ret == 0);
+	if (WARN_ON(ret)) {
+		/* ranges in the io trees already unlocked */
+		btrfs_cmp_data_free(&cmp);
+		return ret;
+	}
 
 	/* pass original length for comparison so we stay within i_size */
 	ret = btrfs_cmp_data(src, loff, dst, dst_loff, olen, &cmp);
@@ -3740,6 +3849,13 @@
 		}
 		btrfs_release_path(path);
 		key.offset = next_key_min_offset;
+
+		if (fatal_signal_pending(current)) {
+			ret = -EINTR;
+			goto out;
+		}
+
+		cond_resched();
 	}
 	ret = 0;
 
@@ -3833,11 +3949,6 @@
 	if (!(src_file.file->f_mode & FMODE_READ))
 		goto out_fput;
 
-	/* don't make the dst file partly checksummed */
-	if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
-	    (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
-		goto out_fput;
-
 	ret = -EISDIR;
 	if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
 		goto out_fput;
@@ -3852,15 +3963,30 @@
 		mutex_lock(&src->i_mutex);
 	}
 
+	/* don't make the dst file partly checksummed */
+	if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
+	    (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
 	/* determine range to clone */
 	ret = -EINVAL;
 	if (off + len > src->i_size || off + len < off)
 		goto out_unlock;
 	if (len == 0)
 		olen = len = src->i_size - off;
-	/* if we extend to eof, continue to block boundary */
-	if (off + len == src->i_size)
+	/*
+	 * If we extend to eof, continue to block boundary if and only if the
+	 * destination end offset matches the destination file's size, otherwise
+	 * we would be corrupting data by placing the eof block into the middle
+	 * of a file.
+	 */
+	if (off + len == src->i_size) {
+		if (!IS_ALIGNED(len, bs) && destoff + len < inode->i_size)
+			goto out_unlock;
 		len = ALIGN(src->i_size, bs) - off;
+	}
 
 	if (len == 0) {
 		ret = 0;
@@ -3895,9 +4021,15 @@
 		u64 lock_start = min_t(u64, off, destoff);
 		u64 lock_len = max_t(u64, off, destoff) + len - lock_start;
 
-		lock_extent_range(src, lock_start, lock_len);
+		ret = lock_extent_range(src, lock_start, lock_len, true);
 	} else {
-		btrfs_double_extent_lock(src, off, inode, destoff, len);
+		ret = btrfs_double_extent_lock(src, off, inode, destoff, len,
+					       true);
+	}
+	ASSERT(ret == 0);
+	if (WARN_ON(ret)) {
+		/* ranges in the io trees already unlocked */
+		goto out_unlock;
 	}
 
 	ret = btrfs_clone(src, inode, off, olen, len, destoff, 0);
@@ -4022,6 +4154,10 @@
 		ret = PTR_ERR(new_root);
 		goto out;
 	}
+	if (!is_fstree(new_root->objectid)) {
+		ret = -ENOENT;
+		goto out;
+	}
 
 	path = btrfs_alloc_path();
 	if (!path) {
@@ -4864,7 +5000,9 @@
 	}
 
 	/* update qgroup status and info */
+	mutex_lock(&root->fs_info->qgroup_ioctl_lock);
 	err = btrfs_run_qgroups(trans, root->fs_info);
+	mutex_unlock(&root->fs_info->qgroup_ioctl_lock);
 	if (err < 0)
 		btrfs_std_error(root->fs_info, ret,
 			    "failed to update qgroup status and info\n");
@@ -5042,7 +5180,7 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	return btrfs_qgroup_wait_for_completion(root->fs_info);
+	return btrfs_qgroup_wait_for_completion(root->fs_info, true);
 }
 
 static long _btrfs_ioctl_set_received_subvol(struct file *file,
@@ -5578,3 +5716,26 @@
 
 	return -ENOTTY;
 }
+
+#ifdef CONFIG_COMPAT
+long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	/*
+	 * These all access 32-bit values anyway so no further
+	 * handling is necessary.
+	 */
+	switch (cmd) {
+	case FS_IOC32_GETFLAGS:
+		cmd = FS_IOC_GETFLAGS;
+		break;
+	case FS_IOC32_SETFLAGS:
+		cmd = FS_IOC_SETFLAGS;
+		break;
+	case FS_IOC32_GETVERSION:
+		cmd = FS_IOC_GETVERSION;
+		break;
+	}
+
+	return btrfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
+}
+#endif
--- linux-4.4.0.orig/fs/btrfs/ordered-data.c
+++ linux-4.4.0/fs/btrfs/ordered-data.c
@@ -820,10 +820,15 @@
 		}
 		btrfs_start_ordered_extent(inode, ordered, 1);
 		end = ordered->file_offset;
+		/*
+		 * If the ordered extent had an error save the error but don't
+		 * exit without waiting first for all other ordered extents in
+		 * the range to complete.
+		 */
 		if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))
 			ret = -EIO;
 		btrfs_put_ordered_extent(ordered);
-		if (ret || end == 0 || end == start)
+		if (end == 0 || end == start)
 			break;
 		end--;
 	}
--- linux-4.4.0.orig/fs/btrfs/qgroup.c
+++ linux-4.4.0/fs/btrfs/qgroup.c
@@ -462,6 +462,7 @@
 			break;
 	}
 out:
+	btrfs_free_path(path);
 	fs_info->qgroup_flags |= flags;
 	if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) {
 		fs_info->quota_enabled = 0;
@@ -470,7 +471,6 @@
 		   ret >= 0) {
 		ret = qgroup_rescan_init(fs_info, rescan_progress, 0);
 	}
-	btrfs_free_path(path);
 
 	if (ret < 0) {
 		ulist_free(fs_info->qgroup_ulist);
@@ -995,7 +995,7 @@
 		goto out;
 	fs_info->quota_enabled = 0;
 	fs_info->pending_quota_state = 0;
-	btrfs_qgroup_wait_for_completion(fs_info);
+	btrfs_qgroup_wait_for_completion(fs_info, false);
 	spin_lock(&fs_info->qgroup_lock);
 	quota_root = fs_info->quota_root;
 	fs_info->quota_root = NULL;
@@ -1782,7 +1782,8 @@
 }
 
 /*
- * called from commit_transaction. Writes all changed qgroups to disk.
+ * Writes all changed qgroups to disk.
+ * Called by the transaction commit path and the qgroup assign ioctl.
  */
 int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
 		      struct btrfs_fs_info *fs_info)
@@ -1791,6 +1792,14 @@
 	int ret = 0;
 	int start_rescan_worker = 0;
 
+	/*
+	 * In case we are called from the qgroup assign ioctl, assert that we
+	 * are holding the qgroup_ioctl_lock, otherwise we can race with a quota
+	 * disable operation (ioctl) and access a freed quota root.
+	 */
+	if (trans->transaction->state != TRANS_STATE_COMMIT_DOING)
+		lockdep_assert_held(&fs_info->qgroup_ioctl_lock);
+
 	if (!quota_root)
 		goto out;
 
@@ -2186,6 +2195,21 @@
 }
 
 /*
+ * Check if the leaf is the last leaf. Which means all node pointers
+ * are at their last position.
+ */
+static bool is_last_leaf(struct btrfs_path *path)
+{
+	int i;
+
+	for (i = 1; i < BTRFS_MAX_LEVEL && path->nodes[i]; i++) {
+		if (path->slots[i] != btrfs_header_nritems(path->nodes[i]) - 1)
+			return false;
+	}
+	return true;
+}
+
+/*
  * returns < 0 on error, 0 when more leafs are to be scanned.
  * returns 1 when done.
  */
@@ -2198,6 +2222,7 @@
 	struct ulist *roots = NULL;
 	struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem);
 	u64 num_bytes;
+	bool done;
 	int slot;
 	int ret;
 
@@ -2225,6 +2250,7 @@
 		mutex_unlock(&fs_info->qgroup_rescan_lock);
 		return ret;
 	}
+	done = is_last_leaf(path);
 
 	btrfs_item_key_to_cpu(path->nodes[0], &found,
 			      btrfs_header_nritems(path->nodes[0]) - 1);
@@ -2271,6 +2297,10 @@
 	}
 	btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
 
+	if (done && !ret) {
+		ret = 1;
+		fs_info->qgroup_rescan_progress.objectid = (u64)-1;
+	}
 	return ret;
 }
 
@@ -2309,9 +2339,6 @@
 	btrfs_free_path(path);
 
 	mutex_lock(&fs_info->qgroup_rescan_lock);
-	if (!btrfs_fs_closing(fs_info))
-		fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
-
 	if (err > 0 &&
 	    fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) {
 		fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
@@ -2327,16 +2354,30 @@
 	trans = btrfs_start_transaction(fs_info->quota_root, 1);
 	if (IS_ERR(trans)) {
 		err = PTR_ERR(trans);
+		trans = NULL;
 		btrfs_err(fs_info,
 			  "fail to start transaction for status update: %d\n",
 			  err);
-		goto done;
 	}
-	ret = update_qgroup_status_item(trans, fs_info, fs_info->quota_root);
-	if (ret < 0) {
-		err = ret;
-		btrfs_err(fs_info, "fail to update qgroup status: %d\n", err);
+
+	mutex_lock(&fs_info->qgroup_rescan_lock);
+	if (!btrfs_fs_closing(fs_info))
+		fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
+	if (trans) {
+		ret = update_qgroup_status_item(trans, fs_info, fs_info->quota_root);
+		if (ret < 0) {
+			err = ret;
+			btrfs_err(fs_info, "fail to update qgroup status: %d",
+				  err);
+		}
 	}
+	fs_info->qgroup_rescan_running = false;
+	complete_all(&fs_info->qgroup_rescan_completion);
+	mutex_unlock(&fs_info->qgroup_rescan_lock);
+
+	if (!trans)
+		return;
+
 	btrfs_end_transaction(trans, fs_info->quota_root);
 
 	if (btrfs_fs_closing(fs_info)) {
@@ -2347,9 +2388,6 @@
 	} else {
 		btrfs_err(fs_info, "qgroup scan failed with %d", err);
 	}
-
-done:
-	complete_all(&fs_info->qgroup_rescan_completion);
 }
 
 /*
@@ -2390,6 +2428,7 @@
 		sizeof(fs_info->qgroup_rescan_progress));
 	fs_info->qgroup_rescan_progress.objectid = progress_objectid;
 	init_completion(&fs_info->qgroup_rescan_completion);
+	fs_info->qgroup_rescan_running = true;
 
 	spin_unlock(&fs_info->qgroup_lock);
 	mutex_unlock(&fs_info->qgroup_rescan_lock);
@@ -2423,6 +2462,7 @@
 		qgroup->rfer_cmpr = 0;
 		qgroup->excl = 0;
 		qgroup->excl_cmpr = 0;
+		qgroup_dirty(fs_info, qgroup);
 	}
 	spin_unlock(&fs_info->qgroup_lock);
 }
@@ -2467,20 +2507,26 @@
 	return 0;
 }
 
-int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info)
+int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info,
+				     bool interruptible)
 {
 	int running;
 	int ret = 0;
 
 	mutex_lock(&fs_info->qgroup_rescan_lock);
 	spin_lock(&fs_info->qgroup_lock);
-	running = fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN;
+	running = fs_info->qgroup_rescan_running;
 	spin_unlock(&fs_info->qgroup_lock);
 	mutex_unlock(&fs_info->qgroup_rescan_lock);
 
-	if (running)
+	if (!running)
+		return 0;
+
+	if (interruptible)
 		ret = wait_for_completion_interruptible(
 					&fs_info->qgroup_rescan_completion);
+	else
+		wait_for_completion(&fs_info->qgroup_rescan_completion);
 
 	return ret;
 }
--- linux-4.4.0.orig/fs/btrfs/qgroup.h
+++ linux-4.4.0/fs/btrfs/qgroup.h
@@ -46,7 +46,8 @@
 			struct btrfs_fs_info *fs_info);
 int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info);
 void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info);
-int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info);
+int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info,
+				     bool interruptible);
 int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
 			      struct btrfs_fs_info *fs_info, u64 src, u64 dst);
 int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
--- linux-4.4.0.orig/fs/btrfs/raid56.c
+++ linux-4.4.0/fs/btrfs/raid56.c
@@ -2160,11 +2160,21 @@
 	}
 
 	/*
-	 * reconstruct from the q stripe if they are
-	 * asking for mirror 3
+	 * Loop retry:
+	 * for 'mirror == 2', reconstruct from all other stripes.
+	 * for 'mirror_num > 2', select a stripe to fail on every retry.
 	 */
-	if (mirror_num == 3)
-		rbio->failb = rbio->real_stripes - 2;
+	if (mirror_num > 2) {
+		/*
+		 * 'mirror == 3' is to fail the p stripe and
+		 * reconstruct from the q stripe.  'mirror > 3' is to
+		 * fail a data stripe and reconstruct from p+q stripe.
+		 */
+		rbio->failb = rbio->real_stripes - (mirror_num - 1);
+		ASSERT(rbio->failb > 0);
+		if (rbio->failb <= rbio->faila)
+			rbio->failb--;
+	}
 
 	ret = lock_stripe_add(rbio);
 
@@ -2410,8 +2420,9 @@
 			bitmap_clear(rbio->dbitmap, pagenr, 1);
 		kunmap(p);
 
-		for (stripe = 0; stripe < rbio->real_stripes; stripe++)
+		for (stripe = 0; stripe < nr_data; stripe++)
 			kunmap(page_in_rbio(rbio, stripe, pagenr, 0));
+		kunmap(p_page);
 	}
 
 	__free_page(p_page);
--- linux-4.4.0.orig/fs/btrfs/reada.c
+++ linux-4.4.0/fs/btrfs/reada.c
@@ -762,16 +762,23 @@
 	u64 total = 0;
 	int i;
 
+again:
 	do {
 		enqueued = 0;
+		mutex_lock(&fs_devices->device_list_mutex);
 		list_for_each_entry(device, &fs_devices->devices, dev_list) {
 			if (atomic_read(&device->reada_in_flight) <
 			    MAX_IN_FLIGHT)
 				enqueued += reada_start_machine_dev(fs_info,
 								    device);
 		}
+		mutex_unlock(&fs_devices->device_list_mutex);
 		total += enqueued;
 	} while (enqueued && total < 10000);
+	if (fs_devices->seed) {
+		fs_devices = fs_devices->seed;
+		goto again;
+	}
 
 	if (enqueued == 0)
 		return;
--- linux-4.4.0.orig/fs/btrfs/relocation.c
+++ linux-4.4.0/fs/btrfs/relocation.c
@@ -921,9 +921,16 @@
 			path2->slots[level]--;
 
 		eb = path2->nodes[level];
-		WARN_ON(btrfs_node_blockptr(eb, path2->slots[level]) !=
-			cur->bytenr);
-
+		if (btrfs_node_blockptr(eb, path2->slots[level]) !=
+		    cur->bytenr) {
+			btrfs_err(root->fs_info,
+	"couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)",
+				  cur->bytenr, level - 1, root->objectid,
+				  node_key->objectid, node_key->type,
+				  node_key->offset);
+			err = -ENOENT;
+			goto out;
+		}
 		lower = cur;
 		need_check = true;
 		for (; level < BTRFS_MAX_LEVEL; level++) {
@@ -1282,7 +1289,7 @@
 	if (!node)
 		return -ENOMEM;
 
-	node->bytenr = root->node->start;
+	node->bytenr = root->commit_root->start;
 	node->data = root;
 
 	spin_lock(&rc->reloc_root_tree.lock);
@@ -1311,18 +1318,18 @@
 	struct mapping_node *node = NULL;
 	struct reloc_control *rc = root->fs_info->reloc_ctl;
 
-	spin_lock(&rc->reloc_root_tree.lock);
-	rb_node = tree_search(&rc->reloc_root_tree.rb_root,
-			      root->node->start);
-	if (rb_node) {
-		node = rb_entry(rb_node, struct mapping_node, rb_node);
-		rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root);
+	if (rc && root->node) {
+		spin_lock(&rc->reloc_root_tree.lock);
+		rb_node = tree_search(&rc->reloc_root_tree.rb_root,
+				      root->commit_root->start);
+		if (rb_node) {
+			node = rb_entry(rb_node, struct mapping_node, rb_node);
+			rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root);
+			RB_CLEAR_NODE(&node->rb_node);
+		}
+		spin_unlock(&rc->reloc_root_tree.lock);
+		ASSERT(!node || (struct btrfs_root *)node->data == root);
 	}
-	spin_unlock(&rc->reloc_root_tree.lock);
-
-	if (!node)
-		return;
-	BUG_ON((struct btrfs_root *)node->data != root);
 
 	spin_lock(&root->fs_info->trans_lock);
 	list_del_init(&root->root_list);
@@ -1334,7 +1341,7 @@
  * helper to update the 'address of tree root -> reloc tree'
  * mapping
  */
-static int __update_reloc_root(struct btrfs_root *root, u64 new_bytenr)
+static int __update_reloc_root(struct btrfs_root *root)
 {
 	struct rb_node *rb_node;
 	struct mapping_node *node = NULL;
@@ -1342,7 +1349,7 @@
 
 	spin_lock(&rc->reloc_root_tree.lock);
 	rb_node = tree_search(&rc->reloc_root_tree.rb_root,
-			      root->node->start);
+			      root->commit_root->start);
 	if (rb_node) {
 		node = rb_entry(rb_node, struct mapping_node, rb_node);
 		rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root);
@@ -1354,7 +1361,7 @@
 	BUG_ON((struct btrfs_root *)node->data != root);
 
 	spin_lock(&rc->reloc_root_tree.lock);
-	node->bytenr = new_bytenr;
+	node->bytenr = root->node->start;
 	rb_node = tree_insert(&rc->reloc_root_tree.rb_root,
 			      node->bytenr, &node->rb_node);
 	spin_unlock(&rc->reloc_root_tree.lock);
@@ -1495,6 +1502,7 @@
 	}
 
 	if (reloc_root->commit_root != reloc_root->node) {
+		__update_reloc_root(reloc_root);
 		btrfs_set_root_node(root_item, reloc_root->node);
 		free_extent_buffer(reloc_root->commit_root);
 		reloc_root->commit_root = btrfs_root_node(reloc_root);
@@ -2344,6 +2352,10 @@
 		reloc_root = list_entry(list->next, struct btrfs_root,
 					root_list);
 		__del_reloc_root(reloc_root);
+		free_extent_buffer(reloc_root->node);
+		free_extent_buffer(reloc_root->commit_root);
+		reloc_root->node = NULL;
+		reloc_root->commit_root = NULL;
 	}
 }
 
@@ -2428,7 +2440,21 @@
 			free_reloc_roots(&reloc_roots);
 	}
 
-	BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root));
+	/*
+	 * We used to have
+	 *
+	 * BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root));
+	 *
+	 * here, but it's wrong.  If we fail to start the transaction in
+	 * prepare_to_merge() we will have only 0 ref reloc roots, none of which
+	 * have actually been removed from the reloc_root_tree rb tree.  This is
+	 * fine because we're bailing here, and we hold a reference on the root
+	 * for the list that holds it, so these roots will be cleaned up when we
+	 * do the reloc_dirty_list afterwards.  Meanwhile the root->reloc_root
+	 * will be cleaned up on unmount.
+	 *
+	 * The remaining nodes will be cleaned up by free_reloc_control.
+	 */
 }
 
 static void free_block_list(struct rb_root *blocks)
@@ -2676,11 +2702,15 @@
 
 		if (!upper->eb) {
 			ret = btrfs_search_slot(trans, root, key, path, 0, 1);
-			if (ret < 0) {
-				err = ret;
+			if (ret) {
+				if (ret < 0)
+					err = ret;
+				else
+					err = -ENOENT;
+
+				btrfs_release_path(path);
 				break;
 			}
-			BUG_ON(ret > 0);
 
 			if (!upper->eb) {
 				upper->eb = path->nodes[upper->level];
@@ -3078,7 +3108,7 @@
 	em->len = end + 1 - start;
 	em->block_len = em->len;
 	em->block_start = block_start;
-	em->bdev = root->fs_info->fs_devices->latest_bdev;
+	em->bdev = root->fs_info->fs_devices->latest_dev->bdev;
 	set_bit(EXTENT_FLAG_PINNED, &em->flags);
 
 	lock_extent(&BTRFS_I(inode)->io_tree, start, end);
@@ -3869,6 +3899,7 @@
 int prepare_to_relocate(struct reloc_control *rc)
 {
 	struct btrfs_trans_handle *trans;
+	int ret;
 
 	rc->block_rsv = btrfs_alloc_block_rsv(rc->extent_root,
 					      BTRFS_BLOCK_RSV_TEMP);
@@ -3897,8 +3928,12 @@
 		 */
 		return PTR_ERR(trans);
 	}
-	btrfs_commit_transaction(trans, rc->extent_root);
-	return 0;
+
+	ret = btrfs_commit_transaction(trans, rc->extent_root);
+	if (ret)
+		unset_reloc_control(rc);
+
+	return ret;
 }
 
 static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
@@ -4438,6 +4473,7 @@
 				       reloc_root->root_key.offset);
 		if (IS_ERR(fs_root)) {
 			err = PTR_ERR(fs_root);
+			list_add_tail(&reloc_root->root_list, &reloc_roots);
 			goto out_free;
 		}
 
@@ -4547,11 +4583,6 @@
 	BUG_ON(rc->stage == UPDATE_DATA_PTRS &&
 	       root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID);
 
-	if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
-		if (buf == root->node)
-			__update_reloc_root(root, cow->start);
-	}
-
 	level = btrfs_header_level(buf);
 	if (btrfs_header_generation(buf) <=
 	    btrfs_root_last_snapshot(&root->root_item))
--- linux-4.4.0.orig/fs/btrfs/root-tree.c
+++ linux-4.4.0/fs/btrfs/root-tree.c
@@ -272,6 +272,23 @@
 		root_key.objectid = key.offset;
 		key.offset++;
 
+		/*
+		 * The root might have been inserted already, as before we look
+		 * for orphan roots, log replay might have happened, which
+		 * triggers a transaction commit and qgroup accounting, which
+		 * in turn reads and inserts fs roots while doing backref
+		 * walking.
+		 */
+		root = btrfs_lookup_fs_root(tree_root->fs_info,
+					    root_key.objectid);
+		if (root) {
+			WARN_ON(!test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED,
+					  &root->state));
+			if (btrfs_root_refs(&root->root_item) == 0)
+				btrfs_add_dead_root(root);
+			continue;
+		}
+
 		root = btrfs_read_fs_root(tree_root, &root_key);
 		err = PTR_ERR_OR_ZERO(root);
 		if (err && err != -ENOENT) {
--- linux-4.4.0.orig/fs/btrfs/scrub.c
+++ linux-4.4.0/fs/btrfs/scrub.c
@@ -918,11 +918,6 @@
 	have_csum = sblock_to_check->pagev[0]->have_csum;
 	dev = sblock_to_check->pagev[0]->dev;
 
-	if (sctx->is_dev_replace && !is_metadata && !have_csum) {
-		sblocks_for_recheck = NULL;
-		goto nodatasum_case;
-	}
-
 	/*
 	 * read all mirrors one after the other. This includes to
 	 * re-read the extent or metadata block that failed (that was
@@ -1035,13 +1030,19 @@
 		goto out;
 	}
 
-	if (!is_metadata && !have_csum) {
+	/*
+	 * NOTE: Even for nodatasum case, it's still possible that it's a
+	 * compressed data extent, thus scrub_fixup_nodatasum(), which write
+	 * inode page cache onto disk, could cause serious data corruption.
+	 *
+	 * So here we could only read from disk, and hope our recovery could
+	 * reach disk before the newer write.
+	 */
+	if (0 && !is_metadata && !have_csum) {
 		struct scrub_fixup_nodatasum *fixup_nodatasum;
 
 		WARN_ON(sctx->is_dev_replace);
 
-nodatasum_case:
-
 		/*
 		 * !is_metadata and !have_csum, this means that the data
 		 * might not be COW'ed, that it might be modified
@@ -2513,7 +2514,7 @@
 			have_csum = scrub_find_csum(sctx, logical, csum);
 			if (have_csum == 0)
 				++sctx->stat.no_csum;
-			if (sctx->is_dev_replace && !have_csum) {
+			if (0 && sctx->is_dev_replace && !have_csum) {
 				ret = copy_nocow_pages(sctx, logical, l,
 						       mirror_num,
 						      physical_for_dev_replace);
@@ -3460,7 +3461,7 @@
 		return ret;
 	}
 
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	if (em->start != chunk_offset)
 		goto out;
 
@@ -3836,7 +3837,7 @@
 
 
 	mutex_lock(&fs_info->fs_devices->device_list_mutex);
-	dev = btrfs_find_device(fs_info, devid, NULL, NULL);
+	dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL, true);
 	if (!dev || (dev->missing && !is_dev_replace)) {
 		mutex_unlock(&fs_info->fs_devices->device_list_mutex);
 		return -ENODEV;
@@ -4005,7 +4006,7 @@
 	struct scrub_ctx *sctx = NULL;
 
 	mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
-	dev = btrfs_find_device(root->fs_info, devid, NULL, NULL);
+	dev = btrfs_find_device(root->fs_info->fs_devices, devid, NULL, NULL, true);
 	if (dev)
 		sctx = dev->scrub_device;
 	if (sctx)
--- linux-4.4.0.orig/fs/btrfs/send.c
+++ linux-4.4.0/fs/btrfs/send.c
@@ -34,6 +34,7 @@
 #include "disk-io.h"
 #include "btrfs_inode.h"
 #include "transaction.h"
+#include "xattr.h"
 
 static int g_verbose = 0;
 
@@ -1469,7 +1470,21 @@
 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 	if (ret < 0)
 		goto out;
-	BUG_ON(ret);
+	if (ret) {
+		/*
+		 * An empty symlink inode. Can happen in rare error paths when
+		 * creating a symlink (transaction committed before the inode
+		 * eviction handler removed the symlink inode items and a crash
+		 * happened in between or the subvol was snapshoted in between).
+		 * Print an informative message to dmesg/syslog so that the user
+		 * can delete the symlink.
+		 */
+		btrfs_err(root->fs_info,
+			  "Found empty symlink inode %llu at root %llu",
+			  ino, root->root_key.objectid);
+		ret = -EIO;
+		goto out;
+	}
 
 	ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
 			struct btrfs_file_extent_item);
@@ -1634,6 +1649,9 @@
 {
 	int ret;
 
+	if (ino == BTRFS_FIRST_FREE_OBJECTID)
+		return 1;
+
 	ret = get_cur_inode_state(sctx, ino, gen);
 	if (ret < 0)
 		goto out;
@@ -1819,7 +1837,7 @@
 	 * not delted and then re-created, if it was then we have no overwrite
 	 * and we can just unlink this entry.
 	 */
-	if (sctx->parent_root) {
+	if (sctx->parent_root && dir != BTRFS_FIRST_FREE_OBJECTID) {
 		ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL,
 				     NULL, NULL, NULL);
 		if (ret < 0 && ret != -ENOENT)
@@ -3215,7 +3233,8 @@
 	kfree(m);
 }
 
-static void tail_append_pending_moves(struct pending_dir_move *moves,
+static void tail_append_pending_moves(struct send_ctx *sctx,
+				      struct pending_dir_move *moves,
 				      struct list_head *stack)
 {
 	if (list_empty(&moves->list)) {
@@ -3226,6 +3245,10 @@
 		list_add_tail(&moves->list, stack);
 		list_splice_tail(&list, stack);
 	}
+	if (!RB_EMPTY_NODE(&moves->node)) {
+		rb_erase(&moves->node, &sctx->pending_dir_moves);
+		RB_CLEAR_NODE(&moves->node);
+	}
 }
 
 static int apply_children_dir_moves(struct send_ctx *sctx)
@@ -3240,7 +3263,7 @@
 		return 0;
 
 	INIT_LIST_HEAD(&stack);
-	tail_append_pending_moves(pm, &stack);
+	tail_append_pending_moves(sctx, pm, &stack);
 
 	while (!list_empty(&stack)) {
 		pm = list_first_entry(&stack, struct pending_dir_move, list);
@@ -3251,7 +3274,7 @@
 			goto out;
 		pm = get_pending_dir_moves(sctx, parent_ino);
 		if (pm)
-			tail_append_pending_moves(pm, &stack);
+			tail_append_pending_moves(sctx, pm, &stack);
 	}
 	return 0;
 
@@ -4172,6 +4195,10 @@
 	struct fs_path *p;
 	posix_acl_xattr_header dummy_acl;
 
+	/* Capabilities are emitted by finish_inode_if_needed */
+	if (!strncmp(name, XATTR_NAME_CAPS, name_len))
+		return 0;
+
 	p = fs_path_alloc();
 	if (!p)
 		return -ENOMEM;
@@ -4657,6 +4684,9 @@
 	u64 len;
 	int ret = 0;
 
+	if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA)
+		return send_update_extent(sctx, offset, end - offset);
+
 	p = fs_path_alloc();
 	if (!p)
 		return -ENOMEM;
@@ -4708,6 +4738,64 @@
 	return 0;
 }
 
+/*
+ * Search for a capability xattr related to sctx->cur_ino. If the capability is
+ * found, call send_set_xattr function to emit it.
+ *
+ * Return 0 if there isn't a capability, or when the capability was emitted
+ * successfully, or < 0 if an error occurred.
+ */
+static int send_capabilities(struct send_ctx *sctx)
+{
+	struct fs_path *fspath = NULL;
+	struct btrfs_path *path;
+	struct btrfs_dir_item *di;
+	struct extent_buffer *leaf;
+	unsigned long data_ptr;
+	char *buf = NULL;
+	int buf_len;
+	int ret = 0;
+
+	path = alloc_path_for_send();
+	if (!path)
+		return -ENOMEM;
+
+	di = btrfs_lookup_xattr(NULL, sctx->send_root, path, sctx->cur_ino,
+				XATTR_NAME_CAPS, strlen(XATTR_NAME_CAPS), 0);
+	if (!di) {
+		/* There is no xattr for this inode */
+		goto out;
+	} else if (IS_ERR(di)) {
+		ret = PTR_ERR(di);
+		goto out;
+	}
+
+	leaf = path->nodes[0];
+	buf_len = btrfs_dir_data_len(leaf, di);
+
+	fspath = fs_path_alloc();
+	buf = kmalloc(buf_len, GFP_KERNEL);
+	if (!fspath || !buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, fspath);
+	if (ret < 0)
+		goto out;
+
+	data_ptr = (unsigned long)(di + 1) + btrfs_dir_name_len(leaf, di);
+	read_extent_buffer(leaf, buf, data_ptr, buf_len);
+
+	ret = send_set_xattr(sctx, fspath, XATTR_NAME_CAPS,
+			strlen(XATTR_NAME_CAPS), buf, buf_len);
+out:
+	kfree(buf);
+	fs_path_free(fspath);
+	btrfs_free_path(path);
+	return ret;
+}
+
 static int clone_range(struct send_ctx *sctx,
 		       struct clone_root *clone_root,
 		       const u64 disk_byte,
@@ -4991,15 +5079,18 @@
 	while (key.offset < ekey->offset + left_len) {
 		ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
 		right_type = btrfs_file_extent_type(eb, ei);
-		if (right_type != BTRFS_FILE_EXTENT_REG) {
+		if (right_type != BTRFS_FILE_EXTENT_REG &&
+		    right_type != BTRFS_FILE_EXTENT_INLINE) {
 			ret = 0;
 			goto out;
 		}
 
-		right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
-		right_len = btrfs_file_extent_num_bytes(eb, ei);
-		right_offset = btrfs_file_extent_offset(eb, ei);
-		right_gen = btrfs_file_extent_generation(eb, ei);
+		if (right_type == BTRFS_FILE_EXTENT_INLINE) {
+			right_len = btrfs_file_extent_inline_len(eb, slot, ei);
+			right_len = PAGE_ALIGN(right_len);
+		} else {
+			right_len = btrfs_file_extent_num_bytes(eb, ei);
+		}
 
 		/*
 		 * Are we at extent 8? If yes, we know the extent is changed.
@@ -5011,6 +5102,23 @@
 			goto out;
 		}
 
+		/*
+		 * We just wanted to see if when we have an inline extent, what
+		 * follows it is a regular extent (wanted to check the above
+		 * condition for inline extents too). This should normally not
+		 * happen but it's possible for example when we have an inline
+		 * compressed extent representing data with a size matching
+		 * the page size (currently the same as sector size).
+		 */
+		if (right_type == BTRFS_FILE_EXTENT_INLINE) {
+			ret = 0;
+			goto out;
+		}
+
+		right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
+		right_offset = btrfs_file_extent_offset(eb, ei);
+		right_gen = btrfs_file_extent_generation(eb, ei);
+
 		left_offset_fixed = left_offset;
 		if (key.offset < ekey->offset) {
 			/* Fix the right offset for 2a and 7. */
@@ -5399,6 +5507,10 @@
 			goto out;
 	}
 
+	ret = send_capabilities(sctx);
+	if (ret < 0)
+		goto out;
+
 	/*
 	 * If other directory inodes depended on our current directory
 	 * inode's move/rename, now do their move/rename operations.
--- linux-4.4.0.orig/fs/btrfs/struct-funcs.c
+++ linux-4.4.0/fs/btrfs/struct-funcs.c
@@ -50,8 +50,8 @@
  */
 
 #define DEFINE_BTRFS_SETGET_BITS(bits)					\
-u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr,	\
-			       unsigned long off,			\
+u##bits btrfs_get_token_##bits(const struct extent_buffer *eb,		\
+			       const void *ptr, unsigned long off,	\
 			       struct btrfs_map_token *token)		\
 {									\
 	unsigned long part_offset = (unsigned long)ptr;			\
@@ -90,7 +90,8 @@
 	return res;							\
 }									\
 void btrfs_set_token_##bits(struct extent_buffer *eb,			\
-			    void *ptr, unsigned long off, u##bits val,	\
+			    const void *ptr, unsigned long off,		\
+			    u##bits val,				\
 			    struct btrfs_map_token *token)		\
 {									\
 	unsigned long part_offset = (unsigned long)ptr;			\
@@ -133,7 +134,7 @@
 DEFINE_BTRFS_SETGET_BITS(32)
 DEFINE_BTRFS_SETGET_BITS(64)
 
-void btrfs_node_key(struct extent_buffer *eb,
+void btrfs_node_key(const struct extent_buffer *eb,
 		    struct btrfs_disk_key *disk_key, int nr)
 {
 	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
--- linux-4.4.0.orig/fs/btrfs/super.c
+++ linux-4.4.0/fs/btrfs/super.c
@@ -239,7 +239,7 @@
 	trans->aborted = errno;
 	/* Nothing used. The other threads that have joined this
 	 * transaction may be able to continue. */
-	if (!trans->blocks_used && list_empty(&trans->new_bgs)) {
+	if (!trans->dirty && list_empty(&trans->new_bgs)) {
 		const char *errstr;
 
 		errstr = btrfs_decode_error(errno);
@@ -843,8 +843,8 @@
 	return error;
 }
 
-static char *get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
-					   u64 subvol_objectid)
+char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
+					  u64 subvol_objectid)
 {
 	struct btrfs_root *root = fs_info->tree_root;
 	struct btrfs_root *fs_root;
@@ -1120,6 +1120,7 @@
 	struct btrfs_fs_info *info = btrfs_sb(dentry->d_sb);
 	struct btrfs_root *root = info->tree_root;
 	char *compress_type;
+	const char *subvol_name;
 
 	if (btrfs_test_opt(root, DEGRADED))
 		seq_puts(seq, ",degraded");
@@ -1204,8 +1205,13 @@
 #endif
 	seq_printf(seq, ",subvolid=%llu",
 		  BTRFS_I(d_inode(dentry))->root->root_key.objectid);
-	seq_puts(seq, ",subvol=");
-	seq_dentry(seq, dentry, " \t\n\\");
+	subvol_name = btrfs_get_subvol_name_from_objectid(info,
+			BTRFS_I(d_inode(dentry))->root->root_key.objectid);
+	if (!IS_ERR(subvol_name)) {
+		seq_puts(seq, ",subvol=");
+		seq_escape(seq, subvol_name, " \t\n\\");
+		kfree(subvol_name);
+	}
 	return 0;
 }
 
@@ -1323,8 +1329,8 @@
 				goto out;
 			}
 		}
-		subvol_name = get_subvol_name_from_objectid(btrfs_sb(mnt->mnt_sb),
-							    subvol_objectid);
+		subvol_name = btrfs_get_subvol_name_from_objectid(
+					btrfs_sb(mnt->mnt_sb), subvol_objectid);
 		if (IS_ERR(subvol_name)) {
 			root = ERR_CAST(subvol_name);
 			subvol_name = NULL;
@@ -1500,7 +1506,7 @@
 		goto error_close_devices;
 	}
 
-	bdev = fs_devices->latest_bdev;
+	bdev = fs_devices->latest_dev->bdev;
 	s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | MS_NOSEC,
 		 fs_info);
 	if (IS_ERR(s)) {
@@ -1702,6 +1708,8 @@
 		}
 
 		if (btrfs_super_log_root(fs_info->super_copy) != 0) {
+			btrfs_warn(fs_info,
+		"mount required to replay tree-log, cannot remount read-write");
 			ret = -EINVAL;
 			goto restore;
 		}
@@ -1727,6 +1735,8 @@
 			goto restore;
 		}
 
+		btrfs_qgroup_rescan_resume(fs_info);
+
 		if (!fs_info->uuid_root) {
 			btrfs_info(fs_info, "creating UUID tree");
 			ret = btrfs_create_uuid_tree(fs_info);
@@ -1956,6 +1966,8 @@
  * there are other factors that may change the result (like a new metadata
  * chunk).
  *
+ * If metadata is exhausted, f_bavail will be 0.
+ *
  * FIXME: not accurate for mixed block groups, total and free/used are ok,
  * available appears slightly larger.
  */
@@ -1967,11 +1979,14 @@
 	struct btrfs_space_info *found;
 	u64 total_used = 0;
 	u64 total_free_data = 0;
+	u64 total_free_meta = 0;
 	int bits = dentry->d_sb->s_blocksize_bits;
 	__be32 *fsid = (__be32 *)fs_info->fsid;
 	unsigned factor = 1;
 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
 	int ret;
+	u64 thresh = 0;
+	int mixed = 0;
 
 	/*
 	 * holding chunk_muext to avoid allocating new chunks, holding
@@ -1998,6 +2013,17 @@
 			}
 		}
 
+		/*
+		 * Metadata in mixed block goup profiles are accounted in data
+		 */
+		if (!mixed && found->flags & BTRFS_BLOCK_GROUP_METADATA) {
+			if (found->flags & BTRFS_BLOCK_GROUP_DATA)
+				mixed = 1;
+			else
+				total_free_meta += found->disk_total -
+					found->disk_used;
+		}
+
 		total_used += found->disk_used;
 	}
 
@@ -2019,6 +2045,32 @@
 	buf->f_bavail += div_u64(total_free_data, factor);
 	buf->f_bavail = buf->f_bavail >> bits;
 
+	/*
+	 * We calculate the remaining metadata space minus global reserve. If
+	 * this is (supposedly) smaller than zero, there's no space. But this
+	 * does not hold in practice, the exhausted state happens where's still
+	 * some positive delta. So we apply some guesswork and compare the
+	 * delta to a 4M threshold.  (Practically observed delta was ~2M.)
+	 *
+	 * We probably cannot calculate the exact threshold value because this
+	 * depends on the internal reservations requested by various
+	 * operations, so some operations that consume a few metadata will
+	 * succeed even if the Avail is zero. But this is better than the other
+	 * way around.
+	 */
+	thresh = 4 * 1024 * 1024;
+
+	/*
+	 * We only want to claim there's no available space if we can no longer
+	 * allocate chunks for our metadata profile and our global reserve will
+	 * not fit in the free metadata space.  If we aren't ->full then we
+	 * still can allocate chunks and thus are fine using the currently
+	 * calculated f_bavail.
+	 */
+	if (!mixed && block_rsv->space_info->full &&
+	    total_free_meta - thresh < block_rsv->size)
+		buf->f_bavail = 0;
+
 	buf->f_type = BTRFS_SUPER_MAGIC;
 	buf->f_bsize = dentry->d_sb->s_blocksize;
 	buf->f_namelen = BTRFS_NAME_LEN;
@@ -2078,6 +2130,7 @@
 	vol = memdup_user((void __user *)arg, sizeof(*vol));
 	if (IS_ERR(vol))
 		return PTR_ERR(vol);
+	vol->name[BTRFS_PATH_NAME_MAX] = '\0';
 
 	switch (cmd) {
 	case BTRFS_IOC_SCAN_DEV:
@@ -2115,35 +2168,16 @@
 static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(root->d_sb);
-	struct btrfs_fs_devices *cur_devices;
-	struct btrfs_device *dev, *first_dev = NULL;
-	struct list_head *head;
-	struct rcu_string *name;
-
-	mutex_lock(&fs_info->fs_devices->device_list_mutex);
-	cur_devices = fs_info->fs_devices;
-	while (cur_devices) {
-		head = &cur_devices->devices;
-		list_for_each_entry(dev, head, dev_list) {
-			if (dev->missing)
-				continue;
-			if (!dev->name)
-				continue;
-			if (!first_dev || dev->devid < first_dev->devid)
-				first_dev = dev;
-		}
-		cur_devices = cur_devices->seed;
-	}
-
-	if (first_dev) {
-		rcu_read_lock();
-		name = rcu_dereference(first_dev->name);
-		seq_escape(m, name->str, " \t\n\\");
-		rcu_read_unlock();
-	} else {
-		WARN_ON(1);
-	}
-	mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+
+	/*
+	 * There should be always a valid pointer in latest_dev, it may be stale
+	 * for a short moment in case it's being deleted but still valid until
+	 * the end of RCU grace period.
+	 */
+	rcu_read_lock();
+	seq_escape(m, rcu_str_deref(fs_info->fs_devices->latest_dev->name), " \t\n\\");
+	rcu_read_unlock();
+
 	return 0;
 }
 
--- linux-4.4.0.orig/fs/btrfs/sysfs.c
+++ linux-4.4.0/fs/btrfs/sysfs.c
@@ -733,7 +733,12 @@
 	fs_devs->fsid_kobj.kset = btrfs_kset;
 	error = kobject_init_and_add(&fs_devs->fsid_kobj,
 				&btrfs_ktype, parent, "%pU", fs_devs->fsid);
-	return error;
+	if (error) {
+		kobject_put(&fs_devs->fsid_kobj);
+		return error;
+	}
+
+	return 0;
 }
 
 int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
--- linux-4.4.0.orig/fs/btrfs/tests/btrfs-tests.c
+++ linux-4.4.0/fs/btrfs/tests/btrfs-tests.c
@@ -48,7 +48,13 @@
 
 struct inode *btrfs_new_test_inode(void)
 {
-	return new_inode(test_mnt->mnt_sb);
+	struct inode *inode;
+
+	inode = new_inode(test_mnt->mnt_sb);
+	if (inode)
+		inode_init_owner(inode, NULL, S_IFREG);
+
+	return inode;
 }
 
 int btrfs_init_test_fs(void)
@@ -109,7 +115,6 @@
 	spin_lock_init(&fs_info->qgroup_op_lock);
 	spin_lock_init(&fs_info->super_lock);
 	spin_lock_init(&fs_info->fs_roots_radix_lock);
-	spin_lock_init(&fs_info->tree_mod_seq_lock);
 	mutex_init(&fs_info->qgroup_ioctl_lock);
 	mutex_init(&fs_info->qgroup_rescan_lock);
 	rwlock_init(&fs_info->tree_mod_log_lock);
--- linux-4.4.0.orig/fs/btrfs/tests/inode-tests.c
+++ linux-4.4.0/fs/btrfs/tests/inode-tests.c
@@ -235,6 +235,7 @@
 		return ret;
 	}
 
+	inode->i_mode = S_IFREG;
 	BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
 	BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
 	BTRFS_I(inode)->location.offset = 0;
@@ -247,7 +248,7 @@
 
 	/*
 	 * We do this since btrfs_get_extent wants to assign em->bdev to
-	 * root->fs_info->fs_devices->latest_bdev.
+	 * root->fs_info->fs_devices->latest_dev->bdev.
 	 */
 	root->fs_info = btrfs_alloc_dummy_fs_info();
 	if (!root->fs_info) {
--- linux-4.4.0.orig/fs/btrfs/tests/qgroup-tests.c
+++ linux-4.4.0/fs/btrfs/tests/qgroup-tests.c
@@ -70,7 +70,7 @@
 	btrfs_set_extent_generation(leaf, item, 1);
 	btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK);
 	block_info = (struct btrfs_tree_block_info *)(item + 1);
-	btrfs_set_tree_block_level(leaf, block_info, 1);
+	btrfs_set_tree_block_level(leaf, block_info, 0);
 	iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
 	if (parent > 0) {
 		btrfs_set_extent_inline_ref_type(leaf, iref,
@@ -477,9 +477,9 @@
 	 * *cough*backref walking code*cough*
 	 */
 	root->node = alloc_test_extent_buffer(root->fs_info, 4096);
-	if (!root->node) {
+	if (IS_ERR(root->node)) {
 		test_msg("Couldn't allocate dummy buffer\n");
-		ret = -ENOMEM;
+		ret = PTR_ERR(root->node);
 		goto out;
 	}
 	btrfs_set_header_level(root->node, 0);
--- linux-4.4.0.orig/fs/btrfs/transaction.c
+++ linux-4.4.0/fs/btrfs/transaction.c
@@ -1806,6 +1806,27 @@
 		   atomic_read(&cur_trans->pending_ordered) == 0);
 }
 
+/*
+ * Add a pending snapshot associated with the given transaction handle to the
+ * respective handle. This must be called after the transaction commit started
+ * and while holding fs_info->trans_lock.
+ * This serves to guarantee a caller of btrfs_commit_transaction() that it can
+ * safely free the pending snapshot pointer in case btrfs_commit_transaction()
+ * returns an error.
+ */
+static void add_pending_snapshot(struct btrfs_trans_handle *trans)
+{
+	struct btrfs_transaction *cur_trans = trans->transaction;
+
+	if (!trans->pending_snapshot)
+		return;
+
+	lockdep_assert_held(&trans->root->fs_info->trans_lock);
+	ASSERT(cur_trans->state >= TRANS_STATE_COMMIT_START);
+
+	list_add(&trans->pending_snapshot->list, &cur_trans->pending_snapshots);
+}
+
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *root)
 {
@@ -1814,6 +1835,14 @@
 	struct btrfs_inode *btree_ino = BTRFS_I(root->fs_info->btree_inode);
 	int ret;
 
+	/*
+	 * Some places just start a transaction to commit it.  We need to make
+	 * sure that if this commit fails that the abort code actually marks the
+	 * transaction as failed, so set trans->dirty to make the abort code do
+	 * the right thing.
+	 */
+	trans->dirty = true;
+
 	/* Stop the commit early if ->aborted is set */
 	if (unlikely(ACCESS_ONCE(cur_trans->aborted))) {
 		ret = cur_trans->aborted;
@@ -1821,6 +1850,9 @@
 		return ret;
 	}
 
+	btrfs_trans_release_metadata(trans, root);
+	trans->block_rsv = NULL;
+
 	/* make a pass through all the delayed refs we have so far
 	 * any runnings procs may add more while we are here
 	 */
@@ -1830,9 +1862,6 @@
 		return ret;
 	}
 
-	btrfs_trans_release_metadata(trans, root);
-	trans->block_rsv = NULL;
-
 	cur_trans = trans->transaction;
 
 	/*
@@ -1883,6 +1912,8 @@
 
 	spin_lock(&root->fs_info->trans_lock);
 	if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
+		add_pending_snapshot(trans);
+
 		spin_unlock(&root->fs_info->trans_lock);
 		atomic_inc(&cur_trans->use_count);
 		ret = btrfs_end_transaction(trans, root);
@@ -1949,6 +1980,7 @@
 	 * COMMIT_DOING so make sure to wait for num_writers to == 1 again.
 	 */
 	spin_lock(&root->fs_info->trans_lock);
+	add_pending_snapshot(trans);
 	cur_trans->state = TRANS_STATE_COMMIT_DOING;
 	spin_unlock(&root->fs_info->trans_lock);
 	wait_event(cur_trans->writer_wait,
--- linux-4.4.0.orig/fs/btrfs/transaction.h
+++ linux-4.4.0/fs/btrfs/transaction.h
@@ -110,17 +110,19 @@
 	u64 chunk_bytes_reserved;
 	unsigned long use_count;
 	unsigned long blocks_reserved;
-	unsigned long blocks_used;
 	unsigned long delayed_ref_updates;
 	struct btrfs_transaction *transaction;
 	struct btrfs_block_rsv *block_rsv;
 	struct btrfs_block_rsv *orig_rsv;
+	/* Set by a task that wants to create a snapshot. */
+	struct btrfs_pending_snapshot *pending_snapshot;
 	short aborted;
 	short adding_csums;
 	bool allocating_chunk;
 	bool can_flush_pending_bgs;
 	bool reloc_reserved;
 	bool sync;
+	bool dirty;
 	unsigned int type;
 	/*
 	 * this root is only needed to validate that the root passed to
--- linux-4.4.0.orig/fs/btrfs/tree-checker.c
+++ linux-4.4.0/fs/btrfs/tree-checker.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) Qu Wenruo 2017.  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 v2 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.
+ */
+
+/*
+ * The module is used to catch unexpected/corrupted tree block data.
+ * Such behavior can be caused either by a fuzzed image or bugs.
+ *
+ * The objective is to do leaf/node validation checks when tree block is read
+ * from disk, and check *every* possible member, so other code won't
+ * need to checking them again.
+ *
+ * Due to the potential and unwanted damage, every checker needs to be
+ * carefully reviewed otherwise so it does not prevent mount of valid images.
+ */
+
+#include "ctree.h"
+#include "tree-checker.h"
+#include "disk-io.h"
+#include "compression.h"
+#include "hash.h"
+#include "volumes.h"
+
+#define CORRUPT(reason, eb, root, slot)					\
+	btrfs_crit(root->fs_info,					\
+		   "corrupt %s, %s: block=%llu, root=%llu, slot=%d",	\
+		   btrfs_header_level(eb) == 0 ? "leaf" : "node",	\
+		   reason, btrfs_header_bytenr(eb), root->objectid, slot)
+
+/*
+ * Error message should follow the following format:
+ * corrupt <type>: <identifier>, <reason>[, <bad_value>]
+ *
+ * @type:	leaf or node
+ * @identifier:	the necessary info to locate the leaf/node.
+ * 		It's recommened to decode key.objecitd/offset if it's
+ * 		meaningful.
+ * @reason:	describe the error
+ * @bad_value:	optional, it's recommened to output bad value and its
+ *		expected value (range).
+ *
+ * Since comma is used to separate the components, only space is allowed
+ * inside each component.
+ */
+
+/*
+ * Append generic "corrupt leaf/node root=%llu block=%llu slot=%d: " to @fmt.
+ * Allows callers to customize the output.
+ */
+__printf(4, 5)
+static void generic_err(const struct btrfs_root *root,
+			const struct extent_buffer *eb, int slot,
+			const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	btrfs_crit(root->fs_info,
+		"corrupt %s: root=%llu block=%llu slot=%d, %pV",
+		btrfs_header_level(eb) == 0 ? "leaf" : "node",
+		root->objectid, btrfs_header_bytenr(eb), slot, &vaf);
+	va_end(args);
+}
+
+static int check_extent_data_item(struct btrfs_root *root,
+				  struct extent_buffer *leaf,
+				  struct btrfs_key *key, int slot)
+{
+	struct btrfs_file_extent_item *fi;
+	u32 sectorsize = root->sectorsize;
+	u32 item_size = btrfs_item_size_nr(leaf, slot);
+
+	if (!IS_ALIGNED(key->offset, sectorsize)) {
+		CORRUPT("unaligned key offset for file extent",
+			leaf, root, slot);
+		return -EUCLEAN;
+	}
+
+	fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+
+	if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
+		CORRUPT("invalid file extent type", leaf, root, slot);
+		return -EUCLEAN;
+	}
+
+	/*
+	 * Support for new compression/encrption must introduce incompat flag,
+	 * and must be caught in open_ctree().
+	 */
+	if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
+		CORRUPT("invalid file extent compression", leaf, root, slot);
+		return -EUCLEAN;
+	}
+	if (btrfs_file_extent_encryption(leaf, fi)) {
+		CORRUPT("invalid file extent encryption", leaf, root, slot);
+		return -EUCLEAN;
+	}
+	if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
+		/* Inline extent must have 0 as key offset */
+		if (key->offset) {
+			CORRUPT("inline extent has non-zero key offset",
+				leaf, root, slot);
+			return -EUCLEAN;
+		}
+
+		/* Compressed inline extent has no on-disk size, skip it */
+		if (btrfs_file_extent_compression(leaf, fi) !=
+		    BTRFS_COMPRESS_NONE)
+			return 0;
+
+		/* Uncompressed inline extent size must match item size */
+		if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
+		    btrfs_file_extent_ram_bytes(leaf, fi)) {
+			CORRUPT("plaintext inline extent has invalid size",
+				leaf, root, slot);
+			return -EUCLEAN;
+		}
+		return 0;
+	}
+
+	/* Regular or preallocated extent has fixed item size */
+	if (item_size != sizeof(*fi)) {
+		CORRUPT(
+		"regluar or preallocated extent data item size is invalid",
+			leaf, root, slot);
+		return -EUCLEAN;
+	}
+	if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) ||
+	    !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) ||
+	    !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) ||
+	    !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) ||
+	    !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) {
+		CORRUPT(
+		"regular or preallocated extent data item has unaligned value",
+			leaf, root, slot);
+		return -EUCLEAN;
+	}
+
+	return 0;
+}
+
+static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
+			   struct btrfs_key *key, int slot)
+{
+	u32 sectorsize = root->sectorsize;
+	u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
+
+	if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
+		CORRUPT("invalid objectid for csum item", leaf, root, slot);
+		return -EUCLEAN;
+	}
+	if (!IS_ALIGNED(key->offset, sectorsize)) {
+		CORRUPT("unaligned key offset for csum item", leaf, root, slot);
+		return -EUCLEAN;
+	}
+	if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
+		CORRUPT("unaligned csum item size", leaf, root, slot);
+		return -EUCLEAN;
+	}
+	return 0;
+}
+
+/*
+ * Customized reported for dir_item, only important new info is key->objectid,
+ * which represents inode number
+ */
+__printf(4, 5)
+static void dir_item_err(const struct btrfs_root *root,
+			 const struct extent_buffer *eb, int slot,
+			 const char *fmt, ...)
+{
+	struct btrfs_key key;
+	struct va_format vaf;
+	va_list args;
+
+	btrfs_item_key_to_cpu(eb, &key, slot);
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	btrfs_crit(root->fs_info,
+	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
+		btrfs_header_level(eb) == 0 ? "leaf" : "node", root->objectid,
+		btrfs_header_bytenr(eb), slot, key.objectid, &vaf);
+	va_end(args);
+}
+
+static int check_dir_item(struct btrfs_root *root,
+			  struct extent_buffer *leaf,
+			  struct btrfs_key *key, int slot)
+{
+	struct btrfs_dir_item *di;
+	u32 item_size = btrfs_item_size_nr(leaf, slot);
+	u32 cur = 0;
+
+	di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
+	while (cur < item_size) {
+		u32 name_len;
+		u32 data_len;
+		u32 max_name_len;
+		u32 total_size;
+		u32 name_hash;
+		u8 dir_type;
+
+		/* header itself should not cross item boundary */
+		if (cur + sizeof(*di) > item_size) {
+			dir_item_err(root, leaf, slot,
+		"dir item header crosses item boundary, have %zu boundary %u",
+				cur + sizeof(*di), item_size);
+			return -EUCLEAN;
+		}
+
+		/* dir type check */
+		dir_type = btrfs_dir_type(leaf, di);
+		if (dir_type >= BTRFS_FT_MAX) {
+			dir_item_err(root, leaf, slot,
+			"invalid dir item type, have %u expect [0, %u)",
+				dir_type, BTRFS_FT_MAX);
+			return -EUCLEAN;
+		}
+
+		if (key->type == BTRFS_XATTR_ITEM_KEY &&
+		    dir_type != BTRFS_FT_XATTR) {
+			dir_item_err(root, leaf, slot,
+		"invalid dir item type for XATTR key, have %u expect %u",
+				dir_type, BTRFS_FT_XATTR);
+			return -EUCLEAN;
+		}
+		if (dir_type == BTRFS_FT_XATTR &&
+		    key->type != BTRFS_XATTR_ITEM_KEY) {
+			dir_item_err(root, leaf, slot,
+			"xattr dir type found for non-XATTR key");
+			return -EUCLEAN;
+		}
+		if (dir_type == BTRFS_FT_XATTR)
+			max_name_len = XATTR_NAME_MAX;
+		else
+			max_name_len = BTRFS_NAME_LEN;
+
+		/* Name/data length check */
+		name_len = btrfs_dir_name_len(leaf, di);
+		data_len = btrfs_dir_data_len(leaf, di);
+		if (name_len > max_name_len) {
+			dir_item_err(root, leaf, slot,
+			"dir item name len too long, have %u max %u",
+				name_len, max_name_len);
+			return -EUCLEAN;
+		}
+		if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)) {
+			dir_item_err(root, leaf, slot,
+			"dir item name and data len too long, have %u max %zu",
+				name_len + data_len,
+				BTRFS_MAX_XATTR_SIZE(root));
+			return -EUCLEAN;
+		}
+
+		if (data_len && dir_type != BTRFS_FT_XATTR) {
+			dir_item_err(root, leaf, slot,
+			"dir item with invalid data len, have %u expect 0",
+				data_len);
+			return -EUCLEAN;
+		}
+
+		total_size = sizeof(*di) + name_len + data_len;
+
+		/* header and name/data should not cross item boundary */
+		if (cur + total_size > item_size) {
+			dir_item_err(root, leaf, slot,
+		"dir item data crosses item boundary, have %u boundary %u",
+				cur + total_size, item_size);
+			return -EUCLEAN;
+		}
+
+		/*
+		 * Special check for XATTR/DIR_ITEM, as key->offset is name
+		 * hash, should match its name
+		 */
+		if (key->type == BTRFS_DIR_ITEM_KEY ||
+		    key->type == BTRFS_XATTR_ITEM_KEY) {
+			char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
+
+			read_extent_buffer(leaf, namebuf,
+					(unsigned long)(di + 1), name_len);
+			name_hash = btrfs_name_hash(namebuf, name_len);
+			if (key->offset != name_hash) {
+				dir_item_err(root, leaf, slot,
+		"name hash mismatch with key, have 0x%016x expect 0x%016llx",
+					name_hash, key->offset);
+				return -EUCLEAN;
+			}
+		}
+		cur += total_size;
+		di = (struct btrfs_dir_item *)((void *)di + total_size);
+	}
+	return 0;
+}
+
+__printf(4, 5)
+__cold
+static void block_group_err(const struct btrfs_fs_info *fs_info,
+			    const struct extent_buffer *eb, int slot,
+			    const char *fmt, ...)
+{
+	struct btrfs_key key;
+	struct va_format vaf;
+	va_list args;
+
+	btrfs_item_key_to_cpu(eb, &key, slot);
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	btrfs_crit(fs_info,
+	"corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV",
+		btrfs_header_level(eb) == 0 ? "leaf" : "node",
+		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
+		key.objectid, key.offset, &vaf);
+	va_end(args);
+}
+
+static int check_block_group_item(struct btrfs_fs_info *fs_info,
+				  struct extent_buffer *leaf,
+				  struct btrfs_key *key, int slot)
+{
+	struct btrfs_block_group_item bgi;
+	u32 item_size = btrfs_item_size_nr(leaf, slot);
+	u64 flags;
+	u64 type;
+
+	/*
+	 * Here we don't really care about alignment since extent allocator can
+	 * handle it.  We care more about the size, as if one block group is
+	 * larger than maximum size, it's must be some obvious corruption.
+	 */
+	if (key->offset > BTRFS_MAX_DATA_CHUNK_SIZE || key->offset == 0) {
+		block_group_err(fs_info, leaf, slot,
+			"invalid block group size, have %llu expect (0, %llu]",
+				key->offset, BTRFS_MAX_DATA_CHUNK_SIZE);
+		return -EUCLEAN;
+	}
+
+	if (item_size != sizeof(bgi)) {
+		block_group_err(fs_info, leaf, slot,
+			"invalid item size, have %u expect %zu",
+				item_size, sizeof(bgi));
+		return -EUCLEAN;
+	}
+
+	read_extent_buffer(leaf, &bgi, btrfs_item_ptr_offset(leaf, slot),
+			   sizeof(bgi));
+	if (btrfs_block_group_chunk_objectid(&bgi) !=
+	    BTRFS_FIRST_CHUNK_TREE_OBJECTID) {
+		block_group_err(fs_info, leaf, slot,
+		"invalid block group chunk objectid, have %llu expect %llu",
+				btrfs_block_group_chunk_objectid(&bgi),
+				BTRFS_FIRST_CHUNK_TREE_OBJECTID);
+		return -EUCLEAN;
+	}
+
+	if (btrfs_block_group_used(&bgi) > key->offset) {
+		block_group_err(fs_info, leaf, slot,
+			"invalid block group used, have %llu expect [0, %llu)",
+				btrfs_block_group_used(&bgi), key->offset);
+		return -EUCLEAN;
+	}
+
+	flags = btrfs_block_group_flags(&bgi);
+	if (hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) > 1) {
+		block_group_err(fs_info, leaf, slot,
+"invalid profile flags, have 0x%llx (%lu bits set) expect no more than 1 bit set",
+			flags & BTRFS_BLOCK_GROUP_PROFILE_MASK,
+			hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK));
+		return -EUCLEAN;
+	}
+
+	type = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
+	if (type != BTRFS_BLOCK_GROUP_DATA &&
+	    type != BTRFS_BLOCK_GROUP_METADATA &&
+	    type != BTRFS_BLOCK_GROUP_SYSTEM &&
+	    type != (BTRFS_BLOCK_GROUP_METADATA |
+			   BTRFS_BLOCK_GROUP_DATA)) {
+		block_group_err(fs_info, leaf, slot,
+"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llx or 0x%llx",
+			type, hweight64(type),
+			BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA,
+			BTRFS_BLOCK_GROUP_SYSTEM,
+			BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA);
+		return -EUCLEAN;
+	}
+	return 0;
+}
+
+/*
+ * Common point to switch the item-specific validation.
+ */
+static int check_leaf_item(struct btrfs_root *root,
+			   struct extent_buffer *leaf,
+			   struct btrfs_key *key, int slot)
+{
+	int ret = 0;
+
+	switch (key->type) {
+	case BTRFS_EXTENT_DATA_KEY:
+		ret = check_extent_data_item(root, leaf, key, slot);
+		break;
+	case BTRFS_EXTENT_CSUM_KEY:
+		ret = check_csum_item(root, leaf, key, slot);
+		break;
+	case BTRFS_DIR_ITEM_KEY:
+	case BTRFS_DIR_INDEX_KEY:
+	case BTRFS_XATTR_ITEM_KEY:
+		ret = check_dir_item(root, leaf, key, slot);
+		break;
+	case BTRFS_BLOCK_GROUP_ITEM_KEY:
+		ret = check_block_group_item(root->fs_info, leaf, key, slot);
+		break;
+	}
+	return ret;
+}
+
+static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
+		      bool check_item_data)
+{
+	struct btrfs_fs_info *fs_info = root->fs_info;
+	/* No valid key type is 0, so all key should be larger than this key */
+	struct btrfs_key prev_key = {0, 0, 0};
+	struct btrfs_key key;
+	u32 nritems = btrfs_header_nritems(leaf);
+	int slot;
+
+	if (btrfs_header_level(leaf) != 0) {
+		generic_err(root, leaf, 0,
+			"invalid level for leaf, have %d expect 0",
+			btrfs_header_level(leaf));
+		return -EUCLEAN;
+	}
+
+	/*
+	 * Extent buffers from a relocation tree have a owner field that
+	 * corresponds to the subvolume tree they are based on. So just from an
+	 * extent buffer alone we can not find out what is the id of the
+	 * corresponding subvolume tree, so we can not figure out if the extent
+	 * buffer corresponds to the root of the relocation tree or not. So
+	 * skip this check for relocation trees.
+	 */
+	if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
+		u64 owner = btrfs_header_owner(leaf);
+		struct btrfs_root *check_root;
+
+		/* These trees must never be empty */
+		if (owner == BTRFS_ROOT_TREE_OBJECTID ||
+		    owner == BTRFS_CHUNK_TREE_OBJECTID ||
+		    owner == BTRFS_EXTENT_TREE_OBJECTID ||
+		    owner == BTRFS_DEV_TREE_OBJECTID ||
+		    owner == BTRFS_FS_TREE_OBJECTID ||
+		    owner == BTRFS_DATA_RELOC_TREE_OBJECTID) {
+			generic_err(root, leaf, 0,
+			"invalid root, root %llu must never be empty",
+				    owner);
+			return -EUCLEAN;
+		}
+		key.objectid = owner;
+		key.type = BTRFS_ROOT_ITEM_KEY;
+		key.offset = (u64)-1;
+
+		check_root = btrfs_get_fs_root(fs_info, &key, false);
+		/*
+		 * The only reason we also check NULL here is that during
+		 * open_ctree() some roots has not yet been set up.
+		 */
+		if (!IS_ERR_OR_NULL(check_root)) {
+			struct extent_buffer *eb;
+
+			eb = btrfs_root_node(check_root);
+			/* if leaf is the root, then it's fine */
+			if (leaf != eb) {
+				CORRUPT("non-root leaf's nritems is 0",
+					leaf, check_root, 0);
+				free_extent_buffer(eb);
+				return -EUCLEAN;
+			}
+			free_extent_buffer(eb);
+		}
+		return 0;
+	}
+
+	if (nritems == 0)
+		return 0;
+
+	/*
+	 * Check the following things to make sure this is a good leaf, and
+	 * leaf users won't need to bother with similar sanity checks:
+	 *
+	 * 1) key ordering
+	 * 2) item offset and size
+	 *    No overlap, no hole, all inside the leaf.
+	 * 3) item content
+	 *    If possible, do comprehensive sanity check.
+	 *    NOTE: All checks must only rely on the item data itself.
+	 */
+	for (slot = 0; slot < nritems; slot++) {
+		u32 item_end_expected;
+		int ret;
+
+		btrfs_item_key_to_cpu(leaf, &key, slot);
+
+		/* Make sure the keys are in the right order */
+		if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
+			CORRUPT("bad key order", leaf, root, slot);
+			return -EUCLEAN;
+		}
+
+		/*
+		 * Make sure the offset and ends are right, remember that the
+		 * item data starts at the end of the leaf and grows towards the
+		 * front.
+		 */
+		if (slot == 0)
+			item_end_expected = BTRFS_LEAF_DATA_SIZE(root);
+		else
+			item_end_expected = btrfs_item_offset_nr(leaf,
+								 slot - 1);
+		if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
+			CORRUPT("slot offset bad", leaf, root, slot);
+			return -EUCLEAN;
+		}
+
+		/*
+		 * Check to make sure that we don't point outside of the leaf,
+		 * just in case all the items are consistent to each other, but
+		 * all point outside of the leaf.
+		 */
+		if (btrfs_item_end_nr(leaf, slot) >
+		    BTRFS_LEAF_DATA_SIZE(root)) {
+			CORRUPT("slot end outside of leaf", leaf, root, slot);
+			return -EUCLEAN;
+		}
+
+		/* Also check if the item pointer overlaps with btrfs item. */
+		if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
+		    btrfs_item_ptr_offset(leaf, slot)) {
+			CORRUPT("slot overlap with its data", leaf, root, slot);
+			return -EUCLEAN;
+		}
+
+		if (check_item_data) {
+			/*
+			 * Check if the item size and content meet other
+			 * criteria
+			 */
+			ret = check_leaf_item(root, leaf, &key, slot);
+			if (ret < 0)
+				return ret;
+		}
+
+		prev_key.objectid = key.objectid;
+		prev_key.type = key.type;
+		prev_key.offset = key.offset;
+	}
+
+	return 0;
+}
+
+int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf)
+{
+	return check_leaf(root, leaf, true);
+}
+
+int btrfs_check_leaf_relaxed(struct btrfs_root *root,
+			     struct extent_buffer *leaf)
+{
+	return check_leaf(root, leaf, false);
+}
+
+int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
+{
+	unsigned long nr = btrfs_header_nritems(node);
+	struct btrfs_key key, next_key;
+	int slot;
+	int level = btrfs_header_level(node);
+	u64 bytenr;
+	int ret = 0;
+
+	if (level <= 0 || level >= BTRFS_MAX_LEVEL) {
+		generic_err(root, node, 0,
+			"invalid level for node, have %d expect [1, %d]",
+			level, BTRFS_MAX_LEVEL - 1);
+		return -EUCLEAN;
+	}
+	if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
+		btrfs_crit(root->fs_info,
+"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%zu]",
+			   root->objectid, node->start,
+			   nr == 0 ? "small" : "large", nr,
+			   BTRFS_NODEPTRS_PER_BLOCK(root));
+		return -EUCLEAN;
+	}
+
+	for (slot = 0; slot < nr - 1; slot++) {
+		bytenr = btrfs_node_blockptr(node, slot);
+		btrfs_node_key_to_cpu(node, &key, slot);
+		btrfs_node_key_to_cpu(node, &next_key, slot + 1);
+
+		if (!bytenr) {
+			generic_err(root, node, slot,
+				"invalid NULL node pointer");
+			ret = -EUCLEAN;
+			goto out;
+		}
+		if (!IS_ALIGNED(bytenr, root->sectorsize)) {
+			generic_err(root, node, slot,
+			"unaligned pointer, have %llu should be aligned to %u",
+				bytenr, root->sectorsize);
+			ret = -EUCLEAN;
+			goto out;
+		}
+
+		if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
+			generic_err(root, node, slot,
+	"bad key order, current (%llu %u %llu) next (%llu %u %llu)",
+				key.objectid, key.type, key.offset,
+				next_key.objectid, next_key.type,
+				next_key.offset);
+			ret = -EUCLEAN;
+			goto out;
+		}
+	}
+out:
+	return ret;
+}
--- linux-4.4.0.orig/fs/btrfs/tree-checker.h
+++ linux-4.4.0/fs/btrfs/tree-checker.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Qu Wenruo 2017.  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 v2 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.
+ */
+
+#ifndef __BTRFS_TREE_CHECKER__
+#define __BTRFS_TREE_CHECKER__
+
+#include "ctree.h"
+#include "extent_io.h"
+
+/*
+ * Comprehensive leaf checker.
+ * Will check not only the item pointers, but also every possible member
+ * in item data.
+ */
+int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf);
+
+/*
+ * Less strict leaf checker.
+ * Will only check item pointers, not reading item data.
+ */
+int btrfs_check_leaf_relaxed(struct btrfs_root *root,
+			     struct extent_buffer *leaf);
+int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
+
+#endif
--- linux-4.4.0.orig/fs/btrfs/tree-log.c
+++ linux-4.4.0/fs/btrfs/tree-log.c
@@ -26,6 +26,7 @@
 #include "print-tree.h"
 #include "backref.h"
 #include "hash.h"
+#include "inode-map.h"
 
 /* magic values for the inode_only field in btrfs_log_inode:
  *
@@ -1581,8 +1582,6 @@
 		ret = btrfs_update_inode(trans, root, inode);
 	} else if (ret == -EEXIST) {
 		ret = 0;
-	} else {
-		BUG(); /* Logic Error */
 	}
 	iput(inode);
 
@@ -1923,12 +1922,11 @@
 next:
 	/* check the next slot in the tree to see if it is a valid item */
 	nritems = btrfs_header_nritems(path->nodes[0]);
+	path->slots[0]++;
 	if (path->slots[0] >= nritems) {
 		ret = btrfs_next_leaf(root, path);
 		if (ret)
 			goto out;
-	} else {
-		path->slots[0]++;
 	}
 
 	btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
@@ -2223,8 +2221,10 @@
 			nritems = btrfs_header_nritems(path->nodes[0]);
 			if (path->slots[0] >= nritems) {
 				ret = btrfs_next_leaf(root, path);
-				if (ret)
+				if (ret == 1)
 					break;
+				else if (ret < 0)
+					goto out;
 			}
 			btrfs_item_key_to_cpu(path->nodes[0], &found_key,
 					      path->slots[0]);
@@ -2446,6 +2446,9 @@
 							next);
 					btrfs_wait_tree_block_writeback(next);
 					btrfs_tree_unlock(next);
+				} else {
+					if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+						clear_extent_buffer_dirty(next);
 				}
 
 				WARN_ON(root_owner !=
@@ -2525,6 +2528,9 @@
 							next);
 					btrfs_wait_tree_block_writeback(next);
 					btrfs_tree_unlock(next);
+				} else {
+					if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+						clear_extent_buffer_dirty(next);
 				}
 
 				WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
@@ -2601,6 +2607,9 @@
 				clean_tree_block(trans, log->fs_info, next);
 				btrfs_wait_tree_block_writeback(next);
 				btrfs_tree_unlock(next);
+			} else {
+				if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+					clear_extent_buffer_dirty(next);
 			}
 
 			WARN_ON(log->root_key.objectid !=
@@ -2696,14 +2705,12 @@
 					     int index, int error)
 {
 	struct btrfs_log_ctx *ctx;
+	struct btrfs_log_ctx *safe;
 
-	if (!error) {
-		INIT_LIST_HEAD(&root->log_ctxs[index]);
-		return;
-	}
-
-	list_for_each_entry(ctx, &root->log_ctxs[index], list)
+	list_for_each_entry_safe(ctx, safe, &root->log_ctxs[index], list) {
+		list_del_init(&ctx->list);
 		ctx->log_ret = error;
+	}
 
 	INIT_LIST_HEAD(&root->log_ctxs[index]);
 }
@@ -2800,6 +2807,12 @@
 	log->log_transid = root->log_transid;
 	root->log_start_pid = 0;
 	/*
+	 * Update or create log root item under the root's log_mutex to prevent
+	 * races with concurrent log syncs that can lead to failure to update
+	 * log root item because it was not created yet.
+	 */
+	ret = update_log_root(trans, log);
+	/*
 	 * IO has been started, blocks of the log tree have WRITTEN flag set
 	 * in their headers. new modifications of the log will be written to
 	 * new positions. so it's safe to allow log writers to go in.
@@ -2818,8 +2831,6 @@
 
 	mutex_unlock(&log_root_tree->log_mutex);
 
-	ret = update_log_root(trans, log);
-
 	mutex_lock(&log_root_tree->log_mutex);
 	if (atomic_dec_and_test(&log_root_tree->log_writers)) {
 		/*
@@ -2850,6 +2861,7 @@
 
 	if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) {
 		blk_finish_plug(&plug);
+		list_del_init(&root_log_ctx.list);
 		mutex_unlock(&log_root_tree->log_mutex);
 		ret = root_log_ctx.log_ret;
 		goto out;
@@ -2943,34 +2955,34 @@
 	mutex_unlock(&root->log_mutex);
 
 out_wake_log_root:
-	/*
-	 * We needn't get log_mutex here because we are sure all
-	 * the other tasks are blocked.
-	 */
+	mutex_lock(&log_root_tree->log_mutex);
 	btrfs_remove_all_log_ctxs(log_root_tree, index2, ret);
 
-	mutex_lock(&log_root_tree->log_mutex);
 	log_root_tree->log_transid_committed++;
 	atomic_set(&log_root_tree->log_commit[index2], 0);
 	mutex_unlock(&log_root_tree->log_mutex);
 
 	/*
-	 * The barrier before waitqueue_active is implied by mutex_unlock
+	 * The barrier before waitqueue_active is needed so all the updates
+	 * above are seen by the woken threads. It might not be necessary, but
+	 * proving that seems to be hard.
 	 */
+	smp_mb();
 	if (waitqueue_active(&log_root_tree->log_commit_wait[index2]))
 		wake_up(&log_root_tree->log_commit_wait[index2]);
 out:
-	/* See above. */
-	btrfs_remove_all_log_ctxs(root, index1, ret);
-
 	mutex_lock(&root->log_mutex);
+	btrfs_remove_all_log_ctxs(root, index1, ret);
 	root->log_transid_committed++;
 	atomic_set(&root->log_commit[index1], 0);
 	mutex_unlock(&root->log_mutex);
 
 	/*
-	 * The barrier before waitqueue_active is implied by mutex_unlock
+	 * The barrier before waitqueue_active is needed so all the updates
+	 * above are seen by the woken threads. It might not be necessary, but
+	 * proving that seems to be hard.
 	 */
+	smp_mb();
 	if (waitqueue_active(&root->log_commit_wait[index1]))
 		wake_up(&root->log_commit_wait[index1]);
 	return ret;
@@ -3155,11 +3167,13 @@
 	btrfs_free_path(path);
 out_unlock:
 	mutex_unlock(&BTRFS_I(dir)->log_mutex);
-	if (ret == -ENOSPC) {
+	if (err == -ENOSPC) {
 		btrfs_set_log_full_commit(root->fs_info, trans);
-		ret = 0;
-	} else if (ret < 0)
-		btrfs_abort_transaction(trans, root, ret);
+		err = 0;
+	} else if (err < 0 && err != -ENOENT) {
+		/* ENOENT can be returned if the entry hasn't been fsynced yet */
+		btrfs_abort_transaction(trans, root, err);
+	}
 
 	btrfs_end_log_trans(root);
 
@@ -3311,9 +3325,17 @@
 	}
 	btrfs_release_path(path);
 
-	/* find the first key from this transaction again */
+	/*
+	 * Find the first key from this transaction again.  See the note for
+	 * log_new_dir_dentries, if we're logging a directory recursively we
+	 * won't be holding its i_mutex, which means we can modify the directory
+	 * while we're logging it.  If we remove an entry between our first
+	 * search and this search we'll not find the key again and can just
+	 * bail.
+	 */
+search:
 	ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
-	if (WARN_ON(ret != 0))
+	if (ret != 0)
 		goto done;
 
 	/*
@@ -3331,6 +3353,13 @@
 
 			if (min_key.objectid != ino || min_key.type != key_type)
 				goto done;
+
+			if (need_resched()) {
+				btrfs_release_path(path);
+				cond_resched();
+				goto search;
+			}
+
 			ret = overwrite_item(trans, log, dst_path, src, i,
 					     &min_key);
 			if (ret) {
@@ -3376,8 +3405,11 @@
 		 * from this directory and from this transaction
 		 */
 		ret = btrfs_next_leaf(root, path);
-		if (ret == 1) {
-			last_offset = (u64)-1;
+		if (ret) {
+			if (ret == 1)
+				last_offset = (u64)-1;
+			else
+				err = ret;
 			goto done;
 		}
 		btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
@@ -3709,11 +3741,8 @@
 						log->fs_info->csum_root,
 						ds + cs, ds + cs + cl - 1,
 						&ordered_sums, 0);
-				if (ret) {
-					btrfs_release_path(dst_path);
-					kfree(ins_data);
-					return ret;
-				}
+				if (ret)
+					break;
 			}
 		}
 	}
@@ -3726,7 +3755,6 @@
 	 * we have to do this after the loop above to avoid changing the
 	 * log tree while trying to change the log tree.
 	 */
-	ret = 0;
 	while (!list_empty(&ordered_sums)) {
 		struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,
 						   struct btrfs_ordered_sum,
@@ -3828,6 +3856,7 @@
 			ASSERT(ret == 0);
 			src = src_path->nodes[0];
 			i = 0;
+			need_find_last_extent = true;
 		}
 
 		btrfs_item_key_to_cpu(src, &key, i);
@@ -4379,13 +4408,8 @@
 					struct btrfs_file_extent_item);
 
 		if (btrfs_file_extent_type(leaf, extent) ==
-		    BTRFS_FILE_EXTENT_INLINE) {
-			len = btrfs_file_extent_inline_len(leaf,
-							   path->slots[0],
-							   extent);
-			ASSERT(len == i_size);
+		    BTRFS_FILE_EXTENT_INLINE)
 			return 0;
-		}
 
 		len = btrfs_file_extent_num_bytes(leaf, extent);
 		/* Last extent goes beyond i_size, no need to log a hole. */
@@ -4406,6 +4430,127 @@
 	return ret;
 }
 
+/*
+ * When we are logging a new inode X, check if it doesn't have a reference that
+ * matches the reference from some other inode Y created in a past transaction
+ * and that was renamed in the current transaction. If we don't do this, then at
+ * log replay time we can lose inode Y (and all its files if it's a directory):
+ *
+ * mkdir /mnt/x
+ * echo "hello world" > /mnt/x/foobar
+ * sync
+ * mv /mnt/x /mnt/y
+ * mkdir /mnt/x                 # or touch /mnt/x
+ * xfs_io -c fsync /mnt/x
+ * <power fail>
+ * mount fs, trigger log replay
+ *
+ * After the log replay procedure, we would lose the first directory and all its
+ * files (file foobar).
+ * For the case where inode Y is not a directory we simply end up losing it:
+ *
+ * echo "123" > /mnt/foo
+ * sync
+ * mv /mnt/foo /mnt/bar
+ * echo "abc" > /mnt/foo
+ * xfs_io -c fsync /mnt/foo
+ * <power fail>
+ *
+ * We also need this for cases where a snapshot entry is replaced by some other
+ * entry (file or directory) otherwise we end up with an unreplayable log due to
+ * attempts to delete the snapshot entry (entry of type BTRFS_ROOT_ITEM_KEY) as
+ * if it were a regular entry:
+ *
+ * mkdir /mnt/x
+ * btrfs subvolume snapshot /mnt /mnt/x/snap
+ * btrfs subvolume delete /mnt/x/snap
+ * rmdir /mnt/x
+ * mkdir /mnt/x
+ * fsync /mnt/x or fsync some new file inside it
+ * <power fail>
+ *
+ * The snapshot delete, rmdir of x, mkdir of a new x and the fsync all happen in
+ * the same transaction.
+ */
+static int btrfs_check_ref_name_override(struct extent_buffer *eb,
+					 const int slot,
+					 const struct btrfs_key *key,
+					 struct inode *inode)
+{
+	int ret;
+	struct btrfs_path *search_path;
+	char *name = NULL;
+	u32 name_len = 0;
+	u32 item_size = btrfs_item_size_nr(eb, slot);
+	u32 cur_offset = 0;
+	unsigned long ptr = btrfs_item_ptr_offset(eb, slot);
+
+	search_path = btrfs_alloc_path();
+	if (!search_path)
+		return -ENOMEM;
+	search_path->search_commit_root = 1;
+	search_path->skip_locking = 1;
+
+	while (cur_offset < item_size) {
+		u64 parent;
+		u32 this_name_len;
+		u32 this_len;
+		unsigned long name_ptr;
+		struct btrfs_dir_item *di;
+
+		if (key->type == BTRFS_INODE_REF_KEY) {
+			struct btrfs_inode_ref *iref;
+
+			iref = (struct btrfs_inode_ref *)(ptr + cur_offset);
+			parent = key->offset;
+			this_name_len = btrfs_inode_ref_name_len(eb, iref);
+			name_ptr = (unsigned long)(iref + 1);
+			this_len = sizeof(*iref) + this_name_len;
+		} else {
+			struct btrfs_inode_extref *extref;
+
+			extref = (struct btrfs_inode_extref *)(ptr +
+							       cur_offset);
+			parent = btrfs_inode_extref_parent(eb, extref);
+			this_name_len = btrfs_inode_extref_name_len(eb, extref);
+			name_ptr = (unsigned long)&extref->name;
+			this_len = sizeof(*extref) + this_name_len;
+		}
+
+		if (this_name_len > name_len) {
+			char *new_name;
+
+			new_name = krealloc(name, this_name_len, GFP_NOFS);
+			if (!new_name) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			name_len = this_name_len;
+			name = new_name;
+		}
+
+		read_extent_buffer(eb, name, name_ptr, this_name_len);
+		di = btrfs_lookup_dir_item(NULL, BTRFS_I(inode)->root,
+					   search_path, parent,
+					   name, this_name_len, 0);
+		if (di && !IS_ERR(di)) {
+			ret = 1;
+			goto out;
+		} else if (IS_ERR(di)) {
+			ret = PTR_ERR(di);
+			goto out;
+		}
+		btrfs_release_path(search_path);
+
+		cur_offset += this_len;
+	}
+	ret = 0;
+out:
+	btrfs_free_path(search_path);
+	kfree(name);
+	return ret;
+}
+
 /* log a single inode in the tree log.
  * At least one parent directory for this inode must exist in the tree
  * or be logged already.
@@ -4445,6 +4590,7 @@
 	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 	u64 logged_isize = 0;
 	bool need_log_inode_item = true;
+	bool xattrs_logged = false;
 
 	path = btrfs_alloc_path();
 	if (!path)
@@ -4578,6 +4724,22 @@
 		if (min_key.type == BTRFS_INODE_ITEM_KEY)
 			need_log_inode_item = false;
 
+		if ((min_key.type == BTRFS_INODE_REF_KEY ||
+		     min_key.type == BTRFS_INODE_EXTREF_KEY) &&
+		    BTRFS_I(inode)->generation == trans->transid) {
+			ret = btrfs_check_ref_name_override(path->nodes[0],
+							    path->slots[0],
+							    &min_key, inode);
+			if (ret < 0) {
+				err = ret;
+				goto out_unlock;
+			} else if (ret > 0) {
+				err = 1;
+				btrfs_set_log_full_commit(root->fs_info, trans);
+				goto out_unlock;
+			}
+		}
+
 		/* Skip xattrs, we log them later with btrfs_log_all_xattrs() */
 		if (min_key.type == BTRFS_XATTR_ITEM_KEY) {
 			if (ins_nr == 0)
@@ -4669,6 +4831,7 @@
 	err = btrfs_log_all_xattrs(trans, root, inode, path, dst_path);
 	if (err)
 		goto out_unlock;
+	xattrs_logged = true;
 	if (max_key.type >= BTRFS_EXTENT_DATA_KEY && !fast_search) {
 		btrfs_release_path(path);
 		btrfs_release_path(dst_path);
@@ -4681,6 +4844,11 @@
 	btrfs_release_path(dst_path);
 	if (need_log_inode_item) {
 		err = log_inode_item(trans, log, dst_path, inode);
+		if (!err && !xattrs_logged) {
+			err = btrfs_log_all_xattrs(trans, root, inode, path,
+						   dst_path);
+			btrfs_release_path(path);
+		}
 		if (err)
 			goto out_unlock;
 	}
@@ -4964,7 +5132,7 @@
 			}
 
 			if (btrfs_inode_in_log(di_inode, trans->transid)) {
-				iput(di_inode);
+				btrfs_add_delayed_iput(di_inode);
 				continue;
 			}
 
@@ -4974,7 +5142,7 @@
 			btrfs_release_path(path);
 			ret = btrfs_log_inode(trans, root, di_inode,
 					      log_mode, 0, LLONG_MAX, ctx);
-			iput(di_inode);
+			btrfs_add_delayed_iput(di_inode);
 			if (ret)
 				goto next_dir_inode;
 			if (ctx->log_new_dentries) {
@@ -5082,13 +5250,37 @@
 
 			dir_inode = btrfs_iget(root->fs_info->sb, &inode_key,
 					       root, NULL);
-			/* If parent inode was deleted, skip it. */
-			if (IS_ERR(dir_inode))
-				continue;
+			/*
+			 * If the parent inode was deleted, return an error to
+			 * fallback to a transaction commit. This is to prevent
+			 * getting an inode that was moved from one parent A to
+			 * a parent B, got its former parent A deleted and then
+			 * it got fsync'ed, from existing at both parents after
+			 * a log replay (and the old parent still existing).
+			 * Example:
+			 *
+			 * mkdir /mnt/A
+			 * mkdir /mnt/B
+			 * touch /mnt/B/bar
+			 * sync
+			 * mv /mnt/B/bar /mnt/A/bar
+			 * mv -T /mnt/A /mnt/B
+			 * fsync /mnt/B/bar
+			 * <power fail>
+			 *
+			 * If we ignore the old parent B which got deleted,
+			 * after a log replay we would have file bar linked
+			 * at both parents and the old parent B would still
+			 * exist.
+			 */
+			if (IS_ERR(dir_inode)) {
+				ret = PTR_ERR(dir_inode);
+				goto out;
+			}
 
 			ret = btrfs_log_inode(trans, root, dir_inode,
 					      LOG_INODE_ALL, 0, LLONG_MAX, ctx);
-			iput(dir_inode);
+			btrfs_add_delayed_iput(dir_inode);
 			if (ret)
 				goto out;
 		}
@@ -5385,6 +5577,23 @@
 						      path);
 		}
 
+		if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) {
+			struct btrfs_root *root = wc.replay_dest;
+
+			btrfs_release_path(path);
+
+			/*
+			 * We have just replayed everything, and the highest
+			 * objectid of fs roots probably has changed in case
+			 * some inode_item's got replayed.
+			 *
+			 * root->objectid_mutex is not acquired as log replay
+			 * could only happen during mount.
+			 */
+			ret = btrfs_find_highest_objectid(root,
+						  &root->highest_objectid);
+		}
+
 		key.offset = found_key.offset - 1;
 		wc.replay_dest->log_root = NULL;
 		free_extent_buffer(log->node);
@@ -5489,6 +5698,21 @@
 	BTRFS_I(dir)->last_unlink_trans = trans->transid;
 }
 
+/*
+ * Make sure that if someone attempts to fsync the parent directory of a deleted
+ * snapshot, it ends up triggering a transaction commit. This is to guarantee
+ * that after replaying the log tree of the parent directory's root we will not
+ * see the snapshot anymore and at log replay time we will not see any log tree
+ * corresponding to the deleted snapshot's root, which could lead to replaying
+ * it after replaying the log tree of the parent directory (which would replay
+ * the snapshot delete operation).
+ */
+void btrfs_record_snapshot_destroy(struct btrfs_trans_handle *trans,
+				   struct inode *dir)
+{
+	BTRFS_I(dir)->last_unlink_trans = trans->transid;
+}
+
 /*
  * Call this after adding a new name for a file and it will properly
  * update the log to reflect the new name.
--- linux-4.4.0.orig/fs/btrfs/tree-log.h
+++ linux-4.4.0/fs/btrfs/tree-log.h
@@ -79,6 +79,8 @@
 void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
 			     struct inode *dir, struct inode *inode,
 			     int for_rename);
+void btrfs_record_snapshot_destroy(struct btrfs_trans_handle *trans,
+				   struct inode *dir);
 int btrfs_log_new_name(struct btrfs_trans_handle *trans,
 			struct inode *inode, struct inode *old_dir,
 			struct dentry *parent);
--- linux-4.4.0.orig/fs/btrfs/uuid-tree.c
+++ linux-4.4.0/fs/btrfs/uuid-tree.c
@@ -332,6 +332,8 @@
 				}
 				if (ret < 0 && ret != -ENOENT)
 					goto out;
+				key.offset++;
+				goto again_search_slot;
 			}
 			item_size -= sizeof(subid_le);
 			offset += sizeof(subid_le);
@@ -348,7 +350,5 @@
 
 out:
 	btrfs_free_path(path);
-	if (ret)
-		btrfs_warn(fs_info, "btrfs_uuid_tree_iterate failed %d", ret);
-	return 0;
+	return ret;
 }
--- linux-4.4.0.orig/fs/btrfs/volumes.c
+++ linux-4.4.0/fs/btrfs/volumes.c
@@ -108,7 +108,7 @@
 	},
 };
 
-const u64 const btrfs_raid_group[BTRFS_NR_RAID_TYPES] = {
+const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES] = {
 	[BTRFS_RAID_RAID10] = BTRFS_BLOCK_GROUP_RAID10,
 	[BTRFS_RAID_RAID1]  = BTRFS_BLOCK_GROUP_RAID1,
 	[BTRFS_RAID_DUP]    = BTRFS_BLOCK_GROUP_DUP,
@@ -232,6 +232,7 @@
 	spin_lock_init(&dev->reada_lock);
 	atomic_set(&dev->reada_in_flight, 0);
 	atomic_set(&dev->dev_stats_ccnt, 0);
+	btrfs_device_data_ordered_init(dev);
 	INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
 	INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
 
@@ -350,7 +351,7 @@
 	 */
 	blk_start_plug(&plug);
 
-	bdi = blk_get_backing_dev_info(device->bdev);
+	bdi = device->bdev->bd_bdi;
 	fs_info = device->dev_root->fs_info;
 	limit = btrfs_async_submit_limit(fs_info);
 	limit = limit * 2 / 3;
@@ -567,6 +568,7 @@
 				btrfs_sysfs_remove_fsid(fs_devs);
 				list_del(&fs_devs->list);
 				free_fs_devices(fs_devs);
+				break;
 			} else {
 				fs_devs->num_devices--;
 				list_del(&dev->dev_list);
@@ -606,8 +608,8 @@
 
 		device = NULL;
 	} else {
-		device = __find_device(&fs_devices->devices, devid,
-				       disk_super->dev_item.uuid);
+		device = btrfs_find_device(fs_devices, devid,
+				disk_super->dev_item.uuid, NULL, false);
 	}
 
 	if (!device) {
@@ -806,7 +808,7 @@
 		goto again;
 	}
 
-	fs_devices->latest_bdev = latest_dev->bdev;
+	fs_devices->latest_dev = latest_dev;
 
 	mutex_unlock(&uuid_mutex);
 }
@@ -963,7 +965,7 @@
 	}
 	fs_devices->seeding = seeding;
 	fs_devices->opened = 1;
-	fs_devices->latest_bdev = latest_dev->bdev;
+	fs_devices->latest_dev = latest_dev;
 	fs_devices->total_rw_bytes = 0;
 out:
 	return ret;
@@ -1182,7 +1184,7 @@
 		struct map_lookup *map;
 		int i;
 
-		map = (struct map_lookup *)em->bdev;
+		map = em->map_lookup;
 		for (i = 0; i < map->num_stripes; i++) {
 			u64 end;
 
@@ -1257,6 +1259,15 @@
 	int ret;
 	int slot;
 	struct extent_buffer *l;
+	u64 min_search_start;
+
+	/*
+	 * We don't want to overwrite the superblock on the drive nor any area
+	 * used by the boot loader (grub for example), so we make sure to start
+	 * at an offset of at least 1MB.
+	 */
+	min_search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
+	search_start = max(search_start, min_search_start);
 
 	path = btrfs_alloc_path();
 	if (!path)
@@ -1397,18 +1408,9 @@
 			 struct btrfs_device *device, u64 num_bytes,
 			 u64 *start, u64 *len)
 {
-	struct btrfs_root *root = device->dev_root;
-	u64 search_start;
-
 	/* FIXME use last free of some kind */
-
-	/*
-	 * we don't want to overwrite the superblock on the drive,
-	 * so we make sure to start at an offset of at least 1MB
-	 */
-	search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
 	return find_free_dev_extent_start(trans->transaction, device,
-					  num_bytes, search_start, start, len);
+					  num_bytes, 0, start, len);
 }
 
 static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
@@ -1776,8 +1778,8 @@
 		disk_super = (struct btrfs_super_block *)bh->b_data;
 		devid = btrfs_stack_device_id(&disk_super->dev_item);
 		dev_uuid = disk_super->dev_item.uuid;
-		device = btrfs_find_device(root->fs_info, devid, dev_uuid,
-					   disk_super->fsid);
+		device = btrfs_find_device(root->fs_info->fs_devices, devid, dev_uuid,
+					   disk_super->fsid, true);
 		if (!device) {
 			ret = -ENOENT;
 			goto error_brelse;
@@ -1844,8 +1846,8 @@
 				 struct btrfs_device, dev_list);
 	if (device->bdev == root->fs_info->sb->s_bdev)
 		root->fs_info->sb->s_bdev = next_device->bdev;
-	if (device->bdev == root->fs_info->fs_devices->latest_bdev)
-		root->fs_info->fs_devices->latest_bdev = next_device->bdev;
+	if (device->bdev == root->fs_info->fs_devices->latest_dev->bdev)
+		root->fs_info->fs_devices->latest_dev->bdev = next_device->bdev;
 
 	if (device->bdev) {
 		device->fs_devices->open_devices--;
@@ -2032,8 +2034,8 @@
 				 struct btrfs_device, dev_list);
 	if (tgtdev->bdev == fs_info->sb->s_bdev)
 		fs_info->sb->s_bdev = next_device->bdev;
-	if (tgtdev->bdev == fs_info->fs_devices->latest_bdev)
-		fs_info->fs_devices->latest_bdev = next_device->bdev;
+	if (tgtdev->bdev == fs_info->fs_devices->latest_dev->bdev)
+		fs_info->fs_devices->latest_dev->bdev = next_device->bdev;
 	list_del_rcu(&tgtdev->dev_list);
 
 	call_rcu(&tgtdev->rcu, free_device);
@@ -2060,8 +2062,8 @@
 	disk_super = (struct btrfs_super_block *)bh->b_data;
 	devid = btrfs_stack_device_id(&disk_super->dev_item);
 	dev_uuid = disk_super->dev_item.uuid;
-	*device = btrfs_find_device(root->fs_info, devid, dev_uuid,
-				    disk_super->fsid);
+	*device = btrfs_find_device(root->fs_info->fs_devices, devid, dev_uuid,
+			disk_super->fsid, true);
 	brelse(bh);
 	if (!*device)
 		ret = -ENOENT;
@@ -2217,9 +2219,9 @@
 		read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
 				   BTRFS_UUID_SIZE);
 		read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
-				   BTRFS_UUID_SIZE);
-		device = btrfs_find_device(root->fs_info, devid, dev_uuid,
-					   fs_uuid);
+				   BTRFS_FSID_SIZE);
+		device = btrfs_find_device(root->fs_info->fs_devices, devid, dev_uuid,
+					   fs_uuid, true);
 		BUG_ON(!device); /* Logic error */
 
 		if (device->fs_devices->seeding) {
@@ -2355,9 +2357,6 @@
 	btrfs_set_super_num_devices(root->fs_info->super_copy,
 				    tmp + 1);
 
-	/* add sysfs device entry */
-	btrfs_sysfs_add_device_link(root->fs_info->fs_devices, device);
-
 	/*
 	 * we've got more storage, clear any full flags on the space
 	 * infos
@@ -2365,6 +2364,10 @@
 	btrfs_clear_space_info_full(root->fs_info);
 
 	unlock_chunks(root);
+
+	/* add sysfs device entry */
+	btrfs_sysfs_add_device_link(root->fs_info->fs_devices, device);
+
 	mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
 	if (seeding_dev) {
@@ -2755,7 +2758,7 @@
 			free_extent_map(em);
 		return -EINVAL;
 	}
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	lock_chunks(root->fs_info->chunk_root);
 	check_system_chunk(trans, extent_root, map->type);
 	unlock_chunks(root->fs_info->chunk_root);
@@ -3848,6 +3851,15 @@
 		return 0;
 	}
 
+	/*
+	 * A ro->rw remount sequence should continue with the paused balance
+	 * regardless of who pauses it, system or the user as of now, so set
+	 * the resume flag.
+	 */
+	spin_lock(&fs_info->balance_lock);
+	fs_info->balance_ctl->flags |= BTRFS_BALANCE_RESUME;
+	spin_unlock(&fs_info->balance_lock);
+
 	tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance");
 	return PTR_ERR_OR_ZERO(tsk);
 }
@@ -4054,6 +4066,7 @@
 			goto skip;
 		}
 update_tree:
+		btrfs_release_path(path);
 		if (!btrfs_is_empty_uuid(root_item.uuid)) {
 			ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root,
 						  root_item.uuid,
@@ -4079,6 +4092,7 @@
 		}
 
 skip:
+		btrfs_release_path(path);
 		if (trans) {
 			ret = btrfs_end_transaction(trans, fs_info->uuid_root);
 			trans = NULL;
@@ -4086,7 +4100,6 @@
 				break;
 		}
 
-		btrfs_release_path(path);
 		if (key.offset < (u64)-1) {
 			key.offset++;
 		} else if (key.type < BTRFS_ROOT_ITEM_KEY) {
@@ -4529,7 +4542,7 @@
 
 	if (type & BTRFS_BLOCK_GROUP_DATA) {
 		max_stripe_size = 1024 * 1024 * 1024;
-		max_chunk_size = 10 * max_stripe_size;
+		max_chunk_size = BTRFS_MAX_DATA_CHUNK_SIZE;
 		if (!devs_max)
 			devs_max = BTRFS_MAX_DEVS(info->chunk_root);
 	} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
@@ -4637,10 +4650,13 @@
 	if (devs_max && ndevs > devs_max)
 		ndevs = devs_max;
 	/*
-	 * the primary goal is to maximize the number of stripes, so use as many
-	 * devices as possible, even if the stripes are not maximum sized.
+	 * The primary goal is to maximize the number of stripes, so use as
+	 * many devices as possible, even if the stripes are not maximum sized.
+	 *
+	 * The DUP profile stores more than one stripe per device, the
+	 * max_avail is the total size so we have to adjust.
 	 */
-	stripe_size = devices_info[ndevs-1].max_avail;
+	stripe_size = div_u64(devices_info[ndevs - 1].max_avail, dev_stripes);
 	num_stripes = ndevs * dev_stripes;
 
 	/*
@@ -4680,8 +4696,6 @@
 			stripe_size = devices_info[ndevs-1].max_avail;
 	}
 
-	stripe_size = div_u64(stripe_size, dev_stripes);
-
 	/* align to BTRFS_STRIPE_LEN */
 	stripe_size = div_u64(stripe_size, raid_stripe_len);
 	stripe_size *= raid_stripe_len;
@@ -4719,7 +4733,7 @@
 		goto error;
 	}
 	set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags);
-	em->bdev = (struct block_device *)map;
+	em->map_lookup = map;
 	em->start = start;
 	em->len = num_bytes;
 	em->block_start = 0;
@@ -4748,6 +4762,7 @@
 	for (i = 0; i < map->num_stripes; i++) {
 		num_bytes = map->stripes[i].dev->bytes_used + stripe_size;
 		btrfs_device_set_bytes_used(map->stripes[i].dev, num_bytes);
+		map->stripes[i].dev->has_pending_chunks = true;
 	}
 
 	spin_lock(&extent_root->fs_info->free_chunk_lock);
@@ -4814,7 +4829,7 @@
 		return -EINVAL;
 	}
 
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	item_size = btrfs_chunk_item_size(map->num_stripes);
 	stripe_size = em->orig_block_len;
 
@@ -4929,8 +4944,7 @@
 
 	if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
 			 BTRFS_BLOCK_GROUP_RAID10 |
-			 BTRFS_BLOCK_GROUP_RAID5 |
-			 BTRFS_BLOCK_GROUP_DUP)) {
+			 BTRFS_BLOCK_GROUP_RAID5)) {
 		max_errors = 1;
 	} else if (map->type & BTRFS_BLOCK_GROUP_RAID6) {
 		max_errors = 2;
@@ -4956,7 +4970,7 @@
 	if (!em)
 		return 1;
 
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	for (i = 0; i < map->num_stripes; i++) {
 		if (map->stripes[i].dev->missing) {
 			miss_ndevs++;
@@ -5036,7 +5050,7 @@
 		return 1;
 	}
 
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
 		ret = map->num_stripes;
 	else if (map->type & BTRFS_BLOCK_GROUP_RAID10)
@@ -5044,7 +5058,14 @@
 	else if (map->type & BTRFS_BLOCK_GROUP_RAID5)
 		ret = 2;
 	else if (map->type & BTRFS_BLOCK_GROUP_RAID6)
-		ret = 3;
+		/*
+		 * There could be two corrupted data stripes, we need
+		 * to loop retry in order to rebuild the correct data.
+		 *
+		 * Fail a stripe at a time on every retry except the
+		 * stripe under reconstruction.
+		 */
+		ret = map->num_stripes;
 	else
 		ret = 1;
 	free_extent_map(em);
@@ -5072,7 +5093,7 @@
 	BUG_ON(!em);
 
 	BUG_ON(em->start > logical || em->start + em->len < logical);
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
 		len = map->stripe_len * nr_data_stripes(map);
 	free_extent_map(em);
@@ -5093,7 +5114,7 @@
 	BUG_ON(!em);
 
 	BUG_ON(em->start > logical || em->start + em->len < logical);
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
 		ret = 1;
 	free_extent_map(em);
@@ -5252,7 +5273,7 @@
 		return -EINVAL;
 	}
 
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 	offset = logical - em->start;
 
 	stripe_len = map->stripe_len;
@@ -5794,7 +5815,7 @@
 		free_extent_map(em);
 		return -EIO;
 	}
-	map = (struct map_lookup *)em->bdev;
+	map = em->map_lookup;
 
 	length = em->len;
 	rmap_len = map->stripe_len;
@@ -6098,22 +6119,36 @@
 	return 0;
 }
 
-struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
-				       u8 *uuid, u8 *fsid)
+/*
+ * Find a device specified by @devid or @uuid in the list of @fs_devices, or
+ * return NULL.
+ *
+ * If devid and uuid are both specified, the match must be exact, otherwise
+ * only devid is used.
+ *
+ * If @seed is true, traverse through the seed devices.
+ */
+struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
+				       u64 devid, u8 *uuid, u8 *fsid,
+				       bool seed)
 {
 	struct btrfs_device *device;
-	struct btrfs_fs_devices *cur_devices;
 
-	cur_devices = fs_info->fs_devices;
-	while (cur_devices) {
+	while (fs_devices) {
 		if (!fsid ||
-		    !memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
-			device = __find_device(&cur_devices->devices,
-					       devid, uuid);
-			if (device)
-				return device;
+		    !memcmp(fs_devices->fsid, fsid, BTRFS_FSID_SIZE)) {
+			list_for_each_entry(device, &fs_devices->devices,
+					    dev_list) {
+				if (device->devid == devid &&
+				    (!uuid || memcmp(device->uuid, uuid,
+						     BTRFS_UUID_SIZE) == 0))
+					return device;
+			}
 		}
-		cur_devices = cur_devices->seed;
+		if (seed)
+			fs_devices = fs_devices->seed;
+		else
+			return NULL;
 	}
 	return NULL;
 }
@@ -6189,6 +6224,108 @@
 	return dev;
 }
 
+/* Return -EIO if any error, otherwise return 0. */
+static int btrfs_check_chunk_valid(struct btrfs_root *root,
+				   struct extent_buffer *leaf,
+				   struct btrfs_chunk *chunk, u64 logical)
+{
+	u64 length;
+	u64 stripe_len;
+	u16 num_stripes;
+	u16 sub_stripes;
+	u64 type;
+	u64 features;
+	bool mixed = false;
+
+	length = btrfs_chunk_length(leaf, chunk);
+	stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
+	num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+	sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
+	type = btrfs_chunk_type(leaf, chunk);
+
+	if (!num_stripes) {
+		btrfs_err(root->fs_info, "invalid chunk num_stripes: %u",
+			  num_stripes);
+		return -EIO;
+	}
+	if (!IS_ALIGNED(logical, root->sectorsize)) {
+		btrfs_err(root->fs_info,
+			  "invalid chunk logical %llu", logical);
+		return -EIO;
+	}
+	if (btrfs_chunk_sector_size(leaf, chunk) != root->sectorsize) {
+		btrfs_err(root->fs_info, "invalid chunk sectorsize %u",
+			  btrfs_chunk_sector_size(leaf, chunk));
+		return -EIO;
+	}
+	if (!length || !IS_ALIGNED(length, root->sectorsize)) {
+		btrfs_err(root->fs_info,
+			"invalid chunk length %llu", length);
+		return -EIO;
+	}
+	if (!is_power_of_2(stripe_len)) {
+		btrfs_err(root->fs_info, "invalid chunk stripe length: %llu",
+			  stripe_len);
+		return -EIO;
+	}
+	if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) &
+	    type) {
+		btrfs_err(root->fs_info, "unrecognized chunk type: %llu",
+			  ~(BTRFS_BLOCK_GROUP_TYPE_MASK |
+			    BTRFS_BLOCK_GROUP_PROFILE_MASK) &
+			  btrfs_chunk_type(leaf, chunk));
+		return -EIO;
+	}
+
+	if (!is_power_of_2(type & BTRFS_BLOCK_GROUP_PROFILE_MASK) &&
+	    (type & BTRFS_BLOCK_GROUP_PROFILE_MASK) != 0) {
+		btrfs_err(root->fs_info,
+		"invalid chunk profile flag: 0x%llx, expect 0 or 1 bit set",
+			  type & BTRFS_BLOCK_GROUP_PROFILE_MASK);
+		return -EUCLEAN;
+	}
+	if ((type & BTRFS_BLOCK_GROUP_TYPE_MASK) == 0) {
+		btrfs_err(root->fs_info, "missing chunk type flag: 0x%llx", type);
+		return -EIO;
+	}
+
+	if ((type & BTRFS_BLOCK_GROUP_SYSTEM) &&
+	    (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA))) {
+		btrfs_err(root->fs_info,
+			"system chunk with data or metadata type: 0x%llx", type);
+		return -EIO;
+	}
+
+	features = btrfs_super_incompat_flags(root->fs_info->super_copy);
+	if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
+		mixed = true;
+
+	if (!mixed) {
+		if ((type & BTRFS_BLOCK_GROUP_METADATA) &&
+		    (type & BTRFS_BLOCK_GROUP_DATA)) {
+			btrfs_err(root->fs_info,
+			"mixed chunk type in non-mixed mode: 0x%llx", type);
+			return -EIO;
+		}
+	}
+
+	if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) ||
+	    (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes != 2) ||
+	    (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) ||
+	    (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) ||
+	    (type & BTRFS_BLOCK_GROUP_DUP && num_stripes != 2) ||
+	    ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 &&
+	     num_stripes != 1)) {
+		btrfs_err(root->fs_info,
+			"invalid num_stripes:sub_stripes %u:%u for profile %llu",
+			num_stripes, sub_stripes,
+			type & BTRFS_BLOCK_GROUP_PROFILE_MASK);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
 			  struct extent_buffer *leaf,
 			  struct btrfs_chunk *chunk)
@@ -6198,6 +6335,7 @@
 	struct extent_map *em;
 	u64 logical;
 	u64 length;
+	u64 stripe_len;
 	u64 devid;
 	u8 uuid[BTRFS_UUID_SIZE];
 	int num_stripes;
@@ -6206,6 +6344,12 @@
 
 	logical = key->offset;
 	length = btrfs_chunk_length(leaf, chunk);
+	stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
+	num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+
+	ret = btrfs_check_chunk_valid(root, leaf, chunk, logical);
+	if (ret)
+		return ret;
 
 	read_lock(&map_tree->map_tree.lock);
 	em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
@@ -6222,7 +6366,6 @@
 	em = alloc_extent_map();
 	if (!em)
 		return -ENOMEM;
-	num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
 	map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
 	if (!map) {
 		free_extent_map(em);
@@ -6230,7 +6373,7 @@
 	}
 
 	set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags);
-	em->bdev = (struct block_device *)map;
+	em->map_lookup = map;
 	em->start = logical;
 	em->len = length;
 	em->orig_start = 0;
@@ -6251,8 +6394,8 @@
 		read_extent_buffer(leaf, uuid, (unsigned long)
 				   btrfs_stripe_dev_uuid_nr(chunk, i),
 				   BTRFS_UUID_SIZE);
-		map->stripes[i].dev = btrfs_find_device(root->fs_info, devid,
-							uuid, NULL);
+		map->stripes[i].dev = btrfs_find_device(root->fs_info->fs_devices,
+							devid, uuid, NULL, true);
 		if (!map->stripes[i].dev && !btrfs_test_opt(root, DEGRADED)) {
 			free_extent_map(em);
 			return -EIO;
@@ -6381,7 +6524,7 @@
 			return PTR_ERR(fs_devices);
 	}
 
-	device = btrfs_find_device(root->fs_info, devid, dev_uuid, fs_uuid);
+	device = btrfs_find_device(fs_devices, devid, dev_uuid, fs_uuid, true);
 	if (!device) {
 		if (!btrfs_test_opt(root, DEGRADED))
 			return -EIO;
@@ -6454,6 +6597,7 @@
 	u32 array_size;
 	u32 len = 0;
 	u32 cur_offset;
+	u64 type;
 	struct btrfs_key key;
 
 	ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize);
@@ -6512,6 +6656,23 @@
 				goto out_short_read;
 
 			num_stripes = btrfs_chunk_num_stripes(sb, chunk);
+			if (!num_stripes) {
+				printk(KERN_ERR
+	    "BTRFS: invalid number of stripes %u in sys_array at offset %u\n",
+					num_stripes, cur_offset);
+				ret = -EIO;
+				break;
+			}
+
+			type = btrfs_chunk_type(sb, chunk);
+			if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) {
+				btrfs_err(root->fs_info,
+			    "invalid chunk type %llu in sys_array at offset %u",
+					type, cur_offset);
+				ret = -EIO;
+				break;
+			}
+
 			len = btrfs_chunk_item_size(num_stripes);
 			if (cur_offset + len > array_size)
 				goto out_short_read;
@@ -6556,6 +6717,14 @@
 	lock_chunks(root);
 
 	/*
+	 * It is possible for mount and umount to race in such a way that
+	 * we execute this code path, but open_fs_devices failed to clear
+	 * total_rw_bytes. We certainly want it cleared before reading the
+	 * device items, so clear it here.
+	 */
+	root->fs_info->fs_devices->total_rw_bytes = 0;
+
+	/*
 	 * Read all device items, and then all the chunk items. All
 	 * device items are found before any chunk item (their object id
 	 * is smaller than the lowest possible object id for a chunk
@@ -6826,7 +6995,7 @@
 	int i;
 
 	mutex_lock(&fs_devices->device_list_mutex);
-	dev = btrfs_find_device(root->fs_info, stats->devid, NULL, NULL);
+	dev = btrfs_find_device(fs_devices, stats->devid, NULL, NULL, true);
 	mutex_unlock(&fs_devices->device_list_mutex);
 
 	if (!dev) {
@@ -6921,11 +7090,12 @@
 	/* In order to kick the device replace finish process */
 	lock_chunks(root);
 	list_for_each_entry(em, &transaction->pending_chunks, list) {
-		map = (struct map_lookup *)em->bdev;
+		map = em->map_lookup;
 
 		for (i = 0; i < map->num_stripes; i++) {
 			dev = map->stripes[i].dev;
 			dev->commit_bytes_used = dev->bytes_used;
+			dev->has_pending_chunks = false;
 		}
 	}
 	unlock_chunks(root);
--- linux-4.4.0.orig/fs/btrfs/volumes.h
+++ linux-4.4.0/fs/btrfs/volumes.h
@@ -24,6 +24,8 @@
 #include <linux/btrfs.h>
 #include "async-thread.h"
 
+#define BTRFS_MAX_DATA_CHUNK_SIZE	(10ULL * SZ_1G)
+
 extern struct mutex uuid_mutex;
 
 #define BTRFS_STRIPE_LEN	(64 * 1024)
@@ -60,6 +62,11 @@
 
 	spinlock_t io_lock ____cacheline_aligned;
 	int running_pending;
+	/* When true means this device has pending chunk alloc in
+	 * current transaction. Protected by chunk_mutex.
+	 */
+	bool has_pending_chunks;
+
 	/* regular prio bios */
 	struct btrfs_pending_bios pending_bios;
 	/* WRITE_SYNC bios */
@@ -228,7 +235,11 @@
 	u64 missing_devices;
 	u64 total_rw_bytes;
 	u64 total_devices;
-	struct block_device *latest_bdev;
+	/*
+	 * The mount device or a device with highest generation after removal
+	 * or replace.
+	 */
+	struct btrfs_device *latest_dev;
 
 	/* all of the devices in the FS, protected by a mutex
 	 * so we can safely walk it to write out the supers without
@@ -305,7 +316,6 @@
 	u64 map_type; /* get from map_lookup->type */
 	bio_end_io_t *end_io;
 	struct bio *orig_bio;
-	unsigned long flags;
 	void *private;
 	atomic_t error;
 	int max_errors;
@@ -456,8 +466,8 @@
 int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
 int btrfs_grow_device(struct btrfs_trans_handle *trans,
 		      struct btrfs_device *device, u64 new_size);
-struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
-				       u8 *uuid, u8 *fsid);
+struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
+				       u64 devid, u8 *uuid, u8 *fsid, bool seed);
 int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
 int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
--- linux-4.4.0.orig/fs/buffer.c
+++ linux-4.4.0/fs/buffer.c
@@ -2298,7 +2298,7 @@
 			    loff_t pos, loff_t *bytes)
 {
 	struct inode *inode = mapping->host;
-	unsigned blocksize = 1 << inode->i_blkbits;
+	unsigned int blocksize = i_blocksize(inode);
 	struct page *page;
 	void *fsdata;
 	pgoff_t index, curidx;
@@ -2378,8 +2378,8 @@
 			get_block_t *get_block, loff_t *bytes)
 {
 	struct inode *inode = mapping->host;
-	unsigned blocksize = 1 << inode->i_blkbits;
-	unsigned zerofrom;
+	unsigned int blocksize = i_blocksize(inode);
+	unsigned int zerofrom;
 	int err;
 
 	err = cont_expand_zero(file, mapping, pos, bytes);
@@ -2741,7 +2741,7 @@
 	struct buffer_head map_bh;
 	int err;
 
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 	length = offset & (blocksize - 1);
 
 	/* Block boundary? Nothing to do */
@@ -2819,7 +2819,7 @@
 	struct buffer_head *bh;
 	int err;
 
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 	length = offset & (blocksize - 1);
 
 	/* Block boundary? Nothing to do */
@@ -2931,7 +2931,7 @@
 	struct inode *inode = mapping->host;
 	tmp.b_state = 0;
 	tmp.b_blocknr = 0;
-	tmp.b_size = 1 << inode->i_blkbits;
+	tmp.b_size = i_blocksize(inode);
 	get_block(inode, block, &tmp, 0);
 	return tmp.b_blocknr;
 }
@@ -2985,6 +2985,13 @@
 	/* Uhhuh. We've got a bio that straddles the device size! */
 	truncated_bytes = bio->bi_iter.bi_size - (maxsector << 9);
 
+	/*
+	 * The bio contains more than one segment which spans EOD, just return
+	 * and let IO layer turn it into an EIO
+	 */
+	if (truncated_bytes > bvec->bv_len)
+		return;
+
 	/* Truncate the bio.. */
 	bio->bi_iter.bi_size -= truncated_bytes;
 	bvec->bv_len -= truncated_bytes;
--- linux-4.4.0.orig/fs/cachefiles/bind.c
+++ linux-4.4.0/fs/cachefiles/bind.c
@@ -218,7 +218,8 @@
 			   "%s",
 			   fsdef->dentry->d_sb->s_id);
 
-	fscache_object_init(&fsdef->fscache, NULL, &cache->cache);
+	fscache_object_init(&fsdef->fscache, &fscache_fsdef_index,
+			    &cache->cache);
 
 	ret = fscache_add_cache(&cache->cache, &fsdef->fscache, cache->tag);
 	if (ret < 0)
@@ -248,6 +249,8 @@
 	kmem_cache_free(cachefiles_object_jar, fsdef);
 error_root_object:
 	cachefiles_end_secure(cache, saved_cred);
+	put_cred(cache->cache_cred);
+	cache->cache_cred = NULL;
 	pr_err("Failed to register: %d\n", ret);
 	return ret;
 }
@@ -268,6 +271,7 @@
 
 	dput(cache->graveyard);
 	mntput(cache->mnt);
+	put_cred(cache->cache_cred);
 
 	kfree(cache->rootdirname);
 	kfree(cache->secctx);
--- linux-4.4.0.orig/fs/cachefiles/namei.c
+++ linux-4.4.0/fs/cachefiles/namei.c
@@ -190,11 +190,12 @@
 	/* an old object from a previous incarnation is hogging the slot - we
 	 * need to wait for it to be destroyed */
 wait_for_old_object:
+	clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
+
 	if (fscache_object_is_live(&xobject->fscache)) {
 		pr_err("\n");
 		pr_err("Error: Unexpected object collision\n");
 		cachefiles_printk_object(object, xobject);
-		BUG();
 	}
 	atomic_inc(&xobject->usage);
 	write_unlock(&cache->active_lock);
@@ -251,7 +252,6 @@
 	goto try_again;
 
 requeue:
-	clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
 	cache->cache.ops->put_object(&xobject->fscache);
 	_leave(" = -ETIMEDOUT");
 	return -ETIMEDOUT;
@@ -318,7 +318,7 @@
 	trap = lock_rename(cache->graveyard, dir);
 
 	/* do some checks before getting the grave dentry */
-	if (rep->d_parent != dir) {
+	if (rep->d_parent != dir || IS_DEADDIR(d_inode(rep))) {
 		/* the entry was probably culled when we dropped the parent dir
 		 * lock */
 		unlock_rename(cache->graveyard, dir);
--- linux-4.4.0.orig/fs/cachefiles/rdwr.c
+++ linux-4.4.0/fs/cachefiles/rdwr.c
@@ -27,6 +27,7 @@
 	struct cachefiles_one_read *monitor =
 		container_of(wait, struct cachefiles_one_read, monitor);
 	struct cachefiles_object *object;
+	struct fscache_retrieval *op = monitor->op;
 	struct wait_bit_key *key = _key;
 	struct page *page = wait->private;
 
@@ -51,16 +52,22 @@
 	list_del(&wait->task_list);
 
 	/* move onto the action list and queue for FS-Cache thread pool */
-	ASSERT(monitor->op);
+	ASSERT(op);
 
-	object = container_of(monitor->op->op.object,
-			      struct cachefiles_object, fscache);
+	/* We need to temporarily bump the usage count as we don't own a ref
+	 * here otherwise cachefiles_read_copier() may free the op between the
+	 * monitor being enqueued on the op->to_do list and the op getting
+	 * enqueued on the work queue.
+	 */
+	fscache_get_retrieval(op);
 
+	object = container_of(op->op.object, struct cachefiles_object, fscache);
 	spin_lock(&object->work_lock);
-	list_add_tail(&monitor->op_link, &monitor->op->to_do);
+	list_add_tail(&monitor->op_link, &op->to_do);
+	fscache_enqueue_retrieval(op);
 	spin_unlock(&object->work_lock);
 
-	fscache_enqueue_retrieval(monitor->op);
+	fscache_put_retrieval(op);
 	return 0;
 }
 
@@ -118,7 +125,7 @@
 		_debug("reissue read");
 		ret = bmapping->a_ops->readpage(NULL, backpage);
 		if (ret < 0)
-			goto unlock_discard;
+			goto discard;
 	}
 
 	/* but the page may have been read before the monitor was installed, so
@@ -135,6 +142,7 @@
 
 unlock_discard:
 	unlock_page(backpage);
+discard:
 	spin_lock_irq(&object->work_lock);
 	list_del(&monitor->op_link);
 	spin_unlock_irq(&object->work_lock);
@@ -506,6 +514,8 @@
 				goto installed_new_backing_page;
 			if (ret != -EEXIST)
 				goto nomem;
+			page_cache_release(newpage);
+			newpage = NULL;
 		}
 
 		/* we've installed a new backing page, so now we need
@@ -530,7 +540,10 @@
 					    netpage->index, cachefiles_gfp);
 		if (ret < 0) {
 			if (ret == -EEXIST) {
+				page_cache_release(backpage);
+				backpage = NULL;
 				page_cache_release(netpage);
+				netpage = NULL;
 				fscache_retrieval_complete(op, 1);
 				continue;
 			}
@@ -603,7 +616,10 @@
 					    netpage->index, cachefiles_gfp);
 		if (ret < 0) {
 			if (ret == -EEXIST) {
+				page_cache_release(backpage);
+				backpage = NULL;
 				page_cache_release(netpage);
+				netpage = NULL;
 				fscache_retrieval_complete(op, 1);
 				continue;
 			}
@@ -956,11 +972,8 @@
 void cachefiles_uncache_page(struct fscache_object *_object, struct page *page)
 {
 	struct cachefiles_object *object;
-	struct cachefiles_cache *cache;
 
 	object = container_of(_object, struct cachefiles_object, fscache);
-	cache = container_of(object->fscache.cache,
-			     struct cachefiles_cache, cache);
 
 	_enter("%p,{%lu}", object, page->index);
 
--- linux-4.4.0.orig/fs/ceph/acl.c
+++ linux-4.4.0/fs/ceph/acl.c
@@ -94,11 +94,9 @@
 	case ACL_TYPE_ACCESS:
 		name = POSIX_ACL_XATTR_ACCESS;
 		if (acl) {
-			ret = posix_acl_equiv_mode(acl, &new_mode);
-			if (ret < 0)
+			ret = posix_acl_update_mode(inode, &new_mode, &acl);
+			if (ret)
 				goto out;
-			if (ret == 0)
-				acl = NULL;
 		}
 		break;
 	case ACL_TYPE_DEFAULT:
@@ -130,7 +128,7 @@
 	if (new_mode != old_mode) {
 		newattrs.ia_mode = new_mode;
 		newattrs.ia_valid = ATTR_MODE;
-		ret = ceph_setattr(dentry, &newattrs);
+		ret = __ceph_setattr(dentry, &newattrs);
 		if (ret)
 			goto out_dput;
 	}
@@ -140,7 +138,7 @@
 		if (new_mode != old_mode) {
 			newattrs.ia_mode = old_mode;
 			newattrs.ia_valid = ATTR_MODE;
-			ceph_setattr(dentry, &newattrs);
+			__ceph_setattr(dentry, &newattrs);
 		}
 		goto out_dput;
 	}
--- linux-4.4.0.orig/fs/ceph/addr.c
+++ linux-4.4.0/fs/ceph/addr.c
@@ -89,7 +89,6 @@
 
 	/* dirty the head */
 	spin_lock(&ci->i_ceph_lock);
-	BUG_ON(ci->i_wr_ref == 0); // caller should hold Fw reference
 	if (__ceph_have_pending_cap_snap(ci)) {
 		struct ceph_cap_snap *capsnap =
 				list_last_entry(&ci->i_cap_snaps,
@@ -189,7 +188,7 @@
 /*
  * read a single page, without unlocking it.
  */
-static int readpage_nounlock(struct file *filp, struct page *page)
+static int ceph_do_readpage(struct file *filp, struct page *page)
 {
 	struct inode *inode = file_inode(filp);
 	struct ceph_inode_info *ci = ceph_inode(inode);
@@ -219,7 +218,7 @@
 
 	err = ceph_readpage_from_fscache(inode, page);
 	if (err == 0)
-		goto out;
+		return -EINPROGRESS;
 
 	dout("readpage inode %p file %p page %p index %lu\n",
 	     inode, filp, page, page->index);
@@ -249,8 +248,11 @@
 
 static int ceph_readpage(struct file *filp, struct page *page)
 {
-	int r = readpage_nounlock(filp, page);
-	unlock_page(page);
+	int r = ceph_do_readpage(filp, page);
+	if (r != -EINPROGRESS)
+		unlock_page(page);
+	else
+		r = 0;
 	return r;
 }
 
@@ -697,7 +699,7 @@
 	struct pagevec pvec;
 	int done = 0;
 	int rc = 0;
-	unsigned wsize = 1 << inode->i_blkbits;
+	unsigned int wsize = i_blocksize(inode);
 	struct ceph_osd_request *req = NULL;
 	int do_sync = 0;
 	loff_t snap_size, i_size;
@@ -1094,7 +1096,7 @@
 			goto retry_locked;
 		r = writepage_nounlock(page, NULL);
 		if (r < 0)
-			goto fail_nosnap;
+			goto fail_unlock;
 		goto retry_locked;
 	}
 
@@ -1122,11 +1124,14 @@
 	}
 
 	/* we need to read it. */
-	r = readpage_nounlock(file, page);
-	if (r < 0)
-		goto fail_nosnap;
+	r = ceph_do_readpage(file, page);
+	if (r < 0) {
+		if (r == -EINPROGRESS)
+			return -EAGAIN;
+		goto fail_unlock;
+	}
 	goto retry_locked;
-fail_nosnap:
+fail_unlock:
 	unlock_page(page);
 	return r;
 }
@@ -1237,7 +1242,7 @@
 	struct ceph_inode_info *ci = ceph_inode(inode);
 	struct ceph_file_info *fi = vma->vm_file->private_data;
 	struct page *pinned_page = NULL;
-	loff_t off = vmf->pgoff << PAGE_CACHE_SHIFT;
+	loff_t off = (loff_t)vmf->pgoff << PAGE_CACHE_SHIFT;
 	int want, got, ret;
 
 	dout("filemap_fault %p %llx.%llx %llu~%zd trying to get caps\n",
--- linux-4.4.0.orig/fs/ceph/cache.c
+++ linux-4.4.0/fs/ceph/cache.c
@@ -224,13 +224,7 @@
 	fscache_relinquish_cookie(cookie, 0);
 }
 
-static void ceph_vfs_readpage_complete(struct page *page, void *data, int error)
-{
-	if (!error)
-		SetPageUptodate(page);
-}
-
-static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
+static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error)
 {
 	if (!error)
 		SetPageUptodate(page);
@@ -259,7 +253,7 @@
 		return -ENOBUFS;
 
 	ret = fscache_read_or_alloc_page(ci->fscache, page,
-					 ceph_vfs_readpage_complete, NULL,
+					 ceph_readpage_from_fscache_complete, NULL,
 					 GFP_KERNEL);
 
 	switch (ret) {
@@ -288,7 +282,7 @@
 		return -ENOBUFS;
 
 	ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
-					  ceph_vfs_readpage_complete_unlock,
+					  ceph_readpage_from_fscache_complete,
 					  NULL, mapping_gfp_mask(mapping));
 
 	switch (ret) {
--- linux-4.4.0.orig/fs/ceph/caps.c
+++ linux-4.4.0/fs/ceph/caps.c
@@ -920,12 +920,24 @@
 {
 	struct ceph_mds_session *session = cap->session;
 	struct ceph_inode_info *ci = cap->ci;
-	struct ceph_mds_client *mdsc =
-		ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
+	struct ceph_mds_client *mdsc;
 	int removed = 0;
 
+	/* 'ci' being NULL means the remove have already occurred */
+	if (!ci) {
+		dout("%s: cap inode is NULL\n", __func__);
+		return;
+	}
+
 	dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
 
+	mdsc = ceph_inode_to_client(&ci->vfs_inode)->mdsc;
+
+	/* remove from inode's cap rbtree, and clear auth cap */
+	rb_erase(&cap->ci_node, &ci->i_caps);
+	if (ci->i_auth_cap == cap)
+		ci->i_auth_cap = NULL;
+
 	/* remove from session list */
 	spin_lock(&session->s_cap_lock);
 	if (session->s_cap_iterator == cap) {
@@ -961,11 +973,6 @@
 
 	spin_unlock(&session->s_cap_lock);
 
-	/* remove from inode list */
-	rb_erase(&cap->ci_node, &ci->i_caps);
-	if (ci->i_auth_cap == cap)
-		ci->i_auth_cap = NULL;
-
 	if (removed)
 		ceph_put_cap(mdsc, cap);
 
@@ -1072,20 +1079,23 @@
 }
 
 /*
- * Queue cap releases when an inode is dropped from our cache.  Since
- * inode is about to be destroyed, there is no need for i_ceph_lock.
+ * Queue cap releases when an inode is dropped from our cache.
  */
 void ceph_queue_caps_release(struct inode *inode)
 {
 	struct ceph_inode_info *ci = ceph_inode(inode);
 	struct rb_node *p;
 
+	/* lock i_ceph_lock, because ceph_d_revalidate(..., LOOKUP_RCU)
+	 * may call __ceph_caps_issued_mask() on a freeing inode. */
+	spin_lock(&ci->i_ceph_lock);
 	p = rb_first(&ci->i_caps);
 	while (p) {
 		struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
 		p = rb_next(p);
 		__ceph_remove_cap(cap, true);
 	}
+	spin_unlock(&ci->i_ceph_lock);
 }
 
 /*
@@ -1187,7 +1197,7 @@
 
 	if (flushing & CEPH_CAP_XATTR_EXCL) {
 		__ceph_build_xattrs_blob(ci);
-		xattr_blob = ci->i_xattrs.blob;
+		xattr_blob = ceph_buffer_get(ci->i_xattrs.blob);
 		xattr_version = ci->i_xattrs.version;
 	}
 
@@ -1206,6 +1216,7 @@
 		delayed = 1;
 	}
 
+	ceph_buffer_put(xattr_blob);
 	if (wake)
 		wake_up_all(&ci->i_cap_wq);
 
@@ -1731,8 +1742,12 @@
 		}
 
 		/* want more caps from mds? */
-		if (want & ~(cap->mds_wanted | cap->issued))
-			goto ack;
+		if (want & ~cap->mds_wanted) {
+			if (want & ~(cap->mds_wanted | cap->issued))
+				goto ack;
+			if (!__cap_is_valid(cap))
+				goto ack;
+		}
 
 		/* things we might delay */
 		if ((cap->issued & ~retain) == 0 &&
@@ -1770,12 +1785,24 @@
 			if (mutex_trylock(&session->s_mutex) == 0) {
 				dout("inverting session/ino locks on %p\n",
 				     session);
+				session = ceph_get_mds_session(session);
 				spin_unlock(&ci->i_ceph_lock);
 				if (took_snap_rwsem) {
 					up_read(&mdsc->snap_rwsem);
 					took_snap_rwsem = 0;
 				}
-				mutex_lock(&session->s_mutex);
+				if (session) {
+					mutex_lock(&session->s_mutex);
+					ceph_put_mds_session(session);
+				} else {
+					/*
+					 * Because we take the reference while
+					 * holding the i_ceph_lock, it should
+					 * never be NULL. Throw a warning if it
+					 * ever is.
+					 */
+					WARN_ON_ONCE(true);
+				}
 				goto retry;
 			}
 		}
@@ -1850,6 +1877,7 @@
 retry:
 	spin_lock(&ci->i_ceph_lock);
 	if (ci->i_ceph_flags & CEPH_I_NOFLUSH) {
+		spin_unlock(&ci->i_ceph_lock);
 		dout("try_flush_caps skipping %p I_NOFLUSH set\n", inode);
 		goto out;
 	}
@@ -1867,8 +1895,10 @@
 			mutex_lock(&session->s_mutex);
 			goto retry;
 		}
-		if (cap->session->s_state < CEPH_MDS_SESSION_OPEN)
+		if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) {
+			spin_unlock(&ci->i_ceph_lock);
 			goto out;
+		}
 
 		flushing = __mark_caps_flushing(inode, session, &flush_tid,
 						&oldest_flush_tid);
@@ -3240,7 +3270,6 @@
 			tcap->cap_id = t_cap_id;
 			tcap->seq = t_seq - 1;
 			tcap->issue_seq = t_seq - 1;
-			tcap->mseq = t_mseq;
 			tcap->issued |= issued;
 			tcap->implemented |= issued;
 			if (cap == ci->i_auth_cap)
@@ -3284,6 +3313,7 @@
 		WARN_ON(1);
 		tsession = NULL;
 		target = -1;
+		mutex_lock(&session->s_mutex);
 	}
 	goto retry;
 
--- linux-4.4.0.orig/fs/ceph/dir.c
+++ linux-4.4.0/fs/ceph/dir.c
@@ -247,6 +247,11 @@
 		if (ret < 0)
 			err = ret;
 		dput(last);
+		/* last_name no longer match cache index */
+		if (fi->readdir_cache_idx >= 0) {
+			fi->readdir_cache_idx = -1;
+			fi->dir_release_count = 0;
+		}
 	}
 	return err;
 }
@@ -1283,6 +1288,7 @@
 unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn)
 {
 	struct ceph_inode_info *dci = ceph_inode(dir);
+	unsigned hash;
 
 	switch (dci->i_dir_layout.dl_dir_hash) {
 	case 0:	/* for backward compat */
@@ -1290,8 +1296,11 @@
 		return dn->d_name.hash;
 
 	default:
-		return ceph_str_hash(dci->i_dir_layout.dl_dir_hash,
+		spin_lock(&dn->d_lock);
+		hash = ceph_str_hash(dci->i_dir_layout.dl_dir_hash,
 				     dn->d_name.name, dn->d_name.len);
+		spin_unlock(&dn->d_lock);
+		return hash;
 	}
 }
 
--- linux-4.4.0.orig/fs/ceph/export.c
+++ linux-4.4.0/fs/ceph/export.c
@@ -146,6 +146,11 @@
 	}
 	req->r_num_caps = 1;
 	err = ceph_mdsc_do_request(mdsc, NULL, req);
+	if (err) {
+		ceph_mdsc_put_request(req);
+		return ERR_PTR(err);
+	}
+
 	inode = req->r_target_inode;
 	if (inode)
 		ihold(inode);
--- linux-4.4.0.orig/fs/ceph/file.c
+++ linux-4.4.0/fs/ceph/file.c
@@ -929,7 +929,8 @@
 		statret = __ceph_do_getattr(inode, page,
 					    CEPH_STAT_CAP_INLINE_DATA, !!page);
 		if (statret < 0) {
-			 __free_page(page);
+			if (page)
+				__free_page(page);
 			if (statret == -ENODATA) {
 				BUG_ON(retry_op != READ_INLINE);
 				goto again;
@@ -1432,6 +1433,7 @@
 	.mmap = ceph_mmap,
 	.fsync = ceph_fsync,
 	.lock = ceph_lock,
+	.setlease = simple_nosetlease,
 	.flock = ceph_flock,
 	.splice_read = generic_file_splice_read,
 	.splice_write = iter_file_splice_write,
--- linux-4.4.0.orig/fs/ceph/inode.c
+++ linux-4.4.0/fs/ceph/inode.c
@@ -474,6 +474,7 @@
 	struct inode *inode = container_of(head, struct inode, i_rcu);
 	struct ceph_inode_info *ci = ceph_inode(inode);
 
+	kfree(ci->i_symlink);
 	kmem_cache_free(ceph_inode_cachep, ci);
 }
 
@@ -505,7 +506,6 @@
 		ceph_put_snap_realm(mdsc, realm);
 	}
 
-	kfree(ci->i_symlink);
 	while ((n = rb_first(&ci->i_fragtree)) != NULL) {
 		frag = rb_entry(n, struct ceph_inode_frag, node);
 		rb_erase(n, &ci->i_fragtree);
@@ -725,7 +725,12 @@
 	ci->i_version = le64_to_cpu(info->version);
 	inode->i_version++;
 	inode->i_rdev = le32_to_cpu(info->rdev);
-	inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
+	/* directories have fl_stripe_unit set to zero */
+	if (le32_to_cpu(info->layout.fl_stripe_unit))
+		inode->i_blkbits =
+			fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
+	else
+		inode->i_blkbits = CEPH_BLOCK_SHIFT;
 
 	if ((new_version || (new_issued & CEPH_CAP_AUTH_SHARED)) &&
 	    (issued & CEPH_CAP_AUTH_EXCL) == 0) {
@@ -1358,15 +1363,20 @@
 
 	if (!ctl->page || pgoff != page_index(ctl->page)) {
 		ceph_readdir_cache_release(ctl);
-		ctl->page  = grab_cache_page(&dir->i_data, pgoff);
+		if (idx == 0)
+			ctl->page = grab_cache_page(&dir->i_data, pgoff);
+		else
+			ctl->page = find_lock_page(&dir->i_data, pgoff);
 		if (!ctl->page) {
 			ctl->index = -1;
-			return -ENOMEM;
+			return idx == 0 ? -ENOMEM : 0;
 		}
 		/* reading/filling the cache are serialized by
 		 * i_mutex, no need to use page lock */
 		unlock_page(ctl->page);
 		ctl->dentries = kmap(ctl->page);
+		if (idx == 0)
+			memset(ctl->dentries, 0, PAGE_CACHE_SIZE);
 	}
 
 	if (req->r_dir_release_cnt == atomic64_read(&ci->i_release_count) &&
@@ -1505,7 +1515,6 @@
 			if (IS_ERR(realdn)) {
 				err = PTR_ERR(realdn);
 				d_drop(dn);
-				dn = NULL;
 				goto next_item;
 			}
 			dn = realdn;
@@ -1768,7 +1777,7 @@
 /*
  * setattr
  */
-int ceph_setattr(struct dentry *dentry, struct iattr *attr)
+int __ceph_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = d_inode(dentry);
 	struct ceph_inode_info *ci = ceph_inode(inode);
@@ -1786,7 +1795,7 @@
 	if (ceph_snap(inode) != CEPH_NOSNAP)
 		return -EROFS;
 
-	err = inode_change_ok(inode, attr);
+	err = setattr_prepare(dentry, attr);
 	if (err != 0)
 		return err;
 
@@ -1970,11 +1979,6 @@
 	if (inode_dirty_flags)
 		__mark_inode_dirty(inode, inode_dirty_flags);
 
-	if (ia_valid & ATTR_MODE) {
-		err = posix_acl_chmod(inode, attr->ia_mode);
-		if (err)
-			goto out_put;
-	}
 
 	if (mask) {
 		req->r_inode = inode;
@@ -1988,13 +1992,23 @@
 	     ceph_cap_string(dirtied), mask);
 
 	ceph_mdsc_put_request(req);
-	if (mask & CEPH_SETATTR_SIZE)
-		__ceph_do_pending_vmtruncate(inode);
 	ceph_free_cap_flush(prealloc_cf);
+
+	if (err >= 0 && (mask & CEPH_SETATTR_SIZE))
+		__ceph_do_pending_vmtruncate(inode);
+
 	return err;
-out_put:
-	ceph_mdsc_put_request(req);
-	ceph_free_cap_flush(prealloc_cf);
+}
+
+int ceph_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	int err;
+
+	err = __ceph_setattr(dentry, attr);
+
+	if (err >= 0 && (attr->ia_valid & ATTR_MODE))
+		err = posix_acl_chmod(d_inode(dentry), attr->ia_mode);
+
 	return err;
 }
 
--- linux-4.4.0.orig/fs/ceph/mds_client.c
+++ linux-4.4.0/fs/ceph/mds_client.c
@@ -274,12 +274,13 @@
 				  struct ceph_mds_reply_info_parsed *info,
 				  u64 features)
 {
-	if (info->head->op == CEPH_MDS_OP_GETFILELOCK)
+	u32 op = le32_to_cpu(info->head->op);
+
+	if (op == CEPH_MDS_OP_GETFILELOCK)
 		return parse_reply_info_filelock(p, end, info, features);
-	else if (info->head->op == CEPH_MDS_OP_READDIR ||
-		 info->head->op == CEPH_MDS_OP_LSSNAP)
+	else if (op == CEPH_MDS_OP_READDIR || op == CEPH_MDS_OP_LSSNAP)
 		return parse_reply_info_dir(p, end, info, features);
-	else if (info->head->op == CEPH_MDS_OP_CREATE)
+	else if (op == CEPH_MDS_OP_CREATE)
 		return parse_reply_info_create(p, end, info, features);
 	else
 		return -EIO;
@@ -643,6 +644,9 @@
 {
 	dout("__unregister_request %p tid %lld\n", req, req->r_tid);
 
+	/* Never leave an unregistered request on an unsafe list! */
+	list_del_init(&req->r_unsafe_item);
+
 	if (req->r_tid == mdsc->oldest_tid) {
 		struct rb_node *p = rb_next(&req->r_node);
 		mdsc->oldest_tid = 0;
@@ -1050,7 +1054,6 @@
 	while (!list_empty(&session->s_unsafe)) {
 		req = list_first_entry(&session->s_unsafe,
 				       struct ceph_mds_request, r_unsafe_item);
-		list_del_init(&req->r_unsafe_item);
 		pr_warn_ratelimited(" dropping unsafe request %llu\n",
 				    req->r_tid);
 		__unregister_request(mdsc, req);
@@ -1195,6 +1198,15 @@
 			list_add(&ci->i_prealloc_cap_flush->list, &to_remove);
 			ci->i_prealloc_cap_flush = NULL;
 		}
+
+               if (drop &&
+                  ci->i_wrbuffer_ref_head == 0 &&
+                  ci->i_wr_ref == 0 &&
+                  ci->i_dirty_caps == 0 &&
+                  ci->i_flushing_caps == 0) {
+                      ceph_put_snap_context(ci->i_head_snapc);
+                      ci->i_head_snapc = NULL;
+               }
 	}
 	spin_unlock(&ci->i_ceph_lock);
 	while (!list_empty(&to_remove)) {
@@ -1397,6 +1409,29 @@
 	return request_close_session(mdsc, session);
 }
 
+static bool drop_negative_children(struct dentry *dentry)
+{
+	struct dentry *child;
+	bool all_negative = true;
+
+	if (!d_is_dir(dentry))
+		goto out;
+
+	spin_lock(&dentry->d_lock);
+	list_for_each_entry(child, &dentry->d_subdirs, d_child) {
+		if (d_really_is_positive(child)) {
+			all_negative = false;
+			break;
+		}
+	}
+	spin_unlock(&dentry->d_lock);
+
+	if (all_negative)
+		shrink_dcache_parent(dentry);
+out:
+	return all_negative;
+}
+
 /*
  * Trim old(er) caps.
  *
@@ -1442,16 +1477,27 @@
 	if ((used | wanted) & ~oissued & mine)
 		goto out;   /* we need these caps */
 
-	session->s_trim_caps--;
 	if (oissued) {
 		/* we aren't the only cap.. just remove us */
 		__ceph_remove_cap(cap, true);
+		session->s_trim_caps--;
 	} else {
+		struct dentry *dentry;
 		/* try dropping referring dentries */
 		spin_unlock(&ci->i_ceph_lock);
-		d_prune_aliases(inode);
-		dout("trim_caps_cb %p cap %p  pruned, count now %d\n",
-		     inode, cap, atomic_read(&inode->i_count));
+		dentry = d_find_any_alias(inode);
+		if (dentry && drop_negative_children(dentry)) {
+			int count;
+			dput(dentry);
+			d_prune_aliases(inode);
+			count = atomic_read(&inode->i_count);
+			if (count == 1)
+				session->s_trim_caps--;
+			dout("trim_caps_cb %p cap %p pruned, count now %d\n",
+			     inode, cap, count);
+		} else {
+			dput(dentry);
+		}
 		return 0;
 	}
 
@@ -1842,13 +1888,18 @@
 			     int *pfreepath)
 {
 	char *path;
+	struct inode *dir;
 
-	if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_NOSNAP) {
-		*pino = ceph_ino(d_inode(dentry->d_parent));
+	rcu_read_lock();
+	dir = d_inode_rcu(dentry->d_parent);
+	if (dir && ceph_snap(dir) == CEPH_NOSNAP) {
+		*pino = ceph_ino(dir);
+		rcu_read_unlock();
 		*ppath = dentry->d_name.name;
 		*ppathlen = dentry->d_name.len;
 		return 0;
 	}
+	rcu_read_unlock();
 	path = ceph_mdsc_build_path(dentry, ppathlen, pino, 1);
 	if (IS_ERR(path))
 		return PTR_ERR(path);
@@ -2476,7 +2527,6 @@
 			 * useful we could do with a revised return value.
 			 */
 			dout("got safe reply %llu, mds%d\n", tid, mds);
-			list_del_init(&req->r_unsafe_item);
 
 			/* last unsafe request during umount? */
 			if (mdsc->stopping && !__get_oldest_req(mdsc))
@@ -3378,6 +3428,9 @@
 	dout("mdsc delayed_work\n");
 	ceph_check_delayed_caps(mdsc);
 
+	if (mdsc->stopping)
+		return;
+
 	mutex_lock(&mdsc->mutex);
 	renew_interval = mdsc->mdsmap->m_session_timeout >> 2;
 	renew_caps = time_after_eq(jiffies, HZ*renew_interval +
@@ -3702,7 +3755,16 @@
 static void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
 {
 	dout("stop\n");
-	cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
+	/*
+	 * Make sure the delayed work stopped before releasing
+	 * the resources.
+	 *
+	 * Because the cancel_delayed_work_sync() will only
+	 * guarantee that the work finishes executing. But the
+	 * delayed work will re-arm itself again after that.
+	 */
+	flush_delayed_work(&mdsc->delayed_work);
+
 	if (mdsc->mdsmap)
 		ceph_mdsmap_destroy(mdsc->mdsmap);
 	kfree(mdsc->sessions);
--- linux-4.4.0.orig/fs/ceph/snap.c
+++ linux-4.4.0/fs/ceph/snap.c
@@ -567,7 +567,12 @@
 	capsnap = NULL;
 
 update_snapc:
-	if (ci->i_head_snapc) {
+       if (ci->i_wrbuffer_ref_head == 0 &&
+           ci->i_wr_ref == 0 &&
+           ci->i_dirty_caps == 0 &&
+           ci->i_flushing_caps == 0) {
+               ci->i_head_snapc = NULL;
+       } else {
 		ci->i_head_snapc = ceph_get_snap_context(new_snapc);
 		dout(" new snapc is %p\n", new_snapc);
 	}
@@ -611,7 +616,8 @@
 	     capsnap->size);
 
 	spin_lock(&mdsc->snap_flush_lock);
-	list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list);
+	if (list_empty(&ci->i_snap_flush_item))
+		list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list);
 	spin_unlock(&mdsc->snap_flush_lock);
 	return 1;  /* caller may want to ceph_flush_snaps */
 }
--- linux-4.4.0.orig/fs/ceph/super.c
+++ linux-4.4.0/fs/ceph/super.c
@@ -712,6 +712,12 @@
 	return;
 }
 
+static int ceph_remount(struct super_block *sb, int *flags, char *data)
+{
+	sync_filesystem(sb);
+	return 0;
+}
+
 static const struct super_operations ceph_super_ops = {
 	.alloc_inode	= ceph_alloc_inode,
 	.destroy_inode	= ceph_destroy_inode,
@@ -719,6 +725,7 @@
 	.drop_inode	= ceph_drop_inode,
 	.sync_fs        = ceph_sync_fs,
 	.put_super	= ceph_put_super,
+	.remount_fs	= ceph_remount,
 	.show_options   = ceph_show_options,
 	.statfs		= ceph_statfs,
 	.umount_begin   = ceph_umount_begin,
--- linux-4.4.0.orig/fs/ceph/super.h
+++ linux-4.4.0/fs/ceph/super.h
@@ -474,7 +474,12 @@
 					   long long release_count,
 					   long long ordered_count)
 {
-	smp_mb__before_atomic();
+	/*
+	 * Makes sure operations that setup readdir cache (update page
+	 * cache and i_size) are strongly ordered w.r.t. the following
+	 * atomic64_set() operations.
+	 */
+	smp_mb();
 	atomic64_set(&ci->i_complete_seq[0], release_count);
 	atomic64_set(&ci->i_complete_seq[1], ordered_count);
 }
@@ -788,6 +793,7 @@
 	return __ceph_do_getattr(inode, NULL, mask, force);
 }
 extern int ceph_permission(struct inode *inode, int mask);
+extern int __ceph_setattr(struct dentry *dentry, struct iattr *attr);
 extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
 extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
 			struct kstat *stat);
--- linux-4.4.0.orig/fs/ceph/xattr.c
+++ linux-4.4.0/fs/ceph/xattr.c
@@ -369,6 +369,7 @@
 
 	if (update_xattr) {
 		int err = 0;
+
 		if (xattr && (flags & XATTR_CREATE))
 			err = -EEXIST;
 		else if (!xattr && (flags & XATTR_REPLACE))
@@ -376,12 +377,14 @@
 		if (err) {
 			kfree(name);
 			kfree(val);
+			kfree(*newxattr);
 			return err;
 		}
 		if (update_xattr < 0) {
 			if (xattr)
 				__remove_xattr(ci, xattr);
 			kfree(name);
+			kfree(*newxattr);
 			return 0;
 		}
 	}
@@ -913,6 +916,7 @@
 	struct ceph_inode_info *ci = ceph_inode(inode);
 	struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc;
 	struct ceph_cap_flush *prealloc_cf = NULL;
+	struct ceph_buffer *old_blob = NULL;
 	int issued;
 	int err;
 	int dirty = 0;
@@ -981,13 +985,15 @@
 		struct ceph_buffer *blob;
 
 		spin_unlock(&ci->i_ceph_lock);
-		dout(" preaallocating new blob size=%d\n", required_blob_size);
+		ceph_buffer_put(old_blob); /* Shouldn't be required */
+		dout(" pre-allocating new blob size=%d\n", required_blob_size);
 		blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
 		if (!blob)
 			goto do_sync_unlocked;
 		spin_lock(&ci->i_ceph_lock);
+		/* prealloc_blob can't be released while holding i_ceph_lock */
 		if (ci->i_xattrs.prealloc_blob)
-			ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+			old_blob = ci->i_xattrs.prealloc_blob;
 		ci->i_xattrs.prealloc_blob = blob;
 		goto retry;
 	}
@@ -1003,6 +1009,7 @@
 	}
 
 	spin_unlock(&ci->i_ceph_lock);
+	ceph_buffer_put(old_blob);
 	if (lock_snap_rwsem)
 		up_read(&mdsc->snap_rwsem);
 	if (dirty)
--- linux-4.4.0.orig/fs/char_dev.c
+++ linux-4.4.0/fs/char_dev.c
@@ -130,6 +130,12 @@
 			ret = -EBUSY;
 			goto out;
 		}
+
+		if (new_min < old_min && new_max > old_max) {
+			ret = -EBUSY;
+			goto out;
+		}
+
 	}
 
 	cd->next = *cp;
@@ -326,7 +332,7 @@
 
 	if (owner && !try_module_get(owner))
 		return NULL;
-	kobj = kobject_get(&p->kobj);
+	kobj = kobject_get_unless_zero(&p->kobj);
 	if (!kobj)
 		module_put(owner);
 	return kobj;
@@ -466,6 +472,85 @@
 	return 0;
 }
 
+/**
+ * cdev_set_parent() - set the parent kobject for a char device
+ * @p: the cdev structure
+ * @kobj: the kobject to take a reference to
+ *
+ * cdev_set_parent() sets a parent kobject which will be referenced
+ * appropriately so the parent is not freed before the cdev. This
+ * should be called before cdev_add.
+ */
+void cdev_set_parent(struct cdev *p, struct kobject *kobj)
+{
+	WARN_ON(!kobj->state_initialized);
+	p->kobj.parent = kobj;
+}
+
+/**
+ * cdev_device_add() - add a char device and it's corresponding
+ *	struct device, linkink
+ * @dev: the device structure
+ * @cdev: the cdev structure
+ *
+ * cdev_device_add() adds the char device represented by @cdev to the system,
+ * just as cdev_add does. It then adds @dev to the system using device_add
+ * The dev_t for the char device will be taken from the struct device which
+ * needs to be initialized first. This helper function correctly takes a
+ * reference to the parent device so the parent will not get released until
+ * all references to the cdev are released.
+ *
+ * This helper uses dev->devt for the device number. If it is not set
+ * it will not add the cdev and it will be equivalent to device_add.
+ *
+ * This function should be used whenever the struct cdev and the
+ * struct device are members of the same structure whose lifetime is
+ * managed by the struct device.
+ *
+ * NOTE: Callers must assume that userspace was able to open the cdev and
+ * can call cdev fops callbacks at any time, even if this function fails.
+ */
+int cdev_device_add(struct cdev *cdev, struct device *dev)
+{
+	int rc = 0;
+
+	if (dev->devt) {
+		cdev_set_parent(cdev, &dev->kobj);
+
+		rc = cdev_add(cdev, dev->devt, 1);
+		if (rc)
+			return rc;
+	}
+
+	rc = device_add(dev);
+	if (rc)
+		cdev_del(cdev);
+
+	return rc;
+}
+
+/**
+ * cdev_device_del() - inverse of cdev_device_add
+ * @dev: the device structure
+ * @cdev: the cdev structure
+ *
+ * cdev_device_del() is a helper function to call cdev_del and device_del.
+ * It should be used whenever cdev_device_add is used.
+ *
+ * If dev->devt is not set it will not remove the cdev and will be equivalent
+ * to device_del.
+ *
+ * NOTE: This guarantees that associated sysfs callbacks are not running
+ * or runnable, however any cdevs already open will remain and their fops
+ * will still be callable even after this function returns.
+ */
+void cdev_device_del(struct cdev *cdev, struct device *dev)
+{
+	device_del(dev);
+	if (dev->devt)
+		cdev_del(cdev);
+}
+
 static void cdev_unmap(dev_t dev, unsigned count)
 {
 	kobj_unmap(cdev_map, dev, count);
@@ -477,6 +562,10 @@
  *
  * cdev_del() removes @p from the system, possibly freeing the structure
  * itself.
+ *
+ * NOTE: This guarantees that cdev device will no longer be able to be
+ * opened, however any cdevs already open will remain and their fops will
+ * still be callable even after cdev_del returns.
  */
 void cdev_del(struct cdev *p)
 {
@@ -565,5 +654,8 @@
 EXPORT_SYMBOL(cdev_alloc);
 EXPORT_SYMBOL(cdev_del);
 EXPORT_SYMBOL(cdev_add);
+EXPORT_SYMBOL(cdev_set_parent);
+EXPORT_SYMBOL(cdev_device_add);
+EXPORT_SYMBOL(cdev_device_del);
 EXPORT_SYMBOL(__register_chrdev);
 EXPORT_SYMBOL(__unregister_chrdev);
--- linux-4.4.0.orig/fs/cifs/Kconfig
+++ linux-4.4.0/fs/cifs/Kconfig
@@ -9,8 +9,6 @@
 	select CRYPTO_ARC4
 	select CRYPTO_ECB
 	select CRYPTO_DES
-	select CRYPTO_SHA256
-	select CRYPTO_CMAC
 	help
 	  This is the client VFS module for the Common Internet File System
 	  (CIFS) protocol which is the successor to the Server Message Block
@@ -169,11 +167,15 @@
 
 config CIFS_SMB2
 	bool "SMB2 and SMB3 network file system support"
-	depends on CIFS && INET
-	select NLS
+	depends on CIFS
 	select KEYS
 	select FSCACHE
 	select DNS_RESOLVER
+	select CRYPTO_AES
+	select CRYPTO_SHA256
+	select CRYPTO_CMAC
+	select CRYPTO_AEAD2
+	select CRYPTO_CCM
 
 	help
 	  This enables support for the Server Message Block version 2
@@ -194,7 +196,7 @@
 
 config CIFS_SMB311
 	bool "SMB3.1.1 network file system support (Experimental)"
-	depends on CIFS_SMB2 && INET
+	depends on CIFS_SMB2
 
 	help
 	  This enables experimental support for the newest, SMB3.1.1, dialect.
--- linux-4.4.0.orig/fs/cifs/asn1.c
+++ linux-4.4.0/fs/cifs/asn1.c
@@ -541,8 +541,8 @@
 		return 0;
 	} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
 		   || (tag != ASN1_EOC)) {
-		cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p (%d) exit 0\n",
-			 cls, con, tag, end, *end);
+		cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p exit 0\n",
+			 cls, con, tag, end);
 		return 0;
 	}
 
@@ -552,8 +552,8 @@
 		return 0;
 	} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
 		   || (tag != ASN1_SEQ)) {
-		cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p (%d) exit 1\n",
-			 cls, con, tag, end, *end);
+		cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p exit 1\n",
+			 cls, con, tag, end);
 		return 0;
 	}
 
@@ -563,8 +563,8 @@
 		return 0;
 	} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
 		   || (tag != ASN1_EOC)) {
-		cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p (%d) exit 0\n",
-			 cls, con, tag, end, *end);
+		cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p exit 0\n",
+			 cls, con, tag, end);
 		return 0;
 	}
 
@@ -575,8 +575,8 @@
 		return 0;
 	} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
 		   || (tag != ASN1_SEQ)) {
-		cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p (%d) exit 1\n",
-			 cls, con, tag, end, *end);
+		cifs_dbg(FYI, "cls = %d con = %d tag = %d sequence_end = %p exit 1\n",
+			 cls, con, tag, sequence_end);
 		return 0;
 	}
 
--- linux-4.4.0.orig/fs/cifs/cifs_debug.c
+++ linux-4.4.0/fs/cifs/cifs_debug.c
@@ -50,7 +50,7 @@
 	vaf.fmt = fmt;
 	vaf.va = &args;
 
-	pr_err("CIFS VFS: %pV", &vaf);
+	pr_err_ratelimited("CIFS VFS: %pV", &vaf);
 
 	va_end(args);
 }
@@ -123,25 +123,41 @@
 	seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
 	seq_printf(m, "Features:");
 #ifdef CONFIG_CIFS_DFS_UPCALL
-	seq_printf(m, " dfs");
+	seq_printf(m, " DFS");
 #endif
 #ifdef CONFIG_CIFS_FSCACHE
-	seq_printf(m, " fscache");
+	seq_printf(m, ",FSCACHE");
+#endif
+#ifdef CONFIG_CIFS_SMB_DIRECT
+	seq_printf(m, ",SMB_DIRECT");
+#endif
+#ifdef CONFIG_CIFS_STATS2
+	seq_printf(m, ",STATS2");
+#elif defined(CONFIG_CIFS_STATS)
+	seq_printf(m, ",STATS");
+#endif
+#ifdef CONFIG_CIFS_DEBUG2
+	seq_printf(m, ",DEBUG2");
+#elif defined(CONFIG_CIFS_DEBUG)
+	seq_printf(m, ",DEBUG");
+#endif
+#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
+	seq_printf(m, ",ALLOW_INSECURE_LEGACY");
 #endif
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-	seq_printf(m, " lanman");
+	seq_printf(m, ",WEAK_PW_HASH");
 #endif
 #ifdef CONFIG_CIFS_POSIX
-	seq_printf(m, " posix");
+	seq_printf(m, ",CIFS_POSIX");
 #endif
 #ifdef CONFIG_CIFS_UPCALL
-	seq_printf(m, " spnego");
+	seq_printf(m, ",UPCALL(SPNEGO)");
 #endif
 #ifdef CONFIG_CIFS_XATTR
-	seq_printf(m, " xattr");
+	seq_printf(m, ",XATTR");
 #endif
 #ifdef CONFIG_CIFS_ACL
-	seq_printf(m, " acl");
+	seq_printf(m, ",ACL");
 #endif
 	seq_putc(m, '\n');
 	seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
@@ -152,10 +168,16 @@
 	list_for_each(tmp1, &cifs_tcp_ses_list) {
 		server = list_entry(tmp1, struct TCP_Server_Info,
 				    tcp_ses_list);
+		seq_printf(m, "\nNumber of credits: %d", server->credits);
 		i++;
 		list_for_each(tmp2, &server->smb_ses_list) {
 			ses = list_entry(tmp2, struct cifs_ses,
 					 smb_ses_list);
+			spin_lock(&GlobalMid_Lock);
+			if (ses->status == CifsExiting) {
+				spin_unlock(&GlobalMid_Lock);
+				continue;
+			}
 			if ((ses->serverDomain == NULL) ||
 				(ses->serverOS == NULL) ||
 				(ses->serverNOS == NULL)) {
@@ -170,6 +192,7 @@
 				ses->ses_count, ses->serverOS, ses->serverNOS,
 				ses->capabilities, ses->status);
 			}
+			spin_unlock(&GlobalMid_Lock);
 			seq_printf(m, "TCP status: %d\n\tLocal Users To "
 				   "Server: %d SecMode: 0x%x Req On Wire: %d",
 				   server->tcpStatus, server->srv_count,
@@ -255,7 +278,6 @@
 static ssize_t cifs_stats_proc_write(struct file *file,
 		const char __user *buffer, size_t count, loff_t *ppos)
 {
-	char c;
 	bool bv;
 	int rc;
 	struct list_head *tmp1, *tmp2, *tmp3;
@@ -263,15 +285,19 @@
 	struct cifs_ses *ses;
 	struct cifs_tcon *tcon;
 
-	rc = get_user(c, buffer);
-	if (rc)
-		return rc;
-
-	if (strtobool(&c, &bv) == 0) {
+	rc = kstrtobool_from_user(buffer, count, &bv);
+	if (rc == 0) {
 #ifdef CONFIG_CIFS_STATS2
 		atomic_set(&totBufAllocCount, 0);
 		atomic_set(&totSmBufAllocCount, 0);
 #endif /* CONFIG_CIFS_STATS2 */
+		atomic_set(&tcpSesReconnectCount, 0);
+		atomic_set(&tconInfoReconnectCount, 0);
+
+		spin_lock(&GlobalMid_Lock);
+		GlobalMaxActiveXid = 0;
+		GlobalCurrentXid = 0;
+		spin_unlock(&GlobalMid_Lock);
 		spin_lock(&cifs_tcp_ses_lock);
 		list_for_each(tmp1, &cifs_tcp_ses_list) {
 			server = list_entry(tmp1, struct TCP_Server_Info,
@@ -284,12 +310,18 @@
 							  struct cifs_tcon,
 							  tcon_list);
 					atomic_set(&tcon->num_smbs_sent, 0);
+					spin_lock(&tcon->stat_lock);
+					tcon->bytes_read = 0;
+					tcon->bytes_written = 0;
+					spin_unlock(&tcon->stat_lock);
 					if (server->ops->clear_stats)
 						server->ops->clear_stats(tcon);
 				}
 			}
 		}
 		spin_unlock(&cifs_tcp_ses_lock);
+	} else {
+		return rc;
 	}
 
 	return count;
@@ -433,17 +465,17 @@
 static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
 		size_t count, loff_t *ppos)
 {
-	char c;
+	char c[2] = { '\0' };
 	bool bv;
 	int rc;
 
-	rc = get_user(c, buffer);
+	rc = get_user(c[0], buffer);
 	if (rc)
 		return rc;
-	if (strtobool(&c, &bv) == 0)
+	if (strtobool(c, &bv) == 0)
 		cifsFYI = bv;
-	else if ((c > '1') && (c <= '9'))
-		cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
+	else if ((c[0] > '1') && (c[0] <= '9'))
+		cifsFYI = (int) (c[0] - '0'); /* see cifs_debug.h for meanings */
 
 	return count;
 }
@@ -471,20 +503,12 @@
 static ssize_t cifs_linux_ext_proc_write(struct file *file,
 		const char __user *buffer, size_t count, loff_t *ppos)
 {
-	char c;
-	bool bv;
 	int rc;
 
-	rc = get_user(c, buffer);
+	rc = kstrtobool_from_user(buffer, count, &linuxExtEnabled);
 	if (rc)
 		return rc;
 
-	rc = strtobool(&c, &bv);
-	if (rc)
-		return rc;
-
-	linuxExtEnabled = bv;
-
 	return count;
 }
 
@@ -511,20 +535,12 @@
 static ssize_t cifs_lookup_cache_proc_write(struct file *file,
 		const char __user *buffer, size_t count, loff_t *ppos)
 {
-	char c;
-	bool bv;
 	int rc;
 
-	rc = get_user(c, buffer);
-	if (rc)
-		return rc;
-
-	rc = strtobool(&c, &bv);
+	rc = kstrtobool_from_user(buffer, count, &lookupCacheEnabled);
 	if (rc)
 		return rc;
 
-	lookupCacheEnabled = bv;
-
 	return count;
 }
 
@@ -551,20 +567,12 @@
 static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
 		size_t count, loff_t *ppos)
 {
-	char c;
-	bool bv;
 	int rc;
 
-	rc = get_user(c, buffer);
+	rc = kstrtobool_from_user(buffer, count, &traceSMB);
 	if (rc)
 		return rc;
 
-	rc = strtobool(&c, &bv);
-	if (rc)
-		return rc;
-
-	traceSMB = bv;
-
 	return count;
 }
 
@@ -622,7 +630,6 @@
 	int rc;
 	unsigned int flags;
 	char flags_string[12];
-	char c;
 	bool bv;
 
 	if ((count < 1) || (count > 11))
@@ -635,11 +642,10 @@
 
 	if (count < 3) {
 		/* single char or single char followed by null */
-		c = flags_string[0];
-		if (strtobool(&c, &bv) == 0) {
+		if (strtobool(flags_string, &bv) == 0) {
 			global_secflags = bv ? CIFSSEC_MAX : CIFSSEC_DEF;
 			return count;
-		} else if (!isdigit(c)) {
+		} else if (!isdigit(flags_string[0])) {
 			cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
 					flags_string);
 			return -EINVAL;
--- linux-4.4.0.orig/fs/cifs/cifs_debug.h
+++ linux-4.4.0/fs/cifs/cifs_debug.h
@@ -25,7 +25,7 @@
 void cifs_dump_mem(char *label, void *data, int length);
 void cifs_dump_detail(void *);
 void cifs_dump_mids(struct TCP_Server_Info *);
-extern int traceSMB;		/* flag which enables the function below */
+extern bool traceSMB;		/* flag which enables the function below */
 void dump_smb(void *, int);
 #define CIFS_INFO	0x01
 #define CIFS_RC		0x02
@@ -51,14 +51,13 @@
 /* information message: e.g., configuration, major event */
 #define cifs_dbg(type, fmt, ...)					\
 do {									\
-	if (type == FYI) {						\
-		if (cifsFYI & CIFS_INFO) {				\
-			pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__);	\
-		}							\
+	if (type == FYI && cifsFYI & CIFS_INFO) {			\
+		pr_debug_ratelimited("%s: "				\
+			    fmt, __FILE__, ##__VA_ARGS__);		\
 	} else if (type == VFS) {					\
 		cifs_vfs_err(fmt, ##__VA_ARGS__);			\
 	} else if (type == NOISY && type != 0) {			\
-		pr_debug(fmt, ##__VA_ARGS__);				\
+		pr_debug_ratelimited(fmt, ##__VA_ARGS__);		\
 	}								\
 } while (0)
 
--- linux-4.4.0.orig/fs/cifs/cifs_dfs_ref.c
+++ linux-4.4.0/fs/cifs/cifs_dfs_ref.c
@@ -241,7 +241,8 @@
  * @fullpath:		full path in UNC format
  * @ref:		server's referral
  */
-static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
+static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
+		struct cifs_sb_info *cifs_sb,
 		const char *fullpath, const struct dfs_info3_param *ref)
 {
 	struct vfsmount *mnt;
@@ -255,7 +256,7 @@
 	if (IS_ERR(mountdata))
 		return (struct vfsmount *)mountdata;
 
-	mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
+	mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
 	kfree(mountdata);
 	kfree(devname);
 	return mnt;
@@ -266,9 +267,9 @@
 {
 	cifs_dbg(FYI, "DFS: ref path: %s\n", ref->path_name);
 	cifs_dbg(FYI, "DFS: node path: %s\n", ref->node_name);
-	cifs_dbg(FYI, "DFS: fl: %hd, srv_type: %hd\n",
+	cifs_dbg(FYI, "DFS: fl: %d, srv_type: %d\n",
 		 ref->flags, ref->server_type);
-	cifs_dbg(FYI, "DFS: ref_flags: %hd, path_consumed: %hd\n",
+	cifs_dbg(FYI, "DFS: ref_flags: %d, path_consumed: %d\n",
 		 ref->ref_flag, ref->path_consumed);
 }
 
@@ -330,7 +331,7 @@
 			mnt = ERR_PTR(-EINVAL);
 			break;
 		}
-		mnt = cifs_dfs_do_refmount(cifs_sb,
+		mnt = cifs_dfs_do_refmount(mntpt, cifs_sb,
 				full_path, referrals + i);
 		cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n",
 			 __func__, referrals[i].node_name, mnt);
--- linux-4.4.0.orig/fs/cifs/cifs_fs_sb.h
+++ linux-4.4.0/fs/cifs/cifs_fs_sb.h
@@ -46,6 +46,9 @@
 #define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
 #define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
 #define CIFS_MOUNT_MAP_SFM_CHR	0x800000 /* SFM/MAC mapping for illegal chars */
+#define CIFS_MOUNT_USE_PREFIX_PATH 0x1000000 /* make subpath with unaccessible
+					      * root mountable
+					      */
 
 struct cifs_sb_info {
 	struct rb_root tlink_tree;
@@ -67,5 +70,6 @@
 	struct backing_dev_info bdi;
 	struct delayed_work prune_tlinks;
 	struct rcu_head rcu;
+	char *prepath;
 };
 #endif				/* _CIFS_FS_SB_H */
--- linux-4.4.0.orig/fs/cifs/cifs_spnego.c
+++ linux-4.4.0/fs/cifs/cifs_spnego.c
@@ -143,8 +143,10 @@
 		sprintf(dp, ";sec=krb5");
 	else if (server->sec_mskerberos)
 		sprintf(dp, ";sec=mskrb5");
-	else
-		goto out;
+	else {
+		cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n");
+		sprintf(dp, ";sec=krb5");
+	}
 
 	dp = description + strlen(description);
 	sprintf(dp, ";uid=0x%x",
--- linux-4.4.0.orig/fs/cifs/cifs_unicode.c
+++ linux-4.4.0/fs/cifs/cifs_unicode.c
@@ -83,6 +83,9 @@
 	case SFM_COLON:
 		*target = ':';
 		break;
+	case SFM_DOUBLEQUOTE:
+		*target = '"';
+		break;
 	case SFM_ASTERISK:
 		*target = '*';
 		break;
@@ -98,8 +101,11 @@
 	case SFM_LESSTHAN:
 		*target = '<';
 		break;
-	case SFM_SLASH:
-		*target = '\\';
+	case SFM_SPACE:
+		*target = ' ';
+		break;
+	case SFM_PERIOD:
+		*target = '.';
 		break;
 	default:
 		return false;
@@ -404,7 +410,7 @@
 	return dest_char;
 }
 
-static __le16 convert_to_sfm_char(char src_char)
+static __le16 convert_to_sfm_char(char src_char, bool end_of_string)
 {
 	__le16 dest_char;
 
@@ -412,6 +418,9 @@
 	case ':':
 		dest_char = cpu_to_le16(SFM_COLON);
 		break;
+	case '"':
+		dest_char = cpu_to_le16(SFM_DOUBLEQUOTE);
+		break;
 	case '*':
 		dest_char = cpu_to_le16(SFM_ASTERISK);
 		break;
@@ -427,6 +436,18 @@
 	case '|':
 		dest_char = cpu_to_le16(SFM_PIPE);
 		break;
+	case '.':
+		if (end_of_string)
+			dest_char = cpu_to_le16(SFM_PERIOD);
+		else
+			dest_char = 0;
+		break;
+	case ' ':
+		if (end_of_string)
+			dest_char = cpu_to_le16(SFM_SPACE);
+		else
+			dest_char = 0;
+		break;
 	default:
 		dest_char = 0;
 	}
@@ -469,9 +490,22 @@
 		/* see if we must remap this char */
 		if (map_chars == SFU_MAP_UNI_RSVD)
 			dst_char = convert_to_sfu_char(src_char);
-		else if (map_chars == SFM_MAP_UNI_RSVD)
-			dst_char = convert_to_sfm_char(src_char);
-		else
+		else if (map_chars == SFM_MAP_UNI_RSVD) {
+			bool end_of_string;
+
+			/**
+			 * Remap spaces and periods found at the end of every
+			 * component of the path. The special cases of '.' and
+			 * '..' do not need to be dealt with explicitly because
+			 * they are addressed in namei.c:link_path_walk().
+			 **/
+			if ((i == srclen - 1) || (source[i+1] == '\\'))
+				end_of_string = true;
+			else
+				end_of_string = false;
+
+			dst_char = convert_to_sfm_char(src_char, end_of_string);
+		} else
 			dst_char = 0;
 		/*
 		 * FIXME: We can not handle remapping backslash (UNI_SLASH)
--- linux-4.4.0.orig/fs/cifs/cifs_unicode.h
+++ linux-4.4.0/fs/cifs/cifs_unicode.h
@@ -57,6 +57,7 @@
  * not conflict (although almost does) with the mapping above.
  */
 
+#define SFM_DOUBLEQUOTE ((__u16) 0xF020)
 #define SFM_ASTERISK    ((__u16) 0xF021)
 #define SFM_QUESTION    ((__u16) 0xF025)
 #define SFM_COLON       ((__u16) 0xF022)
@@ -64,6 +65,8 @@
 #define SFM_LESSTHAN    ((__u16) 0xF023)
 #define SFM_PIPE        ((__u16) 0xF027)
 #define SFM_SLASH       ((__u16) 0xF026)
+#define SFM_SPACE	((__u16) 0xF028)
+#define SFM_PERIOD	((__u16) 0xF029)
 
 /*
  * Mapping mechanism to use when one of the seven reserved characters is
--- linux-4.4.0.orig/fs/cifs/cifsacl.c
+++ linux-4.4.0/fs/cifs/cifsacl.c
@@ -480,7 +480,7 @@
 			((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
 		*pmode |= (S_IXUGO & (*pbits_to_set));
 
-	cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", flags, *pmode);
+	cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode);
 	return;
 }
 
@@ -509,7 +509,7 @@
 	if (mode & S_IXUGO)
 		*pace_flags |= SET_FILE_EXEC_RIGHTS;
 
-	cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
+	cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n",
 		 mode, *pace_flags);
 	return;
 }
--- linux-4.4.0.orig/fs/cifs/cifsencrypt.c
+++ linux-4.4.0/fs/cifs/cifsencrypt.c
@@ -33,6 +33,7 @@
 #include <linux/ctype.h>
 #include <linux/random.h>
 #include <linux/highmem.h>
+#include <crypto/aead.h>
 
 static int
 cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
@@ -65,6 +66,56 @@
 	return 0;
 }
 
+int __cifs_calc_signature(struct smb_rqst *rqst,
+			struct TCP_Server_Info *server, char *signature,
+			struct shash_desc *shash)
+{
+	int i;
+	int rc;
+	struct kvec *iov = rqst->rq_iov;
+	int n_vec = rqst->rq_nvec;
+
+	if (n_vec < 2 || iov[0].iov_len != 4)
+		return -EIO;
+
+	for (i = 1; i < n_vec; i++) {
+		if (iov[i].iov_len == 0)
+			continue;
+		if (iov[i].iov_base == NULL) {
+			cifs_dbg(VFS, "null iovec entry\n");
+			return -EIO;
+		}
+		if (i == 1 && iov[1].iov_len <= 4)
+			break; /* nothing to sign or corrupt header */
+		rc = crypto_shash_update(shash,
+					 iov[i].iov_base, iov[i].iov_len);
+		if (rc) {
+			cifs_dbg(VFS, "%s: Could not update with payload\n",
+				 __func__);
+			return rc;
+		}
+	}
+
+	/* now hash over the rq_pages array */
+	for (i = 0; i < rqst->rq_npages; i++) {
+		void *kaddr = kmap(rqst->rq_pages[i]);
+		size_t len = rqst->rq_pagesz;
+
+		if (i == rqst->rq_npages - 1)
+			len = rqst->rq_tailsz;
+
+		crypto_shash_update(shash, kaddr, len);
+
+		kunmap(rqst->rq_pages[i]);
+	}
+
+	rc = crypto_shash_final(shash, signature);
+	if (rc)
+		cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
+
+	return rc;
+}
+
 /*
  * Calculate and return the CIFS signature based on the mac key and SMB PDU.
  * The 16 byte signature must be allocated by the caller. Note we only use the
@@ -75,12 +126,9 @@
 static int cifs_calc_signature(struct smb_rqst *rqst,
 			struct TCP_Server_Info *server, char *signature)
 {
-	int i;
 	int rc;
-	struct kvec *iov = rqst->rq_iov;
-	int n_vec = rqst->rq_nvec;
 
-	if (iov == NULL || signature == NULL || server == NULL)
+	if (!rqst->rq_iov || !signature || !server)
 		return -EINVAL;
 
 	if (!server->secmech.sdescmd5) {
@@ -104,48 +152,8 @@
 		return rc;
 	}
 
-	for (i = 0; i < n_vec; i++) {
-		if (iov[i].iov_len == 0)
-			continue;
-		if (iov[i].iov_base == NULL) {
-			cifs_dbg(VFS, "null iovec entry\n");
-			return -EIO;
-		}
-		/* The first entry includes a length field (which does not get
-		   signed that occupies the first 4 bytes before the header */
-		if (i == 0) {
-			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
-				break; /* nothing to sign or corrupt header */
-			rc =
-			crypto_shash_update(&server->secmech.sdescmd5->shash,
-				iov[i].iov_base + 4, iov[i].iov_len - 4);
-		} else {
-			rc =
-			crypto_shash_update(&server->secmech.sdescmd5->shash,
-				iov[i].iov_base, iov[i].iov_len);
-		}
-		if (rc) {
-			cifs_dbg(VFS, "%s: Could not update with payload\n",
-				 __func__);
-			return rc;
-		}
-	}
-
-	/* now hash over the rq_pages array */
-	for (i = 0; i < rqst->rq_npages; i++) {
-		struct kvec p_iov;
-
-		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
-		crypto_shash_update(&server->secmech.sdescmd5->shash,
-					p_iov.iov_base, p_iov.iov_len);
-		kunmap(rqst->rq_pages[i]);
-	}
-
-	rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
-	if (rc)
-		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
-
-	return rc;
+	return __cifs_calc_signature(rqst, server, signature,
+				     &server->secmech.sdescmd5->shash);
 }
 
 /* must be called with server->srv_mutex held */
@@ -156,6 +164,10 @@
 	char smb_signature[20];
 	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
+	if (rqst->rq_iov[0].iov_len != 4 ||
+	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+		return -EIO;
+
 	if ((cifs_pdu == NULL) || (server == NULL))
 		return -EINVAL;
 
@@ -197,12 +209,14 @@
 int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
 		  __u32 *pexpected_response_sequence_number)
 {
-	struct kvec iov;
+	struct kvec iov[2];
 
-	iov.iov_base = cifs_pdu;
-	iov.iov_len = be32_to_cpu(cifs_pdu->smb_buf_length) + 4;
+	iov[0].iov_base = cifs_pdu;
+	iov[0].iov_len = 4;
+	iov[1].iov_base = (char *)cifs_pdu + 4;
+	iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
 
-	return cifs_sign_smbv(&iov, 1, server,
+	return cifs_sign_smbv(iov, 2, server,
 			      pexpected_response_sequence_number);
 }
 
@@ -215,6 +229,10 @@
 	char what_we_think_sig_should_be[20];
 	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
+	if (rqst->rq_iov[0].iov_len != 4 ||
+	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+		return -EIO;
+
 	if (cifs_pdu == NULL || server == NULL)
 		return -EINVAL;
 
@@ -306,9 +324,8 @@
 {
 	int i;
 	int rc;
-	char password_with_pad[CIFS_ENCPWD_SIZE];
+	char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
 
-	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
 	if (password)
 		strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
 
@@ -714,7 +731,7 @@
 
 	ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
 	if (!ses->auth_key.response) {
-		rc = ENOMEM;
+		rc = -ENOMEM;
 		ses->auth_key.len = 0;
 		goto setup_ntlmv2_rsp_ret;
 	}
@@ -731,24 +748,26 @@
 
 	memcpy(ses->auth_key.response + baselen, tiblob, tilen);
 
+	mutex_lock(&ses->server->srv_mutex);
+
 	rc = crypto_hmacmd5_alloc(ses->server);
 	if (rc) {
 		cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
-		goto setup_ntlmv2_rsp_ret;
+		goto unlock;
 	}
 
 	/* calculate ntlmv2_hash */
 	rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
 	if (rc) {
 		cifs_dbg(VFS, "could not get v2 hash rc %d\n", rc);
-		goto setup_ntlmv2_rsp_ret;
+		goto unlock;
 	}
 
 	/* calculate first part of the client response (CR1) */
 	rc = CalcNTLMv2_response(ses, ntlmv2_hash);
 	if (rc) {
 		cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc);
-		goto setup_ntlmv2_rsp_ret;
+		goto unlock;
 	}
 
 	/* now calculate the session key for NTLMv2 */
@@ -757,13 +776,13 @@
 	if (rc) {
 		cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
 			 __func__);
-		goto setup_ntlmv2_rsp_ret;
+		goto unlock;
 	}
 
 	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
 	if (rc) {
 		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
-		goto setup_ntlmv2_rsp_ret;
+		goto unlock;
 	}
 
 	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
@@ -771,7 +790,7 @@
 		CIFS_HMAC_MD5_HASH_SIZE);
 	if (rc) {
 		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
-		goto setup_ntlmv2_rsp_ret;
+		goto unlock;
 	}
 
 	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
@@ -779,6 +798,8 @@
 	if (rc)
 		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
 
+unlock:
+	mutex_unlock(&ses->server->srv_mutex);
 setup_ntlmv2_rsp_ret:
 	kfree(tiblob);
 
@@ -834,7 +855,7 @@
 }
 
 void
-cifs_crypto_shash_release(struct TCP_Server_Info *server)
+cifs_crypto_secmech_release(struct TCP_Server_Info *server)
 {
 	if (server->secmech.cmacaes) {
 		crypto_free_shash(server->secmech.cmacaes);
@@ -856,6 +877,16 @@
 		server->secmech.hmacmd5 = NULL;
 	}
 
+	if (server->secmech.ccmaesencrypt) {
+		crypto_free_aead(server->secmech.ccmaesencrypt);
+		server->secmech.ccmaesencrypt = NULL;
+	}
+
+	if (server->secmech.ccmaesdecrypt) {
+		crypto_free_aead(server->secmech.ccmaesdecrypt);
+		server->secmech.ccmaesdecrypt = NULL;
+	}
+
 	kfree(server->secmech.sdesccmacaes);
 	server->secmech.sdesccmacaes = NULL;
 	kfree(server->secmech.sdeschmacsha256);
--- linux-4.4.0.orig/fs/cifs/cifsfs.c
+++ linux-4.4.0/fs/cifs/cifsfs.c
@@ -54,10 +54,10 @@
 #endif
 
 int cifsFYI = 0;
-int traceSMB = 0;
+bool traceSMB;
 bool enable_oplocks = true;
-unsigned int linuxExtEnabled = 1;
-unsigned int lookupCacheEnabled = 1;
+bool linuxExtEnabled = true;
+bool lookupCacheEnabled = true;
 unsigned int global_secflags = CIFSSEC_DEF;
 /* unsigned int ntlmv2_support = 0; */
 unsigned int sign_CIFS_PDUs = 1;
@@ -204,7 +204,7 @@
 		rc = server->ops->queryfs(xid, tcon, buf);
 
 	free_xid(xid);
-	return 0;
+	return rc;
 }
 
 static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
@@ -268,7 +268,7 @@
 	cifs_inode->createtime = 0;
 	cifs_inode->epoch = 0;
 #ifdef CONFIG_CIFS_SMB2
-	get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
+	generate_random_uuid(cifs_inode->lease_key);
 #endif
 	/*
 	 * Can not set i_flags here - they get immediately overwritten to zero
@@ -507,6 +507,8 @@
 
 	seq_printf(s, ",rsize=%u", cifs_sb->rsize);
 	seq_printf(s, ",wsize=%u", cifs_sb->wsize);
+	seq_printf(s, ",echo_interval=%lu",
+			tcon->ses->server->echo_interval / HZ);
 	/* convert actimeo and display it in seconds */
 	seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
 
@@ -683,10 +685,14 @@
 	cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
 	if (cifs_sb->mountdata == NULL) {
 		root = ERR_PTR(-ENOMEM);
-		goto out_cifs_sb;
+		goto out_free;
 	}
 
-	cifs_setup_cifs_sb(volume_info, cifs_sb);
+	rc = cifs_setup_cifs_sb(volume_info, cifs_sb);
+	if (rc) {
+		root = ERR_PTR(rc);
+		goto out_free;
+	}
 
 	rc = cifs_mount(cifs_sb, volume_info);
 	if (rc) {
@@ -694,7 +700,7 @@
 			cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n",
 				 rc);
 		root = ERR_PTR(rc);
-		goto out_mountdata;
+		goto out_free;
 	}
 
 	mnt_data.vol = volume_info;
@@ -724,7 +730,11 @@
 		sb->s_flags |= MS_ACTIVE;
 	}
 
-	root = cifs_get_root(volume_info, sb);
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+		root = dget(sb->s_root);
+	else
+		root = cifs_get_root(volume_info, sb);
+
 	if (IS_ERR(root))
 		goto out_super;
 
@@ -737,9 +747,9 @@
 	cifs_cleanup_volume_info(volume_info);
 	return root;
 
-out_mountdata:
+out_free:
+	kfree(cifs_sb->prepath);
 	kfree(cifs_sb->mountdata);
-out_cifs_sb:
 	kfree(cifs_sb);
 out_nls:
 	unload_nls(volume_info->local_nls);
@@ -1198,7 +1208,6 @@
 	GlobalTotalActiveXid = 0;
 	GlobalMaxActiveXid = 0;
 	spin_lock_init(&cifs_tcp_ses_lock);
-	spin_lock_init(&cifs_file_list_lock);
 	spin_lock_init(&GlobalMid_Lock);
 
 	if (cifs_max_pending < 2) {
@@ -1299,5 +1308,19 @@
     ("VFS to access servers complying with the SNIA CIFS Specification "
      "e.g. Samba and Windows");
 MODULE_VERSION(CIFS_VERSION);
+MODULE_SOFTDEP("pre: arc4");
+MODULE_SOFTDEP("pre: des");
+MODULE_SOFTDEP("pre: ecb");
+MODULE_SOFTDEP("pre: hmac");
+MODULE_SOFTDEP("pre: md4");
+MODULE_SOFTDEP("pre: md5");
+MODULE_SOFTDEP("pre: nls");
+#ifdef CONFIG_CIFS_SMB2
+MODULE_SOFTDEP("pre: aes");
+MODULE_SOFTDEP("pre: cmac");
+MODULE_SOFTDEP("pre: sha256");
+MODULE_SOFTDEP("pre: aead2");
+MODULE_SOFTDEP("pre: ccm");
+#endif /* CONFIG_CIFS_SMB2 */
 module_init(init_cifs)
 module_exit(exit_cifs)
--- linux-4.4.0.orig/fs/cifs/cifsfs.h
+++ linux-4.4.0/fs/cifs/cifsfs.h
@@ -31,19 +31,15 @@
  * so that it will fit. We use hash_64 to convert the value to 31 bits, and
  * then add 1, to ensure that we don't end up with a 0 as the value.
  */
-#if BITS_PER_LONG == 64
 static inline ino_t
 cifs_uniqueid_to_ino_t(u64 fileid)
 {
+	if ((sizeof(ino_t)) < (sizeof(u64)))
+		return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1;
+
 	return (ino_t)fileid;
+
 }
-#else
-static inline ino_t
-cifs_uniqueid_to_ino_t(u64 fileid)
-{
-	return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1;
-}
-#endif
 
 extern struct file_system_type cifs_fs_type;
 extern const struct address_space_operations cifs_addr_ops;
--- linux-4.4.0.orig/fs/cifs/cifsglob.h
+++ linux-4.4.0/fs/cifs/cifsglob.h
@@ -70,8 +70,22 @@
 #define SERVER_NAME_LENGTH 40
 #define SERVER_NAME_LEN_WITH_NULL     (SERVER_NAME_LENGTH + 1)
 
-/* SMB echo "timeout" -- FIXME: tunable? */
-#define SMB_ECHO_INTERVAL (60 * HZ)
+/* echo interval in seconds */
+#define SMB_ECHO_INTERVAL_MIN 1
+#define SMB_ECHO_INTERVAL_MAX 600
+#define SMB_ECHO_INTERVAL_DEFAULT 60
+
+/*
+ * Default number of credits to keep available for SMB3.
+ * This value is chosen somewhat arbitrarily. The Windows client
+ * defaults to 128 credits, the Windows server allows clients up to
+ * 512 credits (or 8K for later versions), and the NetApp server
+ * does not limit clients at all.  Choose a high enough default value
+ * such that the client shouldn't limit performance, but allow mount
+ * to override (until you approach 64K, where we limit credits to 65000
+ * to reduce possibility of seeing more server credit overflow bugs.
+ */
+#define SMB2_MAX_CREDITS_AVAILABLE 32000
 
 #include "cifspdu.h"
 
@@ -122,6 +136,8 @@
 	struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
 	struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
 	struct sdesc *sdesccmacaes;  /* ctxt to generate smb3 signature */
+	struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */
+	struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */
 };
 
 /* per smb session structure/fields */
@@ -194,7 +210,7 @@
 struct cifs_open_parms;
 
 struct smb_version_operations {
-	int (*send_cancel)(struct TCP_Server_Info *, void *,
+	int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
 			   struct mid_q_entry *);
 	bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
 	/* setup request: allocate mid, sign message */
@@ -225,8 +241,9 @@
 	void (*print_stats)(struct seq_file *m, struct cifs_tcon *);
 	void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *);
 	/* verify the message */
-	int (*check_message)(char *, unsigned int);
+	int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
 	bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
+	int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *);
 	void (*downgrade_oplock)(struct TCP_Server_Info *,
 					struct cifsInodeInfo *, bool);
 	/* process transaction2 response */
@@ -350,6 +367,8 @@
 	unsigned int (*calc_smb_size)(void *);
 	/* check for STATUS_PENDING and process it in a positive case */
 	bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
+	/* check for STATUS_NETWORK_SESSION_EXPIRED */
+	bool (*is_session_expired)(char *);
 	/* send oplock break response */
 	int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
 			       struct cifsInodeInfo *);
@@ -417,6 +436,14 @@
 	bool (*dir_needs_close)(struct cifsFileInfo *);
 	long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
 			  loff_t);
+	/* init transform request - used for encryption for now */
+	int (*init_transform_rq)(struct TCP_Server_Info *, struct smb_rqst *,
+				 struct smb_rqst *);
+	/* free transform request */
+	void (*free_transform_rq)(struct smb_rqst *);
+	int (*is_transform_hdr)(void *buf);
+	int (*receive_transform)(struct TCP_Server_Info *,
+				 struct mid_q_entry **);
 };
 
 struct smb_version_values {
@@ -507,6 +534,9 @@
 	struct sockaddr_storage dstaddr; /* destination address */
 	struct sockaddr_storage srcaddr; /* allow binding to a local IP */
 	struct nls_table *local_nls;
+	unsigned int echo_interval; /* echo interval in secs */
+	__u64 snapshot_time; /* needed for timewarp tokens */
+	unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
 };
 
 #define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
@@ -564,7 +594,8 @@
 	bool noblocksnd;		/* use blocking sendmsg */
 	bool noautotune;		/* do not autotune send buf sizes */
 	bool tcp_nodelay;
-	int credits;  /* send no more requests at once */
+	unsigned int credits;  /* send no more requests at once */
+	unsigned int max_credits; /* can override large 32000 default at mnt */
 	unsigned int in_flight;  /* number of requests on the wire to server */
 	spinlock_t req_lock;  /* protect the two values above */
 	struct mutex srv_mutex;
@@ -612,8 +643,6 @@
 	bool	sec_mskerberos;		/* supports legacy MS Kerberos */
 	bool	large_buf;		/* is current buffer large? */
 	struct delayed_work	echo; /* echo ping workqueue job */
-	struct kvec *iov;	/* reusable kvec array for receives */
-	unsigned int nr_iov;	/* number of kvecs in array */
 	char	*smallbuf;	/* pointer to current "small" buffer */
 	char	*bigbuf;	/* pointer to current "big" buffer */
 	unsigned int total_read; /* total amount of data read in this pass */
@@ -627,7 +656,11 @@
 #ifdef CONFIG_CIFS_SMB2
 	unsigned int	max_read;
 	unsigned int	max_write;
+	struct delayed_work reconnect; /* reconnect workqueue job */
+	struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
+	__u8		preauth_hash[512];
 #endif /* CONFIG_CIFS_SMB2 */
+	unsigned long echo_interval;
 };
 
 static inline unsigned int
@@ -809,7 +842,10 @@
 	bool need_reconnect:1; /* connection reset, uid now invalid */
 #ifdef CONFIG_CIFS_SMB2
 	__u16 session_flags;
-	char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
+	__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
+	__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
+	__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
+	__u8 preauth_hash[512];
 #endif /* CONFIG_CIFS_SMB2 */
 };
 
@@ -826,7 +862,9 @@
 struct cifs_tcon {
 	struct list_head tcon_list;
 	int tc_count;
+	struct list_head rlist; /* reconnect list */
 	struct list_head openFileList;
+	spinlock_t open_file_lock; /* protects list above */
 	struct cifs_ses *ses;	/* pointer to session associated with */
 	char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
 	char *nativeFileSystem;
@@ -883,7 +921,7 @@
 #endif /* CONFIG_CIFS_STATS2 */
 	__u64    bytes_read;
 	__u64    bytes_written;
-	spinlock_t stat_lock;
+	spinlock_t stat_lock;  /* protects the two fields above */
 #endif /* CONFIG_CIFS_STATS */
 	FILE_SYSTEM_DEVICE_INFO fsDevInfo;
 	FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
@@ -902,12 +940,12 @@
 	bool use_persistent:1; /* use persistent instead of durable handles */
 #ifdef CONFIG_CIFS_SMB2
 	bool print:1;		/* set if connection to printer share */
-	bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
 	__le32 capabilities;
 	__u32 share_flags;
 	__u32 maximal_access;
 	__u32 vol_serial_number;
 	__le64 vol_create_time;
+	__u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
 	__u32 ss_flags;		/* sector size flags */
 	__u32 perf_sector_size; /* best sector size for perf */
 	__u32 max_chunks;
@@ -1034,8 +1072,10 @@
 };
 
 struct cifsFileInfo {
+	/* following two lists are protected by tcon->open_file_lock */
 	struct list_head tlist;	/* pointer to next fid owned by tcon */
 	struct list_head flist;	/* next fid (file instance) for this inode */
+	/* lock list below protected by cifsi->lock_sem */
 	struct cifs_fid_locks *llist;	/* brlocks held by this fid */
 	kuid_t uid;		/* allows finding which FileInfo structure */
 	__u32 pid;		/* process id who opened file */
@@ -1043,11 +1083,12 @@
 	/* BB add lock scope info here if needed */ ;
 	/* lock scope id (0 if none) */
 	struct dentry *dentry;
-	unsigned int f_flags;
 	struct tcon_link *tlink;
+	unsigned int f_flags;
 	bool invalidHandle:1;	/* file closed via session abend */
 	bool oplock_break_cancelled:1;
-	int count;		/* refcount protected by cifs_file_list_lock */
+	int count;
+	spinlock_t file_info_lock; /* protects four flag/count fields above */
 	struct mutex fh_mutex; /* prevents reopen race after dead ses*/
 	struct cifs_search_info srch_inf;
 	struct work_struct oplock_break; /* work for oplock breaks */
@@ -1083,7 +1124,10 @@
 	int (*read_into_pages)(struct TCP_Server_Info *server,
 				struct cifs_readdata *rdata,
 				unsigned int len);
-	struct kvec			iov;
+	int (*copy_into_pages)(struct TCP_Server_Info *server,
+				struct cifs_readdata *rdata,
+				struct iov_iter *iter);
+	struct kvec			iov[2];
 	unsigned int			pagesz;
 	unsigned int			tailsz;
 	unsigned int			credits;
@@ -1114,7 +1158,7 @@
 
 /*
  * Take a reference on the file private data. Must be called with
- * cifs_file_list_lock held.
+ * cfile->file_info_lock held.
  */
 static inline void
 cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
@@ -1143,6 +1187,11 @@
 struct cifsInodeInfo {
 	bool can_cache_brlcks;
 	struct list_head llist;	/* locks helb by this inode */
+	/*
+	 * NOTE: Some code paths call down_read(lock_sem) twice, so
+	 * we must always use use cifs_down_write() instead of down_write()
+	 * for this semaphore to avoid deadlocks.
+	 */
 	struct rw_semaphore lock_sem;	/* protect the fields above */
 	/* BB add in lists for dirty pages i.e. write caching info for oplock */
 	struct list_head openFileList;
@@ -1266,6 +1315,13 @@
  */
 typedef void (mid_callback_t)(struct mid_q_entry *mid);
 
+/*
+ * This is the protopyte for mid handle function. This is called once the mid
+ * has been recognized after decryption of the message.
+ */
+typedef int (mid_handle_t)(struct TCP_Server_Info *server,
+			    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 */
@@ -1280,13 +1336,22 @@
 #endif
 	mid_receive_t *receive; /* call receive callback */
 	mid_callback_t *callback; /* call completion callback */
+	mid_handle_t *handle; /* call handle mid callback */
 	void *callback_data;	  /* general purpose pointer for callback */
 	void *resp_buf;		/* pointer to received SMB header */
 	int mid_state;	/* wish this were enum but can not pass to wait_event */
+	unsigned int mid_flags;
 	__le16 command;		/* smb command code */
 	bool large_buf:1;	/* if valid response, is pointer to large buf */
 	bool multiRsp:1;	/* multiple trans2 responses for one request  */
 	bool multiEnd:1;	/* both received */
+	bool decrypted:1;	/* decrypted entry */
+};
+
+struct close_cancelled_open {
+	struct cifs_fid         fid;
+	struct cifs_tcon        *tcon;
+	struct work_struct      work;
 };
 
 /*	Make code in transport.c a little cleaner by moving
@@ -1420,6 +1485,9 @@
 #define   MID_RESPONSE_MALFORMED 0x10
 #define   MID_SHUTDOWN		 0x20
 
+/* Flags */
+#define   MID_WAIT_CANCELLED	 1 /* Cancelled while waiting for response */
+
 /* Types of response buffer returned from SendReceive2 */
 #define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
 #define   CIFS_SMALL_BUFFER     1
@@ -1439,7 +1507,9 @@
 #define   CIFS_OBREAK_OP   0x0100    /* oplock break request */
 #define   CIFS_NEG_OP      0x0200    /* negotiate request */
 #define   CIFS_OP_MASK     0x0380    /* mask request type */
+
 #define   CIFS_HAS_CREDITS 0x0400    /* already has credits */
+#define   CIFS_TRANSFORM_REQ 0x0800    /* transform request before sending */
 
 /* Security Flags: indicate type of session setup needed */
 #define   CIFSSEC_MAY_SIGN	0x00001
@@ -1508,8 +1578,10 @@
  *  GlobalMid_Lock protects:
  *	list operations on pending_mid_q and oplockQ
  *      updates to XID counters, multiplex id  and SMB sequence numbers
- *  cifs_file_list_lock protects:
- *	list operations on tcp and SMB session lists and tCon lists
+ *  tcp_ses_lock protects:
+ *	list operations on tcp and SMB session lists
+ *  tcon->open_file_lock protects the list of open files hanging off the tcon
+ *  cfile->file_info_lock protects counters and fields in cifs file struct
  *  f_owner.lock protects certain per file struct operations
  *  mapping->page_lock protects certain per page operations
  *
@@ -1541,18 +1613,12 @@
  * tcp session, and the list of tcon's per smb session. It also protects
  * the reference counters for the server, smb session, and tcon. Finally,
  * changes to the tcon->tidStatus should be done while holding this lock.
+ * generally the locks should be taken in order tcp_ses_lock before
+ * tcon->open_file_lock and that before file->file_info_lock since the
+ * structure order is cifs_socket-->cifs_ses-->cifs_tcon-->cifs_file
  */
 GLOBAL_EXTERN spinlock_t		cifs_tcp_ses_lock;
 
-/*
- * This lock protects the cifs_file->llist and cifs_file->flist
- * list operations, and updates to some flags (cifs_file->invalidHandle)
- * It will be moved to either use the tcon->stat_lock or equivalent later.
- * If cifs_tcp_ses_lock and the lock below are both needed to be held, then
- * the cifs_tcp_ses_lock must be grabbed first and released last.
- */
-GLOBAL_EXTERN spinlock_t	cifs_file_list_lock;
-
 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
 /* Outstanding dir notify requests */
 GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
@@ -1588,11 +1654,11 @@
 
 /* Misc globals */
 GLOBAL_EXTERN bool enable_oplocks; /* enable or disable oplocks */
-GLOBAL_EXTERN unsigned int lookupCacheEnabled;
+GLOBAL_EXTERN bool lookupCacheEnabled;
 GLOBAL_EXTERN unsigned int global_secflags;	/* if on, session setup sent
 				with more secure ntlmssp2 challenge/resp */
 GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
-GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
+GLOBAL_EXTERN bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
 GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
 GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
 GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
@@ -1636,4 +1702,15 @@
 #define ALT_SMB311_VERSION_STRING "3.11"
 extern struct smb_version_operations smb311_operations;
 extern struct smb_version_values smb311_values;
+
+static inline bool cifs_ses_exiting(struct cifs_ses *ses)
+{
+	bool ret;
+
+	spin_lock(&GlobalMid_Lock);
+	ret = ses->status == CifsExiting;
+	spin_unlock(&GlobalMid_Lock);
+	return ret;
+}
+
 #endif	/* _CIFS_GLOB_H */
--- linux-4.4.0.orig/fs/cifs/cifsproto.h
+++ linux-4.4.0/fs/cifs/cifsproto.h
@@ -74,10 +74,16 @@
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
 extern void cifs_delete_mid(struct mid_q_entry *mid);
 extern void cifs_wake_up_task(struct mid_q_entry *mid);
+extern int cifs_handle_standard(struct TCP_Server_Info *server,
+				struct mid_q_entry *mid);
+extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 extern int cifs_call_async(struct TCP_Server_Info *server,
 			struct smb_rqst *rqst,
 			mid_receive_t *receive, mid_callback_t *callback,
-			void *cbdata, const int flags);
+			mid_handle_t *handle, void *cbdata, const int flags);
+extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
+			  struct smb_rqst *rqst, int *resp_buf_type,
+			  const int flags, struct kvec *resp_iov);
 extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 			struct smb_hdr * /* input */ ,
 			struct smb_hdr * /* out */ ,
@@ -95,14 +101,15 @@
 				 unsigned int *credits);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
 			struct kvec *, int /* nvec to send */,
-			int * /* type of buf returned */ , const int flags);
+			int * /* type of buf returned */, const int flags,
+			struct kvec * /* resp vec */);
 extern int SendReceiveBlockingLock(const unsigned int xid,
 			struct cifs_tcon *ptcon,
 			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 int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr);
 extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
 extern bool backup_cred(struct cifs_sb_info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
@@ -138,6 +145,7 @@
 			     struct file_lock *flock, const unsigned int xid);
 extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);
 
+extern void cifs_down_write(struct rw_semaphore *sem);
 extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
 					      struct file *file,
 					      struct tcon_link *tlink,
@@ -181,11 +189,10 @@
 
 extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
 extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
-		     unsigned int to_read);
-extern int cifs_readv_from_socket(struct TCP_Server_Info *server,
-		struct kvec *iov_orig, unsigned int nr_segs,
-		unsigned int to_read);
-extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
+			         unsigned int to_read);
+extern int cifs_read_page_from_socket(struct TCP_Server_Info *server,
+				      struct page *page, unsigned int to_read);
+extern int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
 			       struct cifs_sb_info *cifs_sb);
 extern int cifs_match_super(struct super_block *, void *);
 extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info);
@@ -205,6 +212,9 @@
 					 struct tcon_link *tlink,
 					 struct cifs_pending_open *open);
 extern void cifs_del_pending_open(struct cifs_pending_open *open);
+extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
+				 int from_reconnect);
+extern void cifs_put_tcon(struct cifs_tcon *tcon);
 
 #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_dfs_release_automount_timer(void);
@@ -437,9 +447,10 @@
 			const struct nls_table *);
 extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
 extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
-extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
+extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
 extern int calc_seckey(struct cifs_ses *);
-extern int generate_smb3signingkey(struct cifs_ses *);
+extern int generate_smb30signingkey(struct cifs_ses *);
+extern int generate_smb311signingkey(struct cifs_ses *);
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 extern int calc_lanman_hash(const char *password, const char *cryptkey,
@@ -511,4 +522,7 @@
 			   struct cifs_sb_info *cifs_sb,
 			   const unsigned char *path, char *pbuf,
 			   unsigned int *pbytes_written);
+int __cifs_calc_signature(struct smb_rqst *rqst,
+			struct TCP_Server_Info *server, char *signature,
+			struct shash_desc *shash);
 #endif			/* _CIFSPROTO_H */
--- linux-4.4.0.orig/fs/cifs/cifssmb.c
+++ linux-4.4.0/fs/cifs/cifssmb.c
@@ -98,13 +98,13 @@
 	struct list_head *tmp1;
 
 	/* list all files open on tree connection and mark them invalid */
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&tcon->open_file_lock);
 	list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
 		open_file = list_entry(tmp, struct cifsFileInfo, tlist);
 		open_file->invalidHandle = true;
 		open_file->oplock_break_cancelled = true;
 	}
-	spin_unlock(&cifs_file_list_lock);
+	spin_unlock(&tcon->open_file_lock);
 	/*
 	 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
 	 * to this tcon.
@@ -150,8 +150,14 @@
 	 * greater than cifs socket timeout which is 7 seconds
 	 */
 	while (server->tcpStatus == CifsNeedReconnect) {
-		wait_event_interruptible_timeout(server->response_q,
-			(server->tcpStatus != CifsNeedReconnect), 10 * HZ);
+		rc = wait_event_interruptible_timeout(server->response_q,
+						      (server->tcpStatus != CifsNeedReconnect),
+						      10 * HZ);
+		if (rc < 0) {
+			cifs_dbg(FYI, "%s: aborting reconnect due to a received"
+				 " signal by the process\n", __func__);
+			return -ERESTARTSYS;
+		}
 
 		/* are we still trying to reconnect? */
 		if (server->tcpStatus != CifsNeedReconnect)
@@ -178,6 +184,18 @@
 	 * reconnect the same SMB session
 	 */
 	mutex_lock(&ses->session_mutex);
+
+	/*
+	 * Recheck after acquire mutex. If another thread is negotiating
+	 * and the server never sends an answer the socket will be closed
+	 * and tcpStatus set to reconnect.
+	 */
+	if (server->tcpStatus == CifsNeedReconnect) {
+		rc = -EHOSTDOWN;
+		mutex_unlock(&ses->session_mutex);
+		goto out;
+	}
+
 	rc = cifs_negotiate_protocol(0, ses);
 	if (rc == 0 && ses->need_reconnect)
 		rc = cifs_setup_session(0, ses, nls_codepage);
@@ -571,10 +589,15 @@
 	}
 
 	count = 0;
+	/*
+	 * We know that all the name entries in the protocols array
+	 * are short (< 16 bytes anyway) and are NUL terminated.
+	 */
 	for (i = 0; i < CIFS_NUM_PROT; i++) {
-		strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
-		count += strlen(protocols[i].name) + 1;
-		/* null at end of source and target buffers anyway */
+		size_t len = strlen(protocols[i].name) + 1;
+
+		memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
+		count += len;
 	}
 	inc_rfc1001_len(pSMB, count);
 	pSMB->ByteCount = cpu_to_le16(count);
@@ -673,6 +696,7 @@
 		return rc;
 
 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
+	cifs_small_buf_release(smb_buffer);
 	if (rc)
 		cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
 
@@ -707,9 +731,9 @@
 {
 	ECHO_REQ *smb;
 	int rc = 0;
-	struct kvec iov;
-	struct smb_rqst rqst = { .rq_iov = &iov,
-				 .rq_nvec = 1 };
+	struct kvec iov[2];
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = 2 };
 
 	cifs_dbg(FYI, "In echo request\n");
 
@@ -717,6 +741,9 @@
 	if (rc)
 		return rc;
 
+	if (server->capabilities & CAP_UNICODE)
+		smb->hdr.Flags2 |= SMBFLG2_UNICODE;
+
 	/* set up echo request */
 	smb->hdr.Tid = 0xffff;
 	smb->hdr.WordCount = 1;
@@ -724,10 +751,13 @@
 	put_bcc(1, &smb->hdr);
 	smb->Data[0] = 'a';
 	inc_rfc1001_len(smb, 3);
-	iov.iov_base = smb;
-	iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
-	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
+	iov[0].iov_len = 4;
+	iov[0].iov_base = smb;
+	iov[1].iov_len = get_rfc1002_length(smb);
+	iov[1].iov_base = (char *)smb + 4;
+
+	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
 			     server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
 	if (rc)
 		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
@@ -772,6 +802,7 @@
 
 	pSMB->AndXCommand = 0xFF;
 	rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
+	cifs_small_buf_release(pSMB);
 session_already_dead:
 	mutex_unlock(&ses->session_mutex);
 
@@ -1395,12 +1426,11 @@
  * Discard any remaining data in the current SMB. To do this, we borrow the
  * current bigbuf.
  */
-static int
-cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+int
+cifs_discard_remaining_data(struct TCP_Server_Info *server)
 {
 	unsigned int rfclen = get_rfc1002_length(server->smallbuf);
 	int remaining = rfclen + 4 - server->total_read;
-	struct cifs_readdata *rdata = mid->callback_data;
 
 	while (remaining > 0) {
 		int length;
@@ -1414,10 +1444,22 @@
 		remaining -= length;
 	}
 
-	dequeue_mid(mid, rdata->result);
 	return 0;
 }
 
+static int
+cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+{
+	int length;
+	struct cifs_readdata *rdata = mid->callback_data;
+
+	length = cifs_discard_remaining_data(server);
+	dequeue_mid(mid, rdata->result);
+	mid->resp_buf = server->smallbuf;
+	server->smallbuf = NULL;
+	return length;
+}
+
 int
 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
@@ -1438,14 +1480,25 @@
 	len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
 							HEADER_SIZE(server) + 1;
 
-	rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
-	rdata->iov.iov_len = len;
-
-	length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
+	length = cifs_read_from_socket(server,
+				       buf + HEADER_SIZE(server) - 1, len);
 	if (length < 0)
 		return length;
 	server->total_read += length;
 
+	if (server->ops->is_session_expired &&
+	    server->ops->is_session_expired(buf)) {
+		cifs_reconnect(server);
+		wake_up(&server->response_q);
+		return -1;
+	}
+
+	if (server->ops->is_status_pending &&
+	    server->ops->is_status_pending(buf, server, 0)) {
+		cifs_discard_remaining_data(server);
+		return -1;
+	}
+
 	/* Was the SMB read successful? */
 	rdata->result = server->ops->map_error(buf, false);
 	if (rdata->result != 0) {
@@ -1487,19 +1540,20 @@
 	len = data_offset - server->total_read;
 	if (len > 0) {
 		/* read any junk before data into the rest of smallbuf */
-		rdata->iov.iov_base = buf + server->total_read;
-		rdata->iov.iov_len = len;
-		length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
+		length = cifs_read_from_socket(server,
+					       buf + server->total_read, len);
 		if (length < 0)
 			return length;
 		server->total_read += length;
 	}
 
 	/* set up first iov for signature check */
-	rdata->iov.iov_base = buf;
-	rdata->iov.iov_len = server->total_read;
-	cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
-		 rdata->iov.iov_base, rdata->iov.iov_len);
+	rdata->iov[0].iov_base = buf;
+	rdata->iov[0].iov_len = 4;
+	rdata->iov[1].iov_base = buf + 4;
+	rdata->iov[1].iov_len = server->total_read - 4;
+	cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
+		 rdata->iov[0].iov_base, server->total_read);
 
 	/* how much data is in the response? */
 	data_len = server->ops->read_data_length(buf);
@@ -1523,6 +1577,8 @@
 		return cifs_readv_discard(server, mid);
 
 	dequeue_mid(mid, false);
+	mid->resp_buf = server->smallbuf;
+	server->smallbuf = NULL;
 	return length;
 }
 
@@ -1532,8 +1588,8 @@
 	struct cifs_readdata *rdata = mid->callback_data;
 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
-	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
-				 .rq_nvec = 1,
+	struct smb_rqst rqst = { .rq_iov = rdata->iov,
+				 .rq_nvec = 2,
 				 .rq_pages = rdata->pages,
 				 .rq_npages = rdata->nr_pages,
 				 .rq_pagesz = rdata->pagesz,
@@ -1588,8 +1644,8 @@
 	READ_REQ *smb = NULL;
 	int wct;
 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
-	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
-				 .rq_nvec = 1 };
+	struct smb_rqst rqst = { .rq_iov = rdata->iov,
+				 .rq_nvec = 2 };
 
 	cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
 		 __func__, rdata->offset, rdata->bytes);
@@ -1629,12 +1685,14 @@
 	}
 
 	/* 4 for RFC1001 length + 1 for BCC */
-	rdata->iov.iov_base = smb;
-	rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
+	rdata->iov[0].iov_base = smb;
+	rdata->iov[0].iov_len = 4;
+	rdata->iov[1].iov_base = (char *)smb + 4;
+	rdata->iov[1].iov_len = get_rfc1002_length(smb);
 
 	kref_get(&rdata->refcount);
 	rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
-			     cifs_readv_callback, rdata, 0);
+			     cifs_readv_callback, NULL, rdata, 0);
 
 	if (rc == 0)
 		cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
@@ -1656,6 +1714,7 @@
 	int wct;
 	int resp_buf_type = 0;
 	struct kvec iov[1];
+	struct kvec rsp_iov;
 	__u32 pid = io_parms->pid;
 	__u16 netfid = io_parms->netfid;
 	__u64 offset = io_parms->offset;
@@ -1705,10 +1764,11 @@
 
 	iov[0].iov_base = (char *)pSMB;
 	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
-	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
-			 &resp_buf_type, CIFS_LOG_ERROR);
+	rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
+			  CIFS_LOG_ERROR, &rsp_iov);
+	cifs_small_buf_release(pSMB);
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
-	pSMBr = (READ_RSP *)iov[0].iov_base;
+	pSMBr = (READ_RSP *)rsp_iov.iov_base;
 	if (rc) {
 		cifs_dbg(VFS, "Send error in read = %d\n", rc);
 	} else {
@@ -1736,12 +1796,11 @@
 		}
 	}
 
-/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 	if (*buf) {
-		free_rsp_buf(resp_buf_type, iov[0].iov_base);
+		free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
 	} else if (resp_buf_type != CIFS_NO_BUFFER) {
 		/* return buffer to caller to free */
-		*buf = iov[0].iov_base;
+		*buf = rsp_iov.iov_base;
 		if (resp_buf_type == CIFS_SMALL_BUFFER)
 			*pbuf_type = CIFS_SMALL_BUFFER;
 		else if (resp_buf_type == CIFS_LARGE_BUFFER)
@@ -2088,7 +2147,7 @@
 	WRITE_REQ *smb = NULL;
 	int wct;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
-	struct kvec iov;
+	struct kvec iov[2];
 	struct smb_rqst rqst = { };
 
 	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
@@ -2121,11 +2180,13 @@
 	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 
 	/* 4 for RFC1001 length + 1 for BCC */
-	iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
-	iov.iov_base = smb;
+	iov[0].iov_len = 4;
+	iov[0].iov_base = smb;
+	iov[1].iov_len = get_rfc1002_length(smb) + 1;
+	iov[1].iov_base = (char *)smb + 4;
 
-	rqst.rq_iov = &iov;
-	rqst.rq_nvec = 1;
+	rqst.rq_iov = iov;
+	rqst.rq_nvec = 2;
 	rqst.rq_pages = wdata->pages;
 	rqst.rq_npages = wdata->nr_pages;
 	rqst.rq_pagesz = wdata->pagesz;
@@ -2146,12 +2207,12 @@
 				(struct smb_com_writex_req *)smb;
 		inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
 		put_bcc(wdata->bytes + 5, &smbw->hdr);
-		iov.iov_len += 4; /* pad bigger by four bytes */
+		iov[1].iov_len += 4; /* pad bigger by four bytes */
 	}
 
 	kref_get(&wdata->refcount);
 	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
-				cifs_writev_callback, wdata, 0);
+				cifs_writev_callback, NULL, wdata, 0);
 
 	if (rc == 0)
 		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
@@ -2177,6 +2238,7 @@
 	__u64 offset = io_parms->offset;
 	struct cifs_tcon *tcon = io_parms->tcon;
 	unsigned int count = io_parms->length;
+	struct kvec rsp_iov;
 
 	*nbytes = 0;
 
@@ -2235,8 +2297,9 @@
 	else /* wct == 12 pad bigger by four bytes */
 		iov[0].iov_len = smb_hdr_len + 8;
 
-
-	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
+	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
+			  &rsp_iov);
+	cifs_small_buf_release(pSMB);
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 	if (rc) {
 		cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
@@ -2244,7 +2307,7 @@
 		/* presumably this can not happen, but best to be safe */
 		rc = -EIO;
 	} else {
-		WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
+		WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
 		*nbytes = le16_to_cpu(pSMBr->CountHigh);
 		*nbytes = (*nbytes) << 16;
 		*nbytes += le16_to_cpu(pSMBr->Count);
@@ -2258,8 +2321,7 @@
 			*nbytes &= 0xFFFF;
 	}
 
-/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
-	free_rsp_buf(resp_buf_type, iov[0].iov_base);
+	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls
 		since file handle passed in no longer valid */
@@ -2274,6 +2336,7 @@
 	int rc = 0;
 	LOCK_REQ *pSMB = NULL;
 	struct kvec iov[2];
+	struct kvec rsp_iov;
 	int resp_buf_type;
 	__u16 count;
 
@@ -2302,7 +2365,9 @@
 	iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
 
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
-	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
+	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
+			  &rsp_iov);
+	cifs_small_buf_release(pSMB);
 	if (rc)
 		cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
 
@@ -2363,14 +2428,12 @@
 	inc_rfc1001_len(pSMB, count);
 	pSMB->ByteCount = cpu_to_le16(count);
 
-	if (waitFlag) {
+	if (waitFlag)
 		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
 			(struct smb_hdr *) pSMB, &bytes_returned);
-		cifs_small_buf_release(pSMB);
-	} else {
+	else
 		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
-		/* SMB buffer freed by function above */
-	}
+	cifs_small_buf_release(pSMB);
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
 	if (rc)
 		cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
@@ -2396,6 +2459,7 @@
 	int resp_buf_type = 0;
 	__u16 params, param_offset, offset, byte_count, count;
 	struct kvec iov[1];
+	struct kvec rsp_iov;
 
 	cifs_dbg(FYI, "Posix Lock\n");
 
@@ -2457,11 +2521,10 @@
 		iov[0].iov_base = (char *)pSMB;
 		iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
-				&resp_buf_type, timeout);
-		pSMB = NULL; /* request buf already freed by SendReceive2. Do
-				not try to free it twice below on exit */
-		pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
+				&resp_buf_type, timeout, &rsp_iov);
+		pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
 	}
+	cifs_small_buf_release(pSMB);
 
 	if (rc) {
 		cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
@@ -2501,10 +2564,7 @@
 	}
 
 plk_err_exit:
-	if (pSMB)
-		cifs_small_buf_release(pSMB);
-
-	free_rsp_buf(resp_buf_type, iov[0].iov_base);
+	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls
 	   since file handle passed in no longer valid */
@@ -2531,6 +2591,7 @@
 	pSMB->LastWriteTime = 0xFFFFFFFF;
 	pSMB->ByteCount = 0;
 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+	cifs_small_buf_release(pSMB);
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
 	if (rc) {
 		if (rc != -EINTR) {
@@ -2560,6 +2621,7 @@
 	pSMB->FileID = (__u16) smb_file_id;
 	pSMB->ByteCount = 0;
 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+	cifs_small_buf_release(pSMB);
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
 	if (rc)
 		cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
@@ -3813,6 +3875,7 @@
 	int buf_type = 0;
 	QUERY_SEC_DESC_REQ *pSMB;
 	struct kvec iov[1];
+	struct kvec rsp_iov;
 
 	cifs_dbg(FYI, "GetCifsACL\n");
 
@@ -3836,7 +3899,8 @@
 	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 
 	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
-			 0);
+			  0, &rsp_iov);
+	cifs_small_buf_release(pSMB);
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
 	if (rc) {
 		cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
@@ -3848,11 +3912,11 @@
 		char *pdata;
 
 /* validate_nttransact */
-		rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
+		rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
 					&pdata, &parm_len, pbuflen);
 		if (rc)
 			goto qsec_out;
-		pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
+		pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
 
 		cifs_dbg(FYI, "smb %p parm %p data %p\n",
 			 pSMBr, parm, *acl_inf);
@@ -3889,8 +3953,7 @@
 		}
 	}
 qsec_out:
-	free_rsp_buf(buf_type, iov[0].iov_base);
-/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+	free_rsp_buf(buf_type, rsp_iov.iov_base);
 	return rc;
 }
 
@@ -4659,6 +4722,7 @@
 	pSMB->FileID = searchHandle;
 	pSMB->ByteCount = 0;
 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+	cifs_small_buf_release(pSMB);
 	if (rc)
 		cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
 
@@ -5680,6 +5744,7 @@
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+	cifs_small_buf_release(pSMB);
 	if (rc) {
 		cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
 			 rc);
@@ -5751,6 +5816,7 @@
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+	cifs_small_buf_release(pSMB);
 	if (rc)
 		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
 			 rc);
@@ -5811,6 +5877,7 @@
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	*data_offset = delete_file ? 1 : 0;
 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+	cifs_small_buf_release(pSMB);
 	if (rc)
 		cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
 
@@ -6050,6 +6117,7 @@
 	cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
 
 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+	cifs_small_buf_release(pSMB);
 	if (rc)
 		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
 			 rc);
@@ -6392,9 +6460,7 @@
 	pSMB->InformationLevel =
 		cpu_to_le16(SMB_SET_FILE_EA);
 
-	parm_data =
-		(struct fealist *) (((char *) &pSMB->hdr.Protocol) +
-				       offset);
+	parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
 	pSMB->DataOffset = cpu_to_le16(offset);
 	pSMB->SetupCount = 1;
--- linux-4.4.0.orig/fs/cifs/connect.c
+++ linux-4.4.0/fs/cifs/connect.c
@@ -48,10 +48,14 @@
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
+#include "dns_resolve.h"
 #include "ntlmssp.h"
 #include "nterr.h"
 #include "rfc1002pdu.h"
 #include "fscache.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
 
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
@@ -63,7 +67,6 @@
 #define TLINK_IDLE_EXPIRE	(600 * HZ)
 
 enum {
-
 	/* Mount options that take no arguments */
 	Opt_user_xattr, Opt_nouser_xattr,
 	Opt_forceuid, Opt_noforceuid,
@@ -95,6 +98,8 @@
 	Opt_cruid, Opt_gid, Opt_file_mode,
 	Opt_dirmode, Opt_port,
 	Opt_rsize, Opt_wsize, Opt_actimeo,
+	Opt_echo_interval, Opt_max_credits,
+	Opt_snapshot,
 
 	/* Mount options which take string value */
 	Opt_user, Opt_pass, Opt_ip,
@@ -188,6 +193,9 @@
 	{ Opt_rsize, "rsize=%s" },
 	{ Opt_wsize, "wsize=%s" },
 	{ Opt_actimeo, "actimeo=%s" },
+	{ Opt_echo_interval, "echo_interval=%s" },
+	{ Opt_max_credits, "max_credits=%s" },
+	{ Opt_snapshot, "snapshot=%s" },
 
 	{ Opt_blank_user, "user=" },
 	{ Opt_blank_user, "username=" },
@@ -301,6 +309,55 @@
 					const char *devname);
 
 /*
+ * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may
+ * get their ip addresses changed at some point.
+ *
+ * This should be called with server->srv_mutex held.
+ */
+#ifdef CONFIG_CIFS_DFS_UPCALL
+static int reconn_set_ipaddr(struct TCP_Server_Info *server)
+{
+	int rc;
+	int len;
+	char *unc, *ipaddr = NULL;
+
+	if (!server->hostname)
+		return -EINVAL;
+
+	len = strlen(server->hostname) + 3;
+
+	unc = kmalloc(len, GFP_KERNEL);
+	if (!unc) {
+		cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__);
+		return -ENOMEM;
+	}
+	snprintf(unc, len, "\\\\%s", server->hostname);
+
+	rc = dns_resolve_server_name_to_ip(unc, &ipaddr);
+	kfree(unc);
+
+	if (rc < 0) {
+		cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n",
+			 __func__, server->hostname, rc);
+		return rc;
+	}
+
+	spin_lock(&cifs_tcp_ses_lock);
+	rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
+				  strlen(ipaddr));
+	spin_unlock(&cifs_tcp_ses_lock);
+	kfree(ipaddr);
+
+	return !rc ? -1 : 0;
+}
+#else
+static inline int reconn_set_ipaddr(struct TCP_Server_Info *server)
+{
+	return 0;
+}
+#endif
+
+/*
  * cifs tcp session reconnection
  *
  * mark tcp session as reconnecting so temporarily locked
@@ -368,7 +425,6 @@
 	server->session_key.response = NULL;
 	server->session_key.len = 0;
 	server->lstrp = jiffies;
-	mutex_unlock(&server->srv_mutex);
 
 	/* mark submitted MIDs for retry and issue callback */
 	INIT_LIST_HEAD(&retry_list);
@@ -381,6 +437,7 @@
 		list_move(&mid_entry->qhead, &retry_list);
 	}
 	spin_unlock(&GlobalMid_Lock);
+	mutex_unlock(&server->srv_mutex);
 
 	cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
 	list_for_each_safe(tmp, tmp2, &retry_list) {
@@ -397,6 +454,11 @@
 		rc = generic_ip_connect(server);
 		if (rc) {
 			cifs_dbg(FYI, "reconnect error %d\n", rc);
+			rc = reconn_set_ipaddr(server);
+			if (rc) {
+				cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
+					 __func__, rc);
+			}
 			mutex_unlock(&server->srv_mutex);
 			msleep(3000);
 		} else {
@@ -409,6 +471,9 @@
 		}
 	} while (server->tcpStatus == CifsNeedReconnect);
 
+	if (server->tcpStatus == CifsNeedNegotiate)
+		mod_delayed_work(cifsiod_wq, &server->echo, 0);
+
 	return rc;
 }
 
@@ -418,16 +483,27 @@
 	int rc;
 	struct TCP_Server_Info *server = container_of(work,
 					struct TCP_Server_Info, echo.work);
+	unsigned long echo_interval;
 
 	/*
-	 * We cannot send an echo if it is disabled or until the
-	 * NEGOTIATE_PROTOCOL request is done, which is indicated by
-	 * server->ops->need_neg() == true. Also, no need to ping if
-	 * we got a response recently.
+	 * If we need to renegotiate, set echo interval to zero to
+	 * immediately call echo service where we can renegotiate.
 	 */
-	if (!server->ops->need_neg || server->ops->need_neg(server) ||
+	if (server->tcpStatus == CifsNeedNegotiate)
+		echo_interval = 0;
+	else
+		echo_interval = server->echo_interval;
+
+	/*
+	 * We cannot send an echo if it is disabled.
+	 * Also, no need to ping if we got a response recently.
+	 */
+
+	if (server->tcpStatus == CifsNeedReconnect ||
+	    server->tcpStatus == CifsExiting ||
+	    server->tcpStatus == CifsNew ||
 	    (server->ops->can_echo && !server->ops->can_echo(server)) ||
-	    time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
+	    time_before(jiffies, server->lstrp + echo_interval - HZ))
 		goto requeue_echo;
 
 	rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
@@ -436,7 +512,7 @@
 			 server->hostname);
 
 requeue_echo:
-	queue_delayed_work(cifsiod_wq, &server->echo, SMB_ECHO_INTERVAL);
+	queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
 }
 
 static bool
@@ -476,20 +552,21 @@
 server_unresponsive(struct TCP_Server_Info *server)
 {
 	/*
-	 * We need to wait 2 echo intervals to make sure we handle such
+	 * We need to wait 3 echo intervals to make sure we handle such
 	 * situations right:
 	 * 1s  client sends a normal SMB request
-	 * 2s  client gets a response
+	 * 3s  client gets a response
 	 * 30s echo workqueue job pops, and decides we got a response recently
 	 *     and don't need to send another
 	 * ...
 	 * 65s kernel_recvmsg times out, and we see that we haven't gotten
 	 *     a response in >60s.
 	 */
-	if (server->tcpStatus == CifsGood &&
-	    time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) {
-		cifs_dbg(VFS, "Server %s has not responded in %d seconds. Reconnecting...\n",
-			 server->hostname, (2 * SMB_ECHO_INTERVAL) / HZ);
+	if ((server->tcpStatus == CifsGood ||
+	    server->tcpStatus == CifsNeedNegotiate) &&
+	    time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
+		cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
+			 server->hostname, (3 * server->echo_interval) / HZ);
 		cifs_reconnect(server);
 		wake_up(&server->response_q);
 		return true;
@@ -498,99 +575,34 @@
 	return false;
 }
 
-/*
- * kvec_array_init - clone a kvec array, and advance into it
- * @new:	pointer to memory for cloned array
- * @iov:	pointer to original array
- * @nr_segs:	number of members in original array
- * @bytes:	number of bytes to advance into the cloned array
- *
- * This function will copy the array provided in iov to a section of memory
- * and advance the specified number of bytes into the new array. It returns
- * the number of segments in the new array. "new" must be at least as big as
- * the original iov array.
- */
-static unsigned int
-kvec_array_init(struct kvec *new, struct kvec *iov, unsigned int nr_segs,
-		size_t bytes)
-{
-	size_t base = 0;
-
-	while (bytes || !iov->iov_len) {
-		int copy = min(bytes, iov->iov_len);
-
-		bytes -= copy;
-		base += copy;
-		if (iov->iov_len == base) {
-			iov++;
-			nr_segs--;
-			base = 0;
-		}
-	}
-	memcpy(new, iov, sizeof(*iov) * nr_segs);
-	new->iov_base += base;
-	new->iov_len -= base;
-	return nr_segs;
-}
-
-static struct kvec *
-get_server_iovec(struct TCP_Server_Info *server, unsigned int nr_segs)
-{
-	struct kvec *new_iov;
-
-	if (server->iov && nr_segs <= server->nr_iov)
-		return server->iov;
-
-	/* not big enough -- allocate a new one and release the old */
-	new_iov = kmalloc(sizeof(*new_iov) * nr_segs, GFP_NOFS);
-	if (new_iov) {
-		kfree(server->iov);
-		server->iov = new_iov;
-		server->nr_iov = nr_segs;
-	}
-	return new_iov;
-}
-
-int
-cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
-		       unsigned int nr_segs, unsigned int to_read)
+static int
+cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
 {
 	int length = 0;
 	int total_read;
-	unsigned int segs;
-	struct msghdr smb_msg;
-	struct kvec *iov;
-
-	iov = get_server_iovec(server, nr_segs);
-	if (!iov)
-		return -ENOMEM;
 
-	smb_msg.msg_control = NULL;
-	smb_msg.msg_controllen = 0;
+	smb_msg->msg_control = NULL;
+	smb_msg->msg_controllen = 0;
 
-	for (total_read = 0; to_read; total_read += length, to_read -= length) {
+	for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
 		try_to_freeze();
 
-		if (server_unresponsive(server)) {
-			total_read = -ECONNABORTED;
-			break;
-		}
+		if (server_unresponsive(server))
+			return -ECONNABORTED;
 
-		segs = kvec_array_init(iov, iov_orig, nr_segs, total_read);
+		length = sock_recvmsg(server->ssocket, smb_msg, 0);
 
-		length = kernel_recvmsg(server->ssocket, &smb_msg,
-					iov, segs, to_read, 0);
+		if (server->tcpStatus == CifsExiting)
+			return -ESHUTDOWN;
 
-		if (server->tcpStatus == CifsExiting) {
-			total_read = -ESHUTDOWN;
-			break;
-		} else if (server->tcpStatus == CifsNeedReconnect) {
+		if (server->tcpStatus == CifsNeedReconnect) {
 			cifs_reconnect(server);
-			total_read = -ECONNABORTED;
-			break;
-		} else if (length == -ERESTARTSYS ||
-			   length == -EAGAIN ||
-			   length == -EINTR) {
+			return -ECONNABORTED;
+		}
+
+		if (length == -ERESTARTSYS ||
+		    length == -EAGAIN ||
+		    length == -EINTR) {
 			/*
 			 * Minimum sleep to prevent looping, allowing socket
 			 * to clear and app threads to set tcpStatus
@@ -599,12 +611,12 @@
 			usleep_range(1000, 2000);
 			length = 0;
 			continue;
-		} else if (length <= 0) {
-			cifs_dbg(FYI, "Received no data or error: expecting %d\n"
-				 "got %d", to_read, length);
+		}
+
+		if (length <= 0) {
+			cifs_dbg(FYI, "Received no data or error: %d\n", length);
 			cifs_reconnect(server);
-			total_read = -ECONNABORTED;
-			break;
+			return -ECONNABORTED;
 		}
 	}
 	return total_read;
@@ -614,12 +626,21 @@
 cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
 		      unsigned int to_read)
 {
-	struct kvec iov;
+	struct msghdr smb_msg;
+	struct kvec iov = {.iov_base = buf, .iov_len = to_read};
+	iov_iter_kvec(&smb_msg.msg_iter, READ | ITER_KVEC, &iov, 1, to_read);
 
-	iov.iov_base = buf;
-	iov.iov_len = to_read;
+	return cifs_readv_from_socket(server, &smb_msg);
+}
 
-	return cifs_readv_from_socket(server, &iov, 1, to_read);
+int
+cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
+		      unsigned int to_read)
+{
+	struct msghdr smb_msg;
+	struct bio_vec bv = {.bv_page = page, .bv_len = to_read};
+	iov_iter_bvec(&smb_msg.msg_iter, READ | ITER_BVEC, &bv, 1, to_read);
+	return cifs_readv_from_socket(server, &smb_msg);
 }
 
 static bool
@@ -710,6 +731,8 @@
 	list_del_init(&server->tcp_ses_list);
 	spin_unlock(&cifs_tcp_ses_lock);
 
+	cancel_delayed_work_sync(&server->echo);
+
 	spin_lock(&GlobalMid_Lock);
 	server->tcpStatus = CifsExiting;
 	spin_unlock(&GlobalMid_Lock);
@@ -780,7 +803,6 @@
 	}
 
 	kfree(server->hostname);
-	kfree(server->iov);
 	kfree(server);
 
 	length = atomic_dec_return(&tcpSesAllocCount);
@@ -819,6 +841,15 @@
 
 	dump_smb(buf, server->total_read);
 
+	return cifs_handle_standard(server, mid);
+}
+
+int
+cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+{
+	char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
+	int length;
+
 	/*
 	 * We know that we received enough to get to the MID as we
 	 * checked the pdu_length earlier. Now check to see
@@ -828,11 +859,18 @@
 	 * 48 bytes is enough to display the header and a little bit
 	 * into the payload for debugging purposes.
 	 */
-	length = server->ops->check_message(buf, server->total_read);
+	length = server->ops->check_message(buf, server->total_read, server);
 	if (length != 0)
 		cifs_dump_mem("Bad SMB: ", buf,
 			min_t(unsigned int, server->total_read, 48));
 
+	if (server->ops->is_session_expired &&
+	    server->ops->is_session_expired(buf)) {
+		cifs_reconnect(server);
+		wake_up(&server->response_q);
+		return -1;
+	}
+
 	if (server->ops->is_status_pending &&
 	    server->ops->is_status_pending(buf, server, length))
 		return -1;
@@ -862,6 +900,7 @@
 		mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
 
 	set_freezable();
+	allow_kernel_signal(SIGKILL);
 	while (server->tcpStatus != CifsExiting) {
 		if (try_to_freeze())
 			continue;
@@ -904,12 +943,19 @@
 			continue;
 		server->total_read += length;
 
-		mid_entry = server->ops->find_mid(server, buf);
+		if (server->ops->is_transform_hdr &&
+		    server->ops->receive_transform &&
+		    server->ops->is_transform_hdr(buf)) {
+			length = server->ops->receive_transform(server,
+								&mid_entry);
+		} else {
+			mid_entry = server->ops->find_mid(server, buf);
 
-		if (!mid_entry || !mid_entry->receive)
-			length = standard_receive3(server, mid_entry);
-		else
-			length = mid_entry->receive(server, mid_entry);
+			if (!mid_entry || !mid_entry->receive)
+				length = standard_receive3(server, mid_entry);
+			else
+				length = mid_entry->receive(server, mid_entry);
+		}
 
 		if (length < 0)
 			continue;
@@ -919,10 +965,19 @@
 
 		server->lstrp = jiffies;
 		if (mid_entry != NULL) {
+			if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
+			     mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
+					server->ops->handle_cancelled_mid)
+				server->ops->handle_cancelled_mid(
+							mid_entry->resp_buf,
+							server);
+
 			if (!mid_entry->multiRsp || mid_entry->multiEnd)
 				mid_entry->callback(mid_entry);
-		} else if (!server->ops->is_oplock_break ||
-			   !server->ops->is_oplock_break(buf, server)) {
+		} else if (server->ops->is_oplock_break &&
+			   server->ops->is_oplock_break(buf, server)) {
+			cifs_dbg(FYI, "Received oplock break\n");
+		} else {
 			cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n",
 				 atomic_read(&midCount));
 			cifs_dump_mem("Received Data is: ", buf,
@@ -1169,6 +1224,11 @@
 	const char *delims = "/\\";
 	size_t len;
 
+	if (unlikely(!devname || !*devname)) {
+		cifs_dbg(VFS, "Device name not specified.\n");
+		return -EINVAL;
+	}
+
 	/* make sure we have a valid UNC double delimiter prefix */
 	len = strspn(devname, delims);
 	if (len != 2)
@@ -1624,6 +1684,31 @@
 				goto cifs_parse_mount_err;
 			}
 			break;
+		case Opt_echo_interval:
+			if (get_option_ul(args, &option)) {
+				cifs_dbg(VFS, "%s: Invalid echo interval value\n",
+					 __func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->echo_interval = option;
+			break;
+		case Opt_snapshot:
+			if (get_option_ul(args, &option)) {
+				cifs_dbg(VFS, "%s: Invalid snapshot time\n",
+					 __func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->snapshot_time = option;
+			break;
+		case Opt_max_credits:
+			if (get_option_ul(args, &option) || (option < 20) ||
+			    (option > 60000)) {
+				cifs_dbg(VFS, "%s: Invalid max_credits value\n",
+					 __func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->max_credits = option;
+			break;
 
 		/* String Arguments */
 
@@ -1662,7 +1747,7 @@
 			tmp_end++;
 			if (!(tmp_end < end && tmp_end[1] == delim)) {
 				/* No it is not. Set the password to NULL */
-				kfree(vol->password);
+				kzfree(vol->password);
 				vol->password = NULL;
 				break;
 			}
@@ -1700,7 +1785,7 @@
 					options = end;
 			}
 
-			kfree(vol->password);
+			kzfree(vol->password);
 			/* Now build new password string */
 			temp_len = strlen(value);
 			vol->password = kzalloc(temp_len+1, GFP_KERNEL);
@@ -2089,6 +2174,9 @@
 	if (!match_security(server, vol))
 		return 0;
 
+	if (server->echo_interval != vol->echo_interval)
+		return 0;
+
 	return 1;
 }
 
@@ -2111,8 +2199,8 @@
 	return NULL;
 }
 
-static void
-cifs_put_tcp_session(struct TCP_Server_Info *server)
+void
+cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
 {
 	struct task_struct *task;
 
@@ -2129,11 +2217,24 @@
 
 	cancel_delayed_work_sync(&server->echo);
 
+#ifdef CONFIG_CIFS_SMB2
+	if (from_reconnect)
+		/*
+		 * Avoid deadlock here: reconnect work calls
+		 * cifs_put_tcp_session() at its end. Need to be sure
+		 * that reconnect work does nothing with server pointer after
+		 * that step.
+		 */
+		cancel_delayed_work(&server->reconnect);
+	else
+		cancel_delayed_work_sync(&server->reconnect);
+#endif
+
 	spin_lock(&GlobalMid_Lock);
 	server->tcpStatus = CifsExiting;
 	spin_unlock(&GlobalMid_Lock);
 
-	cifs_crypto_shash_release(server);
+	cifs_crypto_secmech_release(server);
 	cifs_fscache_release_client_cookie(server);
 
 	kfree(server->session_key.response);
@@ -2142,7 +2243,7 @@
 
 	task = xchg(&server->tsk, NULL);
 	if (task)
-		force_sig(SIGKILL, task);
+		send_sig(SIGKILL, task, 1);
 }
 
 static struct TCP_Server_Info *
@@ -2193,12 +2294,16 @@
 	INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
 	INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
 	INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
+#ifdef CONFIG_CIFS_SMB2
+	INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
+	mutex_init(&tcp_ses->reconnect_mutex);
+#endif
 	memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
 	       sizeof(tcp_ses->srcaddr));
 	memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
 		sizeof(tcp_ses->dstaddr));
 #ifdef CONFIG_CIFS_SMB2
-	get_random_bytes(tcp_ses->client_guid, SMB2_CLIENT_GUID_SIZE);
+	generate_random_uuid(tcp_ses->client_guid);
 #endif
 	/*
 	 * at this point we are the only ones with the pointer
@@ -2208,6 +2313,12 @@
 	tcp_ses->tcpStatus = CifsNew;
 	++tcp_ses->srv_count;
 
+	if (volume_info->echo_interval >= SMB_ECHO_INTERVAL_MIN &&
+		volume_info->echo_interval <= SMB_ECHO_INTERVAL_MAX)
+		tcp_ses->echo_interval = volume_info->echo_interval * HZ;
+	else
+		tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ;
+
 	rc = ip_connect(tcp_ses);
 	if (rc < 0) {
 		cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n");
@@ -2237,12 +2348,12 @@
 	cifs_fscache_get_client_cookie(tcp_ses);
 
 	/* queue echo request delayed work */
-	queue_delayed_work(cifsiod_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL);
+	queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
 
 	return tcp_ses;
 
 out_err_crypto_release:
-	cifs_crypto_shash_release(tcp_ses);
+	cifs_crypto_secmech_release(tcp_ses);
 
 	put_net(cifs_net_ns(tcp_ses));
 
@@ -2345,7 +2456,7 @@
 	spin_unlock(&cifs_tcp_ses_lock);
 
 	sesInfoFree(ses);
-	cifs_put_tcp_session(server);
+	cifs_put_tcp_session(server, 0);
 }
 
 #ifdef CONFIG_KEYS
@@ -2358,6 +2469,7 @@
 cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
 {
 	int rc = 0;
+	int is_domain = 0;
 	const char *delim, *payload;
 	char *desc;
 	ssize_t len;
@@ -2405,6 +2517,7 @@
 			rc = PTR_ERR(key);
 			goto out_err;
 		}
+		is_domain = 1;
 	}
 
 	down_read(&key->sem);
@@ -2462,6 +2575,26 @@
 		goto out_key_put;
 	}
 
+	/*
+	 * If we have a domain key then we must set the domainName in the
+	 * for the request.
+	 */
+	if (is_domain && ses->domainName) {
+		vol->domainname = kstrndup(ses->domainName,
+					   strlen(ses->domainName),
+					   GFP_KERNEL);
+		if (!vol->domainname) {
+			cifs_dbg(FYI, "Unable to allocate %zd bytes for "
+				 "domain\n", len);
+			rc = -ENOMEM;
+			kfree(vol->username);
+			vol->username = NULL;
+			kzfree(vol->password);
+			vol->password = NULL;
+			goto out_key_put;
+		}
+	}
+
 out_key_put:
 	up_read(&key->sem);
 	key_put(key);
@@ -2519,7 +2652,7 @@
 		mutex_unlock(&ses->session_mutex);
 
 		/* existing SMB ses has a server reference already */
-		cifs_put_tcp_session(server);
+		cifs_put_tcp_session(server, 0);
 		free_xid(xid);
 		return ses;
 	}
@@ -2581,17 +2714,23 @@
 	return ERR_PTR(rc);
 }
 
-static int match_tcon(struct cifs_tcon *tcon, const char *unc)
+static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
 {
 	if (tcon->tidStatus == CifsExiting)
 		return 0;
-	if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
+	if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE))
 		return 0;
+	if (tcon->seal != volume_info->seal)
+		return 0;
+#ifdef CONFIG_CIFS_SMB2
+	if (tcon->snapshot_time != volume_info->snapshot_time)
+		return 0;
+#endif /* CONFIG_CIFS_SMB2 */
 	return 1;
 }
 
 static struct cifs_tcon *
-cifs_find_tcon(struct cifs_ses *ses, const char *unc)
+cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 {
 	struct list_head *tmp;
 	struct cifs_tcon *tcon;
@@ -2599,7 +2738,7 @@
 	spin_lock(&cifs_tcp_ses_lock);
 	list_for_each(tmp, &ses->tcon_list) {
 		tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
-		if (!match_tcon(tcon, unc))
+		if (!match_tcon(tcon, volume_info))
 			continue;
 		++tcon->tc_count;
 		spin_unlock(&cifs_tcp_ses_lock);
@@ -2609,7 +2748,7 @@
 	return NULL;
 }
 
-static void
+void
 cifs_put_tcon(struct cifs_tcon *tcon)
 {
 	unsigned int xid;
@@ -2641,13 +2780,11 @@
 	int rc, xid;
 	struct cifs_tcon *tcon;
 
-	tcon = cifs_find_tcon(ses, volume_info->UNC);
+	tcon = cifs_find_tcon(ses, volume_info);
 	if (tcon) {
 		cifs_dbg(FYI, "Found match on UNC path\n");
 		/* existing tcon already has a reference */
 		cifs_put_smb_ses(ses);
-		if (tcon->seal != volume_info->seal)
-			cifs_dbg(VFS, "transport encryption setting conflicts with existing tid\n");
 		return tcon;
 	}
 
@@ -2662,6 +2799,22 @@
 		goto out_fail;
 	}
 
+	if (volume_info->snapshot_time) {
+#ifdef CONFIG_CIFS_SMB2
+		if (ses->server->vals->protocol_id == 0) {
+			cifs_dbg(VFS,
+			     "Use SMB2 or later for snapshot mount option\n");
+			rc = -EOPNOTSUPP;
+			goto out_fail;
+		} else
+			tcon->snapshot_time = volume_info->snapshot_time;
+#else
+		cifs_dbg(VFS, "Snapshot mount option requires SMB2 support\n");
+		rc = -EOPNOTSUPP;
+		goto out_fail;
+#endif /* CONFIG_CIFS_SMB2 */
+	}
+
 	tcon->ses = ses;
 	if (volume_info->password) {
 		tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
@@ -2687,7 +2840,6 @@
 		tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
 		cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
 	}
-	tcon->seal = volume_info->seal;
 	tcon->use_persistent = false;
 	/* check if SMB2 or later, CIFS does not support persistent handles */
 	if (volume_info->persistent) {
@@ -2724,6 +2876,24 @@
 		tcon->use_resilient = true;
 	}
 
+	if (volume_info->seal) {
+		if (ses->server->vals->protocol_id == 0) {
+			cifs_dbg(VFS,
+				 "SMB3 or later required for encryption\n");
+			rc = -EOPNOTSUPP;
+			goto out_fail;
+#ifdef CONFIG_CIFS_SMB2
+		} else if (tcon->ses->server->capabilities &
+					SMB2_GLOBAL_CAP_ENCRYPTION)
+			tcon->seal = true;
+		else {
+			cifs_dbg(VFS, "Encryption is not supported on share\n");
+			rc = -EOPNOTSUPP;
+			goto out_fail;
+#endif /* CONFIG_CIFS_SMB2 */
+		}
+	}
+
 	/*
 	 * 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
@@ -2810,6 +2980,24 @@
 	return 1;
 }
 
+static int
+match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data)
+{
+	struct cifs_sb_info *old = CIFS_SB(sb);
+	struct cifs_sb_info *new = mnt_data->cifs_sb;
+
+	if (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) {
+		if (!(new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH))
+			return 0;
+		/* The prepath should be null terminated strings */
+		if (strcmp(new->prepath, old->prepath))
+			return 0;
+
+		return 1;
+	}
+	return 0;
+}
+
 int
 cifs_match_super(struct super_block *sb, void *data)
 {
@@ -2837,7 +3025,8 @@
 
 	if (!match_server(tcp_srv, volume_info) ||
 	    !match_session(ses, volume_info) ||
-	    !match_tcon(tcon, volume_info->UNC)) {
+	    !match_tcon(tcon, volume_info) ||
+	    !match_prepath(sb, mnt_data)) {
 		rc = 0;
 		goto out;
 	}
@@ -3252,7 +3441,7 @@
 	}
 }
 
-void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
+int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
 			struct cifs_sb_info *cifs_sb)
 {
 	INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
@@ -3271,7 +3460,7 @@
 	cifs_sb->mnt_gid = pvolume_info->linux_gid;
 	cifs_sb->mnt_file_mode = pvolume_info->file_mode;
 	cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
-	cifs_dbg(FYI, "file mode: 0x%hx  dir mode: 0x%hx\n",
+	cifs_dbg(FYI, "file mode: %04ho  dir mode: %04ho\n",
 		 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
 
 	cifs_sb->actimeo = pvolume_info->actimeo;
@@ -3346,6 +3535,14 @@
 
 	if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
 		cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n");
+
+	if (pvolume_info->prepath) {
+		cifs_sb->prepath = kstrdup(pvolume_info->prepath, GFP_KERNEL);
+		if (cifs_sb->prepath == NULL)
+			return -ENOMEM;
+	}
+
+	return 0;
 }
 
 static void
@@ -3515,6 +3712,44 @@
 	return volume_info;
 }
 
+static int
+cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
+					unsigned int xid,
+					struct cifs_tcon *tcon,
+					struct cifs_sb_info *cifs_sb,
+					char *full_path)
+{
+	int rc;
+	char *s;
+	char sep, tmp;
+
+	sep = CIFS_DIR_SEP(cifs_sb);
+	s = full_path;
+
+	rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
+	while (rc == 0) {
+		/* skip separators */
+		while (*s == sep)
+			s++;
+		if (!*s)
+			break;
+		/* next separator */
+		while (*s && *s != sep)
+			s++;
+
+		/*
+		 * temporarily null-terminate the path at the end of
+		 * the current component
+		 */
+		tmp = *s;
+		*s = 0;
+		rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
+						     full_path);
+		*s = tmp;
+	}
+	return rc;
+}
+
 int
 cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
 {
@@ -3563,7 +3798,11 @@
 		bdi_destroy(&cifs_sb->bdi);
 		goto out;
 	}
-
+	if ((volume_info->max_credits < 20) ||
+	     (volume_info->max_credits > 60000))
+		server->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
+	else
+		server->max_credits = volume_info->max_credits;
 	/* get a reference to a SMB session */
 	ses = cifs_get_smb_ses(server, volume_info);
 	if (IS_ERR(ses)) {
@@ -3586,6 +3825,9 @@
 	if (IS_ERR(tcon)) {
 		rc = PTR_ERR(tcon);
 		tcon = NULL;
+		if (rc == -EACCES)
+			goto mount_fail_check;
+
 		goto remote_path_check;
 	}
 
@@ -3652,6 +3894,18 @@
 			kfree(full_path);
 			goto mount_fail_check;
 		}
+
+		if (rc != -EREMOTE) {
+			rc = cifs_are_all_path_components_accessible(server,
+							     xid, tcon, cifs_sb,
+							     full_path);
+			if (rc != 0) {
+				cifs_dbg(VFS, "cannot query dirs between root and final path, "
+					 "enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
+				cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+				rc = 0;
+			}
+		}
 		kfree(full_path);
 	}
 
@@ -3715,7 +3969,7 @@
 		else if (ses)
 			cifs_put_smb_ses(ses);
 		else
-			cifs_put_tcp_session(server);
+			cifs_put_tcp_session(server, 0);
 		bdi_destroy(&cifs_sb->bdi);
 	}
 
@@ -3921,6 +4175,7 @@
 
 	bdi_destroy(&cifs_sb->bdi);
 	kfree(cifs_sb->mountdata);
+	kfree(cifs_sb->prepath);
 	call_rcu(&cifs_sb->rcu, delayed_free);
 }
 
@@ -3966,6 +4221,14 @@
 	cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n",
 		 server->sec_mode, server->capabilities, server->timeAdj);
 
+	if (ses->auth_key.response) {
+		cifs_dbg(VFS, "Free previous auth_key.response = %p\n",
+			 ses->auth_key.response);
+		kfree(ses->auth_key.response);
+		ses->auth_key.response = NULL;
+		ses->auth_key.len = 0;
+	}
+
 	if (server->ops->sess_setup)
 		rc = server->ops->sess_setup(xid, ses, nls_info);
 
@@ -4007,9 +4270,12 @@
 	vol_info->retry = master_tcon->retry;
 	vol_info->nocase = master_tcon->nocase;
 	vol_info->local_lease = master_tcon->local_lease;
+	vol_info->resilient = master_tcon->use_resilient;
+	vol_info->persistent = master_tcon->use_persistent;
 	vol_info->no_linux_ext = !master_tcon->unix_ext;
 	vol_info->sectype = master_tcon->ses->sectype;
 	vol_info->sign = master_tcon->ses->sign;
+	vol_info->seal = master_tcon->seal;
 
 	rc = cifs_set_vol_auth(vol_info, master_tcon->ses);
 	if (rc) {
@@ -4025,7 +4291,7 @@
 	ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
 	if (IS_ERR(ses)) {
 		tcon = (struct cifs_tcon *)ses;
-		cifs_put_tcp_session(master_tcon->ses->server);
+		cifs_put_tcp_session(master_tcon->ses->server, 0);
 		goto out;
 	}
 
@@ -4039,7 +4305,7 @@
 		reset_cifs_unix_caps(0, tcon, NULL, vol_info);
 out:
 	kfree(vol_info->username);
-	kfree(vol_info->password);
+	kzfree(vol_info->password);
 	kfree(vol_info);
 
 	return tcon;
--- linux-4.4.0.orig/fs/cifs/dir.c
+++ linux-4.4.0/fs/cifs/dir.c
@@ -84,6 +84,7 @@
 	struct dentry *temp;
 	int namelen;
 	int dfsplen;
+	int pplen = 0;
 	char *full_path;
 	char dirsep;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
@@ -95,8 +96,12 @@
 		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
 	else
 		dfsplen = 0;
+
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+		pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
+
 cifs_bp_rename_retry:
-	namelen = dfsplen;
+	namelen = dfsplen + pplen;
 	seq = read_seqbegin(&rename_lock);
 	rcu_read_lock();
 	for (temp = direntry; !IS_ROOT(temp);) {
@@ -137,7 +142,7 @@
 		}
 	}
 	rcu_read_unlock();
-	if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
+	if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) {
 		cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n",
 			 namelen, dfsplen);
 		/* presumably this is only possible if racing with a rename
@@ -153,6 +158,17 @@
 	   those safely to '/' if any are found in the middle of the prepath */
 	/* BB test paths to Windows with '/' in the midst of prepath */
 
+	if (pplen) {
+		int i;
+
+		cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath);
+		memcpy(full_path+dfsplen+1, cifs_sb->prepath, pplen-1);
+		full_path[dfsplen] = dirsep;
+		for (i = 0; i < pplen-1; i++)
+			if (full_path[dfsplen+1+i] == '/')
+				full_path[dfsplen+1+i] = CIFS_DIR_SEP(cifs_sb);
+	}
+
 	if (dfsplen) {
 		strncpy(full_path, tcon->treeName, dfsplen);
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
@@ -167,15 +183,21 @@
 }
 
 /*
+ * Don't allow path components longer than the server max.
  * 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)
+check_name(struct dentry *direntry, struct cifs_tcon *tcon)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
 	int i;
 
+	if (unlikely(tcon->fsAttrInfo.MaxPathNameComponentLength &&
+		     direntry->d_name.len >
+		     le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
+		return -ENAMETOOLONG;
+
 	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] == '\\') {
@@ -229,6 +251,13 @@
 				goto cifs_create_get_file_info;
 			}
 
+			if (S_ISDIR(newinode->i_mode)) {
+				CIFSSMBClose(xid, tcon, fid->netfid);
+				iput(newinode);
+				rc = -EISDIR;
+				goto out;
+			}
+
 			if (!S_ISREG(newinode->i_mode)) {
 				/*
 				 * The server may allow us to open things like
@@ -399,10 +428,14 @@
 	if (rc != 0) {
 		cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n",
 			 rc);
-		if (server->ops->close)
-			server->ops->close(xid, tcon, fid);
-		goto out;
+		goto out_err;
 	}
+
+	if (S_ISDIR(newinode->i_mode)) {
+		rc = -EISDIR;
+		goto out_err;
+	}
+
 	d_drop(direntry);
 	d_add(direntry, newinode);
 
@@ -410,6 +443,13 @@
 	kfree(buf);
 	kfree(full_path);
 	return rc;
+
+out_err:
+	if (server->ops->close)
+		server->ops->close(xid, tcon, fid);
+	if (newinode)
+		iput(newinode);
+	goto out;
 }
 
 int
@@ -455,10 +495,6 @@
 		return finish_no_open(file, res);
 	}
 
-	rc = check_name(direntry);
-	if (rc)
-		return rc;
-
 	xid = get_xid();
 
 	cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
@@ -471,6 +507,11 @@
 	}
 
 	tcon = tlink_tcon(tlink);
+
+	rc = check_name(direntry, tcon);
+	if (rc)
+		goto out;
+
 	server = tcon->ses->server;
 
 	if (server->ops->new_lease_key)
@@ -632,6 +673,9 @@
 		goto mknod_out;
 	}
 
+	if (!S_ISCHR(mode) && !S_ISBLK(mode))
+		goto mknod_out;
+
 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
 		goto mknod_out;
 
@@ -640,10 +684,8 @@
 
 	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 	if (buf == NULL) {
-		kfree(full_path);
 		rc = -ENOMEM;
-		free_xid(xid);
-		return rc;
+		goto mknod_out;
 	}
 
 	if (backup_cred(cifs_sb))
@@ -690,7 +732,7 @@
 		pdev->minor = cpu_to_le64(MINOR(device_number));
 		rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
 							&bytes_written, iov, 1);
-	} /* else if (S_ISFIFO) */
+	}
 	tcon->ses->server->ops->close(xid, tcon, &fid);
 	d_drop(direntry);
 
@@ -731,7 +773,7 @@
 	}
 	pTcon = tlink_tcon(tlink);
 
-	rc = check_name(direntry);
+	rc = check_name(direntry, pTcon);
 	if (rc)
 		goto lookup_out;
 
@@ -788,12 +830,36 @@
 static int
 cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
 {
+	struct inode *inode;
+	int rc;
+
 	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	if (d_really_is_positive(direntry)) {
-		if (cifs_revalidate_dentry(direntry))
-			return 0;
+		inode = d_inode(direntry);
+		if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode)))
+			CIFS_I(inode)->time = 0; /* force reval */
+
+		rc = cifs_revalidate_dentry(direntry);
+		if (rc) {
+			cifs_dbg(FYI, "cifs_revalidate_dentry failed with rc=%d", rc);
+			switch (rc) {
+			case -ENOENT:
+			case -ESTALE:
+				/*
+				 * Those errors mean the dentry is invalid
+				 * (file was deleted or recreated)
+				 */
+				return 0;
+			default:
+				/*
+				 * Otherwise some unexpected error happened
+				 * report it as-is to VFS layer
+				 */
+				return rc;
+			}
+		}
 		else {
 			/*
 			 * If the inode wasn't known to be a dfs entry when
@@ -802,7 +868,7 @@
 			 * attributes will have been updated by
 			 * cifs_revalidate_dentry().
 			 */
-			if (IS_AUTOMOUNT(d_inode(direntry)) &&
+			if (IS_AUTOMOUNT(inode) &&
 			   !(direntry->d_flags & DCACHE_NEED_AUTOMOUNT)) {
 				spin_lock(&direntry->d_lock);
 				direntry->d_flags |= DCACHE_NEED_AUTOMOUNT;
--- linux-4.4.0.orig/fs/cifs/file.c
+++ linux-4.4.0/fs/cifs/file.c
@@ -224,6 +224,13 @@
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
 
+	/* O_SYNC also has bit for O_DSYNC so following check picks up either */
+	if (f_flags & O_SYNC)
+		create_options |= CREATE_WRITE_THROUGH;
+
+	if (f_flags & O_DIRECT)
+		create_options |= CREATE_NO_BUFFER;
+
 	oparms.tcon = tcon;
 	oparms.cifs_sb = cifs_sb;
 	oparms.desired_access = desired_access;
@@ -245,6 +252,12 @@
 		rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
 					 xid, fid);
 
+	if (rc) {
+		server->ops->close(xid, tcon, fid);
+		if (rc == -ESTALE)
+			rc = -EOPENSTALE;
+	}
+
 out:
 	kfree(buf);
 	return rc;
@@ -267,6 +280,13 @@
 	return has_locks;
 }
 
+void
+cifs_down_write(struct rw_semaphore *sem)
+{
+	while (!down_write_trylock(sem))
+		msleep(10);
+}
+
 struct cifsFileInfo *
 cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
 		  struct tcon_link *tlink, __u32 oplock)
@@ -292,9 +312,6 @@
 	INIT_LIST_HEAD(&fdlocks->locks);
 	fdlocks->cfile = cfile;
 	cfile->llist = fdlocks;
-	down_write(&cinode->lock_sem);
-	list_add(&fdlocks->llist, &cinode->llist);
-	up_write(&cinode->lock_sem);
 
 	cfile->count = 1;
 	cfile->pid = current->tgid;
@@ -305,6 +322,7 @@
 	cfile->tlink = cifs_get_tlink(tlink);
 	INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
 	mutex_init(&cfile->fh_mutex);
+	spin_lock_init(&cfile->file_info_lock);
 
 	cifs_sb_active(inode->i_sb);
 
@@ -317,7 +335,11 @@
 		oplock = 0;
 	}
 
-	spin_lock(&cifs_file_list_lock);
+	cifs_down_write(&cinode->lock_sem);
+	list_add(&fdlocks->llist, &cinode->llist);
+	up_write(&cinode->lock_sem);
+
+	spin_lock(&tcon->open_file_lock);
 	if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
 		oplock = fid->pending_open->oplock;
 	list_del(&fid->pending_open->olist);
@@ -326,12 +348,13 @@
 	server->ops->set_fid(cfile, fid, oplock);
 
 	list_add(&cfile->tlist, &tcon->openFileList);
+
 	/* if readable file instance put first in list*/
 	if (file->f_mode & FMODE_READ)
 		list_add(&cfile->flist, &cinode->openFileList);
 	else
 		list_add_tail(&cfile->flist, &cinode->openFileList);
-	spin_unlock(&cifs_file_list_lock);
+	spin_unlock(&tcon->open_file_lock);
 
 	if (fid->purge_cache)
 		cifs_zap_mapping(inode);
@@ -343,16 +366,16 @@
 struct cifsFileInfo *
 cifsFileInfo_get(struct cifsFileInfo *cifs_file)
 {
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&cifs_file->file_info_lock);
 	cifsFileInfo_get_locked(cifs_file);
-	spin_unlock(&cifs_file_list_lock);
+	spin_unlock(&cifs_file->file_info_lock);
 	return cifs_file;
 }
 
 /*
  * Release a reference on the file private data. This may involve closing
  * the filehandle out on the server. Must be called without holding
- * cifs_file_list_lock.
+ * tcon->open_file_lock and cifs_file->file_info_lock.
  */
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 {
@@ -367,11 +390,15 @@
 	struct cifs_pending_open open;
 	bool oplock_break_cancelled;
 
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&tcon->open_file_lock);
+
+	spin_lock(&cifs_file->file_info_lock);
 	if (--cifs_file->count > 0) {
-		spin_unlock(&cifs_file_list_lock);
+		spin_unlock(&cifs_file->file_info_lock);
+		spin_unlock(&tcon->open_file_lock);
 		return;
 	}
+	spin_unlock(&cifs_file->file_info_lock);
 
 	if (server->ops->get_lease_key)
 		server->ops->get_lease_key(inode, &fid);
@@ -395,7 +422,8 @@
 			set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
 		cifs_set_oplock_level(cifsi, 0);
 	}
-	spin_unlock(&cifs_file_list_lock);
+
+	spin_unlock(&tcon->open_file_lock);
 
 	oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
 
@@ -418,7 +446,7 @@
 	 * Delete any outstanding lock records. We'll lose them when the file
 	 * is closed anyway.
 	 */
-	down_write(&cifsi->lock_sem);
+	cifs_down_write(&cifsi->lock_sem);
 	list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) {
 		list_del(&li->llist);
 		cifs_del_lock_waiters(li);
@@ -575,7 +603,7 @@
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	int rc = 0;
 
-	down_read(&cinode->lock_sem);
+	down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING);
 	if (cinode->can_cache_brlcks) {
 		/* can cache locks - no need to relock */
 		up_read(&cinode->lock_sem);
@@ -675,6 +703,13 @@
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
 
+	/* O_SYNC also has bit for O_DSYNC so following check picks up either */
+	if (cfile->f_flags & O_SYNC)
+		create_options |= CREATE_WRITE_THROUGH;
+
+	if (cfile->f_flags & O_DIRECT)
+		create_options |= CREATE_NO_BUFFER;
+
 	if (server->ops->get_lease_key)
 		server->ops->get_lease_key(inode, &cfile->fid);
 
@@ -772,10 +807,10 @@
 	server = tcon->ses->server;
 
 	cifs_dbg(FYI, "Freeing private data in close dir\n");
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&cfile->file_info_lock);
 	if (server->ops->dir_needs_close(cfile)) {
 		cfile->invalidHandle = true;
-		spin_unlock(&cifs_file_list_lock);
+		spin_unlock(&cfile->file_info_lock);
 		if (server->ops->close_dir)
 			rc = server->ops->close_dir(xid, tcon, &cfile->fid);
 		else
@@ -784,7 +819,7 @@
 		/* not much we can do if it fails anyway, ignore rc */
 		rc = 0;
 	} else
-		spin_unlock(&cifs_file_list_lock);
+		spin_unlock(&cfile->file_info_lock);
 
 	buf = cfile->srch_inf.ntwrk_buf_start;
 	if (buf) {
@@ -927,7 +962,7 @@
 cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
 {
 	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
-	down_write(&cinode->lock_sem);
+	cifs_down_write(&cinode->lock_sem);
 	list_add_tail(&lock->llist, &cfile->llist->locks);
 	up_write(&cinode->lock_sem);
 }
@@ -949,7 +984,7 @@
 
 try_again:
 	exist = false;
-	down_write(&cinode->lock_sem);
+	cifs_down_write(&cinode->lock_sem);
 
 	exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length,
 					lock->type, &conf_lock, CIFS_LOCK_OP);
@@ -971,7 +1006,7 @@
 					(lock->blist.next == &lock->blist));
 		if (!rc)
 			goto try_again;
-		down_write(&cinode->lock_sem);
+		cifs_down_write(&cinode->lock_sem);
 		list_del_init(&lock->blist);
 	}
 
@@ -1024,7 +1059,7 @@
 		return rc;
 
 try_again:
-	down_write(&cinode->lock_sem);
+	cifs_down_write(&cinode->lock_sem);
 	if (!cinode->can_cache_brlcks) {
 		up_write(&cinode->lock_sem);
 		return rc;
@@ -1059,14 +1094,18 @@
 
 	/*
 	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
-	 * and check it for zero before using.
+	 * and check it before using.
 	 */
 	max_buf = tcon->ses->server->maxBuf;
-	if (!max_buf) {
+	if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE))) {
 		free_xid(xid);
 		return -EINVAL;
 	}
 
+	BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) >
+		     PAGE_SIZE);
+	max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr),
+			PAGE_SIZE);
 	max_num = (max_buf - sizeof(struct smb_hdr)) /
 						sizeof(LOCKING_ANDX_RANGE);
 	buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
@@ -1218,7 +1257,7 @@
 	int rc = 0;
 
 	/* we are going to update can_cache_brlcks here - need a write access */
-	down_write(&cinode->lock_sem);
+	cifs_down_write(&cinode->lock_sem);
 	if (!cinode->can_cache_brlcks) {
 		up_write(&cinode->lock_sem);
 		return rc;
@@ -1390,19 +1429,23 @@
 
 	/*
 	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
-	 * and check it for zero before using.
+	 * and check it before using.
 	 */
 	max_buf = tcon->ses->server->maxBuf;
-	if (!max_buf)
+	if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE)))
 		return -EINVAL;
 
+	BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) >
+		     PAGE_SIZE);
+	max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr),
+			PAGE_SIZE);
 	max_num = (max_buf - sizeof(struct smb_hdr)) /
 						sizeof(LOCKING_ANDX_RANGE);
 	buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
-	down_write(&cinode->lock_sem);
+	cifs_down_write(&cinode->lock_sem);
 	for (i = 0; i < 2; i++) {
 		cur = buf;
 		num = 0;
@@ -1552,8 +1595,20 @@
 		rc = server->ops->mand_unlock_range(cfile, flock, xid);
 
 out:
-	if (flock->fl_flags & FL_POSIX && !rc)
+	if (flock->fl_flags & FL_POSIX) {
+		/*
+		 * If this is a request to remove all locks because we
+		 * are closing the file, it doesn't matter if the
+		 * unlocking failed as both cifs.ko and the SMB server
+		 * remove the lock on file close
+		 */
+		if (rc) {
+			cifs_dbg(VFS, "%s failed rc=%d\n", __func__, rc);
+			if (!(flock->fl_flags & FL_CLOSE))
+				return rc;
+		}
 		rc = locks_lock_file_wait(file, flock);
+	}
 	return rc;
 }
 
@@ -1720,12 +1775,13 @@
 {
 	struct cifsFileInfo *open_file = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 
 	/* only filter by fsuid on multiuser mounts */
 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
 		fsuid_only = false;
 
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&tcon->open_file_lock);
 	/* we could simply get the first_list_entry since write-only entries
 	   are always at the end of the list but since the first entry might
 	   have a close pending, we go through the whole list */
@@ -1736,8 +1792,8 @@
 			if (!open_file->invalidHandle) {
 				/* found a good file */
 				/* lock it so it will not be closed on us */
-				cifsFileInfo_get_locked(open_file);
-				spin_unlock(&cifs_file_list_lock);
+				cifsFileInfo_get(open_file);
+				spin_unlock(&tcon->open_file_lock);
 				return open_file;
 			} /* else might as well continue, and look for
 			     another, or simply have the caller reopen it
@@ -1745,7 +1801,7 @@
 		} else /* write only file */
 			break; /* write only files are last so must be done */
 	}
-	spin_unlock(&cifs_file_list_lock);
+	spin_unlock(&tcon->open_file_lock);
 	return NULL;
 }
 
@@ -1754,6 +1810,7 @@
 {
 	struct cifsFileInfo *open_file, *inv_file = NULL;
 	struct cifs_sb_info *cifs_sb;
+	struct cifs_tcon *tcon;
 	bool any_available = false;
 	int rc;
 	unsigned int refind = 0;
@@ -1769,15 +1826,16 @@
 	}
 
 	cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+	tcon = cifs_sb_master_tcon(cifs_sb);
 
 	/* only filter by fsuid on multiuser mounts */
 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
 		fsuid_only = false;
 
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&tcon->open_file_lock);
 refind_writable:
 	if (refind > MAX_REOPEN_ATT) {
-		spin_unlock(&cifs_file_list_lock);
+		spin_unlock(&tcon->open_file_lock);
 		return NULL;
 	}
 	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
@@ -1788,8 +1846,8 @@
 		if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
 			if (!open_file->invalidHandle) {
 				/* found a good writable file */
-				cifsFileInfo_get_locked(open_file);
-				spin_unlock(&cifs_file_list_lock);
+				cifsFileInfo_get(open_file);
+				spin_unlock(&tcon->open_file_lock);
 				return open_file;
 			} else {
 				if (!inv_file)
@@ -1805,24 +1863,24 @@
 
 	if (inv_file) {
 		any_available = false;
-		cifsFileInfo_get_locked(inv_file);
+		cifsFileInfo_get(inv_file);
 	}
 
-	spin_unlock(&cifs_file_list_lock);
+	spin_unlock(&tcon->open_file_lock);
 
 	if (inv_file) {
 		rc = cifs_reopen_file(inv_file, false);
 		if (!rc)
 			return inv_file;
 		else {
-			spin_lock(&cifs_file_list_lock);
+			spin_lock(&tcon->open_file_lock);
 			list_move_tail(&inv_file->flist,
 					&cifs_inode->openFileList);
-			spin_unlock(&cifs_file_list_lock);
+			spin_unlock(&tcon->open_file_lock);
 			cifsFileInfo_put(inv_file);
-			spin_lock(&cifs_file_list_lock);
 			++refind;
 			inv_file = NULL;
+			spin_lock(&tcon->open_file_lock);
 			goto refind_writable;
 		}
 	}
@@ -2535,7 +2593,7 @@
 		wdata->credits = credits;
 
 		if (!wdata->cfile->invalidHandle ||
-		    !cifs_reopen_file(wdata->cfile, false))
+		    !(rc = cifs_reopen_file(wdata->cfile, false)))
 			rc = server->ops->async_writev(wdata,
 					cifs_uncached_writedata_release);
 		if (rc) {
@@ -2728,14 +2786,16 @@
 	 * these pages but not on the region from pos to ppos+len-1.
 	 */
 	written = cifs_user_writev(iocb, from);
-	if (written > 0 && CIFS_CACHE_READ(cinode)) {
+	if (CIFS_CACHE_READ(cinode)) {
 		/*
-		 * Windows 7 server can delay breaking level2 oplock if a write
-		 * request comes - break it on the client to prevent reading
-		 * an old data.
+		 * We have read level caching and we have just sent a write
+		 * request to the server thus making data in the cache stale.
+		 * Zap the cache and set oplock/lease level to NONE to avoid
+		 * reading stale data from the cache. All subsequent read
+		 * operations will read new data from the server.
 		 */
 		cifs_zap_mapping(inode);
-		cifs_dbg(FYI, "Set no oplock for inode=%p after a write operation\n",
+		cifs_dbg(FYI, "Set Oplock/Lease to NONE for inode=%p after write\n",
 			 inode);
 		cinode->oplock = 0;
 	}
@@ -2790,7 +2850,9 @@
 	}
 
 	if (rc) {
-		for (i = 0; i < nr_pages; i++) {
+		unsigned int nr_page_failed = i;
+
+		for (i = 0; i < nr_page_failed; i++) {
 			put_page(rdata->pages[i]);
 			rdata->pages[i] = NULL;
 		}
@@ -2849,56 +2911,67 @@
 }
 
 static int
-cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
-			struct cifs_readdata *rdata, unsigned int len)
+uncached_fill_pages(struct TCP_Server_Info *server,
+		    struct cifs_readdata *rdata, struct iov_iter *iter,
+		    unsigned int len)
 {
 	int result = 0;
 	unsigned int i;
 	unsigned int nr_pages = rdata->nr_pages;
-	struct kvec iov;
 
 	rdata->got_bytes = 0;
 	rdata->tailsz = PAGE_SIZE;
 	for (i = 0; i < nr_pages; i++) {
 		struct page *page = rdata->pages[i];
+		size_t n;
 
-		if (len >= PAGE_SIZE) {
-			/* enough data to fill the page */
-			iov.iov_base = kmap(page);
-			iov.iov_len = PAGE_SIZE;
-			cifs_dbg(FYI, "%u: iov_base=%p iov_len=%zu\n",
-				 i, iov.iov_base, iov.iov_len);
-			len -= PAGE_SIZE;
-		} else if (len > 0) {
-			/* enough for partial page, fill and zero the rest */
-			iov.iov_base = kmap(page);
-			iov.iov_len = len;
-			cifs_dbg(FYI, "%u: iov_base=%p iov_len=%zu\n",
-				 i, iov.iov_base, iov.iov_len);
-			memset(iov.iov_base + len, '\0', PAGE_SIZE - len);
-			rdata->tailsz = len;
-			len = 0;
-		} else {
+		if (len <= 0) {
 			/* no need to hold page hostage */
 			rdata->pages[i] = NULL;
 			rdata->nr_pages--;
 			put_page(page);
 			continue;
 		}
-
-		result = cifs_readv_from_socket(server, &iov, 1, iov.iov_len);
-		kunmap(page);
+		n = len;
+		if (len >= PAGE_SIZE) {
+			/* enough data to fill the page */
+			n = PAGE_SIZE;
+			len -= n;
+		} else {
+			zero_user(page, len, PAGE_SIZE - len);
+			rdata->tailsz = len;
+			len = 0;
+		}
+		if (iter)
+			result = copy_page_from_iter(page, 0, n, iter);
+		else
+			result = cifs_read_page_from_socket(server, page, n);
 		if (result < 0)
 			break;
 
 		rdata->got_bytes += result;
 	}
 
-	return rdata->got_bytes > 0 && result != -ECONNABORTED ?
+	return result != -ECONNABORTED && rdata->got_bytes > 0 ?
 						rdata->got_bytes : result;
 }
 
 static int
+cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
+			      struct cifs_readdata *rdata, unsigned int len)
+{
+	return uncached_fill_pages(server, rdata, NULL, len);
+}
+
+static int
+cifs_uncached_copy_into_pages(struct TCP_Server_Info *server,
+			      struct cifs_readdata *rdata,
+			      struct iov_iter *iter)
+{
+	return uncached_fill_pages(server, rdata, iter, iter->count);
+}
+
+static int
 cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
 		     struct cifs_sb_info *cifs_sb, struct list_head *rdata_list)
 {
@@ -2945,10 +3018,11 @@
 		rdata->pid = pid;
 		rdata->pagesz = PAGE_SIZE;
 		rdata->read_into_pages = cifs_uncached_read_into_pages;
+		rdata->copy_into_pages = cifs_uncached_copy_into_pages;
 		rdata->credits = credits;
 
 		if (!rdata->cfile->invalidHandle ||
-		    !cifs_reopen_file(rdata->cfile, true))
+		    !(rc = cifs_reopen_file(rdata->cfile, true)))
 			rc = server->ops->async_readv(rdata);
 error:
 		if (rc) {
@@ -3168,7 +3242,7 @@
 			 * than it negotiated since it will refuse the read
 			 * then.
 			 */
-			if ((tcon->ses) && !(tcon->ses->capabilities &
+			if (!(tcon->ses->capabilities &
 				tcon->ses->server->vals->cap_large_files)) {
 				current_read_size = min_t(uint,
 					current_read_size, CIFSMaxBufSize);
@@ -3224,20 +3298,18 @@
 
 int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	int rc, xid;
+	int xid, rc = 0;
 	struct inode *inode = file_inode(file);
 
 	xid = get_xid();
 
-	if (!CIFS_CACHE_READ(CIFS_I(inode))) {
+	if (!CIFS_CACHE_READ(CIFS_I(inode)))
 		rc = cifs_zap_mapping(inode);
-		if (rc)
-			return rc;
-	}
-
-	rc = generic_file_mmap(file, vma);
-	if (rc == 0)
+	if (!rc)
+		rc = generic_file_mmap(file, vma);
+	if (!rc)
 		vma->vm_ops = &cifs_file_vm_ops;
+
 	free_xid(xid);
 	return rc;
 }
@@ -3247,16 +3319,16 @@
 	int rc, xid;
 
 	xid = get_xid();
+
 	rc = cifs_revalidate_file(file);
-	if (rc) {
+	if (rc)
 		cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n",
 			 rc);
-		free_xid(xid);
-		return rc;
-	}
-	rc = generic_file_mmap(file, vma);
-	if (rc == 0)
+	if (!rc)
+		rc = generic_file_mmap(file, vma);
+	if (!rc)
 		vma->vm_ops = &cifs_file_vm_ops;
+
 	free_xid(xid);
 	return rc;
 }
@@ -3295,15 +3367,15 @@
 }
 
 static int
-cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
-			struct cifs_readdata *rdata, unsigned int len)
+readpages_fill_pages(struct TCP_Server_Info *server,
+		     struct cifs_readdata *rdata, struct iov_iter *iter,
+		     unsigned int len)
 {
 	int result = 0;
 	unsigned int i;
 	u64 eof;
 	pgoff_t eof_index;
 	unsigned int nr_pages = rdata->nr_pages;
-	struct kvec iov;
 
 	/* determine the eof that the server (probably) has */
 	eof = CIFS_I(rdata->mapping->host)->server_eof;
@@ -3314,23 +3386,14 @@
 	rdata->tailsz = PAGE_CACHE_SIZE;
 	for (i = 0; i < nr_pages; i++) {
 		struct page *page = rdata->pages[i];
+		size_t n = PAGE_CACHE_SIZE;
 
 		if (len >= PAGE_CACHE_SIZE) {
-			/* enough data to fill the page */
-			iov.iov_base = kmap(page);
-			iov.iov_len = PAGE_CACHE_SIZE;
-			cifs_dbg(FYI, "%u: idx=%lu iov_base=%p iov_len=%zu\n",
-				 i, page->index, iov.iov_base, iov.iov_len);
 			len -= PAGE_CACHE_SIZE;
 		} else if (len > 0) {
 			/* enough for partial page, fill and zero the rest */
-			iov.iov_base = kmap(page);
-			iov.iov_len = len;
-			cifs_dbg(FYI, "%u: idx=%lu iov_base=%p iov_len=%zu\n",
-				 i, page->index, iov.iov_base, iov.iov_len);
-			memset(iov.iov_base + len,
-				'\0', PAGE_CACHE_SIZE - len);
-			rdata->tailsz = len;
+			zero_user(page, len, PAGE_CACHE_SIZE - len);
+			n = rdata->tailsz = len;
 			len = 0;
 		} else if (page->index > eof_index) {
 			/*
@@ -3360,19 +3423,36 @@
 			continue;
 		}
 
-		result = cifs_readv_from_socket(server, &iov, 1, iov.iov_len);
-		kunmap(page);
+		if (iter)
+			result = copy_page_from_iter(page, 0, n, iter);
+		else
+			result = cifs_read_page_from_socket(server, page, n);
 		if (result < 0)
 			break;
 
 		rdata->got_bytes += result;
 	}
 
-	return rdata->got_bytes > 0 && result != -ECONNABORTED ?
+	return result != -ECONNABORTED && rdata->got_bytes > 0 ?
 						rdata->got_bytes : result;
 }
 
 static int
+cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
+			       struct cifs_readdata *rdata, unsigned int len)
+{
+	return readpages_fill_pages(server, rdata, NULL, len);
+}
+
+static int
+cifs_readpages_copy_into_pages(struct TCP_Server_Info *server,
+			       struct cifs_readdata *rdata,
+			       struct iov_iter *iter)
+{
+	return readpages_fill_pages(server, rdata, iter, iter->count);
+}
+
+static int
 readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
 		    unsigned int rsize, struct list_head *tmplist,
 		    unsigned int *nr_pages, loff_t *offset, unsigned int *bytes)
@@ -3526,6 +3606,7 @@
 		rdata->pid = pid;
 		rdata->pagesz = PAGE_CACHE_SIZE;
 		rdata->read_into_pages = cifs_readpages_read_into_pages;
+		rdata->copy_into_pages = cifs_readpages_copy_into_pages;
 		rdata->credits = credits;
 
 		list_for_each_entry_safe(page, tpage, &tmplist, lru) {
@@ -3534,7 +3615,7 @@
 		}
 
 		if (!rdata->cfile->invalidHandle ||
-		    !cifs_reopen_file(rdata->cfile, true))
+		    !(rc = cifs_reopen_file(rdata->cfile, true)))
 			rc = server->ops->async_readv(rdata);
 		if (rc) {
 			add_credits_and_wake_if(server, rdata->credits, 0);
@@ -3632,15 +3713,17 @@
 static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
 {
 	struct cifsFileInfo *open_file;
+	struct cifs_tcon *tcon =
+		cifs_sb_master_tcon(CIFS_SB(cifs_inode->vfs_inode.i_sb));
 
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&tcon->open_file_lock);
 	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
 		if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
-			spin_unlock(&cifs_file_list_lock);
+			spin_unlock(&tcon->open_file_lock);
 			return 1;
 		}
 	}
-	spin_unlock(&cifs_file_list_lock);
+	spin_unlock(&tcon->open_file_lock);
 	return 0;
 }
 
--- linux-4.4.0.orig/fs/cifs/inode.c
+++ linux-4.4.0/fs/cifs/inode.c
@@ -405,6 +405,7 @@
 		/* if uniqueid is different, return error */
 		if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
 		    CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) {
+			CIFS_I(*pinode)->time = 0; /* force reval */
 			rc = -ESTALE;
 			goto cgiiu_exit;
 		}
@@ -412,6 +413,7 @@
 		/* if filetype is different, return error */
 		if (unlikely(((*pinode)->i_mode & S_IFMT) !=
 		    (fattr.cf_mode & S_IFMT))) {
+			CIFS_I(*pinode)->time = 0; /* force reval */
 			rc = -ESTALE;
 			goto cgiiu_exit;
 		}
@@ -756,38 +758,53 @@
 	} else if (rc == -EREMOTE) {
 		cifs_create_dfs_fattr(&fattr, sb);
 		rc = 0;
-	} else if (rc == -EACCES && backup_cred(cifs_sb)) {
-			srchinf = kzalloc(sizeof(struct cifs_search_info),
-						GFP_KERNEL);
-			if (srchinf == NULL) {
-				rc = -ENOMEM;
-				goto cgii_exit;
-			}
+	} else if ((rc == -EACCES) && backup_cred(cifs_sb) &&
+		   (strcmp(server->vals->version_string, SMB1_VERSION_STRING)
+		      == 0)) {
+		/*
+		 * For SMB2 and later the backup intent flag is already
+		 * sent if needed on open and there is no path based
+		 * FindFirst operation to use to retry with
+		 */
+
+		srchinf = kzalloc(sizeof(struct cifs_search_info),
+					GFP_KERNEL);
+		if (srchinf == NULL) {
+			rc = -ENOMEM;
+			goto cgii_exit;
+		}
 
-			srchinf->endOfSearch = false;
+		srchinf->endOfSearch = false;
+		if (tcon->unix_ext)
+			srchinf->info_level = SMB_FIND_FILE_UNIX;
+		else if ((tcon->ses->capabilities &
+			 tcon->ses->server->vals->cap_nt_find) == 0)
+			srchinf->info_level = SMB_FIND_FILE_INFO_STANDARD;
+		else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
 			srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
+		else /* no srvino useful for fallback to some netapp */
+			srchinf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
 
-			srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
-					CIFS_SEARCH_CLOSE_AT_END |
-					CIFS_SEARCH_BACKUP_SEARCH;
-
-			rc = CIFSFindFirst(xid, tcon, full_path,
-				cifs_sb, NULL, srchflgs, srchinf, false);
-			if (!rc) {
-				data =
-				(FILE_ALL_INFO *)srchinf->srch_entries_start;
-
-				cifs_dir_info_to_fattr(&fattr,
-				(FILE_DIRECTORY_INFO *)data, cifs_sb);
-				fattr.cf_uniqueid = le64_to_cpu(
-				((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
-				validinum = true;
+		srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
+				CIFS_SEARCH_CLOSE_AT_END |
+				CIFS_SEARCH_BACKUP_SEARCH;
+
+		rc = CIFSFindFirst(xid, tcon, full_path,
+			cifs_sb, NULL, srchflgs, srchinf, false);
+		if (!rc) {
+			data = (FILE_ALL_INFO *)srchinf->srch_entries_start;
+
+			cifs_dir_info_to_fattr(&fattr,
+			(FILE_DIRECTORY_INFO *)data, cifs_sb);
+			fattr.cf_uniqueid = le64_to_cpu(
+			((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
+			validinum = true;
 
-				cifs_buf_release(srchinf->ntwrk_buf_start);
-			}
-			kfree(srchinf);
-			if (rc)
-				goto cgii_exit;
+			cifs_buf_release(srchinf->ntwrk_buf_start);
+		}
+		kfree(srchinf);
+		if (rc)
+			goto cgii_exit;
 	} else
 		goto cgii_exit;
 
@@ -814,8 +831,21 @@
 			}
 		} else
 			fattr.cf_uniqueid = iunique(sb, ROOT_I);
-	} else
-		fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+	} else {
+		if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+		    validinum == false && server->ops->get_srv_inum) {
+			/*
+			 * Pass a NULL tcon to ensure we don't make a round
+			 * trip to the server. This only works for SMB2+.
+			 */
+			tmprc = server->ops->get_srv_inum(xid,
+				NULL, cifs_sb, full_path,
+				&fattr.cf_uniqueid, data);
+			if (tmprc)
+				fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+		} else
+			fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+	}
 
 	/* query for SFU type info if supported and needed */
 	if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
@@ -856,9 +886,18 @@
 	} else {
 		/* we already have inode, update it */
 
+		/* if uniqueid is different, return error */
+		if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
+		    CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
+			CIFS_I(*inode)->time = 0; /* force reval */
+			rc = -ESTALE;
+			goto cgii_exit;
+		}
+
 		/* if filetype is different, return error */
 		if (unlikely(((*inode)->i_mode & S_IFMT) !=
 		    (fattr.cf_mode & S_IFMT))) {
+			CIFS_I(*inode)->time = 0; /* force reval */
 			rc = -ESTALE;
 			goto cgii_exit;
 		}
@@ -982,10 +1021,26 @@
 	struct inode *inode = NULL;
 	long rc;
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+	char *path = NULL;
+	int len;
+
+	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+	    && cifs_sb->prepath) {
+		len = strlen(cifs_sb->prepath);
+		path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
+		if (path == NULL)
+			return ERR_PTR(-ENOMEM);
+		path[0] = '/';
+		memcpy(path+1, cifs_sb->prepath, len);
+	} else {
+		path = kstrdup("", GFP_KERNEL);
+		if (path == NULL)
+			return ERR_PTR(-ENOMEM);
+	}
 
 	xid = get_xid();
 	if (tcon->unix_ext) {
-		rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
+		rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
 		/* some servers mistakenly claim POSIX support */
 		if (rc != -EOPNOTSUPP)
 			goto iget_no_retry;
@@ -993,7 +1048,8 @@
 		tcon->unix_ext = false;
 	}
 
-	rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
+	convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
+	rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
 
 iget_no_retry:
 	if (!inode) {
@@ -1022,6 +1078,7 @@
 	}
 
 out:
+	kfree(path);
 	/* can not call macro free_xid here since in a void func
 	 * TODO: This is no longer true
 	 */
@@ -1045,6 +1102,8 @@
 	if (!server->ops->set_file_info)
 		return -ENOSYS;
 
+	info_buf.Pad = 0;
+
 	if (attrs->ia_valid & ATTR_ATIME) {
 		set_time = true;
 		info_buf.LastAccessTime =
@@ -1481,7 +1540,7 @@
 	struct TCP_Server_Info *server;
 	char *full_path;
 
-	cifs_dbg(FYI, "In cifs_mkdir, mode = 0x%hx inode = 0x%p\n",
+	cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n",
 		 mode, inode);
 
 	cifs_sb = CIFS_SB(inode->i_sb);
@@ -1634,6 +1693,10 @@
 	if (rc == 0 || rc != -EBUSY)
 		goto do_rename_exit;
 
+	/* Don't fall back to using SMB on SMB 2+ mount */
+	if (server->vals->protocol_id != 0)
+		goto do_rename_exit;
+
 	/* open-file renames don't work across directories */
 	if (to_dentry->d_parent != from_dentry->d_parent)
 		goto do_rename_exit;
@@ -1894,6 +1957,7 @@
 	struct inode *inode = d_inode(dentry);
 	struct super_block *sb = dentry->d_sb;
 	char *full_path = NULL;
+	int count = 0;
 
 	if (inode == NULL)
 		return -ENOENT;
@@ -1915,15 +1979,18 @@
 		 full_path, inode, inode->i_count.counter,
 		 dentry, dentry->d_time, jiffies);
 
+again:
 	if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
 		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
 	else
 		rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
 					 xid, NULL);
-
+	if (rc == -EAGAIN && count++ < 10)
+		goto again;
 out:
 	kfree(full_path);
 	free_xid(xid);
+
 	return rc;
 }
 
@@ -2116,7 +2183,7 @@
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
 		attrs->ia_valid |= ATTR_FORCE;
 
-	rc = inode_change_ok(inode, attrs);
+	rc = setattr_prepare(direntry, attrs);
 	if (rc < 0)
 		goto out;
 
@@ -2256,7 +2323,7 @@
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
 		attrs->ia_valid |= ATTR_FORCE;
 
-	rc = inode_change_ok(inode, attrs);
+	rc = setattr_prepare(direntry, attrs);
 	if (rc < 0) {
 		free_xid(xid);
 		return rc;
--- linux-4.4.0.orig/fs/cifs/ioctl.c
+++ linux-4.4.0/fs/cifs/ioctl.c
@@ -272,6 +272,8 @@
 				rc = -EOPNOTSUPP;
 			break;
 		case CIFS_IOC_GET_MNT_INFO:
+			if (pSMBFile == NULL)
+				break;
 			tcon = tlink_tcon(pSMBFile->tlink);
 			rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg);
 			break;
--- linux-4.4.0.orig/fs/cifs/link.c
+++ linux-4.4.0/fs/cifs/link.c
@@ -419,7 +419,7 @@
 	struct cifs_io_parms io_parms;
 	int buf_type = CIFS_NO_BUFFER;
 	__le16 *utf16_path;
-	__u8 oplock = SMB2_OPLOCK_LEVEL_II;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	struct smb2_file_all_info *pfile_info = NULL;
 
 	oparms.tcon = tcon;
@@ -481,7 +481,7 @@
 	struct cifs_io_parms io_parms;
 	int create_options = CREATE_NOT_DIR;
 	__le16 *utf16_path;
-	__u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	struct kvec iov[2];
 
 	if (backup_cred(cifs_sb))
--- linux-4.4.0.orig/fs/cifs/misc.c
+++ linux-4.4.0/fs/cifs/misc.c
@@ -99,14 +99,11 @@
 	kfree(buf_to_free->serverOS);
 	kfree(buf_to_free->serverDomain);
 	kfree(buf_to_free->serverNOS);
-	if (buf_to_free->password) {
-		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
-		kfree(buf_to_free->password);
-	}
+	kzfree(buf_to_free->password);
 	kfree(buf_to_free->user_name);
 	kfree(buf_to_free->domainName);
-	kfree(buf_to_free->auth_key.response);
-	kfree(buf_to_free);
+	kzfree(buf_to_free->auth_key.response);
+	kzfree(buf_to_free);
 }
 
 struct cifs_tcon *
@@ -120,6 +117,7 @@
 		++ret_buf->tc_count;
 		INIT_LIST_HEAD(&ret_buf->openFileList);
 		INIT_LIST_HEAD(&ret_buf->tcon_list);
+		spin_lock_init(&ret_buf->open_file_lock);
 #ifdef CONFIG_CIFS_STATS
 		spin_lock_init(&ret_buf->stat_lock);
 #endif
@@ -136,10 +134,7 @@
 	}
 	atomic_dec(&tconInfoAllocCount);
 	kfree(buf_to_free->nativeFileSystem);
-	if (buf_to_free->password) {
-		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
-		kfree(buf_to_free->password);
-	}
+	kzfree(buf_to_free->password);
 	kfree(buf_to_free);
 }
 
@@ -310,7 +305,7 @@
 }
 
 int
-checkSMB(char *buf, unsigned int total_read)
+checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
 {
 	struct smb_hdr *smb = (struct smb_hdr *)buf;
 	__u32 rfclen = be32_to_cpu(smb->smb_buf_length);
@@ -347,6 +342,10 @@
 			cifs_dbg(VFS, "Length less than smb header size\n");
 		}
 		return -EIO;
+	} else if (total_read < sizeof(*smb) + 2 * smb->WordCount) {
+		cifs_dbg(VFS, "%s: can't read BCC due to invalid WordCount(%u)\n",
+			 __func__, smb->WordCount);
+		return -EIO;
 	}
 
 	/* otherwise, there is enough to get to the BCC */
@@ -411,9 +410,17 @@
 			(struct smb_com_transaction_change_notify_rsp *)buf;
 		struct file_notify_information *pnotify;
 		__u32 data_offset = 0;
+		size_t len = srv->total_read - sizeof(pSMBr->hdr.smb_buf_length);
+
 		if (get_bcc(buf) > sizeof(struct file_notify_information)) {
 			data_offset = le32_to_cpu(pSMBr->DataOffset);
 
+			if (data_offset >
+			    len - sizeof(struct file_notify_information)) {
+				cifs_dbg(FYI, "invalid data_offset %u\n",
+					 data_offset);
+				return true;
+			}
 			pnotify = (struct file_notify_information *)
 				((char *)&pSMBr->hdr.Protocol + data_offset);
 			cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
@@ -465,7 +472,7 @@
 				continue;
 
 			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
-			spin_lock(&cifs_file_list_lock);
+			spin_lock(&tcon->open_file_lock);
 			list_for_each(tmp2, &tcon->openFileList) {
 				netfile = list_entry(tmp2, struct cifsFileInfo,
 						     tlist);
@@ -495,11 +502,11 @@
 					   &netfile->oplock_break);
 				netfile->oplock_break_cancelled = false;
 
-				spin_unlock(&cifs_file_list_lock);
+				spin_unlock(&tcon->open_file_lock);
 				spin_unlock(&cifs_tcp_ses_lock);
 				return true;
 			}
-			spin_unlock(&cifs_file_list_lock);
+			spin_unlock(&tcon->open_file_lock);
 			spin_unlock(&cifs_tcp_ses_lock);
 			cifs_dbg(FYI, "No matching file for oplock break\n");
 			return true;
@@ -613,9 +620,9 @@
 void
 cifs_del_pending_open(struct cifs_pending_open *open)
 {
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&tlink_tcon(open->tlink)->open_file_lock);
 	list_del(&open->olist);
-	spin_unlock(&cifs_file_list_lock);
+	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
 }
 
 void
@@ -635,7 +642,7 @@
 cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
 		      struct cifs_pending_open *open)
 {
-	spin_lock(&cifs_file_list_lock);
+	spin_lock(&tlink_tcon(tlink)->open_file_lock);
 	cifs_add_pending_open_locked(fid, tlink, open);
-	spin_unlock(&cifs_file_list_lock);
+	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
 }
--- linux-4.4.0.orig/fs/cifs/netmisc.c
+++ linux-4.4.0/fs/cifs/netmisc.c
@@ -130,10 +130,6 @@
 	{0, 0}
 };
 
-static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
-	{0, 0}
-};
-
 /*
  * Convert a string containing text IPv4 or IPv6 address to binary form.
  *
@@ -980,10 +976,10 @@
 		cifs_dbg(VFS, "illegal hours %d\n", st->Hours);
 	days = sd->Day;
 	month = sd->Month;
-	if ((days > 31) || (month > 12)) {
+	if (days < 1 || days > 31 || month < 1 || month > 12) {
 		cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, days);
-		if (month > 12)
-			month = 12;
+		days = clamp(days, 1, 31);
+		month = clamp(month, 1, 12);
 	}
 	month -= 1;
 	days += total_days_of_prev_months[month];
--- linux-4.4.0.orig/fs/cifs/ntlmssp.h
+++ linux-4.4.0/fs/cifs/ntlmssp.h
@@ -133,6 +133,6 @@
 
 int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
 void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses);
-int build_ntlmssp_auth_blob(unsigned char *pbuffer, u16 *buflen,
+int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
 			struct cifs_ses *ses,
 			const struct nls_table *nls_cp);
--- linux-4.4.0.orig/fs/cifs/readdir.c
+++ linux-4.4.0/fs/cifs/readdir.c
@@ -282,6 +282,7 @@
 			rc = -ENOMEM;
 			goto error_exit;
 		}
+		spin_lock_init(&cifsFile->file_info_lock);
 		file->private_data = cifsFile;
 		cifsFile->tlink = cifs_get_tlink(tlink);
 		tcon = tlink_tcon(tlink);
@@ -372,8 +373,15 @@
 
 		new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
 				pfData->FileNameLength;
-	} else
-		new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
+	} else {
+		u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset);
+
+		if (old_entry + next_offset < old_entry) {
+			cifs_dbg(VFS, "invalid offset %u\n", next_offset);
+			return NULL;
+		}
+		new_entry = old_entry + next_offset;
+	}
 	cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry);
 	/* validate that new_entry is not past end of SMB */
 	if (new_entry >= end_of_smb) {
@@ -594,14 +602,14 @@
 	     is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
 		/* close and restart search */
 		cifs_dbg(FYI, "search backing up - close and restart search\n");
-		spin_lock(&cifs_file_list_lock);
+		spin_lock(&cfile->file_info_lock);
 		if (server->ops->dir_needs_close(cfile)) {
 			cfile->invalidHandle = true;
-			spin_unlock(&cifs_file_list_lock);
+			spin_unlock(&cfile->file_info_lock);
 			if (server->ops->close_dir)
 				server->ops->close_dir(xid, tcon, &cfile->fid);
 		} else
-			spin_unlock(&cifs_file_list_lock);
+			spin_unlock(&cfile->file_info_lock);
 		if (cfile->srch_inf.ntwrk_buf_start) {
 			cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n");
 			if (cfile->srch_inf.smallBuf)
@@ -644,7 +652,14 @@
 		/* scan and find it */
 		int i;
 		char *cur_ent;
-		char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
+		char *end_of_smb;
+
+		if (cfile->srch_inf.ntwrk_buf_start == NULL) {
+			cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir\n");
+			return -EIO;
+		}
+
+		end_of_smb = cfile->srch_inf.ntwrk_buf_start +
 			server->ops->calc_smb_size(
 					cfile->srch_inf.ntwrk_buf_start);
 
@@ -847,6 +862,7 @@
 		 * if buggy server returns . and .. late do we want to
 		 * check for that here?
 		 */
+		*tmp_buf = 0;
 		rc = cifs_filldir(current_entry, file, ctx,
 				  tmp_buf, max_len);
 		if (rc) {
--- linux-4.4.0.orig/fs/cifs/sess.c
+++ linux-4.4.0/fs/cifs/sess.c
@@ -344,13 +344,12 @@
 	/* BB is NTLMV2 session security format easier to use here? */
 	flags = NTLMSSP_NEGOTIATE_56 |	NTLMSSP_REQUEST_TARGET |
 		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
-		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-	if (ses->server->sign) {
+		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
+		NTLMSSP_NEGOTIATE_SEAL;
+	if (ses->server->sign)
 		flags |= NTLMSSP_NEGOTIATE_SIGN;
-		if (!ses->server->session_estab ||
-				ses->ntlmssp->sesskey_per_smbsess)
-			flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
-	}
+	if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
+		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 
 	sec_blob->NegotiateFlags = cpu_to_le32(flags);
 
@@ -364,34 +363,63 @@
 	sec_blob->DomainName.MaximumLength = 0;
 }
 
-/* We do not malloc the blob, it is passed in pbuffer, because its
-   maximum possible size is fixed and small, making this approach cleaner.
-   This function returns the length of the data in the blob */
-int build_ntlmssp_auth_blob(unsigned char *pbuffer,
+static int size_of_ntlmssp_blob(struct cifs_ses *ses)
+{
+	int sz = sizeof(AUTHENTICATE_MESSAGE) + ses->auth_key.len
+		- CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2;
+
+	if (ses->domainName)
+		sz += 2 * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
+	else
+		sz += 2;
+
+	if (ses->user_name)
+		sz += 2 * strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
+	else
+		sz += 2;
+
+	return sz;
+}
+
+int build_ntlmssp_auth_blob(unsigned char **pbuffer,
 					u16 *buflen,
 				   struct cifs_ses *ses,
 				   const struct nls_table *nls_cp)
 {
 	int rc;
-	AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
+	AUTHENTICATE_MESSAGE *sec_blob;
 	__u32 flags;
 	unsigned char *tmp;
 
+	rc = setup_ntlmv2_rsp(ses, nls_cp);
+	if (rc) {
+		cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc);
+		*buflen = 0;
+		goto setup_ntlmv2_ret;
+	}
+	*pbuffer = kmalloc(size_of_ntlmssp_blob(ses), GFP_KERNEL);
+	if (!*pbuffer) {
+		rc = -ENOMEM;
+		cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
+		*buflen = 0;
+		goto setup_ntlmv2_ret;
+	}
+	sec_blob = (AUTHENTICATE_MESSAGE *)*pbuffer;
+
 	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
 	sec_blob->MessageType = NtLmAuthenticate;
 
 	flags = NTLMSSP_NEGOTIATE_56 |
 		NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
 		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
-		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-	if (ses->server->sign) {
+		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
+		NTLMSSP_NEGOTIATE_SEAL;
+	if (ses->server->sign)
 		flags |= NTLMSSP_NEGOTIATE_SIGN;
-		if (!ses->server->session_estab ||
-				ses->ntlmssp->sesskey_per_smbsess)
-			flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
-	}
+	if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
+		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 
-	tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE);
+	tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
 	sec_blob->NegotiateFlags = cpu_to_le32(flags);
 
 	sec_blob->LmChallengeResponse.BufferOffset =
@@ -399,23 +427,27 @@
 	sec_blob->LmChallengeResponse.Length = 0;
 	sec_blob->LmChallengeResponse.MaximumLength = 0;
 
-	sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
-	rc = setup_ntlmv2_rsp(ses, nls_cp);
-	if (rc) {
-		cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc);
-		goto setup_ntlmv2_ret;
+	sec_blob->NtChallengeResponse.BufferOffset =
+				cpu_to_le32(tmp - *pbuffer);
+	if (ses->user_name != NULL) {
+		memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
+				ses->auth_key.len - CIFS_SESS_KEY_SIZE);
+		tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
+
+		sec_blob->NtChallengeResponse.Length =
+				cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
+		sec_blob->NtChallengeResponse.MaximumLength =
+				cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
+	} else {
+		/*
+		 * don't send an NT Response for anonymous access
+		 */
+		sec_blob->NtChallengeResponse.Length = 0;
+		sec_blob->NtChallengeResponse.MaximumLength = 0;
 	}
-	memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
-			ses->auth_key.len - CIFS_SESS_KEY_SIZE);
-	tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
-
-	sec_blob->NtChallengeResponse.Length =
-			cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
-	sec_blob->NtChallengeResponse.MaximumLength =
-			cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
 
 	if (ses->domainName == NULL) {
-		sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
+		sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
 		sec_blob->DomainName.Length = 0;
 		sec_blob->DomainName.MaximumLength = 0;
 		tmp += 2;
@@ -424,14 +456,14 @@
 		len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName,
 				      CIFS_MAX_USERNAME_LEN, nls_cp);
 		len *= 2; /* unicode is 2 bytes each */
-		sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
+		sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
 		sec_blob->DomainName.Length = cpu_to_le16(len);
 		sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
 		tmp += len;
 	}
 
 	if (ses->user_name == NULL) {
-		sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
+		sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
 		sec_blob->UserName.Length = 0;
 		sec_blob->UserName.MaximumLength = 0;
 		tmp += 2;
@@ -440,13 +472,13 @@
 		len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name,
 				      CIFS_MAX_USERNAME_LEN, nls_cp);
 		len *= 2; /* unicode is 2 bytes each */
-		sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
+		sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
 		sec_blob->UserName.Length = cpu_to_le16(len);
 		sec_blob->UserName.MaximumLength = cpu_to_le16(len);
 		tmp += len;
 	}
 
-	sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer);
+	sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
 	sec_blob->WorkstationName.Length = 0;
 	sec_blob->WorkstationName.MaximumLength = 0;
 	tmp += 2;
@@ -455,19 +487,19 @@
 		(ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
 			&& !calc_seckey(ses)) {
 		memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
-		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
+		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
 		sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
 		sec_blob->SessionKey.MaximumLength =
 				cpu_to_le16(CIFS_CPHTXT_SIZE);
 		tmp += CIFS_CPHTXT_SIZE;
 	} else {
-		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
+		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
 		sec_blob->SessionKey.Length = 0;
 		sec_blob->SessionKey.MaximumLength = 0;
 	}
 
+	*buflen = tmp - *pbuffer;
 setup_ntlmv2_ret:
-	*buflen = tmp - pbuffer;
 	return rc;
 }
 
@@ -624,6 +656,7 @@
 	int rc;
 	struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base;
 	__u16 count;
+	struct kvec rsp_iov = { NULL, 0 };
 
 	count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
 	smb_buf->smb_buf_length =
@@ -633,7 +666,9 @@
 	rc = SendReceive2(sess_data->xid, sess_data->ses,
 			  sess_data->iov, 3 /* num_iovecs */,
 			  &sess_data->buf0_type,
-			  CIFS_LOG_ERROR);
+			  CIFS_LOG_ERROR, &rsp_iov);
+	cifs_small_buf_release(sess_data->iov[0].iov_base);
+	memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
 
 	return rc;
 }
@@ -670,20 +705,24 @@
 
 	pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE;
 
-	/* no capabilities flags in old lanman negotiation */
-	pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
-
-	/* Calculate hash with password and copy into bcc_ptr.
-	 * Encryption Key (stored as in cryptkey) gets used if the
-	 * security mode bit in Negottiate Protocol response states
-	 * to use challenge/response method (i.e. Password bit is 1).
-	 */
-	rc = calc_lanman_hash(ses->password, ses->server->cryptkey,
-			      ses->server->sec_mode & SECMODE_PW_ENCRYPT ?
-			      true : false, lnm_session_key);
+	if (ses->user_name != NULL) {
+		/* no capabilities flags in old lanman negotiation */
+		pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
+
+		/* Calculate hash with password and copy into bcc_ptr.
+		 * Encryption Key (stored as in cryptkey) gets used if the
+		 * security mode bit in Negottiate Protocol response states
+		 * to use challenge/response method (i.e. Password bit is 1).
+		 */
+		rc = calc_lanman_hash(ses->password, ses->server->cryptkey,
+				      ses->server->sec_mode & SECMODE_PW_ENCRYPT ?
+				      true : false, lnm_session_key);
 
-	memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE);
-	bcc_ptr += CIFS_AUTH_RESP_SIZE;
+		memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE);
+		bcc_ptr += CIFS_AUTH_RESP_SIZE;
+	} else {
+		pSMB->old_req.PasswordLength = 0;
+	}
 
 	/*
 	 * can not sign if LANMAN negotiated so no need
@@ -769,27 +808,32 @@
 	capabilities = cifs_ssetup_hdr(ses, pSMB);
 
 	pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
-	pSMB->req_no_secext.CaseInsensitivePasswordLength =
-			cpu_to_le16(CIFS_AUTH_RESP_SIZE);
-	pSMB->req_no_secext.CaseSensitivePasswordLength =
-			cpu_to_le16(CIFS_AUTH_RESP_SIZE);
-
-	/* calculate ntlm response and session key */
-	rc = setup_ntlm_response(ses, sess_data->nls_cp);
-	if (rc) {
-		cifs_dbg(VFS, "Error %d during NTLM authentication\n",
-				 rc);
-		goto out;
+	if (ses->user_name != NULL) {
+		pSMB->req_no_secext.CaseInsensitivePasswordLength =
+				cpu_to_le16(CIFS_AUTH_RESP_SIZE);
+		pSMB->req_no_secext.CaseSensitivePasswordLength =
+				cpu_to_le16(CIFS_AUTH_RESP_SIZE);
+
+		/* calculate ntlm response and session key */
+		rc = setup_ntlm_response(ses, sess_data->nls_cp);
+		if (rc) {
+			cifs_dbg(VFS, "Error %d during NTLM authentication\n",
+					 rc);
+			goto out;
+		}
+
+		/* copy ntlm response */
+		memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
+				CIFS_AUTH_RESP_SIZE);
+		bcc_ptr += CIFS_AUTH_RESP_SIZE;
+		memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
+				CIFS_AUTH_RESP_SIZE);
+		bcc_ptr += CIFS_AUTH_RESP_SIZE;
+	} else {
+		pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+		pSMB->req_no_secext.CaseSensitivePasswordLength = 0;
 	}
 
-	/* copy ntlm response */
-	memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
-			CIFS_AUTH_RESP_SIZE);
-	bcc_ptr += CIFS_AUTH_RESP_SIZE;
-	memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
-			CIFS_AUTH_RESP_SIZE);
-	bcc_ptr += CIFS_AUTH_RESP_SIZE;
-
 	if (ses->capabilities & CAP_UNICODE) {
 		/* unicode strings must be word aligned */
 		if (sess_data->iov[0].iov_len % 2) {
@@ -878,23 +922,27 @@
 	/* LM2 password would be here if we supported it */
 	pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
 
-	/* calculate nlmv2 response and session key */
-	rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp);
-	if (rc) {
-		cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc);
-		goto out;
+	if (ses->user_name != NULL) {
+		/* calculate nlmv2 response and session key */
+		rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp);
+		if (rc) {
+			cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc);
+			goto out;
+		}
+
+		memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
+				ses->auth_key.len - CIFS_SESS_KEY_SIZE);
+		bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
+
+		/* set case sensitive password length after tilen may get
+		 * assigned, tilen is 0 otherwise.
+		 */
+		pSMB->req_no_secext.CaseSensitivePasswordLength =
+			cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
+	} else {
+		pSMB->req_no_secext.CaseSensitivePasswordLength = 0;
 	}
 
-	memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
-			ses->auth_key.len - CIFS_SESS_KEY_SIZE);
-	bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
-
-	/* set case sensitive password length after tilen may get
-	 * assigned, tilen is 0 otherwise.
-	 */
-	pSMB->req_no_secext.CaseSensitivePasswordLength =
-		cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
-
 	if (ses->capabilities & CAP_UNICODE) {
 		if (sess_data->iov[0].iov_len % 2) {
 			*bcc_ptr = 0;
@@ -1245,7 +1293,7 @@
 	struct cifs_ses *ses = sess_data->ses;
 	__u16 bytes_remaining;
 	char *bcc_ptr;
-	char *ntlmsspblob = NULL;
+	unsigned char *ntlmsspblob = NULL;
 	u16 blob_len;
 
 	cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
@@ -1258,19 +1306,7 @@
 	/* Build security blob before we assemble the request */
 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
 	smb_buf = (struct smb_hdr *)pSMB;
-	/*
-	 * 5 is an empirical value, large enough to hold
-	 * authenticate message plus max 10 of av paris,
-	 * domain, user, workstation names, flags, etc.
-	 */
-	ntlmsspblob = kzalloc(5*sizeof(struct _AUTHENTICATE_MESSAGE),
-				GFP_KERNEL);
-	if (!ntlmsspblob) {
-		rc = -ENOMEM;
-		goto out;
-	}
-
-	rc = build_ntlmssp_auth_blob(ntlmsspblob,
+	rc = build_ntlmssp_auth_blob(&ntlmsspblob,
 					&blob_len, ses, sess_data->nls_cp);
 	if (rc)
 		goto out_free_ntlmsspblob;
--- linux-4.4.0.orig/fs/cifs/smb1ops.c
+++ linux-4.4.0/fs/cifs/smb1ops.c
@@ -36,11 +36,11 @@
  * SMB_COM_NT_CANCEL request and then sends it.
  */
 static int
-send_nt_cancel(struct TCP_Server_Info *server, void *buf,
+send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	       struct mid_q_entry *mid)
 {
 	int rc = 0;
-	struct smb_hdr *in_buf = (struct smb_hdr *)buf;
+	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
 	/* -4 for RFC1001 length and +2 for BCC field */
 	in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4  + 2);
@@ -180,6 +180,9 @@
 	/* we do not want to loop forever */
 	last_mid = cur_mid;
 	cur_mid++;
+	/* avoid 0xFFFF MID */
+	if (cur_mid == 0xffff)
+		cur_mid++;
 
 	/*
 	 * This nested loop looks more expensive than it is.
@@ -305,7 +308,7 @@
 	remaining = tgt_total_cnt - total_in_tgt;
 
 	if (remaining < 0) {
-		cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%hu\n",
+		cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
 			 tgt_total_cnt, total_in_tgt);
 		return -EPROTO;
 	}
@@ -849,8 +852,13 @@
 		     struct cifs_fid *fid, __u16 search_flags,
 		     struct cifs_search_info *srch_inf)
 {
-	return CIFSFindFirst(xid, tcon, path, cifs_sb,
-			     &fid->netfid, search_flags, srch_inf, true);
+	int rc;
+
+	rc = CIFSFindFirst(xid, tcon, path, cifs_sb,
+			   &fid->netfid, search_flags, srch_inf, true);
+	if (rc)
+		cifs_dbg(FYI, "find first failed=%d\n", rc);
+	return rc;
 }
 
 static int
@@ -1015,6 +1023,15 @@
 	return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
 }
 
+static bool
+cifs_can_echo(struct TCP_Server_Info *server)
+{
+	if (server->tcpStatus == CifsGood)
+		return true;
+
+	return false;
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -1049,6 +1066,7 @@
 	.get_dfs_refer = CIFSGetDFSRefer,
 	.qfs_tcon = cifs_qfs_tcon,
 	.is_path_accessible = cifs_is_path_accessible,
+	.can_echo = cifs_can_echo,
 	.query_path_info = cifs_query_path_info,
 	.query_file_info = cifs_query_file_info,
 	.get_srv_inum = cifs_get_srv_inum,
--- linux-4.4.0.orig/fs/cifs/smb2file.c
+++ linux-4.4.0/fs/cifs/smb2file.c
@@ -69,7 +69,7 @@
 		goto out;
 
 
-	 if (oparms->tcon->use_resilient) {
+	if (oparms->tcon->use_resilient) {
 		nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
 		nr_ioctl_req.Reserved = 0;
 		rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
@@ -123,12 +123,14 @@
 
 	/*
 	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
-	 * and check it for zero before using.
+	 * and check it before using.
 	 */
 	max_buf = tcon->ses->server->maxBuf;
-	if (!max_buf)
+	if (max_buf < sizeof(struct smb2_lock_element))
 		return -EINVAL;
 
+	BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
+	max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
 	max_num = max_buf / sizeof(struct smb2_lock_element);
 	buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
 	if (!buf)
@@ -136,7 +138,7 @@
 
 	cur = buf;
 
-	down_write(&cinode->lock_sem);
+	cifs_down_write(&cinode->lock_sem);
 	list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
 		if (flock->fl_start > li->offset ||
 		    (flock->fl_start + length) <
@@ -260,11 +262,13 @@
 	 * and check it for zero before using.
 	 */
 	max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
-	if (!max_buf) {
+	if (max_buf < sizeof(struct smb2_lock_element)) {
 		free_xid(xid);
 		return -EINVAL;
 	}
 
+	BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
+	max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
 	max_num = max_buf / sizeof(struct smb2_lock_element);
 	buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
 	if (!buf) {
--- linux-4.4.0.orig/fs/cifs/smb2glob.h
+++ linux-4.4.0/fs/cifs/smb2glob.h
@@ -44,6 +44,7 @@
 #define SMB2_OP_DELETE 7
 #define SMB2_OP_HARDLINK 8
 #define SMB2_OP_SET_EOF 9
+#define SMB2_OP_RMDIR 10
 
 /* Used when constructing chained read requests. */
 #define CHAINED_REQUEST 1
@@ -60,4 +61,9 @@
 /* Maximum buffer size value we can send with 1 credit */
 #define SMB2_MAX_BUFFER_SIZE 65536
 
+static inline struct smb2_sync_hdr *get_sync_hdr(void *buf)
+{
+	return &(((struct smb2_hdr *)buf)->sync_hdr);
+}
+
 #endif	/* _SMB2_GLOB_H */
--- linux-4.4.0.orig/fs/cifs/smb2inode.c
+++ linux-4.4.0/fs/cifs/smb2inode.c
@@ -80,6 +80,10 @@
 		 * SMB2_open() call.
 		 */
 		break;
+	case SMB2_OP_RMDIR:
+		tmprc = SMB2_rmdir(xid, tcon, fid.persistent_fid,
+				   fid.volatile_fid);
+		break;
 	case SMB2_OP_RENAME:
 		tmprc = SMB2_rename(xid, tcon, fid.persistent_fid,
 				    fid.volatile_fid, (__le16 *)data);
@@ -191,8 +195,8 @@
 	   struct cifs_sb_info *cifs_sb)
 {
 	return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
-				  CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
-				  NULL, SMB2_OP_DELETE);
+				  CREATE_NOT_FILE,
+				  NULL, SMB2_OP_RMDIR);
 }
 
 int
@@ -262,9 +266,15 @@
 	struct tcon_link *tlink;
 	int rc;
 
+	if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
+	    (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
+	    (buf->Attributes == 0))
+		return 0; /* would be a no op, no sense sending this */
+
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
+
 	rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
 				FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
 				SMB2_OP_SET_INFO);
--- linux-4.4.0.orig/fs/cifs/smb2maperror.c
+++ linux-4.4.0/fs/cifs/smb2maperror.c
@@ -26,6 +26,7 @@
 #include "smb2pdu.h"
 #include "smb2proto.h"
 #include "smb2status.h"
+#include "smb2glob.h"
 
 struct status_to_posix_error {
 	__le32 smb2_status;
@@ -377,8 +378,8 @@
 	{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_FILE_LOCK_CONFLICT, -EACCES, "STATUS_FILE_LOCK_CONFLICT"},
+	{STATUS_LOCK_NOT_GRANTED, -EACCES, "STATUS_LOCK_NOT_GRANTED"},
 	{STATUS_DELETE_PENDING, -ENOENT, "STATUS_DELETE_PENDING"},
 	{STATUS_CTL_FILE_NOT_SUPPORTED, -ENOSYS,
 	"STATUS_CTL_FILE_NOT_SUPPORTED"},
@@ -455,7 +456,7 @@
 	{STATUS_FILE_INVALID, -EIO, "STATUS_FILE_INVALID"},
 	{STATUS_ALLOTTED_SPACE_EXCEEDED, -EIO,
 	"STATUS_ALLOTTED_SPACE_EXCEEDED"},
-	{STATUS_INSUFFICIENT_RESOURCES, -EREMOTEIO,
+	{STATUS_INSUFFICIENT_RESOURCES, -EAGAIN,
 				"STATUS_INSUFFICIENT_RESOURCES"},
 	{STATUS_DFS_EXIT_PATH_FOUND, -EIO, "STATUS_DFS_EXIT_PATH_FOUND"},
 	{STATUS_DEVICE_DATA_ERROR, -EIO, "STATUS_DEVICE_DATA_ERROR"},
@@ -1034,7 +1035,8 @@
 	{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"},
+	/* Note that ENOATTTR and ENODATA are the same errno */
+	{STATUS_OBJECTID_NOT_FOUND, -ENODATA, "STATUS_OBJECTID_NOT_FOUND"},
 	{STATUS_NO_IP_ADDRESSES, -EIO, "STATUS_NO_IP_ADDRESSES"},
 	{STATUS_WRONG_CREDENTIAL_HANDLE, -EIO,
 	"STATUS_WRONG_CREDENTIAL_HANDLE"},
@@ -2449,10 +2451,10 @@
 int
 map_smb2_to_linux_error(char *buf, bool log_err)
 {
-	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+	struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 	unsigned int i;
 	int rc = -EIO;
-	__le32 smb2err = hdr->Status;
+	__le32 smb2err = shdr->Status;
 
 	if (smb2err == 0)
 		return 0;
--- linux-4.4.0.orig/fs/cifs/smb2misc.c
+++ linux-4.4.0/fs/cifs/smb2misc.c
@@ -28,31 +28,32 @@
 #include "cifs_debug.h"
 #include "cifs_unicode.h"
 #include "smb2status.h"
+#include "smb2glob.h"
 
 static int
-check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
+check_smb2_hdr(struct smb2_sync_hdr *shdr, __u64 mid)
 {
-	__u64 wire_mid = le64_to_cpu(hdr->MessageId);
+	__u64 wire_mid = le64_to_cpu(shdr->MessageId);
 
 	/*
 	 * Make sure that this really is an SMB, that it is a response,
 	 * and that the message ids match.
 	 */
-	if ((*(__le32 *)hdr->ProtocolId == SMB2_PROTO_NUMBER) &&
+	if ((shdr->ProtocolId == SMB2_PROTO_NUMBER) &&
 	    (mid == wire_mid)) {
-		if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
+		if (shdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
 			return 0;
 		else {
 			/* only one valid case where server sends us request */
-			if (hdr->Command == SMB2_OPLOCK_BREAK)
+			if (shdr->Command == SMB2_OPLOCK_BREAK)
 				return 0;
 			else
 				cifs_dbg(VFS, "Received Request not response\n");
 		}
 	} else { /* bad signature or mid */
-		if (*(__le32 *)hdr->ProtocolId != SMB2_PROTO_NUMBER)
+		if (shdr->ProtocolId != SMB2_PROTO_NUMBER)
 			cifs_dbg(VFS, "Bad protocol string signature header %x\n",
-				 *(unsigned int *) hdr->ProtocolId);
+				 le32_to_cpu(shdr->ProtocolId));
 		if (mid != wire_mid)
 			cifs_dbg(VFS, "Mids do not match: %llu and %llu\n",
 				 mid, wire_mid);
@@ -93,11 +94,12 @@
 };
 
 int
-smb2_check_message(char *buf, unsigned int length)
+smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 {
-	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
-	struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
-	__u64 mid = le64_to_cpu(hdr->MessageId);
+	struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
+	struct smb2_hdr *hdr = &pdu->hdr;
+	struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
+	__u64 mid;
 	__u32 len = get_rfc1002_length(buf);
 	__u32 clc_len;  /* calculated length */
 	int command;
@@ -111,8 +113,32 @@
 	 * ie Validate the wct via smb2_struct_sizes table above
 	 */
 
+	if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
+		struct smb2_transform_hdr *thdr =
+			(struct smb2_transform_hdr *)buf;
+		struct cifs_ses *ses = NULL;
+		struct list_head *tmp;
+
+		/* decrypt frame now that it is completely read in */
+		spin_lock(&cifs_tcp_ses_lock);
+		list_for_each(tmp, &srvr->smb_ses_list) {
+			ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+			if (ses->Suid == thdr->SessionId)
+				break;
+
+			ses = NULL;
+		}
+		spin_unlock(&cifs_tcp_ses_lock);
+		if (ses == NULL) {
+			cifs_dbg(VFS, "no decryption - session id not found\n");
+			return 1;
+		}
+	}
+
+	mid = le64_to_cpu(shdr->MessageId);
 	if (length < sizeof(struct smb2_pdu)) {
-		if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) {
+		if ((length >= sizeof(struct smb2_hdr))
+		    && (shdr->Status != 0)) {
 			pdu->StructureSize2 = 0;
 			/*
 			 * As with SMB/CIFS, on some error cases servers may
@@ -130,29 +156,30 @@
 		return 1;
 	}
 
-	if (check_smb2_hdr(hdr, mid))
+	if (check_smb2_hdr(shdr, mid))
 		return 1;
 
-	if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
+	if (shdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
 		cifs_dbg(VFS, "Illegal structure size %u\n",
-			 le16_to_cpu(hdr->StructureSize));
+			 le16_to_cpu(shdr->StructureSize));
 		return 1;
 	}
 
-	command = le16_to_cpu(hdr->Command);
+	command = le16_to_cpu(shdr->Command);
 	if (command >= NUMBER_OF_SMB2_COMMANDS) {
 		cifs_dbg(VFS, "Illegal SMB2 command %d\n", command);
 		return 1;
 	}
 
 	if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
-		if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 ||
+		if (command != SMB2_OPLOCK_BREAK_HE && (shdr->Status == 0 ||
 		    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
 			/* error packets have 9 byte structure size */
 			cifs_dbg(VFS, "Illegal response size %u for command %d\n",
 				 le16_to_cpu(pdu->StructureSize2), command);
 			return 1;
-		} else if (command == SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0)
+		} else if (command == SMB2_OPLOCK_BREAK_HE
+			   && (shdr->Status == 0)
 			   && (le16_to_cpu(pdu->StructureSize2) != 44)
 			   && (le16_to_cpu(pdu->StructureSize2) != 36)) {
 			/* special case for SMB2.1 lease break message */
@@ -175,7 +202,7 @@
 			 clc_len, 4 + len, mid);
 		/* create failed on symlink */
 		if (command == SMB2_CREATE_HE &&
-		    hdr->Status == STATUS_STOPPED_ON_SYMLINK)
+		    shdr->Status == STATUS_STOPPED_ON_SYMLINK)
 			return 0;
 		/* Windows 7 server returns 24 bytes more */
 		if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
@@ -185,6 +212,13 @@
 			return 0;
 
 		/*
+		 * Some windows servers (win2016) will pad also the final
+		 * PDU in a compound to 8 bytes.
+		 */
+		if (((clc_len + 7) & ~7) == len)
+			return 0;
+
+		/*
 		 * MacOS server pads after SMB2.1 write response with 3 bytes
 		 * of junk. Other servers match RFC1001 len to actual
 		 * SMB2/SMB3 frame length (header + smb2 response specific data)
@@ -237,11 +271,12 @@
 char *
 smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 {
+	struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
 	*off = 0;
 	*len = 0;
 
 	/* error responses do not have data area */
-	if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
+	if (shdr->Status && shdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
 	    (((struct smb2_err_rsp *)hdr)->StructureSize) ==
 						SMB2_ERROR_STRUCTURE_SIZE2)
 		return NULL;
@@ -251,7 +286,7 @@
 	 * of the data buffer offset and data buffer length for the particular
 	 * command.
 	 */
-	switch (hdr->Command) {
+	switch (shdr->Command) {
 	case SMB2_NEGOTIATE:
 		*off = le16_to_cpu(
 		    ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset);
@@ -322,7 +357,7 @@
 
 	/* return pointer to beginning of data area, ie offset from SMB start */
 	if ((*off != 0) && (*len != 0))
-		return (char *)(&hdr->ProtocolId[0]) + *off;
+		return (char *)shdr + *off;
 	else
 		return NULL;
 }
@@ -334,12 +369,13 @@
 unsigned int
 smb2_calc_size(void *buf)
 {
-	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
-	struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
+	struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
+	struct smb2_hdr *hdr = &pdu->hdr;
+	struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
 	int offset; /* the offset from the beginning of SMB to data area */
 	int data_length; /* the length of the variable length data area */
 	/* Structure Size has already been checked to make sure it is 64 */
-	int len = 4 + le16_to_cpu(pdu->hdr.StructureSize);
+	int len = 4 + le16_to_cpu(shdr->StructureSize);
 
 	/*
 	 * StructureSize2, ie length of fixed parameter area has already
@@ -347,7 +383,7 @@
 	 */
 	len += le16_to_cpu(pdu->StructureSize2);
 
-	if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false)
+	if (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false)
 		goto calc_size_exit;
 
 	smb2_get_data_area_len(&offset, &data_length, hdr);
@@ -524,20 +560,22 @@
 
 		list_for_each(tmp1, &server->smb_ses_list) {
 			ses = list_entry(tmp1, struct cifs_ses, smb_ses_list);
+			if (cifs_ses_exiting(ses))
+				continue;
 
-			spin_lock(&cifs_file_list_lock);
 			list_for_each(tmp2, &ses->tcon_list) {
 				tcon = list_entry(tmp2, struct cifs_tcon,
 						  tcon_list);
+				spin_lock(&tcon->open_file_lock);
 				cifs_stats_inc(
 				    &tcon->stats.cifs_stats.num_oplock_brks);
 				if (smb2_tcon_has_lease(tcon, rsp, lw)) {
-					spin_unlock(&cifs_file_list_lock);
+					spin_unlock(&tcon->open_file_lock);
 					spin_unlock(&cifs_tcp_ses_lock);
 					return true;
 				}
+				spin_unlock(&tcon->open_file_lock);
 			}
-			spin_unlock(&cifs_file_list_lock);
 		}
 	}
 	spin_unlock(&cifs_tcp_ses_lock);
@@ -558,7 +596,7 @@
 
 	cifs_dbg(FYI, "Checking for oplock break\n");
 
-	if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
+	if (rsp->hdr.sync_hdr.Command != SMB2_OPLOCK_BREAK)
 		return false;
 
 	if (rsp->StructureSize !=
@@ -575,11 +613,11 @@
 	spin_lock(&cifs_tcp_ses_lock);
 	list_for_each(tmp, &server->smb_ses_list) {
 		ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+
 		list_for_each(tmp1, &ses->tcon_list) {
 			tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
 
-			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
-			spin_lock(&cifs_file_list_lock);
+			spin_lock(&tcon->open_file_lock);
 			list_for_each(tmp2, &tcon->openFileList) {
 				cfile = list_entry(tmp2, struct cifsFileInfo,
 						     tlist);
@@ -590,8 +628,10 @@
 					continue;
 
 				cifs_dbg(FYI, "file id match, oplock break\n");
+				cifs_stats_inc(
+				    &tcon->stats.cifs_stats.num_oplock_brks);
 				cinode = CIFS_I(d_inode(cfile->dentry));
-
+				spin_lock(&cfile->file_info_lock);
 				if (!CIFS_CACHE_WRITE(cinode) &&
 				    rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
 					cfile->oplock_break_cancelled = true;
@@ -613,20 +653,63 @@
 					clear_bit(
 					   CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
 					   &cinode->flags);
-
+				spin_unlock(&cfile->file_info_lock);
 				queue_work(cifsiod_wq, &cfile->oplock_break);
 
-				spin_unlock(&cifs_file_list_lock);
+				spin_unlock(&tcon->open_file_lock);
 				spin_unlock(&cifs_tcp_ses_lock);
 				return true;
 			}
-			spin_unlock(&cifs_file_list_lock);
-			spin_unlock(&cifs_tcp_ses_lock);
-			cifs_dbg(FYI, "No matching file for oplock break\n");
-			return true;
+			spin_unlock(&tcon->open_file_lock);
 		}
 	}
 	spin_unlock(&cifs_tcp_ses_lock);
 	cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n");
 	return false;
 }
+
+void
+smb2_cancelled_close_fid(struct work_struct *work)
+{
+	struct close_cancelled_open *cancelled = container_of(work,
+					struct close_cancelled_open, work);
+
+	cifs_dbg(VFS, "Close unmatched open\n");
+
+	SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid,
+		   cancelled->fid.volatile_fid);
+	cifs_put_tcon(cancelled->tcon);
+	kfree(cancelled);
+}
+
+int
+smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
+{
+	struct smb2_sync_hdr *sync_hdr = get_sync_hdr(buffer);
+	struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer;
+	struct cifs_tcon *tcon;
+	struct close_cancelled_open *cancelled;
+
+	if (sync_hdr->Command != SMB2_CREATE ||
+	    sync_hdr->Status != STATUS_SUCCESS)
+		return 0;
+
+	cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
+	if (!cancelled)
+		return -ENOMEM;
+
+	tcon = smb2_find_smb_tcon(server, sync_hdr->SessionId,
+				  sync_hdr->TreeId);
+	if (!tcon) {
+		kfree(cancelled);
+		return -ENOENT;
+	}
+
+	cancelled->fid.persistent_fid = rsp->PersistentFileId;
+	cancelled->fid.volatile_fid = rsp->VolatileFileId;
+	cancelled->tcon = tcon;
+	INIT_WORK(&cancelled->work, smb2_cancelled_close_fid);
+	queue_work(cifsiod_wq, &cancelled->work);
+
+	return 0;
+}
--- linux-4.4.0.orig/fs/cifs/smb2ops.c
+++ linux-4.4.0/fs/cifs/smb2ops.c
@@ -20,6 +20,8 @@
 #include <linux/pagemap.h>
 #include <linux/vfs.h>
 #include <linux/falloc.h>
+#include <linux/scatterlist.h>
+#include <crypto/aead.h>
 #include "cifsglob.h"
 #include "smb2pdu.h"
 #include "smb2proto.h"
@@ -70,6 +72,10 @@
 	spin_lock(&server->req_lock);
 	val = server->ops->get_credits_field(server, optype);
 	*val += add;
+	if (*val > 65000) {
+		*val = 65000; /* Don't get near 64K credits, avoid srv bugs */
+		printk_once(KERN_WARNING "server overflowed SMB3 credits\n");
+	}
 	server->in_flight--;
 	if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP)
 		rc = change_conf(server);
@@ -114,7 +120,9 @@
 static unsigned int
 smb2_get_credits(struct mid_q_entry *mid)
 {
-	return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
+	struct smb2_sync_hdr *shdr = get_sync_hdr(mid->resp_buf);
+
+	return le16_to_cpu(shdr->CreditRequest);
 }
 
 static int
@@ -143,14 +151,14 @@
 
 			scredits = server->credits;
 			/* can deadlock with reopen */
-			if (scredits == 1) {
+			if (scredits <= 8) {
 				*num = SMB2_MAX_BUFFER_SIZE;
 				*credits = 0;
 				break;
 			}
 
-			/* leave one credit for a possible reopen */
-			scredits--;
+			/* leave some credits for reopen and other ops */
+			scredits -= 8;
 			*num = min_t(unsigned int, size,
 				     scredits * SMB2_MAX_BUFFER_SIZE);
 
@@ -179,14 +187,19 @@
 smb2_find_mid(struct TCP_Server_Info *server, char *buf)
 {
 	struct mid_q_entry *mid;
-	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
-	__u64 wire_mid = le64_to_cpu(hdr->MessageId);
+	struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
+	__u64 wire_mid = le64_to_cpu(shdr->MessageId);
+
+	if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
+		cifs_dbg(VFS, "encrypted frame parsing not supported yet");
+		return NULL;
+	}
 
 	spin_lock(&GlobalMid_Lock);
 	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
 		if ((mid->mid == wire_mid) &&
 		    (mid->mid_state == MID_REQUEST_SUBMITTED) &&
-		    (mid->command == hdr->Command)) {
+		    (mid->command == shdr->Command)) {
 			spin_unlock(&GlobalMid_Lock);
 			return mid;
 		}
@@ -199,12 +212,12 @@
 smb2_dump_detail(void *buf)
 {
 #ifdef CONFIG_CIFS_DEBUG2
-	struct smb2_hdr *smb = (struct smb2_hdr *)buf;
+	struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 
 	cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
-		 smb->Command, smb->Status, smb->Flags, smb->MessageId,
-		 smb->ProcessId);
-	cifs_dbg(VFS, "smb buf %p len %u\n", smb, smb2_calc_size(smb));
+		 shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
+		 shdr->ProcessId);
+	cifs_dbg(VFS, "smb buf %p len %u\n", buf, smb2_calc_size(buf));
 #endif
 }
 
@@ -282,7 +295,7 @@
 		cifs_dbg(FYI, "Link Speed %lld\n",
 			le64_to_cpu(out_buf->LinkSpeed));
 	}
-
+	kfree(out_buf);
 	return rc;
 }
 #endif /* STATS2 */
@@ -536,6 +549,7 @@
 	server->ops->set_oplock_level(cinode, oplock, fid->epoch,
 				      &fid->purge_cache);
 	cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
+	memcpy(cfile->fid.create_guid, fid->create_guid, 16);
 }
 
 static void
@@ -694,6 +708,7 @@
 
 cchunk_out:
 	kfree(pcchunk);
+	kfree(retbuf);
 	return rc;
 }
 
@@ -818,7 +833,6 @@
 {
 	int rc;
 	unsigned int ret_data_len;
-	char *retbuf = NULL;
 	struct duplicate_extents_to_file dup_ext_buf;
 	struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink);
 
@@ -844,7 +858,7 @@
 			FSCTL_DUPLICATE_EXTENTS_TO_FILE,
 			true /* is_fsctl */, (char *)&dup_ext_buf,
 			sizeof(struct duplicate_extents_to_file),
-			(char **)&retbuf,
+			NULL,
 			&ret_data_len);
 
 	if (ret_data_len > 0)
@@ -867,7 +881,6 @@
 		   struct cifsFileInfo *cfile)
 {
 	struct fsctl_set_integrity_information_req integr_info;
-	char *retbuf = NULL;
 	unsigned int ret_data_len;
 
 	integr_info.ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED);
@@ -879,7 +892,7 @@
 			FSCTL_SET_INTEGRITY_INFORMATION,
 			true /* is_fsctl */, (char *)&integr_info,
 			sizeof(struct fsctl_set_integrity_information_req),
-			(char **)&retbuf,
+			NULL,
 			&ret_data_len);
 
 }
@@ -909,17 +922,17 @@
 	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
 	kfree(utf16_path);
 	if (rc) {
-		cifs_dbg(VFS, "open dir failed\n");
+		cifs_dbg(FYI, "open dir failed rc=%d\n", rc);
 		return rc;
 	}
 
 	srch_inf->entries_in_buffer = 0;
-	srch_inf->index_of_last_entry = 0;
+	srch_inf->index_of_last_entry = 2;
 
 	rc = SMB2_query_directory(xid, tcon, fid->persistent_fid,
 				  fid->volatile_fid, 0, srch_inf);
 	if (rc) {
-		cifs_dbg(VFS, "query directory failed\n");
+		cifs_dbg(FYI, "query directory failed rc=%d\n", rc);
 		SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
 	}
 	return rc;
@@ -948,14 +961,14 @@
 static bool
 smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
 {
-	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+	struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 
-	if (hdr->Status != STATUS_PENDING)
+	if (shdr->Status != STATUS_PENDING)
 		return false;
 
 	if (!length) {
 		spin_lock(&server->req_lock);
-		server->credits += le16_to_cpu(hdr->CreditRequest);
+		server->credits += le16_to_cpu(shdr->CreditRequest);
 		spin_unlock(&server->req_lock);
 		wake_up(&server->request_q);
 	}
@@ -963,6 +976,18 @@
 	return true;
 }
 
+static bool
+smb2_is_session_expired(char *buf)
+{
+	struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
+
+	if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED)
+		return false;
+
+	cifs_dbg(FYI, "Session expired\n");
+	return true;
+}
+
 static int
 smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
 		     struct cifsInodeInfo *cinode)
@@ -1036,9 +1061,12 @@
 static void
 smb2_new_lease_key(struct cifs_fid *fid)
 {
-	get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
+	generate_random_uuid(fid->lease_key);
 }
 
+#define SMB2_SYMLINK_STRUCT_SIZE \
+	(sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
+
 static int
 smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
 		   const char *full_path, char **target_path,
@@ -1051,7 +1079,10 @@
 	struct cifs_fid fid;
 	struct smb2_err_rsp *err_buf = NULL;
 	struct smb2_symlink_err_rsp *symlink;
-	unsigned int sub_len, sub_offset;
+	unsigned int sub_len;
+	unsigned int sub_offset;
+	unsigned int print_len;
+	unsigned int print_offset;
 
 	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
 
@@ -1072,11 +1103,33 @@
 		kfree(utf16_path);
 		return -ENOENT;
 	}
+
+	if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
+	    get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) {
+		kfree(utf16_path);
+		return -ENOENT;
+	}
+
 	/* open must fail on symlink - reset rc */
 	rc = 0;
 	symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
 	sub_len = le16_to_cpu(symlink->SubstituteNameLength);
 	sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
+	print_len = le16_to_cpu(symlink->PrintNameLength);
+	print_offset = le16_to_cpu(symlink->PrintNameOffset);
+
+	if (get_rfc1002_length(err_buf) + 4 <
+			SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
+		kfree(utf16_path);
+		return -ENOENT;
+	}
+
+	if (get_rfc1002_length(err_buf) + 4 <
+			SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
+		kfree(utf16_path);
+		return -ENOENT;
+	}
+
 	*target_path = cifs_strndup_from_utf16(
 				(char *)symlink->PathBuffer + sub_offset,
 				sub_len, true, cifs_sb->local_nls);
@@ -1105,6 +1158,12 @@
 	inode = d_inode(cfile->dentry);
 	cifsi = CIFS_I(inode);
 
+	/*
+	 * We zero the range through ioctl, so we need remove the page caches
+	 * first, otherwise the data may be inconsistent with the server.
+	 */
+	truncate_pagecache_range(inode, offset, offset + len - 1);
+
 	/* if file not oplocked can't be sure whether asking to extend size */
 	if (!CIFS_CACHE_READ(cifsi))
 		if (keep_size == false)
@@ -1161,6 +1220,12 @@
 	if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse))
 		return -EOPNOTSUPP;
 
+	/*
+	 * We implement the punch hole through ioctl, so we need remove the page
+	 * caches first, otherwise the data may be inconsistent with the server.
+	 */
+	truncate_pagecache_range(inode, offset, offset + len - 1);
+
 	cifs_dbg(FYI, "offset %lld len %lld", offset, len);
 
 	fsctl_buf.FileOffset = cpu_to_le64(offset);
@@ -1289,26 +1354,33 @@
 		       unsigned int epoch, bool *purge_cache)
 {
 	char message[5] = {0};
+	unsigned int new_oplock = 0;
 
 	oplock &= 0xFF;
 	if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
 		return;
 
-	cinode->oplock = 0;
+	/* Check if the server granted an oplock rather than a lease */
+	if (oplock & SMB2_OPLOCK_LEVEL_EXCLUSIVE)
+		return smb2_set_oplock_level(cinode, oplock, epoch,
+					     purge_cache);
+
 	if (oplock & SMB2_LEASE_READ_CACHING_HE) {
-		cinode->oplock |= CIFS_CACHE_READ_FLG;
+		new_oplock |= CIFS_CACHE_READ_FLG;
 		strcat(message, "R");
 	}
 	if (oplock & SMB2_LEASE_HANDLE_CACHING_HE) {
-		cinode->oplock |= CIFS_CACHE_HANDLE_FLG;
+		new_oplock |= CIFS_CACHE_HANDLE_FLG;
 		strcat(message, "H");
 	}
 	if (oplock & SMB2_LEASE_WRITE_CACHING_HE) {
-		cinode->oplock |= CIFS_CACHE_WRITE_FLG;
+		new_oplock |= CIFS_CACHE_WRITE_FLG;
 		strcat(message, "W");
 	}
-	if (!cinode->oplock)
-		strcat(message, "None");
+	if (!new_oplock)
+		strncpy(message, "None", sizeof(message));
+
+	cinode->oplock = new_oplock;
 	cifs_dbg(FYI, "%s Lease granted on inode %p\n", message,
 		 &cinode->vfs_inode);
 }
@@ -1463,6 +1535,655 @@
 	return !cfile->invalidHandle;
 }
 
+static void
+fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
+{
+	struct smb2_sync_hdr *shdr =
+			(struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base;
+	unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
+
+	memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
+	tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
+	tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
+	tr_hdr->Flags = cpu_to_le16(0x01);
+	get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
+	memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
+	inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4);
+	inc_rfc1001_len(tr_hdr, orig_len);
+}
+
+static struct scatterlist *
+init_sg(struct smb_rqst *rqst, u8 *sign)
+{
+	unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
+	unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
+	struct scatterlist *sg;
+	unsigned int i;
+	unsigned int j;
+
+	sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL);
+	if (!sg)
+		return NULL;
+
+	sg_init_table(sg, sg_len);
+	sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
+	for (i = 1; i < rqst->rq_nvec; i++)
+		sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
+						rqst->rq_iov[i].iov_len);
+	for (j = 0; i < sg_len - 1; i++, j++) {
+		unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz
+							: rqst->rq_tailsz;
+		sg_set_page(&sg[i], rqst->rq_pages[j], len, 0);
+	}
+	sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE);
+	return sg;
+}
+
+struct cifs_crypt_result {
+	int err;
+	struct completion completion;
+};
+
+static void cifs_crypt_complete(struct crypto_async_request *req, int err)
+{
+	struct cifs_crypt_result *res = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	res->err = err;
+	complete(&res->completion);
+}
+
+static int
+smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
+{
+	struct cifs_ses *ses;
+	u8 *ses_enc_key;
+
+	spin_lock(&cifs_tcp_ses_lock);
+	list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+		if (ses->Suid != ses_id)
+			continue;
+		ses_enc_key = enc ? ses->smb3encryptionkey :
+							ses->smb3decryptionkey;
+		memcpy(key, ses_enc_key, SMB3_SIGN_KEY_SIZE);
+		spin_unlock(&cifs_tcp_ses_lock);
+		return 0;
+	}
+	spin_unlock(&cifs_tcp_ses_lock);
+
+	return -EAGAIN;
+}
+/*
+ * Encrypt or decrypt @rqst message. @rqst has the following format:
+ * iov[0] - transform header (associate data),
+ * iov[1-N] and pages - data to encrypt.
+ * On success return encrypted data in iov[1-N] and pages, leave iov[0]
+ * untouched.
+ */
+static int
+crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
+{
+	struct smb2_transform_hdr *tr_hdr =
+			(struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
+	unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
+	int rc = 0;
+	struct scatterlist *sg;
+	u8 sign[SMB2_SIGNATURE_SIZE] = {};
+	u8 key[SMB3_SIGN_KEY_SIZE];
+	struct aead_request *req;
+	char *iv;
+	unsigned int iv_len;
+	struct cifs_crypt_result result = {0, };
+	struct crypto_aead *tfm;
+	unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
+
+	init_completion(&result.completion);
+
+	rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key);
+	if (rc) {
+		cifs_dbg(VFS, "%s: Could not get %scryption key\n", __func__,
+			 enc ? "en" : "de");
+		return 0;
+	}
+
+	rc = smb3_crypto_aead_allocate(server);
+	if (rc) {
+		cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
+		return rc;
+	}
+
+	tfm = enc ? server->secmech.ccmaesencrypt :
+						server->secmech.ccmaesdecrypt;
+	rc = crypto_aead_setkey(tfm, key, SMB3_SIGN_KEY_SIZE);
+	if (rc) {
+		cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
+		return rc;
+	}
+
+	rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
+	if (rc) {
+		cifs_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc);
+		return rc;
+	}
+
+	req = aead_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		cifs_dbg(VFS, "%s: Failed to alloc aead request", __func__);
+		return -ENOMEM;
+	}
+
+	if (!enc) {
+		memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
+		crypt_len += SMB2_SIGNATURE_SIZE;
+	}
+
+	sg = init_sg(rqst, sign);
+	if (!sg) {
+		cifs_dbg(VFS, "%s: Failed to init sg", __func__);
+		rc = -ENOMEM;
+		goto free_req;
+	}
+
+	iv_len = crypto_aead_ivsize(tfm);
+	iv = kzalloc(iv_len, GFP_KERNEL);
+	if (!iv) {
+		cifs_dbg(VFS, "%s: Failed to alloc IV", __func__);
+		rc = -ENOMEM;
+		goto free_sg;
+	}
+	iv[0] = 3;
+	memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
+
+	aead_request_set_crypt(req, sg, sg, crypt_len, iv);
+	aead_request_set_ad(req, assoc_data_len);
+
+	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				  cifs_crypt_complete, &result);
+
+	rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
+
+	if (rc == -EINPROGRESS || rc == -EBUSY) {
+		wait_for_completion(&result.completion);
+		rc = result.err;
+	}
+
+	if (!rc && enc)
+		memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
+
+	kfree(iv);
+free_sg:
+	kfree(sg);
+free_req:
+	kfree(req);
+	return rc;
+}
+
+static int
+smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
+		       struct smb_rqst *old_rq)
+{
+	struct kvec *iov;
+	struct page **pages;
+	struct smb2_transform_hdr *tr_hdr;
+	unsigned int npages = old_rq->rq_npages;
+	int i;
+	int rc = -ENOMEM;
+
+	pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
+	if (!pages)
+		return rc;
+
+	new_rq->rq_pages = pages;
+	new_rq->rq_npages = old_rq->rq_npages;
+	new_rq->rq_pagesz = old_rq->rq_pagesz;
+	new_rq->rq_tailsz = old_rq->rq_tailsz;
+
+	for (i = 0; i < npages; i++) {
+		pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
+		if (!pages[i])
+			goto err_free_pages;
+	}
+
+	iov = kmalloc_array(old_rq->rq_nvec, sizeof(struct kvec), GFP_KERNEL);
+	if (!iov)
+		goto err_free_pages;
+
+	/* copy all iovs from the old except the 1st one (rfc1002 length) */
+	memcpy(&iov[1], &old_rq->rq_iov[1],
+				sizeof(struct kvec) * (old_rq->rq_nvec - 1));
+	new_rq->rq_iov = iov;
+	new_rq->rq_nvec = old_rq->rq_nvec;
+
+	tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL);
+	if (!tr_hdr)
+		goto err_free_iov;
+
+	/* fill the 1st iov with a transform header */
+	fill_transform_hdr(tr_hdr, old_rq);
+	new_rq->rq_iov[0].iov_base = tr_hdr;
+	new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
+
+	/* copy pages form the old */
+	for (i = 0; i < npages; i++) {
+		char *dst = kmap(new_rq->rq_pages[i]);
+		char *src = kmap(old_rq->rq_pages[i]);
+		unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz :
+							new_rq->rq_tailsz;
+		memcpy(dst, src, len);
+		kunmap(new_rq->rq_pages[i]);
+		kunmap(old_rq->rq_pages[i]);
+	}
+
+	rc = crypt_message(server, new_rq, 1);
+	cifs_dbg(FYI, "encrypt message returned %d", rc);
+	if (rc)
+		goto err_free_tr_hdr;
+
+	return rc;
+
+err_free_tr_hdr:
+	kfree(tr_hdr);
+err_free_iov:
+	kfree(iov);
+err_free_pages:
+	for (i = i - 1; i >= 0; i--)
+		put_page(pages[i]);
+	kfree(pages);
+	return rc;
+}
+
+static void
+smb3_free_transform_rq(struct smb_rqst *rqst)
+{
+	int i = rqst->rq_npages - 1;
+
+	for (; i >= 0; i--)
+		put_page(rqst->rq_pages[i]);
+	kfree(rqst->rq_pages);
+	/* free transform header */
+	kfree(rqst->rq_iov[0].iov_base);
+	kfree(rqst->rq_iov);
+}
+
+static int
+smb3_is_transform_hdr(void *buf)
+{
+	struct smb2_transform_hdr *trhdr = buf;
+
+	return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;
+}
+
+static int
+decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
+		 unsigned int buf_data_size, struct page **pages,
+		 unsigned int npages, unsigned int page_data_size)
+{
+	struct kvec iov[2];
+	struct smb_rqst rqst = {NULL};
+	struct smb2_hdr *hdr;
+	int rc;
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = sizeof(struct smb2_transform_hdr);
+	iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
+	iov[1].iov_len = buf_data_size;
+
+	rqst.rq_iov = iov;
+	rqst.rq_nvec = 2;
+	rqst.rq_pages = pages;
+	rqst.rq_npages = npages;
+	rqst.rq_pagesz = PAGE_SIZE;
+	rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE;
+
+	rc = crypt_message(server, &rqst, 0);
+	cifs_dbg(FYI, "decrypt message returned %d\n", rc);
+
+	if (rc)
+		return rc;
+
+	memmove(buf + 4, iov[1].iov_base, buf_data_size);
+	hdr = (struct smb2_hdr *)buf;
+	hdr->smb2_buf_length = cpu_to_be32(buf_data_size + page_data_size);
+	server->total_read = buf_data_size + page_data_size + 4;
+
+	return rc;
+}
+
+static int
+read_data_into_pages(struct TCP_Server_Info *server, struct page **pages,
+		     unsigned int npages, unsigned int len)
+{
+	int i;
+	int length;
+
+	for (i = 0; i < npages; i++) {
+		struct page *page = pages[i];
+		size_t n;
+
+		n = len;
+		if (len >= PAGE_SIZE) {
+			/* enough data to fill the page */
+			n = PAGE_SIZE;
+			len -= n;
+		} else {
+			zero_user(page, len, PAGE_SIZE - len);
+			len = 0;
+		}
+		length = cifs_read_page_from_socket(server, page, n);
+		if (length < 0)
+			return length;
+		server->total_read += length;
+	}
+
+	return 0;
+}
+
+static int
+init_read_bvec(struct page **pages, unsigned int npages, unsigned int data_size,
+	       unsigned int cur_off, struct bio_vec **page_vec)
+{
+	struct bio_vec *bvec;
+	int i;
+
+	bvec = kcalloc(npages, sizeof(struct bio_vec), GFP_KERNEL);
+	if (!bvec)
+		return -ENOMEM;
+
+	for (i = 0; i < npages; i++) {
+		bvec[i].bv_page = pages[i];
+		bvec[i].bv_offset = (i == 0) ? cur_off : 0;
+		bvec[i].bv_len = min_t(unsigned int, PAGE_SIZE, data_size);
+		data_size -= bvec[i].bv_len;
+	}
+
+	if (data_size != 0) {
+		cifs_dbg(VFS, "%s: something went wrong\n", __func__);
+		kfree(bvec);
+		return -EIO;
+	}
+
+	*page_vec = bvec;
+	return 0;
+}
+
+static int
+handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
+		 char *buf, unsigned int buf_len, struct page **pages,
+		 unsigned int npages, unsigned int page_data_size)
+{
+	unsigned int data_offset;
+	unsigned int data_len;
+	unsigned int cur_off;
+	unsigned int cur_page_idx;
+	unsigned int pad_len;
+	struct cifs_readdata *rdata = mid->callback_data;
+	struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
+	struct bio_vec *bvec = NULL;
+	struct iov_iter iter;
+	struct kvec iov;
+	int length;
+
+	if (shdr->Command != SMB2_READ) {
+		cifs_dbg(VFS, "only big read responses are supported\n");
+		return -ENOTSUPP;
+	}
+
+	if (server->ops->is_status_pending &&
+			server->ops->is_status_pending(buf, server, 0))
+		return -1;
+
+	rdata->result = server->ops->map_error(buf, false);
+	if (rdata->result != 0) {
+		cifs_dbg(FYI, "%s: server returned error %d\n",
+			 __func__, rdata->result);
+		dequeue_mid(mid, rdata->result);
+		return 0;
+	}
+
+	data_offset = server->ops->read_data_offset(buf) + 4;
+	data_len = server->ops->read_data_length(buf);
+
+	if (data_offset < server->vals->read_rsp_size) {
+		/*
+		 * win2k8 sometimes sends an offset of 0 when the read
+		 * is beyond the EOF. Treat it as if the data starts just after
+		 * the header.
+		 */
+		cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
+			 __func__, data_offset);
+		data_offset = server->vals->read_rsp_size;
+	} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
+		/* data_offset is beyond the end of smallbuf */
+		cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
+			 __func__, data_offset);
+		rdata->result = -EIO;
+		dequeue_mid(mid, rdata->result);
+		return 0;
+	}
+
+	pad_len = data_offset - server->vals->read_rsp_size;
+
+	if (buf_len <= data_offset) {
+		/* read response payload is in pages */
+		cur_page_idx = pad_len / PAGE_SIZE;
+		cur_off = pad_len % PAGE_SIZE;
+
+		if (cur_page_idx != 0) {
+			/* data offset is beyond the 1st page of response */
+			cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
+				 __func__, data_offset);
+			rdata->result = -EIO;
+			dequeue_mid(mid, rdata->result);
+			return 0;
+		}
+
+		if (data_len > page_data_size - pad_len) {
+			/* data_len is corrupt -- discard frame */
+			rdata->result = -EIO;
+			dequeue_mid(mid, rdata->result);
+			return 0;
+		}
+
+		rdata->result = init_read_bvec(pages, npages, page_data_size,
+					       cur_off, &bvec);
+		if (rdata->result != 0) {
+			dequeue_mid(mid, rdata->result);
+			return 0;
+		}
+
+		iov_iter_bvec(&iter, WRITE | ITER_BVEC, bvec, npages, data_len);
+	} else if (buf_len >= data_offset + data_len) {
+		/* read response payload is in buf */
+		WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
+		iov.iov_base = buf + data_offset;
+		iov.iov_len = data_len;
+		iov_iter_kvec(&iter, WRITE | ITER_KVEC, &iov, 1, data_len);
+	} else {
+		/* read response payload cannot be in both buf and pages */
+		WARN_ONCE(1, "buf can not contain only a part of read data");
+		rdata->result = -EIO;
+		dequeue_mid(mid, rdata->result);
+		return 0;
+	}
+
+	/* set up first iov for signature check */
+	rdata->iov[0].iov_base = buf;
+	rdata->iov[0].iov_len = 4;
+	rdata->iov[1].iov_base = buf + 4;
+	rdata->iov[1].iov_len = server->vals->read_rsp_size - 4;
+	cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
+		 rdata->iov[0].iov_base, server->vals->read_rsp_size);
+
+	length = rdata->copy_into_pages(server, rdata, &iter);
+
+	kfree(bvec);
+
+	if (length < 0)
+		return length;
+
+	dequeue_mid(mid, false);
+	return length;
+}
+
+static int
+receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
+{
+	char *buf = server->smallbuf;
+	struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
+	unsigned int npages;
+	struct page **pages;
+	unsigned int len;
+	unsigned int buflen = get_rfc1002_length(buf) + 4;
+	int rc;
+	int i = 0;
+
+	len = min_t(unsigned int, buflen, server->vals->read_rsp_size - 4 +
+		sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
+
+	rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
+	if (rc < 0)
+		return rc;
+	server->total_read += rc;
+
+	len = le32_to_cpu(tr_hdr->OriginalMessageSize) + 4 -
+						server->vals->read_rsp_size;
+	npages = DIV_ROUND_UP(len, PAGE_SIZE);
+
+	pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
+	if (!pages) {
+		rc = -ENOMEM;
+		goto discard_data;
+	}
+
+	for (; i < npages; i++) {
+		pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
+		if (!pages[i]) {
+			rc = -ENOMEM;
+			goto discard_data;
+		}
+	}
+
+	/* read read data into pages */
+	rc = read_data_into_pages(server, pages, npages, len);
+	if (rc)
+		goto free_pages;
+
+	rc = cifs_discard_remaining_data(server);
+	if (rc)
+		goto free_pages;
+
+	rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size - 4,
+			      pages, npages, len);
+	if (rc)
+		goto free_pages;
+
+	*mid = smb2_find_mid(server, buf);
+	if (*mid == NULL)
+		cifs_dbg(FYI, "mid not found\n");
+	else {
+		cifs_dbg(FYI, "mid found\n");
+		(*mid)->decrypted = true;
+		rc = handle_read_data(server, *mid, buf,
+				      server->vals->read_rsp_size,
+				      pages, npages, len);
+	}
+
+free_pages:
+	for (i = i - 1; i >= 0; i--)
+		put_page(pages[i]);
+	kfree(pages);
+	return rc;
+discard_data:
+	cifs_discard_remaining_data(server);
+	goto free_pages;
+}
+
+static int
+receive_encrypted_standard(struct TCP_Server_Info *server,
+			   struct mid_q_entry **mid)
+{
+	int length;
+	char *buf = server->smallbuf;
+	unsigned int pdu_length = get_rfc1002_length(buf);
+	unsigned int buf_size;
+	struct mid_q_entry *mid_entry;
+
+	/* switch to large buffer if too big for a small one */
+	if (pdu_length + 4 > MAX_CIFS_SMALL_BUFFER_SIZE) {
+		server->large_buf = true;
+		memcpy(server->bigbuf, buf, server->total_read);
+		buf = server->bigbuf;
+	}
+
+	/* now read the rest */
+	length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
+				pdu_length - HEADER_SIZE(server) + 1 + 4);
+	if (length < 0)
+		return length;
+	server->total_read += length;
+
+	buf_size = pdu_length + 4 - sizeof(struct smb2_transform_hdr);
+	length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0);
+	if (length)
+		return length;
+
+	mid_entry = smb2_find_mid(server, buf);
+	if (mid_entry == NULL)
+		cifs_dbg(FYI, "mid not found\n");
+	else {
+		cifs_dbg(FYI, "mid found\n");
+		mid_entry->decrypted = true;
+	}
+
+	*mid = mid_entry;
+
+	if (mid_entry && mid_entry->handle)
+		return mid_entry->handle(server, mid_entry);
+
+	return cifs_handle_standard(server, mid_entry);
+}
+
+static int
+smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
+{
+	char *buf = server->smallbuf;
+	unsigned int pdu_length = get_rfc1002_length(buf);
+	struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
+	unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
+
+	if (pdu_length + 4 < sizeof(struct smb2_transform_hdr) +
+						sizeof(struct smb2_sync_hdr)) {
+		cifs_dbg(VFS, "Transform message is too small (%u)\n",
+			 pdu_length);
+		cifs_reconnect(server);
+		wake_up(&server->response_q);
+		return -ECONNABORTED;
+	}
+
+	if (pdu_length + 4 < orig_len + sizeof(struct smb2_transform_hdr)) {
+		cifs_dbg(VFS, "Transform message is broken\n");
+		cifs_reconnect(server);
+		wake_up(&server->response_q);
+		return -ECONNABORTED;
+	}
+
+	if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
+		return receive_encrypted_read(server, mid);
+
+	return receive_encrypted_standard(server, mid);
+}
+
+int
+smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+{
+	char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
+
+	return handle_read_data(server, mid, buf, get_rfc1002_length(buf) + 4,
+				NULL, 0, 0);
+}
+
 struct smb_version_operations smb20_operations = {
 	.compare_fids = smb2_compare_fids,
 	.setup_request = smb2_setup_request,
@@ -1483,6 +2204,7 @@
 	.clear_stats = smb2_clear_stats,
 	.print_stats = smb2_print_stats,
 	.is_oplock_break = smb2_is_valid_oplock_break,
+	.handle_cancelled_mid = smb2_handle_cancelled_mid,
 	.downgrade_oplock = smb2_downgrade_oplock,
 	.need_neg = smb2_need_neg,
 	.negotiate = smb2_negotiate,
@@ -1523,6 +2245,7 @@
 	.close_dir = smb2_close_dir,
 	.calc_smb_size = smb2_calc_size,
 	.is_status_pending = smb2_is_status_pending,
+	.is_session_expired = smb2_is_session_expired,
 	.oplock_response = smb2_oplock_response,
 	.queryfs = smb2_queryfs,
 	.mand_lock = smb2_mand_lock,
@@ -1561,6 +2284,7 @@
 	.clear_stats = smb2_clear_stats,
 	.print_stats = smb2_print_stats,
 	.is_oplock_break = smb2_is_valid_oplock_break,
+	.handle_cancelled_mid = smb2_handle_cancelled_mid,
 	.downgrade_oplock = smb2_downgrade_oplock,
 	.need_neg = smb2_need_neg,
 	.negotiate = smb2_negotiate,
@@ -1603,6 +2327,7 @@
 	.close_dir = smb2_close_dir,
 	.calc_smb_size = smb2_calc_size,
 	.is_status_pending = smb2_is_status_pending,
+	.is_session_expired = smb2_is_session_expired,
 	.oplock_response = smb2_oplock_response,
 	.queryfs = smb2_queryfs,
 	.mand_lock = smb2_mand_lock,
@@ -1642,6 +2367,7 @@
 	.print_stats = smb2_print_stats,
 	.dump_share_caps = smb2_dump_share_caps,
 	.is_oplock_break = smb2_is_valid_oplock_break,
+	.handle_cancelled_mid = smb2_handle_cancelled_mid,
 	.downgrade_oplock = smb2_downgrade_oplock,
 	.need_neg = smb2_need_neg,
 	.negotiate = smb2_negotiate,
@@ -1684,6 +2410,7 @@
 	.close_dir = smb2_close_dir,
 	.calc_smb_size = smb2_calc_size,
 	.is_status_pending = smb2_is_status_pending,
+	.is_session_expired = smb2_is_session_expired,
 	.oplock_response = smb2_oplock_response,
 	.queryfs = smb2_queryfs,
 	.mand_lock = smb2_mand_lock,
@@ -1692,7 +2419,7 @@
 	.get_lease_key = smb2_get_lease_key,
 	.set_lease_key = smb2_set_lease_key,
 	.new_lease_key = smb2_new_lease_key,
-	.generate_signingkey = generate_smb3signingkey,
+	.generate_signingkey = generate_smb30signingkey,
 	.calc_signature = smb3_calc_signature,
 	.set_integrity  = smb3_set_integrity,
 	.is_read_op = smb21_is_read_op,
@@ -1705,6 +2432,10 @@
 	.wp_retry_size = smb2_wp_retry_size,
 	.dir_needs_close = smb2_dir_needs_close,
 	.fallocate = smb3_fallocate,
+	.init_transform_rq = smb3_init_transform_rq,
+	.free_transform_rq = smb3_free_transform_rq,
+	.is_transform_hdr = smb3_is_transform_hdr,
+	.receive_transform = smb3_receive_transform,
 };
 
 #ifdef CONFIG_CIFS_SMB311
@@ -1729,6 +2460,7 @@
 	.print_stats = smb2_print_stats,
 	.dump_share_caps = smb2_dump_share_caps,
 	.is_oplock_break = smb2_is_valid_oplock_break,
+	.handle_cancelled_mid = smb2_handle_cancelled_mid,
 	.downgrade_oplock = smb2_downgrade_oplock,
 	.need_neg = smb2_need_neg,
 	.negotiate = smb2_negotiate,
@@ -1771,6 +2503,7 @@
 	.close_dir = smb2_close_dir,
 	.calc_smb_size = smb2_calc_size,
 	.is_status_pending = smb2_is_status_pending,
+	.is_session_expired = smb2_is_session_expired,
 	.oplock_response = smb2_oplock_response,
 	.queryfs = smb2_queryfs,
 	.mand_lock = smb2_mand_lock,
@@ -1779,7 +2512,7 @@
 	.get_lease_key = smb2_get_lease_key,
 	.set_lease_key = smb2_set_lease_key,
 	.new_lease_key = smb2_new_lease_key,
-	.generate_signingkey = generate_smb3signingkey,
+	.generate_signingkey = generate_smb311signingkey,
 	.calc_signature = smb3_calc_signature,
 	.set_integrity  = smb3_set_integrity,
 	.is_read_op = smb21_is_read_op,
@@ -1792,6 +2525,10 @@
 	.wp_retry_size = smb2_wp_retry_size,
 	.dir_needs_close = smb2_dir_needs_close,
 	.fallocate = smb3_fallocate,
+	.init_transform_rq = smb3_init_transform_rq,
+	.free_transform_rq = smb3_free_transform_rq,
+	.is_transform_hdr = smb3_is_transform_hdr,
+	.receive_transform = smb3_receive_transform,
 };
 #endif /* CIFS_SMB311 */
 
@@ -1838,7 +2575,7 @@
 struct smb_version_values smb30_values = {
 	.version_string = SMB30_VERSION_STRING,
 	.protocol_id = SMB30_PROT_ID,
-	.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
+	.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION,
 	.large_lock_type = 0,
 	.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
 	.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
@@ -1858,7 +2595,7 @@
 struct smb_version_values smb302_values = {
 	.version_string = SMB302_VERSION_STRING,
 	.protocol_id = SMB302_PROT_ID,
-	.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
+	.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION,
 	.large_lock_type = 0,
 	.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
 	.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
--- linux-4.4.0.orig/fs/cifs/smb2pdu.c
+++ linux-4.4.0/fs/cifs/smb2pdu.c
@@ -77,34 +77,42 @@
 	/* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */
 };
 
+static int encryption_required(const struct cifs_tcon *tcon)
+{
+	if (!tcon)
+		return 0;
+	if ((tcon->ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) ||
+	    (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA))
+		return 1;
+	if (tcon->seal &&
+	    (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
+		return 1;
+	return 0;
+}
 
 static void
-smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
+smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
 		  const struct cifs_tcon *tcon)
 {
-	struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
-	char *temp = (char *)hdr;
-	/* lookup word count ie StructureSize from table */
-	__u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_cmd)];
-
-	/*
-	 * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of
-	 * largest operations (Create)
-	 */
-	memset(temp, 0, 256);
+	shdr->ProtocolId = SMB2_PROTO_NUMBER;
+	shdr->StructureSize = cpu_to_le16(64);
+	shdr->Command = smb2_cmd;
+	if (tcon && tcon->ses && tcon->ses->server) {
+		struct TCP_Server_Info *server = tcon->ses->server;
 
-	/* Note this is only network field converted to big endian */
-	hdr->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr)
-			- 4 /*  RFC 1001 length field itself not counted */);
-
-	hdr->ProtocolId[0] = 0xFE;
-	hdr->ProtocolId[1] = 'S';
-	hdr->ProtocolId[2] = 'M';
-	hdr->ProtocolId[3] = 'B';
-	hdr->StructureSize = cpu_to_le16(64);
-	hdr->Command = smb2_cmd;
-	hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */
-	hdr->ProcessId = cpu_to_le32((__u16)current->tgid);
+		spin_lock(&server->req_lock);
+		/* Request up to 2 credits but don't go over the limit. */
+		if (server->credits >= server->max_credits)
+			shdr->CreditRequest = cpu_to_le16(0);
+		else
+			shdr->CreditRequest = cpu_to_le16(
+				min_t(int, server->max_credits -
+						server->credits, 2));
+		spin_unlock(&server->req_lock);
+	} else {
+		shdr->CreditRequest = cpu_to_le16(2);
+	}
+	shdr->ProcessId = cpu_to_le32((__u16)current->tgid);
 
 	if (!tcon)
 		goto out;
@@ -113,13 +121,13 @@
 	/* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
 	if ((tcon->ses) && (tcon->ses->server) &&
 	    (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
-		hdr->CreditCharge = cpu_to_le16(1);
+		shdr->CreditCharge = cpu_to_le16(1);
 	/* else CreditCharge MBZ */
 
-	hdr->TreeId = tcon->tid;
+	shdr->TreeId = tcon->tid;
 	/* Uid is not converted */
 	if (tcon->ses)
-		hdr->SessionId = tcon->ses->Suid;
+		shdr->SessionId = tcon->ses->Suid;
 
 	/*
 	 * If we would set SMB2_FLAGS_DFS_OPERATIONS on open we also would have
@@ -132,19 +140,19 @@
 	 * but it is safer to net set it for now.
 	 */
 /*	if (tcon->share_flags & SHI1005_FLAGS_DFS)
-		hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
+		shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
 
-	if (tcon->ses && tcon->ses->server && tcon->ses->server->sign)
-		hdr->Flags |= SMB2_FLAGS_SIGNED;
+	if (tcon->ses && tcon->ses->server && tcon->ses->server->sign &&
+	    !encryption_required(tcon))
+		shdr->Flags |= SMB2_FLAGS_SIGNED;
 out:
-	pdu->StructureSize2 = cpu_to_le16(parmsize);
 	return;
 }
 
 static int
 smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
 {
-	int rc = 0;
+	int rc;
 	struct nls_table *nls_codepage;
 	struct cifs_ses *ses;
 	struct TCP_Server_Info *server;
@@ -155,10 +163,10 @@
 	 * for those three - in the calling routine.
 	 */
 	if (tcon == NULL)
-		return rc;
+		return 0;
 
-	if (smb2_command == SMB2_TREE_CONNECT)
-		return rc;
+	if (smb2_command == SMB2_TREE_CONNECT || smb2_command == SMB2_IOCTL)
+		return 0;
 
 	if (tcon->tidStatus == CifsExiting) {
 		/*
@@ -201,8 +209,14 @@
 			return -EAGAIN;
 		}
 
-		wait_event_interruptible_timeout(server->response_q,
-			(server->tcpStatus != CifsNeedReconnect), 10 * HZ);
+		rc = wait_event_interruptible_timeout(server->response_q,
+						      (server->tcpStatus != CifsNeedReconnect),
+						      10 * HZ);
+		if (rc < 0) {
+			cifs_dbg(FYI, "%s: aborting reconnect due to a received"
+				 " signal by the process\n", __func__);
+			return -ERESTARTSYS;
+		}
 
 		/* are we still trying to reconnect? */
 		if (server->tcpStatus != CifsNeedReconnect)
@@ -220,7 +234,7 @@
 	}
 
 	if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
-		return rc;
+		return 0;
 
 	nls_codepage = load_nls_default();
 
@@ -229,10 +243,27 @@
 	 * the same SMB session
 	 */
 	mutex_lock(&tcon->ses->session_mutex);
+
+	/*
+	 * Recheck after acquire mutex. If another thread is negotiating
+	 * and the server never sends an answer the socket will be closed
+	 * and tcpStatus set to reconnect.
+	 */
+	if (server->tcpStatus == CifsNeedReconnect) {
+		rc = -EHOSTDOWN;
+		mutex_unlock(&tcon->ses->session_mutex);
+		goto out;
+	}
+
 	rc = cifs_negotiate_protocol(0, tcon->ses);
-	if (!rc && tcon->ses->need_reconnect)
+	if (!rc && tcon->ses->need_reconnect) {
 		rc = cifs_setup_session(0, tcon->ses, nls_codepage);
-
+		if ((rc == -EACCES) && !tcon->retry) {
+			rc = -EHOSTDOWN;
+			mutex_unlock(&tcon->ses->session_mutex);
+			goto failed;
+		}
+	}
 	if (rc || !tcon->need_reconnect) {
 		mutex_unlock(&tcon->ses->session_mutex);
 		goto out;
@@ -264,22 +295,81 @@
 	case SMB2_CHANGE_NOTIFY:
 	case SMB2_QUERY_INFO:
 	case SMB2_SET_INFO:
-		return -EAGAIN;
+		rc = -EAGAIN;
 	}
+failed:
 	unload_nls(nls_codepage);
 	return rc;
 }
 
+static void
+fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf,
+	       unsigned int *total_len)
+{
+	struct smb2_sync_pdu *spdu = (struct smb2_sync_pdu *)buf;
+	/* lookup word count ie StructureSize from table */
+	__u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_command)];
+
+	/*
+	 * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of
+	 * largest operations (Create)
+	 */
+	memset(buf, 0, 256);
+
+	smb2_hdr_assemble(&spdu->sync_hdr, smb2_command, tcon);
+	spdu->StructureSize2 = cpu_to_le16(parmsize);
+
+	*total_len = parmsize + sizeof(struct smb2_sync_hdr);
+}
+
+/* init request without RFC1001 length at the beginning */
+static int
+smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
+		    void **request_buf, unsigned int *total_len)
+{
+	int rc;
+	struct smb2_sync_hdr *shdr;
+
+	rc = smb2_reconnect(smb2_command, tcon);
+	if (rc)
+		return rc;
+
+	/* BB eventually switch this to SMB2 specific small buf size */
+	*request_buf = cifs_small_buf_get();
+	if (*request_buf == NULL) {
+		/* BB should we add a retry in here if not a writepage? */
+		return -ENOMEM;
+	}
+
+	shdr = (struct smb2_sync_hdr *)(*request_buf);
+
+	fill_small_buf(smb2_command, tcon, shdr, total_len);
+
+	if (tcon != NULL) {
+#ifdef CONFIG_CIFS_STATS2
+		uint16_t com_code = le16_to_cpu(smb2_command);
+
+		cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]);
+#endif
+		cifs_stats_inc(&tcon->num_smbs_sent);
+	}
+
+	return rc;
+}
+
 /*
  * Allocate and return pointer to an SMB request hdr, and set basic
  * SMB information in the SMB header. If the return code is zero, this
- * function must have filled in request_buf pointer.
+ * function must have filled in request_buf pointer. The returned buffer
+ * has RFC1001 length at the beginning.
  */
 static int
 small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
 		void **request_buf)
 {
-	int rc = 0;
+	int rc;
+	unsigned int total_len;
+	struct smb2_pdu *pdu;
 
 	rc = smb2_reconnect(smb2_command, tcon);
 	if (rc)
@@ -292,10 +382,15 @@
 		return -ENOMEM;
 	}
 
-	smb2_hdr_assemble((struct smb2_hdr *) *request_buf, smb2_command, tcon);
+	pdu = (struct smb2_pdu *)(*request_buf);
+
+	fill_small_buf(smb2_command, tcon, get_sync_hdr(pdu), &total_len);
+
+	/* Note this is only network field converted to big endian */
+	pdu->hdr.smb2_buf_length = cpu_to_be32(total_len);
 
 	if (tcon != NULL) {
-#ifdef CONFIG_CIFS_STATS2
+#ifdef CONFIG_CIFS_STATS
 		uint16_t com_code = le16_to_cpu(smb2_command);
 		cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]);
 #endif
@@ -347,7 +442,7 @@
 	build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt);
 	req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
 	req->NegotiateContextCount = cpu_to_le16(2);
-	inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context) + 2
+	inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context)
 			+ sizeof(struct smb2_encryption_neg_context)); /* calculate hash */
 }
 #else
@@ -357,7 +452,6 @@
 }
 #endif /* SMB311 */
 
-
 /*
  *
  *	SMB2 Worker functions follow:
@@ -379,6 +473,7 @@
 	struct smb2_negotiate_req *req;
 	struct smb2_negotiate_rsp *rsp;
 	struct kvec iov[1];
+	struct kvec rsp_iov;
 	int rc = 0;
 	int resp_buftype;
 	struct TCP_Server_Info *server = ses->server;
@@ -397,7 +492,7 @@
 	if (rc)
 		return rc;
 
-	req->hdr.SessionId = 0;
+	req->hdr.sync_hdr.SessionId = 0;
 
 	req->Dialects[0] = cpu_to_le16(ses->server->vals->protocol_id);
 
@@ -427,9 +522,9 @@
 	/* 4 for rfc1002 length field */
 	iov[0].iov_len = get_rfc1002_length(req) + 4;
 
-	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags);
-
-	rsp = (struct smb2_negotiate_rsp *)iov[0].iov_base;
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base;
 	/*
 	 * No tcon so can't do
 	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
@@ -512,14 +607,21 @@
 
 	/*
 	 * validation ioctl must be signed, so no point sending this if we
-	 * can not sign it.  We could eventually change this to selectively
+	 * can not sign it (ie are not known user).  Even if signing is not
+	 * required (enabled but not negotiated), in those cases we selectively
 	 * sign just this, the first and only signed request on a connection.
-	 * This is good enough for now since a user who wants better security
-	 * would also enable signing on the mount. Having validation of
-	 * negotiate info for signed connections helps reduce attack vectors
+	 * Having validation of negotiate info  helps reduce attack vectors.
 	 */
-	if (tcon->ses->server->sign == false)
+	if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
+		return 0; /* validation requires signing */
+
+	if (tcon->ses->user_name == NULL) {
+		cifs_dbg(FYI, "Can't validate negotiate: null user mount\n");
 		return 0; /* validation requires signing */
+	}
+
+	if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
+		cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
 
 	vneg_inbuf.Capabilities =
 			cpu_to_le32(tcon->ses->server->vals->req_capabilities);
@@ -550,13 +652,16 @@
 	}
 
 	if (rsplen != sizeof(struct validate_negotiate_info_rsp)) {
-		cifs_dbg(VFS, "invalid size of protocol negotiate response\n");
-		return -EIO;
+		cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n",
+			 rsplen);
+
+		/* relax check since Mac returns max bufsize allowed on ioctl */
+		if (rsplen > CIFSMaxBufSize)
+			return -EIO;
 	}
 
 	/* check validate negotiate info response matches what we got earlier */
-	if (pneg_rsp->Dialect !=
-			cpu_to_le16(tcon->ses->server->vals->protocol_id))
+	if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect))
 		goto vneg_out;
 
 	if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode))
@@ -577,62 +682,46 @@
 	return -EIO;
 }
 
-int
-SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
-		const struct nls_table *nls_cp)
+struct SMB2_sess_data {
+	unsigned int xid;
+	struct cifs_ses *ses;
+	struct nls_table *nls_cp;
+	void (*func)(struct SMB2_sess_data *);
+	int result;
+	u64 previous_session;
+
+	/* we will send the SMB in three pieces:
+	 * a fixed length beginning part, an optional
+	 * SPNEGO blob (which can be zero length), and a
+	 * last part which will include the strings
+	 * and rest of bcc area. This allows us to avoid
+	 * a large buffer 17K allocation
+	 */
+	int buf0_type;
+	struct kvec iov[2];
+};
+
+static int
+SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
 {
+	int rc;
+	struct cifs_ses *ses = sess_data->ses;
 	struct smb2_sess_setup_req *req;
-	struct smb2_sess_setup_rsp *rsp = NULL;
-	struct kvec iov[2];
-	int rc = 0;
-	int resp_buftype = CIFS_NO_BUFFER;
-	__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
 	struct TCP_Server_Info *server = ses->server;
-	u16 blob_length = 0;
-	struct key *spnego_key = NULL;
-	char *security_blob = NULL;
-	char *ntlmssp_blob = NULL;
-	bool use_spnego = false; /* else use raw ntlmssp */
-
-	cifs_dbg(FYI, "Session Setup\n");
-
-	if (!server) {
-		WARN(1, "%s: server is NULL!\n", __func__);
-		return -EIO;
-	}
-
-	/*
-	 * If we are here due to reconnect, free per-smb session key
-	 * in case signing was required.
-	 */
-	kfree(ses->auth_key.response);
-	ses->auth_key.response = NULL;
-
-	/*
-	 * If memory allocation is successful, caller of this function
-	 * frees it.
-	 */
-	ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
-	if (!ses->ntlmssp)
-		return -ENOMEM;
-	ses->ntlmssp->sesskey_per_smbsess = true;
-
-	/* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */
-	if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP)
-		ses->sectype = RawNTLMSSP;
-
-ssetup_ntlmssp_authenticate:
-	if (phase == NtLmChallenge)
-		phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
 
 	rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &req);
 	if (rc)
 		return rc;
 
-	req->hdr.SessionId = 0; /* First session, not a reauthenticate */
+	/* First session, not a reauthenticate */
+	req->hdr.sync_hdr.SessionId = 0;
+
+	/* if reconnect, we need to send previous sess id, otherwise it is 0 */
+	req->PreviousSessionId = sess_data->previous_session;
+
 	req->Flags = 0; /* MBZ */
 	/* to enable echos and oplocks */
-	req->hdr.CreditRequest = cpu_to_le16(3);
+	req->hdr.sync_hdr.CreditRequest = cpu_to_le16(3);
 
 	/* only one of SMB2 signing flags may be set in SMB2 request */
 	if (server->sign)
@@ -642,208 +731,365 @@
 	else
 		req->SecurityMode = 0;
 
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	req->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS);
+#else
 	req->Capabilities = 0;
+#endif /* DFS_UPCALL */
+
 	req->Channel = 0; /* MBZ */
 
-	iov[0].iov_base = (char *)req;
+	sess_data->iov[0].iov_base = (char *)req;
 	/* 4 for rfc1002 length field and 1 for pad */
-	iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+	sess_data->iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+	/*
+	 * This variable will be used to clear the buffer
+	 * allocated above in case of any error in the calling function.
+	 */
+	sess_data->buf0_type = CIFS_SMALL_BUFFER;
 
-	if (ses->sectype == Kerberos) {
-#ifdef CONFIG_CIFS_UPCALL
-		struct cifs_spnego_msg *msg;
+	return 0;
+}
 
-		spnego_key = cifs_get_spnego_key(ses);
-		if (IS_ERR(spnego_key)) {
-			rc = PTR_ERR(spnego_key);
-			spnego_key = NULL;
-			goto ssetup_exit;
-		}
+static void
+SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data)
+{
+	free_rsp_buf(sess_data->buf0_type, sess_data->iov[0].iov_base);
+	sess_data->buf0_type = CIFS_NO_BUFFER;
+}
 
-		msg = spnego_key->payload.data[0];
-		/*
-		 * check version field to make sure that cifs.upcall is
-		 * sending us a response in an expected form
-		 */
-		if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
-			cifs_dbg(VFS,
-				  "bad cifs.upcall version. Expected %d got %d",
-				  CIFS_SPNEGO_UPCALL_VERSION, msg->version);
-			rc = -EKEYREJECTED;
-			goto ssetup_exit;
-		}
-		ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
-						 GFP_KERNEL);
-		if (!ses->auth_key.response) {
-			cifs_dbg(VFS,
-				"Kerberos can't allocate (%u bytes) memory",
-				msg->sesskey_len);
-			rc = -ENOMEM;
-			goto ssetup_exit;
-		}
-		ses->auth_key.len = msg->sesskey_len;
-		blob_length = msg->secblob_len;
-		iov[1].iov_base = msg->data + msg->sesskey_len;
-		iov[1].iov_len = blob_length;
-#else
-		rc = -EOPNOTSUPP;
-		goto ssetup_exit;
-#endif /* CONFIG_CIFS_UPCALL */
-	} else if (phase == NtLmNegotiate) { /* if not krb5 must be ntlmssp */
-		ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
-				       GFP_KERNEL);
-		if (ntlmssp_blob == NULL) {
-			rc = -ENOMEM;
-			goto ssetup_exit;
-		}
-		build_ntlmssp_negotiate_blob(ntlmssp_blob, ses);
-		if (use_spnego) {
-			/* blob_length = build_spnego_ntlmssp_blob(
-					&security_blob,
-					sizeof(struct _NEGOTIATE_MESSAGE),
-					ntlmssp_blob); */
-			/* BB eventually need to add this */
-			cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
-			rc = -EOPNOTSUPP;
-			kfree(ntlmssp_blob);
-			goto ssetup_exit;
-		} else {
-			blob_length = sizeof(struct _NEGOTIATE_MESSAGE);
-			/* with raw NTLMSSP we don't encapsulate in SPNEGO */
-			security_blob = ntlmssp_blob;
-		}
-		iov[1].iov_base = security_blob;
-		iov[1].iov_len = blob_length;
-	} else if (phase == NtLmAuthenticate) {
-		req->hdr.SessionId = ses->Suid;
-		ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
-				       GFP_KERNEL);
-		if (ntlmssp_blob == NULL) {
-			rc = -ENOMEM;
-			goto ssetup_exit;
-		}
-		rc = build_ntlmssp_auth_blob(ntlmssp_blob, &blob_length, ses,
-					     nls_cp);
-		if (rc) {
-			cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n",
-				 rc);
-			goto ssetup_exit; /* BB double check error handling */
-		}
-		if (use_spnego) {
-			/* blob_length = build_spnego_ntlmssp_blob(
-							&security_blob,
-							blob_length,
-							ntlmssp_blob); */
-			cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
-			rc = -EOPNOTSUPP;
-			kfree(ntlmssp_blob);
-			goto ssetup_exit;
-		} else {
-			security_blob = ntlmssp_blob;
-		}
-		iov[1].iov_base = security_blob;
-		iov[1].iov_len = blob_length;
-	} else {
-		cifs_dbg(VFS, "illegal ntlmssp phase\n");
-		rc = -EIO;
-		goto ssetup_exit;
-	}
+static int
+SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
+{
+	int rc;
+	struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base;
+	struct kvec rsp_iov = { NULL, 0 };
 
 	/* Testing shows that buffer offset must be at location of Buffer[0] */
 	req->SecurityBufferOffset =
-				cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
-					    1 /* pad */ - 4 /* rfc1001 len */);
-	req->SecurityBufferLength = cpu_to_le16(blob_length);
+		cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
+			1 /* pad */ - 4 /* rfc1001 len */);
+	req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len);
 
-	inc_rfc1001_len(req, blob_length - 1 /* pad */);
+	inc_rfc1001_len(req, sess_data->iov[1].iov_len - 1 /* pad */);
 
 	/* BB add code to build os and lm fields */
 
-	rc = SendReceive2(xid, ses, iov, 2, &resp_buftype,
-			  CIFS_LOG_ERROR | CIFS_NEG_OP);
+	rc = SendReceive2(sess_data->xid, sess_data->ses,
+				sess_data->iov, 2,
+				&sess_data->buf0_type,
+				CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov);
+	cifs_small_buf_release(sess_data->iov[0].iov_base);
+	memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
 
-	kfree(security_blob);
-	rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
-	ses->Suid = rsp->hdr.SessionId;
-	if (resp_buftype != CIFS_NO_BUFFER &&
-	    rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
-		if (phase != NtLmNegotiate) {
-			cifs_dbg(VFS, "Unexpected more processing error\n");
-			goto ssetup_exit;
-		}
-		if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 !=
-				le16_to_cpu(rsp->SecurityBufferOffset)) {
-			cifs_dbg(VFS, "Invalid security buffer offset %d\n",
-				 le16_to_cpu(rsp->SecurityBufferOffset));
-			rc = -EIO;
-			goto ssetup_exit;
+	return rc;
+}
+
+static int
+SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
+{
+	int rc = 0;
+	struct cifs_ses *ses = sess_data->ses;
+
+	mutex_lock(&ses->server->srv_mutex);
+	if (ses->server->ops->generate_signingkey) {
+		rc = ses->server->ops->generate_signingkey(ses);
+		if (rc) {
+			cifs_dbg(FYI,
+				"SMB3 session key generation failed\n");
+			mutex_unlock(&ses->server->srv_mutex);
+			return rc;
 		}
+	}
+	if (!ses->server->session_estab) {
+		ses->server->sequence_number = 0x2;
+		ses->server->session_estab = true;
+	}
+	mutex_unlock(&ses->server->srv_mutex);
+
+	cifs_dbg(FYI, "SMB2/3 session established successfully\n");
+	spin_lock(&GlobalMid_Lock);
+	ses->status = CifsGood;
+	ses->need_reconnect = false;
+	spin_unlock(&GlobalMid_Lock);
+	return rc;
+}
 
-		/* NTLMSSP Negotiate sent now processing challenge (response) */
-		phase = NtLmChallenge; /* process ntlmssp challenge */
-		rc = 0; /* MORE_PROCESSING is not an error here but expected */
-		rc = decode_ntlmssp_challenge(rsp->Buffer,
-				le16_to_cpu(rsp->SecurityBufferLength), ses);
+#ifdef CONFIG_CIFS_UPCALL
+static void
+SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
+{
+	int rc;
+	struct cifs_ses *ses = sess_data->ses;
+	struct cifs_spnego_msg *msg;
+	struct key *spnego_key = NULL;
+	struct smb2_sess_setup_rsp *rsp = NULL;
+
+	rc = SMB2_sess_alloc_buffer(sess_data);
+	if (rc)
+		goto out;
+
+	spnego_key = cifs_get_spnego_key(ses);
+	if (IS_ERR(spnego_key)) {
+		rc = PTR_ERR(spnego_key);
+		spnego_key = NULL;
+		goto out;
 	}
 
+	msg = spnego_key->payload.data[0];
 	/*
-	 * BB eventually add code for SPNEGO decoding of NtlmChallenge blob,
-	 * but at least the raw NTLMSSP case works.
+	 * check version field to make sure that cifs.upcall is
+	 * sending us a response in an expected form
 	 */
+	if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
+		cifs_dbg(VFS,
+			  "bad cifs.upcall version. Expected %d got %d",
+			  CIFS_SPNEGO_UPCALL_VERSION, msg->version);
+		rc = -EKEYREJECTED;
+		goto out_put_spnego_key;
+	}
+
+	ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
+					 GFP_KERNEL);
+	if (!ses->auth_key.response) {
+		cifs_dbg(VFS,
+			"Kerberos can't allocate (%u bytes) memory",
+			msg->sesskey_len);
+		rc = -ENOMEM;
+		goto out_put_spnego_key;
+	}
+	ses->auth_key.len = msg->sesskey_len;
+
+	sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
+	sess_data->iov[1].iov_len = msg->secblob_len;
+
+	rc = SMB2_sess_sendreceive(sess_data);
+	if (rc)
+		goto out_put_spnego_key;
+
+	rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+	ses->Suid = rsp->hdr.sync_hdr.SessionId;
+
+	ses->session_flags = le16_to_cpu(rsp->SessionFlags);
+
+	rc = SMB2_sess_establish_session(sess_data);
+out_put_spnego_key:
+	key_invalidate(spnego_key);
+	key_put(spnego_key);
+out:
+	sess_data->result = rc;
+	sess_data->func = NULL;
+	SMB2_sess_free_buffer(sess_data);
+}
+#else
+static void
+SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
+{
+	cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
+	sess_data->result = -EOPNOTSUPP;
+	sess_data->func = NULL;
+}
+#endif
+
+static void
+SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data);
+
+static void
+SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
+{
+	int rc;
+	struct cifs_ses *ses = sess_data->ses;
+	struct smb2_sess_setup_rsp *rsp = NULL;
+	char *ntlmssp_blob = NULL;
+	bool use_spnego = false; /* else use raw ntlmssp */
+	u16 blob_length = 0;
+
 	/*
-	 * No tcon so can't do
-	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
+	 * If memory allocation is successful, caller of this function
+	 * frees it.
 	 */
-	if (rc != 0)
-		goto ssetup_exit;
+	ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
+	if (!ses->ntlmssp) {
+		rc = -ENOMEM;
+		goto out_err;
+	}
+	ses->ntlmssp->sesskey_per_smbsess = true;
 
-	ses->session_flags = le16_to_cpu(rsp->SessionFlags);
-	if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
-		cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
-ssetup_exit:
-	free_rsp_buf(resp_buftype, rsp);
+	rc = SMB2_sess_alloc_buffer(sess_data);
+	if (rc)
+		goto out_err;
+
+	ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
+			       GFP_KERNEL);
+	if (ntlmssp_blob == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	build_ntlmssp_negotiate_blob(ntlmssp_blob, ses);
+	if (use_spnego) {
+		/* BB eventually need to add this */
+		cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
+		rc = -EOPNOTSUPP;
+		goto out;
+	} else {
+		blob_length = sizeof(struct _NEGOTIATE_MESSAGE);
+		/* with raw NTLMSSP we don't encapsulate in SPNEGO */
+	}
+	sess_data->iov[1].iov_base = ntlmssp_blob;
+	sess_data->iov[1].iov_len = blob_length;
 
-	/* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
-	if ((phase == NtLmChallenge) && (rc == 0))
-		goto ssetup_ntlmssp_authenticate;
+	rc = SMB2_sess_sendreceive(sess_data);
+	rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
 
+	/* If true, rc here is expected and not an error */
+	if (sess_data->buf0_type != CIFS_NO_BUFFER &&
+		rsp->hdr.sync_hdr.Status == STATUS_MORE_PROCESSING_REQUIRED)
+		rc = 0;
+
+	if (rc)
+		goto out;
+
+	if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 !=
+			le16_to_cpu(rsp->SecurityBufferOffset)) {
+		cifs_dbg(VFS, "Invalid security buffer offset %d\n",
+			le16_to_cpu(rsp->SecurityBufferOffset));
+		rc = -EIO;
+		goto out;
+	}
+	rc = decode_ntlmssp_challenge(rsp->Buffer,
+			le16_to_cpu(rsp->SecurityBufferLength), ses);
+	if (rc)
+		goto out;
+
+	cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
+
+
+	ses->Suid = rsp->hdr.sync_hdr.SessionId;
+	ses->session_flags = le16_to_cpu(rsp->SessionFlags);
+
+out:
+	kfree(ntlmssp_blob);
+	SMB2_sess_free_buffer(sess_data);
 	if (!rc) {
-		mutex_lock(&server->srv_mutex);
-		if (server->sign && server->ops->generate_signingkey) {
-			rc = server->ops->generate_signingkey(ses);
-			kfree(ses->auth_key.response);
-			ses->auth_key.response = NULL;
-			if (rc) {
-				cifs_dbg(FYI,
-					"SMB3 session key generation failed\n");
-				mutex_unlock(&server->srv_mutex);
-				goto keygen_exit;
-			}
-		}
-		if (!server->session_estab) {
-			server->sequence_number = 0x2;
-			server->session_estab = true;
-		}
-		mutex_unlock(&server->srv_mutex);
+		sess_data->result = 0;
+		sess_data->func = SMB2_sess_auth_rawntlmssp_authenticate;
+		return;
+	}
+out_err:
+	kfree(ses->ntlmssp);
+	ses->ntlmssp = NULL;
+	sess_data->result = rc;
+	sess_data->func = NULL;
+}
 
-		cifs_dbg(FYI, "SMB2/3 session established successfully\n");
-		spin_lock(&GlobalMid_Lock);
-		ses->status = CifsGood;
-		ses->need_reconnect = false;
-		spin_unlock(&GlobalMid_Lock);
-	}
-
-keygen_exit:
-	if (!server->sign) {
-		kfree(ses->auth_key.response);
-		ses->auth_key.response = NULL;
-	}
-	if (spnego_key) {
-		key_invalidate(spnego_key);
-		key_put(spnego_key);
+static void
+SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
+{
+	int rc;
+	struct cifs_ses *ses = sess_data->ses;
+	struct smb2_sess_setup_req *req;
+	struct smb2_sess_setup_rsp *rsp = NULL;
+	unsigned char *ntlmssp_blob = NULL;
+	bool use_spnego = false; /* else use raw ntlmssp */
+	u16 blob_length = 0;
+
+	rc = SMB2_sess_alloc_buffer(sess_data);
+	if (rc)
+		goto out;
+
+	req = (struct smb2_sess_setup_req *) sess_data->iov[0].iov_base;
+	req->hdr.sync_hdr.SessionId = ses->Suid;
+
+	rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses,
+					sess_data->nls_cp);
+	if (rc) {
+		cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", rc);
+		goto out;
 	}
+
+	if (use_spnego) {
+		/* BB eventually need to add this */
+		cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
+		rc = -EOPNOTSUPP;
+		goto out;
+	}
+	sess_data->iov[1].iov_base = ntlmssp_blob;
+	sess_data->iov[1].iov_len = blob_length;
+
+	rc = SMB2_sess_sendreceive(sess_data);
+	if (rc)
+		goto out;
+
+	rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+
+	ses->Suid = rsp->hdr.sync_hdr.SessionId;
+	ses->session_flags = le16_to_cpu(rsp->SessionFlags);
+
+	rc = SMB2_sess_establish_session(sess_data);
+out:
+	kfree(ntlmssp_blob);
+	SMB2_sess_free_buffer(sess_data);
 	kfree(ses->ntlmssp);
+	ses->ntlmssp = NULL;
+	sess_data->result = rc;
+	sess_data->func = NULL;
+}
+
+static int
+SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data)
+{
+	if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP)
+		ses->sectype = RawNTLMSSP;
+
+	switch (ses->sectype) {
+	case Kerberos:
+		sess_data->func = SMB2_auth_kerberos;
+		break;
+	case RawNTLMSSP:
+		sess_data->func = SMB2_sess_auth_rawntlmssp_negotiate;
+		break;
+	default:
+		cifs_dbg(VFS, "secType %d not supported!\n", ses->sectype);
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+int
+SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
+		const struct nls_table *nls_cp)
+{
+	int rc = 0;
+	struct TCP_Server_Info *server = ses->server;
+	struct SMB2_sess_data *sess_data;
+
+	cifs_dbg(FYI, "Session Setup\n");
+
+	if (!server) {
+		WARN(1, "%s: server is NULL!\n", __func__);
+		return -EIO;
+	}
+
+	sess_data = kzalloc(sizeof(struct SMB2_sess_data), GFP_KERNEL);
+	if (!sess_data)
+		return -ENOMEM;
+
+	rc = SMB2_select_sec(ses, sess_data);
+	if (rc)
+		goto out;
+	sess_data->xid = xid;
+	sess_data->ses = ses;
+	sess_data->buf0_type = CIFS_NO_BUFFER;
+	sess_data->nls_cp = (struct nls_table *) nls_cp;
+
+	while (sess_data->func)
+		sess_data->func(sess_data);
 
+	rc = sess_data->result;
+out:
+	kfree(sess_data);
 	return rc;
 }
 
@@ -853,6 +1099,7 @@
 	struct smb2_logoff_req *req; /* response is also trivial struct */
 	int rc = 0;
 	struct TCP_Server_Info *server;
+	int flags = 0;
 
 	cifs_dbg(FYI, "disconnect session %p\n", ses);
 
@@ -870,11 +1117,15 @@
 		return rc;
 
 	 /* since no tcon, smb2_init can not do this, so do here */
-	req->hdr.SessionId = ses->Suid;
-	if (server->sign)
-		req->hdr.Flags |= SMB2_FLAGS_SIGNED;
+	req->hdr.sync_hdr.SessionId = ses->Suid;
 
-	rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
+	if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
+		flags |= CIFS_TRANSFORM_REQ;
+	else if (server->sign)
+		req->hdr.sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
+
+	rc = SendReceiveNoRsp(xid, ses, (char *) req, flags);
+	cifs_small_buf_release(req);
 	/*
 	 * No tcon so can't do
 	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
@@ -906,11 +1157,13 @@
 	struct smb2_tree_connect_req *req;
 	struct smb2_tree_connect_rsp *rsp = NULL;
 	struct kvec iov[2];
+	struct kvec rsp_iov;
 	int rc = 0;
 	int resp_buftype;
 	int unc_path_len;
 	struct TCP_Server_Info *server;
 	__le16 *unc_path = NULL;
+	int flags = 0;
 
 	cifs_dbg(FYI, "TCON\n");
 
@@ -919,15 +1172,6 @@
 	else
 		return -EIO;
 
-	if (tcon && tcon->bad_network_name)
-		return -ENOENT;
-
-	if ((tcon && tcon->seal) &&
-	    ((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) {
-		cifs_dbg(VFS, "encryption requested but no server support");
-		return -EOPNOTSUPP;
-	}
-
 	unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
 	if (unc_path == NULL)
 		return -ENOMEM;
@@ -939,6 +1183,10 @@
 		return -EINVAL;
 	}
 
+	/* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
+	if (tcon)
+		tcon->tid = 0;
+
 	rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req);
 	if (rc) {
 		kfree(unc_path);
@@ -946,11 +1194,15 @@
 	}
 
 	if (tcon == NULL) {
+		if ((ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA))
+			flags |= CIFS_TRANSFORM_REQ;
+
 		/* since no tcon, smb2_init can not do this, so do here */
-		req->hdr.SessionId = ses->Suid;
+		req->hdr.sync_hdr.SessionId = ses->Suid;
 		/* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED)
 			req->hdr.Flags |= SMB2_FLAGS_SIGNED; */
-	}
+	} else if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
 
 	iov[0].iov_base = (char *)req;
 	/* 4 for rfc1002 length field and 1 for pad */
@@ -965,8 +1217,9 @@
 
 	inc_rfc1001_len(req, unc_path_len - 1 /* pad */);
 
-	rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
-	rsp = (struct smb2_tree_connect_rsp *)iov[0].iov_base;
+	rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
 
 	if (rc != 0) {
 		if (tcon) {
@@ -977,19 +1230,23 @@
 	}
 
 	if (tcon == NULL) {
-		ses->ipc_tid = rsp->hdr.TreeId;
+		ses->ipc_tid = rsp->hdr.sync_hdr.TreeId;
 		goto tcon_exit;
 	}
 
-	if (rsp->ShareType & SMB2_SHARE_TYPE_DISK)
+	switch (rsp->ShareType) {
+	case SMB2_SHARE_TYPE_DISK:
 		cifs_dbg(FYI, "connection to disk share\n");
-	else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) {
+		break;
+	case SMB2_SHARE_TYPE_PIPE:
 		tcon->ipc = true;
 		cifs_dbg(FYI, "connection to pipe share\n");
-	} else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) {
-		tcon->print = true;
+		break;
+	case SMB2_SHARE_TYPE_PRINT:
+		tcon->ipc = true;
 		cifs_dbg(FYI, "connection to printer\n");
-	} else {
+		break;
+	default:
 		cifs_dbg(VFS, "unknown share type %d\n", rsp->ShareType);
 		rc = -EOPNOTSUPP;
 		goto tcon_error_exit;
@@ -1000,15 +1257,18 @@
 	tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
 	tcon->tidStatus = CifsGood;
 	tcon->need_reconnect = false;
-	tcon->tid = rsp->hdr.TreeId;
+	tcon->tid = rsp->hdr.sync_hdr.TreeId;
 	strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
 
 	if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
 	    ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
 		cifs_dbg(VFS, "DFS capability contradicts DFS flag\n");
+
+	if (tcon->seal &&
+	    !(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
+		cifs_dbg(VFS, "Encryption is requested but not supported\n");
+
 	init_copy_chunk_defaults(tcon);
-	if (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA)
-		cifs_dbg(VFS, "Encrypted shares not supported");
 	if (tcon->ses->server->ops->validate_negotiate)
 		rc = tcon->ses->server->ops->validate_negotiate(xid, tcon);
 tcon_exit:
@@ -1017,10 +1277,8 @@
 	return rc;
 
 tcon_error_exit:
-	if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
+	if (rsp->hdr.sync_hdr.Status == STATUS_BAD_NETWORK_NAME) {
 		cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
-		if (tcon)
-			tcon->bad_network_name = true;
 	}
 	goto tcon_exit;
 }
@@ -1032,6 +1290,7 @@
 	int rc = 0;
 	struct TCP_Server_Info *server;
 	struct cifs_ses *ses = tcon->ses;
+	int flags = 0;
 
 	cifs_dbg(FYI, "Tree Disconnect\n");
 
@@ -1047,7 +1306,11 @@
 	if (rc)
 		return rc;
 
-	rc = SendReceiveNoRsp(xid, ses, (char *)&req->hdr, 0);
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	rc = SendReceiveNoRsp(xid, ses, (char *)req, flags);
+	cifs_small_buf_release(req);
 	if (rc)
 		cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE);
 
@@ -1109,21 +1372,25 @@
 {
 	char *data_offset;
 	struct create_context *cc;
-	unsigned int next = 0;
+	unsigned int next;
+	unsigned int remaining;
 	char *name;
 
 	data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset);
+	remaining = le32_to_cpu(rsp->CreateContextsLength);
 	cc = (struct create_context *)data_offset;
-	do {
-		cc = (struct create_context *)((char *)cc + next);
+	while (remaining >= sizeof(struct create_context)) {
 		name = le16_to_cpu(cc->NameOffset) + (char *)cc;
-		if (le16_to_cpu(cc->NameLength) != 4 ||
-		    strncmp(name, "RqLs", 4)) {
-			next = le32_to_cpu(cc->Next);
-			continue;
-		}
-		return server->ops->parse_lease_buf(cc, epoch);
-	} while (next != 0);
+		if (le16_to_cpu(cc->NameLength) == 4 &&
+		    strncmp(name, "RqLs", 4) == 0)
+			return server->ops->parse_lease_buf(cc, epoch);
+
+		next = le32_to_cpu(cc->Next);
+		if (!next)
+			break;
+		remaining -= next;
+		cc = (struct create_context *)((char *)cc + next);
+	}
 
 	return 0;
 }
@@ -1169,7 +1436,7 @@
 
 	buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
 	buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
-	get_random_bytes(buf->dcontext.CreateGuid, 16);
+	generate_random_uuid(buf->dcontext.CreateGuid);
 	memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
 
 	/* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
@@ -1305,14 +1572,16 @@
 	struct cifs_tcon *tcon = oparms->tcon;
 	struct cifs_ses *ses = tcon->ses;
 	struct kvec iov[4];
+	struct kvec rsp_iov;
 	int resp_buftype;
 	int uni_path_len;
 	__le16 *copy_path = NULL;
 	int copy_size;
 	int rc = 0;
-	unsigned int num_iovecs = 2;
+	unsigned int n_iov = 2;
 	__u32 file_attributes = 0;
 	char *dhc_buf = NULL, *lc_buf = NULL;
+	int flags = 0;
 
 	cifs_dbg(FYI, "create/open\n");
 
@@ -1325,6 +1594,9 @@
 	if (rc)
 		return rc;
 
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
 	if (oparms->create_options & CREATE_OPTION_READONLY)
 		file_attributes |= ATTR_READONLY;
 	if (oparms->create_options & CREATE_OPTION_SPECIAL)
@@ -1375,25 +1647,25 @@
 	    *oplock == SMB2_OPLOCK_LEVEL_NONE)
 		req->RequestedOplockLevel = *oplock;
 	else {
-		rc = add_lease_context(server, iov, &num_iovecs, oplock);
+		rc = add_lease_context(server, iov, &n_iov, oplock);
 		if (rc) {
 			cifs_small_buf_release(req);
 			kfree(copy_path);
 			return rc;
 		}
-		lc_buf = iov[num_iovecs-1].iov_base;
+		lc_buf = iov[n_iov-1].iov_base;
 	}
 
 	if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
 		/* need to set Next field of lease context if we request it */
 		if (server->capabilities & SMB2_GLOBAL_CAP_LEASING) {
 			struct create_context *ccontext =
-			    (struct create_context *)iov[num_iovecs-1].iov_base;
+			    (struct create_context *)iov[n_iov-1].iov_base;
 			ccontext->Next =
 				cpu_to_le32(server->vals->create_lease_size);
 		}
 
-		rc = add_durable_context(iov, &num_iovecs, oparms,
+		rc = add_durable_context(iov, &n_iov, oparms,
 					tcon->use_persistent);
 		if (rc) {
 			cifs_small_buf_release(req);
@@ -1401,11 +1673,12 @@
 			kfree(lc_buf);
 			return rc;
 		}
-		dhc_buf = iov[num_iovecs-1].iov_base;
+		dhc_buf = iov[n_iov-1].iov_base;
 	}
 
-	rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
-	rsp = (struct smb2_create_rsp *)iov[0].iov_base;
+	rc = SendReceive2(xid, ses, iov, n_iov, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
 
 	if (rc != 0) {
 		cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
@@ -1449,12 +1722,15 @@
 {
 	struct smb2_ioctl_req *req;
 	struct smb2_ioctl_rsp *rsp;
+	struct smb2_sync_hdr *shdr;
 	struct TCP_Server_Info *server;
 	struct cifs_ses *ses;
 	struct kvec iov[2];
+	struct kvec rsp_iov;
 	int resp_buftype;
-	int num_iovecs;
+	int n_iov;
 	int rc = 0;
+	int flags = 0;
 
 	cifs_dbg(FYI, "SMB2 IOCTL\n");
 
@@ -1479,6 +1755,9 @@
 	if (rc)
 		return rc;
 
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
 	req->CtlCode = cpu_to_le32(opcode);
 	req->PersistentFileId = persistent_fid;
 	req->VolatileFileId = volatile_fid;
@@ -1490,9 +1769,9 @@
 		       cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer) - 4);
 		iov[1].iov_base = in_data;
 		iov[1].iov_len = indatalen;
-		num_iovecs = 2;
+		n_iov = 2;
 	} else
-		num_iovecs = 1;
+		n_iov = 1;
 
 	req->OutputOffset = 0;
 	req->OutputCount = 0; /* MBZ */
@@ -1502,8 +1781,12 @@
 	 * than one credit. Windows typically sets this smaller, but for some
 	 * ioctls it may be useful to allow server to send more. No point
 	 * limiting what the server can send as long as fits in one credit
+	 * Unfortunately - we can not handle more than CIFS_MAX_MSG_SIZE
+	 * (by default, note that it can be overridden to make max larger)
+	 * in responses (except for read responses which can be bigger.
+	 * We may want to bump this limit up
 	 */
-	req->MaxOutputResponse = cpu_to_le32(0xFF00); /* < 64K uses 1 credit */
+	req->MaxOutputResponse = cpu_to_le32(CIFSMaxBufSize);
 
 	if (is_fsctl)
 		req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
@@ -1528,9 +1811,13 @@
 	} else
 		iov[0].iov_len = get_rfc1002_length(req) + 4;
 
+	/* validate negotiate request must be signed - see MS-SMB2 3.2.5.5 */
+	if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO)
+		req->hdr.sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
 
-	rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
-	rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
+	rc = SendReceive2(xid, ses, iov, n_iov, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base;
 
 	if ((rc != 0) && (rc != -EINVAL)) {
 		cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
@@ -1573,8 +1860,8 @@
 		goto ioctl_exit;
 	}
 
-	memcpy(*out_data, rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset),
-	       *plen);
+	shdr = get_sync_hdr(rsp);
+	memcpy(*out_data, (char *)shdr + le32_to_cpu(rsp->OutputOffset), *plen);
 ioctl_exit:
 	free_rsp_buf(resp_buftype, rsp);
 	return rc;
@@ -1614,8 +1901,10 @@
 	struct TCP_Server_Info *server;
 	struct cifs_ses *ses = tcon->ses;
 	struct kvec iov[1];
+	struct kvec rsp_iov;
 	int resp_buftype;
 	int rc = 0;
+	int flags = 0;
 
 	cifs_dbg(FYI, "Close\n");
 
@@ -1628,6 +1917,9 @@
 	if (rc)
 		return rc;
 
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
 	req->PersistentFileId = persistent_fid;
 	req->VolatileFileId = volatile_fid;
 
@@ -1635,8 +1927,9 @@
 	/* 4 for rfc1002 length field */
 	iov[0].iov_len = get_rfc1002_length(req) + 4;
 
-	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
-	rsp = (struct smb2_close_rsp *)iov[0].iov_base;
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
 
 	if (rc != 0) {
 		cifs_stats_fail_inc(tcon, SMB2_CLOSE_HE);
@@ -1715,10 +2008,12 @@
 	struct smb2_query_info_req *req;
 	struct smb2_query_info_rsp *rsp = NULL;
 	struct kvec iov[2];
+	struct kvec rsp_iov;
 	int rc = 0;
 	int resp_buftype;
 	struct TCP_Server_Info *server;
 	struct cifs_ses *ses = tcon->ses;
+	int flags = 0;
 
 	cifs_dbg(FYI, "Query Info\n");
 
@@ -1731,6 +2026,9 @@
 	if (rc)
 		return rc;
 
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
 	req->InfoType = SMB2_O_INFO_FILE;
 	req->FileInfoClass = info_class;
 	req->PersistentFileId = persistent_fid;
@@ -1744,8 +2042,9 @@
 	/* 4 for rfc1002 length field */
 	iov[0].iov_len = get_rfc1002_length(req) + 4;
 
-	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
-	rsp = (struct smb2_query_info_rsp *)iov[0].iov_base;
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -1793,11 +2092,11 @@
 smb2_echo_callback(struct mid_q_entry *mid)
 {
 	struct TCP_Server_Info *server = mid->callback_data;
-	struct smb2_echo_rsp *smb2 = (struct smb2_echo_rsp *)mid->resp_buf;
+	struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf;
 	unsigned int credits_received = 1;
 
 	if (mid->mid_state == MID_RESPONSE_RECEIVED)
-		credits_received = le16_to_cpu(smb2->hdr.CreditRequest);
+		credits_received = le16_to_cpu(rsp->hdr.sync_hdr.CreditRequest);
 
 	mutex_lock(&server->srv_mutex);
 	DeleteMidQEntry(mid);
@@ -1805,29 +2104,85 @@
 	add_credits(server, credits_received, CIFS_ECHO_OP);
 }
 
+void smb2_reconnect_server(struct work_struct *work)
+{
+	struct TCP_Server_Info *server = container_of(work,
+					struct TCP_Server_Info, reconnect.work);
+	struct cifs_ses *ses;
+	struct cifs_tcon *tcon, *tcon2;
+	struct list_head tmp_list;
+	int tcon_exist = false;
+
+	/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
+	mutex_lock(&server->reconnect_mutex);
+
+	INIT_LIST_HEAD(&tmp_list);
+	cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
+
+	spin_lock(&cifs_tcp_ses_lock);
+	list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+		list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+			if (tcon->need_reconnect) {
+				tcon->tc_count++;
+				list_add_tail(&tcon->rlist, &tmp_list);
+				tcon_exist = true;
+			}
+		}
+	}
+	/*
+	 * Get the reference to server struct to be sure that the last call of
+	 * cifs_put_tcon() in the loop below won't release the server pointer.
+	 */
+	if (tcon_exist)
+		server->srv_count++;
+
+	spin_unlock(&cifs_tcp_ses_lock);
+
+	list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
+		smb2_reconnect(SMB2_ECHO, tcon);
+		list_del_init(&tcon->rlist);
+		cifs_put_tcon(tcon);
+	}
+
+	cifs_dbg(FYI, "Reconnecting tcons finished\n");
+	mutex_unlock(&server->reconnect_mutex);
+
+	/* now we can safely release srv struct */
+	if (tcon_exist)
+		cifs_put_tcp_session(server, 1);
+}
+
 int
 SMB2_echo(struct TCP_Server_Info *server)
 {
 	struct smb2_echo_req *req;
 	int rc = 0;
-	struct kvec iov;
-	struct smb_rqst rqst = { .rq_iov = &iov,
-				 .rq_nvec = 1 };
+	struct kvec iov[2];
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = 2 };
 
 	cifs_dbg(FYI, "In echo request\n");
 
+	if (server->tcpStatus == CifsNeedNegotiate) {
+		/* No need to send echo on newly established connections */
+		queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
+		return rc;
+	}
+
 	rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req);
 	if (rc)
 		return rc;
 
-	req->hdr.CreditRequest = cpu_to_le16(1);
+	req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
 
-	iov.iov_base = (char *)req;
 	/* 4 for rfc1002 length field */
-	iov.iov_len = get_rfc1002_length(req) + 4;
+	iov[0].iov_len = 4;
+	iov[0].iov_base = (char *)req;
+	iov[1].iov_len = get_rfc1002_length(req);
+	iov[1].iov_base = (char *)req + 4;
 
-	rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, server,
-			     CIFS_ECHO_OP);
+	rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL,
+			     server, CIFS_ECHO_OP);
 	if (rc)
 		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
 
@@ -1843,8 +2198,10 @@
 	struct TCP_Server_Info *server;
 	struct cifs_ses *ses = tcon->ses;
 	struct kvec iov[1];
+	struct kvec rsp_iov;
 	int resp_buftype;
 	int rc = 0;
+	int flags = 0;
 
 	cifs_dbg(FYI, "Flush\n");
 
@@ -1857,6 +2214,9 @@
 	if (rc)
 		return rc;
 
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
 	req->PersistentFileId = persistent_fid;
 	req->VolatileFileId = volatile_fid;
 
@@ -1864,12 +2224,13 @@
 	/* 4 for rfc1002 length field */
 	iov[0].iov_len = get_rfc1002_length(req) + 4;
 
-	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
 
 	if (rc != 0)
 		cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
 
-	free_rsp_buf(resp_buftype, iov[0].iov_base);
+	free_rsp_buf(resp_buftype, rsp_iov.iov_base);
 	return rc;
 }
 
@@ -1878,19 +2239,23 @@
  * have the end_of_chain boolean set to true.
  */
 static int
-smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
-		  unsigned int remaining_bytes, int request_type)
+smb2_new_read_req(void **buf, unsigned int *total_len,
+		  struct cifs_io_parms *io_parms, unsigned int remaining_bytes,
+		  int request_type)
 {
 	int rc = -EACCES;
-	struct smb2_read_req *req = NULL;
+	struct smb2_read_plain_req *req = NULL;
+	struct smb2_sync_hdr *shdr;
 
-	rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &req);
+	rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, (void **) &req,
+				 total_len);
 	if (rc)
 		return rc;
 	if (io_parms->tcon->ses->server == NULL)
 		return -ECONNABORTED;
 
-	req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+	shdr = &req->sync_hdr;
+	shdr->ProcessId = cpu_to_le32(io_parms->pid);
 
 	req->PersistentFileId = io_parms->persistent_fid;
 	req->VolatileFileId = io_parms->volatile_fid;
@@ -1903,19 +2268,19 @@
 
 	if (request_type & CHAINED_REQUEST) {
 		if (!(request_type & END_OF_CHAIN)) {
-			/* 4 for rfc1002 length field */
-			req->hdr.NextCommand =
-				cpu_to_le32(get_rfc1002_length(req) + 4);
+			/* next 8-byte aligned request */
+			*total_len = DIV_ROUND_UP(*total_len, 8) * 8;
+			shdr->NextCommand = cpu_to_le32(*total_len);
 		} else /* END_OF_CHAIN */
-			req->hdr.NextCommand = 0;
+			shdr->NextCommand = 0;
 		if (request_type & RELATED_REQUEST) {
-			req->hdr.Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
+			shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
 			/*
 			 * Related requests use info from previous read request
 			 * in chain.
 			 */
-			req->hdr.SessionId = 0xFFFFFFFF;
-			req->hdr.TreeId = 0xFFFFFFFF;
+			shdr->SessionId = 0xFFFFFFFF;
+			shdr->TreeId = 0xFFFFFFFF;
 			req->PersistentFileId = 0xFFFFFFFF;
 			req->VolatileFileId = 0xFFFFFFFF;
 		}
@@ -1925,9 +2290,7 @@
 	else
 		req->RemainingBytes = 0;
 
-	iov[0].iov_base = (char *)req;
-	/* 4 for rfc1002 length field */
-	iov[0].iov_len = get_rfc1002_length(req) + 4;
+	*buf = req;
 	return rc;
 }
 
@@ -1937,10 +2300,11 @@
 	struct cifs_readdata *rdata = mid->callback_data;
 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
-	struct smb2_hdr *buf = (struct smb2_hdr *)rdata->iov.iov_base;
+	struct smb2_sync_hdr *shdr =
+				(struct smb2_sync_hdr *)rdata->iov[1].iov_base;
 	unsigned int credits_received = 1;
-	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
-				 .rq_nvec = 1,
+	struct smb_rqst rqst = { .rq_iov = rdata->iov,
+				 .rq_nvec = 2,
 				 .rq_pages = rdata->pages,
 				 .rq_npages = rdata->nr_pages,
 				 .rq_pagesz = rdata->pagesz,
@@ -1952,9 +2316,9 @@
 
 	switch (mid->mid_state) {
 	case MID_RESPONSE_RECEIVED:
-		credits_received = le16_to_cpu(buf->CreditRequest);
+		credits_received = le16_to_cpu(shdr->CreditRequest);
 		/* result already set, check signature */
-		if (server->sign) {
+		if (server->sign && !mid->decrypted) {
 			int rc;
 
 			rc = smb2_verify_signature(&rqst, server);
@@ -1991,16 +2355,19 @@
 	add_credits(server, credits_received, 0);
 }
 
-/* smb2_async_readv - send an async write, and set up mid to handle result */
+/* smb2_async_readv - send an async read, and set up mid to handle result */
 int
 smb2_async_readv(struct cifs_readdata *rdata)
 {
 	int rc, flags = 0;
-	struct smb2_hdr *buf;
+	char *buf;
+	struct smb2_sync_hdr *shdr;
 	struct cifs_io_parms io_parms;
-	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
-				 .rq_nvec = 1 };
+	struct smb_rqst rqst = { .rq_iov = rdata->iov,
+				 .rq_nvec = 2 };
 	struct TCP_Server_Info *server;
+	unsigned int total_len;
+	__be32 req_len;
 
 	cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
 		 __func__, rdata->offset, rdata->bytes);
@@ -2014,7 +2381,7 @@
 
 	server = io_parms.tcon->ses->server;
 
-	rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0);
+	rc = smb2_new_read_req((void **) &buf, &total_len, &io_parms, 0, 0);
 	if (rc) {
 		if (rc == -EAGAIN && rdata->credits) {
 			/* credits was reset by reconnect */
@@ -2027,25 +2394,34 @@
 		return rc;
 	}
 
-	buf = (struct smb2_hdr *)rdata->iov.iov_base;
-	/* 4 for rfc1002 length field */
-	rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4;
+	if (encryption_required(io_parms.tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	req_len = cpu_to_be32(total_len);
+
+	rdata->iov[0].iov_base = &req_len;
+	rdata->iov[0].iov_len = sizeof(__be32);
+	rdata->iov[1].iov_base = buf;
+	rdata->iov[1].iov_len = total_len;
+
+	shdr = (struct smb2_sync_hdr *)buf;
 
 	if (rdata->credits) {
-		buf->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
+		shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
 						SMB2_MAX_BUFFER_SIZE));
+		shdr->CreditRequest = shdr->CreditCharge;
 		spin_lock(&server->req_lock);
 		server->credits += rdata->credits -
-						le16_to_cpu(buf->CreditCharge);
+						le16_to_cpu(shdr->CreditCharge);
 		spin_unlock(&server->req_lock);
 		wake_up(&server->request_q);
-		flags = CIFS_HAS_CREDITS;
+		flags |= CIFS_HAS_CREDITS;
 	}
 
 	kref_get(&rdata->refcount);
 	rc = cifs_call_async(io_parms.tcon->ses->server, &rqst,
 			     cifs_readv_receive, smb2_readv_callback,
-			     rdata, flags);
+			     smb3_handle_read_data, rdata, flags);
 	if (rc) {
 		kref_put(&rdata->refcount, cifs_readdata_release);
 		cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE);
@@ -2060,21 +2436,41 @@
 	  unsigned int *nbytes, char **buf, int *buf_type)
 {
 	int resp_buftype, rc = -EACCES;
+	struct smb2_read_plain_req *req = NULL;
 	struct smb2_read_rsp *rsp = NULL;
-	struct kvec iov[1];
+	struct smb2_sync_hdr *shdr;
+	struct kvec iov[2];
+	struct kvec rsp_iov;
+	unsigned int total_len;
+	__be32 req_len;
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = 2 };
+	int flags = CIFS_LOG_ERROR;
+	struct cifs_ses *ses = io_parms->tcon->ses;
 
 	*nbytes = 0;
-	rc = smb2_new_read_req(iov, io_parms, 0, 0);
+	rc = smb2_new_read_req((void **)&req, &total_len, io_parms, 0, 0);
 	if (rc)
 		return rc;
 
-	rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
-			  &resp_buftype, CIFS_LOG_ERROR);
+	if (encryption_required(io_parms->tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	req_len = cpu_to_be32(total_len);
+
+	iov[0].iov_base = &req_len;
+	iov[0].iov_len = sizeof(__be32);
+	iov[1].iov_base = req;
+	iov[1].iov_len = total_len;
+
+	rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
 
-	rsp = (struct smb2_read_rsp *)iov[0].iov_base;
+	rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
+	shdr = get_sync_hdr(rsp);
 
-	if (rsp->hdr.Status == STATUS_END_OF_FILE) {
-		free_rsp_buf(resp_buftype, iov[0].iov_base);
+	if (shdr->Status == STATUS_END_OF_FILE) {
+		free_rsp_buf(resp_buftype, rsp_iov.iov_base);
 		return 0;
 	}
 
@@ -2093,11 +2489,10 @@
 	}
 
 	if (*buf) {
-		memcpy(*buf, (char *)rsp->hdr.ProtocolId + rsp->DataOffset,
-		       *nbytes);
-		free_rsp_buf(resp_buftype, iov[0].iov_base);
+		memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes);
+		free_rsp_buf(resp_buftype, rsp_iov.iov_base);
 	} else if (resp_buftype != CIFS_NO_BUFFER) {
-		*buf = iov[0].iov_base;
+		*buf = rsp_iov.iov_base;
 		if (resp_buftype == CIFS_SMALL_BUFFER)
 			*buf_type = CIFS_SMALL_BUFFER;
 		else if (resp_buftype == CIFS_LARGE_BUFFER)
@@ -2122,7 +2517,7 @@
 
 	switch (mid->mid_state) {
 	case MID_RESPONSE_RECEIVED:
-		credits_received = le16_to_cpu(rsp->hdr.CreditRequest);
+		credits_received = le16_to_cpu(rsp->hdr.sync_hdr.CreditRequest);
 		wdata->result = smb2_check_receive(mid, tcon->ses->server, 0);
 		if (wdata->result != 0)
 			break;
@@ -2168,10 +2563,11 @@
 {
 	int rc = -EACCES, flags = 0;
 	struct smb2_write_req *req = NULL;
+	struct smb2_sync_hdr *shdr;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
-	struct kvec iov;
-	struct smb_rqst rqst;
+	struct kvec iov[2];
+	struct smb_rqst rqst = { };
 
 	rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
 	if (rc) {
@@ -2186,7 +2582,11 @@
 		goto async_writev_out;
 	}
 
-	req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	shdr = get_sync_hdr(req);
+	shdr->ProcessId = cpu_to_le32(wdata->cfile->pid);
 
 	req->PersistentFileId = wdata->cfile->fid.persistent_fid;
 	req->VolatileFileId = wdata->cfile->fid.volatile_fid;
@@ -2200,11 +2600,13 @@
 	req->RemainingBytes = 0;
 
 	/* 4 for rfc1002 length field and 1 for Buffer */
-	iov.iov_len = get_rfc1002_length(req) + 4 - 1;
-	iov.iov_base = req;
+	iov[0].iov_len = 4;
+	iov[0].iov_base = req;
+	iov[1].iov_len = get_rfc1002_length(req) - 1;
+	iov[1].iov_base = (char *)req + 4;
 
-	rqst.rq_iov = &iov;
-	rqst.rq_nvec = 1;
+	rqst.rq_iov = iov;
+	rqst.rq_nvec = 2;
 	rqst.rq_pages = wdata->pages;
 	rqst.rq_npages = wdata->nr_pages;
 	rqst.rq_pagesz = wdata->pagesz;
@@ -2218,19 +2620,20 @@
 	inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */);
 
 	if (wdata->credits) {
-		req->hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
+		shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
 						    SMB2_MAX_BUFFER_SIZE));
+		shdr->CreditRequest = shdr->CreditCharge;
 		spin_lock(&server->req_lock);
 		server->credits += wdata->credits -
-					le16_to_cpu(req->hdr.CreditCharge);
+						le16_to_cpu(shdr->CreditCharge);
 		spin_unlock(&server->req_lock);
 		wake_up(&server->request_q);
-		flags = CIFS_HAS_CREDITS;
+		flags |= CIFS_HAS_CREDITS;
 	}
 
 	kref_get(&wdata->refcount);
-	rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, wdata,
-			     flags);
+	rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL,
+			     wdata, flags);
 
 	if (rc) {
 		kref_put(&wdata->refcount, release);
@@ -2256,6 +2659,9 @@
 	struct smb2_write_req *req = NULL;
 	struct smb2_write_rsp *rsp = NULL;
 	int resp_buftype;
+	struct kvec rsp_iov;
+	int flags = 0;
+
 	*nbytes = 0;
 
 	if (n_vec < 1)
@@ -2268,7 +2674,10 @@
 	if (io_parms->tcon->ses->server == NULL)
 		return -ECONNABORTED;
 
-	req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+	if (encryption_required(io_parms->tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	req->hdr.sync_hdr.ProcessId = cpu_to_le32(io_parms->pid);
 
 	req->PersistentFileId = io_parms->persistent_fid;
 	req->VolatileFileId = io_parms->volatile_fid;
@@ -2290,8 +2699,9 @@
 	inc_rfc1001_len(req, io_parms->length - 1 /* Buffer */);
 
 	rc = SendReceive2(xid, io_parms->tcon->ses, iov, n_vec + 1,
-			  &resp_buftype, 0);
-	rsp = (struct smb2_write_rsp *)iov[0].iov_base;
+			  &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
 
 	if (rc) {
 		cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
@@ -2309,33 +2719,38 @@
 	int len;
 	unsigned int entrycount = 0;
 	unsigned int next_offset = 0;
-	FILE_DIRECTORY_INFO *entryptr;
+	char *entryptr;
+	FILE_DIRECTORY_INFO *dir_info;
 
 	if (bufstart == NULL)
 		return 0;
 
-	entryptr = (FILE_DIRECTORY_INFO *)bufstart;
+	entryptr = bufstart;
 
 	while (1) {
-		entryptr = (FILE_DIRECTORY_INFO *)
-					((char *)entryptr + next_offset);
-
-		if ((char *)entryptr + size > end_of_buf) {
+		if (entryptr + next_offset < entryptr ||
+		    entryptr + next_offset > end_of_buf ||
+		    entryptr + next_offset + size > end_of_buf) {
 			cifs_dbg(VFS, "malformed search entry would overflow\n");
 			break;
 		}
 
-		len = le32_to_cpu(entryptr->FileNameLength);
-		if ((char *)entryptr + len + size > end_of_buf) {
+		entryptr = entryptr + next_offset;
+		dir_info = (FILE_DIRECTORY_INFO *)entryptr;
+
+		len = le32_to_cpu(dir_info->FileNameLength);
+		if (entryptr + len < entryptr ||
+		    entryptr + len > end_of_buf ||
+		    entryptr + len + size > end_of_buf) {
 			cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n",
 				 end_of_buf);
 			break;
 		}
 
-		*lastentry = (char *)entryptr;
+		*lastentry = entryptr;
 		entrycount++;
 
-		next_offset = le32_to_cpu(entryptr->NextEntryOffset);
+		next_offset = le32_to_cpu(dir_info->NextEntryOffset);
 		if (!next_offset)
 			break;
 	}
@@ -2354,6 +2769,7 @@
 	struct smb2_query_directory_req *req;
 	struct smb2_query_directory_rsp *rsp = NULL;
 	struct kvec iov[2];
+	struct kvec rsp_iov;
 	int rc = 0;
 	int len;
 	int resp_buftype = CIFS_NO_BUFFER;
@@ -2364,6 +2780,7 @@
 	char *end_of_smb;
 	unsigned int output_size = CIFSMaxBufSize;
 	size_t info_buf_size;
+	int flags = 0;
 
 	if (ses && (ses->server))
 		server = ses->server;
@@ -2374,6 +2791,9 @@
 	if (rc)
 		return rc;
 
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
 	switch (srch_inf->info_level) {
 	case SMB_FIND_FILE_DIRECTORY_INFO:
 		req->FileInformationClass = FILE_DIRECTORY_INFORMATION;
@@ -2418,15 +2838,17 @@
 
 	inc_rfc1001_len(req, len - 1 /* Buffer */);
 
-	rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
-	rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
+	rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base;
 
 	if (rc) {
-		if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) {
+		if (rc == -ENODATA &&
+		    rsp->hdr.sync_hdr.Status == STATUS_NO_MORE_FILES) {
 			srch_inf->endOfSearch = true;
 			rc = 0;
-		}
-		cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
+		} else
+			cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
 		goto qdir_exit;
 	}
 
@@ -2478,11 +2900,13 @@
 	struct smb2_set_info_req *req;
 	struct smb2_set_info_rsp *rsp = NULL;
 	struct kvec *iov;
+	struct kvec rsp_iov;
 	int rc = 0;
 	int resp_buftype;
 	unsigned int i;
 	struct TCP_Server_Info *server;
 	struct cifs_ses *ses = tcon->ses;
+	int flags = 0;
 
 	if (ses && (ses->server))
 		server = ses->server;
@@ -2502,7 +2926,10 @@
 		return rc;
 	}
 
-	req->hdr.ProcessId = cpu_to_le32(pid);
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	req->hdr.sync_hdr.ProcessId = cpu_to_le32(pid);
 
 	req->InfoType = SMB2_O_INFO_FILE;
 	req->FileInfoClass = info_class;
@@ -2529,8 +2956,9 @@
 		iov[i].iov_len = size[i];
 	}
 
-	rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0);
-	rsp = (struct smb2_set_info_rsp *)iov[0].iov_base;
+	rc = SendReceive2(xid, ses, iov, num, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(req);
+	rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
 
 	if (rc != 0)
 		cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
@@ -2573,6 +3001,22 @@
 }
 
 int
+SMB2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
+		  u64 persistent_fid, u64 volatile_fid)
+{
+	__u8 delete_pending = 1;
+	void *data;
+	unsigned int size;
+
+	data = &delete_pending;
+	size = 1; /* sizeof __u8 */
+
+	return send_set_info(xid, tcon, persistent_fid, volatile_fid,
+			current->tgid, FILE_DISPOSITION_INFORMATION, 1, &data,
+			&size);
+}
+
+int
 SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 		  u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
 {
@@ -2642,20 +3086,23 @@
 {
 	int rc;
 	struct smb2_oplock_break *req = NULL;
+	int flags = CIFS_OBREAK_OP;
 
 	cifs_dbg(FYI, "SMB2_oplock_break\n");
 	rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
-
 	if (rc)
 		return rc;
 
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
 	req->VolatileFid = volatile_fid;
 	req->PersistentFid = persistent_fid;
 	req->OplockLevel = oplock_level;
-	req->hdr.CreditRequest = cpu_to_le16(1);
+	req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
 
-	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, CIFS_OBREAK_OP);
-	/* SMB2 buffer freed by function above */
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, flags);
+	cifs_small_buf_release(req);
 
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
@@ -2672,8 +3119,8 @@
 	kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
 			  le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
 	kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
-	kst->f_bfree  = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits);
-	kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
+	kst->f_bfree  = kst->f_bavail =
+			le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
 	return;
 }
 
@@ -2715,10 +3162,12 @@
 {
 	struct smb2_query_info_rsp *rsp = NULL;
 	struct kvec iov;
+	struct kvec rsp_iov;
 	int rc = 0;
 	int resp_buftype;
 	struct cifs_ses *ses = tcon->ses;
 	struct smb2_fs_full_size_info *info = NULL;
+	int flags = 0;
 
 	rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION,
 				sizeof(struct smb2_fs_full_size_info),
@@ -2726,12 +3175,16 @@
 	if (rc)
 		return rc;
 
-	rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(iov.iov_base);
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
 		goto qfsinf_exit;
 	}
-	rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+	rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
 	info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ +
 		le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
@@ -2742,7 +3195,7 @@
 		copy_fs_info_to_kstatfs(info, fsdata);
 
 qfsinf_exit:
-	free_rsp_buf(resp_buftype, iov.iov_base);
+	free_rsp_buf(resp_buftype, rsp_iov.iov_base);
 	return rc;
 }
 
@@ -2752,10 +3205,12 @@
 {
 	struct smb2_query_info_rsp *rsp = NULL;
 	struct kvec iov;
+	struct kvec rsp_iov;
 	int rc = 0;
 	int resp_buftype, max_len, min_len;
 	struct cifs_ses *ses = tcon->ses;
 	unsigned int rsp_len, offset;
+	int flags = 0;
 
 	if (level == FS_DEVICE_INFORMATION) {
 		max_len = sizeof(FILE_SYSTEM_DEVICE_INFO);
@@ -2776,12 +3231,16 @@
 	if (rc)
 		return rc;
 
-	rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
+	cifs_small_buf_release(iov.iov_base);
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
 		goto qfsattr_exit;
 	}
-	rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+	rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
 	rsp_len = le32_to_cpu(rsp->OutputBufferLength);
 	offset = le16_to_cpu(rsp->OutputBufferOffset);
@@ -2805,7 +3264,7 @@
 	}
 
 qfsattr_exit:
-	free_rsp_buf(resp_buftype, iov.iov_base);
+	free_rsp_buf(resp_buftype, rsp_iov.iov_base);
 	return rc;
 }
 
@@ -2817,8 +3276,10 @@
 	int rc = 0;
 	struct smb2_lock_req *req = NULL;
 	struct kvec iov[2];
+	struct kvec rsp_iov;
 	int resp_buf_type;
 	unsigned int count;
+	int flags = CIFS_NO_RESP;
 
 	cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
 
@@ -2826,7 +3287,10 @@
 	if (rc)
 		return rc;
 
-	req->hdr.ProcessId = cpu_to_le32(pid);
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	req->hdr.sync_hdr.ProcessId = cpu_to_le32(pid);
 	req->LockCount = cpu_to_le16(num_lock);
 
 	req->PersistentFileId = persist_fid;
@@ -2842,7 +3306,9 @@
 	iov[1].iov_len = count;
 
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
-	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
+	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, flags,
+			  &rsp_iov);
+	cifs_small_buf_release(req);
 	if (rc) {
 		cifs_dbg(FYI, "Send error in smb2_lockv = %d\n", rc);
 		cifs_stats_fail_inc(tcon, SMB2_LOCK_HE);
@@ -2874,22 +3340,25 @@
 {
 	int rc;
 	struct smb2_lease_ack *req = NULL;
+	int flags = CIFS_OBREAK_OP;
 
 	cifs_dbg(FYI, "SMB2_lease_break\n");
 	rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
-
 	if (rc)
 		return rc;
 
-	req->hdr.CreditRequest = cpu_to_le16(1);
+	if (encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
 	req->StructureSize = cpu_to_le16(36);
 	inc_rfc1001_len(req, 12);
 
 	memcpy(req->LeaseKey, lease_key, 16);
 	req->LeaseState = lease_state;
 
-	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, CIFS_OBREAK_OP);
-	/* SMB2 buffer freed by function above */
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, flags);
+	cifs_small_buf_release(req);
 
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
--- linux-4.4.0.orig/fs/cifs/smb2pdu.h
+++ linux-4.4.0/fs/cifs/smb2pdu.h
@@ -82,10 +82,11 @@
 
 #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 */
+/* 52 transform hdr + 64 hdr + 88 create rsp */
+#define MAX_SMB2_HDR_SIZE 204
 
 #define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe)
+#define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd)
 
 /*
  * SMB2 Header Definition
@@ -98,11 +99,8 @@
 
 #define SMB2_HEADER_STRUCTURE_SIZE cpu_to_le16(64)
 
-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' */
+struct smb2_sync_hdr {
+	__le32 ProtocolId;	/* 0xFE 'S' 'M' 'B' */
 	__le16 StructureSize;	/* 64 */
 	__le16 CreditCharge;	/* MBZ */
 	__le32 Status;		/* Error from server */
@@ -117,22 +115,36 @@
 	__u8   Signature[16];
 } __packed;
 
+struct smb2_sync_pdu {
+	struct smb2_sync_hdr sync_hdr;
+	__le16 StructureSize2; /* size of wct area (varies, request specific) */
+} __packed;
+
+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 */
+	struct smb2_sync_hdr sync_hdr;
+} __packed;
+
 struct smb2_pdu {
 	struct smb2_hdr hdr;
 	__le16 StructureSize2; /* size of wct area (varies, request specific) */
 } __packed;
 
+#define SMB3_AES128CMM_NONCE 11
+#define SMB3_AES128GCM_NONCE 12
+
 struct smb2_transform_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];	/* 0xFD 'S' 'M' 'B' */
+	__le32 ProtocolId;	/* 0xFD 'S' 'M' 'B' */
 	__u8   Signature[16];
-	__u8   Nonce[11];
-	__u8   Reserved[5];
+	__u8   Nonce[16];
 	__le32 OriginalMessageSize;
 	__u16  Reserved1;
-	__le16 EncryptionAlgorithm;
+	__le16 Flags; /* EncryptionAlgorithm */
 	__u64  SessionId;
 } __packed;
 
@@ -276,7 +288,7 @@
 	__le32 Channel;
 	__le16 SecurityBufferOffset;
 	__le16 SecurityBufferLength;
-	__le64 PreviousSessionId;
+	__u64 PreviousSessionId;
 	__u8   Buffer[1];	/* variable length GSS security buffer */
 } __packed;
 
@@ -812,8 +824,9 @@
 #define SMB2_CHANNEL_RDMA_V1		0x00000001 /* SMB3 or later */
 #define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */
 
-struct smb2_read_req {
-	struct smb2_hdr hdr;
+/* SMB2 read request without RFC1001 length at the beginning */
+struct smb2_read_plain_req {
+	struct smb2_sync_hdr sync_hdr;
 	__le16 StructureSize; /* Must be 49 */
 	__u8   Padding; /* offset from start of SMB2 header to place read */
 	__u8   Flags; /* MBZ unless SMB3.02 or later */
--- linux-4.4.0.orig/fs/cifs/smb2proto.h
+++ linux-4.4.0/fs/cifs/smb2proto.h
@@ -34,7 +34,8 @@
  *****************************************************************
  */
 extern int map_smb2_to_linux_error(char *buf, bool log_err);
-extern int smb2_check_message(char *buf, unsigned int length);
+extern int smb2_check_message(char *buf, unsigned int length,
+			      struct TCP_Server_Info *server);
 extern unsigned int smb2_calc_size(void *buf);
 extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr);
 extern __le16 *cifs_convert_path_to_utf16(const char *from,
@@ -47,6 +48,10 @@
 			      struct smb_rqst *rqst);
 extern struct mid_q_entry *smb2_setup_async_request(
 			struct TCP_Server_Info *server, struct smb_rqst *rqst);
+extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
+					   __u64 ses_id);
+extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
+						__u64 ses_id, __u32  tid);
 extern int smb2_calc_signature(struct smb_rqst *rqst,
 				struct TCP_Server_Info *server);
 extern int smb3_calc_signature(struct smb_rqst *rqst,
@@ -55,6 +60,10 @@
 extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
 extern bool smb2_is_valid_oplock_break(char *buffer,
 				       struct TCP_Server_Info *srv);
+extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
+					  __u64 ses_id);
+extern int smb3_handle_read_data(struct TCP_Server_Info *server,
+				 struct mid_q_entry *mid);
 
 extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
 				   struct smb2_file_all_info *src);
@@ -95,6 +104,8 @@
 extern int smb2_unlock_range(struct cifsFileInfo *cfile,
 			     struct file_lock *flock, const unsigned int xid);
 extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
+extern void smb2_reconnect_server(struct work_struct *work);
+extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
@@ -140,6 +151,8 @@
 extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
 		       u64 persistent_fid, u64 volatile_fid,
 		       __le16 *target_file);
+extern int SMB2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
+		      u64 persistent_fid, u64 volatile_fid);
 extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 			     u64 persistent_fid, u64 volatile_fid,
 			     __le16 *target_file);
@@ -154,6 +167,9 @@
 extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 			     const u64 persistent_fid, const u64 volatile_fid,
 			     const __u8 oplock_level);
+extern int smb2_handle_cancelled_mid(char *buffer,
+					struct TCP_Server_Info *server);
+void smb2_cancelled_close_fid(struct work_struct *work);
 extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
 			 u64 persistent_file_id, u64 volatile_file_id,
 			 struct kstatfs *FSData);
--- linux-4.4.0.orig/fs/cifs/smb2transport.c
+++ linux-4.4.0/fs/cifs/smb2transport.c
@@ -31,6 +31,7 @@
 #include <asm/processor.h>
 #include <linux/mempool.h>
 #include <linux/highmem.h>
+#include <crypto/aead.h>
 #include "smb2pdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -115,42 +116,87 @@
 }
 
 static struct cifs_ses *
-smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
+smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
 {
 	struct cifs_ses *ses;
 
-	spin_lock(&cifs_tcp_ses_lock);
 	list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
-		if (ses->Suid != smb2hdr->SessionId)
+		if (ses->Suid != ses_id)
 			continue;
-		spin_unlock(&cifs_tcp_ses_lock);
 		return ses;
 	}
+
+	return NULL;
+}
+
+struct cifs_ses *
+smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id)
+{
+	struct cifs_ses *ses;
+
+	spin_lock(&cifs_tcp_ses_lock);
+	ses = smb2_find_smb_ses_unlocked(server, ses_id);
 	spin_unlock(&cifs_tcp_ses_lock);
 
+	return ses;
+}
+
+static struct cifs_tcon *
+smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32  tid)
+{
+	struct cifs_tcon *tcon;
+
+	list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+		if (tcon->tid != tid)
+			continue;
+		++tcon->tc_count;
+		return tcon;
+	}
+
 	return NULL;
 }
 
+/*
+ * Obtain tcon corresponding to the tid in the given
+ * cifs_ses
+ */
+
+struct cifs_tcon *
+smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32  tid)
+{
+	struct cifs_ses *ses;
+	struct cifs_tcon *tcon;
+
+	spin_lock(&cifs_tcp_ses_lock);
+	ses = smb2_find_smb_ses_unlocked(server, ses_id);
+	if (!ses) {
+		spin_unlock(&cifs_tcp_ses_lock);
+		return NULL;
+	}
+	tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid);
+	spin_unlock(&cifs_tcp_ses_lock);
+
+	return tcon;
+}
 
 int
 smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
-	int i, rc;
+	int rc;
 	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
 	unsigned char *sigptr = smb2_signature;
 	struct kvec *iov = rqst->rq_iov;
-	int n_vec = rqst->rq_nvec;
-	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+	struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
 	struct cifs_ses *ses;
 
-	ses = smb2_find_smb_ses(smb2_pdu, server);
+	ses = smb2_find_smb_ses(server, shdr->SessionId);
 	if (!ses) {
 		cifs_dbg(VFS, "%s: Could not find session\n", __func__);
 		return 0;
 	}
 
 	memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
-	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+	memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
 	rc = smb2_crypto_shash_allocate(server);
 	if (rc) {
@@ -171,59 +217,17 @@
 		return rc;
 	}
 
-	for (i = 0; i < n_vec; i++) {
-		if (iov[i].iov_len == 0)
-			continue;
-		if (iov[i].iov_base == NULL) {
-			cifs_dbg(VFS, "null iovec entry\n");
-			return -EIO;
-		}
-		/*
-		 * The first entry includes a length field (which does not get
-		 * signed that occupies the first 4 bytes before the header).
-		 */
-		if (i == 0) {
-			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
-				break; /* nothing to sign or corrupt header */
-			rc =
-			crypto_shash_update(
-				&server->secmech.sdeschmacsha256->shash,
-				iov[i].iov_base + 4, iov[i].iov_len - 4);
-		} else {
-			rc =
-			crypto_shash_update(
-				&server->secmech.sdeschmacsha256->shash,
-				iov[i].iov_base, iov[i].iov_len);
-		}
-		if (rc) {
-			cifs_dbg(VFS, "%s: Could not update with payload\n",
-				 __func__);
-			return rc;
-		}
-	}
-
-	/* now hash over the rq_pages array */
-	for (i = 0; i < rqst->rq_npages; i++) {
-		struct kvec p_iov;
-
-		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
-		crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
-					p_iov.iov_base, p_iov.iov_len);
-		kunmap(rqst->rq_pages[i]);
-	}
-
-	rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
-				sigptr);
-	if (rc)
-		cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
+	rc = __cifs_calc_signature(rqst, server, sigptr,
+		&server->secmech.sdeschmacsha256->shash);
 
-	memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+	if (!rc)
+		memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 
 	return rc;
 }
 
-int
-generate_smb3signingkey(struct cifs_ses *ses)
+static int generate_key(struct cifs_ses *ses, struct kvec label,
+			struct kvec context, __u8 *key, unsigned int key_size)
 {
 	unsigned char zero = 0x0;
 	__u8 i[4] = {0, 0, 0, 1};
@@ -233,7 +237,7 @@
 	unsigned char *hashptr = prfhash;
 
 	memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
-	memset(ses->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
+	memset(key, 0x0, key_size);
 
 	rc = smb3_crypto_shash_allocate(ses->server);
 	if (rc) {
@@ -262,7 +266,7 @@
 	}
 
 	rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
-				"SMB2AESCMAC", 12);
+				label.iov_base, label.iov_len);
 	if (rc) {
 		cifs_dbg(VFS, "%s: Could not update with label\n", __func__);
 		goto smb3signkey_ret;
@@ -276,7 +280,7 @@
 	}
 
 	rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
-				"SmbSign", 8);
+				context.iov_base, context.iov_len);
 	if (rc) {
 		cifs_dbg(VFS, "%s: Could not update with context\n", __func__);
 		goto smb3signkey_ret;
@@ -296,32 +300,120 @@
 		goto smb3signkey_ret;
 	}
 
-	memcpy(ses->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE);
+	memcpy(key, hashptr, key_size);
 
 smb3signkey_ret:
 	return rc;
 }
 
+struct derivation {
+	struct kvec label;
+	struct kvec context;
+};
+
+struct derivation_triplet {
+	struct derivation signing;
+	struct derivation encryption;
+	struct derivation decryption;
+};
+
+static int
+generate_smb3signingkey(struct cifs_ses *ses,
+			const struct derivation_triplet *ptriplet)
+{
+	int rc;
+
+	rc = generate_key(ses, ptriplet->signing.label,
+			  ptriplet->signing.context, ses->smb3signingkey,
+			  SMB3_SIGN_KEY_SIZE);
+	if (rc)
+		return rc;
+
+	rc = generate_key(ses, ptriplet->encryption.label,
+			  ptriplet->encryption.context, ses->smb3encryptionkey,
+			  SMB3_SIGN_KEY_SIZE);
+	if (rc)
+		return rc;
+
+	return generate_key(ses, ptriplet->decryption.label,
+			    ptriplet->decryption.context,
+			    ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
+}
+
+int
+generate_smb30signingkey(struct cifs_ses *ses)
+
+{
+	struct derivation_triplet triplet;
+	struct derivation *d;
+
+	d = &triplet.signing;
+	d->label.iov_base = "SMB2AESCMAC";
+	d->label.iov_len = 12;
+	d->context.iov_base = "SmbSign";
+	d->context.iov_len = 8;
+
+	d = &triplet.encryption;
+	d->label.iov_base = "SMB2AESCCM";
+	d->label.iov_len = 11;
+	d->context.iov_base = "ServerIn ";
+	d->context.iov_len = 10;
+
+	d = &triplet.decryption;
+	d->label.iov_base = "SMB2AESCCM";
+	d->label.iov_len = 11;
+	d->context.iov_base = "ServerOut";
+	d->context.iov_len = 10;
+
+	return generate_smb3signingkey(ses, &triplet);
+}
+
+int
+generate_smb311signingkey(struct cifs_ses *ses)
+
+{
+	struct derivation_triplet triplet;
+	struct derivation *d;
+
+	d = &triplet.signing;
+	d->label.iov_base = "SMB2AESCMAC";
+	d->label.iov_len = 12;
+	d->context.iov_base = "SmbSign";
+	d->context.iov_len = 8;
+
+	d = &triplet.encryption;
+	d->label.iov_base = "SMB2AESCCM";
+	d->label.iov_len = 11;
+	d->context.iov_base = "ServerIn ";
+	d->context.iov_len = 10;
+
+	d = &triplet.decryption;
+	d->label.iov_base = "SMB2AESCCM";
+	d->label.iov_len = 11;
+	d->context.iov_base = "ServerOut";
+	d->context.iov_len = 10;
+
+	return generate_smb3signingkey(ses, &triplet);
+}
+
 int
 smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
-	int i;
 	int rc = 0;
 	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
 	unsigned char *sigptr = smb3_signature;
 	struct kvec *iov = rqst->rq_iov;
-	int n_vec = rqst->rq_nvec;
-	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+	struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
 	struct cifs_ses *ses;
 
-	ses = smb2_find_smb_ses(smb2_pdu, server);
+	ses = smb2_find_smb_ses(server, shdr->SessionId);
 	if (!ses) {
 		cifs_dbg(VFS, "%s: Could not find session\n", __func__);
 		return 0;
 	}
 
 	memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
-	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+	memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
 	rc = crypto_shash_setkey(server->secmech.cmacaes,
 		ses->smb3signingkey, SMB2_CMACAES_SIZE);
@@ -341,54 +433,12 @@
 		cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
 		return rc;
 	}
+	
+	rc = __cifs_calc_signature(rqst, server, sigptr,
+				   &server->secmech.sdesccmacaes->shash);
 
-	for (i = 0; i < n_vec; i++) {
-		if (iov[i].iov_len == 0)
-			continue;
-		if (iov[i].iov_base == NULL) {
-			cifs_dbg(VFS, "null iovec entry");
-			return -EIO;
-		}
-		/*
-		 * The first entry includes a length field (which does not get
-		 * signed that occupies the first 4 bytes before the header).
-		 */
-		if (i == 0) {
-			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
-				break; /* nothing to sign or corrupt header */
-			rc =
-			crypto_shash_update(
-				&server->secmech.sdesccmacaes->shash,
-				iov[i].iov_base + 4, iov[i].iov_len - 4);
-		} else {
-			rc =
-			crypto_shash_update(
-				&server->secmech.sdesccmacaes->shash,
-				iov[i].iov_base, iov[i].iov_len);
-		}
-		if (rc) {
-			cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n",
-							__func__);
-			return rc;
-		}
-	}
-
-	/* now hash over the rq_pages array */
-	for (i = 0; i < rqst->rq_npages; i++) {
-		struct kvec p_iov;
-
-		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
-		crypto_shash_update(&server->secmech.sdesccmacaes->shash,
-					p_iov.iov_base, p_iov.iov_len);
-		kunmap(rqst->rq_pages[i]);
-	}
-
-	rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash,
-						sigptr);
-	if (rc)
-		cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__);
-
-	memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+	if (!rc)
+		memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 
 	return rc;
 }
@@ -398,14 +448,15 @@
 smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
 	int rc = 0;
-	struct smb2_hdr *smb2_pdu = rqst->rq_iov[0].iov_base;
+	struct smb2_sync_hdr *shdr =
+			(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 
-	if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) ||
+	if (!(shdr->Flags & SMB2_FLAGS_SIGNED) ||
 	    server->tcpStatus == CifsNeedNegotiate)
 		return rc;
 
 	if (!server->session_estab) {
-		strncpy(smb2_pdu->Signature, "BSRSPYL", 8);
+		strncpy(shdr->Signature, "BSRSPYL", 8);
 		return rc;
 	}
 
@@ -419,11 +470,12 @@
 {
 	unsigned int rc;
 	char server_response_sig[16];
-	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
+	struct smb2_sync_hdr *shdr =
+			(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 
-	if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
-	    (smb2_pdu->Command == SMB2_SESSION_SETUP) ||
-	    (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
+	if ((shdr->Command == SMB2_NEGOTIATE) ||
+	    (shdr->Command == SMB2_SESSION_SETUP) ||
+	    (shdr->Command == SMB2_OPLOCK_BREAK) ||
 	    (!server->session_estab))
 		return 0;
 
@@ -433,17 +485,17 @@
 	 */
 
 	/* Do not need to verify session setups with signature "BSRSPYL " */
-	if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0)
+	if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0)
 		cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
-			 smb2_pdu->Command);
+			 shdr->Command);
 
 	/*
 	 * Save off the origiginal signature so we can modify the smb and check
 	 * our calculated signature against what the server sent.
 	 */
-	memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE);
+	memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE);
 
-	memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE);
+	memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
 	mutex_lock(&server->srv_mutex);
 	rc = server->ops->calc_signature(rqst, server);
@@ -452,8 +504,7 @@
 	if (rc)
 		return rc;
 
-	if (memcmp(server_response_sig, smb2_pdu->Signature,
-		   SMB2_SIGNATURE_SIZE))
+	if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE))
 		return -EACCES;
 	else
 		return 0;
@@ -464,18 +515,19 @@
  * and when srv_mutex is held.
  */
 static inline void
-smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
+smb2_seq_num_into_buf(struct TCP_Server_Info *server,
+		      struct smb2_sync_hdr *shdr)
 {
-	unsigned int i, num = le16_to_cpu(hdr->CreditCharge);
+	unsigned int i, num = le16_to_cpu(shdr->CreditCharge);
 
-	hdr->MessageId = get_next_mid64(server);
+	shdr->MessageId = get_next_mid64(server);
 	/* skip message numbers according to CreditCharge field */
 	for (i = 1; i < num; i++)
 		get_next_mid(server);
 }
 
 static struct mid_q_entry *
-smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
+smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
 		     struct TCP_Server_Info *server)
 {
 	struct mid_q_entry *temp;
@@ -490,9 +542,9 @@
 		return temp;
 	else {
 		memset(temp, 0, sizeof(struct mid_q_entry));
-		temp->mid = le64_to_cpu(smb_buffer->MessageId);
+		temp->mid = le64_to_cpu(shdr->MessageId);
 		temp->pid = current->pid;
-		temp->command = smb_buffer->Command;	/* Always LE */
+		temp->command = shdr->Command; /* Always LE */
 		temp->when_alloc = jiffies;
 		temp->server = server;
 
@@ -510,7 +562,7 @@
 }
 
 static int
-smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
+smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr,
 		   struct mid_q_entry **mid)
 {
 	if (ses->server->tcpStatus == CifsExiting)
@@ -522,19 +574,19 @@
 	}
 
 	if (ses->status == CifsNew) {
-		if ((buf->Command != SMB2_SESSION_SETUP) &&
-		    (buf->Command != SMB2_NEGOTIATE))
+		if ((shdr->Command != SMB2_SESSION_SETUP) &&
+		    (shdr->Command != SMB2_NEGOTIATE))
 			return -EAGAIN;
 		/* else ok - we are setting up session */
 	}
 
 	if (ses->status == CifsExiting) {
-		if (buf->Command != SMB2_LOGOFF)
+		if (shdr->Command != SMB2_LOGOFF)
 			return -EAGAIN;
 		/* else ok - we are shutting down the session */
 	}
 
-	*mid = smb2_mid_entry_alloc(buf, ses->server);
+	*mid = smb2_mid_entry_alloc(shdr, ses->server);
 	if (*mid == NULL)
 		return -ENOMEM;
 	spin_lock(&GlobalMid_Lock);
@@ -548,16 +600,18 @@
 		   bool log_error)
 {
 	unsigned int len = get_rfc1002_length(mid->resp_buf);
-	struct kvec iov;
-	struct smb_rqst rqst = { .rq_iov = &iov,
-				 .rq_nvec = 1 };
-
-	iov.iov_base = (char *)mid->resp_buf;
-	iov.iov_len = get_rfc1002_length(mid->resp_buf) + 4;
+	struct kvec iov[2];
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = 2 };
+
+	iov[0].iov_base = (char *)mid->resp_buf;
+	iov[0].iov_len = 4;
+	iov[1].iov_base = (char *)mid->resp_buf + 4;
+	iov[1].iov_len = len;
 
 	dump_smb(mid->resp_buf, min_t(u32, 80, len));
 	/* convert the length into a more usable form */
-	if (len > 24 && server->sign) {
+	if (len > 24 && server->sign && !mid->decrypted) {
 		int rc;
 
 		rc = smb2_verify_signature(&rqst, server);
@@ -573,12 +627,13 @@
 smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 {
 	int rc;
-	struct smb2_hdr *hdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
+	struct smb2_sync_hdr *shdr =
+			(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 	struct mid_q_entry *mid;
 
-	smb2_seq_num_into_buf(ses->server, hdr);
+	smb2_seq_num_into_buf(ses->server, shdr);
 
-	rc = smb2_get_mid_entry(ses, hdr, &mid);
+	rc = smb2_get_mid_entry(ses, shdr, &mid);
 	if (rc)
 		return ERR_PTR(rc);
 	rc = smb2_sign_rqst(rqst, ses->server);
@@ -593,12 +648,13 @@
 smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
 	int rc;
-	struct smb2_hdr *hdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
+	struct smb2_sync_hdr *shdr =
+			(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 	struct mid_q_entry *mid;
 
-	smb2_seq_num_into_buf(server, hdr);
+	smb2_seq_num_into_buf(server, shdr);
 
-	mid = smb2_mid_entry_alloc(hdr, server);
+	mid = smb2_mid_entry_alloc(shdr, server);
 	if (mid == NULL)
 		return ERR_PTR(-ENOMEM);
 
@@ -610,3 +666,33 @@
 
 	return mid;
 }
+
+int
+smb3_crypto_aead_allocate(struct TCP_Server_Info *server)
+{
+	struct crypto_aead *tfm;
+
+	if (!server->secmech.ccmaesencrypt) {
+		tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
+		if (IS_ERR(tfm)) {
+			cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n",
+				 __func__);
+			return PTR_ERR(tfm);
+		}
+		server->secmech.ccmaesencrypt = tfm;
+	}
+
+	if (!server->secmech.ccmaesdecrypt) {
+		tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
+		if (IS_ERR(tfm)) {
+			crypto_free_aead(server->secmech.ccmaesencrypt);
+			server->secmech.ccmaesencrypt = NULL;
+			cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n",
+				 __func__);
+			return PTR_ERR(tfm);
+		}
+		server->secmech.ccmaesdecrypt = tfm;
+	}
+
+	return 0;
+}
--- linux-4.4.0.orig/fs/cifs/transport.c
+++ linux-4.4.0/fs/cifs/transport.c
@@ -291,7 +291,7 @@
 }
 
 static int
-smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+__smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
 	int rc;
 	struct kvec *iov = rqst->rq_iov;
@@ -314,8 +314,12 @@
 		return -EIO;
 	}
 
+	if (n_vec < 2)
+		return -EIO;
+
 	cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
 	dump_smb(iov[0].iov_base, iov[0].iov_len);
+	dump_smb(iov[1].iov_base, iov[1].iov_len);
 
 	/* cork the socket */
 	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
@@ -360,31 +364,50 @@
 	if (rc < 0 && rc != -EINTR)
 		cifs_dbg(VFS, "Error %d sending data on socket to server\n",
 			 rc);
-	else
+	else if (rc > 0)
 		rc = 0;
 
 	return rc;
 }
 
 static int
-smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
+smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
 {
-	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = n_vec };
+	struct smb_rqst cur_rqst;
+	int rc;
+
+	if (!(flags & CIFS_TRANSFORM_REQ))
+		return __smb_send_rqst(server, rqst);
 
-	return smb_send_rqst(server, &rqst);
+	if (!server->ops->init_transform_rq ||
+	    !server->ops->free_transform_rq) {
+		cifs_dbg(VFS, "Encryption requested but transform callbacks are missed\n");
+		return -EIO;
+	}
+
+	rc = server->ops->init_transform_rq(server, &cur_rqst, rqst);
+	if (rc)
+		return rc;
+
+	rc = __smb_send_rqst(server, &cur_rqst);
+	server->ops->free_transform_rq(&cur_rqst);
+	return rc;
 }
 
 int
 smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 	 unsigned int smb_buf_length)
 {
-	struct kvec iov;
+	struct kvec iov[2];
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = 2 };
 
-	iov.iov_base = smb_buffer;
-	iov.iov_len = smb_buf_length + 4;
+	iov[0].iov_base = smb_buffer;
+	iov[0].iov_len = 4;
+	iov[1].iov_base = (char *)smb_buffer + 4;
+	iov[1].iov_len = smb_buf_length;
 
-	return smb_sendv(server, &iov, 1);
+	return __smb_send_rqst(server, &rqst);
 }
 
 static int
@@ -512,6 +535,10 @@
 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 	struct mid_q_entry *mid;
 
+	if (rqst->rq_iov[0].iov_len != 4 ||
+	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+		return ERR_PTR(-EIO);
+
 	/* enable signing if server requires it */
 	if (server->sign)
 		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@@ -536,7 +563,7 @@
 int
 cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 		mid_receive_t *receive, mid_callback_t *callback,
-		void *cbdata, const int flags)
+		mid_handle_t *handle, void *cbdata, const int flags)
 {
 	int rc, timeout, optype;
 	struct mid_q_entry *mid;
@@ -563,6 +590,7 @@
 	mid->receive = receive;
 	mid->callback = callback;
 	mid->callback_data = cbdata;
+	mid->handle = handle;
 	mid->mid_state = MID_REQUEST_SUBMITTED;
 
 	/* put it on the pending_mid_q */
@@ -572,18 +600,20 @@
 
 
 	cifs_in_send_inc(server);
-	rc = smb_send_rqst(server, rqst);
+	rc = smb_send_rqst(server, rqst, flags);
 	cifs_in_send_dec(server);
 	cifs_save_when_sent(mid);
 
-	if (rc < 0)
+	if (rc < 0) {
 		server->sequence_number -= 2;
+		cifs_delete_mid(mid);
+	}
+
 	mutex_unlock(&server->srv_mutex);
 
 	if (rc == 0)
 		return 0;
 
-	cifs_delete_mid(mid);
 	add_credits_and_wake_if(server, credits, optype);
 	return rc;
 }
@@ -603,12 +633,13 @@
 {
 	int rc;
 	struct kvec iov[1];
+	struct kvec rsp_iov;
 	int resp_buf_type;
 
 	iov[0].iov_base = in_buf;
 	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
 	flags |= CIFS_NO_RESP;
-	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
 	cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
 
 	return rc;
@@ -651,10 +682,11 @@
 }
 
 static inline int
-send_cancel(struct TCP_Server_Info *server, void *buf, struct mid_q_entry *mid)
+send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
+	    struct mid_q_entry *mid)
 {
 	return server->ops->send_cancel ?
-				server->ops->send_cancel(server, buf, mid) : 0;
+				server->ops->send_cancel(server, rqst, mid) : 0;
 }
 
 int
@@ -667,13 +699,15 @@
 
 	/* convert the length into a more usable form */
 	if (server->sign) {
-		struct kvec iov;
+		struct kvec iov[2];
 		int rc = 0;
-		struct smb_rqst rqst = { .rq_iov = &iov,
-					 .rq_nvec = 1 };
+		struct smb_rqst rqst = { .rq_iov = iov,
+					 .rq_nvec = 2 };
 
-		iov.iov_base = mid->resp_buf;
-		iov.iov_len = len;
+		iov[0].iov_base = mid->resp_buf;
+		iov[0].iov_len = 4;
+		iov[1].iov_base = (char *)mid->resp_buf + 4;
+		iov[1].iov_len = len - 4;
 		/* FIXME: add code to kill session */
 		rc = cifs_verify_signature(&rqst, server,
 					   mid->sequence_number);
@@ -693,6 +727,10 @@
 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 	struct mid_q_entry *mid;
 
+	if (rqst->rq_iov[0].iov_len != 4 ||
+	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+		return ERR_PTR(-EIO);
+
 	rc = allocate_mid(ses, hdr, &mid);
 	if (rc)
 		return ERR_PTR(rc);
@@ -705,17 +743,15 @@
 }
 
 int
-SendReceive2(const unsigned int xid, struct cifs_ses *ses,
-	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
-	     const int flags)
+cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
+	       struct smb_rqst *rqst, int *resp_buf_type, const int flags,
+	       struct kvec *resp_iov)
 {
 	int rc = 0;
 	int timeout, optype;
 	struct mid_q_entry *midQ;
-	char *buf = iov[0].iov_base;
 	unsigned int credits = 1;
-	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = n_vec };
+	char *buf;
 
 	timeout = flags & CIFS_TIMEOUT_MASK;
 	optype = flags & CIFS_OP_MASK;
@@ -723,15 +759,12 @@
 	*resp_buf_type = CIFS_NO_BUFFER;  /* no response buf yet */
 
 	if ((ses == NULL) || (ses->server == NULL)) {
-		cifs_small_buf_release(buf);
 		cifs_dbg(VFS, "Null session\n");
 		return -EIO;
 	}
 
-	if (ses->server->tcpStatus == CifsExiting) {
-		cifs_small_buf_release(buf);
+	if (ses->server->tcpStatus == CifsExiting)
 		return -ENOENT;
-	}
 
 	/*
 	 * Ensure that we do not send more than 50 overlapping requests
@@ -740,10 +773,8 @@
 	 */
 
 	rc = wait_for_free_request(ses->server, timeout, optype);
-	if (rc) {
-		cifs_small_buf_release(buf);
+	if (rc)
 		return rc;
-	}
 
 	/*
 	 * Make sure that we sign in the same order that we send on this socket
@@ -753,10 +784,9 @@
 
 	mutex_lock(&ses->server->srv_mutex);
 
-	midQ = ses->server->ops->setup_request(ses, &rqst);
+	midQ = ses->server->ops->setup_request(ses, rqst);
 	if (IS_ERR(midQ)) {
 		mutex_unlock(&ses->server->srv_mutex);
-		cifs_small_buf_release(buf);
 		/* Update # of requests on wire to server */
 		add_credits(ses->server, 1, optype);
 		return PTR_ERR(midQ);
@@ -764,7 +794,7 @@
 
 	midQ->mid_state = MID_REQUEST_SUBMITTED;
 	cifs_in_send_inc(ses->server);
-	rc = smb_sendv(ses->server, iov, n_vec);
+	rc = smb_send_rqst(ses->server, rqst, flags);
 	cifs_in_send_dec(ses->server);
 	cifs_save_when_sent(midQ);
 
@@ -772,32 +802,27 @@
 		ses->server->sequence_number -= 2;
 	mutex_unlock(&ses->server->srv_mutex);
 
-	if (rc < 0) {
-		cifs_small_buf_release(buf);
+	if (rc < 0)
 		goto out;
-	}
 
-	if (timeout == CIFS_ASYNC_OP) {
-		cifs_small_buf_release(buf);
+	if (timeout == CIFS_ASYNC_OP)
 		goto out;
-	}
 
 	rc = wait_for_response(ses->server, midQ);
 	if (rc != 0) {
-		send_cancel(ses->server, buf, midQ);
+		cifs_dbg(FYI, "Cancelling wait for mid %llu\n",	midQ->mid);
+		send_cancel(ses->server, rqst, midQ);
 		spin_lock(&GlobalMid_Lock);
 		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
+			midQ->mid_flags |= MID_WAIT_CANCELLED;
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
-			cifs_small_buf_release(buf);
 			add_credits(ses->server, 1, optype);
 			return rc;
 		}
 		spin_unlock(&GlobalMid_Lock);
 	}
 
-	cifs_small_buf_release(buf);
-
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
 		add_credits(ses->server, 1, optype);
@@ -811,8 +836,8 @@
 	}
 
 	buf = (char *)midQ->resp_buf;
-	iov[0].iov_base = buf;
-	iov[0].iov_len = get_rfc1002_length(buf) + 4;
+	resp_iov->iov_base = buf;
+	resp_iov->iov_len = get_rfc1002_length(buf) + 4;
 	if (midQ->large_buf)
 		*resp_buf_type = CIFS_LARGE_BUFFER;
 	else
@@ -834,12 +859,45 @@
 }
 
 int
+SendReceive2(const unsigned int xid, struct cifs_ses *ses,
+	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
+	     const int flags, struct kvec *resp_iov)
+{
+	struct smb_rqst rqst;
+	struct kvec *new_iov;
+	int rc;
+
+	new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), GFP_KERNEL);
+	if (!new_iov)
+		return -ENOMEM;
+
+	/* 1st iov is a RFC1001 length followed by the rest of the packet */
+	memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
+
+	new_iov[0].iov_base = new_iov[1].iov_base;
+	new_iov[0].iov_len = 4;
+	new_iov[1].iov_base += 4;
+	new_iov[1].iov_len -= 4;
+
+	memset(&rqst, 0, sizeof(struct smb_rqst));
+	rqst.rq_iov = new_iov;
+	rqst.rq_nvec = n_vec + 1;
+
+	rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
+	kfree(new_iov);
+	return rc;
+}
+
+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 timeout)
 {
 	int rc = 0;
 	struct mid_q_entry *midQ;
+	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
+	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
 
 	if (ses == NULL) {
 		cifs_dbg(VFS, "Null smb session\n");
@@ -857,10 +915,9 @@
 	   to the same server. We may make this configurable later or
 	   use ses->maxReq */
 
-	if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
-			MAX_CIFS_HDR_SIZE - 4) {
+	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
 		cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
-			 be32_to_cpu(in_buf->smb_buf_length));
+			 len);
 		return -EIO;
 	}
 
@@ -891,7 +948,7 @@
 	midQ->mid_state = MID_REQUEST_SUBMITTED;
 
 	cifs_in_send_inc(ses->server);
-	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
+	rc = smb_send(ses->server, in_buf, len);
 	cifs_in_send_dec(ses->server);
 	cifs_save_when_sent(midQ);
 
@@ -908,7 +965,7 @@
 
 	rc = wait_for_response(ses->server, midQ);
 	if (rc != 0) {
-		send_cancel(ses->server, in_buf, midQ);
+		send_cancel(ses->server, &rqst, midQ);
 		spin_lock(&GlobalMid_Lock);
 		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 			/* no longer considered to be "in-flight" */
@@ -977,6 +1034,9 @@
 	int rstart = 0;
 	struct mid_q_entry *midQ;
 	struct cifs_ses *ses;
+	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
+	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
 
 	if (tcon == NULL || tcon->ses == NULL) {
 		cifs_dbg(VFS, "Null smb session\n");
@@ -996,10 +1056,9 @@
 	   to the same server. We may make this configurable later or
 	   use ses->maxReq */
 
-	if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
-			MAX_CIFS_HDR_SIZE - 4) {
+	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
 		cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
-			 be32_to_cpu(in_buf->smb_buf_length));
+			 len);
 		return -EIO;
 	}
 
@@ -1028,7 +1087,7 @@
 
 	midQ->mid_state = MID_REQUEST_SUBMITTED;
 	cifs_in_send_inc(ses->server);
-	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
+	rc = smb_send(ses->server, in_buf, len);
 	cifs_in_send_dec(ses->server);
 	cifs_save_when_sent(midQ);
 
@@ -1057,7 +1116,7 @@
 		if (in_buf->Command == SMB_COM_TRANSACTION2) {
 			/* POSIX lock. We send a NT_CANCEL SMB to cause the
 			   blocking lock to return. */
-			rc = send_cancel(ses->server, in_buf, midQ);
+			rc = send_cancel(ses->server, &rqst, midQ);
 			if (rc) {
 				cifs_delete_mid(midQ);
 				return rc;
@@ -1078,7 +1137,7 @@
 
 		rc = wait_for_response(ses->server, midQ);
 		if (rc) {
-			send_cancel(ses->server, in_buf, midQ);
+			send_cancel(ses->server, &rqst, midQ);
 			spin_lock(&GlobalMid_Lock);
 			if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 				/* no longer considered to be "in-flight" */
--- linux-4.4.0.orig/fs/coda/file.c
+++ linux-4.4.0/fs/coda/file.c
@@ -81,6 +81,41 @@
 	return ret;
 }
 
+struct coda_vm_ops {
+	atomic_t refcnt;
+	struct file *coda_file;
+	const struct vm_operations_struct *host_vm_ops;
+	struct vm_operations_struct vm_ops;
+};
+
+static void
+coda_vm_open(struct vm_area_struct *vma)
+{
+	struct coda_vm_ops *cvm_ops =
+		container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
+
+	atomic_inc(&cvm_ops->refcnt);
+
+	if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->open)
+		cvm_ops->host_vm_ops->open(vma);
+}
+
+static void
+coda_vm_close(struct vm_area_struct *vma)
+{
+	struct coda_vm_ops *cvm_ops =
+		container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
+
+	if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->close)
+		cvm_ops->host_vm_ops->close(vma);
+
+	if (atomic_dec_and_test(&cvm_ops->refcnt)) {
+		vma->vm_ops = cvm_ops->host_vm_ops;
+		fput(cvm_ops->coda_file);
+		kfree(cvm_ops);
+	}
+}
+
 static int
 coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 {
@@ -88,6 +123,8 @@
 	struct coda_inode_info *cii;
 	struct file *host_file;
 	struct inode *coda_inode, *host_inode;
+	struct coda_vm_ops *cvm_ops;
+	int ret;
 
 	cfi = CODA_FTOC(coda_file);
 	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
@@ -96,6 +133,13 @@
 	if (!host_file->f_op->mmap)
 		return -ENODEV;
 
+	if (WARN_ON(coda_file != vma->vm_file))
+		return -EIO;
+
+	cvm_ops = kmalloc(sizeof(struct coda_vm_ops), GFP_KERNEL);
+	if (!cvm_ops)
+		return -ENOMEM;
+
 	coda_inode = file_inode(coda_file);
 	host_inode = file_inode(host_file);
 
@@ -109,6 +153,7 @@
 	 * the container file on us! */
 	else if (coda_inode->i_mapping != host_inode->i_mapping) {
 		spin_unlock(&cii->c_lock);
+		kfree(cvm_ops);
 		return -EBUSY;
 	}
 
@@ -117,7 +162,29 @@
 	cfi->cfi_mapcount++;
 	spin_unlock(&cii->c_lock);
 
-	return host_file->f_op->mmap(host_file, vma);
+	vma->vm_file = get_file(host_file);
+	ret = host_file->f_op->mmap(host_file, vma);
+
+	if (ret) {
+		/* if call_mmap fails, our caller will put coda_file so we
+		 * should drop the reference to the host_file that we got.
+		 */
+		fput(host_file);
+		kfree(cvm_ops);
+	} else {
+		/* here we add redirects for the open/close vm_operations */
+		cvm_ops->host_vm_ops = vma->vm_ops;
+		if (vma->vm_ops)
+			cvm_ops->vm_ops = *vma->vm_ops;
+
+		cvm_ops->vm_ops.open = coda_vm_open;
+		cvm_ops->vm_ops.close = coda_vm_close;
+		cvm_ops->coda_file = coda_file;
+		atomic_set(&cvm_ops->refcnt, 1);
+
+		vma->vm_ops = &cvm_ops->vm_ops;
+	}
+	return ret;
 }
 
 int coda_open(struct inode *coda_inode, struct file *coda_file)
--- linux-4.4.0.orig/fs/coda/psdev.c
+++ linux-4.4.0/fs/coda/psdev.c
@@ -187,8 +187,11 @@
 	if (req->uc_opcode == CODA_OPEN_BY_FD) {
 		struct coda_open_by_fd_out *outp =
 			(struct coda_open_by_fd_out *)req->uc_data;
-		if (!outp->oh.result)
+		if (!outp->oh.result) {
 			outp->fh = fget(outp->fd);
+			if (!outp->fh)
+				return -EBADF;
+		}
 	}
 
         wake_up(&req->uc_sleep);
--- linux-4.4.0.orig/fs/coda/upcall.c
+++ linux-4.4.0/fs/coda/upcall.c
@@ -446,8 +446,7 @@
 	UPARG(CODA_FSYNC);
 
 	inp->coda_fsync.VFid = *fid;
-	error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
-			    &outsize, inp);
+	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
 	CODA_FREE(inp, insize);
 	return error;
--- linux-4.4.0.orig/fs/compat_binfmt_elf.c
+++ linux-4.4.0/fs/compat_binfmt_elf.c
@@ -51,6 +51,7 @@
 #define elf_prstatus	compat_elf_prstatus
 #define elf_prpsinfo	compat_elf_prpsinfo
 
+#ifdef CONFIG_ELF_CORE
 /*
  * Compat version of cputime_to_compat_timeval, perhaps this
  * should be an inline in <linux/compat.h>.
@@ -63,6 +64,7 @@
 	value->tv_sec = tv.tv_sec;
 	value->tv_usec = tv.tv_usec;
 }
+#endif
 
 #undef cputime_to_timeval
 #define cputime_to_timeval cputime_to_compat_timeval
--- linux-4.4.0.orig/fs/compat_ioctl.c
+++ linux-4.4.0/fs/compat_ioctl.c
@@ -811,7 +811,7 @@
  */
 #define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
 
-#define COMPATIBLE_IOCTL(cmd) XFORM(cmd),
+#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
 /* ioctl should not be warned about even if it's not implemented.
    Valid reasons to use this:
    - It is implemented with ->compat_ioctl on some device, but programs
@@ -1016,9 +1016,6 @@
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
 COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
-/* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD)
-COMPATIBLE_IOCTL(PPPOEIOCDFWD)
 /* ppdev */
 COMPATIBLE_IOCTL(PPSETMODE)
 COMPATIBLE_IOCTL(PPRSTATUS)
--- linux-4.4.0.orig/fs/configfs/dir.c
+++ linux-4.4.0/fs/configfs/dir.c
@@ -58,15 +58,13 @@
 	if (sd) {
 		/* Coordinate with configfs_readdir */
 		spin_lock(&configfs_dirent_lock);
-		/* Coordinate with configfs_attach_attr where will increase
-		 * sd->s_count and update sd->s_dentry to new allocated one.
-		 * Only set sd->dentry to null when this dentry is the only
-		 * sd owner.
-		 * If not do so, configfs_d_iput may run just after
-		 * configfs_attach_attr and set sd->s_dentry to null
-		 * even it's still in use.
+		/*
+		 * Set sd->s_dentry to null only when this dentry is the one
+		 * that is going to be killed.  Otherwise configfs_d_iput may
+		 * run just after configfs_attach_attr and set sd->s_dentry to
+		 * NULL even it's still in use.
 		 */
-		if (atomic_read(&sd->s_count) <= 2)
+		if (sd->s_dentry == dentry)
 			sd->s_dentry = NULL;
 
 		spin_unlock(&configfs_dirent_lock);
--- linux-4.4.0.orig/fs/configfs/symlink.c
+++ linux-4.4.0/fs/configfs/symlink.c
@@ -64,7 +64,7 @@
 
 		/* back up enough to print this bus id with '/' */
 		length -= cur;
-		strncpy(buffer + length,config_item_name(p),cur);
+		memcpy(buffer + length, config_item_name(p), cur);
 		*(buffer + --length) = '/';
 	}
 }
@@ -83,14 +83,13 @@
 	ret = -ENOMEM;
 	sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL);
 	if (sl) {
-		sl->sl_target = config_item_get(item);
 		spin_lock(&configfs_dirent_lock);
 		if (target_sd->s_type & CONFIGFS_USET_DROPPING) {
 			spin_unlock(&configfs_dirent_lock);
-			config_item_put(item);
 			kfree(sl);
 			return -ENOENT;
 		}
+		sl->sl_target = config_item_get(item);
 		list_add(&sl->sl_list, &target_sd->s_links);
 		spin_unlock(&configfs_dirent_lock);
 		ret = configfs_create_link(sl, parent_item->ci_dentry,
@@ -158,11 +157,42 @@
 	    !type->ct_item_ops->allow_link)
 		goto out_put;
 
+	/*
+	 * This is really sick.  What they wanted was a hybrid of
+	 * link(2) and symlink(2) - they wanted the target resolved
+	 * at syscall time (as link(2) would've done), be a directory
+	 * (which link(2) would've refused to do) *AND* be a deep
+	 * fucking magic, making the target busy from rmdir POV.
+	 * symlink(2) is nothing of that sort, and the locking it
+	 * gets matches the normal symlink(2) semantics.  Without
+	 * attempts to resolve the target (which might very well
+	 * not even exist yet) done prior to locking the parent
+	 * directory.  This perversion, OTOH, needs to resolve
+	 * the target, which would lead to obvious deadlocks if
+	 * attempted with any directories locked.
+	 *
+	 * Unfortunately, that garbage is userland ABI and we should've
+	 * said "no" back in 2005.  Too late now, so we get to
+	 * play very ugly games with locking.
+	 *
+	 * Try *ANYTHING* of that sort in new code, and you will
+	 * really regret it.  Just ask yourself - what could a BOFH
+	 * do to me and do I want to find it out first-hand?
+	 *
+	 *  AV, a thoroughly annoyed bastard.
+	 */
+	inode_unlock(dir);
 	ret = get_target(symname, &path, &target_item, dentry->d_sb);
+	inode_lock(dir);
 	if (ret)
 		goto out_put;
 
-	ret = type->ct_item_ops->allow_link(parent_item, target_item);
+	if (dentry->d_inode || d_unhashed(dentry))
+		ret = -EEXIST;
+	else
+		ret = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+	if (!ret)
+		ret = type->ct_item_ops->allow_link(parent_item, target_item);
 	if (!ret) {
 		mutex_lock(&configfs_symlink_mutex);
 		ret = create_link(parent_item, target_item, dentry);
--- linux-4.4.0.orig/fs/coredump.c
+++ linux-4.4.0/fs/coredump.c
@@ -1,6 +1,7 @@
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
+#include <linux/freezer.h>
 #include <linux/mm.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
@@ -32,6 +33,9 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/oom.h>
 #include <linux/compat.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/path.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -396,7 +400,9 @@
 	if (core_waiters > 0) {
 		struct core_thread *ptr;
 
+		freezer_do_not_count();
 		wait_for_completion(&core_state->startup);
+		freezer_count();
 		/*
 		 * Wait for all the threads to become inactive, so that
 		 * all the thread context (extended register state, like
@@ -627,6 +633,8 @@
 		}
 	} else {
 		struct inode *inode;
+		int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
+				 O_LARGEFILE | O_EXCL;
 
 		if (cprm.limit < binfmt->min_coredump)
 			goto fail_unlock;
@@ -665,10 +673,27 @@
 		 * what matters is that at least one of the two processes
 		 * writes its coredump successfully, not which one.
 		 */
-		cprm.file = filp_open(cn.corename,
-				 O_CREAT | 2 | O_NOFOLLOW |
-				 O_LARGEFILE | O_EXCL,
-				 0600);
+		if (need_suid_safe) {
+			/*
+			 * Using user namespaces, normal user tasks can change
+			 * their current->fs->root to point to arbitrary
+			 * directories. Since the intention of the "only dump
+			 * with a fully qualified path" rule is to control where
+			 * coredumps may be placed using root privileges,
+			 * current->fs->root must not be used. Instead, use the
+			 * root directory of init_task.
+			 */
+			struct path root;
+
+			task_lock(&init_task);
+			get_fs_root(init_task.fs, &root);
+			task_unlock(&init_task);
+			cprm.file = file_open_root(root.dentry, root.mnt,
+				cn.corename, open_flags, 0600);
+			path_put(&root);
+		} else {
+			cprm.file = filp_open(cn.corename, open_flags, 0600);
+		}
 		if (IS_ERR(cprm.file))
 			goto fail_unlock;
 
@@ -785,3 +810,21 @@
 	return mod ? dump_skip(cprm, align - mod) : 1;
 }
 EXPORT_SYMBOL(dump_align);
+
+/*
+ * Ensures that file size is big enough to contain the current file
+ * postion. This prevents gdb from complaining about a truncated file
+ * if the last "write" to the file was dump_skip.
+ */
+void dump_truncate(struct coredump_params *cprm)
+{
+	struct file *file = cprm->file;
+	loff_t offset;
+
+	if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
+		offset = file->f_op->llseek(file, 0, SEEK_CUR);
+		if (i_size_read(file->f_mapping->host) < offset)
+			do_truncate(file->f_path.dentry, offset, 0, file);
+	}
+}
+EXPORT_SYMBOL(dump_truncate);
--- linux-4.4.0.orig/fs/cramfs/inode.c
+++ linux-4.4.0/fs/cramfs/inode.c
@@ -185,7 +185,8 @@
 			continue;
 		blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;
 		blk_offset += offset;
-		if (blk_offset + len > BUFFER_SIZE)
+		if (blk_offset > BUFFER_SIZE ||
+		    blk_offset + len > BUFFER_SIZE)
 			continue;
 		return read_buffers[i] + blk_offset;
 	}
--- linux-4.4.0.orig/fs/dcache.c
+++ linux-4.4.0/fs/dcache.c
@@ -269,9 +269,32 @@
 	return dentry->d_name.name != dentry->d_iname;
 }
 
-/*
- * Make sure other CPUs see the inode attached before the type is set.
- */
+void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry)
+{
+	spin_lock(&dentry->d_lock);
+	name->name = dentry->d_name;
+	if (unlikely(dname_external(dentry))) {
+		atomic_inc(&external_name(dentry)->u.count);
+	} else {
+		memcpy(name->inline_name, dentry->d_iname,
+		       dentry->d_name.len + 1);
+		name->name.name = name->inline_name;
+	}
+	spin_unlock(&dentry->d_lock);
+}
+EXPORT_SYMBOL(take_dentry_name_snapshot);
+
+void release_dentry_name_snapshot(struct name_snapshot *name)
+{
+	if (unlikely(name->name.name != name->inline_name)) {
+		struct external_name *p;
+		p = container_of(name->name.name, struct external_name, name[0]);
+		if (unlikely(atomic_dec_and_test(&p->u.count)))
+			kfree_rcu(p, u.head);
+	}
+}
+EXPORT_SYMBOL(release_dentry_name_snapshot);
+
 static inline void __d_set_inode_and_type(struct dentry *dentry,
 					  struct inode *inode,
 					  unsigned type_flags)
@@ -279,28 +302,18 @@
 	unsigned flags;
 
 	dentry->d_inode = inode;
-	smp_wmb();
 	flags = READ_ONCE(dentry->d_flags);
 	flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
 	flags |= type_flags;
 	WRITE_ONCE(dentry->d_flags, flags);
 }
 
-/*
- * Ideally, we want to make sure that other CPUs see the flags cleared before
- * the inode is detached, but this is really a violation of RCU principles
- * since the ordering suggests we should always set inode before flags.
- *
- * We should instead replace or discard the entire dentry - but that sucks
- * performancewise on mass deletion/rename.
- */
 static inline void __d_clear_type_and_inode(struct dentry *dentry)
 {
 	unsigned flags = READ_ONCE(dentry->d_flags);
 
 	flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
 	WRITE_ONCE(dentry->d_flags, flags);
-	smp_wmb();
 	dentry->d_inode = NULL;
 }
 
@@ -370,9 +383,11 @@
 	__releases(dentry->d_inode->i_lock)
 {
 	struct inode *inode = dentry->d_inode;
+
+	raw_write_seqcount_begin(&dentry->d_seq);
 	__d_clear_type_and_inode(dentry);
 	hlist_del_init(&dentry->d_u.d_alias);
-	dentry_rcuwalk_invalidate(dentry);
+	raw_write_seqcount_end(&dentry->d_seq);
 	spin_unlock(&dentry->d_lock);
 	spin_unlock(&inode->i_lock);
 	if (!inode->i_nlink)
@@ -589,7 +604,6 @@
 
 failed:
 	spin_unlock(&dentry->d_lock);
-	cpu_relax();
 	return dentry; /* try again with same dentry */
 }
 
@@ -619,11 +633,16 @@
 		spin_unlock(&parent->d_lock);
 		goto again;
 	}
-	rcu_read_unlock();
-	if (parent != dentry)
+	if (parent != dentry) {
 		spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-	else
+		if (unlikely(dentry->d_lockref.count < 0)) {
+			spin_unlock(&parent->d_lock);
+			parent = NULL;
+		}
+	} else {
 		parent = NULL;
+	}
+	rcu_read_unlock();
 	return parent;
 }
 
@@ -763,6 +782,8 @@
 		return;
 
 repeat:
+	might_sleep();
+
 	rcu_read_lock();
 	if (likely(fast_dput(dentry))) {
 		rcu_read_unlock();
@@ -794,8 +815,10 @@
 
 kill_it:
 	dentry = dentry_kill(dentry);
-	if (dentry)
+	if (dentry) {
+		cond_resched();
 		goto repeat;
+	}
 }
 EXPORT_SYMBOL(dput);
 
@@ -1130,17 +1153,14 @@
  */
 void shrink_dcache_sb(struct super_block *sb)
 {
-	long freed;
-
 	do {
 		LIST_HEAD(dispose);
 
-		freed = list_lru_walk(&sb->s_dentry_lru,
-			dentry_lru_isolate_shrink, &dispose, UINT_MAX);
-
-		this_cpu_sub(nr_dentry_unused, freed);
+		list_lru_walk(&sb->s_dentry_lru,
+			dentry_lru_isolate_shrink, &dispose, 1024);
 		shrink_dentry_list(&dispose);
-	} while (freed > 0);
+		cond_resched();
+	} while (list_lru_count(&sb->s_dentry_lru) > 0);
 }
 EXPORT_SYMBOL(shrink_dcache_sb);
 
@@ -1167,7 +1187,7 @@
  *
  * The @enter() and @finish() callbacks are called with d_lock held.
  */
-static void d_walk(struct dentry *parent, void *data,
+void d_walk(struct dentry *parent, void *data,
 		   enum d_walk_ret (*enter)(void *, struct dentry *),
 		   void (*finish)(void *))
 {
@@ -1272,6 +1292,7 @@
 	seq = 1;
 	goto again;
 }
+EXPORT_SYMBOL(d_walk);
 
 /*
  * Search for at least 1 mount point in the dentry's subdirs.
@@ -1330,8 +1351,11 @@
 	}
 	spin_lock(&dentry->d_lock);
 	if (!d_unlinked(dentry)) {
-		dentry->d_flags |= DCACHE_MOUNTED;
-		ret = 0;
+		ret = -EBUSY;
+		if (!d_mountpoint(dentry)) {
+			dentry->d_flags |= DCACHE_MOUNTED;
+			ret = 0;
+		}
 	}
  	spin_unlock(&dentry->d_lock);
 out:
@@ -1485,7 +1509,7 @@
 {
 	struct detach_data *data = _data;
 
-	if (!data->mountpoint && !data->select.found)
+	if (!data->mountpoint && list_empty(&data->select.dispose))
 		__d_drop(data->select.start);
 }
 
@@ -1527,17 +1551,15 @@
 
 		d_walk(dentry, &data, detach_and_collect, check_and_drop);
 
-		if (data.select.found)
+		if (!list_empty(&data.select.dispose))
 			shrink_dentry_list(&data.select.dispose);
+		else if (!data.mountpoint)
+			return;
 
 		if (data.mountpoint) {
 			detach_mounts(data.mountpoint);
 			dput(data.mountpoint);
 		}
-
-		if (!data.mountpoint && !data.select.found)
-			break;
-
 		cond_resched();
 	}
 }
@@ -1629,7 +1651,7 @@
 	struct dentry *dentry = __d_alloc(parent->d_sb, name);
 	if (!dentry)
 		return NULL;
-
+	dentry->d_flags |= DCACHE_RCUACCESS;
 	spin_lock(&parent->d_lock);
 	/*
 	 * don't need child lock because it is not subject
@@ -1677,7 +1699,8 @@
 				DCACHE_OP_REVALIDATE	|
 				DCACHE_OP_WEAK_REVALIDATE	|
 				DCACHE_OP_DELETE	|
-				DCACHE_OP_SELECT_INODE));
+				DCACHE_OP_SELECT_INODE	|
+				DCACHE_OP_REAL));
 	dentry->d_op = op;
 	if (!op)
 		return;
@@ -1695,6 +1718,8 @@
 		dentry->d_flags |= DCACHE_OP_PRUNE;
 	if (op->d_select_inode)
 		dentry->d_flags |= DCACHE_OP_SELECT_INODE;
+	if (op->d_real)
+		dentry->d_flags |= DCACHE_OP_REAL;
 
 }
 EXPORT_SYMBOL(d_set_d_op);
@@ -1757,8 +1782,9 @@
 	spin_lock(&dentry->d_lock);
 	if (inode)
 		hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
+	raw_write_seqcount_begin(&dentry->d_seq);
 	__d_set_inode_and_type(dentry, inode, add_flags);
-	dentry_rcuwalk_invalidate(dentry);
+	raw_write_seqcount_end(&dentry->d_seq);
 	spin_unlock(&dentry->d_lock);
 	fsnotify_d_instantiate(dentry, inode);
 }
@@ -1865,6 +1891,28 @@
 
 EXPORT_SYMBOL(d_instantiate_unique);
 
+/*
+ * This should be equivalent to d_instantiate() + unlock_new_inode(),
+ * with lockdep-related part of unlock_new_inode() done before
+ * anything else.  Use that instead of open-coding d_instantiate()/
+ * unlock_new_inode() combinations.
+ */
+void d_instantiate_new(struct dentry *entry, struct inode *inode)
+{
+	BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
+	BUG_ON(!inode);
+	lockdep_annotate_inode_mutex_key(inode);
+	spin_lock(&inode->i_lock);
+	__d_instantiate(entry, inode);
+	WARN_ON(!(inode->i_state & I_NEW));
+	inode->i_state &= ~I_NEW;
+	smp_mb();
+	wake_up_bit(&inode->i_state, __I_NEW);
+	spin_unlock(&inode->i_lock);
+	security_d_instantiate(entry, inode);
+}
+EXPORT_SYMBOL(d_instantiate_new);
+
 /**
  * d_instantiate_no_diralias - instantiate a non-aliased dentry
  * @entry: dentry to complete
@@ -1900,10 +1948,12 @@
 		static const struct qstr name = QSTR_INIT("/", 1);
 
 		res = __d_alloc(root_inode->i_sb, &name);
-		if (res)
+		if (res) {
+			res->d_flags |= DCACHE_RCUACCESS;
 			d_instantiate(res, root_inode);
-		else
+		} else {
 			iput(root_inode);
+		}
 	}
 	return res;
 }
@@ -2420,7 +2470,6 @@
 {
 	BUG_ON(!d_unhashed(entry));
 	hlist_bl_lock(b);
-	entry->d_flags |= DCACHE_RCUACCESS;
 	hlist_bl_add_head_rcu(&entry->d_hash, b);
 	hlist_bl_unlock(b);
 }
@@ -2639,6 +2688,7 @@
 	/* ... and switch them in the tree */
 	if (IS_ROOT(dentry)) {
 		/* splicing a tree */
+		dentry->d_flags |= DCACHE_RCUACCESS;
 		dentry->d_parent = target->d_parent;
 		target->d_parent = target;
 		list_del_init(&target->d_child);
--- linux-4.4.0.orig/fs/debugfs/file.c
+++ linux-4.4.0/fs/debugfs/file.c
@@ -22,6 +22,12 @@
 #include <linux/slab.h>
 #include <linux/atomic.h>
 #include <linux/device.h>
+#include <linux/srcu.h>
+#include <asm/poll.h>
+
+#include "internal.h"
+
+struct poll_table_struct;
 
 static ssize_t default_read_file(struct file *file, char __user *buf,
 				 size_t count, loff_t *ppos)
@@ -35,27 +41,300 @@
 	return count;
 }
 
-const struct file_operations debugfs_file_operations = {
+const struct file_operations debugfs_noop_file_operations = {
 	.read =		default_read_file,
 	.write =	default_write_file,
 	.open =		simple_open,
 	.llseek =	noop_llseek,
 };
 
-static struct dentry *debugfs_create_mode(const char *name, umode_t mode,
-					  struct dentry *parent, void *value,
-				          const struct file_operations *fops,
-				          const struct file_operations *fops_ro,
-				          const struct file_operations *fops_wo)
+/**
+ * debugfs_use_file_start - mark the beginning of file data access
+ * @dentry: the dentry object whose data is being accessed.
+ * @srcu_idx: a pointer to some memory to store a SRCU index in.
+ *
+ * Up to a matching call to debugfs_use_file_finish(), any
+ * successive call into the file removing functions debugfs_remove()
+ * and debugfs_remove_recursive() will block. Since associated private
+ * file data may only get freed after a successful return of any of
+ * the removal functions, you may safely access it after a successful
+ * call to debugfs_use_file_start() without worrying about
+ * lifetime issues.
+ *
+ * If -%EIO is returned, the file has already been removed and thus,
+ * it is not safe to access any of its data. If, on the other hand,
+ * it is allowed to access the file data, zero is returned.
+ *
+ * Regardless of the return code, any call to
+ * debugfs_use_file_start() must be followed by a matching call
+ * to debugfs_use_file_finish().
+ */
+int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx)
+	__acquires(&debugfs_srcu)
+{
+	*srcu_idx = srcu_read_lock(&debugfs_srcu);
+	barrier();
+	if (d_unlinked(dentry))
+		return -EIO;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(debugfs_use_file_start);
+
+/**
+ * debugfs_use_file_finish - mark the end of file data access
+ * @srcu_idx: the SRCU index "created" by a former call to
+ *            debugfs_use_file_start().
+ *
+ * Allow any ongoing concurrent call into debugfs_remove() or
+ * debugfs_remove_recursive() blocked by a former call to
+ * debugfs_use_file_start() to proceed and return to its caller.
+ */
+void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu)
+{
+	srcu_read_unlock(&debugfs_srcu, srcu_idx);
+}
+EXPORT_SYMBOL_GPL(debugfs_use_file_finish);
+
+#define F_DENTRY(filp) ((filp)->f_path.dentry)
+
+#define REAL_FOPS_DEREF(dentry)					\
+	((const struct file_operations *)(dentry)->d_fsdata)
+
+static int open_proxy_open(struct inode *inode, struct file *filp)
+{
+	const struct dentry *dentry = F_DENTRY(filp);
+	const struct file_operations *real_fops = NULL;
+	int srcu_idx, r;
+
+	if (secure_modules())
+		return -EPERM;
+
+	r = debugfs_use_file_start(dentry, &srcu_idx);
+	if (r) {
+		r = -ENOENT;
+		goto out;
+	}
+
+	real_fops = REAL_FOPS_DEREF(dentry);
+	real_fops = fops_get(real_fops);
+	if (!real_fops) {
+		/* Huh? Module did not clean up after itself at exit? */
+		WARN(1, "debugfs file owner did not clean up at exit: %pd",
+			dentry);
+		r = -ENXIO;
+		goto out;
+	}
+	replace_fops(filp, real_fops);
+
+	if (real_fops->open)
+		r = real_fops->open(inode, filp);
+
+out:
+	debugfs_use_file_finish(srcu_idx);
+	return r;
+}
+
+const struct file_operations debugfs_open_proxy_file_operations = {
+	.open = open_proxy_open,
+};
+
+#define PROTO(args...) args
+#define ARGS(args...) args
+
+#define FULL_PROXY_FUNC(name, ret_type, filp, proto, args)		\
+static ret_type full_proxy_ ## name(proto)				\
+{									\
+	const struct dentry *dentry = F_DENTRY(filp);			\
+	const struct file_operations *real_fops =			\
+		REAL_FOPS_DEREF(dentry);				\
+	int srcu_idx;							\
+	ret_type r;							\
+									\
+	r = debugfs_use_file_start(dentry, &srcu_idx);			\
+	if (likely(!r))						\
+		r = real_fops->name(args);				\
+	debugfs_use_file_finish(srcu_idx);				\
+	return r;							\
+}
+
+FULL_PROXY_FUNC(llseek, loff_t, filp,
+		PROTO(struct file *filp, loff_t offset, int whence),
+		ARGS(filp, offset, whence));
+
+FULL_PROXY_FUNC(read, ssize_t, filp,
+		PROTO(struct file *filp, char __user *buf, size_t size,
+			loff_t *ppos),
+		ARGS(filp, buf, size, ppos));
+
+FULL_PROXY_FUNC(write, ssize_t, filp,
+		PROTO(struct file *filp, const char __user *buf, size_t size,
+			loff_t *ppos),
+		ARGS(filp, buf, size, ppos));
+
+FULL_PROXY_FUNC(unlocked_ioctl, long, filp,
+		PROTO(struct file *filp, unsigned int cmd, unsigned long arg),
+		ARGS(filp, cmd, arg));
+
+static unsigned int full_proxy_poll(struct file *filp,
+				struct poll_table_struct *wait)
+{
+	const struct dentry *dentry = F_DENTRY(filp);
+	const struct file_operations *real_fops = REAL_FOPS_DEREF(dentry);
+	int srcu_idx;
+	unsigned int r = 0;
+
+	if (debugfs_use_file_start(dentry, &srcu_idx)) {
+		debugfs_use_file_finish(srcu_idx);
+		return POLLHUP;
+	}
+
+	r = real_fops->poll(filp, wait);
+	debugfs_use_file_finish(srcu_idx);
+	return r;
+}
+
+static int full_proxy_release(struct inode *inode, struct file *filp)
+{
+	const struct dentry *dentry = F_DENTRY(filp);
+	const struct file_operations *real_fops = REAL_FOPS_DEREF(dentry);
+	const struct file_operations *proxy_fops = filp->f_op;
+	int r = 0;
+
+	/*
+	 * We must not protect this against removal races here: the
+	 * original releaser should be called unconditionally in order
+	 * not to leak any resources. Releasers must not assume that
+	 * ->i_private is still being meaningful here.
+	 */
+	if (real_fops->release)
+		r = real_fops->release(inode, filp);
+
+	replace_fops(filp, d_inode(dentry)->i_fop);
+	kfree((void *)proxy_fops);
+	fops_put(real_fops);
+	return 0;
+}
+
+static void __full_proxy_fops_init(struct file_operations *proxy_fops,
+				const struct file_operations *real_fops)
+{
+	proxy_fops->release = full_proxy_release;
+	if (real_fops->llseek)
+		proxy_fops->llseek = full_proxy_llseek;
+	if (real_fops->read)
+		proxy_fops->read = full_proxy_read;
+	if (real_fops->write)
+		proxy_fops->write = full_proxy_write;
+	if (real_fops->poll)
+		proxy_fops->poll = full_proxy_poll;
+	if (real_fops->unlocked_ioctl)
+		proxy_fops->unlocked_ioctl = full_proxy_unlocked_ioctl;
+}
+
+static int full_proxy_open(struct inode *inode, struct file *filp)
+{
+	const struct dentry *dentry = F_DENTRY(filp);
+	const struct file_operations *real_fops = NULL;
+	struct file_operations *proxy_fops = NULL;
+	int srcu_idx, r;
+
+	if (secure_modules())
+		return -EPERM;
+
+	r = debugfs_use_file_start(dentry, &srcu_idx);
+	if (r) {
+		r = -ENOENT;
+		goto out;
+	}
+
+	real_fops = REAL_FOPS_DEREF(dentry);
+	real_fops = fops_get(real_fops);
+	if (!real_fops) {
+		/* Huh? Module did not cleanup after itself at exit? */
+		WARN(1, "debugfs file owner did not clean up at exit: %pd",
+			dentry);
+		r = -ENXIO;
+		goto out;
+	}
+
+	proxy_fops = kzalloc(sizeof(*proxy_fops), GFP_KERNEL);
+	if (!proxy_fops) {
+		r = -ENOMEM;
+		goto free_proxy;
+	}
+	__full_proxy_fops_init(proxy_fops, real_fops);
+	replace_fops(filp, proxy_fops);
+
+	if (real_fops->open) {
+		r = real_fops->open(inode, filp);
+		if (r) {
+			replace_fops(filp, d_inode(dentry)->i_fop);
+			goto free_proxy;
+		} else if (filp->f_op != proxy_fops) {
+			/* No protection against file removal anymore. */
+			WARN(1, "debugfs file owner replaced proxy fops: %pd",
+				dentry);
+			goto free_proxy;
+		}
+	}
+
+	goto out;
+free_proxy:
+	kfree(proxy_fops);
+	fops_put(real_fops);
+out:
+	debugfs_use_file_finish(srcu_idx);
+	return r;
+}
+
+const struct file_operations debugfs_full_proxy_file_operations = {
+	.open = full_proxy_open,
+};
+
+ssize_t debugfs_attr_read(struct file *file, char __user *buf,
+			size_t len, loff_t *ppos)
+{
+	ssize_t ret;
+	int srcu_idx;
+
+	ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx);
+	if (likely(!ret))
+		ret = simple_attr_read(file, buf, len, ppos);
+	debugfs_use_file_finish(srcu_idx);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(debugfs_attr_read);
+
+ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
+			 size_t len, loff_t *ppos)
+{
+	ssize_t ret;
+	int srcu_idx;
+
+	ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx);
+	if (likely(!ret))
+		ret = simple_attr_write(file, buf, len, ppos);
+	debugfs_use_file_finish(srcu_idx);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(debugfs_attr_write);
+
+static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode,
+					struct dentry *parent, void *value,
+					const struct file_operations *fops,
+					const struct file_operations *fops_ro,
+					const struct file_operations *fops_wo)
 {
 	/* if there are no write bits set, make read only */
 	if (!(mode & S_IWUGO))
-		return debugfs_create_file(name, mode, parent, value, fops_ro);
+		return debugfs_create_file_unsafe(name, mode, parent, value,
+						fops_ro);
 	/* if there are no read bits set, make write only */
 	if (!(mode & S_IRUGO))
-		return debugfs_create_file(name, mode, parent, value, fops_wo);
+		return debugfs_create_file_unsafe(name, mode, parent, value,
+						fops_wo);
 
-	return debugfs_create_file(name, mode, parent, value, fops);
+	return debugfs_create_file_unsafe(name, mode, parent, value, fops);
 }
 
 static int debugfs_u8_set(void *data, u64 val)
@@ -68,9 +347,9 @@
 	*val = *(u8 *)data;
 	return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
 
 /**
  * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value
@@ -99,7 +378,7 @@
 struct dentry *debugfs_create_u8(const char *name, umode_t mode,
 				 struct dentry *parent, u8 *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_u8,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
 				   &fops_u8_ro, &fops_u8_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u8);
@@ -114,9 +393,9 @@
 	*val = *(u16 *)data;
 	return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
 
 /**
  * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value
@@ -145,7 +424,7 @@
 struct dentry *debugfs_create_u16(const char *name, umode_t mode,
 				  struct dentry *parent, u16 *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_u16,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
 				   &fops_u16_ro, &fops_u16_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u16);
@@ -160,9 +439,9 @@
 	*val = *(u32 *)data;
 	return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n");
 
 /**
  * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value
@@ -191,7 +470,7 @@
 struct dentry *debugfs_create_u32(const char *name, umode_t mode,
 				 struct dentry *parent, u32 *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_u32,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
 				   &fops_u32_ro, &fops_u32_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u32);
@@ -207,9 +486,9 @@
 	*val = *(u64 *)data;
 	return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
 
 /**
  * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
@@ -238,7 +517,7 @@
 struct dentry *debugfs_create_u64(const char *name, umode_t mode,
 				 struct dentry *parent, u64 *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_u64,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
 				   &fops_u64_ro, &fops_u64_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u64);
@@ -254,9 +533,10 @@
 	*val = *(unsigned long *)data;
 	return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set,
+			"%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
 
 /**
  * debugfs_create_ulong - create a debugfs file that is used to read and write
@@ -286,26 +566,30 @@
 struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
 				    struct dentry *parent, unsigned long *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_ulong,
-				   &fops_ulong_ro, &fops_ulong_wo);
+	return debugfs_create_mode_unsafe(name, mode, parent, value,
+					&fops_ulong, &fops_ulong_ro,
+					&fops_ulong_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_ulong);
 
-DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n");
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n");
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n");
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set,
+			"0x%04llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n");
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set,
+			"0x%08llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set,
+			"0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
 
 /*
  * debugfs_create_x{8,16,32,64} - create a debugfs file that is used to read and write an unsigned {8,16,32,64}-bit value
@@ -328,7 +612,7 @@
 struct dentry *debugfs_create_x8(const char *name, umode_t mode,
 				 struct dentry *parent, u8 *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_x8,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
 				   &fops_x8_ro, &fops_x8_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x8);
@@ -346,7 +630,7 @@
 struct dentry *debugfs_create_x16(const char *name, umode_t mode,
 				 struct dentry *parent, u16 *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_x16,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
 				   &fops_x16_ro, &fops_x16_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x16);
@@ -364,7 +648,7 @@
 struct dentry *debugfs_create_x32(const char *name, umode_t mode,
 				 struct dentry *parent, u32 *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_x32,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
 				   &fops_x32_ro, &fops_x32_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x32);
@@ -382,7 +666,7 @@
 struct dentry *debugfs_create_x64(const char *name, umode_t mode,
 				 struct dentry *parent, u64 *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_x64,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
 				   &fops_x64_ro, &fops_x64_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x64);
@@ -398,10 +682,10 @@
 	*val = *(size_t *)data;
 	return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set,
-			"%llu\n");	/* %llu and %zu are more or less the same */
-DEFINE_SIMPLE_ATTRIBUTE(fops_size_t_ro, debugfs_size_t_get, NULL, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set,
+			"%llu\n"); /* %llu and %zu are more or less the same */
+DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_ro, debugfs_size_t_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n");
 
 /**
  * debugfs_create_size_t - create a debugfs file that is used to read and write an size_t value
@@ -416,8 +700,9 @@
 struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
 				     struct dentry *parent, size_t *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_size_t,
-				   &fops_size_t_ro, &fops_size_t_wo);
+	return debugfs_create_mode_unsafe(name, mode, parent, value,
+					&fops_size_t, &fops_size_t_ro,
+					&fops_size_t_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_size_t);
 
@@ -431,10 +716,12 @@
 	*val = atomic_read((atomic_t *)data);
 	return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get,
+DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get,
 			debugfs_atomic_t_set, "%lld\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%lld\n");
-DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%lld\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL,
+			"%lld\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set,
+			"%lld\n");
 
 /**
  * debugfs_create_atomic_t - create a debugfs file that is used to read and
@@ -450,8 +737,9 @@
 struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
 				 struct dentry *parent, atomic_t *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_atomic_t,
-				   &fops_atomic_t_ro, &fops_atomic_t_wo);
+	return debugfs_create_mode_unsafe(name, mode, parent, value,
+					&fops_atomic_t, &fops_atomic_t_ro,
+					&fops_atomic_t_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_atomic_t);
 
@@ -459,9 +747,17 @@
 			       size_t count, loff_t *ppos)
 {
 	char buf[3];
-	bool *val = file->private_data;
+	bool val;
+	int r, srcu_idx;
+
+	r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx);
+	if (likely(!r))
+		val = *(bool *)file->private_data;
+	debugfs_use_file_finish(srcu_idx);
+	if (r)
+		return r;
 
-	if (*val)
+	if (val)
 		buf[0] = 'Y';
 	else
 		buf[0] = 'N';
@@ -477,6 +773,7 @@
 	char buf[32];
 	size_t buf_size;
 	bool bv;
+	int r, srcu_idx;
 	bool *val = file->private_data;
 
 	buf_size = min(count, (sizeof(buf)-1));
@@ -484,8 +781,14 @@
 		return -EFAULT;
 
 	buf[buf_size] = '\0';
-	if (strtobool(buf, &bv) == 0)
-		*val = bv;
+	if (strtobool(buf, &bv) == 0) {
+		r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx);
+		if (likely(!r))
+			*val = bv;
+		debugfs_use_file_finish(srcu_idx);
+		if (r)
+			return r;
+	}
 
 	return count;
 }
@@ -537,7 +840,7 @@
 struct dentry *debugfs_create_bool(const char *name, umode_t mode,
 				   struct dentry *parent, bool *value)
 {
-	return debugfs_create_mode(name, mode, parent, value, &fops_bool,
+	return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
 				   &fops_bool_ro, &fops_bool_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_bool);
@@ -546,8 +849,15 @@
 			      size_t count, loff_t *ppos)
 {
 	struct debugfs_blob_wrapper *blob = file->private_data;
-	return simple_read_from_buffer(user_buf, count, ppos, blob->data,
-			blob->size);
+	ssize_t r;
+	int srcu_idx;
+
+	r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx);
+	if (likely(!r))
+		r = simple_read_from_buffer(user_buf, count, ppos, blob->data,
+					blob->size);
+	debugfs_use_file_finish(srcu_idx);
+	return r;
 }
 
 static const struct file_operations fops_blob = {
@@ -584,7 +894,7 @@
 				   struct dentry *parent,
 				   struct debugfs_blob_wrapper *blob)
 {
-	return debugfs_create_file(name, mode, parent, blob, &fops_blob);
+	return debugfs_create_file_unsafe(name, mode, parent, blob, &fops_blob);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_blob);
 
@@ -689,7 +999,8 @@
 	data->array = array;
 	data->elements = elements;
 
-	return debugfs_create_file(name, mode, parent, data, &u32_array_fops);
+	return debugfs_create_file_unsafe(name, mode, parent, data,
+					&u32_array_fops);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u32_array);
 
--- linux-4.4.0.orig/fs/debugfs/inode.c
+++ linux-4.4.0/fs/debugfs/inode.c
@@ -27,9 +27,14 @@
 #include <linux/parser.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
+#include <linux/srcu.h>
+
+#include "internal.h"
 
 #define DEBUGFS_DEFAULT_MODE	0700
 
+DEFINE_SRCU(debugfs_srcu);
+
 static struct vfsmount *debugfs_mount;
 static int debugfs_mount_count;
 static bool debugfs_registered;
@@ -164,26 +169,31 @@
 	return 0;
 }
 
-static void debugfs_evict_inode(struct inode *inode)
+static void debugfs_i_callback(struct rcu_head *head)
 {
-	truncate_inode_pages_final(&inode->i_data);
-	clear_inode(inode);
+	struct inode *inode = container_of(head, struct inode, i_rcu);
 	if (S_ISLNK(inode->i_mode))
 		kfree(inode->i_link);
+	free_inode_nonrcu(inode);
+}
+
+static void debugfs_destroy_inode(struct inode *inode)
+{
+	call_rcu(&inode->i_rcu, debugfs_i_callback);
 }
 
 static const struct super_operations debugfs_super_operations = {
 	.statfs		= simple_statfs,
 	.remount_fs	= debugfs_remount,
 	.show_options	= debugfs_show_options,
-	.evict_inode	= debugfs_evict_inode,
+	.destroy_inode	= debugfs_destroy_inode,
 };
 
 static struct vfsmount *debugfs_automount(struct path *path)
 {
-	struct vfsmount *(*f)(void *);
-	f = (struct vfsmount *(*)(void *))path->dentry->d_fsdata;
-	return f(d_inode(path->dentry)->i_private);
+	debugfs_automount_t f;
+	f = (debugfs_automount_t)path->dentry->d_fsdata;
+	return f(path->dentry, d_inode(path->dentry)->i_private);
 }
 
 static const struct dentry_operations debugfs_dops = {
@@ -294,6 +304,37 @@
 	return dentry;
 }
 
+static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
+				struct dentry *parent, void *data,
+				const struct file_operations *proxy_fops,
+				const struct file_operations *real_fops)
+{
+	struct dentry *dentry;
+	struct inode *inode;
+
+	if (!(mode & S_IFMT))
+		mode |= S_IFREG;
+	BUG_ON(!S_ISREG(mode));
+	dentry = start_creating(name, parent);
+
+	if (IS_ERR(dentry))
+		return NULL;
+
+	inode = debugfs_get_inode(dentry->d_sb);
+	if (unlikely(!inode))
+		return failed_creating(dentry);
+
+	inode->i_mode = mode;
+	inode->i_private = data;
+
+	inode->i_fop = proxy_fops;
+	dentry->d_fsdata = (void *)real_fops;
+
+	d_instantiate(dentry, inode);
+	fsnotify_create(d_inode(dentry->d_parent), dentry);
+	return end_creating(dentry);
+}
+
 /**
  * debugfs_create_file - create a file in the debugfs filesystem
  * @name: a pointer to a string containing the name of the file to create.
@@ -324,29 +365,52 @@
 				   struct dentry *parent, void *data,
 				   const struct file_operations *fops)
 {
-	struct dentry *dentry;
-	struct inode *inode;
-
-	if (!(mode & S_IFMT))
-		mode |= S_IFREG;
-	BUG_ON(!S_ISREG(mode));
-	dentry = start_creating(name, parent);
 
-	if (IS_ERR(dentry))
-		return NULL;
+	return __debugfs_create_file(name, mode, parent, data,
+				fops ? &debugfs_full_proxy_file_operations :
+					&debugfs_noop_file_operations,
+				fops);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_file);
 
-	inode = debugfs_get_inode(dentry->d_sb);
-	if (unlikely(!inode))
-		return failed_creating(dentry);
+/**
+ * debugfs_create_file_unsafe - create a file in the debugfs filesystem
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have.
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this parameter is NULL, then the
+ *          file will be created in the root of the debugfs filesystem.
+ * @data: a pointer to something that the caller will want to get to later
+ *        on.  The inode.i_private pointer will point to this value on
+ *        the open() call.
+ * @fops: a pointer to a struct file_operations that should be used for
+ *        this file.
+ *
+ * debugfs_create_file_unsafe() is completely analogous to
+ * debugfs_create_file(), the only difference being that the fops
+ * handed it will not get protected against file removals by the
+ * debugfs core.
+ *
+ * It is your responsibility to protect your struct file_operation
+ * methods against file removals by means of debugfs_use_file_start()
+ * and debugfs_use_file_finish(). ->open() is still protected by
+ * debugfs though.
+ *
+ * Any struct file_operations defined by means of
+ * DEFINE_DEBUGFS_ATTRIBUTE() is protected against file removals and
+ * thus, may be used here.
+ */
+struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
+				   struct dentry *parent, void *data,
+				   const struct file_operations *fops)
+{
 
-	inode->i_mode = mode;
-	inode->i_fop = fops ? fops : &debugfs_file_operations;
-	inode->i_private = data;
-	d_instantiate(dentry, inode);
-	fsnotify_create(d_inode(dentry->d_parent), dentry);
-	return end_creating(dentry);
+	return __debugfs_create_file(name, mode, parent, data,
+				fops ? &debugfs_open_proxy_file_operations :
+					&debugfs_noop_file_operations,
+				fops);
 }
-EXPORT_SYMBOL_GPL(debugfs_create_file);
+EXPORT_SYMBOL_GPL(debugfs_create_file_unsafe);
 
 /**
  * debugfs_create_file_size - create a file in the debugfs filesystem
@@ -444,7 +508,7 @@
  */
 struct dentry *debugfs_create_automount(const char *name,
 					struct dentry *parent,
-					struct vfsmount *(*f)(void *),
+					debugfs_automount_t f,
 					void *data)
 {
 	struct dentry *dentry = start_creating(name, parent);
@@ -457,7 +521,7 @@
 	if (unlikely(!inode))
 		return failed_creating(dentry);
 
-	inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
+	make_empty_dir_inode(inode);
 	inode->i_flags |= S_AUTOMOUNT;
 	inode->i_private = data;
 	dentry->d_fsdata = (void *)f;
@@ -565,6 +629,8 @@
 	mutex_unlock(&d_inode(parent)->i_mutex);
 	if (!ret)
 		simple_release_fs(&debugfs_mount, &debugfs_mount_count);
+
+	synchronize_srcu(&debugfs_srcu);
 }
 EXPORT_SYMBOL_GPL(debugfs_remove);
 
@@ -642,6 +708,8 @@
 	if (!__debugfs_remove(child, parent))
 		simple_release_fs(&debugfs_mount, &debugfs_mount_count);
 	mutex_unlock(&d_inode(parent)->i_mutex);
+
+	synchronize_srcu(&debugfs_srcu);
 }
 EXPORT_SYMBOL_GPL(debugfs_remove_recursive);
 
@@ -669,7 +737,14 @@
 {
 	int error;
 	struct dentry *dentry = NULL, *trap;
-	const char *old_name;
+	struct name_snapshot old_name;
+
+	if (IS_ERR(old_dir))
+		return old_dir;
+	if (IS_ERR(new_dir))
+		return new_dir;
+	if (IS_ERR_OR_NULL(old_dentry))
+		return old_dentry;
 
 	trap = lock_rename(new_dir, old_dir);
 	/* Source or destination directories don't exist? */
@@ -684,19 +759,19 @@
 	if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry))
 		goto exit;
 
-	old_name = fsnotify_oldname_init(old_dentry->d_name.name);
+	take_dentry_name_snapshot(&old_name, old_dentry);
 
 	error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir),
 		dentry);
 	if (error) {
-		fsnotify_oldname_free(old_name);
+		release_dentry_name_snapshot(&old_name);
 		goto exit;
 	}
 	d_move(old_dentry, dentry);
-	fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name,
+	fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name.name.name,
 		d_is_dir(old_dentry),
 		NULL, old_dentry);
-	fsnotify_oldname_free(old_name);
+	release_dentry_name_snapshot(&old_name);
 	unlock_rename(new_dir, old_dir);
 	dput(dentry);
 	return old_dentry;
--- linux-4.4.0.orig/fs/debugfs/internal.h
+++ linux-4.4.0/fs/debugfs/internal.h
@@ -0,0 +1,26 @@
+/*
+ *  internal.h - declarations internal to debugfs
+ *
+ *  Copyright (C) 2016 Nicolai Stange <nicstange@gmail.com>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License version
+ *	2 as published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _DEBUGFS_INTERNAL_H_
+#define _DEBUGFS_INTERNAL_H_
+
+struct file_operations;
+
+/* declared over in file.c */
+extern const struct file_operations debugfs_noop_file_operations;
+extern const struct file_operations debugfs_open_proxy_file_operations;
+extern const struct file_operations debugfs_full_proxy_file_operations;
+
+struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
+					struct dentry *parent, void *data,
+					const struct file_operations *fops);
+
+#endif /* _DEBUGFS_INTERNAL_H_ */
--- linux-4.4.0.orig/fs/devpts/inode.c
+++ linux-4.4.0/fs/devpts/inode.c
@@ -128,6 +128,7 @@
 struct pts_fs_info {
 	struct ida allocated_ptys;
 	struct pts_mount_opts mount_opts;
+	struct super_block *sb;
 	struct dentry *ptmx_dentry;
 };
 
@@ -358,7 +359,7 @@
 	.show_options	= devpts_show_options,
 };
 
-static void *new_pts_fs_info(void)
+static void *new_pts_fs_info(struct super_block *sb)
 {
 	struct pts_fs_info *fsi;
 
@@ -369,6 +370,7 @@
 	ida_init(&fsi->allocated_ptys);
 	fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
 	fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
+	fsi->sb = sb;
 
 	return fsi;
 }
@@ -384,7 +386,7 @@
 	s->s_op = &devpts_sops;
 	s->s_time_gran = 1;
 
-	s->s_fs_info = new_pts_fs_info();
+	s->s_fs_info = new_pts_fs_info(s);
 	if (!s->s_fs_info)
 		goto fail;
 
@@ -524,17 +526,14 @@
  * to the System V naming convention
  */
 
-int devpts_new_index(struct inode *ptmx_inode)
+int devpts_new_index(struct pts_fs_info *fsi)
 {
-	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
-	struct pts_fs_info *fsi;
 	int index;
 	int ida_ret;
 
-	if (!sb)
+	if (!fsi)
 		return -ENODEV;
 
-	fsi = DEVPTS_SB(sb);
 retry:
 	if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
 		return -ENOMEM;
@@ -564,17 +563,38 @@
 	return index;
 }
 
-void devpts_kill_index(struct inode *ptmx_inode, int idx)
+void devpts_kill_index(struct pts_fs_info *fsi, int idx)
 {
-	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
-	struct pts_fs_info *fsi = DEVPTS_SB(sb);
-
 	mutex_lock(&allocated_ptys_lock);
 	ida_remove(&fsi->allocated_ptys, idx);
 	pty_count--;
 	mutex_unlock(&allocated_ptys_lock);
 }
 
+/*
+ * pty code needs to hold extra references in case of last /dev/tty close
+ */
+struct pts_fs_info *devpts_get_ref(struct inode *ptmx_inode, struct file *file)
+{
+	struct super_block *sb;
+	struct pts_fs_info *fsi;
+
+	sb = pts_sb_from_inode(ptmx_inode);
+	if (!sb)
+		return NULL;
+	fsi = DEVPTS_SB(sb);
+	if (!fsi)
+		return NULL;
+
+	atomic_inc(&sb->s_active);
+	return fsi;
+}
+
+void devpts_put_ref(struct pts_fs_info *fsi)
+{
+	deactivate_super(fsi->sb);
+}
+
 /**
  * devpts_pty_new -- create a new inode in /dev/pts/
  * @ptmx_inode: inode of the master
@@ -584,22 +604,21 @@
  *
  * The created inode is returned. Remove it from /dev/pts/ by devpts_pty_kill.
  */
-struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
+struct inode *devpts_pty_new(struct pts_fs_info *fsi, dev_t device, int index,
 		void *priv)
 {
 	struct dentry *dentry;
-	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+	struct super_block *sb;
 	struct inode *inode;
 	struct dentry *root;
-	struct pts_fs_info *fsi;
 	struct pts_mount_opts *opts;
 	char s[12];
 
-	if (!sb)
+	if (!fsi)
 		return ERR_PTR(-ENODEV);
 
+	sb = fsi->sb;
 	root = sb->s_root;
-	fsi = DEVPTS_SB(sb);
 	opts = &fsi->mount_opts;
 
 	inode = new_inode(sb);
--- linux-4.4.0.orig/fs/direct-io.c
+++ linux-4.4.0/fs/direct-io.c
@@ -472,8 +472,8 @@
 		dio->io_error = -EIO;
 
 	if (dio->is_async && dio->rw == READ && dio->should_dirty) {
-		bio_check_pages_dirty(bio);	/* transfers ownership */
 		err = bio->bi_error;
+		bio_check_pages_dirty(bio);	/* transfers ownership */
 	} else {
 		bio_for_each_segment_all(bvec, bio, i) {
 			struct page *page = bvec->bv_page;
@@ -575,7 +575,7 @@
 /*
  * Call into the fs to map some more disk blocks.  We record the current number
  * of available blocks at sdio->blocks_available.  These are in units of the
- * fs blocksize, (1 << inode->i_blkbits).
+ * fs blocksize, i_blocksize(inode).
  *
  * The fs is allowed to map lots of blocks at once.  If it wants to do that,
  * it uses the passed inode-relative block number as the file offset, as usual.
@@ -823,7 +823,8 @@
 	 */
 	if (sdio->boundary) {
 		ret = dio_send_cur_page(dio, sdio, map_bh);
-		dio_bio_submit(dio, sdio);
+		if (sdio->bio)
+			dio_bio_submit(dio, sdio);
 		page_cache_release(sdio->cur_page);
 		sdio->cur_page = NULL;
 	}
--- linux-4.4.0.orig/fs/dlm/ast.c
+++ linux-4.4.0/fs/dlm/ast.c
@@ -290,6 +290,8 @@
 		flush_workqueue(ls->ls_callback_wq);
 }
 
+#define MAX_CB_QUEUE 25
+
 void dlm_callback_resume(struct dlm_ls *ls)
 {
 	struct dlm_lkb *lkb, *safe;
@@ -300,15 +302,23 @@
 	if (!ls->ls_callback_wq)
 		return;
 
+more:
 	mutex_lock(&ls->ls_cb_mutex);
 	list_for_each_entry_safe(lkb, safe, &ls->ls_cb_delay, lkb_cb_list) {
 		list_del_init(&lkb->lkb_cb_list);
 		queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work);
 		count++;
+		if (count == MAX_CB_QUEUE)
+			break;
 	}
 	mutex_unlock(&ls->ls_cb_mutex);
 
 	if (count)
 		log_rinfo(ls, "dlm_callback_resume %d", count);
+	if (count == MAX_CB_QUEUE) {
+		count = 0;
+		cond_resched();
+		goto more;
+	}
 }
 
--- linux-4.4.0.orig/fs/dlm/dlm_internal.h
+++ linux-4.4.0/fs/dlm/dlm_internal.h
@@ -92,7 +92,6 @@
                __LINE__, __FILE__, #x, jiffies); \
     {do} \
     printk("\n"); \
-    BUG(); \
     panic("DLM:  Record message above and reboot.\n"); \
   } \
 }
--- linux-4.4.0.orig/fs/dlm/lock.c
+++ linux-4.4.0/fs/dlm/lock.c
@@ -1210,6 +1210,7 @@
 
 	if (rv < 0) {
 		log_error(ls, "create_lkb idr error %d", rv);
+		dlm_free_lkb(lkb);
 		return rv;
 	}
 
@@ -4177,6 +4178,7 @@
 			  (unsigned long long)lkb->lkb_recover_seq,
 			  ms->m_header.h_nodeid, ms->m_lkid);
 		error = -ENOENT;
+		dlm_put_lkb(lkb);
 		goto fail;
 	}
 
@@ -4230,6 +4232,7 @@
 			  lkb->lkb_id, lkb->lkb_remid,
 			  ms->m_header.h_nodeid, ms->m_lkid);
 		error = -ENOENT;
+		dlm_put_lkb(lkb);
 		goto fail;
 	}
 
@@ -5792,20 +5795,20 @@
 			goto out;
 		}
 	}
-
-	/* After ua is attached to lkb it will be freed by dlm_free_lkb().
-	   When DLM_IFL_USER is set, the dlm knows that this is a userspace
-	   lock and that lkb_astparam is the dlm_user_args structure. */
-
 	error = set_lock_args(mode, &ua->lksb, flags, namelen, timeout_cs,
 			      fake_astfn, ua, fake_bastfn, &args);
-	lkb->lkb_flags |= DLM_IFL_USER;
-
 	if (error) {
+		kfree(ua->lksb.sb_lvbptr);
+		ua->lksb.sb_lvbptr = NULL;
+		kfree(ua);
 		__put_lkb(ls, lkb);
 		goto out;
 	}
 
+	/* After ua is attached to lkb it will be freed by dlm_free_lkb().
+	   When DLM_IFL_USER is set, the dlm knows that this is a userspace
+	   lock and that lkb_astparam is the dlm_user_args structure. */
+	lkb->lkb_flags |= DLM_IFL_USER;
 	error = request_lock(ls, lkb, name, namelen, &args);
 
 	switch (error) {
--- linux-4.4.0.orig/fs/dlm/lockspace.c
+++ linux-4.4.0/fs/dlm/lockspace.c
@@ -626,6 +626,9 @@
 	wait_event(ls->ls_recover_lock_wait,
 		   test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
 
+	/* let kobject handle freeing of ls if there's an error */
+	do_unreg = 1;
+
 	ls->ls_kobj.kset = dlm_kset;
 	error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL,
 				     "%s", ls->ls_name);
@@ -633,9 +636,6 @@
 		goto out_recoverd;
 	kobject_uevent(&ls->ls_kobj, KOBJ_ADD);
 
-	/* let kobject handle freeing of ls if there's an error */
-	do_unreg = 1;
-
 	/* This uevent triggers dlm_controld in userspace to add us to the
 	   group of nodes that are members of this lockspace (managed by the
 	   cluster infrastructure.)  Once it's done that, it tells us who the
@@ -673,11 +673,11 @@
 	kfree(ls->ls_recover_buf);
  out_lkbidr:
 	idr_destroy(&ls->ls_lkbidr);
+ out_rsbtbl:
 	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)
@@ -800,6 +800,7 @@
 
 	dlm_delete_debug_file(ls);
 
+	idr_destroy(&ls->ls_recover_idr);
 	kfree(ls->ls_recover_buf);
 
 	/*
--- linux-4.4.0.orig/fs/dlm/lowcomms.c
+++ linux-4.4.0/fs/dlm/lowcomms.c
@@ -1607,16 +1607,12 @@
 	mutex_lock(&connections_lock);
 	dlm_allow_conn = 0;
 	foreach_conn(stop_conn);
+	clean_writequeues();
+	foreach_conn(free_conn);
 	mutex_unlock(&connections_lock);
 
 	work_stop();
 
-	mutex_lock(&connections_lock);
-	clean_writequeues();
-
-	foreach_conn(free_conn);
-
-	mutex_unlock(&connections_lock);
 	kmem_cache_destroy(con_cache);
 }
 
--- linux-4.4.0.orig/fs/dlm/member.c
+++ linux-4.4.0/fs/dlm/member.c
@@ -683,7 +683,7 @@
 
 	error = dlm_config_nodes(ls->ls_name, &nodes, &count);
 	if (error < 0)
-		goto fail;
+		goto fail_rv;
 
 	spin_lock(&ls->ls_recover_lock);
 
@@ -715,8 +715,9 @@
 	return 0;
 
  fail:
-	kfree(rv);
 	kfree(nodes);
+ fail_rv:
+	kfree(rv);
 	return error;
 }
 
--- linux-4.4.0.orig/fs/dlm/memory.c
+++ linux-4.4.0/fs/dlm/memory.c
@@ -38,10 +38,8 @@
 
 void dlm_memory_exit(void)
 {
-	if (lkb_cache)
-		kmem_cache_destroy(lkb_cache);
-	if (rsb_cache)
-		kmem_cache_destroy(rsb_cache);
+	kmem_cache_destroy(lkb_cache);
+	kmem_cache_destroy(rsb_cache);
 }
 
 char *dlm_allocate_lvb(struct dlm_ls *ls)
@@ -86,8 +84,7 @@
 		struct dlm_user_args *ua;
 		ua = lkb->lkb_ua;
 		if (ua) {
-			if (ua->lksb.sb_lvbptr)
-				kfree(ua->lksb.sb_lvbptr);
+			kfree(ua->lksb.sb_lvbptr);
 			kfree(ua);
 		}
 	}
--- linux-4.4.0.orig/fs/dlm/user.c
+++ linux-4.4.0/fs/dlm/user.c
@@ -25,6 +25,7 @@
 #include "lvb_table.h"
 #include "user.h"
 #include "ast.h"
+#include "config.h"
 
 static const char name_prefix[] = "dlm";
 static const struct file_operations device_fops;
@@ -355,6 +356,10 @@
 	error = misc_register(&ls->ls_device);
 	if (error) {
 		kfree(ls->ls_device.name);
+		/* this has to be set to NULL
+		 * to avoid a double-free in dlm_device_deregister
+		 */
+		ls->ls_device.name = NULL;
 	}
 fail:
 	return error;
@@ -398,7 +403,7 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	error = dlm_new_lockspace(params->name, NULL, params->flags,
+	error = dlm_new_lockspace(params->name, dlm_config.ci_cluster_name, params->flags,
 				  DLM_USER_LVB_LEN, NULL, NULL, NULL,
 				  &lockspace);
 	if (error)
@@ -701,7 +706,7 @@
 	result.version[0] = DLM_DEVICE_VERSION_MAJOR;
 	result.version[1] = DLM_DEVICE_VERSION_MINOR;
 	result.version[2] = DLM_DEVICE_VERSION_PATCH;
-	memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb));
+	memcpy(&result.lksb, &ua->lksb, offsetof(struct dlm_lksb, sb_lvbptr));
 	result.user_lksb = ua->user_lksb;
 
 	/* FIXME: dlm1 provides for the user's bastparam/addr to not be updated
--- linux-4.4.0.orig/fs/drop_caches.c
+++ linux-4.4.0/fs/drop_caches.c
@@ -20,8 +20,13 @@
 	spin_lock(&sb->s_inode_list_lock);
 	list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
 		spin_lock(&inode->i_lock);
+		/*
+		 * We must skip inodes in unusual state. We may also skip
+		 * inodes without pages but we deliberately won't in case
+		 * we need to reschedule to avoid softlockups.
+		 */
 		if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
-		    (inode->i_mapping->nrpages == 0)) {
+		    (inode->i_mapping->nrpages == 0 && !need_resched())) {
 			spin_unlock(&inode->i_lock);
 			continue;
 		}
@@ -29,6 +34,7 @@
 		spin_unlock(&inode->i_lock);
 		spin_unlock(&sb->s_inode_list_lock);
 
+		cond_resched();
 		invalidate_mapping_pages(inode->i_mapping, 0, -1);
 		iput(toput_inode);
 		toput_inode = inode;
--- linux-4.4.0.orig/fs/ecryptfs/crypto.c
+++ linux-4.4.0/fs/ecryptfs/crypto.c
@@ -346,8 +346,10 @@
 	struct extent_crypt_result ecr;
 	int rc = 0;
 
-	BUG_ON(!crypt_stat || !crypt_stat->tfm
-	       || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));
+	if (!crypt_stat || !crypt_stat->tfm
+	       || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED))
+		return -EINVAL;
+
 	if (unlikely(ecryptfs_verbosity > 0)) {
 		ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n",
 				crypt_stat->key_size);
@@ -1041,8 +1043,10 @@
 
 	rc = ecryptfs_read_lower(file_size, 0, ECRYPTFS_SIZE_AND_MARKER_BYTES,
 				 inode);
-	if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
-		return rc >= 0 ? -EINVAL : rc;
+	if (rc < 0)
+		return rc;
+	else if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
+		return -EINVAL;
 	rc = ecryptfs_validate_marker(marker);
 	if (!rc)
 		ecryptfs_i_size_init(file_size, inode);
@@ -1400,8 +1404,10 @@
 	rc = ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry),
 				     ECRYPTFS_XATTR_NAME, file_size,
 				     ECRYPTFS_SIZE_AND_MARKER_BYTES);
-	if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
-		return rc >= 0 ? -EINVAL : rc;
+	if (rc < 0)
+		return rc;
+	else if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
+		return -EINVAL;
 	rc = ecryptfs_validate_marker(marker);
 	if (!rc)
 		ecryptfs_i_size_init(file_size, inode);
--- linux-4.4.0.orig/fs/ecryptfs/ecryptfs_kernel.h
+++ linux-4.4.0/fs/ecryptfs/ecryptfs_kernel.h
@@ -84,11 +84,16 @@
 static inline struct ecryptfs_auth_tok *
 ecryptfs_get_encrypted_key_payload_data(struct key *key)
 {
-	if (key->type == &key_type_encrypted)
-		return (struct ecryptfs_auth_tok *)
-			(&((struct encrypted_key_payload *)key->payload.data[0])->payload_data);
-	else
+	struct encrypted_key_payload *payload;
+
+	if (key->type != &key_type_encrypted)
 		return NULL;
+
+	payload = key->payload.data[0];
+	if (!payload)
+		return ERR_PTR(-EKEYREVOKED);
+
+	return (struct ecryptfs_auth_tok *)payload->payload_data;
 }
 
 static inline struct key *ecryptfs_get_encrypted_key(char *sig)
@@ -114,12 +119,17 @@
 ecryptfs_get_key_payload_data(struct key *key)
 {
 	struct ecryptfs_auth_tok *auth_tok;
+	const struct user_key_payload *ukp;
 
 	auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
-	if (!auth_tok)
-		return (struct ecryptfs_auth_tok *)user_key_payload(key)->data;
-	else
+	if (auth_tok)
 		return auth_tok;
+
+	ukp = user_key_payload(key);
+	if (!ukp)
+		return ERR_PTR(-EKEYREVOKED);
+
+	return (struct ecryptfs_auth_tok *)ukp->data;
 }
 
 #define ECRYPTFS_MAX_KEYSET_SIZE 1024
--- linux-4.4.0.orig/fs/ecryptfs/file.c
+++ linux-4.4.0/fs/ecryptfs/file.c
@@ -112,7 +112,6 @@
 		.sb = inode->i_sb,
 	};
 	lower_file = ecryptfs_file_to_lower(file);
-	lower_file->f_pos = ctx->pos;
 	rc = iterate_dir(lower_file, &buf.ctx);
 	ctx->pos = buf.ctx.pos;
 	if (rc < 0)
@@ -170,6 +169,19 @@
 	return rc;
 }
 
+static int ecryptfs_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct file *lower_file = ecryptfs_file_to_lower(file);
+	/*
+	 * Don't allow mmap on top of file systems that don't support it
+	 * natively.  If FILESYSTEM_MAX_STACK_DEPTH > 2 or ecryptfs
+	 * allows recursive mounting, this will need to be extended.
+	 */
+	if (!lower_file->f_op->mmap)
+		return -ENODEV;
+	return generic_file_mmap(file, vma);
+}
+
 /**
  * ecryptfs_open
  * @inode: inode speciying file to open
@@ -223,14 +235,6 @@
 	}
 	ecryptfs_set_file_lower(
 		file, ecryptfs_inode_to_private(inode)->lower_file);
-	if (d_is_dir(ecryptfs_dentry)) {
-		ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
-		mutex_lock(&crypt_stat->cs_mutex);
-		crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
-		mutex_unlock(&crypt_stat->cs_mutex);
-		rc = 0;
-		goto out;
-	}
 	rc = read_or_initialize_metadata(ecryptfs_dentry);
 	if (rc)
 		goto out_put;
@@ -247,6 +251,45 @@
 	return rc;
 }
 
+/**
+ * ecryptfs_dir_open
+ * @inode: inode speciying file to open
+ * @file: Structure to return filled in
+ *
+ * Opens the file specified by inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_dir_open(struct inode *inode, struct file *file)
+{
+	struct dentry *ecryptfs_dentry = file->f_path.dentry;
+	/* Private value of ecryptfs_dentry allocated in
+	 * ecryptfs_lookup() */
+	struct ecryptfs_file_info *file_info;
+	struct file *lower_file;
+
+	/* Released in ecryptfs_release or end of function if failure */
+	file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);
+	ecryptfs_set_file_private(file, file_info);
+	if (unlikely(!file_info)) {
+		ecryptfs_printk(KERN_ERR,
+				"Error attempting to allocate memory\n");
+		return -ENOMEM;
+	}
+	lower_file = dentry_open(ecryptfs_dentry_to_lower_path(ecryptfs_dentry),
+				 file->f_flags, current_cred());
+	if (IS_ERR(lower_file)) {
+		printk(KERN_ERR "%s: Error attempting to initialize "
+			"the lower file for the dentry with name "
+			"[%pd]; rc = [%ld]\n", __func__,
+			ecryptfs_dentry, PTR_ERR(lower_file));
+		kmem_cache_free(ecryptfs_file_info_cache, file_info);
+		return PTR_ERR(lower_file);
+	}
+	ecryptfs_set_file_lower(file, lower_file);
+	return 0;
+}
+
 static int ecryptfs_flush(struct file *file, fl_owner_t td)
 {
 	struct file *lower_file = ecryptfs_file_to_lower(file);
@@ -267,6 +310,19 @@
 	return 0;
 }
 
+static int ecryptfs_dir_release(struct inode *inode, struct file *file)
+{
+	fput(ecryptfs_file_to_lower(file));
+	kmem_cache_free(ecryptfs_file_info_cache,
+			ecryptfs_file_to_private(file));
+	return 0;
+}
+
+static loff_t ecryptfs_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+	return vfs_llseek(ecryptfs_file_to_lower(file), offset, whence);
+}
+
 static int
 ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
@@ -346,25 +402,21 @@
 #ifdef CONFIG_COMPAT
 	.compat_ioctl = ecryptfs_compat_ioctl,
 #endif
-	.open = ecryptfs_open,
-	.flush = ecryptfs_flush,
-	.release = ecryptfs_release,
+	.open = ecryptfs_dir_open,
+	.release = ecryptfs_dir_release,
 	.fsync = ecryptfs_fsync,
-	.fasync = ecryptfs_fasync,
-	.splice_read = generic_file_splice_read,
-	.llseek = default_llseek,
+	.llseek = ecryptfs_dir_llseek,
 };
 
 const struct file_operations ecryptfs_main_fops = {
 	.llseek = generic_file_llseek,
 	.read_iter = ecryptfs_read_update_atime,
 	.write_iter = generic_file_write_iter,
-	.iterate = ecryptfs_readdir,
 	.unlocked_ioctl = ecryptfs_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl = ecryptfs_compat_ioctl,
 #endif
-	.mmap = generic_file_mmap,
+	.mmap = ecryptfs_mmap,
 	.open = ecryptfs_open,
 	.flush = ecryptfs_flush,
 	.release = ecryptfs_release,
--- linux-4.4.0.orig/fs/ecryptfs/inode.c
+++ linux-4.4.0/fs/ecryptfs/inode.c
@@ -287,8 +287,7 @@
 		iput(ecryptfs_inode);
 		goto out;
 	}
-	unlock_new_inode(ecryptfs_inode);
-	d_instantiate(ecryptfs_dentry, ecryptfs_inode);
+	d_instantiate_new(ecryptfs_dentry, ecryptfs_inode);
 out:
 	return rc;
 }
@@ -331,9 +330,9 @@
 				     struct dentry *lower_dentry,
 				     struct inode *dir_inode)
 {
-	struct inode *inode, *lower_inode = d_inode(lower_dentry);
+	struct path *path = ecryptfs_dentry_to_lower_path(dentry->d_parent);
+	struct inode *inode, *lower_inode;
 	struct ecryptfs_dentry_info *dentry_info;
-	struct vfsmount *lower_mnt;
 	int rc = 0;
 
 	dentry_info = kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL);
@@ -345,15 +344,22 @@
 		return -ENOMEM;
 	}
 
-	lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
-	fsstack_copy_attr_atime(dir_inode, d_inode(lower_dentry->d_parent));
+	fsstack_copy_attr_atime(dir_inode, d_inode(path->dentry));
 	BUG_ON(!d_count(lower_dentry));
 
 	ecryptfs_set_dentry_private(dentry, dentry_info);
-	dentry_info->lower_path.mnt = lower_mnt;
+	dentry_info->lower_path.mnt = mntget(path->mnt);
 	dentry_info->lower_path.dentry = lower_dentry;
 
-	if (d_really_is_negative(lower_dentry)) {
+	/*
+	 * negative dentry can go positive under us here - its parent is not
+	 * locked.  That's OK and that could happen just as we return from
+	 * ecryptfs_lookup() anyway.  Just need to be careful and fetch
+	 * ->d_inode only once - it's not stable here.
+	 */
+	lower_inode = READ_ONCE(lower_dentry->d_inode);
+
+	if (!lower_inode) {
 		/* We want to add because we couldn't find in lower */
 		d_add(dentry, NULL);
 		return 0;
@@ -939,7 +945,7 @@
 	}
 	mutex_unlock(&crypt_stat->cs_mutex);
 
-	rc = inode_change_ok(inode, ia);
+	rc = setattr_prepare(dentry, ia);
 	if (rc)
 		goto out;
 	if (ia->ia_valid & ATTR_SIZE) {
--- linux-4.4.0.orig/fs/ecryptfs/keystore.c
+++ linux-4.4.0/fs/ecryptfs/keystore.c
@@ -458,7 +458,8 @@
  * @auth_tok_key: key containing the authentication token
  * @auth_tok: authentication token
  *
- * Returns zero on valid auth tok; -EINVAL otherwise
+ * Returns zero on valid auth tok; -EINVAL if the payload is invalid; or
+ * -EKEYREVOKED if the key was revoked before we acquired its semaphore.
  */
 static int
 ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key,
@@ -467,6 +468,12 @@
 	int rc = 0;
 
 	(*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key);
+	if (IS_ERR(*auth_tok)) {
+		rc = PTR_ERR(*auth_tok);
+		*auth_tok = NULL;
+		goto out;
+	}
+
 	if (ecryptfs_verify_version((*auth_tok)->version)) {
 		printk(KERN_ERR "Data structure version mismatch. Userspace "
 		       "tools must match eCryptfs kernel module with major "
@@ -1323,7 +1330,7 @@
 		printk(KERN_WARNING "Tag 1 packet contains key larger "
 		       "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES");
 		rc = -EINVAL;
-		goto out;
+		goto out_free;
 	}
 	memcpy((*new_auth_tok)->session_key.encrypted_key,
 	       &data[(*packet_size)], (body_size - (ECRYPTFS_SIG_SIZE + 2)));
--- linux-4.4.0.orig/fs/ecryptfs/messaging.c
+++ linux-4.4.0/fs/ecryptfs/messaging.c
@@ -397,6 +397,7 @@
 					* ecryptfs_message_buf_len),
 				       GFP_KERNEL);
 	if (!ecryptfs_msg_ctx_arr) {
+		kfree(ecryptfs_daemon_hash);
 		rc = -ENOMEM;
 		printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
 		goto out;
@@ -442,15 +443,16 @@
 	}
 	if (ecryptfs_daemon_hash) {
 		struct ecryptfs_daemon *daemon;
+		struct hlist_node *n;
 		int i;
 
 		mutex_lock(&ecryptfs_daemon_hash_mux);
 		for (i = 0; i < (1 << ecryptfs_hash_bits); i++) {
 			int rc;
 
-			hlist_for_each_entry(daemon,
-					     &ecryptfs_daemon_hash[i],
-					     euid_chain) {
+			hlist_for_each_entry_safe(daemon, n,
+						  &ecryptfs_daemon_hash[i],
+						  euid_chain) {
 				rc = ecryptfs_exorcise_daemon(daemon);
 				if (rc)
 					printk(KERN_ERR "%s: Error whilst "
--- linux-4.4.0.orig/fs/efivarfs/file.c
+++ linux-4.4.0/fs/efivarfs/file.c
@@ -10,6 +10,7 @@
 #include <linux/efi.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/mount.h>
 
 #include "internal.h"
 
@@ -103,9 +104,78 @@
 	return size;
 }
 
+static int
+efivarfs_ioc_getxflags(struct file *file, void __user *arg)
+{
+	struct inode *inode = file->f_mapping->host;
+	unsigned int i_flags;
+	unsigned int flags = 0;
+
+	i_flags = inode->i_flags;
+	if (i_flags & S_IMMUTABLE)
+		flags |= FS_IMMUTABLE_FL;
+
+	if (copy_to_user(arg, &flags, sizeof(flags)))
+		return -EFAULT;
+	return 0;
+}
+
+static int
+efivarfs_ioc_setxflags(struct file *file, void __user *arg)
+{
+	struct inode *inode = file->f_mapping->host;
+	unsigned int flags;
+	unsigned int i_flags = 0;
+	int error;
+
+	if (!inode_owner_or_capable(inode))
+		return -EACCES;
+
+	if (copy_from_user(&flags, arg, sizeof(flags)))
+		return -EFAULT;
+
+	if (flags & ~FS_IMMUTABLE_FL)
+		return -EOPNOTSUPP;
+
+	if (!capable(CAP_LINUX_IMMUTABLE))
+		return -EPERM;
+
+	if (flags & FS_IMMUTABLE_FL)
+		i_flags |= S_IMMUTABLE;
+
+
+	error = mnt_want_write_file(file);
+	if (error)
+		return error;
+
+	mutex_lock(&inode->i_mutex);
+	inode_set_flags(inode, i_flags, S_IMMUTABLE);
+	mutex_unlock(&inode->i_mutex);
+
+	mnt_drop_write_file(file);
+
+	return 0;
+}
+
+long
+efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
+{
+	void __user *arg = (void __user *)p;
+
+	switch (cmd) {
+	case FS_IOC_GETFLAGS:
+		return efivarfs_ioc_getxflags(file, arg);
+	case FS_IOC_SETFLAGS:
+		return efivarfs_ioc_setxflags(file, arg);
+	}
+
+	return -ENOTTY;
+}
+
 const struct file_operations efivarfs_file_operations = {
 	.open	= simple_open,
 	.read	= efivarfs_file_read,
 	.write	= efivarfs_file_write,
 	.llseek	= no_llseek,
+	.unlocked_ioctl = efivarfs_file_ioctl,
 };
--- linux-4.4.0.orig/fs/efivarfs/inode.c
+++ linux-4.4.0/fs/efivarfs/inode.c
@@ -10,12 +10,14 @@
 #include <linux/efi.h>
 #include <linux/fs.h>
 #include <linux/ctype.h>
+#include <linux/kmemleak.h>
 #include <linux/slab.h>
 
 #include "internal.h"
 
 struct inode *efivarfs_get_inode(struct super_block *sb,
-				const struct inode *dir, int mode, dev_t dev)
+				const struct inode *dir, int mode,
+				dev_t dev, bool is_removable)
 {
 	struct inode *inode = new_inode(sb);
 
@@ -23,6 +25,7 @@
 		inode->i_ino = get_next_ino();
 		inode->i_mode = mode;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		inode->i_flags = is_removable ? 0 : S_IMMUTABLE;
 		switch (mode & S_IFMT) {
 		case S_IFREG:
 			inode->i_fop = &efivarfs_file_operations;
@@ -102,22 +105,17 @@
 static int efivarfs_create(struct inode *dir, struct dentry *dentry,
 			  umode_t mode, bool excl)
 {
-	struct inode *inode;
+	struct inode *inode = NULL;
 	struct efivar_entry *var;
 	int namelen, i = 0, err = 0;
+	bool is_removable = false;
 
 	if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
 		return -EINVAL;
 
-	inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
-	if (!inode)
-		return -ENOMEM;
-
 	var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
-	if (!var) {
-		err = -ENOMEM;
-		goto out;
-	}
+	if (!var)
+		return -ENOMEM;
 
 	/* length of the variable name itself: remove GUID and separator */
 	namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
@@ -125,12 +123,23 @@
 	efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
 			&var->var.VendorGuid);
 
+	if (efivar_variable_is_removable(var->var.VendorGuid,
+					 dentry->d_name.name, namelen))
+		is_removable = true;
+
+	inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable);
+	if (!inode) {
+		err = -ENOMEM;
+		goto out;
+	}
+
 	for (i = 0; i < namelen; i++)
 		var->var.VariableName[i] = dentry->d_name.name[i];
 
 	var->var.VariableName[i] = '\0';
 
 	inode->i_private = var;
+	kmemleak_ignore(var);
 
 	efivar_entry_add(var, &efivarfs_list);
 	d_instantiate(dentry, inode);
@@ -138,7 +147,8 @@
 out:
 	if (err) {
 		kfree(var);
-		iput(inode);
+		if (inode)
+			iput(inode);
 	}
 	return err;
 }
--- linux-4.4.0.orig/fs/efivarfs/internal.h
+++ linux-4.4.0/fs/efivarfs/internal.h
@@ -15,7 +15,8 @@
 extern const struct inode_operations efivarfs_dir_inode_operations;
 extern bool efivarfs_valid_name(const char *str, int len);
 extern struct inode *efivarfs_get_inode(struct super_block *sb,
-			const struct inode *dir, int mode, dev_t dev);
+			const struct inode *dir, int mode, dev_t dev,
+			bool is_removable);
 
 extern struct list_head efivarfs_list;
 
--- linux-4.4.0.orig/fs/efivarfs/super.c
+++ linux-4.4.0/fs/efivarfs/super.c
@@ -118,8 +118,9 @@
 	struct dentry *dentry, *root = sb->s_root;
 	unsigned long size = 0;
 	char *name;
-	int len, i;
+	int len;
 	int err = -ENOMEM;
+	bool is_removable = false;
 
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 	if (!entry)
@@ -128,15 +129,17 @@
 	memcpy(entry->var.VariableName, name16, name_size);
 	memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
 
-	len = ucs2_strlen(entry->var.VariableName);
+	len = ucs2_utf8size(entry->var.VariableName);
 
 	/* name, plus '-', plus GUID, plus NUL*/
 	name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL);
 	if (!name)
 		goto fail;
 
-	for (i = 0; i < len; i++)
-		name[i] = entry->var.VariableName[i] & 0xFF;
+	ucs2_as_utf8(name, entry->var.VariableName, len);
+
+	if (efivar_variable_is_removable(entry->var.VendorGuid, name, len))
+		is_removable = true;
 
 	name[len] = '-';
 
@@ -144,7 +147,11 @@
 
 	name[len + EFI_VARIABLE_GUID_LEN+1] = '\0';
 
-	inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0);
+	/* replace invalid slashes like kobject_set_name_vargs does for /sys/firmware/efi/vars. */
+	strreplace(name, '/', '!');
+
+	inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0,
+				   is_removable);
 	if (!inode)
 		goto fail_name;
 
@@ -200,7 +207,7 @@
 	sb->s_d_op		= &efivarfs_d_ops;
 	sb->s_time_gran         = 1;
 
-	inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
+	inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true);
 	if (!inode)
 		return -ENOMEM;
 	inode->i_op = &efivarfs_dir_inode_operations;
--- linux-4.4.0.orig/fs/eventpoll.c
+++ linux-4.4.0/fs/eventpoll.c
@@ -217,8 +217,7 @@
 	struct file *file;
 
 	/* used to optimize loop detection check */
-	int visited;
-	struct list_head visited_list_link;
+	u64 gen;
 };
 
 /* Wait structure used by the poll hooks */
@@ -262,6 +261,8 @@
  */
 static DEFINE_MUTEX(epmutex);
 
+static u64 loop_check_gen = 0;
+
 /* Used to check for epoll file descriptor inclusion loops */
 static struct nested_calls poll_loop_ncalls;
 
@@ -277,9 +278,6 @@
 /* Slab cache used to allocate "struct eppoll_entry" */
 static struct kmem_cache *pwq_cache __read_mostly;
 
-/* Visited nodes during ep_loop_check(), so we can unset them when we finish */
-static LIST_HEAD(visited_list);
-
 /*
  * List of files with newly added links, where we may need to limit the number
  * of emanating paths. Protected by the epmutex.
@@ -518,8 +516,13 @@
 	wait_queue_head_t *whead;
 
 	rcu_read_lock();
-	/* If it is cleared by POLLFREE, it should be rcu-safe */
-	whead = rcu_dereference(pwq->whead);
+	/*
+	 * If it is cleared by POLLFREE, it should be rcu-safe.
+	 * If we read NULL we need a barrier paired with
+	 * smp_store_release() in ep_poll_callback(), otherwise
+	 * we rely on whead->lock.
+	 */
+	whead = smp_load_acquire(&pwq->whead);
 	if (whead)
 		remove_wait_queue(whead, &pwq->wait);
 	rcu_read_unlock();
@@ -1003,17 +1006,6 @@
 	struct epitem *epi = ep_item_from_wait(wait);
 	struct eventpoll *ep = epi->ep;
 
-	if ((unsigned long)key & POLLFREE) {
-		ep_pwq_from_wait(wait)->whead = NULL;
-		/*
-		 * whead = NULL above can race with ep_remove_wait_queue()
-		 * which can do another remove_wait_queue() after us, so we
-		 * can't use __remove_wait_queue(). whead->lock is held by
-		 * the caller.
-		 */
-		list_del_init(&wait->task_list);
-	}
-
 	spin_lock_irqsave(&ep->lock, flags);
 
 	/*
@@ -1040,7 +1032,7 @@
 	 * semantics). All the events that happen during that period of time are
 	 * chained in ep->ovflist and requeued later on.
 	 */
-	if (unlikely(ep->ovflist != EP_UNACTIVE_PTR)) {
+	if (ep->ovflist != EP_UNACTIVE_PTR) {
 		if (epi->next == EP_UNACTIVE_PTR) {
 			epi->next = ep->ovflist;
 			ep->ovflist = epi;
@@ -1078,6 +1070,23 @@
 	if (pwake)
 		ep_poll_safewake(&ep->poll_wait);
 
+
+	if ((unsigned long)key & POLLFREE) {
+		/*
+		 * If we race with ep_remove_wait_queue() it can miss
+		 * ->whead = NULL and do another remove_wait_queue() after
+		 * us, so we can't use __remove_wait_queue().
+		 */
+		list_del_init(&wait->task_list);
+		/*
+		 * ->whead != NULL protects us from the race with ep_free()
+		 * or ep_remove(), ep_remove_wait_queue() takes whead->lock
+		 * held by the caller. Once we nullify it, nothing protects
+		 * ep/epi or even wait.
+		 */
+		smp_store_release(&ep_pwq_from_wait(wait)->whead, NULL);
+	}
+
 	return 1;
 }
 
@@ -1223,7 +1232,7 @@
 
 static int ep_create_wakeup_source(struct epitem *epi)
 {
-	const char *name;
+	struct name_snapshot n;
 	struct wakeup_source *ws;
 
 	if (!epi->ep->ws) {
@@ -1232,8 +1241,9 @@
 			return -ENOMEM;
 	}
 
-	name = epi->ffd.file->f_path.dentry->d_name.name;
-	ws = wakeup_source_register(name);
+	take_dentry_name_snapshot(&n, epi->ffd.file->f_path.dentry);
+	ws = wakeup_source_register(n.name.name);
+	release_dentry_name_snapshot(&n);
 
 	if (!ws)
 		return -ENOMEM;
@@ -1293,6 +1303,22 @@
 		RCU_INIT_POINTER(epi->ws, NULL);
 	}
 
+	/* Add the current item to the list of active epoll hook for this file */
+	spin_lock(&tfile->f_lock);
+	list_add_tail_rcu(&epi->fllink, &tfile->f_ep_links);
+	spin_unlock(&tfile->f_lock);
+
+	/*
+	 * Add the current item to the RB tree. All RB tree operations are
+	 * protected by "mtx", and ep_insert() is called with "mtx" held.
+	 */
+	ep_rbtree_insert(ep, epi);
+
+	/* now check if we've created too many backpaths */
+	error = -EINVAL;
+	if (full_check && reverse_path_check())
+		goto error_remove_epi;
+
 	/* Initialize the poll table using the queue callback */
 	epq.epi = epi;
 	init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
@@ -1315,22 +1341,6 @@
 	if (epi->nwait < 0)
 		goto error_unregister;
 
-	/* Add the current item to the list of active epoll hook for this file */
-	spin_lock(&tfile->f_lock);
-	list_add_tail_rcu(&epi->fllink, &tfile->f_ep_links);
-	spin_unlock(&tfile->f_lock);
-
-	/*
-	 * Add the current item to the RB tree. All RB tree operations are
-	 * protected by "mtx", and ep_insert() is called with "mtx" held.
-	 */
-	ep_rbtree_insert(ep, epi);
-
-	/* now check if we've created too many backpaths */
-	error = -EINVAL;
-	if (full_check && reverse_path_check())
-		goto error_remove_epi;
-
 	/* We have to drop the new item inside our item list to keep track of it */
 	spin_lock_irqsave(&ep->lock, flags);
 
@@ -1356,6 +1366,8 @@
 
 	return 0;
 
+error_unregister:
+	ep_unregister_pollwait(ep, epi);
 error_remove_epi:
 	spin_lock(&tfile->f_lock);
 	list_del_rcu(&epi->fllink);
@@ -1363,9 +1375,6 @@
 
 	rb_erase(&epi->rbn, &ep->rbr);
 
-error_unregister:
-	ep_unregister_pollwait(ep, epi);
-
 	/*
 	 * We need to do this because an event could have been arrived on some
 	 * allocated wait queue. Note that we don't care about the ep->ovflist
@@ -1686,13 +1695,12 @@
 	struct epitem *epi;
 
 	mutex_lock_nested(&ep->mtx, call_nests + 1);
-	ep->visited = 1;
-	list_add(&ep->visited_list_link, &visited_list);
+	ep->gen = loop_check_gen;
 	for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
 		epi = rb_entry(rbp, struct epitem, rbn);
 		if (unlikely(is_file_epoll(epi->ffd.file))) {
 			ep_tovisit = epi->ffd.file->private_data;
-			if (ep_tovisit->visited)
+			if (ep_tovisit->gen == loop_check_gen)
 				continue;
 			error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
 					ep_loop_check_proc, epi->ffd.file,
@@ -1708,9 +1716,11 @@
 			 * not already there, and calling reverse_path_check()
 			 * during ep_insert().
 			 */
-			if (list_empty(&epi->ffd.file->f_tfile_llink))
-				list_add(&epi->ffd.file->f_tfile_llink,
-					 &tfile_check_list);
+			if (list_empty(&epi->ffd.file->f_tfile_llink)) {
+				if (get_file_rcu(epi->ffd.file))
+					list_add(&epi->ffd.file->f_tfile_llink,
+						 &tfile_check_list);
+			}
 		}
 	}
 	mutex_unlock(&ep->mtx);
@@ -1731,18 +1741,8 @@
  */
 static int ep_loop_check(struct eventpoll *ep, struct file *file)
 {
-	int ret;
-	struct eventpoll *ep_cur, *ep_next;
-
-	ret = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+	return ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
 			      ep_loop_check_proc, file, ep, current);
-	/* clear visited list */
-	list_for_each_entry_safe(ep_cur, ep_next, &visited_list,
-							visited_list_link) {
-		ep_cur->visited = 0;
-		list_del(&ep_cur->visited_list_link);
-	}
-	return ret;
 }
 
 static void clear_tfile_check_list(void)
@@ -1754,6 +1754,7 @@
 		file = list_first_entry(&tfile_check_list, struct file,
 					f_tfile_llink);
 		list_del_init(&file->f_tfile_llink);
+		fput(file);
 	}
 	INIT_LIST_HEAD(&tfile_check_list);
 }
@@ -1885,19 +1886,20 @@
 	mutex_lock_nested(&ep->mtx, 0);
 	if (op == EPOLL_CTL_ADD) {
 		if (!list_empty(&f.file->f_ep_links) ||
+				ep->gen == loop_check_gen ||
 						is_file_epoll(tf.file)) {
 			full_check = 1;
 			mutex_unlock(&ep->mtx);
 			mutex_lock(&epmutex);
 			if (is_file_epoll(tf.file)) {
 				error = -ELOOP;
-				if (ep_loop_check(ep, tf.file) != 0) {
-					clear_tfile_check_list();
+				if (ep_loop_check(ep, tf.file) != 0)
 					goto error_tgt_fput;
-				}
-			} else
+			} else {
+				get_file(tf.file);
 				list_add(&tf.file->f_tfile_llink,
 							&tfile_check_list);
+			}
 			mutex_lock_nested(&ep->mtx, 0);
 			if (is_file_epoll(tf.file)) {
 				tep = tf.file->private_data;
@@ -1921,8 +1923,6 @@
 			error = ep_insert(ep, &epds, tf.file, fd, full_check);
 		} else
 			error = -EEXIST;
-		if (full_check)
-			clear_tfile_check_list();
 		break;
 	case EPOLL_CTL_DEL:
 		if (epi)
@@ -1943,8 +1943,11 @@
 	mutex_unlock(&ep->mtx);
 
 error_tgt_fput:
-	if (full_check)
+	if (full_check) {
+		clear_tfile_check_list();
+		loop_check_gen++;
 		mutex_unlock(&epmutex);
+	}
 
 	fdput(tf);
 error_fput:
--- linux-4.4.0.orig/fs/exec.c
+++ linux-4.4.0/fs/exec.c
@@ -19,7 +19,7 @@
  * current->executable is only used by the procfs.  This allows a dispatch
  * table to check for several different types  of binary formats.  We keep
  * trying until we recognize the file or we run out of supported binary
- * formats. 
+ * formats.
  */
 
 #include <linux/slab.h>
@@ -56,6 +56,9 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/oom.h>
 #include <linux/compat.h>
+#include <linux/user_namespace.h>
+
+#include <trace/events/fs.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -103,6 +106,14 @@
 	return (path->mnt->mnt_flags & MNT_NOEXEC) ||
 	       (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC);
 }
+EXPORT_SYMBOL(path_noexec);
+
+bool path_nosuid(const struct path *path)
+{
+	return !mnt_may_suid(path->mnt) ||
+	       (path->mnt->mnt_sb->s_iflags & SB_I_NOSUID);
+}
+EXPORT_SYMBOL(path_nosuid);
 
 #ifdef CONFIG_USELIB
 /*
@@ -190,6 +201,7 @@
 {
 	struct page *page;
 	int ret;
+	unsigned int gup_flags = FOLL_FORCE;
 
 #ifdef CONFIG_STACK_GROWSUP
 	if (write) {
@@ -198,14 +210,35 @@
 			return NULL;
 	}
 #endif
-	ret = get_user_pages(current, bprm->mm, pos,
-			1, write, 1, &page, NULL);
+
+	if (write)
+		gup_flags |= FOLL_WRITE;
+
+	ret = get_user_pages(current, bprm->mm, pos, 1, gup_flags,
+			&page, NULL);
 	if (ret <= 0)
 		return NULL;
 
 	if (write) {
 		unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
-		struct rlimit *rlim;
+		unsigned long ptr_size, limit;
+
+		/*
+		 * Since the stack will hold pointers to the strings, we
+		 * must account for them as well.
+		 *
+		 * The size calculation is the entire vma while each arg page is
+		 * built, so each time we get here it's calculating how far it
+		 * is currently (rather than each call being just the newly
+		 * added size from the arg page).  As a result, we need to
+		 * always add the entire size of the pointers, so that on the
+		 * last call to get_arg_page() we'll actually have the entire
+		 * correct size.
+		 */
+		ptr_size = (bprm->argc + bprm->envc) * sizeof(void *);
+		if (ptr_size > ULONG_MAX - size)
+			goto fail;
+		size += ptr_size;
 
 		acct_arg_size(bprm, size / PAGE_SIZE);
 
@@ -217,20 +250,24 @@
 			return page;
 
 		/*
-		 * Limit to 1/4-th the stack size for the argv+env strings.
+		 * Limit to 1/4 of the max stack size or 3/4 of _STK_LIM
+		 * (whichever is smaller) for the argv+env strings.
 		 * This ensures that:
 		 *  - the remaining binfmt code will not run out of stack space,
 		 *  - the program will have a reasonable amount of stack left
 		 *    to work from.
 		 */
-		rlim = current->signal->rlim;
-		if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
-			put_page(page);
-			return NULL;
-		}
+		limit = _STK_LIM / 4 * 3;
+		limit = min(limit, rlimit(RLIMIT_STACK) / 4);
+		if (size > limit)
+			goto fail;
 	}
 
 	return page;
+
+fail:
+	put_page(page);
+	return NULL;
 }
 
 static void put_arg_page(struct page *page)
@@ -793,6 +830,8 @@
 	if (name->name[0] != '\0')
 		fsnotify_open(file);
 
+	trace_open_exec(name->name);
+
 out:
 	return file;
 
@@ -848,7 +887,7 @@
 	/* Notify parent that we're no longer interested in the old VM */
 	tsk = current;
 	old_mm = current->mm;
-	mm_release(tsk, old_mm);
+	exec_mm_release(tsk, old_mm);
 
 	if (old_mm) {
 		sync_mm_rss(old_mm);
@@ -1055,15 +1094,14 @@
 	return -EAGAIN;
 }
 
-char *get_task_comm(char *buf, struct task_struct *tsk)
+char *__get_task_comm(char *buf, size_t buf_size, struct task_struct *tsk)
 {
-	/* buf must be at least sizeof(tsk->comm) in size */
 	task_lock(tsk);
-	strncpy(buf, tsk->comm, sizeof(tsk->comm));
+	strncpy(buf, tsk->comm, buf_size);
 	task_unlock(tsk);
 	return buf;
 }
-EXPORT_SYMBOL_GPL(get_task_comm);
+EXPORT_SYMBOL_GPL(__get_task_comm);
 
 /*
  * These functions flushes out all traces of the currently running executable
@@ -1098,6 +1136,8 @@
 	 */
 	set_mm_exe_file(bprm->mm, bprm->file);
 
+	would_dump(bprm, bprm->file);
+
 	/*
 	 * Release all of the old mmap stuff
 	 */
@@ -1114,6 +1154,13 @@
 	flush_thread();
 	current->personality &= ~bprm->per_clear;
 
+	/*
+	 * We have to apply CLOEXEC before we change whether the process is
+	 * dumpable (in setup_new_exec) to avoid a race with a process in userspace
+	 * trying to access the should-be-closed file descriptors of a process
+	 * undergoing exec(2).
+	 */
+	do_close_on_exec(current->files);
 	return 0;
 
 out:
@@ -1123,8 +1170,22 @@
 
 void would_dump(struct linux_binprm *bprm, struct file *file)
 {
-	if (inode_permission(file_inode(file), MAY_READ) < 0)
+	struct inode *inode = file_inode(file);
+	if (inode_permission(inode, MAY_READ) < 0) {
+		struct user_namespace *old, *user_ns;
 		bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+
+		/* Ensure mm->user_ns contains the executable */
+		user_ns = old = bprm->mm->user_ns;
+		while ((user_ns != &init_user_ns) &&
+		       !privileged_wrt_inode_uidgid(user_ns, inode))
+			user_ns = user_ns->parent;
+
+		if (old != user_ns) {
+			bprm->mm->user_ns = get_user_ns(user_ns);
+			put_user_ns(old);
+		}
+	}
 }
 EXPORT_SYMBOL(would_dump);
 
@@ -1154,16 +1215,14 @@
 	    !gid_eq(bprm->cred->gid, current_egid())) {
 		current->pdeath_signal = 0;
 	} else {
-		would_dump(bprm, bprm->file);
 		if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)
 			set_dumpable(current->mm, suid_dumpable);
 	}
 
 	/* An exec changes our domain. We are no longer part of the thread
 	   group */
-	current->self_exec_id++;
+	WRITE_ONCE(current->self_exec_id, current->self_exec_id + 1);
 	flush_signal_handlers(current, 0);
-	do_close_on_exec(current->files);
 }
 EXPORT_SYMBOL(setup_new_exec);
 
@@ -1252,9 +1311,10 @@
 {
 	struct task_struct *p = current, *t;
 	unsigned n_fs;
+	bool fs_recheck;
 
 	if (p->ptrace) {
-		if (p->ptrace & PT_PTRACE_CAP)
+		if (ptracer_capable(p, current_user_ns()))
 			bprm->unsafe |= LSM_UNSAFE_PTRACE_CAP;
 		else
 			bprm->unsafe |= LSM_UNSAFE_PTRACE;
@@ -1267,6 +1327,8 @@
 	if (task_no_new_privs(current))
 		bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
 
+recheck:
+	fs_recheck = false;
 	t = p;
 	n_fs = 1;
 	spin_lock(&p->fs->lock);
@@ -1274,12 +1336,18 @@
 	while_each_thread(p, t) {
 		if (t->fs == p->fs)
 			n_fs++;
+		if (t->flags & (PF_EXITING | PF_FORKNOEXEC))
+			fs_recheck  = true;
 	}
 	rcu_read_unlock();
 
-	if (p->fs->users > n_fs)
+	if (p->fs->users > n_fs) {
+		if (fs_recheck) {
+			spin_unlock(&p->fs->lock);
+			goto recheck;
+		}
 		bprm->unsafe |= LSM_UNSAFE_SHARE;
-	else
+	} else
 		p->fs->in_exec = 1;
 	spin_unlock(&p->fs->lock);
 }
@@ -1290,12 +1358,13 @@
 	unsigned int mode;
 	kuid_t uid;
 	kgid_t gid;
+	int err;
 
 	/* clear any previous set[ug]id data from a previous binary */
 	bprm->cred->euid = current_euid();
 	bprm->cred->egid = current_egid();
 
-	if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
+	if (path_nosuid(&bprm->file->f_path))
 		return;
 
 	if (task_no_new_privs(current))
@@ -1309,12 +1378,17 @@
 	/* Be careful if suid/sgid is set */
 	mutex_lock(&inode->i_mutex);
 
-	/* reload atomically mode/uid/gid now that lock held */
+	/* Atomically reload and check mode/uid/gid now that lock held. */
 	mode = inode->i_mode;
 	uid = inode->i_uid;
 	gid = inode->i_gid;
+	err = inode_permission(inode, MAY_EXEC);
 	mutex_unlock(&inode->i_mutex);
 
+	/* Did the exec bit vanish out from under us? Give up. */
+	if (err)
+		return;
+
 	/* We ignore suid/sgid if there are no mappings for them in the ns */
 	if (!kuid_has_mapping(bprm->cred->user_ns, uid) ||
 		 !kgid_has_mapping(bprm->cred->user_ns, gid))
@@ -1595,7 +1669,7 @@
 	current->fs->in_exec = 0;
 	current->in_execve = 0;
 	acct_update_integrals(current);
-	task_numa_free(current);
+	task_numa_free(current, false);
 	free_bprm(bprm);
 	kfree(pathbuf);
 	putname(filename);
--- linux-4.4.0.orig/fs/exofs/dir.c
+++ linux-4.4.0/fs/exofs/dir.c
@@ -79,7 +79,7 @@
 	return err;
 }
 
-static void exofs_check_page(struct page *page)
+static bool exofs_check_page(struct page *page)
 {
 	struct inode *dir = page->mapping->host;
 	unsigned chunk_size = exofs_chunk_size(dir);
@@ -114,7 +114,7 @@
 		goto Eend;
 out:
 	SetPageChecked(page);
-	return;
+	return true;
 
 Ebadsize:
 	EXOFS_ERR("ERROR [exofs_check_page]: "
@@ -150,8 +150,8 @@
 		dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
 		_LLU(le64_to_cpu(p->inode_no)));
 fail:
-	SetPageChecked(page);
 	SetPageError(page);
+	return false;
 }
 
 static struct page *exofs_get_page(struct inode *dir, unsigned long n)
@@ -161,10 +161,10 @@
 
 	if (!IS_ERR(page)) {
 		kmap(page);
-		if (!PageChecked(page))
-			exofs_check_page(page);
-		if (PageError(page))
-			goto fail;
+		if (unlikely(!PageChecked(page))) {
+			if (PageError(page) || !exofs_check_page(page))
+				goto fail;
+		}
 	}
 	return page;
 
--- linux-4.4.0.orig/fs/exofs/inode.c
+++ linux-4.4.0/fs/exofs/inode.c
@@ -1035,7 +1035,7 @@
 	if (unlikely(error))
 		return error;
 
-	error = inode_change_ok(inode, iattr);
+	error = setattr_prepare(dentry, iattr);
 	if (unlikely(error))
 		return error;
 
--- linux-4.4.0.orig/fs/exofs/super.c
+++ linux-4.4.0/fs/exofs/super.c
@@ -100,6 +100,7 @@
 		token = match_token(p, tokens, args);
 		switch (token) {
 		case Opt_name:
+			kfree(opts->dev_name);
 			opts->dev_name = match_strdup(&args[0]);
 			if (unlikely(!opts->dev_name)) {
 				EXOFS_ERR("Error allocating dev_name");
@@ -868,8 +869,10 @@
 	int ret;
 
 	ret = parse_options(data, &opts);
-	if (ret)
+	if (ret) {
+		kfree(opts.dev_name);
 		return ERR_PTR(ret);
+	}
 
 	if (!opts.dev_name)
 		opts.dev_name = dev_name;
--- linux-4.4.0.orig/fs/exportfs/expfs.c
+++ linux-4.4.0/fs/exportfs/expfs.c
@@ -76,7 +76,7 @@
 		struct dentry *parent = dget_parent(dentry);
 
 		dput(dentry);
-		if (IS_ROOT(dentry)) {
+		if (dentry == parent) {
 			dput(parent);
 			return false;
 		}
@@ -148,6 +148,7 @@
 	mutex_unlock(&parent->d_inode->i_mutex);
 	if (IS_ERR(tmp)) {
 		dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp));
+		err = PTR_ERR(tmp);
 		goto out_err;
 	}
 	if (tmp != dentry) {
--- linux-4.4.0.orig/fs/ext2/acl.c
+++ linux-4.4.0/fs/ext2/acl.c
@@ -178,11 +178,8 @@
 	return acl;
 }
 
-/*
- * inode->i_mutex: down
- */
-int
-ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+static int
+__ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
 	int name_index;
 	void *value = NULL;
@@ -192,17 +189,6 @@
 	switch(type) {
 		case ACL_TYPE_ACCESS:
 			name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
-			if (acl) {
-				error = posix_acl_equiv_mode(acl, &inode->i_mode);
-				if (error < 0)
-					return error;
-				else {
-					inode->i_ctime = CURRENT_TIME_SEC;
-					mark_inode_dirty(inode);
-					if (error == 0)
-						acl = NULL;
-				}
-			}
 			break;
 
 		case ACL_TYPE_DEFAULT:
@@ -229,6 +215,24 @@
 }
 
 /*
+ * inode->i_mutex: down
+ */
+int
+ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+	int error;
+
+	if (type == ACL_TYPE_ACCESS && acl) {
+		error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+		if (error)
+			return error;
+		inode->i_ctime = CURRENT_TIME_SEC;
+		mark_inode_dirty(inode);
+	}
+	return __ext2_set_acl(inode, acl, type);
+}
+
+/*
  * Initialize the ACLs of a new inode. Called from ext2_new_inode.
  *
  * dir->i_mutex: down
@@ -245,12 +249,12 @@
 		return error;
 
 	if (default_acl) {
-		error = ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+		error = __ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
 		posix_acl_release(default_acl);
 	}
 	if (acl) {
 		if (!error)
-			error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
+			error = __ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
 		posix_acl_release(acl);
 	}
 	return error;
--- linux-4.4.0.orig/fs/ext2/dir.c
+++ linux-4.4.0/fs/ext2/dir.c
@@ -110,7 +110,7 @@
 	return err;
 }
 
-static void ext2_check_page(struct page *page, int quiet)
+static bool ext2_check_page(struct page *page, int quiet)
 {
 	struct inode *dir = page->mapping->host;
 	struct super_block *sb = dir->i_sb;
@@ -148,7 +148,7 @@
 		goto Eend;
 out:
 	SetPageChecked(page);
-	return;
+	return true;
 
 	/* Too bad, we had an error */
 
@@ -190,8 +190,8 @@
 			(unsigned long) le32_to_cpu(p->inode));
 	}
 fail:
-	SetPageChecked(page);
 	SetPageError(page);
+	return false;
 }
 
 static struct page * ext2_get_page(struct inode *dir, unsigned long n,
@@ -201,10 +201,10 @@
 	struct page *page = read_mapping_page(mapping, n, NULL);
 	if (!IS_ERR(page)) {
 		kmap(page);
-		if (!PageChecked(page))
-			ext2_check_page(page, quiet);
-		if (PageError(page))
-			goto fail;
+		if (unlikely(!PageChecked(page))) {
+			if (PageError(page) || !ext2_check_page(page, quiet))
+				goto fail;
+		}
 	}
 	return page;
 
--- linux-4.4.0.orig/fs/ext2/ext2.h
+++ linux-4.4.0/fs/ext2/ext2.h
@@ -61,6 +61,8 @@
 #define rsv_start rsv_window._rsv_start
 #define rsv_end rsv_window._rsv_end
 
+struct mb_cache;
+
 /*
  * second extended-fs super-block data in memory
  */
@@ -111,6 +113,7 @@
 	 * of the mount options.
 	 */
 	spinlock_t s_lock;
+	struct mb_cache *s_mb_cache;
 };
 
 static inline spinlock_t *
--- linux-4.4.0.orig/fs/ext2/ialloc.c
+++ linux-4.4.0/fs/ext2/ialloc.c
@@ -79,6 +79,7 @@
 	if (dir)
 		le16_add_cpu(&desc->bg_used_dirs_count, -1);
 	spin_unlock(sb_bgl_lock(EXT2_SB(sb), group));
+	percpu_counter_inc(&EXT2_SB(sb)->s_freeinodes_counter);
 	if (dir)
 		percpu_counter_dec(&EXT2_SB(sb)->s_dirs_counter);
 	mark_buffer_dirty(bh);
@@ -525,7 +526,7 @@
 		goto fail;
 	}
 
-	percpu_counter_add(&sbi->s_freeinodes_counter, -1);
+	percpu_counter_dec(&sbi->s_freeinodes_counter);
 	if (S_ISDIR(mode))
 		percpu_counter_inc(&sbi->s_dirs_counter);
 
--- linux-4.4.0.orig/fs/ext2/inode.c
+++ linux-4.4.0/fs/ext2/inode.c
@@ -1175,21 +1175,11 @@
 
 static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
 {
-	/*
-	 * XXX: it seems like a bug here that we don't allow
-	 * IS_APPEND inode to have blocks-past-i_size trimmed off.
-	 * review and fix this.
-	 *
-	 * Also would be nice to be able to handle IO errors and such,
-	 * but that's probably too much to ask.
-	 */
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	    S_ISLNK(inode->i_mode)))
 		return;
 	if (ext2_inode_is_fast_symlink(inode))
 		return;
-	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-		return;
 
 	dax_sem_down_write(EXT2_I(inode));
 	__ext2_truncate_blocks(inode, offset);
@@ -1559,7 +1549,7 @@
 	struct inode *inode = d_inode(dentry);
 	int error;
 
-	error = inode_change_ok(inode, iattr);
+	error = setattr_prepare(dentry, iattr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/ext2/namei.c
+++ linux-4.4.0/fs/ext2/namei.c
@@ -40,8 +40,7 @@
 {
 	int err = ext2_add_link(dentry, inode);
 	if (!err) {
-		unlock_new_inode(inode);
-		d_instantiate(dentry, inode);
+		d_instantiate_new(dentry, inode);
 		return 0;
 	}
 	inode_dec_link_count(inode);
@@ -267,8 +266,7 @@
 	if (err)
 		goto out_fail;
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 out:
 	return err;
 
--- linux-4.4.0.orig/fs/ext2/super.c
+++ linux-4.4.0/fs/ext2/super.c
@@ -131,7 +131,10 @@
 
 	dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
 
-	ext2_xattr_put_super(sb);
+	if (sbi->s_mb_cache) {
+		ext2_xattr_destroy_cache(sbi->s_mb_cache);
+		sbi->s_mb_cache = NULL;
+	}
 	if (!(sb->s_flags & MS_RDONLY)) {
 		struct ext2_super_block *es = sbi->s_es;
 
@@ -721,7 +724,8 @@
 {
 	loff_t res = EXT2_NDIR_BLOCKS;
 	int meta_blocks;
-	loff_t upper_limit;
+	unsigned int upper_limit;
+	unsigned int ppb = 1 << (bits-2);
 
 	/* This is calculated to be the largest file size for a
 	 * dense, file such that the total number of
@@ -735,24 +739,34 @@
 	/* total blocks in file system block size */
 	upper_limit >>= (bits - 9);
 
-
-	/* indirect blocks */
-	meta_blocks = 1;
-	/* double indirect blocks */
-	meta_blocks += 1 + (1LL << (bits-2));
-	/* tripple indirect blocks */
-	meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2)));
-
-	upper_limit -= meta_blocks;
-	upper_limit <<= bits;
-
+	/* Compute how many blocks we can address by block tree */
 	res += 1LL << (bits-2);
 	res += 1LL << (2*(bits-2));
 	res += 1LL << (3*(bits-2));
+	/* Does block tree limit file size? */
+	if (res < upper_limit)
+		goto check_lfs;
+
+	res = upper_limit;
+	/* How many metadata blocks are needed for addressing upper_limit? */
+	upper_limit -= EXT2_NDIR_BLOCKS;
+	/* indirect blocks */
+	meta_blocks = 1;
+	upper_limit -= ppb;
+	/* double indirect blocks */
+	if (upper_limit < ppb * ppb) {
+		meta_blocks += 1 + DIV_ROUND_UP(upper_limit, ppb);
+		res -= meta_blocks;
+		goto check_lfs;
+	}
+	meta_blocks += 1 + ppb;
+	upper_limit -= ppb * ppb;
+	/* tripple indirect blocks for the rest */
+	meta_blocks += 1 + DIV_ROUND_UP(upper_limit, ppb) +
+		DIV_ROUND_UP(upper_limit, ppb*ppb);
+	res -= meta_blocks;
+check_lfs:
 	res <<= bits;
-	if (res > upper_limit)
-		res = upper_limit;
-
 	if (res > MAX_LFS_FILESIZE)
 		res = MAX_LFS_FILESIZE;
 
@@ -1040,9 +1054,9 @@
 
 	if (EXT2_BLOCKS_PER_GROUP(sb) == 0)
 		goto cantfind_ext2;
- 	sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
- 				le32_to_cpu(es->s_first_data_block) - 1)
- 					/ EXT2_BLOCKS_PER_GROUP(sb)) + 1;
+	sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
+				le32_to_cpu(es->s_first_data_block) - 1)
+					/ EXT2_BLOCKS_PER_GROUP(sb)) + 1;
 	db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
 		   EXT2_DESC_PER_BLOCK(sb);
 	sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL);
@@ -1104,6 +1118,14 @@
 		ext2_msg(sb, KERN_ERR, "error: insufficient memory");
 		goto failed_mount3;
 	}
+
+#ifdef CONFIG_EXT2_FS_XATTR
+	sbi->s_mb_cache = ext2_xattr_create_cache();
+	if (!sbi->s_mb_cache) {
+		ext2_msg(sb, KERN_ERR, "Failed to create an mb_cache");
+		goto failed_mount3;
+	}
+#endif
 	/*
 	 * set up enough so that it can read an inode
 	 */
@@ -1149,6 +1171,8 @@
 			sb->s_id);
 	goto failed_mount;
 failed_mount3:
+	if (sbi->s_mb_cache)
+		ext2_xattr_destroy_cache(sbi->s_mb_cache);
 	percpu_counter_destroy(&sbi->s_freeblocks_counter);
 	percpu_counter_destroy(&sbi->s_freeinodes_counter);
 	percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -1555,20 +1579,17 @@
 
 static int __init init_ext2_fs(void)
 {
-	int err = init_ext2_xattr();
-	if (err)
-		return err;
+	int err;
+
 	err = init_inodecache();
 	if (err)
-		goto out1;
+		return err;
         err = register_filesystem(&ext2_fs_type);
 	if (err)
 		goto out;
 	return 0;
 out:
 	destroy_inodecache();
-out1:
-	exit_ext2_xattr();
 	return err;
 }
 
@@ -1576,7 +1597,6 @@
 {
 	unregister_filesystem(&ext2_fs_type);
 	destroy_inodecache();
-	exit_ext2_xattr();
 }
 
 MODULE_AUTHOR("Remy Card and others");
--- linux-4.4.0.orig/fs/ext2/xattr.c
+++ linux-4.4.0/fs/ext2/xattr.c
@@ -55,6 +55,7 @@
 
 #include <linux/buffer_head.h>
 #include <linux/init.h>
+#include <linux/printk.h>
 #include <linux/slab.h>
 #include <linux/mbcache.h>
 #include <linux/quotaops.h>
@@ -85,21 +86,19 @@
 		printk("\n"); \
 	} while (0)
 #else
-# define ea_idebug(f...)
-# define ea_bdebug(f...)
+# define ea_idebug(inode, f...)	no_printk(f)
+# define ea_bdebug(bh, f...)	no_printk(f)
 #endif
 
 static int ext2_xattr_set2(struct inode *, struct buffer_head *,
 			   struct ext2_xattr_header *);
 
-static int ext2_xattr_cache_insert(struct buffer_head *);
+static int ext2_xattr_cache_insert(struct mb_cache *, struct buffer_head *);
 static struct buffer_head *ext2_xattr_cache_find(struct inode *,
 						 struct ext2_xattr_header *);
 static void ext2_xattr_rehash(struct ext2_xattr_header *,
 			      struct ext2_xattr_entry *);
 
-static struct mb_cache *ext2_xattr_cache;
-
 static const struct xattr_handler *ext2_xattr_handler_map[] = {
 	[EXT2_XATTR_INDEX_USER]		     = &ext2_xattr_user_handler,
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
@@ -154,6 +153,7 @@
 	size_t name_len, size;
 	char *end;
 	int error;
+	struct mb_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
 
 	ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
 		  name_index, name, buffer, (long)buffer_size);
@@ -198,7 +198,7 @@
 			goto found;
 		entry = next;
 	}
-	if (ext2_xattr_cache_insert(bh))
+	if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
 		ea_idebug(inode, "cache insert failed");
 	error = -ENODATA;
 	goto cleanup;
@@ -211,7 +211,7 @@
 	    le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)
 		goto bad_block;
 
-	if (ext2_xattr_cache_insert(bh))
+	if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
 		ea_idebug(inode, "cache insert failed");
 	if (buffer) {
 		error = -ERANGE;
@@ -249,6 +249,7 @@
 	char *end;
 	size_t rest = buffer_size;
 	int error;
+	struct mb_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
 
 	ea_idebug(inode, "buffer=%p, buffer_size=%ld",
 		  buffer, (long)buffer_size);
@@ -283,7 +284,7 @@
 			goto bad_block;
 		entry = next;
 	}
-	if (ext2_xattr_cache_insert(bh))
+	if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
 		ea_idebug(inode, "cache insert failed");
 
 	/* list the attribute names */
@@ -480,22 +481,23 @@
 	/* Here we know that we can set the new attribute. */
 
 	if (header) {
-		struct mb_cache_entry *ce;
-
 		/* assert(header == HDR(bh)); */
-		ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev,
-					bh->b_blocknr);
 		lock_buffer(bh);
 		if (header->h_refcount == cpu_to_le32(1)) {
+			__u32 hash = le32_to_cpu(header->h_hash);
+
 			ea_bdebug(bh, "modifying in-place");
-			if (ce)
-				mb_cache_entry_free(ce);
+			/*
+			 * This must happen under buffer lock for
+			 * ext2_xattr_set2() to reliably detect modified block
+			 */
+			mb_cache_entry_delete_block(EXT2_SB(sb)->s_mb_cache,
+						    hash, bh->b_blocknr);
+
 			/* keep the buffer locked while modifying it. */
 		} else {
 			int offset;
 
-			if (ce)
-				mb_cache_entry_release(ce);
 			unlock_buffer(bh);
 			ea_bdebug(bh, "cloning");
 			header = kmalloc(bh->b_size, GFP_KERNEL);
@@ -605,9 +607,9 @@
 	}
 
 cleanup:
-	brelse(bh);
 	if (!(bh && header == HDR(bh)))
 		kfree(header);
+	brelse(bh);
 	up_write(&EXT2_I(inode)->xattr_sem);
 
 	return error;
@@ -623,6 +625,7 @@
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *new_bh = NULL;
 	int error;
+	struct mb_cache *ext2_mb_cache = EXT2_SB(sb)->s_mb_cache;
 
 	if (header) {
 		new_bh = ext2_xattr_cache_find(inode, header);
@@ -650,7 +653,7 @@
 			   don't need to change the reference count. */
 			new_bh = old_bh;
 			get_bh(new_bh);
-			ext2_xattr_cache_insert(new_bh);
+			ext2_xattr_cache_insert(ext2_mb_cache, new_bh);
 		} else {
 			/* We need to allocate a new block */
 			ext2_fsblk_t goal = ext2_group_first_block_no(sb,
@@ -671,7 +674,7 @@
 			memcpy(new_bh->b_data, header, new_bh->b_size);
 			set_buffer_uptodate(new_bh);
 			unlock_buffer(new_bh);
-			ext2_xattr_cache_insert(new_bh);
+			ext2_xattr_cache_insert(ext2_mb_cache, new_bh);
 			
 			ext2_xattr_update_super_block(sb);
 		}
@@ -704,19 +707,21 @@
 
 	error = 0;
 	if (old_bh && old_bh != new_bh) {
-		struct mb_cache_entry *ce;
-
 		/*
 		 * If there was an old block and we are no longer using it,
 		 * release the old block.
 		 */
-		ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev,
-					old_bh->b_blocknr);
 		lock_buffer(old_bh);
 		if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {
+			__u32 hash = le32_to_cpu(HDR(old_bh)->h_hash);
+
+			/*
+			 * This must happen under buffer lock for
+			 * ext2_xattr_set2() to reliably detect freed block
+			 */
+			mb_cache_entry_delete_block(ext2_mb_cache,
+						    hash, old_bh->b_blocknr);
 			/* Free the old block. */
-			if (ce)
-				mb_cache_entry_free(ce);
 			ea_bdebug(old_bh, "freeing");
 			ext2_free_blocks(inode, old_bh->b_blocknr, 1);
 			mark_inode_dirty(inode);
@@ -727,8 +732,6 @@
 		} else {
 			/* Decrement the refcount only. */
 			le32_add_cpu(&HDR(old_bh)->h_refcount, -1);
-			if (ce)
-				mb_cache_entry_release(ce);
 			dquot_free_block_nodirty(inode, 1);
 			mark_inode_dirty(inode);
 			mark_buffer_dirty(old_bh);
@@ -754,7 +757,6 @@
 ext2_xattr_delete_inode(struct inode *inode)
 {
 	struct buffer_head *bh = NULL;
-	struct mb_cache_entry *ce;
 
 	down_write(&EXT2_I(inode)->xattr_sem);
 	if (!EXT2_I(inode)->i_file_acl)
@@ -774,19 +776,22 @@
 			EXT2_I(inode)->i_file_acl);
 		goto cleanup;
 	}
-	ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr);
 	lock_buffer(bh);
 	if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
-		if (ce)
-			mb_cache_entry_free(ce);
+		__u32 hash = le32_to_cpu(HDR(bh)->h_hash);
+
+		/*
+		 * This must happen under buffer lock for ext2_xattr_set2() to
+		 * reliably detect freed block
+		 */
+		mb_cache_entry_delete_block(EXT2_SB(inode->i_sb)->s_mb_cache,
+					    hash, bh->b_blocknr);
 		ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1);
 		get_bh(bh);
 		bforget(bh);
 		unlock_buffer(bh);
 	} else {
 		le32_add_cpu(&HDR(bh)->h_refcount, -1);
-		if (ce)
-			mb_cache_entry_release(ce);
 		ea_bdebug(bh, "refcount now=%d",
 			le32_to_cpu(HDR(bh)->h_refcount));
 		unlock_buffer(bh);
@@ -803,18 +808,6 @@
 }
 
 /*
- * ext2_xattr_put_super()
- *
- * This is called when a file system is unmounted.
- */
-void
-ext2_xattr_put_super(struct super_block *sb)
-{
-	mb_cache_shrink(sb->s_bdev);
-}
-
-
-/*
  * ext2_xattr_cache_insert()
  *
  * Create a new entry in the extended attribute cache, and insert
@@ -823,28 +816,19 @@
  * Returns 0, or a negative error number on failure.
  */
 static int
-ext2_xattr_cache_insert(struct buffer_head *bh)
+ext2_xattr_cache_insert(struct mb_cache *cache, struct buffer_head *bh)
 {
 	__u32 hash = le32_to_cpu(HDR(bh)->h_hash);
-	struct mb_cache_entry *ce;
 	int error;
 
-	ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS);
-	if (!ce)
-		return -ENOMEM;
-	error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
+	error = mb_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr, 1);
 	if (error) {
-		mb_cache_entry_free(ce);
 		if (error == -EBUSY) {
-			ea_bdebug(bh, "already in cache (%d cache entries)",
-				atomic_read(&ext2_xattr_cache->c_entry_count));
+			ea_bdebug(bh, "already in cache");
 			error = 0;
 		}
-	} else {
-		ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,
-			  atomic_read(&ext2_xattr_cache->c_entry_count));
-		mb_cache_entry_release(ce);
-	}
+	} else
+		ea_bdebug(bh, "inserting [%x]", (int)hash);
 	return error;
 }
 
@@ -901,22 +885,16 @@
 {
 	__u32 hash = le32_to_cpu(header->h_hash);
 	struct mb_cache_entry *ce;
+	struct mb_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
 
 	if (!header->h_hash)
 		return NULL;  /* never share */
 	ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
 again:
-	ce = mb_cache_entry_find_first(ext2_xattr_cache, inode->i_sb->s_bdev,
-				       hash);
+	ce = mb_cache_entry_find_first(ext2_mb_cache, hash);
 	while (ce) {
 		struct buffer_head *bh;
 
-		if (IS_ERR(ce)) {
-			if (PTR_ERR(ce) == -EAGAIN)
-				goto again;
-			break;
-		}
-
 		bh = sb_bread(inode->i_sb, ce->e_block);
 		if (!bh) {
 			ext2_error(inode->i_sb, "ext2_xattr_cache_find",
@@ -924,7 +902,21 @@
 				inode->i_ino, (unsigned long) ce->e_block);
 		} else {
 			lock_buffer(bh);
-			if (le32_to_cpu(HDR(bh)->h_refcount) >
+			/*
+			 * We have to be careful about races with freeing or
+			 * rehashing of xattr block. Once we hold buffer lock
+			 * xattr block's state is stable so we can check
+			 * whether the block got freed / rehashed or not.
+			 * Since we unhash mbcache entry under buffer lock when
+			 * freeing / rehashing xattr block, checking whether
+			 * entry is still hashed is reliable.
+			 */
+			if (hlist_bl_unhashed(&ce->e_hash_list)) {
+				mb_cache_entry_put(ext2_mb_cache, ce);
+				unlock_buffer(bh);
+				brelse(bh);
+				goto again;
+			} else if (le32_to_cpu(HDR(bh)->h_refcount) >
 				   EXT2_XATTR_REFCOUNT_MAX) {
 				ea_idebug(inode, "block %ld refcount %d>%d",
 					  (unsigned long) ce->e_block,
@@ -933,13 +925,14 @@
 			} else if (!ext2_xattr_cmp(header, HDR(bh))) {
 				ea_bdebug(bh, "b_count=%d",
 					  atomic_read(&(bh->b_count)));
-				mb_cache_entry_release(ce);
+				mb_cache_entry_touch(ext2_mb_cache, ce);
+				mb_cache_entry_put(ext2_mb_cache, ce);
 				return bh;
 			}
 			unlock_buffer(bh);
 			brelse(bh);
 		}
-		ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
+		ce = mb_cache_entry_find_next(ext2_mb_cache, ce);
 	}
 	return NULL;
 }
@@ -1012,17 +1005,15 @@
 
 #undef BLOCK_HASH_SHIFT
 
-int __init
-init_ext2_xattr(void)
+#define HASH_BUCKET_BITS 10
+
+struct mb_cache *ext2_xattr_create_cache(void)
 {
-	ext2_xattr_cache = mb_cache_create("ext2_xattr", 6);
-	if (!ext2_xattr_cache)
-		return -ENOMEM;
-	return 0;
+	return mb_cache_create(HASH_BUCKET_BITS);
 }
 
-void
-exit_ext2_xattr(void)
+void ext2_xattr_destroy_cache(struct mb_cache *cache)
 {
-	mb_cache_destroy(ext2_xattr_cache);
+	if (cache)
+		mb_cache_destroy(cache);
 }
--- linux-4.4.0.orig/fs/ext2/xattr.h
+++ linux-4.4.0/fs/ext2/xattr.h
@@ -53,6 +53,8 @@
 #define EXT2_XATTR_SIZE(size) \
 	(((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)
 
+struct mb_cache;
+
 # ifdef CONFIG_EXT2_FS_XATTR
 
 extern const struct xattr_handler ext2_xattr_user_handler;
@@ -65,10 +67,9 @@
 extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
 
 extern void ext2_xattr_delete_inode(struct inode *);
-extern void ext2_xattr_put_super(struct super_block *);
 
-extern int init_ext2_xattr(void);
-extern void exit_ext2_xattr(void);
+extern struct mb_cache *ext2_xattr_create_cache(void);
+extern void ext2_xattr_destroy_cache(struct mb_cache *cache);
 
 extern const struct xattr_handler *ext2_xattr_handlers[];
 
@@ -93,19 +94,7 @@
 {
 }
 
-static inline void
-ext2_xattr_put_super(struct super_block *sb)
-{
-}
-
-static inline int
-init_ext2_xattr(void)
-{
-	return 0;
-}
-
-static inline void
-exit_ext2_xattr(void)
+static inline void ext2_xattr_destroy_cache(struct mb_cache *cache)
 {
 }
 
--- linux-4.4.0.orig/fs/ext4/acl.c
+++ linux-4.4.0/fs/ext4/acl.c
@@ -13,7 +13,7 @@
  * Convert from filesystem to in-memory representation.
  */
 static struct posix_acl *
-ext4_acl_from_disk(const void *value, size_t size)
+ext4_acl_from_disk(struct super_block *sb, const void *value, size_t size)
 {
 	const char *end = (char *)value + size;
 	int n, count;
@@ -57,16 +57,20 @@
 			if ((char *)value > end)
 				goto fail;
 			acl->a_entries[n].e_uid =
-				make_kuid(&init_user_ns,
+				make_kuid(sb->s_user_ns,
 					  le32_to_cpu(entry->e_id));
+			if (!uid_valid(acl->a_entries[n].e_uid))
+				goto fail;
 			break;
 		case ACL_GROUP:
 			value = (char *)value + sizeof(ext4_acl_entry);
 			if ((char *)value > end)
 				goto fail;
 			acl->a_entries[n].e_gid =
-				make_kgid(&init_user_ns,
+				make_kgid(sb->s_user_ns,
 					  le32_to_cpu(entry->e_id));
+			if (!gid_valid(acl->a_entries[n].e_gid))
+				goto fail;
 			break;
 
 		default:
@@ -86,11 +90,14 @@
  * Convert from in-memory to filesystem representation.
  */
 static void *
-ext4_acl_to_disk(const struct posix_acl *acl, size_t *size)
+ext4_acl_to_disk(struct super_block *sb, const struct posix_acl *acl,
+		 size_t *size)
 {
 	ext4_acl_header *ext_acl;
 	char *e;
 	size_t n;
+	uid_t uid;
+	gid_t gid;
 
 	*size = ext4_acl_size(acl->a_count);
 	ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count *
@@ -106,13 +113,17 @@
 		entry->e_perm = cpu_to_le16(acl_e->e_perm);
 		switch (acl_e->e_tag) {
 		case ACL_USER:
-			entry->e_id = cpu_to_le32(
-				from_kuid(&init_user_ns, acl_e->e_uid));
+			uid = from_kuid(sb->s_user_ns, acl_e->e_uid);
+			if (uid == (uid_t)-1)
+				goto fail;
+			entry->e_id = cpu_to_le32(uid);
 			e += sizeof(ext4_acl_entry);
 			break;
 		case ACL_GROUP:
-			entry->e_id = cpu_to_le32(
-				from_kgid(&init_user_ns, acl_e->e_gid));
+			gid = from_kgid(sb->s_user_ns, acl_e->e_gid);
+			if (gid == (gid_t)-1)
+				goto fail;
+			entry->e_id = cpu_to_le32(gid);
 			e += sizeof(ext4_acl_entry);
 			break;
 
@@ -165,7 +176,7 @@
 		retval = ext4_xattr_get(inode, name_index, "", value, retval);
 	}
 	if (retval > 0)
-		acl = ext4_acl_from_disk(value, retval);
+		acl = ext4_acl_from_disk(inode->i_sb, value, retval);
 	else if (retval == -ENODATA || retval == -ENOSYS)
 		acl = NULL;
 	else
@@ -195,17 +206,6 @@
 	switch (type) {
 	case ACL_TYPE_ACCESS:
 		name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
-		if (acl) {
-			error = posix_acl_equiv_mode(acl, &inode->i_mode);
-			if (error < 0)
-				return error;
-			else {
-				inode->i_ctime = ext4_current_time(inode);
-				ext4_mark_inode_dirty(handle, inode);
-				if (error == 0)
-					acl = NULL;
-			}
-		}
 		break;
 
 	case ACL_TYPE_DEFAULT:
@@ -218,7 +218,7 @@
 		return -EINVAL;
 	}
 	if (acl) {
-		value = ext4_acl_to_disk(acl, &size);
+		value = ext4_acl_to_disk(inode->i_sb, acl, &size);
 		if (IS_ERR(value))
 			return (int)PTR_ERR(value);
 	}
@@ -238,6 +238,8 @@
 {
 	handle_t *handle;
 	int error, retries = 0;
+	umode_t mode = inode->i_mode;
+	int update_mode = 0;
 
 retry:
 	handle = ext4_journal_start(inode, EXT4_HT_XATTR,
@@ -245,7 +247,20 @@
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
 
+	if ((type == ACL_TYPE_ACCESS) && acl) {
+		error = posix_acl_update_mode(inode, &mode, &acl);
+		if (error)
+			goto out_stop;
+		update_mode = 1;
+	}
+
 	error = __ext4_set_acl(handle, inode, type, acl);
+	if (!error && update_mode) {
+		inode->i_mode = mode;
+		inode->i_ctime = ext4_current_time(inode);
+		ext4_mark_inode_dirty(handle, inode);
+	}
+out_stop:
 	ext4_journal_stop(handle);
 	if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
 		goto retry;
--- linux-4.4.0.orig/fs/ext4/balloc.c
+++ linux-4.4.0/fs/ext4/balloc.c
@@ -183,7 +183,6 @@
 	unsigned int bit, bit_max;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	ext4_fsblk_t start, tmp;
-	int flex_bg = 0;
 	struct ext4_group_info *grp;
 
 	J_ASSERT_BH(bh, buffer_locked(bh));
@@ -191,7 +190,6 @@
 	/* If checksum is bad mark all blocks used to prevent allocation
 	 * essentially implementing a per-group read-only flag. */
 	if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
-		ext4_error(sb, "Checksum bad for group %u", block_group);
 		grp = ext4_get_group_info(sb, block_group);
 		if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
 			percpu_counter_sub(&sbi->s_freeclusters_counter,
@@ -209,27 +207,27 @@
 	memset(bh->b_data, 0, sb->s_blocksize);
 
 	bit_max = ext4_num_base_meta_clusters(sb, block_group);
+	if ((bit_max >> 3) >= bh->b_size)
+		return -EFSCORRUPTED;
+
 	for (bit = 0; bit < bit_max; bit++)
 		ext4_set_bit(bit, bh->b_data);
 
 	start = ext4_group_first_block_no(sb, block_group);
 
-	if (ext4_has_feature_flex_bg(sb))
-		flex_bg = 1;
-
 	/* Set bits for block and inode bitmaps, and inode table */
 	tmp = ext4_block_bitmap(sb, gdp);
-	if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
+	if (ext4_block_in_group(sb, tmp, block_group))
 		ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
 
 	tmp = ext4_inode_bitmap(sb, gdp);
-	if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
+	if (ext4_block_in_group(sb, tmp, block_group))
 		ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
 
 	tmp = ext4_inode_table(sb, gdp);
 	for (; tmp < ext4_inode_table(sb, gdp) +
 		     sbi->s_itb_per_group; tmp++) {
-		if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
+		if (ext4_block_in_group(sb, tmp, block_group))
 			ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
 	}
 
@@ -240,8 +238,6 @@
 	 */
 	ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
 			     sb->s_blocksize * 8, bh->b_data);
-	ext4_block_bitmap_csum_set(sb, block_group, gdp, bh);
-	ext4_group_desc_csum_set(sb, block_group, gdp);
 	return 0;
 }
 
@@ -283,6 +279,7 @@
 	ext4_group_t ngroups = ext4_get_groups_count(sb);
 	struct ext4_group_desc *desc;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct buffer_head *bh_p;
 
 	if (block_group >= ngroups) {
 		ext4_error(sb, "block_group >= groups_count - block_group = %u,"
@@ -293,7 +290,14 @@
 
 	group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
 	offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
-	if (!sbi->s_group_desc[group_desc]) {
+	bh_p = sbi_array_rcu_deref(sbi, s_group_desc, group_desc);
+	/*
+	 * sbi_array_rcu_deref returns with rcu unlocked, this is ok since
+	 * the pointer being dereferenced won't be dereferenced again. By
+	 * looking at the usage in add_new_gdb() the value isn't modified,
+	 * just the pointer, and so it remains valid.
+	 */
+	if (!bh_p) {
 		ext4_error(sb, "Group descriptor not loaded - "
 			   "block_group = %u, group_desc = %u, desc = %u",
 			   block_group, group_desc, offset);
@@ -301,10 +305,10 @@
 	}
 
 	desc = (struct ext4_group_desc *)(
-		(__u8 *)sbi->s_group_desc[group_desc]->b_data +
+		(__u8 *)bh_p->b_data +
 		offset * EXT4_DESC_SIZE(sb));
 	if (bh)
-		*bh = sbi->s_group_desc[group_desc];
+		*bh = bh_p;
 	return desc;
 }
 
@@ -320,6 +324,7 @@
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	ext4_grpblk_t offset;
 	ext4_grpblk_t next_zero_bit;
+	ext4_grpblk_t max_bit = EXT4_CLUSTERS_PER_GROUP(sb);
 	ext4_fsblk_t blk;
 	ext4_fsblk_t group_first_block;
 
@@ -337,20 +342,25 @@
 	/* check whether block bitmap block number is set */
 	blk = ext4_block_bitmap(sb, desc);
 	offset = blk - group_first_block;
-	if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
+	if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
+	    !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
 		/* bad block bitmap */
 		return blk;
 
 	/* check whether the inode bitmap block number is set */
 	blk = ext4_inode_bitmap(sb, desc);
 	offset = blk - group_first_block;
-	if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
+	if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
+	    !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
 		/* bad block bitmap */
 		return blk;
 
 	/* check whether the inode table block number is set */
 	blk = ext4_inode_table(sb, desc);
 	offset = blk - group_first_block;
+	if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
+	    EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= max_bit)
+		return blk;
 	next_zero_bit = ext4_find_next_zero_bit(bh->b_data,
 			EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group),
 			EXT4_B2C(sbi, offset));
@@ -376,6 +386,8 @@
 		return -EFSCORRUPTED;
 
 	ext4_lock_group(sb, block_group);
+	if (buffer_verified(bh))
+		goto verified;
 	if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group,
 			desc, bh))) {
 		ext4_unlock_group(sb, block_group);
@@ -398,6 +410,7 @@
 		return -EFSCORRUPTED;
 	}
 	set_buffer_verified(bh);
+verified:
 	ext4_unlock_group(sb, block_group);
 	return 0;
 }
@@ -416,6 +429,7 @@
 ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
 {
 	struct ext4_group_desc *desc;
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct buffer_head *bh;
 	ext4_fsblk_t bitmap_blk;
 	int err;
@@ -424,6 +438,12 @@
 	if (!desc)
 		return ERR_PTR(-EFSCORRUPTED);
 	bitmap_blk = ext4_block_bitmap(sb, desc);
+	if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
+	    (bitmap_blk >= ext4_blocks_count(sbi->s_es))) {
+		ext4_error(sb, "Invalid block bitmap block %llu in "
+			   "block_group %u", bitmap_blk, block_group);
+		return ERR_PTR(-EFSCORRUPTED);
+	}
 	bh = sb_getblk(sb, bitmap_blk);
 	if (unlikely(!bh)) {
 		ext4_error(sb, "Cannot get buffer for block bitmap - "
@@ -441,15 +461,27 @@
 		goto verify;
 	}
 	ext4_lock_group(sb, block_group);
-	if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
-
+	if (ext4_has_group_desc_csum(sb) &&
+	    (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
+		if (block_group == 0) {
+			ext4_unlock_group(sb, block_group);
+			unlock_buffer(bh);
+			ext4_error(sb, "Block bitmap for bg 0 marked "
+				   "uninitialized");
+			err = -EFSCORRUPTED;
+			goto out;
+		}
 		err = ext4_init_block_bitmap(sb, bh, block_group, desc);
 		set_bitmap_uptodate(bh);
 		set_buffer_uptodate(bh);
+		set_buffer_verified(bh);
 		ext4_unlock_group(sb, block_group);
 		unlock_buffer(bh);
-		if (err)
+		if (err) {
+			ext4_error(sb, "Failed to init block bitmap for group "
+				   "%u: %d", block_group, err);
 			goto out;
+		}
 		goto verify;
 	}
 	ext4_unlock_group(sb, block_group);
@@ -561,8 +593,8 @@
 
 	/* Hm, nope.  Are (enough) root reserved clusters available? */
 	if (uid_eq(sbi->s_resuid, current_fsuid()) ||
-	    (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) ||
-	    capable(CAP_SYS_RESOURCE) ||
+	    (!gid_eq(sbi->s_resgid, make_kgid(sbi->s_sb->s_user_ns, 0)) && in_group_p(sbi->s_resgid)) ||
+	    ns_capable(sbi->s_sb->s_user_ns, CAP_SYS_RESOURCE) ||
 	    (flags & EXT4_MB_USE_ROOT_BLOCKS)) {
 
 		if (free_clusters >= (nclusters + dirty_clusters +
--- linux-4.4.0.orig/fs/ext4/block_validity.c
+++ linux-4.4.0/fs/ext4/block_validity.c
@@ -23,6 +23,7 @@
 	struct rb_node	node;
 	ext4_fsblk_t	start_blk;
 	unsigned int	count;
+	u32		ino;
 };
 
 static struct kmem_cache *ext4_system_zone_cachep;
@@ -43,7 +44,8 @@
 static inline int can_merge(struct ext4_system_zone *entry1,
 		     struct ext4_system_zone *entry2)
 {
-	if ((entry1->start_blk + entry1->count) == entry2->start_blk)
+	if ((entry1->start_blk + entry1->count) == entry2->start_blk &&
+	    entry1->ino == entry2->ino)
 		return 1;
 	return 0;
 }
@@ -55,9 +57,9 @@
  */
 static int add_system_zone(struct ext4_sb_info *sbi,
 			   ext4_fsblk_t start_blk,
-			   unsigned int count)
+			   unsigned int count, u32 ino)
 {
-	struct ext4_system_zone *new_entry = NULL, *entry;
+	struct ext4_system_zone *new_entry, *entry;
 	struct rb_node **n = &sbi->system_blks.rb_node, *node;
 	struct rb_node *parent = NULL, *new_node = NULL;
 
@@ -68,30 +70,21 @@
 			n = &(*n)->rb_left;
 		else if (start_blk >= (entry->start_blk + entry->count))
 			n = &(*n)->rb_right;
-		else {
-			if (start_blk + count > (entry->start_blk +
-						 entry->count))
-				entry->count = (start_blk + count -
-						entry->start_blk);
-			new_node = *n;
-			new_entry = rb_entry(new_node, struct ext4_system_zone,
-					     node);
-			break;
-		}
+		else	/* Unexpected overlap of system zones. */
+			return -EFSCORRUPTED;
 	}
 
-	if (!new_entry) {
-		new_entry = kmem_cache_alloc(ext4_system_zone_cachep,
-					     GFP_KERNEL);
-		if (!new_entry)
-			return -ENOMEM;
-		new_entry->start_blk = start_blk;
-		new_entry->count = count;
-		new_node = &new_entry->node;
+	new_entry = kmem_cache_alloc(ext4_system_zone_cachep,
+				     GFP_KERNEL);
+	if (!new_entry)
+		return -ENOMEM;
+	new_entry->start_blk = start_blk;
+	new_entry->count = count;
+	new_entry->ino = ino;
+	new_node = &new_entry->node;
 
-		rb_link_node(new_node, parent, n);
-		rb_insert_color(new_node, &sbi->system_blks);
-	}
+	rb_link_node(new_node, parent, n);
+	rb_insert_color(new_node, &sbi->system_blks);
 
 	/* Can we merge to the left? */
 	node = rb_prev(new_node);
@@ -136,6 +129,50 @@
 	printk("\n");
 }
 
+static int ext4_protect_reserved_inode(struct super_block *sb, u32 ino)
+{
+	struct inode *inode;
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct ext4_map_blocks map;
+	u32 i = 0, num;
+	int err = 0, n;
+
+	if ((ino < EXT4_ROOT_INO) ||
+	    (ino > le32_to_cpu(sbi->s_es->s_inodes_count)))
+		return -EINVAL;
+	inode = ext4_iget(sb, ino, EXT4_IGET_SPECIAL);
+	if (IS_ERR(inode))
+		return PTR_ERR(inode);
+	num = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+	while (i < num) {
+		cond_resched();
+		map.m_lblk = i;
+		map.m_len = num - i;
+		n = ext4_map_blocks(NULL, inode, &map, 0);
+		if (n < 0) {
+			err = n;
+			break;
+		}
+		if (n == 0) {
+			i++;
+		} else {
+			err = add_system_zone(sbi, map.m_pblk, n, ino);
+			if (err < 0) {
+				if (err == -EFSCORRUPTED) {
+					ext4_error(sb,
+					   "blocks %llu-%llu from inode %u "
+					   "overlap system zone", map.m_pblk,
+					   map.m_pblk + map.m_len - 1, ino);
+				}
+				break;
+			}
+			i += n;
+		}
+	}
+	iput(inode);
+	return err;
+}
+
 int ext4_setup_system_zone(struct super_block *sb)
 {
 	ext4_group_t ngroups = ext4_get_groups_count(sb);
@@ -157,16 +194,22 @@
 		if (ext4_bg_has_super(sb, i) &&
 		    ((i < 5) || ((i % flex_size) == 0)))
 			add_system_zone(sbi, ext4_group_first_block_no(sb, i),
-					ext4_bg_num_gdb(sb, i) + 1);
+					ext4_bg_num_gdb(sb, i) + 1, 0);
 		gdp = ext4_get_group_desc(sb, i, NULL);
-		ret = add_system_zone(sbi, ext4_block_bitmap(sb, gdp), 1);
+		ret = add_system_zone(sbi, ext4_block_bitmap(sb, gdp), 1, 0);
 		if (ret)
 			return ret;
-		ret = add_system_zone(sbi, ext4_inode_bitmap(sb, gdp), 1);
+		ret = add_system_zone(sbi, ext4_inode_bitmap(sb, gdp), 1, 0);
 		if (ret)
 			return ret;
 		ret = add_system_zone(sbi, ext4_inode_table(sb, gdp),
-				sbi->s_itb_per_group);
+				sbi->s_itb_per_group, 0);
+		if (ret)
+			return ret;
+	}
+	if (ext4_has_feature_journal(sb) && sbi->s_es->s_journal_inum) {
+		ret = ext4_protect_reserved_inode(sb,
+				le32_to_cpu(sbi->s_es->s_journal_inum));
 		if (ret)
 			return ret;
 	}
@@ -193,10 +236,11 @@
  * start_blk+count) is valid; 0 if some part of the block region
  * overlaps with filesystem metadata blocks.
  */
-int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
-			  unsigned int count)
+int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk,
+			   unsigned int count)
 {
 	struct ext4_system_zone *entry;
+	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 	struct rb_node *n = sbi->system_blks.rb_node;
 
 	if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
@@ -212,6 +256,8 @@
 		else if (start_blk >= (entry->start_blk + entry->count))
 			n = n->rb_right;
 		else {
+			if (entry->ino == inode->i_ino)
+				return 1;
 			sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
 			return 0;
 		}
@@ -226,11 +272,15 @@
 	__le32 *bref = p;
 	unsigned int blk;
 
+	if (ext4_has_feature_journal(inode->i_sb) &&
+	    (inode->i_ino ==
+	     le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
+		return 0;
+
 	while (bref < p+max) {
 		blk = le32_to_cpu(*bref++);
 		if (blk &&
-		    unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
-						    blk, 1))) {
+		    unlikely(!ext4_inode_block_valid(inode, blk, 1))) {
 			es->s_last_error_block = cpu_to_le64(blk);
 			ext4_error_inode(inode, function, line, blk,
 					 "invalid block");
--- linux-4.4.0.orig/fs/ext4/crypto.c
+++ linux-4.4.0/fs/ext4/crypto.c
@@ -34,6 +34,7 @@
 #include <linux/random.h>
 #include <linux/scatterlist.h>
 #include <linux/spinlock_types.h>
+#include <linux/namei.h>
 
 #include "ext4_extents.h"
 #include "xattr.h"
@@ -93,7 +94,8 @@
  * Return: An allocated and initialized encryption context on success; error
  * value or NULL otherwise.
  */
-struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode)
+struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode,
+					    gfp_t gfp_flags)
 {
 	struct ext4_crypto_ctx *ctx = NULL;
 	int res = 0;
@@ -120,7 +122,7 @@
 		list_del(&ctx->free_list);
 	spin_unlock_irqrestore(&ext4_crypto_ctx_lock, flags);
 	if (!ctx) {
-		ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, GFP_NOFS);
+		ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, gfp_flags);
 		if (!ctx) {
 			res = -ENOMEM;
 			goto out;
@@ -257,7 +259,8 @@
 			    ext4_direction_t rw,
 			    pgoff_t index,
 			    struct page *src_page,
-			    struct page *dest_page)
+			    struct page *dest_page,
+			    gfp_t gfp_flags)
 
 {
 	u8 xts_tweak[EXT4_XTS_TWEAK_SIZE];
@@ -268,7 +271,7 @@
 	struct crypto_ablkcipher *tfm = ci->ci_ctfm;
 	int res = 0;
 
-	req = ablkcipher_request_alloc(tfm, GFP_NOFS);
+	req = ablkcipher_request_alloc(tfm, gfp_flags);
 	if (!req) {
 		printk_ratelimited(KERN_ERR
 				   "%s: crypto_request_alloc() failed\n",
@@ -309,9 +312,10 @@
 	return 0;
 }
 
-static struct page *alloc_bounce_page(struct ext4_crypto_ctx *ctx)
+static struct page *alloc_bounce_page(struct ext4_crypto_ctx *ctx,
+				      gfp_t gfp_flags)
 {
-	ctx->w.bounce_page = mempool_alloc(ext4_bounce_page_pool, GFP_NOWAIT);
+	ctx->w.bounce_page = mempool_alloc(ext4_bounce_page_pool, gfp_flags);
 	if (ctx->w.bounce_page == NULL)
 		return ERR_PTR(-ENOMEM);
 	ctx->flags |= EXT4_WRITE_PATH_FL;
@@ -334,7 +338,8 @@
  * error value or NULL.
  */
 struct page *ext4_encrypt(struct inode *inode,
-			  struct page *plaintext_page)
+			  struct page *plaintext_page,
+			  gfp_t gfp_flags)
 {
 	struct ext4_crypto_ctx *ctx;
 	struct page *ciphertext_page = NULL;
@@ -342,17 +347,17 @@
 
 	BUG_ON(!PageLocked(plaintext_page));
 
-	ctx = ext4_get_crypto_ctx(inode);
+	ctx = ext4_get_crypto_ctx(inode, gfp_flags);
 	if (IS_ERR(ctx))
 		return (struct page *) ctx;
 
 	/* The encryption operation will require a bounce page. */
-	ciphertext_page = alloc_bounce_page(ctx);
+	ciphertext_page = alloc_bounce_page(ctx, gfp_flags);
 	if (IS_ERR(ciphertext_page))
 		goto errout;
 	ctx->w.control_page = plaintext_page;
 	err = ext4_page_crypto(inode, EXT4_ENCRYPT, plaintext_page->index,
-			       plaintext_page, ciphertext_page);
+			       plaintext_page, ciphertext_page, gfp_flags);
 	if (err) {
 		ciphertext_page = ERR_PTR(err);
 	errout:
@@ -380,8 +385,8 @@
 {
 	BUG_ON(!PageLocked(page));
 
-	return ext4_page_crypto(page->mapping->host,
-				EXT4_DECRYPT, page->index, page, page);
+	return ext4_page_crypto(page->mapping->host, EXT4_DECRYPT,
+				page->index, page, page, GFP_NOFS);
 }
 
 int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
@@ -402,11 +407,11 @@
 
 	BUG_ON(inode->i_sb->s_blocksize != PAGE_CACHE_SIZE);
 
-	ctx = ext4_get_crypto_ctx(inode);
+	ctx = ext4_get_crypto_ctx(inode, GFP_NOFS);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ciphertext_page = alloc_bounce_page(ctx);
+	ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT);
 	if (IS_ERR(ciphertext_page)) {
 		err = PTR_ERR(ciphertext_page);
 		goto errout;
@@ -414,11 +419,12 @@
 
 	while (len--) {
 		err = ext4_page_crypto(inode, EXT4_ENCRYPT, lblk,
-				       ZERO_PAGE(0), ciphertext_page);
+				       ZERO_PAGE(0), ciphertext_page,
+				       GFP_NOFS);
 		if (err)
 			goto errout;
 
-		bio = bio_alloc(GFP_KERNEL, 1);
+		bio = bio_alloc(GFP_NOWAIT, 1);
 		if (!bio) {
 			err = -ENOMEM;
 			goto errout;
@@ -469,3 +475,61 @@
 		return size;
 	return 0;
 }
+
+/*
+ * Validate dentries for encrypted directories to make sure we aren't
+ * potentially caching stale data after a key has been added or
+ * removed.
+ */
+static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+	struct dentry *dir;
+	struct ext4_crypt_info *ci;
+	int dir_has_key, cached_with_key;
+
+	if (flags & LOOKUP_RCU)
+		return -ECHILD;
+
+	dir = dget_parent(dentry);
+	if (!ext4_encrypted_inode(d_inode(dir))) {
+		dput(dir);
+		return 0;
+	}
+	ci = EXT4_I(d_inode(dir))->i_crypt_info;
+
+	/* this should eventually be an flag in d_flags */
+	cached_with_key = dentry->d_fsdata != NULL;
+	dir_has_key = (ci != NULL);
+	dput(dir);
+
+	/*
+	 * If the dentry was cached without the key, and it is a
+	 * negative dentry, it might be a valid name.  We can't check
+	 * if the key has since been made available due to locking
+	 * reasons, so we fail the validation so ext4_lookup() can do
+	 * this check.
+	 *
+	 * We also fail the validation if the dentry was created with
+	 * the key present, but we no longer have the key, or vice versa.
+	 */
+	if ((!cached_with_key && d_is_negative(dentry)) ||
+	    (!cached_with_key && dir_has_key) ||
+	    (cached_with_key && !dir_has_key)) {
+#if 0				/* Revalidation debug */
+		char buf[80];
+		char *cp = simple_dname(dentry, buf, sizeof(buf));
+
+		if (IS_ERR(cp))
+			cp = (char *) "???";
+		pr_err("revalidate: %s %p %d %d %d\n", cp, dentry->d_fsdata,
+		       cached_with_key, d_is_negative(dentry),
+		       dir_has_key);
+#endif
+		return 0;
+	}
+	return 1;
+}
+
+const struct dentry_operations ext4_encrypted_d_ops = {
+	.d_revalidate = ext4_d_revalidate,
+};
--- linux-4.4.0.orig/fs/ext4/crypto_fname.c
+++ linux-4.4.0/fs/ext4/crypto_fname.c
@@ -343,7 +343,7 @@
 		memcpy(buf+4, &hinfo->minor_hash, 4);
 	} else
 		memset(buf, 0, 8);
-	memcpy(buf + 8, iname->name + iname->len - 16, 16);
+	memcpy(buf + 8, iname->name + ((iname->len - 17) & ~15), 16);
 	oname->name[0] = '_';
 	ret = digest_encode(buf, 24, oname->name+1);
 	oname->len = ret + 1;
--- linux-4.4.0.orig/fs/ext4/crypto_key.c
+++ linux-4.4.0/fs/ext4/crypto_key.c
@@ -88,8 +88,6 @@
 	if (!ci)
 		return;
 
-	if (ci->ci_keyring_key)
-		key_put(ci->ci_keyring_key);
 	crypto_free_ablkcipher(ci->ci_ctfm);
 	kmem_cache_free(ext4_crypt_info_cachep, ci);
 }
@@ -111,7 +109,7 @@
 	ext4_free_crypt_info(ci);
 }
 
-int _ext4_get_encryption_info(struct inode *inode)
+int ext4_get_encryption_info(struct inode *inode)
 {
 	struct ext4_inode_info *ei = EXT4_I(inode);
 	struct ext4_crypt_info *crypt_info;
@@ -128,21 +126,12 @@
 	char mode;
 	int res;
 
-	if (!ext4_read_workqueue) {
-		res = ext4_init_crypto();
-		if (res)
-			return res;
-	}
+	if (ei->i_crypt_info)
+		return 0;
 
-retry:
-	crypt_info = ACCESS_ONCE(ei->i_crypt_info);
-	if (crypt_info) {
-		if (!crypt_info->ci_keyring_key ||
-		    key_validate(crypt_info->ci_keyring_key) == 0)
-			return 0;
-		ext4_free_encryption_info(inode, crypt_info);
-		goto retry;
-	}
+	res = ext4_init_crypto();
+	if (res)
+		return res;
 
 	res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 				 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
@@ -166,7 +155,6 @@
 	crypt_info->ci_data_mode = ctx.contents_encryption_mode;
 	crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
 	crypt_info->ci_ctfm = NULL;
-	crypt_info->ci_keyring_key = NULL;
 	memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
 	       sizeof(crypt_info->ci_master_key));
 	if (S_ISREG(inode->i_mode))
@@ -206,16 +194,23 @@
 		keyring_key = NULL;
 		goto out;
 	}
-	crypt_info->ci_keyring_key = keyring_key;
 	if (keyring_key->type != &key_type_logon) {
 		printk_once(KERN_WARNING
 			    "ext4: key type must be logon\n");
 		res = -ENOKEY;
 		goto out;
 	}
+	down_read(&keyring_key->sem);
 	ukp = user_key_payload(keyring_key);
+	if (!ukp) {
+		/* key was revoked before we acquired its semaphore */
+		res = -EKEYREVOKED;
+		up_read(&keyring_key->sem);
+		goto out;
+	}
 	if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
 		res = -EINVAL;
+		up_read(&keyring_key->sem);
 		goto out;
 	}
 	master_key = (struct ext4_encryption_key *)ukp->data;
@@ -226,10 +221,12 @@
 			    "ext4: key size incorrect: %d\n",
 			    master_key->size);
 		res = -ENOKEY;
+		up_read(&keyring_key->sem);
 		goto out;
 	}
 	res = ext4_derive_key_aes(ctx.nonce, master_key->raw,
 				  raw_key);
+	up_read(&keyring_key->sem);
 	if (res)
 		goto out;
 got_key:
@@ -249,16 +246,13 @@
 				       ext4_encryption_key_size(mode));
 	if (res)
 		goto out;
-	memzero_explicit(raw_key, sizeof(raw_key));
-	if (cmpxchg(&ei->i_crypt_info, NULL, crypt_info) != NULL) {
-		ext4_free_crypt_info(crypt_info);
-		goto retry;
-	}
-	return 0;
 
+	if (cmpxchg(&ei->i_crypt_info, NULL, crypt_info) == NULL)
+		crypt_info = NULL;
 out:
 	if (res == -ENOKEY)
 		res = 0;
+	key_put(keyring_key);
 	ext4_free_crypt_info(crypt_info);
 	memzero_explicit(raw_key, sizeof(raw_key));
 	return res;
--- linux-4.4.0.orig/fs/ext4/crypto_policy.c
+++ linux-4.4.0/fs/ext4/crypto_policy.c
@@ -102,12 +102,17 @@
 int ext4_process_policy(const struct ext4_encryption_policy *policy,
 			struct inode *inode)
 {
+	if (!inode_owner_or_capable(inode))
+		return -EACCES;
+
 	if (policy->version != 0)
 		return -EINVAL;
 
 	if (!ext4_inode_has_encryption_context(inode)) {
 		if (!S_ISDIR(inode->i_mode))
 			return -EINVAL;
+		if (IS_DEADDIR(inode))
+			return -ENOENT;
 		if (!ext4_empty_dir(inode))
 			return -ENOTEMPTY;
 		return ext4_create_encryption_context_from_policy(inode,
@@ -145,20 +150,38 @@
 int ext4_is_child_context_consistent_with_parent(struct inode *parent,
 						 struct inode *child)
 {
-	struct ext4_crypt_info *parent_ci, *child_ci;
+	const struct ext4_crypt_info *parent_ci, *child_ci;
+	struct ext4_encryption_context parent_ctx, child_ctx;
 	int res;
 
-	if ((parent == NULL) || (child == NULL)) {
-		pr_err("parent %p child %p\n", parent, child);
-		WARN_ON(1);	/* Should never happen */
-		return 0;
-	}
-	/* no restrictions if the parent directory is not encrypted */
+	/* No restrictions on file types which are never encrypted */
+	if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
+	    !S_ISLNK(child->i_mode))
+		return 1;
+
+	/* No restrictions if the parent directory is unencrypted */
 	if (!ext4_encrypted_inode(parent))
 		return 1;
-	/* if the child directory is not encrypted, this is always a problem */
+
+	/* Encrypted directories must not contain unencrypted files */
 	if (!ext4_encrypted_inode(child))
 		return 0;
+
+	/*
+	 * Both parent and child are encrypted, so verify they use the same
+	 * encryption policy.  Compare the fscrypt_info structs if the keys are
+	 * available, otherwise retrieve and compare the fscrypt_contexts.
+	 *
+	 * Note that the fscrypt_context retrieval will be required frequently
+	 * when accessing an encrypted directory tree without the key.
+	 * Performance-wise this is not a big deal because we already don't
+	 * really optimize for file access without the key (to the extent that
+	 * such access is even possible), given that any attempted access
+	 * already causes a fscrypt_context retrieval and keyring search.
+	 *
+	 * In any case, if an unexpected error occurs, fall back to "forbidden".
+	 */
+
 	res = ext4_get_encryption_info(parent);
 	if (res)
 		return 0;
@@ -167,17 +190,35 @@
 		return 0;
 	parent_ci = EXT4_I(parent)->i_crypt_info;
 	child_ci = EXT4_I(child)->i_crypt_info;
-	if (!parent_ci && !child_ci)
-		return 1;
-	if (!parent_ci || !child_ci)
-		return 0;
+	if (parent_ci && child_ci) {
+		return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key,
+			      EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
+			(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
+			(parent_ci->ci_filename_mode ==
+			 child_ci->ci_filename_mode) &&
+			(parent_ci->ci_flags == child_ci->ci_flags);
+	}
 
-	return (memcmp(parent_ci->ci_master_key,
-		       child_ci->ci_master_key,
-		       EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
-		(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
-		(parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
-		(parent_ci->ci_flags == child_ci->ci_flags));
+	res = ext4_xattr_get(parent, EXT4_XATTR_INDEX_ENCRYPTION,
+			     EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
+			     &parent_ctx, sizeof(parent_ctx));
+	if (res != sizeof(parent_ctx))
+		return 0;
+
+	res = ext4_xattr_get(child, EXT4_XATTR_INDEX_ENCRYPTION,
+			     EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
+			     &child_ctx, sizeof(child_ctx));
+	if (res != sizeof(child_ctx))
+		return 0;
+
+	return memcmp(parent_ctx.master_key_descriptor,
+		      child_ctx.master_key_descriptor,
+		      EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
+		(parent_ctx.contents_encryption_mode ==
+		 child_ctx.contents_encryption_mode) &&
+		(parent_ctx.filenames_encryption_mode ==
+		 child_ctx.filenames_encryption_mode) &&
+		(parent_ctx.flags == child_ctx.flags);
 }
 
 /**
--- linux-4.4.0.orig/fs/ext4/dir.c
+++ linux-4.4.0/fs/ext4/dir.c
@@ -66,6 +66,7 @@
 	const char *error_msg = NULL;
 	const int rlen = ext4_rec_len_from_disk(de->rec_len,
 						dir->i_sb->s_blocksize);
+	const int next_offset = ((char *) de - buf) + rlen;
 
 	if (unlikely(rlen < EXT4_DIR_REC_LEN(1)))
 		error_msg = "rec_len is smaller than minimal";
@@ -73,28 +74,32 @@
 		error_msg = "rec_len % 4 != 0";
 	else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
 		error_msg = "rec_len is too small for name_len";
-	else if (unlikely(((char *) de - buf) + rlen > size))
-		error_msg = "directory entry across range";
+	else if (unlikely(next_offset > size))
+		error_msg = "directory entry overrun";
+	else if (unlikely(next_offset > size - EXT4_DIR_REC_LEN(1) &&
+			  next_offset != size))
+		error_msg = "directory entry too close to block end";
 	else if (unlikely(le32_to_cpu(de->inode) >
 			le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)))
 		error_msg = "inode out of bounds";
+	else if (unlikely(next_offset == size && de->name_len == 1 &&
+			  de->name[0] == '.'))
+		error_msg = "'.' directory cannot be the last in data block";
 	else
 		return 0;
 
 	if (filp)
 		ext4_error_file(filp, function, line, bh->b_blocknr,
-				"bad entry in directory: %s - offset=%u(%u), "
-				"inode=%u, rec_len=%d, name_len=%d",
-				error_msg, (unsigned) (offset % size),
-				offset, le32_to_cpu(de->inode),
-				rlen, de->name_len);
+				"bad entry in directory: %s - offset=%u, "
+				"inode=%u, rec_len=%d, name_len=%d, size=%d",
+				error_msg, offset, le32_to_cpu(de->inode),
+				rlen, de->name_len, size);
 	else
 		ext4_error_inode(dir, function, line, bh->b_blocknr,
-				"bad entry in directory: %s - offset=%u(%u), "
-				"inode=%u, rec_len=%d, name_len=%d",
-				error_msg, (unsigned) (offset % size),
-				offset, le32_to_cpu(de->inode),
-				rlen, de->name_len);
+				"bad entry in directory: %s - offset=%u, "
+				"inode=%u, rec_len=%d, name_len=%d, size=%d",
+				 error_msg, offset, le32_to_cpu(de->inode),
+				 rlen, de->name_len, size);
 
 	return 1;
 }
@@ -111,17 +116,25 @@
 	int dir_has_error = 0;
 	struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
 
+	if (ext4_encrypted_inode(inode)) {
+		err = ext4_get_encryption_info(inode);
+		if (err && err != -ENOKEY)
+			return err;
+	}
+
 	if (is_dx_dir(inode)) {
 		err = ext4_dx_readdir(file, ctx);
 		if (err != ERR_BAD_DX_DIR) {
 			return err;
 		}
-		/*
-		 * We don't set the inode dirty flag since it's not
-		 * critical that it get flushed back to the disk.
-		 */
-		ext4_clear_inode_flag(file_inode(file),
-				      EXT4_INODE_INDEX);
+		/* Can we just clear INDEX flag to ignore htree information? */
+		if (!ext4_has_metadata_csum(sb)) {
+			/*
+			 * We don't set the inode dirty flag since it's not
+			 * critical that it gets flushed back to the disk.
+			 */
+			ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
+		}
 	}
 
 	if (ext4_has_inline_data(inode)) {
--- linux-4.4.0.orig/fs/ext4/ext4.h
+++ linux-4.4.0/fs/ext4/ext4.h
@@ -221,6 +221,7 @@
 #define	EXT4_MAX_BLOCK_SIZE		65536
 #define EXT4_MIN_BLOCK_LOG_SIZE		10
 #define EXT4_MAX_BLOCK_LOG_SIZE		16
+#define EXT4_MAX_CLUSTER_LOG_SIZE	30
 #ifdef __KERNEL__
 # define EXT4_BLOCK_SIZE(s)		((s)->s_blocksize)
 #else
@@ -850,6 +851,29 @@
 #include "extents_status.h"
 
 /*
+ * Lock subclasses for i_data_sem in the ext4_inode_info structure.
+ *
+ * These are needed to avoid lockdep false positives when we need to
+ * allocate blocks to the quota inode during ext4_map_blocks(), while
+ * holding i_data_sem for a normal (non-quota) inode.  Since we don't
+ * do quota tracking for the quota inode, this avoids deadlock (as
+ * well as infinite recursion, since it isn't turtles all the way
+ * down...)
+ *
+ *  I_DATA_SEM_NORMAL - Used for most inodes
+ *  I_DATA_SEM_OTHER  - Used by move_inode.c for the second normal inode
+ *			  where the second inode has larger inode number
+ *			  than the first
+ *  I_DATA_SEM_QUOTA  - Used for quota inodes only
+ */
+enum {
+	I_DATA_SEM_NORMAL = 0,
+	I_DATA_SEM_OTHER,
+	I_DATA_SEM_QUOTA,
+};
+
+
+/*
  * fourth extended file system inode data in memory
  */
 struct ext4_inode_info {
@@ -910,6 +934,15 @@
 	 * by other means, so we have i_data_sem.
 	 */
 	struct rw_semaphore i_data_sem;
+	/*
+	 * i_mmap_sem is for serializing page faults with truncate / punch hole
+	 * operations. We have to make sure that new page cannot be faulted in
+	 * a section of the inode that is being punched. We cannot easily use
+	 * i_data_sem for this since we need protection for the whole punch
+	 * operation and i_data_sem ranks below transaction start so we have
+	 * to occasionally drop it.
+	 */
+	struct rw_semaphore i_mmap_sem;
 	struct inode vfs_inode;
 	struct jbd2_inode *jinode;
 
@@ -1270,7 +1303,7 @@
 	loff_t s_bitmap_maxbytes;	/* max bytes for bitmap files */
 	struct buffer_head * s_sbh;	/* Buffer containing the super block */
 	struct ext4_super_block *s_es;	/* Pointer to the super block in the buffer */
-	struct buffer_head **s_group_desc;
+	struct buffer_head * __rcu *s_group_desc;
 	unsigned int s_mount_opt;
 	unsigned int s_mount_opt2;
 	unsigned int s_mount_flags;
@@ -1330,7 +1363,7 @@
 #endif
 
 	/* for buddy allocator */
-	struct ext4_group_info ***s_group_info;
+	struct ext4_group_info ** __rcu *s_group_info;
 	struct inode *s_buddy_cache;
 	spinlock_t s_md_lock;
 	unsigned short *s_mb_offsets;
@@ -1377,7 +1410,7 @@
 	unsigned int s_extent_max_zeroout_kb;
 
 	unsigned int s_log_groups_per_flex;
-	struct flex_groups *s_flex_groups;
+	struct flex_groups * __rcu *s_flex_groups;
 	ext4_group_t s_flex_groups_allocated;
 
 	/* workqueue for reserved extent conversions (buffered io) */
@@ -1435,11 +1468,6 @@
 static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 {
 	return ino == EXT4_ROOT_INO ||
-		ino == EXT4_USR_QUOTA_INO ||
-		ino == EXT4_GRP_QUOTA_INO ||
-		ino == EXT4_BOOT_LOADER_INO ||
-		ino == EXT4_JOURNAL_INO ||
-		ino == EXT4_RESIZE_INO ||
 		(ino >= EXT4_FIRST_INO(sb) &&
 		 ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
 }
@@ -1464,6 +1492,23 @@
 }
 
 /*
+ * Returns: sbi->field[index]
+ * Used to access an array element from the following sbi fields which require
+ * rcu protection to avoid dereferencing an invalid pointer due to reassignment
+ * - s_group_desc
+ * - s_group_info
+ * - s_flex_group
+ */
+#define sbi_array_rcu_deref(sbi, field, index)				   \
+({									   \
+	typeof(*((sbi)->field)) _v;					   \
+	rcu_read_lock();						   \
+	_v = ((typeof(_v)*)rcu_dereference((sbi)->field))[index];	   \
+	rcu_read_unlock();						   \
+	_v;								   \
+})
+
+/*
  * Inode dynamic state flags
  */
 enum {
@@ -2228,13 +2273,16 @@
 bool ext4_valid_contents_enc_mode(uint32_t mode);
 uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size);
 extern struct workqueue_struct *ext4_read_workqueue;
-struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode);
+struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode,
+					    gfp_t gfp_flags);
 void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx);
 void ext4_restore_control_page(struct page *data_page);
 struct page *ext4_encrypt(struct inode *inode,
-			  struct page *plaintext_page);
+			  struct page *plaintext_page,
+			  gfp_t gfp_flags);
 int ext4_decrypt(struct page *page);
 int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex);
+extern const struct dentry_operations ext4_encrypted_d_ops;
 
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
 int ext4_init_crypto(void);
@@ -2297,23 +2345,11 @@
 /* crypto_key.c */
 void ext4_free_crypt_info(struct ext4_crypt_info *ci);
 void ext4_free_encryption_info(struct inode *inode, struct ext4_crypt_info *ci);
-int _ext4_get_encryption_info(struct inode *inode);
 
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
 int ext4_has_encryption_key(struct inode *inode);
 
-static inline int ext4_get_encryption_info(struct inode *inode)
-{
-	struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
-
-	if (!ci ||
-	    (ci->ci_keyring_key &&
-	     (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
-					   (1 << KEY_FLAG_REVOKED) |
-					   (1 << KEY_FLAG_DEAD)))))
-		return _ext4_get_encryption_info(inode);
-	return 0;
-}
+int ext4_get_encryption_info(struct inode *inode);
 
 static inline struct ext4_crypt_info *ext4_encryption_info(struct inode *inode)
 {
@@ -2362,8 +2398,12 @@
 		       struct ext4_filename *fname);
 static inline void ext4_update_dx_flag(struct inode *inode)
 {
-	if (!ext4_has_feature_dir_index(inode->i_sb))
+	if (!ext4_has_feature_dir_index(inode->i_sb) &&
+	    ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) {
+		/* ext4_iget() should have caught this... */
+		WARN_ON_ONCE(ext4_has_feature_metadata_csum(inode->i_sb));
 		ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
+	}
 }
 static unsigned char ext4_filetype_table[] = {
 	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
@@ -2458,8 +2498,19 @@
 #define FALL_BACK_TO_NONDELALLOC 1
 #define CONVERT_INLINE_DATA	 2
 
-extern struct inode *ext4_iget(struct super_block *, unsigned long);
-extern struct inode *ext4_iget_normal(struct super_block *, unsigned long);
+typedef enum {
+	EXT4_IGET_NORMAL =	0,
+	EXT4_IGET_SPECIAL =	0x0001, /* OK to iget a system inode */
+	EXT4_IGET_HANDLE = 	0x0002	/* Inode # is from a handle */
+} ext4_iget_flags;
+
+extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
+				 ext4_iget_flags flags, const char *function,
+				 unsigned int line);
+
+#define ext4_iget(sb, ino, flags) \
+	__ext4_iget((sb), (ino), (flags), __func__, __LINE__)
+
 extern int  ext4_write_inode(struct inode *, struct writeback_control *);
 extern int  ext4_setattr(struct dentry *, struct iattr *);
 extern int  ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
@@ -2484,9 +2535,13 @@
 extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
 			     loff_t lstart, loff_t lend);
 extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
+extern int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern qsize_t *ext4_get_reserved_space(struct inode *inode);
 extern void ext4_da_update_reserve_space(struct inode *inode,
 					int used, int quota_claim);
+extern int ext4_get_next_extent(struct inode *inode, ext4_lblk_t lblk,
+				unsigned int map_len,
+				struct extent_status *result);
 
 /* indirect.c */
 extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
@@ -2532,6 +2587,7 @@
 extern int ext4_empty_dir(struct inode *inode);
 
 /* resize.c */
+extern void ext4_kvfree_array_rcu(void *to_free);
 extern int ext4_group_add(struct super_block *sb,
 				struct ext4_new_group_data *input);
 extern int ext4_group_extend(struct super_block *sb,
@@ -2772,13 +2828,13 @@
 struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
 					    ext4_group_t group)
 {
-	 struct ext4_group_info ***grp_info;
+	 struct ext4_group_info **grp_info;
 	 long indexv, indexh;
 	 BUG_ON(group >= EXT4_SB(sb)->s_groups_count);
-	 grp_info = EXT4_SB(sb)->s_group_info;
 	 indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
 	 indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
-	 return grp_info[indexv][indexh];
+	 grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv);
+	 return grp_info[indexh];
 }
 
 /*
@@ -2828,7 +2884,7 @@
 		     !mutex_is_locked(&inode->i_mutex));
 	down_write(&EXT4_I(inode)->i_data_sem);
 	if (newsize > EXT4_I(inode)->i_disksize)
-		EXT4_I(inode)->i_disksize = newsize;
+		WRITE_ONCE(EXT4_I(inode)->i_disksize, newsize);
 	up_write(&EXT4_I(inode)->i_data_sem);
 }
 
@@ -2848,6 +2904,9 @@
 	return changed;
 }
 
+int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
+				      loff_t len);
+
 struct ext4_group_info {
 	unsigned long   bb_state;
 	struct rb_root  bb_free_root;
@@ -3016,9 +3075,6 @@
 extern int ext4_inline_data_fiemap(struct inode *inode,
 				   struct fiemap_extent_info *fieinfo,
 				   int *has_inline, __u64 start, __u64 len);
-extern int ext4_try_to_evict_inline_data(handle_t *handle,
-					 struct inode *inode,
-					 int needed);
 extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline);
 
 extern int ext4_convert_inline_data(struct inode *inode);
@@ -3081,9 +3137,9 @@
 extern int ext4_setup_system_zone(struct super_block *sb);
 extern int __init ext4_init_system_zone(void);
 extern void ext4_exit_system_zone(void);
-extern int ext4_data_block_valid(struct ext4_sb_info *sbi,
-				 ext4_fsblk_t start_blk,
-				 unsigned int count);
+extern int ext4_inode_block_valid(struct inode *inode,
+				  ext4_fsblk_t start_blk,
+				  unsigned int count);
 extern int ext4_check_blockref(const char *, unsigned int,
 			       struct inode *, __le32 *, unsigned int);
 
--- linux-4.4.0.orig/fs/ext4/ext4_crypto.h
+++ linux-4.4.0/fs/ext4/ext4_crypto.h
@@ -78,7 +78,6 @@
 	char		ci_filename_mode;
 	char		ci_flags;
 	struct crypto_ablkcipher *ci_ctfm;
-	struct key	*ci_keyring_key;
 	char		ci_master_key[EXT4_KEY_DESCRIPTOR_SIZE];
 };
 
--- linux-4.4.0.orig/fs/ext4/ext4_extents.h
+++ linux-4.4.0/fs/ext4/ext4_extents.h
@@ -103,6 +103,7 @@
 };
 
 #define EXT4_EXT_MAGIC		cpu_to_le16(0xf30a)
+#define EXT4_MAX_EXTENT_DEPTH 5
 
 #define EXT4_EXTENT_TAIL_OFFSET(hdr) \
 	(sizeof(struct ext4_extent_header) + \
@@ -168,10 +169,13 @@
 	(EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
 #define EXT_LAST_INDEX(__hdr__) \
 	(EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
-#define EXT_MAX_EXTENT(__hdr__) \
-	(EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
+#define EXT_MAX_EXTENT(__hdr__)	\
+	((le16_to_cpu((__hdr__)->eh_max)) ? \
+	((EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)) \
+					: 0)
 #define EXT_MAX_INDEX(__hdr__) \
-	(EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
+	((le16_to_cpu((__hdr__)->eh_max)) ? \
+	((EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)) : 0)
 
 static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode)
 {
--- linux-4.4.0.orig/fs/ext4/ext4_jbd2.h
+++ linux-4.4.0/fs/ext4/ext4_jbd2.h
@@ -372,7 +372,7 @@
 {
 	struct ext4_inode_info *ei = EXT4_I(inode);
 
-	if (ext4_handle_valid(handle)) {
+	if (ext4_handle_valid(handle) && !is_handle_aborted(handle)) {
 		ei->i_sync_tid = handle->h_transaction->t_tid;
 		if (datasync)
 			ei->i_datasync_tid = handle->h_transaction->t_tid;
@@ -395,17 +395,19 @@
 		return EXT4_INODE_WRITEBACK_DATA_MODE;	/* writeback */
 	/* We do not support data journalling with delayed allocation */
 	if (!S_ISREG(inode->i_mode) ||
-	    test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
-		return EXT4_INODE_JOURNAL_DATA_MODE;	/* journal data */
-	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
-	    !test_opt(inode->i_sb, DELALLOC))
+	    test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
+	    (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
+	    !test_opt(inode->i_sb, DELALLOC))) {
+		/* We do not support data journalling for encrypted data */
+		if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode))
+			return EXT4_INODE_ORDERED_DATA_MODE;  /* ordered */
 		return EXT4_INODE_JOURNAL_DATA_MODE;	/* journal data */
+	}
 	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
 		return EXT4_INODE_ORDERED_DATA_MODE;	/* ordered */
 	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
 		return EXT4_INODE_WRITEBACK_DATA_MODE;	/* writeback */
-	else
-		BUG();
+	BUG();
 }
 
 static inline int ext4_should_journal_data(struct inode *inode)
--- linux-4.4.0.orig/fs/ext4/extents.c
+++ linux-4.4.0/fs/ext4/extents.c
@@ -376,11 +376,15 @@
 	ext4_fsblk_t block = ext4_ext_pblock(ext);
 	int len = ext4_ext_get_actual_len(ext);
 	ext4_lblk_t lblock = le32_to_cpu(ext->ee_block);
-	ext4_lblk_t last = lblock + len - 1;
 
-	if (len == 0 || lblock > last)
+	/*
+	 * We allow neither:
+	 *  - zero length
+	 *  - overflow/wrap-around
+	 */
+	if (lblock + len <= lblock)
 		return 0;
-	return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
+	return ext4_inode_block_valid(inode, block, len);
 }
 
 static int ext4_valid_extent_idx(struct inode *inode,
@@ -388,7 +392,7 @@
 {
 	ext4_fsblk_t block = ext4_idx_pblock(ext_idx);
 
-	return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, 1);
+	return ext4_inode_block_valid(inode, block, 1);
 }
 
 static int ext4_valid_extent_entries(struct inode *inode,
@@ -469,6 +473,10 @@
 		error_msg = "invalid extent entries";
 		goto corrupted;
 	}
+	if (unlikely(depth > 32)) {
+		error_msg = "too large eh_depth";
+		goto corrupted;
+	}
 	/* Verify checksum on non-root extent tree nodes */
 	if (ext_depth(inode) != depth &&
 	    !ext4_extent_block_csum_verify(inode, eh)) {
@@ -497,6 +505,30 @@
 	return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode), 0);
 }
 
+static void ext4_cache_extents(struct inode *inode,
+			       struct ext4_extent_header *eh)
+{
+	struct ext4_extent *ex = EXT_FIRST_EXTENT(eh);
+	ext4_lblk_t prev = 0;
+	int i;
+
+	for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) {
+		unsigned int status = EXTENT_STATUS_WRITTEN;
+		ext4_lblk_t lblk = le32_to_cpu(ex->ee_block);
+		int len = ext4_ext_get_actual_len(ex);
+
+		if (prev && (prev != lblk))
+			ext4_es_cache_extent(inode, prev, lblk - prev, ~0,
+					     EXTENT_STATUS_HOLE);
+
+		if (ext4_ext_is_unwritten(ex))
+			status = EXTENT_STATUS_UNWRITTEN;
+		ext4_es_cache_extent(inode, lblk, len,
+				     ext4_ext_pblock(ex), status);
+		prev = lblk + len;
+	}
+}
+
 static struct buffer_head *
 __read_extent_tree_block(const char *function, unsigned int line,
 			 struct inode *inode, ext4_fsblk_t pblk, int depth,
@@ -527,26 +559,7 @@
 	 */
 	if (!(flags & EXT4_EX_NOCACHE) && depth == 0) {
 		struct ext4_extent_header *eh = ext_block_hdr(bh);
-		struct ext4_extent *ex = EXT_FIRST_EXTENT(eh);
-		ext4_lblk_t prev = 0;
-		int i;
-
-		for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) {
-			unsigned int status = EXTENT_STATUS_WRITTEN;
-			ext4_lblk_t lblk = le32_to_cpu(ex->ee_block);
-			int len = ext4_ext_get_actual_len(ex);
-
-			if (prev && (prev != lblk))
-				ext4_es_cache_extent(inode, prev,
-						     lblk - prev, ~0,
-						     EXTENT_STATUS_HOLE);
-
-			if (ext4_ext_is_unwritten(ex))
-				status = EXTENT_STATUS_UNWRITTEN;
-			ext4_es_cache_extent(inode, lblk, len,
-					     ext4_ext_pblock(ex), status);
-			prev = lblk + len;
-		}
+		ext4_cache_extents(inode, eh);
 	}
 	return bh;
 errout:
@@ -852,6 +865,7 @@
 	eh->eh_entries = 0;
 	eh->eh_magic = EXT4_EXT_MAGIC;
 	eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
+	eh->eh_generation = 0;
 	ext4_mark_inode_dirty(handle, inode);
 	return 0;
 }
@@ -868,6 +882,12 @@
 
 	eh = ext_inode_hdr(inode);
 	depth = ext_depth(inode);
+	if (depth < 0 || depth > EXT4_MAX_EXTENT_DEPTH) {
+		EXT4_ERROR_INODE(inode, "inode has invalid extent depth: %d",
+				 depth);
+		ret = -EFSCORRUPTED;
+		goto err;
+	}
 
 	if (path) {
 		ext4_ext_drop_refs(path);
@@ -888,6 +908,8 @@
 	path[0].p_bh = NULL;
 
 	i = depth;
+	if (!(flags & EXT4_EX_NOCACHE) && depth == 0)
+		ext4_cache_extents(inode, eh);
 	/* walk through the tree */
 	while (i) {
 		ext_debug("depth %d: num %d, max %d\n",
@@ -1035,6 +1057,7 @@
 	__le32 border;
 	ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */
 	int err = 0;
+	size_t ext_size = 0;
 
 	/* make decision: where to split? */
 	/* FIXME: now decision is simplest: at current extent */
@@ -1106,6 +1129,7 @@
 	neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
 	neh->eh_magic = EXT4_EXT_MAGIC;
 	neh->eh_depth = 0;
+	neh->eh_generation = 0;
 
 	/* move remainder of path[depth] to the new leaf */
 	if (unlikely(path[depth].p_hdr->eh_entries !=
@@ -1126,6 +1150,10 @@
 		le16_add_cpu(&neh->eh_entries, m);
 	}
 
+	/* zero out unused area in the extent block */
+	ext_size = sizeof(struct ext4_extent_header) +
+		sizeof(struct ext4_extent) * le16_to_cpu(neh->eh_entries);
+	memset(bh->b_data + ext_size, 0, inode->i_sb->s_blocksize - ext_size);
 	ext4_extent_block_csum_set(inode, neh);
 	set_buffer_uptodate(bh);
 	unlock_buffer(bh);
@@ -1179,6 +1207,7 @@
 		neh->eh_magic = EXT4_EXT_MAGIC;
 		neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
 		neh->eh_depth = cpu_to_le16(depth - i);
+		neh->eh_generation = 0;
 		fidx = EXT_FIRST_INDEX(neh);
 		fidx->ei_block = border;
 		ext4_idx_store_pblock(fidx, oldblock);
@@ -1205,6 +1234,11 @@
 				sizeof(struct ext4_extent_idx) * m);
 			le16_add_cpu(&neh->eh_entries, m);
 		}
+		/* zero out unused area in the extent block */
+		ext_size = sizeof(struct ext4_extent_header) +
+		   (sizeof(struct ext4_extent) * le16_to_cpu(neh->eh_entries));
+		memset(bh->b_data + ext_size, 0,
+			inode->i_sb->s_blocksize - ext_size);
 		ext4_extent_block_csum_set(inode, neh);
 		set_buffer_uptodate(bh);
 		unlock_buffer(bh);
@@ -1270,6 +1304,7 @@
 	ext4_fsblk_t newblock, goal = 0;
 	struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
 	int err = 0;
+	size_t ext_size = 0;
 
 	/* Try to prepend new index to old one */
 	if (ext_depth(inode))
@@ -1295,9 +1330,11 @@
 		goto out;
 	}
 
+	ext_size = sizeof(EXT4_I(inode)->i_data);
 	/* move top-level index/leaf into new block */
-	memmove(bh->b_data, EXT4_I(inode)->i_data,
-		sizeof(EXT4_I(inode)->i_data));
+	memmove(bh->b_data, EXT4_I(inode)->i_data, ext_size);
+	/* zero out unused area in the extent block */
+	memset(bh->b_data + ext_size, 0, inode->i_sb->s_blocksize - ext_size);
 
 	/* set size of new block */
 	neh = ext_block_hdr(bh);
@@ -2063,6 +2100,7 @@
 				       ppath, newext);
 	if (err)
 		goto cleanup;
+	path = *ppath;
 	depth = ext_depth(inode);
 	eh = path[depth].p_hdr;
 
@@ -2293,59 +2331,69 @@
 }
 
 /*
- * ext4_ext_put_gap_in_cache:
- * calculate boundaries of the gap that the requested block fits into
- * and cache this gap
+ * ext4_ext_determine_hole - determine hole around given block
+ * @inode:	inode we lookup in
+ * @path:	path in extent tree to @lblk
+ * @lblk:	pointer to logical block around which we want to determine hole
+ *
+ * Determine hole length (and start if easily possible) around given logical
+ * block. We don't try too hard to find the beginning of the hole but @path
+ * actually points to extent before @lblk, we provide it.
+ *
+ * The function returns the length of a hole starting at @lblk. We update @lblk
+ * to the beginning of the hole if we managed to find it.
  */
-static void
-ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
-				ext4_lblk_t block)
+static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
+					   struct ext4_ext_path *path,
+					   ext4_lblk_t *lblk)
 {
 	int depth = ext_depth(inode);
-	ext4_lblk_t len;
-	ext4_lblk_t lblock;
 	struct ext4_extent *ex;
-	struct extent_status es;
+	ext4_lblk_t len;
 
 	ex = path[depth].p_ext;
 	if (ex == NULL) {
 		/* there is no extent yet, so gap is [0;-] */
-		lblock = 0;
+		*lblk = 0;
 		len = EXT_MAX_BLOCKS;
-		ext_debug("cache gap(whole file):");
-	} else if (block < le32_to_cpu(ex->ee_block)) {
-		lblock = block;
-		len = le32_to_cpu(ex->ee_block) - block;
-		ext_debug("cache gap(before): %u [%u:%u]",
-				block,
-				le32_to_cpu(ex->ee_block),
-				 ext4_ext_get_actual_len(ex));
-	} else if (block >= le32_to_cpu(ex->ee_block)
+	} else if (*lblk < le32_to_cpu(ex->ee_block)) {
+		len = le32_to_cpu(ex->ee_block) - *lblk;
+	} else if (*lblk >= le32_to_cpu(ex->ee_block)
 			+ ext4_ext_get_actual_len(ex)) {
 		ext4_lblk_t next;
-		lblock = le32_to_cpu(ex->ee_block)
-			+ ext4_ext_get_actual_len(ex);
 
+		*lblk = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex);
 		next = ext4_ext_next_allocated_block(path);
-		ext_debug("cache gap(after): [%u:%u] %u",
-				le32_to_cpu(ex->ee_block),
-				ext4_ext_get_actual_len(ex),
-				block);
-		BUG_ON(next == lblock);
-		len = next - lblock;
+		BUG_ON(next == *lblk);
+		len = next - *lblk;
 	} else {
 		BUG();
 	}
+	return len;
+}
+
+/*
+ * ext4_ext_put_gap_in_cache:
+ * calculate boundaries of the gap that the requested block fits into
+ * and cache this gap
+ */
+static void
+ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start,
+			  ext4_lblk_t hole_len)
+{
+	struct extent_status es;
 
-	ext4_es_find_delayed_extent_range(inode, lblock, lblock + len - 1, &es);
+	ext4_es_find_delayed_extent_range(inode, hole_start,
+					  hole_start + hole_len - 1, &es);
 	if (es.es_len) {
 		/* There's delayed extent containing lblock? */
-		if (es.es_lblk <= lblock)
+		if (es.es_lblk <= hole_start)
 			return;
-		len = min(es.es_lblk - lblock, len);
+		hole_len = min(es.es_lblk - hole_start, hole_len);
 	}
-	ext_debug(" -> %u:%u\n", lblock, len);
-	ext4_es_insert_extent(inode, lblock, len, ~0, EXTENT_STATUS_HOLE);
+	ext_debug(" -> %u:%u\n", hole_start, hole_len);
+	ext4_es_insert_extent(inode, hole_start, hole_len, ~0,
+			      EXTENT_STATUS_HOLE);
 }
 
 /*
@@ -2864,7 +2912,7 @@
 			 * in use to avoid freeing it when removing blocks.
 			 */
 			if (sbi->s_cluster_ratio > 1) {
-				pblk = ext4_ext_pblock(ex) + end - ee_block + 2;
+				pblk = ext4_ext_pblock(ex) + end - ee_block + 1;
 				partial_cluster =
 					-(long long) EXT4_B2C(sbi, pblk);
 			}
@@ -3412,8 +3460,8 @@
 		(unsigned long long)map->m_lblk, map_len);
 
 	sbi = EXT4_SB(inode->i_sb);
-	eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
-		inode->i_sb->s_blocksize_bits;
+	eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1)
+			>> inode->i_sb->s_blocksize_bits;
 	if (eof_block < map->m_lblk + map_len)
 		eof_block = map->m_lblk + map_len;
 
@@ -3674,8 +3722,8 @@
 		  __func__, inode->i_ino,
 		  (unsigned long long)map->m_lblk, map->m_len);
 
-	eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
-		inode->i_sb->s_blocksize_bits;
+	eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1)
+			>> inode->i_sb->s_blocksize_bits;
 	if (eof_block < map->m_lblk + map->m_len)
 		eof_block = map->m_lblk + map->m_len;
 	/*
@@ -4368,11 +4416,22 @@
 	 * we couldn't try to create block if create flag is zero
 	 */
 	if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
+		ext4_lblk_t hole_start, hole_len;
+
+		hole_start = map->m_lblk;
+		hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
 		/*
 		 * put just found gap into cache to speed up
 		 * subsequent requests
 		 */
-		ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
+		ext4_ext_put_gap_in_cache(inode, hole_start, hole_len);
+
+		/* Update hole_len to reflect hole size after map->m_lblk */
+		if (hole_start != map->m_lblk)
+			hole_len -= map->m_lblk - hole_start;
+		map->m_pblk = 0;
+		map->m_len = min_t(unsigned int, map->m_len, hole_len);
+
 		goto out2;
 	}
 
@@ -4685,10 +4744,6 @@
 	if (len <= EXT_UNWRITTEN_MAX_LEN)
 		flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
 
-	/* Wait all existing dio workers, newcomers will block on i_mutex */
-	ext4_inode_block_unlocked_dio(inode);
-	inode_dio_wait(inode);
-
 	/*
 	 * credits to insert 1 extent into extent tree
 	 */
@@ -4742,6 +4797,7 @@
 						    EXT4_INODE_EOFBLOCKS);
 		}
 		ext4_mark_inode_dirty(handle, inode);
+		ext4_update_inode_fsync_trans(handle, inode, 1);
 		ret2 = ext4_journal_stop(handle);
 		if (ret2)
 			break;
@@ -4752,8 +4808,6 @@
 		goto retry;
 	}
 
-	ext4_inode_resume_unlocked_dio(inode);
-
 	return ret > 0 ? ret2 : ret;
 }
 
@@ -4770,7 +4824,6 @@
 	int partial_begin, partial_end;
 	loff_t start, end;
 	ext4_lblk_t lblk;
-	struct address_space *mapping = inode->i_mapping;
 	unsigned int blkbits = inode->i_blkbits;
 
 	trace_ext4_zero_range(inode, offset, len, mode);
@@ -4786,17 +4839,6 @@
 	}
 
 	/*
-	 * Write out all dirty pages to avoid race conditions
-	 * Then release them.
-	 */
-	if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
-		ret = filemap_write_and_wait_range(mapping, offset,
-						   offset + len - 1);
-		if (ret)
-			return ret;
-	}
-
-	/*
 	 * Round up offset. This is not fallocate, we neet to zero out
 	 * blocks, so convert interior block aligned part of the range to
 	 * unwritten and possibly manually zero out unaligned parts of the
@@ -4828,7 +4870,8 @@
 	}
 
 	if (!(mode & FALLOC_FL_KEEP_SIZE) &&
-	     offset + len > i_size_read(inode)) {
+	    (offset + len > i_size_read(inode) ||
+	     offset + len > EXT4_I(inode)->i_disksize)) {
 		new_size = offset + len;
 		ret = inode_newsize_ok(inode, new_size);
 		if (ret)
@@ -4839,6 +4882,10 @@
 	if (mode & FALLOC_FL_KEEP_SIZE)
 		flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
 
+	/* Wait all existing dio workers, newcomers will block on i_mutex */
+	ext4_inode_block_unlocked_dio(inode);
+	inode_dio_wait(inode);
+
 	/* Preallocate the range including the unaligned edges */
 	if (partial_begin || partial_end) {
 		ret = ext4_alloc_file_blocks(file,
@@ -4847,7 +4894,7 @@
 				 round_down(offset, 1 << blkbits)) >> blkbits,
 				new_size, flags, mode);
 		if (ret)
-			goto out_mutex;
+			goto out_dio;
 
 	}
 
@@ -4856,16 +4903,23 @@
 		flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
 			  EXT4_EX_NOCACHE);
 
-		/* Now release the pages and zero block aligned part of pages*/
+		/*
+		 * Prevent page faults from reinstantiating pages we have
+		 * released from page cache.
+		 */
+		down_write(&EXT4_I(inode)->i_mmap_sem);
+		ret = ext4_update_disksize_before_punch(inode, offset, len);
+		if (ret) {
+			up_write(&EXT4_I(inode)->i_mmap_sem);
+			goto out_dio;
+		}
+		/* Now release the pages and zero block aligned part of pages */
 		truncate_pagecache_range(inode, start, end - 1);
 		inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
 
-		/* Wait all existing dio workers, newcomers will block on i_mutex */
-		ext4_inode_block_unlocked_dio(inode);
-		inode_dio_wait(inode);
-
 		ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
 					     flags, mode);
+		up_write(&EXT4_I(inode)->i_mmap_sem);
 		if (ret)
 			goto out_dio;
 	}
@@ -4901,6 +4955,8 @@
 
 	/* Zero out partial block at the edges of the range */
 	ret = ext4_zero_partial_blocks(handle, inode, offset, len);
+	if (ret >= 0)
+		ext4_update_inode_fsync_trans(handle, inode, 1);
 
 	if (file->f_flags & O_SYNC)
 		ext4_handle_sync(handle);
@@ -4991,15 +5047,21 @@
 	}
 
 	if (!(mode & FALLOC_FL_KEEP_SIZE) &&
-	     offset + len > i_size_read(inode)) {
+	    (offset + len > i_size_read(inode) ||
+	     offset + len > EXT4_I(inode)->i_disksize)) {
 		new_size = offset + len;
 		ret = inode_newsize_ok(inode, new_size);
 		if (ret)
 			goto out;
 	}
 
+	/* Wait all existing dio workers, newcomers will block on i_mutex */
+	ext4_inode_block_unlocked_dio(inode);
+	inode_dio_wait(inode);
+
 	ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
 				     flags, mode);
+	ext4_inode_resume_unlocked_dio(inode);
 	if (ret)
 		goto out;
 
@@ -5356,7 +5418,8 @@
 	ext4_lblk_t stop, *iterator, ex_start, ex_end;
 
 	/* Let path point to the last extent */
-	path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0);
+	path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
+				EXT4_EX_NOCACHE);
 	if (IS_ERR(path))
 		return PTR_ERR(path);
 
@@ -5365,15 +5428,16 @@
 	if (!extent)
 		goto out;
 
-	stop = le32_to_cpu(extent->ee_block) +
-			ext4_ext_get_actual_len(extent);
+	stop = le32_to_cpu(extent->ee_block);
 
        /*
-	 * In case of left shift, Don't start shifting extents until we make
-	 * sure the hole is big enough to accommodate the shift.
+	* For left shifts, make sure the hole on the left is big enough to
+	* accommodate the shift.  For right shifts, make sure the last extent
+	* won't be shifted beyond EXT_MAX_BLOCKS.
 	*/
 	if (SHIFT == SHIFT_LEFT) {
-		path = ext4_find_extent(inode, start - 1, &path, 0);
+		path = ext4_find_extent(inode, start - 1, &path,
+					EXT4_EX_NOCACHE);
 		if (IS_ERR(path))
 			return PTR_ERR(path);
 		depth = path->p_depth;
@@ -5389,9 +5453,14 @@
 
 		if ((start == ex_start && shift > ex_start) ||
 		    (shift > start - ex_end)) {
-			ext4_ext_drop_refs(path);
-			kfree(path);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
+		}
+	} else {
+		if (shift > EXT_MAX_BLOCKS -
+		    (stop + ext4_ext_get_actual_len(extent))) {
+			ret = -EINVAL;
+			goto out;
 		}
 	}
 
@@ -5405,9 +5474,14 @@
 	else
 		iterator = &stop;
 
-	/* Its safe to start updating extents */
-	while (start < stop) {
-		path = ext4_find_extent(inode, *iterator, &path, 0);
+	/*
+	 * Its safe to start updating extents.  Start and stop are unsigned, so
+	 * in case of right shift if extent with 0 block is reached, iterator
+	 * becomes NULL to indicate the end of the loop.
+	 */
+	while (iterator && start <= stop) {
+		path = ext4_find_extent(inode, *iterator, &path,
+					EXT4_EX_NOCACHE);
 		if (IS_ERR(path))
 			return PTR_ERR(path);
 		depth = path->p_depth;
@@ -5434,8 +5508,11 @@
 					ext4_ext_get_actual_len(extent);
 		} else {
 			extent = EXT_FIRST_EXTENT(path[depth].p_hdr);
-			*iterator =  le32_to_cpu(extent->ee_block) > 0 ?
-				le32_to_cpu(extent->ee_block) - 1 : 0;
+			if (le32_to_cpu(extent->ee_block) > 0)
+				*iterator = le32_to_cpu(extent->ee_block) - 1;
+			else
+				/* Beginning is reached, end of the loop */
+				iterator = NULL;
 			/* Update path extent in case we need to stop */
 			while (le32_to_cpu(extent->ee_block) < start)
 				extent++;
@@ -5494,21 +5571,7 @@
 			return ret;
 	}
 
-	/*
-	 * Need to round down offset to be aligned with page size boundary
-	 * for page size > block size.
-	 */
-	ioffset = round_down(offset, PAGE_SIZE);
-
-	/* Write out all dirty pages */
-	ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
-					   LLONG_MAX);
-	if (ret)
-		return ret;
-
-	/* Take mutex lock */
 	mutex_lock(&inode->i_mutex);
-
 	/*
 	 * There is no need to overlap collapse range with EOF, in which case
 	 * it is effectively a truncate operation
@@ -5524,17 +5587,43 @@
 		goto out_mutex;
 	}
 
-	truncate_pagecache(inode, ioffset);
-
 	/* Wait for existing dio to complete */
 	ext4_inode_block_unlocked_dio(inode);
 	inode_dio_wait(inode);
 
+	/*
+	 * Prevent page faults from reinstantiating pages we have released from
+	 * page cache.
+	 */
+	down_write(&EXT4_I(inode)->i_mmap_sem);
+	/*
+	 * Need to round down offset to be aligned with page size boundary
+	 * for page size > block size.
+	 */
+	ioffset = round_down(offset, PAGE_SIZE);
+	/*
+	 * Write tail of the last page before removed range since it will get
+	 * removed from the page cache below.
+	 */
+	ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, offset);
+	if (ret)
+		goto out_mmap;
+	/*
+	 * Write data that will be shifted to preserve them when discarding
+	 * page cache below. We are also protected from pages becoming dirty
+	 * by i_mmap_sem.
+	 */
+	ret = filemap_write_and_wait_range(inode->i_mapping, offset + len,
+					   LLONG_MAX);
+	if (ret)
+		goto out_mmap;
+	truncate_pagecache(inode, ioffset);
+
 	credits = ext4_writepage_trans_blocks(inode);
 	handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
 	if (IS_ERR(handle)) {
 		ret = PTR_ERR(handle);
-		goto out_dio;
+		goto out_mmap;
 	}
 
 	down_write(&EXT4_I(inode)->i_data_sem);
@@ -5570,10 +5659,12 @@
 		ext4_handle_sync(handle);
 	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
 	ext4_mark_inode_dirty(handle, inode);
+	ext4_update_inode_fsync_trans(handle, inode, 1);
 
 out_stop:
 	ext4_journal_stop(handle);
-out_dio:
+out_mmap:
+	up_write(&EXT4_I(inode)->i_mmap_sem);
 	ext4_inode_resume_unlocked_dio(inode);
 out_mutex:
 	mutex_unlock(&inode->i_mutex);
@@ -5627,21 +5718,7 @@
 			return ret;
 	}
 
-	/*
-	 * Need to round down to align start offset to page size boundary
-	 * for page size > block size.
-	 */
-	ioffset = round_down(offset, PAGE_SIZE);
-
-	/* Write out all dirty pages */
-	ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
-			LLONG_MAX);
-	if (ret)
-		return ret;
-
-	/* Take mutex lock */
 	mutex_lock(&inode->i_mutex);
-
 	/* Currently just for extent based files */
 	if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
 		ret = -EOPNOTSUPP;
@@ -5660,17 +5737,32 @@
 		goto out_mutex;
 	}
 
-	truncate_pagecache(inode, ioffset);
-
 	/* Wait for existing dio to complete */
 	ext4_inode_block_unlocked_dio(inode);
 	inode_dio_wait(inode);
 
+	/*
+	 * Prevent page faults from reinstantiating pages we have released from
+	 * page cache.
+	 */
+	down_write(&EXT4_I(inode)->i_mmap_sem);
+	/*
+	 * Need to round down to align start offset to page size boundary
+	 * for page size > block size.
+	 */
+	ioffset = round_down(offset, PAGE_SIZE);
+	/* Write out all dirty pages */
+	ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
+			LLONG_MAX);
+	if (ret)
+		goto out_mmap;
+	truncate_pagecache(inode, ioffset);
+
 	credits = ext4_writepage_trans_blocks(inode);
 	handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
 	if (IS_ERR(handle)) {
 		ret = PTR_ERR(handle);
-		goto out_dio;
+		goto out_mmap;
 	}
 
 	/* Expand file to avoid data loss if there is error while shifting */
@@ -5718,6 +5810,9 @@
 			up_write(&EXT4_I(inode)->i_data_sem);
 			goto out_stop;
 		}
+	} else {
+		ext4_ext_drop_refs(path);
+		kfree(path);
 	}
 
 	ret = ext4_es_remove_extent(inode, offset_lblk,
@@ -5738,10 +5833,13 @@
 	up_write(&EXT4_I(inode)->i_data_sem);
 	if (IS_SYNC(inode))
 		ext4_handle_sync(handle);
+	if (ret >= 0)
+		ext4_update_inode_fsync_trans(handle, inode, 1);
 
 out_stop:
 	ext4_journal_stop(handle);
-out_dio:
+out_mmap:
+	up_write(&EXT4_I(inode)->i_mmap_sem);
 	ext4_inode_resume_unlocked_dio(inode);
 out_mutex:
 	mutex_unlock(&inode->i_mutex);
--- linux-4.4.0.orig/fs/ext4/file.c
+++ linux-4.4.0/fs/ext4/file.c
@@ -79,7 +79,7 @@
 	struct super_block *sb = inode->i_sb;
 	int blockmask = sb->s_blocksize - 1;
 
-	if (pos >= i_size_read(inode))
+	if (pos >= ALIGN(i_size_read(inode), sb->s_blocksize))
 		return 0;
 
 	if ((pos | iov_iter_alignment(from)) & blockmask)
@@ -209,15 +209,18 @@
 {
 	int result;
 	handle_t *handle = NULL;
-	struct super_block *sb = file_inode(vma->vm_file)->i_sb;
+	struct inode *inode = file_inode(vma->vm_file);
+	struct super_block *sb = inode->i_sb;
 	bool write = vmf->flags & FAULT_FLAG_WRITE;
 
 	if (write) {
 		sb_start_pagefault(sb);
 		file_update_time(vma->vm_file);
+		down_read(&EXT4_I(inode)->i_mmap_sem);
 		handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE,
 						EXT4_DATA_TRANS_BLOCKS(sb));
-	}
+	} else
+		down_read(&EXT4_I(inode)->i_mmap_sem);
 
 	if (IS_ERR(handle))
 		result = VM_FAULT_SIGBUS;
@@ -228,8 +231,10 @@
 	if (write) {
 		if (!IS_ERR(handle))
 			ext4_journal_stop(handle);
+		up_read(&EXT4_I(inode)->i_mmap_sem);
 		sb_end_pagefault(sb);
-	}
+	} else
+		up_read(&EXT4_I(inode)->i_mmap_sem);
 
 	return result;
 }
@@ -246,10 +251,12 @@
 	if (write) {
 		sb_start_pagefault(sb);
 		file_update_time(vma->vm_file);
+		down_read(&EXT4_I(inode)->i_mmap_sem);
 		handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE,
 				ext4_chunk_trans_blocks(inode,
 							PMD_SIZE / PAGE_SIZE));
-	}
+	} else
+		down_read(&EXT4_I(inode)->i_mmap_sem);
 
 	if (IS_ERR(handle))
 		result = VM_FAULT_SIGBUS;
@@ -260,30 +267,71 @@
 	if (write) {
 		if (!IS_ERR(handle))
 			ext4_journal_stop(handle);
+		up_read(&EXT4_I(inode)->i_mmap_sem);
 		sb_end_pagefault(sb);
-	}
+	} else
+		up_read(&EXT4_I(inode)->i_mmap_sem);
 
 	return result;
 }
 
 static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-	return dax_mkwrite(vma, vmf, ext4_get_block_dax,
-				ext4_end_io_unwritten);
+	int err;
+	struct inode *inode = file_inode(vma->vm_file);
+
+	sb_start_pagefault(inode->i_sb);
+	file_update_time(vma->vm_file);
+	down_read(&EXT4_I(inode)->i_mmap_sem);
+	err = __dax_mkwrite(vma, vmf, ext4_get_block_dax,
+			    ext4_end_io_unwritten);
+	up_read(&EXT4_I(inode)->i_mmap_sem);
+	sb_end_pagefault(inode->i_sb);
+
+	return err;
+}
+
+/*
+ * Handle write fault for VM_MIXEDMAP mappings. Similarly to ext4_dax_mkwrite()
+ * handler we check for races agaist truncate. Note that since we cycle through
+ * i_mmap_sem, we are sure that also any hole punching that began before we
+ * were called is finished by now and so if it included part of the file we
+ * are working on, our pte will get unmapped and the check for pte_same() in
+ * wp_pfn_shared() fails. Thus fault gets retried and things work out as
+ * desired.
+ */
+static int ext4_dax_pfn_mkwrite(struct vm_area_struct *vma,
+				struct vm_fault *vmf)
+{
+	struct inode *inode = file_inode(vma->vm_file);
+	struct super_block *sb = inode->i_sb;
+	int ret = VM_FAULT_NOPAGE;
+	loff_t size;
+
+	sb_start_pagefault(sb);
+	file_update_time(vma->vm_file);
+	down_read(&EXT4_I(inode)->i_mmap_sem);
+	size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	if (vmf->pgoff >= size)
+		ret = VM_FAULT_SIGBUS;
+	up_read(&EXT4_I(inode)->i_mmap_sem);
+	sb_end_pagefault(sb);
+
+	return ret;
 }
 
 static const struct vm_operations_struct ext4_dax_vm_ops = {
 	.fault		= ext4_dax_fault,
 	.pmd_fault	= ext4_dax_pmd_fault,
 	.page_mkwrite	= ext4_dax_mkwrite,
-	.pfn_mkwrite	= dax_pfn_mkwrite,
+	.pfn_mkwrite	= ext4_dax_pfn_mkwrite,
 };
 #else
 #define ext4_dax_vm_ops	ext4_file_vm_ops
 #endif
 
 static const struct vm_operations_struct ext4_file_vm_ops = {
-	.fault		= filemap_fault,
+	.fault		= ext4_filemap_fault,
 	.map_pages	= filemap_map_pages,
 	.page_mkwrite   = ext4_page_mkwrite,
 };
@@ -387,7 +435,7 @@
  */
 static int ext4_find_unwritten_pgoff(struct inode *inode,
 				     int whence,
-				     struct ext4_map_blocks *map,
+				     ext4_lblk_t end_blk,
 				     loff_t *offset)
 {
 	struct pagevec pvec;
@@ -402,7 +450,7 @@
 	blkbits = inode->i_sb->s_blocksize_bits;
 	startoff = *offset;
 	lastoff = startoff;
-	endoff = (loff_t)(map->m_lblk + map->m_len) << blkbits;
+	endoff = (loff_t)end_blk << blkbits;
 
 	index = startoff >> PAGE_CACHE_SHIFT;
 	end = endoff >> PAGE_CACHE_SHIFT;
@@ -412,50 +460,30 @@
 		int i, num;
 		unsigned long nr_pages;
 
-		num = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
+		num = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1;
 		nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
 					  (pgoff_t)num);
-		if (nr_pages == 0) {
-			if (whence == SEEK_DATA)
-				break;
-
-			BUG_ON(whence != SEEK_HOLE);
-			/*
-			 * If this is the first time to go into the loop and
-			 * offset is not beyond the end offset, it will be a
-			 * hole at this offset
-			 */
-			if (lastoff == startoff || lastoff < endoff)
-				found = 1;
+		if (nr_pages == 0)
 			break;
-		}
-
-		/*
-		 * If this is the first time to go into the loop and
-		 * offset is smaller than the first page offset, it will be a
-		 * hole at this offset.
-		 */
-		if (lastoff == startoff && whence == SEEK_HOLE &&
-		    lastoff < page_offset(pvec.pages[0])) {
-			found = 1;
-			break;
-		}
 
 		for (i = 0; i < nr_pages; i++) {
 			struct page *page = pvec.pages[i];
 			struct buffer_head *bh, *head;
 
 			/*
-			 * If the current offset is not beyond the end of given
-			 * range, it will be a hole.
+			 * If current offset is smaller than the page offset,
+			 * there is a hole at this offset.
 			 */
-			if (lastoff < endoff && whence == SEEK_HOLE &&
-			    page->index > end) {
+			if (whence == SEEK_HOLE && lastoff < endoff &&
+			    lastoff < page_offset(pvec.pages[i])) {
 				found = 1;
 				*offset = lastoff;
 				goto out;
 			}
 
+			if (page->index > end)
+				goto out;
+
 			lock_page(page);
 
 			if (unlikely(page->mapping != inode->i_mapping)) {
@@ -472,6 +500,8 @@
 				lastoff = page_offset(page);
 				bh = head = page_buffers(page);
 				do {
+					if (lastoff + bh->b_size <= startoff)
+						goto next;
 					if (buffer_uptodate(bh) ||
 					    buffer_unwritten(bh)) {
 						if (whence == SEEK_DATA)
@@ -486,6 +516,7 @@
 						unlock_page(page);
 						goto out;
 					}
+next:
 					lastoff += bh->b_size;
 					bh = bh->b_this_page;
 				} while (bh != head);
@@ -495,20 +526,18 @@
 			unlock_page(page);
 		}
 
-		/*
-		 * The no. of pages is less than our desired, that would be a
-		 * hole in there.
-		 */
-		if (nr_pages < num && whence == SEEK_HOLE) {
-			found = 1;
-			*offset = lastoff;
+		/* The no. of pages is less than our desired, we are done. */
+		if (nr_pages < num)
 			break;
-		}
 
 		index = pvec.pages[i - 1]->index + 1;
 		pagevec_release(&pvec);
 	} while (index <= end);
 
+	if (whence == SEEK_HOLE && lastoff < endoff) {
+		found = 1;
+		*offset = lastoff;
+	}
 out:
 	pagevec_release(&pvec);
 	return found;
@@ -520,17 +549,16 @@
 static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize)
 {
 	struct inode *inode = file->f_mapping->host;
-	struct ext4_map_blocks map;
 	struct extent_status es;
 	ext4_lblk_t start, last, end;
 	loff_t dataoff, isize;
 	int blkbits;
-	int ret = 0;
+	int ret;
 
 	mutex_lock(&inode->i_mutex);
 
 	isize = i_size_read(inode);
-	if (offset >= isize) {
+	if (offset < 0 || offset >= isize) {
 		mutex_unlock(&inode->i_mutex);
 		return -ENXIO;
 	}
@@ -542,41 +570,32 @@
 	dataoff = offset;
 
 	do {
-		map.m_lblk = last;
-		map.m_len = end - last + 1;
-		ret = ext4_map_blocks(NULL, inode, &map, 0);
-		if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) {
-			if (last != start)
-				dataoff = (loff_t)last << blkbits;
-			break;
+		ret = ext4_get_next_extent(inode, last, end - last + 1, &es);
+		if (ret <= 0) {
+			/* No extent found -> no data */
+			if (ret == 0)
+				ret = -ENXIO;
+			mutex_unlock(&inode->i_mutex);
+			return ret;
 		}
 
-		/*
-		 * If there is a delay extent at this offset,
-		 * it will be as a data.
-		 */
-		ext4_es_find_delayed_extent_range(inode, last, last, &es);
-		if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) {
-			if (last != start)
-				dataoff = (loff_t)last << blkbits;
+		last = es.es_lblk;
+		if (last != start)
+			dataoff = (loff_t)last << blkbits;
+		if (!ext4_es_is_unwritten(&es))
 			break;
-		}
 
 		/*
 		 * If there is a unwritten extent at this offset,
 		 * it will be as a data or a hole according to page
 		 * cache that has data or not.
 		 */
-		if (map.m_flags & EXT4_MAP_UNWRITTEN) {
-			int unwritten;
-			unwritten = ext4_find_unwritten_pgoff(inode, SEEK_DATA,
-							      &map, &dataoff);
-			if (unwritten)
-				break;
-		}
-
-		last++;
+		if (ext4_find_unwritten_pgoff(inode, SEEK_DATA,
+					      es.es_lblk + es.es_len, &dataoff))
+			break;
+		last += es.es_len;
 		dataoff = (loff_t)last << blkbits;
+		cond_resched();
 	} while (last <= end);
 
 	mutex_unlock(&inode->i_mutex);
@@ -593,17 +612,16 @@
 static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize)
 {
 	struct inode *inode = file->f_mapping->host;
-	struct ext4_map_blocks map;
 	struct extent_status es;
 	ext4_lblk_t start, last, end;
 	loff_t holeoff, isize;
 	int blkbits;
-	int ret = 0;
+	int ret;
 
 	mutex_lock(&inode->i_mutex);
 
 	isize = i_size_read(inode);
-	if (offset >= isize) {
+	if (offset < 0 || offset >= isize) {
 		mutex_unlock(&inode->i_mutex);
 		return -ENXIO;
 	}
@@ -615,44 +633,30 @@
 	holeoff = offset;
 
 	do {
-		map.m_lblk = last;
-		map.m_len = end - last + 1;
-		ret = ext4_map_blocks(NULL, inode, &map, 0);
-		if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) {
-			last += ret;
-			holeoff = (loff_t)last << blkbits;
-			continue;
+		ret = ext4_get_next_extent(inode, last, end - last + 1, &es);
+		if (ret < 0) {
+			mutex_unlock(&inode->i_mutex);
+			return ret;
 		}
-
-		/*
-		 * If there is a delay extent at this offset,
-		 * we will skip this extent.
-		 */
-		ext4_es_find_delayed_extent_range(inode, last, last, &es);
-		if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) {
-			last = es.es_lblk + es.es_len;
-			holeoff = (loff_t)last << blkbits;
-			continue;
+		/* Found a hole? */
+		if (ret == 0 || es.es_lblk > last) {
+			if (last != start)
+				holeoff = (loff_t)last << blkbits;
+			break;
 		}
-
 		/*
 		 * If there is a unwritten extent at this offset,
 		 * it will be as a data or a hole according to page
 		 * cache that has data or not.
 		 */
-		if (map.m_flags & EXT4_MAP_UNWRITTEN) {
-			int unwritten;
-			unwritten = ext4_find_unwritten_pgoff(inode, SEEK_HOLE,
-							      &map, &holeoff);
-			if (!unwritten) {
-				last += ret;
-				holeoff = (loff_t)last << blkbits;
-				continue;
-			}
-		}
+		if (ext4_es_is_unwritten(&es) &&
+		    ext4_find_unwritten_pgoff(inode, SEEK_HOLE,
+					      last + es.es_len, &holeoff))
+			break;
 
-		/* find a hole */
-		break;
+		last += es.es_len;
+		holeoff = (loff_t)last << blkbits;
+		cond_resched();
 	} while (last <= end);
 
 	mutex_unlock(&inode->i_mutex);
--- linux-4.4.0.orig/fs/ext4/ialloc.c
+++ linux-4.4.0/fs/ext4/ialloc.c
@@ -63,45 +63,6 @@
 		memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
 }
 
-/* Initializes an uninitialized inode bitmap */
-static int ext4_init_inode_bitmap(struct super_block *sb,
-				       struct buffer_head *bh,
-				       ext4_group_t block_group,
-				       struct ext4_group_desc *gdp)
-{
-	struct ext4_group_info *grp;
-	struct ext4_sb_info *sbi = EXT4_SB(sb);
-	J_ASSERT_BH(bh, buffer_locked(bh));
-
-	/* If checksum is bad mark all blocks and inodes use to prevent
-	 * allocation, essentially implementing a per-group read-only flag. */
-	if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
-		ext4_error(sb, "Checksum bad for group %u", block_group);
-		grp = ext4_get_group_info(sb, block_group);
-		if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
-			percpu_counter_sub(&sbi->s_freeclusters_counter,
-					   grp->bb_free);
-		set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
-		if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
-			int count;
-			count = ext4_free_inodes_count(sb, gdp);
-			percpu_counter_sub(&sbi->s_freeinodes_counter,
-					   count);
-		}
-		set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
-		return -EFSBADCRC;
-	}
-
-	memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
-	ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
-			bh->b_data);
-	ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh,
-				   EXT4_INODES_PER_GROUP(sb) / 8);
-	ext4_group_desc_csum_set(sb, block_group, gdp);
-
-	return 0;
-}
-
 void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
 {
 	if (uptodate) {
@@ -127,6 +88,8 @@
 		return -EFSCORRUPTED;
 
 	ext4_lock_group(sb, block_group);
+	if (buffer_verified(bh))
+		goto verified;
 	blk = ext4_inode_bitmap(sb, desc);
 	if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh,
 					   EXT4_INODES_PER_GROUP(sb) / 8)) {
@@ -144,6 +107,7 @@
 		return -EFSBADCRC;
 	}
 	set_buffer_verified(bh);
+verified:
 	ext4_unlock_group(sb, block_group);
 	return 0;
 }
@@ -158,6 +122,7 @@
 ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
 {
 	struct ext4_group_desc *desc;
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct buffer_head *bh = NULL;
 	ext4_fsblk_t bitmap_blk;
 	int err;
@@ -167,6 +132,12 @@
 		return ERR_PTR(-EFSCORRUPTED);
 
 	bitmap_blk = ext4_inode_bitmap(sb, desc);
+	if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
+	    (bitmap_blk >= ext4_blocks_count(sbi->s_es))) {
+		ext4_error(sb, "Invalid inode bitmap blk %llu in "
+			   "block_group %u", bitmap_blk, block_group);
+		return ERR_PTR(-EFSCORRUPTED);
+	}
 	bh = sb_getblk(sb, bitmap_blk);
 	if (unlikely(!bh)) {
 		ext4_error(sb, "Cannot read inode bitmap - "
@@ -184,15 +155,24 @@
 	}
 
 	ext4_lock_group(sb, block_group);
-	if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
-		err = ext4_init_inode_bitmap(sb, bh, block_group, desc);
+	if (ext4_has_group_desc_csum(sb) &&
+	    (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) {
+		if (block_group == 0) {
+			ext4_unlock_group(sb, block_group);
+			unlock_buffer(bh);
+			ext4_error(sb, "Inode bitmap for bg 0 marked "
+				   "uninitialized");
+			err = -EFSCORRUPTED;
+			goto out;
+		}
+		memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
+		ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
+				     sb->s_blocksize * 8, bh->b_data);
 		set_bitmap_uptodate(bh);
 		set_buffer_uptodate(bh);
 		set_buffer_verified(bh);
 		ext4_unlock_group(sb, block_group);
 		unlock_buffer(bh);
-		if (err)
-			goto out;
 		return bh;
 	}
 	ext4_unlock_group(sb, block_group);
@@ -351,11 +331,13 @@
 
 	percpu_counter_inc(&sbi->s_freeinodes_counter);
 	if (sbi->s_log_groups_per_flex) {
-		ext4_group_t f = ext4_flex_group(sbi, block_group);
+		struct flex_groups *fg;
 
-		atomic_inc(&sbi->s_flex_groups[f].free_inodes);
+		fg = sbi_array_rcu_deref(sbi, s_flex_groups,
+					 ext4_flex_group(sbi, block_group));
+		atomic_inc(&fg->free_inodes);
 		if (is_directory)
-			atomic_dec(&sbi->s_flex_groups[f].used_dirs);
+			atomic_dec(&fg->used_dirs);
 	}
 	BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata");
 	fatal = ext4_handle_dirty_metadata(handle, NULL, bh2);
@@ -396,12 +378,13 @@
 			    int flex_size, struct orlov_stats *stats)
 {
 	struct ext4_group_desc *desc;
-	struct flex_groups *flex_group = EXT4_SB(sb)->s_flex_groups;
 
 	if (flex_size > 1) {
-		stats->free_inodes = atomic_read(&flex_group[g].free_inodes);
-		stats->free_clusters = atomic64_read(&flex_group[g].free_clusters);
-		stats->used_dirs = atomic_read(&flex_group[g].used_dirs);
+		struct flex_groups *fg = sbi_array_rcu_deref(EXT4_SB(sb),
+							     s_flex_groups, g);
+		stats->free_inodes = atomic_read(&fg->free_inodes);
+		stats->free_clusters = atomic64_read(&fg->free_clusters);
+		stats->used_dirs = atomic_read(&fg->used_dirs);
 		return;
 	}
 
@@ -762,6 +745,10 @@
 	if (!dir || !dir->i_nlink)
 		return ERR_PTR(-EPERM);
 
+	/* Supplied owner must be valid */
+	if (owner && (owner[0] == (uid_t)-1 || owner[1] == (uid_t)-1))
+		return ERR_PTR(-EOVERFLOW);
+
 	if ((ext4_encrypted_inode(dir) ||
 	     DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) &&
 	    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) {
@@ -774,7 +761,6 @@
 			nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb);
 		encrypt = 1;
 	}
-
 	sb = dir->i_sb;
 	ngroups = ext4_get_groups_count(sb);
 	trace_ext4_request_inode(dir, mode);
@@ -951,7 +937,8 @@
 
 		/* recheck and clear flag under lock if we still need to */
 		ext4_lock_group(sb, group);
-		if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+		if (ext4_has_group_desc_csum(sb) &&
+		    (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
 			gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
 			ext4_free_group_clusters_set(sb, gdp,
 				ext4_free_clusters_after_init(sb, group, gdp));
@@ -1000,7 +987,8 @@
 		if (sbi->s_log_groups_per_flex) {
 			ext4_group_t f = ext4_flex_group(sbi, group);
 
-			atomic_inc(&sbi->s_flex_groups[f].used_dirs);
+			atomic_inc(&sbi_array_rcu_deref(sbi, s_flex_groups,
+							f)->used_dirs);
 		}
 	}
 	if (ext4_has_group_desc_csum(sb)) {
@@ -1023,7 +1011,8 @@
 
 	if (sbi->s_log_groups_per_flex) {
 		flex_group = ext4_flex_group(sbi, group);
-		atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes);
+		atomic_dec(&sbi_array_rcu_deref(sbi, s_flex_groups,
+						flex_group)->free_inodes);
 	}
 
 	inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
@@ -1141,25 +1130,20 @@
 	unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count);
 	ext4_group_t block_group;
 	int bit;
-	struct buffer_head *bitmap_bh;
+	struct buffer_head *bitmap_bh = NULL;
 	struct inode *inode = NULL;
-	long err = -EIO;
+	int err = -EFSCORRUPTED;
 
-	/* Error cases - e2fsck has already cleaned up for us */
-	if (ino > max_ino) {
-		ext4_warning(sb, "bad orphan ino %lu!  e2fsck was run?", ino);
-		err = -EFSCORRUPTED;
-		goto error;
-	}
+	if (ino < EXT4_FIRST_INO(sb) || ino > max_ino)
+		goto bad_orphan;
 
 	block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
 	bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
 	bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
 	if (IS_ERR(bitmap_bh)) {
-		err = PTR_ERR(bitmap_bh);
-		ext4_warning(sb, "inode bitmap error %ld for orphan %lu",
-			     ino, err);
-		goto error;
+		ext4_error(sb, "inode bitmap error %ld for orphan %lu",
+			   ino, PTR_ERR(bitmap_bh));
+		return (struct inode *) bitmap_bh;
 	}
 
 	/* Having the inode bit set should be a 100% indicator that this
@@ -1169,16 +1153,22 @@
 	if (!ext4_test_bit(bit, bitmap_bh->b_data))
 		goto bad_orphan;
 
-	inode = ext4_iget(sb, ino);
-	if (IS_ERR(inode))
-		goto iget_failed;
+	inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
+	if (IS_ERR(inode)) {
+		err = PTR_ERR(inode);
+		ext4_error(sb, "couldn't read orphan inode %lu (err %d)",
+			   ino, err);
+		return inode;
+	}
 
 	/*
-	 * If the orphans has i_nlinks > 0 then it should be able to be
-	 * truncated, otherwise it won't be removed from the orphan list
-	 * during processing and an infinite loop will result.
+	 * If the orphans has i_nlinks > 0 then it should be able to
+	 * be truncated, otherwise it won't be removed from the orphan
+	 * list during processing and an infinite loop will result.
+	 * Similarly, it must not be a bad inode.
 	 */
-	if (inode->i_nlink && !ext4_can_truncate(inode))
+	if ((inode->i_nlink && !ext4_can_truncate(inode)) ||
+	    is_bad_inode(inode))
 		goto bad_orphan;
 
 	if (NEXT_ORPHAN(inode) > max_ino)
@@ -1186,29 +1176,25 @@
 	brelse(bitmap_bh);
 	return inode;
 
-iget_failed:
-	err = PTR_ERR(inode);
-	inode = NULL;
 bad_orphan:
-	ext4_warning(sb, "bad orphan inode %lu!  e2fsck was run?", ino);
-	printk(KERN_WARNING "ext4_test_bit(bit=%d, block=%llu) = %d\n",
-	       bit, (unsigned long long)bitmap_bh->b_blocknr,
-	       ext4_test_bit(bit, bitmap_bh->b_data));
-	printk(KERN_WARNING "inode=%p\n", inode);
+	ext4_error(sb, "bad orphan inode %lu", ino);
+	if (bitmap_bh)
+		printk(KERN_ERR "ext4_test_bit(bit=%d, block=%llu) = %d\n",
+		       bit, (unsigned long long)bitmap_bh->b_blocknr,
+		       ext4_test_bit(bit, bitmap_bh->b_data));
 	if (inode) {
-		printk(KERN_WARNING "is_bad_inode(inode)=%d\n",
+		printk(KERN_ERR "is_bad_inode(inode)=%d\n",
 		       is_bad_inode(inode));
-		printk(KERN_WARNING "NEXT_ORPHAN(inode)=%u\n",
+		printk(KERN_ERR "NEXT_ORPHAN(inode)=%u\n",
 		       NEXT_ORPHAN(inode));
-		printk(KERN_WARNING "max_ino=%lu\n", max_ino);
-		printk(KERN_WARNING "i_nlink=%u\n", inode->i_nlink);
+		printk(KERN_ERR "max_ino=%lu\n", max_ino);
+		printk(KERN_ERR "i_nlink=%u\n", inode->i_nlink);
 		/* Avoid freeing blocks if we got a bad deleted inode */
 		if (inode->i_nlink == 0)
 			inode->i_blocks = 0;
 		iput(inode);
 	}
 	brelse(bitmap_bh);
-error:
 	return ERR_PTR(err);
 }
 
@@ -1330,7 +1316,10 @@
 			    ext4_itable_unused_count(sb, gdp)),
 			    sbi->s_inodes_per_block);
 
-	if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) {
+	if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group) ||
+	    ((group == 0) && ((EXT4_INODES_PER_GROUP(sb) -
+			       ext4_itable_unused_count(sb, gdp)) <
+			      EXT4_FIRST_INO(sb)))) {
 		ext4_error(sb, "Something is wrong with group %u: "
 			   "used itable blocks: %d; "
 			   "itable unused count: %u",
--- linux-4.4.0.orig/fs/ext4/indirect.c
+++ linux-4.4.0/fs/ext4/indirect.c
@@ -555,8 +555,23 @@
 		goto got_it;
 	}
 
-	/* Next simple case - plain lookup or failed read of indirect block */
-	if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO)
+	/* Next simple case - plain lookup failed */
+	if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
+		unsigned epb = inode->i_sb->s_blocksize / sizeof(u32);
+		int i;
+
+		/* Count number blocks in a subtree under 'partial' */
+		count = 1;
+		for (i = 0; partial + i != chain + depth - 1; i++)
+			count *= epb;
+		/* Fill in size of a hole we found */
+		map->m_pblk = 0;
+		map->m_len = min_t(unsigned int, map->m_len, count);
+		goto cleanup;
+	}
+
+	/* Failed read of indirect block */
+	if (err == -EIO)
 		goto cleanup;
 
 	/*
@@ -946,8 +961,7 @@
 	else if (ext4_should_journal_data(inode))
 		flags |= EXT4_FREE_BLOCKS_FORGET;
 
-	if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free,
-				   count)) {
+	if (!ext4_inode_block_valid(inode, block_to_free, count)) {
 		EXT4_ERROR_INODE(inode, "attempt to clear invalid "
 				 "blocks %llu len %lu",
 				 (unsigned long long) block_to_free, count);
@@ -1109,8 +1123,7 @@
 			if (!nr)
 				continue;		/* A hole */
 
-			if (!ext4_data_block_valid(EXT4_SB(inode->i_sb),
-						   nr, 1)) {
+			if (!ext4_inode_block_valid(inode, nr, 1)) {
 				EXT4_ERROR_INODE(inode,
 						 "invalid indirect mapped "
 						 "block %lu (level %d)",
@@ -1323,6 +1336,7 @@
 	ext4_lblk_t offsets[4], offsets2[4];
 	Indirect chain[4], chain2[4];
 	Indirect *partial, *partial2;
+	Indirect *p = NULL, *p2 = NULL;
 	ext4_lblk_t max_block;
 	__le32 nr = 0, nr2 = 0;
 	int n = 0, n2 = 0;
@@ -1364,7 +1378,7 @@
 		}
 
 
-		partial = ext4_find_shared(inode, n, offsets, chain, &nr);
+		partial = p = ext4_find_shared(inode, n, offsets, chain, &nr);
 		if (nr) {
 			if (partial == chain) {
 				/* Shared branch grows from the inode */
@@ -1389,13 +1403,11 @@
 				partial->p + 1,
 				(__le32 *)partial->bh->b_data+addr_per_block,
 				(chain+n-1) - partial);
-			BUFFER_TRACE(partial->bh, "call brelse");
-			brelse(partial->bh);
 			partial--;
 		}
 
 end_range:
-		partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
+		partial2 = p2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
 		if (nr2) {
 			if (partial2 == chain2) {
 				/*
@@ -1425,16 +1437,14 @@
 					   (__le32 *)partial2->bh->b_data,
 					   partial2->p,
 					   (chain2+n2-1) - partial2);
-			BUFFER_TRACE(partial2->bh, "call brelse");
-			brelse(partial2->bh);
 			partial2--;
 		}
 		goto do_indirects;
 	}
 
 	/* Punch happened within the same level (n == n2) */
-	partial = ext4_find_shared(inode, n, offsets, chain, &nr);
-	partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
+	partial = p = ext4_find_shared(inode, n, offsets, chain, &nr);
+	partial2 = p2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
 
 	/* Free top, but only if partial2 isn't its subtree. */
 	if (nr) {
@@ -1491,11 +1501,7 @@
 					   partial->p + 1,
 					   partial2->p,
 					   (chain+n-1) - partial);
-			BUFFER_TRACE(partial->bh, "call brelse");
-			brelse(partial->bh);
-			BUFFER_TRACE(partial2->bh, "call brelse");
-			brelse(partial2->bh);
-			return 0;
+			goto cleanup;
 		}
 
 		/*
@@ -1510,8 +1516,6 @@
 					   partial->p + 1,
 					   (__le32 *)partial->bh->b_data+addr_per_block,
 					   (chain+n-1) - partial);
-			BUFFER_TRACE(partial->bh, "call brelse");
-			brelse(partial->bh);
 			partial--;
 		}
 		if (partial2 > chain2 && depth2 <= depth) {
@@ -1519,11 +1523,21 @@
 					   (__le32 *)partial2->bh->b_data,
 					   partial2->p,
 					   (chain2+n2-1) - partial2);
-			BUFFER_TRACE(partial2->bh, "call brelse");
-			brelse(partial2->bh);
 			partial2--;
 		}
 	}
+
+cleanup:
+	while (p && p > chain) {
+		BUFFER_TRACE(p->bh, "call brelse");
+		brelse(p->bh);
+		p--;
+	}
+	while (p2 && p2 > chain2) {
+		BUFFER_TRACE(p2->bh, "call brelse");
+		brelse(p2->bh);
+		p2--;
+	}
 	return 0;
 
 do_indirects:
@@ -1531,7 +1545,7 @@
 	switch (offsets[0]) {
 	default:
 		if (++n >= n2)
-			return 0;
+			break;
 		nr = i_data[EXT4_IND_BLOCK];
 		if (nr) {
 			ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
@@ -1539,7 +1553,7 @@
 		}
 	case EXT4_IND_BLOCK:
 		if (++n >= n2)
-			return 0;
+			break;
 		nr = i_data[EXT4_DIND_BLOCK];
 		if (nr) {
 			ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
@@ -1547,7 +1561,7 @@
 		}
 	case EXT4_DIND_BLOCK:
 		if (++n >= n2)
-			return 0;
+			break;
 		nr = i_data[EXT4_TIND_BLOCK];
 		if (nr) {
 			ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
@@ -1556,5 +1570,5 @@
 	case EXT4_TIND_BLOCK:
 		;
 	}
-	return 0;
+	goto cleanup;
 }
--- linux-4.4.0.orig/fs/ext4/inline.c
+++ linux-4.4.0/fs/ext4/inline.c
@@ -336,8 +336,10 @@
 
 	len -= EXT4_MIN_INLINE_DATA_SIZE;
 	value = kzalloc(len, GFP_NOFS);
-	if (!value)
+	if (!value) {
+		error = -ENOMEM;
 		goto out;
+	}
 
 	error = ext4_xattr_ibody_get(inode, i.name_index, i.name,
 				     value, len);
@@ -374,7 +376,7 @@
 static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
 				    unsigned int len)
 {
-	int ret, size;
+	int ret, size, no_expand;
 	struct ext4_inode_info *ei = EXT4_I(inode);
 
 	if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
@@ -384,15 +386,14 @@
 	if (size < len)
 		return -ENOSPC;
 
-	down_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_lock_xattr(inode, &no_expand);
 
 	if (ei->i_inline_off)
 		ret = ext4_update_inline_data(handle, inode, len);
 	else
 		ret = ext4_create_inline_data(handle, inode, len);
 
-	up_write(&EXT4_I(inode)->xattr_sem);
-
+	ext4_write_unlock_xattr(inode, &no_expand);
 	return ret;
 }
 
@@ -433,6 +434,7 @@
 
 	memset((void *)ext4_raw_inode(&is.iloc)->i_block,
 		0, EXT4_MIN_INLINE_DATA_SIZE);
+	memset(ei->i_data, 0, EXT4_MIN_INLINE_DATA_SIZE);
 
 	if (ext4_has_feature_extents(inode->i_sb)) {
 		if (S_ISDIR(inode->i_mode) ||
@@ -521,7 +523,7 @@
 					      struct inode *inode,
 					      unsigned flags)
 {
-	int ret, needed_blocks;
+	int ret, needed_blocks, no_expand;
 	handle_t *handle = NULL;
 	int retries = 0, sem_held = 0;
 	struct page *page = NULL;
@@ -561,7 +563,7 @@
 		goto out;
 	}
 
-	down_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_lock_xattr(inode, &no_expand);
 	sem_held = 1;
 	/* If some one has already done this for us, just exit. */
 	if (!ext4_has_inline_data(inode)) {
@@ -597,7 +599,7 @@
 		page_cache_release(page);
 		page = NULL;
 		ext4_orphan_add(handle, inode);
-		up_write(&EXT4_I(inode)->xattr_sem);
+		ext4_write_unlock_xattr(inode, &no_expand);
 		sem_held = 0;
 		ext4_journal_stop(handle);
 		handle = NULL;
@@ -623,7 +625,7 @@
 		page_cache_release(page);
 	}
 	if (sem_held)
-		up_write(&EXT4_I(inode)->xattr_sem);
+		ext4_write_unlock_xattr(inode, &no_expand);
 	if (handle)
 		ext4_journal_stop(handle);
 	brelse(iloc.bh);
@@ -676,6 +678,10 @@
 		goto convert;
 	}
 
+	ret = ext4_journal_get_write_access(handle, iloc.bh);
+	if (ret)
+		goto out;
+
 	flags |= AOP_FLAG_NOFS;
 
 	page = grab_cache_page_write_begin(mapping, 0, flags);
@@ -695,8 +701,11 @@
 
 	if (!PageUptodate(page)) {
 		ret = ext4_read_inline_page(inode, page);
-		if (ret < 0)
+		if (ret < 0) {
+			unlock_page(page);
+			put_page(page);
 			goto out_up_read;
+		}
 	}
 
 	ret = 1;
@@ -704,7 +713,7 @@
 out_up_read:
 	up_read(&EXT4_I(inode)->xattr_sem);
 out:
-	if (handle)
+	if (handle && (ret != 1))
 		ext4_journal_stop(handle);
 	brelse(iloc.bh);
 	return ret;
@@ -716,7 +725,7 @@
 int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
 			       unsigned copied, struct page *page)
 {
-	int ret;
+	int ret, no_expand;
 	void *kaddr;
 	struct ext4_iloc iloc;
 
@@ -734,9 +743,15 @@
 		goto out;
 	}
 
-	down_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_lock_xattr(inode, &no_expand);
 	BUG_ON(!ext4_has_inline_data(inode));
 
+	/*
+	 * ei->i_inline_off may have changed since ext4_write_begin()
+	 * called ext4_try_to_write_inline_data()
+	 */
+	(void) ext4_find_inline_data_nolock(inode);
+
 	kaddr = kmap_atomic(page);
 	ext4_write_inline_data(inode, &iloc, kaddr, pos, len);
 	kunmap_atomic(kaddr);
@@ -744,8 +759,9 @@
 	/* clear page dirty so that writepages wouldn't work for us. */
 	ClearPageDirty(page);
 
-	up_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_unlock_xattr(inode, &no_expand);
 	brelse(iloc.bh);
+	mark_inode_dirty(inode);
 out:
 	return copied;
 }
@@ -755,7 +771,7 @@
 				  unsigned len,
 				  struct page *page)
 {
-	int ret;
+	int ret, no_expand;
 	void *kaddr;
 	struct ext4_iloc iloc;
 
@@ -765,11 +781,11 @@
 		return NULL;
 	}
 
-	down_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_lock_xattr(inode, &no_expand);
 	kaddr = kmap_atomic(page);
 	ext4_write_inline_data(inode, &iloc, kaddr, 0, len);
 	kunmap_atomic(kaddr);
-	up_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_unlock_xattr(inode, &no_expand);
 
 	return iloc.bh;
 }
@@ -852,7 +868,7 @@
 	handle_t *handle;
 	struct page *page;
 	struct ext4_iloc iloc;
-	int retries;
+	int retries = 0;
 
 	ret = ext4_get_inode_loc(inode, &iloc);
 	if (ret)
@@ -881,18 +897,17 @@
 	flags |= AOP_FLAG_NOFS;
 
 	if (ret == -ENOSPC) {
+		ext4_journal_stop(handle);
 		ret = ext4_da_convert_inline_data_to_extent(mapping,
 							    inode,
 							    flags,
 							    fsdata);
-		ext4_journal_stop(handle);
 		if (ret == -ENOSPC &&
 		    ext4_should_retry_alloc(inode->i_sb, &retries))
 			goto retry_journal;
 		goto out;
 	}
 
-
 	page = grab_cache_page_write_begin(mapping, 0, flags);
 	if (!page) {
 		ret = -ENOMEM;
@@ -910,6 +925,9 @@
 		if (ret < 0)
 			goto out_release_page;
 	}
+	ret = ext4_journal_get_write_access(handle, iloc.bh);
+	if (ret)
+		goto out_release_page;
 
 	up_read(&EXT4_I(inode)->xattr_sem);
 	*pagep = page;
@@ -930,9 +948,15 @@
 				  unsigned len, unsigned copied,
 				  struct page *page)
 {
-	int i_size_changed = 0;
+	int ret;
 
-	copied = ext4_write_inline_data_end(inode, pos, len, copied, page);
+	ret = ext4_write_inline_data_end(inode, pos, len, copied, page);
+	if (ret < 0) {
+		unlock_page(page);
+		put_page(page);
+		return ret;
+	}
+	copied = ret;
 
 	/*
 	 * No need to use i_size_read() here, the i_size
@@ -941,10 +965,8 @@
 	 * But it's important to update i_size while still holding page lock:
 	 * page writeout could otherwise come in and zero beyond i_size.
 	 */
-	if (pos+copied > inode->i_size) {
+	if (pos+copied > inode->i_size)
 		i_size_write(inode, pos+copied);
-		i_size_changed = 1;
-	}
 	unlock_page(page);
 	page_cache_release(page);
 
@@ -954,8 +976,7 @@
 	 * ordering of page lock and transaction start for journaling
 	 * filesystems.
 	 */
-	if (i_size_changed)
-		mark_inode_dirty(inode);
+	mark_inode_dirty(inode);
 
 	return copied;
 }
@@ -1149,10 +1170,9 @@
 	set_buffer_uptodate(dir_block);
 	err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
 	if (err)
-		goto out;
+		return err;
 	set_buffer_verified(dir_block);
-out:
-	return err;
+	return ext4_mark_inode_dirty(handle, inode);
 }
 
 static int ext4_convert_inline_data_nolock(handle_t *handle,
@@ -1247,7 +1267,7 @@
 int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
 			      struct dentry *dentry, struct inode *inode)
 {
-	int ret, inline_size;
+	int ret, inline_size, no_expand;
 	void *inline_start;
 	struct ext4_iloc iloc;
 	struct inode *dir = d_inode(dentry->d_parent);
@@ -1256,7 +1276,7 @@
 	if (ret)
 		return ret;
 
-	down_write(&EXT4_I(dir)->xattr_sem);
+	ext4_write_lock_xattr(dir, &no_expand);
 	if (!ext4_has_inline_data(dir))
 		goto out;
 
@@ -1302,7 +1322,7 @@
 
 out:
 	ext4_mark_inode_dirty(handle, dir);
-	up_write(&EXT4_I(dir)->xattr_sem);
+	ext4_write_unlock_xattr(dir, &no_expand);
 	brelse(iloc.bh);
 	return ret;
 }
@@ -1404,7 +1424,7 @@
 		err = ext4_htree_store_dirent(dir_file, hinfo->hash,
 					      hinfo->minor_hash, de, &tmp_str);
 		if (err) {
-			count = err;
+			ret = err;
 			goto out;
 		}
 		count++;
@@ -1613,24 +1633,35 @@
 					struct ext4_dir_entry_2 **res_dir,
 					int *has_inline_data)
 {
+	struct ext4_xattr_ibody_find is = {
+		.s = { .not_found = -ENODATA, },
+	};
+	struct ext4_xattr_info i = {
+		.name_index = EXT4_XATTR_INDEX_SYSTEM,
+		.name = EXT4_XATTR_SYSTEM_DATA,
+	};
 	int ret;
-	struct ext4_iloc iloc;
 	void *inline_start;
 	int inline_size;
 
-	if (ext4_get_inode_loc(dir, &iloc))
+	if (ext4_get_inode_loc(dir, &is.iloc))
 		return NULL;
 
 	down_read(&EXT4_I(dir)->xattr_sem);
+
+	ret = ext4_xattr_ibody_find(dir, &i, &is);
+	if (ret)
+		goto out;
+
 	if (!ext4_has_inline_data(dir)) {
 		*has_inline_data = 0;
 		goto out;
 	}
 
-	inline_start = (void *)ext4_raw_inode(&iloc)->i_block +
+	inline_start = (void *)ext4_raw_inode(&is.iloc)->i_block +
 						EXT4_INLINE_DOTDOT_SIZE;
 	inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE;
-	ret = ext4_search_dir(iloc.bh, inline_start, inline_size,
+	ret = ext4_search_dir(is.iloc.bh, inline_start, inline_size,
 			      dir, fname, d_name, 0, res_dir);
 	if (ret == 1)
 		goto out_find;
@@ -1640,20 +1671,20 @@
 	if (ext4_get_inline_size(dir) == EXT4_MIN_INLINE_DATA_SIZE)
 		goto out;
 
-	inline_start = ext4_get_inline_xattr_pos(dir, &iloc);
+	inline_start = ext4_get_inline_xattr_pos(dir, &is.iloc);
 	inline_size = ext4_get_inline_size(dir) - EXT4_MIN_INLINE_DATA_SIZE;
 
-	ret = ext4_search_dir(iloc.bh, inline_start, inline_size,
+	ret = ext4_search_dir(is.iloc.bh, inline_start, inline_size,
 			      dir, fname, d_name, 0, res_dir);
 	if (ret == 1)
 		goto out_find;
 
 out:
-	brelse(iloc.bh);
-	iloc.bh = NULL;
+	brelse(is.iloc.bh);
+	is.iloc.bh = NULL;
 out_find:
 	up_read(&EXT4_I(dir)->xattr_sem);
-	return iloc.bh;
+	return is.iloc.bh;
 }
 
 int ext4_delete_inline_entry(handle_t *handle,
@@ -1662,7 +1693,7 @@
 			     struct buffer_head *bh,
 			     int *has_inline_data)
 {
-	int err, inline_size;
+	int err, inline_size, no_expand;
 	struct ext4_iloc iloc;
 	void *inline_start;
 
@@ -1670,7 +1701,7 @@
 	if (err)
 		return err;
 
-	down_write(&EXT4_I(dir)->xattr_sem);
+	ext4_write_lock_xattr(dir, &no_expand);
 	if (!ext4_has_inline_data(dir)) {
 		*has_inline_data = 0;
 		goto out;
@@ -1705,7 +1736,7 @@
 
 	ext4_show_inline_dir(dir, iloc.bh, inline_start, inline_size);
 out:
-	up_write(&EXT4_I(dir)->xattr_sem);
+	ext4_write_unlock_xattr(dir, &no_expand);
 	brelse(iloc.bh);
 	if (err != -ENOENT)
 		ext4_std_error(dir->i_sb, err);
@@ -1745,6 +1776,7 @@
 {
 	int err, inline_size;
 	struct ext4_iloc iloc;
+	size_t inline_len;
 	void *inline_pos;
 	unsigned int offset;
 	struct ext4_dir_entry_2 *de;
@@ -1772,8 +1804,9 @@
 		goto out;
 	}
 
+	inline_len = ext4_get_inline_size(dir);
 	offset = EXT4_INLINE_DOTDOT_SIZE;
-	while (offset < dir->i_size) {
+	while (offset < inline_len) {
 		de = ext4_get_inline_entry(dir, &iloc, offset,
 					   &inline_pos, &inline_size);
 		if (ext4_check_dir_entry(dir, NULL, de,
@@ -1804,11 +1837,11 @@
 
 int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
 {
-	int ret;
+	int ret, no_expand;
 
-	down_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_lock_xattr(inode, &no_expand);
 	ret = ext4_destroy_inline_data_nolock(handle, inode);
-	up_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_unlock_xattr(inode, &no_expand);
 
 	return ret;
 }
@@ -1845,55 +1878,19 @@
 	physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data;
 	physical += offsetof(struct ext4_inode, i_block);
 
-	if (physical)
-		error = fiemap_fill_next_extent(fieinfo, start, physical,
-						inline_len, flags);
 	brelse(iloc.bh);
 out:
 	up_read(&EXT4_I(inode)->xattr_sem);
+	if (physical)
+		error = fiemap_fill_next_extent(fieinfo, start, physical,
+						inline_len, flags);
 	return (error < 0 ? error : 0);
 }
 
-/*
- * Called during xattr set, and if we can sparse space 'needed',
- * just create the extent tree evict the data to the outer block.
- *
- * We use jbd2 instead of page cache to move data to the 1st block
- * so that the whole transaction can be committed as a whole and
- * the data isn't lost because of the delayed page cache write.
- */
-int ext4_try_to_evict_inline_data(handle_t *handle,
-				  struct inode *inode,
-				  int needed)
-{
-	int error;
-	struct ext4_xattr_entry *entry;
-	struct ext4_inode *raw_inode;
-	struct ext4_iloc iloc;
-
-	error = ext4_get_inode_loc(inode, &iloc);
-	if (error)
-		return error;
-
-	raw_inode = ext4_raw_inode(&iloc);
-	entry = (struct ext4_xattr_entry *)((void *)raw_inode +
-					    EXT4_I(inode)->i_inline_off);
-	if (EXT4_XATTR_LEN(entry->e_name_len) +
-	    EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) < needed) {
-		error = -ENOSPC;
-		goto out;
-	}
-
-	error = ext4_convert_inline_data_nolock(handle, inode, &iloc);
-out:
-	brelse(iloc.bh);
-	return error;
-}
-
 void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
 {
 	handle_t *handle;
-	int inline_size, value_len, needed_blocks;
+	int inline_size, value_len, needed_blocks, no_expand;
 	size_t i_size;
 	void *value = NULL;
 	struct ext4_xattr_ibody_find is = {
@@ -1910,8 +1907,9 @@
 	if (IS_ERR(handle))
 		return;
 
-	down_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_lock_xattr(inode, &no_expand);
 	if (!ext4_has_inline_data(inode)) {
+		ext4_write_unlock_xattr(inode, &no_expand);
 		*has_inline = 0;
 		ext4_journal_stop(handle);
 		return;
@@ -1968,7 +1966,7 @@
 	up_write(&EXT4_I(inode)->i_data_sem);
 out:
 	brelse(is.iloc.bh);
-	up_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_unlock_xattr(inode, &no_expand);
 	kfree(value);
 	if (inode->i_nlink)
 		ext4_orphan_del(handle, inode);
@@ -1984,7 +1982,7 @@
 
 int ext4_convert_inline_data(struct inode *inode)
 {
-	int error, needed_blocks;
+	int error, needed_blocks, no_expand;
 	handle_t *handle;
 	struct ext4_iloc iloc;
 
@@ -2006,15 +2004,10 @@
 		goto out_free;
 	}
 
-	down_write(&EXT4_I(inode)->xattr_sem);
-	if (!ext4_has_inline_data(inode)) {
-		up_write(&EXT4_I(inode)->xattr_sem);
-		goto out;
-	}
-
-	error = ext4_convert_inline_data_nolock(handle, inode, &iloc);
-	up_write(&EXT4_I(inode)->xattr_sem);
-out:
+	ext4_write_lock_xattr(inode, &no_expand);
+	if (ext4_has_inline_data(inode))
+		error = ext4_convert_inline_data_nolock(handle, inode, &iloc);
+	ext4_write_unlock_xattr(inode, &no_expand);
 	ext4_journal_stop(handle);
 out_free:
 	brelse(iloc.bh);
--- linux-4.4.0.orig/fs/ext4/inode.c
+++ linux-4.4.0/fs/ext4/inode.c
@@ -51,26 +51,31 @@
 			      struct ext4_inode_info *ei)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-	__u16 csum_lo;
-	__u16 csum_hi = 0;
 	__u32 csum;
+	__u16 dummy_csum = 0;
+	int offset = offsetof(struct ext4_inode, i_checksum_lo);
+	unsigned int csum_size = sizeof(dummy_csum);
+
+	csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw, offset);
+	csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, csum_size);
+	offset += csum_size;
+	csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+			   EXT4_GOOD_OLD_INODE_SIZE - offset);
 
-	csum_lo = le16_to_cpu(raw->i_checksum_lo);
-	raw->i_checksum_lo = 0;
-	if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
-	    EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
-		csum_hi = le16_to_cpu(raw->i_checksum_hi);
-		raw->i_checksum_hi = 0;
+	if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
+		offset = offsetof(struct ext4_inode, i_checksum_hi);
+		csum = ext4_chksum(sbi, csum, (__u8 *)raw +
+				   EXT4_GOOD_OLD_INODE_SIZE,
+				   offset - EXT4_GOOD_OLD_INODE_SIZE);
+		if (EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
+			csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum,
+					   csum_size);
+			offset += csum_size;
+		}
+		csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+				   EXT4_INODE_SIZE(inode->i_sb) - offset);
 	}
 
-	csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw,
-			   EXT4_INODE_SIZE(inode->i_sb));
-
-	raw->i_checksum_lo = cpu_to_le16(csum_lo);
-	if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
-	    EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
-		raw->i_checksum_hi = cpu_to_le16(csum_hi);
-
 	return csum;
 }
 
@@ -205,9 +210,9 @@
 		 * Note that directories do not have this problem because they
 		 * don't use page cache.
 		 */
-		if (ext4_should_journal_data(inode) &&
-		    (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode)) &&
-		    inode->i_ino != EXT4_JOURNAL_INO) {
+		if (inode->i_ino != EXT4_JOURNAL_INO &&
+		    ext4_should_journal_data(inode) &&
+		    (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) {
 			journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
 			tid_t commit_tid = EXT4_I(inode)->i_datasync_tid;
 
@@ -372,12 +377,15 @@
 				unsigned int line,
 				struct ext4_map_blocks *map)
 {
-	if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
-				   map->m_len)) {
+	if (ext4_has_feature_journal(inode->i_sb) &&
+	    (inode->i_ino ==
+	     le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
+		return 0;
+	if (!ext4_inode_block_valid(inode, map->m_pblk, map->m_len)) {
 		ext4_error_inode(inode, func, line, map->m_pblk,
-				 "lblock %lu mapped to illegal pblock "
+				 "lblock %lu mapped to illegal pblock %llu "
 				 "(length %d)", (unsigned long) map->m_lblk,
-				 map->m_len);
+				 map->m_pblk, map->m_len);
 		return -EFSCORRUPTED;
 	}
 	return 0;
@@ -445,13 +453,13 @@
  * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
  * based files
  *
- * On success, it returns the number of blocks being mapped or allocated.
- * if create==0 and the blocks are pre-allocated and unwritten block,
- * the result buffer head is unmapped. If the create ==1, it will make sure
- * the buffer head is mapped.
+ * On success, it returns the number of blocks being mapped or allocated.  if
+ * create==0 and the blocks are pre-allocated and unwritten, the resulting @map
+ * is marked as unwritten. If the create == 1, it will mark @map as mapped.
  *
  * It returns 0 if plain look up failed (blocks have not been allocated), in
- * that case, buffer head is unmapped
+ * that case, @map is returned as unmapped but we still do fill map->m_len to
+ * indicate the length of a hole starting at map->m_lblk.
  *
  * It returns the error in case of allocation failure.
  */
@@ -494,6 +502,11 @@
 				retval = map->m_len;
 			map->m_len = retval;
 		} else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) {
+			map->m_pblk = 0;
+			retval = es.es_len - (map->m_lblk - es.es_lblk);
+			if (retval > map->m_len)
+				retval = map->m_len;
+			map->m_len = retval;
 			retval = 0;
 		} else {
 			BUG_ON(1);
@@ -653,10 +666,52 @@
 		ret = check_block_validity(inode, map);
 		if (ret != 0)
 			return ret;
+
+		/*
+		 * Inodes with freshly allocated blocks where contents will be
+		 * visible after transaction commit must be on transaction's
+		 * ordered data list.
+		 */
+		if (map->m_flags & EXT4_MAP_NEW &&
+		    !(map->m_flags & EXT4_MAP_UNWRITTEN) &&
+		    !IS_NOQUOTA(inode) &&
+		    ext4_should_order_data(inode)) {
+			ret = ext4_jbd2_file_inode(handle, inode);
+			if (ret)
+				return ret;
+		}
 	}
 	return retval;
 }
 
+/*
+ * Update EXT4_MAP_FLAGS in bh->b_state. For buffer heads attached to pages
+ * we have to be careful as someone else may be manipulating b_state as well.
+ */
+static void ext4_update_bh_state(struct buffer_head *bh, unsigned long flags)
+{
+	unsigned long old_state;
+	unsigned long new_state;
+
+	flags &= EXT4_MAP_FLAGS;
+
+	/* Dummy buffer_head? Set non-atomically. */
+	if (!bh->b_page) {
+		bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | flags;
+		return;
+	}
+	/*
+	 * Someone else may be modifying b_state. Be careful! This is ugly but
+	 * once we get rid of using bh as a container for mapping information
+	 * to pass to / from get_block functions, this can go away.
+	 */
+	do {
+		old_state = READ_ONCE(bh->b_state);
+		new_state = (old_state & ~EXT4_MAP_FLAGS) | flags;
+	} while (unlikely(
+		 cmpxchg(&bh->b_state, old_state, new_state) != old_state));
+}
+
 /* Maximum number of blocks we map for direct IO at once. */
 #define DIO_MAX_BLOCKS 4096
 
@@ -693,7 +748,7 @@
 		ext4_io_end_t *io_end = ext4_inode_aio(inode);
 
 		map_bh(bh, inode->i_sb, map.m_pblk);
-		bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
+		ext4_update_bh_state(bh, map.m_flags);
 		if (IS_DAX(inode) && buffer_unwritten(bh)) {
 			/*
 			 * dgc: I suspect unwritten conversion on ext4+DAX is
@@ -1117,22 +1172,18 @@
 	loff_t old_size = inode->i_size;
 	int ret = 0, ret2;
 	int i_size_changed = 0;
+	int inline_data = ext4_has_inline_data(inode);
 
 	trace_ext4_write_end(inode, pos, len, copied);
-	if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
-		ret = ext4_jbd2_file_inode(handle, inode);
-		if (ret) {
-			unlock_page(page);
-			page_cache_release(page);
-			goto errout;
-		}
-	}
-
-	if (ext4_has_inline_data(inode)) {
+	if (inline_data &&
+	    ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
 		ret = ext4_write_inline_data_end(inode, pos, len,
 						 copied, page);
-		if (ret < 0)
+		if (ret < 0) {
+			unlock_page(page);
+			put_page(page);
 			goto errout;
+		}
 		copied = ret;
 	} else
 		copied = block_write_end(file, mapping, pos,
@@ -1153,7 +1204,7 @@
 	 * ordering of page lock and transaction start for journaling
 	 * filesystems.
 	 */
-	if (i_size_changed)
+	if (i_size_changed || inline_data)
 		ext4_mark_inode_dirty(handle, inode);
 
 	if (pos + len > inode->i_size && ext4_can_truncate(inode))
@@ -1186,7 +1237,9 @@
  * set the buffer to be dirty, since in data=journalled mode we need
  * to call ext4_handle_dirty_metadata() instead.
  */
-static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
+static void ext4_journalled_zero_new_buffers(handle_t *handle,
+					    struct page *page,
+					    unsigned from, unsigned to)
 {
 	unsigned int block_start = 0, block_end;
 	struct buffer_head *head, *bh;
@@ -1203,7 +1256,7 @@
 					size = min(to, block_end) - start;
 
 					zero_user(page, start, size);
-					set_buffer_uptodate(bh);
+					write_end_fn(handle, bh);
 				}
 				clear_buffer_new(bh);
 			}
@@ -1225,6 +1278,7 @@
 	int partial = 0;
 	unsigned from, to;
 	int size_changed = 0;
+	int inline_data = ext4_has_inline_data(inode);
 
 	trace_ext4_journalled_write_end(inode, pos, len, copied);
 	from = pos & (PAGE_CACHE_SIZE - 1);
@@ -1232,18 +1286,25 @@
 
 	BUG_ON(!ext4_handle_valid(handle));
 
-	if (ext4_has_inline_data(inode))
-		copied = ext4_write_inline_data_end(inode, pos, len,
-						    copied, page);
-	else {
-		if (copied < len) {
-			if (!PageUptodate(page))
-				copied = 0;
-			zero_new_buffers(page, from+copied, to);
+	if (inline_data) {
+		ret = ext4_write_inline_data_end(inode, pos, len,
+						 copied, page);
+		if (ret < 0) {
+			unlock_page(page);
+			put_page(page);
+			goto errout;
 		}
-
+		copied = ret;
+	} else if (unlikely(copied < len) && !PageUptodate(page)) {
+		copied = 0;
+		ext4_journalled_zero_new_buffers(handle, page, from, to);
+	} else {
+		if (unlikely(copied < len))
+			ext4_journalled_zero_new_buffers(handle, page,
+							 from + copied, to);
 		ret = ext4_walk_page_buffers(handle, page_buffers(page), from,
-					     to, &partial, write_end_fn);
+					     from + copied, &partial,
+					     write_end_fn);
 		if (!partial)
 			SetPageUptodate(page);
 	}
@@ -1256,7 +1317,7 @@
 	if (old_size < pos)
 		pagecache_isize_extended(inode, old_size, pos);
 
-	if (size_changed) {
+	if (size_changed || inline_data) {
 		ret2 = ext4_mark_inode_dirty(handle, inode);
 		if (!ret)
 			ret = ret2;
@@ -1269,6 +1330,7 @@
 		 */
 		ext4_orphan_add(handle, inode);
 
+errout:
 	ret2 = ext4_journal_stop(handle);
 	if (!ret)
 		ret = ret2;
@@ -1464,6 +1526,8 @@
 			BUG_ON(!PageLocked(page));
 			BUG_ON(PageWriteback(page));
 			if (invalidate) {
+				if (page_mapped(page))
+					clear_page_dirty_for_io(page);
 				block_invalidatepage(page, 0, PAGE_CACHE_SIZE);
 				ClearPageUptodate(page);
 			}
@@ -1669,7 +1733,7 @@
 		return ret;
 
 	map_bh(bh, inode->i_sb, map.m_pblk);
-	bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
+	ext4_update_bh_state(bh, map.m_flags);
 
 	if (buffer_unwritten(bh)) {
 		/* A delayed write to unwritten bh should be marked
@@ -1751,11 +1815,7 @@
 	}
 
 	if (inline_data) {
-		BUFFER_TRACE(inode_bh, "get write access");
-		ret = ext4_journal_get_write_access(handle, inode_bh);
-
-		err = ext4_handle_dirty_metadata(handle, inode, inode_bh);
-
+		ret = ext4_mark_inode_dirty(handle, inode);
 	} else {
 		ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL,
 					     do_journal_get_write_access);
@@ -1900,15 +1960,29 @@
 static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
 {
 	int len;
-	loff_t size = i_size_read(mpd->inode);
+	loff_t size;
 	int err;
 
 	BUG_ON(page->index != mpd->first_page);
-	if (page->index == size >> PAGE_CACHE_SHIFT)
-		len = size & ~PAGE_CACHE_MASK;
-	else
-		len = PAGE_CACHE_SIZE;
 	clear_page_dirty_for_io(page);
+	/*
+	 * We have to be very careful here!  Nothing protects writeback path
+	 * against i_size changes and the page can be writeably mapped into
+	 * page tables. So an application can be growing i_size and writing
+	 * data through mmap while writeback runs. clear_page_dirty_for_io()
+	 * write-protects our page in page tables and the page cannot get
+	 * written to again until we release page lock. So only after
+	 * clear_page_dirty_for_io() we are safe to sample i_size for
+	 * ext4_bio_write_page() to zero-out tail of the written page. We rely
+	 * on the barrier provided by TestClearPageDirty in
+	 * clear_page_dirty_for_io() to make sure i_size is really sampled only
+	 * after page tables are updated.
+	 */
+	size = i_size_read(mpd->inode);
+	if (page->index == size >> PAGE_SHIFT)
+		len = size & ~PAGE_MASK;
+	else
+		len = PAGE_SIZE;
 	err = ext4_bio_write_page(&mpd->io_submit, page, len, mpd->wbc, false);
 	if (!err)
 		mpd->wbc->nr_to_write--;
@@ -1998,7 +2072,7 @@
 {
 	struct inode *inode = mpd->inode;
 	int err;
-	ext4_lblk_t blocks = (i_size_read(inode) + (1 << inode->i_blkbits) - 1)
+	ext4_lblk_t blocks = (i_size_read(inode) + i_blocksize(inode) - 1)
 							>> inode->i_blkbits;
 
 	do {
@@ -2255,7 +2329,7 @@
 	 * truncate are avoided by checking i_size under i_data_sem.
 	 */
 	disksize = ((loff_t)mpd->first_page) << PAGE_CACHE_SHIFT;
-	if (disksize > EXT4_I(inode)->i_disksize) {
+	if (disksize > READ_ONCE(EXT4_I(inode)->i_disksize)) {
 		int err2;
 		loff_t i_size;
 
@@ -2561,13 +2635,36 @@
 				done = true;
 			}
 		}
-		ext4_journal_stop(handle);
+		/*
+		 * Caution: If the handle is synchronous,
+		 * ext4_journal_stop() can wait for transaction commit
+		 * to finish which may depend on writeback of pages to
+		 * complete or on page lock to be released.  In that
+		 * case, we have to wait until after after we have
+		 * submitted all the IO, released page locks we hold,
+		 * and dropped io_end reference (for extent conversion
+		 * to be able to complete) before stopping the handle.
+		 */
+		if (!ext4_handle_valid(handle) || handle->h_sync == 0) {
+			ext4_journal_stop(handle);
+			handle = NULL;
+		}
 		/* Submit prepared bio */
 		ext4_io_submit(&mpd.io_submit);
 		/* Unlock pages we didn't use */
 		mpage_release_unused_pages(&mpd, give_up_on_write);
-		/* Drop our io_end reference we got from init */
-		ext4_put_io_end(mpd.io_submit.io_end);
+		/*
+		 * Drop our io_end reference we got from init. We have
+		 * to be careful and use deferred io_end finishing if
+		 * we are still holding the transaction as we can
+		 * release the last reference to io_end which may end
+		 * up doing unwritten extent conversion.
+		 */
+		if (handle) {
+			ext4_put_io_end_defer(mpd.io_submit.io_end);
+			ext4_journal_stop(handle);
+		} else
+			ext4_put_io_end(mpd.io_submit.io_end);
 
 		if (ret == -ENOSPC && sbi->s_journal) {
 			/*
@@ -3168,29 +3265,29 @@
 	 * case, we allocate an io_end structure to hook to the iocb.
 	 */
 	iocb->private = NULL;
-	ext4_inode_aio_set(inode, NULL);
-	if (!is_sync_kiocb(iocb)) {
-		io_end = ext4_init_io_end(inode, GFP_NOFS);
-		if (!io_end) {
-			ret = -ENOMEM;
-			goto retake_lock;
-		}
-		/*
-		 * Grab reference for DIO. Will be dropped in ext4_end_io_dio()
-		 */
-		iocb->private = ext4_get_io_end(io_end);
-		/*
-		 * we save the io structure for current async direct
-		 * IO, so that later ext4_map_blocks() could flag the
-		 * io structure whether there is a unwritten extents
-		 * needs to be converted when IO is completed.
-		 */
-		ext4_inode_aio_set(inode, io_end);
-	}
-
 	if (overwrite) {
 		get_block_func = ext4_get_block_write_nolock;
 	} else {
+		ext4_inode_aio_set(inode, NULL);
+		if (!is_sync_kiocb(iocb)) {
+			io_end = ext4_init_io_end(inode, GFP_NOFS);
+			if (!io_end) {
+				ret = -ENOMEM;
+				goto retake_lock;
+			}
+			/*
+			 * Grab reference for DIO. Will be dropped in
+			 * ext4_end_io_dio()
+			 */
+			iocb->private = ext4_get_io_end(io_end);
+			/*
+			 * we save the io structure for current async direct
+			 * IO, so that later ext4_map_blocks() could flag the
+			 * io structure whether there is a unwritten extents
+			 * needs to be converted when IO is completed.
+			 */
+			ext4_inode_aio_set(inode, io_end);
+		}
 		get_block_func = ext4_get_block_write;
 		dio_flags = DIO_LOCKING;
 	}
@@ -3261,6 +3358,13 @@
 	size_t count = iov_iter_count(iter);
 	ssize_t ret;
 
+	if (iov_iter_rw(iter) == READ) {
+		loff_t size = i_size_read(inode);
+
+		if (offset >= size)
+			return 0;
+	}
+
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
 	if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
 		return 0;
@@ -3503,6 +3607,10 @@
 	unsigned blocksize;
 	struct inode *inode = mapping->host;
 
+	/* If we are processing an encrypted inode during orphan list handling */
+	if (ext4_encrypted_inode(inode) && !ext4_has_encryption_key(inode))
+		return 0;
+
 	blocksize = inode->i_sb->s_blocksize;
 	length = blocksize - (offset & (blocksize - 1));
 
@@ -3559,7 +3667,36 @@
 }
 
 /*
- * ext4_punch_hole: punches a hole in a file by releaseing the blocks
+ * We have to make sure i_disksize gets properly updated before we truncate
+ * page cache due to hole punching or zero range. Otherwise i_disksize update
+ * can get lost as it may have been postponed to submission of writeback but
+ * that will never happen after we truncate page cache.
+ */
+int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
+				      loff_t len)
+{
+	handle_t *handle;
+	loff_t size = i_size_read(inode);
+
+	WARN_ON(!mutex_is_locked(&inode->i_mutex));
+	if (offset > size || offset + len < size)
+		return 0;
+
+	if (EXT4_I(inode)->i_disksize >= size)
+		return 0;
+
+	handle = ext4_journal_start(inode, EXT4_HT_MISC, 1);
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+	ext4_update_i_disksize(inode, size);
+	ext4_mark_inode_dirty(handle, inode);
+	ext4_journal_stop(handle);
+
+	return 0;
+}
+
+/*
+ * ext4_punch_hole: punches a hole in a file by releasing the blocks
  * associated with the given offset and length
  *
  * @inode:  File inode
@@ -3574,7 +3711,8 @@
 	struct super_block *sb = inode->i_sb;
 	ext4_lblk_t first_block, stop_block;
 	struct address_space *mapping = inode->i_mapping;
-	loff_t first_block_offset, last_block_offset;
+	loff_t first_block_offset, last_block_offset, max_length;
+	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 	handle_t *handle;
 	unsigned int credits;
 	int ret = 0;
@@ -3584,11 +3722,20 @@
 
 	trace_ext4_punch_hole(inode, offset, length, 0);
 
+	ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
+	if (ext4_has_inline_data(inode)) {
+		down_write(&EXT4_I(inode)->i_mmap_sem);
+		ret = ext4_convert_inline_data(inode);
+		up_write(&EXT4_I(inode)->i_mmap_sem);
+		if (ret)
+			return ret;
+	}
+
 	/*
 	 * Write out all dirty pages to avoid race conditions
 	 * Then release them.
 	 */
-	if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
+	if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
 		ret = filemap_write_and_wait_range(mapping, offset,
 						   offset + length - 1);
 		if (ret)
@@ -3611,6 +3758,14 @@
 		   offset;
 	}
 
+	/*
+	 * For punch hole the length + offset needs to be within one block
+	 * before last range. Adjust the length if it goes beyond that limit.
+	 */
+	max_length = sbi->s_bitmap_maxbytes - inode->i_sb->s_blocksize;
+	if (offset + length > max_length)
+		length = max_length - offset;
+
 	if (offset & (sb->s_blocksize - 1) ||
 	    (offset + length) & (sb->s_blocksize - 1)) {
 		/*
@@ -3623,17 +3778,26 @@
 
 	}
 
+	/* Wait all existing dio workers, newcomers will block on i_mutex */
+	ext4_inode_block_unlocked_dio(inode);
+	inode_dio_wait(inode);
+
+	/*
+	 * Prevent page faults from reinstantiating pages we have released from
+	 * page cache.
+	 */
+	down_write(&EXT4_I(inode)->i_mmap_sem);
 	first_block_offset = round_up(offset, sb->s_blocksize);
 	last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;
 
 	/* Now release the pages and zero block aligned part of pages*/
-	if (last_block_offset > first_block_offset)
+	if (last_block_offset > first_block_offset) {
+		ret = ext4_update_disksize_before_punch(inode, offset, length);
+		if (ret)
+			goto out_dio;
 		truncate_pagecache_range(inode, first_block_offset,
 					 last_block_offset);
-
-	/* Wait all existing dio workers, newcomers will block on i_mutex */
-	ext4_inode_block_unlocked_dio(inode);
-	inode_dio_wait(inode);
+	}
 
 	if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
 		credits = ext4_writepage_trans_blocks(inode);
@@ -3655,41 +3819,39 @@
 		EXT4_BLOCK_SIZE_BITS(sb);
 	stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
 
-	/* If there are no blocks to remove, return now */
-	if (first_block >= stop_block)
-		goto out_stop;
+	/* If there are blocks to remove, do it */
+	if (stop_block > first_block) {
 
-	down_write(&EXT4_I(inode)->i_data_sem);
-	ext4_discard_preallocations(inode);
+		down_write(&EXT4_I(inode)->i_data_sem);
+		ext4_discard_preallocations(inode);
 
-	ret = ext4_es_remove_extent(inode, first_block,
-				    stop_block - first_block);
-	if (ret) {
-		up_write(&EXT4_I(inode)->i_data_sem);
-		goto out_stop;
-	}
+		ret = ext4_es_remove_extent(inode, first_block,
+					    stop_block - first_block);
+		if (ret) {
+			up_write(&EXT4_I(inode)->i_data_sem);
+			goto out_stop;
+		}
 
-	if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
-		ret = ext4_ext_remove_space(inode, first_block,
-					    stop_block - 1);
-	else
-		ret = ext4_ind_remove_space(handle, inode, first_block,
-					    stop_block);
+		if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+			ret = ext4_ext_remove_space(inode, first_block,
+						    stop_block - 1);
+		else
+			ret = ext4_ind_remove_space(handle, inode, first_block,
+						    stop_block);
 
-	up_write(&EXT4_I(inode)->i_data_sem);
+		up_write(&EXT4_I(inode)->i_data_sem);
+	}
 	if (IS_SYNC(inode))
 		ext4_handle_sync(handle);
 
-	/* Now release the pages again to reduce race window */
-	if (last_block_offset > first_block_offset)
-		truncate_pagecache_range(inode, first_block_offset,
-					 last_block_offset);
-
 	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
 	ext4_mark_inode_dirty(handle, inode);
+	if (ret >= 0)
+		ext4_update_inode_fsync_trans(handle, inode, 1);
 out_stop:
 	ext4_journal_stop(handle);
 out_dio:
+	up_write(&EXT4_I(inode)->i_mmap_sem);
 	ext4_inode_resume_unlocked_dio(inode);
 out_mutex:
 	mutex_unlock(&inode->i_mutex);
@@ -3861,7 +4023,8 @@
 	int			inodes_per_block, inode_offset;
 
 	iloc->bh = NULL;
-	if (!ext4_valid_inum(sb, inode->i_ino))
+	if (inode->i_ino < EXT4_ROOT_INO ||
+	    inode->i_ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))
 		return -EFSCORRUPTED;
 
 	iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
@@ -4076,7 +4239,9 @@
 		EXT4_I(inode)->i_inline_off = 0;
 }
 
-struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
+struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
+			  ext4_iget_flags flags, const char *function,
+			  unsigned int line)
 {
 	struct ext4_iloc iloc;
 	struct ext4_inode *raw_inode;
@@ -4084,10 +4249,23 @@
 	struct inode *inode;
 	journal_t *journal = EXT4_SB(sb)->s_journal;
 	long ret;
+	loff_t size;
 	int block;
 	uid_t i_uid;
 	gid_t i_gid;
 
+	if ((!(flags & EXT4_IGET_SPECIAL) &&
+	     (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)) ||
+	    (ino < EXT4_ROOT_INO) ||
+	    (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) {
+		if (flags & EXT4_IGET_HANDLE)
+			return ERR_PTR(-ESTALE);
+		__ext4_error(sb, function, line,
+			     "inode #%lu: comm %s: iget: illegal inode #",
+			     ino, current->comm);
+		return ERR_PTR(-EFSCORRUPTED);
+	}
+
 	inode = iget_locked(sb, ino);
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
@@ -4102,6 +4280,19 @@
 		goto bad_inode;
 	raw_inode = ext4_raw_inode(&iloc);
 
+	if ((ino == EXT4_ROOT_INO) && (raw_inode->i_links_count == 0)) {
+		ext4_error_inode(inode, function, line, 0,
+				 "iget: root inode unallocated");
+		ret = -EFSCORRUPTED;
+		goto bad_inode;
+	}
+
+	if ((flags & EXT4_IGET_HANDLE) &&
+	    (raw_inode->i_links_count == 0) && (raw_inode->i_mode == 0)) {
+		ret = -ESTALE;
+		goto bad_inode;
+	}
+
 	if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
 		ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
 		if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
@@ -4128,7 +4319,8 @@
 	}
 
 	if (!ext4_inode_csum_verify(inode, raw_inode, ei)) {
-		EXT4_ERROR_INODE(inode, "checksum invalid");
+		ext4_error_inode(inode, function, line, 0,
+				 "iget: checksum invalid");
 		ret = -EFSBADCRC;
 		goto bad_inode;
 	}
@@ -4175,6 +4367,24 @@
 		ei->i_file_acl |=
 			((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
 	inode->i_size = ext4_isize(raw_inode);
+	if ((size = i_size_read(inode)) < 0) {
+		ext4_error_inode(inode, function, line, 0,
+				 "iget: bad i_size value: %lld", size);
+		ret = -EFSCORRUPTED;
+		goto bad_inode;
+	}
+	/*
+	 * If dir_index is not enabled but there's dir with INDEX flag set,
+	 * we'd normally treat htree data as empty space. But with metadata
+	 * checksumming that corrupts checksums so forbid that.
+	 */
+	if (!ext4_has_feature_dir_index(sb) && ext4_has_metadata_csum(sb) &&
+	    ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) {
+		EXT4_ERROR_INODE(inode,
+				 "iget: Dir with htree data on filesystem without dir_index feature.");
+		ret = -EFSCORRUPTED;
+		goto bad_inode;
+	}
 	ei->i_disksize = inode->i_size;
 #ifdef CONFIG_QUOTA
 	ei->i_reserved_quota = 0;
@@ -4241,8 +4451,9 @@
 
 	ret = 0;
 	if (ei->i_file_acl &&
-	    !ext4_data_block_valid(EXT4_SB(sb), ei->i_file_acl, 1)) {
-		EXT4_ERROR_INODE(inode, "bad extended attribute block %llu",
+	    !ext4_inode_block_valid(inode, ei->i_file_acl, 1)) {
+		ext4_error_inode(inode, function, line, 0,
+				 "iget: bad extended attribute block %llu",
 				 ei->i_file_acl);
 		ret = -EFSCORRUPTED;
 		goto bad_inode;
@@ -4283,6 +4494,7 @@
 			inode->i_op = &ext4_symlink_inode_operations;
 			ext4_set_aops(inode);
 		}
+		inode_nohighmem(inode);
 	} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
 	      S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
 		inode->i_op = &ext4_special_inode_operations;
@@ -4296,7 +4508,8 @@
 		make_bad_inode(inode);
 	} else {
 		ret = -EFSCORRUPTED;
-		EXT4_ERROR_INODE(inode, "bogus i_mode (%o)", inode->i_mode);
+		ext4_error_inode(inode, function, line, 0,
+				 "iget: bogus i_mode (%o)", inode->i_mode);
 		goto bad_inode;
 	}
 	brelse(iloc.bh);
@@ -4310,19 +4523,12 @@
 	return ERR_PTR(ret);
 }
 
-struct inode *ext4_iget_normal(struct super_block *sb, unsigned long ino)
-{
-	if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
-		return ERR_PTR(-EFSCORRUPTED);
-	return ext4_iget(sb, ino);
-}
-
 static int ext4_inode_blocks_set(handle_t *handle,
 				struct ext4_inode *raw_inode,
 				struct ext4_inode_info *ei)
 {
 	struct inode *inode = &(ei->vfs_inode);
-	u64 i_blocks = inode->i_blocks;
+	u64 i_blocks = READ_ONCE(inode->i_blocks);
 	struct super_block *sb = inode->i_sb;
 
 	if (i_blocks <= ~0U) {
@@ -4458,14 +4664,14 @@
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
-		if (!ei->i_dtime) {
+		if (ei->i_dtime && list_empty(&ei->i_orphan)) {
+			raw_inode->i_uid_high = 0;
+			raw_inode->i_gid_high = 0;
+		} else {
 			raw_inode->i_uid_high =
 				cpu_to_le16(high_16_bits(i_uid));
 			raw_inode->i_gid_high =
 				cpu_to_le16(high_16_bits(i_gid));
-		} else {
-			raw_inode->i_uid_high = 0;
-			raw_inode->i_gid_high = 0;
 		}
 	} else {
 		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
@@ -4708,7 +4914,7 @@
 	int orphan = 0;
 	const unsigned int ia_valid = attr->ia_valid;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
@@ -4802,7 +5008,7 @@
 			up_write(&EXT4_I(inode)->i_data_sem);
 			ext4_journal_stop(handle);
 			if (error) {
-				if (orphan)
+				if (orphan && inode->i_nlink)
 					ext4_orphan_del(NULL, inode);
 				goto err_out;
 			}
@@ -4823,6 +5029,7 @@
 			} else
 				ext4_wait_for_tail_page_commit(inode);
 		}
+		down_write(&EXT4_I(inode)->i_mmap_sem);
 		/*
 		 * Truncate pagecache after we've waited for commit
 		 * in data=journal mode to make pages freeable.
@@ -4830,6 +5037,7 @@
 		truncate_pagecache(inode, inode->i_size);
 		if (shrink)
 			ext4_truncate(inode);
+		up_write(&EXT4_I(inode)->i_mmap_sem);
 	}
 
 	if (!rc) {
@@ -5036,10 +5244,25 @@
 {
 	struct ext4_inode *raw_inode;
 	struct ext4_xattr_ibody_header *header;
+	unsigned int inode_size = EXT4_INODE_SIZE(inode->i_sb);
+	struct ext4_inode_info *ei = EXT4_I(inode);
 
 	if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
 		return 0;
 
+	/* this was checked at iget time, but double check for good measure */
+	if ((EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > inode_size) ||
+	    (ei->i_extra_isize & 3)) {
+		EXT4_ERROR_INODE(inode, "bad extra_isize %u (inode size %u)",
+				 ei->i_extra_isize,
+				 EXT4_INODE_SIZE(inode->i_sb));
+		return -EFSCORRUPTED;
+	}
+	if ((new_extra_isize < ei->i_extra_isize) ||
+	    (new_extra_isize < 4) ||
+	    (new_extra_isize > inode_size - EXT4_GOOD_OLD_INODE_SIZE))
+		return -EINVAL;	/* Should never happen */
+
 	raw_inode = ext4_raw_inode(&iloc);
 
 	header = IHDR(inode, raw_inode);
@@ -5047,8 +5270,9 @@
 	/* No extended attributes present */
 	if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
 	    header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
-		memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
-			new_extra_isize);
+		memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
+		       EXT4_I(inode)->i_extra_isize, 0,
+		       new_extra_isize - EXT4_I(inode)->i_extra_isize);
 		EXT4_I(inode)->i_extra_isize = new_extra_isize;
 		return 0;
 	}
@@ -5081,6 +5305,8 @@
 	might_sleep();
 	trace_ext4_mark_inode_dirty(inode, _RET_IP_);
 	err = ext4_reserve_inode_write(handle, inode, &iloc);
+	if (err)
+		return err;
 	if (ext4_handle_valid(handle) &&
 	    EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
 	    !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) {
@@ -5097,8 +5323,6 @@
 						      sbi->s_want_extra_isize,
 						      iloc, handle);
 			if (ret) {
-				ext4_set_inode_state(inode,
-						     EXT4_STATE_NO_EXPAND);
 				if (mnt_count !=
 					le16_to_cpu(sbi->s_es->s_mnt_count)) {
 					ext4_warning(inode->i_sb,
@@ -5111,9 +5335,7 @@
 			}
 		}
 	}
-	if (!err)
-		err = ext4_mark_iloc_dirty(handle, inode, &iloc);
-	return err;
+	return ext4_mark_iloc_dirty(handle, inode, &iloc);
 }
 
 /*
@@ -5278,6 +5500,13 @@
 
 	sb_start_pagefault(inode->i_sb);
 	file_update_time(vma->vm_file);
+
+	down_read(&EXT4_I(inode)->i_mmap_sem);
+
+	ret = ext4_convert_inline_data(inode);
+	if (ret)
+		goto out_ret;
+
 	/* Delalloc case is easy... */
 	if (test_opt(inode->i_sb, DELALLOC) &&
 	    !ext4_should_journal_data(inode) &&
@@ -5347,6 +5576,87 @@
 out_ret:
 	ret = block_page_mkwrite_return(ret);
 out:
+	up_read(&EXT4_I(inode)->i_mmap_sem);
 	sb_end_pagefault(inode->i_sb);
 	return ret;
 }
+
+int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct inode *inode = file_inode(vma->vm_file);
+	int err;
+
+	down_read(&EXT4_I(inode)->i_mmap_sem);
+	err = filemap_fault(vma, vmf);
+	up_read(&EXT4_I(inode)->i_mmap_sem);
+
+	return err;
+}
+
+/*
+ * Find the first extent at or after @lblk in an inode that is not a hole.
+ * Search for @map_len blocks at most. The extent is returned in @result.
+ *
+ * The function returns 1 if we found an extent. The function returns 0 in
+ * case there is no extent at or after @lblk and in that case also sets
+ * @result->es_len to 0. In case of error, the error code is returned.
+ */
+int ext4_get_next_extent(struct inode *inode, ext4_lblk_t lblk,
+			 unsigned int map_len, struct extent_status *result)
+{
+	struct ext4_map_blocks map;
+	struct extent_status es = {};
+	int ret;
+
+	map.m_lblk = lblk;
+	map.m_len = map_len;
+
+	/*
+	 * For non-extent based files this loop may iterate several times since
+	 * we do not determine full hole size.
+	 */
+	while (map.m_len > 0) {
+		ret = ext4_map_blocks(NULL, inode, &map, 0);
+		if (ret < 0)
+			return ret;
+		/* There's extent covering m_lblk? Just return it. */
+		if (ret > 0) {
+			int status;
+
+			ext4_es_store_pblock(result, map.m_pblk);
+			result->es_lblk = map.m_lblk;
+			result->es_len = map.m_len;
+			if (map.m_flags & EXT4_MAP_UNWRITTEN)
+				status = EXTENT_STATUS_UNWRITTEN;
+			else
+				status = EXTENT_STATUS_WRITTEN;
+			ext4_es_store_status(result, status);
+			return 1;
+		}
+		ext4_es_find_delayed_extent_range(inode, map.m_lblk,
+						  map.m_lblk + map.m_len - 1,
+						  &es);
+		/* Is delalloc data before next block in extent tree? */
+		if (es.es_len && es.es_lblk < map.m_lblk + map.m_len) {
+			ext4_lblk_t offset = 0;
+
+			if (es.es_lblk < lblk)
+				offset = lblk - es.es_lblk;
+			result->es_lblk = es.es_lblk + offset;
+			ext4_es_store_pblock(result,
+					     ext4_es_pblock(&es) + offset);
+			result->es_len = es.es_len - offset;
+			ext4_es_store_status(result, ext4_es_status(&es));
+
+			return 1;
+		}
+		/* There's a hole at m_lblk, advance us after it */
+		map.m_lblk += map.m_len;
+		map_len -= map.m_len;
+		map.m_len = map_len;
+		cond_resched();
+	}
+	result->es_len = 0;
+	return 0;
+}
+
--- linux-4.4.0.orig/fs/ext4/ioctl.c
+++ linux-4.4.0/fs/ext4/ioctl.c
@@ -105,7 +105,7 @@
 	if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO);
+	inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL);
 	if (IS_ERR(inode_bl))
 		return PTR_ERR(inode_bl);
 	ei_bl = EXT4_I(inode_bl);
@@ -253,7 +253,7 @@
 		 * This test looks nicer. Thanks to Pauline Middelink
 		 */
 		if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
-			if (!capable(CAP_LINUX_IMMUTABLE))
+			if (!ns_capable(sb->s_user_ns, CAP_LINUX_IMMUTABLE))
 				goto flags_out;
 		}
 
@@ -262,7 +262,7 @@
 		 * the relevant capability.
 		 */
 		if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
-			if (!capable(CAP_SYS_RESOURCE))
+			if (!ns_capable(sb->s_user_ns, CAP_SYS_RESOURCE))
 				goto flags_out;
 		}
 		if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
@@ -577,7 +577,7 @@
 		if (err == 0)
 			err = err2;
 		mnt_drop_write_file(filp);
-		if (!err && (o_group > EXT4_SB(sb)->s_groups_count) &&
+		if (!err && (o_group < EXT4_SB(sb)->s_groups_count) &&
 		    ext4_has_group_desc_csum(sb) &&
 		    test_opt(sb, INIT_INODE_TABLE))
 			err = ext4_register_li_request(sb, o_group);
@@ -593,12 +593,19 @@
 		struct fstrim_range range;
 		int ret = 0;
 
-		if (!capable(CAP_SYS_ADMIN))
+		if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
 			return -EPERM;
 
 		if (!blk_queue_discard(q))
 			return -EOPNOTSUPP;
 
+		/*
+		 * We haven't replayed the journal, so we cannot use our
+		 * block-bitmap-guided storage zapping commands.
+		 */
+		if (test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb))
+			return -EROFS;
+
 		if (copy_from_user(&range, (struct fstrim_range __user *)arg,
 		    sizeof(range)))
 			return -EFAULT;
@@ -622,6 +629,9 @@
 		struct ext4_encryption_policy policy;
 		int err = 0;
 
+		if (!ext4_has_feature_encrypt(sb))
+			return -EOPNOTSUPP;
+
 		if (copy_from_user(&policy,
 				   (struct ext4_encryption_policy __user *)arg,
 				   sizeof(policy))) {
@@ -629,7 +639,17 @@
 			goto encryption_policy_out;
 		}
 
+		err = mnt_want_write_file(filp);
+		if (err)
+			goto encryption_policy_out;
+
+		mutex_lock(&inode->i_mutex);
+
 		err = ext4_process_policy(&policy, inode);
+
+		mutex_unlock(&inode->i_mutex);
+
+		mnt_drop_write_file(filp);
 encryption_policy_out:
 		return err;
 #else
@@ -655,7 +675,10 @@
 			err = ext4_journal_get_write_access(handle, sbi->s_sbh);
 			if (err)
 				goto pwsalt_err_journal;
+			lock_buffer(sbi->s_sbh);
 			generate_random_uuid(sbi->s_es->s_encrypt_pw_salt);
+			ext4_superblock_csum_set(sb);
+			unlock_buffer(sbi->s_sbh);
 			err = ext4_handle_dirty_metadata(handle, NULL,
 							 sbi->s_sbh);
 		pwsalt_err_journal:
--- linux-4.4.0.orig/fs/ext4/mballoc.c
+++ linux-4.4.0/fs/ext4/mballoc.c
@@ -26,6 +26,7 @@
 #include <linux/log2.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/nospec.h>
 #include <linux/backing-dev.h>
 #include <trace/events/ext4.h>
 
@@ -669,7 +670,7 @@
 	ext4_grpblk_t min;
 	ext4_grpblk_t max;
 	ext4_grpblk_t chunk;
-	unsigned short border;
+	unsigned int border;
 
 	BUG_ON(len > EXT4_CLUSTERS_PER_GROUP(sb));
 
@@ -815,7 +816,7 @@
  * for this page; do not hold this lock when calling this routine!
  */
 
-static int ext4_mb_init_cache(struct page *page, char *incore)
+static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp)
 {
 	ext4_group_t ngroups;
 	int blocksize;
@@ -848,7 +849,7 @@
 	/* allocate buffer_heads to read bitmaps */
 	if (groups_per_page > 1) {
 		i = sizeof(struct buffer_head *) * groups_per_page;
-		bh = kzalloc(i, GFP_NOFS);
+		bh = kzalloc(i, gfp);
 		if (bh == NULL) {
 			err = -ENOMEM;
 			goto out;
@@ -983,7 +984,7 @@
  * are on the same page e4b->bd_buddy_page is NULL and return value is 0.
  */
 static int ext4_mb_get_buddy_page_lock(struct super_block *sb,
-		ext4_group_t group, struct ext4_buddy *e4b)
+		ext4_group_t group, struct ext4_buddy *e4b, gfp_t gfp)
 {
 	struct inode *inode = EXT4_SB(sb)->s_buddy_cache;
 	int block, pnum, poff;
@@ -1002,7 +1003,7 @@
 	block = group * 2;
 	pnum = block / blocks_per_page;
 	poff = block % blocks_per_page;
-	page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+	page = find_or_create_page(inode->i_mapping, pnum, gfp);
 	if (!page)
 		return -ENOMEM;
 	BUG_ON(page->mapping != inode->i_mapping);
@@ -1016,7 +1017,7 @@
 
 	block++;
 	pnum = block / blocks_per_page;
-	page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+	page = find_or_create_page(inode->i_mapping, pnum, gfp);
 	if (!page)
 		return -ENOMEM;
 	BUG_ON(page->mapping != inode->i_mapping);
@@ -1042,7 +1043,7 @@
  * calling this routine!
  */
 static noinline_for_stack
-int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
+int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp)
 {
 
 	struct ext4_group_info *this_grp;
@@ -1062,7 +1063,7 @@
 	 * The call to ext4_mb_get_buddy_page_lock will mark the
 	 * page accessed.
 	 */
-	ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b);
+	ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b, gfp);
 	if (ret || !EXT4_MB_GRP_NEED_INIT(this_grp)) {
 		/*
 		 * somebody initialized the group
@@ -1072,7 +1073,7 @@
 	}
 
 	page = e4b.bd_bitmap_page;
-	ret = ext4_mb_init_cache(page, NULL);
+	ret = ext4_mb_init_cache(page, NULL, gfp);
 	if (ret)
 		goto err;
 	if (!PageUptodate(page)) {
@@ -1091,7 +1092,7 @@
 	}
 	/* init buddy cache */
 	page = e4b.bd_buddy_page;
-	ret = ext4_mb_init_cache(page, e4b.bd_bitmap);
+	ret = ext4_mb_init_cache(page, e4b.bd_bitmap, gfp);
 	if (ret)
 		goto err;
 	if (!PageUptodate(page)) {
@@ -1109,8 +1110,8 @@
  * calling this routine!
  */
 static noinline_for_stack int
-ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
-					struct ext4_buddy *e4b)
+ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
+		       struct ext4_buddy *e4b, gfp_t gfp)
 {
 	int blocks_per_page;
 	int block;
@@ -1140,7 +1141,7 @@
 		 * we need full data about the group
 		 * to make a good selection
 		 */
-		ret = ext4_mb_init_group(sb, group);
+		ret = ext4_mb_init_group(sb, group, gfp);
 		if (ret)
 			return ret;
 	}
@@ -1168,11 +1169,11 @@
 			 * wait for it to initialize.
 			 */
 			page_cache_release(page);
-		page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+		page = find_or_create_page(inode->i_mapping, pnum, gfp);
 		if (page) {
 			BUG_ON(page->mapping != inode->i_mapping);
 			if (!PageUptodate(page)) {
-				ret = ext4_mb_init_cache(page, NULL);
+				ret = ext4_mb_init_cache(page, NULL, gfp);
 				if (ret) {
 					unlock_page(page);
 					goto err;
@@ -1204,11 +1205,12 @@
 	if (page == NULL || !PageUptodate(page)) {
 		if (page)
 			page_cache_release(page);
-		page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+		page = find_or_create_page(inode->i_mapping, pnum, gfp);
 		if (page) {
 			BUG_ON(page->mapping != inode->i_mapping);
 			if (!PageUptodate(page)) {
-				ret = ext4_mb_init_cache(page, e4b->bd_bitmap);
+				ret = ext4_mb_init_cache(page, e4b->bd_bitmap,
+							 gfp);
 				if (ret) {
 					unlock_page(page);
 					goto err;
@@ -1247,6 +1249,12 @@
 	return ret;
 }
 
+static int ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+			      struct ext4_buddy *e4b)
+{
+	return ext4_mb_load_buddy_gfp(sb, group, e4b, GFP_NOFS);
+}
+
 static void ext4_mb_unload_buddy(struct ext4_buddy *e4b)
 {
 	if (e4b->bd_bitmap_page)
@@ -1259,6 +1267,7 @@
 static int mb_find_order_for_block(struct ext4_buddy *e4b, int block)
 {
 	int order = 1;
+	int bb_incr = 1 << (e4b->bd_blkbits - 1);
 	void *bb;
 
 	BUG_ON(e4b->bd_bitmap == e4b->bd_buddy);
@@ -1271,7 +1280,8 @@
 			/* this block is part of buddy of order 'order' */
 			return order;
 		}
-		bb += 1 << (e4b->bd_blkbits - order);
+		bb += bb_incr;
+		bb_incr >>= 1;
 		order++;
 	}
 	return 0;
@@ -1934,7 +1944,8 @@
 	int free;
 
 	free = e4b->bd_info->bb_free;
-	BUG_ON(free <= 0);
+	if (WARN_ON(free <= 0))
+		return;
 
 	i = e4b->bd_info->bb_first_free;
 
@@ -1955,7 +1966,8 @@
 		}
 
 		mb_find_extent(e4b, i, ac->ac_g_ex.fe_len, &ex);
-		BUG_ON(ex.fe_len <= 0);
+		if (WARN_ON(ex.fe_len <= 0))
+			break;
 		if (free < ex.fe_len) {
 			ext4_grp_locked_error(sb, e4b->bd_group, 0, 0,
 					"%d free clusters as per "
@@ -2045,7 +2057,7 @@
 
 	/* We only do this if the grp has never been initialized */
 	if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
-		int ret = ext4_mb_init_group(ac->ac_sb, group);
+		int ret = ext4_mb_init_group(ac->ac_sb, group, GFP_NOFS);
 		if (ret)
 			return ret;
 	}
@@ -2127,13 +2139,16 @@
 	 * We search using buddy data only if the order of the request
 	 * is greater than equal to the sbi_s_mb_order2_reqs
 	 * You can tune it via /sys/fs/ext4/<partition>/mb_order2_req
+	 * We also support searching for power-of-two requests only for
+	 * requests upto maximum buddy size we have constructed.
 	 */
-	if (i >= sbi->s_mb_order2_reqs) {
+	if (i >= sbi->s_mb_order2_reqs && i <= sb->s_blocksize_bits + 2) {
 		/*
 		 * This should tell if fe_len is exactly power of 2
 		 */
 		if ((ac->ac_g_ex.fe_len & (~(1 << (i - 1)))) == 0)
-			ac->ac_2order = i - 1;
+			ac->ac_2order = array_index_nospec(i - 1,
+							   sb->s_blocksize_bits + 2);
 	}
 
 	/* if stream allocation is enabled, use global goal */
@@ -2198,7 +2213,7 @@
 			}
 
 			ac->ac_groups_scanned++;
-			if (cr == 0 && ac->ac_2order < sb->s_blocksize_bits+2)
+			if (cr == 0)
 				ext4_mb_simple_scan_group(ac, &e4b);
 			else if (cr == 1 && sbi->s_stripe &&
 					!(ac->ac_g_ex.fe_len % sbi->s_stripe))
@@ -2278,7 +2293,7 @@
 	struct ext4_group_info *grinfo;
 	struct sg {
 		struct ext4_group_info info;
-		ext4_grpblk_t counters[16];
+		ext4_grpblk_t counters[EXT4_MAX_BLOCK_LOG_SIZE + 2];
 	} sg;
 
 	group--;
@@ -2365,7 +2380,7 @@
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	unsigned size;
-	struct ext4_group_info ***new_groupinfo;
+	struct ext4_group_info ***old_groupinfo, ***new_groupinfo;
 
 	size = (ngroups + EXT4_DESC_PER_BLOCK(sb) - 1) >>
 		EXT4_DESC_PER_BLOCK_BITS(sb);
@@ -2378,13 +2393,16 @@
 		ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group");
 		return -ENOMEM;
 	}
-	if (sbi->s_group_info) {
-		memcpy(new_groupinfo, sbi->s_group_info,
+	rcu_read_lock();
+	old_groupinfo = rcu_dereference(sbi->s_group_info);
+	if (old_groupinfo)
+		memcpy(new_groupinfo, old_groupinfo,
 		       sbi->s_group_info_size * sizeof(*sbi->s_group_info));
-		kvfree(sbi->s_group_info);
-	}
-	sbi->s_group_info = new_groupinfo;
+	rcu_read_unlock();
+	rcu_assign_pointer(sbi->s_group_info, new_groupinfo);
 	sbi->s_group_info_size = size / sizeof(*sbi->s_group_info);
+	if (old_groupinfo)
+		ext4_kvfree_array_rcu(old_groupinfo);
 	ext4_debug("allocated s_groupinfo array for %d meta_bg's\n", 
 		   sbi->s_group_info_size);
 	return 0;
@@ -2396,6 +2414,7 @@
 {
 	int i;
 	int metalen = 0;
+	int idx = group >> EXT4_DESC_PER_BLOCK_BITS(sb);
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct ext4_group_info **meta_group_info;
 	struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
@@ -2414,12 +2433,12 @@
 				 "for a buddy group");
 			goto exit_meta_group_info;
 		}
-		sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] =
-			meta_group_info;
+		rcu_read_lock();
+		rcu_dereference(sbi->s_group_info)[idx] = meta_group_info;
+		rcu_read_unlock();
 	}
 
-	meta_group_info =
-		sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)];
+	meta_group_info = sbi_array_rcu_deref(sbi, s_group_info, idx);
 	i = group & (EXT4_DESC_PER_BLOCK(sb) - 1);
 
 	meta_group_info[i] = kmem_cache_zalloc(cachep, GFP_NOFS);
@@ -2434,7 +2453,8 @@
 	 * initialize bb_free to be able to skip
 	 * empty groups without initialization
 	 */
-	if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+	if (ext4_has_group_desc_csum(sb) &&
+	    (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
 		meta_group_info[i]->bb_free =
 			ext4_free_clusters_after_init(sb, group, desc);
 	} else {
@@ -2466,8 +2486,13 @@
 exit_group_info:
 	/* If a meta_group_info table has been allocated, release it now */
 	if (group % EXT4_DESC_PER_BLOCK(sb) == 0) {
-		kfree(sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]);
-		sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = NULL;
+		struct ext4_group_info ***group_info;
+
+		rcu_read_lock();
+		group_info = rcu_dereference(sbi->s_group_info);
+		kfree(group_info[idx]);
+		group_info[idx] = NULL;
+		rcu_read_unlock();
 	}
 exit_meta_group_info:
 	return -ENOMEM;
@@ -2480,6 +2505,7 @@
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	int err;
 	struct ext4_group_desc *desc;
+	struct ext4_group_info ***group_info;
 	struct kmem_cache *cachep;
 
 	err = ext4_mb_alloc_groupinfo(sb, ngroups);
@@ -2514,11 +2540,16 @@
 	while (i-- > 0)
 		kmem_cache_free(cachep, ext4_get_group_info(sb, i));
 	i = sbi->s_group_info_size;
+	rcu_read_lock();
+	group_info = rcu_dereference(sbi->s_group_info);
 	while (i-- > 0)
-		kfree(sbi->s_group_info[i]);
+		kfree(group_info[i]);
+	rcu_read_unlock();
 	iput(sbi->s_buddy_cache);
 err_freesgi:
-	kvfree(sbi->s_group_info);
+	rcu_read_lock();
+	kvfree(rcu_dereference(sbi->s_group_info));
+	rcu_read_unlock();
 	return -ENOMEM;
 }
 
@@ -2576,7 +2607,7 @@
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	unsigned i, j;
-	unsigned offset;
+	unsigned offset, offset_incr;
 	unsigned max;
 	int ret;
 
@@ -2605,11 +2636,13 @@
 
 	i = 1;
 	offset = 0;
+	offset_incr = 1 << (sb->s_blocksize_bits - 1);
 	max = sb->s_blocksize << 2;
 	do {
 		sbi->s_mb_offsets[i] = offset;
 		sbi->s_mb_maxs[i] = max;
-		offset += 1 << (sb->s_blocksize_bits - i);
+		offset += offset_incr;
+		offset_incr = offset_incr >> 1;
 		max = max >> 1;
 		i++;
 	} while (i <= sb->s_blocksize_bits + 1);
@@ -2704,7 +2737,7 @@
 	ext4_group_t ngroups = ext4_get_groups_count(sb);
 	ext4_group_t i;
 	int num_meta_group_infos;
-	struct ext4_group_info *grinfo;
+	struct ext4_group_info *grinfo, ***group_info;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
 
@@ -2722,9 +2755,12 @@
 		num_meta_group_infos = (ngroups +
 				EXT4_DESC_PER_BLOCK(sb) - 1) >>
 			EXT4_DESC_PER_BLOCK_BITS(sb);
+		rcu_read_lock();
+		group_info = rcu_dereference(sbi->s_group_info);
 		for (i = 0; i < num_meta_group_infos; i++)
-			kfree(sbi->s_group_info[i]);
-		kvfree(sbi->s_group_info);
+			kfree(group_info[i]);
+		kvfree(group_info);
+		rcu_read_unlock();
 	}
 	kfree(sbi->s_mb_offsets);
 	kfree(sbi->s_mb_maxs);
@@ -2924,11 +2960,11 @@
 	block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex);
 
 	len = EXT4_C2B(sbi, ac->ac_b_ex.fe_len);
-	if (!ext4_data_block_valid(sbi, block, len)) {
+	if (!ext4_inode_block_valid(ac->ac_inode, block, len)) {
 		ext4_error(sb, "Allocating blocks %llu-%llu which overlap "
 			   "fs metadata", block, block+len);
 		/* File system mounted not to panic on error
-		 * Fix the bitmap and repeat the block allocation
+		 * Fix the bitmap and return EFSCORRUPTED
 		 * We leak some of the blocks here.
 		 */
 		ext4_lock_group(sb, ac->ac_b_ex.fe_group);
@@ -2937,7 +2973,7 @@
 		ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
 		err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
 		if (!err)
-			err = -EAGAIN;
+			err = -EFSCORRUPTED;
 		goto out_err;
 	}
 
@@ -2953,7 +2989,8 @@
 #endif
 	ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
 		      ac->ac_b_ex.fe_len);
-	if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+	if (ext4_has_group_desc_csum(sb) &&
+	    (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
 		gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
 		ext4_free_group_clusters_set(sb, gdp,
 					     ext4_free_clusters_after_init(sb,
@@ -2978,7 +3015,8 @@
 		ext4_group_t flex_group = ext4_flex_group(sbi,
 							  ac->ac_b_ex.fe_group);
 		atomic64_sub(ac->ac_b_ex.fe_len,
-			     &sbi->s_flex_groups[flex_group].free_clusters);
+			     &sbi_array_rcu_deref(sbi, s_flex_groups,
+						  flex_group)->free_clusters);
 	}
 
 	err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
@@ -3109,6 +3147,13 @@
 	if (ar->pright && start + size - 1 >= ar->lright)
 		size -= start + size - ar->lright;
 
+	/*
+	 * Trim allocation request for filesystems with artificially small
+	 * groups.
+	 */
+	if (size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb))
+		size = EXT4_BLOCKS_PER_GROUP(ac->ac_sb);
+
 	end = start + size;
 
 	/* check we don't cross already preallocated blocks */
@@ -3854,7 +3899,8 @@
 
 	err = ext4_mb_load_buddy(sb, group, &e4b);
 	if (err) {
-		ext4_error(sb, "Error loading buddy information for %u", group);
+		ext4_warning(sb, "Error %d loading buddy information for %u",
+			     err, group);
 		put_bh(bitmap_bh);
 		return 0;
 	}
@@ -4011,10 +4057,11 @@
 		BUG_ON(pa->pa_type != MB_INODE_PA);
 		group = ext4_get_group_number(sb, pa->pa_pstart);
 
-		err = ext4_mb_load_buddy(sb, group, &e4b);
+		err = ext4_mb_load_buddy_gfp(sb, group, &e4b,
+					     GFP_NOFS|__GFP_NOFAIL);
 		if (err) {
-			ext4_error(sb, "Error loading buddy information for %u",
-					group);
+			ext4_error(sb, "Error %d loading buddy information for %u",
+				   err, group);
 			continue;
 		}
 
@@ -4270,11 +4317,14 @@
 	spin_unlock(&lg->lg_prealloc_lock);
 
 	list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
+		int err;
 
 		group = ext4_get_group_number(sb, pa->pa_pstart);
-		if (ext4_mb_load_buddy(sb, group, &e4b)) {
-			ext4_error(sb, "Error loading buddy information for %u",
-					group);
+		err = ext4_mb_load_buddy_gfp(sb, group, &e4b,
+					     GFP_NOFS|__GFP_NOFAIL);
+		if (err) {
+			ext4_error(sb, "Error %d loading buddy information for %u",
+				   err, group);
 			continue;
 		}
 		ext4_lock_group(sb, group);
@@ -4502,18 +4552,7 @@
 	}
 	if (likely(ac->ac_status == AC_STATUS_FOUND)) {
 		*errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs);
-		if (*errp == -EAGAIN) {
-			/*
-			 * drop the reference that we took
-			 * in ext4_mb_use_best_found
-			 */
-			ext4_mb_release_context(ac);
-			ac->ac_b_ex.fe_group = 0;
-			ac->ac_b_ex.fe_start = 0;
-			ac->ac_b_ex.fe_len = 0;
-			ac->ac_status = AC_STATUS_CONTINUE;
-			goto repeat;
-		} else if (*errp) {
+		if (*errp) {
 			ext4_discard_allocated_blocks(ac);
 			goto errout;
 		} else {
@@ -4607,6 +4646,7 @@
 				ext4_group_first_block_no(sb, group) +
 				EXT4_C2B(sbi, cluster),
 				"Block already on to-be-freed list");
+			kmem_cache_free(ext4_free_data_cachep, new_entry);
 			return 0;
 		}
 	}
@@ -4678,7 +4718,7 @@
 
 	sbi = EXT4_SB(sb);
 	if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) &&
-	    !ext4_data_block_valid(sbi, block, count)) {
+	    !ext4_inode_block_valid(inode, block, count)) {
 		ext4_error(sb, "Freeing blocks not in datazone - "
 			   "block = %llu, count = %lu", block, count);
 		goto error_return;
@@ -4815,7 +4855,9 @@
 #endif
 	trace_ext4_mballoc_free(sb, inode, block_group, bit, count_clusters);
 
-	err = ext4_mb_load_buddy(sb, block_group, &e4b);
+	/* __GFP_NOFAIL: retry infinitely, ignore TIF_MEMDIE and memcg limit. */
+	err = ext4_mb_load_buddy_gfp(sb, block_group, &e4b,
+				     GFP_NOFS|__GFP_NOFAIL);
 	if (err)
 		goto error_return;
 
@@ -4867,7 +4909,8 @@
 	if (sbi->s_log_groups_per_flex) {
 		ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
 		atomic64_add(count_clusters,
-			     &sbi->s_flex_groups[flex_group].free_clusters);
+			     &sbi_array_rcu_deref(sbi, s_flex_groups,
+						  flex_group)->free_clusters);
 	}
 
 	if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
@@ -5012,7 +5055,8 @@
 	if (sbi->s_log_groups_per_flex) {
 		ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
 		atomic64_add(EXT4_NUM_B2C(sbi, blocks_freed),
-			     &sbi->s_flex_groups[flex_group].free_clusters);
+			     &sbi_array_rcu_deref(sbi, s_flex_groups,
+						  flex_group)->free_clusters);
 	}
 
 	ext4_mb_unload_buddy(&e4b);
@@ -5105,8 +5149,8 @@
 
 	ret = ext4_mb_load_buddy(sb, group, &e4b);
 	if (ret) {
-		ext4_error(sb, "Error in loading buddy "
-				"information for %u", group);
+		ext4_warning(sb, "Error %d loading buddy information for %u",
+			     ret, group);
 		return ret;
 	}
 	bitmap = e4b.bd_bitmap;
@@ -5217,7 +5261,7 @@
 		grp = ext4_get_group_info(sb, group);
 		/* We only do this if the grp has never been initialized */
 		if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
-			ret = ext4_mb_init_group(sb, group);
+			ret = ext4_mb_init_group(sb, group, GFP_NOFS);
 			if (ret)
 				break;
 		}
--- linux-4.4.0.orig/fs/ext4/migrate.c
+++ linux-4.4.0/fs/ext4/migrate.c
@@ -674,7 +674,7 @@
 		ei->i_data[i] = cpu_to_le32(blk++);
 	ext4_mark_inode_dirty(handle, inode);
 errout:
-	ext4_journal_stop(handle);
 	up_write(&EXT4_I(inode)->i_data_sem);
+	ext4_journal_stop(handle);
 	return ret;
 }
--- linux-4.4.0.orig/fs/ext4/mmp.c
+++ linux-4.4.0/fs/ext4/mmp.c
@@ -48,7 +48,6 @@
 	 */
 	sb_start_write(sb);
 	ext4_mmp_csum_set(sb, mmp);
-	mark_buffer_dirty(bh);
 	lock_buffer(bh);
 	bh->b_end_io = end_buffer_write_sync;
 	get_bh(bh);
--- linux-4.4.0.orig/fs/ext4/move_extent.c
+++ linux-4.4.0/fs/ext4/move_extent.c
@@ -60,10 +60,10 @@
 {
 	if (first < second) {
 		down_write(&EXT4_I(first)->i_data_sem);
-		down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING);
+		down_write_nested(&EXT4_I(second)->i_data_sem, I_DATA_SEM_OTHER);
 	} else {
 		down_write(&EXT4_I(second)->i_data_sem);
-		down_write_nested(&EXT4_I(first)->i_data_sem, SINGLE_DEPTH_NESTING);
+		down_write_nested(&EXT4_I(first)->i_data_sem, I_DATA_SEM_OTHER);
 
 	}
 }
@@ -187,7 +187,7 @@
 	if (PageUptodate(page))
 		return 0;
 
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, blocksize, 0);
 
@@ -265,11 +265,12 @@
 	ext4_lblk_t orig_blk_offset, donor_blk_offset;
 	unsigned long blocksize = orig_inode->i_sb->s_blocksize;
 	unsigned int tmp_data_size, data_size, replaced_size;
-	int err2, jblocks, retries = 0;
+	int i, err2, jblocks, retries = 0;
 	int replaced_count = 0;
 	int from = data_offset_in_page << orig_inode->i_blkbits;
 	int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits;
 	struct super_block *sb = orig_inode->i_sb;
+	struct buffer_head *bh = NULL;
 
 	/*
 	 * It needs twice the amount of ordinary journal buffers because
@@ -380,8 +381,17 @@
 	}
 	/* Perform all necessary steps similar write_begin()/write_end()
 	 * but keeping in mind that i_size will not change */
-	*err = __block_write_begin(pagep[0], from, replaced_size,
-				   ext4_get_block);
+	if (!page_has_buffers(pagep[0]))
+		create_empty_buffers(pagep[0], 1 << orig_inode->i_blkbits, 0);
+	bh = page_buffers(pagep[0]);
+	for (i = 0; i < data_offset_in_page; i++)
+		bh = bh->b_this_page;
+	for (i = 0; i < block_len_in_page; i++) {
+		*err = ext4_get_block(orig_inode, orig_blk_offset + i, bh, 0);
+		if (*err < 0)
+			break;
+		bh = bh->b_this_page;
+	}
 	if (!*err)
 		*err = block_commit_write(pagep[0], from, from + replaced_size);
 
@@ -474,6 +484,13 @@
 		return -EBUSY;
 	}
 
+	if (IS_NOQUOTA(orig_inode) || IS_NOQUOTA(donor_inode)) {
+		ext4_debug("ext4 move extent: The argument files should "
+			"not be quota files [ino:orig %lu, donor %lu]\n",
+			orig_inode->i_ino, donor_inode->i_ino);
+		return -EBUSY;
+	}
+
 	/* Ext4 move extent supports only extent based file */
 	if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) {
 		ext4_debug("ext4 move extent: orig file is not extents "
@@ -509,9 +526,13 @@
 			orig_inode->i_ino, donor_inode->i_ino);
 		return -EINVAL;
 	}
-	if (orig_eof < orig_start + *len - 1)
+	if (orig_eof <= orig_start)
+		*len = 0;
+	else if (orig_eof < orig_start + *len - 1)
 		*len = orig_eof - orig_start;
-	if (donor_eof < donor_start + *len - 1)
+	if (donor_eof <= donor_start)
+		*len = 0;
+	else if (donor_eof < donor_start + *len - 1)
 		*len = donor_eof - donor_start;
 	if (!*len) {
 		ext4_debug("ext4 move extent: len should not be 0 "
@@ -581,6 +602,13 @@
 		return -EOPNOTSUPP;
 	}
 
+	if (ext4_encrypted_inode(orig_inode) ||
+	    ext4_encrypted_inode(donor_inode)) {
+		ext4_msg(orig_inode->i_sb, KERN_ERR,
+			 "Online defrag not supported for encrypted files");
+		return -EOPNOTSUPP;
+	}
+
 	/* Protect orig and donor inodes against a truncate */
 	lock_two_nondirectories(orig_inode, donor_inode);
 
@@ -599,6 +627,7 @@
 		goto out;
 	o_end = o_start + len;
 
+	*moved_len = 0;
 	while (o_start < o_end) {
 		struct ext4_extent *ex;
 		ext4_lblk_t cur_blk, next_blk;
@@ -654,7 +683,7 @@
 		 */
 		ext4_double_up_write_data_sem(orig_inode, donor_inode);
 		/* Swap original branches with new branches */
-		move_extent_per_page(o_filp, donor_inode,
+		*moved_len += move_extent_per_page(o_filp, donor_inode,
 				     orig_page_index, donor_page_index,
 				     offset_in_page, cur_len,
 				     unwritten, &ret);
@@ -664,9 +693,6 @@
 		o_start += cur_len;
 		d_start += cur_len;
 	}
-	*moved_len = o_start - orig_blk;
-	if (*moved_len > len)
-		*moved_len = len;
 
 out:
 	if (*moved_len) {
--- linux-4.4.0.orig/fs/ext4/namei.c
+++ linux-4.4.0/fs/ext4/namei.c
@@ -51,6 +51,7 @@
 					struct inode *inode,
 					ext4_lblk_t *block)
 {
+	struct ext4_map_blocks map;
 	struct buffer_head *bh;
 	int err;
 
@@ -60,6 +61,21 @@
 		return ERR_PTR(-ENOSPC);
 
 	*block = inode->i_size >> inode->i_sb->s_blocksize_bits;
+	map.m_lblk = *block;
+	map.m_len = 1;
+
+	/*
+	 * We're appending new directory block. Make sure the block is not
+	 * allocated yet, otherwise we will end up corrupting the
+	 * directory.
+	 */
+	err = ext4_map_blocks(NULL, inode, &map, 0);
+	if (err < 0)
+		return ERR_PTR(err);
+	if (err) {
+		EXT4_ERROR_INODE(inode, "Logical block already allocated");
+		return ERR_PTR(-EFSCORRUPTED);
+	}
 
 	bh = ext4_bread(handle, inode, *block, EXT4_GET_BLOCKS_CREATE);
 	if (IS_ERR(bh))
@@ -96,6 +112,13 @@
 	struct ext4_dir_entry *dirent;
 	int is_dx_block = 0;
 
+	if (block >= inode->i_size >> inode->i_blkbits) {
+		ext4_error_inode(inode, func, line, block,
+		       "Attempting to read directory block (%u) that is past i_size (%llu)",
+		       block, inode->i_size);
+		return ERR_PTR(-EFSCORRUPTED);
+	}
+
 	bh = ext4_bread(NULL, inode, block, 0);
 	if (IS_ERR(bh)) {
 		__ext4_warning(inode->i_sb, func, line,
@@ -124,6 +147,7 @@
 	if (!is_dx_block && type == INDEX) {
 		ext4_error_inode(inode, func, line, block,
 		       "directory leaf block found instead of index block");
+		brelse(bh);
 		return ERR_PTR(-EFSCORRUPTED);
 	}
 	if (!ext4_has_metadata_csum(inode->i_sb) ||
@@ -256,9 +280,9 @@
 				 struct dx_hash_info *hinfo,
 				 struct dx_frame *frame);
 static void dx_release(struct dx_frame *frames);
-static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
-		       unsigned blocksize, struct dx_hash_info *hinfo,
-		       struct dx_map_entry map[]);
+static int dx_make_map(struct inode *dir, struct buffer_head *bh,
+		       struct dx_hash_info *hinfo,
+		       struct dx_map_entry *map_tail);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
 static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
 		struct dx_map_entry *offsets, int count, unsigned blocksize);
@@ -420,15 +444,14 @@
 	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 	struct ext4_inode_info *ei = EXT4_I(inode);
 	__u32 csum;
-	__le32 save_csum;
 	int size;
+	__u32 dummy_csum = 0;
+	int offset = offsetof(struct dx_tail, dt_checksum);
 
 	size = count_offset + (count * sizeof(struct dx_entry));
-	save_csum = t->dt_checksum;
-	t->dt_checksum = 0;
 	csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size);
-	csum = ext4_chksum(sbi, csum, (__u8 *)t, sizeof(struct dx_tail));
-	t->dt_checksum = save_csum;
+	csum = ext4_chksum(sbi, csum, (__u8 *)t, offset);
+	csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum));
 
 	return cpu_to_le32(csum);
 }
@@ -730,12 +753,14 @@
 dx_probe(struct ext4_filename *fname, struct inode *dir,
 	 struct dx_hash_info *hinfo, struct dx_frame *frame_in)
 {
-	unsigned count, indirect;
+	unsigned count, indirect, level, i;
 	struct dx_entry *at, *entries, *p, *q, *m;
 	struct dx_root *root;
 	struct dx_frame *frame = frame_in;
 	struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR);
 	u32 hash;
+	ext4_lblk_t block;
+	ext4_lblk_t blocks[2];
 
 	frame->bh = ext4_read_dirblock(dir, 0, INDEX);
 	if (IS_ERR(frame->bh))
@@ -784,6 +809,8 @@
 	}
 
 	dxtrace(printk("Look up %x", hash));
+	level = 0;
+	blocks[0] = 0;
 	while (1) {
 		count = dx_get_count(entries);
 		if (!count || count > dx_get_limit(entries)) {
@@ -824,15 +851,27 @@
 			       dx_get_block(at)));
 		frame->entries = entries;
 		frame->at = at;
-		if (!indirect--)
+
+		block = dx_get_block(at);
+		for (i = 0; i <= level; i++) {
+			if (blocks[i] == block) {
+				ext4_warning_inode(dir,
+					"dx entry: tree cycle block %u points back to block %u",
+					blocks[level], block);
+				goto fail;
+			}
+		}
+		if (++level > indirect)
 			return frame;
+		blocks[level] = block;
 		frame++;
-		frame->bh = ext4_read_dirblock(dir, dx_get_block(at), INDEX);
+		frame->bh = ext4_read_dirblock(dir, block, INDEX);
 		if (IS_ERR(frame->bh)) {
 			ret_err = (struct dx_frame *) frame->bh;
 			frame->bh = NULL;
 			goto fail;
 		}
+
 		entries = ((struct dx_node *) frame->bh->b_data)->entries;
 
 		if (dx_get_limit(entries) != dx_node_limit(dir)) {
@@ -1160,15 +1199,23 @@
  * Create map of hash values, offsets, and sizes, stored at end of block.
  * Returns number of entries mapped.
  */
-static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
-		       unsigned blocksize, struct dx_hash_info *hinfo,
+static int dx_make_map(struct inode *dir, struct buffer_head *bh,
+		       struct dx_hash_info *hinfo,
 		       struct dx_map_entry *map_tail)
 {
 	int count = 0;
-	char *base = (char *) de;
+	struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)bh->b_data;
+	unsigned int buflen = bh->b_size;
+	char *base = bh->b_data;
 	struct dx_hash_info h = *hinfo;
 
-	while ((char *) de < base + blocksize) {
+	if (ext4_has_metadata_csum(dir->i_sb))
+		buflen -= sizeof(struct ext4_dir_entry_tail);
+
+	while ((char *) de < base + buflen) {
+		if (ext4_check_dir_entry(dir, NULL, de, bh, base, buflen,
+					 ((char *)de) - base))
+			return -EFSCORRUPTED;
 		if (de->name_len && de->inode) {
 			ext4fs_dirhash(de->name, de->name_len, &h);
 			map_tail--;
@@ -1178,8 +1225,7 @@
 			count++;
 			cond_resched();
 		}
-		/* XXX: do we need to check rec_len == 0 case? -Chris */
-		de = ext4_next_entry(de, blocksize);
+		de = ext4_next_entry(de, dir->i_sb->s_blocksize);
 	}
 	return count;
 }
@@ -1226,27 +1272,26 @@
 }
 
 /*
- * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure.
+ * Test whether a directory entry matches the filename being searched for.
  *
- * `len <= EXT4_NAME_LEN' is guaranteed by caller.
- * `de != NULL' is guaranteed by caller.
+ * Return: %true if the directory entry matches, otherwise %false.
  */
-static inline int ext4_match(struct ext4_filename *fname,
-			     struct ext4_dir_entry_2 *de)
+static inline bool ext4_match(const struct ext4_filename *fname,
+			      const struct ext4_dir_entry_2 *de)
 {
 	const void *name = fname_name(fname);
 	u32 len = fname_len(fname);
 
 	if (!de->inode)
-		return 0;
+		return false;
 
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
 	if (unlikely(!name)) {
 		if (fname->usr_fname->name[0] == '_') {
 			int ret;
-			if (de->name_len < 16)
+			if (de->name_len <= 32)
 				return 0;
-			ret = memcmp(de->name + de->name_len - 16,
+			ret = memcmp(de->name + ((de->name_len - 17) & ~15),
 				     fname->crypto_buf.name + 8, 16);
 			return (ret == 0) ? 1 : 0;
 		}
@@ -1270,48 +1315,31 @@
 	struct ext4_dir_entry_2 * de;
 	char * dlimit;
 	int de_len;
-	int res;
 
 	de = (struct ext4_dir_entry_2 *)search_buf;
 	dlimit = search_buf + buf_size;
 	while ((char *) de < dlimit) {
 		/* this code is executed quadratically often */
 		/* do minimal checking `by hand' */
-		if ((char *) de + de->name_len <= dlimit) {
-			res = ext4_match(fname, de);
-			if (res < 0) {
-				res = -1;
-				goto return_result;
-			}
-			if (res > 0) {
-				/* found a match - just to be sure, do
-				 * a full check */
-				if (ext4_check_dir_entry(dir, NULL, de, bh,
-						bh->b_data,
-						 bh->b_size, offset)) {
-					res = -1;
-					goto return_result;
-				}
-				*res_dir = de;
-				res = 1;
-				goto return_result;
-			}
-
+		if ((char *) de + de->name_len <= dlimit &&
+		    ext4_match(fname, de)) {
+			/* found a match - just to be sure, do
+			 * a full check */
+			if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf,
+						 buf_size, offset))
+				return -1;
+			*res_dir = de;
+			return 1;
 		}
 		/* prevent looping on a bad block */
 		de_len = ext4_rec_len_from_disk(de->rec_len,
 						dir->i_sb->s_blocksize);
-		if (de_len <= 0) {
-			res = -1;
-			goto return_result;
-		}
+		if (de_len <= 0)
+			return -1;
 		offset += de_len;
 		de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
 	}
-
-	res = 0;
-return_result:
-	return res;
+	return 0;
 }
 
 static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block,
@@ -1402,8 +1430,13 @@
 			goto cleanup_and_exit;
 		dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
 			       "falling back\n"));
+		ret = NULL;
 	}
 	nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb);
+	if (!nblocks) {
+		ret = NULL;
+		goto cleanup_and_exit;
+	}
 	start = EXT4_I(dir)->i_dir_start_lookup;
 	if (start >= nblocks)
 		start = 0;
@@ -1413,6 +1446,7 @@
 		/*
 		 * We deal with the read-ahead logic here.
 		 */
+		cond_resched();
 		if (ra_ptr >= ra_max) {
 			/* Refill the readahead buffer */
 			ra_ptr = 0;
@@ -1558,6 +1592,24 @@
 	struct ext4_dir_entry_2 *de;
 	struct buffer_head *bh;
 
+       if (ext4_encrypted_inode(dir)) {
+               int res = ext4_get_encryption_info(dir);
+
+		/*
+		 * This should be a properly defined flag for
+		 * dentry->d_flags when we uplift this to the VFS.
+		 * d_fsdata is set to (void *) 1 if if the dentry is
+		 * created while the directory was encrypted and we
+		 * don't have access to the key.
+		 */
+	       dentry->d_fsdata = NULL;
+	       if (ext4_encryption_info(dir))
+		       dentry->d_fsdata = (void *) 1;
+	       d_set_d_op(dentry, &ext4_encrypted_d_ops);
+	       if (res && res != -ENOKEY)
+		       return ERR_PTR(res);
+       }
+
 	if (dentry->d_name.len > EXT4_NAME_LEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
@@ -1577,7 +1629,7 @@
 					 dentry);
 			return ERR_PTR(-EFSCORRUPTED);
 		}
-		inode = ext4_iget_normal(dir->i_sb, ino);
+		inode = ext4_iget(dir->i_sb, ino, EXT4_IGET_NORMAL);
 		if (inode == ERR_PTR(-ESTALE)) {
 			EXT4_ERROR_INODE(dir,
 					 "deleted inode referenced: %u",
@@ -1622,7 +1674,7 @@
 		return ERR_PTR(-EFSCORRUPTED);
 	}
 
-	return d_obtain_alias(ext4_iget_normal(d_inode(child)->i_sb, ino));
+	return d_obtain_alias(ext4_iget(d_inode(child)->i_sb, ino, EXT4_IGET_NORMAL));
 }
 
 /*
@@ -1720,11 +1772,14 @@
 
 	/* create map in the end of data2 block */
 	map = (struct dx_map_entry *) (data2 + blocksize);
-	count = dx_make_map(dir, (struct ext4_dir_entry_2 *) data1,
-			     blocksize, hinfo, map);
+	count = dx_make_map(dir, *bh, hinfo, map);
+	if (count < 0) {
+		err = count;
+		goto journal_error;
+	}
 	map -= count;
 	dx_sort_map(map, count);
-	/* Split the existing block in the middle, size-wise */
+	/* Ensure that neither split block is over half full */
 	size = 0;
 	move = 0;
 	for (i = count-1; i >= 0; i--) {
@@ -1734,10 +1789,20 @@
 		size += map[i].size;
 		move++;
 	}
-	/* map index at which we will split */
-	split = count - move;
+	/*
+	 * map index at which we will split
+	 *
+	 * If the sum of active entries didn't exceed half the block size, just
+	 * split it in half by count; each resulting block will have at least
+	 * half the space free.
+	 */
+	if (i > 0)
+		split = count - move;
+	else
+		split = count/2;
+
 	hash2 = map[split].hash;
-	continued = hash2 == map[split - 1].hash;
+	continued = split > 0 ? hash2 == map[split - 1].hash : 0;
 	dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n",
 			(unsigned long)dx_get_block(frame->at),
 					hash2, split, count-split));
@@ -1800,24 +1865,15 @@
 	int nlen, rlen;
 	unsigned int offset = 0;
 	char *top;
-	int res;
 
 	de = (struct ext4_dir_entry_2 *)buf;
 	top = buf + buf_size - reclen;
 	while ((char *) de <= top) {
 		if (ext4_check_dir_entry(dir, NULL, de, bh,
-					 buf, buf_size, offset)) {
-			res = -EFSCORRUPTED;
-			goto return_result;
-		}
-		/* Provide crypto context and crypto buffer to ext4 match */
-		res = ext4_match(fname, de);
-		if (res < 0)
-			goto return_result;
-		if (res > 0) {
-			res = -EEXIST;
-			goto return_result;
-		}
+					 buf, buf_size, offset))
+			return -EFSCORRUPTED;
+		if (ext4_match(fname, de))
+			return -EEXIST;
 		nlen = EXT4_DIR_REC_LEN(de->name_len);
 		rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
 		if ((de->inode ? rlen - nlen : rlen) >= reclen)
@@ -1825,15 +1881,11 @@
 		de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
 		offset += rlen;
 	}
-
 	if ((char *) de > top)
-		res = -ENOSPC;
-	else {
-		*dest_de = de;
-		res = 0;
-	}
-return_result:
-	return res;
+		return -ENOSPC;
+
+	*dest_de = de;
+	return 0;
 }
 
 int ext4_insert_dentry(struct inode *dir,
@@ -2018,33 +2070,31 @@
 	frame->entries = entries;
 	frame->at = entries;
 	frame->bh = bh;
-	bh = bh2;
 
 	retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
 	if (retval)
 		goto out_frames;	
-	retval = ext4_handle_dirty_dirent_node(handle, dir, bh);
+	retval = ext4_handle_dirty_dirent_node(handle, dir, bh2);
 	if (retval)
 		goto out_frames;	
 
-	de = do_split(handle,dir, &bh, frame, &fname->hinfo);
+	de = do_split(handle,dir, &bh2, frame, &fname->hinfo);
 	if (IS_ERR(de)) {
 		retval = PTR_ERR(de);
 		goto out_frames;
 	}
-	dx_release(frames);
 
-	retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh);
-	brelse(bh);
-	return retval;
+	retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh2);
 out_frames:
 	/*
 	 * Even if the block split failed, we have to properly write
 	 * out all the changes we did so far. Otherwise we can end up
 	 * with corrupted filesystem.
 	 */
-	ext4_mark_inode_dirty(handle, dir);
+	if (retval)
+		ext4_mark_inode_dirty(handle, dir);
 	dx_release(frames);
+	brelse(bh2);
 	return retval;
 }
 
@@ -2100,6 +2150,13 @@
 		retval = ext4_dx_add_entry(handle, &fname, dentry, inode);
 		if (!retval || (retval != ERR_BAD_DX_DIR))
 			goto out;
+		/* Can we just ignore htree data? */
+		if (ext4_has_metadata_csum(sb)) {
+			EXT4_ERROR_INODE(dir,
+				"Directory has corrupted htree index.");
+			retval = -EFSCORRUPTED;
+			goto out;
+		}
 		ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
 		dx_fallback++;
 		ext4_mark_inode_dirty(handle, dir);
@@ -2314,7 +2371,7 @@
 	de = (struct ext4_dir_entry_2 *)entry_buf;
 	while (i < buf_size - csum_size) {
 		if (ext4_check_dir_entry(dir, NULL, de, bh,
-					 bh->b_data, bh->b_size, i))
+					 entry_buf, buf_size, i))
 			return -EFSCORRUPTED;
 		if (de == de_del)  {
 			if (pde)
@@ -2410,8 +2467,7 @@
 	int err = ext4_add_entry(handle, dentry, inode);
 	if (!err) {
 		ext4_mark_inode_dirty(handle, inode);
-		unlock_new_inode(inode);
-		d_instantiate(dentry, inode);
+		d_instantiate_new(dentry, inode);
 		return 0;
 	}
 	drop_nlink(inode);
@@ -2650,8 +2706,7 @@
 	err = ext4_mark_inode_dirty(handle, dir);
 	if (err)
 		goto out_clear_inode;
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	if (IS_DIRSYNC(dir))
 		ext4_handle_sync(handle);
 
@@ -2809,10 +2864,12 @@
 			 * list entries can cause panics at unmount time.
 			 */
 			mutex_lock(&sbi->s_orphan_lock);
-			list_del(&EXT4_I(inode)->i_orphan);
+			list_del_init(&EXT4_I(inode)->i_orphan);
 			mutex_unlock(&sbi->s_orphan_lock);
 		}
-	}
+	} else
+		brelse(iloc.bh);
+
 	jbd_debug(4, "superblock will point to %lu\n", inode->i_ino);
 	jbd_debug(4, "orphan inode %lu will point to %d\n",
 			inode->i_ino, NEXT_ORPHAN(inode));
@@ -3019,18 +3076,17 @@
 	if (IS_DIRSYNC(dir))
 		ext4_handle_sync(handle);
 
-	if (inode->i_nlink == 0) {
-		ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
-				   dentry->d_name.len, dentry->d_name.name);
-		set_nlink(inode, 1);
-	}
 	retval = ext4_delete_entry(handle, dir, de, bh);
 	if (retval)
 		goto end_unlink;
 	dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
 	ext4_update_dx_flag(dir);
 	ext4_mark_inode_dirty(handle, dir);
-	drop_nlink(inode);
+	if (inode->i_nlink == 0)
+		ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
+				   dentry->d_name.len, dentry->d_name.name);
+	else
+		drop_nlink(inode);
 	if (!inode->i_nlink)
 		ext4_orphan_add(handle, inode);
 	inode->i_ctime = ext4_current_time(inode);
@@ -3132,6 +3188,7 @@
 	if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
 		if (!encryption_required)
 			inode->i_op = &ext4_symlink_inode_operations;
+		inode_nohighmem(inode);
 		ext4_set_aops(inode);
 		/*
 		 * We cannot call page_symlink() with transaction started
@@ -3210,7 +3267,7 @@
 		return -EMLINK;
 	if (ext4_encrypted_inode(dir) &&
 	    !ext4_is_child_context_consistent_with_parent(dir, inode))
-		return -EPERM;
+		return -EXDEV;
 	err = dquot_initialize(dir);
 	if (err)
 		return err;
@@ -3363,8 +3420,6 @@
 			return retval;
 		}
 	}
-	brelse(ent->bh);
-	ent->bh = NULL;
 
 	return 0;
 }
@@ -3491,6 +3546,12 @@
 	int credits;
 	u8 old_file_type;
 
+	if ((ext4_encrypted_inode(old_dir) &&
+	     !ext4_has_encryption_key(old_dir)) ||
+	    (ext4_encrypted_inode(new_dir) &&
+	     !ext4_has_encryption_key(new_dir)))
+		return -ENOKEY;
+
 	retval = dquot_initialize(old.dir);
 	if (retval)
 		return retval;
@@ -3523,7 +3584,7 @@
 	    ext4_encrypted_inode(new.dir) &&
 	    !ext4_is_child_context_consistent_with_parent(new.dir,
 							  old.inode)) {
-		retval = -EPERM;
+		retval = -EXDEV;
 		goto end_rename;
 	}
 
@@ -3561,6 +3622,7 @@
 		}
 	}
 
+	old_file_type = old.de->file_type;
 	if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir))
 		ext4_handle_sync(handle);
 
@@ -3588,7 +3650,6 @@
 	force_reread = (new.dir->i_ino == old.dir->i_ino &&
 			ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA));
 
-	old_file_type = old.de->file_type;
 	if (whiteout) {
 		/*
 		 * Do this before adding a new entry, so the old entry is sure
@@ -3660,15 +3721,19 @@
 	retval = 0;
 
 end_rename:
-	brelse(old.dir_bh);
-	brelse(old.bh);
-	brelse(new.bh);
 	if (whiteout) {
-		if (retval)
+		if (retval) {
+			ext4_setent(handle, &old,
+				old.inode->i_ino, old_file_type);
 			drop_nlink(whiteout);
+		}
 		unlock_new_inode(whiteout);
 		iput(whiteout);
+
 	}
+	brelse(old.dir_bh);
+	brelse(old.bh);
+	brelse(new.bh);
 	if (handle)
 		ext4_journal_stop(handle);
 	return retval;
@@ -3691,6 +3756,12 @@
 	u8 new_file_type;
 	int retval;
 
+	if ((ext4_encrypted_inode(old_dir) &&
+	     !ext4_has_encryption_key(old_dir)) ||
+	    (ext4_encrypted_inode(new_dir) &&
+	     !ext4_has_encryption_key(new_dir)))
+		return -ENOKEY;
+
 	if ((ext4_encrypted_inode(old_dir) ||
 	     ext4_encrypted_inode(new_dir)) &&
 	    (old_dir != new_dir) &&
@@ -3698,7 +3769,7 @@
 							   old.inode) ||
 	     !ext4_is_child_context_consistent_with_parent(old_dir,
 							   new.inode)))
-		return -EPERM;
+		return -EXDEV;
 
 	retval = dquot_initialize(old.dir);
 	if (retval)
--- linux-4.4.0.orig/fs/ext4/page-io.c
+++ linux-4.4.0/fs/ext4/page-io.c
@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
+#include <linux/backing-dev.h>
 
 #include "ext4_jbd2.h"
 #include "xattr.h"
@@ -485,9 +486,20 @@
 
 	if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) &&
 	    nr_to_submit) {
-		data_page = ext4_encrypt(inode, page);
+		gfp_t gfp_flags = GFP_NOFS;
+
+	retry_encrypt:
+		data_page = ext4_encrypt(inode, page, gfp_flags);
 		if (IS_ERR(data_page)) {
 			ret = PTR_ERR(data_page);
+			if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {
+				if (io->io_bio) {
+					ext4_io_submit(io);
+					congestion_wait(BLK_RW_ASYNC, HZ/50);
+				}
+				gfp_flags |= __GFP_NOFAIL;
+				goto retry_encrypt;
+			}
 			data_page = NULL;
 			goto out;
 		}
--- linux-4.4.0.orig/fs/ext4/readpage.c
+++ linux-4.4.0/fs/ext4/readpage.c
@@ -279,7 +279,7 @@
 
 			if (ext4_encrypted_inode(inode) &&
 			    S_ISREG(inode->i_mode)) {
-				ctx = ext4_get_crypto_ctx(inode);
+				ctx = ext4_get_crypto_ctx(inode, GFP_NOFS);
 				if (IS_ERR(ctx))
 					goto set_error_page;
 			}
--- linux-4.4.0.orig/fs/ext4/resize.c
+++ linux-4.4.0/fs/ext4/resize.c
@@ -16,11 +16,39 @@
 
 #include "ext4_jbd2.h"
 
+struct ext4_rcu_ptr {
+	struct rcu_head rcu;
+	void *ptr;
+};
+
+static void ext4_rcu_ptr_callback(struct rcu_head *head)
+{
+	struct ext4_rcu_ptr *ptr;
+
+	ptr = container_of(head, struct ext4_rcu_ptr, rcu);
+	kvfree(ptr->ptr);
+	kfree(ptr);
+}
+
+void ext4_kvfree_array_rcu(void *to_free)
+{
+	struct ext4_rcu_ptr *ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+
+	if (ptr) {
+		ptr->ptr = to_free;
+		call_rcu(&ptr->rcu, ext4_rcu_ptr_callback);
+		return;
+	}
+	synchronize_rcu();
+	kvfree(to_free);
+}
+
 int ext4_resize_begin(struct super_block *sb)
 {
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	int ret = 0;
 
-	if (!capable(CAP_SYS_RESOURCE))
+	if (!ns_capable(sb->s_user_ns, CAP_SYS_RESOURCE))
 		return -EPERM;
 
 	/*
@@ -28,7 +56,7 @@
          * because the user tools have no way of handling this.  Probably a
          * bad time to do it anyways.
          */
-	if (EXT4_SB(sb)->s_sbh->b_blocknr !=
+	if (EXT4_B2C(sbi, sbi->s_sbh->b_blocknr) !=
 	    le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
 		ext4_warning(sb, "won't resize using backup superblock at %llu",
 			(unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
@@ -198,7 +226,7 @@
 	if (flex_gd == NULL)
 		goto out3;
 
-	if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_flex_group_data))
+	if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_group_data))
 		goto out2;
 	flex_gd->count = flexbg_size;
 
@@ -441,16 +469,18 @@
 
 		BUFFER_TRACE(bh, "get_write_access");
 		err = ext4_journal_get_write_access(handle, bh);
-		if (err)
+		if (err) {
+			brelse(bh);
 			return err;
+		}
 		ext4_debug("mark block bitmap %#04llx (+%llu/%u)\n", block,
 			   block - start, count2);
 		ext4_set_bits(bh->b_data, block - start, count2);
 
 		err = ext4_handle_dirty_metadata(handle, NULL, bh);
+		brelse(bh);
 		if (unlikely(err))
 			return err;
-		brelse(bh);
 	}
 
 	return 0;
@@ -538,8 +568,8 @@
 				brelse(gdb);
 				goto out;
 			}
-			memcpy(gdb->b_data, sbi->s_group_desc[j]->b_data,
-			       gdb->b_size);
+			memcpy(gdb->b_data, sbi_array_rcu_deref(sbi,
+				s_group_desc, j)->b_data, gdb->b_size);
 			set_buffer_uptodate(gdb);
 
 			err = ext4_handle_dirty_metadata(handle, NULL, gdb);
@@ -587,7 +617,6 @@
 		bh = bclean(handle, sb, block);
 		if (IS_ERR(bh)) {
 			err = PTR_ERR(bh);
-			bh = NULL;
 			goto out;
 		}
 		overhead = ext4_group_overhead_blocks(sb, group);
@@ -599,9 +628,9 @@
 		ext4_mark_bitmap_end(group_data[i].blocks_count,
 				     sb->s_blocksize * 8, bh->b_data);
 		err = ext4_handle_dirty_metadata(handle, NULL, bh);
+		brelse(bh);
 		if (err)
 			goto out;
-		brelse(bh);
 
 handle_ib:
 		if (bg_flags[i] & EXT4_BG_INODE_UNINIT)
@@ -616,18 +645,16 @@
 		bh = bclean(handle, sb, block);
 		if (IS_ERR(bh)) {
 			err = PTR_ERR(bh);
-			bh = NULL;
 			goto out;
 		}
 
 		ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
 				     sb->s_blocksize * 8, bh->b_data);
 		err = ext4_handle_dirty_metadata(handle, NULL, bh);
+		brelse(bh);
 		if (err)
 			goto out;
-		brelse(bh);
 	}
-	bh = NULL;
 
 	/* Mark group tables in block bitmap */
 	for (j = 0; j < GROUP_TABLE_COUNT; j++) {
@@ -658,7 +685,6 @@
 	}
 
 out:
-	brelse(bh);
 	err2 = ext4_journal_stop(handle);
 	if (err2 && !err)
 		err = err2;
@@ -845,17 +871,20 @@
 	err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh);
 	if (unlikely(err)) {
 		ext4_std_error(sb, err);
+		iloc.bh = NULL;
 		goto exit_inode;
 	}
 	brelse(dind);
 
-	o_group_desc = EXT4_SB(sb)->s_group_desc;
+	rcu_read_lock();
+	o_group_desc = rcu_dereference(EXT4_SB(sb)->s_group_desc);
 	memcpy(n_group_desc, o_group_desc,
 	       EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *));
+	rcu_read_unlock();
 	n_group_desc[gdb_num] = gdb_bh;
-	EXT4_SB(sb)->s_group_desc = n_group_desc;
+	rcu_assign_pointer(EXT4_SB(sb)->s_group_desc, n_group_desc);
 	EXT4_SB(sb)->s_gdb_count++;
-	kvfree(o_group_desc);
+	ext4_kvfree_array_rcu(o_group_desc);
 
 	le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
 	err = ext4_handle_dirty_super(handle, sb);
@@ -896,23 +925,31 @@
 				     sizeof(struct buffer_head *),
 				     GFP_NOFS);
 	if (!n_group_desc) {
+		brelse(gdb_bh);
 		err = -ENOMEM;
 		ext4_warning(sb, "not enough memory for %lu groups",
 			     gdb_num + 1);
 		return err;
 	}
 
-	o_group_desc = EXT4_SB(sb)->s_group_desc;
+	rcu_read_lock();
+	o_group_desc = rcu_dereference(EXT4_SB(sb)->s_group_desc);
 	memcpy(n_group_desc, o_group_desc,
 	       EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *));
+	rcu_read_unlock();
 	n_group_desc[gdb_num] = gdb_bh;
-	EXT4_SB(sb)->s_group_desc = n_group_desc;
-	EXT4_SB(sb)->s_gdb_count++;
-	kvfree(o_group_desc);
+
 	BUFFER_TRACE(gdb_bh, "get_write_access");
 	err = ext4_journal_get_write_access(handle, gdb_bh);
-	if (unlikely(err))
+	if (err) {
+		kvfree(n_group_desc);
 		brelse(gdb_bh);
+		return err;
+	}
+
+	rcu_assign_pointer(EXT4_SB(sb)->s_group_desc, n_group_desc);
+	EXT4_SB(sb)->s_gdb_count++;
+	ext4_kvfree_array_rcu(o_group_desc);
 	return err;
 }
 
@@ -1094,8 +1131,10 @@
 			   backup_block, backup_block -
 			   ext4_group_first_block_no(sb, group));
 		BUFFER_TRACE(bh, "get_write_access");
-		if ((err = ext4_journal_get_write_access(handle, bh)))
+		if ((err = ext4_journal_get_write_access(handle, bh))) {
+			brelse(bh);
 			break;
+		}
 		lock_buffer(bh);
 		memcpy(bh->b_data, data, size);
 		if (rest)
@@ -1172,7 +1211,8 @@
 		 * use non-sparse filesystems anymore.  This is already checked above.
 		 */
 		if (gdb_off) {
-			gdb_bh = sbi->s_group_desc[gdb_num];
+			gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc,
+						     gdb_num);
 			BUFFER_TRACE(gdb_bh, "get_write_access");
 			err = ext4_journal_get_write_access(handle, gdb_bh);
 
@@ -1254,7 +1294,7 @@
 		/*
 		 * get_write_access() has been called on gdb_bh by ext4_add_new_desc().
 		 */
-		gdb_bh = sbi->s_group_desc[gdb_num];
+		gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc, gdb_num);
 		/* Update group descriptor block for new group */
 		gdp = (struct ext4_group_desc *)(gdb_bh->b_data +
 						 gdb_off * EXT4_DESC_SIZE(sb));
@@ -1382,11 +1422,14 @@
 		   percpu_counter_read(&sbi->s_freeclusters_counter));
 	if (ext4_has_feature_flex_bg(sb) && sbi->s_log_groups_per_flex) {
 		ext4_group_t flex_group;
+		struct flex_groups *fg;
+
 		flex_group = ext4_flex_group(sbi, group_data[0].group);
+		fg = sbi_array_rcu_deref(sbi, s_flex_groups, flex_group);
 		atomic64_add(EXT4_NUM_B2C(sbi, free_blocks),
-			     &sbi->s_flex_groups[flex_group].free_clusters);
+			     &fg->free_clusters);
 		atomic_add(EXT4_INODES_PER_GROUP(sb) * flex_gd->count,
-			   &sbi->s_flex_groups[flex_group].free_inodes);
+			   &fg->free_inodes);
 	}
 
 	/*
@@ -1481,7 +1524,8 @@
 		for (; gdb_num <= gdb_num_end; gdb_num++) {
 			struct buffer_head *gdb_bh;
 
-			gdb_bh = sbi->s_group_desc[gdb_num];
+			gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc,
+						     gdb_num);
 			if (old_gdb == gdb_bh->b_blocknr)
 				continue;
 			update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data,
@@ -1599,13 +1643,13 @@
 	}
 
 	if (reserved_gdb || gdb_off == 0) {
-		if (ext4_has_feature_resize_inode(sb) ||
+		if (!ext4_has_feature_resize_inode(sb) ||
 		    !le16_to_cpu(es->s_reserved_gdt_blocks)) {
 			ext4_warning(sb,
 				     "No reserved GDT blocks, can't resize");
 			return -EPERM;
 		}
-		inode = ext4_iget(sb, EXT4_RESIZE_INO);
+		inode = ext4_iget(sb, EXT4_RESIZE_INO, EXT4_IGET_SPECIAL);
 		if (IS_ERR(inode)) {
 			ext4_warning(sb, "Error opening resize inode");
 			return PTR_ERR(inode);
@@ -1903,7 +1947,7 @@
 		return 0;
 
 	n_group = ext4_get_group_number(sb, n_blocks_count - 1);
-	if (n_group > (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) {
+	if (n_group >= (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) {
 		ext4_warning(sb, "resize would cause inodes_count overflow");
 		return -EINVAL;
 	}
@@ -1926,12 +1970,15 @@
 			n_desc_blocks = o_desc_blocks +
 				le16_to_cpu(es->s_reserved_gdt_blocks);
 			n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb);
-			n_blocks_count = n_group * EXT4_BLOCKS_PER_GROUP(sb);
+			n_blocks_count = (ext4_fsblk_t)n_group *
+				EXT4_BLOCKS_PER_GROUP(sb) +
+				le32_to_cpu(es->s_first_data_block);
 			n_group--; /* set to last group number */
 		}
 
 		if (!resize_inode)
-			resize_inode = ext4_iget(sb, EXT4_RESIZE_INO);
+			resize_inode = ext4_iget(sb, EXT4_RESIZE_INO,
+						 EXT4_IGET_SPECIAL);
 		if (IS_ERR(resize_inode)) {
 			ext4_warning(sb, "Error opening resize inode");
 			return PTR_ERR(resize_inode);
@@ -1953,6 +2000,26 @@
 		}
 	}
 
+	/*
+	 * Make sure the last group has enough space so that it's
+	 * guaranteed to have enough space for all metadata blocks
+	 * that it might need to hold.  (We might not need to store
+	 * the inode table blocks in the last block group, but there
+	 * will be cases where this might be needed.)
+	 */
+	if ((ext4_group_first_block_no(sb, n_group) +
+	     ext4_group_overhead_blocks(sb, n_group) + 2 +
+	     sbi->s_itb_per_group + sbi->s_cluster_ratio) >= n_blocks_count) {
+		n_blocks_count = ext4_group_first_block_no(sb, n_group);
+		n_group--;
+		n_blocks_count_retry = 0;
+		if (resize_inode) {
+			iput(resize_inode);
+			resize_inode = NULL;
+		}
+		goto retry;
+	}
+
 	/* extend the last group */
 	if (n_group == o_group)
 		add = n_blocks_count - o_blocks_count;
@@ -1969,7 +2036,7 @@
 
 	err = ext4_alloc_flex_bg_array(sb, n_group + 1);
 	if (err)
-		return err;
+		goto out;
 
 	err = ext4_mb_alloc_groupinfo(sb, n_group + 1);
 	if (err)
@@ -2005,6 +2072,10 @@
 		n_blocks_count_retry = 0;
 		free_flex_gd(flex_gd);
 		flex_gd = NULL;
+		if (resize_inode) {
+			iput(resize_inode);
+			resize_inode = NULL;
+		}
 		goto retry;
 	}
 
@@ -2013,6 +2084,10 @@
 		free_flex_gd(flex_gd);
 	if (resize_inode != NULL)
 		iput(resize_inode);
-	ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", n_blocks_count);
+	if (err)
+		ext4_warning(sb, "error (%d) occurred during "
+			     "file system resize", err);
+	ext4_msg(sb, KERN_INFO, "resized filesystem to %llu",
+		 ext4_blocks_count(es));
 	return err;
 }
--- linux-4.4.0.orig/fs/ext4/super.c
+++ linux-4.4.0/fs/ext4/super.c
@@ -38,6 +38,7 @@
 #include <linux/log2.h>
 #include <linux/crc16.h>
 #include <linux/cleancache.h>
+#include <linux/user_namespace.h>
 #include <asm/uaccess.h>
 
 #include <linux/kthread.h>
@@ -55,7 +56,6 @@
 
 static struct ext4_lazy_init *ext4_li_info;
 static struct mutex ext4_li_mtx;
-static int ext4_mballoc_ready;
 static struct ratelimit_state ext4_mount_msg_ratelimit;
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
@@ -80,13 +80,17 @@
 static void ext4_unregister_li_request(struct super_block *sb);
 static void ext4_clear_request_list(void);
 
+static bool userns_mounts = false;
+module_param(userns_mounts, bool, 0644);
+MODULE_PARM_DESC(userns_mounts, "Allow mounts from unprivileged user namespaces");
+
 #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2)
 static struct file_system_type ext2_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "ext2",
 	.mount		= ext4_mount,
 	.kill_sb	= kill_block_super,
-	.fs_flags	= FS_REQUIRES_DEV,
+	.fs_flags	= FS_REQUIRES_DEV | FS_USERNS_MOUNT,
 };
 MODULE_ALIAS_FS("ext2");
 MODULE_ALIAS("ext2");
@@ -101,7 +105,7 @@
 	.name		= "ext3",
 	.mount		= ext4_mount,
 	.kill_sb	= kill_block_super,
-	.fs_flags	= FS_REQUIRES_DEV,
+	.fs_flags	= FS_REQUIRES_DEV | FS_USERNS_MOUNT,
 };
 MODULE_ALIAS_FS("ext3");
 MODULE_ALIAS("ext3");
@@ -313,7 +317,8 @@
 			    unsigned int line)
 {
 	__save_error_info(sb, func, line);
-	ext4_commit_super(sb, 1);
+	if (!bdev_read_only(sb->s_bdev))
+		ext4_commit_super(sb, 1);
 }
 
 /*
@@ -688,6 +693,7 @@
 	}
 
 	ext4_unlock_group(sb, grp);
+	ext4_commit_super(sb, 1);
 	ext4_handle_error(sb);
 	/*
 	 * We only get here in the ERRORS_RO case; relocking the group
@@ -793,6 +799,9 @@
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct ext4_super_block *es = sbi->s_es;
+	struct buffer_head **group_desc;
+	struct flex_groups **flex_groups;
+	int aborted = 0;
 	int i, err;
 
 	ext4_unregister_li_request(sb);
@@ -802,9 +811,10 @@
 	destroy_workqueue(sbi->rsv_conversion_wq);
 
 	if (sbi->s_journal) {
+		aborted = is_journal_aborted(sbi->s_journal);
 		err = jbd2_journal_destroy(sbi->s_journal);
 		sbi->s_journal = NULL;
-		if (err < 0)
+		if ((err < 0) && !aborted)
 			ext4_abort(sb, "Couldn't clean up the journal");
 	}
 
@@ -814,19 +824,26 @@
 	ext4_release_system_zone(sb);
 	ext4_mb_release(sb);
 	ext4_ext_release(sb);
-	ext4_xattr_put_super(sb);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & MS_RDONLY) && !aborted) {
 		ext4_clear_feature_journal_needs_recovery(sb);
 		es->s_state = cpu_to_le16(sbi->s_mount_state);
 	}
 	if (!(sb->s_flags & MS_RDONLY))
 		ext4_commit_super(sb, 1);
 
+	rcu_read_lock();
+	group_desc = rcu_dereference(sbi->s_group_desc);
 	for (i = 0; i < sbi->s_gdb_count; i++)
-		brelse(sbi->s_group_desc[i]);
-	kvfree(sbi->s_group_desc);
-	kvfree(sbi->s_flex_groups);
+		brelse(group_desc[i]);
+	kvfree(group_desc);
+	flex_groups = rcu_dereference(sbi->s_flex_groups);
+	if (flex_groups) {
+		for (i = 0; i < sbi->s_flex_groups_allocated; i++)
+			kvfree(flex_groups[i]);
+		kvfree(flex_groups);
+	}
+	rcu_read_unlock();
 	percpu_counter_destroy(&sbi->s_freeclusters_counter);
 	percpu_counter_destroy(&sbi->s_freeinodes_counter);
 	percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -958,6 +975,7 @@
 	INIT_LIST_HEAD(&ei->i_orphan);
 	init_rwsem(&ei->xattr_sem);
 	init_rwsem(&ei->i_data_sem);
+	init_rwsem(&ei->i_mmap_sem);
 	inode_init_once(&ei->vfs_inode);
 }
 
@@ -1007,20 +1025,11 @@
 {
 	struct inode *inode;
 
-	if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
-		return ERR_PTR(-ESTALE);
-	if (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))
-		return ERR_PTR(-ESTALE);
-
-	/* iget isn't really right if the inode is currently unallocated!!
-	 *
-	 * ext4_read_inode will return a bad_inode if the inode had been
-	 * deleted, so we should be safe.
-	 *
+	/*
 	 * Currently we don't know the generation for parent directory, so
 	 * a generation of 0 means "accept any"
 	 */
-	inode = ext4_iget_normal(sb, ino);
+	inode = ext4_iget(sb, ino, EXT4_IGET_HANDLE);
 	if (IS_ERR(inode))
 		return ERR_CAST(inode);
 	if (generation && inode->i_generation != generation) {
@@ -1045,6 +1054,16 @@
 				    ext4_nfs_get_inode);
 }
 
+static int ext4_nfs_commit_metadata(struct inode *inode)
+{
+	struct writeback_control wbc = {
+		.sync_mode = WB_SYNC_ALL
+	};
+
+	trace_ext4_nfs_commit_metadata(inode);
+	return ext4_write_inode(inode, &wbc);
+}
+
 /*
  * Try to release metadata pages (indirect blocks, directories) which are
  * mapped via the block device.  Since these pages could have journal heads
@@ -1139,6 +1158,7 @@
 	.fh_to_dentry = ext4_fh_to_dentry,
 	.fh_to_parent = ext4_fh_to_parent,
 	.get_parent = ext4_get_parent,
+	.commit_metadata = ext4_nfs_commit_metadata,
 };
 
 enum {
@@ -1292,9 +1312,9 @@
 		return -1;
 	}
 	if (ext4_has_feature_quota(sb)) {
-		ext4_msg(sb, KERN_ERR, "Cannot set journaled quota options "
-			 "when QUOTA feature is enabled");
-		return -1;
+		ext4_msg(sb, KERN_INFO, "Journaled quota options "
+			 "ignored when QUOTA feature is enabled");
+		return 1;
 	}
 	qname = match_strdup(args);
 	if (!qname) {
@@ -1435,8 +1455,8 @@
 							MOPT_SET | MOPT_Q},
 	{Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
 		       EXT4_MOUNT_GRPQUOTA), MOPT_CLEAR | MOPT_Q},
-	{Opt_usrjquota, 0, MOPT_Q},
-	{Opt_grpjquota, 0, MOPT_Q},
+	{Opt_usrjquota, 0, MOPT_Q | MOPT_STRING},
+	{Opt_grpjquota, 0, MOPT_Q | MOPT_STRING},
 	{Opt_offusrjquota, 0, MOPT_Q},
 	{Opt_offgrpjquota, 0, MOPT_Q},
 	{Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT},
@@ -1512,6 +1532,13 @@
 		return -1;
 	}
 
+	if (token == Opt_err_panic && !capable(CAP_SYS_ADMIN)) {
+		ext4_msg(sb, KERN_ERR,
+			 "Mount option \"%s\" not allowed for unprivileged mounts",
+			 opt);
+		return -1;
+	}
+
 	if (args->from && !(m->flags & MOPT_STRING) && match_int(args, &arg))
 		return -1;
 	if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
@@ -1560,14 +1587,14 @@
 	} else if (token == Opt_stripe) {
 		sbi->s_stripe = arg;
 	} else if (token == Opt_resuid) {
-		uid = make_kuid(current_user_ns(), arg);
+		uid = make_kuid(sb->s_user_ns, arg);
 		if (!uid_valid(uid)) {
 			ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
 			return -1;
 		}
 		sbi->s_resuid = uid;
 	} else if (token == Opt_resgid) {
-		gid = make_kgid(current_user_ns(), arg);
+		gid = make_kgid(sb->s_user_ns, arg);
 		if (!gid_valid(gid)) {
 			ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
 			return -1;
@@ -1606,6 +1633,19 @@
 			return -1;
 		}
 
+		/*
+		 * Refuse access for unprivileged mounts if the user does
+		 * not have rw access to the journal device via the supplied
+		 * path.
+		 */
+		if (!capable(CAP_SYS_ADMIN) &&
+		    inode_permission(d_inode(path.dentry), MAY_READ|MAY_WRITE)) {
+			ext4_msg(sb, KERN_ERR,
+				 "error: Insufficient access to journal path %s",
+				 journal_path);
+			return -1;
+		}
+
 		journal_inode = d_inode(path.dentry);
 		if (!S_ISBLK(journal_inode->i_mode)) {
 			ext4_msg(sb, KERN_ERR, "error: journal path %s "
@@ -1657,10 +1697,10 @@
 			return -1;
 		}
 		if (ext4_has_feature_quota(sb)) {
-			ext4_msg(sb, KERN_ERR,
-				 "Cannot set journaled quota options "
+			ext4_msg(sb, KERN_INFO,
+				 "Quota format mount options ignored "
 				 "when QUOTA feature is enabled");
-			return -1;
+			return 1;
 		}
 		sbi->s_jquota_fmt = m->mount_opt;
 #endif
@@ -1721,11 +1761,11 @@
 #ifdef CONFIG_QUOTA
 	if (ext4_has_feature_quota(sb) &&
 	    (test_opt(sb, USRQUOTA) || test_opt(sb, GRPQUOTA))) {
-		ext4_msg(sb, KERN_ERR, "Cannot set quota options when QUOTA "
-			 "feature is enabled");
-		return 0;
-	}
-	if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+		ext4_msg(sb, KERN_INFO, "Quota feature enabled, usrquota and grpquota "
+			 "mount options ignored.");
+		clear_opt(sb, USRQUOTA);
+		clear_opt(sb, GRPQUOTA);
+	} else if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
 		if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
 			clear_opt(sb, USRQUOTA);
 
@@ -1839,14 +1879,14 @@
 		SEQ_OPTS_PRINT("%s", token2str(m->token));
 	}
 
-	if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) ||
+	if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(sb->s_user_ns, EXT4_DEF_RESUID)) ||
 	    le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
 		SEQ_OPTS_PRINT("resuid=%u",
-				from_kuid_munged(&init_user_ns, sbi->s_resuid));
-	if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) ||
+				from_kuid_munged(sb->s_user_ns, sbi->s_resuid));
+	if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(sb->s_user_ns, EXT4_DEF_RESGID)) ||
 	    le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
 		SEQ_OPTS_PRINT("resgid=%u",
-				from_kgid_munged(&init_user_ns, sbi->s_resgid));
+				from_kgid_munged(sb->s_user_ns, sbi->s_resgid));
 	def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
 	if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
 		SEQ_OPTS_PUTS("errors=remount-ro");
@@ -1963,8 +2003,8 @@
 int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
-	struct flex_groups *new_groups;
-	int size;
+	struct flex_groups **old_groups, **new_groups;
+	int size, i, j;
 
 	if (!sbi->s_log_groups_per_flex)
 		return 0;
@@ -1973,22 +2013,37 @@
 	if (size <= sbi->s_flex_groups_allocated)
 		return 0;
 
-	size = roundup_pow_of_two(size * sizeof(struct flex_groups));
-	new_groups = ext4_kvzalloc(size, GFP_KERNEL);
+	new_groups = ext4_kvzalloc(roundup_pow_of_two(size *
+				   sizeof(*sbi->s_flex_groups)), GFP_KERNEL);
 	if (!new_groups) {
-		ext4_msg(sb, KERN_ERR, "not enough memory for %d flex groups",
-			 size / (int) sizeof(struct flex_groups));
+		ext4_msg(sb, KERN_ERR,
+			 "not enough memory for %d flex group pointers", size);
 		return -ENOMEM;
 	}
-
-	if (sbi->s_flex_groups) {
-		memcpy(new_groups, sbi->s_flex_groups,
-		       (sbi->s_flex_groups_allocated *
-			sizeof(struct flex_groups)));
-		kvfree(sbi->s_flex_groups);
+	for (i = sbi->s_flex_groups_allocated; i < size; i++) {
+		new_groups[i] = ext4_kvzalloc(roundup_pow_of_two(
+					      sizeof(struct flex_groups)),
+					      GFP_KERNEL);
+		if (!new_groups[i]) {
+			for (j = sbi->s_flex_groups_allocated; j < i; j++)
+				kvfree(new_groups[j]);
+			kvfree(new_groups);
+			ext4_msg(sb, KERN_ERR,
+				 "not enough memory for %d flex groups", size);
+			return -ENOMEM;
+		}
 	}
-	sbi->s_flex_groups = new_groups;
-	sbi->s_flex_groups_allocated = size / sizeof(struct flex_groups);
+	rcu_read_lock();
+	old_groups = rcu_dereference(sbi->s_flex_groups);
+	if (old_groups)
+		memcpy(new_groups, old_groups,
+		       (sbi->s_flex_groups_allocated *
+			sizeof(struct flex_groups *)));
+	rcu_read_unlock();
+	rcu_assign_pointer(sbi->s_flex_groups, new_groups);
+	sbi->s_flex_groups_allocated = size;
+	if (old_groups)
+		ext4_kvfree_array_rcu(old_groups);
 	return 0;
 }
 
@@ -1996,6 +2051,7 @@
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct ext4_group_desc *gdp = NULL;
+	struct flex_groups *fg;
 	ext4_group_t flex_group;
 	int i, err;
 
@@ -2013,12 +2069,11 @@
 		gdp = ext4_get_group_desc(sb, i, NULL);
 
 		flex_group = ext4_flex_group(sbi, i);
-		atomic_add(ext4_free_inodes_count(sb, gdp),
-			   &sbi->s_flex_groups[flex_group].free_inodes);
+		fg = sbi_array_rcu_deref(sbi, s_flex_groups, flex_group);
+		atomic_add(ext4_free_inodes_count(sb, gdp), &fg->free_inodes);
 		atomic64_add(ext4_free_group_clusters(sb, gdp),
-			     &sbi->s_flex_groups[flex_group].free_clusters);
-		atomic_add(ext4_used_dirs_count(sb, gdp),
-			   &sbi->s_flex_groups[flex_group].used_dirs);
+			     &fg->free_clusters);
+		atomic_add(ext4_used_dirs_count(sb, gdp), &fg->used_dirs);
 	}
 
 	return 1;
@@ -2029,23 +2084,25 @@
 static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
 				   struct ext4_group_desc *gdp)
 {
-	int offset;
+	int offset = offsetof(struct ext4_group_desc, bg_checksum);
 	__u16 crc = 0;
 	__le32 le_group = cpu_to_le32(block_group);
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 
 	if (ext4_has_metadata_csum(sbi->s_sb)) {
 		/* Use new metadata_csum algorithm */
-		__le16 save_csum;
 		__u32 csum32;
+		__u16 dummy_csum = 0;
 
-		save_csum = gdp->bg_checksum;
-		gdp->bg_checksum = 0;
 		csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group,
 				     sizeof(le_group));
-		csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp,
-				     sbi->s_desc_size);
-		gdp->bg_checksum = save_csum;
+		csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, offset);
+		csum32 = ext4_chksum(sbi, csum32, (__u8 *)&dummy_csum,
+				     sizeof(dummy_csum));
+		offset += sizeof(dummy_csum);
+		if (offset < sbi->s_desc_size)
+			csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp + offset,
+					     sbi->s_desc_size - offset);
 
 		crc = csum32 & 0xFFFF;
 		goto out;
@@ -2055,18 +2112,14 @@
 	if (!ext4_has_feature_gdt_csum(sb))
 		return 0;
 
-	offset = offsetof(struct ext4_group_desc, bg_checksum);
-
 	crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
 	crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
 	crc = crc16(crc, (__u8 *)gdp, offset);
 	offset += sizeof(gdp->bg_checksum); /* skip checksum */
 	/* for checksum of struct ext4_group_desc do the rest...*/
-	if (ext4_has_feature_64bit(sb) &&
-	    offset < le16_to_cpu(sbi->s_es->s_desc_size))
+	if (ext4_has_feature_64bit(sb) && offset < sbi->s_desc_size)
 		crc = crc16(crc, (__u8 *)gdp + offset,
-			    le16_to_cpu(sbi->s_es->s_desc_size) -
-				offset);
+			    sbi->s_desc_size - offset);
 
 out:
 	return cpu_to_le16(crc);
@@ -2092,11 +2145,13 @@
 
 /* Called at mount-time, super-block is locked */
 static int ext4_check_descriptors(struct super_block *sb,
+				  ext4_fsblk_t sb_block,
 				  ext4_group_t *first_not_zeroed)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
 	ext4_fsblk_t last_block;
+	ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0);
 	ext4_fsblk_t block_bitmap;
 	ext4_fsblk_t inode_bitmap;
 	ext4_fsblk_t inode_table;
@@ -2122,6 +2177,21 @@
 			grp = i;
 
 		block_bitmap = ext4_block_bitmap(sb, gdp);
+		if (block_bitmap == sb_block) {
+			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+				 "Block bitmap for group %u overlaps "
+				 "superblock", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
+		}
+		if (block_bitmap >= sb_block + 1 &&
+		    block_bitmap <= last_bg_block) {
+			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+				 "Block bitmap for group %u overlaps "
+				 "block group descriptors", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
+		}
 		if (block_bitmap < first_block || block_bitmap > last_block) {
 			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
 			       "Block bitmap for group %u not in group "
@@ -2129,6 +2199,21 @@
 			return 0;
 		}
 		inode_bitmap = ext4_inode_bitmap(sb, gdp);
+		if (inode_bitmap == sb_block) {
+			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+				 "Inode bitmap for group %u overlaps "
+				 "superblock", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
+		}
+		if (inode_bitmap >= sb_block + 1 &&
+		    inode_bitmap <= last_bg_block) {
+			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+				 "Inode bitmap for group %u overlaps "
+				 "block group descriptors", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
+		}
 		if (inode_bitmap < first_block || inode_bitmap > last_block) {
 			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
 			       "Inode bitmap for group %u not in group "
@@ -2136,6 +2221,21 @@
 			return 0;
 		}
 		inode_table = ext4_inode_table(sb, gdp);
+		if (inode_table == sb_block) {
+			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+				 "Inode table for group %u overlaps "
+				 "superblock", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
+		}
+		if (inode_table >= sb_block + 1 &&
+		    inode_table <= last_bg_block) {
+			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+				 "Inode table for group %u overlaps "
+				 "block group descriptors", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
+		}
 		if (inode_table < first_block ||
 		    inode_table + sbi->s_itb_per_group - 1 > last_block) {
 			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2186,6 +2286,7 @@
 	unsigned int s_flags = sb->s_flags;
 	int nr_orphans = 0, nr_truncates = 0;
 #ifdef CONFIG_QUOTA
+	int quota_update = 0;
 	int i;
 #endif
 	if (!es->s_last_orphan) {
@@ -2224,14 +2325,32 @@
 #ifdef CONFIG_QUOTA
 	/* Needed for iput() to work correctly and not trash data */
 	sb->s_flags |= MS_ACTIVE;
-	/* Turn on quotas so that they are updated correctly */
+
+	/*
+	 * Turn on quotas which were not enabled for read-only mounts if
+	 * filesystem has quota feature, so that they are updated correctly.
+	 */
+	if (ext4_has_feature_quota(sb) && (s_flags & MS_RDONLY)) {
+		int ret = ext4_enable_quotas(sb);
+
+		if (!ret)
+			quota_update = 1;
+		else
+			ext4_msg(sb, KERN_ERR,
+				"Cannot turn on quotas: error %d", ret);
+	}
+
+	/* Turn on journaled quotas used for old sytle */
 	for (i = 0; i < EXT4_MAXQUOTAS; i++) {
 		if (EXT4_SB(sb)->s_qf_names[i]) {
 			int ret = ext4_quota_on_mount(sb, i);
-			if (ret < 0)
+
+			if (!ret)
+				quota_update = 1;
+			else
 				ext4_msg(sb, KERN_ERR,
 					"Cannot turn on journaled "
-					"quota: error %d", ret);
+					"quota: type %d: error %d", i, ret);
 		}
 	}
 #endif
@@ -2239,6 +2358,16 @@
 	while (es->s_last_orphan) {
 		struct inode *inode;
 
+		/*
+		 * We may have encountered an error during cleanup; if
+		 * so, skip the rest.
+		 */
+		if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
+			jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");
+			es->s_last_orphan = 0;
+			break;
+		}
+
 		inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
 		if (IS_ERR(inode)) {
 			es->s_last_orphan = 0;
@@ -2280,10 +2409,12 @@
 		ext4_msg(sb, KERN_INFO, "%d truncate%s cleaned up",
 		       PLURAL(nr_truncates));
 #ifdef CONFIG_QUOTA
-	/* Turn quotas off */
-	for (i = 0; i < EXT4_MAXQUOTAS; i++) {
-		if (sb_dqopt(sb)->files[i])
-			dquot_quota_off(sb, i);
+	/* Turn off quotas if they were enabled for orphan cleanup */
+	if (quota_update) {
+		for (i = 0; i < EXT4_MAXQUOTAS; i++) {
+			if (sb_dqopt(sb)->files[i])
+				dquot_quota_off(sb, i);
+		}
 	}
 #endif
 	sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -2449,9 +2580,9 @@
 
 	if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group)
 		ret = sbi->s_stripe;
-	else if (stripe_width <= sbi->s_blocks_per_group)
+	else if (stripe_width && stripe_width <= sbi->s_blocks_per_group)
 		ret = stripe_width;
-	else if (stride <= sbi->s_blocks_per_group)
+	else if (stride && stride <= sbi->s_blocks_per_group)
 		ret = stride;
 	else
 		ret = 0;
@@ -2785,6 +2916,9 @@
 	ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
 	struct ext4_group_desc *gdp = NULL;
 
+	if (!ext4_has_group_desc_csum(sb))
+		return ngroups;
+
 	for (group = 0; group < ngroups; group++) {
 		gdp = ext4_get_group_desc(sb, group, NULL);
 		if (!gdp)
@@ -3010,10 +3144,15 @@
 			ext4_set_bit(s++, buf);
 			count++;
 		}
-		for (j = ext4_bg_num_gdb(sb, grp); j > 0; j--) {
-			ext4_set_bit(EXT4_B2C(sbi, s++), buf);
-			count++;
+		j = ext4_bg_num_gdb(sb, grp);
+		if (s + j > EXT4_BLOCKS_PER_GROUP(sb)) {
+			ext4_error(sb, "Invalid number of block group "
+				   "descriptor blocks: %d", j);
+			j = EXT4_BLOCKS_PER_GROUP(sb) - s;
 		}
+		count += j;
+		for (; j > 0; j--)
+			ext4_set_bit(EXT4_B2C(sbi, s++), buf);
 	}
 	if (!count)
 		return 0;
@@ -3068,6 +3207,40 @@
 	return 0;
 }
 
+static void ext4_clamp_want_extra_isize(struct super_block *sb)
+{
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct ext4_super_block *es = sbi->s_es;
+	unsigned def_extra_isize = sizeof(struct ext4_inode) -
+						EXT4_GOOD_OLD_INODE_SIZE;
+
+	if (sbi->s_inode_size == EXT4_GOOD_OLD_INODE_SIZE) {
+		sbi->s_want_extra_isize = 0;
+		return;
+	}
+	if (sbi->s_want_extra_isize < 4) {
+		sbi->s_want_extra_isize = def_extra_isize;
+		if (ext4_has_feature_extra_isize(sb)) {
+			if (sbi->s_want_extra_isize <
+			    le16_to_cpu(es->s_want_extra_isize))
+				sbi->s_want_extra_isize =
+					le16_to_cpu(es->s_want_extra_isize);
+			if (sbi->s_want_extra_isize <
+			    le16_to_cpu(es->s_min_extra_isize))
+				sbi->s_want_extra_isize =
+					le16_to_cpu(es->s_min_extra_isize);
+		}
+	}
+	/* Check if enough inode space is available */
+	if ((sbi->s_want_extra_isize > sbi->s_inode_size) ||
+	    (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
+							sbi->s_inode_size)) {
+		sbi->s_want_extra_isize = def_extra_isize;
+		ext4_msg(sb, KERN_INFO,
+			 "required extra inode space not available");
+	}
+}
+
 static void ext4_set_resv_clusters(struct super_block *sb)
 {
 	ext4_fsblk_t resv_clusters;
@@ -3101,9 +3274,10 @@
 static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 {
 	char *orig_data = kstrdup(data, GFP_KERNEL);
-	struct buffer_head *bh;
+	struct buffer_head *bh, **group_desc;
 	struct ext4_super_block *es = NULL;
-	struct ext4_sb_info *sbi;
+	struct ext4_sb_info *sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+	struct flex_groups **flex_groups;
 	ext4_fsblk_t block;
 	ext4_fsblk_t sb_block = get_sb_block(&data);
 	ext4_fsblk_t logical_sb_block;
@@ -3122,16 +3296,17 @@
 	unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
 	ext4_group_t first_not_zeroed;
 
-	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
-	if (!sbi)
-		goto out_free_orig;
+	if (!userns_mounts && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if ((data && !orig_data) || !sbi)
+		goto out_free_base;
 
 	sbi->s_blockgroup_lock =
 		kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
-	if (!sbi->s_blockgroup_lock) {
-		kfree(sbi);
-		goto out_free_orig;
-	}
+	if (!sbi->s_blockgroup_lock)
+		goto out_free_base;
+
 	sb->s_fs_info = sbi;
 	sbi->s_sb = sb;
 	sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
@@ -3243,19 +3418,26 @@
 	else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK)
 		set_opt(sb, WRITEBACK_DATA);
 
-	if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC)
+	if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC) {
+		if (!capable(CAP_SYS_ADMIN))
+			goto failed_mount;
 		set_opt(sb, ERRORS_PANIC);
-	else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_CONTINUE)
+	} else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_CONTINUE) {
 		set_opt(sb, ERRORS_CONT);
-	else
+	} else {
 		set_opt(sb, ERRORS_RO);
+	}
 	/* block_validity enabled by default; disable with noblock_validity */
 	set_opt(sb, BLOCK_VALIDITY);
 	if (def_mount_opts & EXT4_DEFM_DISCARD)
 		set_opt(sb, DISCARD);
 
-	sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
-	sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
+	sbi->s_resuid = make_kuid(sb->s_user_ns, le16_to_cpu(es->s_def_resuid));
+	if (!uid_valid(sbi->s_resuid))
+		sbi->s_resuid = make_kuid(sb->s_user_ns, EXT4_DEF_RESUID);
+	sbi->s_resgid = make_kgid(sb->s_user_ns, le16_to_cpu(es->s_def_resgid));
+	if (!gid_valid(sbi->s_resgid))
+		sbi->s_resgid = make_kgid(sb->s_user_ns, EXT4_DEF_RESGID);
 	sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ;
 	sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
 	sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
@@ -3277,11 +3459,19 @@
 	 */
 	sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
 
-	if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
-			   &journal_devnum, &journal_ioprio, 0)) {
-		ext4_msg(sb, KERN_WARNING,
-			 "failed to parse options in superblock: %s",
-			 sbi->s_es->s_mount_opts);
+	if (sbi->s_es->s_mount_opts[0]) {
+		char *s_mount_opts = kstrndup(sbi->s_es->s_mount_opts,
+					      sizeof(sbi->s_es->s_mount_opts),
+					      GFP_KERNEL);
+		if (!s_mount_opts)
+			goto failed_mount;
+		if (!parse_options(s_mount_opts, sb, &journal_devnum,
+				   &journal_ioprio, 0)) {
+			ext4_msg(sb, KERN_WARNING,
+				 "failed to parse options in superblock: %s",
+				 s_mount_opts);
+		}
+		kfree(s_mount_opts);
 	}
 	sbi->s_def_mount_opt = sbi->s_mount_opt;
 	if (!parse_options((char *) data, sb, &journal_devnum,
@@ -3307,6 +3497,11 @@
 				 "both data=journal and dax");
 			goto failed_mount;
 		}
+		if (ext4_has_feature_encrypt(sb)) {
+			ext4_msg(sb, KERN_WARNING,
+				 "encrypted files will use data=ordered "
+				 "instead of data journaling mode");
+		}
 		if (test_opt(sb, DELALLOC))
 			clear_opt(sb, DELALLOC);
 	} else {
@@ -3367,7 +3562,29 @@
 	if (blocksize < EXT4_MIN_BLOCK_SIZE ||
 	    blocksize > EXT4_MAX_BLOCK_SIZE) {
 		ext4_msg(sb, KERN_ERR,
-		       "Unsupported filesystem blocksize %d", blocksize);
+		       "Unsupported filesystem blocksize %d (%d log_block_size)",
+			 blocksize, le32_to_cpu(es->s_log_block_size));
+		goto failed_mount;
+	}
+	if (le32_to_cpu(es->s_log_block_size) >
+	    (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
+		ext4_msg(sb, KERN_ERR,
+			 "Invalid log block size: %u",
+			 le32_to_cpu(es->s_log_block_size));
+		goto failed_mount;
+	}
+	if (le32_to_cpu(es->s_log_cluster_size) >
+	    (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
+		ext4_msg(sb, KERN_ERR,
+			 "Invalid log cluster size: %u",
+			 le32_to_cpu(es->s_log_cluster_size));
+		goto failed_mount;
+	}
+
+	if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) {
+		ext4_msg(sb, KERN_ERR,
+			 "Number of reserved GDT blocks insanely large: %d",
+			 le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks));
 		goto failed_mount;
 	}
 
@@ -3391,14 +3608,20 @@
 	}
 
 	if (sb->s_blocksize != blocksize) {
+		/*
+		 * bh must be released before kill_bdev(), otherwise
+		 * it won't be freed and its page also. kill_bdev()
+		 * is called by sb_set_blocksize().
+		 */
+		brelse(bh);
 		/* Validate the filesystem blocksize */
 		if (!sb_set_blocksize(sb, blocksize)) {
 			ext4_msg(sb, KERN_ERR, "bad block size %d",
 					blocksize);
+			bh = NULL;
 			goto failed_mount;
 		}
 
-		brelse(bh);
 		logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
 		offset = do_div(logical_sb_block, blocksize);
 		bh = sb_bread_unmovable(sb, logical_sb_block);
@@ -3427,6 +3650,11 @@
 	} else {
 		sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
 		sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
+		if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) {
+			ext4_msg(sb, KERN_ERR, "invalid first ino: %u",
+				 sbi->s_first_ino);
+			goto failed_mount;
+		}
 		if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
 		    (!is_power_of_2(sbi->s_inode_size)) ||
 		    (sbi->s_inode_size > blocksize)) {
@@ -3454,12 +3682,16 @@
 
 	sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
 	sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
-	if (EXT4_INODE_SIZE(sb) == 0 || EXT4_INODES_PER_GROUP(sb) == 0)
-		goto cantfind_ext4;
 
 	sbi->s_inodes_per_block = blocksize / EXT4_INODE_SIZE(sb);
 	if (sbi->s_inodes_per_block == 0)
 		goto cantfind_ext4;
+	if (sbi->s_inodes_per_group < sbi->s_inodes_per_block ||
+	    sbi->s_inodes_per_group > blocksize * 8) {
+		ext4_msg(sb, KERN_ERR, "invalid inodes per group: %lu\n",
+			 sbi->s_inodes_per_group);
+		goto failed_mount;
+	}
 	sbi->s_itb_per_group = sbi->s_inodes_per_group /
 					sbi->s_inodes_per_block;
 	sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb);
@@ -3519,10 +3751,10 @@
 		}
 	} else {
 		if (clustersize != blocksize) {
-			ext4_warning(sb, "fragment/cluster size (%d) != "
-				     "block size (%d)", clustersize,
-				     blocksize);
-			clustersize = blocksize;
+			ext4_msg(sb, KERN_ERR,
+				 "fragment/cluster size (%d) != "
+				 "block size (%d)", clustersize, blocksize);
+			goto failed_mount;
 		}
 		if (sbi->s_blocks_per_group > blocksize * 8) {
 			ext4_msg(sb, KERN_ERR,
@@ -3535,13 +3767,6 @@
 	}
 	sbi->s_cluster_ratio = clustersize / blocksize;
 
-	if (sbi->s_inodes_per_group > blocksize * 8) {
-		ext4_msg(sb, KERN_ERR,
-		       "#inodes per group too big: %lu",
-		       sbi->s_inodes_per_group);
-		goto failed_mount;
-	}
-
 	/* Do we have standard group size of clustersize * 8 blocks ? */
 	if (sbi->s_blocks_per_group == clustersize << 3)
 		set_opt2(sb, STD_GROUP_SIZE);
@@ -3583,14 +3808,21 @@
 			 ext4_blocks_count(es));
 		goto failed_mount;
 	}
+	if ((es->s_first_data_block == 0) && (es->s_log_block_size == 0) &&
+	    (sbi->s_cluster_ratio == 1)) {
+		ext4_msg(sb, KERN_WARNING, "bad geometry: first data "
+			 "block is 0 with a 1k block and cluster size");
+		goto failed_mount;
+	}
+
 	blocks_count = (ext4_blocks_count(es) -
 			le32_to_cpu(es->s_first_data_block) +
 			EXT4_BLOCKS_PER_GROUP(sb) - 1);
 	do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb));
 	if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) {
-		ext4_msg(sb, KERN_WARNING, "groups count too large: %u "
+		ext4_msg(sb, KERN_WARNING, "groups count too large: %llu "
 		       "(block count %llu, first data block %u, "
-		       "blocks per group %lu)", sbi->s_groups_count,
+		       "blocks per group %lu)", blocks_count,
 		       ext4_blocks_count(es),
 		       le32_to_cpu(es->s_first_data_block),
 		       EXT4_BLOCKS_PER_GROUP(sb));
@@ -3599,11 +3831,29 @@
 	sbi->s_groups_count = blocks_count;
 	sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count,
 			(EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb)));
+	if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) !=
+	    le32_to_cpu(es->s_inodes_count)) {
+		ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu",
+			 le32_to_cpu(es->s_inodes_count),
+			 ((u64)sbi->s_groups_count * sbi->s_inodes_per_group));
+		ret = -EINVAL;
+		goto failed_mount;
+	}
 	db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
 		   EXT4_DESC_PER_BLOCK(sb);
-	sbi->s_group_desc = ext4_kvmalloc(db_count *
+	if (ext4_has_feature_meta_bg(sb)) {
+		if (le32_to_cpu(es->s_first_meta_bg) > db_count) {
+			ext4_msg(sb, KERN_WARNING,
+				 "first meta block group too large: %u "
+				 "(group descriptor block count %u)",
+				 le32_to_cpu(es->s_first_meta_bg), db_count);
+			goto failed_mount;
+		}
+	}
+	rcu_assign_pointer(sbi->s_group_desc,
+			   ext4_kvmalloc(db_count *
 					  sizeof(struct buffer_head *),
-					  GFP_KERNEL);
+					  GFP_KERNEL));
 	if (sbi->s_group_desc == NULL) {
 		ext4_msg(sb, KERN_ERR, "not enough memory");
 		ret = -ENOMEM;
@@ -3613,22 +3863,27 @@
 	bgl_lock_init(sbi->s_blockgroup_lock);
 
 	for (i = 0; i < db_count; i++) {
+		struct buffer_head *bh;
+
 		block = descriptor_loc(sb, logical_sb_block, i);
-		sbi->s_group_desc[i] = sb_bread_unmovable(sb, block);
-		if (!sbi->s_group_desc[i]) {
+		bh = sb_bread_unmovable(sb, block);
+		if (!bh) {
 			ext4_msg(sb, KERN_ERR,
 			       "can't read group descriptor %d", i);
 			db_count = i;
 			goto failed_mount2;
 		}
+		rcu_read_lock();
+		rcu_dereference(sbi->s_group_desc)[i] = bh;
+		rcu_read_unlock();
 	}
-	if (!ext4_check_descriptors(sb, &first_not_zeroed)) {
+	sbi->s_gdb_count = db_count;
+	if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) {
 		ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
 		ret = -EFSCORRUPTED;
 		goto failed_mount2;
 	}
 
-	sbi->s_gdb_count = db_count;
 	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
 	spin_lock_init(&sbi->s_next_gen_lock);
 
@@ -3675,7 +3930,8 @@
 	 * root first: it may be modified in the journal!
 	 */
 	if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) {
-		if (ext4_load_journal(sb, es, journal_devnum))
+		err = ext4_load_journal(sb, es, journal_devnum);
+		if (err)
 			goto failed_mount3a;
 	} else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
 		   ext4_has_feature_journal_needs_recovery(sb)) {
@@ -3706,7 +3962,7 @@
 				 "data=, fs mounted w/o journal");
 			goto failed_mount_wq;
 		}
-		sbi->s_def_mount_opt &= EXT4_MOUNT_JOURNAL_CHECKSUM;
+		sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM;
 		clear_opt(sb, JOURNAL_CHECKSUM);
 		clear_opt(sb, DATA_FLAGS);
 		sbi->s_journal = NULL;
@@ -3758,12 +4014,10 @@
 	sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
 
 no_journal:
-	if (ext4_mballoc_ready) {
-		sbi->s_mb_cache = ext4_xattr_create_cache(sb->s_id);
-		if (!sbi->s_mb_cache) {
-			ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
-			goto failed_mount_wq;
-		}
+	sbi->s_mb_cache = ext4_xattr_create_cache();
+	if (!sbi->s_mb_cache) {
+		ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
+		goto failed_mount_wq;
 	}
 
 	if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) &&
@@ -3808,7 +4062,7 @@
 	 * so we can safely mount the rest of the filesystem now.
 	 */
 
-	root = ext4_iget(sb, EXT4_ROOT_INO);
+	root = ext4_iget(sb, EXT4_ROOT_INO, EXT4_IGET_SPECIAL);
 	if (IS_ERR(root)) {
 		ext4_msg(sb, KERN_ERR, "get root inode failed");
 		ret = PTR_ERR(root);
@@ -3830,29 +4084,7 @@
 	if (ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY))
 		sb->s_flags |= MS_RDONLY;
 
-	/* determine the minimum size of new large inodes, if present */
-	if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
-		sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
-						     EXT4_GOOD_OLD_INODE_SIZE;
-		if (ext4_has_feature_extra_isize(sb)) {
-			if (sbi->s_want_extra_isize <
-			    le16_to_cpu(es->s_want_extra_isize))
-				sbi->s_want_extra_isize =
-					le16_to_cpu(es->s_want_extra_isize);
-			if (sbi->s_want_extra_isize <
-			    le16_to_cpu(es->s_min_extra_isize))
-				sbi->s_want_extra_isize =
-					le16_to_cpu(es->s_min_extra_isize);
-		}
-	}
-	/* Check if enough inode space is available */
-	if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
-							sbi->s_inode_size) {
-		sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
-						       EXT4_GOOD_OLD_INODE_SIZE;
-		ext4_msg(sb, KERN_INFO, "required extra inode space not"
-			 "available");
-	}
+	ext4_clamp_want_extra_isize(sb);
 
 	ext4_set_resv_clusters(sb);
 
@@ -3874,11 +4106,13 @@
 	block = ext4_count_free_clusters(sb);
 	ext4_free_blocks_count_set(sbi->s_es, 
 				   EXT4_C2B(sbi, block));
+	ext4_superblock_csum_set(sb);
 	err = percpu_counter_init(&sbi->s_freeclusters_counter, block,
 				  GFP_KERNEL);
 	if (!err) {
 		unsigned long freei = ext4_count_free_inodes(sb);
 		sbi->s_es->s_free_inodes_count = cpu_to_le32(freei);
+		ext4_superblock_csum_set(sb);
 		err = percpu_counter_init(&sbi->s_freeinodes_counter, freei,
 					  GFP_KERNEL);
 	}
@@ -3945,7 +4179,9 @@
 
 	if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount"))
 		ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
-			 "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts,
+			 "Opts: %.*s%s%s", descr,
+			 (int) sizeof(sbi->s_es->s_mount_opts),
+			 sbi->s_es->s_mount_opts,
 			 *sbi->s_es->s_mount_opts ? "; " : "", orig_data);
 
 	if (es->s_error_count)
@@ -3967,13 +4203,20 @@
 #ifdef CONFIG_QUOTA
 failed_mount8:
 	ext4_unregister_sysfs(sb);
+	kobject_put(&sbi->s_kobj);
 #endif
 failed_mount7:
 	ext4_unregister_li_request(sb);
 failed_mount6:
 	ext4_mb_release(sb);
-	if (sbi->s_flex_groups)
-		kvfree(sbi->s_flex_groups);
+	rcu_read_lock();
+	flex_groups = rcu_dereference(sbi->s_flex_groups);
+	if (flex_groups) {
+		for (i = 0; i < sbi->s_flex_groups_allocated; i++)
+			kvfree(flex_groups[i]);
+		kvfree(flex_groups);
+	}
+	rcu_read_unlock();
 	percpu_counter_destroy(&sbi->s_freeclusters_counter);
 	percpu_counter_destroy(&sbi->s_freeinodes_counter);
 	percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -3989,6 +4232,10 @@
 	if (EXT4_SB(sb)->rsv_conversion_wq)
 		destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq);
 failed_mount_wq:
+	if (sbi->s_mb_cache) {
+		ext4_xattr_destroy_cache(sbi->s_mb_cache);
+		sbi->s_mb_cache = NULL;
+	}
 	if (sbi->s_journal) {
 		jbd2_journal_destroy(sbi->s_journal);
 		sbi->s_journal = NULL;
@@ -4000,9 +4247,12 @@
 	if (sbi->s_mmp_tsk)
 		kthread_stop(sbi->s_mmp_tsk);
 failed_mount2:
+	rcu_read_lock();
+	group_desc = rcu_dereference(sbi->s_group_desc);
 	for (i = 0; i < db_count; i++)
-		brelse(sbi->s_group_desc[i]);
-	kvfree(sbi->s_group_desc);
+		brelse(group_desc[i]);
+	kvfree(group_desc);
+	rcu_read_unlock();
 failed_mount:
 	if (sbi->s_chksum_driver)
 		crypto_free_shash(sbi->s_chksum_driver);
@@ -4010,13 +4260,15 @@
 	for (i = 0; i < EXT4_MAXQUOTAS; i++)
 		kfree(sbi->s_qf_names[i]);
 #endif
-	ext4_blkdev_remove(sbi);
+	/* ext4_blkdev_remove() calls kill_bdev(), release bh before it. */
 	brelse(bh);
+	ext4_blkdev_remove(sbi);
 out_fail:
+	/* sb->s_user_ns will be put when sb is destroyed */
 	sb->s_fs_info = NULL;
 	kfree(sbi->s_blockgroup_lock);
+out_free_base:
 	kfree(sbi);
-out_free_orig:
 	kfree(orig_data);
 	return err ? err : ret;
 }
@@ -4054,11 +4306,12 @@
 
 	BUG_ON(!ext4_has_feature_journal(sb));
 
-	/* First, test for the existence of a valid inode on disk.  Bad
-	 * things happen if we iget() an unused inode, as the subsequent
-	 * iput() will try to delete it. */
-
-	journal_inode = ext4_iget(sb, journal_inum);
+	/*
+	 * Test for the existence of a valid inode on disk.  Bad things
+	 * happen if we iget() an unused inode, as the subsequent iput()
+	 * will try to delete it.
+	 */
+	journal_inode = ext4_iget(sb, journal_inum, EXT4_IGET_SPECIAL);
 	if (IS_ERR(journal_inode)) {
 		ext4_msg(sb, KERN_ERR, "no journal found");
 		return NULL;
@@ -4284,6 +4537,14 @@
 
 	if (!sbh || block_device_ejected(sb))
 		return error;
+
+	/*
+	 * The superblock bh should be mapped, but it might not be if the
+	 * device was hot-removed. Not much we can do but fail the I/O.
+	 */
+	if (!buffer_mapped(sbh))
+		return error;
+
 	if (buffer_write_io_error(sbh)) {
 		/*
 		 * Oh, dear.  A previous attempt to write the
@@ -4593,6 +4854,8 @@
 		goto restore_opts;
 	}
 
+	ext4_clamp_want_extra_isize(sb);
+
 	if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
 	    test_opt(sb, JOURNAL_CHECKSUM)) {
 		ext4_msg(sb, KERN_ERR, "changing journal_checksum "
@@ -4751,9 +5014,6 @@
 		ext4_commit_super(sb, 1);
 
 #ifdef CONFIG_QUOTA
-	/* Release old quota file names */
-	for (i = 0; i < EXT4_MAXQUOTAS; i++)
-		kfree(old_opts.s_qf_names[i]);
 	if (enable_quota) {
 		if (sb_any_quota_suspended(sb))
 			dquot_resume(sb, -1);
@@ -4763,6 +5023,9 @@
 				goto restore_opts;
 		}
 	}
+	/* Release old quota file names */
+	for (i = 0; i < EXT4_MAXQUOTAS; i++)
+		kfree(old_opts.s_qf_names[i]);
 #endif
 
 	*flags = (*flags & ~MS_LAZYTIME) | (sb->s_flags & MS_LAZYTIME);
@@ -4771,6 +5034,13 @@
 	return 0;
 
 restore_opts:
+	/*
+	 * If there was a failing r/w to ro transition, we may need to
+	 * re-enable quota
+	 */
+	if ((sb->s_flags & MS_RDONLY) && !(old_sb_flags & MS_RDONLY) &&
+	    sb_any_quota_suspended(sb))
+		dquot_resume(sb, -1);
 	sb->s_flags = old_sb_flags;
 	sbi->s_mount_opt = old_opts.s_mount_opt;
 	sbi->s_mount_opt2 = old_opts.s_mount_opt2;
@@ -4936,6 +5206,20 @@
 					EXT4_SB(sb)->s_jquota_fmt, type);
 }
 
+static void lockdep_set_quota_inode(struct inode *inode, int subclass)
+{
+	struct ext4_inode_info *ei = EXT4_I(inode);
+
+	/* The first argument of lockdep_set_subclass has to be
+	 * *exactly* the same as the argument to init_rwsem() --- in
+	 * this case, in init_once() --- or lockdep gets unhappy
+	 * because the name of the lock is set using the
+	 * stringification of the argument to init_rwsem().
+	 */
+	(void) ei;	/* shut up clang warning if !CONFIG_LOCKDEP */
+	lockdep_set_subclass(&ei->i_data_sem, subclass);
+}
+
 /*
  * Standard function to be called on quota_on
  */
@@ -4950,6 +5234,11 @@
 	/* Quotafile not on the same filesystem? */
 	if (path->dentry->d_sb != sb)
 		return -EXDEV;
+
+	/* Quota already enabled for this file? */
+	if (IS_NOQUOTA(d_inode(path->dentry)))
+		return -EBUSY;
+
 	/* Journaling quota? */
 	if (EXT4_SB(sb)->s_qf_names[type]) {
 		/* Quotafile not in fs root? */
@@ -4975,8 +5264,12 @@
 		if (err)
 			return err;
 	}
-
-	return dquot_quota_on(sb, type, format_id, path);
+	lockdep_set_quota_inode(path->dentry->d_inode, I_DATA_SEM_QUOTA);
+	err = dquot_quota_on(sb, type, format_id, path);
+	if (err)
+		lockdep_set_quota_inode(path->dentry->d_inode,
+					     I_DATA_SEM_NORMAL);
+	return err;
 }
 
 static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
@@ -4994,7 +5287,7 @@
 	if (!qf_inums[type])
 		return -EPERM;
 
-	qf_inode = ext4_iget(sb, qf_inums[type]);
+	qf_inode = ext4_iget(sb, qf_inums[type], EXT4_IGET_SPECIAL);
 	if (IS_ERR(qf_inode)) {
 		ext4_error(sb, "Bad quota inode # %lu", qf_inums[type]);
 		return PTR_ERR(qf_inode);
@@ -5002,7 +5295,10 @@
 
 	/* Don't account quota for quota files to avoid recursion */
 	qf_inode->i_flags |= S_NOQUOTA;
+	lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA);
 	err = dquot_enable(qf_inode, type, format_id, flags);
+	if (err)
+		lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL);
 	iput(qf_inode);
 
 	return err;
@@ -5023,6 +5319,9 @@
 			err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
 						DQUOT_USAGE_ENABLED);
 			if (err) {
+				for (type--; type >= 0; type--)
+					dquot_quota_off(sb, type);
+
 				ext4_warning(sb,
 					"Failed to enable quota tracking "
 					"(type=%d, err=%d). Please run "
@@ -5228,7 +5527,7 @@
 	.name		= "ext4",
 	.mount		= ext4_mount,
 	.kill_sb	= kill_block_super,
-	.fs_flags	= FS_REQUIRES_DEV,
+	.fs_flags	= FS_REQUIRES_DEV | FS_USERNS_MOUNT,
 };
 MODULE_ALIAS_FS("ext4");
 
@@ -5271,8 +5570,6 @@
 	err = ext4_init_mballoc();
 	if (err)
 		goto out2;
-	else
-		ext4_mballoc_ready = 1;
 	err = init_inodecache();
 	if (err)
 		goto out1;
@@ -5288,7 +5585,6 @@
 	unregister_as_ext3();
 	destroy_inodecache();
 out1:
-	ext4_mballoc_ready = 0;
 	ext4_exit_mballoc();
 out2:
 	ext4_exit_sysfs();
--- linux-4.4.0.orig/fs/ext4/symlink.c
+++ linux-4.4.0/fs/ext4/symlink.c
@@ -45,7 +45,7 @@
 		cpage = read_mapping_page(inode->i_mapping, 0, NULL);
 		if (IS_ERR(cpage))
 			return ERR_CAST(cpage);
-		caddr = kmap(cpage);
+		caddr = page_address(cpage);
 		caddr[size] = 0;
 	}
 
@@ -75,16 +75,12 @@
 	/* Null-terminate the name */
 	if (res <= plen)
 		paddr[res] = '\0';
-	if (cpage) {
-		kunmap(cpage);
+	if (cpage)
 		page_cache_release(cpage);
-	}
 	return *cookie = paddr;
 errout:
-	if (cpage) {
-		kunmap(cpage);
+	if (cpage)
 		page_cache_release(cpage);
-	}
 	kfree(paddr);
 	return ERR_PTR(res);
 }
--- linux-4.4.0.orig/fs/ext4/sysfs.c
+++ linux-4.4.0/fs/ext4/sysfs.c
@@ -100,7 +100,7 @@
 	int ret;
 
 	ret = kstrtoull(skip_spaces(buf), 0, &val);
-	if (!ret || val >= clusters)
+	if (ret || val >= clusters)
 		return -EINVAL;
 
 	atomic64_set(&sbi->s_resv_clusters, val);
@@ -223,14 +223,18 @@
 EXT4_ATTR_FEATURE(lazy_itable_init);
 EXT4_ATTR_FEATURE(batched_discard);
 EXT4_ATTR_FEATURE(meta_bg_resize);
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
 EXT4_ATTR_FEATURE(encryption);
+#endif
 EXT4_ATTR_FEATURE(metadata_csum_seed);
 
 static struct attribute *ext4_feat_attrs[] = {
 	ATTR_LIST(lazy_itable_init),
 	ATTR_LIST(batched_discard),
 	ATTR_LIST(meta_bg_resize),
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
 	ATTR_LIST(encryption),
+#endif
 	ATTR_LIST(metadata_csum_seed),
 	NULL,
 };
@@ -273,8 +277,12 @@
 	case attr_pointer_ui:
 		if (!ptr)
 			return 0;
-		return snprintf(buf, PAGE_SIZE, "%u\n",
-				*((unsigned int *) ptr));
+		if (a->attr_ptr == ptr_ext4_super_block_offset)
+			return snprintf(buf, PAGE_SIZE, "%u\n",
+					le32_to_cpup(ptr));
+		else
+			return snprintf(buf, PAGE_SIZE, "%u\n",
+					*((unsigned int *) ptr));
 	case attr_pointer_atomic:
 		if (!ptr)
 			return 0;
@@ -307,7 +315,10 @@
 		ret = kstrtoul(skip_spaces(buf), 0, &t);
 		if (ret)
 			return ret;
-		*((unsigned int *) ptr) = t;
+		if (a->attr_ptr == ptr_ext4_super_block_offset)
+			*((__le32 *) ptr) = cpu_to_le32(t);
+		else
+			*((unsigned int *) ptr) = t;
 		return len;
 	case attr_inode_readahead:
 		return inode_readahead_blks_store(a, sbi, buf, len);
--- linux-4.4.0.orig/fs/ext4/truncate.h
+++ linux-4.4.0/fs/ext4/truncate.h
@@ -10,8 +10,10 @@
  */
 static inline void ext4_truncate_failed_write(struct inode *inode)
 {
+	down_write(&EXT4_I(inode)->i_mmap_sem);
 	truncate_inode_pages(inode->i_mapping, inode->i_size);
 	ext4_truncate(inode);
+	up_write(&EXT4_I(inode)->i_mmap_sem);
 }
 
 /*
--- linux-4.4.0.orig/fs/ext4/xattr.c
+++ linux-4.4.0/fs/ext4/xattr.c
@@ -123,46 +123,42 @@
 {
 	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 	__u32 csum;
-	__le32 save_csum;
 	__le64 dsk_block_nr = cpu_to_le64(block_nr);
+	__u32 dummy_csum = 0;
+	int offset = offsetof(struct ext4_xattr_header, h_checksum);
 
-	save_csum = hdr->h_checksum;
-	hdr->h_checksum = 0;
 	csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr,
 			   sizeof(dsk_block_nr));
-	csum = ext4_chksum(sbi, csum, (__u8 *)hdr,
-			   EXT4_BLOCK_SIZE(inode->i_sb));
+	csum = ext4_chksum(sbi, csum, (__u8 *)hdr, offset);
+	csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum));
+	offset += sizeof(dummy_csum);
+	csum = ext4_chksum(sbi, csum, (__u8 *)hdr + offset,
+			   EXT4_BLOCK_SIZE(inode->i_sb) - offset);
 
-	hdr->h_checksum = save_csum;
 	return cpu_to_le32(csum);
 }
 
 static int ext4_xattr_block_csum_verify(struct inode *inode,
-					sector_t block_nr,
-					struct ext4_xattr_header *hdr)
+					struct buffer_head *bh)
 {
-	if (ext4_has_metadata_csum(inode->i_sb) &&
-	    (hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr)))
-		return 0;
-	return 1;
-}
+	struct ext4_xattr_header *hdr = BHDR(bh);
+	int ret = 1;
 
-static void ext4_xattr_block_csum_set(struct inode *inode,
-				      sector_t block_nr,
-				      struct ext4_xattr_header *hdr)
-{
-	if (!ext4_has_metadata_csum(inode->i_sb))
-		return;
-
-	hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr);
+	if (ext4_has_metadata_csum(inode->i_sb)) {
+		lock_buffer(bh);
+		ret = (hdr->h_checksum == ext4_xattr_block_csum(inode,
+							bh->b_blocknr, hdr));
+		unlock_buffer(bh);
+	}
+	return ret;
 }
 
-static inline int ext4_handle_dirty_xattr_block(handle_t *handle,
-						struct inode *inode,
-						struct buffer_head *bh)
+static void ext4_xattr_block_csum_set(struct inode *inode,
+				      struct buffer_head *bh)
 {
-	ext4_xattr_block_csum_set(inode, bh->b_blocknr, BHDR(bh));
-	return ext4_handle_dirty_metadata(handle, inode, bh);
+	if (ext4_has_metadata_csum(inode->i_sb))
+		BHDR(bh)->h_checksum = ext4_xattr_block_csum(inode,
+						bh->b_blocknr, BHDR(bh));
 }
 
 static inline const struct xattr_handler *
@@ -196,6 +192,8 @@
 		struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e);
 		if ((void *)next >= end)
 			return -EFSCORRUPTED;
+		if (strnlen(e->e_name, e->e_name_len) != e->e_name_len)
+			return -EFSCORRUPTED;
 		e = next;
 	}
 
@@ -217,13 +215,13 @@
 {
 	int error;
 
-	if (buffer_verified(bh))
-		return 0;
-
 	if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
 	    BHDR(bh)->h_blocks != cpu_to_le32(1))
 		return -EFSCORRUPTED;
-	if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
+	if (buffer_verified(bh))
+		return 0;
+
+	if (!ext4_xattr_block_csum_verify(inode, bh))
 		return -EFSBADCRC;
 	error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
 				       bh->b_data);
@@ -232,6 +230,27 @@
 	return error;
 }
 
+static int
+__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header,
+			 void *end, const char *function, unsigned int line)
+{
+	struct ext4_xattr_entry *entry = IFIRST(header);
+	int error = -EFSCORRUPTED;
+
+	if (((void *) header >= end) ||
+	    (header->h_magic != le32_to_cpu(EXT4_XATTR_MAGIC)))
+		goto errout;
+	error = ext4_xattr_check_names(entry, end, entry);
+errout:
+	if (error)
+		__ext4_error_inode(inode, function, line, 0,
+				   "corrupted in-inode xattr");
+	return error;
+}
+
+#define xattr_check_inode(inode, header, end) \
+	__xattr_check_inode((inode), (header), (end), __func__, __LINE__)
+
 static inline int
 ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size)
 {
@@ -343,7 +362,7 @@
 	header = IHDR(inode, raw_inode);
 	entry = IFIRST(header);
 	end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
-	error = ext4_xattr_check_names(entry, end, entry);
+	error = xattr_check_inode(inode, header, end);
 	if (error)
 		goto cleanup;
 	error = ext4_xattr_find_entry(&entry, name_index, name,
@@ -474,7 +493,7 @@
 	raw_inode = ext4_raw_inode(&iloc);
 	header = IHDR(inode, raw_inode);
 	end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
-	error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header));
+	error = xattr_check_inode(inode, header, end);
 	if (error)
 		goto cleanup;
 	error = ext4_xattr_list_entries(dentry, IFIRST(header),
@@ -542,47 +561,60 @@
 ext4_xattr_release_block(handle_t *handle, struct inode *inode,
 			 struct buffer_head *bh)
 {
-	struct mb_cache_entry *ce = NULL;
-	int error = 0;
 	struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+	u32 hash, ref;
+	int error = 0;
 
-	ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
 	BUFFER_TRACE(bh, "get_write_access");
 	error = ext4_journal_get_write_access(handle, bh);
 	if (error)
 		goto out;
 
 	lock_buffer(bh);
-	if (BHDR(bh)->h_refcount == cpu_to_le32(1)) {
+	hash = le32_to_cpu(BHDR(bh)->h_hash);
+	ref = le32_to_cpu(BHDR(bh)->h_refcount);
+	if (ref == 1) {
 		ea_bdebug(bh, "refcount now=0; freeing");
-		if (ce)
-			mb_cache_entry_free(ce);
+		/*
+		 * This must happen under buffer lock for
+		 * ext4_xattr_block_set() to reliably detect freed block
+		 */
+		mb_cache_entry_delete_block(ext4_mb_cache, hash, bh->b_blocknr);
 		get_bh(bh);
 		unlock_buffer(bh);
 		ext4_free_blocks(handle, inode, bh, 0, 1,
 				 EXT4_FREE_BLOCKS_METADATA |
 				 EXT4_FREE_BLOCKS_FORGET);
 	} else {
-		le32_add_cpu(&BHDR(bh)->h_refcount, -1);
-		if (ce)
-			mb_cache_entry_release(ce);
+		ref--;
+		BHDR(bh)->h_refcount = cpu_to_le32(ref);
+		if (ref == EXT4_XATTR_REFCOUNT_MAX - 1) {
+			struct mb_cache_entry *ce;
+
+			ce = mb_cache_entry_get(ext4_mb_cache, hash,
+						bh->b_blocknr);
+			if (ce) {
+				ce->e_reusable = 1;
+				mb_cache_entry_put(ext4_mb_cache, ce);
+			}
+		}
+
+		ext4_xattr_block_csum_set(inode, bh);
 		/*
 		 * Beware of this ugliness: Releasing of xattr block references
 		 * from different inodes can race and so we have to protect
 		 * from a race where someone else frees the block (and releases
 		 * its journal_head) before we are done dirtying the buffer. In
 		 * nojournal mode this race is harmless and we actually cannot
-		 * call ext4_handle_dirty_xattr_block() with locked buffer as
+		 * call ext4_handle_dirty_metadata() with locked buffer as
 		 * that function can call sync_dirty_buffer() so for that case
 		 * we handle the dirtying after unlocking the buffer.
 		 */
 		if (ext4_handle_valid(handle))
-			error = ext4_handle_dirty_xattr_block(handle, inode,
-							      bh);
+			error = ext4_handle_dirty_metadata(handle, inode, bh);
 		unlock_buffer(bh);
 		if (!ext4_handle_valid(handle))
-			error = ext4_handle_dirty_xattr_block(handle, inode,
-							      bh);
+			error = ext4_handle_dirty_metadata(handle, inode, bh);
 		if (IS_SYNC(inode))
 			ext4_handle_sync(handle);
 		dquot_free_block(inode, EXT4_C2B(EXT4_SB(inode->i_sb), 1));
@@ -614,14 +646,20 @@
 }
 
 static int
-ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
+ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s,
+		     struct inode *inode)
 {
-	struct ext4_xattr_entry *last;
+	struct ext4_xattr_entry *last, *next;
 	size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
 
 	/* Compute min_offs and last. */
 	last = s->first;
-	for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+	for (; !IS_LAST_ENTRY(last); last = next) {
+		next = EXT4_XATTR_NEXT(last);
+		if ((void *)next >= s->end) {
+			EXT4_ERROR_INODE(inode, "corrupted xattr entries");
+			return -EFSCORRUPTED;
+		}
 		if (!last->e_value_block && last->e_value_size) {
 			size_t offs = le16_to_cpu(last->e_value_offs);
 			if (offs < min_offs)
@@ -787,8 +825,6 @@
 	if (i->value && i->value_len > sb->s_blocksize)
 		return -ENOSPC;
 	if (s->base) {
-		ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
-					bs->bh->b_blocknr);
 		BUFFER_TRACE(bs->bh, "get_write_access");
 		error = ext4_journal_get_write_access(handle, bs->bh);
 		if (error)
@@ -796,26 +832,30 @@
 		lock_buffer(bs->bh);
 
 		if (header(s->base)->h_refcount == cpu_to_le32(1)) {
-			if (ce) {
-				mb_cache_entry_free(ce);
-				ce = NULL;
-			}
+			__u32 hash = le32_to_cpu(BHDR(bs->bh)->h_hash);
+
+			/*
+			 * This must happen under buffer lock for
+			 * ext4_xattr_block_set() to reliably detect modified
+			 * block
+			 */
+			mb_cache_entry_delete_block(ext4_mb_cache, hash,
+						    bs->bh->b_blocknr);
 			ea_bdebug(bs->bh, "modifying in-place");
-			error = ext4_xattr_set_entry(i, s);
+			error = ext4_xattr_set_entry(i, s, inode);
 			if (!error) {
 				if (!IS_LAST_ENTRY(s->first))
 					ext4_xattr_rehash(header(s->base),
 							  s->here);
-				ext4_xattr_cache_insert(ext4_mb_cache,
-					bs->bh);
 			}
+			ext4_xattr_block_csum_set(inode, bs->bh);
 			unlock_buffer(bs->bh);
 			if (error == -EFSCORRUPTED)
 				goto bad_block;
 			if (!error)
-				error = ext4_handle_dirty_xattr_block(handle,
-								      inode,
-								      bs->bh);
+				error = ext4_handle_dirty_metadata(handle,
+								   inode,
+								   bs->bh);
 			if (error)
 				goto cleanup;
 			goto inserted;
@@ -823,10 +863,6 @@
 			int offset = (char *)s->here - bs->bh->b_data;
 
 			unlock_buffer(bs->bh);
-			if (ce) {
-				mb_cache_entry_release(ce);
-				ce = NULL;
-			}
 			ea_bdebug(bs->bh, "cloning");
 			s->base = kmalloc(bs->bh->b_size, GFP_NOFS);
 			error = -ENOMEM;
@@ -853,7 +889,7 @@
 		s->end = s->base + sb->s_blocksize;
 	}
 
-	error = ext4_xattr_set_entry(i, s);
+	error = ext4_xattr_set_entry(i, s, inode);
 	if (error == -EFSCORRUPTED)
 		goto bad_block;
 	if (error)
@@ -869,6 +905,8 @@
 			if (new_bh == bs->bh)
 				ea_bdebug(new_bh, "keeping");
 			else {
+				u32 ref;
+
 				/* The old block is released after updating
 				   the inode. */
 				error = dquot_alloc_block(inode,
@@ -881,21 +919,55 @@
 				if (error)
 					goto cleanup_dquot;
 				lock_buffer(new_bh);
-				le32_add_cpu(&BHDR(new_bh)->h_refcount, 1);
+				/*
+				 * We have to be careful about races with
+				 * freeing, rehashing or adding references to
+				 * xattr block. Once we hold buffer lock xattr
+				 * block's state is stable so we can check
+				 * whether the block got freed / rehashed or
+				 * not.  Since we unhash mbcache entry under
+				 * buffer lock when freeing / rehashing xattr
+				 * block, checking whether entry is still
+				 * hashed is reliable. Same rules hold for
+				 * e_reusable handling.
+				 */
+				if (hlist_bl_unhashed(&ce->e_hash_list) ||
+				    !ce->e_reusable) {
+					/*
+					 * Undo everything and check mbcache
+					 * again.
+					 */
+					unlock_buffer(new_bh);
+					dquot_free_block(inode,
+							 EXT4_C2B(EXT4_SB(sb),
+								  1));
+					brelse(new_bh);
+					mb_cache_entry_put(ext4_mb_cache, ce);
+					ce = NULL;
+					new_bh = NULL;
+					goto inserted;
+				}
+				ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1;
+				BHDR(new_bh)->h_refcount = cpu_to_le32(ref);
+				if (ref >= EXT4_XATTR_REFCOUNT_MAX)
+					ce->e_reusable = 0;
 				ea_bdebug(new_bh, "reusing; refcount now=%d",
-					le32_to_cpu(BHDR(new_bh)->h_refcount));
+					  ref);
+				ext4_xattr_block_csum_set(inode, new_bh);
 				unlock_buffer(new_bh);
-				error = ext4_handle_dirty_xattr_block(handle,
-								      inode,
-								      new_bh);
+				error = ext4_handle_dirty_metadata(handle,
+								   inode,
+								   new_bh);
 				if (error)
 					goto cleanup_dquot;
 			}
-			mb_cache_entry_release(ce);
+			mb_cache_entry_touch(ext4_mb_cache, ce);
+			mb_cache_entry_put(ext4_mb_cache, ce);
 			ce = NULL;
 		} else if (bs->bh && s->base == bs->bh->b_data) {
 			/* We were modifying this block in-place. */
 			ea_bdebug(bs->bh, "keeping this block");
+			ext4_xattr_cache_insert(ext4_mb_cache, bs->bh);
 			new_bh = bs->bh;
 			get_bh(new_bh);
 		} else {
@@ -936,11 +1008,12 @@
 				goto getblk_failed;
 			}
 			memcpy(new_bh->b_data, s->base, new_bh->b_size);
+			ext4_xattr_block_csum_set(inode, new_bh);
 			set_buffer_uptodate(new_bh);
 			unlock_buffer(new_bh);
 			ext4_xattr_cache_insert(ext4_mb_cache, new_bh);
-			error = ext4_handle_dirty_xattr_block(handle,
-							      inode, new_bh);
+			error = ext4_handle_dirty_metadata(handle, inode,
+							   new_bh);
 			if (error)
 				goto cleanup;
 		}
@@ -956,7 +1029,7 @@
 
 cleanup:
 	if (ce)
-		mb_cache_entry_release(ce);
+		mb_cache_entry_put(ext4_mb_cache, ce);
 	brelse(new_bh);
 	if (!(bs->bh && s->base == bs->bh->b_data))
 		kfree(s->base);
@@ -982,16 +1055,16 @@
 	struct ext4_inode *raw_inode;
 	int error;
 
-	if (EXT4_I(inode)->i_extra_isize == 0)
+	if (!EXT4_INODE_HAS_XATTR_SPACE(inode))
 		return 0;
+
 	raw_inode = ext4_raw_inode(&is->iloc);
 	header = IHDR(inode, raw_inode);
 	is->s.base = is->s.first = IFIRST(header);
 	is->s.here = is->s.first;
 	is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
 	if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) {
-		error = ext4_xattr_check_names(IFIRST(header), is->s.end,
-					       IFIRST(header));
+		error = xattr_check_inode(inode, header, is->s.end);
 		if (error)
 			return error;
 		/* Find the named attribute. */
@@ -1013,25 +1086,11 @@
 	struct ext4_xattr_search *s = &is->s;
 	int error;
 
-	if (EXT4_I(inode)->i_extra_isize == 0)
+	if (!EXT4_INODE_HAS_XATTR_SPACE(inode))
 		return -ENOSPC;
-	error = ext4_xattr_set_entry(i, s);
-	if (error) {
-		if (error == -ENOSPC &&
-		    ext4_has_inline_data(inode)) {
-			error = ext4_try_to_evict_inline_data(handle, inode,
-					EXT4_XATTR_LEN(strlen(i->name) +
-					EXT4_XATTR_SIZE(i->value_len)));
-			if (error)
-				return error;
-			error = ext4_xattr_ibody_find(inode, i, is);
-			if (error)
-				return error;
-			error = ext4_xattr_set_entry(i, s);
-		}
-		if (error)
-			return error;
-	}
+	error = ext4_xattr_set_entry(i, s, inode);
+	if (error)
+		return error;
 	header = IHDR(inode, ext4_raw_inode(&is->iloc));
 	if (!IS_LAST_ENTRY(s->first)) {
 		header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
@@ -1051,9 +1110,9 @@
 	struct ext4_xattr_search *s = &is->s;
 	int error;
 
-	if (EXT4_I(inode)->i_extra_isize == 0)
+	if (!EXT4_INODE_HAS_XATTR_SPACE(inode))
 		return -ENOSPC;
-	error = ext4_xattr_set_entry(i, s);
+	error = ext4_xattr_set_entry(i, s, inode);
 	if (error)
 		return error;
 	header = IHDR(inode, ext4_raw_inode(&is->iloc));
@@ -1067,6 +1126,17 @@
 	return 0;
 }
 
+static int ext4_xattr_value_same(struct ext4_xattr_search *s,
+				 struct ext4_xattr_info *i)
+{
+	void *value;
+
+	if (le32_to_cpu(s->here->e_value_size) != i->value_len)
+		return 0;
+	value = ((void *)s->base) + le16_to_cpu(s->here->e_value_offs);
+	return !memcmp(value, i->value, i->value_len);
+}
+
 /*
  * ext4_xattr_set_handle()
  *
@@ -1097,16 +1167,14 @@
 	struct ext4_xattr_block_find bs = {
 		.s = { .not_found = -ENODATA, },
 	};
-	unsigned long no_expand;
+	int no_expand;
 	int error;
 
 	if (!name)
 		return -EINVAL;
 	if (strlen(name) > 255)
 		return -ERANGE;
-	down_write(&EXT4_I(inode)->xattr_sem);
-	no_expand = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
-	ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
+	ext4_write_lock_xattr(inode, &no_expand);
 
 	error = ext4_reserve_inode_write(handle, inode, &is.iloc);
 	if (error)
@@ -1143,12 +1211,21 @@
 		else if (!bs.s.not_found)
 			error = ext4_xattr_block_set(handle, inode, &i, &bs);
 	} else {
+		error = 0;
+		/* Xattr value did not change? Save us some work and bail out */
+		if (!is.s.not_found && ext4_xattr_value_same(&is.s, &i))
+			goto cleanup;
+		if (!bs.s.not_found && ext4_xattr_value_same(&bs.s, &i))
+			goto cleanup;
+
 		error = ext4_xattr_ibody_set(handle, inode, &i, &is);
 		if (!error && !bs.s.not_found) {
 			i.value = NULL;
 			error = ext4_xattr_block_set(handle, inode, &i, &bs);
 		} else if (error == -ENOSPC) {
 			if (EXT4_I(inode)->i_file_acl && !bs.s.base) {
+				brelse(bs.bh);
+				bs.bh = NULL;
 				error = ext4_xattr_block_find(inode, &i, &bs);
 				if (error)
 					goto cleanup;
@@ -1167,7 +1244,7 @@
 		ext4_xattr_update_super_block(handle, inode->i_sb);
 		inode->i_ctime = ext4_current_time(inode);
 		if (!value)
-			ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
+			no_expand = 0;
 		error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
 		/*
 		 * The bh is consumed by ext4_mark_iloc_dirty, even with
@@ -1181,9 +1258,7 @@
 cleanup:
 	brelse(is.iloc.bh);
 	brelse(bs.bh);
-	if (no_expand == 0)
-		ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
-	up_write(&EXT4_I(inode)->xattr_sem);
+	ext4_write_unlock_xattr(inode, &no_expand);
 	return error;
 }
 
@@ -1264,15 +1339,18 @@
 	size_t min_offs, free;
 	int total_ino;
 	void *base, *start, *end;
-	int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
+	int error = 0, tried_min_extra_isize = 0;
 	int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize);
+	int isize_diff;	/* How much do we need to grow i_extra_isize */
+	int no_expand;
 
-	down_write(&EXT4_I(inode)->xattr_sem);
-retry:
-	if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) {
-		up_write(&EXT4_I(inode)->xattr_sem);
+	if (ext4_write_trylock_xattr(inode, &no_expand) == 0)
 		return 0;
-	}
+
+retry:
+	isize_diff = new_extra_isize - EXT4_I(inode)->i_extra_isize;
+	if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
+		goto out;
 
 	header = IHDR(inode, raw_inode);
 	entry = IFIRST(header);
@@ -1288,8 +1366,12 @@
 	last = entry;
 	total_ino = sizeof(struct ext4_xattr_ibody_header);
 
+	error = xattr_check_inode(inode, header, end);
+	if (error)
+		goto cleanup;
+
 	free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
-	if (free >= new_extra_isize) {
+	if (free >= isize_diff) {
 		entry = IFIRST(header);
 		ext4_xattr_shift_entries(entry,	EXT4_I(inode)->i_extra_isize
 				- new_extra_isize, (void *)raw_inode +
@@ -1297,8 +1379,7 @@
 				(void *)header, total_ino,
 				inode->i_sb->s_blocksize);
 		EXT4_I(inode)->i_extra_isize = new_extra_isize;
-		error = 0;
-		goto cleanup;
+		goto out;
 	}
 
 	/*
@@ -1321,7 +1402,7 @@
 		end = bh->b_data + bh->b_size;
 		min_offs = end - base;
 		free = ext4_xattr_free_space(first, &min_offs, base, NULL);
-		if (free < new_extra_isize) {
+		if (free < isize_diff) {
 			if (!tried_min_extra_isize && s_min_extra_isize) {
 				tried_min_extra_isize++;
 				new_extra_isize = s_min_extra_isize;
@@ -1335,7 +1416,7 @@
 		free = inode->i_sb->s_blocksize;
 	}
 
-	while (new_extra_isize > 0) {
+	while (isize_diff > 0) {
 		size_t offs, size, entry_size;
 		struct ext4_xattr_entry *small_entry = NULL;
 		struct ext4_xattr_info i = {
@@ -1362,11 +1443,16 @@
 		/* Find the entry best suited to be pushed into EA block */
 		entry = NULL;
 		for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+			/* never move system.data out of the inode */
+			if ((last->e_name_len == 4) &&
+			    (last->e_name_index == EXT4_XATTR_INDEX_SYSTEM) &&
+			    !memcmp(last->e_name, "data", 4))
+				continue;
 			total_size =
 			EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
 					EXT4_XATTR_LEN(last->e_name_len);
 			if (total_size <= free && total_size < min_total_size) {
-				if (total_size < new_extra_isize) {
+				if (total_size < isize_diff) {
 					small_entry = last;
 				} else {
 					entry = last;
@@ -1421,22 +1507,22 @@
 		error = ext4_xattr_ibody_set(handle, inode, &i, is);
 		if (error)
 			goto cleanup;
+		total_ino -= entry_size;
 
 		entry = IFIRST(header);
-		if (entry_size + EXT4_XATTR_SIZE(size) >= new_extra_isize)
-			shift_bytes = new_extra_isize;
+		if (entry_size + EXT4_XATTR_SIZE(size) >= isize_diff)
+			shift_bytes = isize_diff;
 		else
-			shift_bytes = entry_size + size;
+			shift_bytes = entry_size + EXT4_XATTR_SIZE(size);
 		/* Adjust the offsets and shift the remaining entries ahead */
-		ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize -
-			shift_bytes, (void *)raw_inode +
-			EXT4_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
-			(void *)header, total_ino - entry_size,
-			inode->i_sb->s_blocksize);
-
-		extra_isize += shift_bytes;
-		new_extra_isize -= shift_bytes;
-		EXT4_I(inode)->i_extra_isize = extra_isize;
+		ext4_xattr_shift_entries(entry, -shift_bytes,
+			(void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
+			EXT4_I(inode)->i_extra_isize + shift_bytes,
+			(void *)header, total_ino, inode->i_sb->s_blocksize);
+
+		isize_diff -= shift_bytes;
+		EXT4_I(inode)->i_extra_isize += shift_bytes;
+		header = IHDR(inode, raw_inode);
 
 		i.name = b_entry_name;
 		i.value = buffer;
@@ -1458,7 +1544,8 @@
 		kfree(bs);
 	}
 	brelse(bh);
-	up_write(&EXT4_I(inode)->xattr_sem);
+out:
+	ext4_write_unlock_xattr(inode, &no_expand);
 	return 0;
 
 cleanup:
@@ -1466,10 +1553,16 @@
 	kfree(buffer);
 	if (is)
 		brelse(is->iloc.bh);
+	if (bs)
+		brelse(bs->bh);
 	kfree(is);
 	kfree(bs);
 	brelse(bh);
-	up_write(&EXT4_I(inode)->xattr_sem);
+	/*
+	 * Inode size expansion failed; don't try again
+	 */
+	no_expand = 1;
+	ext4_write_unlock_xattr(inode, &no_expand);
 	return error;
 }
 
@@ -1509,17 +1602,6 @@
 }
 
 /*
- * ext4_xattr_put_super()
- *
- * This is called when a file system is unmounted.
- */
-void
-ext4_xattr_put_super(struct super_block *sb)
-{
-	mb_cache_shrink(sb->s_bdev);
-}
-
-/*
  * ext4_xattr_cache_insert()
  *
  * Create a new entry in the extended attribute cache, and insert
@@ -1530,26 +1612,19 @@
 static void
 ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh)
 {
-	__u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
-	struct mb_cache_entry *ce;
+	struct ext4_xattr_header *header = BHDR(bh);
+	__u32 hash = le32_to_cpu(header->h_hash);
+	int reusable = le32_to_cpu(header->h_refcount) <
+		       EXT4_XATTR_REFCOUNT_MAX;
 	int error;
 
-	ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS);
-	if (!ce) {
-		ea_bdebug(bh, "out of memory");
-		return;
-	}
-	error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
+	error = mb_cache_entry_create(ext4_mb_cache, GFP_NOFS, hash,
+				      bh->b_blocknr, reusable);
 	if (error) {
-		mb_cache_entry_free(ce);
-		if (error == -EBUSY) {
+		if (error == -EBUSY)
 			ea_bdebug(bh, "already in cache");
-			error = 0;
-		}
-	} else {
+	} else
 		ea_bdebug(bh, "inserting [%x]", (int)hash);
-		mb_cache_entry_release(ce);
-	}
 }
 
 /*
@@ -1611,33 +1686,20 @@
 	if (!header->h_hash)
 		return NULL;  /* never share */
 	ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
-again:
-	ce = mb_cache_entry_find_first(ext4_mb_cache, inode->i_sb->s_bdev,
-				       hash);
+	ce = mb_cache_entry_find_first(ext4_mb_cache, hash);
 	while (ce) {
 		struct buffer_head *bh;
 
-		if (IS_ERR(ce)) {
-			if (PTR_ERR(ce) == -EAGAIN)
-				goto again;
-			break;
-		}
 		bh = sb_bread(inode->i_sb, ce->e_block);
 		if (!bh) {
 			EXT4_ERROR_INODE(inode, "block %lu read error",
 					 (unsigned long) ce->e_block);
-		} else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
-				EXT4_XATTR_REFCOUNT_MAX) {
-			ea_idebug(inode, "block %lu refcount %d>=%d",
-				  (unsigned long) ce->e_block,
-				  le32_to_cpu(BHDR(bh)->h_refcount),
-					  EXT4_XATTR_REFCOUNT_MAX);
 		} else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) {
 			*pce = ce;
 			return bh;
 		}
 		brelse(bh);
-		ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
+		ce = mb_cache_entry_find_next(ext4_mb_cache, ce);
 	}
 	return NULL;
 }
@@ -1713,9 +1775,9 @@
 #define	HASH_BUCKET_BITS	10
 
 struct mb_cache *
-ext4_xattr_create_cache(char *name)
+ext4_xattr_create_cache(void)
 {
-	return mb_cache_create(name, HASH_BUCKET_BITS);
+	return mb_cache_create(HASH_BUCKET_BITS);
 }
 
 void ext4_xattr_destroy_cache(struct mb_cache *cache)
--- linux-4.4.0.orig/fs/ext4/xattr.h
+++ linux-4.4.0/fs/ext4/xattr.h
@@ -75,6 +75,19 @@
 
 #define EXT4_ZERO_XATTR_VALUE ((void *)-1)
 
+/*
+ * If we want to add an xattr to the inode, we should make sure that
+ * i_extra_isize is not 0 and that the inode size is not less than
+ * EXT4_GOOD_OLD_INODE_SIZE + extra_isize + pad.
+ *   EXT4_GOOD_OLD_INODE_SIZE   extra_isize header   entry   pad  data
+ * |--------------------------|------------|------|---------|---|-------|
+ */
+#define EXT4_INODE_HAS_XATTR_SPACE(inode)				\
+	((EXT4_I(inode)->i_extra_isize != 0) &&				\
+	 (EXT4_GOOD_OLD_INODE_SIZE + EXT4_I(inode)->i_extra_isize +	\
+	  sizeof(struct ext4_xattr_ibody_header) + EXT4_XATTR_PAD <=	\
+	  EXT4_INODE_SIZE((inode)->i_sb)))
+
 struct ext4_xattr_info {
 	int name_index;
 	const char *name;
@@ -101,6 +114,38 @@
 
 #define EXT4_XATTR_NAME_ENCRYPTION_CONTEXT "c"
 
+/*
+ * The EXT4_STATE_NO_EXPAND is overloaded and used for two purposes.
+ * The first is to signal that there the inline xattrs and data are
+ * taking up so much space that we might as well not keep trying to
+ * expand it.  The second is that xattr_sem is taken for writing, so
+ * we shouldn't try to recurse into the inode expansion.  For this
+ * second case, we need to make sure that we take save and restore the
+ * NO_EXPAND state flag appropriately.
+ */
+static inline void ext4_write_lock_xattr(struct inode *inode, int *save)
+{
+	down_write(&EXT4_I(inode)->xattr_sem);
+	*save = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
+	ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
+}
+
+static inline int ext4_write_trylock_xattr(struct inode *inode, int *save)
+{
+	if (down_write_trylock(&EXT4_I(inode)->xattr_sem) == 0)
+		return 0;
+	*save = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
+	ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
+	return 1;
+}
+
+static inline void ext4_write_unlock_xattr(struct inode *inode, int *save)
+{
+	if (*save == 0)
+		ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
+	up_write(&EXT4_I(inode)->xattr_sem);
+}
+
 extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
 
 extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
@@ -108,7 +153,6 @@
 extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
 
 extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
-extern void ext4_xattr_put_super(struct super_block *);
 
 extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
 			    struct ext4_inode *raw_inode, handle_t *handle);
@@ -124,7 +168,7 @@
 				       struct ext4_xattr_info *i,
 				       struct ext4_xattr_ibody_find *is);
 
-extern struct mb_cache *ext4_xattr_create_cache(char *name);
+extern struct mb_cache *ext4_xattr_create_cache(void);
 extern void ext4_xattr_destroy_cache(struct mb_cache *);
 
 #ifdef CONFIG_EXT4_FS_SECURITY
--- linux-4.4.0.orig/fs/f2fs/acl.c
+++ linux-4.4.0/fs/f2fs/acl.c
@@ -213,13 +213,11 @@
 	switch (type) {
 	case ACL_TYPE_ACCESS:
 		name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
-		if (acl) {
-			error = posix_acl_equiv_mode(acl, &inode->i_mode);
-			if (error < 0)
+		if (acl && !ipage) {
+			error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+			if (error)
 				return error;
 			set_acl_inode(fi, inode->i_mode);
-			if (error == 0)
-				acl = NULL;
 		}
 		break;
 
@@ -352,12 +350,14 @@
 		return PTR_ERR(p);
 
 	clone = f2fs_acl_clone(p, GFP_NOFS);
-	if (!clone)
-		goto no_mem;
+	if (!clone) {
+		ret = -ENOMEM;
+		goto release_acl;
+	}
 
 	ret = f2fs_acl_create_masq(clone, mode);
 	if (ret < 0)
-		goto no_mem_clone;
+		goto release_clone;
 
 	if (ret == 0)
 		posix_acl_release(clone);
@@ -371,11 +371,11 @@
 
 	return 0;
 
-no_mem_clone:
+release_clone:
 	posix_acl_release(clone);
-no_mem:
+release_acl:
 	posix_acl_release(p);
-	return -ENOMEM;
+	return ret;
 }
 
 int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
--- linux-4.4.0.orig/fs/f2fs/checkpoint.c
+++ linux-4.4.0/fs/f2fs/checkpoint.c
@@ -58,6 +58,7 @@
 		.rw = READ_SYNC | REQ_META | REQ_PRIO,
 		.blk_addr = index,
 		.encrypted_page = NULL,
+		.is_meta = is_meta,
 	};
 
 	if (unlikely(!is_meta))
@@ -74,8 +75,10 @@
 	fio.page = page;
 
 	if (f2fs_submit_page_bio(&fio)) {
-		f2fs_put_page(page, 1);
-		goto repeat;
+		memset(page_address(page), 0, PAGE_SIZE);
+		f2fs_stop_checkpoint(sbi);
+		f2fs_bug_on(sbi, 1);
+		return page;
 	}
 
 	lock_page(page);
@@ -106,7 +109,8 @@
 	return __get_meta_page(sbi, index, false);
 }
 
-bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
+bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
+					block_t blkaddr, int type)
 {
 	switch (type) {
 	case META_NAT:
@@ -126,8 +130,20 @@
 			return false;
 		break;
 	case META_POR:
+	case DATA_GENERIC:
 		if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
-			blkaddr < MAIN_BLKADDR(sbi)))
+			blkaddr < MAIN_BLKADDR(sbi))) {
+			if (type == DATA_GENERIC) {
+				f2fs_msg(sbi->sb, KERN_WARNING,
+					"access invalid blkaddr:%u", blkaddr);
+				WARN_ON(1);
+			}
+			return false;
+		}
+		break;
+	case META_GENERIC:
+		if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
+			blkaddr >= MAIN_BLKADDR(sbi)))
 			return false;
 		break;
 	default:
@@ -151,6 +167,7 @@
 		.type = META,
 		.rw = sync ? (READ_SYNC | REQ_META | REQ_PRIO) : READA,
 		.encrypted_page = NULL,
+		.is_meta = (type != META_POR),
 	};
 
 	if (unlikely(type == META_POR))
@@ -158,7 +175,7 @@
 
 	for (; nrpages-- > 0; blkno++) {
 
-		if (!is_valid_blkaddr(sbi, blkno, type))
+		if (!f2fs_is_valid_blkaddr(sbi, blkno, type))
 			goto out;
 
 		switch (type) {
@@ -171,6 +188,8 @@
 					blkno * NAT_ENTRY_PER_BLOCK);
 			break;
 		case META_SIT:
+			if (unlikely(blkno >= TOTAL_SEGS(sbi)))
+				goto out;
 			/* get sit block addr */
 			fio.blk_addr = current_sit_addr(sbi,
 					blkno * SIT_ENTRY_PER_BLOCK);
@@ -601,54 +620,73 @@
 	}
 }
 
-static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
-				block_t cp_addr, unsigned long long *version)
+static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
+		struct f2fs_checkpoint **cp_block, struct page **cp_page,
+		unsigned long long *version)
 {
-	struct page *cp_page_1, *cp_page_2 = NULL;
 	unsigned long blk_size = sbi->blocksize;
-	struct f2fs_checkpoint *cp_block;
-	unsigned long long cur_version = 0, pre_version = 0;
-	size_t crc_offset;
+	size_t crc_offset = 0;
 	__u32 crc = 0;
 
-	/* Read the 1st cp block in this CP pack */
-	cp_page_1 = get_meta_page(sbi, cp_addr);
+	*cp_page = get_meta_page(sbi, cp_addr);
+	*cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
 
-	/* get the version number */
-	cp_block = (struct f2fs_checkpoint *)page_address(cp_page_1);
-	crc_offset = le32_to_cpu(cp_block->checksum_offset);
-	if (crc_offset >= blk_size)
-		goto invalid_cp1;
-
-	crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset)));
-	if (!f2fs_crc_valid(crc, cp_block, crc_offset))
-		goto invalid_cp1;
+	crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
+	if (crc_offset >= blk_size) {
+		f2fs_put_page(*cp_page, 1);
+		f2fs_msg(sbi->sb, KERN_WARNING,
+			"invalid crc_offset: %zu", crc_offset);
+		return -EINVAL;
+	}
+
+	crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block
+							+ crc_offset)));
+	if (!f2fs_crc_valid(crc, *cp_block, crc_offset)) {
+		f2fs_put_page(*cp_page, 1);
+		f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
+		return -EINVAL;
+	}
 
-	pre_version = cur_cp_version(cp_block);
+	*version = cur_cp_version(*cp_block);
+	return 0;
+}
 
-	/* Read the 2nd cp block in this CP pack */
-	cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
-	cp_page_2 = get_meta_page(sbi, cp_addr);
+static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
+				block_t cp_addr, unsigned long long *version)
+{
+	struct page *cp_page_1 = NULL, *cp_page_2 = NULL;
+	struct f2fs_checkpoint *cp_block = NULL;
+	unsigned long long cur_version = 0, pre_version = 0;
+	int err;
 
-	cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2);
-	crc_offset = le32_to_cpu(cp_block->checksum_offset);
-	if (crc_offset >= blk_size)
-		goto invalid_cp2;
-
-	crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset)));
-	if (!f2fs_crc_valid(crc, cp_block, crc_offset))
-		goto invalid_cp2;
+	err = get_checkpoint_version(sbi, cp_addr, &cp_block,
+					&cp_page_1, version);
+	if (err)
+		return NULL;
+
+	if (le32_to_cpu(cp_block->cp_pack_total_block_count) >
+					sbi->blocks_per_seg) {
+		f2fs_msg(sbi->sb, KERN_WARNING,
+			"invalid cp_pack_total_block_count:%u",
+			le32_to_cpu(cp_block->cp_pack_total_block_count));
+		goto invalid_cp;
+	}
+	pre_version = *version;
 
-	cur_version = cur_cp_version(cp_block);
+	cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
+	err = get_checkpoint_version(sbi, cp_addr, &cp_block,
+					&cp_page_2, version);
+	if (err)
+		goto invalid_cp;
+	cur_version = *version;
 
 	if (cur_version == pre_version) {
 		*version = cur_version;
 		f2fs_put_page(cp_page_2, 1);
 		return cp_page_1;
 	}
-invalid_cp2:
 	f2fs_put_page(cp_page_2, 1);
-invalid_cp1:
+invalid_cp:
 	f2fs_put_page(cp_page_1, 1);
 	return NULL;
 }
@@ -696,6 +734,15 @@
 	cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
 	memcpy(sbi->ckpt, cp_block, blk_size);
 
+	if (cur_page == cp1)
+		sbi->cur_cp_pack = 1;
+	else
+		sbi->cur_cp_pack = 2;
+
+	/* Sanity checking of checkpoint */
+	if (sanity_check_ckpt(sbi))
+		goto free_fail_no_cp;
+
 	if (cp_blks <= 1)
 		goto done;
 
@@ -717,6 +764,9 @@
 	f2fs_put_page(cp2, 1);
 	return 0;
 
+free_fail_no_cp:
+	f2fs_put_page(cp1, 1);
+	f2fs_put_page(cp2, 1);
 fail_no_cp:
 	kfree(sbi->ckpt);
 	return -EINVAL;
@@ -767,24 +817,6 @@
 	f2fs_trace_pid(page);
 }
 
-void add_dirty_dir_inode(struct inode *inode)
-{
-	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-	struct inode_entry *new =
-			f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
-	int ret = 0;
-
-	new->inode = inode;
-	INIT_LIST_HEAD(&new->list);
-
-	spin_lock(&sbi->dir_inode_lock);
-	ret = __add_dirty_inode(inode, new);
-	spin_unlock(&sbi->dir_inode_lock);
-
-	if (ret)
-		kmem_cache_free(inode_entry_slab, new);
-}
-
 void remove_dirty_dir_inode(struct inode *inode)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -807,12 +839,6 @@
 	stat_dec_dirty_dir(sbi);
 	spin_unlock(&sbi->dir_inode_lock);
 	kmem_cache_free(inode_entry_slab, entry);
-
-	/* Only from the recovery routine */
-	if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
-		clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
-		iput(inode);
-	}
 }
 
 void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
@@ -922,7 +948,6 @@
 static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 {
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
-	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
 	struct f2fs_nm_info *nm_i = NM_I(sbi);
 	unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
 	nid_t last_nid = nm_i->next_scan_nid;
@@ -931,15 +956,6 @@
 	__u32 crc32 = 0;
 	int i;
 	int cp_payload_blks = __cp_payload(sbi);
-	block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg);
-	bool invalidate = false;
-
-	/*
-	 * This avoids to conduct wrong roll-forward operations and uses
-	 * metapages, so should be called prior to sync_meta_pages below.
-	 */
-	if (discard_next_dnode(sbi, discard_blk))
-		invalidate = true;
 
 	/* Flush all the NAT/SIT pages */
 	while (get_pages(sbi, F2FS_DIRTY_META)) {
@@ -1016,6 +1032,9 @@
 	if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
 		set_ckpt_flags(ckpt, CP_FSCK_FLAG);
 
+	/* set this flag to activate crc|cp_ver for recovery */
+	set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
+
 	/* update SIT/NAT bitmap */
 	get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));
 	get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP));
@@ -1025,7 +1044,7 @@
 				le32_to_cpu(ckpt->checksum_offset)))
 				= cpu_to_le32(crc32);
 
-	start_blk = __start_cp_addr(sbi);
+	start_blk = __start_cp_next_addr(sbi);
 
 	/* need to wait for end_io results */
 	wait_on_all_pages_writeback(sbi);
@@ -1073,14 +1092,6 @@
 	/* wait for previous submitted meta pages writeback */
 	wait_on_all_pages_writeback(sbi);
 
-	/*
-	 * invalidate meta page which is used temporarily for zeroing out
-	 * block at the end of warm node chain.
-	 */
-	if (invalidate)
-		invalidate_mapping_pages(META_MAPPING(sbi), discard_blk,
-								discard_blk);
-
 	release_dirty_inode(sbi);
 
 	if (unlikely(f2fs_cp_error(sbi)))
@@ -1088,6 +1099,7 @@
 
 	clear_prefree_segments(sbi, cpc);
 	clear_sbi_flag(sbi, SBI_IS_DIRTY);
+	__set_cp_next_pack(sbi);
 }
 
 /*
--- linux-4.4.0.orig/fs/f2fs/crypto.c
+++ linux-4.4.0/fs/f2fs/crypto.c
@@ -362,7 +362,6 @@
 	else
 		res = crypto_ablkcipher_encrypt(req);
 	if (res == -EINPROGRESS || res == -EBUSY) {
-		BUG_ON(req->base.data != &ecr);
 		wait_for_completion(&ecr.completion);
 		res = ecr.res;
 	}
--- linux-4.4.0.orig/fs/f2fs/crypto_fname.c
+++ linux-4.4.0/fs/f2fs/crypto_fname.c
@@ -124,7 +124,6 @@
 	ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
 	res = crypto_ablkcipher_encrypt(req);
 	if (res == -EINPROGRESS || res == -EBUSY) {
-		BUG_ON(req->base.data != &ecr);
 		wait_for_completion(&ecr.completion);
 		res = ecr.res;
 	}
@@ -180,7 +179,6 @@
 	ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
 	res = crypto_ablkcipher_decrypt(req);
 	if (res == -EINPROGRESS || res == -EBUSY) {
-		BUG_ON(req->base.data != &ecr);
 		wait_for_completion(&ecr.completion);
 		res = ecr.res;
 	}
@@ -333,7 +331,7 @@
 		memset(buf + 4, 0, 4);
 	} else
 		memset(buf, 0, 8);
-	memcpy(buf + 8, iname->name + iname->len - 16, 16);
+	memcpy(buf + 8, iname->name + ((iname->len - 17) & ~15), 16);
 	oname->name[0] = '_';
 	ret = digest_encode(buf, 24, oname->name + 1);
 	oname->len = ret + 1;
--- linux-4.4.0.orig/fs/f2fs/crypto_key.c
+++ linux-4.4.0/fs/f2fs/crypto_key.c
@@ -75,7 +75,6 @@
 					F2FS_AES_256_XTS_KEY_SIZE, NULL);
 	res = crypto_ablkcipher_encrypt(req);
 	if (res == -EINPROGRESS || res == -EBUSY) {
-		BUG_ON(req->base.data != &ecr);
 		wait_for_completion(&ecr.completion);
 		res = ecr.res;
 	}
@@ -92,7 +91,6 @@
 	if (!ci)
 		return;
 
-	key_put(ci->ci_keyring_key);
 	crypto_free_ablkcipher(ci->ci_ctfm);
 	kmem_cache_free(f2fs_crypt_info_cachep, ci);
 }
@@ -113,7 +111,7 @@
 	f2fs_free_crypt_info(ci);
 }
 
-int _f2fs_get_encryption_info(struct inode *inode)
+int f2fs_get_encryption_info(struct inode *inode)
 {
 	struct f2fs_inode_info *fi = F2FS_I(inode);
 	struct f2fs_crypt_info *crypt_info;
@@ -129,18 +127,12 @@
 	char mode;
 	int res;
 
+	if (fi->i_crypt_info)
+		return 0;
+
 	res = f2fs_crypto_initialize();
 	if (res)
 		return res;
-retry:
-	crypt_info = ACCESS_ONCE(fi->i_crypt_info);
-	if (crypt_info) {
-		if (!crypt_info->ci_keyring_key ||
-				key_validate(crypt_info->ci_keyring_key) == 0)
-			return 0;
-		f2fs_free_encryption_info(inode, crypt_info);
-		goto retry;
-	}
 
 	res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
 				F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
@@ -159,7 +151,6 @@
 	crypt_info->ci_data_mode = ctx.contents_encryption_mode;
 	crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
 	crypt_info->ci_ctfm = NULL;
-	crypt_info->ci_keyring_key = NULL;
 	memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
 				sizeof(crypt_info->ci_master_key));
 	if (S_ISREG(inode->i_mode))
@@ -197,19 +188,38 @@
 		keyring_key = NULL;
 		goto out;
 	}
-	crypt_info->ci_keyring_key = keyring_key;
-	BUG_ON(keyring_key->type != &key_type_logon);
+	if (keyring_key->type != &key_type_logon) {
+		printk_once(KERN_WARNING "f2fs: key type must be logon\n");
+		res = -ENOKEY;
+		goto out;
+	}
+	down_read(&keyring_key->sem);
 	ukp = user_key_payload(keyring_key);
+	if (!ukp) {
+		/* key was revoked before we acquired its semaphore */
+		res = -EKEYREVOKED;
+		up_read(&keyring_key->sem);
+		goto out;
+	}
 	if (ukp->datalen != sizeof(struct f2fs_encryption_key)) {
 		res = -EINVAL;
+		up_read(&keyring_key->sem);
 		goto out;
 	}
 	master_key = (struct f2fs_encryption_key *)ukp->data;
 	BUILD_BUG_ON(F2FS_AES_128_ECB_KEY_SIZE !=
 				F2FS_KEY_DERIVATION_NONCE_SIZE);
-	BUG_ON(master_key->size != F2FS_AES_256_XTS_KEY_SIZE);
+	if (master_key->size != F2FS_AES_256_XTS_KEY_SIZE) {
+		printk_once(KERN_WARNING
+				"f2fs: key size incorrect: %d\n",
+				master_key->size);
+		res = -ENOKEY;
+		up_read(&keyring_key->sem);
+		goto out;
+	}
 	res = f2fs_derive_key_aes(ctx.nonce, master_key->raw,
 				  raw_key);
+	up_read(&keyring_key->sem);
 	if (res)
 		goto out;
 
@@ -230,17 +240,12 @@
 	if (res)
 		goto out;
 
-	memzero_explicit(raw_key, sizeof(raw_key));
-	if (cmpxchg(&fi->i_crypt_info, NULL, crypt_info) != NULL) {
-		f2fs_free_crypt_info(crypt_info);
-		goto retry;
-	}
-	return 0;
-
+	if (cmpxchg(&fi->i_crypt_info, NULL, crypt_info) == NULL)
+		crypt_info = NULL;
 out:
 	if (res == -ENOKEY && !S_ISREG(inode->i_mode))
 		res = 0;
-
+	key_put(keyring_key);
 	f2fs_free_crypt_info(crypt_info);
 	memzero_explicit(raw_key, sizeof(raw_key));
 	return res;
--- linux-4.4.0.orig/fs/f2fs/crypto_policy.c
+++ linux-4.4.0/fs/f2fs/crypto_policy.c
@@ -89,6 +89,9 @@
 int f2fs_process_policy(const struct f2fs_encryption_policy *policy,
 			struct inode *inode)
 {
+	if (!inode_owner_or_capable(inode))
+		return -EACCES;
+
 	if (policy->version != 0)
 		return -EINVAL;
 
@@ -96,6 +99,8 @@
 		return -EINVAL;
 
 	if (!f2fs_inode_has_encryption_context(inode)) {
+		if (IS_DEADDIR(inode))
+			return -ENOENT;
 		if (!f2fs_empty_dir(inode))
 			return -ENOTEMPTY;
 		return f2fs_create_encryption_context_from_policy(inode,
@@ -138,20 +143,38 @@
 int f2fs_is_child_context_consistent_with_parent(struct inode *parent,
 						struct inode *child)
 {
-	struct f2fs_crypt_info *parent_ci, *child_ci;
+	const struct f2fs_crypt_info *parent_ci, *child_ci;
+	struct f2fs_encryption_context parent_ctx, child_ctx;
 	int res;
 
-	if ((parent == NULL) || (child == NULL)) {
-		pr_err("parent %p child %p\n", parent, child);
-		BUG_ON(1);
-	}
+	/* No restrictions on file types which are never encrypted */
+	if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
+	    !S_ISLNK(child->i_mode))
+		return 1;
 
-	/* no restrictions if the parent directory is not encrypted */
+	/* No restrictions if the parent directory is unencrypted */
 	if (!f2fs_encrypted_inode(parent))
 		return 1;
-	/* if the child directory is not encrypted, this is always a problem */
+
+	/* Encrypted directories must not contain unencrypted files */
 	if (!f2fs_encrypted_inode(child))
 		return 0;
+
+	/*
+	 * Both parent and child are encrypted, so verify they use the same
+	 * encryption policy.  Compare the fscrypt_info structs if the keys are
+	 * available, otherwise retrieve and compare the fscrypt_contexts.
+	 *
+	 * Note that the fscrypt_context retrieval will be required frequently
+	 * when accessing an encrypted directory tree without the key.
+	 * Performance-wise this is not a big deal because we already don't
+	 * really optimize for file access without the key (to the extent that
+	 * such access is even possible), given that any attempted access
+	 * already causes a fscrypt_context retrieval and keyring search.
+	 *
+	 * In any case, if an unexpected error occurs, fall back to "forbidden".
+	 */
+
 	res = f2fs_get_encryption_info(parent);
 	if (res)
 		return 0;
@@ -160,17 +183,35 @@
 		return 0;
 	parent_ci = F2FS_I(parent)->i_crypt_info;
 	child_ci = F2FS_I(child)->i_crypt_info;
-	if (!parent_ci && !child_ci)
-		return 1;
-	if (!parent_ci || !child_ci)
+	if (parent_ci && child_ci) {
+		return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key,
+			      F2FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+			(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
+			(parent_ci->ci_filename_mode ==
+			 child_ci->ci_filename_mode) &&
+			(parent_ci->ci_flags == child_ci->ci_flags);
+	}
+
+	res = f2fs_getxattr(parent, F2FS_XATTR_INDEX_ENCRYPTION,
+			    F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
+			    &parent_ctx, sizeof(parent_ctx), NULL);
+	if (res != sizeof(parent_ctx))
+		return 0;
+
+	res = f2fs_getxattr(child, F2FS_XATTR_INDEX_ENCRYPTION,
+			    F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
+			    &child_ctx, sizeof(child_ctx), NULL);
+	if (res != sizeof(child_ctx))
 		return 0;
 
-	return (memcmp(parent_ci->ci_master_key,
-			child_ci->ci_master_key,
-			F2FS_KEY_DESCRIPTOR_SIZE) == 0 &&
-		(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
-		(parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
-		(parent_ci->ci_flags == child_ci->ci_flags));
+	return memcmp(parent_ctx.master_key_descriptor,
+		      child_ctx.master_key_descriptor,
+		      F2FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+		(parent_ctx.contents_encryption_mode ==
+		 child_ctx.contents_encryption_mode) &&
+		(parent_ctx.filenames_encryption_mode ==
+		 child_ctx.filenames_encryption_mode) &&
+		(parent_ctx.flags == child_ctx.flags);
 }
 
 /**
--- linux-4.4.0.orig/fs/f2fs/data.c
+++ linux-4.4.0/fs/f2fs/data.c
@@ -147,6 +147,10 @@
 	struct bio *bio;
 	struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page;
 
+	if (!f2fs_is_valid_blkaddr(fio->sbi, fio->blk_addr,
+			__is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
+		return -EFAULT;
+
 	trace_f2fs_submit_page_bio(page, fio);
 	f2fs_trace_ios(fio, 0);
 
@@ -172,7 +176,7 @@
 
 	io = is_read ? &sbi->read_io : &sbi->write_io[btype];
 
-	verify_block_addr(sbi, fio->blk_addr);
+	verify_block_addr(fio, fio->blk_addr);
 
 	down_write(&io->io_rwsem);
 
@@ -603,7 +607,13 @@
 		goto unlock_out;
 	}
 
-	if (dn.data_blkaddr == NEW_ADDR || dn.data_blkaddr == NULL_ADDR) {
+	if (__is_valid_data_blkaddr(dn.data_blkaddr) &&
+		!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr, DATA_GENERIC)) {
+		err = -EFAULT;
+		goto sync_out;
+	}
+
+	if (!is_valid_data_blkaddr(sbi, dn.data_blkaddr)) {
 		if (create) {
 			if (unlikely(f2fs_cp_error(sbi))) {
 				err = -EIO;
@@ -721,7 +731,7 @@
 	if (!ret) {
 		map_bh(bh, inode->i_sb, map.m_pblk);
 		bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags;
-		bh->b_size = map.m_len << inode->i_blkbits;
+		bh->b_size = (u64)map.m_len << inode->i_blkbits;
 	}
 	return ret;
 }
@@ -866,6 +876,40 @@
 	return ret;
 }
 
+struct bio *f2fs_grab_bio(struct inode *inode, block_t blkaddr,
+							unsigned nr_pages)
+{
+	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+	struct f2fs_crypto_ctx *ctx = NULL;
+	struct block_device *bdev = sbi->sb->s_bdev;
+	struct bio *bio;
+
+	if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
+		return ERR_PTR(-EFAULT);
+
+	if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
+		ctx = f2fs_get_crypto_ctx(inode);
+		if (IS_ERR(ctx))
+			return ERR_CAST(ctx);
+
+		/* wait the page to be moved by cleaning */
+		f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr);
+	}
+
+	bio = bio_alloc(GFP_KERNEL, min_t(int, nr_pages, BIO_MAX_PAGES));
+	if (!bio) {
+		if (ctx)
+			f2fs_release_crypto_ctx(ctx);
+		return ERR_PTR(-ENOMEM);
+	}
+	bio->bi_bdev = bdev;
+	bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(blkaddr);
+	bio->bi_end_io = f2fs_read_end_io;
+	bio->bi_private = ctx;
+
+	return bio;
+}
+
 /*
  * This function was originally taken from fs/mpage.c, and customized for f2fs.
  * Major change was from block_size == page_size in f2fs by default.
@@ -884,7 +928,6 @@
 	sector_t last_block;
 	sector_t last_block_in_file;
 	sector_t block_nr;
-	struct block_device *bdev = inode->i_sb->s_bdev;
 	struct f2fs_map_blocks map;
 
 	map.m_pblk = 0;
@@ -941,6 +984,10 @@
 				SetPageUptodate(page);
 				goto confused;
 			}
+
+			if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
+								DATA_GENERIC))
+				goto set_error_page;
 		} else {
 			zero_user_segment(page, 0, PAGE_CACHE_SIZE);
 			SetPageUptodate(page);
@@ -958,31 +1005,9 @@
 			bio = NULL;
 		}
 		if (bio == NULL) {
-			struct f2fs_crypto_ctx *ctx = NULL;
-
-			if (f2fs_encrypted_inode(inode) &&
-					S_ISREG(inode->i_mode)) {
-
-				ctx = f2fs_get_crypto_ctx(inode);
-				if (IS_ERR(ctx))
-					goto set_error_page;
-
-				/* wait the page to be moved by cleaning */
-				f2fs_wait_on_encrypted_page_writeback(
-						F2FS_I_SB(inode), block_nr);
-			}
-
-			bio = bio_alloc(GFP_KERNEL,
-				min_t(int, nr_pages, BIO_MAX_PAGES));
-			if (!bio) {
-				if (ctx)
-					f2fs_release_crypto_ctx(ctx);
+			bio = f2fs_grab_bio(inode, block_nr, nr_pages);
+			if (IS_ERR(bio))
 				goto set_error_page;
-			}
-			bio->bi_bdev = bdev;
-			bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(block_nr);
-			bio->bi_end_io = f2fs_read_end_io;
-			bio->bi_private = ctx;
 		}
 
 		if (bio_add_page(bio, page, blocksize, 0) < blocksize)
@@ -1077,11 +1102,17 @@
 
 	set_page_writeback(page);
 
+	if (__is_valid_data_blkaddr(fio->blk_addr) &&
+		!f2fs_is_valid_blkaddr(fio->sbi, fio->blk_addr,
+							DATA_GENERIC)) {
+		err = -EFAULT;
+		goto out_writepage;
+	}
 	/*
 	 * If current allocation needs SSR,
 	 * it had better in-place writes for updated data.
 	 */
-	if (unlikely(fio->blk_addr != NEW_ADDR &&
+	if (unlikely(is_valid_data_blkaddr(fio->sbi, fio->blk_addr) &&
 			!is_cold_data(page) &&
 			need_inplace_update(inode))) {
 		rewrite_data_page(fio);
@@ -1416,7 +1447,12 @@
 			goto fail;
 	}
 repeat:
-	page = grab_cache_page_write_begin(mapping, index, flags);
+	/*
+	 * Do not use grab_cache_page_write_begin() to avoid deadlock due to
+	 * wait_for_stable_page. Will wait that below with our IO control.
+	 */
+	page = pagecache_get_page(mapping, index,
+				FGP_LOCK | FGP_WRITE | FGP_CREAT, GFP_NOFS);
 	if (!page) {
 		err = -ENOMEM;
 		goto fail;
@@ -1477,17 +1513,21 @@
 	if (dn.data_blkaddr == NEW_ADDR) {
 		zero_user_segment(page, 0, PAGE_CACHE_SIZE);
 	} else {
-		struct f2fs_io_info fio = {
-			.sbi = sbi,
-			.type = DATA,
-			.rw = READ_SYNC,
-			.blk_addr = dn.data_blkaddr,
-			.page = page,
-			.encrypted_page = NULL,
-		};
-		err = f2fs_submit_page_bio(&fio);
-		if (err)
+		struct bio *bio;
+
+		bio = f2fs_grab_bio(inode, dn.data_blkaddr, 1);
+		if (IS_ERR(bio)) {
+			err = PTR_ERR(bio);
 			goto fail;
+		}
+
+		if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
+			bio_put(bio);
+			err = -EFAULT;
+			goto fail;
+		}
+
+		submit_bio(READ_SYNC, bio);
 
 		lock_page(page);
 		if (unlikely(!PageUptodate(page))) {
@@ -1498,13 +1538,6 @@
 			f2fs_put_page(page, 1);
 			goto repeat;
 		}
-
-		/* avoid symlink page */
-		if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
-			err = f2fs_decrypt_one(inode, page);
-			if (err)
-				goto fail;
-		}
 	}
 out_update:
 	SetPageUptodate(page);
--- linux-4.4.0.orig/fs/f2fs/debug.c
+++ linux-4.4.0/fs/f2fs/debug.c
@@ -352,6 +352,7 @@
 }
 
 static const struct file_operations stat_fops = {
+	.owner = THIS_MODULE,
 	.open = stat_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
--- linux-4.4.0.orig/fs/f2fs/dir.c
+++ linux-4.4.0/fs/f2fs/dir.c
@@ -48,7 +48,6 @@
 	[F2FS_FT_SYMLINK]	= DT_LNK,
 };
 
-#define S_SHIFT 12
 static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = {
 	[S_IFREG >> S_SHIFT]	= F2FS_FT_REG_FILE,
 	[S_IFDIR >> S_SHIFT]	= F2FS_FT_DIR,
@@ -64,6 +63,13 @@
 	de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
 }
 
+unsigned char get_de_type(struct f2fs_dir_entry *de)
+{
+	if (de->file_type < F2FS_FT_MAX)
+		return f2fs_filetype_table[de->file_type];
+	return DT_UNKNOWN;
+}
+
 static unsigned long dir_block_index(unsigned int level,
 				int dir_level, unsigned int idx)
 {
@@ -124,19 +130,29 @@
 
 		de = &d->dentry[bit_pos];
 
-		/* encrypted case */
+		if (de->hash_code != namehash)
+			goto not_match;
+
 		de_name.name = d->filename[bit_pos];
 		de_name.len = le16_to_cpu(de->name_len);
 
-		/* show encrypted name */
-		if (fname->hash) {
-			if (de->hash_code == fname->hash)
-				goto found;
-		} else if (de_name.len == name->len &&
-			de->hash_code == namehash &&
-			!memcmp(de_name.name, name->name, name->len))
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+		if (unlikely(!name->name)) {
+			if (fname->usr_fname->name[0] == '_') {
+				if (de_name.len > 32 &&
+					!memcmp(de_name.name + ((de_name.len - 17) & ~15),
+						fname->crypto_buf.name + 8, 16))
+					goto found;
+				goto not_match;
+			}
+			name->name = fname->crypto_buf.name;
+			name->len = fname->crypto_buf.len;
+		}
+#endif
+		if (de_name.len == name->len &&
+				!memcmp(de_name.name, name->name, name->len))
 			goto found;
-
+not_match:
 		if (max_slots && max_len > *max_slots)
 			*max_slots = max_len;
 		max_len = 0;
@@ -170,7 +186,7 @@
 	int max_slots;
 	f2fs_hash_t namehash;
 
-	namehash = f2fs_dentry_hash(&name);
+	namehash = f2fs_dentry_hash(&name, fname);
 
 	f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH);
 
@@ -509,11 +525,7 @@
 		test_and_set_bit_le(bit_pos + i, (void *)d->bitmap);
 }
 
-/*
- * Caller should grab and release a rwsem by calling f2fs_lock_op() and
- * f2fs_unlock_op().
- */
-int __f2fs_add_link(struct inode *dir, const struct qstr *name,
+int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
 				struct inode *inode, nid_t ino, umode_t mode)
 {
 	unsigned int bit_pos;
@@ -526,28 +538,11 @@
 	struct f2fs_dentry_block *dentry_blk = NULL;
 	struct f2fs_dentry_ptr d;
 	struct page *page = NULL;
-	struct f2fs_filename fname;
-	struct qstr new_name;
-	int slots, err;
-
-	err = f2fs_fname_setup_filename(dir, name, 0, &fname);
-	if (err)
-		return err;
-
-	new_name.name = fname_name(&fname);
-	new_name.len = fname_len(&fname);
-
-	if (f2fs_has_inline_dentry(dir)) {
-		err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
-		if (!err || err != -EAGAIN)
-			goto out;
-		else
-			err = 0;
-	}
+	int slots, err = 0;
 
 	level = 0;
-	slots = GET_DENTRY_SLOTS(new_name.len);
-	dentry_hash = f2fs_dentry_hash(&new_name);
+	slots = GET_DENTRY_SLOTS(new_name->len);
+	dentry_hash = f2fs_dentry_hash(new_name, NULL);
 
 	current_depth = F2FS_I(dir)->i_current_depth;
 	if (F2FS_I(dir)->chash == dentry_hash) {
@@ -556,10 +551,8 @@
 	}
 
 start:
-	if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) {
-		err = -ENOSPC;
-		goto out;
-	}
+	if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
+		return -ENOSPC;
 
 	/* Increase the depth, if required */
 	if (level == current_depth)
@@ -573,10 +566,8 @@
 
 	for (block = bidx; block <= (bidx + nblock - 1); block++) {
 		dentry_page = get_new_data_page(dir, NULL, block, true);
-		if (IS_ERR(dentry_page)) {
-			err = PTR_ERR(dentry_page);
-			goto out;
-		}
+		if (IS_ERR(dentry_page))
+			return PTR_ERR(dentry_page);
 
 		dentry_blk = kmap(dentry_page);
 		bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
@@ -596,7 +587,7 @@
 
 	if (inode) {
 		down_write(&F2FS_I(inode)->i_sem);
-		page = init_inode_metadata(inode, dir, &new_name, NULL);
+		page = init_inode_metadata(inode, dir, new_name, NULL);
 		if (IS_ERR(page)) {
 			err = PTR_ERR(page);
 			goto fail;
@@ -606,7 +597,7 @@
 	}
 
 	make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
-	f2fs_update_dentry(ino, mode, &d, &new_name, dentry_hash, bit_pos);
+	f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos);
 
 	set_page_dirty(dentry_page);
 
@@ -628,7 +619,34 @@
 	}
 	kunmap(dentry_page);
 	f2fs_put_page(dentry_page, 1);
-out:
+
+	return err;
+}
+
+/*
+ * Caller should grab and release a rwsem by calling f2fs_lock_op() and
+ * f2fs_unlock_op().
+ */
+int __f2fs_add_link(struct inode *dir, const struct qstr *name,
+				struct inode *inode, nid_t ino, umode_t mode)
+{
+	struct f2fs_filename fname;
+	struct qstr new_name;
+	int err;
+
+	err = f2fs_fname_setup_filename(dir, name, 0, &fname);
+	if (err)
+		return err;
+
+	new_name.name = fname_name(&fname);
+	new_name.len = fname_len(&fname);
+
+	err = -EAGAIN;
+	if (f2fs_has_inline_dentry(dir))
+		err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
+	if (err == -EAGAIN)
+		err = f2fs_add_regular_entry(dir, &new_name, inode, ino, mode);
+
 	f2fs_fname_free_filename(&fname);
 	return err;
 }
@@ -782,27 +800,28 @@
 			break;
 
 		de = &d->dentry[bit_pos];
-		if (de->file_type < F2FS_FT_MAX)
-			d_type = f2fs_filetype_table[de->file_type];
-		else
-			d_type = DT_UNKNOWN;
+		d_type = get_de_type(de);
 
 		de_name.name = d->filename[bit_pos];
 		de_name.len = le16_to_cpu(de->name_len);
 
+		/* check memory boundary before moving forward */
+		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+		if (unlikely(bit_pos > d->max ||
+				le16_to_cpu(de->name_len) > F2FS_NAME_LEN)) {
+			f2fs_msg(F2FS_I_SB(d->inode)->sb, KERN_WARNING,
+				"%s: corrupted namelen=%d, run fsck to fix.",
+				__func__, le16_to_cpu(de->name_len));
+			set_sbi_flag(F2FS_I_SB(d->inode)->sb->s_fs_info, SBI_NEED_FSCK);
+			return -EINVAL;
+		}
+
 		if (f2fs_encrypted_inode(d->inode)) {
 			int save_len = fstr->len;
 			int ret;
 
-			de_name.name = kmalloc(de_name.len, GFP_NOFS);
-			if (!de_name.name)
-				return false;
-
-			memcpy(de_name.name, d->filename[bit_pos], de_name.len);
-
 			ret = f2fs_fname_disk_to_usr(d->inode, &de->hash_code,
 							&de_name, fstr);
-			kfree(de_name.name);
 			if (ret < 0)
 				return true;
 
@@ -814,7 +833,6 @@
 					le32_to_cpu(de->ino), d_type))
 			return true;
 
-		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
 		ctx->pos = start_pos + bit_pos;
 	}
 	return false;
--- linux-4.4.0.orig/fs/f2fs/extent_cache.c
+++ linux-4.4.0/fs/f2fs/extent_cache.c
@@ -172,7 +172,7 @@
 	__drop_largest_extent(inode, fofs, 1);
 }
 
-void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
+static void __f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct extent_tree *et;
@@ -204,6 +204,14 @@
 	write_unlock(&et->lock);
 }
 
+void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
+{
+	__f2fs_init_extent_tree(inode, i_ext);
+
+	if (!F2FS_I(inode)->extent_tree)
+		set_inode_flag(F2FS_I(inode), FI_NO_EXTENT);
+}
+
 static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
 							struct extent_info *ei)
 {
--- linux-4.4.0.orig/fs/f2fs/f2fs.h
+++ linux-4.4.0/fs/f2fs/f2fs.h
@@ -135,7 +135,7 @@
 };
 
 /*
- * For CP/NAT/SIT/SSA readahead
+ * indicate meta/data type
  */
 enum {
 	META_CP,
@@ -143,6 +143,8 @@
 	META_SIT,
 	META_SSA,
 	META_POR,
+	DATA_GENERIC,
+	META_GENERIC,
 };
 
 /* for the list of ino */
@@ -684,6 +686,7 @@
 	block_t blk_addr;	/* block address to be written */
 	struct page *page;	/* page to be written */
 	struct page *encrypted_page;	/* encrypted page */
+	bool is_meta;		/* indicate borrow meta inode mapping or not */
 };
 
 #define is_read_io(rw)	(((rw) & 1) == READ)
@@ -731,6 +734,7 @@
 
 	/* for checkpoint */
 	struct f2fs_checkpoint *ckpt;		/* raw checkpoint pointer */
+	int cur_cp_pack;			/* remain current cp pack */
 	struct inode *meta_inode;		/* cache meta blocks */
 	struct mutex cp_mutex;			/* checkpoint procedure lock */
 	struct rw_semaphore cp_rwsem;		/* blocking FS operations */
@@ -1140,22 +1144,27 @@
 
 static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
 {
-	block_t start_addr;
-	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
-	unsigned long long ckpt_version = cur_cp_version(ckpt);
-
-	start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
+	block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
 
-	/*
-	 * odd numbered checkpoint should at cp segment 0
-	 * and even segment must be at cp segment 1
-	 */
-	if (!(ckpt_version & 1))
+	if (sbi->cur_cp_pack == 2)
 		start_addr += sbi->blocks_per_seg;
+	return start_addr;
+}
+
+static inline block_t __start_cp_next_addr(struct f2fs_sb_info *sbi)
+{
+	block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
 
+	if (sbi->cur_cp_pack == 1)
+		start_addr += sbi->blocks_per_seg;
 	return start_addr;
 }
 
+static inline void __set_cp_next_pack(struct f2fs_sb_info *sbi)
+{
+	sbi->cur_cp_pack = (sbi->cur_cp_pack == 1) ? 2 : 1;
+}
+
 static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi)
 {
 	return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
@@ -1402,7 +1411,6 @@
 	FI_NO_ALLOC,		/* should not allocate any blocks */
 	FI_FREE_NID,		/* free allocated nide */
 	FI_UPDATE_DIR,		/* should update inode block for consistency */
-	FI_DELAY_IPUT,		/* used for the recovery */
 	FI_NO_EXTENT,		/* not to use the extent cache */
 	FI_INLINE_XATTR,	/* used for inline xattr */
 	FI_INLINE_DATA,		/* used for inline data*/
@@ -1641,6 +1649,39 @@
 	(pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) /	\
 	ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi))
 
+#define __is_meta_io(fio) (PAGE_TYPE_OF_BIO(fio->type) == META &&	\
+				(!is_read_io(fio->rw) || fio->is_meta))
+
+bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
+					block_t blkaddr, int type);
+void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
+static inline void verify_blkaddr(struct f2fs_sb_info *sbi,
+					block_t blkaddr, int type)
+{
+	if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) {
+		f2fs_msg(sbi->sb, KERN_ERR,
+			"invalid blkaddr: %u, type: %d, run fsck to fix.",
+			blkaddr, type);
+		f2fs_bug_on(sbi, 1);
+	}
+}
+
+static inline bool __is_valid_data_blkaddr(block_t blkaddr)
+{
+	if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
+		return false;
+	return true;
+}
+
+static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi,
+						block_t blkaddr)
+{
+	if (!__is_valid_data_blkaddr(blkaddr))
+		return false;
+	verify_blkaddr(sbi, blkaddr, DATA_GENERIC);
+	return true;
+}
+
 /*
  * file.c
  */
@@ -1677,7 +1718,7 @@
  */
 extern unsigned char f2fs_filetype_table[F2FS_FT_MAX];
 void set_de_type(struct f2fs_dir_entry *, umode_t);
-
+unsigned char get_de_type(struct f2fs_dir_entry *);
 struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *,
 			f2fs_hash_t, int *, struct f2fs_dentry_ptr *);
 bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
@@ -1698,6 +1739,8 @@
 int update_dent_inode(struct inode *, struct inode *, const struct qstr *);
 void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *,
 			const struct qstr *, f2fs_hash_t , unsigned int);
+int f2fs_add_regular_entry(struct inode *, const struct qstr *,
+						struct inode *, nid_t, umode_t);
 int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t,
 			umode_t);
 void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *,
@@ -1718,11 +1761,13 @@
 int f2fs_sync_fs(struct super_block *, int);
 extern __printf(3, 4)
 void f2fs_msg(struct super_block *, const char *, const char *, ...);
+int sanity_check_ckpt(struct f2fs_sb_info *sbi);
 
 /*
  * hash.c
  */
-f2fs_hash_t f2fs_dentry_hash(const struct qstr *);
+f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info,
+				struct f2fs_filename *fname);
 
 /*
  * node.c
@@ -1777,7 +1822,6 @@
 void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t);
 void clear_prefree_segments(struct f2fs_sb_info *, struct cp_control *);
 void release_discard_addrs(struct f2fs_sb_info *);
-bool discard_next_dnode(struct f2fs_sb_info *, block_t);
 int npages_for_summary_flush(struct f2fs_sb_info *, bool);
 void allocate_new_segments(struct f2fs_sb_info *);
 int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *);
@@ -1809,7 +1853,8 @@
 struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
 struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
 struct page *get_tmp_page(struct f2fs_sb_info *, pgoff_t);
-bool is_valid_blkaddr(struct f2fs_sb_info *, block_t, int);
+bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
+					block_t blkaddr, int type);
 int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int, bool);
 void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t);
 long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
@@ -1824,7 +1869,6 @@
 int recover_orphan_inodes(struct f2fs_sb_info *);
 int get_valid_checkpoint(struct f2fs_sb_info *);
 void update_dirty_page(struct inode *, struct page *);
-void add_dirty_dir_inode(struct inode *);
 void remove_dirty_dir_inode(struct inode *);
 void sync_dirty_dir_inodes(struct f2fs_sb_info *);
 void write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
@@ -1863,7 +1907,7 @@
 /*
  * recovery.c
  */
-int recover_fsync_data(struct f2fs_sb_info *);
+int recover_fsync_data(struct f2fs_sb_info *, bool);
 bool space_for_roll_forward(struct f2fs_sb_info *);
 
 /*
@@ -2149,7 +2193,6 @@
 
 /* crypto_key.c */
 void f2fs_free_encryption_info(struct inode *, struct f2fs_crypt_info *);
-int _f2fs_get_encryption_info(struct inode *inode);
 
 /* crypto_fname.c */
 bool f2fs_valid_filenames_enc_mode(uint32_t);
@@ -2170,18 +2213,7 @@
 
 int f2fs_has_encryption_key(struct inode *);
 
-static inline int f2fs_get_encryption_info(struct inode *inode)
-{
-	struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info;
-
-	if (!ci ||
-		(ci->ci_keyring_key &&
-		 (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
-					       (1 << KEY_FLAG_REVOKED) |
-					       (1 << KEY_FLAG_DEAD)))))
-		return _f2fs_get_encryption_info(inode);
-	return 0;
-}
+int f2fs_get_encryption_info(struct inode *inode);
 
 void f2fs_fname_crypto_free_buffer(struct f2fs_str *);
 int f2fs_fname_setup_filename(struct inode *, const struct qstr *,
--- linux-4.4.0.orig/fs/f2fs/f2fs_crypto.h
+++ linux-4.4.0/fs/f2fs/f2fs_crypto.h
@@ -79,7 +79,6 @@
 	char		ci_filename_mode;
 	char		ci_flags;
 	struct crypto_ablkcipher *ci_ctfm;
-	struct key	*ci_keyring_key;
 	char		ci_master_key[F2FS_KEY_DESCRIPTOR_SIZE];
 };
 
--- linux-4.4.0.orig/fs/f2fs/file.c
+++ linux-4.4.0/fs/f2fs/file.c
@@ -200,6 +200,9 @@
 
 	trace_f2fs_sync_file_enter(inode);
 
+	if (S_ISDIR(inode->i_mode))
+		goto go_write;
+
 	/* if fdatasync is triggered, let's do in-place-update */
 	if (get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
 		set_inode_flag(fi, FI_NEED_IPU);
@@ -305,13 +308,13 @@
 	return pgofs;
 }
 
-static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
-							int whence)
+static bool __found_offset(struct f2fs_sb_info *sbi, block_t blkaddr,
+				pgoff_t dirty, pgoff_t pgofs, int whence)
 {
 	switch (whence) {
 	case SEEK_DATA:
 		if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
-			(blkaddr != NEW_ADDR && blkaddr != NULL_ADDR))
+			is_valid_data_blkaddr(sbi, blkaddr))
 			return true;
 		break;
 	case SEEK_HOLE:
@@ -374,7 +377,15 @@
 			block_t blkaddr;
 			blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
 
-			if (__found_offset(blkaddr, dirty, pgofs, whence)) {
+			if (__is_valid_data_blkaddr(blkaddr) &&
+				!f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
+						blkaddr, DATA_GENERIC)) {
+				f2fs_put_dnode(&dn);
+				goto fail;
+			}
+
+			if (__found_offset(F2FS_I_SB(inode), blkaddr, dirty,
+							pgofs, whence)) {
 				f2fs_put_dnode(&dn);
 				goto found;
 			}
@@ -466,6 +477,11 @@
 
 		dn->data_blkaddr = NULL_ADDR;
 		set_data_blkaddr(dn);
+
+		if (__is_valid_data_blkaddr(blkaddr) &&
+			!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
+			continue;
+
 		invalidate_blocks(sbi, blkaddr);
 		if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page))
 			clear_inode_flag(F2FS_I(dn->inode),
@@ -650,7 +666,8 @@
 	if (ia_valid & ATTR_MODE) {
 		umode_t mode = attr->ia_mode;
 
-		if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
+		if (!in_group_p(inode->i_gid) &&
+			!capable_wrt_inode_uidgid(inode, CAP_FSETID))
 			mode &= ~S_ISGID;
 		set_acl_inode(fi, mode);
 	}
@@ -665,7 +682,7 @@
 	struct f2fs_inode_info *fi = F2FS_I(inode);
 	int err;
 
-	err = inode_change_ok(inode, attr);
+	err = setattr_prepare(dentry, attr);
 	if (err)
 		return err;
 
@@ -1535,12 +1552,25 @@
 #ifdef CONFIG_F2FS_FS_ENCRYPTION
 	struct f2fs_encryption_policy policy;
 	struct inode *inode = file_inode(filp);
+	int err;
 
 	if (copy_from_user(&policy, (struct f2fs_encryption_policy __user *)arg,
 				sizeof(policy)))
 		return -EFAULT;
 
-	return f2fs_process_policy(&policy, inode);
+	err = mnt_want_write_file(filp);
+	if (err)
+		return err;
+
+	mutex_lock(&inode->i_mutex);
+
+	err = f2fs_process_policy(&policy, inode);
+
+	mutex_unlock(&inode->i_mutex);
+
+	mnt_drop_write_file(filp);
+
+	return err;
 #else
 	return -EOPNOTSUPP;
 #endif
--- linux-4.4.0.orig/fs/f2fs/gc.c
+++ linux-4.4.0/fs/f2fs/gc.c
@@ -522,8 +522,10 @@
 	get_node_info(sbi, nid, dni);
 
 	if (sum->version != dni->version) {
-		f2fs_put_page(node_page, 1);
-		return false;
+		f2fs_msg(sbi->sb, KERN_WARNING,
+				"%s: valid data with mismatched node version.",
+				__func__);
+		set_sbi_flag(sbi, SBI_NEED_FSCK);
 	}
 
 	*nofs = ofs_of_node(node_page);
@@ -713,6 +715,16 @@
 			if (IS_ERR(inode) || is_bad_inode(inode))
 				continue;
 
+			if (f2fs_has_inline_data(inode)) {
+				iput(inode);
+				set_sbi_flag(sbi, SBI_NEED_FSCK);
+				f2fs_msg(sbi->sb, KERN_ERR,
+					"inode %lx has both inline_data flag and "
+					"data block, nid=%u, ofs_in_node=%u",
+					inode->i_ino, dni.nid, ofs_in_node);
+				continue;
+			}
+
 			/* if encrypted inode, let's go phase 3 */
 			if (f2fs_encrypted_inode(inode) &&
 						S_ISREG(inode->i_mode)) {
@@ -878,7 +890,7 @@
 
 	put_gc_inode(&gc_list);
 
-	if (sync)
+	if (sync && !ret)
 		ret = sec_freed ? 0 : -EAGAIN;
 	return ret;
 }
--- linux-4.4.0.orig/fs/f2fs/hash.c
+++ linux-4.4.0/fs/f2fs/hash.c
@@ -70,7 +70,8 @@
 		*buf++ = pad;
 }
 
-f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info)
+f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info,
+				struct f2fs_filename *fname)
 {
 	__u32 hash;
 	f2fs_hash_t f2fs_hash;
@@ -79,6 +80,10 @@
 	const unsigned char *name = name_info->name;
 	size_t len = name_info->len;
 
+	/* encrypted bigname case */
+	if (fname && !fname->disk_name.name)
+		return cpu_to_le32(fname->hash);
+
 	if (is_dot_dotdot(name_info))
 		return 0;
 
--- linux-4.4.0.orig/fs/f2fs/inline.c
+++ linux-4.4.0/fs/f2fs/inline.c
@@ -127,6 +127,16 @@
 	if (err)
 		return err;
 
+	if (unlikely(dn->data_blkaddr != NEW_ADDR)) {
+		f2fs_put_dnode(dn);
+		set_sbi_flag(fio.sbi, SBI_NEED_FSCK);
+		f2fs_msg(fio.sbi->sb, KERN_WARNING,
+			"%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, "
+			"run fsck to fix.",
+			__func__, dn->inode->i_ino, dn->data_blkaddr);
+		return -EINVAL;
+	}
+
 	f2fs_wait_on_page_writeback(page, DATA);
 
 	if (PageUptodate(page))
@@ -303,7 +313,7 @@
 	if (IS_ERR(ipage))
 		return NULL;
 
-	namehash = f2fs_dentry_hash(&name);
+	namehash = f2fs_dentry_hash(&name, fname);
 
 	inline_dentry = inline_data_addr(ipage);
 
@@ -367,7 +377,7 @@
  * NOTE: ipage is grabbed by caller, but if any error occurs, we should
  * release ipage in this function.
  */
-static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
+static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
 				struct f2fs_inline_dentry *inline_dentry)
 {
 	struct page *page;
@@ -386,6 +396,17 @@
 	if (err)
 		goto out;
 
+	if (unlikely(dn.data_blkaddr != NEW_ADDR)) {
+		f2fs_put_dnode(&dn);
+		set_sbi_flag(F2FS_P_SB(page), SBI_NEED_FSCK);
+		f2fs_msg(F2FS_P_SB(page)->sb, KERN_WARNING,
+			"%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, "
+			"run fsck to fix.",
+			__func__, dir->i_ino, dn.data_blkaddr);
+		err = -EINVAL;
+		goto out;
+	}
+
 	f2fs_wait_on_page_writeback(page, DATA);
 	zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
 
@@ -428,6 +449,98 @@
 	return err;
 }
 
+static int f2fs_add_inline_entries(struct inode *dir,
+			struct f2fs_inline_dentry *inline_dentry)
+{
+	struct f2fs_dentry_ptr d;
+	unsigned long bit_pos = 0;
+	int err = 0;
+
+	make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2);
+
+	while (bit_pos < d.max) {
+		struct f2fs_dir_entry *de;
+		struct qstr new_name;
+		nid_t ino;
+		umode_t fake_mode;
+
+		if (!test_bit_le(bit_pos, d.bitmap)) {
+			bit_pos++;
+			continue;
+		}
+
+		de = &d.dentry[bit_pos];
+		new_name.name = d.filename[bit_pos];
+		new_name.len = de->name_len;
+
+		ino = le32_to_cpu(de->ino);
+		fake_mode = get_de_type(de) << S_SHIFT;
+
+		err = f2fs_add_regular_entry(dir, &new_name, NULL,
+							ino, fake_mode);
+		if (err)
+			goto punch_dentry_pages;
+
+		if (unlikely(!de->name_len))
+			d.max = -1;
+
+		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+	}
+	return 0;
+punch_dentry_pages:
+	truncate_inode_pages(&dir->i_data, 0);
+	truncate_blocks(dir, 0, false);
+	remove_dirty_dir_inode(dir);
+	return err;
+}
+
+static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
+				struct f2fs_inline_dentry *inline_dentry)
+{
+	struct f2fs_inline_dentry *backup_dentry;
+	int err;
+
+	backup_dentry = kmalloc(sizeof(struct f2fs_inline_dentry),
+							GFP_F2FS_ZERO);
+	if (!backup_dentry)
+		return -ENOMEM;
+
+	memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA);
+	truncate_inline_inode(ipage, 0);
+
+	unlock_page(ipage);
+
+	err = f2fs_add_inline_entries(dir, backup_dentry);
+	if (err)
+		goto recover;
+
+	lock_page(ipage);
+
+	stat_dec_inline_dir(dir);
+	clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY);
+	update_inode(dir, ipage);
+	kfree(backup_dentry);
+	return 0;
+recover:
+	lock_page(ipage);
+	memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA);
+	i_size_write(dir, MAX_INLINE_DATA);
+	update_inode(dir, ipage);
+	f2fs_put_page(ipage, 1);
+
+	kfree(backup_dentry);
+	return err;
+}
+
+static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
+				struct f2fs_inline_dentry *inline_dentry)
+{
+	if (!F2FS_I(dir)->i_dir_level)
+		return f2fs_move_inline_dirents(dir, ipage, inline_dentry);
+	else
+		return f2fs_move_rehashed_dirents(dir, ipage, inline_dentry);
+}
+
 int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
 			struct inode *inode, nid_t ino, umode_t mode)
 {
@@ -468,7 +581,7 @@
 
 	f2fs_wait_on_page_writeback(ipage, NODE);
 
-	name_hash = f2fs_dentry_hash(name);
+	name_hash = f2fs_dentry_hash(name, NULL);
 	make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2);
 	f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos);
 
--- linux-4.4.0.orig/fs/f2fs/inode.c
+++ linux-4.4.0/fs/f2fs/inode.c
@@ -50,13 +50,16 @@
 	}
 }
 
-static bool __written_first_block(struct f2fs_inode *ri)
+static int __written_first_block(struct f2fs_sb_info *sbi,
+					struct f2fs_inode *ri)
 {
 	block_t addr = le32_to_cpu(ri->i_addr[0]);
 
-	if (addr != NEW_ADDR && addr != NULL_ADDR)
-		return true;
-	return false;
+	if (!__is_valid_data_blkaddr(addr))
+		return 1;
+	if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC))
+		return -EFAULT;
+	return 0;
 }
 
 static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
@@ -94,12 +97,57 @@
 	return;
 }
 
+static bool sanity_check_inode(struct inode *inode, struct page *node_page)
+{
+	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+	unsigned long long iblocks;
+
+	iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks);
+	if (!iblocks) {
+		set_sbi_flag(sbi, SBI_NEED_FSCK);
+		f2fs_msg(sbi->sb, KERN_WARNING,
+			"%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, "
+			"run fsck to fix.",
+			__func__, inode->i_ino, iblocks);
+		return false;
+	}
+
+	if (ino_of_node(node_page) != nid_of_node(node_page)) {
+		set_sbi_flag(sbi, SBI_NEED_FSCK);
+		f2fs_msg(sbi->sb, KERN_WARNING,
+			"%s: corrupted inode footer i_ino=%lx, ino,nid: "
+			"[%u, %u] run fsck to fix.",
+			__func__, inode->i_ino,
+			ino_of_node(node_page), nid_of_node(node_page));
+		return false;
+	}
+
+	if (F2FS_I(inode)->extent_tree) {
+		struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;
+
+		if (ei->len &&
+			(!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC) ||
+			!f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
+							DATA_GENERIC))) {
+			set_sbi_flag(sbi, SBI_NEED_FSCK);
+			f2fs_msg(sbi->sb, KERN_WARNING,
+				"%s: inode (ino=%lx) extent info [%u, %u, %u] "
+				"is incorrect, run fsck to fix",
+				__func__, inode->i_ino,
+				ei->blk, ei->fofs, ei->len);
+			return false;
+		}
+	}
+	return true;
+}
+
 static int do_read_inode(struct inode *inode)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct f2fs_inode_info *fi = F2FS_I(inode);
 	struct page *node_page;
 	struct f2fs_inode *ri;
+	int err;
 
 	/* Check if ino is within scope */
 	if (check_nid_range(sbi, inode->i_ino)) {
@@ -142,6 +190,11 @@
 
 	get_inline_info(fi, ri);
 
+	if (!sanity_check_inode(inode, node_page)) {
+		f2fs_put_page(node_page, 1);
+		return -EINVAL;
+	}
+
 	/* check data exist */
 	if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
 		__recover_inline_status(inode, node_page);
@@ -149,7 +202,12 @@
 	/* get rdev by using inline_info */
 	__get_inode_rdev(inode, ri);
 
-	if (__written_first_block(ri))
+	err = __written_first_block(sbi, ri);
+	if (err < 0) {
+		f2fs_put_page(node_page, 1);
+		return err;
+	}
+	if (!err)
 		set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
 
 	f2fs_put_page(node_page, 1);
@@ -202,6 +260,7 @@
 			inode->i_op = &f2fs_encrypted_symlink_inode_operations;
 		else
 			inode->i_op = &f2fs_symlink_inode_operations;
+		inode_nohighmem(inode);
 		inode->i_mapping->a_ops = &f2fs_dblock_aops;
 	} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
 			S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
--- linux-4.4.0.orig/fs/f2fs/namei.c
+++ linux-4.4.0/fs/f2fs/namei.c
@@ -150,8 +150,7 @@
 
 	alloc_nid_done(sbi, ino);
 
-	d_instantiate(dentry, inode);
-	unlock_new_inode(inode);
+	d_instantiate_new(dentry, inode);
 
 	if (IS_DIRSYNC(dir))
 		f2fs_sync_fs(sbi->sb, 1);
@@ -170,7 +169,7 @@
 
 	if (f2fs_encrypted_inode(dir) &&
 		!f2fs_is_child_context_consistent_with_parent(dir, inode))
-		return -EPERM;
+		return -EXDEV;
 
 	f2fs_balance_fs(sbi);
 
@@ -351,6 +350,7 @@
 		inode->i_op = &f2fs_encrypted_symlink_inode_operations;
 	else
 		inode->i_op = &f2fs_symlink_inode_operations;
+	inode_nohighmem(inode);
 	inode->i_mapping->a_ops = &f2fs_dblock_aops;
 
 	f2fs_lock_op(sbi);
@@ -398,8 +398,7 @@
 	err = page_symlink(inode, p_str, p_len);
 
 err_out:
-	d_instantiate(dentry, inode);
-	unlock_new_inode(inode);
+	d_instantiate_new(dentry, inode);
 
 	/*
 	 * Let's flush symlink data in order to avoid broken symlink as much as
@@ -453,8 +452,7 @@
 
 	alloc_nid_done(sbi, inode->i_ino);
 
-	d_instantiate(dentry, inode);
-	unlock_new_inode(inode);
+	d_instantiate_new(dentry, inode);
 
 	if (IS_DIRSYNC(dir))
 		f2fs_sync_fs(sbi->sb, 1);
@@ -498,8 +496,7 @@
 
 	alloc_nid_done(sbi, inode->i_ino);
 
-	d_instantiate(dentry, inode);
-	unlock_new_inode(inode);
+	d_instantiate_new(dentry, inode);
 
 	if (IS_DIRSYNC(dir))
 		f2fs_sync_fs(sbi->sb, 1);
@@ -600,7 +597,7 @@
 	if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) &&
 		!f2fs_is_child_context_consistent_with_parent(new_dir,
 							old_inode)) {
-		err = -EPERM;
+		err = -EXDEV;
 		goto out;
 	}
 
@@ -702,7 +699,7 @@
 	}
 
 	if (old_dir_entry) {
-		if (old_dir != new_dir && !whiteout) {
+		if (old_dir != new_dir) {
 			f2fs_set_link(old_inode, old_dir_entry,
 						old_dir_page, new_dir);
 			update_inode_page(old_inode);
@@ -761,7 +758,7 @@
 								old_inode) ||
 		!f2fs_is_child_context_consistent_with_parent(old_dir,
 								new_inode)))
-		return -EPERM;
+		return -EXDEV;
 
 	f2fs_balance_fs(sbi);
 
@@ -942,7 +939,7 @@
 	cpage = read_mapping_page(inode->i_mapping, 0, NULL);
 	if (IS_ERR(cpage))
 		return ERR_CAST(cpage);
-	caddr = kmap(cpage);
+	caddr = page_address(cpage);
 	caddr[size] = 0;
 
 	/* Symlink is encrypted */
@@ -982,13 +979,11 @@
 	/* Null-terminate the name */
 	paddr[res] = '\0';
 
-	kunmap(cpage);
 	page_cache_release(cpage);
 	return *cookie = paddr;
 errout:
 	kfree(cstr.name);
 	f2fs_fname_crypto_free_buffer(&pstr);
-	kunmap(cpage);
 	page_cache_release(cpage);
 	return ERR_PTR(res);
 }
--- linux-4.4.0.orig/fs/f2fs/node.c
+++ linux-4.4.0/fs/f2fs/node.c
@@ -261,13 +261,11 @@
 {
 	struct nat_entry *e;
 
-	down_write(&nm_i->nat_tree_lock);
 	e = __lookup_nat_cache(nm_i, nid);
 	if (!e) {
 		e = grab_nat_entry(nm_i, nid);
 		node_info_from_raw_nat(&e->ni, ne);
 	}
-	up_write(&nm_i->nat_tree_lock);
 }
 
 static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
@@ -298,8 +296,7 @@
 			new_blkaddr == NULL_ADDR);
 	f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
 			new_blkaddr == NEW_ADDR);
-	f2fs_bug_on(sbi, nat_get_blkaddr(e) != NEW_ADDR &&
-			nat_get_blkaddr(e) != NULL_ADDR &&
+	f2fs_bug_on(sbi, is_valid_data_blkaddr(sbi, nat_get_blkaddr(e)) &&
 			new_blkaddr == NEW_ADDR);
 
 	/* increment version no as node is removed */
@@ -314,7 +311,7 @@
 
 	/* change address */
 	nat_set_blkaddr(e, new_blkaddr);
-	if (new_blkaddr == NEW_ADDR || new_blkaddr == NULL_ADDR)
+	if (!is_valid_data_blkaddr(sbi, new_blkaddr))
 		set_nat_flag(e, IS_CHECKPOINTED, false);
 	__set_nat_cache_dirty(nm_i, e);
 
@@ -379,6 +376,8 @@
 
 	memset(&ne, 0, sizeof(struct f2fs_nat_entry));
 
+	down_write(&nm_i->nat_tree_lock);
+
 	/* Check current segment summary */
 	mutex_lock(&curseg->curseg_mutex);
 	i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0);
@@ -399,6 +398,7 @@
 cache:
 	/* cache nat entry */
 	cache_nat_entry(NM_I(sbi), nid, &ne);
+	up_write(&nm_i->nat_tree_lock);
 }
 
 /*
@@ -590,6 +590,7 @@
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
 	struct node_info ni;
+	pgoff_t index;
 
 	get_node_info(sbi, dn->nid, &ni);
 	if (dn->inode->i_blocks == 0) {
@@ -613,10 +614,11 @@
 	clear_node_page_dirty(dn->node_page);
 	set_sbi_flag(sbi, SBI_IS_DIRTY);
 
+	index = dn->node_page->index;
 	f2fs_put_page(dn->node_page, 1);
 
 	invalidate_mapping_pages(NODE_MAPPING(sbi),
-			dn->node_page->index, dn->node_page->index);
+			index, index);
 
 	dn->node_page = NULL;
 	trace_f2fs_truncate_node(dn->inode, dn->nid, ni.blk_addr);
@@ -1341,6 +1343,12 @@
 		return 0;
 	}
 
+	if (__is_valid_data_blkaddr(ni.blk_addr) &&
+		!f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) {
+		up_read(&sbi->node_write);
+		goto redirty_out;
+	}
+
 	set_page_writeback(page);
 	fio.blk_addr = ni.blk_addr;
 	write_node_page(nid, &fio);
@@ -1427,9 +1435,9 @@
 static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
 {
 	struct f2fs_nm_info *nm_i = NM_I(sbi);
-	struct free_nid *i;
+	struct free_nid *i, *e;
 	struct nat_entry *ne;
-	bool allocated = false;
+	int err = -EINVAL;
 
 	if (!available_free_memory(sbi, FREE_NIDS))
 		return -1;
@@ -1438,40 +1446,58 @@
 	if (unlikely(nid == 0))
 		return 0;
 
-	if (build) {
-		/* do not add allocated nids */
-		down_read(&nm_i->nat_tree_lock);
-		ne = __lookup_nat_cache(nm_i, nid);
-		if (ne &&
-			(!get_nat_flag(ne, IS_CHECKPOINTED) ||
-				nat_get_blkaddr(ne) != NULL_ADDR))
-			allocated = true;
-		up_read(&nm_i->nat_tree_lock);
-		if (allocated)
-			return 0;
-	}
-
 	i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
 	i->nid = nid;
 	i->state = NID_NEW;
 
-	if (radix_tree_preload(GFP_NOFS)) {
-		kmem_cache_free(free_nid_slab, i);
-		return 0;
-	}
+	if (radix_tree_preload(GFP_NOFS))
+		goto err;
 
 	spin_lock(&nm_i->free_nid_list_lock);
-	if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i)) {
-		spin_unlock(&nm_i->free_nid_list_lock);
-		radix_tree_preload_end();
-		kmem_cache_free(free_nid_slab, i);
-		return 0;
-	}
+
+	if (build) {
+		/*
+		 *   Thread A             Thread B
+		 *  - f2fs_create
+		 *   - f2fs_new_inode
+		 *    - alloc_nid
+		 *     - __insert_nid_to_list(ALLOC_NID_LIST)
+		 *                     - f2fs_balance_fs_bg
+		 *                      - build_free_nids
+		 *                       - __build_free_nids
+		 *                        - scan_nat_page
+		 *                         - add_free_nid
+		 *                          - __lookup_nat_cache
+		 *  - f2fs_add_link
+		 *   - init_inode_metadata
+		 *    - new_inode_page
+		 *     - new_node_page
+		 *      - set_node_addr
+		 *  - alloc_nid_done
+		 *   - __remove_nid_from_list(ALLOC_NID_LIST)
+		 *                         - __insert_nid_to_list(FREE_NID_LIST)
+		 */
+		ne = __lookup_nat_cache(nm_i, nid);
+		if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
+				nat_get_blkaddr(ne) != NULL_ADDR))
+			goto err_out;
+
+		e = __lookup_free_nid_list(nm_i, nid);
+		if (e)
+			goto err_out;
+	}
+	if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i))
+		goto err_out;
+	err = 0;
 	list_add_tail(&i->list, &nm_i->free_nid_list);
 	nm_i->fcnt++;
+err_out:
 	spin_unlock(&nm_i->free_nid_list_lock);
 	radix_tree_preload_end();
-	return 1;
+err:
+	if (err)
+		kmem_cache_free(free_nid_slab, i);
+	return !err;
 }
 
 static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
@@ -1532,6 +1558,8 @@
 	ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES,
 							META_NAT, true);
 
+	down_read(&nm_i->nat_tree_lock);
+
 	while (1) {
 		struct page *page = get_current_nat_page(sbi, nid);
 
@@ -1560,6 +1588,7 @@
 			remove_free_nid(nm_i, nid);
 	}
 	mutex_unlock(&curseg->curseg_mutex);
+	up_read(&nm_i->nat_tree_lock);
 
 	ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
 					nm_i->ra_nid_pages, META_NAT, false);
@@ -1840,16 +1869,17 @@
 		struct f2fs_nat_entry raw_ne;
 		nid_t nid = le32_to_cpu(nid_in_journal(sum, i));
 
+		if (check_nid_range(sbi, nid))
+			continue;
+
 		raw_ne = nat_in_journal(sum, i);
 
-		down_write(&nm_i->nat_tree_lock);
 		ne = __lookup_nat_cache(nm_i, nid);
 		if (!ne) {
 			ne = grab_nat_entry(nm_i, nid);
 			node_info_from_raw_nat(&ne->ni, &raw_ne);
 		}
 		__set_nat_cache_dirty(nm_i, ne);
-		up_write(&nm_i->nat_tree_lock);
 	}
 	update_nats_in_cursum(sum, -i);
 	mutex_unlock(&curseg->curseg_mutex);
@@ -1883,7 +1913,6 @@
 	struct f2fs_nat_block *nat_blk;
 	struct nat_entry *ne, *cur;
 	struct page *page = NULL;
-	struct f2fs_nm_info *nm_i = NM_I(sbi);
 
 	/*
 	 * there are two steps to flush nat entries:
@@ -1920,12 +1949,8 @@
 			raw_ne = &nat_blk->entries[nid - start_nid];
 		}
 		raw_nat_from_node_info(raw_ne, &ne->ni);
-
-		down_write(&NM_I(sbi)->nat_tree_lock);
 		nat_reset_flag(ne);
 		__clear_nat_cache_dirty(NM_I(sbi), ne);
-		up_write(&NM_I(sbi)->nat_tree_lock);
-
 		if (nat_get_blkaddr(ne) == NULL_ADDR)
 			add_free_nid(sbi, nid, false);
 	}
@@ -1937,9 +1962,7 @@
 
 	f2fs_bug_on(sbi, set->entry_cnt);
 
-	down_write(&nm_i->nat_tree_lock);
 	radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
-	up_write(&nm_i->nat_tree_lock);
 	kmem_cache_free(nat_entry_set_slab, set);
 }
 
@@ -1959,6 +1982,9 @@
 
 	if (!nm_i->dirty_nat_cnt)
 		return;
+
+	down_write(&nm_i->nat_tree_lock);
+
 	/*
 	 * if there are no enough space in journal to store dirty nat
 	 * entries, remove all entries from journal and merge them
@@ -1967,7 +1993,6 @@
 	if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL))
 		remove_nats_in_journal(sbi);
 
-	down_write(&nm_i->nat_tree_lock);
 	while ((found = __gang_lookup_nat_set(nm_i,
 					set_idx, SETVEC_SIZE, setvec))) {
 		unsigned idx;
@@ -1976,12 +2001,13 @@
 			__adjust_nat_entry_set(setvec[idx], &sets,
 							MAX_NAT_JENTRIES(sum));
 	}
-	up_write(&nm_i->nat_tree_lock);
 
 	/* flush dirty nats in nat entry set */
 	list_for_each_entry_safe(set, tmp, &sets, set_list)
 		__flush_nat_entry_set(sbi, set);
 
+	up_write(&nm_i->nat_tree_lock);
+
 	f2fs_bug_on(sbi, nm_i->dirty_nat_cnt);
 }
 
--- linux-4.4.0.orig/fs/f2fs/node.h
+++ linux-4.4.0/fs/f2fs/node.h
@@ -212,6 +212,37 @@
 	f2fs_change_bit(block_off, nm_i->nat_bitmap);
 }
 
+static inline nid_t ino_of_node(struct page *node_page)
+{
+	struct f2fs_node *rn = F2FS_NODE(node_page);
+	return le32_to_cpu(rn->footer.ino);
+}
+
+static inline nid_t nid_of_node(struct page *node_page)
+{
+	struct f2fs_node *rn = F2FS_NODE(node_page);
+	return le32_to_cpu(rn->footer.nid);
+}
+
+static inline unsigned int ofs_of_node(struct page *node_page)
+{
+	struct f2fs_node *rn = F2FS_NODE(node_page);
+	unsigned flag = le32_to_cpu(rn->footer.flag);
+	return flag >> OFFSET_BIT_SHIFT;
+}
+
+static inline __u64 cpver_of_node(struct page *node_page)
+{
+	struct f2fs_node *rn = F2FS_NODE(node_page);
+	return le64_to_cpu(rn->footer.cp_ver);
+}
+
+static inline block_t next_blkaddr_of_node(struct page *node_page)
+{
+	struct f2fs_node *rn = F2FS_NODE(node_page);
+	return le32_to_cpu(rn->footer.next_blkaddr);
+}
+
 static inline void fill_node_footer(struct page *page, nid_t nid,
 				nid_t ino, unsigned int ofs, bool reset)
 {
@@ -242,40 +273,30 @@
 {
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page));
 	struct f2fs_node *rn = F2FS_NODE(page);
+	size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
+	__u64 cp_ver = le64_to_cpu(ckpt->checkpoint_ver);
 
-	rn->footer.cp_ver = ckpt->checkpoint_ver;
+	if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
+		__u64 crc = le32_to_cpu(*((__le32 *)
+				((unsigned char *)ckpt + crc_offset)));
+		cp_ver |= (crc << 32);
+	}
+	rn->footer.cp_ver = cpu_to_le64(cp_ver);
 	rn->footer.next_blkaddr = cpu_to_le32(blkaddr);
 }
 
-static inline nid_t ino_of_node(struct page *node_page)
-{
-	struct f2fs_node *rn = F2FS_NODE(node_page);
-	return le32_to_cpu(rn->footer.ino);
-}
-
-static inline nid_t nid_of_node(struct page *node_page)
-{
-	struct f2fs_node *rn = F2FS_NODE(node_page);
-	return le32_to_cpu(rn->footer.nid);
-}
-
-static inline unsigned int ofs_of_node(struct page *node_page)
-{
-	struct f2fs_node *rn = F2FS_NODE(node_page);
-	unsigned flag = le32_to_cpu(rn->footer.flag);
-	return flag >> OFFSET_BIT_SHIFT;
-}
-
-static inline unsigned long long cpver_of_node(struct page *node_page)
+static inline bool is_recoverable_dnode(struct page *page)
 {
-	struct f2fs_node *rn = F2FS_NODE(node_page);
-	return le64_to_cpu(rn->footer.cp_ver);
-}
+	struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page));
+	size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
+	__u64 cp_ver = cur_cp_version(ckpt);
 
-static inline block_t next_blkaddr_of_node(struct page *node_page)
-{
-	struct f2fs_node *rn = F2FS_NODE(node_page);
-	return le32_to_cpu(rn->footer.next_blkaddr);
+	if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
+		__u64 crc = le32_to_cpu(*((__le32 *)
+				((unsigned char *)ckpt + crc_offset)));
+		cp_ver |= (crc << 32);
+	}
+	return cpu_to_le64(cp_ver) == cpver_of_node(page);
 }
 
 /*
--- linux-4.4.0.orig/fs/f2fs/recovery.c
+++ linux-4.4.0/fs/f2fs/recovery.c
@@ -67,7 +67,30 @@
 	return NULL;
 }
 
-static int recover_dentry(struct inode *inode, struct page *ipage)
+static struct fsync_inode_entry *add_fsync_inode(struct list_head *head,
+							struct inode *inode)
+{
+	struct fsync_inode_entry *entry;
+
+	entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO);
+	if (!entry)
+		return NULL;
+
+	entry->inode = inode;
+	list_add_tail(&entry->list, head);
+
+	return entry;
+}
+
+static void del_fsync_inode(struct fsync_inode_entry *entry)
+{
+	iput(entry->inode);
+	list_del(&entry->list);
+	kmem_cache_free(fsync_entry_slab, entry);
+}
+
+static int recover_dentry(struct inode *inode, struct page *ipage,
+						struct list_head *dir_list)
 {
 	struct f2fs_inode *raw_inode = F2FS_INODE(ipage);
 	nid_t pino = le32_to_cpu(raw_inode->i_pino);
@@ -75,18 +98,29 @@
 	struct qstr name;
 	struct page *page;
 	struct inode *dir, *einode;
+	struct fsync_inode_entry *entry;
 	int err = 0;
 
-	dir = f2fs_iget(inode->i_sb, pino);
-	if (IS_ERR(dir)) {
-		err = PTR_ERR(dir);
-		goto out;
+	entry = get_fsync_inode(dir_list, pino);
+	if (!entry) {
+		dir = f2fs_iget(inode->i_sb, pino);
+		if (IS_ERR(dir)) {
+			err = PTR_ERR(dir);
+			goto out;
+		}
+
+		entry = add_fsync_inode(dir_list, dir);
+		if (!entry) {
+			err = -ENOMEM;
+			iput(dir);
+			goto out;
+		}
 	}
 
-	if (file_enc_name(inode)) {
-		iput(dir);
+	dir = entry->inode;
+
+	if (file_enc_name(inode))
 		return 0;
-	}
 
 	name.len = le32_to_cpu(raw_inode->i_namelen);
 	name.name = raw_inode->i_name;
@@ -94,7 +128,7 @@
 	if (unlikely(name.len > F2FS_NAME_LEN)) {
 		WARN_ON(1);
 		err = -ENAMETOOLONG;
-		goto out_err;
+		goto out;
 	}
 retry:
 	de = f2fs_find_entry(dir, &name, &page);
@@ -120,23 +154,12 @@
 		goto retry;
 	}
 	err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode);
-	if (err)
-		goto out_err;
-
-	if (is_inode_flag_set(F2FS_I(dir), FI_DELAY_IPUT)) {
-		iput(dir);
-	} else {
-		add_dirty_dir_inode(dir);
-		set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT);
-	}
 
 	goto out;
 
 out_unmap_put:
 	f2fs_dentry_kunmap(dir, page);
 	f2fs_put_page(page, 0);
-out_err:
-	iput(dir);
 out:
 	f2fs_msg(inode->i_sb, KERN_NOTICE,
 			"%s: ino = %x, name = %s, dir = %lx, err = %d",
@@ -170,8 +193,8 @@
 
 static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
 {
-	unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
 	struct curseg_info *curseg;
+	struct inode *inode;
 	struct page *page = NULL;
 	block_t blkaddr;
 	int err = 0;
@@ -185,12 +208,12 @@
 	while (1) {
 		struct fsync_inode_entry *entry;
 
-		if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
+		if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
 			return 0;
 
 		page = get_tmp_page(sbi, blkaddr);
 
-		if (cp_ver != cpver_of_node(page))
+		if (!is_recoverable_dnode(page))
 			break;
 
 		if (!is_fsync_dnode(page))
@@ -204,27 +227,27 @@
 					break;
 			}
 
-			/* add this fsync inode to the list */
-			entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO);
-			if (!entry) {
-				err = -ENOMEM;
-				break;
-			}
 			/*
 			 * CP | dnode(F) | inode(DF)
 			 * For this case, we should not give up now.
 			 */
-			entry->inode = f2fs_iget(sbi->sb, ino_of_node(page));
-			if (IS_ERR(entry->inode)) {
-				err = PTR_ERR(entry->inode);
-				kmem_cache_free(fsync_entry_slab, entry);
+			inode = f2fs_iget(sbi->sb, ino_of_node(page));
+			if (IS_ERR(inode)) {
+				err = PTR_ERR(inode);
 				if (err == -ENOENT) {
 					err = 0;
 					goto next;
 				}
 				break;
 			}
-			list_add_tail(&entry->list, head);
+
+			/* add this fsync inode to the list */
+			entry = add_fsync_inode(head, inode);
+			if (!entry) {
+				err = -ENOMEM;
+				iput(inode);
+				break;
+			}
 		}
 		entry->blkaddr = blkaddr;
 
@@ -248,11 +271,8 @@
 {
 	struct fsync_inode_entry *entry, *tmp;
 
-	list_for_each_entry_safe(entry, tmp, head, list) {
-		iput(entry->inode);
-		list_del(&entry->list);
-		kmem_cache_free(fsync_entry_slab, entry);
-	}
+	list_for_each_entry_safe(entry, tmp, head, list)
+		del_fsync_inode(entry);
 }
 
 static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
@@ -276,7 +296,7 @@
 		return 0;
 
 	/* Get the previous summary */
-	for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) {
+	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
 		struct curseg_info *curseg = CURSEG_I(sbi, i);
 		if (curseg->segno == segno) {
 			sum = curseg->sum_blk->entries[blkoff];
@@ -393,7 +413,15 @@
 
 	get_node_info(sbi, dn.nid, &ni);
 	f2fs_bug_on(sbi, ni.ino != ino_of_node(page));
-	f2fs_bug_on(sbi, ofs_of_node(dn.node_page) != ofs_of_node(page));
+
+	if (ofs_of_node(dn.node_page) != ofs_of_node(page)) {
+		f2fs_msg(sbi->sb, KERN_WARNING,
+			"Inconsistent ofs_of_node, ino:%lu, ofs:%u, %u",
+			inode->i_ino, ofs_of_node(dn.node_page),
+			ofs_of_node(page));
+		err = -EFAULT;
+		goto err;
+	}
 
 	for (; start < end; start++, dn.ofs_in_node++) {
 		block_t src, dest;
@@ -423,7 +451,7 @@
 		}
 
 		/* dest is valid block, try to recover from src to dest */
-		if (is_valid_blkaddr(sbi, dest, META_POR)) {
+		if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
 
 			if (src == NULL_ADDR) {
 				err = reserve_new_block(&dn);
@@ -459,35 +487,34 @@
 	return err;
 }
 
-static int recover_data(struct f2fs_sb_info *sbi,
-				struct list_head *head, int type)
+static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
+						struct list_head *dir_list)
 {
-	unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
 	struct curseg_info *curseg;
 	struct page *page = NULL;
 	int err = 0;
 	block_t blkaddr;
 
 	/* get node pages in the current segment */
-	curseg = CURSEG_I(sbi, type);
+	curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
 	blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
 
 	while (1) {
 		struct fsync_inode_entry *entry;
 
-		if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
+		if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
 			break;
 
 		ra_meta_pages_cond(sbi, blkaddr);
 
 		page = get_tmp_page(sbi, blkaddr);
 
-		if (cp_ver != cpver_of_node(page)) {
+		if (!is_recoverable_dnode(page)) {
 			f2fs_put_page(page, 1);
 			break;
 		}
 
-		entry = get_fsync_inode(head, ino_of_node(page));
+		entry = get_fsync_inode(inode_list, ino_of_node(page));
 		if (!entry)
 			goto next;
 		/*
@@ -498,7 +525,7 @@
 		if (entry->last_inode == blkaddr)
 			recover_inode(entry->inode, page);
 		if (entry->last_dentry == blkaddr) {
-			err = recover_dentry(entry->inode, page);
+			err = recover_dentry(entry->inode, page, dir_list);
 			if (err) {
 				f2fs_put_page(page, 1);
 				break;
@@ -510,11 +537,8 @@
 			break;
 		}
 
-		if (entry->blkaddr == blkaddr) {
-			iput(entry->inode);
-			list_del(&entry->list);
-			kmem_cache_free(fsync_entry_slab, entry);
-		}
+		if (entry->blkaddr == blkaddr)
+			del_fsync_inode(entry);
 next:
 		/* check next segment */
 		blkaddr = next_blkaddr_of_node(page);
@@ -525,12 +549,14 @@
 	return err;
 }
 
-int recover_fsync_data(struct f2fs_sb_info *sbi)
+int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
 {
 	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
 	struct list_head inode_list;
+	struct list_head dir_list;
 	block_t blkaddr;
 	int err;
+	int ret = 0;
 	bool need_writecp = false;
 
 	fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
@@ -539,6 +565,7 @@
 		return -ENOMEM;
 
 	INIT_LIST_HEAD(&inode_list);
+	INIT_LIST_HEAD(&dir_list);
 
 	/* prevent checkpoint */
 	mutex_lock(&sbi->cp_mutex);
@@ -547,21 +574,22 @@
 
 	/* step #1: find fsynced inode numbers */
 	err = find_fsync_dnodes(sbi, &inode_list);
-	if (err)
+	if (err || list_empty(&inode_list))
 		goto out;
 
-	if (list_empty(&inode_list))
+	if (check_only) {
+		ret = 1;
 		goto out;
+	}
 
 	need_writecp = true;
 
 	/* step #2: recover data */
-	err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
+	err = recover_data(sbi, &inode_list, &dir_list);
 	if (!err)
 		f2fs_bug_on(sbi, !list_empty(&inode_list));
 out:
 	destroy_fsync_dnodes(&inode_list);
-	kmem_cache_destroy(fsync_entry_slab);
 
 	/* truncate meta pages to be used by the recovery */
 	truncate_inode_pages_range(META_MAPPING(sbi),
@@ -573,31 +601,20 @@
 	}
 
 	clear_sbi_flag(sbi, SBI_POR_DOING);
-	if (err) {
-		bool invalidate = false;
-
-		if (discard_next_dnode(sbi, blkaddr))
-			invalidate = true;
+	if (err)
+		set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
+	mutex_unlock(&sbi->cp_mutex);
 
-		/* Flush all the NAT/SIT pages */
-		while (get_pages(sbi, F2FS_DIRTY_META))
-			sync_meta_pages(sbi, META, LONG_MAX);
-
-		/* invalidate temporary meta page */
-		if (invalidate)
-			invalidate_mapping_pages(META_MAPPING(sbi),
-							blkaddr, blkaddr);
+	/* let's drop all the directory inodes for clean checkpoint */
+	destroy_fsync_dnodes(&dir_list);
 
-		set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
-		mutex_unlock(&sbi->cp_mutex);
-	} else if (need_writecp) {
+	if (!err && need_writecp) {
 		struct cp_control cpc = {
 			.reason = CP_RECOVERY,
 		};
-		mutex_unlock(&sbi->cp_mutex);
 		write_checkpoint(sbi, &cpc);
-	} else {
-		mutex_unlock(&sbi->cp_mutex);
 	}
-	return err;
+
+	kmem_cache_destroy(fsync_entry_slab);
+	return ret ? ret: err;
 }
--- linux-4.4.0.orig/fs/f2fs/segment.c
+++ linux-4.4.0/fs/f2fs/segment.c
@@ -295,6 +295,9 @@
 
 void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
 {
+	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
+		return;
+
 	/* try to shrink extent cache when there is no enough memory */
 	if (!available_free_memory(sbi, EXTENT_CACHE))
 		f2fs_shrink_extent_tree(sbi, EXTENT_CACHE_SHRINK_NUMBER);
@@ -395,6 +398,9 @@
 	init_waitqueue_head(&fcc->flush_wait_queue);
 	init_llist_head(&fcc->issue_list);
 	SM_I(sbi)->cmd_control_info = fcc;
+	if (!test_opt(sbi, FLUSH_MERGE))
+		return err;
+
 	fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
 				"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
 	if (IS_ERR(fcc->f2fs_issue_flush)) {
@@ -513,28 +519,6 @@
 	return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
 }
 
-bool discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr)
-{
-	int err = -ENOTSUPP;
-
-	if (test_opt(sbi, DISCARD)) {
-		struct seg_entry *se = get_seg_entry(sbi,
-				GET_SEGNO(sbi, blkaddr));
-		unsigned int offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
-
-		if (f2fs_test_bit(offset, se->discard_map))
-			return false;
-
-		err = f2fs_issue_discard(sbi, blkaddr, 1);
-	}
-
-	if (err) {
-		update_meta_page(sbi, NULL, blkaddr);
-		return true;
-	}
-	return false;
-}
-
 static void __add_discard_entry(struct f2fs_sb_info *sbi,
 		struct cp_control *cpc, struct seg_entry *se,
 		unsigned int start, unsigned int end)
@@ -768,7 +752,7 @@
 	struct seg_entry *se;
 	bool is_cp = false;
 
-	if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
+	if (!is_valid_data_blkaddr(sbi, blkaddr))
 		return true;
 
 	mutex_lock(&sit_i->sentry_lock);
@@ -1482,7 +1466,7 @@
 {
 	struct page *cpage;
 
-	if (blkaddr == NEW_ADDR)
+	if (!is_valid_data_blkaddr(sbi, blkaddr))
 		return;
 
 	f2fs_bug_on(sbi, blkaddr == NULL_ADDR);
@@ -2117,7 +2101,7 @@
 	return restore_curseg_summaries(sbi);
 }
 
-static void build_sit_entries(struct f2fs_sb_info *sbi)
+static int build_sit_entries(struct f2fs_sb_info *sbi)
 {
 	struct sit_info *sit_i = SIT_I(sbi);
 	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
@@ -2126,6 +2110,7 @@
 	unsigned int i, start, end;
 	unsigned int readed, start_blk = 0;
 	int nrpages = MAX_BIO_BLOCKS(sbi);
+	int err = 0;
 
 	do {
 		readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT, true);
@@ -2139,36 +2124,62 @@
 			struct f2fs_sit_entry sit;
 			struct page *page;
 
-			mutex_lock(&curseg->curseg_mutex);
-			for (i = 0; i < sits_in_cursum(sum); i++) {
-				if (le32_to_cpu(segno_in_journal(sum, i))
-								== start) {
-					sit = sit_in_journal(sum, i);
-					mutex_unlock(&curseg->curseg_mutex);
-					goto got_it;
-				}
-			}
-			mutex_unlock(&curseg->curseg_mutex);
-
 			page = get_current_sit_page(sbi, start);
 			sit_blk = (struct f2fs_sit_block *)page_address(page);
 			sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
 			f2fs_put_page(page, 1);
-got_it:
-			check_block_count(sbi, start, &sit);
+
+			err = check_block_count(sbi, start, &sit);
+			if (err)
+				return err;
 			seg_info_from_raw_sit(se, &sit);
 
 			/* build discard map only one time */
 			memcpy(se->discard_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
 			sbi->discard_blks += sbi->blocks_per_seg - se->valid_blocks;
 
-			if (sbi->segs_per_sec > 1) {
-				struct sec_entry *e = get_sec_entry(sbi, start);
-				e->valid_blocks += se->valid_blocks;
-			}
+			if (sbi->segs_per_sec > 1)
+				get_sec_entry(sbi, start)->valid_blocks +=
+							se->valid_blocks;
 		}
 		start_blk += readed;
 	} while (start_blk < sit_blk_cnt);
+
+	mutex_lock(&curseg->curseg_mutex);
+	for (i = 0; i < sits_in_cursum(sum); i++) {
+		struct f2fs_sit_entry sit;
+		struct seg_entry *se;
+		unsigned int old_valid_blocks;
+
+		start = le32_to_cpu(segno_in_journal(sum, i));
+		if (start >= MAIN_SEGS(sbi)) {
+			f2fs_msg(sbi->sb, KERN_ERR,
+					"Wrong journal entry on segno %u",
+					start);
+			set_sbi_flag(sbi, SBI_NEED_FSCK);
+			err = -EINVAL;
+			break;
+		}
+
+		se = &sit_i->sentries[start];
+		sit = sit_in_journal(sum, i);
+
+		old_valid_blocks = se->valid_blocks;
+
+		err = check_block_count(sbi, start, &sit);
+		if (err)
+			break;
+		seg_info_from_raw_sit(se, &sit);
+
+		memcpy(se->discard_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
+		sbi->discard_blks += old_valid_blocks - se->valid_blocks;
+
+		if (sbi->segs_per_sec > 1)
+			get_sec_entry(sbi, start)->valid_blocks +=
+				se->valid_blocks - old_valid_blocks;
+	}
+	mutex_unlock(&curseg->curseg_mutex);
+	return err;
 }
 
 static void init_free_segmap(struct f2fs_sb_info *sbi)
@@ -2251,6 +2262,41 @@
 	return init_victim_secmap(sbi);
 }
 
+static int sanity_check_curseg(struct f2fs_sb_info *sbi)
+{
+	int i;
+
+	/*
+	 * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr;
+	 * In LFS curseg, all blkaddr after .next_blkoff should be unused.
+	 */
+	for (i = 0; i < NO_CHECK_TYPE; i++) {
+		struct curseg_info *curseg = CURSEG_I(sbi, i);
+		struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
+		unsigned int blkofs = curseg->next_blkoff;
+
+		if (f2fs_test_bit(blkofs, se->cur_valid_map))
+			goto out;
+
+		if (curseg->alloc_type == SSR)
+			continue;
+
+		for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) {
+			if (!f2fs_test_bit(blkofs, se->cur_valid_map))
+				continue;
+out:
+			f2fs_msg(sbi->sb, KERN_ERR,
+				"Current segment's next free block offset is "
+				"inconsistent with bitmap, logtype:%u, "
+				"segno:%u, type:%u, next_blkoff:%u, blkofs:%u",
+				i, curseg->segno, curseg->alloc_type,
+				curseg->next_blkoff, blkofs);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
 /*
  * Update min, max modified time for cost-benefit GC algorithm
  */
@@ -2313,7 +2359,7 @@
 
 	INIT_LIST_HEAD(&sm_info->sit_entry_set);
 
-	if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) {
+	if (!f2fs_readonly(sbi->sb)) {
 		err = create_flush_cmd_control(sbi);
 		if (err)
 			return err;
@@ -2330,13 +2376,19 @@
 		return err;
 
 	/* reinit free segmap based on SIT */
-	build_sit_entries(sbi);
+	err = build_sit_entries(sbi);
+	if (err)
+		return err;
 
 	init_free_segmap(sbi);
 	err = build_dirty_segmap(sbi);
 	if (err)
 		return err;
 
+	err = sanity_check_curseg(sbi);
+	if (err)
+		return err;
+
 	init_min_max_mtime(sbi);
 	return 0;
 }
--- linux-4.4.0.orig/fs/f2fs/segment.h
+++ linux-4.4.0/fs/f2fs/segment.h
@@ -17,6 +17,9 @@
 
 #define DEF_RECLAIM_PREFREE_SEGMENTS	5	/* 5% over total segments */
 
+#define F2FS_MIN_SEGMENTS	9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */
+#define F2FS_MIN_META_SEGMENTS	8 /* SB + 2 (CP + SIT + NAT) + SSA */
+
 /* L: Logical segment # in volume, R: Relative segment # in main area */
 #define GET_L2R_SEGNO(free_i, segno)	(segno - free_i->start_segno)
 #define GET_R2L_SEGNO(free_i, segno)	(segno + free_i->start_segno)
@@ -46,13 +49,19 @@
 	 (secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno /		\
 	  sbi->segs_per_sec))	\
 
-#define MAIN_BLKADDR(sbi)	(SM_I(sbi)->main_blkaddr)
-#define SEG0_BLKADDR(sbi)	(SM_I(sbi)->seg0_blkaddr)
+#define MAIN_BLKADDR(sbi)						\
+	(SM_I(sbi) ? SM_I(sbi)->main_blkaddr : 				\
+		le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr))
+#define SEG0_BLKADDR(sbi)						\
+	(SM_I(sbi) ? SM_I(sbi)->seg0_blkaddr : 				\
+		le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment0_blkaddr))
 
 #define MAIN_SEGS(sbi)	(SM_I(sbi)->main_segments)
 #define MAIN_SECS(sbi)	(sbi->total_sections)
 
-#define TOTAL_SEGS(sbi)	(SM_I(sbi)->segment_count)
+#define TOTAL_SEGS(sbi)							\
+	(SM_I(sbi) ? SM_I(sbi)->segment_count : 				\
+		le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count))
 #define TOTAL_BLKS(sbi)	(TOTAL_SEGS(sbi) << sbi->log_blocks_per_seg)
 
 #define MAX_BLKADDR(sbi)	(SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
@@ -72,7 +81,7 @@
 	(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1))
 
 #define GET_SEGNO(sbi, blk_addr)					\
-	(((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ?		\
+	((!is_valid_data_blkaddr(sbi, blk_addr)) ?			\
 	NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),			\
 		GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
 #define GET_SECNO(sbi, segno)					\
@@ -381,6 +390,8 @@
 	if (test_and_clear_bit(segno, free_i->free_segmap)) {
 		free_i->free_segments++;
 
+		if (IS_CURSEC(sbi, secno))
+			goto skip_free;
 		next = find_next_bit(free_i->free_segmap,
 				start_segno + sbi->segs_per_sec, start_segno);
 		if (next >= start_segno + sbi->segs_per_sec) {
@@ -388,6 +399,7 @@
 				free_i->free_sections++;
 		}
 	}
+skip_free:
 	spin_unlock(&free_i->segmap_lock);
 }
 
@@ -571,19 +583,22 @@
 	f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1);
 }
 
-static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
+static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
 {
-	f2fs_bug_on(sbi, blk_addr < SEG0_BLKADDR(sbi)
-					|| blk_addr >= MAX_BLKADDR(sbi));
+	struct f2fs_sb_info *sbi = fio->sbi;
+
+	if (__is_meta_io(fio))
+		verify_blkaddr(sbi, blk_addr, META_GENERIC);
+	else
+		verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
 }
 
 /*
  * Summary block is always treated as an invalid block
  */
-static inline void check_block_count(struct f2fs_sb_info *sbi,
+static inline int check_block_count(struct f2fs_sb_info *sbi,
 		int segno, struct f2fs_sit_entry *raw_sit)
 {
-#ifdef CONFIG_F2FS_CHECK_FS
 	bool is_valid  = test_bit_le(0, raw_sit->valid_map) ? true : false;
 	int valid_blocks = 0;
 	int cur_pos = 0, next_pos;
@@ -602,11 +617,25 @@
 		cur_pos = next_pos;
 		is_valid = !is_valid;
 	} while (cur_pos < sbi->blocks_per_seg);
-	BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
-#endif
+
+	if (unlikely(GET_SIT_VBLOCKS(raw_sit) != valid_blocks)) {
+		f2fs_msg(sbi->sb, KERN_ERR,
+				"Mismatch valid blocks %d vs. %d",
+					GET_SIT_VBLOCKS(raw_sit), valid_blocks);
+		set_sbi_flag(sbi, SBI_NEED_FSCK);
+		return -EINVAL;
+	}
+
 	/* check segment usage, and check boundary of a given segment number */
-	f2fs_bug_on(sbi, GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
-					|| segno > TOTAL_SEGS(sbi) - 1);
+	if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
+					|| segno > TOTAL_SEGS(sbi) - 1)) {
+		f2fs_msg(sbi->sb, KERN_ERR,
+				"Wrong valid blocks %d or segno %u",
+					GET_SIT_VBLOCKS(raw_sit), segno);
+		set_sbi_flag(sbi, SBI_NEED_FSCK);
+		return -EINVAL;
+	}
+	return 0;
 }
 
 static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
--- linux-4.4.0.orig/fs/f2fs/super.c
+++ linux-4.4.0/fs/f2fs/super.c
@@ -918,9 +918,84 @@
 	return result;
 }
 
+static inline bool sanity_check_area_boundary(struct super_block *sb,
+					struct f2fs_super_block *raw_super)
+{
+	u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
+	u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr);
+	u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr);
+	u32 nat_blkaddr = le32_to_cpu(raw_super->nat_blkaddr);
+	u32 ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
+	u32 main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
+	u32 segment_count_ckpt = le32_to_cpu(raw_super->segment_count_ckpt);
+	u32 segment_count_sit = le32_to_cpu(raw_super->segment_count_sit);
+	u32 segment_count_nat = le32_to_cpu(raw_super->segment_count_nat);
+	u32 segment_count_ssa = le32_to_cpu(raw_super->segment_count_ssa);
+	u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main);
+	u32 segment_count = le32_to_cpu(raw_super->segment_count);
+	u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
+
+	if (segment0_blkaddr != cp_blkaddr) {
+		f2fs_msg(sb, KERN_INFO,
+			"Mismatch start address, segment0(%u) cp_blkaddr(%u)",
+			segment0_blkaddr, cp_blkaddr);
+		return true;
+	}
+
+	if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) !=
+							sit_blkaddr) {
+		f2fs_msg(sb, KERN_INFO,
+			"Wrong CP boundary, start(%u) end(%u) blocks(%u)",
+			cp_blkaddr, sit_blkaddr,
+			segment_count_ckpt << log_blocks_per_seg);
+		return true;
+	}
+
+	if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) !=
+							nat_blkaddr) {
+		f2fs_msg(sb, KERN_INFO,
+			"Wrong SIT boundary, start(%u) end(%u) blocks(%u)",
+			sit_blkaddr, nat_blkaddr,
+			segment_count_sit << log_blocks_per_seg);
+		return true;
+	}
+
+	if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) !=
+							ssa_blkaddr) {
+		f2fs_msg(sb, KERN_INFO,
+			"Wrong NAT boundary, start(%u) end(%u) blocks(%u)",
+			nat_blkaddr, ssa_blkaddr,
+			segment_count_nat << log_blocks_per_seg);
+		return true;
+	}
+
+	if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) !=
+							main_blkaddr) {
+		f2fs_msg(sb, KERN_INFO,
+			"Wrong SSA boundary, start(%u) end(%u) blocks(%u)",
+			ssa_blkaddr, main_blkaddr,
+			segment_count_ssa << log_blocks_per_seg);
+		return true;
+	}
+
+	if (main_blkaddr + (segment_count_main << log_blocks_per_seg) !=
+		segment0_blkaddr + (segment_count << log_blocks_per_seg)) {
+		f2fs_msg(sb, KERN_INFO,
+			"Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)",
+			main_blkaddr,
+			segment0_blkaddr + (segment_count << log_blocks_per_seg),
+			segment_count_main << log_blocks_per_seg);
+		return true;
+	}
+
+	return false;
+}
+
 static int sanity_check_raw_super(struct super_block *sb,
 			struct f2fs_super_block *raw_super)
 {
+	block_t segment_count, segs_per_sec, secs_per_zone, segment_count_main;
+	block_t total_sections, blocks_per_seg;
 	unsigned int blocksize;
 
 	if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
@@ -947,6 +1022,14 @@
 		return 1;
 	}
 
+	/* check log blocks per segment */
+	if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) {
+		f2fs_msg(sb, KERN_INFO,
+			"Invalid log blocks per segment (%u)\n",
+			le32_to_cpu(raw_super->log_blocks_per_seg));
+		return 1;
+	}
+
 	/* Currently, support 512/1024/2048/4096 bytes sector size */
 	if (le32_to_cpu(raw_super->log_sectorsize) >
 				F2FS_MAX_LOG_SECTOR_SIZE ||
@@ -965,25 +1048,210 @@
 			le32_to_cpu(raw_super->log_sectorsize));
 		return 1;
 	}
+
+	segment_count = le32_to_cpu(raw_super->segment_count);
+	segment_count_main = le32_to_cpu(raw_super->segment_count_main);
+	segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
+	secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
+	total_sections = le32_to_cpu(raw_super->section_count);
+
+	/* blocks_per_seg should be 512, given the above check */
+	blocks_per_seg = 1 << le32_to_cpu(raw_super->log_blocks_per_seg);
+
+	if (segment_count > F2FS_MAX_SEGMENT ||
+				segment_count < F2FS_MIN_SEGMENTS) {
+		f2fs_msg(sb, KERN_INFO,
+			"Invalid segment count (%u)",
+			segment_count);
+		return 1;
+	}
+
+	if (total_sections > segment_count_main || total_sections < 1 ||
+			segs_per_sec > segment_count || !segs_per_sec) {
+		f2fs_msg(sb, KERN_INFO,
+			"Invalid segment/section count (%u, %u x %u)",
+			segment_count, total_sections, segs_per_sec);
+		return 1;
+	}
+
+	if (segment_count_main != total_sections * segs_per_sec) {
+		f2fs_msg(sb, KERN_INFO,
+			"Invalid segment/section count (%u != %u * %u)",
+			segment_count_main, total_sections, segs_per_sec);
+		return 1;
+	}
+
+	if ((segment_count / segs_per_sec) < total_sections) {
+		f2fs_msg(sb, KERN_INFO,
+			"Small segment_count (%u < %u * %u)",
+			segment_count, segs_per_sec, total_sections);
+		return 1;
+	}
+
+	if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) {
+		f2fs_msg(sb, KERN_INFO,
+			"Wrong segment_count / block_count (%u > %llu)",
+			segment_count, le64_to_cpu(raw_super->block_count));
+		return 1;
+	}
+
+	if (secs_per_zone > total_sections || !secs_per_zone) {
+		f2fs_msg(sb, KERN_INFO,
+			"Wrong secs_per_zone / total_sections (%u, %u)",
+			secs_per_zone, total_sections);
+		return 1;
+	}
+	if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION) {
+		f2fs_msg(sb, KERN_INFO,
+			"Corrupted extension count (%u > %u)",
+			le32_to_cpu(raw_super->extension_count),
+			F2FS_MAX_EXTENSION);
+		return 1;
+	}
+
+	if (le32_to_cpu(raw_super->cp_payload) >
+				(blocks_per_seg - F2FS_CP_PACKS)) {
+		f2fs_msg(sb, KERN_INFO,
+			"Insane cp_payload (%u > %u)",
+			le32_to_cpu(raw_super->cp_payload),
+			blocks_per_seg - F2FS_CP_PACKS);
+		return 1;
+	}
+
+	/* check reserved ino info */
+	if (le32_to_cpu(raw_super->node_ino) != 1 ||
+		le32_to_cpu(raw_super->meta_ino) != 2 ||
+		le32_to_cpu(raw_super->root_ino) != 3) {
+		f2fs_msg(sb, KERN_INFO,
+			"Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
+			le32_to_cpu(raw_super->node_ino),
+			le32_to_cpu(raw_super->meta_ino),
+			le32_to_cpu(raw_super->root_ino));
+		return 1;
+	}
+
+	/* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
+	if (sanity_check_area_boundary(sb, raw_super))
+		return 1;
+
 	return 0;
 }
 
-static int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+int sanity_check_ckpt(struct f2fs_sb_info *sbi)
 {
 	unsigned int total, fsmeta;
 	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+	unsigned int ovp_segments, reserved_segments;
+	unsigned int main_segs, blocks_per_seg;
+	unsigned int sit_segs, nat_segs;
+	unsigned int sit_bitmap_size, nat_bitmap_size;
+	unsigned int log_blocks_per_seg;
+	unsigned int segment_count_main;
+	unsigned int cp_pack_start_sum, cp_payload;
+	block_t user_block_count;
+	int i, j;
 
 	total = le32_to_cpu(raw_super->segment_count);
 	fsmeta = le32_to_cpu(raw_super->segment_count_ckpt);
-	fsmeta += le32_to_cpu(raw_super->segment_count_sit);
-	fsmeta += le32_to_cpu(raw_super->segment_count_nat);
+	sit_segs = le32_to_cpu(raw_super->segment_count_sit);
+	fsmeta += sit_segs;
+	nat_segs = le32_to_cpu(raw_super->segment_count_nat);
+	fsmeta += nat_segs;
 	fsmeta += le32_to_cpu(ckpt->rsvd_segment_count);
 	fsmeta += le32_to_cpu(raw_super->segment_count_ssa);
 
 	if (unlikely(fsmeta >= total))
 		return 1;
 
+	ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
+	reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
+
+	if (unlikely(fsmeta < F2FS_MIN_META_SEGMENTS ||
+			ovp_segments == 0 || reserved_segments == 0)) {
+		f2fs_msg(sbi->sb, KERN_ERR,
+			"Wrong layout: check mkfs.f2fs version");
+		return 1;
+	}
+
+	user_block_count = le64_to_cpu(ckpt->user_block_count);
+	segment_count_main = le32_to_cpu(raw_super->segment_count_main);
+	log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
+	if (!user_block_count || user_block_count >=
+			segment_count_main << log_blocks_per_seg) {
+		f2fs_msg(sbi->sb, KERN_ERR,
+			"Wrong user_block_count: %u", user_block_count);
+		return 1;
+	}
+
+	main_segs = le32_to_cpu(raw_super->segment_count_main);
+	blocks_per_seg = sbi->blocks_per_seg;
+
+	for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
+		if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs ||
+			le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg)
+			return 1;
+		for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) {
+			if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
+				le32_to_cpu(ckpt->cur_node_segno[j])) {
+				f2fs_msg(sbi->sb, KERN_ERR,
+					"Node segment (%u, %u) has the same "
+					"segno: %u", i, j,
+					le32_to_cpu(ckpt->cur_node_segno[i]));
+				return 1;
+			}
+		}
+	}
+	for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) {
+		if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs ||
+			le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg)
+			return 1;
+		for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) {
+			if (le32_to_cpu(ckpt->cur_data_segno[i]) ==
+				le32_to_cpu(ckpt->cur_data_segno[j])) {
+				f2fs_msg(sbi->sb, KERN_ERR,
+					"Data segment (%u, %u) has the same "
+					"segno: %u", i, j,
+					le32_to_cpu(ckpt->cur_data_segno[i]));
+				return 1;
+			}
+		}
+	}
+	for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
+		for (j = 0; j < NR_CURSEG_DATA_TYPE; j++) {
+			if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
+				le32_to_cpu(ckpt->cur_data_segno[j])) {
+				f2fs_msg(sbi->sb, KERN_ERR,
+					"Node segment (%u) and Data segment (%u)"
+					" has the same segno: %u", i, j,
+					le32_to_cpu(ckpt->cur_node_segno[i]));
+				return 1;
+			}
+		}
+	}
+
+	sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
+	nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
+
+	if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 ||
+		nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) {
+		f2fs_msg(sbi->sb, KERN_ERR,
+			"Wrong bitmap size: sit: %u, nat:%u",
+			sit_bitmap_size, nat_bitmap_size);
+		return 1;
+	}
+
+	cp_pack_start_sum = __start_sum_addr(sbi);
+	cp_payload = __cp_payload(sbi);
+	if (cp_pack_start_sum < cp_payload + 1 ||
+		cp_pack_start_sum > blocks_per_seg - 1 -
+			NR_CURSEG_TYPE) {
+		f2fs_msg(sbi->sb, KERN_ERR,
+			"Wrong cp_pack_start_sum: %u",
+			cp_pack_start_sum);
+		return 1;
+	}
+
 	if (unlikely(f2fs_cp_error(sbi))) {
 		f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");
 		return 1;
@@ -1220,13 +1488,6 @@
 		goto free_meta_inode;
 	}
 
-	/* sanity checking of checkpoint */
-	err = -EINVAL;
-	if (sanity_check_ckpt(sbi)) {
-		f2fs_msg(sb, KERN_ERR, "Invalid F2FS checkpoint");
-		goto free_cp;
-	}
-
 	sbi->total_valid_node_count =
 				le32_to_cpu(sbi->ckpt->valid_node_count);
 	sbi->total_valid_inode_count =
@@ -1326,14 +1587,27 @@
 		if (need_fsck)
 			set_sbi_flag(sbi, SBI_NEED_FSCK);
 
-		err = recover_fsync_data(sbi);
-		if (err) {
+		if (!retry)
+			goto skip_recovery;
+
+		err = recover_fsync_data(sbi, false);
+		if (err < 0) {
 			need_fsck = true;
 			f2fs_msg(sb, KERN_ERR,
 				"Cannot recover all fsync data errno=%ld", err);
 			goto free_kobj;
 		}
+	} else {
+		err = recover_fsync_data(sbi, true);
+
+		if (!f2fs_readonly(sb) && err > 0) {
+			err = -EINVAL;
+			f2fs_msg(sb, KERN_ERR,
+				"Need to recover fsync data");
+			goto free_kobj;
+		}
 	}
+skip_recovery:
 	/* recover_fsync_data() cleared this already */
 	clear_sbi_flag(sbi, SBI_POR_DOING);
 
@@ -1379,7 +1653,6 @@
 	destroy_node_manager(sbi);
 free_sm:
 	destroy_segment_manager(sbi);
-free_cp:
 	kfree(sbi->ckpt);
 free_meta_inode:
 	make_bad_inode(sbi->meta_inode);
@@ -1445,6 +1718,12 @@
 {
 	int err;
 
+	if (PAGE_SIZE != F2FS_BLKSIZE) {
+		printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n",
+				PAGE_SIZE, F2FS_BLKSIZE);
+		return -EINVAL;
+	}
+
 	f2fs_build_trace_ios();
 
 	err = init_inodecache();
--- linux-4.4.0.orig/fs/f2fs/trace.c
+++ linux-4.4.0/fs/f2fs/trace.c
@@ -60,6 +60,7 @@
 
 	page->private = pid;
 
+retry:
 	if (radix_tree_preload(GFP_NOFS))
 		return;
 
@@ -70,7 +71,12 @@
 	if (p)
 		radix_tree_delete(&pids, pid);
 
-	f2fs_radix_tree_insert(&pids, pid, current);
+	if (radix_tree_insert(&pids, pid, current)) {
+		spin_unlock(&pids_lock);
+		radix_tree_preload_end();
+		cond_resched();
+		goto retry;
+	}
 
 	trace_printk("%3x:%3x %4x %-16s\n",
 			MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev),
--- linux-4.4.0.orig/fs/f2fs/xattr.c
+++ linux-4.4.0/fs/f2fs/xattr.c
@@ -248,12 +248,17 @@
 	return handler;
 }
 
-static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
-					size_t len, const char *name)
+static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
+				void *last_base_addr, int index,
+				size_t len, const char *name)
 {
 	struct f2fs_xattr_entry *entry;
 
 	list_for_each_xattr(entry, base_addr) {
+		if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
+		    (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr)
+			return NULL;
+
 		if (entry->e_name_index != index)
 			continue;
 		if (entry->e_name_len != len)
@@ -401,9 +406,10 @@
 		void *buffer, size_t buffer_size, struct page *ipage)
 {
 	struct f2fs_xattr_entry *entry;
-	void *base_addr;
+	void *base_addr, *last_base_addr;
 	int error = 0;
 	size_t size, len;
+	nid_t xnid = F2FS_I(inode)->i_xattr_nid;
 
 	if (name == NULL)
 		return -EINVAL;
@@ -416,7 +422,9 @@
 	if (!base_addr)
 		return -ENOMEM;
 
-	entry = __find_xattr(base_addr, index, len, name);
+	last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode);
+	
+	entry = __find_xattr(base_addr, last_base_addr, index, len, name);
 	if (IS_XATTR_LAST_ENTRY(entry)) {
 		error = -ENODATA;
 		goto cleanup;
@@ -443,8 +451,9 @@
 ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 {
 	struct inode *inode = d_inode(dentry);
+	nid_t xnid = F2FS_I(inode)->i_xattr_nid;
 	struct f2fs_xattr_entry *entry;
-	void *base_addr;
+	void *base_addr, *last_base_addr;
 	int error = 0;
 	size_t rest = buffer_size;
 
@@ -452,11 +461,23 @@
 	if (!base_addr)
 		return -ENOMEM;
 
+	last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode);
+
 	list_for_each_xattr(entry, base_addr) {
 		const struct xattr_handler *handler =
 			f2fs_xattr_handler(entry->e_name_index);
 		size_t size;
 
+		if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
+			(void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) {
+			f2fs_msg(F2FS_I_SB(inode)->sb, KERN_ERR,
+				 "inode (%lu) has corrupted xattr",
+				inode->i_ino);
+			set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
+			error = -EUCLEAN;
+			goto cleanup;
+		}
+
 		if (!handler)
 			continue;
 
@@ -483,7 +504,9 @@
 {
 	struct f2fs_inode_info *fi = F2FS_I(inode);
 	struct f2fs_xattr_entry *here, *last;
-	void *base_addr;
+	void *base_addr, *last_base_addr;
+	nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+
 	int found, newsize;
 	size_t len;
 	__u32 new_hsize;
@@ -507,8 +530,14 @@
 	if (!base_addr)
 		goto exit;
 
+	last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode);
+
 	/* find entry with wanted name. */
-	here = __find_xattr(base_addr, index, len, name);
+	here = __find_xattr(base_addr, last_base_addr, index, len, name);
+	if (!here) {
+		error = -EFAULT;
+		goto exit;
+	}
 
 	found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
 
@@ -521,8 +550,17 @@
 	}
 
 	last = here;
-	while (!IS_XATTR_LAST_ENTRY(last))
+	while (!IS_XATTR_LAST_ENTRY(last)) {
+		if ((void *)(last) + sizeof(__u32) > last_base_addr ||
+			(void *)XATTR_NEXT_ENTRY(last) > last_base_addr) {
+			f2fs_msg(F2FS_I_SB(inode)->sb, KERN_ERR, "inode (%lu) has invalid last xattr entry, entry_size: %zu",
+					inode->i_ino, ENTRY_SIZE(last));
+			set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
+			error = -EUCLEAN;
+			goto exit;
+		}
 		last = XATTR_NEXT_ENTRY(last);
+	}
 
 	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
 
@@ -574,6 +612,12 @@
 		memcpy(pval, value, size);
 		last->e_value_size = cpu_to_le16(size);
 		new_hsize += newsize;
+		/*
+		 * Explicitly add the null terminator.  The unused xattr space
+		 * is supposed to always be zeroed, which would make this
+		 * unnecessary, but don't depend on that.
+		 */
+		*(u32 *)((u8 *)last + newsize) = 0;
 	}
 
 	error = write_all_xattrs(inode, new_hsize, base_addr, ipage);
--- linux-4.4.0.orig/fs/f2fs/xattr.h
+++ linux-4.4.0/fs/f2fs/xattr.h
@@ -72,7 +72,9 @@
 		for (entry = XATTR_FIRST_ENTRY(addr);\
 				!IS_XATTR_LAST_ENTRY(entry);\
 				entry = XATTR_NEXT_ENTRY(entry))
-
+#define VALID_XATTR_BLOCK_SIZE	(PAGE_SIZE - sizeof(struct node_footer))
+#define XATTR_SIZE(x,i)		(((x) ? VALID_XATTR_BLOCK_SIZE : 0) +	\
+						(inline_xattr_size(i)))
 #define MIN_OFFSET(i)	XATTR_ALIGN(inline_xattr_size(i) + PAGE_SIZE -	\
 				sizeof(struct node_footer) - sizeof(__u32))
 
--- linux-4.4.0.orig/fs/fat/cache.c
+++ linux-4.4.0/fs/fat/cache.c
@@ -224,7 +224,8 @@
 int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
 {
 	struct super_block *sb = inode->i_sb;
-	const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	const int limit = sb->s_maxbytes >> sbi->cluster_bits;
 	struct fat_entry fatent;
 	struct fat_cache_id cid;
 	int nr;
@@ -233,6 +234,12 @@
 
 	*fclus = 0;
 	*dclus = MSDOS_I(inode)->i_start;
+	if (!fat_valid_entry(sbi, *dclus)) {
+		fat_fs_error_ratelimit(sb,
+			"%s: invalid start cluster (i_pos %lld, start %08x)",
+			__func__, MSDOS_I(inode)->i_pos, *dclus);
+		return -EIO;
+	}
 	if (cluster == 0)
 		return 0;
 
@@ -249,9 +256,8 @@
 		/* prevent the infinite loop of cluster chain */
 		if (*fclus > limit) {
 			fat_fs_error_ratelimit(sb,
-					"%s: detected the cluster chain loop"
-					" (i_pos %lld)", __func__,
-					MSDOS_I(inode)->i_pos);
+				"%s: detected the cluster chain loop (i_pos %lld)",
+				__func__, MSDOS_I(inode)->i_pos);
 			nr = -EIO;
 			goto out;
 		}
@@ -261,9 +267,8 @@
 			goto out;
 		else if (nr == FAT_ENT_FREE) {
 			fat_fs_error_ratelimit(sb,
-				       "%s: invalid cluster chain (i_pos %lld)",
-				       __func__,
-				       MSDOS_I(inode)->i_pos);
+				"%s: invalid cluster chain (i_pos %lld)",
+				__func__, MSDOS_I(inode)->i_pos);
 			nr = -EIO;
 			goto out;
 		} else if (nr == FAT_ENT_EOF) {
--- linux-4.4.0.orig/fs/fat/dir.c
+++ linux-4.4.0/fs/fat/dir.c
@@ -1097,8 +1097,11 @@
 			err = -ENOMEM;
 			goto error;
 		}
+		/* Avoid race with userspace read via bdev */
+		lock_buffer(bhs[n]);
 		memset(bhs[n]->b_data, 0, sb->s_blocksize);
 		set_buffer_uptodate(bhs[n]);
+		unlock_buffer(bhs[n]);
 		mark_buffer_dirty_inode(bhs[n], dir);
 
 		n++;
@@ -1155,6 +1158,8 @@
 	fat_time_unix2fat(sbi, ts, &time, &date, &time_cs);
 
 	de = (struct msdos_dir_entry *)bhs[0]->b_data;
+	/* Avoid race with userspace read via bdev */
+	lock_buffer(bhs[0]);
 	/* filling the new directory slots ("." and ".." entries) */
 	memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
 	memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
@@ -1177,6 +1182,7 @@
 	de[0].size = de[1].size = 0;
 	memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de));
 	set_buffer_uptodate(bhs[0]);
+	unlock_buffer(bhs[0]);
 	mark_buffer_dirty_inode(bhs[0], dir);
 
 	err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE);
@@ -1234,11 +1240,14 @@
 
 			/* fill the directory entry */
 			copy = min(size, sb->s_blocksize);
+			/* Avoid race with userspace read via bdev */
+			lock_buffer(bhs[n]);
 			memcpy(bhs[n]->b_data, slots, copy);
-			slots += copy;
-			size -= copy;
 			set_buffer_uptodate(bhs[n]);
+			unlock_buffer(bhs[n]);
 			mark_buffer_dirty_inode(bhs[n], dir);
+			slots += copy;
+			size -= copy;
 			if (!size)
 				break;
 			n++;
--- linux-4.4.0.orig/fs/fat/fat.h
+++ linux-4.4.0/fs/fat/fat.h
@@ -344,6 +344,11 @@
 	fatent->fat_inode = NULL;
 }
 
+static inline bool fat_valid_entry(struct msdos_sb_info *sbi, int entry)
+{
+	return FAT_START_ENT <= entry && entry < sbi->max_cluster;
+}
+
 extern void fat_ent_access_init(struct super_block *sb);
 extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent,
 			int entry);
--- linux-4.4.0.orig/fs/fat/fatent.c
+++ linux-4.4.0/fs/fat/fatent.c
@@ -23,7 +23,7 @@
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	int bytes = entry + (entry >> 1);
-	WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
+	WARN_ON(!fat_valid_entry(sbi, entry));
 	*offset = bytes & (sb->s_blocksize - 1);
 	*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
 }
@@ -33,7 +33,7 @@
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	int bytes = (entry << sbi->fatent_shift);
-	WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
+	WARN_ON(!fat_valid_entry(sbi, entry));
 	*offset = bytes & (sb->s_blocksize - 1);
 	*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
 }
@@ -353,7 +353,7 @@
 	int err, offset;
 	sector_t blocknr;
 
-	if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
+	if (!fat_valid_entry(sbi, entry)) {
 		fatent_brelse(fatent);
 		fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry);
 		return -EIO;
@@ -389,8 +389,11 @@
 				err = -ENOMEM;
 				goto error;
 			}
+			/* Avoid race with userspace read via bdev */
+			lock_buffer(c_bh);
 			memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize);
 			set_buffer_uptodate(c_bh);
+			unlock_buffer(c_bh);
 			mark_buffer_dirty_inode(c_bh, sbi->fat_inode);
 			if (sb->s_flags & MS_SYNCHRONOUS)
 				err = sync_dirty_buffer(c_bh);
@@ -681,6 +684,7 @@
 			if (ops->ent_get(&fatent) == FAT_ENT_FREE)
 				free++;
 		} while (fat_ent_next(sbi, &fatent));
+		cond_resched();
 	}
 	sbi->free_clusters = free;
 	sbi->free_clus_valid = 1;
--- linux-4.4.0.orig/fs/fat/file.c
+++ linux-4.4.0/fs/fat/file.c
@@ -156,12 +156,17 @@
 int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
 	struct inode *inode = filp->f_mapping->host;
-	int res, err;
+	int err;
+
+	err = __generic_file_fsync(filp, start, end, datasync);
+	if (err)
+		return err;
 
-	res = generic_file_fsync(filp, start, end, datasync);
 	err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);
+	if (err)
+		return err;
 
-	return res ? res : err;
+	return blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
 }
 
 
@@ -389,7 +394,7 @@
 			attr->ia_valid &= ~TIMES_SET_FLAGS;
 	}
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	attr->ia_valid = ia_valid;
 	if (error) {
 		if (sbi->options.quiet)
--- linux-4.4.0.orig/fs/fat/inode.c
+++ linux-4.4.0/fs/fat/inode.c
@@ -613,13 +613,21 @@
 	brelse(bh);
 }
 
+static void fat_reset_iocharset(struct fat_mount_options *opts)
+{
+	if (opts->iocharset != fat_default_iocharset) {
+		/* Note: opts->iocharset can be NULL here */
+		kfree(opts->iocharset);
+		opts->iocharset = fat_default_iocharset;
+	}
+}
+
 static void delayed_free(struct rcu_head *p)
 {
 	struct msdos_sb_info *sbi = container_of(p, struct msdos_sb_info, rcu);
 	unload_nls(sbi->nls_disk);
 	unload_nls(sbi->nls_io);
-	if (sbi->options.iocharset != fat_default_iocharset)
-		kfree(sbi->options.iocharset);
+	fat_reset_iocharset(&sbi->options);
 	kfree(sbi);
 }
 
@@ -645,6 +653,13 @@
 		return NULL;
 
 	init_rwsem(&ei->truncate_lock);
+	/* Zeroing to allow iput() even if partial initialized inode. */
+	ei->mmu_private = 0;
+	ei->i_start = 0;
+	ei->i_logstart = 0;
+	ei->i_attrs = 0;
+	ei->i_pos = 0;
+
 	return &ei->vfs_inode;
 }
 
@@ -1034,7 +1049,7 @@
 	opts->fs_fmask = opts->fs_dmask = current_umask();
 	opts->allow_utime = -1;
 	opts->codepage = fat_default_codepage;
-	opts->iocharset = fat_default_iocharset;
+	fat_reset_iocharset(opts);
 	if (is_vfat) {
 		opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95;
 		opts->rodir = 0;
@@ -1184,8 +1199,7 @@
 
 		/* vfat specific */
 		case Opt_charset:
-			if (opts->iocharset != fat_default_iocharset)
-				kfree(opts->iocharset);
+			fat_reset_iocharset(opts);
 			iocharset = match_strdup(&args[0]);
 			if (!iocharset)
 				return -ENOMEM;
@@ -1408,6 +1422,12 @@
 		goto out;
 	}
 
+	if (bpb->fat_fat_length == 0 && bpb->fat32_length == 0) {
+		if (!silent)
+			fat_msg(sb, KERN_ERR, "bogus number of FAT sectors");
+		goto out;
+	}
+
 	error = 0;
 
 out:
@@ -1713,7 +1733,6 @@
 	fat_inode = new_inode(sb);
 	if (!fat_inode)
 		goto out_fail;
-	MSDOS_I(fat_inode)->i_pos = 0;
 	sbi->fat_inode = fat_inode;
 
 	fsinfo_inode = new_inode(sb);
@@ -1765,8 +1784,7 @@
 		iput(fat_inode);
 	unload_nls(sbi->nls_io);
 	unload_nls(sbi->nls_disk);
-	if (sbi->options.iocharset != fat_default_iocharset)
-		kfree(sbi->options.iocharset);
+	fat_reset_iocharset(&sbi->options);
 	sb->s_fs_info = NULL;
 	kfree(sbi);
 	return error;
--- linux-4.4.0.orig/fs/fcntl.c
+++ linux-4.4.0/fs/fcntl.c
@@ -113,6 +113,10 @@
 	int who = arg;
 	type = PIDTYPE_PID;
 	if (who < 0) {
+		/* avoid overflow below */
+		if (who == INT_MIN)
+			return;
+
 		type = PIDTYPE_PGID;
 		who = -who;
 	}
@@ -740,16 +744,10 @@
 	 * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
 	 * is defined as O_NONBLOCK on some platforms and not on others.
 	 */
-	BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
-		O_RDONLY	| O_WRONLY	| O_RDWR	|
-		O_CREAT		| O_EXCL	| O_NOCTTY	|
-		O_TRUNC		| O_APPEND	| /* O_NONBLOCK	| */
-		__O_SYNC	| O_DSYNC	| FASYNC	|
-		O_DIRECT	| O_LARGEFILE	| O_DIRECTORY	|
-		O_NOFOLLOW	| O_NOATIME	| O_CLOEXEC	|
-		__FMODE_EXEC	| O_PATH	| __O_TMPFILE	|
-		__FMODE_NONOTIFY
-		));
+	BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ !=
+		HWEIGHT32(
+			(VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) |
+			__FMODE_EXEC | __FMODE_NONOTIFY));
 
 	fasync_cache = kmem_cache_create("fasync_cache",
 		sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL);
--- linux-4.4.0.orig/fs/fhandle.c
+++ linux-4.4.0/fs/fhandle.c
@@ -35,7 +35,7 @@
 	if (f_handle.handle_bytes > MAX_HANDLE_SZ)
 		return -EINVAL;
 
-	handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
+	handle = kzalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
 			 GFP_KERNEL);
 	if (!handle)
 		return -ENOMEM;
@@ -228,7 +228,7 @@
 		path_put(&path);
 		return fd;
 	}
-	file = file_open_root(path.dentry, path.mnt, "", open_flag);
+	file = file_open_root(path.dentry, path.mnt, "", open_flag, 0);
 	if (IS_ERR(file)) {
 		put_unused_fd(fd);
 		retval =  PTR_ERR(file);
--- linux-4.4.0.orig/fs/file.c
+++ linux-4.4.0/fs/file.c
@@ -88,7 +88,7 @@
  */
 static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt)
 {
-	unsigned int cpy, set;
+	size_t cpy, set;
 
 	BUG_ON(nfdt->max_fds < ofdt->max_fds);
 
@@ -474,6 +474,7 @@
 		.full_fds_bits	= init_files.full_fds_bits_init,
 	},
 	.file_lock	= __SPIN_LOCK_UNLOCKED(init_files.file_lock),
+	.resize_wait	= __WAIT_QUEUE_HEAD_INITIALIZER(init_files.resize_wait),
 };
 
 static unsigned long find_next_fd(struct fdtable *fdt, unsigned long start)
@@ -690,7 +691,7 @@
 	spin_unlock(&files->file_lock);
 }
 
-static struct file *__fget(unsigned int fd, fmode_t mask)
+static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs)
 {
 	struct files_struct *files = current->files;
 	struct file *file;
@@ -705,23 +706,32 @@
 		 */
 		if (file->f_mode & mask)
 			file = NULL;
-		else if (!get_file_rcu(file))
+		else if (!get_file_rcu_many(file, refs))
 			goto loop;
+		else if (__fcheck_files(files, fd) != file) {
+			fput_many(file, refs);
+			goto loop;
+		}
 	}
 	rcu_read_unlock();
 
 	return file;
 }
 
+struct file *fget_many(unsigned int fd, unsigned int refs)
+{
+	return __fget(fd, FMODE_PATH, refs);
+}
+
 struct file *fget(unsigned int fd)
 {
-	return __fget(fd, FMODE_PATH);
+	return __fget(fd, FMODE_PATH, 1);
 }
 EXPORT_SYMBOL(fget);
 
 struct file *fget_raw(unsigned int fd)
 {
-	return __fget(fd, 0);
+	return __fget(fd, 0, 1);
 }
 EXPORT_SYMBOL(fget_raw);
 
@@ -752,7 +762,7 @@
 			return 0;
 		return (unsigned long)file;
 	} else {
-		file = __fget(fd, mask);
+		file = __fget(fd, mask, 1);
 		if (!file)
 			return 0;
 		return FDPUT_FPUT | (unsigned long)file;
--- linux-4.4.0.orig/fs/file_table.c
+++ linux-4.4.0/fs/file_table.c
@@ -147,6 +147,7 @@
 	}
 	return ERR_PTR(-ENFILE);
 }
+EXPORT_SYMBOL(get_empty_filp);
 
 /**
  * alloc_file - allocate and initialize a 'struct file'
@@ -261,9 +262,9 @@
 
 static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput);
 
-void fput(struct file *file)
+void fput_many(struct file *file, unsigned int refs)
 {
-	if (atomic_long_dec_and_test(&file->f_count)) {
+	if (atomic_long_sub_and_test(refs, &file->f_count)) {
 		struct task_struct *task = current;
 
 		if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
@@ -282,6 +283,11 @@
 	}
 }
 
+void fput(struct file *file)
+{
+	fput_many(file, 1);
+}
+
 /*
  * synchronous analog of fput(); for kernel threads that might be needed
  * in some umount() (and thus can't use flush_delayed_fput() without
@@ -308,6 +314,7 @@
 		file_free(file);
 	}
 }
+EXPORT_SYMBOL(put_filp);
 
 void __init files_init(void)
 { 
--- linux-4.4.0.orig/fs/fs-writeback.c
+++ linux-4.4.0/fs/fs-writeback.c
@@ -45,7 +45,6 @@
 struct wb_writeback_work {
 	long nr_pages;
 	struct super_block *sb;
-	unsigned long *older_than_this;
 	enum writeback_sync_modes sync_mode;
 	unsigned int tagged_writepages:1;
 	unsigned int for_kupdate:1;
@@ -160,7 +159,9 @@
 				     struct bdi_writeback *wb)
 {
 	assert_spin_locked(&wb->list_lock);
+	assert_spin_locked(&inode->i_lock);
 
+	inode->i_state &= ~I_SYNC_QUEUED;
 	list_del_init(&inode->i_io_list);
 	wb_io_lists_depopulated(wb);
 }
@@ -173,19 +174,33 @@
 	spin_unlock_bh(&wb->work_lock);
 }
 
+static void finish_writeback_work(struct bdi_writeback *wb,
+				  struct wb_writeback_work *work)
+{
+	struct wb_completion *done = work->done;
+
+	if (work->auto_free)
+		kfree(work);
+	if (done && atomic_dec_and_test(&done->cnt))
+		wake_up_all(&wb->bdi->wb_waitq);
+}
+
 static void wb_queue_work(struct bdi_writeback *wb,
 			  struct wb_writeback_work *work)
 {
 	trace_writeback_queue(wb, work);
 
-	spin_lock_bh(&wb->work_lock);
-	if (!test_bit(WB_registered, &wb->state))
-		goto out_unlock;
 	if (work->done)
 		atomic_inc(&work->done->cnt);
-	list_add_tail(&work->list, &wb->work_list);
-	mod_delayed_work(bdi_wq, &wb->dwork, 0);
-out_unlock:
+
+	spin_lock_bh(&wb->work_lock);
+
+	if (test_bit(WB_registered, &wb->state)) {
+		list_add_tail(&work->list, &wb->work_list);
+		mod_delayed_work(bdi_wq, &wb->dwork, 0);
+	} else
+		finish_writeback_work(wb, work);
+
 	spin_unlock_bh(&wb->work_lock);
 }
 
@@ -223,6 +238,9 @@
 #define WB_FRN_HIST_MAX_SLOTS	(WB_FRN_HIST_THR_SLOTS / 2 + 1)
 					/* one round can affect upto 5 slots */
 
+static atomic_t isw_nr_in_flight = ATOMIC_INIT(0);
+static struct workqueue_struct *isw_wq;
+
 void __inode_attach_wb(struct inode *inode, struct page *page)
 {
 	struct backing_dev_info *bdi = inode_to_bdi(inode);
@@ -252,6 +270,7 @@
 	if (unlikely(cmpxchg(&inode->i_wb, NULL, wb)))
 		wb_put(wb);
 }
+EXPORT_SYMBOL_GPL(__inode_attach_wb);
 
 /**
  * locked_inode_to_wb_and_lock_list - determine a locked inode's wb and lock it
@@ -278,13 +297,15 @@
 		wb_get(wb);
 		spin_unlock(&inode->i_lock);
 		spin_lock(&wb->list_lock);
-		wb_put(wb);		/* not gonna deref it anymore */
 
 		/* i_wb may have changed inbetween, can't use inode_to_wb() */
-		if (likely(wb == inode->i_wb))
-			return wb;	/* @inode already has ref */
+		if (likely(wb == inode->i_wb)) {
+			wb_put(wb);	/* @inode already has ref */
+			return wb;
+		}
 
 		spin_unlock(&wb->list_lock);
+		wb_put(wb);
 		cpu_relax();
 		spin_lock(&inode->i_lock);
 	}
@@ -312,11 +333,22 @@
 	struct work_struct	work;
 };
 
+static void bdi_down_write_wb_switch_rwsem(struct backing_dev_info *bdi)
+{
+	down_write(&bdi->wb_switch_rwsem);
+}
+
+static void bdi_up_write_wb_switch_rwsem(struct backing_dev_info *bdi)
+{
+	up_write(&bdi->wb_switch_rwsem);
+}
+
 static void inode_switch_wbs_work_fn(struct work_struct *work)
 {
 	struct inode_switch_wbs_context *isw =
 		container_of(work, struct inode_switch_wbs_context, work);
 	struct inode *inode = isw->inode;
+	struct backing_dev_info *bdi = inode_to_bdi(inode);
 	struct address_space *mapping = inode->i_mapping;
 	struct bdi_writeback *old_wb = inode->i_wb;
 	struct bdi_writeback *new_wb = isw->new_wb;
@@ -325,6 +357,12 @@
 	void **slot;
 
 	/*
+	 * If @inode switches cgwb membership while sync_inodes_sb() is
+	 * being issued, sync_inodes_sb() might miss it.  Synchronize.
+	 */
+	down_read(&bdi->wb_switch_rwsem);
+
+	/*
 	 * By the time control reaches here, RCU grace period has passed
 	 * since I_WB_SWITCH assertion and all wb stat update transactions
 	 * between unlocked_inode_to_wb_begin/end() are guaranteed to be
@@ -416,6 +454,8 @@
 	spin_unlock(&new_wb->list_lock);
 	spin_unlock(&old_wb->list_lock);
 
+	up_read(&bdi->wb_switch_rwsem);
+
 	if (switched) {
 		wb_wakeup(new_wb);
 		wb_put(old_wb);
@@ -424,6 +464,8 @@
 
 	iput(inode);
 	kfree(isw);
+
+	atomic_dec(&isw_nr_in_flight);
 }
 
 static void inode_switch_wbs_rcu_fn(struct rcu_head *rcu_head)
@@ -433,7 +475,7 @@
 
 	/* needs to grab bh-unsafe locks, bounce to work item */
 	INIT_WORK(&isw->work, inode_switch_wbs_work_fn);
-	schedule_work(&isw->work);
+	queue_work(isw_wq, &isw->work);
 }
 
 /**
@@ -454,9 +496,18 @@
 	if (inode->i_state & I_WB_SWITCH)
 		return;
 
+	/*
+	 * Avoid starting new switches while sync_inodes_sb() is in
+	 * progress.  Otherwise, if the down_write protected issue path
+	 * blocks heavily, we might end up starting a large number of
+	 * switches which will block on the rwsem.
+	 */
+	if (!down_read_trylock(&bdi->wb_switch_rwsem))
+		return;
+
 	isw = kzalloc(sizeof(*isw), GFP_ATOMIC);
 	if (!isw)
-		return;
+		goto out_unlock;
 
 	/* find and pin the new wb */
 	rcu_read_lock();
@@ -469,7 +520,8 @@
 
 	/* while holding I_WB_SWITCH, no one else can update the association */
 	spin_lock(&inode->i_lock);
-	if (inode->i_state & (I_WB_SWITCH | I_FREEING) ||
+	if (!(inode->i_sb->s_flags & MS_ACTIVE) ||
+	    inode->i_state & (I_WB_SWITCH | I_FREEING) ||
 	    inode_to_wb(inode) == isw->new_wb) {
 		spin_unlock(&inode->i_lock);
 		goto out_free;
@@ -487,12 +539,17 @@
 	 * Let's continue after I_WB_SWITCH is guaranteed to be visible.
 	 */
 	call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn);
-	return;
+
+	atomic_inc(&isw_nr_in_flight);
+
+	goto out_unlock;
 
 out_free:
 	if (isw->new_wb)
 		wb_put(isw->new_wb);
 	kfree(isw);
+out_unlock:
+	up_read(&bdi->wb_switch_rwsem);
 }
 
 /**
@@ -527,10 +584,13 @@
 	spin_unlock(&inode->i_lock);
 
 	/*
-	 * A dying wb indicates that the memcg-blkcg mapping has changed
-	 * and a new wb is already serving the memcg.  Switch immediately.
+	 * A dying wb indicates that either the blkcg associated with the
+	 * memcg changed or the associated memcg is dying.  In the first
+	 * case, a replacement wb should already be available and we should
+	 * refresh the wb immediately.  In the second case, trying to
+	 * refresh will keep failing.
 	 */
-	if (unlikely(wb_dying(wbc->wb)))
+	if (unlikely(wb_dying(wbc->wb) && !css_is_dying(wbc->wb->memcg_css)))
 		inode_switch_wbs(inode, wbc->wb_id);
 }
 
@@ -723,11 +783,12 @@
 	 */
 	if (inode && inode_to_wb_is_valid(inode)) {
 		struct bdi_writeback *wb;
-		bool locked, congested;
+		struct wb_lock_cookie lock_cookie = {};
+		bool congested;
 
-		wb = unlocked_inode_to_wb_begin(inode, &locked);
+		wb = unlocked_inode_to_wb_begin(inode, &lock_cookie);
 		congested = wb_congested(wb, cong_bits);
-		unlocked_inode_to_wb_end(inode, locked);
+		unlocked_inode_to_wb_end(inode, &lock_cookie);
 		return congested;
 	}
 
@@ -842,8 +903,42 @@
 		wb_put(last_wb);
 }
 
+/**
+ * cgroup_writeback_umount - flush inode wb switches for umount
+ *
+ * This function is called when a super_block is about to be destroyed and
+ * flushes in-flight inode wb switches.  An inode wb switch goes through
+ * RCU and then workqueue, so the two need to be flushed in order to ensure
+ * that all previously scheduled switches are finished.  As wb switches are
+ * rare occurrences and synchronize_rcu() can take a while, perform
+ * flushing iff wb switches are in flight.
+ */
+void cgroup_writeback_umount(void)
+{
+	if (atomic_read(&isw_nr_in_flight)) {
+		/*
+		 * Use rcu_barrier() to wait for all pending callbacks to
+		 * ensure that all in-flight wb switches are in the workqueue.
+		 */
+		rcu_barrier();
+		flush_workqueue(isw_wq);
+	}
+}
+
+static int __init cgroup_writeback_init(void)
+{
+	isw_wq = alloc_workqueue("inode_switch_wbs", 0, 0);
+	if (!isw_wq)
+		return -ENOMEM;
+	return 0;
+}
+fs_initcall(cgroup_writeback_init);
+
 #else	/* CONFIG_CGROUP_WRITEBACK */
 
+static void bdi_down_write_wb_switch_rwsem(struct backing_dev_info *bdi) { }
+static void bdi_up_write_wb_switch_rwsem(struct backing_dev_info *bdi) { }
+
 static struct bdi_writeback *
 locked_inode_to_wb_and_lock_list(struct inode *inode)
 	__releases(&inode->i_lock)
@@ -940,7 +1035,9 @@
 	struct bdi_writeback *wb;
 
 	wb = inode_to_wb_and_lock_list(inode);
+	spin_lock(&inode->i_lock);
 	inode_io_list_del_locked(inode, wb);
+	spin_unlock(&inode->i_lock);
 	spin_unlock(&wb->list_lock);
 }
 
@@ -953,8 +1050,10 @@
  * the case then the inode must have been redirtied while it was being written
  * out and we don't reset its dirtied_when.
  */
-static void redirty_tail(struct inode *inode, struct bdi_writeback *wb)
+static void redirty_tail_locked(struct inode *inode, struct bdi_writeback *wb)
 {
+	assert_spin_locked(&inode->i_lock);
+
 	if (!list_empty(&wb->b_dirty)) {
 		struct inode *tail;
 
@@ -963,6 +1062,14 @@
 			inode->dirtied_when = jiffies;
 	}
 	inode_io_list_move_locked(inode, wb, &wb->b_dirty);
+	inode->i_state &= ~I_SYNC_QUEUED;
+}
+
+static void redirty_tail(struct inode *inode, struct bdi_writeback *wb)
+{
+	spin_lock(&inode->i_lock);
+	redirty_tail_locked(inode, wb);
+	spin_unlock(&inode->i_lock);
 }
 
 /*
@@ -1001,16 +1108,13 @@
 #define EXPIRE_DIRTY_ATIME 0x0001
 
 /*
- * Move expired (dirtied before work->older_than_this) dirty inodes from
+ * Move expired (dirtied before dirtied_before) dirty inodes from
  * @delaying_queue to @dispatch_queue.
  */
 static int move_expired_inodes(struct list_head *delaying_queue,
 			       struct list_head *dispatch_queue,
-			       int flags,
-			       struct wb_writeback_work *work)
+			       int flags, unsigned long dirtied_before)
 {
-	unsigned long *older_than_this = NULL;
-	unsigned long expire_time;
 	LIST_HEAD(tmp);
 	struct list_head *pos, *node;
 	struct super_block *sb = NULL;
@@ -1018,21 +1122,17 @@
 	int do_sb_sort = 0;
 	int moved = 0;
 
-	if ((flags & EXPIRE_DIRTY_ATIME) == 0)
-		older_than_this = work->older_than_this;
-	else if (!work->for_sync) {
-		expire_time = jiffies - (dirtytime_expire_interval * HZ);
-		older_than_this = &expire_time;
-	}
 	while (!list_empty(delaying_queue)) {
 		inode = wb_inode(delaying_queue->prev);
-		if (older_than_this &&
-		    inode_dirtied_after(inode, *older_than_this))
+		if (inode_dirtied_after(inode, dirtied_before))
 			break;
 		list_move(&inode->i_io_list, &tmp);
 		moved++;
+		spin_lock(&inode->i_lock);
 		if (flags & EXPIRE_DIRTY_ATIME)
-			set_bit(__I_DIRTY_TIME_EXPIRED, &inode->i_state);
+			inode->i_state |= I_DIRTY_TIME_EXPIRED;
+		inode->i_state |= I_SYNC_QUEUED;
+		spin_unlock(&inode->i_lock);
 		if (sb_is_blkdev_sb(inode->i_sb))
 			continue;
 		if (sb && sb != inode->i_sb)
@@ -1070,18 +1170,22 @@
  *                                           |
  *                                           +--> dequeue for IO
  */
-static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work)
+static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work,
+		     unsigned long dirtied_before)
 {
 	int moved;
+	unsigned long time_expire_jif = dirtied_before;
 
 	assert_spin_locked(&wb->list_lock);
 	list_splice_init(&wb->b_more_io, &wb->b_io);
-	moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, 0, work);
+	moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, 0, dirtied_before);
+	if (!work->for_sync)
+		time_expire_jif = jiffies - dirtytime_expire_interval * HZ;
 	moved += move_expired_inodes(&wb->b_dirty_time, &wb->b_io,
-				     EXPIRE_DIRTY_ATIME, work);
+				     EXPIRE_DIRTY_ATIME, time_expire_jif);
 	if (moved)
 		wb_io_lists_populated(wb);
-	trace_writeback_queue_io(wb, work, moved);
+	trace_writeback_queue_io(wb, work, dirtied_before, moved);
 }
 
 static int write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -1175,7 +1279,7 @@
 		 * writeback is not making progress due to locked
 		 * buffers. Skip this inode for now.
 		 */
-		redirty_tail(inode, wb);
+		redirty_tail_locked(inode, wb);
 		return;
 	}
 
@@ -1195,7 +1299,7 @@
 			 * retrying writeback of the dirty page/inode
 			 * that cannot be performed immediately.
 			 */
-			redirty_tail(inode, wb);
+			redirty_tail_locked(inode, wb);
 		}
 	} else if (inode->i_state & I_DIRTY) {
 		/*
@@ -1203,10 +1307,11 @@
 		 * such as delayed allocation during submission or metadata
 		 * updates after data IO completion.
 		 */
-		redirty_tail(inode, wb);
+		redirty_tail_locked(inode, wb);
 	} else if (inode->i_state & I_DIRTY_TIME) {
 		inode->dirtied_when = jiffies;
 		inode_io_list_move_locked(inode, wb, &wb->b_dirty_time);
+		inode->i_state &= ~I_SYNC_QUEUED;
 	} else {
 		/* The inode is clean. Remove from writeback lists. */
 		inode_io_list_del_locked(inode, wb);
@@ -1255,6 +1360,7 @@
 	dirty = inode->i_state & I_DIRTY;
 	if (inode->i_state & I_DIRTY_TIME) {
 		if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
+		    wbc->sync_mode == WB_SYNC_ALL ||
 		    unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) ||
 		    unlikely(time_after(jiffies,
 					(inode->dirtied_time_when +
@@ -1304,10 +1410,10 @@
  * we go e.g. from filesystem. Flusher thread uses __writeback_single_inode()
  * and does more profound writeback list handling in writeback_sb_inodes().
  */
-static int
-writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
-		       struct writeback_control *wbc)
+static int writeback_single_inode(struct inode *inode,
+				  struct writeback_control *wbc)
 {
+	struct bdi_writeback *wb;
 	int ret = 0;
 
 	spin_lock(&inode->i_lock);
@@ -1345,7 +1451,8 @@
 	ret = __writeback_single_inode(inode, wbc);
 
 	wbc_detach_inode(wbc);
-	spin_lock(&wb->list_lock);
+
+	wb = inode_to_wb_and_lock_list(inode);
 	spin_lock(&inode->i_lock);
 	/*
 	 * If inode is clean, remove it from writeback lists. Otherwise don't
@@ -1420,6 +1527,7 @@
 
 	while (!list_empty(&wb->b_io)) {
 		struct inode *inode = wb_inode(wb->b_io.prev);
+		struct bdi_writeback *tmp_wb;
 
 		if (inode->i_sb != sb) {
 			if (work->sb) {
@@ -1447,8 +1555,8 @@
 		 */
 		spin_lock(&inode->i_lock);
 		if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+			redirty_tail_locked(inode, wb);
 			spin_unlock(&inode->i_lock);
-			redirty_tail(inode, wb);
 			continue;
 		}
 		if ((inode->i_state & I_SYNC) && wbc.sync_mode != WB_SYNC_ALL) {
@@ -1510,15 +1618,23 @@
 			cond_resched();
 		}
 
-
-		spin_lock(&wb->list_lock);
+		/*
+		 * Requeue @inode if still dirty.  Be careful as @inode may
+		 * have been switched to another wb in the meantime.
+		 */
+		tmp_wb = inode_to_wb_and_lock_list(inode);
 		spin_lock(&inode->i_lock);
 		if (!(inode->i_state & I_DIRTY_ALL))
 			wrote++;
-		requeue_inode(inode, wb, &wbc);
+		requeue_inode(inode, tmp_wb, &wbc);
 		inode_sync_complete(inode);
 		spin_unlock(&inode->i_lock);
 
+		if (unlikely(tmp_wb != wb)) {
+			spin_unlock(&tmp_wb->list_lock);
+			spin_lock(&wb->list_lock);
+		}
+
 		/*
 		 * bail out to wb_writeback() often enough to check
 		 * background threshold and other termination conditions.
@@ -1581,7 +1697,7 @@
 	blk_start_plug(&plug);
 	spin_lock(&wb->list_lock);
 	if (list_empty(&wb->b_io))
-		queue_io(wb, &work);
+		queue_io(wb, &work, jiffies);
 	__writeback_inodes_wb(wb, &work);
 	spin_unlock(&wb->list_lock);
 	blk_finish_plug(&plug);
@@ -1601,7 +1717,7 @@
  * takes longer than a dirty_writeback_interval interval, then leave a
  * one-second gap.
  *
- * older_than_this takes precedence over nr_to_write.  So we'll only write back
+ * dirtied_before takes precedence over nr_to_write.  So we'll only write back
  * all dirty pages if they are all attached to "old" mappings.
  */
 static long wb_writeback(struct bdi_writeback *wb,
@@ -1609,14 +1725,11 @@
 {
 	unsigned long wb_start = jiffies;
 	long nr_pages = work->nr_pages;
-	unsigned long oldest_jif;
+	unsigned long dirtied_before = jiffies;
 	struct inode *inode;
 	long progress;
 	struct blk_plug plug;
 
-	oldest_jif = jiffies;
-	work->older_than_this = &oldest_jif;
-
 	blk_start_plug(&plug);
 	spin_lock(&wb->list_lock);
 	for (;;) {
@@ -1650,14 +1763,14 @@
 		 * safe.
 		 */
 		if (work->for_kupdate) {
-			oldest_jif = jiffies -
+			dirtied_before = jiffies -
 				msecs_to_jiffies(dirty_expire_interval * 10);
 		} else if (work->for_background)
-			oldest_jif = jiffies;
+			dirtied_before = jiffies;
 
 		trace_writeback_start(wb, work);
 		if (list_empty(&wb->b_io))
-			queue_io(wb, work);
+			queue_io(wb, work, dirtied_before);
 		if (work->sb)
 			progress = writeback_sb_inodes(work->sb, wb, work);
 		else
@@ -1792,16 +1905,9 @@
 
 	set_bit(WB_writeback_running, &wb->state);
 	while ((work = get_next_work_item(wb)) != NULL) {
-		struct wb_completion *done = work->done;
-
 		trace_writeback_exec(wb, work);
-
 		wrote += wb_writeback(wb, work);
-
-		if (work->auto_free)
-			kfree(work);
-		if (done && atomic_dec_and_test(&done->cnt))
-			wake_up_all(&wb->bdi->wb_waitq);
+		finish_writeback_work(wb, work);
 	}
 
 	/*
@@ -1824,7 +1930,7 @@
 						struct bdi_writeback, dwork);
 	long pages_written;
 
-	set_worker_desc("flush-%s", dev_name(wb->bdi->dev));
+	set_worker_desc("flush-%s", bdi_dev_name(wb->bdi));
 	current->flags |= PF_SWAPWRITE;
 
 	if (likely(!current_is_workqueue_rescuer() ||
@@ -1851,7 +1957,7 @@
 	}
 
 	if (!list_empty(&wb->work_list))
-		mod_delayed_work(bdi_wq, &wb->dwork, 0);
+		wb_wakeup(wb);
 	else if (wb_has_dirty_io(wb) && dirty_writeback_interval)
 		wb_wakeup_delayed(wb);
 
@@ -2031,11 +2137,12 @@
 		inode->i_state |= flags;
 
 		/*
-		 * If the inode is being synced, just update its dirty state.
-		 * The unlocker will place the inode on the appropriate
-		 * superblock list, based upon its state.
+		 * If the inode is queued for writeback by flush worker, just
+		 * update its dirty state. Once the flush worker is done with
+		 * the inode it will place it on the appropriate superblock
+		 * list, based upon its state.
 		 */
-		if (inode->i_state & I_SYNC)
+		if (inode->i_state & I_SYNC_QUEUED)
 			goto out_unlock_inode;
 
 		/*
@@ -2286,8 +2393,11 @@
 		return;
 	WARN_ON(!rwsem_is_locked(&sb->s_umount));
 
+	/* protect against inode wb switch, see inode_switch_wbs_work_fn() */
+	bdi_down_write_wb_switch_rwsem(bdi);
 	bdi_split_work_to_wbs(bdi, &work, false);
 	wb_wait_for_completion(bdi, &done);
+	bdi_up_write_wb_switch_rwsem(bdi);
 
 	wait_sb_inodes(sb);
 }
@@ -2305,7 +2415,6 @@
  */
 int write_inode_now(struct inode *inode, int sync)
 {
-	struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
 	struct writeback_control wbc = {
 		.nr_to_write = LONG_MAX,
 		.sync_mode = sync ? WB_SYNC_ALL : WB_SYNC_NONE,
@@ -2317,7 +2426,7 @@
 		wbc.nr_to_write = 0;
 
 	might_sleep();
-	return writeback_single_inode(inode, wb, &wbc);
+	return writeback_single_inode(inode, &wbc);
 }
 EXPORT_SYMBOL(write_inode_now);
 
@@ -2334,7 +2443,7 @@
  */
 int sync_inode(struct inode *inode, struct writeback_control *wbc)
 {
-	return writeback_single_inode(inode, &inode_to_bdi(inode)->wb, wbc);
+	return writeback_single_inode(inode, wbc);
 }
 EXPORT_SYMBOL(sync_inode);
 
--- linux-4.4.0.orig/fs/fscache/cache.c
+++ linux-4.4.0/fs/fscache/cache.c
@@ -220,6 +220,7 @@
 {
 	struct fscache_cache_tag *tag;
 
+	ASSERTCMP(ifsdef->cookie, ==, &fscache_fsdef_index);
 	BUG_ON(!cache->ops);
 	BUG_ON(!ifsdef);
 
@@ -248,7 +249,6 @@
 	if (!cache->kobj)
 		goto error;
 
-	ifsdef->cookie = &fscache_fsdef_index;
 	ifsdef->cache = cache;
 	cache->fsdef = ifsdef;
 
--- linux-4.4.0.orig/fs/fscache/cookie.c
+++ linux-4.4.0/fs/fscache/cookie.c
@@ -302,6 +302,7 @@
 		goto error;
 	}
 
+	ASSERTCMP(object->cookie, ==, cookie);
 	fscache_stat(&fscache_n_object_alloc);
 
 	object->debug_id = atomic_inc_return(&fscache_object_debug_id);
@@ -357,6 +358,8 @@
 
 	_enter("{%s},{OBJ%x}", cookie->def->name, object->debug_id);
 
+	ASSERTCMP(object->cookie, ==, cookie);
+
 	spin_lock(&cookie->lock);
 
 	/* there may be multiple initial creations of this object, but we only
@@ -396,9 +399,7 @@
 		spin_unlock(&cache->object_list_lock);
 	}
 
-	/* attach to the cookie */
-	object->cookie = cookie;
-	atomic_inc(&cookie->usage);
+	/* Attach to the cookie.  The object already has a ref on it. */
 	hlist_add_head(&object->cookie_link, &cookie->backing_objects);
 
 	fscache_objlist_add(object);
@@ -542,6 +543,7 @@
 		hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) {
 			if (invalidate)
 				set_bit(FSCACHE_OBJECT_RETIRED, &object->flags);
+			clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
 			fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL);
 		}
 	} else {
@@ -560,6 +562,10 @@
 		wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t,
 				 TASK_UNINTERRUPTIBLE);
 
+	/* Make sure any pending writes are cancelled. */
+	if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
+		fscache_invalidate_writes(cookie);
+
 	/* Reset the cookie state if it wasn't relinquished */
 	if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) {
 		atomic_inc(&cookie->n_active);
--- linux-4.4.0.orig/fs/fscache/netfs.c
+++ linux-4.4.0/fs/fscache/netfs.c
@@ -48,6 +48,7 @@
 	cookie->flags		= 1 << FSCACHE_COOKIE_ENABLED;
 
 	spin_lock_init(&cookie->lock);
+	spin_lock_init(&cookie->stores_lock);
 	INIT_HLIST_HEAD(&cookie->backing_objects);
 
 	/* check the netfs type is not already present */
--- linux-4.4.0.orig/fs/fscache/object-list.c
+++ linux-4.4.0/fs/fscache/object-list.c
@@ -330,6 +330,13 @@
 	rcu_read_lock();
 
 	confkey = user_key_payload(key);
+	if (!confkey) {
+		/* key was revoked */
+		rcu_read_unlock();
+		key_put(key);
+		goto no_config;
+	}
+
 	buf = confkey->data;
 
 	for (len = confkey->datalen - 1; len >= 0; len--) {
--- linux-4.4.0.orig/fs/fscache/object.c
+++ linux-4.4.0/fs/fscache/object.c
@@ -30,6 +30,7 @@
 static const struct fscache_state *fscache_object_available(struct fscache_object *, int);
 static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int);
 static const struct fscache_state *fscache_update_object(struct fscache_object *, int);
+static const struct fscache_state *fscache_object_dead(struct fscache_object *, int);
 
 #define __STATE_NAME(n) fscache_osm_##n
 #define STATE(n) (&__STATE_NAME(n))
@@ -91,7 +92,7 @@
 static WORK_STATE(KILL_OBJECT,		"KILL", fscache_kill_object);
 static WORK_STATE(KILL_DEPENDENTS,	"KDEP", fscache_kill_dependents);
 static WORK_STATE(DROP_OBJECT,		"DROP", fscache_drop_object);
-static WORK_STATE(OBJECT_DEAD,		"DEAD", (void*)2UL);
+static WORK_STATE(OBJECT_DEAD,		"DEAD", fscache_object_dead);
 
 static WAIT_STATE(WAIT_FOR_INIT,	"?INI",
 		  TRANSIT_TO(INIT_OBJECT,	1 << FSCACHE_OBJECT_EV_NEW_CHILD));
@@ -229,6 +230,10 @@
 	event = -1;
 	if (new_state == NO_TRANSIT) {
 		_debug("{OBJ%x} %s notrans", object->debug_id, state->name);
+		if (unlikely(state == STATE(OBJECT_DEAD))) {
+			_leave(" [dead]");
+			return;
+		}
 		fscache_enqueue_object(object);
 		event_mask = object->oob_event_mask;
 		goto unmask_events;
@@ -239,7 +244,7 @@
 	object->state = state = new_state;
 
 	if (state->work) {
-		if (unlikely(state->work == ((void *)2UL))) {
+		if (unlikely(state == STATE(OBJECT_DEAD))) {
 			_leave(" [dead]");
 			return;
 		}
@@ -313,6 +318,7 @@
 	object->store_limit_l = 0;
 	object->cache = cache;
 	object->cookie = cookie;
+	atomic_inc(&cookie->usage);
 	object->parent = NULL;
 #ifdef CONFIG_FSCACHE_OBJECT_LIST
 	RB_CLEAR_NODE(&object->objlist_link);
@@ -645,6 +651,12 @@
 	fscache_mark_object_dead(object);
 	object->oob_event_mask = 0;
 
+	if (test_bit(FSCACHE_OBJECT_RETIRED, &object->flags)) {
+		/* Reject any new read/write ops and abort any that are pending. */
+		clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
+		fscache_cancel_all_ops(object);
+	}
+
 	if (list_empty(&object->dependents) &&
 	    object->n_ops == 0 &&
 	    object->n_children == 0)
@@ -704,6 +716,9 @@
 
 	if (awaken)
 		wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING);
+	if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags))
+		wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
+
 
 	/* Prevent a race with our last child, which has to signal EV_CLEARED
 	 * before dropping our spinlock.
@@ -1077,3 +1092,20 @@
 	}
 }
 EXPORT_SYMBOL(fscache_object_mark_killed);
+
+/*
+ * The object is dead.  We can get here if an object gets queued by an event
+ * that would lead to its death (such as EV_KILL) when the dispatcher is
+ * already running (and so can be requeued) but hasn't yet cleared the event
+ * mask.
+ */
+static const struct fscache_state *fscache_object_dead(struct fscache_object *object,
+						       int event)
+{
+	if (!test_and_set_bit(FSCACHE_OBJECT_RUN_AFTER_DEAD,
+			      &object->flags))
+		return NO_TRANSIT;
+
+	WARN(true, "FS-Cache object redispatched after death");
+	return NO_TRANSIT;
+}
--- linux-4.4.0.orig/fs/fscache/operation.c
+++ linux-4.4.0/fs/fscache/operation.c
@@ -66,7 +66,8 @@
 	ASSERT(op->processor != NULL);
 	ASSERT(fscache_object_is_available(op->object));
 	ASSERTCMP(atomic_read(&op->usage), >, 0);
-	ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS);
+	ASSERTIFCMP(op->state != FSCACHE_OP_ST_IN_PROGRESS,
+		    op->state, ==,  FSCACHE_OP_ST_CANCELLED);
 
 	fscache_stat(&fscache_n_op_enqueue);
 	switch (op->flags & FSCACHE_OP_TYPE) {
@@ -481,7 +482,8 @@
 	struct fscache_cache *cache;
 
 	_enter("{OBJ%x OP%x,%d}",
-	       op->object->debug_id, op->debug_id, atomic_read(&op->usage));
+	       op->object ? op->object->debug_id : 0,
+	       op->debug_id, atomic_read(&op->usage));
 
 	ASSERTCMP(atomic_read(&op->usage), >, 0);
 
--- linux-4.4.0.orig/fs/fscache/page.c
+++ linux-4.4.0/fs/fscache/page.c
@@ -776,6 +776,7 @@
 
 	_enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage));
 
+again:
 	spin_lock(&object->lock);
 	cookie = object->cookie;
 
@@ -816,10 +817,6 @@
 		goto superseded;
 	page = results[0];
 	_debug("gang %d [%lx]", n, page->index);
-	if (page->index >= op->store_limit) {
-		fscache_stat(&fscache_n_store_pages_over_limit);
-		goto superseded;
-	}
 
 	radix_tree_tag_set(&cookie->stores, page->index,
 			   FSCACHE_COOKIE_STORING_TAG);
@@ -829,6 +826,9 @@
 	spin_unlock(&cookie->stores_lock);
 	spin_unlock(&object->lock);
 
+	if (page->index >= op->store_limit)
+		goto discard_page;
+
 	fscache_stat(&fscache_n_store_pages);
 	fscache_stat(&fscache_n_cop_write_page);
 	ret = object->cache->ops->write_page(op, page);
@@ -844,6 +844,11 @@
 	_leave("");
 	return;
 
+discard_page:
+	fscache_stat(&fscache_n_store_pages_over_limit);
+	fscache_end_page_write(object, page);
+	goto again;
+
 superseded:
 	/* this writer is going away and there aren't any more things to
 	 * write */
--- linux-4.4.0.orig/fs/fuse/control.c
+++ linux-4.4.0/fs/fuse/control.c
@@ -107,7 +107,7 @@
 	if (!fc)
 		return 0;
 
-	val = fc->max_background;
+	val = READ_ONCE(fc->max_background);
 	fuse_conn_put(fc);
 
 	return fuse_conn_limit_read(file, buf, len, ppos, val);
@@ -144,7 +144,7 @@
 	if (!fc)
 		return 0;
 
-	val = fc->congestion_threshold;
+	val = READ_ONCE(fc->congestion_threshold);
 	fuse_conn_put(fc);
 
 	return fuse_conn_limit_read(file, buf, len, ppos, val);
@@ -211,10 +211,11 @@
 	if (!dentry)
 		return NULL;
 
-	fc->ctl_dentry[fc->ctl_ndents++] = dentry;
 	inode = new_inode(fuse_control_sb);
-	if (!inode)
+	if (!inode) {
+		dput(dentry);
 		return NULL;
+	}
 
 	inode->i_ino = get_next_ino();
 	inode->i_mode = mode;
@@ -228,6 +229,9 @@
 	set_nlink(inode, nlink);
 	inode->i_private = fc;
 	d_add(dentry, inode);
+
+	fc->ctl_dentry[fc->ctl_ndents++] = dentry;
+
 	return dentry;
 }
 
@@ -284,7 +288,10 @@
 	for (i = fc->ctl_ndents - 1; i >= 0; i--) {
 		struct dentry *dentry = fc->ctl_dentry[i];
 		d_inode(dentry)->i_private = NULL;
-		d_drop(dentry);
+		if (!i) {
+			/* Get rid of submounts: */
+			d_invalidate(dentry);
+		}
 		dput(dentry);
 	}
 	drop_nlink(d_inode(fuse_control_sb->s_root));
--- linux-4.4.0.orig/fs/fuse/cuse.c
+++ linux-4.4.0/fs/fuse/cuse.c
@@ -48,6 +48,7 @@
 #include <linux/stat.h>
 #include <linux/module.h>
 #include <linux/uio.h>
+#include <linux/user_namespace.h>
 
 #include "fuse_i.h"
 
@@ -90,7 +91,7 @@
 
 static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 {
-	struct fuse_io_priv io = { .async = 0, .file = kiocb->ki_filp };
+	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb->ki_filp);
 	loff_t pos = 0;
 
 	return fuse_direct_io(&io, to, &pos, FUSE_DIO_CUSE);
@@ -98,7 +99,7 @@
 
 static ssize_t cuse_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 {
-	struct fuse_io_priv io = { .async = 0, .file = kiocb->ki_filp };
+	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb->ki_filp);
 	loff_t pos = 0;
 	/*
 	 * No locking or generic_write_checks(), the server is
@@ -498,7 +499,7 @@
 	if (!cc)
 		return -ENOMEM;
 
-	fuse_conn_init(&cc->fc);
+	fuse_conn_init(&cc->fc, current_user_ns());
 
 	fud = fuse_dev_alloc(&cc->fc);
 	if (!fud) {
@@ -513,6 +514,7 @@
 	rc = cuse_send_init(cc);
 	if (rc) {
 		fuse_dev_free(fud);
+		fuse_conn_put(&cc->fc);
 		return rc;
 	}
 	file->private_data = fud;
--- linux-4.4.0.orig/fs/fuse/dev.c
+++ linux-4.4.0/fs/fuse/dev.c
@@ -19,6 +19,7 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/swap.h>
 #include <linux/splice.h>
+#include <linux/sched.h>
 
 MODULE_ALIAS_MISCDEV(FUSE_MINOR);
 MODULE_ALIAS("devname:fuse");
@@ -124,11 +125,11 @@
 	atomic_dec(&req->count);
 }
 
-static void fuse_req_init_context(struct fuse_req *req)
+static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
 {
-	req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
-	req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
-	req->in.h.pid = current->pid;
+	req->in.h.uid = from_kuid(fc->user_ns, current_fsuid());
+	req->in.h.gid = from_kgid(fc->user_ns, current_fsgid());
+	req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
 }
 
 void fuse_set_initialized(struct fuse_conn *fc)
@@ -143,6 +144,20 @@
 	return !fc->initialized || (for_background && fc->blocked);
 }
 
+static void fuse_drop_waiting(struct fuse_conn *fc)
+{
+	/*
+	 * lockess check of fc->connected is okay, because atomic_dec_and_test()
+	 * provides a memory barrier mached with the one in fuse_wait_aborted()
+	 * to ensure no wake-up is missed.
+	 */
+	if (atomic_dec_and_test(&fc->num_waiting) &&
+	    !READ_ONCE(fc->connected)) {
+		/* wake up aborters */
+		wake_up_all(&fc->blocked_waitq);
+	}
+}
+
 static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
 				       bool for_background)
 {
@@ -181,15 +196,19 @@
 		goto out;
 	}
 
-	fuse_req_init_context(req);
+	fuse_req_init_context(fc, req);
 	__set_bit(FR_WAITING, &req->flags);
 	if (for_background)
 		__set_bit(FR_BACKGROUND, &req->flags);
+	if (req->in.h.uid == (uid_t)-1 || req->in.h.gid == (gid_t)-1) {
+		fuse_put_request(fc, req);
+		return ERR_PTR(-EOVERFLOW);
+	}
 
 	return req;
 
  out:
-	atomic_dec(&fc->num_waiting);
+	fuse_drop_waiting(fc);
 	return ERR_PTR(err);
 }
 
@@ -274,7 +293,7 @@
 	if (!req)
 		req = get_reserved_req(fc, file);
 
-	fuse_req_init_context(req);
+	fuse_req_init_context(fc, req);
 	__set_bit(FR_WAITING, &req->flags);
 	__clear_bit(FR_BACKGROUND, &req->flags);
 	return req;
@@ -296,7 +315,7 @@
 
 		if (test_bit(FR_WAITING, &req->flags)) {
 			__clear_bit(FR_WAITING, &req->flags);
-			atomic_dec(&fc->num_waiting);
+			fuse_drop_waiting(fc);
 		}
 
 		if (req->stolen_file)
@@ -382,7 +401,7 @@
 	struct fuse_iqueue *fiq = &fc->iq;
 
 	if (test_and_set_bit(FR_FINISHED, &req->flags))
-		return;
+		goto put_request;
 
 	spin_lock(&fiq->waitq.lock);
 	list_del_init(&req->intr_entry);
@@ -392,12 +411,19 @@
 	if (test_bit(FR_BACKGROUND, &req->flags)) {
 		spin_lock(&fc->lock);
 		clear_bit(FR_BACKGROUND, &req->flags);
-		if (fc->num_background == fc->max_background)
+		if (fc->num_background == fc->max_background) {
 			fc->blocked = 0;
-
-		/* Wake up next waiter, if any */
-		if (!fc->blocked && waitqueue_active(&fc->blocked_waitq))
 			wake_up(&fc->blocked_waitq);
+		} else if (!fc->blocked) {
+			/*
+			 * Wake up next waiter, if any.  It's okay to use
+			 * waitqueue_active(), as we've already synced up
+			 * fc->blocked with waiters with the wake_up() call
+			 * above.
+			 */
+			if (waitqueue_active(&fc->blocked_waitq))
+				wake_up(&fc->blocked_waitq);
+		}
 
 		if (fc->num_background == fc->congestion_threshold &&
 		    fc->connected && fc->bdi_initialized) {
@@ -412,12 +438,17 @@
 	wake_up(&req->waitq);
 	if (req->end)
 		req->end(fc, req);
+put_request:
 	fuse_put_request(fc, req);
 }
 
 static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
 {
 	spin_lock(&fiq->waitq.lock);
+	if (test_bit(FR_FINISHED, &req->flags)) {
+		spin_unlock(&fiq->waitq.lock);
+		return;
+	}
 	if (list_empty(&req->intr_entry)) {
 		list_add_tail(&req->intr_entry, &fiq->interrupts);
 		wake_up_locked(&fiq->waitq);
@@ -824,7 +855,6 @@
 {
 	if (page_mapcount(page) ||
 	    page->mapping != NULL ||
-	    page_count(page) != 1 ||
 	    (page->flags & PAGE_FLAGS_CHECK_AT_PREP &
 	     ~(1 << PG_locked |
 	       1 << PG_referenced |
@@ -1243,6 +1273,10 @@
 	struct fuse_in *in;
 	unsigned reqsize;
 
+	if (task_active_pid_ns(current) != fc->pid_ns ||
+	    current_user_ns() != fc->user_ns)
+		return -EIO;
+
  restart:
 	spin_lock(&fiq->waitq.lock);
 	err = -EAGAIN;
@@ -1313,12 +1347,14 @@
 		goto out_end;
 	}
 	list_move_tail(&req->list, &fpq->processing);
-	spin_unlock(&fpq->lock);
+	__fuse_get_request(req);
 	set_bit(FR_SENT, &req->flags);
+	spin_unlock(&fpq->lock);
 	/* matches barrier in request_wait_answer() */
 	smp_mb__after_atomic();
 	if (test_bit(FR_INTERRUPTED, &req->flags))
 		queue_interrupt(fiq, req);
+	fuse_put_request(fc, req);
 
 	return reqsize;
 
@@ -1654,9 +1690,11 @@
 
 		this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
 		err = fuse_copy_page(cs, &page, offset, this_num, 0);
-		if (!err && offset == 0 &&
-		    (this_num == PAGE_CACHE_SIZE || file_size == end))
+		if (!PageUptodate(page) && !err && offset == 0 &&
+		    (this_num == PAGE_CACHE_SIZE || file_size == end)) {
+			zero_user_segment(page, this_num, PAGE_SIZE);
 			SetPageUptodate(page);
+		}
 		unlock_page(page);
 		page_cache_release(page);
 
@@ -1700,7 +1738,7 @@
 	offset = outarg->offset & ~PAGE_CACHE_MASK;
 	file_size = i_size_read(inode);
 
-	num = outarg->size;
+	num = min(outarg->size, fc->max_write);
 	if (outarg->offset > file_size)
 		num = 0;
 	else if (outarg->offset + num > file_size)
@@ -1717,7 +1755,6 @@
 	req->in.h.nodeid = outarg->nodeid;
 	req->in.numargs = 2;
 	req->in.argpages = 1;
-	req->page_descs[0].offset = offset;
 	req->end = fuse_retrieve_end;
 
 	index = outarg->offset >> PAGE_CACHE_SHIFT;
@@ -1732,6 +1769,7 @@
 
 		this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
 		req->pages[req->num_pages] = page;
+		req->page_descs[req->num_pages].offset = offset;
 		req->page_descs[req->num_pages].length = this_num;
 		req->num_pages++;
 
@@ -1747,8 +1785,10 @@
 	req->in.args[1].size = total_len;
 
 	err = fuse_request_send_notify_reply(fc, req, outarg->notify_unique);
-	if (err)
+	if (err) {
 		fuse_retrieve_end(fc, req);
+		fuse_put_request(fc, req);
+	}
 
 	return err;
 }
@@ -1872,6 +1912,10 @@
 	struct fuse_req *req;
 	struct fuse_out_header oh;
 
+	if (task_active_pid_ns(current) != fc->pid_ns ||
+	    current_user_ns() != fc->user_ns)
+		return -EIO;
+
 	if (nbytes < sizeof(struct fuse_out_header))
 		return -EINVAL;
 
@@ -1907,16 +1951,20 @@
 
 	/* Is it an interrupt reply? */
 	if (req->intr_unique == oh.unique) {
+		__fuse_get_request(req);
 		spin_unlock(&fpq->lock);
 
 		err = -EINVAL;
-		if (nbytes != sizeof(struct fuse_out_header))
+		if (nbytes != sizeof(struct fuse_out_header)) {
+			fuse_put_request(fc, req);
 			goto err_finish;
+		}
 
 		if (oh.error == -ENOSYS)
 			fc->no_interrupt = 1;
 		else if (oh.error == -EAGAIN)
 			queue_interrupt(&fc->iq, req);
+		fuse_put_request(fc, req);
 
 		fuse_copy_finish(cs);
 		return nbytes;
@@ -1987,21 +2035,22 @@
 	if (!fud)
 		return -EPERM;
 
+	pipe_lock(pipe);
+
 	bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL);
-	if (!bufs)
+	if (!bufs) {
+		pipe_unlock(pipe);
 		return -ENOMEM;
+	}
 
-	pipe_lock(pipe);
 	nbuf = 0;
 	rem = 0;
 	for (idx = 0; idx < pipe->nrbufs && rem < len; idx++)
 		rem += pipe->bufs[(pipe->curbuf + idx) & (pipe->buffers - 1)].len;
 
 	ret = -EINVAL;
-	if (rem < len) {
-		pipe_unlock(pipe);
-		goto out;
-	}
+	if (rem < len)
+		goto out_free;
 
 	rem = len;
 	while (rem) {
@@ -2019,7 +2068,9 @@
 			pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
 			pipe->nrbufs--;
 		} else {
-			ibuf->ops->get(pipe, ibuf);
+			if (!pipe_buf_get(pipe, ibuf))
+				goto out_free;
+
 			*obuf = *ibuf;
 			obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
 			obuf->len = rem;
@@ -2041,11 +2092,14 @@
 
 	ret = fuse_dev_do_write(fud, &cs, len);
 
+	pipe_lock(pipe);
+out_free:
 	for (idx = 0; idx < nbuf; idx++) {
 		struct pipe_buffer *buf = &bufs[idx];
 		buf->ops->release(pipe, buf);
 	}
-out:
+	pipe_unlock(pipe);
+
 	kfree(bufs);
 	return ret;
 }
@@ -2083,7 +2137,6 @@
 		struct fuse_req *req;
 		req = list_entry(head->next, struct fuse_req, list);
 		req->out.h.error = -ECONNABORTED;
-		clear_bit(FR_PENDING, &req->flags);
 		clear_bit(FR_SENT, &req->flags);
 		list_del_init(&req->list);
 		request_end(fc, req);
@@ -2148,6 +2201,7 @@
 				set_bit(FR_ABORTED, &req->flags);
 				if (!test_bit(FR_LOCKED, &req->flags)) {
 					set_bit(FR_PRIVATE, &req->flags);
+					__fuse_get_request(req);
 					list_move(&req->list, &to_end1);
 				}
 				spin_unlock(&req->waitq.lock);
@@ -2161,6 +2215,8 @@
 		spin_lock(&fiq->waitq.lock);
 		fiq->connected = 0;
 		list_splice_init(&fiq->pending, &to_end2);
+		list_for_each_entry(req, &to_end2, list)
+			clear_bit(FR_PENDING, &req->flags);
 		while (forget_pending(fiq))
 			kfree(dequeue_forget(fiq, 1, NULL));
 		wake_up_all_locked(&fiq->waitq);
@@ -2172,7 +2228,6 @@
 
 		while (!list_empty(&to_end1)) {
 			req = list_first_entry(&to_end1, struct fuse_req, list);
-			__fuse_get_request(req);
 			list_del_init(&req->list);
 			request_end(fc, req);
 		}
@@ -2183,6 +2238,13 @@
 }
 EXPORT_SYMBOL_GPL(fuse_abort_conn);
 
+void fuse_wait_aborted(struct fuse_conn *fc)
+{
+	/* matches implicit memory barrier in fuse_drop_waiting() */
+	smp_mb();
+	wait_event(fc->blocked_waitq, atomic_read(&fc->num_waiting) == 0);
+}
+
 int fuse_dev_release(struct inode *inode, struct file *file)
 {
 	struct fuse_dev *fud = fuse_get_dev(file);
@@ -2190,9 +2252,15 @@
 	if (fud) {
 		struct fuse_conn *fc = fud->fc;
 		struct fuse_pqueue *fpq = &fud->pq;
+		LIST_HEAD(to_end);
 
+		spin_lock(&fpq->lock);
 		WARN_ON(!list_empty(&fpq->io));
-		end_requests(fc, &fpq->processing);
+		list_splice_init(&fpq->processing, &to_end);
+		spin_unlock(&fpq->lock);
+
+		end_requests(fc, &to_end);
+
 		/* Are we the last open device? */
 		if (atomic_dec_and_test(&fc->dev_count)) {
 			WARN_ON(fc->iq.fasync != NULL);
--- linux-4.4.0.orig/fs/fuse/dir.c
+++ linux-4.4.0/fs/fuse/dir.c
@@ -13,6 +13,8 @@
 #include <linux/sched.h>
 #include <linux/namei.h>
 #include <linux/slab.h>
+#include <uapi/linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
 
 static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx)
 {
@@ -193,7 +195,7 @@
 	int ret;
 
 	inode = d_inode_rcu(entry);
-	if (inode && is_bad_inode(inode))
+	if (inode && fuse_is_bad(inode))
 		goto invalid;
 	else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
 		 (flags & LOOKUP_REVAL)) {
@@ -240,7 +242,8 @@
 		kfree(forget);
 		if (ret == -ENOMEM)
 			goto out;
-		if (ret || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
+		if (ret || fuse_invalid_attr(&outarg.attr) ||
+		    (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
 			goto invalid;
 
 		fuse_change_attributes(inode, &outarg.attr,
@@ -282,6 +285,12 @@
 		S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
 }
 
+bool fuse_invalid_attr(struct fuse_attr *attr)
+{
+	return !fuse_valid_type(attr->mode) ||
+		attr->size > LLONG_MAX;
+}
+
 int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
 		     struct fuse_entry_out *outarg, struct inode **inode)
 {
@@ -313,7 +322,7 @@
 	err = -EIO;
 	if (!outarg->nodeid)
 		goto out_put_forget;
-	if (!fuse_valid_type(outarg->attr.mode))
+	if (fuse_invalid_attr(&outarg->attr))
 		goto out_put_forget;
 
 	*inode = fuse_iget(sb, outarg->nodeid, outarg->generation,
@@ -341,6 +350,9 @@
 	struct dentry *newent;
 	bool outarg_valid = true;
 
+	if (fuse_is_bad(dir))
+		return ERR_PTR(-EIO);
+
 	err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
 			       &outarg, &inode);
 	if (err == -ENOENT) {
@@ -433,7 +445,8 @@
 		goto out_free_ff;
 
 	err = -EIO;
-	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
+	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) ||
+	    fuse_invalid_attr(&outentry.attr))
 		goto out_free_ff;
 
 	ff->fh = outopen.fh;
@@ -478,6 +491,9 @@
 	struct fuse_conn *fc = get_fuse_conn(dir);
 	struct dentry *res = NULL;
 
+	if (fuse_is_bad(dir))
+		return -EIO;
+
 	if (d_unhashed(entry)) {
 		res = fuse_lookup(dir, entry, 0);
 		if (IS_ERR(res))
@@ -525,6 +541,9 @@
 	int err;
 	struct fuse_forget_link *forget;
 
+	if (fuse_is_bad(dir))
+		return -EIO;
+
 	forget = fuse_alloc_forget();
 	if (!forget)
 		return -ENOMEM;
@@ -539,7 +558,7 @@
 		goto out_put_forget_req;
 
 	err = -EIO;
-	if (invalid_nodeid(outarg.nodeid))
+	if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr))
 		goto out_put_forget_req;
 
 	if ((outarg.attr.mode ^ mode) & S_IFMT)
@@ -646,6 +665,9 @@
 	struct fuse_conn *fc = get_fuse_conn(dir);
 	FUSE_ARGS(args);
 
+	if (fuse_is_bad(dir))
+		return -EIO;
+
 	args.in.h.opcode = FUSE_UNLINK;
 	args.in.h.nodeid = get_node_id(dir);
 	args.in.numargs = 1;
@@ -682,6 +704,9 @@
 	struct fuse_conn *fc = get_fuse_conn(dir);
 	FUSE_ARGS(args);
 
+	if (fuse_is_bad(dir))
+		return -EIO;
+
 	args.in.h.opcode = FUSE_RMDIR;
 	args.in.h.nodeid = get_node_id(dir);
 	args.in.numargs = 1;
@@ -760,6 +785,9 @@
 	struct fuse_conn *fc = get_fuse_conn(olddir);
 	int err;
 
+	if (fuse_is_bad(olddir))
+		return -EIO;
+
 	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
 		return -EINVAL;
 
@@ -812,7 +840,8 @@
 
 		spin_lock(&fc->lock);
 		fi->attr_version = ++fc->attr_version;
-		inc_nlink(inode);
+		if (likely(inode->i_nlink < UINT_MAX))
+			inc_nlink(inode);
 		spin_unlock(&fc->lock);
 		fuse_invalidate_attr(inode);
 		fuse_update_ctime(inode);
@@ -841,8 +870,8 @@
 	stat->ino = attr->ino;
 	stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
 	stat->nlink = attr->nlink;
-	stat->uid = make_kuid(&init_user_ns, attr->uid);
-	stat->gid = make_kgid(&init_user_ns, attr->gid);
+	stat->uid = inode->i_uid;
+	stat->gid = inode->i_gid;
 	stat->rdev = inode->i_rdev;
 	stat->atime.tv_sec = attr->atime;
 	stat->atime.tv_nsec = attr->atimensec;
@@ -892,8 +921,9 @@
 	args.out.args[0].value = &outarg;
 	err = fuse_simple_request(fc, &args);
 	if (!err) {
-		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
-			make_bad_inode(inode);
+		if (fuse_invalid_attr(&outarg.attr) ||
+		    (inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
+			fuse_make_bad(inode);
 			err = -EIO;
 		} else {
 			fuse_change_attributes(inode, &outarg.attr,
@@ -1015,7 +1045,7 @@
 	const struct cred *cred;
 
 	if (fc->flags & FUSE_ALLOW_OTHER)
-		return 1;
+		return current_in_userns(fc->user_ns);
 
 	cred = current_cred();
 	if (uid_eq(cred->euid, fc->user_id) &&
@@ -1083,6 +1113,9 @@
 	bool refreshed = false;
 	int err = 0;
 
+	if (fuse_is_bad(inode))
+		return -EIO;
+
 	if (!fuse_allow_current_process(fc))
 		return -EACCES;
 
@@ -1197,7 +1230,7 @@
 
 	if (invalid_nodeid(o->nodeid))
 		return -EIO;
-	if (!fuse_valid_type(o->attr.mode))
+	if (fuse_invalid_attr(&o->attr))
 		return -EIO;
 
 	fc = get_fuse_conn(dir);
@@ -1231,6 +1264,10 @@
 			 */
 			goto found;
 		}
+		if (inode && fuse_is_bad(inode)) {
+			dput(dentry);
+			return -EIO;
+		}
 		dput(dentry);
 	}
 
@@ -1295,7 +1332,8 @@
 			*/
 			over = !dir_emit(ctx, dirent->name, dirent->namelen,
 				       dirent->ino, dirent->type);
-			ctx->pos = dirent->off;
+			if (!over)
+				ctx->pos = dirent->off;
 		}
 
 		buf += reclen;
@@ -1319,7 +1357,7 @@
 	struct fuse_req *req;
 	u64 attr_version = 0;
 
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		return -EIO;
 
 	req = fuse_get_req(fc, 1);
@@ -1373,6 +1411,9 @@
 	char *link;
 	ssize_t ret;
 
+	if (fuse_is_bad(inode))
+		return ERR_PTR(-EIO);
+
 	link = (char *) __get_free_page(GFP_KERNEL);
 	if (!link)
 		return ERR_PTR(-ENOMEM);
@@ -1455,17 +1496,17 @@
 	return true;
 }
 
-static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
-			   bool trust_local_cmtime)
+static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr,
+			   struct fuse_setattr_in *arg, bool trust_local_cmtime)
 {
 	unsigned ivalid = iattr->ia_valid;
 
 	if (ivalid & ATTR_MODE)
 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
 	if (ivalid & ATTR_UID)
-		arg->valid |= FATTR_UID,    arg->uid = from_kuid(&init_user_ns, iattr->ia_uid);
+		arg->valid |= FATTR_UID,    arg->uid = from_kuid(fc->user_ns, iattr->ia_uid);
 	if (ivalid & ATTR_GID)
-		arg->valid |= FATTR_GID,    arg->gid = from_kgid(&init_user_ns, iattr->ia_gid);
+		arg->valid |= FATTR_GID,    arg->gid = from_kgid(fc->user_ns, iattr->ia_gid);
 	if (ivalid & ATTR_SIZE)
 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
 	if (ivalid & ATTR_ATIME) {
@@ -1586,9 +1627,10 @@
  * vmtruncate() doesn't allow for this case, so do the rlimit checking
  * and the actual truncation by hand.
  */
-int fuse_do_setattr(struct inode *inode, struct iattr *attr,
+int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
 		    struct file *file)
 {
+	struct inode *inode = d_inode(dentry);
 	struct fuse_conn *fc = get_fuse_conn(inode);
 	struct fuse_inode *fi = get_fuse_inode(inode);
 	FUSE_ARGS(args);
@@ -1603,19 +1645,43 @@
 	if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
 		attr->ia_valid |= ATTR_FORCE;
 
-	err = inode_change_ok(inode, attr);
+	err = setattr_prepare(dentry, attr);
 	if (err)
 		return err;
 
 	if (attr->ia_valid & ATTR_OPEN) {
-		if (fc->atomic_o_trunc)
+		/* This is coming from open(..., ... | O_TRUNC); */
+		WARN_ON(!(attr->ia_valid & ATTR_SIZE));
+		WARN_ON(attr->ia_size != 0);
+		if (fc->atomic_o_trunc) {
+			/*
+			 * No need to send request to userspace, since actual
+			 * truncation has already been done by OPEN.  But still
+			 * need to truncate page cache.
+			 */
+			i_size_write(inode, 0);
+			truncate_pagecache(inode, 0);
 			return 0;
+		}
 		file = NULL;
 	}
 
 	if (attr->ia_valid & ATTR_SIZE)
 		is_truncate = true;
 
+	/* Flush dirty data/metadata before non-truncate SETATTR */
+	if (is_wb && S_ISREG(inode->i_mode) &&
+	    attr->ia_valid &
+			(ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_MTIME_SET |
+			 ATTR_TIMES_SET)) {
+		err = write_inode_now(inode, true);
+		if (err)
+			return err;
+
+		fuse_set_nowrite(inode);
+		fuse_release_nowrite(inode);
+	}
+
 	if (is_truncate) {
 		fuse_set_nowrite(inode);
 		set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
@@ -1625,7 +1691,7 @@
 
 	memset(&inarg, 0, sizeof(inarg));
 	memset(&outarg, 0, sizeof(outarg));
-	iattr_to_fattr(attr, &inarg, trust_local_cmtime);
+	iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime);
 	if (file) {
 		struct fuse_file *ff = file->private_data;
 		inarg.valid |= FATTR_FH;
@@ -1644,8 +1710,9 @@
 		goto error;
 	}
 
-	if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
-		make_bad_inode(inode);
+	if (fuse_invalid_attr(&outarg.attr) ||
+	    (inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
+		fuse_make_bad(inode);
 		err = -EIO;
 		goto error;
 	}
@@ -1697,14 +1764,49 @@
 static int fuse_setattr(struct dentry *entry, struct iattr *attr)
 {
 	struct inode *inode = d_inode(entry);
+	struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL;
+	int ret;
+
+	if (fuse_is_bad(inode))
+		return -EIO;
 
 	if (!fuse_allow_current_process(get_fuse_conn(inode)))
 		return -EACCES;
 
-	if (attr->ia_valid & ATTR_FILE)
-		return fuse_do_setattr(inode, attr, attr->ia_file);
-	else
-		return fuse_do_setattr(inode, attr, NULL);
+	if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) {
+		int kill;
+
+		attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID |
+				    ATTR_MODE);
+		/*
+		 * ia_mode calculation may have used stale i_mode.  Refresh and
+		 * recalculate.
+		 */
+		ret = fuse_do_getattr(inode, NULL, file);
+		if (ret)
+			return ret;
+
+		attr->ia_mode = inode->i_mode;
+		kill = should_remove_suid(entry);
+		if (kill & ATTR_KILL_SUID) {
+			attr->ia_valid |= ATTR_MODE;
+			attr->ia_mode &= ~S_ISUID;
+		}
+		if (kill & ATTR_KILL_SGID) {
+			attr->ia_valid |= ATTR_MODE;
+			attr->ia_mode &= ~S_ISGID;
+		}
+	}
+	if (!attr->ia_valid)
+		return 0;
+
+	ret = fuse_do_setattr(entry, attr, file);
+	if (!ret) {
+		/* Directory mode changed, may need to revalidate access */
+		if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE))
+			fuse_invalidate_entry_cache(entry);
+	}
+	return ret;
 }
 
 static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
@@ -1713,6 +1815,9 @@
 	struct inode *inode = d_inode(entry);
 	struct fuse_conn *fc = get_fuse_conn(inode);
 
+	if (fuse_is_bad(inode))
+		return -EIO;
+
 	if (!fuse_allow_current_process(fc))
 		return -EACCES;
 
@@ -1725,12 +1830,24 @@
 	struct inode *inode = d_inode(entry);
 	struct fuse_conn *fc = get_fuse_conn(inode);
 	FUSE_ARGS(args);
+	void *buf = NULL;
 	struct fuse_setxattr_in inarg;
 	int err;
 
 	if (fc->no_setxattr)
 		return -EOPNOTSUPP;
 
+	if (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ||
+	    !strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT)) {
+		buf = kmemdup(value, size, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+		err = posix_acl_fix_xattr_userns(inode->i_sb->s_user_ns,
+						 &init_user_ns, buf, size);
+		if (err)
+			goto out;
+	}
+
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.size = size;
 	inarg.flags = flags;
@@ -1742,7 +1859,7 @@
 	args.in.args[1].size = strlen(name) + 1;
 	args.in.args[1].value = name;
 	args.in.args[2].size = size;
-	args.in.args[2].value = value;
+	args.in.args[2].value = buf ? buf : value;
 	err = fuse_simple_request(fc, &args);
 	if (err == -ENOSYS) {
 		fc->no_setxattr = 1;
@@ -1752,6 +1869,8 @@
 		fuse_invalidate_attr(inode);
 		fuse_update_ctime(inode);
 	}
+out:
+	kfree(buf);
 	return err;
 }
 
@@ -1788,8 +1907,16 @@
 		args.out.args[0].value = &outarg;
 	}
 	ret = fuse_simple_request(fc, &args);
-	if (!ret && !size)
-		ret = outarg.size;
+	if (!ret) {
+		if (!size) {
+			ret = outarg.size;
+		} else if (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ||
+			   !strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT)) {
+			ret = posix_acl_fix_xattr_userns(&init_user_ns,
+							 inode->i_sb->s_user_ns,
+							 value, size);
+		}
+	}
 	if (ret == -ENOSYS) {
 		fc->no_getxattr = 1;
 		ret = -EOPNOTSUPP;
@@ -1797,6 +1924,23 @@
 	return ret;
 }
 
+static int fuse_verify_xattr_list(char *list, size_t size)
+{
+	size_t origsize = size;
+
+	while (size) {
+		size_t thislen = strnlen(list, size);
+
+		if (!thislen || thislen == size)
+			return -EIO;
+
+		size -= thislen + 1;
+		list += thislen + 1;
+	}
+
+	return origsize;
+}
+
 static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
 {
 	struct inode *inode = d_inode(entry);
@@ -1832,6 +1976,8 @@
 	ret = fuse_simple_request(fc, &args);
 	if (!ret && !size)
 		ret = outarg.size;
+	if (ret > 0 && size)
+		ret = fuse_verify_xattr_list(list, ret);
 	if (ret == -ENOSYS) {
 		fc->no_listxattr = 1;
 		ret = -EOPNOTSUPP;
--- linux-4.4.0.orig/fs/fuse/file.c
+++ linux-4.4.0/fs/fuse/file.c
@@ -17,6 +17,7 @@
 #include <linux/swap.h>
 #include <linux/falloc.h>
 #include <linux/uio.h>
+#include <linux/fs.h>
 
 static const struct file_operations fuse_direct_io_file_operations;
 
@@ -46,7 +47,7 @@
 {
 	struct fuse_file *ff;
 
-	ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
+	ff = kzalloc(sizeof(struct fuse_file), GFP_KERNEL);
 	if (unlikely(!ff))
 		return NULL;
 
@@ -100,6 +101,7 @@
 			iput(req->misc.release.inode);
 			fuse_put_request(ff->fc, req);
 		} else if (sync) {
+			__set_bit(FR_FORCE, &req->flags);
 			__clear_bit(FR_BACKGROUND, &req->flags);
 			fuse_request_send(ff->fc, req);
 			iput(req->misc.release.inode);
@@ -177,7 +179,9 @@
 		file->f_op = &fuse_direct_io_file_operations;
 	if (!(ff->open_flags & FOPEN_KEEP_CACHE))
 		invalidate_inode_pages2(inode->i_mapping);
-	if (ff->open_flags & FOPEN_NONSEEKABLE)
+	if (ff->open_flags & FOPEN_STREAM)
+		stream_open(inode, file);
+	else if (ff->open_flags & FOPEN_NONSEEKABLE)
 		nonseekable_open(inode, file);
 	if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) {
 		struct fuse_inode *fi = get_fuse_inode(inode);
@@ -198,24 +202,31 @@
 {
 	struct fuse_conn *fc = get_fuse_conn(inode);
 	int err;
-	bool lock_inode = (file->f_flags & O_TRUNC) &&
+	bool is_wb_truncate = (file->f_flags & O_TRUNC) &&
 			  fc->atomic_o_trunc &&
 			  fc->writeback_cache;
 
+	if (fuse_is_bad(inode))
+		return -EIO;
+
 	err = generic_file_open(inode, file);
 	if (err)
 		return err;
 
-	if (lock_inode)
+	if (is_wb_truncate) {
 		mutex_lock(&inode->i_mutex);
+		fuse_set_nowrite(inode);
+	}
 
 	err = fuse_do_open(fc, get_node_id(inode), file, isdir);
 
 	if (!err)
 		fuse_finish_open(inode, file);
 
-	if (lock_inode)
+	if (is_wb_truncate) {
+		fuse_release_nowrite(inode);
 		mutex_unlock(&inode->i_mutex);
+	}
 
 	return err;
 }
@@ -403,7 +414,7 @@
 	struct fuse_flush_in inarg;
 	int err;
 
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		return -EIO;
 
 	if (fc->no_flush)
@@ -417,6 +428,15 @@
 	fuse_sync_writes(inode);
 	mutex_unlock(&inode->i_mutex);
 
+	if (test_bit(AS_ENOSPC, &file->f_mapping->flags) &&
+	    test_and_clear_bit(AS_ENOSPC, &file->f_mapping->flags))
+		err = -ENOSPC;
+	if (test_bit(AS_EIO, &file->f_mapping->flags) &&
+	    test_and_clear_bit(AS_EIO, &file->f_mapping->flags))
+		err = -EIO;
+	if (err)
+		return err;
+
 	req = fuse_get_req_nofail_nopages(fc, file);
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.fh = ff->fh;
@@ -447,7 +467,7 @@
 	struct fuse_fsync_in inarg;
 	int err;
 
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		return -EIO;
 
 	mutex_lock(&inode->i_mutex);
@@ -462,6 +482,21 @@
 		goto out;
 
 	fuse_sync_writes(inode);
+
+	/*
+	 * Due to implementation of fuse writeback
+	 * filemap_write_and_wait_range() does not catch errors.
+	 * We have to do this directly after fuse_sync_writes()
+	 */
+	if (test_bit(AS_ENOSPC, &file->f_mapping->flags) &&
+	    test_and_clear_bit(AS_ENOSPC, &file->f_mapping->flags))
+		err = -ENOSPC;
+	if (test_bit(AS_EIO, &file->f_mapping->flags) &&
+	    test_and_clear_bit(AS_EIO, &file->f_mapping->flags))
+		err = -EIO;
+	if (err)
+		goto out;
+
 	err = sync_inode_metadata(inode, 1);
 	if (err)
 		goto out;
@@ -516,18 +551,23 @@
 	req->out.args[0].size = count;
 }
 
-static void fuse_release_user_pages(struct fuse_req *req, int write)
+static void fuse_release_user_pages(struct fuse_req *req, bool should_dirty)
 {
 	unsigned i;
 
 	for (i = 0; i < req->num_pages; i++) {
 		struct page *page = req->pages[i];
-		if (write)
+		if (should_dirty)
 			set_page_dirty_lock(page);
 		put_page(page);
 	}
 }
 
+static void fuse_io_release(struct kref *kref)
+{
+	kfree(container_of(kref, struct fuse_io_priv, refcnt));
+}
+
 static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io)
 {
 	if (io->err)
@@ -585,8 +625,9 @@
 		}
 
 		io->iocb->ki_complete(io->iocb, res, 0);
-		kfree(io);
 	}
+
+	kref_put(&io->refcnt, fuse_io_release);
 }
 
 static void fuse_aio_complete_req(struct fuse_conn *fc, struct fuse_req *req)
@@ -594,7 +635,7 @@
 	struct fuse_io_priv *io = req->io;
 	ssize_t pos = -1;
 
-	fuse_release_user_pages(req, !io->write);
+	fuse_release_user_pages(req, io->should_dirty);
 
 	if (io->write) {
 		if (req->misc.write.in.size != req->misc.write.out.size)
@@ -613,6 +654,7 @@
 		size_t num_bytes, struct fuse_io_priv *io)
 {
 	spin_lock(&io->lock);
+	kref_get(&io->refcnt);
 	io->size += num_bytes;
 	io->reqs++;
 	spin_unlock(&io->lock);
@@ -691,7 +733,7 @@
 
 static int fuse_do_readpage(struct file *file, struct page *page)
 {
-	struct fuse_io_priv io = { .async = 0, .file = file };
+	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file);
 	struct inode *inode = page->mapping->host;
 	struct fuse_conn *fc = get_fuse_conn(inode);
 	struct fuse_req *req;
@@ -743,7 +785,7 @@
 	int err;
 
 	err = -EIO;
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		goto out;
 
 	err = fuse_do_readpage(file, page);
@@ -847,6 +889,7 @@
 	}
 
 	if (WARN_ON(req->num_pages >= req->max_pages)) {
+		unlock_page(page);
 		fuse_put_request(fc, req);
 		return -EIO;
 	}
@@ -869,7 +912,7 @@
 	int nr_alloc = min_t(unsigned, nr_pages, FUSE_MAX_PAGES_PER_REQ);
 
 	err = -EIO;
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		goto out;
 
 	data.file = file;
@@ -899,6 +942,9 @@
 	struct inode *inode = iocb->ki_filp->f_mapping->host;
 	struct fuse_conn *fc = get_fuse_conn(inode);
 
+	if (fuse_is_bad(inode))
+		return -EIO;
+
 	/*
 	 * In auto invalidate mode, always update attributes on read.
 	 * Otherwise, only update if we attempt to read past EOF (to ensure
@@ -984,7 +1030,7 @@
 	size_t res;
 	unsigned offset;
 	unsigned i;
-	struct fuse_io_priv io = { .async = 0, .file = file };
+	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file);
 
 	for (i = 0; i < req->num_pages; i++)
 		fuse_wait_on_page_writeback(inode, req->pages[i]->index);
@@ -1094,7 +1140,7 @@
 	int err = 0;
 	ssize_t res = 0;
 
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		return -EIO;
 
 	if (inode->i_size < pos + iov_iter_count(ii))
@@ -1151,6 +1197,9 @@
 	ssize_t err;
 	loff_t endbyte = 0;
 
+	if (fuse_is_bad(inode))
+		return -EIO;
+
 	if (get_fuse_conn(inode)->writeback_cache) {
 		/* Update size (EOF optimization) and mode (SUID clearing) */
 		err = fuse_update_attributes(mapping->host, NULL, file, NULL);
@@ -1328,6 +1377,7 @@
 			mutex_unlock(&inode->i_mutex);
 	}
 
+	io->should_dirty = !write && iter_is_iovec(iter);
 	while (count) {
 		size_t nres;
 		fl_owner_t owner = current->files;
@@ -1344,7 +1394,7 @@
 			nres = fuse_send_read(req, io, pos, nbytes, owner);
 
 		if (!io->async)
-			fuse_release_user_pages(req, !write);
+			fuse_release_user_pages(req, io->should_dirty);
 		if (req->out.h.error) {
 			if (!res)
 				res = req->out.h.error;
@@ -1386,7 +1436,7 @@
 	struct file *file = io->file;
 	struct inode *inode = file_inode(file);
 
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		return -EIO;
 
 	res = fuse_direct_io(io, iter, ppos, 0);
@@ -1398,7 +1448,7 @@
 
 static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
-	struct fuse_io_priv io = { .async = 0, .file = iocb->ki_filp };
+	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb->ki_filp);
 	return __fuse_direct_read(&io, to, &iocb->ki_pos);
 }
 
@@ -1406,10 +1456,10 @@
 {
 	struct file *file = iocb->ki_filp;
 	struct inode *inode = file_inode(file);
-	struct fuse_io_priv io = { .async = 0, .file = file };
+	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file);
 	ssize_t res;
 
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		return -EIO;
 
 	/* Don't allow parallel writes to the same file */
@@ -1499,7 +1549,7 @@
 {
 	struct fuse_conn *fc = get_fuse_conn(inode);
 	struct fuse_inode *fi = get_fuse_inode(inode);
-	size_t crop = i_size_read(inode);
+	loff_t crop = i_size_read(inode);
 	struct fuse_req *req;
 
 	while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) {
@@ -1670,6 +1720,7 @@
 		WARN_ON(wbc->sync_mode == WB_SYNC_ALL);
 
 		redirty_page_for_writepage(wbc, page);
+		unlock_page(page);
 		return 0;
 	}
 
@@ -1750,7 +1801,7 @@
 		spin_unlock(&fc->lock);
 
 		dec_wb_stat(&bdi->wb, WB_WRITEBACK);
-		dec_zone_page_state(page, NR_WRITEBACK_TEMP);
+		dec_zone_page_state(new_req->pages[0], NR_WRITEBACK_TEMP);
 		wb_writeout_inc(&bdi->wb);
 		fuse_writepage_free(fc, new_req);
 		fuse_request_free(new_req);
@@ -1881,7 +1932,7 @@
 	int err;
 
 	err = -EIO;
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		goto out;
 
 	data.inode = inode;
@@ -1965,6 +2016,10 @@
 {
 	struct inode *inode = page->mapping->host;
 
+	/* Haven't copied anything?  Skip zeroing, size extending, dirtying. */
+	if (!copied)
+		goto unlock;
+
 	if (!PageUptodate(page)) {
 		/* Zero any unwritten bytes at the end of the page */
 		size_t endoff = (pos + copied) & ~PAGE_CACHE_MASK;
@@ -1975,6 +2030,8 @@
 
 	fuse_write_update_size(inode, pos + copied);
 	set_page_dirty(page);
+
+unlock:
 	unlock_page(page);
 	page_cache_release(page);
 
@@ -2061,7 +2118,8 @@
 	return generic_file_mmap(file, vma);
 }
 
-static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
+static int convert_fuse_file_lock(struct fuse_conn *fc,
+				  const struct fuse_file_lock *ffl,
 				  struct file_lock *fl)
 {
 	switch (ffl->type) {
@@ -2076,7 +2134,14 @@
 
 		fl->fl_start = ffl->start;
 		fl->fl_end = ffl->end;
-		fl->fl_pid = ffl->pid;
+
+		/*
+		 * Convert pid into the caller's pid namespace. If the pid
+		 * does not map into the namespace fl_pid will get set to 0.
+		 */
+		rcu_read_lock();
+		fl->fl_pid = pid_vnr(find_pid_ns(ffl->pid, fc->pid_ns));
+		rcu_read_unlock();
 		break;
 
 	default:
@@ -2125,7 +2190,7 @@
 	args.out.args[0].value = &outarg;
 	err = fuse_simple_request(fc, &args);
 	if (!err)
-		err = convert_fuse_file_lock(&outarg.lk, fl);
+		err = convert_fuse_file_lock(fc, &outarg.lk, fl);
 
 	return err;
 }
@@ -2137,7 +2202,8 @@
 	FUSE_ARGS(args);
 	struct fuse_lk_in inarg;
 	int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
-	pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
+	struct pid *pid = fl->fl_type != F_UNLCK ? task_tgid(current) : NULL;
+	pid_t pid_nr = pid_nr_ns(pid, fc->pid_ns);
 	int err;
 
 	if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
@@ -2149,7 +2215,10 @@
 	if (fl->fl_flags & FL_CLOSE)
 		return 0;
 
-	fuse_lk_fill(&args, file, fl, opcode, pid, flock, &inarg);
+	if (pid && pid_nr == 0)
+		return -EOVERFLOW;
+
+	fuse_lk_fill(&args, file, fl, opcode, pid_nr, flock, &inarg);
 	err = fuse_simple_request(fc, &args);
 
 	/* locking is restartable */
@@ -2470,7 +2539,16 @@
 		struct iovec *iov = iov_page;
 
 		iov->iov_base = (void __user *)arg;
-		iov->iov_len = _IOC_SIZE(cmd);
+
+		switch (cmd) {
+		case FS_IOC_GETFLAGS:
+		case FS_IOC_SETFLAGS:
+			iov->iov_len = sizeof(int);
+			break;
+		default:
+			iov->iov_len = _IOC_SIZE(cmd);
+			break;
+		}
 
 		if (_IOC_DIR(cmd) & _IOC_WRITE) {
 			in_iov = iov;
@@ -2617,7 +2695,7 @@
 	if (!fuse_allow_current_process(fc))
 		return -EACCES;
 
-	if (is_bad_inode(inode))
+	if (fuse_is_bad(inode))
 		return -EIO;
 
 	return fuse_do_ioctl(file, cmd, arg, flags);
@@ -2765,7 +2843,7 @@
 	attr.ia_file = file;
 	attr.ia_valid |= ATTR_FILE;
 
-	fuse_do_setattr(inode, &attr, file);
+	fuse_do_setattr(file_dentry(file), &attr, file);
 }
 
 static inline loff_t fuse_round_up(loff_t off)
@@ -2786,6 +2864,7 @@
 	loff_t i_size;
 	size_t count = iov_iter_count(iter);
 	struct fuse_io_priv *io;
+	bool is_sync = is_sync_kiocb(iocb);
 
 	pos = offset;
 	inode = file->f_mapping->host;
@@ -2806,6 +2885,7 @@
 	if (!io)
 		return -ENOMEM;
 	spin_lock_init(&io->lock);
+	kref_init(&io->refcnt);
 	io->reqs = 1;
 	io->bytes = -1;
 	io->size = 0;
@@ -2825,12 +2905,18 @@
 	 * to wait on real async I/O requests, so we must submit this request
 	 * synchronously.
 	 */
-	if (!is_sync_kiocb(iocb) && (offset + count > i_size) &&
+	if (!is_sync && (offset + count > i_size) &&
 	    iov_iter_rw(iter) == WRITE)
 		io->async = false;
 
-	if (io->async && is_sync_kiocb(iocb))
+	if (io->async && is_sync) {
+		/*
+		 * Additional reference to keep io around after
+		 * calling fuse_aio_complete()
+		 */
+		kref_get(&io->refcnt);
 		io->done = &wait;
+	}
 
 	if (iov_iter_rw(iter) == WRITE) {
 		ret = fuse_direct_io(io, iter, &pos, FUSE_DIO_WRITE);
@@ -2843,14 +2929,14 @@
 		fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
 
 		/* we have a non-extending, async request, so return */
-		if (!is_sync_kiocb(iocb))
+		if (!is_sync)
 			return -EIOCBQUEUED;
 
 		wait_for_completion(&wait);
 		ret = fuse_get_res_by_io(io);
 	}
 
-	kfree(io);
+	kref_put(&io->refcnt, fuse_io_release);
 
 	if (iov_iter_rw(iter) == WRITE) {
 		if (ret > 0)
@@ -2899,6 +2985,13 @@
 		}
 	}
 
+	if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+	    offset + length > i_size_read(inode)) {
+		err = inode_newsize_ok(inode, offset + length);
+		if (err)
+			goto out;
+	}
+
 	if (!(mode & FALLOC_FL_KEEP_SIZE))
 		set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
 
--- linux-4.4.0.orig/fs/fuse/fuse_i.h
+++ linux-4.4.0/fs/fuse/fuse_i.h
@@ -22,6 +22,9 @@
 #include <linux/rbtree.h>
 #include <linux/poll.h>
 #include <linux/workqueue.h>
+#include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
+#include <linux/kref.h>
 
 /** Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
@@ -119,6 +122,8 @@
 	FUSE_I_INIT_RDPLUS,
 	/** An operation changing file size is in progress  */
 	FUSE_I_SIZE_UNSTABLE,
+	/* Bad inode */
+	FUSE_I_BAD,
 };
 
 struct fuse_conn;
@@ -243,6 +248,7 @@
 
 /** The request IO state (for asynchronous processing) */
 struct fuse_io_priv {
+	struct kref refcnt;
 	int async;
 	spinlock_t lock;
 	unsigned reqs;
@@ -250,12 +256,20 @@
 	size_t size;
 	__u64 offset;
 	bool write;
+	bool should_dirty;
 	int err;
 	struct kiocb *iocb;
 	struct file *file;
 	struct completion *done;
 };
 
+#define FUSE_IO_PRIV_SYNC(f) \
+{					\
+	.refcnt = { ATOMIC_INIT(1) },	\
+	.async = 0,			\
+	.file = f,			\
+}
+
 /**
  * Request flags
  *
@@ -456,6 +470,12 @@
 	/** The group id for this mount */
 	kgid_t group_id;
 
+	/** The pid namespace for this mount */
+	struct pid_namespace *pid_ns;
+
+	/** The user namespace for this mount */
+	struct user_namespace *user_ns;
+
 	/** The fuse mount flags for this mount */
 	unsigned flags;
 
@@ -668,6 +688,17 @@
 	return get_fuse_inode(inode)->nodeid;
 }
 
+static inline void fuse_make_bad(struct inode *inode)
+{
+	remove_inode_hash(inode);
+	set_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state);
+}
+
+static inline bool fuse_is_bad(struct inode *inode)
+{
+	return unlikely(test_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state));
+}
+
 /** Device operations */
 extern const struct file_operations fuse_dev_operations;
 
@@ -833,6 +864,7 @@
 
 /* Abort all requests */
 void fuse_abort_conn(struct fuse_conn *fc);
+void fuse_wait_aborted(struct fuse_conn *fc);
 
 /**
  * Invalidate inode attributes
@@ -851,7 +883,7 @@
 /**
  * Initialize fuse_conn
  */
-void fuse_conn_init(struct fuse_conn *fc);
+void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns);
 
 /**
  * Release reference to fuse_conn
@@ -876,6 +908,8 @@
  */
 int fuse_valid_type(int m);
 
+bool fuse_invalid_attr(struct fuse_attr *attr);
+
 /**
  * Is current process allowed to perform filesystem operation?
  */
@@ -939,7 +973,7 @@
 int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
 int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
 
-int fuse_do_setattr(struct inode *inode, struct iattr *attr,
+int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
 		    struct file *file);
 
 void fuse_set_initialized(struct fuse_conn *fc);
--- linux-4.4.0.orig/fs/fuse/inode.c
+++ linux-4.4.0/fs/fuse/inode.c
@@ -20,6 +20,7 @@
 #include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/exportfs.h>
+#include <linux/pid_namespace.h>
 
 MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
 MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -47,6 +48,10 @@
  "Global limit for the maximum congestion threshold an "
  "unprivileged user can set");
 
+static bool userns_mounts = true;
+module_param(userns_mounts, bool, 0644);
+MODULE_PARM_DESC(userns_mounts, "Allow mounts from unprivileged user namespaces");
+
 #define FUSE_SUPER_MAGIC 0x65735546
 
 #define FUSE_DEFAULT_BLKSIZE 512
@@ -166,8 +171,8 @@
 	inode->i_ino     = fuse_squash_ino(attr->ino);
 	inode->i_mode    = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
 	set_nlink(inode, attr->nlink);
-	inode->i_uid     = make_kuid(&init_user_ns, attr->uid);
-	inode->i_gid     = make_kgid(&init_user_ns, attr->gid);
+	inode->i_uid     = make_kuid(fc->user_ns, attr->uid);
+	inode->i_gid     = make_kgid(fc->user_ns, attr->gid);
 	inode->i_blocks  = attr->blocks;
 	inode->i_atime.tv_sec   = attr->atime;
 	inode->i_atime.tv_nsec  = attr->atimensec;
@@ -312,7 +317,7 @@
 		unlock_new_inode(inode);
 	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
 		/* Inode has changed type, any I/O on the old should fail */
-		make_bad_inode(inode);
+		fuse_make_bad(inode);
 		iput(inode);
 		goto retry;
 	}
@@ -379,9 +384,6 @@
 {
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 
-	fuse_send_destroy(fc);
-
-	fuse_abort_conn(fc);
 	mutex_lock(&fuse_mutex);
 	list_del(&fc->entry);
 	fuse_ctl_remove_conn(fc);
@@ -466,7 +468,8 @@
 	return err;
 }
 
-static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
+static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev,
+			  struct user_namespace *user_ns)
 {
 	char *p;
 	memset(d, 0, sizeof(struct fuse_mount_data));
@@ -502,7 +505,7 @@
 		case OPT_USER_ID:
 			if (fuse_match_uint(&args[0], &uv))
 				return 0;
-			d->user_id = make_kuid(current_user_ns(), uv);
+			d->user_id = make_kuid(user_ns, uv);
 			if (!uid_valid(d->user_id))
 				return 0;
 			d->user_id_present = 1;
@@ -511,7 +514,7 @@
 		case OPT_GROUP_ID:
 			if (fuse_match_uint(&args[0], &uv))
 				return 0;
-			d->group_id = make_kgid(current_user_ns(), uv);
+			d->group_id = make_kgid(user_ns, uv);
 			if (!gid_valid(d->group_id))
 				return 0;
 			d->group_id_present = 1;
@@ -554,8 +557,10 @@
 	struct super_block *sb = root->d_sb;
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 
-	seq_printf(m, ",user_id=%u", from_kuid_munged(&init_user_ns, fc->user_id));
-	seq_printf(m, ",group_id=%u", from_kgid_munged(&init_user_ns, fc->group_id));
+	seq_printf(m, ",user_id=%u",
+		   from_kuid_munged(fc->user_ns, fc->user_id));
+	seq_printf(m, ",group_id=%u",
+		   from_kgid_munged(fc->user_ns, fc->group_id));
 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
 		seq_puts(m, ",default_permissions");
 	if (fc->flags & FUSE_ALLOW_OTHER)
@@ -586,7 +591,7 @@
 	fpq->connected = 1;
 }
 
-void fuse_conn_init(struct fuse_conn *fc)
+void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns)
 {
 	memset(fc, 0, sizeof(*fc));
 	spin_lock_init(&fc->lock);
@@ -609,6 +614,8 @@
 	fc->connected = 1;
 	fc->attr_version = 1;
 	get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
+	fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
+	fc->user_ns = get_user_ns(user_ns);
 }
 EXPORT_SYMBOL_GPL(fuse_conn_init);
 
@@ -617,6 +624,8 @@
 	if (atomic_dec_and_test(&fc->count)) {
 		if (fc->destroy_req)
 			fuse_request_free(fc->destroy_req);
+		put_pid_ns(fc->pid_ns);
+		put_user_ns(fc->user_ns);
 		fc->release(fc);
 	}
 }
@@ -926,7 +935,7 @@
 	arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
 		FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
 		FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
-		FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
+		FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
 		FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
 		FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT;
 	req->in.h.opcode = FUSE_INIT;
@@ -1037,13 +1046,16 @@
 	int err;
 	int is_bdev = sb->s_bdev != NULL;
 
+	if (!userns_mounts && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	err = -EINVAL;
 	if (sb->s_flags & MS_MANDLOCK)
 		goto err;
 
 	sb->s_flags &= ~(MS_NOSEC | MS_I_VERSION);
 
-	if (!parse_fuse_opt(data, &d, is_bdev))
+	if (!parse_fuse_opt(data, &d, is_bdev, sb->s_user_ns))
 		goto err;
 
 	if (is_bdev) {
@@ -1067,8 +1079,12 @@
 	if (!file)
 		goto err;
 
-	if ((file->f_op != &fuse_dev_operations) ||
-	    (file->f_cred->user_ns != &init_user_ns))
+	/*
+	 * Require mount to happen from the same user namespace which
+	 * opened /dev/fuse to prevent potential attacks.
+	 */
+	if (file->f_op != &fuse_dev_operations ||
+	    file->f_cred->user_ns != sb->s_user_ns)
 		goto err_fput;
 
 	fc = kmalloc(sizeof(*fc), GFP_KERNEL);
@@ -1076,7 +1092,7 @@
 	if (!fc)
 		goto err_fput;
 
-	fuse_conn_init(fc);
+	fuse_conn_init(fc, sb->s_user_ns);
 	fc->release = fuse_free_conn;
 
 	fud = fuse_dev_alloc(fc);
@@ -1158,6 +1174,7 @@
  err_put_conn:
 	fuse_bdi_destroy(fc);
 	fuse_conn_put(fc);
+	sb->s_fs_info = NULL;
  err_fput:
 	fput(file);
  err:
@@ -1171,23 +1188,32 @@
 	return mount_nodev(fs_type, flags, raw_data, fuse_fill_super);
 }
 
-static void fuse_kill_sb_anon(struct super_block *sb)
+static void fuse_sb_destroy(struct super_block *sb)
 {
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 
 	if (fc) {
+		fuse_send_destroy(fc);
+
+		fuse_abort_conn(fc);
+		fuse_wait_aborted(fc);
+
 		down_write(&fc->killsb);
 		fc->sb = NULL;
 		up_write(&fc->killsb);
 	}
+}
 
+static void fuse_kill_sb_anon(struct super_block *sb)
+{
+	fuse_sb_destroy(sb);
 	kill_anon_super(sb);
 }
 
 static struct file_system_type fuse_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "fuse",
-	.fs_flags	= FS_HAS_SUBTYPE,
+	.fs_flags	= FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
 	.mount		= fuse_mount,
 	.kill_sb	= fuse_kill_sb_anon,
 };
@@ -1203,14 +1229,7 @@
 
 static void fuse_kill_sb_blk(struct super_block *sb)
 {
-	struct fuse_conn *fc = get_fuse_conn_super(sb);
-
-	if (fc) {
-		down_write(&fc->killsb);
-		fc->sb = NULL;
-		up_write(&fc->killsb);
-	}
-
+	fuse_sb_destroy(sb);
 	kill_block_super(sb);
 }
 
@@ -1219,7 +1238,7 @@
 	.name		= "fuseblk",
 	.mount		= fuse_mount_blk,
 	.kill_sb	= fuse_kill_sb_blk,
-	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
+	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
 };
 MODULE_ALIAS_FS("fuseblk");
 
--- linux-4.4.0.orig/fs/gfs2/acl.c
+++ linux-4.4.0/fs/gfs2/acl.c
@@ -79,17 +79,11 @@
 	if (type == ACL_TYPE_ACCESS) {
 		umode_t mode = inode->i_mode;
 
-		error = posix_acl_equiv_mode(acl, &mode);
-		if (error < 0)
+		error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+		if (error)
 			return error;
-
-		if (error == 0)
-			acl = NULL;
-
-		if (mode != inode->i_mode) {
-			inode->i_mode = mode;
+		if (mode != inode->i_mode)
 			mark_inode_dirty(inode);
-		}
 	}
 
 	if (acl) {
--- linux-4.4.0.orig/fs/gfs2/bmap.c
+++ linux-4.4.0/fs/gfs2/bmap.c
@@ -1235,6 +1235,8 @@
 	}
 
 	error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT +
+				 (unstuff &&
+				  gfs2_is_jdata(ip) ? RES_JDATA : 0) +
 				 (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF ?
 				  0 : RES_QUOTA), 0);
 	if (error)
@@ -1476,7 +1478,7 @@
 	end_of_file = (i_size_read(&ip->i_inode) + sdp->sd_sb.sb_bsize - 1) >> shift;
 	lblock = offset >> shift;
 	lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
-	if (lblock_stop > end_of_file)
+	if (lblock_stop > end_of_file && ip != GFS2_I(sdp->sd_rindex))
 		return 1;
 
 	size = (lblock_stop - lblock) << shift;
--- linux-4.4.0.orig/fs/gfs2/dir.c
+++ linux-4.4.0/fs/gfs2/dir.c
@@ -760,7 +760,7 @@
 	int error;
 
 	error = get_leaf_nr(dip, index, &leaf_no);
-	if (!error)
+	if (!IS_ERR_VALUE(error))
 		error = get_leaf(dip, leaf_no, bh_out);
 
 	return error;
@@ -976,7 +976,7 @@
 
 	index = name->hash >> (32 - dip->i_depth);
 	error = get_leaf_nr(dip, index, &leaf_no);
-	if (error)
+	if (IS_ERR_VALUE(error))
 		return error;
 
 	/*  Get the old leaf block  */
--- linux-4.4.0.orig/fs/gfs2/file.c
+++ linux-4.4.0/fs/gfs2/file.c
@@ -255,7 +255,7 @@
 			goto out;
 	}
 	if ((flags ^ new_flags) & GFS2_DIF_JDATA) {
-		if (flags & GFS2_DIF_JDATA)
+		if (new_flags & GFS2_DIF_JDATA)
 			gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH);
 		error = filemap_fdatawrite(inode->i_mapping);
 		if (error)
@@ -263,6 +263,8 @@
 		error = filemap_fdatawait(inode->i_mapping);
 		if (error)
 			goto out;
+		if (new_flags & GFS2_DIF_JDATA)
+			gfs2_ordered_del_inode(ip);
 	}
 	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
 	if (error)
@@ -804,7 +806,7 @@
 	struct gfs2_inode *ip = GFS2_I(inode);
 	struct gfs2_alloc_parms ap = { .aflags = 0, };
 	unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
-	loff_t bytes, max_bytes, max_blks = UINT_MAX;
+	loff_t bytes, max_bytes, max_blks;
 	int error;
 	const loff_t pos = offset;
 	const loff_t count = len;
@@ -856,7 +858,8 @@
 			return error;
 		/* ap.allowed tells us how many blocks quota will allow
 		 * us to write. Check if this reduces max_blks */
-		if (ap.allowed && ap.allowed < max_blks)
+		max_blks = UINT_MAX;
+		if (ap.allowed)
 			max_blks = ap.allowed;
 
 		error = gfs2_inplace_reserve(ip, &ap);
@@ -1032,7 +1035,10 @@
 		if (fl_gh->gh_state == state)
 			goto out;
 		locks_lock_file_wait(file,
-				     &(struct file_lock){.fl_type = F_UNLCK});
+				     &(struct file_lock) {
+					     .fl_type = F_UNLCK,
+					     .fl_flags = FL_FLOCK
+				     });
 		gfs2_glock_dq(fl_gh);
 		gfs2_holder_reinit(state, flags, fl_gh);
 	} else {
--- linux-4.4.0.orig/fs/gfs2/glock.c
+++ linux-4.4.0/fs/gfs2/glock.c
@@ -80,9 +80,9 @@
 
 static struct rhashtable gl_hash_table;
 
-void gfs2_glock_free(struct gfs2_glock *gl)
+static void gfs2_glock_dealloc(struct rcu_head *rcu)
 {
-	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
+	struct gfs2_glock *gl = container_of(rcu, struct gfs2_glock, gl_rcu);
 
 	if (gl->gl_ops->go_flags & GLOF_ASPACE) {
 		kmem_cache_free(gfs2_glock_aspace_cachep, gl);
@@ -90,8 +90,42 @@
 		kfree(gl->gl_lksb.sb_lvbptr);
 		kmem_cache_free(gfs2_glock_cachep, gl);
 	}
+}
+
+static void __gfs2_glock_free(struct gfs2_glock *gl)
+{
+	call_rcu(&gl->gl_rcu, gfs2_glock_dealloc);
+}
+
+void gfs2_glock_free(struct gfs2_glock *gl) {
+	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
+
+	__gfs2_glock_free(gl);
 	if (atomic_dec_and_test(&sdp->sd_glock_disposal))
-		wake_up(&sdp->sd_glock_wait);
+		wake_up(&sdp->sd_kill_wait);
+}
+
+void gfs2_glock_free_later(struct gfs2_glock *gl) {
+	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
+
+	spin_lock(&lru_lock);
+	list_add(&gl->gl_lru, &sdp->sd_dead_glocks);
+	spin_unlock(&lru_lock);
+	if (atomic_dec_and_test(&sdp->sd_glock_disposal))
+		wake_up(&sdp->sd_kill_wait);
+}
+
+static void gfs2_free_dead_glocks(struct gfs2_sbd *sdp)
+{
+	struct list_head *list = &sdp->sd_dead_glocks;
+
+	while(!list_empty(list)) {
+		struct gfs2_glock *gl;
+
+		gl = list_first_entry(list, struct gfs2_glock, gl_lru);
+		list_del_init(&gl->gl_lru);
+		__gfs2_glock_free(gl);
+	}
 }
 
 /**
@@ -129,22 +163,26 @@
 
 void gfs2_glock_add_to_lru(struct gfs2_glock *gl)
 {
+	if (!(gl->gl_ops->go_flags & GLOF_LRU))
+		return;
+
 	spin_lock(&lru_lock);
 
-	if (!list_empty(&gl->gl_lru))
-		list_del_init(&gl->gl_lru);
-	else
+	list_del(&gl->gl_lru);
+	list_add_tail(&gl->gl_lru, &lru_list);
+
+	if (!test_bit(GLF_LRU, &gl->gl_flags)) {
+		set_bit(GLF_LRU, &gl->gl_flags);
 		atomic_inc(&lru_count);
+	}
 
-	list_add_tail(&gl->gl_lru, &lru_list);
-	set_bit(GLF_LRU, &gl->gl_flags);
 	spin_unlock(&lru_lock);
 }
 
 static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
 {
 	spin_lock(&lru_lock);
-	if (!list_empty(&gl->gl_lru)) {
+	if (test_bit(GLF_LRU, &gl->gl_flags)) {
 		list_del_init(&gl->gl_lru);
 		atomic_dec(&lru_count);
 		clear_bit(GLF_LRU, &gl->gl_flags);
@@ -651,9 +689,11 @@
 	struct kmem_cache *cachep;
 	int ret, tries = 0;
 
+	rcu_read_lock();
 	gl = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms);
 	if (gl && !lockref_get_not_dead(&gl->gl_lockref))
 		gl = NULL;
+	rcu_read_unlock();
 
 	*glp = gl;
 	if (gl)
@@ -721,21 +761,25 @@
 
 	if (ret == -EEXIST) {
 		ret = 0;
+		rcu_read_lock();
 		tmp = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms);
 		if (tmp == NULL || !lockref_get_not_dead(&tmp->gl_lockref)) {
 			if (++tries < 100) {
+				rcu_read_unlock();
 				cond_resched();
 				goto again;
 			}
 			tmp = NULL;
 			ret = -ENOMEM;
 		}
+		rcu_read_unlock();
 	} else {
 		WARN_ON_ONCE(ret);
 	}
 	kfree(gl->gl_lksb.sb_lvbptr);
 	kmem_cache_free(cachep, gl);
-	atomic_dec(&sdp->sd_glock_disposal);
+	if (atomic_dec_and_test(&sdp->sd_glock_disposal))
+		wake_up(&sdp->sd_kill_wait);
 	*glp = tmp;
 
 	return ret;
@@ -1028,8 +1072,7 @@
 		    !test_bit(GLF_DEMOTE, &gl->gl_flags))
 			fast_path = 1;
 	}
-	if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl) &&
-	    (glops->go_flags & GLOF_LRU))
+	if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl))
 		gfs2_glock_add_to_lru(gl);
 
 	trace_gfs2_glock_queue(gh, 0);
@@ -1326,9 +1369,11 @@
 	while(!list_empty(list)) {
 		gl = list_entry(list->next, struct gfs2_glock, gl_lru);
 		list_del_init(&gl->gl_lru);
+		clear_bit(GLF_LRU, &gl->gl_flags);
 		if (!spin_trylock(&gl->gl_lockref.lock)) {
 add_back_to_lru:
 			list_add(&gl->gl_lru, &lru_list);
+			set_bit(GLF_LRU, &gl->gl_flags);
 			atomic_inc(&lru_count);
 			continue;
 		}
@@ -1336,7 +1381,6 @@
 			spin_unlock(&gl->gl_lockref.lock);
 			goto add_back_to_lru;
 		}
-		clear_bit(GLF_LRU, &gl->gl_flags);
 		gl->gl_lockref.count++;
 		if (demote_ok(gl))
 			handle_callback(gl, LM_ST_UNLOCKED, 0, false);
@@ -1506,7 +1550,11 @@
 	flush_workqueue(glock_workqueue);
 	glock_hash_walk(clear_glock, sdp);
 	flush_workqueue(glock_workqueue);
-	wait_event(sdp->sd_glock_wait, atomic_read(&sdp->sd_glock_disposal) == 0);
+	wait_event_timeout(sdp->sd_kill_wait,
+			   atomic_read(&sdp->sd_glock_disposal) == 0,
+			   HZ * 600);
+	gfs2_lm_unmount(sdp);
+	gfs2_free_dead_glocks(sdp);
 	glock_hash_walk(dump_glock_func, sdp);
 }
 
@@ -1786,29 +1834,28 @@
 
 static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
 {
-	do {
-		gi->gl = rhashtable_walk_next(&gi->hti);
+	while ((gi->gl = rhashtable_walk_next(&gi->hti))) {
 		if (IS_ERR(gi->gl)) {
 			if (PTR_ERR(gi->gl) == -EAGAIN)
 				continue;
 			gi->gl = NULL;
+			return;
 		}
-	/* Skip entries for other sb and dead entries */
-	} while ((gi->gl) && ((gi->sdp != gi->gl->gl_name.ln_sbd) ||
-			      __lockref_is_dead(&gi->gl->gl_lockref)));
+		/* Skip entries for other sb and dead entries */
+		if (gi->sdp == gi->gl->gl_name.ln_sbd &&
+		    !__lockref_is_dead(&gi->gl->gl_lockref))
+			return;
+	}
 }
 
 static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	struct gfs2_glock_iter *gi = seq->private;
 	loff_t n = *pos;
-	int ret;
 
-	if (gi->last_pos <= *pos)
-		n = (*pos - gi->last_pos);
-
-	ret = rhashtable_walk_start(&gi->hti);
-	if (ret)
+	if (rhashtable_walk_init(&gl_hash_table, &gi->hti) != 0)
+		return NULL;
+	if (rhashtable_walk_start(&gi->hti) != 0)
 		return NULL;
 
 	do {
@@ -1816,6 +1863,7 @@
 	} while (gi->gl && n--);
 
 	gi->last_pos = *pos;
+
 	return gi->gl;
 }
 
@@ -1827,6 +1875,7 @@
 	(*pos)++;
 	gi->last_pos = *pos;
 	gfs2_glock_iter_next(gi);
+
 	return gi->gl;
 }
 
@@ -1835,7 +1884,10 @@
 	struct gfs2_glock_iter *gi = seq->private;
 
 	gi->gl = NULL;
-	rhashtable_walk_stop(&gi->hti);
+	if (gi->hti.walker) {
+		rhashtable_walk_stop(&gi->hti);
+		rhashtable_walk_exit(&gi->hti);
+	}
 }
 
 static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr)
@@ -1898,12 +1950,10 @@
 		struct gfs2_glock_iter *gi = seq->private;
 
 		gi->sdp = inode->i_private;
-		gi->last_pos = 0;
 		seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN);
 		if (seq->buf)
 			seq->size = GFS2_SEQ_GOODSIZE;
 		gi->gl = NULL;
-		ret = rhashtable_walk_init(&gl_hash_table, &gi->hti);
 	}
 	return ret;
 }
@@ -1914,7 +1964,6 @@
 	struct gfs2_glock_iter *gi = seq->private;
 
 	gi->gl = NULL;
-	rhashtable_walk_exit(&gi->hti);
 	return seq_release_private(inode, file);
 }
 
@@ -1926,12 +1975,10 @@
 		struct seq_file *seq = file->private_data;
 		struct gfs2_glock_iter *gi = seq->private;
 		gi->sdp = inode->i_private;
-		gi->last_pos = 0;
 		seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN);
 		if (seq->buf)
 			seq->size = GFS2_SEQ_GOODSIZE;
 		gi->gl = NULL;
-		ret = rhashtable_walk_init(&gl_hash_table, &gi->hti);
 	}
 	return ret;
 }
--- linux-4.4.0.orig/fs/gfs2/glock.h
+++ linux-4.4.0/fs/gfs2/glock.h
@@ -236,6 +236,7 @@
 extern void gfs2_glock_thaw(struct gfs2_sbd *sdp);
 extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl);
 extern void gfs2_glock_free(struct gfs2_glock *gl);
+void gfs2_glock_free_later(struct gfs2_glock *gl);
 
 extern int __init gfs2_glock_init(void);
 extern void gfs2_glock_exit(void);
--- linux-4.4.0.orig/fs/gfs2/incore.h
+++ linux-4.4.0/fs/gfs2/incore.h
@@ -207,7 +207,7 @@
 	struct gfs2_sbd *ln_sbd;
 	u64 ln_number;
 	unsigned int ln_type;
-};
+} __packed __aligned(sizeof(int));
 
 #define lm_name_equal(name1, name2) \
         (((name1)->ln_number == (name2)->ln_number) &&	\
@@ -367,6 +367,7 @@
 			loff_t end;
 		} gl_vm;
 	};
+	struct rcu_head gl_rcu;
 	struct rhash_head gl_node;
 };
 
@@ -696,7 +697,7 @@
 	struct gfs2_glock *sd_rename_gl;
 	struct gfs2_glock *sd_freeze_gl;
 	struct work_struct sd_freeze_work;
-	wait_queue_head_t sd_glock_wait;
+	wait_queue_head_t sd_kill_wait;
 	atomic_t sd_glock_disposal;
 	struct completion sd_locking_init;
 	struct completion sd_wdack;
@@ -814,6 +815,7 @@
 	struct gfs2_holder sd_freeze_gh;
 	atomic_t sd_freeze_state;
 	struct mutex sd_freeze_mutex;
+	struct list_head sd_dead_glocks;
 
 	char sd_fsname[GFS2_FSNAME_LEN];
 	char sd_table_name[GFS2_FSNAME_LEN];
--- linux-4.4.0.orig/fs/gfs2/inode.c
+++ linux-4.4.0/fs/gfs2/inode.c
@@ -1245,7 +1245,7 @@
 		if (!(*opened & FILE_OPENED))
 			return finish_no_open(file, d);
 		dput(d);
-		return 0;
+		return excl && (flags & O_CREAT) ? -EEXIST : 0;
 	}
 
 	BUG_ON(d != NULL);
@@ -1932,7 +1932,7 @@
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		goto out;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		goto out;
 
--- linux-4.4.0.orig/fs/gfs2/lock_dlm.c
+++ linux-4.4.0/fs/gfs2/lock_dlm.c
@@ -32,9 +32,10 @@
  * @delta is the difference between the current rtt sample and the
  * running average srtt. We add 1/8 of that to the srtt in order to
  * update the current srtt estimate. The variance estimate is a bit
- * more complicated. We subtract the abs value of the @delta from
- * the current variance estimate and add 1/4 of that to the running
- * total.
+ * more complicated. We subtract the current variance estimate from
+ * the abs value of the @delta and add 1/4 of that to the running
+ * total.  That's equivalent to 3/4 of the current variance
+ * estimate plus 1/4 of the abs of @delta.
  *
  * Note that the index points at the array entry containing the smoothed
  * mean value, and the variance is always in the following entry
@@ -50,7 +51,7 @@
 	s64 delta = sample - s->stats[index];
 	s->stats[index] += (delta >> 3);
 	index++;
-	s->stats[index] += ((abs(delta) - s->stats[index]) >> 2);
+	s->stats[index] += (s64)(abs(delta) - s->stats[index]) >> 2;
 }
 
 /**
@@ -119,6 +120,11 @@
 	struct gfs2_glock *gl = arg;
 	unsigned ret = gl->gl_state;
 
+	/* If the glock is dead, we only react to a dlm_unlock() reply. */
+	if (__lockref_is_dead(&gl->gl_lockref) &&
+	    gl->gl_lksb.sb_status != -DLM_EUNLOCK)
+		return;
+
 	gfs2_update_reply_times(gl);
 	BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);
 
@@ -167,6 +173,9 @@
 {
 	struct gfs2_glock *gl = arg;
 
+	if (__lockref_is_dead(&gl->gl_lockref))
+		return;
+
 	switch (mode) {
 	case DLM_LOCK_EX:
 		gfs2_glock_cb(gl, LM_ST_UNLOCKED);
@@ -283,9 +292,10 @@
 {
 	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
 	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-	int lvb_needs_unlock = 0;
 	int error;
 
+	BUG_ON(!__lockref_is_dead(&gl->gl_lockref));
+
 	if (gl->gl_lksb.sb_lkid == 0) {
 		gfs2_glock_free(gl);
 		return;
@@ -296,14 +306,11 @@
 	gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
 	gfs2_update_request_times(gl);
 
-	/* don't want to skip dlm_unlock writing the lvb when lock is ex */
-
-	if (gl->gl_lksb.sb_lvbptr && (gl->gl_state == LM_ST_EXCLUSIVE))
-		lvb_needs_unlock = 1;
+	/* don't want to skip dlm_unlock writing the lvb when lock has one */
 
 	if (test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags) &&
-	    !lvb_needs_unlock) {
-		gfs2_glock_free(gl);
+	    !gl->gl_lksb.sb_lvbptr) {
+		gfs2_glock_free_later(gl);
 		return;
 	}
 
--- linux-4.4.0.orig/fs/gfs2/ops_fstype.c
+++ linux-4.4.0/fs/gfs2/ops_fstype.c
@@ -71,18 +71,18 @@
 	if (!sdp)
 		return NULL;
 
-	sb->s_fs_info = sdp;
 	sdp->sd_vfs = sb;
 	sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats);
 	if (!sdp->sd_lkstats) {
 		kfree(sdp);
 		return NULL;
 	}
+	sb->s_fs_info = sdp;
 
 	set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
 	gfs2_tune_init(&sdp->sd_tune);
 
-	init_waitqueue_head(&sdp->sd_glock_wait);
+	init_waitqueue_head(&sdp->sd_kill_wait);
 	atomic_set(&sdp->sd_glock_disposal, 0);
 	init_completion(&sdp->sd_locking_init);
 	init_completion(&sdp->sd_wdack);
@@ -133,6 +133,7 @@
 	init_waitqueue_head(&sdp->sd_log_flush_wait);
 	atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
 	mutex_init(&sdp->sd_freeze_mutex);
+	INIT_LIST_HEAD(&sdp->sd_dead_glocks);
 
 	return sdp;
 }
@@ -160,15 +161,19 @@
 		return -EINVAL;
 	}
 
-	/*  If format numbers match exactly, we're done.  */
-
-	if (sb->sb_fs_format == GFS2_FORMAT_FS &&
-	    sb->sb_multihost_format == GFS2_FORMAT_MULTI)
-		return 0;
+	if (sb->sb_fs_format != GFS2_FORMAT_FS ||
+	    sb->sb_multihost_format != GFS2_FORMAT_MULTI) {
+		fs_warn(sdp, "Unknown on-disk format, unable to mount\n");
+		return -EINVAL;
+	}
 
-	fs_warn(sdp, "Unknown on-disk format, unable to mount\n");
+	if (sb->sb_bsize < 512 || sb->sb_bsize > PAGE_SIZE ||
+	    (sb->sb_bsize & (sb->sb_bsize - 1))) {
+		pr_warn("Invalid superblock size\n");
+		return -EINVAL;
+	}
 
-	return -EINVAL;
+	return 0;
 }
 
 static void end_bio_io_page(struct bio *bio)
@@ -916,7 +921,7 @@
 }
 
 static const match_table_t nolock_tokens = {
-	{ Opt_jid, "jid=%d\n", },
+	{ Opt_jid, "jid=%d", },
 	{ Opt_err, NULL },
 };
 
@@ -1222,7 +1227,7 @@
 	 * We set the bdi here to the queue backing, file systems can
 	 * overwrite this in ->fill_super()
 	 */
-	s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+	s->s_bdi = bdev_get_queue(s->s_bdev)->backing_dev_info;
 	return 0;
 }
 
@@ -1353,6 +1358,9 @@
 	struct path path;
 	int error;
 
+	if (!dev_name || !*dev_name)
+		return ERR_PTR(-EINVAL);
+
 	error = kern_path(dev_name, LOOKUP_FOLLOW, &path);
 	if (error) {
 		pr_warn("path_lookup on %s returned error %d\n",
--- linux-4.4.0.orig/fs/gfs2/quota.h
+++ linux-4.4.0/fs/gfs2/quota.h
@@ -43,6 +43,8 @@
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
 	int ret;
+
+	ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */
 	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
 		return 0;
 	ret = gfs2_quota_lock(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);
--- linux-4.4.0.orig/fs/gfs2/rgrp.c
+++ linux-4.4.0/fs/gfs2/rgrp.c
@@ -645,7 +645,10 @@
 	RB_CLEAR_NODE(&rs->rs_node);
 
 	if (rs->rs_free) {
-		struct gfs2_bitmap *bi = rbm_bi(&rs->rs_rbm);
+		u64 last_block = gfs2_rbm_to_block(&rs->rs_rbm) +
+				 rs->rs_free - 1;
+		struct gfs2_rbm last_rbm = { .rgd = rs->rs_rbm.rgd, };
+		struct gfs2_bitmap *start, *last;
 
 		/* return reserved blocks to the rgrp */
 		BUG_ON(rs->rs_rbm.rgd->rd_reserved < rs->rs_free);
@@ -656,7 +659,13 @@
 		   it will force the number to be recalculated later. */
 		rgd->rd_extfail_pt += rs->rs_free;
 		rs->rs_free = 0;
-		clear_bit(GBF_FULL, &bi->bi_flags);
+		if (gfs2_rbm_from_block(&last_rbm, last_block))
+			return;
+		start = rbm_bi(&rs->rs_rbm);
+		last = rbm_bi(&last_rbm);
+		do
+			clear_bit(GBF_FULL, &start->bi_flags);
+		while (start++ != last);
 	}
 }
 
@@ -732,13 +741,15 @@
 			spin_lock(&gl->gl_lockref.lock);
 			gl->gl_object = NULL;
 			spin_unlock(&gl->gl_lockref.lock);
+			gfs2_rgrp_brelse(rgd);
 			gfs2_glock_add_to_lru(gl);
 			gfs2_glock_put(gl);
 		}
 
 		gfs2_free_clones(rgd);
-		kfree(rgd->rd_bits);
 		return_all_reservations(rgd);
+		kfree(rgd->rd_bits);
+		rgd->rd_bits = NULL;
 		kmem_cache_free(gfs2_rgrpd_cachep, rgd);
 	}
 }
@@ -932,10 +943,6 @@
 	if (error)
 		goto fail;
 
-	rgd->rd_gl->gl_object = rgd;
-	rgd->rd_gl->gl_vm.start = (rgd->rd_addr * bsize) & PAGE_CACHE_MASK;
-	rgd->rd_gl->gl_vm.end = PAGE_CACHE_ALIGN((rgd->rd_addr +
-						  rgd->rd_length) * bsize) - 1;
 	rgd->rd_rgl = (struct gfs2_rgrp_lvb *)rgd->rd_gl->gl_lksb.sb_lvbptr;
 	rgd->rd_flags &= ~(GFS2_RDF_UPTODATE | GFS2_RDF_PREFERRED);
 	if (rgd->rd_data > sdp->sd_max_rg_data)
@@ -943,14 +950,20 @@
 	spin_lock(&sdp->sd_rindex_spin);
 	error = rgd_insert(rgd);
 	spin_unlock(&sdp->sd_rindex_spin);
-	if (!error)
+	if (!error) {
+		rgd->rd_gl->gl_object = rgd;
+		rgd->rd_gl->gl_vm.start = (rgd->rd_addr * bsize) & PAGE_MASK;
+		rgd->rd_gl->gl_vm.end = PAGE_ALIGN((rgd->rd_addr +
+						    rgd->rd_length) * bsize) - 1;
 		return 0;
+	}
 
 	error = 0; /* someone else read in the rgrp; free it and ignore it */
 	gfs2_glock_put(rgd->rd_gl);
 
 fail:
 	kfree(rgd->rd_bits);
+	rgd->rd_bits = NULL;
 	kmem_cache_free(gfs2_rgrpd_cachep, rgd);
 	return error;
 }
@@ -1004,6 +1017,10 @@
 	if (error < 0)
 		return error;
 
+	if (RB_EMPTY_ROOT(&sdp->sd_rindex_tree)) {
+		fs_err(sdp, "no resource groups found in the file system.\n");
+		return -ENOENT;
+	}
 	set_rgrp_preferences(sdp);
 
 	sdp->sd_rindex_uptodate = 1;
@@ -1139,7 +1156,7 @@
  * @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.
+ * Caller must eventually call gfs2_rgrp_brelse() to free the bitmaps.
  *
  * Returns: errno
  */
@@ -1224,7 +1241,7 @@
 	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);
+	rgd->rd_flags |= (rl_flags | 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);
@@ -1375,6 +1392,9 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
+	if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
+		return -EROFS;
+
 	if (!blk_queue_discard(q))
 		return -EOPNOTSUPP;
 
--- linux-4.4.0.orig/fs/gfs2/super.c
+++ linux-4.4.0/fs/gfs2/super.c
@@ -835,10 +835,10 @@
 	if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
 		return error;
 
+	flush_workqueue(gfs2_delete_workqueue);
 	kthread_stop(sdp->sd_quotad_process);
 	kthread_stop(sdp->sd_logd_process);
 
-	flush_workqueue(gfs2_delete_workqueue);
 	gfs2_quota_sync(sdp->sd_vfs, 0);
 	gfs2_statfs_sync(sdp->sd_vfs, 0);
 
@@ -891,6 +891,8 @@
 		error = gfs2_make_fs_ro(sdp);
 		if (error)
 			gfs2_io_error(sdp);
+	} else {
+		gfs2_quota_cleanup(sdp);
 	}
 	/*  At this point, we're through modifying the disk  */
 
@@ -918,10 +920,7 @@
 	gfs2_jindex_free(sdp);
 	/*  Take apart glock structures and buffer lists  */
 	gfs2_gl_hash_clear(sdp);
-	/*  Unmount the locking protocol  */
-	gfs2_lm_unmount(sdp);
 
-	/*  At this point, we're through participating in the lockspace  */
 	gfs2_sys_fs_del(sdp);
 }
 
@@ -1522,6 +1521,14 @@
 	if (inode->i_nlink || (sb->s_flags & MS_RDONLY))
 		goto out;
 
+	/*
+	 * In case of an incomplete mount, gfs2_evict_inode() may be called for
+	 * system files without having an active journal to write to.  In that
+	 * case, skip the filesystem evict.
+	 */
+	if (!sdp->sd_jdesc)
+		goto out;
+
 	/* Must not read inode block until block type has been verified */
 	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh);
 	if (unlikely(error)) {
--- linux-4.4.0.orig/fs/hfs/bnode.c
+++ linux-4.4.0/fs/hfs/bnode.c
@@ -42,7 +42,7 @@
 	return data;
 }
 
-void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
+int hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
 {
 	struct hfs_btree *tree;
 	int key_len;
@@ -54,7 +54,13 @@
 	else
 		key_len = tree->max_key_len + 1;
 
+	if (key_len > tree->max_key_len + 1) {
+		pr_err("key_len %d too large\n", key_len);
+		return -EINVAL;
+	}
+
 	hfs_bnode_read(node, key, off, key_len);
+	return 0;
 }
 
 void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
--- linux-4.4.0.orig/fs/hfs/brec.c
+++ linux-4.4.0/fs/hfs/brec.c
@@ -69,14 +69,16 @@
 	int data_off, end_off;
 	int idx_rec_off, data_rec_off, end_rec_off;
 	__be32 cnid;
+	int res;
 
 	tree = fd->tree;
 	if (!fd->bnode) {
 		if (!tree->root)
 			hfs_btree_inc_height(tree);
-		fd->bnode = hfs_bnode_find(tree, tree->leaf_head);
-		if (IS_ERR(fd->bnode))
-			return PTR_ERR(fd->bnode);
+		node = hfs_bnode_find(tree, tree->leaf_head);
+		if (IS_ERR(node))
+			return PTR_ERR(node);
+		fd->bnode = node;
 		fd->record = -1;
 	}
 	new_node = NULL;
@@ -136,7 +138,10 @@
 	 * at the start of the node and it is not the new node
 	 */
 	if (!rec && new_node != node) {
-		hfs_bnode_read_key(node, fd->search_key, data_off + size);
+		res = hfs_bnode_read_key(node, fd->search_key, data_off + size);
+		if (res < 0)
+			return res;
+
 		hfs_brec_update_parent(fd);
 	}
 
@@ -154,7 +159,10 @@
 		entry_len = sizeof(cnid);
 
 		/* get index key */
-		hfs_bnode_read_key(new_node, fd->search_key, 14);
+		res = hfs_bnode_read_key(new_node, fd->search_key, 14);
+		if (res < 0)
+			return res;
+
 		__hfs_brec_find(fd->bnode, fd);
 
 		hfs_bnode_put(new_node);
@@ -354,6 +362,7 @@
 	int newkeylen, diff;
 	int rec, rec_off, end_rec_off;
 	int start_off, end_off;
+	int res;
 
 	tree = fd->tree;
 	node = fd->bnode;
@@ -423,9 +432,16 @@
 	if (new_node) {
 		__be32 cnid;
 
+		if (!new_node->parent) {
+			hfs_btree_inc_height(tree);
+			new_node->parent = tree->root;
+		}
 		fd->bnode = hfs_bnode_find(tree, new_node->parent);
 		/* create index key and entry */
-		hfs_bnode_read_key(new_node, fd->search_key, 14);
+		res = hfs_bnode_read_key(new_node, fd->search_key, 14);
+		if (res < 0)
+			return res;
+
 		cnid = cpu_to_be32(new_node->this);
 
 		__hfs_brec_find(fd->bnode, fd);
@@ -437,8 +453,11 @@
 			if (new_node == node)
 				goto out;
 			/* restore search_key */
-			hfs_bnode_read_key(node, fd->search_key, 14);
+			res = hfs_bnode_read_key(node, fd->search_key, 14);
+			if (res < 0)
+				return res;
 		}
+		new_node = NULL;
 	}
 
 	if (!rec && node->parent)
--- linux-4.4.0.orig/fs/hfs/btree.c
+++ linux-4.4.0/fs/hfs/btree.c
@@ -219,25 +219,17 @@
 	return node;
 }
 
-struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
+/* Make sure @tree has enough space for the @rsvd_nodes */
+int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes)
 {
-	struct hfs_bnode *node, *next_node;
-	struct page **pagep;
-	u32 nidx, idx;
-	unsigned off;
-	u16 off16;
-	u16 len;
-	u8 *data, byte, m;
-	int i;
-
-	while (!tree->free_nodes) {
-		struct inode *inode = tree->inode;
-		u32 count;
-		int res;
+	struct inode *inode = tree->inode;
+	u32 count;
+	int res;
 
+	while (tree->free_nodes < rsvd_nodes) {
 		res = hfs_extend_file(inode);
 		if (res)
-			return ERR_PTR(res);
+			return res;
 		HFS_I(inode)->phys_size = inode->i_size =
 				(loff_t)HFS_I(inode)->alloc_blocks *
 				HFS_SB(tree->sb)->alloc_blksz;
@@ -245,9 +237,26 @@
 					  tree->sb->s_blocksize_bits;
 		inode_set_bytes(inode, inode->i_size);
 		count = inode->i_size >> tree->node_size_shift;
-		tree->free_nodes = count - tree->node_count;
+		tree->free_nodes += count - tree->node_count;
 		tree->node_count = count;
 	}
+	return 0;
+}
+
+struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
+{
+	struct hfs_bnode *node, *next_node;
+	struct page **pagep;
+	u32 nidx, idx;
+	unsigned off;
+	u16 off16;
+	u16 len;
+	u8 *data, byte, m;
+	int i, res;
+
+	res = hfs_bmap_reserve(tree, 1);
+	if (res)
+		return ERR_PTR(res);
 
 	nidx = 0;
 	node = hfs_bnode_find(tree, nidx);
@@ -328,13 +337,14 @@
 
 		nidx -= len * 8;
 		i = node->next;
-		hfs_bnode_put(node);
 		if (!i) {
 			/* panic */;
 			pr_crit("unable to free bnode %u. bmap not found!\n",
 				node->this);
+			hfs_bnode_put(node);
 			return;
 		}
+		hfs_bnode_put(node);
 		node = hfs_bnode_find(tree, i);
 		if (IS_ERR(node))
 			return;
--- linux-4.4.0.orig/fs/hfs/btree.h
+++ linux-4.4.0/fs/hfs/btree.h
@@ -81,6 +81,7 @@
 extern struct hfs_btree *hfs_btree_open(struct super_block *, u32, btree_keycmp);
 extern void hfs_btree_close(struct hfs_btree *);
 extern void hfs_btree_write(struct hfs_btree *);
+extern int hfs_bmap_reserve(struct hfs_btree *, int);
 extern struct hfs_bnode * hfs_bmap_alloc(struct hfs_btree *);
 extern void hfs_bmap_free(struct hfs_bnode *node);
 
@@ -88,7 +89,7 @@
 extern void hfs_bnode_read(struct hfs_bnode *, void *, int, int);
 extern u16 hfs_bnode_read_u16(struct hfs_bnode *, int);
 extern u8 hfs_bnode_read_u8(struct hfs_bnode *, int);
-extern void hfs_bnode_read_key(struct hfs_bnode *, void *, int);
+extern int hfs_bnode_read_key(struct hfs_bnode *, void *, int);
 extern void hfs_bnode_write(struct hfs_bnode *, void *, int, int);
 extern void hfs_bnode_write_u16(struct hfs_bnode *, int, u16);
 extern void hfs_bnode_write_u8(struct hfs_bnode *, int, u8);
--- linux-4.4.0.orig/fs/hfs/catalog.c
+++ linux-4.4.0/fs/hfs/catalog.c
@@ -97,6 +97,14 @@
 	if (err)
 		return err;
 
+	/*
+	 * Fail early and avoid ENOSPC during the btree operations. We may
+	 * have to split the root node at most once.
+	 */
+	err = hfs_bmap_reserve(fd.tree, 2 * fd.tree->depth);
+	if (err)
+		goto err2;
+
 	hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
 	entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
 			HFS_CDR_THD : HFS_CDR_FTH,
@@ -294,6 +302,14 @@
 		return err;
 	dst_fd = src_fd;
 
+	/*
+	 * Fail early and avoid ENOSPC during the btree operations. We may
+	 * have to split the root node at most once.
+	 */
+	err = hfs_bmap_reserve(src_fd.tree, 2 * src_fd.tree->depth);
+	if (err)
+		goto out;
+
 	/* find the old dir entry and read the data */
 	hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
 	err = hfs_brec_find(&src_fd);
--- linux-4.4.0.orig/fs/hfs/extent.c
+++ linux-4.4.0/fs/hfs/extent.c
@@ -117,6 +117,10 @@
 	if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) {
 		if (res != -ENOENT)
 			return res;
+		/* Fail early and avoid ENOSPC during the btree operation */
+		res = hfs_bmap_reserve(fd->tree, fd->tree->depth + 1);
+		if (res)
+			return res;
 		hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec));
 		HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
 	} else {
@@ -300,7 +304,7 @@
 		return 0;
 
 	blocks = 0;
-	for (i = 0; i < 3; extent++, i++)
+	for (i = 0; i < 3; i++)
 		blocks += be16_to_cpu(extent[i].count);
 
 	res = hfs_free_extents(sb, extent, blocks, blocks);
@@ -341,7 +345,9 @@
 	ablock = (u32)block / HFS_SB(sb)->fs_div;
 
 	if (block >= HFS_I(inode)->fs_blocks) {
-		if (block > HFS_I(inode)->fs_blocks || !create)
+		if (!create)
+			return 0;
+		if (block > HFS_I(inode)->fs_blocks)
 			return -EIO;
 		if (ablock >= HFS_I(inode)->alloc_blocks) {
 			res = hfs_extend_file(inode);
--- linux-4.4.0.orig/fs/hfs/inode.c
+++ linux-4.4.0/fs/hfs/inode.c
@@ -197,6 +197,7 @@
 	HFS_I(inode)->flags = 0;
 	HFS_I(inode)->rsrc_inode = NULL;
 	HFS_I(inode)->fs_blocks = 0;
+	HFS_I(inode)->tz_secondswest = sys_tz.tz_minuteswest * 60;
 	if (S_ISDIR(mode)) {
 		inode->i_size = 2;
 		HFS_SB(sb)->folder_count++;
@@ -272,6 +273,8 @@
 	for (count = 0, i = 0; i < 3; i++)
 		count += be16_to_cpu(ext[i].count);
 	HFS_I(inode)->first_blocks = count;
+	HFS_I(inode)->cached_start = 0;
+	HFS_I(inode)->cached_blocks = 0;
 
 	inode->i_size = HFS_I(inode)->phys_size = log_size;
 	HFS_I(inode)->fs_blocks = (log_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
@@ -604,7 +607,7 @@
 	struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
 	int error;
 
-	error = inode_change_ok(inode, attr); /* basic permission checks */
+	error = setattr_prepare(dentry, attr); /* basic permission checks */
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/hfsplus/attributes.c
+++ linux-4.4.0/fs/hfsplus/attributes.c
@@ -216,6 +216,11 @@
 	if (err)
 		goto failed_init_create_attr;
 
+	/* Fail early and avoid ENOSPC during the btree operation */
+	err = hfs_bmap_reserve(fd.tree, fd.tree->depth + 1);
+	if (err)
+		goto failed_create_attr;
+
 	if (name) {
 		err = hfsplus_attr_build_key(sb, fd.search_key,
 						inode->i_ino, name);
@@ -286,6 +291,10 @@
 		return -ENOENT;
 	}
 
+	/* Avoid btree corruption */
+	hfs_bnode_read(fd->bnode, fd->search_key,
+			fd->keyoffset, fd->keylength);
+
 	err = hfs_brec_remove(fd);
 	if (err)
 		return err;
@@ -312,6 +321,11 @@
 	if (err)
 		return err;
 
+	/* Fail early and avoid ENOSPC during the btree operation */
+	err = hfs_bmap_reserve(fd.tree, fd.tree->depth);
+	if (err)
+		goto out;
+
 	if (name) {
 		err = hfsplus_attr_build_key(sb, fd.search_key,
 						inode->i_ino, name);
--- linux-4.4.0.orig/fs/hfsplus/bnode.c
+++ linux-4.4.0/fs/hfsplus/bnode.c
@@ -55,7 +55,7 @@
 	return data;
 }
 
-void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
+int hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
 {
 	struct hfs_btree *tree;
 	int key_len;
@@ -68,7 +68,13 @@
 	else
 		key_len = tree->max_key_len + 2;
 
+	if (key_len > tree->max_key_len + 2) {
+		pr_err("key_len %d too large\n", key_len);
+		return -EINVAL;
+	}
+
 	hfs_bnode_read(node, key, off, key_len);
+	return 0;
 }
 
 void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
--- linux-4.4.0.orig/fs/hfsplus/brec.c
+++ linux-4.4.0/fs/hfsplus/brec.c
@@ -67,6 +67,7 @@
 	int data_off, end_off;
 	int idx_rec_off, data_rec_off, end_rec_off;
 	__be32 cnid;
+	int res;
 
 	tree = fd->tree;
 	if (!fd->bnode) {
@@ -136,7 +137,10 @@
 	 * at the start of the node and it is not the new node
 	 */
 	if (!rec && new_node != node) {
-		hfs_bnode_read_key(node, fd->search_key, data_off + size);
+		res = hfs_bnode_read_key(node, fd->search_key, data_off + size);
+		if (res < 0)
+			return res;
+
 		hfs_brec_update_parent(fd);
 	}
 
@@ -154,7 +158,10 @@
 		entry_len = sizeof(cnid);
 
 		/* get index key */
-		hfs_bnode_read_key(new_node, fd->search_key, 14);
+		res = hfs_bnode_read_key(new_node, fd->search_key, 14);
+		if (res < 0)
+			return res;
+
 		__hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key);
 
 		hfs_bnode_put(new_node);
@@ -358,6 +365,7 @@
 	int newkeylen, diff;
 	int rec, rec_off, end_rec_off;
 	int start_off, end_off;
+	int res;
 
 	tree = fd->tree;
 	node = fd->bnode;
@@ -427,9 +435,16 @@
 	if (new_node) {
 		__be32 cnid;
 
+		if (!new_node->parent) {
+			hfs_btree_inc_height(tree);
+			new_node->parent = tree->root;
+		}
 		fd->bnode = hfs_bnode_find(tree, new_node->parent);
 		/* create index key and entry */
-		hfs_bnode_read_key(new_node, fd->search_key, 14);
+		res = hfs_bnode_read_key(new_node, fd->search_key, 14);
+		if (res < 0)
+			return res;
+
 		cnid = cpu_to_be32(new_node->this);
 
 		__hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key);
@@ -441,8 +456,11 @@
 			if (new_node == node)
 				goto out;
 			/* restore search_key */
-			hfs_bnode_read_key(node, fd->search_key, 14);
+			res = hfs_bnode_read_key(node, fd->search_key, 14);
+			if (res < 0)
+				return res;
 		}
+		new_node = NULL;
 	}
 
 	if (!rec && node->parent)
--- linux-4.4.0.orig/fs/hfsplus/btree.c
+++ linux-4.4.0/fs/hfsplus/btree.c
@@ -341,26 +341,21 @@
 	return node;
 }
 
-struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
+/* Make sure @tree has enough space for the @rsvd_nodes */
+int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes)
 {
-	struct hfs_bnode *node, *next_node;
-	struct page **pagep;
-	u32 nidx, idx;
-	unsigned off;
-	u16 off16;
-	u16 len;
-	u8 *data, byte, m;
-	int i;
+	struct inode *inode = tree->inode;
+	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
+	u32 count;
+	int res;
 
-	while (!tree->free_nodes) {
-		struct inode *inode = tree->inode;
-		struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
-		u32 count;
-		int res;
+	if (rsvd_nodes <= 0)
+		return 0;
 
+	while (tree->free_nodes < rsvd_nodes) {
 		res = hfsplus_file_extend(inode, hfs_bnode_need_zeroout(tree));
 		if (res)
-			return ERR_PTR(res);
+			return res;
 		hip->phys_size = inode->i_size =
 			(loff_t)hip->alloc_blocks <<
 				HFSPLUS_SB(tree->sb)->alloc_blksz_shift;
@@ -368,9 +363,26 @@
 			hip->alloc_blocks << HFSPLUS_SB(tree->sb)->fs_shift;
 		inode_set_bytes(inode, inode->i_size);
 		count = inode->i_size >> tree->node_size_shift;
-		tree->free_nodes = count - tree->node_count;
+		tree->free_nodes += count - tree->node_count;
 		tree->node_count = count;
 	}
+	return 0;
+}
+
+struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
+{
+	struct hfs_bnode *node, *next_node;
+	struct page **pagep;
+	u32 nidx, idx;
+	unsigned off;
+	u16 off16;
+	u16 len;
+	u8 *data, byte, m;
+	int i, res;
+
+	res = hfs_bmap_reserve(tree, 1);
+	if (res)
+		return ERR_PTR(res);
 
 	nidx = 0;
 	node = hfs_bnode_find(tree, nidx);
@@ -453,14 +465,15 @@
 
 		nidx -= len * 8;
 		i = node->next;
-		hfs_bnode_put(node);
 		if (!i) {
 			/* panic */;
 			pr_crit("unable to free bnode %u. "
 					"bmap not found!\n",
 				node->this);
+			hfs_bnode_put(node);
 			return;
 		}
+		hfs_bnode_put(node);
 		node = hfs_bnode_find(tree, i);
 		if (IS_ERR(node))
 			return;
--- linux-4.4.0.orig/fs/hfsplus/catalog.c
+++ linux-4.4.0/fs/hfsplus/catalog.c
@@ -264,6 +264,14 @@
 	if (err)
 		return err;
 
+	/*
+	 * Fail early and avoid ENOSPC during the btree operations. We may
+	 * have to split the root node at most once.
+	 */
+	err = hfs_bmap_reserve(fd.tree, 2 * fd.tree->depth);
+	if (err)
+		goto err2;
+
 	hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid);
 	entry_size = hfsplus_fill_cat_thread(sb, &entry,
 		S_ISDIR(inode->i_mode) ?
@@ -332,6 +340,14 @@
 	if (err)
 		return err;
 
+	/*
+	 * Fail early and avoid ENOSPC during the btree operations. We may
+	 * have to split the root node at most once.
+	 */
+	err = hfs_bmap_reserve(fd.tree, 2 * (int)fd.tree->depth - 2);
+	if (err)
+		goto out;
+
 	if (!str) {
 		int len;
 
@@ -429,6 +445,14 @@
 		return err;
 	dst_fd = src_fd;
 
+	/*
+	 * Fail early and avoid ENOSPC during the btree operations. We may
+	 * have to split the root node at most twice.
+	 */
+	err = hfs_bmap_reserve(src_fd.tree, 4 * (int)src_fd.tree->depth - 1);
+	if (err)
+		goto out;
+
 	/* find the old dir entry and read the data */
 	err = hfsplus_cat_build_key(sb, src_fd.search_key,
 			src_dir->i_ino, src_name);
--- linux-4.4.0.orig/fs/hfsplus/dir.c
+++ linux-4.4.0/fs/hfsplus/dir.c
@@ -77,13 +77,13 @@
 				cpu_to_be32(HFSP_HARDLINK_TYPE) &&
 				entry.file.user_info.fdCreator ==
 				cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
+				HFSPLUS_SB(sb)->hidden_dir &&
 				(entry.file.create_date ==
 					HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->
 						create_date ||
 				entry.file.create_date ==
 					HFSPLUS_I(d_inode(sb->s_root))->
-						create_date) &&
-				HFSPLUS_SB(sb)->hidden_dir) {
+						create_date)) {
 			struct qstr str;
 			char name[32];
 
--- linux-4.4.0.orig/fs/hfsplus/extents.c
+++ linux-4.4.0/fs/hfsplus/extents.c
@@ -99,6 +99,10 @@
 	if (hip->extent_state & HFSPLUS_EXT_NEW) {
 		if (res != -ENOENT)
 			return res;
+		/* Fail early and avoid ENOSPC during the btree operation */
+		res = hfs_bmap_reserve(fd->tree, fd->tree->depth + 1);
+		if (res)
+			return res;
 		hfs_brec_insert(fd, hip->cached_extents,
 				sizeof(hfsplus_extent_rec));
 		hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
@@ -232,7 +236,9 @@
 	ablock = iblock >> sbi->fs_shift;
 
 	if (iblock >= hip->fs_blocks) {
-		if (iblock > hip->fs_blocks || !create)
+		if (!create)
+			return 0;
+		if (iblock > hip->fs_blocks)
 			return -EIO;
 		if (ablock >= hip->alloc_blocks) {
 			res = hfsplus_file_extend(inode, false);
--- linux-4.4.0.orig/fs/hfsplus/hfsplus_fs.h
+++ linux-4.4.0/fs/hfsplus/hfsplus_fs.h
@@ -156,6 +156,7 @@
 
 	/* Runtime variables */
 	u32 blockoffset;
+	u32 min_io_size;
 	sector_t part_start;
 	sector_t sect_count;
 	int fs_shift;
@@ -303,13 +304,14 @@
  */
 static inline unsigned short hfsplus_min_io_size(struct super_block *sb)
 {
-	return max_t(unsigned short, bdev_logical_block_size(sb->s_bdev),
+	return max_t(unsigned short, HFSPLUS_SB(sb)->min_io_size,
 		     HFSPLUS_SECTOR_SIZE);
 }
 
 #define hfs_btree_open hfsplus_btree_open
 #define hfs_btree_close hfsplus_btree_close
 #define hfs_btree_write hfsplus_btree_write
+#define hfs_bmap_reserve hfsplus_bmap_reserve
 #define hfs_bmap_alloc hfsplus_bmap_alloc
 #define hfs_bmap_free hfsplus_bmap_free
 #define hfs_bnode_read hfsplus_bnode_read
@@ -394,6 +396,7 @@
 struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id);
 void hfs_btree_close(struct hfs_btree *tree);
 int hfs_btree_write(struct hfs_btree *tree);
+int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes);
 struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree);
 void hfs_bmap_free(struct hfs_bnode *node);
 
@@ -401,7 +404,7 @@
 void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len);
 u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off);
 u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off);
-void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off);
+int hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off);
 void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len);
 void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data);
 void hfs_bnode_clear(struct hfs_bnode *node, int off, int len);
--- linux-4.4.0.orig/fs/hfsplus/inode.c
+++ linux-4.4.0/fs/hfsplus/inode.c
@@ -246,7 +246,7 @@
 	struct inode *inode = d_inode(dentry);
 	int error;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/hfsplus/posix_acl.c
+++ linux-4.4.0/fs/hfsplus/posix_acl.c
@@ -68,8 +68,8 @@
 	case ACL_TYPE_ACCESS:
 		xattr_name = POSIX_ACL_XATTR_ACCESS;
 		if (acl) {
-			err = posix_acl_equiv_mode(acl, &inode->i_mode);
-			if (err < 0)
+			err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+			if (err)
 				return err;
 		}
 		err = 0;
--- linux-4.4.0.orig/fs/hfsplus/super.c
+++ linux-4.4.0/fs/hfsplus/super.c
@@ -291,11 +291,11 @@
 		hfsplus_sync_fs(sb, 1);
 	}
 
+	iput(sbi->alloc_file);
+	iput(sbi->hidden_dir);
 	hfs_btree_close(sbi->attr_tree);
 	hfs_btree_close(sbi->cat_tree);
 	hfs_btree_close(sbi->ext_tree);
-	iput(sbi->alloc_file);
-	iput(sbi->hidden_dir);
 	kfree(sbi->s_vhdr_buf);
 	kfree(sbi->s_backup_vhdr_buf);
 	unload_nls(sbi->nls);
@@ -521,8 +521,10 @@
 		goto out_put_root;
 	if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
 		hfs_find_exit(&fd);
-		if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
+		if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) {
+			err = -EINVAL;
 			goto out_put_root;
+		}
 		inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
 		if (IS_ERR(inode)) {
 			err = PTR_ERR(inode);
@@ -585,6 +587,7 @@
 	return 0;
 
 out_put_hidden_dir:
+	cancel_delayed_work_sync(&sbi->sync_work);
 	iput(sbi->hidden_dir);
 out_put_root:
 	dput(sb->s_root);
--- linux-4.4.0.orig/fs/hfsplus/wrapper.c
+++ linux-4.4.0/fs/hfsplus/wrapper.c
@@ -167,6 +167,8 @@
 	if (!blocksize)
 		goto out;
 
+	sbi->min_io_size = blocksize;
+
 	if (hfsplus_get_last_session(sb, &part_start, &part_size))
 		goto out;
 
--- linux-4.4.0.orig/fs/hfsplus/xattr.c
+++ linux-4.4.0/fs/hfsplus/xattr.c
@@ -712,7 +712,7 @@
 		return err;
 	}
 
-	strbuf = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN +
+	strbuf = kzalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN +
 			XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL);
 	if (!strbuf) {
 		res = -ENOMEM;
--- linux-4.4.0.orig/fs/hostfs/hostfs_kern.c
+++ linux-4.4.0/fs/hostfs/hostfs_kern.c
@@ -730,15 +730,13 @@
 
 	init_special_inode(inode, mode, dev);
 	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
-	if (!err)
+	if (err)
 		goto out_free;
 
 	err = read_name(inode, name);
 	__putname(name);
 	if (err)
 		goto out_put;
-	if (err)
-		goto out_put;
 
 	d_instantiate(dentry, inode);
 	return 0;
@@ -814,7 +812,7 @@
 
 	int fd = HOSTFS_I(inode)->fd;
 
-	err = inode_change_ok(inode, attr);
+	err = setattr_prepare(dentry, attr);
 	if (err)
 		return err;
 
@@ -961,10 +959,11 @@
 
 	if (S_ISLNK(root_inode->i_mode)) {
 		char *name = follow_link(host_root_path);
-		if (IS_ERR(name))
+		if (IS_ERR(name)) {
 			err = PTR_ERR(name);
-		else
-			err = read_name(root_inode, name);
+			goto out_put;
+		}
+		err = read_name(root_inode, name);
 		kfree(name);
 		if (err)
 			goto out_put;
--- linux-4.4.0.orig/fs/hpfs/inode.c
+++ linux-4.4.0/fs/hpfs/inode.c
@@ -272,7 +272,7 @@
 	if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size)
 		goto out_unlock;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		goto out_unlock;
 
--- linux-4.4.0.orig/fs/hpfs/namei.c
+++ linux-4.4.0/fs/hpfs/namei.c
@@ -375,12 +375,11 @@
 	struct inode *inode = d_inode(dentry);
 	dnode_secno dno;
 	int r;
-	int rep = 0;
 	int err;
 
 	hpfs_lock(dir->i_sb);
 	hpfs_adjust_length(name, &len);
-again:
+
 	err = -ENOENT;
 	de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
 	if (!de)
@@ -400,33 +399,9 @@
 		hpfs_error(dir->i_sb, "there was error when removing dirent");
 		err = -EFSERROR;
 		break;
-	case 2:		/* no space for deleting, try to truncate file */
-
+	case 2:		/* no space for deleting */
 		err = -ENOSPC;
-		if (rep++)
-			break;
-
-		dentry_unhash(dentry);
-		if (!d_unhashed(dentry)) {
-			hpfs_unlock(dir->i_sb);
-			return -ENOSPC;
-		}
-		if (generic_permission(inode, MAY_WRITE) ||
-		    !S_ISREG(inode->i_mode) ||
-		    get_write_access(inode)) {
-			d_rehash(dentry);
-		} else {
-			struct iattr newattrs;
-			/*pr_info("truncating file before delete.\n");*/
-			newattrs.ia_size = 0;
-			newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-			err = notify_change(dentry, &newattrs, NULL);
-			put_write_access(inode);
-			if (!err)
-				goto again;
-		}
-		hpfs_unlock(dir->i_sb);
-		return -ENOSPC;
+		break;
 	default:
 		drop_nlink(inode);
 		err = 0;
--- linux-4.4.0.orig/fs/hpfs/super.c
+++ linux-4.4.0/fs/hpfs/super.c
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/bitmap.h>
 #include <linux/slab.h>
+#include <linux/seq_file.h>
 
 /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */
 
@@ -453,10 +454,6 @@
 	int lowercase, eas, chk, errs, chkdsk, timeshift;
 	int o;
 	struct hpfs_sb_info *sbi = hpfs_sb(s);
-	char *new_opts = kstrdup(data, GFP_KERNEL);
-
-	if (!new_opts)
-		return -ENOMEM;
 
 	sync_filesystem(s);
 
@@ -493,17 +490,44 @@
 
 	if (!(*flags & MS_RDONLY)) mark_dirty(s, 1);
 
-	replace_mount_options(s, new_opts);
-
 	hpfs_unlock(s);
 	return 0;
 
 out_err:
 	hpfs_unlock(s);
-	kfree(new_opts);
 	return -EINVAL;
 }
 
+static int hpfs_show_options(struct seq_file *seq, struct dentry *root)
+{
+	struct hpfs_sb_info *sbi = hpfs_sb(root->d_sb);
+
+	seq_printf(seq, ",uid=%u", from_kuid_munged(&init_user_ns, sbi->sb_uid));
+	seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, sbi->sb_gid));
+	seq_printf(seq, ",umask=%03o", (~sbi->sb_mode & 0777));
+	if (sbi->sb_lowercase)
+		seq_printf(seq, ",case=lower");
+	if (!sbi->sb_chk)
+		seq_printf(seq, ",check=none");
+	if (sbi->sb_chk == 2)
+		seq_printf(seq, ",check=strict");
+	if (!sbi->sb_err)
+		seq_printf(seq, ",errors=continue");
+	if (sbi->sb_err == 2)
+		seq_printf(seq, ",errors=panic");
+	if (!sbi->sb_chkdsk)
+		seq_printf(seq, ",chkdsk=no");
+	if (sbi->sb_chkdsk == 2)
+		seq_printf(seq, ",chkdsk=always");
+	if (!sbi->sb_eas)
+		seq_printf(seq, ",eas=no");
+	if (sbi->sb_eas == 1)
+		seq_printf(seq, ",eas=ro");
+	if (sbi->sb_timeshift)
+		seq_printf(seq, ",timeshift=%d", sbi->sb_timeshift);
+	return 0;
+}
+
 /* Super operations */
 
 static const struct super_operations hpfs_sops =
@@ -514,7 +538,7 @@
 	.put_super	= hpfs_put_super,
 	.statfs		= hpfs_statfs,
 	.remount_fs	= hpfs_remount_fs,
-	.show_options	= generic_show_options,
+	.show_options	= hpfs_show_options,
 };
 
 static int hpfs_fill_super(struct super_block *s, void *options, int silent)
@@ -537,8 +561,6 @@
 
 	int o;
 
-	save_mount_options(s, options);
-
 	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
 	if (!sbi) {
 		return -ENOMEM;
--- linux-4.4.0.orig/fs/hugetlbfs/inode.c
+++ linux-4.4.0/fs/hugetlbfs/inode.c
@@ -118,6 +118,16 @@
 	pagevec_reinit(pvec);
 }
 
+/*
+ * Mask used when checking the page offset value passed in via system
+ * calls.  This value will be converted to a loff_t which is signed.
+ * Therefore, we want to check the upper PAGE_SHIFT + 1 bits of the
+ * value.  The extra bit (- 1 in the shift value) is to take the sign
+ * bit into account.
+ */
+#define PGOFF_LOFFT_MAX \
+	(((1UL << (PAGE_SHIFT + 1)) - 1) <<  (BITS_PER_LONG - (PAGE_SHIFT + 1)))
+
 static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct inode *inode = file_inode(file);
@@ -136,17 +146,31 @@
 	vma->vm_flags |= VM_HUGETLB | VM_DONTEXPAND;
 	vma->vm_ops = &hugetlb_vm_ops;
 
+	/*
+	 * page based offset in vm_pgoff could be sufficiently large to
+	 * overflow a loff_t when converted to byte offset.  This can
+	 * only happen on architectures where sizeof(loff_t) ==
+	 * sizeof(unsigned long).  So, only check in those instances.
+	 */
+	if (sizeof(unsigned long) == sizeof(loff_t)) {
+		if (vma->vm_pgoff & PGOFF_LOFFT_MAX)
+			return -EINVAL;
+	}
+
+	/* must be huge page aligned */
 	if (vma->vm_pgoff & (~huge_page_mask(h) >> PAGE_SHIFT))
 		return -EINVAL;
 
 	vma_len = (loff_t)(vma->vm_end - vma->vm_start);
+	len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
+	/* check for overflow */
+	if (len < vma_len)
+		return -EINVAL;
 
 	mutex_lock(&inode->i_mutex);
 	file_accessed(file);
 
 	ret = -ENOMEM;
-	len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
-
 	if (hugetlb_reserve_pages(inode,
 				vma->vm_pgoff >> huge_page_order(h),
 				len >> huge_page_shift(h), vma,
@@ -155,7 +179,7 @@
 
 	ret = 0;
 	if (vma->vm_flags & VM_WRITE && inode->i_size < len)
-		inode->i_size = len;
+		i_size_write(inode, len);
 out:
 	mutex_unlock(&inode->i_mutex);
 
@@ -191,7 +215,7 @@
 		addr = ALIGN(addr, huge_page_size(h));
 		vma = find_vma(mm, addr);
 		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)))
 			return addr;
 	}
 
@@ -390,9 +414,7 @@
 			if (next >= end)
 				break;
 
-			hash = hugetlb_fault_mutex_hash(h, current->mm,
-							&pseudo_vma,
-							mapping, next, 0);
+			hash = hugetlb_fault_mutex_hash(h, mapping, next, 0);
 			mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
 			lock_page(page);
@@ -463,6 +485,7 @@
 	 */
 	vma_interval_tree_foreach(vma, root, start, end ? end : ULONG_MAX) {
 		unsigned long v_offset;
+		unsigned long v_end;
 
 		/*
 		 * Can the expression below overflow on 32-bit arches?
@@ -475,15 +498,17 @@
 		else
 			v_offset = 0;
 
-		if (end) {
-			end = ((end - start) << PAGE_SHIFT) +
-			       vma->vm_start + v_offset;
-			if (end > vma->vm_end)
-				end = vma->vm_end;
-		} else
-			end = vma->vm_end;
+		if (!end)
+			v_end = vma->vm_end;
+		else {
+			v_end = ((end - vma->vm_pgoff) << PAGE_SHIFT)
+							+ vma->vm_start;
+			if (v_end > vma->vm_end)
+				v_end = vma->vm_end;
+		}
 
-		unmap_hugepage_range(vma, vma->vm_start + v_offset, end, NULL);
+		unmap_hugepage_range(vma, vma->vm_start + v_offset, v_end,
+									NULL);
 	}
 }
 
@@ -542,7 +567,6 @@
 	struct address_space *mapping = inode->i_mapping;
 	struct hstate *h = hstate_inode(inode);
 	struct vm_area_struct pseudo_vma;
-	struct mm_struct *mm = current->mm;
 	loff_t hpage_size = huge_page_size(h);
 	unsigned long hpage_shift = huge_page_shift(h);
 	pgoff_t start, index, end;
@@ -606,8 +630,7 @@
 		addr = index * hpage_size;
 
 		/* mutex taken here, fault path and hole punch */
-		hash = hugetlb_fault_mutex_hash(h, mm, &pseudo_vma, mapping,
-						index, addr);
+		hash = hugetlb_fault_mutex_hash(h, mapping, index, addr);
 		mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
 		/* See if already present in mapping to avoid alloc/free */
@@ -638,8 +661,9 @@
 
 		mutex_unlock(&hugetlb_fault_mutex_table[hash]);
 
+		set_page_huge_active(page);
 		/*
-		 * page_put due to reference from alloc_huge_page()
+		 * put_page() due to reference from alloc_huge_page()
 		 * unlock_page because locked by add_to_page_cache()
 		 */
 		put_page(page);
@@ -663,7 +687,7 @@
 
 	BUG_ON(!inode);
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
@@ -718,11 +742,17 @@
 					umode_t mode, dev_t dev)
 {
 	struct inode *inode;
-	struct resv_map *resv_map;
+	struct resv_map *resv_map = NULL;
 
-	resv_map = resv_map_alloc();
-	if (!resv_map)
-		return NULL;
+	/*
+	 * Reserve maps are only needed for inodes that can have associated
+	 * page allocations.
+	 */
+	if (S_ISREG(mode) || S_ISLNK(mode)) {
+		resv_map = resv_map_alloc();
+		if (!resv_map)
+			return NULL;
+	}
 
 	inode = new_inode(sb);
 	if (inode) {
@@ -763,8 +793,10 @@
 			break;
 		}
 		lockdep_annotate_inode_mutex_key(inode);
-	} else
-		kref_put(&resv_map->refs, resv_map_release);
+	} else {
+		if (resv_map)
+			kref_put(&resv_map->refs, resv_map_release);
+	}
 
 	return inode;
 }
@@ -842,6 +874,18 @@
 	rc = migrate_huge_page_move_mapping(mapping, newpage, page);
 	if (rc != MIGRATEPAGE_SUCCESS)
 		return rc;
+
+	/*
+	 * page_private is subpool pointer in hugetlb pages.  Transfer to
+	 * new page.  PagePrivate is not associated with page_private for
+	 * hugetlb pages and can not be set here as only page_huge_active
+	 * pages can be migrated.
+	 */
+	if (page_private(page)) {
+		set_page_private(newpage, page_private(page));
+		set_page_private(page, 0);
+	}
+
 	migrate_page_copy(newpage, page);
 
 	return MIGRATEPAGE_SUCCESS;
--- linux-4.4.0.orig/fs/inode.c
+++ linux-4.4.0/fs/inode.c
@@ -135,6 +135,7 @@
 	inode->i_sb = sb;
 	inode->i_blkbits = sb->s_blocksize_bits;
 	inode->i_flags = 0;
+	atomic64_set(&inode->i_sequence, 0);
 	atomic_set(&inode->i_count, 1);
 	inode->i_op = &empty_iops;
 	inode->i_fop = &no_open_fops;
@@ -154,8 +155,12 @@
 	inode->i_rdev = 0;
 	inode->dirtied_when = 0;
 
-	if (security_inode_alloc(inode))
-		goto out;
+#ifdef CONFIG_CGROUP_WRITEBACK
+	inode->i_wb_frn_winner = 0;
+	inode->i_wb_frn_avg_time = 0;
+	inode->i_wb_frn_history = 0;
+#endif
+
 	spin_lock_init(&inode->i_lock);
 	lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
 
@@ -182,6 +187,9 @@
 	inode->i_fsnotify_mask = 0;
 #endif
 	inode->i_flctx = NULL;
+
+	if (security_inode_alloc(inode))
+		goto out;
 	this_cpu_inc(nr_inodes);
 
 	return 0;
@@ -1610,6 +1618,13 @@
 
 	if (inode->i_flags & S_NOATIME)
 		return false;
+
+	/* Atime updates will likely cause i_uid and i_gid to be written
+	 * back improprely if their true value is unknown to the vfs.
+	 */
+	if (HAS_UNMAPPED_ID(inode))
+		return false;
+
 	if (IS_NOATIME(inode))
 		return false;
 	if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
@@ -1670,7 +1685,8 @@
  */
 int should_remove_suid(struct dentry *dentry)
 {
-	umode_t mode = d_inode(dentry)->i_mode;
+	struct inode *inode = d_inode(dentry);
+	umode_t mode = inode->i_mode;
 	int kill = 0;
 
 	/* suid always must be killed */
@@ -1684,7 +1700,8 @@
 	if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
 		kill |= ATTR_KILL_SGID;
 
-	if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
+	if (unlikely(kill && !capable_wrt_inode_uidgid(inode, CAP_FSETID) &&
+		     S_ISREG(mode)))
 		return kill;
 
 	return 0;
@@ -1733,16 +1750,21 @@
  */
 int file_remove_privs(struct file *file)
 {
-	struct dentry *dentry = file->f_path.dentry;
-	struct inode *inode = d_inode(dentry);
+	struct dentry *dentry = file_dentry(file);
+	struct inode *inode = file_inode(file);
 	int kill;
 	int error = 0;
 
-	/* Fast path for nothing security related */
-	if (IS_NOSEC(inode))
+	/*
+	 * Fast path for nothing security related.
+	 * As well for non-regular files, e.g. blkdev inodes.
+	 * For example, blkdev_write_iter() might get here
+	 * trying to remove privs which it is not allowed to.
+	 */
+	if (IS_NOSEC(inode) || !S_ISREG(inode->i_mode))
 		return 0;
 
-	kill = file_needs_remove_privs(file);
+	kill = dentry_needs_remove_privs(dentry);
 	if (kill < 0)
 		return kill;
 	if (kill)
@@ -1937,8 +1959,14 @@
 	inode->i_uid = current_fsuid();
 	if (dir && dir->i_mode & S_ISGID) {
 		inode->i_gid = dir->i_gid;
+
+		/* Directories are special, and always inherit S_ISGID */
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
+		else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
+			 !in_group_p(inode->i_gid) &&
+			 !capable_wrt_inode_uidgid(dir, CAP_FSETID))
+			mode &= ~S_ISGID;
 	} else
 		inode->i_gid = current_fsgid();
 	inode->i_mode = mode;
@@ -2028,3 +2056,9 @@
 				  new_flags) != old_flags));
 }
 EXPORT_SYMBOL(inode_set_flags);
+
+void inode_nohighmem(struct inode *inode)
+{
+	mapping_set_gfp_mask(inode->i_mapping, GFP_USER);
+}
+EXPORT_SYMBOL(inode_nohighmem);
--- linux-4.4.0.orig/fs/ioctl.c
+++ linux-4.4.0/fs/ioctl.c
@@ -519,7 +519,7 @@
 {
 	struct super_block *sb = file_inode(filp)->i_sb;
 
-	if (!capable(CAP_SYS_ADMIN))
+	if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
 		return -EPERM;
 
 	/* If filesystem doesn't support freeze feature, return. */
@@ -536,7 +536,7 @@
 {
 	struct super_block *sb = file_inode(filp)->i_sb;
 
-	if (!capable(CAP_SYS_ADMIN))
+	if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
 		return -EPERM;
 
 	/* Thaw */
--- linux-4.4.0.orig/fs/isofs/dir.c
+++ linux-4.4.0/fs/isofs/dir.c
@@ -151,6 +151,7 @@
 			printk(KERN_NOTICE "iso9660: Corrupted directory entry"
 			       " in block %lu of inode %lu\n", block,
 			       inode->i_ino);
+			brelse(bh);
 			return -EIO;
 		}
 
--- linux-4.4.0.orig/fs/isofs/inode.c
+++ linux-4.4.0/fs/isofs/inode.c
@@ -690,6 +690,11 @@
 	pri_bh = NULL;
 
 root_found:
+	/* We don't support read-write mounts */
+	if (!(s->s_flags & MS_RDONLY)) {
+		error = -EACCES;
+		goto out_freebh;
+	}
 
 	if (joliet_level && (pri == NULL || !opt.rock)) {
 		/* This is the case of Joliet with the norock mount flag.
@@ -1503,9 +1508,6 @@
 static struct dentry *isofs_mount(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data)
 {
-	/* We don't support read-write mounts */
-	if (!(flags & MS_RDONLY))
-		return ERR_PTR(-EACCES);
 	return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
 }
 
--- linux-4.4.0.orig/fs/isofs/isofs.h
+++ linux-4.4.0/fs/isofs/isofs.h
@@ -103,7 +103,7 @@
 	/* Ignore bigendian datum due to broken mastering programs */
 	return get_unaligned_le32(p);
 }
-extern int iso_date(char *, int);
+extern int iso_date(u8 *, int);
 
 struct inode;		/* To make gcc happy */
 
--- linux-4.4.0.orig/fs/isofs/namei.c
+++ linux-4.4.0/fs/isofs/namei.c
@@ -101,6 +101,7 @@
 			printk(KERN_NOTICE "iso9660: Corrupted directory entry"
 			       " in block %lu of inode %lu\n", block,
 			       dir->i_ino);
+			brelse(bh);
 			return 0;
 		}
 
--- linux-4.4.0.orig/fs/isofs/rock.c
+++ linux-4.4.0/fs/isofs/rock.c
@@ -203,6 +203,8 @@
 	int retnamlen = 0;
 	int truncate = 0;
 	int ret = 0;
+	char *p;
+	int len;
 
 	if (!ISOFS_SB(inode->i_sb)->s_rock)
 		return 0;
@@ -267,12 +269,17 @@
 					rr->u.NM.flags);
 				break;
 			}
-			if ((strlen(retname) + rr->len - 5) >= 254) {
+			len = rr->len - 5;
+			if (retnamlen + len >= 254) {
 				truncate = 1;
 				break;
 			}
-			strncat(retname, rr->u.NM.name, rr->len - 5);
-			retnamlen += rr->len - 5;
+			p = memchr(rr->u.NM.name, '\0', len);
+			if (unlikely(p))
+				len = p - rr->u.NM.name;
+			memcpy(retname + retnamlen, rr->u.NM.name, len);
+			retnamlen += len;
+			retname[retnamlen] = '\0';
 			break;
 		case SIG('R', 'E'):
 			kfree(rs.buffer);
--- linux-4.4.0.orig/fs/isofs/rock.h
+++ linux-4.4.0/fs/isofs/rock.h
@@ -65,7 +65,7 @@
 };
 
 struct stamp {
-	char time[7];
+	__u8 time[7];		/* actually 6 unsigned, 1 signed */
 } __attribute__ ((packed));
 
 struct RR_TF_s {
--- linux-4.4.0.orig/fs/isofs/util.c
+++ linux-4.4.0/fs/isofs/util.c
@@ -15,7 +15,7 @@
  * to GMT.  Thus  we should always be correct.
  */
 
-int iso_date(char * p, int flag)
+int iso_date(u8 *p, int flag)
 {
 	int year, month, day, hour, minute, second, tz;
 	int crtime;
--- linux-4.4.0.orig/fs/jbd2/checkpoint.c
+++ linux-4.4.0/fs/jbd2/checkpoint.c
@@ -147,8 +147,11 @@
 			write_unlock(&journal->j_state_lock);
 			if (chkpt) {
 				jbd2_log_do_checkpoint(journal);
-			} else if (jbd2_cleanup_journal_tail(journal) == 0) {
-				/* We were able to recover space; yay! */
+			} else if (jbd2_cleanup_journal_tail(journal) <= 0) {
+				/*
+				 * We were able to recover space or the
+				 * journal was aborted due to an error.
+				 */
 				;
 			} else if (tid) {
 				/*
@@ -168,7 +171,7 @@
 				       "journal space in %s\n", __func__,
 				       journal->j_devname);
 				WARN_ON(1);
-				jbd2_journal_abort(journal, 0);
+				jbd2_journal_abort(journal, -EIO);
 			}
 			write_lock(&journal->j_state_lock);
 		} else {
@@ -254,8 +257,8 @@
 		bh = jh2bh(jh);
 
 		if (buffer_locked(bh)) {
-			spin_unlock(&journal->j_list_lock);
 			get_bh(bh);
+			spin_unlock(&journal->j_list_lock);
 			wait_on_buffer(bh);
 			/* the journal_head may have gone by now */
 			BUFFER_TRACE(bh, "brelse");
@@ -336,8 +339,8 @@
 		jh = transaction->t_checkpoint_io_list;
 		bh = jh2bh(jh);
 		if (buffer_locked(bh)) {
-			spin_unlock(&journal->j_list_lock);
 			get_bh(bh);
+			spin_unlock(&journal->j_list_lock);
 			wait_on_buffer(bh);
 			/* the journal_head may have gone by now */
 			BUFFER_TRACE(bh, "brelse");
--- linux-4.4.0.orig/fs/jbd2/commit.c
+++ linux-4.4.0/fs/jbd2/commit.c
@@ -124,7 +124,7 @@
 	struct commit_header *tmp;
 	struct buffer_head *bh;
 	int ret;
-	struct timespec now = current_kernel_time();
+	struct timespec64 now = current_kernel_time64();
 
 	*cbh = NULL;
 
@@ -740,7 +740,6 @@
 				submit_bh(WRITE_SYNC, bh);
 			}
 			cond_resched();
-			stats.run.rs_blocks_logged += bufs;
 
 			/* Force a new descriptor to be generated next
                            time round the loop. */
@@ -798,7 +797,7 @@
 		err = journal_submit_commit_record(journal, commit_transaction,
 						 &cbh, crc32_sum);
 		if (err)
-			__jbd2_journal_abort_hard(journal);
+			jbd2_journal_abort(journal, err);
 	}
 
 	blk_finish_plug(&plug);
@@ -827,6 +826,7 @@
 		if (unlikely(!buffer_uptodate(bh)))
 			err = -EIO;
 		jbd2_unfile_log_bh(bh);
+		stats.run.rs_blocks_logged++;
 
 		/*
 		 * The list contains temporary buffer heads created by
@@ -872,6 +872,7 @@
 		BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile");
 		clear_buffer_jwrite(bh);
 		jbd2_unfile_log_bh(bh);
+		stats.run.rs_blocks_logged++;
 		__brelse(bh);		/* One for getblk */
 		/* AKPM: bforget here */
 	}
@@ -889,10 +890,11 @@
 		err = journal_submit_commit_record(journal, commit_transaction,
 						&cbh, crc32_sum);
 		if (err)
-			__jbd2_journal_abort_hard(journal);
+			jbd2_journal_abort(journal, err);
 	}
 	if (cbh)
 		err = journal_wait_on_commit_record(journal, cbh);
+	stats.run.rs_blocks_logged++;
 	if (jbd2_has_feature_async_commit(journal) &&
 	    journal->j_flags & JBD2_BARRIER) {
 		blkdev_issue_flush(journal->j_dev, GFP_NOFS, NULL);
@@ -985,29 +987,34 @@
 		 * it. */
 
 		/*
-		* A buffer which has been freed while still being journaled by
-		* a previous transaction.
-		*/
-		if (buffer_freed(bh)) {
+		 * A buffer which has been freed while still being journaled
+		 * by a previous transaction, refile the buffer to BJ_Forget of
+		 * the running transaction. If the just committed transaction
+		 * contains "add to orphan" operation, we can completely
+		 * invalidate the buffer now. We are rather through in that
+		 * since the buffer may be still accessible when blocksize <
+		 * pagesize and it is attached to the last partial page.
+		 */
+		if (buffer_freed(bh) && !jh->b_next_transaction) {
+			struct address_space *mapping;
+
+			clear_buffer_freed(bh);
+			clear_buffer_jbddirty(bh);
+
 			/*
-			 * If the running transaction is the one containing
-			 * "add to orphan" operation (b_next_transaction !=
-			 * NULL), we have to wait for that transaction to
-			 * commit before we can really get rid of the buffer.
-			 * So just clear b_modified to not confuse transaction
-			 * credit accounting and refile the buffer to
-			 * BJ_Forget of the running transaction. If the just
-			 * committed transaction contains "add to orphan"
-			 * operation, we can completely invalidate the buffer
-			 * now. We are rather through in that since the
-			 * buffer may be still accessible when blocksize <
-			 * pagesize and it is attached to the last partial
-			 * page.
+			 * Block device buffers need to stay mapped all the
+			 * time, so it is enough to clear buffer_jbddirty and
+			 * buffer_freed bits. For the file mapping buffers (i.e.
+			 * journalled data) we need to unmap buffer and clear
+			 * more bits. We also need to be careful about the check
+			 * because the data page mapping can get cleared under
+			 * our hands. Note that if mapping == NULL, we don't
+			 * need to make buffer unmapped because the page is
+			 * already detached from the mapping and buffers cannot
+			 * get reused.
 			 */
-			jh->b_modified = 0;
-			if (!jh->b_next_transaction) {
-				clear_buffer_freed(bh);
-				clear_buffer_jbddirty(bh);
+			mapping = READ_ONCE(bh->b_page->mapping);
+			if (mapping && !sb_is_blkdev_sb(mapping->host->i_sb)) {
 				clear_buffer_mapped(bh);
 				clear_buffer_new(bh);
 				clear_buffer_req(bh);
--- linux-4.4.0.orig/fs/jbd2/journal.c
+++ linux-4.4.0/fs/jbd2/journal.c
@@ -275,11 +275,11 @@
 	goto loop;
 
 end_loop:
-	write_unlock(&journal->j_state_lock);
 	del_timer_sync(&journal->j_commit_timer);
 	journal->j_task = NULL;
 	wake_up(&journal->j_wait_done_commit);
 	jbd_debug(1, "Journal thread exiting.\n");
+	write_unlock(&journal->j_state_lock);
 	return 0;
 }
 
@@ -914,7 +914,7 @@
 }
 
 /*
- * This is a variaon of __jbd2_update_log_tail which checks for validity of
+ * This is a variation of __jbd2_update_log_tail which checks for validity of
  * provided log tail and locks j_checkpoint_mutex. So it is safe against races
  * with other threads updating log tail.
  */
@@ -1384,6 +1384,9 @@
 	journal_superblock_t *sb = journal->j_superblock;
 	int ret;
 
+	if (is_journal_aborted(journal))
+		return -EIO;
+
 	BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
 	jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n",
 		  tail_block, tail_tid);
@@ -1408,11 +1411,12 @@
 /**
  * jbd2_mark_journal_empty() - Mark on disk journal as empty.
  * @journal: The journal to update.
+ * @write_op: With which operation should we write the journal sb
  *
  * Update a journal's dynamic superblock fields to show that journal is empty.
  * Write updated superblock to disk waiting for IO to complete.
  */
-static void jbd2_mark_journal_empty(journal_t *journal)
+static void jbd2_mark_journal_empty(journal_t *journal, int write_op)
 {
 	journal_superblock_t *sb = journal->j_superblock;
 
@@ -1430,7 +1434,7 @@
 	sb->s_start    = cpu_to_be32(0);
 	read_unlock(&journal->j_state_lock);
 
-	jbd2_write_superblock(journal, WRITE_FUA);
+	jbd2_write_superblock(journal, write_op);
 
 	/* Log is no longer empty */
 	write_lock(&journal->j_state_lock);
@@ -1652,6 +1656,11 @@
 		       journal->j_devname);
 		return -EFSCORRUPTED;
 	}
+	/*
+	 * clear JBD2_ABORT flag initialized in journal_init_common
+	 * here to update log tail information with the newest seq.
+	 */
+	journal->j_flags &= ~JBD2_ABORT;
 
 	/* OK, we've finished with the dynamic journal bits:
 	 * reinitialise the dynamic contents of the superblock in memory
@@ -1659,7 +1668,6 @@
 	if (journal_reset(journal))
 		goto recovery_error;
 
-	journal->j_flags &= ~JBD2_ABORT;
 	journal->j_flags |= JBD2_LOADED;
 	return 0;
 
@@ -1716,7 +1724,13 @@
 	if (journal->j_sb_buffer) {
 		if (!is_journal_aborted(journal)) {
 			mutex_lock(&journal->j_checkpoint_mutex);
-			jbd2_mark_journal_empty(journal);
+
+			write_lock(&journal->j_state_lock);
+			journal->j_tail_sequence =
+				++journal->j_transaction_sequence;
+			write_unlock(&journal->j_state_lock);
+
+			jbd2_mark_journal_empty(journal, WRITE_FLUSH_FUA);
 			mutex_unlock(&journal->j_checkpoint_mutex);
 		} else
 			err = -EIO;
@@ -1975,7 +1989,7 @@
 	 * the magic code for a fully-recovered superblock.  Any future
 	 * commits of data to the journal will restore the current
 	 * s_start value. */
-	jbd2_mark_journal_empty(journal);
+	jbd2_mark_journal_empty(journal, WRITE_FUA);
 	mutex_unlock(&journal->j_checkpoint_mutex);
 	write_lock(&journal->j_state_lock);
 	J_ASSERT(!journal->j_running_transaction);
@@ -2021,7 +2035,7 @@
 	if (write) {
 		/* Lock to make assertions happy... */
 		mutex_lock(&journal->j_checkpoint_mutex);
-		jbd2_mark_journal_empty(journal);
+		jbd2_mark_journal_empty(journal, WRITE_FUA);
 		mutex_unlock(&journal->j_checkpoint_mutex);
 	}
 
@@ -2072,12 +2086,10 @@
 
 	__jbd2_journal_abort_hard(journal);
 
-	if (errno) {
-		jbd2_journal_update_sb_errno(journal);
-		write_lock(&journal->j_state_lock);
-		journal->j_flags |= JBD2_REC_ERR;
-		write_unlock(&journal->j_state_lock);
-	}
+	jbd2_journal_update_sb_errno(journal);
+	write_lock(&journal->j_state_lock);
+	journal->j_flags |= JBD2_REC_ERR;
+	write_unlock(&journal->j_state_lock);
 }
 
 /**
@@ -2119,11 +2131,6 @@
  * failure to disk.  ext3_error, for example, now uses this
  * functionality.
  *
- * Errors which originate from within the journaling layer will NOT
- * supply an errno; a null errno implies that absolutely no further
- * writes are done to the journal (unless there are any already in
- * progress).
- *
  */
 
 void jbd2_journal_abort(journal_t *journal, int errno)
--- linux-4.4.0.orig/fs/jbd2/transaction.c
+++ linux-4.4.0/fs/jbd2/transaction.c
@@ -527,6 +527,7 @@
 	 */
 	ret = start_this_handle(journal, handle, GFP_NOFS);
 	if (ret < 0) {
+		handle->h_journal = journal;
 		jbd2_journal_free_reserved(handle);
 		return ret;
 	}
@@ -1040,8 +1041,8 @@
 	/* For undo access buffer must have data copied */
 	if (undo && !jh->b_committed_data)
 		goto out;
-	if (jh->b_transaction != handle->h_transaction &&
-	    jh->b_next_transaction != handle->h_transaction)
+	if (READ_ONCE(jh->b_transaction) != handle->h_transaction &&
+	    READ_ONCE(jh->b_next_transaction) != handle->h_transaction)
 		goto out;
 	/*
 	 * There are two reasons for the barrier here:
@@ -1156,6 +1157,7 @@
 		JBUFFER_TRACE(jh, "file as BJ_Reserved");
 		spin_lock(&journal->j_list_lock);
 		__jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
+		spin_unlock(&journal->j_list_lock);
 	} else if (jh->b_transaction == journal->j_committing_transaction) {
 		/* first access by this transaction */
 		jh->b_modified = 0;
@@ -1163,8 +1165,8 @@
 		JBUFFER_TRACE(jh, "set next transaction");
 		spin_lock(&journal->j_list_lock);
 		jh->b_next_transaction = transaction;
+		spin_unlock(&journal->j_list_lock);
 	}
-	spin_unlock(&journal->j_list_lock);
 	jbd_unlock_bh_state(bh);
 
 	/*
@@ -1213,11 +1215,12 @@
 	struct journal_head *jh;
 	char *committed_data = NULL;
 
-	JBUFFER_TRACE(jh, "entry");
 	if (jbd2_write_access_granted(handle, bh, true))
 		return 0;
 
 	jh = jbd2_journal_add_journal_head(bh);
+	JBUFFER_TRACE(jh, "entry");
+
 	/*
 	 * Do this first --- it can drop the journal lock, so we want to
 	 * make sure that obtaining the committed_data is done
@@ -1334,15 +1337,17 @@
 
 	if (is_handle_aborted(handle))
 		return -EROFS;
-	if (!buffer_jbd(bh)) {
-		ret = -EUCLEAN;
-		goto out;
-	}
+	if (!buffer_jbd(bh))
+		return -EUCLEAN;
+
 	/*
 	 * We don't grab jh reference here since the buffer must be part
 	 * of the running transaction.
 	 */
 	jh = bh2jh(bh);
+	jbd_debug(5, "journal_head %p\n", jh);
+	JBUFFER_TRACE(jh, "entry");
+
 	/*
 	 * This and the following assertions are unreliable since we may see jh
 	 * in inconsistent state unless we grab bh_state lock. But this is
@@ -1361,6 +1366,13 @@
 		if (jh->b_transaction == transaction &&
 		    jh->b_jlist != BJ_Metadata) {
 			jbd_lock_bh_state(bh);
+			if (jh->b_transaction == transaction &&
+			    jh->b_jlist != BJ_Metadata)
+				pr_err("JBD2: assertion failure: h_type=%u "
+				       "h_line_no=%u block_no=%llu jlist=%u\n",
+				       handle->h_type, handle->h_line_no,
+				       (unsigned long long) bh->b_blocknr,
+				       jh->b_jlist);
 			J_ASSERT_JH(jh, jh->b_transaction != transaction ||
 					jh->b_jlist == BJ_Metadata);
 			jbd_unlock_bh_state(bh);
@@ -1369,9 +1381,6 @@
 	}
 
 	journal = transaction->t_journal;
-	jbd_debug(5, "journal_head %p\n", jh);
-	JBUFFER_TRACE(jh, "entry");
-
 	jbd_lock_bh_state(bh);
 
 	if (jh->b_modified == 0) {
@@ -1380,11 +1389,11 @@
 		 * of the transaction. This needs to be done
 		 * once a transaction -bzzz
 		 */
-		jh->b_modified = 1;
 		if (handle->h_buffer_credits <= 0) {
 			ret = -ENOSPC;
 			goto out_unlock_bh;
 		}
+		jh->b_modified = 1;
 		handle->h_buffer_credits--;
 	}
 
@@ -1569,14 +1578,21 @@
 		/* However, if the buffer is still owned by a prior
 		 * (committing) transaction, we can't drop it yet... */
 		JBUFFER_TRACE(jh, "belongs to older transaction");
-		/* ... but we CAN drop it from the new transaction if we
-		 * have also modified it since the original commit. */
+		/* ... but we CAN drop it from the new transaction through
+		 * marking the buffer as freed and set j_next_transaction to
+		 * the new transaction, so that not only the commit code
+		 * knows it should clear dirty bits when it is done with the
+		 * buffer, but also the buffer can be checkpointed only
+		 * after the new transaction commits. */
 
-		if (jh->b_next_transaction) {
-			J_ASSERT(jh->b_next_transaction == transaction);
+		set_buffer_freed(bh);
+
+		if (!jh->b_next_transaction) {
 			spin_lock(&journal->j_list_lock);
-			jh->b_next_transaction = NULL;
+			jh->b_next_transaction = transaction;
 			spin_unlock(&journal->j_list_lock);
+		} else {
+			J_ASSERT(jh->b_next_transaction == transaction);
 
 			/*
 			 * only drop a reference if this transaction modified
@@ -1875,7 +1891,9 @@
 
 	__blist_del_buffer(list, jh);
 	jh->b_jlist = BJ_None;
-	if (test_clear_buffer_jbddirty(bh))
+	if (transaction && is_journal_aborted(transaction->t_journal))
+		clear_buffer_jbddirty(bh);
+	else if (test_clear_buffer_jbddirty(bh))
 		mark_buffer_dirty(bh);	/* Expose it to the VM */
 }
 
@@ -1888,6 +1906,9 @@
  */
 static void __jbd2_journal_unfile_buffer(struct journal_head *jh)
 {
+	J_ASSERT_JH(jh, jh->b_transaction != NULL);
+	J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+
 	__jbd2_journal_temp_unlink_buffer(jh);
 	jh->b_transaction = NULL;
 	jbd2_journal_put_journal_head(jh);
@@ -1979,6 +2000,7 @@
 {
 	struct buffer_head *head;
 	struct buffer_head *bh;
+	bool has_write_io_error = false;
 	int ret = 0;
 
 	J_ASSERT(PageLocked(page));
@@ -2003,11 +2025,26 @@
 		jbd_unlock_bh_state(bh);
 		if (buffer_jbd(bh))
 			goto busy;
+
+		/*
+		 * If we free a metadata buffer which has been failed to
+		 * write out, the jbd2 checkpoint procedure will not detect
+		 * this failure and may lead to filesystem inconsistency
+		 * after cleanup journal tail.
+		 */
+		if (buffer_write_io_error(bh)) {
+			pr_err("JBD2: Error while async write back metadata bh %llu.",
+			       (unsigned long long)bh->b_blocknr);
+			has_write_io_error = true;
+		}
 	} while ((bh = bh->b_this_page) != head);
 
 	ret = try_to_free_buffers(page);
 
 busy:
+	if (has_write_io_error)
+		jbd2_journal_abort(journal, -EIO);
+
 	return ret;
 }
 
@@ -2205,14 +2242,16 @@
 			return -EBUSY;
 		}
 		/*
-		 * OK, buffer won't be reachable after truncate. We just set
-		 * j_next_transaction to the running transaction (if there is
-		 * one) and mark buffer as freed so that commit code knows it
-		 * should clear dirty bits when it is done with the buffer.
+		 * OK, buffer won't be reachable after truncate. We just clear
+		 * b_modified to not confuse transaction credit accounting, and
+		 * set j_next_transaction to the running transaction (if there
+		 * is one) and mark buffer as freed so that commit code knows
+		 * it should clear dirty bits when it is done with the buffer.
 		 */
 		set_buffer_freed(bh);
 		if (journal->j_running_transaction && buffer_jbddirty(bh))
 			jh->b_next_transaction = journal->j_running_transaction;
+		jh->b_modified = 0;
 		jbd2_journal_put_journal_head(jh);
 		spin_unlock(&journal->j_list_lock);
 		jbd_unlock_bh_state(bh);
@@ -2433,13 +2472,20 @@
 
 	was_dirty = test_clear_buffer_jbddirty(bh);
 	__jbd2_journal_temp_unlink_buffer(jh);
+
+	/*
+	 * b_transaction must be set, otherwise the new b_transaction won't
+	 * be holding jh reference
+	 */
+	J_ASSERT_JH(jh, jh->b_transaction != NULL);
+
 	/*
 	 * We set b_transaction here because b_next_transaction will inherit
 	 * our jh reference and thus __jbd2_journal_file_buffer() must not
 	 * take a new one.
 	 */
-	jh->b_transaction = jh->b_next_transaction;
-	jh->b_next_transaction = NULL;
+	WRITE_ONCE(jh->b_transaction, jh->b_next_transaction);
+	WRITE_ONCE(jh->b_next_transaction, NULL);
 	if (buffer_freed(bh))
 		jlist = BJ_Forget;
 	else if (jh->b_modified)
--- linux-4.4.0.orig/fs/jffs2/README.Locking
+++ linux-4.4.0/fs/jffs2/README.Locking
@@ -2,10 +2,6 @@
 	JFFS2 LOCKING DOCUMENTATION
 	---------------------------
 
-At least theoretically, JFFS2 does not require the Big Kernel Lock
-(BKL), which was always helpfully obtained for it by Linux 2.4 VFS
-code. It has its own locking, as described below.
-
 This document attempts to describe the existing locking rules for
 JFFS2. It is not expected to remain perfectly up to date, but ought to
 be fairly close.
@@ -69,6 +65,7 @@
 	   any f->sem held.
 	2. Never attempt to lock two file mutexes in one thread.
 	   No ordering rules have been made for doing so.
+	3. Never lock a page cache page with f->sem held.
 
 
 	erase_completion_lock spinlock
--- linux-4.4.0.orig/fs/jffs2/acl.c
+++ linux-4.4.0/fs/jffs2/acl.c
@@ -235,9 +235,10 @@
 	case ACL_TYPE_ACCESS:
 		xprefix = JFFS2_XPREFIX_ACL_ACCESS;
 		if (acl) {
-			umode_t mode = inode->i_mode;
-			rc = posix_acl_equiv_mode(acl, &mode);
-			if (rc < 0)
+			umode_t mode;
+
+			rc = posix_acl_update_mode(inode, &mode, &acl);
+			if (rc)
 				return rc;
 			if (inode->i_mode != mode) {
 				struct iattr attr;
@@ -249,8 +250,6 @@
 				if (rc < 0)
 					return rc;
 			}
-			if (rc == 0)
-				acl = NULL;
 		}
 		break;
 	case ACL_TYPE_DEFAULT:
--- linux-4.4.0.orig/fs/jffs2/build.c
+++ linux-4.4.0/fs/jffs2/build.c
@@ -49,7 +49,8 @@
 
 
 static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
-				    struct jffs2_inode_cache *ic)
+				    struct jffs2_inode_cache *ic,
+				    int *dir_hardlinks)
 {
 	struct jffs2_full_dirent *fd;
 
@@ -68,19 +69,21 @@
 			dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
 				  fd->name, fd->ino, ic->ino);
 			jffs2_mark_node_obsolete(c, fd->raw);
+			/* Clear the ic/raw union so it doesn't cause problems later. */
+			fd->ic = NULL;
 			continue;
 		}
 
+		/* From this point, fd->raw is no longer used so we can set fd->ic */
+		fd->ic = child_ic;
+		child_ic->pino_nlink++;
+		/* If we appear (at this stage) to have hard-linked directories,
+		 * set a flag to trigger a scan later */
 		if (fd->type == DT_DIR) {
-			if (child_ic->pino_nlink) {
-				JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
-					    fd->name, fd->ino, ic->ino);
-				/* TODO: What do we do about it? */
-			} else {
-				child_ic->pino_nlink = ic->ino;
-			}
-		} else
-			child_ic->pino_nlink++;
+			child_ic->flags |= INO_FLAGS_IS_DIR;
+			if (child_ic->pino_nlink > 1)
+				*dir_hardlinks = 1;
+		}
 
 		dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
 		/* Can't free scan_dents so far. We might need them in pass 2 */
@@ -94,8 +97,7 @@
 */
 static int jffs2_build_filesystem(struct jffs2_sb_info *c)
 {
-	int ret;
-	int i;
+	int ret, i, dir_hardlinks = 0;
 	struct jffs2_inode_cache *ic;
 	struct jffs2_full_dirent *fd;
 	struct jffs2_full_dirent *dead_fds = NULL;
@@ -119,7 +121,7 @@
 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
 	for_each_inode(i, c, ic) {
 		if (ic->scan_dents) {
-			jffs2_build_inode_pass1(c, ic);
+			jffs2_build_inode_pass1(c, ic, &dir_hardlinks);
 			cond_resched();
 		}
 	}
@@ -155,6 +157,20 @@
 	}
 
 	dbg_fsbuild("pass 2a complete\n");
+
+	if (dir_hardlinks) {
+		/* If we detected directory hardlinks earlier, *hopefully*
+		 * they are gone now because some of the links were from
+		 * dead directories which still had some old dirents lying
+		 * around and not yet garbage-collected, but which have
+		 * been discarded above. So clear the pino_nlink field
+		 * in each directory, so that the final scan below can
+		 * print appropriate warnings. */
+		for_each_inode(i, c, ic) {
+			if (ic->flags & INO_FLAGS_IS_DIR)
+				ic->pino_nlink = 0;
+		}
+	}
 	dbg_fsbuild("freeing temporary data structures\n");
 
 	/* Finally, we can scan again and free the dirent structs */
@@ -162,6 +178,33 @@
 		while(ic->scan_dents) {
 			fd = ic->scan_dents;
 			ic->scan_dents = fd->next;
+			/* We do use the pino_nlink field to count nlink of
+			 * directories during fs build, so set it to the
+			 * parent ino# now. Now that there's hopefully only
+			 * one. */
+			if (fd->type == DT_DIR) {
+				if (!fd->ic) {
+					/* We'll have complained about it and marked the coresponding
+					   raw node obsolete already. Just skip it. */
+					continue;
+				}
+
+				/* We *have* to have set this in jffs2_build_inode_pass1() */
+				BUG_ON(!(fd->ic->flags & INO_FLAGS_IS_DIR));
+
+				/* We clear ic->pino_nlink ∀ directories' ic *only* if dir_hardlinks
+				 * is set. Otherwise, we know this should never trigger anyway, so
+				 * we don't do the check. And ic->pino_nlink still contains the nlink
+				 * value (which is 1). */
+				if (dir_hardlinks && fd->ic->pino_nlink) {
+					JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u is also hard linked from dir ino #%u\n",
+						    fd->name, fd->ino, ic->ino, fd->ic->pino_nlink);
+					/* Should we unlink it from its previous parent? */
+				}
+
+				/* For directories, ic->pino_nlink holds that parent inode # */
+				fd->ic->pino_nlink = ic->ino;
+			}
 			jffs2_free_full_dirent(fd);
 		}
 		ic->scan_dents = NULL;
@@ -240,11 +283,7 @@
 
 			/* Reduce nlink of the child. If it's now zero, stick it on the
 			   dead_fds list to be cleaned up later. Else just free the fd */
-
-			if (fd->type == DT_DIR)
-				child_ic->pino_nlink = 0;
-			else
-				child_ic->pino_nlink--;
+			child_ic->pino_nlink--;
 
 			if (!child_ic->pino_nlink) {
 				dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
--- linux-4.4.0.orig/fs/jffs2/compr_rtime.c
+++ linux-4.4.0/fs/jffs2/compr_rtime.c
@@ -92,6 +92,9 @@
 
 		positions[value]=outpos;
 		if (repeat) {
+			if ((outpos + repeat) > destlen) {
+				return 1;
+			}
 			if (backoffs + repeat >= outpos) {
 				while(repeat) {
 					cpage_out[outpos++] = cpage_out[backoffs++];
--- linux-4.4.0.orig/fs/jffs2/dir.c
+++ linux-4.4.0/fs/jffs2/dir.c
@@ -207,8 +207,7 @@
 		  __func__, inode->i_ino, inode->i_mode, inode->i_nlink,
 		  f->inocache->pino_nlink, inode->i_mapping->nrpages);
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	return 0;
 
  fail:
@@ -428,8 +427,7 @@
 	mutex_unlock(&dir_f->sem);
 	jffs2_complete_reservation(c);
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	return 0;
 
  fail:
@@ -573,8 +571,7 @@
 	mutex_unlock(&dir_f->sem);
 	jffs2_complete_reservation(c);
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	return 0;
 
  fail:
@@ -591,10 +588,14 @@
 	int ret;
 	uint32_t now = get_seconds();
 
+	mutex_lock(&f->sem);
 	for (fd = f->dents ; fd; fd = fd->next) {
-		if (fd->ino)
+		if (fd->ino) {
+			mutex_unlock(&f->sem);
 			return -ENOTEMPTY;
+		}
 	}
+	mutex_unlock(&f->sem);
 
 	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
 			      dentry->d_name.len, f, now);
@@ -745,8 +746,7 @@
 	mutex_unlock(&dir_f->sem);
 	jffs2_complete_reservation(c);
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	return 0;
 
  fail:
@@ -843,9 +843,14 @@
 
 		pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n",
 			  __func__, ret);
-		/* Might as well let the VFS know */
-		d_instantiate(new_dentry, d_inode(old_dentry));
-		ihold(d_inode(old_dentry));
+		/*
+		 * We can't keep the target in dcache after that.
+		 * For one thing, we can't afford dentry aliases for directories.
+		 * For another, if there was a victim, we _can't_ set new inode
+		 * for that sucker and we have to trigger mount eviction - the
+		 * caller won't do it on its own since we are returning an error.
+		 */
+		d_invalidate(new_dentry);
 		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
 		return ret;
 	}
--- linux-4.4.0.orig/fs/jffs2/file.c
+++ linux-4.4.0/fs/jffs2/file.c
@@ -137,39 +137,33 @@
 	struct page *pg;
 	struct inode *inode = mapping->host;
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-	struct jffs2_raw_inode ri;
-	uint32_t alloc_len = 0;
 	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
 	uint32_t pageofs = index << PAGE_CACHE_SHIFT;
 	int ret = 0;
 
-	jffs2_dbg(1, "%s()\n", __func__);
-
-	if (pageofs > inode->i_size) {
-		ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
-					  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
-		if (ret)
-			return ret;
-	}
-
-	mutex_lock(&f->sem);
 	pg = grab_cache_page_write_begin(mapping, index, flags);
-	if (!pg) {
-		if (alloc_len)
-			jffs2_complete_reservation(c);
-		mutex_unlock(&f->sem);
+	if (!pg)
 		return -ENOMEM;
-	}
 	*pagep = pg;
 
-	if (alloc_len) {
+	jffs2_dbg(1, "%s()\n", __func__);
+
+	if (pageofs > inode->i_size) {
 		/* Make new hole frag from old EOF to new page */
+		struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+		struct jffs2_raw_inode ri;
 		struct jffs2_full_dnode *fn;
+		uint32_t alloc_len;
 
 		jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
 			  (unsigned int)inode->i_size, pageofs);
 
+		ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
+					  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
+		if (ret)
+			goto out_page;
+
+		mutex_lock(&f->sem);
 		memset(&ri, 0, sizeof(ri));
 
 		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -196,6 +190,7 @@
 		if (IS_ERR(fn)) {
 			ret = PTR_ERR(fn);
 			jffs2_complete_reservation(c);
+			mutex_unlock(&f->sem);
 			goto out_page;
 		}
 		ret = jffs2_add_full_dnode_to_inode(c, f, fn);
@@ -210,10 +205,12 @@
 			jffs2_mark_node_obsolete(c, fn->raw);
 			jffs2_free_full_dnode(fn);
 			jffs2_complete_reservation(c);
+			mutex_unlock(&f->sem);
 			goto out_page;
 		}
 		jffs2_complete_reservation(c);
 		inode->i_size = pageofs;
+		mutex_unlock(&f->sem);
 	}
 
 	/*
@@ -222,18 +219,18 @@
 	 * case of a short-copy.
 	 */
 	if (!PageUptodate(pg)) {
+		mutex_lock(&f->sem);
 		ret = jffs2_do_readpage_nolock(inode, pg);
+		mutex_unlock(&f->sem);
 		if (ret)
 			goto out_page;
 	}
-	mutex_unlock(&f->sem);
 	jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags);
 	return ret;
 
 out_page:
 	unlock_page(pg);
 	page_cache_release(pg);
-	mutex_unlock(&f->sem);
 	return ret;
 }
 
--- linux-4.4.0.orig/fs/jffs2/fs.c
+++ linux-4.4.0/fs/jffs2/fs.c
@@ -193,7 +193,7 @@
 	struct inode *inode = d_inode(dentry);
 	int rc;
 
-	rc = inode_change_ok(inode, iattr);
+	rc = setattr_prepare(dentry, iattr);
 	if (rc)
 		return rc;
 
@@ -361,7 +361,6 @@
 	ret = -EIO;
 error:
 	mutex_unlock(&f->sem);
-	jffs2_do_clear_inode(c, f);
 	iget_failed(inode);
 	return ERR_PTR(ret);
 }
--- linux-4.4.0.orig/fs/jffs2/gc.c
+++ linux-4.4.0/fs/jffs2/gc.c
@@ -1296,14 +1296,17 @@
 		BUG_ON(start > orig_start);
 	}
 
-	/* First, use readpage() to read the appropriate page into the page cache */
-	/* Q: What happens if we actually try to GC the _same_ page for which commit_write()
-	 *    triggered garbage collection in the first place?
-	 * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the
-	 *    page OK. We'll actually write it out again in commit_write, which is a little
-	 *    suboptimal, but at least we're correct.
-	 */
+	/* The rules state that we must obtain the page lock *before* f->sem, so
+	 * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's
+	 * actually going to *change* so we're safe; we only allow reading.
+	 *
+	 * It is important to note that jffs2_write_begin() will ensure that its
+	 * page is marked Uptodate before allocating space. That means that if we
+	 * end up here trying to GC the *same* page that jffs2_write_begin() is
+	 * trying to write out, read_cache_page() will not deadlock. */
+	mutex_unlock(&f->sem);
 	pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
+	mutex_lock(&f->sem);
 
 	if (IS_ERR(pg_ptr)) {
 		pr_warn("read_cache_page() returned error: %ld\n",
--- linux-4.4.0.orig/fs/jffs2/nodelist.h
+++ linux-4.4.0/fs/jffs2/nodelist.h
@@ -194,6 +194,7 @@
 #define INO_STATE_CLEARING	6	/* In clear_inode() */
 
 #define INO_FLAGS_XATTR_CHECKED	0x01	/* has no duplicate xattr_ref */
+#define INO_FLAGS_IS_DIR	0x02	/* is a directory */
 
 #define RAWNODE_CLASS_INODE_CACHE	0
 #define RAWNODE_CLASS_XATTR_DATUM	1
@@ -249,7 +250,10 @@
 
 struct jffs2_full_dirent
 {
-	struct jffs2_raw_node_ref *raw;
+	union {
+		struct jffs2_raw_node_ref *raw;
+		struct jffs2_inode_cache *ic; /* Just during part of build */
+	};
 	struct jffs2_full_dirent *next;
 	uint32_t version;
 	uint32_t ino; /* == zero for unlink */
--- linux-4.4.0.orig/fs/jffs2/readinode.c
+++ linux-4.4.0/fs/jffs2/readinode.c
@@ -672,6 +672,22 @@
 			jffs2_free_full_dirent(fd);
 			return -EIO;
 		}
+
+#ifdef CONFIG_JFFS2_SUMMARY
+		/*
+		 * we use CONFIG_JFFS2_SUMMARY because without it, we
+		 * have checked it while mounting
+		 */
+		crc = crc32(0, fd->name, rd->nsize);
+		if (unlikely(crc != je32_to_cpu(rd->name_crc))) {
+			JFFS2_NOTICE("name CRC failed on dirent node at"
+			   "%#08x: read %#08x,calculated %#08x\n",
+			   ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
+			jffs2_mark_node_obsolete(c, ref);
+			jffs2_free_full_dirent(fd);
+			return 0;
+		}
+#endif
 	}
 
 	fd->nhash = full_name_hash(fd->name, rd->nsize);
@@ -1414,11 +1430,6 @@
 
 	jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
 
-	if (f->target) {
-		kfree(f->target);
-		f->target = NULL;
-	}
-
 	fds = f->dents;
 	while(fds) {
 		fd = fds;
--- linux-4.4.0.orig/fs/jffs2/summary.c
+++ linux-4.4.0/fs/jffs2/summary.c
@@ -783,6 +783,8 @@
 					dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n",
 						    je16_to_cpu(temp->u.nodetype));
 					jffs2_sum_disable_collecting(c->summary);
+					/* The above call removes the list, nothing more to do */
+					goto bail_rwcompat;
 				} else {
 					BUG();	/* unknown node in summary information */
 				}
@@ -794,6 +796,7 @@
 
 		c->summary->sum_num--;
 	}
+ bail_rwcompat:
 
 	jffs2_sum_reset_collected(c->summary);
 
--- linux-4.4.0.orig/fs/jffs2/super.c
+++ linux-4.4.0/fs/jffs2/super.c
@@ -47,7 +47,10 @@
 static void jffs2_i_callback(struct rcu_head *head)
 {
 	struct inode *inode = container_of(head, struct inode, i_rcu);
-	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+
+	kfree(f->target);
+	kmem_cache_free(jffs2_inode_cachep, f);
 }
 
 static void jffs2_destroy_inode(struct inode *inode)
@@ -101,7 +104,8 @@
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
 
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-	cancel_delayed_work_sync(&c->wbuf_dwork);
+	if (jffs2_is_writebuffered(c))
+		cancel_delayed_work_sync(&c->wbuf_dwork);
 #endif
 
 	mutex_lock(&c->alloc_sem);
@@ -285,10 +289,8 @@
 	sb->s_fs_info = c;
 
 	ret = jffs2_parse_options(c, data);
-	if (ret) {
-		kfree(c);
+	if (ret)
 		return -EINVAL;
-	}
 
 	/* Initialize JFFS2 superblock locks, the further initialization will
 	 * be done later */
@@ -345,7 +347,7 @@
 static void jffs2_kill_sb(struct super_block *sb)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-	if (!(sb->s_flags & MS_RDONLY))
+	if (c && !(sb->s_flags & MS_RDONLY))
 		jffs2_stop_garbage_collect_thread(c);
 	kill_mtd_super(sb);
 	kfree(c);
--- linux-4.4.0.orig/fs/jffs2/xattr.c
+++ linux-4.4.0/fs/jffs2/xattr.c
@@ -1004,12 +1004,14 @@
 			rc = xhandle->list(xhandle, dentry, buffer + len,
 					   size - len, xd->xname,
 					   xd->name_len);
+			if (rc > size - len) {
+				rc = -ERANGE;
+				goto out;
+			}
 		} else {
 			rc = xhandle->list(xhandle, dentry, NULL, 0,
 					   xd->xname, xd->name_len);
 		}
-		if (rc < 0)
-			goto out;
 		len += rc;
 	}
 	rc = len;
--- linux-4.4.0.orig/fs/jfs/acl.c
+++ linux-4.4.0/fs/jfs/acl.c
@@ -84,13 +84,11 @@
 	case ACL_TYPE_ACCESS:
 		ea_name = POSIX_ACL_XATTR_ACCESS;
 		if (acl) {
-			rc = posix_acl_equiv_mode(acl, &inode->i_mode);
-			if (rc < 0)
+			rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+			if (rc)
 				return rc;
 			inode->i_ctime = CURRENT_TIME;
 			mark_inode_dirty(inode);
-			if (rc == 0)
-				acl = NULL;
 		}
 		break;
 	case ACL_TYPE_DEFAULT:
--- linux-4.4.0.orig/fs/jfs/file.c
+++ linux-4.4.0/fs/jfs/file.c
@@ -103,7 +103,7 @@
 	struct inode *inode = d_inode(dentry);
 	int rc;
 
-	rc = inode_change_ok(inode, iattr);
+	rc = setattr_prepare(dentry, iattr);
 	if (rc)
 		return rc;
 
--- linux-4.4.0.orig/fs/jfs/inode.c
+++ linux-4.4.0/fs/jfs/inode.c
@@ -155,12 +155,14 @@
 		dquot_initialize(inode);
 
 		if (JFS_IP(inode)->fileset == FILESYSTEM_I) {
+			struct inode *ipimap = JFS_SBI(inode->i_sb)->ipimap;
 			truncate_inode_pages_final(&inode->i_data);
 
 			if (test_cflag(COMMIT_Freewmap, inode))
 				jfs_free_zero_link(inode);
 
-			diFree(inode);
+			if (ipimap && JFS_IP(ipimap)->i_imap)
+				diFree(inode);
 
 			/*
 			 * Free the inode from the quota allocation.
--- linux-4.4.0.orig/fs/jfs/jfs_dmap.c
+++ linux-4.4.0/fs/jfs/jfs_dmap.c
@@ -76,10 +76,10 @@
  */
 static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
 			int nblocks);
-static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval);
-static int dbBackSplit(dmtree_t * tp, int leafno);
-static int dbJoin(dmtree_t * tp, int leafno, int newval);
-static void dbAdjTree(dmtree_t * tp, int leafno, int newval);
+static void dbSplit(dmtree_t *tp, int leafno, int splitsz, int newval, bool is_ctl);
+static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl);
+static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl);
+static void dbAdjTree(dmtree_t *tp, int leafno, int newval, bool is_ctl);
 static int dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc,
 		    int level);
 static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results);
@@ -100,7 +100,7 @@
 static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks);
 static int dbFindBits(u32 word, int l2nb);
 static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno);
-static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx);
+static int dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx, bool is_ctl);
 static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
 		      int nblocks);
 static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
@@ -391,7 +391,8 @@
 	}
 
 	/* write the last buffer. */
-	write_metapage(mp);
+	if (mp)
+		write_metapage(mp);
 
 	IREAD_UNLOCK(ipbmap);
 
@@ -1669,7 +1670,9 @@
 		} else if (rc == -ENOSPC) {
 			/* search for next smaller log2 block */
 			l2nb = BLKSTOL2(nblocks) - 1;
-			nblocks = 1 << l2nb;
+			if (unlikely(l2nb < 0))
+				break;
+			nblocks = 1LL << l2nb;
 		} else {
 			/* Trim any already allocated blocks */
 			jfs_error(bmp->db_ipbmap->i_sb, "-EIO\n");
@@ -1760,7 +1763,7 @@
 		 * dbFindLeaf() returns the index of the leaf at which
 		 * free space was found.
 		 */
-		rc = dbFindLeaf((dmtree_t *) dcp, l2nb, &leafidx);
+		rc = dbFindLeaf((dmtree_t *) dcp, l2nb, &leafidx, true);
 
 		/* release the buffer.
 		 */
@@ -2007,7 +2010,7 @@
 	 * free space.  if sufficient free space is found, dbFindLeaf()
 	 * returns the index of the leaf at which free space was found.
 	 */
-	if (dbFindLeaf((dmtree_t *) & dp->tree, l2nb, &leafidx))
+	if (dbFindLeaf((dmtree_t *) &dp->tree, l2nb, &leafidx, false))
 		return -ENOSPC;
 
 	/* determine the block number within the file system corresponding
@@ -2143,7 +2146,7 @@
 		 * system.
 		 */
 		if (dp->tree.stree[word] == NOFREE)
-			dbBackSplit((dmtree_t *) & dp->tree, word);
+			dbBackSplit((dmtree_t *)&dp->tree, word, false);
 
 		dbAllocBits(bmp, dp, blkno, nblocks);
 	}
@@ -2229,7 +2232,7 @@
 			 * the binary system of the leaves if need be.
 			 */
 			dbSplit(tp, word, BUDMIN,
-				dbMaxBud((u8 *) & dp->wmap[word]));
+				dbMaxBud((u8 *)&dp->wmap[word]), false);
 
 			word += 1;
 		} else {
@@ -2269,7 +2272,7 @@
 				 * system of the leaves to reflect the current
 				 * allocation (size).
 				 */
-				dbSplit(tp, word, size, NOFREE);
+				dbSplit(tp, word, size, NOFREE, false);
 
 				/* get the number of dmap words handled */
 				nw = BUDSIZE(size, BUDMIN);
@@ -2376,7 +2379,7 @@
 			/* update the leaf for this dmap word.
 			 */
 			rc = dbJoin(tp, word,
-				    dbMaxBud((u8 *) & dp->wmap[word]));
+				    dbMaxBud((u8 *)&dp->wmap[word]), false);
 			if (rc)
 				return rc;
 
@@ -2409,7 +2412,7 @@
 
 				/* update the leaf.
 				 */
-				rc = dbJoin(tp, word, size);
+				rc = dbJoin(tp, word, size, false);
 				if (rc)
 					return rc;
 
@@ -2561,16 +2564,20 @@
 		 * that it is at the front of a binary buddy system.
 		 */
 		if (oldval == NOFREE) {
-			rc = dbBackSplit((dmtree_t *) dcp, leafno);
-			if (rc)
+			rc = dbBackSplit((dmtree_t *)dcp, leafno, true);
+			if (rc) {
+				release_metapage(mp);
 				return rc;
+			}
 			oldval = dcp->stree[ti];
 		}
-		dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval);
+		dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval, true);
 	} else {
-		rc = dbJoin((dmtree_t *) dcp, leafno, newval);
-		if (rc)
+		rc = dbJoin((dmtree_t *) dcp, leafno, newval, true);
+		if (rc) {
+			release_metapage(mp);
 			return rc;
+		}
 	}
 
 	/* check if the root of the current dmap control page changed due
@@ -2597,7 +2604,7 @@
 				 */
 				if (alloc) {
 					dbJoin((dmtree_t *) dcp, leafno,
-					       oldval);
+					       oldval, true);
 				} else {
 					/* the dbJoin() above might have
 					 * caused a larger binary buddy system
@@ -2607,9 +2614,9 @@
 					 */
 					if (dcp->stree[ti] == NOFREE)
 						dbBackSplit((dmtree_t *)
-							    dcp, leafno);
+							    dcp, leafno, true);
 					dbSplit((dmtree_t *) dcp, leafno,
-						dcp->budmin, oldval);
+						dcp->budmin, oldval, true);
 				}
 
 				/* release the buffer and return the error.
@@ -2657,7 +2664,7 @@
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
-static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
+static void dbSplit(dmtree_t *tp, int leafno, int splitsz, int newval, bool is_ctl)
 {
 	int budsz;
 	int cursz;
@@ -2679,7 +2686,7 @@
 		while (cursz >= splitsz) {
 			/* update the buddy's leaf with its new value.
 			 */
-			dbAdjTree(tp, leafno ^ budsz, cursz);
+			dbAdjTree(tp, leafno ^ budsz, cursz, is_ctl);
 
 			/* on to the next size and buddy.
 			 */
@@ -2691,7 +2698,7 @@
 	/* adjust the dmap tree to reflect the specified leaf's new
 	 * value.
 	 */
-	dbAdjTree(tp, leafno, newval);
+	dbAdjTree(tp, leafno, newval, is_ctl);
 }
 
 
@@ -2722,7 +2729,7 @@
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
-static int dbBackSplit(dmtree_t * tp, int leafno)
+static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl)
 {
 	int budsz, bud, w, bsz, size;
 	int cursz;
@@ -2773,7 +2780,7 @@
 				 * system in two.
 				 */
 				cursz = leaf[bud] - 1;
-				dbSplit(tp, bud, cursz, cursz);
+				dbSplit(tp, bud, cursz, cursz, is_ctl);
 				break;
 			}
 		}
@@ -2801,7 +2808,7 @@
  *
  * RETURN VALUES: none
  */
-static int dbJoin(dmtree_t * tp, int leafno, int newval)
+static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl)
 {
 	int budsz, buddy;
 	s8 *leaf;
@@ -2856,12 +2863,12 @@
 			if (leafno < buddy) {
 				/* leafno is the left buddy.
 				 */
-				dbAdjTree(tp, buddy, NOFREE);
+				dbAdjTree(tp, buddy, NOFREE, is_ctl);
 			} else {
 				/* buddy is the left buddy and becomes
 				 * leafno.
 				 */
-				dbAdjTree(tp, leafno, NOFREE);
+				dbAdjTree(tp, leafno, NOFREE, is_ctl);
 				leafno = buddy;
 			}
 
@@ -2874,7 +2881,7 @@
 
 	/* update the leaf value.
 	 */
-	dbAdjTree(tp, leafno, newval);
+	dbAdjTree(tp, leafno, newval, is_ctl);
 
 	return 0;
 }
@@ -2895,15 +2902,20 @@
  *
  * RETURN VALUES: none
  */
-static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
+static void dbAdjTree(dmtree_t *tp, int leafno, int newval, bool is_ctl)
 {
 	int lp, pp, k;
-	int max;
+	int max, size;
+
+	size = is_ctl ? CTLTREESIZE : TREESIZE;
 
 	/* pick up the index of the leaf for this leafno.
 	 */
 	lp = leafno + le32_to_cpu(tp->dmt_leafidx);
 
+	if (WARN_ON_ONCE(lp >= size || lp < 0))
+		return;
+
 	/* is the current value the same as the old value ?  if so,
 	 * there is nothing to do.
 	 */
@@ -2917,6 +2929,9 @@
 	/* bubble the new value up the tree as required.
 	 */
 	for (k = 0; k < le32_to_cpu(tp->dmt_height); k++) {
+		if (lp == 0)
+			break;
+
 		/* get the index of the first leaf of the 4 leaf
 		 * group containing the specified leaf (leafno).
 		 */
@@ -2964,14 +2979,19 @@
  *	leafidx	- return pointer to be set to the index of the leaf
  *		  describing at least l2nb free blocks if sufficient
  *		  free blocks are found.
+ *	is_ctl	- determines if the tree is of type ctl
  *
  * RETURN VALUES:
  *	0	- success
  *	-ENOSPC	- insufficient free blocks.
  */
-static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
+static int dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx, bool is_ctl)
 {
 	int ti, n = 0, k, x = 0;
+	int max_size, max_idx;
+
+	max_size = is_ctl ? CTLTREESIZE : TREESIZE;
+	max_idx = is_ctl ? LPERCTL : LPERDMAP;
 
 	/* first check the root of the tree to see if there is
 	 * sufficient free space.
@@ -2992,6 +3012,8 @@
 			/* sufficient free space found.  move to the next
 			 * level (or quit if this is the last level).
 			 */
+			if (x + n > max_size)
+				return -ENOSPC;
 			if (l2nb <= tp->dmt_stree[x + n])
 				break;
 		}
@@ -3001,6 +3023,8 @@
 		 */
 		assert(n < 4);
 	}
+	if (le32_to_cpu(tp->dmt_leafidx) >= max_idx)
+		return -ENOSPC;
 
 	/* set the return to the leftmost leaf describing sufficient
 	 * free space.
--- linux-4.4.0.orig/fs/jfs/jfs_dmap.h
+++ linux-4.4.0/fs/jfs/jfs_dmap.h
@@ -196,7 +196,7 @@
 #define	dmt_leafidx	t1.leafidx
 #define	dmt_height	t1.height
 #define	dmt_budmin	t1.budmin
-#define	dmt_stree	t1.stree
+#define	dmt_stree	t2.stree
 
 /*
  *	on-disk aggregate disk allocation map descriptor.
--- linux-4.4.0.orig/fs/jfs/jfs_dtree.c
+++ linux-4.4.0/fs/jfs/jfs_dtree.c
@@ -645,6 +645,11 @@
 		for (base = 0, lim = p->header.nextindex; lim; lim >>= 1) {
 			index = base + (lim >> 1);
 
+			if (stbl[index] < 0) {
+				rc = -EIO;
+				goto out;
+			}
+
 			if (p->header.flag & BT_LEAF) {
 				/* uppercase leaf name to compare */
 				cmp =
@@ -1982,7 +1987,7 @@
 		do {
 			f = &rp->slot[fsi];
 			fsi = f->next;
-		} while (fsi != -1);
+		} while (fsi >= 0);
 
 		f->next = n;
 	}
@@ -3196,6 +3201,14 @@
 		stbl = DT_GETSTBL(p);
 
 		for (i = index; i < p->header.nextindex; i++) {
+			if (stbl[i] < 0 || stbl[i] > 127) {
+				jfs_err("JFS: Invalid stbl[%d] = %d for inode %ld, block = %lld",
+					i, stbl[i], (long)ip->i_ino, (long long)bn);
+				free_page(dirent_buf);
+				DT_PUTPAGE(mp);
+				return -EIO;
+			}
+
 			d = (struct ldtentry *) & p->slot[stbl[i]];
 
 			if (((long) jfs_dirent + d->namlen + 1) >
@@ -3391,6 +3404,13 @@
 
 		/* get the leftmost entry */
 		stbl = DT_GETSTBL(p);
+
+		if (stbl[0] < 0 || stbl[0] > 127) {
+			DT_PUTPAGE(mp);
+			jfs_error(ip->i_sb, "stbl[0] out of bound\n");
+			return -EIO;
+		}
+
 		xd = (pxd_t *) & p->slot[stbl[0]];
 
 		/* get the child page block address */
--- linux-4.4.0.orig/fs/jfs/jfs_filsys.h
+++ linux-4.4.0/fs/jfs/jfs_filsys.h
@@ -281,5 +281,6 @@
 				 * fsck() must be run to repair
 				 */
 #define	FM_EXTENDFS 0x00000008	/* file system extendfs() in progress */
+#define	FM_STATE_MAX 0x0000000f	/* max value of s_state */
 
 #endif				/* _H_JFS_FILSYS */
--- linux-4.4.0.orig/fs/jfs/jfs_imap.c
+++ linux-4.4.0/fs/jfs/jfs_imap.c
@@ -304,7 +304,7 @@
 int diRead(struct inode *ip)
 {
 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
-	int iagno, ino, extno, rc;
+	int iagno, ino, extno, rc, agno;
 	struct inode *ipimap;
 	struct dinode *dp;
 	struct iag *iagp;
@@ -353,8 +353,11 @@
 
 	/* get the ag for the iag */
 	agstart = le64_to_cpu(iagp->agstart);
+	agno = BLKTOAG(agstart, JFS_SBI(ip->i_sb));
 
 	release_metapage(mp);
+	if (agno >= MAXAG || agno < 0)
+		return -EIO;
 
 	rel_inode = (ino & (INOSPERPAGE - 1));
 	pageno = blkno >> sbi->l2nbperpage;
@@ -2197,6 +2200,9 @@
 	/* get the ag and iag numbers for this iag.
 	 */
 	agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
+	if (agno >= MAXAG || agno < 0)
+		return -EIO;
+
 	iagno = le32_to_cpu(iagp->iagnum);
 
 	/* check if this is the last free extent within the
--- linux-4.4.0.orig/fs/jfs/jfs_mount.c
+++ linux-4.4.0/fs/jfs/jfs_mount.c
@@ -49,6 +49,7 @@
 
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
+#include <linux/log2.h>
 
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
@@ -92,14 +93,14 @@
 	 * (initialize mount inode from the superblock)
 	 */
 	if ((rc = chkSuper(sb))) {
-		goto errout20;
+		goto out;
 	}
 
 	ipaimap = diReadSpecial(sb, AGGREGATE_I, 0);
 	if (ipaimap == NULL) {
 		jfs_err("jfs_mount: Failed to read AGGREGATE_I");
 		rc = -EIO;
-		goto errout20;
+		goto out;
 	}
 	sbi->ipaimap = ipaimap;
 
@@ -110,7 +111,7 @@
 	 */
 	if ((rc = diMount(ipaimap))) {
 		jfs_err("jfs_mount: diMount(ipaimap) failed w/rc = %d", rc);
-		goto errout21;
+		goto err_ipaimap;
 	}
 
 	/*
@@ -119,7 +120,7 @@
 	ipbmap = diReadSpecial(sb, BMAP_I, 0);
 	if (ipbmap == NULL) {
 		rc = -EIO;
-		goto errout22;
+		goto err_umount_ipaimap;
 	}
 
 	jfs_info("jfs_mount: ipbmap:0x%p", ipbmap);
@@ -131,7 +132,7 @@
 	 */
 	if ((rc = dbMount(ipbmap))) {
 		jfs_err("jfs_mount: dbMount failed w/rc = %d", rc);
-		goto errout22;
+		goto err_ipbmap;
 	}
 
 	/*
@@ -150,7 +151,7 @@
 		if (!ipaimap2) {
 			jfs_err("jfs_mount: Failed to read AGGREGATE_I");
 			rc = -EIO;
-			goto errout35;
+			goto err_umount_ipbmap;
 		}
 		sbi->ipaimap2 = ipaimap2;
 
@@ -162,7 +163,7 @@
 		if ((rc = diMount(ipaimap2))) {
 			jfs_err("jfs_mount: diMount(ipaimap2) failed, rc = %d",
 				rc);
-			goto errout35;
+			goto err_ipaimap2;
 		}
 	} else
 		/* Secondary aggregate inode table is not valid */
@@ -179,51 +180,44 @@
 		jfs_err("jfs_mount: Failed to read FILESYSTEM_I");
 		/* open fileset secondary inode allocation map */
 		rc = -EIO;
-		goto errout40;
+		goto err_umount_ipaimap2;
 	}
 	jfs_info("jfs_mount: ipimap:0x%p", ipimap);
 
-	/* map further access of per fileset inodes by the fileset inode */
-	sbi->ipimap = ipimap;
-
 	/* initialize fileset inode allocation map */
 	if ((rc = diMount(ipimap))) {
 		jfs_err("jfs_mount: diMount failed w/rc = %d", rc);
-		goto errout41;
+		goto err_ipimap;
 	}
 
-	goto out;
+	/* map further access of per fileset inodes by the fileset inode */
+	sbi->ipimap = ipimap;
+
+	return rc;
 
 	/*
 	 *	unwind on error
 	 */
-      errout41:		/* close fileset inode allocation map inode */
+err_ipimap:
+	/* close fileset inode allocation map inode */
 	diFreeSpecial(ipimap);
-
-      errout40:		/* fileset closed */
-
+err_umount_ipaimap2:
 	/* close secondary aggregate inode allocation map */
-	if (ipaimap2) {
+	if (ipaimap2)
 		diUnmount(ipaimap2, 1);
+err_ipaimap2:
+	/* close aggregate inodes */
+	if (ipaimap2)
 		diFreeSpecial(ipaimap2);
-	}
-
-      errout35:
-
-	/* close aggregate block allocation map */
+err_umount_ipbmap:	/* close aggregate block allocation map */
 	dbUnmount(ipbmap, 1);
+err_ipbmap:		/* close aggregate inodes */
 	diFreeSpecial(ipbmap);
-
-      errout22:		/* close aggregate inode allocation map */
-
+err_umount_ipaimap:	/* close aggregate inode allocation map */
 	diUnmount(ipaimap, 1);
-
-      errout21:		/* close aggregate inodes */
+err_ipaimap:		/* close aggregate inodes */
 	diFreeSpecial(ipaimap);
-      errout20:		/* aggregate closed */
-
-      out:
-
+out:
 	if (rc)
 		jfs_err("Mount JFS Failure: %d", rc);
 
@@ -378,6 +372,15 @@
 	sbi->bsize = bsize;
 	sbi->l2bsize = le16_to_cpu(j_sb->s_l2bsize);
 
+	/* check some fields for possible corruption */
+	if (sbi->l2bsize != ilog2((u32)bsize) ||
+	    j_sb->pad != 0 ||
+	    le32_to_cpu(j_sb->s_state) > FM_STATE_MAX) {
+		rc = -EINVAL;
+		jfs_err("jfs_mount: Mount Failure: superblock is corrupt!");
+		goto out;
+	}
+
 	/*
 	 * For now, ignore s_pbsize, l2bfactor.  All I/O going through buffer
 	 * cache.
--- linux-4.4.0.orig/fs/jfs/jfs_txnmgr.c
+++ linux-4.4.0/fs/jfs/jfs_txnmgr.c
@@ -1928,8 +1928,7 @@
 	 * header ?
 	 */
 	if (tlck->type & tlckTRUNCATE) {
-		/* This odd declaration suppresses a bogus gcc warning */
-		pxd_t pxd = pxd;	/* truncated extent of xad */
+		pxd_t pxd;	/* truncated extent of xad */
 		int twm;
 
 		/*
--- linux-4.4.0.orig/fs/jfs/namei.c
+++ linux-4.4.0/fs/jfs/namei.c
@@ -178,8 +178,7 @@
 		unlock_new_inode(ip);
 		iput(ip);
 	} else {
-		unlock_new_inode(ip);
-		d_instantiate(dentry, ip);
+		d_instantiate_new(dentry, ip);
 	}
 
       out2:
@@ -313,8 +312,7 @@
 		unlock_new_inode(ip);
 		iput(ip);
 	} else {
-		unlock_new_inode(ip);
-		d_instantiate(dentry, ip);
+		d_instantiate_new(dentry, ip);
 	}
 
       out2:
@@ -1058,8 +1056,7 @@
 		unlock_new_inode(ip);
 		iput(ip);
 	} else {
-		unlock_new_inode(ip);
-		d_instantiate(dentry, ip);
+		d_instantiate_new(dentry, ip);
 	}
 
       out2:
@@ -1443,8 +1440,7 @@
 		unlock_new_inode(ip);
 		iput(ip);
 	} else {
-		unlock_new_inode(ip);
-		d_instantiate(dentry, ip);
+		d_instantiate_new(dentry, ip);
 	}
 
       out1:
--- linux-4.4.0.orig/fs/jfs/super.c
+++ linux-4.4.0/fs/jfs/super.c
@@ -758,7 +758,7 @@
 				sb->s_blocksize - offset : toread;
 
 		tmp_bh.b_state = 0;
-		tmp_bh.b_size = 1 << inode->i_blkbits;
+		tmp_bh.b_size = i_blocksize(inode);
 		err = jfs_get_block(inode, blk, &tmp_bh, 0);
 		if (err)
 			return err;
@@ -798,7 +798,7 @@
 				sb->s_blocksize - offset : towrite;
 
 		tmp_bh.b_state = 0;
-		tmp_bh.b_size = 1 << inode->i_blkbits;
+		tmp_bh.b_size = i_blocksize(inode);
 		err = jfs_get_block(inode, blk, &tmp_bh, 1);
 		if (err)
 			goto out;
--- linux-4.4.0.orig/fs/jfs/xattr.c
+++ linux-4.4.0/fs/jfs/xattr.c
@@ -493,15 +493,17 @@
 	if (size > PSIZE) {
 		/*
 		 * To keep the rest of the code simple.  Allocate a
-		 * contiguous buffer to work with
+		 * contiguous buffer to work with. Make the buffer large
+		 * enough to make use of the whole extent.
 		 */
-		ea_buf->xattr = kmalloc(size, GFP_KERNEL);
+		ea_buf->max_size = (size + sb->s_blocksize - 1) &
+		    ~(sb->s_blocksize - 1);
+
+		ea_buf->xattr = kmalloc(ea_buf->max_size, GFP_KERNEL);
 		if (ea_buf->xattr == NULL)
 			return -ENOMEM;
 
 		ea_buf->flag = EA_MALLOC;
-		ea_buf->max_size = (size + sb->s_blocksize - 1) &
-		    ~(sb->s_blocksize - 1);
 
 		if (ea_size == 0)
 			return 0;
@@ -570,9 +572,11 @@
 
       size_check:
 	if (EALIST_SIZE(ea_buf->xattr) != ea_size) {
+		int size = min_t(int, EALIST_SIZE(ea_buf->xattr), ea_size);
+
 		printk(KERN_ERR "ea_get: invalid extended attribute\n");
 		print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1,
-				     ea_buf->xattr, ea_size, 1);
+				     ea_buf->xattr, size, 1);
 		ea_release(inode, ea_buf);
 		rc = -EIO;
 		goto clean_up;
--- linux-4.4.0.orig/fs/kernfs/dir.c
+++ linux-4.4.0/fs/kernfs/dir.c
@@ -44,28 +44,123 @@
 	return strlcpy(buf, kn->parent ? kn->name : "/", buflen);
 }
 
-static char * __must_check kernfs_path_locked(struct kernfs_node *kn, char *buf,
-					      size_t buflen)
+/* kernfs_node_depth - compute depth from @from to @to */
+static size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to)
 {
-	char *p = buf + buflen;
-	int len;
+	size_t depth = 0;
 
-	*--p = '\0';
+	while (to->parent && to != from) {
+		depth++;
+		to = to->parent;
+	}
+	return depth;
+}
 
-	do {
-		len = strlen(kn->name);
-		if (p - buf < len + 1) {
-			buf[0] = '\0';
-			p = NULL;
-			break;
-		}
-		p -= len;
-		memcpy(p, kn->name, len);
-		*--p = '/';
-		kn = kn->parent;
-	} while (kn && kn->parent);
+static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a,
+						  struct kernfs_node *b)
+{
+	size_t da, db;
+	struct kernfs_root *ra = kernfs_root(a), *rb = kernfs_root(b);
+
+	if (ra != rb)
+		return NULL;
+
+	da = kernfs_depth(ra->kn, a);
+	db = kernfs_depth(rb->kn, b);
+
+	while (da > db) {
+		a = a->parent;
+		da--;
+	}
+	while (db > da) {
+		b = b->parent;
+		db--;
+	}
+
+	/* worst case b and a will be the same at root */
+	while (b != a) {
+		b = b->parent;
+		a = a->parent;
+	}
+
+	return a;
+}
+
+/**
+ * kernfs_path_from_node_locked - find a pseudo-absolute path to @kn_to,
+ * where kn_from is treated as root of the path.
+ * @kn_from: kernfs node which should be treated as root for the path
+ * @kn_to: kernfs node to which path is needed
+ * @buf: buffer to copy the path into
+ * @buflen: size of @buf
+ *
+ * We need to handle couple of scenarios here:
+ * [1] when @kn_from is an ancestor of @kn_to at some level
+ * kn_from: /n1/n2/n3
+ * kn_to:   /n1/n2/n3/n4/n5
+ * result:  /n4/n5
+ *
+ * [2] when @kn_from is on a different hierarchy and we need to find common
+ * ancestor between @kn_from and @kn_to.
+ * kn_from: /n1/n2/n3/n4
+ * kn_to:   /n1/n2/n5
+ * result:  /../../n5
+ * OR
+ * kn_from: /n1/n2/n3/n4/n5   [depth=5]
+ * kn_to:   /n1/n2/n3         [depth=3]
+ * result:  /../..
+ *
+ * return value: length of the string.  If greater than buflen,
+ * then contents of buf are undefined.  On error, -1 is returned.
+ */
+static int
+kernfs_path_from_node_locked(struct kernfs_node *kn_to,
+			     struct kernfs_node *kn_from, char *buf,
+			     size_t buflen)
+{
+	struct kernfs_node *kn, *common;
+	const char parent_str[] = "/..";
+	size_t depth_from, depth_to, len = 0, nlen = 0;
+	char *p;
+	int i;
+
+	if (!kn_from)
+		kn_from = kernfs_root(kn_to)->kn;
+
+	if (kn_from == kn_to)
+		return strlcpy(buf, "/", buflen);
+
+	common = kernfs_common_ancestor(kn_from, kn_to);
+	if (WARN_ON(!common))
+		return -1;
+
+	depth_to = kernfs_depth(common, kn_to);
+	depth_from = kernfs_depth(common, kn_from);
+
+	if (buf)
+		buf[0] = '\0';
+
+	for (i = 0; i < depth_from; i++)
+		len += strlcpy(buf + len, parent_str,
+			       len < buflen ? buflen - len : 0);
 
-	return p;
+	/* Calculate how many bytes we need for the rest */
+	for (kn = kn_to; kn != common; kn = kn->parent)
+		nlen += strlen(kn->name) + 1;
+
+	if (len + nlen >= buflen)
+		return len + nlen;
+
+	p = buf + len + nlen;
+	*p = '\0';
+	for (kn = kn_to; kn != common; kn = kn->parent) {
+		nlen = strlen(kn->name);
+		p -= nlen;
+		memcpy(p, kn->name, nlen);
+		*(--p) = '/';
+	}
+
+	return len + nlen;
 }
 
 /**
@@ -115,6 +210,34 @@
 }
 
 /**
+ * kernfs_path_from_node - build path of node @to relative to @from.
+ * @from: parent kernfs_node relative to which we need to build the path
+ * @to: kernfs_node of interest
+ * @buf: buffer to copy @to's path into
+ * @buflen: size of @buf
+ *
+ * Builds @to's path relative to @from in @buf. @from and @to must
+ * be on the same kernfs-root. If @from is not parent of @to, then a relative
+ * path (which includes '..'s) as needed to reach from @from to @to is
+ * returned.
+ *
+ * If @buf isn't long enough, the return value will be greater than @buflen
+ * and @buf contents are undefined.
+ */
+int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
+			  char *buf, size_t buflen)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&kernfs_rename_lock, flags);
+	ret = kernfs_path_from_node_locked(to, from, buf, buflen);
+	spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(kernfs_path_from_node);
+
+/**
  * kernfs_path - build full path of a given node
  * @kn: kernfs_node of interest
  * @buf: buffer to copy @kn's name into
@@ -127,13 +250,12 @@
  */
 char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen)
 {
-	unsigned long flags;
-	char *p;
+	int ret;
 
-	spin_lock_irqsave(&kernfs_rename_lock, flags);
-	p = kernfs_path_locked(kn, buf, buflen);
-	spin_unlock_irqrestore(&kernfs_rename_lock, flags);
-	return p;
+	ret = kernfs_path_from_node(kn, NULL, buf, buflen);
+	if (ret < 0 || ret >= buflen)
+		return NULL;
+	return buf;
 }
 EXPORT_SYMBOL_GPL(kernfs_path);
 
@@ -164,17 +286,25 @@
 void pr_cont_kernfs_path(struct kernfs_node *kn)
 {
 	unsigned long flags;
-	char *p;
+	int sz;
 
 	spin_lock_irqsave(&kernfs_rename_lock, flags);
 
-	p = kernfs_path_locked(kn, kernfs_pr_cont_buf,
-			       sizeof(kernfs_pr_cont_buf));
-	if (p)
-		pr_cont("%s", p);
-	else
-		pr_cont("<name too long>");
+	sz = kernfs_path_from_node_locked(kn, NULL, kernfs_pr_cont_buf,
+					  sizeof(kernfs_pr_cont_buf));
+	if (sz < 0) {
+		pr_cont("(error)");
+		goto out;
+	}
+
+	if (sz >= sizeof(kernfs_pr_cont_buf)) {
+		pr_cont("(name too long)");
+		goto out;
+	}
+
+	pr_cont("%s", kernfs_pr_cont_buf);
 
+out:
 	spin_unlock_irqrestore(&kernfs_rename_lock, flags);
 }
 
--- linux-4.4.0.orig/fs/kernfs/file.c
+++ linux-4.4.0/fs/kernfs/file.c
@@ -272,7 +272,7 @@
 {
 	struct kernfs_open_file *of = kernfs_of(file);
 	const struct kernfs_ops *ops;
-	size_t len;
+	ssize_t len;
 	char *buf;
 
 	if (of->atomic_write_len) {
@@ -833,21 +833,35 @@
 	mutex_lock(&kernfs_mutex);
 
 	list_for_each_entry(info, &kernfs_root(kn)->supers, node) {
+		struct kernfs_node *parent;
 		struct inode *inode;
-		struct dentry *dentry;
 
+		/*
+		 * We want fsnotify_modify() on @kn but as the
+		 * modifications aren't originating from userland don't
+		 * have the matching @file available.  Look up the inodes
+		 * and generate the events manually.
+		 */
 		inode = ilookup(info->sb, kn->ino);
 		if (!inode)
 			continue;
 
-		dentry = d_find_any_alias(inode);
-		if (dentry) {
-			fsnotify_parent(NULL, dentry, FS_MODIFY);
-			fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE,
-				 NULL, 0);
-			dput(dentry);
+		parent = kernfs_get_parent(kn);
+		if (parent) {
+			struct inode *p_inode;
+
+			p_inode = ilookup(info->sb, parent->ino);
+			if (p_inode) {
+				fsnotify(p_inode, FS_MODIFY | FS_EVENT_ON_CHILD,
+					 inode, FSNOTIFY_EVENT_INODE, kn->name, 0);
+				iput(p_inode);
+			}
+
+			kernfs_put(parent);
 		}
 
+		fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE,
+			 kn->name, 0);
 		iput(inode);
 	}
 
--- linux-4.4.0.orig/fs/kernfs/inode.c
+++ linux-4.4.0/fs/kernfs/inode.c
@@ -119,7 +119,7 @@
 		return -EINVAL;
 
 	mutex_lock(&kernfs_mutex);
-	error = inode_change_ok(inode, iattr);
+	error = setattr_prepare(dentry, iattr);
 	if (error)
 		goto out;
 
--- linux-4.4.0.orig/fs/kernfs/mount.c
+++ linux-4.4.0/fs/kernfs/mount.c
@@ -14,6 +14,8 @@
 #include <linux/magic.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
+#include <linux/namei.h>
+#include <linux/seq_file.h>
 
 #include "kernfs-internal.h"
 
@@ -39,6 +41,19 @@
 	return 0;
 }
 
+static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
+{
+	struct kernfs_node *node = dentry->d_fsdata;
+	struct kernfs_root *root = kernfs_root(node);
+	struct kernfs_syscall_ops *scops = root->syscall_ops;
+
+	if (scops && scops->show_path)
+		return scops->show_path(sf, node, root);
+
+	seq_dentry(sf, dentry, " \t\n\\");
+	return 0;
+}
+
 const struct super_operations kernfs_sops = {
 	.statfs		= simple_statfs,
 	.drop_inode	= generic_delete_inode,
@@ -46,6 +61,7 @@
 
 	.remount_fs	= kernfs_sop_remount_fs,
 	.show_options	= kernfs_sop_show_options,
+	.show_path	= kernfs_sop_show_path,
 };
 
 /**
@@ -62,6 +78,74 @@
 	return NULL;
 }
 
+/*
+ * find the next ancestor in the path down to @child, where @parent was the
+ * ancestor whose descendant we want to find.
+ *
+ * Say the path is /a/b/c/d.  @child is d, @parent is NULL.  We return the root
+ * node.  If @parent is b, then we return the node for c.
+ * Passing in d as @parent is not ok.
+ */
+static struct kernfs_node *
+find_next_ancestor(struct kernfs_node *child, struct kernfs_node *parent)
+{
+	if (child == parent) {
+		pr_crit_once("BUG in find_next_ancestor: called with parent == child");
+		return NULL;
+	}
+
+	while (child->parent != parent) {
+		if (!child->parent)
+			return NULL;
+		child = child->parent;
+	}
+
+	return child;
+}
+
+/**
+ * kernfs_node_dentry - get a dentry for the given kernfs_node
+ * @kn: kernfs_node for which a dentry is needed
+ * @sb: the kernfs super_block
+ */
+struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+				  struct super_block *sb)
+{
+	struct dentry *dentry;
+	struct kernfs_node *knparent = NULL;
+
+	BUG_ON(sb->s_op != &kernfs_sops);
+
+	dentry = dget(sb->s_root);
+
+	/* Check if this is the root kernfs_node */
+	if (!kn->parent)
+		return dentry;
+
+	knparent = find_next_ancestor(kn, NULL);
+	if (WARN_ON(!knparent))
+		return ERR_PTR(-EINVAL);
+
+	do {
+		struct dentry *dtmp;
+		struct kernfs_node *kntmp;
+
+		if (kn == knparent)
+			return dentry;
+		kntmp = find_next_ancestor(kn, knparent);
+		if (WARN_ON(!kntmp))
+			return ERR_PTR(-EINVAL);
+		mutex_lock(&d_inode(dentry)->i_mutex);
+		dtmp = lookup_one_len(kntmp->name, dentry, strlen(kntmp->name));
+		mutex_unlock(&d_inode(dentry)->i_mutex);
+		dput(dentry);
+		if (IS_ERR(dtmp))
+			return dtmp;
+		knparent = kntmp;
+		dentry = dtmp;
+	} while (1);
+}
+
 static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
 {
 	struct kernfs_super_info *info = kernfs_info(sb);
@@ -69,6 +153,8 @@
 	struct dentry *root;
 
 	info->sb = sb;
+	/* Userspace would break if executables appear on sysfs */
+	sb->s_iflags |= SB_I_NOEXEC;
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->s_magic = magic;
@@ -158,7 +244,8 @@
 	info->root = root;
 	info->ns = ns;
 
-	sb = sget(fs_type, kernfs_test_super, kernfs_set_super, flags, info);
+	sb = sget_userns(fs_type, kernfs_test_super, kernfs_set_super, flags,
+			 &init_user_ns, info);
 	if (IS_ERR(sb) || sb->s_fs_info != info)
 		kfree(info);
 	if (IS_ERR(sb))
--- linux-4.4.0.orig/fs/kernfs/symlink.c
+++ linux-4.4.0/fs/kernfs/symlink.c
@@ -63,6 +63,9 @@
 		if (base == kn)
 			break;
 
+		if ((s - path) + 3 >= PATH_MAX)
+			return -ENAMETOOLONG;
+
 		strcpy(s, "../");
 		s += 3;
 		base = base->parent;
@@ -79,7 +82,7 @@
 	if (len < 2)
 		return -EINVAL;
 	len--;
-	if ((s - path) + len > PATH_MAX)
+	if ((s - path) + len >= PATH_MAX)
 		return -ENAMETOOLONG;
 
 	/* reverse fillup of target string from target to base */
@@ -88,7 +91,7 @@
 		int slen = strlen(kn->name);
 
 		len -= slen;
-		strncpy(s + len, kn->name, slen);
+		memcpy(s + len, kn->name, slen);
 		if (len)
 			s[--len] = '/';
 
--- linux-4.4.0.orig/fs/libfs.c
+++ linux-4.4.0/fs/libfs.c
@@ -366,7 +366,7 @@
 	struct inode *inode = d_inode(dentry);
 	int error;
 
-	error = inode_change_ok(inode, iattr);
+	error = setattr_prepare(dentry, iattr);
 	if (error)
 		return error;
 
@@ -761,7 +761,7 @@
 {
 	struct simple_attr *attr;
 
-	attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
 	if (!attr)
 		return -ENOMEM;
 
@@ -801,9 +801,11 @@
 	if (ret)
 		return ret;
 
-	if (*ppos) {		/* continued read */
+	if (*ppos && attr->get_buf[0]) {
+		/* continued read */
 		size = strlen(attr->get_buf);
-	} else {		/* first read */
+	} else {
+		/* first read */
 		u64 val;
 		ret = attr->get(attr->data, &val);
 		if (ret)
@@ -825,7 +827,7 @@
 			  size_t len, loff_t *ppos)
 {
 	struct simple_attr *attr;
-	u64 val;
+	unsigned long long val;
 	size_t size;
 	ssize_t ret;
 
@@ -843,7 +845,9 @@
 		goto out;
 
 	attr->set_buf[size] = '\0';
-	val = simple_strtoll(attr->set_buf, NULL, 0);
+	ret = kstrtoull(attr->set_buf, 0, &val);
+	if (ret)
+		goto out;
 	ret = attr->set(attr->data, val);
 	if (ret == 0)
 		ret = len; /* on success, claim we got the whole input */
--- linux-4.4.0.orig/fs/lockd/host.c
+++ linux-4.4.0/fs/lockd/host.c
@@ -340,7 +340,7 @@
 	};
 	struct lockd_net *ln = net_generic(net, lockd_net_id);
 
-	dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
+	dprintk("lockd: %s(host='%.*s', vers=%u, proto=%s)\n", __func__,
 			(int)hostname_len, hostname, rqstp->rq_vers,
 			(rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
 
@@ -430,12 +430,7 @@
 	 * RPC rebind is required
 	 */
 	if ((clnt = host->h_rpcclnt) != NULL) {
-		if (time_after_eq(jiffies, host->h_nextrebind)) {
-			rpc_force_rebind(clnt);
-			host->h_nextrebind = jiffies + NLM_HOST_REBIND;
-			dprintk("lockd: next rebind in %lu jiffies\n",
-					host->h_nextrebind - jiffies);
-		}
+		nlm_rebind_host(host);
 	} else {
 		unsigned long increment = nlmsvc_timeout;
 		struct rpc_timeout timeparms = {
@@ -483,13 +478,20 @@
 	return clnt;
 }
 
-/*
- * Force a portmap lookup of the remote lockd port
+/**
+ * nlm_rebind_host - If needed, force a portmap lookup of the peer's lockd port
+ * @host: NLM host handle for peer
+ *
+ * This is not needed when using a connection-oriented protocol, such as TCP.
+ * The existing autobind mechanism is sufficient to force a rebind when
+ * required, e.g. on connection state transitions.
  */
 void
 nlm_rebind_host(struct nlm_host *host)
 {
-	dprintk("lockd: rebind host %s\n", host->h_name);
+	if (host->h_proto != IPPROTO_UDP)
+		return;
+
 	if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
 		rpc_force_rebind(host->h_rpcclnt);
 		host->h_nextrebind = jiffies + NLM_HOST_REBIND;
--- linux-4.4.0.orig/fs/lockd/svc.c
+++ linux-4.4.0/fs/lockd/svc.c
@@ -129,6 +129,8 @@
 {
 	int		err = 0;
 	struct svc_rqst *rqstp = vrqstp;
+	struct net *net = &init_net;
+	struct lockd_net *ln = net_generic(net, lockd_net_id);
 
 	/* try_to_freeze() is called from svc_recv() */
 	set_freezable();
@@ -173,6 +175,8 @@
 	if (nlmsvc_ops)
 		nlmsvc_invalidate_all();
 	nlm_shutdown_hosts();
+	cancel_delayed_work_sync(&ln->grace_period_end);
+	locks_end_grace(&ln->lockd_manager);
 	return 0;
 }
 
--- linux-4.4.0.orig/fs/locks.c
+++ linux-4.4.0/fs/locks.c
@@ -1602,7 +1602,7 @@
 {
 	struct file_lock *fl, *my_fl = NULL, *lease;
 	struct dentry *dentry = filp->f_path.dentry;
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = file_inode(filp);
 	struct file_lock_context *ctx;
 	bool is_deleg = (*flp)->fl_flags & FL_DELEG;
 	int error;
@@ -2182,7 +2182,6 @@
 		goto out;
 	}
 
-again:
 	error = flock_to_posix_lock(filp, file_lock, &flock);
 	if (error)
 		goto out;
@@ -2221,22 +2220,26 @@
 	error = do_lock_file_wait(filp, cmd, file_lock);
 
 	/*
-	 * Attempt to detect a close/fcntl race and recover by
-	 * releasing the lock that was just acquired.
+	 * Detect close/fcntl races and recover by zapping all POSIX locks
+	 * associated with this file and our files_struct, just like on
+	 * filp_flush(). There is no need to do that when we're
+	 * unlocking though, or for OFD locks.
 	 */
-	/*
-	 * we need that spin_lock here - it prevents reordering between
-	 * update of i_flctx->flc_posix and check for it done in close().
-	 * rcu_read_lock() wouldn't do.
-	 */
-	spin_lock(&current->files->file_lock);
-	f = fcheck(fd);
-	spin_unlock(&current->files->file_lock);
-	if (!error && f != filp && flock.l_type != F_UNLCK) {
-		flock.l_type = F_UNLCK;
-		goto again;
+	if (!error && file_lock->fl_type != F_UNLCK &&
+	    !(file_lock->fl_flags & FL_OFDLCK)) {
+		/*
+		 * We need that spin_lock here - it prevents reordering between
+		 * update of i_flctx->flc_posix and check for it done in
+		 * close(). rcu_read_lock() wouldn't do.
+		 */
+		spin_lock(&current->files->file_lock);
+		f = fcheck(fd);
+		spin_unlock(&current->files->file_lock);
+		if (f != filp) {
+			locks_remove_posix(filp, current->files);
+			error = -EBADF;
+		}
 	}
-
 out:
 	locks_free_lock(file_lock);
 	return error;
@@ -2322,7 +2325,6 @@
 		goto out;
 	}
 
-again:
 	error = flock64_to_posix_lock(filp, file_lock, &flock);
 	if (error)
 		goto out;
@@ -2361,17 +2363,26 @@
 	error = do_lock_file_wait(filp, cmd, file_lock);
 
 	/*
-	 * Attempt to detect a close/fcntl race and recover by
-	 * releasing the lock that was just acquired.
+	 * Detect close/fcntl races and recover by zapping all POSIX locks
+	 * associated with this file and our files_struct, just like on
+	 * filp_flush(). There is no need to do that when we're
+	 * unlocking though, or for OFD locks.
 	 */
-	spin_lock(&current->files->file_lock);
-	f = fcheck(fd);
-	spin_unlock(&current->files->file_lock);
-	if (!error && f != filp && flock.l_type != F_UNLCK) {
-		flock.l_type = F_UNLCK;
-		goto again;
+	if (!error && file_lock->fl_type != F_UNLCK &&
+	    !(file_lock->fl_flags & FL_OFDLCK)) {
+		/*
+		 * We need that spin_lock here - it prevents reordering between
+		 * update of i_flctx->flc_posix and check for it done in
+		 * close(). rcu_read_lock() wouldn't do.
+		 */
+		spin_lock(&current->files->file_lock);
+		f = fcheck(fd);
+		spin_unlock(&current->files->file_lock);
+		if (f != filp) {
+			locks_remove_posix(filp, current->files);
+			error = -EBADF;
+		}
 	}
-
 out:
 	locks_free_lock(file_lock);
 	return error;
@@ -2586,7 +2597,7 @@
 	}
 	if (inode) {
 		/* userspace relies on this representation of dev_t */
-		seq_printf(f, "%d %02x:%02x:%ld ", fl_pid,
+		seq_printf(f, "%d %02x:%02x:%lu ", fl_pid,
 				MAJOR(inode->i_sb->s_dev),
 				MINOR(inode->i_sb->s_dev), inode->i_ino);
 	} else {
--- linux-4.4.0.orig/fs/logfs/file.c
+++ linux-4.4.0/fs/logfs/file.c
@@ -244,7 +244,7 @@
 	struct inode *inode = d_inode(dentry);
 	int err = 0;
 
-	err = inode_change_ok(inode, attr);
+	err = setattr_prepare(dentry, attr);
 	if (err)
 		return err;
 
--- linux-4.4.0.orig/fs/mbcache.c
+++ linux-4.4.0/fs/mbcache.c
@@ -1,858 +1,433 @@
-/*
- * linux/fs/mbcache.c
- * (C) 2001-2002 Andreas Gruenbacher, <a.gruenbacher@computer.org>
- */
-
-/*
- * Filesystem Meta Information Block Cache (mbcache)
- *
- * The mbcache caches blocks of block devices that need to be located
- * by their device/block number, as well as by other criteria (such
- * as the block's contents).
- *
- * There can only be one cache entry in a cache per device and block number.
- * Additional indexes need not be unique in this sense. The number of
- * additional indexes (=other criteria) can be hardwired at compile time
- * or specified at cache create time.
- *
- * Each cache entry is of fixed size. An entry may be `valid' or `invalid'
- * in the cache. A valid entry is in the main hash tables of the cache,
- * and may also be in the lru list. An invalid entry is not in any hashes
- * or lists.
- *
- * A valid cache entry is only in the lru list if no handles refer to it.
- * Invalid cache entries will be freed when the last handle to the cache
- * entry is released. Entries that cannot be freed immediately are put
- * back on the lru list.
- */
-
-/*
- * Lock descriptions and usage:
- *
- * Each hash chain of both the block and index hash tables now contains
- * a built-in lock used to serialize accesses to the hash chain.
- *
- * Accesses to global data structures mb_cache_list and mb_cache_lru_list
- * are serialized via the global spinlock mb_cache_spinlock.
- *
- * Each mb_cache_entry contains a spinlock, e_entry_lock, to serialize
- * accesses to its local data, such as e_used and e_queued.
- *
- * Lock ordering:
- *
- * Each block hash chain's lock has the highest lock order, followed by an
- * index hash chain's lock, mb_cache_bg_lock (used to implement mb_cache_entry's
- * lock), and mb_cach_spinlock, with the lowest order.  While holding
- * either a block or index hash chain lock, a thread can acquire an
- * mc_cache_bg_lock, which in turn can also acquire mb_cache_spinlock.
- *
- * Synchronization:
- *
- * Since both mb_cache_entry_get and mb_cache_entry_find scan the block and
- * index hash chian, it needs to lock the corresponding hash chain.  For each
- * mb_cache_entry within the chain, it needs to lock the mb_cache_entry to
- * prevent either any simultaneous release or free on the entry and also
- * to serialize accesses to either the e_used or e_queued member of the entry.
- *
- * To avoid having a dangling reference to an already freed
- * mb_cache_entry, an mb_cache_entry is only freed when it is not on a
- * block hash chain and also no longer being referenced, both e_used,
- * and e_queued are 0's.  When an mb_cache_entry is explicitly freed it is
- * first removed from a block hash chain.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <linux/hash.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
+#include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <linux/sched.h>
+#include <linux/list.h>
 #include <linux/list_bl.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
 #include <linux/mbcache.h>
-#include <linux/init.h>
-#include <linux/blockgroup_lock.h>
-#include <linux/log2.h>
-
-#ifdef MB_CACHE_DEBUG
-# define mb_debug(f...) do { \
-		printk(KERN_DEBUG f); \
-		printk("\n"); \
-	} while (0)
-#define mb_assert(c) do { if (!(c)) \
-		printk(KERN_ERR "assertion " #c " failed\n"); \
-	} while(0)
-#else
-# define mb_debug(f...) do { } while(0)
-# define mb_assert(c) do { } while(0)
-#endif
-#define mb_error(f...) do { \
-		printk(KERN_ERR f); \
-		printk("\n"); \
-	} while(0)
-
-#define MB_CACHE_WRITER ((unsigned short)~0U >> 1)
-
-#define MB_CACHE_ENTRY_LOCK_BITS	ilog2(NR_BG_LOCKS)
-#define	MB_CACHE_ENTRY_LOCK_INDEX(ce)			\
-	(hash_long((unsigned long)ce, MB_CACHE_ENTRY_LOCK_BITS))
-
-static DECLARE_WAIT_QUEUE_HEAD(mb_cache_queue);
-static struct blockgroup_lock *mb_cache_bg_lock;
-static struct kmem_cache *mb_cache_kmem_cache;
-
-MODULE_AUTHOR("Andreas Gruenbacher <a.gruenbacher@computer.org>");
-MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(mb_cache_create);
-EXPORT_SYMBOL(mb_cache_shrink);
-EXPORT_SYMBOL(mb_cache_destroy);
-EXPORT_SYMBOL(mb_cache_entry_alloc);
-EXPORT_SYMBOL(mb_cache_entry_insert);
-EXPORT_SYMBOL(mb_cache_entry_release);
-EXPORT_SYMBOL(mb_cache_entry_free);
-EXPORT_SYMBOL(mb_cache_entry_get);
-#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0)
-EXPORT_SYMBOL(mb_cache_entry_find_first);
-EXPORT_SYMBOL(mb_cache_entry_find_next);
-#endif
 
 /*
- * Global data: list of all mbcache's, lru list, and a spinlock for
- * accessing cache data structures on SMP machines. The lru list is
- * global across all mbcaches.
- */
-
-static LIST_HEAD(mb_cache_list);
-static LIST_HEAD(mb_cache_lru_list);
-static DEFINE_SPINLOCK(mb_cache_spinlock);
-
-static inline void
-__spin_lock_mb_cache_entry(struct mb_cache_entry *ce)
-{
-	spin_lock(bgl_lock_ptr(mb_cache_bg_lock,
-		MB_CACHE_ENTRY_LOCK_INDEX(ce)));
-}
-
-static inline void
-__spin_unlock_mb_cache_entry(struct mb_cache_entry *ce)
-{
-	spin_unlock(bgl_lock_ptr(mb_cache_bg_lock,
-		MB_CACHE_ENTRY_LOCK_INDEX(ce)));
-}
-
-static inline int
-__mb_cache_entry_is_block_hashed(struct mb_cache_entry *ce)
-{
-	return !hlist_bl_unhashed(&ce->e_block_list);
-}
+ * Mbcache is a simple key-value store. Keys need not be unique, however
+ * key-value pairs are expected to be unique (we use this fact in
+ * mb_cache_entry_delete_block()).
+ *
+ * Ext2 and ext4 use this cache for deduplication of extended attribute blocks.
+ * They use hash of a block contents as a key and block number as a value.
+ * That's why keys need not be unique (different xattr blocks may end up having
+ * the same hash). However block number always uniquely identifies a cache
+ * entry.
+ *
+ * We provide functions for creation and removal of entries, search by key,
+ * and a special "delete entry with given key-value pair" operation. Fixed
+ * size hash table is used for fast key lookups.
+ */
+
+struct mb_cache {
+	/* Hash table of entries */
+	struct hlist_bl_head	*c_hash;
+	/* log2 of hash table size */
+	int			c_bucket_bits;
+	/* Maximum entries in cache to avoid degrading hash too much */
+	int			c_max_entries;
+	/* Protects c_list, c_entry_count */
+	spinlock_t		c_list_lock;
+	struct list_head	c_list;
+	/* Number of entries in cache */
+	unsigned long		c_entry_count;
+	struct shrinker		c_shrink;
+	/* Work for shrinking when the cache has too many entries */
+	struct work_struct	c_shrink_work;
+};
 
+static struct kmem_cache *mb_entry_cache;
 
-static inline void
-__mb_cache_entry_unhash_block(struct mb_cache_entry *ce)
-{
-	if (__mb_cache_entry_is_block_hashed(ce))
-		hlist_bl_del_init(&ce->e_block_list);
-}
+static unsigned long mb_cache_shrink(struct mb_cache *cache,
+				     unsigned int nr_to_scan);
 
-static inline int
-__mb_cache_entry_is_index_hashed(struct mb_cache_entry *ce)
+static inline struct hlist_bl_head *mb_cache_entry_head(struct mb_cache *cache,
+							u32 key)
 {
-	return !hlist_bl_unhashed(&ce->e_index.o_list);
+	return &cache->c_hash[hash_32(key, cache->c_bucket_bits)];
 }
 
-static inline void
-__mb_cache_entry_unhash_index(struct mb_cache_entry *ce)
-{
-	if (__mb_cache_entry_is_index_hashed(ce))
-		hlist_bl_del_init(&ce->e_index.o_list);
-}
+/*
+ * Number of entries to reclaim synchronously when there are too many entries
+ * in cache
+ */
+#define SYNC_SHRINK_BATCH 64
 
 /*
- * __mb_cache_entry_unhash_unlock()
+ * mb_cache_entry_create - create entry in cache
+ * @cache - cache where the entry should be created
+ * @mask - gfp mask with which the entry should be allocated
+ * @key - key of the entry
+ * @block - block that contains data
+ * @reusable - is the block reusable by other inodes?
  *
- * This function is called to unhash both the block and index hash
- * chain.
- * It assumes both the block and index hash chain is locked upon entry.
- * It also unlock both hash chains both exit
+ * Creates entry in @cache with key @key and records that data is stored in
+ * block @block. The function returns -EBUSY if entry with the same key
+ * and for the same block already exists in cache. Otherwise 0 is returned.
  */
-static inline void
-__mb_cache_entry_unhash_unlock(struct mb_cache_entry *ce)
+int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
+			  sector_t block, bool reusable)
 {
-	__mb_cache_entry_unhash_index(ce);
-	hlist_bl_unlock(ce->e_index_hash_p);
-	__mb_cache_entry_unhash_block(ce);
-	hlist_bl_unlock(ce->e_block_hash_p);
-}
+	struct mb_cache_entry *entry, *dup;
+	struct hlist_bl_node *dup_node;
+	struct hlist_bl_head *head;
 
-static void
-__mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask)
-{
-	struct mb_cache *cache = ce->e_cache;
+	/* Schedule background reclaim if there are too many entries */
+	if (cache->c_entry_count >= cache->c_max_entries)
+		schedule_work(&cache->c_shrink_work);
+	/* Do some sync reclaim if background reclaim cannot keep up */
+	if (cache->c_entry_count >= 2*cache->c_max_entries)
+		mb_cache_shrink(cache, SYNC_SHRINK_BATCH);
 
-	mb_assert(!(ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt)));
-	kmem_cache_free(cache->c_entry_cache, ce);
-	atomic_dec(&cache->c_entry_count);
-}
+	entry = kmem_cache_alloc(mb_entry_cache, mask);
+	if (!entry)
+		return -ENOMEM;
 
-static void
-__mb_cache_entry_release(struct mb_cache_entry *ce)
-{
-	/* First lock the entry to serialize access to its local data. */
-	__spin_lock_mb_cache_entry(ce);
-	/* Wake up all processes queuing for this cache entry. */
-	if (ce->e_queued)
-		wake_up_all(&mb_cache_queue);
-	if (ce->e_used >= MB_CACHE_WRITER)
-		ce->e_used -= MB_CACHE_WRITER;
-	/*
-	 * Make sure that all cache entries on lru_list have
-	 * both e_used and e_qued of 0s.
-	 */
-	ce->e_used--;
-	if (!(ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt))) {
-		if (!__mb_cache_entry_is_block_hashed(ce)) {
-			__spin_unlock_mb_cache_entry(ce);
-			goto forget;
+	INIT_LIST_HEAD(&entry->e_list);
+	/* One ref for hash, one ref returned */
+	atomic_set(&entry->e_refcnt, 1);
+	entry->e_key = key;
+	entry->e_block = block;
+	entry->e_reusable = reusable;
+	head = mb_cache_entry_head(cache, key);
+	hlist_bl_lock(head);
+	hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
+		if (dup->e_key == key && dup->e_block == block) {
+			hlist_bl_unlock(head);
+			kmem_cache_free(mb_entry_cache, entry);
+			return -EBUSY;
 		}
-		/*
-		 * Need access to lru list, first drop entry lock,
-		 * then reacquire the lock in the proper order.
-		 */
-		spin_lock(&mb_cache_spinlock);
-		if (list_empty(&ce->e_lru_list))
-			list_add_tail(&ce->e_lru_list, &mb_cache_lru_list);
-		spin_unlock(&mb_cache_spinlock);
 	}
-	__spin_unlock_mb_cache_entry(ce);
-	return;
-forget:
-	mb_assert(list_empty(&ce->e_lru_list));
-	__mb_cache_entry_forget(ce, GFP_KERNEL);
-}
-
-/*
- * mb_cache_shrink_scan()  memory pressure callback
- *
- * This function is called by the kernel memory management when memory
- * gets low.
- *
- * @shrink: (ignored)
- * @sc: shrink_control passed from reclaim
- *
- * Returns the number of objects freed.
- */
-static unsigned long
-mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
-{
-	LIST_HEAD(free_list);
-	struct mb_cache_entry *entry, *tmp;
-	int nr_to_scan = sc->nr_to_scan;
-	gfp_t gfp_mask = sc->gfp_mask;
-	unsigned long freed = 0;
+	hlist_bl_add_head(&entry->e_hash_list, head);
+	hlist_bl_unlock(head);
 
-	mb_debug("trying to free %d entries", nr_to_scan);
-	spin_lock(&mb_cache_spinlock);
-	while ((nr_to_scan-- > 0) && !list_empty(&mb_cache_lru_list)) {
-		struct mb_cache_entry *ce =
-			list_entry(mb_cache_lru_list.next,
-				struct mb_cache_entry, e_lru_list);
-		list_del_init(&ce->e_lru_list);
-		if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt))
-			continue;
-		spin_unlock(&mb_cache_spinlock);
-		/* Prevent any find or get operation on the entry */
-		hlist_bl_lock(ce->e_block_hash_p);
-		hlist_bl_lock(ce->e_index_hash_p);
-		/* Ignore if it is touched by a find/get */
-		if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt) ||
-			!list_empty(&ce->e_lru_list)) {
-			hlist_bl_unlock(ce->e_index_hash_p);
-			hlist_bl_unlock(ce->e_block_hash_p);
-			spin_lock(&mb_cache_spinlock);
-			continue;
-		}
-		__mb_cache_entry_unhash_unlock(ce);
-		list_add_tail(&ce->e_lru_list, &free_list);
-		spin_lock(&mb_cache_spinlock);
-	}
-	spin_unlock(&mb_cache_spinlock);
+	spin_lock(&cache->c_list_lock);
+	list_add_tail(&entry->e_list, &cache->c_list);
+	/* Grab ref for LRU list */
+	atomic_inc(&entry->e_refcnt);
+	cache->c_entry_count++;
+	spin_unlock(&cache->c_list_lock);
 
-	list_for_each_entry_safe(entry, tmp, &free_list, e_lru_list) {
-		__mb_cache_entry_forget(entry, gfp_mask);
-		freed++;
-	}
-	return freed;
+	return 0;
 }
+EXPORT_SYMBOL(mb_cache_entry_create);
 
-static unsigned long
-mb_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+void __mb_cache_entry_free(struct mb_cache_entry *entry)
 {
-	struct mb_cache *cache;
-	unsigned long count = 0;
+	kmem_cache_free(mb_entry_cache, entry);
+}
+EXPORT_SYMBOL(__mb_cache_entry_free);
 
-	spin_lock(&mb_cache_spinlock);
-	list_for_each_entry(cache, &mb_cache_list, c_cache_list) {
-		mb_debug("cache %s (%d)", cache->c_name,
-			  atomic_read(&cache->c_entry_count));
-		count += atomic_read(&cache->c_entry_count);
+static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
+					   struct mb_cache_entry *entry,
+					   u32 key)
+{
+	struct mb_cache_entry *old_entry = entry;
+	struct hlist_bl_node *node;
+	struct hlist_bl_head *head;
+
+	head = mb_cache_entry_head(cache, key);
+	hlist_bl_lock(head);
+	if (entry && !hlist_bl_unhashed(&entry->e_hash_list))
+		node = entry->e_hash_list.next;
+	else
+		node = hlist_bl_first(head);
+	while (node) {
+		entry = hlist_bl_entry(node, struct mb_cache_entry,
+				       e_hash_list);
+		if (entry->e_key == key && entry->e_reusable) {
+			atomic_inc(&entry->e_refcnt);
+			goto out;
+		}
+		node = node->next;
 	}
-	spin_unlock(&mb_cache_spinlock);
+	entry = NULL;
+out:
+	hlist_bl_unlock(head);
+	if (old_entry)
+		mb_cache_entry_put(cache, old_entry);
 
-	return vfs_pressure_ratio(count);
+	return entry;
 }
 
-static struct shrinker mb_cache_shrinker = {
-	.count_objects = mb_cache_shrink_count,
-	.scan_objects = mb_cache_shrink_scan,
-	.seeks = DEFAULT_SEEKS,
-};
-
 /*
- * mb_cache_create()  create a new cache
+ * mb_cache_entry_find_first - find the first entry in cache with given key
+ * @cache: cache where we should search
+ * @key: key to look for
  *
- * All entries in one cache are equal size. Cache entries may be from
- * multiple devices. If this is the first mbcache created, registers
- * the cache with kernel memory management. Returns NULL if no more
- * memory was available.
- *
- * @name: name of the cache (informal)
- * @bucket_bits: log2(number of hash buckets)
+ * Search in @cache for entry with key @key. Grabs reference to the first
+ * entry found and returns the entry.
  */
-struct mb_cache *
-mb_cache_create(const char *name, int bucket_bits)
+struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache,
+						 u32 key)
 {
-	int n, bucket_count = 1 << bucket_bits;
-	struct mb_cache *cache = NULL;
-
-	if (!mb_cache_bg_lock) {
-		mb_cache_bg_lock = kmalloc(sizeof(struct blockgroup_lock),
-			GFP_KERNEL);
-		if (!mb_cache_bg_lock)
-			return NULL;
-		bgl_lock_init(mb_cache_bg_lock);
-	}
-
-	cache = kmalloc(sizeof(struct mb_cache), GFP_KERNEL);
-	if (!cache)
-		return NULL;
-	cache->c_name = name;
-	atomic_set(&cache->c_entry_count, 0);
-	cache->c_bucket_bits = bucket_bits;
-	cache->c_block_hash = kmalloc(bucket_count *
-		sizeof(struct hlist_bl_head), GFP_KERNEL);
-	if (!cache->c_block_hash)
-		goto fail;
-	for (n=0; n<bucket_count; n++)
-		INIT_HLIST_BL_HEAD(&cache->c_block_hash[n]);
-	cache->c_index_hash = kmalloc(bucket_count *
-		sizeof(struct hlist_bl_head), GFP_KERNEL);
-	if (!cache->c_index_hash)
-		goto fail;
-	for (n=0; n<bucket_count; n++)
-		INIT_HLIST_BL_HEAD(&cache->c_index_hash[n]);
-	if (!mb_cache_kmem_cache) {
-		mb_cache_kmem_cache = kmem_cache_create(name,
-			sizeof(struct mb_cache_entry), 0,
-			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
-		if (!mb_cache_kmem_cache)
-			goto fail2;
-	}
-	cache->c_entry_cache = mb_cache_kmem_cache;
-
-	/*
-	 * Set an upper limit on the number of cache entries so that the hash
-	 * chains won't grow too long.
-	 */
-	cache->c_max_entries = bucket_count << 4;
-
-	spin_lock(&mb_cache_spinlock);
-	list_add(&cache->c_cache_list, &mb_cache_list);
-	spin_unlock(&mb_cache_spinlock);
-	return cache;
-
-fail2:
-	kfree(cache->c_index_hash);
-
-fail:
-	kfree(cache->c_block_hash);
-	kfree(cache);
-	return NULL;
+	return __entry_find(cache, NULL, key);
 }
-
+EXPORT_SYMBOL(mb_cache_entry_find_first);
 
 /*
- * mb_cache_shrink()
- *
- * Removes all cache entries of a device from the cache. All cache entries
- * currently in use cannot be freed, and thus remain in the cache. All others
- * are freed.
- *
- * @bdev: which device's cache entries to shrink
+ * mb_cache_entry_find_next - find next entry in cache with the same
+ * @cache: cache where we should search
+ * @entry: entry to start search from
+ *
+ * Finds next entry in the hash chain which has the same key as @entry.
+ * If @entry is unhashed (which can happen when deletion of entry races
+ * with the search), finds the first entry in the hash chain. The function
+ * drops reference to @entry and returns with a reference to the found entry.
  */
-void
-mb_cache_shrink(struct block_device *bdev)
+struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache *cache,
+						struct mb_cache_entry *entry)
 {
-	LIST_HEAD(free_list);
-	struct list_head *l;
-	struct mb_cache_entry *ce, *tmp;
-
-	l = &mb_cache_lru_list;
-	spin_lock(&mb_cache_spinlock);
-	while (!list_is_last(l, &mb_cache_lru_list)) {
-		l = l->next;
-		ce = list_entry(l, struct mb_cache_entry, e_lru_list);
-		if (ce->e_bdev == bdev) {
-			list_del_init(&ce->e_lru_list);
-			if (ce->e_used || ce->e_queued ||
-				atomic_read(&ce->e_refcnt))
-				continue;
-			spin_unlock(&mb_cache_spinlock);
-			/*
-			 * Prevent any find or get operation on the entry.
-			 */
-			hlist_bl_lock(ce->e_block_hash_p);
-			hlist_bl_lock(ce->e_index_hash_p);
-			/* Ignore if it is touched by a find/get */
-			if (ce->e_used || ce->e_queued ||
-				atomic_read(&ce->e_refcnt) ||
-				!list_empty(&ce->e_lru_list)) {
-				hlist_bl_unlock(ce->e_index_hash_p);
-				hlist_bl_unlock(ce->e_block_hash_p);
-				l = &mb_cache_lru_list;
-				spin_lock(&mb_cache_spinlock);
-				continue;
-			}
-			__mb_cache_entry_unhash_unlock(ce);
-			mb_assert(!(ce->e_used || ce->e_queued ||
-				atomic_read(&ce->e_refcnt)));
-			list_add_tail(&ce->e_lru_list, &free_list);
-			l = &mb_cache_lru_list;
-			spin_lock(&mb_cache_spinlock);
+	return __entry_find(cache, entry, entry->e_key);
+}
+EXPORT_SYMBOL(mb_cache_entry_find_next);
+
+/*
+ * mb_cache_entry_get - get a cache entry by block number (and key)
+ * @cache - cache we work with
+ * @key - key of block number @block
+ * @block - block number
+ */
+struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key,
+					  sector_t block)
+{
+	struct hlist_bl_node *node;
+	struct hlist_bl_head *head;
+	struct mb_cache_entry *entry;
+
+	head = mb_cache_entry_head(cache, key);
+	hlist_bl_lock(head);
+	hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
+		if (entry->e_key == key && entry->e_block == block) {
+			atomic_inc(&entry->e_refcnt);
+			goto out;
 		}
 	}
-	spin_unlock(&mb_cache_spinlock);
+	entry = NULL;
+out:
+	hlist_bl_unlock(head);
+	return entry;
+}
+EXPORT_SYMBOL(mb_cache_entry_get);
 
-	list_for_each_entry_safe(ce, tmp, &free_list, e_lru_list) {
-		__mb_cache_entry_forget(ce, GFP_KERNEL);
+/* mb_cache_entry_delete_block - remove information about block from cache
+ * @cache - cache we work with
+ * @key - key of block @block
+ * @block - block number
+ *
+ * Remove entry from cache @cache with key @key with data stored in @block.
+ */
+void mb_cache_entry_delete_block(struct mb_cache *cache, u32 key,
+				 sector_t block)
+{
+	struct hlist_bl_node *node;
+	struct hlist_bl_head *head;
+	struct mb_cache_entry *entry;
+
+	head = mb_cache_entry_head(cache, key);
+	hlist_bl_lock(head);
+	hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
+		if (entry->e_key == key && entry->e_block == block) {
+			/* We keep hash list reference to keep entry alive */
+			hlist_bl_del_init(&entry->e_hash_list);
+			hlist_bl_unlock(head);
+			spin_lock(&cache->c_list_lock);
+			if (!list_empty(&entry->e_list)) {
+				list_del_init(&entry->e_list);
+				cache->c_entry_count--;
+				atomic_dec(&entry->e_refcnt);
+			}
+			spin_unlock(&cache->c_list_lock);
+			mb_cache_entry_put(cache, entry);
+			return;
+		}
 	}
+	hlist_bl_unlock(head);
 }
+EXPORT_SYMBOL(mb_cache_entry_delete_block);
 
-
-/*
- * mb_cache_destroy()
+/* mb_cache_entry_touch - cache entry got used
+ * @cache - cache the entry belongs to
+ * @entry - entry that got used
  *
- * Shrinks the cache to its minimum possible size (hopefully 0 entries),
- * and then destroys it. If this was the last mbcache, un-registers the
- * mbcache from kernel memory management.
+ * Marks entry as used to give hit higher chances of surviving in cache.
  */
-void
-mb_cache_destroy(struct mb_cache *cache)
+void mb_cache_entry_touch(struct mb_cache *cache,
+			  struct mb_cache_entry *entry)
 {
-	LIST_HEAD(free_list);
-	struct mb_cache_entry *ce, *tmp;
-
-	spin_lock(&mb_cache_spinlock);
-	list_for_each_entry_safe(ce, tmp, &mb_cache_lru_list, e_lru_list) {
-		if (ce->e_cache == cache)
-			list_move_tail(&ce->e_lru_list, &free_list);
-	}
-	list_del(&cache->c_cache_list);
-	spin_unlock(&mb_cache_spinlock);
-
-	list_for_each_entry_safe(ce, tmp, &free_list, e_lru_list) {
-		list_del_init(&ce->e_lru_list);
-		/*
-		 * Prevent any find or get operation on the entry.
-		 */
-		hlist_bl_lock(ce->e_block_hash_p);
-		hlist_bl_lock(ce->e_index_hash_p);
-		mb_assert(!(ce->e_used || ce->e_queued ||
-			atomic_read(&ce->e_refcnt)));
-		__mb_cache_entry_unhash_unlock(ce);
-		__mb_cache_entry_forget(ce, GFP_KERNEL);
-	}
+	entry->e_referenced = 1;
+}
+EXPORT_SYMBOL(mb_cache_entry_touch);
 
-	if (atomic_read(&cache->c_entry_count) > 0) {
-		mb_error("cache %s: %d orphaned entries",
-			  cache->c_name,
-			  atomic_read(&cache->c_entry_count));
-	}
+static unsigned long mb_cache_count(struct shrinker *shrink,
+				    struct shrink_control *sc)
+{
+	struct mb_cache *cache = container_of(shrink, struct mb_cache,
+					      c_shrink);
 
-	if (list_empty(&mb_cache_list)) {
-		kmem_cache_destroy(mb_cache_kmem_cache);
-		mb_cache_kmem_cache = NULL;
-	}
-	kfree(cache->c_index_hash);
-	kfree(cache->c_block_hash);
-	kfree(cache);
+	return cache->c_entry_count;
 }
 
-/*
- * mb_cache_entry_alloc()
- *
- * Allocates a new cache entry. The new entry will not be valid initially,
- * and thus cannot be looked up yet. It should be filled with data, and
- * then inserted into the cache using mb_cache_entry_insert(). Returns NULL
- * if no more memory was available.
- */
-struct mb_cache_entry *
-mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags)
+/* Shrink number of entries in cache */
+static unsigned long mb_cache_shrink(struct mb_cache *cache,
+				     unsigned int nr_to_scan)
 {
-	struct mb_cache_entry *ce;
+	struct mb_cache_entry *entry;
+	struct hlist_bl_head *head;
+	unsigned int shrunk = 0;
 
-	if (atomic_read(&cache->c_entry_count) >= cache->c_max_entries) {
-		struct list_head *l;
-
-		l = &mb_cache_lru_list;
-		spin_lock(&mb_cache_spinlock);
-		while (!list_is_last(l, &mb_cache_lru_list)) {
-			l = l->next;
-			ce = list_entry(l, struct mb_cache_entry, e_lru_list);
-			if (ce->e_cache == cache) {
-				list_del_init(&ce->e_lru_list);
-				if (ce->e_used || ce->e_queued ||
-					atomic_read(&ce->e_refcnt))
-					continue;
-				spin_unlock(&mb_cache_spinlock);
-				/*
-				 * Prevent any find or get operation on the
-				 * entry.
-				 */
-				hlist_bl_lock(ce->e_block_hash_p);
-				hlist_bl_lock(ce->e_index_hash_p);
-				/* Ignore if it is touched by a find/get */
-				if (ce->e_used || ce->e_queued ||
-					atomic_read(&ce->e_refcnt) ||
-					!list_empty(&ce->e_lru_list)) {
-					hlist_bl_unlock(ce->e_index_hash_p);
-					hlist_bl_unlock(ce->e_block_hash_p);
-					l = &mb_cache_lru_list;
-					spin_lock(&mb_cache_spinlock);
-					continue;
-				}
-				mb_assert(list_empty(&ce->e_lru_list));
-				mb_assert(!(ce->e_used || ce->e_queued ||
-					atomic_read(&ce->e_refcnt)));
-				__mb_cache_entry_unhash_unlock(ce);
-				goto found;
-			}
+	spin_lock(&cache->c_list_lock);
+	while (nr_to_scan-- && !list_empty(&cache->c_list)) {
+		entry = list_first_entry(&cache->c_list,
+					 struct mb_cache_entry, e_list);
+		if (entry->e_referenced) {
+			entry->e_referenced = 0;
+			list_move_tail(&cache->c_list, &entry->e_list);
+			continue;
 		}
-		spin_unlock(&mb_cache_spinlock);
+		list_del_init(&entry->e_list);
+		cache->c_entry_count--;
+		/*
+		 * We keep LRU list reference so that entry doesn't go away
+		 * from under us.
+		 */
+		spin_unlock(&cache->c_list_lock);
+		head = mb_cache_entry_head(cache, entry->e_key);
+		hlist_bl_lock(head);
+		if (!hlist_bl_unhashed(&entry->e_hash_list)) {
+			hlist_bl_del_init(&entry->e_hash_list);
+			atomic_dec(&entry->e_refcnt);
+		}
+		hlist_bl_unlock(head);
+		if (mb_cache_entry_put(cache, entry))
+			shrunk++;
+		cond_resched();
+		spin_lock(&cache->c_list_lock);
 	}
+	spin_unlock(&cache->c_list_lock);
 
-	ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags);
-	if (!ce)
-		return NULL;
-	atomic_inc(&cache->c_entry_count);
-	INIT_LIST_HEAD(&ce->e_lru_list);
-	INIT_HLIST_BL_NODE(&ce->e_block_list);
-	INIT_HLIST_BL_NODE(&ce->e_index.o_list);
-	ce->e_cache = cache;
-	ce->e_queued = 0;
-	atomic_set(&ce->e_refcnt, 0);
-found:
-	ce->e_block_hash_p = &cache->c_block_hash[0];
-	ce->e_index_hash_p = &cache->c_index_hash[0];
-	ce->e_used = 1 + MB_CACHE_WRITER;
-	return ce;
+	return shrunk;
 }
 
-
-/*
- * mb_cache_entry_insert()
- *
- * Inserts an entry that was allocated using mb_cache_entry_alloc() into
- * the cache. After this, the cache entry can be looked up, but is not yet
- * in the lru list as the caller still holds a handle to it. Returns 0 on
- * success, or -EBUSY if a cache entry for that device + inode exists
- * already (this may happen after a failed lookup, but when another process
- * has inserted the same cache entry in the meantime).
- *
- * @bdev: device the cache entry belongs to
- * @block: block number
- * @key: lookup key
- */
-int
-mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev,
-		      sector_t block, unsigned int key)
-{
-	struct mb_cache *cache = ce->e_cache;
-	unsigned int bucket;
-	struct hlist_bl_node *l;
-	struct hlist_bl_head *block_hash_p;
-	struct hlist_bl_head *index_hash_p;
-	struct mb_cache_entry *lce;
-
-	mb_assert(ce);
-	bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), 
-			   cache->c_bucket_bits);
-	block_hash_p = &cache->c_block_hash[bucket];
-	hlist_bl_lock(block_hash_p);
-	hlist_bl_for_each_entry(lce, l, block_hash_p, e_block_list) {
-		if (lce->e_bdev == bdev && lce->e_block == block) {
-			hlist_bl_unlock(block_hash_p);
-			return -EBUSY;
-		}
-	}
-	mb_assert(!__mb_cache_entry_is_block_hashed(ce));
-	__mb_cache_entry_unhash_block(ce);
-	__mb_cache_entry_unhash_index(ce);
-	ce->e_bdev = bdev;
-	ce->e_block = block;
-	ce->e_block_hash_p = block_hash_p;
-	ce->e_index.o_key = key;
-	hlist_bl_add_head(&ce->e_block_list, block_hash_p);
-	hlist_bl_unlock(block_hash_p);
-	bucket = hash_long(key, cache->c_bucket_bits);
-	index_hash_p = &cache->c_index_hash[bucket];
-	hlist_bl_lock(index_hash_p);
-	ce->e_index_hash_p = index_hash_p;
-	hlist_bl_add_head(&ce->e_index.o_list, index_hash_p);
-	hlist_bl_unlock(index_hash_p);
-	return 0;
+static unsigned long mb_cache_scan(struct shrinker *shrink,
+				   struct shrink_control *sc)
+{
+	int nr_to_scan = sc->nr_to_scan;
+	struct mb_cache *cache = container_of(shrink, struct mb_cache,
+					      c_shrink);
+	return mb_cache_shrink(cache, nr_to_scan);
 }
 
+/* We shrink 1/X of the cache when we have too many entries in it */
+#define SHRINK_DIVISOR 16
 
-/*
- * mb_cache_entry_release()
- *
- * Release a handle to a cache entry. When the last handle to a cache entry
- * is released it is either freed (if it is invalid) or otherwise inserted
- * in to the lru list.
- */
-void
-mb_cache_entry_release(struct mb_cache_entry *ce)
+static void mb_cache_shrink_worker(struct work_struct *work)
 {
-	__mb_cache_entry_release(ce);
+	struct mb_cache *cache = container_of(work, struct mb_cache,
+					      c_shrink_work);
+	mb_cache_shrink(cache, cache->c_max_entries / SHRINK_DIVISOR);
 }
 
-
 /*
- * mb_cache_entry_free()
+ * mb_cache_create - create cache
+ * @bucket_bits: log2 of the hash table size
  *
+ * Create cache for keys with 2^bucket_bits hash entries.
  */
-void
-mb_cache_entry_free(struct mb_cache_entry *ce)
+struct mb_cache *mb_cache_create(int bucket_bits)
 {
-	mb_assert(ce);
-	mb_assert(list_empty(&ce->e_lru_list));
-	hlist_bl_lock(ce->e_index_hash_p);
-	__mb_cache_entry_unhash_index(ce);
-	hlist_bl_unlock(ce->e_index_hash_p);
-	hlist_bl_lock(ce->e_block_hash_p);
-	__mb_cache_entry_unhash_block(ce);
-	hlist_bl_unlock(ce->e_block_hash_p);
-	__mb_cache_entry_release(ce);
-}
+	struct mb_cache *cache;
+	int bucket_count = 1 << bucket_bits;
+	int i;
 
+	if (!try_module_get(THIS_MODULE))
+		return NULL;
 
-/*
- * mb_cache_entry_get()
- *
- * Get a cache entry  by device / block number. (There can only be one entry
- * in the cache per device and block.) Returns NULL if no such cache entry
- * exists. The returned cache entry is locked for exclusive access ("single
- * writer").
- */
-struct mb_cache_entry *
-mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev,
-		   sector_t block)
-{
-	unsigned int bucket;
-	struct hlist_bl_node *l;
-	struct mb_cache_entry *ce;
-	struct hlist_bl_head *block_hash_p;
-
-	bucket = hash_long((unsigned long)bdev + (block & 0xffffffff),
-			   cache->c_bucket_bits);
-	block_hash_p = &cache->c_block_hash[bucket];
-	/* First serialize access to the block corresponding hash chain. */
-	hlist_bl_lock(block_hash_p);
-	hlist_bl_for_each_entry(ce, l, block_hash_p, e_block_list) {
-		mb_assert(ce->e_block_hash_p == block_hash_p);
-		if (ce->e_bdev == bdev && ce->e_block == block) {
-			/*
-			 * Prevent a free from removing the entry.
-			 */
-			atomic_inc(&ce->e_refcnt);
-			hlist_bl_unlock(block_hash_p);
-			__spin_lock_mb_cache_entry(ce);
-			atomic_dec(&ce->e_refcnt);
-			if (ce->e_used > 0) {
-				DEFINE_WAIT(wait);
-				while (ce->e_used > 0) {
-					ce->e_queued++;
-					prepare_to_wait(&mb_cache_queue, &wait,
-							TASK_UNINTERRUPTIBLE);
-					__spin_unlock_mb_cache_entry(ce);
-					schedule();
-					__spin_lock_mb_cache_entry(ce);
-					ce->e_queued--;
-				}
-				finish_wait(&mb_cache_queue, &wait);
-			}
-			ce->e_used += 1 + MB_CACHE_WRITER;
-			__spin_unlock_mb_cache_entry(ce);
+	cache = kzalloc(sizeof(struct mb_cache), GFP_KERNEL);
+	if (!cache)
+		goto err_out;
+	cache->c_bucket_bits = bucket_bits;
+	cache->c_max_entries = bucket_count << 4;
+	INIT_LIST_HEAD(&cache->c_list);
+	spin_lock_init(&cache->c_list_lock);
+	cache->c_hash = kmalloc(bucket_count * sizeof(struct hlist_bl_head),
+				GFP_KERNEL);
+	if (!cache->c_hash) {
+		kfree(cache);
+		goto err_out;
+	}
+	for (i = 0; i < bucket_count; i++)
+		INIT_HLIST_BL_HEAD(&cache->c_hash[i]);
+
+	cache->c_shrink.count_objects = mb_cache_count;
+	cache->c_shrink.scan_objects = mb_cache_scan;
+	cache->c_shrink.seeks = DEFAULT_SEEKS;
+	register_shrinker(&cache->c_shrink);
 
-			if (!list_empty(&ce->e_lru_list)) {
-				spin_lock(&mb_cache_spinlock);
-				list_del_init(&ce->e_lru_list);
-				spin_unlock(&mb_cache_spinlock);
-			}
-			if (!__mb_cache_entry_is_block_hashed(ce)) {
-				__mb_cache_entry_release(ce);
-				return NULL;
-			}
-			return ce;
-		}
-	}
-	hlist_bl_unlock(block_hash_p);
-	return NULL;
-}
+	INIT_WORK(&cache->c_shrink_work, mb_cache_shrink_worker);
 
-#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0)
+	return cache;
 
-static struct mb_cache_entry *
-__mb_cache_entry_find(struct hlist_bl_node *l, struct hlist_bl_head *head,
-		      struct block_device *bdev, unsigned int key)
-{
-
-	/* The index hash chain is alredy acquire by caller. */
-	while (l != NULL) {
-		struct mb_cache_entry *ce =
-			hlist_bl_entry(l, struct mb_cache_entry,
-				e_index.o_list);
-		mb_assert(ce->e_index_hash_p == head);
-		if (ce->e_bdev == bdev && ce->e_index.o_key == key) {
-			/*
-			 * Prevent a free from removing the entry.
-			 */
-			atomic_inc(&ce->e_refcnt);
-			hlist_bl_unlock(head);
-			__spin_lock_mb_cache_entry(ce);
-			atomic_dec(&ce->e_refcnt);
-			ce->e_used++;
-			/* Incrementing before holding the lock gives readers
-			   priority over writers. */
-			if (ce->e_used >= MB_CACHE_WRITER) {
-				DEFINE_WAIT(wait);
-
-				while (ce->e_used >= MB_CACHE_WRITER) {
-					ce->e_queued++;
-					prepare_to_wait(&mb_cache_queue, &wait,
-							TASK_UNINTERRUPTIBLE);
-					__spin_unlock_mb_cache_entry(ce);
-					schedule();
-					__spin_lock_mb_cache_entry(ce);
-					ce->e_queued--;
-				}
-				finish_wait(&mb_cache_queue, &wait);
-			}
-			__spin_unlock_mb_cache_entry(ce);
-			if (!list_empty(&ce->e_lru_list)) {
-				spin_lock(&mb_cache_spinlock);
-				list_del_init(&ce->e_lru_list);
-				spin_unlock(&mb_cache_spinlock);
-			}
-			if (!__mb_cache_entry_is_block_hashed(ce)) {
-				__mb_cache_entry_release(ce);
-				return ERR_PTR(-EAGAIN);
-			}
-			return ce;
-		}
-		l = l->next;
-	}
-	hlist_bl_unlock(head);
+err_out:
+	module_put(THIS_MODULE);
 	return NULL;
 }
-
+EXPORT_SYMBOL(mb_cache_create);
 
 /*
- * mb_cache_entry_find_first()
- *
- * Find the first cache entry on a given device with a certain key in
- * an additional index. Additional matches can be found with
- * mb_cache_entry_find_next(). Returns NULL if no match was found. The
- * returned cache entry is locked for shared access ("multiple readers").
+ * mb_cache_destroy - destroy cache
+ * @cache: the cache to destroy
  *
- * @cache: the cache to search
- * @bdev: the device the cache entry should belong to
- * @key: the key in the index
+ * Free all entries in cache and cache itself. Caller must make sure nobody
+ * (except shrinker) can reach @cache when calling this.
  */
-struct mb_cache_entry *
-mb_cache_entry_find_first(struct mb_cache *cache, struct block_device *bdev,
-			  unsigned int key)
-{
-	unsigned int bucket = hash_long(key, cache->c_bucket_bits);
-	struct hlist_bl_node *l;
-	struct mb_cache_entry *ce = NULL;
-	struct hlist_bl_head *index_hash_p;
-
-	index_hash_p = &cache->c_index_hash[bucket];
-	hlist_bl_lock(index_hash_p);
-	if (!hlist_bl_empty(index_hash_p)) {
-		l = hlist_bl_first(index_hash_p);
-		ce = __mb_cache_entry_find(l, index_hash_p, bdev, key);
-	} else
-		hlist_bl_unlock(index_hash_p);
-	return ce;
-}
+void mb_cache_destroy(struct mb_cache *cache)
+{
+	struct mb_cache_entry *entry, *next;
 
+	unregister_shrinker(&cache->c_shrink);
 
-/*
- * mb_cache_entry_find_next()
- *
- * Find the next cache entry on a given device with a certain key in an
- * additional index. Returns NULL if no match could be found. The previous
- * entry is atomatically released, so that mb_cache_entry_find_next() can
- * be called like this:
- *
- * entry = mb_cache_entry_find_first();
- * while (entry) {
- * 	...
- *	entry = mb_cache_entry_find_next(entry, ...);
- * }
- *
- * @prev: The previous match
- * @bdev: the device the cache entry should belong to
- * @key: the key in the index
- */
-struct mb_cache_entry *
-mb_cache_entry_find_next(struct mb_cache_entry *prev,
-			 struct block_device *bdev, unsigned int key)
-{
-	struct mb_cache *cache = prev->e_cache;
-	unsigned int bucket = hash_long(key, cache->c_bucket_bits);
-	struct hlist_bl_node *l;
-	struct mb_cache_entry *ce;
-	struct hlist_bl_head *index_hash_p;
-
-	index_hash_p = &cache->c_index_hash[bucket];
-	mb_assert(prev->e_index_hash_p == index_hash_p);
-	hlist_bl_lock(index_hash_p);
-	mb_assert(!hlist_bl_empty(index_hash_p));
-	l = prev->e_index.o_list.next;
-	ce = __mb_cache_entry_find(l, index_hash_p, bdev, key);
-	__mb_cache_entry_release(prev);
-	return ce;
+	/*
+	 * We don't bother with any locking. Cache must not be used at this
+	 * point.
+	 */
+	list_for_each_entry_safe(entry, next, &cache->c_list, e_list) {
+		if (!hlist_bl_unhashed(&entry->e_hash_list)) {
+			hlist_bl_del_init(&entry->e_hash_list);
+			atomic_dec(&entry->e_refcnt);
+		} else
+			WARN_ON(1);
+		list_del(&entry->e_list);
+		WARN_ON(atomic_read(&entry->e_refcnt) != 1);
+		mb_cache_entry_put(cache, entry);
+	}
+	kfree(cache->c_hash);
+	kfree(cache);
+	module_put(THIS_MODULE);
 }
+EXPORT_SYMBOL(mb_cache_destroy);
 
-#endif  /* !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) */
-
-static int __init init_mbcache(void)
+static int __init mbcache_init(void)
 {
-	register_shrinker(&mb_cache_shrinker);
+	mb_entry_cache = kmem_cache_create("mbcache",
+				sizeof(struct mb_cache_entry), 0,
+				SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
+	BUG_ON(!mb_entry_cache);
 	return 0;
 }
 
-static void __exit exit_mbcache(void)
+static void __exit mbcache_exit(void)
 {
-	unregister_shrinker(&mb_cache_shrinker);
+	kmem_cache_destroy(mb_entry_cache);
 }
 
-module_init(init_mbcache)
-module_exit(exit_mbcache)
+module_init(mbcache_init)
+module_exit(mbcache_exit)
 
+MODULE_AUTHOR("Jan Kara <jack@suse.cz>");
+MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
+MODULE_LICENSE("GPL");
--- linux-4.4.0.orig/fs/minix/file.c
+++ linux-4.4.0/fs/minix/file.c
@@ -26,7 +26,7 @@
 	struct inode *inode = d_inode(dentry);
 	int error;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/minix/inode.c
+++ linux-4.4.0/fs/minix/inode.c
@@ -155,6 +155,23 @@
 	return 0;
 }
 
+static bool minix_check_superblock(struct minix_sb_info *sbi)
+{
+	if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0)
+		return false;
+
+	/*
+	 * s_max_size must not exceed the block mapping limitation.  This check
+	 * is only needed for V1 filesystems, since V2/V3 support an extra level
+	 * of indirect blocks which places the limit well above U32_MAX.
+	 */
+	if (sbi->s_version == MINIX_V1 &&
+	    sbi->s_max_size > (7 + 512 + 512*512) * BLOCK_SIZE)
+		return false;
+
+	return true;
+}
+
 static int minix_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct buffer_head *bh;
@@ -233,11 +250,12 @@
 	} else
 		goto out_no_fs;
 
+	if (!minix_check_superblock(sbi))
+		goto out_illegal_sb;
+
 	/*
 	 * Allocate the buffer map to keep the superblock small.
 	 */
-	if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0)
-		goto out_illegal_sb;
 	i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh);
 	map = kzalloc(i, GFP_KERNEL);
 	if (!map)
@@ -472,6 +490,13 @@
 		iget_failed(inode);
 		return ERR_PTR(-EIO);
 	}
+	if (raw_inode->i_nlinks == 0) {
+		printk("MINIX-fs: deleted inode referenced: %lu\n",
+		       inode->i_ino);
+		brelse(bh);
+		iget_failed(inode);
+		return ERR_PTR(-ESTALE);
+	}
 	inode->i_mode = raw_inode->i_mode;
 	i_uid_write(inode, raw_inode->i_uid);
 	i_gid_write(inode, raw_inode->i_gid);
@@ -505,6 +530,13 @@
 		iget_failed(inode);
 		return ERR_PTR(-EIO);
 	}
+	if (raw_inode->i_nlinks == 0) {
+		printk("MINIX-fs: deleted inode referenced: %lu\n",
+		       inode->i_ino);
+		brelse(bh);
+		iget_failed(inode);
+		return ERR_PTR(-ESTALE);
+	}
 	inode->i_mode = raw_inode->i_mode;
 	i_uid_write(inode, raw_inode->i_uid);
 	i_gid_write(inode, raw_inode->i_gid);
--- linux-4.4.0.orig/fs/minix/itree_common.c
+++ linux-4.4.0/fs/minix/itree_common.c
@@ -74,6 +74,7 @@
 	int n = 0;
 	int i;
 	int parent = minix_new_block(inode);
+	int err = -ENOSPC;
 
 	branch[0].key = cpu_to_block(parent);
 	if (parent) for (n = 1; n < num; n++) {
@@ -84,6 +85,11 @@
 			break;
 		branch[n].key = cpu_to_block(nr);
 		bh = sb_getblk(inode->i_sb, parent);
+		if (!bh) {
+			minix_free_block(inode, nr);
+			err = -ENOMEM;
+			break;
+		}
 		lock_buffer(bh);
 		memset(bh->b_data, 0, bh->b_size);
 		branch[n].bh = bh;
@@ -102,7 +108,7 @@
 		bforget(branch[i].bh);
 	for (i = 0; i < n; i++)
 		minix_free_block(inode, block_to_cpu(branch[i].key));
-	return -ENOSPC;
+	return err;
 }
 
 static inline int splice_branch(struct inode *inode,
--- linux-4.4.0.orig/fs/mount.h
+++ linux-4.4.0/fs/mount.h
@@ -13,6 +13,8 @@
 	u64			seq;	/* Sequence number to prevent loops */
 	wait_queue_head_t poll;
 	u64 event;
+	unsigned int		mounts; /* # of mounts in the namespace */
+	unsigned int		pending_mounts;
 };
 
 struct mnt_pcp {
@@ -55,6 +57,7 @@
 	struct mnt_namespace *mnt_ns;	/* containing namespace */
 	struct mountpoint *mnt_mp;	/* where is it mounted */
 	struct hlist_node mnt_mp_list;	/* list mounts with the same mountpoint */
+	struct list_head mnt_umounting; /* list entry for umount propagation */
 #ifdef CONFIG_FSNOTIFY
 	struct hlist_head mnt_fsnotify_marks;
 	__u32 mnt_fsnotify_mask;
@@ -86,7 +89,6 @@
 }
 
 extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *);
-extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
 
 extern int __legitimize_mnt(struct vfsmount *, unsigned);
 extern bool legitimize_mnt(struct vfsmount *, unsigned);
--- linux-4.4.0.orig/fs/mpage.c
+++ linux-4.4.0/fs/mpage.c
@@ -111,7 +111,7 @@
 			SetPageUptodate(page);    
 			return;
 		}
-		create_empty_buffers(page, 1 << inode->i_blkbits, 0);
+		create_empty_buffers(page, i_blocksize(inode), 0);
 	}
 	head = page_buffers(page);
 	page_bh = head;
--- linux-4.4.0.orig/fs/namei.c
+++ linux-4.4.0/fs/namei.c
@@ -35,6 +35,7 @@
 #include <linux/fs_struct.h>
 #include <linux/posix_acl.h>
 #include <linux/hash.h>
+#include <linux/init_task.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
@@ -219,9 +220,10 @@
 	if (len <= EMBEDDED_NAME_MAX) {
 		result->name = (char *)result->iname;
 	} else if (len <= PATH_MAX) {
+		const size_t size = offsetof(struct filename, iname[1]);
 		struct filename *tmp;
 
-		tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+		tmp = kmalloc(size, GFP_KERNEL);
 		if (unlikely(!tmp)) {
 			__putname(result);
 			return ERR_PTR(-ENOMEM);
@@ -409,6 +411,14 @@
 		 */
 		if (IS_IMMUTABLE(inode))
 			return -EACCES;
+
+		/*
+		 * Updating mtime will likely cause i_uid and i_gid to be
+		 * written back improperly if their true value is unknown
+		 * to the vfs.
+		 */
+		if (HAS_UNMAPPED_ID(inode))
+			return -EACCES;
 	}
 
 	retval = do_inode_permission(inode, mask);
@@ -570,9 +580,10 @@
 static bool path_connected(const struct path *path)
 {
 	struct vfsmount *mnt = path->mnt;
+	struct super_block *sb = mnt->mnt_sb;
 
-	/* Only bind mounts can have disconnected paths */
-	if (mnt->mnt_root == mnt->mnt_sb->s_root)
+	/* Bind mounts and multi-root filesystems can have disconnected paths */
+	if (!(sb->s_iflags & SB_I_MULTIROOT) && (mnt->mnt_root == sb->s_root))
 		return true;
 
 	return is_subdir(path->dentry, mnt->mnt_root);
@@ -865,8 +876,10 @@
 		path_put(&last->link);
 }
 
-int sysctl_protected_symlinks __read_mostly = 0;
-int sysctl_protected_hardlinks __read_mostly = 0;
+int sysctl_protected_symlinks __read_mostly = 1;
+int sysctl_protected_hardlinks __read_mostly = 1;
+int sysctl_protected_fifos __read_mostly;
+int sysctl_protected_regular __read_mostly;
 
 /**
  * may_follow_link - Check symlink following for unsafe situations
@@ -887,6 +900,7 @@
 {
 	const struct inode *inode;
 	const struct inode *parent;
+	kuid_t puid;
 
 	if (!sysctl_protected_symlinks)
 		return 0;
@@ -902,7 +916,8 @@
 		return 0;
 
 	/* Allowed if parent directory and link owner match. */
-	if (uid_eq(parent->i_uid, inode->i_uid))
+	puid = parent->i_uid;
+	if (uid_valid(puid) && uid_eq(puid, inode->i_uid))
 		return 0;
 
 	if (nd->flags & LOOKUP_RCU)
@@ -978,6 +993,46 @@
 	return -EPERM;
 }
 
+/**
+ * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory
+ *			  should be allowed, or not, on files that already
+ *			  exist.
+ * @dir_mode: mode bits of directory
+ * @dir_uid: owner of directory
+ * @inode: the inode of the file to open
+ *
+ * Block an O_CREAT open of a FIFO (or a regular file) when:
+ *   - sysctl_protected_fifos (or sysctl_protected_regular) is enabled
+ *   - the file already exists
+ *   - we are in a sticky directory
+ *   - we don't own the file
+ *   - the owner of the directory doesn't own the file
+ *   - the directory is world writable
+ * If the sysctl_protected_fifos (or sysctl_protected_regular) is set to 2
+ * the directory doesn't have to be world writable: being group writable will
+ * be enough.
+ *
+ * Returns 0 if the open is allowed, -ve on error.
+ */
+static int may_create_in_sticky(umode_t dir_mode, kuid_t dir_uid,
+				struct inode * const inode)
+{
+	if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
+	    (!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
+	    likely(!(dir_mode & S_ISVTX)) ||
+	    uid_eq(inode->i_uid, dir_uid) ||
+	    uid_eq(current_fsuid(), inode->i_uid))
+		return 0;
+
+	if (likely(dir_mode & 0002) ||
+	    (dir_mode & 0020 &&
+	     ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) ||
+	      (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) {
+		return -EACCES;
+	}
+	return 0;
+}
+
 static __always_inline
 const char *get_link(struct nameidata *nd)
 {
@@ -1105,6 +1160,9 @@
 	    path->dentry->d_inode)
 		return -EISDIR;
 
+	if (path->dentry->d_sb->s_user_ns != &init_user_ns)
+		return -EACCES;
+
 	nd->total_link_count++;
 	if (nd->total_link_count >= 40)
 		return -ELOOP;
@@ -1312,7 +1370,7 @@
 			nd->path.dentry = parent;
 			nd->seq = seq;
 			if (unlikely(!path_connected(&nd->path)))
-				return -ENOENT;
+				return -ECHILD;
 			break;
 		} else {
 			struct mount *mnt = real_mount(nd->path.mnt);
@@ -1711,6 +1769,11 @@
 		return 0;
 	if (!follow)
 		return 0;
+	/* make sure that d_is_symlink above matches inode */
+	if (nd->flags & LOOKUP_RCU) {
+		if (read_seqcount_retry(&link->dentry->d_seq, seq))
+			return -ECHILD;
+	}
 	return pick_link(nd, link, inode, seq);
 }
 
@@ -1742,11 +1805,11 @@
 		if (err < 0)
 			return err;
 
-		inode = d_backing_inode(path.dentry);
 		seq = 0;	/* we are already out of RCU mode */
 		err = -ENOENT;
 		if (d_is_negative(path.dentry))
 			goto out_path_put;
+		inode = d_backing_inode(path.dentry);
 	}
 
 	if (flags & WALK_PUT)
@@ -1993,6 +2056,9 @@
 	int retval = 0;
 	const char *s = nd->name->name;
 
+	if (!*s)
+		flags &= ~LOOKUP_RCU;
+
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
 	nd->depth = 0;
@@ -2539,10 +2605,11 @@
  *	c. have CAP_FOWNER capability
  *  6. If the victim is append-only or immutable we can't do antyhing with
  *     links pointing to it.
- *  7. If we were asked to remove a directory and victim isn't one - ENOTDIR.
- *  8. If we were asked to remove a non-directory and victim isn't one - EISDIR.
- *  9. We can't remove a root or mountpoint.
- * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
+ *  7. If the victim has an unknown uid or gid we can't change the inode.
+ *  8. If we were asked to remove a directory and victim isn't one - ENOTDIR.
+ *  9. If we were asked to remove a non-directory and victim isn't one - EISDIR.
+ * 10. We can't remove a root or mountpoint.
+ * 11. We don't allow removal of NFS sillyrenamed files; it's handled by
  *     nfs_async_unlink().
  */
 static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
@@ -2564,7 +2631,7 @@
 		return -EPERM;
 
 	if (check_sticky(dir, inode) || IS_APPEND(inode) ||
-	    IS_IMMUTABLE(inode) || IS_SWAPFILE(inode))
+	    IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode))
 		return -EPERM;
 	if (isdir) {
 		if (!d_is_dir(victim))
@@ -2585,16 +2652,22 @@
  *  1. We can't do it if child already exists (open has special treatment for
  *     this case, but since we are inlined it's OK)
  *  2. We can't do it if dir is read-only (done in permission())
- *  3. We should have write and exec permissions on dir
- *  4. We can't do it if dir is immutable (done in permission())
+ *  3. We can't do it if the fs can't represent the fsuid or fsgid.
+ *  4. We should have write and exec permissions on dir
+ *  5. We can't do it if dir is immutable (done in permission())
  */
 static inline int may_create(struct inode *dir, struct dentry *child)
 {
+	struct user_namespace *s_user_ns;
 	audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
 	if (child->d_inode)
 		return -EEXIST;
 	if (IS_DEADDIR(dir))
 		return -ENOENT;
+	s_user_ns = dir->i_sb->s_user_ns;
+	if (!kuid_has_mapping(s_user_ns, current_fsuid()) ||
+	    !kgid_has_mapping(s_user_ns, current_fsgid()))
+		return -EOVERFLOW;
 	return inode_permission(dir, MAY_WRITE | MAY_EXEC);
 }
 
@@ -2901,22 +2974,10 @@
 		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) &&
-				   d_is_reg(dentry)) {
-				goto out;
-			}
-			/* will fail later, go on to get the right error */
-		}
+	}
+	if (create_error && !dentry->d_inode) {
+		error = create_error;
+		goto out;
 	}
 looked_up:
 	path->dentry = dentry;
@@ -3018,6 +3079,8 @@
 		   int *opened)
 {
 	struct dentry *dir = nd->path.dentry;
+	kuid_t dir_uid = nd->inode->i_uid;
+	umode_t dir_mode = nd->inode->i_mode;
 	int open_flag = op->open_flag;
 	bool will_truncate = (open_flag & O_TRUNC) != 0;
 	bool got_write = false;
@@ -3130,12 +3193,12 @@
 		return error;
 
 	BUG_ON(nd->flags & LOOKUP_RCU);
-	inode = d_backing_inode(path.dentry);
 	seq = 0;	/* out of RCU mode, so the value doesn't matter */
 	if (unlikely(d_is_negative(path.dentry))) {
 		path_to_nameidata(&path, nd);
 		return -ENOENT;
 	}
+	inode = d_backing_inode(path.dentry);
 finish_lookup:
 	if (nd->depth)
 		put_link(nd);
@@ -3144,11 +3207,6 @@
 	if (unlikely(error))
 		return error;
 
-	if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) {
-		path_to_nameidata(&path, nd);
-		return -ELOOP;
-	}
-
 	if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) {
 		path_to_nameidata(&path, nd);
 	} else {
@@ -3167,9 +3225,19 @@
 		return error;
 	}
 	audit_inode(nd->name, nd->path.dentry, 0);
-	error = -EISDIR;
-	if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
+	if (unlikely(d_is_symlink(nd->path.dentry)) && !(open_flag & O_PATH)) {
+		error = -ELOOP;
 		goto out;
+	}
+	if (open_flag & O_CREAT) {
+		error = -EISDIR;
+		if (d_is_dir(nd->path.dentry))
+			goto out;
+		error = may_create_in_sticky(dir_mode, dir_uid,
+					     d_backing_inode(nd->path.dentry));
+		if (unlikely(error))
+			goto out;
+	}
 	error = -ENOTDIR;
 	if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
 		goto out;
@@ -3210,6 +3278,10 @@
 			goto exit_fput;
 	}
 out:
+	if (unlikely(error > 0)) {
+		WARN_ON(1);
+		error = -EINVAL;
+	}
 	if (got_write)
 		mnt_drop_write(nd->path.mnt);
 	path_put(&save_parent);
@@ -4014,6 +4086,13 @@
 	 */
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 		return -EPERM;
+	/*
+	 * Updating the link count will likely cause i_uid and i_gid to
+	 * be writen back improperly if their true value is unknown to
+	 * the vfs.
+	 */
+	if (HAS_UNMAPPED_ID(inode))
+		return -EPERM;
 	if (!dir->i_op->link)
 		return -EPERM;
 	if (S_ISDIR(inode->i_mode))
@@ -4181,13 +4260,17 @@
 {
 	int error;
 	bool is_dir = d_is_dir(old_dentry);
-	const unsigned char *old_name;
 	struct inode *source = old_dentry->d_inode;
 	struct inode *target = new_dentry->d_inode;
 	bool new_is_dir = false;
 	unsigned max_links = new_dir->i_sb->s_max_links;
+	struct name_snapshot old_name;
 
-	if (source == target)
+	/*
+	 * Check source == target.
+	 * On overlayfs need to look at underlying inodes.
+	 */
+	if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))
 		return 0;
 
 	error = may_delete(old_dir, old_dentry, is_dir);
@@ -4235,7 +4318,7 @@
 	if (error)
 		return error;
 
-	old_name = fsnotify_oldname_init(old_dentry->d_name.name);
+	take_dentry_name_snapshot(&old_name, old_dentry);
 	dget(new_dentry);
 	if (!is_dir || (flags & RENAME_EXCHANGE))
 		lock_two_nondirectories(source, target);
@@ -4296,14 +4379,14 @@
 		mutex_unlock(&target->i_mutex);
 	dput(new_dentry);
 	if (!error) {
-		fsnotify_move(old_dir, new_dir, old_name, is_dir,
+		fsnotify_move(old_dir, new_dir, old_name.name.name, is_dir,
 			      !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry);
 		if (flags & RENAME_EXCHANGE) {
 			fsnotify_move(new_dir, old_dir, old_dentry->d_name.name,
 				      new_is_dir, NULL, new_dentry);
 		}
 	}
-	fsnotify_oldname_free(old_name);
+	release_dentry_name_snapshot(&old_name);
 
 	return error;
 }
--- linux-4.4.0.orig/fs/namespace.c
+++ linux-4.4.0/fs/namespace.c
@@ -27,6 +27,9 @@
 #include "pnode.h"
 #include "internal.h"
 
+/* Maximum number of mounts in a mount namespace */
+unsigned int sysctl_mount_max __read_mostly = 100000;
+
 static unsigned int m_hash_mask __read_mostly;
 static unsigned int m_hash_shift __read_mostly;
 static unsigned int mp_hash_mask __read_mostly;
@@ -234,6 +237,7 @@
 		INIT_LIST_HEAD(&mnt->mnt_slave_list);
 		INIT_LIST_HEAD(&mnt->mnt_slave);
 		INIT_HLIST_NODE(&mnt->mnt_mp_list);
+		INIT_LIST_HEAD(&mnt->mnt_umounting);
 #ifdef CONFIG_FSNOTIFY
 		INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);
 #endif
@@ -463,6 +467,7 @@
 	mnt_dec_writers(real_mount(mnt));
 	preempt_enable();
 }
+EXPORT_SYMBOL_GPL(__mnt_drop_write);
 
 /**
  * mnt_drop_write - give up write access to a mount
@@ -599,12 +604,21 @@
 		return 0;
 	mnt = real_mount(bastard);
 	mnt_add_count(mnt, 1);
+	smp_mb();			// see mntput_no_expire()
 	if (likely(!read_seqretry(&mount_lock, seq)))
 		return 0;
 	if (bastard->mnt_flags & MNT_SYNC_UMOUNT) {
 		mnt_add_count(mnt, -1);
 		return 1;
 	}
+	lock_mount_hash();
+	if (unlikely(bastard->mnt_flags & MNT_DOOMED)) {
+		mnt_add_count(mnt, -1);
+		unlock_mount_hash();
+		return 1;
+	}
+	unlock_mount_hash();
+	/* caller will mntput() */
 	return -1;
 }
 
@@ -638,28 +652,6 @@
 }
 
 /*
- * find the last mount at @dentry on vfsmount @mnt.
- * mount_lock must be held.
- */
-struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry)
-{
-	struct mount *p, *res = NULL;
-	p = __lookup_mnt(mnt, dentry);
-	if (!p)
-		goto out;
-	if (!(p->mnt.mnt_flags & MNT_UMOUNT))
-		res = p;
-	hlist_for_each_entry_continue(p, mnt_hash) {
-		if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry)
-			break;
-		if (!(p->mnt.mnt_flags & MNT_UMOUNT))
-			res = p;
-	}
-out:
-	return res;
-}
-
-/*
  * lookup_mnt - Return the first child mount mounted at path
  *
  * "First" means first mounted chronologically.  If you create the
@@ -743,26 +735,50 @@
 	return NULL;
 }
 
-static struct mountpoint *new_mountpoint(struct dentry *dentry)
+static struct mountpoint *get_mountpoint(struct dentry *dentry)
 {
-	struct hlist_head *chain = mp_hash(dentry);
-	struct mountpoint *mp;
+	struct mountpoint *mp, *new = NULL;
 	int ret;
 
-	mp = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
-	if (!mp)
+	if (d_mountpoint(dentry)) {
+mountpoint:
+		read_seqlock_excl(&mount_lock);
+		mp = lookup_mountpoint(dentry);
+		read_sequnlock_excl(&mount_lock);
+		if (mp)
+			goto done;
+	}
+
+	if (!new)
+		new = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
+	if (!new)
 		return ERR_PTR(-ENOMEM);
 
+
+	/* Exactly one processes may set d_mounted */
 	ret = d_set_mounted(dentry);
-	if (ret) {
-		kfree(mp);
-		return ERR_PTR(ret);
-	}
 
-	mp->m_dentry = dentry;
-	mp->m_count = 1;
-	hlist_add_head(&mp->m_hash, chain);
-	INIT_HLIST_HEAD(&mp->m_list);
+	/* Someone else set d_mounted? */
+	if (ret == -EBUSY)
+		goto mountpoint;
+
+	/* The dentry is not available as a mountpoint? */
+	mp = ERR_PTR(ret);
+	if (ret)
+		goto done;
+
+	/* Add the new mountpoint to the hash table */
+	read_seqlock_excl(&mount_lock);
+	new->m_dentry = dentry;
+	new->m_count = 1;
+	hlist_add_head(&new->m_hash, mp_hash(dentry));
+	INIT_HLIST_HEAD(&new->m_list);
+	read_sequnlock_excl(&mount_lock);
+
+	mp = new;
+	new = NULL;
+done:
+	kfree(new);
 	return mp;
 }
 
@@ -855,6 +871,13 @@
 	hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list);
 }
 
+static void __attach_mnt(struct mount *mnt, struct mount *parent)
+{
+	hlist_add_head_rcu(&mnt->mnt_hash,
+			   m_hash(&parent->mnt, mnt->mnt_mountpoint));
+	list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
+}
+
 /*
  * vfsmount lock must be held for write
  */
@@ -863,28 +886,45 @@
 			struct mountpoint *mp)
 {
 	mnt_set_mountpoint(parent, mp, mnt);
-	hlist_add_head_rcu(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry));
-	list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
+	__attach_mnt(mnt, parent);
 }
 
-static void attach_shadowed(struct mount *mnt,
-			struct mount *parent,
-			struct mount *shadows)
+void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp, struct mount *mnt)
 {
-	if (shadows) {
-		hlist_add_behind_rcu(&mnt->mnt_hash, &shadows->mnt_hash);
-		list_add(&mnt->mnt_child, &shadows->mnt_child);
-	} else {
-		hlist_add_head_rcu(&mnt->mnt_hash,
-				m_hash(&parent->mnt, mnt->mnt_mountpoint));
-		list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
-	}
+	struct mountpoint *old_mp = mnt->mnt_mp;
+	struct dentry *old_mountpoint = mnt->mnt_mountpoint;
+	struct mount *old_parent = mnt->mnt_parent;
+
+	list_del_init(&mnt->mnt_child);
+	hlist_del_init(&mnt->mnt_mp_list);
+	hlist_del_init_rcu(&mnt->mnt_hash);
+
+	attach_mnt(mnt, parent, mp);
+
+	put_mountpoint(old_mp);
+
+	/*
+	 * Safely avoid even the suggestion this code might sleep or
+	 * lock the mount hash by taking advantage of the knowledge that
+	 * mnt_change_mountpoint will not release the final reference
+	 * to a mountpoint.
+	 *
+	 * During mounting, the mount passed in as the parent mount will
+	 * continue to use the old mountpoint and during unmounting, the
+	 * old mountpoint will continue to exist until namespace_unlock,
+	 * which happens well after mnt_change_mountpoint.
+	 */
+	spin_lock(&old_mountpoint->d_lock);
+	old_mountpoint->d_lockref.count--;
+	spin_unlock(&old_mountpoint->d_lock);
+
+	mnt_add_count(old_parent, -1);
 }
 
 /*
  * vfsmount lock must be held for write
  */
-static void commit_tree(struct mount *mnt, struct mount *shadows)
+static void commit_tree(struct mount *mnt)
 {
 	struct mount *parent = mnt->mnt_parent;
 	struct mount *m;
@@ -899,7 +939,10 @@
 
 	list_splice(&head, n->list.prev);
 
-	attach_shadowed(mnt, parent, shadows);
+	n->mounts += n->pending_mounts;
+	n->pending_mounts = 0;
+
+	__attach_mnt(mnt, parent);
 	touch_mnt_namespace(n);
 }
 
@@ -963,6 +1006,21 @@
 }
 EXPORT_SYMBOL_GPL(vfs_kern_mount);
 
+struct vfsmount *
+vfs_submount(const struct dentry *mountpoint, struct file_system_type *type,
+	     const char *name, void *data)
+{
+	/* Until it is worked out how to pass the user namespace
+	 * through from the parent mount to the submount don't support
+	 * unprivileged mounts with submounts.
+	 */
+	if (mountpoint->d_sb->s_user_ns != &init_user_ns)
+		return ERR_PTR(-EPERM);
+
+	return vfs_kern_mount(type, MS_SUBMOUNT, name, data);
+}
+EXPORT_SYMBOL_GPL(vfs_submount);
+
 static struct mount *clone_mnt(struct mount *old, struct dentry *root,
 					int flag)
 {
@@ -985,7 +1043,8 @@
 			goto out_free;
 	}
 
-	mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED);
+	mnt->mnt.mnt_flags = old->mnt.mnt_flags;
+	mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL);
 	/* Don't allow unprivileged users to change mount flags */
 	if (flag & CL_UNPRIVILEGED) {
 		mnt->mnt.mnt_flags |= MNT_LOCK_ATIME;
@@ -1090,12 +1149,27 @@
 static void mntput_no_expire(struct mount *mnt)
 {
 	rcu_read_lock();
-	mnt_add_count(mnt, -1);
-	if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */
+	if (likely(READ_ONCE(mnt->mnt_ns))) {
+		/*
+		 * Since we don't do lock_mount_hash() here,
+		 * ->mnt_ns can change under us.  However, if it's
+		 * non-NULL, then there's a reference that won't
+		 * be dropped until after an RCU delay done after
+		 * turning ->mnt_ns NULL.  So if we observe it
+		 * non-NULL under rcu_read_lock(), the reference
+		 * we are dropping is not the final one.
+		 */
+		mnt_add_count(mnt, -1);
 		rcu_read_unlock();
 		return;
 	}
 	lock_mount_hash();
+	/*
+	 * make sure that if __legitimize_mnt() has not seen us grab
+	 * mount_lock, we'll see their refcount increment here.
+	 */
+	smp_mb();
+	mnt_add_count(mnt, -1);
 	if (mnt_get_count(mnt)) {
 		rcu_read_unlock();
 		unlock_mount_hash();
@@ -1419,11 +1493,16 @@
 		propagate_umount(&tmp_list);
 
 	while (!list_empty(&tmp_list)) {
+		struct mnt_namespace *ns;
 		bool disconnect;
 		p = list_first_entry(&tmp_list, struct mount, mnt_list);
 		list_del_init(&p->mnt_expire);
 		list_del_init(&p->mnt_list);
-		__touch_mnt_namespace(p->mnt_ns);
+		ns = p->mnt_ns;
+		if (ns) {
+			ns->mounts--;
+			__touch_mnt_namespace(ns);
+		}
 		p->mnt_ns = NULL;
 		if (how & UMOUNT_SYNC)
 			p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
@@ -1510,7 +1589,7 @@
 		 * Special case for "unmounting" root ...
 		 * we just try to remount it readonly.
 		 */
-		if (!capable(CAP_SYS_ADMIN))
+		if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
 			return -EPERM;
 		down_write(&sb->s_umount);
 		if (!(sb->s_flags & MS_RDONLY))
@@ -1521,8 +1600,13 @@
 
 	namespace_lock();
 	lock_mount_hash();
-	event++;
 
+	/* Recheck MNT_LOCKED with the locks held */
+	retval = -EINVAL;
+	if (mnt->mnt.mnt_flags & MNT_LOCKED)
+		goto out;
+
+	event++;
 	if (flags & MNT_DETACH) {
 		if (!list_empty(&mnt->mnt_list))
 			umount_tree(mnt, UMOUNT_PROPAGATE);
@@ -1536,6 +1620,7 @@
 			retval = 0;
 		}
 	}
+out:
 	unlock_mount_hash();
 	namespace_unlock();
 	return retval;
@@ -1557,11 +1642,12 @@
 	struct mount *mnt;
 
 	namespace_lock();
+	lock_mount_hash();
 	mp = lookup_mountpoint(dentry);
 	if (IS_ERR_OR_NULL(mp))
 		goto out_unlock;
 
-	lock_mount_hash();
+	event++;
 	while (!hlist_empty(&mp->m_list)) {
 		mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
 		if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
@@ -1570,9 +1656,9 @@
 		}
 		else umount_tree(mnt, UMOUNT_CONNECTED);
 	}
-	unlock_mount_hash();
 	put_mountpoint(mp);
 out_unlock:
+	unlock_mount_hash();
 	namespace_unlock();
 }
 
@@ -1617,7 +1703,7 @@
 		goto dput_and_out;
 	if (!check_mnt(mnt))
 		goto dput_and_out;
-	if (mnt->mnt.mnt_flags & MNT_LOCKED)
+	if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
 		goto dput_and_out;
 	retval = -EPERM;
 	if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
@@ -1693,11 +1779,16 @@
 			continue;
 
 		for (s = r; s; s = next_mnt(s, r)) {
-			struct mount *t = NULL;
 			if (!(flag & CL_COPY_UNBINDABLE) &&
 			    IS_MNT_UNBINDABLE(s)) {
-				s = skip_mnt_tree(s);
-				continue;
+				if (s->mnt.mnt_flags & MNT_LOCKED) {
+					/* Both unbindable and locked. */
+					q = ERR_PTR(-EPERM);
+					goto out;
+				} else {
+					s = skip_mnt_tree(s);
+					continue;
+				}
 			}
 			if (!(flag & CL_COPY_MNT_NS_FILE) &&
 			    is_mnt_ns_file(s->mnt.mnt_root)) {
@@ -1715,14 +1806,7 @@
 				goto out;
 			lock_mount_hash();
 			list_add_tail(&q->mnt_list, &res->mnt_list);
-			mnt_set_mountpoint(parent, p->mnt_mp, q);
-			if (!list_empty(&parent->mnt_mounts)) {
-				t = list_last_entry(&parent->mnt_mounts,
-					struct mount, mnt_child);
-				if (t->mnt_mp != p->mnt_mp)
-					t = NULL;
-			}
-			attach_shadowed(q, parent, t);
+			attach_mnt(q, parent, p->mnt_mp);
 			unlock_mount_hash();
 		}
 	}
@@ -1757,11 +1841,25 @@
 {
 	namespace_lock();
 	lock_mount_hash();
-	umount_tree(real_mount(mnt), UMOUNT_SYNC);
+	umount_tree(real_mount(mnt), 0);
 	unlock_mount_hash();
 	namespace_unlock();
 }
 
+static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
+{
+	struct mount *child;
+
+	list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
+		if (!is_subdir(child->mnt_mountpoint, dentry))
+			continue;
+
+		if (child->mnt.mnt_flags & MNT_LOCKED)
+			return true;
+	}
+	return false;
+}
+
 /**
  * clone_private_mount - create a private clone of a path
  *
@@ -1776,16 +1874,27 @@
 	struct mount *old_mnt = real_mount(path->mnt);
 	struct mount *new_mnt;
 
+	down_read(&namespace_sem);
 	if (IS_MNT_UNBINDABLE(old_mnt))
-		return ERR_PTR(-EINVAL);
+		goto invalid;
+
+	if (!check_mnt(old_mnt))
+		goto invalid;
+
+	if (has_locked_children(old_mnt, path->dentry))
+		goto invalid;
 
-	down_read(&namespace_sem);
 	new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
 	up_read(&namespace_sem);
+
 	if (IS_ERR(new_mnt))
 		return ERR_CAST(new_mnt);
 
 	return &new_mnt->mnt;
+
+invalid:
+	up_read(&namespace_sem);
+	return ERR_PTR(-EINVAL);
 }
 EXPORT_SYMBOL_GPL(clone_private_mount);
 
@@ -1803,6 +1912,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(iterate_mounts);
 
 static void cleanup_group_ids(struct mount *mnt, struct mount *end)
 {
@@ -1831,6 +1941,28 @@
 	return 0;
 }
 
+int count_mounts(struct mnt_namespace *ns, struct mount *mnt)
+{
+	unsigned int max = READ_ONCE(sysctl_mount_max);
+	unsigned int mounts = 0, old, pending, sum;
+	struct mount *p;
+
+	for (p = mnt; p; p = next_mnt(p, mnt))
+		mounts++;
+
+	old = ns->mounts;
+	pending = ns->pending_mounts;
+	sum = old + pending;
+	if ((old > sum) ||
+	    (pending > sum) ||
+	    (max < sum) ||
+	    (mounts > (max - sum)))
+		return -ENOSPC;
+
+	ns->pending_mounts = pending + mounts;
+	return 0;
+}
+
 /*
  *  @source_mnt : mount tree to be attached
  *  @nd         : place the mount tree @source_mnt is attached
@@ -1900,10 +2032,26 @@
 			struct path *parent_path)
 {
 	HLIST_HEAD(tree_list);
+	struct mnt_namespace *ns = dest_mnt->mnt_ns;
+	struct mountpoint *smp;
 	struct mount *child, *p;
 	struct hlist_node *n;
 	int err;
 
+	/* Is there space to add these mounts to the mount namespace? */
+	if (!parent_path) {
+		err = count_mounts(ns, source_mnt);
+		if (err)
+			goto out;
+	}
+
+	/* Preallocate a mountpoint in case the new mounts need
+	 * to be tucked under other mounts.
+	 */
+	smp = get_mountpoint(source_mnt->mnt.mnt_root);
+	if (IS_ERR(smp))
+		return PTR_ERR(smp);
+
 	if (IS_MNT_SHARED(dest_mnt)) {
 		err = invent_group_ids(source_mnt, true);
 		if (err)
@@ -1923,16 +2071,19 @@
 		touch_mnt_namespace(source_mnt->mnt_ns);
 	} else {
 		mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt);
-		commit_tree(source_mnt, NULL);
+		commit_tree(source_mnt);
 	}
 
 	hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) {
 		struct mount *q;
 		hlist_del_init(&child->mnt_hash);
-		q = __lookup_mnt_last(&child->mnt_parent->mnt,
-				      child->mnt_mountpoint);
-		commit_tree(child, q);
+		q = __lookup_mnt(&child->mnt_parent->mnt,
+				 child->mnt_mountpoint);
+		if (q)
+			mnt_change_mountpoint(child, smp, q);
+		commit_tree(child);
 	}
+	put_mountpoint(smp);
 	unlock_mount_hash();
 
 	return 0;
@@ -1940,11 +2091,17 @@
  out_cleanup_ids:
 	while (!hlist_empty(&tree_list)) {
 		child = hlist_entry(tree_list.first, struct mount, mnt_hash);
+		child->mnt_parent->mnt_ns->pending_mounts = 0;
 		umount_tree(child, UMOUNT_SYNC);
 	}
 	unlock_mount_hash();
 	cleanup_group_ids(source_mnt, NULL);
  out:
+	ns->pending_mounts = 0;
+	read_seqlock_excl(&mount_lock);
+	put_mountpoint(smp);
+	read_sequnlock_excl(&mount_lock);
+
 	return err;
 }
 
@@ -1961,9 +2118,7 @@
 	namespace_lock();
 	mnt = lookup_mnt(path);
 	if (likely(!mnt)) {
-		struct mountpoint *mp = lookup_mountpoint(dentry);
-		if (!mp)
-			mp = new_mountpoint(dentry);
+		struct mountpoint *mp = get_mountpoint(dentry);
 		if (IS_ERR(mp)) {
 			namespace_unlock();
 			mutex_unlock(&dentry->d_inode->i_mutex);
@@ -1982,7 +2137,11 @@
 static void unlock_mount(struct mountpoint *where)
 {
 	struct dentry *dentry = where->m_dentry;
+
+	read_seqlock_excl(&mount_lock);
 	put_mountpoint(where);
+	read_sequnlock_excl(&mount_lock);
+
 	namespace_unlock();
 	mutex_unlock(&dentry->d_inode->i_mutex);
 }
@@ -2051,19 +2210,6 @@
 	return err;
 }
 
-static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
-{
-	struct mount *child;
-	list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
-		if (!is_subdir(child->mnt_mountpoint, dentry))
-			continue;
-
-		if (child->mnt.mnt_flags & MNT_LOCKED)
-			return true;
-	}
-	return false;
-}
-
 /*
  * do loopback mount.
  */
@@ -2205,7 +2351,7 @@
 	down_write(&sb->s_umount);
 	if (flags & MS_BIND)
 		err = change_mount_flags(path->mnt, flags);
-	else if (!capable(CAP_SYS_ADMIN))
+	else if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
 		err = -EPERM;
 	else
 		err = do_remount_sb(sb, flags, data, 0);
@@ -2381,6 +2527,9 @@
 	struct vfsmount *mnt;
 	int err;
 
+	if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN))
+		return -EPERM;
+
 	if (!fstype)
 		return -EINVAL;
 
@@ -2389,10 +2538,6 @@
 		return -ENODEV;
 
 	if (user_ns != &init_user_ns) {
-		if (!(type->fs_flags & FS_USERNS_MOUNT)) {
-			put_filesystem(type);
-			return -EPERM;
-		}
 		/* Only in special cases allow devices from mounts
 		 * created outside the initial user namespace.
 		 */
@@ -2401,8 +2546,10 @@
 			mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
 		}
 		if (type->fs_flags & FS_USERNS_VISIBLE) {
-			if (!fs_fully_visible(type, &mnt_flags))
+			if (!fs_fully_visible(type, &mnt_flags)) {
+				put_filesystem(type);
 				return -EPERM;
+			}
 		}
 	}
 
@@ -2710,7 +2857,7 @@
 
 	flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
 		   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
-		   MS_STRICTATIME);
+		   MS_STRICTATIME | MS_SUBMOUNT);
 
 	if (flags & MS_REMOUNT)
 		retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
@@ -2766,6 +2913,8 @@
 	init_waitqueue_head(&new_ns->poll);
 	new_ns->event = 0;
 	new_ns->user_ns = get_user_ns(user_ns);
+	new_ns->mounts = 0;
+	new_ns->pending_mounts = 0;
 	return new_ns;
 }
 
@@ -2815,6 +2964,7 @@
 	q = new;
 	while (p) {
 		q->mnt_ns = new_ns;
+		new_ns->mounts++;
 		if (new_fs) {
 			if (&p->mnt == new_fs->root.mnt) {
 				new_fs->root.mnt = mntget(&q->mnt);
@@ -2853,6 +3003,7 @@
 		struct mount *mnt = real_mount(m);
 		mnt->mnt_ns = new_ns;
 		new_ns->root = mnt;
+		new_ns->mounts++;
 		list_add(&mnt->mnt_list, &new_ns->list);
 	} else {
 		mntput(m);
@@ -3037,8 +3188,8 @@
 	/* make certain new is below the root */
 	if (!is_path_reachable(new_mnt, new.dentry, &root))
 		goto out4;
-	root_mp->m_count++; /* pin it so it won't go away */
 	lock_mount_hash();
+	root_mp->m_count++; /* pin it so it won't go away */
 	detach_mnt(new_mnt, &parent_path);
 	detach_mnt(root_mnt, &root_parent);
 	if (root_mnt->mnt.mnt_flags & MNT_LOCKED) {
@@ -3052,9 +3203,9 @@
 	touch_mnt_namespace(current->nsproxy->mnt_ns);
 	/* A moved mount should not expire automatically */
 	list_del_init(&new_mnt->mnt_expire);
+	put_mountpoint(root_mp);
 	unlock_mount_hash();
 	chroot_fs_refs(&root, &new);
-	put_mountpoint(root_mp);
 	error = 0;
 out4:
 	unlock_mount(old_mp);
@@ -3236,6 +3387,10 @@
 		if (mnt->mnt.mnt_sb->s_iflags & SB_I_NOEXEC)
 			mnt_flags &= ~(MNT_LOCK_NOSUID | MNT_LOCK_NOEXEC);
 
+		/* Don't miss readonly hidden in the superblock flags */
+		if (mnt->mnt.mnt_sb->s_flags & MS_RDONLY)
+			mnt_flags |= MNT_LOCK_READONLY;
+
 		/* Verify the mount flags are equal to or more permissive
 		 * than the proposed new mount.
 		 */
@@ -3262,7 +3417,7 @@
 		list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
 			struct inode *inode = child->mnt_mountpoint->d_inode;
 			/* Only worry about locked mounts */
-			if (!(mnt_flags & MNT_LOCKED))
+			if (!(child->mnt.mnt_flags & MNT_LOCKED))
 				continue;
 			/* Is the directory permanetly empty? */
 			if (!is_empty_dir_inode(inode))
@@ -3283,6 +3438,19 @@
 	return visible;
 }
 
+bool mnt_may_suid(struct vfsmount *mnt)
+{
+	/*
+	 * Foreign mounts (accessed via fchdir or through /proc
+	 * symlinks) are always treated as if they are nosuid.  This
+	 * prevents namespaces from trusting potentially unsafe
+	 * suid/sgid bits, file caps, or security labels that originate
+	 * in other namespaces.
+	 */
+	return !(mnt->mnt_flags & MNT_NOSUID) && check_mnt(real_mount(mnt)) &&
+	       current_in_userns(mnt->mnt_sb->s_user_ns);
+}
+
 static struct ns_common *mntns_get(struct task_struct *task)
 {
 	struct ns_common *ns = NULL;
--- linux-4.4.0.orig/fs/ncpfs/dir.c
+++ linux-4.4.0/fs/ncpfs/dir.c
@@ -133,12 +133,11 @@
 		return 0;
 
 	if (!ncp_case_sensitive(inode)) {
-		struct super_block *sb = dentry->d_sb;
 		struct nls_table *t;
 		unsigned long hash;
 		int i;
 
-		t = NCP_IO_TABLE(sb);
+		t = NCP_IO_TABLE(dentry->d_sb);
 		hash = init_name_hash();
 		for (i=0; i<this->len ; i++)
 			hash = partial_name_hash(ncp_tolower(t, this->name[i]),
@@ -633,7 +632,7 @@
 				d_rehash(newdent);
 		} else {
 			spin_lock(&dentry->d_lock);
-			NCP_FINFO(inode)->flags &= ~NCPI_DIR_CACHE;
+			NCP_FINFO(dir)->flags &= ~NCPI_DIR_CACHE;
 			spin_unlock(&dentry->d_lock);
 		}
 	} else {
--- linux-4.4.0.orig/fs/ncpfs/inode.c
+++ linux-4.4.0/fs/ncpfs/inode.c
@@ -884,7 +884,7 @@
 	/* ageing the dentry to force validation */
 	ncp_age_dentry(server, dentry);
 
-	result = inode_change_ok(inode, attr);
+	result = setattr_prepare(dentry, attr);
 	if (result < 0)
 		goto out;
 
--- linux-4.4.0.orig/fs/ncpfs/ioctl.c
+++ linux-4.4.0/fs/ncpfs/ioctl.c
@@ -233,7 +233,7 @@
 		len = strlen(server->nls_vol->charset);
 		if (len > NCP_IOCSNAME_LEN)
 			len = NCP_IOCSNAME_LEN;
-		strncpy(user.codepage, server->nls_vol->charset, len);
+		strscpy(user.codepage, server->nls_vol->charset, NCP_IOCSNAME_LEN);
 		user.codepage[len] = 0;
 	}
 
@@ -243,7 +243,7 @@
 		len = strlen(server->nls_io->charset);
 		if (len > NCP_IOCSNAME_LEN)
 			len = NCP_IOCSNAME_LEN;
-		strncpy(user.iocharset,	server->nls_io->charset, len);
+		strscpy(user.iocharset,	server->nls_io->charset, NCP_IOCSNAME_LEN);
 		user.iocharset[len] = 0;
 	}
 	mutex_unlock(&server->root_setup_lock);
--- linux-4.4.0.orig/fs/ncpfs/ncplib_kernel.c
+++ linux-4.4.0/fs/ncpfs/ncplib_kernel.c
@@ -980,6 +980,10 @@
 		goto out;
 	}
 	*bytes_read = ncp_reply_be16(server, 0);
+	if (*bytes_read > to_read) {
+		result = -EINVAL;
+		goto out;
+	}
 	source = ncp_reply_data(server, 2 + (offset & 1));
 
 	memcpy(target, source, *bytes_read);
--- linux-4.4.0.orig/fs/nfs/Kconfig
+++ linux-4.4.0/fs/nfs/Kconfig
@@ -89,7 +89,7 @@
 config NFS_SWAP
 	bool "Provide swap over NFS support"
 	default n
-	depends on NFS_FS
+	depends on NFS_FS && SWAP
 	select SUNRPC_SWAP
 	help
 	  This option enables swapon to work on files located on NFS mounts.
@@ -121,6 +121,7 @@
 config PNFS_BLOCK
 	tristate
 	depends on NFS_V4_1 && BLK_DEV_DM
+	depends on 64BIT || LBDAF
 	default NFS_V4
 
 config PNFS_OBJLAYOUT
--- linux-4.4.0.orig/fs/nfs/blocklayout/dev.c
+++ linux-4.4.0/fs/nfs/blocklayout/dev.c
@@ -162,7 +162,7 @@
 	chunk = div_u64(offset, dev->chunk_size);
 	div_u64_rem(chunk, dev->nr_children, &chunk_idx);
 
-	if (chunk_idx > dev->nr_children) {
+	if (chunk_idx >= dev->nr_children) {
 		dprintk("%s: invalid chunk idx %d (%lld/%lld)\n",
 			__func__, chunk_idx, offset, dev->chunk_size);
 		/* error, should not happen */
--- linux-4.4.0.orig/fs/nfs/callback.c
+++ linux-4.4.0/fs/nfs/callback.c
@@ -261,7 +261,7 @@
 	}
 
 	ret = -EPROTONOSUPPORT;
-	if (minorversion == 0)
+	if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
 		ret = nfs4_callback_up_net(serv, net);
 	else if (xprt->ops->bc_up)
 		ret = xprt->ops->bc_up(serv, net);
@@ -275,6 +275,7 @@
 err_socks:
 	svc_rpcb_cleanup(serv, net);
 err_bind:
+	nn->cb_users[minorversion]--;
 	dprintk("NFS: Couldn't create callback socket: err = %d; "
 			"net = %p\n", ret, net);
 	return ret;
--- linux-4.4.0.orig/fs/nfs/callback_proc.c
+++ linux-4.4.0/fs/nfs/callback_proc.c
@@ -368,7 +368,7 @@
 				  uint32_t nrclists,
 				  struct referring_call_list *rclists)
 {
-	bool status = 0;
+	bool status = false;
 	int i, j;
 	struct nfs4_session *session;
 	struct nfs4_slot_table *tbl;
--- linux-4.4.0.orig/fs/nfs/callback_xdr.c
+++ linux-4.4.0/fs/nfs/callback_xdr.c
@@ -911,16 +911,21 @@
 
 	if (hdr_arg.minorversion == 0) {
 		cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident);
-		if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
-			return rpc_drop_reply;
+		if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) {
+			if (cps.clp)
+				nfs_put_client(cps.clp);
+			goto out_invalidcred;
+		}
 	}
 
 	cps.minorversion = hdr_arg.minorversion;
 	hdr_res.taglen = hdr_arg.taglen;
 	hdr_res.tag = hdr_arg.tag;
-	if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
+	if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) {
+		if (cps.clp)
+			nfs_put_client(cps.clp);
 		return rpc_system_err;
-
+	}
 	while (status == 0 && nops != hdr_arg.nops) {
 		status = process_op(nops, rqstp, &xdr_in,
 				    argp, &xdr_out, resp, &cps);
@@ -940,6 +945,10 @@
 	nfs_put_client(cps.clp);
 	dprintk("%s: done, status = %u\n", __func__, ntohl(status));
 	return rpc_success;
+
+out_invalidcred:
+	pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n");
+	return rpc_autherr_badcred;
 }
 
 /*
--- linux-4.4.0.orig/fs/nfs/client.c
+++ linux-4.4.0/fs/nfs/client.c
@@ -377,7 +377,7 @@
 
 	if (cl_init->hostname == NULL) {
 		WARN_ON(1);
-		return NULL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	dprintk("--> nfs_get_client(%s,v%u)\n",
--- linux-4.4.0.orig/fs/nfs/delegation.c
+++ linux-4.4.0/fs/nfs/delegation.c
@@ -41,6 +41,27 @@
 	set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
 }
 
+static bool
+nfs4_is_valid_delegation(const struct nfs_delegation *delegation,
+		fmode_t flags)
+{
+	if (delegation != NULL && (delegation->type & flags) == flags &&
+	    !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
+	    !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
+		return true;
+	return false;
+}
+
+struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode)
+{
+	struct nfs_delegation *delegation;
+
+	delegation = rcu_dereference(NFS_I(inode)->delegation);
+	if (nfs4_is_valid_delegation(delegation, 0))
+		return delegation;
+	return NULL;
+}
+
 static int
 nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark)
 {
@@ -50,8 +71,7 @@
 	flags &= FMODE_READ|FMODE_WRITE;
 	rcu_read_lock();
 	delegation = rcu_dereference(NFS_I(inode)->delegation);
-	if (delegation != NULL && (delegation->type & flags) == flags &&
-	    !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
+	if (nfs4_is_valid_delegation(delegation, flags)) {
 		if (mark)
 			nfs_mark_delegation_referenced(delegation);
 		ret = 1;
@@ -81,7 +101,7 @@
 	return nfs4_do_check_delegation(inode, flags, false);
 }
 
-static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
+static int nfs_delegation_claim_locks(struct nfs4_state *state, const nfs4_stateid *stateid)
 {
 	struct inode *inode = state->inode;
 	struct file_lock *fl;
@@ -96,7 +116,7 @@
 	spin_lock(&flctx->flc_lock);
 restart:
 	list_for_each_entry(fl, list, fl_list) {
-		if (nfs_file_open_context(fl->fl_file) != ctx)
+		if (nfs_file_open_context(fl->fl_file)->state != state)
 			continue;
 		spin_unlock(&flctx->flc_lock);
 		status = nfs4_lock_delegation_recall(fl, state, stateid);
@@ -143,7 +163,7 @@
 		seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
 		err = nfs4_open_delegation_recall(ctx, state, stateid, type);
 		if (!err)
-			err = nfs_delegation_claim_locks(ctx, state, stateid);
+			err = nfs_delegation_claim_locks(state, stateid);
 		if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
 			err = -EAGAIN;
 		mutex_unlock(&sp->so_delegreturn_mutex);
@@ -892,7 +912,7 @@
 	flags &= FMODE_READ|FMODE_WRITE;
 	rcu_read_lock();
 	delegation = rcu_dereference(nfsi->delegation);
-	ret = (delegation != NULL && (delegation->type & flags) == flags);
+	ret = nfs4_is_valid_delegation(delegation, flags);
 	if (ret) {
 		nfs4_stateid_copy(dst, &delegation->stateid);
 		nfs_mark_delegation_referenced(delegation);
--- linux-4.4.0.orig/fs/nfs/delegation.h
+++ linux-4.4.0/fs/nfs/delegation.h
@@ -58,6 +58,7 @@
 int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
 bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags);
 
+struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode);
 void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
 int nfs4_have_delegation(struct inode *inode, fmode_t flags);
 int nfs4_check_delegation(struct inode *inode, fmode_t flags);
--- linux-4.4.0.orig/fs/nfs/dir.c
+++ linux-4.4.0/fs/nfs/dir.c
@@ -169,6 +169,17 @@
 	unsigned int	eof:1;
 } nfs_readdir_descriptor_t;
 
+static
+void nfs_readdir_init_array(struct page *page)
+{
+	struct nfs_cache_array *array;
+
+	array = kmap_atomic(page);
+	memset(array, 0, sizeof(struct nfs_cache_array));
+	array->eof_index = -1;
+	kunmap_atomic(array);
+}
+
 /*
  * The caller is responsible for calling nfs_readdir_release_array(page)
  */
@@ -202,6 +213,7 @@
 	array = kmap_atomic(page);
 	for (i = 0; i < array->size; i++)
 		kfree(array->array[i].string.name);
+	array->size = 0;
 	kunmap_atomic(array);
 }
 
@@ -277,7 +289,7 @@
 	desc->cache_entry_index = index;
 	return 0;
 out_eof:
-	desc->eof = 1;
+	desc->eof = true;
 	return -EBADCOOKIE;
 }
 
@@ -331,7 +343,7 @@
 	if (array->eof_index >= 0) {
 		status = -EBADCOOKIE;
 		if (*desc->dir_cookie == array->last_cookie)
-			desc->eof = 1;
+			desc->eof = true;
 	}
 out:
 	return status;
@@ -377,7 +389,7 @@
  again:
 	timestamp = jiffies;
 	gencount = nfs_inc_attr_generation_counter();
-	error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages,
+	error = NFS_PROTO(inode)->readdir(file_dentry(file), cred, entry->cookie, pages,
 					  NFS_SERVER(inode)->dtsize, desc->plus);
 	if (error < 0) {
 		/* We requested READDIRPLUS, but the server doesn't grok it */
@@ -462,7 +474,7 @@
 {
 	if (!list_empty(&NFS_I(dir)->open_files)) {
 		nfs_advise_use_readdirplus(dir);
-		nfs_zap_mapping(dir, dir->i_mapping);
+		invalidate_mapping_pages(dir->i_mapping, 0, -1);
 	}
 }
 
@@ -550,6 +562,9 @@
 	xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
 
 	do {
+		if (entry->label)
+			entry->label->len = NFS4_MAXLABELLEN;
+
 		status = xdr_decode(desc, entry, &stream);
 		if (status != 0) {
 			if (status == -EAGAIN)
@@ -560,7 +575,7 @@
 		count++;
 
 		if (desc->plus != 0)
-			nfs_prime_dcache(desc->file->f_path.dentry, entry);
+			nfs_prime_dcache(file_dentry(desc->file), entry);
 
 		status = nfs_readdir_add_to_array(entry, page);
 		if (status != 0)
@@ -622,6 +637,8 @@
 	int status = -ENOMEM;
 	unsigned int array_size = ARRAY_SIZE(pages);
 
+	nfs_readdir_init_array(page);
+
 	entry.prev_cookie = 0;
 	entry.cookie = desc->last_cookie;
 	entry.eof = 0;
@@ -642,8 +659,6 @@
 		status = PTR_ERR(array);
 		goto out_label_free;
 	}
-	memset(array, 0, sizeof(struct nfs_cache_array));
-	array->eof_index = -1;
 
 	status = nfs_readdir_alloc_pages(pages, array_size);
 	if (status < 0)
@@ -698,6 +713,7 @@
 	unlock_page(page);
 	return 0;
  error:
+	nfs_readdir_clear_array(page);
 	unlock_page(page);
 	return ret;
 }
@@ -705,8 +721,6 @@
 static
 void cache_page_release(nfs_readdir_descriptor_t *desc)
 {
-	if (!desc->page->mapping)
-		nfs_readdir_clear_array(desc->page);
 	page_cache_release(desc->page);
 	desc->page = NULL;
 }
@@ -720,19 +734,28 @@
 
 /*
  * Returns 0 if desc->dir_cookie was found on page desc->page_index
+ * and locks the page to prevent removal from the page cache.
  */
 static
-int find_cache_page(nfs_readdir_descriptor_t *desc)
+int find_and_lock_cache_page(nfs_readdir_descriptor_t *desc)
 {
 	int res;
 
 	desc->page = get_cache_page(desc);
 	if (IS_ERR(desc->page))
 		return PTR_ERR(desc->page);
-
-	res = nfs_readdir_search_array(desc);
+	res = lock_page_killable(desc->page);
 	if (res != 0)
-		cache_page_release(desc);
+		goto error;
+	res = -EAGAIN;
+	if (desc->page->mapping != NULL) {
+		res = nfs_readdir_search_array(desc);
+		if (res == 0)
+			return 0;
+	}
+	unlock_page(desc->page);
+error:
+	cache_page_release(desc);
 	return res;
 }
 
@@ -747,7 +770,7 @@
 		desc->last_cookie = 0;
 	}
 	do {
-		res = find_cache_page(desc);
+		res = find_and_lock_cache_page(desc);
 	} while (res == -EAGAIN);
 	return res;
 }
@@ -776,7 +799,7 @@
 		ent = &array->array[i];
 		if (!dir_emit(desc->ctx, ent->string.name, ent->string.len,
 		    nfs_compat_user_ino64(ent->ino), ent->d_type)) {
-			desc->eof = 1;
+			desc->eof = true;
 			break;
 		}
 		desc->ctx->pos++;
@@ -788,11 +811,10 @@
 			ctx->duped = 1;
 	}
 	if (array->eof_index >= 0)
-		desc->eof = 1;
+		desc->eof = true;
 
 	nfs_readdir_release_array(desc->page);
 out:
-	cache_page_release(desc);
 	dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
 			(unsigned long long)*desc->dir_cookie, res);
 	return res;
@@ -838,24 +860,13 @@
 
 	status = nfs_do_filldir(desc);
 
+ out_release:
+	nfs_readdir_clear_array(desc->page);
+	cache_page_release(desc);
  out:
 	dfprintk(DIRCACHE, "NFS: %s: returns %d\n",
 			__func__, status);
 	return status;
- out_release:
-	cache_page_release(desc);
-	goto out;
-}
-
-static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
-{
-	struct nfs_inode *nfsi = NFS_I(dir);
-
-	if (nfs_attribute_cache_expired(dir))
-		return true;
-	if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
-		return true;
-	return false;
 }
 
 /* The file offset position represents the dirent entry number.  A
@@ -864,7 +875,7 @@
  */
 static int nfs_readdir(struct file *file, struct dir_context *ctx)
 {
-	struct dentry	*dentry = file->f_path.dentry;
+	struct dentry	*dentry = file_dentry(file);
 	struct inode	*inode = d_inode(dentry);
 	nfs_readdir_descriptor_t my_desc,
 			*desc = &my_desc;
@@ -890,7 +901,7 @@
 	desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
 
 	nfs_block_sillyrename(dentry);
-	if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode))
+	if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
 		res = nfs_revalidate_mapping(inode, file->f_mapping);
 	if (res < 0)
 		goto out;
@@ -901,7 +912,7 @@
 		if (res == -EBADCOOKIE) {
 			res = 0;
 			/* This means either end of directory */
-			if (*desc->dir_cookie && desc->eof == 0) {
+			if (*desc->dir_cookie && !desc->eof) {
 				/* Or that the server has 'lost' a cookie */
 				res = uncached_readdir(desc);
 				if (res == 0)
@@ -921,6 +932,8 @@
 			break;
 
 		res = nfs_do_filldir(desc);
+		unlock_page(desc->page);
+		cache_page_release(desc);
 		if (res < 0)
 			break;
 	} while (!desc->eof);
@@ -1146,11 +1159,13 @@
 	/* Force a full look up iff the parent directory has changed */
 	if (!nfs_is_exclusive_create(dir, flags) &&
 	    nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
-
-		if (nfs_lookup_verify_inode(inode, flags)) {
+		error = nfs_lookup_verify_inode(inode, flags);
+		if (error) {
 			if (flags & LOOKUP_RCU)
 				return -ECHILD;
-			goto out_zap_parent;
+			if (error == -ESTALE)
+				goto out_zap_parent;
+			goto out_error;
 		}
 		goto out_valid;
 	}
@@ -1174,8 +1189,10 @@
 	trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
 	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
 	trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
-	if (error)
+	if (error == -ESTALE || error == -ENOENT)
 		goto out_bad;
+	if (error)
+		goto out_error;
 	if (nfs_compare_fh(NFS_FH(inode), fhandle))
 		goto out_bad;
 	if ((error = nfs_refresh_inode(inode, fattr)) != 0)
@@ -1267,7 +1284,7 @@
 		return 0;
 	}
 
-	error = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	error = nfs_lookup_verify_inode(inode, flags);
 	dfprintk(LOOKUPCACHE, "NFS: %s: inode %lu is %s\n",
 			__func__, inode->i_ino, error ? "invalid" : "valid");
 	return !error;
@@ -1427,6 +1444,7 @@
 
 const struct dentry_operations nfs4_dentry_operations = {
 	.d_revalidate	= nfs4_lookup_revalidate,
+	.d_weak_revalidate	= nfs_weak_revalidate,
 	.d_delete	= nfs_dentry_delete,
 	.d_iput		= nfs_dentry_iput,
 	.d_automount	= nfs_d_automount,
@@ -1531,9 +1549,9 @@
 		err = PTR_ERR(inode);
 		trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
 		put_nfs_open_context(ctx);
+		d_drop(dentry);
 		switch (err) {
 		case -ENOENT:
-			d_drop(dentry);
 			d_add(dentry, NULL);
 			nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 			break;
@@ -1559,6 +1577,19 @@
 
 no_open:
 	res = nfs_lookup(dir, dentry, lookup_flags);
+	if (!res) {
+		inode = d_inode(dentry);
+		if ((lookup_flags & LOOKUP_DIRECTORY) && inode &&
+		    !(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
+			res = ERR_PTR(-ENOTDIR);
+	} else if (!IS_ERR(res)) {
+		inode = d_inode(res);
+		if ((lookup_flags & LOOKUP_DIRECTORY) && inode &&
+		    !(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) {
+			dput(res);
+			res = ERR_PTR(-ENOTDIR);
+		}
+	}
 	err = PTR_ERR(res);
 	if (IS_ERR(res))
 		goto out;
@@ -2057,7 +2088,7 @@
 		if (new_inode != NULL)
 			nfs_drop_nlink(new_inode);
 		d_move(old_dentry, new_dentry);
-		nfs_set_verifier(new_dentry,
+		nfs_set_verifier(old_dentry,
 					nfs_save_change_attribute(new_dir));
 	} else if (error == -ENOENT)
 		nfs_dentry_handle_enoent(old_dentry);
@@ -2432,6 +2463,20 @@
 }
 EXPORT_SYMBOL_GPL(nfs_may_open);
 
+static int nfs_execute_ok(struct inode *inode, int mask)
+{
+	struct nfs_server *server = NFS_SERVER(inode);
+	int ret;
+
+	if (mask & MAY_NOT_BLOCK)
+		ret = nfs_revalidate_inode_rcu(server, inode);
+	else
+		ret = nfs_revalidate_inode(server, inode);
+	if (ret == 0 && !execute_ok(inode))
+		ret = -EACCES;
+	return ret;
+}
+
 int nfs_permission(struct inode *inode, int mask)
 {
 	struct rpc_cred *cred;
@@ -2449,6 +2494,9 @@
 		case S_IFLNK:
 			goto out;
 		case S_IFREG:
+			if ((mask & MAY_OPEN) &&
+			   nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN))
+				return 0;
 			break;
 		case S_IFDIR:
 			/*
@@ -2481,8 +2529,8 @@
 			res = PTR_ERR(cred);
 	}
 out:
-	if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
-		res = -EACCES;
+	if (!res && (mask & MAY_EXEC))
+		res = nfs_execute_ok(inode, mask);
 
 	dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n",
 		inode->i_sb->s_id, inode->i_ino, mask, res);
--- linux-4.4.0.orig/fs/nfs/direct.c
+++ linux-4.4.0/fs/nfs/direct.c
@@ -86,9 +86,9 @@
 	struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX];
 	int			mirror_count;
 
+	loff_t			io_start;	/* Start offset for I/O */
 	ssize_t			count,		/* bytes actually processed */
 				bytes_left,	/* bytes left to be sent */
-				io_start,	/* start of IO */
 				error;		/* any reported error */
 	struct completion	completion;	/* wait for i/o completion */
 
@@ -605,6 +605,7 @@
 	l_ctx = nfs_get_lock_context(dreq->ctx);
 	if (IS_ERR(l_ctx)) {
 		result = PTR_ERR(l_ctx);
+		nfs_direct_req_release(dreq);
 		goto out_release;
 	}
 	dreq->l_ctx = l_ctx;
@@ -670,6 +671,10 @@
 
 	req = nfs_list_entry(reqs.next);
 	nfs_direct_setup_mirroring(dreq, &desc, req);
+	if (desc.pg_error < 0) {
+		list_splice_init(&reqs, &failed);
+		goto out_failed;
+	}
 
 	list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
 		if (!nfs_pageio_add_request(&desc, req)) {
@@ -677,13 +682,17 @@
 			nfs_list_add_request(req, &failed);
 			spin_lock(cinfo.lock);
 			dreq->flags = 0;
-			dreq->error = -EIO;
+			if (desc.pg_error < 0)
+				dreq->error = desc.pg_error;
+			else
+				dreq->error = -EIO;
 			spin_unlock(cinfo.lock);
 		}
 		nfs_release_request(req);
 	}
 	nfs_pageio_complete(&desc);
 
+out_failed:
 	while (!list_empty(&failed)) {
 		req = nfs_list_entry(failed.next);
 		nfs_list_remove_request(req);
@@ -787,10 +796,8 @@
 
 	spin_lock(&dreq->lock);
 
-	if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
-		dreq->flags = 0;
+	if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
 		dreq->error = hdr->error;
-	}
 	if (dreq->error == 0) {
 		nfs_direct_good_bytes(dreq, hdr);
 		if (nfs_write_need_commit(hdr)) {
@@ -900,6 +907,11 @@
 			}
 
 			nfs_direct_setup_mirroring(dreq, &desc, req);
+			if (desc.pg_error < 0) {
+				nfs_free_request(req);
+				result = desc.pg_error;
+				break;
+			}
 
 			nfs_lock_request(req);
 			req->wb_index = pos >> PAGE_SHIFT;
@@ -1004,6 +1016,7 @@
 	l_ctx = nfs_get_lock_context(dreq->ctx);
 	if (IS_ERR(l_ctx)) {
 		result = PTR_ERR(l_ctx);
+		nfs_direct_req_release(dreq);
 		goto out_release;
 	}
 	dreq->l_ctx = l_ctx;
--- linux-4.4.0.orig/fs/nfs/file.c
+++ linux-4.4.0/fs/nfs/file.c
@@ -407,7 +407,7 @@
 	 */
 	if (!PageUptodate(page)) {
 		unsigned pglen = nfs_page_length(page);
-		unsigned end = offset + len;
+		unsigned end = offset + copied;
 
 		if (pglen == 0) {
 			zero_user_segments(page, 0, offset,
--- linux-4.4.0.orig/fs/nfs/filelayout/filelayout.c
+++ linux-4.4.0/fs/nfs/filelayout/filelayout.c
@@ -374,8 +374,7 @@
 		return -EAGAIN;
 	}
 
-	if (data->verf.committed == NFS_UNSTABLE)
-		pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
+	pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
 
 	return 0;
 }
@@ -883,13 +882,19 @@
 filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
 			struct nfs_page *req)
 {
-	if (!pgio->pg_lseg)
+	if (!pgio->pg_lseg) {
 		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
 					   req->wb_context,
 					   0,
 					   NFS4_MAX_UINT64,
 					   IOMODE_READ,
 					   GFP_KERNEL);
+		if (IS_ERR(pgio->pg_lseg)) {
+			pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+			pgio->pg_lseg = NULL;
+			return;
+		}
+	}
 	/* If no lseg, fall back to read through mds */
 	if (pgio->pg_lseg == NULL)
 		nfs_pageio_reset_read_mds(pgio);
@@ -902,13 +907,20 @@
 	struct nfs_commit_info cinfo;
 	int status;
 
-	if (!pgio->pg_lseg)
+	if (!pgio->pg_lseg) {
 		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
 					   req->wb_context,
 					   0,
 					   NFS4_MAX_UINT64,
 					   IOMODE_RW,
 					   GFP_NOFS);
+		if (IS_ERR(pgio->pg_lseg)) {
+			pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+			pgio->pg_lseg = NULL;
+			return;
+		}
+	}
+
 	/* If no lseg, fall back to write through mds */
 	if (pgio->pg_lseg == NULL)
 		goto out_mds;
--- linux-4.4.0.orig/fs/nfs/filelayout/filelayoutdev.c
+++ linux-4.4.0/fs/nfs/filelayout/filelayoutdev.c
@@ -283,7 +283,8 @@
 			     s->nfs_client->cl_rpcclient->cl_auth->au_flavor);
 
 out_test_devid:
-	if (filelayout_test_devid_unavailable(devid))
+	if (ret->ds_clp == NULL ||
+	    filelayout_test_devid_unavailable(devid))
 		ret = NULL;
 out:
 	return ret;
--- linux-4.4.0.orig/fs/nfs/flexfilelayout/flexfilelayout.c
+++ linux-4.4.0/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -86,7 +86,7 @@
 	if (unlikely(!p))
 		return -ENOBUFS;
 	fh->size = be32_to_cpup(p++);
-	if (fh->size > sizeof(struct nfs_fh)) {
+	if (fh->size > NFS_MAXFHSIZE) {
 		printk(KERN_ERR "NFS flexfiles: Too big fh received %d\n",
 		       fh->size);
 		return -EOVERFLOW;
@@ -145,7 +145,7 @@
 		return false;
 	for (i = 0; i < m1->fh_versions_cnt; i++) {
 		bool found_fh = false;
-		for (j = 0; j < m2->fh_versions_cnt; i++) {
+		for (j = 0; j < m2->fh_versions_cnt; j++) {
 			if (nfs_compare_fh(&m1->fh_versions[i],
 					&m2->fh_versions[j]) == 0) {
 				found_fh = true;
@@ -461,6 +461,7 @@
 			goto out_err_free;
 
 		/* fh */
+		rc = -EIO;
 		p = xdr_inline_decode(&stream, 4);
 		if (!p)
 			goto out_err_free;
@@ -785,13 +786,19 @@
 	int ds_idx;
 
 	/* Use full layout for now */
-	if (!pgio->pg_lseg)
+	if (!pgio->pg_lseg) {
 		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
 						   req->wb_context,
 						   0,
 						   NFS4_MAX_UINT64,
 						   IOMODE_READ,
 						   GFP_KERNEL);
+		if (IS_ERR(pgio->pg_lseg)) {
+			pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+			pgio->pg_lseg = NULL;
+			return;
+		}
+	}
 	/* If no lseg, fall back to read through mds */
 	if (pgio->pg_lseg == NULL)
 		goto out_mds;
@@ -825,13 +832,19 @@
 	int i;
 	int status;
 
-	if (!pgio->pg_lseg)
+	if (!pgio->pg_lseg) {
 		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
 						   req->wb_context,
 						   0,
 						   NFS4_MAX_UINT64,
 						   IOMODE_RW,
 						   GFP_NOFS);
+		if (IS_ERR(pgio->pg_lseg)) {
+			pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+			pgio->pg_lseg = NULL;
+			return;
+		}
+	}
 	/* If no lseg, fall back to write through mds */
 	if (pgio->pg_lseg == NULL)
 		goto out_mds;
@@ -842,9 +855,8 @@
 		goto out_mds;
 
 	/* Use a direct mapping of ds_idx to pgio mirror_idx */
-	if (WARN_ON_ONCE(pgio->pg_mirror_count !=
-	    FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg)))
-		goto out_mds;
+	if (pgio->pg_mirror_count != FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg))
+		goto out_eagain;
 
 	for (i = 0; i < pgio->pg_mirror_count; i++) {
 		ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true);
@@ -856,29 +868,40 @@
 	}
 
 	return;
-
+out_eagain:
+	pnfs_generic_pg_cleanup(pgio);
+	pgio->pg_error = -EAGAIN;
+	return;
 out_mds:
 	pnfs_put_lseg(pgio->pg_lseg);
 	pgio->pg_lseg = NULL;
 	nfs_pageio_reset_write_mds(pgio);
+	pgio->pg_error = -EAGAIN;
 }
 
 static unsigned int
 ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
 				    struct nfs_page *req)
 {
-	if (!pgio->pg_lseg)
+	if (!pgio->pg_lseg) {
 		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
 						   req->wb_context,
 						   0,
 						   NFS4_MAX_UINT64,
 						   IOMODE_RW,
 						   GFP_NOFS);
+		if (IS_ERR(pgio->pg_lseg)) {
+			pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+			pgio->pg_lseg = NULL;
+			goto out;
+		}
+	}
 	if (pgio->pg_lseg)
 		return FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg);
 
 	/* no lseg means that pnfs is not in use, so no mirroring here */
 	nfs_pageio_reset_write_mds(pgio);
+out:
 	return 1;
 }
 
@@ -1414,8 +1437,7 @@
 		return -EAGAIN;
 	}
 
-	if (data->verf.committed == NFS_UNSTABLE
-	    && ff_layout_need_layoutcommit(data->lseg))
+	if (ff_layout_need_layoutcommit(data->lseg))
 		pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
 
 	return 0;
@@ -1859,11 +1881,9 @@
 	start = xdr_reserve_space(xdr, 4);
 	BUG_ON(!start);
 
-	if (ff_layout_encode_ioerr(flo, xdr, args))
-		goto out;
-
+	ff_layout_encode_ioerr(flo, xdr, args);
 	ff_layout_encode_iostats(flo, xdr, args);
-out:
+
 	*start = cpu_to_be32((xdr->p - start - 1) * 4);
 	dprintk("%s: Return\n", __func__);
 }
--- linux-4.4.0.orig/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+++ linux-4.4.0/fs/nfs/flexfilelayout/flexfilelayoutdev.c
@@ -30,6 +30,7 @@
 {
 	nfs4_print_deviceid(&mirror_ds->id_node.deviceid);
 	nfs4_pnfs_ds_put(mirror_ds->ds);
+	kfree(mirror_ds->ds_versions);
 	kfree_rcu(mirror_ds, id_node.rcu);
 }
 
--- linux-4.4.0.orig/fs/nfs/inode.c
+++ linux-4.4.0/fs/nfs/inode.c
@@ -927,7 +927,7 @@
 {
 	struct nfs_open_context *ctx;
 
-	ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
+	ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 	nfs_file_set_open_context(filp, ctx);
@@ -935,6 +935,7 @@
 	nfs_fscache_open_file(inode, filp);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(nfs_open);
 
 /*
  * This function is called whenever some part of NFS notices that
@@ -1241,9 +1242,9 @@
 		return 0;
 	/* Has the inode gone and changed behind our back? */
 	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
-		return -EIO;
+		return -ESTALE;
 	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
-		return -EIO;
+		return -ESTALE;
 
 	if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
 			inode->i_version != fattr->change_attr)
@@ -1304,6 +1305,7 @@
 	fattr->gencount = nfs_inc_attr_generation_counter();
 	fattr->owner_name = NULL;
 	fattr->group_name = NULL;
+	fattr->mdsthreshold = NULL;
 }
 EXPORT_SYMBOL_GPL(nfs_fattr_init);
 
@@ -1641,6 +1643,7 @@
 	unsigned long invalid = 0;
 	unsigned long now = jiffies;
 	unsigned long save_cache_validity;
+	bool cache_revalidated = true;
 
 	dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
 			__func__, inode->i_sb->s_id, inode->i_ino,
@@ -1702,22 +1705,28 @@
 				nfs_force_lookup_revalidate(inode);
 			inode->i_version = fattr->change_attr;
 		}
-	} else
+	} else {
 		nfsi->cache_validity |= save_cache_validity;
+		cache_revalidated = false;
+	}
 
 	if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
 		memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
-	} else if (server->caps & NFS_CAP_MTIME)
+	} else if (server->caps & NFS_CAP_MTIME) {
 		nfsi->cache_validity |= save_cache_validity &
 				(NFS_INO_INVALID_ATTR
 				| NFS_INO_REVAL_FORCED);
+		cache_revalidated = false;
+	}
 
 	if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
 		memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-	} else if (server->caps & NFS_CAP_CTIME)
+	} else if (server->caps & NFS_CAP_CTIME) {
 		nfsi->cache_validity |= save_cache_validity &
 				(NFS_INO_INVALID_ATTR
 				| NFS_INO_REVAL_FORCED);
+		cache_revalidated = false;
+	}
 
 	/* Check if our cached file size is stale */
 	if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
@@ -1737,19 +1746,23 @@
 					(long long)cur_isize,
 					(long long)new_isize);
 		}
-	} else
+	} else {
 		nfsi->cache_validity |= save_cache_validity &
 				(NFS_INO_INVALID_ATTR
 				| NFS_INO_REVAL_PAGECACHE
 				| NFS_INO_REVAL_FORCED);
+		cache_revalidated = false;
+	}
 
 
 	if (fattr->valid & NFS_ATTR_FATTR_ATIME)
 		memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
-	else if (server->caps & NFS_CAP_ATIME)
+	else if (server->caps & NFS_CAP_ATIME) {
 		nfsi->cache_validity |= save_cache_validity &
 				(NFS_INO_INVALID_ATIME
 				| NFS_INO_REVAL_FORCED);
+		cache_revalidated = false;
+	}
 
 	if (fattr->valid & NFS_ATTR_FATTR_MODE) {
 		if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
@@ -1758,36 +1771,42 @@
 			inode->i_mode = newmode;
 			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
 		}
-	} else if (server->caps & NFS_CAP_MODE)
+	} else if (server->caps & NFS_CAP_MODE) {
 		nfsi->cache_validity |= save_cache_validity &
 				(NFS_INO_INVALID_ATTR
 				| NFS_INO_INVALID_ACCESS
 				| NFS_INO_INVALID_ACL
 				| NFS_INO_REVAL_FORCED);
+		cache_revalidated = false;
+	}
 
 	if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
 		if (!uid_eq(inode->i_uid, fattr->uid)) {
 			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
 			inode->i_uid = fattr->uid;
 		}
-	} else if (server->caps & NFS_CAP_OWNER)
+	} else if (server->caps & NFS_CAP_OWNER) {
 		nfsi->cache_validity |= save_cache_validity &
 				(NFS_INO_INVALID_ATTR
 				| NFS_INO_INVALID_ACCESS
 				| NFS_INO_INVALID_ACL
 				| NFS_INO_REVAL_FORCED);
+		cache_revalidated = false;
+	}
 
 	if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
 		if (!gid_eq(inode->i_gid, fattr->gid)) {
 			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
 			inode->i_gid = fattr->gid;
 		}
-	} else if (server->caps & NFS_CAP_OWNER_GROUP)
+	} else if (server->caps & NFS_CAP_OWNER_GROUP) {
 		nfsi->cache_validity |= save_cache_validity &
 				(NFS_INO_INVALID_ATTR
 				| NFS_INO_INVALID_ACCESS
 				| NFS_INO_INVALID_ACL
 				| NFS_INO_REVAL_FORCED);
+		cache_revalidated = false;
+	}
 
 	if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
 		if (inode->i_nlink != fattr->nlink) {
@@ -1796,19 +1815,22 @@
 				invalid |= NFS_INO_INVALID_DATA;
 			set_nlink(inode, fattr->nlink);
 		}
-	} else if (server->caps & NFS_CAP_NLINK)
+	} else if (server->caps & NFS_CAP_NLINK) {
 		nfsi->cache_validity |= save_cache_validity &
 				(NFS_INO_INVALID_ATTR
 				| NFS_INO_REVAL_FORCED);
+		cache_revalidated = false;
+	}
 
 	if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
 		/*
 		 * report the blocks in 512byte units
 		 */
 		inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
- 	}
-	if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
+	} else if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
 		inode->i_blocks = fattr->du.nfs2.blocks;
+	else
+		cache_revalidated = false;
 
 	/* Update attrtimeo value if we're out of the unstable period */
 	if (invalid & NFS_INO_INVALID_ATTR) {
@@ -1818,9 +1840,13 @@
 		/* Set barrier to be more recent than all outstanding updates */
 		nfsi->attr_gencount = nfs_inc_attr_generation_counter();
 	} else {
-		if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
-			if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
-				nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
+		if (cache_revalidated) {
+			if (!time_in_range_open(now, nfsi->attrtimeo_timestamp,
+				nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
+				nfsi->attrtimeo <<= 1;
+				if (nfsi->attrtimeo > NFS_MAXATTRTIMEO(inode))
+					nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
+			}
 			nfsi->attrtimeo_timestamp = now;
 		}
 		/* Set the barrier to be more recent than this fattr */
@@ -1829,7 +1855,7 @@
 	}
 
 	/* Don't declare attrcache up to date if there were no attrs! */
-	if (fattr->valid != 0)
+	if (cache_revalidated)
 		invalid &= ~NFS_INO_INVALID_ATTR;
 
 	/* Don't invalidate the data if we were to blame */
@@ -1939,7 +1965,7 @@
 {
 	struct workqueue_struct *wq;
 	dprintk("RPC:       creating workqueue nfsiod\n");
-	wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM, 0);
+	wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
 	if (wq == NULL)
 		return -ENOMEM;
 	nfsiod_workqueue = wq;
--- linux-4.4.0.orig/fs/nfs/internal.h
+++ linux-4.4.0/fs/nfs/internal.h
@@ -243,7 +243,6 @@
 extern const struct nfs_pageio_ops nfs_pgio_rw_ops;
 struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *);
 void nfs_pgio_header_free(struct nfs_pgio_header *);
-void nfs_pgio_data_destroy(struct nfs_pgio_header *);
 int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *);
 int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
 		      struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops,
@@ -535,12 +534,14 @@
 
 static inline struct inode *nfs_igrab_and_active(struct inode *inode)
 {
-	inode = igrab(inode);
-	if (inode != NULL && !nfs_sb_active(inode->i_sb)) {
-		iput(inode);
-		inode = NULL;
+	struct super_block *sb = inode->i_sb;
+
+	if (sb && nfs_sb_active(sb)) {
+		if (igrab(inode))
+			return inode;
+		nfs_sb_deactive(sb);
 	}
-	return inode;
+	return NULL;
 }
 
 static inline void nfs_iput_and_deactive(struct inode *inode)
--- linux-4.4.0.orig/fs/nfs/namespace.c
+++ linux-4.4.0/fs/nfs/namespace.c
@@ -30,9 +30,9 @@
 /*
  * nfs_path - reconstruct the path given an arbitrary dentry
  * @base - used to return pointer to the end of devname part of path
- * @dentry - pointer to dentry
+ * @dentry_in - pointer to dentry
  * @buffer - result buffer
- * @buflen - length of buffer
+ * @buflen_in - length of buffer
  * @flags - options (see below)
  *
  * Helper function for constructing the server pathname
@@ -47,15 +47,19 @@
  *		       the original device (export) name
  *		       (if unset, the original name is returned verbatim)
  */
-char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen,
-	       unsigned flags)
+char *nfs_path(char **p, struct dentry *dentry_in, char *buffer,
+	       ssize_t buflen_in, unsigned flags)
 {
 	char *end;
 	int namelen;
 	unsigned seq;
 	const char *base;
+	struct dentry *dentry;
+	ssize_t buflen;
 
 rename_retry:
+	buflen = buflen_in;
+	dentry = dentry_in;
 	end = buffer+buflen;
 	*--end = '\0';
 	buflen--;
@@ -226,7 +230,7 @@
 					   const char *devname,
 					   struct nfs_clone_mount *mountdata)
 {
-	return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
+	return vfs_submount(mountdata->dentry, &nfs_xdev_fs_type, devname, mountdata);
 }
 
 /**
--- linux-4.4.0.orig/fs/nfs/nfs3acl.c
+++ linux-4.4.0/fs/nfs/nfs3acl.c
@@ -213,37 +213,45 @@
 
 int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
-	struct posix_acl *alloc = NULL, *dfacl = NULL;
+	struct posix_acl *orig = acl, *dfacl = NULL, *alloc;
 	int status;
 
 	if (S_ISDIR(inode->i_mode)) {
 		switch(type) {
 		case ACL_TYPE_ACCESS:
-			alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT);
+			alloc = get_acl(inode, ACL_TYPE_DEFAULT);
 			if (IS_ERR(alloc))
 				goto fail;
+			dfacl = alloc;
 			break;
 
 		case ACL_TYPE_DEFAULT:
-			dfacl = acl;
-			alloc = acl = get_acl(inode, ACL_TYPE_ACCESS);
+			alloc = get_acl(inode, ACL_TYPE_ACCESS);
 			if (IS_ERR(alloc))
 				goto fail;
+			dfacl = acl;
+			acl = alloc;
 			break;
 		}
 	}
 
 	if (acl == NULL) {
-		alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
+		alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
 		if (IS_ERR(alloc))
 			goto fail;
+		acl = alloc;
 	}
 	status = __nfs3_proc_setacls(inode, acl, dfacl);
-	posix_acl_release(alloc);
+out:
+	if (acl != orig)
+		posix_acl_release(acl);
+	if (dfacl != orig)
+		posix_acl_release(dfacl);
 	return status;
 
 fail:
-	return PTR_ERR(alloc);
+	status = PTR_ERR(alloc);
+	goto out;
 }
 
 const struct xattr_handler *nfs3_xattr_handlers[] = {
--- linux-4.4.0.orig/fs/nfs/nfs3proc.c
+++ linux-4.4.0/fs/nfs/nfs3proc.c
@@ -363,7 +363,7 @@
 				break;
 
 			case NFS3_CREATE_UNCHECKED:
-				goto out;
+				goto out_release_acls;
 		}
 		nfs_fattr_init(data->res.dir_attr);
 		nfs_fattr_init(data->res.fattr);
@@ -708,7 +708,7 @@
 		break;
 	default:
 		status = -EINVAL;
-		goto out;
+		goto out_release_acls;
 	}
 
 	status = nfs3_do_create(dir, dentry, data);
--- linux-4.4.0.orig/fs/nfs/nfs42proc.c
+++ linux-4.4.0/fs/nfs/nfs42proc.c
@@ -269,6 +269,7 @@
 	task = rpc_run_task(&task_setup);
 	if (IS_ERR(task))
 		return PTR_ERR(task);
+	rpc_put_task(task);
 	return 0;
 }
 
--- linux-4.4.0.orig/fs/nfs/nfs4_fs.h
+++ linux-4.4.0/fs/nfs/nfs4_fs.h
@@ -416,7 +416,8 @@
 
 extern struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *, gfp_t);
 extern void nfs4_put_state_owner(struct nfs4_state_owner *);
-extern void nfs4_purge_state_owners(struct nfs_server *);
+extern void nfs4_purge_state_owners(struct nfs_server *, struct list_head *);
+extern void nfs4_free_state_owners(struct list_head *head);
 extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
 extern void nfs4_put_open_state(struct nfs4_state *);
 extern void nfs4_close_state(struct nfs4_state *, fmode_t);
--- linux-4.4.0.orig/fs/nfs/nfs4client.c
+++ linux-4.4.0/fs/nfs/nfs4client.c
@@ -685,9 +685,12 @@
 
 static void nfs4_destroy_server(struct nfs_server *server)
 {
+	LIST_HEAD(freeme);
+
 	nfs_server_return_all_delegations(server);
 	unset_pnfs_layoutdriver(server);
-	nfs4_purge_state_owners(server);
+	nfs4_purge_state_owners(server, &freeme);
+	nfs4_free_state_owners(&freeme);
 }
 
 /*
@@ -748,7 +751,7 @@
 
 	spin_lock(&nn->nfs_client_lock);
 	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
-		if (nfs4_cb_match_client(addr, clp, minorversion) == false)
+		if (!nfs4_cb_match_client(addr, clp, minorversion))
 			continue;
 
 		if (!nfs4_has_session(clp))
@@ -879,10 +882,10 @@
 
 /*
  * Session has been established, and the client marked ready.
- * Set the mount rsize and wsize with negotiated fore channel
- * attributes which will be bound checked in nfs_server_set_fsinfo.
+ * Limit the mount rsize, wsize and dtsize using negotiated fore
+ * channel attributes.
  */
-static void nfs4_session_set_rwsize(struct nfs_server *server)
+static void nfs4_session_limit_rwsize(struct nfs_server *server)
 {
 #ifdef CONFIG_NFS_V4_1
 	struct nfs4_session *sess;
@@ -895,6 +898,8 @@
 	server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
 	server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
 
+	if (server->dtsize > server_resp_sz)
+		server->dtsize = server_resp_sz;
 	if (server->rsize > server_resp_sz)
 		server->rsize = server_resp_sz;
 	if (server->wsize > server_rqst_sz)
@@ -944,12 +949,12 @@
 			(unsigned long long) server->fsid.minor);
 	nfs_display_fhandle(mntfh, "Pseudo-fs root FH");
 
-	nfs4_session_set_rwsize(server);
-
 	error = nfs_probe_fsinfo(server, mntfh, fattr);
 	if (error < 0)
 		goto out;
 
+	nfs4_session_limit_rwsize(server);
+
 	if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
 		server->namelen = NFS4_MAXNAMLEN;
 
--- linux-4.4.0.orig/fs/nfs/nfs4file.c
+++ linux-4.4.0/fs/nfs/nfs4file.c
@@ -26,7 +26,7 @@
 nfs4_file_open(struct inode *inode, struct file *filp)
 {
 	struct nfs_open_context *ctx;
-	struct dentry *dentry = filp->f_path.dentry;
+	struct dentry *dentry = file_dentry(filp);
 	struct dentry *parent = NULL;
 	struct inode *dir;
 	unsigned openflags = filp->f_flags;
@@ -49,7 +49,7 @@
 		return err;
 
 	if ((openflags & O_ACCMODE) == 3)
-		openflags--;
+		return nfs_open(inode, filp);
 
 	/* We can't create new files here */
 	openflags &= ~(O_CREAT|O_EXCL);
@@ -57,7 +57,7 @@
 	parent = dget_parent(dentry);
 	dir = d_inode(parent);
 
-	ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
+	ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode);
 	err = PTR_ERR(ctx);
 	if (IS_ERR(ctx))
 		goto out;
@@ -73,13 +73,13 @@
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
 		switch (err) {
-		case -EPERM:
-		case -EACCES:
-		case -EDQUOT:
-		case -ENOSPC:
-		case -EROFS:
-			goto out_put_ctx;
 		default:
+			goto out_put_ctx;
+		case -ENOENT:
+		case -ESTALE:
+		case -EISDIR:
+		case -ENOTDIR:
+		case -ELOOP:
 			goto out_drop;
 		}
 	}
--- linux-4.4.0.orig/fs/nfs/nfs4idmap.c
+++ linux-4.4.0/fs/nfs/nfs4idmap.c
@@ -343,7 +343,7 @@
 	int id_len;
 	ssize_t ret;
 
-	id_len = snprintf(id_str, sizeof(id_str), "%u", id);
+	id_len = nfs_map_numeric_to_string(id, id_str, sizeof(id_str));
 	ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap);
 	if (ret < 0)
 		return -EINVAL;
@@ -567,9 +567,13 @@
 	struct idmap_msg *im;
 	struct idmap *idmap = (struct idmap *)aux;
 	struct key *key = cons->key;
-	int ret = -ENOMEM;
+	int ret = -ENOKEY;
+
+	if (!aux)
+		goto out1;
 
 	/* msg and im are freed in idmap_pipe_destroy_msg */
+	ret = -ENOMEM;
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		goto out1;
@@ -622,7 +626,8 @@
 		if (strcmp(upcall->im_name, im->im_name) != 0)
 			break;
 		/* Note: here we store the NUL terminator too */
-		len = sprintf(id_str, "%d", im->im_id) + 1;
+		len = 1 + nfs_map_numeric_to_string(im->im_id, id_str,
+						    sizeof(id_str));
 		ret = nfs_idmap_instantiate(key, authkey, id_str, len);
 		break;
 	case IDMAP_CONV_IDTONAME:
--- linux-4.4.0.orig/fs/nfs/nfs4namespace.c
+++ linux-4.4.0/fs/nfs/nfs4namespace.c
@@ -279,7 +279,7 @@
 				mountdata->hostname,
 				mountdata->mnt_path);
 
-		mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, mountdata);
+		mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata);
 		if (!IS_ERR(mnt))
 			break;
 	}
--- linux-4.4.0.orig/fs/nfs/nfs4proc.c
+++ linux-4.4.0/fs/nfs/nfs4proc.c
@@ -38,7 +38,6 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
-#include <linux/file.h>
 #include <linux/string.h>
 #include <linux/ratelimit.h>
 #include <linux/printk.h>
@@ -242,15 +241,12 @@
 };
 
 const u32 nfs4_fs_locations_bitmap[3] = {
-	FATTR4_WORD0_TYPE
-	| FATTR4_WORD0_CHANGE
+	FATTR4_WORD0_CHANGE
 	| FATTR4_WORD0_SIZE
 	| FATTR4_WORD0_FSID
 	| FATTR4_WORD0_FILEID
 	| FATTR4_WORD0_FS_LOCATIONS,
-	FATTR4_WORD1_MODE
-	| FATTR4_WORD1_NUMLINKS
-	| FATTR4_WORD1_OWNER
+	FATTR4_WORD1_OWNER
 	| FATTR4_WORD1_OWNER_GROUP
 	| FATTR4_WORD1_RAWDEV
 	| FATTR4_WORD1_SPACE_USED
@@ -1001,6 +997,12 @@
 	int cancelled;
 };
 
+struct nfs4_open_createattrs {
+	struct nfs4_label *label;
+	struct iattr *sattr;
+	const __u32 verf[2];
+};
+
 static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
 		int err, struct nfs4_exception *exception)
 {
@@ -1070,8 +1072,7 @@
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 		struct nfs4_state_owner *sp, fmode_t fmode, int flags,
-		const struct iattr *attrs,
-		struct nfs4_label *label,
+		const struct nfs4_open_createattrs *c,
 		enum open_claim_type4 claim,
 		gfp_t gfp_mask)
 {
@@ -1079,6 +1080,7 @@
 	struct inode *dir = d_inode(parent);
 	struct nfs_server *server = NFS_SERVER(dir);
 	struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
+	struct nfs4_label *label = (c != NULL) ? c->label : NULL;
 	struct nfs4_opendata *p;
 
 	p = kzalloc(sizeof(*p), gfp_mask);
@@ -1135,15 +1137,11 @@
 	case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
 		p->o_arg.fh = NFS_FH(d_inode(dentry));
 	}
-	if (attrs != NULL && attrs->ia_valid != 0) {
-		__u32 verf[2];
-
+	if (c != NULL && c->sattr != NULL && c->sattr->ia_valid != 0) {
 		p->o_arg.u.attrs = &p->attrs;
-		memcpy(&p->attrs, attrs, sizeof(p->attrs));
+		memcpy(&p->attrs, c->sattr, sizeof(p->attrs));
 
-		verf[0] = jiffies;
-		verf[1] = current->pid;
-		memcpy(p->o_arg.u.verifier.data, verf,
+		memcpy(p->o_arg.u.verifier.data, c->verf,
 				sizeof(p->o_arg.u.verifier.data));
 	}
 	p->c_arg.fh = &p->o_res.fh;
@@ -1245,8 +1243,6 @@
 		return 0;
 	if ((delegation->type & fmode) != fmode)
 		return 0;
-	if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
-		return 0;
 	switch (claim) {
 	case NFS4_OPEN_CLAIM_NULL:
 	case NFS4_OPEN_CLAIM_FH:
@@ -1385,6 +1381,7 @@
 	 * Protect the call to nfs4_state_set_mode_locked and
 	 * serialise the stateid update
 	 */
+	spin_lock(&state->owner->so_lock);
 	write_seqlock(&state->seqlock);
 	if (deleg_stateid != NULL) {
 		nfs4_stateid_copy(&state->stateid, deleg_stateid);
@@ -1393,7 +1390,6 @@
 	if (open_stateid != NULL)
 		nfs_set_open_stateid_locked(state, open_stateid, fmode);
 	write_sequnlock(&state->seqlock);
-	spin_lock(&state->owner->so_lock);
 	update_open_stateflags(state, fmode);
 	spin_unlock(&state->owner->so_lock);
 }
@@ -1475,7 +1471,6 @@
 static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
 {
 	struct nfs4_state *state = opendata->state;
-	struct nfs_inode *nfsi = NFS_I(state->inode);
 	struct nfs_delegation *delegation;
 	int open_mode = opendata->o_arg.open_flags;
 	fmode_t fmode = opendata->o_arg.fmode;
@@ -1492,7 +1487,7 @@
 		}
 		spin_unlock(&state->owner->so_lock);
 		rcu_read_lock();
-		delegation = rcu_dereference(nfsi->delegation);
+		delegation = nfs4_get_valid_delegation(state->inode);
 		if (!can_open_delegated(delegation, fmode, claim)) {
 			rcu_read_unlock();
 			break;
@@ -1657,7 +1652,7 @@
 	struct nfs4_opendata *opendata;
 
 	opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0,
-			NULL, NULL, claim, GFP_NOFS);
+			NULL, claim, GFP_NOFS);
 	if (opendata == NULL)
 		return ERR_PTR(-ENOMEM);
 	opendata->state = state;
@@ -1784,7 +1779,7 @@
 	return ret;
 }
 
-static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, int err)
+static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, struct file_lock *fl, int err)
 {
 	switch (err) {
 		default:
@@ -1831,7 +1826,11 @@
 			return -EAGAIN;
 		case -ENOMEM:
 		case -NFS4ERR_DENIED:
-			/* kill_proc(fl->fl_pid, SIGLOST, 1); */
+			if (fl) {
+				struct nfs4_lock_state *lsp = fl->fl_u.nfs4_fl.owner;
+				if (lsp)
+					set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
+			}
 			return 0;
 	}
 	return err;
@@ -1867,7 +1866,7 @@
 		err = nfs4_open_recover_helper(opendata, FMODE_READ);
 	}
 	nfs4_opendata_put(opendata);
-	return nfs4_handle_delegation_recall_error(server, state, stateid, err);
+	return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err);
 }
 
 static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
@@ -1979,7 +1978,7 @@
 		if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags))
 			goto out_no_action;
 		rcu_read_lock();
-		delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
+		delegation = nfs4_get_valid_delegation(data->state->inode);
 		if (can_open_delegated(delegation, data->o_arg.fmode, claim))
 			goto unlock_no_action;
 		rcu_read_unlock();
@@ -2058,12 +2057,14 @@
 	struct nfs4_opendata *data = calldata;
 	struct nfs4_state *state = NULL;
 
+	/* In case of error, no cleanup! */
+	if (data->rpc_status != 0 || !data->rpc_done) {
+		nfs_release_seqid(data->o_arg.seqid);
+		goto out_free;
+	}
 	/* If this request hasn't been cancelled, do nothing */
 	if (data->cancelled == 0)
 		goto out_free;
-	/* In case of error, no cleanup! */
-	if (data->rpc_status != 0 || !data->rpc_done)
-		goto out_free;
 	/* In case we need an open_confirm, no cleanup! */
 	if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)
 		goto out_free;
@@ -2188,8 +2189,6 @@
 	if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0)
 		return 0;
 
-	/* even though OPEN succeeded, access is denied. Close the file */
-	nfs4_close_state(state, fmode);
 	return -EACCES;
 }
 
@@ -2422,7 +2421,8 @@
 		sattr->ia_valid |= ATTR_MTIME;
 
 	/* Except MODE, it seems harmless of setting twice. */
-	if ((attrset[1] & FATTR4_WORD1_MODE))
+	if (opendata->o_arg.createmode != NFS4_CREATE_EXCLUSIVE &&
+		attrset[1] & FATTR4_WORD1_MODE)
 		sattr->ia_valid &= ~ATTR_MODE;
 
 	if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL)
@@ -2451,6 +2451,7 @@
 	ret = PTR_ERR(state);
 	if (IS_ERR(state))
 		goto out;
+	ctx->state = state;
 	if (server->caps & NFS_CAP_POSIX_LOCK)
 		set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
 
@@ -2461,9 +2462,9 @@
 		dentry = d_add_unique(dentry, igrab(state->inode));
 		if (dentry == NULL) {
 			dentry = opendata->dentry;
-		} else if (dentry != ctx->dentry) {
+		} else {
 			dput(ctx->dentry);
-			ctx->dentry = dget(dentry);
+			ctx->dentry = dentry;
 		}
 		nfs_set_verifier(dentry,
 				nfs_save_change_attribute(d_inode(opendata->dir)));
@@ -2473,7 +2474,6 @@
 	if (ret != 0)
 		goto out;
 
-	ctx->state = state;
 	if (d_inode(dentry) == state->inode) {
 		nfs_inode_attach_open_context(ctx);
 		if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
@@ -2489,8 +2489,7 @@
 static int _nfs4_do_open(struct inode *dir,
 			struct nfs_open_context *ctx,
 			int flags,
-			struct iattr *sattr,
-			struct nfs4_label *label,
+			const struct nfs4_open_createattrs *c,
 			int *opened)
 {
 	struct nfs4_state_owner  *sp;
@@ -2502,6 +2501,8 @@
 	struct nfs4_threshold **ctx_th = &ctx->mdsthreshold;
 	fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
 	enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
+	struct iattr *sattr = c->sattr;
+	struct nfs4_label *label = c->label;
 	struct nfs4_label *olabel = NULL;
 	int status;
 
@@ -2520,8 +2521,8 @@
 	status = -ENOMEM;
 	if (d_really_is_positive(dentry))
 		claim = NFS4_OPEN_CLAIM_FH;
-	opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr,
-			label, claim, GFP_KERNEL);
+	opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags,
+			c, claim, GFP_KERNEL);
 	if (opendata == NULL)
 		goto err_put_state_owner;
 
@@ -2597,10 +2598,18 @@
 	struct nfs_server *server = NFS_SERVER(dir);
 	struct nfs4_exception exception = { };
 	struct nfs4_state *res;
+	struct nfs4_open_createattrs c = {
+		.label = label,
+		.sattr = sattr,
+		.verf = {
+			[0] = (__u32)jiffies,
+			[1] = (__u32)current->pid,
+		},
+	};
 	int status;
 
 	do {
-		status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened);
+		status = _nfs4_do_open(dir, ctx, flags, &c, opened);
 		res = ctx->state;
 		trace_nfs4_open_file(ctx, flags, status);
 		if (status == 0)
@@ -2854,12 +2863,11 @@
 			call_close |= is_wronly;
 		else if (is_wronly)
 			calldata->arg.fmode |= FMODE_WRITE;
+		if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE))
+			call_close |= is_rdwr;
 	} else if (is_rdwr)
 		calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
 
-	if (calldata->arg.fmode == 0)
-		call_close |= is_rdwr;
-
 	if (!nfs4_valid_open_stateid(state))
 		call_close = 0;
 	spin_unlock(&state->owner->so_lock);
@@ -3031,6 +3039,7 @@
 		.rpc_resp = &res,
 	};
 	int status;
+	int i;
 
 	bitmask[0] = FATTR4_WORD0_SUPPORTED_ATTRS |
 		     FATTR4_WORD0_FH_EXPIRE_TYPE |
@@ -3096,8 +3105,13 @@
 		server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
 		server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
 		server->cache_consistency_bitmask[2] = 0;
+
+		/* Avoid a regression due to buggy server */
+		for (i = 0; i < ARRAY_SIZE(res.exclcreat_bitmask); i++)
+			res.exclcreat_bitmask[i] &= res.attr_bitmask[i];
 		memcpy(server->exclcreat_bitmask, res.exclcreat_bitmask,
 			sizeof(server->exclcreat_bitmask));
+
 		server->acl_bitmask = res.acl_bitmask;
 		server->fh_expire_type = res.fh_expire_type;
 	}
@@ -4035,12 +4049,12 @@
 		u64 cookie, struct page **pages, unsigned int count, int plus)
 {
 	struct inode		*dir = d_inode(dentry);
+	struct nfs_server	*server = NFS_SERVER(dir);
 	struct nfs4_readdir_arg args = {
 		.fh = NFS_FH(dir),
 		.pages = pages,
 		.pgbase = 0,
 		.count = count,
-		.bitmask = NFS_SERVER(d_inode(dentry))->attr_bitmask,
 		.plus = plus,
 	};
 	struct nfs4_readdir_res res;
@@ -4055,9 +4069,15 @@
 	dprintk("%s: dentry = %pd2, cookie = %Lu\n", __func__,
 			dentry,
 			(unsigned long long)cookie);
+	if (!(server->caps & NFS_CAP_SECURITY_LABEL))
+		args.bitmask = server->attr_bitmask_nl;
+	else
+		args.bitmask = server->attr_bitmask;
+
 	nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);
 	res.pgbase = args.pgbase;
-	status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
+	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
+			&res.seq_res, 0);
 	if (status >= 0) {
 		memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);
 		status += args.pgbase;
@@ -4711,7 +4731,7 @@
  */
 static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
 {
-	struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
+	struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, };
 	struct nfs_getaclargs args = {
 		.fh = NFS_FH(inode),
 		.acl_pages = pages,
@@ -4725,13 +4745,9 @@
 		.rpc_argp = &args,
 		.rpc_resp = &res,
 	};
-	unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
+	unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
 	int ret = -ENOMEM, i;
 
-	/* As long as we're doing a round trip to the server anyway,
-	 * let's be prepared for a page of acl data. */
-	if (npages == 0)
-		npages = 1;
 	if (npages > ARRAY_SIZE(pages))
 		return -ERANGE;
 
@@ -4908,9 +4924,7 @@
 		return ret;
 	if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
 		return -ENOENT;
-	if (buflen < label.len)
-		return -ERANGE;
-	return 0;
+	return label.len;
 }
 
 static int nfs4_get_security_label(struct inode *inode, void *buf,
@@ -5244,6 +5258,7 @@
 	}
 	status = task->tk_status;
 	if (setclientid.sc_cred) {
+		kfree(clp->cl_acceptor);
 		clp->cl_acceptor = rpcauth_stringify_acceptor(setclientid.sc_cred);
 		put_rpccred(setclientid.sc_cred);
 	}
@@ -5747,7 +5762,6 @@
 	p->server = server;
 	atomic_inc(&lsp->ls_count);
 	p->ctx = get_nfs_open_context(ctx);
-	get_file(fl->fl_file);
 	memcpy(&p->fl, fl, sizeof(p->fl));
 	return p;
 out_free_seqid:
@@ -5860,7 +5874,6 @@
 		nfs_free_seqid(data->arg.lock_seqid);
 	nfs4_put_lock_state(data->lsp);
 	put_nfs_open_context(data->ctx);
-	fput(data->fl.fl_file);
 	kfree(data);
 	dprintk("%s: done!\n", __func__);
 }
@@ -6047,6 +6060,7 @@
 static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
 	struct nfs_inode *nfsi = NFS_I(state->inode);
+	struct nfs4_state_owner *sp = state->owner;
 	unsigned char fl_flags = request->fl_flags;
 	int status = -ENOLCK;
 
@@ -6061,6 +6075,7 @@
 	status = do_vfs_lock(state->inode, request);
 	if (status < 0)
 		goto out;
+	mutex_lock(&sp->so_delegreturn_mutex);
 	down_read(&nfsi->rwsem);
 	if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
 		/* Yes: cache locks! */
@@ -6068,9 +6083,11 @@
 		request->fl_flags = fl_flags & ~FL_SLEEP;
 		status = do_vfs_lock(state->inode, request);
 		up_read(&nfsi->rwsem);
+		mutex_unlock(&sp->so_delegreturn_mutex);
 		goto out;
 	}
 	up_read(&nfsi->rwsem);
+	mutex_unlock(&sp->so_delegreturn_mutex);
 	status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
 out:
 	request->fl_flags = fl_flags;
@@ -6162,8 +6179,13 @@
 	err = nfs4_set_lock_state(state, fl);
 	if (err != 0)
 		return err;
-	err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
-	return nfs4_handle_delegation_recall_error(server, state, stateid, err);
+	do {
+		err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
+		if (err != -NFS4ERR_DELAY)
+			break;
+		ssleep(1);
+	} while (err == -NFS4ERR_DELAY);
+	return nfs4_handle_delegation_recall_error(server, state, stateid, fl, err);
 }
 
 struct nfs_release_lockowner_data {
@@ -6285,10 +6307,6 @@
 }
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
-static inline int nfs4_server_supports_labels(struct nfs_server *server)
-{
-	return server->caps & NFS_CAP_SECURITY_LABEL;
-}
 
 static int nfs4_xattr_set_nfs4_label(const struct xattr_handler *handler,
 				     struct dentry *dentry, const char *key,
@@ -6310,29 +6328,34 @@
 	return -EOPNOTSUPP;
 }
 
-static size_t nfs4_xattr_list_nfs4_label(const struct xattr_handler *handler,
-					 struct dentry *dentry, char *list,
-					 size_t list_len, const char *name,
-					 size_t name_len)
-{
-	size_t len = 0;
-
-	if (nfs_server_capable(d_inode(dentry), NFS_CAP_SECURITY_LABEL)) {
-		len = security_inode_listsecurity(d_inode(dentry), NULL, 0);
-		if (list && len <= list_len)
-			security_inode_listsecurity(d_inode(dentry), list, len);
+static ssize_t
+nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
+{
+	int len = 0;
+
+	if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
+		len = security_inode_listsecurity(inode, list, list_len);
+		if (list_len && len > list_len)
+			return -ERANGE;
 	}
 	return len;
 }
 
 static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
 	.prefix = XATTR_SECURITY_PREFIX,
-	.list	= nfs4_xattr_list_nfs4_label,
 	.get	= nfs4_xattr_get_nfs4_label,
 	.set	= nfs4_xattr_set_nfs4_label,
 };
-#endif
 
+#else
+
+static ssize_t
+nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
+{
+	return 0;
+}
+
+#endif
 
 /*
  * nfs_fhget will use either the mounted_on_fileid or the fileid
@@ -6357,9 +6380,7 @@
 				   struct page *page)
 {
 	struct nfs_server *server = NFS_SERVER(dir);
-	u32 bitmask[3] = {
-		[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
-	};
+	u32 bitmask[3];
 	struct nfs4_fs_locations_arg args = {
 		.dir_fh = NFS_FH(dir),
 		.name = name,
@@ -6378,12 +6399,15 @@
 
 	dprintk("%s: start\n", __func__);
 
+	bitmask[0] = nfs4_fattr_bitmap[0] | FATTR4_WORD0_FS_LOCATIONS;
+	bitmask[1] = nfs4_fattr_bitmap[1];
+
 	/* Ask for the fileid of the absent filesystem if mounted_on_fileid
 	 * is not supported */
 	if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
-		bitmask[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
+		bitmask[0] &= ~FATTR4_WORD0_FILEID;
 	else
-		bitmask[0] |= FATTR4_WORD0_FILEID;
+		bitmask[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
 
 	nfs_fattr_init(&fs_locations->fattr);
 	fs_locations->server = server;
@@ -7425,12 +7449,20 @@
 	status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
 	trace_nfs4_create_session(clp, status);
 
+	switch (status) {
+	case -NFS4ERR_STALE_CLIENTID:
+	case -NFS4ERR_DELAY:
+	case -ETIMEDOUT:
+	case -EACCES:
+	case -EAGAIN:
+		goto out;
+	};
+
+	clp->cl_seqid++;
 	if (!status) {
 		/* Verify the session's negotiated channel_attrs values */
 		status = nfs4_verify_channel_attrs(&args, &res);
 		/* Increment the clientid slot sequence id */
-		if (clp->cl_seqid == res.seqid)
-			clp->cl_seqid++;
 		if (status)
 			goto out;
 		nfs4_update_session(session, &res);
@@ -7673,6 +7705,12 @@
 		/* fall through */
 	case -NFS4ERR_RETRY_UNCACHED_REP:
 		return -EAGAIN;
+	case -NFS4ERR_BADSESSION:
+	case -NFS4ERR_DEADSESSION:
+	case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+		nfs4_schedule_session_recovery(clp->cl_session,
+				task->tk_status);
+		break;
 	default:
 		nfs4_schedule_lease_recovery(clp);
 	}
@@ -7751,7 +7789,6 @@
 	if (status == 0)
 		status = task->tk_status;
 	rpc_put_task(task);
-	return 0;
 out:
 	dprintk("<-- %s status=%d\n", __func__, status);
 	return status;
@@ -8054,7 +8091,6 @@
 		pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
 	pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
 	pnfs_clear_layoutreturn_waitbit(lo);
-	lo->plh_block_lgets--;
 	spin_unlock(&lo->plh_inode->i_lock);
 	pnfs_free_lseg_list(&freeme);
 	pnfs_put_layout_hdr(lrp->args.layout);
@@ -8749,6 +8785,24 @@
 #endif
 };
 
+ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+	ssize_t error, error2;
+
+	error = generic_listxattr(dentry, list, size);
+	if (error < 0)
+		return error;
+	if (list) {
+		list += error;
+		size -= error;
+	}
+
+	error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
+	if (error2 < 0)
+		return error2;
+	return error + error2;
+}
+
 static const struct inode_operations nfs4_dir_inode_operations = {
 	.create		= nfs_create,
 	.lookup		= nfs_lookup,
@@ -8765,7 +8819,7 @@
 	.setattr	= nfs_setattr,
 	.getxattr	= generic_getxattr,
 	.setxattr	= generic_setxattr,
-	.listxattr	= generic_listxattr,
+	.listxattr	= nfs4_listxattr,
 	.removexattr	= generic_removexattr,
 };
 
@@ -8775,7 +8829,7 @@
 	.setattr	= nfs_setattr,
 	.getxattr	= generic_getxattr,
 	.setxattr	= generic_setxattr,
-	.listxattr	= generic_listxattr,
+	.listxattr	= nfs4_listxattr,
 	.removexattr	= generic_removexattr,
 };
 
--- linux-4.4.0.orig/fs/nfs/nfs4state.c
+++ linux-4.4.0/fs/nfs/nfs4state.c
@@ -140,6 +140,10 @@
 		/* Sustain the lease, even if it's empty.  If the clientid4
 		 * goes stale it's of no use for trunking discovery. */
 		nfs4_schedule_state_renewal(*result);
+
+		/* If the client state need to recover, do it. */
+		if (clp->cl_state)
+			nfs4_schedule_state_manager(clp);
 	}
 out:
 	return status;
@@ -607,24 +611,39 @@
 /**
  * nfs4_purge_state_owners - Release all cached state owners
  * @server: nfs_server with cached state owners to release
+ * @head: resulting list of state owners
  *
  * Called at umount time.  Remaining state owners will be on
  * the LRU with ref count of zero.
+ * Note that the state owners are not freed, but are added
+ * to the list @head, which can later be used as an argument
+ * to nfs4_free_state_owners.
  */
-void nfs4_purge_state_owners(struct nfs_server *server)
+void nfs4_purge_state_owners(struct nfs_server *server, struct list_head *head)
 {
 	struct nfs_client *clp = server->nfs_client;
 	struct nfs4_state_owner *sp, *tmp;
-	LIST_HEAD(doomed);
 
 	spin_lock(&clp->cl_lock);
 	list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
-		list_move(&sp->so_lru, &doomed);
+		list_move(&sp->so_lru, head);
 		nfs4_remove_state_owner_locked(sp);
 	}
 	spin_unlock(&clp->cl_lock);
+}
 
-	list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
+/**
+ * nfs4_purge_state_owners - Release all cached state owners
+ * @head: resulting list of state owners
+ *
+ * Frees a list of state owners that was generated by
+ * nfs4_purge_state_owners
+ */
+void nfs4_free_state_owners(struct list_head *head)
+{
+	struct nfs4_state_owner *sp, *tmp;
+
+	list_for_each_entry_safe(sp, tmp, head, so_lru) {
 		list_del(&sp->so_lru);
 		nfs4_free_state_owner(sp);
 	}
@@ -1072,6 +1091,7 @@
 		case -NFS4ERR_BADXDR:
 		case -NFS4ERR_RESOURCE:
 		case -NFS4ERR_NOFILEHANDLE:
+		case -NFS4ERR_MOVED:
 			/* Non-seqid mutating errors */
 			return;
 	};
@@ -1385,6 +1405,7 @@
 	struct inode *inode = state->inode;
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct file_lock *fl;
+	struct nfs4_lock_state *lsp;
 	int status = 0;
 	struct file_lock_context *flctx = inode->i_flctx;
 	struct list_head *list;
@@ -1425,7 +1446,9 @@
 		case -NFS4ERR_DENIED:
 		case -NFS4ERR_RECLAIM_BAD:
 		case -NFS4ERR_RECLAIM_CONFLICT:
-			/* kill_proc(fl->fl_pid, SIGLOST, 1); */
+			lsp = fl->fl_u.nfs4_fl.owner;
+			if (lsp)
+				set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
 			status = 0;
 		}
 		spin_lock(&flctx->flc_lock);
@@ -1493,6 +1516,9 @@
 					__func__, status);
 			case -ENOENT:
 			case -ENOMEM:
+			case -EACCES:
+			case -EROFS:
+			case -EIO:
 			case -ESTALE:
 				/* Open state on this file cannot be recovered */
 				nfs4_state_mark_recovery_failed(state, status);
@@ -1589,13 +1615,14 @@
 	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
 }
 
-static void nfs4_reclaim_complete(struct nfs_client *clp,
+static int nfs4_reclaim_complete(struct nfs_client *clp,
 				 const struct nfs4_state_recovery_ops *ops,
 				 struct rpc_cred *cred)
 {
 	/* Notify the server we're done reclaiming our state */
 	if (ops->reclaim_complete)
-		(void)ops->reclaim_complete(clp, cred);
+		return ops->reclaim_complete(clp, cred);
+	return 0;
 }
 
 static void nfs4_clear_reclaim_server(struct nfs_server *server)
@@ -1642,13 +1669,16 @@
 {
 	const struct nfs4_state_recovery_ops *ops;
 	struct rpc_cred *cred;
+	int err;
 
 	if (!nfs4_state_clear_reclaim_reboot(clp))
 		return;
 	ops = clp->cl_mvops->reboot_recovery_ops;
 	cred = nfs4_get_clid_cred(clp);
-	nfs4_reclaim_complete(clp, ops, cred);
+	err = nfs4_reclaim_complete(clp, ops, cred);
 	put_rpccred(cred);
+	if (err == -NFS4ERR_CONN_NOT_BOUND_TO_SESSION)
+		set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
 }
 
 static void nfs_delegation_clear_all(struct nfs_client *clp)
@@ -1676,7 +1706,6 @@
 			break;
 		case -NFS4ERR_STALE_CLIENTID:
 			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
-			nfs4_state_clear_reclaim_reboot(clp);
 			nfs4_state_start_reclaim_reboot(clp);
 			break;
 		case -NFS4ERR_EXPIRED:
@@ -1710,12 +1739,13 @@
 	struct nfs4_state_owner *sp;
 	struct nfs_server *server;
 	struct rb_node *pos;
+	LIST_HEAD(freeme);
 	int status = 0;
 
 restart:
 	rcu_read_lock();
 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
-		nfs4_purge_state_owners(server);
+		nfs4_purge_state_owners(server, &freeme);
 		spin_lock(&clp->cl_lock);
 		for (pos = rb_first(&server->state_owners);
 		     pos != NULL;
@@ -1744,6 +1774,7 @@
 		spin_unlock(&clp->cl_lock);
 	}
 	rcu_read_unlock();
+	nfs4_free_state_owners(&freeme);
 	return 0;
 }
 
--- linux-4.4.0.orig/fs/nfs/nfs4sysctl.c
+++ linux-4.4.0/fs/nfs/nfs4sysctl.c
@@ -31,7 +31,7 @@
 		.data = &nfs_idmap_cache_timeout,
 		.maxlen = sizeof(int),
 		.mode = 0644,
-		.proc_handler = proc_dointvec_jiffies,
+		.proc_handler = proc_dointvec,
 	},
 	{ }
 };
--- linux-4.4.0.orig/fs/nfs/nfs4xdr.c
+++ linux-4.4.0/fs/nfs/nfs4xdr.c
@@ -1123,7 +1123,7 @@
 		} else
 			*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
 	}
-	if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
+	if (label && (bmval[2] & FATTR4_WORD2_SECURITY_LABEL)) {
 		*p++ = cpu_to_be32(label->lfs);
 		*p++ = cpu_to_be32(label->pi);
 		*p++ = cpu_to_be32(label->len);
@@ -2487,7 +2487,7 @@
 	encode_compound_hdr(xdr, req, &hdr);
 	encode_sequence(xdr, &args->seq_args, &hdr);
 	encode_putfh(xdr, args->fh, &hdr);
-	replen = hdr.replen + op_decode_hdr_maxsz + 1;
+	replen = hdr.replen + op_decode_hdr_maxsz;
 	encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
 
 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
@@ -4158,7 +4158,11 @@
 			goto out_overflow;
 		if (len < NFS4_MAXLABELLEN) {
 			if (label) {
-				memcpy(label->label, p, len);
+				if (label->len) {
+					if (label->len < len)
+						return -ERANGE;
+					memcpy(label->label, p, len);
+				}
 				label->len = len;
 				label->pi = pi;
 				label->lfs = lfs;
--- linux-4.4.0.orig/fs/nfs/pagelist.c
+++ linux-4.4.0/fs/nfs/pagelist.c
@@ -29,13 +29,14 @@
 static struct kmem_cache *nfs_page_cachep;
 static const struct rpc_call_ops nfs_pgio_common_ops;
 
-static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount)
+static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount,
+					gfp_t gfp_flags)
 {
 	p->npages = pagecount;
 	if (pagecount <= ARRAY_SIZE(p->page_array))
 		p->pagevec = p->page_array;
 	else {
-		p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL);
+		p->pagevec = kcalloc(pagecount, sizeof(struct page *), gfp_flags);
 		if (!p->pagevec)
 			p->npages = 0;
 	}
@@ -528,16 +529,6 @@
 }
 EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc);
 
-/*
- * nfs_pgio_header_free - Free a read or write header
- * @hdr: The header to free
- */
-void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
-{
-	hdr->rw_ops->rw_free_header(hdr);
-}
-EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
-
 /**
  * nfs_pgio_data_destroy - make @hdr suitable for reuse
  *
@@ -546,14 +537,24 @@
  *
  * @hdr: A header that has had nfs_generic_pgio called
  */
-void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr)
+static void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr)
 {
 	if (hdr->args.context)
 		put_nfs_open_context(hdr->args.context);
 	if (hdr->page_array.pagevec != hdr->page_array.page_array)
 		kfree(hdr->page_array.pagevec);
 }
-EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy);
+
+/*
+ * nfs_pgio_header_free - Free a read or write header
+ * @hdr: The header to free
+ */
+void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
+{
+	nfs_pgio_data_destroy(hdr);
+	hdr->rw_ops->rw_free_header(hdr);
+}
+EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
 
 /**
  * nfs_pgio_rpcsetup - Set up arguments for a pageio call
@@ -593,7 +594,7 @@
 	}
 
 	hdr->res.fattr   = &hdr->fattr;
-	hdr->res.count   = count;
+	hdr->res.count   = 0;
 	hdr->res.eof     = 0;
 	hdr->res.verf    = &hdr->verf;
 	nfs_fattr_init(&hdr->fattr);
@@ -671,7 +672,6 @@
 	u32 midx;
 
 	set_bit(NFS_IOHDR_REDO, &hdr->flags);
-	nfs_pgio_data_destroy(hdr);
 	hdr->completion_ops->completion(hdr);
 	/* TODO: Make sure it's right to clean up all mirrors here
 	 *       and not just hdr->pgio_mirror_idx */
@@ -689,7 +689,6 @@
 static void nfs_pgio_release(void *calldata)
 {
 	struct nfs_pgio_header *hdr = calldata;
-	nfs_pgio_data_destroy(hdr);
 	hdr->completion_ops->completion(hdr);
 }
 
@@ -724,6 +723,7 @@
 {
 	struct nfs_pgio_mirror *new;
 	int i;
+	gfp_t gfp_flags = GFP_KERNEL;
 
 	desc->pg_moreio = 0;
 	desc->pg_inode = inode;
@@ -743,8 +743,10 @@
 	if (pg_ops->pg_get_mirror_count) {
 		/* until we have a request, we don't have an lseg and no
 		 * idea how many mirrors there will be */
+		if (desc->pg_rw_ops->rw_mode == FMODE_WRITE)
+			gfp_flags = GFP_NOIO;
 		new = kcalloc(NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX,
-			      sizeof(struct nfs_pgio_mirror), GFP_KERNEL);
+			      sizeof(struct nfs_pgio_mirror), gfp_flags);
 		desc->pg_mirrors_dynamic = new;
 		desc->pg_mirrors = new;
 
@@ -798,10 +800,14 @@
 	struct list_head *head = &mirror->pg_list;
 	struct nfs_commit_info cinfo;
 	unsigned int pagecount, pageused;
+	gfp_t gfp_flags = GFP_KERNEL;
 
 	pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count);
-	if (!nfs_pgarray_set(&hdr->page_array, pagecount))
+	if (desc->pg_rw_ops->rw_mode == FMODE_WRITE)
+		gfp_flags = GFP_NOIO;
+	if (!nfs_pgarray_set(&hdr->page_array, pagecount, gfp_flags)) {
 		return nfs_pgio_error(desc, hdr);
+	}
 
 	nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq);
 	pages = hdr->page_array.pagevec;
@@ -874,6 +880,9 @@
 
 	mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req);
 
+	if (pgio->pg_error < 0)
+		return pgio->pg_error;
+
 	if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX)
 		return -EINVAL;
 
@@ -885,15 +894,6 @@
 	return 0;
 }
 
-/*
- * nfs_pageio_stop_mirroring - stop using mirroring (set mirror count to 1)
- */
-void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio)
-{
-	pgio->pg_mirror_count = 1;
-	pgio->pg_mirror_idx = 0;
-}
-
 static void nfs_pageio_cleanup_mirroring(struct nfs_pageio_descriptor *pgio)
 {
 	pgio->pg_mirror_count = 1;
@@ -982,6 +982,8 @@
 	} else {
 		if (desc->pg_ops->pg_init)
 			desc->pg_ops->pg_init(desc, req);
+		if (desc->pg_error < 0)
+			return 0;
 		mirror->pg_base = req->wb_pgbase;
 	}
 	if (!nfs_can_coalesce_requests(prev, req, desc))
@@ -1104,7 +1106,6 @@
 			struct nfs_page *req;
 
 			req = list_first_entry(&head, struct nfs_page, wb_list);
-			nfs_list_remove_request(req);
 			if (__nfs_pageio_add_request(desc, req))
 				continue;
 			if (desc->pg_error < 0) {
@@ -1147,6 +1148,8 @@
 	bytes = req->wb_bytes;
 
 	nfs_pageio_setup_mirroring(desc, req);
+	if (desc->pg_error < 0)
+		return 0;
 
 	for (midx = 0; midx < desc->pg_mirror_count; midx++) {
 		if (midx) {
@@ -1198,7 +1201,7 @@
 		desc->pg_mirror_idx = mirror_idx;
 	for (;;) {
 		nfs_pageio_doio(desc);
-		if (!mirror->pg_recoalesce)
+		if (desc->pg_error < 0 || !mirror->pg_recoalesce)
 			break;
 		if (!nfs_do_recoalesce(desc))
 			break;
@@ -1232,7 +1235,7 @@
 	nfs_pageio_complete(desc);
 	if (!list_empty(&failed)) {
 		list_move(&failed, &hdr->pages);
-		return -EIO;
+		return desc->pg_error < 0 ? desc->pg_error : -EIO;
 	}
 	return 0;
 }
@@ -1275,12 +1278,22 @@
 		mirror = &desc->pg_mirrors[midx];
 		if (!list_empty(&mirror->pg_list)) {
 			prev = nfs_list_entry(mirror->pg_list.prev);
-			if (index != prev->wb_index + 1)
-				nfs_pageio_complete_mirror(desc, midx);
+			if (index != prev->wb_index + 1) {
+				nfs_pageio_complete(desc);
+				break;
+			}
 		}
 	}
 }
 
+/*
+ * nfs_pageio_stop_mirroring - stop using mirroring (set mirror count to 1)
+ */
+void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio)
+{
+	nfs_pageio_complete(pgio);
+}
+
 int __init nfs_init_nfspagecache(void)
 {
 	nfs_page_cachep = kmem_cache_create("nfs_page",
--- linux-4.4.0.orig/fs/nfs/pnfs.c
+++ linux-4.4.0/fs/nfs/pnfs.c
@@ -365,6 +365,9 @@
 static bool
 pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
 {
+	/* Serialise LAYOUTGET/LAYOUTRETURN */
+	if (atomic_read(&lo->plh_outstanding) != 0)
+		return false;
 	if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
 		return false;
 	lo->plh_return_iomode = 0;
@@ -906,14 +909,15 @@
 
 	if (IS_ERR(lseg)) {
 		switch (PTR_ERR(lseg)) {
-		case -ENOMEM:
 		case -ERESTARTSYS:
+		case -EIO:
+		case -ENOSPC:
+		case -EROFS:
+		case -E2BIG:
 			break;
 		default:
-			/* remember that LAYOUTGET failed and suspend trying */
-			pnfs_layout_io_set_failed(lo, range->iomode);
+			return NULL;
 		}
-		return NULL;
 	} else
 		pnfs_layout_clear_fail_bit(lo,
 				pnfs_iomode_to_fail_bit(range->iomode));
@@ -1182,13 +1186,11 @@
 	 * i_lock */
         spin_lock(&ino->i_lock);
         lo = nfsi->layout;
-        if (lo && test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
+        if (lo && test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) {
+                rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
                 sleep = true;
+	}
         spin_unlock(&ino->i_lock);
-
-        if (sleep)
-                rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
-
         return sleep;
 }
 
@@ -1530,6 +1532,7 @@
 		goto out;
 
 lookup_again:
+	nfs4_client_recover_expired_lease(clp);
 	first = false;
 	spin_lock(&ino->i_lock);
 	lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
@@ -1623,7 +1626,7 @@
 			"(%s, offset: %llu, length: %llu)\n",
 			__func__, ino->i_sb->s_id,
 			(unsigned long long)NFS_FILEID(ino),
-			lseg == NULL ? "not found" : "found",
+			IS_ERR_OR_NULL(lseg) ? "not found" : "found",
 			iomode==IOMODE_RW ?  "read/write" : "read-only",
 			(unsigned long long)pos,
 			(unsigned long long)count);
@@ -1802,6 +1805,11 @@
 						   rd_size,
 						   IOMODE_READ,
 						   GFP_KERNEL);
+		if (IS_ERR(pgio->pg_lseg)) {
+			pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+			pgio->pg_lseg = NULL;
+			return;
+		}
 	}
 	/* If no lseg, fall back to read through mds */
 	if (pgio->pg_lseg == NULL)
@@ -1814,13 +1822,19 @@
 pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
 			   struct nfs_page *req, u64 wb_size)
 {
-	if (pgio->pg_lseg == NULL)
+	if (pgio->pg_lseg == NULL) {
 		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
 						   req->wb_context,
 						   req_offset(req),
 						   wb_size,
 						   IOMODE_RW,
 						   GFP_NOFS);
+		if (IS_ERR(pgio->pg_lseg)) {
+			pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+			pgio->pg_lseg = NULL;
+			return;
+		}
+	}
 	/* If no lseg, fall back to write through mds */
 	if (pgio->pg_lseg == NULL)
 		nfs_pageio_reset_write_mds(pgio);
@@ -1941,8 +1955,7 @@
 		nfs_pageio_reset_write_mds(desc);
 		mirror->pg_recoalesce = 1;
 	}
-	nfs_pgio_data_destroy(hdr);
-	hdr->release(hdr);
+	hdr->completion_ops->completion(hdr);
 }
 
 static enum pnfs_try_status
@@ -2057,8 +2070,7 @@
 		nfs_pageio_reset_read_mds(desc);
 		mirror->pg_recoalesce = 1;
 	}
-	nfs_pgio_data_destroy(hdr);
-	hdr->release(hdr);
+	hdr->completion_ops->completion(hdr);
 }
 
 /*
--- linux-4.4.0.orig/fs/nfs/proc.c
+++ linux-4.4.0/fs/nfs/proc.c
@@ -588,7 +588,8 @@
 		/* Emulate the eof flag, which isn't normally needed in NFSv2
 		 * as it is guaranteed to always return the file attributes
 		 */
-		if (hdr->args.offset + hdr->res.count >= hdr->res.fattr->size)
+		if ((hdr->res.count == 0 && hdr->args.count > 0) ||
+		    hdr->args.offset + hdr->res.count >= hdr->res.fattr->size)
 			hdr->res.eof = 1;
 	}
 	return 0;
@@ -609,8 +610,10 @@
 
 static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
 {
-	if (task->tk_status >= 0)
+	if (task->tk_status >= 0) {
+		hdr->res.count = hdr->args.count;
 		nfs_writeback_update_inode(hdr);
+	}
 	return 0;
 }
 
--- linux-4.4.0.orig/fs/nfs/read.c
+++ linux-4.4.0/fs/nfs/read.c
@@ -115,7 +115,7 @@
 	pgm = &pgio.pg_mirrors[0];
 	NFS_I(inode)->read_io += pgm->pg_bytes_written;
 
-	return 0;
+	return pgio.pg_error < 0 ? pgio.pg_error : 0;
 }
 
 static void nfs_readpage_release(struct nfs_page *req)
--- linux-4.4.0.orig/fs/nfs/super.c
+++ linux-4.4.0/fs/nfs/super.c
@@ -1322,7 +1322,7 @@
 			mnt->options |= NFS_OPTION_MIGRATION;
 			break;
 		case Opt_nomigration:
-			mnt->options &= NFS_OPTION_MIGRATION;
+			mnt->options &= ~NFS_OPTION_MIGRATION;
 			break;
 
 		/*
@@ -1877,6 +1877,11 @@
 	size_t len;
 	char *end;
 
+	if (unlikely(!dev_name || !*dev_name)) {
+		dfprintk(MOUNT, "NFS: device name not specified\n");
+		return -EINVAL;
+	}
+
 	/* Is the host name protected with square brakcets? */
 	if (*dev_name == '[') {
 		end = strchr(++dev_name, ']');
@@ -1896,7 +1901,7 @@
 		/* kill possible hostname list: not supported */
 		comma = strchr(dev_name, ',');
 		if (comma != NULL && comma < end)
-			*comma = 0;
+			len = comma - dev_name;
 	}
 
 	if (len > maxnamlen)
@@ -2015,7 +2020,8 @@
 		memcpy(sap, &data->addr, sizeof(data->addr));
 		args->nfs_server.addrlen = sizeof(data->addr);
 		args->nfs_server.port = ntohs(data->addr.sin_port);
-		if (!nfs_verify_server_address(sap))
+		if (sap->sa_family != AF_INET ||
+		    !nfs_verify_server_address(sap))
 			goto out_no_address;
 
 		if (!(data->flags & NFS_MOUNT_TCP))
@@ -2376,8 +2382,7 @@
 		goto Ebusy;
 	if (a->acdirmax != b->acdirmax)
 		goto Ebusy;
-	if (b->auth_info.flavor_len > 0 &&
-	   clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
+	if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
 		goto Ebusy;
 	return 1;
 Ebusy:
@@ -2581,6 +2586,8 @@
 		/* initial superblock/root creation */
 		mount_info->fill_super(s, mount_info);
 		nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
+		if (!(server->flags & NFS_MOUNT_UNSHARED))
+			s->s_iflags |= SB_I_MULTIROOT;
 	}
 
 	mntroot = nfs_get_root(s, mount_info->mntfh, dev_name);
--- linux-4.4.0.orig/fs/nfs/write.c
+++ linux-4.4.0/fs/nfs/write.c
@@ -1261,6 +1261,9 @@
 	dprintk("NFS:       nfs_updatepage(%pD2 %d@%lld)\n",
 		file, count, (long long)(page_file_offset(page) + offset));
 
+	if (!count)
+		goto out;
+
 	if (nfs_can_extend_write(file, page, inode)) {
 		count = max(count + offset, nfs_page_length(page));
 		offset = 0;
@@ -1271,7 +1274,7 @@
 		nfs_set_pageerror(page);
 	else
 		__set_page_dirty_nobuffers(page);
-
+out:
 	dprintk("NFS:       nfs_updatepage returns %d (isize %lld)\n",
 			status, (long long)i_size_read(inode));
 	return status;
@@ -1743,6 +1746,8 @@
 		set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
 	next:
 		nfs_unlock_and_release_request(req);
+		/* Latency breaker */
+		cond_resched();
 	}
 	nfss = NFS_SERVER(data->inode);
 	if (atomic_long_read(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
--- linux-4.4.0.orig/fs/nfs_common/grace.c
+++ linux-4.4.0/fs/nfs_common/grace.c
@@ -30,7 +30,11 @@
 	struct list_head *grace_list = net_generic(net, grace_net_id);
 
 	spin_lock(&grace_lock);
-	list_add(&lm->list, grace_list);
+	if (list_empty(&lm->list))
+		list_add(&lm->list, grace_list);
+	else
+		WARN(1, "double list_add attempt detected in net %x %s\n",
+		     net->ns.inum, (net == &init_net) ? "(init_net)" : "");
 	spin_unlock(&grace_lock);
 }
 EXPORT_SYMBOL_GPL(locks_start_grace);
@@ -71,10 +75,14 @@
 	if (!open)
 		return !list_empty(grace_list);
 
+	spin_lock(&grace_lock);
 	list_for_each_entry(lm, grace_list, list) {
-		if (lm->block_opens)
+		if (lm->block_opens) {
+			spin_unlock(&grace_lock);
 			return true;
+		}
 	}
+	spin_unlock(&grace_lock);
 	return false;
 }
 
@@ -104,7 +112,9 @@
 {
 	struct list_head *grace_list = net_generic(net, grace_net_id);
 
-	BUG_ON(!list_empty(grace_list));
+	WARN_ONCE(!list_empty(grace_list),
+		  "net %x %s: grace_list is not empty\n",
+		  net->ns.inum, __func__);
 }
 
 static struct pernet_operations grace_net_ops = {
--- linux-4.4.0.orig/fs/nfsd/auth.c
+++ linux-4.4.0/fs/nfsd/auth.c
@@ -59,7 +59,11 @@
 				GROUP_AT(gi, i) = exp->ex_anon_gid;
 			else
 				GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
+
 		}
+
+		/* Each thread allocates its own gi, no race */
+		groups_sort(gi);
 	} else {
 		gi = get_group_info(rqgi);
 	}
--- linux-4.4.0.orig/fs/nfsd/blocklayout.c
+++ linux-4.4.0/fs/nfsd/blocklayout.c
@@ -50,7 +50,7 @@
 {
 	struct nfsd4_layout_seg *seg = &args->lg_seg;
 	struct super_block *sb = inode->i_sb;
-	u32 block_size = (1 << inode->i_blkbits);
+	u32 block_size = i_blocksize(inode);
 	struct pnfs_block_extent *bex;
 	struct iomap iomap;
 	u32 device_generation = 0;
@@ -151,7 +151,7 @@
 	int error;
 
 	nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
-			lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits);
+			lcp->lc_up_len, &iomaps, i_blocksize(inode));
 	if (nr_iomaps < 0)
 		return nfserrno(nr_iomaps);
 
--- linux-4.4.0.orig/fs/nfsd/nfs2acl.c
+++ linux-4.4.0/fs/nfsd/nfs2acl.c
@@ -81,6 +81,8 @@
 fail:
 	posix_acl_release(resp->acl_access);
 	posix_acl_release(resp->acl_default);
+	resp->acl_access = NULL;
+	resp->acl_default = NULL;
 	RETURN_STATUS(nfserr);
 }
 
@@ -104,22 +106,21 @@
 		goto out;
 
 	inode = d_inode(fh->fh_dentry);
-	if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
-		error = -EOPNOTSUPP;
-		goto out_errno;
-	}
 
 	error = fh_want_write(fh);
 	if (error)
 		goto out_errno;
 
-	error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS);
+	fh_lock(fh);
+
+	error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
 	if (error)
-		goto out_drop_write;
-	error = inode->i_op->set_acl(inode, argp->acl_default,
-				     ACL_TYPE_DEFAULT);
+		goto out_drop_lock;
+	error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);
 	if (error)
-		goto out_drop_write;
+		goto out_drop_lock;
+
+	fh_unlock(fh);
 
 	fh_drop_write(fh);
 
@@ -131,7 +132,8 @@
 	posix_acl_release(argp->acl_access);
 	posix_acl_release(argp->acl_default);
 	return nfserr;
-out_drop_write:
+out_drop_lock:
+	fh_unlock(fh);
 	fh_drop_write(fh);
 out_errno:
 	nfserr = nfserrno(error);
--- linux-4.4.0.orig/fs/nfsd/nfs3acl.c
+++ linux-4.4.0/fs/nfsd/nfs3acl.c
@@ -74,6 +74,8 @@
 fail:
 	posix_acl_release(resp->acl_access);
 	posix_acl_release(resp->acl_default);
+	resp->acl_access = NULL;
+	resp->acl_default = NULL;
 	RETURN_STATUS(nfserr);
 }
 
@@ -95,22 +97,20 @@
 		goto out;
 
 	inode = d_inode(fh->fh_dentry);
-	if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
-		error = -EOPNOTSUPP;
-		goto out_errno;
-	}
 
 	error = fh_want_write(fh);
 	if (error)
 		goto out_errno;
 
-	error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS);
+	fh_lock(fh);
+
+	error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
 	if (error)
-		goto out_drop_write;
-	error = inode->i_op->set_acl(inode, argp->acl_default,
-				     ACL_TYPE_DEFAULT);
+		goto out_drop_lock;
+	error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);
 
-out_drop_write:
+out_drop_lock:
+	fh_unlock(fh);
 	fh_drop_write(fh);
 out_errno:
 	nfserr = nfserrno(error);
--- linux-4.4.0.orig/fs/nfsd/nfs3proc.c
+++ linux-4.4.0/fs/nfsd/nfs3proc.c
@@ -430,8 +430,19 @@
 					&resp->common, nfs3svc_encode_entry);
 	memcpy(resp->verf, argp->verf, 8);
 	resp->count = resp->buffer - argp->buffer;
-	if (resp->offset)
-		xdr_encode_hyper(resp->offset, argp->cookie);
+	if (resp->offset) {
+		loff_t offset = argp->cookie;
+
+		if (unlikely(resp->offset1)) {
+			/* we ended up with offset on a page boundary */
+			*resp->offset = htonl(offset >> 32);
+			*resp->offset1 = htonl(offset & 0xffffffff);
+			resp->offset1 = NULL;
+		} else {
+			xdr_encode_hyper(resp->offset, offset);
+		}
+		resp->offset = NULL;
+	}
 
 	RETURN_STATUS(nfserr);
 }
@@ -499,6 +510,7 @@
 		} else {
 			xdr_encode_hyper(resp->offset, offset);
 		}
+		resp->offset = NULL;
 	}
 
 	RETURN_STATUS(nfserr);
--- linux-4.4.0.orig/fs/nfsd/nfs3xdr.c
+++ linux-4.4.0/fs/nfsd/nfs3xdr.c
@@ -358,6 +358,7 @@
 {
 	unsigned int len, v, hdr, dlen;
 	u32 max_blocksize = svc_max_payload(rqstp);
+	struct kvec *head = rqstp->rq_arg.head;
 
 	p = decode_fh(p, &args->fh);
 	if (!p)
@@ -367,6 +368,8 @@
 	args->count = ntohl(*p++);
 	args->stable = ntohl(*p++);
 	len = args->len = ntohl(*p++);
+	if ((void *)p > head->iov_base + head->iov_len)
+		return 0;
 	/*
 	 * The count must equal the amount of data passed.
 	 */
@@ -377,9 +380,8 @@
 	 * Check to make sure that we got the right number of
 	 * bytes.
 	 */
-	hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
-	dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
-		- hdr;
+	hdr = (void*)p - head->iov_base;
+	dlen = head->iov_len + rqstp->rq_arg.page_len - hdr;
 	/*
 	 * Round the length of the data which was specified up to
 	 * the next multiple of XDR units and then compare that
@@ -396,7 +398,7 @@
 		len = args->len = max_blocksize;
 	}
 	rqstp->rq_vec[0].iov_base = (void*)p;
-	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
+	rqstp->rq_vec[0].iov_len = head->iov_len - hdr;
 	v = 0;
 	while (len > rqstp->rq_vec[v].iov_len) {
 		len -= rqstp->rq_vec[v].iov_len;
@@ -471,6 +473,8 @@
 	/* first copy and check from the first page */
 	old = (char*)p;
 	vec = &rqstp->rq_arg.head[0];
+	if ((void *)old > vec->iov_base + vec->iov_len)
+		return 0;
 	avail = vec->iov_len - (old - (char*)vec->iov_base);
 	while (len && avail && *old) {
 		*new++ = *old++;
@@ -817,9 +821,14 @@
 	if (isdotent(name, namlen)) {
 		if (namlen == 2) {
 			dchild = dget_parent(dparent);
-			/* filesystem root - cannot return filehandle for ".." */
+			/*
+			 * Don't return filehandle for ".." if we're at
+			 * the filesystem or export root:
+			 */
 			if (dchild == dparent)
 				goto out;
+			if (dparent == exp->ex_path.dentry)
+				goto out;
 		} else
 			dchild = dget(dparent);
 	} else
@@ -894,6 +903,7 @@
 		} else {
 			xdr_encode_hyper(cd->offset, offset64);
 		}
+		cd->offset = NULL;
 	}
 
 	/*
--- linux-4.4.0.orig/fs/nfsd/nfs4acl.c
+++ linux-4.4.0/fs/nfsd/nfs4acl.c
@@ -770,9 +770,6 @@
 	dentry = fhp->fh_dentry;
 	inode = d_inode(dentry);
 
-	if (!inode->i_op->set_acl || !IS_POSIXACL(inode))
-		return nfserr_attrnotsupp;
-
 	if (S_ISDIR(inode->i_mode))
 		flags = NFS4_ACL_DIR;
 
@@ -782,16 +779,19 @@
 	if (host_error < 0)
 		goto out_nfserr;
 
-	host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS);
+	fh_lock(fhp);
+
+	host_error = set_posix_acl(inode, ACL_TYPE_ACCESS, pacl);
 	if (host_error < 0)
-		goto out_release;
+		goto out_drop_lock;
 
 	if (S_ISDIR(inode->i_mode)) {
-		host_error = inode->i_op->set_acl(inode, dpacl,
-						  ACL_TYPE_DEFAULT);
+		host_error = set_posix_acl(inode, ACL_TYPE_DEFAULT, dpacl);
 	}
 
-out_release:
+out_drop_lock:
+	fh_unlock(fhp);
+
 	posix_acl_release(pacl);
 	posix_acl_release(dpacl);
 out_nfserr:
--- linux-4.4.0.orig/fs/nfsd/nfs4callback.c
+++ linux-4.4.0/fs/nfsd/nfs4callback.c
@@ -696,6 +696,14 @@
 	return 0;
 }
 
+void cleanup_callback_cred(void)
+{
+	if (callback_cred) {
+		put_rpccred(callback_cred);
+		callback_cred = NULL;
+	}
+}
+
 static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses)
 {
 	if (clp->cl_minorversion == 0) {
@@ -710,22 +718,6 @@
 	}
 }
 
-static struct rpc_clnt *create_backchannel_client(struct rpc_create_args *args)
-{
-	struct rpc_xprt *xprt;
-
-	if (args->protocol != XPRT_TRANSPORT_BC_TCP)
-		return rpc_create(args);
-
-	xprt = args->bc_xprt->xpt_bc_xprt;
-	if (xprt) {
-		xprt_get(xprt);
-		return rpc_create_xprt(args, xprt);
-	}
-
-	return rpc_create(args);
-}
-
 static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
 {
 	int maxtime = max_cb_time(clp->net);
@@ -757,7 +749,7 @@
 		args.authflavor = clp->cl_cred.cr_flavor;
 		clp->cl_cb_ident = conn->cb_ident;
 	} else {
-		if (!conn->cb_xprt)
+		if (!conn->cb_xprt || !ses)
 			return -EINVAL;
 		clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
 		clp->cl_cb_session = ses;
@@ -768,7 +760,7 @@
 		args.authflavor = ses->se_cb_sec.flavor;
 	}
 	/* Create RPC client */
-	client = create_backchannel_client(&args);
+	client = rpc_create(&args);
 	if (IS_ERR(client)) {
 		dprintk("NFSD: couldn't create callback client: %ld\n",
 			PTR_ERR(client));
@@ -882,8 +874,9 @@
 	cb->cb_seq_status = 1;
 	cb->cb_status = 0;
 	if (minorversion) {
-		if (!nfsd41_cb_get_slot(clp, task))
+		if (!cb->cb_holds_slot && !nfsd41_cb_get_slot(clp, task))
 			return;
+		cb->cb_holds_slot = true;
 	}
 	rpc_call_start(task);
 }
@@ -910,6 +903,9 @@
 		return true;
 	}
 
+	if (!cb->cb_holds_slot)
+		goto need_restart;
+
 	switch (cb->cb_seq_status) {
 	case 0:
 		/*
@@ -947,6 +943,7 @@
 			cb->cb_seq_status);
 	}
 
+	cb->cb_holds_slot = false;
 	clear_bit(0, &clp->cl_cb_slot_busy);
 	rpc_wake_up_next(&clp->cl_cb_waitq);
 	dprintk("%s: freed slot, new seqid=%d\n", __func__,
@@ -1099,6 +1096,8 @@
 	err = setup_callback_client(clp, &conn, ses);
 	if (err) {
 		nfsd4_mark_cb_down(clp, err);
+		if (c)
+			svc_xprt_put(c->cn_xprt);
 		return;
 	}
 }
@@ -1154,6 +1153,7 @@
 	cb->cb_seq_status = 1;
 	cb->cb_status = 0;
 	cb->cb_need_restart = false;
+	cb->cb_holds_slot = false;
 }
 
 void nfsd4_run_cb(struct nfsd4_callback *cb)
--- linux-4.4.0.orig/fs/nfsd/nfs4layouts.c
+++ linux-4.4.0/fs/nfsd/nfs4layouts.c
@@ -189,10 +189,11 @@
 	struct nfs4_layout_stateid *ls;
 	struct nfs4_stid *stp;
 
-	stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache);
+	stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache,
+					nfsd4_free_layout_stateid);
 	if (!stp)
 		return NULL;
-	stp->sc_free = nfsd4_free_layout_stateid;
+
 	get_nfs4_file(fp);
 	stp->sc_file = fp;
 
--- linux-4.4.0.orig/fs/nfsd/nfs4proc.c
+++ linux-4.4.0/fs/nfsd/nfs4proc.c
@@ -877,6 +877,7 @@
 				    &exp, &dentry);
 	if (err)
 		return err;
+	fh_unlock(&cstate->current_fh);
 	if (d_really_is_negative(dentry)) {
 		exp_put(exp);
 		err = nfserr_noent;
@@ -1244,14 +1245,14 @@
 	const struct nfsd4_layout_ops *ops;
 	struct nfs4_layout_stateid *ls;
 	__be32 nfserr;
-	int accmode;
+	int accmode = NFSD_MAY_READ_IF_EXEC;
 
 	switch (lgp->lg_seg.iomode) {
 	case IOMODE_READ:
-		accmode = NFSD_MAY_READ;
+		accmode |= NFSD_MAY_READ;
 		break;
 	case IOMODE_RW:
-		accmode = NFSD_MAY_READ | NFSD_MAY_WRITE;
+		accmode |= NFSD_MAY_READ | NFSD_MAY_WRITE;
 		break;
 	default:
 		dprintk("%s: invalid iomode %d\n",
@@ -1631,6 +1632,7 @@
 	if (status) {
 		op = &args->ops[0];
 		op->status = status;
+		resp->opcnt = 1;
 		goto encode_op;
 	}
 
@@ -1689,6 +1691,12 @@
 			opdesc->op_get_currentstateid(cstate, &op->u);
 		op->status = opdesc->op_func(rqstp, cstate, &op->u);
 
+		/* Only from SEQUENCE */
+		if (cstate->status == nfserr_replay_cache) {
+			dprintk("%s NFS4.1 replay from cache\n", __func__);
+			status = op->status;
+			goto out;
+		}
 		if (!op->status) {
 			if (opdesc->op_set_currentstateid)
 				opdesc->op_set_currentstateid(cstate, &op->u);
@@ -1699,14 +1707,7 @@
 			if (need_wrongsec_check(rqstp))
 				op->status = check_nfsd_access(current_fh->fh_export, rqstp);
 		}
-
 encode_op:
-		/* Only from SEQUENCE */
-		if (cstate->status == nfserr_replay_cache) {
-			dprintk("%s NFS4.1 replay from cache\n", __func__);
-			status = op->status;
-			goto out;
-		}
 		if (op->status == nfserr_replay_me) {
 			op->replay = &cstate->replay_owner->so_replay;
 			nfsd4_encode_replay(&resp->xdr, op);
@@ -1753,6 +1754,22 @@
 
 #define op_encode_channel_attrs_maxsz	(6 + 1 + 1)
 
+/*
+ * The _rsize() helpers are invoked by the NFSv4 COMPOUND decoder, which
+ * is called before sunrpc sets rq_res.buflen. Thus we have to compute
+ * the maximum payload size here, based on transport limits and the size
+ * of the remaining space in the rq_pages array.
+ */
+static u32 nfsd4_max_payload(const struct svc_rqst *rqstp)
+{
+	u32 buflen;
+
+	buflen = (rqstp->rq_page_end - rqstp->rq_next_page) * PAGE_SIZE;
+	buflen -= rqstp->rq_auth_slack;
+	buflen -= rqstp->rq_res.head[0].iov_len;
+	return min_t(u32, buflen, svc_max_payload(rqstp));
+}
+
 static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 {
 	return (op_encode_hdr_size) * sizeof(__be32);
@@ -1787,9 +1804,9 @@
 	u32 ret = 0;
 
 	if (bmap0 & FATTR4_WORD0_ACL)
-		return svc_max_payload(rqstp);
+		return nfsd4_max_payload(rqstp);
 	if (bmap0 & FATTR4_WORD0_FS_LOCATIONS)
-		return svc_max_payload(rqstp);
+		return nfsd4_max_payload(rqstp);
 
 	if (bmap1 & FATTR4_WORD1_OWNER) {
 		ret += IDMAP_NAMESZ + 4;
@@ -1839,20 +1856,14 @@
 
 static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 {
-	u32 maxcount = 0, rlen = 0;
-
-	maxcount = svc_max_payload(rqstp);
-	rlen = min(op->u.read.rd_length, maxcount);
+	u32 rlen = min(op->u.read.rd_length, nfsd4_max_payload(rqstp));
 
 	return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32);
 }
 
 static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 {
-	u32 maxcount = 0, rlen = 0;
-
-	maxcount = svc_max_payload(rqstp);
-	rlen = min(op->u.readdir.rd_maxcount, maxcount);
+	u32 rlen = min(op->u.readdir.rd_maxcount, nfsd4_max_payload(rqstp));
 
 	return (op_encode_hdr_size + op_encode_verifier_maxsz +
 		XDR_QUADLEN(rlen)) * sizeof(__be32);
--- linux-4.4.0.orig/fs/nfsd/nfs4recover.c
+++ linux-4.4.0/fs/nfsd/nfs4recover.c
@@ -655,7 +655,7 @@
 struct cld_upcall {
 	struct list_head	 cu_list;
 	struct cld_net		*cu_net;
-	struct task_struct	*cu_task;
+	struct completion	 cu_done;
 	struct cld_msg		 cu_msg;
 };
 
@@ -664,23 +664,18 @@
 {
 	int ret;
 	struct rpc_pipe_msg msg;
+	struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_msg);
 
 	memset(&msg, 0, sizeof(msg));
 	msg.data = cmsg;
 	msg.len = sizeof(*cmsg);
 
-	/*
-	 * Set task state before we queue the upcall. That prevents
-	 * wake_up_process in the downcall from racing with schedule.
-	 */
-	set_current_state(TASK_UNINTERRUPTIBLE);
 	ret = rpc_queue_upcall(pipe, &msg);
 	if (ret < 0) {
-		set_current_state(TASK_RUNNING);
 		goto out;
 	}
 
-	schedule();
+	wait_for_completion(&cup->cu_done);
 
 	if (msg.errno < 0)
 		ret = msg.errno;
@@ -747,7 +742,7 @@
 	if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
 		return -EFAULT;
 
-	wake_up_process(cup->cu_task);
+	complete(&cup->cu_done);
 	return mlen;
 }
 
@@ -762,7 +757,7 @@
 	if (msg->errno >= 0)
 		return;
 
-	wake_up_process(cup->cu_task);
+	complete(&cup->cu_done);
 }
 
 static const struct rpc_pipe_ops cld_upcall_ops = {
@@ -893,7 +888,7 @@
 			goto restart_search;
 		}
 	}
-	new->cu_task = current;
+	init_completion(&new->cu_done);
 	new->cu_msg.cm_vers = CLD_UPCALL_VERSION;
 	put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid);
 	new->cu_net = cn;
--- linux-4.4.0.orig/fs/nfsd/nfs4state.c
+++ linux-4.4.0/fs/nfsd/nfs4state.c
@@ -63,12 +63,16 @@
 static const stateid_t currentstateid = {
 	.si_generation = 1,
 };
+static const stateid_t close_stateid = {
+	.si_generation = 0xffffffffU,
+};
 
 static u64 current_sessionid = 1;
 
 #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
 #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
 #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
+#define CLOSE_STATEID(stateid)  (!memcmp((stateid), &close_stateid, sizeof(stateid_t)))
 
 /* forward declarations */
 static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
@@ -553,8 +557,8 @@
 	return co;
 }
 
-struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
-					 struct kmem_cache *slab)
+struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
+				  void (*sc_free)(struct nfs4_stid *))
 {
 	struct nfs4_stid *stid;
 	int new_id;
@@ -570,6 +574,8 @@
 	idr_preload_end();
 	if (new_id < 0)
 		goto out_free;
+
+	stid->sc_free = sc_free;
 	stid->sc_client = cl;
 	stid->sc_stateid.si_opaque.so_id = new_id;
 	stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
@@ -595,15 +601,12 @@
 static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
 {
 	struct nfs4_stid *stid;
-	struct nfs4_ol_stateid *stp;
 
-	stid = nfs4_alloc_stid(clp, stateid_slab);
+	stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
 	if (!stid)
 		return NULL;
 
-	stp = openlockstateid(stid);
-	stp->st_stid.sc_free = nfs4_free_ol_stateid;
-	return stp;
+	return openlockstateid(stid);
 }
 
 static void nfs4_free_deleg(struct nfs4_stid *stid)
@@ -701,11 +704,10 @@
 		goto out_dec;
 	if (delegation_blocked(&current_fh->fh_handle))
 		goto out_dec;
-	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
+	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
 	if (dp == NULL)
 		goto out_dec;
 
-	dp->dl_stid.sc_free = nfs4_free_deleg;
 	/*
 	 * delegation seqid's are never incremented.  The 4.1 special
 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
@@ -842,6 +844,11 @@
 	return 0;
 }
 
+static bool delegation_hashed(struct nfs4_delegation *dp)
+{
+	return !(list_empty(&dp->dl_perfile));
+}
+
 static bool
 unhash_delegation_locked(struct nfs4_delegation *dp)
 {
@@ -849,7 +856,7 @@
 
 	lockdep_assert_held(&state_lock);
 
-	if (list_empty(&dp->dl_perfile))
+	if (!delegation_hashed(dp))
 		return false;
 
 	dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
@@ -1147,9 +1154,7 @@
 
 static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
 {
-	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
-
-	lockdep_assert_held(&oo->oo_owner.so_client->cl_lock);
+	lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
 
 	list_del_init(&stp->st_locks);
 	nfs4_unhash_stid(&stp->st_stid);
@@ -1158,12 +1163,12 @@
 
 static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 {
-	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
+	struct nfs4_client *clp = stp->st_stid.sc_client;
 	bool unhashed;
 
-	spin_lock(&oo->oo_owner.so_client->cl_lock);
+	spin_lock(&clp->cl_lock);
 	unhashed = unhash_lock_stateid(stp);
-	spin_unlock(&oo->oo_owner.so_client->cl_lock);
+	spin_unlock(&clp->cl_lock);
 	if (unhashed)
 		nfs4_put_stid(&stp->st_stid);
 }
@@ -1200,27 +1205,6 @@
 	}
 }
 
-static void release_lockowner(struct nfs4_lockowner *lo)
-{
-	struct nfs4_client *clp = lo->lo_owner.so_client;
-	struct nfs4_ol_stateid *stp;
-	struct list_head reaplist;
-
-	INIT_LIST_HEAD(&reaplist);
-
-	spin_lock(&clp->cl_lock);
-	unhash_lockowner_locked(lo);
-	while (!list_empty(&lo->lo_owner.so_stateids)) {
-		stp = list_first_entry(&lo->lo_owner.so_stateids,
-				struct nfs4_ol_stateid, st_perstateowner);
-		WARN_ON(!unhash_lock_stateid(stp));
-		put_ol_stateid_locked(stp, &reaplist);
-	}
-	spin_unlock(&clp->cl_lock);
-	free_ol_stateid_reaplist(&reaplist);
-	nfs4_put_stateowner(&lo->lo_owner);
-}
-
 static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
 				       struct list_head *reaplist)
 {
@@ -1412,11 +1396,16 @@
 {
 	u32 slotsize = slot_bytes(ca);
 	u32 num = ca->maxreqs;
-	int avail;
+	unsigned long avail, total_avail;
 
 	spin_lock(&nfsd_drc_lock);
-	avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
-		    nfsd_drc_max_mem - nfsd_drc_mem_used);
+	total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used;
+	avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail);
+	/*
+	 * Never use more than a third of the remaining memory,
+	 * unless it's the only way to give this client a slot:
+	 */
+	avail = clamp_t(unsigned long, avail, slotsize, total_avail/3);
 	num = min_t(int, num, avail / slotsize);
 	nfsd_drc_mem_used += num * slotsize;
 	spin_unlock(&nfsd_drc_lock);
@@ -3404,7 +3393,9 @@
 		/* ignore lock owners */
 		if (local->st_stateowner->so_is_open_owner == 0)
 			continue;
-		if (local->st_stateowner == &oo->oo_owner) {
+		if (local->st_stateowner != &oo->oo_owner)
+			continue;
+		if (local->st_stid.sc_type == NFS4_OPEN_STID) {
 			ret = local;
 			atomic_inc(&ret->st_stid.sc_count);
 			break;
@@ -3413,6 +3404,52 @@
 	return ret;
 }
 
+static __be32
+nfsd4_verify_open_stid(struct nfs4_stid *s)
+{
+	__be32 ret = nfs_ok;
+
+	switch (s->sc_type) {
+	default:
+		break;
+	case NFS4_CLOSED_STID:
+	case NFS4_CLOSED_DELEG_STID:
+		ret = nfserr_bad_stateid;
+		break;
+	case NFS4_REVOKED_DELEG_STID:
+		ret = nfserr_deleg_revoked;
+	}
+	return ret;
+}
+
+/* Lock the stateid st_mutex, and deal with races with CLOSE */
+static __be32
+nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp)
+{
+	__be32 ret;
+
+	mutex_lock(&stp->st_mutex);
+	ret = nfsd4_verify_open_stid(&stp->st_stid);
+	if (ret != nfs_ok)
+		mutex_unlock(&stp->st_mutex);
+	return ret;
+}
+
+static struct nfs4_ol_stateid *
+nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
+{
+	struct nfs4_ol_stateid *stp;
+	for (;;) {
+		spin_lock(&fp->fi_lock);
+		stp = nfsd4_find_existing_open(fp, open);
+		spin_unlock(&fp->fi_lock);
+		if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok)
+			break;
+		nfs4_put_stid(&stp->st_stid);
+	}
+	return stp;
+}
+
 static struct nfs4_openowner *
 alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 			   struct nfsd4_compound_state *cstate)
@@ -3445,19 +3482,27 @@
 }
 
 static struct nfs4_ol_stateid *
-init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
-		struct nfsd4_open *open)
+init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open)
 {
 
 	struct nfs4_openowner *oo = open->op_openowner;
 	struct nfs4_ol_stateid *retstp = NULL;
+	struct nfs4_ol_stateid *stp;
+
+	stp = open->op_stp;
+	/* We are moving these outside of the spinlocks to avoid the warnings */
+	mutex_init(&stp->st_mutex);
+	mutex_lock(&stp->st_mutex);
 
+retry:
 	spin_lock(&oo->oo_owner.so_client->cl_lock);
 	spin_lock(&fp->fi_lock);
 
 	retstp = nfsd4_find_existing_open(fp, open);
 	if (retstp)
 		goto out_unlock;
+
+	open->op_stp = NULL;
 	atomic_inc(&stp->st_stid.sc_count);
 	stp->st_stid.sc_type = NFS4_OPEN_STID;
 	INIT_LIST_HEAD(&stp->st_locks);
@@ -3467,14 +3512,23 @@
 	stp->st_access_bmap = 0;
 	stp->st_deny_bmap = 0;
 	stp->st_openstp = NULL;
-	init_rwsem(&stp->st_rwsem);
 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
 	list_add(&stp->st_perfile, &fp->fi_stateids);
 
 out_unlock:
 	spin_unlock(&fp->fi_lock);
 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
-	return retstp;
+	if (retstp) {
+		/* Handle races with CLOSE */
+		if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) {
+			nfs4_put_stid(&retstp->st_stid);
+			goto retry;
+		}
+		/* To keep mutex tracking happy */
+		mutex_unlock(&stp->st_mutex);
+		stp = retstp;
+	}
+	return stp;
 }
 
 /*
@@ -3607,7 +3661,7 @@
 	 * queued for a lease break. Don't queue it again.
 	 */
 	spin_lock(&state_lock);
-	if (dp->dl_time == 0) {
+	if (delegation_hashed(dp) && dp->dl_time == 0) {
 		dp->dl_time = get_seconds();
 		list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
 	}
@@ -3846,7 +3900,8 @@
 {
 	struct nfs4_stid *ret;
 
-	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
+	ret = find_stateid_by_type(cl, s,
+				NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID);
 	if (!ret)
 		return NULL;
 	return delegstateid(ret);
@@ -3869,6 +3924,12 @@
 	deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
 	if (deleg == NULL)
 		goto out;
+	if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) {
+		nfs4_put_stid(&deleg->dl_stid);
+		if (cl->cl_minorversion)
+			status = nfserr_deleg_revoked;
+		goto out;
+	}
 	flags = share_access_to_flags(open->op_share_access);
 	status = nfs4_check_delegmode(deleg, flags);
 	if (status) {
@@ -4270,9 +4331,9 @@
 	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
 	struct nfs4_file *fp = NULL;
 	struct nfs4_ol_stateid *stp = NULL;
-	struct nfs4_ol_stateid *swapstp = NULL;
 	struct nfs4_delegation *dp = NULL;
 	__be32 status;
+	bool new_stp = false;
 
 	/*
 	 * Lookup file; if found, lookup stateid and check open request,
@@ -4284,9 +4345,7 @@
 		status = nfs4_check_deleg(cl, open, &dp);
 		if (status)
 			goto out;
-		spin_lock(&fp->fi_lock);
-		stp = nfsd4_find_existing_open(fp, open);
-		spin_unlock(&fp->fi_lock);
+		stp = nfsd4_find_and_lock_existing_open(fp, open);
 	} else {
 		open->op_file = NULL;
 		status = nfserr_bad_stateid;
@@ -4294,39 +4353,31 @@
 			goto out;
 	}
 
+	if (!stp) {
+		stp = init_open_stateid(fp, open);
+		if (!open->op_stp)
+			new_stp = true;
+	}
+
 	/*
 	 * OPEN the file, or upgrade an existing OPEN.
 	 * If truncate fails, the OPEN fails.
+	 *
+	 * stp is already locked.
 	 */
-	if (stp) {
+	if (!new_stp) {
 		/* Stateid was found, this is an OPEN upgrade */
-		down_read(&stp->st_rwsem);
 		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
 		if (status) {
-			up_read(&stp->st_rwsem);
+			mutex_unlock(&stp->st_mutex);
 			goto out;
 		}
 	} else {
-		stp = open->op_stp;
-		open->op_stp = NULL;
-		swapstp = init_open_stateid(stp, fp, open);
-		if (swapstp) {
-			nfs4_put_stid(&stp->st_stid);
-			stp = swapstp;
-			down_read(&stp->st_rwsem);
-			status = nfs4_upgrade_open(rqstp, fp, current_fh,
-						stp, open);
-			if (status) {
-				up_read(&stp->st_rwsem);
-				goto out;
-			}
-			goto upgrade_out;
-		}
-		down_read(&stp->st_rwsem);
 		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
 		if (status) {
-			up_read(&stp->st_rwsem);
+			stp->st_stid.sc_type = NFS4_CLOSED_STID;
 			release_open_stateid(stp);
+			mutex_unlock(&stp->st_mutex);
 			goto out;
 		}
 
@@ -4335,9 +4386,9 @@
 		if (stp->st_clnt_odstate == open->op_odstate)
 			open->op_odstate = NULL;
 	}
-upgrade_out:
+
 	nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
-	up_read(&stp->st_rwsem);
+	mutex_unlock(&stp->st_mutex);
 
 	if (nfsd4_has_session(&resp->cstate)) {
 		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
@@ -4664,7 +4715,8 @@
 	struct nfs4_stid *s;
 	__be32 status = nfserr_bad_stateid;
 
-	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
+		CLOSE_STATEID(stateid))
 		return status;
 	/* Client debugging aid. */
 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
@@ -4711,8 +4763,19 @@
 		     struct nfs4_stid **s, struct nfsd_net *nn)
 {
 	__be32 status;
+	bool return_revoked = false;
 
-	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+	/*
+	 *  only return revoked delegations if explicitly asked.
+	 *  otherwise we report revoked or bad_stateid status.
+	 */
+	if (typemask & NFS4_REVOKED_DELEG_STID)
+		return_revoked = true;
+	else if (typemask & NFS4_DELEG_STID)
+		typemask |= NFS4_REVOKED_DELEG_STID;
+
+	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
+		CLOSE_STATEID(stateid))
 		return nfserr_bad_stateid;
 	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
 	if (status == nfserr_stale_clientid) {
@@ -4725,6 +4788,12 @@
 	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
 	if (!*s)
 		return nfserr_bad_stateid;
+	if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) {
+		nfs4_put_stid(*s);
+		if (cstate->minorversion)
+			return nfserr_deleg_revoked;
+		return nfserr_bad_stateid;
+	}
 	return nfs_ok;
 }
 
@@ -4872,6 +4941,32 @@
 	return nfs_ok;
 }
 
+static __be32
+nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
+{
+	struct nfs4_ol_stateid *stp = openlockstateid(s);
+	__be32 ret;
+
+	mutex_lock(&stp->st_mutex);
+
+	ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
+	if (ret)
+		goto out;
+
+	ret = nfserr_locks_held;
+	if (check_for_locks(stp->st_stid.sc_file,
+			    lockowner(stp->st_stateowner)))
+		goto out;
+
+	release_lock_stateid(stp);
+	ret = nfs_ok;
+
+out:
+	mutex_unlock(&stp->st_mutex);
+	nfs4_put_stid(s);
+	return ret;
+}
+
 __be32
 nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		   struct nfsd4_free_stateid *free_stateid)
@@ -4879,7 +4974,6 @@
 	stateid_t *stateid = &free_stateid->fr_stateid;
 	struct nfs4_stid *s;
 	struct nfs4_delegation *dp;
-	struct nfs4_ol_stateid *stp;
 	struct nfs4_client *cl = cstate->session->se_client;
 	__be32 ret = nfserr_bad_stateid;
 
@@ -4898,18 +4992,9 @@
 		ret = nfserr_locks_held;
 		break;
 	case NFS4_LOCK_STID:
-		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
-		if (ret)
-			break;
-		stp = openlockstateid(s);
-		ret = nfserr_locks_held;
-		if (check_for_locks(stp->st_stid.sc_file,
-				    lockowner(stp->st_stateowner)))
-			break;
-		WARN_ON(!unhash_lock_stateid(stp));
+		atomic_inc(&s->sc_count);
 		spin_unlock(&cl->cl_lock);
-		nfs4_put_stid(s);
-		ret = nfs_ok;
+		ret = nfsd4_free_lock_stateid(stateid, s);
 		goto out;
 	case NFS4_REVOKED_DELEG_STID:
 		dp = delegstateid(s);
@@ -4942,20 +5027,14 @@
 	status = nfsd4_check_seqid(cstate, sop, seqid);
 	if (status)
 		return status;
-	if (stp->st_stid.sc_type == NFS4_CLOSED_STID
-		|| stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
-		/*
-		 * "Closed" stateid's exist *only* to return
-		 * nfserr_replay_me from the previous step, and
-		 * revoked delegations are kept only for free_stateid.
-		 */
-		return nfserr_bad_stateid;
-	down_write(&stp->st_rwsem);
+	status = nfsd4_lock_ol_stateid(stp);
+	if (status != nfs_ok)
+		return status;
 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
 	if (status == nfs_ok)
 		status = nfs4_check_fh(current_fh, &stp->st_stid);
 	if (status != nfs_ok)
-		up_write(&stp->st_rwsem);
+		mutex_unlock(&stp->st_mutex);
 	return status;
 }
 
@@ -5003,7 +5082,7 @@
 		return status;
 	oo = openowner(stp->st_stateowner);
 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
-		up_write(&stp->st_rwsem);
+		mutex_unlock(&stp->st_mutex);
 		nfs4_put_stid(&stp->st_stid);
 		return nfserr_bad_stateid;
 	}
@@ -5035,12 +5114,12 @@
 	oo = openowner(stp->st_stateowner);
 	status = nfserr_bad_stateid;
 	if (oo->oo_flags & NFS4_OO_CONFIRMED) {
-		up_write(&stp->st_rwsem);
+		mutex_unlock(&stp->st_mutex);
 		goto put_stateid;
 	}
 	oo->oo_flags |= NFS4_OO_CONFIRMED;
 	nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid);
-	up_write(&stp->st_rwsem);
+	mutex_unlock(&stp->st_mutex);
 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
 
@@ -5116,7 +5195,7 @@
 	nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid);
 	status = nfs_ok;
 put_stateid:
-	up_write(&stp->st_rwsem);
+	mutex_unlock(&stp->st_mutex);
 	nfs4_put_stid(&stp->st_stid);
 out:
 	nfsd4_bump_seqid(cstate, status);
@@ -5129,7 +5208,6 @@
 	bool unhashed;
 	LIST_HEAD(reaplist);
 
-	s->st_stid.sc_type = NFS4_CLOSED_STID;
 	spin_lock(&clp->cl_lock);
 	unhashed = unhash_open_stateid(s, &reaplist);
 
@@ -5168,10 +5246,17 @@
 	nfsd4_bump_seqid(cstate, status);
 	if (status)
 		goto out; 
+
+	stp->st_stid.sc_type = NFS4_CLOSED_STID;
 	nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
-	up_write(&stp->st_rwsem);
 
 	nfsd4_close_open_stateid(stp);
+	mutex_unlock(&stp->st_mutex);
+
+	/* See RFC5661 sectionm 18.2.4 */
+	if (stp->st_stid.sc_client->cl_minorversion)
+		memcpy(&close->cl_stateid, &close_stateid,
+				sizeof(close->cl_stateid));
 
 	/* put reference from nfs4_preprocess_seqid_op */
 	nfs4_put_stid(&stp->st_stid);
@@ -5391,11 +5476,10 @@
 	stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
 	get_nfs4_file(fp);
 	stp->st_stid.sc_file = fp;
-	stp->st_stid.sc_free = nfs4_free_lock_stateid;
 	stp->st_access_bmap = 0;
 	stp->st_deny_bmap = open_stp->st_deny_bmap;
 	stp->st_openstp = open_stp;
-	init_rwsem(&stp->st_rwsem);
+	mutex_init(&stp->st_mutex);
 	list_add(&stp->st_locks, &open_stp->st_locks);
 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
 	spin_lock(&fp->fi_lock);
@@ -5434,7 +5518,7 @@
 	lst = find_lock_stateid(lo, fi);
 	if (lst == NULL) {
 		spin_unlock(&clp->cl_lock);
-		ns = nfs4_alloc_stid(clp, stateid_slab);
+		ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
 		if (ns == NULL)
 			return NULL;
 
@@ -5476,7 +5560,7 @@
 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
 			    struct nfs4_ol_stateid *ost,
 			    struct nfsd4_lock *lock,
-			    struct nfs4_ol_stateid **lst, bool *new)
+			    struct nfs4_ol_stateid **plst, bool *new)
 {
 	__be32 status;
 	struct nfs4_file *fi = ost->st_stid.sc_file;
@@ -5484,7 +5568,9 @@
 	struct nfs4_client *cl = oo->oo_owner.so_client;
 	struct inode *inode = d_inode(cstate->current_fh.fh_dentry);
 	struct nfs4_lockowner *lo;
+	struct nfs4_ol_stateid *lst;
 	unsigned int strhashval;
+	bool hashed;
 
 	lo = find_lockowner_str(cl, &lock->lk_new_owner);
 	if (!lo) {
@@ -5500,12 +5586,27 @@
 			goto out;
 	}
 
-	*lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
-	if (*lst == NULL) {
+retry:
+	lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
+	if (lst == NULL) {
 		status = nfserr_jukebox;
 		goto out;
 	}
+
+	mutex_lock(&lst->st_mutex);
+
+	/* See if it's still hashed to avoid race with FREE_STATEID */
+	spin_lock(&cl->cl_lock);
+	hashed = !list_empty(&lst->st_perfile);
+	spin_unlock(&cl->cl_lock);
+
+	if (!hashed) {
+		mutex_unlock(&lst->st_mutex);
+		nfs4_put_stid(&lst->st_stid);
+		goto retry;
+	}
 	status = nfs_ok;
+	*plst = lst;
 out:
 	nfs4_put_stateowner(&lo->lo_owner);
 	return status;
@@ -5564,7 +5665,7 @@
 					&open_stp, nn);
 		if (status)
 			goto out;
-		up_write(&open_stp->st_rwsem);
+		mutex_unlock(&open_stp->st_mutex);
 		open_sop = openowner(open_stp->st_stateowner);
 		status = nfserr_bad_stateid;
 		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
@@ -5572,8 +5673,6 @@
 			goto out;
 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
 							&lock_stp, &new);
-		if (status == nfs_ok)
-			down_write(&lock_stp->st_rwsem);
 	} else {
 		status = nfs4_preprocess_seqid_op(cstate,
 				       lock->lk_old_lock_seqid,
@@ -5677,7 +5776,7 @@
 		    seqid_mutating_err(ntohl(status)))
 			lock_sop->lo_owner.so_seqid++;
 
-		up_write(&lock_stp->st_rwsem);
+		mutex_unlock(&lock_stp->st_mutex);
 
 		/*
 		 * If this is a new, never-before-used stateid, and we are
@@ -5847,7 +5946,7 @@
 fput:
 	fput(filp);
 put_stateid:
-	up_write(&stp->st_rwsem);
+	mutex_unlock(&stp->st_mutex);
 	nfs4_put_stid(&stp->st_stid);
 out:
 	nfsd4_bump_seqid(cstate, status);
@@ -5911,6 +6010,7 @@
 	__be32 status;
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 	struct nfs4_client *clp;
+	LIST_HEAD (reaplist);
 
 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
 		clid->cl_boot, clid->cl_id);
@@ -5941,9 +6041,23 @@
 		nfs4_get_stateowner(sop);
 		break;
 	}
+	if (!lo) {
+		spin_unlock(&clp->cl_lock);
+		return status;
+	}
+
+	unhash_lockowner_locked(lo);
+	while (!list_empty(&lo->lo_owner.so_stateids)) {
+		stp = list_first_entry(&lo->lo_owner.so_stateids,
+				       struct nfs4_ol_stateid,
+				       st_perstateowner);
+		WARN_ON(!unhash_lock_stateid(stp));
+		put_ol_stateid_locked(stp, &reaplist);
+	}
 	spin_unlock(&clp->cl_lock);
-	if (lo)
-		release_lockowner(lo);
+	free_ol_stateid_reaplist(&reaplist);
+	nfs4_put_stateowner(&lo->lo_owner);
+
 	return status;
 }
 
@@ -6688,6 +6802,10 @@
 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
 	nn->conf_name_tree = RB_ROOT;
 	nn->unconf_name_tree = RB_ROOT;
+	nn->boot_time = get_seconds();
+	nn->grace_ended = false;
+	nn->nfsd4_manager.block_opens = true;
+	INIT_LIST_HEAD(&nn->nfsd4_manager.list);
 	INIT_LIST_HEAD(&nn->client_lru);
 	INIT_LIST_HEAD(&nn->close_lru);
 	INIT_LIST_HEAD(&nn->del_recall_lru);
@@ -6742,9 +6860,6 @@
 	ret = nfs4_state_create_net(net);
 	if (ret)
 		return ret;
-	nn->boot_time = get_seconds();
-	nn->grace_ended = false;
-	nn->nfsd4_manager.block_opens = true;
 	locks_start_grace(net, &nn->nfsd4_manager);
 	nfsd4_client_tracking_init(net);
 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
@@ -6762,23 +6877,24 @@
 
 	ret = set_callback_cred();
 	if (ret)
-		return -ENOMEM;
+		return ret;
+
 	laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
 	if (laundry_wq == NULL) {
 		ret = -ENOMEM;
-		goto out_recovery;
+		goto out_cleanup_cred;
 	}
 	ret = nfsd4_create_callback_queue();
 	if (ret)
 		goto out_free_laundry;
 
 	set_max_delegations();
-
 	return 0;
 
 out_free_laundry:
 	destroy_workqueue(laundry_wq);
-out_recovery:
+out_cleanup_cred:
+	cleanup_callback_cred();
 	return ret;
 }
 
@@ -6817,6 +6933,7 @@
 {
 	destroy_workqueue(laundry_wq);
 	nfsd4_destroy_callback_queue();
+	cleanup_callback_cred();
 }
 
 static void
--- linux-4.4.0.orig/fs/nfsd/nfs4xdr.c
+++ linux-4.4.0/fs/nfsd/nfs4xdr.c
@@ -129,7 +129,7 @@
 	argp->p = page_address(argp->pagelist[0]);
 	argp->pagelist++;
 	if (argp->pagelen < PAGE_SIZE) {
-		argp->end = argp->p + (argp->pagelen>>2);
+		argp->end = argp->p + XDR_QUADLEN(argp->pagelen);
 		argp->pagelen = 0;
 	} else {
 		argp->end = argp->p + (PAGE_SIZE>>2);
@@ -1072,8 +1072,9 @@
 
 	READ_BUF(4);
 	rename->rn_snamelen = be32_to_cpup(p++);
-	READ_BUF(rename->rn_snamelen + 4);
+	READ_BUF(rename->rn_snamelen);
 	SAVEMEM(rename->rn_sname, rename->rn_snamelen);
+	READ_BUF(4);
 	rename->rn_tnamelen = be32_to_cpup(p++);
 	READ_BUF(rename->rn_tnamelen);
 	SAVEMEM(rename->rn_tname, rename->rn_tnamelen);
@@ -1155,13 +1156,14 @@
 	READ_BUF(8);
 	setclientid->se_callback_prog = be32_to_cpup(p++);
 	setclientid->se_callback_netid_len = be32_to_cpup(p++);
-
-	READ_BUF(setclientid->se_callback_netid_len + 4);
+	READ_BUF(setclientid->se_callback_netid_len);
 	SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len);
+	READ_BUF(4);
 	setclientid->se_callback_addr_len = be32_to_cpup(p++);
 
-	READ_BUF(setclientid->se_callback_addr_len + 4);
+	READ_BUF(setclientid->se_callback_addr_len);
 	SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len);
+	READ_BUF(4);
 	setclientid->se_callback_ident = be32_to_cpup(p++);
 
 	DECODE_TAIL;
@@ -1244,9 +1246,7 @@
 		argp->pagelen -= pages * PAGE_SIZE;
 		len -= pages * PAGE_SIZE;
 
-		argp->p = (__be32 *)page_address(argp->pagelist[0]);
-		argp->pagelist++;
-		argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
+		next_decode_page(argp);
 	}
 	argp->p += XDR_QUADLEN(len);
 
@@ -1538,6 +1538,8 @@
 	gdev->gd_maxcount = be32_to_cpup(p++);
 	num = be32_to_cpup(p++);
 	if (num) {
+		if (num > 1000)
+			goto xdr_error;
 		READ_BUF(4 * num);
 		gdev->gd_notify_types = be32_to_cpup(p++);
 		for (i = 1; i < num; i++) {
@@ -1815,8 +1817,9 @@
 
 	READ_BUF(4);
 	argp->taglen = be32_to_cpup(p++);
-	READ_BUF(argp->taglen + 8);
+	READ_BUF(argp->taglen);
 	SAVEMEM(argp->tag, argp->taglen);
+	READ_BUF(8);
 	argp->minorversion = be32_to_cpup(p++);
 	argp->opcnt = be32_to_cpup(p++);
 	max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2);
@@ -2750,9 +2753,16 @@
 	}
 #endif /* CONFIG_NFSD_PNFS */
 	if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
-		status = nfsd4_encode_bitmap(xdr, NFSD_SUPPATTR_EXCLCREAT_WORD0,
-						  NFSD_SUPPATTR_EXCLCREAT_WORD1,
-						  NFSD_SUPPATTR_EXCLCREAT_WORD2);
+		u32 supp[3];
+
+		supp[0] = nfsd_suppattrs0(minorversion);
+		supp[1] = nfsd_suppattrs1(minorversion);
+		supp[2] = nfsd_suppattrs2(minorversion);
+		supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0;
+		supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1;
+		supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2;
+
+		status = nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]);
 		if (status)
 			goto out;
 	}
@@ -3587,7 +3597,8 @@
 		nfserr = nfserr_resource;
 		goto err_no_verf;
 	}
-	maxcount = min_t(u32, readdir->rd_maxcount, INT_MAX);
+	maxcount = svc_max_payload(resp->rqstp);
+	maxcount = min_t(u32, readdir->rd_maxcount, maxcount);
 	/*
 	 * Note the rfc defines rd_maxcount as the size of the
 	 * READDIR4resok structure, which includes the verifier above
@@ -3601,7 +3612,7 @@
 
 	/* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */
 	if (!readdir->rd_dircount)
-		readdir->rd_dircount = INT_MAX;
+		readdir->rd_dircount = svc_max_payload(resp->rqstp);
 
 	readdir->xdr = xdr;
 	readdir->rd_maxcount = maxcount;
@@ -4038,8 +4049,7 @@
 		struct nfsd4_getdeviceinfo *gdev)
 {
 	struct xdr_stream *xdr = &resp->xdr;
-	const struct nfsd4_layout_ops *ops =
-		nfsd4_layout_ops[gdev->gd_layout_type];
+	const struct nfsd4_layout_ops *ops;
 	u32 starting_len = xdr->buf->len, needed_len;
 	__be32 *p;
 
@@ -4056,6 +4066,7 @@
 
 	/* If maxcount is 0 then just update notifications */
 	if (gdev->gd_maxcount != 0) {
+		ops = nfsd4_layout_ops[gdev->gd_layout_type];
 		nfserr = ops->encode_getdeviceinfo(xdr, gdev);
 		if (nfserr) {
 			/*
@@ -4108,8 +4119,7 @@
 		struct nfsd4_layoutget *lgp)
 {
 	struct xdr_stream *xdr = &resp->xdr;
-	const struct nfsd4_layout_ops *ops =
-		nfsd4_layout_ops[lgp->lg_layout_type];
+	const struct nfsd4_layout_ops *ops;
 	__be32 *p;
 
 	dprintk("%s: err %d\n", __func__, nfserr);
@@ -4132,6 +4142,7 @@
 	*p++ = cpu_to_be32(lgp->lg_seg.iomode);
 	*p++ = cpu_to_be32(lgp->lg_layout_type);
 
+	ops = nfsd4_layout_ops[lgp->lg_layout_type];
 	nfserr = ops->encode_layoutget(xdr, lgp);
 out:
 	kfree(lgp->lg_content);
--- linux-4.4.0.orig/fs/nfsd/nfsctl.c
+++ linux-4.4.0/fs/nfsd/nfsctl.c
@@ -1106,6 +1106,8 @@
 		case 'Y':
 		case 'y':
 		case '1':
+			if (!nn->nfsd_serv)
+				return -EBUSY;
 			nfsd4_end_grace(nn);
 			break;
 		default:
@@ -1154,20 +1156,15 @@
 #endif
 		/* last one */ {""}
 	};
-	struct net *net = data;
-	int ret;
-
-	ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
-	if (ret)
-		return ret;
-	sb->s_fs_info = get_net(net);
-	return 0;
+	get_net(sb->s_fs_info);
+	return simple_fill_super(sb, 0x6e667364, nfsd_files);
 }
 
 static struct dentry *nfsd_mount(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data)
 {
-	return mount_ns(fs_type, flags, current->nsproxy->net_ns, nfsd_fill_super);
+	struct net *net = current->nsproxy->net_ns;
+	return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super);
 }
 
 static void nfsd_umount(struct super_block *sb)
--- linux-4.4.0.orig/fs/nfsd/nfsproc.c
+++ linux-4.4.0/fs/nfsd/nfsproc.c
@@ -74,10 +74,10 @@
 	 * which only requires access, and "set-[ac]time-to-X" which
 	 * requires ownership.
 	 * So if it looks like it might be "set both to the same time which
-	 * is close to now", and if inode_change_ok fails, then we
+	 * is close to now", and if setattr_prepare fails, then we
 	 * convert to "set to now" instead of "set to explicit time"
 	 *
-	 * We only call inode_change_ok as the last test as technically
+	 * We only call setattr_prepare as the last test as technically
 	 * it is not an interface that we should be using.
 	 */
 #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
@@ -92,17 +92,15 @@
 		 * request is.  We require it be within 30 minutes of now.
 		 */
 		time_t delta = iap->ia_atime.tv_sec - get_seconds();
-		struct inode *inode;
 
 		nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
 		if (nfserr)
 			goto done;
-		inode = d_inode(fhp->fh_dentry);
 
 		if (delta < 0)
 			delta = -delta;
 		if (delta < MAX_TOUCH_TIME_ERROR &&
-		    inode_change_ok(inode, iap) != 0) {
+		    setattr_prepare(fhp->fh_dentry, iap) != 0) {
 			/*
 			 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
 			 * This will cause notify_change to set these times
--- linux-4.4.0.orig/fs/nfsd/nfssvc.c
+++ linux-4.4.0/fs/nfsd/nfssvc.c
@@ -151,7 +151,8 @@
 
 int nfsd_minorversion(u32 minorversion, enum vers_op change)
 {
-	if (minorversion > NFSD_SUPPORTED_MINOR_VERSION)
+	if (minorversion > NFSD_SUPPORTED_MINOR_VERSION &&
+	    change != NFSD_AVAIL)
 		return -1;
 	switch(change) {
 	case NFSD_SET:
@@ -329,23 +330,20 @@
 
 void nfsd_reset_versions(void)
 {
-	int found_one = 0;
 	int i;
 
-	for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
-		if (nfsd_program.pg_vers[i])
-			found_one = 1;
-	}
-
-	if (!found_one) {
-		for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
-			nfsd_program.pg_vers[i] = nfsd_version[i];
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-		for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
-			nfsd_acl_program.pg_vers[i] =
-				nfsd_acl_version[i];
-#endif
-	}
+	for (i = 0; i < NFSD_NRVERS; i++)
+		if (nfsd_vers(i, NFSD_TEST))
+			return;
+
+	for (i = 0; i < NFSD_NRVERS; i++)
+		if (i != 4)
+			nfsd_vers(i, NFSD_SET);
+		else {
+			int minor = 0;
+			while (nfsd_minorversion(minor, NFSD_SET) >= 0)
+				minor++;
+		}
 }
 
 /*
@@ -362,7 +360,7 @@
  */
 static void set_max_drc(void)
 {
-	#define NFSD_DRC_SIZE_SHIFT	10
+	#define NFSD_DRC_SIZE_SHIFT	7
 	nfsd_drc_max_mem = (nr_free_buffer_pages()
 					>> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
 	nfsd_drc_mem_used = 0;
@@ -656,6 +654,37 @@
 	return nfserr;
 }
 
+/*
+ * A write procedure can have a large argument, and a read procedure can
+ * have a large reply, but no NFSv2 or NFSv3 procedure has argument and
+ * reply that can both be larger than a page.  The xdr code has taken
+ * advantage of this assumption to be a sloppy about bounds checking in
+ * some cases.  Pending a rewrite of the NFSv2/v3 xdr code to fix that
+ * problem, we enforce these assumptions here:
+ */
+static bool nfs_request_too_big(struct svc_rqst *rqstp,
+				struct svc_procedure *proc)
+{
+	/*
+	 * The ACL code has more careful bounds-checking and is not
+	 * susceptible to this problem:
+	 */
+	if (rqstp->rq_prog != NFS_PROGRAM)
+		return false;
+	/*
+	 * Ditto NFSv4 (which can in theory have argument and reply both
+	 * more than a page):
+	 */
+	if (rqstp->rq_vers >= 4)
+		return false;
+	/* The reply will be small, we're OK: */
+	if (proc->pc_xdrressize > 0 &&
+	    proc->pc_xdrressize < XDR_QUADLEN(PAGE_SIZE))
+		return false;
+
+	return rqstp->rq_arg.len > PAGE_SIZE;
+}
+
 int
 nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
 {
@@ -668,6 +697,11 @@
 				rqstp->rq_vers, rqstp->rq_proc);
 	proc = rqstp->rq_procinfo;
 
+	if (nfs_request_too_big(rqstp, proc)) {
+		dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers);
+		*statp = rpc_garbage_args;
+		return 1;
+	}
 	/*
 	 * Give the xdr decoder a chance to change this if it wants
 	 * (necessary in the NFSv4.0 compound case)
--- linux-4.4.0.orig/fs/nfsd/nfsxdr.c
+++ linux-4.4.0/fs/nfsd/nfsxdr.c
@@ -280,6 +280,7 @@
 					struct nfsd_writeargs *args)
 {
 	unsigned int len, hdr, dlen;
+	struct kvec *head = rqstp->rq_arg.head;
 	int v;
 
 	p = decode_fh(p, &args->fh);
@@ -300,9 +301,10 @@
 	 * Check to make sure that we got the right number of
 	 * bytes.
 	 */
-	hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
-	dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
-		- hdr;
+	hdr = (void*)p - head->iov_base;
+	if (hdr > head->iov_len)
+		return 0;
+	dlen = head->iov_len + rqstp->rq_arg.page_len - hdr;
 
 	/*
 	 * Round the length of the data which was specified up to
@@ -316,7 +318,7 @@
 		return 0;
 
 	rqstp->rq_vec[0].iov_base = (void*)p;
-	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
+	rqstp->rq_vec[0].iov_len = head->iov_len - hdr;
 	v = 0;
 	while (len > rqstp->rq_vec[v].iov_len) {
 		len -= rqstp->rq_vec[v].iov_len;
--- linux-4.4.0.orig/fs/nfsd/state.h
+++ linux-4.4.0/fs/nfsd/state.h
@@ -70,6 +70,7 @@
 	int cb_seq_status;
 	int cb_status;
 	bool cb_need_restart;
+	bool cb_holds_slot;
 };
 
 struct nfsd4_callback_ops {
@@ -535,7 +536,7 @@
 	unsigned char			st_access_bmap;
 	unsigned char			st_deny_bmap;
 	struct nfs4_ol_stateid		*st_openstp;
-	struct rw_semaphore		st_rwsem;
+	struct mutex			st_mutex;
 };
 
 static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)
@@ -583,8 +584,8 @@
 __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
 		     stateid_t *stateid, unsigned char typemask,
 		     struct nfs4_stid **s, struct nfsd_net *nn);
-struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
-		struct kmem_cache *slab);
+struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
+				  void (*sc_free)(struct nfs4_stid *));
 void nfs4_unhash_stid(struct nfs4_stid *s);
 void nfs4_put_stid(struct nfs4_stid *s);
 void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
@@ -595,6 +596,7 @@
 extern __be32 nfs4_check_open_reclaim(clientid_t *clid,
 		struct nfsd4_compound_state *cstate, struct nfsd_net *nn);
 extern int set_callback_cred(void);
+extern void cleanup_callback_cred(void);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
 extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
--- linux-4.4.0.orig/fs/nfsd/vfs.c
+++ linux-4.4.0/fs/nfsd/vfs.c
@@ -92,6 +92,12 @@
 	err = follow_down(&path);
 	if (err < 0)
 		goto out;
+	if (path.mnt == exp->ex_path.mnt && path.dentry == dentry &&
+	    nfsd_mountpoint(dentry, exp) == 2) {
+		/* This is only a mountpoint in some other namespace */
+		path_put(&path);
+		goto out;
+	}
 
 	exp2 = rqst_exp_get_by_name(rqstp, &path);
 	if (IS_ERR(exp2)) {
@@ -165,16 +171,26 @@
 /*
  * For nfsd purposes, we treat V4ROOT exports as though there was an
  * export at *every* directory.
+ * We return:
+ * '1' if this dentry *must* be an export point,
+ * '2' if it might be, if there is really a mount here, and
+ * '0' if there is no chance of an export point here.
  */
 int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp)
 {
-	if (d_mountpoint(dentry))
+	if (!d_inode(dentry))
+		return 0;
+	if (exp->ex_flags & NFSEXP_V4ROOT)
 		return 1;
 	if (nfsd4_is_junction(dentry))
 		return 1;
-	if (!(exp->ex_flags & NFSEXP_V4ROOT))
-		return 0;
-	return d_inode(dentry) != NULL;
+	if (d_mountpoint(dentry))
+		/*
+		 * Might only be a mountpoint in a different namespace,
+		 * but we need to check.
+		 */
+		return 2;
+	return 0;
 }
 
 __be32
@@ -369,12 +385,25 @@
 	__be32		err;
 	int		host_err;
 	bool		get_write_count;
-	int		size_change = 0;
+	bool		size_change = (iap->ia_valid & ATTR_SIZE);
 
-	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
+	if (iap->ia_valid & ATTR_SIZE) {
 		accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
-	if (iap->ia_valid & ATTR_SIZE)
 		ftype = S_IFREG;
+	}
+
+	/*
+	 * If utimes(2) and friends are called with times not NULL, we should
+	 * not set NFSD_MAY_WRITE bit. Otherwise fh_verify->nfsd_permission
+	 * will return EACCESS, when the caller's effective UID does not match
+	 * the owner of the file, and the caller is not privileged. In this
+	 * situation, we should return EPERM(notify_change will return this).
+	 */
+	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME)) {
+		accmode |= NFSD_MAY_OWNER_OVERRIDE;
+		if (!(iap->ia_valid & (ATTR_ATIME_SET | ATTR_MTIME_SET)))
+			accmode |= NFSD_MAY_WRITE;
+	}
 
 	/* Callers that do fh_verify should do the fh_want_write: */
 	get_write_count = !fhp->fh_dentry;
@@ -382,11 +411,11 @@
 	/* Get inode */
 	err = fh_verify(rqstp, fhp, ftype, accmode);
 	if (err)
-		goto out;
+		return err;
 	if (get_write_count) {
 		host_err = fh_want_write(fhp);
 		if (host_err)
-			return nfserrno(host_err);
+			goto out;
 	}
 
 	dentry = fhp->fh_dentry;
@@ -397,20 +426,28 @@
 		iap->ia_valid &= ~ATTR_MODE;
 
 	if (!iap->ia_valid)
-		goto out;
+		return 0;
 
 	nfsd_sanitize_attrs(inode, iap);
 
+	if (check_guard && guardtime != inode->i_ctime.tv_sec)
+		return nfserr_notsync;
+
 	/*
 	 * The size case is special, it changes the file in addition to the
-	 * attributes.
+	 * attributes, and file systems don't expect it to be mixed with
+	 * "random" attribute changes.  We thus split out the size change
+	 * into a separate call to ->setattr, and do the rest as a separate
+	 * setattr call.
 	 */
-	if (iap->ia_valid & ATTR_SIZE) {
+	if (size_change) {
 		err = nfsd_get_write_access(rqstp, fhp, iap);
 		if (err)
-			goto out;
-		size_change = 1;
+			return err;
+	}
 
+	fh_lock(fhp);
+	if (size_change) {
 		/*
 		 * RFC5661, Section 18.30.4:
 		 *   Changing the size of a file with SETATTR indirectly
@@ -418,29 +455,36 @@
 		 *
 		 * (and similar for the older RFCs)
 		 */
-		if (iap->ia_size != i_size_read(inode))
-			iap->ia_valid |= ATTR_MTIME;
-	}
+		struct iattr size_attr = {
+			.ia_valid	= ATTR_SIZE | ATTR_CTIME | ATTR_MTIME,
+			.ia_size	= iap->ia_size,
+		};
 
-	iap->ia_valid |= ATTR_CTIME;
+		host_err = notify_change(dentry, &size_attr, NULL);
+		if (host_err)
+			goto out_unlock;
+		iap->ia_valid &= ~ATTR_SIZE;
 
-	if (check_guard && guardtime != inode->i_ctime.tv_sec) {
-		err = nfserr_notsync;
-		goto out_put_write_access;
+		/*
+		 * Avoid the additional setattr call below if the only other
+		 * attribute that the client sends is the mtime, as we update
+		 * it as part of the size change above.
+		 */
+		if ((iap->ia_valid & ~ATTR_MTIME) == 0)
+			goto out_unlock;
 	}
 
-	fh_lock(fhp);
+	iap->ia_valid |= ATTR_CTIME;
 	host_err = notify_change(dentry, iap, NULL);
-	fh_unlock(fhp);
-	err = nfserrno(host_err);
 
-out_put_write_access:
+out_unlock:
+	fh_unlock(fhp);
 	if (size_change)
 		put_write_access(inode);
-	if (!err)
-		err = nfserrno(commit_metadata(fhp));
 out:
-	return err;
+	if (!host_err)
+		host_err = commit_metadata(fhp);
+	return nfserrno(host_err);
 }
 
 #if defined(CONFIG_NFSD_V4)
--- linux-4.4.0.orig/fs/nfsd/vfs.h
+++ linux-4.4.0/fs/nfsd/vfs.h
@@ -109,8 +109,11 @@
 
 static inline int fh_want_write(struct svc_fh *fh)
 {
-	int ret = mnt_want_write(fh->fh_export->ex_path.mnt);
+	int ret;
 
+	if (fh->fh_want_write)
+		return 0;
+	ret = mnt_want_write(fh->fh_export->ex_path.mnt);
 	if (!ret)
 		fh->fh_want_write = true;
 	return ret;
--- linux-4.4.0.orig/fs/nilfs2/btnode.c
+++ linux-4.4.0/fs/nilfs2/btnode.c
@@ -55,8 +55,7 @@
 		brelse(bh);
 		BUG();
 	}
-	memset(bh->b_data, 0, 1 << inode->i_blkbits);
-	bh->b_bdev = inode->i_sb->s_bdev;
+	memset(bh->b_data, 0, i_blocksize(inode));
 	bh->b_blocknr = blocknr;
 	set_buffer_mapped(bh);
 	set_buffer_uptodate(bh);
@@ -115,7 +114,6 @@
 		goto found;
 	}
 	set_buffer_mapped(bh);
-	bh->b_bdev = inode->i_sb->s_bdev;
 	bh->b_blocknr = pblocknr; /* set block address for read */
 	bh->b_end_io = end_buffer_read_sync;
 	get_bh(bh);
--- linux-4.4.0.orig/fs/nilfs2/dir.c
+++ linux-4.4.0/fs/nilfs2/dir.c
@@ -102,7 +102,7 @@
 	unlock_page(page);
 }
 
-static void nilfs_check_page(struct page *page)
+static bool nilfs_check_page(struct page *page)
 {
 	struct inode *dir = page->mapping->host;
 	struct super_block *sb = dir->i_sb;
@@ -132,12 +132,15 @@
 			goto Enamelen;
 		if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))
 			goto Espan;
+		if (unlikely(p->inode &&
+			     NILFS_PRIVATE_INODE(le64_to_cpu(p->inode))))
+			goto Einumber;
 	}
 	if (offs != limit)
 		goto Eend;
 out:
 	SetPageChecked(page);
-	return;
+	return true;
 
 	/* Too bad, we had an error */
 
@@ -158,6 +161,9 @@
 	goto bad_entry;
 Espan:
 	error = "directory entry across blocks";
+	goto bad_entry;
+Einumber:
+	error = "disallowed inode number";
 bad_entry:
 	nilfs_error(sb, "nilfs_check_page", "bad entry in directory #%lu: %s - "
 		    "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
@@ -173,23 +179,28 @@
 		    dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
 		    (unsigned long) le64_to_cpu(p->inode));
 fail:
-	SetPageChecked(page);
 	SetPageError(page);
+	return false;
 }
 
-static struct page *nilfs_get_page(struct inode *dir, unsigned long n)
+static void *nilfs_get_page(struct inode *dir, unsigned long n,
+		struct page **pagep)
 {
 	struct address_space *mapping = dir->i_mapping;
 	struct page *page = read_mapping_page(mapping, n, NULL);
+	void *kaddr;
+
+	if (IS_ERR(page))
+		return page;
 
-	if (!IS_ERR(page)) {
-		kmap(page);
-		if (!PageChecked(page))
-			nilfs_check_page(page);
-		if (PageError(page))
+	kaddr = kmap(page);
+	if (unlikely(!PageChecked(page))) {
+		if (!nilfs_check_page(page))
 			goto fail;
 	}
-	return page;
+
+	*pagep = page;
+	return kaddr;
 
 fail:
 	nilfs_put_page(page);
@@ -267,15 +278,15 @@
 	for ( ; n < npages; n++, offset = 0) {
 		char *kaddr, *limit;
 		struct nilfs_dir_entry *de;
-		struct page *page = nilfs_get_page(inode, n);
+		struct page *page;
 
-		if (IS_ERR(page)) {
+		kaddr = nilfs_get_page(inode, n, &page);
+		if (IS_ERR(kaddr)) {
 			nilfs_error(sb, __func__, "bad page in #%lu",
 				    inode->i_ino);
 			ctx->pos += PAGE_CACHE_SIZE - offset;
 			return -EIO;
 		}
-		kaddr = page_address(page);
 		de = (struct nilfs_dir_entry *)(kaddr + offset);
 		limit = kaddr + nilfs_last_byte(inode, n) -
 			NILFS_DIR_REC_LEN(1);
@@ -314,6 +325,8 @@
  * returns the page in which the entry was found, and the entry itself
  * (as a parameter - res_dir). Page is returned mapped and unlocked.
  * Entry is guaranteed to be valid.
+ *
+ * On failure, returns an error pointer and the caller should ignore res_page.
  */
 struct nilfs_dir_entry *
 nilfs_find_entry(struct inode *dir, const struct qstr *qstr,
@@ -339,25 +352,26 @@
 		start = 0;
 	n = start;
 	do {
-		char *kaddr;
-		page = nilfs_get_page(dir, n);
-		if (!IS_ERR(page)) {
-			kaddr = page_address(page);
-			de = (struct nilfs_dir_entry *)kaddr;
-			kaddr += nilfs_last_byte(dir, n) - reclen;
-			while ((char *) de <= kaddr) {
-				if (de->rec_len == 0) {
-					nilfs_error(dir->i_sb, __func__,
-						"zero-length directory entry");
-					nilfs_put_page(page);
-					goto out;
-				}
-				if (nilfs_match(namelen, name, de))
-					goto found;
-				de = nilfs_next_entry(de);
+		char *kaddr = nilfs_get_page(dir, n, &page);
+
+		if (IS_ERR(kaddr))
+			return ERR_CAST(kaddr);
+
+		de = (struct nilfs_dir_entry *)kaddr;
+		kaddr += nilfs_last_byte(dir, n) - reclen;
+		while ((char *) de <= kaddr) {
+			if (de->rec_len == 0) {
+				nilfs_error(dir->i_sb, __func__,
+					"zero-length directory entry");
+				nilfs_put_page(page);
+				goto out;
 			}
-			nilfs_put_page(page);
+			if (nilfs_match(namelen, name, de))
+				goto found;
+			de = nilfs_next_entry(de);
 		}
+		nilfs_put_page(page);
+
 		if (++n >= npages)
 			n = 0;
 		/* next page is past the blocks we've got */
@@ -370,7 +384,7 @@
 		}
 	} while (n != start);
 out:
-	return NULL;
+	return ERR_PTR(-ENOENT);
 
 found:
 	*res_page = page;
@@ -380,30 +394,27 @@
 
 struct nilfs_dir_entry *nilfs_dotdot(struct inode *dir, struct page **p)
 {
-	struct page *page = nilfs_get_page(dir, 0);
-	struct nilfs_dir_entry *de = NULL;
+	struct nilfs_dir_entry *de = nilfs_get_page(dir, 0, p);
 
-	if (!IS_ERR(page)) {
-		de = nilfs_next_entry(
-			(struct nilfs_dir_entry *)page_address(page));
-		*p = page;
-	}
-	return de;
+	if (IS_ERR(de))
+		return NULL;
+	return nilfs_next_entry(de);
 }
 
-ino_t nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr)
+int nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr, ino_t *ino)
 {
-	ino_t res = 0;
 	struct nilfs_dir_entry *de;
 	struct page *page;
 
 	de = nilfs_find_entry(dir, qstr, &page);
-	if (de) {
-		res = le64_to_cpu(de->inode);
-		kunmap(page);
-		page_cache_release(page);
-	}
-	return res;
+	if (IS_ERR(de))
+		return PTR_ERR(de);
+
+	*ino = le64_to_cpu(de->inode);
+	kunmap(page);
+	page_cache_release(page);
+
+	return 0;
 }
 
 /* Releases the page */
@@ -452,12 +463,11 @@
 	for (n = 0; n <= npages; n++) {
 		char *dir_end;
 
-		page = nilfs_get_page(dir, n);
-		err = PTR_ERR(page);
-		if (IS_ERR(page))
+		kaddr = nilfs_get_page(dir, n, &page);
+		err = PTR_ERR(kaddr);
+		if (IS_ERR(kaddr))
 			goto out;
 		lock_page(page);
-		kaddr = page_address(page);
 		dir_end = kaddr + nilfs_last_byte(dir, n);
 		de = (struct nilfs_dir_entry *)kaddr;
 		kaddr += PAGE_CACHE_SIZE - reclen;
@@ -619,11 +629,10 @@
 		char *kaddr;
 		struct nilfs_dir_entry *de;
 
-		page = nilfs_get_page(inode, i);
-		if (IS_ERR(page))
+		kaddr = nilfs_get_page(inode, i, &page);
+		if (IS_ERR(kaddr))
 			continue;
 
-		kaddr = page_address(page);
 		de = (struct nilfs_dir_entry *)kaddr;
 		kaddr += nilfs_last_byte(inode, i) - NILFS_DIR_REC_LEN(1);
 
--- linux-4.4.0.orig/fs/nilfs2/gcinode.c
+++ linux-4.4.0/fs/nilfs2/gcinode.c
@@ -87,10 +87,8 @@
 		struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
 
 		err = nilfs_dat_translate(nilfs->ns_dat, vbn, &pbn);
-		if (unlikely(err)) { /* -EIO, -ENOMEM, -ENOENT */
-			brelse(bh);
+		if (unlikely(err)) /* -EIO, -ENOMEM, -ENOENT */
 			goto failed;
-		}
 	}
 
 	lock_buffer(bh);
@@ -99,10 +97,8 @@
 		goto out;
 	}
 
-	if (!buffer_mapped(bh)) {
-		bh->b_bdev = inode->i_sb->s_bdev;
+	if (!buffer_mapped(bh))
 		set_buffer_mapped(bh);
-	}
 	bh->b_blocknr = pbn;
 	bh->b_end_io = end_buffer_read_sync;
 	get_bh(bh);
@@ -116,6 +112,8 @@
  failed:
 	unlock_page(bh->b_page);
 	page_cache_release(bh->b_page);
+	if (unlikely(err))
+		brelse(bh);
 	return err;
 }
 
--- linux-4.4.0.orig/fs/nilfs2/inode.c
+++ linux-4.4.0/fs/nilfs2/inode.c
@@ -55,7 +55,7 @@
 {
 	struct nilfs_root *root = NILFS_I(inode)->i_root;
 
-	inode_add_bytes(inode, (1 << inode->i_blkbits) * n);
+	inode_add_bytes(inode, i_blocksize(inode) * n);
 	if (root)
 		atomic64_add(n, &root->blocks_count);
 }
@@ -64,7 +64,7 @@
 {
 	struct nilfs_root *root = NILFS_I(inode)->i_root;
 
-	inode_sub_bytes(inode, (1 << inode->i_blkbits) * n);
+	inode_sub_bytes(inode, i_blocksize(inode) * n);
 	if (root)
 		atomic64_sub(n, &root->blocks_count);
 }
@@ -348,6 +348,7 @@
 	struct inode *inode;
 	struct nilfs_inode_info *ii;
 	struct nilfs_root *root;
+	struct buffer_head *bh;
 	int err = -ENOMEM;
 	ino_t ino;
 
@@ -363,11 +364,26 @@
 	ii->i_state = 1 << NILFS_I_NEW;
 	ii->i_root = root;
 
-	err = nilfs_ifile_create_inode(root->ifile, &ino, &ii->i_bh);
+	err = nilfs_ifile_create_inode(root->ifile, &ino, &bh);
 	if (unlikely(err))
 		goto failed_ifile_create_inode;
 	/* reference count of i_bh inherits from nilfs_mdt_read_block() */
 
+	if (unlikely(ino < NILFS_USER_INO)) {
+		printk(KERN_WARNING
+			  "inode bitmap is inconsistent for reserved inodes");
+		do {
+			brelse(bh);
+			err = nilfs_ifile_create_inode(root->ifile, &ino, &bh);
+			if (unlikely(err))
+				goto failed_ifile_create_inode;
+		} while (ino < NILFS_USER_INO);
+
+		printk(KERN_INFO
+			  "repaired inode bitmap for reserved inodes");
+	}
+	ii->i_bh = bh;
+
 	atomic64_inc(&root->inodes_count);
 	inode_init_owner(inode, dir, mode);
 	inode->i_ino = ino;
@@ -456,6 +472,8 @@
 	inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);
 	inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec);
 	inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);
+	if (inode->i_private != NULL && !S_ISREG(inode->i_mode))
+		return -EIO; /* this inode is for metadata and corrupted */
 	if (inode->i_nlink == 0)
 		return -ESTALE; /* this inode is deleted */
 
@@ -821,7 +839,7 @@
 	struct super_block *sb = inode->i_sb;
 	int err;
 
-	err = inode_change_ok(inode, iattr);
+	err = setattr_prepare(dentry, iattr);
 	if (err)
 		return err;
 
--- linux-4.4.0.orig/fs/nilfs2/mdt.c
+++ linux-4.4.0/fs/nilfs2/mdt.c
@@ -60,7 +60,7 @@
 	set_buffer_mapped(bh);
 
 	kaddr = kmap_atomic(bh->b_page);
-	memset(kaddr + bh_offset(bh), 0, 1 << inode->i_blkbits);
+	memset(kaddr + bh_offset(bh), 0, i_blocksize(inode));
 	if (init_block)
 		init_block(inode, bh, kaddr);
 	flush_dcache_page(bh->b_page);
@@ -101,7 +101,6 @@
 	if (buffer_uptodate(bh))
 		goto failed_bh;
 
-	bh->b_bdev = sb->s_bdev;
 	err = nilfs_mdt_insert_new_block(inode, block, bh, init_block);
 	if (likely(!err)) {
 		get_bh(bh);
@@ -503,7 +502,7 @@
 	struct nilfs_mdt_info *mi = NILFS_MDT(inode);
 
 	mi->mi_entry_size = entry_size;
-	mi->mi_entries_per_block = (1 << inode->i_blkbits) / entry_size;
+	mi->mi_entries_per_block = i_blocksize(inode) / entry_size;
 	mi->mi_first_entry_offset = DIV_ROUND_UP(header_size, entry_size);
 }
 
--- linux-4.4.0.orig/fs/nilfs2/namei.c
+++ linux-4.4.0/fs/nilfs2/namei.c
@@ -50,8 +50,7 @@
 {
 	int err = nilfs_add_link(dentry, inode);
 	if (!err) {
-		d_instantiate(dentry, inode);
-		unlock_new_inode(inode);
+		d_instantiate_new(dentry, inode);
 		return 0;
 	}
 	inode_dec_link_count(inode);
@@ -69,12 +68,20 @@
 {
 	struct inode *inode;
 	ino_t ino;
+	int res;
 
 	if (dentry->d_name.len > NILFS_NAME_LEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
-	ino = nilfs_inode_by_name(dir, &dentry->d_name);
-	inode = ino ? nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino) : NULL;
+	res = nilfs_inode_by_name(dir, &dentry->d_name, &ino);
+	if (res) {
+		if (res != -ENOENT)
+			return ERR_PTR(res);
+		inode = NULL;
+	} else {
+		inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino);
+	}
+
 	return d_splice_alias(inode, dentry);
 }
 
@@ -246,8 +253,7 @@
 		goto out_fail;
 
 	nilfs_mark_inode_dirty(inode);
-	d_instantiate(dentry, inode);
-	unlock_new_inode(inode);
+	d_instantiate_new(dentry, inode);
 out:
 	if (!err)
 		err = nilfs_transaction_commit(dir->i_sb);
@@ -275,10 +281,11 @@
 	struct page *page;
 	int err;
 
-	err = -ENOENT;
 	de = nilfs_find_entry(dir, &dentry->d_name, &page);
-	if (!de)
+	if (IS_ERR(de)) {
+		err = PTR_ERR(de);
 		goto out;
+	}
 
 	inode = d_inode(dentry);
 	err = -EIO;
@@ -368,10 +375,11 @@
 	if (unlikely(err))
 		return err;
 
-	err = -ENOENT;
 	old_de = nilfs_find_entry(old_dir, &old_dentry->d_name, &old_page);
-	if (!old_de)
+	if (IS_ERR(old_de)) {
+		err = PTR_ERR(old_de);
 		goto out;
+	}
 
 	if (S_ISDIR(old_inode->i_mode)) {
 		err = -EIO;
@@ -388,10 +396,12 @@
 		if (dir_de && !nilfs_empty_dir(new_inode))
 			goto out_dir;
 
-		err = -ENOENT;
-		new_de = nilfs_find_entry(new_dir, &new_dentry->d_name, &new_page);
-		if (!new_de)
+		new_de = nilfs_find_entry(new_dir, &new_dentry->d_name,
+					  &new_page);
+		if (IS_ERR(new_de)) {
+			err = PTR_ERR(new_de);
 			goto out_dir;
+		}
 		nilfs_set_link(new_dir, new_de, new_page, old_inode);
 		nilfs_mark_inode_dirty(new_dir);
 		new_inode->i_ctime = CURRENT_TIME;
@@ -445,14 +455,15 @@
  */
 static struct dentry *nilfs_get_parent(struct dentry *child)
 {
-	unsigned long ino;
+	ino_t ino;
+	int res;
 	struct inode *inode;
 	struct qstr dotdot = QSTR_INIT("..", 2);
 	struct nilfs_root *root;
 
-	ino = nilfs_inode_by_name(d_inode(child), &dotdot);
-	if (!ino)
-		return ERR_PTR(-ENOENT);
+	res = nilfs_inode_by_name(d_inode(child), &dotdot, &ino);
+	if (res)
+		return ERR_PTR(res);
 
 	root = NILFS_I(d_inode(child))->i_root;
 
--- linux-4.4.0.orig/fs/nilfs2/nilfs.h
+++ linux-4.4.0/fs/nilfs2/nilfs.h
@@ -135,6 +135,11 @@
 #define NILFS_VALID_INODE(sb, ino) \
 	((ino) >= NILFS_FIRST_INO(sb) || (NILFS_SYS_INO_BITS & (1 << (ino))))
 
+#define NILFS_PRIVATE_INODE(ino) ({					\
+	ino_t __ino = (ino);						\
+	((__ino) < NILFS_USER_INO && (__ino) != NILFS_ROOT_INO &&	\
+	 (__ino) != NILFS_SKETCH_INO); })
+
 /**
  * struct nilfs_transaction_info: context information for synchronization
  * @ti_magic: Magic number
@@ -235,7 +240,7 @@
 
 /* dir.c */
 extern int nilfs_add_link(struct dentry *, struct inode *);
-extern ino_t nilfs_inode_by_name(struct inode *, const struct qstr *);
+int nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr, ino_t *ino);
 extern int nilfs_make_empty(struct inode *, struct inode *);
 extern struct nilfs_dir_entry *
 nilfs_find_entry(struct inode *, const struct qstr *, struct page **);
--- linux-4.4.0.orig/fs/nilfs2/page.c
+++ linux-4.4.0/fs/nilfs2/page.c
@@ -53,7 +53,6 @@
 	first_block = (unsigned long)index << (PAGE_CACHE_SHIFT - blkbits);
 	bh = nilfs_page_get_nth_block(page, block - first_block);
 
-	touch_buffer(bh);
 	wait_on_buffer(bh);
 	return bh;
 }
@@ -78,6 +77,7 @@
 		page_cache_release(page);
 		return NULL;
 	}
+	bh->b_bdev = inode->i_sb->s_bdev;
 	return bh;
 }
 
@@ -92,7 +92,8 @@
 	const unsigned long clear_bits =
 		(1 << BH_Uptodate | 1 << BH_Dirty | 1 << BH_Mapped |
 		 1 << BH_Async_Write | 1 << BH_NILFS_Volatile |
-		 1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected);
+		 1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected |
+		 1 << BH_Delay);
 
 	lock_buffer(bh);
 	set_mask_bits(&bh->b_state, clear_bits, 0);
@@ -400,6 +401,11 @@
  * nilfs_clear_dirty_page - discard dirty page
  * @page: dirty page that will be discarded
  * @silent: suppress [true] or print [false] warning messages
+ *
+ * nilfs_clear_dirty_page() clears working states including dirty state for
+ * the page and its buffers.  If the page has buffers, clear only if it is
+ * confirmed that none of the buffer heads are busy (none have valid
+ * references and none are locked).
  */
 void nilfs_clear_dirty_page(struct page *page, bool silent)
 {
@@ -418,13 +424,33 @@
 	ClearPageMappedToDisk(page);
 
 	if (page_has_buffers(page)) {
-		struct buffer_head *bh, *head;
+		struct buffer_head *bh, *head = page_buffers(page);
 		const unsigned long clear_bits =
 			(1 << BH_Uptodate | 1 << BH_Dirty | 1 << BH_Mapped |
 			 1 << BH_Async_Write | 1 << BH_NILFS_Volatile |
-			 1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected);
+			 1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected |
+			 1 << BH_Delay);
+		bool busy, invalidated = false;
+
+recheck_buffers:
+		busy = false;
+		bh = head;
+		do {
+			if (atomic_read(&bh->b_count) | buffer_locked(bh)) {
+				busy = true;
+				break;
+			}
+		} while (bh = bh->b_this_page, bh != head);
 
-		bh = head = page_buffers(page);
+		if (busy) {
+			if (invalidated)
+				return;
+			invalidate_bh_lrus();
+			invalidated = true;
+			goto recheck_buffers;
+		}
+
+		bh = head;
 		do {
 			lock_buffer(bh);
 			if (!silent) {
@@ -437,6 +463,9 @@
 		} while (bh = bh->b_this_page, bh != head);
 	}
 
+	ClearPageUptodate(page);
+	ClearPageMappedToDisk(page);
+	ClearPageChecked(page);
 	__nilfs_clear_page_dirty(page);
 }
 
--- linux-4.4.0.orig/fs/nilfs2/segment.c
+++ linux-4.4.0/fs/nilfs2/segment.c
@@ -719,8 +719,7 @@
 
 		lock_page(page);
 		if (!page_has_buffers(page))
-			create_empty_buffers(page, 1 << inode->i_blkbits, 0);
-		unlock_page(page);
+			create_empty_buffers(page, i_blocksize(inode), 0);
 
 		bh = head = page_buffers(page);
 		do {
@@ -730,11 +729,14 @@
 			list_add_tail(&bh->b_assoc_buffers, listp);
 			ndirties++;
 			if (unlikely(ndirties >= nlimit)) {
+				unlock_page(page);
 				pagevec_release(&pvec);
 				cond_resched();
 				return ndirties;
 			}
 		} while (bh = bh->b_this_page, bh != head);
+
+		unlock_page(page);
 	}
 	pagevec_release(&pvec);
 	cond_resched();
@@ -1664,7 +1666,6 @@
 
 		list_for_each_entry(bh, &segbuf->sb_payload_buffers,
 				    b_assoc_buffers) {
-			set_buffer_async_write(bh);
 			if (bh == segbuf->sb_super_root) {
 				if (bh->b_page != bd_page) {
 					lock_page(bd_page);
@@ -1675,6 +1676,7 @@
 				}
 				break;
 			}
+			set_buffer_async_write(bh);
 			if (bh->b_page != fs_page) {
 				nilfs_begin_page_io(fs_page);
 				fs_page = bh->b_page;
@@ -1759,7 +1761,6 @@
 
 		list_for_each_entry(bh, &segbuf->sb_payload_buffers,
 				    b_assoc_buffers) {
-			clear_buffer_async_write(bh);
 			if (bh == segbuf->sb_super_root) {
 				if (bh->b_page != bd_page) {
 					end_page_writeback(bd_page);
@@ -1767,6 +1768,7 @@
 				}
 				break;
 			}
+			clear_buffer_async_write(bh);
 			if (bh->b_page != fs_page) {
 				nilfs_end_page_io(fs_page, err);
 				fs_page = bh->b_page;
@@ -1854,8 +1856,9 @@
 				 1 << BH_Delay | 1 << BH_NILFS_Volatile |
 				 1 << BH_NILFS_Redirected);
 
-			set_mask_bits(&bh->b_state, clear_bits, set_bits);
 			if (bh == segbuf->sb_super_root) {
+				set_buffer_uptodate(bh);
+				clear_buffer_dirty(bh);
 				if (bh->b_page != bd_page) {
 					end_page_writeback(bd_page);
 					bd_page = bh->b_page;
@@ -1863,6 +1866,7 @@
 				update_sr = true;
 				break;
 			}
+			set_mask_bits(&bh->b_state, clear_bits, set_bits);
 			if (bh->b_page != fs_page) {
 				nilfs_end_page_io(fs_page, 0);
 				fs_page = bh->b_page;
@@ -1945,8 +1949,6 @@
 					      "failed to get inode block.\n");
 				return err;
 			}
-			mark_buffer_dirty(ibh);
-			nilfs_mdt_mark_dirty(ifile);
 			spin_lock(&nilfs->ns_inode_lock);
 			if (likely(!ii->i_bh))
 				ii->i_bh = ibh;
@@ -1955,6 +1957,10 @@
 			goto retry;
 		}
 
+		// Always redirty the buffer to avoid race condition
+		mark_buffer_dirty(ii->i_bh);
+		nilfs_mdt_mark_dirty(ifile);
+
 		clear_bit(NILFS_I_QUEUED, &ii->i_state);
 		set_bit(NILFS_I_BUSY, &ii->i_state);
 		list_move_tail(&ii->i_dirty, &sci->sc_dirty_files);
@@ -2111,8 +2117,10 @@
 {
 	spin_lock(&sci->sc_state_lock);
 	if (!(sci->sc_state & NILFS_SEGCTOR_COMMIT)) {
-		sci->sc_timer.expires = jiffies + sci->sc_interval;
-		add_timer(&sci->sc_timer);
+		if (sci->sc_task) {
+			sci->sc_timer.expires = jiffies + sci->sc_interval;
+			add_timer(&sci->sc_timer);
+		}
 		sci->sc_state |= NILFS_SEGCTOR_COMMIT;
 	}
 	spin_unlock(&sci->sc_state_lock);
@@ -2316,10 +2324,21 @@
  */
 static void nilfs_segctor_accept(struct nilfs_sc_info *sci)
 {
+	bool thread_is_alive;
+
 	spin_lock(&sci->sc_state_lock);
 	sci->sc_seq_accepted = sci->sc_seq_request;
+	thread_is_alive = (bool)sci->sc_task;
 	spin_unlock(&sci->sc_state_lock);
-	del_timer_sync(&sci->sc_timer);
+
+	/*
+	 * This function does not race with the log writer thread's
+	 * termination.  Therefore, deleting sc_timer, which should not be
+	 * done after the log writer thread exits, can be done safely outside
+	 * the area protected by sc_state_lock.
+	 */
+	if (thread_is_alive)
+		del_timer_sync(&sci->sc_timer);
 }
 
 /**
@@ -2345,7 +2364,7 @@
 			sci->sc_flush_request &= ~FLUSH_DAT_BIT;
 
 		/* re-enable timer if checkpoint creation was not done */
-		if ((sci->sc_state & NILFS_SEGCTOR_COMMIT) &&
+		if ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && sci->sc_task &&
 		    time_before(jiffies, sci->sc_timer.expires))
 			add_timer(&sci->sc_timer);
 	}
@@ -2392,10 +2411,11 @@
 	return err;
 }
 
-static void nilfs_construction_timeout(unsigned long data)
+static void nilfs_construction_timeout(struct timer_list *t)
 {
-	struct task_struct *p = (struct task_struct *)data;
-	wake_up_process(p);
+	struct nilfs_sc_info *sci = from_timer(sci, t, sc_timer);
+
+	wake_up_process(sci->sc_timer_task);
 }
 
 static void
@@ -2534,8 +2554,8 @@
 	struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
 	int timeout = 0;
 
-	sci->sc_timer.data = (unsigned long)current;
-	sci->sc_timer.function = nilfs_construction_timeout;
+	sci->sc_timer_task = current;
+	timer_setup(&sci->sc_timer, nilfs_construction_timeout, 0);
 
 	/* start sync. */
 	sci->sc_task = current;
@@ -2605,6 +2625,7 @@
 
 	/* end sync. */
 	sci->sc_task = NULL;
+	del_timer_sync(&sci->sc_timer);
 	wake_up(&sci->sc_wait_task); /* for nilfs_segctor_kill_thread() */
 	return 0;
 }
@@ -2667,7 +2688,6 @@
 	INIT_LIST_HEAD(&sci->sc_gc_inodes);
 	INIT_LIST_HEAD(&sci->sc_iput_queue);
 	INIT_WORK(&sci->sc_iput_work, nilfs_iput_work_func);
-	init_timer(&sci->sc_timer);
 
 	sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT;
 	sci->sc_mjcp_freq = HZ * NILFS_SC_DEFAULT_SR_FREQ;
@@ -2744,7 +2764,6 @@
 
 	down_write(&nilfs->ns_segctor_sem);
 
-	del_timer_sync(&sci->sc_timer);
 	kfree(sci);
 }
 
@@ -2779,11 +2798,12 @@
 	if (!nilfs->ns_writer)
 		return -ENOMEM;
 
+	inode_attach_wb(nilfs->ns_bdev->bd_inode, NULL);
+
 	err = nilfs_segctor_start_thread(nilfs->ns_writer);
-	if (err) {
-		kfree(nilfs->ns_writer);
-		nilfs->ns_writer = NULL;
-	}
+	if (unlikely(err))
+		nilfs_detach_log_writer(sb);
+
 	return err;
 }
 
--- linux-4.4.0.orig/fs/nilfs2/segment.h
+++ linux-4.4.0/fs/nilfs2/segment.h
@@ -185,6 +185,7 @@
 	unsigned long		sc_watermark;
 
 	struct timer_list	sc_timer;
+	struct task_struct     *sc_timer_task;
 	struct task_struct     *sc_task;
 };
 
--- linux-4.4.0.orig/fs/nilfs2/super.c
+++ linux-4.4.0/fs/nilfs2/super.c
@@ -1079,7 +1079,7 @@
 	sb->s_time_gran = 1;
 	sb->s_max_links = NILFS_LINK_MAX;
 
-	sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info;
+	sb->s_bdi = bdev_get_queue(sb->s_bdev)->backing_dev_info;
 
 	err = load_nilfs(nilfs, sb);
 	if (err)
--- linux-4.4.0.orig/fs/nilfs2/sysfs.c
+++ linux-4.4.0/fs/nilfs2/sysfs.c
@@ -854,9 +854,15 @@
 				struct the_nilfs *nilfs,
 				char *buf)
 {
-	struct nilfs_super_block **sbp = nilfs->ns_sbp;
-	u32 major = le32_to_cpu(sbp[0]->s_rev_level);
-	u16 minor = le16_to_cpu(sbp[0]->s_minor_rev_level);
+	struct nilfs_super_block *raw_sb;
+	u32 major;
+	u16 minor;
+
+	down_read(&nilfs->ns_sem);
+	raw_sb = nilfs->ns_sbp[0];
+	major = le32_to_cpu(raw_sb->s_rev_level);
+	minor = le16_to_cpu(raw_sb->s_minor_rev_level);
+	up_read(&nilfs->ns_sem);
 
 	return snprintf(buf, PAGE_SIZE, "%d.%d\n", major, minor);
 }
@@ -874,8 +880,13 @@
 				    struct the_nilfs *nilfs,
 				    char *buf)
 {
-	struct nilfs_super_block **sbp = nilfs->ns_sbp;
-	u64 dev_size = le64_to_cpu(sbp[0]->s_dev_size);
+	struct nilfs_super_block *raw_sb;
+	u64 dev_size;
+
+	down_read(&nilfs->ns_sem);
+	raw_sb = nilfs->ns_sbp[0];
+	dev_size = le64_to_cpu(raw_sb->s_dev_size);
+	up_read(&nilfs->ns_sem);
 
 	return snprintf(buf, PAGE_SIZE, "%llu\n", dev_size);
 }
@@ -897,9 +908,15 @@
 			    struct the_nilfs *nilfs,
 			    char *buf)
 {
-	struct nilfs_super_block **sbp = nilfs->ns_sbp;
+	struct nilfs_super_block *raw_sb;
+	ssize_t len;
+
+	down_read(&nilfs->ns_sem);
+	raw_sb = nilfs->ns_sbp[0];
+	len = sysfs_emit(buf, "%pUb\n", raw_sb->s_uuid);
+	up_read(&nilfs->ns_sem);
 
-	return snprintf(buf, PAGE_SIZE, "%pUb\n", sbp[0]->s_uuid);
+	return len;
 }
 
 static
@@ -907,10 +924,16 @@
 				    struct the_nilfs *nilfs,
 				    char *buf)
 {
-	struct nilfs_super_block **sbp = nilfs->ns_sbp;
+	struct nilfs_super_block *raw_sb;
+	ssize_t len;
+
+	down_read(&nilfs->ns_sem);
+	raw_sb = nilfs->ns_sbp[0];
+	len = scnprintf(buf, sizeof(raw_sb->s_volume_name), "%s\n",
+			raw_sb->s_volume_name);
+	up_read(&nilfs->ns_sem);
 
-	return scnprintf(buf, sizeof(sbp[0]->s_volume_name), "%s\n",
-			 sbp[0]->s_volume_name);
+	return len;
 }
 
 static const char dev_readme_str[] =
--- linux-4.4.0.orig/fs/nilfs2/the_nilfs.c
+++ linux-4.4.0/fs/nilfs2/the_nilfs.c
@@ -443,7 +443,7 @@
 	if (!sbp || le16_to_cpu(sbp->s_magic) != NILFS_SUPER_MAGIC)
 		return 0;
 	bytes = le16_to_cpu(sbp->s_bytes);
-	if (bytes > BLOCK_SIZE)
+	if (bytes < sumoff + 4 || bytes > BLOCK_SIZE)
 		return 0;
 	crc = crc32_le(le32_to_cpu(sbp->s_crc_seed), (unsigned char *)sbp,
 		       sumoff);
--- linux-4.4.0.orig/fs/notify/fanotify/fanotify.c
+++ linux-4.4.0/fs/notify/fanotify/fanotify.c
@@ -67,18 +67,7 @@
 
 	pr_debug("%s: group=%p event=%p\n", __func__, group, event);
 
-	wait_event(group->fanotify_data.access_waitq, event->response ||
-				atomic_read(&group->fanotify_data.bypass_perm));
-
-	if (!event->response) {	/* bypass_perm set */
-		/*
-		 * Event was canceled because group is being destroyed. Remove
-		 * it from group's event list because we are responsible for
-		 * freeing the permission event.
-		 */
-		fsnotify_remove_event(group, &event->fae.fse);
-		return 0;
-	}
+	wait_event(group->fanotify_data.access_waitq, event->response);
 
 	/* userspace responded, convert to something usable */
 	switch (event->response) {
@@ -103,7 +92,7 @@
 				       u32 event_mask,
 				       void *data, int data_type)
 {
-	__u32 marks_mask, marks_ignored_mask;
+	__u32 marks_mask = 0, marks_ignored_mask = 0;
 	struct path *path = data;
 
 	pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p"
@@ -119,24 +108,20 @@
 	    !d_can_lookup(path->dentry))
 		return false;
 
-	if (inode_mark && vfsmnt_mark) {
-		marks_mask = (vfsmnt_mark->mask | inode_mark->mask);
-		marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask);
-	} else if (inode_mark) {
-		/*
-		 * if the event is for a child and this inode doesn't care about
-		 * events on the child, don't send it!
-		 */
-		if ((event_mask & FS_EVENT_ON_CHILD) &&
-		    !(inode_mark->mask & FS_EVENT_ON_CHILD))
-			return false;
-		marks_mask = inode_mark->mask;
-		marks_ignored_mask = inode_mark->ignored_mask;
-	} else if (vfsmnt_mark) {
-		marks_mask = vfsmnt_mark->mask;
-		marks_ignored_mask = vfsmnt_mark->ignored_mask;
-	} else {
-		BUG();
+	/*
+	 * if the event is for a child and this inode doesn't care about
+	 * events on the child, don't send it!
+	 */
+	if (inode_mark &&
+	    (!(event_mask & FS_EVENT_ON_CHILD) ||
+	     (inode_mark->mask & FS_EVENT_ON_CHILD))) {
+		marks_mask |= inode_mark->mask;
+		marks_ignored_mask |= inode_mark->ignored_mask;
+	}
+
+	if (vfsmnt_mark) {
+		marks_mask |= vfsmnt_mark->mask;
+		marks_ignored_mask |= vfsmnt_mark->ignored_mask;
 	}
 
 	if (d_is_dir(path->dentry) &&
--- linux-4.4.0.orig/fs/notify/fanotify/fanotify_user.c
+++ linux-4.4.0/fs/notify/fanotify/fanotify_user.c
@@ -358,16 +358,20 @@
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
 	struct fanotify_perm_event_info *event, *next;
+	struct fsnotify_event *fsn_event;
 
 	/*
-	 * There may be still new events arriving in the notification queue
-	 * but since userspace cannot use fanotify fd anymore, no event can
-	 * enter or leave access_list by now.
+	 * Stop new events from arriving in the notification queue. since
+	 * userspace cannot use fanotify fd anymore, no event can enter or
+	 * leave access_list by now either.
 	 */
-	spin_lock(&group->fanotify_data.access_lock);
-
-	atomic_inc(&group->fanotify_data.bypass_perm);
+	fsnotify_group_stop_queueing(group);
 
+	/*
+	 * Process all permission events on access_list and notification queue
+	 * and simulate reply from userspace.
+	 */
+	spin_lock(&group->fanotify_data.access_lock);
 	list_for_each_entry_safe(event, next, &group->fanotify_data.access_list,
 				 fae.fse.list) {
 		pr_debug("%s: found group=%p event=%p\n", __func__, group,
@@ -379,12 +383,21 @@
 	spin_unlock(&group->fanotify_data.access_lock);
 
 	/*
-	 * Since bypass_perm is set, newly queued events will not wait for
-	 * access response. Wake up the already sleeping ones now.
-	 * synchronize_srcu() in fsnotify_destroy_group() will wait for all
-	 * processes sleeping in fanotify_handle_event() waiting for access
-	 * response and thus also for all permission events to be freed.
+	 * Destroy all non-permission events. For permission events just
+	 * dequeue them and set the response. They will be freed once the
+	 * response is consumed and fanotify_get_response() returns.
 	 */
+	mutex_lock(&group->notification_mutex);
+	while (!fsnotify_notify_queue_is_empty(group)) {
+		fsn_event = fsnotify_remove_first_event(group);
+		if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS))
+			fsnotify_destroy_event(group, fsn_event);
+		else
+			FANOTIFY_PE(fsn_event)->response = FAN_ALLOW;
+	}
+	mutex_unlock(&group->notification_mutex);
+
+	/* Response for all permission events it set, wakeup waiters */
 	wake_up(&group->fanotify_data.access_waitq);
 #endif
 
@@ -755,7 +768,6 @@
 	spin_lock_init(&group->fanotify_data.access_lock);
 	init_waitqueue_head(&group->fanotify_data.access_waitq);
 	INIT_LIST_HEAD(&group->fanotify_data.access_list);
-	atomic_set(&group->fanotify_data.bypass_perm, 0);
 #endif
 	switch (flags & FAN_ALL_CLASS_BITS) {
 	case FAN_CLASS_NOTIF:
--- linux-4.4.0.orig/fs/notify/fsnotify.c
+++ linux-4.4.0/fs/notify/fsnotify.c
@@ -104,16 +104,20 @@
 	if (unlikely(!fsnotify_inode_watches_children(p_inode)))
 		__fsnotify_update_child_dentry_flags(p_inode);
 	else if (p_inode->i_fsnotify_mask & mask) {
+		struct name_snapshot name;
+
 		/* we are notifying a parent so come up with the new mask which
 		 * specifies these are events which came from a child. */
 		mask |= FS_EVENT_ON_CHILD;
 
+		take_dentry_name_snapshot(&name, dentry);
 		if (path)
 			ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
-				       dentry->d_name.name, 0);
+				       name.name.name, 0);
 		else
 			ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
-				       dentry->d_name.name, 0);
+				       name.name.name, 0);
+		release_dentry_name_snapshot(&name);
 	}
 
 	dput(parent);
--- linux-4.4.0.orig/fs/notify/group.c
+++ linux-4.4.0/fs/notify/group.c
@@ -22,6 +22,7 @@
 #include <linux/srcu.h>
 #include <linux/rculist.h>
 #include <linux/wait.h>
+#include <linux/module.h>
 
 #include <linux/fsnotify_backend.h>
 #include "fsnotify.h"
@@ -40,6 +41,17 @@
 }
 
 /*
+ * Stop queueing new events for this group. Once this function returns
+ * fsnotify_add_event() will not add any new events to the group's queue.
+ */
+void fsnotify_group_stop_queueing(struct fsnotify_group *group)
+{
+	mutex_lock(&group->notification_mutex);
+	group->shutdown = true;
+	mutex_unlock(&group->notification_mutex);
+}
+
+/*
  * 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
@@ -47,6 +59,14 @@
  */
 void fsnotify_destroy_group(struct fsnotify_group *group)
 {
+	/*
+	 * Stop queueing new events. The code below is careful enough to not
+	 * require this but fanotify needs to stop queuing events even before
+	 * fsnotify_destroy_group() is called and this makes the other callers
+	 * of fsnotify_destroy_group() to see the same behavior.
+	 */
+	fsnotify_group_stop_queueing(group);
+
 	/* clear all inode marks for this group */
 	fsnotify_clear_marks_by_group(group);
 
@@ -72,6 +92,7 @@
 {
 	atomic_inc(&group->refcnt);
 }
+EXPORT_SYMBOL(fsnotify_get_group);
 
 /*
  * Drop a reference to a group.  Free it if it's through.
@@ -81,6 +102,7 @@
 	if (atomic_dec_and_test(&group->refcnt))
 		fsnotify_final_destroy_group(group);
 }
+EXPORT_SYMBOL(fsnotify_put_group);
 
 /*
  * Create a new fsnotify_group and hold a reference for the group returned.
@@ -109,6 +131,7 @@
 
 	return group;
 }
+EXPORT_SYMBOL(fsnotify_alloc_group);
 
 int fsnotify_fasync(int fd, struct file *file, int on)
 {
--- linux-4.4.0.orig/fs/notify/mark.c
+++ linux-4.4.0/fs/notify/mark.c
@@ -109,6 +109,7 @@
 		mark->free_mark(mark);
 	}
 }
+EXPORT_SYMBOL(fsnotify_put_mark);
 
 /* Calculate mask of events for a list of marks */
 u32 fsnotify_recalc_mask(struct hlist_head *head)
@@ -208,6 +209,7 @@
 	mutex_unlock(&group->mark_mutex);
 	fsnotify_free_mark(mark);
 }
+EXPORT_SYMBOL(fsnotify_destroy_mark);
 
 void fsnotify_destroy_marks(struct hlist_head *head, spinlock_t *lock)
 {
@@ -392,6 +394,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(fsnotify_add_mark);
 
 int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
 		      struct inode *inode, struct vfsmount *mnt, int allow_dups)
@@ -492,6 +495,7 @@
 	atomic_set(&mark->refcnt, 1);
 	mark->free_mark = free_mark;
 }
+EXPORT_SYMBOL(fsnotify_init_mark);
 
 static int fsnotify_mark_destroy(void *ignored)
 {
--- linux-4.4.0.orig/fs/notify/notification.c
+++ linux-4.4.0/fs/notify/notification.c
@@ -82,7 +82,8 @@
  * Add an event to the group notification queue.  The group can later pull this
  * event off the queue to deal with.  The function returns 0 if the event was
  * added to the queue, 1 if the event was merged with some other queued event,
- * 2 if the queue of events has overflown.
+ * 2 if the event was not queued - either the queue of events has overflown
+ * or the group is shutting down.
  */
 int fsnotify_add_event(struct fsnotify_group *group,
 		       struct fsnotify_event *event,
@@ -96,6 +97,11 @@
 
 	mutex_lock(&group->notification_mutex);
 
+	if (group->shutdown) {
+		mutex_unlock(&group->notification_mutex);
+		return 2;
+	}
+
 	if (group->q_len >= group->max_events) {
 		ret = 2;
 		/* Queue overflow event only if it isn't already queued */
@@ -126,21 +132,6 @@
 }
 
 /*
- * Remove @event from group's notification queue. It is the responsibility of
- * the caller to destroy the event.
- */
-void fsnotify_remove_event(struct fsnotify_group *group,
-			   struct fsnotify_event *event)
-{
-	mutex_lock(&group->notification_mutex);
-	if (!list_empty(&event->list)) {
-		list_del_init(&event->list);
-		group->q_len--;
-	}
-	mutex_unlock(&group->notification_mutex);
-}
-
-/*
  * Remove and return the first event from the notification list.  It is the
  * responsibility of the caller to destroy the obtained event
  */
--- linux-4.4.0.orig/fs/nsfs.c
+++ linux-4.4.0/fs/nsfs.c
@@ -95,6 +95,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 	d_instantiate(dentry, inode);
+	dentry->d_flags |= DCACHE_RCUACCESS;
 	dentry->d_fsdata = (void *)ns_ops;
 	d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
 	if (d) {
--- linux-4.4.0.orig/fs/ntfs/attrib.c
+++ linux-4.4.0/fs/ntfs/attrib.c
@@ -606,9 +606,25 @@
 		a = (ATTR_RECORD*)((u8*)ctx->attr +
 				le32_to_cpu(ctx->attr->length));
 	for (;;	a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {
-		if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +
-				le32_to_cpu(ctx->mrec->bytes_allocated))
+		u8 *mrec_end = (u8 *)ctx->mrec +
+		               le32_to_cpu(ctx->mrec->bytes_allocated);
+		u8 *name_end;
+
+		/* check whether ATTR_RECORD wrap */
+		if ((u8 *)a < (u8 *)ctx->mrec)
 			break;
+
+		/* check whether Attribute Record Header is within bounds */
+		if ((u8 *)a > mrec_end ||
+		    (u8 *)a + sizeof(ATTR_RECORD) > mrec_end)
+			break;
+
+		/* check whether ATTR_RECORD's name is within bounds */
+		name_end = (u8 *)a + le16_to_cpu(a->name_offset) +
+			   a->name_length * sizeof(ntfschar);
+		if (name_end > mrec_end)
+			break;
+
 		ctx->attr = a;
 		if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||
 				a->type == AT_END))
--- linux-4.4.0.orig/fs/ntfs/inode.c
+++ linux-4.4.0/fs/ntfs/inode.c
@@ -661,6 +661,12 @@
 	}
 	a = ctx->attr;
 	/* Get the standard information attribute value. */
+	if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
+			+ le32_to_cpu(a->data.resident.value_length) >
+			(u8 *)ctx->mrec + vol->mft_record_size) {
+		ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode.");
+		goto unm_err_out;
+	}
 	si = (STANDARD_INFORMATION*)((u8*)a +
 			le16_to_cpu(a->data.resident.value_offset));
 
@@ -1844,6 +1850,12 @@
 		brelse(bh);
 	}
 
+	if (le32_to_cpu(m->bytes_allocated) != vol->mft_record_size) {
+		ntfs_error(sb, "Incorrect mft record size %u in superblock, should be %u.",
+				le32_to_cpu(m->bytes_allocated), vol->mft_record_size);
+		goto err_out;
+	}
+
 	/* Apply the mst fixups. */
 	if (post_read_mst_fixup((NTFS_RECORD*)m, vol->mft_record_size)) {
 		/* FIXME: Try to use the $MFTMirr now. */
@@ -2893,7 +2905,7 @@
 	int err;
 	unsigned int ia_valid = attr->ia_valid;
 
-	err = inode_change_ok(vi, attr);
+	err = setattr_prepare(dentry, attr);
 	if (err)
 		goto out;
 	/* We do not support NTFS ACLs yet. */
--- linux-4.4.0.orig/fs/ocfs2/acl.c
+++ linux-4.4.0/fs/ocfs2/acl.c
@@ -241,13 +241,11 @@
 	case ACL_TYPE_ACCESS:
 		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
 		if (acl) {
-			umode_t mode = inode->i_mode;
-			ret = posix_acl_equiv_mode(acl, &mode);
-			if (ret < 0)
-				return ret;
+			umode_t mode;
 
-			if (ret == 0)
-				acl = NULL;
+			ret = posix_acl_update_mode(inode, &mode, &acl);
+			if (ret)
+				return ret;
 
 			ret = ocfs2_acl_set_mode(inode, di_bh,
 						 handle, mode);
@@ -316,9 +314,102 @@
 		return ERR_PTR(ret);
 	}
 
+	down_read(&OCFS2_I(inode)->ip_xattr_sem);
 	acl = ocfs2_get_acl_nolock(inode, type, di_bh);
+	up_read(&OCFS2_I(inode)->ip_xattr_sem);
 
 	ocfs2_inode_unlock(inode, 0);
 	brelse(di_bh);
 	return acl;
 }
+
+int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
+{
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct posix_acl *acl;
+	int ret;
+
+	if (S_ISLNK(inode->i_mode))
+		return -EOPNOTSUPP;
+
+	if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
+		return 0;
+
+	down_read(&OCFS2_I(inode)->ip_xattr_sem);
+	acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
+	up_read(&OCFS2_I(inode)->ip_xattr_sem);
+	if (IS_ERR_OR_NULL(acl))
+		return PTR_ERR_OR_ZERO(acl);
+	ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
+	if (ret)
+		return ret;
+	ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
+			    acl, NULL, NULL);
+	posix_acl_release(acl);
+	return ret;
+}
+
+/*
+ * Initialize the ACLs of a new inode. If parent directory has default ACL,
+ * then clone to new inode. Called from ocfs2_mknod.
+ */
+int ocfs2_init_acl(handle_t *handle,
+		   struct inode *inode,
+		   struct inode *dir,
+		   struct buffer_head *di_bh,
+		   struct buffer_head *dir_bh,
+		   struct ocfs2_alloc_context *meta_ac,
+		   struct ocfs2_alloc_context *data_ac)
+{
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct posix_acl *acl = NULL;
+	int ret = 0, ret2;
+	umode_t mode;
+
+	if (!S_ISLNK(inode->i_mode)) {
+		if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
+			down_read(&OCFS2_I(dir)->ip_xattr_sem);
+			acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
+						   dir_bh);
+			up_read(&OCFS2_I(dir)->ip_xattr_sem);
+			if (IS_ERR(acl))
+				return PTR_ERR(acl);
+		}
+		if (!acl) {
+			mode = inode->i_mode & ~current_umask();
+			ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
+			if (ret) {
+				mlog_errno(ret);
+				goto cleanup;
+			}
+		}
+	}
+	if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
+		if (S_ISDIR(inode->i_mode)) {
+			ret = ocfs2_set_acl(handle, inode, di_bh,
+					    ACL_TYPE_DEFAULT, acl,
+					    meta_ac, data_ac);
+			if (ret)
+				goto cleanup;
+		}
+		mode = inode->i_mode;
+		ret = __posix_acl_create(&acl, GFP_NOFS, &mode);
+		if (ret < 0)
+			return ret;
+
+		ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
+		if (ret2) {
+			mlog_errno(ret2);
+			ret = ret2;
+			goto cleanup;
+		}
+		if (ret > 0) {
+			ret = ocfs2_set_acl(handle, inode,
+					    di_bh, ACL_TYPE_ACCESS,
+					    acl, meta_ac, data_ac);
+		}
+	}
+cleanup:
+	posix_acl_release(acl);
+	return ret;
+}
--- linux-4.4.0.orig/fs/ocfs2/acl.h
+++ linux-4.4.0/fs/ocfs2/acl.h
@@ -35,5 +35,10 @@
 			 struct posix_acl *acl,
 			 struct ocfs2_alloc_context *meta_ac,
 			 struct ocfs2_alloc_context *data_ac);
+extern int ocfs2_acl_chmod(struct inode *, struct buffer_head *);
+extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *,
+			  struct buffer_head *, struct buffer_head *,
+			  struct ocfs2_alloc_context *,
+			  struct ocfs2_alloc_context *);
 
 #endif /* OCFS2_ACL_H */
--- linux-4.4.0.orig/fs/ocfs2/alloc.c
+++ linux-4.4.0/fs/ocfs2/alloc.c
@@ -7206,6 +7206,10 @@
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 	struct ocfs2_inline_data *idata = &di->id2.i_data;
 
+	/* No need to punch hole beyond i_size. */
+	if (start >= i_size_read(inode))
+		return 0;
+
 	if (end > i_size_read(inode))
 		end = i_size_read(inode);
 
@@ -7270,13 +7274,24 @@
 
 static int ocfs2_trim_extent(struct super_block *sb,
 			     struct ocfs2_group_desc *gd,
-			     u32 start, u32 count)
+			     u64 group, u32 start, u32 count)
 {
 	u64 discard, bcount;
+	struct ocfs2_super *osb = OCFS2_SB(sb);
 
 	bcount = ocfs2_clusters_to_blocks(sb, count);
-	discard = le64_to_cpu(gd->bg_blkno) +
-			ocfs2_clusters_to_blocks(sb, start);
+	discard = ocfs2_clusters_to_blocks(sb, start);
+
+	/*
+	 * For the first cluster group, the gd->bg_blkno is not at the start
+	 * of the group, but at an offset from the start. If we add it while
+	 * calculating discard for first group, we will wrongly start fstrim a
+	 * few blocks after the desried start block and the range can cross
+	 * over into the next cluster group. So, add it only if this is not
+	 * the first cluster group.
+	 */
+	if (group != osb->first_cluster_group_blkno)
+		discard += le64_to_cpu(gd->bg_blkno);
 
 	trace_ocfs2_trim_extent(sb, (unsigned long long)discard, bcount);
 
@@ -7284,7 +7299,7 @@
 }
 
 static int ocfs2_trim_group(struct super_block *sb,
-			    struct ocfs2_group_desc *gd,
+			    struct ocfs2_group_desc *gd, u64 group,
 			    u32 start, u32 max, u32 minbits)
 {
 	int ret = 0, count = 0, next;
@@ -7303,7 +7318,7 @@
 		next = ocfs2_find_next_bit(bitmap, max, start);
 
 		if ((next - start) >= minbits) {
-			ret = ocfs2_trim_extent(sb, gd,
+			ret = ocfs2_trim_extent(sb, gd, group,
 						start, next - start);
 			if (ret < 0) {
 				mlog_errno(ret);
@@ -7401,7 +7416,8 @@
 		}
 
 		gd = (struct ocfs2_group_desc *)gd_bh->b_data;
-		cnt = ocfs2_trim_group(sb, gd, first_bit, last_bit, minlen);
+		cnt = ocfs2_trim_group(sb, gd, group,
+				       first_bit, last_bit, minlen);
 		brelse(gd_bh);
 		gd_bh = NULL;
 		if (cnt < 0) {
--- linux-4.4.0.orig/fs/ocfs2/aops.c
+++ linux-4.4.0/fs/ocfs2/aops.c
@@ -956,6 +956,7 @@
 		tmp_ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
 				update_isize, end);
 		if (tmp_ret < 0) {
+			ocfs2_inode_unlock(inode, 1);
 			ret = tmp_ret;
 			mlog_errno(ret);
 			brelse(di_bh);
@@ -1102,7 +1103,7 @@
 	int ret = 0;
 	struct buffer_head *head, *bh, *wait[2], **wait_bh = wait;
 	unsigned int block_end, block_start;
-	unsigned int bsize = 1 << inode->i_blkbits;
+	unsigned int bsize = i_blocksize(inode);
 
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, bsize, 0);
--- linux-4.4.0.orig/fs/ocfs2/aops.h
+++ linux-4.4.0/fs/ocfs2/aops.h
@@ -83,6 +83,8 @@
 	OCFS2_IOCB_NUM_LOCKS
 };
 
+#define ocfs2_iocb_init_rw_locked(iocb) \
+	(iocb->private = NULL)
 #define ocfs2_iocb_clear_rw_locked(iocb) \
 	clear_bit(OCFS2_IOCB_RW_LOCK, (unsigned long *)&iocb->private)
 #define ocfs2_iocb_rw_locked_level(iocb) \
--- linux-4.4.0.orig/fs/ocfs2/buffer_head_io.c
+++ linux-4.4.0/fs/ocfs2/buffer_head_io.c
@@ -98,25 +98,34 @@
 	return ret;
 }
 
+/* Caller must provide a bhs[] with all NULL or non-NULL entries, so it
+ * will be easier to handle read failure.
+ */
 int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
 			   unsigned int nr, struct buffer_head *bhs[])
 {
 	int status = 0;
 	unsigned int i;
 	struct buffer_head *bh;
+	int new_bh = 0;
 
 	trace_ocfs2_read_blocks_sync((unsigned long long)block, nr);
 
 	if (!nr)
 		goto bail;
 
+	/* Don't put buffer head and re-assign it to NULL if it is allocated
+	 * outside since the caller can't be aware of this alternation!
+	 */
+	new_bh = (bhs[0] == NULL);
+
 	for (i = 0 ; i < nr ; i++) {
 		if (bhs[i] == NULL) {
 			bhs[i] = sb_getblk(osb->sb, block++);
 			if (bhs[i] == NULL) {
 				status = -ENOMEM;
 				mlog_errno(status);
-				goto bail;
+				break;
 			}
 		}
 		bh = bhs[i];
@@ -146,15 +155,31 @@
 			BUG();
 		}
 
-		clear_buffer_uptodate(bh);
 		get_bh(bh); /* for end_buffer_read_sync() */
 		bh->b_end_io = end_buffer_read_sync;
 		submit_bh(READ, bh);
 	}
 
+read_failure:
 	for (i = nr; i > 0; i--) {
 		bh = bhs[i - 1];
 
+		if (unlikely(status)) {
+			if (new_bh && bh) {
+				/* If middle bh fails, let previous bh
+				 * finish its read and then put it to
+				 * aovoid bh leak
+				 */
+				if (!buffer_jbd(bh))
+					wait_on_buffer(bh);
+				put_bh(bh);
+				bhs[i - 1] = NULL;
+			} else if (bh && buffer_uptodate(bh)) {
+				clear_buffer_uptodate(bh);
+			}
+			continue;
+		}
+
 		/* No need to wait on the buffer if it's managed by JBD. */
 		if (!buffer_jbd(bh))
 			wait_on_buffer(bh);
@@ -164,8 +189,7 @@
 			 * so we can safely record this and loop back
 			 * to cleanup the other buffers. */
 			status = -EIO;
-			put_bh(bh);
-			bhs[i - 1] = NULL;
+			goto read_failure;
 		}
 	}
 
@@ -173,6 +197,9 @@
 	return status;
 }
 
+/* Caller must provide a bhs[] with all NULL or non-NULL entries, so it
+ * will be easier to handle read failure.
+ */
 int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
 		      struct buffer_head *bhs[], int flags,
 		      int (*validate)(struct super_block *sb,
@@ -182,6 +209,7 @@
 	int i, ignore_cache = 0;
 	struct buffer_head *bh;
 	struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
+	int new_bh = 0;
 
 	trace_ocfs2_read_blocks_begin(ci, (unsigned long long)block, nr, flags);
 
@@ -207,6 +235,11 @@
 		goto bail;
 	}
 
+	/* Don't put buffer head and re-assign it to NULL if it is allocated
+	 * outside since the caller can't be aware of this alternation!
+	 */
+	new_bh = (bhs[0] == NULL);
+
 	ocfs2_metadata_cache_io_lock(ci);
 	for (i = 0 ; i < nr ; i++) {
 		if (bhs[i] == NULL) {
@@ -215,7 +248,8 @@
 				ocfs2_metadata_cache_io_unlock(ci);
 				status = -ENOMEM;
 				mlog_errno(status);
-				goto bail;
+				/* Don't forget to put previous bh! */
+				break;
 			}
 		}
 		bh = bhs[i];
@@ -300,7 +334,6 @@
 				continue;
 			}
 
-			clear_buffer_uptodate(bh);
 			get_bh(bh); /* for end_buffer_read_sync() */
 			if (validate)
 				set_buffer_needs_validate(bh);
@@ -310,16 +343,27 @@
 		}
 	}
 
-	status = 0;
-
+read_failure:
 	for (i = (nr - 1); i >= 0; i--) {
 		bh = bhs[i];
 
 		if (!(flags & OCFS2_BH_READAHEAD)) {
-			if (status) {
-				/* Clear the rest of the buffers on error */
-				put_bh(bh);
-				bhs[i] = NULL;
+			if (unlikely(status)) {
+				/* Clear the buffers on error including those
+				 * ever succeeded in reading
+				 */
+				if (new_bh && bh) {
+					/* If middle bh fails, let previous bh
+					 * finish its read and then put it to
+					 * aovoid bh leak
+					 */
+					if (!buffer_jbd(bh))
+						wait_on_buffer(bh);
+					put_bh(bh);
+					bhs[i] = NULL;
+				} else if (bh && buffer_uptodate(bh)) {
+					clear_buffer_uptodate(bh);
+				}
 				continue;
 			}
 			/* We know this can't have changed as we hold the
@@ -336,9 +380,8 @@
 				 * for this bh as it's not marked locally
 				 * uptodate. */
 				status = -EIO;
-				put_bh(bh);
-				bhs[i] = NULL;
-				continue;
+				clear_buffer_needs_validate(bh);
+				goto read_failure;
 			}
 
 			if (buffer_needs_validate(bh)) {
@@ -348,11 +391,8 @@
 				BUG_ON(buffer_jbd(bh));
 				clear_buffer_needs_validate(bh);
 				status = validate(sb, bh);
-				if (status) {
-					put_bh(bh);
-					bhs[i] = NULL;
-					continue;
-				}
+				if (status)
+					goto read_failure;
 			}
 		}
 
--- linux-4.4.0.orig/fs/ocfs2/cluster/heartbeat.c
+++ linux-4.4.0/fs/ocfs2/cluster/heartbeat.c
@@ -2070,13 +2070,13 @@
 	spin_unlock(&o2hb_live_lock);
 }
 
-static ssize_t o2hb_heartbeat_group_threshold_show(struct config_item *item,
+static ssize_t o2hb_heartbeat_group_dead_threshold_show(struct config_item *item,
 		char *page)
 {
 	return sprintf(page, "%u\n", o2hb_dead_threshold);
 }
 
-static ssize_t o2hb_heartbeat_group_threshold_store(struct config_item *item,
+static ssize_t o2hb_heartbeat_group_dead_threshold_store(struct config_item *item,
 		const char *page, size_t count)
 {
 	unsigned long tmp;
@@ -2125,11 +2125,11 @@
 
 }
 
-CONFIGFS_ATTR(o2hb_heartbeat_group_, threshold);
+CONFIGFS_ATTR(o2hb_heartbeat_group_, dead_threshold);
 CONFIGFS_ATTR(o2hb_heartbeat_group_, mode);
 
 static struct configfs_attribute *o2hb_heartbeat_group_attrs[] = {
-	&o2hb_heartbeat_group_attr_threshold,
+	&o2hb_heartbeat_group_attr_dead_threshold,
 	&o2hb_heartbeat_group_attr_mode,
 	NULL,
 };
--- linux-4.4.0.orig/fs/ocfs2/cluster/nodemanager.c
+++ linux-4.4.0/fs/ocfs2/cluster/nodemanager.c
@@ -40,6 +40,9 @@
 		"panic",	/* O2NM_FENCE_PANIC */
 };
 
+static inline void o2nm_lock_subsystem(void);
+static inline void o2nm_unlock_subsystem(void);
+
 struct o2nm_node *o2nm_get_node_by_num(u8 node_num)
 {
 	struct o2nm_node *node = NULL;
@@ -181,7 +184,10 @@
 {
 	/* through the first node_set .parent
 	 * mycluster/nodes/mynode == o2nm_cluster->o2nm_node_group->o2nm_node */
-	return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
+	if (node->nd_item.ci_parent)
+		return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
+	else
+		return NULL;
 }
 
 enum {
@@ -194,7 +200,7 @@
 				   size_t count)
 {
 	struct o2nm_node *node = to_o2nm_node(item);
-	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
+	struct o2nm_cluster *cluster;
 	unsigned long tmp;
 	char *p = (char *)page;
 	int ret = 0;
@@ -214,6 +220,13 @@
 	    !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
 		return -EINVAL; /* XXX */
 
+	o2nm_lock_subsystem();
+	cluster = to_o2nm_cluster_from_node(node);
+	if (!cluster) {
+		o2nm_unlock_subsystem();
+		return -EINVAL;
+	}
+
 	write_lock(&cluster->cl_nodes_lock);
 	if (cluster->cl_nodes[tmp])
 		ret = -EEXIST;
@@ -226,6 +239,8 @@
 		set_bit(tmp, cluster->cl_nodes_bitmap);
 	}
 	write_unlock(&cluster->cl_nodes_lock);
+	o2nm_unlock_subsystem();
+
 	if (ret)
 		return ret;
 
@@ -269,7 +284,7 @@
 					    size_t count)
 {
 	struct o2nm_node *node = to_o2nm_node(item);
-	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
+	struct o2nm_cluster *cluster;
 	int ret, i;
 	struct rb_node **p, *parent;
 	unsigned int octets[4];
@@ -286,6 +301,13 @@
 		be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
 	}
 
+	o2nm_lock_subsystem();
+	cluster = to_o2nm_cluster_from_node(node);
+	if (!cluster) {
+		o2nm_unlock_subsystem();
+		return -EINVAL;
+	}
+
 	ret = 0;
 	write_lock(&cluster->cl_nodes_lock);
 	if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
@@ -298,6 +320,8 @@
 		rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
 	}
 	write_unlock(&cluster->cl_nodes_lock);
+	o2nm_unlock_subsystem();
+
 	if (ret)
 		return ret;
 
@@ -315,7 +339,7 @@
 				     size_t count)
 {
 	struct o2nm_node *node = to_o2nm_node(item);
-	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
+	struct o2nm_cluster *cluster;
 	unsigned long tmp;
 	char *p = (char *)page;
 	ssize_t ret;
@@ -333,17 +357,26 @@
 	    !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
 		return -EINVAL; /* XXX */
 
+	o2nm_lock_subsystem();
+	cluster = to_o2nm_cluster_from_node(node);
+	if (!cluster) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* the only failure case is trying to set a new local node
 	 * when a different one is already set */
 	if (tmp && tmp == cluster->cl_has_local &&
-	    cluster->cl_local_node != node->nd_num)
-		return -EBUSY;
+	    cluster->cl_local_node != node->nd_num) {
+		ret = -EBUSY;
+		goto out;
+	}
 
 	/* bring up the rx thread if we're setting the new local node. */
 	if (tmp && !cluster->cl_has_local) {
 		ret = o2net_start_listening(node);
 		if (ret)
-			return ret;
+			goto out;
 	}
 
 	if (!tmp && cluster->cl_has_local &&
@@ -358,7 +391,11 @@
 		cluster->cl_local_node = node->nd_num;
 	}
 
-	return count;
+	ret = count;
+
+out:
+	o2nm_unlock_subsystem();
+	return ret;
 }
 
 CONFIGFS_ATTR(o2nm_node_, num);
@@ -584,13 +621,15 @@
 	struct o2nm_node *node = to_o2nm_node(item);
 	struct o2nm_cluster *cluster = to_o2nm_cluster(group->cg_item.ci_parent);
 
-	o2net_disconnect_node(node);
+	if (cluster->cl_nodes[node->nd_num] == node) {
+		o2net_disconnect_node(node);
 
-	if (cluster->cl_has_local &&
-	    (cluster->cl_local_node == node->nd_num)) {
-		cluster->cl_has_local = 0;
-		cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
-		o2net_stop_listening(node);
+		if (cluster->cl_has_local &&
+		    (cluster->cl_local_node == node->nd_num)) {
+			cluster->cl_has_local = 0;
+			cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
+			o2net_stop_listening(node);
+		}
 	}
 
 	/* XXX call into net to stop this node from trading messages */
@@ -750,6 +789,16 @@
 	},
 };
 
+static inline void o2nm_lock_subsystem(void)
+{
+	mutex_lock(&o2nm_cluster_group.cs_subsys.su_mutex);
+}
+
+static inline void o2nm_unlock_subsystem(void)
+{
+	mutex_unlock(&o2nm_cluster_group.cs_subsys.su_mutex);
+}
+
 int o2nm_depend_item(struct config_item *item)
 {
 	return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item);
--- linux-4.4.0.orig/fs/ocfs2/dcache.c
+++ linux-4.4.0/fs/ocfs2/dcache.c
@@ -310,6 +310,18 @@
 
 out_attach:
 	spin_lock(&dentry_attach_lock);
+	if (unlikely(dentry->d_fsdata && !alias)) {
+		/* d_fsdata is set by a racing thread which is doing
+		 * the same thing as this thread is doing. Leave the racing
+		 * thread going ahead and we return here.
+		 */
+		spin_unlock(&dentry_attach_lock);
+		iput(dl->dl_inode);
+		ocfs2_lock_res_free(&dl->dl_lockres);
+		kfree(dl);
+		return 0;
+	}
+
 	dentry->d_fsdata = dl;
 	dl->dl_count++;
 	spin_unlock(&dentry_attach_lock);
--- linux-4.4.0.orig/fs/ocfs2/dir.c
+++ linux-4.4.0/fs/ocfs2/dir.c
@@ -1896,8 +1896,7 @@
 				/* On error, skip the f_pos to the
 				   next block. */
 				ctx->pos = (ctx->pos | (sb->s_blocksize - 1)) + 1;
-				brelse(bh);
-				continue;
+				break;
 			}
 			if (le64_to_cpu(de->inode)) {
 				unsigned char d_type = DT_UNKNOWN;
--- linux-4.4.0.orig/fs/ocfs2/dlm/dlmconvert.c
+++ linux-4.4.0/fs/ocfs2/dlm/dlmconvert.c
@@ -287,6 +287,19 @@
 		status = DLM_DENIED;
 		goto bail;
 	}
+
+	if (lock->ml.type == type && lock->ml.convert_type == LKM_IVMODE) {
+		mlog(0, "last convert request returned DLM_RECOVERING, but "
+		     "owner has already queued and sent ast to me. res %.*s, "
+		     "(cookie=%u:%llu, type=%d, conv=%d)\n",
+		     res->lockname.len, res->lockname.name,
+		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
+		     lock->ml.type, lock->ml.convert_type);
+		status = DLM_NORMAL;
+		goto bail;
+	}
+
 	res->state |= DLM_LOCK_RES_IN_PROGRESS;
 	/* move lock to local convert queue */
 	/* do not alter lock refcount.  switching lists. */
@@ -315,13 +328,22 @@
 
 	spin_lock(&res->spinlock);
 	res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
-	lock->convert_pending = 0;
-	/* if it failed, move it back to granted queue */
+	/* if it failed, move it back to granted queue.
+	 * if master returns DLM_NORMAL and then down before sending ast,
+	 * it may have already been moved to granted queue, reset to
+	 * DLM_RECOVERING and retry convert */
 	if (status != DLM_NORMAL) {
 		if (status != DLM_NOTQUEUED)
 			dlm_error(status);
 		dlm_revert_pending_convert(res, lock);
+	} else if (!lock->convert_pending) {
+		mlog(0, "%s: res %.*s, owner died and lock has been moved back "
+				"to granted list, retry convert.\n",
+				dlm->name, res->lockname.len, res->lockname.name);
+		status = DLM_RECOVERING;
 	}
+
+	lock->convert_pending = 0;
 bail:
 	spin_unlock(&res->spinlock);
 
--- linux-4.4.0.orig/fs/ocfs2/dlm/dlmdebug.c
+++ linux-4.4.0/fs/ocfs2/dlm/dlmdebug.c
@@ -329,7 +329,7 @@
 {
 	char *buf;
 
-	buf = (char *) get_zeroed_page(GFP_NOFS);
+	buf = (char *) get_zeroed_page(GFP_ATOMIC);
 	if (buf) {
 		dump_mle(mle, buf, PAGE_SIZE - 1);
 		free_page((unsigned long)buf);
--- linux-4.4.0.orig/fs/ocfs2/dlm/dlmdomain.c
+++ linux-4.4.0/fs/ocfs2/dlm/dlmdomain.c
@@ -674,20 +674,6 @@
 	spin_unlock(&dlm->spinlock);
 }
 
-int dlm_shutting_down(struct dlm_ctxt *dlm)
-{
-	int ret = 0;
-
-	spin_lock(&dlm_domain_lock);
-
-	if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN)
-		ret = 1;
-
-	spin_unlock(&dlm_domain_lock);
-
-	return ret;
-}
-
 void dlm_unregister_domain(struct dlm_ctxt *dlm)
 {
 	int leave = 0;
--- linux-4.4.0.orig/fs/ocfs2/dlm/dlmdomain.h
+++ linux-4.4.0/fs/ocfs2/dlm/dlmdomain.h
@@ -28,7 +28,30 @@
 extern spinlock_t dlm_domain_lock;
 extern struct list_head dlm_domains;
 
-int dlm_shutting_down(struct dlm_ctxt *dlm);
+static inline int dlm_joined(struct dlm_ctxt *dlm)
+{
+	int ret = 0;
+
+	spin_lock(&dlm_domain_lock);
+	if (dlm->dlm_state == DLM_CTXT_JOINED)
+		ret = 1;
+	spin_unlock(&dlm_domain_lock);
+
+	return ret;
+}
+
+static inline int dlm_shutting_down(struct dlm_ctxt *dlm)
+{
+	int ret = 0;
+
+	spin_lock(&dlm_domain_lock);
+	if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN)
+		ret = 1;
+	spin_unlock(&dlm_domain_lock);
+
+	return ret;
+}
+
 void dlm_fire_domain_eviction_callbacks(struct dlm_ctxt *dlm,
 					int node_num);
 
--- linux-4.4.0.orig/fs/ocfs2/dlm/dlmmaster.c
+++ linux-4.4.0/fs/ocfs2/dlm/dlmmaster.c
@@ -589,9 +589,9 @@
 
 	res->last_used = 0;
 
-	spin_lock(&dlm->spinlock);
+	spin_lock(&dlm->track_lock);
 	list_add_tail(&res->tracking, &dlm->tracking_list);
-	spin_unlock(&dlm->spinlock);
+	spin_unlock(&dlm->track_lock);
 
 	memset(res->lvb, 0, DLM_LVB_LEN);
 	memset(res->refmap, 0, sizeof(res->refmap));
@@ -2519,6 +2519,11 @@
 	spin_lock(&dlm->master_lock);
 	ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, name,
 				    namelen, target, dlm->node_num);
+	/* get an extra reference on the mle.
+	 * otherwise the assert_master from the new
+	 * master will destroy this.
+	 */
+	dlm_get_mle_inuse(mle);
 	spin_unlock(&dlm->master_lock);
 	spin_unlock(&dlm->spinlock);
 
@@ -2554,6 +2559,7 @@
 		if (mle_added) {
 			dlm_mle_detach_hb_events(dlm, mle);
 			dlm_put_mle(mle);
+			dlm_put_mle_inuse(mle);
 		} else if (mle) {
 			kmem_cache_free(dlm_mle_cache, mle);
 			mle = NULL;
@@ -2571,17 +2577,6 @@
 	 * ensure that all assert_master work is flushed. */
 	flush_workqueue(dlm->dlm_worker);
 
-	/* get an extra reference on the mle.
-	 * otherwise the assert_master from the new
-	 * master will destroy this.
-	 * also, make sure that all callers of dlm_get_mle
-	 * take both dlm->spinlock and dlm->master_lock */
-	spin_lock(&dlm->spinlock);
-	spin_lock(&dlm->master_lock);
-	dlm_get_mle_inuse(mle);
-	spin_unlock(&dlm->master_lock);
-	spin_unlock(&dlm->spinlock);
-
 	/* notify new node and send all lock state */
 	/* call send_one_lockres with migration flag.
 	 * this serves as notice to the target node that a
@@ -3312,6 +3307,15 @@
 			    mle->new_master != dead_node)
 				continue;
 
+			if (mle->new_master == dead_node && mle->inuse) {
+				mlog(ML_NOTICE, "%s: target %u died during "
+						"migration from %u, the MLE is "
+						"still keep used, ignore it!\n",
+						dlm->name, dead_node,
+						mle->master);
+				continue;
+			}
+
 			/* If we have reached this point, this mle needs to be
 			 * removed from the list and freed. */
 			dlm_clean_migration_mle(dlm, mle);
--- linux-4.4.0.orig/fs/ocfs2/dlm/dlmrecovery.c
+++ linux-4.4.0/fs/ocfs2/dlm/dlmrecovery.c
@@ -1377,6 +1377,15 @@
 	if (!dlm_grab(dlm))
 		return -EINVAL;
 
+	if (!dlm_joined(dlm)) {
+		mlog(ML_ERROR, "Domain %s not joined! "
+			  "lockres %.*s, master %u\n",
+			  dlm->name, mres->lockname_len,
+			  mres->lockname, mres->master);
+		dlm_put(dlm);
+		return -EINVAL;
+	}
+
 	BUG_ON(!(mres->flags & (DLM_MRES_RECOVERY|DLM_MRES_MIGRATION)));
 
 	real_master = mres->master;
@@ -2064,7 +2073,6 @@
 			dlm_lock_get(lock);
 			if (lock->convert_pending) {
 				/* move converting lock back to granted */
-				BUG_ON(i != DLM_CONVERTING_LIST);
 				mlog(0, "node died with convert pending "
 				     "on %.*s. move back to granted list.\n",
 				     res->lockname.len, res->lockname.name);
@@ -2360,6 +2368,8 @@
 						break;
 					}
 				}
+				dlm_lockres_clear_refmap_bit(dlm, res,
+						dead_node);
 				spin_unlock(&res->spinlock);
 				continue;
 			}
--- linux-4.4.0.orig/fs/ocfs2/dlm/dlmunlock.c
+++ linux-4.4.0/fs/ocfs2/dlm/dlmunlock.c
@@ -105,7 +105,8 @@
 	enum dlm_status status;
 	int actions = 0;
 	int in_use;
-        u8 owner;
+	u8 owner;
+	int recovery_wait = 0;
 
 	mlog(0, "master_node = %d, valblk = %d\n", master_node,
 	     flags & LKM_VALBLK);
@@ -208,9 +209,12 @@
 		}
 		if (flags & LKM_CANCEL)
 			lock->cancel_pending = 0;
-		else
-			lock->unlock_pending = 0;
-
+		else {
+			if (!lock->unlock_pending)
+				recovery_wait = 1;
+			else
+				lock->unlock_pending = 0;
+		}
 	}
 
 	/* get an extra ref on lock.  if we are just switching
@@ -244,6 +248,17 @@
 	spin_unlock(&res->spinlock);
 	wake_up(&res->wq);
 
+	if (recovery_wait) {
+		spin_lock(&res->spinlock);
+		/* Unlock request will directly succeed after owner dies,
+		 * and the lock is already removed from grant list. We have to
+		 * wait for RECOVERING done or we miss the chance to purge it
+		 * since the removement is much faster than RECOVERING proc.
+		 */
+		__dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_RECOVERING);
+		spin_unlock(&res->spinlock);
+	}
+
 	/* let the caller's final dlm_lock_put handle the actual kfree */
 	if (actions & DLM_UNLOCK_FREE_LOCK) {
 		/* this should always be coupled with list removal */
--- linux-4.4.0.orig/fs/ocfs2/dlmfs/dlmfs.c
+++ linux-4.4.0/fs/ocfs2/dlmfs/dlmfs.c
@@ -211,7 +211,7 @@
 	struct inode *inode = d_inode(dentry);
 
 	attr->ia_valid &= ~ATTR_SIZE;
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/ocfs2/dlmglue.c
+++ linux-4.4.0/fs/ocfs2/dlmglue.c
@@ -531,6 +531,7 @@
 	init_waitqueue_head(&res->l_event);
 	INIT_LIST_HEAD(&res->l_blocked_list);
 	INIT_LIST_HEAD(&res->l_mask_waiters);
+	INIT_LIST_HEAD(&res->l_holders);
 }
 
 void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
@@ -748,6 +749,50 @@
 	res->l_flags = 0UL;
 }
 
+/*
+ * Keep a list of processes who have interest in a lockres.
+ * Note: this is now only uesed for check recursive cluster locking.
+ */
+static inline void ocfs2_add_holder(struct ocfs2_lock_res *lockres,
+				   struct ocfs2_lock_holder *oh)
+{
+	INIT_LIST_HEAD(&oh->oh_list);
+	oh->oh_owner_pid = get_pid(task_pid(current));
+
+	spin_lock(&lockres->l_lock);
+	list_add_tail(&oh->oh_list, &lockres->l_holders);
+	spin_unlock(&lockres->l_lock);
+}
+
+static inline void ocfs2_remove_holder(struct ocfs2_lock_res *lockres,
+				       struct ocfs2_lock_holder *oh)
+{
+	spin_lock(&lockres->l_lock);
+	list_del(&oh->oh_list);
+	spin_unlock(&lockres->l_lock);
+
+	put_pid(oh->oh_owner_pid);
+}
+
+static inline int ocfs2_is_locked_by_me(struct ocfs2_lock_res *lockres)
+{
+	struct ocfs2_lock_holder *oh;
+	struct pid *pid;
+
+	/* look in the list of holders for one with the current task as owner */
+	spin_lock(&lockres->l_lock);
+	pid = task_pid(current);
+	list_for_each_entry(oh, &lockres->l_holders, oh_list) {
+		if (oh->oh_owner_pid == pid) {
+			spin_unlock(&lockres->l_lock);
+			return 1;
+		}
+	}
+	spin_unlock(&lockres->l_lock);
+
+	return 0;
+}
+
 static inline void ocfs2_inc_holders(struct ocfs2_lock_res *lockres,
 				     int level)
 {
@@ -1390,6 +1435,7 @@
 	unsigned int gen;
 	int noqueue_attempted = 0;
 	int dlm_locked = 0;
+	int kick_dc = 0;
 
 	if (!(lockres->l_flags & OCFS2_LOCK_INITIALIZED)) {
 		mlog_errno(-EINVAL);
@@ -1524,7 +1570,12 @@
 unlock:
 	lockres_clear_flags(lockres, OCFS2_LOCK_UPCONVERT_FINISHING);
 
+	/* ocfs2_unblock_lock reques on seeing OCFS2_LOCK_UPCONVERT_FINISHING */
+	kick_dc = (lockres->l_flags & OCFS2_LOCK_BLOCKED);
+
 	spin_unlock_irqrestore(&lockres->l_lock, flags);
+	if (kick_dc)
+		ocfs2_wake_downconvert_thread(osb);
 out:
 	/*
 	 * This is helping work around a lock inversion between the page lock
@@ -2337,8 +2388,9 @@
 		goto getbh;
 	}
 
-	if (ocfs2_mount_local(osb))
-		goto local;
+	if ((arg_flags & OCFS2_META_LOCK_GETBH) ||
+	    ocfs2_mount_local(osb))
+		goto update;
 
 	if (!(arg_flags & OCFS2_META_LOCK_RECOVERY))
 		ocfs2_wait_for_recovery(osb);
@@ -2367,7 +2419,7 @@
 	if (!(arg_flags & OCFS2_META_LOCK_RECOVERY))
 		ocfs2_wait_for_recovery(osb);
 
-local:
+update:
 	/*
 	 * We only see this flag if we're being called from
 	 * ocfs2_read_locked_inode(). It means we're locking an inode
@@ -2509,6 +2561,59 @@
 		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
 }
 
+/*
+ * This _tracker variantes are introduced to deal with the recursive cluster
+ * locking issue. The idea is to keep track of a lock holder on the stack of
+ * the current process. If there's a lock holder on the stack, we know the
+ * task context is already protected by cluster locking. Currently, they're
+ * used in some VFS entry routines.
+ *
+ * return < 0 on error, return == 0 if there's no lock holder on the stack
+ * before this call, return == 1 if this call would be a recursive locking.
+ */
+int ocfs2_inode_lock_tracker(struct inode *inode,
+			     struct buffer_head **ret_bh,
+			     int ex,
+			     struct ocfs2_lock_holder *oh)
+{
+	int status;
+	int arg_flags = 0, has_locked;
+	struct ocfs2_lock_res *lockres;
+
+	lockres = &OCFS2_I(inode)->ip_inode_lockres;
+	has_locked = ocfs2_is_locked_by_me(lockres);
+	/* Just get buffer head if the cluster lock has been taken */
+	if (has_locked)
+		arg_flags = OCFS2_META_LOCK_GETBH;
+
+	if (likely(!has_locked || ret_bh)) {
+		status = ocfs2_inode_lock_full(inode, ret_bh, ex, arg_flags);
+		if (status < 0) {
+			if (status != -ENOENT)
+				mlog_errno(status);
+			return status;
+		}
+	}
+	if (!has_locked)
+		ocfs2_add_holder(lockres, oh);
+
+	return has_locked;
+}
+
+void ocfs2_inode_unlock_tracker(struct inode *inode,
+				int ex,
+				struct ocfs2_lock_holder *oh,
+				int had_lock)
+{
+	struct ocfs2_lock_res *lockres;
+
+	lockres = &OCFS2_I(inode)->ip_inode_lockres;
+	if (!had_lock) {
+		ocfs2_remove_holder(lockres, oh);
+		ocfs2_inode_unlock(inode, ex);
+	}
+}
+
 int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno)
 {
 	struct ocfs2_lock_res *lockres;
@@ -3315,6 +3420,16 @@
 	mlog(ML_BASTS, "lockres %s, level %d => %d\n", lockres->l_name,
 	     lockres->l_level, new_level);
 
+	/*
+	 * On DLM_LKF_VALBLK, fsdlm behaves differently with o2cb. It always
+	 * expects DLM_LKF_VALBLK being set if the LKB has LVB, so that
+	 * we can recover correctly from node failure. Otherwise, we may get
+	 * invalid LVB in LKB, but without DLM_SBF_VALNOTVALID being set.
+	 */
+	if (ocfs2_userspace_stack(osb) &&
+	    lockres->l_ops->flags & LOCK_TYPE_USES_LVB)
+		lvb = 1;
+
 	if (lvb)
 		dlm_flags |= DLM_LKF_VALBLK;
 
--- linux-4.4.0.orig/fs/ocfs2/dlmglue.h
+++ linux-4.4.0/fs/ocfs2/dlmglue.h
@@ -70,6 +70,11 @@
 	__be32	lvb_os_seqno;
 };
 
+struct ocfs2_lock_holder {
+	struct list_head oh_list;
+	struct pid *oh_owner_pid;
+};
+
 /* ocfs2_inode_lock_full() 'arg_flags' flags */
 /* don't wait on recovery. */
 #define OCFS2_META_LOCK_RECOVERY	(0x01)
@@ -77,6 +82,8 @@
 #define OCFS2_META_LOCK_NOQUEUE		(0x02)
 /* don't block waiting for the downconvert thread, instead return -EAGAIN */
 #define OCFS2_LOCK_NONBLOCK		(0x04)
+/* just get back disk inode bh if we've got cluster lock. */
+#define OCFS2_META_LOCK_GETBH		(0x08)
 
 /* Locking subclasses of inode cluster lock */
 enum {
@@ -170,4 +177,15 @@
 
 /* To set the locking protocol on module initialization */
 void ocfs2_set_locking_protocol(void);
+
+/* The _tracker pair is used to avoid cluster recursive locking */
+int ocfs2_inode_lock_tracker(struct inode *inode,
+			     struct buffer_head **ret_bh,
+			     int ex,
+			     struct ocfs2_lock_holder *oh);
+void ocfs2_inode_unlock_tracker(struct inode *inode,
+				int ex,
+				struct ocfs2_lock_holder *oh,
+				int had_lock);
+
 #endif	/* DLMGLUE_H */
--- linux-4.4.0.orig/fs/ocfs2/export.c
+++ linux-4.4.0/fs/ocfs2/export.c
@@ -125,10 +125,10 @@
 
 check_gen:
 	if (handle->ih_generation != inode->i_generation) {
-		iput(inode);
 		trace_ocfs2_get_dentry_generation((unsigned long long)blkno,
 						  handle->ih_generation,
 						  inode->i_generation);
+		iput(inode);
 		result = ERR_PTR(-ESTALE);
 		goto bail;
 	}
@@ -148,16 +148,24 @@
 	u64 blkno;
 	struct dentry *parent;
 	struct inode *dir = d_inode(child);
+	int set;
 
 	trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name,
 			       (unsigned long long)OCFS2_I(dir)->ip_blkno);
 
+	status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1);
+	if (status < 0) {
+		mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
+		parent = ERR_PTR(status);
+		goto bail;
+	}
+
 	status = ocfs2_inode_lock(dir, NULL, 0);
 	if (status < 0) {
 		if (status != -ENOENT)
 			mlog_errno(status);
 		parent = ERR_PTR(status);
-		goto bail;
+		goto unlock_nfs_sync;
 	}
 
 	status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
@@ -166,11 +174,31 @@
 		goto bail_unlock;
 	}
 
+	status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, &set);
+	if (status < 0) {
+		if (status == -EINVAL) {
+			status = -ESTALE;
+		} else
+			mlog(ML_ERROR, "test inode bit failed %d\n", status);
+		parent = ERR_PTR(status);
+		goto bail_unlock;
+	}
+
+	trace_ocfs2_get_dentry_test_bit(status, set);
+	if (!set) {
+		status = -ESTALE;
+		parent = ERR_PTR(status);
+		goto bail_unlock;
+	}
+
 	parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
 
 bail_unlock:
 	ocfs2_inode_unlock(dir, 0);
 
+unlock_nfs_sync:
+	ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1);
+
 bail:
 	trace_ocfs2_get_parent_end(parent);
 
--- linux-4.4.0.orig/fs/ocfs2/file.c
+++ linux-4.4.0/fs/ocfs2/file.c
@@ -808,7 +808,7 @@
 	/* We know that zero_from is block aligned */
 	for (block_start = zero_from; block_start < zero_to;
 	     block_start = block_end) {
-		block_end = block_start + (1 << inode->i_blkbits);
+		block_end = block_start + i_blocksize(inode);
 
 		/*
 		 * block_start is block-aligned.  Bump it by one to force
@@ -1155,7 +1155,7 @@
 	if (!(attr->ia_valid & OCFS2_VALID_ATTRS))
 		return 0;
 
-	status = inode_change_ok(inode, attr);
+	status = setattr_prepare(dentry, attr);
 	if (status)
 		return status;
 
@@ -1268,20 +1268,20 @@
 	if (size_change)
 		ocfs2_rw_unlock(inode, 1);
 bail:
-	brelse(bh);
 
 	/* Release quota pointers in case we acquired them */
 	for (qtype = 0; qtype < OCFS2_MAXQUOTAS; qtype++)
 		dqput(transfer_to[qtype]);
 
 	if (!status && attr->ia_valid & ATTR_MODE) {
-		status = posix_acl_chmod(inode, inode->i_mode);
+		status = ocfs2_acl_chmod(inode, bh);
 		if (status < 0)
 			mlog_errno(status);
 	}
 	if (inode_locked)
 		ocfs2_inode_unlock(inode, 1);
 
+	brelse(bh);
 	return status;
 }
 
@@ -1536,7 +1536,8 @@
 				       u64 start, u64 len)
 {
 	int ret = 0;
-	u64 tmpend, end = start + len;
+	u64 tmpend = 0;
+	u64 end = start + len;
 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 	unsigned int csize = osb->s_clustersize;
 	handle_t *handle;
@@ -1568,18 +1569,31 @@
 	}
 
 	/*
-	 * We want to get the byte offset of the end of the 1st cluster.
+	 * If start is on a cluster boundary and end is somewhere in another
+	 * cluster, we have not COWed the cluster starting at start, unless
+	 * end is also within the same cluster. So, in this case, we skip this
+	 * first call to ocfs2_zero_range_for_truncate() truncate and move on
+	 * to the next one.
 	 */
-	tmpend = (u64)osb->s_clustersize + (start & ~(osb->s_clustersize - 1));
-	if (tmpend > end)
-		tmpend = end;
-
-	trace_ocfs2_zero_partial_clusters_range1((unsigned long long)start,
-						 (unsigned long long)tmpend);
+	if ((start & (csize - 1)) != 0) {
+		/*
+		 * We want to get the byte offset of the end of the 1st
+		 * cluster.
+		 */
+		tmpend = (u64)osb->s_clustersize +
+			(start & ~(osb->s_clustersize - 1));
+		if (tmpend > end)
+			tmpend = end;
+
+		trace_ocfs2_zero_partial_clusters_range1(
+			(unsigned long long)start,
+			(unsigned long long)tmpend);
 
-	ret = ocfs2_zero_range_for_truncate(inode, handle, start, tmpend);
-	if (ret)
-		mlog_errno(ret);
+		ret = ocfs2_zero_range_for_truncate(inode, handle, start,
+						    tmpend);
+		if (ret)
+			mlog_errno(ret);
+	}
 
 	if (tmpend < end) {
 		/*
@@ -1866,6 +1880,8 @@
 
 	mutex_lock(&inode->i_mutex);
 
+	/* Wait all existing dio workers, newcomers will block on i_rwsem */
+	inode_dio_wait(inode);
 	/*
 	 * This prevents concurrent writes on other nodes
 	 */
@@ -2293,6 +2309,8 @@
 
 	mutex_lock(&inode->i_mutex);
 
+	ocfs2_iocb_init_rw_locked(iocb);
+
 relock:
 	/*
 	 * Concurrent O_DIRECT writes are allowed with
@@ -2484,6 +2502,8 @@
 		goto bail;
 	}
 
+	ocfs2_iocb_init_rw_locked(iocb);
+
 	/*
 	 * buffered reads protect themselves in ->readpage().  O_DIRECT reads
 	 * need locks to protect pending reads from racing with truncate.
--- linux-4.4.0.orig/fs/ocfs2/ioctl.c
+++ linux-4.4.0/fs/ocfs2/ioctl.c
@@ -289,7 +289,7 @@
 	if (inode_alloc)
 		mutex_lock(&inode_alloc->i_mutex);
 
-	if (o2info_coherent(&fi->ifi_req)) {
+	if (inode_alloc && o2info_coherent(&fi->ifi_req)) {
 		status = ocfs2_inode_lock(inode_alloc, &bh, 0);
 		if (status < 0) {
 			mlog_errno(status);
--- linux-4.4.0.orig/fs/ocfs2/journal.c
+++ linux-4.4.0/fs/ocfs2/journal.c
@@ -666,23 +666,24 @@
 	/* we can safely remove this assertion after testing. */
 	if (!buffer_uptodate(bh)) {
 		mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n");
-		mlog(ML_ERROR, "b_blocknr=%llu\n",
-		     (unsigned long long)bh->b_blocknr);
+		mlog(ML_ERROR, "b_blocknr=%llu, b_state=0x%lx\n",
+		     (unsigned long long)bh->b_blocknr, bh->b_state);
 
 		lock_buffer(bh);
 		/*
-		 * A previous attempt to write this buffer head failed.
-		 * Nothing we can do but to retry the write and hope for
-		 * the best.
+		 * A previous transaction with a couple of buffer heads fail
+		 * to checkpoint, so all the bhs are marked as BH_Write_EIO.
+		 * For current transaction, the bh is just among those error
+		 * bhs which previous transaction handle. We can't just clear
+		 * its BH_Write_EIO and reuse directly, since other bhs are
+		 * not written to disk yet and that will cause metadata
+		 * inconsistency. So we should set fs read-only to avoid
+		 * further damage.
 		 */
 		if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) {
-			clear_buffer_write_io_error(bh);
-			set_buffer_uptodate(bh);
-		}
-
-		if (!buffer_uptodate(bh)) {
 			unlock_buffer(bh);
-			return -EIO;
+			return ocfs2_error(osb->sb, "A previous attempt to "
+					"write this buffer head failed\n");
 		}
 		unlock_buffer(bh);
 	}
@@ -1016,7 +1017,8 @@
 			mlog_errno(status);
 	}
 
-	if (status == 0) {
+	/* Shutdown the kernel journal system */
+	if (!jbd2_journal_destroy(journal->j_journal) && !status) {
 		/*
 		 * Do not toggle if flush was unsuccessful otherwise
 		 * will leave dirty metadata in a "clean" journal
@@ -1025,9 +1027,6 @@
 		if (status < 0)
 			mlog_errno(status);
 	}
-
-	/* Shutdown the kernel journal system */
-	jbd2_journal_destroy(journal->j_journal);
 	journal->j_journal = NULL;
 
 	OCFS2_I(inode)->ip_open_count--;
@@ -1081,6 +1080,14 @@
 
 	ocfs2_clear_journal_error(osb->sb, journal->j_journal, osb->slot_num);
 
+	if (replayed) {
+		jbd2_journal_lock_updates(journal->j_journal);
+		status = jbd2_journal_flush(journal->j_journal);
+		jbd2_journal_unlock_updates(journal->j_journal);
+		if (status < 0)
+			mlog_errno(status);
+	}
+
 	status = ocfs2_journal_toggle_dirty(osb, 1, replayed);
 	if (status < 0) {
 		mlog_errno(status);
--- linux-4.4.0.orig/fs/ocfs2/journal.h
+++ linux-4.4.0/fs/ocfs2/journal.h
@@ -637,9 +637,11 @@
 {
 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-	oi->i_sync_tid = handle->h_transaction->t_tid;
-	if (datasync)
-		oi->i_datasync_tid = handle->h_transaction->t_tid;
+	if (!is_handle_aborted(handle)) {
+		oi->i_sync_tid = handle->h_transaction->t_tid;
+		if (datasync)
+			oi->i_datasync_tid = handle->h_transaction->t_tid;
+	}
 }
 
 #endif /* OCFS2_JOURNAL_H */
--- linux-4.4.0.orig/fs/ocfs2/localalloc.c
+++ linux-4.4.0/fs/ocfs2/localalloc.c
@@ -345,13 +345,18 @@
 	if (num_used
 	    || alloc->id1.bitmap1.i_used
 	    || alloc->id1.bitmap1.i_total
-	    || la->la_bm_off)
-		mlog(ML_ERROR, "Local alloc hasn't been recovered!\n"
+	    || la->la_bm_off) {
+		mlog(ML_ERROR, "inconsistent detected, clean journal with"
+		     " unrecovered local alloc, please run fsck.ocfs2!\n"
 		     "found = %u, set = %u, taken = %u, off = %u\n",
 		     num_used, le32_to_cpu(alloc->id1.bitmap1.i_used),
 		     le32_to_cpu(alloc->id1.bitmap1.i_total),
 		     OCFS2_LOCAL_ALLOC(alloc)->la_bm_off);
 
+		status = -EINVAL;
+		goto bail;
+	}
+
 	osb->local_alloc_bh = alloc_bh;
 	osb->local_alloc_state = OCFS2_LA_ENABLED;
 
--- linux-4.4.0.orig/fs/ocfs2/move_extents.c
+++ linux-4.4.0/fs/ocfs2/move_extents.c
@@ -25,6 +25,7 @@
 #include "ocfs2_ioctl.h"
 
 #include "alloc.h"
+#include "localalloc.h"
 #include "aops.h"
 #include "dlmglue.h"
 #include "extent_map.h"
@@ -156,18 +157,14 @@
 }
 
 /*
- * lock allocators, and reserving appropriate number of bits for
- * meta blocks and data clusters.
- *
- * in some cases, we don't need to reserve clusters, just let data_ac
- * be NULL.
+ * lock allocator, and reserve appropriate number of bits for
+ * meta blocks.
  */
-static int ocfs2_lock_allocators_move_extents(struct inode *inode,
+static int ocfs2_lock_meta_allocator_move_extents(struct inode *inode,
 					struct ocfs2_extent_tree *et,
 					u32 clusters_to_move,
 					u32 extents_to_split,
 					struct ocfs2_alloc_context **meta_ac,
-					struct ocfs2_alloc_context **data_ac,
 					int extra_blocks,
 					int *credits)
 {
@@ -192,13 +189,6 @@
 		goto out;
 	}
 
-	if (data_ac) {
-		ret = ocfs2_reserve_clusters(osb, clusters_to_move, data_ac);
-		if (ret) {
-			mlog_errno(ret);
-			goto out;
-		}
-	}
 
 	*credits += ocfs2_calc_extend_credits(osb->sb, et->et_root_el);
 
@@ -233,6 +223,7 @@
 	struct ocfs2_refcount_tree *ref_tree = NULL;
 	u32 new_phys_cpos, new_len;
 	u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+	int need_free = 0;
 
 	if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) {
 
@@ -260,10 +251,10 @@
 		}
 	}
 
-	ret = ocfs2_lock_allocators_move_extents(inode, &context->et, *len, 1,
-						 &context->meta_ac,
-						 &context->data_ac,
-						 extra_blocks, &credits);
+	ret = ocfs2_lock_meta_allocator_move_extents(inode, &context->et,
+						*len, 1,
+						&context->meta_ac,
+						extra_blocks, &credits);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
@@ -286,6 +277,21 @@
 		}
 	}
 
+	/*
+	 * Make sure ocfs2_reserve_cluster is called after
+	 * __ocfs2_flush_truncate_log, otherwise, dead lock may happen.
+	 *
+	 * If ocfs2_reserve_cluster is called
+	 * before __ocfs2_flush_truncate_log, dead lock on global bitmap
+	 * may happen.
+	 *
+	 */
+	ret = ocfs2_reserve_clusters(osb, *len, &context->data_ac);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_unlock_mutex;
+	}
+
 	handle = ocfs2_start_trans(osb, credits);
 	if (IS_ERR(handle)) {
 		ret = PTR_ERR(handle);
@@ -311,6 +317,7 @@
 		if (!partial) {
 			context->range->me_flags &= ~OCFS2_MOVE_EXT_FL_COMPLETE;
 			ret = -ENOSPC;
+			need_free = 1;
 			goto out_commit;
 		}
 	}
@@ -335,6 +342,20 @@
 		mlog_errno(ret);
 
 out_commit:
+	if (need_free && context->data_ac) {
+		struct ocfs2_alloc_context *data_ac = context->data_ac;
+
+		if (context->data_ac->ac_which == OCFS2_AC_USE_LOCAL)
+			ocfs2_free_local_alloc_bits(osb, handle, data_ac,
+					new_phys_cpos, new_len);
+		else
+			ocfs2_free_clusters(handle,
+					data_ac->ac_inode,
+					data_ac->ac_bh,
+					ocfs2_clusters_to_blocks(osb->sb, new_phys_cpos),
+					new_len);
+	}
+
 	ocfs2_commit_trans(osb, handle);
 
 out_unlock_mutex:
@@ -606,9 +627,10 @@
 		}
 	}
 
-	ret = ocfs2_lock_allocators_move_extents(inode, &context->et, len, 1,
-						 &context->meta_ac,
-						 NULL, extra_blocks, &credits);
+	ret = ocfs2_lock_meta_allocator_move_extents(inode, &context->et,
+						len, 1,
+						&context->meta_ac,
+						extra_blocks, &credits);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
--- linux-4.4.0.orig/fs/ocfs2/namei.c
+++ linux-4.4.0/fs/ocfs2/namei.c
@@ -259,7 +259,6 @@
 	struct ocfs2_dir_lookup_result lookup = { NULL, };
 	sigset_t oldset;
 	int did_block_signals = 0;
-	struct posix_acl *default_acl = NULL, *acl = NULL;
 	struct ocfs2_dentry_lock *dl = NULL;
 
 	trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name,
@@ -367,12 +366,6 @@
 		goto leave;
 	}
 
-	status = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
-	if (status) {
-		mlog_errno(status);
-		goto leave;
-	}
-
 	handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb,
 							    S_ISDIR(mode),
 							    xattr_credits));
@@ -421,16 +414,8 @@
 		inc_nlink(dir);
 	}
 
-	if (default_acl) {
-		status = ocfs2_set_acl(handle, inode, new_fe_bh,
-				       ACL_TYPE_DEFAULT, default_acl,
-				       meta_ac, data_ac);
-	}
-	if (!status && acl) {
-		status = ocfs2_set_acl(handle, inode, new_fe_bh,
-				       ACL_TYPE_ACCESS, acl,
-				       meta_ac, data_ac);
-	}
+	status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh,
+			 meta_ac, data_ac);
 
 	if (status < 0) {
 		mlog_errno(status);
@@ -472,10 +457,6 @@
 	d_instantiate(dentry, inode);
 	status = 0;
 leave:
-	if (default_acl)
-		posix_acl_release(default_acl);
-	if (acl)
-		posix_acl_release(acl);
 	if (status < 0 && did_quota_inode)
 		dquot_free_inode(inode);
 	if (handle)
--- linux-4.4.0.orig/fs/ocfs2/ocfs2.h
+++ linux-4.4.0/fs/ocfs2/ocfs2.h
@@ -172,6 +172,7 @@
 
 	struct list_head         l_blocked_list;
 	struct list_head         l_mask_waiters;
+	struct list_head	 l_holders;
 
 	unsigned long		 l_flags;
 	char                     l_name[OCFS2_LOCK_ID_MAX_LEN];
@@ -336,8 +337,8 @@
 	spinlock_t osb_lock;
 	u32 s_next_generation;
 	unsigned long osb_flags;
-	s16 s_inode_steal_slot;
-	s16 s_meta_steal_slot;
+	u16 s_inode_steal_slot;
+	u16 s_meta_steal_slot;
 	atomic_t s_num_inodes_stolen;
 	atomic_t s_num_meta_stolen;
 
--- linux-4.4.0.orig/fs/ocfs2/ocfs2_fs.h
+++ linux-4.4.0/fs/ocfs2/ocfs2_fs.h
@@ -304,7 +304,7 @@
 #define OCFS2_MAX_SLOTS			255
 
 /* Slot map indicator for an empty slot */
-#define OCFS2_INVALID_SLOT		-1
+#define OCFS2_INVALID_SLOT		((u16)-1)
 
 #define OCFS2_VOL_UUID_LEN		16
 #define OCFS2_MAX_VOL_LABEL_LEN		64
@@ -340,8 +340,8 @@
 enum {
 	BAD_BLOCK_SYSTEM_INODE = 0,
 	GLOBAL_INODE_ALLOC_SYSTEM_INODE,
+#define OCFS2_FIRST_ONLINE_SYSTEM_INODE GLOBAL_INODE_ALLOC_SYSTEM_INODE
 	SLOT_MAP_SYSTEM_INODE,
-#define OCFS2_FIRST_ONLINE_SYSTEM_INODE SLOT_MAP_SYSTEM_INODE
 	HEARTBEAT_SYSTEM_INODE,
 	GLOBAL_BITMAP_SYSTEM_INODE,
 	USER_QUOTA_SYSTEM_INODE,
--- linux-4.4.0.orig/fs/ocfs2/quota_global.c
+++ linux-4.4.0/fs/ocfs2/quota_global.c
@@ -714,7 +714,7 @@
 
 	mutex_lock(&dquot->dq_lock);
 	/* Check whether we are not racing with some other dqget() */
-	if (atomic_read(&dquot->dq_count) > 1)
+	if (dquot_is_busy(dquot))
 		goto out;
 	/* Running from downconvert thread? Postpone quota processing to wq */
 	if (current == osb->dc_task) {
--- linux-4.4.0.orig/fs/ocfs2/refcounttree.c
+++ linux-4.4.0/fs/ocfs2/refcounttree.c
@@ -34,6 +34,7 @@
 #include "xattr.h"
 #include "namei.h"
 #include "ocfs2_trace.h"
+#include "symlink.h"
 
 #include <linux/bio.h>
 #include <linux/blkdev.h>
@@ -4178,8 +4179,9 @@
 	int ret;
 	struct inode *inode = d_inode(old_dentry);
 	struct buffer_head *new_bh = NULL;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-	if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE) {
+	if (oi->ip_flags & OCFS2_INODE_SYSTEM_FILE) {
 		ret = -EINVAL;
 		mlog_errno(ret);
 		goto out;
@@ -4205,6 +4207,26 @@
 		goto out_unlock;
 	}
 
+	if ((oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) &&
+	    (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
+		/*
+		 * Adjust extent record count to reserve space for extended attribute.
+		 * Inline data count had been adjusted in ocfs2_duplicate_inline_data().
+		 */
+		struct ocfs2_inode_info *new_oi = OCFS2_I(new_inode);
+
+		if (!(new_oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) &&
+		    !(ocfs2_inode_is_fast_symlink(new_inode))) {
+			struct ocfs2_dinode *new_di = (struct ocfs2_dinode *)new_bh->b_data;
+			struct ocfs2_dinode *old_di = (struct ocfs2_dinode *)old_bh->b_data;
+			struct ocfs2_extent_list *el = &new_di->id2.i_list;
+			int inline_size = le16_to_cpu(old_di->i_xattr_inline_size);
+
+			le16_add_cpu(&el->l_count, -(inline_size /
+					sizeof(struct ocfs2_extent_rec)));
+		}
+	}
+
 	ret = ocfs2_create_reflink_node(inode, old_bh,
 					new_inode, new_bh, preserve);
 	if (ret) {
@@ -4212,7 +4234,7 @@
 		goto inode_unlock;
 	}
 
-	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
+	if (oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
 		ret = ocfs2_reflink_xattrs(inode, old_bh,
 					   new_inode, new_bh,
 					   preserve);
@@ -4248,20 +4270,12 @@
 	struct inode *inode = d_inode(old_dentry);
 	struct buffer_head *old_bh = NULL;
 	struct inode *new_orphan_inode = NULL;
-	struct posix_acl *default_acl, *acl;
-	umode_t mode;
 
 	if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)))
 		return -EOPNOTSUPP;
 
-	mode = inode->i_mode;
-	error = posix_acl_create(dir, &mode, &default_acl, &acl);
-	if (error) {
-		mlog_errno(error);
-		return error;
-	}
 
-	error = ocfs2_create_inode_in_orphan(dir, mode,
+	error = ocfs2_create_inode_in_orphan(dir, inode->i_mode,
 					     &new_orphan_inode);
 	if (error) {
 		mlog_errno(error);
@@ -4300,16 +4314,11 @@
 	/* If the security isn't preserved, we need to re-initialize them. */
 	if (!preserve) {
 		error = ocfs2_init_security_and_acl(dir, new_orphan_inode,
-						    &new_dentry->d_name,
-						    default_acl, acl);
+						    &new_dentry->d_name);
 		if (error)
 			mlog_errno(error);
 	}
 out:
-	if (default_acl)
-		posix_acl_release(default_acl);
-	if (acl)
-		posix_acl_release(acl);
 	if (!error) {
 		error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode,
 						       new_dentry);
--- linux-4.4.0.orig/fs/ocfs2/resize.c
+++ linux-4.4.0/fs/ocfs2/resize.c
@@ -582,6 +582,8 @@
 	ocfs2_commit_trans(osb, handle);
 
 out_free_group_bh:
+	if (ret < 0)
+		ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh);
 	brelse(group_bh);
 
 out_unlock:
--- linux-4.4.0.orig/fs/ocfs2/suballoc.c
+++ linux-4.4.0/fs/ocfs2/suballoc.c
@@ -895,9 +895,9 @@
 {
 	spin_lock(&osb->osb_lock);
 	if (type == INODE_ALLOC_SYSTEM_INODE)
-		osb->s_inode_steal_slot = slot;
+		osb->s_inode_steal_slot = (u16)slot;
 	else if (type == EXTENT_ALLOC_SYSTEM_INODE)
-		osb->s_meta_steal_slot = slot;
+		osb->s_meta_steal_slot = (u16)slot;
 	spin_unlock(&osb->osb_lock);
 }
 
@@ -2863,9 +2863,12 @@
 		goto bail;
 	}
 
-	inode_alloc_inode =
-		ocfs2_get_system_file_inode(osb, INODE_ALLOC_SYSTEM_INODE,
-					    suballoc_slot);
+	if (suballoc_slot == (u16)OCFS2_INVALID_SLOT)
+		inode_alloc_inode = ocfs2_get_system_file_inode(osb,
+			GLOBAL_INODE_ALLOC_SYSTEM_INODE, suballoc_slot);
+	else
+		inode_alloc_inode = ocfs2_get_system_file_inode(osb,
+			INODE_ALLOC_SYSTEM_INODE, suballoc_slot);
 	if (!inode_alloc_inode) {
 		/* the error code could be inaccurate, but we are not able to
 		 * get the correct one. */
--- linux-4.4.0.orig/fs/ocfs2/super.c
+++ linux-4.4.0/fs/ocfs2/super.c
@@ -96,7 +96,7 @@
 	unsigned long	commit_interval;
 	unsigned long	mount_opt;
 	unsigned int	atime_quantum;
-	signed short	slot;
+	unsigned short	slot;
 	int		localalloc_opt;
 	unsigned int	resv_level;
 	int		dir_resv_level;
@@ -477,9 +477,8 @@
 		new = ocfs2_get_system_file_inode(osb, i, osb->slot_num);
 		if (!new) {
 			ocfs2_release_system_inodes(osb);
-			status = -EINVAL;
+			status = ocfs2_is_soft_readonly(osb) ? -EROFS : -EINVAL;
 			mlog_errno(status);
-			/* FIXME: Should ERROR_RO_FS */
 			mlog(ML_ERROR, "Unable to load system inode %d, "
 			     "possibly corrupt fs?", i);
 			goto bail;
@@ -508,7 +507,7 @@
 		new = ocfs2_get_system_file_inode(osb, i, osb->slot_num);
 		if (!new) {
 			ocfs2_release_system_inodes(osb);
-			status = -EINVAL;
+			status = ocfs2_is_soft_readonly(osb) ? -EROFS : -EINVAL;
 			mlog(ML_ERROR, "status=%d, sysfile=%d, slot=%d\n",
 			     status, i, osb->slot_num);
 			goto bail;
@@ -1373,7 +1372,7 @@
 				goto bail;
 			}
 			if (option)
-				mopt->slot = (s16)option;
+				mopt->slot = (u16)option;
 			break;
 		case Opt_commit:
 			option = 0;
@@ -1752,6 +1751,7 @@
 
 	oi->ip_blkno = 0ULL;
 	oi->ip_clusters = 0;
+	oi->ip_next_orphan = NULL;
 
 	ocfs2_resv_init_once(&oi->ip_la_data_resv);
 
--- linux-4.4.0.orig/fs/ocfs2/xattr.c
+++ linux-4.4.0/fs/ocfs2/xattr.c
@@ -639,9 +639,11 @@
 						     si->value_len);
 
 	if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
+		down_read(&OCFS2_I(dir)->ip_xattr_sem);
 		acl_len = ocfs2_xattr_get_nolock(dir, dir_bh,
 					OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT,
 					"", NULL, 0);
+		up_read(&OCFS2_I(dir)->ip_xattr_sem);
 		if (acl_len > 0) {
 			a_size = ocfs2_xattr_entry_real_size(0, acl_len);
 			if (S_ISDIR(mode))
@@ -2016,8 +2018,7 @@
 				rc = 0;
 			ocfs2_xa_cleanup_value_truncate(loc, "removing",
 							orig_clusters);
-			if (rc)
-				goto out;
+			goto out;
 		}
 	}
 
@@ -3806,7 +3807,6 @@
 	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
 	int low_bucket = 0, bucket, high_bucket;
 	struct ocfs2_xattr_bucket *search;
-	u32 last_hash;
 	u64 blkno, lower_blkno = 0;
 
 	search = ocfs2_xattr_bucket_new(inode);
@@ -3850,8 +3850,6 @@
 		if (xh->xh_count)
 			xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
 
-		last_hash = le32_to_cpu(xe->xe_name_hash);
-
 		/* record lower_blkno which may be the insert place. */
 		lower_blkno = blkno;
 
@@ -6503,16 +6501,7 @@
 	}
 
 	new_oi = OCFS2_I(args->new_inode);
-	/*
-	 * Adjust extent record count to reserve space for extended attribute.
-	 * Inline data count had been adjusted in ocfs2_duplicate_inline_data().
-	 */
-	if (!(new_oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) &&
-	    !(ocfs2_inode_is_fast_symlink(args->new_inode))) {
-		struct ocfs2_extent_list *el = &new_di->id2.i_list;
-		le16_add_cpu(&el->l_count, -(inline_size /
-					sizeof(struct ocfs2_extent_rec)));
-	}
+
 	spin_lock(&new_oi->ip_lock);
 	new_oi->ip_dyn_features |= OCFS2_HAS_XATTR_FL | OCFS2_INLINE_XATTR_FL;
 	new_di->i_dyn_features = cpu_to_le16(new_oi->ip_dyn_features);
@@ -7197,12 +7186,10 @@
  */
 int ocfs2_init_security_and_acl(struct inode *dir,
 				struct inode *inode,
-				const struct qstr *qstr,
-				struct posix_acl *default_acl,
-				struct posix_acl *acl)
+				const struct qstr *qstr)
 {
-	struct buffer_head *dir_bh = NULL;
 	int ret = 0;
+	struct buffer_head *dir_bh = NULL;
 
 	ret = ocfs2_init_security_get(inode, dir, qstr, NULL);
 	if (ret) {
@@ -7215,11 +7202,9 @@
 		mlog_errno(ret);
 		goto leave;
 	}
-
-	if (!ret && default_acl)
-		ret = ocfs2_iop_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
-	if (!ret && acl)
-		ret = ocfs2_iop_set_acl(inode, acl, ACL_TYPE_ACCESS);
+	ret = ocfs2_init_acl(NULL, inode, dir, NULL, dir_bh, NULL, NULL);
+	if (ret)
+		mlog_errno(ret);
 
 	ocfs2_inode_unlock(dir, 0);
 	brelse(dir_bh);
--- linux-4.4.0.orig/fs/ocfs2/xattr.h
+++ linux-4.4.0/fs/ocfs2/xattr.h
@@ -94,7 +94,5 @@
 			 bool preserve_security);
 int ocfs2_init_security_and_acl(struct inode *dir,
 				struct inode *inode,
-				const struct qstr *qstr,
-				struct posix_acl *default_acl,
-				struct posix_acl *acl);
+				const struct qstr *qstr);
 #endif /* OCFS2_XATTR_H */
--- linux-4.4.0.orig/fs/omfs/file.c
+++ linux-4.4.0/fs/omfs/file.c
@@ -349,7 +349,7 @@
 	struct inode *inode = d_inode(dentry);
 	int error;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/open.c
+++ linux-4.4.0/fs/open.c
@@ -34,6 +34,9 @@
 
 #include "internal.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/fs.h>
+
 int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
 	struct file *filp)
 {
@@ -64,6 +67,7 @@
 	mutex_unlock(&dentry->d_inode->i_mutex);
 	return ret;
 }
+EXPORT_SYMBOL(do_truncate);
 
 long vfs_truncate(struct path *path, loff_t length)
 {
@@ -363,6 +367,25 @@
 				override_cred->cap_permitted;
 	}
 
+	/*
+	 * The new set of credentials can *only* be used in
+	 * task-synchronous circumstances, and does not need
+	 * RCU freeing, unless somebody then takes a separate
+	 * reference to it.
+	 *
+	 * NOTE! This is _only_ true because this credential
+	 * is used purely for override_creds() that installs
+	 * it as the subjective cred. Other threads will be
+	 * accessing ->real_cred, not the subjective cred.
+	 *
+	 * If somebody _does_ make a copy of this (using the
+	 * 'get_current_cred()' function), that will clear the
+	 * non_rcu field, because now that other user may be
+	 * expecting RCU freeing. But normal thread-synchronous
+	 * cred accesses will keep things non-RCY.
+	 */
+	override_cred->non_rcu = 1;
+
 	old_cred = override_creds(override_cred);
 retry:
 	res = user_path_at(dfd, filename, lookup_flags, &path);
@@ -678,6 +701,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(open_check_o_direct);
 
 static int do_dentry_open(struct file *f,
 			  struct inode *inode,
@@ -840,16 +864,12 @@
 int vfs_open(const struct path *path, struct file *file,
 	     const struct cred *cred)
 {
-	struct dentry *dentry = path->dentry;
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = vfs_select_inode(path->dentry, file->f_flags);
 
-	file->f_path = *path;
-	if (dentry->d_flags & DCACHE_OP_SELECT_INODE) {
-		inode = dentry->d_op->d_select_inode(dentry, file->f_flags);
-		if (IS_ERR(inode))
-			return PTR_ERR(inode);
-	}
+	if (IS_ERR(inode))
+		return PTR_ERR(inode);
 
+	file->f_path = *path;
 	return do_dentry_open(file, inode, NULL, cred);
 }
 
@@ -889,6 +909,12 @@
 	int lookup_flags = 0;
 	int acc_mode;
 
+	/*
+	 * Clear out all open flags we don't know about so that we don't report
+	 * them in fcntl(F_GETFD) or similar interfaces.
+	 */
+	flags &= VALID_OPEN_FLAGS;
+
 	if (flags & (O_CREAT | __O_TMPFILE))
 		op->mode = (mode & S_IALLUGO) | S_IFREG;
 	else
@@ -995,14 +1021,12 @@
 EXPORT_SYMBOL(filp_open);
 
 struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
-			    const char *filename, int flags)
+			    const char *filename, int flags, umode_t mode)
 {
 	struct open_flags op;
-	int err = build_open_flags(flags, 0, &op);
+	int err = build_open_flags(flags, mode, &op);
 	if (err)
 		return ERR_PTR(err);
-	if (flags & O_CREAT)
-		return ERR_PTR(-EINVAL);
 	return do_file_open_root(dentry, mnt, filename, &op);
 }
 EXPORT_SYMBOL(file_open_root);
@@ -1029,6 +1053,7 @@
 		} else {
 			fsnotify_open(f);
 			fd_install(fd, f);
+			trace_do_sys_open(tmp->name, flags, mode);
 		}
 	}
 	putname(tmp);
@@ -1152,3 +1177,21 @@
 }
 
 EXPORT_SYMBOL(nonseekable_open);
+
+/*
+ * stream_open is used by subsystems that want stream-like file descriptors.
+ * Such file descriptors are not seekable and don't have notion of position
+ * (file.f_pos is always 0). Contrary to file descriptors of other regular
+ * files, .read() and .write() can run simultaneously.
+ *
+ * stream_open never fails and is marked to return int so that it could be
+ * directly used as file_operations.open .
+ */
+int stream_open(struct inode *inode, struct file *filp)
+{
+	filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE | FMODE_ATOMIC_POS);
+	filp->f_mode |= FMODE_STREAM;
+	return 0;
+}
+
+EXPORT_SYMBOL(stream_open);
--- linux-4.4.0.orig/fs/overlayfs/Kconfig
+++ linux-4.4.0/fs/overlayfs/Kconfig
@@ -8,3 +8,10 @@
 	  merged with the 'upper' object.
 
 	  For more information see Documentation/filesystems/overlayfs.txt
+
+config OVERLAY_FS_V1
+	bool "Overlayfs filesystem (V1) format support"
+	help
+	  Support the older whiteout format overlayfs filesystems via
+	  the overlay module.  This is needed to support legacy kernels
+	  built using the original overlayfs patch set.
--- linux-4.4.0.orig/fs/overlayfs/copy_up.c
+++ linux-4.4.0/fs/overlayfs/copy_up.c
@@ -22,9 +22,10 @@
 
 int ovl_copy_xattr(struct dentry *old, struct dentry *new)
 {
-	ssize_t list_size, size;
-	char *buf, *name, *value;
-	int error;
+	ssize_t list_size, size, value_size = 0;
+	char *buf, *name, *value = NULL;
+	int error = 0;
+	size_t slen;
 
 	if (!old->d_inode->i_op->getxattr ||
 	    !new->d_inode->i_op->getxattr)
@@ -41,29 +42,51 @@
 	if (!buf)
 		return -ENOMEM;
 
-	error = -ENOMEM;
-	value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL);
-	if (!value)
-		goto out;
-
 	list_size = vfs_listxattr(old, buf, list_size);
 	if (list_size <= 0) {
 		error = list_size;
-		goto out_free_value;
+		goto out;
 	}
 
-	for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
-		size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX);
-		if (size <= 0) {
+	for (name = buf; list_size; name += slen) {
+		slen = strnlen(name, list_size) + 1;
+
+		/* underlying fs providing us with an broken xattr list? */
+		if (WARN_ON(slen > list_size)) {
+			error = -EIO;
+			break;
+		}
+		list_size -= slen;
+
+		if (ovl_is_private_xattr(name))
+			continue;
+retry:
+		size = vfs_getxattr(old, name, value, value_size);
+		if (size == -ERANGE)
+			size = vfs_getxattr(old, name, NULL, 0);
+
+		if (size < 0) {
 			error = size;
-			goto out_free_value;
+			break;
+		}
+
+		if (size > value_size) {
+			void *new;
+
+			new = krealloc(value, size, GFP_KERNEL);
+			if (!new) {
+				error = -ENOMEM;
+				break;
+			}
+			value = new;
+			value_size = size;
+			goto retry;
 		}
+
 		error = vfs_setxattr(new, name, value, size, 0);
 		if (error)
-			goto out_free_value;
+			break;
 	}
-
-out_free_value:
 	kfree(value);
 out:
 	kfree(buf);
@@ -116,6 +139,8 @@
 		len -= bytes;
 	}
 
+	if (!error)
+		error = vfs_fsync(new_file, 0);
 	fput(new_file);
 out_fput:
 	fput(old_file);
@@ -172,10 +197,19 @@
 {
 	int err = 0;
 
+	/*
+	 * For the most part we want to set the mode bits before setting
+	 * the user, otherwise the current context might lack permission
+	 * for setting the mode. However for sxid/sticky bits we want
+	 * the operation to fail if the current user isn't privileged
+	 * towards the resulting inode. So we first set the mode but
+	 * exclude the sxid/sticky bits, then set the user, then set the
+	 * mode again if any of the sxid/sticky bits are set.
+	 */
 	if (!S_ISLNK(stat->mode)) {
 		struct iattr attr = {
 			.ia_valid = ATTR_MODE,
-			.ia_mode = stat->mode,
+			.ia_mode = stat->mode & ~(S_ISUID|S_ISGID|S_ISVTX),
 		};
 		err = notify_change(upperdentry, &attr, NULL);
 	}
@@ -187,6 +221,14 @@
 		};
 		err = notify_change(upperdentry, &attr, NULL);
 	}
+	if (!err && !S_ISLNK(stat->mode) &&
+	    (stat->mode & (S_ISUID|S_ISGID|S_ISVTX))) {
+		struct iattr attr = {
+			.ia_valid = ATTR_MODE,
+			.ia_mode = stat->mode,
+		};
+		err = notify_change(upperdentry, &attr, NULL);
+	}
 	if (!err)
 		ovl_set_timestamps(upperdentry, stat);
 
@@ -292,15 +334,22 @@
 	struct dentry *upperdir;
 	struct dentry *upperdentry;
 	const struct cred *old_cred;
-	struct cred *override_cred;
 	char *link = NULL;
 
 	if (WARN_ON(!workdir))
 		return -EROFS;
 
+	err = ovl_dentry_root_may(dentry, lowerpath, MAY_READ);
+	if (err)
+		return err;
+
 	ovl_path_upper(parent, &parentpath);
 	upperdir = parentpath.dentry;
 
+	err = ovl_dentry_root_may(dentry, &parentpath, MAY_WRITE);
+	if (err)
+		return err;
+
 	err = vfs_getattr(&parentpath, &pstat);
 	if (err)
 		return err;
@@ -311,28 +360,7 @@
 			return PTR_ERR(link);
 	}
 
-	err = -ENOMEM;
-	override_cred = prepare_creds();
-	if (!override_cred)
-		goto out_free_link;
-
-	override_cred->fsuid = stat->uid;
-	override_cred->fsgid = stat->gid;
-	/*
-	 * CAP_SYS_ADMIN for copying up extended attributes
-	 * CAP_DAC_OVERRIDE for create
-	 * CAP_FOWNER for chmod, timestamp update
-	 * CAP_FSETID for chmod
-	 * CAP_CHOWN for chown
-	 * CAP_MKNOD for mknod
-	 */
-	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
-	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
-	cap_raise(override_cred->cap_effective, CAP_FOWNER);
-	cap_raise(override_cred->cap_effective, CAP_FSETID);
-	cap_raise(override_cred->cap_effective, CAP_CHOWN);
-	cap_raise(override_cred->cap_effective, CAP_MKNOD);
-	old_cred = override_creds(override_cred);
+	old_cred = ovl_override_creds(dentry->d_sb);
 
 	err = -EIO;
 	if (lock_rename(workdir, upperdir) != NULL) {
@@ -355,9 +383,7 @@
 out_unlock:
 	unlock_rename(workdir, upperdir);
 	revert_creds(old_cred);
-	put_cred(override_cred);
 
-out_free_link:
 	if (link)
 		free_page((unsigned long) link);
 
--- linux-4.4.0.orig/fs/overlayfs/dir.c
+++ linux-4.4.0/fs/overlayfs/dir.c
@@ -12,6 +12,8 @@
 #include <linux/xattr.h>
 #include <linux/security.h>
 #include <linux/cred.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
 #include "overlayfs.h"
 
 void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
@@ -35,8 +37,10 @@
 {
 	struct dentry *temp;
 	char name[20];
+	static atomic_t temp_id = ATOMIC_INIT(0);
 
-	snprintf(name, sizeof(name), "#%lx", (unsigned long) dentry);
+	/* counter is allowed to wrap, since temp dentries are ephemeral */
+	snprintf(name, sizeof(name), "#%x", atomic_inc_return(&temp_id));
 
 	temp = lookup_one_len(name, workdir, strlen(name));
 	if (!IS_ERR(temp) && temp->d_inode) {
@@ -48,6 +52,34 @@
 	return temp;
 }
 
+#ifdef CONFIG_OVERLAY_FS_V1
+static const char *ovl_whiteout_symlink = "(overlay-whiteout)";
+int ovl_do_whiteout_v1(struct inode *workdir,
+			      struct dentry *dentry)
+{
+	int err;
+
+	err = vfs_symlink(workdir, dentry, ovl_whiteout_symlink);
+	if (err)
+		return err;
+
+	err = ovl_do_setxattr(dentry, ovl_whiteout_xattr, "y", 1, 0);
+	if (err)
+		vfs_unlink(workdir, dentry, NULL);
+
+	if (err) {
+		/*
+		 * There's no way to recover from failure to whiteout.
+		 * What should we do?  Log a big fat error and... ?
+		 */
+		pr_err("overlayfs: ERROR - failed to whiteout '%s'\n",
+		       dentry->d_name.name);
+	}
+
+	return err;
+}
+#endif
+
 /* caller holds i_mutex on workdir */
 static struct dentry *ovl_whiteout(struct dentry *workdir,
 				   struct dentry *dentry)
@@ -60,7 +92,7 @@
 	if (IS_ERR(whiteout))
 		return whiteout;
 
-	err = ovl_do_whiteout(wdir, whiteout);
+	err = ovl_do_whiteout(wdir, whiteout, dentry);
 	if (err) {
 		dput(whiteout);
 		whiteout = ERR_PTR(err);
@@ -144,8 +176,35 @@
 	if (err)
 		return err;
 
+	/*
+	 * When all layers are on the same fs, use the copy-up-origin st_ino,
+	 * which is persistent, unique and constant across copy up.
+	 *
+	 * Otherwise the pair {real st_ino; overlay st_dev} is not unique, so
+	 * use the non persistent overlay st_ino.
+	 */
+	if (ovl_same_sb(dentry->d_sb)) {
+		if (OVL_TYPE_MERGE(type) && OVL_TYPE_UPPER(type)) {
+			struct kstat lowerstat;
+
+			ovl_path_lower(dentry, &realpath);
+			err = vfs_getattr(&realpath, &lowerstat);
+			if (err)
+				return err;
+
+			WARN_ON_ONCE(stat->dev != lowerstat.dev);
+			stat->ino = lowerstat.ino;
+		}
+	} else {
+		stat->ino = dentry->d_inode->i_ino;
+	}
+
+	/*
+	 * Always use the overlay st_dev for directories, so 'find -xdev' will
+	 * scan the entire overlay mount and won't cross the overlay mount
+	 * boundaries.
+	 */
 	stat->dev = dentry->d_sb->s_dev;
-	stat->ino = dentry->d_inode->i_ino;
 
 	/*
 	 * It's probably not worth it to count subdirs to get the
@@ -321,6 +380,11 @@
 	struct inode *wdir = workdir->d_inode;
 	struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
 	struct inode *udir = upperdir->d_inode;
+	struct iattr attr = {
+		.ia_valid = ATTR_UID | ATTR_GID,
+		.ia_uid = stat->uid,
+		.ia_gid = stat->gid,
+	};
 	struct dentry *upper;
 	struct dentry *newdentry;
 	int err;
@@ -346,6 +410,11 @@
 	err = ovl_create_real(wdir, newdentry, stat, link, hardlink, true);
 	if (err)
 		goto out_dput2;
+	mutex_lock(&newdentry->d_inode->i_mutex);
+	err = notify_change(newdentry, &attr, NULL);
+	mutex_unlock(&newdentry->d_inode->i_mutex);
+	if (err)
+		goto out_cleanup;
 
 	if (S_ISDIR(stat->mode)) {
 		err = ovl_set_opaque(newdentry);
@@ -390,6 +459,8 @@
 	struct kstat stat = {
 		.mode = mode,
 		.rdev = rdev,
+		.uid  = current->cred->fsuid,
+		.gid  = current->cred->fsgid,
 	};
 
 	err = -ENOMEM;
@@ -407,26 +478,20 @@
 		const struct cred *old_cred;
 		struct cred *override_cred;
 
+		old_cred = ovl_override_creds(dentry->d_sb);
+
 		err = -ENOMEM;
 		override_cred = prepare_creds();
-		if (!override_cred)
-			goto out_iput;
-
-		/*
-		 * CAP_SYS_ADMIN for setting opaque xattr
-		 * CAP_DAC_OVERRIDE for create in workdir, rename
-		 * CAP_FOWNER for removing whiteout from sticky dir
-		 */
-		cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
-		cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
-		cap_raise(override_cred->cap_effective, CAP_FOWNER);
-		old_cred = override_creds(override_cred);
-
-		err = ovl_create_over_whiteout(dentry, inode, &stat, link,
-					       hardlink);
+		if (override_cred) {
+			override_cred->fsuid = old_cred->fsuid;
+			override_cred->fsgid = old_cred->fsgid;
+			put_cred(override_creds(override_cred));
+			put_cred(override_cred);
 
+			err = ovl_create_over_whiteout(dentry, inode, &stat,
+						       link, hardlink);
+		}
 		revert_creds(old_cred);
-		put_cred(override_cred);
 	}
 
 	if (!err)
@@ -511,6 +576,7 @@
 	struct dentry *upper;
 	struct dentry *opaquedir = NULL;
 	int err;
+	int flags = 0;
 
 	if (WARN_ON(!workdir))
 		return -EROFS;
@@ -540,46 +606,39 @@
 	if (err)
 		goto out_dput;
 
-	whiteout = ovl_whiteout(workdir, dentry);
-	err = PTR_ERR(whiteout);
-	if (IS_ERR(whiteout))
+	upper = lookup_one_len(dentry->d_name.name, upperdir,
+			       dentry->d_name.len);
+	err = PTR_ERR(upper);
+	if (IS_ERR(upper))
 		goto out_unlock;
 
-	upper = ovl_dentry_upper(dentry);
-	if (!upper) {
-		upper = lookup_one_len(dentry->d_name.name, upperdir,
-				       dentry->d_name.len);
-		err = PTR_ERR(upper);
-		if (IS_ERR(upper))
-			goto kill_whiteout;
-
-		err = ovl_do_rename(wdir, whiteout, udir, upper, 0);
-		dput(upper);
-		if (err)
-			goto kill_whiteout;
-	} else {
-		int flags = 0;
+	err = -ESTALE;
+	if ((opaquedir && upper != opaquedir) ||
+	    (!opaquedir && ovl_dentry_upper(dentry) &&
+	     upper != ovl_dentry_upper(dentry))) {
+		goto out_dput_upper;
+	}
 
-		if (opaquedir)
-			upper = opaquedir;
-		err = -ESTALE;
-		if (upper->d_parent != upperdir)
-			goto kill_whiteout;
+	whiteout = ovl_whiteout(workdir, dentry);
+	err = PTR_ERR(whiteout);
+	if (IS_ERR(whiteout))
+		goto out_dput_upper;
 
-		if (is_dir)
-			flags |= RENAME_EXCHANGE;
+	if (d_is_dir(upper))
+		flags = RENAME_EXCHANGE;
 
-		err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
-		if (err)
-			goto kill_whiteout;
+	err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
+	if (err)
+		goto kill_whiteout;
+	if (flags)
+		ovl_cleanup(wdir, upper);
 
-		if (is_dir)
-			ovl_cleanup(wdir, upper);
-	}
 	ovl_dentry_version_inc(dentry->d_parent);
 out_d_drop:
 	d_drop(dentry);
 	dput(whiteout);
+out_dput_upper:
+	dput(upper);
 out_unlock:
 	unlock_rename(workdir, upperdir);
 out_dput:
@@ -596,21 +655,25 @@
 {
 	struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
 	struct inode *dir = upperdir->d_inode;
-	struct dentry *upper = ovl_dentry_upper(dentry);
+	struct dentry *upper;
 	int err;
 
 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+	upper = lookup_one_len(dentry->d_name.name, upperdir,
+			       dentry->d_name.len);
+	err = PTR_ERR(upper);
+	if (IS_ERR(upper))
+		goto out_unlock;
+
 	err = -ESTALE;
-	if (upper->d_parent == upperdir) {
-		/* Don't let d_delete() think it can reset d_inode */
-		dget(upper);
+	if (upper == ovl_dentry_upper(dentry)) {
 		if (is_dir)
 			err = vfs_rmdir(dir, upper);
 		else
 			err = vfs_unlink(dir, upper, NULL);
-		dput(upper);
 		ovl_dentry_version_inc(dentry->d_parent);
 	}
+	dput(upper);
 
 	/*
 	 * Keeping this dentry hashed would mean having to release
@@ -618,7 +681,9 @@
 	 * sole user of this dentry.  Too tricky...  Just unhash for
 	 * now.
 	 */
-	d_drop(dentry);
+	if (!err)
+		d_drop(dentry);
+out_unlock:
 	mutex_unlock(&dir->i_mutex);
 
 	return err;
@@ -656,32 +721,11 @@
 	if (OVL_TYPE_PURE_UPPER(type)) {
 		err = ovl_remove_upper(dentry, is_dir);
 	} else {
-		const struct cred *old_cred;
-		struct cred *override_cred;
-
-		err = -ENOMEM;
-		override_cred = prepare_creds();
-		if (!override_cred)
-			goto out_drop_write;
-
-		/*
-		 * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
-		 * CAP_DAC_OVERRIDE for create in workdir, rename
-		 * CAP_FOWNER for removing whiteout from sticky dir
-		 * CAP_FSETID for chmod of opaque dir
-		 * CAP_CHOWN for chown of opaque dir
-		 */
-		cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
-		cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
-		cap_raise(override_cred->cap_effective, CAP_FOWNER);
-		cap_raise(override_cred->cap_effective, CAP_FSETID);
-		cap_raise(override_cred->cap_effective, CAP_CHOWN);
-		old_cred = override_creds(override_cred);
+		const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
 
 		err = ovl_remove_and_whiteout(dentry, is_dir);
 
 		revert_creds(old_cred);
-		put_cred(override_cred);
 	}
 out_drop_write:
 	ovl_drop_write(dentry);
@@ -699,6 +743,51 @@
 	return ovl_do_remove(dentry, true);
 }
 
+/*
+ * ovl_downgrade_whiteout -- build a symlink whiteout and install it
+ * over the existing chardev whiteout.
+ */
+static void ovl_downgrade_whiteout(struct dentry *old_upperdir,
+				   struct dentry *old)
+{
+	struct dentry *workdir = ovl_workdir(old);
+	struct dentry *legacy_whiteout = NULL;
+	struct dentry *whtdentry;
+	int err;
+
+	err = ovl_lock_rename_workdir(workdir, old_upperdir);
+	if (err)
+		goto out;
+
+	whtdentry = lookup_one_len(old->d_name.name, old_upperdir,
+				   old->d_name.len);
+	if (IS_ERR(whtdentry)) {
+		err = PTR_ERR(whtdentry);
+		goto out_unlock_workdir;
+	}
+
+	legacy_whiteout = ovl_whiteout(workdir, old);
+	if (IS_ERR(legacy_whiteout)) {
+		err = PTR_ERR(legacy_whiteout);
+		goto out_dput;
+	}
+
+	err = ovl_do_rename(workdir->d_inode, legacy_whiteout,
+			    old_upperdir->d_inode, whtdentry, 0);
+	if (err)
+		ovl_cleanup(workdir->d_inode, legacy_whiteout);
+
+out_dput:
+	dput(whtdentry);
+	dput(legacy_whiteout);
+out_unlock_workdir:
+	unlock_rename(workdir, old_upperdir);
+out:
+	if (err)
+		pr_err("overlayfs: dowgrade of '%pd2' whiteout failed (%i)\n",
+		       old, err);
+}
+
 static int ovl_rename2(struct inode *olddir, struct dentry *old,
 		       struct inode *newdir, struct dentry *new,
 		       unsigned int flags)
@@ -720,7 +809,6 @@
 	bool new_is_dir = false;
 	struct dentry *opaquedir = NULL;
 	const struct cred *old_cred = NULL;
-	struct cred *override_cred = NULL;
 
 	err = -EINVAL;
 	if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
@@ -789,26 +877,8 @@
 	old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
 	new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
 
-	if (old_opaque || new_opaque) {
-		err = -ENOMEM;
-		override_cred = prepare_creds();
-		if (!override_cred)
-			goto out_drop_write;
-
-		/*
-		 * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
-		 * CAP_DAC_OVERRIDE for create in workdir
-		 * CAP_FOWNER for removing whiteout from sticky dir
-		 * CAP_FSETID for chmod of opaque dir
-		 * CAP_CHOWN for chown of opaque dir
-		 */
-		cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
-		cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
-		cap_raise(override_cred->cap_effective, CAP_FOWNER);
-		cap_raise(override_cred->cap_effective, CAP_FSETID);
-		cap_raise(override_cred->cap_effective, CAP_CHOWN);
-		old_cred = override_creds(override_cred);
-	}
+	if (old_opaque || new_opaque)
+		old_cred = ovl_override_creds(old->d_sb);
 
 	if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
 		opaquedir = ovl_check_empty_and_clear(new);
@@ -839,29 +909,43 @@
 
 	trap = lock_rename(new_upperdir, old_upperdir);
 
-	olddentry = ovl_dentry_upper(old);
-	newdentry = ovl_dentry_upper(new);
-	if (newdentry) {
+
+	olddentry = lookup_one_len(old->d_name.name, old_upperdir,
+				   old->d_name.len);
+	err = PTR_ERR(olddentry);
+	if (IS_ERR(olddentry))
+		goto out_unlock;
+
+	err = -ESTALE;
+	if (olddentry != ovl_dentry_upper(old))
+		goto out_dput_old;
+
+	newdentry = lookup_one_len(new->d_name.name, new_upperdir,
+				   new->d_name.len);
+	err = PTR_ERR(newdentry);
+	if (IS_ERR(newdentry))
+		goto out_dput_old;
+
+	err = -ESTALE;
+	if (ovl_dentry_upper(new)) {
 		if (opaquedir) {
-			newdentry = opaquedir;
-			opaquedir = NULL;
+			if (newdentry != opaquedir)
+				goto out_dput;
 		} else {
-			dget(newdentry);
+			if (newdentry != ovl_dentry_upper(new))
+				goto out_dput;
 		}
 	} else {
 		new_create = true;
-		newdentry = lookup_one_len(new->d_name.name, new_upperdir,
-					   new->d_name.len);
-		err = PTR_ERR(newdentry);
-		if (IS_ERR(newdentry))
-			goto out_unlock;
+		if (!d_is_negative(newdentry)) {
+			if (!new_opaque || !ovl_is_whiteout(newdentry, ovl_config_legacy(new)))
+				goto out_dput;
+		} else {
+			if (flags & RENAME_EXCHANGE)
+				goto out_dput;
+		}
 	}
 
-	err = -ESTALE;
-	if (olddentry->d_parent != old_upperdir)
-		goto out_dput;
-	if (newdentry->d_parent != new_upperdir)
-		goto out_dput;
 	if (olddentry == trap)
 		goto out_dput;
 	if (newdentry == trap)
@@ -903,6 +987,13 @@
 	if (!overwrite && new_is_dir && !old_opaque && new_opaque)
 		ovl_remove_opaque(newdentry);
 
+	/*
+	 * Old dentry now lives in different location. Dentries in
+	 * lowerstack are stale. We cannot drop them here because
+	 * access to them is lockless. This could be only pure upper
+	 * or opaque directory - numlower is zero. Or upper non-dir
+	 * entry - its pureness is tracked by flag opaque.
+	 */
 	if (old_opaque != new_opaque) {
 		ovl_dentry_set_opaque(old, new_opaque);
 		if (!overwrite)
@@ -917,13 +1008,16 @@
 
 out_dput:
 	dput(newdentry);
+out_dput_old:
+	dput(olddentry);
 out_unlock:
 	unlock_rename(new_upperdir, old_upperdir);
+
+	if (!err && ovl_config_legacy(old) && flags & RENAME_WHITEOUT)
+		ovl_downgrade_whiteout(old_upperdir, old);
 out_revert_creds:
-	if (old_opaque || new_opaque) {
+	if (old_opaque || new_opaque)
 		revert_creds(old_cred);
-		put_cred(override_cred);
-	}
 out_drop_write:
 	ovl_drop_write(old);
 out:
--- linux-4.4.0.orig/fs/overlayfs/inode.c
+++ linux-4.4.0/fs/overlayfs/inode.c
@@ -42,6 +42,19 @@
 	int err;
 	struct dentry *upperdentry;
 
+	/*
+	 * Check for permissions before trying to copy-up.  This is redundant
+	 * since it will be rechecked later by ->setattr() on upper dentry.  But
+	 * without this, copy-up can be triggered by just about anybody.
+	 *
+	 * We don't initialize inode->size, which just means that
+	 * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
+	 * check for a swapfile (which this won't be anyway).
+	 */
+	err = setattr_prepare(dentry, attr);
+	if (err)
+		return err;
+
 	err = ovl_want_write(dentry);
 	if (err)
 		goto out;
@@ -50,8 +63,13 @@
 	if (!err) {
 		upperdentry = ovl_dentry_upper(dentry);
 
+		if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
+			attr->ia_valid &= ~ATTR_MODE;
+
 		mutex_lock(&upperdentry->d_inode->i_mutex);
 		err = notify_change(upperdentry, attr, NULL);
+		if (!err)
+			ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
 		mutex_unlock(&upperdentry->d_inode->i_mutex);
 	}
 	ovl_drop_write(dentry);
@@ -201,7 +219,7 @@
 }
 
 
-static bool ovl_is_private_xattr(const char *name)
+bool ovl_is_private_xattr(const char *name)
 {
 	return strncmp(name, OVL_XATTR_PRE_NAME, OVL_XATTR_PRE_LEN) == 0;
 }
@@ -254,12 +272,24 @@
 	return vfs_getxattr(realpath.dentry, name, value, size);
 }
 
+static bool ovl_can_list(const char *s)
+{
+	/* List all non-trusted xatts */
+	if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
+		return true;
+
+	/* Never list trusted.overlay, list other trusted for superuser only */
+	return !ovl_is_private_xattr(s) &&
+	       ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
+}
+
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
 {
 	struct path realpath;
 	enum ovl_path_type type = ovl_path_real(dentry, &realpath);
 	ssize_t res;
-	int off;
+	size_t len;
+	char *s;
 
 	res = vfs_listxattr(realpath.dentry, list, size);
 	if (res <= 0 || size == 0)
@@ -269,17 +299,19 @@
 		return res;
 
 	/* filter out private xattrs */
-	for (off = 0; off < res;) {
-		char *s = list + off;
-		size_t slen = strlen(s) + 1;
+	for (s = list, len = res; len;) {
+		size_t slen = strnlen(s, len) + 1;
 
-		BUG_ON(off + slen > res);
+		/* underlying fs providing us with an broken xattr list? */
+		if (WARN_ON(slen > len))
+			return -EIO;
 
-		if (ovl_is_private_xattr(s)) {
+		len -= slen;
+		if (!ovl_can_list(s)) {
 			res -= slen;
-			memmove(s, s + slen, res - off);
+			memmove(s, s + slen, len);
 		} else {
-			off += slen;
+			s += slen;
 		}
 	}
 
@@ -397,12 +429,11 @@
 	if (!inode)
 		return NULL;
 
-	mode &= S_IFMT;
-
 	inode->i_ino = get_next_ino();
 	inode->i_mode = mode;
 	inode->i_flags |= S_NOATIME | S_NOCMTIME;
 
+	mode &= S_IFMT;
 	switch (mode) {
 	case S_IFDIR:
 		inode->i_private = oe;
--- linux-4.4.0.orig/fs/overlayfs/overlayfs.h
+++ linux-4.4.0/fs/overlayfs/overlayfs.h
@@ -27,6 +27,8 @@
 #define OVL_XATTR_PRE_LEN  16
 #define OVL_XATTR_OPAQUE   OVL_XATTR_PRE_NAME"opaque"
 
+extern const char *ovl_whiteout_xattr; /* XXX: should be ^^ */
+
 static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	int err = vfs_rmdir(dir, dentry);
@@ -93,7 +95,14 @@
 static inline int ovl_do_setxattr(struct dentry *dentry, const char *name,
 				  const void *value, size_t size, int flags)
 {
-	int err = vfs_setxattr(dentry, name, value, size, flags);
+	struct inode *inode = dentry->d_inode;
+	int err = -EOPNOTSUPP;
+
+	mutex_lock(&inode->i_mutex);
+	if (inode->i_op->setxattr)
+		err = inode->i_op->setxattr(dentry, name, value, size, flags);
+	mutex_unlock(&inode->i_mutex);
+
 	pr_debug("setxattr(%pd2, \"%s\", \"%*s\", 0x%x) = %i\n",
 		 dentry, name, (int) size, (char *) value, flags, err);
 	return err;
@@ -101,7 +110,14 @@
 
 static inline int ovl_do_removexattr(struct dentry *dentry, const char *name)
 {
-	int err = vfs_removexattr(dentry, name);
+	struct inode *inode = dentry->d_inode;
+	int err = -EOPNOTSUPP;
+
+	mutex_lock(&inode->i_mutex);
+	if (inode->i_op->removexattr)
+		err = inode->i_op->removexattr(dentry, name);
+	mutex_unlock(&inode->i_mutex);
+
 	pr_debug("removexattr(%pd2, \"%s\") = %i\n", dentry, name, err);
 	return err;
 }
@@ -124,13 +140,30 @@
 	return err;
 }
 
-static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
+#ifdef CONFIG_OVERLAY_FS_V1
+extern int ovl_config_legacy(struct dentry *dentry);
+#else
+#define ovl_config_legacy(x) (0)
+#endif
+
+int ovl_do_whiteout_v1(struct inode *dir, struct dentry *dentry);
+
+static inline int ovl_do_whiteout_v2(struct inode *dir, struct dentry *dentry)
 {
 	int err = vfs_whiteout(dir, dentry);
 	pr_debug("whiteout(%pd2) = %i\n", dentry, err);
 	return err;
 }
+static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry,
+				  struct dentry *ovlentry)
+{
+	if (ovl_config_legacy(ovlentry))
+		return ovl_do_whiteout_v1(dir, dentry);
+
+	return ovl_do_whiteout_v2(dir, dentry);
+}
 
+struct super_block *ovl_same_sb(struct super_block *sb);
 enum ovl_path_type ovl_path_type(struct dentry *dentry);
 u64 ovl_dentry_version_get(struct dentry *dentry);
 void ovl_dentry_version_inc(struct dentry *dentry);
@@ -149,7 +182,8 @@
 void ovl_drop_write(struct dentry *dentry);
 bool ovl_dentry_is_opaque(struct dentry *dentry);
 void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
-bool ovl_is_whiteout(struct dentry *dentry);
+bool ovl_is_whiteout(struct dentry *dentry, int is_legacy);
+const struct cred *ovl_override_creds(struct super_block *sb);
 void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
 struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 			  unsigned int flags);
@@ -157,12 +191,16 @@
 
 struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry,
 				struct kstat *stat, const char *link);
+int ovl_dentry_root_may(struct dentry *dentry, struct path *realpath, int mode);
 
 /* readdir.c */
 extern const struct file_operations ovl_dir_operations;
 int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
 void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
 void ovl_cache_free(struct list_head *list);
+int ovl_check_d_type_supported(struct path *realpath);
+void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
+			 struct dentry *dentry, int level);
 
 /* inode.c */
 int ovl_setattr(struct dentry *dentry, struct iattr *attr);
@@ -174,6 +212,7 @@
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
 int ovl_removexattr(struct dentry *dentry, const char *name);
 struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags);
+bool ovl_is_private_xattr(const char *name);
 
 struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
 			    struct ovl_entry *oe);
@@ -181,6 +220,7 @@
 {
 	to->i_uid = from->i_uid;
 	to->i_gid = from->i_gid;
+	to->i_mode = from->i_mode;
 }
 
 /* dir.c */
--- linux-4.4.0.orig/fs/overlayfs/readdir.c
+++ linux-4.4.0/fs/overlayfs/readdir.c
@@ -14,6 +14,7 @@
 #include <linux/xattr.h>
 #include <linux/rbtree.h>
 #include <linux/security.h>
+#include <linux/sched.h>
 #include <linux/cred.h>
 #include "overlayfs.h"
 
@@ -36,13 +37,16 @@
 
 struct ovl_readdir_data {
 	struct dir_context ctx;
-	bool is_merge;
+	struct dentry *dentry;
+	bool is_lowest;
 	struct rb_root root;
 	struct list_head *list;
 	struct list_head middle;
 	struct ovl_cache_entry *first_maybe_whiteout;
 	int count;
 	int err;
+	bool d_type_supported;
+	int is_legacy;
 };
 
 struct ovl_dir_file {
@@ -98,7 +102,7 @@
 	p->ino = ino;
 	p->is_whiteout = false;
 
-	if (d_type == DT_CHR) {
+	if ((d_type == DT_CHR && !rdd->is_legacy) || (d_type == DT_LNK && rdd->is_legacy)) {
 		p->next_maybe_whiteout = rdd->first_maybe_whiteout;
 		rdd->first_maybe_whiteout = p;
 	}
@@ -139,9 +143,9 @@
 	return 0;
 }
 
-static int ovl_fill_lower(struct ovl_readdir_data *rdd,
-			  const char *name, int namelen,
-			  loff_t offset, u64 ino, unsigned int d_type)
+static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
+			   const char *name, int namelen,
+			   loff_t offset, u64 ino, unsigned int d_type)
 {
 	struct ovl_cache_entry *p;
 
@@ -193,10 +197,10 @@
 		container_of(ctx, struct ovl_readdir_data, ctx);
 
 	rdd->count++;
-	if (!rdd->is_merge)
+	if (!rdd->is_lowest)
 		return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
 	else
-		return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type);
+		return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
 }
 
 static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
@@ -205,17 +209,8 @@
 	struct ovl_cache_entry *p;
 	struct dentry *dentry;
 	const struct cred *old_cred;
-	struct cred *override_cred;
-
-	override_cred = prepare_creds();
-	if (!override_cred)
-		return -ENOMEM;
 
-	/*
-	 * CAP_DAC_OVERRIDE for lookup
-	 */
-	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
-	old_cred = override_creds(override_cred);
+	old_cred = ovl_override_creds(rdd->dentry->d_sb);
 
 	err = mutex_lock_killable(&dir->d_inode->i_mutex);
 	if (!err) {
@@ -224,14 +219,13 @@
 			rdd->first_maybe_whiteout = p->next_maybe_whiteout;
 			dentry = lookup_one_len(p->name, dir, p->len);
 			if (!IS_ERR(dentry)) {
-				p->is_whiteout = ovl_is_whiteout(dentry);
+				p->is_whiteout = ovl_is_whiteout(dentry, rdd->is_legacy);
 				dput(dentry);
 			}
 		}
 		mutex_unlock(&dir->d_inode->i_mutex);
 	}
 	revert_creds(old_cred);
-	put_cred(override_cred);
 
 	return err;
 }
@@ -256,7 +250,7 @@
 			err = rdd->err;
 	} while (!err && rdd->count);
 
-	if (!err && rdd->first_maybe_whiteout)
+	if (!err && rdd->first_maybe_whiteout && rdd->dentry)
 		err = ovl_check_whiteouts(realpath->dentry, rdd);
 
 	fput(realfile);
@@ -287,15 +281,21 @@
 	struct path realpath;
 	struct ovl_readdir_data rdd = {
 		.ctx.actor = ovl_fill_merge,
+		.dentry = dentry,
 		.list = list,
 		.root = RB_ROOT,
-		.is_merge = false,
+		.is_lowest = false,
+		.is_legacy = ovl_config_legacy(dentry),
 	};
 	int idx, next;
 
 	for (idx = 0; idx != -1; idx = next) {
 		next = ovl_path_next(idx, dentry, &realpath);
 
+		err = ovl_dentry_root_may(dentry, &realpath, MAY_READ);
+		if (err)
+			break;
+
 		if (next != -1) {
 			err = ovl_dir_read(&realpath, &rdd);
 			if (err)
@@ -306,7 +306,7 @@
 			 * allows offsets to be reasonably constant
 			 */
 			list_add(&rdd.middle, rdd.list);
-			rdd.is_merge = true;
+			rdd.is_lowest = true;
 			err = ovl_dir_read(&realpath, &rdd);
 			list_del(&rdd.middle);
 		}
@@ -369,8 +369,13 @@
 	if (!ctx->pos)
 		ovl_dir_reset(file);
 
-	if (od->is_real)
+	if (od->is_real) {
+		int res = ovl_dentry_root_may(dentry, &(od->realfile->f_path), MAY_READ);
+		if (res)
+			return res;
+
 		return iterate_dir(od->realfile, ctx);
+	}
 
 	if (!od->cache) {
 		struct ovl_dir_cache *cache;
@@ -441,10 +446,14 @@
 	struct dentry *dentry = file->f_path.dentry;
 	struct file *realfile = od->realfile;
 
+	/* Nothing to sync for lower */
+	if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
+		return 0;
+
 	/*
 	 * Need to check if we started out being a lower dir, but got copied up
 	 */
-	if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
+	if (!od->is_upper) {
 		struct inode *inode = file_inode(file);
 
 		realfile = lockless_dereference(od->upperfile);
@@ -571,8 +580,106 @@
 			       (int) PTR_ERR(dentry));
 			continue;
 		}
-		ovl_cleanup(upper->d_inode, dentry);
+		if (dentry->d_inode)
+			ovl_cleanup(upper->d_inode, dentry);
 		dput(dentry);
 	}
 	mutex_unlock(&upper->d_inode->i_mutex);
 }
+
+static int ovl_check_d_type(struct dir_context *ctx, const char *name,
+			  int namelen, loff_t offset, u64 ino,
+			  unsigned int d_type)
+{
+	struct ovl_readdir_data *rdd =
+		container_of(ctx, struct ovl_readdir_data, ctx);
+
+	/* Even if d_type is not supported, DT_DIR is returned for . and .. */
+	if (!strncmp(name, ".", namelen) || !strncmp(name, "..", namelen))
+		return 0;
+
+	if (d_type != DT_UNKNOWN)
+		rdd->d_type_supported = true;
+
+	return 0;
+}
+
+/*
+ * Returns 1 if d_type is supported, 0 not supported/unknown. Negative values
+ * if error is encountered.
+ */
+int ovl_check_d_type_supported(struct path *realpath)
+{
+	int err;
+	struct ovl_readdir_data rdd = {
+		.ctx.actor = ovl_check_d_type,
+		.d_type_supported = false,
+	};
+
+	err = ovl_dir_read(realpath, &rdd);
+	if (err)
+		return err;
+
+	return rdd.d_type_supported;
+}
+
+static void ovl_workdir_cleanup_recurse(struct path *path, int level)
+{
+	int err;
+	struct inode *dir = path->dentry->d_inode;
+	LIST_HEAD(list);
+	struct ovl_cache_entry *p;
+	struct ovl_readdir_data rdd = {
+		.ctx.actor = ovl_fill_merge,
+		.dentry = NULL,
+		.list = &list,
+		.root = RB_ROOT,
+		.is_lowest = false,
+	};
+
+	err = ovl_dir_read(path, &rdd);
+	if (err)
+		goto out;
+
+	inode_lock_nested(dir, I_MUTEX_PARENT);
+	list_for_each_entry(p, &list, l_node) {
+		struct dentry *dentry;
+
+		if (p->name[0] == '.') {
+			if (p->len == 1)
+				continue;
+			if (p->len == 2 && p->name[1] == '.')
+				continue;
+		}
+		dentry = lookup_one_len(p->name, path->dentry, p->len);
+		if (IS_ERR(dentry))
+			continue;
+		if (dentry->d_inode)
+			ovl_workdir_cleanup(dir, path->mnt, dentry, level);
+		dput(dentry);
+	}
+	inode_unlock(dir);
+out:
+	ovl_cache_free(&list);
+}
+
+void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
+			 struct dentry *dentry, int level)
+{
+	int err;
+
+	if (!d_is_dir(dentry) || level > 1) {
+		ovl_cleanup(dir, dentry);
+		return;
+	}
+
+	err = ovl_do_rmdir(dir, dentry);
+	if (err) {
+		struct path path = { .mnt = mnt, .dentry = dentry };
+
+		inode_unlock(dir);
+		ovl_workdir_cleanup_recurse(&path, level + 1);
+		inode_lock_nested(dir, I_MUTEX_PARENT);
+		ovl_cleanup(dir, dentry);
+	}
+}
--- linux-4.4.0.orig/fs/overlayfs/super.c
+++ linux-4.4.0/fs/overlayfs/super.c
@@ -9,6 +9,7 @@
 
 #include <linux/fs.h>
 #include <linux/namei.h>
+#include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/security.h>
 #include <linux/mount.h>
@@ -39,8 +40,13 @@
 	struct vfsmount **lower_mnt;
 	struct dentry *workdir;
 	long lower_namelen;
+	int legacy;
 	/* pathnames of lower and upper dirs, for show_options */
 	struct ovl_config config;
+	/* creds of process who forced instantiation of super block */
+	struct cred *creator_cred;
+	/* sb common to all layers */
+	struct super_block *same_sb;
 };
 
 struct ovl_dir_cache;
@@ -75,12 +81,14 @@
 	if (oe->__upperdentry) {
 		type = __OVL_PATH_UPPER;
 
-		if (oe->numlower) {
-			if (S_ISDIR(dentry->d_inode->i_mode))
-				type |= __OVL_PATH_MERGE;
-		} else if (!oe->opaque) {
+		/*
+		 * Non-dir dentry can hold lower dentry from previous
+		 * location. Its purity depends only on opaque flag.
+		 */
+		if (oe->numlower && S_ISDIR(dentry->d_inode->i_mode))
+			type |= __OVL_PATH_MERGE;
+		else if (!oe->opaque)
 			type |= __OVL_PATH_PURE;
-		}
 	} else {
 		if (oe->numlower > 1)
 			type |= __OVL_PATH_MERGE;
@@ -236,13 +244,79 @@
 	return oe->version;
 }
 
-bool ovl_is_whiteout(struct dentry *dentry)
+int ovl_dentry_root_may(struct dentry *dentry, struct path *realpath, int mode)
+{
+	const struct cred *old_cred;
+	int err = 0;
+        struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
+
+	old_cred = override_creds(ofs->creator_cred);
+
+	if (inode_permission(realpath->dentry->d_inode, mode))
+		err = -EACCES;
+
+	revert_creds(old_cred);
+
+	return err;
+}
+
+#ifdef CONFIG_OVERLAY_FS_V1
+int ovl_config_legacy(struct dentry *dentry)
+{
+	struct super_block *sb = dentry->d_sb;
+	struct ovl_fs *ufs = sb->s_fs_info;
+
+	return ufs->legacy;
+}
+
+const char *ovl_whiteout_xattr = "trusted.overlay.whiteout";
+
+bool ovl_is_whiteout_v1(struct dentry *dentry)
+{
+	int res;
+	char val;
+
+	if (!dentry)
+		return false;
+	if (!dentry->d_inode)
+		return false;
+	if (!S_ISLNK(dentry->d_inode->i_mode))
+		return false;
+	if (!dentry->d_inode->i_op->getxattr)
+		return false;
+
+	res = dentry->d_inode->i_op->getxattr(dentry, ovl_whiteout_xattr, &val, 1);
+	if (res == 1 && val == 'y')
+		return true;
+
+	return false;
+}
+#else
+#define ovl_is_whiteout_v1(x) (0)
+#endif
+
+bool ovl_is_whiteout_v2(struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
 
 	return inode && IS_WHITEOUT(inode);
 }
 
+bool ovl_is_whiteout(struct dentry *dentry, int is_legacy)
+{
+	if (is_legacy)
+		return ovl_is_whiteout_v2(dentry) || ovl_is_whiteout_v1(dentry);
+
+	return ovl_is_whiteout_v2(dentry);
+}
+
+const struct cred *ovl_override_creds(struct super_block *sb)
+{
+	struct ovl_fs *ofs = sb->s_fs_info;
+
+	return override_creds(ofs->creator_cred);
+}
+
 static bool ovl_is_opaquedir(struct dentry *dentry)
 {
 	int res;
@@ -273,6 +347,37 @@
 	}
 }
 
+static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
+{
+	struct dentry *real;
+
+	if (d_is_dir(dentry)) {
+		if (!inode || inode == d_inode(dentry))
+			return dentry;
+		goto bug;
+	}
+
+	real = ovl_dentry_upper(dentry);
+	if (real && (!inode || inode == d_inode(real)))
+		return real;
+
+	real = ovl_dentry_lower(dentry);
+	if (!real)
+		goto bug;
+
+	if (!inode || inode == d_inode(real))
+		return real;
+
+	/* Handle recursion */
+	if (real->d_flags & DCACHE_OP_REAL)
+		return real->d_op->d_real(real, inode);
+
+bug:
+	WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry,
+	     inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0);
+	return dentry;
+}
+
 static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct ovl_entry *oe = dentry->d_fsdata;
@@ -317,14 +422,24 @@
 static const struct dentry_operations ovl_dentry_operations = {
 	.d_release = ovl_dentry_release,
 	.d_select_inode = ovl_d_select_inode,
+	.d_real = ovl_d_real,
 };
 
 static const struct dentry_operations ovl_reval_dentry_operations = {
 	.d_release = ovl_dentry_release,
+	.d_select_inode = ovl_d_select_inode,
+	.d_real = ovl_d_real,
 	.d_revalidate = ovl_dentry_revalidate,
 	.d_weak_revalidate = ovl_dentry_weak_revalidate,
 };
 
+struct super_block *ovl_same_sb(struct super_block *sb)
+{
+	struct ovl_fs *ofs = sb->s_fs_info;
+
+	return ofs->same_sb;
+}
+
 static struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
 {
 	size_t size = offsetof(struct ovl_entry, lowerstack[numlower]);
@@ -339,7 +454,8 @@
 static bool ovl_dentry_remote(struct dentry *dentry)
 {
 	return dentry->d_flags &
-		(DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
+		(DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE |
+		 DCACHE_OP_REAL);
 }
 
 static bool ovl_dentry_weird(struct dentry *dentry)
@@ -350,14 +466,18 @@
 				  DCACHE_OP_COMPARE);
 }
 
-static inline struct dentry *ovl_lookup_real(struct dentry *dir,
+static inline struct dentry *ovl_lookup_real(struct super_block *ovl_sb,
+					     struct dentry *dir,
 					     struct qstr *name)
 {
+	const struct cred *old_cred;
 	struct dentry *dentry;
 
+	old_cred = ovl_override_creds(ovl_sb);
 	mutex_lock(&dir->d_inode->i_mutex);
 	dentry = lookup_one_len(name->name, dir, name->len);
 	mutex_unlock(&dir->d_inode->i_mutex);
+	revert_creds(old_cred);
 
 	if (IS_ERR(dentry)) {
 		if (PTR_ERR(dentry) == -ENOENT)
@@ -407,10 +527,11 @@
 	struct dentry *this, *prev = NULL;
 	unsigned int i;
 	int err;
+	int is_legacy = ovl_config_legacy(dentry);
 
 	upperdir = ovl_upperdentry_dereference(poe);
 	if (upperdir) {
-		this = ovl_lookup_real(upperdir, &dentry->d_name);
+		this = ovl_lookup_real(dentry->d_sb, upperdir, &dentry->d_name);
 		err = PTR_ERR(this);
 		if (IS_ERR(this))
 			goto out;
@@ -421,7 +542,7 @@
 				err = -EREMOTE;
 				goto out;
 			}
-			if (ovl_is_whiteout(this)) {
+			if (ovl_is_whiteout(this, is_legacy)) {
 				dput(this);
 				this = NULL;
 				upperopaque = true;
@@ -443,7 +564,8 @@
 		bool opaque = false;
 		struct path lowerpath = poe->lowerstack[i];
 
-		this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name);
+		this = ovl_lookup_real(dentry->d_sb,
+				       lowerpath.dentry, &dentry->d_name);
 		err = PTR_ERR(this);
 		if (IS_ERR(this)) {
 			/*
@@ -455,7 +577,7 @@
 		}
 		if (!this)
 			continue;
-		if (ovl_is_whiteout(this)) {
+		if (ovl_is_whiteout(this, is_legacy)) {
 			dput(this);
 			break;
 		}
@@ -549,6 +671,7 @@
 	kfree(ufs->config.lowerdir);
 	kfree(ufs->config.upperdir);
 	kfree(ufs->config.workdir);
+	put_cred(ufs->creator_cred);
 	kfree(ufs);
 }
 
@@ -725,6 +848,10 @@
 		struct kstat stat = {
 			.mode = S_IFDIR | 0,
 		};
+		struct iattr attr = {
+			.ia_valid = ATTR_MODE,
+			.ia_mode = stat.mode,
+		};
 
 		if (work->d_inode) {
 			err = -EEXIST;
@@ -732,7 +859,7 @@
 				goto out_dput;
 
 			retried = true;
-			ovl_cleanup(dir, work);
+			ovl_workdir_cleanup(dir, mnt, work, 0);
 			dput(work);
 			goto retry;
 		}
@@ -740,6 +867,21 @@
 		err = ovl_create_real(dir, work, &stat, NULL, NULL, true);
 		if (err)
 			goto out_dput;
+
+		err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_DEFAULT);
+		if (err && err != -ENODATA && err != -EOPNOTSUPP)
+			goto out_dput;
+
+		err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_ACCESS);
+		if (err && err != -ENODATA && err != -EOPNOTSUPP)
+			goto out_dput;
+
+		/* Clear any inherited mode bits */
+		inode_lock(work->d_inode);
+		err = notify_change(work, &attr, NULL);
+		inode_unlock(work->d_inode);
+		if (err)
+			goto out_dput;
 	}
 out_unlock:
 	mutex_unlock(&dir->i_mutex);
@@ -910,6 +1052,7 @@
 	}
 
 	sb->s_stack_depth = 0;
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	if (ufs->config.upperdir) {
 		if (!ufs->config.workdir) {
 			pr_err("overlayfs: missing 'workdir'\n");
@@ -988,6 +1131,9 @@
 			goto out_put_lowerpath;
 		}
 
+		if (ufs->upper_mnt->mnt_flags & MNT_NOSUID)
+			sb->s_iflags |= SB_I_NOSUID;
+
 		ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
 		err = PTR_ERR(ufs->workdir);
 		if (IS_ERR(ufs->workdir)) {
@@ -996,6 +1142,26 @@
 			sb->s_flags |= MS_RDONLY;
 			ufs->workdir = NULL;
 		}
+
+		/*
+		 * Upper should support d_type, else whiteouts are visible.
+		 * Given workdir and upper are on same fs, we can do
+		 * iterate_dir() on workdir. This check requires successful
+		 * creation of workdir in previous step.
+		 */
+		if (ufs->workdir) {
+			err = ovl_check_d_type_supported(&workpath);
+			if (err < 0)
+				goto out_put_workdir;
+
+			/*
+			 * We allowed this configuration and don't want to
+			 * break users over kernel upgrade. So warn instead
+			 * of erroring out.
+			 */
+			if (!err)
+				pr_warn("overlayfs: upper fs needs to support d_type.\n");
+		}
 	}
 
 	err = -ENOMEM;
@@ -1016,23 +1182,38 @@
 		 */
 		mnt->mnt_flags |= MNT_READONLY;
 
+		if (mnt->mnt_flags & MNT_NOSUID)
+			sb->s_iflags |= SB_I_NOSUID;
+
 		ufs->lower_mnt[ufs->numlower] = mnt;
 		ufs->numlower++;
+
+		/* Check if all lower layers are on same sb */
+		if (i == 0)
+			ufs->same_sb = mnt->mnt_sb;
+		else if (ufs->same_sb != mnt->mnt_sb)
+			ufs->same_sb = NULL;
 	}
 
 	/* If the upper fs is nonexistent, we mark overlayfs r/o too */
 	if (!ufs->upper_mnt)
 		sb->s_flags |= MS_RDONLY;
+	else if (ufs->upper_mnt->mnt_sb != ufs->same_sb)
+		ufs->same_sb = NULL;
 
 	if (remote)
 		sb->s_d_op = &ovl_reval_dentry_operations;
 	else
 		sb->s_d_op = &ovl_dentry_operations;
 
+	ufs->creator_cred = prepare_creds();
+	if (!ufs->creator_cred)
+		goto out_put_lower_mnt;
+
 	err = -ENOMEM;
 	oe = ovl_alloc_entry(numlower);
 	if (!oe)
-		goto out_put_lower_mnt;
+		goto out_put_cred;
 
 	root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
 	if (!root_dentry)
@@ -1053,6 +1234,9 @@
 
 	root_dentry->d_fsdata = oe;
 
+	ovl_copyattr(ovl_dentry_real(root_dentry)->d_inode,
+		     root_dentry->d_inode);
+
 	sb->s_magic = OVERLAYFS_SUPER_MAGIC;
 	sb->s_op = &ovl_super_operations;
 	sb->s_root = root_dentry;
@@ -1062,6 +1246,8 @@
 
 out_free_oe:
 	kfree(oe);
+out_put_cred:
+	put_cred(ufs->creator_cred);
 out_put_lower_mnt:
 	for (i = 0; i < ufs->numlower; i++)
 		mntput(ufs->lower_mnt[i]);
@@ -1099,17 +1285,63 @@
 	.name		= "overlay",
 	.mount		= ovl_mount,
 	.kill_sb	= kill_anon_super,
+	.fs_flags	= FS_USERNS_MOUNT,
 };
 MODULE_ALIAS_FS("overlay");
 
+#ifdef CONFIG_OVERLAY_FS_V1
+static int ovl_v1_fill_super(struct super_block *sb, void *data, int silent)
+{
+	int ret;
+	struct ovl_fs *ufs;
+
+	ret = ovl_fill_super(sb, data, silent);
+	if (ret)
+		return ret;
+
+	/* Mark this as a overlayfs format. */
+	ufs = sb->s_fs_info;
+	ufs->legacy = 1;
+
+	return ret;
+}
+
+static struct dentry *ovl_mount_v1(struct file_system_type *fs_type, int flags,
+				const char *dev_name, void *raw_data)
+{
+	return mount_nodev(fs_type, flags, raw_data, ovl_v1_fill_super);
+}
+
+static struct file_system_type ovl_v1_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "overlayfs",
+	.mount		= ovl_mount_v1,
+	.kill_sb	= kill_anon_super,
+	.fs_flags	= FS_USERNS_MOUNT,  /* XXX */
+};
+MODULE_ALIAS_FS("overlayfs");
+MODULE_ALIAS("overlayfs");
+#endif
+
 static int __init ovl_init(void)
 {
+	int ret;
+
+	if (IS_ENABLED(CONFIG_OVERLAY_FS_V1)) {
+		ret = register_filesystem(&ovl_v1_fs_type);
+		if (ret)
+			return ret;
+	}
+
 	return register_filesystem(&ovl_fs_type);
 }
 
 static void __exit ovl_exit(void)
 {
 	unregister_filesystem(&ovl_fs_type);
+
+	if (IS_ENABLED(CONFIG_OVERLAY_FS_V1))
+		unregister_filesystem(&ovl_v1_fs_type);
 }
 
 module_init(ovl_init);
--- linux-4.4.0.orig/fs/pipe.c
+++ linux-4.4.0/fs/pipe.c
@@ -38,6 +38,12 @@
  */
 unsigned int pipe_min_size = PAGE_SIZE;
 
+/* Maximum allocatable pages per user. Hard limit is unset by default, soft
+ * matches default values.
+ */
+unsigned long pipe_user_pages_hard;
+unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR;
+
 /*
  * We use a start+len construction, which provides full use of the 
  * allocated memory.
@@ -172,9 +178,9 @@
  *	in the tee() system call, when we duplicate the buffers in one
  *	pipe into another.
  */
-void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
+bool generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
 {
-	page_cache_get(buf->page);
+	return try_get_page(buf->page);
 }
 EXPORT_SYMBOL(generic_pipe_buf_get);
 
@@ -583,20 +589,52 @@
 	return retval;
 }
 
+static void account_pipe_buffers(struct pipe_inode_info *pipe,
+                                 unsigned long old, unsigned long new)
+{
+	atomic_long_add(new - old, &pipe->user->pipe_bufs);
+}
+
+static bool too_many_pipe_buffers_soft(struct user_struct *user)
+{
+	return pipe_user_pages_soft &&
+	       atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_soft;
+}
+
+static bool too_many_pipe_buffers_hard(struct user_struct *user)
+{
+	return pipe_user_pages_hard &&
+	       atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_hard;
+}
+
 struct pipe_inode_info *alloc_pipe_info(void)
 {
 	struct pipe_inode_info *pipe;
 
 	pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
 	if (pipe) {
-		pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL);
+		unsigned long pipe_bufs = PIPE_DEF_BUFFERS;
+		struct user_struct *user = get_current_user();
+
+		if (pipe_bufs * PAGE_SIZE > pipe_max_size && !capable(CAP_SYS_RESOURCE))
+			pipe_bufs = pipe_max_size >> PAGE_SHIFT;
+
+		if (!too_many_pipe_buffers_hard(user)) {
+			if (too_many_pipe_buffers_soft(user))
+				pipe_bufs = 1;
+			pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * pipe_bufs, GFP_KERNEL);
+		}
+
 		if (pipe->bufs) {
 			init_waitqueue_head(&pipe->wait);
 			pipe->r_counter = pipe->w_counter = 1;
-			pipe->buffers = PIPE_DEF_BUFFERS;
+			pipe->buffers = pipe_bufs;
+			pipe->user = user;
+			account_pipe_buffers(pipe, 0, pipe_bufs);
 			mutex_init(&pipe->mutex);
 			return pipe;
 		}
+		free_uid(user);
 		kfree(pipe);
 	}
 
@@ -607,6 +645,8 @@
 {
 	int i;
 
+	account_pipe_buffers(pipe, pipe->buffers, 0);
+	free_uid(pipe->user);
 	for (i = 0; i < pipe->buffers; i++) {
 		struct pipe_buffer *buf = pipe->bufs + i;
 		if (buf->ops)
@@ -964,6 +1004,9 @@
 {
 	struct pipe_buffer *bufs;
 
+	if (!nr_pages)
+		return -EINVAL;
+
 	/*
 	 * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't
 	 * expect a lot of shrink+grow operations, just free and allocate
@@ -998,6 +1041,7 @@
 			memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer));
 	}
 
+	account_pipe_buffers(pipe, pipe->buffers, nr_pages);
 	pipe->curbuf = 0;
 	kfree(pipe->bufs);
 	pipe->bufs = bufs;
@@ -1007,13 +1051,19 @@
 
 /*
  * Currently we rely on the pipe array holding a power-of-2 number
- * of pages.
+ * of pages. Returns 0 on error.
  */
 static inline unsigned int round_pipe_size(unsigned int size)
 {
 	unsigned long nr_pages;
 
+	if (size < pipe_min_size)
+		size = pipe_min_size;
+
 	nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	if (nr_pages == 0)
+		return 0;
+
 	return roundup_pow_of_two(nr_pages) << PAGE_SHIFT;
 }
 
@@ -1024,13 +1074,18 @@
 int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
 		 size_t *lenp, loff_t *ppos)
 {
+	unsigned int rounded_pipe_max_size;
 	int ret;
 
 	ret = proc_dointvec_minmax(table, write, buf, lenp, ppos);
 	if (ret < 0 || !write)
 		return ret;
 
-	pipe_max_size = round_pipe_size(pipe_max_size);
+	rounded_pipe_max_size = round_pipe_size(pipe_max_size);
+	if (rounded_pipe_max_size == 0)
+		return -EINVAL;
+
+	pipe_max_size = rounded_pipe_max_size;
 	return ret;
 }
 
@@ -1069,6 +1124,11 @@
 		if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) {
 			ret = -EPERM;
 			goto out;
+		} else if ((too_many_pipe_buffers_hard(pipe->user) ||
+			    too_many_pipe_buffers_soft(pipe->user)) &&
+		           !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
+			ret = -EPERM;
+			goto out;
 		}
 		ret = pipe_set_size(pipe, nr_pages);
 		break;
--- linux-4.4.0.orig/fs/pnode.c
+++ linux-4.4.0/fs/pnode.c
@@ -24,6 +24,11 @@
 	return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave);
 }
 
+static inline struct mount *last_slave(struct mount *p)
+{
+	return list_entry(p->mnt_slave_list.prev, struct mount, mnt_slave);
+}
+
 static inline struct mount *next_slave(struct mount *p)
 {
 	return list_entry(p->mnt_slave.next, struct mount, mnt_slave);
@@ -164,6 +169,19 @@
 	}
 }
 
+static struct mount *skip_propagation_subtree(struct mount *m,
+						struct mount *origin)
+{
+	/*
+	 * Advance m such that propagation_next will not return
+	 * the slaves of m.
+	 */
+	if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
+		m = last_slave(m);
+
+	return m;
+}
+
 static struct mount *next_group(struct mount *m, struct mount *origin)
 {
 	while (1) {
@@ -198,10 +216,15 @@
 
 /* all accesses are serialized by namespace_sem */
 static struct user_namespace *user_ns;
-static struct mount *last_dest, *last_source, *dest_master;
+static struct mount *last_dest, *first_source, *last_source, *dest_master;
 static struct mountpoint *mp;
 static struct hlist_head *list;
 
+static inline bool peers(struct mount *m1, struct mount *m2)
+{
+	return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id;
+}
+
 static int propagate_one(struct mount *m)
 {
 	struct mount *child;
@@ -212,24 +235,26 @@
 	/* skip if mountpoint isn't covered by it */
 	if (!is_subdir(mp->m_dentry, m->mnt.mnt_root))
 		return 0;
-	if (m->mnt_group_id == last_dest->mnt_group_id) {
+	if (peers(m, last_dest)) {
 		type = CL_MAKE_SHARED;
 	} else {
 		struct mount *n, *p;
+		bool done;
 		for (n = m; ; n = p) {
 			p = n->mnt_master;
-			if (p == dest_master || IS_MNT_MARKED(p)) {
-				while (last_dest->mnt_master != p) {
-					last_source = last_source->mnt_master;
-					last_dest = last_source->mnt_parent;
-				}
-				if (n->mnt_group_id != last_dest->mnt_group_id) {
-					last_source = last_source->mnt_master;
-					last_dest = last_source->mnt_parent;
-				}
+			if (p == dest_master || IS_MNT_MARKED(p))
 				break;
-			}
 		}
+		do {
+			struct mount *parent = last_source->mnt_parent;
+			if (last_source == first_source)
+				break;
+			done = parent->mnt_master == p;
+			if (done && peers(n, parent))
+				break;
+			last_source = last_source->mnt_master;
+		} while (!done);
+
 		type = CL_SLAVE;
 		/* beginning of peer group among the slaves? */
 		if (IS_MNT_SHARED(m))
@@ -243,16 +268,15 @@
 	if (IS_ERR(child))
 		return PTR_ERR(child);
 	child->mnt.mnt_flags &= ~MNT_LOCKED;
+	read_seqlock_excl(&mount_lock);
 	mnt_set_mountpoint(m, mp, child);
+	if (m->mnt_master != dest_master)
+		SET_MNT_MARK(m->mnt_master);
+	read_sequnlock_excl(&mount_lock);
 	last_dest = m;
 	last_source = child;
-	if (m->mnt_master != dest_master) {
-		read_seqlock_excl(&mount_lock);
-		SET_MNT_MARK(m->mnt_master);
-		read_sequnlock_excl(&mount_lock);
-	}
 	hlist_add_head(&child->mnt_hash, list);
-	return 0;
+	return count_mounts(m->mnt_ns, child);
 }
 
 /*
@@ -281,6 +305,7 @@
 	 */
 	user_ns = current->nsproxy->mnt_ns->user_ns;
 	last_dest = dest_mnt;
+	first_source = source_mnt;
 	last_source = source_mnt;
 	mp = dest_mp;
 	list = tree_list;
@@ -316,6 +341,21 @@
 	return ret;
 }
 
+static struct mount *find_topper(struct mount *mnt)
+{
+	/* If there is exactly one mount covering mnt completely return it. */
+	struct mount *child;
+
+	if (!list_is_singular(&mnt->mnt_mounts))
+		return NULL;
+
+	child = list_first_entry(&mnt->mnt_mounts, struct mount, mnt_child);
+	if (child->mnt_mountpoint != mnt->mnt.mnt_root)
+		return NULL;
+
+	return child;
+}
+
 /*
  * return true if the refcount is greater than count
  */
@@ -336,9 +376,8 @@
  */
 int propagate_mount_busy(struct mount *mnt, int refcnt)
 {
-	struct mount *m, *child;
+	struct mount *m, *child, *topper;
 	struct mount *parent = mnt->mnt_parent;
-	int ret = 0;
 
 	if (mnt == parent)
 		return do_refcount_check(mnt, refcnt);
@@ -353,12 +392,24 @@
 
 	for (m = propagation_next(parent, parent); m;
 	     		m = propagation_next(m, parent)) {
-		child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
-		if (child && list_empty(&child->mnt_mounts) &&
-		    (ret = do_refcount_check(child, 1)))
-			break;
+		int count = 1;
+		child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
+		if (!child)
+			continue;
+
+		/* Is there exactly one mount on the child that covers
+		 * it completely whose reference should be ignored?
+		 */
+		topper = find_topper(child);
+		if (topper)
+			count += 1;
+		else if (!list_empty(&child->mnt_mounts))
+			continue;
+
+		if (do_refcount_check(child, count))
+			return 1;
 	}
-	return ret;
+	return 0;
 }
 
 /*
@@ -375,60 +426,110 @@
 
 	for (m = propagation_next(parent, parent); m;
 			m = propagation_next(m, parent)) {
-		child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
+		child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
 		if (child)
 			child->mnt.mnt_flags &= ~MNT_LOCKED;
 	}
 }
 
-/*
- * Mark all mounts that the MNT_LOCKED logic will allow to be unmounted.
- */
-static void mark_umount_candidates(struct mount *mnt)
+static void umount_one(struct mount *mnt, struct list_head *to_umount)
 {
-	struct mount *parent = mnt->mnt_parent;
-	struct mount *m;
-
-	BUG_ON(parent == mnt);
-
-	for (m = propagation_next(parent, parent); m;
-			m = propagation_next(m, parent)) {
-		struct mount *child = __lookup_mnt_last(&m->mnt,
-						mnt->mnt_mountpoint);
-		if (child && (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m))) {
-			SET_MNT_MARK(child);
-		}
-	}
+	CLEAR_MNT_MARK(mnt);
+	mnt->mnt.mnt_flags |= MNT_UMOUNT;
+	list_del_init(&mnt->mnt_child);
+	list_del_init(&mnt->mnt_umounting);
+	list_move_tail(&mnt->mnt_list, to_umount);
 }
 
 /*
  * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
  * parent propagates to.
  */
-static void __propagate_umount(struct mount *mnt)
+static bool __propagate_umount(struct mount *mnt,
+			       struct list_head *to_umount,
+			       struct list_head *to_restore)
 {
-	struct mount *parent = mnt->mnt_parent;
-	struct mount *m;
-
-	BUG_ON(parent == mnt);
+	bool progress = false;
+	struct mount *child;
 
-	for (m = propagation_next(parent, parent); m;
-			m = propagation_next(m, parent)) {
+	/*
+	 * The state of the parent won't change if this mount is
+	 * already unmounted or marked as without children.
+	 */
+	if (mnt->mnt.mnt_flags & (MNT_UMOUNT | MNT_MARKED))
+		goto out;
 
-		struct mount *child = __lookup_mnt_last(&m->mnt,
-						mnt->mnt_mountpoint);
-		/*
-		 * umount the child only if the child has no children
-		 * and the child is marked safe to unmount.
-		 */
-		if (!child || !IS_MNT_MARKED(child))
+	/* Verify topper is the only grandchild that has not been
+	 * speculatively unmounted.
+	 */
+	list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
+		if (child->mnt_mountpoint == mnt->mnt.mnt_root)
+			continue;
+		if (!list_empty(&child->mnt_umounting) && IS_MNT_MARKED(child))
 			continue;
-		CLEAR_MNT_MARK(child);
-		if (list_empty(&child->mnt_mounts)) {
-			list_del_init(&child->mnt_child);
-			child->mnt.mnt_flags |= MNT_UMOUNT;
-			list_move_tail(&child->mnt_list, &mnt->mnt_list);
+		/* Found a mounted child */
+		goto children;
+	}
+
+	/* Mark mounts that can be unmounted if not locked */
+	SET_MNT_MARK(mnt);
+	progress = true;
+
+	/* If a mount is without children and not locked umount it. */
+	if (!IS_MNT_LOCKED(mnt)) {
+		umount_one(mnt, to_umount);
+	} else {
+children:
+		list_move_tail(&mnt->mnt_umounting, to_restore);
+	}
+out:
+	return progress;
+}
+
+static void umount_list(struct list_head *to_umount,
+			struct list_head *to_restore)
+{
+	struct mount *mnt, *child, *tmp;
+	list_for_each_entry(mnt, to_umount, mnt_list) {
+		list_for_each_entry_safe(child, tmp, &mnt->mnt_mounts, mnt_child) {
+			/* topper? */
+			if (child->mnt_mountpoint == mnt->mnt.mnt_root)
+				list_move_tail(&child->mnt_umounting, to_restore);
+			else
+				umount_one(child, to_umount);
+		}
+	}
+}
+
+static void restore_mounts(struct list_head *to_restore)
+{
+	/* Restore mounts to a clean working state */
+	while (!list_empty(to_restore)) {
+		struct mount *mnt, *parent;
+		struct mountpoint *mp;
+
+		mnt = list_first_entry(to_restore, struct mount, mnt_umounting);
+		CLEAR_MNT_MARK(mnt);
+		list_del_init(&mnt->mnt_umounting);
+
+		/* Should this mount be reparented? */
+		mp = mnt->mnt_mp;
+		parent = mnt->mnt_parent;
+		while (parent->mnt.mnt_flags & MNT_UMOUNT) {
+			mp = parent->mnt_mp;
+			parent = parent->mnt_parent;
 		}
+		if (parent != mnt->mnt_parent)
+			mnt_change_mountpoint(parent, mp, mnt);
+	}
+}
+
+static void cleanup_umount_visitations(struct list_head *visited)
+{
+	while (!list_empty(visited)) {
+		struct mount *mnt =
+			list_first_entry(visited, struct mount, mnt_umounting);
+		list_del_init(&mnt->mnt_umounting);
 	}
 }
 
@@ -442,11 +543,68 @@
 int propagate_umount(struct list_head *list)
 {
 	struct mount *mnt;
+	LIST_HEAD(to_restore);
+	LIST_HEAD(to_umount);
+	LIST_HEAD(visited);
+
+	/* Find candidates for unmounting */
+	list_for_each_entry_reverse(mnt, list, mnt_list) {
+		struct mount *parent = mnt->mnt_parent;
+		struct mount *m;
+
+		/*
+		 * If this mount has already been visited it is known that it's
+		 * entire peer group and all of their slaves in the propagation
+		 * tree for the mountpoint has already been visited and there is
+		 * no need to visit them again.
+		 */
+		if (!list_empty(&mnt->mnt_umounting))
+			continue;
+
+		list_add_tail(&mnt->mnt_umounting, &visited);
+		for (m = propagation_next(parent, parent); m;
+		     m = propagation_next(m, parent)) {
+			struct mount *child = __lookup_mnt(&m->mnt,
+							   mnt->mnt_mountpoint);
+			if (!child)
+				continue;
+
+			if (!list_empty(&child->mnt_umounting)) {
+				/*
+				 * If the child has already been visited it is
+				 * know that it's entire peer group and all of
+				 * their slaves in the propgation tree for the
+				 * mountpoint has already been visited and there
+				 * is no need to visit this subtree again.
+				 */
+				m = skip_propagation_subtree(m, parent);
+				continue;
+			} else if (child->mnt.mnt_flags & MNT_UMOUNT) {
+				/*
+				 * We have come accross an partially unmounted
+				 * mount in list that has not been visited yet.
+				 * Remember it has been visited and continue
+				 * about our merry way.
+				 */
+				list_add_tail(&child->mnt_umounting, &visited);
+				continue;
+			}
+
+			/* Check the child and parents while progress is made */
+			while (__propagate_umount(child,
+						  &to_umount, &to_restore)) {
+				/* Is the parent a umount candidate? */
+				child = child->mnt_parent;
+				if (list_empty(&child->mnt_umounting))
+					break;
+			}
+		}
+	}
 
-	list_for_each_entry_reverse(mnt, list, mnt_list)
-		mark_umount_candidates(mnt);
+	umount_list(&to_umount, &to_restore);
+	restore_mounts(&to_restore);
+	cleanup_umount_visitations(&visited);
+	list_splice_tail(&to_umount, list);
 
-	list_for_each_entry(mnt, list, mnt_list)
-		__propagate_umount(mnt);
 	return 0;
 }
--- linux-4.4.0.orig/fs/pnode.h
+++ linux-4.4.0/fs/pnode.h
@@ -49,7 +49,10 @@
 unsigned int mnt_get_count(struct mount *mnt);
 void mnt_set_mountpoint(struct mount *, struct mountpoint *,
 			struct mount *);
+void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp,
+			   struct mount *mnt);
 struct mount *copy_tree(struct mount *, struct dentry *, int);
 bool is_path_reachable(struct mount *, struct dentry *,
 			 const struct path *root);
+int count_mounts(struct mnt_namespace *ns, struct mount *mnt);
 #endif /* _LINUX_PNODE_H */
--- linux-4.4.0.orig/fs/posix_acl.c
+++ linux-4.4.0/fs/posix_acl.c
@@ -171,7 +171,7 @@
  * Check if an acl is valid. Returns 0 if it is, or -E... otherwise.
  */
 int
-posix_acl_valid(const struct posix_acl *acl)
+posix_acl_valid(struct user_namespace *user_ns, const struct posix_acl *acl)
 {
 	const struct posix_acl_entry *pa, *pe;
 	int state = ACL_USER_OBJ;
@@ -191,7 +191,7 @@
 			case ACL_USER:
 				if (state != ACL_USER)
 					return -EINVAL;
-				if (!uid_valid(pa->e_uid))
+				if (!kuid_has_mapping(user_ns, pa->e_uid))
 					return -EINVAL;
 				needs_mask = 1;
 				break;
@@ -206,7 +206,7 @@
 			case ACL_GROUP:
 				if (state != ACL_GROUP)
 					return -EINVAL;
-				if (!gid_valid(pa->e_gid))
+				if (!kgid_has_mapping(user_ns, pa->e_gid))
 					return -EINVAL;
 				needs_mask = 1;
 				break;
@@ -592,61 +592,102 @@
 }
 EXPORT_SYMBOL_GPL(posix_acl_create);
 
+/**
+ * posix_acl_update_mode  -  update mode in set_acl
+ *
+ * Update the file mode when setting an ACL: compute the new file permission
+ * bits based on the ACL.  In addition, if the ACL is equivalent to the new
+ * file mode, set *acl to NULL to indicate that no ACL should be set.
+ *
+ * As with chmod, clear the setgit bit if the caller is not in the owning group
+ * or capable of CAP_FSETID (see inode_change_ok).
+ *
+ * Called from set_acl inode operations.
+ */
+int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
+			  struct posix_acl **acl)
+{
+	umode_t mode = inode->i_mode;
+	int error;
+
+	error = posix_acl_equiv_mode(*acl, &mode);
+	if (error < 0)
+		return error;
+	if (error == 0)
+		*acl = NULL;
+	if (!in_group_p(inode->i_gid) &&
+	    !capable_wrt_inode_uidgid(inode, CAP_FSETID))
+		mode &= ~S_ISGID;
+	*mode_p = mode;
+	return 0;
+}
+EXPORT_SYMBOL(posix_acl_update_mode);
+
 /*
  * Fix up the uids and gids in posix acl extended attributes in place.
  */
-static void posix_acl_fix_xattr_userns(
+int posix_acl_fix_xattr_userns(
 	struct user_namespace *to, struct user_namespace *from,
 	void *value, size_t size)
 {
 	posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
 	posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
 	int count;
-	kuid_t uid;
-	kgid_t gid;
+	kuid_t kuid;
+	kgid_t kgid;
+	uid_t uid;
+	gid_t gid;
+	int ret = 0;
 
+	if (to == from)
+		return 0;
 	if (!value)
-		return;
+		return 0;
 	if (size < sizeof(posix_acl_xattr_header))
-		return;
+		return -EINVAL;
 	if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
-		return;
+		return -EINVAL;
 
 	count = posix_acl_xattr_count(size);
 	if (count < 0)
-		return;
+		return -EINVAL;
 	if (count == 0)
-		return;
+		return 0;
 
 	for (end = entry + count; entry != end; entry++) {
 		switch(le16_to_cpu(entry->e_tag)) {
 		case ACL_USER:
-			uid = make_kuid(from, le32_to_cpu(entry->e_id));
-			entry->e_id = cpu_to_le32(from_kuid(to, uid));
+			kuid = make_kuid(from, le32_to_cpu(entry->e_id));
+			uid = from_kuid(to, kuid);
+			entry->e_id = cpu_to_le32(uid);
+			if (uid == (uid_t)-1)
+				ret = -EOVERFLOW;
 			break;
 		case ACL_GROUP:
-			gid = make_kgid(from, le32_to_cpu(entry->e_id));
-			entry->e_id = cpu_to_le32(from_kgid(to, gid));
+			kgid = make_kgid(from, le32_to_cpu(entry->e_id));
+			gid = from_kgid(to, kgid);
+			entry->e_id = cpu_to_le32(gid);
+			if (gid == (gid_t)-1)
+				ret = -EOVERFLOW;
 			break;
 		default:
 			break;
 		}
 	}
+
+	return ret;
 }
+EXPORT_SYMBOL(posix_acl_fix_xattr_userns);
 
 void posix_acl_fix_xattr_from_user(void *value, size_t size)
 {
 	struct user_namespace *user_ns = current_user_ns();
-	if (user_ns == &init_user_ns)
-		return;
 	posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
 }
 
 void posix_acl_fix_xattr_to_user(void *value, size_t size)
 {
 	struct user_namespace *user_ns = current_user_ns();
-	if (user_ns == &init_user_ns)
-		return;
 	posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
 }
 
@@ -788,6 +829,28 @@
 	return error;
 }
 
+int
+set_posix_acl(struct inode *inode, int type, struct posix_acl *acl)
+{
+	if (!IS_POSIXACL(inode))
+		return -EOPNOTSUPP;
+	if (!inode->i_op->set_acl)
+		return -EOPNOTSUPP;
+
+	if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
+		return acl ? -EACCES : 0;
+	if (!inode_owner_or_capable(inode))
+		return -EPERM;
+
+	if (acl) {
+		int ret = posix_acl_valid(inode->i_sb->s_user_ns, acl);
+		if (ret)
+			return ret;
+	}
+	return inode->i_op->set_acl(inode, acl, type);
+}
+EXPORT_SYMBOL(set_posix_acl);
+
 static int
 posix_acl_xattr_set(const struct xattr_handler *handler,
 		    struct dentry *dentry, const char *name,
@@ -799,30 +862,13 @@
 
 	if (strcmp(name, "") != 0)
 		return -EINVAL;
-	if (!IS_POSIXACL(inode))
-		return -EOPNOTSUPP;
-	if (!inode->i_op->set_acl)
-		return -EOPNOTSUPP;
-
-	if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
-		return value ? -EACCES : 0;
-	if (!inode_owner_or_capable(inode))
-		return -EPERM;
 
 	if (value) {
 		acl = posix_acl_from_xattr(&init_user_ns, value, size);
 		if (IS_ERR(acl))
 			return PTR_ERR(acl);
-
-		if (acl) {
-			ret = posix_acl_valid(acl);
-			if (ret)
-				goto out;
-		}
 	}
-
-	ret = inode->i_op->set_acl(inode, acl, handler->flags);
-out:
+	ret = set_posix_acl(inode, handler->flags, acl);
 	posix_acl_release(acl);
 	return ret;
 }
@@ -867,11 +913,10 @@
 	int error;
 
 	if (type == ACL_TYPE_ACCESS) {
-		error = posix_acl_equiv_mode(acl, &inode->i_mode);
-		if (error < 0)
-			return 0;
-		if (error == 0)
-			acl = NULL;
+		error = posix_acl_update_mode(inode,
+				&inode->i_mode, &acl);
+		if (error)
+			return error;
 	}
 
 	inode->i_ctime = CURRENT_TIME;
--- linux-4.4.0.orig/fs/proc/Makefile
+++ linux-4.4.0/fs/proc/Makefile
@@ -30,3 +30,4 @@
 proc-$(CONFIG_PROC_VMCORE)	+= vmcore.o
 proc-$(CONFIG_PRINTK)	+= kmsg.o
 proc-$(CONFIG_PROC_PAGE_MONITOR)	+= page.o
+proc-y	+= version_signature.o
--- linux-4.4.0.orig/fs/proc/array.c
+++ linux-4.4.0/fs/proc/array.c
@@ -79,6 +79,8 @@
 #include <linux/delayacct.h>
 #include <linux/seq_file.h>
 #include <linux/pid_namespace.h>
+#include <linux/nospec.h>
+#include <linux/prctl.h>
 #include <linux/ptrace.h>
 #include <linux/tracehook.h>
 #include <linux/string_helpers.h>
@@ -332,6 +334,31 @@
 #ifdef CONFIG_SECCOMP
 	seq_printf(m, "Seccomp:\t%d\n", p->seccomp.mode);
 #endif
+	seq_printf(m, "Speculation_Store_Bypass:\t");
+	switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) {
+	case -EINVAL:
+		seq_printf(m, "unknown");
+		break;
+	case PR_SPEC_NOT_AFFECTED:
+		seq_printf(m, "not vulnerable");
+		break;
+	case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE:
+		seq_printf(m, "thread force mitigated");
+		break;
+	case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
+		seq_printf(m, "thread mitigated");
+		break;
+	case PR_SPEC_PRCTL | PR_SPEC_ENABLE:
+		seq_printf(m, "thread vulnerable");
+		break;
+	case PR_SPEC_DISABLE:
+		seq_printf(m, "globally mitigated");
+		break;
+	default:
+		seq_printf(m, "vulnerable");
+		break;
+	}
+	seq_putc(m, '\n');
 }
 
 static inline void task_context_switch_counts(struct seq_file *m,
@@ -395,13 +422,25 @@
 
 	state = *get_task_state(task);
 	vsize = eip = esp = 0;
-	permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT);
+	permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT);
 	mm = get_task_mm(task);
 	if (mm) {
 		vsize = task_vsize(mm);
-		if (permitted) {
-			eip = KSTK_EIP(task);
-			esp = KSTK_ESP(task);
+		/*
+		 * esp and eip are intentionally zeroed out.  There is no
+		 * non-racy way to read them without freezing the task.
+		 * Programs that need reliable values can use ptrace(2).
+		 *
+		 * The only exception is if the task is core dumping because
+		 * a program is not able to use ptrace(2) in that case. It is
+		 * safe because the task has stopped executing permanently.
+		 */
+		if (permitted && (task->flags & (PF_EXITING|PF_DUMPCORE))) {
+			if (try_get_task_stack(task)) {
+				eip = KSTK_EIP(task);
+				esp = KSTK_ESP(task);
+				put_task_stack(task);
+			}
 		}
 	}
 
--- linux-4.4.0.orig/fs/proc/base.c
+++ linux-4.4.0/fs/proc/base.c
@@ -94,6 +94,8 @@
 #include "internal.h"
 #include "fd.h"
 
+#include "../../lib/kstrtox.h"
+
 /* NOTE:
  *	Implementing inode permission operations in /proc is almost
  *	certainly an error.  Permission checks need to happen during
@@ -252,7 +254,7 @@
 	 * Inherently racy -- command line shares address space
 	 * with code and data.
 	 */
-	rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0);
+	rv = access_remote_vm(mm, arg_end - 1, &c, 1, FOLL_ANON);
 	if (rv <= 0)
 		goto out_free_page;
 
@@ -270,7 +272,7 @@
 			int nr_read;
 
 			_count = min3(count, len, PAGE_SIZE);
-			nr_read = access_remote_vm(mm, p, page, _count, 0);
+			nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
 			if (nr_read < 0)
 				rv = nr_read;
 			if (nr_read <= 0)
@@ -305,7 +307,7 @@
 			bool final;
 
 			_count = min3(count, len, PAGE_SIZE);
-			nr_read = access_remote_vm(mm, p, page, _count, 0);
+			nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
 			if (nr_read < 0)
 				rv = nr_read;
 			if (nr_read <= 0)
@@ -354,7 +356,7 @@
 			bool final;
 
 			_count = min3(count, len, PAGE_SIZE);
-			nr_read = access_remote_vm(mm, p, page, _count, 0);
+			nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
 			if (nr_read < 0)
 				rv = nr_read;
 			if (nr_read <= 0)
@@ -403,7 +405,7 @@
 static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns,
 			 struct pid *pid, struct task_struct *task)
 {
-	struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ);
+	struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
 	if (mm && !IS_ERR(mm)) {
 		unsigned int nwords = 0;
 		do {
@@ -430,7 +432,8 @@
 
 	wchan = get_wchan(task);
 
-	if (wchan && ptrace_may_access(task, PTRACE_MODE_READ) && !lookup_symbol_name(wchan, symname))
+	if (wchan && ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)
+			&& !lookup_symbol_name(wchan, symname))
 		seq_printf(m, "%s", symname);
 	else
 		seq_putc(m, '0');
@@ -444,7 +447,7 @@
 	int err = mutex_lock_killable(&task->signal->cred_guard_mutex);
 	if (err)
 		return err;
-	if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
+	if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) {
 		mutex_unlock(&task->signal->cred_guard_mutex);
 		return -EPERM;
 	}
@@ -468,6 +471,20 @@
 	int err;
 	int i;
 
+	/*
+	 * The ability to racily run the kernel stack unwinder on a running task
+	 * and then observe the unwinder output is scary; while it is useful for
+	 * debugging kernel issues, it can also allow an attacker to leak kernel
+	 * stack contents.
+	 * Doing this in a manner that is at least safe from races would require
+	 * some work to ensure that the remote task can not be scheduled; and
+	 * even then, this would still expose the unwinder as local attack
+	 * surface.
+	 * Therefore, this interface is restricted to root.
+	 */
+	if (!file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN))
+		return -EACCES;
+
 	entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL);
 	if (!entries)
 		return -ENOMEM;
@@ -697,7 +714,7 @@
 	 */
 	task = get_proc_task(inode);
 	if (task) {
-		allowed = ptrace_may_access(task, PTRACE_MODE_READ);
+		allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
 		put_task_struct(task);
 	}
 	return allowed;
@@ -707,11 +724,18 @@
 {
 	int error;
 	struct inode *inode = d_inode(dentry);
+	struct user_namespace *s_user_ns;
 
 	if (attr->ia_valid & ATTR_MODE)
 		return -EPERM;
 
-	error = inode_change_ok(inode, attr);
+	/* Don't let anyone mess with weird proc files */
+	s_user_ns = inode->i_sb->s_user_ns;
+	if (!kuid_has_mapping(s_user_ns, inode->i_uid) ||
+	    !kgid_has_mapping(s_user_ns, inode->i_gid))
+		return -EPERM;
+
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
@@ -732,7 +756,7 @@
 		return true;
 	if (in_group_p(pid->pid_gid))
 		return true;
-	return ptrace_may_access(task, PTRACE_MODE_READ);
+	return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
 }
 
 
@@ -809,7 +833,7 @@
 	struct mm_struct *mm = ERR_PTR(-ESRCH);
 
 	if (task) {
-		mm = mm_access(task, mode);
+		mm = mm_access(task, mode | PTRACE_MODE_FSCREDS);
 		put_task_struct(task);
 
 		if (!IS_ERR_OR_NULL(mm)) {
@@ -851,6 +875,7 @@
 	unsigned long addr = *ppos;
 	ssize_t copied;
 	char *page;
+	unsigned int flags;
 
 	if (!mm)
 		return 0;
@@ -863,6 +888,11 @@
 	if (!atomic_inc_not_zero(&mm->mm_users))
 		goto free;
 
+	/* Maybe we should limit FOLL_FORCE to actual ptrace users? */
+	flags = FOLL_FORCE;
+	if (write)
+		flags |= FOLL_WRITE;
+
 	while (count > 0) {
 		int this_len = min_t(int, count, PAGE_SIZE);
 
@@ -871,7 +901,7 @@
 			break;
 		}
 
-		this_len = access_remote_vm(mm, addr, page, this_len, write);
+		this_len = access_remote_vm(mm, addr, page, this_len, flags);
 		if (!this_len) {
 			if (!copied)
 				copied = -EIO;
@@ -952,8 +982,10 @@
 	unsigned long src = *ppos;
 	int ret = 0;
 	struct mm_struct *mm = file->private_data;
+	unsigned long env_start, env_end;
 
-	if (!mm)
+	/* Ensure the process spawned far enough to have an environment. */
+	if (!mm || !mm->env_end)
 		return 0;
 
 	page = (char *)__get_free_page(GFP_TEMPORARY);
@@ -963,20 +995,25 @@
 	ret = 0;
 	if (!atomic_inc_not_zero(&mm->mm_users))
 		goto free;
+
+	down_read(&mm->mmap_sem);
+	env_start = mm->env_start;
+	env_end = mm->env_end;
+	up_read(&mm->mmap_sem);
+
 	while (count > 0) {
 		size_t this_len, max_len;
 		int retval;
 
-		if (src >= (mm->env_end - mm->env_start))
+		if (src >= (env_end - env_start))
 			break;
 
-		this_len = mm->env_end - (mm->env_start + src);
+		this_len = env_end - (env_start + src);
 
 		max_len = min_t(size_t, PAGE_SIZE, count);
 		this_len = min(max_len, this_len);
 
-		retval = access_remote_vm(mm, (mm->env_start + src),
-			page, this_len, 0);
+		retval = access_remote_vm(mm, (env_start + src), page, this_len, FOLL_ANON);
 
 		if (retval <= 0) {
 			ret = retval;
@@ -1543,18 +1580,13 @@
 static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
 {
 	struct task_struct *task;
-	struct mm_struct *mm;
 	struct file *exe_file;
 
 	task = get_proc_task(d_inode(dentry));
 	if (!task)
 		return -ENOENT;
-	mm = get_task_mm(task);
+	exe_file = get_task_exe_file(task);
 	put_task_struct(task);
-	if (!mm)
-		return -ENOENT;
-	exe_file = get_mm_exe_file(mm);
-	mmput(mm);
 	if (exe_file) {
 		*exe_path = exe_file->f_path;
 		path_get(&exe_file->f_path);
@@ -1832,8 +1864,33 @@
 static int dname_to_vma_addr(struct dentry *dentry,
 			     unsigned long *start, unsigned long *end)
 {
-	if (sscanf(dentry->d_name.name, "%lx-%lx", start, end) != 2)
+	const char *str = dentry->d_name.name;
+	unsigned long long sval, eval;
+	unsigned int len;
+
+	len = _parse_integer(str, 16, &sval);
+	if (len & KSTRTOX_OVERFLOW)
+		return -EINVAL;
+	if (sval != (unsigned long)sval)
+		return -EINVAL;
+	str += len;
+
+	if (*str != '-')
+		return -EINVAL;
+	str++;
+
+	len = _parse_integer(str, 16, &eval);
+	if (len & KSTRTOX_OVERFLOW)
 		return -EINVAL;
+	if (eval != (unsigned long)eval)
+		return -EINVAL;
+	str += len;
+
+	if (*str != '\0')
+		return -EINVAL;
+
+	*start = sval;
+	*end = eval;
 
 	return 0;
 }
@@ -1856,7 +1913,7 @@
 	if (!task)
 		goto out_notask;
 
-	mm = mm_access(task, PTRACE_MODE_READ);
+	mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
 	if (IS_ERR_OR_NULL(mm))
 		goto out;
 
@@ -1921,7 +1978,7 @@
 	down_read(&mm->mmap_sem);
 	vma = find_exact_vma(mm, vm_start, vm_end);
 	if (vma && vma->vm_file) {
-		*path = vma->vm_file->f_path;
+		*path = vma_pr_or_file(vma)->f_path;
 		path_get(path);
 		rc = 0;
 	}
@@ -2007,7 +2064,7 @@
 		goto out;
 
 	result = -EACCES;
-	if (!ptrace_may_access(task, PTRACE_MODE_READ))
+	if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
 		goto out_put_task;
 
 	result = -ENOENT;
@@ -2060,7 +2117,7 @@
 		goto out;
 
 	ret = -EACCES;
-	if (!ptrace_may_access(task, PTRACE_MODE_READ))
+	if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
 		goto out_put_task;
 
 	ret = 0;
@@ -2530,7 +2587,7 @@
 	if (result)
 		return result;
 
-	if (!ptrace_may_access(task, PTRACE_MODE_READ)) {
+	if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
 		result = -EACCES;
 		goto out_unlock;
 	}
@@ -3061,6 +3118,8 @@
 	     iter.tgid += 1, iter = next_tgid(ns, iter)) {
 		char name[PROC_NUMBUF];
 		int len;
+
+		cond_resched();
 		if (!has_pid_permissions(ns, iter.task, 2))
 			continue;
 
@@ -3077,6 +3136,44 @@
 }
 
 /*
+ * proc_tid_comm_permission is a special permission function exclusively
+ * used for the node /proc/<pid>/task/<tid>/comm.
+ * It bypasses generic permission checks in the case where a task of the same
+ * task group attempts to access the node.
+ * The rationale behind this is that glibc and bionic access this node for
+ * cross thread naming (pthread_set/getname_np(!self)). However, if
+ * PR_SET_DUMPABLE gets set to 0 this node among others becomes uid=0 gid=0,
+ * which locks out the cross thread naming implementation.
+ * This function makes sure that the node is always accessible for members of
+ * same thread group.
+ */
+static int proc_tid_comm_permission(struct inode *inode, int mask)
+{
+	bool is_same_tgroup;
+	struct task_struct *task;
+
+	task = get_proc_task(inode);
+	if (!task)
+		return -ESRCH;
+	is_same_tgroup = same_thread_group(current, task);
+	put_task_struct(task);
+
+	if (likely(is_same_tgroup && !(mask & MAY_EXEC))) {
+		/* This file (/proc/<pid>/task/<tid>/comm) can always be
+		 * read or written by the members of the corresponding
+		 * thread group.
+		 */
+		return 0;
+	}
+
+	return generic_permission(inode, mask);
+}
+
+static const struct inode_operations proc_tid_comm_inode_operations = {
+		.permission = proc_tid_comm_permission,
+};
+
+/*
  * Tasks
  */
 static const struct pid_entry tid_base_stuff[] = {
@@ -3094,7 +3191,9 @@
 #ifdef CONFIG_SCHED_DEBUG
 	REG("sched",     S_IRUGO|S_IWUSR, proc_pid_sched_operations),
 #endif
-	REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
+	NOD("comm",      S_IFREG|S_IRUGO|S_IWUSR,
+			 &proc_tid_comm_inode_operations,
+			 &proc_pid_set_comm_operations, {}),
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
 	ONE("syscall",   S_IRUSR, proc_pid_syscall),
 #endif
--- linux-4.4.0.orig/fs/proc/generic.c
+++ linux-4.4.0/fs/proc/generic.c
@@ -103,9 +103,16 @@
 {
 	struct inode *inode = d_inode(dentry);
 	struct proc_dir_entry *de = PDE(inode);
+	struct user_namespace *s_user_ns;
 	int error;
 
-	error = inode_change_ok(inode, iattr);
+	/* Don't let anyone mess with weird proc files */
+	s_user_ns = inode->i_sb->s_user_ns;
+	if (!kuid_has_mapping(s_user_ns, inode->i_uid) ||
+	    !kgid_has_mapping(s_user_ns, inode->i_gid))
+		return -EPERM;
+
+	error = setattr_prepare(dentry, iattr);
 	if (error)
 		return error;
 
@@ -469,6 +476,7 @@
 		ent->data = NULL;
 		ent->proc_fops = NULL;
 		ent->proc_iops = NULL;
+		parent->nlink++;
 		if (proc_register(parent, ent) < 0) {
 			kfree(ent);
 			parent->nlink--;
@@ -477,6 +485,7 @@
 	}
 	return ent;
 }
+EXPORT_SYMBOL(proc_create_mount_point);
 
 struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
 					struct proc_dir_entry *parent,
--- linux-4.4.0.orig/fs/proc/inode.c
+++ linux-4.4.0/fs/proc/inode.c
@@ -415,7 +415,7 @@
 
 struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
 {
-	struct inode *inode = new_inode_pseudo(sb);
+	struct inode *inode = new_inode(sb);
 
 	if (inode) {
 		inode->i_ino = de->low_ino;
--- linux-4.4.0.orig/fs/proc/internal.h
+++ linux-4.4.0/fs/proc/internal.h
@@ -195,7 +195,6 @@
 {
 	return S_ISDIR(pde->mode) && !pde->proc_iops;
 }
-struct proc_dir_entry *proc_create_mount_point(const char *name);
 
 /*
  * inode.c
--- linux-4.4.0.orig/fs/proc/meminfo.c
+++ linux-4.4.0/fs/proc/meminfo.c
@@ -29,10 +29,7 @@
 	unsigned long committed;
 	long cached;
 	long available;
-	unsigned long pagecache;
-	unsigned long wmark_low = 0;
 	unsigned long pages[NR_LRU_LISTS];
-	struct zone *zone;
 	int lru;
 
 /*
@@ -51,36 +48,7 @@
 	for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
 		pages[lru] = global_page_state(NR_LRU_BASE + lru);
 
-	for_each_zone(zone)
-		wmark_low += zone->watermark[WMARK_LOW];
-
-	/*
-	 * Estimate the amount of memory available for userspace allocations,
-	 * without causing swapping.
-	 *
-	 * Free memory cannot be taken below the low watermark, before the
-	 * system starts swapping.
-	 */
-	available = i.freeram - wmark_low;
-
-	/*
-	 * Not all the page cache can be freed, otherwise the system will
-	 * start swapping. Assume at least half of the page cache, or the
-	 * low watermark worth of cache, needs to stay.
-	 */
-	pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE];
-	pagecache -= min(pagecache / 2, wmark_low);
-	available += pagecache;
-
-	/*
-	 * Part of the reclaimable slab consists of items that are in use,
-	 * and cannot be freed. Cap this estimate at the low watermark.
-	 */
-	available += global_page_state(NR_SLAB_RECLAIMABLE) -
-		     min(global_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low);
-
-	if (available < 0)
-		available = 0;
+	available = si_mem_available();
 
 	/*
 	 * Tagged format, for easy grepping and expansion.
--- linux-4.4.0.orig/fs/proc/namespaces.c
+++ linux-4.4.0/fs/proc/namespaces.c
@@ -28,6 +28,9 @@
 	&userns_operations,
 #endif
 	&mntns_operations,
+#ifdef CONFIG_CGROUPS
+	&cgroupns_operations,
+#endif
 };
 
 static const char *proc_ns_follow_link(struct dentry *dentry, void **cookie)
@@ -42,7 +45,7 @@
 	if (!task)
 		return error;
 
-	if (ptrace_may_access(task, PTRACE_MODE_READ)) {
+	if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
 		error = ns_get_path(&ns_path, task, ns_ops);
 		if (!error)
 			nd_jump_link(&ns_path);
@@ -63,7 +66,7 @@
 	if (!task)
 		return res;
 
-	if (ptrace_may_access(task, PTRACE_MODE_READ)) {
+	if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
 		res = ns_get_name(name, sizeof(name), task, ns_ops);
 		if (res >= 0)
 			res = readlink_copy(buffer, buflen, name);
--- linux-4.4.0.orig/fs/proc/nommu.c
+++ linux-4.4.0/fs/proc/nommu.c
@@ -45,7 +45,10 @@
 	file = region->vm_file;
 
 	if (file) {
-		struct inode *inode = file_inode(region->vm_file);
+		struct inode *inode;
+
+		file = vmr_pr_or_file(region);
+		inode = file_inode(file);
 		dev = inode->i_sb->s_dev;
 		ino = inode->i_ino;
 	}
--- linux-4.4.0.orig/fs/proc/proc_sysctl.c
+++ linux-4.4.0/fs/proc/proc_sysctl.c
@@ -654,7 +654,10 @@
 				    struct ctl_table *table)
 {
 	bool ret = true;
+
 	head = sysctl_head_grab(head);
+	if (IS_ERR(head))
+		return false;
 
 	if (S_ISLNK(table->mode)) {
 		/* It is not an error if we can not follow the link ignore it */
@@ -703,7 +706,7 @@
 	ctl_dir = container_of(head, struct ctl_dir, header);
 
 	if (!dir_emit_dots(file, ctx))
-		return 0;
+		goto out;
 
 	pos = 2;
 
@@ -713,6 +716,7 @@
 			break;
 		}
 	}
+out:
 	sysctl_head_finish(head);
 	return 0;
 }
@@ -748,12 +752,19 @@
 static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = d_inode(dentry);
+	struct user_namespace *s_user_ns;
 	int error;
 
 	if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
 		return -EPERM;
 
-	error = inode_change_ok(inode, attr);
+	/* Don't let anyone mess with weird proc files */
+	s_user_ns = inode->i_sb->s_user_ns;
+	if (!kuid_has_mapping(s_user_ns, inode->i_uid) ||
+	    !kgid_has_mapping(s_user_ns, inode->i_gid))
+		return -EPERM;
+
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
@@ -1546,8 +1557,11 @@
 	if (--header->nreg)
 		return;
 
-	put_links(header);
-	start_unregistering(header);
+	if (parent) {
+		put_links(header);
+		start_unregistering(header);
+	}
+
 	if (!--header->count)
 		kfree_rcu(header, rcu);
 
--- linux-4.4.0.orig/fs/proc/proc_tty.c
+++ linux-4.4.0/fs/proc/proc_tty.c
@@ -14,6 +14,7 @@
 #include <linux/tty.h>
 #include <linux/seq_file.h>
 #include <linux/bitops.h>
+#include "internal.h"
 
 /*
  * The /proc/tty directory inodes...
@@ -164,7 +165,7 @@
 	if (!ent)
 		return;
 		
-	remove_proc_entry(driver->driver_name, proc_tty_driver);
+	remove_proc_entry(ent->name, proc_tty_driver);
 	
 	driver->proc_entry = NULL;
 }
--- linux-4.4.0.orig/fs/proc/root.c
+++ linux-4.4.0/fs/proc/root.c
@@ -117,10 +117,18 @@
 			return ERR_PTR(-EPERM);
 	}
 
-	sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns);
+	sb = sget_userns(fs_type, proc_test_super, proc_set_super, flags,
+			 ns->user_ns, ns);
 	if (IS_ERR(sb))
 		return ERR_CAST(sb);
 
+	/*
+	 * procfs isn't actually a stacking filesystem; however, there is
+	 * too much magic going on inside it to permit stacking things on
+	 * top of it
+	 */
+	sb->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
+
 	if (!proc_parse_options(options, ns)) {
 		deactivate_locked_super(sb);
 		return ERR_PTR(-EINVAL);
--- linux-4.4.0.orig/fs/proc/self.c
+++ linux-4.4.0/fs/proc/self.c
@@ -24,6 +24,13 @@
 	pid_t tgid = task_tgid_nr_ns(current, ns);
 	char *name;
 
+	/*
+	 * Not currently supported. Once we can inherit all of struct pid,
+	 * we can allow this.
+	 */
+	if (current->flags & PF_KTHREAD)
+		return ERR_PTR(-EOPNOTSUPP);
+
 	if (!tgid)
 		return ERR_PTR(-ENOENT);
 	/* 11 for max length of signed int in decimal + NULL term */
@@ -51,7 +58,7 @@
 	mutex_lock(&root_inode->i_mutex);
 	self = d_alloc_name(s->s_root, "self");
 	if (self) {
-		struct inode *inode = new_inode_pseudo(s);
+		struct inode *inode = new_inode(s);
 		if (inode) {
 			inode->i_ino = self_inum;
 			inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
--- linux-4.4.0.orig/fs/proc/task_mmu.c
+++ linux-4.4.0/fs/proc/task_mmu.c
@@ -248,23 +248,20 @@
 				sizeof(struct proc_maps_private));
 }
 
-static pid_t pid_of_stack(struct proc_maps_private *priv,
-				struct vm_area_struct *vma, bool is_pid)
+/*
+ * Indicate if the VMA is a stack for the given task; for
+ * /proc/PID/maps that is the stack of the main task.
+ */
+static int is_stack(struct proc_maps_private *priv,
+		    struct vm_area_struct *vma)
 {
-	struct inode *inode = priv->inode;
-	struct task_struct *task;
-	pid_t ret = 0;
-
-	rcu_read_lock();
-	task = pid_task(proc_pid(inode), PIDTYPE_PID);
-	if (task) {
-		task = task_of_stack(task, vma, is_pid);
-		if (task)
-			ret = task_pid_nr_ns(task, inode->i_sb->s_fs_info);
-	}
-	rcu_read_unlock();
-
-	return ret;
+	/*
+	 * We make no effort to guess what a given thread considers to be
+	 * its "stack".  It's not even well-defined for programs written
+	 * languages like Go.
+	 */
+	return vma->vm_start <= vma->vm_mm->start_stack &&
+		vma->vm_end >= vma->vm_mm->start_stack;
 }
 
 static void
@@ -281,7 +278,10 @@
 	const char *name = NULL;
 
 	if (file) {
-		struct inode *inode = file_inode(vma->vm_file);
+		struct inode *inode;
+
+		file = vma_pr_or_file(vma);
+		inode = file_inode(file);
 		dev = inode->i_sb->s_dev;
 		ino = inode->i_ino;
 		pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT;
@@ -289,11 +289,7 @@
 
 	/* We don't show the stack guard page in /proc/maps */
 	start = vma->vm_start;
-	if (stack_guard_page_start(vma, start))
-		start += PAGE_SIZE;
 	end = vma->vm_end;
-	if (stack_guard_page_end(vma, end))
-		end -= PAGE_SIZE;
 
 	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
 	seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
@@ -324,8 +320,6 @@
 
 	name = arch_vma_name(vma);
 	if (!name) {
-		pid_t tid;
-
 		if (!mm) {
 			name = "[vdso]";
 			goto done;
@@ -337,21 +331,8 @@
 			goto done;
 		}
 
-		tid = pid_of_stack(priv, vma, is_pid);
-		if (tid != 0) {
-			/*
-			 * Thread stack in /proc/PID/task/TID/maps or
-			 * the main process stack.
-			 */
-			if (!is_pid || (vma->vm_start <= mm->start_stack &&
-			    vma->vm_end >= mm->start_stack)) {
-				name = "[stack]";
-			} else {
-				/* Thread stack in /proc/PID/maps */
-				seq_pad(m, ' ');
-				seq_printf(m, "[stack:%d]", tid);
-			}
-		}
+		if (is_stack(priv, vma))
+			name = "[stack]";
 	}
 
 done:
@@ -812,7 +793,14 @@
 static inline void clear_soft_dirty_pmd(struct vm_area_struct *vma,
 		unsigned long addr, pmd_t *pmdp)
 {
-	pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, addr, pmdp);
+	pmd_t pmd = *pmdp;
+
+	/* See comment in change_huge_pmd() */
+	pmdp_invalidate(vma, addr, pmdp);
+	if (pmd_dirty(*pmdp))
+		pmd = pmd_mkdirty(pmd);
+	if (pmd_young(*pmdp))
+		pmd = pmd_mkyoung(pmd);
 
 	pmd = pmd_wrprotect(pmd);
 	pmd = pmd_clear_soft_dirty(pmd);
@@ -962,6 +950,24 @@
 					continue;
 				up_read(&mm->mmap_sem);
 				down_write(&mm->mmap_sem);
+				/*
+				 * Avoid to modify vma->vm_flags
+				 * without locked ops while the
+				 * coredump reads the vm_flags.
+				 */
+				if (!mmget_still_valid(mm)) {
+					/*
+					 * Silently return "count"
+					 * like if get_task_mm()
+					 * failed. FIXME: should this
+					 * function have returned
+					 * -ESRCH if get_task_mm()
+					 * failed like if
+					 * get_proc_task() fails?
+					 */
+					up_write(&mm->mmap_sem);
+					goto out_mm;
+				}
 				for (vma = mm->mmap; vma; vma = vma->vm_next) {
 					vma->vm_flags &= ~VM_SOFTDIRTY;
 					vma_set_page_prot(vma);
@@ -1435,6 +1441,32 @@
 	return page;
 }
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static struct page *can_gather_numa_stats_pmd(pmd_t pmd,
+					      struct vm_area_struct *vma,
+					      unsigned long addr)
+{
+	struct page *page;
+	int nid;
+
+	if (!pmd_present(pmd))
+		return NULL;
+
+	page = vm_normal_page_pmd(vma, addr, pmd);
+	if (!page)
+		return NULL;
+
+	if (PageReserved(page))
+		return NULL;
+
+	nid = page_to_nid(page);
+	if (!node_isset(nid, node_states[N_MEMORY]))
+		return NULL;
+
+	return page;
+}
+#endif
+
 static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
 		unsigned long end, struct mm_walk *walk)
 {
@@ -1444,13 +1476,13 @@
 	pte_t *orig_pte;
 	pte_t *pte;
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
-		pte_t huge_pte = *(pte_t *)pmd;
 		struct page *page;
 
-		page = can_gather_numa_stats(huge_pte, vma, addr);
+		page = can_gather_numa_stats_pmd(*pmd, vma, addr);
 		if (page)
-			gather_stats(page, md, pte_dirty(huge_pte),
+			gather_stats(page, md, pmd_dirty(*pmd),
 				     HPAGE_PMD_SIZE/PAGE_SIZE);
 		spin_unlock(ptl);
 		return 0;
@@ -1458,6 +1490,7 @@
 
 	if (pmd_trans_unstable(pmd))
 		return 0;
+#endif
 	orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
 	do {
 		struct page *page = can_gather_numa_stats(*pte, vma, addr);
@@ -1473,18 +1506,19 @@
 static int gather_hugetlb_stats(pte_t *pte, unsigned long hmask,
 		unsigned long addr, unsigned long end, struct mm_walk *walk)
 {
+	pte_t huge_pte = huge_ptep_get(pte);
 	struct numa_maps *md;
 	struct page *page;
 
-	if (!pte_present(*pte))
+	if (!pte_present(huge_pte))
 		return 0;
 
-	page = pte_page(*pte);
+	page = pte_page(huge_pte);
 	if (!page)
 		return 0;
 
 	md = walk->private;
-	gather_stats(page, md, pte_dirty(*pte), 1);
+	gather_stats(page, md, pte_dirty(huge_pte), 1);
 	return 0;
 }
 
@@ -1505,7 +1539,7 @@
 	struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
 	struct vm_area_struct *vma = v;
 	struct numa_maps *md = &numa_priv->md;
-	struct file *file = vma->vm_file;
+	struct file *file = vma_pr_or_file(vma);
 	struct mm_struct *mm = vma->vm_mm;
 	struct mm_walk walk = {
 		.hugetlb_entry = gather_hugetlb_stats,
@@ -1538,19 +1572,8 @@
 		seq_file_path(m, file, "\n\t= ");
 	} else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
 		seq_puts(m, " heap");
-	} else {
-		pid_t tid = pid_of_stack(proc_priv, vma, is_pid);
-		if (tid != 0) {
-			/*
-			 * Thread stack in /proc/PID/task/TID/maps or
-			 * the main process stack.
-			 */
-			if (!is_pid || (vma->vm_start <= mm->start_stack &&
-			    vma->vm_end >= mm->start_stack))
-				seq_puts(m, " stack");
-			else
-				seq_printf(m, " stack:%d", tid);
-		}
+	} else if (is_stack(proc_priv, vma)) {
+		seq_puts(m, " stack");
 	}
 
 	if (is_vm_hugetlb_page(vma))
--- linux-4.4.0.orig/fs/proc/task_nommu.c
+++ linux-4.4.0/fs/proc/task_nommu.c
@@ -123,23 +123,18 @@
 	return size;
 }
 
-static pid_t pid_of_stack(struct proc_maps_private *priv,
-				struct vm_area_struct *vma, bool is_pid)
+static int is_stack(struct proc_maps_private *priv,
+		    struct vm_area_struct *vma)
 {
-	struct inode *inode = priv->inode;
-	struct task_struct *task;
-	pid_t ret = 0;
-
-	rcu_read_lock();
-	task = pid_task(proc_pid(inode), PIDTYPE_PID);
-	if (task) {
-		task = task_of_stack(task, vma, is_pid);
-		if (task)
-			ret = task_pid_nr_ns(task, inode->i_sb->s_fs_info);
-	}
-	rcu_read_unlock();
+	struct mm_struct *mm = vma->vm_mm;
 
-	return ret;
+	/*
+	 * We make no effort to guess what a given thread considers to be
+	 * its "stack".  It's not even well-defined for programs written
+	 * languages like Go.
+	 */
+	return vma->vm_start <= mm->start_stack &&
+		vma->vm_end >= mm->start_stack;
 }
 
 /*
@@ -160,7 +155,10 @@
 	file = vma->vm_file;
 
 	if (file) {
-		struct inode *inode = file_inode(vma->vm_file);
+		struct inode *inode;
+
+		file = vma_pr_or_file(vma);
+		inode = file_inode(file);
 		dev = inode->i_sb->s_dev;
 		ino = inode->i_ino;
 		pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
@@ -181,21 +179,9 @@
 	if (file) {
 		seq_pad(m, ' ');
 		seq_file_path(m, file, "");
-	} else if (mm) {
-		pid_t tid = pid_of_stack(priv, vma, is_pid);
-
-		if (tid != 0) {
-			seq_pad(m, ' ');
-			/*
-			 * Thread stack in /proc/PID/task/TID/maps or
-			 * the main process stack.
-			 */
-			if (!is_pid || (vma->vm_start <= mm->start_stack &&
-			    vma->vm_end >= mm->start_stack))
-				seq_printf(m, "[stack]");
-			else
-				seq_printf(m, "[stack:%d]", tid);
-		}
+	} else if (mm && is_stack(priv, vma)) {
+		seq_pad(m, ' ');
+		seq_printf(m, "[stack]");
 	}
 
 	seq_putc(m, '\n');
--- linux-4.4.0.orig/fs/proc/thread_self.c
+++ linux-4.4.0/fs/proc/thread_self.c
@@ -52,7 +52,7 @@
 	mutex_lock(&root_inode->i_mutex);
 	thread_self = d_alloc_name(s->s_root, "thread-self");
 	if (thread_self) {
-		struct inode *inode = new_inode_pseudo(s);
+		struct inode *inode = new_inode(s);
 		if (inode) {
 			inode->i_ino = thread_self_inum;
 			inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
--- linux-4.4.0.orig/fs/proc/version_signature.c
+++ linux-4.4.0/fs/proc/version_signature.c
@@ -0,0 +1,32 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/utsname.h>
+
+static int version_signature_proc_show(struct seq_file *m, void *v)
+{
+	seq_printf(m, "%s\n", CONFIG_VERSION_SIGNATURE);
+	return 0;
+}
+
+static int version_signature_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, version_signature_proc_show, NULL);
+}
+
+static const struct file_operations version_signature_proc_fops = {
+	.open		= version_signature_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init proc_version_signature_init(void)
+{
+	proc_create("version_signature", 0, NULL, &version_signature_proc_fops);
+	return 0;
+}
+module_init(proc_version_signature_init);
--- linux-4.4.0.orig/fs/proc/vmcore.c
+++ linux-4.4.0/fs/proc/vmcore.c
@@ -165,6 +165,16 @@
 }
 
 /*
+ * Architectures which support memory encryption override this.
+ */
+ssize_t __weak
+copy_oldmem_page_encrypted(unsigned long pfn, char *buf, size_t csize,
+			   unsigned long offset, int userbuf)
+{
+	return copy_oldmem_page(pfn, buf, csize, offset, userbuf);
+}
+
+/*
  * Copy to either kernel or user space
  */
 static int copy_to(void *target, void *src, size_t size, int userbuf)
--- linux-4.4.0.orig/fs/proc_namespace.c
+++ linux-4.4.0/fs/proc_namespace.c
@@ -197,6 +197,8 @@
 	if (sb->s_op->show_devname) {
 		seq_puts(m, "device ");
 		err = sb->s_op->show_devname(m, mnt_path.dentry);
+		if (err)
+			goto out;
 	} else {
 		if (r->mnt_devname) {
 			seq_puts(m, "device ");
--- linux-4.4.0.orig/fs/pstore/inode.c
+++ linux-4.4.0/fs/pstore/inode.c
@@ -178,7 +178,6 @@
 }
 
 static const struct file_operations pstore_file_operations = {
-	.owner		= THIS_MODULE,
 	.open		= pstore_file_open,
 	.read		= pstore_file_read,
 	.llseek		= pstore_file_llseek,
--- linux-4.4.0.orig/fs/pstore/platform.c
+++ linux-4.4.0/fs/pstore/platform.c
@@ -392,8 +392,8 @@
 		} else {
 			spin_lock_irqsave(&psinfo->buf_lock, flags);
 		}
-		memcpy(psinfo->buf, s, c);
-		psinfo->write(PSTORE_TYPE_CONSOLE, 0, &id, 0, 0, 0, c, psinfo);
+		psinfo->write_buf(PSTORE_TYPE_CONSOLE, 0, &id, 0,
+				  s, 0, c, psinfo);
 		spin_unlock_irqrestore(&psinfo->buf_lock, flags);
 		s += c;
 		c = e - s;
--- linux-4.4.0.orig/fs/pstore/ram.c
+++ linux-4.4.0/fs/pstore/ram.c
@@ -56,7 +56,7 @@
 MODULE_PARM_DESC(pmsg_size, "size of user space message log");
 
 static ulong mem_address;
-module_param(mem_address, ulong, 0400);
+module_param_hw(mem_address, ulong, other, 0400);
 MODULE_PARM_DESC(mem_address,
 		"start of reserved RAM used to store oops/panic logs");
 
@@ -319,6 +319,17 @@
 
 	prz = cxt->przs[cxt->dump_write_cnt];
 
+	/*
+	 * Since this is a new crash dump, we need to reset the buffer in
+	 * case it still has an old dump present. Without this, the new dump
+	 * will get appended, which would seriously confuse anything trying
+	 * to check dump file contents. Specifically, ramoops_read_kmsg_hdr()
+	 * expects to find a dump header in the beginning of buffer data, so
+	 * we must to reset the buffer values, in order to ensure that the
+	 * header will be written to the beginning of the buffer.
+	 */
+	persistent_ram_zap(prz);
+
 	hlen = ramoops_write_kmsg_hdr(prz, compressed);
 	if (size + hlen > prz->buffer_size)
 		size = prz->buffer_size - hlen;
@@ -375,13 +386,14 @@
 {
 	int i;
 
-	cxt->max_dump_cnt = 0;
 	if (!cxt->przs)
 		return;
 
-	for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
+	for (i = 0; i < cxt->max_dump_cnt; i++)
 		persistent_ram_free(cxt->przs[i]);
+
 	kfree(cxt->przs);
+	cxt->max_dump_cnt = 0;
 }
 
 static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
@@ -406,17 +418,22 @@
 			     GFP_KERNEL);
 	if (!cxt->przs) {
 		dev_err(dev, "failed to initialize a prz array for dumps\n");
-		goto fail_prz;
+		goto fail_mem;
 	}
 
 	for (i = 0; i < cxt->max_dump_cnt; i++) {
 		cxt->przs[i] = persistent_ram_new(*paddr, cxt->record_size, 0,
 						  &cxt->ecc_info,
-						  cxt->memtype);
+						  cxt->memtype, 0);
 		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",
 				cxt->record_size, (unsigned long long)*paddr, err);
+
+			while (i > 0) {
+				i--;
+				persistent_ram_free(cxt->przs[i]);
+			}
 			goto fail_prz;
 		}
 		*paddr += cxt->record_size;
@@ -424,7 +441,9 @@
 
 	return 0;
 fail_prz:
-	ramoops_free_przs(cxt);
+	kfree(cxt->przs);
+fail_mem:
+	cxt->max_dump_cnt = 0;
 	return err;
 }
 
@@ -442,7 +461,8 @@
 		return -ENOMEM;
 	}
 
-	*prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info, cxt->memtype);
+	*prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info,
+				  cxt->memtype, 0);
 	if (IS_ERR(*prz)) {
 		int err = PTR_ERR(*prz);
 
@@ -583,7 +603,6 @@
 	struct ramoops_context *cxt = &oops_cxt;
 
 	pstore_unregister(&cxt->pstore);
-	cxt->max_dump_cnt = 0;
 
 	kfree(cxt->pstore.buf);
 	cxt->pstore.bufsize = 0;
--- linux-4.4.0.orig/fs/pstore/ram_core.c
+++ linux-4.4.0/fs/pstore/ram_core.c
@@ -48,48 +48,14 @@
 }
 
 /* increase and wrap the start pointer, returning the old value */
-static size_t buffer_start_add_atomic(struct persistent_ram_zone *prz, size_t a)
+static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
 {
 	int old;
 	int new;
+	unsigned long flags = 0;
 
-	do {
-		old = atomic_read(&prz->buffer->start);
-		new = old + a;
-		while (unlikely(new >= prz->buffer_size))
-			new -= prz->buffer_size;
-	} while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
-
-	return old;
-}
-
-/* increase the size counter until it hits the max size */
-static void buffer_size_add_atomic(struct persistent_ram_zone *prz, size_t a)
-{
-	size_t old;
-	size_t new;
-
-	if (atomic_read(&prz->buffer->size) == prz->buffer_size)
-		return;
-
-	do {
-		old = atomic_read(&prz->buffer->size);
-		new = old + a;
-		if (new > prz->buffer_size)
-			new = prz->buffer_size;
-	} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
-}
-
-static DEFINE_RAW_SPINLOCK(buffer_lock);
-
-/* increase and wrap the start pointer, returning the old value */
-static size_t buffer_start_add_locked(struct persistent_ram_zone *prz, size_t a)
-{
-	int old;
-	int new;
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&buffer_lock, flags);
+	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
+		raw_spin_lock_irqsave(&prz->buffer_lock, flags);
 
 	old = atomic_read(&prz->buffer->start);
 	new = old + a;
@@ -97,19 +63,21 @@
 		new -= prz->buffer_size;
 	atomic_set(&prz->buffer->start, new);
 
-	raw_spin_unlock_irqrestore(&buffer_lock, flags);
+	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
+		raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
 
 	return old;
 }
 
 /* increase the size counter until it hits the max size */
-static void buffer_size_add_locked(struct persistent_ram_zone *prz, size_t a)
+static void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
 {
 	size_t old;
 	size_t new;
-	unsigned long flags;
+	unsigned long flags = 0;
 
-	raw_spin_lock_irqsave(&buffer_lock, flags);
+	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
+		raw_spin_lock_irqsave(&prz->buffer_lock, flags);
 
 	old = atomic_read(&prz->buffer->size);
 	if (old == prz->buffer_size)
@@ -121,12 +89,10 @@
 	atomic_set(&prz->buffer->size, new);
 
 exit:
-	raw_spin_unlock_irqrestore(&buffer_lock, flags);
+	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
+		raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
 }
 
-static size_t (*buffer_start_add)(struct persistent_ram_zone *, size_t) = buffer_start_add_atomic;
-static void (*buffer_size_add)(struct persistent_ram_zone *, size_t) = buffer_size_add_atomic;
-
 static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
 	uint8_t *data, size_t len, uint8_t *ecc)
 {
@@ -299,7 +265,7 @@
 	const void *s, unsigned int start, unsigned int count)
 {
 	struct persistent_ram_buffer *buffer = prz->buffer;
-	memcpy(buffer->data + start, s, count);
+	memcpy_toio(buffer->data + start, s, count);
 	persistent_ram_update_ecc(prz, start, count);
 }
 
@@ -322,8 +288,8 @@
 	}
 
 	prz->old_log_size = size;
-	memcpy(prz->old_log, &buffer->data[start], size - start);
-	memcpy(prz->old_log + size - start, &buffer->data[0], start);
+	memcpy_fromio(prz->old_log, &buffer->data[start], size - start);
+	memcpy_fromio(prz->old_log + size - start, &buffer->data[0], start);
 }
 
 int notrace persistent_ram_write(struct persistent_ram_zone *prz,
@@ -412,7 +378,12 @@
 	vaddr = vmap(pages, page_count, VM_MAP, prot);
 	kfree(pages);
 
-	return vaddr;
+	/*
+	 * Since vmap() uses page granularity, we must add the offset
+	 * into the page here, to get the byte granularity address
+	 * into the mapping to represent the actual "start" location.
+	 */
+	return vaddr + offset_in_page(start);
 }
 
 static void *persistent_ram_iomap(phys_addr_t start, size_t size,
@@ -426,14 +397,16 @@
 		return NULL;
 	}
 
-	buffer_start_add = buffer_start_add_locked;
-	buffer_size_add = buffer_size_add_locked;
-
 	if (memtype)
 		va = ioremap(start, size);
 	else
 		va = ioremap_wc(start, size);
 
+	/*
+	 * Since request_mem_region() and ioremap() are byte-granularity
+	 * there is no need handle anything special like we do when the
+	 * vmap() case in persistent_ram_vmap() above.
+	 */
 	return va;
 }
 
@@ -454,7 +427,7 @@
 		return -ENOMEM;
 	}
 
-	prz->buffer = prz->vaddr + offset_in_page(start);
+	prz->buffer = prz->vaddr;
 	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
 
 	return 0;
@@ -472,6 +445,11 @@
 	sig ^= PERSISTENT_RAM_SIG;
 
 	if (prz->buffer->sig == sig) {
+		if (buffer_size(prz) == 0) {
+			pr_debug("found existing empty buffer\n");
+			return 0;
+		}
+
 		if (buffer_size(prz) > prz->buffer_size ||
 		    buffer_start(prz) > buffer_size(prz))
 			pr_info("found existing invalid buffer, size %zu, start %zu\n",
@@ -487,6 +465,7 @@
 			 prz->buffer->sig);
 	}
 
+	/* Rewind missing or invalid memory area. */
 	prz->buffer->sig = sig;
 	persistent_ram_zap(prz);
 
@@ -500,7 +479,8 @@
 
 	if (prz->vaddr) {
 		if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
-			vunmap(prz->vaddr);
+			/* We must vunmap() at page-granularity. */
+			vunmap(prz->vaddr - offset_in_page(prz->paddr));
 		} else {
 			iounmap(prz->vaddr);
 			release_mem_region(prz->paddr, prz->size);
@@ -513,7 +493,7 @@
 
 struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
 			u32 sig, struct persistent_ram_ecc_info *ecc_info,
-			unsigned int memtype)
+			unsigned int memtype, u32 flags)
 {
 	struct persistent_ram_zone *prz;
 	int ret = -ENOMEM;
@@ -524,6 +504,10 @@
 		goto err;
 	}
 
+	/* Initialize general buffer state. */
+	raw_spin_lock_init(&prz->buffer_lock);
+	prz->flags = flags;
+
 	ret = persistent_ram_buffer_map(start, size, prz, memtype);
 	if (ret)
 		goto err;
--- linux-4.4.0.orig/fs/quota/dquot.c
+++ linux-4.4.0/fs/quota/dquot.c
@@ -472,7 +472,7 @@
 
 	mutex_lock(&dquot->dq_lock);
 	/* Check whether we are not racing with some other dqget() */
-	if (atomic_read(&dquot->dq_count) > 1)
+	if (dquot_is_busy(dquot))
 		goto out_dqlock;
 	mutex_lock(&dqopt->dqio_mutex);
 	if (dqopt->ops[dquot->dq_id.type]->release_dqblk) {
@@ -604,7 +604,7 @@
 /* Write all dquot structures to quota files */
 int dquot_writeback_dquots(struct super_block *sb, int type)
 {
-	struct list_head *dirty;
+	struct list_head dirty;
 	struct dquot *dquot;
 	struct quota_info *dqopt = sb_dqopt(sb);
 	int cnt;
@@ -617,9 +617,10 @@
 		if (!sb_has_quota_active(sb, cnt))
 			continue;
 		spin_lock(&dq_list_lock);
-		dirty = &dqopt->info[cnt].dqi_dirty_list;
-		while (!list_empty(dirty)) {
-			dquot = list_first_entry(dirty, struct dquot,
+		/* Move list away to avoid livelock. */
+		list_replace_init(&dqopt->info[cnt].dqi_dirty_list, &dirty);
+		while (!list_empty(&dirty)) {
+			dquot = list_first_entry(&dirty, struct dquot,
 						 dq_dirty);
 			/* Dirty and inactive can be only bad dquot... */
 			if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
@@ -834,6 +835,9 @@
 	unsigned int hashent = hashfn(sb, qid);
 	struct dquot *dquot, *empty = NULL;
 
+	if (!qid_has_mapping(sb->s_user_ns, qid))
+		return ERR_PTR(-EINVAL);
+
         if (!sb_has_quota_active(sb, qid.type))
 		return ERR_PTR(-ESRCH);
 we_slept:
@@ -1398,7 +1402,7 @@
 static int __dquot_initialize(struct inode *inode, int type)
 {
 	int cnt, init_needed = 0;
-	struct dquot **dquots, *got[MAXQUOTAS];
+	struct dquot **dquots, *got[MAXQUOTAS] = {};
 	struct super_block *sb = inode->i_sb;
 	qsize_t rsv;
 	int ret = 0;
@@ -1415,7 +1419,6 @@
 		int rc;
 		struct dquot *dquot;
 
-		got[cnt] = NULL;
 		if (type != -1 && cnt != type)
 			continue;
 		/*
@@ -2232,6 +2235,11 @@
 		error = -EINVAL;
 		goto out_fmt;
 	}
+	/* Filesystems outside of init_user_ns not yet supported */
+	if (sb->s_user_ns != &init_user_ns) {
+		error = -EINVAL;
+		goto out_fmt;
+	}
 	/* Usage always has to be set... */
 	if (!(flags & DQUOT_USAGE_ENABLED)) {
 		error = -EINVAL;
@@ -2783,68 +2791,73 @@
 static int do_proc_dqstats(struct ctl_table *table, int write,
 		     void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-	unsigned int type = (int *)table->data - dqstats.stat;
+	unsigned int type = (unsigned long *)table->data - dqstats.stat;
+	s64 value = percpu_counter_sum(&dqstats.counter[type]);
+
+	/* Filter negative values for non-monotonic counters */
+	if (value < 0 && (type == DQST_ALLOC_DQUOTS ||
+			  type == DQST_FREE_DQUOTS))
+		value = 0;
 
 	/* Update global table */
-	dqstats.stat[type] =
-			percpu_counter_sum_positive(&dqstats.counter[type]);
-	return proc_dointvec(table, write, buffer, lenp, ppos);
+	dqstats.stat[type] = value;
+	return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 }
 
 static struct ctl_table fs_dqstats_table[] = {
 	{
 		.procname	= "lookups",
 		.data		= &dqstats.stat[DQST_LOOKUPS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "drops",
 		.data		= &dqstats.stat[DQST_DROPS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "reads",
 		.data		= &dqstats.stat[DQST_READS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "writes",
 		.data		= &dqstats.stat[DQST_WRITES],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "cache_hits",
 		.data		= &dqstats.stat[DQST_CACHE_HITS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "allocated_dquots",
 		.data		= &dqstats.stat[DQST_ALLOC_DQUOTS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "free_dquots",
 		.data		= &dqstats.stat[DQST_FREE_DQUOTS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "syncs",
 		.data		= &dqstats.stat[DQST_SYNCS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
@@ -2920,7 +2933,8 @@
 	pr_info("VFS: Dquot-cache hash table entries: %ld (order %ld,"
 		" %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order));
 
-	register_shrinker(&dqcache_shrinker);
+	if (register_shrinker(&dqcache_shrinker))
+		panic("Cannot register dquot shrinker");
 
 	return 0;
 }
--- linux-4.4.0.orig/fs/quota/quota.c
+++ linux-4.4.0/fs/quota/quota.c
@@ -17,6 +17,7 @@
 #include <linux/quotaops.h>
 #include <linux/types.h>
 #include <linux/writeback.h>
+#include <linux/nospec.h>
 
 static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
 				     qid_t id)
@@ -211,7 +212,7 @@
 	if (!sb->s_qcop->get_dqblk)
 		return -ENOSYS;
 	qid = make_kqid(current_user_ns(), type, id);
-	if (!qid_valid(qid))
+	if (!qid_has_mapping(sb->s_user_ns, qid))
 		return -EINVAL;
 	ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
 	if (ret)
@@ -260,7 +261,7 @@
 	if (!sb->s_qcop->set_dqblk)
 		return -ENOSYS;
 	qid = make_kqid(current_user_ns(), type, id);
-	if (!qid_valid(qid))
+	if (!qid_has_mapping(sb->s_user_ns, qid))
 		return -EINVAL;
 	copy_from_if_dqblk(&fdq, &idq);
 	return sb->s_qcop->set_dqblk(sb, qid, &fdq);
@@ -553,10 +554,10 @@
 	if (!sb->s_qcop->set_dqblk)
 		return -ENOSYS;
 	qid = make_kqid(current_user_ns(), type, id);
-	if (!qid_valid(qid))
+	if (!qid_has_mapping(sb->s_user_ns, qid))
 		return -EINVAL;
 	/* Are we actually setting timer / warning limits for all users? */
-	if (from_kqid(&init_user_ns, qid) == 0 &&
+	if (from_kqid(sb->s_user_ns, qid) == 0 &&
 	    fdq.d_fieldmask & (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) {
 		struct qc_info qinfo;
 		int ret;
@@ -614,7 +615,7 @@
 	if (!sb->s_qcop->get_dqblk)
 		return -ENOSYS;
 	qid = make_kqid(current_user_ns(), type, id);
-	if (!qid_valid(qid))
+	if (!qid_has_mapping(sb->s_user_ns, qid))
 		return -EINVAL;
 	ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
 	if (ret)
@@ -644,6 +645,7 @@
 
 	if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS))
 		return -EINVAL;
+	type = array_index_nospec(type, MAXQUOTAS);
 	/*
 	 * Quota not supported on this fs? Check this before s_quota_types
 	 * since they needn't be set if quota is not supported at all.
@@ -733,7 +735,7 @@
 
 	if (IS_ERR(tmp))
 		return ERR_CAST(tmp);
-	bdev = lookup_bdev(tmp->name);
+	bdev = lookup_bdev(tmp->name, 0);
 	putname(tmp);
 	if (IS_ERR(bdev))
 		return ERR_CAST(bdev);
--- linux-4.4.0.orig/fs/quota/quota_tree.c
+++ linux-4.4.0/fs/quota/quota_tree.c
@@ -55,7 +55,7 @@
 
 	memset(buf, 0, info->dqi_usable_bs);
 	return sb->s_op->quota_read(sb, info->dqi_type, buf,
-	       info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
+	       info->dqi_usable_bs, (loff_t)blk << info->dqi_blocksize_bits);
 }
 
 static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf)
@@ -64,7 +64,7 @@
 	ssize_t ret;
 
 	ret = sb->s_op->quota_write(sb, info->dqi_type, buf,
-	       info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
+	       info->dqi_usable_bs, (loff_t)blk << info->dqi_blocksize_bits);
 	if (ret != info->dqi_usable_bs) {
 		quota_error(sb, "dquota write failed");
 		if (ret >= 0)
@@ -277,7 +277,7 @@
 			    blk);
 		goto out_buf;
 	}
-	dquot->dq_off = (blk << info->dqi_blocksize_bits) +
+	dquot->dq_off = ((loff_t)blk << info->dqi_blocksize_bits) +
 			sizeof(struct qt_disk_dqdbheader) +
 			i * info->dqi_entry_size;
 	kfree(buf);
@@ -481,6 +481,13 @@
 		goto out_buf;
 	}
 	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+	if (newblk < QT_TREEOFF || newblk >= info->dqi_blocks) {
+		quota_error(dquot->dq_sb, "Getting block too big (%u >= %u)",
+			    newblk, info->dqi_blocks);
+		ret = -EUCLEAN;
+		goto out_buf;
+	}
+
 	if (depth == info->dqi_qtree_depth - 1) {
 		ret = free_dqentry(info, dquot, newblk);
 		newblk = 0;
@@ -552,7 +559,7 @@
 		ret = -EIO;
 		goto out_buf;
 	} else {
-		ret = (blk << info->dqi_blocksize_bits) + sizeof(struct
+		ret = ((loff_t)blk << info->dqi_blocksize_bits) + sizeof(struct
 		  qt_disk_dqdbheader) + i * info->dqi_entry_size;
 	}
 out_buf:
@@ -580,6 +587,13 @@
 	blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
 	if (!blk)	/* No reference? */
 		goto out_buf;
+	if (blk < QT_TREEOFF || blk >= info->dqi_blocks) {
+		quota_error(dquot->dq_sb, "Getting block too big (%u >= %u)",
+			    blk, info->dqi_blocks);
+		ret = -EUCLEAN;
+		goto out_buf;
+	}
+
 	if (depth < info->dqi_qtree_depth - 1)
 		ret = find_tree_dqentry(info, dquot, blk, depth+1);
 	else
--- linux-4.4.0.orig/fs/quota/quota_v2.c
+++ linux-4.4.0/fs/quota/quota_v2.c
@@ -266,6 +266,7 @@
 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
 	d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
+	d->dqb_pad = 0;
 	if (qtree_entry_unused(info, dp))
 		d->dqb_itime = cpu_to_le64(1);
 }
--- linux-4.4.0.orig/fs/ramfs/file-nommu.c
+++ linux-4.4.0/fs/ramfs/file-nommu.c
@@ -169,7 +169,7 @@
 	int ret = 0;
 
 	/* POSIX UID/GID verification for setting inode attributes */
-	ret = inode_change_ok(inode, ia);
+	ret = setattr_prepare(dentry, ia);
 	if (ret)
 		return ret;
 
--- linux-4.4.0.orig/fs/read_write.c
+++ linux-4.4.0/fs/read_write.c
@@ -112,7 +112,7 @@
 		 * In the generic case the entire file is data, so as long as
 		 * offset isn't at the end of the file then the offset is data.
 		 */
-		if (offset >= eof)
+		if ((unsigned long long)offset >= eof)
 			return -ENXIO;
 		break;
 	case SEEK_HOLE:
@@ -120,7 +120,7 @@
 		 * There is a virtual hole at the end of the file, so as long as
 		 * offset isn't i_size or larger, return i_size.
 		 */
-		if (offset >= eof)
+		if ((unsigned long long)offset >= eof)
 			return -ENXIO;
 		offset = eof;
 		break;
@@ -363,8 +363,10 @@
 	iter->type |= WRITE;
 	ret = file->f_op->write_iter(&kiocb, iter);
 	BUG_ON(ret == -EIOCBQUEUED);
-	if (ret > 0)
+	if (ret > 0) {
 		*ppos = kiocb.ki_pos;
+		fsnotify_modify(file);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(vfs_iter_write);
@@ -494,6 +496,30 @@
 }
 EXPORT_SYMBOL(__vfs_write);
 
+vfs_readf_t vfs_readf(struct file *file)
+{
+	const struct file_operations *fop = file->f_op;
+
+	if (fop->read)
+		return fop->read;
+	if (fop->read_iter)
+		return new_sync_read;
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(vfs_readf);
+
+vfs_writef_t vfs_writef(struct file *file)
+{
+	const struct file_operations *fop = file->f_op;
+
+	if (fop->write)
+		return fop->write;
+	if (fop->write_iter)
+		return new_sync_write;
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(vfs_writef);
+
 ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
 {
 	mm_segment_t old_fs;
@@ -551,12 +577,13 @@
 
 static inline loff_t file_pos_read(struct file *file)
 {
-	return file->f_pos;
+	return file->f_mode & FMODE_STREAM ? 0 : file->f_pos;
 }
 
 static inline void file_pos_write(struct file *file, loff_t pos)
 {
-	file->f_pos = pos;
+	if ((file->f_mode & FMODE_STREAM) == 0)
+		file->f_pos = pos;
 }
 
 SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
--- linux-4.4.0.orig/fs/readdir.c
+++ linux-4.4.0/fs/readdir.c
@@ -51,6 +51,40 @@
 EXPORT_SYMBOL(iterate_dir);
 
 /*
+ * POSIX says that a dirent name cannot contain NULL or a '/'.
+ *
+ * It's not 100% clear what we should really do in this case.
+ * The filesystem is clearly corrupted, but returning a hard
+ * error means that you now don't see any of the other names
+ * either, so that isn't a perfect alternative.
+ *
+ * And if you return an error, what error do you use? Several
+ * filesystems seem to have decided on EUCLEAN being the error
+ * code for EFSCORRUPTED, and that may be the error to use. Or
+ * just EIO, which is perhaps more obvious to users.
+ *
+ * In order to see the other file names in the directory, the
+ * caller might want to make this a "soft" error: skip the
+ * entry, and return the error at the end instead.
+ *
+ * Note that this should likely do a "memchr(name, 0, len)"
+ * check too, since that would be filesystem corruption as
+ * well. However, that case can't actually confuse user space,
+ * which has to do a strlen() on the name anyway to find the
+ * filename length, and the above "soft error" worry means
+ * that it's probably better left alone until we have that
+ * issue clarified.
+ */
+static int verify_dirent_name(const char *name, int len)
+{
+	if (!len)
+		return -EIO;
+	if (memchr(name, '/', len))
+		return -EIO;
+	return 0;
+}
+
+/*
  * Traditional linux readdir() handling..
  *
  * "count=1" is a special case, meaning that the buffer is one
@@ -159,6 +193,9 @@
 	int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
 		sizeof(long));
 
+	buf->error = verify_dirent_name(name, namlen);
+	if (unlikely(buf->error))
+		return buf->error;
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
 		return -EINVAL;
@@ -243,6 +280,9 @@
 	int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
 		sizeof(u64));
 
+	buf->error = verify_dirent_name(name, namlen);
+	if (unlikely(buf->error))
+		return buf->error;
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
 		return -EINVAL;
--- linux-4.4.0.orig/fs/reiserfs/bitmap.c
+++ linux-4.4.0/fs/reiserfs/bitmap.c
@@ -513,9 +513,17 @@
 			       "inode has negative prealloc blocks count.");
 #endif
 	while (ei->i_prealloc_count > 0) {
-		reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
-		ei->i_prealloc_block++;
+		b_blocknr_t block_to_free;
+
+		/*
+		 * reiserfs_free_prealloc_block can drop the write lock,
+		 * which could allow another caller to free the same block.
+		 * We can protect against it by modifying the prealloc
+		 * state before calling it.
+		 */
+		block_to_free = ei->i_prealloc_block++;
 		ei->i_prealloc_count--;
+		reiserfs_free_prealloc_block(th, inode, block_to_free);
 		dirty = 1;
 	}
 	if (dirty)
@@ -1128,7 +1136,7 @@
 	hint->prealloc_size = 0;
 
 	if (!hint->formatted_node && hint->preallocate) {
-		if (S_ISREG(hint->inode->i_mode)
+		if (S_ISREG(hint->inode->i_mode) && !IS_PRIVATE(hint->inode)
 		    && hint->inode->i_size >=
 		    REISERFS_SB(hint->th->t_super)->s_alloc_options.
 		    preallocmin * hint->inode->i_sb->s_blocksize)
--- linux-4.4.0.orig/fs/reiserfs/file.c
+++ linux-4.4.0/fs/reiserfs/file.c
@@ -189,7 +189,7 @@
 	int ret = 0;
 
 	th.t_trans_id = 0;
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 
 	if (logit) {
 		reiserfs_write_lock(s);
@@ -260,10 +260,10 @@
 
 const struct inode_operations reiserfs_file_inode_operations = {
 	.setattr = reiserfs_setattr,
-	.setxattr = reiserfs_setxattr,
-	.getxattr = reiserfs_getxattr,
+	.setxattr = generic_setxattr,
+	.getxattr = generic_getxattr,
 	.listxattr = reiserfs_listxattr,
-	.removexattr = reiserfs_removexattr,
+	.removexattr = generic_removexattr,
 	.permission = reiserfs_permission,
 	.get_acl = reiserfs_get_acl,
 	.set_acl = reiserfs_set_acl,
--- linux-4.4.0.orig/fs/reiserfs/ibalance.c
+++ linux-4.4.0/fs/reiserfs/ibalance.c
@@ -1153,8 +1153,9 @@
 				       insert_ptr);
 	}
 
-	memcpy(new_insert_key_addr, &new_insert_key, KEY_SIZE);
 	insert_ptr[0] = new_insert_ptr;
+	if (new_insert_ptr)
+		memcpy(new_insert_key_addr, &new_insert_key, KEY_SIZE);
 
 	return order;
 }
--- linux-4.4.0.orig/fs/reiserfs/inode.c
+++ linux-4.4.0/fs/reiserfs/inode.c
@@ -524,7 +524,7 @@
 	 * referenced in convert_tail_for_hole() that may be called from
 	 * reiserfs_get_block()
 	 */
-	bh_result->b_size = (1 << inode->i_blkbits);
+	bh_result->b_size = i_blocksize(inode);
 
 	ret = reiserfs_get_block(inode, iblock, bh_result,
 				 create | GET_BLOCK_NO_DANGLE);
@@ -1553,11 +1553,7 @@
 	 * set version 1, version 2 could be used too, because stat data
 	 * key is the same in both versions
 	 */
-	key.version = KEY_FORMAT_3_5;
-	key.on_disk_key.k_dir_id = dirino;
-	key.on_disk_key.k_objectid = inode->i_ino;
-	key.on_disk_key.k_offset = 0;
-	key.on_disk_key.k_type = 0;
+	_make_cpu_key(&key, KEY_FORMAT_3_5, dirino, inode->i_ino, 0, 0, 3);
 
 	/* look for the object's stat data */
 	retval = search_item(inode->i_sb, &key, &path_to_sd);
@@ -2161,7 +2157,8 @@
 out_inserted_sd:
 	clear_nlink(inode);
 	th->t_trans_id = 0;	/* so the caller can't use this handle later */
-	unlock_new_inode(inode); /* OK to do even if we hadn't locked it */
+	if (inode->i_state & I_NEW)
+		unlock_new_inode(inode);
 	iput(inode);
 	return err;
 }
@@ -3312,7 +3309,7 @@
 	unsigned int ia_valid;
 	int error;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/reiserfs/journal.c
+++ linux-4.4.0/fs/reiserfs/journal.c
@@ -1961,7 +1961,7 @@
 	 * will be requeued because superblock is being shutdown and doesn't
 	 * have MS_ACTIVE set.
 	 */
-	cancel_delayed_work_sync(&REISERFS_SB(sb)->old_work);
+	reiserfs_cancel_old_flush(sb);
 	/* wait for all commits to finish */
 	cancel_delayed_work_sync(&SB_JOURNAL(sb)->j_work);
 
@@ -2643,7 +2643,7 @@
 	if (IS_ERR(journal->j_dev_bd)) {
 		result = PTR_ERR(journal->j_dev_bd);
 		journal->j_dev_bd = NULL;
-		reiserfs_warning(super,
+		reiserfs_warning(super, "sh-457",
 				 "journal_init_dev: Cannot open '%s': %i",
 				 jdev_name, result);
 		return result;
--- linux-4.4.0.orig/fs/reiserfs/lbalance.c
+++ linux-4.4.0/fs/reiserfs/lbalance.c
@@ -475,7 +475,7 @@
 			 * 'cpy_bytes'; create new item header;
 			 * n_ih = new item_header;
 			 */
-			memcpy(&n_ih, ih, SHORT_KEY_SIZE);
+			memcpy(&n_ih.ih_key, &ih->ih_key, KEY_SIZE);
 
 			/* Endian safe, both le */
 			n_ih.ih_version = ih->ih_version;
--- linux-4.4.0.orig/fs/reiserfs/namei.c
+++ linux-4.4.0/fs/reiserfs/namei.c
@@ -687,8 +687,7 @@
 	reiserfs_update_inode_transaction(inode);
 	reiserfs_update_inode_transaction(dir);
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	retval = journal_end(&th);
 
 out_failed:
@@ -771,8 +770,7 @@
 		goto out_failed;
 	}
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	retval = journal_end(&th);
 
 out_failed:
@@ -871,8 +869,7 @@
 	/* the above add_entry did not update dir's stat data */
 	reiserfs_update_sd(&th, dir);
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	retval = journal_end(&th);
 out_failed:
 	reiserfs_write_unlock(dir->i_sb);
@@ -1186,8 +1183,7 @@
 		goto out_failed;
 	}
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	retval = journal_end(&th);
 out_failed:
 	reiserfs_write_unlock(parent_dir->i_sb);
@@ -1649,10 +1645,10 @@
 	.mknod = reiserfs_mknod,
 	.rename = reiserfs_rename,
 	.setattr = reiserfs_setattr,
-	.setxattr = reiserfs_setxattr,
-	.getxattr = reiserfs_getxattr,
+	.setxattr = generic_setxattr,
+	.getxattr = generic_getxattr,
 	.listxattr = reiserfs_listxattr,
-	.removexattr = reiserfs_removexattr,
+	.removexattr = generic_removexattr,
 	.permission = reiserfs_permission,
 	.get_acl = reiserfs_get_acl,
 	.set_acl = reiserfs_set_acl,
@@ -1667,10 +1663,10 @@
 	.follow_link = page_follow_link_light,
 	.put_link = page_put_link,
 	.setattr = reiserfs_setattr,
-	.setxattr = reiserfs_setxattr,
-	.getxattr = reiserfs_getxattr,
+	.setxattr = generic_setxattr,
+	.getxattr = generic_getxattr,
 	.listxattr = reiserfs_listxattr,
-	.removexattr = reiserfs_removexattr,
+	.removexattr = generic_removexattr,
 	.permission = reiserfs_permission,
 };
 
@@ -1679,10 +1675,10 @@
  */
 const struct inode_operations reiserfs_special_inode_operations = {
 	.setattr = reiserfs_setattr,
-	.setxattr = reiserfs_setxattr,
-	.getxattr = reiserfs_getxattr,
+	.setxattr = generic_setxattr,
+	.getxattr = generic_getxattr,
 	.listxattr = reiserfs_listxattr,
-	.removexattr = reiserfs_removexattr,
+	.removexattr = generic_removexattr,
 	.permission = reiserfs_permission,
 	.get_acl = reiserfs_get_acl,
 	.set_acl = reiserfs_set_acl,
--- linux-4.4.0.orig/fs/reiserfs/reiserfs.h
+++ linux-4.4.0/fs/reiserfs/reiserfs.h
@@ -270,7 +270,7 @@
 
 	struct mutex j_commit_mutex;
 	unsigned int j_trans_id;
-	time_t j_timestamp;
+	time64_t j_timestamp; /* write-only but useful for crash dump analysis */
 	struct reiserfs_list_bitmap *j_list_bitmap;
 	struct buffer_head *j_commit_bh;	/* commit buffer head */
 	struct reiserfs_journal_cnode *j_realblock;
@@ -1326,7 +1326,6 @@
 #define KEY_NOT_FOUND 0
 
 #define KEY_SIZE (sizeof(struct reiserfs_key))
-#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
 
 /* return values for search_by_key and clones */
 #define ITEM_FOUND 1
@@ -2949,6 +2948,7 @@
 				   struct reiserfs_list_bitmap *, unsigned int);
 
 void reiserfs_schedule_old_flush(struct super_block *s);
+void reiserfs_cancel_old_flush(struct super_block *s);
 void add_save_link(struct reiserfs_transaction_handle *th,
 		   struct inode *inode, int truncate);
 int remove_save_link(struct inode *inode, int truncate);
--- linux-4.4.0.orig/fs/reiserfs/stree.c
+++ linux-4.4.0/fs/reiserfs/stree.c
@@ -453,6 +453,12 @@
 					 "(second one): %h", ih);
 			return 0;
 		}
+		if (is_direntry_le_ih(ih) && (ih_item_len(ih) < (ih_entry_count(ih) * IH_SIZE))) {
+			reiserfs_warning(NULL, "reiserfs-5093",
+					 "item entry count seems wrong %h",
+					 ih);
+			return 0;
+		}
 		prev_location = ih_location(ih);
 	}
 
@@ -2249,7 +2255,8 @@
 	/* also releases the path */
 	unfix_nodes(&s_ins_balance);
 #ifdef REISERQUOTA_DEBUG
-	reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE,
+	if (inode)
+		reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE,
 		       "reiserquota insert_item(): freeing %u id=%u type=%c",
 		       quota_bytes, inode->i_uid, head2type(ih));
 #endif
--- linux-4.4.0.orig/fs/reiserfs/super.c
+++ linux-4.4.0/fs/reiserfs/super.c
@@ -90,7 +90,9 @@
 	s = sbi->s_journal->j_work_sb;
 
 	spin_lock(&sbi->old_work_lock);
-	sbi->work_queued = 0;
+	/* Avoid clobbering the cancel state... */
+	if (sbi->work_queued == 1)
+		sbi->work_queued = 0;
 	spin_unlock(&sbi->old_work_lock);
 
 	reiserfs_sync_fs(s, 1);
@@ -117,21 +119,22 @@
 	spin_unlock(&sbi->old_work_lock);
 }
 
-static void cancel_old_flush(struct super_block *s)
+void reiserfs_cancel_old_flush(struct super_block *s)
 {
 	struct reiserfs_sb_info *sbi = REISERFS_SB(s);
 
-	cancel_delayed_work_sync(&REISERFS_SB(s)->old_work);
 	spin_lock(&sbi->old_work_lock);
-	sbi->work_queued = 0;
+	/* Make sure no new flushes will be queued */
+	sbi->work_queued = 2;
 	spin_unlock(&sbi->old_work_lock);
+	cancel_delayed_work_sync(&REISERFS_SB(s)->old_work);
 }
 
 static int reiserfs_freeze(struct super_block *s)
 {
 	struct reiserfs_transaction_handle th;
 
-	cancel_old_flush(s);
+	reiserfs_cancel_old_flush(s);
 
 	reiserfs_write_lock(s);
 	if (!(s->s_flags & MS_RDONLY)) {
@@ -152,7 +155,13 @@
 
 static int reiserfs_unfreeze(struct super_block *s)
 {
+	struct reiserfs_sb_info *sbi = REISERFS_SB(s);
+
 	reiserfs_allow_writes(s);
+	spin_lock(&sbi->old_work_lock);
+	/* Allow old_work to run again */
+	sbi->work_queued = 0;
+	spin_unlock(&sbi->old_work_lock);
 	return 0;
 }
 
@@ -190,7 +199,15 @@
 static int reiserfs_quota_on_mount(struct super_block *, int);
 #endif
 
-/* look for uncompleted unlinks and truncates and complete them */
+/*
+ * Look for uncompleted unlinks and truncates and complete them
+ *
+ * Called with superblock write locked.  If quotas are enabled, we have to
+ * release/retake lest we call dquot_quota_on_mount(), proceed to
+ * schedule_on_each_cpu() in invalidate_bdev() and deadlock waiting for the per
+ * cpu worklets to complete flush_async_commits() that in turn wait for the
+ * superblock write lock.
+ */
 static int finish_unfinished(struct super_block *s)
 {
 	INITIALIZE_PATH(path);
@@ -237,7 +254,9 @@
 				quota_enabled[i] = 0;
 				continue;
 			}
+			reiserfs_write_unlock(s);
 			ret = reiserfs_quota_on_mount(s, i);
+			reiserfs_write_lock(s);
 			if (ret < 0)
 				reiserfs_warning(s, "reiserfs-2500",
 						 "cannot turn on journaled "
@@ -580,6 +599,7 @@
 	reiserfs_write_unlock(s);
 	mutex_destroy(&REISERFS_SB(s)->lock);
 	destroy_workqueue(REISERFS_SB(s)->commit_wq);
+	kfree(REISERFS_SB(s)->s_jdev);
 	kfree(s->s_fs_info);
 	s->s_fs_info = NULL;
 }
@@ -1212,6 +1232,10 @@
 						 "turned on.");
 				return 0;
 			}
+			if (qf_names[qtype] !=
+			    REISERFS_SB(s)->s_qf_names[qtype])
+				kfree(qf_names[qtype]);
+			qf_names[qtype] = NULL;
 			if (*arg) {	/* Some filename specified? */
 				if (REISERFS_SB(s)->s_qf_names[qtype]
 				    && strcmp(REISERFS_SB(s)->s_qf_names[qtype],
@@ -1241,10 +1265,6 @@
 				else
 					*mount_options |= 1 << REISERFS_GRPQUOTA;
 			} else {
-				if (qf_names[qtype] !=
-				    REISERFS_SB(s)->s_qf_names[qtype])
-					kfree(qf_names[qtype]);
-				qf_names[qtype] = NULL;
 				if (qtype == USRQUOTA)
 					*mount_options &= ~(1 << REISERFS_USRQUOTA);
 				else
@@ -1901,7 +1921,7 @@
 		if (!sbi->s_jdev) {
 			SWARN(silent, s, "", "Cannot allocate memory for "
 				"journal device name");
-			goto error;
+			goto error_unlocked;
 		}
 	}
 #ifdef CONFIG_QUOTA
@@ -2177,7 +2197,7 @@
 	if (sbi->commit_wq)
 		destroy_workqueue(sbi->commit_wq);
 
-	cancel_delayed_work_sync(&REISERFS_SB(s)->old_work);
+	reiserfs_cancel_old_flush(s);
 
 	reiserfs_free_bitmap_cache(s);
 	if (SB_BUFFER_WITH_SB(s))
@@ -2189,6 +2209,7 @@
 			kfree(qf_names[j]);
 	}
 #endif
+	kfree(sbi->s_jdev);
 	kfree(sbi);
 
 	s->s_fs_info = NULL;
--- linux-4.4.0.orig/fs/reiserfs/xattr.c
+++ linux-4.4.0/fs/reiserfs/xattr.c
@@ -184,6 +184,7 @@
 	struct dir_context ctx;
 	struct dentry *xadir;
 	int count;
+	int err;
 	struct dentry *dentries[8];
 };
 
@@ -206,6 +207,7 @@
 
 	dentry = lookup_one_len(name, dbuf->xadir, namelen);
 	if (IS_ERR(dentry)) {
+		dbuf->err = PTR_ERR(dentry);
 		return PTR_ERR(dentry);
 	} else if (d_really_is_negative(dentry)) {
 		/* A directory entry exists, but no file? */
@@ -214,6 +216,7 @@
 			       "not found for file %pd.\n",
 			       dentry, dbuf->xadir);
 		dput(dentry);
+		dbuf->err = -EIO;
 		return -EIO;
 	}
 
@@ -261,6 +264,10 @@
 		err = reiserfs_readdir_inode(d_inode(dir), &buf.ctx);
 		if (err)
 			break;
+		if (buf.err) {
+			err = buf.err;
+			break;
+		}
 		if (!buf.count)
 			break;
 		for (i = 0; !err && i < buf.count && buf.dentries[i]; i++) {
@@ -649,6 +656,13 @@
 	if (get_inode_sd_version(inode) == STAT_DATA_V1)
 		return -EOPNOTSUPP;
 
+	/*
+	 * priv_root needn't be initialized during mount so allow initial
+	 * lookups to succeed.
+	 */
+	if (!REISERFS_SB(inode->i_sb)->priv_root)
+		return 0;
+
 	dentry = xattr_lookup(inode, name, XATTR_REPLACE);
 	if (IS_ERR(dentry)) {
 		err = PTR_ERR(dentry);
@@ -763,60 +777,6 @@
 	return xah;
 }
 
-
-/*
- * Inode operation getxattr()
- */
-ssize_t
-reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
-		  size_t size)
-{
-	const struct xattr_handler *handler;
-
-	handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
-
-	if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
-		return -EOPNOTSUPP;
-
-	return handler->get(handler, dentry, name, buffer, size);
-}
-
-/*
- * Inode operation setxattr()
- *
- * d_inode(dentry)->i_mutex down
- */
-int
-reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
-		  size_t size, int flags)
-{
-	const struct xattr_handler *handler;
-
-	handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
-
-	if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
-		return -EOPNOTSUPP;
-
-	return handler->set(handler, dentry, name, value, size, flags);
-}
-
-/*
- * Inode operation removexattr()
- *
- * d_inode(dentry)->i_mutex down
- */
-int reiserfs_removexattr(struct dentry *dentry, const char *name)
-{
-	const struct xattr_handler *handler;
-
-	handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
-
-	if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
-		return -EOPNOTSUPP;
-
-	return handler->set(handler, dentry, name, NULL, 0, XATTR_REPLACE);
-}
-
 struct listxattr_buf {
 	struct dir_context ctx;
 	size_t size;
@@ -845,8 +805,10 @@
 			size = handler->list(handler, b->dentry,
 					     b->buf + b->pos, b->size, name,
 					     namelen);
-			if (size > b->size)
+			if (b->pos + size > b->size) {
+				b->pos = -ERANGE;
 				return -ERANGE;
+			}
 		} else {
 			size = handler->list(handler, b->dentry,
 					     NULL, 0, name, namelen);
--- linux-4.4.0.orig/fs/reiserfs/xattr.h
+++ linux-4.4.0/fs/reiserfs/xattr.h
@@ -2,6 +2,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/rwsem.h>
+#include <linux/xattr.h>
 
 struct inode;
 struct dentry;
@@ -18,12 +19,7 @@
 
 #ifdef CONFIG_REISERFS_FS_XATTR
 #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
-ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
-			  void *buffer, size_t size);
-int reiserfs_setxattr(struct dentry *dentry, const char *name,
-		      const void *value, size_t size, int flags);
 ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
-int reiserfs_removexattr(struct dentry *dentry, const char *name);
 
 int reiserfs_xattr_get(struct inode *, const char *, void *, size_t);
 int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int);
@@ -92,10 +88,7 @@
 
 #else
 
-#define reiserfs_getxattr NULL
-#define reiserfs_setxattr NULL
 #define reiserfs_listxattr NULL
-#define reiserfs_removexattr NULL
 
 static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
 {
--- linux-4.4.0.orig/fs/reiserfs/xattr_acl.c
+++ linux-4.4.0/fs/reiserfs/xattr_acl.c
@@ -37,7 +37,14 @@
 	error = journal_begin(&th, inode->i_sb, jcreate_blocks);
 	reiserfs_write_unlock(inode->i_sb);
 	if (error == 0) {
+		if (type == ACL_TYPE_ACCESS && acl) {
+			error = posix_acl_update_mode(inode, &inode->i_mode,
+						      &acl);
+			if (error)
+				goto unlock;
+		}
 		error = __reiserfs_set_acl(&th, inode, type, acl);
+unlock:
 		reiserfs_write_lock(inode->i_sb);
 		error2 = journal_end(&th);
 		reiserfs_write_unlock(inode->i_sb);
@@ -245,15 +252,6 @@
 	switch (type) {
 	case ACL_TYPE_ACCESS:
 		name = POSIX_ACL_XATTR_ACCESS;
-		if (acl) {
-			error = posix_acl_equiv_mode(acl, &inode->i_mode);
-			if (error < 0)
-				return error;
-			else {
-				if (error == 0)
-					acl = NULL;
-			}
-		}
 		break;
 	case ACL_TYPE_DEFAULT:
 		name = POSIX_ACL_XATTR_DEFAULT;
--- linux-4.4.0.orig/fs/reiserfs/xattr_security.c
+++ linux-4.4.0/fs/reiserfs/xattr_security.c
@@ -12,26 +12,24 @@
 security_get(const struct xattr_handler *handler, struct dentry *dentry,
 	     const char *name, void *buffer, size_t size)
 {
-	if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
-		return -EINVAL;
-
 	if (IS_PRIVATE(d_inode(dentry)))
 		return -EPERM;
 
-	return reiserfs_xattr_get(d_inode(dentry), name, buffer, size);
+	return reiserfs_xattr_get(d_inode(dentry),
+				  xattr_full_name(handler, name),
+				  buffer, size);
 }
 
 static int
 security_set(const struct xattr_handler *handler, struct dentry *dentry,
 	     const char *name, const void *buffer, size_t size, int flags)
 {
-	if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
-		return -EINVAL;
-
 	if (IS_PRIVATE(d_inode(dentry)))
 		return -EPERM;
 
-	return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
+	return reiserfs_xattr_set(d_inode(dentry),
+				  xattr_full_name(handler, name),
+				  buffer, size, flags);
 }
 
 static size_t security_list(const struct xattr_handler *handler,
--- linux-4.4.0.orig/fs/reiserfs/xattr_trusted.c
+++ linux-4.4.0/fs/reiserfs/xattr_trusted.c
@@ -11,26 +11,24 @@
 trusted_get(const struct xattr_handler *handler, struct dentry *dentry,
 	    const char *name, void *buffer, size_t size)
 {
-	if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
-		return -EINVAL;
-
 	if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry)))
 		return -EPERM;
 
-	return reiserfs_xattr_get(d_inode(dentry), name, buffer, size);
+	return reiserfs_xattr_get(d_inode(dentry),
+				  xattr_full_name(handler, name),
+				  buffer, size);
 }
 
 static int
 trusted_set(const struct xattr_handler *handler, struct dentry *dentry,
 	    const char *name, const void *buffer, size_t size, int flags)
 {
-	if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
-		return -EINVAL;
-
 	if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry)))
 		return -EPERM;
 
-	return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
+	return reiserfs_xattr_set(d_inode(dentry),
+				  xattr_full_name(handler, name),
+				  buffer, size, flags);
 }
 
 static size_t trusted_list(const struct xattr_handler *handler,
--- linux-4.4.0.orig/fs/reiserfs/xattr_user.c
+++ linux-4.4.0/fs/reiserfs/xattr_user.c
@@ -10,24 +10,22 @@
 user_get(const struct xattr_handler *handler, struct dentry *dentry,
 	 const char *name, void *buffer, size_t size)
 {
-
-	if (strlen(name) < sizeof(XATTR_USER_PREFIX))
-		return -EINVAL;
 	if (!reiserfs_xattrs_user(dentry->d_sb))
 		return -EOPNOTSUPP;
-	return reiserfs_xattr_get(d_inode(dentry), name, buffer, size);
+	return reiserfs_xattr_get(d_inode(dentry),
+				  xattr_full_name(handler, name),
+				  buffer, size);
 }
 
 static int
 user_set(const struct xattr_handler *handler, struct dentry *dentry,
 	 const char *name, const void *buffer, size_t size, int flags)
 {
-	if (strlen(name) < sizeof(XATTR_USER_PREFIX))
-		return -EINVAL;
-
 	if (!reiserfs_xattrs_user(dentry->d_sb))
 		return -EOPNOTSUPP;
-	return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
+	return reiserfs_xattr_set(d_inode(dentry),
+				  xattr_full_name(handler, name),
+				  buffer, size, flags);
 }
 
 static size_t user_list(const struct xattr_handler *handler,
--- linux-4.4.0.orig/fs/romfs/storage.c
+++ linux-4.4.0/fs/romfs/storage.c
@@ -221,10 +221,8 @@
 	size_t limit;
 
 	limit = romfs_maxsize(sb);
-	if (pos >= limit)
+	if (pos >= limit || buflen > limit - pos)
 		return -EIO;
-	if (buflen > limit - pos)
-		buflen = limit - pos;
 
 #ifdef CONFIG_ROMFS_ON_MTD
 	if (sb->s_mtd)
--- linux-4.4.0.orig/fs/romfs/super.c
+++ linux-4.4.0/fs/romfs/super.c
@@ -74,6 +74,7 @@
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/uaccess.h>
+#include <linux/major.h>
 #include "internal.h"
 
 static struct kmem_cache *romfs_inode_cachep;
@@ -415,7 +416,22 @@
 static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
 	struct super_block *sb = dentry->d_sb;
-	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+	u64 id = 0;
+
+	/* When calling huge_encode_dev(),
+	 * use sb->s_bdev->bd_dev when,
+	 *   - CONFIG_ROMFS_ON_BLOCK defined
+	 * use sb->s_dev when,
+	 *   - CONFIG_ROMFS_ON_BLOCK undefined and
+	 *   - CONFIG_ROMFS_ON_MTD defined
+	 * leave id as 0 when,
+	 *   - CONFIG_ROMFS_ON_BLOCK undefined and
+	 *   - CONFIG_ROMFS_ON_MTD undefined
+	 */
+	if (sb->s_bdev)
+		id = huge_encode_dev(sb->s_bdev->bd_dev);
+	else if (sb->s_dev)
+		id = huge_encode_dev(sb->s_dev);
 
 	buf->f_type = ROMFS_MAGIC;
 	buf->f_namelen = ROMFS_MAXFN;
@@ -488,6 +504,11 @@
 	sb->s_flags |= MS_RDONLY | MS_NOATIME;
 	sb->s_op = &romfs_super_ops;
 
+#ifdef CONFIG_ROMFS_ON_MTD
+	/* Use same dev ID from the underlying mtdblock device */
+	if (sb->s_mtd)
+		sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, sb->s_mtd->index);
+#endif
 	/* read the image superblock and check it */
 	rsb = kmalloc(512, GFP_KERNEL);
 	if (!rsb)
--- linux-4.4.0.orig/fs/select.c
+++ linux-4.4.0/fs/select.c
@@ -29,6 +29,7 @@
 #include <linux/sched/rt.h>
 #include <linux/freezer.h>
 #include <net/busy_poll.h>
+#include <linux/vmalloc.h>
 
 #include <asm/uaccess.h>
 
@@ -550,7 +551,7 @@
 	fd_set_bits fds;
 	void *bits;
 	int ret, max_fds;
-	unsigned int size;
+	size_t size, alloc_size;
 	struct fdtable *fdt;
 	/* Allocate small arguments on the stack to save memory and be faster */
 	long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
@@ -577,7 +578,14 @@
 	if (size > sizeof(stack_fds) / 6) {
 		/* Not enough space in on-stack array; must use kmalloc */
 		ret = -ENOMEM;
-		bits = kmalloc(6 * size, GFP_KERNEL);
+		if (size > (SIZE_MAX / 6))
+			goto out_nofds;
+
+		alloc_size = 6 * size;
+		bits = kmalloc(alloc_size, GFP_KERNEL|__GFP_NOWARN);
+		if (!bits && alloc_size > PAGE_SIZE)
+			bits = vmalloc(alloc_size);
+
 		if (!bits)
 			goto out_nofds;
 	}
@@ -614,7 +622,7 @@
 
 out:
 	if (bits != stack_fds)
-		kfree(bits);
+		kvfree(bits);
 out_nofds:
 	return ret;
 }
--- linux-4.4.0.orig/fs/seq_file.c
+++ linux-4.4.0/fs/seq_file.c
@@ -14,6 +14,7 @@
 #include <linux/mm.h>
 #include <linux/printk.h>
 #include <linux/string_helpers.h>
+#include <linux/pagemap.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -28,6 +29,9 @@
 	void *buf;
 	gfp_t gfp = GFP_KERNEL;
 
+	if (unlikely(size > MAX_RW_COUNT))
+		return NULL;
+
 	/*
 	 * For high order allocations, use __GFP_NORETRY to avoid oom-killing -
 	 * it's better to fall back to vmalloc() than to kill things.  For small
@@ -72,9 +76,10 @@
 
 	mutex_init(&p->lock);
 	p->op = op;
-#ifdef CONFIG_USER_NS
-	p->user_ns = file->f_cred->user_ns;
-#endif
+
+	// No refcounting: the lifetime of 'p' is constrained
+	// to the lifetime of the file.
+	p->file = file;
 
 	/*
 	 * Wrappers around seq_open(e.g. swaps_open) need to be
@@ -222,8 +227,10 @@
 		size -= n;
 		buf += n;
 		copied += n;
-		if (!m->count)
+		if (!m->count) {
+			m->from = 0;
 			m->index++;
+		}
 		if (!size)
 			goto Done;
 	}
--- linux-4.4.0.orig/fs/splice.c
+++ linux-4.4.0/fs/splice.c
@@ -185,6 +185,9 @@
 	unsigned int spd_pages = spd->nr_pages;
 	int ret, do_wakeup, page_nr;
 
+	if (!spd_pages)
+		return 0;
+
 	ret = 0;
 	do_wakeup = 0;
 	page_nr = 0;
@@ -208,6 +211,7 @@
 			buf->len = spd->partial[page_nr].len;
 			buf->private = spd->partial[page_nr].private;
 			buf->ops = spd->ops;
+			buf->flags = 0;
 			if (spd->flags & SPLICE_F_GIFT)
 				buf->flags |= PIPE_BUF_FLAG_GIFT;
 
@@ -1110,8 +1114,8 @@
 /*
  * Attempt to initiate a splice from pipe to file.
  */
-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
-			   loff_t *ppos, size_t len, unsigned int flags)
+long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+		    loff_t *ppos, size_t len, unsigned int flags)
 {
 	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
 				loff_t *, size_t, unsigned int);
@@ -1123,13 +1127,14 @@
 
 	return splice_write(pipe, out, ppos, len, flags);
 }
+EXPORT_SYMBOL(do_splice_from);
 
 /*
  * Attempt to initiate a splice from a file to a pipe.
  */
-static long do_splice_to(struct file *in, loff_t *ppos,
-			 struct pipe_inode_info *pipe, size_t len,
-			 unsigned int flags)
+long do_splice_to(struct file *in, loff_t *ppos,
+		  struct pipe_inode_info *pipe, size_t len,
+		  unsigned int flags)
 {
 	ssize_t (*splice_read)(struct file *, loff_t *,
 			       struct pipe_inode_info *, size_t, unsigned int);
@@ -1149,6 +1154,7 @@
 
 	return splice_read(in, ppos, pipe, len, flags);
 }
+EXPORT_SYMBOL(do_splice_to);
 
 /**
  * splice_direct_to_actor - splices data directly between two non-pipes
@@ -1872,7 +1878,11 @@
 			 * Get a reference to this pipe buffer,
 			 * so we can copy the contents over.
 			 */
-			ibuf->ops->get(ipipe, ibuf);
+			if (!pipe_buf_get(ipipe, ibuf)) {
+				if (ret == 0)
+					ret = -EFAULT;
+				break;
+			}
 			*obuf = *ibuf;
 
 			/*
@@ -1944,7 +1954,11 @@
 		 * Get a reference to this pipe buffer,
 		 * so we can copy the contents over.
 		 */
-		ibuf->ops->get(ipipe, ibuf);
+		if (!pipe_buf_get(ipipe, ibuf)) {
+			if (ret == 0)
+				ret = -EFAULT;
+			break;
+		}
 
 		obuf = opipe->bufs + nbuf;
 		*obuf = *ibuf;
--- linux-4.4.0.orig/fs/squashfs/block.c
+++ linux-4.4.0/fs/squashfs/block.c
@@ -166,6 +166,8 @@
 	}
 
 	if (compressed) {
+		if (!msblk->stream)
+			goto read_failure;
 		length = squashfs_decompress(msblk, bh, b, offset, length,
 			output);
 		if (length < 0)
--- linux-4.4.0.orig/fs/squashfs/cache.c
+++ linux-4.4.0/fs/squashfs/cache.c
@@ -350,6 +350,9 @@
 
 	TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset);
 
+	if (unlikely(length < 0))
+		return -EIO;
+
 	while (length) {
 		entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
 		if (entry->error) {
--- linux-4.4.0.orig/fs/squashfs/export.c
+++ linux-4.4.0/fs/squashfs/export.c
@@ -54,12 +54,17 @@
 	struct squashfs_sb_info *msblk = sb->s_fs_info;
 	int blk = SQUASHFS_LOOKUP_BLOCK(ino_num - 1);
 	int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino_num - 1);
-	u64 start = le64_to_cpu(msblk->inode_lookup_table[blk]);
+	u64 start;
 	__le64 ino;
 	int err;
 
 	TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino_num);
 
+	if (ino_num == 0 || (ino_num - 1) >= msblk->inodes)
+		return -EINVAL;
+
+	start = le64_to_cpu(msblk->inode_lookup_table[blk]);
+
 	err = squashfs_read_metadata(sb, &ino, &start, &offset, sizeof(ino));
 	if (err < 0)
 		return err;
@@ -124,7 +129,10 @@
 		u64 lookup_table_start, u64 next_table, unsigned int inodes)
 {
 	unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes);
+	unsigned int indexes = SQUASHFS_LOOKUP_BLOCKS(inodes);
+	int n;
 	__le64 *table;
+	u64 start, end;
 
 	TRACE("In read_inode_lookup_table, length %d\n", length);
 
@@ -134,20 +142,37 @@
 	if (inodes == 0)
 		return ERR_PTR(-EINVAL);
 
-	/* length bytes should not extend into the next table - this check
-	 * also traps instances where lookup_table_start is incorrectly larger
-	 * than the next table start
+	/*
+	 * The computed size of the lookup table (length bytes) should exactly
+	 * match the table start and end points
 	 */
-	if (lookup_table_start + length > next_table)
+	if (length != (next_table - lookup_table_start))
 		return ERR_PTR(-EINVAL);
 
 	table = squashfs_read_table(sb, lookup_table_start, length);
+	if (IS_ERR(table))
+		return table;
 
 	/*
-	 * table[0] points to the first inode lookup table metadata block,
-	 * this should be less than lookup_table_start
+	 * table0], table[1], ... table[indexes - 1] store the locations
+	 * of the compressed inode lookup blocks.  Each entry should be
+	 * less than the next (i.e. table[0] < table[1]), and the difference
+	 * between them should be SQUASHFS_METADATA_SIZE or less.
+	 * table[indexes - 1] should  be less than lookup_table_start, and
+	 * again the difference should be SQUASHFS_METADATA_SIZE or less
 	 */
-	if (!IS_ERR(table) && le64_to_cpu(table[0]) >= lookup_table_start) {
+	for (n = 0; n < (indexes - 1); n++) {
+		start = le64_to_cpu(table[n]);
+		end = le64_to_cpu(table[n + 1]);
+
+		if (start >= end || (end - start) > SQUASHFS_METADATA_SIZE) {
+			kfree(table);
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	start = le64_to_cpu(table[indexes - 1]);
+	if (start >= lookup_table_start || (lookup_table_start - start) > SQUASHFS_METADATA_SIZE) {
 		kfree(table);
 		return ERR_PTR(-EINVAL);
 	}
--- linux-4.4.0.orig/fs/squashfs/file.c
+++ linux-4.4.0/fs/squashfs/file.c
@@ -194,7 +194,11 @@
 		}
 
 		for (i = 0; i < blocks; i++) {
-			int size = le32_to_cpu(blist[i]);
+			int size = squashfs_block_size(blist[i]);
+			if (size < 0) {
+				err = size;
+				goto failure;
+			}
 			block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
 		}
 		n -= blocks;
@@ -367,7 +371,24 @@
 			sizeof(size));
 	if (res < 0)
 		return res;
-	return le32_to_cpu(size);
+	return squashfs_block_size(size);
+}
+
+void squashfs_fill_page(struct page *page, struct squashfs_cache_entry *buffer, int offset, int avail)
+{
+	int copied;
+	void *pageaddr;
+
+	pageaddr = kmap_atomic(page);
+	copied = squashfs_copy_data(pageaddr, buffer, offset, avail);
+	memset(pageaddr + copied, 0, PAGE_CACHE_SIZE - copied);
+	kunmap_atomic(pageaddr);
+
+	flush_dcache_page(page);
+	if (copied == avail)
+		SetPageUptodate(page);
+	else
+		SetPageError(page);
 }
 
 /* Copy data into page cache  */
@@ -376,7 +397,6 @@
 {
 	struct inode *inode = page->mapping->host;
 	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
-	void *pageaddr;
 	int i, mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1;
 	int start_index = page->index & ~mask, end_index = start_index | mask;
 
@@ -402,12 +422,7 @@
 		if (PageUptodate(push_page))
 			goto skip_page;
 
-		pageaddr = kmap_atomic(push_page);
-		squashfs_copy_data(pageaddr, buffer, offset, avail);
-		memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
-		kunmap_atomic(pageaddr);
-		flush_dcache_page(push_page);
-		SetPageUptodate(push_page);
+		squashfs_fill_page(push_page, buffer, offset, avail);
 skip_page:
 		unlock_page(push_page);
 		if (i != page->index)
@@ -416,10 +431,9 @@
 }
 
 /* Read datablock stored packed inside a fragment (tail-end packed block) */
-static int squashfs_readpage_fragment(struct page *page)
+static int squashfs_readpage_fragment(struct page *page, int expected)
 {
 	struct inode *inode = page->mapping->host;
-	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
 	struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb,
 		squashfs_i(inode)->fragment_block,
 		squashfs_i(inode)->fragment_size);
@@ -430,23 +444,16 @@
 			squashfs_i(inode)->fragment_block,
 			squashfs_i(inode)->fragment_size);
 	else
-		squashfs_copy_cache(page, buffer, i_size_read(inode) &
-			(msblk->block_size - 1),
+		squashfs_copy_cache(page, buffer, expected,
 			squashfs_i(inode)->fragment_offset);
 
 	squashfs_cache_put(buffer);
 	return res;
 }
 
-static int squashfs_readpage_sparse(struct page *page, int index, int file_end)
+static int squashfs_readpage_sparse(struct page *page, int expected)
 {
-	struct inode *inode = page->mapping->host;
-	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
-	int bytes = index == file_end ?
-			(i_size_read(inode) & (msblk->block_size - 1)) :
-			 msblk->block_size;
-
-	squashfs_copy_cache(page, NULL, bytes, 0);
+	squashfs_copy_cache(page, NULL, expected, 0);
 	return 0;
 }
 
@@ -456,6 +463,9 @@
 	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
 	int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT);
 	int file_end = i_size_read(inode) >> msblk->block_log;
+	int expected = index == file_end ?
+			(i_size_read(inode) & (msblk->block_size - 1)) :
+			 msblk->block_size;
 	int res;
 	void *pageaddr;
 
@@ -474,11 +484,11 @@
 			goto error_out;
 
 		if (bsize == 0)
-			res = squashfs_readpage_sparse(page, index, file_end);
+			res = squashfs_readpage_sparse(page, expected);
 		else
-			res = squashfs_readpage_block(page, block, bsize);
+			res = squashfs_readpage_block(page, block, bsize, expected);
 	} else
-		res = squashfs_readpage_fragment(page);
+		res = squashfs_readpage_fragment(page, expected);
 
 	if (!res)
 		return 0;
--- linux-4.4.0.orig/fs/squashfs/file_cache.c
+++ linux-4.4.0/fs/squashfs/file_cache.c
@@ -20,7 +20,7 @@
 #include "squashfs.h"
 
 /* Read separately compressed datablock and memcopy into page cache */
-int squashfs_readpage_block(struct page *page, u64 block, int bsize)
+int squashfs_readpage_block(struct page *page, u64 block, int bsize, int expected)
 {
 	struct inode *i = page->mapping->host;
 	struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
@@ -31,7 +31,7 @@
 		ERROR("Unable to read page, block %llx, size %x\n", block,
 			bsize);
 	else
-		squashfs_copy_cache(page, buffer, buffer->length, 0);
+		squashfs_copy_cache(page, buffer, expected, 0);
 
 	squashfs_cache_put(buffer);
 	return res;
--- linux-4.4.0.orig/fs/squashfs/file_direct.c
+++ linux-4.4.0/fs/squashfs/file_direct.c
@@ -21,10 +21,11 @@
 #include "page_actor.h"
 
 static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
-	int pages, struct page **page);
+	int pages, struct page **page, int bytes);
 
 /* Read separately compressed datablock directly into page cache */
-int squashfs_readpage_block(struct page *target_page, u64 block, int bsize)
+int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
+	int expected)
 
 {
 	struct inode *inode = target_page->mapping->host;
@@ -83,7 +84,7 @@
 		 * using an intermediate buffer.
 		 */
 		res = squashfs_read_cache(target_page, block, bsize, pages,
-								page);
+							page, expected);
 		if (res < 0)
 			goto mark_errored;
 
@@ -95,6 +96,11 @@
 	if (res < 0)
 		goto mark_errored;
 
+	if (res != expected) {
+		res = -EIO;
+		goto mark_errored;
+	}
+
 	/* Last page may have trailing bytes not filled */
 	bytes = res % PAGE_CACHE_SIZE;
 	if (bytes) {
@@ -138,13 +144,12 @@
 
 
 static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
-	int pages, struct page **page)
+	int pages, struct page **page, int bytes)
 {
 	struct inode *i = target_page->mapping->host;
 	struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
 						 block, bsize);
-	int bytes = buffer->length, res = buffer->error, n, offset = 0;
-	void *pageaddr;
+	int res = buffer->error, n, offset = 0;
 
 	if (res) {
 		ERROR("Unable to read page, block %llx, size %x\n", block,
@@ -159,12 +164,7 @@
 		if (page[n] == NULL)
 			continue;
 
-		pageaddr = kmap_atomic(page[n]);
-		squashfs_copy_data(pageaddr, buffer, offset, avail);
-		memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
-		kunmap_atomic(pageaddr);
-		flush_dcache_page(page[n]);
-		SetPageUptodate(page[n]);
+		squashfs_fill_page(page[n], buffer, offset, avail);
 		unlock_page(page[n]);
 		if (page[n] != target_page)
 			page_cache_release(page[n]);
--- linux-4.4.0.orig/fs/squashfs/fragment.c
+++ linux-4.4.0/fs/squashfs/fragment.c
@@ -49,11 +49,16 @@
 				u64 *fragment_block)
 {
 	struct squashfs_sb_info *msblk = sb->s_fs_info;
-	int block = SQUASHFS_FRAGMENT_INDEX(fragment);
-	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
-	u64 start_block = le64_to_cpu(msblk->fragment_index[block]);
+	int block, offset, size;
 	struct squashfs_fragment_entry fragment_entry;
-	int size;
+	u64 start_block;
+
+	if (fragment >= msblk->fragments)
+		return -EIO;
+	block = SQUASHFS_FRAGMENT_INDEX(fragment);
+	offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
+
+	start_block = le64_to_cpu(msblk->fragment_index[block]);
 
 	size = squashfs_read_metadata(sb, &fragment_entry, &start_block,
 					&offset, sizeof(fragment_entry));
@@ -61,9 +66,7 @@
 		return size;
 
 	*fragment_block = le64_to_cpu(fragment_entry.start_block);
-	size = le32_to_cpu(fragment_entry.size);
-
-	return size;
+	return squashfs_block_size(fragment_entry.size);
 }
 
 
--- linux-4.4.0.orig/fs/squashfs/id.c
+++ linux-4.4.0/fs/squashfs/id.c
@@ -48,10 +48,15 @@
 	struct squashfs_sb_info *msblk = sb->s_fs_info;
 	int block = SQUASHFS_ID_BLOCK(index);
 	int offset = SQUASHFS_ID_BLOCK_OFFSET(index);
-	u64 start_block = le64_to_cpu(msblk->id_table[block]);
+	u64 start_block;
 	__le32 disk_id;
 	int err;
 
+	if (index >= msblk->ids)
+		return -EINVAL;
+
+	start_block = le64_to_cpu(msblk->id_table[block]);
+
 	err = squashfs_read_metadata(sb, &disk_id, &start_block, &offset,
 							sizeof(disk_id));
 	if (err < 0)
@@ -69,7 +74,10 @@
 		u64 id_table_start, u64 next_table, unsigned short no_ids)
 {
 	unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids);
+	unsigned int indexes = SQUASHFS_ID_BLOCKS(no_ids);
+	int n;
 	__le64 *table;
+	u64 start, end;
 
 	TRACE("In read_id_index_table, length %d\n", length);
 
@@ -80,20 +88,36 @@
 		return ERR_PTR(-EINVAL);
 
 	/*
-	 * length bytes should not extend into the next table - this check
-	 * also traps instances where id_table_start is incorrectly larger
-	 * than the next table start
+	 * The computed size of the index table (length bytes) should exactly
+	 * match the table start and end points
 	 */
-	if (id_table_start + length > next_table)
+	if (length != (next_table - id_table_start))
 		return ERR_PTR(-EINVAL);
 
 	table = squashfs_read_table(sb, id_table_start, length);
+	if (IS_ERR(table))
+		return table;
 
 	/*
-	 * table[0] points to the first id lookup table metadata block, this
-	 * should be less than id_table_start
+	 * table[0], table[1], ... table[indexes - 1] store the locations
+	 * of the compressed id blocks.   Each entry should be less than
+	 * the next (i.e. table[0] < table[1]), and the difference between them
+	 * should be SQUASHFS_METADATA_SIZE or less.  table[indexes - 1]
+	 * should be less than id_table_start, and again the difference
+	 * should be SQUASHFS_METADATA_SIZE or less
 	 */
-	if (!IS_ERR(table) && le64_to_cpu(table[0]) >= id_table_start) {
+	for (n = 0; n < (indexes - 1); n++) {
+		start = le64_to_cpu(table[n]);
+		end = le64_to_cpu(table[n + 1]);
+
+		if (start >= end || (end - start) > SQUASHFS_METADATA_SIZE) {
+			kfree(table);
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	start = le64_to_cpu(table[indexes - 1]);
+	if (start >= id_table_start || (id_table_start - start) > SQUASHFS_METADATA_SIZE) {
 		kfree(table);
 		return ERR_PTR(-EINVAL);
 	}
--- linux-4.4.0.orig/fs/squashfs/squashfs.h
+++ linux-4.4.0/fs/squashfs/squashfs.h
@@ -67,11 +67,12 @@
 				u64, u64, unsigned int);
 
 /* file.c */
+void squashfs_fill_page(struct page *, struct squashfs_cache_entry *, int, int);
 void squashfs_copy_cache(struct page *, struct squashfs_cache_entry *, int,
 				int);
 
 /* file_xxx.c */
-extern int squashfs_readpage_block(struct page *, u64, int);
+extern int squashfs_readpage_block(struct page *, u64, int, int);
 
 /* id.c */
 extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);
--- linux-4.4.0.orig/fs/squashfs/squashfs_fs.h
+++ linux-4.4.0/fs/squashfs/squashfs_fs.h
@@ -129,6 +129,12 @@
 
 #define SQUASHFS_COMPRESSED_BLOCK(B)	(!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
 
+static inline int squashfs_block_size(__le32 raw)
+{
+	u32 size = le32_to_cpu(raw);
+	return (size >> 25) ? -EIO : size;
+}
+
 /*
  * Inode number ops.  Inodes consist of a compressed block number, and an
  * uncompressed offset within that block
--- linux-4.4.0.orig/fs/squashfs/squashfs_fs_sb.h
+++ linux-4.4.0/fs/squashfs/squashfs_fs_sb.h
@@ -75,6 +75,8 @@
 	unsigned short				block_log;
 	long long				bytes_used;
 	unsigned int				inodes;
+	unsigned int				fragments;
 	int					xattr_ids;
+	unsigned int				ids;
 };
 #endif
--- linux-4.4.0.orig/fs/squashfs/super.c
+++ linux-4.4.0/fs/squashfs/super.c
@@ -176,6 +176,8 @@
 	msblk->inode_table = le64_to_cpu(sblk->inode_table_start);
 	msblk->directory_table = le64_to_cpu(sblk->directory_table_start);
 	msblk->inodes = le32_to_cpu(sblk->inodes);
+	msblk->fragments = le32_to_cpu(sblk->fragments);
+	msblk->ids = le16_to_cpu(sblk->no_ids);
 	flags = le16_to_cpu(sblk->flags);
 
 	TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b));
@@ -186,8 +188,8 @@
 	TRACE("Filesystem size %lld bytes\n", msblk->bytes_used);
 	TRACE("Block size %d\n", msblk->block_size);
 	TRACE("Number of inodes %d\n", msblk->inodes);
-	TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments));
-	TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids));
+	TRACE("Number of fragments %d\n", msblk->fragments);
+	TRACE("Number of ids %d\n", msblk->ids);
 	TRACE("sblk->inode_table_start %llx\n", msblk->inode_table);
 	TRACE("sblk->directory_table_start %llx\n", msblk->directory_table);
 	TRACE("sblk->fragment_table_start %llx\n",
@@ -244,8 +246,7 @@
 allocate_id_index_table:
 	/* Allocate and read id index table */
 	msblk->id_table = squashfs_read_id_index_table(sb,
-		le64_to_cpu(sblk->id_table_start), next_table,
-		le16_to_cpu(sblk->no_ids));
+		le64_to_cpu(sblk->id_table_start), next_table, msblk->ids);
 	if (IS_ERR(msblk->id_table)) {
 		ERROR("unable to read id index table\n");
 		err = PTR_ERR(msblk->id_table);
@@ -273,7 +274,7 @@
 	sb->s_export_op = &squashfs_export_ops;
 
 handle_fragments:
-	fragments = le32_to_cpu(sblk->fragments);
+	fragments = msblk->fragments;
 	if (fragments == 0)
 		goto check_directory_table;
 
--- linux-4.4.0.orig/fs/squashfs/xattr.h
+++ linux-4.4.0/fs/squashfs/xattr.h
@@ -30,8 +30,16 @@
 static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb,
 		u64 start, u64 *xattr_table_start, int *xattr_ids)
 {
+	struct squashfs_xattr_id_table *id_table;
+
+	id_table = squashfs_read_table(sb, start, sizeof(*id_table));
+	if (IS_ERR(id_table))
+		return (__le64 *) id_table;
+
+	*xattr_table_start = le64_to_cpu(id_table->xattr_table_start);
+	kfree(id_table);
+
 	ERROR("Xattrs in filesystem, these will be ignored\n");
-	*xattr_table_start = start;
 	return ERR_PTR(-ENOTSUPP);
 }
 
--- linux-4.4.0.orig/fs/squashfs/xattr_id.c
+++ linux-4.4.0/fs/squashfs/xattr_id.c
@@ -44,10 +44,15 @@
 	struct squashfs_sb_info *msblk = sb->s_fs_info;
 	int block = SQUASHFS_XATTR_BLOCK(index);
 	int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index);
-	u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]);
+	u64 start_block;
 	struct squashfs_xattr_id id;
 	int err;
 
+	if (index >= msblk->xattr_ids)
+		return -EINVAL;
+
+	start_block = le64_to_cpu(msblk->xattr_id_table[block]);
+
 	err = squashfs_read_metadata(sb, &id, &start_block, &offset,
 							sizeof(id));
 	if (err < 0)
@@ -63,13 +68,17 @@
 /*
  * Read uncompressed xattr id lookup table indexes from disk into memory
  */
-__le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start,
+__le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 table_start,
 		u64 *xattr_table_start, int *xattr_ids)
 {
-	unsigned int len;
+	struct squashfs_sb_info *msblk = sb->s_fs_info;
+	unsigned int len, indexes;
 	struct squashfs_xattr_id_table *id_table;
+	__le64 *table;
+	u64 start, end;
+	int n;
 
-	id_table = squashfs_read_table(sb, start, sizeof(*id_table));
+	id_table = squashfs_read_table(sb, table_start, sizeof(*id_table));
 	if (IS_ERR(id_table))
 		return (__le64 *) id_table;
 
@@ -83,13 +92,52 @@
 	if (*xattr_ids == 0)
 		return ERR_PTR(-EINVAL);
 
-	/* xattr_table should be less than start */
-	if (*xattr_table_start >= start)
+	len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
+	indexes = SQUASHFS_XATTR_BLOCKS(*xattr_ids);
+
+	/*
+	 * The computed size of the index table (len bytes) should exactly
+	 * match the table start and end points
+	 */
+	start = table_start + sizeof(*id_table);
+	end = msblk->bytes_used;
+
+	if (len != (end - start))
 		return ERR_PTR(-EINVAL);
 
-	len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
+	table = squashfs_read_table(sb, start, len);
+	if (IS_ERR(table))
+		return table;
+
+	/* table[0], table[1], ... table[indexes - 1] store the locations
+	 * of the compressed xattr id blocks.  Each entry should be less than
+	 * the next (i.e. table[0] < table[1]), and the difference between them
+	 * should be SQUASHFS_METADATA_SIZE or less.  table[indexes - 1]
+	 * should be less than table_start, and again the difference
+	 * shouls be SQUASHFS_METADATA_SIZE or less.
+	 *
+	 * Finally xattr_table_start should be less than table[0].
+	 */
+	for (n = 0; n < (indexes - 1); n++) {
+		start = le64_to_cpu(table[n]);
+		end = le64_to_cpu(table[n + 1]);
+
+		if (start >= end || (end - start) > SQUASHFS_METADATA_SIZE) {
+			kfree(table);
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	start = le64_to_cpu(table[indexes - 1]);
+	if (start >= table_start || (table_start - start) > SQUASHFS_METADATA_SIZE) {
+		kfree(table);
+		return ERR_PTR(-EINVAL);
+	}
 
-	TRACE("In read_xattr_index_table, length %d\n", len);
+	if (*xattr_table_start >= le64_to_cpu(table[0])) {
+		kfree(table);
+		return ERR_PTR(-EINVAL);
+	}
 
-	return squashfs_read_table(sb, start + sizeof(*id_table), len);
+	return table;
 }
--- linux-4.4.0.orig/fs/stat.c
+++ linux-4.4.0/fs/stat.c
@@ -31,7 +31,7 @@
 	stat->atime = inode->i_atime;
 	stat->mtime = inode->i_mtime;
 	stat->ctime = inode->i_ctime;
-	stat->blksize = (1 << inode->i_blkbits);
+	stat->blksize = i_blocksize(inode);
 	stat->blocks = inode->i_blocks;
 }
 
@@ -454,6 +454,7 @@
 		inode->i_bytes -= 512;
 	}
 }
+EXPORT_SYMBOL(__inode_add_bytes);
 
 void inode_add_bytes(struct inode *inode, loff_t bytes)
 {
--- linux-4.4.0.orig/fs/super.c
+++ linux-4.4.0/fs/super.c
@@ -33,6 +33,7 @@
 #include <linux/cleancache.h>
 #include <linux/fsnotify.h>
 #include <linux/lockdep.h>
+#include <linux/user_namespace.h>
 #include "internal.h"
 
 
@@ -118,13 +119,23 @@
 	sb = container_of(shrink, struct super_block, s_shrink);
 
 	/*
-	 * Don't call trylock_super as it is a potential
-	 * scalability bottleneck. The counts could get updated
-	 * between super_cache_count and super_cache_scan anyway.
-	 * Call to super_cache_count with shrinker_rwsem held
-	 * ensures the safety of call to list_lru_shrink_count() and
-	 * s_op->nr_cached_objects().
+	 * We don't call trylock_super() here as it is a scalability bottleneck,
+	 * so we're exposed to partial setup state. The shrinker rwsem does not
+	 * protect filesystem operations backing list_lru_shrink_count() or
+	 * s_op->nr_cached_objects(). Counts can change between
+	 * super_cache_count and super_cache_scan, so we really don't need locks
+	 * here.
+	 *
+	 * However, if we are currently mounting the superblock, the underlying
+	 * filesystem might be in a state of partial construction and hence it
+	 * is dangerous to access it.  trylock_super() uses a MS_BORN check to
+	 * avoid this situation, so do the same here. The memory barrier is
+	 * matched with the one in mount_fs() as we don't hold locks here.
 	 */
+	if (!(sb->s_flags & MS_BORN))
+		return 0;
+	smp_rmb();
+
 	if (sb->s_op && sb->s_op->nr_cached_objects)
 		total_objects = sb->s_op->nr_cached_objects(sb, sc);
 
@@ -165,6 +176,7 @@
 	list_lru_destroy(&s->s_inode_lru);
 	security_sb_free(s);
 	WARN_ON(!list_empty(&s->s_mounts));
+	put_user_ns(s->s_user_ns);
 	kfree(s->s_subtype);
 	kfree(s->s_options);
 	call_rcu(&s->rcu, destroy_super_rcu);
@@ -174,11 +186,13 @@
  *	alloc_super	-	create new superblock
  *	@type:	filesystem type superblock should belong to
  *	@flags: the mount flags
+ *	@user_ns: User namespace for the super_block
  *
  *	Allocates and initializes a new &struct super_block.  alloc_super()
  *	returns a pointer new superblock or %NULL if allocation had failed.
  */
-static struct super_block *alloc_super(struct file_system_type *type, int flags)
+static struct super_block *alloc_super(struct file_system_type *type, int flags,
+				       struct user_namespace *user_ns)
 {
 	struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);
 	static const struct super_operations default_op;
@@ -188,6 +202,7 @@
 		return NULL;
 
 	INIT_LIST_HEAD(&s->s_mounts);
+	s->s_user_ns = get_user_ns(user_ns);
 
 	if (security_sb_alloc(s))
 		goto fail;
@@ -415,6 +430,7 @@
 		sb->s_flags &= ~MS_ACTIVE;
 
 		fsnotify_unmount_inodes(sb);
+		cgroup_writeback_umount();
 
 		evict_inodes(sb);
 
@@ -442,29 +458,42 @@
 EXPORT_SYMBOL(generic_shutdown_super);
 
 /**
- *	sget	-	find or create a superblock
+ *	sget_userns -	find or create a superblock
  *	@type:	filesystem type superblock should belong to
  *	@test:	comparison callback
  *	@set:	setup callback
  *	@flags:	mount flags
+ *	@user_ns: User namespace for the super_block
  *	@data:	argument to each of them
  */
-struct super_block *sget(struct file_system_type *type,
+struct super_block *sget_userns(struct file_system_type *type,
 			int (*test)(struct super_block *,void *),
 			int (*set)(struct super_block *,void *),
-			int flags,
+			int flags, struct user_namespace *user_ns,
 			void *data)
 {
 	struct super_block *s = NULL;
 	struct super_block *old;
 	int err;
 
+	if (!(flags & (MS_KERNMOUNT|MS_SUBMOUNT)) &&
+	    !(type->fs_flags & FS_USERNS_MOUNT) &&
+	    !capable(CAP_SYS_ADMIN))
+		return ERR_PTR(-EPERM);
 retry:
 	spin_lock(&sb_lock);
 	if (test) {
 		hlist_for_each_entry(old, &type->fs_supers, s_instances) {
 			if (!test(old, data))
 				continue;
+			if (user_ns != old->s_user_ns) {
+				spin_unlock(&sb_lock);
+				if (s) {
+					up_write(&s->s_umount);
+					destroy_super(s);
+				}
+				return ERR_PTR(-EBUSY);
+			}
 			if (!grab_super(old))
 				goto retry;
 			if (s) {
@@ -477,7 +506,7 @@
 	}
 	if (!s) {
 		spin_unlock(&sb_lock);
-		s = alloc_super(type, flags);
+		s = alloc_super(type, (flags & ~MS_SUBMOUNT), user_ns);
 		if (!s)
 			return ERR_PTR(-ENOMEM);
 		goto retry;
@@ -496,10 +525,46 @@
 	hlist_add_head(&s->s_instances, &type->fs_supers);
 	spin_unlock(&sb_lock);
 	get_filesystem(type);
-	register_shrinker(&s->s_shrink);
+	err = register_shrinker(&s->s_shrink);
+	if (err) {
+		deactivate_locked_super(s);
+		s = ERR_PTR(err);
+	}
 	return s;
 }
 
+EXPORT_SYMBOL(sget_userns);
+
+/**
+ *	sget	-	find or create a superblock
+ *	@type:	  filesystem type superblock should belong to
+ *	@test:	  comparison callback
+ *	@set:	  setup callback
+ *	@flags:	  mount flags
+ *	@data:	  argument to each of them
+ */
+struct super_block *sget(struct file_system_type *type,
+			int (*test)(struct super_block *,void *),
+			int (*set)(struct super_block *,void *),
+			int flags,
+			void *data)
+{
+	struct user_namespace *user_ns = current_user_ns();
+
+	/* We don't yet pass the user namespace of the parent
+	 * mount through to here so always use &init_user_ns
+	 * until that changes.
+	 */
+	if (flags & MS_SUBMOUNT)
+		user_ns = &init_user_ns;
+
+	/* Ensure the requestor has permissions over the target filesystem */
+	if (!(flags & (MS_KERNMOUNT|MS_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN))
+		return ERR_PTR(-EPERM);
+
+	return sget_userns(type, test, set, flags, user_ns, data);
+}
+
 EXPORT_SYMBOL(sget);
 
 void drop_super(struct super_block *sb)
@@ -917,12 +982,20 @@
 	return set_anon_super(sb, NULL);
 }
 
-struct dentry *mount_ns(struct file_system_type *fs_type, int flags,
-	void *data, int (*fill_super)(struct super_block *, void *, int))
+struct dentry *mount_ns(struct file_system_type *fs_type,
+	int flags, void *data, void *ns, struct user_namespace *user_ns,
+	int (*fill_super)(struct super_block *, void *, int))
 {
 	struct super_block *sb;
 
-	sb = sget(fs_type, ns_test_super, ns_set_super, flags, data);
+	/* Don't allow mounting unless the caller has CAP_SYS_ADMIN
+	 * over the namespace.
+	 */
+	if (!(flags & MS_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN))
+		return ERR_PTR(-EPERM);
+
+	sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags,
+			 user_ns, ns);
 	if (IS_ERR(sb))
 		return ERR_CAST(sb);
 
@@ -952,7 +1025,7 @@
 	 * We set the bdi here to the queue backing, file systems can
 	 * overwrite this in ->fill_super()
 	 */
-	s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+	s->s_bdi = bdev_get_queue(s->s_bdev)->backing_dev_info;
 	return 0;
 }
 
@@ -977,6 +1050,23 @@
 	if (IS_ERR(bdev))
 		return ERR_CAST(bdev);
 
+	if (current_user_ns() != &init_user_ns) {
+		/*
+		 * For userns mounts, disallow mounting if bdev is open for
+		 * writing
+		 */
+		if (!atomic_dec_unless_positive(&bdev->bd_inode->i_writecount)) {
+			error = -EBUSY;
+			goto error_bdev;
+		}
+		if (bdev->bd_contains != bdev &&
+		    !atomic_dec_unless_positive(&bdev->bd_contains->bd_inode->i_writecount)) {
+			atomic_inc(&bdev->bd_inode->i_writecount);
+			error = -EBUSY;
+			goto error_bdev;
+		}
+	}
+
 	/*
 	 * once the super is inserted into the list by sget, s_umount
 	 * will protect the lockfs code from trying to start a snapshot
@@ -986,7 +1076,7 @@
 	if (bdev->bd_fsfreeze_count > 0) {
 		mutex_unlock(&bdev->bd_fsfreeze_mutex);
 		error = -EBUSY;
-		goto error_bdev;
+		goto error_inc;
 	}
 	s = sget(fs_type, test_bdev_super, set_bdev_super, flags | MS_NOSEC,
 		 bdev);
@@ -998,7 +1088,7 @@
 		if ((flags ^ s->s_flags) & MS_RDONLY) {
 			deactivate_locked_super(s);
 			error = -EBUSY;
-			goto error_bdev;
+			goto error_inc;
 		}
 
 		/*
@@ -1031,6 +1121,12 @@
 
 error_s:
 	error = PTR_ERR(s);
+error_inc:
+	if (current_user_ns() != &init_user_ns) {
+		atomic_inc(&bdev->bd_inode->i_writecount);
+		if (bdev->bd_contains != bdev)
+			atomic_inc(&bdev->bd_contains->bd_inode->i_writecount);
+	}
 error_bdev:
 	blkdev_put(bdev, mode);
 error:
@@ -1047,6 +1143,11 @@
 	generic_shutdown_super(sb);
 	sync_blockdev(bdev);
 	WARN_ON_ONCE(!(mode & FMODE_EXCL));
+	if (sb->s_user_ns != &init_user_ns) {
+		atomic_inc(&bdev->bd_inode->i_writecount);
+		if (bdev->bd_contains != bdev)
+			atomic_inc(&bdev->bd_contains->bd_inode->i_writecount);
+	}
 	blkdev_put(bdev, mode | FMODE_EXCL);
 }
 
@@ -1128,6 +1229,14 @@
 	sb = root->d_sb;
 	BUG_ON(!sb);
 	WARN_ON(!sb->s_bdi);
+
+	/*
+	 * Write barrier is for super_cache_count(). We place it before setting
+	 * MS_BORN as the data dependency between the two functions is the
+	 * superblock structure contents that we just set up, not the MS_BORN
+	 * flag.
+	 */
+	smp_wmb();
 	sb->s_flags |= MS_BORN;
 
 	error = security_sb_kern_mount(sb, flags, secdata);
@@ -1325,8 +1434,8 @@
 		}
 	}
 	/*
-	 * This is just for debugging purposes so that fs can warn if it
-	 * sees write activity when frozen is set to SB_FREEZE_COMPLETE.
+	 * For debugging purposes so that fs can warn if it sees write activity
+	 * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super().
 	 */
 	sb->s_writers.frozen = SB_FREEZE_COMPLETE;
 	up_write(&sb->s_umount);
@@ -1345,7 +1454,7 @@
 	int error;
 
 	down_write(&sb->s_umount);
-	if (sb->s_writers.frozen == SB_UNFROZEN) {
+	if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) {
 		up_write(&sb->s_umount);
 		return -EINVAL;
 	}
--- linux-4.4.0.orig/fs/sysfs/file.c
+++ linux-4.4.0/fs/sysfs/file.c
@@ -17,6 +17,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
+#include <linux/mm.h>
 
 #include "sysfs.h"
 #include "../kernfs/kernfs-internal.h"
@@ -108,16 +109,24 @@
 {
 	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
 	struct kobject *kobj = of->kn->parent->priv;
-	size_t len;
+	ssize_t len;
 
 	/*
 	 * If buf != of->prealloc_buf, we don't know how
 	 * large it is, so cannot safely pass it to ->show
 	 */
-	if (pos || WARN_ON_ONCE(buf != of->prealloc_buf))
+	if (WARN_ON_ONCE(buf != of->prealloc_buf))
 		return 0;
 	len = ops->show(kobj, of->kn->priv, buf);
-	return min(count, len);
+	if (len < 0)
+		return len;
+	if (pos) {
+		if (len <= pos)
+			return 0;
+		len -= pos;
+		memmove(buf, buf + pos, len);
+	}
+	return min_t(ssize_t, count, len);
 }
 
 /* kernfs write callback for regular sysfs files */
@@ -400,6 +409,50 @@
 EXPORT_SYMBOL_GPL(sysfs_chmod_file);
 
 /**
+ * sysfs_break_active_protection - break "active" protection
+ * @kobj: The kernel object @attr is associated with.
+ * @attr: The attribute to break the "active" protection for.
+ *
+ * With sysfs, just like kernfs, deletion of an attribute is postponed until
+ * all active .show() and .store() callbacks have finished unless this function
+ * is called. Hence this function is useful in methods that implement self
+ * deletion.
+ */
+struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
+						  const struct attribute *attr)
+{
+	struct kernfs_node *kn;
+
+	kobject_get(kobj);
+	kn = kernfs_find_and_get(kobj->sd, attr->name);
+	if (kn)
+		kernfs_break_active_protection(kn);
+	return kn;
+}
+EXPORT_SYMBOL_GPL(sysfs_break_active_protection);
+
+/**
+ * sysfs_unbreak_active_protection - restore "active" protection
+ * @kn: Pointer returned by sysfs_break_active_protection().
+ *
+ * Undo the effects of sysfs_break_active_protection(). Since this function
+ * calls kernfs_put() on the kernfs node that corresponds to the 'attr'
+ * argument passed to sysfs_break_active_protection() that attribute may have
+ * been removed between the sysfs_break_active_protection() and
+ * sysfs_unbreak_active_protection() calls, it is not safe to access @kn after
+ * this function has returned.
+ */
+void sysfs_unbreak_active_protection(struct kernfs_node *kn)
+{
+	struct kobject *kobj = kn->parent->priv;
+
+	kernfs_unbreak_active_protection(kn);
+	kernfs_put(kn);
+	kobject_put(kobj);
+}
+EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection);
+
+/**
  * sysfs_remove_file_ns - remove an object attribute with a custom ns tag
  * @kobj: object we're acting for
  * @attr: attribute descriptor
@@ -497,3 +550,57 @@
 	kernfs_remove_by_name(kobj->sd, attr->attr.name);
 }
 EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
+
+/**
+ *	sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
+ *	@buf:	start of PAGE_SIZE buffer.
+ *	@fmt:	format
+ *	@...:	optional arguments to @format
+ *
+ *
+ * Returns number of characters written to @buf.
+ */
+int sysfs_emit(char *buf, const char *fmt, ...)
+{
+	va_list args;
+	int len;
+
+	if (WARN(!buf || offset_in_page(buf),
+		 "invalid sysfs_emit: buf:%p\n", buf))
+		return 0;
+
+	va_start(args, fmt);
+	len = vscnprintf(buf, PAGE_SIZE, fmt, args);
+	va_end(args);
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(sysfs_emit);
+
+/**
+ *	sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
+ *	@buf:	start of PAGE_SIZE buffer.
+ *	@at:	offset in @buf to start write in bytes
+ *		@at must be >= 0 && < PAGE_SIZE
+ *	@fmt:	format
+ *	@...:	optional arguments to @fmt
+ *
+ *
+ * Returns number of characters written starting at &@buf[@at].
+ */
+int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
+{
+	va_list args;
+	int len;
+
+	if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
+		 "invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
+		return 0;
+
+	va_start(args, fmt);
+	len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
+	va_end(args);
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(sysfs_emit_at);
--- linux-4.4.0.orig/fs/sysfs/mount.c
+++ linux-4.4.0/fs/sysfs/mount.c
@@ -40,9 +40,6 @@
 				SYSFS_MAGIC, &new_sb, ns);
 	if (IS_ERR(root) || !new_sb)
 		kobj_ns_drop(KOBJ_NS_TYPE_NET, ns);
-	else if (new_sb)
-		/* Userspace would break if executables appear on sysfs */
-		root->d_sb->s_iflags |= SB_I_NOEXEC;
 
 	return root;
 }
--- linux-4.4.0.orig/fs/sysv/file.c
+++ linux-4.4.0/fs/sysv/file.c
@@ -33,7 +33,7 @@
 	struct inode *inode = d_inode(dentry);
 	int error;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/sysv/inode.c
+++ linux-4.4.0/fs/sysv/inode.c
@@ -275,7 +275,7 @@
                 }
         }
 	brelse(bh);
-	return 0;
+	return err;
 }
 
 int sysv_write_inode(struct inode *inode, struct writeback_control *wbc)
--- linux-4.4.0.orig/fs/timerfd.c
+++ linux-4.4.0/fs/timerfd.c
@@ -40,6 +40,7 @@
 	short unsigned settime_flags;	/* to show in fdinfo */
 	struct rcu_head rcu;
 	struct list_head clist;
+	spinlock_t cancel_lock;
 	bool might_cancel;
 };
 
@@ -112,7 +113,7 @@
 	rcu_read_unlock();
 }
 
-static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
+static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
 {
 	if (ctx->might_cancel) {
 		ctx->might_cancel = false;
@@ -122,6 +123,13 @@
 	}
 }
 
+static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
+{
+	spin_lock(&ctx->cancel_lock);
+	__timerfd_remove_cancel(ctx);
+	spin_unlock(&ctx->cancel_lock);
+}
+
 static bool timerfd_canceled(struct timerfd_ctx *ctx)
 {
 	if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX)
@@ -132,6 +140,7 @@
 
 static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
 {
+	spin_lock(&ctx->cancel_lock);
 	if ((ctx->clockid == CLOCK_REALTIME ||
 	     ctx->clockid == CLOCK_REALTIME_ALARM) &&
 	    (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
@@ -141,9 +150,10 @@
 			list_add_rcu(&ctx->clist, &cancel_list);
 			spin_unlock(&cancel_lock);
 		}
-	} else if (ctx->might_cancel) {
-		timerfd_remove_cancel(ctx);
+	} else {
+		__timerfd_remove_cancel(ctx);
 	}
+	spin_unlock(&ctx->cancel_lock);
 }
 
 static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
@@ -153,7 +163,7 @@
 	if (isalarm(ctx))
 		remaining = alarm_expires_remaining(&ctx->t.alarm);
 	else
-		remaining = hrtimer_expires_remaining(&ctx->t.tmr);
+		remaining = hrtimer_expires_remaining_adjusted(&ctx->t.tmr);
 
 	return remaining.tv64 < 0 ? ktime_set(0, 0): remaining;
 }
@@ -395,6 +405,7 @@
 		return -ENOMEM;
 
 	init_waitqueue_head(&ctx->wqh);
+	spin_lock_init(&ctx->cancel_lock);
 	ctx->clockid = clockid;
 
 	if (isalarm(ctx))
--- linux-4.4.0.orig/fs/ubifs/debug.c
+++ linux-4.4.0/fs/ubifs/debug.c
@@ -1125,6 +1125,7 @@
 			err = PTR_ERR(dent);
 			if (err == -ENOENT)
 				break;
+			kfree(pdent);
 			return err;
 		}
 
--- linux-4.4.0.orig/fs/ubifs/dir.c
+++ linux-4.4.0/fs/ubifs/dir.c
@@ -350,7 +350,7 @@
  */
 static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 {
-	int err;
+	int err = 0;
 	struct qstr nm;
 	union ubifs_key key;
 	struct ubifs_dent_node *dent;
@@ -452,14 +452,20 @@
 	kfree(file->private_data);
 	file->private_data = NULL;
 
-	if (err != -ENOENT) {
+	if (err != -ENOENT)
 		ubifs_err(c, "cannot find next direntry, error %d", err);
-		return err;
-	}
+	else
+		/*
+		 * -ENOENT is a non-fatal error in this context, the TNC uses
+		 * it to indicate that the cursor moved past the current directory
+		 * and readdir() has to stop.
+		 */
+		err = 0;
+
 
 	/* 2 is a special value indicating that there are no more direntries */
 	ctx->pos = 2;
-	return 0;
+	return err;
 }
 
 /* Free saved readdir() state when the directory is closed */
--- linux-4.4.0.orig/fs/ubifs/file.c
+++ linux-4.4.0/fs/ubifs/file.c
@@ -52,6 +52,7 @@
 #include "ubifs.h"
 #include <linux/mount.h>
 #include <linux/slab.h>
+#include <linux/migrate.h>
 
 static int read_block(struct inode *inode, void *addr, unsigned int block,
 		      struct ubifs_data_node *dn)
@@ -781,8 +782,9 @@
 
 		if (page_offset > end_index)
 			break;
-		page = find_or_create_page(mapping, page_offset,
-					   GFP_NOFS | __GFP_COLD);
+		page = pagecache_get_page(mapping, page_offset,
+				 FGP_LOCK|FGP_ACCESSED|FGP_CREAT|FGP_NOWAIT,
+				 GFP_NOFS | __GFP_COLD);
 		if (!page)
 			break;
 		if (!PageUptodate(page))
@@ -1261,7 +1263,7 @@
 
 	dbg_gen("ino %lu, mode %#x, ia_valid %#x",
 		inode->i_ino, inode->i_mode, attr->ia_valid);
-	err = inode_change_ok(inode, attr);
+	err = setattr_prepare(dentry, attr);
 	if (err)
 		return err;
 
@@ -1452,6 +1454,26 @@
 	return ret;
 }
 
+#ifdef CONFIG_MIGRATION
+static int ubifs_migrate_page(struct address_space *mapping,
+		struct page *newpage, struct page *page, enum migrate_mode mode)
+{
+	int rc;
+
+	rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode, 0);
+	if (rc != MIGRATEPAGE_SUCCESS)
+		return rc;
+
+	if (PagePrivate(page)) {
+		ClearPagePrivate(page);
+		SetPagePrivate(newpage);
+	}
+
+	migrate_page_copy(newpage, page);
+	return MIGRATEPAGE_SUCCESS;
+}
+#endif
+
 static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
 {
 	/*
@@ -1591,6 +1613,9 @@
 	.write_end      = ubifs_write_end,
 	.invalidatepage = ubifs_invalidatepage,
 	.set_page_dirty = ubifs_set_page_dirty,
+#ifdef CONFIG_MIGRATION
+	.migratepage	= ubifs_migrate_page,
+#endif
 	.releasepage    = ubifs_releasepage,
 };
 
--- linux-4.4.0.orig/fs/ubifs/io.c
+++ linux-4.4.0/fs/ubifs/io.c
@@ -237,7 +237,7 @@
 int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
 		     int offs, int quiet, int must_chk_crc)
 {
-	int err = -EINVAL, type, node_len;
+	int err = -EINVAL, type, node_len, dump_node = 1;
 	uint32_t crc, node_crc, magic;
 	const struct ubifs_ch *ch = buf;
 
@@ -290,10 +290,22 @@
 out_len:
 	if (!quiet)
 		ubifs_err(c, "bad node length %d", node_len);
+	if (type == UBIFS_DATA_NODE && node_len > UBIFS_DATA_NODE_SZ)
+		dump_node = 0;
 out:
 	if (!quiet) {
 		ubifs_err(c, "bad node at LEB %d:%d", lnum, offs);
-		ubifs_dump_node(c, buf);
+		if (dump_node) {
+			ubifs_dump_node(c, buf);
+		} else {
+			int safe_len = min3(node_len, c->leb_size - offs,
+				(int)UBIFS_MAX_DATA_NODE_SZ);
+			pr_err("\tprevent out-of-bounds memory access\n");
+			pr_err("\ttruncated data node length      %d\n", safe_len);
+			pr_err("\tcorrupted data node:\n");
+			print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1,
+					buf, safe_len, 0);
+		}
 		dump_stack();
 	}
 	return err;
@@ -319,7 +331,7 @@
 {
 	uint32_t crc;
 
-	ubifs_assert(pad >= 0 && !(pad & 7));
+	ubifs_assert(pad >= 0);
 
 	if (pad >= UBIFS_PAD_NODE_SZ) {
 		struct ubifs_ch *ch = buf;
@@ -709,6 +721,10 @@
 		 * write-buffer.
 		 */
 		memcpy(wbuf->buf + wbuf->used, buf, len);
+		if (aligned_len > len) {
+			ubifs_assert(aligned_len - len < 8);
+			ubifs_pad(c, wbuf->buf + wbuf->used + len, aligned_len - len);
+		}
 
 		if (aligned_len == wbuf->avail) {
 			dbg_io("flush jhead %s wbuf to LEB %d:%d",
@@ -801,13 +817,18 @@
 	}
 
 	spin_lock(&wbuf->lock);
-	if (aligned_len)
+	if (aligned_len) {
 		/*
 		 * And now we have what's left and what does not take whole
 		 * max. write unit, so write it to the write-buffer and we are
 		 * done.
 		 */
 		memcpy(wbuf->buf, buf + written, len);
+		if (aligned_len > len) {
+			ubifs_assert(aligned_len - len < 8);
+			ubifs_pad(c, wbuf->buf + len, aligned_len - len);
+		}
+	}
 
 	if (c->leb_size - wbuf->offs >= c->max_write_size)
 		wbuf->size = c->max_write_size;
--- linux-4.4.0.orig/fs/ubifs/journal.c
+++ linux-4.4.0/fs/ubifs/journal.c
@@ -661,6 +661,11 @@
 	spin_lock(&ui->ui_lock);
 	ui->synced_i_size = ui->ui_size;
 	spin_unlock(&ui->ui_lock);
+	if (xent) {
+		spin_lock(&host_ui->ui_lock);
+		host_ui->synced_i_size = host_ui->ui_size;
+		spin_unlock(&host_ui->ui_lock);
+	}
 	mark_inode_clean(c, ui);
 	mark_inode_clean(c, host_ui);
 	return 0;
@@ -1186,7 +1191,16 @@
 		else if (err)
 			goto out_free;
 		else {
-			if (le32_to_cpu(dn->size) <= dlen)
+			int dn_len = le32_to_cpu(dn->size);
+
+			if (dn_len <= 0 || dn_len > UBIFS_BLOCK_SIZE) {
+				ubifs_err(c, "bad data node (block %u, inode %lu)",
+					  blk, inode->i_ino);
+				ubifs_dump_node(c, dn);
+				goto out_free;
+			}
+
+			if (dn_len <= dlen)
 				dlen = 0; /* Nothing to do */
 			else {
 				int compr_type = le16_to_cpu(dn->compr_type);
--- linux-4.4.0.orig/fs/ubifs/lprops.c
+++ linux-4.4.0/fs/ubifs/lprops.c
@@ -1091,10 +1091,6 @@
 		}
 	}
 
-	buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
 	/*
 	 * After an unclean unmount, empty and freeable LEBs
 	 * may contain garbage - do not scan them.
@@ -1113,6 +1109,10 @@
 		return LPT_SCAN_CONTINUE;
 	}
 
+	buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
 	sleb = ubifs_scan(c, lnum, 0, buf, 0);
 	if (IS_ERR(sleb)) {
 		ret = PTR_ERR(sleb);
--- linux-4.4.0.orig/fs/ubifs/super.c
+++ linux-4.4.0/fs/ubifs/super.c
@@ -1728,8 +1728,11 @@
 
 	dbg_save_space_info(c);
 
-	for (i = 0; i < c->jhead_cnt; i++)
-		ubifs_wbuf_sync(&c->jheads[i].wbuf);
+	for (i = 0; i < c->jhead_cnt; i++) {
+		err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+		if (err)
+			ubifs_ro_mode(c, err);
+	}
 
 	c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
 	c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
@@ -1795,8 +1798,11 @@
 			int err;
 
 			/* Synchronize write-buffers */
-			for (i = 0; i < c->jhead_cnt; i++)
-				ubifs_wbuf_sync(&c->jheads[i].wbuf);
+			for (i = 0; i < c->jhead_cnt; i++) {
+				err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+				if (err)
+					ubifs_ro_mode(c, err);
+			}
 
 			/*
 			 * We are being cleanly unmounted which means the
@@ -1912,6 +1918,9 @@
 	int dev, vol;
 	char *endptr;
 
+	if (!name || !*name)
+		return ERR_PTR(-EINVAL);
+
 	/* First, try to open using the device node path method */
 	ubi = ubi_open_volume_path(name, mode);
 	if (!IS_ERR(ubi))
--- linux-4.4.0.orig/fs/ubifs/tnc.c
+++ linux-4.4.0/fs/ubifs/tnc.c
@@ -34,6 +34,11 @@
 #include <linux/slab.h>
 #include "ubifs.h"
 
+static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+			 int len, int lnum, int offs);
+static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+			      struct ubifs_zbranch *zbr, void *node);
+
 /*
  * Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
  * @NAME_LESS: name corresponding to the first argument is less than second
@@ -402,7 +407,19 @@
 		return 0;
 	}
 
-	err = ubifs_tnc_read_node(c, zbr, node);
+	if (c->replaying) {
+		err = fallible_read_node(c, &zbr->key, zbr, node);
+		/*
+		 * When the node was not found, return -ENOENT, 0 otherwise.
+		 * Negative return codes stay as-is.
+		 */
+		if (err == 0)
+			err = -ENOENT;
+		else if (err == 1)
+			err = 0;
+	} else {
+		err = ubifs_tnc_read_node(c, zbr, node);
+	}
 	if (err)
 		return err;
 
@@ -2766,7 +2783,11 @@
 	if (nm->name) {
 		if (err) {
 			/* Handle collisions */
-			err = resolve_collision(c, key, &znode, &n, nm);
+			if (c->replaying)
+				err = fallible_resolve_collision(c, key, &znode, &n,
+							 nm, 0);
+			else
+				err = resolve_collision(c, key, &znode, &n, nm);
 			dbg_tnc("rc returned %d, znode %p, n %d",
 				err, znode, n);
 			if (unlikely(err < 0))
--- linux-4.4.0.orig/fs/ubifs/tnc_commit.c
+++ linux-4.4.0/fs/ubifs/tnc_commit.c
@@ -370,7 +370,7 @@
 
 	p = c->gap_lebs;
 	do {
-		ubifs_assert(p < c->gap_lebs + sizeof(int) * c->lst.idx_lebs);
+		ubifs_assert(p < c->gap_lebs + c->lst.idx_lebs);
 		written = layout_leb_in_gaps(c, p);
 		if (written < 0) {
 			err = written;
--- linux-4.4.0.orig/fs/ubifs/xattr.c
+++ linux-4.4.0/fs/ubifs/xattr.c
@@ -173,6 +173,7 @@
 	host_ui->xattr_cnt -= 1;
 	host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
 	host_ui->xattr_size -= CALC_XATTR_BYTES(size);
+	host_ui->xattr_names -= nm->len;
 	mutex_unlock(&host_ui->ui_mutex);
 out_free:
 	make_bad_inode(inode);
@@ -533,6 +534,7 @@
 	host_ui->xattr_cnt += 1;
 	host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
 	host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
+	host_ui->xattr_names += nm->len;
 	mutex_unlock(&host_ui->ui_mutex);
 	ubifs_release_budget(c, &req);
 	make_bad_inode(inode);
--- linux-4.4.0.orig/fs/udf/directory.c
+++ linux-4.4.0/fs/udf/directory.c
@@ -150,6 +150,9 @@
 			       sizeof(struct fileIdentDesc));
 		}
 	}
+	/* Got last entry outside of dir size - fs is corrupted! */
+	if (*nf_pos > dir->i_size)
+		return NULL;
 	return fi;
 }
 
--- linux-4.4.0.orig/fs/udf/file.c
+++ linux-4.4.0/fs/udf/file.c
@@ -250,7 +250,7 @@
 	struct inode *inode = d_inode(dentry);
 	int error;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/udf/inode.c
+++ linux-4.4.0/fs/udf/inode.c
@@ -140,21 +140,24 @@
 	struct udf_inode_info *iinfo = UDF_I(inode);
 	int want_delete = 0;
 
-	if (!inode->i_nlink && !is_bad_inode(inode)) {
-		want_delete = 1;
-		udf_setsize(inode, 0);
-		udf_update_inode(inode, IS_SYNC(inode));
+	if (!is_bad_inode(inode)) {
+		if (!inode->i_nlink) {
+			want_delete = 1;
+			udf_setsize(inode, 0);
+			udf_update_inode(inode, IS_SYNC(inode));
+		}
+		if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB &&
+		    inode->i_size != iinfo->i_lenExtents) {
+			udf_warn(inode->i_sb,
+				 "Inode %lu (mode %o) has inode size %llu different from extent length %llu. Filesystem need not be standards compliant.\n",
+				 inode->i_ino, inode->i_mode,
+				 (unsigned long long)inode->i_size,
+				 (unsigned long long)iinfo->i_lenExtents);
+		}
 	}
 	truncate_inode_pages_final(&inode->i_data);
 	invalidate_inode_buffers(inode);
 	clear_inode(inode);
-	if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB &&
-	    inode->i_size != iinfo->i_lenExtents) {
-		udf_warn(inode->i_sb, "Inode %lu (mode %o) has inode size %llu different from extent length %llu. Filesystem need not be standards compliant.\n",
-			 inode->i_ino, inode->i_mode,
-			 (unsigned long long)inode->i_size,
-			 (unsigned long long)iinfo->i_lenExtents);
-	}
 	kfree(iinfo->i_ext.i_data);
 	iinfo->i_ext.i_data = NULL;
 	udf_clear_extent_cache(inode);
@@ -257,10 +260,6 @@
 	char *kaddr;
 	struct udf_inode_info *iinfo = UDF_I(inode);
 	int err;
-	struct writeback_control udf_wbc = {
-		.sync_mode = WB_SYNC_NONE,
-		.nr_to_write = 1,
-	};
 
 	WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
 	if (!iinfo->i_lenAlloc) {
@@ -304,8 +303,10 @@
 		iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
 	/* from now on we have normal address_space methods */
 	inode->i_data.a_ops = &udf_aops;
+	set_page_dirty(page);
+	unlock_page(page);
 	up_write(&iinfo->i_data_sem);
-	err = inode->i_data.a_ops->writepage(page, &udf_wbc);
+	err = filemap_fdatawrite(inode->i_mapping);
 	if (err) {
 		/* Restore everything back so that we don't lose data... */
 		lock_page(page);
@@ -317,6 +318,7 @@
 		unlock_page(page);
 		iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
 		inode->i_data.a_ops = &udf_adinicb_aops;
+		iinfo->i_lenAlloc = inode->i_size;
 		up_write(&iinfo->i_data_sem);
 	}
 	page_cache_release(page);
@@ -479,13 +481,15 @@
 	return NULL;
 }
 
-/* Extend the file by 'blocks' blocks, return the number of extents added */
+/* Extend the file with new blocks totaling 'new_block_bytes',
+ * return the number of extents added
+ */
 static int udf_do_extend_file(struct inode *inode,
 			      struct extent_position *last_pos,
 			      struct kernel_long_ad *last_ext,
-			      sector_t blocks)
+			      loff_t new_block_bytes)
 {
-	sector_t add;
+	uint32_t add;
 	int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
 	struct super_block *sb = inode->i_sb;
 	struct kernel_lb_addr prealloc_loc = {};
@@ -495,7 +499,7 @@
 
 	/* The previous extent is fake and we should not extend by anything
 	 * - there's nothing to do... */
-	if (!blocks && fake)
+	if (!new_block_bytes && fake)
 		return 0;
 
 	iinfo = UDF_I(inode);
@@ -526,13 +530,12 @@
 	/* Can we merge with the previous extent? */
 	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
 					EXT_NOT_RECORDED_NOT_ALLOCATED) {
-		add = ((1 << 30) - sb->s_blocksize -
-			(last_ext->extLength & UDF_EXTENT_LENGTH_MASK)) >>
-			sb->s_blocksize_bits;
-		if (add > blocks)
-			add = blocks;
-		blocks -= add;
-		last_ext->extLength += add << sb->s_blocksize_bits;
+		add = (1 << 30) - sb->s_blocksize -
+			(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+		if (add > new_block_bytes)
+			add = new_block_bytes;
+		new_block_bytes -= add;
+		last_ext->extLength += add;
 	}
 
 	if (fake) {
@@ -544,28 +547,27 @@
 				last_ext->extLength, 1);
 
 	/* Managed to do everything necessary? */
-	if (!blocks)
+	if (!new_block_bytes)
 		goto out;
 
 	/* All further extents will be NOT_RECORDED_NOT_ALLOCATED */
 	last_ext->extLocation.logicalBlockNum = 0;
 	last_ext->extLocation.partitionReferenceNum = 0;
-	add = (1 << (30-sb->s_blocksize_bits)) - 1;
-	last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
-				(add << sb->s_blocksize_bits);
+	add = (1 << 30) - sb->s_blocksize;
+	last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | add;
 
 	/* Create enough extents to cover the whole hole */
-	while (blocks > add) {
-		blocks -= add;
+	while (new_block_bytes > add) {
+		new_block_bytes -= add;
 		err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
 				   last_ext->extLength, 1);
 		if (err)
 			return err;
 		count++;
 	}
-	if (blocks) {
+	if (new_block_bytes) {
 		last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
-			(blocks << sb->s_blocksize_bits);
+			new_block_bytes;
 		err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
 				   last_ext->extLength, 1);
 		if (err)
@@ -596,6 +598,24 @@
 	return count;
 }
 
+/* Extend the final block of the file to final_block_len bytes */
+static void udf_do_extend_final_block(struct inode *inode,
+				      struct extent_position *last_pos,
+				      struct kernel_long_ad *last_ext,
+				      uint32_t final_block_len)
+{
+	struct super_block *sb = inode->i_sb;
+	uint32_t added_bytes;
+
+	added_bytes = final_block_len -
+		      (last_ext->extLength & (sb->s_blocksize - 1));
+	last_ext->extLength += added_bytes;
+	UDF_I(inode)->i_lenExtents += added_bytes;
+
+	udf_write_aext(inode, last_pos, &last_ext->extLocation,
+			last_ext->extLength, 1);
+}
+
 static int udf_extend_file(struct inode *inode, loff_t newsize)
 {
 
@@ -605,10 +625,12 @@
 	int8_t etype;
 	struct super_block *sb = inode->i_sb;
 	sector_t first_block = newsize >> sb->s_blocksize_bits, offset;
+	unsigned long partial_final_block;
 	int adsize;
 	struct udf_inode_info *iinfo = UDF_I(inode);
 	struct kernel_long_ad extent;
-	int err;
+	int err = 0;
+	int within_final_block;
 
 	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
 		adsize = sizeof(struct short_ad);
@@ -618,18 +640,8 @@
 		BUG();
 
 	etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
+	within_final_block = (etype != -1);
 
-	/* File has extent covering the new size (could happen when extending
-	 * inside a block)? */
-	if (etype != -1)
-		return 0;
-	if (newsize & (sb->s_blocksize - 1))
-		offset++;
-	/* Extended file just to the boundary of the last file block? */
-	if (offset == 0)
-		return 0;
-
-	/* Truncate is extending the file by 'offset' blocks */
 	if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
 	    (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
 		/* File has no extents at all or has empty last
@@ -643,7 +655,22 @@
 				      &extent.extLength, 0);
 		extent.extLength |= etype << 30;
 	}
-	err = udf_do_extend_file(inode, &epos, &extent, offset);
+
+	partial_final_block = newsize & (sb->s_blocksize - 1);
+
+	/* File has extent covering the new size (could happen when extending
+	 * inside a block)?
+	 */
+	if (within_final_block) {
+		/* Extending file within the last file block */
+		udf_do_extend_final_block(inode, &epos, &extent,
+					  partial_final_block);
+	} else {
+		loff_t add = ((loff_t)offset << sb->s_blocksize_bits) |
+			     partial_final_block;
+		err = udf_do_extend_file(inode, &epos, &extent, add);
+	}
+
 	if (err < 0)
 		goto out;
 	err = 0;
@@ -748,6 +775,7 @@
 	/* Are we beyond EOF? */
 	if (etype == -1) {
 		int ret;
+		loff_t hole_len;
 		isBeyondEOF = true;
 		if (count) {
 			if (c)
@@ -763,7 +791,8 @@
 			startnum = (offset > 0);
 		}
 		/* Create extents for the hole between EOF and offset */
-		ret = udf_do_extend_file(inode, &prev_epos, laarr, offset);
+		hole_len = (loff_t)offset << inode->i_blkbits;
+		ret = udf_do_extend_file(inode, &prev_epos, laarr, hole_len);
 		if (ret < 0) {
 			brelse(prev_epos.bh);
 			brelse(cur_epos.bh);
@@ -1206,7 +1235,7 @@
 {
 	int err;
 	struct udf_inode_info *iinfo;
-	int bsize = 1 << inode->i_blkbits;
+	int bsize = i_blocksize(inode);
 
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	      S_ISLNK(inode->i_mode)))
@@ -1235,8 +1264,8 @@
 			return err;
 		}
 set_size:
-		truncate_setsize(inode, newsize);
 		up_write(&iinfo->i_data_sem);
+		truncate_setsize(inode, newsize);
 	} else {
 		if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
 			down_write(&iinfo->i_data_sem);
@@ -1253,9 +1282,9 @@
 					  udf_get_block);
 		if (err)
 			return err;
+		truncate_setsize(inode, newsize);
 		down_write(&iinfo->i_data_sem);
 		udf_clear_extent_cache(inode);
-		truncate_setsize(inode, newsize);
 		udf_truncate_extents(inode);
 		up_write(&iinfo->i_data_sem);
 	}
@@ -1364,6 +1393,12 @@
 
 	iinfo->i_alloc_type = le16_to_cpu(fe->icbTag.flags) &
 							ICBTAG_FLAG_AD_MASK;
+	if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_SHORT &&
+	    iinfo->i_alloc_type != ICBTAG_FLAG_AD_LONG &&
+	    iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+		ret = -EIO;
+		goto out;
+	}
 	iinfo->i_unique = 0;
 	iinfo->i_lenEAttr = 0;
 	iinfo->i_lenExtents = 0;
@@ -2047,14 +2082,29 @@
 		epos->offset += adsize;
 }
 
+/*
+ * Only 1 indirect extent in a row really makes sense but allow upto 16 in case
+ * someone does some weird stuff.
+ */
+#define UDF_MAX_INDIR_EXTS 16
+
 int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
 		     struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
 {
 	int8_t etype;
+	unsigned int indirections = 0;
 
 	while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
 	       (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
 		int block;
+
+		if (++indirections > UDF_MAX_INDIR_EXTS) {
+			udf_err(inode->i_sb,
+				"too many indirect extents in inode %lu\n",
+				inode->i_ino);
+			return -1;
+		}
+
 		epos->block = *eloc;
 		epos->offset = sizeof(struct allocExtDesc);
 		brelse(epos->bh);
--- linux-4.4.0.orig/fs/udf/misc.c
+++ linux-4.4.0/fs/udf/misc.c
@@ -24,6 +24,7 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/crc-itu-t.h>
+#include <linux/nospec.h>
 
 #include "udf_i.h"
 #include "udf_sb.h"
@@ -103,7 +104,9 @@
 			if (le32_to_cpu(eahd->appAttrLocation) <
 					iinfo->i_lenEAttr) {
 				uint32_t aal =
-					le32_to_cpu(eahd->appAttrLocation);
+					array_index_nospec(le32_to_cpu(eahd->appAttrLocation),
+							   iinfo->i_lenEAttr); /* needed? */
+
 				memmove(&ea[offset - aal + size],
 					&ea[aal], offset - aal);
 				offset -= aal;
@@ -113,7 +116,9 @@
 			if (le32_to_cpu(eahd->impAttrLocation) <
 					iinfo->i_lenEAttr) {
 				uint32_t ial =
-					le32_to_cpu(eahd->impAttrLocation);
+					array_index_nospec(le32_to_cpu(eahd->impAttrLocation),
+							   iinfo->i_lenEAttr); /* needed? */
+
 				memmove(&ea[offset - ial + size],
 					&ea[ial], offset - ial);
 				offset -= ial;
@@ -124,7 +129,9 @@
 			if (le32_to_cpu(eahd->appAttrLocation) <
 					iinfo->i_lenEAttr) {
 				uint32_t aal =
-					le32_to_cpu(eahd->appAttrLocation);
+					array_index_nospec(le32_to_cpu(eahd->appAttrLocation),
+							   iinfo->i_lenEAttr); /* needed? */
+
 				memmove(&ea[offset - aal + size],
 					&ea[aal], offset - aal);
 				offset -= aal;
--- linux-4.4.0.orig/fs/udf/namei.c
+++ linux-4.4.0/fs/udf/namei.c
@@ -611,8 +611,7 @@
 	if (fibh.sbh != fibh.ebh)
 		brelse(fibh.ebh);
 	brelse(fibh.sbh);
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 
 	return 0;
 }
@@ -722,8 +721,7 @@
 	inc_nlink(dir);
 	dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
 	mark_inode_dirty(dir);
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	if (fibh.sbh != fibh.ebh)
 		brelse(fibh.ebh);
 	brelse(fibh.sbh);
@@ -947,6 +945,10 @@
 				iinfo->i_location.partitionReferenceNum,
 				0);
 		epos.bh = udf_tgetblk(sb, block);
+		if (unlikely(!epos.bh)) {
+			err = -ENOMEM;
+			goto out_no_entry;
+		}
 		lock_buffer(epos.bh);
 		memset(epos.bh->b_data, 0x00, bsize);
 		set_buffer_uptodate(epos.bh);
--- linux-4.4.0.orig/fs/udf/super.c
+++ linux-4.4.0/fs/udf/super.c
@@ -56,6 +56,7 @@
 #include <linux/bitmap.h>
 #include <linux/crc-itu-t.h>
 #include <linux/log2.h>
+#include <linux/overflow.h>
 #include <asm/byteorder.h>
 
 #include "udf_sb.h"
@@ -705,7 +706,7 @@
 	else
 		sectorsize = sb->s_blocksize;
 
-	sector += (sbi->s_session << sb->s_blocksize_bits);
+	sector += (((loff_t)sbi->s_session) << sb->s_blocksize_bits);
 
 	udf_debug("Starting at sector %u (%ld byte sectors)\n",
 		  (unsigned int)(sector >> sb->s_blocksize_bits),
@@ -1092,11 +1093,18 @@
 	struct udf_part_map *map;
 	struct udf_sb_info *sbi = UDF_SB(sb);
 	struct partitionHeaderDesc *phd;
+	u32 sum;
 
 	map = &sbi->s_partmaps[p_index];
 
 	map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */
 	map->s_partition_root = le32_to_cpu(p->partitionStartingLocation);
+	if (check_add_overflow(map->s_partition_root, map->s_partition_len,
+			       &sum)) {
+		udf_err(sb, "Partition %d has invalid location %u + %u\n",
+			p_index, map->s_partition_root, map->s_partition_len);
+		return -EUCLEAN;
+	}
 
 	if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY))
 		map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY;
@@ -1144,7 +1152,15 @@
 		bitmap->s_extPosition = le32_to_cpu(
 				phd->unallocSpaceBitmap.extPosition);
 		map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP;
-		udf_debug("unallocSpaceBitmap (part %d) @ %d\n",
+		/* Check whether math over bitmap won't overflow. */
+		if (check_add_overflow(map->s_partition_len,
+				       sizeof(struct spaceBitmapDesc) << 3,
+				       &sum)) {
+			udf_err(sb, "Partition %d is too long (%u)\n", p_index,
+				map->s_partition_len);
+			return -EUCLEAN;
+		}
+		udf_debug("unallocSpaceBitmap (part %d) @ %u\n",
 			  p_index, bitmap->s_extPosition);
 	}
 
@@ -1390,6 +1406,12 @@
 			(int)spm->numSparingTables);
 		return -EIO;
 	}
+	if (le32_to_cpu(spm->sizeSparingTable) > sb->s_blocksize) {
+		udf_err(sb, "error loading logical volume descriptor: "
+			"Too big sparing table size (%u)\n",
+			le32_to_cpu(spm->sizeSparingTable));
+		return -EIO;
+	}
 
 	for (i = 0; i < spm->numSparingTables; i++) {
 		loc = le32_to_cpu(spm->locSparingTable[i]);
@@ -2073,8 +2095,9 @@
 	bool lvid_open = false;
 
 	uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
-	uopt.uid = INVALID_UID;
-	uopt.gid = INVALID_GID;
+	/* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */
+	uopt.uid = make_kuid(current_user_ns(), overflowuid);
+	uopt.gid = make_kgid(current_user_ns(), overflowgid);
 	uopt.umask = 0;
 	uopt.fmode = UDF_INVALID_MODE;
 	uopt.dmode = UDF_INVALID_MODE;
--- linux-4.4.0.orig/fs/udf/truncate.c
+++ linux-4.4.0/fs/udf/truncate.c
@@ -260,6 +260,9 @@
 			epos.block = eloc;
 			epos.bh = udf_tread(sb,
 					udf_get_lb_pblock(sb, &eloc, 0));
+			/* Error reading indirect block? */
+			if (!epos.bh)
+				return;
 			if (elen)
 				indirect_ext_len =
 					(elen + sb->s_blocksize - 1) >>
--- linux-4.4.0.orig/fs/udf/unicode.c
+++ linux-4.4.0/fs/udf/unicode.c
@@ -128,11 +128,15 @@
 		if (c < 0x80U)
 			utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
 		else if (c < 0x800U) {
+			if (utf_o->u_len > (UDF_NAME_LEN - 4))
+				break;
 			utf_o->u_name[utf_o->u_len++] =
 						(uint8_t)(0xc0 | (c >> 6));
 			utf_o->u_name[utf_o->u_len++] =
 						(uint8_t)(0x80 | (c & 0x3f));
 		} else {
+			if (utf_o->u_len > (UDF_NAME_LEN - 5))
+				break;
 			utf_o->u_name[utf_o->u_len++] =
 						(uint8_t)(0xe0 | (c >> 12));
 			utf_o->u_name[utf_o->u_len++] =
@@ -173,17 +177,22 @@
 static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
 {
 	unsigned c, i, max_val, utf_char;
-	int utf_cnt, u_len;
+	int utf_cnt, u_len, u_ch;
 
 	memset(ocu, 0, sizeof(dstring) * length);
 	ocu[0] = 8;
 	max_val = 0xffU;
+	u_ch = 1;
 
 try_again:
 	u_len = 0U;
 	utf_char = 0U;
 	utf_cnt = 0U;
 	for (i = 0U; i < utf->u_len; i++) {
+		/* Name didn't fit? */
+		if (u_len + 1 + u_ch >= length)
+			return 0;
+
 		c = (uint8_t)utf->u_name[i];
 
 		/* Complete a multi-byte UTF-8 character */
@@ -225,6 +234,7 @@
 			if (max_val == 0xffU) {
 				max_val = 0xffffU;
 				ocu[0] = (uint8_t)0x10U;
+				u_ch = 2;
 				goto try_again;
 			}
 			goto error_out;
@@ -277,7 +287,7 @@
 			c = (c << 8) | ocu[i++];
 
 		len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
-				    UDF_NAME_LEN - utf_o->u_len);
+				    UDF_NAME_LEN - 2 - utf_o->u_len);
 		/* Valid character? */
 		if (len >= 0)
 			utf_o->u_len += len;
@@ -295,15 +305,19 @@
 	int len;
 	unsigned i, max_val;
 	uint16_t uni_char;
-	int u_len;
+	int u_len, u_ch;
 
 	memset(ocu, 0, sizeof(dstring) * length);
 	ocu[0] = 8;
 	max_val = 0xffU;
+	u_ch = 1;
 
 try_again:
 	u_len = 0U;
 	for (i = 0U; i < uni->u_len; i++) {
+		/* Name didn't fit? */
+		if (u_len + 1 + u_ch >= length)
+			return 0;
 		len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
 		if (!len)
 			continue;
@@ -316,6 +330,7 @@
 		if (uni_char > max_val) {
 			max_val = 0xffffU;
 			ocu[0] = (uint8_t)0x10U;
+			u_ch = 2;
 			goto try_again;
 		}
 
--- linux-4.4.0.orig/fs/ufs/balloc.c
+++ linux-4.4.0/fs/ufs/balloc.c
@@ -81,7 +81,8 @@
 			ufs_error (sb, "ufs_free_fragments",
 				   "bit already cleared for fragment %u", i);
 	}
-	
+
+	inode_sub_bytes(inode, count << uspi->s_fshift);
 	fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
 	uspi->cs_total.cs_nffree += count;
 	fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
@@ -183,6 +184,7 @@
 			ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
 		}
 		ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
+		inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
 		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 			ufs_clusteracct (sb, ucpi, blkno, 1);
 
@@ -494,6 +496,20 @@
 	return 0;
 }		
 
+static bool try_add_frags(struct inode *inode, unsigned frags)
+{
+	unsigned size = frags * i_blocksize(inode);
+	spin_lock(&inode->i_lock);
+	__inode_add_bytes(inode, size);
+	if (unlikely((u32)inode->i_blocks != inode->i_blocks)) {
+		__inode_sub_bytes(inode, size);
+		spin_unlock(&inode->i_lock);
+		return false;
+	}
+	spin_unlock(&inode->i_lock);
+	return true;
+}
+
 static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
 			     unsigned oldcount, unsigned newcount)
 {
@@ -530,6 +546,9 @@
 	for (i = oldcount; i < newcount; i++)
 		if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
 			return 0;
+
+	if (!try_add_frags(inode, count))
+		return 0;
 	/*
 	 * Block can be extended
 	 */
@@ -647,6 +666,7 @@
 			ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
 		i = uspi->s_fpb - count;
 
+		inode_sub_bytes(inode, i << uspi->s_fshift);
 		fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
 		uspi->cs_total.cs_nffree += i;
 		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
@@ -657,6 +677,8 @@
 	result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
 	if (result == INVBLOCK)
 		return 0;
+	if (!try_add_frags(inode, count))
+		return 0;
 	for (i = 0; i < count; i++)
 		ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
 	
@@ -716,6 +738,8 @@
 		return INVBLOCK;
 	ucpi->c_rotor = result;
 gotit:
+	if (!try_add_frags(inode, uspi->s_fpb))
+		return 0;
 	blkno = ufs_fragstoblks(result);
 	ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
 	if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
--- linux-4.4.0.orig/fs/ufs/dir.c
+++ linux-4.4.0/fs/ufs/dir.c
@@ -105,7 +105,7 @@
 }
 
 
-static void ufs_check_page(struct page *page)
+static bool ufs_check_page(struct page *page)
 {
 	struct inode *dir = page->mapping->host;
 	struct super_block *sb = dir->i_sb;
@@ -143,7 +143,7 @@
 		goto Eend;
 out:
 	SetPageChecked(page);
-	return;
+	return true;
 
 	/* Too bad, we had an error */
 
@@ -180,8 +180,8 @@
 		   "offset=%lu",
 		   dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs);
 fail:
-	SetPageChecked(page);
 	SetPageError(page);
+	return false;
 }
 
 static struct page *ufs_get_page(struct inode *dir, unsigned long n)
@@ -190,10 +190,10 @@
 	struct page *page = read_mapping_page(mapping, n, NULL);
 	if (!IS_ERR(page)) {
 		kmap(page);
-		if (!PageChecked(page))
-			ufs_check_page(page);
-		if (PageError(page))
-			goto fail;
+		if (unlikely(!PageChecked(page))) {
+			if (PageError(page) || !ufs_check_page(page))
+				goto fail;
+		}
 	}
 	return page;
 
--- linux-4.4.0.orig/fs/ufs/inode.c
+++ linux-4.4.0/fs/ufs/inode.c
@@ -235,7 +235,8 @@
 
 	p = ufs_get_direct_data_ptr(uspi, ufsi, block);
 	tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p),
-				new_size, err, locked_page);
+				new_size - (lastfrag & uspi->s_fpbmask), err,
+				locked_page);
 	return tmp != 0;
 }
 
@@ -284,7 +285,7 @@
 			goal += uspi->s_fpb;
 	}
 	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment),
-				goal, uspi->s_fpb, err, locked_page);
+				goal, nfrags, err, locked_page);
 
 	if (!tmp) {
 		*err = -ENOSPC;
@@ -402,7 +403,9 @@
 
 	if (!create) {
 		phys64 = ufs_frag_map(inode, offsets, depth);
-		goto out;
+		if (phys64)
+			map_bh(bh_result, sb, phys64 + frag);
+		return 0;
 	}
 
         /* This code entered only while writing ....? */
@@ -1207,7 +1210,7 @@
 	unsigned int ia_valid = attr->ia_valid;
 	int error;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
--- linux-4.4.0.orig/fs/ufs/namei.c
+++ linux-4.4.0/fs/ufs/namei.c
@@ -38,8 +38,7 @@
 {
 	int err = ufs_add_link(dentry, inode);
 	if (!err) {
-		unlock_new_inode(inode);
-		d_instantiate(dentry, inode);
+		d_instantiate_new(dentry, inode);
 		return 0;
 	}
 	inode_dec_link_count(inode);
@@ -191,8 +190,7 @@
 	if (err)
 		goto out_fail;
 
-	unlock_new_inode(inode);
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 	return 0;
 
 out_fail:
--- linux-4.4.0.orig/fs/ufs/super.c
+++ linux-4.4.0/fs/ufs/super.c
@@ -99,7 +99,7 @@
 	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
 	struct inode *inode;
 
-	if (ino < UFS_ROOTINO || ino > uspi->s_ncg * uspi->s_ipg)
+	if (ino < UFS_ROOTINO || ino > (u64)uspi->s_ncg * uspi->s_ipg)
 		return ERR_PTR(-ESTALE);
 
 	inode = ufs_iget(sb, ino);
@@ -746,6 +746,23 @@
 	return;
 }
 
+static u64 ufs_max_bytes(struct super_block *sb)
+{
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+	int bits = uspi->s_apbshift;
+	u64 res;
+
+	if (bits > 21)
+		res = ~0ULL;
+	else
+		res = UFS_NDADDR + (1LL << bits) + (1LL << (2*bits)) +
+			(1LL << (3*bits));
+
+	if (res >= (MAX_LFS_FILESIZE >> uspi->s_bshift))
+		return MAX_LFS_FILESIZE;
+	return res << uspi->s_bshift;
+}
+
 static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct ufs_sb_info * sbi;
@@ -1212,6 +1229,7 @@
 			    "fast symlink size (%u)\n", uspi->s_maxsymlinklen);
 		uspi->s_maxsymlinklen = maxsymlen;
 	}
+	sb->s_maxbytes = ufs_max_bytes(sb);
 	sb->s_max_links = UFS_LINK_MAX;
 
 	inode = ufs_iget(sb, UFS_ROOTINO);
--- linux-4.4.0.orig/fs/ufs/util.h
+++ linux-4.4.0/fs/ufs/util.h
@@ -228,7 +228,7 @@
 	case UFS_UID_44BSD:
 		return fs32_to_cpu(sb, inode->ui_u3.ui_44.ui_gid);
 	case UFS_UID_EFT:
-		if (inode->ui_u1.oldids.ui_suid == 0xFFFF)
+		if (inode->ui_u1.oldids.ui_sgid == 0xFFFF)
 			return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_gid);
 		/* Fall through */
 	default:
@@ -473,15 +473,19 @@
 static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
 	struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
 {
+	u8 mask;
 	switch (uspi->s_fpb) {
 	case 8:
 	    	return (*ubh_get_addr (ubh, begin + block) == 0xff);
 	case 4:
-		return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2)));
+		mask = 0x0f << ((block & 0x01) << 2);
+		return (*ubh_get_addr (ubh, begin + (block >> 1)) & mask) == mask;
 	case 2:
-		return (*ubh_get_addr (ubh, begin + (block >> 2)) == (0x03 << ((block & 0x03) << 1)));
+		mask = 0x03 << ((block & 0x03) << 1);
+		return (*ubh_get_addr (ubh, begin + (block >> 2)) & mask) == mask;
 	case 1:
-		return (*ubh_get_addr (ubh, begin + (block >> 3)) == (0x01 << (block & 0x07)));
+		mask = 0x01 << (block & 0x07);
+		return (*ubh_get_addr (ubh, begin + (block >> 3)) & mask) == mask;
 	}
 	return 0;	
 }
--- linux-4.4.0.orig/fs/userfaultfd.c
+++ linux-4.4.0/fs/userfaultfd.c
@@ -137,7 +137,7 @@
 		VM_BUG_ON(waitqueue_active(&ctx->fault_wqh));
 		VM_BUG_ON(spin_is_locked(&ctx->fd_wqh.lock));
 		VM_BUG_ON(waitqueue_active(&ctx->fd_wqh));
-		mmput(ctx->mm);
+		mmdrop(ctx->mm);
 		kmem_cache_free(userfaultfd_ctx_cachep, ctx);
 	}
 }
@@ -287,6 +287,12 @@
 		goto out;
 
 	/*
+	 * We don't do userfault handling for the final child pid update.
+	 */
+	if (current->flags & PF_EXITING)
+		goto out;
+
+	/*
 	 * Check that we can return VM_FAULT_RETRY.
 	 *
 	 * NOTE: it should become possible to return VM_FAULT_RETRY
@@ -380,7 +386,7 @@
 			 * in such case.
 			 */
 			down_read(&mm->mmap_sem);
-			ret = 0;
+			ret = VM_FAULT_NOPAGE;
 		}
 	}
 
@@ -425,9 +431,13 @@
 	/* len == 0 means wake all */
 	struct userfaultfd_wake_range range = { .len = 0, };
 	unsigned long new_flags;
+	bool still_valid;
 
 	ACCESS_ONCE(ctx->released) = true;
 
+	if (!mmget_not_zero(mm))
+		goto wakeup;
+
 	/*
 	 * Flush page faults out of all CPUs. NOTE: all page faults
 	 * must be retried without returning VM_FAULT_SIGBUS if
@@ -437,6 +447,7 @@
 	 * taking the mmap_sem for writing.
 	 */
 	down_write(&mm->mmap_sem);
+	still_valid = mmget_still_valid(mm);
 	prev = NULL;
 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
 		cond_resched();
@@ -447,20 +458,23 @@
 			continue;
 		}
 		new_flags = vma->vm_flags & ~(VM_UFFD_MISSING | VM_UFFD_WP);
-		prev = vma_merge(mm, prev, vma->vm_start, vma->vm_end,
-				 new_flags, vma->anon_vma,
-				 vma->vm_file, vma->vm_pgoff,
-				 vma_policy(vma),
-				 NULL_VM_UFFD_CTX);
-		if (prev)
-			vma = prev;
-		else
-			prev = vma;
+		if (still_valid) {
+			prev = vma_merge(mm, prev, vma->vm_start, vma->vm_end,
+					 new_flags, vma->anon_vma,
+					 vma->vm_file, vma->vm_pgoff,
+					 vma_policy(vma),
+					 NULL_VM_UFFD_CTX);
+			if (prev)
+				vma = prev;
+			else
+				prev = vma;
+		}
 		vma->vm_flags = new_flags;
 		vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
 	}
 	up_write(&mm->mmap_sem);
-
+	mmput(mm);
+wakeup:
 	/*
 	 * After no new page faults can wait on this fault_*wqh, flush
 	 * the last page faults that may have been already waiting on
@@ -754,10 +768,14 @@
 	start = uffdio_register.range.start;
 	end = start + uffdio_register.range.len;
 
+	ret = -ENOMEM;
+	if (!mmget_not_zero(mm))
+		goto out;
+
 	down_write(&mm->mmap_sem);
+	if (!mmget_still_valid(mm))
+		goto out_unlock;
 	vma = find_vma_prev(mm, start, &prev);
-
-	ret = -ENOMEM;
 	if (!vma)
 		goto out_unlock;
 
@@ -858,6 +876,7 @@
 	} while (vma && vma->vm_start < end);
 out_unlock:
 	up_write(&mm->mmap_sem);
+	mmput(mm);
 	if (!ret) {
 		/*
 		 * Now that we scanned all vmas we can already tell
@@ -896,10 +915,14 @@
 	start = uffdio_unregister.start;
 	end = start + uffdio_unregister.len;
 
+	ret = -ENOMEM;
+	if (!mmget_not_zero(mm))
+		goto out;
+
 	down_write(&mm->mmap_sem);
+	if (!mmget_still_valid(mm))
+		goto out_unlock;
 	vma = find_vma_prev(mm, start, &prev);
-
-	ret = -ENOMEM;
 	if (!vma)
 		goto out_unlock;
 
@@ -992,6 +1015,7 @@
 	} while (vma && vma->vm_start < end);
 out_unlock:
 	up_write(&mm->mmap_sem);
+	mmput(mm);
 out:
 	return ret;
 }
@@ -1061,9 +1085,11 @@
 		goto out;
 	if (uffdio_copy.mode & ~UFFDIO_COPY_MODE_DONTWAKE)
 		goto out;
-
-	ret = mcopy_atomic(ctx->mm, uffdio_copy.dst, uffdio_copy.src,
-			   uffdio_copy.len);
+	if (mmget_not_zero(ctx->mm)) {
+		ret = mcopy_atomic(ctx->mm, uffdio_copy.dst, uffdio_copy.src,
+				   uffdio_copy.len);
+		mmput(ctx->mm);
+	}
 	if (unlikely(put_user(ret, &user_uffdio_copy->copy)))
 		return -EFAULT;
 	if (ret < 0)
@@ -1104,8 +1130,11 @@
 	if (uffdio_zeropage.mode & ~UFFDIO_ZEROPAGE_MODE_DONTWAKE)
 		goto out;
 
-	ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start,
-			     uffdio_zeropage.range.len);
+	if (mmget_not_zero(ctx->mm)) {
+		ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start,
+				     uffdio_zeropage.range.len);
+		mmput(ctx->mm);
+	}
 	if (unlikely(put_user(ret, &user_uffdio_zeropage->zeropage)))
 		return -EFAULT;
 	if (ret < 0)
@@ -1283,12 +1312,12 @@
 	ctx->released = false;
 	ctx->mm = current->mm;
 	/* prevent the mm struct to be freed */
-	atomic_inc(&ctx->mm->mm_users);
+	atomic_inc(&ctx->mm->mm_count);
 
 	file = anon_inode_getfile("[userfaultfd]", &userfaultfd_fops, ctx,
 				  O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS));
 	if (IS_ERR(file)) {
-		mmput(ctx->mm);
+		mmdrop(ctx->mm);
 		kmem_cache_free(userfaultfd_ctx_cachep, ctx);
 	}
 out:
--- linux-4.4.0.orig/fs/utimes.c
+++ linux-4.4.0/fs/utimes.c
@@ -81,26 +81,13 @@
 			newattrs.ia_valid |= ATTR_MTIME_SET;
 		}
 		/*
-		 * Tell inode_change_ok(), that this is an explicit time
+		 * Tell setattr_prepare(), that this is an explicit time
 		 * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
 		 * were used.
 		 */
 		newattrs.ia_valid |= ATTR_TIMES_SET;
 	} else {
-		/*
-		 * If times is NULL (or both times are UTIME_NOW),
-		 * then we need to check permissions, because
-		 * inode_change_ok() won't do it.
-		 */
-		error = -EACCES;
-                if (IS_IMMUTABLE(inode))
-			goto mnt_drop_write_and_out;
-
-		if (!inode_owner_or_capable(inode)) {
-			error = inode_permission(inode, MAY_WRITE);
-			if (error)
-				goto mnt_drop_write_and_out;
-		}
+		newattrs.ia_valid |= ATTR_TOUCH;
 	}
 retry_deleg:
 	mutex_lock(&inode->i_mutex);
@@ -112,7 +99,6 @@
 			goto retry_deleg;
 	}
 
-mnt_drop_write_and_out:
 	mnt_drop_write(path->mnt);
 out:
 	return error;
--- linux-4.4.0.orig/fs/xattr.c
+++ linux-4.4.0/fs/xattr.c
@@ -38,6 +38,13 @@
 	if (mask & MAY_WRITE) {
 		if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 			return -EPERM;
+		/*
+		 * Updating an xattr will likely cause i_uid and i_gid
+		 * to be writen back improperly if their true value is
+		 * unknown to the vfs.
+		 */
+		if (HAS_UNMAPPED_ID(inode))
+			return -EPERM;
 	}
 
 	/*
@@ -123,11 +130,19 @@
 		size_t size, int flags)
 {
 	struct inode *inode = dentry->d_inode;
+	const void  *orig_value = value;
 	int error;
 
+	if (size && strcmp(name, XATTR_NAME_CAPS) == 0) {
+		error = cap_convert_nscap(dentry, &value, size);
+		if (error < 0)
+			return error;
+		size = error;
+	}
+
 	error = xattr_permission(inode, name, MAY_WRITE);
 	if (error)
-		return error;
+		goto out_free;
 
 	mutex_lock(&inode->i_mutex);
 	error = security_inode_setxattr(dentry, name, value, size, flags);
@@ -138,6 +153,10 @@
 
 out:
 	mutex_unlock(&inode->i_mutex);
+out_free:
+	if (value != orig_value)
+		kfree(value);
+
 	return error;
 }
 EXPORT_SYMBOL_GPL(vfs_setxattr);
@@ -163,7 +182,7 @@
 	}
 	memcpy(value, buffer, len);
 out:
-	security_release_secctx(buffer, len);
+	kfree(buffer);
 out_noalloc:
 	return len;
 }
@@ -207,6 +226,7 @@
 	*xattr_value = value;
 	return error;
 }
+EXPORT_SYMBOL(vfs_getxattr_alloc);
 
 /* Compare an extended attribute value with the given value */
 int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
@@ -442,7 +462,7 @@
 			size = XATTR_SIZE_MAX;
 		kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
 		if (!kvalue) {
-			vvalue = vmalloc(size);
+			vvalue = vzalloc(size);
 			if (!vvalue)
 				return -ENOMEM;
 			kvalue = vvalue;
@@ -453,7 +473,7 @@
 	if (error > 0) {
 		if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
 		    (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
-			posix_acl_fix_xattr_to_user(kvalue, size);
+			posix_acl_fix_xattr_to_user(kvalue, error);
 		if (size && copy_to_user(value, kvalue, error))
 			error = -EFAULT;
 	} else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
@@ -735,6 +755,8 @@
 
 	if (!buffer) {
 		for_each_xattr_handler(handlers, handler) {
+			if (!handler->list)
+				continue;
 			size += handler->list(handler, dentry, NULL, 0,
 					      NULL, 0);
 		}
@@ -742,6 +764,8 @@
 		char *buf = buffer;
 
 		for_each_xattr_handler(handlers, handler) {
+			if (!handler->list)
+				continue;
 			size = handler->list(handler, dentry, buf, buffer_size,
 					     NULL, 0);
 			if (size > buffer_size)
--- linux-4.4.0.orig/fs/xfs/kmem.c
+++ linux-4.4.0/fs/xfs/kmem.c
@@ -24,24 +24,6 @@
 #include "kmem.h"
 #include "xfs_message.h"
 
-/*
- * Greedy allocation.  May fail and may return vmalloced memory.
- */
-void *
-kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize)
-{
-	void		*ptr;
-	size_t		kmsize = maxsize;
-
-	while (!(ptr = vzalloc(kmsize))) {
-		if ((kmsize >>= 1) <= minsize)
-			kmsize = minsize;
-	}
-	if (ptr)
-		*size = kmsize;
-	return ptr;
-}
-
 void *
 kmem_alloc(size_t size, xfs_km_flags_t flags)
 {
--- linux-4.4.0.orig/fs/xfs/kmem.h
+++ linux-4.4.0/fs/xfs/kmem.h
@@ -69,8 +69,6 @@
 }
 
 
-extern void *kmem_zalloc_greedy(size_t *, size_t, size_t);
-
 static inline void *
 kmem_zalloc(size_t size, xfs_km_flags_t flags)
 {
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_alloc.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_alloc.c
@@ -535,6 +535,7 @@
 }
 
 const struct xfs_buf_ops xfs_agfl_buf_ops = {
+	.name = "xfs_agfl",
 	.verify_read = xfs_agfl_read_verify,
 	.verify_write = xfs_agfl_write_verify,
 };
@@ -1923,6 +1924,93 @@
 }
 
 /*
+ * Check the agfl fields of the agf for inconsistency or corruption. The purpose
+ * is to detect an agfl header padding mismatch between current and early v5
+ * kernels. This problem manifests as a 1-slot size difference between the
+ * on-disk flcount and the active [first, last] range of a wrapped agfl. This
+ * may also catch variants of agfl count corruption unrelated to padding. Either
+ * way, we'll reset the agfl and warn the user.
+ *
+ * Return true if a reset is required before the agfl can be used, false
+ * otherwise.
+ */
+static bool
+xfs_agfl_needs_reset(
+	struct xfs_mount	*mp,
+	struct xfs_agf		*agf)
+{
+	uint32_t		f = be32_to_cpu(agf->agf_flfirst);
+	uint32_t		l = be32_to_cpu(agf->agf_fllast);
+	uint32_t		c = be32_to_cpu(agf->agf_flcount);
+	int			agfl_size = XFS_AGFL_SIZE(mp);
+	int			active;
+
+	/* no agfl header on v4 supers */
+	if (!xfs_sb_version_hascrc(&mp->m_sb))
+		return false;
+
+	/*
+	 * The agf read verifier catches severe corruption of these fields.
+	 * Repeat some sanity checks to cover a packed -> unpacked mismatch if
+	 * the verifier allows it.
+	 */
+	if (f >= agfl_size || l >= agfl_size)
+		return true;
+	if (c > agfl_size)
+		return true;
+
+	/*
+	 * Check consistency between the on-disk count and the active range. An
+	 * agfl padding mismatch manifests as an inconsistent flcount.
+	 */
+	if (c && l >= f)
+		active = l - f + 1;
+	else if (c)
+		active = agfl_size - f + l + 1;
+	else
+		active = 0;
+
+	return active != c;
+}
+
+/*
+ * Reset the agfl to an empty state. Ignore/drop any existing blocks since the
+ * agfl content cannot be trusted. Warn the user that a repair is required to
+ * recover leaked blocks.
+ *
+ * The purpose of this mechanism is to handle filesystems affected by the agfl
+ * header padding mismatch problem. A reset keeps the filesystem online with a
+ * relatively minor free space accounting inconsistency rather than suffer the
+ * inevitable crash from use of an invalid agfl block.
+ */
+static void
+xfs_agfl_reset(
+	struct xfs_trans	*tp,
+	struct xfs_buf		*agbp,
+	struct xfs_perag	*pag)
+{
+	struct xfs_mount	*mp = tp->t_mountp;
+	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
+
+	ASSERT(pag->pagf_agflreset);
+	trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_);
+
+	xfs_warn(mp,
+	       "WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. "
+	       "Please unmount and run xfs_repair.",
+	         pag->pag_agno, pag->pagf_flcount);
+
+	agf->agf_flfirst = 0;
+	agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1);
+	agf->agf_flcount = 0;
+	xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST |
+				    XFS_AGF_FLCOUNT);
+
+	pag->pagf_flcount = 0;
+	pag->pagf_agflreset = false;
+}
+
+/*
  * Decide whether to use this allocation group for this allocation.
  * If so, fix up the btree freelist's size.
  */
@@ -1982,6 +2070,10 @@
 		}
 	}
 
+	/* reset a padding mismatched agfl before final free space check */
+	if (pag->pagf_agflreset)
+		xfs_agfl_reset(tp, agbp, pag);
+
 	/* If there isn't enough total space or single-extent, reject it. */
 	need = xfs_alloc_min_freelist(mp, pag);
 	if (!xfs_alloc_space_available(args, need, flags))
@@ -2120,6 +2212,7 @@
 		agf->agf_flfirst = 0;
 
 	pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
+	ASSERT(!pag->pagf_agflreset);
 	be32_add_cpu(&agf->agf_flcount, -1);
 	xfs_trans_agflist_delta(tp, -1);
 	pag->pagf_flcount--;
@@ -2225,6 +2318,7 @@
 		agf->agf_fllast = 0;
 
 	pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
+	ASSERT(!pag->pagf_agflreset);
 	be32_add_cpu(&agf->agf_flcount, 1);
 	xfs_trans_agflist_delta(tp, 1);
 	pag->pagf_flcount++;
@@ -2277,6 +2371,13 @@
 	      be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
 		return false;
 
+	if (be32_to_cpu(agf->agf_length) > mp->m_sb.sb_dblocks)
+		return false;
+
+	if (be32_to_cpu(agf->agf_freeblks) < be32_to_cpu(agf->agf_longest) ||
+	    be32_to_cpu(agf->agf_freeblks) > be32_to_cpu(agf->agf_length))
+		return false;
+
 	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
 	    be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
 		return false;
@@ -2339,6 +2440,7 @@
 }
 
 const struct xfs_buf_ops xfs_agf_buf_ops = {
+	.name = "xfs_agf",
 	.verify_read = xfs_agf_read_verify,
 	.verify_write = xfs_agf_write_verify,
 };
@@ -2415,6 +2517,7 @@
 		pag->pagb_count = 0;
 		pag->pagb_tree = RB_ROOT;
 		pag->pagf_init = 1;
+		pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf);
 	}
 #ifdef DEBUG
 	else if (!XFS_FORCED_SHUTDOWN(mp)) {
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_alloc_btree.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -379,6 +379,7 @@
 }
 
 const struct xfs_buf_ops xfs_allocbt_buf_ops = {
+	.name = "xfs_allocbt",
 	.verify_read = xfs_allocbt_read_verify,
 	.verify_write = xfs_allocbt_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_attr.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_attr.c
@@ -130,9 +130,6 @@
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return -EIO;
 
-	if (!xfs_inode_hasattr(ip))
-		return -ENOATTR;
-
 	error = xfs_attr_args_init(&args, ip, name, flags);
 	if (error)
 		return error;
@@ -417,9 +414,6 @@
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	if (!xfs_inode_hasattr(dp))
-		return -ENOATTR;
-
 	error = xfs_attr_args_init(&args, dp, name, flags);
 	if (error)
 		return error;
@@ -534,7 +528,14 @@
 		if (args->flags & ATTR_CREATE)
 			return retval;
 		retval = xfs_attr_shortform_remove(args);
-		ASSERT(retval == 0);
+		if (retval)
+			return retval;
+		/*
+		 * Since we have removed the old attr, clear ATTR_REPLACE so
+		 * that the leaf format add routine won't trip over the attr
+		 * not being around.
+		 */
+		args->flags &= ~ATTR_REPLACE;
 	}
 
 	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_attr_leaf.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -328,6 +328,7 @@
 }
 
 const struct xfs_buf_ops xfs_attr3_leaf_buf_ops = {
+	.name = "xfs_attr3_leaf",
 	.verify_read = xfs_attr3_leaf_read_verify,
 	.verify_write = xfs_attr3_leaf_write_verify,
 };
@@ -513,8 +514,8 @@
 		ASSERT(ifp->if_flags & XFS_IFINLINE);
 	}
 	xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK);
-	hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data;
-	hdr->count = 0;
+	hdr = (struct xfs_attr_sf_hdr *)ifp->if_u1.if_data;
+	memset(hdr, 0, sizeof(*hdr));
 	hdr->totsize = cpu_to_be16(sizeof(*hdr));
 	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
 }
@@ -778,9 +779,8 @@
 	ASSERT(blkno == 0);
 	error = xfs_attr3_leaf_create(args, blkno, &bp);
 	if (error) {
-		error = xfs_da_shrink_inode(args, 0, bp);
-		bp = NULL;
-		if (error)
+		/* xfs_attr3_leaf_create may not have instantiated a block */
+		if (bp && (xfs_da_shrink_inode(args, 0, bp) != 0))
 			goto out;
 		xfs_idata_realloc(dp, size, XFS_ATTR_FORK);	/* try to put */
 		memcpy(ifp->if_u1.if_data, tmpbuffer, size);	/* it back */
@@ -1326,7 +1326,9 @@
 	for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
 		if (ichdr->freemap[i].base == tmp) {
 			ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t);
-			ichdr->freemap[i].size -= sizeof(xfs_attr_leaf_entry_t);
+			ichdr->freemap[i].size -=
+				min_t(uint16_t, ichdr->freemap[i].size,
+						sizeof(xfs_attr_leaf_entry_t));
 		}
 	}
 	ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index);
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_attr_remote.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_attr_remote.c
@@ -201,6 +201,7 @@
 }
 
 const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
+	.name = "xfs_attr3_rmt",
 	.verify_read = xfs_attr3_rmt_read_verify,
 	.verify_write = xfs_attr3_rmt_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_bmap.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_bmap.c
@@ -793,6 +793,8 @@
 	*logflagsp = 0;
 	if ((error = xfs_alloc_vextent(&args))) {
 		xfs_iroot_realloc(ip, -1, whichfork);
+		ASSERT(ifp->if_broot == NULL);
+		XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
 		xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
 		return error;
 	}
@@ -2179,8 +2181,10 @@
 		}
 		temp = xfs_bmap_worst_indlen(bma->ip, temp);
 		temp2 = xfs_bmap_worst_indlen(bma->ip, temp2);
-		diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) -
-			(bma->cur ? bma->cur->bc_private.b.allocated : 0));
+		diff = (int)(temp + temp2 -
+			     (startblockval(PREV.br_startblock) -
+			      (bma->cur ?
+			       bma->cur->bc_private.b.allocated : 0)));
 		if (diff > 0) {
 			error = xfs_mod_fdblocks(bma->ip->i_mount,
 						 -((int64_t)diff), false);
@@ -2232,7 +2236,6 @@
 		temp = da_new;
 		if (bma->cur)
 			temp += bma->cur->bc_private.b.allocated;
-		ASSERT(temp <= da_old);
 		if (temp < da_old)
 			xfs_mod_fdblocks(bma->ip->i_mount,
 					(int64_t)(da_old - temp), false);
@@ -2669,7 +2672,7 @@
 					&i)))
 				goto done;
 			XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
-			cur->bc_rec.b.br_state = XFS_EXT_NORM;
+			cur->bc_rec.b.br_state = new->br_state;
 			if ((error = xfs_btree_insert(cur, &i)))
 				goto done;
 			XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_bmap_btree.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -720,6 +720,7 @@
 }
 
 const struct xfs_buf_ops xfs_bmbt_buf_ops = {
+	.name = "xfs_bmbt",
 	.verify_read = xfs_bmbt_read_verify,
 	.verify_write = xfs_bmbt_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_btree.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_btree.c
@@ -4064,7 +4064,7 @@
 			xfs_btree_readahead_ptr(cur, ptr, 1);
 
 			/* save for the next iteration of the loop */
-			lptr = *ptr;
+			xfs_btree_copy_ptrs(cur, &lptr, ptr, 1);
 		}
 
 		/* for each buffer in the level */
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_da_btree.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_da_btree.c
@@ -245,6 +245,7 @@
 }
 
 const struct xfs_buf_ops xfs_da3_node_buf_ops = {
+	.name = "xfs_da3_node",
 	.verify_read = xfs_da3_node_read_verify,
 	.verify_write = xfs_da3_node_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_dir2.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_dir2.c
@@ -630,7 +630,8 @@
 	if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
 		return rval;
 	rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
-	ASSERT(rval == 0 || args->dp->i_d.di_size == args->geo->blksize);
+	if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
+		return -EFSCORRUPTED;
 	*vp = rval;
 	return 0;
 }
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_dir2_block.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_dir2_block.c
@@ -123,6 +123,7 @@
 }
 
 const struct xfs_buf_ops xfs_dir3_block_buf_ops = {
+	.name = "xfs_dir3_block",
 	.verify_read = xfs_dir3_block_read_verify,
 	.verify_write = xfs_dir3_block_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_dir2_data.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_dir2_data.c
@@ -305,11 +305,13 @@
 }
 
 const struct xfs_buf_ops xfs_dir3_data_buf_ops = {
+	.name = "xfs_dir3_data",
 	.verify_read = xfs_dir3_data_read_verify,
 	.verify_write = xfs_dir3_data_write_verify,
 };
 
 static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = {
+	.name = "xfs_dir3_data_reada",
 	.verify_read = xfs_dir3_data_reada_verify,
 	.verify_write = xfs_dir3_data_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -245,11 +245,13 @@
 }
 
 const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = {
+	.name = "xfs_dir3_leaf1",
 	.verify_read = xfs_dir3_leaf1_read_verify,
 	.verify_write = xfs_dir3_leaf1_write_verify,
 };
 
 const struct xfs_buf_ops xfs_dir3_leafn_buf_ops = {
+	.name = "xfs_dir3_leafn",
 	.verify_read = xfs_dir3_leafn_read_verify,
 	.verify_write = xfs_dir3_leafn_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_dir2_node.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_dir2_node.c
@@ -150,6 +150,7 @@
 }
 
 const struct xfs_buf_ops xfs_dir3_free_buf_ops = {
+	.name = "xfs_dir3_free",
 	.verify_read = xfs_dir3_free_read_verify,
 	.verify_write = xfs_dir3_free_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_dquot_buf.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -54,7 +54,7 @@
 	xfs_dqid_t	 id,
 	uint		 type,	  /* used only when IO_dorepair is true */
 	uint		 flags,
-	char		 *str)
+	const char	 *str)
 {
 	xfs_dqblk_t	 *d = (xfs_dqblk_t *)ddq;
 	int		errs = 0;
@@ -191,8 +191,7 @@
 	if (mp->m_quotainfo)
 		ndquots = mp->m_quotainfo->qi_dqperchunk;
 	else
-		ndquots = xfs_calc_dquots_per_chunk(
-					XFS_BB_TO_FSB(mp, bp->b_length));
+		ndquots = xfs_calc_dquots_per_chunk(bp->b_length);
 
 	for (i = 0; i < ndquots; i++, d++) {
 		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
@@ -207,7 +206,8 @@
 STATIC bool
 xfs_dquot_buf_verify(
 	struct xfs_mount	*mp,
-	struct xfs_buf		*bp)
+	struct xfs_buf		*bp,
+	int			warn)
 {
 	struct xfs_dqblk	*d = (struct xfs_dqblk *)bp->b_addr;
 	xfs_dqid_t		id = 0;
@@ -240,8 +240,7 @@
 		if (i == 0)
 			id = be32_to_cpu(ddq->d_id);
 
-		error = xfs_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN,
-				       "xfs_dquot_buf_verify");
+		error = xfs_dqcheck(mp, ddq, id + i, 0, warn, __func__);
 		if (error)
 			return false;
 	}
@@ -256,7 +255,7 @@
 
 	if (!xfs_dquot_buf_verify_crc(mp, bp))
 		xfs_buf_ioerror(bp, -EFSBADCRC);
-	else if (!xfs_dquot_buf_verify(mp, bp))
+	else if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN))
 		xfs_buf_ioerror(bp, -EFSCORRUPTED);
 
 	if (bp->b_error)
@@ -264,6 +263,25 @@
 }
 
 /*
+ * readahead errors are silent and simply leave the buffer as !done so a real
+ * read will then be run with the xfs_dquot_buf_ops verifier. See
+ * xfs_inode_buf_verify() for why we use EIO and ~XBF_DONE here rather than
+ * reporting the failure.
+ */
+static void
+xfs_dquot_buf_readahead_verify(
+	struct xfs_buf	*bp)
+{
+	struct xfs_mount	*mp = bp->b_target->bt_mount;
+
+	if (!xfs_dquot_buf_verify_crc(mp, bp) ||
+	    !xfs_dquot_buf_verify(mp, bp, 0)) {
+		xfs_buf_ioerror(bp, -EIO);
+		bp->b_flags &= ~XBF_DONE;
+	}
+}
+
+/*
  * we don't calculate the CRC here as that is done when the dquot is flushed to
  * the buffer after the update is done. This ensures that the dquot in the
  * buffer always has an up-to-date CRC value.
@@ -274,7 +292,7 @@
 {
 	struct xfs_mount	*mp = bp->b_target->bt_mount;
 
-	if (!xfs_dquot_buf_verify(mp, bp)) {
+	if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN)) {
 		xfs_buf_ioerror(bp, -EFSCORRUPTED);
 		xfs_verifier_error(bp);
 		return;
@@ -282,7 +300,13 @@
 }
 
 const struct xfs_buf_ops xfs_dquot_buf_ops = {
+	.name = "xfs_dquot",
 	.verify_read = xfs_dquot_buf_read_verify,
 	.verify_write = xfs_dquot_buf_write_verify,
 };
 
+const struct xfs_buf_ops xfs_dquot_buf_ra_ops = {
+	.name = "xfs_dquot_ra",
+	.verify_read = xfs_dquot_buf_readahead_verify,
+	.verify_write = xfs_dquot_buf_write_verify,
+};
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_format.h
+++ linux-4.4.0/fs/xfs/libxfs/xfs_format.h
@@ -786,7 +786,7 @@
 	__be64		agfl_lsn;
 	__be32		agfl_crc;
 	__be32		agfl_bno[];	/* actually XFS_AGFL_SIZE(mp) */
-} xfs_agfl_t;
+} __attribute__((packed)) xfs_agfl_t;
 
 #define XFS_AGFL_CRC_OFF	offsetof(struct xfs_agfl, agfl_crc)
 
@@ -949,6 +949,9 @@
 		XFS_DFORK_DSIZE(dip, mp) : \
 		XFS_DFORK_ASIZE(dip, mp))
 
+#define XFS_DFORK_MAXEXT(dip, mp, w) \
+	(XFS_DFORK_SIZE(dip, mp, w) / sizeof(struct xfs_bmbt_rec))
+
 /*
  * Return pointers to the data or attribute forks.
  */
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_ialloc.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_ialloc.c
@@ -2572,6 +2572,7 @@
 }
 
 const struct xfs_buf_ops xfs_agi_buf_ops = {
+	.name = "xfs_agi",
 	.verify_read = xfs_agi_read_verify,
 	.verify_write = xfs_agi_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -304,6 +304,7 @@
 }
 
 const struct xfs_buf_ops xfs_inobt_buf_ops = {
+	.name = "xfs_inobt",
 	.verify_read = xfs_inobt_read_verify,
 	.verify_write = xfs_inobt_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_inode_buf.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_inode_buf.c
@@ -62,11 +62,14 @@
  * has not had the inode cores stamped into it. Hence for readahead, the buffer
  * may be potentially invalid.
  *
- * If the readahead buffer is invalid, we don't want to mark it with an error,
- * but we do want to clear the DONE status of the buffer so that a followup read
- * will re-read it from disk. This will ensure that we don't get an unnecessary
- * warnings during log recovery and we don't get unnecssary panics on debug
- * kernels.
+ * If the readahead buffer is invalid, we need to mark it with an error and
+ * clear the DONE status of the buffer so that a followup read will re-read it
+ * from disk. We don't report the error otherwise to avoid warnings during log
+ * recovery and we don't get unnecssary panics on debug kernels. We use EIO here
+ * because all we want to do is say readahead failed; there is no-one to report
+ * the error to, so this will distinguish it from a non-ra verifier failure.
+ * Changes to this readahead error behavour also need to be reflected in
+ * xfs_dquot_buf_readahead_verify().
  */
 static void
 xfs_inode_buf_verify(
@@ -93,6 +96,7 @@
 						XFS_RANDOM_ITOBP_INOTOBP))) {
 			if (readahead) {
 				bp->b_flags &= ~XBF_DONE;
+				xfs_buf_ioerror(bp, -EIO);
 				return;
 			}
 
@@ -132,11 +136,13 @@
 }
 
 const struct xfs_buf_ops xfs_inode_buf_ops = {
+	.name = "xfs_inode",
 	.verify_read = xfs_inode_buf_read_verify,
 	.verify_write = xfs_inode_buf_write_verify,
 };
 
 const struct xfs_buf_ops xfs_inode_buf_ra_ops = {
+	.name = "xxfs_inode_ra",
 	.verify_read = xfs_inode_buf_readahead_verify,
 	.verify_write = xfs_inode_buf_write_verify,
 };
@@ -284,15 +290,131 @@
 	}
 }
 
+static xfs_failaddr_t
+xfs_dinode_verify_fork(
+	struct xfs_dinode	*dip,
+	struct xfs_mount	*mp,
+	int			whichfork)
+{
+	uint32_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
+
+	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
+	case XFS_DINODE_FMT_LOCAL:
+		/*
+		 * no local regular files yet
+		 */
+		if (whichfork == XFS_DATA_FORK) {
+			if (S_ISREG(be16_to_cpu(dip->di_mode)))
+				return __this_address;
+			if (be64_to_cpu(dip->di_size) >
+					XFS_DFORK_SIZE(dip, mp, whichfork))
+				return __this_address;
+		}
+		if (di_nextents)
+			return __this_address;
+		break;
+	case XFS_DINODE_FMT_EXTENTS:
+		if (di_nextents > XFS_DFORK_MAXEXT(dip, mp, whichfork))
+			return __this_address;
+		break;
+	case XFS_DINODE_FMT_BTREE:
+		if (whichfork == XFS_ATTR_FORK) {
+			if (di_nextents > MAXAEXTNUM)
+				return __this_address;
+		} else if (di_nextents > MAXEXTNUM) {
+			return __this_address;
+		}
+		break;
+	default:
+		return __this_address;
+	}
+	return NULL;
+}
+
 static bool
 xfs_dinode_verify(
 	struct xfs_mount	*mp,
-	struct xfs_inode	*ip,
+	xfs_ino_t		ino,
 	struct xfs_dinode	*dip)
 {
+	xfs_failaddr_t		fa;
+	uint16_t		mode;
+	uint16_t		flags;
+	uint64_t		di_size;
+
 	if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
 		return false;
 
+	/* don't allow invalid i_size */
+	di_size = be64_to_cpu(dip->di_size);
+	if (di_size & (1ULL << 63))
+		return false;
+
+	mode = be16_to_cpu(dip->di_mode);
+
+	/* No zero-length symlinks/dirs. */
+	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
+		return false;
+
+	/* Fork checks carried over from xfs_iformat_fork */
+	if (mode &&
+	    be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) >
+			be64_to_cpu(dip->di_nblocks))
+		return false;
+
+	if (mode && XFS_DFORK_BOFF(dip) > mp->m_sb.sb_inodesize)
+		return false;
+
+	flags = be16_to_cpu(dip->di_flags);
+
+	if (mode && (flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)
+		return false;
+
+	/* Do we have appropriate data fork formats for the mode? */
+	switch (mode & S_IFMT) {
+	case S_IFIFO:
+	case S_IFCHR:
+	case S_IFBLK:
+	case S_IFSOCK:
+		if (dip->di_format != XFS_DINODE_FMT_DEV)
+			return false;
+		break;
+	case S_IFREG:
+	case S_IFLNK:
+	case S_IFDIR:
+		fa = xfs_dinode_verify_fork(dip, mp, XFS_DATA_FORK);
+		if (fa)
+			return false;
+		break;
+	case 0:
+		/* Uninitialized inode ok. */
+		break;
+	default:
+		return false;
+	}
+
+	if (XFS_DFORK_Q(dip)) {
+		fa = xfs_dinode_verify_fork(dip, mp, XFS_ATTR_FORK);
+		if (fa)
+			return false;
+	} else {
+		/*
+		 * If there is no fork offset, this may be a freshly-made inode
+		 * in a new disk cluster, in which case di_aformat is zeroed.
+		 * Otherwise, such an inode must be in EXTENTS format; this goes
+		 * for freed inodes as well.
+		 */
+		switch (dip->di_aformat) {
+		case 0:
+		case XFS_DINODE_FMT_EXTENTS:
+			break;
+		default:
+			return false;
+		}
+		if (dip->di_anextents)
+			return false;
+	}
+
 	/* only version 3 or greater inodes are extensively verified here */
 	if (dip->di_version < 3)
 		return true;
@@ -302,7 +424,7 @@
 	if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize,
 			      XFS_DINODE_CRC_OFF))
 		return false;
-	if (be64_to_cpu(dip->di_ino) != ip->i_ino)
+	if (be64_to_cpu(dip->di_ino) != ino)
 		return false;
 	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
@@ -380,7 +502,7 @@
 		return error;
 
 	/* even unallocated inodes are verified */
-	if (!xfs_dinode_verify(mp, ip, dip)) {
+	if (!xfs_dinode_verify(mp, ip->i_ino, dip)) {
 		xfs_alert(mp, "%s: validation failed for inode %lld failed",
 				__func__, ip->i_ino);
 
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_inode_fork.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_inode_fork.c
@@ -86,50 +86,11 @@
 	int			error = 0;
 	xfs_fsize_t             di_size;
 
-	if (unlikely(be32_to_cpu(dip->di_nextents) +
-		     be16_to_cpu(dip->di_anextents) >
-		     be64_to_cpu(dip->di_nblocks))) {
-		xfs_warn(ip->i_mount,
-			"corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",
-			(unsigned long long)ip->i_ino,
-			(int)(be32_to_cpu(dip->di_nextents) +
-			      be16_to_cpu(dip->di_anextents)),
-			(unsigned long long)
-				be64_to_cpu(dip->di_nblocks));
-		XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW,
-				     ip->i_mount, dip);
-		return -EFSCORRUPTED;
-	}
-
-	if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
-		xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.",
-			(unsigned long long)ip->i_ino,
-			dip->di_forkoff);
-		XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,
-				     ip->i_mount, dip);
-		return -EFSCORRUPTED;
-	}
-
-	if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
-		     !ip->i_mount->m_rtdev_targp)) {
-		xfs_warn(ip->i_mount,
-			"corrupt dinode %Lu, has realtime flag set.",
-			ip->i_ino);
-		XFS_CORRUPTION_ERROR("xfs_iformat(realtime)",
-				     XFS_ERRLEVEL_LOW, ip->i_mount, dip);
-		return -EFSCORRUPTED;
-	}
-
 	switch (ip->i_d.di_mode & S_IFMT) {
 	case S_IFIFO:
 	case S_IFCHR:
 	case S_IFBLK:
 	case S_IFSOCK:
-		if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) {
-			XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW,
-					      ip->i_mount, dip);
-			return -EFSCORRUPTED;
-		}
 		ip->i_d.di_size = 0;
 		ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
 		break;
@@ -139,32 +100,7 @@
 	case S_IFDIR:
 		switch (dip->di_format) {
 		case XFS_DINODE_FMT_LOCAL:
-			/*
-			 * no local regular files yet
-			 */
-			if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) {
-				xfs_warn(ip->i_mount,
-			"corrupt inode %Lu (local format for regular file).",
-					(unsigned long long) ip->i_ino);
-				XFS_CORRUPTION_ERROR("xfs_iformat(4)",
-						     XFS_ERRLEVEL_LOW,
-						     ip->i_mount, dip);
-				return -EFSCORRUPTED;
-			}
-
 			di_size = be64_to_cpu(dip->di_size);
-			if (unlikely(di_size < 0 ||
-				     di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
-				xfs_warn(ip->i_mount,
-			"corrupt inode %Lu (bad size %Ld for local inode).",
-					(unsigned long long) ip->i_ino,
-					(long long) di_size);
-				XFS_CORRUPTION_ERROR("xfs_iformat(5)",
-						     XFS_ERRLEVEL_LOW,
-						     ip->i_mount, dip);
-				return -EFSCORRUPTED;
-			}
-
 			size = (int)di_size;
 			error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size);
 			break;
@@ -175,14 +111,11 @@
 			error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
 			break;
 		default:
-			XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW,
-					 ip->i_mount);
 			return -EFSCORRUPTED;
 		}
 		break;
 
 	default:
-		XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount);
 		return -EFSCORRUPTED;
 	}
 	if (error) {
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_quota_defs.h
+++ linux-4.4.0/fs/xfs/libxfs/xfs_quota_defs.h
@@ -153,7 +153,7 @@
 #define XFS_QMOPT_RESBLK_MASK	(XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)
 
 extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq,
-		       xfs_dqid_t id, uint type, uint flags, char *str);
+		       xfs_dqid_t id, uint type, uint flags, const char *str);
 extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
 
 #endif	/* __XFS_QUOTA_H__ */
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_sb.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_sb.c
@@ -581,7 +581,8 @@
 	 * Only check the in progress field for the primary superblock as
 	 * mkfs.xfs doesn't clear it from secondary superblocks.
 	 */
-	return xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR,
+	return xfs_mount_validate_sb(mp, &sb,
+				     bp->b_maps[0].bm_bn == XFS_SB_DADDR,
 				     check_version);
 }
 
@@ -679,11 +680,13 @@
 }
 
 const struct xfs_buf_ops xfs_sb_buf_ops = {
+	.name = "xfs_sb",
 	.verify_read = xfs_sb_read_verify,
 	.verify_write = xfs_sb_write_verify,
 };
 
 const struct xfs_buf_ops xfs_sb_quiet_buf_ops = {
+	.name = "xfs_sb_quiet",
 	.verify_read = xfs_sb_quiet_read_verify,
 	.verify_write = xfs_sb_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_shared.h
+++ linux-4.4.0/fs/xfs/libxfs/xfs_shared.h
@@ -49,6 +49,7 @@
 extern const struct xfs_buf_ops xfs_inode_buf_ops;
 extern const struct xfs_buf_ops xfs_inode_buf_ra_ops;
 extern const struct xfs_buf_ops xfs_dquot_buf_ops;
+extern const struct xfs_buf_ops xfs_dquot_buf_ra_ops;
 extern const struct xfs_buf_ops xfs_sb_buf_ops;
 extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;
 extern const struct xfs_buf_ops xfs_symlink_buf_ops;
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_symlink_remote.c
+++ linux-4.4.0/fs/xfs/libxfs/xfs_symlink_remote.c
@@ -168,6 +168,7 @@
 }
 
 const struct xfs_buf_ops xfs_symlink_buf_ops = {
+	.name = "xfs_symlink",
 	.verify_read = xfs_symlink_read_verify,
 	.verify_write = xfs_symlink_write_verify,
 };
--- linux-4.4.0.orig/fs/xfs/libxfs/xfs_types.h
+++ linux-4.4.0/fs/xfs/libxfs/xfs_types.h
@@ -47,6 +47,13 @@
 typedef	__int64_t	xfs_srtblock_t;	/* signed version of xfs_rtblock_t */
 typedef __int64_t	xfs_sfiloff_t;	/* signed block number in a file */
 
+
+/*
+ * New verifiers will return the instruction address of the failing check.
+ * NULL means everything is ok.
+ */
+typedef void *		xfs_failaddr_t;
+
 /*
  * Null values for the types.
  */
--- linux-4.4.0.orig/fs/xfs/xfs_acl.c
+++ linux-4.4.0/fs/xfs/xfs_acl.c
@@ -288,16 +288,11 @@
 		return error;
 
 	if (type == ACL_TYPE_ACCESS) {
-		umode_t mode = inode->i_mode;
-		error = posix_acl_equiv_mode(acl, &mode);
-
-		if (error <= 0) {
-			acl = NULL;
-
-			if (error < 0)
-				return error;
-		}
+		umode_t mode;
 
+		error = posix_acl_update_mode(inode, &mode, &acl);
+		if (error)
+			return error;
 		error = xfs_set_mode(inode, mode);
 		if (error)
 			return error;
--- linux-4.4.0.orig/fs/xfs/xfs_aops.c
+++ linux-4.4.0/fs/xfs/xfs_aops.c
@@ -214,10 +214,12 @@
 	struct xfs_inode *ip = XFS_I(ioend->io_inode);
 	int		error = 0;
 
-	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+	/*
+	 * Set an error if the mount has shut down and proceed with end I/O
+	 * processing so it can perform whatever cleanups are necessary.
+	 */
+	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		ioend->io_error = -EIO;
-		goto done;
-	}
 
 	/*
 	 * For unwritten extents we need to issue transactions to convert a
@@ -288,7 +290,7 @@
 {
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_mount	*mp = ip->i_mount;
-	ssize_t			count = 1 << inode->i_blkbits;
+	ssize_t			count = i_blocksize(inode);
 	xfs_fileoff_t		offset_fsb, end_fsb;
 	int			error = 0;
 	int			bmapi_flags = XFS_BMAPI_ENTIRE;
@@ -310,7 +312,7 @@
 	       (ip->i_df.if_flags & XFS_IFEXTENTS));
 	ASSERT(offset <= mp->m_super->s_maxbytes);
 
-	if (offset + count > mp->m_super->s_maxbytes)
+	if ((xfs_ufsize_t)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);
@@ -921,7 +923,7 @@
 			break;
 		}
 next_buffer:
-		offset += 1 << inode->i_blkbits;
+		offset += i_blocksize(inode);
 
 	} while ((bh = bh->b_this_page) != head);
 
@@ -1360,10 +1362,10 @@
 	if (mapping_size > size)
 		mapping_size = size;
 	if (offset < i_size_read(inode) &&
-	    offset + mapping_size >= i_size_read(inode)) {
+	    (xfs_ufsize_t)offset + mapping_size >= i_size_read(inode)) {
 		/* limit mapping to block that spans EOF */
 		mapping_size = roundup_64(i_size_read(inode) - offset,
-					  1 << inode->i_blkbits);
+					  i_blocksize(inode));
 	}
 	if (mapping_size > LONG_MAX)
 		mapping_size = LONG_MAX;
@@ -1395,7 +1397,7 @@
 		return -EIO;
 
 	offset = (xfs_off_t)iblock << inode->i_blkbits;
-	ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
+	ASSERT(bh_result->b_size >= i_blocksize(inode));
 	size = bh_result->b_size;
 
 	if (!create && direct && offset >= i_size_read(inode))
@@ -1416,7 +1418,7 @@
 	}
 
 	ASSERT(offset <= mp->m_super->s_maxbytes);
-	if (offset + size > mp->m_super->s_maxbytes)
+	if ((xfs_ufsize_t)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);
@@ -1426,6 +1428,26 @@
 	if (error)
 		goto out_unlock;
 
+	/*
+	 * The only time we can ever safely find delalloc blocks on direct I/O
+	 * is a dio write to post-eof speculative preallocation. All other
+	 * scenarios are indicative of a problem or misuse (such as mixing
+	 * direct and mapped I/O).
+	 *
+	 * The file may be unmapped by the time we get here so we cannot
+	 * reliably fail the I/O based on mapping. Instead, fail the I/O if this
+	 * is a read or a write within eof. Otherwise, carry on but warn as a
+	 * precuation if the file happens to be mapped.
+	 */
+	if (direct && imap.br_startblock == DELAYSTARTBLOCK) {
+	        if (!create || offset < i_size_read(VFS_I(ip))) {
+	                WARN_ON_ONCE(1);
+	                error = -EIO;
+	                goto out_unlock;
+	        }
+	        WARN_ON_ONCE(mapping_mapped(VFS_I(ip)->i_mapping));
+	}
+
 	/* for DAX, we convert unwritten extents directly */
 	if (create &&
 	    (!nimaps ||
@@ -1525,7 +1547,6 @@
 		set_buffer_new(bh_result);
 
 	if (imap.br_startblock == DELAYSTARTBLOCK) {
-		BUG_ON(direct);
 		if (create) {
 			set_buffer_uptodate(bh_result);
 			set_buffer_mapped(bh_result);
@@ -1968,7 +1989,7 @@
 			if (offset < end_offset)
 				set_buffer_dirty(bh);
 			bh = bh->b_this_page;
-			offset += 1 << inode->i_blkbits;
+			offset += i_blocksize(inode);
 		} while (bh != head);
 	}
 	/*
--- linux-4.4.0.orig/fs/xfs/xfs_attr.h
+++ linux-4.4.0/fs/xfs/xfs_attr.h
@@ -112,6 +112,7 @@
  *========================================================================*/
 
 
+/* Return 0 on success, or -errno; other state communicated via *context */
 typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int,
 			      unsigned char *, int, int, unsigned char *);
 
--- linux-4.4.0.orig/fs/xfs/xfs_attr_inactive.c
+++ linux-4.4.0/fs/xfs/xfs_attr_inactive.c
@@ -302,6 +302,8 @@
 						 &bp, XFS_ATTR_FORK);
 			if (error)
 				return error;
+			node = bp->b_addr;
+			btree = dp->d_ops->node_tree_p(node);
 			child_fsb = be32_to_cpu(btree[i + 1].before);
 			xfs_trans_brelse(*trans, bp);
 		}
--- linux-4.4.0.orig/fs/xfs/xfs_attr_list.c
+++ linux-4.4.0/fs/xfs/xfs_attr_list.c
@@ -108,16 +108,14 @@
 					   (int)sfe->namelen,
 					   (int)sfe->valuelen,
 					   &sfe->nameval[sfe->namelen]);
-
+			if (error)
+				return error;
 			/*
 			 * Either search callback finished early or
 			 * didn't fit it all in the buffer after all.
 			 */
 			if (context->seen_enough)
 				break;
-
-			if (error)
-				return error;
 			sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
 		}
 		trace_xfs_attr_list_sf_all(context);
@@ -202,8 +200,10 @@
 					sbp->namelen,
 					sbp->valuelen,
 					&sbp->name[sbp->namelen]);
-		if (error)
+		if (error) {
+			kmem_free(sbuf);
 			return error;
+		}
 		if (context->seen_enough)
 			break;
 		cursor->offset++;
@@ -454,14 +454,13 @@
 				args.rmtblkcnt = xfs_attr3_rmt_blocks(
 							args.dp->i_mount, valuelen);
 				retval = xfs_attr_rmtval_get(&args);
-				if (retval)
-					return retval;
-				retval = context->put_listent(context,
-						entry->flags,
-						name_rmt->name,
-						(int)name_rmt->namelen,
-						valuelen,
-						args.value);
+				if (!retval)
+					retval = context->put_listent(context,
+							entry->flags,
+							name_rmt->name,
+							(int)name_rmt->namelen,
+							valuelen,
+							args.value);
 				kmem_free(args.value);
 			} else {
 				retval = context->put_listent(context,
@@ -580,7 +579,7 @@
 		trace_xfs_attr_list_full(context);
 		alist->al_more = 1;
 		context->seen_enough = 1;
-		return 1;
+		return 0;
 	}
 
 	aep = (attrlist_ent_t *)&context->alist[context->firstu];
--- linux-4.4.0.orig/fs/xfs/xfs_bmap_util.c
+++ linux-4.4.0/fs/xfs/xfs_bmap_util.c
@@ -682,7 +682,7 @@
 			 * extents.
 			 */
 			if (map[i].br_startblock == DELAYSTARTBLOCK &&
-			    map[i].br_startoff <= XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
+			    map[i].br_startoff < XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
 				ASSERT((iflags & BMV_IF_DELALLOC) != 0);
 
                         if (map[i].br_startblock == HOLESTARTBLOCK &&
@@ -961,6 +961,7 @@
 	xfs_filblks_t		allocatesize_fsb;
 	xfs_extlen_t		extsz, temp;
 	xfs_fileoff_t		startoffset_fsb;
+	xfs_fileoff_t		endoffset_fsb;
 	xfs_fsblock_t		firstfsb;
 	int			nimaps;
 	int			quota_flag;
@@ -991,7 +992,8 @@
 	imapp = &imaps[0];
 	nimaps = 1;
 	startoffset_fsb	= XFS_B_TO_FSBT(mp, offset);
-	allocatesize_fsb = XFS_B_TO_FSB(mp, count);
+	endoffset_fsb = XFS_B_TO_FSB(mp, offset + count);
+	allocatesize_fsb = endoffset_fsb - startoffset_fsb;
 
 	/*
 	 * Allocate file space until done or until there is an error
@@ -1713,6 +1715,7 @@
 	xfs_trans_t	*tp;
 	xfs_bstat_t	*sbp = &sxp->sx_stat;
 	xfs_ifork_t	*tempifp, *ifp, *tifp;
+	xfs_extnum_t	nextents;
 	int		src_log_flags, target_log_flags;
 	int		error = 0;
 	int		aforkblks = 0;
@@ -1899,7 +1902,8 @@
 		 * pointer.  Otherwise it's already NULL or
 		 * pointing to the extent.
 		 */
-		if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) {
+		nextents = ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+		if (nextents <= XFS_INLINE_EXTS) {
 			ifp->if_u1.if_extents =
 				ifp->if_u2.if_inline_ext;
 		}
@@ -1918,7 +1922,8 @@
 		 * pointer.  Otherwise it's already NULL or
 		 * pointing to the extent.
 		 */
-		if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) {
+		nextents = tip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+		if (nextents <= XFS_INLINE_EXTS) {
 			tifp->if_u1.if_extents =
 				tifp->if_u2.if_inline_ext;
 		}
--- linux-4.4.0.orig/fs/xfs/xfs_buf.c
+++ linux-4.4.0/fs/xfs/xfs_buf.c
@@ -375,6 +375,7 @@
 out_free_pages:
 	for (i = 0; i < bp->b_page_count; i++)
 		__free_page(bp->b_pages[i]);
+	bp->b_flags &= ~_XBF_PAGES;
 	return error;
 }
 
@@ -604,6 +605,13 @@
 		}
 	}
 
+	/*
+	 * Clear b_error if this is a lookup from a caller that doesn't expect
+	 * valid data to be found in the buffer.
+	 */
+	if (!(flags & XBF_READ))
+		xfs_buf_ioerror(bp, 0);
+
 	XFS_STATS_INC(target->bt_mount, xb_get);
 	trace_xfs_buf_get(bp, flags, _RET_IP_);
 	return bp;
@@ -674,7 +682,7 @@
 	int			nmaps,
 	const struct xfs_buf_ops *ops)
 {
-	if (bdi_read_congested(target->bt_bdi))
+	if (bdi_read_congested(target->bt_bdev->bd_bdi))
 		return;
 
 	xfs_buf_read_map(target, map, nmaps,
@@ -971,6 +979,8 @@
 xfs_buf_unlock(
 	struct xfs_buf		*bp)
 {
+	ASSERT(xfs_buf_islocked(bp));
+
 	XB_CLEAR_OWNER(bp);
 	up(&bp->b_sema);
 
@@ -1520,6 +1530,16 @@
 	LIST_HEAD(dispose);
 	int loop = 0;
 
+	/*
+	 * We need to flush the buffer workqueue to ensure that all IO
+	 * completion processing is 100% done. Just waiting on buffer locks is
+	 * not sufficient for async IO as the reference count held over IO is
+	 * not released until after the buffer lock is dropped. Hence we need to
+	 * ensure here that all reference counts have been dropped before we
+	 * start walking the LRU list.
+	 */
+	flush_workqueue(btp->bt_mount->m_buf_workqueue);
+
 	/* loop until there is nothing left on the lru list. */
 	while (list_lru_count(&btp->bt_lru)) {
 		list_lru_walk(&btp->bt_lru, xfs_buftarg_wait_rele,
@@ -1564,7 +1584,7 @@
 	 * zero. If the value is already zero, we need to reclaim the
 	 * buffer, otherwise it gets another trip through the LRU.
 	 */
-	if (!atomic_add_unless(&bp->b_lru_ref, -1, 0)) {
+	if (atomic_add_unless(&bp->b_lru_ref, -1, 0)) {
 		spin_unlock(&bp->b_lock);
 		return LRU_ROTATE;
 	}
@@ -1674,7 +1694,6 @@
 	btp->bt_mount = mp;
 	btp->bt_dev =  bdev->bd_dev;
 	btp->bt_bdev = bdev;
-	btp->bt_bdi = blk_get_backing_dev_info(bdev);
 
 	if (xfs_setsize_buftarg_early(btp, bdev))
 		goto error;
@@ -1695,6 +1714,28 @@
 }
 
 /*
+ * Cancel a delayed write list.
+ *
+ * Remove each buffer from the list, clear the delwri queue flag and drop the
+ * associated buffer reference.
+ */
+void
+xfs_buf_delwri_cancel(
+	struct list_head	*list)
+{
+	struct xfs_buf		*bp;
+
+	while (!list_empty(list)) {
+		bp = list_first_entry(list, struct xfs_buf, b_list);
+
+		xfs_buf_lock(bp);
+		bp->b_flags &= ~_XBF_DELWRI_Q;
+		list_del_init(&bp->b_list);
+		xfs_buf_relse(bp);
+	}
+}
+
+/*
  * Add a buffer to the delayed write list.
  *
  * This queues a buffer for writeout if it hasn't already been.  Note that
--- linux-4.4.0.orig/fs/xfs/xfs_buf.h
+++ linux-4.4.0/fs/xfs/xfs_buf.h
@@ -105,7 +105,6 @@
 typedef struct xfs_buftarg {
 	dev_t			bt_dev;
 	struct block_device	*bt_bdev;
-	struct backing_dev_info	*bt_bdi;
 	struct xfs_mount	*bt_mount;
 	unsigned int		bt_meta_sectorsize;
 	size_t			bt_meta_sectormask;
@@ -132,6 +131,7 @@
 	struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) };
 
 struct xfs_buf_ops {
+	char *name;
 	void (*verify_read)(struct xfs_buf *);
 	void (*verify_write)(struct xfs_buf *);
 };
@@ -303,6 +303,7 @@
 extern void *xfs_buf_offset(struct xfs_buf *, size_t);
 
 /* Delayed Write Buffer Routines */
+extern void xfs_buf_delwri_cancel(struct list_head *);
 extern bool xfs_buf_delwri_queue(struct xfs_buf *, struct list_head *);
 extern int xfs_buf_delwri_submit(struct list_head *);
 extern int xfs_buf_delwri_submit_nowait(struct list_head *);
--- linux-4.4.0.orig/fs/xfs/xfs_dir2_readdir.c
+++ linux-4.4.0/fs/xfs/xfs_dir2_readdir.c
@@ -406,6 +406,7 @@
 
 	/*
 	 * Do we need more readahead?
+	 * Each loop tries to process 1 full dir blk; last may be partial.
 	 */
 	blk_start_plug(&plug);
 	for (mip->ra_index = mip->ra_offset = i = 0;
@@ -416,7 +417,8 @@
 		 * Read-ahead a contiguous directory block.
 		 */
 		if (i > mip->ra_current &&
-		    map[mip->ra_index].br_blockcount >= geo->fsbcount) {
+		    (map[mip->ra_index].br_blockcount - mip->ra_offset) >=
+		    geo->fsbcount) {
 			xfs_dir3_data_readahead(dp,
 				map[mip->ra_index].br_startoff + mip->ra_offset,
 				XFS_FSB_TO_DADDR(dp->i_mount,
@@ -437,14 +439,19 @@
 		}
 
 		/*
-		 * Advance offset through the mapping table.
+		 * Advance offset through the mapping table, processing a full
+		 * dir block even if it is fragmented into several extents.
+		 * But stop if we have consumed all valid mappings, even if
+		 * it's not yet a full directory block.
 		 */
-		for (j = 0; j < geo->fsbcount; j += length ) {
+		for (j = 0;
+		     j < geo->fsbcount && mip->ra_index < mip->map_valid;
+		     j += length ) {
 			/*
 			 * The rest of this extent but not more than a dir
 			 * block.
 			 */
-			length = min_t(int, geo->fsbcount,
+			length = min_t(int, geo->fsbcount - j,
 					map[mip->ra_index].br_blockcount -
 							mip->ra_offset);
 			mip->ra_offset += length;
--- linux-4.4.0.orig/fs/xfs/xfs_discard.c
+++ linux-4.4.0/fs/xfs/xfs_discard.c
@@ -50,19 +50,19 @@
 
 	pag = xfs_perag_get(mp, agno);
 
-	error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
-	if (error || !agbp)
-		goto out_put_perag;
-
-	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
-
 	/*
 	 * Force out the log.  This means any transactions that might have freed
-	 * space before we took the AGF buffer lock are now on disk, and the
+	 * space before we take the AGF buffer lock are now on disk, and the
 	 * volatile disk cache is flushed.
 	 */
 	xfs_log_force(mp, XFS_LOG_SYNC);
 
+	error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
+	if (error || !agbp)
+		goto out_put_perag;
+
+	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
+
 	/*
 	 * Look up the longest btree in the AGF and start with it.
 	 */
--- linux-4.4.0.orig/fs/xfs/xfs_error.c
+++ linux-4.4.0/fs/xfs/xfs_error.c
@@ -164,9 +164,9 @@
 {
 	struct xfs_mount *mp = bp->b_target->bt_mount;
 
-	xfs_alert(mp, "Metadata %s detected at %pF, block 0x%llx",
+	xfs_alert(mp, "Metadata %s detected at %pF, %s block 0x%llx",
 		  bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
-		  __return_address, bp->b_bn);
+		  __return_address, bp->b_ops->name, bp->b_bn);
 
 	xfs_alert(mp, "Unmount and run xfs_repair");
 
--- linux-4.4.0.orig/fs/xfs/xfs_file.c
+++ linux-4.4.0/fs/xfs/xfs_file.c
@@ -947,7 +947,7 @@
 		if (error)
 			goto out_unlock;
 	} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
-		unsigned blksize_mask = (1 << inode->i_blkbits) - 1;
+		unsigned int blksize_mask = i_blocksize(inode) - 1;
 
 		if (offset & blksize_mask || len & blksize_mask) {
 			error = -EINVAL;
@@ -969,22 +969,26 @@
 		if (error)
 			goto out_unlock;
 	} else if (mode & FALLOC_FL_INSERT_RANGE) {
-		unsigned blksize_mask = (1 << inode->i_blkbits) - 1;
+		unsigned int	blksize_mask = i_blocksize(inode) - 1;
+		loff_t		isize = i_size_read(inode);
 
-		new_size = i_size_read(inode) + len;
 		if (offset & blksize_mask || len & blksize_mask) {
 			error = -EINVAL;
 			goto out_unlock;
 		}
 
-		/* check the new inode size does not wrap through zero */
-		if (new_size > inode->i_sb->s_maxbytes) {
+		/*
+		 * New inode size must not exceed ->s_maxbytes, accounting for
+		 * possible signed overflow.
+		 */
+		if (inode->i_sb->s_maxbytes - isize < len) {
 			error = -EFBIG;
 			goto out_unlock;
 		}
+		new_size = isize + len;
 
 		/* Offset should be less than i_size */
-		if (offset >= i_size_read(inode)) {
+		if (offset >= isize) {
 			error = -EINVAL;
 			goto out_unlock;
 		}
@@ -1022,7 +1026,7 @@
 
 		iattr.ia_valid = ATTR_SIZE;
 		iattr.ia_size = new_size;
-		error = xfs_setattr_size(ip, &iattr);
+		error = xfs_vn_setattr_size(file_dentry(file), &iattr);
 		if (error)
 			goto out_unlock;
 	}
@@ -1208,7 +1212,7 @@
 		unsigned	nr_pages;
 		unsigned int	i;
 
-		want = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
+		want = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1;
 		nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
 					  want);
 		/*
@@ -1235,17 +1239,6 @@
 			break;
 		}
 
-		/*
-		 * At lease we found one page.  If this is the first time we
-		 * step into the loop, and if the first page index offset is
-		 * greater than the given search offset, a hole was found.
-		 */
-		if (type == HOLE_OFF && lastoff == startoff &&
-		    lastoff < page_offset(pvec.pages[0])) {
-			found = true;
-			break;
-		}
-
 		for (i = 0; i < nr_pages; i++) {
 			struct page	*page = pvec.pages[i];
 			loff_t		b_offset;
@@ -1257,18 +1250,18 @@
 			 * file mapping. However, page->index will not change
 			 * because we have a reference on the page.
 			 *
-			 * Searching done if the page index is out of range.
-			 * If the current offset is not reaches the end of
-			 * the specified search range, there should be a hole
-			 * between them.
+			 * If current page offset is beyond where we've ended,
+			 * we've found a hole.
 			 */
-			if (page->index > end) {
-				if (type == HOLE_OFF && lastoff < endoff) {
-					*offset = lastoff;
-					found = true;
-				}
+			if (type == HOLE_OFF && lastoff < endoff &&
+			    lastoff < page_offset(pvec.pages[i])) {
+				found = true;
+				*offset = lastoff;
 				goto out;
 			}
+			/* Searching done if the page index is out of range. */
+			if (page->index > end)
+				goto out;
 
 			lock_page(page);
 			/*
--- linux-4.4.0.orig/fs/xfs/xfs_fsops.c
+++ linux-4.4.0/fs/xfs/xfs_fsops.c
@@ -243,8 +243,8 @@
 		agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp));
 		agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1);
 		agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1);
-		agf->agf_flfirst = 0;
-		agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1);
+		agf->agf_flfirst = cpu_to_be32(1);
+		agf->agf_fllast = 0;
 		agf->agf_flcount = 0;
 		tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);
 		agf->agf_freeblks = cpu_to_be32(tmpsize);
--- linux-4.4.0.orig/fs/xfs/xfs_icache.c
+++ linux-4.4.0/fs/xfs/xfs_icache.c
@@ -135,6 +135,46 @@
 }
 
 /*
+ * If we are allocating a new inode, then check what was returned is
+ * actually a free, empty inode. If we are not allocating an inode,
+ * then check we didn't find a free inode.
+ *
+ * Returns:
+ *	0		if the inode free state matches the lookup context
+ *	-ENOENT		if the inode is free and we are not allocating
+ *	-EFSCORRUPTED	if there is any state mismatch at all
+ */
+static int
+xfs_iget_check_free_state(
+	struct xfs_inode	*ip,
+	int			flags)
+{
+	if (flags & XFS_IGET_CREATE) {
+		/* should be a free inode */
+		if (ip->i_d.di_mode != 0) {
+			xfs_warn(ip->i_mount,
+"Corruption detected! Free inode 0x%llx not marked free! (mode 0x%x)",
+				ip->i_ino, ip->i_d.di_mode);
+			return -EFSCORRUPTED;
+		}
+
+		if (ip->i_d.di_nblocks != 0) {
+			xfs_warn(ip->i_mount,
+"Corruption detected! Free inode 0x%llx has blocks allocated!",
+				ip->i_ino);
+			return -EFSCORRUPTED;
+		}
+		return 0;
+	}
+
+	/* should be an allocated inode */
+	if (ip->i_d.di_mode == 0)
+		return -ENOENT;
+
+	return 0;
+}
+
+/*
  * Check the validity of the inode we just found it the cache
  */
 static int
@@ -183,12 +223,12 @@
 	}
 
 	/*
-	 * If lookup is racing with unlink return an error immediately.
+	 * Check the inode free state is valid. This also detects lookup
+	 * racing with unlinks.
 	 */
-	if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {
-		error = -ENOENT;
+	error = xfs_iget_check_free_state(ip, flags);
+	if (error)
 		goto out_error;
-	}
 
 	/*
 	 * If IRECLAIMABLE is set, we've torn down the VFS inode already.
@@ -210,14 +250,17 @@
 
 		error = inode_init_always(mp->m_super, inode);
 		if (error) {
+			bool wake;
 			/*
 			 * Re-initializing the inode failed, and we are in deep
 			 * trouble.  Try to re-add it to the reclaim list.
 			 */
 			rcu_read_lock();
 			spin_lock(&ip->i_flags_lock);
-
+			wake = !!__xfs_iflags_test(ip, XFS_INEW);
 			ip->i_flags &= ~(XFS_INEW | XFS_IRECLAIM);
+			if (wake)
+				wake_up_bit(&ip->i_flags, __XFS_INEW_BIT);
 			ASSERT(ip->i_flags & XFS_IRECLAIMABLE);
 			trace_xfs_iget_reclaim_fail(ip);
 			goto out_error;
@@ -295,10 +338,14 @@
 
 	trace_xfs_iget_miss(ip);
 
-	if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
-		error = -ENOENT;
+
+	/*
+	 * Check the inode free state is valid. This also detects lookup
+	 * racing with unlinks.
+	 */
+	error = xfs_iget_check_free_state(ip, flags);
+	if (error)
 		goto out_destroy;
-	}
 
 	/*
 	 * Preload the radix tree so we can insert safely under the
@@ -363,6 +410,22 @@
 	return error;
 }
 
+static void
+xfs_inew_wait(
+	struct xfs_inode	*ip)
+{
+	wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_INEW_BIT);
+	DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_INEW_BIT);
+
+	do {
+		prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
+		if (!xfs_iflags_test(ip, XFS_INEW))
+			break;
+		schedule();
+	} while (true);
+	finish_wait(wq, &wait.wait);
+}
+
 /*
  * Look up an inode by number in the given file system.
  * The inode is looked up in the cache held in each AG.
@@ -467,9 +530,11 @@
 
 STATIC int
 xfs_inode_ag_walk_grab(
-	struct xfs_inode	*ip)
+	struct xfs_inode	*ip,
+	int			flags)
 {
 	struct inode		*inode = VFS_I(ip);
+	bool			newinos = !!(flags & XFS_AGITER_INEW_WAIT);
 
 	ASSERT(rcu_read_lock_held());
 
@@ -487,7 +552,8 @@
 		goto out_unlock_noent;
 
 	/* avoid new or reclaimable inodes. Leave for reclaim code to flush */
-	if (__xfs_iflags_test(ip, XFS_INEW | XFS_IRECLAIMABLE | XFS_IRECLAIM))
+	if ((!newinos && __xfs_iflags_test(ip, XFS_INEW)) ||
+	    __xfs_iflags_test(ip, XFS_IRECLAIMABLE | XFS_IRECLAIM))
 		goto out_unlock_noent;
 	spin_unlock(&ip->i_flags_lock);
 
@@ -515,7 +581,8 @@
 					   void *args),
 	int			flags,
 	void			*args,
-	int			tag)
+	int			tag,
+	int			iter_flags)
 {
 	uint32_t		first_index;
 	int			last_error = 0;
@@ -557,7 +624,7 @@
 		for (i = 0; i < nr_found; i++) {
 			struct xfs_inode *ip = batch[i];
 
-			if (done || xfs_inode_ag_walk_grab(ip))
+			if (done || xfs_inode_ag_walk_grab(ip, iter_flags))
 				batch[i] = NULL;
 
 			/*
@@ -585,6 +652,9 @@
 		for (i = 0; i < nr_found; i++) {
 			if (!batch[i])
 				continue;
+			if ((iter_flags & XFS_AGITER_INEW_WAIT) &&
+			    xfs_iflags_test(batch[i], XFS_INEW))
+				xfs_inew_wait(batch[i]);
 			error = execute(batch[i], flags, args);
 			IRELE(batch[i]);
 			if (error == -EAGAIN) {
@@ -637,12 +707,13 @@
 }
 
 int
-xfs_inode_ag_iterator(
+xfs_inode_ag_iterator_flags(
 	struct xfs_mount	*mp,
 	int			(*execute)(struct xfs_inode *ip, int flags,
 					   void *args),
 	int			flags,
-	void			*args)
+	void			*args,
+	int			iter_flags)
 {
 	struct xfs_perag	*pag;
 	int			error = 0;
@@ -652,7 +723,8 @@
 	ag = 0;
 	while ((pag = xfs_perag_get(mp, ag))) {
 		ag = pag->pag_agno + 1;
-		error = xfs_inode_ag_walk(mp, pag, execute, flags, args, -1);
+		error = xfs_inode_ag_walk(mp, pag, execute, flags, args, -1,
+					  iter_flags);
 		xfs_perag_put(pag);
 		if (error) {
 			last_error = error;
@@ -664,6 +736,17 @@
 }
 
 int
+xfs_inode_ag_iterator(
+	struct xfs_mount	*mp,
+	int			(*execute)(struct xfs_inode *ip, int flags,
+					   void *args),
+	int			flags,
+	void			*args)
+{
+	return xfs_inode_ag_iterator_flags(mp, execute, flags, args, 0);
+}
+
+int
 xfs_inode_ag_iterator_tag(
 	struct xfs_mount	*mp,
 	int			(*execute)(struct xfs_inode *ip, int flags,
@@ -680,7 +763,8 @@
 	ag = 0;
 	while ((pag = xfs_perag_get_tag(mp, ag, tag))) {
 		ag = pag->pag_agno + 1;
-		error = xfs_inode_ag_walk(mp, pag, execute, flags, args, tag);
+		error = xfs_inode_ag_walk(mp, pag, execute, flags, args, tag,
+					  0);
 		xfs_perag_put(pag);
 		if (error) {
 			last_error = error;
--- linux-4.4.0.orig/fs/xfs/xfs_icache.h
+++ linux-4.4.0/fs/xfs/xfs_icache.h
@@ -48,6 +48,11 @@
 #define XFS_IGET_UNTRUSTED	0x2
 #define XFS_IGET_DONTCACHE	0x4
 
+/*
+ * flags for AG inode iterator
+ */
+#define XFS_AGITER_INEW_WAIT	0x1	/* wait on new inodes */
+
 int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino,
 	     uint flags, uint lock_flags, xfs_inode_t **ipp);
 
@@ -72,6 +77,9 @@
 int xfs_inode_ag_iterator(struct xfs_mount *mp,
 	int (*execute)(struct xfs_inode *ip, int flags, void *args),
 	int flags, void *args);
+int xfs_inode_ag_iterator_flags(struct xfs_mount *mp,
+	int (*execute)(struct xfs_inode *ip, int flags, void *args),
+	int flags, void *args, int iter_flags);
 int xfs_inode_ag_iterator_tag(struct xfs_mount *mp,
 	int (*execute)(struct xfs_inode *ip, int flags, void *args),
 	int flags, void *args, int tag);
--- linux-4.4.0.orig/fs/xfs/xfs_inode.c
+++ linux-4.4.0/fs/xfs/xfs_inode.c
@@ -751,12 +751,14 @@
 	xfs_buf_t	**ialloc_context,
 	xfs_inode_t	**ipp)
 {
+	struct inode		*dir = pip ? VFS_I(pip) : NULL;
 	struct xfs_mount *mp = tp->t_mountp;
 	xfs_ino_t	ino;
 	xfs_inode_t	*ip;
 	uint		flags;
 	int		error;
 	struct timespec	tv;
+	struct inode	*inode;
 
 	/*
 	 * Call the space management code to pick
@@ -782,6 +784,7 @@
 	if (error)
 		return error;
 	ASSERT(ip != NULL);
+	inode = VFS_I(ip);
 
 	/*
 	 * We always convert v1 inodes to v2 now - we only support filesystems
@@ -791,21 +794,23 @@
 	if (ip->i_d.di_version == 1)
 		ip->i_d.di_version = 2;
 
-	ip->i_d.di_mode = mode;
 	ip->i_d.di_onlink = 0;
 	ip->i_d.di_nlink = nlink;
 	ASSERT(ip->i_d.di_nlink == nlink);
-	ip->i_d.di_uid = xfs_kuid_to_uid(current_fsuid());
-	ip->i_d.di_gid = xfs_kgid_to_gid(current_fsgid());
 	xfs_set_projid(ip, prid);
 	memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
 
-	if (pip && XFS_INHERIT_GID(pip)) {
-		ip->i_d.di_gid = pip->i_d.di_gid;
-		if ((pip->i_d.di_mode & S_ISGID) && S_ISDIR(mode)) {
-			ip->i_d.di_mode |= S_ISGID;
-		}
+	if (dir && !(dir->i_mode & S_ISGID) &&
+	    (mp->m_flags & XFS_MOUNT_GRPID)) {
+		inode->i_uid = current_fsuid();
+		inode->i_gid = dir->i_gid;
+		inode->i_mode = mode;
+	} else {
+		inode_init_owner(inode, dir, mode);
 	}
+	ip->i_d.di_uid = xfs_kuid_to_uid(inode->i_uid);
+	ip->i_d.di_gid = xfs_kgid_to_gid(inode->i_gid);
+	ip->i_d.di_mode = inode->i_mode;
 
 	/*
 	 * If the group ID of the new file does not match the effective group
@@ -1738,7 +1743,7 @@
 	/*
 	 * Log the inode size first to prevent stale data exposure in the event
 	 * of a system crash before the truncate completes. See the related
-	 * comment in xfs_setattr_size() for details.
+	 * comment in xfs_vn_setattr_size() for details.
 	 */
 	ip->i_d.di_size = 0;
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@@ -3220,13 +3225,14 @@
 		 * We need to check under the i_flags_lock for a valid inode
 		 * here. Skip it if it is not valid or the wrong inode.
 		 */
-		spin_lock(&ip->i_flags_lock);
-		if (!ip->i_ino ||
+		spin_lock(&iq->i_flags_lock);
+		if (!iq->i_ino ||
+		    __xfs_iflags_test(iq, XFS_ISTALE) ||
 		    (XFS_INO_TO_AGINO(mp, iq->i_ino) & mask) != first_index) {
-			spin_unlock(&ip->i_flags_lock);
+			spin_unlock(&iq->i_flags_lock);
 			continue;
 		}
-		spin_unlock(&ip->i_flags_lock);
+		spin_unlock(&iq->i_flags_lock);
 
 		/*
 		 * Do an un-protected check to see if the inode is dirty and
@@ -3342,7 +3348,7 @@
 	struct xfs_buf		**bpp)
 {
 	struct xfs_mount	*mp = ip->i_mount;
-	struct xfs_buf		*bp;
+	struct xfs_buf		*bp = NULL;
 	struct xfs_dinode	*dip;
 	int			error;
 
@@ -3384,14 +3390,22 @@
 	}
 
 	/*
-	 * Get the buffer containing the on-disk inode.
+	 * Get the buffer containing the on-disk inode. We are doing a try-lock
+	 * operation here, so we may get  an EAGAIN error. In that case, we
+	 * simply want to return with the inode still dirty.
+	 *
+	 * If we get any other error, we effectively have a corruption situation
+	 * and we cannot flush the inode, so we treat it the same as failing
+	 * xfs_iflush_int().
 	 */
 	error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK,
 			       0);
-	if (error || !bp) {
+	if (error == -EAGAIN) {
 		xfs_ifunlock(ip);
 		return error;
 	}
+	if (error)
+		goto corrupt_out;
 
 	/*
 	 * First flush out the inode that xfs_iflush was called with.
@@ -3419,7 +3433,8 @@
 	return 0;
 
 corrupt_out:
-	xfs_buf_relse(bp);
+	if (bp)
+		xfs_buf_relse(bp);
 	xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
 cluster_corrupt_out:
 	error = -EFSCORRUPTED;
--- linux-4.4.0.orig/fs/xfs/xfs_inode.h
+++ linux-4.4.0/fs/xfs/xfs_inode.h
@@ -208,7 +208,8 @@
 #define XFS_IRECLAIM		(1 << 0) /* started reclaiming this inode */
 #define XFS_ISTALE		(1 << 1) /* inode has been staled */
 #define XFS_IRECLAIMABLE	(1 << 2) /* inode can be reclaimed */
-#define XFS_INEW		(1 << 3) /* inode has just been allocated */
+#define __XFS_INEW_BIT		3	 /* inode has just been allocated */
+#define XFS_INEW		(1 << __XFS_INEW_BIT)
 #define XFS_ITRUNCATED		(1 << 5) /* truncated down so flush-on-close */
 #define XFS_IDIRTY_RELEASE	(1 << 6) /* dirty release already seen */
 #define __XFS_IFLOCK_BIT	7	 /* inode is being flushed right now */
@@ -453,6 +454,7 @@
 	xfs_iflags_clear(ip, XFS_INEW);
 	barrier();
 	unlock_new_inode(VFS_I(ip));
+	wake_up_bit(&ip->i_flags, __XFS_INEW_BIT);
 }
 
 static inline void xfs_setup_existing_inode(struct xfs_inode *ip)
--- linux-4.4.0.orig/fs/xfs/xfs_ioctl.c
+++ linux-4.4.0/fs/xfs/xfs_ioctl.c
@@ -403,6 +403,7 @@
 {
 	int			error = -ENOMEM;
 	attrlist_cursor_kern_t	*cursor;
+	struct xfs_fsop_attrlist_handlereq __user	*p = arg;
 	xfs_fsop_attrlist_handlereq_t al_hreq;
 	struct dentry		*dentry;
 	char			*kbuf;
@@ -435,6 +436,11 @@
 	if (error)
 		goto out_kfree;
 
+	if (copy_to_user(&p->pos, cursor, sizeof(attrlist_cursor_kern_t))) {
+		error = -EFAULT;
+		goto out_kfree;
+	}
+
 	if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))
 		error = -EFAULT;
 
@@ -723,7 +729,8 @@
 		flags |= XFS_PREALLOC_CLEAR;
 		if (bf->l_start > XFS_ISIZE(ip)) {
 			error = xfs_alloc_file_space(ip, XFS_ISIZE(ip),
-					bf->l_start - XFS_ISIZE(ip), 0);
+					bf->l_start - XFS_ISIZE(ip),
+					XFS_BMAPI_PREALLOC);
 			if (error)
 				goto out_unlock;
 		}
@@ -731,7 +738,7 @@
 		iattr.ia_valid = ATTR_SIZE;
 		iattr.ia_size = bf->l_start;
 
-		error = xfs_setattr_size(ip, &iattr);
+		error = xfs_vn_setattr_size(file_dentry(filp), &iattr);
 		break;
 	default:
 		ASSERT(0);
@@ -1379,10 +1386,11 @@
 	unsigned int		cmd,
 	void			__user *arg)
 {
-	struct getbmapx		bmx;
+	struct getbmapx		bmx = { 0 };
 	int			error;
 
-	if (copy_from_user(&bmx, arg, sizeof(struct getbmapx)))
+	/* struct getbmap is a strict subset of struct getbmapx. */
+	if (copy_from_user(&bmx, arg, offsetof(struct getbmapx, bmv_iflags)))
 		return -EFAULT;
 
 	if (bmx.bmv_count < 2)
--- linux-4.4.0.orig/fs/xfs/xfs_ioctl32.c
+++ linux-4.4.0/fs/xfs/xfs_ioctl32.c
@@ -346,6 +346,7 @@
 {
 	int			error;
 	attrlist_cursor_kern_t	*cursor;
+	compat_xfs_fsop_attrlist_handlereq_t __user *p = arg;
 	compat_xfs_fsop_attrlist_handlereq_t al_hreq;
 	struct dentry		*dentry;
 	char			*kbuf;
@@ -380,6 +381,11 @@
 	if (error)
 		goto out_kfree;
 
+	if (copy_to_user(&p->pos, cursor, sizeof(attrlist_cursor_kern_t))) {
+		error = -EFAULT;
+		goto out_kfree;
+	}
+
 	if (copy_to_user(compat_ptr(al_hreq.buffer), kbuf, al_hreq.buflen))
 		error = -EFAULT;
 
--- linux-4.4.0.orig/fs/xfs/xfs_iops.c
+++ linux-4.4.0/fs/xfs/xfs_iops.c
@@ -534,6 +534,28 @@
 	}
 }
 
+static int
+xfs_vn_change_ok(
+	struct dentry	*dentry,
+	struct iattr	*iattr)
+{
+	struct xfs_mount	*mp = XFS_I(d_inode(dentry))->i_mount;
+
+	if (mp->m_flags & XFS_MOUNT_RDONLY)
+		return -EROFS;
+
+	if (XFS_FORCED_SHUTDOWN(mp))
+		return -EIO;
+
+	return setattr_prepare(dentry, iattr);
+}
+
+/*
+ * Set non-size attributes of an inode.
+ *
+ * Caution: The caller of this function is responsible for calling
+ * setattr_prepare() or otherwise verifying the change is fine.
+ */
 int
 xfs_setattr_nonsize(
 	struct xfs_inode	*ip,
@@ -550,21 +572,6 @@
 	struct xfs_dquot	*udqp = NULL, *gdqp = NULL;
 	struct xfs_dquot	*olddquot1 = NULL, *olddquot2 = NULL;
 
-	trace_xfs_setattr(ip);
-
-	/* If acls are being inherited, we already have this checked */
-	if (!(flags & XFS_ATTR_NOACL)) {
-		if (mp->m_flags & XFS_MOUNT_RDONLY)
-			return -EROFS;
-
-		if (XFS_FORCED_SHUTDOWN(mp))
-			return -EIO;
-
-		error = inode_change_ok(inode, iattr);
-		if (error)
-			return error;
-	}
-
 	ASSERT((mask & ATTR_SIZE) == 0);
 
 	/*
@@ -738,8 +745,27 @@
 	return error;
 }
 
+int
+xfs_vn_setattr_nonsize(
+	struct dentry		*dentry,
+	struct iattr		*iattr)
+{
+	struct xfs_inode	*ip = XFS_I(d_inode(dentry));
+	int error;
+
+	trace_xfs_setattr(ip);
+
+	error = xfs_vn_change_ok(dentry, iattr);
+	if (error)
+		return error;
+	return xfs_setattr_nonsize(ip, iattr, 0);
+}
+
 /*
  * Truncate file.  Must have write permission and not be a directory.
+ *
+ * Caution: The caller of this function is responsible for calling
+ * setattr_prepare() or otherwise verifying the change is fine.
  */
 int
 xfs_setattr_size(
@@ -754,23 +780,11 @@
 	uint			lock_flags = 0;
 	bool			did_zeroing = false;
 
-	trace_xfs_setattr(ip);
-
-	if (mp->m_flags & XFS_MOUNT_RDONLY)
-		return -EROFS;
-
-	if (XFS_FORCED_SHUTDOWN(mp))
-		return -EIO;
-
-	error = inode_change_ok(inode, iattr);
-	if (error)
-		return error;
-
 	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
 	ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL));
 	ASSERT(S_ISREG(ip->i_d.di_mode));
 	ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
-		ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
+		ATTR_MTIME_SET|ATTR_TIMES_SET)) == 0);
 
 	oldsize = inode->i_size;
 	newsize = iattr->ia_size;
@@ -938,16 +952,32 @@
 	goto out_unlock;
 }
 
+int
+xfs_vn_setattr_size(
+	struct dentry		*dentry,
+	struct iattr		*iattr)
+{
+	struct xfs_inode	*ip = XFS_I(d_inode(dentry));
+	int error;
+
+	trace_xfs_setattr(ip);
+
+	error = xfs_vn_change_ok(dentry, iattr);
+	if (error)
+		return error;
+	return xfs_setattr_size(ip, iattr);
+}
+
 STATIC int
 xfs_vn_setattr(
 	struct dentry		*dentry,
 	struct iattr		*iattr)
 {
-	struct xfs_inode	*ip = XFS_I(d_inode(dentry));
 	int			error;
 
 	if (iattr->ia_valid & ATTR_SIZE) {
-		uint		iolock = XFS_IOLOCK_EXCL;
+		struct xfs_inode	*ip = XFS_I(d_inode(dentry));
+		uint			iolock = XFS_IOLOCK_EXCL;
 
 		xfs_ilock(ip, iolock);
 		error = xfs_break_layouts(d_inode(dentry), &iolock, true);
@@ -955,11 +985,11 @@
 			xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
 			iolock |= XFS_MMAPLOCK_EXCL;
 
-			error = xfs_setattr_size(ip, iattr);
+			error = xfs_vn_setattr_size(dentry, iattr);
 		}
 		xfs_iunlock(ip, iolock);
 	} else {
-		error = xfs_setattr_nonsize(ip, iattr, 0);
+		error = xfs_vn_setattr_nonsize(dentry, iattr);
 	}
 
 	return error;
--- linux-4.4.0.orig/fs/xfs/xfs_iops.h
+++ linux-4.4.0/fs/xfs/xfs_iops.h
@@ -33,6 +33,7 @@
 extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr);
 extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
 			       int flags);
-extern int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap);
+extern int xfs_vn_setattr_nonsize(struct dentry *dentry, struct iattr *vap);
+extern int xfs_vn_setattr_size(struct dentry *dentry, struct iattr *vap);
 
 #endif /* __XFS_IOPS_H__ */
--- linux-4.4.0.orig/fs/xfs/xfs_itable.c
+++ linux-4.4.0/fs/xfs/xfs_itable.c
@@ -351,7 +351,6 @@
 	xfs_agino_t		agino;	/* inode # in allocation group */
 	xfs_agnumber_t		agno;	/* allocation group number */
 	xfs_btree_cur_t		*cur;	/* btree cursor for ialloc btree */
-	size_t			irbsize; /* size of irec buffer in bytes */
 	xfs_inobt_rec_incore_t	*irbuf;	/* start of irec buffer */
 	int			nirbuf;	/* size of irbuf */
 	int			ubcount; /* size of user's buffer */
@@ -378,11 +377,10 @@
 	*ubcountp = 0;
 	*done = 0;
 
-	irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4);
+	irbuf = kmem_zalloc_large(PAGE_SIZE * 4, KM_SLEEP);
 	if (!irbuf)
 		return -ENOMEM;
-
-	nirbuf = irbsize / sizeof(*irbuf);
+	nirbuf = (PAGE_SIZE * 4) / sizeof(*irbuf);
 
 	/*
 	 * Loop over the allocation groups, starting from the last
--- linux-4.4.0.orig/fs/xfs/xfs_linux.h
+++ linux-4.4.0/fs/xfs/xfs_linux.h
@@ -148,6 +148,13 @@
 #define SYNCHRONIZE()	barrier()
 #define __return_address __builtin_return_address(0)
 
+/*
+ * Return the address of a label.  Use barrier() so that the optimizer
+ * won't reorder code to refactor the error jumpouts into a single
+ * return, which throws off the reported address.
+ */
+#define __this_address	({ __label__ __here; __here: barrier(); &&__here; })
+
 #define XFS_PROJID_DEFAULT	0
 #define MAXPATHLEN	1024
 
@@ -369,7 +376,14 @@
 #endif /* DEBUG */
 
 #ifdef CONFIG_XFS_RT
-#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME)
+
+/*
+ * make sure we ignore the inode flag if the filesystem doesn't have a
+ * configured realtime device.
+ */
+#define XFS_IS_REALTIME_INODE(ip)			\
+	(((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) &&	\
+	 (ip)->i_mount->m_rtdev_targp)
 #else
 #define XFS_IS_REALTIME_INODE(ip) (0)
 #endif
--- linux-4.4.0.orig/fs/xfs/xfs_log.c
+++ linux-4.4.0/fs/xfs/xfs_log.c
@@ -1503,6 +1503,8 @@
 		if (iclog->ic_bp)
 			xfs_buf_free(iclog->ic_bp);
 		kmem_free(iclog);
+		if (prev_iclog == log->l_iclog)
+			break;
 	}
 	spinlock_destroy(&log->l_icloglock);
 	xfs_buf_free(log->l_xbuf);
@@ -3323,8 +3325,6 @@
 		 */
 		if (iclog->ic_state & XLOG_STATE_IOERROR)
 			return -EIO;
-		if (log_flushed)
-			*log_flushed = 1;
 	} else {
 
 no_sleep:
@@ -3432,8 +3432,6 @@
 
 				xlog_wait(&iclog->ic_prev->ic_write_wait,
 							&log->l_icloglock);
-				if (log_flushed)
-					*log_flushed = 1;
 				already_slept = 1;
 				goto try_again;
 			}
@@ -3467,9 +3465,6 @@
 			 */
 			if (iclog->ic_state & XLOG_STATE_IOERROR)
 				return -EIO;
-
-			if (log_flushed)
-				*log_flushed = 1;
 		} else {		/* just return */
 			spin_unlock(&log->l_icloglock);
 		}
--- linux-4.4.0.orig/fs/xfs/xfs_log_recover.c
+++ linux-4.4.0/fs/xfs/xfs_log_recover.c
@@ -738,7 +738,7 @@
 	 * in the in-core log.  The following number can be made tighter if
 	 * we actually look at the block size of the filesystem.
 	 */
-	num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log);
+	num_scan_bblks = min_t(int, log_bbnum, XLOG_TOTAL_REC_SHIFT(log));
 	if (head_blk >= num_scan_bblks) {
 		/*
 		 * We are guaranteed that the entire check can be performed
@@ -2379,6 +2379,16 @@
 	lsn = xlog_recover_get_buf_lsn(mp, bp);
 	if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
 		xlog_recover_validate_buf_type(mp, bp, buf_f);
+
+		/*
+		 * We're skipping replay of this buffer log item due to the log
+		 * item LSN being behind the ondisk buffer.  Verify the buffer
+		 * contents since we aren't going to run the write verifier.
+		 */
+		if (bp->b_ops) {
+			bp->b_ops->verify_read(bp);
+			error = bp->b_error;
+		}
 		goto out_release;
 	}
 
@@ -3204,6 +3214,7 @@
 	struct xfs_disk_dquot	*recddq;
 	struct xfs_dq_logformat	*dq_f;
 	uint			type;
+	int			len;
 
 
 	if (mp->m_qflags == 0)
@@ -3224,8 +3235,12 @@
 	ASSERT(dq_f);
 	ASSERT(dq_f->qlf_len == 1);
 
-	xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno,
-			  XFS_FSB_TO_BB(mp, dq_f->qlf_len), NULL);
+	len = XFS_FSB_TO_BB(mp, dq_f->qlf_len);
+	if (xlog_peek_buffer_cancelled(log, dq_f->qlf_blkno, len, 0))
+		return;
+
+	xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno, len,
+			  &xfs_dquot_buf_ra_ops);
 }
 
 STATIC void
@@ -3975,6 +3990,7 @@
 	agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
 	offset = offsetof(xfs_agi_t, agi_unlinked) +
 		 (sizeof(xfs_agino_t) * bucket);
+	xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF);
 	xfs_trans_log_buf(tp, agibp, offset,
 			  (offset + sizeof(xfs_agino_t) - 1));
 
--- linux-4.4.0.orig/fs/xfs/xfs_mount.h
+++ linux-4.4.0/fs/xfs/xfs_mount.h
@@ -278,6 +278,7 @@
 	char		pagi_inodeok;	/* The agi is ok for inodes */
 	__uint8_t	pagf_levels[XFS_BTNUM_AGF];
 					/* # of levels in bno & cnt btree */
+	bool		pagf_agflreset; /* agfl requires reset before use */
 	__uint32_t	pagf_flcount;	/* count of blocks in freelist */
 	xfs_extlen_t	pagf_freeblks;	/* total free blocks */
 	xfs_extlen_t	pagf_longest;	/* longest free space */
--- linux-4.4.0.orig/fs/xfs/xfs_pnfs.c
+++ linux-4.4.0/fs/xfs/xfs_pnfs.c
@@ -162,7 +162,7 @@
 		goto out_unlock;
 	error = invalidate_inode_pages2(inode->i_mapping);
 	if (WARN_ON_ONCE(error))
-		return error;
+		goto out_unlock;
 
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + length);
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
--- linux-4.4.0.orig/fs/xfs/xfs_qm.c
+++ linux-4.4.0/fs/xfs/xfs_qm.c
@@ -47,7 +47,7 @@
 STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int	xfs_qm_init_quotainfo(xfs_mount_t *);
 
-
+STATIC void	xfs_qm_destroy_quotainos(xfs_quotainfo_t *qi);
 STATIC void	xfs_qm_dqfree_one(struct xfs_dquot *dqp);
 /*
  * We use the batch lookup interface to iterate over the dquots as it
@@ -660,9 +660,17 @@
 	qinf->qi_shrinker.scan_objects = xfs_qm_shrink_scan;
 	qinf->qi_shrinker.seeks = DEFAULT_SEEKS;
 	qinf->qi_shrinker.flags = SHRINKER_NUMA_AWARE;
-	register_shrinker(&qinf->qi_shrinker);
+
+	error = register_shrinker(&qinf->qi_shrinker);
+	if (error)
+		goto out_free_inos;
+
 	return 0;
 
+out_free_inos:
+	mutex_destroy(&qinf->qi_quotaofflock);
+	mutex_destroy(&qinf->qi_tree_lock);
+	xfs_qm_destroy_quotainos(qinf);
 out_free_lru:
 	list_lru_destroy(&qinf->qi_lru);
 out_free_qinf:
@@ -671,7 +679,6 @@
 	return error;
 }
 
-
 /*
  * Gets called when unmounting a filesystem or when all quotas get
  * turned off.
@@ -688,19 +695,8 @@
 
 	unregister_shrinker(&qi->qi_shrinker);
 	list_lru_destroy(&qi->qi_lru);
-
-	if (qi->qi_uquotaip) {
-		IRELE(qi->qi_uquotaip);
-		qi->qi_uquotaip = NULL; /* paranoia */
-	}
-	if (qi->qi_gquotaip) {
-		IRELE(qi->qi_gquotaip);
-		qi->qi_gquotaip = NULL;
-	}
-	if (qi->qi_pquotaip) {
-		IRELE(qi->qi_pquotaip);
-		qi->qi_pquotaip = NULL;
-	}
+	xfs_qm_destroy_quotainos(qi);
+	mutex_destroy(&qi->qi_tree_lock);
 	mutex_destroy(&qi->qi_quotaofflock);
 	kmem_free(qi);
 	mp->m_quotainfo = NULL;
@@ -1355,12 +1351,7 @@
 	mp->m_qflags |= flags;
 
  error_return:
-	while (!list_empty(&buffer_list)) {
-		struct xfs_buf *bp =
-			list_first_entry(&buffer_list, struct xfs_buf, b_list);
-		list_del_init(&bp->b_list);
-		xfs_buf_relse(bp);
-	}
+	xfs_buf_delwri_cancel(&buffer_list);
 
 	if (error) {
 		xfs_warn(mp,
@@ -1567,6 +1558,24 @@
 }
 
 STATIC void
+xfs_qm_destroy_quotainos(
+	xfs_quotainfo_t	*qi)
+{
+	if (qi->qi_uquotaip) {
+		IRELE(qi->qi_uquotaip);
+		qi->qi_uquotaip = NULL; /* paranoia */
+	}
+	if (qi->qi_gquotaip) {
+		IRELE(qi->qi_gquotaip);
+		qi->qi_gquotaip = NULL;
+	}
+	if (qi->qi_pquotaip) {
+		IRELE(qi->qi_pquotaip);
+		qi->qi_pquotaip = NULL;
+	}
+}
+
+STATIC void
 xfs_qm_dqfree_one(
 	struct xfs_dquot	*dqp)
 {
--- linux-4.4.0.orig/fs/xfs/xfs_qm_syscalls.c
+++ linux-4.4.0/fs/xfs/xfs_qm_syscalls.c
@@ -764,5 +764,6 @@
 	uint		 flags)
 {
 	ASSERT(mp->m_quotainfo);
-	xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags, NULL);
+	xfs_inode_ag_iterator_flags(mp, xfs_dqrele_inode, flags, NULL,
+				    XFS_AGITER_INEW_WAIT);
 }
--- linux-4.4.0.orig/fs/xfs/xfs_quotaops.c
+++ linux-4.4.0/fs/xfs/xfs_quotaops.c
@@ -214,6 +214,9 @@
 	if (XFS_IS_QUOTA_ON(mp))
 		return -EINVAL;
 
+	if (uflags & ~(FS_USER_QUOTA | FS_GROUP_QUOTA | FS_PROJ_QUOTA))
+		return -EINVAL;
+
 	if (uflags & FS_USER_QUOTA)
 		flags |= XFS_DQ_USER;
 	if (uflags & FS_GROUP_QUOTA)
--- linux-4.4.0.orig/fs/xfs/xfs_rtalloc.c
+++ linux-4.4.0/fs/xfs/xfs_rtalloc.c
@@ -256,6 +256,9 @@
 		end = XFS_BLOCKTOBIT(mp, bbno + 1) - 1;
 	     i <= end;
 	     i++) {
+		/* Make sure we don't scan off the end of the rt volume. */
+		maxlen = min(mp->m_sb.sb_rextents, i + maxlen) - i;
+
 		/*
 		 * See if there's a free extent of maxlen starting at i.
 		 * If it's not so then next will contain the first non-free.
@@ -447,6 +450,14 @@
 	 */
 	if (bno >= mp->m_sb.sb_rextents)
 		bno = mp->m_sb.sb_rextents - 1;
+
+	/* Make sure we don't run off the end of the rt volume. */
+	maxlen = min(mp->m_sb.sb_rextents, bno + maxlen) - bno;
+	if (maxlen < minlen) {
+		*rtblock = NULLRTBLOCK;
+		return 0;
+	}
+
 	/*
 	 * Try the exact allocation first.
 	 */
@@ -1006,10 +1017,13 @@
 		xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
 		xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
 		/*
-		 * Update the bitmap inode's size.
+		 * Update the bitmap inode's size ondisk and incore.  We need
+		 * to update the incore size so that inode inactivation won't
+		 * punch what it thinks are "posteof" blocks.
 		 */
 		mp->m_rbmip->i_d.di_size =
 			nsbp->sb_rbmblocks * nsbp->sb_blocksize;
+		i_size_write(VFS_I(mp->m_rbmip), mp->m_rbmip->i_d.di_size);
 		xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
 		/*
 		 * Get the summary inode into the transaction.
@@ -1017,9 +1031,12 @@
 		xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL);
 		xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
 		/*
-		 * Update the summary inode's size.
+		 * Update the summary inode's size.  We need to update the
+		 * incore size so that inode inactivation won't punch what it
+		 * thinks are "posteof" blocks.
 		 */
 		mp->m_rsumip->i_d.di_size = nmp->m_rsumsize;
+		i_size_write(VFS_I(mp->m_rsumip), mp->m_rsumip->i_d.di_size);
 		xfs_trans_log_inode(tp, mp->m_rsumip, XFS_ILOG_CORE);
 		/*
 		 * Copy summary data from old to new sizes.
@@ -1225,13 +1242,11 @@
 	xfs_sb_t	*sbp;
 
 	sbp = &mp->m_sb;
-	if (sbp->sb_rbmino == NULLFSINO)
-		return 0;
 	error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip);
 	if (error)
 		return error;
 	ASSERT(mp->m_rbmip != NULL);
-	ASSERT(sbp->sb_rsumino != NULLFSINO);
+
 	error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip);
 	if (error) {
 		IRELE(mp->m_rbmip);
--- linux-4.4.0.orig/fs/xfs/xfs_super.c
+++ linux-4.4.0/fs/xfs/xfs_super.c
@@ -1233,6 +1233,16 @@
 			return -EINVAL;
 		}
 
+		if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+		    xfs_sb_has_ro_compat_feature(sbp,
+					XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
+			xfs_warn(mp,
+"ro->rw transition prohibited on unknown (0x%x) ro-compat filesystem",
+				(sbp->sb_features_ro_compat &
+					XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
+			return -EINVAL;
+		}
+
 		mp->m_flags &= ~XFS_MOUNT_RDONLY;
 
 		/*
@@ -1562,6 +1572,7 @@
  out_close_devices:
 	xfs_close_devices(mp);
  out_free_fsname:
+	sb->s_fs_info = NULL;
 	xfs_free_fsname(mp);
 	kfree(mp);
  out:
@@ -1579,6 +1590,10 @@
 {
 	struct xfs_mount	*mp = XFS_M(sb);
 
+	/* if ->fill_super failed, we have no mount to tear down */
+	if (!sb->s_fs_info)
+		return;
+
 	xfs_notice(mp, "Unmounting Filesystem");
 	xfs_filestream_unmount(mp);
 	xfs_unmountfs(mp);
@@ -1588,6 +1603,8 @@
 	xfs_destroy_percpu_counters(mp);
 	xfs_destroy_mount_workqueues(mp);
 	xfs_close_devices(mp);
+
+	sb->s_fs_info = NULL;
 	xfs_free_fsname(mp);
 	kfree(mp);
 }
@@ -1607,6 +1624,9 @@
 	struct super_block	*sb,
 	struct shrink_control	*sc)
 {
+	/* Paranoia: catch incorrect calls during mount setup or teardown */
+	if (WARN_ON_ONCE(!sb->s_fs_info))
+		return 0;
 	return xfs_reclaim_inodes_count(XFS_M(sb));
 }
 
--- linux-4.4.0.orig/fs/xfs/xfs_sysfs.h
+++ linux-4.4.0/fs/xfs/xfs_sysfs.h
@@ -44,9 +44,11 @@
 	struct xfs_kobj		*parent_kobj,
 	const char		*name)
 {
+	struct kobject		*parent;
+
+	parent = parent_kobj ? &parent_kobj->kobject : NULL;
 	init_completion(&kobj->complete);
-	return kobject_init_and_add(&kobj->kobject, ktype,
-				    &parent_kobj->kobject, "%s", name);
+	return kobject_init_and_add(&kobj->kobject, ktype, parent, "%s", name);
 }
 
 static inline void
--- linux-4.4.0.orig/fs/xfs/xfs_trace.h
+++ linux-4.4.0/fs/xfs/xfs_trace.h
@@ -1485,7 +1485,7 @@
 		  __entry->lsn)
 );
 
-TRACE_EVENT(xfs_agf,
+DECLARE_EVENT_CLASS(xfs_agf_class,
 	TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags,
 		 unsigned long caller_ip),
 	TP_ARGS(mp, agf, flags, caller_ip),
@@ -1541,6 +1541,13 @@
 		  __entry->longest,
 		  (void *)__entry->caller_ip)
 );
+#define DEFINE_AGF_EVENT(name) \
+DEFINE_EVENT(xfs_agf_class, name, \
+	TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, \
+		 unsigned long caller_ip), \
+	TP_ARGS(mp, agf, flags, caller_ip))
+DEFINE_AGF_EVENT(xfs_agf);
+DEFINE_AGF_EVENT(xfs_agfl_reset);
 
 TRACE_EVENT(xfs_free_extent,
 	TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno,
--- linux-4.4.0.orig/fs/xfs/xfs_trans_ail.c
+++ linux-4.4.0/fs/xfs/xfs_trans_ail.c
@@ -497,7 +497,6 @@
 	long		tout = 0;	/* milliseconds */
 
 	current->flags |= PF_MEMALLOC;
-	set_freezable();
 
 	while (!kthread_should_stop()) {
 		if (tout && tout <= 20)
--- linux-4.4.0.orig/fs/xfs/xfs_trans_dquot.c
+++ linux-4.4.0/fs/xfs/xfs_trans_dquot.c
@@ -662,7 +662,7 @@
 			}
 		}
 		if (ninos > 0) {
-			total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos;
+			total_count = dqp->q_res_icount + ninos;
 			timer = be32_to_cpu(dqp->q_core.d_itimer);
 			warns = be16_to_cpu(dqp->q_core.d_iwarns);
 			warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;
--- linux-4.4.0.orig/fs/xfs/xfs_xattr.c
+++ linux-4.4.0/fs/xfs/xfs_xattr.c
@@ -180,7 +180,8 @@
 	arraytop = context->count + prefix_len + namelen + 1;
 	if (arraytop > context->firstu) {
 		context->count = -1;	/* insufficient space */
-		return 1;
+		context->seen_enough = 1;
+		return 0;
 	}
 	offset = (char *)context->alist + context->count;
 	strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
@@ -222,12 +223,15 @@
 }
 
 ssize_t
-xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
+xfs_vn_listxattr(
+	struct dentry	*dentry,
+	char		*data,
+	size_t		size)
 {
 	struct xfs_attr_list_context context;
 	struct attrlist_cursor_kern cursor = { 0 };
-	struct inode		*inode = d_inode(dentry);
-	int			error;
+	struct inode	*inode = d_inode(dentry);
+	int		error;
 
 	/*
 	 * First read the regular on-disk attributes.
@@ -245,7 +249,9 @@
 	else
 		context.put_listent = xfs_xattr_put_listent_sizes;
 
-	xfs_attr_list_int(&context);
+	error = xfs_attr_list_int(&context);
+	if (error)
+		return error;
 	if (context.count < 0)
 		return -ERANGE;
 
--- linux-4.4.0.orig/include/acpi/actbl2.h
+++ linux-4.4.0/include/acpi/actbl2.h
@@ -321,7 +321,7 @@
  * DBG2 - Debug Port Table 2
  *        Version 0 (Both main table and subtables)
  *
- * Conforms to "Microsoft Debug Port Table 2 (DBG2)", May 22 2012.
+ * Conforms to "Microsoft Debug Port Table 2 (DBG2)", December 10, 2015
  *
  ******************************************************************************/
 
@@ -371,6 +371,11 @@
 
 #define ACPI_DBG2_16550_COMPATIBLE  0x0000
 #define ACPI_DBG2_16550_SUBSET      0x0001
+#define ACPI_DBG2_ARM_PL011         0x0003
+#define ACPI_DBG2_ARM_SBSA_32BIT    0x000D
+#define ACPI_DBG2_ARM_SBSA_GENERIC  0x000E
+#define ACPI_DBG2_ARM_DCC           0x000F
+#define ACPI_DBG2_BCM2835           0x0010
 
 #define ACPI_DBG2_1394_STANDARD     0x0000
 
--- linux-4.4.0.orig/include/asm-generic/asm-prototypes.h
+++ linux-4.4.0/include/asm-generic/asm-prototypes.h
@@ -0,0 +1,13 @@
+#include <linux/bitops.h>
+#undef __memset
+extern void *__memset(void *, int, __kernel_size_t);
+#undef __memcpy
+extern void *__memcpy(void *, const void *, __kernel_size_t);
+#undef __memmove
+extern void *__memmove(void *, const void *, __kernel_size_t);
+#undef memset
+extern void *memset(void *, int, __kernel_size_t);
+#undef memcpy
+extern void *memcpy(void *, const void *, __kernel_size_t);
+#undef memmove
+extern void *memmove(void *, const void *, __kernel_size_t);
--- linux-4.4.0.orig/include/asm-generic/barrier.h
+++ linux-4.4.0/include/asm-generic/barrier.h
@@ -42,6 +42,10 @@
 #define wmb()	mb()
 #endif
 
+#ifndef gmb
+#define gmb()	do { } while (0)
+#endif
+
 #ifndef dma_rmb
 #define dma_rmb()	rmb()
 #endif
@@ -54,22 +58,38 @@
 #define read_barrier_depends()		do { } while (0)
 #endif
 
+#ifndef __smp_mb
+#define __smp_mb()	mb()
+#endif
+
+#ifndef __smp_rmb
+#define __smp_rmb()	rmb()
+#endif
+
+#ifndef __smp_wmb
+#define __smp_wmb()	wmb()
+#endif
+
+#ifndef __smp_read_barrier_depends
+#define __smp_read_barrier_depends()	read_barrier_depends()
+#endif
+
 #ifdef CONFIG_SMP
 
 #ifndef smp_mb
-#define smp_mb()	mb()
+#define smp_mb()	__smp_mb()
 #endif
 
 #ifndef smp_rmb
-#define smp_rmb()	rmb()
+#define smp_rmb()	__smp_rmb()
 #endif
 
 #ifndef smp_wmb
-#define smp_wmb()	wmb()
+#define smp_wmb()	__smp_wmb()
 #endif
 
 #ifndef smp_read_barrier_depends
-#define smp_read_barrier_depends()	read_barrier_depends()
+#define smp_read_barrier_depends()	__smp_read_barrier_depends()
 #endif
 
 #else	/* !CONFIG_SMP */
@@ -92,32 +112,115 @@
 
 #endif	/* CONFIG_SMP */
 
+#ifndef __smp_store_mb
+#define __smp_store_mb(var, value)  do { WRITE_ONCE(var, value); __smp_mb(); } while (0)
+#endif
+
+#ifndef __smp_mb__before_atomic
+#define __smp_mb__before_atomic()	__smp_mb()
+#endif
+
+#ifndef __smp_mb__after_atomic
+#define __smp_mb__after_atomic()	__smp_mb()
+#endif
+
+#ifndef __smp_store_release
+#define __smp_store_release(p, v)					\
+do {									\
+	compiletime_assert_atomic_type(*p);				\
+	__smp_mb();							\
+	WRITE_ONCE(*p, v);						\
+} while (0)
+#endif
+
+#ifndef __smp_load_acquire
+#define __smp_load_acquire(p)						\
+({									\
+	typeof(*p) ___p1 = READ_ONCE(*p);				\
+	compiletime_assert_atomic_type(*p);				\
+	__smp_mb();							\
+	___p1;								\
+})
+#endif
+
+#ifdef CONFIG_SMP
+
+#ifndef smp_store_mb
+#define smp_store_mb(var, value)  __smp_store_mb(var, value)
+#endif
+
+#ifndef smp_mb__before_atomic
+#define smp_mb__before_atomic()	__smp_mb__before_atomic()
+#endif
+
+#ifndef smp_mb__after_atomic
+#define smp_mb__after_atomic()	__smp_mb__after_atomic()
+#endif
+
+#ifndef smp_store_release
+#define smp_store_release(p, v) __smp_store_release(p, v)
+#endif
+
+#ifndef smp_load_acquire
+#define smp_load_acquire(p) __smp_load_acquire(p)
+#endif
+
+#else	/* !CONFIG_SMP */
+
 #ifndef smp_store_mb
-#define smp_store_mb(var, value)  do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value)  do { WRITE_ONCE(var, value); barrier(); } while (0)
 #endif
 
 #ifndef smp_mb__before_atomic
-#define smp_mb__before_atomic()	smp_mb()
+#define smp_mb__before_atomic()	barrier()
 #endif
 
 #ifndef smp_mb__after_atomic
-#define smp_mb__after_atomic()	smp_mb()
+#define smp_mb__after_atomic()	barrier()
 #endif
 
+#ifndef smp_store_release
 #define smp_store_release(p, v)						\
 do {									\
 	compiletime_assert_atomic_type(*p);				\
-	smp_mb();							\
+	barrier();							\
 	WRITE_ONCE(*p, v);						\
 } while (0)
+#endif
 
+#ifndef smp_load_acquire
 #define smp_load_acquire(p)						\
 ({									\
 	typeof(*p) ___p1 = READ_ONCE(*p);				\
 	compiletime_assert_atomic_type(*p);				\
-	smp_mb();							\
+	barrier();							\
 	___p1;								\
 })
+#endif
+
+#endif
+
+/* Barriers for virtual machine guests when talking to an SMP host */
+#define virt_mb() __smp_mb()
+#define virt_rmb() __smp_rmb()
+#define virt_wmb() __smp_wmb()
+#define virt_read_barrier_depends() __smp_read_barrier_depends()
+#define virt_store_mb(var, value) __smp_store_mb(var, value)
+#define virt_mb__before_atomic() __smp_mb__before_atomic()
+#define virt_mb__after_atomic()	__smp_mb__after_atomic()
+#define virt_store_release(p, v) __smp_store_release(p, v)
+#define virt_load_acquire(p) __smp_load_acquire(p)
+
+/* Observable speculation barrier: ensures that any user
+ * observable speculation doesn't cross the boundary.
+ * Any user observable speculative activity on this CPU
+ * thread before this point either completes, reaches a
+ * state it can no longer cause observable activity, or
+ * is aborted before instructions after the barrier execute.
+ */
+#ifndef osb
+#define osb()	do { } while (0)
+#endif
 
 #endif /* !__ASSEMBLY__ */
 #endif /* __ASM_GENERIC_BARRIER_H */
--- linux-4.4.0.orig/include/asm-generic/bitops/lock.h
+++ linux-4.4.0/include/asm-generic/bitops/lock.h
@@ -29,16 +29,16 @@
  * @nr: the bit to set
  * @addr: the address to start counting from
  *
- * This operation is like clear_bit_unlock, however it is not atomic.
- * It does provide release barrier semantics so it can be used to unlock
- * a bit lock, however it would only be used if no other CPU can modify
- * any bits in the memory until the lock is released (a good example is
- * if the bit lock itself protects access to the other bits in the word).
+ * A weaker form of clear_bit_unlock() as used by __bit_lock_unlock(). If all
+ * the bits in the word are protected by this lock some archs can use weaker
+ * ops to safely unlock.
+ *
+ * See for example x86's implementation.
  */
 #define __clear_bit_unlock(nr, addr)	\
 do {					\
-	smp_mb();			\
-	__clear_bit(nr, addr);		\
+	smp_mb__before_atomic();	\
+	clear_bit(nr, addr);		\
 } while (0)
 
 #endif /* _ASM_GENERIC_BITOPS_LOCK_H_ */
--- linux-4.4.0.orig/include/asm-generic/bug.h
+++ linux-4.4.0/include/asm-generic/bug.h
@@ -47,6 +47,7 @@
 #ifndef HAVE_ARCH_BUG
 #define BUG() do { \
 	printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
+	barrier_before_unreachable(); \
 	panic("BUG!"); \
 } while (0)
 #endif
@@ -142,7 +143,7 @@
 #endif
 
 #ifndef HAVE_ARCH_BUG_ON
-#define BUG_ON(condition) do { if (condition) ; } while (0)
+#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
 #endif
 
 #ifndef HAVE_ARCH_WARN_ON
--- linux-4.4.0.orig/include/asm-generic/cputime_nsecs.h
+++ linux-4.4.0/include/asm-generic/cputime_nsecs.h
@@ -75,7 +75,7 @@
  */
 static inline cputime_t timespec_to_cputime(const struct timespec *val)
 {
-	u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec;
+	u64 ret = (u64)val->tv_sec * NSEC_PER_SEC + val->tv_nsec;
 	return (__force cputime_t) ret;
 }
 static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val)
@@ -91,7 +91,8 @@
  */
 static inline cputime_t timeval_to_cputime(const struct timeval *val)
 {
-	u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_usec * NSEC_PER_USEC;
+	u64 ret = (u64)val->tv_sec * NSEC_PER_SEC +
+			val->tv_usec * NSEC_PER_USEC;
 	return (__force cputime_t) ret;
 }
 static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val)
--- linux-4.4.0.orig/include/asm-generic/export.h
+++ linux-4.4.0/include/asm-generic/export.h
@@ -0,0 +1,94 @@
+#ifndef __ASM_GENERIC_EXPORT_H
+#define __ASM_GENERIC_EXPORT_H
+
+#ifndef KSYM_FUNC
+#define KSYM_FUNC(x) x
+#endif
+#ifdef CONFIG_64BIT
+#define __put .quad
+#ifndef KSYM_ALIGN
+#define KSYM_ALIGN 8
+#endif
+#ifndef KCRC_ALIGN
+#define KCRC_ALIGN 8
+#endif
+#else
+#define __put .long
+#ifndef KSYM_ALIGN
+#define KSYM_ALIGN 4
+#endif
+#ifndef KCRC_ALIGN
+#define KCRC_ALIGN 4
+#endif
+#endif
+
+#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
+#define KSYM(name) _##name
+#else
+#define KSYM(name) name
+#endif
+
+/*
+ * note on .section use: @progbits vs %progbits nastiness doesn't matter,
+ * since we immediately emit into those sections anyway.
+ */
+.macro ___EXPORT_SYMBOL name,val,sec
+#ifdef CONFIG_MODULES
+	.globl KSYM(__ksymtab_\name)
+	.section ___ksymtab\sec+\name,"a"
+	.balign KSYM_ALIGN
+KSYM(__ksymtab_\name):
+	__put \val, KSYM(__kstrtab_\name)
+	.previous
+	.section __ksymtab_strings,"a"
+KSYM(__kstrtab_\name):
+#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
+	.asciz "_\name"
+#else
+	.asciz "\name"
+#endif
+	.previous
+#ifdef CONFIG_MODVERSIONS
+	.section ___kcrctab\sec+\name,"a"
+	.balign KCRC_ALIGN
+KSYM(__kcrctab_\name):
+	__put KSYM(__crc_\name)
+	.weak KSYM(__crc_\name)
+	.previous
+#endif
+#endif
+.endm
+#undef __put
+
+#if defined(__KSYM_DEPS__)
+
+#define __EXPORT_SYMBOL(sym, val, sec)	=== __KSYM_##sym ===
+
+#elif defined(CONFIG_TRIM_UNUSED_KSYMS)
+
+#include <linux/kconfig.h>
+#include <generated/autoksyms.h>
+
+#define __EXPORT_SYMBOL(sym, val, sec)				\
+	__cond_export_sym(sym, val, sec, config_enabled(__KSYM_##sym))
+#define __cond_export_sym(sym, val, sec, conf)			\
+	___cond_export_sym(sym, val, sec, conf)
+#define ___cond_export_sym(sym, val, sec, enabled)		\
+	__cond_export_sym_##enabled(sym, val, sec)
+#define __cond_export_sym_1(sym, val, sec) ___EXPORT_SYMBOL sym, val, sec
+#define __cond_export_sym_0(sym, val, sec) /* nothing */
+
+#else
+#define __EXPORT_SYMBOL(sym, val, sec) ___EXPORT_SYMBOL sym, val, sec
+#endif
+
+#define EXPORT_SYMBOL(name)					\
+	__EXPORT_SYMBOL(name, KSYM_FUNC(KSYM(name)),)
+#define EXPORT_SYMBOL_GPL(name) 				\
+	__EXPORT_SYMBOL(name, KSYM_FUNC(KSYM(name)), _gpl)
+#define EXPORT_DATA_SYMBOL(name)				\
+	__EXPORT_SYMBOL(name, KSYM(name),)
+#define EXPORT_DATA_SYMBOL_GPL(name)				\
+	__EXPORT_SYMBOL(name, KSYM(name),_gpl)
+
+#endif
--- linux-4.4.0.orig/include/asm-generic/fixmap.h
+++ linux-4.4.0/include/asm-generic/fixmap.h
@@ -70,12 +70,12 @@
 #endif
 
 /* Return a pointer with offset calculated */
-#define __set_fixmap_offset(idx, phys, flags)		      \
-({							      \
-	unsigned long addr;				      \
-	__set_fixmap(idx, phys, flags);			      \
-	addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1)); \
-	addr;						      \
+#define __set_fixmap_offset(idx, phys, flags)				\
+({									\
+	unsigned long ________addr;					\
+	__set_fixmap(idx, phys, flags);					\
+	________addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1));	\
+	________addr;							\
 })
 
 #define set_fixmap_offset(idx, phys) \
--- linux-4.4.0.orig/include/asm-generic/futex.h
+++ linux-4.4.0/include/asm-generic/futex.h
@@ -13,7 +13,7 @@
  */
 
 /**
- * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
+ * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant
  *			  argument and comparison of the previous
  *			  futex value with another constant.
  *
@@ -25,18 +25,11 @@
  * <0 - On error
  */
 static inline int
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval, ret;
 	u32 tmp;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
 	preempt_disable();
 	pagefault_disable();
 
@@ -74,17 +67,9 @@
 	pagefault_enable();
 	preempt_enable();
 
-	if (ret == 0) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (ret == 0)
+		*oval = oldval;
+
 	return ret;
 }
 
@@ -108,11 +93,15 @@
 	u32 val;
 
 	preempt_disable();
-	if (unlikely(get_user(val, uaddr) != 0))
+	if (unlikely(get_user(val, uaddr) != 0)) {
+		preempt_enable();
 		return -EFAULT;
+	}
 
-	if (val == oldval && unlikely(put_user(newval, uaddr) != 0))
+	if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
+		preempt_enable();
 		return -EFAULT;
+	}
 
 	*uval = val;
 	preempt_enable();
@@ -122,18 +111,9 @@
 
 #else
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -149,17 +129,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
--- linux-4.4.0.orig/include/asm-generic/getorder.h
+++ linux-4.4.0/include/asm-generic/getorder.h
@@ -6,24 +6,6 @@
 #include <linux/compiler.h>
 #include <linux/log2.h>
 
-/*
- * Runtime evaluation of get_order()
- */
-static inline __attribute_const__
-int __get_order(unsigned long size)
-{
-	int order;
-
-	size--;
-	size >>= PAGE_SHIFT;
-#if BITS_PER_LONG == 32
-	order = fls(size);
-#else
-	order = fls64(size);
-#endif
-	return order;
-}
-
 /**
  * get_order - Determine the allocation order of a memory size
  * @size: The size for which to get the order
@@ -42,19 +24,27 @@
  * to hold an object of the specified size.
  *
  * The result is undefined if the size is 0.
- *
- * This function may be used to initialise variables with compile time
- * evaluations of constants.
  */
-#define get_order(n)						\
-(								\
-	__builtin_constant_p(n) ? (				\
-		((n) == 0UL) ? BITS_PER_LONG - PAGE_SHIFT :	\
-		(((n) < (1UL << PAGE_SHIFT)) ? 0 :		\
-		 ilog2((n) - 1) - PAGE_SHIFT + 1)		\
-	) :							\
-	__get_order(n)						\
-)
+static inline __attribute_const__ int get_order(unsigned long size)
+{
+	if (__builtin_constant_p(size)) {
+		if (!size)
+			return BITS_PER_LONG - PAGE_SHIFT;
+
+		if (size < (1UL << PAGE_SHIFT))
+			return 0;
+
+		return ilog2((size) - 1) - PAGE_SHIFT + 1;
+	}
+
+	size--;
+	size >>= PAGE_SHIFT;
+#if BITS_PER_LONG == 32
+	return fls(size);
+#else
+	return fls64(size);
+#endif
+}
 
 #endif	/* __ASSEMBLY__ */
 
--- linux-4.4.0.orig/include/asm-generic/memory_model.h
+++ linux-4.4.0/include/asm-generic/memory_model.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_MEMORY_MODEL_H
 #define __ASM_MEMORY_MODEL_H
 
+#include <linux/pfn.h>
+
 #ifndef __ASSEMBLY__
 
 #if defined(CONFIG_FLATMEM)
@@ -72,7 +74,7 @@
 /*
  * Convert a physical address to a Page Frame Number and back
  */
-#define	__phys_to_pfn(paddr)	((unsigned long)((paddr) >> PAGE_SHIFT))
+#define	__phys_to_pfn(paddr)	PHYS_PFN(paddr)
 #define	__pfn_to_phys(pfn)	PFN_PHYS(pfn)
 
 #define page_to_pfn __page_to_pfn
--- linux-4.4.0.orig/include/asm-generic/percpu.h
+++ linux-4.4.0/include/asm-generic/percpu.h
@@ -105,15 +105,35 @@
 	(__ret);							\
 })
 
-#define this_cpu_generic_read(pcp)					\
+#define __this_cpu_generic_read_nopreempt(pcp)				\
 ({									\
 	typeof(pcp) __ret;						\
 	preempt_disable();						\
-	__ret = *this_cpu_ptr(&(pcp));					\
+	__ret = READ_ONCE(*raw_cpu_ptr(&(pcp)));			\
 	preempt_enable();						\
 	__ret;								\
 })
 
+#define __this_cpu_generic_read_noirq(pcp)				\
+({									\
+	typeof(pcp) __ret;						\
+	unsigned long __flags;						\
+	raw_local_irq_save(__flags);					\
+	__ret = *raw_cpu_ptr(&(pcp));					\
+	raw_local_irq_restore(__flags);					\
+	__ret;								\
+})
+
+#define this_cpu_generic_read(pcp)					\
+({									\
+	typeof(pcp) __ret;						\
+	if (__native_word(pcp))						\
+		__ret = __this_cpu_generic_read_nopreempt(pcp);		\
+	else								\
+		__ret = __this_cpu_generic_read_noirq(pcp);		\
+	__ret;								\
+})
+
 #define this_cpu_generic_to_op(pcp, val, op)				\
 do {									\
 	unsigned long __flags;						\
--- linux-4.4.0.orig/include/asm-generic/pgtable.h
+++ linux-4.4.0/include/asm-generic/pgtable.h
@@ -237,6 +237,21 @@
 extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
 #endif
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+/*
+ * This is an implementation of pmdp_establish() that is only suitable for an
+ * architecture that doesn't have hardware dirty/accessed bits. In this case we
+ * can't race with CPU which sets these bits and non-atomic aproach is fine.
+ */
+static inline pmd_t generic_pmdp_establish(struct vm_area_struct *vma,
+		unsigned long address, pmd_t *pmdp, pmd_t pmd)
+{
+	pmd_t old_pmd = *pmdp;
+	set_pmd_at(vma->vm_mm, address, pmdp, pmd);
+	return old_pmd;
+}
+#endif
+
 #ifndef __HAVE_ARCH_PMDP_INVALIDATE
 extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
 			    pmd_t *pmdp);
@@ -755,6 +770,8 @@
 int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot);
 int pud_clear_huge(pud_t *pud);
 int pmd_clear_huge(pmd_t *pmd);
+int pud_free_pmd_page(pud_t *pud, unsigned long addr);
+int pmd_free_pte_page(pmd_t *pmd, unsigned long addr);
 #else	/* !CONFIG_HAVE_ARCH_HUGE_VMAP */
 static inline int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
 {
@@ -772,8 +789,28 @@
 {
 	return 0;
 }
+static inline int pud_free_pmd_page(pud_t *pud, unsigned long addr)
+{
+	return 0;
+}
+static inline int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
+{
+	return 0;
+}
 #endif	/* CONFIG_HAVE_ARCH_HUGE_VMAP */
 
+#ifndef __HAVE_ARCH_PFN_MODIFY_ALLOWED
+static inline bool pfn_modify_allowed(unsigned long pfn, pgprot_t prot)
+{
+	return true;
+}
+
+static inline bool arch_has_pfn_modify_check(void)
+{
+	return false;
+}
+#endif /* !_HAVE_ARCH_PFN_MODIFY_ALLOWED */
+
 #endif /* !__ASSEMBLY__ */
 
 #ifndef io_remap_pfn_range
--- linux-4.4.0.orig/include/asm-generic/preempt.h
+++ linux-4.4.0/include/asm-generic/preempt.h
@@ -7,10 +7,10 @@
 
 static __always_inline int preempt_count(void)
 {
-	return current_thread_info()->preempt_count;
+	return READ_ONCE(current_thread_info()->preempt_count);
 }
 
-static __always_inline int *preempt_count_ptr(void)
+static __always_inline volatile int *preempt_count_ptr(void)
 {
 	return &current_thread_info()->preempt_count;
 }
--- linux-4.4.0.orig/include/asm-generic/qspinlock.h
+++ linux-4.4.0/include/asm-generic/qspinlock.h
@@ -21,14 +21,33 @@
 #include <asm-generic/qspinlock_types.h>
 
 /**
+ * queued_spin_unlock_wait - wait until the _current_ lock holder releases the lock
+ * @lock : Pointer to queued spinlock structure
+ *
+ * There is a very slight possibility of live-lock if the lockers keep coming
+ * and the waiter is just unfortunate enough to not see any unlock state.
+ */
+#ifndef queued_spin_unlock_wait
+extern void queued_spin_unlock_wait(struct qspinlock *lock);
+#endif
+
+/**
  * queued_spin_is_locked - is the spinlock locked?
  * @lock: Pointer to queued spinlock structure
  * Return: 1 if it is locked, 0 otherwise
  */
+#ifndef queued_spin_is_locked
 static __always_inline int queued_spin_is_locked(struct qspinlock *lock)
 {
+	/*
+	 * See queued_spin_unlock_wait().
+	 *
+	 * Any !0 state indicates it is locked, even if _Q_LOCKED_VAL
+	 * isn't immediately observable.
+	 */
 	return atomic_read(&lock->val);
 }
+#endif
 
 /**
  * queued_spin_value_unlocked - is the spinlock structure unlocked?
@@ -98,19 +117,6 @@
 }
 #endif
 
-/**
- * queued_spin_unlock_wait - wait until current lock holder releases the lock
- * @lock : Pointer to queued spinlock structure
- *
- * There is a very slight possibility of live-lock if the lockers keep coming
- * and the waiter is just unfortunate enough to not see any unlock state.
- */
-static inline void queued_spin_unlock_wait(struct qspinlock *lock)
-{
-	while (atomic_read(&lock->val) & _Q_LOCKED_MASK)
-		cpu_relax();
-}
-
 #ifndef virt_spin_lock
 static __always_inline bool virt_spin_lock(struct qspinlock *lock)
 {
@@ -119,11 +125,6 @@
 #endif
 
 /*
- * Initializier
- */
-#define	__ARCH_SPIN_LOCK_UNLOCKED	{ ATOMIC_INIT(0) }
-
-/*
  * Remapping spinlock architecture specific functions to the corresponding
  * queued spinlock functions.
  */
--- linux-4.4.0.orig/include/asm-generic/qspinlock_types.h
+++ linux-4.4.0/include/asm-generic/qspinlock_types.h
@@ -33,6 +33,11 @@
 } arch_spinlock_t;
 
 /*
+ * Initializier
+ */
+#define	__ARCH_SPIN_LOCK_UNLOCKED	{ ATOMIC_INIT(0) }
+
+/*
  * Bitfields in the atomic value:
  *
  * When NR_CPUS < 16K
--- linux-4.4.0.orig/include/asm-generic/rtc.h
+++ linux-4.4.0/include/asm-generic/rtc.h
@@ -106,7 +106,7 @@
 	time->tm_year += real_year - 72;
 #endif
 
-	if (century)
+	if (century > 20)
 		time->tm_year += (century - 19) * 100;
 
 	/*
--- linux-4.4.0.orig/include/asm-generic/siginfo.h
+++ linux-4.4.0/include/asm-generic/siginfo.h
@@ -17,21 +17,6 @@
 struct siginfo;
 void do_schedule_next_timer(struct siginfo *info);
 
-#ifndef HAVE_ARCH_COPY_SIGINFO
-
-#include <linux/string.h>
-
-static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(*to));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
-}
-
-#endif
-
 extern int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from);
 
 #endif
--- linux-4.4.0.orig/include/asm-generic/tlb.h
+++ linux-4.4.0/include/asm-generic/tlb.h
@@ -165,6 +165,13 @@
 #define tlb_end_vma	__tlb_end_vma
 #endif
 
+static inline void tlb_flush_pmd_range(struct mmu_gather *tlb,
+				unsigned long address, unsigned long size)
+{
+	tlb->start = min(tlb->start, address);
+	tlb->end = max(tlb->end, address + size);
+}
+
 #ifndef __tlb_remove_tlb_entry
 #define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
 #endif
--- linux-4.4.0.orig/include/asm-generic/topology.h
+++ linux-4.4.0/include/asm-generic/topology.h
@@ -48,7 +48,11 @@
 #define parent_node(node)	((void)(node),0)
 #endif
 #ifndef cpumask_of_node
-#define cpumask_of_node(node)	((void)node, cpu_online_mask)
+  #ifdef CONFIG_NEED_MULTIPLE_NODES
+    #define cpumask_of_node(node)	((node) == 0 ? cpu_online_mask : cpu_none_mask)
+  #else
+    #define cpumask_of_node(node)	((void)(node), cpu_online_mask)
+  #endif
 #endif
 #ifndef pcibus_to_node
 #define pcibus_to_node(bus)	((void)(bus), -1)
--- linux-4.4.0.orig/include/asm-generic/uaccess.h
+++ linux-4.4.0/include/asm-generic/uaccess.h
@@ -230,14 +230,18 @@
 	might_fault();						\
 	access_ok(VERIFY_READ, __p, sizeof(*ptr)) ?		\
 		__get_user((x), (__typeof__(*(ptr)) *)__p) :	\
-		-EFAULT;					\
+		((x) = (__typeof__(*(ptr)))0,-EFAULT);		\
 })
 
 #ifndef __get_user_fn
 static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
 {
-	size = __copy_from_user(x, ptr, size);
-	return size ? -EFAULT : size;
+	size_t n = __copy_from_user(x, ptr, size);
+	if (unlikely(n)) {
+		memset(x + (size - n), 0, n);
+		return -EFAULT;
+	}
+	return 0;
 }
 
 #define __get_user_fn(sz, u, k)	__get_user_fn(sz, u, k)
@@ -257,11 +261,13 @@
 static inline long copy_from_user(void *to,
 		const void __user * from, unsigned long n)
 {
+	unsigned long res = n;
 	might_fault();
-	if (access_ok(VERIFY_READ, from, n))
-		return __copy_from_user(to, from, n);
-	else
-		return n;
+	if (likely(access_ok(VERIFY_READ, from, n)))
+		res = __copy_from_user(to, from, n);
+	if (unlikely(res))
+		memset(to + (n - res), 0, res);
+	return res;
 }
 
 static inline long copy_to_user(void __user *to,
--- linux-4.4.0.orig/include/asm-generic/vmlinux.lds.h
+++ linux-4.4.0/include/asm-generic/vmlinux.lds.h
@@ -256,6 +256,7 @@
 	.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start_rodata) = .;			\
 		*(.rodata) *(.rodata.*)					\
+		*(.data..ro_after_init)	/* Read only after init */	\
 		*(__vermagic)		/* Kernel version magic */	\
 		. = ALIGN(8);						\
 		VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .;		\
@@ -422,7 +423,10 @@
  * during second ld run in second ld pass when generating System.map */
 #define TEXT_TEXT							\
 		ALIGN_FUNCTION();					\
-		*(.text.hot .text .text.fixup .text.unlikely)		\
+		*(.text.hot .text.hot.*)				\
+		*(.text .text.fixup)					\
+		*(.text.unlikely .text.unlikely.*)			\
+		*(.text.unknown .text.unknown.*)			\
 		*(.ref.text)						\
 	MEM_KEEP(init.text)						\
 	MEM_KEEP(exit.text)						\
@@ -531,15 +535,19 @@
 
 #define INIT_TEXT							\
 	*(.init.text)							\
+	*(.text.startup)						\
 	MEM_DISCARD(init.text)
 
 #define EXIT_DATA							\
 	*(.exit.data)							\
+	*(.fini_array)							\
+	*(.dtors)							\
 	MEM_DISCARD(exit.data)						\
 	MEM_DISCARD(exit.rodata)
 
 #define EXIT_TEXT							\
 	*(.exit.text)							\
+	*(.text.exit)							\
 	MEM_DISCARD(exit.text)
 
 #define EXIT_CALL							\
@@ -721,7 +729,14 @@
  */
 #define PERCPU_INPUT(cacheline)						\
 	VMLINUX_SYMBOL(__per_cpu_start) = .;				\
+	VMLINUX_SYMBOL(__per_cpu_user_mapped_start) = .;		\
 	*(.data..percpu..first)						\
+	. = ALIGN(cacheline);						\
+	*(.data..percpu..user_mapped)					\
+	*(.data..percpu..user_mapped..shared_aligned)			\
+	. = ALIGN(PAGE_SIZE);						\
+	*(.data..percpu..user_mapped..page_aligned)			\
+	VMLINUX_SYMBOL(__per_cpu_user_mapped_end) = .;			\
 	. = ALIGN(PAGE_SIZE);						\
 	*(.data..percpu..page_aligned)					\
 	. = ALIGN(cacheline);						\
--- linux-4.4.0.orig/include/crypto/dh.h
+++ linux-4.4.0/include/crypto/dh.h
@@ -0,0 +1,87 @@
+/*
+ * Diffie-Hellman secret to be used with kpp API along with helper functions
+ *
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#ifndef _CRYPTO_DH_
+#define _CRYPTO_DH_
+
+/**
+ * DOC: DH Helper Functions
+ *
+ * To use DH with the KPP cipher API, the following data structure and
+ * functions should be used.
+ *
+ * To use DH with KPP, the following functions should be used to operate on
+ * a DH private key. The packet private key that can be set with
+ * the KPP API function call of crypto_kpp_set_secret.
+ */
+
+/**
+ * struct dh - define a DH private key
+ *
+ * @key:	Private DH key
+ * @p:		Diffie-Hellman parameter P
+ * @g:		Diffie-Hellman generator G
+ * @key_size:	Size of the private DH key
+ * @p_size:	Size of DH parameter P
+ * @g_size:	Size of DH generator G
+ */
+struct dh {
+	void *key;
+	void *p;
+	void *g;
+	unsigned int key_size;
+	unsigned int p_size;
+	unsigned int g_size;
+};
+
+/**
+ * crypto_dh_key_len() - Obtain the size of the private DH key
+ * @params:	private DH key
+ *
+ * This function returns the packet DH key size. A caller can use that
+ * with the provided DH private key reference to obtain the required
+ * memory size to hold a packet key.
+ *
+ * Return: size of the key in bytes
+ */
+int crypto_dh_key_len(const struct dh *params);
+
+/**
+ * crypto_dh_encode_key() - encode the private key
+ * @buf:	Buffer allocated by the caller to hold the packet DH
+ *		private key. The buffer should be at least crypto_dh_key_len
+ *		bytes in size.
+ * @len:	Length of the packet private key buffer
+ * @params:	Buffer with the caller-specified private key
+ *
+ * The DH implementations operate on a packet representation of the private
+ * key.
+ *
+ * Return:	-EINVAL if buffer has insufficient size, 0 on success
+ */
+int crypto_dh_encode_key(char *buf, unsigned int len, const struct dh *params);
+
+/**
+ * crypto_dh_decode_key() - decode a private key
+ * @buf:	Buffer holding a packet key that should be decoded
+ * @len:	Length of the packet private key buffer
+ * @params:	Buffer allocated by the caller that is filled with the
+ *		unpacked DH private key.
+ *
+ * The unpacking obtains the private key by pointing @p to the correct location
+ * in @buf. Thus, both pointers refer to the same memory.
+ *
+ * Return:	-EINVAL if buffer has insufficient size, 0 on success
+ */
+int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params);
+
+#endif
--- linux-4.4.0.orig/include/crypto/ecdh.h
+++ linux-4.4.0/include/crypto/ecdh.h
@@ -0,0 +1,88 @@
+/*
+ * ECDH params to be used with kpp API
+ *
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#ifndef _CRYPTO_ECDH_
+#define _CRYPTO_ECDH_
+
+/**
+ * DOC: ECDH Helper Functions
+ *
+ * To use ECDH with the KPP cipher API, the following data structure and
+ * functions should be used.
+ *
+ * The ECC curves known to the ECDH implementation are specified in this
+ * header file.
+ *
+ * To use ECDH with KPP, the following functions should be used to operate on
+ * an ECDH private key. The packet private key that can be set with
+ * the KPP API function call of crypto_kpp_set_secret.
+ */
+
+/* Curves IDs */
+#define ECC_CURVE_NIST_P192	0x0001
+#define ECC_CURVE_NIST_P256	0x0002
+
+/**
+ * struct ecdh - define an ECDH private key
+ *
+ * @curve_id:	ECC curve the key is based on.
+ * @key:	Private ECDH key
+ * @key_size:	Size of the private ECDH key
+ */
+struct ecdh {
+	unsigned short curve_id;
+	char *key;
+	unsigned short key_size;
+};
+
+/**
+ * crypto_ecdh_key_len() - Obtain the size of the private ECDH key
+ * @params:	private ECDH key
+ *
+ * This function returns the packet ECDH key size. A caller can use that
+ * with the provided ECDH private key reference to obtain the required
+ * memory size to hold a packet key.
+ *
+ * Return: size of the key in bytes
+ */
+int crypto_ecdh_key_len(const struct ecdh *params);
+
+/**
+ * crypto_ecdh_encode_key() - encode the private key
+ * @buf:	Buffer allocated by the caller to hold the packet ECDH
+ *		private key. The buffer should be at least crypto_ecdh_key_len
+ *		bytes in size.
+ * @len:	Length of the packet private key buffer
+ * @p:		Buffer with the caller-specified private key
+ *
+ * The ECDH implementations operate on a packet representation of the private
+ * key.
+ *
+ * Return:	-EINVAL if buffer has insufficient size, 0 on success
+ */
+int crypto_ecdh_encode_key(char *buf, unsigned int len, const struct ecdh *p);
+
+/**
+ * crypto_ecdh_decode_key() - decode a private key
+ * @buf:	Buffer holding a packet key that should be decoded
+ * @len:	Length of the packet private key buffer
+ * @p:		Buffer allocated by the caller that is filled with the
+ *		unpacked ECDH private key.
+ *
+ * The unpacking obtains the private key by pointing @p to the correct location
+ * in @buf. Thus, both pointers refer to the same memory.
+ *
+ * Return:	-EINVAL if buffer has insufficient size, 0 on success
+ */
+int crypto_ecdh_decode_key(const char *buf, unsigned int len, struct ecdh *p);
+
+#endif
--- linux-4.4.0.orig/include/crypto/ghash.h
+++ linux-4.4.0/include/crypto/ghash.h
@@ -0,0 +1,23 @@
+/*
+ * Common values for GHASH algorithms
+ */
+
+#ifndef __CRYPTO_GHASH_H__
+#define __CRYPTO_GHASH_H__
+
+#include <linux/types.h>
+#include <crypto/gf128mul.h>
+
+#define GHASH_BLOCK_SIZE	16
+#define GHASH_DIGEST_SIZE	16
+
+struct ghash_ctx {
+	struct gf128mul_4k *gf128;
+};
+
+struct ghash_desc_ctx {
+	u8 buffer[GHASH_BLOCK_SIZE];
+	u32 bytes;
+};
+
+#endif
--- linux-4.4.0.orig/include/crypto/hash.h
+++ linux-4.4.0/include/crypto/hash.h
@@ -204,6 +204,7 @@
 		      unsigned int keylen);
 
 	unsigned int reqsize;
+	bool has_setkey;
 	struct crypto_tfm base;
 };
 
@@ -375,6 +376,11 @@
 int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
 			unsigned int keylen);
 
+static inline bool crypto_ahash_has_setkey(struct crypto_ahash *tfm)
+{
+	return tfm->has_setkey;
+}
+
 /**
  * crypto_ahash_finup() - update and finalize message digest
  * @req: reference to the ahash_request handle that holds all information
--- linux-4.4.0.orig/include/crypto/hash_info.h
+++ linux-4.4.0/include/crypto/hash_info.h
@@ -34,6 +34,9 @@
 #define TGR160_DIGEST_SIZE 20
 #define TGR192_DIGEST_SIZE 24
 
+/* not defined in include/crypto/ */
+#define SM3256_DIGEST_SIZE 32
+
 extern const char *const hash_algo_name[HASH_ALGO__LAST];
 extern const int hash_digest_size[HASH_ALGO__LAST];
 
--- linux-4.4.0.orig/include/crypto/if_alg.h
+++ linux-4.4.0/include/crypto/if_alg.h
@@ -30,6 +30,9 @@
 
 	struct sock *parent;
 
+	atomic_t refcnt;
+	atomic_t nokey_refcnt;
+
 	const struct af_alg_type *type;
 	void *private;
 };
@@ -50,9 +53,11 @@
 	void (*release)(void *private);
 	int (*setkey)(void *private, const u8 *key, unsigned int keylen);
 	int (*accept)(void *private, struct sock *sk);
+	int (*accept_nokey)(void *private, struct sock *sk);
 	int (*setauthsize)(void *private, unsigned int authsize);
 
 	struct proto_ops *ops;
+	struct proto_ops *ops_nokey;
 	struct module *owner;
 	char name[14];
 };
@@ -67,6 +72,7 @@
 int af_alg_unregister_type(const struct af_alg_type *type);
 
 int af_alg_release(struct socket *sock);
+void af_alg_release_parent(struct sock *sk);
 int af_alg_accept(struct sock *sk, struct socket *newsock);
 
 int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len);
@@ -83,11 +89,6 @@
 	return (struct alg_sock *)sk;
 }
 
-static inline void af_alg_release_parent(struct sock *sk)
-{
-	sock_put(alg_sk(sk)->parent);
-}
-
 static inline void af_alg_init_completion(struct af_alg_completion *completion)
 {
 	init_completion(&completion->completion);
--- linux-4.4.0.orig/include/crypto/internal/hash.h
+++ linux-4.4.0/include/crypto/internal/hash.h
@@ -83,6 +83,16 @@
 			    struct ahash_instance *inst);
 void ahash_free_instance(struct crypto_instance *inst);
 
+int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+		    unsigned int keylen);
+
+static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
+{
+	return alg->setkey != shash_no_setkey;
+}
+
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg);
+
 int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
 			    struct hash_alg_common *alg,
 			    struct crypto_instance *inst);
@@ -173,6 +183,16 @@
 	return crypto_alloc_instance2(name, alg, ahash_instance_headroom());
 }
 
+static inline void ahash_request_complete(struct ahash_request *req, int err)
+{
+	req->base.complete(&req->base, err);
+}
+
+static inline u32 ahash_request_flags(struct ahash_request *req)
+{
+	return req->base.flags;
+}
+
 static inline struct crypto_ahash *crypto_spawn_ahash(
 	struct crypto_ahash_spawn *spawn)
 {
--- linux-4.4.0.orig/include/crypto/internal/kpp.h
+++ linux-4.4.0/include/crypto/internal/kpp.h
@@ -0,0 +1,64 @@
+/*
+ * Key-agreement Protocol Primitives (KPP)
+ *
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#ifndef _CRYPTO_KPP_INT_H
+#define _CRYPTO_KPP_INT_H
+#include <crypto/kpp.h>
+#include <crypto/algapi.h>
+
+/*
+ * Transform internal helpers.
+ */
+static inline void *kpp_request_ctx(struct kpp_request *req)
+{
+	return req->__ctx;
+}
+
+static inline void *kpp_tfm_ctx(struct crypto_kpp *tfm)
+{
+	return tfm->base.__crt_ctx;
+}
+
+static inline void kpp_request_complete(struct kpp_request *req, int err)
+{
+	req->base.complete(&req->base, err);
+}
+
+static inline const char *kpp_alg_name(struct crypto_kpp *tfm)
+{
+	return crypto_kpp_tfm(tfm)->__crt_alg->cra_name;
+}
+
+/**
+ * crypto_register_kpp() -- Register key-agreement protocol primitives algorithm
+ *
+ * Function registers an implementation of a key-agreement protocol primitive
+ * algorithm
+ *
+ * @alg:	algorithm definition
+ *
+ * Return: zero on success; error code in case of error
+ */
+int crypto_register_kpp(struct kpp_alg *alg);
+
+/**
+ * crypto_unregister_kpp() -- Unregister key-agreement protocol primitive
+ * algorithm
+ *
+ * Function unregisters an implementation of a key-agreement protocol primitive
+ * algorithm
+ *
+ * @alg:	algorithm definition
+ */
+void crypto_unregister_kpp(struct kpp_alg *alg);
+
+#endif
--- linux-4.4.0.orig/include/crypto/kpp.h
+++ linux-4.4.0/include/crypto/kpp.h
@@ -0,0 +1,339 @@
+/*
+ * Key-agreement Protocol Primitives (KPP)
+ *
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_KPP_
+#define _CRYPTO_KPP_
+#include <linux/crypto.h>
+
+/**
+ * struct kpp_request
+ *
+ * @base:	Common attributes for async crypto requests
+ * @src:	Source data
+ * @dst:	Destination data
+ * @src_len:	Size of the input buffer
+ * @dst_len:	Size of the output buffer. It needs to be at least
+ *		as big as the expected result depending	on the operation
+ *		After operation it will be updated with the actual size of the
+ *		result. In case of error where the dst sgl size was insufficient,
+ *		it will be updated to the size required for the operation.
+ * @__ctx:	Start of private context data
+ */
+struct kpp_request {
+	struct crypto_async_request base;
+	struct scatterlist *src;
+	struct scatterlist *dst;
+	unsigned int src_len;
+	unsigned int dst_len;
+	void *__ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
+/**
+ * struct crypto_kpp - user-instantiated object which encapsulate
+ * algorithms and core processing logic
+ *
+ * @base:	Common crypto API algorithm data structure
+ */
+struct crypto_kpp {
+	struct crypto_tfm base;
+};
+
+/**
+ * struct kpp_alg - generic key-agreement protocol primitives
+ *
+ * @set_secret:		Function invokes the protocol specific function to
+ *			store the secret private key along with parameters.
+ *			The implementation knows how to decode the buffer
+ * @generate_public_key: Function generate the public key to be sent to the
+ *			counterpart. In case of error, where output is not big
+ *			enough req->dst_len will be updated to the size
+ *			required
+ * @compute_shared_secret: Function compute the shared secret as defined by
+ *			the algorithm. The result is given back to the user.
+ *			In case of error, where output is not big enough,
+ *			req->dst_len will be updated to the size required
+ * @max_size:		Function returns the size of the output buffer
+ * @init:		Initialize the object. This is called only once at
+ *			instantiation time. In case the cryptographic hardware
+ *			needs to be initialized. Software fallback should be
+ *			put in place here.
+ * @exit:		Undo everything @init did.
+ *
+ * @reqsize:		Request context size required by algorithm
+ *			implementation
+ * @base:		Common crypto API algorithm data structure
+ */
+struct kpp_alg {
+	int (*set_secret)(struct crypto_kpp *tfm, void *buffer,
+			  unsigned int len);
+	int (*generate_public_key)(struct kpp_request *req);
+	int (*compute_shared_secret)(struct kpp_request *req);
+
+	int (*max_size)(struct crypto_kpp *tfm);
+
+	int (*init)(struct crypto_kpp *tfm);
+	void (*exit)(struct crypto_kpp *tfm);
+
+	unsigned int reqsize;
+	struct crypto_alg base;
+};
+
+/**
+ * DOC: Generic Key-agreement Protocol Primitives API
+ *
+ * The KPP API is used with the algorithm type
+ * CRYPTO_ALG_TYPE_KPP (listed as type "kpp" in /proc/crypto)
+ */
+
+/**
+ * crypto_alloc_kpp() - allocate KPP tfm handle
+ * @alg_name: is the name of the kpp algorithm (e.g. "dh", "ecdh")
+ * @type: specifies the type of the algorithm
+ * @mask: specifies the mask for the algorithm
+ *
+ * Allocate a handle for kpp algorithm. The returned struct crypto_kpp
+ * is required for any following API invocation
+ *
+ * Return: allocated handle in case of success; IS_ERR() is true in case of
+ *	   an error, PTR_ERR() returns the error code.
+ */
+struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask);
+
+static inline struct crypto_tfm *crypto_kpp_tfm(struct crypto_kpp *tfm)
+{
+	return &tfm->base;
+}
+
+static inline struct kpp_alg *__crypto_kpp_alg(struct crypto_alg *alg)
+{
+	return container_of(alg, struct kpp_alg, base);
+}
+
+static inline struct crypto_kpp *__crypto_kpp_tfm(struct crypto_tfm *tfm)
+{
+	return container_of(tfm, struct crypto_kpp, base);
+}
+
+static inline struct kpp_alg *crypto_kpp_alg(struct crypto_kpp *tfm)
+{
+	return __crypto_kpp_alg(crypto_kpp_tfm(tfm)->__crt_alg);
+}
+
+static inline unsigned int crypto_kpp_reqsize(struct crypto_kpp *tfm)
+{
+	return crypto_kpp_alg(tfm)->reqsize;
+}
+
+static inline void kpp_request_set_tfm(struct kpp_request *req,
+				       struct crypto_kpp *tfm)
+{
+	req->base.tfm = crypto_kpp_tfm(tfm);
+}
+
+static inline struct crypto_kpp *crypto_kpp_reqtfm(struct kpp_request *req)
+{
+	return __crypto_kpp_tfm(req->base.tfm);
+}
+
+/**
+ * crypto_free_kpp() - free KPP tfm handle
+ *
+ * @tfm: KPP tfm handle allocated with crypto_alloc_kpp()
+ */
+static inline void crypto_free_kpp(struct crypto_kpp *tfm)
+{
+	crypto_destroy_tfm(tfm, crypto_kpp_tfm(tfm));
+}
+
+/**
+ * kpp_request_alloc() - allocates kpp request
+ *
+ * @tfm:	KPP tfm handle allocated with crypto_alloc_kpp()
+ * @gfp:	allocation flags
+ *
+ * Return: allocated handle in case of success or NULL in case of an error.
+ */
+static inline struct kpp_request *kpp_request_alloc(struct crypto_kpp *tfm,
+						    gfp_t gfp)
+{
+	struct kpp_request *req;
+
+	req = kmalloc(sizeof(*req) + crypto_kpp_reqsize(tfm), gfp);
+	if (likely(req))
+		kpp_request_set_tfm(req, tfm);
+
+	return req;
+}
+
+/**
+ * kpp_request_free() - zeroize and free kpp request
+ *
+ * @req:	request to free
+ */
+static inline void kpp_request_free(struct kpp_request *req)
+{
+	kzfree(req);
+}
+
+/**
+ * kpp_request_set_callback() - Sets an asynchronous callback.
+ *
+ * Callback will be called when an asynchronous operation on a given
+ * request is finished.
+ *
+ * @req:	request that the callback will be set for
+ * @flgs:	specify for instance if the operation may backlog
+ * @cmpl:	callback which will be called
+ * @data:	private data used by the caller
+ */
+static inline void kpp_request_set_callback(struct kpp_request *req,
+					    u32 flgs,
+					    crypto_completion_t cmpl,
+					    void *data)
+{
+	req->base.complete = cmpl;
+	req->base.data = data;
+	req->base.flags = flgs;
+}
+
+/**
+ * kpp_request_set_input() - Sets input buffer
+ *
+ * Sets parameters required by generate_public_key
+ *
+ * @req:	kpp request
+ * @input:	ptr to input scatter list
+ * @input_len:	size of the input scatter list
+ */
+static inline void kpp_request_set_input(struct kpp_request *req,
+					 struct scatterlist *input,
+					 unsigned int input_len)
+{
+	req->src = input;
+	req->src_len = input_len;
+}
+
+/**
+ * kpp_request_set_output() - Sets output buffer
+ *
+ * Sets parameters required by kpp operation
+ *
+ * @req:	kpp request
+ * @output:	ptr to output scatter list
+ * @output_len:	size of the output scatter list
+ */
+static inline void kpp_request_set_output(struct kpp_request *req,
+					  struct scatterlist *output,
+					  unsigned int output_len)
+{
+	req->dst = output;
+	req->dst_len = output_len;
+}
+
+enum {
+	CRYPTO_KPP_SECRET_TYPE_UNKNOWN,
+	CRYPTO_KPP_SECRET_TYPE_DH,
+	CRYPTO_KPP_SECRET_TYPE_ECDH,
+};
+
+/**
+ * struct kpp_secret - small header for packing secret buffer
+ *
+ * @type:	define type of secret. Each kpp type will define its own
+ * @len:	specify the len of the secret, include the header, that
+ *		follows the struct
+ */
+struct kpp_secret {
+	unsigned short type;
+	unsigned short len;
+};
+
+/**
+ * crypto_kpp_set_secret() - Invoke kpp operation
+ *
+ * Function invokes the specific kpp operation for a given alg.
+ *
+ * @tfm:	tfm handle
+ * @buffer:	Buffer holding the packet representation of the private
+ *		key. The structure of the packet key depends on the particular
+ *		KPP implementation. Packing and unpacking helpers are provided
+ *		for ECDH and DH (see the respective header files for those
+ *		implementations).
+ * @len:	Length of the packet private key buffer.
+ *
+ * Return: zero on success; error code in case of error
+ */
+static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, void *buffer,
+					unsigned int len)
+{
+	struct kpp_alg *alg = crypto_kpp_alg(tfm);
+
+	return alg->set_secret(tfm, buffer, len);
+}
+
+/**
+ * crypto_kpp_generate_public_key() - Invoke kpp operation
+ *
+ * Function invokes the specific kpp operation for generating the public part
+ * for a given kpp algorithm.
+ *
+ * To generate a private key, the caller should use a random number generator.
+ * The output of the requested length serves as the private key.
+ *
+ * @req:	kpp key request
+ *
+ * Return: zero on success; error code in case of error
+ */
+static inline int crypto_kpp_generate_public_key(struct kpp_request *req)
+{
+	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+	struct kpp_alg *alg = crypto_kpp_alg(tfm);
+
+	return alg->generate_public_key(req);
+}
+
+/**
+ * crypto_kpp_compute_shared_secret() - Invoke kpp operation
+ *
+ * Function invokes the specific kpp operation for computing the shared secret
+ * for a given kpp algorithm.
+ *
+ * @req:	kpp key request
+ *
+ * Return: zero on success; error code in case of error
+ */
+static inline int crypto_kpp_compute_shared_secret(struct kpp_request *req)
+{
+	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+	struct kpp_alg *alg = crypto_kpp_alg(tfm);
+
+	return alg->compute_shared_secret(req);
+}
+
+/**
+ * crypto_kpp_maxsize() - Get len for output buffer
+ *
+ * Function returns the output buffer size required
+ *
+ * @tfm:	KPP tfm handle allocated with crypto_alloc_kpp()
+ *
+ * Return: minimum len for output buffer or error code if key hasn't been set
+ */
+static inline int crypto_kpp_maxsize(struct crypto_kpp *tfm)
+{
+	struct kpp_alg *alg = crypto_kpp_alg(tfm);
+
+	return alg->max_size(tfm);
+}
+
+#endif
--- linux-4.4.0.orig/include/crypto/mcryptd.h
+++ linux-4.4.0/include/crypto/mcryptd.h
@@ -26,6 +26,7 @@
 
 struct mcryptd_cpu_queue {
 	struct crypto_queue queue;
+	spinlock_t q_lock;
 	struct work_struct work;
 };
 
--- linux-4.4.0.orig/include/crypto/poly1305.h
+++ linux-4.4.0/include/crypto/poly1305.h
@@ -30,8 +30,6 @@
 };
 
 int crypto_poly1305_init(struct shash_desc *desc);
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
-			   const u8 *key, unsigned int keylen);
 unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
 					const u8 *src, unsigned int srclen);
 int crypto_poly1305_update(struct shash_desc *desc,
--- linux-4.4.0.orig/include/crypto/public_key.h
+++ linux-4.4.0/include/crypto/public_key.h
@@ -24,7 +24,6 @@
 };
 
 extern const char *const pkey_algo_name[PKEY_ALGO__LAST];
-extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST];
 
 /* asymmetric key implementation supports only up to SHA224 */
 #define PKEY_HASH__LAST		(HASH_ALGO_SHA224 + 1)
@@ -59,31 +58,10 @@
  * part.
  */
 struct public_key {
-	const struct public_key_algorithm *algo;
-	u8	capabilities;
-#define PKEY_CAN_ENCRYPT	0x01
-#define PKEY_CAN_DECRYPT	0x02
-#define PKEY_CAN_SIGN		0x04
-#define PKEY_CAN_VERIFY		0x08
+	void *key;
+	u32 keylen;
 	enum pkey_algo pkey_algo : 8;
 	enum pkey_id_type id_type : 8;
-	union {
-		MPI	mpi[5];
-		struct {
-			MPI	p;	/* DSA prime */
-			MPI	q;	/* DSA group order */
-			MPI	g;	/* DSA group generator */
-			MPI	y;	/* DSA public-key value = g^x mod p */
-			MPI	x;	/* DSA secret exponent (if present) */
-		} dsa;
-		struct {
-			MPI	n;	/* RSA public modulus */
-			MPI	e;	/* RSA public encryption exponent */
-			MPI	d;	/* RSA secret encryption exponent (if present) */
-			MPI	p;	/* RSA secret prime (if present) */
-			MPI	q;	/* RSA secret prime (if present) */
-		} rsa;
-	};
 };
 
 extern void public_key_destroy(void *payload);
@@ -92,6 +70,8 @@
  * Public key cryptography signature data
  */
 struct public_key_signature {
+	u8 *s;			/* Signature */
+	u32 s_size;		/* Number of bytes in signature */
 	u8 *digest;
 	u8 digest_size;			/* Number of bytes in digest */
 	u8 nr_mpi;			/* Occupancy of mpi[] */
@@ -109,6 +89,7 @@
 	};
 };
 
+extern struct asymmetric_key_subtype public_key_subtype;
 struct key;
 extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
@@ -119,4 +100,9 @@
 					       const struct asymmetric_key_id *skid,
 					       bool partial);
 
+int public_key_verify_signature(const struct public_key *pkey,
+				const struct public_key_signature *sig);
+
+int rsa_verify_signature(const struct public_key *pkey,
+			 const struct public_key_signature *sig);
 #endif /* _LINUX_PUBLIC_KEY_H */
--- linux-4.4.0.orig/include/crypto/skcipher.h
+++ linux-4.4.0/include/crypto/skcipher.h
@@ -61,6 +61,8 @@
 	unsigned int ivsize;
 	unsigned int reqsize;
 
+	bool has_setkey;
+
 	struct crypto_tfm base;
 };
 
@@ -305,6 +307,11 @@
 	return tfm->setkey(tfm, key, keylen);
 }
 
+static inline bool crypto_skcipher_has_setkey(struct crypto_skcipher *tfm)
+{
+	return tfm->has_setkey;
+}
+
 /**
  * crypto_skcipher_reqtfm() - obtain cipher handle from request
  * @req: skcipher_request out of which the cipher handle is to be obtained
--- linux-4.4.0.orig/include/crypto/xts.h
+++ linux-4.4.0/include/crypto/xts.h
@@ -2,6 +2,9 @@
 #define _CRYPTO_XTS_H
 
 #include <crypto/b128ops.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <linux/fips.h>
 
 struct scatterlist;
 struct blkcipher_desc;
@@ -24,4 +27,28 @@
 	      struct scatterlist *src, unsigned int nbytes,
 	      struct xts_crypt_req *req);
 
+static inline int xts_check_key(struct crypto_tfm *tfm,
+				const u8 *key, unsigned int keylen)
+{
+	u32 *flags = &tfm->crt_flags;
+
+	/*
+	 * 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;
+	}
+
+	/* ensure that the AES and tweak key are not identical */
+	if (fips_enabled &&
+	    !crypto_memneq(key, key + (keylen / 2), keylen / 2)) {
+		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 #endif  /* _CRYPTO_XTS_H */
--- linux-4.4.0.orig/include/drm/drmP.h
+++ linux-4.4.0/include/drm/drmP.h
@@ -158,6 +158,26 @@
 /** \name Macros to make printk easier */
 /*@{*/
 
+#define _DRM_PRINTK(once, level, fmt, ...)				\
+	do {								\
+		printk##once(KERN_##level "[" DRM_NAME "] " fmt,	\
+			     ##__VA_ARGS__);				\
+	} while (0)
+
+#define DRM_INFO(fmt, ...)						\
+	_DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__)
+#define DRM_NOTE(fmt, ...)						\
+	_DRM_PRINTK(, NOTICE, fmt, ##__VA_ARGS__)
+#define DRM_WARN(fmt, ...)						\
+	_DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__)
+
+#define DRM_INFO_ONCE(fmt, ...)						\
+	_DRM_PRINTK(_once, INFO, fmt, ##__VA_ARGS__)
+#define DRM_NOTE_ONCE(fmt, ...)						\
+	_DRM_PRINTK(_once, NOTICE, fmt, ##__VA_ARGS__)
+#define DRM_WARN_ONCE(fmt, ...)						\
+	_DRM_PRINTK(_once, WARNING, fmt, ##__VA_ARGS__)
+
 /**
  * Error output.
  *
@@ -183,12 +203,6 @@
 		drm_err(fmt, ##__VA_ARGS__);				\
 })
 
-#define DRM_INFO(fmt, ...)				\
-	printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
-
-#define DRM_INFO_ONCE(fmt, ...)				\
-	printk_once(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
-
 /**
  * Debug output.
  *
@@ -1029,7 +1043,8 @@
 #endif
 
 extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
-		struct drm_gem_object *obj, int flags);
+					    struct drm_gem_object *obj,
+					    int flags);
 extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
 		struct drm_file *file_priv, uint32_t handle, uint32_t flags,
 		int *prime_fd);
@@ -1108,6 +1123,7 @@
 #define DRM_PCIE_SPEED_80 4
 
 extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask);
+extern int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw);
 
 /* platform section */
 extern int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device);
@@ -1121,4 +1137,7 @@
 	return true;
 }
 
+/* helper for handling conditionals in various for_each macros */
+#define for_each_if(condition) if (!(condition)) {} else
+
 #endif
--- linux-4.4.0.orig/include/drm/drm_atomic.h
+++ linux-4.4.0/include/drm/drm_atomic.h
@@ -130,10 +130,6 @@
 drm_atomic_add_affected_planes(struct drm_atomic_state *state,
 			       struct drm_crtc *crtc);
 
-int
-drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
-			       struct drm_crtc *crtc);
-
 void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
 
 void
@@ -149,7 +145,7 @@
 	     ((connector) = (state)->connectors[__i],			\
 	     (connector_state) = (state)->connector_states[__i], 1); 	\
 	     (__i)++)							\
-		if (connector)
+		for_each_if (connector)
 
 #define for_each_crtc_in_state(state, crtc, crtc_state, __i)	\
 	for ((__i) = 0;						\
@@ -157,7 +153,7 @@
 	     ((crtc) = (state)->crtcs[__i],			\
 	     (crtc_state) = (state)->crtc_states[__i], 1);	\
 	     (__i)++)						\
-		if (crtc_state)
+		for_each_if (crtc_state)
 
 #define for_each_plane_in_state(state, plane, plane_state, __i)		\
 	for ((__i) = 0;							\
@@ -165,7 +161,7 @@
 	     ((plane) = (state)->planes[__i],				\
 	     (plane_state) = (state)->plane_states[__i], 1);		\
 	     (__i)++)							\
-		if (plane_state)
+		for_each_if (plane_state)
 static inline bool
 drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state)
 {
--- linux-4.4.0.orig/include/drm/drm_atomic_helper.h
+++ linux-4.4.0/include/drm/drm_atomic_helper.h
@@ -42,6 +42,10 @@
 			     struct drm_atomic_state *state,
 			     bool async);
 
+bool drm_atomic_helper_framebuffer_changed(struct drm_device *dev,
+					   struct drm_atomic_state *old_state,
+					   struct drm_crtc *crtc);
+
 void drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
 					struct drm_atomic_state *old_state);
 
@@ -81,6 +85,12 @@
 int __drm_atomic_helper_set_config(struct drm_mode_set *set,
 		struct drm_atomic_state *state);
 
+int drm_atomic_helper_disable_all(struct drm_device *dev,
+				  struct drm_modeset_acquire_ctx *ctx);
+struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev);
+int drm_atomic_helper_resume(struct drm_device *dev,
+			     struct drm_atomic_state *state);
+
 int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
 					struct drm_property *property,
 					uint64_t val);
@@ -118,6 +128,8 @@
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
 					  struct drm_plane_state *state);
 
+void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
+					 struct drm_connector_state *conn_state);
 void drm_atomic_helper_connector_reset(struct drm_connector *connector);
 void
 __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
@@ -132,6 +144,9 @@
 					    struct drm_connector_state *state);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
 					  struct drm_connector_state *state);
+void drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
+					u16 *red, u16 *green, u16 *blue,
+					uint32_t start, uint32_t size);
 
 /**
  * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
--- linux-4.4.0.orig/include/drm/drm_cache.h
+++ linux-4.4.0/include/drm/drm_cache.h
@@ -35,4 +35,15 @@
 
 void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
 
+static inline bool drm_arch_can_wc_memory(void)
+{
+#if defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
+	return false;
+#elif defined(CONFIG_MIPS) && defined(CONFIG_CPU_LOONGSON3)
+	return false;
+#else
+	return true;
+#endif
+}
+
 #endif
--- linux-4.4.0.orig/include/drm/drm_crtc.h
+++ linux-4.4.0/include/drm/drm_crtc.h
@@ -259,11 +259,20 @@
  * @mode_changed: crtc_state->mode or crtc_state->enable has been changed
  * @active_changed: crtc_state->active has been toggled.
  * @connectors_changed: connectors to this crtc have been updated
+ * @color_mgmt_changed: color management properties have changed (degamma or
+ *	gamma LUT or CSC matrix)
  * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
+ * @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors
+ * @encoder_mask: bitmask of (1 << drm_encoder_index(encoder)) of attached encoders
  * @last_vblank_count: for helpers and drivers to capture the vblank of the
  * 	update to ensure framebuffer cleanup isn't done too early
  * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
  * @mode: current mode timings
+ * @degamma_lut: Lookup table for converting framebuffer pixel data
+ *	before apply the conversion matrix
+ * @ctm: Transformation matrix
+ * @gamma_lut: Lookup table for converting pixel data after the
+ *	conversion matrix
  * @event: optional pointer to a DRM event to signal upon completion of the
  * 	state update
  * @state: backpointer to global drm_atomic_state
@@ -285,6 +294,7 @@
 	bool mode_changed : 1;
 	bool active_changed : 1;
 	bool connectors_changed : 1;
+	bool color_mgmt_changed : 1;
 
 	/* attached planes bitmask:
 	 * WARNING: transitional helpers do not maintain plane_mask so
@@ -293,6 +303,9 @@
 	 */
 	u32 plane_mask;
 
+	u32 connector_mask;
+	u32 encoder_mask;
+
 	/* last_vblank_count: for vblank waits before cleanup */
 	u32 last_vblank_count;
 
@@ -304,6 +317,11 @@
 	/* blob property to expose current mode to atomic userspace */
 	struct drm_property_blob *mode_blob;
 
+	/* blob property to expose color management to userspace */
+	struct drm_property_blob *degamma_lut;
+	struct drm_property_blob *ctm;
+	struct drm_property_blob *gamma_lut;
+
 	struct drm_pending_vblank_event *event;
 
 	struct drm_atomic_state *state;
@@ -458,7 +476,7 @@
 	int x, y;
 	const struct drm_crtc_funcs *funcs;
 
-	/* CRTC gamma size for reporting to userspace */
+	/* Legacy FB CRTC gamma size for reporting to userspace */
 	uint32_t gamma_size;
 	uint16_t *gamma_store;
 
@@ -1038,6 +1056,15 @@
  * @property_blob_list: list of all the blob property objects
  * @blob_lock: mutex for blob property allocation and management
  * @*_property: core property tracking
+ * @degamma_lut_property: LUT used to convert the framebuffer's colors to linear
+ *	gamma
+ * @degamma_lut_size_property: size of the degamma LUT as supported by the
+ *	driver (read-only)
+ * @ctm_property: Matrix used to convert colors after the lookup in the
+ *	degamma LUT
+ * @gamma_lut_property: LUT used to convert the colors, after the CSC matrix, to
+ *	the gamma space of the connected screen (read-only)
+ * @gamma_lut_size_property: size of the gamma LUT as supported by the driver
  * @preferred_depth: preferred RBG pixel depth, used by fb helpers
  * @prefer_shadow: hint to userspace to prefer shadow-fb rendering
  * @async_page_flip: does this device support async flips on the primary plane?
@@ -1139,6 +1166,13 @@
 	struct drm_property *aspect_ratio_property;
 	struct drm_property *dirty_info_property;
 
+	/* Optional color correction properties */
+	struct drm_property *degamma_lut_property;
+	struct drm_property *degamma_lut_size_property;
+	struct drm_property *ctm_property;
+	struct drm_property *gamma_lut_property;
+	struct drm_property *gamma_lut_size_property;
+
 	/* properties for virtual machine layout */
 	struct drm_property *suggested_x_property;
 	struct drm_property *suggested_y_property;
@@ -1166,8 +1200,19 @@
  */
 #define drm_for_each_plane_mask(plane, dev, plane_mask) \
 	list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
-		if ((plane_mask) & (1 << drm_plane_index(plane)))
+		for_each_if ((plane_mask) & (1 << drm_plane_index(plane)))
 
+/**
+ * drm_for_each_encoder_mask - iterate over encoders specified by bitmask
+ * @encoder: the loop cursor
+ * @dev: the DRM device
+ * @encoder_mask: bitmask of encoder indices
+ *
+ * Iterate over all encoders specified by bitmask.
+ */
+#define drm_for_each_encoder_mask(encoder, dev, encoder_mask) \
+	list_for_each_entry((encoder), &(dev)->mode_config.encoder_list, head) \
+		for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder)))
 
 #define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
 #define obj_to_connector(x) container_of(x, struct drm_connector, base)
@@ -1237,6 +1282,7 @@
 			    struct drm_encoder *encoder,
 			    const struct drm_encoder_funcs *funcs,
 			    int encoder_type);
+extern unsigned int drm_encoder_index(struct drm_encoder *encoder);
 
 /**
  * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
@@ -1540,10 +1586,29 @@
 	return mo ? obj_to_property(mo) : NULL;
 }
 
+/*
+ * Extract a degamma/gamma LUT value provided by user and round it to the
+ * precision supported by the hardware.
+ */
+static inline uint32_t drm_color_lut_extract(uint32_t user_input,
+					     uint32_t bit_precision)
+{
+	uint32_t val = user_input;
+	uint32_t max = 0xffff >> (16 - bit_precision);
+
+	/* Round only if we're not using full precision. */
+	if (bit_precision < 16) {
+		val += 1UL << (16 - bit_precision - 1);
+		val >>= 16 - bit_precision;
+	}
+
+	return clamp_val(val, 0, max);
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, dev) \
 	list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
-		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+		for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY)
 
 #define drm_for_each_plane(plane, dev) \
 	list_for_each_entry(plane, &(dev)->mode_config.plane_list, head)
--- linux-4.4.0.orig/include/drm/drm_crtc_helper.h
+++ linux-4.4.0/include/drm/drm_crtc_helper.h
@@ -189,6 +189,9 @@
 				     struct drm_display_mode *mode,
 				     int x, int y,
 				     struct drm_framebuffer *old_fb);
+extern void drm_helper_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+					      int degamma_lut_size,
+					      int gamma_lut_size);
 extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
 extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
 
@@ -241,5 +244,6 @@
 extern void drm_kms_helper_poll_disable(struct drm_device *dev);
 extern void drm_kms_helper_poll_enable(struct drm_device *dev);
 extern void drm_kms_helper_poll_enable_locked(struct drm_device *dev);
+extern bool drm_kms_helper_is_poll_worker(void);
 
 #endif
--- linux-4.4.0.orig/include/drm/drm_dp_aux_dev.h
+++ linux-4.4.0/include/drm/drm_dp_aux_dev.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *
+ */
+
+#ifndef DRM_DP_AUX_DEV
+#define DRM_DP_AUX_DEV
+
+#include <drm/drm_dp_helper.h>
+
+#ifdef CONFIG_DRM_DP_AUX_CHARDEV
+
+int drm_dp_aux_dev_init(void);
+void drm_dp_aux_dev_exit(void);
+int drm_dp_aux_register_devnode(struct drm_dp_aux *aux);
+void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux);
+
+#else
+
+static inline int drm_dp_aux_dev_init(void)
+{
+	return 0;
+}
+
+static inline void drm_dp_aux_dev_exit(void)
+{
+}
+
+static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
+{
+	return 0;
+}
+
+static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
+{
+}
+
+#endif
+
+#endif
--- linux-4.4.0.orig/include/drm/drm_dp_dual_mode_helper.h
+++ linux-4.4.0/include/drm/drm_dp_dual_mode_helper.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DRM_DP_DUAL_MODE_HELPER_H
+#define DRM_DP_DUAL_MODE_HELPER_H
+
+#include <linux/types.h>
+
+/*
+ * Optional for type 1 DVI adaptors
+ * Mandatory for type 1 HDMI and type 2 adaptors
+ */
+#define DP_DUAL_MODE_HDMI_ID 0x00 /* 00-0f */
+#define  DP_DUAL_MODE_HDMI_ID_LEN 16
+/*
+ * Optional for type 1 adaptors
+ * Mandatory for type 2 adaptors
+ */
+#define DP_DUAL_MODE_ADAPTOR_ID 0x10
+#define  DP_DUAL_MODE_REV_MASK 0x07
+#define  DP_DUAL_MODE_REV_TYPE2 0x00
+#define  DP_DUAL_MODE_TYPE_MASK 0xf0
+#define  DP_DUAL_MODE_TYPE_TYPE2 0xa0
+/* This field is marked reserved in dual mode spec, used in LSPCON */
+#define  DP_DUAL_MODE_TYPE_HAS_DPCD 0x08
+#define DP_DUAL_MODE_IEEE_OUI 0x11 /* 11-13*/
+#define  DP_DUAL_IEEE_OUI_LEN 3
+#define DP_DUAL_DEVICE_ID 0x14 /* 14-19 */
+#define  DP_DUAL_DEVICE_ID_LEN 6
+#define DP_DUAL_MODE_HARDWARE_REV 0x1a
+#define DP_DUAL_MODE_FIRMWARE_MAJOR_REV 0x1b
+#define DP_DUAL_MODE_FIRMWARE_MINOR_REV 0x1c
+#define DP_DUAL_MODE_MAX_TMDS_CLOCK 0x1d
+#define DP_DUAL_MODE_I2C_SPEED_CAP 0x1e
+#define DP_DUAL_MODE_TMDS_OEN 0x20
+#define  DP_DUAL_MODE_TMDS_DISABLE 0x01
+#define DP_DUAL_MODE_HDMI_PIN_CTRL 0x21
+#define  DP_DUAL_MODE_CEC_ENABLE 0x01
+#define DP_DUAL_MODE_I2C_SPEED_CTRL 0x22
+
+/* LSPCON specific registers, defined by MCA */
+#define DP_DUAL_MODE_LSPCON_MODE_CHANGE		0x40
+#define DP_DUAL_MODE_LSPCON_CURRENT_MODE		0x41
+#define  DP_DUAL_MODE_LSPCON_MODE_PCON			0x1
+
+struct i2c_adapter;
+
+ssize_t drm_dp_dual_mode_read(struct i2c_adapter *adapter,
+			      u8 offset, void *buffer, size_t size);
+ssize_t drm_dp_dual_mode_write(struct i2c_adapter *adapter,
+			       u8 offset, const void *buffer, size_t size);
+
+/**
+* enum drm_lspcon_mode
+* @lspcon_mode_ls: Level shifter mode of LSPCON
+*	which drives DP++ to HDMI 1.4 conversion.
+* @lspcon_mode_pcon: Protocol converter mode of LSPCON
+*	which drives DP++ to HDMI 2.0 active conversion.
+*/
+enum drm_lspcon_mode {
+	DRM_LSPCON_MODE_INVALID,
+	DRM_LSPCON_MODE_LS,
+	DRM_LSPCON_MODE_PCON,
+};
+
+/**
+ * enum drm_dp_dual_mode_type - Type of the DP dual mode adaptor
+ * @DRM_DP_DUAL_MODE_NONE: No DP dual mode adaptor
+ * @DRM_DP_DUAL_MODE_UNKNOWN: Could be either none or type 1 DVI adaptor
+ * @DRM_DP_DUAL_MODE_TYPE1_DVI: Type 1 DVI adaptor
+ * @DRM_DP_DUAL_MODE_TYPE1_HDMI: Type 1 HDMI adaptor
+ * @DRM_DP_DUAL_MODE_TYPE2_DVI: Type 2 DVI adaptor
+ * @DRM_DP_DUAL_MODE_TYPE2_HDMI: Type 2 HDMI adaptor
+ * @DRM_DP_DUAL_MODE_TYPE2_LSPCON: Level shifter /protocol converter
+ */
+enum drm_dp_dual_mode_type {
+	DRM_DP_DUAL_MODE_NONE,
+	DRM_DP_DUAL_MODE_UNKNOWN,
+	DRM_DP_DUAL_MODE_TYPE1_DVI,
+	DRM_DP_DUAL_MODE_TYPE1_HDMI,
+	DRM_DP_DUAL_MODE_TYPE2_DVI,
+	DRM_DP_DUAL_MODE_TYPE2_HDMI,
+	DRM_DP_DUAL_MODE_LSPCON,
+};
+
+enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(struct i2c_adapter *adapter);
+int drm_dp_dual_mode_max_tmds_clock(enum drm_dp_dual_mode_type type,
+				    struct i2c_adapter *adapter);
+int drm_dp_dual_mode_get_tmds_output(enum drm_dp_dual_mode_type type,
+				     struct i2c_adapter *adapter, bool *enabled);
+int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type,
+				     struct i2c_adapter *adapter, bool enable);
+const char *drm_dp_get_dual_mode_type_name(enum drm_dp_dual_mode_type type);
+
+int drm_lspcon_get_mode(struct i2c_adapter *adapter,
+			enum drm_lspcon_mode *current_mode);
+int drm_lspcon_set_mode(struct i2c_adapter *adapter,
+			enum drm_lspcon_mode reqd_mode);
+#endif
--- linux-4.4.0.orig/include/drm/drm_dp_helper.h
+++ linux-4.4.0/include/drm/drm_dp_helper.h
@@ -342,6 +342,7 @@
 # define DP_PSR_FRAME_CAPTURE		    (1 << 3)
 # define DP_PSR_SELECTIVE_UPDATE	    (1 << 4)
 # define DP_PSR_IRQ_HPD_WITH_CRC_ERRORS     (1 << 5)
+# define DP_PSR_ENABLE_PSR2		    (1 << 6) /* eDP 1.4a */
 
 #define DP_ADAPTER_CTRL			    0x1a0
 # define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE   (1 << 0)
--- linux-4.4.0.orig/include/drm/drm_dp_mst_helper.h
+++ linux-4.4.0/include/drm/drm_dp_mst_helper.h
@@ -44,8 +44,6 @@
 /**
  * struct drm_dp_mst_port - MST port
  * @kref: reference count for this port.
- * @guid_valid: for DP 1.2 devices if we have validated the GUID.
- * @guid: guid for DP 1.2 device on this port.
  * @port_num: port number
  * @input: if this port is an input port.
  * @mcs: message capability status - DP 1.2 spec.
@@ -70,10 +68,6 @@
 struct drm_dp_mst_port {
 	struct kref kref;
 
-	/* if dpcd 1.2 device is on this port - its GUID info */
-	bool guid_valid;
-	u8 guid[16];
-
 	u8 port_num;
 	bool input;
 	bool mcs;
@@ -94,6 +88,7 @@
 	struct drm_dp_mst_topology_mgr *mgr;
 
 	struct edid *cached_edid; /* for DP logical ports - make tiling work */
+	bool has_audio;
 };
 
 /**
@@ -109,10 +104,12 @@
  * @tx_slots: transmission slots for this device.
  * @last_seqno: last sequence number used to talk to this.
  * @link_address_sent: if a link address message has been sent to this device yet.
+ * @guid: guid for DP 1.2 branch device. port under this branch can be
+ * identified by port #.
  *
  * This structure represents an MST branch device, there is one
- * primary branch device at the root, along with any others connected
- * to downstream ports
+ * primary branch device at the root, along with any other branches connected
+ * to downstream port of parent branches.
  */
 struct drm_dp_mst_branch {
 	struct kref kref;
@@ -131,6 +128,9 @@
 	struct drm_dp_sideband_msg_tx *tx_slots[2];
 	int last_seqno;
 	bool link_address_sent;
+
+	/* global unique identifier to identify branch devices */
+	u8 guid[16];
 };
 
 
@@ -215,13 +215,13 @@
 	struct drm_dp_sideband_msg_hdr initial_hdr;
 };
 
-
+#define DRM_DP_MAX_SDP_STREAMS 16
 struct drm_dp_allocate_payload {
 	u8 port_number;
 	u8 number_sdp_streams;
 	u8 vcpi;
 	u16 pbn;
-	u8 sdp_stream_sink[8];
+	u8 sdp_stream_sink[DRM_DP_MAX_SDP_STREAMS];
 };
 
 struct drm_dp_allocate_payload_ack_reply {
@@ -304,7 +304,7 @@
 
 struct drm_dp_query_payload_ack_reply {
 	u8 port_number;
-	u8 allocated_pbn;
+	u16 allocated_pbn;
 };
 
 struct drm_dp_sideband_msg_req_body {
@@ -405,11 +405,9 @@
  * @conn_base_id: DRM connector ID this mgr is connected to.
  * @down_rep_recv: msg receiver state for down replies.
  * @up_req_recv: msg receiver state for up requests.
- * @lock: protects mst state, primary, guid, dpcd.
+ * @lock: protects mst state, primary, dpcd.
  * @mst_state: if this manager is enabled for an MST capable port.
  * @mst_primary: pointer to the primary branch device.
- * @guid_valid: GUID valid for the primary branch device.
- * @guid: GUID for primary port.
  * @dpcd: cache of DPCD for primary port.
  * @pbn_div: PBN to slots divisor.
  *
@@ -431,13 +429,11 @@
 	struct drm_dp_sideband_msg_rx up_req_recv;
 
 	/* pointer to info about the initial MST device */
-	struct mutex lock; /* protects mst_state + primary + guid + dpcd */
+	struct mutex lock; /* protects mst_state + primary + dpcd */
 
 	bool mst_state;
 	struct drm_dp_mst_branch *mst_primary;
-	/* primary MST device GUID */
-	bool guid_valid;
-	u8 guid[16];
+
 	u8 dpcd[DP_RECEIVER_CAP_SIZE];
 	u8 sink_count;
 	int pbn_div;
@@ -450,9 +446,7 @@
 	   the mstb tx_slots and txmsg->state once they are queued */
 	struct mutex qlock;
 	struct list_head tx_msg_downq;
-	struct list_head tx_msg_upq;
 	bool tx_down_in_progress;
-	bool tx_up_in_progress;
 
 	/* payload info + lock for it */
 	struct mutex payload_lock;
@@ -484,6 +478,8 @@
 
 enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
 
+bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr,
+					struct drm_dp_mst_port *port);
 struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
 
 
--- linux-4.4.0.orig/include/drm/drm_fb_helper.h
+++ linux-4.4.0/include/drm/drm_fb_helper.h
@@ -148,6 +148,7 @@
 };
 
 #ifdef CONFIG_DRM_FBDEV_EMULATION
+int drm_fb_helper_modinit(void);
 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
 			   const struct drm_fb_helper_funcs *funcs);
 int drm_fb_helper_init(struct drm_device *dev,
@@ -212,6 +213,11 @@
 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
 				       struct drm_connector *connector);
 #else
+static inline int drm_fb_helper_modinit(void)
+{
+	return 0;
+}
+
 static inline void drm_fb_helper_prepare(struct drm_device *dev,
 					struct drm_fb_helper *helper,
 					const struct drm_fb_helper_funcs *funcs)
--- linux-4.4.0.orig/include/drm/drm_fixed.h
+++ linux-4.4.0/include/drm/drm_fixed.h
@@ -73,18 +73,28 @@
 #define DRM_FIXED_ONE		(1ULL << DRM_FIXED_POINT)
 #define DRM_FIXED_DECIMAL_MASK	(DRM_FIXED_ONE - 1)
 #define DRM_FIXED_DIGITS_MASK	(~DRM_FIXED_DECIMAL_MASK)
+#define DRM_FIXED_EPSILON	1LL
+#define DRM_FIXED_ALMOST_ONE	(DRM_FIXED_ONE - DRM_FIXED_EPSILON)
 
 static inline s64 drm_int2fixp(int a)
 {
 	return ((s64)a) << DRM_FIXED_POINT;
 }
 
-static inline int drm_fixp2int(int64_t a)
+static inline int drm_fixp2int(s64 a)
 {
 	return ((s64)a) >> DRM_FIXED_POINT;
 }
 
-static inline unsigned drm_fixp_msbset(int64_t a)
+static inline int drm_fixp2int_ceil(s64 a)
+{
+	if (a > 0)
+		return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE);
+	else
+		return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);
+}
+
+static inline unsigned drm_fixp_msbset(s64 a)
 {
 	unsigned shift, sign = (a >> 63) & 1;
 
@@ -136,6 +146,45 @@
 	return result;
 }
 
+static inline s64 drm_fixp_from_fraction(s64 a, s64 b)
+{
+	s64 res;
+	bool a_neg = a < 0;
+	bool b_neg = b < 0;
+	u64 a_abs = a_neg ? -a : a;
+	u64 b_abs = b_neg ? -b : b;
+	u64 rem;
+
+	/* determine integer part */
+	u64 res_abs  = div64_u64_rem(a_abs, b_abs, &rem);
+
+	/* determine fractional part */
+	{
+		u32 i = DRM_FIXED_POINT;
+
+		do {
+			rem <<= 1;
+			res_abs <<= 1;
+			if (rem >= b_abs) {
+				res_abs |= 1;
+				rem -= b_abs;
+			}
+		} while (--i != 0);
+	}
+
+	/* round up LSB */
+	{
+		u64 summand = (rem << 1) >= b_abs;
+
+		res_abs += summand;
+	}
+
+	res = (s64) res_abs;
+	if (a_neg ^ b_neg)
+		res = -res;
+	return res;
+}
+
 static inline s64 drm_fixp_exp(s64 x)
 {
 	s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000);
--- linux-4.4.0.orig/include/drm/drm_mem_util.h
+++ linux-4.4.0/include/drm/drm_mem_util.h
@@ -54,6 +54,25 @@
 			 GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
 }
 
+static __inline__ void *drm_malloc_gfp(size_t nmemb, size_t size, gfp_t gfp)
+{
+	if (size != 0 && nmemb > SIZE_MAX / size)
+		return NULL;
+
+	if (size * nmemb <= PAGE_SIZE)
+		return kmalloc(nmemb * size, gfp);
+
+	if (gfp & __GFP_RECLAIMABLE) {
+		void *ptr = kmalloc(nmemb * size,
+				    gfp | __GFP_NOWARN | __GFP_NORETRY);
+		if (ptr)
+			return ptr;
+	}
+
+	return __vmalloc(size * nmemb,
+			 gfp | __GFP_HIGHMEM, PAGE_KERNEL);
+}
+
 static __inline void drm_free_large(void *ptr)
 {
 	kvfree(ptr);
--- linux-4.4.0.orig/include/drm/drm_mipi_dsi.h
+++ linux-4.4.0/include/drm/drm_mipi_dsi.h
@@ -163,6 +163,31 @@
 	return container_of(dev, struct mipi_dsi_device, dev);
 }
 
+/**
+ * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
+ *                                given pixel format defined by the MIPI DSI
+ *                                specification
+ * @fmt: MIPI DSI pixel format
+ *
+ * Returns: The number of bits per pixel of the given pixel format.
+ */
+static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
+{
+	switch (fmt) {
+	case MIPI_DSI_FMT_RGB888:
+	case MIPI_DSI_FMT_RGB666:
+		return 24;
+
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		return 18;
+
+	case MIPI_DSI_FMT_RGB565:
+		return 16;
+	}
+
+	return -EINVAL;
+}
+
 struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
 int mipi_dsi_attach(struct mipi_dsi_device *dsi);
 int mipi_dsi_detach(struct mipi_dsi_device *dsi);
--- linux-4.4.0.orig/include/drm/drm_modeset_lock.h
+++ linux-4.4.0/include/drm/drm_modeset_lock.h
@@ -138,7 +138,7 @@
 struct drm_modeset_acquire_ctx *
 drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc);
 
-int drm_modeset_lock_all_crtcs(struct drm_device *dev,
-		struct drm_modeset_acquire_ctx *ctx);
+int drm_modeset_lock_all_ctx(struct drm_device *dev,
+			     struct drm_modeset_acquire_ctx *ctx);
 
 #endif /* DRM_MODESET_LOCK_H_ */
--- linux-4.4.0.orig/include/drm/drm_rect.h
+++ linux-4.4.0/include/drm/drm_rect.h
@@ -162,7 +162,8 @@
 int drm_rect_calc_vscale_relaxed(struct drm_rect *src,
 				 struct drm_rect *dst,
 				 int min_vscale, int max_vscale);
-void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point);
+void drm_rect_debug_print(const char *prefix,
+			  const struct drm_rect *r, bool fixed_point);
 void drm_rect_rotate(struct drm_rect *r,
 		     int width, int height,
 		     unsigned int rotation);
--- linux-4.4.0.orig/include/drm/i915_component.h
+++ linux-4.4.0/include/drm/i915_component.h
@@ -45,7 +45,21 @@
 	void (*put_power)(struct device *);
 	void (*codec_wake_override)(struct device *, bool enable);
 	int (*get_cdclk_freq)(struct device *);
-	int (*sync_audio_rate)(struct device *, int port, int rate);
+	int (*sync_audio_rate)(struct device *, int port, int pipe, int rate);
+	/**
+	 * @get_eld: fill the audio state and ELD bytes for the given port
+	 *
+	 * Called from audio driver to get the HDMI/DP audio state of the given
+	 * digital port, and also fetch ELD bytes to the given pointer.
+	 *
+	 * It returns the byte size of the original ELD (not the actually
+	 * copied size), zero for an invalid ELD, or a negative error code.
+	 *
+	 * Note that the returned size may be over @max_bytes.  Then it
+	 * implies that only a part of ELD has been copied to the buffer.
+	 */
+	int (*get_eld)(struct device *, int port, int pipe, bool *enabled,
+		       unsigned char *buf, int max_bytes);
 };
 
 struct i915_audio_component_audio_ops {
@@ -56,7 +70,7 @@
 	 * @audio_ptr:		HDA driver object
 	 * @port:	Which port has changed (PORTA / PORTB / PORTC etc)
 	 */
-	void (*pin_eld_notify)(void *audio_ptr, int port);
+	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
 };
 
 /**
--- linux-4.4.0.orig/include/drm/i915_drm_bpo.h
+++ linux-4.4.0/include/drm/i915_drm_bpo.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef _I915_DRM_BPO_H_
+#define _I915_DRM_BPO_H_
+
+/* For use by IPS driver */
+extern unsigned long i915_bpo_read_mch_val(void);
+extern bool i915_bpo_gpu_raise(void);
+extern bool i915_bpo_gpu_lower(void);
+extern bool i915_bpo_gpu_busy(void);
+extern bool i915_bpo_gpu_turbo_disable(void);
+
+#endif				/* _I915_DRM_BPO_H_ */
--- linux-4.4.0.orig/include/drm/i915_pciids.h
+++ linux-4.4.0/include/drm/i915_pciids.h
@@ -277,18 +277,63 @@
 	INTEL_VGA_DEVICE(0x191D, info)  /* WKS GT2 */
 
 #define INTEL_SKL_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ \
 	INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */ \
 	INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
-	INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */ \
+	INTEL_VGA_DEVICE(0x192A, info)  /* SRV GT3 */
 
-#define INTEL_SKL_IDS(info) \
+#define INTEL_SKL_GT4_IDS(info) \
+	INTEL_VGA_DEVICE(0x1932, info), /* DT GT4 */ \
+	INTEL_VGA_DEVICE(0x193B, info), /* Halo GT4 */ \
+	INTEL_VGA_DEVICE(0x193D, info), /* WKS GT4 */ \
+	INTEL_VGA_DEVICE(0x193A, info)  /* SRV GT4 */
+
+#define INTEL_SKL_IDS(info)	 \
 	INTEL_SKL_GT1_IDS(info), \
 	INTEL_SKL_GT2_IDS(info), \
-	INTEL_SKL_GT3_IDS(info)
+	INTEL_SKL_GT3_IDS(info), \
+	INTEL_SKL_GT4_IDS(info)
 
 #define INTEL_BXT_IDS(info) \
 	INTEL_VGA_DEVICE(0x0A84, info), \
 	INTEL_VGA_DEVICE(0x1A84, info), \
-	INTEL_VGA_DEVICE(0x5A84, info)
+	INTEL_VGA_DEVICE(0x1A85, info), \
+	INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */ \
+	INTEL_VGA_DEVICE(0x5A85, info)  /* APL HD Graphics 500 */
+
+#define INTEL_KBL_GT1_IDS(info)	\
+	INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \
+	INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \
+	INTEL_VGA_DEVICE(0x5917, info), /* DT  GT1.5 */ \
+	INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \
+	INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \
+	INTEL_VGA_DEVICE(0x5902, info), /* DT  GT1 */ \
+	INTEL_VGA_DEVICE(0x5908, info), /* Halo GT1 */ \
+	INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \
+	INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */
+
+#define INTEL_KBL_GT2_IDS(info)	\
+	INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \
+	INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \
+	INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \
+	INTEL_VGA_DEVICE(0x5912, info), /* DT  GT2 */ \
+	INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \
+	INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \
+	INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */
+
+#define INTEL_KBL_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x5923, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x5927, info) /* ULT GT3 */
+
+#define INTEL_KBL_GT4_IDS(info) \
+	INTEL_VGA_DEVICE(0x593B, info) /* Halo GT4 */
+
+#define INTEL_KBL_IDS(info) \
+	INTEL_KBL_GT1_IDS(info), \
+	INTEL_KBL_GT2_IDS(info), \
+	INTEL_KBL_GT3_IDS(info), \
+	INTEL_KBL_GT4_IDS(info)
 
 #endif /* _I915_PCIIDS_H */
--- linux-4.4.0.orig/include/drm/ttm/ttm_bo_api.h
+++ linux-4.4.0/include/drm/ttm/ttm_bo_api.h
@@ -316,6 +316,20 @@
  */
 extern int ttm_bo_wait(struct ttm_buffer_object *bo, bool lazy,
 		       bool interruptible, bool no_wait);
+
+/**
+ * ttm_bo_mem_compat - Check if proposed placement is compatible with a bo
+ *
+ * @placement:  Return immediately if buffer is busy.
+ * @mem:  The struct ttm_mem_reg indicating the region where the bo resides
+ * @new_flags: Describes compatible placement found
+ *
+ * Returns true if the placement is compatible
+ */
+extern bool ttm_bo_mem_compat(struct ttm_placement *placement,
+			      struct ttm_mem_reg *mem,
+			      uint32_t *new_flags);
+
 /**
  * ttm_bo_validate
  *
@@ -383,6 +397,16 @@
  */
 extern int ttm_bo_del_from_lru(struct ttm_buffer_object *bo);
 
+/**
+ * ttm_bo_move_to_lru_tail
+ *
+ * @bo: The buffer object.
+ *
+ * Move this BO to the tail of all lru lists used to lookup and reserve an
+ * object. This function must be called with struct ttm_bo_global::lru_lock
+ * held, and is used to make a BO less likely to be considered for eviction.
+ */
+extern void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo);
 
 /**
  * ttm_bo_lock_delayed_workqueue
--- linux-4.4.0.orig/include/drm/ttm/ttm_object.h
+++ linux-4.4.0/include/drm/ttm/ttm_object.h
@@ -229,6 +229,8 @@
  * @ref_type: The type of reference.
  * @existed: Upon completion, indicates that an identical reference object
  * already existed, and the refcount was upped on that object instead.
+ * @require_existed: Fail with -EPERM if an identical ref object didn't
+ * already exist.
  *
  * Checks that the base object is shareable and adds a ref object to it.
  *
@@ -243,7 +245,8 @@
  */
 extern int ttm_ref_object_add(struct ttm_object_file *tfile,
 			      struct ttm_base_object *base,
-			      enum ttm_ref_type ref_type, bool *existed);
+			      enum ttm_ref_type ref_type, bool *existed,
+			      bool require_existed);
 
 extern bool ttm_ref_object_exists(struct ttm_object_file *tfile,
 				  struct ttm_base_object *base);
--- linux-4.4.0.orig/include/dt-bindings/iio/adi,ad5592r.h
+++ linux-4.4.0/include/dt-bindings/iio/adi,ad5592r.h
@@ -0,0 +1,16 @@
+
+#ifndef _DT_BINDINGS_ADI_AD5592R_H
+#define _DT_BINDINGS_ADI_AD5592R_H
+
+#define CH_MODE_UNUSED			0
+#define CH_MODE_ADC			1
+#define CH_MODE_DAC			2
+#define CH_MODE_DAC_AND_ADC		3
+#define CH_MODE_GPIO			8
+
+#define CH_OFFSTATE_PULLDOWN		0
+#define CH_OFFSTATE_OUT_LOW		1
+#define CH_OFFSTATE_OUT_HIGH		2
+#define CH_OFFSTATE_OUT_TRISTATE	3
+
+#endif /* _DT_BINDINGS_ADI_AD5592R_H */
--- linux-4.4.0.orig/include/dt-bindings/pinctrl/omap.h
+++ linux-4.4.0/include/dt-bindings/pinctrl/omap.h
@@ -45,8 +45,8 @@
 #define PIN_OFF_NONE		0
 #define PIN_OFF_OUTPUT_HIGH	(OFF_EN | OFFOUT_EN | OFFOUT_VAL)
 #define PIN_OFF_OUTPUT_LOW	(OFF_EN | OFFOUT_EN)
-#define PIN_OFF_INPUT_PULLUP	(OFF_EN | OFF_PULL_EN | OFF_PULL_UP)
-#define PIN_OFF_INPUT_PULLDOWN	(OFF_EN | OFF_PULL_EN)
+#define PIN_OFF_INPUT_PULLUP	(OFF_EN | OFFOUT_EN | OFF_PULL_EN | OFF_PULL_UP)
+#define PIN_OFF_INPUT_PULLDOWN	(OFF_EN | OFFOUT_EN | OFF_PULL_EN)
 #define PIN_OFF_WAKEUPENABLE	WAKEUP_EN
 
 /*
--- linux-4.4.0.orig/include/keys/system_keyring.h
+++ linux-4.4.0/include/keys/system_keyring.h
@@ -35,4 +35,32 @@
 			      enum key_being_used_for usage);
 #endif
 
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
+extern struct key *system_blacklist_keyring;
+#endif
+
+#ifdef CONFIG_IMA_MOK_KEYRING
+extern struct key *ima_mok_keyring;
+extern struct key *ima_blacklist_keyring;
+
+static inline struct key *get_ima_mok_keyring(void)
+{
+	return ima_mok_keyring;
+}
+static inline struct key *get_ima_blacklist_keyring(void)
+{
+	return ima_blacklist_keyring;
+}
+#else
+static inline struct key *get_ima_mok_keyring(void)
+{
+	return NULL;
+}
+static inline struct key *get_ima_blacklist_keyring(void)
+{
+	return NULL;
+}
+#endif /* CONFIG_IMA_MOK_KEYRING */
+
+
 #endif /* _KEYS_SYSTEM_KEYRING_H */
--- linux-4.4.0.orig/include/keys/trusted-type.h
+++ linux-4.4.0/include/keys/trusted-type.h
@@ -18,6 +18,7 @@
 #define MAX_KEY_SIZE			128
 #define MAX_BLOB_SIZE			512
 #define MAX_PCRINFO_SIZE		64
+#define MAX_DIGEST_SIZE			64
 
 struct trusted_key_payload {
 	struct rcu_head rcu;
@@ -36,6 +37,10 @@
 	uint32_t pcrinfo_len;
 	unsigned char pcrinfo[MAX_PCRINFO_SIZE];
 	int pcrlock;
+	uint32_t hash;
+	uint32_t policydigest_len;
+	unsigned char policydigest[MAX_DIGEST_SIZE];
+	uint32_t policyhandle;
 };
 
 extern struct key_type key_type_trusted;
--- linux-4.4.0.orig/include/keys/user-type.h
+++ linux-4.4.0/include/keys/user-type.h
@@ -31,7 +31,7 @@
 struct user_key_payload {
 	struct rcu_head	rcu;		/* RCU destructor */
 	unsigned short	datalen;	/* length of this data */
-	char		data[0];	/* actual data */
+	char		data[0] __aligned(__alignof__(u64)); /* actual data */
 };
 
 extern struct key_type key_type_user;
--- linux-4.4.0.orig/include/linux/acpi.h
+++ linux-4.4.0/include/linux/acpi.h
@@ -75,7 +75,7 @@
 static inline void acpi_preset_companion(struct device *dev,
 					 struct acpi_device *parent, u64 addr)
 {
-	ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, NULL));
+	ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, false));
 }
 
 static inline const char *acpi_dev_name(struct acpi_device *adev)
@@ -226,7 +226,10 @@
 #ifdef CONFIG_X86_IO_APIC
 extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
 #else
-#define acpi_get_override_irq(gsi, trigger, polarity) (-1)
+static inline int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
+{
+	return -1;
+}
 #endif
 /*
  * This function undoes the effect of one call to acpi_register_gsi().
@@ -601,6 +604,13 @@
 	return -ENODEV;
 }
 
+static inline struct platform_device *
+acpi_create_platform_device(struct acpi_device *adev,
+			    struct property_entry *properties)
+{
+	return NULL;
+}
+
 static inline bool acpi_dma_supported(struct acpi_device *adev)
 {
 	return false;
@@ -920,7 +930,7 @@
 	return NULL;
 }
 
-#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, validate, data, fn) \
+#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \
 	static const void * __acpi_table_##name[]			\
 		__attribute__((unused))					\
 		 = { (void *) table_id,					\
@@ -932,4 +942,10 @@
 #define acpi_probe_device_table(t)	({ int __r = 0; __r;})
 #endif
 
+#ifdef CONFIG_ACPI_SPCR_TABLE
+int parse_spcr(bool earlycon);
+#else
+static inline int parse_spcr(bool earlycon) { return 0; }
+#endif
+
 #endif	/*_LINUX_ACPI_H*/
--- linux-4.4.0.orig/include/linux/arm-smccc.h
+++ linux-4.4.0/include/linux/arm-smccc.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * 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 __LINUX_ARM_SMCCC_H
+#define __LINUX_ARM_SMCCC_H
+
+#include <uapi/linux/const.h>
+
+/*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+ */
+
+#define ARM_SMCCC_STD_CALL	        _AC(0,U)
+#define ARM_SMCCC_FAST_CALL	        _AC(1,U)
+#define ARM_SMCCC_TYPE_SHIFT		31
+
+#define ARM_SMCCC_SMC_32		0
+#define ARM_SMCCC_SMC_64		1
+#define ARM_SMCCC_CALL_CONV_SHIFT	30
+
+#define ARM_SMCCC_OWNER_MASK		0x3F
+#define ARM_SMCCC_OWNER_SHIFT		24
+
+#define ARM_SMCCC_FUNC_MASK		0xFFFF
+
+#define ARM_SMCCC_IS_FAST_CALL(smc_val)	\
+	((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
+#define ARM_SMCCC_IS_64(smc_val) \
+	((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
+#define ARM_SMCCC_FUNC_NUM(smc_val)	((smc_val) & ARM_SMCCC_FUNC_MASK)
+#define ARM_SMCCC_OWNER_NUM(smc_val) \
+	(((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+	(((type) << ARM_SMCCC_TYPE_SHIFT) | \
+	((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+	(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+	((func_num) & ARM_SMCCC_FUNC_MASK))
+
+#define ARM_SMCCC_OWNER_ARCH		0
+#define ARM_SMCCC_OWNER_CPU		1
+#define ARM_SMCCC_OWNER_SIP		2
+#define ARM_SMCCC_OWNER_OEM		3
+#define ARM_SMCCC_OWNER_STANDARD	4
+#define ARM_SMCCC_OWNER_TRUSTED_APP	48
+#define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
+#define ARM_SMCCC_OWNER_TRUSTED_OS	50
+#define ARM_SMCCC_OWNER_TRUSTED_OS_END	63
+
+#define ARM_SMCCC_VERSION_1_0		0x10000
+#define ARM_SMCCC_VERSION_1_1		0x10001
+
+#define ARM_SMCCC_VERSION_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0)
+
+#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 1)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_1					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x8000)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/linkage.h>
+#include <linux/types.h>
+
+/**
+ * struct arm_smccc_res - Result from SMC/HVC call
+ * @a0-a3 result values from registers 0 to 3
+ */
+struct arm_smccc_res {
+	unsigned long a0;
+	unsigned long a1;
+	unsigned long a2;
+	unsigned long a3;
+};
+
+/**
+ * arm_smccc_smc() - make SMC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This function is used to make SMC calls following SMC Calling Convention.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the SMC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the SMC instruction.
+ */
+asmlinkage void arm_smccc_smc(unsigned long a0, unsigned long a1,
+			unsigned long a2, unsigned long a3, unsigned long a4,
+			unsigned long a5, unsigned long a6, unsigned long a7,
+			struct arm_smccc_res *res);
+
+/**
+ * arm_smccc_hvc() - make HVC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This function is used to make HVC calls following SMC Calling
+ * Convention.  The content of the supplied param are copied to registers 0
+ * to 7 prior to the HVC instruction. The return values are updated with
+ * the content from register 0 to 3 on return from the HVC instruction.
+ */
+asmlinkage void arm_smccc_hvc(unsigned long a0, unsigned long a1,
+			unsigned long a2, unsigned long a3, unsigned long a4,
+			unsigned long a5, unsigned long a6, unsigned long a7,
+			struct arm_smccc_res *res);
+
+/* SMCCC v1.1 implementation madness follows */
+#ifdef CONFIG_ARM64
+
+#define SMCCC_SMC_INST	"smc	#0"
+#define SMCCC_HVC_INST	"hvc	#0"
+
+#elif defined(CONFIG_ARM)
+#include <asm/opcodes-sec.h>
+#include <asm/opcodes-virt.h>
+
+#define SMCCC_SMC_INST	__SMC(0)
+#define SMCCC_HVC_INST	__HVC(0)
+
+#endif
+
+#define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x
+
+#define __count_args(...)						\
+	___count_args(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
+
+#define __constraint_write_0						\
+	"+r" (r0), "=&r" (r1), "=&r" (r2), "=&r" (r3)
+#define __constraint_write_1						\
+	"+r" (r0), "+r" (r1), "=&r" (r2), "=&r" (r3)
+#define __constraint_write_2						\
+	"+r" (r0), "+r" (r1), "+r" (r2), "=&r" (r3)
+#define __constraint_write_3						\
+	"+r" (r0), "+r" (r1), "+r" (r2), "+r" (r3)
+#define __constraint_write_4	__constraint_write_3
+#define __constraint_write_5	__constraint_write_4
+#define __constraint_write_6	__constraint_write_5
+#define __constraint_write_7	__constraint_write_6
+
+#define __constraint_read_0
+#define __constraint_read_1
+#define __constraint_read_2
+#define __constraint_read_3
+#define __constraint_read_4	"r" (r4)
+#define __constraint_read_5	__constraint_read_4, "r" (r5)
+#define __constraint_read_6	__constraint_read_5, "r" (r6)
+#define __constraint_read_7	__constraint_read_6, "r" (r7)
+
+#define __declare_arg_0(a0, res)					\
+	struct arm_smccc_res   *___res = res;				\
+	register unsigned long r0 asm("r0") = (u32)a0;			\
+	register unsigned long r1 asm("r1");				\
+	register unsigned long r2 asm("r2");				\
+	register unsigned long r3 asm("r3")
+
+#define __declare_arg_1(a0, a1, res)					\
+	typeof(a1) __a1 = a1;						\
+	struct arm_smccc_res   *___res = res;				\
+	register unsigned long r0 asm("r0") = (u32)a0;			\
+	register unsigned long r1 asm("r1") = __a1;			\
+	register unsigned long r2 asm("r2");				\
+	register unsigned long r3 asm("r3")
+
+#define __declare_arg_2(a0, a1, a2, res)				\
+	typeof(a1) __a1 = a1;						\
+	typeof(a2) __a2 = a2;						\
+	struct arm_smccc_res   *___res = res;				\
+	register unsigned long r0 asm("r0") = (u32)a0;			\
+	register unsigned long r1 asm("r1") = __a1;			\
+	register unsigned long r2 asm("r2") = __a2;			\
+	register unsigned long r3 asm("r3")
+
+#define __declare_arg_3(a0, a1, a2, a3, res)				\
+	typeof(a1) __a1 = a1;						\
+	typeof(a2) __a2 = a2;						\
+	typeof(a3) __a3 = a3;						\
+	struct arm_smccc_res   *___res = res;				\
+	register unsigned long r0 asm("r0") = (u32)a0;			\
+	register unsigned long r1 asm("r1") = __a1;			\
+	register unsigned long r2 asm("r2") = __a2;			\
+	register unsigned long r3 asm("r3") = __a3
+
+#define __declare_arg_4(a0, a1, a2, a3, a4, res)			\
+	typeof(a4) __a4 = a4;						\
+	__declare_arg_3(a0, a1, a2, a3, res);				\
+	register unsigned long r4 asm("r4") = __a4
+
+#define __declare_arg_5(a0, a1, a2, a3, a4, a5, res)			\
+	typeof(a5) __a5 = a5;						\
+	__declare_arg_4(a0, a1, a2, a3, a4, res);			\
+	register unsigned long r5 asm("r5") = __a5
+
+#define __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res)		\
+	typeof(a6) __a6 = a6;						\
+	__declare_arg_5(a0, a1, a2, a3, a4, a5, res);			\
+	register unsigned long r6 asm("r6") = __a6
+
+#define __declare_arg_7(a0, a1, a2, a3, a4, a5, a6, a7, res)		\
+	typeof(a7) __a7 = a7;						\
+	__declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res);		\
+	register unsigned long r7 asm("r7") = __a7
+
+#define ___declare_args(count, ...) __declare_arg_ ## count(__VA_ARGS__)
+#define __declare_args(count, ...)  ___declare_args(count, __VA_ARGS__)
+
+#define ___constraints(count)						\
+	: __constraint_write_ ## count					\
+	: __constraint_read_ ## count					\
+	: "memory"
+#define __constraints(count)	___constraints(count)
+
+/*
+ * We have an output list that is not necessarily used, and GCC feels
+ * entitled to optimise the whole sequence away. "volatile" is what
+ * makes it stick.
+ */
+#define __arm_smccc_1_1(inst, ...)					\
+	do {								\
+		__declare_args(__count_args(__VA_ARGS__), __VA_ARGS__);	\
+		asm volatile(inst "\n"					\
+			     __constraints(__count_args(__VA_ARGS__)));	\
+		if (___res)						\
+			*___res = (typeof(*___res)){r0, r1, r2, r3};	\
+	} while (0)
+
+/*
+ * arm_smccc_1_1_smc() - make an SMCCC v1.1 compliant SMC call
+ *
+ * This is a variadic macro taking one to eight source arguments, and
+ * an optional return structure.
+ *
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This macro is used to make SMC calls following SMC Calling Convention v1.1.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the SMC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the SMC instruction if not NULL.
+ */
+#define arm_smccc_1_1_smc(...)	__arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__)
+
+/*
+ * arm_smccc_1_1_hvc() - make an SMCCC v1.1 compliant HVC call
+ *
+ * This is a variadic macro taking one to eight source arguments, and
+ * an optional return structure.
+ *
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This macro is used to make HVC calls following SMC Calling Convention v1.1.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the HVC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the HVC instruction if not NULL.
+ */
+#define arm_smccc_1_1_hvc(...)	__arm_smccc_1_1(SMCCC_HVC_INST, __VA_ARGS__)
+
+/* Return codes defined in ARM DEN 0070A */
+#define SMCCC_RET_SUCCESS			0
+#define SMCCC_RET_NOT_SUPPORTED			-1
+#define SMCCC_RET_NOT_REQUIRED			-2
+
+#endif /*__ASSEMBLY__*/
+#endif /*__LINUX_ARM_SMCCC_H*/
--- linux-4.4.0.orig/include/linux/ata.h
+++ linux-4.4.0/include/linux/ata.h
@@ -487,8 +487,8 @@
 };
 
 enum ata_ioctls {
-	ATA_IOC_GET_IO32	= 0x309,
-	ATA_IOC_SET_IO32	= 0x324,
+	ATA_IOC_GET_IO32	= 0x309, /* HDIO_GET_32BIT */
+	ATA_IOC_SET_IO32	= 0x324, /* HDIO_SET_32BIT */
 };
 
 /* core structures */
--- linux-4.4.0.orig/include/linux/atalk.h
+++ linux-4.4.0/include/linux/atalk.h
@@ -107,7 +107,7 @@
 #define AARP_RESOLVE_TIME	(10 * HZ)
 
 extern struct datalink_proto *ddp_dl, *aarp_dl;
-extern void aarp_proto_init(void);
+extern int aarp_proto_init(void);
 
 /* Inter module exports */
 
@@ -150,19 +150,29 @@
 extern int sysctl_aarp_resolve_time;
 
 #ifdef CONFIG_SYSCTL
-extern void atalk_register_sysctl(void);
+extern int atalk_register_sysctl(void);
 extern void atalk_unregister_sysctl(void);
 #else
-#define atalk_register_sysctl()		do { } while(0)
-#define atalk_unregister_sysctl()	do { } while(0)
+static inline int atalk_register_sysctl(void)
+{
+	return 0;
+}
+static inline void atalk_unregister_sysctl(void)
+{
+}
 #endif
 
 #ifdef CONFIG_PROC_FS
 extern int atalk_proc_init(void);
 extern void atalk_proc_exit(void);
 #else
-#define atalk_proc_init()	({ 0; })
-#define atalk_proc_exit()	do { } while(0)
+static inline int atalk_proc_init(void)
+{
+	return 0;
+}
+static inline void atalk_proc_exit(void)
+{
+}
 #endif /* CONFIG_PROC_FS */
 
 #endif /* __LINUX_ATALK_H__ */
--- linux-4.4.0.orig/include/linux/atomic.h
+++ linux-4.4.0/include/linux/atomic.h
@@ -34,20 +34,29 @@
  * The idea here is to build acquire/release variants by adding explicit
  * barriers on top of the relaxed variant. In the case where the relaxed
  * variant is already fully ordered, no additional barriers are needed.
+ *
+ * Besides, if an arch has a special barrier for acquire/release, it could
+ * implement its own __atomic_op_* and use the same framework for building
+ * variants
  */
+#ifndef __atomic_op_acquire
 #define __atomic_op_acquire(op, args...)				\
 ({									\
 	typeof(op##_relaxed(args)) __ret  = op##_relaxed(args);		\
 	smp_mb__after_atomic();						\
 	__ret;								\
 })
+#endif
 
+#ifndef __atomic_op_release
 #define __atomic_op_release(op, args...)				\
 ({									\
 	smp_mb__before_atomic();					\
 	op##_relaxed(args);						\
 })
+#endif
 
+#ifndef __atomic_op_fence
 #define __atomic_op_fence(op, args...)					\
 ({									\
 	typeof(op##_relaxed(args)) __ret;				\
@@ -56,6 +65,7 @@
 	smp_mb__after_atomic();						\
 	__ret;								\
 })
+#endif
 
 /* atomic_add_return_relaxed */
 #ifndef atomic_add_return_relaxed
--- linux-4.4.0.orig/include/linux/audit.h
+++ linux-4.4.0/include/linux/audit.h
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <uapi/linux/audit.h>
+#include <linux/tty.h>
 
 #define AUDIT_INO_UNSET ((unsigned long)-1)
 #define AUDIT_DEV_UNSET ((dev_t)-1)
@@ -212,8 +213,7 @@
 
 static inline void audit_seccomp(unsigned long syscall, long signr, int code)
 {
-	/* Force a record to be reported if a signal was delivered. */
-	if (signr || unlikely(!audit_dummy_context()))
+	if (unlikely(!audit_dummy_context()))
 		__audit_seccomp(syscall, signr, code);
 }
 
@@ -239,6 +239,23 @@
 	return tsk->sessionid;
 }
 
+static inline struct tty_struct *audit_get_tty(struct task_struct *tsk)
+{
+	struct tty_struct *tty = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tsk->sighand->siglock, flags);
+	if (tsk->signal)
+		tty = tty_kref_get(tsk->signal->tty);
+	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+	return tty;
+}
+
+static inline void audit_put_tty(struct tty_struct *tty)
+{
+	tty_kref_put(tty);
+}
+
 extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
 extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
 extern void __audit_bprm(struct linux_binprm *bprm);
@@ -281,6 +298,20 @@
 		return __audit_socketcall(nargs, args);
 	return 0;
 }
+
+static inline int audit_socketcall_compat(int nargs, u32 *args)
+{
+	unsigned long a[AUDITSC_ARGS];
+	int i;
+
+	if (audit_dummy_context())
+		return 0;
+
+	for (i = 0; i < nargs; i++)
+		a[i] = (unsigned long)args[i];
+	return __audit_socketcall(nargs, a);
+}
+
 static inline int audit_sockaddr(int len, void *addr)
 {
 	if (unlikely(!audit_dummy_context()))
@@ -396,6 +427,12 @@
 {
 	return -1;
 }
+static inline struct tty_struct *audit_get_tty(struct task_struct *tsk)
+{
+	return NULL;
+}
+static inline void audit_put_tty(struct tty_struct *tty)
+{ }
 static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
 { }
 static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid,
@@ -407,6 +444,12 @@
 {
 	return 0;
 }
+
+static inline int audit_socketcall_compat(int nargs, u32 *args)
+{
+	return 0;
+}
+
 static inline void audit_fd_pair(int fd1, int fd2)
 { }
 static inline int audit_sockaddr(int len, void *addr)
--- linux-4.4.0.orig/include/linux/backing-dev-defs.h
+++ linux-4.4.0/include/linux/backing-dev-defs.h
@@ -10,6 +10,7 @@
 #include <linux/flex_proportions.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/kref.h>
 
 struct page;
 struct device;
@@ -20,6 +21,7 @@
  */
 enum wb_state {
 	WB_registered,		/* bdi_register() was done */
+	WB_shutting_down,	/* wb_shutdown() in progress */
 	WB_writeback_running,	/* Writeback is in progress */
 	WB_has_dirty_io,	/* Dirty inodes on ->b_{dirty|io|more_io} */
 };
@@ -53,7 +55,9 @@
 	atomic_t refcnt;		/* nr of attached wb's and blkg */
 
 #ifdef CONFIG_CGROUP_WRITEBACK
-	struct backing_dev_info *bdi;	/* the associated bdi */
+	struct backing_dev_info *__bdi;	/* the associated bdi, set to NULL
+					 * on bdi unregistration. For memcg-wb
+					 * internal use only! */
 	int blkcg_id;			/* ID of the associated blkcg */
 	struct rb_node rb_node;		/* on bdi->cgwb_congestion_tree */
 #endif
@@ -142,6 +146,7 @@
 
 	char *name;
 
+	struct kref refcnt;	/* Reference counter for the structure */
 	unsigned int min_ratio;
 	unsigned int max_ratio, max_prop_frac;
 
@@ -156,13 +161,14 @@
 #ifdef CONFIG_CGROUP_WRITEBACK
 	struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */
 	struct rb_root cgwb_congested_tree; /* their congested states */
-	atomic_t usage_cnt; /* counts both cgwbs and cgwb_contested's */
+	struct rw_semaphore wb_switch_rwsem; /* no cgwb switch while syncing */
 #else
 	struct bdi_writeback_congested *wb_congested;
 #endif
 	wait_queue_head_t wb_waitq;
 
 	struct device *dev;
+	struct device *owner;
 
 	struct timer_list laptop_mode_wb_timer;
 
@@ -190,6 +196,11 @@
 	set_wb_congested(bdi->wb.congested, sync);
 }
 
+struct wb_lock_cookie {
+	bool locked;
+	unsigned long flags;
+};
+
 #ifdef CONFIG_CGROUP_WRITEBACK
 
 /**
@@ -219,6 +230,14 @@
  */
 static inline void wb_put(struct bdi_writeback *wb)
 {
+	if (WARN_ON_ONCE(!wb->bdi)) {
+		/*
+		 * A driver bug might cause a file to be removed before bdi was
+		 * initialized.
+		 */
+		return;
+	}
+
 	if (wb != &wb->bdi->wb)
 		percpu_ref_put(&wb->refcnt);
 }
--- linux-4.4.0.orig/include/linux/backing-dev.h
+++ linux-4.4.0/include/linux/backing-dev.h
@@ -12,22 +12,32 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/blkdev.h>
+#include <linux/device.h>
 #include <linux/writeback.h>
 #include <linux/blk-cgroup.h>
 #include <linux/backing-dev-defs.h>
 #include <linux/slab.h>
 
 int __must_check bdi_init(struct backing_dev_info *bdi);
-void bdi_exit(struct backing_dev_info *bdi);
+
+static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi)
+{
+	kref_get(&bdi->refcnt);
+	return bdi;
+}
+
+void bdi_put(struct backing_dev_info *bdi);
 
 __printf(3, 4)
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
 		const char *fmt, ...);
 int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
+int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner);
 void bdi_unregister(struct backing_dev_info *bdi);
 
 int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
 void bdi_destroy(struct backing_dev_info *bdi);
+struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id);
 
 void wb_start_writeback(struct bdi_writeback *wb, long nr_pages,
 			bool range_cyclic, enum wb_reason reason);
@@ -182,7 +192,7 @@
 	sb = inode->i_sb;
 #ifdef CONFIG_BLOCK
 	if (sb_is_blkdev_sb(sb))
-		return blk_get_backing_dev_info(I_BDEV(inode));
+		return I_BDEV(inode)->bd_bdi;
 #endif
 	return sb->s_bdi;
 }
@@ -365,7 +375,7 @@
 /**
  * unlocked_inode_to_wb_begin - begin unlocked inode wb access transaction
  * @inode: target inode
- * @lockedp: temp bool output param, to be passed to the end function
+ * @cookie: output param, to be passed to the end function
  *
  * The caller wants to access the wb associated with @inode but isn't
  * holding inode->i_lock, mapping->tree_lock or wb->list_lock.  This
@@ -373,12 +383,12 @@
  * association doesn't change until the transaction is finished with
  * unlocked_inode_to_wb_end().
  *
- * The caller must call unlocked_inode_to_wb_end() with *@lockdep
- * afterwards and can't sleep during transaction.  IRQ may or may not be
- * disabled on return.
+ * The caller must call unlocked_inode_to_wb_end() with *@cookie afterwards and
+ * can't sleep during the transaction.  IRQs may or may not be disabled on
+ * return.
  */
 static inline struct bdi_writeback *
-unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp)
+unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
 {
 	rcu_read_lock();
 
@@ -386,10 +396,10 @@
 	 * Paired with store_release in inode_switch_wb_work_fn() and
 	 * ensures that we see the new wb if we see cleared I_WB_SWITCH.
 	 */
-	*lockedp = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
+	cookie->locked = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
 
-	if (unlikely(*lockedp))
-		spin_lock_irq(&inode->i_mapping->tree_lock);
+	if (unlikely(cookie->locked))
+		spin_lock_irqsave(&inode->i_mapping->tree_lock, cookie->flags);
 
 	/*
 	 * Protected by either !I_WB_SWITCH + rcu_read_lock() or tree_lock.
@@ -401,12 +411,14 @@
 /**
  * unlocked_inode_to_wb_end - end inode wb access transaction
  * @inode: target inode
- * @locked: *@lockedp from unlocked_inode_to_wb_begin()
+ * @cookie: @cookie from unlocked_inode_to_wb_begin()
  */
-static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked)
+static inline void unlocked_inode_to_wb_end(struct inode *inode,
+					    struct wb_lock_cookie *cookie)
 {
-	if (unlikely(locked))
-		spin_unlock_irq(&inode->i_mapping->tree_lock);
+	if (unlikely(cookie->locked))
+		spin_unlock_irqrestore(&inode->i_mapping->tree_lock,
+				       cookie->flags);
 
 	rcu_read_unlock();
 }
@@ -453,12 +465,13 @@
 }
 
 static inline struct bdi_writeback *
-unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp)
+unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
 {
 	return inode_to_wb(inode);
 }
 
-static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked)
+static inline void unlocked_inode_to_wb_end(struct inode *inode,
+					    struct wb_lock_cookie *cookie)
 {
 }
 
@@ -514,4 +527,13 @@
 				  (1 << WB_async_congested));
 }
 
+extern const char *bdi_unknown_name;
+
+static inline const char *bdi_dev_name(struct backing_dev_info *bdi)
+{
+	if (!bdi || !bdi->dev)
+		return bdi_unknown_name;
+	return dev_name(bdi->dev);
+}
+
 #endif	/* _LINUX_BACKING_DEV_H */
--- linux-4.4.0.orig/include/linux/bcma/bcma.h
+++ linux-4.4.0/include/linux/bcma/bcma.h
@@ -156,6 +156,7 @@
 #define BCMA_CORE_DEFAULT		0xFFF
 
 #define BCMA_MAX_NR_CORES		16
+#define BCMA_CORE_SIZE			0x1000
 
 /* Chip IDs of PCIe devices */
 #define BCMA_CHIP_ID_BCM4313	0x4313
--- linux-4.4.0.orig/include/linux/bio.h
+++ linux-4.4.0/include/linux/bio.h
@@ -290,7 +290,7 @@
 {
 	if (count != 1) {
 		bio->bi_flags |= (1 << BIO_REFFED);
-		smp_mb__before_atomic();
+		smp_mb();
 	}
 	atomic_set(&bio->__bi_cnt, count);
 }
@@ -310,6 +310,38 @@
 	bio->bi_flags &= ~(1U << bit);
 }
 
+static inline void bio_get_first_bvec(struct bio *bio, struct bio_vec *bv)
+{
+	*bv = bio_iovec(bio);
+}
+
+static inline void bio_get_last_bvec(struct bio *bio, struct bio_vec *bv)
+{
+	struct bvec_iter iter = bio->bi_iter;
+	int idx;
+
+	if (unlikely(!bio_multiple_segments(bio))) {
+		*bv = bio_iovec(bio);
+		return;
+	}
+
+	bio_advance_iter(bio, &iter, iter.bi_size);
+
+	if (!iter.bi_bvec_done)
+		idx = iter.bi_idx - 1;
+	else	/* in the middle of bvec */
+		idx = iter.bi_idx;
+
+	*bv = bio->bi_io_vec[idx];
+
+	/*
+	 * iter.bi_bvec_done records actual length of the last bvec
+	 * if this bio ends in the middle of one io vector
+	 */
+	if (iter.bi_bvec_done)
+		bv->bv_len = iter.bi_bvec_done;
+}
+
 enum bip_flags {
 	BIP_BLOCK_INTEGRITY	= 1 << 0, /* block layer owns integrity data */
 	BIP_MAPPED_INTEGRITY	= 1 << 1, /* ref tag has been remapped */
@@ -318,16 +350,6 @@
 	BIP_IP_CHECKSUM		= 1 << 4, /* IP checksum */
 };
 
-#if defined(CONFIG_BLK_DEV_INTEGRITY)
-
-static inline struct bio_integrity_payload *bio_integrity(struct bio *bio)
-{
-	if (bio->bi_rw & REQ_INTEGRITY)
-		return bio->bi_integrity;
-
-	return NULL;
-}
-
 /*
  * bio integrity payload
  */
@@ -349,6 +371,16 @@
 	struct bio_vec		bip_inline_vecs[0];/* embedded bvec array */
 };
 
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+
+static inline struct bio_integrity_payload *bio_integrity(struct bio *bio)
+{
+	if (bio->bi_rw & REQ_INTEGRITY)
+		return bio->bi_integrity;
+
+	return NULL;
+}
+
 static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
 {
 	struct bio_integrity_payload *bip = bio_integrity(bio);
@@ -495,11 +527,14 @@
 int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css);
 int bio_associate_current(struct bio *bio);
 void bio_disassociate_task(struct bio *bio);
+void bio_clone_blkcg_association(struct bio *dst, struct bio *src);
 #else	/* CONFIG_BLK_CGROUP */
 static inline int bio_associate_blkcg(struct bio *bio,
 			struct cgroup_subsys_state *blkcg_css) { return 0; }
 static inline int bio_associate_current(struct bio *bio) { return -ENOENT; }
 static inline void bio_disassociate_task(struct bio *bio) { }
+static inline void bio_clone_blkcg_association(struct bio *dst,
+			struct bio *src) { }
 #endif	/* CONFIG_BLK_CGROUP */
 
 #ifdef CONFIG_HIGHMEM
@@ -795,6 +830,18 @@
 	return false;
 }
 
+static inline void *bio_integrity_alloc(struct bio * bio, gfp_t gfp,
+								unsigned int nr)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int bio_integrity_add_page(struct bio *bio, struct page *page,
+					unsigned int len, unsigned int offset)
+{
+	return 0;
+}
+
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
 #endif /* CONFIG_BLOCK */
--- linux-4.4.0.orig/include/linux/bitmap.h
+++ linux-4.4.0/include/linux/bitmap.h
@@ -59,6 +59,8 @@
  * bitmap_find_free_region(bitmap, bits, order)	Find and allocate bit region
  * bitmap_release_region(bitmap, pos, order)	Free specified bit region
  * bitmap_allocate_region(bitmap, pos, order)	Allocate specified bit region
+ * bitmap_from_u32array(dst, nbits, buf, nwords) *dst = *buf (nwords 32b words)
+ * bitmap_to_u32array(buf, nwords, src, nbits)	*buf = *dst (nwords 32b words)
  */
 
 /*
@@ -84,6 +86,14 @@
  */
 
 /*
+ * Allocation and deallocation of bitmap.
+ * Provided in lib/bitmap.c to avoid circular dependency.
+ */
+extern unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags);
+extern unsigned long *bitmap_zalloc(unsigned int nbits, gfp_t flags);
+extern void bitmap_free(const unsigned long *bitmap);
+
+/*
  * lib/bitmap.c provides these functions:
  */
 
@@ -163,6 +173,14 @@
 extern int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order);
 extern void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order);
 extern int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order);
+extern unsigned int bitmap_from_u32array(unsigned long *bitmap,
+					 unsigned int nbits,
+					 const u32 *buf,
+					 unsigned int nwords);
+extern unsigned int bitmap_to_u32array(u32 *buf,
+				       unsigned int nwords,
+				       const unsigned long *bitmap,
+				       unsigned int nbits);
 #ifdef __BIG_ENDIAN
 extern void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits);
 #else
@@ -175,8 +193,13 @@
 #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
 #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))
 
+/*
+ * The static inlines below do not handle constant nbits==0 correctly,
+ * so make such users (should any ever turn up) call the out-of-line
+ * versions.
+ */
 #define small_const_nbits(nbits) \
-	(__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
+	(__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG && (nbits) > 0)
 
 static inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
 {
@@ -303,7 +326,7 @@
 }
 
 static inline void bitmap_shift_right(unsigned long *dst, const unsigned long *src,
-				unsigned int shift, int nbits)
+				unsigned int shift, unsigned int nbits)
 {
 	if (small_const_nbits(nbits))
 		*dst = (*src & BITMAP_LAST_WORD_MASK(nbits)) >> shift;
--- linux-4.4.0.orig/include/linux/bitops.h
+++ linux-4.4.0/include/linux/bitops.h
@@ -1,28 +1,10 @@
 #ifndef _LINUX_BITOPS_H
 #define _LINUX_BITOPS_H
 #include <asm/types.h>
+#include <linux/bits.h>
 
-#ifdef	__KERNEL__
-#define BIT(nr)			(1UL << (nr))
-#define BIT_ULL(nr)		(1ULL << (nr))
-#define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
-#define BIT_WORD(nr)		((nr) / BITS_PER_LONG)
-#define BIT_ULL_MASK(nr)	(1ULL << ((nr) % BITS_PER_LONG_LONG))
-#define BIT_ULL_WORD(nr)	((nr) / BITS_PER_LONG_LONG)
-#define BITS_PER_BYTE		8
-#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
-#endif
-
-/*
- * Create a contiguous bitmask starting at bit position @l and ending at
- * position @h. For example
- * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
- */
-#define GENMASK(h, l) \
-	(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
-
-#define GENMASK_ULL(h, l) \
-	(((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
+#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
+#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_TYPE(long))
 
 extern unsigned int __sw_hweight8(unsigned int w);
 extern unsigned int __sw_hweight16(unsigned int w);
@@ -77,7 +59,7 @@
 
 static __always_inline unsigned long hweight_long(unsigned long w)
 {
-	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
+	return sizeof(w) == 4 ? hweight32(w) : hweight64((__u64)w);
 }
 
 /**
@@ -87,7 +69,7 @@
  */
 static inline __u64 rol64(__u64 word, unsigned int shift)
 {
-	return (word << shift) | (word >> (64 - shift));
+	return (word << (shift & 63)) | (word >> ((-shift) & 63));
 }
 
 /**
@@ -97,7 +79,7 @@
  */
 static inline __u64 ror64(__u64 word, unsigned int shift)
 {
-	return (word >> shift) | (word << (64 - shift));
+	return (word >> (shift & 63)) | (word << ((-shift) & 63));
 }
 
 /**
@@ -107,7 +89,7 @@
  */
 static inline __u32 rol32(__u32 word, unsigned int shift)
 {
-	return (word << shift) | (word >> ((-shift) & 31));
+	return (word << (shift & 31)) | (word >> ((-shift) & 31));
 }
 
 /**
@@ -117,7 +99,7 @@
  */
 static inline __u32 ror32(__u32 word, unsigned int shift)
 {
-	return (word >> shift) | (word << (32 - shift));
+	return (word >> (shift & 31)) | (word << ((-shift) & 31));
 }
 
 /**
@@ -127,7 +109,7 @@
  */
 static inline __u16 rol16(__u16 word, unsigned int shift)
 {
-	return (word << shift) | (word >> (16 - shift));
+	return (word << (shift & 15)) | (word >> ((-shift) & 15));
 }
 
 /**
@@ -137,7 +119,7 @@
  */
 static inline __u16 ror16(__u16 word, unsigned int shift)
 {
-	return (word >> shift) | (word << (16 - shift));
+	return (word >> (shift & 15)) | (word << ((-shift) & 15));
 }
 
 /**
@@ -147,7 +129,7 @@
  */
 static inline __u8 rol8(__u8 word, unsigned int shift)
 {
-	return (word << shift) | (word >> (8 - shift));
+	return (word << (shift & 7)) | (word >> ((-shift) & 7));
 }
 
 /**
@@ -157,7 +139,7 @@
  */
 static inline __u8 ror8(__u8 word, unsigned int shift)
 {
-	return (word >> shift) | (word << (8 - shift));
+	return (word >> (shift & 7)) | (word << ((-shift) & 7));
 }
 
 /**
--- linux-4.4.0.orig/include/linux/bitrev.h
+++ linux-4.4.0/include/linux/bitrev.h
@@ -31,32 +31,32 @@
 
 #define __constant_bitrev32(x)	\
 ({					\
-	u32 __x = x;			\
-	__x = (__x >> 16) | (__x << 16);	\
-	__x = ((__x & (u32)0xFF00FF00UL) >> 8) | ((__x & (u32)0x00FF00FFUL) << 8);	\
-	__x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4);	\
-	__x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2);	\
-	__x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1);	\
-	__x;								\
+	u32 ___x = x;			\
+	___x = (___x >> 16) | (___x << 16);	\
+	___x = ((___x & (u32)0xFF00FF00UL) >> 8) | ((___x & (u32)0x00FF00FFUL) << 8);	\
+	___x = ((___x & (u32)0xF0F0F0F0UL) >> 4) | ((___x & (u32)0x0F0F0F0FUL) << 4);	\
+	___x = ((___x & (u32)0xCCCCCCCCUL) >> 2) | ((___x & (u32)0x33333333UL) << 2);	\
+	___x = ((___x & (u32)0xAAAAAAAAUL) >> 1) | ((___x & (u32)0x55555555UL) << 1);	\
+	___x;								\
 })
 
 #define __constant_bitrev16(x)	\
 ({					\
-	u16 __x = x;			\
-	__x = (__x >> 8) | (__x << 8);	\
-	__x = ((__x & (u16)0xF0F0U) >> 4) | ((__x & (u16)0x0F0FU) << 4);	\
-	__x = ((__x & (u16)0xCCCCU) >> 2) | ((__x & (u16)0x3333U) << 2);	\
-	__x = ((__x & (u16)0xAAAAU) >> 1) | ((__x & (u16)0x5555U) << 1);	\
-	__x;								\
+	u16 ___x = x;			\
+	___x = (___x >> 8) | (___x << 8);	\
+	___x = ((___x & (u16)0xF0F0U) >> 4) | ((___x & (u16)0x0F0FU) << 4);	\
+	___x = ((___x & (u16)0xCCCCU) >> 2) | ((___x & (u16)0x3333U) << 2);	\
+	___x = ((___x & (u16)0xAAAAU) >> 1) | ((___x & (u16)0x5555U) << 1);	\
+	___x;								\
 })
 
 #define __constant_bitrev8(x)	\
 ({					\
-	u8 __x = x;			\
-	__x = (__x >> 4) | (__x << 4);	\
-	__x = ((__x & (u8)0xCCU) >> 2) | ((__x & (u8)0x33U) << 2);	\
-	__x = ((__x & (u8)0xAAU) >> 1) | ((__x & (u8)0x55U) << 1);	\
-	__x;								\
+	u8 ___x = x;			\
+	___x = (___x >> 4) | (___x << 4);	\
+	___x = ((___x & (u8)0xCCU) >> 2) | ((___x & (u8)0x33U) << 2);	\
+	___x = ((___x & (u8)0xAAU) >> 1) | ((___x & (u8)0x55U) << 1);	\
+	___x;								\
 })
 
 #define bitrev32(x) \
--- linux-4.4.0.orig/include/linux/bits.h
+++ linux-4.4.0/include/linux/bits.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_BITS_H
+#define __LINUX_BITS_H
+#include <asm/bitsperlong.h>
+
+#define BIT(nr)			(1UL << (nr))
+#define BIT_ULL(nr)		(1ULL << (nr))
+#define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr)		((nr) / BITS_PER_LONG)
+#define BIT_ULL_MASK(nr)	(1ULL << ((nr) % BITS_PER_LONG_LONG))
+#define BIT_ULL_WORD(nr)	((nr) / BITS_PER_LONG_LONG)
+#define BITS_PER_BYTE		8
+
+/*
+ * Create a contiguous bitmask starting at bit position @l and ending at
+ * position @h. For example
+ * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
+ */
+#define GENMASK(h, l) \
+	(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+
+#define GENMASK_ULL(h, l) \
+	(((~0ULL) - (1ULL << (l)) + 1) & \
+	 (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
+
+#endif	/* __LINUX_BITS_H */
--- linux-4.4.0.orig/include/linux/blk-mq.h
+++ linux-4.4.0/include/linux/blk-mq.h
@@ -188,8 +188,16 @@
 void blk_mq_free_request(struct request *rq);
 void blk_mq_free_hctx_request(struct blk_mq_hw_ctx *, struct request *rq);
 bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
+
+enum {
+	BLK_MQ_REQ_NOWAIT	= (1 << 0), /* return when out of requests */
+	BLK_MQ_REQ_RESERVED	= (1 << 1), /* allocate from reserved pool */
+};
+
 struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
-		gfp_t gfp, bool reserved);
+		unsigned int flags);
+struct request *blk_mq_alloc_request_hctx(struct request_queue *q, int op,
+		unsigned int flags, unsigned int hctx_idx);
 struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag);
 struct cpumask *blk_mq_tags_cpumask(struct blk_mq_tags *tags);
 
@@ -255,22 +263,8 @@
 	for ((i) = 0; (i) < (q)->nr_hw_queues &&			\
 	     ({ hctx = (q)->queue_hw_ctx[i]; 1; }); (i)++)
 
-#define queue_for_each_ctx(q, ctx, i)					\
-	for ((i) = 0; (i) < (q)->nr_queues &&				\
-	     ({ ctx = per_cpu_ptr((q)->queue_ctx, (i)); 1; }); (i)++)
-
 #define hctx_for_each_ctx(hctx, ctx, i)					\
 	for ((i) = 0; (i) < (hctx)->nr_ctx &&				\
 	     ({ ctx = (hctx)->ctxs[(i)]; 1; }); (i)++)
 
-#define blk_ctx_sum(q, sum)						\
-({									\
-	struct blk_mq_ctx *__x;						\
-	unsigned int __ret = 0, __i;					\
-									\
-	queue_for_each_ctx((q), __x, __i)				\
-		__ret += sum;						\
-	__ret;								\
-})
-
 #endif
--- linux-4.4.0.orig/include/linux/blkdev.h
+++ linux-4.4.0/include/linux/blkdev.h
@@ -199,6 +199,11 @@
 	struct request *next_rq;
 };
 
+static inline bool blk_rq_is_passthrough(struct request *rq)
+{
+	return rq->cmd_type != REQ_TYPE_FS;
+}
+
 static inline unsigned short req_get_ioprio(struct request *req)
 {
 	return req->ioprio;
@@ -259,6 +264,7 @@
 	unsigned int		max_sectors;
 	unsigned int		max_segment_size;
 	unsigned int		physical_block_size;
+	unsigned int		logical_block_size;
 	unsigned int		alignment_offset;
 	unsigned int		io_min;
 	unsigned int		io_opt;
@@ -268,7 +274,6 @@
 	unsigned int		discard_granularity;
 	unsigned int		discard_alignment;
 
-	unsigned short		logical_block_size;
 	unsigned short		max_segments;
 	unsigned short		max_integrity_segments;
 
@@ -329,7 +334,7 @@
 	 */
 	struct delayed_work	delay_work;
 
-	struct backing_dev_info	backing_dev_info;
+	struct backing_dev_info	*backing_dev_info;
 
 	/*
 	 * The queue owner gets to use this for whatever they like.
@@ -408,6 +413,7 @@
 
 	unsigned int		rq_timeout;
 	struct timer_list	timeout;
+	struct work_struct	timeout_work;
 	struct list_head	timeout_list;
 
 	struct list_head	icq_list;
@@ -426,7 +432,8 @@
 	unsigned int		sg_reserved_size;
 	int			node;
 #ifdef CONFIG_BLK_DEV_IO_TRACE
-	struct blk_trace	*blk_trace;
+	struct blk_trace __rcu	*blk_trace;
+	struct mutex		blk_trace_mutex;
 #endif
 	/*
 	 * for flush operations
@@ -582,9 +589,10 @@
 	((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
 			     REQ_FAILFAST_DRIVER))
 
-#define blk_account_rq(rq) \
-	(((rq)->cmd_flags & REQ_STARTED) && \
-	 ((rq)->cmd_type == REQ_TYPE_FS))
+static inline bool blk_account_rq(struct request *rq)
+{
+	return (rq->cmd_flags & REQ_STARTED) && !blk_rq_is_passthrough(rq);
+}
 
 #define blk_rq_cpu_valid(rq)	((rq)->cpu != -1)
 #define blk_bidi_rq(rq)		((rq)->next_rq != NULL)
@@ -645,7 +653,7 @@
 
 static inline bool rq_mergeable(struct request *rq)
 {
-	if (rq->cmd_type != REQ_TYPE_FS)
+	if (blk_rq_is_passthrough(rq))
 		return false;
 
 	if (rq->cmd_flags & REQ_NOMERGE_FLAGS)
@@ -794,7 +802,7 @@
 extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
 			 struct scsi_ioctl_command __user *);
 
-extern int blk_queue_enter(struct request_queue *q, gfp_t gfp);
+extern int blk_queue_enter(struct request_queue *q, bool nowait);
 extern void blk_queue_exit(struct request_queue *q);
 extern void blk_start_queue(struct request_queue *q);
 extern void blk_start_queue_async(struct request_queue *q);
@@ -826,6 +834,19 @@
 }
 
 /*
+ * The basic unit of block I/O is a sector. It is used in a number of contexts
+ * in Linux (blk, bio, genhd). The size of one sector is 512 = 2**9
+ * bytes. Variables of type sector_t represent an offset or size that is a
+ * multiple of 512 bytes. Hence these two constants.
+ */
+#ifndef SECTOR_SHIFT
+#define SECTOR_SHIFT 9
+#endif
+#ifndef SECTOR_SIZE
+#define SECTOR_SIZE (1 << SECTOR_SHIFT)
+#endif
+
+/*
  * blk_rq_pos()			: the current sector
  * blk_rq_bytes()		: bytes left in the entire request
  * blk_rq_cur_bytes()		: bytes left in the current segment
@@ -852,19 +873,20 @@
 
 static inline unsigned int blk_rq_sectors(const struct request *rq)
 {
-	return blk_rq_bytes(rq) >> 9;
+	return blk_rq_bytes(rq) >> SECTOR_SHIFT;
 }
 
 static inline unsigned int blk_rq_cur_sectors(const struct request *rq)
 {
-	return blk_rq_cur_bytes(rq) >> 9;
+	return blk_rq_cur_bytes(rq) >> SECTOR_SHIFT;
 }
 
 static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
 						     unsigned int cmd_flags)
 {
 	if (unlikely(cmd_flags & REQ_DISCARD))
-		return min(q->limits.max_discard_sectors, UINT_MAX >> 9);
+		return min(q->limits.max_discard_sectors,
+			   UINT_MAX >> SECTOR_SHIFT);
 
 	if (unlikely(cmd_flags & REQ_WRITE_SAME))
 		return q->limits.max_write_same_sectors;
@@ -882,15 +904,15 @@
 	if (!q->limits.chunk_sectors)
 		return q->limits.max_sectors;
 
-	return q->limits.chunk_sectors -
-			(offset & (q->limits.chunk_sectors - 1));
+	return min(q->limits.max_sectors, (unsigned int)(q->limits.chunk_sectors -
+			(offset & (q->limits.chunk_sectors - 1))));
 }
 
 static inline unsigned int blk_rq_get_max_sectors(struct request *rq)
 {
 	struct request_queue *q = rq->q;
 
-	if (unlikely(rq->cmd_type == REQ_TYPE_BLOCK_PC))
+	if (blk_rq_is_passthrough(rq))
 		return q->limits.max_hw_sectors;
 
 	if (!q->limits.chunk_sectors || (rq->cmd_flags & REQ_DISCARD))
@@ -969,7 +991,7 @@
 		unsigned int max_discard_sectors);
 extern void blk_queue_max_write_same_sectors(struct request_queue *q,
 		unsigned int max_write_same_sectors);
-extern void blk_queue_logical_block_size(struct request_queue *, unsigned short);
+extern void blk_queue_logical_block_size(struct request_queue *, unsigned int);
 extern void blk_queue_physical_block_size(struct request_queue *, unsigned int);
 extern void blk_queue_alignment_offset(struct request_queue *q,
 				       unsigned int alignment);
@@ -1003,7 +1025,6 @@
 extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern void blk_queue_flush(struct request_queue *q, unsigned int flush);
 extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable);
-extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
@@ -1127,16 +1148,21 @@
 static inline int sb_issue_discard(struct super_block *sb, sector_t block,
 		sector_t nr_blocks, gfp_t gfp_mask, unsigned long flags)
 {
-	return blkdev_issue_discard(sb->s_bdev, block << (sb->s_blocksize_bits - 9),
-				    nr_blocks << (sb->s_blocksize_bits - 9),
+	return blkdev_issue_discard(sb->s_bdev,
+				    block << (sb->s_blocksize_bits -
+					      SECTOR_SHIFT),
+				    nr_blocks << (sb->s_blocksize_bits -
+						  SECTOR_SHIFT),
 				    gfp_mask, flags);
 }
 static inline int sb_issue_zeroout(struct super_block *sb, sector_t block,
 		sector_t nr_blocks, gfp_t gfp_mask)
 {
 	return blkdev_issue_zeroout(sb->s_bdev,
-				    block << (sb->s_blocksize_bits - 9),
-				    nr_blocks << (sb->s_blocksize_bits - 9),
+				    block << (sb->s_blocksize_bits -
+					      SECTOR_SHIFT),
+				    nr_blocks << (sb->s_blocksize_bits -
+						  SECTOR_SHIFT),
 				    gfp_mask, true);
 }
 
@@ -1187,7 +1213,7 @@
 	return q->limits.max_segment_size;
 }
 
-static inline unsigned short queue_logical_block_size(struct request_queue *q)
+static inline unsigned queue_logical_block_size(struct request_queue *q)
 {
 	int retval = 512;
 
@@ -1197,7 +1223,7 @@
 	return retval;
 }
 
-static inline unsigned short bdev_logical_block_size(struct block_device *bdev)
+static inline unsigned int bdev_logical_block_size(struct block_device *bdev)
 {
 	return queue_logical_block_size(bdev_get_queue(bdev));
 }
@@ -1243,7 +1269,8 @@
 static inline int queue_limit_alignment_offset(struct queue_limits *lim, sector_t sector)
 {
 	unsigned int granularity = max(lim->physical_block_size, lim->io_min);
-	unsigned int alignment = sector_div(sector, granularity >> 9) << 9;
+	unsigned int alignment = sector_div(sector, granularity >> SECTOR_SHIFT)
+		<< SECTOR_SHIFT;
 
 	return (granularity + lim->alignment_offset - alignment) % granularity;
 }
@@ -1277,8 +1304,8 @@
 		return 0;
 
 	/* Why are these in bytes, not sectors? */
-	alignment = lim->discard_alignment >> 9;
-	granularity = lim->discard_granularity >> 9;
+	alignment = lim->discard_alignment >> SECTOR_SHIFT;
+	granularity = lim->discard_granularity >> SECTOR_SHIFT;
 	if (!granularity)
 		return 0;
 
@@ -1289,7 +1316,7 @@
 	offset = (granularity + alignment - offset) % granularity;
 
 	/* Turn it back into bytes, gaah */
-	return offset << 9;
+	return offset << SECTOR_SHIFT;
 }
 
 static inline int bdev_discard_alignment(struct block_device *bdev)
@@ -1367,6 +1394,13 @@
 	page_cache_release(p.v);
 }
 
+static inline bool __bvec_gap_to_prev(struct request_queue *q,
+				struct bio_vec *bprv, unsigned int offset)
+{
+	return offset ||
+		((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q));
+}
+
 /*
  * Check if adding a bio_vec after bprv with offset would create a gap in
  * the SG list. Most drivers don't care about this, but some do.
@@ -1376,28 +1410,76 @@
 {
 	if (!queue_virt_boundary(q))
 		return false;
-	return offset ||
-		((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q));
+	return __bvec_gap_to_prev(q, bprv, offset);
 }
 
-static inline bool bio_will_gap(struct request_queue *q, struct bio *prev,
-			 struct bio *next)
+/*
+ * Check if the two bvecs from two bios can be merged to one segment.
+ * If yes, no need to check gap between the two bios since the 1st bio
+ * and the 1st bvec in the 2nd bio can be handled in one segment.
+ */
+static inline bool bios_segs_mergeable(struct request_queue *q,
+		struct bio *prev, struct bio_vec *prev_last_bv,
+		struct bio_vec *next_first_bv)
 {
-	if (!bio_has_data(prev))
+	if (!BIOVEC_PHYS_MERGEABLE(prev_last_bv, next_first_bv))
+		return false;
+	if (!BIOVEC_SEG_BOUNDARY(q, prev_last_bv, next_first_bv))
 		return false;
+	if (prev->bi_seg_back_size + next_first_bv->bv_len >
+			queue_max_segment_size(q))
+		return false;
+	return true;
+}
+
+static inline bool bio_will_gap(struct request_queue *q,
+				struct request *prev_rq,
+				struct bio *prev,
+				struct bio *next)
+{
+	if (bio_has_data(prev) && queue_virt_boundary(q)) {
+		struct bio_vec pb, nb;
+
+		/*
+		 * don't merge if the 1st bio starts with non-zero
+		 * offset, otherwise it is quite difficult to respect
+		 * sg gap limit. We work hard to merge a huge number of small
+		 * single bios in case of mkfs.
+		 */
+		if (prev_rq)
+			bio_get_first_bvec(prev_rq->bio, &pb);
+		else
+			bio_get_first_bvec(prev, &pb);
+		if (pb.bv_offset)
+			return true;
+
+		/*
+		 * We don't need to worry about the situation that the
+		 * merged segment ends in unaligned virt boundary:
+		 *
+		 * - if 'pb' ends aligned, the merged segment ends aligned
+		 * - if 'pb' ends unaligned, the next bio must include
+		 *   one single bvec of 'nb', otherwise the 'nb' can't
+		 *   merge with 'pb'
+		 */
+		bio_get_last_bvec(prev, &pb);
+		bio_get_first_bvec(next, &nb);
 
-	return bvec_gap_to_prev(q, &prev->bi_io_vec[prev->bi_vcnt - 1],
-				next->bi_io_vec[0].bv_offset);
+		if (!bios_segs_mergeable(q, prev, &pb, &nb))
+			return __bvec_gap_to_prev(q, &pb, nb.bv_offset);
+	}
+
+	return false;
 }
 
 static inline bool req_gap_back_merge(struct request *req, struct bio *bio)
 {
-	return bio_will_gap(req->q, req->biotail, bio);
+	return bio_will_gap(req->q, req, req->biotail, bio);
 }
 
 static inline bool req_gap_front_merge(struct request *req, struct bio *bio)
 {
-	return bio_will_gap(req->q, bio, req->bio);
+	return bio_will_gap(req->q, NULL, bio, req->bio);
 }
 
 struct work_struct;
--- linux-4.4.0.orig/include/linux/blktrace_api.h
+++ linux-4.4.0/include/linux/blktrace_api.h
@@ -51,9 +51,13 @@
  **/
 #define blk_add_trace_msg(q, fmt, ...)					\
 	do {								\
-		struct blk_trace *bt = (q)->blk_trace;			\
+		struct blk_trace *bt;					\
+									\
+		rcu_read_lock();					\
+		bt = rcu_dereference((q)->blk_trace);			\
 		if (unlikely(bt))					\
 			__trace_note_message(bt, fmt, ##__VA_ARGS__);	\
+		rcu_read_unlock();					\
 	} while (0)
 #define BLK_TN_MAX_MSG		128
 
--- linux-4.4.0.orig/include/linux/bootmem.h
+++ linux-4.4.0/include/linux/bootmem.h
@@ -353,6 +353,7 @@
 #define HASH_EARLY	0x00000001	/* Allocating during early boot? */
 #define HASH_SMALL	0x00000002	/* sub-page allocation allowed, min
 					 * shift passed via *_hash_shift */
+#define HASH_ZERO	0x00000004	/* Zero allocated hash table */
 
 /* Only NUMA needs hash distribution. 64bit NUMA architectures have
  * sufficient vmalloc space.
--- linux-4.4.0.orig/include/linux/bpf.h
+++ linux-4.4.0/include/linux/bpf.h
@@ -31,16 +31,25 @@
 };
 
 struct bpf_map {
-	atomic_t refcnt;
+	/* 1st cacheline with read-mostly members of which some
+	 * are also accessed in fast-path (e.g. ops, max_entries).
+	 */
+	const struct bpf_map_ops *ops ____cacheline_aligned;
 	enum bpf_map_type map_type;
 	u32 key_size;
 	u32 value_size;
 	u32 max_entries;
 	u32 pages;
-	struct user_struct *user;
-	const struct bpf_map_ops *ops;
-	struct work_struct work;
+	bool unpriv_array;
+	/* 7 bytes hole */
+
+	/* 2nd cacheline with misc members to avoid false sharing
+	 * particularly with refcounting.
+	 */
+	struct user_struct *user ____cacheline_aligned;
+	atomic_t refcnt;
 	atomic_t usercnt;
+	struct work_struct work;
 };
 
 struct bpf_map_type_list {
@@ -141,6 +150,7 @@
 struct bpf_array {
 	struct bpf_map map;
 	u32 elem_size;
+	u32 index_mask;
 	/* 'ownership' of prog_array is claimed by the first program that
 	 * is going to use this map or by the first program which FD is stored
 	 * in the map to make sure that all callers and callees have the same
@@ -165,12 +175,12 @@
 void bpf_register_map_type(struct bpf_map_type_list *tl);
 
 struct bpf_prog *bpf_prog_get(u32 ufd);
+struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog);
 void bpf_prog_put(struct bpf_prog *prog);
-void bpf_prog_put_rcu(struct bpf_prog *prog);
 
 struct bpf_map *bpf_map_get_with_uref(u32 ufd);
 struct bpf_map *__bpf_map_get(struct fd f);
-void bpf_map_inc(struct bpf_map *map, bool uref);
+struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref);
 void bpf_map_put_with_uref(struct bpf_map *map);
 void bpf_map_put(struct bpf_map *map);
 
--- linux-4.4.0.orig/include/linux/buffer_head.h
+++ linux-4.4.0/include/linux/buffer_head.h
@@ -234,12 +234,10 @@
 {
 	if (err == 0)
 		return VM_FAULT_LOCKED;
-	if (err == -EFAULT)
+	if (err == -EFAULT || err == -EAGAIN)
 		return VM_FAULT_NOPAGE;
 	if (err == -ENOMEM)
 		return VM_FAULT_OOM;
-	if (err == -EAGAIN)
-		return VM_FAULT_RETRY;
 	/* -ENOSPC, -EDQUOT, -EIO ... */
 	return VM_FAULT_SIGBUS;
 }
--- linux-4.4.0.orig/include/linux/bug.h
+++ linux-4.4.0/include/linux/bug.h
@@ -102,6 +102,11 @@
 
 #else	/* !CONFIG_GENERIC_BUG */
 
+static inline void *find_bug(unsigned long bugaddr)
+{
+	return NULL;
+}
+
 static inline enum bug_trap_type report_bug(unsigned long bug_addr,
 					    struct pt_regs *regs)
 {
--- linux-4.4.0.orig/include/linux/cache.h
+++ linux-4.4.0/include/linux/cache.h
@@ -12,10 +12,24 @@
 #define SMP_CACHE_BYTES L1_CACHE_BYTES
 #endif
 
+/*
+ * __read_mostly is used to keep rarely changing variables out of frequently
+ * updated cachelines. If an architecture doesn't support it, ignore the
+ * hint.
+ */
 #ifndef __read_mostly
 #define __read_mostly
 #endif
 
+/*
+ * __ro_after_init is used to mark things that are read-only after init (i.e.
+ * after mark_rodata_ro() has been called). These are effectively read-only,
+ * but may get written to during init, so can't live in .rodata (via "const").
+ */
+#ifndef __ro_after_init
+#define __ro_after_init __attribute__((__section__(".data..ro_after_init")))
+#endif
+
 #ifndef ____cacheline_aligned
 #define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
 #endif
--- linux-4.4.0.orig/include/linux/cacheinfo.h
+++ linux-4.4.0/include/linux/cacheinfo.h
@@ -71,6 +71,7 @@
 	struct cacheinfo *info_list;
 	unsigned int num_levels;
 	unsigned int num_leaves;
+	bool cpu_map_populated;
 };
 
 /*
--- linux-4.4.0.orig/include/linux/can/core.h
+++ linux-4.4.0/include/linux/can/core.h
@@ -45,10 +45,9 @@
 extern int  can_proto_register(const struct can_proto *cp);
 extern void can_proto_unregister(const struct can_proto *cp);
 
-extern int  can_rx_register(struct net_device *dev, canid_t can_id,
-			    canid_t mask,
-			    void (*func)(struct sk_buff *, void *),
-			    void *data, char *ident);
+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
+		    void (*func)(struct sk_buff *, void *),
+		    void *data, char *ident, struct sock *sk);
 
 extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
 			      canid_t mask,
--- linux-4.4.0.orig/include/linux/can/dev.h
+++ linux-4.4.0/include/linux/can/dev.h
@@ -17,6 +17,7 @@
 #include <linux/can/error.h>
 #include <linux/can/led.h>
 #include <linux/can/netlink.h>
+#include <linux/can/skb.h>
 #include <linux/netdevice.h>
 
 /*
@@ -32,6 +33,7 @@
  * CAN common private data
  */
 struct can_priv {
+	struct net_device *dev;
 	struct can_device_stats can_stats;
 
 	struct can_bittiming bittiming, data_bittiming;
@@ -40,11 +42,14 @@
 	struct can_clock clock;
 
 	enum can_state state;
-	u32 ctrlmode;
-	u32 ctrlmode_supported;
+
+	/* CAN controller features - see include/uapi/linux/can/netlink.h */
+	u32 ctrlmode;		/* current options setting */
+	u32 ctrlmode_supported;	/* options that can be modified by netlink */
+	u32 ctrlmode_static;	/* static enabled options for driver/hardware */
 
 	int restart_ms;
-	struct timer_list restart_timer;
+	struct delayed_work restart_work;
 
 	int (*do_set_bittiming)(struct net_device *dev);
 	int (*do_set_data_bittiming)(struct net_device *dev);
@@ -77,6 +82,36 @@
 #define get_can_dlc(i)		(min_t(__u8, (i), CAN_MAX_DLC))
 #define get_canfd_dlc(i)	(min_t(__u8, (i), CANFD_MAX_DLC))
 
+/* Check for outgoing skbs that have not been created by the CAN subsystem */
+static inline bool can_skb_headroom_valid(struct net_device *dev,
+					  struct sk_buff *skb)
+{
+	/* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
+	if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
+		return false;
+
+	/* af_packet does not apply CAN skb specific settings */
+	if (skb->ip_summed == CHECKSUM_NONE) {
+		/* init headroom */
+		can_skb_prv(skb)->ifindex = dev->ifindex;
+		can_skb_prv(skb)->skbcnt = 0;
+
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+		/* preform proper loopback on capable devices */
+		if (dev->flags & IFF_ECHO)
+			skb->pkt_type = PACKET_LOOPBACK;
+		else
+			skb->pkt_type = PACKET_HOST;
+
+		skb_reset_mac_header(skb);
+		skb_reset_network_header(skb);
+		skb_reset_transport_header(skb);
+	}
+
+	return true;
+}
+
 /* Drop a given socketbuffer if it does not contain a valid CAN frame. */
 static inline bool can_dropped_invalid_skb(struct net_device *dev,
 					  struct sk_buff *skb)
@@ -94,6 +129,9 @@
 	} else
 		goto inval_skb;
 
+	if (!can_skb_headroom_valid(dev, skb))
+		goto inval_skb;
+
 	return false;
 
 inval_skb:
@@ -108,6 +146,21 @@
 	return skb->len == CANFD_MTU;
 }
 
+/* helper to define static CAN controller features at device creation time */
+static inline void can_set_static_ctrlmode(struct net_device *dev,
+					   u32 static_mode)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	/* alloc_candev() succeeded => netdev_priv() is valid at this point */
+	priv->ctrlmode = static_mode;
+	priv->ctrlmode_static = static_mode;
+
+	/* override MTU which was set by default in can_setup()? */
+	if (static_mode & CAN_CTRLMODE_FD)
+		dev->mtu = CANFD_MTU;
+}
+
 /* get data length from can_dlc with sanitized can_dlc */
 u8 can_dlc2len(u8 can_dlc);
 
@@ -135,6 +188,7 @@
 
 void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
 		      unsigned int idx);
+struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr);
 unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx);
 void can_free_echo_skb(struct net_device *dev, unsigned int idx);
 
--- linux-4.4.0.orig/include/linux/can/skb.h
+++ linux-4.4.0/include/linux/can/skb.h
@@ -48,8 +48,12 @@
 
 static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk)
 {
-	if (sk) {
-		sock_hold(sk);
+	/* If the socket has already been closed by user space, the
+	 * refcount may already be 0 (and the socket will be freed
+	 * after the last TX skb has been freed). So only increase
+	 * socket refcount if the refcount is > 0.
+	 */
+	if (sk && atomic_inc_not_zero(&sk->sk_refcnt)) {
 		skb->destructor = sock_efree;
 		skb->sk = sk;
 	}
@@ -60,21 +64,17 @@
  */
 static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
 {
-	if (skb_shared(skb)) {
-		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+	struct sk_buff *nskb;
 
-		if (likely(nskb)) {
-			can_skb_set_owner(nskb, skb->sk);
-			consume_skb(skb);
-			return nskb;
-		} else {
-			kfree_skb(skb);
-			return NULL;
-		}
+	nskb = skb_clone(skb, GFP_ATOMIC);
+	if (unlikely(!nskb)) {
+		kfree_skb(skb);
+		return NULL;
 	}
 
-	/* we can assume to have an unshared skb with proper owner */
-	return skb;
+	can_skb_set_owner(nskb, skb->sk);
+	consume_skb(skb);
+	return nskb;
 }
 
 #endif /* !_CAN_SKB_H */
--- linux-4.4.0.orig/include/linux/capability.h
+++ linux-4.4.0/include/linux/capability.h
@@ -40,8 +40,6 @@
 struct dentry;
 struct user_namespace;
 
-struct user_namespace *current_user_ns(void);
-
 extern const kernel_cap_t __cap_empty_set;
 extern const kernel_cap_t __cap_init_eff_set;
 
@@ -214,6 +212,7 @@
 				      struct user_namespace *ns, int cap);
 extern bool capable(int cap);
 extern bool ns_capable(struct user_namespace *ns, int cap);
+extern bool ns_capable_noaudit(struct user_namespace *ns, int cap);
 #else
 static inline bool has_capability(struct task_struct *t, int cap)
 {
@@ -241,11 +240,19 @@
 {
 	return true;
 }
+static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap)
+{
+	return true;
+}
 #endif /* CONFIG_MULTIUSER */
+extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode);
 extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
 extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
+extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns);
 
 /* audit system wants to get cap info from files as well */
 extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
 
+extern int cap_convert_nscap(struct dentry *dentry, const void **ivalue, size_t size);
+
 #endif /* !_LINUX_CAPABILITY_H */
--- linux-4.4.0.orig/include/linux/cdev.h
+++ linux-4.4.0/include/linux/cdev.h
@@ -4,6 +4,7 @@
 #include <linux/kobject.h>
 #include <linux/kdev_t.h>
 #include <linux/list.h>
+#include <linux/device.h>
 
 struct file_operations;
 struct inode;
@@ -26,6 +27,10 @@
 
 int cdev_add(struct cdev *, dev_t, unsigned);
 
+void cdev_set_parent(struct cdev *p, struct kobject *kobj);
+int cdev_device_add(struct cdev *cdev, struct device *dev);
+void cdev_device_del(struct cdev *cdev, struct device *dev);
+
 void cdev_del(struct cdev *);
 
 void cd_forget(struct inode *);
--- linux-4.4.0.orig/include/linux/ceph/buffer.h
+++ linux-4.4.0/include/linux/ceph/buffer.h
@@ -29,7 +29,8 @@
 
 static inline void ceph_buffer_put(struct ceph_buffer *b)
 {
-	kref_put(&b->kref, ceph_buffer_release);
+	if (b)
+		kref_put(&b->kref, ceph_buffer_release);
 }
 
 extern int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end);
--- linux-4.4.0.orig/include/linux/ceph/libceph.h
+++ linux-4.4.0/include/linux/ceph/libceph.h
@@ -72,7 +72,13 @@
 
 #define CEPH_MSG_MAX_FRONT_LEN	(16*1024*1024)
 #define CEPH_MSG_MAX_MIDDLE_LEN	(16*1024*1024)
-#define CEPH_MSG_MAX_DATA_LEN	(16*1024*1024)
+
+/*
+ * Handle the largest possible rbd object in one message.
+ * There is no limit on the size of cephfs objects, but it has to obey
+ * rsize and wsize mount options anyway.
+ */
+#define CEPH_MSG_MAX_DATA_LEN	(32*1024*1024)
 
 #define CEPH_AUTH_NAME_DEFAULT   "guest"
 
--- linux-4.4.0.orig/include/linux/ceph/messenger.h
+++ linux-4.4.0/include/linux/ceph/messenger.h
@@ -220,6 +220,7 @@
 	struct ceph_entity_addr actual_peer_addr;
 
 	/* message out temps */
+	struct ceph_msg_header out_hdr;
 	struct ceph_msg *out_msg;        /* sending message (== tail of
 					    out_sent) */
 	bool out_msg_done;
@@ -229,7 +230,6 @@
 	int out_kvec_left;   /* kvec's left in out_kvec */
 	int out_skip;        /* skip this many bytes */
 	int out_kvec_bytes;  /* total bytes left */
-	bool out_kvec_is_msg; /* kvec refers to out_msg */
 	int out_more;        /* there is more data after the kvecs */
 	__le64 out_temp_ack; /* for writing an ack */
 	struct ceph_timespec out_temp_keepalive2; /* for writing keepalive2
--- linux-4.4.0.orig/include/linux/ceph/osdmap.h
+++ linux-4.4.0/include/linux/ceph/osdmap.h
@@ -49,7 +49,7 @@
 	case CEPH_POOL_TYPE_EC:
 		return false;
 	default:
-		BUG_ON(1);
+		BUG();
 	}
 }
 
--- linux-4.4.0.orig/include/linux/cgroup-defs.h
+++ linux-4.4.0/include/linux/cgroup-defs.h
@@ -133,6 +133,12 @@
 	 */
 	u64 serial_nr;
 
+	/*
+	 * Incremented by online self and children.  Used to guarantee that
+	 * parents are not offlined before their children.
+	 */
+	atomic_t online_cnt;
+
 	/* percpu_ref killing and RCU release */
 	struct rcu_head rcu_head;
 	struct work_struct destroy_work;
@@ -210,6 +216,9 @@
 	/* all css_task_iters currently walking this cset */
 	struct list_head task_iters;
 
+	/* dead and being drained, ignore for migration */
+	bool dead;
+
 	/* For RCU-protected deletion */
 	struct rcu_head rcu_head;
 };
@@ -425,6 +434,7 @@
 	int (*can_attach)(struct cgroup_taskset *tset);
 	void (*cancel_attach)(struct cgroup_taskset *tset);
 	void (*attach)(struct cgroup_taskset *tset);
+	void (*post_attach)(void);
 	int (*can_fork)(struct task_struct *task, void **priv_p);
 	void (*cancel_fork)(struct task_struct *task, void *priv);
 	void (*fork)(struct task_struct *task, void *priv);
--- linux-4.4.0.orig/include/linux/cgroup.h
+++ linux-4.4.0/include/linux/cgroup.h
@@ -17,6 +17,11 @@
 #include <linux/seq_file.h>
 #include <linux/kernfs.h>
 #include <linux/jump_label.h>
+#include <linux/nsproxy.h>
+#include <linux/types.h>
+#include <linux/ns_common.h>
+#include <linux/nsproxy.h>
+#include <linux/user_namespace.h>
 
 #include <linux/cgroup-defs.h>
 
@@ -340,6 +345,26 @@
 }
 
 /**
+ * css_is_dying - test whether the specified css is dying
+ * @css: target css
+ *
+ * Test whether @css is in the process of offlining or already offline.  In
+ * most cases, ->css_online() and ->css_offline() callbacks should be
+ * enough; however, the actual offline operations are RCU delayed and this
+ * test returns %true also when @css is scheduled to be offlined.
+ *
+ * This is useful, for example, when the use case requires synchronous
+ * behavior with respect to cgroup removal.  cgroup removal schedules css
+ * offlining but the css can seem alive while the operation is being
+ * delayed.  If the delay affects user visible semantics, this test can be
+ * used to resolve the situation.
+ */
+static inline bool css_is_dying(struct cgroup_subsys_state *css)
+{
+	return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt);
+}
+
+/**
  * css_put - put a css reference
  * @css: target css
  *
@@ -433,7 +458,7 @@
  *
  * Find the css for the (@task, @subsys_id) combination, increment a
  * reference on and return it.  This function is guaranteed to return a
- * valid css.
+ * valid css.  The returned css may already have been offlined.
  */
 static inline struct cgroup_subsys_state *
 task_get_css(struct task_struct *task, int subsys_id)
@@ -443,7 +468,13 @@
 	rcu_read_lock();
 	while (true) {
 		css = task_css(task, subsys_id);
-		if (likely(css_tryget_online(css)))
+		/*
+		 * Can't use css_tryget_online() here.  A task which has
+		 * PF_EXITING set may stay associated with an offline css.
+		 * If such task calls this function, css_tryget_online()
+		 * will keep failing.
+		 */
+		if (likely(css_tryget(css)))
 			break;
 		cpu_relax();
 	}
@@ -528,6 +559,25 @@
 	pr_cont_kernfs_path(cgrp->kn);
 }
 
+static inline void cgroup_init_kthreadd(void)
+{
+	/*
+	 * kthreadd is inherited by all kthreads, keep it in the root so
+	 * that the new kthreads are guaranteed to stay in the root until
+	 * initialization is finished.
+	 */
+	current->no_cgroup_migration = 1;
+}
+
+static inline void cgroup_kthread_ready(void)
+{
+	/*
+	 * This kthread finished initialization.  The creator should have
+	 * set PF_NO_SETAFFINITY if this kthread should stay in the root.
+	 */
+	current->no_cgroup_migration = 0;
+}
+
 #else /* !CONFIG_CGROUPS */
 
 struct cgroup_subsys_state;
@@ -551,7 +601,53 @@
 
 static inline int cgroup_init_early(void) { return 0; }
 static inline int cgroup_init(void) { return 0; }
+static inline void cgroup_init_kthreadd(void) {}
+static inline void cgroup_kthread_ready(void) {}
 
 #endif /* !CONFIG_CGROUPS */
 
+struct cgroup_namespace {
+	atomic_t		count;
+	struct ns_common	ns;
+	struct user_namespace	*user_ns;
+	struct css_set          *root_cset;
+};
+
+extern struct cgroup_namespace init_cgroup_ns;
+
+#ifdef CONFIG_CGROUPS
+
+void free_cgroup_ns(struct cgroup_namespace *ns);
+
+struct cgroup_namespace *
+copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns,
+	       struct cgroup_namespace *old_ns);
+
+char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen,
+		     struct cgroup_namespace *ns);
+
+#else /* !CONFIG_CGROUPS */
+
+static inline void free_cgroup_ns(struct cgroup_namespace *ns) { }
+static inline struct cgroup_namespace *
+copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns,
+	       struct cgroup_namespace *old_ns)
+{
+	return old_ns;
+}
+
+#endif /* !CONFIG_CGROUPS */
+
+static inline void get_cgroup_ns(struct cgroup_namespace *ns)
+{
+	if (ns)
+		atomic_inc(&ns->count);
+}
+
+static inline void put_cgroup_ns(struct cgroup_namespace *ns)
+{
+	if (ns && atomic_dec_and_test(&ns->count))
+		free_cgroup_ns(ns);
+}
+
 #endif /* _LINUX_CGROUP_H */
--- linux-4.4.0.orig/include/linux/clk-provider.h
+++ linux-4.4.0/include/linux/clk-provider.h
@@ -384,6 +384,7 @@
 #define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)
 
 extern const struct clk_ops clk_divider_ops;
+extern const struct clk_ops clk_divider_ro_ops;
 
 unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
 		unsigned int val, const struct clk_div_table *table,
--- linux-4.4.0.orig/include/linux/coda.h
+++ linux-4.4.0/include/linux/coda.h
@@ -58,8 +58,7 @@
 #ifndef _CODA_HEADER_
 #define _CODA_HEADER_
 
-#if defined(__linux__)
 typedef unsigned long long u_quad_t;
-#endif
+
 #include <uapi/linux/coda.h>
 #endif 
--- linux-4.4.0.orig/include/linux/coda_psdev.h
+++ linux-4.4.0/include/linux/coda_psdev.h
@@ -19,6 +19,17 @@
 	struct mutex	    vc_mutex;
 };
 
+/* messages between coda filesystem in kernel and Venus */
+struct upc_req {
+	struct list_head	uc_chain;
+	caddr_t			uc_data;
+	u_short			uc_flags;
+	u_short			uc_inSize;  /* Size is at most 5000 bytes */
+	u_short			uc_outSize;
+	u_short			uc_opcode;  /* copied from data to save lookup */
+	int			uc_unique;
+	wait_queue_head_t	uc_sleep;   /* process' wait queue */
+};
 
 static inline struct venus_comm *coda_vcp(struct super_block *sb)
 {
--- linux-4.4.0.orig/include/linux/compaction.h
+++ linux-4.4.0/include/linux/compaction.h
@@ -2,21 +2,40 @@
 #define _LINUX_COMPACTION_H
 
 /* Return values for compact_zone() and try_to_compact_pages() */
-/* compaction didn't start as it was deferred due to past failures */
-#define COMPACT_DEFERRED	0
-/* compaction didn't start as it was not possible or direct reclaim was more suitable */
-#define COMPACT_SKIPPED		1
-/* compaction should continue to another pageblock */
-#define COMPACT_CONTINUE	2
-/* direct compaction partially compacted a zone and there are suitable pages */
-#define COMPACT_PARTIAL		3
-/* The full zone was compacted */
-#define COMPACT_COMPLETE	4
-/* For more detailed tracepoint output */
-#define COMPACT_NO_SUITABLE_PAGE	5
-#define COMPACT_NOT_SUITABLE_ZONE	6
-#define COMPACT_CONTENDED		7
 /* When adding new states, please adjust include/trace/events/compaction.h */
+enum compact_result {
+	/*
+	 * compaction didn't start as it was not possible or direct reclaim
+	 * was more suitable
+	 */
+	COMPACT_SKIPPED,
+	/* compaction didn't start as it was deferred due to past failures */
+	COMPACT_DEFERRED,
+	/* compaction not active last round */
+	COMPACT_INACTIVE = COMPACT_DEFERRED,
+
+	/* compaction should continue to another pageblock */
+	COMPACT_CONTINUE,
+	/*
+	 * direct compaction partially compacted a zone and there are suitable
+	 * pages
+	 */
+	COMPACT_PARTIAL,
+	/*
+	 * direct compaction has scanned part of the zone but wasn't successfull
+	 * to compact suitable pages.
+	 */
+	COMPACT_PARTIAL_SKIPPED,
+	/*
+	 * The full zone was compacted scanned but wasn't successfull to compact
+	 * suitable pages.
+	 */
+	COMPACT_COMPLETE,
+	/* For more detailed tracepoint output */
+	COMPACT_NO_SUITABLE_PAGE,
+	COMPACT_NOT_SUITABLE_ZONE,
+	COMPACT_CONTENDED,
+};
 
 /* Used to signal whether compaction detected need_sched() or lock contention */
 /* No contention detected */
@@ -38,13 +57,14 @@
 extern int sysctl_compact_unevictable_allowed;
 
 extern int fragmentation_index(struct zone *zone, unsigned int order);
-extern unsigned long try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
-			int alloc_flags, const struct alloc_context *ac,
-			enum migrate_mode mode, int *contended);
+extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
+			unsigned int order,
+		unsigned int alloc_flags, const struct alloc_context *ac,
+		enum migrate_mode mode, int *contended);
 extern void compact_pgdat(pg_data_t *pgdat, int order);
 extern void reset_isolation_suitable(pg_data_t *pgdat);
-extern unsigned long compaction_suitable(struct zone *zone, int order,
-					int alloc_flags, int classzone_idx);
+extern enum compact_result compaction_suitable(struct zone *zone, int order,
+		unsigned int alloc_flags, int classzone_idx);
 
 extern void defer_compaction(struct zone *zone, int order);
 extern bool compaction_deferred(struct zone *zone, int order);
@@ -52,8 +72,75 @@
 				bool alloc_success);
 extern bool compaction_restarting(struct zone *zone, int order);
 
+/* Compaction has made some progress and retrying makes sense */
+static inline bool compaction_made_progress(enum compact_result result)
+{
+	/*
+	 * Even though this might sound confusing this in fact tells us
+	 * that the compaction successfully isolated and migrated some
+	 * pageblocks.
+	 */
+	if (result == COMPACT_PARTIAL)
+		return true;
+
+	return false;
+}
+
+/* Compaction has failed and it doesn't make much sense to keep retrying. */
+static inline bool compaction_failed(enum compact_result result)
+{
+	/* All zones were scanned completely and still not result. */
+	if (result == COMPACT_COMPLETE)
+		return true;
+
+	return false;
+}
+
+/*
+ * Compaction  has backed off for some reason. It might be throttling or
+ * lock contention. Retrying is still worthwhile.
+ */
+static inline bool compaction_withdrawn(enum compact_result result)
+{
+	/*
+	 * Compaction backed off due to watermark checks for order-0
+	 * so the regular reclaim has to try harder and reclaim something.
+	 */
+	if (result == COMPACT_SKIPPED)
+		return true;
+
+	/*
+	 * If compaction is deferred for high-order allocations, it is
+	 * because sync compaction recently failed. If this is the case
+	 * and the caller requested a THP allocation, we do not want
+	 * to heavily disrupt the system, so we fail the allocation
+	 * instead of entering direct reclaim.
+	 */
+	if (result == COMPACT_DEFERRED)
+		return true;
+
+	/*
+	 * If compaction in async mode encounters contention or blocks higher
+	 * priority task we back off early rather than cause stalls.
+	 */
+	if (result == COMPACT_CONTENDED)
+		return true;
+
+	/*
+	 * Page scanners have met but we haven't scanned full zones so this
+	 * is a back off in fact.
+	 */
+	if (result == COMPACT_PARTIAL_SKIPPED)
+		return true;
+
+	return false;
+}
+
+bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
+					int alloc_flags);
+
 #else
-static inline unsigned long try_to_compact_pages(gfp_t gfp_mask,
+static inline enum compact_result try_to_compact_pages(gfp_t gfp_mask,
 			unsigned int order, int alloc_flags,
 			const struct alloc_context *ac,
 			enum migrate_mode mode, int *contended)
@@ -69,7 +156,7 @@
 {
 }
 
-static inline unsigned long compaction_suitable(struct zone *zone, int order,
+static inline enum compact_result compaction_suitable(struct zone *zone, int order,
 					int alloc_flags, int classzone_idx)
 {
 	return COMPACT_SKIPPED;
@@ -84,6 +171,20 @@
 	return true;
 }
 
+static inline bool compaction_made_progress(enum compact_result result)
+{
+	return false;
+}
+
+static inline bool compaction_failed(enum compact_result result)
+{
+	return false;
+}
+
+static inline bool compaction_withdrawn(enum compact_result result)
+{
+	return true;
+}
 #endif /* CONFIG_COMPACTION */
 
 #if defined(CONFIG_COMPACTION) && defined(CONFIG_SYSFS) && defined(CONFIG_NUMA)
--- linux-4.4.0.orig/include/linux/compat.h
+++ linux-4.4.0/include/linux/compat.h
@@ -65,6 +65,9 @@
 	compat_size_t			ss_size;
 } compat_stack_t;
 #endif
+#ifndef COMPAT_MINSIGSTKSZ
+#define COMPAT_MINSIGSTKSZ	MINSIGSTKSZ
+#endif
 
 #define compat_jiffies_to_clock_t(x)	\
 		(((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
@@ -306,8 +309,6 @@
 struct compat_mq_attr;
 struct compat_msgbuf;
 
-extern void compat_exit_robust_list(struct task_struct *curr);
-
 asmlinkage long
 compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
 			   compat_size_t len);
--- linux-4.4.0.orig/include/linux/compiler-clang.h
+++ linux-4.4.0/include/linux/compiler-clang.h
@@ -10,3 +10,22 @@
 #undef uninitialized_var
 #define uninitialized_var(x) x = *(&(x))
 #endif
+
+/* same as gcc, this was present in clang-2.6 so we can assume it works
+ * with any version that can compile the kernel
+ */
+#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
+
+/*
+ * Not all versions of clang implement the the type-generic versions
+ * of the builtin overflow checkers. Fortunately, clang implements
+ * __has_builtin allowing us to avoid awkward version
+ * checks. Unfortunately, we don't know which version of gcc clang
+ * pretends to be, so the macro may or may not be defined.
+ */
+#undef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
+#if __has_builtin(__builtin_mul_overflow) && \
+    __has_builtin(__builtin_add_overflow) && \
+    __has_builtin(__builtin_sub_overflow)
+#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1
+#endif
--- linux-4.4.0.orig/include/linux/compiler-gcc.h
+++ linux-4.4.0/include/linux/compiler-gcc.h
@@ -65,21 +65,40 @@
 #endif
 
 /*
+ * Feature detection for gnu_inline (gnu89 extern inline semantics). Either
+ * __GNUC_STDC_INLINE__ is defined (not using gnu89 extern inline semantics,
+ * and we opt in to the gnu89 semantics), or __GNUC_STDC_INLINE__ is not
+ * defined so the gnu89 semantics are the default.
+ */
+#ifdef __GNUC_STDC_INLINE__
+# define __gnu_inline	__attribute__((gnu_inline))
+#else
+# define __gnu_inline
+#endif
+
+/*
  * Force always-inline if the user requests it so via the .config,
- * or if gcc is too old:
+ * or if gcc is too old.
+ * GCC does not warn about unused static inline functions for
+ * -Wunused-function.  This turns out to avoid the need for complex #ifdef
+ * directives.  Suppress the warning in clang as well by using "unused"
+ * function attribute, which is redundant but not harmful for gcc.
+ * Prefer gnu_inline, so that extern inline functions do not emit an
+ * externally visible function. This makes extern inline behave as per gnu89
+ * semantics rather than c99. This prevents multiple symbol definition errors
+ * of extern inline functions at link time.
+ * A lot of inline functions can cause havoc with function tracing.
  */
 #if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||		\
     !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
-#define inline		inline		__attribute__((always_inline)) notrace
-#define __inline__	__inline__	__attribute__((always_inline)) notrace
-#define __inline	__inline	__attribute__((always_inline)) notrace
+#define inline \
+	inline __attribute__((always_inline, unused)) notrace __gnu_inline
 #else
-/* A lot of inline functions can cause havoc with function tracing */
-#define inline		inline		notrace
-#define __inline__	__inline__	notrace
-#define __inline	__inline	notrace
+#define inline inline		__attribute__((unused)) notrace __gnu_inline
 #endif
 
+#define __inline__ inline
+#define __inline inline
 #define __always_inline	inline __attribute__((always_inline))
 #define  noinline	__attribute__((noinline))
 
@@ -126,6 +145,12 @@
 
 #if GCC_VERSION < 30200
 # error Sorry, your compiler is too old - please upgrade it.
+#elif defined(CONFIG_ARM64) && GCC_VERSION < 50100 && !defined(__clang__)
+/*
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63293
+ * https://lore.kernel.org/r/20210107111841.GN1551@shell.armlinux.org.uk
+ */
+# error Sorry, your version of GCC is too old - please use 5.1 or newer.
 #endif
 
 #if GCC_VERSION < 30300
@@ -188,6 +213,15 @@
 
 #if GCC_VERSION >= 40500
 /*
+ * calling noreturn functions, __builtin_unreachable() and __builtin_trap()
+ * confuse the stack allocation in gcc, leading to overly large stack
+ * frames, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365
+ *
+ * Adding an empty inline assembly before it works around the problem
+ */
+#define barrier_before_unreachable() asm volatile("")
+
+/*
  * Mark a position in code as unreachable.  This can be used to
  * suppress control flow warnings after asm blocks that transfer
  * control elsewhere.
@@ -196,10 +230,14 @@
  * this in the preprocessor, but we can live with this because they're
  * unreleased.  Really, we need to have autoconf for the kernel.
  */
-#define unreachable() __builtin_unreachable()
+#define unreachable() \
+	do {					\
+		barrier_before_unreachable();	\
+		__builtin_unreachable();	\
+	} while (0)
 
 /* Mark a function definition as prohibited from being cloned. */
-#define __noclone	__attribute__((__noclone__))
+#define __noclone	__attribute__((__noclone__, __optimize__("no-tracer")))
 
 #endif /* GCC_VERSION >= 40500 */
 
@@ -251,7 +289,9 @@
 #endif
 #endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
 
-#if GCC_VERSION >= 50000
+#if GCC_VERSION >= 70000
+#define KASAN_ABI_VERSION 5
+#elif GCC_VERSION >= 50000
 #define KASAN_ABI_VERSION 4
 #elif GCC_VERSION >= 40902
 #define KASAN_ABI_VERSION 3
@@ -281,3 +321,7 @@
  * code
  */
 #define uninitialized_var(x) x = x
+
+#if GCC_VERSION >= 50100
+#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1
+#endif
--- linux-4.4.0.orig/include/linux/compiler-intel.h
+++ linux-4.4.0/include/linux/compiler-intel.h
@@ -43,3 +43,7 @@
 #define __builtin_bswap16 _bswap16
 #endif
 
+/*
+ * icc defines __GNUC__, but does not implement the builtin overflow checkers.
+ */
+#undef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
--- linux-4.4.0.orig/include/linux/compiler.h
+++ linux-4.4.0/include/linux/compiler.h
@@ -52,6 +52,22 @@
 
 #ifdef __KERNEL__
 
+/*
+ * Minimal backport of compiler_attributes.h to add support for __copy
+ * to v4.9.y so that we can use it in init/exit_module to avoid
+ * -Werror=missing-attributes errors on GCC 9.
+ */
+#ifndef __has_attribute
+# define __has_attribute(x) __GCC4_has_attribute_##x
+# define __GCC4_has_attribute___copy__                0
+#endif
+
+#if __has_attribute(__copy__)
+# define __copy(symbol)                 __attribute__((__copy__(symbol)))
+#else
+# define __copy(symbol)
+#endif
+
 #ifdef __GNUC__
 #include <linux/compiler-gcc.h>
 #endif
@@ -111,7 +127,7 @@
 #define unlikely_notrace(x)	__builtin_expect(!!(x), 0)
 
 #define __branch_check__(x, expect) ({					\
-			int ______r;					\
+			long ______r;					\
 			static struct ftrace_branch_data		\
 				__attribute__((__aligned__(4)))		\
 				__attribute__((section("_ftrace_annotated_branch"))) \
@@ -144,7 +160,7 @@
  */
 #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
 #define __trace_if(cond) \
-	if (__builtin_constant_p((cond)) ? !!(cond) :			\
+	if (__builtin_constant_p(!!(cond)) ? !!(cond) :			\
 	({								\
 		int ______r;						\
 		static struct ftrace_branch_data			\
@@ -175,6 +191,11 @@
 # define barrier_data(ptr) barrier()
 #endif
 
+/* workaround for GCC PR82365 if needed */
+#ifndef barrier_before_unreachable
+# define barrier_before_unreachable() do { } while (0)
+#endif
+
 /* Unreachable code */
 #ifndef unreachable
 # define unreachable() do { } while (1)
@@ -220,23 +241,21 @@
 
 #ifdef CONFIG_KASAN
 /*
- * This function is not 'inline' because __no_sanitize_address confilcts
+ * We can't declare function 'inline' because __no_sanitize_address confilcts
  * with inlining. Attempt to inline it may cause a build failure.
  * 	https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
  * '__maybe_unused' allows us to avoid defined-but-not-used warnings.
  */
-static __no_sanitize_address __maybe_unused
-void __read_once_size_nocheck(const volatile void *p, void *res, int size)
-{
-	__READ_ONCE_SIZE;
-}
+# define __no_kasan_or_inline __no_sanitize_address __maybe_unused
 #else
-static __always_inline
+# define __no_kasan_or_inline __always_inline
+#endif
+
+static __no_kasan_or_inline
 void __read_once_size_nocheck(const volatile void *p, void *res, int size)
 {
 	__READ_ONCE_SIZE;
 }
-#endif
 
 static __always_inline void __write_once_size(volatile void *p, void *res, int size)
 {
@@ -273,6 +292,7 @@
  * with an explicit memory barrier or atomic instruction that provides the
  * required ordering.
  */
+#include <linux/kasan-checks.h>
 
 #define __READ_ONCE(x, check)						\
 ({									\
@@ -291,6 +311,13 @@
  */
 #define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)
 
+static __no_kasan_or_inline
+unsigned long read_word_at_a_time(const void *addr)
+{
+	kasan_check_read(addr, 1);
+	return *(unsigned long *)addr;
+}
+
 #define WRITE_ONCE(x, val) \
 ({							\
 	union { typeof(x) __val; char __c[1]; } __u =	\
@@ -481,7 +508,7 @@
  * compiler has support to do so.
  */
 #define compiletime_assert(condition, msg) \
-	_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
+	_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
 
 #define compiletime_assert_atomic_type(t)				\
 	compiletime_assert(__native_word(t),				\
@@ -535,4 +562,11 @@
 # define __kprobes
 # define nokprobe_inline	inline
 #endif
+
+/*
+ * This is needed in functions which generate the stack canary, see
+ * arch/x86/kernel/smpboot.c::start_secondary() for an example.
+ */
+#define prevent_tail_call_optimization()	mb()
+
 #endif /* __LINUX_COMPILER_H */
--- linux-4.4.0.orig/include/linux/console.h
+++ linux-4.4.0/include/linux/console.h
@@ -150,6 +150,7 @@
 extern void console_unlock(void);
 extern void console_conditional_schedule(void);
 extern void console_unblank(void);
+extern void console_flush_on_panic(void);
 extern struct tty_driver *console_device(int *);
 extern void console_stop(struct console *);
 extern void console_start(struct console *);
--- linux-4.4.0.orig/include/linux/coredump.h
+++ linux-4.4.0/include/linux/coredump.h
@@ -14,6 +14,7 @@
 extern int dump_skip(struct coredump_params *cprm, size_t nr);
 extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr);
 extern int dump_align(struct coredump_params *cprm, int align);
+extern void dump_truncate(struct coredump_params *cprm);
 #ifdef CONFIG_COREDUMP
 extern void do_coredump(const siginfo_t *siginfo);
 #else
--- linux-4.4.0.orig/include/linux/cpu.h
+++ linux-4.4.0/include/linux/cpu.h
@@ -40,6 +40,32 @@
 extern int cpu_add_dev_attr_group(struct attribute_group *attrs);
 extern void cpu_remove_dev_attr_group(struct attribute_group *attrs);
 
+extern ssize_t cpu_show_meltdown(struct device *dev,
+				 struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_spectre_v1(struct device *dev,
+				   struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_spectre_v2(struct device *dev,
+				   struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_spec_store_bypass(struct device *dev,
+					  struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_l1tf(struct device *dev,
+			     struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_mds(struct device *dev,
+			    struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_tsx_async_abort(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+extern ssize_t cpu_show_itlb_multihit(struct device *dev,
+				      struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_mmio_stale_data(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+extern ssize_t cpu_show_retbleed(struct device *dev,
+				 struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_vmscape(struct device *dev,
+				struct device_attribute *attr, char *buf);
+
 extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,
 				 const struct attribute_group **groups,
@@ -131,22 +157,16 @@
 		{ .notifier_call = fn, .priority = pri };	\
 	__register_cpu_notifier(&fn##_nb);			\
 }
-#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
-#define cpu_notifier(fn, pri)	do { (void)(fn); } while (0)
-#define __cpu_notifier(fn, pri)	do { (void)(fn); } while (0)
-#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
 
-#ifdef CONFIG_HOTPLUG_CPU
 extern int register_cpu_notifier(struct notifier_block *nb);
 extern int __register_cpu_notifier(struct notifier_block *nb);
 extern void unregister_cpu_notifier(struct notifier_block *nb);
 extern void __unregister_cpu_notifier(struct notifier_block *nb);
-#else
 
-#ifndef MODULE
-extern int register_cpu_notifier(struct notifier_block *nb);
-extern int __register_cpu_notifier(struct notifier_block *nb);
-#else
+#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
+#define cpu_notifier(fn, pri)	do { (void)(fn); } while (0)
+#define __cpu_notifier(fn, pri)	do { (void)(fn); } while (0)
+
 static inline int register_cpu_notifier(struct notifier_block *nb)
 {
 	return 0;
@@ -156,7 +176,6 @@
 {
 	return 0;
 }
-#endif
 
 static inline void unregister_cpu_notifier(struct notifier_block *nb)
 {
@@ -239,6 +258,7 @@
 #define __unregister_hotcpu_notifier(nb)	__unregister_cpu_notifier(nb)
 void clear_tasks_mm_cpumask(int cpu);
 int cpu_down(unsigned int cpu);
+int cpu_down_maps_locked(unsigned int cpu);
 
 #else		/* CONFIG_HOTPLUG_CPU */
 
@@ -282,6 +302,12 @@
 
 DECLARE_PER_CPU(bool, cpu_dead_idle);
 
+#ifdef CONFIG_ARCH_HAS_CPU_FINALIZE_INIT
+void arch_cpu_finalize_init(void);
+#else
+static inline void arch_cpu_finalize_init(void) { }
+#endif
+
 int cpu_report_state(int cpu);
 int cpu_check_up_prepare(int cpu);
 void cpu_set_state_online(int cpu);
@@ -290,4 +316,26 @@
 bool cpu_report_death(void);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
+enum cpuhp_smt_control {
+	CPU_SMT_ENABLED,
+	CPU_SMT_DISABLED,
+	CPU_SMT_FORCE_DISABLED,
+	CPU_SMT_NOT_SUPPORTED,
+};
+
+#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_SMT)
+extern enum cpuhp_smt_control cpu_smt_control;
+extern void cpu_smt_disable(bool force);
+extern void cpu_smt_check_topology(void);
+extern bool cpu_smt_possible(void);
+#else
+# define cpu_smt_control		(CPU_SMT_ENABLED)
+static inline void cpu_smt_disable(bool force) { }
+static inline void cpu_smt_check_topology(void) { }
+static inline bool cpu_smt_possible(void) { return false; }
+#endif
+
+extern bool cpu_mitigations_off(void);
+extern bool cpu_mitigations_auto_nosmt(void);
+
 #endif /* _LINUX_CPU_H_ */
--- linux-4.4.0.orig/include/linux/cpufeature.h
+++ linux-4.4.0/include/linux/cpufeature.h
@@ -45,7 +45,7 @@
  * 'asm/cpufeature.h' of your favorite architecture.
  */
 #define module_cpu_feature_match(x, __initfunc)			\
-static struct cpu_feature const cpu_feature_match_ ## x[] =	\
+static struct cpu_feature const __maybe_unused cpu_feature_match_ ## x[] = \
 	{ { .feature = cpu_feature(x) }, { } };			\
 MODULE_DEVICE_TABLE(cpu, cpu_feature_match_ ## x);		\
 								\
--- linux-4.4.0.orig/include/linux/cpufreq.h
+++ linux-4.4.0/include/linux/cpufreq.h
@@ -100,10 +100,6 @@
 	 * - Any routine that will write to the policy structure and/or may take away
 	 *   the policy altogether (eg. CPU hotplug), will hold this lock in write
 	 *   mode before doing so.
-	 *
-	 * Additional rules:
-	 * - Lock should not be held across
-	 *     __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
 	 */
 	struct rw_semaphore	rwsem;
 
@@ -203,20 +199,12 @@
 static struct freq_attr _name =			\
 __ATTR(_name, 0644, show_##_name, store_##_name)
 
-struct global_attr {
-	struct attribute attr;
-	ssize_t (*show)(struct kobject *kobj,
-			struct attribute *attr, char *buf);
-	ssize_t (*store)(struct kobject *a, struct attribute *b,
-			 const char *c, size_t count);
-};
-
 #define define_one_global_ro(_name)		\
-static struct global_attr _name =		\
+static struct kobj_attribute _name =		\
 __ATTR(_name, 0444, show_##_name, NULL)
 
 #define define_one_global_rw(_name)		\
-static struct global_attr _name =		\
+static struct kobj_attribute _name =		\
 __ATTR(_name, 0644, show_##_name, store_##_name)
 
 
--- linux-4.4.0.orig/include/linux/cpuidle.h
+++ linux-4.4.0/include/linux/cpuidle.h
@@ -152,6 +152,8 @@
 extern int cpuidle_play_dead(void);
 
 extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
+static inline struct cpuidle_device *cpuidle_get_device(void)
+{return __this_cpu_read(cpuidle_devices); }
 #else
 static inline void disable_cpuidle(void) { }
 static inline bool cpuidle_not_available(struct cpuidle_driver *drv,
@@ -187,6 +189,7 @@
 static inline int cpuidle_play_dead(void) {return -ENODEV; }
 static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
 	struct cpuidle_device *dev) {return NULL; }
+static inline struct cpuidle_device *cpuidle_get_device(void) {return NULL; }
 #endif
 
 #if defined(CONFIG_CPU_IDLE) && defined(CONFIG_SUSPEND)
--- linux-4.4.0.orig/include/linux/cpumask.h
+++ linux-4.4.0/include/linux/cpumask.h
@@ -160,6 +160,8 @@
 	for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
 #define for_each_cpu_not(cpu, mask)		\
 	for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
+#define for_each_cpu_wrap(cpu, mask, start)	\
+	for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)(start))
 #define for_each_cpu_and(cpu, mask, and)	\
 	for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and)
 #else
@@ -232,6 +234,23 @@
 		(cpu) = cpumask_next_zero((cpu), (mask)),	\
 		(cpu) < nr_cpu_ids;)
 
+extern int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap);
+
+/**
+ * for_each_cpu_wrap - iterate over every cpu in a mask, starting at a specified location
+ * @cpu: the (optionally unsigned) integer iterator
+ * @mask: the cpumask poiter
+ * @start: the start location
+ *
+ * The implementation does not assume any bit in @mask is set (including @start).
+ *
+ * After the loop, cpu is >= nr_cpu_ids.
+ */
+#define for_each_cpu_wrap(cpu, mask, start)					\
+	for ((cpu) = cpumask_next_wrap((start)-1, (mask), (start), false);	\
+	     (cpu) < nr_cpumask_bits;						\
+	     (cpu) = cpumask_next_wrap((cpu), (mask), (start), true))
+
 /**
  * for_each_cpu_and - iterate over every cpu in both masks
  * @cpu: the (optionally unsigned) integer iterator
@@ -556,7 +575,7 @@
 static inline int cpumask_parse_user(const char __user *buf, int len,
 				     struct cpumask *dstp)
 {
-	return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpu_ids);
+	return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
 }
 
 /**
@@ -571,7 +590,7 @@
 				     struct cpumask *dstp)
 {
 	return bitmap_parselist_user(buf, len, cpumask_bits(dstp),
-				     nr_cpu_ids);
+				     nr_cpumask_bits);
 }
 
 /**
@@ -586,7 +605,7 @@
 	char *nl = strchr(buf, '\n');
 	unsigned int len = nl ? (unsigned int)(nl - buf) : strlen(buf);
 
-	return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpu_ids);
+	return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
 }
 
 /**
@@ -598,7 +617,7 @@
  */
 static inline int cpulist_parse(const char *buf, struct cpumask *dstp)
 {
-	return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpu_ids);
+	return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpumask_bits);
 }
 
 /**
@@ -661,6 +680,11 @@
 void free_cpumask_var(cpumask_var_t mask);
 void free_bootmem_cpumask_var(cpumask_var_t mask);
 
+static inline bool cpumask_available(cpumask_var_t mask)
+{
+	return mask != NULL;
+}
+
 #else
 typedef struct cpumask cpumask_var_t[1];
 
@@ -701,6 +725,11 @@
 static inline void free_bootmem_cpumask_var(cpumask_var_t mask)
 {
 }
+
+static inline bool cpumask_available(cpumask_var_t mask)
+{
+	return true;
+}
 #endif /* CONFIG_CPUMASK_OFFSTACK */
 
 /* It's common to want to use cpu_all_mask in struct member initializers,
--- linux-4.4.0.orig/include/linux/cpuset.h
+++ linux-4.4.0/include/linux/cpuset.h
@@ -16,6 +16,7 @@
 
 #ifdef CONFIG_CPUSETS
 
+extern struct static_key cpusets_pre_enable_key;
 extern struct static_key cpusets_enabled_key;
 static inline bool cpusets_enabled(void)
 {
@@ -30,17 +31,21 @@
 
 static inline void cpuset_inc(void)
 {
+	static_key_slow_inc(&cpusets_pre_enable_key);
 	static_key_slow_inc(&cpusets_enabled_key);
 }
 
 static inline void cpuset_dec(void)
 {
 	static_key_slow_dec(&cpusets_enabled_key);
+	static_key_slow_dec(&cpusets_pre_enable_key);
 }
 
 extern int cpuset_init(void);
 extern void cpuset_init_smp(void);
+extern void cpuset_force_rebuild(void);
 extern void cpuset_update_active_cpus(bool cpu_online);
+extern void cpuset_wait_for_hotplug(void);
 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);
@@ -104,7 +109,7 @@
  */
 static inline unsigned int read_mems_allowed_begin(void)
 {
-	if (!cpusets_enabled())
+	if (!static_key_false(&cpusets_pre_enable_key))
 		return 0;
 
 	return read_seqcount_begin(&current->mems_allowed_seq);
@@ -118,7 +123,7 @@
  */
 static inline bool read_mems_allowed_retry(unsigned int seq)
 {
-	if (!cpusets_enabled())
+	if (!static_key_false(&cpusets_enabled_key))
 		return false;
 
 	return read_seqcount_retry(&current->mems_allowed_seq, seq);
@@ -144,11 +149,15 @@
 static inline int cpuset_init(void) { return 0; }
 static inline void cpuset_init_smp(void) {}
 
+static inline void cpuset_force_rebuild(void) { }
+
 static inline void cpuset_update_active_cpus(bool cpu_online)
 {
 	partition_sched_domains(1, NULL, NULL);
 }
 
+static inline void cpuset_wait_for_hotplug(void) { }
+
 static inline void cpuset_cpus_allowed(struct task_struct *p,
 				       struct cpumask *mask)
 {
--- linux-4.4.0.orig/include/linux/cred.h
+++ linux-4.4.0/include/linux/cred.h
@@ -87,6 +87,7 @@
 extern void set_groups(struct cred *, struct group_info *);
 extern int groups_search(const struct group_info *, kgid_t);
 extern bool may_setgroups(void);
+extern void groups_sort(struct group_info *);
 
 /* access the groups "array" with this macro */
 #define GROUP_AT(gi, i) \
@@ -152,7 +153,11 @@
 	struct user_struct *user;	/* real user ID subscription */
 	struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
 	struct group_info *group_info;	/* supplementary groups for euid/fsgid */
-	struct rcu_head	rcu;		/* RCU deletion hook */
+	/* RCU deletion */
+	union {
+		int non_rcu;			/* Can we skip RCU deletion? */
+		struct rcu_head	rcu;		/* RCU deletion hook */
+	};
 };
 
 extern void __put_cred(struct cred *);
@@ -238,7 +243,7 @@
  * @cred: The credentials to reference
  *
  * Get a reference on the specified set of credentials.  The caller must
- * release the reference.
+ * release the reference.  If %NULL is passed, it is returned with no action.
  *
  * This is used to deal with a committed set of credentials.  Although the
  * pointer is const, this will temporarily discard the const and increment the
@@ -249,7 +254,10 @@
 static inline const struct cred *get_cred(const struct cred *cred)
 {
 	struct cred *nonconst_cred = (struct cred *) cred;
+	if (!cred)
+		return cred;
 	validate_creds(cred);
+	nonconst_cred->non_rcu = 0;
 	return get_new_cred(nonconst_cred);
 }
 
@@ -258,7 +266,7 @@
  * @cred: The credentials to release
  *
  * Release a reference to a set of credentials, deleting them when the last ref
- * is released.
+ * is released.  If %NULL is passed, nothing is done.
  *
  * This takes a const pointer to a set of credentials because the credentials
  * on task_struct are attached by const pointers to prevent accidental
@@ -268,9 +276,11 @@
 {
 	struct cred *cred = (struct cred *) _cred;
 
-	validate_creds(cred);
-	if (atomic_dec_and_test(&(cred)->usage))
-		__put_cred(cred);
+	if (cred) {
+		validate_creds(cred);
+		if (atomic_dec_and_test(&(cred)->usage))
+			__put_cred(cred);
+	}
 }
 
 /**
@@ -377,7 +387,10 @@
 #ifdef CONFIG_USER_NS
 #define current_user_ns()	(current_cred_xxx(user_ns))
 #else
-#define current_user_ns()	(&init_user_ns)
+static inline struct user_namespace *current_user_ns(void)
+{
+	return &init_user_ns;
+}
 #endif
 
 
--- linux-4.4.0.orig/include/linux/crypto.h
+++ linux-4.4.0/include/linux/crypto.h
@@ -52,6 +52,7 @@
 #define CRYPTO_ALG_TYPE_HASH		0x00000008
 #define CRYPTO_ALG_TYPE_SHASH		0x00000009
 #define CRYPTO_ALG_TYPE_AHASH		0x0000000a
+#define CRYPTO_ALG_TYPE_KPP		0x0000000b
 #define CRYPTO_ALG_TYPE_RNG		0x0000000c
 #define CRYPTO_ALG_TYPE_AKCIPHER	0x0000000d
 #define CRYPTO_ALG_TYPE_PCOMPRESS	0x0000000f
--- linux-4.4.0.orig/include/linux/dcache.h
+++ linux-4.4.0/include/linux/dcache.h
@@ -161,6 +161,7 @@
 	struct vfsmount *(*d_automount)(struct path *);
 	int (*d_manage)(struct dentry *, bool);
 	struct inode *(*d_select_inode)(struct dentry *, unsigned);
+	struct dentry *(*d_real)(struct dentry *, struct inode *);
 } ____cacheline_aligned;
 
 /*
@@ -227,6 +228,7 @@
 #define DCACHE_MAY_FREE			0x00800000
 #define DCACHE_FALLTHRU			0x01000000 /* Fall through to lower layer */
 #define DCACHE_OP_SELECT_INODE		0x02000000 /* Unioned entry: dcache op selects inode */
+#define DCACHE_OP_REAL			0x08000000
 
 extern seqlock_t rename_lock;
 
@@ -234,6 +236,7 @@
  * These are the low-level FS interfaces to the dcache..
  */
 extern void d_instantiate(struct dentry *, struct inode *);
+extern void d_instantiate_new(struct dentry *, struct inode *);
 extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
 extern int d_instantiate_no_diralias(struct dentry *, struct inode *);
 extern void __d_drop(struct dentry *dentry);
@@ -409,9 +412,7 @@
  */
 static inline unsigned __d_entry_type(const struct dentry *dentry)
 {
-	unsigned type = READ_ONCE(dentry->d_flags);
-	smp_rmb();
-	return type & DCACHE_ENTRY_TYPE;
+	return dentry->d_flags & DCACHE_ENTRY_TYPE;
 }
 
 static inline bool d_is_miss(const struct dentry *dentry)
@@ -584,4 +585,42 @@
 	return upper;
 }
 
+static inline struct dentry *d_real(struct dentry *dentry)
+{
+	if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
+		return dentry->d_op->d_real(dentry, NULL);
+	else
+		return dentry;
+}
+
+static inline struct inode *vfs_select_inode(struct dentry *dentry,
+					     unsigned open_flags)
+{
+	struct inode *inode = d_inode(dentry);
+
+	if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE))
+		inode = dentry->d_op->d_select_inode(dentry, open_flags);
+
+	return inode;
+}
+
+/**
+ * d_real_inode - Return the real inode
+ * @dentry: The dentry to query
+ *
+ * If dentry is on an union/overlay, then return the underlying, real inode.
+ * Otherwise return d_inode().
+ */
+static inline struct inode *d_real_inode(struct dentry *dentry)
+{
+	return d_backing_inode(d_real(dentry));
+}
+
+struct name_snapshot {
+	struct qstr name;
+	unsigned char inline_name[DNAME_INLINE_LEN];
+};
+void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
+void release_dentry_name_snapshot(struct name_snapshot *);
+
 #endif	/* __LINUX_DCACHE_H */
--- linux-4.4.0.orig/include/linux/dccp.h
+++ linux-4.4.0/include/linux/dccp.h
@@ -163,6 +163,7 @@
 	__u64			 dreq_isr;
 	__u64			 dreq_gsr;
 	__be32			 dreq_service;
+	spinlock_t		 dreq_lock;
 	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
--- linux-4.4.0.orig/include/linux/debugfs.h
+++ linux-4.4.0/include/linux/debugfs.h
@@ -19,9 +19,11 @@
 #include <linux/seq_file.h>
 
 #include <linux/types.h>
+#include <linux/compiler.h>
 
 struct device;
 struct file_operations;
+struct srcu_struct;
 
 struct debugfs_blob_wrapper {
 	void *data;
@@ -41,14 +43,16 @@
 
 extern struct dentry *arch_debugfs_dir;
 
-#if defined(CONFIG_DEBUG_FS)
+extern struct srcu_struct debugfs_srcu;
 
-/* declared over in file.c */
-extern const struct file_operations debugfs_file_operations;
+#if defined(CONFIG_DEBUG_FS)
 
 struct dentry *debugfs_create_file(const char *name, umode_t mode,
 				   struct dentry *parent, void *data,
 				   const struct file_operations *fops);
+struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
+				   struct dentry *parent, void *data,
+				   const struct file_operations *fops);
 
 struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
 					struct dentry *parent, void *data,
@@ -60,14 +64,40 @@
 struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
 				      const char *dest);
 
+typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *);
 struct dentry *debugfs_create_automount(const char *name,
 					struct dentry *parent,
-					struct vfsmount *(*f)(void *),
+					debugfs_automount_t f,
 					void *data);
 
 void debugfs_remove(struct dentry *dentry);
 void debugfs_remove_recursive(struct dentry *dentry);
 
+int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx)
+	__acquires(&debugfs_srcu);
+
+void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu);
+
+ssize_t debugfs_attr_read(struct file *file, char __user *buf,
+			size_t len, loff_t *ppos);
+ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
+			size_t len, loff_t *ppos);
+
+#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt)		\
+static int __fops ## _open(struct inode *inode, struct file *file)	\
+{									\
+	__simple_attr_check_format(__fmt, 0ull);			\
+	return simple_attr_open(inode, file, __get, __set, __fmt);	\
+}									\
+static const struct file_operations __fops = {				\
+	.owner	 = THIS_MODULE,					\
+	.open	 = __fops ## _open,					\
+	.release = simple_attr_release,				\
+	.read	 = debugfs_attr_read,					\
+	.write	 = debugfs_attr_write,					\
+	.llseek  = generic_file_llseek,				\
+}
+
 struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
                 struct dentry *new_dir, const char *new_name);
 
@@ -168,6 +198,20 @@
 static inline void debugfs_remove_recursive(struct dentry *dentry)
 { }
 
+static inline int debugfs_use_file_start(const struct dentry *dentry,
+					int *srcu_idx)
+	__acquires(&debugfs_srcu)
+{
+	return 0;
+}
+
+static inline void debugfs_use_file_finish(int srcu_idx)
+	__releases(&debugfs_srcu)
+{ }
+
+#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt)	\
+	static const struct file_operations __fops = { 0 }
+
 static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
                 struct dentry *new_dir, char *new_name)
 {
--- linux-4.4.0.orig/include/linux/devfreq-event.h
+++ linux-4.4.0/include/linux/devfreq-event.h
@@ -148,11 +148,6 @@
 	return -EINVAL;
 }
 
-static inline void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev)
-{
-	return ERR_PTR(-EINVAL);
-}
-
 static inline struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(
 					struct device *dev, int index)
 {
--- linux-4.4.0.orig/include/linux/devfreq_cooling.h
+++ linux-4.4.0/include/linux/devfreq_cooling.h
@@ -53,7 +53,7 @@
 
 #else /* !CONFIG_DEVFREQ_THERMAL */
 
-struct thermal_cooling_device *
+static inline struct thermal_cooling_device *
 of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
 				  struct devfreq_cooling_power *dfc_power)
 {
--- linux-4.4.0.orig/include/linux/device-mapper.h
+++ linux-4.4.0/include/linux/device-mapper.h
@@ -124,6 +124,8 @@
 	char name[16];
 };
 
+dev_t dm_get_dev_t(const char *path);
+
 /*
  * Constructors should call these functions to ensure destination devices
  * are opened/closed correctly.
@@ -541,8 +543,6 @@
 #define DMEMIT(x...) sz += ((sz >= maxlen) ? \
 			  0 : scnprintf(result + sz, maxlen - sz, x))
 
-#define SECTOR_SHIFT 9
-
 /*
  * Definitions of return values from target end_io function.
  */
@@ -591,7 +591,7 @@
  */
 #define dm_target_offset(ti, sector) ((sector) - (ti)->begin)
 
-static inline sector_t to_sector(unsigned long n)
+static inline sector_t to_sector(unsigned long long n)
 {
 	return (n >> SECTOR_SHIFT);
 }
--- linux-4.4.0.orig/include/linux/device.h
+++ linux-4.4.0/include/linux/device.h
@@ -368,6 +368,7 @@
  * @suspend:	Used to put the device to sleep mode, usually to a low power
  *		state.
  * @resume:	Used to bring the device from the sleep mode.
+ * @shutdown:	Called at shut-down time to quiesce the device.
  * @ns_type:	Callbacks so sysfs can detemine namespaces.
  * @namespace:	Namespace of the device belongs to this class.
  * @pm:		The default device power management operations of this class.
@@ -396,6 +397,7 @@
 
 	int (*suspend)(struct device *dev, pm_message_t state);
 	int (*resume)(struct device *dev);
+	int (*shutdown)(struct device *dev);
 
 	const struct kobj_ns_type_operations *ns_type;
 	const void *(*namespace)(struct device *dev);
@@ -675,7 +677,8 @@
 					 gfp_t gfp_mask, unsigned int order);
 extern void devm_free_pages(struct device *dev, unsigned long addr);
 
-void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
+void __iomem *devm_ioremap_resource(struct device *dev,
+				    const struct resource *res);
 
 /* allows to add/remove a custom action to devres stack */
 int devm_add_action(struct device *dev, void (*action)(void *), void *data);
@@ -1270,8 +1273,11 @@
 		dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);	\
 } while (0)
 #else
-#define dev_dbg_ratelimited(dev, fmt, ...)			\
-	no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#define dev_dbg_ratelimited(dev, fmt, ...)				\
+do {									\
+	if (0)								\
+		dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);	\
+} while (0)
 #endif
 
 #ifdef VERBOSE_DEBUG
--- linux-4.4.0.orig/include/linux/devpts_fs.h
+++ linux-4.4.0/include/linux/devpts_fs.h
@@ -15,34 +15,24 @@
 
 #include <linux/errno.h>
 
+struct pts_fs_info;
+
 #ifdef CONFIG_UNIX98_PTYS
 
-int devpts_new_index(struct inode *ptmx_inode);
-void devpts_kill_index(struct inode *ptmx_inode, int idx);
+/* Look up a pts fs info and get a ref to it */
+struct pts_fs_info *devpts_get_ref(struct inode *, struct file *);
+void devpts_put_ref(struct pts_fs_info *);
+
+int devpts_new_index(struct pts_fs_info *);
+void devpts_kill_index(struct pts_fs_info *, int);
+
 /* mknod in devpts */
-struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
-		void *priv);
+struct inode *devpts_pty_new(struct pts_fs_info *, dev_t, int, void *);
 /* get private structure */
 void *devpts_get_priv(struct inode *pts_inode);
 /* unlink */
 void devpts_pty_kill(struct inode *inode);
 
-#else
-
-/* Dummy stubs in the no-pty case */
-static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
-static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
-static inline struct inode *devpts_pty_new(struct inode *ptmx_inode,
-		dev_t device, int index, void *priv)
-{
-	return ERR_PTR(-EINVAL);
-}
-static inline void *devpts_get_priv(struct inode *pts_inode)
-{
-	return NULL;
-}
-static inline void devpts_pty_kill(struct inode *inode) { }
-
 #endif
 
 
--- linux-4.4.0.orig/include/linux/dim.h
+++ linux-4.4.0/include/linux/dim.h
@@ -0,0 +1,346 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#ifndef DIM_H
+#define DIM_H
+
+#include <linux/module.h>
+
+/**
+ * Number of events between DIM iterations.
+ * Causes a moderation of the algorithm run.
+ */
+#define DIM_NEVENTS 64
+
+/**
+ * Is a difference between values justifies taking an action.
+ * We consider 10% difference as significant.
+ */
+#define IS_SIGNIFICANT_DIFF(val, ref) \
+	(((100UL * abs((val) - (ref))) / (ref)) > 10)
+
+/**
+ * Calculate the gap between two values.
+ * Take wrap-around and variable size into consideration.
+ */
+#define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) \
+		& (BIT_ULL(bits) - 1))
+
+/**
+ * Structure for CQ moderation values.
+ * Used for communications between DIM and its consumer.
+ *
+ * @usec: CQ timer suggestion (by DIM)
+ * @pkts: CQ packet counter suggestion (by DIM)
+ * @cq_period_mode: CQ priod count mode (from CQE/EQE)
+ */
+struct dim_cq_moder {
+	u16 usec;
+	u16 pkts;
+	u16 comps;
+	u8 cq_period_mode;
+};
+
+/**
+ * Structure for DIM sample data.
+ * Used for communications between DIM and its consumer.
+ *
+ * @time: Sample timestamp
+ * @pkt_ctr: Number of packets
+ * @byte_ctr: Number of bytes
+ * @event_ctr: Number of events
+ */
+struct dim_sample {
+	ktime_t time;
+	u32 pkt_ctr;
+	u32 byte_ctr;
+	u16 event_ctr;
+	u32 comp_ctr;
+};
+
+/**
+ * Structure for DIM stats.
+ * Used for holding current measured rates.
+ *
+ * @ppms: Packets per msec
+ * @bpms: Bytes per msec
+ * @epms: Events per msec
+ */
+struct dim_stats {
+	int ppms; /* packets per msec */
+	int bpms; /* bytes per msec */
+	int epms; /* events per msec */
+	int cpms; /* completions per msec */
+	int cpe_ratio; /* ratio of completions to events */
+};
+
+/**
+ * Main structure for dynamic interrupt moderation (DIM).
+ * Used for holding all information about a specific DIM instance.
+ *
+ * @state: Algorithm state (see below)
+ * @prev_stats: Measured rates from previous iteration (for comparison)
+ * @start_sample: Sampled data at start of current iteration
+ * @work: Work to perform on action required
+ * @priv: A pointer to the struct that points to dim
+ * @profile_ix: Current moderation profile
+ * @mode: CQ period count mode
+ * @tune_state: Algorithm tuning state (see below)
+ * @steps_right: Number of steps taken towards higher moderation
+ * @steps_left: Number of steps taken towards lower moderation
+ * @tired: Parking depth counter
+ */
+struct dim {
+	u8 state;
+	struct dim_stats prev_stats;
+	struct dim_sample start_sample;
+	struct dim_sample measuring_sample;
+	struct work_struct work;
+	void *priv;
+	u8 profile_ix;
+	u8 mode;
+	u8 tune_state;
+	u8 steps_right;
+	u8 steps_left;
+	u8 tired;
+};
+
+/**
+ * enum dim_cq_period_mode
+ *
+ * These are the modes for CQ period count.
+ *
+ * @DIM_CQ_PERIOD_MODE_START_FROM_EQE: Start counting from EQE
+ * @DIM_CQ_PERIOD_MODE_START_FROM_CQE: Start counting from CQE (implies timer reset)
+ * @DIM_CQ_PERIOD_NUM_MODES: Number of modes
+ */
+enum {
+	DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0x0,
+	DIM_CQ_PERIOD_MODE_START_FROM_CQE = 0x1,
+	DIM_CQ_PERIOD_NUM_MODES
+};
+
+/**
+ * enum dim_state
+ *
+ * These are the DIM algorithm states.
+ * These will determine if the algorithm is in a valid state to start an iteration.
+ *
+ * @DIM_START_MEASURE: This is the first iteration (also after applying a new profile)
+ * @DIM_MEASURE_IN_PROGRESS: Algorithm is already in progress - check if
+ * need to perform an action
+ * @DIM_APPLY_NEW_PROFILE: DIM consumer is currently applying a profile - no need to measure
+ */
+enum {
+	DIM_START_MEASURE,
+	DIM_MEASURE_IN_PROGRESS,
+	DIM_APPLY_NEW_PROFILE,
+};
+
+/**
+ * enum dim_tune_state
+ *
+ * These are the DIM algorithm tune states.
+ * These will determine which action the algorithm should perform.
+ *
+ * @DIM_PARKING_ON_TOP: Algorithm found a local top point - exit on significant difference
+ * @DIM_PARKING_TIRED: Algorithm found a deep top point - don't exit if tired > 0
+ * @DIM_GOING_RIGHT: Algorithm is currently trying higher moderation levels
+ * @DIM_GOING_LEFT: Algorithm is currently trying lower moderation levels
+ */
+enum {
+	DIM_PARKING_ON_TOP,
+	DIM_PARKING_TIRED,
+	DIM_GOING_RIGHT,
+	DIM_GOING_LEFT,
+};
+
+/**
+ * enum dim_stats_state
+ *
+ * These are the DIM algorithm statistics states.
+ * These will determine the verdict of current iteration.
+ *
+ * @DIM_STATS_WORSE: Current iteration shows worse performance than before
+ * @DIM_STATS_WORSE: Current iteration shows same performance than before
+ * @DIM_STATS_WORSE: Current iteration shows better performance than before
+ */
+enum {
+	DIM_STATS_WORSE,
+	DIM_STATS_SAME,
+	DIM_STATS_BETTER,
+};
+
+/**
+ * enum dim_step_result
+ *
+ * These are the DIM algorithm step results.
+ * These describe the result of a step.
+ *
+ * @DIM_STEPPED: Performed a regular step
+ * @DIM_TOO_TIRED: Same kind of step was done multiple times - should go to
+ * tired parking
+ * @DIM_ON_EDGE: Stepped to the most left/right profile
+ */
+enum {
+	DIM_STEPPED,
+	DIM_TOO_TIRED,
+	DIM_ON_EDGE,
+};
+
+/**
+ *	dim_on_top - check if current state is a good place to stop (top location)
+ *	@dim: DIM context
+ *
+ * Check if current profile is a good place to park at.
+ * This will result in reducing the DIM checks frequency as we assume we
+ * shouldn't probably change profiles, unless traffic pattern wasn't changed.
+ */
+bool dim_on_top(struct dim *dim);
+
+/**
+ *	dim_turn - change profile alterning direction
+ *	@dim: DIM context
+ *
+ * Go left if we were going right and vice-versa.
+ * Do nothing if currently parking.
+ */
+void dim_turn(struct dim *dim);
+
+/**
+ *	dim_park_on_top - enter a parking state on a top location
+ *	@dim: DIM context
+ *
+ * Enter parking state.
+ * Clear all movement history.
+ */
+void dim_park_on_top(struct dim *dim);
+
+/**
+ *	dim_park_tired - enter a tired parking state
+ *	@dim: DIM context
+ *
+ * Enter parking state.
+ * Clear all movement history and cause DIM checks frequency to reduce.
+ */
+void dim_park_tired(struct dim *dim);
+
+/**
+ *	dim_calc_stats - calculate the difference between two samples
+ *	@start: start sample
+ *	@end: end sample
+ *	@curr_stats: delta between samples
+ *
+ * Calculate the delta between two samples (in data rates).
+ * Takes into consideration counter wrap-around.
+ */
+void dim_calc_stats(struct dim_sample *start, struct dim_sample *end,
+		    struct dim_stats *curr_stats);
+
+/**
+ *	dim_update_sample - set a sample's fields with give values
+ *	@event_ctr: number of events to set
+ *	@packets: number of packets to set
+ *	@bytes: number of bytes to set
+ *	@s: DIM sample
+ */
+static inline void
+dim_update_sample(u16 event_ctr, u64 packets, u64 bytes, struct dim_sample *s)
+{
+	s->time	     = ktime_get();
+	s->pkt_ctr   = packets;
+	s->byte_ctr  = bytes;
+	s->event_ctr = event_ctr;
+}
+
+/**
+ *	dim_update_sample_with_comps - set a sample's fields with given
+ *	values including the completion parameter
+ *	@event_ctr: number of events to set
+ *	@packets: number of packets to set
+ *	@bytes: number of bytes to set
+ *	@comps: number of completions to set
+ *	@s: DIM sample
+ */
+static inline void
+dim_update_sample_with_comps(u16 event_ctr, u64 packets, u64 bytes, u64 comps,
+			     struct dim_sample *s)
+{
+	dim_update_sample(event_ctr, packets, bytes, s);
+	s->comp_ctr = comps;
+}
+
+/* Net DIM */
+
+/**
+ *	net_dim_get_rx_moderation - provide a CQ moderation object for the given RX profile
+ *	@cq_period_mode: CQ period mode
+ *	@ix: Profile index
+ */
+struct dim_cq_moder net_dim_get_rx_moderation(u8 cq_period_mode, int ix);
+
+/**
+ *	net_dim_get_def_rx_moderation - provide the default RX moderation
+ *	@cq_period_mode: CQ period mode
+ */
+struct dim_cq_moder net_dim_get_def_rx_moderation(u8 cq_period_mode);
+
+/**
+ *	net_dim_get_tx_moderation - provide a CQ moderation object for the given TX profile
+ *	@cq_period_mode: CQ period mode
+ *	@ix: Profile index
+ */
+struct dim_cq_moder net_dim_get_tx_moderation(u8 cq_period_mode, int ix);
+
+/**
+ *	net_dim_get_def_tx_moderation - provide the default TX moderation
+ *	@cq_period_mode: CQ period mode
+ */
+struct dim_cq_moder net_dim_get_def_tx_moderation(u8 cq_period_mode);
+
+/**
+ *	net_dim - main DIM algorithm entry point
+ *	@dim: DIM instance information
+ *	@end_sample: Current data measurement
+ *
+ * Called by the consumer.
+ * This is the main logic of the algorithm, where data is processed in order to decide on next
+ * required action.
+ */
+void net_dim(struct dim *dim, struct dim_sample end_sample);
+
+/* RDMA DIM */
+
+/*
+ * RDMA DIM profile:
+ * profile size must be of RDMA_DIM_PARAMS_NUM_PROFILES.
+ */
+#define RDMA_DIM_PARAMS_NUM_PROFILES 9
+#define RDMA_DIM_START_PROFILE 0
+
+static const struct dim_cq_moder
+rdma_dim_prof[RDMA_DIM_PARAMS_NUM_PROFILES] = {
+	{1,   0, 1,  0},
+	{1,   0, 4,  0},
+	{2,   0, 4,  0},
+	{2,   0, 8,  0},
+	{4,   0, 8,  0},
+	{16,  0, 8,  0},
+	{16,  0, 16, 0},
+	{32,  0, 16, 0},
+	{32,  0, 32, 0},
+};
+
+/**
+ * rdma_dim - Runs the adaptive moderation.
+ * @dim: The moderation struct.
+ * @completions: The number of completions collected in this round.
+ *
+ * Each call to rdma_dim takes the latest amount of completions that
+ * have been collected and counts them as a new event.
+ * Once enough events have been collected the algorithm decides a new
+ * moderation level.
+ */
+void rdma_dim(struct dim *dim, u64 completions);
+
+#endif /* DIM_H */
--- linux-4.4.0.orig/include/linux/dma-attrs.h
+++ linux-4.4.0/include/linux/dma-attrs.h
@@ -18,6 +18,7 @@
 	DMA_ATTR_NO_KERNEL_MAPPING,
 	DMA_ATTR_SKIP_CPU_SYNC,
 	DMA_ATTR_FORCE_CONTIGUOUS,
+	DMA_ATTR_NO_WARN,
 	DMA_ATTR_MAX,
 };
 
--- linux-4.4.0.orig/include/linux/dma-iommu.h
+++ linux-4.4.0/include/linux/dma-iommu.h
@@ -17,6 +17,7 @@
 #define __DMA_IOMMU_H
 
 #ifdef __KERNEL__
+#include <linux/types.h>
 #include <asm/errno.h>
 
 #ifdef CONFIG_IOMMU_DMA
--- linux-4.4.0.orig/include/linux/dma-mapping.h
+++ linux-4.4.0/include/linux/dma-mapping.h
@@ -151,8 +151,7 @@
 	return SZ_64K;
 }
 
-static inline unsigned int dma_set_max_seg_size(struct device *dev,
-						unsigned int size)
+static inline int dma_set_max_seg_size(struct device *dev, unsigned int size)
 {
 	if (dev->dma_parms) {
 		dev->dma_parms->max_segment_size = size;
--- linux-4.4.0.orig/include/linux/dmaengine.h
+++ linux-4.4.0/include/linux/dmaengine.h
@@ -767,6 +767,9 @@
 	sg_dma_address(&sg) = buf;
 	sg_dma_len(&sg) = len;
 
+	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+		return NULL;
+
 	return chan->device->device_prep_slave_sg(chan, &sg, 1,
 						  dir, flags, NULL);
 }
@@ -775,6 +778,9 @@
 	struct dma_chan *chan, struct scatterlist *sgl,	unsigned int sg_len,
 	enum dma_transfer_direction dir, unsigned long flags)
 {
+	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+		return NULL;
+
 	return chan->device->device_prep_slave_sg(chan, sgl, sg_len,
 						  dir, flags, NULL);
 }
@@ -786,6 +792,9 @@
 	enum dma_transfer_direction dir, unsigned long flags,
 	struct rio_dma_ext *rio_ext)
 {
+	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+		return NULL;
+
 	return chan->device->device_prep_slave_sg(chan, sgl, sg_len,
 						  dir, flags, rio_ext);
 }
@@ -796,6 +805,9 @@
 		size_t period_len, enum dma_transfer_direction dir,
 		unsigned long flags)
 {
+	if (!chan || !chan->device || !chan->device->device_prep_dma_cyclic)
+		return NULL;
+
 	return chan->device->device_prep_dma_cyclic(chan, buf_addr, buf_len,
 						period_len, dir, flags);
 }
@@ -804,6 +816,9 @@
 		struct dma_chan *chan, struct dma_interleaved_template *xt,
 		unsigned long flags)
 {
+	if (!chan || !chan->device || !chan->device->device_prep_interleaved_dma)
+		return NULL;
+
 	return chan->device->device_prep_interleaved_dma(chan, xt, flags);
 }
 
@@ -811,7 +826,7 @@
 		struct dma_chan *chan, dma_addr_t dest, int value, size_t len,
 		unsigned long flags)
 {
-	if (!chan || !chan->device)
+	if (!chan || !chan->device || !chan->device->device_prep_dma_memset)
 		return NULL;
 
 	return chan->device->device_prep_dma_memset(chan, dest, value,
@@ -824,6 +839,9 @@
 		struct scatterlist *src_sg, unsigned int src_nents,
 		unsigned long flags)
 {
+	if (!chan || !chan->device || !chan->device->device_prep_dma_sg)
+		return NULL;
+
 	return chan->device->device_prep_dma_sg(chan, dst_sg, dst_nents,
 			src_sg, src_nents, flags);
 }
@@ -1189,8 +1207,11 @@
 static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx)
 {
 	struct dma_slave_caps caps;
+	int ret;
 
-	dma_get_slave_caps(tx->chan, &caps);
+	ret = dma_get_slave_caps(tx->chan, &caps);
+	if (ret)
+		return ret;
 
 	if (caps.descriptor_reuse) {
 		tx->flags |= DMA_CTRL_REUSE;
--- linux-4.4.0.orig/include/linux/edac.h
+++ linux-4.4.0/include/linux/edac.h
@@ -17,6 +17,7 @@
 #include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
+#include <linux/numa.h>
 
 struct device;
 
@@ -237,8 +238,10 @@
 #define MEM_FLAG_FB_DDR2        BIT(MEM_FB_DDR2)
 #define MEM_FLAG_RDDR2          BIT(MEM_RDDR2)
 #define MEM_FLAG_XDR            BIT(MEM_XDR)
-#define MEM_FLAG_DDR3		 BIT(MEM_DDR3)
-#define MEM_FLAG_RDDR3		 BIT(MEM_RDDR3)
+#define MEM_FLAG_DDR3           BIT(MEM_DDR3)
+#define MEM_FLAG_RDDR3          BIT(MEM_RDDR3)
+#define MEM_FLAG_DDR4           BIT(MEM_DDR4)
+#define MEM_FLAG_RDDR4          BIT(MEM_RDDR4)
 
 /**
  * enum edac-type - Error Detection and Correction capabilities and mode
@@ -778,6 +781,6 @@
 /*
  * Maximum number of memory controllers in the coherent fabric.
  */
-#define EDAC_MAX_MCS	16
+#define EDAC_MAX_MCS	2 * MAX_NUMNODES
 
 #endif
--- linux-4.4.0.orig/include/linux/efi.h
+++ linux-4.4.0/include/linux/efi.h
@@ -97,6 +97,7 @@
 #define EFI_MEMORY_WP		((u64)0x0000000000001000ULL)	/* write-protect */
 #define EFI_MEMORY_RP		((u64)0x0000000000002000ULL)	/* read-protect */
 #define EFI_MEMORY_XP		((u64)0x0000000000004000ULL)	/* execute-protect */
+#define EFI_MEMORY_NV		((u64)0x0000000000008000ULL)	/* non-volatile */
 #define EFI_MEMORY_MORE_RELIABLE \
 				((u64)0x0000000000010000ULL)	/* higher reliability */
 #define EFI_MEMORY_RO		((u64)0x0000000000020000ULL)	/* read-only */
@@ -299,7 +300,7 @@
 	void *open_protocol_information;
 	void *protocols_per_handle;
 	void *locate_handle_buffer;
-	void *locate_protocol;
+	efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **);
 	void *install_multiple_protocol_interfaces;
 	void *uninstall_multiple_protocol_interfaces;
 	void *calculate_crc32;
@@ -364,8 +365,8 @@
 	u32 attributes;
 	u32 get_bar_attributes;
 	u32 set_bar_attributes;
-	uint64_t romsize;
-	void *romimage;
+	u64 romsize;
+	u32 romimage;
 } efi_pci_io_protocol_32;
 
 typedef struct {
@@ -384,8 +385,8 @@
 	u64 attributes;
 	u64 get_bar_attributes;
 	u64 set_bar_attributes;
-	uint64_t romsize;
-	void *romimage;
+	u64 romsize;
+	u64 romimage;
 } efi_pci_io_protocol_64;
 
 typedef struct {
@@ -507,10 +508,6 @@
 typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, 
 					 u32 attr, unsigned long data_size,
 					 void *data);
-typedef efi_status_t
-efi_set_variable_nonblocking_t(efi_char16_t *name, efi_guid_t *vendor,
-			       u32 attr, unsigned long data_size, void *data);
-
 typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count);
 typedef void efi_reset_system_t (int reset_type, efi_status_t status,
 				 unsigned long data_size, efi_char16_t *data);
@@ -529,7 +526,9 @@
 					      unsigned long count,
 					      u64 *max_size,
 					      int *reset_type);
-typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long size);
+typedef efi_status_t efi_query_variable_store_t(u32 attributes,
+						unsigned long size,
+						bool nonblocking);
 
 void efi_native_runtime_setup(void);
 
@@ -537,73 +536,110 @@
  *  EFI Configuration Table and GUID definitions
  */
 #define NULL_GUID \
-    EFI_GUID(  0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 )
+	EFI_GUID(0x00000000, 0x0000, 0x0000, \
+		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
 
 #define MPS_TABLE_GUID    \
-    EFI_GUID(  0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+	EFI_GUID(0xeb9d2d2f, 0x2d88, 0x11d3, \
+		 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 
 #define ACPI_TABLE_GUID    \
-    EFI_GUID(  0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+	EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, \
+		 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 
 #define ACPI_20_TABLE_GUID    \
-    EFI_GUID(  0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 )
+	EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, \
+		 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81)
 
 #define SMBIOS_TABLE_GUID    \
-    EFI_GUID(  0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+	EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \
+		 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 
 #define SMBIOS3_TABLE_GUID    \
-    EFI_GUID(  0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 )
+	EFI_GUID(0xf2fd1544, 0x9794, 0x4a2c, \
+		 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94)
 
 #define SAL_SYSTEM_TABLE_GUID    \
-    EFI_GUID(  0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+	EFI_GUID(0xeb9d2d32, 0x2d88, 0x11d3, \
+		 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 
 #define HCDP_TABLE_GUID	\
-    EFI_GUID(  0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 )
+	EFI_GUID(0xf951938d, 0x620b, 0x42ef, \
+		 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98)
 
 #define UGA_IO_PROTOCOL_GUID \
-    EFI_GUID(  0x61a4d49e, 0x6f68, 0x4f1b, 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0xb, 0x7, 0xa2 )
+	EFI_GUID(0x61a4d49e, 0x6f68, 0x4f1b, \
+		 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0x0b, 0x07, 0xa2)
 
 #define EFI_GLOBAL_VARIABLE_GUID \
-    EFI_GUID(  0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c )
+	EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, \
+		 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
 
 #define UV_SYSTEM_TABLE_GUID \
-    EFI_GUID(  0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93 )
+	EFI_GUID(0x3b13a7d4, 0x633e, 0x11dd, \
+		 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93)
 
 #define LINUX_EFI_CRASH_GUID \
-    EFI_GUID(  0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0 )
+	EFI_GUID(0xcfc8fc79, 0xbe2e, 0x4ddc, \
+		 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0)
 
 #define LOADED_IMAGE_PROTOCOL_GUID \
-    EFI_GUID(  0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+	EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \
+		 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
 #define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \
-    EFI_GUID(  0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a )
+	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
+		 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
 
 #define EFI_UGA_PROTOCOL_GUID \
-    EFI_GUID(  0x982c298b, 0xf4fa, 0x41cb, 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 )
+	EFI_GUID(0x982c298b, 0xf4fa, 0x41cb, \
+		 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39)
 
 #define EFI_PCI_IO_PROTOCOL_GUID \
-    EFI_GUID(  0x4cf5b200, 0x68b8, 0x4ca5, 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a )
+	EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5, \
+		 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a)
 
 #define EFI_FILE_INFO_ID \
-    EFI_GUID(  0x9576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+	EFI_GUID(0x9576e92, 0x6d3f, 0x11d2, \
+		 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
 #define EFI_SYSTEM_RESOURCE_TABLE_GUID \
-    EFI_GUID(  0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80 )
+	EFI_GUID(0xb122a263, 0x3661, 0x4f68, \
+		 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80)
 
 #define EFI_FILE_SYSTEM_GUID \
-    EFI_GUID(  0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+	EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \
+		 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
 #define DEVICE_TREE_GUID \
-    EFI_GUID(  0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 )
+	EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \
+		 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
 
 #define EFI_PROPERTIES_TABLE_GUID \
-    EFI_GUID(  0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5 )
+	EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, \
+		 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5)
+
+#define EFI_RNG_PROTOCOL_GUID \
+	EFI_GUID(0x3152bca5, 0xeade, 0x433d, \
+		 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44)
+
+#define EFI_CERT_SHA256_GUID \
+    EFI_GUID(  0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 )
+
+#define EFI_CERT_X509_GUID \
+    EFI_GUID(  0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
 
 typedef struct {
 	efi_guid_t guid;
 	u64 table;
 } efi_config_table_64_t;
 
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
+    EFI_GUID(  0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f )
+
+#define EFI_SHIM_LOCK_GUID \
+    EFI_GUID(  0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 )
+
 typedef struct {
 	efi_guid_t guid;
 	u32 table;
@@ -823,6 +859,20 @@
 
 #define EFI_INVALID_TABLE_ADDR		(~0UL)
 
+typedef struct  {
+	efi_guid_t signature_owner;
+	u8 signature_data[];
+} efi_signature_data_t;
+
+typedef struct {
+	efi_guid_t signature_type;
+	u32 signature_list_size;
+	u32 signature_header_size;
+	u32 signature_size;
+	u8 signature_header[];
+	/* efi_signature_data_t signatures[][] */
+} efi_signature_list_t;
+
 /*
  * All runtime access to EFI goes through this structure:
  */
@@ -851,8 +901,9 @@
 	efi_get_variable_t *get_variable;
 	efi_get_next_variable_t *get_next_variable;
 	efi_set_variable_t *set_variable;
-	efi_set_variable_nonblocking_t *set_variable_nonblocking;
+	efi_set_variable_t *set_variable_nonblocking;
 	efi_query_variable_info_t *query_variable_info;
+	efi_query_variable_info_t *query_variable_info_nonblocking;
 	efi_update_capsule_t *update_capsule;
 	efi_query_capsule_caps_t *query_capsule_caps;
 	efi_get_next_high_mono_count_t *get_next_high_mono_count;
@@ -884,13 +935,17 @@
 #ifdef CONFIG_X86
 extern void efi_late_init(void);
 extern void efi_free_boot_services(void);
-extern efi_status_t efi_query_variable_store(u32 attributes, unsigned long size);
+extern efi_status_t efi_query_variable_store(u32 attributes,
+					     unsigned long size,
+					     bool nonblocking);
 extern void efi_find_mirror(void);
 #else
 static inline void efi_late_init(void) {}
 static inline void efi_free_boot_services(void) {}
 
-static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
+static inline efi_status_t efi_query_variable_store(u32 attributes,
+						    unsigned long size,
+						    bool nonblocking)
 {
 	return EFI_SUCCESS;
 }
@@ -941,6 +996,10 @@
 char * __init efi_md_typeattr_format(char *buf, size_t size,
 				     const efi_memory_desc_t *md);
 
+struct key;
+extern int __init parse_efi_signature_list(const void *data, size_t size,
+					   struct key *keyring);
+
 /**
  * efi_range_is_wc - check the WC bit on an address range
  * @start: starting kvirt address
@@ -980,6 +1039,8 @@
 #define EFI_ARCH_1		7	/* First arch-specific bit */
 #define EFI_DBG			8	/* Print additional debug info at runtime */
 #define EFI_NX_PE_DATA		9	/* Can runtime data regions be mapped non-executable? */
+#define EFI_SECURE_BOOT		10	/* Are we in Secure Boot mode? */
+#define EFI_MOKSBSTATE_DISABLED	11	/* Secure boot mode disabled in the MOK */
 
 #ifdef CONFIG_EFI
 /*
@@ -1091,7 +1152,7 @@
 	efi_get_variable_t *get_variable;
 	efi_get_next_variable_t *get_next_variable;
 	efi_set_variable_t *set_variable;
-	efi_set_variable_nonblocking_t *set_variable_nonblocking;
+	efi_set_variable_t *set_variable_nonblocking;
 	efi_query_variable_store_t *query_variable_store;
 };
 
@@ -1199,7 +1260,10 @@
 struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
 				       struct list_head *head, bool remove);
 
-bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len);
+bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
+		     unsigned long data_size);
+bool efivar_variable_is_removable(efi_guid_t vendor, const char *name,
+				  size_t len);
 
 extern struct work_struct efivar_work;
 void efivar_run_worker(void);
--- linux-4.4.0.orig/include/linux/elevator.h
+++ linux-4.4.0/include/linux/elevator.h
@@ -97,7 +97,7 @@
 	struct module *elevator_owner;
 
 	/* managed by elevator core */
-	char icq_cache_name[ELV_NAME_MAX + 5];	/* elvname + "_io_cq" */
+	char icq_cache_name[ELV_NAME_MAX + 6];	/* elvname + "_io_cq" */
 	struct list_head list;
 };
 
--- linux-4.4.0.orig/include/linux/elfcore.h
+++ linux-4.4.0/include/linux/elfcore.h
@@ -55,6 +55,7 @@
 }
 #endif
 
+#if defined(CONFIG_UM) || defined(CONFIG_IA64)
 /*
  * These functions parameterize elf_core_dump in fs/binfmt_elf.c to write out
  * extra segments containing the gate DSO contents.  Dumping its
@@ -69,5 +70,26 @@
 extern int
 elf_core_write_extra_data(struct coredump_params *cprm);
 extern size_t elf_core_extra_data_size(void);
+#else
+static inline Elf_Half elf_core_extra_phdrs(void)
+{
+	return 0;
+}
+
+static inline int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
+{
+	return 1;
+}
+
+static inline int elf_core_write_extra_data(struct coredump_params *cprm)
+{
+	return 1;
+}
+
+static inline size_t elf_core_extra_data_size(void)
+{
+	return 0;
+}
+#endif
 
 #endif /* _LINUX_ELFCORE_H */
--- linux-4.4.0.orig/include/linux/elfnote.h
+++ linux-4.4.0/include/linux/elfnote.h
@@ -53,7 +53,7 @@
 .popsection				;
 
 #define ELFNOTE(name, type, desc)		\
-	ELFNOTE_START(name, type, "")		\
+	ELFNOTE_START(name, type, "a")		\
 		desc			;	\
 	ELFNOTE_END
 
--- linux-4.4.0.orig/include/linux/etherdevice.h
+++ linux-4.4.0/include/linux/etherdevice.h
@@ -29,6 +29,9 @@
 #include <asm/bitsperlong.h>
 
 #ifdef __KERNEL__
+struct device;
+int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr);
+unsigned char *arch_get_platform_get_mac_address(void);
 u32 eth_get_headlen(void *data, unsigned int max_len);
 __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
 extern const struct header_ops eth_header_ops;
--- linux-4.4.0.orig/include/linux/ethtool.h
+++ linux-4.4.0/include/linux/ethtool.h
@@ -12,6 +12,7 @@
 #ifndef _LINUX_ETHTOOL_H
 #define _LINUX_ETHTOOL_H
 
+#include <linux/bitmap.h>
 #include <linux/compat.h>
 #include <uapi/linux/ethtool.h>
 
@@ -40,9 +41,6 @@
 
 #include <linux/rculist.h>
 
-extern int __ethtool_get_settings(struct net_device *dev,
-				  struct ethtool_cmd *cmd);
-
 /**
  * enum ethtool_phys_id_state - indicator state for physical identification
  * @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated
@@ -97,13 +95,74 @@
 	return index % n_rx_rings;
 }
 
+/* number of link mode bits/ulongs handled internally by kernel */
+#define __ETHTOOL_LINK_MODE_MASK_NBITS			\
+	(__ETHTOOL_LINK_MODE_LAST + 1)
+
+/* declare a link mode bitmap */
+#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name)		\
+	DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS)
+
+/* drivers must ignore base.cmd and base.link_mode_masks_nwords
+ * fields, but they are allowed to overwrite them (will be ignored).
+ */
+struct ethtool_link_ksettings {
+	struct ethtool_link_settings base;
+	struct {
+		__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+		__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
+		__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
+	} link_modes;
+};
+
+/**
+ * ethtool_link_ksettings_zero_link_mode - clear link_ksettings link mode mask
+ *   @ptr : pointer to struct ethtool_link_ksettings
+ *   @name : one of supported/advertising/lp_advertising
+ */
+#define ethtool_link_ksettings_zero_link_mode(ptr, name)		\
+	bitmap_zero((ptr)->link_modes.name, __ETHTOOL_LINK_MODE_MASK_NBITS)
+
+/**
+ * ethtool_link_ksettings_add_link_mode - set bit in link_ksettings
+ * link mode mask
+ *   @ptr : pointer to struct ethtool_link_ksettings
+ *   @name : one of supported/advertising/lp_advertising
+ *   @mode : one of the ETHTOOL_LINK_MODE_*_BIT
+ * (not atomic, no bound checking)
+ */
+#define ethtool_link_ksettings_add_link_mode(ptr, name, mode)		\
+	__set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
+
+/**
+ * ethtool_link_ksettings_test_link_mode - test bit in ksettings link mode mask
+ *   @ptr : pointer to struct ethtool_link_ksettings
+ *   @name : one of supported/advertising/lp_advertising
+ *   @mode : one of the ETHTOOL_LINK_MODE_*_BIT
+ * (not atomic, no bound checking)
+ *
+ * Returns true/false.
+ */
+#define ethtool_link_ksettings_test_link_mode(ptr, name, mode)		\
+	test_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
+
+extern int
+__ethtool_get_link_ksettings(struct net_device *dev,
+			     struct ethtool_link_ksettings *link_ksettings);
+
+/* DEPRECATED, use __ethtool_get_link_ksettings */
+extern int __ethtool_get_settings(struct net_device *dev,
+				  struct ethtool_cmd *cmd);
+
 /**
  * struct ethtool_ops - optional netdev operations
- * @get_settings: Get various device settings including Ethernet link
+ * @get_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings
+ *	API. Get various device settings including Ethernet link
  *	settings. The @cmd parameter is expected to have been cleared
- *	before get_settings is called. Returns a negative error code or
- *	zero.
- * @set_settings: Set various device settings including Ethernet link
+ *	before get_settings is called. Returns a negative error code
+ *	or zero.
+ * @set_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings
+ *	API. Set various device settings including Ethernet link
  *	settings.  Returns a negative error code or zero.
  * @get_drvinfo: Report driver/device information.  Should only set the
  *	@driver, @version, @fw_version and @bus_info fields.  If not
@@ -201,6 +260,19 @@
  * @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.
+ * @get_link_ksettings: When defined, takes precedence over the
+ *	%get_settings method. Get various device settings
+ *	including Ethernet link settings. The %cmd and
+ *	%link_mode_masks_nwords fields should be ignored (use
+ *	%__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter), any
+ *	change to them will be overwritten by kernel. Returns a
+ *	negative error code or zero.
+ * @set_link_ksettings: When defined, takes precedence over the
+ *	%set_settings method. Set various device settings including
+ *	Ethernet link settings. The %cmd and %link_mode_masks_nwords
+ *	fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS
+ *	instead of the latter), any change to them will be overwritten
+ *	by kernel. Returns a negative error code or zero.
  *
  * All operations are optional (i.e. the function pointer may be set
  * to %NULL) and callers must take this into account.  Callers must
@@ -279,7 +351,9 @@
 			       const struct ethtool_tunable *, void *);
 	int	(*set_tunable)(struct net_device *,
 			       const struct ethtool_tunable *, const void *);
-
-
+	int	(*get_link_ksettings)(struct net_device *,
+				      struct ethtool_link_ksettings *);
+	int	(*set_link_ksettings)(struct net_device *,
+				      const struct ethtool_link_ksettings *);
 };
 #endif /* _LINUX_ETHTOOL_H */
--- linux-4.4.0.orig/include/linux/f2fs_fs.h
+++ linux-4.4.0/include/linux/f2fs_fs.h
@@ -99,6 +99,7 @@
 /*
  * For checkpoint
  */
+#define CP_CRC_RECOVERY_FLAG	0x00000040
 #define CP_FASTBOOT_FLAG	0x00000020
 #define CP_FSCK_FLAG		0x00000010
 #define CP_ERROR_FLAG		0x00000008
@@ -284,6 +285,12 @@
 #define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry))
 
 /*
+ * F2FS uses 4 bytes to represent block address. As a result, supported size of
+ * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments.
+ */
+#define F2FS_MAX_SEGMENT       ((16 * 1024 * 1024) / 2)
+
+/*
  * Note that f2fs_sit_entry->vblocks has the following bit-field information.
  * [15:10] : allocation type such as CURSEG_XXXX_TYPE
  * [9:0] : valid block count
@@ -491,4 +498,6 @@
 	F2FS_FT_MAX
 };
 
+#define S_SHIFT 12
+
 #endif  /* _LINUX_F2FS_FS_H */
--- linux-4.4.0.orig/include/linux/fb.h
+++ linux-4.4.0/include/linux/fb.h
@@ -716,8 +716,6 @@
 extern const unsigned char *fb_firmware_edid(struct device *device);
 extern void fb_edid_to_monspecs(unsigned char *edid,
 				struct fb_monspecs *specs);
-extern void fb_edid_add_monspecs(unsigned char *edid,
-				 struct fb_monspecs *specs);
 extern void fb_destroy_modedb(struct fb_videomode *modedb);
 extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb);
 extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter);
@@ -791,7 +789,6 @@
 
 extern const char *fb_mode_option;
 extern const struct fb_videomode vesa_modes[];
-extern const struct fb_videomode cea_modes[65];
 extern const struct dmt_videomode dmt_modes[];
 
 struct fb_modelist {
--- linux-4.4.0.orig/include/linux/fcntl.h
+++ linux-4.4.0/include/linux/fcntl.h
@@ -3,6 +3,12 @@
 
 #include <uapi/linux/fcntl.h>
 
+/* list of all valid flags for the open/openat flags argument: */
+#define VALID_OPEN_FLAGS \
+	(O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \
+	 O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \
+	 FASYNC	| O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
+	 O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE)
 
 #ifndef force_o_largefile
 #define force_o_largefile() (BITS_PER_LONG != 32)
--- linux-4.4.0.orig/include/linux/fdtable.h
+++ linux-4.4.0/include/linux/fdtable.h
@@ -9,6 +9,7 @@
 #include <linux/compiler.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/nospec.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/fs.h>
@@ -81,8 +82,10 @@
 {
 	struct fdtable *fdt = rcu_dereference_raw(files->fdt);
 
-	if (fd < fdt->max_fds)
+	if (fd < fdt->max_fds) {
+		fd = array_index_nospec(fd, fdt->max_fds);
 		return rcu_dereference_raw(fdt->fd[fd]);
+	}
 	return NULL;
 }
 
--- linux-4.4.0.orig/include/linux/file.h
+++ linux-4.4.0/include/linux/file.h
@@ -12,6 +12,7 @@
 struct file;
 
 extern void fput(struct file *);
+extern void fput_many(struct file *, unsigned int);
 
 struct file_operations;
 struct vfsmount;
@@ -19,6 +20,7 @@
 struct path;
 extern struct file *alloc_file(struct path *, fmode_t mode,
 	const struct file_operations *fop);
+extern struct file *get_empty_filp(void);
 
 static inline void fput_light(struct file *file, int fput_needed)
 {
@@ -40,6 +42,7 @@
 }
 
 extern struct file *fget(unsigned int fd);
+extern struct file *fget_many(unsigned int fd, unsigned int refs);
 extern struct file *fget_raw(unsigned int fd);
 extern unsigned long __fdget(unsigned int fd);
 extern unsigned long __fdget_raw(unsigned int fd);
--- linux-4.4.0.orig/include/linux/filter.h
+++ linux-4.4.0/include/linux/filter.h
@@ -13,6 +13,8 @@
 #include <linux/printk.h>
 #include <linux/workqueue.h>
 #include <linux/sched.h>
+#include <linux/capability.h>
+
 #include <net/sch_generic.h>
 
 #include <asm/cacheflush.h>
@@ -42,6 +44,15 @@
 #define BPF_REG_X	BPF_REG_7
 #define BPF_REG_TMP	BPF_REG_8
 
+/* Kernel hidden auxiliary/helper register for hardening step.
+ * Only used by eBPF JITs. It's nothing more than a temporary
+ * register that JITs use internally, only that here it's part
+ * of eBPF instructions that have been rewritten for blinding
+ * constants. See JIT pre-step in bpf_jit_blind_constants().
+ */
+#define BPF_REG_AX		MAX_BPF_REG
+#define MAX_BPF_JIT_REG		(MAX_BPF_REG + 1)
+
 /* BPF program can access up to 512 bytes of stack space. */
 #define MAX_BPF_STACK	512
 
@@ -421,9 +432,13 @@
 }
 #endif /* CONFIG_DEBUG_SET_MODULE_RONX */
 
-int sk_filter(struct sock *sk, struct sk_buff *skb);
+int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap);
+static inline int sk_filter(struct sock *sk, struct sk_buff *skb)
+{
+	return sk_filter_trim_cap(sk, skb, 1);
+}
 
-int bpf_prog_select_runtime(struct bpf_prog *fp);
+struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err);
 void bpf_prog_free(struct bpf_prog *fp);
 
 struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags);
@@ -446,8 +461,12 @@
 void bpf_prog_destroy(struct bpf_prog *fp);
 
 int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
+		       bool locked);
 int sk_attach_bpf(u32 ufd, struct sock *sk);
 int sk_detach_filter(struct sock *sk);
+int __sk_detach_filter(struct sock *sk, bool locked);
+
 int sk_get_filter(struct sock *sk, struct sock_filter __user *filter,
 		  unsigned int len);
 
@@ -455,10 +474,16 @@
 void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp);
 
 u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
-void bpf_int_jit_compile(struct bpf_prog *fp);
+
+struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog);
 bool bpf_helper_changes_skb_data(void *func);
 
+struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
+				       const struct bpf_insn *patch, u32 len);
+
 #ifdef CONFIG_BPF_JIT
+extern int bpf_jit_harden;
+
 typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
 
 struct bpf_binary_header *
@@ -470,6 +495,9 @@
 void bpf_jit_compile(struct bpf_prog *fp);
 void bpf_jit_free(struct bpf_prog *fp);
 
+struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *fp);
+void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other);
+
 static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
 				u32 pass, void *image)
 {
@@ -480,6 +508,43 @@
 		print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_OFFSET,
 			       16, 1, image, proglen, false);
 }
+
+static inline bool bpf_jit_is_ebpf(void)
+{
+# ifdef CONFIG_HAVE_EBPF_JIT
+	return true;
+# else
+	return false;
+# endif
+}
+
+static inline bool bpf_jit_blinding_enabled(void)
+{
+	/* These are the prerequisites, should someone ever have the
+	 * idea to call blinding outside of them, we make sure to
+	 * bail out.
+	 */
+	if (!bpf_jit_is_ebpf())
+		return false;
+	if (!bpf_jit_enable)
+		return false;
+	if (!bpf_jit_harden)
+		return false;
+	if (bpf_jit_harden == 1 && capable(CAP_SYS_ADMIN))
+		return false;
+
+	return true;
+}
+static inline bool bpf_jit_fence_present(void)
+{
+	/* Check if lfence is present on CPU
+	 */
+#ifdef CONFIG_X86
+	if (boot_cpu_has(X86_FEATURE_LFENCE_RDTSC))
+		return true;
+#endif
+	return false;
+}
 #else
 static inline void bpf_jit_compile(struct bpf_prog *fp)
 {
--- linux-4.4.0.orig/include/linux/font.h
+++ linux-4.4.0/include/linux/font.h
@@ -32,6 +32,7 @@
 #define ACORN8x8_IDX	8
 #define	MINI4x6_IDX	9
 #define FONT6x10_IDX	10
+#define TER16x32_IDX	11
 
 extern const struct font_desc	font_vga_8x8,
 			font_vga_8x16,
@@ -43,7 +44,8 @@
 			font_sun_12x22,
 			font_acorn_8x8,
 			font_mini_4x6,
-			font_6x10;
+			font_6x10,
+			font_ter_16x32;
 
 /* Find a font with a specific name */
 
@@ -57,4 +59,17 @@
 /* Max. length for the name of a predefined font */
 #define MAX_FONT_NAME	32
 
+/* Extra word getters */
+#define REFCOUNT(fd)	(((int *)(fd))[-1])
+#define FNTSIZE(fd)	(((int *)(fd))[-2])
+#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
+#define FNTSUM(fd)	(((int *)(fd))[-4])
+
+#define FONT_EXTRA_WORDS 4
+
+struct font_data {
+	unsigned int extra[FONT_EXTRA_WORDS];
+	const unsigned char data[];
+} __packed;
+
 #endif /* _VIDEO_FONT_H */
--- linux-4.4.0.orig/include/linux/fs.h
+++ linux-4.4.0/include/linux/fs.h
@@ -65,6 +65,8 @@
 extern int leases_enable, lease_break_time;
 extern int sysctl_protected_symlinks;
 extern int sysctl_protected_hardlinks;
+extern int sysctl_protected_fifos;
+extern int sysctl_protected_regular;
 
 struct buffer_head;
 typedef int (get_block_t)(struct inode *inode, sector_t iblock,
@@ -138,6 +140,9 @@
 /* Has write method(s) */
 #define FMODE_CAN_WRITE         ((__force fmode_t)0x40000)
 
+/* File is stream-like */
+#define FMODE_STREAM		((__force fmode_t)0x200000)
+
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY		((__force fmode_t)0x4000000)
 
@@ -226,6 +231,7 @@
 #define ATTR_KILL_PRIV	(1 << 14)
 #define ATTR_OPEN	(1 << 15) /* Truncating from open(O_TRUNC) */
 #define ATTR_TIMES_SET	(1 << 16)
+#define ATTR_TOUCH	(1 << 17)
 
 /*
  * Whiteout is represented by a char device.  The following constants define the
@@ -469,6 +475,7 @@
 	int			bd_invalidated;
 	struct gendisk *	bd_disk;
 	struct request_queue *  bd_queue;
+	struct backing_dev_info *bd_bdi;
 	struct list_head	bd_list;
 	/*
 	 * Private data.  You must have bd_claim'ed the block_device
@@ -652,6 +659,7 @@
 		struct rcu_head		i_rcu;
 	};
 	u64			i_version;
+	atomic64_t		i_sequence; /* see futex */
 	atomic_t		i_count;
 	atomic_t		i_dio_count;
 	atomic_t		i_writecount;
@@ -679,6 +687,11 @@
 	void			*i_private; /* fs or device private pointer */
 };
 
+static inline unsigned int i_blocksize(const struct inode *node)
+{
+	return (1 << node->i_blkbits);
+}
+
 static inline int inode_unhashed(struct inode *inode)
 {
 	return hlist_unhashed(&inode->i_hash);
@@ -710,6 +723,31 @@
 	I_MUTEX_PARENT2,
 };
 
+static inline void inode_lock(struct inode *inode)
+{
+	mutex_lock(&inode->i_mutex);
+}
+
+static inline void inode_unlock(struct inode *inode)
+{
+	mutex_unlock(&inode->i_mutex);
+}
+
+static inline int inode_trylock(struct inode *inode)
+{
+	return mutex_trylock(&inode->i_mutex);
+}
+
+static inline int inode_is_locked(struct inode *inode)
+{
+	return mutex_is_locked(&inode->i_mutex);
+}
+
+static inline void inode_lock_nested(struct inode *inode, unsigned subclass)
+{
+	mutex_lock_nested(&inode->i_mutex, subclass);
+}
+
 void lock_two_nondirectories(struct inode *, struct inode*);
 void unlock_two_nondirectories(struct inode *, struct inode*);
 
@@ -768,31 +806,6 @@
 #endif
 }
 
-/* Helper functions so that in most cases filesystems will
- * not need to deal directly with kuid_t and kgid_t and can
- * instead deal with the raw numeric values that are stored
- * in the filesystem.
- */
-static inline uid_t i_uid_read(const struct inode *inode)
-{
-	return from_kuid(&init_user_ns, inode->i_uid);
-}
-
-static inline gid_t i_gid_read(const struct inode *inode)
-{
-	return from_kgid(&init_user_ns, inode->i_gid);
-}
-
-static inline void i_uid_write(struct inode *inode, uid_t uid)
-{
-	inode->i_uid = make_kuid(&init_user_ns, uid);
-}
-
-static inline void i_gid_write(struct inode *inode, gid_t gid)
-{
-	inode->i_gid = make_kgid(&init_user_ns, gid);
-}
-
 static inline unsigned iminor(const struct inode *inode)
 {
 	return MINOR(inode->i_rdev);
@@ -878,7 +891,7 @@
 	__u32 handle_bytes;
 	int handle_type;
 	/* file identifier */
-	unsigned char f_handle[0];
+	unsigned char f_handle[];
 };
 
 static inline struct file *get_file(struct file *f)
@@ -886,7 +899,9 @@
 	atomic_long_inc(&f->f_count);
 	return f;
 }
-#define get_file_rcu(x) atomic_long_inc_not_zero(&(x)->f_count)
+#define get_file_rcu_many(x, cnt)	\
+	atomic_long_add_unless(&(x)->f_count, (cnt), 0)
+#define get_file_rcu(x) get_file_rcu_many((x), 1)
 #define fput_atomic(x)	atomic_long_add_unless(&(x)->f_count, -1, 1)
 #define file_count(x)	atomic_long_read(&(x)->f_count)
 
@@ -895,9 +910,9 @@
 /* Page cache limit. The filesystems should put that into their s_maxbytes 
    limits, otherwise bad things can happen in VM. */ 
 #if BITS_PER_LONG==32
-#define MAX_LFS_FILESIZE	(((loff_t)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) 
+#define MAX_LFS_FILESIZE	((loff_t)ULONG_MAX << PAGE_SHIFT)
 #elif BITS_PER_LONG==64
-#define MAX_LFS_FILESIZE 	((loff_t)0x7fffffffffffffffLL)
+#define MAX_LFS_FILESIZE 	((loff_t)LLONG_MAX)
 #endif
 
 #define FL_POSIX	1
@@ -1207,6 +1222,16 @@
 	return f->f_inode;
 }
 
+static inline struct dentry *file_dentry(const struct file *file)
+{
+	struct dentry *dentry = file->f_path.dentry;
+
+	if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
+		return dentry->d_op->d_real(dentry, file_inode(file));
+	else
+		return dentry;
+}
+
 static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
 {
 	return locks_lock_inode_wait(file_inode(filp), fl);
@@ -1254,6 +1279,8 @@
 /* sb->s_iflags */
 #define SB_I_CGROUPWB	0x00000001	/* cgroup-aware writeback enabled */
 #define SB_I_NOEXEC	0x00000002	/* Ignore executables on this fs */
+#define SB_I_NOSUID	0x00000004	/* Ignore suid on this fs */
+#define SB_I_MULTIROOT	0x00000008	/* Multiple roots to the dentry tree */
 
 /* Possible states of 'frozen' field */
 enum {
@@ -1355,6 +1382,13 @@
 	struct hlist_head s_pins;
 
 	/*
+	 * Context in which to interpret filesystem uids, gids,
+	 * quotas, device nodes, extended attributes and security
+	 * labels.
+	 */
+	struct user_namespace *s_user_ns;
+
+	/*
 	 * Keep the lru lists last in the structure so they always sit on their
 	 * own individual cachelines.
 	 */
@@ -1375,6 +1409,31 @@
 	struct list_head	s_inodes;	/* all inodes */
 };
 
+/* Helper functions so that in most cases filesystems will
+ * not need to deal directly with kuid_t and kgid_t and can
+ * instead deal with the raw numeric values that are stored
+ * in the filesystem.
+ */
+static inline uid_t i_uid_read(const struct inode *inode)
+{
+	return from_kuid_munged(inode->i_sb->s_user_ns, inode->i_uid);
+}
+
+static inline gid_t i_gid_read(const struct inode *inode)
+{
+	return from_kgid_munged(inode->i_sb->s_user_ns, inode->i_gid);
+}
+
+static inline void i_uid_write(struct inode *inode, uid_t uid)
+{
+	inode->i_uid = make_kuid(inode->i_sb->s_user_ns, uid);
+}
+
+static inline void i_gid_write(struct inode *inode, gid_t gid)
+{
+	inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid);
+}
+
 extern struct timespec current_fs_time(struct super_block *sb);
 
 /*
@@ -1672,6 +1731,12 @@
 			      struct iovec *fast_pointer,
 			      struct iovec **ret_pointer);
 
+typedef ssize_t (*vfs_readf_t)(struct file *, char __user *, size_t, loff_t *);
+typedef ssize_t (*vfs_writef_t)(struct file *, const char __user *, size_t,
+				loff_t *);
+vfs_readf_t vfs_readf(struct file *file);
+vfs_writef_t vfs_writef(struct file *file);
+
 extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *);
 extern ssize_t __vfs_write(struct file *, const char __user *, size_t, loff_t *);
 extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
@@ -1713,6 +1778,10 @@
 				  struct shrink_control *);
 	long (*free_cached_objects)(struct super_block *,
 				    struct shrink_control *);
+#if defined(CONFIG_BLK_DEV_LOOP) ||  defined(CONFIG_BLK_DEV_LOOP_MODULE)
+	/* and aufs */
+	struct file *(*real_loop)(struct file *);
+#endif
 };
 
 /*
@@ -1778,6 +1847,11 @@
 #define IS_WHITEOUT(inode)	(S_ISCHR(inode->i_mode) && \
 				 (inode)->i_rdev == WHITEOUT_DEV)
 
+static inline bool HAS_UNMAPPED_ID(struct inode *inode)
+{
+	return !uid_valid(inode->i_uid) || !gid_valid(inode->i_gid);
+}
+
 /*
  * Inode state bits.  Protected by inode->i_lock
  *
@@ -1834,6 +1908,10 @@
  *			wb stat updates to grab mapping->tree_lock.  See
  *			inode_switch_wb_work_fn() for details.
  *
+ * I_SYNC_QUEUED	Inode is queued in b_io or b_more_io writeback lists.
+ *			Used to detect that mark_inode_dirty() should not move
+ * 			inode between dirty lists.
+ *
  * Q: What is the difference between I_WILL_FREE and I_FREEING?
  */
 #define I_DIRTY_SYNC		(1 << 0)
@@ -1851,9 +1929,9 @@
 #define I_DIO_WAKEUP		(1 << __I_DIO_WAKEUP)
 #define I_LINKABLE		(1 << 10)
 #define I_DIRTY_TIME		(1 << 11)
-#define __I_DIRTY_TIME_EXPIRED	12
-#define I_DIRTY_TIME_EXPIRED	(1 << __I_DIRTY_TIME_EXPIRED)
+#define I_DIRTY_TIME_EXPIRED	(1 << 12)
 #define I_WB_SWITCH		(1 << 13)
+#define I_SYNC_QUEUED		(1 << 17)
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
 #define I_DIRTY_ALL (I_DIRTY | I_DIRTY_TIME)
@@ -1948,8 +2026,9 @@
 
 #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME)
 
-extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags,
-	void *data, int (*fill_super)(struct super_block *, void *, int));
+extern struct dentry *mount_ns(struct file_system_type *fs_type,
+	int flags, void *data, void *ns, struct user_namespace *user_ns,
+	int (*fill_super)(struct super_block *, void *, int));
 extern struct dentry *mount_bdev(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data,
 	int (*fill_super)(struct super_block *, void *, int));
@@ -1969,6 +2048,11 @@
 int set_anon_super(struct super_block *s, void *data);
 int get_anon_bdev(dev_t *);
 void free_anon_bdev(dev_t);
+struct super_block *sget_userns(struct file_system_type *type,
+			int (*test)(struct super_block *,void *),
+			int (*set)(struct super_block *,void *),
+			int flags, struct user_namespace *user_ns,
+			void *data);
 struct super_block *sget(struct file_system_type *type,
 			int (*test)(struct super_block *,void *),
 			int (*set)(struct super_block *,void *),
@@ -2217,7 +2301,7 @@
 extern struct file *file_open_name(struct filename *, int, umode_t);
 extern struct file *filp_open(const char *, int, umode_t);
 extern struct file *file_open_root(struct dentry *, struct vfsmount *,
-				   const char *, int);
+				   const char *, int, umode_t);
 extern struct file * dentry_open(const struct path *, int, const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
 
@@ -2251,6 +2335,7 @@
 #ifdef CONFIG_BLOCK
 extern int register_blkdev(unsigned int, const char *);
 extern void unregister_blkdev(unsigned int, const char *);
+extern void bdev_unhash_inode(dev_t dev);
 extern struct block_device *bdget(dev_t);
 extern struct block_device *bdgrab(struct block_device *bdev);
 extern void bd_set_size(struct block_device *, loff_t size);
@@ -2360,7 +2445,7 @@
 #define BLKDEV_MAJOR_HASH_SIZE	255
 extern const char *__bdevname(dev_t, char *buffer);
 extern const char *bdevname(struct block_device *bdev, char *buffer);
-extern struct block_device *lookup_bdev(const char *);
+extern struct block_device *lookup_bdev(const char *, int mask);
 extern void blkdev_show(struct seq_file *,off_t);
 
 #else
@@ -2662,6 +2747,7 @@
 		int whence, loff_t size);
 extern int generic_file_open(struct inode * inode, struct file * filp);
 extern int nonseekable_open(struct inode * inode, struct file * filp);
+extern int stream_open(struct inode * inode, struct file * filp);
 
 #ifdef CONFIG_BLOCK
 typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode,
@@ -2841,7 +2927,7 @@
 #define buffer_migrate_page NULL
 #endif
 
-extern int inode_change_ok(const struct inode *, struct iattr *);
+extern int setattr_prepare(struct dentry *, struct iattr *);
 extern int inode_newsize_ok(const struct inode *, loff_t offset);
 extern void setattr_copy(struct inode *inode, const struct iattr *attr);
 
@@ -3019,11 +3105,13 @@
 }
 static inline bool dir_relax(struct inode *inode)
 {
-	mutex_unlock(&inode->i_mutex);
-	mutex_lock(&inode->i_mutex);
+	inode_unlock(inode);
+	inode_lock(inode);
 	return !IS_DEADDIR(inode);
 }
 
 extern bool path_noexec(const struct path *path);
+extern bool path_nosuid(const struct path *path);
+extern void inode_nohighmem(struct inode *inode);
 
 #endif /* _LINUX_FS_H */
--- linux-4.4.0.orig/include/linux/fscache-cache.h
+++ linux-4.4.0/include/linux/fscache-cache.h
@@ -183,8 +183,7 @@
 static inline void fscache_retrieval_complete(struct fscache_retrieval *op,
 					      int n_pages)
 {
-	atomic_sub(n_pages, &op->n_pages);
-	if (atomic_read(&op->n_pages) <= 0)
+	if (atomic_sub_return(n_pages, &op->n_pages) <= 0)
 		fscache_op_complete(&op->op, true);
 }
 
@@ -360,6 +359,7 @@
 #define FSCACHE_OBJECT_IS_AVAILABLE	5	/* T if object has become active */
 #define FSCACHE_OBJECT_RETIRED		6	/* T if object was retired on relinquishment */
 #define FSCACHE_OBJECT_KILLED_BY_CACHE	7	/* T if object was killed by the cache */
+#define FSCACHE_OBJECT_RUN_AFTER_DEAD	8	/* T if object has been dispatched after death */
 
 	struct list_head	cache_link;	/* link in cache->object_list */
 	struct hlist_node	cookie_link;	/* link in cookie->backing_objects */
--- linux-4.4.0.orig/include/linux/fscache.h
+++ linux-4.4.0/include/linux/fscache.h
@@ -764,7 +764,7 @@
 {
 	if (fscache_cookie_valid(cookie) && PageFsCache(page))
 		return __fscache_maybe_release_page(cookie, page, gfp);
-	return false;
+	return true;
 }
 
 /**
--- linux-4.4.0.orig/include/linux/fsl/guts.h
+++ linux-4.4.0/include/linux/fsl/guts.h
@@ -16,6 +16,7 @@
 #define __FSL_GUTS_H__
 
 #include <linux/types.h>
+#include <linux/io.h>
 
 /**
  * Global Utility Registers.
--- linux-4.4.0.orig/include/linux/fsnotify.h
+++ linux-4.4.0/include/linux/fsnotify.h
@@ -310,35 +310,4 @@
 	}
 }
 
-#if defined(CONFIG_FSNOTIFY)	/* notify helpers */
-
-/*
- * fsnotify_oldname_init - save off the old filename before we change it
- */
-static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name)
-{
-	return kstrdup(name, GFP_KERNEL);
-}
-
-/*
- * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
- */
-static inline void fsnotify_oldname_free(const unsigned char *old_name)
-{
-	kfree(old_name);
-}
-
-#else	/* CONFIG_FSNOTIFY */
-
-static inline const char *fsnotify_oldname_init(const unsigned char *name)
-{
-	return NULL;
-}
-
-static inline void fsnotify_oldname_free(const unsigned char *old_name)
-{
-}
-
-#endif	/*  CONFIG_FSNOTIFY */
-
 #endif	/* _LINUX_FS_NOTIFY_H */
--- linux-4.4.0.orig/include/linux/fsnotify_backend.h
+++ linux-4.4.0/include/linux/fsnotify_backend.h
@@ -148,6 +148,7 @@
 	#define FS_PRIO_1	1 /* fanotify content based access control */
 	#define FS_PRIO_2	2 /* fanotify pre-content access */
 	unsigned int priority;
+	bool shutdown;		/* group is being shut down, don't queue more events */
 
 	/* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
 	struct mutex mark_mutex;	/* protect marks_list */
@@ -179,7 +180,6 @@
 			spinlock_t access_lock;
 			struct list_head access_list;
 			wait_queue_head_t access_waitq;
-			atomic_t bypass_perm;
 #endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
 			int f_flags;
 			unsigned int max_marks;
@@ -308,6 +308,8 @@
 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);
+/* group destruction begins, stop queuing new events */
+extern void fsnotify_group_stop_queueing(struct fsnotify_group *group);
 /* destroy group */
 extern void fsnotify_destroy_group(struct fsnotify_group *group);
 /* fasync handler function */
@@ -320,8 +322,6 @@
 			      struct fsnotify_event *event,
 			      int (*merge)(struct list_head *,
 					   struct fsnotify_event *));
-/* Remove passed event from groups notification queue */
-extern void fsnotify_remove_event(struct fsnotify_group *group, struct fsnotify_event *event);
 /* true if the group notification queue is empty */
 extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
 /* return, but do not dequeue the first event on the notification queue */
--- linux-4.4.0.orig/include/linux/ftrace.h
+++ linux-4.4.0/include/linux/ftrace.h
@@ -747,7 +747,9 @@
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 /* for init task */
-#define INIT_FTRACE_GRAPH		.ret_stack = NULL,
+#define INIT_FTRACE_GRAPH				\
+	.ret_stack		= NULL,			\
+	.tracing_graph_pause	= ATOMIC_INIT(0),
 
 /*
  * Stack of return addresses for functions
--- linux-4.4.0.orig/include/linux/futex.h
+++ linux-4.4.0/include/linux/futex.h
@@ -1,6 +1,8 @@
 #ifndef _LINUX_FUTEX_H
 #define _LINUX_FUTEX_H
 
+#include <linux/sched.h>
+
 #include <uapi/linux/futex.h>
 
 struct inode;
@@ -11,9 +13,6 @@
 long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
 	      u32 __user *uaddr2, u32 val2, u32 val3);
 
-extern int
-handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi);
-
 /*
  * Futexes are matched on equal values of this key.
  * The key type depends on whether it's a shared or private mapping.
@@ -34,38 +33,56 @@
 
 union futex_key {
 	struct {
+		u64 i_seq;
 		unsigned long pgoff;
-		struct inode *inode;
-		int offset;
+		unsigned int offset;
 	} shared;
 	struct {
+		union {
+			struct mm_struct *mm;
+			u64 __tmp;
+		};
 		unsigned long address;
-		struct mm_struct *mm;
-		int offset;
+		unsigned int offset;
 	} private;
 	struct {
+		u64 ptr;
 		unsigned long word;
-		void *ptr;
-		int offset;
+		unsigned int offset;
 	} both;
 };
 
-#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } }
+#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = 0ULL } }
 
 #ifdef CONFIG_FUTEX
-extern void exit_robust_list(struct task_struct *curr);
-extern void exit_pi_state_list(struct task_struct *curr);
-#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
-#define futex_cmpxchg_enabled 1
-#else
-extern int futex_cmpxchg_enabled;
-#endif
-#else
-static inline void exit_robust_list(struct task_struct *curr)
-{
-}
-static inline void exit_pi_state_list(struct task_struct *curr)
+enum {
+	FUTEX_STATE_OK,
+	FUTEX_STATE_EXITING,
+	FUTEX_STATE_DEAD,
+};
+
+static inline void futex_init_task(struct task_struct *tsk)
 {
+	tsk->robust_list = NULL;
+#ifdef CONFIG_COMPAT
+	tsk->compat_robust_list = NULL;
+#endif
+	INIT_LIST_HEAD(&tsk->pi_state_list);
+	tsk->pi_state_cache = NULL;
+	tsk->futex_state = FUTEX_STATE_OK;
+	mutex_init(&tsk->futex_exit_mutex);
 }
+
+void futex_exit_recursive(struct task_struct *tsk);
+void futex_exit_release(struct task_struct *tsk);
+void futex_exec_release(struct task_struct *tsk);
+
+long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
+	      u32 __user *uaddr2, u32 val2, u32 val3);
+#else
+static inline void futex_init_task(struct task_struct *tsk) { }
+static inline void futex_exit_recursive(struct task_struct *tsk) { }
+static inline void futex_exit_release(struct task_struct *tsk) { }
+static inline void futex_exec_release(struct task_struct *tsk) { }
 #endif
 #endif
--- linux-4.4.0.orig/include/linux/genalloc.h
+++ linux-4.4.0/include/linux/genalloc.h
@@ -31,6 +31,7 @@
 #define __GENALLOC_H__
 
 #include <linux/spinlock_types.h>
+#include <linux/atomic.h>
 
 struct device;
 struct device_node;
@@ -68,7 +69,7 @@
  */
 struct gen_pool_chunk {
 	struct list_head next_chunk;	/* next chunk in pool */
-	atomic_t avail;
+	atomic_long_t avail;
 	phys_addr_t phys_addr;		/* physical starting address of memory chunk */
 	unsigned long start_addr;	/* start address of memory chunk */
 	unsigned long end_addr;		/* end address of memory chunk (inclusive) */
--- linux-4.4.0.orig/include/linux/genhd.h
+++ linux-4.4.0/include/linux/genhd.h
@@ -727,9 +727,11 @@
 static inline void part_nr_sects_write(struct hd_struct *part, sector_t size)
 {
 #if BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_SMP)
+	preempt_disable();
 	write_seqcount_begin(&part->nr_sects_seq);
 	part->nr_sects = size;
 	write_seqcount_end(&part->nr_sects_seq);
+	preempt_enable();
 #elif BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_PREEMPT)
 	preempt_disable();
 	part->nr_sects = size;
@@ -742,11 +744,9 @@
 #if defined(CONFIG_BLK_DEV_INTEGRITY)
 extern void blk_integrity_add(struct gendisk *);
 extern void blk_integrity_del(struct gendisk *);
-extern void blk_integrity_revalidate(struct gendisk *);
 #else	/* CONFIG_BLK_DEV_INTEGRITY */
 static inline void blk_integrity_add(struct gendisk *disk) { }
 static inline void blk_integrity_del(struct gendisk *disk) { }
-static inline void blk_integrity_revalidate(struct gendisk *disk) { }
 #endif	/* CONFIG_BLK_DEV_INTEGRITY */
 
 #else /* CONFIG_BLOCK */
--- linux-4.4.0.orig/include/linux/genl_magic_struct.h
+++ linux-4.4.0/include/linux/genl_magic_struct.h
@@ -185,6 +185,7 @@
 {
 	switch (0) {
 #include GENL_MAGIC_INCLUDE_FILE
+	case 0:
 		;
 	}
 }
@@ -203,6 +204,7 @@
 {
 	switch (0) {
 #include GENL_MAGIC_INCLUDE_FILE
+	case 0:
 		;
 	}
 }
@@ -212,7 +214,8 @@
 static inline void ct_assert_unique_ ## s_name ## _attributes(void)	\
 {									\
 	switch (0) {							\
-		s_fields						\
+	s_fields							\
+	case 0:								\
 			;						\
 	}								\
 }
--- linux-4.4.0.orig/include/linux/gfp.h
+++ linux-4.4.0/include/linux/gfp.h
@@ -274,6 +274,29 @@
 	return (bool __force)(gfp_flags & __GFP_DIRECT_RECLAIM);
 }
 
+/**
+ * gfpflags_normal_context - is gfp_flags a normal sleepable context?
+ * @gfp_flags: gfp_flags to test
+ *
+ * Test whether @gfp_flags indicates that the allocation is from the
+ * %current context and allowed to sleep.
+ *
+ * An allocation being allowed to block doesn't mean it owns the %current
+ * context.  When direct reclaim path tries to allocate memory, the
+ * allocation context is nested inside whatever %current was doing at the
+ * time of the original allocation.  The nested allocation may be allowed
+ * to block but modifying anything %current owns can corrupt the outer
+ * context's expectations.
+ *
+ * %true result from this function indicates that the allocation context
+ * can sleep and use anything that's associated with %current.
+ */
+static inline bool gfpflags_normal_context(const gfp_t gfp_flags)
+{
+	return (gfp_flags & (__GFP_DIRECT_RECLAIM | __GFP_MEMALLOC)) ==
+		__GFP_DIRECT_RECLAIM;
+}
+
 #ifdef CONFIG_HIGHMEM
 #define OPT_ZONE_HIGHMEM ZONE_HIGHMEM
 #else
@@ -322,22 +345,29 @@
  *       0xe    => BAD (MOVABLE+DMA32+HIGHMEM)
  *       0xf    => BAD (MOVABLE+DMA32+HIGHMEM+DMA)
  *
- * ZONES_SHIFT must be <= 2 on 32 bit platforms.
+ * GFP_ZONES_SHIFT must be <= 2 on 32 bit platforms.
  */
 
-#if 16 * ZONES_SHIFT > BITS_PER_LONG
-#error ZONES_SHIFT too large to create GFP_ZONE_TABLE integer
+#if defined(CONFIG_ZONE_DEVICE) && (MAX_NR_ZONES-1) <= 4
+/* ZONE_DEVICE is not a valid GFP zone specifier */
+#define GFP_ZONES_SHIFT 2
+#else
+#define GFP_ZONES_SHIFT ZONES_SHIFT
+#endif
+
+#if 16 * GFP_ZONES_SHIFT > BITS_PER_LONG
+#error GFP_ZONES_SHIFT too large to create GFP_ZONE_TABLE integer
 #endif
 
 #define GFP_ZONE_TABLE ( \
-	(ZONE_NORMAL << 0 * ZONES_SHIFT)				      \
-	| (OPT_ZONE_DMA << ___GFP_DMA * ZONES_SHIFT)			      \
-	| (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * ZONES_SHIFT)		      \
-	| (OPT_ZONE_DMA32 << ___GFP_DMA32 * ZONES_SHIFT)		      \
-	| (ZONE_NORMAL << ___GFP_MOVABLE * ZONES_SHIFT)			      \
-	| (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * ZONES_SHIFT)	      \
-	| (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * ZONES_SHIFT)   \
-	| (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * ZONES_SHIFT)   \
+	(ZONE_NORMAL << 0 * GFP_ZONES_SHIFT)				       \
+	| (OPT_ZONE_DMA << ___GFP_DMA * GFP_ZONES_SHIFT)		       \
+	| (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * GFP_ZONES_SHIFT)	       \
+	| (OPT_ZONE_DMA32 << ___GFP_DMA32 * GFP_ZONES_SHIFT)		       \
+	| (ZONE_NORMAL << ___GFP_MOVABLE * GFP_ZONES_SHIFT)		       \
+	| (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * GFP_ZONES_SHIFT)    \
+	| (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * GFP_ZONES_SHIFT)\
+	| (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * GFP_ZONES_SHIFT)\
 )
 
 /*
@@ -362,8 +392,8 @@
 	enum zone_type z;
 	int bit = (__force int) (flags & GFP_ZONEMASK);
 
-	z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
-					 ((1 << ZONES_SHIFT) - 1);
+	z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) &
+					 ((1 << GFP_ZONES_SHIFT) - 1);
 	VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
 	return z;
 }
--- linux-4.4.0.orig/include/linux/gpio.h
+++ linux-4.4.0/include/linux/gpio.h
@@ -229,30 +229,6 @@
 	return -EINVAL;
 }
 
-static inline int
-gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
-		       unsigned int gpio_offset, unsigned int pin_offset,
-		       unsigned int npins)
-{
-	WARN_ON(1);
-	return -EINVAL;
-}
-
-static inline int
-gpiochip_add_pingroup_range(struct gpio_chip *chip,
-			struct pinctrl_dev *pctldev,
-			unsigned int gpio_offset, const char *pin_group)
-{
-	WARN_ON(1);
-	return -EINVAL;
-}
-
-static inline void
-gpiochip_remove_pin_ranges(struct gpio_chip *chip)
-{
-	WARN_ON(1);
-}
-
 static inline int devm_gpio_request(struct device *dev, unsigned gpio,
 				    const char *label)
 {
--- linux-4.4.0.orig/include/linux/gpio/consumer.h
+++ linux-4.4.0/include/linux/gpio/consumer.h
@@ -398,7 +398,7 @@
 
 static inline struct gpio_desc *gpio_to_desc(unsigned gpio)
 {
-	return ERR_PTR(-EINVAL);
+	return NULL;
 }
 
 static inline int desc_to_gpio(const struct gpio_desc *desc)
--- linux-4.4.0.orig/include/linux/gpio/driver.h
+++ linux-4.4.0/include/linux/gpio/driver.h
@@ -75,6 +75,10 @@
  *	initialization, provided by GPIO driver
  * @irq_parent: GPIO IRQ chip parent/bank linux irq number,
  *	provided by GPIO driver
+ * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
+ *	bits set to one
+ * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
+ *	be included in IRQ domain of the chip
  * @lock_key: per GPIO IRQ chip lockdep class
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
@@ -138,6 +142,8 @@
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
 	int			irq_parent;
+	bool			irq_need_valid_mask;
+	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
 #endif
 
@@ -174,6 +180,7 @@
 /* lock/unlock as IRQ */
 int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
 void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
+bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset);
 
 struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
 
--- linux-4.4.0.orig/include/linux/hash.h
+++ linux-4.4.0/include/linux/hash.h
@@ -32,12 +32,28 @@
 #error Wordsize not 32 or 64
 #endif
 
+/*
+ * The above primes are actively bad for hashing, since they are
+ * too sparse. The 32-bit one is mostly ok, the 64-bit one causes
+ * real problems. Besides, the "prime" part is pointless for the
+ * multiplicative hash.
+ *
+ * Although a random odd number will do, it turns out that the golden
+ * ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice
+ * properties.
+ *
+ * These are the negative, (1 - phi) = (phi^2) = (3 - sqrt(5))/2.
+ * (See Knuth vol 3, section 6.4, exercise 9.)
+ */
+#define GOLDEN_RATIO_32 0x61C88647
+#define GOLDEN_RATIO_64 0x61C8864680B583EBull
+
 static __always_inline u64 hash_64(u64 val, unsigned int bits)
 {
 	u64 hash = val;
 
-#if defined(CONFIG_ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64
-	hash = hash * GOLDEN_RATIO_PRIME_64;
+#if BITS_PER_LONG == 64
+	hash = hash * GOLDEN_RATIO_64;
 #else
 	/*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
 	u64 n = hash;
--- linux-4.4.0.orig/include/linux/hid-debug.h
+++ linux-4.4.0/include/linux/hid-debug.h
@@ -24,7 +24,10 @@
 
 #ifdef CONFIG_DEBUG_FS
 
+#include <linux/kfifo.h>
+
 #define HID_DEBUG_BUFSIZE 512
+#define HID_DEBUG_FIFOSIZE 512
 
 void hid_dump_input(struct hid_device *, struct hid_usage *, __s32);
 void hid_dump_report(struct hid_device *, int , u8 *, int);
@@ -37,11 +40,8 @@
 void hid_debug_exit(void);
 void hid_debug_event(struct hid_device *, char *);
 
-
 struct hid_debug_list {
-	char *hid_debug_buf;
-	int head;
-	int tail;
+	DECLARE_KFIFO_PTR(hid_debug_fifo, char);
 	struct fasync_struct *fasync;
 	struct hid_device *hdev;
 	struct list_head node;
@@ -64,4 +64,3 @@
 #endif
 
 #endif
-
--- linux-4.4.0.orig/include/linux/hid.h
+++ linux-4.4.0/include/linux/hid.h
@@ -372,6 +372,7 @@
 
 struct hid_local {
 	unsigned usage[HID_MAX_USAGES]; /* usage array */
+	u8 usage_size[HID_MAX_USAGES]; /* usage size array */
 	unsigned collection_index[HID_MAX_USAGES]; /* collection index array */
 	unsigned usage_index;
 	unsigned usage_minimum;
@@ -450,7 +451,7 @@
 };
 
 #define HID_MIN_BUFFER_SIZE	64		/* make sure there is at least a packet size of space */
-#define HID_MAX_BUFFER_SIZE	4096		/* 4kb */
+#define HID_MAX_BUFFER_SIZE	8192		/* 8kb */
 #define HID_CONTROL_FIFO_SIZE	256		/* to init devices with >100 reports */
 #define HID_OUTPUT_FIFO_SIZE	64
 
@@ -751,6 +752,22 @@
 	int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
 };
 
+extern struct hid_ll_driver i2c_hid_ll_driver;
+extern struct hid_ll_driver hidp_hid_driver;
+extern struct hid_ll_driver uhid_hid_driver;
+extern struct hid_ll_driver usb_hid_driver;
+
+static inline bool hid_is_using_ll_driver(struct hid_device *hdev,
+		struct hid_ll_driver *driver)
+{
+	return hdev->ll_driver == driver;
+}
+
+static inline bool hid_is_usb(struct hid_device *hdev)
+{
+	return hid_is_using_ll_driver(hdev, &usb_hid_driver);
+}
+
 #define	PM_HINT_FULLON	1<<5
 #define PM_HINT_NORMAL	1<<1
 
@@ -793,7 +810,7 @@
 extern void hidinput_disconnect(struct hid_device *);
 
 int hid_set_field(struct hid_field *, unsigned, __s32);
-int hid_input_report(struct hid_device *, int type, u8 *, int, int);
+int hid_input_report(struct hid_device *, int type, u8 *, u32, int);
 int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
 struct hid_field *hidinput_get_led_field(struct hid_device *hid);
 unsigned int hidinput_count_leds(struct hid_device *hid);
@@ -865,34 +882,49 @@
  * @max: maximal valid usage->code to consider later (out parameter)
  * @type: input event type (EV_KEY, EV_REL, ...)
  * @c: code which corresponds to this usage and type
+ *
+ * The value pointed to by @bit will be set to NULL if either @type is
+ * an unhandled event type, or if @c is out of range for @type. This
+ * can be used as an error condition.
  */
 static inline void hid_map_usage(struct hid_input *hidinput,
 		struct hid_usage *usage, unsigned long **bit, int *max,
-		__u8 type, __u16 c)
+		__u8 type, unsigned int c)
 {
 	struct input_dev *input = hidinput->input;
-
-	usage->type = type;
-	usage->code = c;
+	unsigned long *bmap = NULL;
+	unsigned int limit = 0;
 
 	switch (type) {
 	case EV_ABS:
-		*bit = input->absbit;
-		*max = ABS_MAX;
+		bmap = input->absbit;
+		limit = ABS_MAX;
 		break;
 	case EV_REL:
-		*bit = input->relbit;
-		*max = REL_MAX;
+		bmap = input->relbit;
+		limit = REL_MAX;
 		break;
 	case EV_KEY:
-		*bit = input->keybit;
-		*max = KEY_MAX;
+		bmap = input->keybit;
+		limit = KEY_MAX;
 		break;
 	case EV_LED:
-		*bit = input->ledbit;
-		*max = LED_MAX;
+		bmap = input->ledbit;
+		limit = LED_MAX;
 		break;
 	}
+
+	if (unlikely(c > limit || !bmap)) {
+		pr_warn_ratelimited("%s: Invalid code %d type %d\n",
+				    input->name, c, type);
+		*bit = NULL;
+		return;
+	}
+
+	usage->type = type;
+	usage->code = c;
+	*max = limit;
+	*bit = bmap;
 }
 
 /**
@@ -906,7 +938,8 @@
 		__u8 type, __u16 c)
 {
 	hid_map_usage(hidinput, usage, bit, max, type, c);
-	clear_bit(c, *bit);
+	if (*bit)
+		clear_bit(usage->code, *bit);
 }
 
 /**
@@ -1098,13 +1131,12 @@
  *
  * @report: the report we want to know the length
  */
-static inline int hid_report_len(struct hid_report *report)
+static inline u32 hid_report_len(struct hid_report *report)
 {
-	/* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
-	return ((report->size - 1) >> 3) + 1 + (report->id > 0);
+	return DIV_ROUND_UP(report->size, 8) + (report->id > 0);
 }
 
-int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
 		int interrupt);
 
 /* HID quirks API */
--- linux-4.4.0.orig/include/linux/hil_mlc.h
+++ linux-4.4.0/include/linux/hil_mlc.h
@@ -103,7 +103,7 @@
 
 /* Methods for back-end drivers, e.g. hp_sdc_mlc */
 typedef int	(hil_mlc_cts) (hil_mlc *mlc);
-typedef void	(hil_mlc_out) (hil_mlc *mlc);
+typedef int	(hil_mlc_out) (hil_mlc *mlc);
 typedef int	(hil_mlc_in)  (hil_mlc *mlc, suseconds_t timeout);
 
 struct hil_mlc_devinfo {
--- linux-4.4.0.orig/include/linux/hrtimer.h
+++ linux-4.4.0/include/linux/hrtimer.h
@@ -87,12 +87,7 @@
  * @function:	timer expiry callback function
  * @base:	pointer to the timer base (per cpu and per clock)
  * @state:	state information (See bit values above)
- * @start_pid: timer statistics field to store the pid of the task which
- *		started the timer
- * @start_site:	timer statistics field to store the site where the timer
- *		was started
- * @start_comm: timer statistics field to store the name of the process which
- *		started the timer
+ * @is_rel:	Set if the timer was armed relative
  *
  * The hrtimer structure must be initialized by hrtimer_init()
  */
@@ -101,12 +96,8 @@
 	ktime_t				_softexpires;
 	enum hrtimer_restart		(*function)(struct hrtimer *);
 	struct hrtimer_clock_base	*base;
-	unsigned long			state;
-#ifdef CONFIG_TIMER_STATS
-	int				start_pid;
-	void				*start_site;
-	char				start_comm[16];
-#endif
+	u8				state;
+	u8				is_rel;
 };
 
 /**
@@ -321,6 +312,27 @@
 
 #endif
 
+static inline ktime_t
+__hrtimer_expires_remaining_adjusted(const struct hrtimer *timer, ktime_t now)
+{
+	ktime_t rem = ktime_sub(timer->node.expires, now);
+
+	/*
+	 * Adjust relative timers for the extra we added in
+	 * hrtimer_start_range_ns() to prevent short timeouts.
+	 */
+	if (IS_ENABLED(CONFIG_TIME_LOW_RES) && timer->is_rel)
+		rem.tv64 -= hrtimer_resolution;
+	return rem;
+}
+
+static inline ktime_t
+hrtimer_expires_remaining_adjusted(const struct hrtimer *timer)
+{
+	return __hrtimer_expires_remaining_adjusted(timer,
+						    timer->base->get_time());
+}
+
 extern void clock_was_set(void);
 #ifdef CONFIG_TIMERFD
 extern void timerfd_clock_was_set(void);
@@ -390,18 +402,29 @@
 }
 
 /* Query timers: */
-extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer);
+extern ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust);
+
+static inline ktime_t hrtimer_get_remaining(const struct hrtimer *timer)
+{
+	return __hrtimer_get_remaining(timer, false);
+}
 
 extern u64 hrtimer_get_next_event(void);
 
 extern bool hrtimer_active(const struct hrtimer *timer);
 
-/*
- * Helper function to check, whether the timer is on one of the queues
+/**
+ * hrtimer_is_queued = check, whether the timer is on one of the queues
+ * @timer:	Timer to check
+ *
+ * Returns: True if the timer is queued, false otherwise
+ *
+ * The function can be used lockless, but it gives only a current snapshot.
  */
-static inline int hrtimer_is_queued(struct hrtimer *timer)
+static inline bool hrtimer_is_queued(struct hrtimer *timer)
 {
-	return timer->state & HRTIMER_STATE_ENQUEUED;
+	/* The READ_ONCE pairs with the update functions of timer->state */
+	return !!(READ_ONCE(timer->state) & HRTIMER_STATE_ENQUEUED);
 }
 
 /*
--- linux-4.4.0.orig/include/linux/hugetlb.h
+++ linux-4.4.0/include/linux/hugetlb.h
@@ -91,9 +91,7 @@
 void free_huge_page(struct page *page);
 void hugetlb_fix_reserve_counts(struct inode *inode, bool restore_reserve);
 extern struct mutex *hugetlb_fault_mutex_table;
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
-				struct vm_area_struct *vma,
-				struct address_space *mapping,
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
 				pgoff_t idx, unsigned long address);
 
 #ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
@@ -110,6 +108,8 @@
 			unsigned long addr, unsigned long sz);
 pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr);
 int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep);
+void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma,
+				unsigned long *start, unsigned long *end);
 struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
 			      int write);
 struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
@@ -132,6 +132,18 @@
 	return 0;
 }
 
+static inline int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr,
+						pte_t *ptep)
+{
+	return 0;
+}
+
+static inline void adjust_range_if_pmd_sharing_possible(
+				struct vm_area_struct *vma,
+				unsigned long *start, unsigned long *end)
+{
+}
+
 #define follow_hugetlb_page(m,v,p,vs,a,b,i,w)	({ BUG(); 0; })
 #define follow_huge_addr(mm, addr, write)	ERR_PTR(-EINVAL)
 #define copy_hugetlb_page_range(src, dst, vma)	({ BUG(); 0; })
@@ -494,6 +506,9 @@
 {
 	atomic_long_sub(l, &mm->hugetlb_usage);
 }
+
+void set_page_huge_active(struct page *page);
+
 #else	/* CONFIG_HUGETLB_PAGE */
 struct hstate {};
 #define alloc_huge_page(v, a, r) NULL
--- linux-4.4.0.orig/include/linux/hyperv.h
+++ linux-4.4.0/include/linux/hyperv.h
@@ -126,6 +126,9 @@
 
 	u32 ring_datasize;		/* < ring_size */
 	u32 ring_data_startoffset;
+	u32 priv_write_index;
+	u32 priv_read_index;
+	u32 cached_read_index;
 };
 
 /*
@@ -141,8 +144,6 @@
 {
 	u32 read_loc, write_loc, dsize;
 
-	smp_read_barrier_depends();
-
 	/* Capture the read/write indices before they changed */
 	read_loc = rbi->ring_buffer->read_index;
 	write_loc = rbi->ring_buffer->write_index;
@@ -153,6 +154,46 @@
 	*read = dsize - *write;
 }
 
+static inline u32 hv_get_bytes_to_read(struct hv_ring_buffer_info *rbi)
+{
+	u32 read_loc, write_loc, dsize, read;
+
+	dsize = rbi->ring_datasize;
+	read_loc = rbi->ring_buffer->read_index;
+	write_loc = READ_ONCE(rbi->ring_buffer->write_index);
+
+	read = write_loc >= read_loc ? (write_loc - read_loc) :
+		(dsize - read_loc) + write_loc;
+
+	return read;
+}
+
+static inline u32 hv_get_bytes_to_write(struct hv_ring_buffer_info *rbi)
+{
+	u32 read_loc, write_loc, dsize, write;
+
+	dsize = rbi->ring_datasize;
+	read_loc = READ_ONCE(rbi->ring_buffer->read_index);
+	write_loc = rbi->ring_buffer->write_index;
+
+	write = write_loc >= read_loc ? dsize - (write_loc - read_loc) :
+		read_loc - write_loc;
+	return write;
+}
+
+static inline u32 hv_get_cached_bytes_to_write(
+	const struct hv_ring_buffer_info *rbi)
+{
+	u32 read_loc, write_loc, dsize, write;
+
+	dsize = rbi->ring_datasize;
+	read_loc = rbi->cached_read_index;
+	write_loc = rbi->ring_buffer->write_index;
+
+	write = write_loc >= read_loc ? dsize - (write_loc - read_loc) :
+		read_loc - write_loc;
+	return write;
+}
 /*
  * VMBUS version is 32 bit entity broken up into
  * two 16 bit quantities: major_number. minor_number.
@@ -237,6 +278,7 @@
 #define VMBUS_CHANNEL_LOOPBACK_OFFER			0x100
 #define VMBUS_CHANNEL_PARENT_OFFER			0x200
 #define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION	0x400
+#define VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER		0x2000
 
 struct vmpacket_descriptor {
 	u16 type;
@@ -393,6 +435,10 @@
 	CHANNELMSG_VERSION_RESPONSE		= 15,
 	CHANNELMSG_UNLOAD			= 16,
 	CHANNELMSG_UNLOAD_RESPONSE		= 17,
+	CHANNELMSG_18				= 18,
+	CHANNELMSG_19				= 19,
+	CHANNELMSG_20				= 20,
+	CHANNELMSG_TL_CONNECT_REQUEST		= 21,
 	CHANNELMSG_COUNT
 };
 
@@ -563,6 +609,13 @@
 	u64 monitor_page2;
 } __packed;
 
+/* Hyper-V socket: guest's connect()-ing to host */
+struct vmbus_channel_tl_connect_request {
+	struct vmbus_channel_message_header header;
+	uuid_le guest_endpoint_id;
+	uuid_le host_service_id;
+} __packed;
+
 struct vmbus_channel_version_response {
 	struct vmbus_channel_message_header header;
 	u8 version_supported;
@@ -630,10 +683,43 @@
 	struct hv_input_signal_event event;
 };
 
-struct vmbus_channel {
-	/* Unique channel id */
-	int id;
+enum hv_signal_policy {
+	HV_SIGNAL_POLICY_DEFAULT = 0,
+	HV_SIGNAL_POLICY_EXPLICIT,
+};
 
+enum hv_numa_policy {
+	HV_BALANCED = 0,
+	HV_LOCALIZED,
+};
+
+enum vmbus_device_type {
+	HV_IDE = 0,
+	HV_SCSI,
+	HV_FC,
+	HV_NIC,
+	HV_ND,
+	HV_PCIE,
+	HV_FB,
+	HV_KBD,
+	HV_MOUSE,
+	HV_KVP,
+	HV_TS,
+	HV_HB,
+	HV_SHUTDOWN,
+	HV_FCOPY,
+	HV_BACKUP,
+	HV_DM,
+	HV_UNKOWN,
+};
+
+struct vmbus_device {
+	u16  dev_type;
+	uuid_le guid;
+	bool perf_device;
+};
+
+struct vmbus_channel {
 	struct list_head listentry;
 
 	struct hv_device *device_obj;
@@ -725,6 +811,12 @@
 	void (*sc_creation_callback)(struct vmbus_channel *new_sc);
 
 	/*
+	 * Channel rescind callback. Some channels (the hvsock ones), need to
+	 * register a callback which is invoked in vmbus_onoffer_rescind().
+	 */
+	void (*chn_rescind_callback)(struct vmbus_channel *channel);
+
+	/*
 	 * The spinlock to protect the structure. It is being used to protect
 	 * test-and-set access to various attributes of the structure as well
 	 * as all sc_list operations.
@@ -757,8 +849,86 @@
 	 * link up channels based on their CPU affinity.
 	 */
 	struct list_head percpu_list;
+	/*
+	 * Host signaling policy: The default policy will be
+	 * based on the ring buffer state. We will also support
+	 * a policy where the client driver can have explicit
+	 * signaling control.
+	 */
+	enum hv_signal_policy  signal_policy;
+	/*
+	 * On the channel send side, many of the VMBUS
+	 * device drivers explicity serialize access to the
+	 * outgoing ring buffer. Give more control to the
+	 * VMBUS device drivers in terms how to serialize
+	 * accesss to the outgoing ring buffer.
+	 * The default behavior will be to aquire the
+	 * ring lock to preserve the current behavior.
+	 */
+	bool acquire_ring_lock;
+	/*
+	 * For performance critical channels (storage, networking
+	 * etc,), Hyper-V has a mechanism to enhance the throughput
+	 * at the expense of latency:
+	 * When the host is to be signaled, we just set a bit in a shared page
+	 * and this bit will be inspected by the hypervisor within a certain
+	 * window and if the bit is set, the host will be signaled. The window
+	 * of time is the monitor latency - currently around 100 usecs. This
+	 * mechanism improves throughput by:
+	 *
+	 * A) Making the host more efficient - each time it wakes up,
+	 *    potentially it will process morev number of packets. The
+	 *    monitor latency allows a batch to build up.
+	 * B) By deferring the hypercall to signal, we will also minimize
+	 *    the interrupts.
+	 *
+	 * Clearly, these optimizations improve throughput at the expense of
+	 * latency. Furthermore, since the channel is shared for both
+	 * control and data messages, control messages currently suffer
+	 * unnecessary latency adversley impacting performance and boot
+	 * time. To fix this issue, permit tagging the channel as being
+	 * in "low latency" mode. In this mode, we will bypass the monitor
+	 * mechanism.
+	 */
+	bool low_latency;
+
+	/*
+	 * NUMA distribution policy:
+	 * We support teo policies:
+	 * 1) Balanced: Here all performance critical channels are
+	 *    distributed evenly amongst all the NUMA nodes.
+	 *    This policy will be the default policy.
+	 * 2) Localized: All channels of a given instance of a
+	 *    performance critical service will be assigned CPUs
+	 *    within a selected NUMA node.
+	 */
+	enum hv_numa_policy affinity_policy;
+
 };
 
+static inline void set_channel_lock_state(struct vmbus_channel *c, bool state)
+{
+	c->acquire_ring_lock = state;
+}
+
+static inline bool is_hvsock_channel(const struct vmbus_channel *c)
+{
+	return !!(c->offermsg.offer.chn_flags &
+		  VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER);
+}
+
+static inline void set_channel_signal_state(struct vmbus_channel *c,
+					    enum hv_signal_policy policy)
+{
+	c->signal_policy = policy;
+}
+
+static inline void set_channel_affinity_state(struct vmbus_channel *c,
+					      enum hv_numa_policy policy)
+{
+	c->affinity_policy = policy;
+}
+
 static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
 {
 	c->batched_reading = state;
@@ -774,6 +944,22 @@
 	return c->per_channel_state;
 }
 
+static inline void set_channel_pending_send_size(struct vmbus_channel *c,
+						 u32 size)
+{
+	c->outbound.ring_buffer->pending_send_sz = size;
+}
+
+static inline void set_low_latency_mode(struct vmbus_channel *c)
+{
+	c->low_latency = true;
+}
+
+static inline void clear_low_latency_mode(struct vmbus_channel *c)
+{
+	c->low_latency = false;
+}
+
 void vmbus_onmessage(void *context);
 
 int vmbus_request_offers(void);
@@ -785,6 +971,9 @@
 void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel,
 			void (*sc_cr_cb)(struct vmbus_channel *new_sc));
 
+void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel,
+		void (*chn_rescind_cb)(struct vmbus_channel *));
+
 /*
  * Retrieve the (sub) channel on which to send an outgoing request.
  * When a primary channel has multiple sub-channels, we choose a
@@ -924,6 +1113,20 @@
 struct hv_driver {
 	const char *name;
 
+	/*
+	 * A hvsock offer, which has a VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER
+	 * channel flag, actually doesn't mean a synthetic device because the
+	 * offer's if_type/if_instance can change for every new hvsock
+	 * connection.
+	 *
+	 * However, to facilitate the notification of new-offer/rescind-offer
+	 * from vmbus driver to hvsock driver, we can handle hvsock offer as
+	 * a special vmbus device, and hence we need the below flag to
+	 * indicate if the driver is the hvsock driver or not: we need to
+	 * specially treat the hvosck offer & driver in vmbus_match().
+	 */
+	bool hvsock;
+
 	/* the device type supported by this driver */
 	uuid_le dev_type;
 	const struct hv_vmbus_device_id *id_table;
@@ -943,6 +1146,8 @@
 
 	/* the device instance id of this device */
 	uuid_le dev_instance;
+	u16 vendor_id;
+	u16 device_id;
 
 	struct device device;
 
@@ -978,21 +1183,15 @@
 					 const char *mod_name);
 void vmbus_driver_unregister(struct hv_driver *hv_driver);
 
+void vmbus_hvsock_device_unregister(struct vmbus_channel *channel);
+
 int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
 			resource_size_t min, resource_size_t max,
 			resource_size_t size, resource_size_t align,
 			bool fb_overlap_ok);
-
-/**
- * VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device
- *
- * This macro is used to create a struct hv_vmbus_device_id that matches a
- * specific device.
- */
-#define VMBUS_DEVICE(g0, g1, g2, g3, g4, g5, g6, g7,	\
-		     g8, g9, ga, gb, gc, gd, ge, gf)	\
-	.guid = { g0, g1, g2, g3, g4, g5, g6, g7,	\
-		  g8, g9, ga, gb, gc, gd, ge, gf },
+void vmbus_free_mmio(resource_size_t start, resource_size_t size);
+int vmbus_cpu_number_to_vp_number(int cpu_number);
+u64 hv_do_hypercall(u64 control, void *input, void *output);
 
 /*
  * GUID definitions of various offer types - services offered to the guest.
@@ -1003,118 +1202,102 @@
  * {f8615163-df3e-46c5-913f-f2d2f965ed0e}
  */
 #define HV_NIC_GUID \
-	.guid = { \
-			0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46, \
-			0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e \
-		}
+	.guid = UUID_LE(0xf8615163, 0xdf3e, 0x46c5, 0x91, 0x3f, \
+			0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e)
 
 /*
  * IDE GUID
  * {32412632-86cb-44a2-9b5c-50d1417354f5}
  */
 #define HV_IDE_GUID \
-	.guid = { \
-			0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, \
-			0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 \
-		}
+	.guid = UUID_LE(0x32412632, 0x86cb, 0x44a2, 0x9b, 0x5c, \
+			0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5)
 
 /*
  * SCSI GUID
  * {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}
  */
 #define HV_SCSI_GUID \
-	.guid = { \
-			0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, \
-			0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f \
-		}
+	.guid = UUID_LE(0xba6163d9, 0x04a1, 0x4d29, 0xb6, 0x05, \
+			0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f)
 
 /*
  * Shutdown GUID
  * {0e0b6031-5213-4934-818b-38d90ced39db}
  */
 #define HV_SHUTDOWN_GUID \
-	.guid = { \
-			0x31, 0x60, 0x0b, 0x0e, 0x13, 0x52, 0x34, 0x49, \
-			0x81, 0x8b, 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb \
-		}
+	.guid = UUID_LE(0x0e0b6031, 0x5213, 0x4934, 0x81, 0x8b, \
+			0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb)
 
 /*
  * Time Synch GUID
  * {9527E630-D0AE-497b-ADCE-E80AB0175CAF}
  */
 #define HV_TS_GUID \
-	.guid = { \
-			0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49, \
-			0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf \
-		}
+	.guid = UUID_LE(0x9527e630, 0xd0ae, 0x497b, 0xad, 0xce, \
+			0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf)
 
 /*
  * Heartbeat GUID
  * {57164f39-9115-4e78-ab55-382f3bd5422d}
  */
 #define HV_HEART_BEAT_GUID \
-	.guid = { \
-			0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, \
-			0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d \
-		}
+	.guid = UUID_LE(0x57164f39, 0x9115, 0x4e78, 0xab, 0x55, \
+			0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d)
 
 /*
  * KVP GUID
  * {a9a0f4e7-5a45-4d96-b827-8a841e8c03e6}
  */
 #define HV_KVP_GUID \
-	.guid = { \
-			0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d, \
-			0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3,  0xe6 \
-		}
+	.guid = UUID_LE(0xa9a0f4e7, 0x5a45, 0x4d96, 0xb8, 0x27, \
+			0x8a, 0x84, 0x1e, 0x8c, 0x03, 0xe6)
 
 /*
  * Dynamic memory GUID
  * {525074dc-8985-46e2-8057-a307dc18a502}
  */
 #define HV_DM_GUID \
-	.guid = { \
-			0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46, \
-			0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02 \
-		}
+	.guid = UUID_LE(0x525074dc, 0x8985, 0x46e2, 0x80, 0x57, \
+			0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02)
 
 /*
  * Mouse GUID
  * {cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a}
  */
 #define HV_MOUSE_GUID \
-	.guid = { \
-			0x9e, 0xb6, 0xa8, 0xcf, 0x4a, 0x5b, 0xc0, 0x4c, \
-			0xb9, 0x8b, 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a \
-		}
+	.guid = UUID_LE(0xcfa8b69e, 0x5b4a, 0x4cc0, 0xb9, 0x8b, \
+			0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a)
+
+/*
+ * Keyboard GUID
+ * {f912ad6d-2b17-48ea-bd65-f927a61c7684}
+ */
+#define HV_KBD_GUID \
+	.guid = UUID_LE(0xf912ad6d, 0x2b17, 0x48ea, 0xbd, 0x65, \
+			0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84)
 
 /*
  * VSS (Backup/Restore) GUID
  */
 #define HV_VSS_GUID \
-	.guid = { \
-			0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42, \
-			0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4,  0x40 \
-		}
+	.guid = UUID_LE(0x35fa2e29, 0xea23, 0x4236, 0x96, 0xae, \
+			0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40)
 /*
  * Synthetic Video GUID
  * {DA0A7802-E377-4aac-8E77-0558EB1073F8}
  */
 #define HV_SYNTHVID_GUID \
-	.guid = { \
-			0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a, \
-			0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 \
-		}
+	.guid = UUID_LE(0xda0a7802, 0xe377, 0x4aac, 0x8e, 0x77, \
+			0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8)
 
 /*
  * Synthetic FC GUID
  * {2f9bcc4a-0069-4af3-b76b-6fd0be528cda}
  */
 #define HV_SYNTHFC_GUID \
-	.guid = { \
-			0x4A, 0xCC, 0x9B, 0x2F, 0x69, 0x00, 0xF3, 0x4A, \
-			0xB7, 0x6B, 0x6F, 0xD0, 0xBE, 0x52, 0x8C, 0xDA \
-		}
+	.guid = UUID_LE(0x2f9bcc4a, 0x0069, 0x4af3, 0xb7, 0x6b, \
+			0x6f, 0xd0, 0xbe, 0x52, 0x8c, 0xda)
 
 /*
  * Guest File Copy Service
@@ -1122,20 +1305,46 @@
  */
 
 #define HV_FCOPY_GUID \
-	.guid = { \
-			0xE3, 0x4B, 0xD1, 0x34, 0xE4, 0xDE, 0xC8, 0x41, \
-			0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \
-		}
+	.guid = UUID_LE(0x34d14be3, 0xdee4, 0x41c8, 0x9a, 0xe7, \
+			0x6b, 0x17, 0x49, 0x77, 0xc1, 0x92)
 
 /*
  * NetworkDirect. This is the guest RDMA service.
  * {8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}
  */
 #define HV_ND_GUID \
-	.guid = { \
-			0x3d, 0xaf, 0x2e, 0x8c, 0xa7, 0x32, 0x09, 0x4b, \
-			0xab, 0x99, 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01 \
-		}
+	.guid = UUID_LE(0x8c2eaf3d, 0x32a7, 0x4b09, 0xab, 0x99, \
+			0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01)
+
+/*
+ * PCI Express Pass Through
+ * {44C4F61D-4444-4400-9D52-802E27EDE19F}
+ */
+
+#define HV_PCIE_GUID \
+	.guid = UUID_LE(0x44c4f61d, 0x4444, 0x4400, 0x9d, 0x52, \
+			0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f)
+
+/*
+ * Linux doesn't support the 3 devices: the first two are for
+ * Automatic Virtual Machine Activation, and the third is for
+ * Remote Desktop Virtualization.
+ * {f8e65716-3cb3-4a06-9a60-1889c5cccab5}
+ * {3375baf4-9e15-4b30-b765-67acb10d607b}
+ * {276aacf4-ac15-426c-98dd-7521ad3f01fe}
+ */
+
+#define HV_AVMA1_GUID \
+	.guid = UUID_LE(0xf8e65716, 0x3cb3, 0x4a06, 0x9a, 0x60, \
+			0x18, 0x89, 0xc5, 0xcc, 0xca, 0xb5)
+
+#define HV_AVMA2_GUID \
+	.guid = UUID_LE(0x3375baf4, 0x9e15, 0x4b30, 0xb7, 0x65, \
+			0x67, 0xac, 0xb1, 0x0d, 0x60, 0x7b)
+
+#define HV_RDV_GUID \
+	.guid = UUID_LE(0x276aacf4, 0xac15, 0x426c, 0x98, 0xdd, \
+			0x75, 0x21, 0xad, 0x3f, 0x01, 0xfe)
 
 /*
  * Common header for Hyper-V ICs
@@ -1161,6 +1370,7 @@
 
 struct hv_util_service {
 	u8 *recv_buffer;
+	void *channel;
 	void (*util_cb)(void *);
 	int (*util_init)(struct hv_util_service *);
 	void (*util_deinit)(void);
@@ -1224,6 +1434,15 @@
 	u8 flags;
 } __packed;
 
+struct ictimesync_ref_data {
+	u64 parenttime;
+	u64 vmreferencetime;
+	u8 flags;
+	char leapflags;
+	char stratum;
+	u8 reserved[3];
+} __packed;
+
 struct hyperv_service_callback {
 	u8 msg_type;
 	char *log_msg;
@@ -1237,12 +1456,171 @@
 					struct icmsg_negotiate *, u8 *, int,
 					int);
 
+void hv_event_tasklet_disable(struct vmbus_channel *channel);
+void hv_event_tasklet_enable(struct vmbus_channel *channel);
+
 void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
 
+void vmbus_setevent(struct vmbus_channel *channel);
 /*
  * Negotiated version with the Host.
  */
 
 extern __u32 vmbus_proto_version;
 
+int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id,
+				  const uuid_le *shv_host_servie_id);
+void vmbus_set_event(struct vmbus_channel *channel);
+
+/* Get the start of the ring buffer. */
+static inline void *
+hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
+{
+	return (void *)ring_info->ring_buffer->buffer;
+}
+
+/*
+ * To optimize the flow management on the send-side,
+ * when the sender is blocked because of lack of
+ * sufficient space in the ring buffer, potential the
+ * consumer of the ring buffer can signal the producer.
+ * This is controlled by the following parameters:
+ *
+ * 1. pending_send_sz: This is the size in bytes that the
+ *    producer is trying to send.
+ * 2. The feature bit feat_pending_send_sz set to indicate if
+ *    the consumer of the ring will signal when the ring
+ *    state transitions from being full to a state where
+ *    there is room for the producer to send the pending packet.
+ */
+
+static inline  void hv_signal_on_read(struct vmbus_channel *channel)
+{
+	u32 cur_write_sz, cached_write_sz;
+	u32 pending_sz;
+	struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+	/*
+	 * Issue a full memory barrier before making the signaling decision.
+	 * Here is the reason for having this barrier:
+	 * If the reading of the pend_sz (in this function)
+	 * were to be reordered and read before we commit the new read
+	 * index (in the calling function)  we could
+	 * have a problem. If the host were to set the pending_sz after we
+	 * have sampled pending_sz and go to sleep before we commit the
+	 * read index, we could miss sending the interrupt. Issue a full
+	 * memory barrier to address this.
+	 */
+	virt_mb();
+
+	pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz);
+	/* If the other end is not blocked on write don't bother. */
+	if (pending_sz == 0)
+		return;
+
+	cur_write_sz = hv_get_bytes_to_write(rbi);
+
+	if (cur_write_sz <= pending_sz)
+		return;
+
+	cached_write_sz = hv_get_cached_bytes_to_write(rbi);
+	if (cached_write_sz <= pending_sz)
+		vmbus_setevent(channel);
+
+	return;
+}
+
+static inline void
+init_cached_read_index(struct vmbus_channel *channel)
+{
+	struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+	rbi->cached_read_index = rbi->ring_buffer->read_index;
+}
+
+/*
+ * An API to support in-place processing of incoming VMBUS packets.
+ */
+#define VMBUS_PKT_TRAILER	8
+
+static inline struct vmpacket_descriptor *
+get_next_pkt_raw(struct vmbus_channel *channel)
+{
+	struct hv_ring_buffer_info *ring_info = &channel->inbound;
+	u32 read_loc = ring_info->priv_read_index;
+	void *ring_buffer = hv_get_ring_buffer(ring_info);
+	struct vmpacket_descriptor *cur_desc;
+	u32 packetlen;
+	u32 dsize = ring_info->ring_datasize;
+	u32 delta = read_loc - ring_info->ring_buffer->read_index;
+	u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
+
+	if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
+		return NULL;
+
+	if ((read_loc + sizeof(*cur_desc)) > dsize)
+		return NULL;
+
+	cur_desc = ring_buffer + read_loc;
+	packetlen = cur_desc->len8 << 3;
+
+	/*
+	 * If the packet under consideration is wrapping around,
+	 * return failure.
+	 */
+	if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > (dsize - 1))
+		return NULL;
+
+	return cur_desc;
+}
+
+/*
+ * A helper function to step through packets "in-place"
+ * This API is to be called after each successful call
+ * get_next_pkt_raw().
+ */
+static inline void put_pkt_raw(struct vmbus_channel *channel,
+				struct vmpacket_descriptor *desc)
+{
+	struct hv_ring_buffer_info *ring_info = &channel->inbound;
+	u32 read_loc = ring_info->priv_read_index;
+	u32 packetlen = desc->len8 << 3;
+	u32 dsize = ring_info->ring_datasize;
+
+	if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > dsize)
+		BUG();
+	/*
+	 * Include the packet trailer.
+	 */
+	ring_info->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
+}
+
+/*
+ * This call commits the read index and potentially signals the host.
+ * Here is the pattern for using the "in-place" consumption APIs:
+ *
+ * init_cached_read_index();
+ *
+ * while (get_next_pkt_raw() {
+ *	process the packet "in-place";
+ *	put_pkt_raw();
+ * }
+ * if (packets processed in place)
+ *	commit_rd_index();
+ */
+static inline void commit_rd_index(struct vmbus_channel *channel)
+{
+	struct hv_ring_buffer_info *ring_info = &channel->inbound;
+	/*
+	 * Make sure all reads are done before we update the read index since
+	 * the writer may start writing to the read area once the read index
+	 * is updated.
+	 */
+	virt_rmb();
+	ring_info->ring_buffer->read_index = ring_info->priv_read_index;
+
+	hv_signal_on_read(channel);
+}
+
+
 #endif /* _HYPERV_H */
--- linux-4.4.0.orig/include/linux/i2c-algo-pca.h
+++ linux-4.4.0/include/linux/i2c-algo-pca.h
@@ -52,6 +52,20 @@
 #define I2C_PCA_CON_SI		0x08 /* Serial Interrupt */
 #define I2C_PCA_CON_CR		0x07 /* Clock Rate (MASK) */
 
+/**
+ * struct pca_i2c_bus_settings - The configured PCA i2c bus settings
+ * @mode: Configured i2c bus mode
+ * @tlow: Configured SCL LOW period
+ * @thi: Configured SCL HIGH period
+ * @clock_freq: The configured clock frequency
+ */
+struct pca_i2c_bus_settings {
+	int mode;
+	int tlow;
+	int thi;
+	int clock_freq;
+};
+
 struct i2c_algo_pca_data {
 	void 				*data;	/* private low level data */
 	void (*write_byte)		(void *data, int reg, int val);
@@ -63,6 +77,7 @@
 	 * For PCA9665, use the frequency you want here. */
 	unsigned int			i2c_clock;
 	unsigned int			chip;
+	struct pca_i2c_bus_settings		bus_settings;
 };
 
 int i2c_pca_add_bus(struct i2c_adapter *);
--- linux-4.4.0.orig/include/linux/i2c-pnx.h
+++ linux-4.4.0/include/linux/i2c-pnx.h
@@ -19,7 +19,6 @@
 	int			ret;		/* Return value */
 	int			mode;		/* Interface mode */
 	struct completion	complete;	/* I/O completion */
-	struct timer_list	timer;		/* Timeout */
 	u8 *			buf;		/* Data buffer */
 	int			len;		/* Length of data buffer */
 	int			order;		/* RX Bytes to order via TX */
--- linux-4.4.0.orig/include/linux/i8042.h
+++ linux-4.4.0/include/linux/i8042.h
@@ -62,7 +62,6 @@
 void i8042_lock_chip(void);
 void i8042_unlock_chip(void);
 int i8042_command(unsigned char *param, int command);
-bool i8042_check_port_owner(const struct serio *);
 int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
 					struct serio *serio));
 int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
@@ -83,11 +82,6 @@
 	return -ENODEV;
 }
 
-static inline bool i8042_check_port_owner(const struct serio *serio)
-{
-	return false;
-}
-
 static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
 					struct serio *serio))
 {
--- linux-4.4.0.orig/include/linux/i8253.h
+++ linux-4.4.0/include/linux/i8253.h
@@ -21,6 +21,7 @@
 #define PIT_LATCH	((PIT_TICK_RATE + HZ/2) / HZ)
 
 extern raw_spinlock_t i8253_lock;
+extern bool i8253_clear_counter_on_shutdown;
 extern struct clock_event_device i8253_clockevent;
 extern void clockevent_i8253_init(bool oneshot);
 
--- linux-4.4.0.orig/include/linux/ide.h
+++ linux-4.4.0/include/linux/ide.h
@@ -128,7 +128,6 @@
  */
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
-#define SECTOR_SIZE	512
 
 /*
  * Timeouts for various operations:
--- linux-4.4.0.orig/include/linux/ieee80211.h
+++ linux-4.4.0/include/linux/ieee80211.h
@@ -7,6 +7,7 @@
  * Copyright (c) 2005, Devicescape Software, Inc.
  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
  * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright (c) 2018        Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -607,6 +608,15 @@
 }
 
 /**
+ * ieee80211_is_any_nullfunc - check if frame is regular or QoS nullfunc frame
+ * @fc: frame control bytes in little-endian byteorder
+ */
+static inline bool ieee80211_is_any_nullfunc(__le16 fc)
+{
+	return (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc));
+}
+
+/**
  * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
  * @fc: frame control field in little-endian byteorder
  */
@@ -2337,6 +2347,17 @@
 }
 
 /**
+ * ieee80211_get_tid - get qos TID
+ * @hdr: the frame
+ */
+static inline u8 ieee80211_get_tid(struct ieee80211_hdr *hdr)
+{
+	u8 *qc = ieee80211_get_qos_ctl(hdr);
+
+	return qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+/**
  * ieee80211_get_SA - get pointer to SA
  * @hdr: the frame
  *
@@ -2550,4 +2571,57 @@
 	return true;
 }
 
+struct element {
+	u8 id;
+	u8 datalen;
+	u8 data[];
+} __packed;
+
+/* element iteration helpers */
+#define for_each_element(_elem, _data, _datalen)			\
+	for (_elem = (const struct element *)(_data);			\
+	     (const u8 *)(_data) + (_datalen) - (const u8 *)_elem >=	\
+		(int)sizeof(*_elem) &&					\
+	     (const u8 *)(_data) + (_datalen) - (const u8 *)_elem >=	\
+		(int)sizeof(*_elem) + _elem->datalen;			\
+	     _elem = (const struct element *)(_elem->data + _elem->datalen))
+
+#define for_each_element_id(element, _id, data, datalen)		\
+	for_each_element(element, data, datalen)			\
+		if (element->id == (_id))
+
+#define for_each_element_extid(element, extid, data, datalen)		\
+	for_each_element(element, data, datalen)			\
+		if (element->id == WLAN_EID_EXTENSION &&		\
+		    element->datalen > 0 &&				\
+		    element->data[0] == (extid))
+
+#define for_each_subelement(sub, element)				\
+	for_each_element(sub, (element)->data, (element)->datalen)
+
+#define for_each_subelement_id(sub, id, element)			\
+	for_each_element_id(sub, id, (element)->data, (element)->datalen)
+
+#define for_each_subelement_extid(sub, extid, element)			\
+	for_each_element_extid(sub, extid, (element)->data, (element)->datalen)
+
+/**
+ * for_each_element_completed - determine if element parsing consumed all data
+ * @element: element pointer after for_each_element() or friends
+ * @data: same data pointer as passed to for_each_element() or friends
+ * @datalen: same data length as passed to for_each_element() or friends
+ *
+ * This function returns %true if all the data was parsed or considered
+ * while walking the elements. Only use this if your for_each_element()
+ * loop cannot be broken out of, otherwise it always returns %false.
+ *
+ * If some data was malformed, this returns %false since the last parsed
+ * element will not fill the whole remaining data.
+ */
+static inline bool for_each_element_completed(const struct element *element,
+					      const void *data, size_t datalen)
+{
+	return (const u8 *)element == (const u8 *)data + datalen;
+}
+
 #endif /* LINUX_IEEE80211_H */
--- linux-4.4.0.orig/include/linux/if_bridge.h
+++ linux-4.4.0/include/linux/if_bridge.h
@@ -46,10 +46,6 @@
 #define BR_LEARNING_SYNC	BIT(9)
 #define BR_PROXYARP_WIFI	BIT(10)
 
-/* values as per ieee8021QBridgeFdbAgingTime */
-#define BR_MIN_AGEING_TIME	(10 * HZ)
-#define BR_MAX_AGEING_TIME	(1000000 * HZ)
-
 #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
 
 extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
--- linux-4.4.0.orig/include/linux/if_ether.h
+++ linux-4.4.0/include/linux/if_ether.h
@@ -28,6 +28,14 @@
 	return (struct ethhdr *)skb_mac_header(skb);
 }
 
+/* Prefer this version in TX path, instead of
+ * skb_reset_mac_header() + eth_hdr()
+ */
+static inline struct ethhdr *skb_eth_hdr(const struct sk_buff *skb)
+{
+	return (struct ethhdr *)skb->data;
+}
+
 int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
 
 extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
--- linux-4.4.0.orig/include/linux/if_pppox.h
+++ linux-4.4.0/include/linux/if_pppox.h
@@ -84,6 +84,9 @@
 extern void unregister_pppox_proto(int proto_num);
 extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */
 extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+extern int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+
+#define PPPOEIOCSFWD32    _IOW(0xB1 ,0, compat_size_t)
 
 /* PPPoX socket states */
 enum {
--- linux-4.4.0.orig/include/linux/if_team.h
+++ linux-4.4.0/include/linux/if_team.h
@@ -176,6 +176,8 @@
 	struct net_device *dev; /* associated netdevice */
 	struct team_pcpu_stats __percpu *pcpu_stats;
 
+	const struct header_ops *header_ops_cache;
+
 	struct mutex lock; /* used for overall locking, e.g. port lists write */
 
 	/*
--- linux-4.4.0.orig/include/linux/if_vlan.h
+++ linux-4.4.0/include/linux/if_vlan.h
@@ -30,6 +30,8 @@
 #define VLAN_ETH_DATA_LEN	1500	/* Max. octets in payload	 */
 #define VLAN_ETH_FRAME_LEN	1518	/* Max. octets in frame sans FCS */
 
+#define VLAN_MAX_DEPTH	8		/* Max. number of nested VLAN tags parsed */
+
 /*
  * 	struct vlan_hdr - vlan header
  * 	@h_vlan_TCI: priority and VLAN ID
@@ -478,10 +480,10 @@
  * Returns the EtherType of the packet, regardless of whether it is
  * vlan encapsulated (normal or hardware accelerated) or not.
  */
-static inline __be16 __vlan_get_protocol(struct sk_buff *skb, __be16 type,
+static inline __be16 __vlan_get_protocol(const struct sk_buff *skb, __be16 type,
 					 int *depth)
 {
-	unsigned int vlan_depth = skb->mac_len;
+	unsigned int vlan_depth = skb->mac_len, parse_depth = VLAN_MAX_DEPTH;
 
 	/* if type is 802.1Q/AD then the header should already be
 	 * present at mac_len - VLAN_HLEN (if mac_len > 0), or at
@@ -496,13 +498,12 @@
 			vlan_depth = ETH_HLEN;
 		}
 		do {
-			struct vlan_hdr *vh;
+			struct vlan_hdr vhdr, *vh;
 
-			if (unlikely(!pskb_may_pull(skb,
-						    vlan_depth + VLAN_HLEN)))
+			vh = skb_header_pointer(skb, vlan_depth, sizeof(vhdr), &vhdr);
+			if (unlikely(!vh || !--parse_depth))
 				return 0;
 
-			vh = (struct vlan_hdr *)(skb->data + vlan_depth);
 			type = vh->h_vlan_encapsulated_proto;
 			vlan_depth += VLAN_HLEN;
 		} while (type == htons(ETH_P_8021Q) ||
@@ -522,11 +523,25 @@
  * Returns the EtherType of the packet, regardless of whether it is
  * vlan encapsulated (normal or hardware accelerated) or not.
  */
-static inline __be16 vlan_get_protocol(struct sk_buff *skb)
+static inline __be16 vlan_get_protocol(const struct sk_buff *skb)
 {
 	return __vlan_get_protocol(skb, skb->protocol, NULL);
 }
 
+/* A getter for the SKB protocol field which will handle VLAN tags consistently
+ * whether VLAN acceleration is enabled or not.
+ */
+static inline __be16 skb_protocol(const struct sk_buff *skb, bool skip_vlan)
+{
+	if (!skip_vlan)
+		/* VLAN acceleration strips the VLAN header from the skb and
+		 * moves it to skb->vlan_proto
+		 */
+		return skb_vlan_tag_present(skb) ? skb->vlan_proto : skb->protocol;
+
+	return vlan_get_protocol(skb);
+}
+
 static inline void vlan_set_encap_proto(struct sk_buff *skb,
 					struct vlan_hdr *vhdr)
 {
@@ -585,7 +600,7 @@
  * Returns true if the skb is tagged with multiple vlan headers, regardless
  * of whether it is hardware accelerated or not.
  */
-static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
+static inline bool skb_vlan_tagged_multi(struct sk_buff *skb)
 {
 	__be16 protocol = skb->protocol;
 
@@ -596,6 +611,9 @@
 			   protocol != htons(ETH_P_8021AD)))
 			return false;
 
+		if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN)))
+			return false;
+
 		veh = (struct vlan_ethhdr *)skb->data;
 		protocol = veh->h_vlan_encapsulated_proto;
 	}
@@ -613,18 +631,19 @@
  *
  * Returns features without unsafe ones if the skb has multiple tags.
  */
-static inline netdev_features_t vlan_features_check(const struct sk_buff *skb,
+static inline netdev_features_t vlan_features_check(struct sk_buff *skb,
 						    netdev_features_t features)
 {
-	if (skb_vlan_tagged_multi(skb))
-		features = netdev_intersect_features(features,
-						     NETIF_F_SG |
-						     NETIF_F_HIGHDMA |
-						     NETIF_F_FRAGLIST |
-						     NETIF_F_GEN_CSUM |
-						     NETIF_F_HW_VLAN_CTAG_TX |
-						     NETIF_F_HW_VLAN_STAG_TX);
-
+	if (skb_vlan_tagged_multi(skb)) {
+		/* In the case of multi-tagged packets, use a direct mask
+		 * instead of using netdev_interesect_features(), to make
+		 * sure that only devices supporting NETIF_F_HW_CSUM will
+		 * have checksum offloading support.
+		 */
+		features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM |
+			    NETIF_F_FRAGLIST | NETIF_F_HW_VLAN_CTAG_TX |
+			    NETIF_F_HW_VLAN_STAG_TX;
+	}
 	return features;
 }
 
--- linux-4.4.0.orig/include/linux/iio/adc/ad_sigma_delta.h
+++ linux-4.4.0/include/linux/iio/adc/ad_sigma_delta.h
@@ -66,6 +66,7 @@
 	bool			irq_dis;
 
 	bool			bus_locked;
+	bool			keep_cs_asserted;
 
 	uint8_t			comm;
 
@@ -111,6 +112,9 @@
 int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
 	unsigned int size, unsigned int *val);
 
+int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
+	unsigned int reset_length);
+
 int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
 	const struct iio_chan_spec *chan, int *val);
 int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
--- linux-4.4.0.orig/include/linux/iio/buffer.h
+++ linux-4.4.0/include/linux/iio/buffer.h
@@ -49,7 +49,7 @@
 	int (*request_update)(struct iio_buffer *buffer);
 
 	int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
-	int (*set_length)(struct iio_buffer *buffer, int length);
+	int (*set_length)(struct iio_buffer *buffer, unsigned int length);
 
 	void (*release)(struct iio_buffer *buffer);
 
@@ -78,8 +78,8 @@
  * @watermark:		[INTERN] number of datums to wait for poll/read.
  */
 struct iio_buffer {
-	int					length;
-	int					bytes_per_datum;
+	unsigned int				length;
+	size_t					bytes_per_datum;
 	struct attribute_group			*scan_el_attrs;
 	long					*scan_mask;
 	bool					scan_timestamp;
--- linux-4.4.0.orig/include/linux/iio/common/st_sensors.h
+++ linux-4.4.0/include/linux/iio/common/st_sensors.h
@@ -37,6 +37,7 @@
 #define ST_SENSORS_DEFAULT_AXIS_ADDR		0x20
 #define ST_SENSORS_DEFAULT_AXIS_MASK		0x07
 #define ST_SENSORS_DEFAULT_AXIS_N_BIT		3
+#define ST_SENSORS_DEFAULT_STAT_ADDR		0x27
 
 #define ST_SENSORS_MAX_NAME			17
 #define ST_SENSORS_MAX_4WAI			7
@@ -119,6 +120,11 @@
  * @addr: address of the register.
  * @mask_int1: mask to enable/disable IRQ on INT1 pin.
  * @mask_int2: mask to enable/disable IRQ on INT2 pin.
+ * @addr_ihl: address to enable/disable active low on the INT lines.
+ * @mask_ihl: mask to enable/disable active low on the INT lines.
+ * @addr_od: address to enable/disable Open Drain on the INT lines.
+ * @mask_od: mask to enable/disable Open Drain on the INT lines.
+ * @addr_stat_drdy: address to read status of DRDY (data ready) interrupt
  * struct ig1 - represents the Interrupt Generator 1 of sensors.
  * @en_addr: address of the enable ig1 register.
  * @en_mask: mask to write the on/off value for enable.
@@ -127,6 +133,11 @@
 	u8 addr;
 	u8 mask_int1;
 	u8 mask_int2;
+	u8 addr_ihl;
+	u8 mask_ihl;
+	u8 addr_od;
+	u8 mask_od;
+	u8 addr_stat_drdy;
 	struct {
 		u8 en_addr;
 		u8 en_mask;
@@ -208,9 +219,12 @@
  * @odr: Output data rate of the sensor [Hz].
  * num_data_channels: Number of data channels used in buffer.
  * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
+ * @int_pin_open_drain: Set the interrupt/DRDY to open drain.
  * @get_irq_data_ready: Function to get the IRQ used for data ready signal.
  * @tf: Transfer function structure used by I/O operations.
  * @tb: Transfer buffers and mutex used by I/O operations.
+ * @hw_irq_trigger: if we're using the hardware interrupt on the sensor.
+ * @hw_timestamp: Latest timestamp from the interrupt handler, when in use.
  */
 struct st_sensor_data {
 	struct device *dev;
@@ -229,11 +243,15 @@
 	unsigned int num_data_channels;
 
 	u8 drdy_int_pin;
+	bool int_pin_open_drain;
 
 	unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev);
 
 	const struct st_sensor_transfer_function *tf;
 	struct st_sensor_transfer_buffer tb;
+
+	bool hw_irq_trigger;
+	s64 hw_timestamp;
 };
 
 #ifdef CONFIG_IIO_BUFFER
@@ -247,7 +265,8 @@
 				const struct iio_trigger_ops *trigger_ops);
 
 void st_sensors_deallocate_trigger(struct iio_dev *indio_dev);
-
+int st_sensors_validate_device(struct iio_trigger *trig,
+			       struct iio_dev *indio_dev);
 #else
 static inline int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 				const struct iio_trigger_ops *trigger_ops)
@@ -258,6 +277,7 @@
 {
 	return;
 }
+#define st_sensors_validate_device NULL
 #endif
 
 int st_sensors_init_sensor(struct iio_dev *indio_dev,
@@ -267,7 +287,7 @@
 
 int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable);
 
-void st_sensors_power_enable(struct iio_dev *indio_dev);
+int st_sensors_power_enable(struct iio_dev *indio_dev);
 
 void st_sensors_power_disable(struct iio_dev *indio_dev);
 
--- linux-4.4.0.orig/include/linux/iio/common/st_sensors_i2c.h
+++ linux-4.4.0/include/linux/iio/common/st_sensors_i2c.h
@@ -28,4 +28,13 @@
 }
 #endif
 
+#ifdef CONFIG_ACPI
+int st_sensors_match_acpi_device(struct device *dev);
+#else
+static inline int st_sensors_match_acpi_device(struct device *dev)
+{
+	return -ENODEV;
+}
+#endif
+
 #endif /* ST_SENSORS_I2C_H */
--- linux-4.4.0.orig/include/linux/init.h
+++ linux-4.4.0/include/linux/init.h
@@ -4,6 +4,13 @@
 #include <linux/compiler.h>
 #include <linux/types.h>
 
+/* Built-in __init functions needn't be compiled with retpoline */
+#if defined(RETPOLINE) && !defined(MODULE)
+#define __noretpoline __attribute__((indirect_branch("keep")))
+#else
+#define __noretpoline
+#endif
+
 /* These macros are used to mark some functions or 
  * initialized data (doesn't apply to uninitialized data)
  * as `initialization' functions. The kernel can take this
@@ -39,7 +46,7 @@
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
-#define __init		__section(.init.text) __cold notrace
+#define __init		__section(.init.text) __cold notrace __noretpoline
 #define __initdata	__section(.init.data)
 #define __initconst	__constsection(.init.rodata)
 #define __exitdata	__section(.exit.data)
--- linux-4.4.0.orig/include/linux/init_task.h
+++ linux-4.4.0/include/linux/init_task.h
@@ -15,6 +15,8 @@
 #include <net/net_namespace.h>
 #include <linux/sched/rt.h>
 
+#include <asm/thread_info.h>
+
 #ifdef CONFIG_SMP
 # define INIT_PUSHABLE_TASKS(tsk)					\
 	.pushable_tasks = PLIST_NODE_INIT(tsk.pushable_tasks, MAX_PRIO),
@@ -183,12 +185,19 @@
 # define INIT_KASAN(tsk)
 #endif
 
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+# define INIT_TASK_TI(tsk) .thread_info = INIT_THREAD_INFO(tsk),
+#else
+# define INIT_TASK_TI(tsk)
+#endif
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
  */
 #define INIT_TASK(tsk)	\
 {									\
+	INIT_TASK_TI(tsk)						\
 	.state		= 0,						\
 	.stack		= &init_thread_info,				\
 	.usage		= ATOMIC_INIT(2),				\
--- linux-4.4.0.orig/include/linux/input.h
+++ linux-4.4.0/include/linux/input.h
@@ -529,6 +529,7 @@
 
 int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file);
 int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
+int input_ff_flush(struct input_dev *dev, struct file *file);
 
 int input_ff_create_memless(struct input_dev *dev, void *data,
 		int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
--- linux-4.4.0.orig/include/linux/intel-iommu.h
+++ linux-4.4.0/include/linux/intel-iommu.h
@@ -125,6 +125,7 @@
  * Extended Capability Register
  */
 
+#define ecap_dit(e)		((e >> 41) & 0x1)
 #define ecap_pasid(e)		((e >> 40) & 0x1)
 #define ecap_pss(e)		((e >> 35) & 0x1f)
 #define ecap_eafs(e)		((e >> 34) & 0x1)
@@ -153,8 +154,8 @@
 #define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
 #define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
 #define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
-#define DMA_TLB_IIRG(type) ((type >> 60) & 7)
-#define DMA_TLB_IAIG(val) (((val) >> 57) & 7)
+#define DMA_TLB_IIRG(type) ((type >> 60) & 3)
+#define DMA_TLB_IAIG(val) (((val) >> 57) & 3)
 #define DMA_TLB_READ_DRAIN (((u64)1) << 49)
 #define DMA_TLB_WRITE_DRAIN (((u64)1) << 48)
 #define DMA_TLB_DID(id)	(((u64)((id) & 0xffff)) << 32)
@@ -164,9 +165,9 @@
 
 /* INVALID_DESC */
 #define DMA_CCMD_INVL_GRANU_OFFSET  61
-#define DMA_ID_TLB_GLOBAL_FLUSH	(((u64)1) << 3)
-#define DMA_ID_TLB_DSI_FLUSH	(((u64)2) << 3)
-#define DMA_ID_TLB_PSI_FLUSH	(((u64)3) << 3)
+#define DMA_ID_TLB_GLOBAL_FLUSH	(((u64)1) << 4)
+#define DMA_ID_TLB_DSI_FLUSH	(((u64)2) << 4)
+#define DMA_ID_TLB_PSI_FLUSH	(((u64)3) << 4)
 #define DMA_ID_TLB_READ_DRAIN	(((u64)1) << 7)
 #define DMA_ID_TLB_WRITE_DRAIN	(((u64)1) << 6)
 #define DMA_ID_TLB_DID(id)	(((u64)((id & 0xffff) << 16)))
@@ -235,6 +236,9 @@
 /* low 64 bit */
 #define dma_frcd_page_addr(d) (d & (((u64)-1) << PAGE_SHIFT))
 
+/* PRS_REG */
+#define DMA_PRS_PPR	((u32)1)
+
 #define IOMMU_WAIT_OP(iommu, offset, op, cond, sts)			\
 do {									\
 	cycles_t start_time = get_cycles();				\
@@ -291,6 +295,8 @@
 #define QI_DEV_IOTLB_SID(sid)	((u64)((sid) & 0xffff) << 32)
 #define QI_DEV_IOTLB_QDEP(qdep)	(((qdep) & 0x1f) << 16)
 #define QI_DEV_IOTLB_ADDR(addr)	((u64)(addr) & VTD_PAGE_MASK)
+#define QI_DEV_IOTLB_PFSID(pfsid) (((u64)(pfsid & 0xf) << 12) | \
+				   ((u64)((pfsid >> 4) & 0xfff) << 52))
 #define QI_DEV_IOTLB_SIZE	1
 #define QI_DEV_IOTLB_MAX_INVS	32
 
@@ -311,10 +317,12 @@
 
 #define QI_DEV_EIOTLB_ADDR(a)	((u64)(a) & VTD_PAGE_MASK)
 #define QI_DEV_EIOTLB_SIZE	(((u64)1) << 11)
-#define QI_DEV_EIOTLB_GLOB(g)	((u64)g)
-#define QI_DEV_EIOTLB_PASID(p)	(((u64)p) << 32)
-#define QI_DEV_EIOTLB_SID(sid)	((u64)((sid) & 0xffff) << 32)
-#define QI_DEV_EIOTLB_QDEP(qd)	(((qd) & 0x1f) << 16)
+#define QI_DEV_EIOTLB_GLOB(g)	((u64)(g) & 0x1)
+#define QI_DEV_EIOTLB_PASID(p)	((u64)((p) & 0xfffff) << 32)
+#define QI_DEV_EIOTLB_SID(sid)	((u64)((sid) & 0xffff) << 16)
+#define QI_DEV_EIOTLB_QDEP(qd)	((u64)((qd) & 0x1f) << 4)
+#define QI_DEV_EIOTLB_PFSID(pfsid) (((u64)(pfsid & 0xf) << 12) | \
+				    ((u64)((pfsid >> 4) & 0xfff) << 52))
 #define QI_DEV_EIOTLB_MAX_INVS	32
 
 #define QI_PGRP_IDX(idx)	(((u64)(idx)) << 55)
@@ -426,6 +434,7 @@
 	struct page_req_dsc *prq;
 	unsigned char prq_name[16];    /* Name for PRQ interrupt */
 	struct idr pasid_idr;
+	u32 pasid_max;
 #endif
 	struct q_inval  *qi;            /* Queued invalidation info */
 	u32 *iommu_state; /* Store iommu states between suspend and resume.*/
@@ -438,6 +447,8 @@
 	struct device	*iommu_dev; /* IOMMU-sysfs device */
 	int		node;
 	u32		flags;      /* Software defined flags */
+
+	struct dmar_drhd_unit *drhd;
 };
 
 static inline void __iommu_flush_cache(
@@ -459,9 +470,8 @@
 			     u8 fm, u64 type);
 extern void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
 			  unsigned int size_order, u64 type);
-extern void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep,
-			       u64 addr, unsigned mask);
-
+extern void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid,
+			u16 qdep, u64 addr, unsigned mask);
 extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
 
 extern int dmar_ir_support(void);
--- linux-4.4.0.orig/include/linux/interrupt.h
+++ linux-4.4.0/include/linux/interrupt.h
@@ -61,6 +61,9 @@
  *                interrupt handler after suspending interrupts. For system
  *                wakeup devices users need to implement wakeup detection in
  *                their interrupt handlers.
+ * IRQF_NO_AUTOEN - Don't enable IRQ or NMI automatically when users request it.
+ *                Users will enable it explicitly by enable_irq() or enable_nmi()
+ *                later.
  */
 #define IRQF_SHARED		0x00000080
 #define IRQF_PROBE_SHARED	0x00000100
@@ -74,6 +77,7 @@
 #define IRQF_NO_THREAD		0x00010000
 #define IRQF_EARLY_RESUME	0x00020000
 #define IRQF_COND_SUSPEND	0x00040000
+#define IRQF_NO_AUTOEN		0x00080000
 
 #define IRQF_TIMER		(__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
 
--- linux-4.4.0.orig/include/linux/io.h
+++ linux-4.4.0/include/linux/io.h
@@ -154,4 +154,26 @@
 void *memremap(resource_size_t offset, size_t size, unsigned long flags);
 void memunmap(void *addr);
 
+/*
+ * On x86 PAT systems we have memory tracking that keeps track of
+ * the allowed mappings on memory ranges. This tracking works for
+ * all the in-kernel mapping APIs (ioremap*), but where the user
+ * wishes to map a range from a physical device into user memory
+ * the tracking won't be updated. This API is to be used by
+ * drivers which remap physical device pages into userspace,
+ * and wants to make sure they are mapped WC and not UC.
+ */
+#ifndef arch_io_reserve_memtype_wc
+static inline int arch_io_reserve_memtype_wc(resource_size_t base,
+					     resource_size_t size)
+{
+	return 0;
+}
+
+static inline void arch_io_free_memtype_wc(resource_size_t base,
+					   resource_size_t size)
+{
+}
+#endif
+
 #endif /* _LINUX_IO_H */
--- linux-4.4.0.orig/include/linux/ipv6.h
+++ linux-4.4.0/include/linux/ipv6.h
@@ -215,7 +215,8 @@
 						 * 100: prefer care-of address
 						 */
 				dontfrag:1,
-				autoflowlabel:1;
+				autoflowlabel:1,
+				autoflowlabel_set:1;
 	__u8			min_hopcount;
 	__u8			tclass;
 	__be32			rcv_flowinfo;
--- linux-4.4.0.orig/include/linux/irq.h
+++ linux-4.4.0/include/linux/irq.h
@@ -916,6 +916,16 @@
 static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
 #endif
 
+/*
+ * The irqsave variants are for usage in non interrupt code. Do not use
+ * them in irq_chip callbacks. Use irq_gc_lock() instead.
+ */
+#define irq_gc_lock_irqsave(gc, flags)	\
+	raw_spin_lock_irqsave(&(gc)->lock, flags)
+
+#define irq_gc_unlock_irqrestore(gc, flags)	\
+	raw_spin_unlock_irqrestore(&(gc)->lock, flags)
+
 static inline void irq_reg_writel(struct irq_chip_generic *gc,
 				  u32 val, int reg_offset)
 {
--- linux-4.4.0.orig/include/linux/irqchip/arm-gic-v3.h
+++ linux-4.4.0/include/linux/irqchip/arm-gic-v3.h
@@ -218,7 +218,7 @@
 #define GITS_BASER_TYPE_SHIFT		(56)
 #define GITS_BASER_TYPE(r)		(((r) >> GITS_BASER_TYPE_SHIFT) & 7)
 #define GITS_BASER_ENTRY_SIZE_SHIFT	(48)
-#define GITS_BASER_ENTRY_SIZE(r)	((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1)
+#define GITS_BASER_ENTRY_SIZE(r)	((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
 #define GITS_BASER_NonShareable		(0UL << 10)
 #define GITS_BASER_InnerShareable	(1UL << 10)
 #define GITS_BASER_OuterShareable	(2UL << 10)
@@ -301,7 +301,7 @@
 #define ICC_SGI1R_AFFINITY_1_SHIFT	16
 #define ICC_SGI1R_AFFINITY_1_MASK	(0xff << ICC_SGI1R_AFFINITY_1_SHIFT)
 #define ICC_SGI1R_SGI_ID_SHIFT		24
-#define ICC_SGI1R_SGI_ID_MASK		(0xff << ICC_SGI1R_SGI_ID_SHIFT)
+#define ICC_SGI1R_SGI_ID_MASK		(0xfULL << ICC_SGI1R_SGI_ID_SHIFT)
 #define ICC_SGI1R_AFFINITY_2_SHIFT	32
 #define ICC_SGI1R_AFFINITY_2_MASK	(0xffULL << ICC_SGI1R_AFFINITY_1_SHIFT)
 #define ICC_SGI1R_IRQ_ROUTING_MODE_BIT	40
--- linux-4.4.0.orig/include/linux/irqchip/arm-gic.h
+++ linux-4.4.0/include/linux/irqchip/arm-gic.h
@@ -106,7 +106,8 @@
 void gic_init(unsigned int nr, int start,
 	      void __iomem *dist , void __iomem *cpu);
 
-int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
+int gicv2m_init(struct fwnode_handle *parent_handle,
+		struct irq_domain *parent);
 
 void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
 int gic_get_cpu_id(unsigned int cpu);
--- linux-4.4.0.orig/include/linux/irqdomain.h
+++ linux-4.4.0/include/linux/irqdomain.h
@@ -211,6 +211,11 @@
 	return node ? &node->fwnode : NULL;
 }
 
+static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode)
+{
+	return fwnode && fwnode->type == FWNODE_IRQCHIP;
+}
+
 static inline struct irq_domain *irq_find_matching_host(struct device_node *node,
 							enum irq_domain_bus_token bus_token)
 {
@@ -410,6 +415,11 @@
 static inline void irq_dispose_mapping(unsigned int virq) { }
 static inline void irq_domain_activate_irq(struct irq_data *data) { }
 static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
+static inline struct irq_domain *irq_find_matching_fwnode(
+	struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token)
+{
+	return NULL;
+}
 #endif /* !CONFIG_IRQ_DOMAIN */
 
 #endif /* _LINUX_IRQDOMAIN_H */
--- linux-4.4.0.orig/include/linux/jbd2.h
+++ linux-4.4.0/include/linux/jbd2.h
@@ -1440,7 +1440,7 @@
 static inline unsigned long jbd2_log_space_left(journal_t *journal)
 {
 	/* Allow for rounding errors */
-	unsigned long free = journal->j_free - 32;
+	long free = journal->j_free - 32;
 
 	if (journal->j_committing_transaction) {
 		unsigned long committing = atomic_read(&journal->
@@ -1449,7 +1449,7 @@
 		/* Transaction + control blocks */
 		free -= committing + (committing >> JBD2_CONTROL_BLOCKS_SHIFT);
 	}
-	return free;
+	return max_t(long, free, 0);
 }
 
 /*
--- linux-4.4.0.orig/include/linux/jiffies.h
+++ linux-4.4.0/include/linux/jiffies.h
@@ -1,6 +1,7 @@
 #ifndef _LINUX_JIFFIES_H
 #define _LINUX_JIFFIES_H
 
+#include <linux/cache.h>
 #include <linux/math64.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -63,19 +64,17 @@
 /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
 #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
 
-/* some arch's have a small-data section that can be accessed register-relative
- * but that can only take up to, say, 4-byte variables. jiffies being part of
- * an 8-byte variable may not be correctly accessed unless we force the issue
- */
-#define __jiffy_data  __attribute__((section(".data")))
+#ifndef __jiffy_arch_data
+#define __jiffy_arch_data
+#endif
 
 /*
  * The 64-bit value is not atomic - you MUST NOT read it
  * without sampling the sequence number in jiffies_lock.
  * get_jiffies_64() will do this for you as appropriate.
  */
-extern u64 __jiffy_data jiffies_64;
-extern unsigned long volatile __jiffy_data jiffies;
+extern u64 __cacheline_aligned_in_smp jiffies_64;
+extern unsigned long volatile __cacheline_aligned_in_smp __jiffy_arch_data jiffies;
 
 #if (BITS_PER_LONG < 64)
 u64 get_jiffies_64(void);
@@ -289,6 +288,8 @@
 	return (u64)jiffies_to_usecs(j) * NSEC_PER_USEC;
 }
 
+extern u64 jiffies64_to_nsecs(u64 j);
+
 extern unsigned long __msecs_to_jiffies(const unsigned int m);
 #if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
 /*
--- linux-4.4.0.orig/include/linux/jump_label.h
+++ linux-4.4.0/include/linux/jump_label.h
@@ -117,13 +117,18 @@
 
 #include <linux/atomic.h>
 
+#ifdef HAVE_JUMP_LABEL
+
 static inline int static_key_count(struct static_key *key)
 {
-	return atomic_read(&key->enabled);
+	/*
+	 * -1 means the first static_key_slow_inc() is in progress.
+	 *  static_key_enabled() must return true, so return 1 here.
+	 */
+	int n = atomic_read(&key->enabled);
+	return n >= 0 ? n : 1;
 }
 
-#ifdef HAVE_JUMP_LABEL
-
 #define JUMP_TYPE_FALSE	0UL
 #define JUMP_TYPE_TRUE	1UL
 #define JUMP_TYPE_MASK	1UL
@@ -162,6 +167,11 @@
 
 #else  /* !HAVE_JUMP_LABEL */
 
+static inline int static_key_count(struct static_key *key)
+{
+	return atomic_read(&key->enabled);
+}
+
 static __always_inline void jump_label_init(void)
 {
 	static_key_initialized = true;
@@ -257,9 +267,15 @@
 #define DEFINE_STATIC_KEY_TRUE(name)	\
 	struct static_key_true name = STATIC_KEY_TRUE_INIT
 
+#define DECLARE_STATIC_KEY_TRUE(name)	\
+	extern struct static_key_true name
+
 #define DEFINE_STATIC_KEY_FALSE(name)	\
 	struct static_key_false name = STATIC_KEY_FALSE_INIT
 
+#define DECLARE_STATIC_KEY_FALSE(name)	\
+	extern struct static_key_false name
+
 extern bool ____wrong_branch_error(void);
 
 #define static_key_enabled(x)							\
--- linux-4.4.0.orig/include/linux/jump_label_ratelimit.h
+++ linux-4.4.0/include/linux/jump_label_ratelimit.h
@@ -14,6 +14,7 @@
 
 #ifdef HAVE_JUMP_LABEL
 extern void static_key_slow_dec_deferred(struct static_key_deferred *key);
+extern void static_key_deferred_flush(struct static_key_deferred *key);
 extern void
 jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl);
 
@@ -26,6 +27,10 @@
 	STATIC_KEY_CHECK_USE();
 	static_key_slow_dec(&key->key);
 }
+static inline void static_key_deferred_flush(struct static_key_deferred *key)
+{
+	STATIC_KEY_CHECK_USE();
+}
 static inline void
 jump_label_rate_limit(struct static_key_deferred *key,
 		unsigned long rl)
--- linux-4.4.0.orig/include/linux/kaiser.h
+++ linux-4.4.0/include/linux/kaiser.h
@@ -0,0 +1,52 @@
+#ifndef _LINUX_KAISER_H
+#define _LINUX_KAISER_H
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#include <asm/kaiser.h>
+
+static inline int kaiser_map_thread_stack(void *stack)
+{
+	/*
+	 * Map that page of kernel stack on which we enter from user context.
+	 */
+	return kaiser_add_mapping((unsigned long)stack +
+			THREAD_SIZE - PAGE_SIZE, PAGE_SIZE, __PAGE_KERNEL);
+}
+
+static inline void kaiser_unmap_thread_stack(void *stack)
+{
+	/*
+	 * Note: may be called even when kaiser_map_thread_stack() failed.
+	 */
+	kaiser_remove_mapping((unsigned long)stack +
+			THREAD_SIZE - PAGE_SIZE, PAGE_SIZE);
+}
+#else
+
+/*
+ * These stubs are used whenever CONFIG_PAGE_TABLE_ISOLATION is off, which
+ * includes architectures that support KAISER, but have it disabled.
+ */
+
+static inline void kaiser_init(void)
+{
+}
+static inline int kaiser_add_mapping(unsigned long addr,
+				     unsigned long size, u64 flags)
+{
+	return 0;
+}
+static inline void kaiser_remove_mapping(unsigned long start,
+					 unsigned long size)
+{
+}
+static inline int kaiser_map_thread_stack(void *stack)
+{
+	return 0;
+}
+static inline void kaiser_unmap_thread_stack(void *stack)
+{
+}
+
+#endif /* !CONFIG_PAGE_TABLE_ISOLATION */
+#endif /* _LINUX_KAISER_H */
--- linux-4.4.0.orig/include/linux/kasan-checks.h
+++ linux-4.4.0/include/linux/kasan-checks.h
@@ -0,0 +1,12 @@
+#ifndef _LINUX_KASAN_CHECKS_H
+#define _LINUX_KASAN_CHECKS_H
+
+#ifdef CONFIG_KASAN
+void kasan_check_read(const void *p, unsigned int size);
+void kasan_check_write(const void *p, unsigned int size);
+#else
+static inline void kasan_check_read(const void *p, unsigned int size) { }
+static inline void kasan_check_write(const void *p, unsigned int size) { }
+#endif
+
+#endif
--- linux-4.4.0.orig/include/linux/kbuild.h
+++ linux-4.4.0/include/linux/kbuild.h
@@ -2,14 +2,14 @@
 #define __LINUX_KBUILD_H
 
 #define DEFINE(sym, val) \
-        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+	asm volatile("\n.ascii \"->" #sym " %0 " #val "\"" : : "i" (val))
 
-#define BLANK() asm volatile("\n->" : : )
+#define BLANK() asm volatile("\n.ascii \"->\"" : : )
 
 #define OFFSET(sym, str, mem) \
 	DEFINE(sym, offsetof(struct str, mem))
 
 #define COMMENT(x) \
-	asm volatile("\n->#" x)
+	asm volatile("\n.ascii \"->#" x "\"")
 
 #endif
--- linux-4.4.0.orig/include/linux/kconfig.h
+++ linux-4.4.0/include/linux/kconfig.h
@@ -17,10 +17,11 @@
  * the last step cherry picks the 2nd arg, we get a zero.
  */
 #define __ARG_PLACEHOLDER_1 0,
-#define config_enabled(cfg) _config_enabled(cfg)
-#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
-#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
-#define ___config_enabled(__ignored, val, ...) val
+#define config_enabled(cfg)		___is_defined(cfg)
+#define __is_defined(x)			___is_defined(x)
+#define ___is_defined(val)		____is_defined(__ARG_PLACEHOLDER_##val)
+#define ____is_defined(arg1_or_junk)	__take_second_arg(arg1_or_junk 1, 0)
+#define __take_second_arg(__ignored, val, ...) val
 
 /*
  * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
@@ -42,7 +43,7 @@
  * built-in code when CONFIG_FOO is set to 'm'.
  */
 #define IS_REACHABLE(option) (config_enabled(option) || \
-		 (config_enabled(option##_MODULE) && config_enabled(MODULE)))
+		 (config_enabled(option##_MODULE) && __is_defined(MODULE)))
 
 /*
  * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
--- linux-4.4.0.orig/include/linux/kernel.h
+++ linux-4.4.0/include/linux/kernel.h
@@ -65,8 +65,11 @@
 
 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-#define DIV_ROUND_UP_ULL(ll,d) \
-	({ unsigned long long _tmp = (ll)+(d)-1; do_div(_tmp, d); _tmp; })
+
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+	({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+
+#define DIV_ROUND_UP_ULL(ll, d)		DIV_ROUND_DOWN_ULL((ll) + (d) - 1, (d))
 
 #if BITS_PER_LONG == 32
 # define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d)
@@ -202,26 +205,26 @@
 
 /**
  * abs - return absolute value of an argument
- * @x: the value.  If it is unsigned type, it is converted to signed type first
- *   (s64, long or int depending on its size).
- *
- * Return: an absolute value of x.  If x is 64-bit, macro's return type is s64,
- *   otherwise it is signed long.
- */
-#define abs(x) __builtin_choose_expr(sizeof(x) == sizeof(s64), ({	\
-		s64 __x = (x);						\
-		(__x < 0) ? -__x : __x;					\
-	}), ({								\
-		long ret;						\
-		if (sizeof(x) == sizeof(long)) {			\
-			long __x = (x);					\
-			ret = (__x < 0) ? -__x : __x;			\
-		} else {						\
-			int __x = (x);					\
-			ret = (__x < 0) ? -__x : __x;			\
-		}							\
-		ret;							\
-	}))
+ * @x: the value.  If it is unsigned type, it is converted to signed type first.
+ *     char is treated as if it was signed (regardless of whether it really is)
+ *     but the macro's return type is preserved as char.
+ *
+ * Return: an absolute value of x.
+ */
+#define abs(x)	__abs_choose_expr(x, long long,				\
+		__abs_choose_expr(x, long,				\
+		__abs_choose_expr(x, int,				\
+		__abs_choose_expr(x, short,				\
+		__abs_choose_expr(x, char,				\
+		__builtin_choose_expr(					\
+			__builtin_types_compatible_p(typeof(x), char),	\
+			(char)({ signed char __x = (x); __x<0?-__x:__x; }), \
+			((void)0)))))))
+
+#define __abs_choose_expr(x, type, other) __builtin_choose_expr(	\
+	__builtin_types_compatible_p(typeof(x),   signed type) ||	\
+	__builtin_types_compatible_p(typeof(x), unsigned type),		\
+	({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)
 
 /**
  * reciprocal_scale - "scale" a value into range [0, ep_ro)
@@ -356,6 +359,7 @@
 int __must_check kstrtos16(const char *s, unsigned int base, s16 *res);
 int __must_check kstrtou8(const char *s, unsigned int base, u8 *res);
 int __must_check kstrtos8(const char *s, unsigned int base, s8 *res);
+int __must_check kstrtobool(const char *s, bool *res);
 
 int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res);
 int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res);
@@ -367,6 +371,7 @@
 int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res);
 int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res);
 int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
+int __must_check kstrtobool_from_user(const char __user *s, size_t count, bool *res);
 
 static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res)
 {
@@ -607,7 +612,7 @@
 
 #define do_trace_printk(fmt, args...)					\
 do {									\
-	static const char *trace_printk_fmt				\
+	static const char *trace_printk_fmt __used			\
 		__attribute__((section("__trace_printk_fmt"))) =	\
 		__builtin_constant_p(fmt) ? fmt : NULL;			\
 									\
@@ -651,7 +656,7 @@
  */
 
 #define trace_puts(str) ({						\
-	static const char *trace_printk_fmt				\
+	static const char *trace_printk_fmt __used			\
 		__attribute__((section("__trace_printk_fmt"))) =	\
 		__builtin_constant_p(str) ? str : NULL;			\
 									\
@@ -673,7 +678,7 @@
 #define ftrace_vprintk(fmt, vargs)					\
 do {									\
 	if (__builtin_constant_p(fmt)) {				\
-		static const char *trace_printk_fmt			\
+		static const char *trace_printk_fmt __used		\
 		  __attribute__((section("__trace_printk_fmt"))) =	\
 			__builtin_constant_p(fmt) ? fmt : NULL;		\
 									\
--- linux-4.4.0.orig/include/linux/kernfs.h
+++ linux-4.4.0/include/linux/kernfs.h
@@ -152,6 +152,8 @@
 	int (*rmdir)(struct kernfs_node *kn);
 	int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent,
 		      const char *new_name);
+	int (*show_path)(struct seq_file *sf, struct kernfs_node *kn,
+			 struct kernfs_root *root);
 };
 
 struct kernfs_root {
@@ -267,8 +269,9 @@
 
 int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen);
 size_t kernfs_path_len(struct kernfs_node *kn);
-char * __must_check kernfs_path(struct kernfs_node *kn, char *buf,
-				size_t buflen);
+int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn,
+			  char *buf, size_t buflen);
+char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen);
 void pr_cont_kernfs_name(struct kernfs_node *kn);
 void pr_cont_kernfs_path(struct kernfs_node *kn);
 struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn);
@@ -281,6 +284,8 @@
 struct kernfs_root *kernfs_root_from_sb(struct super_block *sb);
 struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn);
 
+struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+				  struct super_block *sb);
 struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
 				       unsigned int flags, void *priv);
 void kernfs_destroy_root(struct kernfs_root *root);
@@ -336,8 +341,8 @@
 static inline size_t kernfs_path_len(struct kernfs_node *kn)
 { return 0; }
 
-static inline char * __must_check kernfs_path(struct kernfs_node *kn, char *buf,
-					      size_t buflen)
+static inline char *kernfs_path(struct kernfs_node *kn, char *buf,
+				size_t buflen)
 { return NULL; }
 
 static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { }
--- linux-4.4.0.orig/include/linux/key.h
+++ linux-4.4.0/include/linux/key.h
@@ -126,6 +126,11 @@
 	return (unsigned long) key_ref & 1UL;
 }
 
+enum key_state {
+	KEY_IS_UNINSTANTIATED,
+	KEY_IS_POSITIVE,		/* Positively instantiated */
+};
+
 /*****************************************************************************/
 /*
  * authentication token / access credential / keyring
@@ -157,6 +162,7 @@
 						 * - may not match RCU dereferenced payload
 						 * - payload should contain own length
 						 */
+	short			state;		/* Key state (+) or rejection error (-) */
 
 #ifdef KEY_DEBUGGING
 	unsigned		magic;
@@ -165,18 +171,17 @@
 #endif
 
 	unsigned long		flags;		/* status flags (change with bitops) */
-#define KEY_FLAG_INSTANTIATED	0	/* set if key has been instantiated */
-#define KEY_FLAG_DEAD		1	/* set if key type has been deleted */
-#define KEY_FLAG_REVOKED	2	/* set if key had been revoked */
-#define KEY_FLAG_IN_QUOTA	3	/* set if key consumes quota */
-#define KEY_FLAG_USER_CONSTRUCT	4	/* set if key is being constructed in userspace */
-#define KEY_FLAG_NEGATIVE	5	/* set if key is negative */
-#define KEY_FLAG_ROOT_CAN_CLEAR	6	/* set if key can be cleared by root without permission */
-#define KEY_FLAG_INVALIDATED	7	/* set if key has been invalidated */
-#define KEY_FLAG_TRUSTED	8	/* set if key is trusted */
-#define KEY_FLAG_TRUSTED_ONLY	9	/* set if keyring only accepts links to trusted keys */
-#define KEY_FLAG_BUILTIN	10	/* set if key is builtin */
-#define KEY_FLAG_ROOT_CAN_INVAL	11	/* set if key can be invalidated by root without permission */
+#define KEY_FLAG_DEAD		0	/* set if key type has been deleted */
+#define KEY_FLAG_REVOKED	1	/* set if key had been revoked */
+#define KEY_FLAG_IN_QUOTA	2	/* set if key consumes quota */
+#define KEY_FLAG_USER_CONSTRUCT	3	/* set if key is being constructed in userspace */
+#define KEY_FLAG_ROOT_CAN_CLEAR	4	/* set if key can be cleared by root without permission */
+#define KEY_FLAG_INVALIDATED	5	/* set if key has been invalidated */
+#define KEY_FLAG_TRUSTED	6	/* set if key is trusted */
+#define KEY_FLAG_TRUSTED_ONLY	7	/* set if keyring only accepts links to trusted keys */
+#define KEY_FLAG_BUILTIN	8	/* set if key is builtin */
+#define KEY_FLAG_ROOT_CAN_INVAL	9	/* set if key can be invalidated by root without permission */
+#define KEY_FLAG_UID_KEYRING	10	/* set if key is a user or user session keyring */
 
 	/* the key type and key description string
 	 * - the desc is used to match a key against search criteria
@@ -202,7 +207,6 @@
 			struct list_head name_link;
 			struct assoc_array keys;
 		};
-		int reject_error;
 	};
 };
 
@@ -218,6 +222,8 @@
 #define KEY_ALLOC_QUOTA_OVERRUN	0x0001	/* add to quota, permit even if overrun */
 #define KEY_ALLOC_NOT_IN_QUOTA	0x0002	/* not in quota */
 #define KEY_ALLOC_TRUSTED	0x0004	/* Key should be flagged as trusted */
+#define KEY_ALLOC_BUILT_IN	0x0008	/* Key is built into kernel */
+#define KEY_ALLOC_UID_KEYRING	0x0010  /* allocating a user or user session keyring */
 
 extern void key_revoke(struct key *key);
 extern void key_invalidate(struct key *key);
@@ -317,17 +323,27 @@
 #define	KEY_NEED_SETATTR 0x20	/* Require permission to change attributes */
 #define	KEY_NEED_ALL	0x3f	/* All the above permissions */
 
+static inline short key_read_state(const struct key *key)
+{
+	/* Barrier versus mark_key_instantiated(). */
+	return smp_load_acquire(&key->state);
+}
+
 /**
- * key_is_instantiated - Determine if a key has been positively instantiated
+ * key_is_positive - Determine if a key has been positively instantiated
  * @key: The key to check.
  *
  * Return true if the specified key has been positively instantiated, false
  * otherwise.
  */
-static inline bool key_is_instantiated(const struct key *key)
+static inline bool key_is_positive(const struct key *key)
+{
+	return key_read_state(key) == KEY_IS_POSITIVE;
+}
+
+static inline bool key_is_negative(const struct key *key)
 {
-	return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
-		!test_bit(KEY_FLAG_NEGATIVE, &key->flags);
+	return key_read_state(key) < 0;
 }
 
 #define rcu_dereference_key(KEY)					\
--- linux-4.4.0.orig/include/linux/kgdb.h
+++ linux-4.4.0/include/linux/kgdb.h
@@ -317,7 +317,7 @@
 extern int			kgdb_single_step;
 extern atomic_t			kgdb_active;
 #define in_dbg_master() \
-	(raw_smp_processor_id() == atomic_read(&kgdb_active))
+	(irqs_disabled() && (smp_processor_id() == atomic_read(&kgdb_active)))
 extern bool dbg_is_early;
 extern void __init dbg_late_init(void);
 #else /* ! CONFIG_KGDB */
--- linux-4.4.0.orig/include/linux/kobject.h
+++ linux-4.4.0/include/linux/kobject.h
@@ -108,11 +108,30 @@
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern struct kobject *kobject_get(struct kobject *kobj);
+extern struct kobject * __must_check kobject_get_unless_zero(
+						struct kobject *kobj);
 extern void kobject_put(struct kobject *kobj);
 
 extern const void *kobject_namespace(struct kobject *kobj);
 extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);
 
+/**
+ * kobject_has_children - Returns whether a kobject has children.
+ * @kobj: the object to test
+ *
+ * This will return whether a kobject has other kobjects as children.
+ *
+ * It does NOT account for the presence of attribute files, only sub
+ * directories. It also assumes there is no concurrent addition or
+ * removal of such children, and thus relies on external locking.
+ */
+static inline bool kobject_has_children(struct kobject *kobj)
+{
+	WARN_ON_ONCE(atomic_read(&kobj->kref.refcount) == 0);
+
+	return kobj->sd && kobj->sd->dir.subdirs;
+}
+
 struct kobj_type {
 	void (*release)(struct kobject *kobj);
 	const struct sysfs_ops *sysfs_ops;
--- linux-4.4.0.orig/include/linux/kprobes.h
+++ linux-4.4.0/include/linux/kprobes.h
@@ -197,6 +197,7 @@
 	struct kretprobe *rp;
 	kprobe_opcode_t *ret_addr;
 	struct task_struct *task;
+	void *fp;
 	char data[0];
 };
 
@@ -330,7 +331,9 @@
 					     int write, void __user *buffer,
 					     size_t *length, loff_t *ppos);
 #endif
-
+extern void wait_for_kprobe_optimizer(void);
+#else
+static inline void wait_for_kprobe_optimizer(void) { }
 #endif /* CONFIG_OPTPROBES */
 #ifdef CONFIG_KPROBES_ON_FTRACE
 extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
@@ -363,6 +366,10 @@
 	return this_cpu_ptr(&kprobe_ctlblk);
 }
 
+extern struct kprobe kprobe_busy;
+void kprobe_busy_begin(void);
+void kprobe_busy_end(void);
+
 int register_kprobe(struct kprobe *p);
 void unregister_kprobe(struct kprobe *p);
 int register_kprobes(struct kprobe **kps, int num);
--- linux-4.4.0.orig/include/linux/kref.h
+++ linux-4.4.0/include/linux/kref.h
@@ -33,6 +33,11 @@
 	atomic_set(&kref->refcount, 1);
 }
 
+static inline int kref_read(const struct kref *kref)
+{
+	return atomic_read(&kref->refcount);
+}
+
 /**
  * kref_get - increment refcount for object.
  * @kref: object.
--- linux-4.4.0.orig/include/linux/ktime.h
+++ linux-4.4.0/include/linux/ktime.h
@@ -64,6 +64,13 @@
 		({ (ktime_t){ .tv64 = (lhs).tv64 + (rhs).tv64 }; })
 
 /*
+ * Same as ktime_add(), but avoids undefined behaviour on overflow; however,
+ * this means that you must check the result for overflow yourself.
+ */
+#define ktime_add_unsafe(lhs, rhs) \
+		({ (ktime_t){ .tv64 = (u64) (lhs).tv64 + (rhs).tv64 }; })
+
+/*
  * Add a ktime_t variable and a scalar nanosecond value.
  * res = kt + nsval:
  */
--- linux-4.4.0.orig/include/linux/kvm_host.h
+++ linux-4.4.0/include/linux/kvm_host.h
@@ -143,13 +143,15 @@
 #define KVM_REQ_HV_CRASH          27
 #define KVM_REQ_IOAPIC_EOI_EXIT   28
 #define KVM_REQ_HV_RESET          29
+#define KVM_REQ_HV_EXIT           30
+#define KVM_REQ_HV_STIMER         31
 
 #define KVM_USERSPACE_IRQ_SOURCE_ID		0
 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID	1
 
 extern struct kmem_cache *kvm_vcpu_cache;
 
-extern spinlock_t kvm_lock;
+extern struct mutex kvm_lock;
 extern struct list_head vm_list;
 
 struct kvm_io_range {
@@ -182,8 +184,8 @@
 		    int len, void *val);
 int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 			    int len, struct kvm_io_device *dev);
-int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
-			      struct kvm_io_device *dev);
+void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+			       struct kvm_io_device *dev);
 
 #ifdef CONFIG_KVM_ASYNC_PF
 struct kvm_async_pf {
@@ -318,6 +320,11 @@
 	u32 adapter_id;
 };
 
+struct kvm_hv_sint {
+	u32 vcpu;
+	u32 sint;
+};
+
 struct kvm_kernel_irq_routing_entry {
 	u32 gsi;
 	u32 type;
@@ -331,6 +338,7 @@
 		} irqchip;
 		struct msi_msg msi;
 		struct kvm_s390_adapter_int adapter;
+		struct kvm_hv_sint hv_sint;
 	};
 	struct hlist_node link;
 };
@@ -443,6 +451,8 @@
 
 #define vcpu_debug(vcpu, fmt, ...)					\
 	kvm_debug("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
+#define vcpu_err(vcpu, fmt, ...)					\
+	kvm_err("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
 
 static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
 {
@@ -484,12 +494,12 @@
 
 #ifdef __KVM_HAVE_IOAPIC
 void kvm_vcpu_request_scan_ioapic(struct kvm *kvm);
-void kvm_arch_irq_routing_update(struct kvm *kvm);
+void kvm_arch_post_irq_routing_update(struct kvm *kvm);
 #else
 static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm)
 {
 }
-static inline void kvm_arch_irq_routing_update(struct kvm *kvm)
+static inline void kvm_arch_post_irq_routing_update(struct kvm *kvm)
 {
 }
 #endif
@@ -934,7 +944,7 @@
 			start = slot + 1;
 	}
 
-	if (gfn >= memslots[start].base_gfn &&
+	if (start < slots->used_slots && gfn >= memslots[start].base_gfn &&
 	    gfn < memslots[start].base_gfn + memslots[start].npages) {
 		atomic_set(&slots->lru_slot, start);
 		return &memslots[start];
@@ -1091,6 +1101,7 @@
 {
 }
 #endif
+void kvm_arch_irq_routing_update(struct kvm *kvm);
 
 static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
 {
@@ -1195,4 +1206,10 @@
 				  uint32_t guest_irq, bool set);
 #endif /* CONFIG_HAVE_KVM_IRQ_BYPASS */
 
+typedef int (*kvm_vm_thread_fn_t)(struct kvm *kvm, uintptr_t data);
+
+int kvm_vm_create_worker_thread(struct kvm *kvm, kvm_vm_thread_fn_t thread_fn,
+				uintptr_t data, const char *name,
+				struct task_struct **thread_ptr);
+
 #endif
--- linux-4.4.0.orig/include/linux/libata.h
+++ linux-4.4.0/include/linux/libata.h
@@ -38,6 +38,7 @@
 #include <linux/acpi.h>
 #include <linux/cdrom.h>
 #include <linux/sched.h>
+#include <linux/async.h>
 
 /*
  * Define if arch has non-standard setup.  This is a _PCI_ standard
@@ -210,6 +211,7 @@
 	ATA_FLAG_SLAVE_POSS	= (1 << 0), /* host supports slave dev */
 					    /* (doesn't imply presence) */
 	ATA_FLAG_SATA		= (1 << 1),
+	ATA_FLAG_NO_LPM		= (1 << 2), /* host not happy with LPM */
 	ATA_FLAG_NO_LOG_PAGE	= (1 << 5), /* do not issue log page read */
 	ATA_FLAG_NO_ATAPI	= (1 << 6), /* No ATAPI support */
 	ATA_FLAG_PIO_DMA	= (1 << 7), /* PIO cmds via DMA */
@@ -498,6 +500,7 @@
 };
 
 enum ata_completion_errors {
+	AC_ERR_OK		= 0,	    /* no error */
 	AC_ERR_DEV		= (1 << 0), /* device reported error */
 	AC_ERR_HSM		= (1 << 1), /* host state machine violation */
 	AC_ERR_TIMEOUT		= (1 << 2), /* timeout */
@@ -718,7 +721,7 @@
 	union {
 		u16		id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
 		u32		gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
-	};
+	} ____cacheline_aligned;
 
 	/* DEVSLP Timing Variables from Identify Device Data Log */
 	u8			devslp_timing[ATA_LOG_DEVSLP_SIZE];
@@ -871,6 +874,8 @@
 	struct timer_list	fastdrain_timer;
 	unsigned long		fastdrain_cnt;
 
+	async_cookie_t		cookie;
+
 	int			em_message_type;
 	void			*private_data;
 
@@ -892,9 +897,9 @@
 	/*
 	 * Command execution
 	 */
-	int  (*qc_defer)(struct ata_queued_cmd *qc);
-	int  (*check_atapi_dma)(struct ata_queued_cmd *qc);
-	void (*qc_prep)(struct ata_queued_cmd *qc);
+	int (*qc_defer)(struct ata_queued_cmd *qc);
+	int (*check_atapi_dma)(struct ata_queued_cmd *qc);
+	enum ata_completion_errors (*qc_prep)(struct ata_queued_cmd *qc);
 	unsigned int (*qc_issue)(struct ata_queued_cmd *qc);
 	bool (*qc_fill_rtf)(struct ata_queued_cmd *qc);
 
@@ -1186,7 +1191,7 @@
 extern const char *ata_mode_string(unsigned long xfer_mask);
 extern unsigned long ata_id_xfermask(const u16 *id);
 extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
-extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
+extern enum ata_completion_errors ata_noop_qc_prep(struct ata_queued_cmd *qc);
 extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
 		 unsigned int n_elem);
 extern unsigned int ata_dev_classify(const struct ata_taskfile *tf);
@@ -1877,9 +1882,9 @@
 	.sg_tablesize		= LIBATA_MAX_PRD,		\
 	.dma_boundary		= ATA_DMA_BOUNDARY
 
-extern void ata_bmdma_qc_prep(struct ata_queued_cmd *qc);
+extern enum ata_completion_errors ata_bmdma_qc_prep(struct ata_queued_cmd *qc);
 extern unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc);
-extern void ata_bmdma_dumb_qc_prep(struct ata_queued_cmd *qc);
+extern enum ata_completion_errors ata_bmdma_dumb_qc_prep(struct ata_queued_cmd *qc);
 extern unsigned int ata_bmdma_port_intr(struct ata_port *ap,
 				      struct ata_queued_cmd *qc);
 extern irqreturn_t ata_bmdma_interrupt(int irq, void *dev_instance);
--- linux-4.4.0.orig/include/linux/libfdt_env.h
+++ linux-4.4.0/include/linux/libfdt_env.h
@@ -1,10 +1,14 @@
 #ifndef _LIBFDT_ENV_H
 #define _LIBFDT_ENV_H
 
+#include <linux/kernel.h>	/* For INT_MAX */
 #include <linux/string.h>
 
 #include <asm/byteorder.h>
 
+#define INT32_MAX	S32_MAX
+#define UINT32_MAX	U32_MAX
+
 typedef __be16 fdt16_t;
 typedef __be32 fdt32_t;
 typedef __be64 fdt64_t;
--- linux-4.4.0.orig/include/linux/libnvdimm.h
+++ linux-4.4.0/include/linux/libnvdimm.h
@@ -83,6 +83,8 @@
 
 struct nd_interleave_set {
 	u64 cookie;
+	/* compatibility with initial buggy Linux implementation */
+	u64 altcookie;
 };
 
 struct nd_region_desc {
--- linux-4.4.0.orig/include/linux/lightnvm.h
+++ linux-4.4.0/include/linux/lightnvm.h
@@ -1,6 +1,8 @@
 #ifndef NVM_H
 #define NVM_H
 
+#include <linux/types.h>
+
 enum {
 	NVM_IO_OK = 0,
 	NVM_IO_REQUEUE = 1,
@@ -11,12 +13,74 @@
 	NVM_IOTYPE_GC = 1,
 };
 
+#define NVM_BLK_BITS (16)
+#define NVM_PG_BITS  (16)
+#define NVM_SEC_BITS (8)
+#define NVM_PL_BITS  (8)
+#define NVM_LUN_BITS (8)
+#define NVM_CH_BITS  (8)
+
+struct ppa_addr {
+	/* Generic structure for all addresses */
+	union {
+		struct {
+			u64 blk		: NVM_BLK_BITS;
+			u64 pg		: NVM_PG_BITS;
+			u64 sec		: NVM_SEC_BITS;
+			u64 pl		: NVM_PL_BITS;
+			u64 lun		: NVM_LUN_BITS;
+			u64 ch		: NVM_CH_BITS;
+		} g;
+
+		u64 ppa;
+	};
+};
+
+struct nvm_rq;
+struct nvm_id;
+struct nvm_dev;
+
+typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
+typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *);
+typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
+typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32,
+				nvm_l2p_update_fn *, void *);
+typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, int,
+				nvm_bb_update_fn *, void *);
+typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int);
+typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
+typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *);
+typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *);
+typedef void (nvm_destroy_dma_pool_fn)(void *);
+typedef void *(nvm_dev_dma_alloc_fn)(struct nvm_dev *, void *, gfp_t,
+								dma_addr_t *);
+typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t);
+
+struct nvm_dev_ops {
+	nvm_id_fn		*identity;
+	nvm_get_l2p_tbl_fn	*get_l2p_tbl;
+	nvm_op_bb_tbl_fn	*get_bb_tbl;
+	nvm_op_set_bb_fn	*set_bb_tbl;
+
+	nvm_submit_io_fn	*submit_io;
+	nvm_erase_blk_fn	*erase_block;
+
+	nvm_create_dma_pool_fn	*create_dma_pool;
+	nvm_destroy_dma_pool_fn	*destroy_dma_pool;
+	nvm_dev_dma_alloc_fn	*dev_dma_alloc;
+	nvm_dev_dma_free_fn	*dev_dma_free;
+
+	unsigned int		max_phys_sect;
+};
+
+
+
 #ifdef CONFIG_NVM
 
 #include <linux/blkdev.h>
-#include <linux/types.h>
 #include <linux/file.h>
 #include <linux/dmapool.h>
+#include <uapi/linux/lightnvm.h>
 
 enum {
 	/* HW Responsibilities */
@@ -58,8 +122,29 @@
 	/* Block Types */
 	NVM_BLK_T_FREE		= 0x0,
 	NVM_BLK_T_BAD		= 0x1,
-	NVM_BLK_T_DEV		= 0x2,
-	NVM_BLK_T_HOST		= 0x4,
+	NVM_BLK_T_GRWN_BAD	= 0x2,
+	NVM_BLK_T_DEV		= 0x4,
+	NVM_BLK_T_HOST		= 0x8,
+
+	/* Memory capabilities */
+	NVM_ID_CAP_SLC		= 0x1,
+	NVM_ID_CAP_CMD_SUSPEND	= 0x2,
+	NVM_ID_CAP_SCRAMBLE	= 0x4,
+	NVM_ID_CAP_ENCRYPT	= 0x8,
+
+	/* Memory types */
+	NVM_ID_FMTYPE_SLC	= 0,
+	NVM_ID_FMTYPE_MLC	= 1,
+};
+
+struct nvm_id_lp_mlc {
+	u16	num_pairs;
+	u8	pairs[886];
+};
+
+struct nvm_id_lp_tbl {
+	__u8	id[8];
+	struct nvm_id_lp_mlc mlc;
 };
 
 struct nvm_id_group {
@@ -82,6 +167,8 @@
 	u32	mpos;
 	u32	mccap;
 	u16	cpar;
+
+	struct nvm_id_lp_tbl lptbl;
 };
 
 struct nvm_addr_format {
@@ -125,28 +212,8 @@
 #define NVM_VERSION_MINOR 0
 #define NVM_VERSION_PATCH 0
 
-#define NVM_BLK_BITS (16)
-#define NVM_PG_BITS  (16)
-#define NVM_SEC_BITS (8)
-#define NVM_PL_BITS  (8)
-#define NVM_LUN_BITS (8)
-#define NVM_CH_BITS  (8)
-
-struct ppa_addr {
-	/* Generic structure for all addresses */
-	union {
-		struct {
-			u64 blk		: NVM_BLK_BITS;
-			u64 pg		: NVM_PG_BITS;
-			u64 sec		: NVM_SEC_BITS;
-			u64 pl		: NVM_PL_BITS;
-			u64 lun		: NVM_LUN_BITS;
-			u64 ch		: NVM_CH_BITS;
-		} g;
-
-		u64 ppa;
-	};
-};
+struct nvm_rq;
+typedef void (nvm_end_io_fn)(struct nvm_rq *);
 
 struct nvm_rq {
 	struct nvm_tgt_instance *ins;
@@ -164,9 +231,14 @@
 	void *metadata;
 	dma_addr_t dma_metadata;
 
+	struct completion *wait;
+	nvm_end_io_fn *end_io;
+
 	uint8_t opcode;
 	uint16_t nr_pages;
 	uint16_t flags;
+
+	int error;
 };
 
 static inline struct nvm_rq *nvm_rq_from_pdu(void *pdu)
@@ -181,51 +253,31 @@
 
 struct nvm_block;
 
-typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
-typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *);
-typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
-typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32,
-				nvm_l2p_update_fn *, void *);
-typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, int,
-				nvm_bb_update_fn *, void *);
-typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int);
-typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
-typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *);
-typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *);
-typedef void (nvm_destroy_dma_pool_fn)(void *);
-typedef void *(nvm_dev_dma_alloc_fn)(struct nvm_dev *, void *, gfp_t,
-								dma_addr_t *);
-typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t);
-
-struct nvm_dev_ops {
-	nvm_id_fn		*identity;
-	nvm_get_l2p_tbl_fn	*get_l2p_tbl;
-	nvm_op_bb_tbl_fn	*get_bb_tbl;
-	nvm_op_set_bb_fn	*set_bb_tbl;
-
-	nvm_submit_io_fn	*submit_io;
-	nvm_erase_blk_fn	*erase_block;
-
-	nvm_create_dma_pool_fn	*create_dma_pool;
-	nvm_destroy_dma_pool_fn	*destroy_dma_pool;
-	nvm_dev_dma_alloc_fn	*dev_dma_alloc;
-	nvm_dev_dma_free_fn	*dev_dma_free;
-
-	unsigned int		max_phys_sect;
-};
-
 struct nvm_lun {
 	int id;
 
 	int lun_id;
 	int chnl_id;
 
-	unsigned int nr_inuse_blocks;	/* Number of used blocks */
+	/* It is up to the target to mark blocks as closed. If the target does
+	 * not do it, all blocks are marked as open, and nr_open_blocks
+	 * represents the number of blocks in use
+	 */
+	unsigned int nr_open_blocks;	/* Number of used, writable blocks */
+	unsigned int nr_closed_blocks;	/* Number of used, read-only blocks */
 	unsigned int nr_free_blocks;	/* Number of unused blocks */
 	unsigned int nr_bad_blocks;	/* Number of bad blocks */
-	struct nvm_block *blocks;
 
 	spinlock_t lock;
+
+	struct nvm_block *blocks;
+};
+
+enum {
+	NVM_BLK_ST_FREE =	0x1,	/* Free block */
+	NVM_BLK_ST_OPEN =	0x2,	/* Open block - read-write */
+	NVM_BLK_ST_CLOSED =	0x4,	/* Closed block - read-only */
+	NVM_BLK_ST_BAD =	0x8,	/* Bad block */
 };
 
 struct nvm_block {
@@ -234,7 +286,16 @@
 	unsigned long id;
 
 	void *priv;
-	int type;
+	int state;
+};
+
+/* system block cpu representation */
+struct nvm_sb_info {
+	unsigned long		seqnr;
+	unsigned long		erase_cnt;
+	unsigned int		version;
+	char			mmtype[NVM_MMTYPE_LEN];
+	struct ppa_addr		fs_ppa;
 };
 
 struct nvm_dev {
@@ -247,6 +308,9 @@
 	struct nvmm_type *mt;
 	void *mp;
 
+	/* System blocks */
+	struct nvm_sb_info sb;
+
 	/* Device information */
 	int nr_chnls;
 	int nr_planes;
@@ -256,6 +320,7 @@
 	int blks_per_lun;
 	int sec_size;
 	int oob_size;
+	int mccap;
 	struct nvm_addr_format ppaf;
 
 	/* Calculated/Cached values. These do not reflect the actual usable
@@ -268,6 +333,10 @@
 	int sec_per_blk;
 	int sec_per_lun;
 
+	/* lower page table */
+	int lps_per_blk;
+	int *lptbl;
+
 	unsigned long total_pages;
 	unsigned long total_blocks;
 	int nr_luns;
@@ -280,6 +349,8 @@
 	/* Backend device */
 	struct request_queue *q;
 	char name[DISK_NAME_LEN];
+
+	struct mutex mlock;
 };
 
 static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
@@ -302,6 +373,7 @@
 {
 	struct ppa_addr l;
 
+	l.ppa = 0;
 	/*
 	 * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc.
 	 */
@@ -345,9 +417,13 @@
 	return ppa;
 }
 
+static inline int ppa_to_slc(struct nvm_dev *dev, int slc_pg)
+{
+	return dev->lptbl[slc_pg];
+}
+
 typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
 typedef sector_t (nvm_tgt_capacity_fn)(void *);
-typedef int (nvm_tgt_end_io_fn)(struct nvm_rq *, int);
 typedef void *(nvm_tgt_init_fn)(struct nvm_dev *, struct gendisk *, int, int);
 typedef void (nvm_tgt_exit_fn)(void *);
 
@@ -358,7 +434,7 @@
 	/* target entry points */
 	nvm_tgt_make_rq_fn *make_rq;
 	nvm_tgt_capacity_fn *capacity;
-	nvm_tgt_end_io_fn *end_io;
+	nvm_end_io_fn *end_io;
 
 	/* module-specific init/teardown */
 	nvm_tgt_init_fn *init;
@@ -383,7 +459,6 @@
 typedef int (nvmm_close_blk_fn)(struct nvm_dev *, struct nvm_block *);
 typedef void (nvmm_flush_blk_fn)(struct nvm_dev *, struct nvm_block *);
 typedef int (nvmm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
-typedef int (nvmm_end_io_fn)(struct nvm_rq *, int);
 typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
 								unsigned long);
 typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int);
@@ -397,6 +472,8 @@
 	nvmm_unregister_fn *unregister_mgr;
 
 	/* Block administration callbacks */
+	nvmm_get_blk_fn *get_blk_unlocked;
+	nvmm_put_blk_fn *put_blk_unlocked;
 	nvmm_get_blk_fn *get_blk;
 	nvmm_put_blk_fn *put_blk;
 	nvmm_open_blk_fn *open_blk;
@@ -404,7 +481,6 @@
 	nvmm_flush_blk_fn *flush_blk;
 
 	nvmm_submit_io_fn *submit_io;
-	nvmm_end_io_fn *end_io;
 	nvmm_erase_blk_fn *erase_blk;
 
 	/* Configuration management */
@@ -418,6 +494,10 @@
 extern int nvm_register_mgr(struct nvmm_type *);
 extern void nvm_unregister_mgr(struct nvmm_type *);
 
+extern struct nvm_block *nvm_get_blk_unlocked(struct nvm_dev *,
+					struct nvm_lun *, unsigned long);
+extern void nvm_put_blk_unlocked(struct nvm_dev *, struct nvm_block *);
+
 extern struct nvm_block *nvm_get_blk(struct nvm_dev *, struct nvm_lun *,
 								unsigned long);
 extern void nvm_put_blk(struct nvm_dev *, struct nvm_block *);
@@ -427,7 +507,36 @@
 extern void nvm_unregister(char *);
 
 extern int nvm_submit_io(struct nvm_dev *, struct nvm_rq *);
+extern void nvm_generic_to_addr_mode(struct nvm_dev *, struct nvm_rq *);
+extern void nvm_addr_to_generic_mode(struct nvm_dev *, struct nvm_rq *);
+extern int nvm_set_rqd_ppalist(struct nvm_dev *, struct nvm_rq *,
+							struct ppa_addr *, int);
+extern void nvm_free_rqd_ppalist(struct nvm_dev *, struct nvm_rq *);
+extern int nvm_erase_ppa(struct nvm_dev *, struct ppa_addr *, int);
 extern int nvm_erase_blk(struct nvm_dev *, struct nvm_block *);
+extern void nvm_end_io(struct nvm_rq *, int);
+extern int nvm_submit_ppa(struct nvm_dev *, struct ppa_addr *, int, int, int,
+								void *, int);
+
+/* sysblk.c */
+#define NVM_SYSBLK_MAGIC 0x4E564D53 /* "NVMS" */
+
+/* system block on disk representation */
+struct nvm_system_block {
+	__be32			magic;		/* magic signature */
+	__be32			seqnr;		/* sequence number */
+	__be32			erase_cnt;	/* erase count */
+	__be16			version;	/* version number */
+	u8			mmtype[NVM_MMTYPE_LEN]; /* media manager name */
+	__be64			fs_ppa;		/* PPA for media manager
+						 * superblock */
+};
+
+extern int nvm_get_sysblock(struct nvm_dev *, struct nvm_sb_info *);
+extern int nvm_update_sysblock(struct nvm_dev *, struct nvm_sb_info *);
+extern int nvm_init_sysblock(struct nvm_dev *, struct nvm_sb_info *);
+
+extern int nvm_dev_factory(struct nvm_dev *, int flags);
 #else /* CONFIG_NVM */
 struct nvm_dev_ops;
 
--- linux-4.4.0.orig/include/linux/list_lru.h
+++ linux-4.4.0/include/linux/list_lru.h
@@ -44,12 +44,14 @@
 	/* for cgroup aware lrus points to per cgroup lists, otherwise NULL */
 	struct list_lru_memcg	*memcg_lrus;
 #endif
+	long nr_items;
 } ____cacheline_aligned_in_smp;
 
 struct list_lru {
 	struct list_lru_node	*node;
 #ifdef CONFIG_MEMCG_KMEM
 	struct list_head	list;
+	bool			memcg_aware;
 #endif
 };
 
--- linux-4.4.0.orig/include/linux/list_nulls.h
+++ linux-4.4.0/include/linux/list_nulls.h
@@ -66,10 +66,10 @@
 	struct hlist_nulls_node *first = h->first;
 
 	n->next = first;
-	n->pprev = &h->first;
+	WRITE_ONCE(n->pprev, &h->first);
 	h->first = n;
 	if (!is_a_nulls(first))
-		first->pprev = &n->next;
+		WRITE_ONCE(first->pprev, &n->next);
 }
 
 static inline void __hlist_nulls_del(struct hlist_nulls_node *n)
@@ -79,13 +79,13 @@
 
 	WRITE_ONCE(*pprev, next);
 	if (!is_a_nulls(next))
-		next->pprev = pprev;
+		WRITE_ONCE(next->pprev, pprev);
 }
 
 static inline void hlist_nulls_del(struct hlist_nulls_node *n)
 {
 	__hlist_nulls_del(n);
-	n->pprev = LIST_POISON2;
+	WRITE_ONCE(n->pprev, LIST_POISON2);
 }
 
 /**
--- linux-4.4.0.orig/include/linux/livepatch.h
+++ linux-4.4.0/include/linux/livepatch.h
@@ -37,8 +37,9 @@
  * struct klp_func - function structure for live patching
  * @old_name:	name of the function to be patched
  * @new_func:	pointer to the patched function code
- * @old_addr:	a hint conveying at what address the old function
- *		can be found (optional, vmlinux patches only)
+ * @old_sympos: a hint indicating which symbol position the old function
+ *		can be found (optional)
+ * @old_addr:	the address of the function being patched
  * @kobj:	kobject for sysfs resources
  * @state:	tracks function-level patch application state
  * @stack_node:	list node for klp_ops func_stack list
@@ -48,16 +49,16 @@
 	const char *old_name;
 	void *new_func;
 	/*
-	 * The old_addr field is optional and can be used to resolve
-	 * duplicate symbol names in the vmlinux object.  If this
-	 * information is not present, the symbol is located by name
-	 * with kallsyms. If the name is not unique and old_addr is
-	 * not provided, the patch application fails as there is no
-	 * way to resolve the ambiguity.
+	 * The old_sympos field is optional and can be used to resolve
+	 * duplicate symbol names in livepatch objects. If this field is zero,
+	 * it is expected the symbol is unique, otherwise patching fails. If
+	 * this value is greater than zero then that occurrence of the symbol
+	 * in kallsyms for the given object is used.
 	 */
-	unsigned long old_addr;
+	unsigned long old_sympos;
 
 	/* internal */
+	unsigned long old_addr;
 	struct kobject kobj;
 	enum klp_state state;
 	struct list_head stack_node;
@@ -66,8 +67,7 @@
 /**
  * struct klp_reloc - relocation structure for live patching
  * @loc:	address where the relocation will be written
- * @val:	address of the referenced symbol (optional,
- *		vmlinux	patches only)
+ * @sympos:	position in kallsyms to disambiguate symbols (optional)
  * @type:	ELF relocation type
  * @name:	name of the referenced symbol (for lookup/verification)
  * @addend:	offset from the referenced symbol
@@ -75,7 +75,7 @@
  */
 struct klp_reloc {
 	unsigned long loc;
-	unsigned long val;
+	unsigned long sympos;
 	unsigned long type;
 	const char *name;
 	int addend;
--- linux-4.4.0.orig/include/linux/llist.h
+++ linux-4.4.0/include/linux/llist.h
@@ -88,6 +88,23 @@
 	container_of(ptr, type, member)
 
 /**
+ * member_address_is_nonnull - check whether the member address is not NULL
+ * @ptr:	the object pointer (struct type * that contains the llist_node)
+ * @member:	the name of the llist_node within the struct.
+ *
+ * This macro is conceptually the same as
+ *	&ptr->member != NULL
+ * but it works around the fact that compilers can decide that taking a member
+ * address is never a NULL pointer.
+ *
+ * Real objects that start at a high address and have a member at NULL are
+ * unlikely to exist, but such pointers may be returned e.g. by the
+ * container_of() macro.
+ */
+#define member_address_is_nonnull(ptr, member)	\
+	((uintptr_t)(ptr) + offsetof(typeof(*(ptr)), member) != 0)
+
+/**
  * llist_for_each - iterate over some deleted entries of a lock-less list
  * @pos:	the &struct llist_node to use as a loop cursor
  * @node:	the first entry of deleted list entries
@@ -121,7 +138,7 @@
  */
 #define llist_for_each_entry(pos, node, member)				\
 	for ((pos) = llist_entry((node), typeof(*(pos)), member);	\
-	     &(pos)->member != NULL;					\
+	     member_address_is_nonnull(pos, member);			\
 	     (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
 
 /**
@@ -143,7 +160,7 @@
  */
 #define llist_for_each_entry_safe(pos, n, node, member)			       \
 	for (pos = llist_entry((node), typeof(*pos), member);		       \
-	     &pos->member != NULL &&					       \
+	     member_address_is_nonnull(pos, member) &&			       \
 	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
 	     pos = n)
 
--- linux-4.4.0.orig/include/linux/lockd/lockd.h
+++ linux-4.4.0/include/linux/lockd/lockd.h
@@ -355,7 +355,8 @@
 static inline int nlm_compare_locks(const struct file_lock *fl1,
 				    const struct file_lock *fl2)
 {
-	return	fl1->fl_pid   == fl2->fl_pid
+	return file_inode(fl1->fl_file) == file_inode(fl2->fl_file)
+	     && fl1->fl_pid   == fl2->fl_pid
 	     && fl1->fl_owner == fl2->fl_owner
 	     && fl1->fl_start == fl2->fl_start
 	     && fl1->fl_end   == fl2->fl_end
--- linux-4.4.0.orig/include/linux/log2.h
+++ linux-4.4.0/include/linux/log2.h
@@ -16,12 +16,6 @@
 #include <linux/bitops.h>
 
 /*
- * deal with unrepresentable constant logarithms
- */
-extern __attribute__((const, noreturn))
-int ____ilog2_NaN(void);
-
-/*
  * non-constant log of base 2 calculators
  * - the arch may override these in asm/bitops.h if they can be implemented
  *   more efficiently than using fls() and fls64()
@@ -85,7 +79,7 @@
 #define ilog2(n)				\
 (						\
 	__builtin_constant_p(n) ? (		\
-		(n) < 1 ? ____ilog2_NaN() :	\
+		(n) < 2 ? 0 :			\
 		(n) & (1ULL << 63) ? 63 :	\
 		(n) & (1ULL << 62) ? 62 :	\
 		(n) & (1ULL << 61) ? 61 :	\
@@ -148,10 +142,7 @@
 		(n) & (1ULL <<  4) ?  4 :	\
 		(n) & (1ULL <<  3) ?  3 :	\
 		(n) & (1ULL <<  2) ?  2 :	\
-		(n) & (1ULL <<  1) ?  1 :	\
-		(n) & (1ULL <<  0) ?  0 :	\
-		____ilog2_NaN()			\
-				   ) :		\
+		1 ) :				\
 	(sizeof(n) <= 4) ?			\
 	__ilog2_u32(n) :			\
 	__ilog2_u64(n)				\
@@ -168,7 +159,7 @@
 #define roundup_pow_of_two(n)			\
 (						\
 	__builtin_constant_p(n) ? (		\
-		(n == 1) ? 1 :			\
+		((n) == 1) ? 1 :		\
 		(1UL << (ilog2((n) - 1) + 1))	\
 				   ) :		\
 	__roundup_pow_of_two(n)			\
@@ -203,6 +194,17 @@
  *  ... and so on.
  */
 
-#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+static inline __attribute_const__
+int __order_base_2(unsigned long n)
+{
+	return n > 1 ? ilog2(n - 1) + 1 : 0;
+}
 
+#define order_base_2(n)				\
+(						\
+	__builtin_constant_p(n) ? (		\
+		((n) == 0 || (n) == 1) ? 0 :	\
+		ilog2((n) - 1) + 1) :		\
+	__order_base_2(n)			\
+)
 #endif /* _LINUX_LOG2_H */
--- linux-4.4.0.orig/include/linux/mbcache.h
+++ linux-4.4.0/include/linux/mbcache.h
@@ -1,55 +1,52 @@
-/*
-  File: linux/mbcache.h
+#ifndef _LINUX_MBCACHE_H
+#define _LINUX_MBCACHE_H
 
-  (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
-*/
-struct mb_cache_entry {
-	struct list_head		e_lru_list;
-	struct mb_cache			*e_cache;
-	unsigned short			e_used;
-	unsigned short			e_queued;
-	atomic_t			e_refcnt;
-	struct block_device		*e_bdev;
-	sector_t			e_block;
-	struct hlist_bl_node		e_block_list;
-	struct {
-		struct hlist_bl_node	o_list;
-		unsigned int		o_key;
-	} e_index;
-	struct hlist_bl_head		*e_block_hash_p;
-	struct hlist_bl_head		*e_index_hash_p;
-};
+#include <linux/hash.h>
+#include <linux/list_bl.h>
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <linux/fs.h>
+
+struct mb_cache;
 
-struct mb_cache {
-	struct list_head		c_cache_list;
-	const char			*c_name;
-	atomic_t			c_entry_count;
-	int				c_max_entries;
-	int				c_bucket_bits;
-	struct kmem_cache		*c_entry_cache;
-	struct hlist_bl_head		*c_block_hash;
-	struct hlist_bl_head		*c_index_hash;
+struct mb_cache_entry {
+	/* List of entries in cache - protected by cache->c_list_lock */
+	struct list_head	e_list;
+	/* Hash table list - protected by hash chain bitlock */
+	struct hlist_bl_node	e_hash_list;
+	atomic_t		e_refcnt;
+	/* Key in hash - stable during lifetime of the entry */
+	u32			e_key;
+	u32			e_referenced:1;
+	u32			e_reusable:1;
+	/* Block number of hashed block - stable during lifetime of the entry */
+	sector_t		e_block;
 };
 
-/* Functions on caches */
+struct mb_cache *mb_cache_create(int bucket_bits);
+void mb_cache_destroy(struct mb_cache *cache);
 
-struct mb_cache *mb_cache_create(const char *, int);
-void mb_cache_shrink(struct block_device *);
-void mb_cache_destroy(struct mb_cache *);
-
-/* Functions on cache entries */
-
-struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *, gfp_t);
-int mb_cache_entry_insert(struct mb_cache_entry *, struct block_device *,
-			  sector_t, unsigned int);
-void mb_cache_entry_release(struct mb_cache_entry *);
-void mb_cache_entry_free(struct mb_cache_entry *);
-struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *,
-					  struct block_device *,
-					  sector_t);
+int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
+			  sector_t block, bool reusable);
+void __mb_cache_entry_free(struct mb_cache_entry *entry);
+static inline int mb_cache_entry_put(struct mb_cache *cache,
+				     struct mb_cache_entry *entry)
+{
+	if (!atomic_dec_and_test(&entry->e_refcnt))
+		return 0;
+	__mb_cache_entry_free(entry);
+	return 1;
+}
+
+void mb_cache_entry_delete_block(struct mb_cache *cache, u32 key,
+				  sector_t block);
+struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key,
+					  sector_t block);
 struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache,
-						 struct block_device *, 
-						 unsigned int);
-struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache_entry *,
-						struct block_device *, 
-						unsigned int);
+						 u32 key);
+struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache *cache,
+						struct mb_cache_entry *entry);
+void mb_cache_entry_touch(struct mb_cache *cache,
+			  struct mb_cache_entry *entry);
+
+#endif	/* _LINUX_MBCACHE_H */
--- linux-4.4.0.orig/include/linux/mbus.h
+++ linux-4.4.0/include/linux/mbus.h
@@ -29,8 +29,8 @@
 	struct mbus_dram_window {
 		u8	cs_index;
 		u8	mbus_attr;
-		u32	base;
-		u32	size;
+		u64	base;
+		u64	size;
 	} cs[4];
 };
 
--- linux-4.4.0.orig/include/linux/memblock.h
+++ linux-4.4.0/include/linux/memblock.h
@@ -408,11 +408,19 @@
 }
 #endif
 
+extern unsigned long memblock_reserved_memory_within(phys_addr_t start_addr,
+		phys_addr_t end_addr);
 #else
 static inline phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align)
 {
 	return 0;
 }
+
+static inline unsigned long memblock_reserved_memory_within(phys_addr_t start_addr,
+		phys_addr_t end_addr)
+{
+	return 0;
+}
 
 #endif /* CONFIG_HAVE_MEMBLOCK */
 
--- linux-4.4.0.orig/include/linux/memcontrol.h
+++ linux-4.4.0/include/linux/memcontrol.h
@@ -174,6 +174,11 @@
 	struct mem_cgroup_threshold_ary *spare;
 };
 
+struct mem_cgroup_id {
+	int id;
+	atomic_t ref;
+};
+
 /*
  * The memory controller data structure. The memory controller controls both
  * page cache and RSS per cgroup. We would eventually like to provide
@@ -183,6 +188,9 @@
 struct mem_cgroup {
 	struct cgroup_subsys_state css;
 
+	/* Private memcg ID. Used to ID objects that outlive the cgroup */
+	struct mem_cgroup_id id;
+
 	/* Accounted resources */
 	struct page_counter memory;
 	struct page_counter memsw;
--- linux-4.4.0.orig/include/linux/memory.h
+++ linux-4.4.0/include/linux/memory.h
@@ -109,6 +109,9 @@
 extern int register_memory_isolate_notifier(struct notifier_block *nb);
 extern void unregister_memory_isolate_notifier(struct notifier_block *nb);
 extern int register_new_memory(int, struct mem_section *);
+extern int memory_block_change_state(struct memory_block *mem,
+				     unsigned long to_state,
+				     unsigned long from_state_req);
 #ifdef CONFIG_MEMORY_HOTREMOVE
 extern int unregister_memory_section(struct mem_section *);
 #endif
--- linux-4.4.0.orig/include/linux/memory_hotplug.h
+++ linux-4.4.0/include/linux/memory_hotplug.h
@@ -85,7 +85,8 @@
 extern int add_one_highpage(struct page *page, int pfn, int bad_ppro);
 /* VM interface that may be used by firmware interface */
 extern int online_pages(unsigned long, unsigned long, int);
-extern int test_pages_in_a_zone(unsigned long, unsigned long);
+extern int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
+	unsigned long *valid_start, unsigned long *valid_end);
 extern void __offline_isolated_pages(unsigned long, unsigned long);
 
 typedef void (*online_page_callback_t)(struct page *page);
@@ -99,6 +100,8 @@
 
 extern int try_online_node(int nid);
 
+extern bool memhp_auto_online;
+
 #ifdef CONFIG_MEMORY_HOTREMOVE
 extern bool is_pageblock_removable_nolock(struct page *page);
 extern int arch_remove_memory(u64 start, u64 size);
@@ -267,7 +270,7 @@
 extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
 		void *arg, int (*func)(struct memory_block *, void *));
 extern int add_memory(int nid, u64 start, u64 size);
-extern int add_memory_resource(int nid, struct resource *resource);
+extern int add_memory_resource(int nid, struct resource *resource, bool online);
 extern int zone_for_memory(int nid, u64 start, u64 size, int zone_default,
 		bool for_device);
 extern int arch_add_memory(int nid, u64 start, u64 size, bool for_device);
--- linux-4.4.0.orig/include/linux/mfd/88pm80x.h
+++ linux-4.4.0/include/linux/mfd/88pm80x.h
@@ -350,7 +350,7 @@
 	int irq = platform_get_irq(pdev, 0);
 
 	if (device_may_wakeup(dev))
-		set_bit((1 << irq), &chip->wu_flag);
+		set_bit(irq, &chip->wu_flag);
 
 	return 0;
 }
@@ -362,7 +362,7 @@
 	int irq = platform_get_irq(pdev, 0);
 
 	if (device_may_wakeup(dev))
-		clear_bit((1 << irq), &chip->wu_flag);
+		clear_bit(irq, &chip->wu_flag);
 
 	return 0;
 }
--- linux-4.4.0.orig/include/linux/mfd/core.h
+++ linux-4.4.0/include/linux/mfd/core.h
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 
 struct irq_domain;
+struct property_set;
 
 /* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */
 struct mfd_cell_acpi_match {
@@ -44,6 +45,10 @@
 	/* platform data passed to the sub devices drivers */
 	void			*platform_data;
 	size_t			pdata_size;
+
+	/* device properties passed to the sub devices drivers */
+	const struct property_set *pset;
+
 	/*
 	 * Device Tree compatible string
 	 * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details
--- linux-4.4.0.orig/include/linux/mfd/cros_ec.h
+++ linux-4.4.0/include/linux/mfd/cros_ec.h
@@ -224,6 +224,21 @@
 		     struct cros_ec_command *msg);
 
 /**
+ * cros_ec_cmd_xfer_status - Send a command to the ChromeOS EC
+ *
+ * This function is identical to cros_ec_cmd_xfer, except it returns success
+ * status only if both the command was transmitted successfully and the EC
+ * replied with success status. It's not necessary to check msg->result when
+ * using this function.
+ *
+ * @ec_dev: EC device
+ * @msg: Message to write
+ * @return: Num. of bytes transferred on success, <0 on failure
+ */
+int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
+			    struct cros_ec_command *msg);
+
+/**
  * cros_ec_remove - Remove a ChromeOS EC
  *
  * Call this to deregister a ChromeOS EC, then clean up any private data.
--- linux-4.4.0.orig/include/linux/mfd/da9063/registers.h
+++ linux-4.4.0/include/linux/mfd/da9063/registers.h
@@ -215,9 +215,9 @@
 
 /* DA9063 Configuration registers */
 /* OTP */
-#define	DA9063_REG_OPT_COUNT		0x101
-#define	DA9063_REG_OPT_ADDR		0x102
-#define	DA9063_REG_OPT_DATA		0x103
+#define	DA9063_REG_OTP_CONT		0x101
+#define	DA9063_REG_OTP_ADDR		0x102
+#define	DA9063_REG_OTP_DATA		0x103
 
 /* Customer Trim and Configuration */
 #define	DA9063_REG_T_OFFSET		0x104
--- linux-4.4.0.orig/include/linux/mfd/max8997.h
+++ linux-4.4.0/include/linux/mfd/max8997.h
@@ -178,7 +178,6 @@
 struct max8997_platform_data {
 	/* IRQ */
 	int ono;
-	int wakeup;
 
 	/* ---- PMIC ---- */
 	struct max8997_regulator_data *regulators;
--- linux-4.4.0.orig/include/linux/mfd/mc13xxx.h
+++ linux-4.4.0/include/linux/mfd/mc13xxx.h
@@ -247,6 +247,7 @@
 #define MC13XXX_ADC0_TSMOD0		(1 << 12)
 #define MC13XXX_ADC0_TSMOD1		(1 << 13)
 #define MC13XXX_ADC0_TSMOD2		(1 << 14)
+#define MC13XXX_ADC0_CHRGRAWDIV		(1 << 15)
 #define MC13XXX_ADC0_ADINC1		(1 << 16)
 #define MC13XXX_ADC0_ADINC2		(1 << 17)
 
--- linux-4.4.0.orig/include/linux/mfd/samsung/s2mps11.h
+++ linux-4.4.0/include/linux/mfd/samsung/s2mps11.h
@@ -173,10 +173,12 @@
 
 #define S2MPS11_LDO_VSEL_MASK	0x3F
 #define S2MPS11_BUCK_VSEL_MASK	0xFF
+#define S2MPS11_BUCK9_VSEL_MASK	0x1F
 #define S2MPS11_ENABLE_MASK	(0x03 << S2MPS11_ENABLE_SHIFT)
 #define S2MPS11_ENABLE_SHIFT	0x06
 #define S2MPS11_LDO_N_VOLTAGES	(S2MPS11_LDO_VSEL_MASK + 1)
 #define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1)
+#define S2MPS11_BUCK9_N_VOLTAGES (S2MPS11_BUCK9_VSEL_MASK + 1)
 #define S2MPS11_RAMP_DELAY	25000		/* uV/us */
 
 #define S2MPS11_CTRL1_PWRHOLD_MASK	BIT(4)
--- linux-4.4.0.orig/include/linux/mfd/ti_am335x_tscadc.h
+++ linux-4.4.0/include/linux/mfd/ti_am335x_tscadc.h
@@ -138,16 +138,16 @@
 /*
  * time in us for processing a single channel, calculated as follows:
  *
- * num cycles = open delay + (sample delay + conv time) * averaging
+ * max num cycles = open delay + (sample delay + conv time) * averaging
  *
- * num cycles: 152 + (1 + 13) * 16 = 376
+ * max num cycles: 262143 + (255 + 13) * 16 = 266431
  *
  * clock frequency: 26MHz / 8 = 3.25MHz
  * clock period: 1 / 3.25MHz = 308ns
  *
- * processing time: 376 * 308ns = 116us
+ * max processing time: 266431 * 308ns = 83ms(approx)
  */
-#define IDLE_TIMEOUT 116 /* microsec */
+#define IDLE_TIMEOUT 83 /* milliseconds */
 
 #define TSCADC_CELLS		2
 
--- linux-4.4.0.orig/include/linux/mlx4/device.h
+++ linux-4.4.0/include/linux/mlx4/device.h
@@ -44,6 +44,8 @@
 
 #include <linux/timecounter.h>
 
+#define DEFAULT_UAR_PAGE_SHIFT  12
+
 #define MAX_MSIX_P_PORT		17
 #define MAX_MSIX		64
 #define MIN_MSIX_P_PORT		5
@@ -460,6 +462,7 @@
 enum {
 	MLX4_INTERFACE_STATE_UP		= 1 << 0,
 	MLX4_INTERFACE_STATE_DELETION	= 1 << 1,
+	MLX4_INTERFACE_STATE_NOWAIT	= 1 << 2,
 };
 
 #define MSTR_SM_CHANGE_MASK (MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK | \
@@ -822,6 +825,11 @@
 	u8			n_ports;
 };
 
+enum mlx4_pci_status {
+	MLX4_PCI_STATUS_DISABLED,
+	MLX4_PCI_STATUS_ENABLED,
+};
+
 struct mlx4_dev_persistent {
 	struct pci_dev	       *pdev;
 	struct mlx4_dev	       *dev;
@@ -835,6 +843,8 @@
 	u8		state;
 	struct mutex	interface_state_mutex; /* protect SW state */
 	u8	interface_state;
+	struct mutex		pci_status_mutex; /* sync pci state */
+	enum mlx4_pci_status	pci_status;
 };
 
 struct mlx4_dev {
@@ -853,6 +863,7 @@
 	u64			regid_promisc_array[MLX4_MAX_PORTS + 1];
 	u64			regid_allmulti_array[MLX4_MAX_PORTS + 1];
 	struct mlx4_vf_dev     *dev_vfs;
+	u8  uar_page_shift;
 };
 
 struct mlx4_clock_params {
@@ -1527,4 +1538,14 @@
 int mlx4_get_internal_clock_params(struct mlx4_dev *dev,
 				   struct mlx4_clock_params *params);
 
+static inline int mlx4_to_hw_uar_index(struct mlx4_dev *dev, int index)
+{
+	return (index << (PAGE_SHIFT - dev->uar_page_shift));
+}
+
+static inline int mlx4_get_num_reserved_uar(struct mlx4_dev *dev)
+{
+	/* The first 128 UARs are used for EQ doorbells */
+	return (128 >> (PAGE_SHIFT - dev->uar_page_shift));
+}
 #endif /* MLX4_DEVICE_H */
--- linux-4.4.0.orig/include/linux/mlx4/qp.h
+++ linux-4.4.0/include/linux/mlx4/qp.h
@@ -465,6 +465,7 @@
 	u16	rate_val;
 };
 
+struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn);
 int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
 		   enum mlx4_update_qp_attr attr,
 		   struct mlx4_update_qp_params *params);
--- linux-4.4.0.orig/include/linux/mlx5/cq.h
+++ linux-4.4.0/include/linux/mlx5/cq.h
@@ -45,7 +45,7 @@
 	atomic_t		refcount;
 	struct completion	free;
 	unsigned		vector;
-	int			irqn;
+	unsigned int		irqn;
 	void (*comp)		(struct mlx5_core_cq *);
 	void (*event)		(struct mlx5_core_cq *, enum mlx5_event);
 	struct mlx5_uar	       *uar;
--- linux-4.4.0.orig/include/linux/mlx5/device.h
+++ linux-4.4.0/include/linux/mlx5/device.h
@@ -251,6 +251,7 @@
 	MLX5_EVENT_TYPE_PAGE_REQUEST	   = 0xb,
 
 	MLX5_EVENT_TYPE_PAGE_FAULT	   = 0xc,
+	MLX5_EVENT_TYPE_NIC_VPORT_CHANGE   = 0xd,
 };
 
 enum {
@@ -334,6 +335,17 @@
 	MLX5_CAP_OFF_CMDIF_CSUM		= 46,
 };
 
+enum {
+	/*
+	 * Max wqe size for rdma read is 512 bytes, so this
+	 * limits our max_sge_rd as the wqe needs to fit:
+	 * - ctrl segment (16 bytes)
+	 * - rdma segment (16 bytes)
+	 * - scatter elements (16 bytes each)
+	 */
+	MLX5_MAX_SGE_RD	= (512 - 16 - 16) / 16
+};
+
 struct mlx5_inbox_hdr {
 	__be16		opcode;
 	u8		rsvd[4];
@@ -520,6 +532,12 @@
 	__be32 flags_qpn;
 } __packed;
 
+struct mlx5_eqe_vport_change {
+	u8		rsvd0[2];
+	__be16		vport_num;
+	__be32		rsvd1[6];
+} __packed;
+
 union ev_data {
 	__be32				raw[7];
 	struct mlx5_eqe_cmd		cmd;
@@ -532,6 +550,7 @@
 	struct mlx5_eqe_stall_vl	stall_vl;
 	struct mlx5_eqe_page_req	req_pages;
 	struct mlx5_eqe_page_fault	page_fault;
+	struct mlx5_eqe_vport_change	vport_change;
 } __packed;
 
 struct mlx5_eqe {
@@ -624,8 +643,14 @@
 };
 
 enum {
-	CQE_RSS_HTYPE_IP	= 0x3 << 6,
-	CQE_RSS_HTYPE_L4	= 0x3 << 2,
+	CQE_RSS_HTYPE_IP	= 0x3 << 2,
+	/* cqe->rss_hash_type[3:2] - IP destination selected for hash
+	 * (00 = none,  01 = IPv4, 10 = IPv6, 11 = Reserved)
+	 */
+	CQE_RSS_HTYPE_L4	= 0x3 << 6,
+	/* cqe->rss_hash_type[7:6] - L4 destination selected for hash
+	 * (00 = none, 01 = TCP. 10 = UDP, 11 = IPSEC.SPI
+	 */
 };
 
 enum {
@@ -1067,6 +1092,12 @@
 };
 
 enum {
+	MLX5_ESW_VPORT_ADMIN_STATE_DOWN  = 0x0,
+	MLX5_ESW_VPORT_ADMIN_STATE_UP    = 0x1,
+	MLX5_ESW_VPORT_ADMIN_STATE_AUTO  = 0x2,
+};
+
+enum {
 	MLX5_L3_PROT_TYPE_IPV4		= 0,
 	MLX5_L3_PROT_TYPE_IPV6		= 1,
 };
@@ -1102,6 +1133,12 @@
 	MLX5_FLOW_CONTEXT_DEST_TYPE_TIR		= 2,
 };
 
+enum mlx5_list_type {
+	MLX5_NVPRT_LIST_TYPE_UC   = 0x0,
+	MLX5_NVPRT_LIST_TYPE_MC   = 0x1,
+	MLX5_NVPRT_LIST_TYPE_VLAN = 0x2,
+};
+
 enum {
 	MLX5_RQC_RQ_TYPE_MEMORY_RQ_INLINE = 0x0,
 	MLX5_RQC_RQ_TYPE_MEMORY_RQ_RPM    = 0x1,
@@ -1124,6 +1161,8 @@
 	MLX5_CAP_IPOIB_OFFLOADS,
 	MLX5_CAP_EOIB_OFFLOADS,
 	MLX5_CAP_FLOW_TABLE,
+	MLX5_CAP_ESWITCH_FLOW_TABLE,
+	MLX5_CAP_ESWITCH,
 	/* NUM OF CAP Types */
 	MLX5_CAP_NUM
 };
@@ -1161,6 +1200,28 @@
 #define MLX5_CAP_FLOWTABLE_MAX(mdev, cap) \
 	MLX5_GET(flow_table_nic_cap, mdev->hca_caps_max[MLX5_CAP_FLOW_TABLE], cap)
 
+#define MLX5_CAP_ESW_FLOWTABLE(mdev, cap) \
+	MLX5_GET(flow_table_eswitch_cap, \
+		 mdev->hca_caps_cur[MLX5_CAP_ESWITCH_FLOW_TABLE], cap)
+
+#define MLX5_CAP_ESW_FLOWTABLE_MAX(mdev, cap) \
+	MLX5_GET(flow_table_eswitch_cap, \
+		 mdev->hca_caps_max[MLX5_CAP_ESWITCH_FLOW_TABLE], cap)
+
+#define MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, cap) \
+	MLX5_CAP_ESW_FLOWTABLE(mdev, flow_table_properties_nic_esw_fdb.cap)
+
+#define MLX5_CAP_ESW_FLOWTABLE_FDB_MAX(mdev, cap) \
+	MLX5_CAP_ESW_FLOWTABLE_MAX(mdev, flow_table_properties_nic_esw_fdb.cap)
+
+#define MLX5_CAP_ESW(mdev, cap) \
+	MLX5_GET(e_switch_cap, \
+		 mdev->hca_caps_cur[MLX5_CAP_ESWITCH], cap)
+
+#define MLX5_CAP_ESW_MAX(mdev, cap) \
+	MLX5_GET(e_switch_cap, \
+		 mdev->hca_caps_max[MLX5_CAP_ESWITCH], cap)
+
 #define MLX5_CAP_ODP(mdev, cap)\
 	MLX5_GET(odp_cap, mdev->hca_caps_cur[MLX5_CAP_ODP], cap)
 
--- linux-4.4.0.orig/include/linux/mlx5/driver.h
+++ linux-4.4.0/include/linux/mlx5/driver.h
@@ -54,7 +54,7 @@
 	/* one minute for the sake of bringup. Generally, commands must always
 	 * complete and we may need to increase this timeout value
 	 */
-	MLX5_CMD_TIMEOUT_MSEC	= 7200 * 1000,
+	MLX5_CMD_TIMEOUT_MSEC	= 60 * 1000,
 	MLX5_CMD_WQ_MAX_NAME	= 32,
 };
 
@@ -303,7 +303,7 @@
 	u32			cons_index;
 	struct mlx5_buf		buf;
 	int			size;
-	u8			irqn;
+	unsigned int		irqn;
 	u8			eqn;
 	int			nent;
 	u64			mask;
@@ -426,11 +426,23 @@
 	struct radix_tree_root	tree;
 };
 
+struct mlx5_vf_context {
+	int	enabled;
+};
+
+struct mlx5_core_sriov {
+	struct mlx5_vf_context	*vfs_ctx;
+	int			num_vfs;
+	int			enabled_vfs;
+};
+
 struct mlx5_irq_info {
 	cpumask_var_t mask;
 	char name[MLX5_MAX_IRQ_NAME];
 };
 
+struct mlx5_eswitch;
+
 struct mlx5_priv {
 	char			name[MLX5_MAX_NAME_LEN];
 	struct mlx5_eq_table	eq_table;
@@ -447,6 +459,7 @@
 	int			fw_pages;
 	atomic_t		reg_pages;
 	struct list_head	free_list;
+	int			vfs_pages;
 
 	struct mlx5_core_health health;
 
@@ -485,6 +498,10 @@
 	struct list_head        dev_list;
 	struct list_head        ctx_list;
 	spinlock_t              ctx_lock;
+
+	struct mlx5_eswitch     *eswitch;
+	struct mlx5_core_sriov	sriov;
+	unsigned long		pci_dev_data;
 };
 
 enum mlx5_device_state {
@@ -493,8 +510,9 @@
 };
 
 enum mlx5_interface_state {
-	MLX5_INTERFACE_STATE_DOWN,
-	MLX5_INTERFACE_STATE_UP,
+	MLX5_INTERFACE_STATE_DOWN = BIT(0),
+	MLX5_INTERFACE_STATE_UP = BIT(1),
+	MLX5_INTERFACE_STATE_SHUTDOWN = BIT(2),
 };
 
 enum mlx5_pci_status {
@@ -518,7 +536,7 @@
 	enum mlx5_device_state	state;
 	/* sync interface state */
 	struct mutex		intf_state_mutex;
-	enum mlx5_interface_state interface_state;
+	unsigned long		intf_state;
 	void			(*event) (struct mlx5_core_dev *dev,
 					  enum mlx5_dev_event event,
 					  unsigned long param);
@@ -566,8 +584,10 @@
 	void		       *uout;
 	int			uout_size;
 	mlx5_cmd_cbk_t		callback;
+	struct delayed_work	cb_timeout_work;
 	void		       *context;
 	int			idx;
+	struct completion	handling;
 	struct completion	done;
 	struct mlx5_cmd        *cmd;
 	struct work_struct	work;
@@ -739,6 +759,8 @@
 void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev);
 int mlx5_pagealloc_start(struct mlx5_core_dev *dev);
 void mlx5_pagealloc_stop(struct mlx5_core_dev *dev);
+int mlx5_sriov_init(struct mlx5_core_dev *dev);
+int mlx5_sriov_cleanup(struct mlx5_core_dev *dev);
 void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
 				 s32 npages);
 int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot);
@@ -762,7 +784,8 @@
 int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
 int mlx5_start_eqs(struct mlx5_core_dev *dev);
 int mlx5_stop_eqs(struct mlx5_core_dev *dev);
-int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn);
+int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn,
+		    unsigned int *irqn);
 int mlx5_core_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn);
 int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn);
 
@@ -772,37 +795,6 @@
 			 int size_in, void *data_out, int size_out,
 			 u16 reg_num, int arg, int write);
 
-int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps);
-int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
-			 int ptys_size, int proto_mask, u8 local_port);
-int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
-			      u32 *proto_cap, int proto_mask);
-int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
-				u32 *proto_admin, int proto_mask);
-int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
-				    u8 *link_width_oper, u8 local_port);
-int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
-			       u8 *proto_oper, int proto_mask,
-			       u8 local_port);
-int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
-			int proto_mask);
-int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
-			       enum mlx5_port_status status);
-int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
-				 enum mlx5_port_status *status);
-
-int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu, u8 port);
-void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu, u8 port);
-void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu,
-			      u8 port);
-
-int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
-			      u8 *vl_hw_cap, u8 local_port);
-
-int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause);
-int mlx5_query_port_pause(struct mlx5_core_dev *dev,
-			  u32 *rx_pause, u32 *tx_pause);
-
 int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
 void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
 int mlx5_core_eq_query(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
@@ -884,6 +876,15 @@
 	} mr_cache[MAX_MR_CACHE_ENTRIES];
 };
 
+enum {
+	MLX5_PCI_DEV_IS_VF		= 1 << 0,
+};
+
+static inline int mlx5_core_is_pf(struct mlx5_core_dev *dev)
+{
+	return !(dev->priv.pci_dev_data & MLX5_PCI_DEV_IS_VF);
+}
+
 static inline int mlx5_get_gid_table_len(u16 param)
 {
 	if (param > 4) {
--- linux-4.4.0.orig/include/linux/mlx5/flow_table.h
+++ linux-4.4.0/include/linux/mlx5/flow_table.h
@@ -41,6 +41,15 @@
 	u32	match_criteria[MLX5_ST_SZ_DW(fte_match_param)];
 };
 
+struct mlx5_flow_destination {
+	enum mlx5_flow_destination_type	type;
+	union {
+		u32			tir_num;
+		void			*ft;
+		u32			vport_num;
+	};
+};
+
 void *mlx5_create_flow_table(struct mlx5_core_dev *dev, u8 level, u8 table_type,
 			     u16 num_groups,
 			     struct mlx5_flow_table_group *group);
--- linux-4.4.0.orig/include/linux/mlx5/mlx5_ifc.h
+++ linux-4.4.0/include/linux/mlx5/mlx5_ifc.h
@@ -447,6 +447,29 @@
 	u8         reserved_3[0x7200];
 };
 
+struct mlx5_ifc_flow_table_eswitch_cap_bits {
+	u8     reserved_0[0x200];
+
+	struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_esw_fdb;
+
+	struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_esw_acl_ingress;
+
+	struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_esw_acl_egress;
+
+	u8      reserved_1[0x7800];
+};
+
+struct mlx5_ifc_e_switch_cap_bits {
+	u8         vport_svlan_strip[0x1];
+	u8         vport_cvlan_strip[0x1];
+	u8         vport_svlan_insert[0x1];
+	u8         vport_cvlan_insert_if_not_exist[0x1];
+	u8         vport_cvlan_insert_overwrite[0x1];
+	u8         reserved_0[0x1b];
+
+	u8         reserved_1[0x7e0];
+};
+
 struct mlx5_ifc_per_protocol_networking_offload_caps_bits {
 	u8         csum_cap[0x1];
 	u8         vlan_cap[0x1];
@@ -665,7 +688,9 @@
 	u8         reserved_17[0x1];
 	u8         ets[0x1];
 	u8         nic_flow_table[0x1];
-	u8         reserved_18[0x4];
+	u8         eswitch_flow_table[0x1];
+	u8	   early_vf_enable;
+	u8         reserved_18[0x2];
 	u8         local_ca_ack_delay[0x5];
 	u8         reserved_19[0x6];
 	u8         port_type[0x2];
@@ -787,27 +812,36 @@
 	u8         reserved_60[0x1b];
 	u8         log_max_wq_sz[0x5];
 
-	u8         reserved_61[0xa0];
-
+	u8         nic_vport_change_event[0x1];
+	u8         reserved_61[0xa];
+	u8         log_max_vlan_list[0x5];
 	u8         reserved_62[0x3];
+	u8         log_max_current_mc_list[0x5];
+	u8         reserved_63[0x3];
+	u8         log_max_current_uc_list[0x5];
+
+	u8         reserved_64[0x80];
+
+	u8         reserved_65[0x3];
 	u8         log_max_l2_table[0x5];
-	u8         reserved_63[0x8];
+	u8         reserved_66[0x8];
 	u8         log_uar_page_sz[0x10];
 
-	u8         reserved_64[0x100];
+	u8         reserved_67[0xe0];
 
-	u8         reserved_65[0x1f];
+	u8         reserved_68[0x1f];
 	u8         cqe_zip[0x1];
 
 	u8         cqe_zip_timeout[0x10];
 	u8         cqe_zip_max_num[0x10];
 
-	u8         reserved_66[0x220];
+	u8         reserved_69[0x220];
 };
 
-enum {
-	MLX5_DEST_FORMAT_STRUCT_DESTINATION_TYPE_FLOW_TABLE_  = 0x1,
-	MLX5_DEST_FORMAT_STRUCT_DESTINATION_TYPE_TIR          = 0x2,
+enum mlx5_flow_destination_type {
+	MLX5_FLOW_DESTINATION_TYPE_VPORT        = 0x0,
+	MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE   = 0x1,
+	MLX5_FLOW_DESTINATION_TYPE_TIR          = 0x2,
 };
 
 struct mlx5_ifc_dest_format_struct_bits {
@@ -900,6 +934,13 @@
 	u8         mac_addr_31_0[0x20];
 };
 
+struct mlx5_ifc_vlan_layout_bits {
+	u8         reserved_0[0x14];
+	u8         vlan[0x0c];
+
+	u8         reserved_1[0x20];
+};
+
 struct mlx5_ifc_cong_control_r_roce_ecn_np_bits {
 	u8         reserved_0[0xa0];
 
@@ -1829,6 +1870,8 @@
 	struct mlx5_ifc_roce_cap_bits roce_cap;
 	struct mlx5_ifc_per_protocol_networking_offload_caps_bits per_protocol_networking_offload_caps;
 	struct mlx5_ifc_flow_table_nic_cap_bits flow_table_nic_cap;
+	struct mlx5_ifc_flow_table_eswitch_cap_bits flow_table_eswitch_cap;
+	struct mlx5_ifc_e_switch_cap_bits e_switch_cap;
 	u8         reserved_0[0x8000];
 };
 
@@ -2133,24 +2176,35 @@
 	struct mlx5_ifc_wq_bits wq;
 };
 
-enum {
-	MLX5_NIC_VPORT_CONTEXT_ALLOWED_LIST_TYPE_CURRENT_UC_MAC_ADDRESS  = 0x0,
-};
-
 struct mlx5_ifc_nic_vport_context_bits {
 	u8         reserved_0[0x1f];
 	u8         roce_en[0x1];
 
-	u8         reserved_1[0x760];
-
-	u8         reserved_2[0x5];
+	u8         arm_change_event[0x1];
+	u8         reserved_1[0x1a];
+	u8         event_on_mtu[0x1];
+	u8         event_on_promisc_change[0x1];
+	u8         event_on_vlan_change[0x1];
+	u8         event_on_mc_address_change[0x1];
+	u8         event_on_uc_address_change[0x1];
+
+	u8         reserved_2[0xf0];
+
+	u8         mtu[0x10];
+
+	u8         reserved_3[0x640];
+
+	u8         promisc_uc[0x1];
+	u8         promisc_mc[0x1];
+	u8         promisc_all[0x1];
+	u8         reserved_4[0x2];
 	u8         allowed_list_type[0x3];
-	u8         reserved_3[0xc];
+	u8         reserved_5[0xc];
 	u8         allowed_list_size[0xc];
 
 	struct mlx5_ifc_mac_address_layout_bits permanent_address;
 
-	u8         reserved_4[0x20];
+	u8         reserved_6[0x20];
 
 	u8         current_uc_mac_address[0][0x40];
 };
@@ -2263,6 +2317,26 @@
 	u8         reserved_6[0xca0];
 };
 
+struct mlx5_ifc_esw_vport_context_bits {
+	u8         reserved_0[0x3];
+	u8         vport_svlan_strip[0x1];
+	u8         vport_cvlan_strip[0x1];
+	u8         vport_svlan_insert[0x1];
+	u8         vport_cvlan_insert[0x2];
+	u8         reserved_1[0x18];
+
+	u8         reserved_2[0x20];
+
+	u8         svlan_cfi[0x1];
+	u8         svlan_pcp[0x3];
+	u8         svlan_id[0xc];
+	u8         cvlan_cfi[0x1];
+	u8         cvlan_pcp[0x3];
+	u8         cvlan_id[0xc];
+
+	u8         reserved_3[0x7a0];
+};
+
 enum {
 	MLX5_EQC_STATUS_OK                = 0x0,
 	MLX5_EQC_STATUS_EQ_WRITE_FAILURE  = 0xa,
@@ -2940,6 +3014,7 @@
 
 enum {
 	MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT  = 0x0,
+	MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT   = 0x1,
 };
 
 struct mlx5_ifc_query_vport_state_in_bits {
@@ -3700,6 +3775,64 @@
 	u8         reserved_5[0x120];
 };
 
+struct mlx5_ifc_query_esw_vport_context_out_bits {
+	u8         status[0x8];
+	u8         reserved_0[0x18];
+
+	u8         syndrome[0x20];
+
+	u8         reserved_1[0x40];
+
+	struct mlx5_ifc_esw_vport_context_bits esw_vport_context;
+};
+
+struct mlx5_ifc_query_esw_vport_context_in_bits {
+	u8         opcode[0x10];
+	u8         reserved_0[0x10];
+
+	u8         reserved_1[0x10];
+	u8         op_mod[0x10];
+
+	u8         other_vport[0x1];
+	u8         reserved_2[0xf];
+	u8         vport_number[0x10];
+
+	u8         reserved_3[0x20];
+};
+
+struct mlx5_ifc_modify_esw_vport_context_out_bits {
+	u8         status[0x8];
+	u8         reserved_0[0x18];
+
+	u8         syndrome[0x20];
+
+	u8         reserved_1[0x40];
+};
+
+struct mlx5_ifc_esw_vport_context_fields_select_bits {
+	u8         reserved[0x1c];
+	u8         vport_cvlan_insert[0x1];
+	u8         vport_svlan_insert[0x1];
+	u8         vport_cvlan_strip[0x1];
+	u8         vport_svlan_strip[0x1];
+};
+
+struct mlx5_ifc_modify_esw_vport_context_in_bits {
+	u8         opcode[0x10];
+	u8         reserved_0[0x10];
+
+	u8         reserved_1[0x10];
+	u8         op_mod[0x10];
+
+	u8         other_vport[0x1];
+	u8         reserved_2[0xf];
+	u8         vport_number[0x10];
+
+	struct mlx5_ifc_esw_vport_context_fields_select_bits field_select;
+
+	struct mlx5_ifc_esw_vport_context_bits esw_vport_context;
+};
+
 struct mlx5_ifc_query_eq_out_bits {
 	u8         status[0x8];
 	u8         reserved_0[0x18];
@@ -4228,7 +4361,10 @@
 };
 
 struct mlx5_ifc_modify_nic_vport_field_select_bits {
-	u8         reserved_0[0x1c];
+	u8         reserved_0[0x19];
+	u8         mtu[0x1];
+	u8         change_event[0x1];
+	u8         promisc[0x1];
 	u8         permanent_address[0x1];
 	u8         addresses_list[0x1];
 	u8         roce_en[0x1];
--- linux-4.4.0.orig/include/linux/mlx5/port.h
+++ linux-4.4.0/include/linux/mlx5/port.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_PORT_H__
+#define __MLX5_PORT_H__
+
+#include <linux/mlx5/driver.h>
+
+int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps);
+int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
+			 int ptys_size, int proto_mask, u8 local_port);
+int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
+			      u32 *proto_cap, int proto_mask);
+int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
+				u32 *proto_admin, int proto_mask);
+int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
+				    u8 *link_width_oper, u8 local_port);
+int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
+			       u8 *proto_oper, int proto_mask,
+			       u8 local_port);
+int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
+			int proto_mask);
+int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
+			       enum mlx5_port_status status);
+int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
+				 enum mlx5_port_status *status);
+
+int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port);
+void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, u8 port);
+void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
+			      u8 port);
+
+int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
+			      u8 *vl_hw_cap, u8 local_port);
+
+int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause);
+int mlx5_query_port_pause(struct mlx5_core_dev *dev,
+			  u32 *rx_pause, u32 *tx_pause);
+
+#endif /* __MLX5_PORT_H__ */
--- linux-4.4.0.orig/include/linux/mlx5/qp.h
+++ linux-4.4.0/include/linux/mlx5/qp.h
@@ -160,6 +160,7 @@
 enum {
 	MLX5_FENCE_MODE_NONE			= 0 << 5,
 	MLX5_FENCE_MODE_INITIATOR_SMALL		= 1 << 5,
+	MLX5_FENCE_MODE_FENCE			= 2 << 5,
 	MLX5_FENCE_MODE_STRONG_ORDERING		= 3 << 5,
 	MLX5_FENCE_MODE_SMALL_AND_FENCE		= 4 << 5,
 };
@@ -534,10 +535,11 @@
 struct mlx5_modify_qp_mbox_in {
 	struct mlx5_inbox_hdr	hdr;
 	__be32			qpn;
-	u8			rsvd1[4];
-	__be32			optparam;
 	u8			rsvd0[4];
+	__be32			optparam;
+	u8			rsvd1[4];
 	struct mlx5_qp_context	ctx;
+	u8			rsvd2[16];
 };
 
 struct mlx5_modify_qp_mbox_out {
--- linux-4.4.0.orig/include/linux/mlx5/vport.h
+++ linux-4.4.0/include/linux/mlx5/vport.h
@@ -34,9 +34,17 @@
 #define __MLX5_VPORT_H__
 
 #include <linux/mlx5/driver.h>
+#include <linux/mlx5/device.h>
 
-u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod);
-void mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr);
+u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport);
+u8 mlx5_query_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod,
+				u16 vport);
+int mlx5_modify_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod,
+				  u16 vport, u8 state);
+int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev,
+				     u16 vport, u8 *addr);
+int mlx5_modify_nic_vport_mac_address(struct mlx5_core_dev *dev,
+				      u16 vport, u8 *addr);
 int mlx5_query_hca_vport_gid(struct mlx5_core_dev *dev, u8 other_vport,
 			     u8 port_num, u16  vf_num, u16 gid_index,
 			     union ib_gid *gid);
@@ -51,5 +59,30 @@
 					   u64 *sys_image_guid);
 int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev,
 				   u64 *node_guid);
+int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,
+				  u32 vport,
+				  enum mlx5_list_type list_type,
+				  u8 addr_list[][ETH_ALEN],
+				  int *list_size);
+int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev,
+				   enum mlx5_list_type list_type,
+				   u8 addr_list[][ETH_ALEN],
+				   int list_size);
+int mlx5_query_nic_vport_promisc(struct mlx5_core_dev *mdev,
+				 u32 vport,
+				 int *promisc_uc,
+				 int *promisc_mc,
+				 int *promisc_all);
+int mlx5_modify_nic_vport_promisc(struct mlx5_core_dev *mdev,
+				  int promisc_uc,
+				  int promisc_mc,
+				  int promisc_all);
+int mlx5_query_nic_vport_vlans(struct mlx5_core_dev *dev,
+			       u32 vport,
+			       u16 vlans[],
+			       int *size);
+int mlx5_modify_nic_vport_vlans(struct mlx5_core_dev *dev,
+				u16 vlans[],
+				int list_size);
 
 #endif /* __MLX5_VPORT_H__ */
--- linux-4.4.0.orig/include/linux/mm.h
+++ linux-4.4.0/include/linux/mm.h
@@ -225,10 +225,14 @@
  * ->fault function. The vma's ->fault is responsible for returning a bitmask
  * of VM_FAULT_xxx flags that give details about how the fault was handled.
  *
+ * MM layer fills up gfp_mask for page allocations but fault handler might
+ * alter it if its implementation requires a different allocation context.
+ *
  * pgoff should be used in favour of virtual_address, if possible.
  */
 struct vm_fault {
 	unsigned int flags;		/* FAULT_FLAG_xxx flags */
+	gfp_t gfp_mask;			/* gfp mask to be used for allocations */
 	pgoff_t pgoff;			/* Logical page offset based on vma */
 	void __user *virtual_address;	/* Faulting virtual address */
 
@@ -442,7 +446,6 @@
 
 static inline int page_mapcount(struct page *page)
 {
-	VM_BUG_ON_PAGE(PageSlab(page), page);
 	return atomic_read(&page->_mapcount) + 1;
 }
 
@@ -484,6 +487,10 @@
 
 extern bool __get_page_tail(struct page *page);
 
+/* 127: arbitrary random number, small enough to assemble well */
+#define page_ref_zero_or_close_to_overflow(page) \
+	((unsigned int) atomic_read(&page->_count) + 127u <= 127u)
+
 static inline void get_page(struct page *page)
 {
 	if (unlikely(PageTail(page)))
@@ -493,7 +500,7 @@
 	 * Getting a normal page or the head of a compound page
 	 * requires to already have an elevated page->_count.
 	 */
-	VM_BUG_ON_PAGE(atomic_read(&page->_count) <= 0, page);
+	VM_BUG_ON_PAGE(page_ref_zero_or_close_to_overflow(page), page);
 	atomic_inc(&page->_count);
 }
 
@@ -689,6 +696,11 @@
 	return (page->flags >> ZONES_PGSHIFT) & ZONES_MASK;
 }
 
+static inline bool is_cow_mapping(vm_flags_t flags)
+{
+	return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
+}
+
 #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
 #define SECTION_IN_PAGE_FLAGS
 #endif
@@ -984,6 +996,15 @@
 	return atomic_read(&(page)->_mapcount) >= 0;
 }
 
+static inline __must_check bool try_get_page(struct page *page)
+{
+	page = compound_head(page);
+	if (WARN_ON_ONCE(atomic_read(&page->_count) <= 0))
+		return false;
+	atomic_inc(&page->_count);
+	return true;
+}
+
 /*
  * Return true only if the page has been allocated with
  * ALLOC_NO_WATERMARKS and the low watermark was not
@@ -1084,6 +1105,8 @@
 
 struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
 		pte_t pte);
+struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
+				pmd_t pmd);
 
 int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
 		unsigned long size);
@@ -1092,6 +1115,31 @@
 void unmap_vmas(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
 		unsigned long start, unsigned long end);
 
+/*
+ * This has to be called after a get_task_mm()/mmget_not_zero()
+ * followed by taking the mmap_sem for writing before modifying the
+ * vmas or anything the coredump pretends not to change from under it.
+ *
+ * It also has to be called when mmgrab() is used in the context of
+ * the process, but then the mm_count refcount is transferred outside
+ * the context of the process to run down_write() on that pinned mm.
+ *
+ * NOTE: find_extend_vma() called from GUP context is the only place
+ * that can modify the "mm" (notably the vm_start/end) under mmap_sem
+ * for reading and outside the context of the process, so it is also
+ * the only case that holds the mmap_sem for reading that must call
+ * this function. Generally if the mmap_sem is hold for reading
+ * there's no need of this check after get_task_mm()/mmget_not_zero().
+ *
+ * This function can be obsoleted and the check can be removed, after
+ * the coredump code will hold the mmap_sem for writing before
+ * invoking the ->core_dump methods.
+ */
+static inline bool mmget_still_valid(struct mm_struct *mm)
+{
+	return likely(!mm->core_state);
+}
+
 /**
  * mm_walk - callbacks for walk_page_range
  * @pmd_entry: if set, called for each non-empty PMD (3rd-level) entry
@@ -1183,9 +1231,31 @@
 }
 #endif
 
+extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int);
+extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[],
+				      int);
+extern void vma_do_get_file(struct vm_area_struct *, const char[], int);
+extern void vma_do_fput(struct vm_area_struct *, const char[], int);
+
+#define vma_file_update_time(vma)	vma_do_file_update_time(vma, __func__, \
+								__LINE__)
+#define vma_pr_or_file(vma)		vma_do_pr_or_file(vma, __func__, \
+							  __LINE__)
+#define vma_get_file(vma)		vma_do_get_file(vma, __func__, __LINE__)
+#define vma_fput(vma)			vma_do_fput(vma, __func__, __LINE__)
+
+#ifndef CONFIG_MMU
+extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int);
+extern void vmr_do_fput(struct vm_region *, const char[], int);
+
+#define vmr_pr_or_file(region)		vmr_do_pr_or_file(region, __func__, \
+							  __LINE__)
+#define vmr_fput(region)		vmr_do_fput(region, __func__, __LINE__)
+#endif /* !CONFIG_MMU */
+
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 extern int access_remote_vm(struct mm_struct *mm, unsigned long addr,
-		void *buf, int len, int write);
+		void *buf, int len, unsigned int gup_flags);
 
 long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 		      unsigned long start, unsigned long nr_pages,
@@ -1193,19 +1263,17 @@
 		      struct vm_area_struct **vmas, int *nonblocking);
 long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 		    unsigned long start, unsigned long nr_pages,
-		    int write, int force, struct page **pages,
+		    unsigned int gup_flags, struct page **pages,
 		    struct vm_area_struct **vmas);
 long get_user_pages_locked(struct task_struct *tsk, struct mm_struct *mm,
 		    unsigned long start, unsigned long nr_pages,
-		    int write, int force, struct page **pages,
-		    int *locked);
+		    unsigned int gup_flags, struct page **pages, int *locked);
 long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
 			       unsigned long start, unsigned long nr_pages,
-			       int write, int force, struct page **pages,
-			       unsigned int gup_flags);
+			       struct page **pages, unsigned int gup_flags);
 long get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
 		    unsigned long start, unsigned long nr_pages,
-		    int write, int force, struct page **pages);
+		    struct page **pages, unsigned int gup_flags);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
 			struct page **pages);
 
@@ -1223,7 +1291,7 @@
 struct frame_vector *frame_vector_create(unsigned int nr_frames);
 void frame_vector_destroy(struct frame_vector *vec);
 int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
-		     bool write, bool force, struct frame_vector *vec);
+		     unsigned int gup_flags, struct frame_vector *vec);
 void put_vaddr_frames(struct frame_vector *vec);
 int frame_vector_to_pages(struct frame_vector *vec);
 void frame_vector_to_pfns(struct frame_vector *vec);
@@ -1276,41 +1344,12 @@
 
 int get_cmdline(struct task_struct *task, char *buffer, int buflen);
 
-/* Is the vma a continuation of the stack vma above it? */
-static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr)
-{
-	return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN);
-}
-
 static inline bool vma_is_anonymous(struct vm_area_struct *vma)
 {
 	return !vma->vm_ops;
 }
 
-static inline int stack_guard_page_start(struct vm_area_struct *vma,
-					     unsigned long addr)
-{
-	return (vma->vm_flags & VM_GROWSDOWN) &&
-		(vma->vm_start == addr) &&
-		!vma_growsdown(vma->vm_prev, addr);
-}
-
-/* Is the vma a continuation of the stack vma below it? */
-static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr)
-{
-	return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP);
-}
-
-static inline int stack_guard_page_end(struct vm_area_struct *vma,
-					   unsigned long addr)
-{
-	return (vma->vm_flags & VM_GROWSUP) &&
-		(vma->vm_end == addr) &&
-		!vma_growsup(vma->vm_next, addr);
-}
-
-extern struct task_struct *task_of_stack(struct task_struct *task,
-				struct vm_area_struct *vma, bool in_group);
+int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t);
 
 extern unsigned long move_page_tables(struct vm_area_struct *vma,
 		unsigned long old_addr, struct vm_area_struct *new_vma,
@@ -1694,7 +1733,7 @@
 extern void adjust_managed_page_count(struct page *page, long count);
 extern void mem_init_print_info(const char *str);
 
-extern void reserve_bootmem_region(unsigned long start, unsigned long end);
+extern void reserve_bootmem_region(phys_addr_t start, phys_addr_t end);
 
 /* Free the reserved page into the buddy system, so it gets managed. */
 static inline void __free_reserved_page(struct page *page)
@@ -1806,6 +1845,7 @@
 extern void mem_init(void);
 extern void __init mmap_init(void);
 extern void show_mem(unsigned int flags);
+extern long si_mem_available(void);
 extern void si_meminfo(struct sysinfo * val);
 extern void si_meminfo_node(struct sysinfo *val, int nid);
 
@@ -1897,6 +1937,7 @@
 
 extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
 extern struct file *get_mm_exe_file(struct mm_struct *mm);
+extern struct file *get_task_exe_file(struct task_struct *task);
 
 extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
 extern struct vm_area_struct *_install_special_mapping(struct mm_struct *mm,
@@ -2010,6 +2051,7 @@
 				pgoff_t offset,
 				unsigned long size);
 
+extern unsigned long stack_guard_gap;
 /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */
 extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
 
@@ -2038,6 +2080,30 @@
 	return vma;
 }
 
+static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
+{
+	unsigned long vm_start = vma->vm_start;
+
+	if (vma->vm_flags & VM_GROWSDOWN) {
+		vm_start -= stack_guard_gap;
+		if (vm_start > vma->vm_start)
+			vm_start = 0;
+	}
+	return vm_start;
+}
+
+static inline unsigned long vm_end_gap(struct vm_area_struct *vma)
+{
+	unsigned long vm_end = vma->vm_end;
+
+	if (vma->vm_flags & VM_GROWSUP) {
+		vm_end += stack_guard_gap;
+		if (vm_end < vma->vm_end)
+			vm_end = -PAGE_SIZE;
+	}
+	return vm_end;
+}
+
 static inline unsigned long vma_pages(struct vm_area_struct *vma)
 {
 	return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
@@ -2055,6 +2121,12 @@
 	return vma;
 }
 
+static inline bool range_in_vma(struct vm_area_struct *vma,
+				unsigned long start, unsigned long end)
+{
+	return (vma && vma->vm_start <= start && end <= vma->vm_end);
+}
+
 #ifdef CONFIG_MMU
 pgprot_t vm_get_page_prot(unsigned long vm_flags);
 void vma_set_page_prot(struct vm_area_struct *vma);
@@ -2080,6 +2152,8 @@
 int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
 int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
 			unsigned long pfn);
+int vm_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr,
+			unsigned long pfn, pgprot_t pgprot);
 int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
 			unsigned long pfn);
 int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len);
@@ -2110,6 +2184,8 @@
 #define FOLL_MIGRATION	0x400	/* wait for page to replace migration entry */
 #define FOLL_TRIED	0x800	/* a retry, previous pass started an IO */
 #define FOLL_MLOCK	0x1000	/* lock present pages */
+#define FOLL_COW	0x4000	/* internal GUP flag */
+#define FOLL_ANON	0x8000	/* don't do file mappings */
 
 typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
 			void *data);
--- linux-4.4.0.orig/include/linux/mm_types.h
+++ linux-4.4.0/include/linux/mm_types.h
@@ -272,6 +272,7 @@
 	unsigned long	vm_top;		/* region allocated to here */
 	unsigned long	vm_pgoff;	/* the offset in vm_file corresponding to vm_start */
 	struct file	*vm_file;	/* the backing file or NULL */
+	struct file	*vm_prfile;	/* the virtual backing file or NULL */
 
 	int		vm_usage;	/* region usage count (access under nommu_region_sem) */
 	bool		vm_icache_flushed : 1; /* true if the icache has been flushed for
@@ -346,6 +347,7 @@
 	unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZE
 					   units, *not* PAGE_CACHE_SIZE */
 	struct file * vm_file;		/* File we map to (can be NULL). */
+	struct file *vm_prfile;		/* shadow of vm_file */
 	void * vm_private_data;		/* was vm_pte (shared mem) */
 
 #ifndef CONFIG_MMU
@@ -392,7 +394,7 @@
 struct mm_struct {
 	struct vm_area_struct *mmap;		/* list of VMAs */
 	struct rb_root mm_rb;
-	u32 vmacache_seqnum;                   /* per-thread vmacache */
+	u64 vmacache_seqnum;                   /* per-thread vmacache */
 #ifdef CONFIG_MMU
 	unsigned long (*get_unmapped_area) (struct file *filp,
 				unsigned long addr, unsigned long len,
@@ -469,6 +471,7 @@
 	 */
 	struct task_struct __rcu *owner;
 #endif
+	struct user_namespace *user_ns;
 
 	/* store ref to file /proc/<pid>/exe symlink points to */
 	struct file __rcu *exe_file;
@@ -503,6 +506,10 @@
 	 */
 	bool tlb_flush_pending;
 #endif
+#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
+	/* See flush_tlb_batched_pending() */
+	bool tlb_flush_batched;
+#endif
 	struct uprobes_state uprobes_state;
 #ifdef CONFIG_X86_INTEL_MPX
 	/* address of the bounds directory */
--- linux-4.4.0.orig/include/linux/mman.h
+++ linux-4.4.0/include/linux/mman.h
@@ -63,8 +63,9 @@
  * ("bit1" and "bit2" must be single bits)
  */
 #define _calc_vm_trans(x, bit1, bit2) \
+  ((!(bit1) || !(bit2)) ? 0 : \
   ((bit1) <= (bit2) ? ((x) & (bit1)) * ((bit2) / (bit1)) \
-   : ((x) & (bit1)) / ((bit1) / (bit2)))
+   : ((x) & (bit1)) / ((bit1) / (bit2))))
 
 /*
  * Combine the mmap "prot" argument into "vm_flags" used internally.
--- linux-4.4.0.orig/include/linux/mmc/dw_mmc.h
+++ linux-4.4.0/include/linux/mmc/dw_mmc.h
@@ -172,7 +172,7 @@
 	/* For edmac */
 	struct dw_mci_dma_slave *dms;
 	/* Registers's physical base address */
-	void                    *phy_regs;
+	resource_size_t		phy_regs;
 
 	u32			cmd_status;
 	u32			data_status;
--- linux-4.4.0.orig/include/linux/mmc/sdio_func.h
+++ linux-4.4.0/include/linux/mmc/sdio_func.h
@@ -53,7 +53,7 @@
 	unsigned int		state;		/* function state */
 #define SDIO_STATE_PRESENT	(1<<0)		/* present in sysfs */
 
-	u8			tmpbuf[4];	/* DMA:able scratch buffer */
+	u8			*tmpbuf;	/* DMA:able scratch buffer */
 
 	unsigned		num_info;	/* number of info strings */
 	const char		**info;		/* info strings */
--- linux-4.4.0.orig/include/linux/mmc/sdio_ids.h
+++ linux-4.4.0/include/linux/mmc/sdio_ids.h
@@ -33,6 +33,7 @@
 #define SDIO_DEVICE_ID_BROADCOM_43341		0xa94d
 #define SDIO_DEVICE_ID_BROADCOM_4335_4339	0x4335
 #define SDIO_DEVICE_ID_BROADCOM_43362		0xa962
+#define SDIO_DEVICE_ID_BROADCOM_43364		0xa9a4
 #define SDIO_DEVICE_ID_BROADCOM_43430		0xa9a6
 #define SDIO_DEVICE_ID_BROADCOM_4345		0x4345
 #define SDIO_DEVICE_ID_BROADCOM_4354		0x4354
--- linux-4.4.0.orig/include/linux/mmu_context.h
+++ linux-4.4.0/include/linux/mmu_context.h
@@ -1,9 +1,16 @@
 #ifndef _LINUX_MMU_CONTEXT_H
 #define _LINUX_MMU_CONTEXT_H
 
+#include <asm/mmu_context.h>
+
 struct mm_struct;
 
 void use_mm(struct mm_struct *mm);
 void unuse_mm(struct mm_struct *mm);
 
+/* Architectures that care about IRQ state in switch_mm can override this. */
+#ifndef switch_mm_irqs_off
+# define switch_mm_irqs_off switch_mm
+#endif
+
 #endif
--- linux-4.4.0.orig/include/linux/mmu_notifier.h
+++ linux-4.4.0/include/linux/mmu_notifier.h
@@ -381,18 +381,6 @@
 	___pmd;								\
 })
 
-#define pmdp_huge_get_and_clear_notify(__mm, __haddr, __pmd)		\
-({									\
-	unsigned long ___haddr = __haddr & HPAGE_PMD_MASK;		\
-	pmd_t ___pmd;							\
-									\
-	___pmd = pmdp_huge_get_and_clear(__mm, __haddr, __pmd);		\
-	mmu_notifier_invalidate_range(__mm, ___haddr,			\
-				      ___haddr + HPAGE_PMD_SIZE);	\
-									\
-	___pmd;								\
-})
-
 /*
  * set_pte_at_notify() sets the pte _after_ running the notifier.
  * This is safe to start by updating the secondary MMUs, because the primary MMU
@@ -475,7 +463,6 @@
 #define pmdp_clear_young_notify pmdp_test_and_clear_young
 #define	ptep_clear_flush_notify ptep_clear_flush
 #define pmdp_huge_clear_flush_notify pmdp_huge_clear_flush
-#define pmdp_huge_get_and_clear_notify pmdp_huge_get_and_clear
 #define set_pte_at_notify set_pte_at
 
 #endif /* CONFIG_MMU_NOTIFIER */
--- linux-4.4.0.orig/include/linux/mmzone.h
+++ linux-4.4.0/include/linux/mmzone.h
@@ -131,8 +131,9 @@
 	NR_SLAB_RECLAIMABLE,
 	NR_SLAB_UNRECLAIMABLE,
 	NR_PAGETABLE,		/* used for pagetables */
-	NR_KERNEL_STACK,
 	/* Second 128 byte cacheline */
+	NR_KERNEL_STACK,
+	NR_KAISERTABLE,
 	NR_UNSTABLE_NFS,	/* NFS unstable pages */
 	NR_BOUNCE,
 	NR_VMSCAN_WRITE,
@@ -688,6 +689,8 @@
 	 * is the first PFN that needs to be initialised.
 	 */
 	unsigned long first_deferred_pfn;
+	/* Number of non-deferred pages */
+	unsigned long static_init_pgcnt;
 #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
 } pg_data_t;
 
@@ -737,8 +740,12 @@
 extern struct mutex zonelists_mutex;
 void build_all_zonelists(pg_data_t *pgdat, struct zone *zone);
 void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx);
+bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
+			 int classzone_idx, unsigned int alloc_flags,
+			 long free_pages);
 bool zone_watermark_ok(struct zone *z, unsigned int order,
-		unsigned long mark, int classzone_idx, int alloc_flags);
+		unsigned long mark, int classzone_idx,
+		unsigned int alloc_flags);
 bool zone_watermark_ok_safe(struct zone *z, unsigned int order,
 		unsigned long mark, int classzone_idx);
 enum memmap_context {
--- linux-4.4.0.orig/include/linux/mod_devicetable.h
+++ linux-4.4.0/include/linux/mod_devicetable.h
@@ -404,7 +404,7 @@
  * For Hyper-V devices we use the device guid as the id.
  */
 struct hv_vmbus_device_id {
-	__u8 guid[16];
+	uuid_le guid;
 	kernel_ulong_t driver_data;	/* Data private to the driver */
 };
 
@@ -502,9 +502,9 @@
 
 #define MDIO_MODULE_PREFIX	"mdio:"
 
-#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
+#define MDIO_ID_FMT "%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u"
 #define MDIO_ID_ARGS(_id) \
-	(_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1,	\
+	((_id)>>31) & 1, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \
 	((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \
 	((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \
 	((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \
@@ -572,6 +572,10 @@
 /*
  * MODULE_DEVICE_TABLE expects this struct to be called x86cpu_device_id.
  * Although gcc seems to ignore this error, clang fails without this define.
+ *
+ * Note: The ordering of the struct is different from upstream because the
+ * static initializers in kernels < 5.7 still use C89 style while upstream
+ * has been converted to proper C99 initializers.
  */
 #define x86cpu_device_id x86_cpu_id
 struct x86_cpu_id {
@@ -580,14 +584,14 @@
 	__u16 model;
 	__u16 feature;	/* bit index */
 	kernel_ulong_t driver_data;
+	__u16 steppings;
 };
 
-#define X86_FEATURE_MATCH(x) \
-	{ X86_VENDOR_ANY, X86_FAMILY_ANY, X86_MODEL_ANY, x }
-
+/* Wild cards for x86_cpu_id::vendor, family, model and feature */
 #define X86_VENDOR_ANY 0xffff
 #define X86_FAMILY_ANY 0
 #define X86_MODEL_ANY  0
+#define X86_STEPPING_ANY 0
 #define X86_FEATURE_ANY 0	/* Same as FPU, you can't test for that */
 
 /*
--- linux-4.4.0.orig/include/linux/module.h
+++ linux-4.4.0/include/linux/module.h
@@ -125,15 +125,15 @@
 
 /* Each module must use one module_init(). */
 #define module_init(initfn)					\
-	static inline initcall_t __inittest(void)		\
+	static inline initcall_t __maybe_unused __inittest(void)		\
 	{ return initfn; }					\
-	int init_module(void) __attribute__((alias(#initfn)));
+	int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));
 
 /* This is only required if you want to be unloadable. */
 #define module_exit(exitfn)					\
-	static inline exitcall_t __exittest(void)		\
+	static inline exitcall_t __maybe_unused __exittest(void)		\
 	{ return exitfn; }					\
-	void cleanup_module(void) __attribute__((alias(#exitfn)));
+	void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn)));
 
 #endif
 
@@ -273,6 +273,12 @@
 
 struct notifier_block;
 
+#ifdef CONFIG_MODULE_SIG
+extern void enforce_signed_modules(void);
+#else
+static inline void enforce_signed_modules(void) {};
+#endif
+
 #ifdef CONFIG_MODULES
 
 extern int modules_disabled; /* for sysctl */
@@ -302,6 +308,34 @@
 	struct latch_tree_node node;
 };
 
+struct module_layout {
+	/* The actual code + data. */
+	void *base;
+	/* Total size. */
+	unsigned int size;
+	/* The size of the executable code.  */
+	unsigned int text_size;
+	/* Size of RO section of the module (text+rodata) */
+	unsigned int ro_size;
+
+#ifdef CONFIG_MODULES_TREE_LOOKUP
+	struct mod_tree_node mtn;
+#endif
+};
+
+#ifdef CONFIG_MODULES_TREE_LOOKUP
+/* Only touch one cacheline for common rbtree-for-core-layout case. */
+#define __module_layout_align ____cacheline_aligned
+#else
+#define __module_layout_align
+#endif
+
+struct mod_kallsyms {
+	Elf_Sym *symtab;
+	unsigned int num_symtab;
+	char *strtab;
+};
+
 struct module {
 	enum module_state state;
 
@@ -366,37 +400,9 @@
 	/* Startup function. */
 	int (*init)(void);
 
-	/*
-	 * If this is non-NULL, vfree() after init() returns.
-	 *
-	 * Cacheline align here, such that:
-	 *   module_init, module_core, init_size, core_size,
-	 *   init_text_size, core_text_size and mtn_core::{mod,node[0]}
-	 * are on the same cacheline.
-	 */
-	void *module_init	____cacheline_aligned;
-
-	/* Here is the actual code + data, vfree'd on unload. */
-	void *module_core;
-
-	/* Here are the sizes of the init and core sections */
-	unsigned int init_size, core_size;
-
-	/* The size of the executable code in each section.  */
-	unsigned int init_text_size, core_text_size;
-
-#ifdef CONFIG_MODULES_TREE_LOOKUP
-	/*
-	 * We want mtn_core::{mod,node[0]} to be in the same cacheline as the
-	 * above entries such that a regular lookup will only touch one
-	 * cacheline.
-	 */
-	struct mod_tree_node	mtn_core;
-	struct mod_tree_node	mtn_init;
-#endif
-
-	/* Size of RO sections of the module (text+rodata) */
-	unsigned int init_ro_size, core_ro_size;
+	/* Core layout: rbtree is accessed frequently, so keep together. */
+	struct module_layout core_layout __module_layout_align;
+	struct module_layout init_layout;
 
 	/* Arch-specific module values */
 	struct mod_arch_specific arch;
@@ -411,15 +417,10 @@
 #endif
 
 #ifdef CONFIG_KALLSYMS
-	/*
-	 * We keep the symbol and string tables for kallsyms.
-	 * The core_* fields below are temporary, loader-only (they
-	 * could really be discarded after module init).
-	 */
-	Elf_Sym *symtab, *core_symtab;
-	unsigned int num_symtab, core_num_syms;
-	char *strtab, *core_strtab;
-
+	/* Protected by RCU and/or module_mutex: use rcu_dereference() */
+	struct mod_kallsyms *kallsyms;
+	struct mod_kallsyms core_kallsyms;
+	
 	/* Section attributes */
 	struct module_sect_attrs *sect_attrs;
 
@@ -505,15 +506,15 @@
 static inline bool within_module_core(unsigned long addr,
 				      const struct module *mod)
 {
-	return (unsigned long)mod->module_core <= addr &&
-	       addr < (unsigned long)mod->module_core + mod->core_size;
+	return (unsigned long)mod->core_layout.base <= addr &&
+	       addr < (unsigned long)mod->core_layout.base + mod->core_layout.size;
 }
 
 static inline bool within_module_init(unsigned long addr,
 				      const struct module *mod)
 {
-	return (unsigned long)mod->module_init <= addr &&
-	       addr < (unsigned long)mod->module_init + mod->init_size;
+	return (unsigned long)mod->init_layout.base <= addr &&
+	       addr < (unsigned long)mod->init_layout.base + mod->init_layout.size;
 }
 
 static inline bool within_module(unsigned long addr, const struct module *mod)
@@ -635,6 +636,8 @@
 	return module && module->async_probe_requested;
 }
 
+extern bool secure_modules(void);
+
 #else /* !CONFIG_MODULES... */
 
 /* Given an address, look for it in the exception tables. */
@@ -751,6 +754,10 @@
 	return false;
 }
 
+static inline bool secure_modules(void)
+{
+	return false;
+}
 #endif /* CONFIG_MODULES */
 
 #ifdef CONFIG_SYSFS
@@ -768,9 +775,13 @@
 #ifdef CONFIG_DEBUG_SET_MODULE_RONX
 extern void set_all_modules_text_rw(void);
 extern void set_all_modules_text_ro(void);
+extern void module_enable_ro(const struct module *mod);
+extern void module_disable_ro(const struct module *mod);
 #else
 static inline void set_all_modules_text_rw(void) { }
 static inline void set_all_modules_text_ro(void) { }
+static inline void module_enable_ro(const struct module *mod) { }
+static inline void module_disable_ro(const struct module *mod) { }
 #endif
 
 #ifdef CONFIG_GENERIC_BUG
@@ -788,6 +799,15 @@
 static inline void module_bug_cleanup(struct module *mod) {}
 #endif	/* CONFIG_GENERIC_BUG */
 
+#ifdef RETPOLINE
+extern bool retpoline_module_ok(bool has_retpoline);
+#else
+static inline bool retpoline_module_ok(bool has_retpoline)
+{
+	return true;
+}
+#endif
+
 #ifdef CONFIG_MODULE_SIG
 static inline bool module_sig_ok(struct module *module)
 {
--- linux-4.4.0.orig/include/linux/moduleparam.h
+++ linux-4.4.0/include/linux/moduleparam.h
@@ -60,9 +60,11 @@
  * Flags available for kernel_param
  *
  * UNSAFE - the parameter is dangerous and setting it will taint the kernel
+ * HWPARAM - Hardware param not permitted in lockdown mode
  */
 enum {
-	KERNEL_PARAM_FL_UNSAFE = (1 << 0)
+	KERNEL_PARAM_FL_UNSAFE	= (1 << 0),
+	KERNEL_PARAM_FL_HWPARAM	= (1 << 1),
 };
 
 struct kernel_param {
@@ -451,6 +453,67 @@
 			    perm, -1, 0);				\
 	__MODULE_PARM_TYPE(name, "array of " #type)
 
+enum hwparam_type {
+	hwparam_ioport,		/* Module parameter configures an I/O port */
+	hwparam_iomem,		/* Module parameter configures an I/O mem address */
+	hwparam_ioport_or_iomem, /* Module parameter could be either, depending on other option */
+	hwparam_irq,		/* Module parameter configures an I/O port */
+	hwparam_dma,		/* Module parameter configures a DMA channel */
+	hwparam_dma_addr,	/* Module parameter configures a DMA buffer address */
+	hwparam_other,		/* Module parameter configures some other value */
+};
+
+/**
+ * module_param_hw_named - A parameter representing a hw parameters
+ * @name: a valid C identifier which is the parameter name.
+ * @value: the actual lvalue to alter.
+ * @type: the type of the parameter
+ * @hwtype: what the value represents (enum hwparam_type)
+ * @perm: visibility in sysfs.
+ *
+ * Usually it's a good idea to have variable names and user-exposed names the
+ * same, but that's harder if the variable must be non-static or is inside a
+ * structure.  This allows exposure under a different name.
+ */
+#define module_param_hw_named(name, value, type, hwtype, perm)		\
+	param_check_##type(name, &(value));				\
+	__module_param_call(MODULE_PARAM_PREFIX, name,			\
+			    &param_ops_##type, &value,			\
+			    perm, -1,					\
+			    KERNEL_PARAM_FL_HWPARAM | (hwparam_##hwtype & 0));	\
+	__MODULE_PARM_TYPE(name, #type)
+
+#define module_param_hw(name, type, hwtype, perm)		\
+	module_param_hw_named(name, name, type, hwtype, perm)
+
+/**
+ * module_param_hw_array - A parameter representing an array of hw parameters
+ * @name: the name of the array variable
+ * @type: the type, as per module_param()
+ * @hwtype: what the value represents (enum hwparam_type)
+ * @nump: optional pointer filled in with the number written
+ * @perm: visibility in sysfs
+ *
+ * Input and output are as comma-separated values.  Commas inside values
+ * don't work properly (eg. an array of charp).
+ *
+ * ARRAY_SIZE(@name) is used to determine the number of elements in the
+ * array, so the definition must be visible.
+ */
+#define module_param_hw_array(name, type, hwtype, nump, perm)		\
+	param_check_##type(name, &(name)[0]);				\
+	static const struct kparam_array __param_arr_##name		\
+	= { .max = ARRAY_SIZE(name), .num = nump,			\
+	    .ops = &param_ops_##type,					\
+	    .elemsize = sizeof(name[0]), .elem = name };		\
+	__module_param_call(MODULE_PARAM_PREFIX, name,			\
+			    &param_array_ops,				\
+			    .arr = &__param_arr_##name,			\
+			    perm, -1,					\
+			    KERNEL_PARAM_FL_HWPARAM | (hwparam_##hwtype & 0));	\
+	__MODULE_PARM_TYPE(name, "array of " #type)
+
+
 extern const struct kernel_param_ops param_array_ops;
 
 extern const struct kernel_param_ops param_ops_string;
--- linux-4.4.0.orig/include/linux/mount.h
+++ linux-4.4.0/include/linux/mount.h
@@ -81,6 +81,7 @@
 extern struct vfsmount *mntget(struct vfsmount *mnt);
 extern struct vfsmount *mnt_clone_internal(struct path *path);
 extern int __mnt_is_readonly(struct vfsmount *mnt);
+extern bool mnt_may_suid(struct vfsmount *mnt);
 
 struct path;
 extern struct vfsmount *clone_private_mount(struct path *path);
@@ -89,10 +90,15 @@
 extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
 				      int flags, const char *name,
 				      void *data);
+extern struct vfsmount *vfs_submount(const struct dentry *mountpoint,
+				     struct file_system_type *type,
+				     const char *name, void *data);
 
 extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list);
 extern void mark_mounts_for_expiry(struct list_head *mounts);
 
 extern dev_t name_to_dev_t(const char *name);
 
+extern unsigned int sysctl_mount_max;
+
 #endif /* _LINUX_MOUNT_H */
--- linux-4.4.0.orig/include/linux/mroute.h
+++ linux-4.4.0/include/linux/mroute.h
@@ -103,5 +103,5 @@
 struct rtmsg;
 extern int ipmr_get_route(struct net *net, struct sk_buff *skb,
 			  __be32 saddr, __be32 daddr,
-			  struct rtmsg *rtm, int nowait);
+			  struct rtmsg *rtm, int nowait, u32 portid);
 #endif
--- linux-4.4.0.orig/include/linux/mroute6.h
+++ linux-4.4.0/include/linux/mroute6.h
@@ -115,7 +115,7 @@
 
 struct rtmsg;
 extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,
-			   struct rtmsg *rtm, int nowait);
+			   struct rtmsg *rtm, int nowait, u32 portid);
 
 #ifdef CONFIG_IPV6_MROUTE
 extern struct sock *mroute6_socket(struct net *net, struct sk_buff *skb);
--- linux-4.4.0.orig/include/linux/msi.h
+++ linux-4.4.0/include/linux/msi.h
@@ -17,7 +17,13 @@
 struct pci_dev;
 struct platform_msi_priv_data;
 void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+#ifdef CONFIG_GENERIC_MSI_IRQ
 void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
+#else
+static inline void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+}
+#endif
 
 typedef void (*irq_write_msi_msg_t)(struct msi_desc *desc,
 				    struct msi_msg *msg);
@@ -105,18 +111,21 @@
 
 struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc);
 void *msi_desc_to_pci_sysdata(struct msi_desc *desc);
+void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg);
 #else /* CONFIG_PCI_MSI */
 static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc)
 {
 	return NULL;
 }
+static inline void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+}
 #endif /* CONFIG_PCI_MSI */
 
 struct msi_desc *alloc_msi_entry(struct device *dev);
 void free_msi_entry(struct msi_desc *entry);
 void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
 u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag);
 u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag);
@@ -254,12 +263,12 @@
 	 * callbacks.
 	 */
 	MSI_FLAG_USE_DEF_CHIP_OPS	= (1 << 1),
-	/* Build identity map between hwirq and irq */
-	MSI_FLAG_IDENTITY_MAP		= (1 << 2),
 	/* Support multiple PCI MSI interrupts */
-	MSI_FLAG_MULTI_PCI_MSI		= (1 << 3),
+	MSI_FLAG_MULTI_PCI_MSI		= (1 << 2),
 	/* Support PCI MSIX interrupts */
-	MSI_FLAG_PCI_MSIX		= (1 << 4),
+	MSI_FLAG_PCI_MSIX		= (1 << 3),
+	/* Needs early activate, required for PCI */
+	MSI_FLAG_ACTIVATE_EARLY		= (1 << 4),
 };
 
 int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
--- linux-4.4.0.orig/include/linux/mtd/flashchip.h
+++ linux-4.4.0/include/linux/mtd/flashchip.h
@@ -85,6 +85,7 @@
 	unsigned int write_suspended:1;
 	unsigned int erase_suspended:1;
 	unsigned long in_progress_block_addr;
+	unsigned long in_progress_block_mask;
 
 	struct mutex mutex;
 	wait_queue_head_t wq; /* Wait on here when we're waiting for the chip
--- linux-4.4.0.orig/include/linux/mtd/map.h
+++ linux-4.4.0/include/linux/mtd/map.h
@@ -122,18 +122,13 @@
 #endif
 
 #ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
-# ifdef map_bankwidth
-#  undef map_bankwidth
-#  define map_bankwidth(map) ((map)->bankwidth)
-#  undef map_bankwidth_is_large
-#  define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
-#  undef map_words
-#  define map_words(map) map_calc_words(map)
-# else
-#  define map_bankwidth(map) 32
-#  define map_bankwidth_is_large(map) (1)
-#  define map_words(map) map_calc_words(map)
-# endif
+/* always use indirect access for 256-bit to preserve kernel stack */
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# undef map_bankwidth_is_large
+# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
+# undef map_words
+# define map_words(map) map_calc_words(map)
 #define map_bankwidth_is_32(map) (map_bankwidth(map) == 32)
 #undef MAX_MAP_BANKWIDTH
 #define MAX_MAP_BANKWIDTH 32
@@ -270,75 +265,67 @@
 #define INVALIDATE_CACHED_RANGE(map, from, size) \
 	do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0)
 
-
-static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
-{
-	int i;
-
-	for (i = 0; i < map_words(map); i++) {
-		if (val1.x[i] != val2.x[i])
-			return 0;
-	}
-
-	return 1;
-}
-
-static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
-{
-	map_word r;
-	int i;
-
-	for (i = 0; i < map_words(map); i++)
-		r.x[i] = val1.x[i] & val2.x[i];
-
-	return r;
-}
-
-static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
-{
-	map_word r;
-	int i;
-
-	for (i = 0; i < map_words(map); i++)
-		r.x[i] = val1.x[i] & ~val2.x[i];
-
-	return r;
-}
-
-static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
-{
-	map_word r;
-	int i;
-
-	for (i = 0; i < map_words(map); i++)
-		r.x[i] = val1.x[i] | val2.x[i];
-
-	return r;
-}
-
-static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3)
-{
-	int i;
-
-	for (i = 0; i < map_words(map); i++) {
-		if ((val1.x[i] & val2.x[i]) != val3.x[i])
-			return 0;
-	}
-
-	return 1;
-}
-
-static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
-{
-	int i;
-
-	for (i = 0; i < map_words(map); i++) {
-		if (val1.x[i] & val2.x[i])
-			return 1;
-	}
-
-	return 0;
-}
+#define map_word_equal(map, val1, val2)					\
+({									\
+	int i, ret = 1;							\
+	for (i = 0; i < map_words(map); i++)				\
+		if ((val1).x[i] != (val2).x[i]) {			\
+			ret = 0;					\
+			break;						\
+		}							\
+	ret;								\
+})
+
+#define map_word_and(map, val1, val2)					\
+({									\
+	map_word r;							\
+	int i;								\
+	for (i = 0; i < map_words(map); i++)				\
+		r.x[i] = (val1).x[i] & (val2).x[i];			\
+	r;								\
+})
+
+#define map_word_clr(map, val1, val2)					\
+({									\
+	map_word r;							\
+	int i;								\
+	for (i = 0; i < map_words(map); i++)				\
+		r.x[i] = (val1).x[i] & ~(val2).x[i];			\
+	r;								\
+})
+
+#define map_word_or(map, val1, val2)					\
+({									\
+	map_word r;							\
+	int i;								\
+	for (i = 0; i < map_words(map); i++)				\
+		r.x[i] = (val1).x[i] | (val2).x[i];			\
+	r;								\
+})
+
+#define map_word_andequal(map, val1, val2, val3)			\
+({									\
+	int i, ret = 1;							\
+	for (i = 0; i < map_words(map); i++) {				\
+		if (((val1).x[i] & (val2).x[i]) != (val3).x[i]) {	\
+			ret = 0;					\
+			break;						\
+		}							\
+	}								\
+	ret;								\
+})
+
+#define map_word_bitsset(map, val1, val2)				\
+({									\
+	int i, ret = 0;							\
+	for (i = 0; i < map_words(map); i++) {				\
+		if ((val1).x[i] & (val2).x[i]) {			\
+			ret = 1;					\
+			break;						\
+		}							\
+	}								\
+	ret;								\
+})
 
 static inline map_word map_word_load(struct map_info *map, const void *ptr)
 {
--- linux-4.4.0.orig/include/linux/mtd/nand.h
+++ linux-4.4.0/include/linux/mtd/nand.h
@@ -38,7 +38,7 @@
 			   struct nand_flash_dev *table);
 extern int nand_scan_tail(struct mtd_info *mtd);
 
-/* Free resources held by the NAND device */
+/* Unregister the MTD device and free resources held by the NAND device */
 extern void nand_release(struct mtd_info *mtd);
 
 /* Internal helper for board drivers which need to override command function */
@@ -276,7 +276,7 @@
 	__le16 t_r;
 	__le16 t_ccs;
 	__le16 src_sync_timing_mode;
-	__le16 src_ssync_features;
+	u8 src_ssync_features;
 	__le16 clk_pin_capacitance_typ;
 	__le16 io_pin_capacitance_typ;
 	__le16 input_pin_capacitance_typ;
@@ -284,7 +284,7 @@
 	u8 driver_strength_support;
 	__le16 t_int_r;
 	__le16 t_ald;
-	u8 reserved4[7];
+	u8 reserved4[8];
 
 	/* vendor */
 	__le16 vendor_revision;
@@ -1029,4 +1029,8 @@
 				void *ecc, int ecclen,
 				void *extraoob, int extraooblen,
 				int threshold);
+
+/* Free resources held by the NAND device */
+void nand_cleanup(struct nand_chip *chip);
+
 #endif /* __LINUX_MTD_NAND_H */
--- linux-4.4.0.orig/include/linux/mtd/pfow.h
+++ linux-4.4.0/include/linux/mtd/pfow.h
@@ -127,7 +127,7 @@
 
 	if (!(dsr & DSR_AVAILABLE))
 		printk(KERN_NOTICE"DSR.15: (0) Device not Available\n");
-	if (prog_status & 0x03)
+	if ((prog_status & 0x03) == 0x03)
 		printk(KERN_NOTICE"DSR.9,8: (11) Attempt to program invalid "
 						"half with 41h command\n");
 	else if (prog_status & 0x02)
--- linux-4.4.0.orig/include/linux/mtd/sh_flctl.h
+++ linux-4.4.0/include/linux/mtd/sh_flctl.h
@@ -148,6 +148,7 @@
 	struct platform_device	*pdev;
 	struct dev_pm_qos_request pm_qos;
 	void __iomem		*reg;
+	resource_size_t		fifo;
 
 	uint8_t	done_buff[2048 + 64];	/* max size 2048 + 64 */
 	int	read_bytes;
--- linux-4.4.0.orig/include/linux/net.h
+++ linux-4.4.0/include/linux/net.h
@@ -217,8 +217,7 @@
 int sock_create_lite(int family, int type, int proto, struct socket **res);
 void sock_release(struct socket *sock);
 int sock_sendmsg(struct socket *sock, struct msghdr *msg);
-int sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
-		 int flags);
+int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags);
 struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname);
 struct socket *sockfd_lookup(int fd, int *err);
 struct socket *sock_from_file(struct file *file, int *err);
@@ -245,7 +244,16 @@
 	net_ratelimited_function(pr_warn, fmt, ##__VA_ARGS__)
 #define net_info_ratelimited(fmt, ...)				\
 	net_ratelimited_function(pr_info, fmt, ##__VA_ARGS__)
-#if defined(DEBUG)
+#if defined(CONFIG_DYNAMIC_DEBUG)
+#define net_dbg_ratelimited(fmt, ...)					\
+do {									\
+	DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);			\
+	if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) &&	\
+	    net_ratelimit())						\
+		__dynamic_pr_debug(&descriptor, pr_fmt(fmt),		\
+		                   ##__VA_ARGS__);			\
+} while (0)
+#elif defined(DEBUG)
 #define net_dbg_ratelimited(fmt, ...)				\
 	net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
 #else
@@ -282,6 +290,9 @@
 int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
 int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
 
+/* Routine returns the IP overhead imposed by a (caller-protected) socket. */
+u32 kernel_sock_ip_overhead(struct sock *sk);
+
 #define MODULE_ALIAS_NETPROTO(proto) \
 	MODULE_ALIAS("net-pf-" __stringify(proto))
 
--- linux-4.4.0.orig/include/linux/netdev_features.h
+++ linux-4.4.0/include/linux/netdev_features.h
@@ -11,6 +11,8 @@
 #define _LINUX_NETDEV_FEATURES_H
 
 #include <linux/types.h>
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
 
 typedef u64 netdev_features_t;
 
@@ -52,7 +54,7 @@
 		NETIF_F_GSO_TUNNEL_REMCSUM_BIT,
 
 	NETIF_F_FCOE_CRC_BIT,		/* FCoE CRC32 */
-	NETIF_F_SCTP_CSUM_BIT,		/* SCTP checksum offload */
+	NETIF_F_SCTP_CRC_BIT,		/* SCTP checksum offload */
 	NETIF_F_FCOE_MTU_BIT,		/* Supports max FCoE MTU, 2158 bytes*/
 	NETIF_F_NTUPLE_BIT,		/* N-tuple filters supported */
 	NETIF_F_RXHASH_BIT,		/* Receive hashing offload */
@@ -67,6 +69,8 @@
 	NETIF_F_HW_L2FW_DOFFLOAD_BIT,	/* Allow L2 Forwarding in Hardware */
 	NETIF_F_BUSY_POLL_BIT,		/* Busy poll */
 
+	NETIF_F_HW_TC_BIT,		/* Offload TC infrastructure */
+
 	/*
 	 * Add your fresh new feature above and remember to update
 	 * netdev_features_strings[] in net/core/ethtool.c and maybe
@@ -103,7 +107,7 @@
 #define NETIF_F_NTUPLE		__NETIF_F(NTUPLE)
 #define NETIF_F_RXCSUM		__NETIF_F(RXCSUM)
 #define NETIF_F_RXHASH		__NETIF_F(RXHASH)
-#define NETIF_F_SCTP_CSUM	__NETIF_F(SCTP_CSUM)
+#define NETIF_F_SCTP_CRC	__NETIF_F(SCTP_CRC)
 #define NETIF_F_SG		__NETIF_F(SG)
 #define NETIF_F_TSO6		__NETIF_F(TSO6)
 #define NETIF_F_TSO_ECN		__NETIF_F(TSO_ECN)
@@ -124,9 +128,28 @@
 #define NETIF_F_HW_VLAN_STAG_TX	__NETIF_F(HW_VLAN_STAG_TX)
 #define NETIF_F_HW_L2FW_DOFFLOAD	__NETIF_F(HW_L2FW_DOFFLOAD)
 #define NETIF_F_BUSY_POLL	__NETIF_F(BUSY_POLL)
+#define NETIF_F_HW_TC		__NETIF_F(HW_TC)
+
+/* Finds the next feature with the highest number of the range of start till 0.
+ */
+static inline int find_next_netdev_feature(u64 feature, unsigned long start)
+{
+	/* like BITMAP_LAST_WORD_MASK() for u64
+	 * this sets the most significant 64 - start to 0.
+	 */
+	feature &= ~0ULL >> (-start & ((sizeof(feature) * 8) - 1));
+
+	return fls64(feature) - 1;
+}
 
-#define for_each_netdev_feature(mask_addr, bit)	\
-	for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
+/* This goes for the MSB to the LSB through the set feature bits,
+ * mask_addr should be a u64 and bit an int
+ */
+#define for_each_netdev_feature(mask_addr, bit)				\
+	for ((bit) = find_next_netdev_feature((mask_addr),		\
+					      NETDEV_FEATURE_COUNT);	\
+	     (bit) >= 0;						\
+	     (bit) = find_next_netdev_feature((mask_addr), (bit) - 1))
 
 /* Features valid for ethtool to change */
 /* = all defined minus driver/device-class-related */
--- linux-4.4.0.orig/include/linux/netdevice.h
+++ linux-4.4.0/include/linux/netdevice.h
@@ -51,6 +51,7 @@
 #include <linux/neighbour.h>
 #include <uapi/linux/netdevice.h>
 #include <uapi/linux/if_bonding.h>
+#include <uapi/linux/pkt_cls.h>
 
 struct netpoll_info;
 struct device;
@@ -132,7 +133,9 @@
  *	used.
  */
 
-#if defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
+#if defined(CONFIG_HYPERV_NET)
+# define LL_MAX_HEADER 128
+#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
 # if defined(CONFIG_MAC80211_MESH)
 #  define LL_MAX_HEADER 128
 # else
@@ -154,31 +157,38 @@
  *	(unsigned long) so they can be read and written atomically.
  */
 
+#define NET_DEV_STAT(FIELD)			\
+	union {					\
+		unsigned long FIELD;		\
+		atomic_long_t __##FIELD;	\
+	}
+
 struct net_device_stats {
-	unsigned long	rx_packets;
-	unsigned long	tx_packets;
-	unsigned long	rx_bytes;
-	unsigned long	tx_bytes;
-	unsigned long	rx_errors;
-	unsigned long	tx_errors;
-	unsigned long	rx_dropped;
-	unsigned long	tx_dropped;
-	unsigned long	multicast;
-	unsigned long	collisions;
-	unsigned long	rx_length_errors;
-	unsigned long	rx_over_errors;
-	unsigned long	rx_crc_errors;
-	unsigned long	rx_frame_errors;
-	unsigned long	rx_fifo_errors;
-	unsigned long	rx_missed_errors;
-	unsigned long	tx_aborted_errors;
-	unsigned long	tx_carrier_errors;
-	unsigned long	tx_fifo_errors;
-	unsigned long	tx_heartbeat_errors;
-	unsigned long	tx_window_errors;
-	unsigned long	rx_compressed;
-	unsigned long	tx_compressed;
+	NET_DEV_STAT(rx_packets);
+	NET_DEV_STAT(tx_packets);
+	NET_DEV_STAT(rx_bytes);
+	NET_DEV_STAT(tx_bytes);
+	NET_DEV_STAT(rx_errors);
+	NET_DEV_STAT(tx_errors);
+	NET_DEV_STAT(rx_dropped);
+	NET_DEV_STAT(tx_dropped);
+	NET_DEV_STAT(multicast);
+	NET_DEV_STAT(collisions);
+	NET_DEV_STAT(rx_length_errors);
+	NET_DEV_STAT(rx_over_errors);
+	NET_DEV_STAT(rx_crc_errors);
+	NET_DEV_STAT(rx_frame_errors);
+	NET_DEV_STAT(rx_fifo_errors);
+	NET_DEV_STAT(rx_missed_errors);
+	NET_DEV_STAT(tx_aborted_errors);
+	NET_DEV_STAT(tx_carrier_errors);
+	NET_DEV_STAT(tx_fifo_errors);
+	NET_DEV_STAT(tx_heartbeat_errors);
+	NET_DEV_STAT(tx_window_errors);
+	NET_DEV_STAT(rx_compressed);
+	NET_DEV_STAT(tx_compressed);
 };
+#undef NET_DEV_STAT
 
 
 #include <linux/cache.h>
@@ -265,6 +275,7 @@
 	void	(*cache_update)(struct hh_cache *hh,
 				const struct net_device *dev,
 				const unsigned char *haddr);
+	bool	(*validate)(const char *ll_header, unsigned int len);
 };
 
 /* These flag bits are private to the generic network queueing
@@ -510,7 +521,6 @@
 	clear_bit(NAPI_STATE_NPSVC, &n->state);
 }
 
-#ifdef CONFIG_SMP
 /**
  *	napi_synchronize - wait until NAPI is not running
  *	@n: napi context
@@ -521,12 +531,12 @@
  */
 static inline void napi_synchronize(const struct napi_struct *n)
 {
-	while (test_bit(NAPI_STATE_SCHED, &n->state))
-		msleep(1);
+	if (IS_ENABLED(CONFIG_SMP))
+		while (test_bit(NAPI_STATE_SCHED, &n->state))
+			msleep(1);
+	else
+		barrier();
 }
-#else
-# define napi_synchronize(n)	barrier()
-#endif
 
 enum netdev_queue_state_t {
 	__QUEUE_STATE_DRV_XOFF,
@@ -777,6 +787,25 @@
 typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
 				       struct sk_buff *skb);
 
+/* These structures hold the attributes of qdisc and classifiers
+ * that are being passed to the netdevice through the setup_tc op.
+ */
+enum {
+	TC_SETUP_MQPRIO,
+	TC_SETUP_CLSU32,
+};
+
+struct tc_cls_u32_offload;
+
+struct tc_to_netdev {
+	unsigned int type;
+	union {
+		u8 tc;
+		struct tc_cls_u32_offload *cls_u32;
+	};
+};
+
+
 /*
  * This structure defines the management hooks for network devices.
  * The following hooks can be defined; unless noted otherwise, they are
@@ -1011,6 +1040,19 @@
  *	a new port starts listening. The operation is protected by the
  *	vxlan_net->sock_lock.
  *
+ * void (*ndo_add_geneve_port)(struct net_device *dev,
+ *			      sa_family_t sa_family, __be16 port);
+ *	Called by geneve to notify a driver about the UDP port and socket
+ *	address family that geneve is listnening to. It is called only when
+ *	a new port starts listening. The operation is protected by the
+ *	geneve_net->sock_lock.
+ *
+ * void (*ndo_del_geneve_port)(struct net_device *dev,
+ *			      sa_family_t sa_family, __be16 port);
+ *	Called by geneve to notify the driver about a UDP port and socket
+ *	address family that geneve is not listening to anymore. The operation
+ *	is protected by the geneve_net->sock_lock.
+ *
  * void (*ndo_del_vxlan_port)(struct  net_device *dev,
  *			      sa_family_t sa_family, __be16 port);
  *	Called by vxlan to notify the driver about a UDP port and socket
@@ -1133,7 +1175,10 @@
 	int			(*ndo_set_vf_rss_query_en)(
 						   struct net_device *dev,
 						   int vf, bool setting);
-	int			(*ndo_setup_tc)(struct net_device *dev, u8 tc);
+	int			(*ndo_setup_tc)(struct net_device *dev,
+						u32 handle,
+						__be16 protocol,
+						struct tc_to_netdev *tc);
 #if IS_ENABLED(CONFIG_FCOE)
 	int			(*ndo_fcoe_enable)(struct net_device *dev);
 	int			(*ndo_fcoe_disable)(struct net_device *dev);
@@ -1215,7 +1260,12 @@
 	void			(*ndo_del_vxlan_port)(struct  net_device *dev,
 						      sa_family_t sa_family,
 						      __be16 port);
-
+	void			(*ndo_add_geneve_port)(struct  net_device *dev,
+						       sa_family_t sa_family,
+						       __be16 port);
+	void			(*ndo_del_geneve_port)(struct  net_device *dev,
+						       sa_family_t sa_family,
+						       __be16 port);
 	void*			(*ndo_dfwd_add_station)(struct net_device *pdev,
 							struct net_device *dev);
 	void			(*ndo_dfwd_del_station)(struct net_device *pdev,
@@ -1271,6 +1321,8 @@
  * @IFF_NO_QUEUE: device can run without qdisc attached
  * @IFF_OPENVSWITCH: device is a Open vSwitch master
  * @IFF_L3MDEV_SLAVE: device is enslaved to an L3 master device
+ * @IFF_TEAM: device is a team device
+ * @IFF_RXFH_CONFIGURED: device has had Rx Flow indirection table configured
  */
 enum netdev_priv_flags {
 	IFF_802_1Q_VLAN			= 1<<0,
@@ -1297,6 +1349,8 @@
 	IFF_NO_QUEUE			= 1<<21,
 	IFF_OPENVSWITCH			= 1<<22,
 	IFF_L3MDEV_SLAVE		= 1<<23,
+	IFF_TEAM			= 1<<24,
+	IFF_RXFH_CONFIGURED		= 1<<25,
 };
 
 #define IFF_802_1Q_VLAN			IFF_802_1Q_VLAN
@@ -1323,6 +1377,8 @@
 #define IFF_NO_QUEUE			IFF_NO_QUEUE
 #define IFF_OPENVSWITCH			IFF_OPENVSWITCH
 #define IFF_L3MDEV_SLAVE		IFF_L3MDEV_SLAVE
+#define IFF_TEAM			IFF_TEAM
+#define IFF_RXFH_CONFIGURED		IFF_RXFH_CONFIGURED
 
 /**
  *	struct net_device - The DEVICE structure.
@@ -1398,8 +1454,8 @@
  *	@dma:		DMA channel
  *	@mtu:		Interface MTU value
  *	@type:		Interface hardware type
- *	@hard_header_len: Hardware header length, which means that this is the
- *			  minimum size of a packet.
+ *	@hard_header_len: Maximum hardware header length.
+ *	@min_header_len:  Minimum hardware header length
  *
  *	@needed_headroom: Extra headroom the hardware may need, but not in all
  *			  cases can this be guaranteed
@@ -1617,9 +1673,15 @@
 	unsigned char		if_port;
 	unsigned char		dma;
 
+	/* Note : dev->mtu is often read without holding a lock.
+	 * Writers usually hold RTNL.
+	 * It is recommended to use READ_ONCE() to annotate the reads,
+	 * and to use WRITE_ONCE() to annotate the writes.
+	 */
 	unsigned int		mtu;
 	unsigned short		type;
 	unsigned short		hard_header_len;
+	unsigned short		min_header_len;
 
 	unsigned short		needed_headroom;
 	unsigned short		needed_tailroom;
@@ -1987,8 +2049,8 @@
 	/* This is non-zero if the packet may be of the same flow. */
 	u8	same_flow:1;
 
-	/* Used in udp_gro_receive */
-	u8	udp_mark:1;
+	/* Used in tunnel GRO receive */
+	u8	encap_mark:1;
 
 	/* GRO checksum is valid */
 	u8	csum_valid:1;
@@ -2004,7 +2066,13 @@
 	/* Used in foo-over-udp, set in udp[46]_gro_receive */
 	u8	is_ipv6:1;
 
-	/* 7 bit hole */
+	/* Number of gro_receive callbacks this packet already went through */
+	u8 recursion_counter:4;
+
+	/* Used in GRE, set in fou/gue_gro_receive */
+	u8	is_fou:1;
+
+	/* 2 bit hole */
 
 	/* used to support CHECKSUM_COMPLETE for tunneling protocols */
 	__wsum	csum;
@@ -2015,6 +2083,25 @@
 
 #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
 
+#define GRO_RECURSION_LIMIT 15
+static inline int gro_recursion_inc_test(struct sk_buff *skb)
+{
+	return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT;
+}
+
+typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff *);
+static inline struct sk_buff **call_gro_receive(gro_receive_t cb,
+						struct sk_buff **head,
+						struct sk_buff *skb)
+{
+	if (unlikely(gro_recursion_inc_test(skb))) {
+		NAPI_GRO_CB(skb)->flush |= 1;
+		return NULL;
+	}
+
+	return cb(head, skb);
+}
+
 struct packet_type {
 	__be16			type;	/* This is really htons(ether_type). */
 	struct net_device	*dev;	/* NULL is wildcarded here	     */
@@ -2060,6 +2147,22 @@
 	struct udp_offload_callbacks callbacks;
 };
 
+typedef struct sk_buff **(*gro_receive_udp_t)(struct sk_buff **,
+					      struct sk_buff *,
+					      struct udp_offload *);
+static inline struct sk_buff **call_gro_receive_udp(gro_receive_udp_t cb,
+						    struct sk_buff **head,
+						    struct sk_buff *skb,
+						    struct udp_offload *uoff)
+{
+	if (unlikely(gro_recursion_inc_test(skb))) {
+		NAPI_GRO_CB(skb)->flush |= 1;
+		return NULL;
+	}
+
+	return cb(head, skb, uoff);
+}
+
 /* often modified stats are per cpu, other are shared (netdev->stats) */
 struct pcpu_sw_netstats {
 	u64     rx_packets;
@@ -2129,6 +2232,13 @@
 	struct net_device *dev;
 };
 
+struct netdev_notifier_info_ext {
+	struct netdev_notifier_info info; /* must be first */
+	union {
+		u32 mtu;
+	} ext;
+};
+
 struct netdev_notifier_change_info {
 	struct netdev_notifier_info info; /* must be first */
 	unsigned int flags_changed;
@@ -2288,14 +2398,19 @@
 	return NAPI_GRO_CB(skb)->frag0_len < hlen;
 }
 
+static inline void skb_gro_frag0_invalidate(struct sk_buff *skb)
+{
+	NAPI_GRO_CB(skb)->frag0 = NULL;
+	NAPI_GRO_CB(skb)->frag0_len = 0;
+}
+
 static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
 					unsigned int offset)
 {
 	if (!pskb_may_pull(skb, hlen))
 		return NULL;
 
-	NAPI_GRO_CB(skb)->frag0 = NULL;
-	NAPI_GRO_CB(skb)->frag0_len = 0;
+	skb_gro_frag0_invalidate(skb);
 	return skb->data + offset;
 }
 
@@ -2493,6 +2608,26 @@
 	return dev->header_ops->parse(skb, haddr);
 }
 
+/* ll_header must have at least hard_header_len allocated */
+static inline bool dev_validate_header(const struct net_device *dev,
+				       char *ll_header, int len)
+{
+	if (likely(len >= dev->hard_header_len))
+		return true;
+	if (len < dev->min_header_len)
+		return false;
+
+	if (capable(CAP_SYS_RAWIO)) {
+		memset(ll_header + len, 0, dev->hard_header_len - len);
+		return true;
+	}
+
+	if (dev->header_ops && dev->header_ops->validate)
+		return dev->header_ops->validate(ll_header, len);
+
+	return false;
+}
+
 typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
 int register_gifconf(unsigned int family, gifconf_func_t *gifconf);
 static inline int unregister_gifconf(unsigned int family)
@@ -3019,6 +3154,7 @@
 	napi->skb = NULL;
 }
 
+bool netdev_is_rx_handler_busy(struct net_device *dev);
 int netdev_rx_handler_register(struct net_device *dev,
 			       rx_handler_func_t *rx_handler,
 			       void *rx_handler_data);
@@ -3035,6 +3171,7 @@
 int dev_change_name(struct net_device *, const char *);
 int dev_set_alias(struct net_device *, const char *, size_t);
 int dev_change_net_namespace(struct net_device *, struct net *, const char *);
+int __dev_set_mtu(struct net_device *, int);
 int dev_set_mtu(struct net_device *, int);
 void dev_set_group(struct net_device *, int);
 int dev_set_mac_address(struct net_device *, struct sockaddr *);
@@ -3064,7 +3201,8 @@
  */
 static inline void dev_put(struct net_device *dev)
 {
-	this_cpu_dec(*dev->pcpu_refcnt);
+	if (dev)
+		this_cpu_dec(*dev->pcpu_refcnt);
 }
 
 /**
@@ -3075,7 +3213,8 @@
  */
 static inline void dev_hold(struct net_device *dev)
 {
-	this_cpu_inc(*dev->pcpu_refcnt);
+	if (dev)
+		this_cpu_inc(*dev->pcpu_refcnt);
 }
 
 /* Carrier loss detection, dial on demand. The functions netif_carrier_on
@@ -3226,7 +3365,7 @@
 	if (debug_value == 0)	/* no output */
 		return 0;
 	/* set low N bits */
-	return (1 << debug_value) - 1;
+	return (1U << debug_value) - 1;
 }
 
 static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu)
@@ -3348,6 +3487,7 @@
 
 	local_bh_disable();
 	cpu = smp_processor_id();
+	spin_lock(&dev->tx_global_lock);
 	for (i = 0; i < dev->num_tx_queues; i++) {
 		struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
 
@@ -3355,6 +3495,7 @@
 		netif_tx_stop_queue(txq);
 		__netif_tx_unlock(txq);
 	}
+	spin_unlock(&dev->tx_global_lock);
 	local_bh_enable();
 }
 
@@ -3404,6 +3545,9 @@
 				    unsigned char name_assign_type,
 				    void (*setup)(struct net_device *),
 				    unsigned int txqs, unsigned int rxqs);
+int dev_get_valid_name(struct net *net, struct net_device *dev,
+		       const char *name);
+
 #define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \
 	alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, 1, 1)
 
@@ -3868,6 +4012,31 @@
 	return dev->priv_flags & IFF_OPENVSWITCH;
 }
 
+static inline bool netif_is_team_master(struct net_device *dev)
+{
+	return dev->priv_flags & IFF_TEAM;
+}
+
+static inline bool netif_is_team_port(struct net_device *dev)
+{
+	return dev->priv_flags & IFF_TEAM_PORT;
+}
+
+static inline bool netif_is_lag_master(struct net_device *dev)
+{
+	return netif_is_bond_master(dev) || netif_is_team_master(dev);
+}
+
+static inline bool netif_is_lag_port(struct net_device *dev)
+{
+	return netif_is_bond_slave(dev) || netif_is_team_port(dev);
+}
+
+static inline bool netif_is_rxfh_configured(const struct net_device *dev)
+{
+	return dev->priv_flags & IFF_RXFH_CONFIGURED;
+}
+
 /* This device needs to keep skb dst for qdisc enqueue or ndo_start_xmit() */
 static inline void netif_keep_dst(struct net_device *dev)
 {
@@ -4048,4 +4217,9 @@
 #define PTYPE_HASH_SIZE	(16)
 #define PTYPE_HASH_MASK	(PTYPE_HASH_SIZE - 1)
 
+/* Note: Avoid these macros in fast path, prefer per-cpu or per-queue counters. */
+#define DEV_STATS_INC(DEV, FIELD) atomic_long_inc(&(DEV)->stats.__##FIELD)
+#define DEV_STATS_ADD(DEV, FIELD, VAL) 	\
+		atomic_long_add((VAL), &(DEV)->stats.__##FIELD)
+
 #endif	/* _LINUX_NETDEVICE_H */
--- linux-4.4.0.orig/include/linux/netfilter/ipset/ip_set.h
+++ linux-4.4.0/include/linux/netfilter/ipset/ip_set.h
@@ -234,6 +234,10 @@
 	spinlock_t lock;
 	/* References to the set */
 	u32 ref;
+	/* References to the set for netlink events like dump,
+	 * ref can be swapped out by ip_set_swap
+	 */
+	u32 ref_netlink;
 	/* The core set type */
 	struct ip_set_type *type;
 	/* The type variant doing the real job */
@@ -530,13 +534,6 @@
 	       sizeof(*addr));
 }
 
-/* Calculate the bytes required to store the inclusive range of a-b */
-static inline int
-bitmap_bytes(u32 a, u32 b)
-{
-	return 4 * ((((b - a + 8) / 8) + 3) / 4);
-}
-
 #include <linux/netfilter/ipset/ip_set_timeout.h>
 #include <linux/netfilter/ipset/ip_set_comment.h>
 
--- linux-4.4.0.orig/include/linux/netfilter/ipset/ip_set_comment.h
+++ linux-4.4.0/include/linux/netfilter/ipset/ip_set_comment.h
@@ -41,11 +41,11 @@
 	rcu_assign_pointer(comment->c, c);
 }
 
-/* Used only when dumping a set, protected by rcu_read_lock_bh() */
+/* Used only when dumping a set, protected by rcu_read_lock() */
 static inline int
 ip_set_put_comment(struct sk_buff *skb, struct ip_set_comment *comment)
 {
-	struct ip_set_comment_rcu *c = rcu_dereference_bh(comment->c);
+	struct ip_set_comment_rcu *c = rcu_dereference(comment->c);
 
 	if (!c)
 		return 0;
--- linux-4.4.0.orig/include/linux/netfilter/ipset/ip_set_timeout.h
+++ linux-4.4.0/include/linux/netfilter/ipset/ip_set_timeout.h
@@ -65,8 +65,14 @@
 static inline u32
 ip_set_timeout_get(unsigned long *timeout)
 {
-	return *timeout == IPSET_ELEM_PERMANENT ? 0 :
-		jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC;
+	u32 t;
+
+	if (*timeout == IPSET_ELEM_PERMANENT)
+		return 0;
+
+	t = jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC;
+	/* Zero value in userspace means no timeout */
+	return t == 0 ? 1 : t;
 }
 
 #endif	/* __KERNEL__ */
--- linux-4.4.0.orig/include/linux/netfilter/nf_conntrack_pptp.h
+++ linux-4.4.0/include/linux/netfilter/nf_conntrack_pptp.h
@@ -4,7 +4,7 @@
 
 #include <linux/netfilter/nf_conntrack_common.h>
 
-extern const char *const pptp_msg_name[];
+const char *pptp_msg_name(u_int16_t msg);
 
 /* state of the control session */
 enum pptp_ctrlsess_state {
--- linux-4.4.0.orig/include/linux/netfilter/nfnetlink.h
+++ linux-4.4.0/include/linux/netfilter/nfnetlink.h
@@ -8,12 +8,12 @@
 #include <uapi/linux/netfilter/nfnetlink.h>
 
 struct nfnl_callback {
-	int (*call)(struct sock *nl, struct sk_buff *skb, 
-		    const struct nlmsghdr *nlh,
-		    const struct nlattr * const cda[]);
-	int (*call_rcu)(struct sock *nl, struct sk_buff *skb, 
+	int (*call)(struct net *net, struct sock *nl, struct sk_buff *skb,
 		    const struct nlmsghdr *nlh,
 		    const struct nlattr * const cda[]);
+	int (*call_rcu)(struct net *net, struct sock *nl, struct sk_buff *skb,
+			const struct nlmsghdr *nlh,
+			const struct nlattr * const cda[]);
 	int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
 			  const struct nlmsghdr *nlh,
 			  const struct nlattr * const cda[]);
--- linux-4.4.0.orig/include/linux/netfilter/x_tables.h
+++ linux-4.4.0/include/linux/netfilter/x_tables.h
@@ -135,6 +135,7 @@
 
 	const char *table;
 	unsigned int matchsize;
+	unsigned int usersize;
 #ifdef CONFIG_COMPAT
 	unsigned int compatsize;
 #endif
@@ -175,6 +176,7 @@
 
 	const char *table;
 	unsigned int targetsize;
+	unsigned int usersize;
 #ifdef CONFIG_COMPAT
 	unsigned int compatsize;
 #endif
@@ -239,11 +241,31 @@
 int xt_register_matches(struct xt_match *match, unsigned int n);
 void xt_unregister_matches(struct xt_match *match, unsigned int n);
 
+int xt_check_entry_offsets(const void *base, const char *elems,
+			   unsigned int target_offset,
+			   unsigned int next_offset);
+
+unsigned int *xt_alloc_entry_offsets(unsigned int size);
+bool xt_find_jump_offset(const unsigned int *offsets,
+			 unsigned int target, unsigned int size);
+
+int xt_check_proc_name(const char *name, unsigned int size);
+
 int xt_check_match(struct xt_mtchk_param *, unsigned int size, u_int8_t proto,
 		   bool inv_proto);
 int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto,
 		    bool inv_proto);
 
+int xt_match_to_user(const struct xt_entry_match *m,
+		     struct xt_entry_match __user *u);
+int xt_target_to_user(const struct xt_entry_target *t,
+		      struct xt_entry_target __user *u);
+int xt_data_to_user(void __user *dst, const void *src,
+		    int usersize, int size, int aligned_size);
+
+void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
+				 struct xt_counters_info *info, bool compat);
+
 struct xt_table *xt_register_table(struct net *net,
 				   const struct xt_table *table,
 				   struct xt_table_info *bootstrap,
@@ -314,7 +336,7 @@
 	 * since addend is most likely 1
 	 */
 	__this_cpu_add(xt_recseq.sequence, addend);
-	smp_wmb();
+	smp_mb();
 
 	return addend;
 }
@@ -357,38 +379,14 @@
 	return ret;
 }
 
+struct xt_percpu_counter_alloc_state {
+       unsigned int off;
+       const char __percpu *mem;
+};
 
-/* On SMP, ip(6)t_entry->counters.pcnt holds address of the
- * real (percpu) counter.  On !SMP, its just the packet count,
- * so nothing needs to be done there.
- *
- * xt_percpu_counter_alloc returns the address of the percpu
- * counter, or 0 on !SMP. We force an alignment of 16 bytes
- * so that bytes/packets share a common cache line.
- *
- * Hence caller must use IS_ERR_VALUE to check for error, this
- * allows us to return 0 for single core systems without forcing
- * callers to deal with SMP vs. NONSMP issues.
- */
-static inline u64 xt_percpu_counter_alloc(void)
-{
-	if (nr_cpu_ids > 1) {
-		void __percpu *res = __alloc_percpu(sizeof(struct xt_counters),
-						    sizeof(struct xt_counters));
-
-		if (res == NULL)
-			return (u64) -ENOMEM;
-
-		return (u64) (__force unsigned long) res;
-	}
-
-	return 0;
-}
-static inline void xt_percpu_counter_free(u64 pcnt)
-{
-	if (nr_cpu_ids > 1)
-		free_percpu((void __percpu *) (unsigned long) pcnt);
-}
+bool xt_percpu_counter_alloc(struct xt_percpu_counter_alloc_state *state,
+                            struct xt_counters *counter);
+void xt_percpu_counter_free(struct xt_counters *cnt);
 
 static inline struct xt_counters *
 xt_get_this_cpu_counter(struct xt_counters *cnt)
@@ -478,7 +476,7 @@
 int xt_compat_calc_jump(u_int8_t af, unsigned int offset);
 
 int xt_compat_match_offset(const struct xt_match *match);
-int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
+void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
 			      unsigned int *size);
 int xt_compat_match_to_user(const struct xt_entry_match *m,
 			    void __user **dstptr, unsigned int *size);
@@ -488,6 +486,9 @@
 				unsigned int *size);
 int xt_compat_target_to_user(const struct xt_entry_target *t,
 			     void __user **dstptr, unsigned int *size);
+int xt_compat_check_entry_offsets(const void *base, const char *elems,
+				  unsigned int target_offset,
+				  unsigned int next_offset);
 
 #endif /* CONFIG_COMPAT */
 #endif /* _X_TABLES_H */
--- linux-4.4.0.orig/include/linux/netfilter_bridge/ebtables.h
+++ linux-4.4.0/include/linux/netfilter_bridge/ebtables.h
@@ -125,4 +125,9 @@
 /* True if the target is not a standard target */
 #define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0)
 
+static inline bool ebt_invalid_target(int target)
+{
+	return (target < -NUM_STANDARD_TARGETS || target >= 0);
+}
+
 #endif
--- linux-4.4.0.orig/include/linux/netlink.h
+++ linux-4.4.0/include/linux/netlink.h
@@ -131,6 +131,7 @@
 struct netlink_callback {
 	struct sk_buff		*skb;
 	const struct nlmsghdr	*nlh;
+	int			(*start)(struct netlink_callback *);
 	int			(*dump)(struct sk_buff * skb,
 					struct netlink_callback *cb);
 	int			(*done)(struct netlink_callback *cb);
@@ -153,6 +154,7 @@
 __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags);
 
 struct netlink_dump_control {
+	int (*start)(struct netlink_callback *);
 	int (*dump)(struct sk_buff *skb, struct netlink_callback *);
 	int (*done)(struct netlink_callback *);
 	void *data;
--- linux-4.4.0.orig/include/linux/netpoll.h
+++ linux-4.4.0/include/linux/netpoll.h
@@ -47,8 +47,9 @@
 };
 
 #ifdef CONFIG_NETPOLL
-extern void netpoll_poll_disable(struct net_device *dev);
-extern void netpoll_poll_enable(struct net_device *dev);
+void netpoll_poll_dev(struct net_device *dev);
+void netpoll_poll_disable(struct net_device *dev);
+void netpoll_poll_enable(struct net_device *dev);
 #else
 static inline void netpoll_poll_disable(struct net_device *dev) { return; }
 static inline void netpoll_poll_enable(struct net_device *dev) { return; }
--- linux-4.4.0.orig/include/linux/nfs4.h
+++ linux-4.4.0/include/linux/nfs4.h
@@ -266,7 +266,7 @@
 
 static inline bool seqid_mutating_err(u32 err)
 {
-	/* rfc 3530 section 8.1.5: */
+	/* See RFC 7530, section 9.1.7 */
 	switch (err) {
 	case NFS4ERR_STALE_CLIENTID:
 	case NFS4ERR_STALE_STATEID:
@@ -275,6 +275,7 @@
 	case NFS4ERR_BADXDR:
 	case NFS4ERR_RESOURCE:
 	case NFS4ERR_NOFILEHANDLE:
+	case NFS4ERR_MOVED:
 		return false;
 	};
 	return true;
--- linux-4.4.0.orig/include/linux/nfs_fs.h
+++ linux-4.4.0/include/linux/nfs_fs.h
@@ -544,9 +544,7 @@
 
 static inline loff_t nfs_size_to_loff_t(__u64 size)
 {
-	if (size > (__u64) OFFSET_MAX - 1)
-		return OFFSET_MAX - 1;
-	return (loff_t) size;
+	return min_t(u64, size, OFFSET_MAX);
 }
 
 static inline ino_t
--- linux-4.4.0.orig/include/linux/nospec.h
+++ linux-4.4.0/include/linux/nospec.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Linus Torvalds. All rights reserved.
+// Copyright(c) 2018 Alexei Starovoitov. All rights reserved.
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+
+#ifndef _LINUX_NOSPEC_H
+#define _LINUX_NOSPEC_H
+#include <asm/barrier.h>
+
+struct task_struct;
+
+#ifndef barrier_nospec
+#define barrier_nospec()	do { } while (0)
+#endif
+
+/**
+ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * When @index is out of bounds (@index >= @size), the sign bit will be
+ * set.  Extend the sign bit to all bits and invert, giving a result of
+ * zero for an out of bounds index, or ~0 if within bounds [0, @size).
+ */
+#ifndef array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+						    unsigned long size)
+{
+	/*
+	 * Always calculate and emit the mask even if the compiler
+	 * thinks the mask is not needed. The compiler does not take
+	 * into account the value of @index under speculation.
+	 */
+	OPTIMIZER_HIDE_VAR(index);
+	return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
+}
+#endif
+
+/*
+ * array_index_nospec - sanitize an array index after a bounds check
+ *
+ * For a code sequence like:
+ *
+ *     if (index < size) {
+ *         index = array_index_nospec(index, size);
+ *         val = array[index];
+ *     }
+ *
+ * ...if the CPU speculates past the bounds check then
+ * array_index_nospec() will clamp the index within the range of [0,
+ * size).
+ */
+#define array_index_nospec(index, size)					\
+({									\
+	typeof(index) _i = (index);					\
+	typeof(size) _s = (size);					\
+	unsigned long _mask = array_index_mask_nospec(_i, _s);		\
+									\
+	BUILD_BUG_ON(sizeof(_i) > sizeof(long));			\
+	BUILD_BUG_ON(sizeof(_s) > sizeof(long));			\
+									\
+	(typeof(_i)) (_i & _mask);					\
+})
+
+/* Speculation control prctl */
+int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which);
+int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
+			     unsigned long ctrl);
+/* Speculation control for seccomp enforced mitigation */
+void arch_seccomp_spec_mitigate(struct task_struct *task);
+
+#endif /* _LINUX_NOSPEC_H */
--- linux-4.4.0.orig/include/linux/nsproxy.h
+++ linux-4.4.0/include/linux/nsproxy.h
@@ -8,6 +8,7 @@
 struct uts_namespace;
 struct ipc_namespace;
 struct pid_namespace;
+struct cgroup_namespace;
 struct fs_struct;
 
 /*
@@ -33,6 +34,7 @@
 	struct mnt_namespace *mnt_ns;
 	struct pid_namespace *pid_ns_for_children;
 	struct net 	     *net_ns;
+	struct cgroup_namespace *cgroup_ns;
 };
 extern struct nsproxy init_nsproxy;
 
--- linux-4.4.0.orig/include/linux/nvme.h
+++ linux-4.4.0/include/linux/nvme.h
@@ -16,21 +16,92 @@
 #define _LINUX_NVME_H
 
 #include <linux/types.h>
+#include <linux/uuid.h>
 
-struct nvme_bar {
-	__u64			cap;	/* Controller Capabilities */
-	__u32			vs;	/* Version */
-	__u32			intms;	/* Interrupt Mask Set */
-	__u32			intmc;	/* Interrupt Mask Clear */
-	__u32			cc;	/* Controller Configuration */
-	__u32			rsvd1;	/* Reserved */
-	__u32			csts;	/* Controller Status */
-	__u32			nssr;	/* Subsystem Reset */
-	__u32			aqa;	/* Admin Queue Attributes */
-	__u64			asq;	/* Admin SQ Base Address */
-	__u64			acq;	/* Admin CQ Base Address */
-	__u32			cmbloc; /* Controller Memory Buffer Location */
-	__u32			cmbsz;  /* Controller Memory Buffer Size */
+/* NQN names in commands fields specified one size */
+#define NVMF_NQN_FIELD_LEN	256
+
+/* However the max length of a qualified name is another size */
+#define NVMF_NQN_SIZE		223
+
+#define NVMF_TRSVCID_SIZE	32
+#define NVMF_TRADDR_SIZE	256
+#define NVMF_TSAS_SIZE		256
+
+#define NVME_DISC_SUBSYS_NAME	"nqn.2014-08.org.nvmexpress.discovery"
+
+#define NVME_RDMA_IP_PORT	4420
+
+enum nvme_subsys_type {
+	NVME_NQN_DISC	= 1,		/* Discovery type target subsystem */
+	NVME_NQN_NVME	= 2,		/* NVME type target subsystem */
+};
+
+/* Address Family codes for Discovery Log Page entry ADRFAM field */
+enum {
+	NVMF_ADDR_FAMILY_PCI	= 0,	/* PCIe */
+	NVMF_ADDR_FAMILY_IP4	= 1,	/* IP4 */
+	NVMF_ADDR_FAMILY_IP6	= 2,	/* IP6 */
+	NVMF_ADDR_FAMILY_IB	= 3,	/* InfiniBand */
+	NVMF_ADDR_FAMILY_FC	= 4,	/* Fibre Channel */
+};
+
+/* Transport Type codes for Discovery Log Page entry TRTYPE field */
+enum {
+	NVMF_TRTYPE_RDMA	= 1,	/* RDMA */
+	NVMF_TRTYPE_FC		= 2,	/* Fibre Channel */
+	NVMF_TRTYPE_LOOP	= 254,	/* Reserved for host usage */
+	NVMF_TRTYPE_MAX,
+};
+
+/* Transport Requirements codes for Discovery Log Page entry TREQ field */
+enum {
+	NVMF_TREQ_NOT_SPECIFIED	= 0,	/* Not specified */
+	NVMF_TREQ_REQUIRED	= 1,	/* Required */
+	NVMF_TREQ_NOT_REQUIRED	= 2,	/* Not Required */
+};
+
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
+ * RDMA_QPTYPE field
+ */
+enum {
+	NVMF_RDMA_QPTYPE_CONNECTED	= 0, /* Reliable Connected */
+	NVMF_RDMA_QPTYPE_DATAGRAM	= 1, /* Reliable Datagram */
+};
+
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
+ * RDMA_QPTYPE field
+ */
+enum {
+	NVMF_RDMA_PRTYPE_NOT_SPECIFIED	= 0, /* No Provider Specified */
+	NVMF_RDMA_PRTYPE_IB		= 1, /* InfiniBand */
+	NVMF_RDMA_PRTYPE_ROCE		= 2, /* InfiniBand RoCE */
+	NVMF_RDMA_PRTYPE_ROCEV2		= 3, /* InfiniBand RoCEV2 */
+	NVMF_RDMA_PRTYPE_IWARP		= 4, /* IWARP */
+};
+
+/* RDMA Connection Management Service Type codes for Discovery Log Page
+ * entry TSAS RDMA_CMS field
+ */
+enum {
+	NVMF_RDMA_CMS_RDMA_CM	= 0, /* Sockets based enpoint addressing */
+};
+
+#define NVMF_AQ_DEPTH		32
+
+enum {
+	NVME_REG_CAP	= 0x0000,	/* Controller Capabilities */
+	NVME_REG_VS	= 0x0008,	/* Version */
+	NVME_REG_INTMS	= 0x000c,	/* Interrupt Mask Set */
+	NVME_REG_INTMC	= 0x0010,	/* Interrupt Mask Set */
+	NVME_REG_CC	= 0x0014,	/* Controller Configuration */
+	NVME_REG_CSTS	= 0x001c,	/* Controller Status */
+	NVME_REG_NSSR	= 0x0020,	/* NVM Subsystem Reset */
+	NVME_REG_AQA	= 0x0024,	/* Admin Queue Attributes */
+	NVME_REG_ASQ	= 0x0028,	/* Admin SQ Base Address */
+	NVME_REG_ACQ	= 0x0030,	/* Admin SQ Base Address */
+	NVME_REG_CMBLOC = 0x0038,	/* Controller Memory Buffer Location */
+	NVME_REG_CMBSZ	= 0x003c,	/* Controller Memory Buffer Size */
 };
 
 #define NVME_CAP_MQES(cap)	((cap) & 0xffff)
@@ -108,7 +179,11 @@
 	__u8			mdts;
 	__le16			cntlid;
 	__le32			ver;
-	__u8			rsvd84[172];
+	__le32			rtd3r;
+	__le32			rtd3e;
+	__le32			oaes;
+	__le32			ctratt;
+	__u8			rsvd100[156];
 	__le16			oacs;
 	__u8			acl;
 	__u8			aerl;
@@ -123,7 +198,7 @@
 	__u8			rsvd270[242];
 	__u8			sqes;
 	__u8			cqes;
-	__u8			rsvd514[2];
+	__le16			maxcmd;
 	__le32			nn;
 	__le16			oncs;
 	__le16			fuses;
@@ -136,7 +211,15 @@
 	__le16			acwu;
 	__u8			rsvd534[2];
 	__le32			sgls;
-	__u8			rsvd540[1508];
+	__u8			rsvd540[228];
+	char			subnqn[256];
+	__u8			rsvd1024[768];
+	__le32			ioccsz;
+	__le32			iorcsz;
+	__le16			icdoff;
+	__u8			ctrattr;
+	__u8			msdbd;
+	__u8			rsvd1804[244];
 	struct nvme_id_power_state	psd[32];
 	__u8			vs[1024];
 };
@@ -291,6 +374,84 @@
 	nvme_cmd_resv_release	= 0x15,
 };
 
+/*
+ * Descriptor subtype - lower 4 bits of nvme_(keyed_)sgl_desc identifier
+ *
+ * @NVME_SGL_FMT_ADDRESS:     absolute address of the data block
+ * @NVME_SGL_FMT_OFFSET:      relative offset of the in-capsule data block
+ * @NVME_SGL_FMT_INVALIDATE:  RDMA transport specific remote invalidation
+ *                            request subtype
+ */
+enum {
+	NVME_SGL_FMT_ADDRESS		= 0x00,
+	NVME_SGL_FMT_OFFSET		= 0x01,
+	NVME_SGL_FMT_INVALIDATE		= 0x0f,
+};
+
+/*
+ * Descriptor type - upper 4 bits of nvme_(keyed_)sgl_desc identifier
+ *
+ * For struct nvme_sgl_desc:
+ *   @NVME_SGL_FMT_DATA_DESC:		data block descriptor
+ *   @NVME_SGL_FMT_SEG_DESC:		sgl segment descriptor
+ *   @NVME_SGL_FMT_LAST_SEG_DESC:	last sgl segment descriptor
+ *
+ * For struct nvme_keyed_sgl_desc:
+ *   @NVME_KEY_SGL_FMT_DATA_DESC:	keyed data block descriptor
+ */
+enum {
+	NVME_SGL_FMT_DATA_DESC		= 0x00,
+	NVME_SGL_FMT_SEG_DESC		= 0x02,
+	NVME_SGL_FMT_LAST_SEG_DESC	= 0x03,
+	NVME_KEY_SGL_FMT_DATA_DESC	= 0x04,
+};
+
+struct nvme_sgl_desc {
+	__le64	addr;
+	__le32	length;
+	__u8	rsvd[3];
+	__u8	type;
+};
+
+struct nvme_keyed_sgl_desc {
+	__le64	addr;
+	__u8	length[3];
+	__u8	key[4];
+	__u8	type;
+};
+
+union nvme_data_ptr {
+	struct {
+		__le64	prp1;
+		__le64	prp2;
+	};
+	struct nvme_sgl_desc	sgl;
+	struct nvme_keyed_sgl_desc ksgl;
+};
+
+/*
+ * Lowest two bits of our flags field (FUSE field in the spec):
+ *
+ * @NVME_CMD_FUSE_FIRST:   Fused Operation, first command
+ * @NVME_CMD_FUSE_SECOND:  Fused Operation, second command
+ *
+ * Highest two bits in our flags field (PSDT field in the spec):
+ *
+ * @NVME_CMD_PSDT_SGL_METABUF:	Use SGLS for this transfer,
+ *	If used, MPTR contains addr of single physical buffer (byte aligned).
+ * @NVME_CMD_PSDT_SGL_METASEG:	Use SGLS for this transfer,
+ *	If used, MPTR contains an address of an SGL segment containing
+ *	exactly 1 SGL descriptor (qword aligned).
+ */
+enum {
+	NVME_CMD_FUSE_FIRST	= (1 << 0),
+	NVME_CMD_FUSE_SECOND	= (1 << 1),
+
+	NVME_CMD_SGL_METABUF	= (1 << 6),
+	NVME_CMD_SGL_METASEG	= (1 << 7),
+	NVME_CMD_SGL_ALL	= NVME_CMD_SGL_METABUF | NVME_CMD_SGL_METASEG,
+};
+
 struct nvme_common_command {
 	__u8			opcode;
 	__u8			flags;
@@ -298,8 +459,7 @@
 	__le32			nsid;
 	__le32			cdw2[2];
 	__le64			metadata;
-	__le64			prp1;
-	__le64			prp2;
+	union nvme_data_ptr	dptr;
 	__le32			cdw10[6];
 };
 
@@ -310,8 +470,7 @@
 	__le32			nsid;
 	__u64			rsvd2;
 	__le64			metadata;
-	__le64			prp1;
-	__le64			prp2;
+	union nvme_data_ptr	dptr;
 	__le64			slba;
 	__le16			length;
 	__le16			control;
@@ -351,8 +510,7 @@
 	__u16			command_id;
 	__le32			nsid;
 	__u64			rsvd2[2];
-	__le64			prp1;
-	__le64			prp2;
+	union nvme_data_ptr	dptr;
 	__le32			nr;
 	__le32			attributes;
 	__u32			rsvd12[4];
@@ -370,6 +528,12 @@
 	__le64			slba;
 };
 
+/* Features */
+
+struct nvme_feat_auto_pst {
+	__le64 entries[32];
+};
+
 /* Admin commands */
 
 enum nvme_admin_opcode {
@@ -388,6 +552,9 @@
 	nvme_admin_format_nvm		= 0x80,
 	nvme_admin_security_send	= 0x81,
 	nvme_admin_security_recv	= 0x82,
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	nvme_admin_doorbell_memory	= 0xC0,
+#endif
 };
 
 enum {
@@ -416,6 +583,7 @@
 	NVME_LOG_ERROR		= 0x01,
 	NVME_LOG_SMART		= 0x02,
 	NVME_LOG_FW_SLOT	= 0x03,
+	NVME_LOG_DISC		= 0x70,
 	NVME_LOG_RESERVATION	= 0x80,
 	NVME_FWACT_REPL		= (0 << 3),
 	NVME_FWACT_REPL_ACTV	= (1 << 3),
@@ -428,8 +596,7 @@
 	__u16			command_id;
 	__le32			nsid;
 	__u64			rsvd2[2];
-	__le64			prp1;
-	__le64			prp2;
+	union nvme_data_ptr	dptr;
 	__le32			cns;
 	__u32			rsvd11[5];
 };
@@ -440,8 +607,7 @@
 	__u16			command_id;
 	__le32			nsid;
 	__u64			rsvd2[2];
-	__le64			prp1;
-	__le64			prp2;
+	union nvme_data_ptr	dptr;
 	__le32			fid;
 	__le32			dword11;
 	__u32			rsvd12[4];
@@ -500,8 +666,7 @@
 	__u8			flags;
 	__u16			command_id;
 	__u32			rsvd1[5];
-	__le64			prp1;
-	__le64			prp2;
+	union nvme_data_ptr	dptr;
 	__le32			numd;
 	__le32			offset;
 	__u32			rsvd12[4];
@@ -517,6 +682,155 @@
 	__u32			rsvd11[5];
 };
 
+struct nvme_get_log_page_command {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2[2];
+	union nvme_data_ptr	dptr;
+	__u8			lid;
+	__u8			rsvd10;
+	__le16			numdl;
+	__le16			numdu;
+	__u16			rsvd11;
+	__le32			lpol;
+	__le32			lpou;
+	__u32			rsvd14[2];
+};
+
+/*
+ * Fabrics subcommands.
+ */
+enum nvmf_fabrics_opcode {
+	nvme_fabrics_command		= 0x7f,
+};
+
+enum nvmf_capsule_command {
+	nvme_fabrics_type_property_set	= 0x00,
+	nvme_fabrics_type_connect	= 0x01,
+	nvme_fabrics_type_property_get	= 0x04,
+};
+
+struct nvmf_common_command {
+	__u8	opcode;
+	__u8	resv1;
+	__u16	command_id;
+	__u8	fctype;
+	__u8	resv2[35];
+	__u8	ts[24];
+};
+
+/*
+ * The legal cntlid range a NVMe Target will provide.
+ * Note that cntlid of value 0 is considered illegal in the fabrics world.
+ * Devices based on earlier specs did not have the subsystem concept;
+ * therefore, those devices had their cntlid value set to 0 as a result.
+ */
+#define NVME_CNTLID_MIN		1
+#define NVME_CNTLID_MAX		0xffef
+#define NVME_CNTLID_DYNAMIC	0xffff
+
+#define MAX_DISC_LOGS	255
+
+/* Discovery log page entry */
+struct nvmf_disc_rsp_page_entry {
+	__u8		trtype;
+	__u8		adrfam;
+	__u8		nqntype;
+	__u8		treq;
+	__le16		portid;
+	__le16		cntlid;
+	__le16		asqsz;
+	__u8		resv8[22];
+	char		trsvcid[NVMF_TRSVCID_SIZE];
+	__u8		resv64[192];
+	char		subnqn[NVMF_NQN_FIELD_LEN];
+	char		traddr[NVMF_TRADDR_SIZE];
+	union tsas {
+		char		common[NVMF_TSAS_SIZE];
+		struct rdma {
+			__u8	qptype;
+			__u8	prtype;
+			__u8	cms;
+			__u8	resv3[5];
+			__u16	pkey;
+			__u8	resv10[246];
+		} rdma;
+	} tsas;
+};
+
+/* Discovery log page header */
+struct nvmf_disc_rsp_page_hdr {
+	__le64		genctr;
+	__le64		numrec;
+	__le16		recfmt;
+	__u8		resv14[1006];
+	struct nvmf_disc_rsp_page_entry entries[0];
+};
+
+struct nvmf_connect_command {
+	__u8		opcode;
+	__u8		resv1;
+	__u16		command_id;
+	__u8		fctype;
+	__u8		resv2[19];
+	union nvme_data_ptr dptr;
+	__le16		recfmt;
+	__le16		qid;
+	__le16		sqsize;
+	__u8		cattr;
+	__u8		resv3;
+	__le32		kato;
+	__u8		resv4[12];
+};
+
+struct nvmf_connect_data {
+	uuid_le		hostid;
+	__le16		cntlid;
+	char		resv4[238];
+	char		subsysnqn[NVMF_NQN_FIELD_LEN];
+	char		hostnqn[NVMF_NQN_FIELD_LEN];
+	char		resv5[256];
+};
+
+struct nvmf_property_set_command {
+	__u8		opcode;
+	__u8		resv1;
+	__u16		command_id;
+	__u8		fctype;
+	__u8		resv2[35];
+	__u8		attrib;
+	__u8		resv3[3];
+	__le32		offset;
+	__le64		value;
+	__u8		resv4[8];
+};
+
+struct nvmf_property_get_command {
+	__u8		opcode;
+	__u8		resv1;
+	__u16		command_id;
+	__u8		fctype;
+	__u8		resv2[35];
+	__u8		attrib;
+	__u8		resv3[3];
+	__le32		offset;
+	__u8		resv4[16];
+};
+
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+struct nvme_doorbell_memory {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__u32			rsvd1[5];
+	__le64			prp1;
+	__le64			prp2;
+	__u32			rsvd12[6];
+};
+#endif
+
 struct nvme_command {
 	union {
 		struct nvme_common_command common;
@@ -530,10 +844,33 @@
 		struct nvme_format_cmd format;
 		struct nvme_dsm_cmd dsm;
 		struct nvme_abort_cmd abort;
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+		struct nvme_doorbell_memory doorbell_memory;
+#endif
+		struct nvme_get_log_page_command get_log_page;
+		struct nvmf_common_command fabrics;
+		struct nvmf_connect_command connect;
+		struct nvmf_property_set_command prop_set;
+		struct nvmf_property_get_command prop_get;
 	};
 };
 
-enum {
+static inline bool nvme_is_write(struct nvme_command *cmd)
+{
+	/*
+	 * What a mess...
+	 *
+	 * Why can't we simply have a Fabrics In and Fabrics out command?
+	 */
+	if (unlikely(cmd->common.opcode == nvme_fabrics_command))
+		return cmd->fabrics.opcode & 1;
+	return cmd->common.opcode & 1;
+}
+
+enum {
+	/*
+	 * Generic Command Status:
+	 */
 	NVME_SC_SUCCESS			= 0x0,
 	NVME_SC_INVALID_OPCODE		= 0x1,
 	NVME_SC_INVALID_FIELD		= 0x2,
@@ -552,10 +889,18 @@
 	NVME_SC_SGL_INVALID_DATA	= 0xf,
 	NVME_SC_SGL_INVALID_METADATA	= 0x10,
 	NVME_SC_SGL_INVALID_TYPE	= 0x11,
+
+	NVME_SC_SGL_INVALID_OFFSET	= 0x16,
+	NVME_SC_SGL_INVALID_SUBTYPE	= 0x17,
+
 	NVME_SC_LBA_RANGE		= 0x80,
 	NVME_SC_CAP_EXCEEDED		= 0x81,
 	NVME_SC_NS_NOT_READY		= 0x82,
 	NVME_SC_RESERVATION_CONFLICT	= 0x83,
+
+	/*
+	 * Command Specific Status:
+	 */
 	NVME_SC_CQ_INVALID		= 0x100,
 	NVME_SC_QID_INVALID		= 0x101,
 	NVME_SC_QUEUE_SIZE		= 0x102,
@@ -573,9 +918,32 @@
 	NVME_SC_FEATURE_NOT_CHANGEABLE	= 0x10e,
 	NVME_SC_FEATURE_NOT_PER_NS	= 0x10f,
 	NVME_SC_FW_NEEDS_RESET_SUBSYS	= 0x110,
+
+	/*
+	 * I/O Command Set Specific - NVM commands:
+	 */
 	NVME_SC_BAD_ATTRIBUTES		= 0x180,
 	NVME_SC_INVALID_PI		= 0x181,
 	NVME_SC_READ_ONLY		= 0x182,
+#ifdef CONFIG_NVME_VENDOR_EXT_GOOGLE
+	NVME_SC_DOORBELL_MEMORY_INVALID	= 0x1C0,
+#endif
+
+	/*
+	 * I/O Command Set Specific - Fabrics commands:
+	 */
+	NVME_SC_CONNECT_FORMAT		= 0x180,
+	NVME_SC_CONNECT_CTRL_BUSY	= 0x181,
+	NVME_SC_CONNECT_INVALID_PARAM	= 0x182,
+	NVME_SC_CONNECT_RESTART_DISC	= 0x183,
+	NVME_SC_CONNECT_INVALID_HOST	= 0x184,
+
+	NVME_SC_DISCOVERY_RESTART	= 0x190,
+	NVME_SC_AUTH_REQUIRED		= 0x191,
+
+	/*
+	 * Media and Data Integrity Errors:
+	 */
 	NVME_SC_WRITE_FAULT		= 0x280,
 	NVME_SC_READ_ERROR		= 0x281,
 	NVME_SC_GUARD_CHECK		= 0x282,
@@ -583,12 +951,19 @@
 	NVME_SC_REFTAG_CHECK		= 0x284,
 	NVME_SC_COMPARE_FAILED		= 0x285,
 	NVME_SC_ACCESS_DENIED		= 0x286,
+
 	NVME_SC_DNR			= 0x4000,
 };
 
 struct nvme_completion {
-	__le32	result;		/* Used by admin commands to return data */
-	__u32	rsvd;
+	/*
+	 * Used by Admin and Fabrics commands to return data:
+	 */
+	union {
+		__le16	result16;
+		__le32	result;
+		__le64	result64;
+	};
 	__le16	sq_head;	/* how much of this queue may be reclaimed */
 	__le16	sq_id;		/* submission queue that generated this entry */
 	__u16	command_id;	/* of the command which completed */
--- linux-4.4.0.orig/include/linux/nvmem-consumer.h
+++ linux-4.4.0/include/linux/nvmem-consumer.h
@@ -74,7 +74,7 @@
 {
 }
 
-static inline char *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
+static inline void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
 {
 	return ERR_PTR(-ENOSYS);
 }
--- linux-4.4.0.orig/include/linux/of.h
+++ linux-4.4.0/include/linux/of.h
@@ -199,8 +199,8 @@
 static inline u64 of_read_number(const __be32 *cell, int size)
 {
 	u64 r = 0;
-	while (size--)
-		r = (r << 32) | be32_to_cpu(*(cell++));
+	for (; size--; cell++)
+		r = (r << 32) | be32_to_cpu(*cell);
 	return r;
 }
 
@@ -265,6 +265,8 @@
 extern struct device_node *of_get_next_available_child(
 	const struct device_node *node, struct device_node *prev);
 
+extern struct device_node *of_get_compatible_child(const struct device_node *parent,
+					const char *compatible);
 extern struct device_node *of_get_child_by_name(const struct device_node *node,
 					const char *name);
 
@@ -462,6 +464,12 @@
 	return false;
 }
 
+static inline struct device_node *of_get_compatible_child(const struct device_node *parent,
+					const char *compatible)
+{
+	return NULL;
+}
+
 static inline struct device_node *of_get_child_by_name(
 					const struct device_node *node,
 					const char *name)
@@ -685,6 +693,15 @@
 }
 #endif
 
+#ifdef CONFIG_OF_NUMA
+extern int of_numa_init(void);
+#else
+static inline int of_numa_init(void)
+{
+	return -ENOSYS;
+}
+#endif
+
 static inline struct device_node *of_find_matching_node(
 	struct device_node *from,
 	const struct of_device_id *matches)
@@ -933,6 +950,7 @@
 #define _OF_DECLARE(table, name, compat, fn, fn_type)			\
 	static const struct of_device_id __of_table_##name		\
 		__used __section(__##table##_of_table)			\
+		__aligned(__alignof__(struct of_device_id))		\
 		 = { .compatible = compat,				\
 		     .data = (fn == (fn_type)NULL) ? fn : fn  }
 #else
--- linux-4.4.0.orig/include/linux/of_address.h
+++ linux-4.4.0/include/linux/of_address.h
@@ -44,10 +44,6 @@
 extern const __be32 *of_get_address(struct device_node *dev, int index,
 			   u64 *size, unsigned int *flags);
 
-extern int pci_register_io_range(phys_addr_t addr, resource_size_t size);
-extern unsigned long pci_address_to_pio(phys_addr_t addr);
-extern phys_addr_t pci_pio_to_address(unsigned long pio);
-
 extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
 			struct device_node *node);
 extern struct of_pci_range *of_pci_range_parser_one(
@@ -78,11 +74,6 @@
 	return NULL;
 }
 
-static inline phys_addr_t pci_pio_to_address(unsigned long pio)
-{
-	return 0;
-}
-
 static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
 			struct device_node *node)
 {
--- linux-4.4.0.orig/include/linux/of_fdt.h
+++ linux-4.4.0/include/linux/of_fdt.h
@@ -14,6 +14,7 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/errno.h>
 
 /* Definitions used by the flattened device tree */
 #define OF_DT_HEADER		0xd00dfeed	/* marker */
@@ -63,6 +64,7 @@
 				     int depth, void *data);
 extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
 				     int depth, void *data);
+extern int early_init_dt_scan_chosen_stdout(void);
 extern void early_init_fdt_scan_reserved_mem(void);
 extern void early_init_fdt_reserve_self(void);
 extern void early_init_dt_add_memory_arch(u64 base, u64 size);
@@ -91,6 +93,7 @@
 extern u64 fdt_translate_address(const void *blob, int node_offset);
 extern void of_fdt_limit_memory(int limit);
 #else /* CONFIG_OF_FLATTREE */
+static inline int early_init_dt_scan_chosen_stdout(void) { return -ENODEV; }
 static inline void early_init_fdt_scan_reserved_mem(void) {}
 static inline void early_init_fdt_reserve_self(void) {}
 static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
--- linux-4.4.0.orig/include/linux/omap-gpmc.h
+++ linux-4.4.0/include/linux/omap-gpmc.h
@@ -191,10 +191,11 @@
 #endif
 
 #if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
-extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
+extern int gpmc_onenand_init(struct omap_onenand_platform_data *d);
 #else
 #define board_onenand_data	NULL
-static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
+static inline int gpmc_onenand_init(struct omap_onenand_platform_data *d)
 {
+	return 0;
 }
 #endif
--- linux-4.4.0.orig/include/linux/overflow.h
+++ linux-4.4.0/include/linux/overflow.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+#ifndef __LINUX_OVERFLOW_H
+#define __LINUX_OVERFLOW_H
+
+#include <linux/compiler.h>
+
+/*
+ * In the fallback code below, we need to compute the minimum and
+ * maximum values representable in a given type. These macros may also
+ * be useful elsewhere, so we provide them outside the
+ * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block.
+ *
+ * It would seem more obvious to do something like
+ *
+ * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0)
+ * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0)
+ *
+ * Unfortunately, the middle expressions, strictly speaking, have
+ * undefined behaviour, and at least some versions of gcc warn about
+ * the type_max expression (but not if -fsanitize=undefined is in
+ * effect; in that case, the warning is deferred to runtime...).
+ *
+ * The slightly excessive casting in type_min is to make sure the
+ * macros also produce sensible values for the exotic type _Bool. [The
+ * overflow checkers only almost work for _Bool, but that's
+ * a-feature-not-a-bug, since people shouldn't be doing arithmetic on
+ * _Bools. Besides, the gcc builtins don't allow _Bool* as third
+ * argument.]
+ *
+ * Idea stolen from
+ * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
+ * credit to Christian Biere.
+ */
+#define is_signed_type(type)       (((type)(-1)) < (type)1)
+#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
+#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
+#define type_min(T) ((T)((T)-type_max(T)-(T)1))
+
+
+#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
+/*
+ * For simplicity and code hygiene, the fallback code below insists on
+ * a, b and *d having the same type (similar to the min() and max()
+ * macros), whereas gcc's type-generic overflow checkers accept
+ * different types. Hence we don't just make check_add_overflow an
+ * alias for __builtin_add_overflow, but add type checks similar to
+ * below.
+ */
+#define check_add_overflow(a, b, d) ({		\
+	typeof(a) __a = (a);			\
+	typeof(b) __b = (b);			\
+	typeof(d) __d = (d);			\
+	(void) (&__a == &__b);			\
+	(void) (&__a == __d);			\
+	__builtin_add_overflow(__a, __b, __d);	\
+})
+
+#define check_sub_overflow(a, b, d) ({		\
+	typeof(a) __a = (a);			\
+	typeof(b) __b = (b);			\
+	typeof(d) __d = (d);			\
+	(void) (&__a == &__b);			\
+	(void) (&__a == __d);			\
+	__builtin_sub_overflow(__a, __b, __d);	\
+})
+
+#define check_mul_overflow(a, b, d) ({		\
+	typeof(a) __a = (a);			\
+	typeof(b) __b = (b);			\
+	typeof(d) __d = (d);			\
+	(void) (&__a == &__b);			\
+	(void) (&__a == __d);			\
+	__builtin_mul_overflow(__a, __b, __d);	\
+})
+
+#else
+
+
+/* Checking for unsigned overflow is relatively easy without causing UB. */
+#define __unsigned_add_overflow(a, b, d) ({	\
+	typeof(a) __a = (a);			\
+	typeof(b) __b = (b);			\
+	typeof(d) __d = (d);			\
+	(void) (&__a == &__b);			\
+	(void) (&__a == __d);			\
+	*__d = __a + __b;			\
+	*__d < __a;				\
+})
+#define __unsigned_sub_overflow(a, b, d) ({	\
+	typeof(a) __a = (a);			\
+	typeof(b) __b = (b);			\
+	typeof(d) __d = (d);			\
+	(void) (&__a == &__b);			\
+	(void) (&__a == __d);			\
+	*__d = __a - __b;			\
+	__a < __b;				\
+})
+/*
+ * If one of a or b is a compile-time constant, this avoids a division.
+ */
+#define __unsigned_mul_overflow(a, b, d) ({		\
+	typeof(a) __a = (a);				\
+	typeof(b) __b = (b);				\
+	typeof(d) __d = (d);				\
+	(void) (&__a == &__b);				\
+	(void) (&__a == __d);				\
+	*__d = __a * __b;				\
+	__builtin_constant_p(__b) ?			\
+	  __b > 0 && __a > type_max(typeof(__a)) / __b : \
+	  __a > 0 && __b > type_max(typeof(__b)) / __a;	 \
+})
+
+/*
+ * For signed types, detecting overflow is much harder, especially if
+ * we want to avoid UB. But the interface of these macros is such that
+ * we must provide a result in *d, and in fact we must produce the
+ * result promised by gcc's builtins, which is simply the possibly
+ * wrapped-around value. Fortunately, we can just formally do the
+ * operations in the widest relevant unsigned type (u64) and then
+ * truncate the result - gcc is smart enough to generate the same code
+ * with and without the (u64) casts.
+ */
+
+/*
+ * Adding two signed integers can overflow only if they have the same
+ * sign, and overflow has happened iff the result has the opposite
+ * sign.
+ */
+#define __signed_add_overflow(a, b, d) ({	\
+	typeof(a) __a = (a);			\
+	typeof(b) __b = (b);			\
+	typeof(d) __d = (d);			\
+	(void) (&__a == &__b);			\
+	(void) (&__a == __d);			\
+	*__d = (u64)__a + (u64)__b;		\
+	(((~(__a ^ __b)) & (*__d ^ __a))	\
+		& type_min(typeof(__a))) != 0;	\
+})
+
+/*
+ * Subtraction is similar, except that overflow can now happen only
+ * when the signs are opposite. In this case, overflow has happened if
+ * the result has the opposite sign of a.
+ */
+#define __signed_sub_overflow(a, b, d) ({	\
+	typeof(a) __a = (a);			\
+	typeof(b) __b = (b);			\
+	typeof(d) __d = (d);			\
+	(void) (&__a == &__b);			\
+	(void) (&__a == __d);			\
+	*__d = (u64)__a - (u64)__b;		\
+	((((__a ^ __b)) & (*__d ^ __a))		\
+		& type_min(typeof(__a))) != 0;	\
+})
+
+/*
+ * Signed multiplication is rather hard. gcc always follows C99, so
+ * division is truncated towards 0. This means that we can write the
+ * overflow check like this:
+ *
+ * (a > 0 && (b > MAX/a || b < MIN/a)) ||
+ * (a < -1 && (b > MIN/a || b < MAX/a) ||
+ * (a == -1 && b == MIN)
+ *
+ * The redundant casts of -1 are to silence an annoying -Wtype-limits
+ * (included in -Wextra) warning: When the type is u8 or u16, the
+ * __b_c_e in check_mul_overflow obviously selects
+ * __unsigned_mul_overflow, but unfortunately gcc still parses this
+ * code and warns about the limited range of __b.
+ */
+
+#define __signed_mul_overflow(a, b, d) ({				\
+	typeof(a) __a = (a);						\
+	typeof(b) __b = (b);						\
+	typeof(d) __d = (d);						\
+	typeof(a) __tmax = type_max(typeof(a));				\
+	typeof(a) __tmin = type_min(typeof(a));				\
+	(void) (&__a == &__b);						\
+	(void) (&__a == __d);						\
+	*__d = (u64)__a * (u64)__b;					\
+	(__b > 0   && (__a > __tmax/__b || __a < __tmin/__b)) ||	\
+	(__b < (typeof(__b))-1  && (__a > __tmin/__b || __a < __tmax/__b)) || \
+	(__b == (typeof(__b))-1 && __a == __tmin);			\
+})
+
+
+#define check_add_overflow(a, b, d)					\
+	__builtin_choose_expr(is_signed_type(typeof(a)),		\
+			__signed_add_overflow(a, b, d),			\
+			__unsigned_add_overflow(a, b, d))
+
+#define check_sub_overflow(a, b, d)					\
+	__builtin_choose_expr(is_signed_type(typeof(a)),		\
+			__signed_sub_overflow(a, b, d),			\
+			__unsigned_sub_overflow(a, b, d))
+
+#define check_mul_overflow(a, b, d)					\
+	__builtin_choose_expr(is_signed_type(typeof(a)),		\
+			__signed_mul_overflow(a, b, d),			\
+			__unsigned_mul_overflow(a, b, d))
+
+
+#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */
+
+#endif /* __LINUX_OVERFLOW_H */
--- linux-4.4.0.orig/include/linux/padata.h
+++ linux-4.4.0/include/linux/padata.h
@@ -24,7 +24,6 @@
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
-#include <linux/timer.h>
 #include <linux/notifier.h>
 #include <linux/kobject.h>
 
@@ -37,6 +36,7 @@
  * @list: List entry, to attach to the padata lists.
  * @pd: Pointer to the internal control structure.
  * @cb_cpu: Callback cpu for serializatioon.
+ * @cpu: Cpu for parallelization.
  * @seq_nr: Sequence number of the parallelized data object.
  * @info: Used to pass information from the parallel to the serial function.
  * @parallel: Parallel execution function.
@@ -46,6 +46,7 @@
 	struct list_head	list;
 	struct parallel_data	*pd;
 	int			cb_cpu;
+	int			cpu;
 	int			info;
 	void                    (*parallel)(struct padata_priv *padata);
 	void                    (*serial)(struct padata_priv *padata);
@@ -83,7 +84,6 @@
  * @serial: List to wait for serialization after reordering.
  * @pwork: work struct for parallelization.
  * @swork: work struct for serialization.
- * @pd: Backpointer to the internal control structure.
  * @work: work struct for parallelization.
  * @num_obj: Number of objects that are processed by this cpu.
  * @cpu_index: Index of the cpu.
@@ -91,7 +91,6 @@
 struct padata_parallel_queue {
        struct padata_list    parallel;
        struct padata_list    reorder;
-       struct parallel_data *pd;
        struct work_struct    work;
        atomic_t              num_obj;
        int                   cpu_index;
@@ -118,10 +117,10 @@
  * @reorder_objects: Number of objects waiting in the reorder queues.
  * @refcnt: Number of objects holding a reference on this parallel_data.
  * @max_seq_nr:  Maximal used sequence number.
+ * @cpu: Next CPU to be processed.
  * @cpumask: The cpumasks in use for parallel and serial workers.
+ * @reorder_work: work struct for reordering.
  * @lock: Reorder lock.
- * @processed: Number of already processed objects.
- * @timer: Reorder timer.
  */
 struct parallel_data {
 	struct padata_instance		*pinst;
@@ -130,10 +129,10 @@
 	atomic_t			reorder_objects;
 	atomic_t			refcnt;
 	atomic_t			seq_nr;
+	int				cpu;
 	struct padata_cpumask		cpumask;
+	struct work_struct		reorder_work;
 	spinlock_t                      lock ____cacheline_aligned;
-	unsigned int			processed;
-	struct timer_list		timer;
 };
 
 /**
--- linux-4.4.0.orig/include/linux/page-flags-layout.h
+++ linux-4.4.0/include/linux/page-flags-layout.h
@@ -17,6 +17,8 @@
 #define ZONES_SHIFT 1
 #elif MAX_NR_ZONES <= 4
 #define ZONES_SHIFT 2
+#elif MAX_NR_ZONES <= 8
+#define ZONES_SHIFT 3
 #else
 #error ZONES_SHIFT -- too many zones configured adjust calculation
 #endif
--- linux-4.4.0.orig/include/linux/page_idle.h
+++ linux-4.4.0/include/linux/page_idle.h
@@ -46,33 +46,62 @@
 
 static inline bool page_is_young(struct page *page)
 {
-	return test_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags);
+	struct page_ext *page_ext = lookup_page_ext(page);
+
+	if (unlikely(!page_ext))
+		return false;
+
+	return test_bit(PAGE_EXT_YOUNG, &page_ext->flags);
 }
 
 static inline void set_page_young(struct page *page)
 {
-	set_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags);
+	struct page_ext *page_ext = lookup_page_ext(page);
+
+	if (unlikely(!page_ext))
+		return;
+
+	set_bit(PAGE_EXT_YOUNG, &page_ext->flags);
 }
 
 static inline bool test_and_clear_page_young(struct page *page)
 {
-	return test_and_clear_bit(PAGE_EXT_YOUNG,
-				  &lookup_page_ext(page)->flags);
+	struct page_ext *page_ext = lookup_page_ext(page);
+
+	if (unlikely(!page_ext))
+		return false;
+
+	return test_and_clear_bit(PAGE_EXT_YOUNG, &page_ext->flags);
 }
 
 static inline bool page_is_idle(struct page *page)
 {
-	return test_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
+	struct page_ext *page_ext = lookup_page_ext(page);
+
+	if (unlikely(!page_ext))
+		return false;
+
+	return test_bit(PAGE_EXT_IDLE, &page_ext->flags);
 }
 
 static inline void set_page_idle(struct page *page)
 {
-	set_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
+	struct page_ext *page_ext = lookup_page_ext(page);
+
+	if (unlikely(!page_ext))
+		return;
+
+	set_bit(PAGE_EXT_IDLE, &page_ext->flags);
 }
 
 static inline void clear_page_idle(struct page *page)
 {
-	clear_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
+	struct page_ext *page_ext = lookup_page_ext(page);
+
+	if (unlikely(!page_ext))
+		return;
+
+	clear_bit(PAGE_EXT_IDLE, &page_ext->flags);
 }
 #endif /* CONFIG_64BIT */
 
--- linux-4.4.0.orig/include/linux/pagemap.h
+++ linux-4.4.0/include/linux/pagemap.h
@@ -153,7 +153,7 @@
 
 #ifdef CONFIG_TINY_RCU
 # ifdef CONFIG_PREEMPT_COUNT
-	VM_BUG_ON(!in_atomic());
+	VM_BUG_ON(!in_atomic() && !irqs_disabled());
 # endif
 	/*
 	 * Preempt must be disabled here - we rely on rcu_read_lock doing
@@ -191,7 +191,7 @@
 
 #if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU)
 # ifdef CONFIG_PREEMPT_COUNT
-	VM_BUG_ON(!in_atomic());
+	VM_BUG_ON(!in_atomic() && !irqs_disabled());
 # endif
 	VM_BUG_ON_PAGE(page_count(page) == 0, page);
 	atomic_add(count, &page->_count);
@@ -601,56 +601,56 @@
  */
 static inline int fault_in_multipages_writeable(char __user *uaddr, int size)
 {
-	int ret = 0;
 	char __user *end = uaddr + size - 1;
 
 	if (unlikely(size == 0))
-		return ret;
+		return 0;
 
+	if (unlikely(uaddr > end))
+		return -EFAULT;
 	/*
 	 * Writing zeroes into userspace here is OK, because we know that if
 	 * the zero gets there, we'll be overwriting it.
 	 */
-	while (uaddr <= end) {
-		ret = __put_user(0, uaddr);
-		if (ret != 0)
-			return ret;
+	do {
+		if (unlikely(__put_user(0, uaddr) != 0))
+			return -EFAULT;
 		uaddr += PAGE_SIZE;
-	}
+	} while (uaddr <= end);
 
 	/* Check whether the range spilled into the next page. */
 	if (((unsigned long)uaddr & PAGE_MASK) ==
 			((unsigned long)end & PAGE_MASK))
-		ret = __put_user(0, end);
+		return __put_user(0, end);
 
-	return ret;
+	return 0;
 }
 
 static inline int fault_in_multipages_readable(const char __user *uaddr,
 					       int size)
 {
 	volatile char c;
-	int ret = 0;
 	const char __user *end = uaddr + size - 1;
 
 	if (unlikely(size == 0))
-		return ret;
+		return 0;
 
-	while (uaddr <= end) {
-		ret = __get_user(c, uaddr);
-		if (ret != 0)
-			return ret;
+	if (unlikely(uaddr > end))
+		return -EFAULT;
+
+	do {
+		if (unlikely(__get_user(c, uaddr) != 0))
+			return -EFAULT;
 		uaddr += PAGE_SIZE;
-	}
+	} while (uaddr <= end);
 
 	/* Check whether the range spilled into the next page. */
 	if (((unsigned long)uaddr & PAGE_MASK) ==
 			((unsigned long)end & PAGE_MASK)) {
-		ret = __get_user(c, end);
-		(void)c;
+		return __get_user(c, end);
 	}
 
-	return ret;
+	return 0;
 }
 
 int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
--- linux-4.4.0.orig/include/linux/pci-acpi.h
+++ linux-4.4.0/include/linux/pci-acpi.h
@@ -24,6 +24,8 @@
 }
 extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
 
+extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res);
+
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 {
 	struct pci_bus *pbus = pdev->bus;
--- linux-4.4.0.orig/include/linux/pci-ecam.h
+++ linux-4.4.0/include/linux/pci-ecam.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+#ifndef DRIVERS_PCI_ECAM_H
+#define DRIVERS_PCI_ECAM_H
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+/*
+ * struct to hold pci ops and bus shift of the config window
+ * for a PCI controller.
+ */
+struct pci_config_window;
+struct pci_ecam_ops {
+	unsigned int			bus_shift;
+	struct pci_ops			pci_ops;
+	int				(*init)(struct pci_config_window *);
+};
+
+/*
+ * struct to hold the mappings of a config space window. This
+ * is expected to be used as sysdata for PCI controllers that
+ * use ECAM.
+ */
+struct pci_config_window {
+	struct resource			res;
+	struct resource			busr;
+	void				*priv;
+	struct pci_ecam_ops		*ops;
+	union {
+		void __iomem		*win;	/* 64-bit single mapping */
+		void __iomem		**winp; /* 32-bit per-bus mapping */
+	};
+	struct device			*parent;/* ECAM res was from this dev */
+};
+
+/* create and free pci_config_window */
+struct pci_config_window *pci_ecam_create(struct device *dev,
+		struct resource *cfgres, struct resource *busr,
+		struct pci_ecam_ops *ops);
+void pci_ecam_free(struct pci_config_window *cfg);
+
+/* map_bus when ->sysdata is an instance of pci_config_window */
+void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
+			       int where);
+/* default ECAM ops */
+extern struct pci_ecam_ops pci_generic_ecam_ops;
+
+#ifdef CONFIG_PCI_HOST_GENERIC
+/* for DT-based PCI controllers that support ECAM */
+int pci_host_common_probe(struct platform_device *pdev,
+			  struct pci_ecam_ops *ops);
+#endif
+#endif
--- linux-4.4.0.orig/include/linux/pci.h
+++ linux-4.4.0/include/linux/pci.h
@@ -359,6 +359,7 @@
 	unsigned int	io_window_1k:1;	/* Intel P2P bridge 1K I/O windows */
 	unsigned int	irq_managed:1;
 	unsigned int	has_secondary_link:1;
+	unsigned int	non_compliant_bars:1;	/* broken BARs; ignore them */
 	pci_dev_flags_t dev_flags;
 	atomic_t	enable_cnt;	/* pci_enable_device has been called */
 
@@ -988,23 +989,6 @@
 	return pdev->is_managed;
 }
 
-static inline void pci_set_managed_irq(struct pci_dev *pdev, unsigned int irq)
-{
-	pdev->irq = irq;
-	pdev->irq_managed = 1;
-}
-
-static inline void pci_reset_managed_irq(struct pci_dev *pdev)
-{
-	pdev->irq = 0;
-	pdev->irq_managed = 0;
-}
-
-static inline bool pci_has_managed_irq(struct pci_dev *pdev)
-{
-	return pdev->irq_managed && pdev->irq > 0;
-}
-
 void pci_disable_device(struct pci_dev *dev);
 
 extern unsigned int pcibios_max_latency;
@@ -1168,7 +1152,11 @@
 			void *alignf_data);
 
 
+int pci_register_io_range(phys_addr_t addr, resource_size_t size);
+unsigned long pci_address_to_pio(phys_addr_t addr);
+phys_addr_t pci_pio_to_address(unsigned long pio);
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
+void pci_unmap_iospace(struct resource *res);
 
 static inline pci_bus_addr_t pci_bus_address(struct pci_dev *pdev, int bar)
 {
@@ -1392,12 +1380,13 @@
 {
 	return bus->domain_nr;
 }
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
+#ifdef CONFIG_ACPI
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus);
 #else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
-					struct device *parent)
-{
-}
+static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+{ return 0; }
+#endif
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent);
 #endif
 
 /* some architectures require additional setup to direct VGA traffic */
@@ -1490,6 +1479,8 @@
 { return -EIO; }
 static inline void pci_release_regions(struct pci_dev *dev) { }
 
+static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
+
 static inline void pci_block_cfg_access(struct pci_dev *dev) { }
 static inline int pci_block_cfg_access_in_atomic(struct pci_dev *dev)
 { return 0; }
@@ -1517,6 +1508,10 @@
 
 #include <asm/pci.h>
 
+#ifndef pci_root_bus_fwnode
+#define pci_root_bus_fwnode(bus)	NULL
+#endif
+
 /* these helpers provide future and backwards compatibility
  * for accessing popular PCI BAR info */
 #define pci_resource_start(dev, bar)	((dev)->resource[(bar)].start)
@@ -1721,7 +1716,7 @@
 extern struct dev_pm_ops pcibios_pm_ops;
 #endif
 
-#ifdef CONFIG_PCI_MMCONFIG
+#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG)
 void __init pci_mmcfg_early_init(void);
 void __init pci_mmcfg_late_init(void);
 #else
@@ -1818,6 +1813,20 @@
 	return (pcie_caps_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
 }
 
+static inline struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
+{
+	while (1) {
+		if (!pci_is_pcie(dev))
+			break;
+		if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
+			return dev;
+		if (!dev->bus->self)
+			break;
+		dev = dev->bus->self;
+	}
+	return NULL;
+}
+
 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,
@@ -1946,6 +1955,16 @@
 pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; }
 #endif  /* CONFIG_OF */
 
+#ifdef CONFIG_ACPI
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
+
+void
+pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *));
+#else
+static inline struct irq_domain *
+pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
+#endif
+
 #ifdef CONFIG_EEH
 static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
 {
--- linux-4.4.0.orig/include/linux/pci_ids.h
+++ linux-4.4.0/include/linux/pci_ids.h
@@ -573,6 +573,7 @@
 #define PCI_DEVICE_ID_AMD_CS5536_EHC    0x2095
 #define PCI_DEVICE_ID_AMD_CS5536_UDC    0x2096
 #define PCI_DEVICE_ID_AMD_CS5536_UOC    0x2097
+#define PCI_DEVICE_ID_AMD_CS5536_DEV_IDE    0x2092
 #define PCI_DEVICE_ID_AMD_CS5536_IDE    0x209A
 #define PCI_DEVICE_ID_AMD_LX_VIDEO  0x2081
 #define PCI_DEVICE_ID_AMD_LX_AES    0x2082
@@ -2495,6 +2496,15 @@
 #define PCI_DEVICE_ID_KORENIX_JETCARDF2	0x1700
 #define PCI_DEVICE_ID_KORENIX_JETCARDF3	0x17ff
 
+#define PCI_VENDOR_ID_HUAWEI         	0x19e5
+
+#define PCI_VENDOR_ID_NETRONOME		0x19ee
+#define PCI_DEVICE_ID_NETRONOME_NFP3200	0x3200
+#define PCI_DEVICE_ID_NETRONOME_NFP3240	0x3240
+#define PCI_DEVICE_ID_NETRONOME_NFP4000	0x4000
+#define PCI_DEVICE_ID_NETRONOME_NFP6000	0x6000
+#define PCI_DEVICE_ID_NETRONOME_NFP6000_VF	0x6003
+
 #define PCI_VENDOR_ID_QMI		0x1a32
 
 #define PCI_VENDOR_ID_AZWAVE		0x1a3b
--- linux-4.4.0.orig/include/linux/percpu-defs.h
+++ linux-4.4.0/include/linux/percpu-defs.h
@@ -35,6 +35,12 @@
 
 #endif
 
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#define USER_MAPPED_SECTION "..user_mapped"
+#else
+#define USER_MAPPED_SECTION ""
+#endif
+
 /*
  * Base implementations of per-CPU variable declarations and definitions, where
  * the section in which the variable is to be placed is provided by the
@@ -115,6 +121,12 @@
 #define DEFINE_PER_CPU(type, name)					\
 	DEFINE_PER_CPU_SECTION(type, name, "")
 
+#define DECLARE_PER_CPU_USER_MAPPED(type, name)				\
+	DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION)
+
+#define DEFINE_PER_CPU_USER_MAPPED(type, name)				\
+	DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION)
+
 /*
  * Declaration/definition used for per-CPU variables that must come first in
  * the set of variables.
@@ -144,6 +156,14 @@
 	DEFINE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \
 	____cacheline_aligned_in_smp
 
+#define DECLARE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(type, name)		\
+	DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION PER_CPU_SHARED_ALIGNED_SECTION) \
+	____cacheline_aligned_in_smp
+
+#define DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(type, name)		\
+	DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION PER_CPU_SHARED_ALIGNED_SECTION) \
+	____cacheline_aligned_in_smp
+
 #define DECLARE_PER_CPU_ALIGNED(type, name)				\
 	DECLARE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION)	\
 	____cacheline_aligned
@@ -162,11 +182,21 @@
 #define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)				\
 	DEFINE_PER_CPU_SECTION(type, name, "..page_aligned")		\
 	__aligned(PAGE_SIZE)
+/*
+ * Declaration/definition used for per-CPU variables that must be page aligned and need to be mapped in user mode.
+ */
+#define DECLARE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(type, name)		\
+	DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION"..page_aligned") \
+	__aligned(PAGE_SIZE)
+
+#define DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(type, name)		\
+	DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION"..page_aligned") \
+	__aligned(PAGE_SIZE)
 
 /*
  * Declaration/definition used for per-CPU variables that must be read mostly.
  */
-#define DECLARE_PER_CPU_READ_MOSTLY(type, name)			\
+#define DECLARE_PER_CPU_READ_MOSTLY(type, name)				\
 	DECLARE_PER_CPU_SECTION(type, name, "..read_mostly")
 
 #define DEFINE_PER_CPU_READ_MOSTLY(type, name)				\
--- linux-4.4.0.orig/include/linux/percpu-refcount.h
+++ linux-4.4.0/include/linux/percpu-refcount.h
@@ -206,7 +206,7 @@
 static inline bool percpu_ref_tryget(struct percpu_ref *ref)
 {
 	unsigned long __percpu *percpu_count;
-	int ret;
+	bool ret;
 
 	rcu_read_lock_sched();
 
@@ -240,7 +240,7 @@
 static inline bool percpu_ref_tryget_live(struct percpu_ref *ref)
 {
 	unsigned long __percpu *percpu_count;
-	int ret = false;
+	bool ret = false;
 
 	rcu_read_lock_sched();
 
--- linux-4.4.0.orig/include/linux/percpu_counter.h
+++ linux-4.4.0/include/linux/percpu_counter.h
@@ -76,9 +76,9 @@
  */
 static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
 {
-	s64 ret = fbc->count;
+	/* Prevent reloads of fbc->count */
+	s64 ret = READ_ONCE(fbc->count);
 
-	barrier();		/* Prevent reloads of fbc->count */
 	if (ret >= 0)
 		return ret;
 	return 0;
--- linux-4.4.0.orig/include/linux/perf/arm_pmu.h
+++ linux-4.4.0/include/linux/perf/arm_pmu.h
@@ -111,8 +111,6 @@
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
 
-int armpmu_register(struct arm_pmu *armpmu, int type);
-
 u64 armpmu_event_update(struct perf_event *event);
 
 int armpmu_event_set_period(struct perf_event *event);
--- linux-4.4.0.orig/include/linux/perf_event.h
+++ linux-4.4.0/include/linux/perf_event.h
@@ -121,6 +121,7 @@
 		struct { /* intel_cqm */
 			int			cqm_state;
 			u32			cqm_rmid;
+			int			is_group_event;
 			struct list_head	cqm_events_entry;
 			struct list_head	cqm_groups_entry;
 			struct list_head	cqm_group_entry;
@@ -465,6 +466,8 @@
 	struct list_head		active_entry;
 	int				nr_siblings;
 	int				group_flags;
+
+	unsigned int			group_generation;
 	struct perf_event		*group_leader;
 	struct pmu			*pmu;
 
--- linux-4.4.0.orig/include/linux/pfn.h
+++ linux-4.4.0/include/linux/pfn.h
@@ -9,5 +9,6 @@
 #define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 #define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
 #define PFN_PHYS(x)	((phys_addr_t)(x) << PAGE_SHIFT)
+#define PHYS_PFN(x)	((unsigned long)((x) >> PAGE_SHIFT))
 
 #endif
--- linux-4.4.0.orig/include/linux/phy.h
+++ linux-4.4.0/include/linux/phy.h
@@ -136,11 +136,7 @@
 /* Used when trying to connect to a specific phy (mii bus id:phy device id) */
 #define PHY_ID_FMT "%s:%02x"
 
-/*
- * Need to be a little smaller than phydev->dev.bus_id to leave room
- * for the ":%02x"
- */
-#define MII_BUS_ID_SIZE	(20 - 3)
+#define MII_BUS_ID_SIZE	61
 
 /* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
    IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */
@@ -599,7 +595,7 @@
 /* A Structure for boards to register fixups with the PHY Lib */
 struct phy_fixup {
 	struct list_head list;
-	char bus_id[20];
+	char bus_id[MII_BUS_ID_SIZE + 3];
 	u32 phy_uid;
 	u32 phy_uid_mask;
 	int (*run)(struct phy_device *phydev);
@@ -687,6 +683,17 @@
 }
 
 /**
+ * phy_interface_mode_is_rgmii - Convenience function for testing if a
+ * PHY interface mode is RGMII (all variants)
+ * @mode: the phy_interface_t enum
+ */
+static inline bool phy_interface_mode_is_rgmii(phy_interface_t mode)
+{
+	return mode >= PHY_INTERFACE_MODE_RGMII &&
+		mode <= PHY_INTERFACE_MODE_RGMII_TXID;
+};
+
+/**
  * phy_interface_is_rgmii - Convenience function for testing if a PHY interface
  * is RGMII (all variants)
  * @phydev: the phy_device struct
@@ -785,6 +792,10 @@
 int genphy_suspend(struct phy_device *phydev);
 int genphy_resume(struct phy_device *phydev);
 int genphy_soft_reset(struct phy_device *phydev);
+static inline int genphy_no_soft_reset(struct phy_device *phydev)
+{
+	return 0;
+}
 void phy_driver_unregister(struct phy_driver *drv);
 void phy_drivers_unregister(struct phy_driver *drv, int n);
 int phy_driver_register(struct phy_driver *new_driver);
--- linux-4.4.0.orig/include/linux/pid.h
+++ linux-4.4.0/include/linux/pid.h
@@ -8,7 +8,9 @@
 	PIDTYPE_PID,
 	PIDTYPE_PGID,
 	PIDTYPE_SID,
-	PIDTYPE_MAX
+	PIDTYPE_MAX,
+	/* only valid to __task_pid_nr_ns() */
+	__PIDTYPE_TGID
 };
 
 /*
--- linux-4.4.0.orig/include/linux/pinctrl/pinctrl.h
+++ linux-4.4.0/include/linux/pinctrl/pinctrl.h
@@ -144,6 +144,12 @@
 extern struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
 				struct device *dev, void *driver_data);
 extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
+extern struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
+				struct pinctrl_desc *pctldesc,
+				void *driver_data);
+extern void devm_pinctrl_unregister(struct device *dev,
+				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);
--- linux-4.4.0.orig/include/linux/pipe_fs_i.h
+++ linux-4.4.0/include/linux/pipe_fs_i.h
@@ -42,6 +42,7 @@
  *	@fasync_readers: reader side fasync
  *	@fasync_writers: writer side fasync
  *	@bufs: the circular array of pipe buffers
+ *	@user: the user who created this pipe
  **/
 struct pipe_inode_info {
 	struct mutex mutex;
@@ -57,6 +58,7 @@
 	struct fasync_struct *fasync_readers;
 	struct fasync_struct *fasync_writers;
 	struct pipe_buffer *bufs;
+	struct user_struct *user;
 };
 
 /*
@@ -110,9 +112,22 @@
 	/*
 	 * Get a reference to the pipe buffer.
 	 */
-	void (*get)(struct pipe_inode_info *, struct pipe_buffer *);
+	bool (*get)(struct pipe_inode_info *, struct pipe_buffer *);
 };
 
+/**
+ * pipe_buf_get - get a reference to a pipe_buffer
+ * @pipe:	the pipe that the buffer belongs to
+ * @buf:	the buffer to get a reference to
+ *
+ * Return: %true if the reference was successfully obtained.
+ */
+static inline __must_check bool pipe_buf_get(struct pipe_inode_info *pipe,
+				struct pipe_buffer *buf)
+{
+	return buf->ops->get(pipe, buf);
+}
+
 /* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
    memory allocation, whereas PIPE_BUF makes atomicity guarantees.  */
 #define PIPE_SIZE		PAGE_SIZE
@@ -123,6 +138,8 @@
 void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *);
 
 extern unsigned int pipe_max_size, pipe_min_size;
+extern unsigned long pipe_user_pages_hard;
+extern unsigned long pipe_user_pages_soft;
 int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *);
 
 
@@ -133,7 +150,7 @@
 void free_pipe_info(struct pipe_inode_info *);
 
 /* Generic pipe buffer ops functions */
-void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
+bool generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
 int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *);
 int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *);
 void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *);
--- linux-4.4.0.orig/include/linux/platform_data/asoc-s3c.h
+++ linux-4.4.0/include/linux/platform_data/asoc-s3c.h
@@ -39,6 +39,10 @@
  */
 struct s3c_audio_pdata {
 	int (*cfg_gpio)(struct platform_device *);
+	void *dma_playback;
+	void *dma_capture;
+	void *dma_play_sec;
+	void *dma_capture_mic;
 	union {
 		struct samsung_i2s i2s;
 	} type;
--- linux-4.4.0.orig/include/linux/platform_data/dma-ep93xx.h
+++ linux-4.4.0/include/linux/platform_data/dma-ep93xx.h
@@ -84,7 +84,7 @@
 ep93xx_dma_chan_direction(struct dma_chan *chan)
 {
 	if (!ep93xx_dma_chan_is_m2p(chan))
-		return DMA_NONE;
+		return DMA_TRANS_NONE;
 
 	/* even channels are for TX, odd for RX */
 	return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
--- linux-4.4.0.orig/include/linux/platform_data/dma-imx-sdma.h
+++ linux-4.4.0/include/linux/platform_data/dma-imx-sdma.h
@@ -50,7 +50,10 @@
 	/* End of v2 array */
 	s32 zcanfd_2_mcu_addr;
 	s32 zqspi_2_mcu_addr;
+	s32 mcu_2_ecspi_addr;
 	/* End of v3 array */
+	s32 mcu_2_zqspi_addr;
+	/* End of v4 array */
 };
 
 /**
--- linux-4.4.0.orig/include/linux/platform_data/ina2xx.h
+++ linux-4.4.0/include/linux/platform_data/ina2xx.h
@@ -1,7 +1,7 @@
 /*
  * Driver for Texas Instruments INA219, INA226 power monitor chips
  *
- * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ * Copyright (C) 2012 Lothar Felten <lothar.felten@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
--- linux-4.4.0.orig/include/linux/platform_data/isl9305.h
+++ linux-4.4.0/include/linux/platform_data/isl9305.h
@@ -24,7 +24,7 @@
 struct regulator_init_data;
 
 struct isl9305_pdata {
-	struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR];
+	struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR + 1];
 };
 
 #endif
--- linux-4.4.0.orig/include/linux/platform_data/mmp_dma.h
+++ linux-4.4.0/include/linux/platform_data/mmp_dma.h
@@ -14,6 +14,7 @@
 
 struct mmp_dma_platdata {
 	int dma_channels;
+	int nb_requestors;
 };
 
 #endif /* MMP_DMA_H */
--- linux-4.4.0.orig/include/linux/platform_data/pwm_omap_dmtimer.h
+++ linux-4.4.0/include/linux/platform_data/pwm_omap_dmtimer.h
@@ -0,0 +1,69 @@
+/*
+ * include/linux/platform_data/pwm_omap_dmtimer.h
+ *
+ * OMAP Dual-Mode Timer PWM platform data
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Platform device conversion and hwmod support.
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ * PWM and clock framework support by Timo Teras.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU 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
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PWM_OMAP_DMTIMER_PDATA_H
+#define __PWM_OMAP_DMTIMER_PDATA_H
+
+/* trigger types */
+#define PWM_OMAP_DMTIMER_TRIGGER_NONE			0x00
+#define PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW		0x01
+#define PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE	0x02
+
+struct omap_dm_timer;
+typedef struct omap_dm_timer pwm_omap_dmtimer;
+
+struct pwm_omap_dmtimer_pdata {
+	pwm_omap_dmtimer *(*request_by_node)(struct device_node *np);
+	int	(*free)(pwm_omap_dmtimer *timer);
+
+	void	(*enable)(pwm_omap_dmtimer *timer);
+	void	(*disable)(pwm_omap_dmtimer *timer);
+
+	struct clk *(*get_fclk)(pwm_omap_dmtimer *timer);
+
+	int	(*start)(pwm_omap_dmtimer *timer);
+	int	(*stop)(pwm_omap_dmtimer *timer);
+
+	int	(*set_load)(pwm_omap_dmtimer *timer, int autoreload,
+			unsigned int value);
+	int	(*set_match)(pwm_omap_dmtimer *timer, int enable,
+			unsigned int match);
+	int	(*set_pwm)(pwm_omap_dmtimer *timer, int def_on,
+			int toggle, int trigger);
+	int	(*set_prescaler)(pwm_omap_dmtimer *timer, int prescaler);
+
+	int	(*write_counter)(pwm_omap_dmtimer *timer, unsigned int value);
+};
+
+#endif /* __PWM_OMAP_DMTIMER_PDATA_H */
--- linux-4.4.0.orig/include/linux/platform_data/st_sensors_pdata.h
+++ linux-4.4.0/include/linux/platform_data/st_sensors_pdata.h
@@ -16,9 +16,11 @@
  * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
  *	Available only for accelerometer and pressure sensors.
  *	Accelerometer DRDY on LSM330 available only on pin 1 (see datasheet).
+ * @open_drain: set the interrupt line to be open drain if possible.
  */
 struct st_sensors_platform_data {
 	u8 drdy_int_pin;
+	bool open_drain;
 };
 
 #endif /* ST_SENSORS_PDATA_H */
--- linux-4.4.0.orig/include/linux/platform_device.h
+++ linux-4.4.0/include/linux/platform_device.h
@@ -18,6 +18,7 @@
 #define PLATFORM_DEVID_AUTO	(-2)
 
 struct mfd_cell;
+struct property_set;
 
 struct platform_device {
 	const char	*name;
@@ -70,6 +71,8 @@
 		const void *data;
 		size_t size_data;
 		u64 dma_mask;
+
+		const struct property_set *pset;
 };
 extern struct platform_device *platform_device_register_full(
 		const struct platform_device_info *pdevinfo);
@@ -167,6 +170,8 @@
 					 unsigned int num);
 extern int platform_device_add_data(struct platform_device *pdev,
 				    const void *data, size_t size);
+extern int platform_device_add_properties(struct platform_device *pdev,
+					  const struct property_set *pset);
 extern int platform_device_add(struct platform_device *pdev);
 extern void platform_device_del(struct platform_device *pdev);
 extern void platform_device_put(struct platform_device *pdev);
--- linux-4.4.0.orig/include/linux/pm_runtime.h
+++ linux-4.4.0/include/linux/pm_runtime.h
@@ -39,6 +39,7 @@
 extern int __pm_runtime_idle(struct device *dev, int rpmflags);
 extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
 extern int __pm_runtime_resume(struct device *dev, int rpmflags);
+extern int pm_runtime_get_if_in_use(struct device *dev);
 extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
 extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
 extern int pm_runtime_barrier(struct device *dev);
@@ -143,6 +144,10 @@
 {
 	return -ENOSYS;
 }
+static inline int pm_runtime_get_if_in_use(struct device *dev)
+{
+	return -EINVAL;
+}
 static inline int __pm_runtime_set_status(struct device *dev,
 					    unsigned int status) { return 0; }
 static inline int pm_runtime_barrier(struct device *dev) { return 0; }
--- linux-4.4.0.orig/include/linux/pnp.h
+++ linux-4.4.0/include/linux/pnp.h
@@ -219,10 +219,8 @@
 #define global_to_pnp_card(n) list_entry(n, struct pnp_card, global_list)
 #define protocol_to_pnp_card(n) list_entry(n, struct pnp_card, protocol_list)
 #define to_pnp_card(n) container_of(n, struct pnp_card, dev)
-#define pnp_for_each_card(card) \
-	for((card) = global_to_pnp_card(pnp_cards.next); \
-	(card) != global_to_pnp_card(&pnp_cards); \
-	(card) = global_to_pnp_card((card)->global_list.next))
+#define pnp_for_each_card(card)	\
+	list_for_each_entry(card, &pnp_cards, global_list)
 
 struct pnp_card_link {
 	struct pnp_card *card;
@@ -275,14 +273,9 @@
 #define card_to_pnp_dev(n) list_entry(n, struct pnp_dev, card_list)
 #define protocol_to_pnp_dev(n) list_entry(n, struct pnp_dev, protocol_list)
 #define	to_pnp_dev(n) container_of(n, struct pnp_dev, dev)
-#define pnp_for_each_dev(dev) \
-	for((dev) = global_to_pnp_dev(pnp_global.next); \
-	(dev) != global_to_pnp_dev(&pnp_global); \
-	(dev) = global_to_pnp_dev((dev)->global_list.next))
-#define card_for_each_dev(card,dev) \
-	for((dev) = card_to_pnp_dev((card)->devices.next); \
-	(dev) != card_to_pnp_dev(&(card)->devices); \
-	(dev) = card_to_pnp_dev((dev)->card_list.next))
+#define pnp_for_each_dev(dev) list_for_each_entry(dev, &pnp_global, global_list)
+#define card_for_each_dev(card, dev)	\
+	list_for_each_entry(dev, &(card)->devices, card_list)
 #define pnp_dev_name(dev) (dev)->name
 
 static inline void *pnp_get_drvdata(struct pnp_dev *pdev)
@@ -434,14 +427,10 @@
 };
 
 #define to_pnp_protocol(n) list_entry(n, struct pnp_protocol, protocol_list)
-#define protocol_for_each_card(protocol,card) \
-	for((card) = protocol_to_pnp_card((protocol)->cards.next); \
-	(card) != protocol_to_pnp_card(&(protocol)->cards); \
-	(card) = protocol_to_pnp_card((card)->protocol_list.next))
-#define protocol_for_each_dev(protocol,dev) \
-	for((dev) = protocol_to_pnp_dev((protocol)->devices.next); \
-	(dev) != protocol_to_pnp_dev(&(protocol)->devices); \
-	(dev) = protocol_to_pnp_dev((dev)->protocol_list.next))
+#define protocol_for_each_card(protocol, card)	\
+	list_for_each_entry(card, &(protocol)->cards, protocol_list)
+#define protocol_for_each_dev(protocol, dev)	\
+	list_for_each_entry(dev, &(protocol)->devices, protocol_list)
 
 extern struct bus_type pnp_bus_type;
 
--- linux-4.4.0.orig/include/linux/posix-clock.h
+++ linux-4.4.0/include/linux/posix-clock.h
@@ -59,23 +59,23 @@
 
 	int  (*clock_adjtime)(struct posix_clock *pc, struct timex *tx);
 
-	int  (*clock_gettime)(struct posix_clock *pc, struct timespec *ts);
+	int  (*clock_gettime)(struct posix_clock *pc, struct timespec64 *ts);
 
-	int  (*clock_getres) (struct posix_clock *pc, struct timespec *ts);
+	int  (*clock_getres) (struct posix_clock *pc, struct timespec64 *ts);
 
 	int  (*clock_settime)(struct posix_clock *pc,
-			      const struct timespec *ts);
+			      const struct timespec64 *ts);
 
 	int  (*timer_create) (struct posix_clock *pc, struct k_itimer *kit);
 
 	int  (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit);
 
 	void (*timer_gettime)(struct posix_clock *pc,
-			      struct k_itimer *kit, struct itimerspec *tsp);
+			      struct k_itimer *kit, struct itimerspec64 *tsp);
 
 	int  (*timer_settime)(struct posix_clock *pc,
 			      struct k_itimer *kit, int flags,
-			      struct itimerspec *tsp, struct itimerspec *old);
+			      struct itimerspec64 *tsp, struct itimerspec64 *old);
 	/*
 	 * Optional character device methods:
 	 */
@@ -104,29 +104,32 @@
  *
  * @ops:     Functional interface to the clock
  * @cdev:    Character device instance for this clock
- * @kref:    Reference count.
+ * @dev:     Pointer to the clock's device.
  * @rwsem:   Protects the 'zombie' field from concurrent access.
  * @zombie:  If 'zombie' is true, then the hardware has disappeared.
- * @release: A function to free the structure when the reference count reaches
- *           zero. May be NULL if structure is statically allocated.
  *
  * Drivers should embed their struct posix_clock within a private
  * structure, obtaining a reference to it during callbacks using
  * container_of().
+ *
+ * Drivers should supply an initialized but not exposed struct device
+ * to posix_clock_register(). It is used to manage lifetime of the
+ * driver's private structure. It's 'release' field should be set to
+ * a release function for this private structure.
  */
 struct posix_clock {
 	struct posix_clock_operations ops;
 	struct cdev cdev;
-	struct kref kref;
+	struct device *dev;
 	struct rw_semaphore rwsem;
 	bool zombie;
-	void (*release)(struct posix_clock *clk);
 };
 
 /**
  * posix_clock_register() - register a new clock
- * @clk:   Pointer to the clock. Caller must provide 'ops' and 'release'
- * @devid: Allocated device id
+ * @clk:   Pointer to the clock. Caller must provide 'ops' field
+ * @dev:   Pointer to the initialized device. Caller must provide
+ *         'release' field
  *
  * A clock driver calls this function to register itself with the
  * clock device subsystem. If 'clk' points to dynamically allocated
@@ -135,7 +138,7 @@
  *
  * Returns zero on success, non-zero otherwise.
  */
-int posix_clock_register(struct posix_clock *clk, dev_t devid);
+int posix_clock_register(struct posix_clock *clk, struct device *dev);
 
 /**
  * posix_clock_unregister() - unregister a clock
--- linux-4.4.0.orig/include/linux/posix-timers.h
+++ linux-4.4.0/include/linux/posix-timers.h
@@ -65,8 +65,8 @@
 	spinlock_t it_lock;
 	clockid_t it_clock;		/* which timer type */
 	timer_t it_id;			/* timer id */
-	int it_overrun;			/* overrun on pending signal  */
-	int it_overrun_last;		/* overrun on last delivered signal */
+	s64 it_overrun;			/* overrun on pending signal  */
+	s64 it_overrun_last;		/* overrun on last delivered signal */
 	int it_requeue_pending;		/* waiting to requeue this timer */
 #define REQUEUE_PENDING 1
 	int it_sigev_notify;		/* notify word of sigevent struct */
--- linux-4.4.0.orig/include/linux/posix_acl.h
+++ linux-4.4.0/include/linux/posix_acl.h
@@ -81,7 +81,7 @@
 
 extern void posix_acl_init(struct posix_acl *, int);
 extern struct posix_acl *posix_acl_alloc(int, gfp_t);
-extern int posix_acl_valid(const struct posix_acl *);
+extern int posix_acl_valid(struct user_namespace *, const struct posix_acl *);
 extern int posix_acl_permission(struct inode *, const struct posix_acl *, int);
 extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t);
 extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *);
@@ -95,6 +95,7 @@
 extern int posix_acl_chmod(struct inode *, umode_t);
 extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
 		struct posix_acl **);
+extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
 
 extern int simple_set_acl(struct inode *, struct posix_acl *, int);
 extern int simple_acl_create(struct inode *, struct inode *);
--- linux-4.4.0.orig/include/linux/posix_acl_xattr.h
+++ linux-4.4.0/include/linux/posix_acl_xattr.h
@@ -53,9 +53,18 @@
 }
 
 #ifdef CONFIG_FS_POSIX_ACL
+int posix_acl_fix_xattr_userns(struct user_namespace *to,
+			       struct user_namespace *from,
+			       void *value, size_t size);
 void posix_acl_fix_xattr_from_user(void *value, size_t size);
 void posix_acl_fix_xattr_to_user(void *value, size_t size);
 #else
+static inline int posix_acl_fix_xattr_userns(struct user_namespace *to,
+					     struct user_namespace *from,
+					     void *value, size_t size)
+{
+	return 0;
+}
 static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
 {
 }
--- linux-4.4.0.orig/include/linux/pps_kernel.h
+++ linux-4.4.0/include/linux/pps_kernel.h
@@ -111,22 +111,17 @@
 	kt->nsec = ts.tv_nsec;
 }
 
-#ifdef CONFIG_NTP_PPS
-
 static inline void pps_get_ts(struct pps_event_time *ts)
 {
-	ktime_get_raw_and_real_ts64(&ts->ts_raw, &ts->ts_real);
-}
-
-#else /* CONFIG_NTP_PPS */
+	struct system_time_snapshot snap;
 
-static inline void pps_get_ts(struct pps_event_time *ts)
-{
-	ktime_get_real_ts64(&ts->ts_real);
+	ktime_get_snapshot(&snap);
+	ts->ts_real = ktime_to_timespec64(snap.real);
+#ifdef CONFIG_NTP_PPS
+	ts->ts_raw = ktime_to_timespec64(snap.raw);
+#endif
 }
 
-#endif /* CONFIG_NTP_PPS */
-
 /* Subtract known time delay from PPS event time(s) */
 static inline void pps_sub_ts(struct pps_event_time *ts, struct timespec64 delta)
 {
--- linux-4.4.0.orig/include/linux/prandom.h
+++ linux-4.4.0/include/linux/prandom.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/linux/prandom.h
+ *
+ * Include file for the fast pseudo-random 32-bit
+ * generation.
+ */
+#ifndef _LINUX_PRANDOM_H
+#define _LINUX_PRANDOM_H
+
+#include <linux/types.h>
+#include <linux/percpu.h>
+
+u32 prandom_u32(void);
+void prandom_bytes(void *buf, size_t nbytes);
+void prandom_seed(u32 seed);
+void prandom_reseed_late(void);
+
+#if BITS_PER_LONG == 64
+/*
+ * The core SipHash round function.  Each line can be executed in
+ * parallel given enough CPU resources.
+ */
+#define PRND_SIPROUND(v0, v1, v2, v3) ( \
+	v0 += v1, v1 = rol64(v1, 13),  v2 += v3, v3 = rol64(v3, 16), \
+	v1 ^= v0, v0 = rol64(v0, 32),  v3 ^= v2,                     \
+	v0 += v3, v3 = rol64(v3, 21),  v2 += v1, v1 = rol64(v1, 17), \
+	v3 ^= v0,                      v1 ^= v2, v2 = rol64(v2, 32)  \
+)
+
+#define PRND_K0 (0x736f6d6570736575 ^ 0x6c7967656e657261)
+#define PRND_K1 (0x646f72616e646f6d ^ 0x7465646279746573)
+
+#elif BITS_PER_LONG == 32
+/*
+ * On 32-bit machines, we use HSipHash, a reduced-width version of SipHash.
+ * This is weaker, but 32-bit machines are not used for high-traffic
+ * applications, so there is less output for an attacker to analyze.
+ */
+#define PRND_SIPROUND(v0, v1, v2, v3) ( \
+	v0 += v1, v1 = rol32(v1,  5),  v2 += v3, v3 = rol32(v3,  8), \
+	v1 ^= v0, v0 = rol32(v0, 16),  v3 ^= v2,                     \
+	v0 += v3, v3 = rol32(v3,  7),  v2 += v1, v1 = rol32(v1, 13), \
+	v3 ^= v0,                      v1 ^= v2, v2 = rol32(v2, 16)  \
+)
+#define PRND_K0 0x6c796765
+#define PRND_K1 0x74656462
+
+#else
+#error Unsupported BITS_PER_LONG
+#endif
+
+struct rnd_state {
+	__u32 s1, s2, s3, s4;
+};
+
+u32 prandom_u32_state(struct rnd_state *state);
+void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
+void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
+
+#define prandom_init_once(pcpu_state)			\
+	DO_ONCE(prandom_seed_full_state, (pcpu_state))
+
+/**
+ * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro)
+ * @ep_ro: right open interval endpoint
+ *
+ * Returns a pseudo-random number that is in interval [0, ep_ro). Note
+ * that the result depends on PRNG being well distributed in [0, ~0U]
+ * u32 space. Here we use maximally equidistributed combined Tausworthe
+ * generator, that is, prandom_u32(). This is useful when requesting a
+ * random index of an array containing ep_ro elements, for example.
+ *
+ * Returns: pseudo-random number in interval [0, ep_ro)
+ */
+static inline u32 prandom_u32_max(u32 ep_ro)
+{
+	return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
+}
+
+/*
+ * Handle minimum values for seeds
+ */
+static inline u32 __seed(u32 x, u32 m)
+{
+	return (x < m) ? x + m : x;
+}
+
+/**
+ * prandom_seed_state - set seed for prandom_u32_state().
+ * @state: pointer to state structure to receive the seed.
+ * @seed: arbitrary 64-bit value to use as a seed.
+ */
+static inline void prandom_seed_state(struct rnd_state *state, u64 seed)
+{
+	u32 i = (seed >> 32) ^ (seed << 10) ^ seed;
+
+	state->s1 = __seed(i,   2U);
+	state->s2 = __seed(i,   8U);
+	state->s3 = __seed(i,  16U);
+	state->s4 = __seed(i, 128U);
+}
+
+/* Pseudo random number generator from numerical recipes. */
+static inline u32 next_pseudo_random32(u32 seed)
+{
+	return seed * 1664525 + 1013904223;
+}
+
+#endif
--- linux-4.4.0.orig/include/linux/preempt.h
+++ linux-4.4.0/include/linux/preempt.h
@@ -65,19 +65,24 @@
 
 /*
  * Are we doing bottom half or hardware interrupt processing?
- * Are we in a softirq context? Interrupt context?
- * in_softirq - Are we currently processing softirq or have bh disabled?
- * in_serving_softirq - Are we currently processing softirq?
+ *
+ * in_irq()       - We're in (hard) IRQ context
+ * in_softirq()   - We have BH disabled, or are processing softirqs
+ * in_interrupt() - We're in NMI,IRQ,SoftIRQ context or have BH disabled
+ * in_serving_softirq() - We're in softirq context
+ * in_nmi()       - We're in NMI context
+ * in_task()	  - We're in task context
+ *
+ * Note: due to the BH disabled confusion: in_softirq(),in_interrupt() really
+ *       should not be used in new code.
  */
 #define in_irq()		(hardirq_count())
 #define in_softirq()		(softirq_count())
 #define in_interrupt()		(irq_count())
 #define in_serving_softirq()	(softirq_count() & SOFTIRQ_OFFSET)
-
-/*
- * Are we in NMI context?
- */
-#define in_nmi()	(preempt_count() & NMI_MASK)
+#define in_nmi()		(preempt_count() & NMI_MASK)
+#define in_task()		(!(preempt_count() & \
+				   (NMI_MASK | HARDIRQ_MASK | SOFTIRQ_OFFSET)))
 
 /*
  * The preempt_count offset after preempt_disable();
--- linux-4.4.0.orig/include/linux/printk.h
+++ linux-4.4.0/include/linux/printk.h
@@ -106,13 +106,13 @@
 
 /*
  * Dummy printk for disabled debugging statements to use whilst maintaining
- * gcc's format and side-effect checking.
+ * gcc's format checking.
  */
-static inline __printf(1, 2)
-int no_printk(const char *fmt, ...)
-{
-	return 0;
-}
+#define no_printk(fmt, ...)			\
+do {						\
+	if (0)					\
+		printk(fmt, ##__VA_ARGS__);	\
+} while (0)
 
 #ifdef CONFIG_EARLY_PRINTK
 extern asmlinkage __printf(1, 2)
--- linux-4.4.0.orig/include/linux/proc_fs.h
+++ linux-4.4.0/include/linux/proc_fs.h
@@ -21,6 +21,7 @@
 					      struct proc_dir_entry *, void *);
 extern struct proc_dir_entry *proc_mkdir_mode(const char *, umode_t,
 					      struct proc_dir_entry *);
+struct proc_dir_entry *proc_create_mount_point(const char *name);
  
 extern struct proc_dir_entry *proc_create_data(const char *, umode_t,
 					       struct proc_dir_entry *,
@@ -56,6 +57,7 @@
 		struct proc_dir_entry *parent,const char *dest) { return NULL;}
 static inline struct proc_dir_entry *proc_mkdir(const char *name,
 	struct proc_dir_entry *parent) {return NULL;}
+static inline struct proc_dir_entry *proc_create_mount_point(const char *name) { return NULL; }
 static inline struct proc_dir_entry *proc_mkdir_data(const char *name,
 	umode_t mode, struct proc_dir_entry *parent, void *data) { return NULL; }
 static inline struct proc_dir_entry *proc_mkdir_mode(const char *name,
--- linux-4.4.0.orig/include/linux/proc_ns.h
+++ linux-4.4.0/include/linux/proc_ns.h
@@ -9,6 +9,8 @@
 struct pid_namespace;
 struct nsproxy;
 struct path;
+struct task_struct;
+struct inode;
 
 struct proc_ns_operations {
 	const char *name;
@@ -24,6 +26,7 @@
 extern const struct proc_ns_operations pidns_operations;
 extern const struct proc_ns_operations userns_operations;
 extern const struct proc_ns_operations mntns_operations;
+extern const struct proc_ns_operations cgroupns_operations;
 
 /*
  * We always define these enumerators
@@ -34,6 +37,7 @@
 	PROC_UTS_INIT_INO	= 0xEFFFFFFEU,
 	PROC_USER_INIT_INO	= 0xEFFFFFFDU,
 	PROC_PID_INIT_INO	= 0xEFFFFFFCU,
+	PROC_CGROUP_INIT_INO	= 0xEFFFFFFBU,
 };
 
 #ifdef CONFIG_PROC_FS
--- linux-4.4.0.orig/include/linux/property.h
+++ linux-4.4.0/include/linux/property.h
@@ -73,8 +73,8 @@
 struct fwnode_handle *device_get_next_child_node(struct device *dev,
 						 struct fwnode_handle *child);
 
-#define device_for_each_child_node(dev, child) \
-	for (child = device_get_next_child_node(dev, NULL); child; \
+#define device_for_each_child_node(dev, child)				\
+	for (child = device_get_next_child_node(dev, NULL); child;	\
 	     child = device_get_next_child_node(dev, child))
 
 void fwnode_handle_put(struct fwnode_handle *fwnode);
@@ -144,24 +144,92 @@
 /**
  * struct property_entry - "Built-in" device property representation.
  * @name: Name of the property.
- * @type: Type of the property.
- * @nval: Number of items of type @type making up the value.
- * @value: Value of the property (an array of @nval items of type @type).
+ * @length: Length of data making up the value.
+ * @is_array: True when the property is an array.
+ * @is_string: True when property is a string.
+ * @pointer: Pointer to the property (an array of items of the given type).
+ * @value: Value of the property (when it is a single item of the given type).
  */
 struct property_entry {
 	const char *name;
-	enum dev_prop_type type;
-	size_t nval;
+	size_t length;
+	bool is_array;
+	bool is_string;
 	union {
-		void *raw_data;
-		u8 *u8_data;
-		u16 *u16_data;
-		u32 *u32_data;
-		u64 *u64_data;
-		const char **str;
-	} value;
+		union {
+			void *raw_data;
+			u8 *u8_data;
+			u16 *u16_data;
+			u32 *u32_data;
+			u64 *u64_data;
+			const char **str;
+		} pointer;
+		union {
+			unsigned long long raw_data;
+			u8 u8_data;
+			u16 u16_data;
+			u32 u32_data;
+			u64 u64_data;
+			const char *str;
+		} value;
+	};
 };
 
+#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_)	\
+{								\
+	.name = _name_,						\
+	.length = ARRAY_SIZE(_val_) * sizeof(_type_),		\
+	.is_array = true,					\
+	.pointer._type_##_data = _val_,				\
+}
+
+#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_)			\
+	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, _val_)
+#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_)			\
+	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, _val_)
+#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_)			\
+	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, _val_)
+#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_)			\
+	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_)
+
+#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_)		\
+{								\
+	.name = _name_,						\
+	.length = ARRAY_SIZE(_val_) * sizeof(const char *),	\
+	.is_array = true,					\
+	.is_string = true,					\
+	.pointer.str = _val_,					\
+}
+
+#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_)	\
+{							\
+	.name = _name_,					\
+	.length = sizeof(_type_),			\
+	.value._type_##_data = _val_,			\
+}
+
+#define PROPERTY_ENTRY_U8(_name_, _val_)		\
+	PROPERTY_ENTRY_INTEGER(_name_, u8, _val_)
+#define PROPERTY_ENTRY_U16(_name_, _val_)		\
+	PROPERTY_ENTRY_INTEGER(_name_, u16, _val_)
+#define PROPERTY_ENTRY_U32(_name_, _val_)		\
+	PROPERTY_ENTRY_INTEGER(_name_, u32, _val_)
+#define PROPERTY_ENTRY_U64(_name_, _val_)		\
+	PROPERTY_ENTRY_INTEGER(_name_, u64, _val_)
+
+#define PROPERTY_ENTRY_STRING(_name_, _val_)		\
+{							\
+	.name = _name_,					\
+	.length = sizeof(_val_),			\
+	.is_string = true,				\
+	.value.str = _val_,				\
+}
+
+#define PROPERTY_ENTRY_BOOL(_name_)		\
+{						\
+	.name = _name_,				\
+}
+
 /**
  * struct property_set - Collection of "built-in" device properties.
  * @fwnode: Handle to be pointed to by the fwnode field of struct device.
@@ -172,7 +240,8 @@
 	struct property_entry *properties;
 };
 
-void device_add_property_set(struct device *dev, struct property_set *pset);
+int device_add_property_set(struct device *dev, const struct property_set *pset);
+void device_remove_property_set(struct device *dev);
 
 bool device_dma_supported(struct device *dev);
 
--- linux-4.4.0.orig/include/linux/psci.h
+++ linux-4.4.0/include/linux/psci.h
@@ -24,6 +24,17 @@
 bool psci_power_state_loses_context(u32 state);
 bool psci_power_state_is_valid(u32 state);
 
+enum psci_conduit {
+	PSCI_CONDUIT_NONE,
+	PSCI_CONDUIT_SMC,
+	PSCI_CONDUIT_HVC,
+};
+
+enum smccc_version {
+	SMCCC_VERSION_1_0,
+	SMCCC_VERSION_1_1,
+};
+
 struct psci_operations {
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
 	int (*cpu_off)(u32 state);
@@ -32,6 +43,8 @@
 	int (*affinity_info)(unsigned long target_affinity,
 			unsigned long lowest_affinity_level);
 	int (*migrate_info_type)(void);
+	enum psci_conduit conduit;
+	enum smccc_version smccc_version;
 };
 
 extern struct psci_operations psci_ops;
--- linux-4.4.0.orig/include/linux/pstore_ram.h
+++ linux-4.4.0/include/linux/pstore_ram.h
@@ -23,6 +23,13 @@
 #include <linux/types.h>
 #include <linux/init.h>
 
+/*
+ * Choose whether access to the RAM zone requires locking or not.  If a zone
+ * can be written to from different CPUs like with ftrace for example, then
+ * PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
+ */
+#define PRZ_FLAG_NO_LOCK	BIT(0)
+
 struct persistent_ram_buffer;
 struct rs_control;
 
@@ -39,6 +46,8 @@
 	void *vaddr;
 	struct persistent_ram_buffer *buffer;
 	size_t buffer_size;
+	u32 flags;
+	raw_spinlock_t buffer_lock;
 
 	/* ECC correction */
 	char *par_buffer;
@@ -54,7 +63,7 @@
 
 struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
 			u32 sig, struct persistent_ram_ecc_info *ecc_info,
-			unsigned int memtype);
+			unsigned int memtype, u32 flags);
 void persistent_ram_free(struct persistent_ram_zone *prz);
 void persistent_ram_zap(struct persistent_ram_zone *prz);
 
--- linux-4.4.0.orig/include/linux/ptp_clock_kernel.h
+++ linux-4.4.0/include/linux/ptp_clock_kernel.h
@@ -38,6 +38,7 @@
 	};
 };
 
+struct system_device_crosststamp;
 /**
  * struct ptp_clock_info - decribes a PTP hardware clock
  *
@@ -67,6 +68,11 @@
  * @gettime64:  Reads the current time from the hardware clock.
  *              parameter ts: Holds the result.
  *
+ * @getcrosststamp:  Reads the current time from the hardware clock and
+ *                   system clock simultaneously.
+ *                   parameter cts: Contains timestamp (device,system) pair,
+ *                   where system time is realtime and monotonic.
+ *
  * @settime64:  Set the current time on the hardware clock.
  *              parameter ts: Time value to set.
  *
@@ -105,6 +111,8 @@
 	int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
 	int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
 	int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts);
+	int (*getcrosststamp)(struct ptp_clock_info *ptp,
+			      struct system_device_crosststamp *cts);
 	int (*settime64)(struct ptp_clock_info *p, const struct timespec64 *ts);
 	int (*enable)(struct ptp_clock_info *ptp,
 		      struct ptp_clock_request *request, int on);
--- linux-4.4.0.orig/include/linux/ptrace.h
+++ linux-4.4.0/include/linux/ptrace.h
@@ -19,7 +19,6 @@
 #define PT_SEIZED	0x00010000	/* SEIZE used, enable new behavior */
 #define PT_PTRACED	0x00000001
 #define PT_DTRACE	0x00000002	/* delayed trace (used on m68k, i386) */
-#define PT_PTRACE_CAP	0x00000004	/* ptracer can follow suid-exec */
 
 #define PT_OPT_FLAG_SHIFT	3
 /* PT_TRACE_* event enable flags */
@@ -51,15 +50,55 @@
 			  unsigned long addr, unsigned long data);
 extern void ptrace_notify(int exit_code);
 extern void __ptrace_link(struct task_struct *child,
-			  struct task_struct *new_parent);
+			  struct task_struct *new_parent,
+			  const struct cred *ptracer_cred);
 extern void __ptrace_unlink(struct task_struct *child);
 extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
 #define PTRACE_MODE_READ	0x01
 #define PTRACE_MODE_ATTACH	0x02
 #define PTRACE_MODE_NOAUDIT	0x04
-/* Returns true on success, false on denial. */
+#define PTRACE_MODE_FSCREDS	0x08
+#define PTRACE_MODE_REALCREDS	0x10
+#define PTRACE_MODE_SCHED	0x20
+#define PTRACE_MODE_IBPB	0x40
+
+/* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */
+#define PTRACE_MODE_READ_FSCREDS (PTRACE_MODE_READ | PTRACE_MODE_FSCREDS)
+#define PTRACE_MODE_READ_REALCREDS (PTRACE_MODE_READ | PTRACE_MODE_REALCREDS)
+#define PTRACE_MODE_ATTACH_FSCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS)
+#define PTRACE_MODE_ATTACH_REALCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS)
+#define PTRACE_MODE_SPEC_IBPB (PTRACE_MODE_ATTACH_REALCREDS | PTRACE_MODE_IBPB)
+
+/**
+ * ptrace_may_access - check whether the caller is permitted to access
+ * a target task.
+ * @task: target task
+ * @mode: selects type of access and caller credentials
+ *
+ * Returns true on success, false on denial.
+ *
+ * One of the flags PTRACE_MODE_FSCREDS and PTRACE_MODE_REALCREDS must
+ * be set in @mode to specify whether the access was requested through
+ * a filesystem syscall (should use effective capabilities and fsuid
+ * of the caller) or through an explicit syscall such as
+ * process_vm_writev or ptrace (and should use the real credentials).
+ */
 extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
 
+/**
+ * ptrace_may_access - check whether the caller is permitted to access
+ * a target task.
+ * @task: target task
+ * @mode: selects type of access and caller credentials
+ *
+ * Returns true on success, false on denial.
+ *
+ * Similar to ptrace_may_access(). Only to be called from context switch
+ * code. Does not call into audit and the regular LSM hooks due to locking
+ * constraints.
+ */
+extern bool ptrace_may_access_sched(struct task_struct *task, unsigned int mode);
+
 static inline int ptrace_reparented(struct task_struct *child)
 {
 	return !same_thread_group(child->real_parent, child->parent);
@@ -181,7 +220,7 @@
 
 	if (unlikely(ptrace) && current->ptrace) {
 		child->ptrace = current->ptrace;
-		__ptrace_link(child, current->parent);
+		__ptrace_link(child, current->parent, current->ptracer_cred);
 
 		if (child->ptrace & PT_SEIZED)
 			task_set_jobctl_pending(child, JOBCTL_TRAP_STOP);
@@ -190,6 +229,8 @@
 
 		set_tsk_thread_flag(child, TIF_SIGPENDING);
 	}
+	else
+		child->ptracer_cred = NULL;
 }
 
 /**
--- linux-4.4.0.orig/include/linux/quota.h
+++ linux-4.4.0/include/linux/quota.h
@@ -179,6 +179,16 @@
 	return kqid;
 }
 
+/**
+ *	qid_has_mapping - Report if a qid maps into a user namespace.
+ *	@ns:  The user namespace to see if a value maps into.
+ *	@qid: The kernel internal quota identifier to test.
+ */
+static inline bool qid_has_mapping(struct user_namespace *ns, struct kqid qid)
+{
+	return from_kqid(ns, qid) != (qid_t) -1;
+}
+
 
 extern spinlock_t dq_data_lock;
 
@@ -253,7 +263,7 @@
 };
 
 struct dqstats {
-	int stat[_DQST_DQSTAT_LAST];
+	unsigned long stat[_DQST_DQSTAT_LAST];
 	struct percpu_counter counter[_DQST_DQSTAT_LAST];
 };
 
--- linux-4.4.0.orig/include/linux/quotaops.h
+++ linux-4.4.0/include/linux/quotaops.h
@@ -21,7 +21,7 @@
 /* i_mutex must being held */
 static inline bool is_quota_modification(struct inode *inode, struct iattr *ia)
 {
-	return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) ||
+	return (ia->ia_valid & ATTR_SIZE) ||
 		(ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) ||
 		(ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid));
 }
@@ -54,6 +54,16 @@
 	atomic_inc(&dquot->dq_count);
 	return dquot;
 }
+
+static inline bool dquot_is_busy(struct dquot *dquot)
+{
+	if (test_bit(DQ_MOD_B, &dquot->dq_flags))
+		return true;
+	if (atomic_read(&dquot->dq_count) > 1)
+		return true;
+	return false;
+}
+
 void dqput(struct dquot *dquot);
 int dquot_scan_active(struct super_block *sb,
 		      int (*fn)(struct dquot *dquot, unsigned long priv),
--- linux-4.4.0.orig/include/linux/radix-tree.h
+++ linux-4.4.0/include/linux/radix-tree.h
@@ -370,12 +370,29 @@
 			     struct radix_tree_iter *iter, unsigned flags);
 
 /**
+ * radix_tree_iter_retry - retry this chunk of the iteration
+ * @iter:	iterator state
+ *
+ * If we iterate over a tree protected only by the RCU lock, a race
+ * against deletion or creation may result in seeing a slot for which
+ * radix_tree_deref_retry() returns true.  If so, call this function
+ * and continue the iteration.
+ */
+static inline __must_check
+void **radix_tree_iter_retry(struct radix_tree_iter *iter)
+{
+	iter->next_index = iter->index;
+	iter->tags = 0;
+	return NULL;
+}
+
+/**
  * radix_tree_chunk_size - get current chunk size
  *
  * @iter:	pointer to radix tree iterator
  * Returns:	current chunk size
  */
-static __always_inline unsigned
+static __always_inline long
 radix_tree_chunk_size(struct radix_tree_iter *iter)
 {
 	return iter->next_index - iter->index;
@@ -409,9 +426,9 @@
 			return slot + offset + 1;
 		}
 	} else {
-		unsigned size = radix_tree_chunk_size(iter) - 1;
+		long size = radix_tree_chunk_size(iter);
 
-		while (size--) {
+		while (--size > 0) {
 			slot++;
 			iter->index++;
 			if (likely(*slot))
--- linux-4.4.0.orig/include/linux/random.h
+++ linux-4.4.0/include/linux/random.h
@@ -34,63 +34,15 @@
 #endif
 
 unsigned int get_random_int(void);
+unsigned long get_random_long(void);
 unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
 
-u32 prandom_u32(void);
-void prandom_bytes(void *buf, size_t nbytes);
-void prandom_seed(u32 seed);
-void prandom_reseed_late(void);
-
-struct rnd_state {
-	__u32 s1, s2, s3, s4;
-};
-
-u32 prandom_u32_state(struct rnd_state *state);
-void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
-void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
-
-#define prandom_init_once(pcpu_state)			\
-	DO_ONCE(prandom_seed_full_state, (pcpu_state))
-
-/**
- * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro)
- * @ep_ro: right open interval endpoint
- *
- * Returns a pseudo-random number that is in interval [0, ep_ro). Note
- * that the result depends on PRNG being well distributed in [0, ~0U]
- * u32 space. Here we use maximally equidistributed combined Tausworthe
- * generator, that is, prandom_u32(). This is useful when requesting a
- * random index of an array containing ep_ro elements, for example.
- *
- * Returns: pseudo-random number in interval [0, ep_ro)
- */
-static inline u32 prandom_u32_max(u32 ep_ro)
-{
-	return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
-}
-
 /*
- * Handle minimum values for seeds
- */
-static inline u32 __seed(u32 x, u32 m)
-{
-	return (x < m) ? x + m : x;
-}
-
-/**
- * prandom_seed_state - set seed for prandom_u32_state().
- * @state: pointer to state structure to receive the seed.
- * @seed: arbitrary 64-bit value to use as a seed.
+ * This is designed to be standalone for just prandom
+ * users, but for now we include it from <linux/random.h>
+ * for legacy reasons.
  */
-static inline void prandom_seed_state(struct rnd_state *state, u64 seed)
-{
-	u32 i = (seed >> 32) ^ (seed << 10) ^ seed;
-
-	state->s1 = __seed(i,   2U);
-	state->s2 = __seed(i,   8U);
-	state->s3 = __seed(i,  16U);
-	state->s4 = __seed(i, 128U);
-}
+#include <linux/prandom.h>
 
 #ifdef CONFIG_ARCH_RANDOM
 # include <asm/archrandom.h>
@@ -121,10 +73,4 @@
 }
 #endif
 
-/* Pseudo random number generator from numerical recipes. */
-static inline u32 next_pseudo_random32(u32 seed)
-{
-	return seed * 1664525 + 1013904223;
-}
-
 #endif /* _LINUX_RANDOM_H */
--- linux-4.4.0.orig/include/linux/rbtree.h
+++ linux-4.4.0/include/linux/rbtree.h
@@ -44,10 +44,25 @@
 	struct rb_node *rb_node;
 };
 
+/*
+ * Leftmost-cached rbtrees.
+ *
+ * We do not cache the rightmost node based on footprint
+ * size vs number of potential users that could benefit
+ * from O(1) rb_last(). Just not worth it, users that want
+ * this feature can always implement the logic explicitly.
+ * Furthermore, users that want to cache both pointers may
+ * find it a bit asymmetric, but that's ok.
+ */
+struct rb_root_cached {
+	struct rb_root rb_root;
+	struct rb_node *rb_leftmost;
+};
 
 #define rb_parent(r)   ((struct rb_node *)((r)->__rb_parent_color & ~3))
 
 #define RB_ROOT	(struct rb_root) { NULL, }
+#define RB_ROOT_CACHED (struct rb_root_cached) { {NULL, }, NULL }
 #define	rb_entry(ptr, type, member) container_of(ptr, type, member)
 
 #define RB_EMPTY_ROOT(root)  ((root)->rb_node == NULL)
@@ -69,6 +84,12 @@
 extern struct rb_node *rb_first(const struct rb_root *);
 extern struct rb_node *rb_last(const struct rb_root *);
 
+extern void rb_insert_color_cached(struct rb_node *,
+				   struct rb_root_cached *, bool);
+extern void rb_erase_cached(struct rb_node *node, struct rb_root_cached *);
+/* Same as rb_first(), but O(1) */
+#define rb_first_cached(root) (root)->rb_leftmost
+
 /* Postorder iteration - always visit the parent after its children */
 extern struct rb_node *rb_first_postorder(const struct rb_root *);
 extern struct rb_node *rb_next_postorder(const struct rb_node *);
--- linux-4.4.0.orig/include/linux/rbtree_augmented.h
+++ linux-4.4.0/include/linux/rbtree_augmented.h
@@ -41,7 +41,9 @@
 	void (*rotate)(struct rb_node *old, struct rb_node *new);
 };
 
-extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
+extern void __rb_insert_augmented(struct rb_node *node,
+				  struct rb_root *root,
+				  bool newleft, struct rb_node **leftmost,
 	void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
 /*
  * Fixup the rbtree and update the augmented information when rebalancing.
@@ -57,7 +59,16 @@
 rb_insert_augmented(struct rb_node *node, struct rb_root *root,
 		    const struct rb_augment_callbacks *augment)
 {
-	__rb_insert_augmented(node, root, augment->rotate);
+	__rb_insert_augmented(node, root, false, NULL, augment->rotate);
+}
+
+static inline void
+rb_insert_augmented_cached(struct rb_node *node,
+			   struct rb_root_cached *root, bool newleft,
+			   const struct rb_augment_callbacks *augment)
+{
+	__rb_insert_augmented(node, &root->rb_root,
+			      newleft, &root->rb_leftmost, augment->rotate);
 }
 
 #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield,	\
@@ -135,6 +146,7 @@
 
 static __always_inline struct rb_node *
 __rb_erase_augmented(struct rb_node *node, struct rb_root *root,
+		     struct rb_node **leftmost,
 		     const struct rb_augment_callbacks *augment)
 {
 	struct rb_node *child = node->rb_right;
@@ -142,6 +154,9 @@
 	struct rb_node *parent, *rebalance;
 	unsigned long pc;
 
+	if (leftmost && node == *leftmost)
+		*leftmost = rb_next(node);
+
 	if (!tmp) {
 		/*
 		 * Case 1: node to erase has no more than 1 child (easy!)
@@ -241,9 +256,21 @@
 rb_erase_augmented(struct rb_node *node, struct rb_root *root,
 		   const struct rb_augment_callbacks *augment)
 {
-	struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
+	struct rb_node *rebalance = __rb_erase_augmented(node, root,
+							 NULL, augment);
 	if (rebalance)
 		__rb_erase_color(rebalance, root, augment->rotate);
 }
 
+static __always_inline void
+rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root,
+			  const struct rb_augment_callbacks *augment)
+{
+	struct rb_node *rebalance = __rb_erase_augmented(node, &root->rb_root,
+							 &root->rb_leftmost,
+							 augment);
+	if (rebalance)
+		__rb_erase_color(rebalance, &root->rb_root, augment->rotate);
+}
+
 #endif	/* _LINUX_RBTREE_AUGMENTED_H */
--- linux-4.4.0.orig/include/linux/rculist.h
+++ linux-4.4.0/include/linux/rculist.h
@@ -402,6 +402,42 @@
 }
 
 /**
+ * hlist_add_tail_rcu
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * Description:
+ * Adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.  Regardless of the type of CPU, the
+ * list-traversal primitive must be guarded by rcu_read_lock().
+ */
+static inline void hlist_add_tail_rcu(struct hlist_node *n,
+				      struct hlist_head *h)
+{
+	struct hlist_node *i, *last = NULL;
+
+	for (i = hlist_first_rcu(h); i; i = hlist_next_rcu(i))
+		last = i;
+
+	if (last) {
+		n->next = last->next;
+		n->pprev = &last->next;
+		rcu_assign_pointer(hlist_next_rcu(last), n);
+	} else {
+		hlist_add_head_rcu(n, h);
+	}
+}
+
+/**
  * hlist_add_before_rcu
  * @n: the new element to add to the hash list.
  * @next: the existing element to add the new element before.
--- linux-4.4.0.orig/include/linux/rculist_nulls.h
+++ linux-4.4.0/include/linux/rculist_nulls.h
@@ -33,7 +33,7 @@
 {
 	if (!hlist_nulls_unhashed(n)) {
 		__hlist_nulls_del(n);
-		n->pprev = NULL;
+		WRITE_ONCE(n->pprev, NULL);
 	}
 }
 
@@ -65,7 +65,7 @@
 static inline void hlist_nulls_del_rcu(struct hlist_nulls_node *n)
 {
 	__hlist_nulls_del(n);
-	n->pprev = LIST_POISON2;
+	WRITE_ONCE(n->pprev, LIST_POISON2);
 }
 
 /**
@@ -93,10 +93,10 @@
 	struct hlist_nulls_node *first = h->first;
 
 	n->next = first;
-	n->pprev = &h->first;
+	WRITE_ONCE(n->pprev, &h->first);
 	rcu_assign_pointer(hlist_nulls_first_rcu(h), n);
 	if (!is_a_nulls(first))
-		first->pprev = &n->next;
+		WRITE_ONCE(first->pprev, &n->next);
 }
 /**
  * hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type
--- linux-4.4.0.orig/include/linux/rcupdate.h
+++ linux-4.4.0/include/linux/rcupdate.h
@@ -297,14 +297,12 @@
 
 static inline void __rcu_read_lock(void)
 {
-	if (IS_ENABLED(CONFIG_PREEMPT_COUNT))
-		preempt_disable();
+	preempt_disable();
 }
 
 static inline void __rcu_read_unlock(void)
 {
-	if (IS_ENABLED(CONFIG_PREEMPT_COUNT))
-		preempt_enable();
+	preempt_enable();
 }
 
 static inline void synchronize_rcu(void)
@@ -854,7 +852,7 @@
  * read-side critical sections may be preempted and they may also block, but
  * only when acquiring spinlocks that are subject to priority inheritance.
  */
-static inline void rcu_read_lock(void)
+static __always_inline void rcu_read_lock(void)
 {
 	__rcu_read_lock();
 	__acquire(RCU);
--- linux-4.4.0.orig/include/linux/regmap.h
+++ linux-4.4.0/include/linux/regmap.h
@@ -144,6 +144,20 @@
  *                field is NULL but precious_table (see below) is not, the
  *                check is performed on such table (a register is precious if
  *                it belongs to one of the ranges specified by precious_table).
+ * @writeable_noinc_reg: Optional callback returning true if the register
+ *			supports multiple write operations without incrementing
+ *			the register number. If this field is NULL but
+ *			wr_noinc_table (see below) is not, the check is
+ *			performed on such table (a register is no increment
+ *			writeable if it belongs to one of the ranges specified
+ *			by wr_noinc_table).
+ * @readable_noinc_reg: Optional callback returning true if the register
+ *			supports multiple read operations without incrementing
+ *			the register number. If this field is NULL but
+ *			rd_noinc_table (see below) is not, the check is
+ *			performed on such table (a register is no increment
+ *			readable if it belongs to one of the ranges specified
+ *			by rd_noinc_table).
  * @lock:	  Optional lock callback (overrides regmap's default lock
  *		  function, based on spinlock or mutex).
  * @unlock:	  As above for unlocking.
@@ -168,6 +182,8 @@
  * @rd_table:     As above, for read access.
  * @volatile_table: As above, for volatile registers.
  * @precious_table: As above, for precious registers.
+ * @wr_noinc_table: As above, for no increment writeable registers.
+ * @rd_noinc_table: As above, for no increment readable registers.
  * @reg_defaults: Power on reset values for registers (for use with
  *                register cache support).
  * @num_reg_defaults: Number of elements in reg_defaults.
@@ -210,6 +226,9 @@
 	bool (*readable_reg)(struct device *dev, unsigned int reg);
 	bool (*volatile_reg)(struct device *dev, unsigned int reg);
 	bool (*precious_reg)(struct device *dev, unsigned int reg);
+	bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
+	bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
+
 	regmap_lock lock;
 	regmap_unlock unlock;
 	void *lock_arg;
@@ -224,6 +243,8 @@
 	const struct regmap_access_table *rd_table;
 	const struct regmap_access_table *volatile_table;
 	const struct regmap_access_table *precious_table;
+	const struct regmap_access_table *wr_noinc_table;
+	const struct regmap_access_table *rd_noinc_table;
 	const struct reg_default *reg_defaults;
 	unsigned int num_reg_defaults;
 	enum regcache_type cache_type;
@@ -677,6 +698,8 @@
 int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val);
 int regmap_raw_write(struct regmap *map, unsigned int reg,
 		     const void *val, size_t val_len);
+int regmap_noinc_write(struct regmap *map, unsigned int reg,
+		     const void *val, size_t val_len);
 int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 			size_t val_count);
 int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
@@ -689,6 +712,8 @@
 int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
 int regmap_raw_read(struct regmap *map, unsigned int reg,
 		    void *val, size_t val_len);
+int regmap_noinc_read(struct regmap *map, unsigned int reg,
+		      void *val, size_t val_len);
 int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 		     size_t val_count);
 int regmap_update_bits(struct regmap *map, unsigned int reg,
@@ -893,6 +918,13 @@
 	return -EINVAL;
 }
 
+static inline int regmap_noinc_write(struct regmap *map, unsigned int reg,
+				    const void *val, size_t val_len)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
 				    const void *val, size_t val_count)
 {
@@ -912,6 +944,13 @@
 {
 	WARN_ONCE(1, "regmap API is disabled");
 	return -EINVAL;
+}
+
+static inline int regmap_noinc_read(struct regmap *map, unsigned int reg,
+				    void *val, size_t val_len)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
 }
 
 static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
--- linux-4.4.0.orig/include/linux/regulator/ab8500.h
+++ linux-4.4.0/include/linux/regulator/ab8500.h
@@ -44,8 +44,6 @@
 	AB8505_LDO_ANAMIC2,
 	AB8505_LDO_AUX8,
 	AB8505_LDO_ANA,
-	AB8505_SYSCLKREQ_2,
-	AB8505_SYSCLKREQ_4,
 	AB8505_NUM_REGULATORS,
 };
 
--- linux-4.4.0.orig/include/linux/regulator/consumer.h
+++ linux-4.4.0/include/linux/regulator/consumer.h
@@ -485,7 +485,7 @@
 
 static inline int regulator_set_load(struct regulator *regulator, int load_uA)
 {
-	return REGULATOR_MODE_NORMAL;
+	return 0;
 }
 
 static inline int regulator_allow_bypass(struct regulator *regulator,
--- linux-4.4.0.orig/include/linux/reset-controller.h
+++ linux-4.4.0/include/linux/reset-controller.h
@@ -6,7 +6,7 @@
 struct reset_controller_dev;
 
 /**
- * struct reset_control_ops
+ * struct reset_control_ops - reset controller driver callbacks
  *
  * @reset: for self-deasserting resets, does all necessary
  *         things to reset the device
--- linux-4.4.0.orig/include/linux/rhashtable.h
+++ linux-4.4.0/include/linux/rhashtable.h
@@ -133,23 +133,23 @@
 /**
  * struct rhashtable - Hash table handle
  * @tbl: Bucket table
- * @nelems: Number of elements in table
  * @key_len: Key length for hashfn
  * @elasticity: Maximum chain length before rehash
  * @p: Configuration parameters
  * @run_work: Deferred worker to expand/shrink asynchronously
  * @mutex: Mutex to protect current/future table swapping
  * @lock: Spin lock to protect walker list
+ * @nelems: Number of elements in table
  */
 struct rhashtable {
 	struct bucket_table __rcu	*tbl;
-	atomic_t			nelems;
 	unsigned int			key_len;
 	unsigned int			elasticity;
 	struct rhashtable_params	p;
 	struct work_struct		run_work;
 	struct mutex                    mutex;
 	spinlock_t			lock;
+	atomic_t			nelems;
 };
 
 /**
@@ -343,7 +343,8 @@
 struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
 					    const void *key,
 					    struct rhash_head *obj,
-					    struct bucket_table *old_tbl);
+					    struct bucket_table *old_tbl,
+					    void **data);
 int rhashtable_insert_rehash(struct rhashtable *ht, struct bucket_table *tbl);
 
 int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter);
@@ -514,18 +515,8 @@
 	return memcmp(ptr + ht->p.key_offset, arg->key, ht->p.key_len);
 }
 
-/**
- * rhashtable_lookup_fast - search hash table, inlined version
- * @ht:		hash table
- * @key:	the pointer to the key
- * @params:	hash table parameters
- *
- * Computes the hash value for the key and traverses the bucket chain looking
- * for a entry with an identical key. The first matching entry is returned.
- *
- * Returns the first entry on which the compare function returned true.
- */
-static inline void *rhashtable_lookup_fast(
+/* Internal function, do not use. */
+static inline struct rhash_head *__rhashtable_lookup(
 	struct rhashtable *ht, const void *key,
 	const struct rhashtable_params params)
 {
@@ -537,8 +528,6 @@
 	struct rhash_head *he;
 	unsigned int hash;
 
-	rcu_read_lock();
-
 	tbl = rht_dereference_rcu(ht->tbl, ht);
 restart:
 	hash = rht_key_hashfn(ht, tbl, key, params);
@@ -547,8 +536,7 @@
 		    params.obj_cmpfn(&arg, rht_obj(ht, he)) :
 		    rhashtable_compare(&arg, rht_obj(ht, he)))
 			continue;
-		rcu_read_unlock();
-		return rht_obj(ht, he);
+		return he;
 	}
 
 	/* Ensure we see any new tables. */
@@ -557,13 +545,64 @@
 	tbl = rht_dereference_rcu(tbl->future_tbl, ht);
 	if (unlikely(tbl))
 		goto restart;
-	rcu_read_unlock();
 
 	return NULL;
 }
 
-/* Internal function, please use rhashtable_insert_fast() instead */
-static inline int __rhashtable_insert_fast(
+/**
+ * rhashtable_lookup - search hash table
+ * @ht:		hash table
+ * @key:	the pointer to the key
+ * @params:	hash table parameters
+ *
+ * Computes the hash value for the key and traverses the bucket chain looking
+ * for a entry with an identical key. The first matching entry is returned.
+ *
+ * This must only be called under the RCU read lock.
+ *
+ * Returns the first entry on which the compare function returned true.
+ */
+static inline void *rhashtable_lookup(
+	struct rhashtable *ht, const void *key,
+	const struct rhashtable_params params)
+{
+	struct rhash_head *he = __rhashtable_lookup(ht, key, params);
+
+	return he ? rht_obj(ht, he) : NULL;
+}
+
+/**
+ * rhashtable_lookup_fast - search hash table, without RCU read lock
+ * @ht:		hash table
+ * @key:	the pointer to the key
+ * @params:	hash table parameters
+ *
+ * Computes the hash value for the key and traverses the bucket chain looking
+ * for a entry with an identical key. The first matching entry is returned.
+ *
+ * Only use this function when you have other mechanisms guaranteeing
+ * that the object won't go away after the RCU read lock is released.
+ *
+ * Returns the first entry on which the compare function returned true.
+ */
+static inline void *rhashtable_lookup_fast(
+	struct rhashtable *ht, const void *key,
+	const struct rhashtable_params params)
+{
+	void *obj;
+
+	rcu_read_lock();
+	obj = rhashtable_lookup(ht, key, params);
+	rcu_read_unlock();
+
+	return obj;
+}
+
+/* Internal function, please use rhashtable_insert_fast() instead. This
+ * function returns the existing element already in hashes in there is a clash,
+ * otherwise it returns an error via ERR_PTR().
+ */
+static inline void *__rhashtable_insert_fast(
 	struct rhashtable *ht, const void *key, struct rhash_head *obj,
 	const struct rhashtable_params params)
 {
@@ -576,6 +615,7 @@
 	spinlock_t *lock;
 	unsigned int elasticity;
 	unsigned int hash;
+	void *data = NULL;
 	int err;
 
 restart:
@@ -600,11 +640,14 @@
 
 	new_tbl = rht_dereference_rcu(tbl->future_tbl, ht);
 	if (unlikely(new_tbl)) {
-		tbl = rhashtable_insert_slow(ht, key, obj, new_tbl);
+		tbl = rhashtable_insert_slow(ht, key, obj, new_tbl, &data);
 		if (!IS_ERR_OR_NULL(tbl))
 			goto slow_path;
 
 		err = PTR_ERR(tbl);
+		if (err == -EEXIST)
+			err = 0;
+
 		goto out;
 	}
 
@@ -618,25 +661,25 @@
 		err = rhashtable_insert_rehash(ht, tbl);
 		rcu_read_unlock();
 		if (err)
-			return err;
+			return ERR_PTR(err);
 
 		goto restart;
 	}
 
-	err = -EEXIST;
+	err = 0;
 	elasticity = ht->elasticity;
 	rht_for_each(head, tbl, hash) {
 		if (key &&
 		    unlikely(!(params.obj_cmpfn ?
 			       params.obj_cmpfn(&arg, rht_obj(ht, head)) :
-			       rhashtable_compare(&arg, rht_obj(ht, head)))))
+			       rhashtable_compare(&arg, rht_obj(ht, head))))) {
+			data = rht_obj(ht, head);
 			goto out;
+		}
 		if (!--elasticity)
 			goto slow_path;
 	}
 
-	err = 0;
-
 	head = rht_dereference_bucket(tbl->buckets[hash], tbl, hash);
 
 	RCU_INIT_POINTER(obj->next, head);
@@ -651,7 +694,7 @@
 	spin_unlock_bh(lock);
 	rcu_read_unlock();
 
-	return err;
+	return err ? ERR_PTR(err) : data;
 }
 
 /**
@@ -674,7 +717,13 @@
 	struct rhashtable *ht, struct rhash_head *obj,
 	const struct rhashtable_params params)
 {
-	return __rhashtable_insert_fast(ht, NULL, obj, params);
+	void *ret;
+
+	ret = __rhashtable_insert_fast(ht, NULL, obj, params);
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	return ret == NULL ? 0 : -EEXIST;
 }
 
 /**
@@ -703,11 +752,15 @@
 	const struct rhashtable_params params)
 {
 	const char *key = rht_obj(ht, obj);
+	void *ret;
 
 	BUG_ON(ht->p.obj_hashfn);
 
-	return __rhashtable_insert_fast(ht, key + ht->p.key_offset, obj,
-					params);
+	ret = __rhashtable_insert_fast(ht, key + ht->p.key_offset, obj, params);
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	return ret == NULL ? 0 : -EEXIST;
 }
 
 /**
@@ -736,6 +789,32 @@
 	struct rhashtable *ht, const void *key, struct rhash_head *obj,
 	const struct rhashtable_params params)
 {
+	void *ret;
+
+	BUG_ON(!ht->p.obj_hashfn || !key);
+
+	ret = __rhashtable_insert_fast(ht, key, obj, params);
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	return ret == NULL ? 0 : -EEXIST;
+}
+
+/**
+ * rhashtable_lookup_get_insert_key - lookup and insert object into hash table
+ * @ht:		hash table
+ * @obj:	pointer to hash head inside object
+ * @params:	hash table parameters
+ * @data:	pointer to element data already in hashes
+ *
+ * Just like rhashtable_lookup_insert_key(), but this function returns the
+ * object if it exists, NULL if it does not and the insertion was successful,
+ * and an ERR_PTR otherwise.
+ */
+static inline void *rhashtable_lookup_get_insert_key(
+	struct rhashtable *ht, const void *key, struct rhash_head *obj,
+	const struct rhashtable_params params)
+{
 	BUG_ON(!ht->p.obj_hashfn || !key);
 
 	return __rhashtable_insert_fast(ht, key, obj, params);
--- linux-4.4.0.orig/include/linux/ring_buffer.h
+++ linux-4.4.0/include/linux/ring_buffer.h
@@ -125,7 +125,7 @@
 		    unsigned long *lost_events);
 
 struct ring_buffer_iter *
-ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu);
+ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu, gfp_t flags);
 void ring_buffer_read_prepare_sync(void);
 void ring_buffer_read_start(struct ring_buffer_iter *iter);
 void ring_buffer_read_finish(struct ring_buffer_iter *iter);
@@ -162,6 +162,7 @@
 void ring_buffer_record_off(struct ring_buffer *buffer);
 void ring_buffer_record_on(struct ring_buffer *buffer);
 int ring_buffer_record_is_on(struct ring_buffer *buffer);
+int ring_buffer_record_is_set_on(struct ring_buffer *buffer);
 void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu);
 void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu);
 
--- linux-4.4.0.orig/include/linux/rmap.h
+++ linux-4.4.0/include/linux/rmap.h
@@ -37,12 +37,15 @@
 	atomic_t refcount;
 
 	/*
-	 * Count of child anon_vmas and VMAs which points to this anon_vma.
+	 * Count of child anon_vmas. Equals to the count of all anon_vmas that
+	 * have ->parent pointing to this one, including itself.
 	 *
 	 * This counter is used for making decision about reusing anon_vma
 	 * instead of forking new one. See comments in function anon_vma_clone.
 	 */
-	unsigned degree;
+	unsigned long num_children;
+	/* Count of VMAs whose ->anon_vma pointer points to this object. */
+	unsigned long num_active_vmas;
 
 	struct anon_vma *parent;	/* Parent of this anon_vma */
 
@@ -108,20 +111,6 @@
 		__put_anon_vma(anon_vma);
 }
 
-static inline void vma_lock_anon_vma(struct vm_area_struct *vma)
-{
-	struct anon_vma *anon_vma = vma->anon_vma;
-	if (anon_vma)
-		down_write(&anon_vma->root->rwsem);
-}
-
-static inline void vma_unlock_anon_vma(struct vm_area_struct *vma)
-{
-	struct anon_vma *anon_vma = vma->anon_vma;
-	if (anon_vma)
-		up_write(&anon_vma->root->rwsem);
-}
-
 static inline void anon_vma_lock_write(struct anon_vma *anon_vma)
 {
 	down_write(&anon_vma->root->rwsem);
@@ -147,11 +136,19 @@
  * anon_vma helper functions.
  */
 void anon_vma_init(void);	/* create anon_vma_cachep */
-int  anon_vma_prepare(struct vm_area_struct *);
+int  __anon_vma_prepare(struct vm_area_struct *);
 void unlink_anon_vmas(struct vm_area_struct *);
 int anon_vma_clone(struct vm_area_struct *, struct vm_area_struct *);
 int anon_vma_fork(struct vm_area_struct *, struct vm_area_struct *);
 
+static inline int anon_vma_prepare(struct vm_area_struct *vma)
+{
+	if (likely(vma->anon_vma))
+		return 0;
+
+	return __anon_vma_prepare(vma);
+}
+
 static inline void anon_vma_merge(struct vm_area_struct *vma,
 				  struct vm_area_struct *next)
 {
--- linux-4.4.0.orig/include/linux/sched.h
+++ linux-4.4.0/include/linux/sched.h
@@ -801,6 +801,16 @@
 
 #define SIGNAL_UNKILLABLE	0x00000040 /* for init: ignore fatal signals */
 
+#define SIGNAL_STOP_MASK (SIGNAL_CLD_MASK | SIGNAL_STOP_STOPPED | \
+			  SIGNAL_STOP_CONTINUED)
+
+static inline void signal_set_stop_flags(struct signal_struct *sig,
+					 unsigned int flags)
+{
+	WARN_ON(sig->flags & (SIGNAL_GROUP_EXIT|SIGNAL_GROUP_COREDUMP));
+	sig->flags = (sig->flags & ~SIGNAL_STOP_MASK) | flags;
+}
+
 /* If true, all threads except ->group_exit_task have pending SIGKILL */
 static inline int signal_group_exit(const struct signal_struct *sig)
 {
@@ -830,6 +840,8 @@
 	unsigned long mq_bytes;	/* How many bytes can be allocated to mqueue? */
 #endif
 	unsigned long locked_shm; /* How many pages of mlocked shm ? */
+	unsigned long unix_inflight;	/* How many files in flight in unix sockets */
+	atomic_long_t pipe_bufs;  /* how many pages are allocated in pipe buffers */
 
 #ifdef CONFIG_KEYS
 	struct key *uid_keyring;	/* UID specific keyring */
@@ -1301,6 +1313,7 @@
 	u64 dl_deadline;	/* relative deadline of each instance	*/
 	u64 dl_period;		/* separation of two instances (period) */
 	u64 dl_bw;		/* dl_runtime / dl_deadline		*/
+	u64 dl_density;		/* dl_runtime / dl_deadline		*/
 
 	/*
 	 * Actual scheduling parameters. Initialized with the values above,
@@ -1376,6 +1389,13 @@
 };
 
 struct task_struct {
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+	/*
+	 * For reasons of header soup (see current_thread_info()), this
+	 * must be the first element of task_struct.
+	 */
+	struct thread_info thread_info;
+#endif
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	void *stack;
 	atomic_t usage;
@@ -1385,6 +1405,9 @@
 #ifdef CONFIG_SMP
 	struct llist_node wake_entry;
 	int on_cpu;
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+	unsigned int cpu;	/* current CPU */
+#endif
 	unsigned int wakee_flips;
 	unsigned long wakee_flip_decay_ts;
 	struct task_struct *last_wakee;
@@ -1441,7 +1464,7 @@
 
 	struct mm_struct *mm, *active_mm;
 	/* per-thread vma caching */
-	u32 vmacache_seqnum;
+	u64 vmacache_seqnum;
 	struct vm_area_struct *vmacache[VMACACHE_SIZE];
 #if defined(SPLIT_RSS_COUNTING)
 	struct task_rss_stat	rss_stat;
@@ -1473,6 +1496,10 @@
 #ifdef CONFIG_COMPAT_BRK
 	unsigned brk_randomized:1;
 #endif
+#ifdef CONFIG_CGROUPS
+	/* disallow userland-initiated cgroup migration */
+	unsigned no_cgroup_migration:1;
+#endif
 
 	unsigned long atomic_flags; /* Flags needing atomic access. */
 
@@ -1538,6 +1565,7 @@
 	struct list_head cpu_timers[3];
 
 /* process credentials */
+	const struct cred __rcu *ptracer_cred; /* Tracer's credentials at attach */
 	const struct cred __rcu *real_cred; /* objective and real subjective task
 					 * credentials (COW) */
 	const struct cred __rcu *cred;	/* effective (overridable) subjective task
@@ -1584,8 +1612,8 @@
 	struct seccomp seccomp;
 
 /* Thread group tracking */
-   	u32 parent_exec_id;
-   	u32 self_exec_id;
+	u64 parent_exec_id;
+	u64 self_exec_id;
 /* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed,
  * mempolicy */
 	spinlock_t alloc_lock;
@@ -1676,6 +1704,8 @@
 #endif
 	struct list_head pi_state_list;
 	struct futex_pi_state *pi_state_cache;
+	struct mutex futex_exit_mutex;
+	unsigned int futex_state;
 #endif
 #ifdef CONFIG_PERF_EVENTS
 	struct perf_event_context *perf_event_ctxp[perf_nr_task_contexts];
@@ -1842,7 +1872,7 @@
 extern void task_numa_fault(int last_node, int node, int pages, int flags);
 extern pid_t task_numa_group_id(struct task_struct *p);
 extern void set_numabalancing_state(bool enabled);
-extern void task_numa_free(struct task_struct *p);
+extern void task_numa_free(struct task_struct *p, bool final);
 extern bool should_numa_migrate_memory(struct task_struct *p, struct page *page,
 					int src_nid, int dst_cpu);
 #else
@@ -1857,7 +1887,7 @@
 static inline void set_numabalancing_state(bool enabled)
 {
 }
-static inline void task_numa_free(struct task_struct *p)
+static inline void task_numa_free(struct task_struct *p, bool final)
 {
 }
 static inline bool should_numa_migrate_memory(struct task_struct *p,
@@ -1932,31 +1962,8 @@
 	return tsk->tgid;
 }
 
-pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-
-static inline pid_t task_tgid_vnr(struct task_struct *tsk)
-{
-	return pid_vnr(task_tgid(tsk));
-}
-
 
 static inline int pid_alive(const struct task_struct *p);
-static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
-{
-	pid_t pid = 0;
-
-	rcu_read_lock();
-	if (pid_alive(tsk))
-		pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns);
-	rcu_read_unlock();
-
-	return pid;
-}
-
-static inline pid_t task_ppid_nr(const struct task_struct *tsk)
-{
-	return task_ppid_nr_ns(tsk, &init_pid_ns);
-}
 
 static inline pid_t task_pgrp_nr_ns(struct task_struct *tsk,
 					struct pid_namespace *ns)
@@ -1981,6 +1988,33 @@
 	return __task_pid_nr_ns(tsk, PIDTYPE_SID, NULL);
 }
 
+static inline pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
+{
+	return __task_pid_nr_ns(tsk, __PIDTYPE_TGID, ns);
+}
+
+static inline pid_t task_tgid_vnr(struct task_struct *tsk)
+{
+	return __task_pid_nr_ns(tsk, __PIDTYPE_TGID, NULL);
+}
+
+static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
+{
+	pid_t pid = 0;
+
+	rcu_read_lock();
+	if (pid_alive(tsk))
+		pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns);
+	rcu_read_unlock();
+
+	return pid;
+}
+
+static inline pid_t task_ppid_nr(const struct task_struct *tsk)
+{
+	return task_ppid_nr_ns(tsk, &init_pid_ns);
+}
+
 /* obsolete, do not use */
 static inline pid_t task_pgrp_nr(struct task_struct *tsk)
 {
@@ -2067,7 +2101,6 @@
  * Per process flags
  */
 #define PF_EXITING	0x00000004	/* getting shut down */
-#define PF_EXITPIDONE	0x00000008	/* pi exit done on shut down */
 #define PF_VCPU		0x00000010	/* I'm a virtual CPU */
 #define PF_WQ_WORKER	0x00000020	/* I'm a workqueue worker */
 #define PF_FORKNOEXEC	0x00000040	/* forked but didn't exec */
@@ -2145,7 +2178,10 @@
 #define PFA_NO_NEW_PRIVS 0	/* May not gain new privileges. */
 #define PFA_SPREAD_PAGE  1      /* Spread page cache over cpuset */
 #define PFA_SPREAD_SLAB  2      /* Spread some slab caches over cpuset */
-
+#define PFA_SPEC_SSB_DISABLE		3	/* Speculative Store Bypass disabled */
+#define PFA_SPEC_SSB_FORCE_DISABLE	4	/* Speculative Store Bypass force disabled*/
+#define PFA_SPEC_IB_DISABLE		6	/* Indirect branch speculation restricted */
+#define PFA_SPEC_IB_FORCE_DISABLE	7	/* Indirect branch speculation permanently restricted */
 
 #define TASK_PFA_TEST(name, func)					\
 	static inline bool task_##func(struct task_struct *p)		\
@@ -2168,6 +2204,20 @@
 TASK_PFA_SET(SPREAD_SLAB, spread_slab)
 TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab)
 
+TASK_PFA_TEST(SPEC_SSB_DISABLE, spec_ssb_disable)
+TASK_PFA_SET(SPEC_SSB_DISABLE, spec_ssb_disable)
+TASK_PFA_CLEAR(SPEC_SSB_DISABLE, spec_ssb_disable)
+
+TASK_PFA_TEST(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
+TASK_PFA_SET(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
+
+TASK_PFA_TEST(SPEC_IB_DISABLE, spec_ib_disable)
+TASK_PFA_SET(SPEC_IB_DISABLE, spec_ib_disable)
+TASK_PFA_CLEAR(SPEC_IB_DISABLE, spec_ib_disable)
+
+TASK_PFA_TEST(SPEC_IB_FORCE_DISABLE, spec_ib_force_disable)
+TASK_PFA_SET(SPEC_IB_FORCE_DISABLE, spec_ib_force_disable)
+
 /*
  * task->jobctl flags
  */
@@ -2400,7 +2450,9 @@
 void yield(void);
 
 union thread_union {
+#ifndef CONFIG_THREAD_INFO_IN_TASK
 	struct thread_info thread_info;
+#endif
 	unsigned long stack[THREAD_SIZE/sizeof(long)];
 };
 
@@ -2574,12 +2626,17 @@
 
 /* mmdrop drops the mm and the page tables */
 extern void __mmdrop(struct mm_struct *);
-static inline void mmdrop(struct mm_struct * mm)
+static inline void mmdrop(struct mm_struct *mm)
 {
 	if (unlikely(atomic_dec_and_test(&mm->mm_count)))
 		__mmdrop(mm);
 }
 
+static inline bool mmget_not_zero(struct mm_struct *mm)
+{
+	return atomic_inc_not_zero(&mm->mm_users);
+}
+
 /* mmput gets rid of the mappings and all user-space */
 extern void mmput(struct mm_struct *);
 /* Grab a reference to a task's mm, if it is not already going away */
@@ -2590,8 +2647,10 @@
  * succeeds.
  */
 extern struct mm_struct *mm_access(struct task_struct *task, unsigned int mode);
-/* Remove the current tasks stale references to the old mm_struct */
-extern void mm_release(struct task_struct *, struct mm_struct *);
+/* Remove the current tasks stale references to the old mm_struct on exit() */
+extern void exit_mm_release(struct task_struct *, struct mm_struct *);
+/* Remove the current tasks stale references to the old mm_struct on exec() */
+extern void exec_mm_release(struct task_struct *, struct mm_struct *);
 
 #ifdef CONFIG_HAVE_COPY_THREAD_TLS
 extern int copy_thread_tls(unsigned long, unsigned long, unsigned long,
@@ -2637,7 +2696,12 @@
 {
 	__set_task_comm(tsk, from, false);
 }
-extern char *get_task_comm(char *to, struct task_struct *tsk);
+
+extern char *__get_task_comm(char *to, size_t len, struct task_struct *tsk);
+#define get_task_comm(buf, tsk) ({			\
+	BUILD_BUG_ON(sizeof(buf) != TASK_COMM_LEN);	\
+	__get_task_comm(buf, sizeof(buf), tsk);		\
+})
 
 #ifdef CONFIG_SMP
 void scheduler_ipi(void);
@@ -2790,10 +2854,34 @@
 	cgroup_threadgroup_change_end(tsk);
 }
 
-#ifndef __HAVE_THREAD_FUNCTIONS
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+
+static inline struct thread_info *task_thread_info(struct task_struct *task)
+{
+	return &task->thread_info;
+}
+
+/*
+ * When accessing the stack of a non-current task that might exit, use
+ * try_get_task_stack() instead.  task_stack_page will return a pointer
+ * that could get freed out from under you.
+ */
+static inline void *task_stack_page(const struct task_struct *task)
+{
+	return task->stack;
+}
+
+#define setup_thread_stack(new,old)	do { } while(0)
+
+static inline unsigned long *end_of_stack(const struct task_struct *task)
+{
+	return task->stack;
+}
+
+#elif !defined(__HAVE_THREAD_FUNCTIONS)
 
 #define task_thread_info(task)	((struct thread_info *)(task)->stack)
-#define task_stack_page(task)	((task)->stack)
+#define task_stack_page(task)	((void *)(task)->stack)
 
 static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
 {
@@ -2820,6 +2908,14 @@
 }
 
 #endif
+
+static inline void *try_get_task_stack(struct task_struct *tsk)
+{
+	return task_stack_page(tsk);
+}
+
+static inline void put_task_stack(struct task_struct *tsk) {}
+
 #define task_stack_end_corrupted(task) \
 		(*(end_of_stack(task)) != STACK_END_MAGIC)
 
@@ -3085,7 +3181,11 @@
 
 static inline unsigned int task_cpu(const struct task_struct *p)
 {
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+	return p->cpu;
+#else
 	return task_thread_info(p)->cpu;
+#endif
 }
 
 static inline int task_node(const struct task_struct *p)
--- linux-4.4.0.orig/include/linux/sched/smt.h
+++ linux-4.4.0/include/linux/sched/smt.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SCHED_SMT_H
+#define _LINUX_SCHED_SMT_H
+
+#include <linux/static_key.h>
+
+#ifdef CONFIG_SCHED_SMT
+extern struct static_key_false sched_smt_present;
+
+static __always_inline bool sched_smt_active(void)
+{
+	return static_branch_likely(&sched_smt_present);
+}
+#else
+static inline bool sched_smt_active(void) { return false; }
+#endif
+
+void arch_smt_update(void);
+
+#endif
--- linux-4.4.0.orig/include/linux/sched/sysctl.h
+++ linux-4.4.0/include/linux/sched/sysctl.h
@@ -81,6 +81,7 @@
 extern unsigned int sysctl_sched_autogroup_enabled;
 #endif
 
+extern int sysctl_sched_rr_timeslice;
 extern int sched_rr_timeslice;
 
 extern int sched_rr_handler(struct ctl_table *table, int write,
--- linux-4.4.0.orig/include/linux/seccomp.h
+++ linux-4.4.0/include/linux/seccomp.h
@@ -3,7 +3,9 @@
 
 #include <uapi/linux/seccomp.h>
 
-#define SECCOMP_FILTER_FLAG_MASK	(SECCOMP_FILTER_FLAG_TSYNC)
+#define SECCOMP_FILTER_FLAG_MASK	(SECCOMP_FILTER_FLAG_TSYNC	| \
+					 SECCOMP_FILTER_FLAG_LOG	| \
+					 SECCOMP_FILTER_FLAG_SPEC_ALLOW)
 
 #ifdef CONFIG_SECCOMP
 
--- linux-4.4.0.orig/include/linux/security.h
+++ linux-4.4.0/include/linux/security.h
@@ -28,6 +28,7 @@
 #include <linux/err.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/fs.h>
 
 struct linux_binprm;
 struct cred;
@@ -84,6 +85,8 @@
 extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
 extern int cap_inode_need_killpriv(struct dentry *dentry);
 extern int cap_inode_killpriv(struct dentry *dentry);
+extern int cap_inode_getsecurity(const struct inode *inode, const char *name,
+				 void **buffer, bool alloc);
 extern int cap_mmap_addr(unsigned long addr);
 extern int cap_mmap_file(struct file *file, unsigned long reqprot,
 			 unsigned long prot, unsigned long flags);
@@ -1585,7 +1588,15 @@
 #endif /* CONFIG_AUDIT */
 
 #ifdef CONFIG_SECURITYFS
-
+extern int securityfs_pin_fs(void);
+extern int __securityfs_setup_d_inode(struct inode *dir, struct dentry *dentry,
+				      umode_t mode, void *data,
+				      const struct file_operations *fops,
+				      const struct inode_operations *iops);
+extern struct dentry *securityfs_create_dentry(const char *name, umode_t mode,
+				        struct dentry *parent, void *data,
+					const struct file_operations *fops,
+					const struct inode_operations *iops);
 extern struct dentry *securityfs_create_file(const char *name, umode_t mode,
 					     struct dentry *parent, void *data,
 					     const struct file_operations *fops);
@@ -1593,6 +1604,28 @@
 extern void securityfs_remove(struct dentry *dentry);
 
 #else /* CONFIG_SECURITYFS */
+static inline int securityfs_pin_fs(void)
+{
+	return -ENODEV;
+}
+
+static inline int __securityfs_setup_d_inode(struct inode *dir,
+					struct dentry *dentry,
+					umode_t mode, void *data,
+					const struct file_operations *fops,
+					const struct inode_operations *iops)
+{
+	return -ENODEV;
+}
+
+static inline struct dentry *securityfs_create_dentry(const char *name,
+					umode_t mode,
+					struct dentry *parent, void *data,
+					const struct file_operations *fops,
+					const struct inode_operations *iops)
+{
+	return ERR_PTR(-ENODEV);
+}
 
 static inline struct dentry *securityfs_create_dir(const char *name,
 						   struct dentry *parent)
--- linux-4.4.0.orig/include/linux/selection.h
+++ linux-4.4.0/include/linux/selection.h
@@ -12,8 +12,8 @@
 
 struct tty_struct;
 
-extern struct vc_data *sel_cons;
 struct tty_struct;
+struct vc_data;
 
 extern void clear_selection(void);
 extern int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty);
@@ -22,6 +22,8 @@
 extern int mouse_reporting(void);
 extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
 
+bool vc_is_sel(struct vc_data *vc);
+
 extern int console_blanked;
 
 extern unsigned char color_table[];
--- linux-4.4.0.orig/include/linux/sem.h
+++ linux-4.4.0/include/linux/sem.h
@@ -21,6 +21,7 @@
 	struct list_head	list_id;	/* undo requests on this array */
 	int			sem_nsems;	/* no. of semaphores in array */
 	int			complex_count;	/* pending complex operations */
+	bool			complex_mode;	/* no parallel simple ops */
 };
 
 #ifdef CONFIG_SYSVIPC
--- linux-4.4.0.orig/include/linux/seq_buf.h
+++ linux-4.4.0/include/linux/seq_buf.h
@@ -29,7 +29,7 @@
 }
 
 static inline void
-seq_buf_init(struct seq_buf *s, unsigned char *buf, unsigned int size)
+seq_buf_init(struct seq_buf *s, char *buf, unsigned int size)
 {
 	s->buffer = buf;
 	s->size = size;
--- linux-4.4.0.orig/include/linux/seq_file.h
+++ linux-4.4.0/include/linux/seq_file.h
@@ -7,13 +7,10 @@
 #include <linux/mutex.h>
 #include <linux/cpumask.h>
 #include <linux/nodemask.h>
+#include <linux/fs.h>
+#include <linux/cred.h>
 
 struct seq_operations;
-struct file;
-struct path;
-struct inode;
-struct dentry;
-struct user_namespace;
 
 struct seq_file {
 	char *buf;
@@ -27,9 +24,7 @@
 	struct mutex lock;
 	const struct seq_operations *op;
 	int poll_event;
-#ifdef CONFIG_USER_NS
-	struct user_namespace *user_ns;
-#endif
+	const struct file *file;
 	void *private;
 };
 
@@ -147,7 +142,7 @@
 static inline struct user_namespace *seq_user_ns(struct seq_file *seq)
 {
 #ifdef CONFIG_USER_NS
-	return seq->user_ns;
+	return seq->file->f_cred->user_ns;
 #else
 	extern struct user_namespace init_user_ns;
 	return &init_user_ns;
--- linux-4.4.0.orig/include/linux/seqlock.h
+++ linux-4.4.0/include/linux/seqlock.h
@@ -242,6 +242,13 @@
  * usual consistency guarantee. It is one wmb cheaper, because we can
  * collapse the two back-to-back wmb()s.
  *
+ * Note that, writes surrounding the barrier should be declared atomic (e.g.
+ * via WRITE_ONCE): a) to ensure the writes become visible to other threads
+ * atomically, avoiding compiler optimizations; b) to document which writes are
+ * meant to propagate to the reader critical section. This is necessary because
+ * neither writes before and after the barrier are enclosed in a seq-writer
+ * critical section that would ensure readers are aware of ongoing writes.
+ *
  *      seqcount_t seq;
  *      bool X = true, Y = false;
  *
@@ -261,11 +268,11 @@
  *
  *      void write(void)
  *      {
- *              Y = true;
+ *              WRITE_ONCE(Y, true);
  *
  *              raw_write_seqcount_barrier(seq);
  *
- *              X = false;
+ *              WRITE_ONCE(X, false);
  *      }
  */
 static inline void raw_write_seqcount_barrier(seqcount_t *s)
--- linux-4.4.0.orig/include/linux/serial_core.h
+++ linux-4.4.0/include/linux/serial_core.h
@@ -159,6 +159,7 @@
 	struct console		*cons;			/* struct console, if any */
 #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
 	unsigned long		sysrq;			/* sysrq timeout */
+	unsigned int		sysrq_ch;		/* char for sysrq */
 #endif
 
 	/* flags must be updated while holding port mutex */
@@ -344,7 +345,6 @@
 	int	(*setup)(struct earlycon_device *, const char *options);
 } __aligned(32);
 
-extern int setup_earlycon(char *buf);
 extern int of_setup_earlycon(unsigned long addr,
 			     int (*setup)(struct earlycon_device *, const char *));
 
@@ -357,6 +357,14 @@
 #define OF_EARLYCON_DECLARE(name, compat, fn)				\
 	_OF_DECLARE(earlycon, name, compat, fn, void *)
 
+#ifdef CONFIG_SERIAL_EARLYCON
+extern bool earlycon_init_is_deferred __initdata;
+int setup_earlycon(char *buf);
+#else
+static const bool earlycon_init_is_deferred;
+static inline int setup_earlycon(char *buf) { return 0; }
+#endif
+
 struct uart_port *uart_get_console(struct uart_port *ports, int nr,
 				   struct console *c);
 int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
@@ -440,8 +448,42 @@
 	}
 	return 0;
 }
+static inline int
+uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
+{
+	if (port->sysrq) {
+		if (ch && time_before(jiffies, port->sysrq)) {
+			port->sysrq_ch = ch;
+			port->sysrq = 0;
+			return 1;
+		}
+		port->sysrq = 0;
+	}
+	return 0;
+}
+static inline void
+uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
+{
+	int sysrq_ch;
+
+	sysrq_ch = port->sysrq_ch;
+	port->sysrq_ch = 0;
+
+	spin_unlock_irqrestore(&port->lock, irqflags);
+
+	if (sysrq_ch)
+		handle_sysrq(sysrq_ch);
+}
 #else
-#define uart_handle_sysrq_char(port,ch) ({ (void)port; 0; })
+static inline int
+uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) { return 0; }
+static inline int
+uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) { return 0; }
+static inline void
+uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
+{
+	spin_unlock_irqrestore(&port->lock, irqflags);
+}
 #endif
 
 /*
--- linux-4.4.0.orig/include/linux/serio.h
+++ linux-4.4.0/include/linux/serio.h
@@ -31,7 +31,8 @@
 
 	struct serio_device_id id;
 
-	spinlock_t lock;		/* protects critical sections from port's interrupt handler */
+	/* Protects critical sections from port's interrupt handler */
+	spinlock_t lock;
 
 	int (*write)(struct serio *, unsigned char);
 	int (*open)(struct serio *);
@@ -40,16 +41,29 @@
 	void (*stop)(struct serio *);
 
 	struct serio *parent;
-	struct list_head child_node;	/* Entry in parent->children list */
+	/* Entry in parent->children list */
+	struct list_head child_node;
 	struct list_head children;
-	unsigned int depth;		/* level of nesting in serio hierarchy */
+	/* Level of nesting in serio hierarchy */
+	unsigned int depth;
 
-	struct serio_driver *drv;	/* accessed from interrupt, must be protected by serio->lock and serio->sem */
-	struct mutex drv_mutex;		/* protects serio->drv so attributes can pin driver */
+	/*
+	 * serio->drv is accessed from interrupt handlers; when modifying
+	 * caller should acquire serio->drv_mutex and serio->lock.
+	 */
+	struct serio_driver *drv;
+	/* Protects serio->drv so attributes can pin current driver */
+	struct mutex drv_mutex;
 
 	struct device dev;
 
 	struct list_head node;
+
+	/*
+	 * For use by PS/2 layer when several ports share hardware and
+	 * may get indigestion when exposed to concurrent access (i8042).
+	 */
+	struct mutex *ps2_cmd_mutex;
 };
 #define to_serio_port(d)	container_of(d, struct serio, dev)
 
--- linux-4.4.0.orig/include/linux/sh_eth.h
+++ linux-4.4.0/include/linux/sh_eth.h
@@ -16,7 +16,6 @@
 	unsigned char mac_addr[ETH_ALEN];
 	unsigned no_ether_link:1;
 	unsigned ether_link_active_low:1;
-	unsigned needs_init:1;
 };
 
 #endif
--- linux-4.4.0.orig/include/linux/shmem_fs.h
+++ linux-4.4.0/include/linux/shmem_fs.h
@@ -15,10 +15,7 @@
 	unsigned int		seals;		/* shmem seals */
 	unsigned long		flags;
 	unsigned long		alloced;	/* data pages alloced to file */
-	union {
-		unsigned long	swapped;	/* subtotal assigned to swap */
-		char		*symlink;	/* unswappable short symlink */
-	};
+	unsigned long		swapped;	/* subtotal assigned to swap */
 	struct shared_policy	policy;		/* NUMA memory alloc policy */
 	struct list_head	swaplist;	/* chain of maybes on swap */
 	struct simple_xattrs	xattrs;		/* list of xattrs */
@@ -26,10 +23,13 @@
 };
 
 struct shmem_sb_info {
+	struct mutex idr_lock;
+	bool idr_nouse;
+	struct idr idr;		    /* manages inode-number */
 	unsigned long max_blocks;   /* How many blocks are allowed */
 	struct percpu_counter used_blocks;  /* How many are allocated */
-	unsigned long max_inodes;   /* How many inodes are allowed */
-	unsigned long free_inodes;  /* How many are left for allocation */
+	int max_inodes;		    /* How many inodes are allowed */
+	int free_inodes;	    /* How many are left for allocation */
 	spinlock_t stat_lock;	    /* Serialize shmem_sb_info changes */
 	kuid_t uid;		    /* Mount uid for root directory */
 	kgid_t gid;		    /* Mount gid for root directory */
--- linux-4.4.0.orig/include/linux/signal.h
+++ linux-4.4.0/include/linux/signal.h
@@ -28,6 +28,21 @@
 	sigset_t signal;
 };
 
+#ifndef HAVE_ARCH_COPY_SIGINFO
+
+#include <linux/string.h>
+
+static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
+{
+	if (from->si_code < 0)
+		memcpy(to, from, sizeof(*to));
+	else
+		/* _sigchld is currently the largest know union member */
+		memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
+}
+
+#endif
+
 /*
  * Define some primitives to manipulate sigset_t.
  */
@@ -82,6 +97,23 @@
 	}
 }
 
+static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2)
+{
+	switch (_NSIG_WORDS) {
+	case 4:
+		return	(set1->sig[3] == set2->sig[3]) &&
+			(set1->sig[2] == set2->sig[2]) &&
+			(set1->sig[1] == set2->sig[1]) &&
+			(set1->sig[0] == set2->sig[0]);
+	case 2:
+		return	(set1->sig[1] == set2->sig[1]) &&
+			(set1->sig[0] == set2->sig[0]);
+	case 1:
+		return	set1->sig[0] == set2->sig[0];
+	}
+	return 0;
+}
+
 #define sigmask(sig)	(1UL << ((sig) - 1))
 
 #ifndef __HAVE_ARCH_SIG_SETOPS
@@ -281,6 +313,9 @@
 extern void exit_signals(struct task_struct *tsk);
 extern void kernel_sigaction(int, __sighandler_t);
 
+#define SIG_KTHREAD ((__force __sighandler_t)2)
+#define SIG_KTHREAD_KERNEL ((__force __sighandler_t)3)
+
 static inline void allow_signal(int sig)
 {
 	/*
@@ -288,7 +323,17 @@
 	 * know it'll be handled, so that they don't get converted to
 	 * SIGKILL or just silently dropped.
 	 */
-	kernel_sigaction(sig, (__force __sighandler_t)2);
+	kernel_sigaction(sig, SIG_KTHREAD);
+}
+
+static inline void allow_kernel_signal(int sig)
+{
+	/*
+	 * Kernel threads handle their own signals. Let the signal code
+	 * know signals sent by the kernel will be handled, so that they
+	 * don't get silently dropped.
+	 */
+	kernel_sigaction(sig, SIG_KTHREAD_KERNEL);
 }
 
 static inline void disallow_signal(int sig)
--- linux-4.4.0.orig/include/linux/siphash.h
+++ linux-4.4.0/include/linux/siphash.h
@@ -0,0 +1,145 @@
+/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.
+ *
+ * SipHash: a fast short-input PRF
+ * https://131002.net/siphash/
+ *
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
+ */
+
+#ifndef _LINUX_SIPHASH_H
+#define _LINUX_SIPHASH_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#define SIPHASH_ALIGNMENT __alignof__(u64)
+typedef struct {
+	u64 key[2];
+} siphash_key_t;
+
+static inline bool siphash_key_is_zero(const siphash_key_t *key)
+{
+	return !(key->key[0] | key->key[1]);
+}
+
+u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key);
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key);
+#endif
+
+u64 siphash_1u64(const u64 a, const siphash_key_t *key);
+u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key);
+u64 siphash_3u64(const u64 a, const u64 b, const u64 c,
+		 const siphash_key_t *key);
+u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d,
+		 const siphash_key_t *key);
+u64 siphash_1u32(const u32 a, const siphash_key_t *key);
+u64 siphash_3u32(const u32 a, const u32 b, const u32 c,
+		 const siphash_key_t *key);
+
+static inline u64 siphash_2u32(const u32 a, const u32 b,
+			       const siphash_key_t *key)
+{
+	return siphash_1u64((u64)b << 32 | a, key);
+}
+static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c,
+			       const u32 d, const siphash_key_t *key)
+{
+	return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key);
+}
+
+
+static inline u64 ___siphash_aligned(const __le64 *data, size_t len,
+				     const siphash_key_t *key)
+{
+	if (__builtin_constant_p(len) && len == 4)
+		return siphash_1u32(le32_to_cpup((const __le32 *)data), key);
+	if (__builtin_constant_p(len) && len == 8)
+		return siphash_1u64(le64_to_cpu(data[0]), key);
+	if (__builtin_constant_p(len) && len == 16)
+		return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+				    key);
+	if (__builtin_constant_p(len) && len == 24)
+		return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+				    le64_to_cpu(data[2]), key);
+	if (__builtin_constant_p(len) && len == 32)
+		return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+				    le64_to_cpu(data[2]), le64_to_cpu(data[3]),
+				    key);
+	return __siphash_aligned(data, len, key);
+}
+
+/**
+ * siphash - compute 64-bit siphash PRF value
+ * @data: buffer to hash
+ * @size: size of @data
+ * @key: the siphash key
+ */
+static inline u64 siphash(const void *data, size_t len,
+			  const siphash_key_t *key)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
+		return __siphash_unaligned(data, len, key);
+#endif
+	return ___siphash_aligned(data, len, key);
+}
+
+#define HSIPHASH_ALIGNMENT __alignof__(unsigned long)
+typedef struct {
+	unsigned long key[2];
+} hsiphash_key_t;
+
+u32 __hsiphash_aligned(const void *data, size_t len,
+		       const hsiphash_key_t *key);
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len,
+			 const hsiphash_key_t *key);
+#endif
+
+u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key);
+u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key);
+u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c,
+		  const hsiphash_key_t *key);
+u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d,
+		  const hsiphash_key_t *key);
+
+static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len,
+				      const hsiphash_key_t *key)
+{
+	if (__builtin_constant_p(len) && len == 4)
+		return hsiphash_1u32(le32_to_cpu(data[0]), key);
+	if (__builtin_constant_p(len) && len == 8)
+		return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+				     key);
+	if (__builtin_constant_p(len) && len == 12)
+		return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+				     le32_to_cpu(data[2]), key);
+	if (__builtin_constant_p(len) && len == 16)
+		return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+				     le32_to_cpu(data[2]), le32_to_cpu(data[3]),
+				     key);
+	return __hsiphash_aligned(data, len, key);
+}
+
+/**
+ * hsiphash - compute 32-bit hsiphash PRF value
+ * @data: buffer to hash
+ * @size: size of @data
+ * @key: the hsiphash key
+ */
+static inline u32 hsiphash(const void *data, size_t len,
+			   const hsiphash_key_t *key)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
+		return __hsiphash_unaligned(data, len, key);
+#endif
+	return ___hsiphash_aligned(data, len, key);
+}
+
+#endif /* _LINUX_SIPHASH_H */
--- linux-4.4.0.orig/include/linux/skbuff.h
+++ linux-4.4.0/include/linux/skbuff.h
@@ -219,6 +219,7 @@
 #else
 #define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1)
 #endif
+extern int sysctl_max_skb_frags;
 
 typedef struct skb_frag_struct skb_frag_t;
 
@@ -513,6 +514,7 @@
  *	@hash: the packet hash
  *	@queue_mapping: Queue mapping for multiqueue devices
  *	@xmit_more: More SKBs are pending for this queue
+ *	@pfmemalloc: skbuff was allocated from PFMEMALLOC reserves
  *	@ndisc_nodetype: router type (from link layer)
  *	@ooo_okay: allow the mapping of a socket to a queue to be changed
  *	@l4_hash: indicate hash is a canonical 4-tuple hash over transport
@@ -521,6 +523,7 @@
  *	@wifi_acked_valid: wifi_acked was set
  *	@wifi_acked: whether frame was acked on wifi or not
  *	@no_fcs:  Request NIC to treat last 4 bytes as Ethernet FCS
+ *	@dst_pending_confirm: need to confirm neighbour
   *	@napi_id: id of the NAPI struct this skb came from
  *	@secmark: security marking
  *	@offload_fwd_mark: fwding offload mark
@@ -554,9 +557,11 @@
 				struct skb_mstamp skb_mstamp;
 			};
 		};
-		struct rb_node	rbnode; /* used in netem & tcp stack */
+		struct rb_node		rbnode; /* used in netem, ip4 defrag, and tcp stack */
 	};
+
 	struct sock		*sk;
+
 	struct net_device	*dev;
 
 	/*
@@ -593,8 +598,8 @@
 				fclone:2,
 				peeked:1,
 				head_frag:1,
-				xmit_more:1;
-	/* one bit hole */
+				xmit_more:1,
+				pfmemalloc:1;
 	kmemcheck_bitfield_end(flags1);
 
 	/* fields enclosed in headers_start/headers_end are copied
@@ -614,19 +619,18 @@
 
 	__u8			__pkt_type_offset[0];
 	__u8			pkt_type:3;
-	__u8			pfmemalloc:1;
 	__u8			ignore_df:1;
 	__u8			nfctinfo:3;
-
 	__u8			nf_trace:1;
+
 	__u8			ip_summed:2;
 	__u8			ooo_okay:1;
 	__u8			l4_hash:1;
 	__u8			sw_hash:1;
 	__u8			wifi_acked_valid:1;
 	__u8			wifi_acked:1;
-
 	__u8			no_fcs:1;
+
 	/* Indicates the inner headers are valid in the skbuff. */
 	__u8			encapsulation:1;
 	__u8			encap_hdr_csum:1;
@@ -634,11 +638,12 @@
 	__u8			csum_complete_sw:1;
 	__u8			csum_level:2;
 	__u8			csum_bad:1;
-
+	__u8			dst_pending_confirm:1;
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
 	__u8			ndisc_nodetype:2;
 #endif
 	__u8			ipvs_property:1;
+
 	__u8			inner_protocol_type:1;
 	__u8			remcsum_offload:1;
 	/* 3 or 5 bit hole */
@@ -864,6 +869,7 @@
 struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
 int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask);
 struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t priority);
+void skb_copy_header(struct sk_buff *new, const struct sk_buff *old);
 struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t priority);
 struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom,
 				   gfp_t gfp_mask, bool fclone);
@@ -878,10 +884,10 @@
 				     unsigned int headroom);
 struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom,
 				int newtailroom, gfp_t priority);
-int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
-			int offset, int len);
-int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset,
-		 int len);
+int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
+				     int offset, int len);
+int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg,
+			      int offset, int len);
 int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
 int skb_pad(struct sk_buff *skb, int pad);
 #define dev_kfree_skb(a)	consume_skb(a)
@@ -981,6 +987,7 @@
 }
 
 void __skb_get_hash(struct sk_buff *skb);
+u32 __skb_get_hash_symmetric(struct sk_buff *skb);
 u32 skb_get_poff(const struct sk_buff *skb);
 u32 __skb_get_poff(const struct sk_buff *skb, void *data,
 		   const struct flow_keys *keys, int hlen);
@@ -1066,7 +1073,8 @@
 	return skb->hash;
 }
 
-__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb);
+__u32 skb_get_hash_perturb(const struct sk_buff *skb,
+			   const siphash_key_t *perturb);
 
 static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
 {
@@ -1082,9 +1090,6 @@
 
 static inline void skb_sender_cpu_clear(struct sk_buff *skb)
 {
-#ifdef CONFIG_XPS
-	skb->sender_cpu = 0;
-#endif
 }
 
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
@@ -1434,6 +1439,18 @@
 }
 
 /**
+ *	skb_queue_len_lockless	- get queue length
+ *	@list_: list to measure
+ *
+ *	Return the length of an &sk_buff queue.
+ *	This variant can be used in lockless contexts.
+ */
+static inline __u32 skb_queue_len_lockless(const struct sk_buff_head *list_)
+{
+	return READ_ONCE(list_->qlen);
+}
+
+/**
  *	__skb_queue_head_init - initialize non-spinlock portions of sk_buff_head
  *	@list: queue to initialize
  *
@@ -1485,7 +1502,7 @@
 	newsk->next = next;
 	newsk->prev = prev;
 	next->prev  = prev->next = newsk;
-	list->qlen++;
+	WRITE_ONCE(list->qlen, list->qlen + 1);
 }
 
 static inline void __skb_queue_splice(const struct sk_buff_head *list,
@@ -1636,7 +1653,7 @@
 {
 	struct sk_buff *next, *prev;
 
-	list->qlen--;
+	WRITE_ONCE(list->qlen, list->qlen - 1);
 	next	   = skb->next;
 	prev	   = skb->prev;
 	skb->next  = skb->prev = NULL;
@@ -1810,6 +1827,15 @@
 	return tmp;
 }
 
+static inline unsigned char *skb_put_zero(struct sk_buff *skb, unsigned int len)
+{
+	unsigned char *tmp = skb_put(skb, len);
+
+	memset(tmp, 0, len);
+
+	return tmp;
+}
+
 unsigned char *skb_push(struct sk_buff *skb, unsigned int len);
 static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len)
 {
@@ -1907,6 +1933,30 @@
 	skb->tail += len;
 }
 
+/**
+ *	skb_tailroom_reserve - adjust reserved_tailroom
+ *	@skb: buffer to alter
+ *	@mtu: maximum amount of headlen permitted
+ *	@needed_tailroom: minimum amount of reserved_tailroom
+ *
+ *	Set reserved_tailroom so that headlen can be as large as possible but
+ *	not larger than mtu and tailroom cannot be smaller than
+ *	needed_tailroom.
+ *	The required headroom should already have been reserved before using
+ *	this function.
+ */
+static inline void skb_tailroom_reserve(struct sk_buff *skb, unsigned int mtu,
+					unsigned int needed_tailroom)
+{
+	SKB_LINEAR_ASSERT(skb);
+	if (mtu < skb_tailroom(skb) - needed_tailroom)
+		/* use at most mtu */
+		skb->reserved_tailroom = skb_tailroom(skb) - mtu;
+	else
+		/* use up to all available space */
+		skb->reserved_tailroom = needed_tailroom;
+}
+
 #define ENCAP_TYPE_ETHER	0
 #define ENCAP_TYPE_IPPROTO	1
 
@@ -2250,6 +2300,8 @@
 		kfree_skb(skb);
 }
 
+unsigned int skb_rbtree_purge(struct rb_root *root);
+
 void *netdev_alloc_frag(unsigned int fragsz);
 
 struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int length,
@@ -2317,6 +2369,9 @@
 {
 	return __napi_alloc_skb(napi, length, GFP_ATOMIC);
 }
+void napi_consume_skb(struct sk_buff *skb, int budget);
+
+void __kfree_skb_flush(void);
 
 /**
  * __dev_alloc_pages - allocate page for network Rx
@@ -2539,6 +2594,13 @@
 	       skb_headroom(skb) + len <= skb->hdr_len;
 }
 
+static inline int skb_try_make_writable(struct sk_buff *skb,
+					unsigned int write_len)
+{
+	return skb_cloned(skb) && !skb_clone_writable(skb, write_len) &&
+	       pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+}
+
 static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom,
 			    int cloned)
 {
@@ -2613,7 +2675,7 @@
  *	is untouched. Otherwise it is extended. Returns zero on
  *	success. The skb is freed on error.
  */
-static inline int skb_put_padto(struct sk_buff *skb, unsigned int len)
+static inline int __must_check skb_put_padto(struct sk_buff *skb, unsigned int len)
 {
 	unsigned int size = skb->len;
 
@@ -2723,6 +2785,43 @@
 
 unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len);
 
+static inline void skb_postpush_rcsum(struct sk_buff *skb,
+				      const void *start, unsigned int len)
+{
+	/* For performing the reverse operation to skb_postpull_rcsum(),
+	 * we can instead of ...
+	 *
+	 *   skb->csum = csum_add(skb->csum, csum_partial(start, len, 0));
+	 *
+	 * ... just use this equivalent version here to save a few
+	 * instructions. Feeding csum of 0 in csum_partial() and later
+	 * on adding skb->csum is equivalent to feed skb->csum in the
+	 * first place.
+	 */
+	if (skb->ip_summed == CHECKSUM_COMPLETE)
+		skb->csum = csum_partial(start, len, skb->csum);
+}
+
+/**
+ *	skb_push_rcsum - push skb and update receive checksum
+ *	@skb: buffer to update
+ *	@len: length of data pulled
+ *
+ *	This function performs an skb_push on the packet and updates
+ *	the CHECKSUM_COMPLETE checksum.  It should be used on
+ *	receive path processing instead of skb_push unless you know
+ *	that the checksum difference is zero (e.g., a valid IP header)
+ *	or you are setting ip_summed to CHECKSUM_NONE.
+ */
+static inline unsigned char *skb_push_rcsum(struct sk_buff *skb,
+					    unsigned int len)
+{
+	skb_push(skb, len);
+	skb_postpush_rcsum(skb, skb->data, len);
+	return skb->data;
+}
+
+int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len);
 /**
  *	pskb_trim_rcsum - trim received skb and update checksum
  *	@skb: buffer to trim
@@ -2730,17 +2829,22 @@
  *
  *	This is exactly the same as pskb_trim except that it ensures the
  *	checksum of received packets are still valid after the operation.
+ *	It can change skb pointers.
  */
 
 static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
 {
 	if (likely(len >= skb->len))
 		return 0;
-	if (skb->ip_summed == CHECKSUM_COMPLETE)
-		skb->ip_summed = CHECKSUM_NONE;
-	return __pskb_trim(skb, len);
+	return pskb_trim_rcsum_slow(skb, len);
 }
 
+#define rb_to_skb(rb) rb_entry_safe(rb, struct sk_buff, rbnode)
+#define skb_rb_first(root) rb_to_skb(rb_first(root))
+#define skb_rb_last(root)  rb_to_skb(rb_last(root))
+#define skb_rb_next(skb)   rb_to_skb(rb_next(&(skb)->rbnode))
+#define skb_rb_prev(skb)   rb_to_skb(rb_prev(&(skb)->rbnode))
+
 #define skb_queue_walk(queue, skb) \
 		for (skb = (queue)->next;					\
 		     skb != (struct sk_buff *)(queue);				\
@@ -2830,6 +2934,7 @@
 int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
 void skb_scrub_packet(struct sk_buff *skb, bool xnet);
 unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
+bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len);
 struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
 struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
 int skb_ensure_writable(struct sk_buff *skb, int write_len);
@@ -3334,6 +3439,13 @@
 #endif
 }
 
+static inline void ipvs_reset(struct sk_buff *skb)
+{
+#if IS_ENABLED(CONFIG_IP_VS)
+	skb->ipvs_property = 0;
+#endif
+}
+
 /* Note: This doesn't put any conntrack and bridge info in dst. */
 static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src,
 			     bool copy)
@@ -3426,6 +3538,16 @@
 	return skb->queue_mapping != 0;
 }
 
+static inline void skb_set_dst_pending_confirm(struct sk_buff *skb, u32 val)
+{
+	skb->dst_pending_confirm = val;
+}
+
+static inline bool skb_get_dst_pending_confirm(const struct sk_buff *skb)
+{
+	return skb->dst_pending_confirm != 0;
+}
+
 static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
 {
 #ifdef CONFIG_XFRM
@@ -3446,7 +3568,8 @@
 	int	encap_level;
 	__u16	csum_start;
 };
-#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb)
+#define SKB_SGO_CB_OFFSET	32
+#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_SGO_CB_OFFSET))
 
 static inline int skb_tnl_header_len(const struct sk_buff *inner_skb)
 {
@@ -3577,5 +3700,20 @@
 	return hdr_len + skb_gso_transport_seglen(skb);
 }
 
+/**
+ * skb_gso_mac_seglen - Return length of individual segments of a gso packet
+ *
+ * @skb: GSO skb
+ *
+ * skb_gso_mac_seglen is used to determine the real size of the
+ * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
+ * headers (TCP/UDP).
+ */
+static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
+{
+	unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
+	return hdr_len + skb_gso_transport_seglen(skb);
+}
+
 #endif	/* __KERNEL__ */
 #endif	/* _LINUX_SKBUFF_H */
--- linux-4.4.0.orig/include/linux/slab.h
+++ linux-4.4.0/include/linux/slab.h
@@ -203,7 +203,7 @@
  * (PAGE_SIZE*2).  Larger requests are passed to the page allocator.
  */
 #define KMALLOC_SHIFT_HIGH	(PAGE_SHIFT + 1)
-#define KMALLOC_SHIFT_MAX	(MAX_ORDER + PAGE_SHIFT)
+#define KMALLOC_SHIFT_MAX	(MAX_ORDER + PAGE_SHIFT - 1)
 #ifndef KMALLOC_SHIFT_LOW
 #define KMALLOC_SHIFT_LOW	3
 #endif
@@ -216,7 +216,7 @@
  * be allocated from the same page.
  */
 #define KMALLOC_SHIFT_HIGH	PAGE_SHIFT
-#define KMALLOC_SHIFT_MAX	30
+#define KMALLOC_SHIFT_MAX	(MAX_ORDER + PAGE_SHIFT - 1)
 #ifndef KMALLOC_SHIFT_LOW
 #define KMALLOC_SHIFT_LOW	3
 #endif
--- linux-4.4.0.orig/include/linux/slub_def.h
+++ linux-4.4.0/include/linux/slub_def.h
@@ -67,7 +67,8 @@
 	int size;		/* The size of an object including 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 */
+	/* Number of per cpu partial objects to keep around */
+	unsigned int cpu_partial;
 	struct kmem_cache_order_objects oo;
 
 	/* Allocation and freeing of slabs */
--- linux-4.4.0.orig/include/linux/smc91x.h
+++ linux-4.4.0/include/linux/smc91x.h
@@ -1,6 +1,16 @@
 #ifndef __SMC91X_H__
 #define __SMC91X_H__
 
+/*
+ * These bits define which access sizes a platform can support, rather
+ * than the maximal access size.  So, if your platform can do 16-bit
+ * and 32-bit accesses to the SMC91x device, but not 8-bit, set both
+ * SMC91X_USE_16BIT and SMC91X_USE_32BIT.
+ *
+ * The SMC91x driver requires at least one of SMC91X_USE_8BIT or
+ * SMC91X_USE_16BIT to be supported - just setting SMC91X_USE_32BIT is
+ * an invalid configuration.
+ */
 #define SMC91X_USE_8BIT (1 << 0)
 #define SMC91X_USE_16BIT (1 << 1)
 #define SMC91X_USE_32BIT (1 << 2)
--- linux-4.4.0.orig/include/linux/smpboot.h
+++ linux-4.4.0/include/linux/smpboot.h
@@ -30,7 +30,7 @@
  * @thread_comm:	The base name of the thread
  */
 struct smp_hotplug_thread {
-	struct task_struct __percpu	**store;
+	struct task_struct		* __percpu *store;
 	struct list_head		list;
 	int				(*thread_should_run)(unsigned int cpu);
 	void				(*thread_fn)(unsigned int cpu);
--- linux-4.4.0.orig/include/linux/sock_diag.h
+++ linux-4.4.0/include/linux/sock_diag.h
@@ -35,6 +35,9 @@
 {
 	switch (sk->sk_family) {
 	case AF_INET:
+		if (sk->sk_type == SOCK_RAW)
+			return SKNLGRP_NONE;
+
 		switch (sk->sk_protocol) {
 		case IPPROTO_TCP:
 			return SKNLGRP_INET_TCP_DESTROY;
@@ -44,6 +47,9 @@
 			return SKNLGRP_NONE;
 		}
 	case AF_INET6:
+		if (sk->sk_type == SOCK_RAW)
+			return SKNLGRP_NONE;
+
 		switch (sk->sk_protocol) {
 		case IPPROTO_TCP:
 			return SKNLGRP_INET6_TCP_DESTROY;
--- linux-4.4.0.orig/include/linux/spi/spi.h
+++ linux-4.4.0/include/linux/spi/spi.h
@@ -425,6 +425,12 @@
 #define SPI_MASTER_MUST_RX      BIT(3)		/* requires rx */
 #define SPI_MASTER_MUST_TX      BIT(4)		/* requires tx */
 
+	/* flag indicating this is a non-devres managed controller */
+	bool			devm_allocated;
+
+	/* Used to avoid adding the same CS twice */
+	struct mutex		add_lock;
+
 	/* lock and mutex for SPI bus locking */
 	spinlock_t		bus_lock_spinlock;
 	struct mutex		bus_lock_mutex;
@@ -568,6 +574,8 @@
 /* the spi driver core manages memory for the spi_master classdev */
 extern struct spi_master *
 spi_alloc_master(struct device *host, unsigned size);
+extern struct spi_master *
+devm_spi_alloc_master(struct device *dev, unsigned int size);
 
 extern int spi_register_master(struct spi_master *master);
 extern int devm_spi_register_master(struct device *dev,
--- linux-4.4.0.orig/include/linux/splice.h
+++ linux-4.4.0/include/linux/splice.h
@@ -83,4 +83,10 @@
 extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
 
 extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
+
+extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+			   loff_t *ppos, size_t len, unsigned int flags);
+extern long do_splice_to(struct file *in, loff_t *ppos,
+			 struct pipe_inode_info *pipe, size_t len,
+			 unsigned int flags);
 #endif
--- linux-4.4.0.orig/include/linux/string.h
+++ linux-4.4.0/include/linux/string.h
@@ -10,6 +10,7 @@
 
 extern char *strndup_user(const char __user *, long);
 extern void *memdup_user(const void __user *, size_t);
+extern void *memdup_user_nul(const void __user *, size_t);
 
 /*
  * Include machine specific inline routines
@@ -26,8 +27,12 @@
 size_t strlcpy(char *, const char *, size_t);
 #endif
 #ifndef __HAVE_ARCH_STRSCPY
-ssize_t __must_check strscpy(char *, const char *, size_t);
+ssize_t strscpy(char *, const char *, size_t);
 #endif
+
+/* Wraps calls to strscpy()/memset(), no arch specific code required */
+ssize_t strscpy_pad(char *dest, const char *src, size_t count);
+
 #ifndef __HAVE_ARCH_STRCAT
 extern char * strcat(char *, const char *);
 #endif
@@ -110,6 +115,9 @@
 #ifndef __HAVE_ARCH_MEMCMP
 extern int memcmp(const void *,const void *,__kernel_size_t);
 #endif
+#ifndef __HAVE_ARCH_BCMP
+extern int bcmp(const void *,const void *,__kernel_size_t);
+#endif
 #ifndef __HAVE_ARCH_MEMCHR
 extern void * memchr(const void *,int,__kernel_size_t);
 #endif
@@ -122,12 +130,17 @@
 extern const char *kstrdup_const(const char *s, gfp_t gfp);
 extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
 extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
 
 extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
 
 extern bool sysfs_streq(const char *s1, const char *s2);
-extern int strtobool(const char *s, bool *res);
+extern int kstrtobool(const char *s, bool *res);
+static inline int strtobool(const char *s, bool *res)
+{
+	return kstrtobool(s, res);
+}
 
 #ifdef CONFIG_BINARY_PRINTF
 int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
--- linux-4.4.0.orig/include/linux/sunrpc/clnt.h
+++ linux-4.4.0/include/linux/sunrpc/clnt.h
@@ -135,8 +135,6 @@
 #define RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT	(1UL << 9)
 
 struct rpc_clnt *rpc_create(struct rpc_create_args *args);
-struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
-					struct rpc_xprt *xprt);
 struct rpc_clnt	*rpc_bind_new_program(struct rpc_clnt *,
 				const struct rpc_program *, u32);
 void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
@@ -182,5 +180,6 @@
 int		rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
 
 const char *rpc_proc_name(const struct rpc_task *task);
+void rpc_cleanup_clids(void);
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */
--- linux-4.4.0.orig/include/linux/sunrpc/gss_api.h
+++ linux-4.4.0/include/linux/sunrpc/gss_api.h
@@ -81,6 +81,7 @@
 	u32	service;
 	char	*name;
 	char	*auth_domain_name;
+	struct auth_domain *domain;
 };
 
 /* Different mechanisms (e.g., krb5 or spkm3) may implement gss-api, and
--- linux-4.4.0.orig/include/linux/sunrpc/msg_prot.h
+++ linux-4.4.0/include/linux/sunrpc/msg_prot.h
@@ -158,9 +158,9 @@
 
 /*
  * Note that RFC 1833 does not put any size restrictions on the
- * netid string, but all currently defined netid's fit in 4 bytes.
+ * netid string, but all currently defined netid's fit in 5 bytes.
  */
-#define RPCBIND_MAXNETIDLEN	(4u)
+#define RPCBIND_MAXNETIDLEN	(5u)
 
 /*
  * Universal addresses are introduced in RFC 1833 and further spelled
--- linux-4.4.0.orig/include/linux/sunrpc/sched.h
+++ linux-4.4.0/include/linux/sunrpc/sched.h
@@ -181,7 +181,6 @@
 struct rpc_wait_queue {
 	spinlock_t		lock;
 	struct list_head	tasks[RPC_NR_PRIORITY];	/* task queue for each priority level */
-	pid_t			owner;			/* process id of last task serviced */
 	unsigned char		maxpriority;		/* maximum priority (0 if queue is not a priority queue) */
 	unsigned char		priority;		/* current priority */
 	unsigned char		nr;			/* # tasks remaining for cookie */
@@ -197,7 +196,6 @@
  * from a single cookie.  The aim is to improve
  * performance of NFS operations such as read/write.
  */
-#define RPC_BATCH_COUNT			16
 #define RPC_IS_PRIORITY(q)		((q)->maxpriority > 0)
 
 /*
--- linux-4.4.0.orig/include/linux/sunrpc/svc.h
+++ linux-4.4.0/include/linux/sunrpc/svc.h
@@ -290,9 +290,12 @@
 	struct svc_cacherep *	rq_cacherep;	/* cache info */
 	struct task_struct	*rq_task;	/* service thread */
 	spinlock_t		rq_lock;	/* per-request lock */
+	struct net		*rq_bc_net;	/* pointer to backchannel's
+						 * net namespace
+						 */
 };
 
-#define SVC_NET(svc_rqst)	(svc_rqst->rq_xprt->xpt_net)
+#define SVC_NET(rqst) (rqst->rq_xprt ? rqst->rq_xprt->xpt_net : rqst->rq_bc_net)
 
 /*
  * Rigorous type checking on sockaddr type conversions
--- linux-4.4.0.orig/include/linux/sunrpc/svcauth_gss.h
+++ linux-4.4.0/include/linux/sunrpc/svcauth_gss.h
@@ -20,7 +20,8 @@
 void gss_svc_shutdown(void);
 int gss_svc_init_net(struct net *net);
 void gss_svc_shutdown_net(struct net *net);
-int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
+struct auth_domain *svcauth_gss_register_pseudoflavor(u32 pseudoflavor,
+						      char *name);
 u32 svcauth_gss_flavor(struct auth_domain *dom);
 
 #endif /* __KERNEL__ */
--- linux-4.4.0.orig/include/linux/sunrpc/xdr.h
+++ linux-4.4.0/include/linux/sunrpc/xdr.h
@@ -23,8 +23,7 @@
 #define XDR_QUADLEN(l)		(((l) + 3) >> 2)
 
 /*
- * Generic opaque `network object.' At the kernel level, this type
- * is used only by lockd.
+ * Generic opaque `network object.'
  */
 #define XDR_MAX_NETOBJ		1024
 struct xdr_netobj {
--- linux-4.4.0.orig/include/linux/suspend.h
+++ linux-4.4.0/include/linux/suspend.h
@@ -377,6 +377,8 @@
 extern void swsusp_set_page_free(struct page *);
 extern void swsusp_unset_page_free(struct page *);
 extern unsigned long get_safe_page(gfp_t gfp_mask);
+extern asmlinkage int swsusp_arch_suspend(void);
+extern asmlinkage int swsusp_arch_resume(void);
 
 extern void hibernation_set_ops(const struct platform_hibernation_ops *ops);
 extern int hibernate(void);
--- linux-4.4.0.orig/include/linux/swap.h
+++ linux-4.4.0/include/linux/swap.h
@@ -135,9 +135,9 @@
 /*
  * Max bad pages in the new format..
  */
-#define __swapoffset(x) ((unsigned long)&((union swap_header *)0)->x)
 #define MAX_SWAP_BADPAGES \
-	((__swapoffset(magic.magic) - __swapoffset(info.badpages)) / sizeof(int))
+	((offsetof(union swap_header, magic.magic) - \
+	  offsetof(union swap_header, info.badpages)) / sizeof(int))
 
 enum {
 	SWP_USED	= (1 << 0),	/* is slot in swap_info[] used? */
@@ -266,6 +266,7 @@
 
 static inline void workingset_node_pages_dec(struct radix_tree_node *node)
 {
+	VM_WARN_ON_ONCE(!workingset_node_pages(node));
 	node->count--;
 }
 
@@ -281,6 +282,7 @@
 
 static inline void workingset_node_shadows_dec(struct radix_tree_node *node)
 {
+	VM_WARN_ON_ONCE(!workingset_node_shadows(node));
 	node->count -= 1U << RADIX_TREE_COUNT_SHIFT;
 }
 
@@ -316,6 +318,7 @@
 						struct vm_area_struct *vma);
 
 /* linux/mm/vmscan.c */
+extern unsigned long zone_reclaimable_pages(struct zone *zone);
 extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 					gfp_t gfp_mask, nodemask_t *mask);
 extern int __isolate_lru_page(struct page *page, isolate_mode_t mode);
--- linux-4.4.0.orig/include/linux/swapfile.h
+++ linux-4.4.0/include/linux/swapfile.h
@@ -9,5 +9,7 @@
 extern struct plist_head swap_active_head;
 extern struct swap_info_struct *swap_info[];
 extern int try_to_unuse(unsigned int, bool, unsigned long);
+extern unsigned long generic_max_swapfile_size(void);
+extern unsigned long max_swapfile_size(void);
 
 #endif /* _LINUX_SWAPFILE_H */
--- linux-4.4.0.orig/include/linux/swiotlb.h
+++ linux-4.4.0/include/linux/swiotlb.h
@@ -1,10 +1,13 @@
 #ifndef __LINUX_SWIOTLB_H
 #define __LINUX_SWIOTLB_H
 
+#include <linux/dma-direction.h>
+#include <linux/init.h>
 #include <linux/types.h>
 
 struct device;
 struct dma_attrs;
+struct page;
 struct scatterlist;
 
 extern int swiotlb_force;
--- linux-4.4.0.orig/include/linux/sysctl.h
+++ linux-4.4.0/include/linux/sysctl.h
@@ -41,6 +41,8 @@
 			 void __user *, size_t *, loff_t *);
 extern int proc_dointvec(struct ctl_table *, int,
 			 void __user *, size_t *, loff_t *);
+extern int proc_douintvec(struct ctl_table *, int,
+			 void __user *, size_t *, loff_t *);
 extern int proc_dointvec_minmax(struct ctl_table *, int,
 				void __user *, size_t *, loff_t *);
 extern int proc_dointvec_jiffies(struct ctl_table *, int,
--- linux-4.4.0.orig/include/linux/sysfs.h
+++ linux-4.4.0/include/linux/sysfs.h
@@ -116,6 +116,12 @@
 	.show	= _name##_show,						\
 }
 
+#define __ATTR_RO_MODE(_name, _mode) {					\
+	.attr	= { .name = __stringify(_name),				\
+		    .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },		\
+	.show	= _name##_show,						\
+}
+
 #define __ATTR_WO(_name) {						\
 	.attr	= { .name = __stringify(_name), .mode = S_IWUSR },	\
 	.store	= _name##_store,					\
@@ -232,6 +238,9 @@
 				   const struct attribute **attr);
 int __must_check sysfs_chmod_file(struct kobject *kobj,
 				  const struct attribute *attr, umode_t mode);
+struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
+						  const struct attribute *attr);
+void sysfs_unbreak_active_protection(struct kernfs_node *kn);
 void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
 			  const void *ns);
 bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr);
@@ -291,6 +300,11 @@
 	return kernfs_enable_ns(kn);
 }
 
+__printf(2, 3)
+int sysfs_emit(char *buf, const char *fmt, ...);
+__printf(3, 4)
+int sysfs_emit_at(char *buf, int at, const char *fmt, ...);
+
 #else /* CONFIG_SYSFS */
 
 static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
@@ -345,6 +359,17 @@
 	return 0;
 }
 
+static inline struct kernfs_node *
+sysfs_break_active_protection(struct kobject *kobj,
+			      const struct attribute *attr)
+{
+	return NULL;
+}
+
+static inline void sysfs_unbreak_active_protection(struct kernfs_node *kn)
+{
+}
+
 static inline void sysfs_remove_file_ns(struct kobject *kobj,
 					const struct attribute *attr,
 					const void *ns)
@@ -486,6 +511,17 @@
 {
 }
 
+__printf(2, 3)
+static inline int sysfs_emit(char *buf, const char *fmt, ...)
+{
+	return 0;
+}
+
+__printf(3, 4)
+static inline int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
+{
+	return 0;
+}
 #endif /* CONFIG_SYSFS */
 
 static inline int __must_check sysfs_create_file(struct kobject *kobj,
--- linux-4.4.0.orig/include/linux/tc.h
+++ linux-4.4.0/include/linux/tc.h
@@ -84,6 +84,7 @@
 					   device. */
 	struct device	dev;		/* Generic device interface. */
 	struct resource	resource;	/* Address space of this device. */
+	u64		dma_mask;	/* DMA addressable range. */
 	char		vendor[9];
 	char		name[9];
 	char		firmware[9];
--- linux-4.4.0.orig/include/linux/tcp.h
+++ linux-4.4.0/include/linux/tcp.h
@@ -29,9 +29,14 @@
 	return (struct tcphdr *)skb_transport_header(skb);
 }
 
+static inline unsigned int __tcp_hdrlen(const struct tcphdr *th)
+{
+	return th->doff * 4;
+}
+
 static inline unsigned int tcp_hdrlen(const struct sk_buff *skb)
 {
-	return tcp_hdr(skb)->doff * 4;
+	return __tcp_hdrlen(tcp_hdr(skb));
 }
 
 static inline struct tcphdr *inner_tcp_hdr(const struct sk_buff *skb)
@@ -56,8 +61,13 @@
 
 /* TCP Fast Open Cookie as stored in memory */
 struct tcp_fastopen_cookie {
+	union {
+		u8	val[TCP_FASTOPEN_COOKIE_MAX];
+#if IS_ENABLED(CONFIG_IPV6)
+		struct in6_addr addr;
+#endif
+	};
 	s8	len;
-	u8	val[TCP_FASTOPEN_COOKIE_MAX];
 	bool	exp;	/* In RFC6994 experimental option format */
 };
 
@@ -201,7 +211,8 @@
 		u8 reord;    /* reordering detected */
 	} rack;
 	u16	advmss;		/* Advertised MSS			*/
-	u8	unused;
+	u8	tlp_retrans:1,	/* TLP is a retransmission */
+		unused_1:7;
 	u8	nonagle     : 4,/* Disable Nagle algorithm?             */
 		thin_lto    : 1,/* Use linear timeouts for thin streams */
 		thin_dupack : 1,/* Fast retransmit on first dupack      */
@@ -215,7 +226,7 @@
 		syn_data_acked:1,/* data in SYN is acked by SYN-ACK */
 		save_syn:1,	/* Save headers of SYN packet */
 		is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */
-	u32	tlp_high_seq;	/* snd_nxt at the time of TLP retransmit. */
+	u32	tlp_high_seq;	/* snd_nxt at the time of TLP */
 
 /* RTT measurement */
 	u32	srtt_us;	/* smoothed round trip time << 3 in usecs */
@@ -269,10 +280,9 @@
 	struct sk_buff* lost_skb_hint;
 	struct sk_buff *retransmit_skb_hint;
 
-	/* OOO segments go in this list. Note that socket lock must be held,
-	 * as we do not use sk_buff_head lock.
-	 */
-	struct sk_buff_head	out_of_order_queue;
+	/* OOO segments go in this rbtree. Socket lock must be held. */
+	struct rb_root	out_of_order_queue;
+	struct sk_buff	*ooo_last_skb; /* cache rb_last(out_of_order_queue) */
 
 	/* SACKs data, these 2 need to be together (see tcp_options_write) */
 	struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
@@ -314,7 +324,7 @@
 
 /* Receiver queue space */
 	struct {
-		int	space;
+		u32	space;
 		u32	seq;
 		u32	time;
 	} rcvq_space;
@@ -410,4 +420,7 @@
 	tp->saved_syn = NULL;
 }
 
+int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from, int pcount,
+		  int shiftlen);
+
 #endif	/* _LINUX_TCP_H */
--- linux-4.4.0.orig/include/linux/thermal.h
+++ linux-4.4.0/include/linux/thermal.h
@@ -43,6 +43,9 @@
 /* Default weight of a bound cooling device */
 #define THERMAL_WEIGHT_DEFAULT 0
 
+/* use value, which < 0K, to indicate an invalid/uninitialized temperature */
+#define THERMAL_TEMP_INVALID	-274000
+
 /* Unit conversion macros */
 #define DECI_KELVIN_TO_CELSIUS(t)	({			\
 	long _t = (t);						\
@@ -153,6 +156,7 @@
  * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
  * @devdata:	private pointer for device private data
  * @trips:	number of trip points the thermal zone supports
+ * @trips_disabled;	bitmap for disabled trips
  * @passive_delay:	number of milliseconds to wait between polls when
  *			performing passive cooling.
  * @polling_delay:	number of milliseconds to wait between polls when
@@ -167,6 +171,7 @@
  * @forced_passive:	If > 0, temperature at which to switch on all ACPI
  *			processor cooling devices.  Currently only used by the
  *			step-wise governor.
+ * @need_update:	if equals 1, thermal_zone_device_update needs to be invoked.
  * @ops:	operations this &thermal_zone_device supports
  * @tzp:	thermal zone parameters
  * @governor:	pointer to the governor for this thermal zone
@@ -187,6 +192,7 @@
 	struct thermal_attr *trip_hyst_attrs;
 	void *devdata;
 	int trips;
+	unsigned long trips_disabled;	/* bitmap for disabled trips */
 	int passive_delay;
 	int polling_delay;
 	int temperature;
@@ -194,6 +200,7 @@
 	int emul_temperature;
 	int passive;
 	unsigned int forced_passive;
+	atomic_t need_update;
 	struct thermal_zone_device_ops *ops;
 	struct thermal_zone_params *tzp;
 	struct thermal_governor *governor;
--- linux-4.4.0.orig/include/linux/thread_info.h
+++ linux-4.4.0/include/linux/thread_info.h
@@ -13,6 +13,10 @@
 struct timespec;
 struct compat_timespec;
 
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+#define current_thread_info() ((struct thread_info *)current)
+#endif
+
 /*
  * System call restart block.
  */
@@ -55,11 +59,7 @@
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_DEBUG_STACK_USAGE
-# define THREADINFO_GFP		(GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO)
-#else
-# define THREADINFO_GFP		(GFP_KERNEL | __GFP_NOTRACK)
-#endif
+#define THREADINFO_GFP		(GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO)
 
 /*
  * flag set/clear/test wrappers
--- linux-4.4.0.orig/include/linux/time.h
+++ linux-4.4.0/include/linux/time.h
@@ -125,6 +125,32 @@
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 
+/*
+ * Validates if a timespec/timeval used to inject a time offset is valid.
+ * Offsets can be postive or negative. The value of the timeval/timespec
+ * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
+ * always be non-negative.
+ */
+static inline bool timeval_inject_offset_valid(const struct timeval *tv)
+{
+	/* We don't check the tv_sec as it can be positive or negative */
+
+	/* Can't have more microseconds then a second */
+	if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+		return false;
+	return true;
+}
+
+static inline bool timespec_inject_offset_valid(const struct timespec *ts)
+{
+	/* We don't check the tv_sec as it can be positive or negative */
+
+	/* Can't have more nanoseconds then a second */
+	if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
+		return false;
+	return true;
+}
+
 #define CURRENT_TIME		(current_kernel_time())
 #define CURRENT_TIME_SEC	((struct timespec) { get_seconds(), 0 })
 
@@ -236,4 +262,16 @@
 	a->tv_nsec = ns;
 }
 
+/**
+ * time_between32 - check if a 32-bit timestamp is within a given time range
+ * @t:	the time which may be within [l,h]
+ * @l:	the lower bound of the range
+ * @h:	the higher bound of the range
+ *
+ * time_before32(t, l, h) returns true if @l <= @t <= @h. All operands are
+ * treated as 32-bit integers.
+ *
+ * Equivalent to !(time_before32(@t, @l) || time_after32(@t, @h)).
+ */
+#define time_between32(t, l, h) ((u32)(h) - (u32)(l) >= (u32)(t) - (u32)(l))
 #endif
--- linux-4.4.0.orig/include/linux/time64.h
+++ linux-4.4.0/include/linux/time64.h
@@ -197,6 +197,10 @@
  */
 static inline s64 timespec64_to_ns(const struct timespec64 *ts)
 {
+	/* Prevent multiplication overflow */
+	if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX)
+		return KTIME_MAX;
+
 	return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
 }
 
--- linux-4.4.0.orig/include/linux/timekeeper_internal.h
+++ linux-4.4.0/include/linux/timekeeper_internal.h
@@ -29,7 +29,6 @@
  */
 struct tk_read_base {
 	struct clocksource	*clock;
-	cycle_t			(*read)(struct clocksource *cs);
 	cycle_t			mask;
 	cycle_t			cycle_last;
 	u32			mult;
@@ -50,6 +49,7 @@
  * @offs_tai:		Offset clock monotonic -> clock tai
  * @tai_offset:		The current UTC to TAI offset in seconds
  * @clock_was_set_seq:	The sequence number of clock was set events
+ * @cs_was_changed_seq:	The sequence number of clocksource change events
  * @next_leap_ktime:	CLOCK_MONOTONIC time value of a pending leap-second
  * @raw_time:		Monotonic raw base time in timespec64 format
  * @cycle_interval:	Number of clock cycles in one NTP interval
@@ -57,7 +57,7 @@
  *			interval.
  * @xtime_remainder:	Shifted nano seconds left over when rounding
  *			@cycle_interval
- * @raw_interval:	Raw nano seconds accumulated per NTP interval.
+ * @raw_interval:	Shifted raw nano seconds accumulated per NTP interval.
  * @ntp_error:		Difference between accumulated time and NTP time in ntp
  *			shifted nano seconds.
  * @ntp_error_shift:	Shift conversion between clock shifted nano seconds and
@@ -91,6 +91,7 @@
 	ktime_t			offs_tai;
 	s32			tai_offset;
 	unsigned int		clock_was_set_seq;
+	u8			cs_was_changed_seq;
 	ktime_t			next_leap_ktime;
 	struct timespec64	raw_time;
 
@@ -98,7 +99,7 @@
 	cycle_t			cycle_interval;
 	u64			xtime_interval;
 	s64			xtime_remainder;
-	u32			raw_interval;
+	u64			raw_interval;
 	/* The ntp_tick_length() value currently being used.
 	 * This cached copy ensures we consistently apply the tick
 	 * length for an entire tick, as ntp_tick_length may change
--- linux-4.4.0.orig/include/linux/timekeeping.h
+++ linux-4.4.0/include/linux/timekeeping.h
@@ -267,6 +267,64 @@
 				        struct timespec64 *ts_real);
 
 /*
+ * struct system_time_snapshot - simultaneous raw/real time capture with
+ *	counter value
+ * @cycles:	Clocksource counter value to produce the system times
+ * @real:	Realtime system time
+ * @raw:	Monotonic raw system time
+ * @clock_was_set_seq:	The sequence number of clock was set events
+ * @cs_was_changed_seq:	The sequence number of clocksource change events
+ */
+struct system_time_snapshot {
+	cycle_t		cycles;
+	ktime_t		real;
+	ktime_t		raw;
+	unsigned int	clock_was_set_seq;
+	u8		cs_was_changed_seq;
+};
+
+/*
+ * struct system_device_crosststamp - system/device cross-timestamp
+ *	(syncronized capture)
+ * @device:		Device time
+ * @sys_realtime:	Realtime simultaneous with device time
+ * @sys_monoraw:	Monotonic raw simultaneous with device time
+ */
+struct system_device_crosststamp {
+	ktime_t device;
+	ktime_t sys_realtime;
+	ktime_t sys_monoraw;
+};
+
+/*
+ * struct system_counterval_t - system counter value with the pointer to the
+ *	corresponding clocksource
+ * @cycles:	System counter value
+ * @cs:		Clocksource corresponding to system counter value. Used by
+ *	timekeeping code to verify comparibility of two cycle values
+ */
+struct system_counterval_t {
+	cycle_t			cycles;
+	struct clocksource	*cs;
+};
+
+/*
+ * Get cross timestamp between system clock and device clock
+ */
+extern int get_device_system_crosststamp(
+			int (*get_time_fn)(ktime_t *device_time,
+				struct system_counterval_t *system_counterval,
+				void *ctx),
+			void *ctx,
+			struct system_time_snapshot *history,
+			struct system_device_crosststamp *xtstamp);
+
+/*
+ * Simultaneously snapshot realtime and monotonic raw clocks
+ */
+extern void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot);
+
+/*
  * Persistent clock related interfaces
  */
 extern int persistent_clock_is_local;
--- linux-4.4.0.orig/include/linux/timer.h
+++ linux-4.4.0/include/linux/timer.h
@@ -21,11 +21,6 @@
 	u32			flags;
 	int			slack;
 
-#ifdef CONFIG_TIMER_STATS
-	int			start_pid;
-	void			*start_site;
-	char			start_comm[16];
-#endif
 #ifdef CONFIG_LOCKDEP
 	struct lockdep_map	lockdep_map;
 #endif
@@ -150,6 +145,31 @@
 #define setup_deferrable_timer_on_stack(timer, fn, data)		\
 	__setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE)
 
+#define TIMER_DATA_TYPE		unsigned long
+#define TIMER_FUNC_TYPE		void (*)(TIMER_DATA_TYPE)
+
+#ifndef CONFIG_LOCKDEP
+static inline void timer_setup(struct timer_list *timer,
+			       void (*callback)(struct timer_list *),
+			       unsigned int flags)
+{
+	__setup_timer(timer, (TIMER_FUNC_TYPE)callback,
+		      (TIMER_DATA_TYPE)timer, flags);
+}
+#else
+/*
+ * Under LOCKDEP, the timer lock_class_key (set up in __init_timer) needs
+ * to be tied to the caller's context, so an inline (above) won't work. We
+ * do want to keep the inline for argument type checking, though.
+ */
+# define timer_setup(timer, callback, flags)				\
+		__setup_timer(timer, (TIMER_FUNC_TYPE)callback,		\
+			      (TIMER_DATA_TYPE)timer, flags)
+#endif
+
+#define from_timer(var, callback_timer, timer_fieldname) \
+	container_of(callback_timer, typeof(*var), timer_fieldname)
+
 /**
  * timer_pending - is a timer pending?
  * @timer: the timer in question
@@ -181,46 +201,6 @@
  */
 #define NEXT_TIMER_MAX_DELTA	((1UL << 30) - 1)
 
-/*
- * Timer-statistics info:
- */
-#ifdef CONFIG_TIMER_STATS
-
-extern int timer_stats_active;
-
-extern void init_timer_stats(void);
-
-extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
-				     void *timerf, char *comm, u32 flags);
-
-extern void __timer_stats_timer_set_start_info(struct timer_list *timer,
-					       void *addr);
-
-static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
-{
-	if (likely(!timer_stats_active))
-		return;
-	__timer_stats_timer_set_start_info(timer, __builtin_return_address(0));
-}
-
-static inline void timer_stats_timer_clear_start_info(struct timer_list *timer)
-{
-	timer->start_site = NULL;
-}
-#else
-static inline void init_timer_stats(void)
-{
-}
-
-static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
-{
-}
-
-static inline void timer_stats_timer_clear_start_info(struct timer_list *timer)
-{
-}
-#endif
-
 extern void add_timer(struct timer_list *timer);
 
 extern int try_to_del_timer_sync(struct timer_list *timer);
--- linux-4.4.0.orig/include/linux/timerqueue.h
+++ linux-4.4.0/include/linux/timerqueue.h
@@ -11,8 +11,7 @@
 };
 
 struct timerqueue_head {
-	struct rb_root head;
-	struct timerqueue_node *next;
+	struct rb_root_cached rb_root;
 };
 
 
@@ -28,13 +27,14 @@
  *
  * @head: head of timerqueue
  *
- * Returns a pointer to the timer node that has the
- * earliest expiration time.
+ * Returns a pointer to the timer node that has the earliest expiration time.
  */
 static inline
 struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head)
 {
-	return head->next;
+	struct rb_node *leftmost = rb_first_cached(&head->rb_root);
+
+	return rb_entry(leftmost, struct timerqueue_node, node);
 }
 
 static inline void timerqueue_init(struct timerqueue_node *node)
@@ -44,7 +44,6 @@
 
 static inline void timerqueue_init_head(struct timerqueue_head *head)
 {
-	head->head = RB_ROOT;
-	head->next = NULL;
+	head->rb_root = RB_ROOT_CACHED;
 }
 #endif /* _LINUX_TIMERQUEUE_H */
--- linux-4.4.0.orig/include/linux/trace_events.h
+++ linux-4.4.0/include/linux/trace_events.h
@@ -301,6 +301,7 @@
 	int				perf_refcount;
 	struct hlist_head __percpu	*perf_events;
 	struct bpf_prog			*prog;
+	struct perf_event		*bpf_prog_owner;
 
 	int	(*perf_perm)(struct trace_event_call *,
 			     struct perf_event *);
@@ -568,6 +569,8 @@
 	FILTER_DYN_STRING,
 	FILTER_PTR_STRING,
 	FILTER_TRACE_FN,
+	FILTER_COMM,
+	FILTER_CPU,
 };
 
 extern int trace_event_raw_init(struct trace_event_call *call);
--- linux-4.4.0.orig/include/linux/trace_seq.h
+++ linux-4.4.0/include/linux/trace_seq.h
@@ -11,7 +11,7 @@
  */
 
 struct trace_seq {
-	unsigned char		buffer[PAGE_SIZE];
+	char			buffer[PAGE_SIZE];
 	struct seq_buf		seq;
 	int			full;
 };
@@ -50,7 +50,7 @@
  * that is about to be written to and then return the result
  * of that write.
  */
-static inline unsigned char *
+static inline char *
 trace_seq_buffer_ptr(struct trace_seq *s)
 {
 	return s->buffer + seq_buf_used(&s->seq);
--- linux-4.4.0.orig/include/linux/tracepoint.h
+++ linux-4.4.0/include/linux/tracepoint.h
@@ -14,8 +14,10 @@
  * See the file COPYING for more details.
  */
 
+#include <linux/smp.h>
 #include <linux/errno.h>
 #include <linux/types.h>
+#include <linux/cpumask.h>
 #include <linux/rcupdate.h>
 #include <linux/static_key.h>
 
@@ -326,7 +328,7 @@
 		static const char *___tp_str __tracepoint_string = str; \
 		___tp_str;						\
 	})
-#define __tracepoint_string	__attribute__((section("__tracepoint_str")))
+#define __tracepoint_string	__attribute__((section("__tracepoint_str"), used))
 #else
 /*
  * tracepoint_string() is used to save the string address for userspace
@@ -352,15 +354,19 @@
  * "void *__data, proto" as the callback prototype.
  */
 #define DECLARE_TRACE_NOARGS(name)					\
-		__DECLARE_TRACE(name, void, , 1, void *__data, __data)
+	__DECLARE_TRACE(name, void, ,					\
+			cpu_online(raw_smp_processor_id()),		\
+			void *__data, __data)
 
 #define DECLARE_TRACE(name, proto, args)				\
-		__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), 1,	\
-				PARAMS(void *__data, proto),		\
-				PARAMS(__data, args))
+	__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args),		\
+			cpu_online(raw_smp_processor_id()),		\
+			PARAMS(void *__data, proto),			\
+			PARAMS(__data, args))
 
 #define DECLARE_TRACE_CONDITION(name, proto, args, cond)		\
-	__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), PARAMS(cond), \
+	__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args),		\
+			cpu_online(raw_smp_processor_id()) && (PARAMS(cond)), \
 			PARAMS(void *__data, proto),			\
 			PARAMS(__data, args))
 
--- linux-4.4.0.orig/include/linux/tty.h
+++ linux-4.4.0/include/linux/tty.h
@@ -64,7 +64,7 @@
 	int read;
 	int flags;
 	/* Data points here */
-	unsigned long data[0];
+	unsigned long data[];
 };
 
 /* Values for .flags field of tty_buffer */
@@ -280,6 +280,10 @@
 	struct termiox *termiox;	/* May be NULL for unsupported */
 	char name[64];
 	struct pid *pgrp;		/* Protected by ctrl lock */
+	/*
+	 * Writes protected by both ctrl lock and legacy mutex, readers must use
+	 * at least one of them.
+	 */
 	struct pid *session;
 	unsigned long flags;
 	int count;
@@ -338,11 +342,12 @@
 #define TTY_EXCLUSIVE 		3	/* Exclusive open mode */
 #define TTY_DEBUG 		4	/* Debugging */
 #define TTY_DO_WRITE_WAKEUP 	5	/* Call write_wakeup after queuing new */
-#define TTY_OTHER_DONE		6	/* Closed pty has completed input processing */
 #define TTY_LDISC_OPEN	 	11	/* Line discipline is open */
 #define TTY_PTY_LOCK 		16	/* pty private */
 #define TTY_NO_WRITE_SPLIT 	17	/* Preserve write boundaries to driver */
 #define TTY_HUPPED 		18	/* Post driver->hangup() */
+#define TTY_HUPPING		19	/* Hangup in progress */
+#define TTY_LDISC_CHANGING	20	/* Change pending - non-block IO */
 #define TTY_LDISC_HALTED	22	/* Line discipline is halted */
 
 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
@@ -362,6 +367,12 @@
 	smp_mb();
 }
 
+static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
+{
+	return file->f_flags & O_NONBLOCK ||
+		test_bit(TTY_LDISC_CHANGING, &tty->flags);
+}
+
 #ifdef CONFIG_TTY
 extern void console_init(void);
 extern void tty_kref_put(struct tty_struct *tty);
@@ -373,6 +384,9 @@
 extern struct tty_struct *get_current_tty(void);
 /* tty_io.c */
 extern int __init tty_init(void);
+extern const char *tty_name(const struct tty_struct *tty);
+extern int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout);
+extern void tty_ldisc_unlock(struct tty_struct *tty);
 #else
 static inline void console_init(void)
 { }
@@ -393,6 +407,8 @@
 /* tty_io.c */
 static inline int __init tty_init(void)
 { return 0; }
+static inline const char *tty_name(const struct tty_struct *tty)
+{ return "(none)"; }
 #endif
 
 extern void tty_write_flush(struct tty_struct *);
@@ -421,7 +437,6 @@
 
 extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
 			      const char *routine);
-extern const char *tty_name(const struct tty_struct *tty);
 extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
 extern int __tty_check_change(struct tty_struct *tty, int sig);
 extern int tty_check_change(struct tty_struct *tty);
@@ -469,6 +484,7 @@
 extern void tty_buffer_set_lock_subclass(struct tty_port *port);
 extern bool tty_buffer_restart_work(struct tty_port *port);
 extern bool tty_buffer_cancel_work(struct tty_port *port);
+extern void tty_buffer_flush_work(struct tty_port *port);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
 extern void tty_termios_encode_baud_rate(struct ktermios *termios,
@@ -498,7 +514,8 @@
 extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
 extern void tty_ldisc_deref(struct tty_ldisc *);
 extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *);
-extern void tty_ldisc_hangup(struct tty_struct *tty);
+extern void tty_ldisc_hangup(struct tty_struct *tty, bool reset);
+extern int tty_ldisc_reinit(struct tty_struct *tty, int disc);
 extern const struct file_operations tty_ldiscs_proc_fops;
 
 extern void tty_wakeup(struct tty_struct *tty);
@@ -580,10 +597,10 @@
 
 extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
-extern int tty_set_ldisc(struct tty_struct *tty, int ldisc);
+extern int tty_set_ldisc(struct tty_struct *tty, int disc);
 extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty);
 extern void tty_ldisc_release(struct tty_struct *tty);
-extern void tty_ldisc_init(struct tty_struct *tty);
+extern int __must_check tty_ldisc_init(struct tty_struct *tty);
 extern void tty_ldisc_deinit(struct tty_struct *tty);
 extern void tty_ldisc_begin(void);
 
@@ -594,7 +611,7 @@
 		count = ld->ops->receive_buf2(ld->tty, p, f, count);
 	else {
 		count = min_t(int, count, ld->tty->receive_room);
-		if (count)
+		if (count && ld->ops->receive_buf)
 			ld->ops->receive_buf(ld->tty, p, f, count);
 	}
 	return count;
@@ -654,6 +671,7 @@
 /* tty_mutex.c */
 /* functions for preparation of BKL removal */
 extern void __lockfunc tty_lock(struct tty_struct *tty);
+extern int  tty_lock_interruptible(struct tty_struct *tty);
 extern void __lockfunc tty_unlock(struct tty_struct *tty);
 extern void __lockfunc tty_lock_slave(struct tty_struct *tty);
 extern void __lockfunc tty_unlock_slave(struct tty_struct *tty);
--- linux-4.4.0.orig/include/linux/tty_flip.h
+++ linux-4.4.0/include/linux/tty_flip.h
@@ -12,6 +12,7 @@
 		unsigned char **chars, size_t size);
 extern void tty_flip_buffer_push(struct tty_port *port);
 void tty_schedule_flip(struct tty_port *port);
+int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag);
 
 static inline int tty_insert_flip_char(struct tty_port *port,
 					unsigned char ch, char flag)
@@ -26,7 +27,7 @@
 		*char_buf_ptr(tb, tb->used++) = ch;
 		return 1;
 	}
-	return tty_insert_flip_string_flags(port, &ch, &flag, 1);
+	return __tty_insert_flip_char(port, ch, flag);
 }
 
 static inline int tty_insert_flip_string(struct tty_port *port,
@@ -38,4 +39,7 @@
 extern void tty_buffer_lock_exclusive(struct tty_port *port);
 extern void tty_buffer_unlock_exclusive(struct tty_port *port);
 
+int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
+		const unsigned char *chars, size_t cnt);
+
 #endif /* _LINUX_TTY_FLIP_H */
--- linux-4.4.0.orig/include/linux/uaccess.h
+++ linux-4.4.0/include/linux/uaccess.h
@@ -2,6 +2,9 @@
 #define __LINUX_UACCESS_H__
 
 #include <linux/sched.h>
+
+#define uaccess_kernel() segment_eq(get_fs(), KERNEL_DS)
+
 #include <asm/uaccess.h>
 
 static __always_inline void pagefault_disabled_inc(void)
@@ -88,6 +91,17 @@
 extern long __probe_kernel_read(void *dst, const void *src, size_t size);
 
 /*
+ * probe_user_read(): safely attempt to read from a location in user space
+ * @dst: pointer to the buffer that shall take the data
+ * @src: address to read from
+ * @size: size of the data chunk
+ *
+ * Safely read from address @src to the buffer at @dst.  If a kernel fault
+ * happens, handle that and return -EFAULT.
+ */
+extern long probe_user_read(void *dst, const void __user *src, size_t size);
+
+/*
  * probe_kernel_write(): safely attempt to write to a location
  * @dst: address to write to
  * @src: pointer to the data that shall be written
@@ -99,7 +113,22 @@
 extern long notrace probe_kernel_write(void *dst, const void *src, size_t size);
 extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size);
 
+/*
+ * probe_user_write(): safely attempt to write to a location in user space
+ * @dst: address to write to
+ * @src: pointer to the data that shall be written
+ * @size: size of the data chunk
+ *
+ * Safely write to address @dst from the buffer at @src.  If a kernel fault
+ * happens, handle that and return -EFAULT.
+ */
+extern long notrace probe_user_write(void __user *dst, const void *src, size_t size);
+extern long notrace __probe_user_write(void __user *dst, const void *src, size_t size);
+
 extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count);
+extern long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
+				     long count);
+extern long strnlen_unsafe_user(const void __user *unsafe_addr, long count);
 
 /**
  * probe_kernel_address(): safely attempt to read from a location
--- linux-4.4.0.orig/include/linux/ucs2_string.h
+++ linux-4.4.0/include/linux/ucs2_string.h
@@ -11,4 +11,8 @@
 unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength);
 int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len);
 
+unsigned long ucs2_utf8size(const ucs2_char_t *src);
+unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src,
+			   unsigned long maxlength);
+
 #endif /* _LINUX_UCS2_STRING_H_ */
--- linux-4.4.0.orig/include/linux/uidgid.h
+++ linux-4.4.0/include/linux/uidgid.h
@@ -117,6 +117,16 @@
 	return __kgid_val(gid) != (gid_t) -1;
 }
 
+static inline bool uid_valid_eq(kuid_t left, kuid_t right)
+{
+	return uid_eq(left, right) && uid_valid(left);
+}
+
+static inline bool gid_valid_eq(kgid_t left, kgid_t right)
+{
+	return gid_eq(left, right) && gid_valid(left);
+}
+
 #ifdef CONFIG_USER_NS
 
 extern kuid_t make_kuid(struct user_namespace *from, uid_t uid);
--- linux-4.4.0.orig/include/linux/uio.h
+++ linux-4.4.0/include/linux/uio.h
@@ -76,7 +76,7 @@
 		struct iov_iter *i, unsigned long offset, size_t bytes);
 void iov_iter_advance(struct iov_iter *i, size_t bytes);
 int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
-int iov_iter_fault_in_multipages_readable(struct iov_iter *i, size_t bytes);
+#define iov_iter_fault_in_multipages_readable iov_iter_fault_in_readable
 size_t iov_iter_single_seg_count(const struct iov_iter *i);
 size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
 			 struct iov_iter *i);
@@ -101,12 +101,12 @@
 
 const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags);
 
-static inline size_t iov_iter_count(struct iov_iter *i)
+static inline size_t iov_iter_count(const struct iov_iter *i)
 {
 	return i->count;
 }
 
-static inline bool iter_is_iovec(struct iov_iter *i)
+static inline bool iter_is_iovec(const struct iov_iter *i)
 {
 	return !(i->type & (ITER_BVEC | ITER_KVEC));
 }
--- linux-4.4.0.orig/include/linux/usb.h
+++ linux-4.4.0/include/linux/usb.h
@@ -50,6 +50,7 @@
  * struct usb_host_endpoint - host-side endpoint descriptor and queue
  * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
  * @ss_ep_comp: SuperSpeed companion descriptor for this endpoint
+ * @ssp_isoc_ep_comp: SuperSpeedPlus isoc companion descriptor for this endpoint
  * @urb_list: urbs queued to this endpoint; maintained by usbcore
  * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
  *	with one or more transfer descriptors (TDs) per urb
@@ -65,6 +66,7 @@
 struct usb_host_endpoint {
 	struct usb_endpoint_descriptor		desc;
 	struct usb_ss_ep_comp_descriptor	ss_ep_comp;
+	struct usb_ssp_isoc_ep_comp_descriptor	ssp_isoc_ep_comp;
 	struct list_head		urb_list;
 	void				*hcpriv;
 	struct ep_device		*ep_dev;	/* For sysfs info */
@@ -97,6 +99,76 @@
 	USB_INTERFACE_UNBINDING,
 };
 
+int __must_check
+usb_find_common_endpoints(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **bulk_in,
+		struct usb_endpoint_descriptor **bulk_out,
+		struct usb_endpoint_descriptor **int_in,
+		struct usb_endpoint_descriptor **int_out);
+
+int __must_check
+usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **bulk_in,
+		struct usb_endpoint_descriptor **bulk_out,
+		struct usb_endpoint_descriptor **int_in,
+		struct usb_endpoint_descriptor **int_out);
+
+static inline int __must_check
+usb_find_bulk_in_endpoint(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **bulk_in)
+{
+	return usb_find_common_endpoints(alt, bulk_in, NULL, NULL, NULL);
+}
+
+static inline int __must_check
+usb_find_bulk_out_endpoint(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **bulk_out)
+{
+	return usb_find_common_endpoints(alt, NULL, bulk_out, NULL, NULL);
+}
+
+static inline int __must_check
+usb_find_int_in_endpoint(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **int_in)
+{
+	return usb_find_common_endpoints(alt, NULL, NULL, int_in, NULL);
+}
+
+static inline int __must_check
+usb_find_int_out_endpoint(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **int_out)
+{
+	return usb_find_common_endpoints(alt, NULL, NULL, NULL, int_out);
+}
+
+static inline int __must_check
+usb_find_last_bulk_in_endpoint(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **bulk_in)
+{
+	return usb_find_common_endpoints_reverse(alt, bulk_in, NULL, NULL, NULL);
+}
+
+static inline int __must_check
+usb_find_last_bulk_out_endpoint(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **bulk_out)
+{
+	return usb_find_common_endpoints_reverse(alt, NULL, bulk_out, NULL, NULL);
+}
+
+static inline int __must_check
+usb_find_last_int_in_endpoint(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **int_in)
+{
+	return usb_find_common_endpoints_reverse(alt, NULL, NULL, int_in, NULL);
+}
+
+static inline int __must_check
+usb_find_last_int_out_endpoint(struct usb_host_interface *alt,
+		struct usb_endpoint_descriptor **int_out)
+{
+	return usb_find_common_endpoints_reverse(alt, NULL, NULL, NULL, int_out);
+}
+
 /**
  * struct usb_interface - what usb device drivers talk to
  * @altsetting: array of interface structures, one for each alternate
@@ -127,7 +199,6 @@
  * @dev: driver model's view of this device
  * @usb_dev: if an interface is bound to the USB major, this will point
  *	to the sysfs representation for that device.
- * @pm_usage_cnt: PM usage counter for this interface
  * @reset_ws: Used for scheduling resets from atomic context.
  * @resetting_device: USB core reset the device, so use alt setting 0 as
  *	current; needs bandwidth alloc after reset.
@@ -184,7 +255,6 @@
 
 	struct device dev;		/* interface specific device info */
 	struct device *usb_dev;
-	atomic_t pm_usage_cnt;		/* usage counter for autosuspend */
 	struct work_struct reset_ws;	/* for resets in atomic context */
 };
 #define	to_usb_interface(d) container_of(d, struct usb_interface, dev)
@@ -208,6 +278,11 @@
 #define USB_MAXINTERFACES	32
 #define USB_MAXIADS		(USB_MAXINTERFACES/2)
 
+bool usb_check_bulk_endpoints(
+		const struct usb_interface *intf, const u8 *ep_addrs);
+bool usb_check_int_endpoints(
+		const struct usb_interface *intf, const u8 *ep_addrs);
+
 /*
  * USB Resume Timer: Every Host controller driver should drive the resume
  * signalling on the bus for the amount of time defined by this macro.
@@ -330,14 +405,15 @@
 	struct usb_ss_cap_descriptor	*ss_cap;
 	struct usb_ssp_cap_descriptor	*ssp_cap;
 	struct usb_ss_container_id_descriptor	*ss_id;
+	struct usb_ptm_cap_descriptor	*ptm_cap;
 };
 
 int __usb_get_extra_descriptor(char *buffer, unsigned size,
-	unsigned char type, void **ptr);
+	unsigned char type, void **ptr, size_t min);
 #define usb_get_extra_descriptor(ifpoint, type, ptr) \
 				__usb_get_extra_descriptor((ifpoint)->extra, \
 				(ifpoint)->extralen, \
-				type, (void **)ptr)
+				type, (void **)ptr, sizeof(**(ptr)))
 
 /* ----------------------------------------------------------------------- */
 
@@ -371,14 +447,13 @@
 
 	int devnum_next;		/* Next open device number in
 					 * round-robin allocation */
+	struct mutex devnum_next_mutex; /* devnum_next mutex */
 
 	struct usb_devmap devmap;	/* device address allocation map */
 	struct usb_device *root_hub;	/* Root hub */
 	struct usb_bus *hs_companion;	/* Companion EHCI bus, if any */
 	struct list_head bus_list;	/* list of busses */
 
-	struct mutex usb_address0_mutex; /* unaddressed device mutex */
-
 	int bandwidth_allocated;	/* on this bus: how much of the time
 					 * reserved for periodic (intr/iso)
 					 * requests is used, on average?
@@ -497,6 +572,7 @@
  * @level: number of USB hub ancestors
  * @can_submit: URBs may be submitted
  * @persist_enabled:  USB_PERSIST enabled for this device
+ * @reset_in_progress: the device is being reset
  * @have_langid: whether string_langid is valid
  * @authorized: policy has said we can use it;
  *	(user space) policy determines if we authorize this device to be
@@ -511,6 +587,8 @@
  * @usb2_hw_lpm_enabled: USB2 hardware LPM is enabled
  * @usb2_hw_lpm_allowed: Userspace allows USB 2.0 LPM to be enabled
  * @usb3_lpm_enabled: USB3 hardware LPM enabled
+ * @usb3_lpm_u1_enabled: USB3 hardware U1 LPM enabled
+ * @usb3_lpm_u2_enabled: USB3 hardware U2 LPM enabled
  * @string_langid: language ID for strings
  * @product: iProduct string, if present (static)
  * @manufacturer: iManufacturer string, if present (static)
@@ -574,6 +652,7 @@
 
 	unsigned can_submit:1;
 	unsigned persist_enabled:1;
+	unsigned reset_in_progress:1;
 	unsigned have_langid:1;
 	unsigned authorized:1;
 	unsigned authenticated:1;
@@ -584,6 +663,8 @@
 	unsigned usb2_hw_lpm_enabled:1;
 	unsigned usb2_hw_lpm_allowed:1;
 	unsigned usb3_lpm_enabled:1;
+	unsigned usb3_lpm_u1_enabled:1;
+	unsigned usb3_lpm_u2_enabled:1;
 	int string_langid;
 
 	/* static strings from the device */
@@ -1064,7 +1145,7 @@
  *	for interfaces bound to this driver.
  * @soft_unbind: if set to 1, the USB core will not kill URBs and disable
  *	endpoints before calling the driver's disconnect method.
- * @disable_hub_initiated_lpm: if set to 0, the USB core will not allow hubs
+ * @disable_hub_initiated_lpm: if set to 1, the USB core will not allow hubs
  *	to initiate lower power link state transitions when an idle timeout
  *	occurs.  Device-initiated USB 3.0 link PM will still be allowed.
  *
@@ -1653,6 +1734,9 @@
 	return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
 }
 
+int usb_pipe_type_check(struct usb_device *dev, unsigned int pipe);
+int usb_urb_ep_type_check(const struct urb *urb);
+
 void *usb_alloc_coherent(struct usb_device *dev, size_t size,
 	gfp_t mem_flags, dma_addr_t *dma);
 void usb_free_coherent(struct usb_device *dev, size_t size,
@@ -1688,6 +1772,14 @@
 	int timeout);
 
 /* wrappers around usb_control_msg() for the most common standard requests */
+int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request,
+			 __u8 requesttype, __u16 value, __u16 index,
+			 const void *data, __u16 size, int timeout,
+			 gfp_t memflags);
+int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request,
+			 __u8 requesttype, __u16 value, __u16 index,
+			 void *data, __u16 size, int timeout,
+			 gfp_t memflags);
 extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
 	unsigned char descindex, void *buf, int size);
 extern int usb_get_status(struct usb_device *dev,
--- linux-4.4.0.orig/include/linux/usb/cdc_ncm.h
+++ linux-4.4.0/include/linux/usb/cdc_ncm.h
@@ -82,6 +82,7 @@
 
 /* Driver flags */
 #define CDC_NCM_FLAG_NDP_TO_END	0x02		/* NDP is placed at end of frame */
+#define CDC_NCM_FLAG_RESET_NTB16 0x08	/* set NDP16 one more time after altsetting switch */
 
 #define cdc_ncm_comm_intf_is_mbim(x)  ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
 				       (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)
--- linux-4.4.0.orig/include/linux/usb/chipidea.h
+++ linux-4.4.0/include/linux/usb/chipidea.h
@@ -14,6 +14,7 @@
  * struct ci_hdrc_cable - structure for external connector cable state tracking
  * @state: current state of the line
  * @changed: set to true when extcon event happen
+ * @enabled: set to true if we've enabled the vbus or id interrupt
  * @edev: device which generate events
  * @ci: driver state of the chipidea device
  * @nb: hold event notification callback
@@ -22,6 +23,7 @@
 struct ci_hdrc_cable {
 	bool				state;
 	bool				changed;
+	bool				enabled;
 	struct extcon_dev		*edev;
 	struct ci_hdrc			*ci;
 	struct notifier_block		nb;
--- linux-4.4.0.orig/include/linux/usb/composite.h
+++ linux-4.4.0/include/linux/usb/composite.h
@@ -53,6 +53,9 @@
 /* big enough to hold our biggest descriptor */
 #define USB_COMP_EP0_BUFSIZ	1024
 
+/* OS feature descriptor length <= 4kB */
+#define USB_COMP_EP0_OS_DESC_BUFSIZ	4096
+
 #define USB_MS_TO_HS_INTERVAL(x)	(ilog2((x * 1000 / 125)) + 1)
 struct usb_configuration;
 
--- linux-4.4.0.orig/include/linux/usb/ehci_def.h
+++ linux-4.4.0/include/linux/usb/ehci_def.h
@@ -180,11 +180,11 @@
  * PORTSCx
  */
 	/* HOSTPC: offset 0x84 */
-	u32		hostpc[1];	/* HOSTPC extension */
+	u32		hostpc[0];	/* HOSTPC extension */
 #define HOSTPC_PHCD	(1<<22)		/* Phy clock disable */
 #define HOSTPC_PSPD	(3<<25)		/* Port speed detection */
 
-	u32		reserved5[16];
+	u32		reserved5[17];
 
 	/* USBMODE_EX: offset 0xc8 */
 	u32		usbmode_ex;	/* USB Device mode extension */
--- linux-4.4.0.orig/include/linux/usb/gadget.h
+++ linux-4.4.0/include/linux/usb/gadget.h
@@ -270,6 +270,16 @@
 	if (ep->enabled)
 		return 0;
 
+	/* UDC drivers can't handle endpoints with maxpacket size 0 */
+	if (usb_endpoint_maxp(ep->desc) == 0) {
+		/*
+		 * We should log an error message here, but we can't call
+		 * dev_err() because there's no way to find the gadget
+		 * given only ep.
+		 */
+		return -EINVAL;
+	}
+
 	ret = ep->ops->enable(ep, ep->desc);
 	if (ret)
 		return ret;
@@ -663,8 +673,22 @@
 	list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
 
 /**
+ * usb_ep_align - returns @len aligned to ep's maxpacketsize.
+ * @ep: the endpoint whose maxpacketsize is used to align @len
+ * @len: buffer size's length to align to @ep's maxpacketsize
+ *
+ * This helper is used to align buffer's size to an ep's maxpacketsize.
+ */
+static inline size_t usb_ep_align(struct usb_ep *ep, size_t len)
+{
+	int max_packet_size = (size_t)usb_endpoint_maxp(ep->desc) & 0x7ff;
+
+	return round_up(len, max_packet_size);
+}
+
+/**
  * usb_ep_align_maybe - returns @len aligned to ep's maxpacketsize if gadget
- *	requires quirk_ep_out_aligned_size, otherwise reguens len.
+ *	requires quirk_ep_out_aligned_size, otherwise returns len.
  * @g: controller to check for quirk
  * @ep: the endpoint whose maxpacketsize is used to align @len
  * @len: buffer size's length to align to @ep's maxpacketsize
@@ -675,8 +699,7 @@
 static inline size_t
 usb_ep_align_maybe(struct usb_gadget *g, struct usb_ep *ep, size_t len)
 {
-	return !g->quirk_ep_out_aligned_size ? len :
-			round_up(len, (size_t)ep->desc->wMaxPacketSize);
+	return g->quirk_ep_out_aligned_size ? usb_ep_align(ep, len) : len;
 }
 
 /**
--- linux-4.4.0.orig/include/linux/usb/hcd.h
+++ linux-4.4.0/include/linux/usb/hcd.h
@@ -180,6 +180,7 @@
 	 * bandwidth_mutex should be dropped after a successful control message
 	 * to the device, or resetting the bandwidth after a failed attempt.
 	 */
+	struct mutex		*address0_mutex;
 	struct mutex		*bandwidth_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
@@ -559,9 +560,9 @@
 	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
 
 #define EndpointRequest \
-	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
 #define EndpointOutRequest \
-	((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+	((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
 
 /* class requests from the USB 2.0 hub spec, table 11-15 */
 /* GetBusState and SetHubDescriptor are optional, omitted */
--- linux-4.4.0.orig/include/linux/usb/irda.h
+++ linux-4.4.0/include/linux/usb/irda.h
@@ -118,11 +118,22 @@
  * 6 - 115200 bps
  * 7 - 576000 bps
  * 8 - 1.152 Mbps
- * 9 - 5 mbps
+ * 9 - 4 Mbps
  * 10..15 - Reserved
  */
 #define USB_IRDA_STATUS_LINK_SPEED	0x0f
 
+#define USB_IRDA_LS_NO_CHANGE		0
+#define USB_IRDA_LS_2400		1
+#define USB_IRDA_LS_9600		2
+#define USB_IRDA_LS_19200		3
+#define USB_IRDA_LS_38400		4
+#define USB_IRDA_LS_57600		5
+#define USB_IRDA_LS_115200		6
+#define USB_IRDA_LS_576000		7
+#define USB_IRDA_LS_1152000		8
+#define USB_IRDA_LS_4000000		9
+
 /* The following is a 4-bit value used only for
  * outbound header:
  *
--- linux-4.4.0.orig/include/linux/usb/quirks.h
+++ linux-4.4.0/include/linux/usb/quirks.h
@@ -50,4 +50,16 @@
 /* device can't handle Link Power Management */
 #define USB_QUIRK_NO_LPM			BIT(10)
 
+/*
+ * Device reports its bInterval as linear frames instead of the
+ * USB 2.0 calculation.
+ */
+#define USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL	BIT(11)
+
+/* Device needs a pause after every control message. */
+#define USB_QUIRK_DELAY_CTRL_MSG		BIT(13)
+
+/* device has blacklisted endpoints */
+#define USB_QUIRK_ENDPOINT_BLACKLIST		BIT(15)
+
 #endif /* __LINUX_USB_QUIRKS_H */
--- linux-4.4.0.orig/include/linux/usb_usual.h
+++ linux-4.4.0/include/linux/usb_usual.h
@@ -79,6 +79,8 @@
 		/* Cannot handle MI_REPORT_SUPPORTED_OPERATION_CODES */	\
 	US_FLAG(MAX_SECTORS_240,	0x08000000)		\
 		/* Sets max_sectors to 240 */			\
+	US_FLAG(NO_REPORT_LUNS,	0x10000000)			\
+		/* Cannot handle REPORT_LUNS */			\
 
 #define US_FLAG(name, value)	US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };
--- linux-4.4.0.orig/include/linux/user_namespace.h
+++ linux-4.4.0/include/linux/user_namespace.h
@@ -72,6 +72,7 @@
 extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *);
 extern int proc_setgroups_show(struct seq_file *m, void *v);
 extern bool userns_may_setgroups(const struct user_namespace *ns);
+extern bool current_in_userns(const struct user_namespace *target_ns);
 #else
 
 static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@ -100,6 +101,11 @@
 {
 	return true;
 }
+
+static inline bool current_in_userns(const struct user_namespace *target_ns)
+{
+	return true;
+}
 #endif
 
 #endif /* _LINUX_USER_H */
--- linux-4.4.0.orig/include/linux/vfio.h
+++ linux-4.4.0/include/linux/vfio.h
@@ -85,6 +85,8 @@
  */
 extern struct vfio_group *vfio_group_get_external_user(struct file *filep);
 extern void vfio_group_put_external_user(struct vfio_group *group);
+extern bool vfio_external_group_match_file(struct vfio_group *group,
+					   struct file *filep);
 extern int vfio_external_user_iommu_id(struct vfio_group *group);
 extern long vfio_external_check_extension(struct vfio_group *group,
 					  unsigned long arg);
@@ -126,6 +128,7 @@
 	wait_queue_t		wait;
 	poll_table		pt;
 	struct work_struct	shutdown;
+	struct work_struct	flush_inject;
 	struct virqfd		**pvirqfd;
 };
 
@@ -134,5 +137,6 @@
 			      void (*thread)(void *, void *),
 			      void *data, struct virqfd **pvirqfd, int fd);
 extern void vfio_virqfd_disable(struct virqfd **pvirqfd);
+void vfio_virqfd_flush_thread(struct virqfd **pvirqfd);
 
 #endif /* VFIO_H */
--- linux-4.4.0.orig/include/linux/virtio.h
+++ linux-4.4.0/include/linux/virtio.h
@@ -124,6 +124,9 @@
 int virtio_device_restore(struct virtio_device *dev);
 #endif
 
+#define virtio_device_for_each_vq(vdev, vq) \
+	list_for_each_entry(vq, &vdev->vqs, list)
+
 /**
  * virtio_driver - operations for a virtio I/O driver
  * @driver: underlying device driver (populate name and owner).
--- linux-4.4.0.orig/include/linux/vm_event_item.h
+++ linux-4.4.0/include/linux/vm_event_item.h
@@ -80,17 +80,14 @@
 #endif
 #endif
 #ifdef CONFIG_DEBUG_TLBFLUSH
-#ifdef CONFIG_SMP
 		NR_TLB_REMOTE_FLUSH,	/* cpu tried to flush others' tlbs */
 		NR_TLB_REMOTE_FLUSH_RECEIVED,/* cpu received ipi for flush */
-#endif /* CONFIG_SMP */
 		NR_TLB_LOCAL_FLUSH_ALL,
 		NR_TLB_LOCAL_FLUSH_ONE,
 #endif /* CONFIG_DEBUG_TLBFLUSH */
 #ifdef CONFIG_DEBUG_VM_VMACACHE
 		VMACACHE_FIND_CALLS,
 		VMACACHE_FIND_HITS,
-		VMACACHE_FULL_FLUSHES,
 #endif
 		NR_VM_EVENT_ITEMS
 };
--- linux-4.4.0.orig/include/linux/vmacache.h
+++ linux-4.4.0/include/linux/vmacache.h
@@ -15,7 +15,6 @@
 	memset(tsk->vmacache, 0, sizeof(tsk->vmacache));
 }
 
-extern void vmacache_flush_all(struct mm_struct *mm);
 extern void vmacache_update(unsigned long addr, struct vm_area_struct *newvma);
 extern struct vm_area_struct *vmacache_find(struct mm_struct *mm,
 						    unsigned long addr);
@@ -29,10 +28,6 @@
 static inline void vmacache_invalidate(struct mm_struct *mm)
 {
 	mm->vmacache_seqnum++;
-
-	/* deal with overflows */
-	if (unlikely(mm->vmacache_seqnum == 0))
-		vmacache_flush_all(mm);
 }
 
 #endif /* __LINUX_VMACACHE_H */
--- linux-4.4.0.orig/include/linux/vmalloc.h
+++ linux-4.4.0/include/linux/vmalloc.h
@@ -92,8 +92,9 @@
 
 extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
 							unsigned long pgoff);
-void vmalloc_sync_all(void);
- 
+void vmalloc_sync_mappings(void);
+void vmalloc_sync_unmappings(void);
+
 /*
  *	Lowlevel-APIs (not for driver use!)
  */
--- linux-4.4.0.orig/include/linux/vmstat.h
+++ linux-4.4.0/include/linux/vmstat.h
@@ -189,6 +189,7 @@
 extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
 
+void quiet_vmstat(void);
 void cpu_vm_stats_fold(int cpu);
 void refresh_zone_stat_thresholds(void);
 
@@ -249,6 +250,7 @@
 
 static inline void refresh_zone_stat_thresholds(void) { }
 static inline void cpu_vm_stats_fold(int cpu) { }
+static inline void quiet_vmstat(void) { }
 
 static inline void drain_zonestat(struct zone *zone,
 			struct per_cpu_pageset *pset) { }
--- linux-4.4.0.orig/include/linux/vmw_vmci_defs.h
+++ linux-4.4.0/include/linux/vmw_vmci_defs.h
@@ -75,9 +75,18 @@
 
 /*
  * A single VMCI device has an upper limit of 128MB on the amount of
- * memory that can be used for queue pairs.
+ * memory that can be used for queue pairs. Since each queue pair
+ * consists of at least two pages, the memory limit also dictates the
+ * number of queue pairs a guest can create.
  */
 #define VMCI_MAX_GUEST_QP_MEMORY (128 * 1024 * 1024)
+#define VMCI_MAX_GUEST_QP_COUNT  (VMCI_MAX_GUEST_QP_MEMORY / PAGE_SIZE / 2)
+
+/*
+ * There can be at most PAGE_SIZE doorbells since there is one doorbell
+ * per byte in the doorbell bitmap page.
+ */
+#define VMCI_MAX_GUEST_DOORBELL_COUNT PAGE_SIZE
 
 /*
  * Queues with pre-mapped data pages must be small, so that we don't pin
--- linux-4.4.0.orig/include/linux/vt_kern.h
+++ linux-4.4.0/include/linux/vt_kern.h
@@ -130,7 +130,8 @@
 void vt_event_post(unsigned int event, unsigned int old, unsigned int new);
 int vt_waitactive(int n);
 void change_console(struct vc_data *new_vc);
-void reset_vc(struct vc_data *vc);
+void reset_vc(struct vc_data *vc, int mode);
+
 extern int do_unbind_con_driver(const struct consw *csw, int first, int last,
 			     int deflt);
 int vty_init(const struct file_operations *console_fops);
@@ -142,7 +143,7 @@
 	return false;
 }
 
-extern char vt_dont_switch;
+extern bool vt_dont_switch;
 extern int default_utf8;
 extern int global_cursor_default;
 
--- linux-4.4.0.orig/include/linux/workqueue.h
+++ linux-4.4.0/include/linux/workqueue.h
@@ -311,6 +311,7 @@
 
 	__WQ_DRAINING		= 1 << 16, /* internal: workqueue is draining */
 	__WQ_ORDERED		= 1 << 17, /* internal: workqueue is ordered */
+	__WQ_ORDERED_EXPLICIT	= 1 << 19, /* internal: alloc_ordered_workqueue() */
 
 	WQ_MAX_ACTIVE		= 512,	  /* I like 512, better ideas? */
 	WQ_MAX_UNBOUND_PER_CPU	= 4,	  /* 4 * #cpus for unbound wq */
@@ -408,7 +409,8 @@
  * Pointer to the allocated workqueue on success, %NULL on failure.
  */
 #define alloc_ordered_workqueue(fmt, flags, args...)			\
-	alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
+	alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED |		\
+			__WQ_ORDERED_EXPLICIT | (flags), 1, ##args)
 
 #define create_workqueue(name)						\
 	alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, (name))
@@ -449,6 +451,7 @@
 
 extern void workqueue_set_max_active(struct workqueue_struct *wq,
 				     int max_active);
+extern struct work_struct *current_work(void);
 extern bool current_is_workqueue_rescuer(void);
 extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
 extern unsigned int work_busy(struct work_struct *work);
--- linux-4.4.0.orig/include/linux/writeback.h
+++ linux-4.4.0/include/linux/writeback.h
@@ -198,6 +198,7 @@
 void wbc_detach_inode(struct writeback_control *wbc);
 void wbc_account_io(struct writeback_control *wbc, struct page *page,
 		    size_t bytes);
+void cgroup_writeback_umount(void);
 
 /**
  * inode_attach_wb - associate an inode with its wb
@@ -223,6 +224,7 @@
 static inline void inode_detach_wb(struct inode *inode)
 {
 	if (inode->i_wb) {
+		WARN_ON_ONCE(!(inode->i_state & I_CLEAR));
 		wb_put(inode->i_wb);
 		inode->i_wb = NULL;
 	}
@@ -301,6 +303,10 @@
 {
 }
 
+static inline void cgroup_writeback_umount(void)
+{
+}
+
 #endif	/* CONFIG_CGROUP_WRITEBACK */
 
 /*
--- linux-4.4.0.orig/include/linux/zsmalloc.h
+++ linux-4.4.0/include/linux/zsmalloc.h
@@ -36,7 +36,7 @@
 
 struct zs_pool_stats {
 	/* How many pages were migrated (freed) */
-	unsigned long pages_compacted;
+	atomic_long_t pages_compacted;
 };
 
 struct zs_pool;
--- linux-4.4.0.orig/include/math-emu/soft-fp.h
+++ linux-4.4.0/include/math-emu/soft-fp.h
@@ -138,7 +138,7 @@
       _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND);		\
 } while (0)
 
-#define _FP_ROUND_ZERO(wc, X)		0
+#define _FP_ROUND_ZERO(wc, X)		(void)0
 
 #define _FP_ROUND_PINF(wc, X)				\
 do {							\
--- linux-4.4.0.orig/include/media/davinci/vpbe.h
+++ linux-4.4.0/include/media/davinci/vpbe.h
@@ -96,7 +96,7 @@
 	struct encoder_config_info *ext_encoders;
 	/* amplifier information goes here */
 	struct amp_config_info *amp;
-	int num_outputs;
+	unsigned int num_outputs;
 	/* Order is venc outputs followed by LCD and then external encoders */
 	struct vpbe_output *outputs;
 };
--- linux-4.4.0.orig/include/media/media-device.h
+++ linux-4.4.0/include/media/media-device.h
@@ -60,7 +60,7 @@
 struct media_device {
 	/* dev->driver_data points to this struct. */
 	struct device *dev;
-	struct media_devnode devnode;
+	struct media_devnode *devnode;
 
 	char model[32];
 	char serial[40];
@@ -84,9 +84,6 @@
 #define MEDIA_DEV_NOTIFY_PRE_LINK_CH	0
 #define MEDIA_DEV_NOTIFY_POST_LINK_CH	1
 
-/* media_devnode to media_device */
-#define to_media_device(node) container_of(node, struct media_device, devnode)
-
 int __must_check __media_device_register(struct media_device *mdev,
 					 struct module *owner);
 #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE)
--- linux-4.4.0.orig/include/media/media-devnode.h
+++ linux-4.4.0/include/media/media-devnode.h
@@ -33,6 +33,8 @@
 #include <linux/device.h>
 #include <linux/cdev.h>
 
+struct media_device;
+
 /*
  * Flag to mark the media_devnode struct as registered. Drivers must not touch
  * this flag directly, it will be set and cleared by media_devnode_register and
@@ -67,6 +69,8 @@
  * before registering the node.
  */
 struct media_devnode {
+	struct media_device *media_dev;
+
 	/* device ops */
 	const struct media_file_operations *fops;
 
@@ -80,24 +84,42 @@
 	unsigned long flags;		/* Use bitops to access flags */
 
 	/* callbacks */
-	void (*release)(struct media_devnode *mdev);
+	void (*release)(struct media_devnode *devnode);
 };
 
 /* dev to media_devnode */
 #define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
 
-int __must_check media_devnode_register(struct media_devnode *mdev,
+int __must_check media_devnode_register(struct media_device *mdev,
+					struct media_devnode *devnode,
 					struct module *owner);
-void media_devnode_unregister(struct media_devnode *mdev);
+
+/**
+ * media_devnode_unregister_prepare - clear the media device node register bit
+ * @devnode: the device node to prepare for unregister
+ *
+ * This clears the passed device register bit. Future open calls will be met
+ * with errors. Should be called before media_devnode_unregister() to avoid
+ * races with unregister and device file open calls.
+ *
+ * This function can safely be called if the device node has never been
+ * registered or has already been unregistered.
+ */
+void media_devnode_unregister_prepare(struct media_devnode *devnode);
+
+void media_devnode_unregister(struct media_devnode *devnode);
 
 static inline struct media_devnode *media_devnode_data(struct file *filp)
 {
 	return filp->private_data;
 }
 
-static inline int media_devnode_is_registered(struct media_devnode *mdev)
+static inline int media_devnode_is_registered(struct media_devnode *devnode)
 {
-	return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+	if (!devnode)
+		return false;
+
+	return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
 }
 
 #endif /* _MEDIA_DEVNODE_H */
--- linux-4.4.0.orig/include/media/v4l2-fh.h
+++ linux-4.4.0/include/media/v4l2-fh.h
@@ -43,6 +43,7 @@
 	wait_queue_head_t	wait;
 	struct list_head	subscribed; /* Subscribed events */
 	struct list_head	available; /* Dequeueable event */
+	struct mutex		subscribe_lock;
 	unsigned int		navailable;
 	u32			sequence;
 
--- linux-4.4.0.orig/include/media/videobuf2-core.h
+++ linux-4.4.0/include/media/videobuf2-core.h
@@ -363,6 +363,7 @@
 };
 
 struct vb2_buf_ops {
+	int (*verify_planes_array)(struct vb2_buffer *vb, const void *pb);
 	int (*fill_user_buffer)(struct vb2_buffer *vb, void *pb);
 	int (*fill_vb2_buffer)(struct vb2_buffer *vb, const void *pb,
 				struct vb2_plane *planes);
--- linux-4.4.0.orig/include/misc/cxl.h
+++ linux-4.4.0/include/misc/cxl.h
@@ -30,9 +30,6 @@
 /* Get the AFU conf record number associated with a pci_dev */
 unsigned int cxl_pci_to_cfg_record(struct pci_dev *dev);
 
-/* Get the physical device (ie. the PCIe card) which the AFU is attached */
-struct device *cxl_get_phys_dev(struct pci_dev *dev);
-
 
 /*
  * Context lifetime overview:
@@ -210,4 +207,9 @@
 void cxl_perst_reloads_same_image(struct cxl_afu *afu,
 				  bool perst_reloads_same_image);
 
+/*
+ * Read the VPD for the card where the AFU resides
+ */
+ssize_t cxl_read_adapter_vpd(struct pci_dev *dev, void *buf, size_t count);
+
 #endif /* _MISC_CXL_H */
--- linux-4.4.0.orig/include/net/addrconf.h
+++ linux-4.4.0/include/net/addrconf.h
@@ -19,6 +19,8 @@
 #define ADDRCONF_TIMER_FUZZ		(HZ / 4)
 #define ADDRCONF_TIMER_FUZZ_MAX		(HZ)
 
+#define ADDRCONF_NOTIFY_PRIORITY	0
+
 #include <linux/in.h>
 #include <linux/in6.h>
 
@@ -160,6 +162,7 @@
 		      const struct in6_addr *addr);
 int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
 		      const struct in6_addr *addr);
+void __ipv6_sock_mc_close(struct sock *sk);
 void ipv6_sock_mc_close(struct sock *sk);
 bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
 		    const struct in6_addr *src_addr);
@@ -189,8 +192,10 @@
 				 const struct in6_addr *addr);
 	int (*ipv6_sock_mc_drop)(struct sock *sk, int ifindex,
 				 const struct in6_addr *addr);
-	int (*ipv6_dst_lookup)(struct net *net, struct sock *sk,
-			       struct dst_entry **dst, struct flowi6 *fl6);
+	struct dst_entry *(*ipv6_dst_lookup_flow)(struct net *net,
+						  const struct sock *sk,
+						  struct flowi6 *fl6,
+						  const struct in6_addr *final_dst);
 	void (*udpv6_encap_enable)(void);
 	void (*ndisc_send_na)(struct net_device *dev, const struct in6_addr *daddr,
 			      const struct in6_addr *solicited_addr,
@@ -234,6 +239,7 @@
 		      const struct in6_addr *addr);
 int ipv6_sock_ac_drop(struct sock *sk, int ifindex,
 		      const struct in6_addr *addr);
+void __ipv6_sock_ac_close(struct sock *sk);
 void ipv6_sock_ac_close(struct sock *sk);
 
 int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr);
@@ -299,6 +305,16 @@
 		in6_dev_finish_destroy(idev);
 }
 
+static inline void in6_dev_put_clear(struct inet6_dev **pidev)
+{
+	struct inet6_dev *idev = *pidev;
+
+	if (idev) {
+		in6_dev_put(idev);
+		*pidev = NULL;
+	}
+}
+
 static inline void __in6_dev_put(struct inet6_dev *idev)
 {
 	atomic_dec(&idev->refcnt);
--- linux-4.4.0.orig/include/net/af_unix.h
+++ linux-4.4.0/include/net/af_unix.h
@@ -6,8 +6,9 @@
 #include <linux/mutex.h>
 #include <net/sock.h>
 
-void unix_inflight(struct file *fp);
-void unix_notinflight(struct file *fp);
+void unix_inflight(struct user_struct *user, struct file *fp);
+void unix_notinflight(struct user_struct *user, struct file *fp);
+void unix_destruct_scm(struct sk_buff *skb);
 void unix_gc(void);
 void wait_for_unix_gc(void);
 struct sock *unix_get_socket(struct file *filp);
@@ -52,10 +53,10 @@
 	struct sock		sk;
 	struct unix_address     *addr;
 	struct path		path;
-	struct mutex		readlock;
+	struct mutex		iolock, bindlock;
 	struct sock		*peer;
 	struct list_head	link;
-	atomic_long_t		inflight;
+	unsigned long		inflight;
 	spinlock_t		lock;
 	unsigned char		recursion_level;
 	unsigned long		gc_flags;
--- linux-4.4.0.orig/include/net/af_vsock.h
+++ linux-4.4.0/include/net/af_vsock.h
@@ -62,7 +62,8 @@
 	struct list_head pending_links;
 	struct list_head accept_queue;
 	bool rejected;
-	struct delayed_work dwork;
+	struct delayed_work connect_work;
+	struct delayed_work pending_work;
 	u32 peer_shutdown;
 	bool sent_request;
 	bool ignore_connecting_rst;
@@ -73,7 +74,6 @@
 
 s64 vsock_stream_has_data(struct vsock_sock *vsk);
 s64 vsock_stream_has_space(struct vsock_sock *vsk);
-void vsock_pending_work(struct work_struct *work);
 struct sock *__vsock_create(struct net *net,
 			    struct socket *sock,
 			    struct sock *parent,
--- linux-4.4.0.orig/include/net/arp.h
+++ linux-4.4.0/include/net/arp.h
@@ -17,10 +17,21 @@
 	return val * hash_rnd[0];
 }
 
+#ifdef CONFIG_INET
 static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
 {
+	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
+		key = INADDR_ANY;
+
 	return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev);
 }
+#else
+static inline
+struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
+{
+	return NULL;
+}
+#endif
 
 static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key)
 {
@@ -35,6 +46,22 @@
 	return n;
 }
 
+static inline void __ipv4_confirm_neigh(struct net_device *dev, u32 key)
+{
+	struct neighbour *n;
+
+	rcu_read_lock_bh();
+	n = __ipv4_neigh_lookup_noref(dev, key);
+	if (n) {
+		unsigned long now = jiffies;
+
+		/* avoid dirtying neighbour */
+		if (n->confirmed != now)
+			n->confirmed = now;
+	}
+	rcu_read_unlock_bh();
+}
+
 void arp_init(void);
 int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg);
 void arp_send(int type, int ptype, __be32 dest_ip,
--- linux-4.4.0.orig/include/net/ax25.h
+++ linux-4.4.0/include/net/ax25.h
@@ -199,6 +199,18 @@
 
 void __ax25_put_route(ax25_route *ax25_rt);
 
+extern rwlock_t ax25_route_lock;
+
+static inline void ax25_route_lock_use(void)
+{
+	read_lock(&ax25_route_lock);
+}
+
+static inline void ax25_route_lock_unuse(void)
+{
+	read_unlock(&ax25_route_lock);
+}
+
 static inline void ax25_put_route(ax25_route *ax25_rt)
 {
 	if (atomic_dec_and_test(&ax25_rt->refcount))
@@ -222,6 +234,8 @@
 #if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
 	ax25_dama_info		dama;
 #endif
+	atomic_t		refcount;
+	bool device_up;
 } ax25_dev;
 
 typedef struct ax25_cb {
@@ -276,6 +290,17 @@
 	}
 }
 
+static inline void ax25_dev_hold(ax25_dev *ax25_dev)
+{
+	atomic_inc(&ax25_dev->refcount);
+}
+
+static inline void ax25_dev_put(ax25_dev *ax25_dev)
+{
+	if (atomic_dec_and_test(&ax25_dev->refcount)) {
+		kfree(ax25_dev);
+	}
+}
 static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	skb->dev      = dev;
--- linux-4.4.0.orig/include/net/bluetooth/hci.h
+++ linux-4.4.0/include/net/bluetooth/hci.h
@@ -266,7 +266,7 @@
 #define HCI_AUTO_OFF_TIMEOUT	msecs_to_jiffies(2000)	/* 2 seconds */
 #define HCI_POWER_OFF_TIMEOUT	msecs_to_jiffies(5000)	/* 5 seconds */
 #define HCI_LE_CONN_TIMEOUT	msecs_to_jiffies(20000)	/* 20 seconds */
-#define HCI_LE_AUTOCONN_TIMEOUT	msecs_to_jiffies(2000)	/* 2 seconds */
+#define HCI_LE_AUTOCONN_TIMEOUT	msecs_to_jiffies(4000)	/* 4 seconds */
 
 /* HCI data types */
 #define HCI_COMMAND_PKT		0x01
@@ -447,6 +447,7 @@
 #define HCI_ERROR_CONNECTION_TIMEOUT	0x08
 #define HCI_ERROR_REJ_LIMITED_RESOURCES	0x0d
 #define HCI_ERROR_REJ_BAD_ADDR		0x0f
+#define HCI_ERROR_INVALID_PARAMETERS	0x12
 #define HCI_ERROR_REMOTE_USER_TERM	0x13
 #define HCI_ERROR_REMOTE_LOW_RESOURCES	0x14
 #define HCI_ERROR_REMOTE_POWER_OFF	0x15
@@ -1277,6 +1278,15 @@
 	__u8     mask[8];
 } __packed;
 
+/* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 4, Part E
+ * 7.8.2 LE Read Buffer Size command
+ * MAX_LE_MTU is 0xffff.
+ * 0 is also valid. It means that no dedicated LE Buffer exists.
+ * It should use the HCI_Read_Buffer_Size command and mtu is shared
+ * between BR/EDR and LE.
+ */
+#define HCI_MIN_LE_MTU 0x001b
+
 #define HCI_OP_LE_READ_BUFFER_SIZE	0x2002
 struct hci_rp_le_read_buffer_size {
 	__u8     status;
--- linux-4.4.0.orig/include/net/bluetooth/hci_core.h
+++ linux-4.4.0/include/net/bluetooth/hci_core.h
@@ -174,6 +174,9 @@
 
 #define HCI_MAX_SHORT_NAME_LENGTH	10
 
+/* Min encryption key size to match with SMP */
+#define HCI_MIN_ENC_KEY_SIZE		7
+
 /* Default LE RPA expiry time, 15 minutes */
 #define HCI_DEFAULT_RPA_TIMEOUT		(15 * 60)
 
@@ -251,6 +254,7 @@
 	__u16		discov_interleaved_timeout;
 	__u16		conn_info_min_age;
 	__u16		conn_info_max_age;
+	__u8		min_enc_key_size;
 	__u8		ssp_debug_mode;
 	__u8		hw_error_code;
 	__u32		clock;
@@ -394,6 +398,7 @@
 	int (*close)(struct hci_dev *hdev);
 	int (*flush)(struct hci_dev *hdev);
 	int (*setup)(struct hci_dev *hdev);
+	void (*post_open)(struct hci_dev *hdev);
 	int (*shutdown)(struct hci_dev *hdev);
 	int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
 	void (*notify)(struct hci_dev *hdev, unsigned int evt);
@@ -420,6 +425,7 @@
 	__u8		resp_addr_type;
 	__u16		handle;
 	__u16		state;
+	__u16		mtu;
 	__u8		mode;
 	__u8		type;
 	__u8		role;
@@ -495,6 +501,7 @@
 	struct sk_buff_head data_q;
 	unsigned int	sent;
 	__u8		state;
+	bool		amp;
 };
 
 struct hci_conn_params {
@@ -878,7 +885,7 @@
 				     u16 conn_timeout, u8 role);
 struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 				u8 dst_type, u8 sec_level, u16 conn_timeout,
-				u8 role);
+				u8 role, bdaddr_t *direct_rpa);
 struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
 				 u8 sec_level, u8 auth_type);
 struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
@@ -1009,6 +1016,7 @@
 void hci_free_dev(struct hci_dev *hdev);
 int hci_register_dev(struct hci_dev *hdev);
 void hci_unregister_dev(struct hci_dev *hdev);
+void hci_cleanup_dev(struct hci_dev *hdev);
 int hci_suspend_dev(struct hci_dev *hdev);
 int hci_resume_dev(struct hci_dev *hdev);
 int hci_reset_dev(struct hci_dev *hdev);
@@ -1232,16 +1240,34 @@
 		conn->security_cfm_cb(conn, status);
 }
 
-static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
-								__u8 encrypt)
+static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status)
 {
 	struct hci_cb *cb;
+	__u8 encrypt;
 
-	if (conn->sec_level == BT_SECURITY_SDP)
-		conn->sec_level = BT_SECURITY_LOW;
+	if (conn->state == BT_CONFIG) {
+		if (!status)
+			conn->state = BT_CONNECTED;
 
-	if (conn->pending_sec_level > conn->sec_level)
-		conn->sec_level = conn->pending_sec_level;
+		hci_connect_cfm(conn, status);
+		hci_conn_drop(conn);
+		return;
+	}
+
+	if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
+		encrypt = 0x00;
+	else if (test_bit(HCI_CONN_AES_CCM, &conn->flags))
+		encrypt = 0x02;
+	else
+		encrypt = 0x01;
+
+	if (!status) {
+		if (conn->sec_level == BT_SECURITY_SDP)
+			conn->sec_level = BT_SECURITY_LOW;
+
+		if (conn->pending_sec_level > conn->sec_level)
+			conn->sec_level = conn->pending_sec_level;
+	}
 
 	mutex_lock(&hci_cb_list_lock);
 	list_for_each_entry(cb, &hci_cb_list, list) {
--- linux-4.4.0.orig/include/net/bluetooth/l2cap.h
+++ linux-4.4.0/include/net/bluetooth/l2cap.h
@@ -252,6 +252,12 @@
 #define L2CAP_PSM_3DSP		0x0021
 #define L2CAP_PSM_IPSP		0x0023 /* 6LoWPAN */
 
+#define L2CAP_PSM_DYN_START	0x1001
+#define L2CAP_PSM_DYN_END	0xffff
+#define L2CAP_PSM_AUTO_END	0x10ff
+#define L2CAP_PSM_LE_DYN_START  0x0080
+#define L2CAP_PSM_LE_DYN_END	0x00ff
+
 /* channel identifier */
 #define L2CAP_CID_SIGNALING	0x0001
 #define L2CAP_CID_CONN_LESS	0x0002
@@ -790,6 +796,7 @@
 };
 
 void l2cap_chan_hold(struct l2cap_chan *c);
+struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c);
 void l2cap_chan_put(struct l2cap_chan *c);
 
 static inline void l2cap_chan_lock(struct l2cap_chan *chan)
--- linux-4.4.0.orig/include/net/bonding.h
+++ linux-4.4.0/include/net/bonding.h
@@ -34,6 +34,9 @@
 
 #define BOND_DEFAULT_MIIMON	100
 
+#ifndef __long_aligned
+#define __long_aligned __attribute__((aligned((sizeof(long)))))
+#endif
 /*
  * Less bad way to call ioctl from within the kernel; this needs to be
  * done some other way to get the call out of interrupt context.
@@ -138,7 +141,9 @@
 	struct reciprocal_value reciprocal_packets_per_slave;
 	u16 ad_actor_sys_prio;
 	u16 ad_user_port_key;
-	u8 ad_actor_system[ETH_ALEN];
+
+	/* 2 bytes of padding : see ether_addr_equal_64bits() */
+	u8 ad_actor_system[ETH_ALEN + 2];
 };
 
 struct bond_parm_tbl {
@@ -146,12 +151,6 @@
 	int mode;
 };
 
-struct netdev_notify_work {
-	struct delayed_work	work;
-	struct net_device	*dev;
-	struct netdev_bonding_info bonding_info;
-};
-
 struct slave {
 	struct net_device *dev; /* first - useful for panic debug */
 	struct bonding *bond; /* our master */
@@ -165,7 +164,8 @@
 	u8     backup:1,   /* indicates backup slave. Value corresponds with
 			      BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
 	       inactive:1, /* indicates inactive slave */
-	       should_notify:1; /* indicateds whether the state changed */
+	       should_notify:1, /* indicates whether the state changed */
+	       should_notify_link:1; /* indicates whether the link changed */
 	u8     duplex;
 	u32    original_mtu;
 	u32    link_failure_count;
@@ -177,10 +177,16 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	struct netpoll *np;
 #endif
+	struct delayed_work notify_work;
 	struct kobject kobj;
 	struct rtnl_link_stats64 slave_stats;
 };
 
+static inline struct slave *to_slave(struct kobject *kobj)
+{
+	return container_of(kobj, struct slave, kobj);
+}
+
 struct bond_up_slave {
 	unsigned int	count;
 	struct rcu_head rcu;
@@ -214,6 +220,7 @@
 	 * ALB mode (6) - to sync the use and modifications of its hash table
 	 */
 	spinlock_t mode_lock;
+	spinlock_t stats_lock;
 	u8	 send_peer_notif;
 	u8       igmp_retrans;
 #ifdef CONFIG_PROC_FS
@@ -504,10 +511,35 @@
 	return slave->inactive;
 }
 
-static inline void bond_set_slave_link_state(struct slave *slave, int state)
+static inline void bond_set_slave_link_state(struct slave *slave, int state,
+					     bool notify)
 {
+	if (slave->link == state)
+		return;
+
 	slave->link = state;
-	bond_queue_slave_event(slave);
+	if (notify) {
+		bond_queue_slave_event(slave);
+		slave->should_notify_link = 0;
+	} else {
+		if (slave->should_notify_link)
+			slave->should_notify_link = 0;
+		else
+			slave->should_notify_link = 1;
+	}
+}
+
+static inline void bond_slave_link_notify(struct bonding *bond)
+{
+	struct list_head *iter;
+	struct slave *tmp;
+
+	bond_for_each_slave(bond, tmp, iter) {
+		if (tmp->should_notify_link) {
+			bond_queue_slave_event(tmp);
+			tmp->should_notify_link = 0;
+		}
+	}
 }
 
 static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be32 local)
@@ -666,6 +698,9 @@
 /* exported from bond_netlink.c */
 extern struct rtnl_link_ops bond_link_ops;
 
+/* exported from bond_sysfs_slave.c */
+extern const struct sysfs_ops slave_sysfs_ops;
+
 static inline void bond_tx_drop(struct net_device *dev, struct sk_buff *skb)
 {
 	atomic_long_inc(&dev->tx_dropped);
--- linux-4.4.0.orig/include/net/busy_poll.h
+++ linux-4.4.0/include/net/busy_poll.h
@@ -93,7 +93,7 @@
 		goto out;
 
 	ops = napi->dev->netdev_ops;
-	if (!ops->ndo_busy_poll)
+	if (!ops || !ops->ndo_busy_poll)
 		goto out;
 
 	do {
--- linux-4.4.0.orig/include/net/caif/caif_dev.h
+++ linux-4.4.0/include/net/caif/caif_dev.h
@@ -119,7 +119,7 @@
  * The link_support layer is used to add any Link Layer specific
  * framing.
  */
-void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
+int caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
 			struct cflayer *link_support, int head_room,
 			struct cflayer **layer, int (**rcv_func)(
 				struct sk_buff *, struct net_device *,
--- linux-4.4.0.orig/include/net/caif/cfcnfg.h
+++ linux-4.4.0/include/net/caif/cfcnfg.h
@@ -62,7 +62,7 @@
  * @fcs:	Specify if checksum is used in CAIF Framing Layer.
  * @head_room:	Head space needed by link specific protocol.
  */
-void
+int
 cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
 		     struct net_device *dev, struct cflayer *phy_layer,
 		     enum cfcnfg_phy_preference pref,
--- linux-4.4.0.orig/include/net/caif/cfserl.h
+++ linux-4.4.0/include/net/caif/cfserl.h
@@ -9,4 +9,5 @@
 #include <net/caif/caif_layer.h>
 
 struct cflayer *cfserl_create(int instance, bool use_stx);
+void cfserl_release(struct cflayer *layer);
 #endif
--- linux-4.4.0.orig/include/net/cfg80211.h
+++ linux-4.4.0/include/net/cfg80211.h
@@ -933,9 +933,9 @@
  * @RATE_INFO_BW_160: 160 MHz bandwidth
  */
 enum rate_info_bw {
+	RATE_INFO_BW_20 = 0,
 	RATE_INFO_BW_5,
 	RATE_INFO_BW_10,
-	RATE_INFO_BW_20,
 	RATE_INFO_BW_40,
 	RATE_INFO_BW_80,
 	RATE_INFO_BW_160,
@@ -3856,6 +3856,17 @@
 				  const u8 *ies, int len);
 
 /**
+ * cfg80211_send_layer2_update - send layer 2 update frame
+ *
+ * @dev: network device
+ * @addr: STA MAC address
+ *
+ * Wireless drivers can use this function to update forwarding tables in bridge
+ * devices upon STA association.
+ */
+void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr);
+
+/**
  * DOC: Regulatory enforcement infrastructure
  *
  * TODO
@@ -4258,6 +4269,17 @@
 void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss);
 
 /**
+ * cfg80211_abandon_assoc - notify cfg80211 of abandoned association attempt
+ * @dev: network device
+ * @bss: The BSS entry with which association was abandoned.
+ *
+ * Call this whenever - for reasons reported through other API, like deauth RX,
+ * an association attempt was abandoned.
+ * This function may sleep. The caller must hold the corresponding wdev's mutex.
+ */
+void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss);
+
+/**
  * cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame
  * @dev: network device
  * @buf: 802.11 frame (header + body)
--- linux-4.4.0.orig/include/net/cipso_ipv4.h
+++ linux-4.4.0/include/net/cipso_ipv4.h
@@ -309,6 +309,10 @@
 	}
 
 	for (opt_iter = 6; opt_iter < opt_len;) {
+		if (opt_iter + 1 == opt_len) {
+			err_offset = opt_iter;
+			goto out;
+		}
 		tag_len = opt[opt_iter + 1];
 		if ((tag_len == 0) || (tag_len > (opt_len - opt_iter))) {
 			err_offset = opt_iter + 1;
--- linux-4.4.0.orig/include/net/codel.h
+++ linux-4.4.0/include/net/codel.h
@@ -162,12 +162,14 @@
  * struct codel_stats - contains codel shared variables and stats
  * @maxpacket:	largest packet we've seen so far
  * @drop_count:	temp count of dropped packets in dequeue()
+ * @drop_len:	bytes of dropped packets in dequeue()
  * ecn_mark:	number of packets we ECN marked instead of dropping
  * ce_mark:	number of packets CE marked because sojourn time was above ce_threshold
  */
 struct codel_stats {
 	u32		maxpacket;
 	u32		drop_count;
+	u32		drop_len;
 	u32		ecn_mark;
 	u32		ce_mark;
 };
@@ -308,6 +310,7 @@
 								  vars->rec_inv_sqrt);
 					goto end;
 				}
+				stats->drop_len += qdisc_pkt_len(skb);
 				qdisc_drop(skb, sch);
 				stats->drop_count++;
 				skb = dequeue_func(vars, sch);
@@ -330,6 +333,7 @@
 		if (params->ecn && INET_ECN_set_ce(skb)) {
 			stats->ecn_mark++;
 		} else {
+			stats->drop_len += qdisc_pkt_len(skb);
 			qdisc_drop(skb, sch);
 			stats->drop_count++;
 
--- linux-4.4.0.orig/include/net/dst.h
+++ linux-4.4.0/include/net/dst.h
@@ -59,8 +59,6 @@
 #define DST_XFRM_QUEUE		0x0100
 #define DST_METADATA		0x0200
 
-	unsigned short		pending_confirm;
-
 	short			error;
 
 	/* A non-zero value of dst->obsolete forces by-hand validation
@@ -78,6 +76,8 @@
 #define DST_OBSOLETE_KILL	-2
 	unsigned short		header_len;	/* more space at head required */
 	unsigned short		trailer_len;	/* space to reserve at tail */
+	unsigned short		__pad3;
+
 #ifdef CONFIG_IP_ROUTE_CLASSID
 	__u32			tclassid;
 #else
@@ -110,10 +110,16 @@
 	};
 };
 
+struct dst_metrics {
+	u32		metrics[RTAX_MAX];
+	atomic_t	refcnt;
+} __aligned(4);		/* Low pointer bits contain DST_METRICS_FLAGS */
+extern const struct dst_metrics dst_default_metrics;
+
 u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
-extern const u32 dst_default_metrics[];
 
 #define DST_METRICS_READ_ONLY		0x1UL
+#define DST_METRICS_REFCOUNTED		0x2UL
 #define DST_METRICS_FLAGS		0x3UL
 #define __DST_METRICS_PTR(Y)	\
 	((u32 *)((Y) & ~DST_METRICS_FLAGS))
@@ -392,9 +398,8 @@
 static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev,
 				 struct net *net)
 {
-	/* TODO : stats should be SMP safe */
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += skb->len;
+	DEV_STATS_INC(dev, rx_packets);
+	DEV_STATS_ADD(dev, rx_bytes, skb->len);
 	__skb_tunnel_rx(skb, dev, net);
 }
 
@@ -431,7 +436,6 @@
 
 static inline void dst_confirm(struct dst_entry *dst)
 {
-	dst->pending_confirm = 1;
 }
 
 static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
@@ -439,15 +443,6 @@
 {
 	const struct hh_cache *hh;
 
-	if (dst->pending_confirm) {
-		unsigned long now = jiffies;
-
-		dst->pending_confirm = 0;
-		/* avoid dirtying neighbour */
-		if (n->confirmed != now)
-			n->confirmed = now;
-	}
-
 	hh = &n->hh;
 	if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
 		return neigh_hh_output(hh, skb);
@@ -464,10 +459,25 @@
 static inline struct neighbour *dst_neigh_lookup_skb(const struct dst_entry *dst,
 						     struct sk_buff *skb)
 {
-	struct neighbour *n =  dst->ops->neigh_lookup(dst, skb, NULL);
+	struct neighbour *n = NULL;
+
+	/* The packets from tunnel devices (eg bareudp) may have only
+	 * metadata in the dst pointer of skb. Hence a pointer check of
+	 * neigh_lookup is needed.
+	 */
+	if (dst->ops->neigh_lookup)
+		n = dst->ops->neigh_lookup(dst, skb, NULL);
+
 	return IS_ERR(n) ? NULL : n;
 }
 
+static inline void dst_confirm_neigh(const struct dst_entry *dst,
+				     const void *daddr)
+{
+	if (dst->ops->confirm_neigh)
+		dst->ops->confirm_neigh(dst, daddr);
+}
+
 static inline void dst_link_failure(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb_dst(skb);
--- linux-4.4.0.orig/include/net/dst_cache.h
+++ linux-4.4.0/include/net/dst_cache.h
@@ -0,0 +1,97 @@
+#ifndef _NET_DST_CACHE_H
+#define _NET_DST_CACHE_H
+
+#include <linux/jiffies.h>
+#include <net/dst.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ip6_fib.h>
+#endif
+
+struct dst_cache {
+	struct dst_cache_pcpu __percpu *cache;
+	unsigned long reset_ts;
+};
+
+/**
+ *	dst_cache_get - perform cache lookup
+ *	@dst_cache: the cache
+ *
+ *	The caller should use dst_cache_get_ip4() if it need to retrieve the
+ *	source address to be used when xmitting to the cached dst.
+ *	local BH must be disabled.
+ */
+struct dst_entry *dst_cache_get(struct dst_cache *dst_cache);
+
+/**
+ *	dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address
+ *	@dst_cache: the cache
+ *	@saddr: return value for the retrieved source address
+ *
+ *	local BH must be disabled.
+ */
+struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr);
+
+/**
+ *	dst_cache_set_ip4 - store the ipv4 dst into the cache
+ *	@dst_cache: the cache
+ *	@dst: the entry to be cached
+ *	@saddr: the source address to be stored inside the cache
+ *
+ *	local BH must be disabled.
+ */
+void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
+		       __be32 saddr);
+
+#if IS_ENABLED(CONFIG_IPV6)
+
+/**
+ *	dst_cache_set_ip6 - store the ipv6 dst into the cache
+ *	@dst_cache: the cache
+ *	@dst: the entry to be cached
+ *	@saddr: the source address to be stored inside the cache
+ *
+ *	local BH must be disabled.
+ */
+void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+		       const struct in6_addr *addr);
+
+/**
+ *	dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address
+ *	@dst_cache: the cache
+ *	@saddr: return value for the retrieved source address
+ *
+ *	local BH must be disabled.
+ */
+struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
+				    struct in6_addr *saddr);
+#endif
+
+/**
+ *	dst_cache_reset - invalidate the cache contents
+ *	@dst_cache: the cache
+ *
+ *	This do not free the cached dst to avoid races and contentions.
+ *	the dst will be freed on later cache lookup.
+ */
+static inline void dst_cache_reset(struct dst_cache *dst_cache)
+{
+	dst_cache->reset_ts = jiffies;
+}
+
+/**
+ *	dst_cache_init - initialize the cache, allocating the required storage
+ *	@dst_cache: the cache
+ *	@gfp: allocation flags
+ */
+int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp);
+
+/**
+ *	dst_cache_destroy - empty the cache and free the allocated storage
+ *	@dst_cache: the cache
+ *
+ *	No synchronization is enforced: it must be called only when the cache
+ *	is unsed.
+ */
+void dst_cache_destroy(struct dst_cache *dst_cache);
+
+#endif
--- linux-4.4.0.orig/include/net/dst_metadata.h
+++ linux-4.4.0/include/net/dst_metadata.h
@@ -44,6 +44,24 @@
 	return dst && !(dst->flags & DST_METADATA);
 }
 
+static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
+				       const struct sk_buff *skb_b)
+{
+	const struct metadata_dst *a, *b;
+
+	if (!(skb_a->_skb_refdst | skb_b->_skb_refdst))
+		return 0;
+
+	a = (const struct metadata_dst *) skb_dst(skb_a);
+	b = (const struct metadata_dst *) skb_dst(skb_b);
+
+	if (!a != !b || a->u.tun_info.options_len != b->u.tun_info.options_len)
+		return 1;
+
+	return memcmp(&a->u.tun_info, &b->u.tun_info,
+		      sizeof(a->u.tun_info) + a->u.tun_info.options_len);
+}
+
 struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags);
 struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags);
 
--- linux-4.4.0.orig/include/net/dst_ops.h
+++ linux-4.4.0/include/net/dst_ops.h
@@ -33,6 +33,8 @@
 	struct neighbour *	(*neigh_lookup)(const struct dst_entry *dst,
 						struct sk_buff *skb,
 						const void *daddr);
+	void			(*confirm_neigh)(const struct dst_entry *dst,
+						 const void *daddr);
 
 	struct kmem_cache	*kmem_cachep;
 
--- linux-4.4.0.orig/include/net/fib_rules.h
+++ linux-4.4.0/include/net/fib_rules.h
@@ -85,6 +85,7 @@
 	[FRA_OIFNAME]	= { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \
 	[FRA_PRIORITY]	= { .type = NLA_U32 }, \
 	[FRA_FWMARK]	= { .type = NLA_U32 }, \
+	[FRA_TUN_ID]	= { .type = NLA_U64 }, \
 	[FRA_FWMASK]	= { .type = NLA_U32 }, \
 	[FRA_TABLE]     = { .type = NLA_U32 }, \
 	[FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
--- linux-4.4.0.orig/include/net/flow_dissector.h
+++ linux-4.4.0/include/net/flow_dissector.h
@@ -3,6 +3,8 @@
 
 #include <linux/types.h>
 #include <linux/in6.h>
+#include <linux/siphash.h>
+#include <linux/string.h>
 #include <uapi/linux/if_ether.h>
 
 /**
@@ -146,7 +148,7 @@
 struct flow_keys {
 	struct flow_dissector_key_control control;
 #define FLOW_KEYS_HASH_START_FIELD basic
-	struct flow_dissector_key_basic basic;
+	struct flow_dissector_key_basic basic __aligned(SIPHASH_ALIGNMENT);
 	struct flow_dissector_key_tags tags;
 	struct flow_dissector_key_keyid keyid;
 	struct flow_dissector_key_ports ports;
@@ -184,4 +186,12 @@
 
 u32 flow_hash_from_keys(struct flow_keys *keys);
 
+static inline void
+flow_dissector_init_keys(struct flow_dissector_key_control *key_control,
+			 struct flow_dissector_key_basic *key_basic)
+{
+	memset(key_control, 0, sizeof(*key_control));
+	memset(key_basic, 0, sizeof(*key_basic));
+}
+
 #endif
--- linux-4.4.0.orig/include/net/genetlink.h
+++ linux-4.4.0/include/net/genetlink.h
@@ -33,12 +33,6 @@
  *	do additional, common, filtering and return an error
  * @post_doit: called after an operation's doit callback, it may
  *	undo operations done by pre_doit, for example release locks
- * @mcast_bind: a socket bound to the given multicast group (which
- *	is given as the offset into the groups array)
- * @mcast_unbind: a socket was unbound from the given multicast group.
- *	Note that unbind() will not be called symmetrically if the
- *	generic netlink family is removed while there are still open
- *	sockets.
  * @attrbuf: buffer to store parsed attributes
  * @family_list: family list
  * @mcgrps: multicast groups used by this family (private)
@@ -61,8 +55,6 @@
 	void			(*post_doit)(const struct genl_ops *ops,
 					     struct sk_buff *skb,
 					     struct genl_info *info);
-	int			(*mcast_bind)(struct net *net, int group);
-	void			(*mcast_unbind)(struct net *net, int group);
 	struct nlattr **	attrbuf;	/* private */
 	const struct genl_ops *	ops;		/* private */
 	const struct genl_multicast_group *mcgrps; /* private */
@@ -114,6 +106,7 @@
  * @flags: flags
  * @policy: attribute validation policy
  * @doit: standard command callback
+ * @start: start callback for dumps
  * @dumpit: callback for dumpers
  * @done: completion callback for dumps
  * @ops_list: operations list
@@ -122,6 +115,7 @@
 	const struct nla_policy	*policy;
 	int		       (*doit)(struct sk_buff *skb,
 				       struct genl_info *info);
+	int		       (*start)(struct netlink_callback *cb);
 	int		       (*dumpit)(struct sk_buff *skb,
 					 struct netlink_callback *cb);
 	int		       (*done)(struct netlink_callback *cb);
--- linux-4.4.0.orig/include/net/geneve.h
+++ linux-4.4.0/include/net/geneve.h
@@ -62,6 +62,14 @@
 	struct geneve_opt options[];
 };
 
+#if IS_ENABLED(CONFIG_GENEVE)
+void geneve_get_rx_port(struct net_device *netdev);
+#else
+static inline void geneve_get_rx_port(struct net_device *netdev)
+{
+}
+#endif
+
 #ifdef CONFIG_INET
 struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
 					u8 name_assign_type, u16 dst_port);
--- linux-4.4.0.orig/include/net/gro_cells.h
+++ linux-4.4.0/include/net/gro_cells.h
@@ -19,22 +19,30 @@
 	struct gro_cell *cell;
 	struct net_device *dev = skb->dev;
 
+	rcu_read_lock();
+	if (unlikely(!(dev->flags & IFF_UP)))
+		goto drop;
+
 	if (!gcells->cells || skb_cloned(skb) || !(dev->features & NETIF_F_GRO)) {
 		netif_rx(skb);
-		return;
+		goto unlock;
 	}
 
 	cell = this_cpu_ptr(gcells->cells);
 
 	if (skb_queue_len(&cell->napi_skbs) > netdev_max_backlog) {
+drop:
 		atomic_long_inc(&dev->rx_dropped);
 		kfree_skb(skb);
-		return;
+		goto unlock;
 	}
 
 	__skb_queue_tail(&cell->napi_skbs, skb);
 	if (skb_queue_len(&cell->napi_skbs) == 1)
 		napi_schedule(&cell->napi);
+
+unlock:
+	rcu_read_unlock();
 }
 
 /* called under BH context */
@@ -84,6 +92,7 @@
 	for_each_possible_cpu(i) {
 		struct gro_cell *cell = per_cpu_ptr(gcells->cells, i);
 
+		napi_disable(&cell->napi);
 		netif_napi_del(&cell->napi);
 		__skb_queue_purge(&cell->napi_skbs);
 	}
--- linux-4.4.0.orig/include/net/icmp.h
+++ linux-4.4.0/include/net/icmp.h
@@ -22,6 +22,7 @@
 
 #include <net/inet_sock.h>
 #include <net/snmp.h>
+#include <net/ip.h>
 
 struct icmp_err {
   int		errno;
@@ -39,7 +40,13 @@
 struct sk_buff;
 struct net;
 
-void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info);
+void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
+		 const struct ip_options *opt);
+static inline void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
+{
+	__icmp_send(skb_in, type, code, info, &IPCB(skb_in)->opt);
+}
+
 int icmp_rcv(struct sk_buff *skb);
 void icmp_err(struct sk_buff *skb, u32 info);
 int icmp_init(void);
--- linux-4.4.0.orig/include/net/inet_connection_sock.h
+++ linux-4.4.0/include/net/inet_connection_sock.h
@@ -270,8 +270,9 @@
 					    struct sock *newsk,
 					    const struct request_sock *req);
 
-void inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req,
-			      struct sock *child);
+struct sock *inet_csk_reqsk_queue_add(struct sock *sk,
+				      struct request_sock *req,
+				      struct sock *child);
 void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
 				   unsigned long timeout);
 struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child,
@@ -288,11 +289,6 @@
 	return reqsk_queue_len(&inet_csk(sk)->icsk_accept_queue);
 }
 
-static inline int inet_csk_reqsk_queue_young(const struct sock *sk)
-{
-	return reqsk_queue_len_young(&inet_csk(sk)->icsk_accept_queue);
-}
-
 static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk)
 {
 	return inet_csk_reqsk_queue_len(sk) >= sk->sk_max_ack_backlog;
@@ -323,5 +319,18 @@
 int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
 			       char __user *optval, unsigned int optlen);
 
+/* update the fast reuse flag when adding a socket */
+void inet_csk_update_fastreuse(struct inet_bind_bucket *tb,
+			       struct sock *sk);
+
 struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu);
+
+static inline void inet_init_csk_locks(struct sock *sk)
+{
+	struct inet_connection_sock *icsk = inet_csk(sk);
+
+	spin_lock_init(&icsk->icsk_accept_queue.rskq_lock);
+	spin_lock_init(&icsk->icsk_accept_queue.fastopenq.lock);
+}
+
 #endif /* _INET_CONNECTION_SOCK_H */
--- linux-4.4.0.orig/include/net/inet_ecn.h
+++ linux-4.4.0/include/net/inet_ecn.h
@@ -3,6 +3,7 @@
 
 #include <linux/ip.h>
 #include <linux/skbuff.h>
+#include <linux/if_vlan.h>
 
 #include <net/inet_sock.h>
 #include <net/dsfield.h>
@@ -111,11 +112,25 @@
 
 struct ipv6hdr;
 
-static inline int IP6_ECN_set_ce(struct ipv6hdr *iph)
+/* Note:
+ * IP_ECN_set_ce() has to tweak IPV4 checksum when setting CE,
+ * meaning both changes have no effect on skb->csum if/when CHECKSUM_COMPLETE
+ * In IPv6 case, no checksum compensates the change in IPv6 header,
+ * so we have to update skb->csum.
+ */
+static inline int IP6_ECN_set_ce(struct sk_buff *skb, struct ipv6hdr *iph)
 {
+	__be32 from, to;
+
 	if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph)))
 		return 0;
-	*(__be32*)iph |= htonl(INET_ECN_CE << 20);
+
+	from = *(__be32 *)iph;
+	to = from | htonl(INET_ECN_CE << 20);
+	*(__be32 *)iph = to;
+	if (skb->ip_summed == CHECKSUM_COMPLETE)
+		skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)from),
+				     (__force __wsum)to);
 	return 1;
 }
 
@@ -142,7 +157,7 @@
 	case cpu_to_be16(ETH_P_IPV6):
 		if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
 		    skb_tail_pointer(skb))
-			return IP6_ECN_set_ce(ipv6_hdr(skb));
+			return IP6_ECN_set_ce(skb, ipv6_hdr(skb));
 		break;
 	}
 
--- linux-4.4.0.orig/include/net/inet_frag.h
+++ linux-4.4.0/include/net/inet_frag.h
@@ -1,18 +1,19 @@
 #ifndef __NET_FRAG_H__
 #define __NET_FRAG_H__
 
-#include <linux/percpu_counter.h>
+#include <linux/rhashtable.h>
 
 struct netns_frags {
-	/* The percpu_counter "mem" need to be cacheline aligned.
-	 *  mem.count must not share cacheline with other writers
-	 */
-	struct percpu_counter   mem ____cacheline_aligned_in_smp;
-
 	/* sysctls */
+	long			high_thresh;
+	long			low_thresh;
 	int			timeout;
-	int			high_thresh;
-	int			low_thresh;
+	struct inet_frags	*f;
+
+	struct rhashtable       rhashtable ____cacheline_aligned_in_smp;
+
+	/* Keep atomic mem on separate cachelines in structs that include it */
+	atomic_long_t		mem ____cacheline_aligned_in_smp;
 };
 
 /**
@@ -28,81 +29,75 @@
 	INET_FRAG_COMPLETE	= BIT(2),
 };
 
+struct frag_v4_compare_key {
+	__be32		saddr;
+	__be32		daddr;
+	u32		user;
+	u32		vif;
+	__be16		id;
+	u16		protocol;
+};
+
+struct frag_v6_compare_key {
+	struct in6_addr	saddr;
+	struct in6_addr	daddr;
+	u32		user;
+	__be32		id;
+	u32		iif;
+};
+
 /**
  * struct inet_frag_queue - fragment queue
  *
- * @lock: spinlock protecting the queue
+ * @node: rhash node
+ * @key: keys identifying this frag.
  * @timer: queue expiration timer
- * @list: hash bucket list
+ * @lock: spinlock protecting this frag
  * @refcnt: reference count of the queue
  * @fragments: received fragments head
+ * @rb_fragments: received fragments rb-tree root
  * @fragments_tail: received fragments tail
+ * @last_run_head: the head of the last "run". see ip_fragment.c
  * @stamp: timestamp of the last received fragment
  * @len: total length of the original datagram
  * @meat: length of received fragments so far
  * @flags: fragment queue flags
  * @max_size: maximum received fragment size
  * @net: namespace that this frag belongs to
- * @list_evictor: list of queues to forcefully evict (e.g. due to low memory)
+ * @rcu: rcu head for freeing deferall
  */
 struct inet_frag_queue {
-	spinlock_t		lock;
+	struct rhash_head	node;
+	union {
+		struct frag_v4_compare_key v4;
+		struct frag_v6_compare_key v6;
+	} key;
 	struct timer_list	timer;
-	struct hlist_node	list;
+	spinlock_t		lock;
 	atomic_t		refcnt;
-	struct sk_buff		*fragments;
+	struct sk_buff		*fragments;  /* used in 6lopwpan IPv6. */
+	struct rb_root		rb_fragments; /* Used in IPv4/IPv6. */
 	struct sk_buff		*fragments_tail;
+	struct sk_buff		*last_run_head;
 	ktime_t			stamp;
 	int			len;
 	int			meat;
 	__u8			flags;
 	u16			max_size;
-	struct netns_frags	*net;
-	struct hlist_node	list_evictor;
-};
-
-#define INETFRAGS_HASHSZ	1024
-
-/* averaged:
- * max_depth = default ipfrag_high_thresh / INETFRAGS_HASHSZ /
- *	       rounded up (SKB_TRUELEN(0) + sizeof(struct ipq or
- *	       struct frag_queue))
- */
-#define INETFRAGS_MAXDEPTH	128
-
-struct inet_frag_bucket {
-	struct hlist_head	chain;
-	spinlock_t		chain_lock;
+	struct netns_frags      *net;
+	struct rcu_head		rcu;
 };
 
 struct inet_frags {
-	struct inet_frag_bucket	hash[INETFRAGS_HASHSZ];
-
-	struct work_struct	frags_work;
-	unsigned int next_bucket;
-	unsigned long last_rebuild_jiffies;
-	bool rebuild;
-
-	/* The first call to hashfn is responsible to initialize
-	 * rnd. This is best done with net_get_random_once.
-	 *
-	 * rnd_seqlock is used to let hash insertion detect
-	 * when it needs to re-lookup the hash chain to use.
-	 */
-	u32			rnd;
-	seqlock_t		rnd_seqlock;
 	int			qsize;
 
-	unsigned int		(*hashfn)(const struct inet_frag_queue *);
-	bool			(*match)(const struct inet_frag_queue *q,
-					 const void *arg);
 	void			(*constructor)(struct inet_frag_queue *q,
 					       const void *arg);
 	void			(*destructor)(struct inet_frag_queue *);
-	void			(*skb_free)(struct sk_buff *);
 	void			(*frag_expire)(unsigned long data);
 	struct kmem_cache	*frags_cachep;
 	const char		*frags_cache_name;
+	struct rhashtable_params rhash_params;
 };
 
 int inet_frags_init(struct inet_frags *);
@@ -110,67 +105,39 @@
 
 static inline int inet_frags_init_net(struct netns_frags *nf)
 {
-	return percpu_counter_init(&nf->mem, 0, GFP_KERNEL);
-}
-static inline void inet_frags_uninit_net(struct netns_frags *nf)
-{
-	percpu_counter_destroy(&nf->mem);
+	atomic_long_set(&nf->mem, 0);
+	return rhashtable_init(&nf->rhashtable, &nf->f->rhash_params);
 }
+void inet_frags_exit_net(struct netns_frags *nf);
 
-void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f);
+void inet_frag_kill(struct inet_frag_queue *q);
+void inet_frag_destroy(struct inet_frag_queue *q);
+struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, void *key);
 
-void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);
-void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f);
-struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
-		struct inet_frags *f, void *key, unsigned int hash);
+/* Free all skbs in the queue; return the sum of their truesizes. */
+unsigned int inet_frag_rbtree_purge(struct rb_root *root);
 
-void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q,
-				   const char *prefix);
-
-static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f)
+static inline void inet_frag_put(struct inet_frag_queue *q)
 {
 	if (atomic_dec_and_test(&q->refcnt))
-		inet_frag_destroy(q, f);
-}
-
-static inline bool inet_frag_evicting(struct inet_frag_queue *q)
-{
-	return !hlist_unhashed(&q->list_evictor);
+		inet_frag_destroy(q);
 }
 
 /* Memory Tracking Functions. */
 
-/* The default percpu_counter batch size is not big enough to scale to
- * fragmentation mem acct sizes.
- * The mem size of a 64K fragment is approx:
- *  (44 fragments * 2944 truesize) + frag_queue struct(200) = 129736 bytes
- */
-static unsigned int frag_percpu_counter_batch = 130000;
-
-static inline int frag_mem_limit(struct netns_frags *nf)
+static inline long frag_mem_limit(const struct netns_frags *nf)
 {
-	return percpu_counter_read(&nf->mem);
+	return atomic_long_read(&nf->mem);
 }
 
-static inline void sub_frag_mem_limit(struct netns_frags *nf, int i)
+static inline void sub_frag_mem_limit(struct netns_frags *nf, long val)
 {
-	__percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch);
+	atomic_long_sub(val, &nf->mem);
 }
 
-static inline void add_frag_mem_limit(struct netns_frags *nf, int i)
+static inline void add_frag_mem_limit(struct netns_frags *nf, long val)
 {
-	__percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch);
-}
-
-static inline unsigned int sum_frag_mem_limit(struct netns_frags *nf)
-{
-	unsigned int res;
-
-	local_bh_disable();
-	res = percpu_counter_sum_positive(&nf->mem);
-	local_bh_enable();
-
-	return res;
+	atomic_long_add(val, &nf->mem);
 }
 
 /* RFC 3168 support :
@@ -184,4 +151,16 @@
 
 extern const u8 ip_frag_ecn_table[16];
 
+/* Return values of inet_frag_queue_insert() */
+#define IPFRAG_OK	0
+#define IPFRAG_DUP	1
+#define IPFRAG_OVERLAP	2
+int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
+			   int offset, int end);
+void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,
+			      struct sk_buff *parent);
+void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
+			    void *reasm_data);
+struct sk_buff *inet_frag_pull_head(struct inet_frag_queue *q);
+
 #endif
--- linux-4.4.0.orig/include/net/inet_sock.h
+++ linux-4.4.0/include/net/inet_sock.h
@@ -95,7 +95,7 @@
 	kmemcheck_bitfield_end(flags);
 	u32                     ir_mark;
 	union {
-		struct ip_options_rcu	*opt;
+		struct ip_options_rcu __rcu	*ireq_opt;
 		struct sk_buff		*pktopts;
 	};
 };
@@ -113,6 +113,12 @@
 	return sk->sk_mark;
 }
 
+static inline struct ip_options_rcu *ireq_opt_deref(const struct inet_request_sock *ireq)
+{
+	return rcu_dereference_check(ireq->ireq_opt,
+				     atomic_read(&ireq->req.rsk_refcnt) > 0);
+}
+
 struct inet_cork {
 	unsigned int		flags;
 	__be32			addr;
--- linux-4.4.0.orig/include/net/inet_timewait_sock.h
+++ linux-4.4.0/include/net/inet_timewait_sock.h
@@ -55,6 +55,7 @@
 #define tw_family		__tw_common.skc_family
 #define tw_state		__tw_common.skc_state
 #define tw_reuse		__tw_common.skc_reuse
+#define tw_reuseport		__tw_common.skc_reuseport
 #define tw_ipv6only		__tw_common.skc_ipv6only
 #define tw_bound_dev_if		__tw_common.skc_bound_dev_if
 #define tw_node			__tw_common.skc_nulls_node
--- linux-4.4.0.orig/include/net/inetpeer.h
+++ linux-4.4.0/include/net/inetpeer.h
@@ -40,6 +40,7 @@
 
 	u32			metrics[RTAX_MAX];
 	u32			rate_tokens;	/* rate limiting for ICMP */
+	u32			n_redirects;
 	unsigned long		rate_last;
 	union {
 		struct list_head	gc_list;
--- linux-4.4.0.orig/include/net/ip.h
+++ linux-4.4.0/include/net/ip.h
@@ -33,6 +33,8 @@
 #include <net/flow.h>
 #include <net/flow_dissector.h>
 
+#define IPV4_MIN_MTU		68			/* RFC 791 */
+
 struct sock;
 
 struct inet_skb_parm {
@@ -277,6 +279,13 @@
 	return --iph->ttl;
 }
 
+static inline int ip_mtu_locked(const struct dst_entry *dst)
+{
+	const struct rtable *rt = (const struct rtable *)dst;
+
+	return rt->rt_mtu_locked || dst_metric_locked(dst, RTAX_MTU);
+}
+
 static inline
 int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst)
 {
@@ -284,7 +293,7 @@
 
 	return  pmtudisc == IP_PMTUDISC_DO ||
 		(pmtudisc == IP_PMTUDISC_WANT &&
-		 !(dst_metric_locked(dst, RTAX_MTU)));
+		 !ip_mtu_locked(dst));
 }
 
 static inline bool ip_sk_accept_pmtu(const struct sock *sk)
@@ -308,13 +317,19 @@
 						    bool forwarding)
 {
 	struct net *net = dev_net(dst->dev);
+	unsigned int mtu;
 
 	if (net->ipv4.sysctl_ip_fwd_use_pmtu ||
-	    dst_metric_locked(dst, RTAX_MTU) ||
+	    ip_mtu_locked(dst) ||
 	    !forwarding)
 		return dst_mtu(dst);
 
-	return min(dst->dev->mtu, IP_MAX_MTU);
+	/* 'forwarding = true' case should always honour route mtu */
+	mtu = dst_metric_raw(dst, RTAX_MTU);
+	if (mtu)
+		return mtu;
+
+	return min(READ_ONCE(dst->dev->mtu), IP_MAX_MTU);
 }
 
 static inline unsigned int ip_skb_dst_mtu(const struct sk_buff *skb)
@@ -327,7 +342,7 @@
 		return ip_dst_mtu_maybe_forward(skb_dst(skb), forwarding);
 	}
 
-	return min(skb_dst(skb)->dev->mtu, IP_MAX_MTU);
+	return min(READ_ONCE(skb_dst(skb)->dev->mtu), IP_MAX_MTU);
 }
 
 u32 ip_idents_reserve(u32 hash, int segs);
@@ -338,19 +353,18 @@
 {
 	struct iphdr *iph = ip_hdr(skb);
 
+	/* We had many attacks based on IPID, use the private
+	 * generator as much as we can.
+	 */
+	if (sk && inet_sk(sk)->inet_daddr) {
+		iph->id = htons(inet_sk(sk)->inet_id);
+		inet_sk(sk)->inet_id += segs;
+		return;
+	}
 	if ((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) {
-		/* This is only to work around buggy Windows95/2000
-		 * VJ compression implementations.  If the ID field
-		 * does not change, they drop every other packet in
-		 * a TCP stream using header compression.
-		 */
-		if (sk && inet_sk(sk)->inet_daddr) {
-			iph->id = htons(inet_sk(sk)->inet_id);
-			inet_sk(sk)->inet_id += segs;
-		} else {
-			iph->id = 0;
-		}
+		iph->id = 0;
 	} else {
+		/* Unfortunately we need the big hammer to get a suitable IPID */
 		__ip_select_ident(net, iph, segs);
 	}
 }
@@ -515,7 +529,6 @@
 	return skb;
 }
 #endif
-int ip_frag_mem(struct net *net);
 
 /*
  *	Functions provided by ip_forward.c
@@ -538,6 +551,8 @@
 }
 
 void ip_options_fragment(struct sk_buff *skb);
+int __ip_options_compile(struct net *net, struct ip_options *opt,
+			 struct sk_buff *skb, __be32 *info);
 int ip_options_compile(struct net *net, struct ip_options *opt,
 		       struct sk_buff *skb);
 int ip_options_get(struct net *net, struct ip_options_rcu **optp,
@@ -553,7 +568,7 @@
  */
 
 void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb);
-void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int offset);
+void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int tlen, int offset);
 int ip_cmsg_send(struct net *net, struct msghdr *msg,
 		 struct ipcm_cookie *ipc, bool allow_ipv6);
 int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
@@ -575,7 +590,7 @@
 
 static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 {
-	ip_cmsg_recv_offset(msg, skb, 0);
+	ip_cmsg_recv_offset(msg, skb, 0, 0);
 }
 
 bool icmp_global_allow(void);
@@ -586,4 +601,9 @@
 int ip_misc_proc_init(void);
 #endif
 
+static inline bool inetdev_valid_mtu(unsigned int mtu)
+{
+	return likely(mtu >= IPV4_MIN_MTU);
+}
+
 #endif	/* _IP_H */
--- linux-4.4.0.orig/include/net/ip6_fib.h
+++ linux-4.4.0/include/net/ip6_fib.h
@@ -68,6 +68,7 @@
 	__u16			fn_flags;
 	int			fn_sernum;
 	struct rt6_info		*rr_ptr;
+	struct rcu_head		rcu;
 };
 
 #ifndef CONFIG_IPV6_SUBTREES
@@ -102,7 +103,7 @@
 	 * the same cache line.
 	 */
 	struct fib6_table		*rt6i_table;
-	struct fib6_node		*rt6i_node;
+	struct fib6_node __rcu		*rt6i_node;
 
 	struct in6_addr			rt6i_gateway;
 
@@ -165,13 +166,40 @@
 	rt0->rt6i_flags |= RTF_EXPIRES;
 }
 
+/* Function to safely get fn->sernum for passed in rt
+ * and store result in passed in cookie.
+ * Return true if we can get cookie safely
+ * Return false if not
+ */
+static inline bool rt6_get_cookie_safe(const struct rt6_info *rt,
+				       u32 *cookie)
+{
+	struct fib6_node *fn;
+	bool status = false;
+
+	rcu_read_lock();
+	fn = rcu_dereference(rt->rt6i_node);
+
+	if (fn) {
+		*cookie = fn->fn_sernum;
+		status = true;
+	}
+
+	rcu_read_unlock();
+	return status;
+}
+
 static inline u32 rt6_get_cookie(const struct rt6_info *rt)
 {
+	u32 cookie = 0;
+
 	if (rt->rt6i_flags & RTF_PCPU ||
 	    (unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from))
 		rt = (struct rt6_info *)(rt->dst.from);
 
-	return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+	rt6_get_cookie_safe(rt, &cookie);
+
+	return cookie;
 }
 
 static inline void ip6_rt_put(struct rt6_info *rt)
@@ -230,6 +258,8 @@
 	rwlock_t		tb6_lock;
 	struct fib6_node	tb6_root;
 	struct inet_peer_base	tb6_peers;
+	unsigned int		flags;
+#define RT6_TABLE_HAS_DFLT_ROUTER	BIT(0)
 };
 
 #define RT6_TABLE_UNSPEC	RT_TABLE_UNSPEC
--- linux-4.4.0.orig/include/net/ip6_route.h
+++ linux-4.4.0/include/net/ip6_route.h
@@ -21,6 +21,7 @@
 #include <net/flow.h>
 #include <net/ip6_fib.h>
 #include <net/sock.h>
+#include <net/lwtunnel.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/route.h>
@@ -64,11 +65,20 @@
 
 void ip6_route_input(struct sk_buff *skb);
 
-struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
-				   struct flowi6 *fl6);
+struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
+					 struct flowi6 *fl6, int flags);
+
+static inline struct dst_entry *ip6_route_output(struct net *net,
+						 const struct sock *sk,
+						 struct flowi6 *fl6)
+{
+	return ip6_route_output_flags(net, sk, fl6, 0);
+}
+
 struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
 				   int flags);
 
+void ip6_route_init_special_entries(void);
 int ip6_route_init(void);
 void ip6_route_cleanup(void);
 
@@ -93,6 +103,9 @@
 struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 				    const struct in6_addr *addr, bool anycast);
 
+struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
+			       int flags);
+
 /*
  *	support functions for ND
  *
@@ -161,6 +174,7 @@
 
 	return rt->rt6i_flags & RTF_ANYCAST ||
 		(rt->rt6i_dst.plen != 128 &&
+		 !(rt->rt6i_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) &&
 		 ipv6_addr_equal(&rt->rt6i_dst.addr, daddr));
 }
 
@@ -199,4 +213,11 @@
 		return daddr;
 }
 
+static inline bool rt6_duplicate_nexthop(struct rt6_info *a, struct rt6_info *b)
+{
+	return a->dst.dev == b->dst.dev &&
+	       a->rt6i_idev == b->rt6i_idev &&
+	       ipv6_addr_equal(&a->rt6i_gateway, &b->rt6i_gateway) &&
+	       !lwtunnel_cmp_encap(a->dst.lwtstate, b->dst.lwtstate);
+}
 #endif
--- linux-4.4.0.orig/include/net/ip6_tunnel.h
+++ linux-4.4.0/include/net/ip6_tunnel.h
@@ -5,6 +5,8 @@
 #include <linux/netdevice.h>
 #include <linux/if_tunnel.h>
 #include <linux/ip6_tunnel.h>
+#include <net/ip_tunnels.h>
+#include <net/dst_cache.h>
 
 #define IP6TUNNEL_ERR_TIMEO (30*HZ)
 
@@ -32,12 +34,6 @@
 	__be32			o_key;
 };
 
-struct ip6_tnl_dst {
-	seqlock_t lock;
-	struct dst_entry __rcu *dst;
-	u32 cookie;
-};
-
 /* IPv6 tunnel */
 struct ip6_tnl {
 	struct ip6_tnl __rcu *next;	/* next tunnel in list */
@@ -45,7 +41,7 @@
 	struct net *net;	/* netns for packet i/o */
 	struct __ip6_tnl_parm parms;	/* tunnel configuration parameters */
 	struct flowi fl;	/* flowi template for xmit */
-	struct ip6_tnl_dst __percpu *dst_cache;	/* cached dst */
+	struct dst_cache dst_cache;	/* cached dst */
 
 	int err_count;
 	unsigned long err_time;
@@ -65,11 +61,6 @@
 	__u8 encap_limit;	/* tunnel encapsulation limit   */
 } __packed;
 
-struct dst_entry *ip6_tnl_dst_get(struct ip6_tnl *t);
-int ip6_tnl_dst_init(struct ip6_tnl *t);
-void ip6_tnl_dst_destroy(struct ip6_tnl *t);
-void ip6_tnl_dst_reset(struct ip6_tnl *t);
-void ip6_tnl_dst_set(struct ip6_tnl *t, struct dst_entry *dst);
 int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
 		const struct in6_addr *raddr);
 int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
@@ -86,6 +77,7 @@
 	struct net_device_stats *stats = &dev->stats;
 	int pkt_len, err;
 
+	memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
 	pkt_len = skb->len - skb_inner_network_offset(skb);
 	err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
 
--- linux-4.4.0.orig/include/net/ip_fib.h
+++ linux-4.4.0/include/net/ip_fib.h
@@ -56,11 +56,13 @@
 	int				fnhe_genid;
 	__be32				fnhe_daddr;
 	u32				fnhe_pmtu;
+	bool				fnhe_mtu_locked;
 	__be32				fnhe_gw;
 	unsigned long			fnhe_expires;
 	struct rtable __rcu		*fnhe_rth_input;
 	struct rtable __rcu		*fnhe_rth_output;
 	unsigned long			fnhe_stamp;
+	struct rcu_head			rcu;
 };
 
 struct fnhe_hash_bucket {
@@ -110,12 +112,13 @@
 	unsigned char		fib_scope;
 	unsigned char		fib_type;
 	__be32			fib_prefsrc;
+	u32			fib_tb_id;
 	u32			fib_priority;
-	u32			*fib_metrics;
-#define fib_mtu fib_metrics[RTAX_MTU-1]
-#define fib_window fib_metrics[RTAX_WINDOW-1]
-#define fib_rtt fib_metrics[RTAX_RTT-1]
-#define fib_advmss fib_metrics[RTAX_ADVMSS-1]
+	struct dst_metrics	*fib_metrics;
+#define fib_mtu fib_metrics->metrics[RTAX_MTU-1]
+#define fib_window fib_metrics->metrics[RTAX_WINDOW-1]
+#define fib_rtt fib_metrics->metrics[RTAX_RTT-1]
+#define fib_advmss fib_metrics->metrics[RTAX_ADVMSS-1]
 	int			fib_nhs;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 	int			fib_weight;
@@ -198,7 +201,7 @@
 int fib_table_delete(struct fib_table *, struct fib_config *);
 int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
 		   struct netlink_callback *cb);
-int fib_table_flush(struct fib_table *table);
+int fib_table_flush(struct fib_table *table, bool flush_all);
 struct fib_table *fib_trie_unmerge(struct fib_table *main_tb);
 void fib_table_flush_external(struct fib_table *table);
 void fib_free_table(struct fib_table *tb);
@@ -318,8 +321,9 @@
 /* Exported by fib_semantics.c */
 int ip_fib_check_default(__be32 gw, struct net_device *dev);
 int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force);
-int fib_sync_down_addr(struct net *net, __be32 local);
+int fib_sync_down_addr(struct net_device *dev, __be32 local);
 int fib_sync_up(struct net_device *dev, unsigned int nh_flags);
+void fib_sync_mtu(struct net_device *dev, u32 orig_mtu);
 
 extern u32 fib_multipath_secret __read_mostly;
 
--- linux-4.4.0.orig/include/net/ip_tunnels.h
+++ linux-4.4.0/include/net/ip_tunnels.h
@@ -13,6 +13,7 @@
 #include <net/netns/generic.h>
 #include <net/rtnetlink.h>
 #include <net/lwtunnel.h>
+#include <net/dst_cache.h>
 
 #if IS_ENABLED(CONFIG_IPV6)
 #include <net/ipv6.h>
@@ -85,12 +86,29 @@
 	struct rcu_head			rcu_head;
 };
 
-struct ip_tunnel_dst {
-	struct dst_entry __rcu 		*dst;
-	__be32				 saddr;
+struct metadata_dst;
+/* A fan overlay /8 (250.0.0.0/8, for example) maps to exactly one /16
+ * underlay (10.88.0.0/16, for example).  Multiple local addresses within
+ * the /16 may be used, but a particular overlay may not span
+ * multiple underlay subnets.
+ *
+ * We store one underlay, indexed by the overlay's high order octet.
+ */
+#define FAN_OVERLAY_CNT		256
+
+struct ip_fan_map {
+	__be32			underlay;
+	__be32			overlay;
+	u16			underlay_prefix;
+	u16			overlay_prefix;
+	u32			overlay_mask;
+	struct list_head	list;
+	struct rcu_head		rcu;
 };
 
-struct metadata_dst;
+struct ip_tunnel_fan {
+	struct list_head	fan_maps;
+};
 
 struct ip_tunnel {
 	struct ip_tunnel __rcu	*next;
@@ -108,7 +126,7 @@
 	int		tun_hlen;	/* Precalculated header length */
 	int		mlink;
 
-	struct ip_tunnel_dst __percpu *dst_cache;
+	struct dst_cache dst_cache;
 
 	struct ip_tunnel_parm parms;
 
@@ -123,6 +141,7 @@
 #endif
 	struct ip_tunnel_prl_entry __rcu *prl;	/* potential router list */
 	unsigned int		prl_count;	/* # of entries in PRL */
+	struct ip_tunnel_fan	fan;
 	int			ip_tnl_net_id;
 	struct gro_cells	gro_cells;
 	bool			collect_md;
@@ -144,6 +163,11 @@
 
 #define TUNNEL_OPTIONS_PRESENT	(TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT)
 
+static inline int fan_has_map(const struct ip_tunnel_fan *fan)
+{
+	return !list_empty(&fan->fan_maps);
+}
+
 struct tnl_ptk_info {
 	__be16 flags;
 	__be16 proto;
@@ -230,6 +254,7 @@
 int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
 int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
 		    u8 *protocol, struct flowi4 *fl4);
+int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict);
 int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu);
 
 struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
@@ -247,10 +272,29 @@
 int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
 		      struct ip_tunnel_parm *p);
 void ip_tunnel_setup(struct net_device *dev, int net_id);
-void ip_tunnel_dst_reset_all(struct ip_tunnel *t);
 int ip_tunnel_encap_setup(struct ip_tunnel *t,
 			  struct ip_tunnel_encap *ipencap);
 
+static inline bool pskb_inet_may_pull(struct sk_buff *skb)
+{
+	int nhlen;
+
+	switch (skb->protocol) {
+#if IS_ENABLED(CONFIG_IPV6)
+	case htons(ETH_P_IPV6):
+		nhlen = sizeof(struct ipv6hdr);
+		break;
+#endif
+	case htons(ETH_P_IP):
+		nhlen = sizeof(struct iphdr);
+		break;
+	default:
+		nhlen = 0;
+	}
+
+	return pskb_network_may_pull(skb, nhlen);
+}
+
 /* Extract dsfield from inner protocol */
 static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
 				       const struct sk_buff *skb)
@@ -282,6 +326,22 @@
 struct sk_buff *iptunnel_handle_offloads(struct sk_buff *skb, bool gre_csum,
 					 int gso_type_mask);
 
+static inline int iptunnel_pull_offloads(struct sk_buff *skb)
+{
+	if (skb_is_gso(skb)) {
+		int err;
+
+		err = skb_unclone(skb, GFP_ATOMIC);
+		if (unlikely(err))
+			return err;
+		skb_shinfo(skb)->gso_type &= ~(NETIF_F_GSO_ENCAP_ALL >>
+					       NETIF_F_GSO_SHIFT);
+	}
+
+	skb->encapsulation = 0;
+	return 0;
+}
+
 static inline void iptunnel_xmit_stats(int err,
 				       struct net_device_stats *err_stats,
 				       struct pcpu_sw_netstats __percpu *stats)
--- linux-4.4.0.orig/include/net/ip_vs.h
+++ linux-4.4.0/include/net/ip_vs.h
@@ -880,6 +880,7 @@
 	struct delayed_work	defense_work;   /* Work handler */
 	int			drop_rate;
 	int			drop_counter;
+	int			old_secure_tcp;
 	atomic_t		dropentry;
 	/* locks in ctl.c */
 	spinlock_t		dropentry_lock;  /* drop entry handling */
@@ -1588,6 +1589,23 @@
 }
 #endif /* CONFIG_IP_VS_NFCT */
 
+/* Really using conntrack? */
+static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
+					     struct sk_buff *skb)
+{
+#ifdef CONFIG_IP_VS_NFCT
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct;
+
+	if (!(cp->flags & IP_VS_CONN_F_NFCT))
+		return false;
+	ct = nf_ct_get(skb, &ctinfo);
+	if (ct && !nf_ct_is_untracked(ct))
+		return true;
+#endif
+	return false;
+}
+
 static inline int
 ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
 {
--- linux-4.4.0.orig/include/net/ipv6.h
+++ linux-4.4.0/include/net/ipv6.h
@@ -281,6 +281,7 @@
 			   int flags);
 int ip6_flowlabel_init(void);
 void ip6_flowlabel_cleanup(void);
+bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np);
 
 static inline void fl6_sock_release(struct ip6_flowlabel *fl)
 {
@@ -319,15 +320,8 @@
 	    idev->cnf.accept_ra;
 }
 
-#if IS_ENABLED(CONFIG_IPV6)
-static inline int ip6_frag_mem(struct net *net)
-{
-	return sum_frag_mem_limit(&net->ipv6.frags);
-}
-#endif
-
-#define IPV6_FRAG_HIGH_THRESH	(4 * 1024*1024)	/* 4194304 */
-#define IPV6_FRAG_LOW_THRESH	(3 * 1024*1024)	/* 3145728 */
+#define IPV6_FRAG_HIGH_THRESH	(256 * 1024)	/* 262144 */
+#define IPV6_FRAG_LOW_THRESH	(192 * 1024)	/* 196608 */
 #define IPV6_FRAG_TIMEOUT	(60 * HZ)	/* 60 seconds */
 
 int __ipv6_addr_type(const struct in6_addr *addr);
@@ -504,17 +498,8 @@
 	__IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX,
 };
 
-struct ip6_create_arg {
-	__be32 id;
-	u32 user;
-	const struct in6_addr *src;
-	const struct in6_addr *dst;
-	int iif;
-	u8 ecn;
-};
-
 void ip6_frag_init(struct inet_frag_queue *q, const void *a);
-bool ip6_frag_match(const struct inet_frag_queue *q, const void *a);
+extern const struct rhashtable_params ip6_rhash_params;
 
 /*
  *	Equivalent of ipv4 struct ip
@@ -522,19 +507,13 @@
 struct frag_queue {
 	struct inet_frag_queue	q;
 
-	__be32			id;		/* fragment id		*/
-	u32			user;
-	struct in6_addr		saddr;
-	struct in6_addr		daddr;
-
 	int			iif;
 	unsigned int		csum;
 	__u16			nhoffset;
 	u8			ecn;
 };
 
-void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
-			   struct inet_frags *frags);
+void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq);
 
 static inline bool ipv6_addr_any(const struct in6_addr *a)
 {
@@ -564,12 +543,8 @@
 /* more secured version of ipv6_addr_hash() */
 static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 initval)
 {
-	u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1];
-
-	return jhash_3words(v,
-			    (__force u32)a->s6_addr32[2],
-			    (__force u32)a->s6_addr32[3],
-			    initval);
+	return jhash2((__force const u32 *)a->s6_addr32,
+		      ARRAY_SIZE(a->s6_addr32), initval);
 }
 
 static inline bool ipv6_addr_loopback(const struct in6_addr *a)
@@ -744,6 +719,11 @@
 {
 	u32 hash;
 
+	/* @flowlabel may include more than a flow label, eg, the traffic class.
+	 * Here we want only the flow label value.
+	 */
+	flowlabel &= IPV6_FLOWLABEL_MASK;
+
 	if (flowlabel ||
 	    net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF ||
 	    (!autolabel &&
@@ -756,7 +736,7 @@
 	 * to minimize possbility that any useful information to an
 	 * attacker is leaked. Only lower 20 bits are relevant.
 	 */
-	rol32(hash, 16);
+	hash = rol32(hash, 16);
 
 	flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
 
@@ -869,7 +849,7 @@
 
 int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
 		   struct flowi6 *fl6);
-struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
+struct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, struct flowi6 *fl6,
 				      const struct in6_addr *final_dst);
 struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
 					 const struct in6_addr *final_dst);
@@ -931,6 +911,8 @@
 int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
 			   char __user *optval, int __user *optlen);
 
+int __ip6_datagram_connect(struct sock *sk, struct sockaddr *addr,
+			   int addr_len);
 int ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len);
 int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *addr,
 				 int addr_len);
@@ -958,6 +940,7 @@
  */
 extern const struct proto_ops inet6_stream_ops;
 extern const struct proto_ops inet6_dgram_ops;
+extern const struct proto_ops inet6_sockraw_ops;
 
 struct group_source_req;
 struct group_filter;
--- linux-4.4.0.orig/include/net/iw_handler.h
+++ linux-4.4.0/include/net/iw_handler.h
@@ -439,6 +439,12 @@
 /* Send a single event to user space */
 void wireless_send_event(struct net_device *dev, unsigned int cmd,
 			 union iwreq_data *wrqu, const char *extra);
+#ifdef CONFIG_WEXT_CORE
+/* flush all previous wext events - if work is done from netdev notifiers */
+void wireless_nlevent_flush(void);
+#else
+static inline void wireless_nlevent_flush(void) {}
+#endif
 
 /* We may need a function to send a stream of events to user space.
  * More on that later... */
@@ -550,7 +556,8 @@
 		memcpy(stream + lcp_len,
 		       ((char *) &iwe->u) + IW_EV_POINT_OFF,
 		       IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
-		memcpy(stream + point_len, extra, iwe->u.data.length);
+		if (iwe->u.data.length && extra)
+			memcpy(stream + point_len, extra, iwe->u.data.length);
 		stream += event_len;
 	}
 	return stream;
--- linux-4.4.0.orig/include/net/l3mdev.h
+++ linux-4.4.0/include/net/l3mdev.h
@@ -51,6 +51,24 @@
 	return ifindex;
 }
 
+static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
+{
+	struct net_device *dev;
+	int rc = 0;
+
+	if (likely(ifindex)) {
+		rcu_read_lock();
+
+		dev = dev_get_by_index_rcu(net, ifindex);
+		if (dev)
+			rc = l3mdev_master_ifindex_rcu(dev);
+
+		rcu_read_unlock();
+	}
+
+	return rc;
+}
+
 /* get index of an interface to use for FIB lookups. For devices
  * enslaved to an L3 master device FIB lookups are based on the
  * master index
@@ -169,6 +187,11 @@
 {
 	return 0;
 }
+
+static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
+{
+	return 0;
+}
 
 static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
 {
--- linux-4.4.0.orig/include/net/llc.h
+++ linux-4.4.0/include/net/llc.h
@@ -66,6 +66,7 @@
 	int sk_count;
 	struct hlist_nulls_head sk_laddr_hash[LLC_SK_LADDR_HASH_ENTRIES];
 	struct hlist_head sk_dev_hash[LLC_SK_DEV_HASH_ENTRIES];
+	struct rcu_head rcu;
 };
 
 static inline
@@ -116,6 +117,11 @@
 	atomic_inc(&sap->refcnt);
 }
 
+static inline bool llc_sap_hold_safe(struct llc_sap *sap)
+{
+	return atomic_inc_not_zero(&sap->refcnt);
+}
+
 void llc_sap_close(struct llc_sap *sap);
 
 static inline void llc_sap_put(struct llc_sap *sap)
--- linux-4.4.0.orig/include/net/llc_conn.h
+++ linux-4.4.0/include/net/llc_conn.h
@@ -97,6 +97,7 @@
 
 struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority,
 			  struct proto *prot, int kern);
+void llc_sk_stop_all_timers(struct sock *sk, bool sync);
 void llc_sk_free(struct sock *sk);
 
 void llc_sk_reset(struct sock *sk);
--- linux-4.4.0.orig/include/net/llc_pdu.h
+++ linux-4.4.0/include/net/llc_pdu.h
@@ -250,8 +250,7 @@
  */
 static inline void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa)
 {
-	if (skb->protocol == htons(ETH_P_802_2))
-		memcpy(sa, eth_hdr(skb)->h_source, ETH_ALEN);
+	memcpy(sa, eth_hdr(skb)->h_source, ETH_ALEN);
 }
 
 /**
@@ -263,8 +262,7 @@
  */
 static inline void llc_pdu_decode_da(struct sk_buff *skb, u8 *da)
 {
-	if (skb->protocol == htons(ETH_P_802_2))
-		memcpy(da, eth_hdr(skb)->h_dest, ETH_ALEN);
+	memcpy(da, eth_hdr(skb)->h_dest, ETH_ALEN);
 }
 
 /**
--- linux-4.4.0.orig/include/net/mac80211.h
+++ linux-4.4.0/include/net/mac80211.h
@@ -975,7 +975,7 @@
  * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware.
  * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame,
  *	verification has been done by the hardware.
- * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame.
+ * @RX_FLAG_IV_STRIPPED: The IV and ICV are stripped from this frame.
  *	If this flag is set, the stack cannot do any replay detection
  *	hence the driver or hardware will have to do that.
  * @RX_FLAG_PN_VALIDATED: Currently only valid for CCMP/GCMP frames, this
@@ -1013,6 +1013,8 @@
  *	on this subframe
  * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
  *	is stored in the @ampdu_delimiter_crc field)
+ * @RX_FLAG_MIC_STRIPPED: The mic was stripped of this packet. Decryption was
+ *	done by the hardware
  * @RX_FLAG_LDPC: LDPC was used
  * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3
  * @RX_FLAG_10MHZ: 10 MHz (half channel) was used
@@ -1029,6 +1031,11 @@
  * @RX_FLAG_RADIOTAP_VENDOR_DATA: This frame contains vendor-specific
  *	radiotap data in the skb->data (before the frame) as described by
  *	the &struct ieee80211_vendor_radiotap.
+ * @RX_FLAG_ALLOW_SAME_PN: Allow the same PN as same packet before.
+ *	This is used for AMSDU subframes which can have the same PN as
+ *	the first subframe.
+ * @RX_FLAG_ICV_STRIPPED: The ICV is stripped from this frame. CRC checking must
+ *	be done in the hardware.
  */
 enum mac80211_rx_flags {
 	RX_FLAG_MMIC_ERROR		= BIT(0),
@@ -1059,6 +1066,9 @@
 	RX_FLAG_5MHZ			= BIT(29),
 	RX_FLAG_AMSDU_MORE		= BIT(30),
 	RX_FLAG_RADIOTAP_VENDOR_DATA	= BIT(31),
+	RX_FLAG_MIC_STRIPPED		= BIT_ULL(32),
+	RX_FLAG_ALLOW_SAME_PN		= BIT_ULL(33),
+	RX_FLAG_ICV_STRIPPED		= BIT_ULL(34),
 };
 
 #define RX_FLAG_STBC_SHIFT		26
@@ -1113,7 +1123,7 @@
 	u64 mactime;
 	u32 device_timestamp;
 	u32 ampdu_reference;
-	u32 flag;
+	u64 flag;
 	u16 freq;
 	u8 vht_flag;
 	u8 rate_idx;
@@ -1662,6 +1672,9 @@
  * @supp_rates: Bitmap of supported rates (per band)
  * @ht_cap: HT capabilities of this STA; restricted to our own capabilities
  * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
+ * @max_rx_aggregation_subframes: maximal amount of frames in a single AMPDU
+ *	that this station is allowed to transmit to us.
+ *	Can be modified by driver.
  * @wme: indicates whether the STA supports QoS/WME (if local devices does,
  *	otherwise always false)
  * @drv_priv: data area for driver use, will always be aligned to
@@ -1688,6 +1701,7 @@
 	u16 aid;
 	struct ieee80211_sta_ht_cap ht_cap;
 	struct ieee80211_sta_vht_cap vht_cap;
+	u8 max_rx_aggregation_subframes;
 	bool wme;
 	u8 uapsd_queues;
 	u8 max_sp;
@@ -1901,6 +1915,11 @@
  * @IEEE80211_HW_BEACON_TX_STATUS: The device/driver provides TX status
  *	for sent beacons.
  *
+ * @IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR: Hardware (or driver) requires that each
+ *	station has a unique address, i.e. each station entry can be identified
+ *	by just its MAC address; this prevents, for example, the same station
+ *	from connecting to two virtual AP interfaces at the same time.
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -1936,6 +1955,7 @@
 	IEEE80211_HW_TDLS_WIDER_BW,
 	IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
 	IEEE80211_HW_BEACON_TX_STATUS,
+	IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
 
 	/* keep last, obviously */
 	NUM_IEEE80211_HW_FLAGS
@@ -2674,6 +2694,33 @@
 };
 
 /**
+ * struct ieee80211_ampdu_params - AMPDU action parameters
+ *
+ * @action: the ampdu action, value from %ieee80211_ampdu_mlme_action.
+ * @sta: peer of this AMPDU session
+ * @tid: tid of the BA session
+ * @ssn: start sequence number of the session. TX/RX_STOP can pass 0. When
+ *	action is set to %IEEE80211_AMPDU_RX_START the driver passes back the
+ *	actual ssn value used to start the session and writes the value here.
+ * @buf_size: reorder buffer size  (number of subframes). Valid only when the
+ *	action is set to %IEEE80211_AMPDU_RX_START or
+ *	%IEEE80211_AMPDU_TX_OPERATIONAL
+ * @amsdu: indicates the peer's ability to receive A-MSDU within A-MPDU.
+ *	valid when the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL
+ * @timeout: BA session timeout. Valid only when the action is set to
+ *	%IEEE80211_AMPDU_RX_START
+ */
+struct ieee80211_ampdu_params {
+	enum ieee80211_ampdu_mlme_action action;
+	struct ieee80211_sta *sta;
+	u16 tid;
+	u16 ssn;
+	u8 buf_size;
+	bool amsdu;
+	u16 timeout;
+};
+
+/**
  * enum ieee80211_frame_release_type - frame release reason
  * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll
  * @IEEE80211_FRAME_RELEASE_UAPSD: frame(s) released due to
@@ -3017,13 +3064,9 @@
  * @ampdu_action: Perform a certain A-MPDU action
  * 	The RA/TID combination determines the destination and TID we want
  * 	the ampdu action to be performed for. The action is defined through
- * 	ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
- * 	is the first frame we expect to perform the action on. Notice
- * 	that TX/RX_STOP can pass NULL for this parameter.
- *	The @buf_size parameter is only valid when the action is set to
- *	%IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's reorder
- *	buffer size (number of subframes) for this session -- the driver
- *	may neither send aggregates containing more subframes than this
+ *	ieee80211_ampdu_mlme_action.
+ *	When the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL the driver
+ *	may neither send aggregates containing more subframes than @buf_size
  *	nor send aggregates in a way that lost frames would exceed the
  *	buffer size. If just limiting the aggregate size, this would be
  *	possible with a buf_size of 8:
@@ -3034,9 +3077,6 @@
  *	buffer size of 8. Correct ways to retransmit #1 would be:
  *	 - TX:       1 or 18 or 81
  *	Even "189" would be wrong since 1 could be lost again.
- *	The @amsdu parameter is valid when the action is set to
- *	%IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's ability
- *	to receive A-MSDU within A-MPDU.
  *
  *	Returns a negative error code on failure.
  *	The callback can sleep.
@@ -3378,9 +3418,7 @@
 	int (*tx_last_beacon)(struct ieee80211_hw *hw);
 	int (*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, bool amsdu);
+			    struct ieee80211_ampdu_params *params);
 	int (*get_survey)(struct ieee80211_hw *hw, int idx,
 		struct survey_info *survey);
 	void (*rfkill_poll)(struct ieee80211_hw *hw);
@@ -3866,7 +3904,7 @@
  * The TX headroom reserved by mac80211 for its own tx_status functions.
  * This is enough for the radiotap header.
  */
-#define IEEE80211_TX_STATUS_HEADROOM	14
+#define IEEE80211_TX_STATUS_HEADROOM	ALIGN(14, 4)
 
 /**
  * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
--- linux-4.4.0.orig/include/net/ndisc.h
+++ linux-4.4.0/include/net/ndisc.h
@@ -172,6 +172,23 @@
 	return n;
 }
 
+static inline void __ipv6_confirm_neigh(struct net_device *dev,
+					const void *pkey)
+{
+	struct neighbour *n;
+
+	rcu_read_lock_bh();
+	n = __ipv6_neigh_lookup_noref(dev, pkey);
+	if (n) {
+		unsigned long now = jiffies;
+
+		/* avoid dirtying neighbour */
+		if (n->confirmed != now)
+			n->confirmed = now;
+	}
+	rcu_read_unlock_bh();
+}
+
 int ndisc_init(void);
 int ndisc_late_init(void);
 
--- linux-4.4.0.orig/include/net/neighbour.h
+++ linux-4.4.0/include/net/neighbour.h
@@ -425,8 +425,8 @@
 {
 	unsigned long now = jiffies;
 	
-	if (neigh->used != now)
-		neigh->used = now;
+	if (READ_ONCE(neigh->used) != now)
+		WRITE_ONCE(neigh->used, now);
 	if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
 		return __neigh_event_send(neigh, skb);
 	return 0;
@@ -448,23 +448,41 @@
 
 static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb)
 {
+	unsigned int hh_alen = 0;
 	unsigned int seq;
 	int hh_len;
 
 	do {
 		seq = read_seqbegin(&hh->hh_lock);
-		hh_len = hh->hh_len;
+		hh_len = READ_ONCE(hh->hh_len);
 		if (likely(hh_len <= HH_DATA_MOD)) {
-			/* this is inlined by gcc */
-			memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD);
+			hh_alen = HH_DATA_MOD;
+
+			/* skb_push() would proceed silently if we have room for
+			 * the unaligned size but not for the aligned size:
+			 * check headroom explicitly.
+			 */
+			if (likely(skb_headroom(skb) >= HH_DATA_MOD)) {
+				/* this is inlined by gcc */
+				memcpy(skb->data - HH_DATA_MOD, hh->hh_data,
+				       HH_DATA_MOD);
+			}
 		} else {
-			int hh_alen = HH_DATA_ALIGN(hh_len);
+			hh_alen = HH_DATA_ALIGN(hh_len);
 
-			memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
+			if (likely(skb_headroom(skb) >= hh_alen)) {
+				memcpy(skb->data - hh_alen, hh->hh_data,
+				       hh_alen);
+			}
 		}
 	} while (read_seqretry(&hh->hh_lock, seq));
 
-	skb_push(skb, hh_len);
+	if (WARN_ON_ONCE(skb_headroom(skb) < hh_alen)) {
+		kfree_skb(skb);
+		return NET_XMIT_DROP;
+	}
+
+	__skb_push(skb, hh_len);
 	return dev_queue_xmit(skb);
 }
 
--- linux-4.4.0.orig/include/net/net_namespace.h
+++ linux-4.4.0/include/net/net_namespace.h
@@ -53,12 +53,15 @@
 						 */
 	spinlock_t		rules_mod_lock;
 
+	u32			hash_mix;
 	atomic64_t		cookie_gen;
 
 	struct list_head	list;		/* list of network namespaces */
 	struct list_head	cleanup_list;	/* namespaces on death row */
 	struct list_head	exit_list;	/* Use only net_mutex */
 
+	struct llist_node	defer_free_list;
+
 	struct user_namespace   *user_ns;	/* Owning user namespace */
 	spinlock_t		nsid_lock;
 	struct idr		netns_ids;
@@ -115,12 +118,16 @@
 #endif
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
 	struct netns_nf_frag	nf_frag;
+	struct ctl_table_header *nf_frag_frags_hdr;
 #endif
 	struct sock		*nfnl;
 	struct sock		*nfnl_stash;
 #if IS_ENABLED(CONFIG_NETFILTER_NETLINK_ACCT)
 	struct list_head        nfnl_acct_list;
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+	struct list_head	nfct_timeout_list;
+#endif
 #endif
 #ifdef CONFIG_WEXT_CORE
 	struct sk_buff_head	wext_nlevents;
@@ -209,6 +216,11 @@
 	return net1 == net2;
 }
 
+static inline int check_net(const struct net *net)
+{
+	return atomic_read(&net->count) != 0;
+}
+
 void net_drop_ns(void *);
 
 #else
@@ -232,6 +244,11 @@
 {
 	return 1;
 }
+
+static inline int check_net(const struct net *net)
+{
+	return 1;
+}
 
 #define net_drop_ns NULL
 #endif
--- linux-4.4.0.orig/include/net/netfilter/br_netfilter.h
+++ linux-4.4.0/include/net/netfilter/br_netfilter.h
@@ -42,7 +42,6 @@
 }
 
 struct net_device *setup_pre_routing(struct sk_buff *skb);
-void br_netfilter_enable(void);
 
 #if IS_ENABLED(CONFIG_IPV6)
 int br_validate_ipv6(struct net *net, struct sk_buff *skb);
--- linux-4.4.0.orig/include/net/netfilter/ipv6/nf_defrag_ipv6.h
+++ linux-4.4.0/include/net/netfilter/ipv6/nf_defrag_ipv6.h
@@ -5,8 +5,7 @@
 
 int nf_ct_frag6_init(void);
 void nf_ct_frag6_cleanup(void);
-struct sk_buff *nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user);
-void nf_ct_frag6_consume_orig(struct sk_buff *skb);
+int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user);
 
 struct inet_frags_ctl;
 
--- linux-4.4.0.orig/include/net/netfilter/nf_conntrack.h
+++ linux-4.4.0/include/net/netfilter/nf_conntrack.h
@@ -98,7 +98,7 @@
 	possible_net_t ct_net;
 
 	/* all members below initialized via memset */
-	u8 __nfct_init_offset[0];
+	struct { } __nfct_init_offset;
 
 	/* If we were expected by an expectation, this will be it */
 	struct nf_conn *master;
@@ -297,6 +297,8 @@
 				 gfp_t flags);
 void nf_ct_tmpl_free(struct nf_conn *tmpl);
 
+u32 nf_ct_get_id(const struct nf_conn *ct);
+
 #define NF_CT_STAT_INC(net, count)	  __this_cpu_inc((net)->ct.stat->count)
 #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
 
--- linux-4.4.0.orig/include/net/netfilter/nf_conntrack_count.h
+++ linux-4.4.0/include/net/netfilter/nf_conntrack_count.h
@@ -0,0 +1,15 @@
+#ifndef _NF_CONNTRACK_COUNT_H
+#define _NF_CONNTRACK_COUNT_H
+
+unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,
+				 const struct nf_conntrack_tuple *tuple,
+				 const struct nf_conntrack_zone *zone,
+				 bool *addit);
+
+bool nf_conncount_add(struct hlist_head *head,
+		      const struct nf_conntrack_tuple *tuple,
+		      const struct nf_conntrack_zone *zone);
+
+void nf_conncount_cache_free(struct hlist_head *hhead);
+
+#endif
--- linux-4.4.0.orig/include/net/netfilter/nf_conntrack_timeout.h
+++ linux-4.4.0/include/net/netfilter/nf_conntrack_timeout.h
@@ -104,7 +104,7 @@
 #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
 
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
-extern struct ctnl_timeout *(*nf_ct_timeout_find_get_hook)(const char *name);
+extern struct ctnl_timeout *(*nf_ct_timeout_find_get_hook)(struct net *net, const char *name);
 extern void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout);
 #endif
 
--- linux-4.4.0.orig/include/net/netfilter/nf_log.h
+++ linux-4.4.0/include/net/netfilter/nf_log.h
@@ -49,6 +49,9 @@
 	struct module		*me;
 };
 
+/* sysctl_nf_log_all_netns - allow LOG target in all network namespaces */
+extern int sysctl_nf_log_all_netns;
+
 /* Function to register/unregister log function. */
 int nf_log_register(u_int8_t pf, struct nf_logger *logger);
 void nf_log_unregister(struct nf_logger *logger);
--- linux-4.4.0.orig/include/net/netfilter/nf_queue.h
+++ linux-4.4.0/include/net/netfilter/nf_queue.h
@@ -28,8 +28,8 @@
 						struct nf_hook_ops *ops);
 };
 
-void nf_register_queue_handler(const struct nf_queue_handler *qh);
-void nf_unregister_queue_handler(void);
+void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh);
+void nf_unregister_queue_handler(struct net *net);
 void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
 
 void nf_queue_entry_get_refs(struct nf_queue_entry *entry);
--- linux-4.4.0.orig/include/net/netfilter/nf_tables.h
+++ linux-4.4.0/include/net/netfilter/nf_tables.h
@@ -74,6 +74,8 @@
 static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
 				 unsigned int len)
 {
+	if (len % NFT_REG32_SIZE)
+		dst[len / NFT_REG32_SIZE] = 0;
 	memcpy(dst, src, len);
 }
 
@@ -115,7 +117,8 @@
 int nft_data_init(const struct nft_ctx *ctx,
 		  struct nft_data *data, unsigned int size,
 		  struct nft_data_desc *desc, const struct nlattr *nla);
-void nft_data_uninit(const struct nft_data *data, enum nft_data_types type);
+void nft_data_hold(const struct nft_data *data, enum nft_data_types type);
+void nft_data_release(const struct nft_data *data, enum nft_data_types type);
 int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
 		  enum nft_data_types type, unsigned int len);
 
@@ -169,6 +172,7 @@
 
 struct nft_set;
 struct nft_set_iter {
+	u8		genmask;
 	unsigned int	count;
 	unsigned int	skip;
 	int		err;
@@ -288,14 +292,16 @@
  * 	@ktype: key type (numeric type defined by userspace, not used in the kernel)
  * 	@dtype: data type (verdict or numeric type defined by userspace)
  * 	@size: maximum set size
+ *	@use: number of rules references to this set
  * 	@nelems: number of elements
  * 	@ndeact: number of deactivated elements queued for removal
- * 	@timeout: default timeout value in msecs
+ *	@timeout: default timeout value in jiffies
  * 	@gc_int: garbage collection interval in msecs
  *	@policy: set parameterization (see enum nft_set_policies)
  * 	@ops: set ops
  * 	@pnet: network namespace
  * 	@flags: set flags
+ *	@genmask: generation mask
  * 	@klen: key length
  * 	@dlen: data length
  * 	@data: private set data
@@ -307,6 +313,7 @@
 	u32				ktype;
 	u32				dtype;
 	u32				size;
+	u32				use;
 	atomic_t			nelems;
 	u32				ndeact;
 	u64				timeout;
@@ -315,27 +322,39 @@
 	/* runtime data below here */
 	const struct nft_set_ops	*ops ____cacheline_aligned;
 	possible_net_t			pnet;
-	u16				flags;
+	u16				flags:14,
+					genmask:2;
 	u8				klen;
 	u8				dlen;
 	unsigned char			data[]
 		__attribute__((aligned(__alignof__(u64))));
 };
 
+static inline bool nft_set_is_anonymous(const struct nft_set *set)
+{
+	return set->flags & NFT_SET_ANONYMOUS;
+}
+
 static inline void *nft_set_priv(const struct nft_set *set)
 {
 	return (void *)set->data;
 }
 
+static inline enum nft_data_types nft_set_datatype(const struct nft_set *set)
+{
+	return set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE;
+}
+
 static inline struct nft_set *nft_set_container_of(const void *priv)
 {
 	return (void *)priv - offsetof(struct nft_set, data);
 }
 
 struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
-				     const struct nlattr *nla);
+				     const struct nlattr *nla, u8 genmask);
 struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
-					  const struct nlattr *nla);
+					  const struct nft_table *table,
+					  const struct nlattr *nla, u8 genmask);
 
 static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
 {
@@ -358,10 +377,16 @@
 	u32				flags;
 };
 
+enum nft_trans_phase;
+void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set);
+void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
+			      struct nft_set_binding *binding,
+			      enum nft_trans_phase phase);
 int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
 		       struct nft_set_binding *binding);
 void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
-			  struct nft_set_binding *binding);
+			  struct nft_set_binding *binding, bool commit);
+void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set);
 
 /**
  *	enum nft_set_extensions - set extension type IDs
@@ -484,7 +509,7 @@
 	return nft_set_ext(ext, NFT_SET_EXT_TIMEOUT);
 }
 
-static inline unsigned long *nft_set_ext_expiration(const struct nft_set_ext *ext)
+static inline u64 *nft_set_ext_expiration(const struct nft_set_ext *ext)
 {
 	return nft_set_ext(ext, NFT_SET_EXT_EXPIRATION);
 }
@@ -499,10 +524,16 @@
 	return nft_set_ext(ext, NFT_SET_EXT_EXPR);
 }
 
-static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
+static inline bool __nft_set_elem_expired(const struct nft_set_ext *ext,
+					  u64 tstamp)
 {
 	return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) &&
-	       time_is_before_eq_jiffies(*nft_set_ext_expiration(ext));
+	       time_after_eq64(tstamp, *nft_set_ext_expiration(ext));
+}
+
+static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
+{
+	return __nft_set_elem_expired(ext, get_jiffies_64());
 }
 
 static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
@@ -515,7 +546,8 @@
 			const struct nft_set_ext_tmpl *tmpl,
 			const u32 *key, const u32 *data,
 			u64 timeout, gfp_t gfp);
-void nft_set_elem_destroy(const struct nft_set *set, void *elem);
+void nft_set_elem_destroy(const struct nft_set *set, void *elem,
+			  bool destroy_expr);
 
 /**
  *	struct nft_set_gc_batch_head - nf_tables set garbage collection batch
@@ -601,13 +633,22 @@
 
 #define NFT_EXPR_STATEFUL		0x1
 
+enum nft_trans_phase {
+	NFT_TRANS_PREPARE,
+	NFT_TRANS_ABORT,
+	NFT_TRANS_COMMIT,
+	NFT_TRANS_RELEASE
+};
+
 /**
  *	struct nft_expr_ops - nf_tables expression operations
  *
  *	@eval: Expression evaluation function
  *	@size: full expression size, including private data size
  *	@init: initialization function
- *	@destroy: destruction function
+ *	@activate: activate expression in the next generation
+ *	@deactivate: deactivate expression in next generation
+ *	@destroy: destruction function, called after synchronize_rcu
  *	@dump: function to dump parameters
  *	@type: expression type
  *	@validate: validate expression, called during loop detection
@@ -625,6 +666,11 @@
 	int				(*init)(const struct nft_ctx *ctx,
 						const struct nft_expr *expr,
 						const struct nlattr * const tb[]);
+	void				(*activate)(const struct nft_ctx *ctx,
+						    const struct nft_expr *expr);
+	void				(*deactivate)(const struct nft_ctx *ctx,
+						      const struct nft_expr *expr,
+						      enum nft_trans_phase phase);
 	void				(*destroy)(const struct nft_ctx *ctx,
 						   const struct nft_expr *expr);
 	int				(*dump)(struct sk_buff *skb,
@@ -648,7 +694,8 @@
  */
 struct nft_expr {
 	const struct nft_expr_ops	*ops;
-	unsigned char			data[];
+	unsigned char			data[]
+		__attribute__((aligned(__alignof__(u64))));
 };
 
 static inline void *nft_expr_priv(const struct nft_expr *expr)
@@ -666,7 +713,6 @@
 {
 	int err;
 
-	__module_get(src->ops->type->owner);
 	if (src->ops->clone) {
 		dst->ops = src->ops;
 		err = src->ops->clone(dst, src);
@@ -675,6 +721,8 @@
 	} else {
 		memcpy(dst, src, src->ops->size);
 	}
+
+	__module_get(src->ops->type->owner);
 	return 0;
 }
 
@@ -730,7 +778,6 @@
 
 enum nft_chain_flags {
 	NFT_BASE_CHAIN			= 0x1,
-	NFT_CHAIN_INACTIVE		= 0x2,
 };
 
 /**
@@ -752,7 +799,8 @@
 	u64				handle;
 	u32				use;
 	u16				level;
-	u8				flags;
+	u8				flags:6,
+					genmask:2;
 	char				name[NFT_CHAIN_MAXNAMELEN];
 };
 
@@ -839,6 +887,7 @@
  *	@hgenerator: handle generator state
  *	@use: number of chain references to this table
  *	@flags: table flag (see enum nft_table_flags)
+ *	@genmask: generation mask
  *	@name: name of the table
  */
 struct nft_table {
@@ -847,7 +896,8 @@
 	struct list_head		sets;
 	u64				hgenerator;
 	u32				use;
-	u16				flags;
+	u16				flags:14,
+					genmask:2;
 	char				name[NFT_TABLE_MAXNAMELEN];
 };
 
@@ -939,6 +989,32 @@
 #define NFT_GENMASK_ANY		((1 << 0) | (1 << 1))
 
 /*
+ * Generic transaction helpers
+ */
+
+/* Check if this object is currently active. */
+#define nft_is_active(__net, __obj)				\
+	(((__obj)->genmask & nft_genmask_cur(__net)) == 0)
+
+/* Check if this object is active in the next generation. */
+#define nft_is_active_next(__net, __obj)			\
+	(((__obj)->genmask & nft_genmask_next(__net)) == 0)
+
+/* This object becomes active in the next generation. */
+#define nft_activate_next(__net, __obj)				\
+	(__obj)->genmask = nft_genmask_cur(__net)
+
+/* This object becomes inactive in the next generation. */
+#define nft_deactivate_next(__net, __obj)			\
+        (__obj)->genmask = nft_genmask_next(__net)
+
+/* After committing the ruleset, clear the stale generation bit. */
+#define nft_clear(__net, __obj)					\
+	(__obj)->genmask &= ~nft_genmask_next(__net)
+#define nft_active_genmask(__obj, __genmask)			\
+	!((__obj)->genmask & __genmask)
+
+/*
  * Set element transaction helpers
  */
 
@@ -1014,12 +1090,15 @@
 struct nft_trans_set {
 	struct nft_set			*set;
 	u32				set_id;
+	bool				bound;
 };
 
 #define nft_trans_set(trans)	\
 	(((struct nft_trans_set *)trans->data)->set)
 #define nft_trans_set_id(trans)	\
 	(((struct nft_trans_set *)trans->data)->set_id)
+#define nft_trans_set_bound(trans)	\
+	(((struct nft_trans_set *)trans->data)->bound)
 
 struct nft_trans_chain {
 	bool				update;
@@ -1050,11 +1129,19 @@
 struct nft_trans_elem {
 	struct nft_set			*set;
 	struct nft_set_elem		elem;
+	bool				bound;
 };
 
 #define nft_trans_elem_set(trans)	\
 	(((struct nft_trans_elem *)trans->data)->set)
 #define nft_trans_elem(trans)	\
 	(((struct nft_trans_elem *)trans->data)->elem)
+#define nft_trans_elem_set_bound(trans)	\
+	(((struct nft_trans_elem *)trans->data)->bound)
+
+static inline u64 nft_net_tstamp(const struct net *net)
+{
+	return net->nft.tstamp;
+}
 
 #endif /* _NET_NF_TABLES_H */
--- linux-4.4.0.orig/include/net/netlink.h
+++ linux-4.4.0/include/net/netlink.h
@@ -745,7 +745,10 @@
  */
 static inline int nla_put_u8(struct sk_buff *skb, int attrtype, u8 value)
 {
-	return nla_put(skb, attrtype, sizeof(u8), &value);
+	/* temporary variables to work around GCC PR81715 with asan-stack=1 */
+	u8 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(u8), &tmp);
 }
 
 /**
@@ -756,7 +759,9 @@
  */
 static inline int nla_put_u16(struct sk_buff *skb, int attrtype, u16 value)
 {
-	return nla_put(skb, attrtype, sizeof(u16), &value);
+	u16 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(u16), &tmp);
 }
 
 /**
@@ -767,7 +772,9 @@
  */
 static inline int nla_put_be16(struct sk_buff *skb, int attrtype, __be16 value)
 {
-	return nla_put(skb, attrtype, sizeof(__be16), &value);
+	__be16 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(__be16), &tmp);
 }
 
 /**
@@ -778,7 +785,9 @@
  */
 static inline int nla_put_net16(struct sk_buff *skb, int attrtype, __be16 value)
 {
-	return nla_put_be16(skb, attrtype | NLA_F_NET_BYTEORDER, value);
+	__be16 tmp = value;
+
+	return nla_put_be16(skb, attrtype | NLA_F_NET_BYTEORDER, tmp);
 }
 
 /**
@@ -789,7 +798,9 @@
  */
 static inline int nla_put_le16(struct sk_buff *skb, int attrtype, __le16 value)
 {
-	return nla_put(skb, attrtype, sizeof(__le16), &value);
+	__le16 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(__le16), &tmp);
 }
 
 /**
@@ -800,7 +811,9 @@
  */
 static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value)
 {
-	return nla_put(skb, attrtype, sizeof(u32), &value);
+	u32 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(u32), &tmp);
 }
 
 /**
@@ -811,7 +824,9 @@
  */
 static inline int nla_put_be32(struct sk_buff *skb, int attrtype, __be32 value)
 {
-	return nla_put(skb, attrtype, sizeof(__be32), &value);
+	__be32 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(__be32), &tmp);
 }
 
 /**
@@ -822,7 +837,9 @@
  */
 static inline int nla_put_net32(struct sk_buff *skb, int attrtype, __be32 value)
 {
-	return nla_put_be32(skb, attrtype | NLA_F_NET_BYTEORDER, value);
+	__be32 tmp = value;
+
+	return nla_put_be32(skb, attrtype | NLA_F_NET_BYTEORDER, tmp);
 }
 
 /**
@@ -833,7 +850,9 @@
  */
 static inline int nla_put_le32(struct sk_buff *skb, int attrtype, __le32 value)
 {
-	return nla_put(skb, attrtype, sizeof(__le32), &value);
+	__le32 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(__le32), &tmp);
 }
 
 /**
@@ -844,7 +863,9 @@
  */
 static inline int nla_put_u64(struct sk_buff *skb, int attrtype, u64 value)
 {
-	return nla_put(skb, attrtype, sizeof(u64), &value);
+	u64 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(u64), &tmp);
 }
 
 /**
@@ -855,7 +876,9 @@
  */
 static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value)
 {
-	return nla_put(skb, attrtype, sizeof(__be64), &value);
+	__be64 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(__be64), &tmp);
 }
 
 /**
@@ -866,7 +889,9 @@
  */
 static inline int nla_put_net64(struct sk_buff *skb, int attrtype, __be64 value)
 {
-	return nla_put_be64(skb, attrtype | NLA_F_NET_BYTEORDER, value);
+	__be64 tmp = value;
+
+	return nla_put_be64(skb, attrtype | NLA_F_NET_BYTEORDER, tmp);
 }
 
 /**
@@ -877,7 +902,9 @@
  */
 static inline int nla_put_le64(struct sk_buff *skb, int attrtype, __le64 value)
 {
-	return nla_put(skb, attrtype, sizeof(__le64), &value);
+	__le64 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(__le64), &tmp);
 }
 
 /**
@@ -888,7 +915,9 @@
  */
 static inline int nla_put_s8(struct sk_buff *skb, int attrtype, s8 value)
 {
-	return nla_put(skb, attrtype, sizeof(s8), &value);
+	s8 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(s8), &tmp);
 }
 
 /**
@@ -899,7 +928,9 @@
  */
 static inline int nla_put_s16(struct sk_buff *skb, int attrtype, s16 value)
 {
-	return nla_put(skb, attrtype, sizeof(s16), &value);
+	s16 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(s16), &tmp);
 }
 
 /**
@@ -910,7 +941,9 @@
  */
 static inline int nla_put_s32(struct sk_buff *skb, int attrtype, s32 value)
 {
-	return nla_put(skb, attrtype, sizeof(s32), &value);
+	s32 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(s32), &tmp);
 }
 
 /**
@@ -921,7 +954,9 @@
  */
 static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value)
 {
-	return nla_put(skb, attrtype, sizeof(s64), &value);
+	s64 tmp = value;
+
+	return nla_put(skb, attrtype, sizeof(s64), &tmp);
 }
 
 /**
@@ -969,7 +1004,9 @@
 static inline int nla_put_in_addr(struct sk_buff *skb, int attrtype,
 				  __be32 addr)
 {
-	return nla_put_be32(skb, attrtype, addr);
+	__be32 tmp = addr;
+
+	return nla_put_be32(skb, attrtype, tmp);
 }
 
 /**
--- linux-4.4.0.orig/include/net/netns/core.h
+++ linux-4.4.0/include/net/netns/core.h
@@ -10,7 +10,10 @@
 
 	int	sysctl_somaxconn;
 
-	struct prot_inuse __percpu *inuse;
+#ifdef CONFIG_PROC_FS
+	int __percpu *sock_inuse;
+	struct prot_inuse __percpu *prot_inuse;
+#endif
 };
 
 #endif
--- linux-4.4.0.orig/include/net/netns/hash.h
+++ linux-4.4.0/include/net/netns/hash.h
@@ -1,21 +1,10 @@
 #ifndef __NET_NS_HASH_H__
 #define __NET_NS_HASH_H__
 
-#include <asm/cache.h>
-
-struct net;
+#include <net/net_namespace.h>
 
 static inline u32 net_hash_mix(const struct net *net)
 {
-#ifdef CONFIG_NET_NS
-	/*
-	 * shift this right to eliminate bits, that are
-	 * always zeroed
-	 */
-
-	return (u32)(((unsigned long)net) >> L1_CACHE_SHIFT);
-#else
-	return 0;
-#endif
+	return net->hash_mix;
 }
 #endif
--- linux-4.4.0.orig/include/net/netns/ipv4.h
+++ linux-4.4.0/include/net/netns/ipv4.h
@@ -8,6 +8,7 @@
 #include <linux/uidgid.h>
 #include <net/inet_frag.h>
 #include <linux/rcupdate.h>
+#include <linux/siphash.h>
 
 struct tcpm_hash_bucket;
 struct ctl_table_header;
@@ -88,6 +89,7 @@
 	int sysctl_tcp_fwmark_accept;
 	int sysctl_tcp_mtu_probing;
 	int sysctl_tcp_base_mss;
+	int sysctl_tcp_min_snd_mss;
 	int sysctl_tcp_probe_threshold;
 	u32 sysctl_tcp_probe_interval;
 
@@ -108,5 +110,6 @@
 #endif
 #endif
 	atomic_t	rt_genid;
+	siphash_key_t	ip_id_key;
 };
 #endif
--- linux-4.4.0.orig/include/net/netns/ipv6.h
+++ linux-4.4.0/include/net/netns/ipv6.h
@@ -86,7 +86,6 @@
 
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
 struct netns_nf_frag {
-	struct netns_sysctl_ipv6 sysctl;
 	struct netns_frags	frags;
 };
 #endif
--- linux-4.4.0.orig/include/net/netns/netfilter.h
+++ linux-4.4.0/include/net/netns/netfilter.h
@@ -5,11 +5,13 @@
 
 struct proc_dir_entry;
 struct nf_logger;
+struct nf_queue_handler;
 
 struct netns_nf {
 #if defined CONFIG_PROC_FS
 	struct proc_dir_entry *proc_netfilter;
 #endif
+	const struct nf_queue_handler __rcu *queue_handler;
 	const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
 #ifdef CONFIG_SYSCTL
 	struct ctl_table_header *nf_log_dir_header;
--- linux-4.4.0.orig/include/net/netns/nftables.h
+++ linux-4.4.0/include/net/netns/nftables.h
@@ -14,6 +14,7 @@
 	struct nft_af_info	*arp;
 	struct nft_af_info	*bridge;
 	struct nft_af_info	*netdev;
+	u64			tstamp;
 	unsigned int		base_seq;
 	u8			gencursor;
 };
--- linux-4.4.0.orig/include/net/nexthop.h
+++ linux-4.4.0/include/net/nexthop.h
@@ -6,7 +6,7 @@
 
 static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining)
 {
-	return remaining >= sizeof(*rtnh) &&
+	return remaining >= (int)sizeof(*rtnh) &&
 	       rtnh->rtnh_len >= sizeof(*rtnh) &&
 	       rtnh->rtnh_len <= remaining;
 }
--- linux-4.4.0.orig/include/net/nfc/hci.h
+++ linux-4.4.0/include/net/nfc/hci.h
@@ -87,7 +87,7 @@
  * According to specification 102 622 chapter 4.4 Pipes,
  * the pipe identifier is 7 bits long.
  */
-#define NFC_HCI_MAX_PIPES		127
+#define NFC_HCI_MAX_PIPES		128
 struct nfc_hci_init_data {
 	u8 gate_count;
 	struct nfc_hci_gate gates[NFC_HCI_MAX_CUSTOM_GATES];
--- linux-4.4.0.orig/include/net/nfc/nci_core.h
+++ linux-4.4.0/include/net/nfc/nci_core.h
@@ -42,6 +42,7 @@
 	NCI_UP,
 	NCI_DATA_EXCHANGE,
 	NCI_DATA_EXCHANGE_TO,
+	NCI_UNREG,
 };
 
 /* NCI device states */
--- linux-4.4.0.orig/include/net/phonet/pep.h
+++ linux-4.4.0/include/net/phonet/pep.h
@@ -63,10 +63,11 @@
 		u8		state_after_reset;	/* reset request */
 		u8		error_code;		/* any response */
 		u8		pep_type;		/* status indication */
-		u8		data[1];
+		u8		data0;			/* anything else */
 	};
+	u8			data[];
 };
-#define other_pep_type		data[1]
+#define other_pep_type		data[0]
 
 static inline struct pnpipehdr *pnp_hdr(struct sk_buff *skb)
 {
--- linux-4.4.0.orig/include/net/pkt_cls.h
+++ linux-4.4.0/include/net/pkt_cls.h
@@ -358,4 +358,38 @@
 }
 #endif /* CONFIG_NET_CLS_IND */
 
+struct tc_cls_u32_knode {
+	struct tcf_exts *exts;
+	u8 fshift;
+	u32 handle;
+	u32 val;
+	u32 mask;
+	u32 link_handle;
+	struct tc_u32_sel *sel;
+};
+
+struct tc_cls_u32_hnode {
+	u32 handle;
+	u32 prio;
+	unsigned int divisor;
+};
+
+enum tc_clsu32_command {
+	TC_CLSU32_NEW_KNODE,
+	TC_CLSU32_REPLACE_KNODE,
+	TC_CLSU32_DELETE_KNODE,
+	TC_CLSU32_NEW_HNODE,
+	TC_CLSU32_REPLACE_HNODE,
+	TC_CLSU32_DELETE_HNODE,
+};
+
+struct tc_cls_u32_offload {
+	/* knode values */
+	enum tc_clsu32_command command;
+	union {
+		struct tc_cls_u32_knode knode;
+		struct tc_cls_u32_hnode hnode;
+	};
+};
+
 #endif
--- linux-4.4.0.orig/include/net/red.h
+++ linux-4.4.0/include/net/red.h
@@ -167,6 +167,19 @@
 	v->qcount	= -1;
 }
 
+static inline bool red_check_params(u32 qth_min, u32 qth_max, u8 Wlog, u8 Scell_log)
+{
+	if (fls(qth_min) + Wlog > 32)
+		return false;
+	if (fls(qth_max) + Wlog > 32)
+		return false;
+	if (Scell_log >= 32)
+		return false;
+	if (qth_max < qth_min)
+		return false;
+	return true;
+}
+
 static inline void red_set_parms(struct red_parms *p,
 				 u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
 				 u8 Scell_log, u8 *stab, u32 max_P)
@@ -178,7 +191,7 @@
 	p->qth_max	= qth_max << Wlog;
 	p->Wlog		= Wlog;
 	p->Plog		= Plog;
-	if (delta < 0)
+	if (delta <= 0)
 		delta = 1;
 	p->qth_delta	= delta;
 	if (!max_P) {
--- linux-4.4.0.orig/include/net/regulatory.h
+++ linux-4.4.0/include/net/regulatory.h
@@ -78,7 +78,7 @@
 	int wiphy_idx;
 	enum nl80211_reg_initiator initiator;
 	enum nl80211_user_reg_hint_type user_reg_hint_type;
-	char alpha2[2];
+	char alpha2[3];
 	enum nl80211_dfs_regions dfs_region;
 	bool intersect;
 	bool processed;
--- linux-4.4.0.orig/include/net/route.h
+++ linux-4.4.0/include/net/route.h
@@ -64,7 +64,8 @@
 	__be32			rt_gateway;
 
 	/* Miscellaneous cached information */
-	u32			rt_pmtu;
+	u32			rt_mtu_locked:1,
+				rt_pmtu:31;
 
 	u32			rt_table_id;
 
@@ -209,6 +210,9 @@
 void ip_rt_multicast_event(struct in_device *);
 int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
 void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
+struct rtable *rt_dst_alloc(struct net_device *dev,
+			     unsigned int flags, u16 type,
+			     bool nopolicy, bool noxfrm, bool will_cache);
 
 struct in_ifaddr;
 void fib_add_ifaddr(struct in_ifaddr *);
--- linux-4.4.0.orig/include/net/sch_generic.h
+++ linux-4.4.0/include/net/sch_generic.h
@@ -289,6 +289,11 @@
 	return q;
 }
 
+static inline struct Qdisc *qdisc_root_bh(const struct Qdisc *qdisc)
+{
+	return rcu_dereference_bh(qdisc->dev_queue->qdisc);
+}
+
 static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc)
 {
 	return qdisc->dev_queue->qdisc_sleeping;
@@ -396,7 +401,8 @@
 			      struct Qdisc *qdisc);
 void qdisc_reset(struct Qdisc *qdisc);
 void qdisc_destroy(struct Qdisc *qdisc);
-void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
+void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n,
+			       unsigned int len);
 struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
 			  const struct Qdisc_ops *ops);
 struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
@@ -407,6 +413,15 @@
 void tcf_destroy_chain(struct tcf_proto __rcu **fl);
 int skb_do_redirect(struct sk_buff *);
 
+static inline bool skb_at_tc_ingress(const struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_CLS_ACT
+	return G_TC_AT(skb->tc_verd) & AT_INGRESS;
+#else
+	return false;
+#endif
+}
+
 /* Reset all TX qdiscs greater then index of a device.  */
 static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i)
 {
@@ -659,9 +674,11 @@
 	/* we can reuse ->gso_skb because peek isn't called for root qdiscs */
 	if (!sch->gso_skb) {
 		sch->gso_skb = sch->dequeue(sch);
-		if (sch->gso_skb)
+		if (sch->gso_skb) {
 			/* it's still part of the queue */
+			qdisc_qstats_backlog_inc(sch, sch->gso_skb);
 			sch->q.qlen++;
+		}
 	}
 
 	return sch->gso_skb;
@@ -674,6 +691,7 @@
 
 	if (skb) {
 		sch->gso_skb = NULL;
+		qdisc_qstats_backlog_dec(sch, skb);
 		sch->q.qlen--;
 	} else {
 		skb = sch->dequeue(sch);
@@ -698,6 +716,26 @@
 	sch->qstats.backlog = 0;
 }
 
+static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
+					  struct Qdisc **pold)
+{
+	struct Qdisc *old;
+
+	sch_tree_lock(sch);
+	old = *pold;
+	*pold = new;
+	if (old != NULL) {
+		unsigned int qlen = old->q.qlen;
+		unsigned int backlog = old->qstats.backlog;
+
+		qdisc_reset(old);
+		qdisc_tree_reduce_backlog(old, qlen, backlog);
+	}
+	sch_tree_unlock(sch);
+
+	return old;
+}
+
 static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch,
 					      struct sk_buff_head *list)
 {
--- linux-4.4.0.orig/include/net/scm.h
+++ linux-4.4.0/include/net/scm.h
@@ -21,6 +21,7 @@
 struct scm_fp_list {
 	short			count;
 	short			max;
+	struct user_struct	*user;
 	struct file		*fp[SCM_MAX_FD];
 };
 
--- linux-4.4.0.orig/include/net/sctp/checksum.h
+++ linux-4.4.0/include/net/sctp/checksum.h
@@ -60,7 +60,7 @@
 static inline __le32 sctp_compute_cksum(const struct sk_buff *skb,
 					unsigned int offset)
 {
-	struct sctphdr *sh = sctp_hdr(skb);
+	struct sctphdr *sh = (struct sctphdr *)(skb->data + offset);
         __le32 ret, old = sh->checksum;
 	const struct skb_checksum_ops ops = {
 		.update  = sctp_csum_update,
--- linux-4.4.0.orig/include/net/sctp/constants.h
+++ linux-4.4.0/include/net/sctp/constants.h
@@ -357,11 +357,13 @@
 	 ipv4_is_anycast_6to4(a))
 
 /* Flags used for the bind address copy functions.  */
-#define SCTP_ADDR6_ALLOWED	0x00000001	/* IPv6 address is allowed by
+#define SCTP_ADDR4_ALLOWED	0x00000001	/* IPv4 address is allowed by
 						   local sock family */
-#define SCTP_ADDR4_PEERSUPP	0x00000002	/* IPv4 address is supported by
+#define SCTP_ADDR6_ALLOWED	0x00000002	/* IPv6 address is allowed by
+						   local sock family */
+#define SCTP_ADDR4_PEERSUPP	0x00000004	/* IPv4 address is supported by
 						   peer */
-#define SCTP_ADDR6_PEERSUPP	0x00000004	/* IPv6 address is supported by
+#define SCTP_ADDR6_PEERSUPP	0x00000008	/* IPv6 address is supported by
 						   peer */
 
 /* Reasons to retransmit. */
--- linux-4.4.0.orig/include/net/sctp/sctp.h
+++ linux-4.4.0/include/net/sctp/sctp.h
@@ -98,6 +98,8 @@
 /*
  * sctp/socket.c
  */
+int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
+		      int addr_len, int flags);
 int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 int sctp_inet_listen(struct socket *sock, int backlog);
 void sctp_write_space(struct sock *sk);
@@ -396,7 +398,7 @@
 	/*
 	 * This mimics the behavior of skb_set_owner_r
 	 */
-	sk->sk_forward_alloc -= event->rmem_len;
+	sk_mem_charge(sk, event->rmem_len);
 }
 
 /* Tests if the list has one and only one entry. */
@@ -444,6 +446,8 @@
 
 #define _sctp_walk_params(pos, chunk, end, member)\
 for (pos.v = chunk->member;\
+     (pos.v + offsetof(struct sctp_paramhdr, length) + sizeof(pos.p->length) <=\
+      (void *)chunk + end) &&\
      pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\
      ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
      pos.v += WORD_ROUND(ntohs(pos.p->length)))
@@ -454,6 +458,8 @@
 #define _sctp_walk_errors(err, chunk_hdr, end)\
 for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
 	    sizeof(sctp_chunkhdr_t));\
+     ((void *)err + offsetof(sctp_errhdr_t, length) + sizeof(err->length) <=\
+      (void *)chunk_hdr + end) &&\
      (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\
      ntohs(err->length) >= sizeof(sctp_errhdr_t); \
      err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length))))
@@ -592,10 +598,8 @@
  */
 static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t)
 {
-	if (t->dst && !dst_check(t->dst, t->dst_cookie)) {
-		dst_release(t->dst);
-		t->dst = NULL;
-	}
+	if (t->dst && !dst_check(t->dst, t->dst_cookie))
+		sctp_transport_dst_release(t);
 
 	return t->dst;
 }
--- linux-4.4.0.orig/include/net/sctp/structs.h
+++ linux-4.4.0/include/net/sctp/structs.h
@@ -830,6 +830,8 @@
 
 	__u32 burst_limited;	/* Holds old cwnd when max.burst is applied */
 
+	__u32 dst_pending_confirm;	/* need to confirm neighbour */
+
 	/* Destination */
 	struct dst_entry *dst;
 	/* Source address. */
@@ -966,6 +968,8 @@
 void sctp_transport_reset(struct sctp_transport *);
 void sctp_transport_update_pmtu(struct sock *, struct sctp_transport *, u32);
 void sctp_transport_immediate_rtx(struct sctp_transport *);
+void sctp_transport_dst_release(struct sctp_transport *t);
+void sctp_transport_dst_confirm(struct sctp_transport *t);
 
 
 /* This is the structure we use to queue packets as they come into
--- linux-4.4.0.orig/include/net/sctp/ulpevent.h
+++ linux-4.4.0/include/net/sctp/ulpevent.h
@@ -141,8 +141,12 @@
 static inline int sctp_ulpevent_type_enabled(__u16 sn_type,
 					     struct sctp_event_subscribe *mask)
 {
+	int offset = sn_type - SCTP_SN_TYPE_BASE;
 	char *amask = (char *) mask;
-	return amask[sn_type - SCTP_SN_TYPE_BASE];
+
+	if (offset >= sizeof(struct sctp_event_subscribe))
+		return 0;
+	return amask[offset];
 }
 
 /* Given an event subscription, is this event enabled? */
--- linux-4.4.0.orig/include/net/slhc_vj.h
+++ linux-4.4.0/include/net/slhc_vj.h
@@ -127,6 +127,7 @@
  */
 struct cstate {
 	byte_t	cs_this;	/* connection id number (xmit) */
+	bool	initialized;	/* true if initialized */
 	struct cstate *next;	/* next in ring (xmit) */
 	struct iphdr cs_ip;	/* ip/tcp hdr from most recent packet */
 	struct tcphdr cs_tcp;
--- linux-4.4.0.orig/include/net/sock.h
+++ linux-4.4.0/include/net/sock.h
@@ -254,6 +254,7 @@
   *	@sk_wq: sock wait queue and async head
   *	@sk_rx_dst: receive input route used by early demux
   *	@sk_dst_cache: destination cache
+  *	@sk_dst_pending_confirm: need to confirm neighbour
   *	@sk_policy: flow policy
   *	@sk_receive_queue: incoming packets
   *	@sk_wmem_alloc: transmit queue bytes committed
@@ -299,6 +300,7 @@
   *	@sk_filter: socket filtering instructions
   *	@sk_timer: sock cleanup timer
   *	@sk_stamp: time stamp of last packet received
+  *	@sk_stamp_seq: lock for accessing sk_stamp on 32 bit architectures only
   *	@sk_tsflags: SO_TIMESTAMPING socket options
   *	@sk_tskey: counter to disambiguate concurrent tstamp requests
   *	@sk_socket: Identd and reporting IO signals
@@ -390,13 +392,14 @@
 #ifdef CONFIG_XFRM
 	struct xfrm_policy __rcu *sk_policy[2];
 #endif
-	struct dst_entry	*sk_rx_dst;
+	struct dst_entry __rcu	*sk_rx_dst;
 	struct dst_entry __rcu	*sk_dst_cache;
 	/* Note: 32bit hole on 64bit arches */
 	atomic_t		sk_wmem_alloc;
 	atomic_t		sk_omem_alloc;
 	int			sk_sndbuf;
 	struct sk_buff_head	sk_write_queue;
+	__u32			sk_dst_pending_confirm;
 	kmemcheck_bitfield_begin(flags);
 	unsigned int		sk_shutdown  : 2,
 				sk_no_check_tx : 1,
@@ -428,12 +431,17 @@
 #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
 	__u32			sk_cgrp_prioidx;
 #endif
+	spinlock_t		sk_peer_lock;
 	struct pid		*sk_peer_pid;
 	const struct cred	*sk_peer_cred;
+
 	long			sk_rcvtimeo;
 	long			sk_sndtimeo;
 	struct timer_list	sk_timer;
 	ktime_t			sk_stamp;
+#if BITS_PER_LONG==32
+	seqlock_t		sk_stamp_seq;
+#endif
 	u16			sk_tsflags;
 	u32			sk_tskey;
 	struct socket		*sk_socket;
@@ -647,6 +655,12 @@
 	hlist_add_head_rcu(&sk->sk_node, list);
 }
 
+static inline void sk_add_node_tail_rcu(struct sock *sk, struct hlist_head *list)
+{
+	sock_hold(sk);
+	hlist_add_tail_rcu(&sk->sk_node, list);
+}
+
 static inline void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list)
 {
 	hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list);
@@ -769,6 +783,8 @@
 {
 	return static_key_false(&memalloc_socks);
 }
+
+void __receive_sock(struct file *file);
 #else
 
 static inline int sk_memalloc_socks(void)
@@ -776,6 +792,8 @@
 	return 0;
 }
 
+static inline void __receive_sock(struct file *file)
+{ }
 #endif
 
 static inline gfp_t sk_gfp_atomic(const struct sock *sk, gfp_t gfp_mask)
@@ -1194,11 +1212,13 @@
 					      unsigned long amt,
 					      int *parent_status)
 {
-	page_counter_charge(&prot->memory_allocated, amt);
+	struct page_counter *counter;
+
+	if (page_counter_try_charge(&prot->memory_allocated, amt, &counter))
+		return;
 
-	if (page_counter_read(&prot->memory_allocated) >
-	    prot->memory_allocated.limit)
-		*parent_status = OVER_LIMIT;
+	page_counter_charge(&prot->memory_allocated, amt);
+	*parent_status = OVER_LIMIT;
 }
 
 static inline void memcg_memory_allocated_sub(struct cg_proto *prot,
@@ -1272,7 +1292,7 @@
 	percpu_counter_inc(prot->sockets_allocated);
 }
 
-static inline int
+static inline u64
 sk_sockets_allocated_read_positive(struct sock *sk)
 {
 	struct proto *prot = sk->sk_prot;
@@ -1307,12 +1327,23 @@
 #ifdef CONFIG_PROC_FS
 /* Called with local bh disabled */
 void sock_prot_inuse_add(struct net *net, struct proto *prot, int inc);
+
+static inline void sock_inuse_add(const struct net *net, int val)
+{
+	this_cpu_add(*net->core.sock_inuse, val);
+}
+
 int sock_prot_inuse_get(struct net *net, struct proto *proto);
+int sock_inuse_get(struct net *net);
 #else
 static inline void sock_prot_inuse_add(struct net *net, struct proto *prot,
 		int inc)
 {
 }
+
+static inline void sock_inuse_add(const struct net *net, int val)
+{
+}
 #endif
 
 
@@ -1425,6 +1456,16 @@
 	if (!sk_has_account(sk))
 		return;
 	sk->sk_forward_alloc += size;
+
+	/* Avoid a possible overflow.
+	 * TCP send queues can make this happen, if sk_mem_reclaim()
+	 * is not called and more than 2 GBytes are released at once.
+	 *
+	 * If we reach 2 MBytes, reclaim 1 MBytes right now, there is
+	 * no need to hold that much forward allocation anyway.
+	 */
+	if (unlikely(sk->sk_forward_alloc >= 1 << 21))
+		__sk_mem_reclaim(sk, 1 << 20);
 }
 
 static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
@@ -1516,6 +1557,7 @@
 
 struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
 			     gfp_t priority);
+void __sock_wfree(struct sk_buff *skb);
 void sock_wfree(struct sk_buff *skb);
 void skb_orphan_partial(struct sk_buff *skb);
 void sock_rfree(struct sk_buff *skb);
@@ -1631,7 +1673,13 @@
  */
 void sock_gen_put(struct sock *sk);
 
-int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested);
+int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested,
+		     unsigned int trim_cap);
+static inline int sk_receive_skb(struct sock *sk, struct sk_buff *skb,
+				 const int nested)
+{
+	return __sk_receive_skb(sk, skb, nested, 1);
+}
 
 static inline void sk_tx_queue_set(struct sock *sk, int tx_queue)
 {
@@ -1650,7 +1698,6 @@
 
 static inline void sk_set_socket(struct sock *sk, struct socket *sock)
 {
-	sk_tx_queue_clear(sk);
 	sk->sk_socket = sock;
 }
 
@@ -1738,6 +1785,7 @@
 		if (ndst != dst) {
 			rcu_assign_pointer(sk->sk_dst_cache, ndst);
 			sk_tx_queue_clear(sk);
+			sk->sk_dst_pending_confirm = 0;
 		}
 	}
 }
@@ -1748,6 +1796,7 @@
 	struct dst_entry *old_dst;
 
 	sk_tx_queue_clear(sk);
+	sk->sk_dst_pending_confirm = 0;
 	/*
 	 * This can be called while sk is owned by the caller only,
 	 * with no state that can be checked in a rcu_dereference_check() cond
@@ -1763,6 +1812,7 @@
 	struct dst_entry *old_dst;
 
 	sk_tx_queue_clear(sk);
+	sk->sk_dst_pending_confirm = 0;
 	old_dst = xchg((__force struct dst_entry **)&sk->sk_dst_cache, dst);
 	dst_release(old_dst);
 }
@@ -1783,6 +1833,26 @@
 
 struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie);
 
+static inline void sk_dst_confirm(struct sock *sk)
+{
+	if (!sk->sk_dst_pending_confirm)
+		sk->sk_dst_pending_confirm = 1;
+}
+
+static inline void sock_confirm_neigh(struct sk_buff *skb, struct neighbour *n)
+{
+	if (skb_get_dst_pending_confirm(skb)) {
+		struct sock *sk = skb->sk;
+		unsigned long now = jiffies;
+
+		/* avoid dirtying neighbour */
+		if (n->confirmed != now)
+			n->confirmed = now;
+		if (sk && sk->sk_dst_pending_confirm)
+			sk->sk_dst_pending_confirm = 0;
+	}
+}
+
 bool sk_mc_loop(struct sock *sk);
 
 static inline bool sk_can_gso(const struct sock *sk)
@@ -2057,12 +2127,17 @@
  * sk_page_frag - return an appropriate page_frag
  * @sk: socket
  *
- * If socket allocation mode allows current thread to sleep, it means its
- * safe to use the per task page_frag instead of the per socket one.
+ * Use the per task page_frag instead of the per socket one for
+ * optimization when we know that we're in the normal context and owns
+ * everything that's associated with %current.
+ *
+ * gfpflags_allow_blocking() isn't enough here as direct reclaim may nest
+ * inside other socket operations and end up recursing into sk_page_frag()
+ * while it's already in use.
  */
 static inline struct page_frag *sk_page_frag(struct sock *sk)
 {
-	if (gfpflags_allow_blocking(sk->sk_allocation))
+	if (gfpflags_normal_context(sk->sk_allocation))
 		return &current->task_frag;
 
 	return &sk->sk_frag;
@@ -2129,6 +2204,41 @@
 	SOCK_SKB_CB(skb)->dropcount = atomic_read(&sk->sk_drops);
 }
 
+static inline void sk_drops_add(struct sock *sk, const struct sk_buff *skb)
+{
+	int segs = max_t(u16, 1, skb_shinfo(skb)->gso_segs);
+
+	atomic_add(segs, &sk->sk_drops);
+}
+
+static inline ktime_t sock_read_timestamp(struct sock *sk)
+{
+#if BITS_PER_LONG==32
+	unsigned int seq;
+	ktime_t kt;
+
+	do {
+		seq = read_seqbegin(&sk->sk_stamp_seq);
+		kt = sk->sk_stamp;
+	} while (read_seqretry(&sk->sk_stamp_seq, seq));
+
+	return kt;
+#else
+	return READ_ONCE(sk->sk_stamp);
+#endif
+}
+
+static inline void sock_write_timestamp(struct sock *sk, ktime_t kt)
+{
+#if BITS_PER_LONG==32
+	write_seqlock(&sk->sk_stamp_seq);
+	sk->sk_stamp = kt;
+	write_sequnlock(&sk->sk_stamp_seq);
+#else
+	WRITE_ONCE(sk->sk_stamp, kt);
+#endif
+}
+
 void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 			   struct sk_buff *skb);
 void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
@@ -2153,7 +2263,7 @@
 	     (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)))
 		__sock_recv_timestamp(msg, sk, skb);
 	else
-		sk->sk_stamp = kt;
+		sock_write_timestamp(sk, kt);
 
 	if (sock_flag(sk, SOCK_WIFI_STATUS) && skb->wifi_acked_valid)
 		__sock_recv_wifi_status(msg, sk, skb);
@@ -2173,7 +2283,7 @@
 	if (sk->sk_flags & FLAGS_TS_OR_DROPS || sk->sk_tsflags & TSFLAGS_ANY)
 		__sock_recv_ts_and_drops(msg, sk, skb);
 	else
-		sk->sk_stamp = skb->tstamp;
+		sock_write_timestamp(sk, skb->tstamp);
 }
 
 void __sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags);
--- linux-4.4.0.orig/include/net/switchdev.h
+++ linux-4.4.0/include/net/switchdev.h
@@ -88,7 +88,7 @@
 	struct switchdev_obj obj;
 	u32 dst;
 	int dst_len;
-	struct fib_info fi;
+	struct fib_info *fi;
 	u8 tos;
 	u8 type;
 	u32 nlflags;
--- linux-4.4.0.orig/include/net/tc_act/tc_gact.h
+++ linux-4.4.0/include/net/tc_act/tc_gact.h
@@ -2,6 +2,7 @@
 #define __NET_TC_GACT_H
 
 #include <net/act_api.h>
+#include <linux/tc_act/tc_gact.h>
 
 struct tcf_gact {
 	struct tcf_common	common;
@@ -15,4 +16,19 @@
 #define to_gact(a) \
 	container_of(a->priv, struct tcf_gact, common)
 
+#ifdef CONFIG_NET_CLS_ACT
+static inline bool is_tcf_gact_shot(const struct tc_action *a)
+{
+	struct tcf_gact *gact;
+
+	if (a->ops && a->ops->type != TCA_ACT_GACT)
+		return false;
+
+	gact = a->priv;
+	if (gact->tcf_action == TC_ACT_SHOT)
+		return true;
+
+	return false;
+}
+#endif
 #endif /* __NET_TC_GACT_H */
--- linux-4.4.0.orig/include/net/tcp.h
+++ linux-4.4.0/include/net/tcp.h
@@ -52,8 +52,10 @@
 extern struct percpu_counter tcp_orphan_count;
 void tcp_time_wait(struct sock *sk, int state, int timeo);
 
-#define MAX_TCP_HEADER	(128 + MAX_HEADER)
+#define MAX_TCP_HEADER	L1_CACHE_ALIGN(128 + MAX_HEADER)
 #define MAX_TCP_OPTION_SPACE 40
+#define TCP_MIN_SND_MSS		48
+#define TCP_MIN_GSO_SIZE	(TCP_MIN_SND_MSS - MAX_TCP_OPTION_SPACE)
 
 /*
  * Never offer a window over 32767 without using window scaling. Some
@@ -376,6 +378,7 @@
 			struct pipe_inode_info *pipe, size_t len,
 			unsigned int flags);
 
+void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks);
 static inline void tcp_dec_quickack_mode(struct sock *sk,
 					 const unsigned int pkts)
 {
@@ -449,7 +452,7 @@
 
 void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb);
 void tcp_v4_mtu_reduced(struct sock *sk);
-void tcp_req_err(struct sock *sk, u32 seq);
+void tcp_req_err(struct sock *sk, u32 seq, bool abort);
 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 struct sock *tcp_create_openreq_child(const struct sock *sk,
 				      struct request_sock *req,
@@ -499,19 +502,27 @@
  */
 static inline void tcp_synq_overflow(const struct sock *sk)
 {
-	unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp;
+	unsigned long last_overflow = READ_ONCE(tcp_sk(sk)->rx_opt.ts_recent_stamp);
 	unsigned long now = jiffies;
 
-	if (time_after(now, last_overflow + HZ))
-		tcp_sk(sk)->rx_opt.ts_recent_stamp = now;
+	if (!time_between32(now, last_overflow, last_overflow + HZ))
+		WRITE_ONCE(tcp_sk(sk)->rx_opt.ts_recent_stamp, now);
 }
 
 /* syncookies: no recent synqueue overflow on this listening socket? */
 static inline bool tcp_synq_no_recent_overflow(const struct sock *sk)
 {
-	unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp;
+	unsigned long last_overflow = READ_ONCE(tcp_sk(sk)->rx_opt.ts_recent_stamp);
 
-	return time_after(jiffies, last_overflow + TCP_SYNCOOKIE_VALID);
+	/* If last_overflow <= jiffies <= last_overflow + TCP_SYNCOOKIE_VALID,
+	 * then we're under synflood. However, we have to use
+	 * 'last_overflow - HZ' as lower bound. That's because a concurrent
+	 * tcp_synq_overflow() could update .ts_recent_stamp after we read
+	 * jiffies but before we store .ts_recent_stamp into last_overflow,
+	 * which could lead to rejecting a valid syncookie.
+	 */
+	return !time_between32(jiffies, last_overflow - HZ,
+			       last_overflow + TCP_SYNCOOKIE_VALID);
 }
 
 static inline u32 tcp_cookie_time(void)
@@ -559,6 +570,7 @@
 void tcp_send_active_reset(struct sock *sk, gfp_t priority);
 int tcp_send_synack(struct sock *);
 void tcp_push_one(struct sock *, unsigned int mss_now);
+void __tcp_send_ack(struct sock *sk, u32 rcv_nxt);
 void tcp_send_ack(struct sock *sk);
 void tcp_send_delayed_ack(struct sock *sk);
 void tcp_send_loss_probe(struct sock *sk);
@@ -647,7 +659,7 @@
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	if (skb_queue_empty(&tp->out_of_order_queue) &&
+	if (RB_EMPTY_ROOT(&tp->out_of_order_queue) &&
 	    tp->rcv_wnd &&
 	    atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
 	    !tp->urg_data)
@@ -819,8 +831,6 @@
 	CA_EVENT_LOSS,		/* loss timeout */
 	CA_EVENT_ECN_NO_CE,	/* ECT set, but not CE marked */
 	CA_EVENT_ECN_IS_CE,	/* received CE marked IP packet */
-	CA_EVENT_DELAYED_ACK,	/* Delayed ack is sent */
-	CA_EVENT_NON_DELAYED_ACK,
 };
 
 /* Information about inbound ACK, passed to cong_ops->in_ack_event() */
@@ -1156,6 +1166,7 @@
 }
 
 bool tcp_prequeue(struct sock *sk, struct sk_buff *skb);
+int tcp_filter(struct sock *sk, struct sk_buff *skb);
 
 #undef STATE_TRACE
 
@@ -1198,9 +1209,11 @@
 
 static inline int tcp_win_from_space(int space)
 {
-	return sysctl_tcp_adv_win_scale<=0 ?
-		(space>>(-sysctl_tcp_adv_win_scale)) :
-		space - (space>>sysctl_tcp_adv_win_scale);
+	int tcp_adv_win_scale = sysctl_tcp_adv_win_scale;
+
+	return tcp_adv_win_scale <= 0 ?
+		(space>>(-tcp_adv_win_scale)) :
+		space - (space>>tcp_adv_win_scale);
 }
 
 /* Note: caller must be prepared to deal with negative returns */
@@ -1438,6 +1451,11 @@
 void tcp_fastopen_init_key_once(bool publish);
 #define TCP_FASTOPEN_KEY_LENGTH 16
 
+static inline void tcp_init_send_head(struct sock *sk)
+{
+	sk->sk_send_head = NULL;
+}
+
 /* Fastopen key context */
 struct tcp_fastopen_context {
 	struct crypto_cipher	*tfm;
@@ -1454,6 +1472,8 @@
 		sk_wmem_free_skb(sk, skb);
 	sk_mem_reclaim(sk);
 	tcp_clear_all_retrans_hints(tcp_sk(sk));
+	tcp_init_send_head(sk);
+	inet_csk(sk)->icsk_backoff = 0;
 }
 
 static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk)
@@ -1510,11 +1530,29 @@
 {
 	if (sk->sk_send_head == skb_unlinked)
 		sk->sk_send_head = NULL;
+	if (tcp_sk(sk)->highest_sack == skb_unlinked)
+		tcp_sk(sk)->highest_sack = NULL;
 }
 
-static inline void tcp_init_send_head(struct sock *sk)
+static inline struct sk_buff *tcp_rtx_queue_head(const struct sock *sk)
 {
-	sk->sk_send_head = NULL;
+	struct sk_buff *skb = tcp_write_queue_head(sk);
+
+	if (skb == tcp_send_head(sk))
+		skb = NULL;
+
+	return skb;
+}
+
+static inline struct sk_buff *tcp_rtx_queue_tail(const struct sock *sk)
+{
+	struct sk_buff *skb = tcp_send_head(sk);
+
+	/* empty retransmit queue, for example due to zero window */
+	if (skb == tcp_write_queue_head(sk))
+		return NULL;
+
+	return skb ? tcp_write_queue_prev(sk, skb) : tcp_write_queue_tail(sk);
 }
 
 static inline void __tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb)
@@ -1609,12 +1647,12 @@
 	tcp_sk(sk)->highest_sack = tcp_write_queue_head(sk);
 }
 
-/* Called when old skb is about to be deleted (to be combined with new skb) */
-static inline void tcp_highest_sack_combine(struct sock *sk,
+/* Called when old skb is about to be deleted and replaced by new skb */
+static inline void tcp_highest_sack_replace(struct sock *sk,
 					    struct sk_buff *old,
 					    struct sk_buff *new)
 {
-	if (tcp_sk(sk)->sacked_out && (old == tcp_sk(sk)->highest_sack))
+	if (old == tcp_highest_sack(sk))
 		tcp_sk(sk)->highest_sack = new;
 }
 
--- linux-4.4.0.orig/include/net/udplite.h
+++ linux-4.4.0/include/net/udplite.h
@@ -62,6 +62,7 @@
 		UDP_SKB_CB(skb)->cscov = cscov;
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
+		skb->csum_valid = 0;
         }
 
 	return 0;
--- linux-4.4.0.orig/include/net/vxlan.h
+++ linux-4.4.0/include/net/vxlan.h
@@ -161,6 +161,8 @@
 	struct vxlan_rdst default_dst;	/* default destination */
 	u32		  flags;	/* VXLAN_F_* in vxlan.h */
 
+	struct ip_tunnel_fan fan;
+
 	struct timer_list age_timer;
 	spinlock_t	  hash_lock;
 	unsigned int	  addrcnt;
--- linux-4.4.0.orig/include/net/x25.h
+++ linux-4.4.0/include/net/x25.h
@@ -298,10 +298,10 @@
 
 /* sysctl_net_x25.c */
 #ifdef CONFIG_SYSCTL
-void x25_register_sysctl(void);
+int x25_register_sysctl(void);
 void x25_unregister_sysctl(void);
 #else
-static inline void x25_register_sysctl(void) {};
+static inline int x25_register_sysctl(void) { return 0; };
 static inline void x25_unregister_sysctl(void) {};
 #endif /* CONFIG_SYSCTL */
 
--- linux-4.4.0.orig/include/net/xfrm.h
+++ linux-4.4.0/include/net/xfrm.h
@@ -359,8 +359,6 @@
 int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo);
 int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo);
 
-void xfrm_state_delete_tunnel(struct xfrm_state *x);
-
 struct xfrm_type {
 	char			*description;
 	struct module		*owner;
@@ -948,10 +946,6 @@
 	struct flow_cache_object flo;
 	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
 	int num_pols, num_xfrms;
-#ifdef CONFIG_XFRM_SUB_POLICY
-	struct flowi *origin;
-	struct xfrm_selector *partner;
-#endif
 	u32 xfrm_genid;
 	u32 policy_genid;
 	u32 route_mtu_cached;
@@ -967,12 +961,6 @@
 	dst_release(xdst->route);
 	if (likely(xdst->u.dst.xfrm))
 		xfrm_state_put(xdst->u.dst.xfrm);
-#ifdef CONFIG_XFRM_SUB_POLICY
-	kfree(xdst->origin);
-	xdst->origin = NULL;
-	kfree(xdst->partner);
-	xdst->partner = NULL;
-#endif
 }
 #endif
 
@@ -1311,6 +1299,23 @@
 	return atomic_read(&x->tunnel_users);
 }
 
+static inline bool xfrm_id_proto_valid(u8 proto)
+{
+	switch (proto) {
+	case IPPROTO_AH:
+	case IPPROTO_ESP:
+	case IPPROTO_COMP:
+#if IS_ENABLED(CONFIG_IPV6)
+	case IPPROTO_ROUTING:
+	case IPPROTO_DSTOPTS:
+#endif
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* IPSEC_PROTO_ANY only matches 3 IPsec protocols, 0 could match all. */
 static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
 {
 	return (!userproto || proto == userproto ||
@@ -1544,8 +1549,10 @@
 void xfrm4_local_error(struct sk_buff *skb, u32 mtu);
 int xfrm6_extract_header(struct sk_buff *skb);
 int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
-int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
+int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi,
+		  struct ip6_tnl *t);
 int xfrm6_transport_finish(struct sk_buff *skb, int async);
+int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t);
 int xfrm6_rcv(struct sk_buff *skb);
 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 		     xfrm_address_t *saddr, u8 proto);
@@ -1590,13 +1597,15 @@
 		     void *);
 void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
-struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
+struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net,
+					  const struct xfrm_mark *mark,
 					  u8 type, int dir,
 					  struct xfrm_selector *sel,
 					  struct xfrm_sec_ctx *ctx, int delete,
 					  int *err);
-struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir,
-				     u32 id, int delete, int *err);
+struct xfrm_policy *xfrm_policy_byid(struct net *net,
+				     const struct xfrm_mark *mark, u8,
+				     int dir, u32 id, int delete, int *err);
 int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
 void xfrm_policy_hash_rebuild(struct net *net);
 u32 xfrm_get_acqseq(void);
@@ -1721,21 +1730,17 @@
 static inline int xfrm_replay_clone(struct xfrm_state *x,
 				     struct xfrm_state *orig)
 {
-	x->replay_esn = kzalloc(xfrm_replay_state_esn_len(orig->replay_esn),
+
+	x->replay_esn = kmemdup(orig->replay_esn,
+				xfrm_replay_state_esn_len(orig->replay_esn),
 				GFP_KERNEL);
 	if (!x->replay_esn)
 		return -ENOMEM;
-
-	x->replay_esn->bmp_len = orig->replay_esn->bmp_len;
-	x->replay_esn->replay_window = orig->replay_esn->replay_window;
-
-	x->preplay_esn = kmemdup(x->replay_esn,
-				 xfrm_replay_state_esn_len(x->replay_esn),
+	x->preplay_esn = kmemdup(orig->preplay_esn,
+				 xfrm_replay_state_esn_len(orig->preplay_esn),
 				 GFP_KERNEL);
-	if (!x->preplay_esn) {
-		kfree(x->replay_esn);
+	if (!x->preplay_esn)
 		return -ENOMEM;
-	}
 
 	return 0;
 }
--- linux-4.4.0.orig/include/rdma/ib.h
+++ linux-4.4.0/include/rdma/ib.h
@@ -34,6 +34,7 @@
 #define _RDMA_IB_H
 
 #include <linux/types.h>
+#include <linux/sched.h>
 
 struct ib_addr {
 	union {
@@ -86,4 +87,19 @@
 	__u64			sib_scope_id;
 };
 
+/*
+ * The IB interfaces that use write() as bi-directional ioctl() are
+ * fundamentally unsafe, since there are lots of ways to trigger "write()"
+ * calls from various contexts with elevated privileges. That includes the
+ * traditional suid executable error message writes, but also various kernel
+ * interfaces that can write to file descriptors.
+ *
+ * This function provides protection for the legacy API by restricting the
+ * calling context.
+ */
+static inline bool ib_safe_file_access(struct file *filp)
+{
+	return filp->f_cred == current_cred() && segment_eq(get_fs(), USER_DS);
+}
+
 #endif /* _RDMA_IB_H */
--- linux-4.4.0.orig/include/rdma/ib_addr.h
+++ linux-4.4.0/include/rdma/ib_addr.h
@@ -123,6 +123,8 @@
 	      const unsigned char *dst_dev_addr);
 
 int rdma_addr_size(struct sockaddr *addr);
+int rdma_addr_size_in6(struct sockaddr_in6 *addr);
+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr);
 
 int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id);
 int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgid,
@@ -197,10 +199,14 @@
 
 	dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
 	if (dev) {
-		ip4 = (struct in_device *)dev->ip_ptr;
+		ip4 = in_dev_get(dev);
 		if (ip4 && ip4->ifa_list && ip4->ifa_list->ifa_address)
 			ipv6_addr_set_v4mapped(ip4->ifa_list->ifa_address,
 					       (struct in6_addr *)gid);
+
+		if (ip4)
+			in_dev_put(ip4);
+
 		dev_put(dev);
 	}
 }
--- linux-4.4.0.orig/include/rdma/ib_mad.h
+++ linux-4.4.0/include/rdma/ib_mad.h
@@ -438,6 +438,7 @@
 /**
  * ib_mad_recv_handler - callback handler for a received MAD.
  * @mad_agent: MAD agent requesting the received MAD.
+ * @send_buf: Send buffer if found, else NULL
  * @mad_recv_wc: Received work completion information on the received MAD.
  *
  * MADs received in response to a send request operation will be handed to
@@ -447,6 +448,7 @@
  * modify the data referenced by @mad_recv_wc.
  */
 typedef void (*ib_mad_recv_handler)(struct ib_mad_agent *mad_agent,
+				    struct ib_mad_send_buf *send_buf,
 				    struct ib_mad_recv_wc *mad_recv_wc);
 
 /**
--- linux-4.4.0.orig/include/rdma/ib_sa.h
+++ linux-4.4.0/include/rdma/ib_sa.h
@@ -138,12 +138,12 @@
 	union ib_gid sgid;
 	__be16       dlid;
 	__be16       slid;
-	int          raw_traffic;
+	u8           raw_traffic;
 	/* reserved */
 	__be32       flow_label;
 	u8           hop_limit;
 	u8           traffic_class;
-	int          reversible;
+	u8           reversible;
 	u8           numb_path;
 	__be16       pkey;
 	__be16       qos_class;
@@ -204,7 +204,7 @@
 	u8           hop_limit;
 	u8           scope;
 	u8           join_state;
-	int          proxy_join;
+	u8           proxy_join;
 };
 
 /* Service Record Component Mask Sec 15.2.5.14 Ver 1.1	*/
--- linux-4.4.0.orig/include/rdma/ib_verbs.h
+++ linux-4.4.0/include/rdma/ib_verbs.h
@@ -3007,6 +3007,20 @@
 	return 0;
 }
 
+static inline bool ib_access_writable(int access_flags)
+{
+	/*
+	 * We have writable memory backing the MR if any of the following
+	 * access flags are set.  "Local write" and "remote write" obviously
+	 * require write access.  "Remote atomic" can do things like fetch and
+	 * add, which will modify memory, and "MW bind" can change permissions
+	 * by binding a window.
+	 */
+	return access_flags &
+		(IB_ACCESS_LOCAL_WRITE   | IB_ACCESS_REMOTE_WRITE |
+		 IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_MW_BIND);
+}
+
 /**
  * ib_check_mr_status: lightweight check of MR status.
  *     This routine may provide status checks on a selected
--- linux-4.4.0.orig/include/rdma/rdma_cm.h
+++ linux-4.4.0/include/rdma/rdma_cm.h
@@ -284,6 +284,9 @@
  */
 int rdma_listen(struct rdma_cm_id *id, int backlog);
 
+void rdma_lock_handler(struct rdma_cm_id *id);
+void rdma_unlock_handler(struct rdma_cm_id *id);
+
 /**
  * rdma_accept - Called to accept a connection request or response.
  * @id: Connection identifier associated with the request.
@@ -298,6 +301,9 @@
  * In the case of error, a reject message is sent to the remote side and the
  * state of the qp associated with the id is modified to error, such that any
  * previously posted receive buffers would be flushed.
+ *
+ * This function is for use by kernel ULPs and must be called from under the
+ * handler callback.
  */
 int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);
 
--- linux-4.4.0.orig/include/scsi/libfcoe.h
+++ linux-4.4.0/include/scsi/libfcoe.h
@@ -236,6 +236,7 @@
  * @vn_mac:	VN_Node assigned MAC address for data
  */
 struct fcoe_rport {
+	struct fc_rport_priv rdata;
 	unsigned long time;
 	u16 fcoe_len;
 	u16 flags;
--- linux-4.4.0.orig/include/scsi/libiscsi.h
+++ linux-4.4.0/include/scsi/libiscsi.h
@@ -144,6 +144,9 @@
 	void			*dd_data;	/* driver/transport data */
 };
 
+/* invalid scsi_task pointer */
+#define	INVALID_SCSI_TASK	(struct iscsi_task *)-1l
+
 static inline int iscsi_task_has_unsol_data(struct iscsi_task *task)
 {
 	return task->unsol_r2t.data_length > task->unsol_r2t.sent;
@@ -196,6 +199,7 @@
 	struct iscsi_task	*task;		/* xmit task in progress */
 
 	/* xmit */
+	spinlock_t		taskqueuelock;  /* protects the next three lists */
 	struct list_head	mgmtqueue;	/* mgmt (control) xmit queue */
 	struct list_head	cmdqueue;	/* data-path cmd queue */
 	struct list_head	requeue;	/* tasks needing another run */
@@ -331,19 +335,12 @@
 	struct iscsi_transport	*tt;
 	struct Scsi_Host	*host;
 	struct iscsi_conn	*leadconn;	/* leading connection */
-	/* Between the forward and the backward locks exists a strict locking
-	 * hierarchy. The mutual exclusion zone protected by the forward lock
-	 * can enclose the mutual exclusion zone protected by the backward lock
-	 * but not vice versa.
-	 */
-	spinlock_t		frwd_lock;	/* protects session state, *
-						 * cmdsn, queued_cmdsn     *
+	spinlock_t		lock;		/* protects session state, *
+						 * sequence numbers,       *
 						 * session resources:      *
-						 * - cmdpool kfifo_out ,   *
-						 * - mgmtpool,		   */
-	spinlock_t		back_lock;	/* protects cmdsn_exp      *
-						 * cmdsn_max,              *
-						 * cmdpool kfifo_in        */
+						 * - cmdpool,		   *
+						 * - mgmtpool,		   *
+						 * - r2tpool		   */
 	int			state;		/* session state           */
 	int			age;		/* counts session re-opens */
 
@@ -409,6 +406,8 @@
 extern struct iscsi_cls_session *
 iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
 		    uint16_t, int, int, uint32_t, unsigned int);
+void iscsi_session_remove(struct iscsi_cls_session *cls_session);
+void iscsi_session_free(struct iscsi_cls_session *cls_session);
 extern void iscsi_session_teardown(struct iscsi_cls_session *);
 extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
 extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
--- linux-4.4.0.orig/include/scsi/libiscsi_tcp.h
+++ linux-4.4.0/include/scsi/libiscsi_tcp.h
@@ -83,8 +83,6 @@
 	struct iscsi_pool	r2tpool;
 	struct kfifo		r2tqueue;
 	void			*dd_data;
-	spinlock_t		pool2queue;
-	spinlock_t		queue2pool;
 };
 
 enum {
--- linux-4.4.0.orig/include/scsi/libsas.h
+++ linux-4.4.0/include/scsi/libsas.h
@@ -85,13 +85,11 @@
 
 enum discover_event {
 	DISCE_DISCOVER_DOMAIN   = 0U,
-	DISCE_REVALIDATE_DOMAIN = 1,
-	DISCE_PORT_GONE         = 2,
-	DISCE_PROBE		= 3,
-	DISCE_SUSPEND		= 4,
-	DISCE_RESUME		= 5,
-	DISCE_DESTRUCT		= 6,
-	DISC_NUM_EVENTS		= 7,
+	DISCE_REVALIDATE_DOMAIN,
+	DISCE_PORT_GONE,
+	DISCE_SUSPEND,
+	DISCE_RESUME,
+	DISC_NUM_EVENTS,
 };
 
 /* ---------- Expander Devices ---------- */
@@ -165,11 +163,11 @@
 
 struct sata_device {
 	unsigned int class;
-	struct smp_resp        rps_resp; /* report_phy_sata_resp */
 	u8     port_no;        /* port number, if this is a PM (Port) */
 
 	struct ata_port *ap;
 	struct ata_host ata_host;
+	struct smp_resp rps_resp ____cacheline_aligned; /* report_phy_sata_resp */
 	u8     fis[ATA_RESP_FIS_SIZE];
 };
 
@@ -269,6 +267,7 @@
 	struct list_head dev_list;
 	struct list_head disco_list;
 	struct list_head destroy_list;
+	struct list_head sas_port_del_list;
 	enum   sas_linkrate linkrate;
 
 	struct sas_work work;
--- linux-4.4.0.orig/include/scsi/scsi_cmnd.h
+++ linux-4.4.0/include/scsi/scsi_cmnd.h
@@ -214,7 +214,7 @@
 }
 
 static inline int scsi_sg_copy_from_buffer(struct scsi_cmnd *cmd,
-					   void *buf, int buflen)
+					   const void *buf, int buflen)
 {
 	return sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
 				   buf, buflen);
--- linux-4.4.0.orig/include/scsi/scsi_common.h
+++ linux-4.4.0/include/scsi/scsi_common.h
@@ -24,6 +24,13 @@
 		scsi_varlen_cdb_length(cmnd) : COMMAND_SIZE(cmnd[0]);
 }
 
+static inline unsigned char
+scsi_command_control(const unsigned char *cmnd)
+{
+	return (cmnd[0] == VARIABLE_LENGTH_CMD) ?
+		cmnd[1] : cmnd[COMMAND_SIZE(cmnd[0]) - 1];
+}
+
 /* Returns a human-readable name for the device */
 extern const char *scsi_device_type(unsigned type);
 
--- linux-4.4.0.orig/include/scsi/scsi_dbg.h
+++ linux-4.4.0/include/scsi/scsi_dbg.h
@@ -5,8 +5,6 @@
 struct scsi_device;
 struct scsi_sense_hdr;
 
-#define SCSI_LOG_BUFSIZE 128
-
 extern void scsi_print_command(struct scsi_cmnd *);
 extern size_t __scsi_format_command(char *, size_t,
 				   const unsigned char *, size_t);
--- linux-4.4.0.orig/include/scsi/scsi_device.h
+++ linux-4.4.0/include/scsi/scsi_device.h
@@ -175,6 +175,7 @@
 	unsigned no_dif:1;	/* T10 PI (DIF) should be disabled */
 	unsigned broken_fua:1;		/* Don't set FUA bit */
 	unsigned lun_in_cdb:1;		/* Store LUN bits in CDB[1] */
+	unsigned synchronous_alua:1;	/* Synchronous ALUA commands */
 
 	atomic_t disk_events_disable_depth; /* disable depth for disk events */
 
@@ -239,6 +240,8 @@
 enum scsi_target_state {
 	STARGET_CREATED = 1,
 	STARGET_RUNNING,
+	STARGET_REMOVE,
+	STARGET_CREATED_REMOVE,
 	STARGET_DEL,
 };
 
@@ -306,6 +309,7 @@
 extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
 void scsi_attach_vpd(struct scsi_device *sdev);
 
+extern struct scsi_device *scsi_device_from_queue(struct request_queue *q);
 extern int scsi_device_get(struct scsi_device *);
 extern void scsi_device_put(struct scsi_device *);
 extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *,
@@ -414,6 +418,8 @@
 }
 extern void sdev_disable_disk_events(struct scsi_device *sdev);
 extern void sdev_enable_disk_events(struct scsi_device *sdev);
+extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t);
+extern int scsi_vpd_tpg_id(struct scsi_device *, int *);
 
 #ifdef CONFIG_PM
 extern int scsi_autopm_get_device(struct scsi_device *);
--- linux-4.4.0.orig/include/scsi/scsi_devinfo.h
+++ linux-4.4.0/include/scsi/scsi_devinfo.h
@@ -37,5 +37,6 @@
 #define BLIST_TRY_VPD_PAGES	0x10000000 /* Attempt to read VPD pages */
 #define BLIST_NO_RSOC		0x20000000 /* don't try to issue RSOC */
 #define BLIST_MAX_1024		0x40000000 /* maximum 1024 sector cdb length */
+#define BLIST_SYNC_ALUA		0x80000000 /* Synchronous ALUA commands */
 
 #endif
--- linux-4.4.0.orig/include/scsi/scsi_dh.h
+++ linux-4.4.0/include/scsi/scsi_dh.h
@@ -52,6 +52,7 @@
 	SCSI_DH_TIMED_OUT,
 	SCSI_DH_RES_TEMP_UNAVAIL,
 	SCSI_DH_DEV_OFFLINED,
+	SCSI_DH_NOMEM,
 	SCSI_DH_NOSYS,
 	SCSI_DH_DRIVER_MAX,
 };
--- linux-4.4.0.orig/include/scsi/scsi_transport_sas.h
+++ linux-4.4.0/include/scsi/scsi_transport_sas.h
@@ -10,6 +10,21 @@
 struct sas_rphy;
 struct request;
 
+#if !IS_ENABLED(CONFIG_SCSI_SAS_ATTRS)
+static inline int is_sas_attached(struct scsi_device *sdev)
+{
+	return 0;
+}
+
+static inline int scsi_is_sas_rphy(const struct device *sdev)
+{
+	return 0;
+}
+#else
+extern int is_sas_attached(struct scsi_device *sdev);
+extern int scsi_is_sas_rphy(const struct device *);
+#endif
+
 static inline int sas_protocol_ata(enum sas_protocol proto)
 {
 	return ((proto & SAS_PROTOCOL_SATA) ||
@@ -145,6 +160,7 @@
 
 	struct mutex		phy_list_mutex;
 	struct list_head	phy_list;
+	struct list_head	del_list; /* libsas only */
 };
 
 #define dev_to_sas_port(d) \
@@ -180,6 +196,7 @@
 extern void sas_phy_delete(struct sas_phy *);
 extern int scsi_is_sas_phy(const struct device *);
 
+u64 sas_get_address(struct scsi_device *);
 unsigned int sas_tlr_supported(struct scsi_device *);
 unsigned int sas_is_tlr_enabled(struct scsi_device *);
 void sas_disable_tlr(struct scsi_device *);
@@ -192,7 +209,6 @@
 extern void sas_rphy_remove(struct sas_rphy *);
 extern void sas_rphy_delete(struct sas_rphy *);
 extern void sas_rphy_unlink(struct sas_rphy *);
-extern int scsi_is_sas_rphy(const struct device *);
 
 struct sas_port *sas_port_alloc(struct device *, int);
 struct sas_port *sas_port_alloc_num(struct device *);
--- linux-4.4.0.orig/include/scsi/sg.h
+++ linux-4.4.0/include/scsi/sg.h
@@ -197,7 +197,6 @@
 #define SG_DEFAULT_RETRIES 0
 
 /* Defaults, commented if they differ from original sg driver */
-#define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
 #define SG_DEF_FORCE_PACK_ID 0
 #define SG_DEF_KEEP_ORPHAN 0
 #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
--- linux-4.4.0.orig/include/scsi/viosrp.h
+++ linux-4.4.0/include/scsi/viosrp.h
@@ -0,0 +1,212 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* This file contains structures and definitions for IBM RPA (RS/6000        */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
+/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
+/* commands between logical partitions.                                      */
+/*                                                                           */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
+/* between partitions.  The definitions in this file are architected,        */
+/* and cannot be changed without breaking compatibility with other versions  */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions                                                */
+/*****************************************************************************/
+#ifndef VIOSRP_H
+#define VIOSRP_H
+#include <scsi/srp.h>
+
+#define SRP_VERSION "16.a"
+#define SRP_MAX_IU_LEN	256
+#define SRP_MAX_LOC_LEN 32
+
+union srp_iu {
+	struct srp_login_req login_req;
+	struct srp_login_rsp login_rsp;
+	struct srp_login_rej login_rej;
+	struct srp_i_logout i_logout;
+	struct srp_t_logout t_logout;
+	struct srp_tsk_mgmt tsk_mgmt;
+	struct srp_cmd cmd;
+	struct srp_rsp rsp;
+	u8 reserved[SRP_MAX_IU_LEN];
+};
+
+enum viosrp_crq_formats {
+	VIOSRP_SRP_FORMAT = 0x01,
+	VIOSRP_MAD_FORMAT = 0x02,
+	VIOSRP_OS400_FORMAT = 0x03,
+	VIOSRP_AIX_FORMAT = 0x04,
+	VIOSRP_LINUX_FORMAT = 0x06,
+	VIOSRP_INLINE_FORMAT = 0x07
+};
+
+enum viosrp_crq_status {
+	VIOSRP_OK = 0x0,
+	VIOSRP_NONRECOVERABLE_ERR = 0x1,
+	VIOSRP_VIOLATES_MAX_XFER = 0x2,
+	VIOSRP_PARTNER_PANIC = 0x3,
+	VIOSRP_DEVICE_BUSY = 0x8,
+	VIOSRP_ADAPTER_FAIL = 0x10,
+	VIOSRP_OK2 = 0x99,
+};
+
+struct viosrp_crq {
+	u8 valid;		/* used by RPA */
+	u8 format;		/* SCSI vs out-of-band */
+	u8 reserved;
+	u8 status;		/* non-scsi failure? (e.g. DMA failure) */
+	__be16 timeout;		/* in seconds */
+	__be16 IU_length;		/* in bytes */
+	__be64 IU_data_ptr;	/* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.
+ */
+enum viosrp_mad_types {
+	VIOSRP_EMPTY_IU_TYPE = 0x01,
+	VIOSRP_ERROR_LOG_TYPE = 0x02,
+	VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+	VIOSRP_HOST_CONFIG_TYPE = 0x04,
+	VIOSRP_CAPABILITIES_TYPE = 0x05,
+	VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+	VIOSRP_MAD_SUCCESS = 0x00,
+	VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+	VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+	MIGRATION_CAPABILITIES = 0x01,
+	RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+	SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+	SERVER_SUPPORTS_CAP = 0x01,
+	SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+	CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+	CLIENT_MIGRATED = 0x01,
+	CLIENT_RECONNECT = 0x02,
+	CAP_LIST_SUPPORTED = 0x04,
+	CAP_LIST_DATA = 0x08,
+};
+
+/*
+ * Common MAD header
+ */
+struct mad_common {
+	__be32 type;
+	__be16 status;
+	__be16 length;
+	__be64 tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server.  There is no way for the server to send
+ * an asynchronous message back to the client.  The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER
+ */
+struct viosrp_empty_iu {
+	struct mad_common common;
+	__be64 buffer;
+	__be32 port;
+};
+
+struct viosrp_error_log {
+	struct mad_common common;
+	__be64 buffer;
+};
+
+struct viosrp_adapter_info {
+	struct mad_common common;
+	__be64 buffer;
+};
+
+struct viosrp_host_config {
+	struct mad_common common;
+	__be64 buffer;
+};
+
+struct viosrp_fast_fail {
+	struct mad_common common;
+};
+
+struct viosrp_capabilities {
+	struct mad_common common;
+	__be64 buffer;
+};
+
+struct mad_capability_common {
+	__be32 cap_type;
+	__be16 length;
+	__be16 server_support;
+};
+
+struct mad_reserve_cap {
+	struct mad_capability_common common;
+	__be32 type;
+};
+
+struct mad_migration_cap {
+	struct mad_capability_common common;
+	__be32 ecl;
+};
+
+struct capabilities {
+	__be32 flags;
+	char name[SRP_MAX_LOC_LEN];
+	char loc[SRP_MAX_LOC_LEN];
+	struct mad_migration_cap migration;
+	struct mad_reserve_cap reserve;
+};
+
+union mad_iu {
+	struct viosrp_empty_iu empty_iu;
+	struct viosrp_error_log error_log;
+	struct viosrp_adapter_info adapter_info;
+	struct viosrp_host_config host_config;
+	struct viosrp_fast_fail fast_fail;
+	struct viosrp_capabilities capabilities;
+};
+
+union viosrp_iu {
+	union srp_iu srp;
+	union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+	char srp_version[8];
+	char partition_name[96];
+	__be32 partition_number;
+	__be32 mad_version;
+	__be32 os_type;
+	__be32 port_max_txu[8];	/* per-port maximum transfer */
+};
+
+#endif
--- linux-4.4.0.orig/include/soc/at91/at91sam9_ddrsdr.h
+++ linux-4.4.0/include/soc/at91/at91sam9_ddrsdr.h
@@ -81,6 +81,7 @@
 #define			AT91_DDRSDRC_LPCB_POWER_DOWN		2
 #define			AT91_DDRSDRC_LPCB_DEEP_POWER_DOWN	3
 #define		AT91_DDRSDRC_CLKFR	(1 << 2)	/* Clock Frozen */
+#define		AT91_DDRSDRC_LPDDR2_PWOFF	(1 << 3)	/* LPDDR Power Off */
 #define		AT91_DDRSDRC_PASR	(7 << 4)	/* Partial Array Self Refresh */
 #define		AT91_DDRSDRC_TCSR	(3 << 8)	/* Temperature Compensated Self Refresh */
 #define		AT91_DDRSDRC_DS		(3 << 10)	/* Drive Strength */
@@ -96,7 +97,9 @@
 #define			AT91_DDRSDRC_MD_SDR		0
 #define			AT91_DDRSDRC_MD_LOW_POWER_SDR	1
 #define			AT91_DDRSDRC_MD_LOW_POWER_DDR	3
+#define			AT91_DDRSDRC_MD_LPDDR3		5
 #define			AT91_DDRSDRC_MD_DDR2		6	/* [SAM9 Only] */
+#define			AT91_DDRSDRC_MD_LPDDR2		7
 #define		AT91_DDRSDRC_DBW	(1 << 4)		/* Data Bus Width */
 #define			AT91_DDRSDRC_DBW_32BITS		(0 <<  4)
 #define			AT91_DDRSDRC_DBW_16BITS		(1 <<  4)
--- linux-4.4.0.orig/include/soc/tegra/mc.h
+++ linux-4.4.0/include/soc/tegra/mc.h
@@ -99,6 +99,8 @@
 	u8 client_id_mask;
 
 	const struct tegra_smmu_soc *smmu;
+
+	u32 intmask;
 };
 
 struct tegra_mc {
--- linux-4.4.0.orig/include/sound/compress_driver.h
+++ linux-4.4.0/include/sound/compress_driver.h
@@ -71,6 +71,7 @@
  * @direction: stream direction, playback/recording
  * @metadata_set: metadata set flag, true when set
  * @next_track: has userspace signal next track transition, true when set
+ * @partial_drain: undergoing partial_drain for stream, true when set
  * @private_data: pointer to DSP private data
  */
 struct snd_compr_stream {
@@ -81,6 +82,7 @@
 	enum snd_compr_direction direction;
 	bool metadata_set;
 	bool next_track;
+	bool partial_drain;
 	void *private_data;
 };
 
@@ -178,7 +180,14 @@
 	if (snd_BUG_ON(!stream))
 		return;
 
-	stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+	/* for partial_drain case we are back to running state on success */
+	if (stream->partial_drain) {
+		stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+		stream->partial_drain = false; /* clear this flag as well */
+	} else {
+		stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+	}
+
 	wake_up(&stream->runtime->sleep);
 }
 
--- linux-4.4.0.orig/include/sound/control.h
+++ linux-4.4.0/include/sound/control.h
@@ -22,6 +22,7 @@
  *
  */
 
+#include <linux/nospec.h>
 #include <sound/asound.h>
 
 #define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data)
@@ -147,12 +148,14 @@
 
 static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
 {
-	return id->numid - kctl->id.numid;
+	unsigned int ioff = id->numid - kctl->id.numid;
+	return array_index_nospec(ioff, kctl->count);
 }
 
 static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
 {
-	return id->index - kctl->id.index;
+	unsigned int ioff = id->index - kctl->id.index;
+	return array_index_nospec(ioff, kctl->count);
 }
 
 static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
--- linux-4.4.0.orig/include/sound/hda_i915.h
+++ linux-4.4.0/include/sound/hda_i915.h
@@ -11,6 +11,7 @@
 int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
 int snd_hdac_get_display_clk(struct hdac_bus *bus);
 int snd_hdac_i915_init(struct hdac_bus *bus);
+int snd_hdac_i915_init_bpo(struct hdac_bus *bus);
 int snd_hdac_i915_exit(struct hdac_bus *bus);
 int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *);
 #else
@@ -30,6 +31,10 @@
 {
 	return -ENODEV;
 }
+static inline int snd_hdac_i915_init_bpo(struct hdac_bus *bus)
+{
+	return -ENODEV;
+}
 static inline int snd_hdac_i915_exit(struct hdac_bus *bus)
 {
 	return 0;
--- linux-4.4.0.orig/include/sound/pcm.h
+++ linux-4.4.0/include/sound/pcm.h
@@ -100,7 +100,7 @@
 #endif
 
 #define SNDRV_PCM_IOCTL1_RESET		0
-#define SNDRV_PCM_IOCTL1_INFO		1
+/* 1 is absent slot. */
 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO	2
 #define SNDRV_PCM_IOCTL1_GSTATE		3
 #define SNDRV_PCM_IOCTL1_FIFO_SIZE	4
--- linux-4.4.0.orig/include/sound/pcm_oss.h
+++ linux-4.4.0/include/sound/pcm_oss.h
@@ -57,6 +57,7 @@
 	char *buffer;				/* vmallocated period */
 	size_t buffer_used;			/* used length from period buffer */
 	struct mutex params_lock;
+	atomic_t rw_ref;		/* concurrent read/write accesses */
 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	struct snd_pcm_plugin *plugin_first;
 	struct snd_pcm_plugin *plugin_last;
--- linux-4.4.0.orig/include/sound/pcm_params.h
+++ linux-4.4.0/include/sound/pcm_params.h
@@ -247,11 +247,13 @@
 static inline int snd_interval_single(const struct snd_interval *i)
 {
 	return (i->min == i->max || 
-		(i->min + 1 == i->max && i->openmax));
+		(i->min + 1 == i->max && (i->openmin || i->openmax)));
 }
 
 static inline int snd_interval_value(const struct snd_interval *i)
 {
+	if (i->openmin && !i->openmax)
+		return i->max;
 	return i->min;
 }
 
--- linux-4.4.0.orig/include/sound/rawmidi.h
+++ linux-4.4.0/include/sound/rawmidi.h
@@ -76,6 +76,7 @@
 	size_t avail_min;	/* min avail for wakeup */
 	size_t avail;		/* max used buffer for wakeup */
 	size_t xruns;		/* over/underruns counter */
+	int buffer_ref;		/* buffer reference count */
 	/* misc */
 	spinlock_t lock;
 	wait_queue_head_t sleep;
@@ -92,9 +93,9 @@
 	struct list_head list;		/* list of all substream for given stream */
 	int stream;			/* direction */
 	int number;			/* substream number */
-	unsigned int opened: 1,		/* open flag */
-		     append: 1,		/* append flag (merge more streams) */
-		     active_sensing: 1; /* send active sensing when close */
+	bool opened;			/* open flag */
+	bool append;			/* append flag (merge more streams) */
+	bool active_sensing;		/* send active sensing when close */
 	int use_count;			/* use counter (for output) */
 	size_t bytes;
 	struct snd_rawmidi *rmidi;
@@ -167,6 +168,10 @@
 int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count);
 int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
 			 unsigned char *buffer, int count);
+int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
+			      unsigned char *buffer, int count);
+int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
+			       int count);
 
 /* main midi functions */
 
--- linux-4.4.0.orig/include/sound/rt5660.h
+++ linux-4.4.0/include/sound/rt5660.h
@@ -0,0 +1,31 @@
+/*
+ * linux/sound/rt5660.h -- Platform data for RT5660
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.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 __LINUX_SND_RT5660_H
+#define __LINUX_SND_RT5660_H
+
+enum rt5660_dmic1_data_pin {
+	RT5660_DMIC1_NULL,
+	RT5660_DMIC1_DATA_GPIO2,
+	RT5660_DMIC1_DATA_IN1P,
+};
+
+struct rt5660_platform_data {
+	/* IN1 & IN3 can optionally be differential */
+	bool in1_diff;
+	bool in3_diff;
+	bool use_ldo2;
+	bool poweroff_codec_in_suspend;
+
+	enum rt5660_dmic1_data_pin dmic1_data_pin;
+};
+
+#endif
--- linux-4.4.0.orig/include/sound/seq_kernel.h
+++ linux-4.4.0/include/sound/seq_kernel.h
@@ -49,7 +49,8 @@
 #define SNDRV_SEQ_DEFAULT_CLIENT_EVENTS	200
 
 /* max delivery path length */
-#define SNDRV_SEQ_MAX_HOPS		10
+/* NOTE: this shouldn't be greater than MAX_LOCKDEP_SUBCLASSES */
+#define SNDRV_SEQ_MAX_HOPS		8
 
 /* max size of event size */
 #define SNDRV_SEQ_MAX_EVENT_LEN		0x3fffffff
--- linux-4.4.0.orig/include/sound/seq_virmidi.h
+++ linux-4.4.0/include/sound/seq_virmidi.h
@@ -60,6 +60,7 @@
 	int port;			/* created/attached port */
 	unsigned int flags;		/* SNDRV_VIRMIDI_* */
 	rwlock_t filelist_lock;
+	struct rw_semaphore filelist_sem;
 	struct list_head filelist;
 };
 
--- linux-4.4.0.orig/include/sound/soc-dapm.h
+++ linux-4.4.0/include/sound/soc-dapm.h
@@ -335,6 +335,8 @@
 #define SND_SOC_DAPM_WILL_PMD   0x80    /* called at start of sequence */
 #define SND_SOC_DAPM_PRE_POST_PMD \
 				(SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
+#define SND_SOC_DAPM_PRE_POST_PMU \
+				(SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
 
 /* convenience event type detection */
 #define SND_SOC_DAPM_EVENT_ON(e)	\
--- linux-4.4.0.orig/include/target/iscsi/iscsi_target_core.h
+++ linux-4.4.0/include/target/iscsi/iscsi_target_core.h
@@ -64,6 +64,14 @@
 #define TA_DEFAULT_FABRIC_PROT_TYPE	0
 /* TPG status needs to be enabled to return sendtargets discovery endpoint info */
 #define TA_DEFAULT_TPG_ENABLED_SENDTARGETS 1
+/*
+ * Used to control the sending of keys with optional to respond state bit,
+ * as a workaround for non RFC compliant initiators,that do not propose,
+ * nor respond to specific keys required for login to complete.
+ *
+ * See iscsi_check_proposer_for_optional_reply() for more details.
+ */
+#define TA_DEFAULT_LOGIN_KEYS_WORKAROUND 1
 
 #define ISCSI_IOV_DATA_BUFFER		5
 
@@ -554,6 +562,7 @@
 #define LOGIN_FLAGS_READ_ACTIVE		1
 #define LOGIN_FLAGS_CLOSED		2
 #define LOGIN_FLAGS_READY		4
+#define LOGIN_FLAGS_INITIAL_PDU		8
 	unsigned long		login_flags;
 	struct delayed_work	login_work;
 	struct delayed_work	login_cleanup_work;
@@ -765,6 +774,7 @@
 	u8			t10_pi;
 	u32			fabric_prot_type;
 	u32			tpg_enabled_sendtargets;
+	u32			login_keys_workaround;
 	struct iscsi_portal_group *tpg;
 };
 
@@ -774,6 +784,7 @@
 	int			np_sock_type;
 	enum np_thread_state_table np_thread_state;
 	bool                    enabled;
+	atomic_t		np_reset_count;
 	enum iscsi_timer_flags_table np_login_timer_flags;
 	u32			np_exports;
 	enum np_flags_table	np_flags;
--- linux-4.4.0.orig/include/target/target_core_backend.h
+++ linux-4.4.0/include/target/target_core_backend.h
@@ -94,5 +94,8 @@
 	sense_reason_t (*exec_cmd)(struct se_cmd *cmd));
 
 bool target_sense_desc_format(struct se_device *dev);
+sector_t target_to_linux_sector(struct se_device *dev, sector_t lb);
+bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
+				       struct request_queue *q);
 
 #endif /* TARGET_CORE_BACKEND_H */
--- linux-4.4.0.orig/include/target/target_core_base.h
+++ linux-4.4.0/include/target/target_core_base.h
@@ -138,6 +138,9 @@
 	SCF_COMPARE_AND_WRITE		= 0x00080000,
 	SCF_COMPARE_AND_WRITE_POST	= 0x00100000,
 	SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000,
+	SCF_ACK_KREF			= 0x00400000,
+	SCF_USE_CPUID			= 0x00800000,
+	SCF_TASK_ATTR_SET		= 0x01000000,
 };
 
 /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -178,6 +181,11 @@
 	TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED	= R(0x15),
 	TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED	= R(0x16),
 	TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED	= R(0x17),
+	TCM_COPY_TARGET_DEVICE_NOT_REACHABLE	= R(0x18),
+	TCM_TOO_MANY_TARGET_DESCS		= R(0x19),
+	TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE	= R(0x1a),
+	TCM_TOO_MANY_SEGMENT_DESCS		= R(0x1b),
+	TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE	= R(0x1c),
 #undef R
 };
 
@@ -185,6 +193,7 @@
 	TARGET_SCF_BIDI_OP		= 0x01,
 	TARGET_SCF_ACK_KREF		= 0x02,
 	TARGET_SCF_UNKNOWN_SIZE		= 0x04,
+	TARGET_SCF_USE_CPUID	= 0x08,
 };
 
 /* fabric independent task management function values */
@@ -196,6 +205,7 @@
 	TMR_LUN_RESET		= 5,
 	TMR_TARGET_WARM_RESET	= 6,
 	TMR_TARGET_COLD_RESET	= 7,
+	TMR_UNKNOWN		= 0xff,
 };
 
 /* fabric independent task management response values */
@@ -295,7 +305,7 @@
 	struct list_head tg_pt_gp_lun_list;
 	struct se_lun *tg_pt_gp_alua_lun;
 	struct se_node_acl *tg_pt_gp_alua_nacl;
-	struct delayed_work tg_pt_gp_transition_work;
+	struct work_struct tg_pt_gp_transition_work;
 	struct completion *tg_pt_gp_transition_complete;
 };
 
@@ -490,6 +500,9 @@
 #define CMD_T_DEV_ACTIVE	(1 << 7)
 #define CMD_T_REQUEST_STOP	(1 << 8)
 #define CMD_T_BUSY		(1 << 9)
+#define CMD_T_TAS		(1 << 10)
+#define CMD_T_FABRIC_STOP	(1 << 11)
+#define CMD_T_PRE_EXECUTE	(1 << 12)
 	spinlock_t		t_state_lock;
 	struct kref		cmd_kref;
 	struct completion	t_transport_stop_comp;
@@ -526,6 +539,7 @@
 	unsigned int		t_prot_nents;
 	sense_reason_t		pi_err;
 	sector_t		bad_sector;
+	int			cpuid;
 };
 
 struct se_ua {
@@ -539,6 +553,7 @@
 	/* Used to signal demo mode created ACL, disabled by default */
 	bool			dynamic_node_acl;
 	bool			acl_stop:1;
+	bool			dynamic_stop;
 	u32			queue_depth;
 	u32			acl_index;
 	enum target_prot_type	saved_prot_type;
@@ -708,6 +723,7 @@
 #define SE_LUN_LINK_MAGIC			0xffff7771
 	u32			lun_link_magic;
 	u32			lun_access;
+	bool			lun_shutdown;
 	u32			lun_index;
 
 	/* RELATIVE TARGET PORT IDENTIFER */
@@ -734,6 +750,7 @@
 	struct config_group	lun_group;
 	struct se_port_stat_grps port_stat_grps;
 	struct completion	lun_ref_comp;
+	struct completion	lun_shutdown_comp;
 	struct percpu_ref	lun_ref;
 	struct list_head	lun_dev_link;
 	struct hlist_node	link;
--- linux-4.4.0.orig/include/target/target_core_fabric.h
+++ linux-4.4.0/include/target/target_core_fabric.h
@@ -108,6 +108,12 @@
 int target_depend_item(struct config_item *item);
 void target_undepend_item(struct config_item *item);
 
+struct se_session *target_alloc_session(struct se_portal_group *,
+		unsigned int, unsigned int, enum target_prot_op prot_op,
+		const char *, void *,
+		int (*callback)(struct se_portal_group *,
+				struct se_session *, void *));
+
 struct se_session *transport_init_session(enum target_prot_op);
 int transport_alloc_session_tags(struct se_session *, unsigned int,
 		unsigned int);
@@ -117,7 +123,7 @@
 		struct se_node_acl *, struct se_session *, void *);
 void	transport_register_session(struct se_portal_group *,
 		struct se_node_acl *, struct se_session *, void *);
-void	target_get_session(struct se_session *);
+int	target_get_session(struct se_session *);
 void	target_put_session(struct se_session *);
 ssize_t	target_show_dynamic_sessions(struct se_portal_group *, char *);
 void	transport_free_session(struct se_session *);
@@ -163,16 +169,16 @@
 void	core_tmr_release_req(struct se_tmr_req *);
 int	transport_generic_handle_tmr(struct se_cmd *);
 void	transport_generic_request_failure(struct se_cmd *, sense_reason_t);
-void	__target_execute_cmd(struct se_cmd *);
 int	transport_lookup_tmr_lun(struct se_cmd *, u64);
 void	core_allocate_nexus_loss_ua(struct se_node_acl *acl);
 
 struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
 		unsigned char *);
+bool	target_tpg_has_node_acl(struct se_portal_group *tpg,
+		const char *);
 struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *,
 		unsigned char *);
-int	core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
-		unsigned char *, u32, int);
+int	core_tpg_set_initiator_node_queue_depth(struct se_node_acl *, u32);
 int	core_tpg_set_initiator_node_tag(struct se_portal_group *,
 		struct se_node_acl *, const char *);
 int	core_tpg_register(struct se_wwn *, struct se_portal_group *, int);
--- linux-4.4.0.orig/include/trace/events/clk.h
+++ linux-4.4.0/include/trace/events/clk.h
@@ -134,12 +134,12 @@
 
 	TP_STRUCT__entry(
 		__string(        name,           core->name                )
-		__string(        pname,          parent->name              )
+		__string(        pname, parent ? parent->name : "none"     )
 	),
 
 	TP_fast_assign(
 		__assign_str(name, core->name);
-		__assign_str(pname, parent->name);
+		__assign_str(pname, parent ? parent->name : "none");
 	),
 
 	TP_printk("%s %s", __get_str(name), __get_str(pname))
--- linux-4.4.0.orig/include/trace/events/compaction.h
+++ linux-4.4.0/include/trace/events/compaction.h
@@ -10,10 +10,11 @@
 #include <trace/events/gfpflags.h>
 
 #define COMPACTION_STATUS					\
-	EM( COMPACT_DEFERRED,		"deferred")		\
 	EM( COMPACT_SKIPPED,		"skipped")		\
+	EM( COMPACT_DEFERRED,		"deferred")		\
 	EM( COMPACT_CONTINUE,		"continue")		\
 	EM( COMPACT_PARTIAL,		"partial")		\
+	EM( COMPACT_PARTIAL_SKIPPED,	"partial_skipped")	\
 	EM( COMPACT_COMPLETE,		"complete")		\
 	EM( COMPACT_NO_SUITABLE_PAGE,	"no_suitable_page")	\
 	EM( COMPACT_NOT_SUITABLE_ZONE,	"not_suitable_zone")	\
--- linux-4.4.0.orig/include/trace/events/ext4.h
+++ linux-4.4.0/include/trace/events/ext4.h
@@ -223,6 +223,26 @@
 		  (unsigned long) __entry->ino, __entry->drop)
 );
 
+TRACE_EVENT(ext4_nfs_commit_metadata,
+	TP_PROTO(struct inode *inode),
+
+	TP_ARGS(inode),
+
+	TP_STRUCT__entry(
+		__field(	dev_t,	dev			)
+		__field(	ino_t,	ino			)
+	),
+
+	TP_fast_assign(
+		__entry->dev	= inode->i_sb->s_dev;
+		__entry->ino	= inode->i_ino;
+	),
+
+	TP_printk("dev %d,%d ino %lu",
+		  MAJOR(__entry->dev), MINOR(__entry->dev),
+		  (unsigned long) __entry->ino)
+);
+
 TRACE_EVENT(ext4_mark_inode_dirty,
 	TP_PROTO(struct inode *inode, unsigned long IP),
 
--- linux-4.4.0.orig/include/trace/events/fs.h
+++ linux-4.4.0/include/trace/events/fs.h
@@ -0,0 +1,53 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM fs
+
+#if !defined(_TRACE_FS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_FS_H
+
+#include <linux/fs.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(do_sys_open,
+
+	TP_PROTO(const char *filename, int flags, int mode),
+
+	TP_ARGS(filename, flags, mode),
+
+	TP_STRUCT__entry(
+		__string(	filename, filename		)
+		__field(	int, flags			)
+		__field(	int, mode			)
+	),
+
+	TP_fast_assign(
+		__assign_str(filename, filename);
+		__entry->flags = flags;
+		__entry->mode = mode;
+	),
+
+	TP_printk("\"%s\" %x %o",
+		  __get_str(filename), __entry->flags, __entry->mode)
+);
+
+TRACE_EVENT(open_exec,
+
+	TP_PROTO(const char *filename),
+
+	TP_ARGS(filename),
+
+	TP_STRUCT__entry(
+		__string(	filename, filename		)
+	),
+
+	TP_fast_assign(
+		__assign_str(filename, filename);
+	),
+
+	TP_printk("\"%s\"",
+		  __get_str(filename))
+);
+
+#endif /* _TRACE_FS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--- linux-4.4.0.orig/include/trace/events/kvm.h
+++ linux-4.4.0/include/trace/events/kvm.h
@@ -204,7 +204,7 @@
 	{ KVM_TRACE_MMIO_WRITE, "write" }
 
 TRACE_EVENT(kvm_mmio,
-	TP_PROTO(int type, int len, u64 gpa, u64 val),
+	TP_PROTO(int type, int len, u64 gpa, void *val),
 	TP_ARGS(type, len, gpa, val),
 
 	TP_STRUCT__entry(
@@ -218,7 +218,10 @@
 		__entry->type		= type;
 		__entry->len		= len;
 		__entry->gpa		= gpa;
-		__entry->val		= val;
+		__entry->val		= 0;
+		if (val)
+			memcpy(&__entry->val, val,
+			       min_t(u32, sizeof(__entry->val), len));
 	),
 
 	TP_printk("mmio %s len %u gpa 0x%llx val 0x%llx",
--- linux-4.4.0.orig/include/trace/events/power.h
+++ linux-4.4.0/include/trace/events/power.h
@@ -38,6 +38,28 @@
 	TP_ARGS(state, cpu_id)
 );
 
+TRACE_EVENT(powernv_throttle,
+
+	TP_PROTO(int chip_id, const char *reason, int pmax),
+
+	TP_ARGS(chip_id, reason, pmax),
+
+	TP_STRUCT__entry(
+		__field(int, chip_id)
+		__string(reason, reason)
+		__field(int, pmax)
+	),
+
+	TP_fast_assign(
+		__entry->chip_id = chip_id;
+		__assign_str(reason, reason);
+		__entry->pmax = pmax;
+	),
+
+	TP_printk("Chip %d Pmax %d %s", __entry->chip_id,
+		  __entry->pmax, __get_str(reason))
+);
+
 TRACE_EVENT(pstate_sample,
 
 	TP_PROTO(u32 core_busy,
--- linux-4.4.0.orig/include/trace/events/sunrpc.h
+++ linux-4.4.0/include/trace/events/sunrpc.h
@@ -455,20 +455,22 @@
 	TP_ARGS(rqst, status),
 
 	TP_STRUCT__entry(
-		__field(struct sockaddr *, addr)
 		__field(__be32, xid)
 		__field(int, status)
 		__field(unsigned long, flags)
+		__dynamic_array(unsigned char, addr, rqst->rq_addrlen)
 	),
 
 	TP_fast_assign(
-		__entry->addr = (struct sockaddr *)&rqst->rq_addr;
 		__entry->xid = status > 0 ? rqst->rq_xid : 0;
 		__entry->status = status;
 		__entry->flags = rqst->rq_flags;
+		memcpy(__get_dynamic_array(addr),
+			&rqst->rq_addr, rqst->rq_addrlen);
 	),
 
-	TP_printk("addr=%pIScp xid=0x%x status=%d flags=%s", __entry->addr,
+	TP_printk("addr=%pIScp xid=0x%x status=%d flags=%s",
+			(struct sockaddr *)__get_dynamic_array(addr),
 			be32_to_cpu(__entry->xid), __entry->status,
 			show_rqstp_flags(__entry->flags))
 );
@@ -480,22 +482,23 @@
 	TP_ARGS(rqst, status),
 
 	TP_STRUCT__entry(
-		__field(struct sockaddr *, addr)
 		__field(__be32, xid)
-		__field(int, dropme)
 		__field(int, status)
 		__field(unsigned long, flags)
+		__dynamic_array(unsigned char, addr, rqst->rq_addrlen)
 	),
 
 	TP_fast_assign(
-		__entry->addr = (struct sockaddr *)&rqst->rq_addr;
 		__entry->xid = rqst->rq_xid;
 		__entry->status = status;
 		__entry->flags = rqst->rq_flags;
+		memcpy(__get_dynamic_array(addr),
+			&rqst->rq_addr, rqst->rq_addrlen);
 	),
 
 	TP_printk("addr=%pIScp rq_xid=0x%x status=%d flags=%s",
-		__entry->addr, be32_to_cpu(__entry->xid),
+		(struct sockaddr *)__get_dynamic_array(addr),
+		be32_to_cpu(__entry->xid),
 		__entry->status, show_rqstp_flags(__entry->flags))
 );
 
@@ -529,20 +532,27 @@
 
 	TP_STRUCT__entry(
 		__field(struct svc_xprt *, xprt)
-		__field_struct(struct sockaddr_storage, ss)
 		__field(int, pid)
 		__field(unsigned long, flags)
+		__dynamic_array(unsigned char, addr, xprt != NULL ?
+			xprt->xpt_remotelen : 0)
 	),
 
 	TP_fast_assign(
 		__entry->xprt = xprt;
-		xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
 		__entry->pid = rqst? rqst->rq_task->pid : 0;
-		__entry->flags = xprt ? xprt->xpt_flags : 0;
+		if (xprt) {
+			memcpy(__get_dynamic_array(addr),
+				&xprt->xpt_remote,
+				xprt->xpt_remotelen);
+			__entry->flags = xprt->xpt_flags;
+		} else
+			__entry->flags = 0;
 	),
 
 	TP_printk("xprt=0x%p addr=%pIScp pid=%d flags=%s", __entry->xprt,
-		(struct sockaddr *)&__entry->ss,
+		__get_dynamic_array_len(addr) != 0 ?
+			(struct sockaddr *)__get_dynamic_array(addr) : NULL,
 		__entry->pid, show_svc_xprt_flags(__entry->flags))
 );
 
@@ -553,18 +563,25 @@
 
 	TP_STRUCT__entry(
 		__field(struct svc_xprt *, xprt)
-		__field_struct(struct sockaddr_storage, ss)
 		__field(unsigned long, flags)
+		__dynamic_array(unsigned char, addr, xprt != NULL ?
+			xprt->xpt_remotelen : 0)
 	),
 
 	TP_fast_assign(
-		__entry->xprt = xprt,
-		xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
-		__entry->flags = xprt ? xprt->xpt_flags : 0;
+		__entry->xprt = xprt;
+		if (xprt) {
+			memcpy(__get_dynamic_array(addr),
+					&xprt->xpt_remote,
+					xprt->xpt_remotelen);
+			__entry->flags = xprt->xpt_flags;
+		} else
+			__entry->flags = 0;
 	),
 
 	TP_printk("xprt=0x%p addr=%pIScp flags=%s", __entry->xprt,
-		(struct sockaddr *)&__entry->ss,
+		__get_dynamic_array_len(addr) != 0 ?
+			(struct sockaddr *)__get_dynamic_array(addr) : NULL,
 		show_svc_xprt_flags(__entry->flags))
 );
 
@@ -592,19 +609,26 @@
 	TP_STRUCT__entry(
 		__field(struct svc_xprt *, xprt)
 		__field(int, len)
-		__field_struct(struct sockaddr_storage, ss)
 		__field(unsigned long, flags)
+		__dynamic_array(unsigned char, addr, xprt != NULL ?
+			xprt->xpt_remotelen : 0)
 	),
 
 	TP_fast_assign(
 		__entry->xprt = xprt;
-		xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
 		__entry->len = len;
-		__entry->flags = xprt ? xprt->xpt_flags : 0;
+		if (xprt) {
+			memcpy(__get_dynamic_array(addr),
+					&xprt->xpt_remote,
+					xprt->xpt_remotelen);
+			__entry->flags = xprt->xpt_flags;
+		} else
+			__entry->flags = 0;
 	),
 
 	TP_printk("xprt=0x%p addr=%pIScp len=%d flags=%s", __entry->xprt,
-		(struct sockaddr *)&__entry->ss,
+		__get_dynamic_array_len(addr) != 0 ?
+			(struct sockaddr *)__get_dynamic_array(addr) : NULL,
 		__entry->len, show_svc_xprt_flags(__entry->flags))
 );
 #endif /* _TRACE_SUNRPC_H */
--- linux-4.4.0.orig/include/trace/events/syscalls.h
+++ linux-4.4.0/include/trace/events/syscalls.h
@@ -1,5 +1,6 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM raw_syscalls
+#undef TRACE_INCLUDE_FILE
 #define TRACE_INCLUDE_FILE syscalls
 
 #if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ)
--- linux-4.4.0.orig/include/trace/events/target.h
+++ linux-4.4.0/include/trace/events/target.h
@@ -139,6 +139,7 @@
 		__field( unsigned int,	opcode		)
 		__field( unsigned int,	data_length	)
 		__field( unsigned int,	task_attribute  )
+		__field( unsigned char,	control		)
 		__array( unsigned char,	cdb, TCM_MAX_COMMAND_SIZE	)
 		__string( initiator,	cmd->se_sess->se_node_acl->initiatorname	)
 	),
@@ -148,6 +149,7 @@
 		__entry->opcode		= cmd->t_task_cdb[0];
 		__entry->data_length	= cmd->data_length;
 		__entry->task_attribute	= cmd->sam_task_attr;
+		__entry->control	= scsi_command_control(cmd->t_task_cdb);
 		memcpy(__entry->cdb, cmd->t_task_cdb, TCM_MAX_COMMAND_SIZE);
 		__assign_str(initiator, cmd->se_sess->se_node_acl->initiatorname);
 	),
@@ -157,9 +159,7 @@
 		  show_opcode_name(__entry->opcode),
 		  __entry->data_length, __print_hex(__entry->cdb, 16),
 		  show_task_attribute_name(__entry->task_attribute),
-		  scsi_command_size(__entry->cdb) <= 16 ?
-			__entry->cdb[scsi_command_size(__entry->cdb) - 1] :
-			__entry->cdb[1]
+		  __entry->control
 	)
 );
 
@@ -174,6 +174,7 @@
 		__field( unsigned int,	opcode		)
 		__field( unsigned int,	data_length	)
 		__field( unsigned int,	task_attribute  )
+		__field( unsigned char,	control		)
 		__field( unsigned char,	scsi_status	)
 		__field( unsigned char,	sense_length	)
 		__array( unsigned char,	cdb, TCM_MAX_COMMAND_SIZE	)
@@ -186,6 +187,7 @@
 		__entry->opcode		= cmd->t_task_cdb[0];
 		__entry->data_length	= cmd->data_length;
 		__entry->task_attribute	= cmd->sam_task_attr;
+		__entry->control	= scsi_command_control(cmd->t_task_cdb);
 		__entry->scsi_status	= cmd->scsi_status;
 		__entry->sense_length	= cmd->scsi_status == SAM_STAT_CHECK_CONDITION ?
 			min(18, ((u8 *) cmd->sense_buffer)[SPC_ADD_SENSE_LEN_OFFSET] + 8) : 0;
@@ -202,9 +204,7 @@
 		  show_opcode_name(__entry->opcode),
 		  __entry->data_length, __print_hex(__entry->cdb, 16),
 		  show_task_attribute_name(__entry->task_attribute),
-		  scsi_command_size(__entry->cdb) <= 16 ?
-			__entry->cdb[scsi_command_size(__entry->cdb) - 1] :
-			__entry->cdb[1]
+		  __entry->control
 	)
 );
 
--- linux-4.4.0.orig/include/trace/events/timer.h
+++ linux-4.4.0/include/trace/events/timer.h
@@ -125,6 +125,20 @@
 	TP_ARGS(timer)
 );
 
+#define decode_clockid(type)						\
+	__print_symbolic(type,						\
+		{ CLOCK_REALTIME,	"CLOCK_REALTIME"	},	\
+		{ CLOCK_MONOTONIC,	"CLOCK_MONOTONIC"	},	\
+		{ CLOCK_BOOTTIME,	"CLOCK_BOOTTIME"	},	\
+		{ CLOCK_TAI,		"CLOCK_TAI"		})
+
+#define decode_hrtimer_mode(mode)					\
+	__print_symbolic(mode,						\
+		{ HRTIMER_MODE_ABS,		"ABS"		},	\
+		{ HRTIMER_MODE_REL,		"REL"		},	\
+		{ HRTIMER_MODE_ABS_PINNED,	"ABS|PINNED"	},	\
+		{ HRTIMER_MODE_REL_PINNED,	"REL|PINNED"	})
+
 /**
  * hrtimer_init - called when the hrtimer is initialized
  * @hrtimer:	pointer to struct hrtimer
@@ -151,10 +165,8 @@
 	),
 
 	TP_printk("hrtimer=%p clockid=%s mode=%s", __entry->hrtimer,
-		  __entry->clockid == CLOCK_REALTIME ?
-			"CLOCK_REALTIME" : "CLOCK_MONOTONIC",
-		  __entry->mode == HRTIMER_MODE_ABS ?
-			"HRTIMER_MODE_ABS" : "HRTIMER_MODE_REL")
+		  decode_clockid(__entry->clockid),
+		  decode_hrtimer_mode(__entry->mode))
 );
 
 /**
--- linux-4.4.0.orig/include/trace/events/writeback.h
+++ linux-4.4.0/include/trace/events/writeback.h
@@ -65,8 +65,9 @@
 	),
 
 	TP_fast_assign(
-		strncpy(__entry->name,
-			mapping ? dev_name(inode_to_bdi(mapping->host)->dev) : "(unknown)", 32);
+		strscpy_pad(__entry->name,
+			    bdi_dev_name(mapping ? inode_to_bdi(mapping->host) :
+					 NULL), 32);
 		__entry->ino = mapping ? mapping->host->i_ino : 0;
 		__entry->index = page->index;
 	),
@@ -95,8 +96,7 @@
 		struct backing_dev_info *bdi = inode_to_bdi(inode);
 
 		/* may be called for files on pseudo FSes w/ unregistered bdi */
-		strncpy(__entry->name,
-			bdi->dev ? dev_name(bdi->dev) : "(unknown)", 32);
+		strscpy_pad(__entry->name, bdi_dev_name(bdi), 32);
 		__entry->ino		= inode->i_ino;
 		__entry->state		= inode->i_state;
 		__entry->flags		= flags;
@@ -205,8 +205,8 @@
 	),
 
 	TP_fast_assign(
-		strncpy(__entry->name,
-			dev_name(inode_to_bdi(inode)->dev), 32);
+		strscpy_pad(__entry->name,
+			    bdi_dev_name(inode_to_bdi(inode)), 32);
 		__entry->ino		= inode->i_ino;
 		__entry->sync_mode	= wbc->sync_mode;
 		__trace_wbc_assign_cgroup(__get_str(cgroup), wbc);
@@ -249,8 +249,7 @@
 		__dynamic_array(char, cgroup, __trace_wb_cgroup_size(wb))
 	),
 	TP_fast_assign(
-		strncpy(__entry->name,
-			wb->bdi->dev ? dev_name(wb->bdi->dev) : "(unknown)", 32);
+		strscpy_pad(__entry->name, bdi_dev_name(wb->bdi), 32);
 		__entry->nr_pages = work->nr_pages;
 		__entry->sb_dev = work->sb ? work->sb->s_dev : 0;
 		__entry->sync_mode = work->sync_mode;
@@ -303,7 +302,7 @@
 		__dynamic_array(char, cgroup, __trace_wb_cgroup_size(wb))
 	),
 	TP_fast_assign(
-		strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
+		strscpy_pad(__entry->name, bdi_dev_name(wb->bdi), 32);
 		__trace_wb_assign_cgroup(__get_str(cgroup), wb);
 	),
 	TP_printk("bdi %s: cgroup=%s",
@@ -326,7 +325,7 @@
 		__array(char, name, 32)
 	),
 	TP_fast_assign(
-		strncpy(__entry->name, dev_name(bdi->dev), 32);
+		strscpy_pad(__entry->name, bdi_dev_name(bdi), 32);
 	),
 	TP_printk("bdi %s",
 		__entry->name
@@ -351,7 +350,7 @@
 	),
 
 	TP_fast_assign(
-		strncpy(__entry->name, dev_name(bdi->dev), 32);
+		strscpy_pad(__entry->name, bdi_dev_name(bdi), 32);
 		__entry->nr_to_write	= wbc->nr_to_write;
 		__entry->pages_skipped	= wbc->pages_skipped;
 		__entry->sync_mode	= wbc->sync_mode;
@@ -390,8 +389,9 @@
 TRACE_EVENT(writeback_queue_io,
 	TP_PROTO(struct bdi_writeback *wb,
 		 struct wb_writeback_work *work,
+		 unsigned long dirtied_before,
 		 int moved),
-	TP_ARGS(wb, work, moved),
+	TP_ARGS(wb, work, dirtied_before, moved),
 	TP_STRUCT__entry(
 		__array(char,		name, 32)
 		__field(unsigned long,	older)
@@ -401,19 +401,17 @@
 		__dynamic_array(char, cgroup, __trace_wb_cgroup_size(wb))
 	),
 	TP_fast_assign(
-		unsigned long *older_than_this = work->older_than_this;
-		strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
-		__entry->older	= older_than_this ?  *older_than_this : 0;
-		__entry->age	= older_than_this ?
-				  (jiffies - *older_than_this) * 1000 / HZ : -1;
+		strscpy_pad(__entry->name, bdi_dev_name(wb->bdi), 32);
+		__entry->older	= dirtied_before;
+		__entry->age	= (jiffies - dirtied_before) * 1000 / HZ;
 		__entry->moved	= moved;
 		__entry->reason	= work->reason;
 		__trace_wb_assign_cgroup(__get_str(cgroup), wb);
 	),
 	TP_printk("bdi %s: older=%lu age=%ld enqueue=%d reason=%s cgroup=%s",
 		__entry->name,
-		__entry->older,	/* older_than_this in jiffies */
-		__entry->age,	/* older_than_this in relative milliseconds */
+		__entry->older,	/* dirtied_before in jiffies */
+		__entry->age,	/* dirtied_before in relative milliseconds */
 		__entry->moved,
 		__print_symbolic(__entry->reason, WB_WORK_REASON),
 		__get_str(cgroup)
@@ -488,7 +486,7 @@
 	),
 
 	TP_fast_assign(
-		strlcpy(__entry->bdi, dev_name(wb->bdi->dev), 32);
+		strscpy_pad(__entry->bdi, bdi_dev_name(wb->bdi), 32);
 		__entry->write_bw	= KBps(wb->write_bandwidth);
 		__entry->avg_write_bw	= KBps(wb->avg_write_bandwidth);
 		__entry->dirty_rate	= KBps(dirty_rate);
@@ -553,7 +551,7 @@
 
 	TP_fast_assign(
 		unsigned long freerun = (thresh + bg_thresh) / 2;
-		strlcpy(__entry->bdi, dev_name(wb->bdi->dev), 32);
+		strscpy_pad(__entry->bdi, bdi_dev_name(wb->bdi), 32);
 
 		__entry->limit		= global_wb_domain.dirty_limit;
 		__entry->setpoint	= (global_wb_domain.dirty_limit +
@@ -614,8 +612,8 @@
 	),
 
 	TP_fast_assign(
-		strncpy(__entry->name,
-		        dev_name(inode_to_bdi(inode)->dev), 32);
+		strscpy_pad(__entry->name,
+			    bdi_dev_name(inode_to_bdi(inode)), 32);
 		__entry->ino		= inode->i_ino;
 		__entry->state		= inode->i_state;
 		__entry->dirtied_when	= inode->dirtied_when;
@@ -688,8 +686,8 @@
 	),
 
 	TP_fast_assign(
-		strncpy(__entry->name,
-			dev_name(inode_to_bdi(inode)->dev), 32);
+		strscpy_pad(__entry->name,
+			    bdi_dev_name(inode_to_bdi(inode)), 32);
 		__entry->ino		= inode->i_ino;
 		__entry->state		= inode->i_state;
 		__entry->dirtied_when	= inode->dirtied_when;
--- linux-4.4.0.orig/include/trace/events/xen.h
+++ linux-4.4.0/include/trace/events/xen.h
@@ -63,7 +63,11 @@
 	    TP_PROTO(xen_mc_callback_fn_t fn, void *data),
 	    TP_ARGS(fn, data),
 	    TP_STRUCT__entry(
-		    __field(xen_mc_callback_fn_t, fn)
+		    /*
+		     * Use field_struct to avoid is_signed_type()
+		     * comparison of a function pointer.
+		     */
+		    __field_struct(xen_mc_callback_fn_t, fn)
 		    __field(void *, data)
 		    ),
 	    TP_fast_assign(
@@ -377,22 +381,6 @@
 DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_pin);
 DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_unpin);
 
-TRACE_EVENT(xen_mmu_flush_tlb_all,
-	    TP_PROTO(int x),
-	    TP_ARGS(x),
-	    TP_STRUCT__entry(__array(char, x, 0)),
-	    TP_fast_assign((void)x),
-	    TP_printk("%s", "")
-	);
-
-TRACE_EVENT(xen_mmu_flush_tlb,
-	    TP_PROTO(int x),
-	    TP_ARGS(x),
-	    TP_STRUCT__entry(__array(char, x, 0)),
-	    TP_fast_assign((void)x),
-	    TP_printk("%s", "")
-	);
-
 TRACE_EVENT(xen_mmu_flush_tlb_single,
 	    TP_PROTO(unsigned long addr),
 	    TP_ARGS(addr),
--- linux-4.4.0.orig/include/uapi/drm/drm_fourcc.h
+++ linux-4.4.0/include/uapi/drm/drm_fourcc.h
@@ -150,6 +150,7 @@
 
 /* Vendor Ids: */
 #define DRM_FORMAT_MOD_NONE           0
+#define DRM_FORMAT_MOD_VENDOR_NONE    0
 #define DRM_FORMAT_MOD_VENDOR_INTEL   0x01
 #define DRM_FORMAT_MOD_VENDOR_AMD     0x02
 #define DRM_FORMAT_MOD_VENDOR_NV      0x03
--- linux-4.4.0.orig/include/uapi/drm/drm_mode.h
+++ linux-4.4.0/include/uapi/drm/drm_mode.h
@@ -487,6 +487,21 @@
 	__u64 blue;
 };
 
+struct drm_color_ctm {
+	/* Conversion matrix in S31.32 format. */
+	__s64 matrix[9];
+};
+
+struct drm_color_lut {
+	/*
+	 * Data is U0.16 fixed point format.
+	 */
+	__u16 red;
+	__u16 green;
+	__u16 blue;
+	__u16 reserved;
+};
+
 #define DRM_MODE_PAGE_FLIP_EVENT 0x01
 #define DRM_MODE_PAGE_FLIP_ASYNC 0x02
 #define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT|DRM_MODE_PAGE_FLIP_ASYNC)
--- linux-4.4.0.orig/include/uapi/drm/i915_drm.h
+++ linux-4.4.0/include/uapi/drm/i915_drm.h
@@ -356,6 +356,7 @@
 #define I915_PARAM_EU_TOTAL		 34
 #define I915_PARAM_HAS_GPU_RESET	 35
 #define I915_PARAM_HAS_RESOURCE_STREAMER 36
+#define I915_PARAM_HAS_EXEC_SOFTPIN     37
 
 typedef struct drm_i915_getparam {
 	__s32 param;
@@ -682,8 +683,12 @@
 	__u64 alignment;
 
 	/**
-	 * Returned value of the updated offset of the object, for future
-	 * presumed_offset writes.
+	 * When the EXEC_OBJECT_PINNED flag is specified this is populated by
+	 * the user with the GTT offset at which this object will be pinned.
+	 * When the I915_EXEC_NO_RELOC flag is specified this must contain the
+	 * presumed_offset of the object.
+	 * During execbuffer2 the kernel populates it with the value of the
+	 * current GTT offset of the object, for future presumed_offset writes.
 	 */
 	__u64 offset;
 
@@ -691,7 +696,8 @@
 #define EXEC_OBJECT_NEEDS_GTT	(1<<1)
 #define EXEC_OBJECT_WRITE	(1<<2)
 #define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
-#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_SUPPORTS_48B_ADDRESS<<1)
+#define EXEC_OBJECT_PINNED     (1<<4)
+#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_PINNED<<1)
 	__u64 flags;
 
 	__u64 rsvd1;
@@ -766,10 +772,12 @@
 #define I915_EXEC_HANDLE_LUT		(1<<12)
 
 /** Used for switching BSD rings on the platforms with two BSD rings */
-#define I915_EXEC_BSD_MASK		(3<<13)
-#define I915_EXEC_BSD_DEFAULT		(0<<13) /* default ping-pong mode */
-#define I915_EXEC_BSD_RING1		(1<<13)
-#define I915_EXEC_BSD_RING2		(2<<13)
+#define I915_EXEC_BSD_SHIFT     (13)
+#define I915_EXEC_BSD_MASK	(3 << I915_EXEC_BSD_SHIFT)
+/* default ping-pong mode */
+#define I915_EXEC_BSD_DEFAULT	(0 << I915_EXEC_BSD_SHIFT)
+#define I915_EXEC_BSD_RING1	(1 << I915_EXEC_BSD_SHIFT)
+#define I915_EXEC_BSD_RING2	(2 << I915_EXEC_BSD_SHIFT)
 
 /** Tell the kernel that the batchbuffer is processed by
  *  the resource streamer.
@@ -1125,8 +1133,9 @@
 	__u32 ctx_id;
 	__u32 size;
 	__u64 param;
-#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1
-#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2
+#define I915_CONTEXT_PARAM_BAN_PERIOD	0x1
+#define I915_CONTEXT_PARAM_NO_ZEROMAP	0x2
+#define I915_CONTEXT_PARAM_GTT_SIZE	0x3
 	__u64 value;
 };
 
--- linux-4.4.0.orig/include/uapi/drm/virtgpu_drm.h
+++ linux-4.4.0/include/uapi/drm/virtgpu_drm.h
@@ -60,6 +60,7 @@
 };
 
 #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */
+#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */
 
 struct drm_virtgpu_getparam {
 	uint64_t param;
--- linux-4.4.0.orig/include/uapi/linux/Kbuild
+++ linux-4.4.0/include/uapi/linux/Kbuild
@@ -59,6 +59,7 @@
 header-y += atm_tcp.h
 header-y += atm_zatm.h
 header-y += audit.h
+header-y += aufs_type.h
 header-y += auto_fs4.h
 header-y += auto_fs.h
 header-y += auxvec.h
@@ -307,7 +308,7 @@
 header-y += nl80211.h
 header-y += n_r3964.h
 header-y += nubus.h
-header-y += nvme.h
+header-y += nvme_ioctl.h
 header-y += nvram.h
 header-y += omap3isp.h
 header-y += omapfb.h
--- linux-4.4.0.orig/include/uapi/linux/audit.h
+++ linux-4.4.0/include/uapi/linux/audit.h
@@ -110,6 +110,7 @@
 #define AUDIT_SECCOMP		1326	/* Secure Computing event */
 #define AUDIT_PROCTITLE		1327	/* Proctitle emit event */
 #define AUDIT_FEATURE_CHANGE	1328	/* audit log listing feature changes */
+#define AUDIT_REPLACE		1329	/* Replace auditd if this packet unanswerd */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
--- linux-4.4.0.orig/include/uapi/linux/aufs_type.h
+++ linux-4.4.0/include/uapi/linux/aufs_type.h
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2005-2015 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __AUFS_TYPE_H__
+#define __AUFS_TYPE_H__
+
+#define AUFS_NAME	"aufs"
+
+#ifdef __KERNEL__
+/*
+ * define it before including all other headers.
+ * sched.h may use pr_* macros before defining "current", so define the
+ * no-current version first, and re-define later.
+ */
+#define pr_fmt(fmt)	AUFS_NAME " %s:%d: " fmt, __func__, __LINE__
+#include <linux/sched.h>
+#undef pr_fmt
+#define pr_fmt(fmt) \
+		AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \
+		(int)sizeof(current->comm), current->comm, current->pid
+#else
+#include <stdint.h>
+#include <sys/types.h>
+#endif /* __KERNEL__ */
+
+#include <linux/limits.h>
+
+#define AUFS_VERSION	"4.x-rcN-20160111"
+
+/* todo? move this to linux-2.6.19/include/magic.h */
+#define AUFS_SUPER_MAGIC	('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef CONFIG_AUFS_BRANCH_MAX_127
+typedef int8_t aufs_bindex_t;
+#define AUFS_BRANCH_MAX 127
+#else
+typedef int16_t aufs_bindex_t;
+#ifdef CONFIG_AUFS_BRANCH_MAX_511
+#define AUFS_BRANCH_MAX 511
+#elif defined(CONFIG_AUFS_BRANCH_MAX_1023)
+#define AUFS_BRANCH_MAX 1023
+#elif defined(CONFIG_AUFS_BRANCH_MAX_32767)
+#define AUFS_BRANCH_MAX 32767
+#endif
+#endif
+
+#ifdef __KERNEL__
+#ifndef AUFS_BRANCH_MAX
+#error unknown CONFIG_AUFS_BRANCH_MAX value
+#endif
+#endif /* __KERNEL__ */
+
+/* ---------------------------------------------------------------------- */
+
+#define AUFS_FSTYPE		AUFS_NAME
+
+#define AUFS_ROOT_INO		2
+#define AUFS_FIRST_INO		11
+
+#define AUFS_WH_PFX		".wh."
+#define AUFS_WH_PFX_LEN		((int)sizeof(AUFS_WH_PFX) - 1)
+#define AUFS_WH_TMP_LEN		4
+/* a limit for rmdir/rename a dir and copyup */
+#define AUFS_MAX_NAMELEN	(NAME_MAX \
+				- AUFS_WH_PFX_LEN * 2	/* doubly whiteouted */\
+				- 1			/* dot */\
+				- AUFS_WH_TMP_LEN)	/* hex */
+#define AUFS_XINO_FNAME		"." AUFS_NAME ".xino"
+#define AUFS_XINO_DEFPATH	"/tmp/" AUFS_XINO_FNAME
+#define AUFS_XINO_DEF_SEC	30 /* seconds */
+#define AUFS_XINO_DEF_TRUNC	45 /* percentage */
+#define AUFS_DIRWH_DEF		3
+#define AUFS_RDCACHE_DEF	10 /* seconds */
+#define AUFS_RDCACHE_MAX	3600 /* seconds */
+#define AUFS_RDBLK_DEF		512 /* bytes */
+#define AUFS_RDHASH_DEF		32
+#define AUFS_WKQ_NAME		AUFS_NAME "d"
+#define AUFS_MFS_DEF_SEC	30 /* seconds */
+#define AUFS_MFS_MAX_SEC	3600 /* seconds */
+#define AUFS_FHSM_CACHE_DEF_SEC	30 /* seconds */
+#define AUFS_PLINK_WARN		50 /* number of plinks in a single bucket */
+
+/* pseudo-link maintenace under /proc */
+#define AUFS_PLINK_MAINT_NAME	"plink_maint"
+#define AUFS_PLINK_MAINT_DIR	"fs/" AUFS_NAME
+#define AUFS_PLINK_MAINT_PATH	AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME
+
+#define AUFS_DIROPQ_NAME	AUFS_WH_PFX ".opq" /* whiteouted doubly */
+#define AUFS_WH_DIROPQ		AUFS_WH_PFX AUFS_DIROPQ_NAME
+
+#define AUFS_BASE_NAME		AUFS_WH_PFX AUFS_NAME
+#define AUFS_PLINKDIR_NAME	AUFS_WH_PFX "plnk"
+#define AUFS_ORPHDIR_NAME	AUFS_WH_PFX "orph"
+
+/* doubly whiteouted */
+#define AUFS_WH_BASE		AUFS_WH_PFX AUFS_BASE_NAME
+#define AUFS_WH_PLINKDIR	AUFS_WH_PFX AUFS_PLINKDIR_NAME
+#define AUFS_WH_ORPHDIR		AUFS_WH_PFX AUFS_ORPHDIR_NAME
+
+/* branch permissions and attributes */
+#define AUFS_BRPERM_RW		"rw"
+#define AUFS_BRPERM_RO		"ro"
+#define AUFS_BRPERM_RR		"rr"
+#define AUFS_BRATTR_COO_REG	"coo_reg"
+#define AUFS_BRATTR_COO_ALL	"coo_all"
+#define AUFS_BRATTR_FHSM	"fhsm"
+#define AUFS_BRATTR_UNPIN	"unpin"
+#define AUFS_BRATTR_ICEX	"icex"
+#define AUFS_BRATTR_ICEX_SEC	"icexsec"
+#define AUFS_BRATTR_ICEX_SYS	"icexsys"
+#define AUFS_BRATTR_ICEX_TR	"icextr"
+#define AUFS_BRATTR_ICEX_USR	"icexusr"
+#define AUFS_BRATTR_ICEX_OTH	"icexoth"
+#define AUFS_BRRATTR_WH		"wh"
+#define AUFS_BRWATTR_NLWH	"nolwh"
+#define AUFS_BRWATTR_MOO	"moo"
+
+#define AuBrPerm_RW		1		/* writable, hardlinkable wh */
+#define AuBrPerm_RO		(1 << 1)	/* readonly */
+#define AuBrPerm_RR		(1 << 2)	/* natively readonly */
+#define AuBrPerm_Mask		(AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR)
+
+#define AuBrAttr_COO_REG	(1 << 3)	/* copy-up on open */
+#define AuBrAttr_COO_ALL	(1 << 4)
+#define AuBrAttr_COO_Mask	(AuBrAttr_COO_REG | AuBrAttr_COO_ALL)
+
+#define AuBrAttr_FHSM		(1 << 5)	/* file-based hsm */
+#define AuBrAttr_UNPIN		(1 << 6)	/* rename-able top dir of
+						   branch. meaningless since
+						   linux-3.18-rc1 */
+
+/* ignore error in copying XATTR */
+#define AuBrAttr_ICEX_SEC	(1 << 7)
+#define AuBrAttr_ICEX_SYS	(1 << 8)
+#define AuBrAttr_ICEX_TR	(1 << 9)
+#define AuBrAttr_ICEX_USR	(1 << 10)
+#define AuBrAttr_ICEX_OTH	(1 << 11)
+#define AuBrAttr_ICEX		(AuBrAttr_ICEX_SEC	\
+				 | AuBrAttr_ICEX_SYS	\
+				 | AuBrAttr_ICEX_TR	\
+				 | AuBrAttr_ICEX_USR	\
+				 | AuBrAttr_ICEX_OTH)
+
+#define AuBrRAttr_WH		(1 << 12)	/* whiteout-able */
+#define AuBrRAttr_Mask		AuBrRAttr_WH
+
+#define AuBrWAttr_NoLinkWH	(1 << 13)	/* un-hardlinkable whiteouts */
+#define AuBrWAttr_MOO		(1 << 14)	/* move-up on open */
+#define AuBrWAttr_Mask		(AuBrWAttr_NoLinkWH | AuBrWAttr_MOO)
+
+#define AuBrAttr_CMOO_Mask	(AuBrAttr_COO_Mask | AuBrWAttr_MOO)
+
+/* #warning test userspace */
+#ifdef __KERNEL__
+#ifndef CONFIG_AUFS_FHSM
+#undef AuBrAttr_FHSM
+#define AuBrAttr_FHSM		0
+#endif
+#ifndef CONFIG_AUFS_XATTR
+#undef	AuBrAttr_ICEX
+#define AuBrAttr_ICEX		0
+#undef	AuBrAttr_ICEX_SEC
+#define AuBrAttr_ICEX_SEC	0
+#undef	AuBrAttr_ICEX_SYS
+#define AuBrAttr_ICEX_SYS	0
+#undef	AuBrAttr_ICEX_TR
+#define AuBrAttr_ICEX_TR	0
+#undef	AuBrAttr_ICEX_USR
+#define AuBrAttr_ICEX_USR	0
+#undef	AuBrAttr_ICEX_OTH
+#define AuBrAttr_ICEX_OTH	0
+#endif
+#endif
+
+/* the longest combination */
+/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */
+#define AuBrPermStrSz	sizeof(AUFS_BRPERM_RW			\
+			       "+" AUFS_BRATTR_COO_REG		\
+			       "+" AUFS_BRATTR_FHSM		\
+			       "+" AUFS_BRATTR_UNPIN		\
+			       "+" AUFS_BRATTR_ICEX_SEC		\
+			       "+" AUFS_BRATTR_ICEX_SYS		\
+			       "+" AUFS_BRATTR_ICEX_USR		\
+			       "+" AUFS_BRATTR_ICEX_OTH		\
+			       "+" AUFS_BRWATTR_NLWH)
+
+typedef struct {
+	char a[AuBrPermStrSz];
+} au_br_perm_str_t;
+
+static inline int au_br_writable(int brperm)
+{
+	return brperm & AuBrPerm_RW;
+}
+
+static inline int au_br_whable(int brperm)
+{
+	return brperm & (AuBrPerm_RW | AuBrRAttr_WH);
+}
+
+static inline int au_br_wh_linkable(int brperm)
+{
+	return !(brperm & AuBrWAttr_NoLinkWH);
+}
+
+static inline int au_br_cmoo(int brperm)
+{
+	return brperm & AuBrAttr_CMOO_Mask;
+}
+
+static inline int au_br_fhsm(int brperm)
+{
+	return brperm & AuBrAttr_FHSM;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* ioctl */
+enum {
+	/* readdir in userspace */
+	AuCtl_RDU,
+	AuCtl_RDU_INO,
+
+	AuCtl_WBR_FD,	/* pathconf wrapper */
+	AuCtl_IBUSY,	/* busy inode */
+	AuCtl_MVDOWN,	/* move-down */
+	AuCtl_BR,	/* info about branches */
+	AuCtl_FHSM_FD	/* connection for fhsm */
+};
+
+/* borrowed from linux/include/linux/kernel.h */
+#ifndef ALIGN
+#define ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a)-1)
+#define __ALIGN_MASK(x, mask)	(((x)+(mask))&~(mask))
+#endif
+
+/* borrowed from linux/include/linux/compiler-gcc3.h */
+#ifndef __aligned
+#define __aligned(x)			__attribute__((aligned(x)))
+#endif
+
+#ifdef __KERNEL__
+#ifndef __packed
+#define __packed			__attribute__((packed))
+#endif
+#endif
+
+struct au_rdu_cookie {
+	uint64_t	h_pos;
+	int16_t		bindex;
+	uint8_t		flags;
+	uint8_t		pad;
+	uint32_t	generation;
+} __aligned(8);
+
+struct au_rdu_ent {
+	uint64_t	ino;
+	int16_t		bindex;
+	uint8_t		type;
+	uint8_t		nlen;
+	uint8_t		wh;
+	char		name[0];
+} __aligned(8);
+
+static inline int au_rdu_len(int nlen)
+{
+	/* include the terminating NULL */
+	return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1,
+		     sizeof(uint64_t));
+}
+
+union au_rdu_ent_ul {
+	struct au_rdu_ent __user	*e;
+	uint64_t			ul;
+};
+
+enum {
+	AufsCtlRduV_SZ,
+	AufsCtlRduV_End
+};
+
+struct aufs_rdu {
+	/* input */
+	union {
+		uint64_t	sz;	/* AuCtl_RDU */
+		uint64_t	nent;	/* AuCtl_RDU_INO */
+	};
+	union au_rdu_ent_ul	ent;
+	uint16_t		verify[AufsCtlRduV_End];
+
+	/* input/output */
+	uint32_t		blk;
+
+	/* output */
+	union au_rdu_ent_ul	tail;
+	/* number of entries which were added in a single call */
+	uint64_t		rent;
+	uint8_t			full;
+	uint8_t			shwh;
+
+	struct au_rdu_cookie	cookie;
+} __aligned(8);
+
+/* ---------------------------------------------------------------------- */
+
+struct aufs_wbr_fd {
+	uint32_t	oflags;
+	int16_t		brid;
+} __aligned(8);
+
+/* ---------------------------------------------------------------------- */
+
+struct aufs_ibusy {
+	uint64_t	ino, h_ino;
+	int16_t		bindex;
+} __aligned(8);
+
+/* ---------------------------------------------------------------------- */
+
+/* error code for move-down */
+/* the actual message strings are implemented in aufs-util.git */
+enum {
+	EAU_MVDOWN_OPAQUE = 1,
+	EAU_MVDOWN_WHITEOUT,
+	EAU_MVDOWN_UPPER,
+	EAU_MVDOWN_BOTTOM,
+	EAU_MVDOWN_NOUPPER,
+	EAU_MVDOWN_NOLOWERBR,
+	EAU_Last
+};
+
+/* flags for move-down */
+#define AUFS_MVDOWN_DMSG	1
+#define AUFS_MVDOWN_OWLOWER	(1 << 1)	/* overwrite lower */
+#define AUFS_MVDOWN_KUPPER	(1 << 2)	/* keep upper */
+#define AUFS_MVDOWN_ROLOWER	(1 << 3)	/* do even if lower is RO */
+#define AUFS_MVDOWN_ROLOWER_R	(1 << 4)	/* did on lower RO */
+#define AUFS_MVDOWN_ROUPPER	(1 << 5)	/* do even if upper is RO */
+#define AUFS_MVDOWN_ROUPPER_R	(1 << 6)	/* did on upper RO */
+#define AUFS_MVDOWN_BRID_UPPER	(1 << 7)	/* upper brid */
+#define AUFS_MVDOWN_BRID_LOWER	(1 << 8)	/* lower brid */
+#define AUFS_MVDOWN_FHSM_LOWER	(1 << 9)	/* find fhsm attr for lower */
+#define AUFS_MVDOWN_STFS	(1 << 10)	/* req. stfs */
+#define AUFS_MVDOWN_STFS_FAILED	(1 << 11)	/* output: stfs is unusable */
+#define AUFS_MVDOWN_BOTTOM	(1 << 12)	/* output: no more lowers */
+
+/* index for move-down */
+enum {
+	AUFS_MVDOWN_UPPER,
+	AUFS_MVDOWN_LOWER,
+	AUFS_MVDOWN_NARRAY
+};
+
+/*
+ * additional info of move-down
+ * number of free blocks and inodes.
+ * subset of struct kstatfs, but smaller and always 64bit.
+ */
+struct aufs_stfs {
+	uint64_t	f_blocks;
+	uint64_t	f_bavail;
+	uint64_t	f_files;
+	uint64_t	f_ffree;
+};
+
+struct aufs_stbr {
+	int16_t			brid;	/* optional input */
+	int16_t			bindex;	/* output */
+	struct aufs_stfs	stfs;	/* output when AUFS_MVDOWN_STFS set */
+} __aligned(8);
+
+struct aufs_mvdown {
+	uint32_t		flags;			/* input/output */
+	struct aufs_stbr	stbr[AUFS_MVDOWN_NARRAY]; /* input/output */
+	int8_t			au_errno;		/* output */
+} __aligned(8);
+
+/* ---------------------------------------------------------------------- */
+
+union aufs_brinfo {
+	/* PATH_MAX may differ between kernel-space and user-space */
+	char	_spacer[4096];
+	struct {
+		int16_t	id;
+		int	perm;
+		char	path[0];
+	};
+} __aligned(8);
+
+/* ---------------------------------------------------------------------- */
+
+#define AuCtlType		'A'
+#define AUFS_CTL_RDU		_IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu)
+#define AUFS_CTL_RDU_INO	_IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
+#define AUFS_CTL_WBR_FD		_IOW(AuCtlType, AuCtl_WBR_FD, \
+				     struct aufs_wbr_fd)
+#define AUFS_CTL_IBUSY		_IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy)
+#define AUFS_CTL_MVDOWN		_IOWR(AuCtlType, AuCtl_MVDOWN, \
+				      struct aufs_mvdown)
+#define AUFS_CTL_BRINFO		_IOW(AuCtlType, AuCtl_BR, union aufs_brinfo)
+#define AUFS_CTL_FHSM_FD	_IOW(AuCtlType, AuCtl_FHSM_FD, int)
+
+#endif /* __AUFS_TYPE_H__ */
--- linux-4.4.0.orig/include/uapi/linux/bcache.h
+++ linux-4.4.0/include/uapi/linux/bcache.h
@@ -90,7 +90,7 @@
 
 #define PTR_CHECK_DEV			((1 << PTR_DEV_BITS) - 1)
 
-#define PTR(gen, offset, dev)						\
+#define MAKE_PTR(gen, offset, dev)					\
 	((((__u64) dev) << 51) | ((__u64) offset) << 8 | gen)
 
 /* Bkey utility code */
--- linux-4.4.0.orig/include/uapi/linux/can.h
+++ linux-4.4.0/include/uapi/linux/can.h
@@ -196,5 +196,6 @@
 };
 
 #define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */
+#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */
 
 #endif /* !_UAPI_CAN_H */
--- linux-4.4.0.orig/include/uapi/linux/capability.h
+++ linux-4.4.0/include/uapi/linux/capability.h
@@ -62,9 +62,13 @@
 #define VFS_CAP_U32_2           2
 #define XATTR_CAPS_SZ_2         (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
 
-#define XATTR_CAPS_SZ           XATTR_CAPS_SZ_2
-#define VFS_CAP_U32             VFS_CAP_U32_2
-#define VFS_CAP_REVISION	VFS_CAP_REVISION_2
+#define VFS_CAP_REVISION_3	0x03000000
+#define VFS_CAP_U32_3           2
+#define XATTR_CAPS_SZ_3         (sizeof(__le32)*(2 + 2*VFS_CAP_U32_3))
+
+#define XATTR_CAPS_SZ           XATTR_CAPS_SZ_3
+#define VFS_CAP_U32             VFS_CAP_U32_3
+#define VFS_CAP_REVISION	VFS_CAP_REVISION_3
 
 struct vfs_cap_data {
 	__le32 magic_etc;            /* Little endian */
@@ -74,6 +78,18 @@
 	} data[VFS_CAP_U32];
 };
 
+/*
+ * same as vfs_cap_data but with a rootid at the end
+ */
+struct vfs_ns_cap_data {
+	__le32 magic_etc;
+	struct {
+		__le32 permitted;    /* Little endian */
+		__le32 inheritable;  /* Little endian */
+	} data[VFS_CAP_U32];
+	__le32 rootid;
+};
+
 #ifndef __KERNEL__
 
 /*
--- linux-4.4.0.orig/include/uapi/linux/coda_psdev.h
+++ linux-4.4.0/include/uapi/linux/coda_psdev.h
@@ -6,19 +6,6 @@
 #define CODA_PSDEV_MAJOR 67
 #define MAX_CODADEVS  5	   /* how many do we allow */
 
-
-/* messages between coda filesystem in kernel and Venus */
-struct upc_req {
-	struct list_head    uc_chain;
-	caddr_t	            uc_data;
-	u_short	            uc_flags;
-	u_short             uc_inSize;  /* Size is at most 5000 bytes */
-	u_short	            uc_outSize;
-	u_short	            uc_opcode;  /* copied from data to save lookup */
-	int		    uc_unique;
-	wait_queue_head_t   uc_sleep;   /* process' wait queue */
-};
-
 #define CODA_REQ_ASYNC  0x1
 #define CODA_REQ_READ   0x2
 #define CODA_REQ_WRITE  0x4
--- linux-4.4.0.orig/include/uapi/linux/const.h
+++ linux-4.4.0/include/uapi/linux/const.h
@@ -24,4 +24,9 @@
 #define _BITUL(x)	(_AC(1,UL) << (x))
 #define _BITULL(x)	(_AC(1,ULL) << (x))
 
+#define __ALIGN_KERNEL(x, a)		__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
+#define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))
+
+#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
 #endif /* !(_LINUX_CONST_H) */
--- linux-4.4.0.orig/include/uapi/linux/cryptouser.h
+++ linux-4.4.0/include/uapi/linux/cryptouser.h
@@ -45,6 +45,7 @@
 	CRYPTOCFGA_REPORT_RNG,		/* struct crypto_report_rng */
 	CRYPTOCFGA_REPORT_CIPHER,	/* struct crypto_report_cipher */
 	CRYPTOCFGA_REPORT_AKCIPHER,	/* struct crypto_report_akcipher */
+	CRYPTOCFGA_REPORT_KPP,		/* struct crypto_report_kpp */
 	__CRYPTOCFGA_MAX
 
 #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1)
@@ -107,5 +108,9 @@
 	char type[CRYPTO_MAX_NAME];
 };
 
+struct crypto_report_kpp {
+	char type[CRYPTO_MAX_NAME];
+};
+
 #define CRYPTO_REPORT_MAXSIZE (sizeof(struct crypto_user_alg) + \
 			       sizeof(struct crypto_report_blkcipher))
--- linux-4.4.0.orig/include/uapi/linux/ethtool.h
+++ linux-4.4.0/include/uapi/linux/ethtool.h
@@ -16,12 +16,17 @@
 #include <linux/types.h>
 #include <linux/if_ether.h>
 
+#ifndef __KERNEL__
+#include <limits.h> /* for INT_MAX */
+#endif
+
 /* All structures exposed to userland should be defined such that they
  * have the same layout for 32-bit and 64-bit userland.
  */
 
 /**
- * struct ethtool_cmd - link control and status
+ * struct ethtool_cmd - DEPRECATED, link control and status
+ * This structure is DEPRECATED, please use struct ethtool_link_settings.
  * @cmd: Command number = %ETHTOOL_GSET or %ETHTOOL_SSET
  * @supported: Bitmask of %SUPPORTED_* flags for the link modes,
  *	physical connectors and other link features for which the
@@ -819,13 +824,13 @@
 static inline __u64 ethtool_get_flow_spec_ring(__u64 ring_cookie)
 {
 	return ETHTOOL_RX_FLOW_SPEC_RING & ring_cookie;
-};
+}
 
 static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie)
 {
 	return (ETHTOOL_RX_FLOW_SPEC_RING_VF & ring_cookie) >>
 				ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
-};
+}
 
 /**
  * struct ethtool_rxnfc - command to get or set RX flow classification rules
@@ -1146,8 +1151,12 @@
 
 
 /* CMDs currently supported */
-#define ETHTOOL_GSET		0x00000001 /* Get settings. */
-#define ETHTOOL_SSET		0x00000002 /* Set settings. */
+#define ETHTOOL_GSET		0x00000001 /* DEPRECATED, Get settings.
+					    * Please use ETHTOOL_GLINKSETTINGS
+					    */
+#define ETHTOOL_SSET		0x00000002 /* DEPRECATED, Set settings.
+					    * Please use ETHTOOL_SLINKSETTINGS
+					    */
 #define ETHTOOL_GDRVINFO	0x00000003 /* Get driver info. */
 #define ETHTOOL_GREGS		0x00000004 /* Get NIC registers. */
 #define ETHTOOL_GWOL		0x00000005 /* Get wake-on-lan options. */
@@ -1226,73 +1235,139 @@
 #define ETHTOOL_GTUNABLE	0x00000048 /* Get tunable configuration */
 #define ETHTOOL_STUNABLE	0x00000049 /* Set tunable configuration */
 
+#define ETHTOOL_GLINKSETTINGS	0x0000004c /* Get ethtool_link_settings */
+#define ETHTOOL_SLINKSETTINGS	0x0000004d /* Set ethtool_link_settings */
+
+
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
 #define SPARC_ETH_SSET		ETHTOOL_SSET
 
-#define SUPPORTED_10baseT_Half		(1 << 0)
-#define SUPPORTED_10baseT_Full		(1 << 1)
-#define SUPPORTED_100baseT_Half		(1 << 2)
-#define SUPPORTED_100baseT_Full		(1 << 3)
-#define SUPPORTED_1000baseT_Half	(1 << 4)
-#define SUPPORTED_1000baseT_Full	(1 << 5)
-#define SUPPORTED_Autoneg		(1 << 6)
-#define SUPPORTED_TP			(1 << 7)
-#define SUPPORTED_AUI			(1 << 8)
-#define SUPPORTED_MII			(1 << 9)
-#define SUPPORTED_FIBRE			(1 << 10)
-#define SUPPORTED_BNC			(1 << 11)
-#define SUPPORTED_10000baseT_Full	(1 << 12)
-#define SUPPORTED_Pause			(1 << 13)
-#define SUPPORTED_Asym_Pause		(1 << 14)
-#define SUPPORTED_2500baseX_Full	(1 << 15)
-#define SUPPORTED_Backplane		(1 << 16)
-#define SUPPORTED_1000baseKX_Full	(1 << 17)
-#define SUPPORTED_10000baseKX4_Full	(1 << 18)
-#define SUPPORTED_10000baseKR_Full	(1 << 19)
-#define SUPPORTED_10000baseR_FEC	(1 << 20)
-#define SUPPORTED_20000baseMLD2_Full	(1 << 21)
-#define SUPPORTED_20000baseKR2_Full	(1 << 22)
-#define SUPPORTED_40000baseKR4_Full	(1 << 23)
-#define SUPPORTED_40000baseCR4_Full	(1 << 24)
-#define SUPPORTED_40000baseSR4_Full	(1 << 25)
-#define SUPPORTED_40000baseLR4_Full	(1 << 26)
-#define SUPPORTED_56000baseKR4_Full	(1 << 27)
-#define SUPPORTED_56000baseCR4_Full	(1 << 28)
-#define SUPPORTED_56000baseSR4_Full	(1 << 29)
-#define SUPPORTED_56000baseLR4_Full	(1 << 30)
-
-#define ADVERTISED_10baseT_Half		(1 << 0)
-#define ADVERTISED_10baseT_Full		(1 << 1)
-#define ADVERTISED_100baseT_Half	(1 << 2)
-#define ADVERTISED_100baseT_Full	(1 << 3)
-#define ADVERTISED_1000baseT_Half	(1 << 4)
-#define ADVERTISED_1000baseT_Full	(1 << 5)
-#define ADVERTISED_Autoneg		(1 << 6)
-#define ADVERTISED_TP			(1 << 7)
-#define ADVERTISED_AUI			(1 << 8)
-#define ADVERTISED_MII			(1 << 9)
-#define ADVERTISED_FIBRE		(1 << 10)
-#define ADVERTISED_BNC			(1 << 11)
-#define ADVERTISED_10000baseT_Full	(1 << 12)
-#define ADVERTISED_Pause		(1 << 13)
-#define ADVERTISED_Asym_Pause		(1 << 14)
-#define ADVERTISED_2500baseX_Full	(1 << 15)
-#define ADVERTISED_Backplane		(1 << 16)
-#define ADVERTISED_1000baseKX_Full	(1 << 17)
-#define ADVERTISED_10000baseKX4_Full	(1 << 18)
-#define ADVERTISED_10000baseKR_Full	(1 << 19)
-#define ADVERTISED_10000baseR_FEC	(1 << 20)
-#define ADVERTISED_20000baseMLD2_Full	(1 << 21)
-#define ADVERTISED_20000baseKR2_Full	(1 << 22)
-#define ADVERTISED_40000baseKR4_Full	(1 << 23)
-#define ADVERTISED_40000baseCR4_Full	(1 << 24)
-#define ADVERTISED_40000baseSR4_Full	(1 << 25)
-#define ADVERTISED_40000baseLR4_Full	(1 << 26)
-#define ADVERTISED_56000baseKR4_Full	(1 << 27)
-#define ADVERTISED_56000baseCR4_Full	(1 << 28)
-#define ADVERTISED_56000baseSR4_Full	(1 << 29)
-#define ADVERTISED_56000baseLR4_Full	(1 << 30)
+/* Link mode bit indices */
+enum ethtool_link_mode_bit_indices {
+	ETHTOOL_LINK_MODE_10baseT_Half_BIT	= 0,
+	ETHTOOL_LINK_MODE_10baseT_Full_BIT	= 1,
+	ETHTOOL_LINK_MODE_100baseT_Half_BIT	= 2,
+	ETHTOOL_LINK_MODE_100baseT_Full_BIT	= 3,
+	ETHTOOL_LINK_MODE_1000baseT_Half_BIT	= 4,
+	ETHTOOL_LINK_MODE_1000baseT_Full_BIT	= 5,
+	ETHTOOL_LINK_MODE_Autoneg_BIT		= 6,
+	ETHTOOL_LINK_MODE_TP_BIT		= 7,
+	ETHTOOL_LINK_MODE_AUI_BIT		= 8,
+	ETHTOOL_LINK_MODE_MII_BIT		= 9,
+	ETHTOOL_LINK_MODE_FIBRE_BIT		= 10,
+	ETHTOOL_LINK_MODE_BNC_BIT		= 11,
+	ETHTOOL_LINK_MODE_10000baseT_Full_BIT	= 12,
+	ETHTOOL_LINK_MODE_Pause_BIT		= 13,
+	ETHTOOL_LINK_MODE_Asym_Pause_BIT	= 14,
+	ETHTOOL_LINK_MODE_2500baseX_Full_BIT	= 15,
+	ETHTOOL_LINK_MODE_Backplane_BIT		= 16,
+	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT	= 17,
+	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT	= 18,
+	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT	= 19,
+	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT	= 20,
+	ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT = 21,
+	ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT	= 22,
+	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT	= 23,
+	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT	= 24,
+	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT	= 25,
+	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT	= 26,
+	ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT	= 27,
+	ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT	= 28,
+	ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT	= 29,
+	ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT	= 30,
+
+	/* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
+	 * 31. Please do NOT define any SUPPORTED_* or ADVERTISED_*
+	 * macro for bits > 31. The only way to use indices > 31 is to
+	 * use the new ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API.
+	 */
+
+	__ETHTOOL_LINK_MODE_LAST
+	  = ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
+};
+
+#define __ETHTOOL_LINK_MODE_LEGACY_MASK(base_name)	\
+	(1UL << (ETHTOOL_LINK_MODE_ ## base_name ## _BIT))
+
+/* DEPRECATED macros. Please migrate to
+ * ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. Please do NOT
+ * define any new SUPPORTED_* macro for bits > 31.
+ */
+#define SUPPORTED_10baseT_Half		__ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Half)
+#define SUPPORTED_10baseT_Full		__ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Full)
+#define SUPPORTED_100baseT_Half		__ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Half)
+#define SUPPORTED_100baseT_Full		__ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Full)
+#define SUPPORTED_1000baseT_Half	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Half)
+#define SUPPORTED_1000baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Full)
+#define SUPPORTED_Autoneg		__ETHTOOL_LINK_MODE_LEGACY_MASK(Autoneg)
+#define SUPPORTED_TP			__ETHTOOL_LINK_MODE_LEGACY_MASK(TP)
+#define SUPPORTED_AUI			__ETHTOOL_LINK_MODE_LEGACY_MASK(AUI)
+#define SUPPORTED_MII			__ETHTOOL_LINK_MODE_LEGACY_MASK(MII)
+#define SUPPORTED_FIBRE			__ETHTOOL_LINK_MODE_LEGACY_MASK(FIBRE)
+#define SUPPORTED_BNC			__ETHTOOL_LINK_MODE_LEGACY_MASK(BNC)
+#define SUPPORTED_10000baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseT_Full)
+#define SUPPORTED_Pause			__ETHTOOL_LINK_MODE_LEGACY_MASK(Pause)
+#define SUPPORTED_Asym_Pause		__ETHTOOL_LINK_MODE_LEGACY_MASK(Asym_Pause)
+#define SUPPORTED_2500baseX_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(2500baseX_Full)
+#define SUPPORTED_Backplane		__ETHTOOL_LINK_MODE_LEGACY_MASK(Backplane)
+#define SUPPORTED_1000baseKX_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseKX_Full)
+#define SUPPORTED_10000baseKX4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKX4_Full)
+#define SUPPORTED_10000baseKR_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKR_Full)
+#define SUPPORTED_10000baseR_FEC	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseR_FEC)
+#define SUPPORTED_20000baseMLD2_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseMLD2_Full)
+#define SUPPORTED_20000baseKR2_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseKR2_Full)
+#define SUPPORTED_40000baseKR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseKR4_Full)
+#define SUPPORTED_40000baseCR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseCR4_Full)
+#define SUPPORTED_40000baseSR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseSR4_Full)
+#define SUPPORTED_40000baseLR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseLR4_Full)
+#define SUPPORTED_56000baseKR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseKR4_Full)
+#define SUPPORTED_56000baseCR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseCR4_Full)
+#define SUPPORTED_56000baseSR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseSR4_Full)
+#define SUPPORTED_56000baseLR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseLR4_Full)
+/* Please do not define any new SUPPORTED_* macro for bits > 31, see
+ * notice above.
+ */
+
+/*
+ * DEPRECATED macros. Please migrate to
+ * ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. Please do NOT
+ * define any new ADERTISE_* macro for bits > 31.
+ */
+#define ADVERTISED_10baseT_Half		__ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Half)
+#define ADVERTISED_10baseT_Full		__ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Full)
+#define ADVERTISED_100baseT_Half	__ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Half)
+#define ADVERTISED_100baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Full)
+#define ADVERTISED_1000baseT_Half	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Half)
+#define ADVERTISED_1000baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Full)
+#define ADVERTISED_Autoneg		__ETHTOOL_LINK_MODE_LEGACY_MASK(Autoneg)
+#define ADVERTISED_TP			__ETHTOOL_LINK_MODE_LEGACY_MASK(TP)
+#define ADVERTISED_AUI			__ETHTOOL_LINK_MODE_LEGACY_MASK(AUI)
+#define ADVERTISED_MII			__ETHTOOL_LINK_MODE_LEGACY_MASK(MII)
+#define ADVERTISED_FIBRE		__ETHTOOL_LINK_MODE_LEGACY_MASK(FIBRE)
+#define ADVERTISED_BNC			__ETHTOOL_LINK_MODE_LEGACY_MASK(BNC)
+#define ADVERTISED_10000baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseT_Full)
+#define ADVERTISED_Pause		__ETHTOOL_LINK_MODE_LEGACY_MASK(Pause)
+#define ADVERTISED_Asym_Pause		__ETHTOOL_LINK_MODE_LEGACY_MASK(Asym_Pause)
+#define ADVERTISED_2500baseX_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(2500baseX_Full)
+#define ADVERTISED_Backplane		__ETHTOOL_LINK_MODE_LEGACY_MASK(Backplane)
+#define ADVERTISED_1000baseKX_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseKX_Full)
+#define ADVERTISED_10000baseKX4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKX4_Full)
+#define ADVERTISED_10000baseKR_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKR_Full)
+#define ADVERTISED_10000baseR_FEC	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseR_FEC)
+#define ADVERTISED_20000baseMLD2_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseMLD2_Full)
+#define ADVERTISED_20000baseKR2_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseKR2_Full)
+#define ADVERTISED_40000baseKR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseKR4_Full)
+#define ADVERTISED_40000baseCR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseCR4_Full)
+#define ADVERTISED_40000baseSR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseSR4_Full)
+#define ADVERTISED_40000baseLR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseLR4_Full)
+#define ADVERTISED_56000baseKR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseKR4_Full)
+#define ADVERTISED_56000baseCR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseCR4_Full)
+#define ADVERTISED_56000baseSR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseSR4_Full)
+#define ADVERTISED_56000baseLR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseLR4_Full)
+/* Please do not define any new ADVERTISED_* macro for bits > 31, see
+ * notice above.
+ */
 
 /* The following are all involved in forcing a particular link
  * mode for the device for setting things.  When getting the
@@ -1316,11 +1391,28 @@
 
 #define SPEED_UNKNOWN		-1
 
+static inline int ethtool_validate_speed(__u32 speed)
+{
+	return speed <= INT_MAX || speed == SPEED_UNKNOWN;
+}
+
 /* Duplex, half or full. */
 #define DUPLEX_HALF		0x00
 #define DUPLEX_FULL		0x01
 #define DUPLEX_UNKNOWN		0xff
 
+static inline int ethtool_validate_duplex(__u8 duplex)
+{
+	switch (duplex) {
+	case DUPLEX_HALF:
+	case DUPLEX_FULL:
+	case DUPLEX_UNKNOWN:
+		return 1;
+	}
+
+	return 0;
+}
+
 /* Which connector port. */
 #define PORT_TP			0x00
 #define PORT_AUI		0x01
@@ -1438,4 +1530,123 @@
 };
 #define ETH_RESET_SHARED_SHIFT	16
 
+
+/**
+ * struct ethtool_link_settings - link control and status
+ *
+ * IMPORTANT, Backward compatibility notice: When implementing new
+ *	user-space tools, please first try %ETHTOOL_GLINKSETTINGS, and
+ *	if it succeeds use %ETHTOOL_SLINKSETTINGS to change link
+ *	settings; do not use %ETHTOOL_SSET if %ETHTOOL_GLINKSETTINGS
+ *	succeeded: stick to %ETHTOOL_GLINKSETTINGS/%SLINKSETTINGS in
+ *	that case.  Conversely, if %ETHTOOL_GLINKSETTINGS fails, use
+ *	%ETHTOOL_GSET to query and %ETHTOOL_SSET to change link
+ *	settings; do not use %ETHTOOL_SLINKSETTINGS if
+ *	%ETHTOOL_GLINKSETTINGS failed: stick to
+ *	%ETHTOOL_GSET/%ETHTOOL_SSET in that case.
+ *
+ * @cmd: Command number = %ETHTOOL_GLINKSETTINGS or %ETHTOOL_SLINKSETTINGS
+ * @speed: Link speed (Mbps)
+ * @duplex: Duplex mode; one of %DUPLEX_*
+ * @port: Physical connector type; one of %PORT_*
+ * @phy_address: MDIO address of PHY (transceiver); 0 or 255 if not
+ *	applicable.  For clause 45 PHYs this is the PRTAD.
+ * @autoneg: Enable/disable autonegotiation and auto-detection;
+ *	either %AUTONEG_DISABLE or %AUTONEG_ENABLE
+ * @mdio_support: Bitmask of %ETH_MDIO_SUPPORTS_* flags for the MDIO
+ *	protocols supported by the interface; 0 if unknown.
+ *	Read-only.
+ * @eth_tp_mdix: Ethernet twisted-pair MDI(-X) status; one of
+ *	%ETH_TP_MDI_*.  If the status is unknown or not applicable, the
+ *	value will be %ETH_TP_MDI_INVALID.  Read-only.
+ * @eth_tp_mdix_ctrl: Ethernet twisted pair MDI(-X) control; one of
+ *	%ETH_TP_MDI_*.  If MDI(-X) control is not implemented, reads
+ *	yield %ETH_TP_MDI_INVALID and writes may be ignored or rejected.
+ *	When written successfully, the link should be renegotiated if
+ *	necessary.
+ * @link_mode_masks_nwords: Number of 32-bit words for each of the
+ *	supported, advertising, lp_advertising link mode bitmaps. For
+ *	%ETHTOOL_GLINKSETTINGS: on entry, number of words passed by user
+ *	(>= 0); on return, if handshake in progress, negative if
+ *	request size unsupported by kernel: absolute value indicates
+ *	kernel recommended size and cmd field is 0, as well as all the
+ *	other fields; otherwise (handshake completed), strictly
+ *	positive to indicate size used by kernel and cmd field is
+ *	%ETHTOOL_GLINKSETTINGS, all other fields populated by driver. For
+ *	%ETHTOOL_SLINKSETTINGS: must be valid on entry, ie. a positive
+ *	value returned previously by %ETHTOOL_GLINKSETTINGS, otherwise
+ *	refused. For drivers: ignore this field (use kernel's
+ *	__ETHTOOL_LINK_MODE_MASK_NBITS instead), any change to it will
+ *	be overwritten by kernel.
+ * @supported: Bitmap with each bit meaning given by
+ *	%ethtool_link_mode_bit_indices for the link modes, physical
+ *	connectors and other link features for which the interface
+ *	supports autonegotiation or auto-detection.  Read-only.
+ * @advertising: Bitmap with each bit meaning given by
+ *	%ethtool_link_mode_bit_indices for the link modes, physical
+ *	connectors and other link features that are advertised through
+ *	autonegotiation or enabled for auto-detection.
+ * @lp_advertising: Bitmap with each bit meaning given by
+ *	%ethtool_link_mode_bit_indices for the link modes, and other
+ *	link features that the link partner advertised through
+ *	autonegotiation; 0 if unknown or not applicable.  Read-only.
+ *
+ * If autonegotiation is disabled, the speed and @duplex represent the
+ * fixed link mode and are writable if the driver supports multiple
+ * link modes.  If it is enabled then they are read-only; if the link
+ * is up they represent the negotiated link mode; if the link is down,
+ * the speed is 0, %SPEED_UNKNOWN or the highest enabled speed and
+ * @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
+ *
+ * Some hardware interfaces may have multiple PHYs and/or physical
+ * connectors fitted or do not allow the driver to detect which are
+ * fitted.  For these interfaces @port and/or @phy_address may be
+ * writable, possibly dependent on @autoneg being %AUTONEG_DISABLE.
+ * Otherwise, attempts to write different values may be ignored or
+ * rejected.
+ *
+ * Deprecated %ethtool_cmd fields transceiver, maxtxpkt and maxrxpkt
+ * are not available in %ethtool_link_settings. Until all drivers are
+ * converted to ignore them or to the new %ethtool_link_settings API,
+ * for both queries and changes, users should always try
+ * %ETHTOOL_GLINKSETTINGS first, and if it fails with -ENOTSUPP stick
+ * only to %ETHTOOL_GSET and %ETHTOOL_SSET consistently. If it
+ * succeeds, then users should stick to %ETHTOOL_GLINKSETTINGS and
+ * %ETHTOOL_SLINKSETTINGS (which would support drivers implementing
+ * either %ethtool_cmd or %ethtool_link_settings).
+ *
+ * Users should assume that all fields not marked read-only are
+ * writable and subject to validation by the driver.  They should use
+ * %ETHTOOL_GLINKSETTINGS to get the current values before making specific
+ * changes and then applying them with %ETHTOOL_SLINKSETTINGS.
+ *
+ * Drivers that implement %get_link_ksettings and/or
+ * %set_link_ksettings should ignore the @cmd
+ * and @link_mode_masks_nwords fields (any change to them overwritten
+ * by kernel), and rely only on kernel's internal
+ * %__ETHTOOL_LINK_MODE_MASK_NBITS and
+ * %ethtool_link_mode_mask_t. Drivers that implement
+ * %set_link_ksettings() should validate all fields other than @cmd
+ * and @link_mode_masks_nwords that are not described as read-only or
+ * deprecated, and must ignore all fields described as read-only.
+ */
+struct ethtool_link_settings {
+	__u32	cmd;
+	__u32	speed;
+	__u8	duplex;
+	__u8	port;
+	__u8	phy_address;
+	__u8	autoneg;
+	__u8	mdio_support;
+	__u8	eth_tp_mdix;
+	__u8	eth_tp_mdix_ctrl;
+	__s8	link_mode_masks_nwords;
+	__u32	reserved[8];
+	__u32	link_mode_masks[0];
+	/* layout of link_mode_masks fields:
+	 * __u32 map_supported[link_mode_masks_nwords];
+	 * __u32 map_advertising[link_mode_masks_nwords];
+	 * __u32 map_lp_advertising[link_mode_masks_nwords];
+	 */
+};
 #endif /* _UAPI_LINUX_ETHTOOL_H */
--- linux-4.4.0.orig/include/uapi/linux/eventpoll.h
+++ linux-4.4.0/include/uapi/linux/eventpoll.h
@@ -26,6 +26,19 @@
 #define EPOLL_CTL_DEL 2
 #define EPOLL_CTL_MOD 3
 
+/* Epoll event masks */
+#define EPOLLIN		0x00000001
+#define EPOLLPRI	0x00000002
+#define EPOLLOUT	0x00000004
+#define EPOLLERR	0x00000008
+#define EPOLLHUP	0x00000010
+#define EPOLLRDNORM	0x00000040
+#define EPOLLRDBAND	0x00000080
+#define EPOLLWRNORM	0x00000100
+#define EPOLLWRBAND	0x00000200
+#define EPOLLMSG	0x00000400
+#define EPOLLRDHUP	0x00002000
+
 /*
  * Request the handling of system wakeup events so as to prevent system suspends
  * from happening while those events are being processed.
--- linux-4.4.0.orig/include/uapi/linux/fs.h
+++ linux-4.4.0/include/uapi/linux/fs.h
@@ -93,6 +93,7 @@
 #define MS_LAZYTIME	(1<<25) /* Update the on-disk [acm]times lazily */
 
 /* These sb flags are internal to the kernel */
+#define MS_SUBMOUNT     (1<<26)
 #define MS_NOSEC	(1<<28)
 #define MS_BORN		(1<<29)
 #define MS_ACTIVE	(1<<30)
--- linux-4.4.0.orig/include/uapi/linux/fuse.h
+++ linux-4.4.0/include/uapi/linux/fuse.h
@@ -205,10 +205,12 @@
  * FOPEN_DIRECT_IO: bypass page cache for this open file
  * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
  * FOPEN_NONSEEKABLE: the file is not seekable
+ * FOPEN_STREAM: the file is stream-like (no file position at all)
  */
 #define FOPEN_DIRECT_IO		(1 << 0)
 #define FOPEN_KEEP_CACHE	(1 << 1)
 #define FOPEN_NONSEEKABLE	(1 << 2)
+#define FOPEN_STREAM		(1 << 4)
 
 /**
  * INIT request/reply flags
--- linux-4.4.0.orig/include/uapi/linux/genetlink.h
+++ linux-4.4.0/include/uapi/linux/genetlink.h
@@ -21,6 +21,7 @@
 #define GENL_CMD_CAP_DO		0x02
 #define GENL_CMD_CAP_DUMP	0x04
 #define GENL_CMD_CAP_HASPOL	0x08
+#define GENL_UNS_ADMIN_PERM	0x10
 
 /*
  * List of reserved static generic netlink identifiers:
--- linux-4.4.0.orig/include/uapi/linux/hash_info.h
+++ linux-4.4.0/include/uapi/linux/hash_info.h
@@ -31,6 +31,7 @@
 	HASH_ALGO_TGR_128,
 	HASH_ALGO_TGR_160,
 	HASH_ALGO_TGR_192,
+	HASH_ALGO_SM3_256,
 	HASH_ALGO__LAST
 };
 
--- linux-4.4.0.orig/include/uapi/linux/hyperv.h
+++ linux-4.4.0/include/uapi/linux/hyperv.h
@@ -313,6 +313,7 @@
 #define HV_INVALIDARG			0x80070057
 #define HV_GUID_NOTFOUND		0x80041002
 #define HV_ERROR_ALREADY_EXISTS		0x80070050
+#define HV_ERROR_DISK_FULL		0x80070070
 
 #define ADDR_FAMILY_NONE	0x00
 #define ADDR_FAMILY_IPV4	0x01
--- linux-4.4.0.orig/include/uapi/linux/if.h
+++ linux-4.4.0/include/uapi/linux/if.h
@@ -19,14 +19,20 @@
 #ifndef _LINUX_IF_H
 #define _LINUX_IF_H
 
+#include <linux/libc-compat.h>          /* for compatibility with glibc */
 #include <linux/types.h>		/* for "__kernel_caddr_t" et al	*/
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
 #include <linux/compiler.h>		/* for "__user" et al           */
 
+#if __UAPI_DEF_IF_IFNAMSIZ
 #define	IFNAMSIZ	16
+#endif /* __UAPI_DEF_IF_IFNAMSIZ */
 #define	IFALIASZ	256
 #include <linux/hdlc/ioctl.h>
 
+/* For glibc compatibility. An empty enum does not compile. */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || \
+    __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0
 /**
  * enum net_device_flags - &struct net_device flags
  *
@@ -68,6 +74,8 @@
  * @IFF_ECHO: echo sent packets. Volatile.
  */
 enum net_device_flags {
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
 	IFF_UP				= 1<<0,  /* sysfs */
 	IFF_BROADCAST			= 1<<1,  /* volatile */
 	IFF_DEBUG			= 1<<2,  /* sysfs */
@@ -84,11 +92,17 @@
 	IFF_PORTSEL			= 1<<13, /* sysfs */
 	IFF_AUTOMEDIA			= 1<<14, /* sysfs */
 	IFF_DYNAMIC			= 1<<15, /* sysfs */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
 	IFF_LOWER_UP			= 1<<16, /* volatile */
 	IFF_DORMANT			= 1<<17, /* volatile */
 	IFF_ECHO			= 1<<18, /* volatile */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
 };
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */
 
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
 #define IFF_UP				IFF_UP
 #define IFF_BROADCAST			IFF_BROADCAST
 #define IFF_DEBUG			IFF_DEBUG
@@ -105,9 +119,13 @@
 #define IFF_PORTSEL			IFF_PORTSEL
 #define IFF_AUTOMEDIA			IFF_AUTOMEDIA
 #define IFF_DYNAMIC			IFF_DYNAMIC
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
+
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
 #define IFF_LOWER_UP			IFF_LOWER_UP
 #define IFF_DORMANT			IFF_DORMANT
 #define IFF_ECHO			IFF_ECHO
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
 
 #define IFF_VOLATILE	(IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
 		IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
@@ -166,6 +184,8 @@
  *	being very small might be worth keeping for clean configuration.
  */
 
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFMAP
 struct ifmap {
 	unsigned long mem_start;
 	unsigned long mem_end;
@@ -175,6 +195,7 @@
 	unsigned char port;
 	/* 3 bytes spare */
 };
+#endif /* __UAPI_DEF_IF_IFMAP */
 
 struct if_settings {
 	unsigned int type;	/* Type of physical device or protocol */
@@ -200,6 +221,8 @@
  * remainder may be interface specific.
  */
 
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFREQ
 struct ifreq {
 #define IFHWADDRLEN	6
 	union
@@ -223,6 +246,7 @@
 		struct	if_settings ifru_settings;
 	} ifr_ifru;
 };
+#endif /* __UAPI_DEF_IF_IFREQ */
 
 #define ifr_name	ifr_ifrn.ifrn_name	/* interface name 	*/
 #define ifr_hwaddr	ifr_ifru.ifru_hwaddr	/* MAC address 		*/
@@ -249,6 +273,8 @@
  * must know all networks accessible).
  */
 
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFCONF
 struct ifconf  {
 	int	ifc_len;			/* size of buffer	*/
 	union {
@@ -256,6 +282,8 @@
 		struct ifreq __user *ifcu_req;
 	} ifc_ifcu;
 };
+#endif /* __UAPI_DEF_IF_IFCONF */
+
 #define	ifc_buf	ifc_ifcu.ifcu_buf		/* buffer address	*/
 #define	ifc_req	ifc_ifcu.ifcu_req		/* array of structures	*/
 
--- linux-4.4.0.orig/include/uapi/linux/if_ether.h
+++ linux-4.4.0/include/uapi/linux/if_ether.h
@@ -29,12 +29,15 @@
  */
 
 #define ETH_ALEN	6		/* Octets in one ethernet addr	 */
+#define ETH_TLEN	2		/* Octets in ethernet type field */
 #define ETH_HLEN	14		/* Total octets in header.	 */
 #define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
 #define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
 #define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
 #define ETH_FCS_LEN	4		/* Octets in the FCS		 */
 
+#define ETH_MIN_MTU	68		/* Min IPv4 MTU per RFC791	*/
+
 /*
  *	These are the defined Ethernet Protocol ID's.
  */
@@ -135,11 +138,18 @@
  *	This is an Ethernet frame header.
  */
 
+/* allow libcs like musl to deactivate this, glibc does not implement this. */
+#ifndef __UAPI_DEF_ETHHDR
+#define __UAPI_DEF_ETHHDR		1
+#endif
+
+#if __UAPI_DEF_ETHHDR
 struct ethhdr {
 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
 	__be16		h_proto;		/* packet type ID field	*/
 } __attribute__((packed));
+#endif
 
 
 #endif /* _UAPI_LINUX_IF_ETHER_H */
--- linux-4.4.0.orig/include/uapi/linux/if_link.h
+++ linux-4.4.0/include/uapi/linux/if_link.h
@@ -443,6 +443,7 @@
 	IFLA_VXLAN_GBP,
 	IFLA_VXLAN_REMCSUM_NOPARTIAL,
 	IFLA_VXLAN_COLLECT_METADATA,
+	IFLA_VXLAN_FAN_MAP = 33,
 	__IFLA_VXLAN_MAX
 };
 #define IFLA_VXLAN_MAX	(__IFLA_VXLAN_MAX - 1)
@@ -462,6 +463,9 @@
 	IFLA_GENEVE_PORT,	/* destination port */
 	IFLA_GENEVE_COLLECT_METADATA,
 	IFLA_GENEVE_REMOTE6,
+	IFLA_GENEVE_UDP_CSUM,
+	IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
+	IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
 	__IFLA_GENEVE_MAX
 };
 #define IFLA_GENEVE_MAX	(__IFLA_GENEVE_MAX - 1)
--- linux-4.4.0.orig/include/uapi/linux/if_pppol2tp.h
+++ linux-4.4.0/include/uapi/linux/if_pppol2tp.h
@@ -17,6 +17,7 @@
 
 #include <linux/types.h>
 
+#include <linux/l2tp.h>
 
 /* Structure used to connect() the socket to a particular tunnel UDP
  * socket over IPv4.
@@ -89,14 +90,12 @@
 	PPPOL2TP_SO_REORDERTO	= 5,
 };
 
-/* Debug message categories for the DEBUG socket option */
+/* Debug message categories for the DEBUG socket option (deprecated) */
 enum {
-	PPPOL2TP_MSG_DEBUG	= (1 << 0),	/* verbose debug (if
-						 * compiled in) */
-	PPPOL2TP_MSG_CONTROL	= (1 << 1),	/* userspace - kernel
-						 * interface */
-	PPPOL2TP_MSG_SEQ	= (1 << 2),	/* sequence numbers */
-	PPPOL2TP_MSG_DATA	= (1 << 3),	/* data packets */
+	PPPOL2TP_MSG_DEBUG	= L2TP_MSG_DEBUG,
+	PPPOL2TP_MSG_CONTROL	= L2TP_MSG_CONTROL,
+	PPPOL2TP_MSG_SEQ	= L2TP_MSG_SEQ,
+	PPPOL2TP_MSG_DATA	= L2TP_MSG_DATA,
 };
 
 
--- linux-4.4.0.orig/include/uapi/linux/if_tunnel.h
+++ linux-4.4.0/include/uapi/linux/if_tunnel.h
@@ -57,6 +57,10 @@
 	IFLA_IPTUN_ENCAP_FLAGS,
 	IFLA_IPTUN_ENCAP_SPORT,
 	IFLA_IPTUN_ENCAP_DPORT,
+
+	__IFLA_IPTUN_VENDOR_BREAK, /* Ensure new entries do not hit the below. */
+	IFLA_IPTUN_FAN_MAP = 33,
+
 	__IFLA_IPTUN_MAX,
 };
 #define IFLA_IPTUN_MAX	(__IFLA_IPTUN_MAX - 1)
@@ -132,4 +136,20 @@
 };
 
 #define IFLA_VTI_MAX	(__IFLA_VTI_MAX - 1)
+
+enum {
+	IFLA_FAN_UNSPEC,
+	IFLA_FAN_MAPPING,
+	__IFLA_FAN_MAX,
+};
+
+#define IFLA_FAN_MAX (__IFLA_FAN_MAX - 1)
+
+struct ifla_fan_map {
+	__be32		underlay;
+	__be32		overlay;
+	__u16		underlay_prefix;
+	__u16		overlay_prefix;
+};
+
 #endif /* _UAPI_IF_TUNNEL_H_ */
--- linux-4.4.0.orig/include/uapi/linux/input-event-codes.h
+++ linux-4.4.0/include/uapi/linux/input-event-codes.h
@@ -708,6 +708,15 @@
 
 #define ABS_MISC		0x28
 
+/*
+ * 0x2e is reserved and should not be used in input drivers.
+ * It was used by HID as ABS_MISC+6 and userspace needs to detect if
+ * the next ABS_* event is correct or is just ABS_MISC + n.
+ * We define here ABS_RESERVED so userspace can rely on it and detect
+ * the situation described above.
+ */
+#define ABS_RESERVED		0x2e
+
 #define ABS_MT_SLOT		0x2f	/* MT slot being modified */
 #define ABS_MT_TOUCH_MAJOR	0x30	/* Major axis of touching ellipse */
 #define ABS_MT_TOUCH_MINOR	0x31	/* Minor axis (omit if circular) */
--- linux-4.4.0.orig/include/uapi/linux/ipv6_route.h
+++ linux-4.4.0/include/uapi/linux/ipv6_route.h
@@ -34,7 +34,7 @@
 #define RTF_PREF(pref)	((pref) << 27)
 #define RTF_PREF_MASK	0x18000000
 
-#define RTF_PCPU	0x40000000
+#define RTF_PCPU	0x40000000	/* read-only: can not be set by user */
 #define RTF_LOCAL	0x80000000
 
 
--- linux-4.4.0.orig/include/uapi/linux/isdn/capicmd.h
+++ linux-4.4.0/include/uapi/linux/isdn/capicmd.h
@@ -15,6 +15,7 @@
 #define CAPI_MSG_BASELEN		8
 #define CAPI_DATA_B3_REQ_LEN		(CAPI_MSG_BASELEN+4+4+2+2+2)
 #define CAPI_DATA_B3_RESP_LEN		(CAPI_MSG_BASELEN+4+2)
+#define CAPI_DISCONNECT_B3_RESP_LEN	(CAPI_MSG_BASELEN+4)
 
 /*----- CAPI commands -----*/
 #define CAPI_ALERT		    0x01
--- linux-4.4.0.orig/include/uapi/linux/kd.h
+++ linux-4.4.0/include/uapi/linux/kd.h
@@ -45,6 +45,8 @@
 #define		KD_GRAPHICS	0x01
 #define		KD_TEXT0	0x02	/* obsolete */
 #define		KD_TEXT1	0x03	/* obsolete */
+#define		KD_TRANSPARENT	0x04
+
 #define KDGETMODE	0x4B3B	/* get current mode */
 
 #define KDMAPDISP	0x4B3C	/* map display into address space */
--- linux-4.4.0.orig/include/uapi/linux/kvm.h
+++ linux-4.4.0/include/uapi/linux/kvm.h
@@ -154,6 +154,20 @@
 	__u32 flags;
 	__u32 reserved[9];
 };
+
+struct kvm_hyperv_exit {
+#define KVM_EXIT_HYPERV_SYNIC          1
+	__u32 type;
+	union {
+		struct {
+			__u32 msr;
+			__u64 control;
+			__u64 evt_page;
+			__u64 msg_page;
+		} synic;
+	} u;
+};
+
 #define KVM_S390_GET_SKEYS_NONE   1
 #define KVM_S390_SKEYS_MAX        1048576
 
@@ -184,6 +198,7 @@
 #define KVM_EXIT_SYSTEM_EVENT     24
 #define KVM_EXIT_S390_STSI        25
 #define KVM_EXIT_IOAPIC_EOI       26
+#define KVM_EXIT_HYPERV           27
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -338,6 +353,8 @@
 		struct {
 			__u8 vector;
 		} eoi;
+		/* KVM_EXIT_HYPERV */
+		struct kvm_hyperv_exit hyperv;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -688,6 +705,7 @@
 #define KVM_TRACE_PAUSE           __KVM_DEPRECATED_MAIN_0x07
 #define KVM_TRACE_DISABLE         __KVM_DEPRECATED_MAIN_0x08
 #define KVM_GET_EMULATED_CPUID	  _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
+#define KVM_GET_MSR_FEATURE_INDEX_LIST    _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
 
 /*
  * Extension capability list.
@@ -831,6 +849,9 @@
 #define KVM_CAP_GUEST_DEBUG_HW_WPS 120
 #define KVM_CAP_SPLIT_IRQCHIP 121
 #define KVM_CAP_IOEVENTFD_ANY_LENGTH 122
+#define KVM_CAP_HYPERV_SYNIC 123
+#define KVM_CAP_S390_BPB 152
+#define KVM_CAP_GET_MSR_FEATURES 153
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -854,10 +875,16 @@
 	__u32 adapter_id;
 };
 
+struct kvm_irq_routing_hv_sint {
+	__u32 vcpu;
+	__u32 sint;
+};
+
 /* gsi routing entry types */
 #define KVM_IRQ_ROUTING_IRQCHIP 1
 #define KVM_IRQ_ROUTING_MSI 2
 #define KVM_IRQ_ROUTING_S390_ADAPTER 3
+#define KVM_IRQ_ROUTING_HV_SINT 4
 
 struct kvm_irq_routing_entry {
 	__u32 gsi;
@@ -868,6 +895,7 @@
 		struct kvm_irq_routing_irqchip irqchip;
 		struct kvm_irq_routing_msi msi;
 		struct kvm_irq_routing_s390_adapter adapter;
+		struct kvm_irq_routing_hv_sint hv_sint;
 		__u32 pad[8];
 	} u;
 };
--- linux-4.4.0.orig/include/uapi/linux/l2tp.h
+++ linux-4.4.0/include/uapi/linux/l2tp.h
@@ -9,9 +9,8 @@
 
 #include <linux/types.h>
 #include <linux/socket.h>
-#ifndef __KERNEL__
-#include <netinet/in.h>
-#endif
+#include <linux/in.h>
+#include <linux/in6.h>
 
 #define IPPROTO_L2TP		115
 
@@ -31,7 +30,7 @@
 	__u32		l2tp_conn_id;	/* Connection ID of tunnel */
 
 	/* Pad to size of `struct sockaddr'. */
-	unsigned char	__pad[sizeof(struct sockaddr) -
+	unsigned char	__pad[__SOCK_SIZE__ -
 			      sizeof(__kernel_sa_family_t) -
 			      sizeof(__be16) - sizeof(struct in_addr) -
 			      sizeof(__u32)];
@@ -108,7 +107,7 @@
 	L2TP_ATTR_VLAN_ID,		/* u16 */
 	L2TP_ATTR_COOKIE,		/* 0, 4 or 8 bytes */
 	L2TP_ATTR_PEER_COOKIE,		/* 0, 4 or 8 bytes */
-	L2TP_ATTR_DEBUG,		/* u32 */
+	L2TP_ATTR_DEBUG,		/* u32, enum l2tp_debug_flags */
 	L2TP_ATTR_RECV_SEQ,		/* u8 */
 	L2TP_ATTR_SEND_SEQ,		/* u8 */
 	L2TP_ATTR_LNS_MODE,		/* u8 */
@@ -173,6 +172,21 @@
 	L2TP_SEQ_ALL = 2,
 };
 
+/**
+ * enum l2tp_debug_flags - debug message categories for L2TP tunnels/sessions
+ *
+ * @L2TP_MSG_DEBUG: verbose debug (if compiled in)
+ * @L2TP_MSG_CONTROL: userspace - kernel interface
+ * @L2TP_MSG_SEQ: sequence numbers
+ * @L2TP_MSG_DATA: data packets
+ */
+enum l2tp_debug_flags {
+	L2TP_MSG_DEBUG		= (1 << 0),
+	L2TP_MSG_CONTROL	= (1 << 1),
+	L2TP_MSG_SEQ		= (1 << 2),
+	L2TP_MSG_DATA		= (1 << 3),
+};
+
 /*
  * NETLINK_GENERIC related info
  */
--- linux-4.4.0.orig/include/uapi/linux/libc-compat.h
+++ linux-4.4.0/include/uapi/linux/libc-compat.h
@@ -51,6 +51,40 @@
 /* We have included glibc headers... */
 #if defined(__GLIBC__)
 
+/* Coordinate with glibc net/if.h header. */
+#if defined(_NET_IF_H) && defined(__USE_MISC)
+
+/* GLIBC headers included first so don't define anything
+ * that would already be defined. */
+
+#define __UAPI_DEF_IF_IFCONF 0
+#define __UAPI_DEF_IF_IFMAP 0
+#define __UAPI_DEF_IF_IFNAMSIZ 0
+#define __UAPI_DEF_IF_IFREQ 0
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
+
+#else /* _NET_IF_H */
+
+/* Linux headers included first, and we must define everything
+ * we need. The expectation is that glibc will check the
+ * __UAPI_DEF_* defines and adjust appropriately. */
+
+#define __UAPI_DEF_IF_IFCONF 1
+#define __UAPI_DEF_IF_IFMAP 1
+#define __UAPI_DEF_IF_IFNAMSIZ 1
+#define __UAPI_DEF_IF_IFREQ 1
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+
+#endif /* _NET_IF_H */
+
 /* Coordinate with glibc netinet/in.h header. */
 #if defined(_NETINET_IN_H)
 
@@ -117,6 +151,16 @@
  * that we need. */
 #else /* !defined(__GLIBC__) */
 
+/* Definitions for if.h */
+#define __UAPI_DEF_IF_IFCONF 1
+#define __UAPI_DEF_IF_IFMAP 1
+#define __UAPI_DEF_IF_IFNAMSIZ 1
+#define __UAPI_DEF_IF_IFREQ 1
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+
 /* Definitions for in.h */
 #define __UAPI_DEF_IN_ADDR		1
 #define __UAPI_DEF_IN_IPPROTO		1
--- linux-4.4.0.orig/include/uapi/linux/lightnvm.h
+++ linux-4.4.0/include/uapi/linux/lightnvm.h
@@ -20,7 +20,7 @@
 #define _UAPI_LINUX_LIGHTNVM_H
 
 #ifdef __KERNEL__
-#include <linux/kernel.h>
+#include <linux/const.h>
 #include <linux/ioctl.h>
 #else /* __KERNEL__ */
 #include <stdio.h>
@@ -33,6 +33,7 @@
 
 #define NVM_TTYPE_NAME_MAX 48
 #define NVM_TTYPE_MAX 63
+#define NVM_MMTYPE_LEN 8
 
 #define NVM_CTRL_FILE "/dev/lightnvm/control"
 
@@ -100,6 +101,26 @@
 	__u32 flags;
 };
 
+struct nvm_ioctl_dev_init {
+	char dev[DISK_NAME_LEN];		/* open-channel SSD device */
+	char mmtype[NVM_MMTYPE_LEN];		/* register to media manager */
+
+	__u32 flags;
+};
+
+enum {
+	NVM_FACTORY_ERASE_ONLY_USER	= 1 << 0, /* erase only blocks used as
+						   * host blks or grown blks */
+	NVM_FACTORY_RESET_HOST_BLKS	= 1 << 1, /* remove host blk marks */
+	NVM_FACTORY_RESET_GRWN_BBLKS	= 1 << 2, /* remove grown blk marks */
+	NVM_FACTORY_NR_BITS		= 1 << 3, /* stops here */
+};
+
+struct nvm_ioctl_dev_factory {
+	char dev[DISK_NAME_LEN];
+
+	__u32 flags;
+};
 
 /* The ioctl type, 'L', 0x20 - 0x2F documented in ioctl-number.txt */
 enum {
@@ -110,6 +131,12 @@
 	/* device level cmds */
 	NVM_DEV_CREATE_CMD,
 	NVM_DEV_REMOVE_CMD,
+
+	/* Init a device to support LightNVM media managers */
+	NVM_DEV_INIT_CMD,
+
+	/* Factory reset device */
+	NVM_DEV_FACTORY_CMD,
 };
 
 #define NVM_IOCTL 'L' /* 0x4c */
@@ -122,6 +149,10 @@
 						struct nvm_ioctl_create)
 #define NVM_DEV_REMOVE		_IOW(NVM_IOCTL, NVM_DEV_REMOVE_CMD, \
 						struct nvm_ioctl_remove)
+#define NVM_DEV_INIT		_IOW(NVM_IOCTL, NVM_DEV_INIT_CMD, \
+						struct nvm_ioctl_dev_init)
+#define NVM_DEV_FACTORY		_IOW(NVM_IOCTL, NVM_DEV_FACTORY_CMD, \
+						struct nvm_ioctl_dev_factory)
 
 #define NVM_VERSION_MAJOR	1
 #define NVM_VERSION_MINOR	0
--- linux-4.4.0.orig/include/uapi/linux/mmc/ioctl.h
+++ linux-4.4.0/include/uapi/linux/mmc/ioctl.h
@@ -2,6 +2,7 @@
 #define LINUX_MMC_IOCTL_H
 
 #include <linux/types.h>
+#include <linux/major.h>
 
 struct mmc_ioc_cmd {
 	/* Implies direction of data.  true = write, false = read */
--- linux-4.4.0.orig/include/uapi/linux/mroute6.h
+++ linux-4.4.0/include/uapi/linux/mroute6.h
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/sockios.h>
+#include <linux/in6.h>		/* For struct sockaddr_in6. */
 
 /*
  *	Based on the MROUTING 3.5 defines primarily to keep
--- linux-4.4.0.orig/include/uapi/linux/msdos_fs.h
+++ linux-4.4.0/include/uapi/linux/msdos_fs.h
@@ -9,7 +9,9 @@
  * The MS-DOS filesystem constants/structures
  */
 
+#ifndef SECTOR_SIZE
 #define SECTOR_SIZE	512		/* sector size (bytes) */
+#endif
 #define SECTOR_BITS	9		/* log2(SECTOR_SIZE) */
 #define MSDOS_DPB	(MSDOS_DPS)	/* dir entries per block */
 #define MSDOS_DPB_BITS	4		/* log2(MSDOS_DPB) */
--- linux-4.4.0.orig/include/uapi/linux/netfilter/nf_tables.h
+++ linux-4.4.0/include/uapi/linux/netfilter/nf_tables.h
@@ -111,7 +111,7 @@
  * @NFTA_LIST_ELEM: list element (NLA_NESTED)
  */
 enum nft_list_attributes {
-	NFTA_LIST_UNPEC,
+	NFTA_LIST_UNSPEC,
 	NFTA_LIST_ELEM,
 	__NFTA_LIST_MAX
 };
--- linux-4.4.0.orig/include/uapi/linux/netfilter/nfnetlink_cthelper.h
+++ linux-4.4.0/include/uapi/linux/netfilter/nfnetlink_cthelper.h
@@ -4,7 +4,7 @@
 #define NFCT_HELPER_STATUS_DISABLED	0
 #define NFCT_HELPER_STATUS_ENABLED	1
 
-enum nfnl_acct_msg_types {
+enum nfnl_cthelper_msg_types {
 	NFNL_MSG_CTHELPER_NEW,
 	NFNL_MSG_CTHELPER_GET,
 	NFNL_MSG_CTHELPER_DEL,
--- linux-4.4.0.orig/include/uapi/linux/netfilter/x_tables.h
+++ linux-4.4.0/include/uapi/linux/netfilter/x_tables.h
@@ -1,6 +1,6 @@
 #ifndef _UAPI_X_TABLES_H
 #define _UAPI_X_TABLES_H
-#include <linux/kernel.h>
+#include <linux/const.h>
 #include <linux/types.h>
 
 #define XT_FUNCTION_MAXNAMELEN 30
--- linux-4.4.0.orig/include/uapi/linux/netfilter/xt_sctp.h
+++ linux-4.4.0/include/uapi/linux/netfilter/xt_sctp.h
@@ -40,19 +40,19 @@
 #define SCTP_CHUNKMAP_SET(chunkmap, type) 		\
 	do { 						\
 		(chunkmap)[type / bytes(__u32)] |= 	\
-			1 << (type % bytes(__u32));	\
+			1u << (type % bytes(__u32));	\
 	} while (0)
 
 #define SCTP_CHUNKMAP_CLEAR(chunkmap, type)		 	\
 	do {							\
 		(chunkmap)[type / bytes(__u32)] &= 		\
-			~(1 << (type % bytes(__u32)));	\
+			~(1u << (type % bytes(__u32)));	\
 	} while (0)
 
 #define SCTP_CHUNKMAP_IS_SET(chunkmap, type) 			\
 ({								\
 	((chunkmap)[type / bytes (__u32)] & 		\
-		(1 << (type % bytes (__u32)))) ? 1: 0;	\
+		(1u << (type % bytes (__u32)))) ? 1: 0;	\
 })
 
 #define SCTP_CHUNKMAP_RESET(chunkmap) \
--- linux-4.4.0.orig/include/uapi/linux/netlink.h
+++ linux-4.4.0/include/uapi/linux/netlink.h
@@ -1,7 +1,7 @@
 #ifndef _UAPI__LINUX_NETLINK_H
 #define _UAPI__LINUX_NETLINK_H
 
-#include <linux/kernel.h>
+#include <linux/const.h>
 #include <linux/socket.h> /* for __kernel_sa_family_t */
 #include <linux/types.h>
 
@@ -107,8 +107,10 @@
 #define NETLINK_PKTINFO			3
 #define NETLINK_BROADCAST_ERROR		4
 #define NETLINK_NO_ENOBUFS		5
+#ifndef __KERNEL__
 #define NETLINK_RX_RING			6
 #define NETLINK_TX_RING			7
+#endif
 #define NETLINK_LISTEN_ALL_NSID		8
 #define NETLINK_LIST_MEMBERSHIPS	9
 #define NETLINK_CAP_ACK			10
@@ -134,6 +136,7 @@
 	__u32		nm_gid;
 };
 
+#ifndef __KERNEL__
 enum nl_mmap_status {
 	NL_MMAP_STATUS_UNUSED,
 	NL_MMAP_STATUS_RESERVED,
@@ -145,6 +148,7 @@
 #define NL_MMAP_MSG_ALIGNMENT		NLMSG_ALIGNTO
 #define NL_MMAP_MSG_ALIGN(sz)		__ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
 #define NL_MMAP_HDRLEN			NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+#endif
 
 #define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
 
--- linux-4.4.0.orig/include/uapi/linux/netlink_diag.h
+++ linux-4.4.0/include/uapi/linux/netlink_diag.h
@@ -48,6 +48,8 @@
 
 #define NDIAG_SHOW_MEMINFO	0x00000001 /* show memory info of a socket */
 #define NDIAG_SHOW_GROUPS	0x00000002 /* show groups of a netlink socket */
+#ifndef __KERNEL__
 #define NDIAG_SHOW_RING_CFG	0x00000004 /* show ring configuration */
+#endif
 
 #endif
--- linux-4.4.0.orig/include/uapi/linux/nl80211.h
+++ linux-4.4.0/include/uapi/linux/nl80211.h
@@ -2195,6 +2195,8 @@
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
 #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
+#define NL80211_WIPHY_NAME_MAXLEN		64
+
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_HT_RATES		77
 #define NL80211_MAX_SUPP_REG_RULES		64
--- linux-4.4.0.orig/include/uapi/linux/packet_diag.h
+++ linux-4.4.0/include/uapi/linux/packet_diag.h
@@ -64,7 +64,7 @@
 	__u32	pdmc_count;
 	__u16	pdmc_type;
 	__u16	pdmc_alen;
-	__u8	pdmc_addr[MAX_ADDR_LEN];
+	__u8	pdmc_addr[32]; /* MAX_ADDR_LEN */
 };
 
 struct packet_diag_ring {
--- linux-4.4.0.orig/include/uapi/linux/pci_regs.h
+++ linux-4.4.0/include/uapi/linux/pci_regs.h
@@ -106,7 +106,7 @@
 #define PCI_SUBSYSTEM_ID	0x2e
 #define PCI_ROM_ADDRESS		0x30	/* Bits 31..11 are address, 10..1 reserved */
 #define  PCI_ROM_ADDRESS_ENABLE	0x01
-#define PCI_ROM_ADDRESS_MASK	(~0x7ffUL)
+#define PCI_ROM_ADDRESS_MASK	(~0x7ffU)
 
 #define PCI_CAPABILITY_LIST	0x34	/* Offset of first capability list entry */
 
--- linux-4.4.0.orig/include/uapi/linux/pkt_cls.h
+++ linux-4.4.0/include/uapi/linux/pkt_cls.h
@@ -421,6 +421,17 @@
 
 #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
 
+/* Match-all classifier */
+
+enum {
+	TCA_MATCHALL_UNSPEC,
+	TCA_MATCHALL_CLASSID,
+	TCA_MATCHALL_ACT,
+	__TCA_MATCHALL_MAX,
+};
+
+#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1)
+
 /* Extended Matches */
 
 struct tcf_ematch_tree_hdr {
--- linux-4.4.0.orig/include/uapi/linux/prctl.h
+++ linux-4.4.0/include/uapi/linux/prctl.h
@@ -197,4 +197,17 @@
 # define PR_CAP_AMBIENT_LOWER		3
 # define PR_CAP_AMBIENT_CLEAR_ALL	4
 
+/* Per task speculation control */
+#define PR_GET_SPECULATION_CTRL		52
+#define PR_SET_SPECULATION_CTRL		53
+/* Speculation control variants */
+# define PR_SPEC_STORE_BYPASS		0
+# define PR_SPEC_INDIRECT_BRANCH	1
+/* Return and control values for PR_SET/GET_SPECULATION_CTRL */
+# define PR_SPEC_NOT_AFFECTED		0
+# define PR_SPEC_PRCTL			(1UL << 0)
+# define PR_SPEC_ENABLE			(1UL << 1)
+# define PR_SPEC_DISABLE		(1UL << 2)
+# define PR_SPEC_FORCE_DISABLE		(1UL << 3)
+
 #endif /* _LINUX_PRCTL_H */
--- linux-4.4.0.orig/include/uapi/linux/ptp_clock.h
+++ linux-4.4.0/include/uapi/linux/ptp_clock.h
@@ -51,7 +51,9 @@
 	int n_per_out; /* Number of programmable periodic signals. */
 	int pps;       /* Whether the clock supports a PPS callback. */
 	int n_pins;    /* Number of input/output pins. */
-	int rsv[14];   /* Reserved for future use. */
+	/* Whether the clock supports precise system-device cross timestamps */
+	int cross_timestamping;
+	int rsv[13];   /* Reserved for future use. */
 };
 
 struct ptp_extts_request {
@@ -81,6 +83,13 @@
 	struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1];
 };
 
+struct ptp_sys_offset_precise {
+	struct ptp_clock_time device;
+	struct ptp_clock_time sys_realtime;
+	struct ptp_clock_time sys_monoraw;
+	unsigned int rsv[4];    /* Reserved for future use. */
+};
+
 enum ptp_pin_function {
 	PTP_PF_NONE,
 	PTP_PF_EXTTS,
@@ -124,6 +133,8 @@
 #define PTP_SYS_OFFSET     _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset)
 #define PTP_PIN_GETFUNC    _IOWR(PTP_CLK_MAGIC, 6, struct ptp_pin_desc)
 #define PTP_PIN_SETFUNC    _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc)
+#define PTP_SYS_OFFSET_PRECISE \
+	_IOWR(PTP_CLK_MAGIC, 8, struct ptp_sys_offset_precise)
 
 struct ptp_extts_event {
 	struct ptp_clock_time t; /* Time event occured. */
--- linux-4.4.0.orig/include/uapi/linux/raid/md_p.h
+++ linux-4.4.0/include/uapi/linux/raid/md_p.h
@@ -313,6 +313,7 @@
 					     */
 #define MD_FEATURE_CLUSTERED		256 /* clustered MD */
 #define	MD_FEATURE_JOURNAL		512 /* support write cache */
+#define MD_FEATURE_RAID0_LAYOUT		4096 /* layout is meaningful for RAID0 */
 #define	MD_FEATURE_ALL			(MD_FEATURE_BITMAP_OFFSET	\
 					|MD_FEATURE_RECOVERY_OFFSET	\
 					|MD_FEATURE_RESHAPE_ACTIVE	\
@@ -323,6 +324,7 @@
 					|MD_FEATURE_RECOVERY_BITMAP	\
 					|MD_FEATURE_CLUSTERED		\
 					|MD_FEATURE_JOURNAL		\
+					|MD_FEATURE_RAID0_LAYOUT	\
 					)
 
 struct r5l_payload_header {
--- linux-4.4.0.orig/include/uapi/linux/rds.h
+++ linux-4.4.0/include/uapi/linux/rds.h
@@ -35,6 +35,7 @@
 #define _LINUX_RDS_H
 
 #include <linux/types.h>
+#include <linux/socket.h>		/* For __kernel_sockaddr_storage. */
 
 #define RDS_IB_ABI_VERSION		0x301
 
@@ -103,8 +104,8 @@
 #define RDS_INFO_LAST			10010
 
 struct rds_info_counter {
-	uint8_t	name[32];
-	uint64_t	value;
+	__u8	name[32];
+	__u64	value;
 } __attribute__((packed));
 
 #define RDS_INFO_CONNECTION_FLAG_SENDING	0x01
@@ -114,35 +115,35 @@
 #define TRANSNAMSIZ	16
 
 struct rds_info_connection {
-	uint64_t	next_tx_seq;
-	uint64_t	next_rx_seq;
+	__u64		next_tx_seq;
+	__u64		next_rx_seq;
 	__be32		laddr;
 	__be32		faddr;
-	uint8_t	transport[TRANSNAMSIZ];		/* null term ascii */
-	uint8_t	flags;
+	__u8		transport[TRANSNAMSIZ];		/* null term ascii */
+	__u8		flags;
 } __attribute__((packed));
 
 #define RDS_INFO_MESSAGE_FLAG_ACK               0x01
 #define RDS_INFO_MESSAGE_FLAG_FAST_ACK          0x02
 
 struct rds_info_message {
-	uint64_t	seq;
-	uint32_t	len;
+	__u64		seq;
+	__u32		len;
 	__be32		laddr;
 	__be32		faddr;
 	__be16		lport;
 	__be16		fport;
-	uint8_t	flags;
+	__u8		flags;
 } __attribute__((packed));
 
 struct rds_info_socket {
-	uint32_t	sndbuf;
+	__u32		sndbuf;
 	__be32		bound_addr;
 	__be32		connected_addr;
 	__be16		bound_port;
 	__be16		connected_port;
-	uint32_t	rcvbuf;
-	uint64_t	inum;
+	__u32		rcvbuf;
+	__u64		inum;
 } __attribute__((packed));
 
 struct rds_info_tcp_socket {
@@ -150,25 +151,25 @@
 	__be16          local_port;
 	__be32          peer_addr;
 	__be16          peer_port;
-	uint64_t       hdr_rem;
-	uint64_t       data_rem;
-	uint32_t       last_sent_nxt;
-	uint32_t       last_expected_una;
-	uint32_t       last_seen_una;
+	__u64           hdr_rem;
+	__u64           data_rem;
+	__u32           last_sent_nxt;
+	__u32           last_expected_una;
+	__u32           last_seen_una;
 } __attribute__((packed));
 
 #define RDS_IB_GID_LEN	16
 struct rds_info_rdma_connection {
 	__be32		src_addr;
 	__be32		dst_addr;
-	uint8_t		src_gid[RDS_IB_GID_LEN];
-	uint8_t		dst_gid[RDS_IB_GID_LEN];
+	__u8		src_gid[RDS_IB_GID_LEN];
+	__u8		dst_gid[RDS_IB_GID_LEN];
 
-	uint32_t	max_send_wr;
-	uint32_t	max_recv_wr;
-	uint32_t	max_send_sge;
-	uint32_t	rdma_mr_max;
-	uint32_t	rdma_mr_size;
+	__u32		max_send_wr;
+	__u32		max_recv_wr;
+	__u32		max_send_sge;
+	__u32		rdma_mr_max;
+	__u32		rdma_mr_size;
 };
 
 /*
@@ -209,70 +210,70 @@
  * (so that the application does not have to worry about
  * alignment).
  */
-typedef uint64_t	rds_rdma_cookie_t;
+typedef __u64		rds_rdma_cookie_t;
 
 struct rds_iovec {
-	uint64_t	addr;
-	uint64_t	bytes;
+	__u64		addr;
+	__u64		bytes;
 };
 
 struct rds_get_mr_args {
 	struct rds_iovec vec;
-	uint64_t	cookie_addr;
-	uint64_t	flags;
+	__u64		cookie_addr;
+	__u64		flags;
 };
 
 struct rds_get_mr_for_dest_args {
-	struct sockaddr_storage	dest_addr;
+	struct __kernel_sockaddr_storage dest_addr;
 	struct rds_iovec 	vec;
-	uint64_t		cookie_addr;
-	uint64_t		flags;
+	__u64			cookie_addr;
+	__u64			flags;
 };
 
 struct rds_free_mr_args {
 	rds_rdma_cookie_t cookie;
-	uint64_t	flags;
+	__u64		flags;
 };
 
 struct rds_rdma_args {
 	rds_rdma_cookie_t cookie;
 	struct rds_iovec remote_vec;
-	uint64_t	local_vec_addr;
-	uint64_t	nr_local;
-	uint64_t	flags;
-	uint64_t	user_token;
+	__u64		local_vec_addr;
+	__u64		nr_local;
+	__u64		flags;
+	__u64		user_token;
 };
 
 struct rds_atomic_args {
 	rds_rdma_cookie_t cookie;
-	uint64_t 	local_addr;
-	uint64_t 	remote_addr;
+	__u64		local_addr;
+	__u64		remote_addr;
 	union {
 		struct {
-			uint64_t	compare;
-			uint64_t	swap;
+			__u64		compare;
+			__u64		swap;
 		} cswp;
 		struct {
-			uint64_t	add;
+			__u64		add;
 		} fadd;
 		struct {
-			uint64_t	compare;
-			uint64_t	swap;
-			uint64_t	compare_mask;
-			uint64_t	swap_mask;
+			__u64		compare;
+			__u64		swap;
+			__u64		compare_mask;
+			__u64		swap_mask;
 		} m_cswp;
 		struct {
-			uint64_t	add;
-			uint64_t	nocarry_mask;
+			__u64		add;
+			__u64		nocarry_mask;
 		} m_fadd;
 	};
-	uint64_t	flags;
-	uint64_t	user_token;
+	__u64		flags;
+	__u64		user_token;
 };
 
 struct rds_rdma_notify {
-	uint64_t	user_token;
-	int32_t		status;
+	__u64		user_token;
+	__s32		status;
 };
 
 #define RDS_RDMA_SUCCESS	0
--- linux-4.4.0.orig/include/uapi/linux/rtnetlink.h
+++ linux-4.4.0/include/uapi/linux/rtnetlink.h
@@ -343,7 +343,7 @@
 #define RTNH_F_OFFLOAD		8	/* offloaded route */
 #define RTNH_F_LINKDOWN		16	/* carrier-down on nexthop */
 
-#define RTNH_COMPARE_MASK	(RTNH_F_DEAD | RTNH_F_LINKDOWN)
+#define RTNH_COMPARE_MASK	(RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD)
 
 /* Macros to handle hexthops */
 
--- linux-4.4.0.orig/include/uapi/linux/sched.h
+++ linux-4.4.0/include/uapi/linux/sched.h
@@ -21,8 +21,7 @@
 #define CLONE_DETACHED		0x00400000	/* Unused, ignored */
 #define CLONE_UNTRACED		0x00800000	/* set if the tracing process can't force CLONE_PTRACE on this clone */
 #define CLONE_CHILD_SETTID	0x01000000	/* set the TID in the child */
-/* 0x02000000 was previously the unused CLONE_STOPPED (Start in stopped state)
-   and is now available for re-use. */
+#define CLONE_NEWCGROUP		0x02000000	/* New cgroup namespace */
 #define CLONE_NEWUTS		0x04000000	/* New utsname namespace */
 #define CLONE_NEWIPC		0x08000000	/* New ipc namespace */
 #define CLONE_NEWUSER		0x10000000	/* New user namespace */
--- linux-4.4.0.orig/include/uapi/linux/seccomp.h
+++ linux-4.4.0/include/uapi/linux/seccomp.h
@@ -11,11 +11,14 @@
 #define SECCOMP_MODE_FILTER	2 /* uses user-supplied filter. */
 
 /* Valid operations for seccomp syscall. */
-#define SECCOMP_SET_MODE_STRICT	0
-#define SECCOMP_SET_MODE_FILTER	1
+#define SECCOMP_SET_MODE_STRICT		0
+#define SECCOMP_SET_MODE_FILTER		1
+#define SECCOMP_GET_ACTION_AVAIL	2
 
 /* Valid flags for SECCOMP_SET_MODE_FILTER */
-#define SECCOMP_FILTER_FLAG_TSYNC	1
+#define SECCOMP_FILTER_FLAG_TSYNC	(1UL << 0)
+#define SECCOMP_FILTER_FLAG_LOG		(1UL << 1)
+#define SECCOMP_FILTER_FLAG_SPEC_ALLOW	(1UL << 2)
 
 /*
  * All BPF programs must return a 32-bit value.
@@ -29,6 +32,7 @@
 #define SECCOMP_RET_TRAP	0x00030000U /* disallow and force a SIGSYS */
 #define SECCOMP_RET_ERRNO	0x00050000U /* returns an errno */
 #define SECCOMP_RET_TRACE	0x7ff00000U /* pass to a tracer or disallow */
+#define SECCOMP_RET_LOG		0x7ffc0000U /* allow after logging */
 #define SECCOMP_RET_ALLOW	0x7fff0000U /* allow */
 
 /* Masks for the return value sections. */
--- linux-4.4.0.orig/include/uapi/linux/snmp.h
+++ linux-4.4.0/include/uapi/linux/snmp.h
@@ -55,6 +55,7 @@
 	IPSTATS_MIB_ECT1PKTS,			/* InECT1Pkts */
 	IPSTATS_MIB_ECT0PKTS,			/* InECT0Pkts */
 	IPSTATS_MIB_CEPKTS,			/* InCEPkts */
+	IPSTATS_MIB_REASM_OVERLAPS,		/* ReasmOverlaps */
 	__IPSTATS_MIB_MAX
 };
 
@@ -280,6 +281,7 @@
 	LINUX_MIB_TCPKEEPALIVE,			/* TCPKeepAlive */
 	LINUX_MIB_TCPMTUPFAIL,			/* TCPMTUPFail */
 	LINUX_MIB_TCPMTUPSUCCESS,		/* TCPMTUPSuccess */
+	LINUX_MIB_TCPWQUEUETOOBIG,		/* TCPWqueueTooBig */
 	__LINUX_MIB_MAX
 };
 
--- linux-4.4.0.orig/include/uapi/linux/spi/spidev.h
+++ linux-4.4.0/include/uapi/linux/spi/spidev.h
@@ -23,6 +23,7 @@
 #define SPIDEV_H
 
 #include <linux/types.h>
+#include <linux/ioctl.h>
 
 /* User space versions of kernel symbols for SPI clocking modes,
  * matching <linux/spi/spi.h>
--- linux-4.4.0.orig/include/uapi/linux/sysctl.h
+++ linux-4.4.0/include/uapi/linux/sysctl.h
@@ -22,7 +22,7 @@
 #ifndef _UAPI_LINUX_SYSCTL_H
 #define _UAPI_LINUX_SYSCTL_H
 
-#include <linux/kernel.h>
+#include <linux/const.h>
 #include <linux/types.h>
 #include <linux/compiler.h>
 
--- linux-4.4.0.orig/include/uapi/linux/tipc_config.h
+++ linux-4.4.0/include/uapi/linux/tipc_config.h
@@ -301,8 +301,10 @@
 	tlv_ptr = (struct tlv_desc *)tlv;
 	tlv_ptr->tlv_type = htons(type);
 	tlv_ptr->tlv_len  = htons(tlv_len);
-	if (len && data)
-		memcpy(TLV_DATA(tlv_ptr), data, tlv_len);
+	if (len && data) {
+		memcpy(TLV_DATA(tlv_ptr), data, len);
+		memset(TLV_DATA(tlv_ptr) + len, 0, TLV_SPACE(len) - tlv_len);
+	}
 	return TLV_SPACE(len);
 }
 
@@ -399,8 +401,10 @@
 	tcm_hdr->tcm_len   = htonl(msg_len);
 	tcm_hdr->tcm_type  = htons(cmd);
 	tcm_hdr->tcm_flags = htons(flags);
-	if (data_len && data)
+	if (data_len && data) {
 		memcpy(TCM_DATA(msg), data, data_len);
+		memset(TCM_DATA(msg) + data_len, 0, TCM_SPACE(data_len) - msg_len);
+	}
 	return TCM_SPACE(data_len);
 }
 
--- linux-4.4.0.orig/include/uapi/linux/usb/audio.h
+++ linux-4.4.0/include/uapi/linux/usb/audio.h
@@ -369,7 +369,7 @@
 {
 	return (protocol == UAC_VERSION_1) ?
 		desc->baSourceID[desc->bNrInPins + 4] :
-		desc->baSourceID[desc->bNrInPins + 6];
+		2; /* in UAC2, this value is constant */
 }
 
 static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc,
@@ -377,7 +377,7 @@
 {
 	return (protocol == UAC_VERSION_1) ?
 		&desc->baSourceID[desc->bNrInPins + 5] :
-		&desc->baSourceID[desc->bNrInPins + 7];
+		&desc->baSourceID[desc->bNrInPins + 6];
 }
 
 static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc,
--- linux-4.4.0.orig/include/uapi/linux/usb/ch11.h
+++ linux-4.4.0/include/uapi/linux/usb/ch11.h
@@ -22,6 +22,9 @@
  */
 #define USB_MAXCHILDREN		31
 
+/* See USB 3.1 spec Table 10-5 */
+#define USB_SS_MAXPORTS		15
+
 /*
  * Hub request types
  */
@@ -30,6 +33,14 @@
 #define USB_RT_PORT	(USB_TYPE_CLASS | USB_RECIP_OTHER)
 
 /*
+ * Port status type for GetPortStatus requests added in USB 3.1
+ * See USB 3.1 spec Table 10-12
+ */
+#define HUB_PORT_STATUS		0
+#define HUB_PORT_PD_STATUS	1
+#define HUB_EXT_PORT_STATUS	2
+
+/*
  * Hub class requests
  * See USB 2.0 spec Table 11-16
  */
@@ -97,10 +108,13 @@
 /*
  * Hub Status and Hub Change results
  * See USB 2.0 spec Table 11-19 and Table 11-20
+ * USB 3.1 extends the port status request and may return 4 additional bytes.
+ * See USB 3.1 spec section 10.16.2.6 Table 10-12 and 10-15
  */
 struct usb_port_status {
 	__le16 wPortStatus;
 	__le16 wPortChange;
+	__le32 dwExtPortStatus;
 } __attribute__ ((packed));
 
 /*
@@ -173,6 +187,16 @@
 #define USB_PORT_STAT_C_CONFIG_ERROR	0x0080
 
 /*
+ * USB 3.1 dwExtPortStatus field masks
+ * See USB 3.1 spec 10.16.2.6.3 Table 10-15
+ */
+
+#define USB_EXT_PORT_STAT_RX_SPEED_ID	0x0000000f
+#define USB_EXT_PORT_STAT_TX_SPEED_ID	0x000000f0
+#define USB_EXT_PORT_STAT_RX_LANES	0x00000f00
+#define USB_EXT_PORT_STAT_TX_LANES	0x0000f000
+
+/*
  * wHubCharacteristics (masks)
  * See USB 2.0 spec Table 11-13, offset 3
  */
--- linux-4.4.0.orig/include/uapi/linux/usb/ch9.h
+++ linux-4.4.0/include/uapi/linux/usb/ch9.h
@@ -234,6 +234,8 @@
 #define USB_DT_PIPE_USAGE		0x24
 /* From the USB 3.0 spec */
 #define	USB_DT_SS_ENDPOINT_COMP		0x30
+/* From the USB 3.1 spec */
+#define	USB_DT_SSP_ISOC_ENDPOINT_COMP	0x31
 
 /* Conventional codes for class-specific descriptors.  The convention is
  * defined in the USB "Common Class" Spec (3.11).  Individual class specs
@@ -613,6 +615,20 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* USB_DT_SSP_ISOC_ENDPOINT_COMP: SuperSpeedPlus Isochronous Endpoint Companion
+ * descriptor
+ */
+struct usb_ssp_isoc_ep_comp_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__le16 wReseved;
+	__le32 dwBytesPerInterval;
+} __attribute__ ((packed));
+
+#define USB_DT_SSP_ISOC_EP_COMP_SIZE		8
+
+/*-------------------------------------------------------------------------*/
+
 /* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
 struct usb_ss_ep_comp_descriptor {
 	__u8  bLength;
@@ -646,6 +662,8 @@
 
 /* Bits 1:0 of bmAttributes if this is an isoc endpoint */
 #define USB_SS_MULT(p)			(1 + ((p) & 0x3))
+/* Bit 7 of bmAttributes if a SSP isoc endpoint companion descriptor exists */
+#define USB_SS_SSP_ISOC_COMP(p)		((p) & (1 << 7))
 
 /*-------------------------------------------------------------------------*/
 
@@ -717,6 +735,7 @@
 	__u8  iFunction;
 } __attribute__ ((packed));
 
+#define USB_DT_INTERFACE_ASSOCIATION_SIZE	8
 
 /*-------------------------------------------------------------------------*/
 
@@ -811,6 +830,8 @@
 	__u8  bReserved;
 } __attribute__((packed));
 
+#define USB_DT_USB_WIRELESS_CAP_SIZE	11
+
 /* USB 2.0 Extension descriptor */
 #define	USB_CAP_TYPE_EXT		2
 
@@ -894,6 +915,22 @@
 #define USB_SSP_SUBLINK_SPEED_LSM	(0xff << 16)	/* Lanespeed mantissa */
 } __attribute__((packed));
 
+/*
+ * Precision time measurement capability descriptor: advertised by devices and
+ * hubs that support PTM
+ */
+#define	USB_PTM_CAP_TYPE	0xb
+struct usb_ptm_cap_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDevCapabilityType;
+} __attribute__((packed));
+
+/*
+ * The size of the descriptor for the Sublink Speed Attribute Count
+ * (SSAC) specified in bmAttributes[4:0].
+ */
+#define USB_DT_USB_SSP_CAP_SIZE(ssac)	(16 + ssac * 4)
 
 /*-------------------------------------------------------------------------*/
 
@@ -954,6 +991,7 @@
 	USB_SPEED_HIGH,				/* usb 2.0 */
 	USB_SPEED_WIRELESS,			/* wireless (usb 2.5) */
 	USB_SPEED_SUPER,			/* usb 3.0 */
+	USB_SPEED_SUPER_PLUS,			/* usb 3.1 */
 };
 
 
@@ -989,6 +1027,7 @@
 	USB3_LPM_U3
 };
 
+#define USB_DT_USB_PTM_ID_SIZE		3
 /*
  * A U1 timeout of 0x0 means the parent hub will reject any transitions to U1.
  * 0xff means the parent hub will accept transitions to U1, but will not
--- linux-4.4.0.orig/include/uapi/linux/usb/video.h
+++ linux-4.4.0/include/uapi/linux/usb/video.h
@@ -28,6 +28,7 @@
 
 /* A.3. Video Interface Protocol Codes */
 #define UVC_PC_PROTOCOL_UNDEFINED			0x00
+#define UVC_PC_PROTOCOL_15				0x01
 
 /* A.5. Video Class-Specific VC Interface Descriptor Subtypes */
 #define UVC_VC_DESCRIPTOR_UNDEFINED			0x00
--- linux-4.4.0.orig/include/uapi/linux/v4l2-dv-timings.h
+++ linux-4.4.0/include/uapi/linux/v4l2-dv-timings.h
@@ -183,7 +183,8 @@
 
 #define V4L2_DV_BT_CEA_3840X2160P24 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		297000000, 1276, 88, 296, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, \
 		V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
@@ -191,14 +192,16 @@
 
 #define V4L2_DV_BT_CEA_3840X2160P25 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		297000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \
 }
 
 #define V4L2_DV_BT_CEA_3840X2160P30 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		297000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, \
 		V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
@@ -206,14 +209,16 @@
 
 #define V4L2_DV_BT_CEA_3840X2160P50 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		594000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \
 }
 
 #define V4L2_DV_BT_CEA_3840X2160P60 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		594000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, \
 		V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
@@ -221,7 +226,8 @@
 
 #define V4L2_DV_BT_CEA_4096X2160P24 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		297000000, 1020, 88, 296, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, \
 		V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
@@ -229,14 +235,16 @@
 
 #define V4L2_DV_BT_CEA_4096X2160P25 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		297000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \
 }
 
 #define V4L2_DV_BT_CEA_4096X2160P30 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		297000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, \
 		V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
@@ -244,14 +252,16 @@
 
 #define V4L2_DV_BT_CEA_4096X2160P50 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		594000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \
 }
 
 #define V4L2_DV_BT_CEA_4096X2160P60 { \
 	.type = V4L2_DV_BT_656_1120, \
-	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+	V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+		V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
 		594000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \
 		V4L2_DV_BT_STD_CEA861, \
 		V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
--- linux-4.4.0.orig/include/uapi/linux/videodev2.h
+++ linux-4.4.0/include/uapi/linux/videodev2.h
@@ -621,6 +621,9 @@
 #define V4L2_PIX_FMT_JPGL	v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */
 #define V4L2_PIX_FMT_SE401      v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */
 #define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */
+#define V4L2_PIX_FMT_Y8I      v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */
+#define V4L2_PIX_FMT_Y12I     v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */
+#define V4L2_PIX_FMT_Z16      v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
 
 /* SDR formats - used only for Software Defined Radio devices */
 #define V4L2_SDR_FMT_CU8          v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
--- linux-4.4.0.orig/include/uapi/linux/virtio_balloon.h
+++ linux-4.4.0/include/uapi/linux/virtio_balloon.h
@@ -51,7 +51,8 @@
 #define VIRTIO_BALLOON_S_MINFLT   3   /* Number of minor faults */
 #define VIRTIO_BALLOON_S_MEMFREE  4   /* Total amount of free memory */
 #define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
-#define VIRTIO_BALLOON_S_NR       6
+#define VIRTIO_BALLOON_S_AVAIL    6   /* Available memory as in /proc */
+#define VIRTIO_BALLOON_S_NR       7
 
 /*
  * Memory statistics structure.
--- linux-4.4.0.orig/include/uapi/misc/cxl.h
+++ linux-4.4.0/include/uapi/misc/cxl.h
@@ -55,11 +55,35 @@
 	__u64 reserved6;
 };
 
+/* base adapter image header is included in the image */
+#define CXL_AI_NEED_HEADER	0x0000000000000001ULL
+#define CXL_AI_ALL		CXL_AI_NEED_HEADER
+
+#define CXL_AI_HEADER_SIZE 128
+#define CXL_AI_BUFFER_SIZE 4096
+#define CXL_AI_MAX_ENTRIES 256
+#define CXL_AI_MAX_CHUNK_SIZE (CXL_AI_BUFFER_SIZE * CXL_AI_MAX_ENTRIES)
+
+struct cxl_adapter_image {
+	__u64 flags;
+	__u64 data;
+	__u64 len_data;
+	__u64 len_image;
+	__u64 reserved1;
+	__u64 reserved2;
+	__u64 reserved3;
+	__u64 reserved4;
+};
+
 /* ioctl numbers */
 #define CXL_MAGIC 0xCA
+/* AFU devices */
 #define CXL_IOCTL_START_WORK		_IOW(CXL_MAGIC, 0x00, struct cxl_ioctl_start_work)
 #define CXL_IOCTL_GET_PROCESS_ELEMENT	_IOR(CXL_MAGIC, 0x01, __u32)
 #define CXL_IOCTL_GET_AFU_ID            _IOR(CXL_MAGIC, 0x02, struct cxl_afu_id)
+/* adapter devices */
+#define CXL_IOCTL_DOWNLOAD_IMAGE        _IOW(CXL_MAGIC, 0x0A, struct cxl_adapter_image)
+#define CXL_IOCTL_VALIDATE_IMAGE        _IOW(CXL_MAGIC, 0x0B, struct cxl_adapter_image)
 
 #define CXL_READ_MIN_SIZE 0x1000 /* 4K */
 
--- linux-4.4.0.orig/include/uapi/scsi/cxlflash_ioctl.h
+++ linux-4.4.0/include/uapi/scsi/cxlflash_ioctl.h
@@ -31,6 +31,16 @@
 };
 
 /*
+ * Return flag definitions available to all ioctls
+ *
+ * Similar to the input flags, these are grown from the bottom-up with the
+ * intention that ioctl-specific return flag definitions would grow from the
+ * top-down, allowing the two sets to co-exist. While not required/enforced
+ * at this time, this provides future flexibility.
+ */
+#define DK_CXLFLASH_ALL_PORTS_ACTIVE	0x0000000000000001ULL
+
+/*
  * Notes:
  * -----
  * The 'context_id' field of all ioctl structures contains the context
--- linux-4.4.0.orig/include/video/imx-ipu-v3.h
+++ linux-4.4.0/include/video/imx-ipu-v3.h
@@ -16,6 +16,7 @@
 #include <linux/videodev2.h>
 #include <linux/bitmap.h>
 #include <linux/fb.h>
+#include <linux/of.h>
 #include <media/v4l2-mediabus.h>
 #include <video/videomode.h>
 
@@ -344,6 +345,7 @@
 	int dc;
 	int dp;
 	int dma[2];
+	struct device_node *of_node;
 };
 
 #endif /* __DRM_IPU_H__ */
--- linux-4.4.0.orig/include/video/udlfb.h
+++ linux-4.4.0/include/video/udlfb.h
@@ -87,7 +87,7 @@
 #define MIN_RAW_PIX_BYTES	2
 #define MIN_RAW_CMD_BYTES	(RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
 
-#define DL_DEFIO_WRITE_DELAY    5 /* fb_deferred_io.delay in jiffies */
+#define DL_DEFIO_WRITE_DELAY    msecs_to_jiffies(HZ <= 300 ? 4 : 10) /* optimal value for 720p video */
 #define DL_DEFIO_WRITE_DISABLE  (HZ*60) /* "disable" with long delay */
 
 /* remove these once align.h patch is taken into kernel */
--- linux-4.4.0.orig/include/xen/events.h
+++ linux-4.4.0/include/xen/events.h
@@ -12,11 +12,16 @@
 
 unsigned xen_evtchn_nr_channels(void);
 
-int bind_evtchn_to_irq(unsigned int evtchn);
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
+int bind_evtchn_to_irq(evtchn_port_t evtchn);
+int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn);
+int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
 			      irq_handler_t handler,
 			      unsigned long irqflags, const char *devname,
 			      void *dev_id);
+int bind_evtchn_to_irqhandler_lateeoi(evtchn_port_t evtchn,
+				      irq_handler_t handler,
+				      unsigned long irqflags, const char *devname,
+				      void *dev_id);
 int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu);
 int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
 			    irq_handler_t handler,
@@ -29,13 +34,21 @@
 			   const char *devname,
 			   void *dev_id);
 int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-				   unsigned int remote_port);
+				   evtchn_port_t remote_port);
+int bind_interdomain_evtchn_to_irq_lateeoi(unsigned int remote_domain,
+					   evtchn_port_t remote_port);
 int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-					  unsigned int remote_port,
+					  evtchn_port_t remote_port,
 					  irq_handler_t handler,
 					  unsigned long irqflags,
 					  const char *devname,
 					  void *dev_id);
+int bind_interdomain_evtchn_to_irqhandler_lateeoi(unsigned int remote_domain,
+						  evtchn_port_t remote_port,
+						  irq_handler_t handler,
+						  unsigned long irqflags,
+						  const char *devname,
+						  void *dev_id);
 
 /*
  * Common unbind function for all event sources. Takes IRQ to unbind from.
@@ -44,6 +57,14 @@
  */
 void unbind_from_irqhandler(unsigned int irq, void *dev_id);
 
+/*
+ * Send late EOI for an IRQ bound to an event channel via one of the *_lateeoi
+ * functions above.
+ */
+void xen_irq_lateeoi(unsigned int irq, unsigned int eoi_flags);
+/* Signal an event was spurious, i.e. there was no action resulting from it. */
+#define XEN_EOI_FLAG_SPURIOUS	0x00000001
+
 #define XEN_IRQ_PRIORITY_MAX     EVTCHN_FIFO_PRIORITY_MAX
 #define XEN_IRQ_PRIORITY_DEFAULT EVTCHN_FIFO_PRIORITY_DEFAULT
 #define XEN_IRQ_PRIORITY_MIN     EVTCHN_FIFO_PRIORITY_MIN
--- linux-4.4.0.orig/include/xen/grant_table.h
+++ linux-4.4.0/include/xen/grant_table.h
@@ -97,10 +97,27 @@
  * access has been ended, free the given page too.  Access will be ended
  * immediately iff the grant entry is not in use, otherwise it will happen
  * some time later.  page may be 0, in which case no freeing will occur.
+ * Note that the granted page might still be accessed (read or write) by the
+ * other side after gnttab_end_foreign_access() returns, so even if page was
+ * specified as 0 it is not allowed to just reuse the page for other
+ * purposes immediately. gnttab_end_foreign_access() will take an additional
+ * reference to the granted page in this case, which is dropped only after
+ * the grant is no longer in use.
+ * This requires that multi page allocations for areas subject to
+ * gnttab_end_foreign_access() are done via alloc_pages_exact() (and freeing
+ * via free_pages_exact()) in order to avoid high order pages.
  */
 void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
 			       unsigned long page);
 
+/*
+ * End access through the given grant reference, iff the grant entry is
+ * no longer in use.  In case of success ending foreign access, the
+ * grant reference is deallocated.
+ * Return 1 if the grant entry was freed, 0 if it is still in use.
+ */
+int gnttab_try_end_foreign_access(grant_ref_t ref);
+
 int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
 
 unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
@@ -157,6 +174,7 @@
 	map->flags = flags;
 	map->ref = ref;
 	map->dom = domid;
+	map->status = 1; /* arbitrary positive value */
 }
 
 static inline void
--- linux-4.4.0.orig/include/xen/interface/io/ring.h
+++ linux-4.4.0/include/xen/interface/io/ring.h
@@ -24,82 +24,79 @@
  * A ring contains as many entries as will fit, rounded down to the nearest
  * power of two (so we can mask with (size-1) to loop around).
  */
-#define __CONST_RING_SIZE(_s, _sz)				\
-	(__RD32(((_sz) - offsetof(struct _s##_sring, ring)) /	\
-		sizeof(((struct _s##_sring *)0)->ring[0])))
-
+#define __CONST_RING_SIZE(_s, _sz) \
+    (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \
+	    sizeof(((struct _s##_sring *)0)->ring[0])))
 /*
  * The same for passing in an actual pointer instead of a name tag.
  */
-#define __RING_SIZE(_s, _sz)						\
-	(__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
+#define __RING_SIZE(_s, _sz) \
+    (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
 
 /*
  * Macros to make the correct C datatypes for a new kind of ring.
  *
  * To make a new ring datatype, you need to have two message structures,
- * let's say struct request, and struct response already defined.
+ * let's say request_t, and response_t already defined.
  *
  * In a header where you want the ring datatype declared, you then do:
  *
- *     DEFINE_RING_TYPES(mytag, struct request, struct response);
+ *     DEFINE_RING_TYPES(mytag, request_t, response_t);
  *
  * These expand out to give you a set of types, as you can see below.
  * The most important of these are:
  *
- *     struct mytag_sring      - The shared ring.
- *     struct mytag_front_ring - The 'front' half of the ring.
- *     struct mytag_back_ring  - The 'back' half of the ring.
+ *     mytag_sring_t      - The shared ring.
+ *     mytag_front_ring_t - The 'front' half of the ring.
+ *     mytag_back_ring_t  - The 'back' half of the ring.
  *
  * To initialize a ring in your code you need to know the location and size
  * of the shared memory area (PAGE_SIZE, for instance). To initialise
  * the front half:
  *
- *     struct mytag_front_ring front_ring;
- *     SHARED_RING_INIT((struct mytag_sring *)shared_page);
- *     FRONT_RING_INIT(&front_ring, (struct mytag_sring *)shared_page,
- *		       PAGE_SIZE);
+ *     mytag_front_ring_t front_ring;
+ *     SHARED_RING_INIT((mytag_sring_t *)shared_page);
+ *     FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
  *
  * Initializing the back follows similarly (note that only the front
  * initializes the shared ring):
  *
- *     struct mytag_back_ring back_ring;
- *     BACK_RING_INIT(&back_ring, (struct mytag_sring *)shared_page,
- *		      PAGE_SIZE);
+ *     mytag_back_ring_t back_ring;
+ *     BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
  */
 
-#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t)			\
-									\
-/* Shared ring entry */							\
-union __name##_sring_entry {						\
-    __req_t req;							\
-    __rsp_t rsp;							\
-};									\
-									\
-/* Shared ring page */							\
-struct __name##_sring {							\
-    RING_IDX req_prod, req_event;					\
-    RING_IDX rsp_prod, rsp_event;					\
-    uint8_t  pad[48];							\
-    union __name##_sring_entry ring[1]; /* variable-length */		\
-};									\
-									\
-/* "Front" end's private variables */					\
-struct __name##_front_ring {						\
-    RING_IDX req_prod_pvt;						\
-    RING_IDX rsp_cons;							\
-    unsigned int nr_ents;						\
-    struct __name##_sring *sring;					\
-};									\
-									\
-/* "Back" end's private variables */					\
-struct __name##_back_ring {						\
-    RING_IDX rsp_prod_pvt;						\
-    RING_IDX req_cons;							\
-    unsigned int nr_ents;						\
-    struct __name##_sring *sring;					\
-};
-
+#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t)                     \
+                                                                        \
+/* Shared ring entry */                                                 \
+union __name##_sring_entry {                                            \
+    __req_t req;                                                        \
+    __rsp_t rsp;                                                        \
+};                                                                      \
+                                                                        \
+/* Shared ring page */                                                  \
+struct __name##_sring {                                                 \
+    RING_IDX req_prod, req_event;                                       \
+    RING_IDX rsp_prod, rsp_event;                                       \
+    uint8_t __pad[48];                                                  \
+    union __name##_sring_entry ring[1]; /* variable-length */           \
+};                                                                      \
+                                                                        \
+/* "Front" end's private variables */                                   \
+struct __name##_front_ring {                                            \
+    RING_IDX req_prod_pvt;                                              \
+    RING_IDX rsp_cons;                                                  \
+    unsigned int nr_ents;                                               \
+    struct __name##_sring *sring;                                       \
+};                                                                      \
+                                                                        \
+/* "Back" end's private variables */                                    \
+struct __name##_back_ring {                                             \
+    RING_IDX rsp_prod_pvt;                                              \
+    RING_IDX req_cons;                                                  \
+    unsigned int nr_ents;                                               \
+    struct __name##_sring *sring;                                       \
+};                                                                      \
+                                                                        \
 /*
  * Macros for manipulating rings.
  *
@@ -116,105 +113,99 @@
  */
 
 /* Initialising empty rings */
-#define SHARED_RING_INIT(_s) do {					\
-    (_s)->req_prod  = (_s)->rsp_prod  = 0;				\
-    (_s)->req_event = (_s)->rsp_event = 1;				\
-    memset((_s)->pad, 0, sizeof((_s)->pad));				\
+#define SHARED_RING_INIT(_s) do {                                       \
+    (_s)->req_prod  = (_s)->rsp_prod  = 0;                              \
+    (_s)->req_event = (_s)->rsp_event = 1;                              \
+    (void)memset((_s)->__pad, 0, sizeof((_s)->__pad));                  \
 } while(0)
 
-#define FRONT_RING_INIT(_r, _s, __size) do {				\
-    (_r)->req_prod_pvt = 0;						\
-    (_r)->rsp_cons = 0;							\
-    (_r)->nr_ents = __RING_SIZE(_s, __size);				\
-    (_r)->sring = (_s);							\
+#define FRONT_RING_ATTACH(_r, _s, _i, __size) do {                      \
+    (_r)->req_prod_pvt = (_i);                                          \
+    (_r)->rsp_cons = (_i);                                              \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                            \
+    (_r)->sring = (_s);                                                 \
 } while (0)
 
-#define BACK_RING_INIT(_r, _s, __size) do {				\
-    (_r)->rsp_prod_pvt = 0;						\
-    (_r)->req_cons = 0;							\
-    (_r)->nr_ents = __RING_SIZE(_s, __size);				\
-    (_r)->sring = (_s);							\
-} while (0)
+#define FRONT_RING_INIT(_r, _s, __size) FRONT_RING_ATTACH(_r, _s, 0, __size)
 
-/* Initialize to existing shared indexes -- for recovery */
-#define FRONT_RING_ATTACH(_r, _s, __size) do {				\
-    (_r)->sring = (_s);							\
-    (_r)->req_prod_pvt = (_s)->req_prod;				\
-    (_r)->rsp_cons = (_s)->rsp_prod;					\
-    (_r)->nr_ents = __RING_SIZE(_s, __size);				\
+#define BACK_RING_ATTACH(_r, _s, _i, __size) do {                       \
+    (_r)->rsp_prod_pvt = (_i);                                          \
+    (_r)->req_cons = (_i);                                              \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                            \
+    (_r)->sring = (_s);                                                 \
 } while (0)
 
-#define BACK_RING_ATTACH(_r, _s, __size) do {				\
-    (_r)->sring = (_s);							\
-    (_r)->rsp_prod_pvt = (_s)->rsp_prod;				\
-    (_r)->req_cons = (_s)->req_prod;					\
-    (_r)->nr_ents = __RING_SIZE(_s, __size);				\
-} while (0)
+#define BACK_RING_INIT(_r, _s, __size) BACK_RING_ATTACH(_r, _s, 0, __size)
 
 /* How big is this ring? */
-#define RING_SIZE(_r)							\
+#define RING_SIZE(_r)                                                   \
     ((_r)->nr_ents)
 
 /* Number of free requests (for use on front side only). */
-#define RING_FREE_REQUESTS(_r)						\
+#define RING_FREE_REQUESTS(_r)                                          \
     (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons))
 
 /* Test if there is an empty slot available on the front ring.
  * (This is only meaningful from the front. )
  */
-#define RING_FULL(_r)							\
+#define RING_FULL(_r)                                                   \
     (RING_FREE_REQUESTS(_r) == 0)
 
 /* Test if there are outstanding messages to be processed on a ring. */
-#define RING_HAS_UNCONSUMED_RESPONSES(_r)				\
+#define RING_HAS_UNCONSUMED_RESPONSES(_r)                               \
     ((_r)->sring->rsp_prod - (_r)->rsp_cons)
 
-#define RING_HAS_UNCONSUMED_REQUESTS(_r)				\
-    ({									\
-	unsigned int req = (_r)->sring->req_prod - (_r)->req_cons;	\
-	unsigned int rsp = RING_SIZE(_r) -				\
-			   ((_r)->req_cons - (_r)->rsp_prod_pvt);	\
-	req < rsp ? req : rsp;						\
-    })
+#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({                             \
+    unsigned int req = (_r)->sring->req_prod - (_r)->req_cons;          \
+    unsigned int rsp = RING_SIZE(_r) -                                  \
+        ((_r)->req_cons - (_r)->rsp_prod_pvt);                          \
+    req < rsp ? req : rsp;                                              \
+})
 
 /* Direct access to individual ring elements, by index. */
-#define RING_GET_REQUEST(_r, _idx)					\
+#define RING_GET_REQUEST(_r, _idx)                                      \
     (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
 
+#define RING_GET_RESPONSE(_r, _idx)                                     \
+    (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
+
 /*
- * Get a local copy of a request.
+ * Get a local copy of a request/response.
  *
- * Use this in preference to RING_GET_REQUEST() so all processing is
+ * Use this in preference to RING_GET_{REQUEST,RESPONSE}() so all processing is
  * done on a local copy that cannot be modified by the other end.
  *
  * Note that https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 may cause this
- * to be ineffective where _req is a struct which consists of only bitfields.
+ * to be ineffective where dest is a struct which consists of only bitfields.
  */
-#define RING_COPY_REQUEST(_r, _idx, _req) do {				\
-	/* Use volatile to force the copy into _req. */			\
-	*(_req) = *(volatile typeof(_req))RING_GET_REQUEST(_r, _idx);	\
+#define RING_COPY_(type, r, idx, dest) do {				\
+	/* Use volatile to force the copy into dest. */			\
+	*(dest) = *(volatile typeof(dest))RING_GET_##type(r, idx);	\
 } while (0)
 
-#define RING_GET_RESPONSE(_r, _idx)					\
-    (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
+#define RING_COPY_REQUEST(r, idx, req)  RING_COPY_(REQUEST, r, idx, req)
+#define RING_COPY_RESPONSE(r, idx, rsp) RING_COPY_(RESPONSE, r, idx, rsp)
 
 /* Loop termination condition: Would the specified index overflow the ring? */
-#define RING_REQUEST_CONS_OVERFLOW(_r, _cons)				\
+#define RING_REQUEST_CONS_OVERFLOW(_r, _cons)                           \
     (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
 
 /* Ill-behaved frontend determination: Can there be this many requests? */
-#define RING_REQUEST_PROD_OVERFLOW(_r, _prod)               \
+#define RING_REQUEST_PROD_OVERFLOW(_r, _prod)                           \
     (((_prod) - (_r)->rsp_prod_pvt) > RING_SIZE(_r))
 
-
-#define RING_PUSH_REQUESTS(_r) do {					\
-    wmb(); /* back sees requests /before/ updated producer index */	\
-    (_r)->sring->req_prod = (_r)->req_prod_pvt;				\
+/* Ill-behaved backend determination: Can there be this many responses? */
+#define RING_RESPONSE_PROD_OVERFLOW(_r, _prod)                          \
+    (((_prod) - (_r)->rsp_cons) > RING_SIZE(_r))
+
+#define RING_PUSH_REQUESTS(_r) do {                                    \
+    wmb(); /* back sees requests /before/ updated producer index */    \
+    (_r)->sring->req_prod = (_r)->req_prod_pvt;                        \
 } while (0)
 
-#define RING_PUSH_RESPONSES(_r) do {					\
-    wmb(); /* front sees responses /before/ updated producer index */	\
-    (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt;				\
+#define RING_PUSH_RESPONSES(_r) do {                                   \
+    wmb(); /* front sees resps /before/ updated producer index */      \
+    (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt;                        \
 } while (0)
 
 /*
@@ -247,40 +238,40 @@
  *  field appropriately.
  */
 
-#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do {		\
-    RING_IDX __old = (_r)->sring->req_prod;				\
-    RING_IDX __new = (_r)->req_prod_pvt;				\
-    wmb(); /* back sees requests /before/ updated producer index */	\
-    (_r)->sring->req_prod = __new;					\
-    mb(); /* back sees new requests /before/ we check req_event */	\
-    (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) <		\
-		 (RING_IDX)(__new - __old));				\
-} while (0)
-
-#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do {		\
-    RING_IDX __old = (_r)->sring->rsp_prod;				\
-    RING_IDX __new = (_r)->rsp_prod_pvt;				\
-    wmb(); /* front sees responses /before/ updated producer index */	\
-    (_r)->sring->rsp_prod = __new;					\
-    mb(); /* front sees new responses /before/ we check rsp_event */	\
-    (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) <		\
-		 (RING_IDX)(__new - __old));				\
-} while (0)
-
-#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do {		\
-    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);			\
-    if (_work_to_do) break;						\
-    (_r)->sring->req_event = (_r)->req_cons + 1;			\
-    mb();								\
-    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);			\
-} while (0)
-
-#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do {		\
-    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);			\
-    if (_work_to_do) break;						\
-    (_r)->sring->rsp_event = (_r)->rsp_cons + 1;			\
-    mb();								\
-    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);			\
+#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do {          \
+    RING_IDX __old = (_r)->sring->req_prod;                            \
+    RING_IDX __new = (_r)->req_prod_pvt;                               \
+    wmb(); /* back sees requests /before/ updated producer index */    \
+    (_r)->sring->req_prod = __new;                                     \
+    mb(); /* back sees new requests /before/ we check req_event */     \
+    (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) <          \
+                 (RING_IDX)(__new - __old));                           \
+} while (0)
+
+#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do {         \
+    RING_IDX __old = (_r)->sring->rsp_prod;                            \
+    RING_IDX __new = (_r)->rsp_prod_pvt;                               \
+    wmb(); /* front sees resps /before/ updated producer index */      \
+    (_r)->sring->rsp_prod = __new;                                     \
+    mb(); /* front sees new resps /before/ we check rsp_event */       \
+    (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) <          \
+                 (RING_IDX)(__new - __old));                           \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do {            \
+    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);                  \
+    if (_work_to_do) break;                                            \
+    (_r)->sring->req_event = (_r)->req_cons + 1;                       \
+    mb();                                                              \
+    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);                  \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do {           \
+    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                 \
+    if (_work_to_do) break;                                            \
+    (_r)->sring->rsp_event = (_r)->rsp_cons + 1;                       \
+    mb();                                                              \
+    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                 \
 } while (0)
 
 #endif /* __XEN_PUBLIC_IO_RING_H__ */
--- linux-4.4.0.orig/include/xen/page.h
+++ linux-4.4.0/include/xen/page.h
@@ -15,9 +15,9 @@
  */
 
 #define xen_pfn_to_page(xen_pfn)	\
-	((pfn_to_page(((unsigned long)(xen_pfn) << XEN_PAGE_SHIFT) >> PAGE_SHIFT)))
+	(pfn_to_page((unsigned long)(xen_pfn) >> (PAGE_SHIFT - XEN_PAGE_SHIFT)))
 #define page_to_xen_pfn(page)		\
-	(((page_to_pfn(page)) << PAGE_SHIFT) >> XEN_PAGE_SHIFT)
+	((page_to_pfn(page)) << (PAGE_SHIFT - XEN_PAGE_SHIFT))
 
 #define XEN_PFN_PER_PAGE	(PAGE_SIZE / XEN_PAGE_SIZE)
 
--- linux-4.4.0.orig/include/xen/swiotlb-xen.h
+++ linux-4.4.0/include/xen/swiotlb-xen.h
@@ -58,4 +58,9 @@
 
 extern int
 xen_swiotlb_set_dma_mask(struct device *dev, u64 dma_mask);
+
+extern int
+xen_swiotlb_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);
 #endif /* __LINUX_SWIOTLB_XEN_H */
--- linux-4.4.0.orig/include/xen/xenbus.h
+++ linux-4.4.0/include/xen/xenbus.h
@@ -58,6 +58,15 @@
 	/* Path being watched. */
 	const char *node;
 
+	unsigned int nr_pending;
+
+	/*
+	 * Called just before enqueing new event while a spinlock is held.
+	 * The event will be discarded if this callback returns false.
+	 */
+	bool (*will_handle)(struct xenbus_watch *,
+			    const char **vec, unsigned int len);
+
 	/* Callback (executed in a process context with no locks held). */
 	void (*callback)(struct xenbus_watch *,
 			 const char **vec, unsigned int len);
@@ -194,10 +203,14 @@
 
 int xenbus_watch_path(struct xenbus_device *dev, const char *path,
 		      struct xenbus_watch *watch,
+		      bool (*will_handle)(struct xenbus_watch *,
+					  const char **, unsigned int),
 		      void (*callback)(struct xenbus_watch *,
 				       const char **, unsigned int));
-__printf(4, 5)
+__printf(5, 6)
 int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
+			 bool (*will_handle)(struct xenbus_watch *,
+					     const char **, unsigned int),
 			 void (*callback)(struct xenbus_watch *,
 					  const char **, unsigned int),
 			 const char *pathfmt, ...);
--- linux-4.4.0.orig/init/Kconfig
+++ linux-4.4.0/init/Kconfig
@@ -26,6 +26,16 @@
 config BUILDTIME_EXTABLE_SORT
 	bool
 
+config THREAD_INFO_IN_TASK
+	bool
+	help
+	  Select this to move thread_info off the stack into task_struct.  To
+	  make this work, an arch will need to remove all thread_info fields
+	  except flags and fix any runtime bugs.
+
+	  One subtle change that will be needed is to use try_get_task_stack()
+	  and put_task_stack() in save_thread_stack_tsk() and get_wchan().
+
 menu "General setup"
 
 config BROKEN
@@ -208,6 +218,15 @@
 	  but you may wish to use a different default here to make a minimal
 	  system more usable with less configuration.
 
+config VERSION_SIGNATURE
+	string "Arbitrary version signature"
+	help
+	  This string will be created in a file, /proc/version_signature. It
+	  is useful in determining arbitrary data about your kernel. For instance,
+	  if you have several kernels of the same version, but need to keep track
+	  of a revision of the same kernel, but not affect it's ability to load
+	  compatible modules, this is the easiest way to do that.
+
 config SWAP
 	bool "Support for paging of anonymous memory (swap)"
 	depends on MMU && BLOCK
@@ -813,7 +832,8 @@
 
 config LOG_BUF_SHIFT
 	int "Kernel log buffer size (16 => 64KB, 17 => 128KB)"
-	range 12 25
+	range 12 25 if !H8300
+	range 12 19 if H8300
 	default 17
 	depends on PRINTK
 	help
@@ -1308,6 +1328,17 @@
 
 endif
 
+choice
+	prompt "Compiler optimization level"
+	default CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
+
+config CC_OPTIMIZE_FOR_PERFORMANCE
+	bool "Optimize for performance"
+	help
+	  This is the default optimization level for the kernel, building
+	  with the "-O2" compiler flag for best performance and most
+	  helpful compile-time warnings.
+
 config CC_OPTIMIZE_FOR_SIZE
 	bool "Optimize for size"
 	help
@@ -1316,6 +1347,8 @@
 
 	  If unsure, say N.
 
+endchoice
+
 config SYSCTL
 	bool
 
@@ -1556,6 +1589,13 @@
 	  Enable the bpf() system call that allows to manipulate eBPF
 	  programs and maps via file descriptors.
 
+config BPF_JIT_ALWAYS_ON
+	bool "Permanently enable BPF JIT and remove BPF interpreter"
+	depends on BPF_SYSCALL && HAVE_EBPF_JIT && BPF_JIT
+	help
+	  Enables BPF JIT and removes BPF interpreter to avoid
+	  speculative execution of BPF instructions by the interpreter
+
 config SHMEM
 	bool "Use full shmem filesystem" if EXPERT
 	default y
@@ -1585,6 +1625,16 @@
 	  applications use these syscalls, you can disable this option to save
 	  space.
 
+config BPF_UNPRIV_DEFAULT_OFF
+	bool "Disable unprivileged BPF by default"
+	depends on BPF_SYSCALL
+	help
+	  Disables unprivileged BPF by default by setting the corresponding
+	  /proc/sys/kernel/unprivileged_bpf_disabled knob to 2. An admin can
+	  still reenable it by setting it to 0 later on, or permanently
+	  disable it by setting it to 1 (from which no other transition to
+	  0 is possible anymore).
+
 config USERFAULTFD
 	bool "Enable userfaultfd() system call"
 	select ANON_INODES
@@ -1795,6 +1845,15 @@
 	  module verification, kexec image verification and firmware blob
 	  verification.
 
+config SYSTEM_BLACKLIST_KEYRING
+	bool "Provide system-wide ring of blacklisted keys"
+	depends on KEYS
+	help
+	  Provide a system keyring to which blacklisted keys can be added.
+	  Keys in the keyring are considered entirely untrusted.  Keys in this
+	  keyring are used by the module signature checking to reject loading
+	  of modules signed with a blacklisted key.
+
 config PROFILING
 	bool "Profiling support"
 	help
@@ -1936,6 +1995,15 @@
 comment "Do not forget to sign required modules with scripts/sign-file"
 	depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
 
+config MODULE_SIG_UEFI
+	bool "Allow modules signed with certs stored in UEFI"
+	depends on MODULE_SIG && SYSTEM_BLACKLIST_KEYRING && EFI
+	select EFI_SIGNATURE_LIST_PARSER
+	help
+	  This will import certificates stored in UEFI and allow modules
+	  signed with those to be loaded.  It will also disallow loading
+	  of modules stored in the UEFI dbx variable.
+
 choice
 	prompt "Which hash algorithm should modules be signed with?"
 	depends on MODULE_SIG
--- linux-4.4.0.orig/init/init_task.c
+++ linux-4.4.0/init/init_task.c
@@ -22,5 +22,8 @@
  * Initial thread structure. Alignment of this is handled by a special
  * linker map entry.
  */
-union thread_union init_thread_union __init_task_data =
-	{ INIT_THREAD_INFO(init_task) };
+union thread_union init_thread_union __init_task_data = {
+#ifndef CONFIG_THREAD_INFO_IN_TASK
+	INIT_THREAD_INFO(init_task)
+#endif
+};
--- linux-4.4.0.orig/init/main.c
+++ linux-4.4.0/init/main.c
@@ -81,9 +81,9 @@
 #include <linux/integrity.h>
 #include <linux/proc_ns.h>
 #include <linux/io.h>
+#include <linux/kaiser.h>
 
 #include <asm/io.h>
-#include <asm/bugs.h>
 #include <asm/setup.h>
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
@@ -492,6 +492,7 @@
 	pgtable_init();
 	vmalloc_init();
 	ioremap_huge_init();
+	kaiser_init();
 }
 
 asmlinkage __visible void __init start_kernel(void)
@@ -536,6 +537,8 @@
 	page_alloc_init();
 
 	pr_notice("Kernel command line: %s\n", boot_command_line);
+	/* parameters may set static keys */
+	jump_label_init();
 	parse_early_param();
 	after_dashes = parse_args("Booting kernel",
 				  static_command_line, __start___param,
@@ -545,8 +548,6 @@
 		parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
 			   NULL, set_init_arg);
 
-	jump_label_init();
-
 	/*
 	 * These use large bootmem allocations and must precede
 	 * kmem_cache_init()
@@ -667,7 +668,8 @@
 	taskstats_init_early();
 	delayacct_init();
 
-	check_bugs();
+
+	arch_cpu_finalize_init();
 
 	acpi_subsystem_init();
 	sfi_init_late();
@@ -681,6 +683,8 @@
 
 	/* Do the rest non-__init'ed, we're now alive */
 	rest_init();
+
+	prevent_tail_call_optimization();
 }
 
 /* Call all constructor functions linked into the kernel. */
@@ -937,6 +941,13 @@
 	/* need to finish all async __init code before freeing the memory */
 	async_synchronize_full();
 	free_initmem();
+	/*
+	 * load_module() results in W+X mappings, which are cleaned up
+	 * with call_rcu_sched().  Let's make sure that queued work is
+	 * flushed so that we don't hit false positives looking for
+	 * insecure pages which are W+X.
+	 */
+	rcu_barrier_sched();
 	mark_rodata_ro();
 	system_state = SYSTEM_RUNNING;
 	numa_default_policy();
@@ -993,7 +1004,7 @@
 	 */
 	set_cpus_allowed_ptr(current, cpu_all_mask);
 
-	cad_pid = task_pid(current);
+	cad_pid = get_pid(task_pid(current));
 
 	smp_prepare_cpus(setup_max_cpus);
 
--- linux-4.4.0.orig/init/noinitramfs.c
+++ linux-4.4.0/init/noinitramfs.c
@@ -22,6 +22,8 @@
 #include <linux/kdev_t.h>
 #include <linux/syscalls.h>
 
+LIST_HEAD(populate_rootfs_domain);
+
 /*
  * Create a simple rootfs that is similar to the default initramfs
  */
--- linux-4.4.0.orig/init/version.c
+++ linux-4.4.0/init/version.c
@@ -45,7 +45,11 @@
 /* FIXED STRINGS! Don't touch! */
 const char linux_banner[] =
 	"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
-	LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
+	LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION
+#ifdef CONFIG_VERSION_SIGNATURE
+        " (" CONFIG_VERSION_SIGNATURE ")"
+#endif
+	"\n";
 
 const char linux_proc_banner[] =
 	"%s version %s"
--- linux-4.4.0.orig/ipc/mqueue.c
+++ linux-4.4.0/ipc/mqueue.c
@@ -305,8 +305,9 @@
 static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
-	struct ipc_namespace *ns = data;
+	struct ipc_namespace *ns = sb->s_fs_info;
 
+	sb->s_iflags |= SB_I_NOEXEC;
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->s_magic = MQUEUE_MAGIC;
@@ -326,17 +327,14 @@
 			 int flags, const char *dev_name,
 			 void *data)
 {
-	if (!(flags & MS_KERNMOUNT)) {
-		struct ipc_namespace *ns = current->nsproxy->ipc_ns;
-		/* Don't allow mounting unless the caller has CAP_SYS_ADMIN
-		 * over the ipc namespace.
-		 */
-		if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
-			return ERR_PTR(-EPERM);
-
-		data = ns;
+	struct ipc_namespace *ns;
+	if (flags & MS_KERNMOUNT) {
+		ns = data;
+		data = NULL;
+	} else {
+		ns = current->nsproxy->ipc_ns;
 	}
-	return mount_ns(fs_type, flags, data, mqueue_fill_super);
+	return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super);
 }
 
 static void init_once(void *foo)
@@ -371,9 +369,9 @@
 {
 	struct mqueue_inode_info *info;
 	struct user_struct *user;
-	unsigned long mq_bytes, mq_treesize;
 	struct ipc_namespace *ipc_ns;
-	struct msg_msg *msg;
+	struct msg_msg *msg, *nmsg;
+	LIST_HEAD(tmp_msg);
 
 	clear_inode(inode);
 
@@ -384,20 +382,27 @@
 	info = MQUEUE_I(inode);
 	spin_lock(&info->lock);
 	while ((msg = msg_get(info)) != NULL)
-		free_msg(msg);
+		list_add_tail(&msg->m_list, &tmp_msg);
 	kfree(info->node_cache);
 	spin_unlock(&info->lock);
 
-	/* Total amount of bytes accounted for the mqueue */
-	mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
-		min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
-		sizeof(struct posix_msg_tree_node);
-
-	mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
-				  info->attr.mq_msgsize);
+	list_for_each_entry_safe(msg, nmsg, &tmp_msg, m_list) {
+		list_del(&msg->m_list);
+		free_msg(msg);
+	}
 
 	user = info->user;
 	if (user) {
+		unsigned long mq_bytes, mq_treesize;
+
+		/* Total amount of bytes accounted for the mqueue */
+		mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
+			min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
+			sizeof(struct posix_msg_tree_node);
+
+		mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
+					  info->attr.mq_msgsize);
+
 		spin_lock(&mq_lock);
 		user->mq_bytes -= mq_bytes;
 		/*
@@ -1251,8 +1256,10 @@
 
 			timeo = MAX_SCHEDULE_TIMEOUT;
 			ret = netlink_attachskb(sock, nc, &timeo, NULL);
-			if (ret == 1)
+			if (ret == 1) {
+				sock = NULL;
 				goto retry;
+			}
 			if (ret) {
 				sock = NULL;
 				nc = NULL;
--- linux-4.4.0.orig/ipc/msg.c
+++ linux-4.4.0/ipc/msg.c
@@ -680,7 +680,7 @@
 		rcu_read_lock();
 		ipc_lock_object(&msq->q_perm);
 
-		ipc_rcu_putref(msq, ipc_rcu_free);
+		ipc_rcu_putref(msq, msg_rcu_free);
 		/* raced with RMID? */
 		if (!ipc_valid_object(&msq->q_perm)) {
 			err = -EIDRM;
@@ -742,7 +742,10 @@
 	if (*msgtyp == 0)
 		return SEARCH_ANY;
 	if (*msgtyp < 0) {
-		*msgtyp = -*msgtyp;
+		if (*msgtyp == LONG_MIN) /* -LONG_MIN is undefined */
+			*msgtyp = LONG_MAX;
+		else
+			*msgtyp = -*msgtyp;
 		return SEARCH_LESSEQUAL;
 	}
 	if (msgflg & MSG_EXCEPT)
--- linux-4.4.0.orig/ipc/msgutil.c
+++ linux-4.4.0/ipc/msgutil.c
@@ -18,6 +18,7 @@
 #include <linux/utsname.h>
 #include <linux/proc_ns.h>
 #include <linux/uaccess.h>
+#include <linux/sched.h>
 
 #include "util.h"
 
@@ -66,6 +67,9 @@
 	pseg = &msg->next;
 	while (len > 0) {
 		struct msg_msgseg *seg;
+
+		cond_resched();
+
 		alen = min(len, DATALEN_SEG);
 		seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
 		if (seg == NULL)
@@ -178,6 +182,8 @@
 	kfree(msg);
 	while (seg != NULL) {
 		struct msg_msgseg *tmp = seg->next;
+
+		cond_resched();
 		kfree(seg);
 		seg = tmp;
 	}
--- linux-4.4.0.orig/ipc/namespace.c
+++ linux-4.4.0/ipc/namespace.c
@@ -34,8 +34,11 @@
 	ns->ns.ops = &ipcns_operations;
 
 	atomic_set(&ns->count, 1);
+	ns->user_ns = get_user_ns(user_ns);
+
 	err = mq_init_ns(ns);
 	if (err) {
+		put_user_ns(ns->user_ns);
 		ns_free_inum(&ns->ns);
 		kfree(ns);
 		return ERR_PTR(err);
@@ -46,8 +49,6 @@
 	msg_init_ns(ns);
 	shm_init_ns(ns);
 
-	ns->user_ns = get_user_ns(user_ns);
-
 	return ns;
 }
 
--- linux-4.4.0.orig/ipc/sem.c
+++ linux-4.4.0/ipc/sem.c
@@ -155,14 +155,21 @@
 
 /*
  * Locking:
+ * a) global sem_lock() for read/write
  *	sem_undo.id_next,
  *	sem_array.complex_count,
- *	sem_array.pending{_alter,_cont},
- *	sem_array.sem_undo: global sem_lock() for read/write
- *	sem_undo.proc_next: only "current" is allowed to read/write that field.
+ *	sem_array.complex_mode
+ *	sem_array.pending{_alter,_const},
+ *	sem_array.sem_undo
  *
+ * b) global or semaphore sem_lock() for read/write:
  *	sem_array.sem_base[i].pending_{const,alter}:
- *		global or semaphore sem_lock() for read/write
+ *	sem_array.complex_mode (for read)
+ *
+ * c) special:
+ *	sem_undo_list.list_proc:
+ *	* undo_list->lock for write
+ *	* rcu for read
  */
 
 #define sc_semmsl	sem_ctls[0]
@@ -263,24 +270,25 @@
 #define ipc_smp_acquire__after_spin_is_unlocked()	smp_rmb()
 
 /*
- * Wait until all currently ongoing simple ops have completed.
+ * Enter the mode suitable for non-simple operations:
  * Caller must own sem_perm.lock.
- * New simple ops cannot start, because simple ops first check
- * that sem_perm.lock is free.
- * that a) sem_perm.lock is free and b) complex_count is 0.
  */
-static void sem_wait_array(struct sem_array *sma)
+static void complexmode_enter(struct sem_array *sma)
 {
 	int i;
 	struct sem *sem;
 
-	if (sma->complex_count)  {
-		/* The thread that increased sma->complex_count waited on
-		 * all sem->lock locks. Thus we don't need to wait again.
-		 */
+	if (sma->complex_mode)  {
+		/* We are already in complex_mode. Nothing to do */
 		return;
 	}
 
+	/* We need a full barrier after seting complex_mode:
+	 * The write to complex_mode must be visible
+	 * before we read the first sem->lock spinlock state.
+	 */
+	smp_store_mb(sma->complex_mode, true);
+
 	for (i = 0; i < sma->sem_nsems; i++) {
 		sem = sma->sem_base + i;
 		spin_unlock_wait(&sem->lock);
@@ -289,6 +297,28 @@
 }
 
 /*
+ * Try to leave the mode that disallows simple operations:
+ * Caller must own sem_perm.lock.
+ */
+static void complexmode_tryleave(struct sem_array *sma)
+{
+	if (sma->complex_count)  {
+		/* Complex ops are sleeping.
+		 * We must stay in complex mode
+		 */
+		return;
+	}
+	/*
+	 * Immediately after setting complex_mode to false,
+	 * a simple op can start. Thus: all memory writes
+	 * performed by the current operation must be visible
+	 * before we set complex_mode to false.
+	 */
+	smp_store_release(&sma->complex_mode, false);
+}
+
+#define SEM_GLOBAL_LOCK	(-1)
+/*
  * If the request contains only one semaphore operation, and there are
  * no complex transactions pending, lock only the semaphore involved.
  * Otherwise, lock the entire semaphore array, since we either have
@@ -304,56 +334,42 @@
 		/* Complex operation - acquire a full lock */
 		ipc_lock_object(&sma->sem_perm);
 
-		/* And wait until all simple ops that are processed
-		 * right now have dropped their locks.
-		 */
-		sem_wait_array(sma);
-		return -1;
+		/* Prevent parallel simple ops */
+		complexmode_enter(sma);
+		return SEM_GLOBAL_LOCK;
 	}
 
 	/*
 	 * Only one semaphore affected - try to optimize locking.
-	 * The rules are:
-	 * - optimized locking is possible if no complex operation
-	 *   is either enqueued or processed right now.
-	 * - The test for enqueued complex ops is simple:
-	 *      sma->complex_count != 0
-	 * - Testing for complex ops that are processed right now is
-	 *   a bit more difficult. Complex ops acquire the full lock
-	 *   and first wait that the running simple ops have completed.
-	 *   (see above)
-	 *   Thus: If we own a simple lock and the global lock is free
-	 *	and complex_count is now 0, then it will stay 0 and
-	 *	thus just locking sem->lock is sufficient.
+	 * Optimized locking is possible if no complex operation
+	 * is either enqueued or processed right now.
+	 *
+	 * Both facts are tracked by complex_mode.
 	 */
 	sem = sma->sem_base + sops->sem_num;
 
-	if (sma->complex_count == 0) {
+	/*
+	 * Initial check for complex_mode. Just an optimization,
+	 * no locking, no memory barrier.
+	 */
+	if (!sma->complex_mode) {
 		/*
 		 * It appears that no complex operation is around.
 		 * Acquire the per-semaphore lock.
 		 */
 		spin_lock(&sem->lock);
 
-		/* Then check that the global lock is free */
-		if (!spin_is_locked(&sma->sem_perm.lock)) {
-			/*
-			 * We need a memory barrier with acquire semantics,
-			 * otherwise we can race with another thread that does:
-			 *	complex_count++;
-			 *	spin_unlock(sem_perm.lock);
-			 */
-			ipc_smp_acquire__after_spin_is_unlocked();
+		/*
+		 * See 51d7d5205d33
+		 * ("powerpc: Add smp_mb() to arch_spin_is_locked()"):
+		 * A full barrier is required: the write of sem->lock
+		 * must be visible before the read is executed
+		 */
+		smp_mb();
 
-			/*
-			 * Now repeat the test of complex_count:
-			 * It can't change anymore until we drop sem->lock.
-			 * Thus: if is now 0, then it will stay 0.
-			 */
-			if (sma->complex_count == 0) {
-				/* fast path successful! */
-				return sops->sem_num;
-			}
+		if (!smp_load_acquire(&sma->complex_mode)) {
+			/* fast path successful! */
+			return sops->sem_num;
 		}
 		spin_unlock(&sem->lock);
 	}
@@ -373,15 +389,16 @@
 		/* Not a false alarm, thus complete the sequence for a
 		 * full lock.
 		 */
-		sem_wait_array(sma);
-		return -1;
+		complexmode_enter(sma);
+		return SEM_GLOBAL_LOCK;
 	}
 }
 
 static inline void sem_unlock(struct sem_array *sma, int locknum)
 {
-	if (locknum == -1) {
+	if (locknum == SEM_GLOBAL_LOCK) {
 		unmerge_queues(sma);
+		complexmode_tryleave(sma);
 		ipc_unlock_object(&sma->sem_perm);
 	} else {
 		struct sem *sem = sma->sem_base + locknum;
@@ -442,7 +459,7 @@
 static inline void sem_lock_and_putref(struct sem_array *sma)
 {
 	sem_lock(sma, NULL, -1);
-	ipc_rcu_putref(sma, ipc_rcu_free);
+	ipc_rcu_putref(sma, sem_rcu_free);
 }
 
 static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
@@ -533,6 +550,7 @@
 	}
 
 	sma->complex_count = 0;
+	sma->complex_mode = true; /* dropped by sem_unlock below */
 	INIT_LIST_HEAD(&sma->pending_alter);
 	INIT_LIST_HEAD(&sma->pending_const);
 	INIT_LIST_HEAD(&sma->list_id);
@@ -1385,7 +1403,7 @@
 			rcu_read_unlock();
 			sem_io = ipc_alloc(sizeof(ushort)*nsems);
 			if (sem_io == NULL) {
-				ipc_rcu_putref(sma, ipc_rcu_free);
+				ipc_rcu_putref(sma, sem_rcu_free);
 				return -ENOMEM;
 			}
 
@@ -1419,20 +1437,20 @@
 		if (nsems > SEMMSL_FAST) {
 			sem_io = ipc_alloc(sizeof(ushort)*nsems);
 			if (sem_io == NULL) {
-				ipc_rcu_putref(sma, ipc_rcu_free);
+				ipc_rcu_putref(sma, sem_rcu_free);
 				return -ENOMEM;
 			}
 		}
 
 		if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) {
-			ipc_rcu_putref(sma, ipc_rcu_free);
+			ipc_rcu_putref(sma, sem_rcu_free);
 			err = -EFAULT;
 			goto out_free;
 		}
 
 		for (i = 0; i < nsems; i++) {
 			if (sem_io[i] > SEMVMX) {
-				ipc_rcu_putref(sma, ipc_rcu_free);
+				ipc_rcu_putref(sma, sem_rcu_free);
 				err = -ERANGE;
 				goto out_free;
 			}
@@ -1722,7 +1740,7 @@
 	/* step 2: allocate new undo structure */
 	new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
 	if (!new) {
-		ipc_rcu_putref(sma, ipc_rcu_free);
+		ipc_rcu_putref(sma, sem_rcu_free);
 		return ERR_PTR(-ENOMEM);
 	}
 
@@ -1984,6 +2002,14 @@
 	error = get_queue_result(&queue);
 
 	/*
+	 * wake_up_sem_queue_do operates on queue without locking, so we
+	 * need a barrier here to order our read of queue.status and the
+	 * subsequent reuse of queue (queue is on the stack so will be
+	 * most likely reused in the next function call).
+	 */
+	smp_mb();
+
+	/*
 	 * Array removed? If yes, leave without sem_unlock().
 	 */
 	if (IS_ERR(sma)) {
@@ -2133,11 +2159,9 @@
 		ipc_assert_locked_object(&sma->sem_perm);
 		list_del(&un->list_id);
 
-		/* we are the last process using this ulp, acquiring ulp->lock
-		 * isn't required. Besides that, we are also protected against
-		 * IPC_RMID as we hold sma->sem_perm lock now
-		 */
+		spin_lock(&ulp->lock);
 		list_del_rcu(&un->list_proc);
+		spin_unlock(&ulp->lock);
 
 		/* perform adjustments registered in un */
 		for (i = 0; i < sma->sem_nsems; i++) {
@@ -2186,10 +2210,10 @@
 	/*
 	 * The proc interface isn't aware of sem_lock(), it calls
 	 * ipc_lock_object() directly (in sysvipc_find_ipc).
-	 * In order to stay compatible with sem_lock(), we must wait until
-	 * all simple semop() calls have left their critical regions.
+	 * In order to stay compatible with sem_lock(), we must
+	 * enter / leave complex_mode.
 	 */
-	sem_wait_array(sma);
+	complexmode_enter(sma);
 
 	sem_otime = get_semotime(sma);
 
@@ -2206,6 +2230,8 @@
 		   sem_otime,
 		   sma->sem_ctime);
 
+	complexmode_tryleave(sma);
+
 	return 0;
 }
 #endif
--- linux-4.4.0.orig/ipc/shm.c
+++ linux-4.4.0/ipc/shm.c
@@ -156,11 +156,12 @@
 	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
 
 	/*
-	 * We raced in the idr lookup or with shm_destroy().  Either way, the
-	 * ID is busted.
+	 * Callers of shm_lock() must validate the status of the returned ipc
+	 * object pointer (as returned by ipc_lock()), and error out as
+	 * appropriate.
 	 */
-	WARN_ON(IS_ERR(ipcp));
-
+	if (IS_ERR(ipcp))
+		return (void *)ipcp;
 	return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -186,18 +187,39 @@
 }
 
 
-/* This is called by fork, once for every shm attach. */
-static void shm_open(struct vm_area_struct *vma)
+static int __shm_open(struct vm_area_struct *vma)
 {
 	struct file *file = vma->vm_file;
 	struct shm_file_data *sfd = shm_file_data(file);
 	struct shmid_kernel *shp;
 
 	shp = shm_lock(sfd->ns, sfd->id);
+
+	if (IS_ERR(shp))
+		return PTR_ERR(shp);
+
+	if (shp->shm_file != sfd->file) {
+		/* ID was reused */
+		shm_unlock(shp);
+		return -EINVAL;
+	}
+
 	shp->shm_atim = get_seconds();
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_nattch++;
 	shm_unlock(shp);
+	return 0;
+}
+
+/* This is called by fork, once for every shm attach. */
+static void shm_open(struct vm_area_struct *vma)
+{
+	int err = __shm_open(vma);
+	/*
+	 * We raced in the idr lookup or with shm_destroy().
+	 * Either way, the ID is busted.
+	 */
+	WARN_ON_ONCE(err);
 }
 
 /*
@@ -260,6 +282,14 @@
 	down_write(&shm_ids(ns).rwsem);
 	/* remove from the list of attaches of the shm segment */
 	shp = shm_lock(ns, sfd->id);
+
+	/*
+	 * We raced in the idr lookup or with shm_destroy().
+	 * Either way, the ID is busted.
+	 */
+	if (WARN_ON_ONCE(IS_ERR(shp)))
+		goto done; /* no-op */
+
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_dtim = get_seconds();
 	shp->shm_nattch--;
@@ -267,6 +297,7 @@
 		shm_destroy(ns, shp);
 	else
 		shm_unlock(shp);
+done:
 	up_write(&shm_ids(ns).rwsem);
 }
 
@@ -388,17 +419,26 @@
 	struct shm_file_data *sfd = shm_file_data(file);
 	int ret;
 
+	/*
+	 * In case of remap_file_pages() emulation, the file can represent an
+	 * IPC ID that was removed, and possibly even reused by another shm
+	 * segment already.  Propagate this case as an error to caller.
+	 */
+	ret =__shm_open(vma);
+	if (ret)
+		return ret;
+
 	ret = sfd->file->f_op->mmap(sfd->file, vma);
-	if (ret != 0)
+	if (ret) {
+		shm_close(vma);
 		return ret;
+	}
 	sfd->vm_ops = vma->vm_ops;
 #ifdef CONFIG_MMU
 	WARN_ON(!sfd->vm_ops->fault);
 #endif
 	vma->vm_ops = &shm_vm_ops;
-	shm_open(vma);
-
-	return ret;
+	return 0;
 }
 
 static int shm_release(struct inode *ino, struct file *file)
@@ -406,6 +446,7 @@
 	struct shm_file_data *sfd = shm_file_data(file);
 
 	put_ipc_ns(sfd->ns);
+	fput(sfd->file);
 	shm_file_data(file) = NULL;
 	kfree(sfd);
 	return 0;
@@ -1050,8 +1091,8 @@
  * "raddr" thing points to kernel space, and there has to be a wrapper around
  * this.
  */
-long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
-	      unsigned long shmlba)
+long do_shmat(int shmid, char __user *shmaddr, int shmflg,
+	      ulong *raddr, unsigned long shmlba)
 {
 	struct shmid_kernel *shp;
 	unsigned long addr;
@@ -1072,9 +1113,17 @@
 		goto out;
 	else if ((addr = (ulong)shmaddr)) {
 		if (addr & (shmlba - 1)) {
-			if (shmflg & SHM_RND)
-				addr &= ~(shmlba - 1);	   /* round down */
-			else
+			if (shmflg & SHM_RND) {
+				addr &= ~(shmlba - 1);  /* round down */
+
+				/*
+				 * Ensure that the round-down is non-nil
+				 * when remapping. This can happen for
+				 * cases when addr < shmlba.
+				 */
+				if (!addr && (shmflg & SHM_REMAP))
+					goto out;
+			} else
 #ifndef __ARCH_FORCE_SHMLBA
 				if (addr & ~PAGE_MASK)
 #endif
@@ -1160,7 +1209,16 @@
 	file->f_mapping = shp->shm_file->f_mapping;
 	sfd->id = shp->shm_perm.id;
 	sfd->ns = get_ipc_ns(ns);
-	sfd->file = shp->shm_file;
+	/*
+	 * We need to take a reference to the real shm file to prevent the
+	 * pointer from becoming stale in cases where the lifetime of the outer
+	 * file extends beyond that of the shm segment.  It's not usually
+	 * possible, but it can happen during remap_file_pages() emulation as
+	 * that unmaps the memory, then does ->mmap() via file reference only.
+	 * We'll deny the ->mmap() if the shm segment was since removed, but to
+	 * detect shm ID reuse we need to compare the file pointers.
+	 */
+	sfd->file = get_file(shp->shm_file);
 	sfd->vm_ops = NULL;
 
 	err = security_mmap_file(file, prot, flags);
--- linux-4.4.0.orig/ipc/util.c
+++ linux-4.4.0/ipc/util.c
@@ -746,31 +746,23 @@
 static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
 					      loff_t *new_pos)
 {
-	struct kern_ipc_perm *ipc;
-	int total, id;
+	struct kern_ipc_perm *ipc = NULL;
+	int max_idx = ipc_get_maxid(ids);
 
-	total = 0;
-	for (id = 0; id < pos && total < ids->in_use; id++) {
-		ipc = idr_find(&ids->ipcs_idr, id);
-		if (ipc != NULL)
-			total++;
-	}
-
-	if (total >= ids->in_use)
-		return NULL;
+	if (max_idx == -1 || pos > max_idx)
+		goto out;
 
-	for (; pos < IPCMNI; pos++) {
+	for (; pos <= max_idx; pos++) {
 		ipc = idr_find(&ids->ipcs_idr, pos);
 		if (ipc != NULL) {
-			*new_pos = pos + 1;
 			rcu_read_lock();
 			ipc_lock_object(ipc);
-			return ipc;
+			break;
 		}
 	}
-
-	/* Out of range - return NULL to terminate iteration */
-	return NULL;
+out:
+	*new_pos = pos + 1;
+	return ipc;
 }
 
 static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
--- linux-4.4.0.orig/kernel/Makefile
+++ linux-4.4.0/kernel/Makefile
@@ -36,9 +36,6 @@
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-y += time/
 obj-$(CONFIG_FUTEX) += futex.o
-ifeq ($(CONFIG_COMPAT),y)
-obj-$(CONFIG_FUTEX) += futex_compat.o
-endif
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += smp.o
 ifneq ($(CONFIG_SMP),y)
@@ -47,6 +44,7 @@
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_MODULE_SIG) += module_signing.o
+obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
@@ -80,9 +78,6 @@
 obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
 obj-$(CONFIG_TRACEPOINTS) += tracepoint.o
 obj-$(CONFIG_LATENCYTOP) += latencytop.o
-obj-$(CONFIG_BINFMT_ELF) += elfcore.o
-obj-$(CONFIG_COMPAT_BINFMT_ELF) += elfcore.o
-obj-$(CONFIG_BINFMT_ELF_FDPIC) += elfcore.o
 obj-$(CONFIG_FUNCTION_TRACER) += trace/
 obj-$(CONFIG_TRACING) += trace/
 obj-$(CONFIG_TRACE_CLOCK) += trace/
@@ -104,6 +99,8 @@
 
 obj-$(CONFIG_HAS_IOMEM) += memremap.o
 
+$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
+
 $(obj)/configs.o: $(obj)/config_data.h
 
 # config_data.h contains the same information as ikconfig.h but gzipped.
--- linux-4.4.0.orig/kernel/acct.c
+++ linux-4.4.0/kernel/acct.c
@@ -99,7 +99,7 @@
 {
 	struct kstatfs sbuf;
 
-	if (time_is_before_jiffies(acct->needcheck))
+	if (time_is_after_jiffies(acct->needcheck))
 		goto out;
 
 	/* May block */
--- linux-4.4.0.orig/kernel/async.c
+++ linux-4.4.0/kernel/async.c
@@ -84,20 +84,24 @@
 
 static async_cookie_t lowest_in_progress(struct async_domain *domain)
 {
-	struct list_head *pending;
+	struct async_entry *first = NULL;
 	async_cookie_t ret = ASYNC_COOKIE_MAX;
 	unsigned long flags;
 
 	spin_lock_irqsave(&async_lock, flags);
 
-	if (domain)
-		pending = &domain->pending;
-	else
-		pending = &async_global_pending;
-
-	if (!list_empty(pending))
-		ret = list_first_entry(pending, struct async_entry,
-				       domain_list)->cookie;
+	if (domain) {
+		if (!list_empty(&domain->pending))
+			first = list_first_entry(&domain->pending,
+					struct async_entry, domain_list);
+	} else {
+		if (!list_empty(&async_global_pending))
+			first = list_first_entry(&async_global_pending,
+					struct async_entry, global_list);
+	}
+
+	if (first)
+		ret = first->cookie;
 
 	spin_unlock_irqrestore(&async_lock, flags);
 	return ret;
@@ -326,3 +330,4 @@
 
 	return worker && worker->current_func == async_run_entry_fn;
 }
+EXPORT_SYMBOL_GPL(current_is_async);
--- linux-4.4.0.orig/kernel/audit.c
+++ linux-4.4.0/kernel/audit.c
@@ -64,7 +64,6 @@
 #include <linux/security.h>
 #endif
 #include <linux/freezer.h>
-#include <linux/tty.h>
 #include <linux/pid_namespace.h>
 #include <net/netns/generic.h>
 
@@ -80,13 +79,13 @@
 #define AUDIT_OFF	0
 #define AUDIT_ON	1
 #define AUDIT_LOCKED	2
-u32		audit_enabled;
-u32		audit_ever_enabled;
+u32		audit_enabled = AUDIT_OFF;
+u32		audit_ever_enabled = !!AUDIT_OFF;
 
 EXPORT_SYMBOL_GPL(audit_enabled);
 
 /* Default state when kernel boots without any parameters. */
-static u32	audit_default;
+static u32	audit_default = AUDIT_OFF;
 
 /* If auditing cannot proceed, audit_failure selects what happens. */
 static u32	audit_failure = AUDIT_FAIL_PRINTK;
@@ -745,6 +744,8 @@
 		return;
 
 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
+	if (!ab)
+		return;
 	audit_log_task_info(ab, current);
 	audit_log_format(ab, " feature=%s old=%u new=%u old_lock=%u new_lock=%u res=%d",
 			 audit_feature_names[which], !!old_feature, !!new_feature,
@@ -752,13 +753,11 @@
 	audit_log_end(ab);
 }
 
-static int audit_set_feature(struct sk_buff *skb)
+static int audit_set_feature(struct audit_features *uaf)
 {
-	struct audit_features *uaf;
 	int i;
 
 	BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > ARRAY_SIZE(audit_feature_names));
-	uaf = nlmsg_data(nlmsg_hdr(skb));
 
 	/* if there is ever a version 2 we should handle that here */
 
@@ -810,10 +809,21 @@
 	return 0;
 }
 
+static int audit_replace(pid_t pid)
+{
+	struct sk_buff *skb = audit_make_reply(0, 0, AUDIT_REPLACE, 0, 0,
+					       &pid, sizeof(pid));
+
+	if (!skb)
+		return -ENOMEM;
+	return netlink_unicast(audit_sock, skb, audit_nlk_portid, 0);
+}
+
 static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	u32			seq;
 	void			*data;
+	int			data_len;
 	int			err;
 	struct audit_buffer	*ab;
 	u16			msg_type = nlh->nlmsg_type;
@@ -837,6 +847,7 @@
 	}
 	seq  = nlh->nlmsg_seq;
 	data = nlmsg_data(nlh);
+	data_len = nlmsg_len(nlh);
 
 	switch (msg_type) {
 	case AUDIT_GET: {
@@ -858,7 +869,7 @@
 		struct audit_status	s;
 		memset(&s, 0, sizeof(s));
 		/* guard against past and future API changes */
-		memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
+		memcpy(&s, data, min_t(size_t, sizeof(s), data_len));
 		if (s.mask & AUDIT_STATUS_ENABLED) {
 			err = audit_set_enabled(s.enabled);
 			if (err < 0)
@@ -871,9 +882,13 @@
 		}
 		if (s.mask & AUDIT_STATUS_PID) {
 			int new_pid = s.pid;
+			pid_t requesting_pid = task_tgid_vnr(current);
 
-			if ((!new_pid) && (task_tgid_vnr(current) != audit_pid))
+			if ((!new_pid) && (requesting_pid != audit_pid))
 				return -EACCES;
+			if (audit_pid && new_pid &&
+			    audit_replace(requesting_pid) != -ECONNREFUSED)
+				return -EEXIST;
 			if (audit_enabled != AUDIT_OFF)
 				audit_log_config_change("audit_pid", new_pid, audit_pid, 1);
 			audit_pid = new_pid;
@@ -907,7 +922,9 @@
 			return err;
 		break;
 	case AUDIT_SET_FEATURE:
-		err = audit_set_feature(skb);
+		if (data_len < sizeof(struct audit_features))
+			return -EINVAL;
+		err = audit_set_feature(data);
 		if (err)
 			return err;
 		break;
@@ -916,9 +933,14 @@
 	case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
 		if (!audit_enabled && msg_type != AUDIT_USER_AVC)
 			return 0;
+		/* exit early if there isn't at least one character to print */
+		if (data_len < 2)
+			return -EINVAL;
 
 		err = audit_filter_user(msg_type);
 		if (err == 1) { /* match or error */
+			char *str = data;
+
 			err = 0;
 			if (msg_type == AUDIT_USER_TTY) {
 				err = tty_audit_push_current();
@@ -927,19 +949,17 @@
 			}
 			mutex_unlock(&audit_cmd_mutex);
 			audit_log_common_recv_msg(&ab, msg_type);
-			if (msg_type != AUDIT_USER_TTY)
+			if (msg_type != AUDIT_USER_TTY) {
+				/* ensure NULL termination */
+				str[data_len - 1] = '\0';
 				audit_log_format(ab, " msg='%.*s'",
 						 AUDIT_MESSAGE_TEXT_MAX,
-						 (char *)data);
-			else {
-				int size;
-
+						 str);
+			} else {
 				audit_log_format(ab, " data=");
-				size = nlmsg_len(nlh);
-				if (size > 0 &&
-				    ((unsigned char *)data)[size - 1] == '\0')
-					size--;
-				audit_log_n_untrustedstring(ab, data, size);
+				if (data_len > 0 && str[data_len - 1] == '\0')
+					data_len--;
+				audit_log_n_untrustedstring(ab, str, data_len);
 			}
 			audit_set_portid(ab, NETLINK_CB(skb).portid);
 			audit_log_end(ab);
@@ -948,7 +968,7 @@
 		break;
 	case AUDIT_ADD_RULE:
 	case AUDIT_DEL_RULE:
-		if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
+		if (data_len < sizeof(struct audit_rule_data))
 			return -EINVAL;
 		if (audit_enabled == AUDIT_LOCKED) {
 			audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
@@ -957,7 +977,7 @@
 			return -EPERM;
 		}
 		err = audit_rule_change(msg_type, NETLINK_CB(skb).portid,
-					   seq, data, nlmsg_len(nlh));
+					   seq, data, data_len);
 		break;
 	case AUDIT_LIST_RULES:
 		err = audit_list_rules_send(skb, seq);
@@ -971,7 +991,7 @@
 	case AUDIT_MAKE_EQUIV: {
 		void *bufp = data;
 		u32 sizes[2];
-		size_t msglen = nlmsg_len(nlh);
+		size_t msglen = data_len;
 		char *old, *new;
 
 		err = -EINVAL;
@@ -1048,7 +1068,7 @@
 
 		memset(&s, 0, sizeof(s));
 		/* guard against past and future API changes */
-		memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
+		memcpy(&s, data, min_t(size_t, sizeof(s), data_len));
 		/* check if new data is valid */
 		if ((s.enabled != 0 && s.enabled != 1) ||
 		    (s.log_passwd != 0 && s.log_passwd != 1))
@@ -1179,8 +1199,6 @@
 	skb_queue_head_init(&audit_skb_queue);
 	skb_queue_head_init(&audit_skb_hold_queue);
 	audit_initialized = AUDIT_INITIALIZED;
-	audit_enabled = audit_default;
-	audit_ever_enabled |= !!audit_default;
 
 	audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
 
@@ -1197,6 +1215,8 @@
 	audit_default = !!simple_strtol(str, NULL, 0);
 	if (!audit_default)
 		audit_initialized = AUDIT_DISABLED;
+	audit_enabled = audit_default;
+	audit_ever_enabled = !!audit_enabled;
 
 	pr_info("%s\n", audit_default ?
 		"enabled (after initialization)" : "disabled (until reboot)");
@@ -1876,21 +1896,14 @@
 {
 	const struct cred *cred;
 	char comm[sizeof(tsk->comm)];
-	char *tty;
+	struct tty_struct *tty;
 
 	if (!ab)
 		return;
 
 	/* tsk == current */
 	cred = current_cred();
-
-	spin_lock_irq(&tsk->sighand->siglock);
-	if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
-		tty = tsk->signal->tty->name;
-	else
-		tty = "(none)";
-	spin_unlock_irq(&tsk->sighand->siglock);
-
+	tty = audit_get_tty(tsk);
 	audit_log_format(ab,
 			 " ppid=%d pid=%d auid=%u uid=%u gid=%u"
 			 " euid=%u suid=%u fsuid=%u"
@@ -1906,11 +1919,11 @@
 			 from_kgid(&init_user_ns, cred->egid),
 			 from_kgid(&init_user_ns, cred->sgid),
 			 from_kgid(&init_user_ns, cred->fsgid),
-			 tty, audit_get_sessionid(tsk));
-
+			 tty ? tty_name(tty) : "(none)",
+			 audit_get_sessionid(tsk));
+	audit_put_tty(tty);
 	audit_log_format(ab, " comm=");
 	audit_log_untrustedstring(ab, get_task_comm(comm, tsk));
-
 	audit_log_d_path_exe(ab, tsk->mm);
 	audit_log_task_context(ab);
 }
--- linux-4.4.0.orig/kernel/audit_watch.c
+++ linux-4.4.0/kernel/audit_watch.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/file.h>
 #include <linux/kernel.h>
 #include <linux/audit.h>
 #include <linux/kthread.h>
@@ -315,8 +316,6 @@
 			if (oentry->rule.exe)
 				audit_remove_mark(oentry->rule.exe);
 
-			audit_watch_log_rule_change(r, owatch, "updated_rules");
-
 			call_rcu(&oentry->rcu, audit_free_rule_rcu);
 		}
 
@@ -418,6 +417,13 @@
 	struct path parent_path;
 	int h, ret = 0;
 
+	/*
+	 * When we will be calling audit_add_to_parent, krule->watch might have
+	 * been updated and watch might have been freed.
+	 * So we need to keep a reference of watch.
+	 */
+	audit_get_watch(watch);
+
 	mutex_unlock(&audit_filter_mutex);
 
 	/* Avoid calling path_lookup under audit_filter_mutex. */
@@ -426,8 +432,10 @@
 	/* caller expects mutex locked */
 	mutex_lock(&audit_filter_mutex);
 
-	if (ret)
+	if (ret) {
+		audit_put_watch(watch);
 		return ret;
+	}
 
 	/* either find an old parent or attach a new one */
 	parent = audit_find_parent(d_backing_inode(parent_path.dentry));
@@ -445,6 +453,7 @@
 	*list = &audit_inode_hash[h];
 error:
 	path_put(&parent_path);
+	audit_put_watch(watch);
 	return ret;
 }
 
@@ -456,13 +465,15 @@
 	list_del(&krule->rlist);
 
 	if (list_empty(&watch->rules)) {
+		/*
+		 * audit_remove_watch() drops our reference to 'parent' which
+		 * can get freed. Grab our own reference to be safe.
+		 */
+		audit_get_parent(parent);
 		audit_remove_watch(watch);
-
-		if (list_empty(&parent->watches)) {
-			audit_get_parent(parent);
+		if (list_empty(&parent->watches))
 			fsnotify_destroy_mark(&parent->mark, audit_watch_group);
-			audit_put_parent(parent);
-		}
+		audit_put_parent(parent);
 	}
 }
 
@@ -544,10 +555,11 @@
 	unsigned long ino;
 	dev_t dev;
 
-	rcu_read_lock();
-	exe_file = rcu_dereference(tsk->mm->exe_file);
+	exe_file = get_task_exe_file(tsk);
+	if (!exe_file)
+		return 0;
 	ino = exe_file->f_inode->i_ino;
 	dev = exe_file->f_inode->i_sb->s_dev;
-	rcu_read_unlock();
+	fput(exe_file);
 	return audit_mark_compare(mark, ino, dev);
 }
--- linux-4.4.0.orig/kernel/auditfilter.c
+++ linux-4.4.0/kernel/auditfilter.c
@@ -406,7 +406,7 @@
 			return -EINVAL;
 		break;
 	case AUDIT_EXE:
-		if (f->op != Audit_equal)
+		if (f->op != Audit_not_equal && f->op != Audit_equal)
 			return -EINVAL;
 		if (entry->rule.listnr != AUDIT_FILTER_EXIT)
 			return -EINVAL;
@@ -434,6 +434,7 @@
 	bufp = data->buf;
 	for (i = 0; i < data->field_count; i++) {
 		struct audit_field *f = &entry->rule.fields[i];
+		u32 f_val;
 
 		err = -EINVAL;
 
@@ -442,12 +443,12 @@
 			goto exit_free;
 
 		f->type = data->fields[i];
-		f->val = data->values[i];
+		f_val = data->values[i];
 
 		/* Support legacy tests for a valid loginuid */
-		if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
+		if ((f->type == AUDIT_LOGINUID) && (f_val == AUDIT_UID_UNSET)) {
 			f->type = AUDIT_LOGINUID_SET;
-			f->val = 0;
+			f_val = 0;
 			entry->rule.pflags |= AUDIT_LOGINUID_LEGACY;
 		}
 
@@ -463,7 +464,7 @@
 		case AUDIT_SUID:
 		case AUDIT_FSUID:
 		case AUDIT_OBJ_UID:
-			f->uid = make_kuid(current_user_ns(), f->val);
+			f->uid = make_kuid(current_user_ns(), f_val);
 			if (!uid_valid(f->uid))
 				goto exit_free;
 			break;
@@ -472,11 +473,12 @@
 		case AUDIT_SGID:
 		case AUDIT_FSGID:
 		case AUDIT_OBJ_GID:
-			f->gid = make_kgid(current_user_ns(), f->val);
+			f->gid = make_kgid(current_user_ns(), f_val);
 			if (!gid_valid(f->gid))
 				goto exit_free;
 			break;
 		case AUDIT_ARCH:
+			f->val = f_val;
 			entry->rule.arch_f = f;
 			break;
 		case AUDIT_SUBJ_USER:
@@ -489,11 +491,13 @@
 		case AUDIT_OBJ_TYPE:
 		case AUDIT_OBJ_LEV_LOW:
 		case AUDIT_OBJ_LEV_HIGH:
-			str = audit_unpack_string(&bufp, &remain, f->val);
-			if (IS_ERR(str))
+			str = audit_unpack_string(&bufp, &remain, f_val);
+			if (IS_ERR(str)) {
+				err = PTR_ERR(str);
 				goto exit_free;
-			entry->rule.buflen += f->val;
-
+			}
+			entry->rule.buflen += f_val;
+			f->lsm_str = str;
 			err = security_audit_rule_init(f->type, f->op, str,
 						       (void **)&f->lsm_rule);
 			/* Keep currently invalid fields around in case they
@@ -502,68 +506,71 @@
 				pr_warn("audit rule for LSM \'%s\' is invalid\n",
 					str);
 				err = 0;
-			}
-			if (err) {
-				kfree(str);
+			} else if (err)
 				goto exit_free;
-			} else
-				f->lsm_str = str;
 			break;
 		case AUDIT_WATCH:
-			str = audit_unpack_string(&bufp, &remain, f->val);
-			if (IS_ERR(str))
+			str = audit_unpack_string(&bufp, &remain, f_val);
+			if (IS_ERR(str)) {
+				err = PTR_ERR(str);
 				goto exit_free;
-			entry->rule.buflen += f->val;
-
-			err = audit_to_watch(&entry->rule, str, f->val, f->op);
+			}
+			err = audit_to_watch(&entry->rule, str, f_val, f->op);
 			if (err) {
 				kfree(str);
 				goto exit_free;
 			}
+			entry->rule.buflen += f_val;
 			break;
 		case AUDIT_DIR:
-			str = audit_unpack_string(&bufp, &remain, f->val);
-			if (IS_ERR(str))
+			str = audit_unpack_string(&bufp, &remain, f_val);
+			if (IS_ERR(str)) {
+				err = PTR_ERR(str);
 				goto exit_free;
-			entry->rule.buflen += f->val;
-
+			}
 			err = audit_make_tree(&entry->rule, str, f->op);
 			kfree(str);
 			if (err)
 				goto exit_free;
+			entry->rule.buflen += f_val;
 			break;
 		case AUDIT_INODE:
+			f->val = f_val;
 			err = audit_to_inode(&entry->rule, f);
 			if (err)
 				goto exit_free;
 			break;
 		case AUDIT_FILTERKEY:
-			if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
+			if (entry->rule.filterkey || f_val > AUDIT_MAX_KEY_LEN)
 				goto exit_free;
-			str = audit_unpack_string(&bufp, &remain, f->val);
-			if (IS_ERR(str))
+			str = audit_unpack_string(&bufp, &remain, f_val);
+			if (IS_ERR(str)) {
+				err = PTR_ERR(str);
 				goto exit_free;
-			entry->rule.buflen += f->val;
+			}
+			entry->rule.buflen += f_val;
 			entry->rule.filterkey = str;
 			break;
 		case AUDIT_EXE:
-			if (entry->rule.exe || f->val > PATH_MAX)
+			if (entry->rule.exe || f_val > PATH_MAX)
 				goto exit_free;
-			str = audit_unpack_string(&bufp, &remain, f->val);
+			str = audit_unpack_string(&bufp, &remain, f_val);
 			if (IS_ERR(str)) {
 				err = PTR_ERR(str);
 				goto exit_free;
 			}
-			entry->rule.buflen += f->val;
-
-			audit_mark = audit_alloc_mark(&entry->rule, str, f->val);
+			audit_mark = audit_alloc_mark(&entry->rule, str, f_val);
 			if (IS_ERR(audit_mark)) {
 				kfree(str);
 				err = PTR_ERR(audit_mark);
 				goto exit_free;
 			}
+			entry->rule.buflen += f_val;
 			entry->rule.exe = audit_mark;
 			break;
+		default:
+			f->val = f_val;
+			break;
 		}
 	}
 
@@ -1095,22 +1102,24 @@
 	int err = 0;
 	struct audit_entry *entry;
 
-	entry = audit_data_to_entry(data, datasz);
-	if (IS_ERR(entry))
-		return PTR_ERR(entry);
-
 	switch (type) {
 	case AUDIT_ADD_RULE:
+		entry = audit_data_to_entry(data, datasz);
+		if (IS_ERR(entry))
+			return PTR_ERR(entry);
 		err = audit_add_rule(entry);
 		audit_log_rule_change("add_rule", &entry->rule, !err);
 		break;
 	case AUDIT_DEL_RULE:
+		entry = audit_data_to_entry(data, datasz);
+		if (IS_ERR(entry))
+			return PTR_ERR(entry);
 		err = audit_del_rule(entry);
 		audit_log_rule_change("remove_rule", &entry->rule, !err);
 		break;
 	default:
-		err = -EINVAL;
 		WARN_ON(1);
+		return -EINVAL;
 	}
 
 	if (err || type == AUDIT_DEL_RULE) {
--- linux-4.4.0.orig/kernel/auditsc.c
+++ linux-4.4.0/kernel/auditsc.c
@@ -73,6 +73,7 @@
 #include <linux/compat.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
+#include <linux/uaccess.h>
 #include <uapi/linux/limits.h>
 
 #include "audit.h"
@@ -82,7 +83,8 @@
 #define AUDITSC_SUCCESS 1
 #define AUDITSC_FAILURE 2
 
-/* no execve audit message should be longer than this (userspace limits) */
+/* no execve audit message should be longer than this (userspace limits),
+ * see the note near the top of audit_log_execve_info() about this value */
 #define MAX_EXECVE_AUDIT_LEN 7500
 
 /* max length to print of cmdline/proctitle value during audit */
@@ -468,6 +470,8 @@
 			break;
 		case AUDIT_EXE:
 			result = audit_exe_compare(tsk, rule->exe);
+			if (f->op == Audit_not_equal)
+				result = !result;
 			break;
 		case AUDIT_UID:
 			result = audit_uid_comparator(cred->uid, f->op, f->uid);
@@ -988,184 +992,178 @@
 	return rc;
 }
 
-/*
- * to_send and len_sent accounting are very loose estimates.  We aren't
- * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
- * within about 500 bytes (next page boundary)
- *
- * why snprintf?  an int is up to 12 digits long.  if we just assumed when
- * logging that a[%d]= was going to be 16 characters long we would be wasting
- * space in every audit message.  In one 7500 byte message we can log up to
- * about 1000 min size arguments.  That comes down to about 50% waste of space
- * if we didn't do the snprintf to find out how long arg_num_len was.
- */
-static int audit_log_single_execve_arg(struct audit_context *context,
-					struct audit_buffer **ab,
-					int arg_num,
-					size_t *len_sent,
-					const char __user *p,
-					char *buf)
-{
-	char arg_num_len_buf[12];
-	const char __user *tmp_p = p;
-	/* how many digits are in arg_num? 5 is the length of ' a=""' */
-	size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
-	size_t len, len_left, to_send;
-	size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
-	unsigned int i, has_cntl = 0, too_long = 0;
-	int ret;
-
-	/* strnlen_user includes the null we don't want to send */
-	len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
-
-	/*
-	 * We just created this mm, if we can't find the strings
-	 * we just copied into it something is _very_ wrong. Similar
-	 * for strings that are too long, we should not have created
-	 * any.
-	 */
-	if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) {
-		send_sig(SIGKILL, current, 0);
-		return -1;
-	}
-
-	/* walk the whole argument looking for non-ascii chars */
-	do {
-		if (len_left > MAX_EXECVE_AUDIT_LEN)
-			to_send = MAX_EXECVE_AUDIT_LEN;
-		else
-			to_send = len_left;
-		ret = copy_from_user(buf, tmp_p, to_send);
-		/*
-		 * There is no reason for this copy to be short. We just
-		 * copied them here, and the mm hasn't been exposed to user-
-		 * space yet.
-		 */
-		if (ret) {
-			WARN_ON(1);
-			send_sig(SIGKILL, current, 0);
-			return -1;
-		}
-		buf[to_send] = '\0';
-		has_cntl = audit_string_contains_control(buf, to_send);
-		if (has_cntl) {
-			/*
-			 * hex messages get logged as 2 bytes, so we can only
-			 * send half as much in each message
-			 */
-			max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
-			break;
-		}
-		len_left -= to_send;
-		tmp_p += to_send;
-	} while (len_left > 0);
-
-	len_left = len;
-
-	if (len > max_execve_audit_len)
-		too_long = 1;
-
-	/* rewalk the argument actually logging the message */
-	for (i = 0; len_left > 0; i++) {
-		int room_left;
-
-		if (len_left > max_execve_audit_len)
-			to_send = max_execve_audit_len;
-		else
-			to_send = len_left;
-
-		/* do we have space left to send this argument in this ab? */
-		room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
-		if (has_cntl)
-			room_left -= (to_send * 2);
-		else
-			room_left -= to_send;
-		if (room_left < 0) {
-			*len_sent = 0;
-			audit_log_end(*ab);
-			*ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
-			if (!*ab)
-				return 0;
-		}
-
-		/*
-		 * first record needs to say how long the original string was
-		 * so we can be sure nothing was lost.
-		 */
-		if ((i == 0) && (too_long))
-			audit_log_format(*ab, " a%d_len=%zu", arg_num,
-					 has_cntl ? 2*len : len);
-
-		/*
-		 * normally arguments are small enough to fit and we already
-		 * filled buf above when we checked for control characters
-		 * so don't bother with another copy_from_user
-		 */
-		if (len >= max_execve_audit_len)
-			ret = copy_from_user(buf, p, to_send);
-		else
-			ret = 0;
-		if (ret) {
-			WARN_ON(1);
-			send_sig(SIGKILL, current, 0);
-			return -1;
-		}
-		buf[to_send] = '\0';
-
-		/* actually log it */
-		audit_log_format(*ab, " a%d", arg_num);
-		if (too_long)
-			audit_log_format(*ab, "[%d]", i);
-		audit_log_format(*ab, "=");
-		if (has_cntl)
-			audit_log_n_hex(*ab, buf, to_send);
-		else
-			audit_log_string(*ab, buf);
-
-		p += to_send;
-		len_left -= to_send;
-		*len_sent += arg_num_len;
-		if (has_cntl)
-			*len_sent += to_send * 2;
-		else
-			*len_sent += to_send;
-	}
-	/* include the null we didn't log */
-	return len + 1;
-}
-
 static void audit_log_execve_info(struct audit_context *context,
 				  struct audit_buffer **ab)
 {
-	int i, len;
-	size_t len_sent = 0;
-	const char __user *p;
+	long len_max;
+	long len_rem;
+	long len_full;
+	long len_buf;
+	long len_abuf;
+	long len_tmp;
+	bool require_data;
+	bool encode;
+	unsigned int iter;
+	unsigned int arg;
+	char *buf_head;
 	char *buf;
+	const char __user *p = (const char __user *)current->mm->arg_start;
 
-	p = (const char __user *)current->mm->arg_start;
-
-	audit_log_format(*ab, "argc=%d", context->execve.argc);
-
-	/*
-	 * we need some kernel buffer to hold the userspace args.  Just
-	 * allocate one big one rather than allocating one of the right size
-	 * for every single argument inside audit_log_single_execve_arg()
-	 * should be <8k allocation so should be pretty safe.
-	 */
-	buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
-	if (!buf) {
+	/* NOTE: this buffer needs to be large enough to hold all the non-arg
+	 *       data we put in the audit record for this argument (see the
+	 *       code below) ... at this point in time 96 is plenty */
+	char abuf[96];
+
+	/* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the
+	 *       current value of 7500 is not as important as the fact that it
+	 *       is less than 8k, a setting of 7500 gives us plenty of wiggle
+	 *       room if we go over a little bit in the logging below */
+	WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500);
+	len_max = MAX_EXECVE_AUDIT_LEN;
+
+	/* scratch buffer to hold the userspace args */
+	buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
+	if (!buf_head) {
 		audit_panic("out of memory for argv string");
 		return;
 	}
+	buf = buf_head;
 
-	for (i = 0; i < context->execve.argc; i++) {
-		len = audit_log_single_execve_arg(context, ab, i,
-						  &len_sent, p, buf);
-		if (len <= 0)
-			break;
-		p += len;
-	}
-	kfree(buf);
+	audit_log_format(*ab, "argc=%d", context->execve.argc);
+
+	len_rem = len_max;
+	len_buf = 0;
+	len_full = 0;
+	require_data = true;
+	encode = false;
+	iter = 0;
+	arg = 0;
+	do {
+		/* NOTE: we don't ever want to trust this value for anything
+		 *       serious, but the audit record format insists we
+		 *       provide an argument length for really long arguments,
+		 *       e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but
+		 *       to use strncpy_from_user() to obtain this value for
+		 *       recording in the log, although we don't use it
+		 *       anywhere here to avoid a double-fetch problem */
+		if (len_full == 0)
+			len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1;
+
+		/* read more data from userspace */
+		if (require_data) {
+			/* can we make more room in the buffer? */
+			if (buf != buf_head) {
+				memmove(buf_head, buf, len_buf);
+				buf = buf_head;
+			}
+
+			/* fetch as much as we can of the argument */
+			len_tmp = strncpy_from_user(&buf_head[len_buf], p,
+						    len_max - len_buf);
+			if (len_tmp == -EFAULT) {
+				/* unable to copy from userspace */
+				send_sig(SIGKILL, current, 0);
+				goto out;
+			} else if (len_tmp == (len_max - len_buf)) {
+				/* buffer is not large enough */
+				require_data = true;
+				/* NOTE: if we are going to span multiple
+				 *       buffers force the encoding so we stand
+				 *       a chance at a sane len_full value and
+				 *       consistent record encoding */
+				encode = true;
+				len_full = len_full * 2;
+				p += len_tmp;
+			} else {
+				require_data = false;
+				if (!encode)
+					encode = audit_string_contains_control(
+								buf, len_tmp);
+				/* try to use a trusted value for len_full */
+				if (len_full < len_max)
+					len_full = (encode ?
+						    len_tmp * 2 : len_tmp);
+				p += len_tmp + 1;
+			}
+			len_buf += len_tmp;
+			buf_head[len_buf] = '\0';
+
+			/* length of the buffer in the audit record? */
+			len_abuf = (encode ? len_buf * 2 : len_buf + 2);
+		}
+
+		/* write as much as we can to the audit log */
+		if (len_buf >= 0) {
+			/* NOTE: some magic numbers here - basically if we
+			 *       can't fit a reasonable amount of data into the
+			 *       existing audit buffer, flush it and start with
+			 *       a new buffer */
+			if ((sizeof(abuf) + 8) > len_rem) {
+				len_rem = len_max;
+				audit_log_end(*ab);
+				*ab = audit_log_start(context,
+						      GFP_KERNEL, AUDIT_EXECVE);
+				if (!*ab)
+					goto out;
+			}
+
+			/* create the non-arg portion of the arg record */
+			len_tmp = 0;
+			if (require_data || (iter > 0) ||
+			    ((len_abuf + sizeof(abuf)) > len_rem)) {
+				if (iter == 0) {
+					len_tmp += snprintf(&abuf[len_tmp],
+							sizeof(abuf) - len_tmp,
+							" a%d_len=%lu",
+							arg, len_full);
+				}
+				len_tmp += snprintf(&abuf[len_tmp],
+						    sizeof(abuf) - len_tmp,
+						    " a%d[%d]=", arg, iter++);
+			} else
+				len_tmp += snprintf(&abuf[len_tmp],
+						    sizeof(abuf) - len_tmp,
+						    " a%d=", arg);
+			WARN_ON(len_tmp >= sizeof(abuf));
+			abuf[sizeof(abuf) - 1] = '\0';
+
+			/* log the arg in the audit record */
+			audit_log_format(*ab, "%s", abuf);
+			len_rem -= len_tmp;
+			len_tmp = len_buf;
+			if (encode) {
+				if (len_abuf > len_rem)
+					len_tmp = len_rem / 2; /* encoding */
+				audit_log_n_hex(*ab, buf, len_tmp);
+				len_rem -= len_tmp * 2;
+				len_abuf -= len_tmp * 2;
+			} else {
+				if (len_abuf > len_rem)
+					len_tmp = len_rem - 2; /* quotes */
+				audit_log_n_string(*ab, buf, len_tmp);
+				len_rem -= len_tmp + 2;
+				/* don't subtract the "2" because we still need
+				 * to add quotes to the remaining string */
+				len_abuf -= len_tmp;
+			}
+			len_buf -= len_tmp;
+			buf += len_tmp;
+		}
+
+		/* ready to move to the next argument? */
+		if ((len_buf == 0) && !require_data) {
+			arg++;
+			iter = 0;
+			len_full = 0;
+			require_data = true;
+			encode = false;
+		}
+	} while (arg < context->execve.argc);
+
+	/* NOTE: the caller handles the final audit_log_end() call */
+
+out:
+	kfree(buf_head);
 }
 
 static void show_special(struct audit_context *context, int *call_panic)
@@ -1980,21 +1978,26 @@
 {
 	struct audit_buffer *ab;
 	uid_t uid, oldloginuid, loginuid;
+	struct tty_struct *tty;
 
 	if (!audit_enabled)
 		return;
 
+	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
+	if (!ab)
+		return;
+
 	uid = from_kuid(&init_user_ns, task_uid(current));
 	oldloginuid = from_kuid(&init_user_ns, koldloginuid);
 	loginuid = from_kuid(&init_user_ns, kloginuid),
+	tty = audit_get_tty(current);
 
-	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
-	if (!ab)
-		return;
 	audit_log_format(ab, "pid=%d uid=%u", task_pid_nr(current), uid);
 	audit_log_task_context(ab);
-	audit_log_format(ab, " old-auid=%u auid=%u old-ses=%u ses=%u res=%d",
-			 oldloginuid, loginuid, oldsessionid, sessionid, !rc);
+	audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
+			 oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
+			 oldsessionid, sessionid, !rc);
+	audit_put_tty(tty);
 	audit_log_end(ab);
 }
 
--- linux-4.4.0.orig/kernel/bounds.c
+++ linux-4.4.0/kernel/bounds.c
@@ -12,7 +12,7 @@
 #include <linux/log2.h>
 #include <linux/spinlock_types.h>
 
-void foo(void)
+int main(void)
 {
 	/* The enum constants to put into include/generated/bounds.h */
 	DEFINE(NR_PAGEFLAGS, __NR_PAGEFLAGS);
@@ -22,4 +22,6 @@
 #endif
 	DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t));
 	/* End of constants */
+
+	return 0;
 }
--- linux-4.4.0.orig/kernel/bpf/Makefile
+++ linux-4.4.0/kernel/bpf/Makefile
@@ -1,4 +1,5 @@
 obj-y := core.o
+CFLAGS_core.o += $(call cc-disable-warning, override-init)
 
 obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o
 obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o
--- linux-4.4.0.orig/kernel/bpf/arraymap.c
+++ linux-4.4.0/kernel/bpf/arraymap.c
@@ -20,8 +20,10 @@
 /* Called from syscall */
 static struct bpf_map *array_map_alloc(union bpf_attr *attr)
 {
+	u32 elem_size, array_size, index_mask, max_entries;
+	bool unpriv = !capable(CAP_SYS_ADMIN);
 	struct bpf_array *array;
-	u32 elem_size, array_size;
+	u64 mask64;
 
 	/* check sanity of attributes */
 	if (attr->max_entries == 0 || attr->key_size != 4 ||
@@ -36,12 +38,33 @@
 
 	elem_size = round_up(attr->value_size, 8);
 
+	max_entries = attr->max_entries;
+
+	/* On 32 bit archs roundup_pow_of_two() with max_entries that has
+	 * upper most bit set in u32 space is undefined behavior due to
+	 * resulting 1U << 32, so do it manually here in u64 space.
+	 */
+	mask64 = fls_long(max_entries - 1);
+	mask64 = 1ULL << mask64;
+	mask64 -= 1;
+
+	index_mask = mask64;
+	if (unpriv) {
+		/* round up array size to nearest power of 2,
+		 * since cpu will speculate within index_mask limits
+		 */
+		max_entries = index_mask + 1;
+		/* Check for overflows. */
+		if (max_entries < attr->max_entries)
+			return ERR_PTR(-E2BIG);
+	}
+
 	/* check round_up into zero and u32 overflow */
 	if (elem_size == 0 ||
-	    attr->max_entries > (U32_MAX - PAGE_SIZE - sizeof(*array)) / elem_size)
+	    max_entries > (U32_MAX - PAGE_SIZE - sizeof(*array)) / elem_size)
 		return ERR_PTR(-ENOMEM);
 
-	array_size = sizeof(*array) + attr->max_entries * elem_size;
+	array_size = sizeof(*array) + max_entries * elem_size;
 
 	/* allocate all map elements and zero-initialize them */
 	array = kzalloc(array_size, GFP_USER | __GFP_NOWARN);
@@ -50,6 +73,8 @@
 		if (!array)
 			return ERR_PTR(-ENOMEM);
 	}
+	array->index_mask = index_mask;
+	array->map.unpriv_array = unpriv;
 
 	/* copy mandatory map attributes */
 	array->map.key_size = attr->key_size;
@@ -70,14 +95,14 @@
 	if (index >= array->map.max_entries)
 		return NULL;
 
-	return array->value + array->elem_size * index;
+	return array->value + array->elem_size * (index & array->index_mask);
 }
 
 /* Called from syscall */
 static int array_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
 {
 	struct bpf_array *array = container_of(map, struct bpf_array, map);
-	u32 index = *(u32 *)key;
+	u32 index = key ? *(u32 *)key : U32_MAX;
 	u32 *next = (u32 *)next_key;
 
 	if (index >= array->map.max_entries) {
@@ -111,7 +136,9 @@
 		/* all elements already exist */
 		return -EEXIST;
 
-	memcpy(array->value + array->elem_size * index, value, map->value_size);
+	memcpy(array->value +
+	       array->elem_size * (index & array->index_mask),
+	       value, map->value_size);
 	return 0;
 }
 
@@ -243,9 +270,7 @@
 
 static void prog_fd_array_put_ptr(void *ptr)
 {
-	struct bpf_prog *prog = ptr;
-
-	bpf_prog_put_rcu(prog);
+	bpf_prog_put(ptr);
 }
 
 /* decrement refcnt of all bpf_progs that are stored in this map */
--- linux-4.4.0.orig/kernel/bpf/core.c
+++ linux-4.4.0/kernel/bpf/core.c
@@ -137,6 +137,77 @@
 }
 EXPORT_SYMBOL_GPL(__bpf_prog_free);
 
+static bool bpf_is_jmp_and_has_target(const struct bpf_insn *insn)
+{
+	return BPF_CLASS(insn->code) == BPF_JMP  &&
+	       /* Call and Exit are both special jumps with no
+		* target inside the BPF instruction image.
+		*/
+	       BPF_OP(insn->code) != BPF_CALL &&
+	       BPF_OP(insn->code) != BPF_EXIT;
+}
+
+static void bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta)
+{
+	struct bpf_insn *insn = prog->insnsi;
+	u32 i, insn_cnt = prog->len;
+
+	for (i = 0; i < insn_cnt; i++, insn++) {
+		if (!bpf_is_jmp_and_has_target(insn))
+			continue;
+
+		/* Adjust offset of jmps if we cross boundaries. */
+		if (i < pos && i + insn->off + 1 > pos)
+			insn->off += delta;
+		else if (i > pos + delta && i + insn->off + 1 <= pos + delta)
+			insn->off -= delta;
+	}
+}
+
+struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
+				       const struct bpf_insn *patch, u32 len)
+{
+	u32 insn_adj_cnt, insn_rest, insn_delta = len - 1;
+	struct bpf_prog *prog_adj;
+
+	/* Since our patchlet doesn't expand the image, we're done. */
+	if (insn_delta == 0) {
+		memcpy(prog->insnsi + off, patch, sizeof(*patch));
+		return prog;
+	}
+
+	insn_adj_cnt = prog->len + insn_delta;
+
+	/* Several new instructions need to be inserted. Make room
+	 * for them. Likely, there's no need for a new allocation as
+	 * last page could have large enough tailroom.
+	 */
+	prog_adj = bpf_prog_realloc(prog, bpf_prog_size(insn_adj_cnt),
+				    GFP_USER);
+	if (!prog_adj)
+		return NULL;
+
+	prog_adj->len = insn_adj_cnt;
+
+	/* Patching happens in 3 steps:
+	 *
+	 * 1) Move over tail of insnsi from next instruction onwards,
+	 *    so we can patch the single target insn with one or more
+	 *    new ones (patching is always from 1 to n insns, n > 0).
+	 * 2) Inject new instructions at the target location.
+	 * 3) Adjust branch offsets if necessary.
+	 */
+	insn_rest = insn_adj_cnt - off - len;
+
+	memmove(prog_adj->insnsi + off + len, prog_adj->insnsi + off + 1,
+		sizeof(*patch) * insn_rest);
+	memcpy(prog_adj->insnsi + off, patch, sizeof(*patch) * len);
+
+	bpf_adj_branches(prog_adj, off, insn_delta);
+
+	return prog_adj;
+}
+
 #ifdef CONFIG_BPF_JIT
 struct bpf_binary_header *
 bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
@@ -173,6 +244,209 @@
 {
 	module_memfree(hdr);
 }
+
+int bpf_jit_harden __read_mostly;
+
+static int bpf_jit_blind_insn(const struct bpf_insn *from,
+			      const struct bpf_insn *aux,
+			      struct bpf_insn *to_buff)
+{
+	struct bpf_insn *to = to_buff;
+	u32 imm_rnd = prandom_u32();
+	s16 off;
+
+	BUILD_BUG_ON(BPF_REG_AX  + 1 != MAX_BPF_JIT_REG);
+	BUILD_BUG_ON(MAX_BPF_REG + 1 != MAX_BPF_JIT_REG);
+
+	if (from->imm == 0 &&
+	    (from->code == (BPF_ALU   | BPF_MOV | BPF_K) ||
+	     from->code == (BPF_ALU64 | BPF_MOV | BPF_K))) {
+		*to++ = BPF_ALU64_REG(BPF_XOR, from->dst_reg, from->dst_reg);
+		goto out;
+	}
+
+	switch (from->code) {
+	case BPF_ALU | BPF_ADD | BPF_K:
+	case BPF_ALU | BPF_SUB | BPF_K:
+	case BPF_ALU | BPF_AND | BPF_K:
+	case BPF_ALU | BPF_OR  | BPF_K:
+	case BPF_ALU | BPF_XOR | BPF_K:
+	case BPF_ALU | BPF_MUL | BPF_K:
+	case BPF_ALU | BPF_MOV | BPF_K:
+	case BPF_ALU | BPF_DIV | BPF_K:
+	case BPF_ALU | BPF_MOD | BPF_K:
+		*to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+		*to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+		*to++ = BPF_ALU32_REG(from->code, from->dst_reg, BPF_REG_AX);
+		break;
+
+	case BPF_ALU64 | BPF_ADD | BPF_K:
+	case BPF_ALU64 | BPF_SUB | BPF_K:
+	case BPF_ALU64 | BPF_AND | BPF_K:
+	case BPF_ALU64 | BPF_OR  | BPF_K:
+	case BPF_ALU64 | BPF_XOR | BPF_K:
+	case BPF_ALU64 | BPF_MUL | BPF_K:
+	case BPF_ALU64 | BPF_MOV | BPF_K:
+	case BPF_ALU64 | BPF_DIV | BPF_K:
+	case BPF_ALU64 | BPF_MOD | BPF_K:
+		*to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+		*to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+		*to++ = BPF_ALU64_REG(from->code, from->dst_reg, BPF_REG_AX);
+		break;
+
+	case BPF_JMP | BPF_JEQ  | BPF_K:
+	case BPF_JMP | BPF_JNE  | BPF_K:
+	case BPF_JMP | BPF_JGT  | BPF_K:
+	case BPF_JMP | BPF_JGE  | BPF_K:
+	case BPF_JMP | BPF_JSGT | BPF_K:
+	case BPF_JMP | BPF_JSGE | BPF_K:
+	case BPF_JMP | BPF_JSET | BPF_K:
+		/* Accommodate for extra offset in case of a backjump. */
+		off = from->off;
+		if (off < 0)
+			off -= 2;
+		*to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+		*to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+		*to++ = BPF_JMP_REG(from->code, from->dst_reg, BPF_REG_AX, off);
+		break;
+
+	case BPF_LD | BPF_ABS | BPF_W:
+	case BPF_LD | BPF_ABS | BPF_H:
+	case BPF_LD | BPF_ABS | BPF_B:
+		*to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+		*to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+		*to++ = BPF_LD_IND(from->code, BPF_REG_AX, 0);
+		break;
+
+	case BPF_LD | BPF_IND | BPF_W:
+	case BPF_LD | BPF_IND | BPF_H:
+	case BPF_LD | BPF_IND | BPF_B:
+		*to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+		*to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+		*to++ = BPF_ALU32_REG(BPF_ADD, BPF_REG_AX, from->src_reg);
+		*to++ = BPF_LD_IND(from->code, BPF_REG_AX, 0);
+		break;
+
+	case BPF_LD | BPF_IMM | BPF_DW:
+		*to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[1].imm);
+		*to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+		*to++ = BPF_ALU64_IMM(BPF_LSH, BPF_REG_AX, 32);
+		*to++ = BPF_ALU64_REG(BPF_MOV, aux[0].dst_reg, BPF_REG_AX);
+		break;
+	case 0: /* Part 2 of BPF_LD | BPF_IMM | BPF_DW. */
+		*to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[0].imm);
+		*to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+		*to++ = BPF_ALU64_REG(BPF_OR,  aux[0].dst_reg, BPF_REG_AX);
+		break;
+
+	case BPF_ST | BPF_MEM | BPF_DW:
+	case BPF_ST | BPF_MEM | BPF_W:
+	case BPF_ST | BPF_MEM | BPF_H:
+	case BPF_ST | BPF_MEM | BPF_B:
+		*to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+		*to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+		*to++ = BPF_STX_MEM(from->code, from->dst_reg, BPF_REG_AX, from->off);
+		break;
+	}
+out:
+	return to - to_buff;
+}
+
+static struct bpf_prog *bpf_prog_clone_create(struct bpf_prog *fp_other,
+					      gfp_t gfp_extra_flags)
+{
+	gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO |
+			  gfp_extra_flags;
+	struct bpf_prog *fp;
+
+	fp = __vmalloc(fp_other->pages * PAGE_SIZE, gfp_flags, PAGE_KERNEL);
+	if (fp != NULL) {
+		kmemcheck_annotate_bitfield(fp, meta);
+
+		/* aux->prog still points to the fp_other one, so
+		 * when promoting the clone to the real program,
+		 * this still needs to be adapted.
+		 */
+		memcpy(fp, fp_other, fp_other->pages * PAGE_SIZE);
+	}
+
+	return fp;
+}
+
+static void bpf_prog_clone_free(struct bpf_prog *fp)
+{
+	/* aux was stolen by the other clone, so we cannot free
+	 * it from this path! It will be freed eventually by the
+	 * other program on release.
+	 *
+	 * At this point, we don't need a deferred release since
+	 * clone is guaranteed to not be locked.
+	 */
+	fp->aux = NULL;
+	__bpf_prog_free(fp);
+}
+
+void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
+{
+	/* We have to repoint aux->prog to self, as we don't
+	 * know whether fp here is the clone or the original.
+	 */
+	fp->aux->prog = fp;
+	bpf_prog_clone_free(fp_other);
+}
+
+struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
+{
+	struct bpf_insn insn_buff[16], aux[2];
+	struct bpf_prog *clone, *tmp;
+	int insn_delta, insn_cnt;
+	struct bpf_insn *insn;
+	int i, rewritten;
+
+	if (!bpf_jit_blinding_enabled())
+		return prog;
+
+	clone = bpf_prog_clone_create(prog, GFP_USER);
+	if (!clone)
+		return ERR_PTR(-ENOMEM);
+
+	insn_cnt = clone->len;
+	insn = clone->insnsi;
+
+	for (i = 0; i < insn_cnt; i++, insn++) {
+		/* We temporarily need to hold the original ld64 insn
+		 * so that we can still access the first part in the
+		 * second blinding run.
+		 */
+		if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW) &&
+		    insn[1].code == 0)
+			memcpy(aux, insn, sizeof(aux));
+
+		rewritten = bpf_jit_blind_insn(insn, aux, insn_buff);
+		if (!rewritten)
+			continue;
+
+		tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
+		if (!tmp) {
+			/* Patching may have repointed aux->prog during
+			 * realloc from the original one, so we need to
+			 * fix it up here on error.
+			 */
+			bpf_jit_prog_release_other(prog, clone);
+			return ERR_PTR(-ENOMEM);
+		}
+
+		clone = tmp;
+		insn_delta = rewritten - 1;
+
+		/* Walk new program and skip insns we just inserted. */
+		insn = clone->insnsi + i + insn_delta;
+		insn_cnt += insn_delta;
+		i        += insn_delta;
+	}
+
+	return clone;
+}
 #endif /* CONFIG_BPF_JIT */
 
 /* Base function for offset calculation. Needs to go into .text section,
@@ -185,6 +459,7 @@
 }
 EXPORT_SYMBOL_GPL(__bpf_call_base);
 
+#ifndef CONFIG_BPF_JIT_ALWAYS_ON
 /**
  *	__bpf_prog_run - run eBPF program on a given context
  *	@ctx: is the data we are operating on
@@ -372,7 +647,7 @@
 		DST = tmp;
 		CONT;
 	ALU_MOD_X:
-		if (unlikely(SRC == 0))
+		if (unlikely((u32)SRC == 0))
 			return 0;
 		tmp = (u32) DST;
 		DST = do_div(tmp, (u32) SRC);
@@ -391,7 +666,7 @@
 		DST = div64_u64(DST, SRC);
 		CONT;
 	ALU_DIV_X:
-		if (unlikely(SRC == 0))
+		if (unlikely((u32)SRC == 0))
 			return 0;
 		tmp = (u32) DST;
 		do_div(tmp, (u32) SRC);
@@ -446,7 +721,7 @@
 		struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
 		struct bpf_array *array = container_of(map, struct bpf_array, map);
 		struct bpf_prog *prog;
-		u64 index = BPF_R3;
+		u32 index = BPF_R3;
 
 		if (unlikely(index >= array->map.max_entries))
 			goto out;
@@ -654,6 +929,13 @@
 		return 0;
 }
 
+#else
+static unsigned int __bpf_prog_ret0(void *ctx, const struct bpf_insn *insn)
+{
+	return 0;
+}
+#endif
+
 bool bpf_prog_array_compatible(struct bpf_array *array,
 			       const struct bpf_prog *fp)
 {
@@ -694,15 +976,32 @@
 /**
  *	bpf_prog_select_runtime - select exec runtime for BPF program
  *	@fp: bpf_prog populated with internal BPF program
+ *	@err: pointer to error variable
  *
  * Try to JIT eBPF program, if JIT is not available, use interpreter.
  * The BPF program will be executed via BPF_PROG_RUN() macro.
  */
-int bpf_prog_select_runtime(struct bpf_prog *fp)
+struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
 {
+#ifndef CONFIG_BPF_JIT_ALWAYS_ON
 	fp->bpf_func = (void *) __bpf_prog_run;
-
-	bpf_int_jit_compile(fp);
+#else
+	fp->bpf_func = (void *) __bpf_prog_ret0;
+#endif
+
+	/* eBPF JITs can rewrite the program in case constant
+	 * blinding is active. However, in case of error during
+	 * blinding, bpf_int_jit_compile() must always return a
+	 * valid program, which in this case would simply not
+	 * be JITed, but falls back to the interpreter.
+	 */
+	fp = bpf_int_jit_compile(fp);
+#ifdef CONFIG_BPF_JIT_ALWAYS_ON
+	if (!fp->jited) {
+		*err = -ENOTSUPP;
+		return fp;
+	}
+#endif
 	bpf_prog_lock_ro(fp);
 
 	/* The tail call compatibility check can only be done at
@@ -710,7 +1009,9 @@
 	 * with JITed or non JITed program concatenations and not
 	 * all eBPF JITs might immediately support all features.
 	 */
-	return bpf_check_tail_call(fp);
+	*err = bpf_check_tail_call(fp);
+
+	return fp;
 }
 EXPORT_SYMBOL_GPL(bpf_prog_select_runtime);
 
@@ -785,8 +1086,9 @@
 };
 
 /* For classic BPF JITs that don't implement bpf_int_jit_compile(). */
-void __weak bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_prog *prog)
 {
+	return prog;
 }
 
 /* To execute LD_ABS/LD_IND instructions __bpf_prog_run() may call
--- linux-4.4.0.orig/kernel/bpf/hashtab.c
+++ linux-4.4.0/kernel/bpf/hashtab.c
@@ -54,10 +54,15 @@
 	    htab->map.value_size == 0)
 		goto free_htab;
 
-	/* hash table size must be power of 2 */
+	/* hash table size must be power of 2; roundup_pow_of_two() can overflow
+	 * into UB on 32-bit arches, so check that first
+	 */
+	err = -E2BIG;
+	if (htab->map.max_entries > 1UL << 31)
+		goto free_htab;
+
 	htab->n_buckets = roundup_pow_of_two(htab->map.max_entries);
 
-	err = -E2BIG;
 	if (htab->map.key_size > MAX_BPF_STACK)
 		/* eBPF programs initialize keys on stack, so they cannot be
 		 * larger than max stack size
@@ -77,9 +82,8 @@
 			  round_up(htab->map.key_size, 8) +
 			  htab->map.value_size;
 
-	/* prevent zero size kmalloc and check for u32 overflow */
-	if (htab->n_buckets == 0 ||
-	    htab->n_buckets > U32_MAX / sizeof(struct hlist_head))
+	/* check for u32 overflow */
+	if (htab->n_buckets > U32_MAX / sizeof(struct hlist_head))
 		goto free_htab;
 
 	if ((u64) htab->n_buckets * sizeof(struct hlist_head) +
@@ -169,12 +173,15 @@
 	struct hlist_head *head;
 	struct htab_elem *l, *next_l;
 	u32 hash, key_size;
-	int i;
+	int i = 0;
 
 	WARN_ON_ONCE(!rcu_read_lock_held());
 
 	key_size = map->key_size;
 
+	if (!key)
+		goto find_first_elem;
+
 	hash = htab_map_hash(key, key_size);
 
 	head = select_bucket(htab, hash);
@@ -182,10 +189,8 @@
 	/* lookup the key */
 	l = lookup_elem_raw(head, hash, key, key_size);
 
-	if (!l) {
-		i = 0;
+	if (!l)
 		goto find_first_elem;
-	}
 
 	/* key was found, get next key in the same bucket */
 	next_l = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(&l->hash_node)),
--- linux-4.4.0.orig/kernel/bpf/helpers.c
+++ linux-4.4.0/kernel/bpf/helpers.c
@@ -166,7 +166,7 @@
 	if (!task)
 		return -EINVAL;
 
-	memcpy(buf, task->comm, min_t(size_t, size, sizeof(task->comm)));
+	strlcpy(buf, task->comm, min_t(size_t, size, sizeof(task->comm)));
 	return 0;
 }
 
--- linux-4.4.0.orig/kernel/bpf/inode.c
+++ linux-4.4.0/kernel/bpf/inode.c
@@ -31,10 +31,10 @@
 {
 	switch (type) {
 	case BPF_TYPE_PROG:
-		atomic_inc(&((struct bpf_prog *)raw)->aux->refcnt);
+		raw = bpf_prog_inc(raw);
 		break;
 	case BPF_TYPE_MAP:
-		bpf_map_inc(raw, true);
+		raw = bpf_map_inc(raw, true);
 		break;
 	default:
 		WARN_ON_ONCE(1);
@@ -277,7 +277,8 @@
 		goto out;
 
 	raw = bpf_any_get(inode->i_private, *type);
-	touch_atime(&path);
+	if (!IS_ERR(raw))
+		touch_atime(&path);
 
 	path_put(&path);
 	return raw;
@@ -357,7 +358,7 @@
 static struct dentry *bpf_mount(struct file_system_type *type, int flags,
 				const char *dev_name, void *data)
 {
-	return mount_ns(type, flags, current->nsproxy->mnt_ns, bpf_fill_super);
+	return mount_nodev(type, flags, data, bpf_fill_super);
 }
 
 static struct file_system_type bpf_fs_type = {
@@ -365,7 +366,6 @@
 	.name		= "bpf",
 	.mount		= bpf_mount,
 	.kill_sb	= kill_litter_super,
-	.fs_flags	= FS_USERNS_MOUNT,
 };
 
 MODULE_ALIAS_FS("bpf");
--- linux-4.4.0.orig/kernel/bpf/syscall.c
+++ linux-4.4.0/kernel/bpf/syscall.c
@@ -18,7 +18,8 @@
 #include <linux/filter.h>
 #include <linux/version.h>
 
-int sysctl_unprivileged_bpf_disabled __read_mostly;
+int sysctl_unprivileged_bpf_disabled __read_mostly =
+	IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0;
 
 static LIST_HEAD(bpf_map_types);
 
@@ -152,7 +153,7 @@
 
 	err = bpf_map_charge_memlock(map);
 	if (err)
-		goto free_map;
+		goto free_map_nouncharge;
 
 	err = bpf_map_new_fd(map);
 	if (err < 0)
@@ -162,6 +163,8 @@
 	return err;
 
 free_map:
+	bpf_map_uncharge_memlock(map);
+free_map_nouncharge:
 	map->ops->map_free(map);
 	return err;
 }
@@ -181,11 +184,18 @@
 	return f.file->private_data;
 }
 
-void bpf_map_inc(struct bpf_map *map, bool uref)
+/* prog's and map's refcnt limit */
+#define BPF_MAX_REFCNT 32768
+
+struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref)
 {
-	atomic_inc(&map->refcnt);
+	if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) {
+		atomic_dec(&map->refcnt);
+		return ERR_PTR(-EBUSY);
+	}
 	if (uref)
 		atomic_inc(&map->usercnt);
+	return map;
 }
 
 struct bpf_map *bpf_map_get_with_uref(u32 ufd)
@@ -197,7 +207,7 @@
 	if (IS_ERR(map))
 		return map;
 
-	bpf_map_inc(map, true);
+	map = bpf_map_inc(map, true);
 	fdput(f);
 
 	return map;
@@ -383,14 +393,18 @@
 	if (IS_ERR(map))
 		return PTR_ERR(map);
 
-	err = -ENOMEM;
-	key = kmalloc(map->key_size, GFP_USER);
-	if (!key)
-		goto err_put;
-
-	err = -EFAULT;
-	if (copy_from_user(key, ukey, map->key_size) != 0)
-		goto free_key;
+	if (ukey) {
+		err = -ENOMEM;
+		key = kmalloc(map->key_size, GFP_USER);
+		if (!key)
+			goto err_put;
+
+		err = -EFAULT;
+		if (copy_from_user(key, ukey, map->key_size) != 0)
+			goto free_key;
+	} else {
+		key = NULL;
+	}
 
 	err = -ENOMEM;
 	next_key = kmalloc(map->key_size, GFP_USER);
@@ -440,57 +454,6 @@
 	list_add(&tl->list_node, &bpf_prog_types);
 }
 
-/* fixup insn->imm field of bpf_call instructions:
- * if (insn->imm == BPF_FUNC_map_lookup_elem)
- *      insn->imm = bpf_map_lookup_elem - __bpf_call_base;
- * else if (insn->imm == BPF_FUNC_map_update_elem)
- *      insn->imm = bpf_map_update_elem - __bpf_call_base;
- * else ...
- *
- * this function is called after eBPF program passed verification
- */
-static void fixup_bpf_calls(struct bpf_prog *prog)
-{
-	const struct bpf_func_proto *fn;
-	int i;
-
-	for (i = 0; i < prog->len; i++) {
-		struct bpf_insn *insn = &prog->insnsi[i];
-
-		if (insn->code == (BPF_JMP | BPF_CALL)) {
-			/* we reach here when program has bpf_call instructions
-			 * and it passed bpf_check(), means that
-			 * ops->get_func_proto must have been supplied, check it
-			 */
-			BUG_ON(!prog->aux->ops->get_func_proto);
-
-			if (insn->imm == BPF_FUNC_get_route_realm)
-				prog->dst_needed = 1;
-			if (insn->imm == BPF_FUNC_get_prandom_u32)
-				bpf_user_rnd_init_once();
-			if (insn->imm == BPF_FUNC_tail_call) {
-				/* mark bpf_tail_call as different opcode
-				 * to avoid conditional branch in
-				 * interpeter for every normal call
-				 * and to prevent accidental JITing by
-				 * JIT compiler that doesn't support
-				 * bpf_tail_call yet
-				 */
-				insn->imm = 0;
-				insn->code |= BPF_X;
-				continue;
-			}
-
-			fn = prog->aux->ops->get_func_proto(insn->imm);
-			/* all functions that have prototype and verifier allowed
-			 * programs to call them, must be real in-kernel functions
-			 */
-			BUG_ON(!fn->func);
-			insn->imm = fn->func - __bpf_call_base;
-		}
-	}
-}
-
 /* drop refcnt on maps used by eBPF program and free auxilary data */
 static void free_used_maps(struct bpf_prog_aux *aux)
 {
@@ -527,7 +490,7 @@
 	free_uid(user);
 }
 
-static void __prog_put_common(struct rcu_head *rcu)
+static void __bpf_prog_put_rcu(struct rcu_head *rcu)
 {
 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
 
@@ -536,17 +499,10 @@
 	bpf_prog_free(aux->prog);
 }
 
-/* version of bpf_prog_put() that is called after a grace period */
-void bpf_prog_put_rcu(struct bpf_prog *prog)
-{
-	if (atomic_dec_and_test(&prog->aux->refcnt))
-		call_rcu(&prog->aux->rcu, __prog_put_common);
-}
-
 void bpf_prog_put(struct bpf_prog *prog)
 {
 	if (atomic_dec_and_test(&prog->aux->refcnt))
-		__prog_put_common(&prog->aux->rcu);
+		call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
 }
 EXPORT_SYMBOL_GPL(bpf_prog_put);
 
@@ -554,7 +510,7 @@
 {
 	struct bpf_prog *prog = filp->private_data;
 
-	bpf_prog_put_rcu(prog);
+	bpf_prog_put(prog);
 	return 0;
 }
 
@@ -580,6 +536,15 @@
 	return f.file->private_data;
 }
 
+struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
+{
+	if (atomic_inc_return(&prog->aux->refcnt) > BPF_MAX_REFCNT) {
+		atomic_dec(&prog->aux->refcnt);
+		return ERR_PTR(-EBUSY);
+	}
+	return prog;
+}
+
 /* called by sockets/tracing/seccomp before attaching program to an event
  * pairs with bpf_prog_put()
  */
@@ -592,7 +557,7 @@
 	if (IS_ERR(prog))
 		return prog;
 
-	atomic_inc(&prog->aux->refcnt);
+	prog = bpf_prog_inc(prog);
 	fdput(f);
 
 	return prog;
@@ -664,11 +629,8 @@
 	if (err < 0)
 		goto free_used_maps;
 
-	/* fixup BPF_CALL->imm field */
-	fixup_bpf_calls(prog);
-
 	/* eBPF program is ready to be JITed */
-	err = bpf_prog_select_runtime(prog);
+	prog = bpf_prog_select_runtime(prog, &err);
 	if (err < 0)
 		goto free_used_maps;
 
@@ -708,10 +670,10 @@
 
 SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
 {
-	union bpf_attr attr = {};
+	union bpf_attr attr;
 	int err;
 
-	if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled)
+	if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
 	if (!access_ok(VERIFY_READ, uattr, 1))
@@ -744,6 +706,7 @@
 	}
 
 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
+	memset(&attr, 0, sizeof(attr));
 	if (copy_from_user(&attr, uattr, size) != 0)
 		return -EFAULT;
 
--- linux-4.4.0.orig/kernel/bpf/verifier.c
+++ linux-4.4.0/kernel/bpf/verifier.c
@@ -186,8 +186,33 @@
 	struct verifier_stack_elem *next;
 };
 
+struct bpf_insn_aux_data {
+	bool seen; /* this insn was processed by the verifier */
+	union {
+		enum bpf_reg_type ptr_type;	/* pointer type for load/store insns */
+		unsigned long map_state;	/* pointer/poison value for maps */
+	};
+	int sanitize_stack_off; /* stack slot to be cleared */
+};
+
 #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
 
+#define BPF_MAP_PTR_UNPRIV	1UL
+#define BPF_MAP_PTR(X)		((struct bpf_map *)((X) & ~BPF_MAP_PTR_UNPRIV))
+
+static bool bpf_map_ptr_unpriv(const struct bpf_insn_aux_data *aux)
+{
+	return aux->map_state & BPF_MAP_PTR_UNPRIV;
+}
+
+static void bpf_map_ptr_store(struct bpf_insn_aux_data *aux,
+			      const struct bpf_map *map, bool unpriv)
+{
+	unpriv |= bpf_map_ptr_unpriv(aux);
+	aux->map_state = (unsigned long)map |
+			 (unpriv ? BPF_MAP_PTR_UNPRIV : 0UL);
+}
+
 /* single container for all structs
  * one verifier_env per bpf_check() call
  */
@@ -200,6 +225,7 @@
 	struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
 	u32 used_map_cnt;		/* number of used maps */
 	bool allow_ptr_leaks;
+	struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
 };
 
 /* verbose verifier prints what it's seeing
@@ -239,15 +265,6 @@
 	[CONST_IMM]		= "imm",
 };
 
-static const struct {
-	int map_type;
-	int func_id;
-} func_limit[] = {
-	{BPF_MAP_TYPE_PROG_ARRAY, BPF_FUNC_tail_call},
-	{BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_read},
-	{BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_output},
-};
-
 static void print_verifier_state(struct verifier_env *env)
 {
 	enum bpf_reg_type t;
@@ -322,7 +339,8 @@
 	[BPF_EXIT >> 4] = "exit",
 };
 
-static void print_bpf_insn(struct bpf_insn *insn)
+static void print_bpf_insn(const struct verifier_env *env,
+			   const struct bpf_insn *insn)
 {
 	u8 class = BPF_CLASS(insn->code);
 
@@ -386,9 +404,19 @@
 				insn->code,
 				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
 				insn->src_reg, insn->imm);
-		} else if (BPF_MODE(insn->code) == BPF_IMM) {
-			verbose("(%02x) r%d = 0x%x\n",
-				insn->code, insn->dst_reg, insn->imm);
+		} else if (BPF_MODE(insn->code) == BPF_IMM &&
+			   BPF_SIZE(insn->code) == BPF_DW) {
+			/* At this point, we already made sure that the second
+			 * part of the ldimm64 insn is accessible.
+			 */
+			u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
+			bool map_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD;
+
+			if (map_ptr && !env->allow_ptr_leaks)
+				imm = 0;
+
+			verbose("(%02x) r%d = 0x%llx\n", insn->code,
+				insn->dst_reg, (unsigned long long)imm);
 		} else {
 			verbose("BUG_ld_%02x\n", insn->code);
 			return;
@@ -558,10 +586,11 @@
 /* check_stack_read/write functions track spill/fill of registers,
  * stack boundary and alignment are checked in check_mem_access()
  */
-static int check_stack_write(struct verifier_state *state, int off, int size,
-			     int value_regno)
+static int check_stack_write(struct verifier_env *env,
+			     struct verifier_state *state, int off,
+			     int size, int value_regno, int insn_idx)
 {
-	int i;
+	int i, spi = (MAX_BPF_STACK + off) / BPF_REG_SIZE;
 	/* caller checked that off % size == 0 and -MAX_BPF_STACK <= off < 0,
 	 * so it's aligned access and [off, off + size) are within stack limits
 	 */
@@ -576,15 +605,37 @@
 		}
 
 		/* save register state */
-		state->spilled_regs[(MAX_BPF_STACK + off) / BPF_REG_SIZE] =
-			state->regs[value_regno];
+		state->spilled_regs[spi] = state->regs[value_regno];
 
-		for (i = 0; i < BPF_REG_SIZE; i++)
+		for (i = 0; i < BPF_REG_SIZE; i++) {
+			if (state->stack_slot_type[MAX_BPF_STACK + off + i] == STACK_MISC &&
+			    !env->allow_ptr_leaks) {
+				int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off;
+				int soff = (-spi - 1) * BPF_REG_SIZE;
+
+				/* detected reuse of integer stack slot with a pointer
+				 * which means either llvm is reusing stack slot or
+				 * an attacker is trying to exploit CVE-2018-3639
+				 * (speculative store bypass)
+				 * Have to sanitize that slot with preemptive
+				 * store of zero.
+				 */
+				if (*poff && *poff != soff) {
+					/* disallow programs where single insn stores
+					 * into two different stack slots, since verifier
+					 * cannot sanitize them
+					 */
+					verbose("insn %d cannot access two stack slots fp%d and fp%d",
+						insn_idx, *poff, soff);
+					return -EINVAL;
+				}
+				*poff = soff;
+			}
 			state->stack_slot_type[MAX_BPF_STACK + off + i] = STACK_SPILL;
+		}
 	} else {
 		/* regular write of data into stack */
-		state->spilled_regs[(MAX_BPF_STACK + off) / BPF_REG_SIZE] =
-			(struct reg_state) {};
+		state->spilled_regs[spi] = (struct reg_state) {};
 
 		for (i = 0; i < size; i++)
 			state->stack_slot_type[MAX_BPF_STACK + off + i] = STACK_MISC;
@@ -672,13 +723,20 @@
 	}
 }
 
+static bool is_ctx_reg(struct verifier_env *env, int regno)
+{
+	const struct reg_state *reg = &env->cur_state.regs[regno];
+
+	return reg->type == PTR_TO_CTX;
+}
+
 /* check whether memory at (regno + off) is accessible for t = (read | write)
  * if t==write, value_regno is a register which value is stored into memory
  * if t==read, value_regno is a register which will receive the value from memory
  * if t==write && value_regno==-1, some unknown value is stored into memory
  * if t==read && value_regno==-1, don't care what we read from memory
  */
-static int check_mem_access(struct verifier_env *env, u32 regno, int off,
+static int check_mem_access(struct verifier_env *env, int insn_idx, u32 regno, int off,
 			    int bpf_size, enum bpf_access_type t,
 			    int value_regno)
 {
@@ -730,7 +788,8 @@
 				verbose("attempt to corrupt spilled pointer on stack\n");
 				return -EACCES;
 			}
-			err = check_stack_write(state, off, size, value_regno);
+			err = check_stack_write(env, state, off, size,
+						value_regno, insn_idx);
 		} else {
 			err = check_stack_read(state, off, size, value_regno);
 		}
@@ -742,7 +801,7 @@
 	return err;
 }
 
-static int check_xadd(struct verifier_env *env, struct bpf_insn *insn)
+static int check_xadd(struct verifier_env *env, int insn_idx, struct bpf_insn *insn)
 {
 	struct reg_state *regs = env->cur_state.regs;
 	int err;
@@ -763,14 +822,25 @@
 	if (err)
 		return err;
 
+	if (is_pointer_value(env, insn->src_reg)) {
+		verbose("R%d leaks addr into mem\n", insn->src_reg);
+		return -EACCES;
+	}
+
+	if (is_ctx_reg(env, insn->dst_reg)) {
+		verbose("BPF_XADD stores into R%d context is not allowed\n",
+			insn->dst_reg);
+		return -EACCES;
+	}
+
 	/* check whether atomic_add can read the memory */
-	err = check_mem_access(env, insn->dst_reg, insn->off,
+	err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 			       BPF_SIZE(insn->code), BPF_READ, -1);
 	if (err)
 		return err;
 
 	/* check whether atomic_add can write into the same memory */
-	return check_mem_access(env, insn->dst_reg, insn->off,
+	return check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 				BPF_SIZE(insn->code), BPF_WRITE, -1);
 }
 
@@ -898,27 +968,66 @@
 
 static int check_map_func_compatibility(struct bpf_map *map, int func_id)
 {
-	bool bool_map, bool_func;
-	int i;
-
 	if (!map)
 		return 0;
 
-	for (i = 0; i < ARRAY_SIZE(func_limit); i++) {
-		bool_map = (map->map_type == func_limit[i].map_type);
-		bool_func = (func_id == func_limit[i].func_id);
-		/* only when map & func pair match it can continue.
-		 * don't allow any other map type to be passed into
-		 * the special func;
-		 */
-		if (bool_func && bool_map != bool_func)
-			return -EINVAL;
+	/* We need a two way check, first is from map perspective ... */
+	switch (map->map_type) {
+	case BPF_MAP_TYPE_PROG_ARRAY:
+		if (func_id != BPF_FUNC_tail_call)
+			goto error;
+		break;
+	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
+		if (func_id != BPF_FUNC_perf_event_read &&
+		    func_id != BPF_FUNC_perf_event_output)
+			goto error;
+		break;
+	default:
+		break;
 	}
 
+	/* ... and second from the function itself. */
+	switch (func_id) {
+	case BPF_FUNC_tail_call:
+		if (map->map_type != BPF_MAP_TYPE_PROG_ARRAY)
+			goto error;
+		break;
+	case BPF_FUNC_perf_event_read:
+	case BPF_FUNC_perf_event_output:
+		if (map->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
+			goto error;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+error:
+	verbose("cannot pass map_type %d into func %d\n",
+		map->map_type, func_id);
+	return -EINVAL;
+}
+
+static int
+record_func_map(struct verifier_env *env, struct bpf_map *map_ptr,
+		int func_id, int insn_idx)
+{
+	struct bpf_insn_aux_data *aux = &env->insn_aux_data[insn_idx];
+
+	if (func_id != BPF_FUNC_tail_call &&
+	    func_id != BPF_FUNC_map_lookup_elem)
+		return 0;
+	if (map_ptr == NULL) {
+		verbose("kernel subsystem misconfigured verifier\n");
+		return -EINVAL;
+	}
+
+	if (!BPF_MAP_PTR(aux->map_state))
+		bpf_map_ptr_store(aux, map_ptr, map_ptr->unpriv_array);
 	return 0;
 }
 
-static int check_call(struct verifier_env *env, int func_id)
+static int check_call(struct verifier_env *env, int func_id, int insn_idx)
 {
 	struct verifier_state *state = &env->cur_state;
 	const struct bpf_func_proto *fn = NULL;
@@ -964,6 +1073,10 @@
 	if (err)
 		return err;
 
+	err = record_func_map(env, map, func_id, insn_idx);
+	if (err)
+		return err;
+
 	/* reset caller saved regs */
 	for (i = 0; i < CALLER_SAVED_REGS; i++) {
 		reg = regs + caller_saved[i];
@@ -1017,7 +1130,8 @@
 			}
 		} else {
 			if (insn->src_reg != BPF_REG_0 || insn->off != 0 ||
-			    (insn->imm != 16 && insn->imm != 32 && insn->imm != 64)) {
+			    (insn->imm != 16 && insn->imm != 32 && insn->imm != 64) ||
+			    BPF_CLASS(insn->code) == BPF_ALU64) {
 				verbose("BPF_END uses reserved fields\n");
 				return -EINVAL;
 			}
@@ -1078,7 +1192,8 @@
 				regs[insn->dst_reg].type = UNKNOWN_VALUE;
 				regs[insn->dst_reg].map_ptr = NULL;
 			}
-		} else {
+		} else if (BPF_CLASS(insn->code) == BPF_ALU64 ||
+			   insn->imm >= 0) {
 			/* case: R = imm
 			 * remember the value we stored into this reg
 			 */
@@ -1121,6 +1236,21 @@
 			return -EINVAL;
 		}
 
+		if (opcode == BPF_ARSH && BPF_CLASS(insn->code) != BPF_ALU64) {
+			verbose("BPF_ARSH not supported for 32 bit ALU\n");
+			return -EINVAL;
+		}
+
+		if ((opcode == BPF_LSH || opcode == BPF_RSH ||
+		     opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) {
+			int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32;
+
+			if (insn->imm < 0 || insn->imm >= size) {
+				verbose("invalid shift %d\n", insn->imm);
+				return -EINVAL;
+			}
+		}
+
 		/* pattern match 'bpf_add Rx, imm' instruction */
 		if (opcode == BPF_ADD && BPF_CLASS(insn->code) == BPF_ALU64 &&
 		    regs[insn->dst_reg].type == FRAME_PTR &&
@@ -1338,6 +1468,7 @@
 	}
 
 	if (insn->dst_reg != BPF_REG_0 || insn->off != 0 ||
+	    BPF_SIZE(insn->code) == BPF_DW ||
 	    (mode == BPF_ABS && insn->src_reg != BPF_REG_0)) {
 		verbose("BPF_LD_ABS uses reserved fields\n");
 		return -EINVAL;
@@ -1736,16 +1867,17 @@
 
 		if (log_level) {
 			verbose("%d: ", insn_idx);
-			print_bpf_insn(insn);
+			print_bpf_insn(env, insn);
 		}
 
+		env->insn_aux_data[insn_idx].seen = true;
 		if (class == BPF_ALU || class == BPF_ALU64) {
 			err = check_alu_op(env, insn);
 			if (err)
 				return err;
 
 		} else if (class == BPF_LDX) {
-			enum bpf_reg_type src_reg_type;
+			enum bpf_reg_type *prev_src_type, src_reg_type;
 
 			/* check for reserved fields is already done */
 
@@ -1763,27 +1895,30 @@
 			/* check that memory (src_reg + off) is readable,
 			 * the state of dst_reg will be updated by this func
 			 */
-			err = check_mem_access(env, insn->src_reg, insn->off,
+			err = check_mem_access(env, insn_idx, insn->src_reg, insn->off,
 					       BPF_SIZE(insn->code), BPF_READ,
 					       insn->dst_reg);
 			if (err)
 				return err;
 
-			if (BPF_SIZE(insn->code) != BPF_W) {
+			if (BPF_SIZE(insn->code) != BPF_W &&
+			    BPF_SIZE(insn->code) != BPF_DW) {
 				insn_idx++;
 				continue;
 			}
 
-			if (insn->imm == 0) {
+			prev_src_type = &env->insn_aux_data[insn_idx].ptr_type;
+
+			if (*prev_src_type == NOT_INIT) {
 				/* saw a valid insn
 				 * dst_reg = *(u32 *)(src_reg + off)
-				 * use reserved 'imm' field to mark this insn
+				 * save type to validate intersecting paths
 				 */
-				insn->imm = src_reg_type;
+				*prev_src_type = src_reg_type;
 
-			} else if (src_reg_type != insn->imm &&
+			} else if (src_reg_type != *prev_src_type &&
 				   (src_reg_type == PTR_TO_CTX ||
-				    insn->imm == PTR_TO_CTX)) {
+				    *prev_src_type == PTR_TO_CTX)) {
 				/* ABuser program is trying to use the same insn
 				 * dst_reg = *(u32*) (src_reg + off)
 				 * with different pointer types:
@@ -1796,10 +1931,10 @@
 			}
 
 		} else if (class == BPF_STX) {
-			enum bpf_reg_type dst_reg_type;
+			enum bpf_reg_type *prev_dst_type, dst_reg_type;
 
 			if (BPF_MODE(insn->code) == BPF_XADD) {
-				err = check_xadd(env, insn);
+				err = check_xadd(env, insn_idx, insn);
 				if (err)
 					return err;
 				insn_idx++;
@@ -1818,17 +1953,19 @@
 			dst_reg_type = regs[insn->dst_reg].type;
 
 			/* check that memory (dst_reg + off) is writeable */
-			err = check_mem_access(env, insn->dst_reg, insn->off,
+			err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 					       BPF_SIZE(insn->code), BPF_WRITE,
 					       insn->src_reg);
 			if (err)
 				return err;
 
-			if (insn->imm == 0) {
-				insn->imm = dst_reg_type;
-			} else if (dst_reg_type != insn->imm &&
+			prev_dst_type = &env->insn_aux_data[insn_idx].ptr_type;
+
+			if (*prev_dst_type == NOT_INIT) {
+				*prev_dst_type = dst_reg_type;
+			} else if (dst_reg_type != *prev_dst_type &&
 				   (dst_reg_type == PTR_TO_CTX ||
-				    insn->imm == PTR_TO_CTX)) {
+				    *prev_dst_type == PTR_TO_CTX)) {
 				verbose("same insn cannot be used with different pointers\n");
 				return -EINVAL;
 			}
@@ -1844,8 +1981,14 @@
 			if (err)
 				return err;
 
+			if (is_ctx_reg(env, insn->dst_reg)) {
+				verbose("BPF_ST stores into R%d context is not allowed\n",
+					insn->dst_reg);
+				return -EACCES;
+			}
+
 			/* check that memory (dst_reg + off) is writeable */
-			err = check_mem_access(env, insn->dst_reg, insn->off,
+			err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 					       BPF_SIZE(insn->code), BPF_WRITE,
 					       -1);
 			if (err)
@@ -1863,7 +2006,7 @@
 					return -EINVAL;
 				}
 
-				err = check_call(env, insn->imm);
+				err = check_call(env, insn->imm, insn_idx);
 				if (err)
 					return err;
 
@@ -1930,6 +2073,7 @@
 					return err;
 
 				insn_idx++;
+				env->insn_aux_data[insn_idx].seen = true;
 			} else {
 				verbose("invalid BPF_LD mode\n");
 				return -EINVAL;
@@ -1993,7 +2137,6 @@
 			if (IS_ERR(map)) {
 				verbose("fd %d is not pointing to valid bpf_map\n",
 					insn->imm);
-				fdput(f);
 				return PTR_ERR(map);
 			}
 
@@ -2013,15 +2156,18 @@
 				return -E2BIG;
 			}
 
-			/* remember this map */
-			env->used_maps[env->used_map_cnt++] = map;
-
 			/* hold the map. If the program is rejected by verifier,
 			 * the map will be released by release_maps() or it
 			 * will be used by the valid program until it's unloaded
-			 * and all maps are released in free_bpf_prog_info()
+			 * and all maps are released in free_used_maps()
 			 */
-			bpf_map_inc(map, false);
+			map = bpf_map_inc(map, false);
+			if (IS_ERR(map)) {
+				fdput(f);
+				return PTR_ERR(map);
+			}
+			env->used_maps[env->used_map_cnt++] = map;
+
 			fdput(f);
 next_insn:
 			insn++;
@@ -2057,56 +2203,121 @@
 			insn->src_reg = 0;
 }
 
-static void adjust_branches(struct bpf_prog *prog, int pos, int delta)
+/* The verifier does more data flow analysis than llvm and will not explore
+ * branches that are dead at run time. Malicious programs can have dead code
+ * too. Therefore replace all dead at-run-time code with nops.
+ */
+static void sanitize_dead_code(struct verifier_env *env)
 {
-	struct bpf_insn *insn = prog->insnsi;
-	int insn_cnt = prog->len;
+	struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
+	struct bpf_insn nop = BPF_MOV64_REG(BPF_REG_0, BPF_REG_0);
+	struct bpf_insn *insn = env->prog->insnsi;
+	const int insn_cnt = env->prog->len;
 	int i;
 
-	for (i = 0; i < insn_cnt; i++, insn++) {
-		if (BPF_CLASS(insn->code) != BPF_JMP ||
-		    BPF_OP(insn->code) == BPF_CALL ||
-		    BPF_OP(insn->code) == BPF_EXIT)
+	for (i = 0; i < insn_cnt; i++) {
+		if (aux_data[i].seen)
 			continue;
-
-		/* adjust offset of jmps if necessary */
-		if (i < pos && i + insn->off + 1 > pos)
-			insn->off += delta;
-		else if (i > pos && i + insn->off + 1 < pos)
-			insn->off -= delta;
+		memcpy(insn + i, &nop, sizeof(nop));
 	}
 }
 
+/* single env->prog->insni[off] instruction was replaced with the range
+ * insni[off, off + cnt).  Adjust corresponding insn_aux_data by copying
+ * [0, off) and [off, end) to new locations, so the patched range stays zero
+ */
+static int adjust_insn_aux_data(struct verifier_env *env, u32 prog_len,
+				u32 off, u32 cnt)
+{
+	struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
+	int i;
+
+	if (cnt == 1)
+		return 0;
+	new_data = vzalloc(sizeof(struct bpf_insn_aux_data) * prog_len);
+	if (!new_data)
+		return -ENOMEM;
+	memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
+	memcpy(new_data + off + cnt - 1, old_data + off,
+	       sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
+	for (i = off; i < off + cnt - 1; i++)
+		new_data[i].seen = true;
+	env->insn_aux_data = new_data;
+	vfree(old_data);
+	return 0;
+}
+
+static struct bpf_prog *bpf_patch_insn_data(struct verifier_env *env, u32 off,
+					    const struct bpf_insn *patch, u32 len)
+{
+	struct bpf_prog *new_prog;
+
+	new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
+	if (!new_prog)
+		return NULL;
+	if (adjust_insn_aux_data(env, new_prog->len, off, len))
+		return NULL;
+	return new_prog;
+}
+
 /* convert load instructions that access fields of 'struct __sk_buff'
  * into sequence of instructions that access fields of 'struct sk_buff'
  */
 static int convert_ctx_accesses(struct verifier_env *env)
 {
 	struct bpf_insn *insn = env->prog->insnsi;
-	int insn_cnt = env->prog->len;
+	const int insn_cnt = env->prog->len;
 	struct bpf_insn insn_buf[16];
 	struct bpf_prog *new_prog;
-	u32 cnt;
-	int i;
 	enum bpf_access_type type;
+	int i, delta = 0;
 
 	if (!env->prog->aux->ops->convert_ctx_access)
 		return 0;
 
 	for (i = 0; i < insn_cnt; i++, insn++) {
-		if (insn->code == (BPF_LDX | BPF_MEM | BPF_W))
+		u32 cnt;
+
+		if (insn->code == (BPF_LDX | BPF_MEM | BPF_W) ||
+		    insn->code == (BPF_LDX | BPF_MEM | BPF_DW))
 			type = BPF_READ;
-		else if (insn->code == (BPF_STX | BPF_MEM | BPF_W))
+		else if (insn->code == (BPF_STX | BPF_MEM | BPF_W) ||
+			 insn->code == (BPF_STX | BPF_MEM | BPF_DW))
 			type = BPF_WRITE;
 		else
 			continue;
 
-		if (insn->imm != PTR_TO_CTX) {
-			/* clear internal mark */
-			insn->imm = 0;
+		if (type == BPF_WRITE &&
+		    env->insn_aux_data[i + delta].sanitize_stack_off) {
+			struct bpf_insn patch[] = {
+				/* Sanitize suspicious stack slot with zero.
+				 * There are no memory dependencies for this store,
+				 * since it's only using frame pointer and immediate
+				 * constant of zero
+				 */
+				BPF_ST_MEM(BPF_DW, BPF_REG_FP,
+					   env->insn_aux_data[i + delta].sanitize_stack_off,
+					   0),
+				/* the original STX instruction will immediately
+				 * overwrite the same stack slot with appropriate value
+				 */
+				*insn,
+			};
+
+			cnt = ARRAY_SIZE(patch);
+			new_prog = bpf_patch_insn_data(env, i + delta, patch, cnt);
+			if (!new_prog)
+				return -ENOMEM;
+
+			delta    += cnt - 1;
+			env->prog = new_prog;
+			insn      = new_prog->insnsi + i + delta;
 			continue;
 		}
 
+		if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
+			continue;
+
 		cnt = env->prog->aux->ops->
 			convert_ctx_access(type, insn->dst_reg, insn->src_reg,
 					   insn->off, insn_buf, env->prog);
@@ -2115,34 +2326,110 @@
 			return -EINVAL;
 		}
 
-		if (cnt == 1) {
-			memcpy(insn, insn_buf, sizeof(*insn));
-			continue;
-		}
-
-		/* several new insns need to be inserted. Make room for them */
-		insn_cnt += cnt - 1;
-		new_prog = bpf_prog_realloc(env->prog,
-					    bpf_prog_size(insn_cnt),
-					    GFP_USER);
+		new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
 		if (!new_prog)
 			return -ENOMEM;
 
-		new_prog->len = insn_cnt;
+		delta += cnt - 1;
+
+		/* keep walking new program and skip insns we just inserted */
+		env->prog = new_prog;
+		insn      = new_prog->insnsi + i + delta;
+	}
+
+	return 0;
+}
 
-		memmove(new_prog->insnsi + i + cnt, new_prog->insns + i + 1,
-			sizeof(*insn) * (insn_cnt - i - cnt));
+/* fixup insn->imm field of bpf_call instructions
+ *
+ * this function is called after eBPF program passed verification
+ */
+static int fixup_bpf_calls(struct verifier_env *env)
+{
+	struct bpf_prog *prog = env->prog;
+	struct bpf_insn *insn = prog->insnsi;
+	const struct bpf_func_proto *fn;
+	const int insn_cnt = prog->len;
+	struct bpf_insn_aux_data *aux;
+	struct bpf_insn insn_buf[16];
+	struct bpf_prog *new_prog;
+	struct bpf_map *map_ptr;
+	int i, cnt, delta = 0;
 
-		/* copy substitute insns in place of load instruction */
-		memcpy(new_prog->insnsi + i, insn_buf, sizeof(*insn) * cnt);
+	for (i = 0; i < insn_cnt; i++, insn++) {
+		if (insn->code == (BPF_ALU | BPF_MOD | BPF_X) ||
+		    insn->code == (BPF_ALU | BPF_DIV | BPF_X)) {
+			/* due to JIT bugs clear upper 32-bits of src register
+			 * before div/mod operation
+			 */
+			insn_buf[0] = BPF_MOV32_REG(insn->src_reg, insn->src_reg);
+			insn_buf[1] = *insn;
+			cnt = 2;
+			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
+			if (!new_prog)
+				return -ENOMEM;
+
+			delta    += cnt - 1;
+			env->prog = prog = new_prog;
+			insn      = new_prog->insnsi + i + delta;
+			continue;
+		}
 
-		/* adjust branches in the whole program */
-		adjust_branches(new_prog, i, cnt - 1);
+		if (insn->code != (BPF_JMP | BPF_CALL))
+			continue;
 
-		/* keep walking new program and skip insns we just inserted */
-		env->prog = new_prog;
-		insn = new_prog->insnsi + i + cnt - 1;
-		i += cnt - 1;
+		if (insn->imm == BPF_FUNC_get_route_realm)
+			prog->dst_needed = 1;
+		if (insn->imm == BPF_FUNC_get_prandom_u32)
+			bpf_user_rnd_init_once();
+		if (insn->imm == BPF_FUNC_tail_call) {
+			/* mark bpf_tail_call as different opcode to avoid
+			 * conditional branch in the interpeter for every normal
+			 * call and to prevent accidental JITing by JIT compiler
+			 * that doesn't support bpf_tail_call yet
+			 */
+			insn->imm = 0;
+			insn->code |= BPF_X;
+
+			aux = &env->insn_aux_data[i + delta];
+			if (!bpf_map_ptr_unpriv(aux))
+				continue;
+
+			/* instead of changing every JIT dealing with tail_call
+			 * emit two extra insns:
+			 * if (index >= max_entries) goto out;
+			 * index &= array->index_mask;
+			 * to avoid out-of-bounds cpu speculation
+			 */
+			map_ptr = BPF_MAP_PTR(aux->map_state);
+			insn_buf[0] = BPF_JMP_IMM(BPF_JGE, BPF_REG_3,
+						  map_ptr->max_entries, 2);
+			insn_buf[1] = BPF_ALU32_IMM(BPF_AND, BPF_REG_3,
+						    container_of(map_ptr,
+								 struct bpf_array,
+								 map)->index_mask);
+			insn_buf[2] = *insn;
+			cnt = 3;
+			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
+			if (!new_prog)
+				return -ENOMEM;
+
+			delta    += cnt - 1;
+			env->prog = prog = new_prog;
+			insn      = new_prog->insnsi + i + delta;
+			continue;
+		}
+
+		fn = prog->aux->ops->get_func_proto(insn->imm);
+		/* all functions that have prototype and verifier allowed
+		 * programs to call them, must be real in-kernel functions
+		 */
+		if (!fn->func) {
+			verbose("kernel subsystem misconfigured func %d\n",
+				insn->imm);
+			return -EFAULT;
+		}
+		insn->imm = fn->func - __bpf_call_base;
 	}
 
 	return 0;
@@ -2186,6 +2473,11 @@
 	if (!env)
 		return -ENOMEM;
 
+	env->insn_aux_data = vzalloc(sizeof(struct bpf_insn_aux_data) *
+				     (*prog)->len);
+	ret = -ENOMEM;
+	if (!env->insn_aux_data)
+		goto err_free_env;
 	env->prog = *prog;
 
 	/* grab the mutex to protect few globals used by verifier */
@@ -2204,12 +2496,12 @@
 		/* log_* values have to be sane */
 		if (log_size < 128 || log_size > UINT_MAX >> 8 ||
 		    log_level == 0 || log_ubuf == NULL)
-			goto free_env;
+			goto err_unlock;
 
 		ret = -ENOMEM;
 		log_buf = vmalloc(log_size);
 		if (!log_buf)
-			goto free_env;
+			goto err_unlock;
 	} else {
 		log_level = 0;
 	}
@@ -2238,9 +2530,15 @@
 	free_states(env);
 
 	if (ret == 0)
+		sanitize_dead_code(env);
+
+	if (ret == 0)
 		/* program is valid, convert *(u32*)(ctx + off) accesses */
 		ret = convert_ctx_accesses(env);
 
+	if (ret == 0)
+		ret = fixup_bpf_calls(env);
+
 	if (log_level && log_len >= log_size - 1) {
 		BUG_ON(log_len >= log_size);
 		/* verifier log exceeded user supplied buffer */
@@ -2278,14 +2576,16 @@
 free_log_buf:
 	if (log_level)
 		vfree(log_buf);
-free_env:
 	if (!env->prog->aux->used_maps)
 		/* if we didn't copy map pointers into bpf_prog_info, release
-		 * them now. Otherwise free_bpf_prog_info() will release them.
+		 * them now. Otherwise free_used_maps() will release them.
 		 */
 		release_maps(env);
 	*prog = env->prog;
-	kfree(env);
+err_unlock:
 	mutex_unlock(&bpf_verifier_lock);
+	vfree(env->insn_aux_data);
+err_free_env:
+	kfree(env);
 	return ret;
 }
--- linux-4.4.0.orig/kernel/capability.c
+++ linux-4.4.0/kernel/capability.c
@@ -361,6 +361,24 @@
 	return has_ns_capability_noaudit(t, &init_user_ns, cap);
 }
 
+static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
+{
+	int capable;
+
+	if (unlikely(!cap_valid(cap))) {
+		pr_crit("capable() called with invalid cap=%u\n", cap);
+		BUG();
+	}
+
+	capable = audit ? security_capable(current_cred(), ns, cap) :
+			  security_capable_noaudit(current_cred(), ns, cap);
+	if (capable == 0) {
+		current->flags |= PF_SUPERPRIV;
+		return true;
+	}
+	return false;
+}
+
 /**
  * ns_capable - Determine if the current task has a superior capability in effect
  * @ns:  The usernamespace we want the capability in
@@ -374,19 +392,27 @@
  */
 bool ns_capable(struct user_namespace *ns, int cap)
 {
-	if (unlikely(!cap_valid(cap))) {
-		pr_crit("capable() called with invalid cap=%u\n", cap);
-		BUG();
-	}
-
-	if (security_capable(current_cred(), ns, cap) == 0) {
-		current->flags |= PF_SUPERPRIV;
-		return true;
-	}
-	return false;
+	return ns_capable_common(ns, cap, true);
 }
 EXPORT_SYMBOL(ns_capable);
 
+/**
+ * ns_capable_noaudit - Determine if the current task has a superior capability
+ * (unaudited) in effect
+ * @ns:  The usernamespace we want the capability in
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool ns_capable_noaudit(struct user_namespace *ns, int cap)
+{
+	return ns_capable_common(ns, cap, false);
+}
+EXPORT_SYMBOL(ns_capable_noaudit);
 
 /**
  * capable - Determine if the current task has a superior capability in effect
@@ -431,6 +457,19 @@
 EXPORT_SYMBOL(file_ns_capable);
 
 /**
+ * privileged_wrt_inode_uidgid - Do capabilities in the namespace work over the inode?
+ * @ns: The user namespace in question
+ * @inode: The inode in question
+ *
+ * Return true if the inode uid and gid are within the namespace.
+ */
+bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode)
+{
+	return kuid_has_mapping(ns, inode->i_uid) &&
+		kgid_has_mapping(ns, inode->i_gid);
+}
+
+/**
  * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped
  * @inode: The inode in question
  * @cap: The capability in question
@@ -443,7 +482,26 @@
 {
 	struct user_namespace *ns = current_user_ns();
 
-	return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) &&
-		kgid_has_mapping(ns, inode->i_gid);
+	return ns_capable(ns, cap) && privileged_wrt_inode_uidgid(ns, inode);
 }
 EXPORT_SYMBOL(capable_wrt_inode_uidgid);
+
+/**
+ * ptracer_capable - Determine if the ptracer holds CAP_SYS_PTRACE in the namespace
+ * @tsk: The task that may be ptraced
+ * @ns: The user namespace to search for CAP_SYS_PTRACE in
+ *
+ * Return true if the task that is ptracing the current task had CAP_SYS_PTRACE
+ * in the specified user namespace.
+ */
+bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns)
+{
+	int ret = 0;  /* An absent tracer adds no restrictions */
+	const struct cred *cred;
+	rcu_read_lock();
+	cred = rcu_dereference(tsk->ptracer_cred);
+	if (cred)
+		ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE);
+	rcu_read_unlock();
+	return (ret == 0);
+}
--- linux-4.4.0.orig/kernel/cgroup.c
+++ linux-4.4.0/kernel/cgroup.c
@@ -57,8 +57,12 @@
 #include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */
 #include <linux/kthread.h>
 #include <linux/delay.h>
-
+#include <linux/cpuset.h>
 #include <linux/atomic.h>
+#include <linux/cpuset.h>
+#include <linux/nsproxy.h>
+#include <linux/proc_ns.h>
+#include <net/sock.h>
 
 /*
  * pidlists linger the following amount before being destroyed.  The goal
@@ -208,6 +212,15 @@
 static unsigned long have_exit_callback __read_mostly;
 static unsigned long have_free_callback __read_mostly;
 
+/* Cgroup namespace for init task */
+struct cgroup_namespace init_cgroup_ns = {
+	.count		= { .counter = 2, },
+	.user_ns	= &init_user_ns,
+	.ns.ops		= &cgroupns_operations,
+	.ns.inum	= PROC_CGROUP_INIT_INO,
+	.root_cset	= &init_css_set,
+};
+
 /* Ditto for the can_fork callback. */
 static unsigned long have_canfork_callback __read_mostly;
 
@@ -236,6 +249,9 @@
  */
 static bool cgroup_ssid_enabled(int ssid)
 {
+	if (CGROUP_SUBSYS_COUNT == 0)
+		return false;
+
 	return static_key_enabled(cgroup_subsys_enabled_key[ssid]);
 }
 
@@ -781,6 +797,8 @@
 
 static void put_css_set(struct css_set *cset)
 {
+	unsigned long flags;
+
 	/*
 	 * Ensure that the refcount doesn't hit zero while any readers
 	 * can see it. Similar to atomic_dec_and_lock(), but for an
@@ -789,9 +807,9 @@
 	if (atomic_add_unless(&cset->refcount, -1, 1))
 		return;
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irqsave(&css_set_lock, flags);
 	put_css_set_locked(cset);
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irqrestore(&css_set_lock, flags);
 }
 
 /*
@@ -1014,11 +1032,11 @@
 
 	/* First see if we already have a cgroup group that matches
 	 * the desired set */
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	cset = find_existing_css_set(old_cset, cgrp, template);
 	if (cset)
 		get_css_set(cset);
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	if (cset)
 		return cset;
@@ -1046,7 +1064,7 @@
 	 * find_existing_css_set() */
 	memcpy(cset->subsys, template, sizeof(cset->subsys));
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	/* Add reference counts and links from the new css_set. */
 	list_for_each_entry(link, &old_cset->cgrp_links, cgrp_link) {
 		struct cgroup *c = link->cgrp;
@@ -1072,7 +1090,7 @@
 		css_get(css);
 	}
 
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	return cset;
 }
@@ -1136,7 +1154,7 @@
 	 * Release all the links from cset_links to this hierarchy's
 	 * root cgroup
 	 */
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 
 	list_for_each_entry_safe(link, tmp_link, &cgrp->cset_links, cset_link) {
 		list_del(&link->cset_link);
@@ -1144,7 +1162,7 @@
 		kfree(link);
 	}
 
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	if (!list_empty(&root->root_list)) {
 		list_del(&root->root_list);
@@ -1159,6 +1177,41 @@
 	cgroup_free_root(root);
 }
 
+/*
+ * look up cgroup associated with current task's cgroup namespace on the
+ * specified hierarchy
+ */
+static struct cgroup *
+current_cgns_cgroup_from_root(struct cgroup_root *root)
+{
+	struct cgroup *res = NULL;
+	struct css_set *cset;
+
+	lockdep_assert_held(&css_set_lock);
+
+	rcu_read_lock();
+
+	cset = current->nsproxy->cgroup_ns->root_cset;
+	if (cset == &init_css_set) {
+		res = &root->cgrp;
+	} else {
+		struct cgrp_cset_link *link;
+
+		list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
+			struct cgroup *c = link->cgrp;
+
+			if (c->root == root) {
+				res = c;
+				break;
+			}
+		}
+	}
+	rcu_read_unlock();
+
+	BUG_ON(!res);
+	return res;
+}
+
 /* look up cgroup associated with given css_set on the specified hierarchy */
 static struct cgroup *cset_cgroup_from_root(struct css_set *cset,
 					    struct cgroup_root *root)
@@ -1548,11 +1601,11 @@
 		ss->root = dst_root;
 		css->cgroup = dcgrp;
 
-		spin_lock_bh(&css_set_lock);
+		spin_lock_irq(&css_set_lock);
 		hash_for_each(css_set_table, i, cset, hlist)
 			list_move_tail(&cset->e_cset_node[ss->id],
 				       &dcgrp->e_csets[ss->id]);
-		spin_unlock_bh(&css_set_lock);
+		spin_unlock_irq(&css_set_lock);
 
 		src_root->subsys_mask &= ~(1 << ssid);
 		scgrp->subtree_control &= ~(1 << ssid);
@@ -1576,6 +1629,33 @@
 	return 0;
 }
 
+static int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node,
+			    struct kernfs_root *kf_root)
+{
+	int len = 0;
+	char *buf = NULL;
+	struct cgroup_root *kf_cgroot = cgroup_root_from_kf(kf_root);
+	struct cgroup *ns_cgroup;
+
+	buf = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	spin_lock_bh(&css_set_lock);
+	ns_cgroup = current_cgns_cgroup_from_root(kf_cgroot);
+	len = kernfs_path_from_node(kf_node, ns_cgroup->kn, buf, PATH_MAX);
+	spin_unlock_bh(&css_set_lock);
+
+	if (len >= PATH_MAX)
+		len = -ERANGE;
+	else if (len > 0) {
+		seq_escape(sf, buf, " \t\n\\");
+		len = 0;
+	}
+	kfree(buf);
+	return len;
+}
+
 static int cgroup_show_options(struct seq_file *seq,
 			       struct kernfs_root *kf_root)
 {
@@ -1762,6 +1842,7 @@
 {
 	int ret = 0;
 	struct cgroup_root *root = cgroup_root_from_kf(kf_root);
+	struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
 	struct cgroup_sb_opts opts;
 	unsigned long added_mask, removed_mask;
 
@@ -1781,6 +1862,13 @@
 		pr_warn("option changes via remount are deprecated (pid=%d comm=%s)\n",
 			task_tgid_nr(current), current->comm);
 
+	/* See cgroup_mount release_agent handling */
+	if (opts.release_agent &&
+	    ((ns->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
 	added_mask = opts.subsys_mask & ~root->subsys_mask;
 	removed_mask = root->subsys_mask & ~opts.subsys_mask;
 
@@ -1829,7 +1917,7 @@
 {
 	struct task_struct *p, *g;
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 
 	if (use_task_css_set_links)
 		goto out_unlock;
@@ -1854,8 +1942,12 @@
 		 * entry won't be deleted though the process has exited.
 		 * Do it while holding siglock so that we don't end up
 		 * racing against cgroup_exit().
+		 *
+		 * Interrupts were already disabled while acquiring
+		 * the css_set_lock, so we do not need to disable it
+		 * again when acquiring the sighand->siglock here.
 		 */
-		spin_lock_irq(&p->sighand->siglock);
+		spin_lock(&p->sighand->siglock);
 		if (!(p->flags & PF_EXITING)) {
 			struct css_set *cset = task_css_set(p);
 
@@ -1864,11 +1956,11 @@
 			list_add_tail(&p->cg_list, &cset->tasks);
 			get_css_set(cset);
 		}
-		spin_unlock_irq(&p->sighand->siglock);
+		spin_unlock(&p->sighand->siglock);
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 out_unlock:
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 }
 
 static void init_cgroup_housekeeping(struct cgroup *cgrp)
@@ -1973,13 +2065,13 @@
 	 * Link the root cgroup in this hierarchy into all the css_set
 	 * objects.
 	 */
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	hash_for_each(css_set_table, i, cset, hlist) {
 		link_css_set(&tmp_links, cset, root_cgrp);
 		if (css_set_populated(cset))
 			cgroup_update_populated(root_cgrp, true);
 	}
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	BUG_ON(!list_empty(&root_cgrp->self.children));
 	BUG_ON(atomic_read(&root->nr_cgrps) != 1);
@@ -2005,6 +2097,7 @@
 			 void *data)
 {
 	struct super_block *pinned_sb = NULL;
+	struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
 	struct cgroup_subsys *ss;
 	struct cgroup_root *root;
 	struct cgroup_sb_opts opts;
@@ -2013,6 +2106,14 @@
 	int i;
 	bool new_sb;
 
+	get_cgroup_ns(ns);
+
+	/* Check if the caller has permission to mount. */
+	if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) {
+		put_cgroup_ns(ns);
+		return ERR_PTR(-EPERM);
+	}
+
 	/*
 	 * The first time anyone tries to mount a cgroup, enable the list
 	 * linking each css_set to its tasks and fix up all existing tasks.
@@ -2126,6 +2227,26 @@
 		goto out_unlock;
 	}
 
+	/*
+	 * We know this subsystem has not yet been bound.  Users in a non-init
+	 * user namespace may only mount hierarchies with no bound subsystems,
+	 * i.e. 'none,name=user1'
+	 */
+	if (!opts.none && !capable(CAP_SYS_ADMIN)) {
+		ret = -EPERM;
+		goto out_unlock;
+	}
+
+	/*
+	 * Release agent gets called with all capabilities,
+	 * require capabilities to set release agent.
+	 */
+	if (opts.release_agent &&
+	    ((ns->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
 	root = kzalloc(sizeof(*root), GFP_KERNEL);
 	if (!root) {
 		ret = -ENOMEM;
@@ -2144,11 +2265,36 @@
 	kfree(opts.release_agent);
 	kfree(opts.name);
 
-	if (ret)
+	if (ret) {
+		put_cgroup_ns(ns);
 		return ERR_PTR(ret);
+	}
 
 	dentry = kernfs_mount(fs_type, flags, root->kf_root,
-				CGROUP_SUPER_MAGIC, &new_sb);
+			      CGROUP_SUPER_MAGIC, &new_sb);
+
+	/*
+	 * In non-init cgroup namespace, instead of root cgroup's
+	 * dentry, we return the dentry corresponding to the
+	 * cgroupns->root_cgrp.
+	 */
+	if (!IS_ERR(dentry) && ns != &init_cgroup_ns) {
+		struct dentry *nsdentry;
+		struct cgroup *cgrp;
+
+		mutex_lock(&cgroup_mutex);
+		spin_lock_bh(&css_set_lock);
+
+		cgrp = cset_cgroup_from_root(ns->root_cset, root);
+
+		spin_unlock_bh(&css_set_lock);
+		mutex_unlock(&cgroup_mutex);
+
+		nsdentry = kernfs_node_dentry(cgrp->kn, dentry->d_sb);
+		dput(dentry);
+		dentry = nsdentry;
+	}
+
 	if (IS_ERR(dentry) || !new_sb)
 		cgroup_put(&root->cgrp);
 
@@ -2161,6 +2307,7 @@
 		deactivate_super(pinned_sb);
 	}
 
+	put_cgroup_ns(ns);
 	return dentry;
 }
 
@@ -2189,8 +2336,39 @@
 	.name = "cgroup",
 	.mount = cgroup_mount,
 	.kill_sb = cgroup_kill_sb,
+	.fs_flags = FS_USERNS_MOUNT,
 };
 
+static char *
+cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
+		      struct cgroup_namespace *ns)
+{
+	int ret;
+	struct cgroup *root = cset_cgroup_from_root(ns->root_cset, cgrp->root);
+
+	ret = kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen);
+	if (ret < 0 || ret >= buflen)
+		return NULL;
+	return buf;
+}
+
+char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen,
+		     struct cgroup_namespace *ns)
+{
+	char *ret;
+
+	mutex_lock(&cgroup_mutex);
+	spin_lock_bh(&css_set_lock);
+
+	ret = cgroup_path_ns_locked(cgrp, buf, buflen, ns);
+
+	spin_unlock_bh(&css_set_lock);
+	mutex_unlock(&cgroup_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cgroup_path_ns);
+
 /**
  * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
  * @task: target task
@@ -2212,20 +2390,21 @@
 	char *path = NULL;
 
 	mutex_lock(&cgroup_mutex);
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 
 	root = idr_get_next(&cgroup_hierarchy_idr, &hierarchy_id);
 
 	if (root) {
 		cgrp = task_cgroup_from_root(task, root);
-		path = cgroup_path(cgrp, buf, buflen);
+		path = cgroup_path_ns_locked(cgrp, buf, buflen,
+					     &init_cgroup_ns);
 	} else {
 		/* if no hierarchy exists, everyone is in "/" */
 		if (strlcpy(buf, "/", buflen) < buflen)
 			path = buf;
 	}
 
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 	mutex_unlock(&cgroup_mutex);
 	return path;
 }
@@ -2400,7 +2579,7 @@
 	 * the new cgroup.  There are no failure cases after here, so this
 	 * is the commit point.
 	 */
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(cset, &tset->src_csets, mg_node) {
 		list_for_each_entry_safe(task, tmp_task, &cset->mg_tasks, cg_list) {
 			struct css_set *from_cset = task_css_set(task);
@@ -2411,7 +2590,7 @@
 			put_css_set_locked(from_cset);
 		}
 	}
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	/*
 	 * Migration is committed, all target tasks are now on dst_csets.
@@ -2440,13 +2619,13 @@
 		}
 	}
 out_release_tset:
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	list_splice_init(&tset->dst_csets, &tset->src_csets);
 	list_for_each_entry_safe(cset, tmp_cset, &tset->src_csets, mg_node) {
 		list_splice_tail_init(&cset->mg_tasks, &cset->tasks);
 		list_del_init(&cset->mg_node);
 	}
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 	return ret;
 }
 
@@ -2463,14 +2642,14 @@
 
 	lockdep_assert_held(&cgroup_mutex);
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	list_for_each_entry_safe(cset, tmp_cset, preloaded_csets, mg_preload_node) {
 		cset->mg_src_cgrp = NULL;
 		cset->mg_dst_cset = NULL;
 		list_del_init(&cset->mg_preload_node);
 		put_css_set_locked(cset);
 	}
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 }
 
 /**
@@ -2498,6 +2677,14 @@
 	lockdep_assert_held(&cgroup_mutex);
 	lockdep_assert_held(&css_set_lock);
 
+	/*
+	 * If ->dead, @src_set is associated with one or more dead cgroups
+	 * and doesn't contain any migratable tasks.  Ignore it early so
+	 * that the rest of migration path doesn't get confused by it.
+	 */
+	if (src_cset->dead)
+		return;
+
 	src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
 
 	if (!list_empty(&src_cset->mg_preload_node))
@@ -2612,7 +2799,7 @@
 	 * already PF_EXITING could be freed from underneath us unless we
 	 * take an rcu_read_lock.
 	 */
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	rcu_read_lock();
 	task = leader;
 	do {
@@ -2621,7 +2808,7 @@
 			break;
 	} while_each_thread(leader, task);
 	rcu_read_unlock();
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	return cgroup_taskset_migrate(&tset, cgrp);
 }
@@ -2642,7 +2829,7 @@
 	int ret;
 
 	/* look up all src csets */
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	rcu_read_lock();
 	task = leader;
 	do {
@@ -2652,7 +2839,7 @@
 			break;
 	} while_each_thread(leader, task);
 	rcu_read_unlock();
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	/* prepare dst csets and commit */
 	ret = cgroup_migrate_prepare_dst(dst_cgrp, &preloaded_csets);
@@ -2667,7 +2854,7 @@
 					 struct cgroup *dst_cgrp,
 					 struct kernfs_open_file *of)
 {
-	const struct cred *cred = current_cred();
+	const struct cred *cred = of->file->f_cred;
 	const struct cred *tcred = get_task_cred(task);
 	int ret = 0;
 
@@ -2684,10 +2871,18 @@
 		struct super_block *sb = of->file->f_path.dentry->d_sb;
 		struct cgroup *cgrp;
 		struct inode *inode;
+		const struct cred *saved_cred;
 
-		spin_lock_bh(&css_set_lock);
+		/*
+		 * Process and thread migrations follow same delegation rule. Check
+		 * permissions using the credentials from file open to protect against
+		 * inherited fd attacks.
+		 */
+		saved_cred = override_creds(of->file->f_cred);
+
+		spin_lock_irq(&css_set_lock);
 		cgrp = task_cgroup_from_root(task, &cgrp_dfl_root);
-		spin_unlock_bh(&css_set_lock);
+		spin_unlock_irq(&css_set_lock);
 
 		while (!cgroup_is_descendant(dst_cgrp, cgrp))
 			cgrp = cgroup_parent(cgrp);
@@ -2698,6 +2893,8 @@
 			ret = inode_permission(inode, MAY_WRITE);
 			iput(inode);
 		}
+
+		revert_creds(saved_cred);
 	}
 
 	put_cred(tcred);
@@ -2713,9 +2910,10 @@
 				    size_t nbytes, loff_t off, bool threadgroup)
 {
 	struct task_struct *tsk;
+	struct cgroup_subsys *ss;
 	struct cgroup *cgrp;
 	pid_t pid;
-	int ret;
+	int ssid, ret;
 
 	if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)
 		return -EINVAL;
@@ -2740,11 +2938,12 @@
 		tsk = tsk->group_leader;
 
 	/*
-	 * Workqueue threads may acquire PF_NO_SETAFFINITY and become
-	 * trapped in a cpuset, or RT worker may be born in a cgroup
-	 * with no rt_runtime allocated.  Just say no.
+	 * kthreads may acquire PF_NO_SETAFFINITY during initialization.
+	 * If userland migrates such a kthread to a non-root cgroup, it can
+	 * become trapped in a cpuset, or RT kthread may be born in a
+	 * cgroup with no rt_runtime allocated.  Just say no.
 	 */
-	if (tsk == kthreadd_task || (tsk->flags & PF_NO_SETAFFINITY)) {
+	if (tsk->no_cgroup_migration || (tsk->flags & PF_NO_SETAFFINITY)) {
 		ret = -EINVAL;
 		goto out_unlock_rcu;
 	}
@@ -2763,6 +2962,9 @@
 	rcu_read_unlock();
 out_unlock_threadgroup:
 	percpu_up_write(&cgroup_threadgroup_rwsem);
+	for_each_subsys(ss, ssid)
+		if (ss->post_attach)
+			ss->post_attach();
 	cgroup_kn_unlock(of->kn);
 	return ret ?: nbytes;
 }
@@ -2784,9 +2986,9 @@
 		if (root == &cgrp_dfl_root)
 			continue;
 
-		spin_lock_bh(&css_set_lock);
+		spin_lock_irq(&css_set_lock);
 		from_cgrp = task_cgroup_from_root(from, root);
-		spin_unlock_bh(&css_set_lock);
+		spin_unlock_irq(&css_set_lock);
 
 		retval = cgroup_attach_task(from_cgrp, tsk, false);
 		if (retval)
@@ -2817,6 +3019,14 @@
 
 	BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
 
+	/*
+	 * Release agent gets called with all capabilities,
+	 * require capabilities to set release agent.
+	 */
+	if ((of->file->f_cred->user_ns != &init_user_ns) ||
+	    !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	cgrp = cgroup_kn_lock_live(of->kn);
 	if (!cgrp)
 		return -ENODEV;
@@ -2911,7 +3121,7 @@
 	percpu_down_write(&cgroup_threadgroup_rwsem);
 
 	/* look up all csses currently attached to @cgrp's subtree */
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	css_for_each_descendant_pre(css, cgroup_css(cgrp, NULL)) {
 		struct cgrp_cset_link *link;
 
@@ -2923,14 +3133,14 @@
 			cgroup_migrate_add_src(link->cset, cgrp,
 					       &preloaded_csets);
 	}
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	/* NULL dst indicates self on default hierarchy */
 	ret = cgroup_migrate_prepare_dst(NULL, &preloaded_csets);
 	if (ret)
 		goto out_finish;
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(src_cset, &preloaded_csets, mg_preload_node) {
 		struct task_struct *task, *ntask;
 
@@ -2942,7 +3152,7 @@
 		list_for_each_entry_safe(task, ntask, &src_cset->tasks, cg_list)
 			cgroup_taskset_add(task, &tset);
 	}
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	ret = cgroup_taskset_migrate(&tset, cgrp);
 out_finish:
@@ -3625,10 +3835,10 @@
 	int count = 0;
 	struct cgrp_cset_link *link;
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(link, &cgrp->cset_links, cset_link)
 		count += atomic_read(&link->cset->refcount);
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 	return count;
 }
 
@@ -3966,7 +4176,7 @@
 
 	memset(it, 0, sizeof(*it));
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 
 	it->ss = css->ss;
 
@@ -3979,7 +4189,7 @@
 
 	css_task_iter_advance_css_set(it);
 
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 }
 
 /**
@@ -3997,7 +4207,7 @@
 		it->cur_task = NULL;
 	}
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 
 	if (it->task_pos) {
 		it->cur_task = list_entry(it->task_pos, struct task_struct,
@@ -4006,7 +4216,7 @@
 		css_task_iter_advance(it);
 	}
 
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	return it->cur_task;
 }
@@ -4020,10 +4230,10 @@
 void css_task_iter_end(struct css_task_iter *it)
 {
 	if (it->cur_cset) {
-		spin_lock_bh(&css_set_lock);
+		spin_lock_irq(&css_set_lock);
 		list_del(&it->iters_node);
 		put_css_set_locked(it->cur_cset);
-		spin_unlock_bh(&css_set_lock);
+		spin_unlock_irq(&css_set_lock);
 	}
 
 	if (it->cur_task)
@@ -4052,10 +4262,10 @@
 	mutex_lock(&cgroup_mutex);
 
 	/* all tasks in @from are being moved, all csets are source */
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(link, &from->cset_links, cset_link)
 		cgroup_migrate_add_src(link->cset, to, &preloaded_csets);
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 
 	ret = cgroup_migrate_prepare_dst(to, &preloaded_csets);
 	if (ret)
@@ -4067,7 +4277,11 @@
 	 */
 	do {
 		css_task_iter_start(&from->self, &it);
-		task = css_task_iter_next(&it);
+
+		do {
+			task = css_task_iter_next(&it);
+		} while (task && (task->flags & PF_EXITING));
+
 		if (task)
 			get_task_struct(task);
 		css_task_iter_end(&it);
@@ -4680,14 +4894,15 @@
 
 	if (ss) {
 		/* css free path */
+		struct cgroup_subsys_state *parent = css->parent;
 		int id = css->id;
 
-		if (css->parent)
-			css_put(css->parent);
-
 		ss->css_free(css);
 		cgroup_idr_remove(&ss->css_idr, id);
 		cgroup_put(cgrp);
+
+		if (parent)
+			css_put(parent);
 	} else {
 		/* cgroup free path */
 		atomic_dec(&cgrp->root->nr_cgrps);
@@ -4780,9 +4995,11 @@
 	memset(css, 0, sizeof(*css));
 	css->cgroup = cgrp;
 	css->ss = ss;
+	css->id = -1;
 	INIT_LIST_HEAD(&css->sibling);
 	INIT_LIST_HEAD(&css->children);
 	css->serial_nr = css_serial_nr_next++;
+	atomic_set(&css->online_cnt, 0);
 
 	if (cgroup_parent(cgrp)) {
 		css->parent = cgroup_css(cgroup_parent(cgrp), ss);
@@ -4805,6 +5022,10 @@
 	if (!ret) {
 		css->flags |= CSS_ONLINE;
 		rcu_assign_pointer(css->cgroup->subsys[ss->id], css);
+
+		atomic_inc(&css->online_cnt);
+		if (css->parent)
+			atomic_inc(&css->parent->online_cnt);
 	}
 	return ret;
 }
@@ -5036,10 +5257,15 @@
 		container_of(work, struct cgroup_subsys_state, destroy_work);
 
 	mutex_lock(&cgroup_mutex);
-	offline_css(css);
-	mutex_unlock(&cgroup_mutex);
 
-	css_put(css);
+	do {
+		offline_css(css);
+		css_put(css);
+		/* @css can't go away while we're holding cgroup_mutex */
+		css = css->parent;
+	} while (css && atomic_dec_and_test(&css->online_cnt));
+
+	mutex_unlock(&cgroup_mutex);
 }
 
 /* css kill confirmation processing requires process context, bounce */
@@ -5048,8 +5274,10 @@
 	struct cgroup_subsys_state *css =
 		container_of(ref, struct cgroup_subsys_state, refcnt);
 
-	INIT_WORK(&css->destroy_work, css_killed_work_fn);
-	queue_work(cgroup_destroy_wq, &css->destroy_work);
+	if (atomic_dec_and_test(&css->online_cnt)) {
+		INIT_WORK(&css->destroy_work, css_killed_work_fn);
+		queue_work(cgroup_destroy_wq, &css->destroy_work);
+	}
 }
 
 /**
@@ -5118,6 +5346,7 @@
 	__releases(&cgroup_mutex) __acquires(&cgroup_mutex)
 {
 	struct cgroup_subsys_state *css;
+	struct cgrp_cset_link *link;
 	int ssid;
 
 	lockdep_assert_held(&cgroup_mutex);
@@ -5138,11 +5367,18 @@
 		return -EBUSY;
 
 	/*
-	 * Mark @cgrp dead.  This prevents further task migration and child
-	 * creation by disabling cgroup_lock_live_group().
+	 * Mark @cgrp and the associated csets dead.  The former prevents
+	 * further task migration and child creation by disabling
+	 * cgroup_lock_live_group().  The latter makes the csets ignored by
+	 * the migration path.
 	 */
 	cgrp->self.flags &= ~CSS_ONLINE;
 
+	spin_lock_irq(&css_set_lock);
+	list_for_each_entry(link, &cgrp->cset_links, cset_link)
+		link->cset->dead = true;
+	spin_unlock_irq(&css_set_lock);
+
 	/* initiate massacre of all css's */
 	for_each_css(css, ssid, cgrp)
 		kill_css(css);
@@ -5182,6 +5418,7 @@
 	.mkdir			= cgroup_mkdir,
 	.rmdir			= cgroup_rmdir,
 	.rename			= cgroup_rename,
+	.show_path		= cgroup_show_path,
 };
 
 static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
@@ -5291,6 +5528,8 @@
 	BUG_ON(cgroup_init_cftypes(NULL, cgroup_dfl_base_files));
 	BUG_ON(cgroup_init_cftypes(NULL, cgroup_legacy_base_files));
 
+	get_user_ns(init_cgroup_ns.user_ns);
+
 	mutex_lock(&cgroup_mutex);
 
 	/* Add init_css_set to the hash table */
@@ -5394,7 +5633,7 @@
 		goto out;
 
 	mutex_lock(&cgroup_mutex);
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 
 	for_each_root(root) {
 		struct cgroup_subsys *ss;
@@ -5427,7 +5666,8 @@
 		 * " (deleted)" is appended to the cgroup path.
 		 */
 		if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) {
-			path = cgroup_path(cgrp, buf, PATH_MAX);
+			path = cgroup_path_ns_locked(cgrp, buf, PATH_MAX,
+						     current->nsproxy->cgroup_ns);
 			if (!path) {
 				retval = -ENAMETOOLONG;
 				goto out_unlock;
@@ -5446,7 +5686,7 @@
 
 	retval = 0;
 out_unlock:
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 	mutex_unlock(&cgroup_mutex);
 	kfree(buf);
 out:
@@ -5607,13 +5847,13 @@
 	if (use_task_css_set_links) {
 		struct css_set *cset;
 
-		spin_lock_bh(&css_set_lock);
+		spin_lock_irq(&css_set_lock);
 		cset = task_css_set(current);
 		if (list_empty(&child->cg_list)) {
 			get_css_set(cset);
 			css_set_move_task(child, NULL, cset, false);
 		}
-		spin_unlock_bh(&css_set_lock);
+		spin_unlock_irq(&css_set_lock);
 	}
 
 	/*
@@ -5657,9 +5897,9 @@
 	cset = task_css_set(tsk);
 
 	if (!list_empty(&tsk->cg_list)) {
-		spin_lock_bh(&css_set_lock);
+		spin_lock_irq(&css_set_lock);
 		css_set_move_task(tsk, cset, NULL, false);
-		spin_unlock_bh(&css_set_lock);
+		spin_unlock_irq(&css_set_lock);
 	} else {
 		get_css_set(cset);
 	}
@@ -5725,7 +5965,10 @@
 	if (!pathbuf || !agentbuf)
 		goto out;
 
-	path = cgroup_path(cgrp, pathbuf, PATH_MAX);
+	spin_lock_bh(&css_set_lock);
+	path = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX,
+				     &init_cgroup_ns);
+	spin_unlock_bh(&css_set_lock);
 	if (!path)
 		goto out;
 
@@ -5822,6 +6065,133 @@
 	return id > 0 ? idr_find(&ss->css_idr, id) : NULL;
 }
 
+/* cgroup namespaces */
+
+static struct cgroup_namespace *alloc_cgroup_ns(void)
+{
+	struct cgroup_namespace *new_ns;
+	int ret;
+
+	new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL);
+	if (!new_ns)
+		return ERR_PTR(-ENOMEM);
+	ret = ns_alloc_inum(&new_ns->ns);
+	if (ret) {
+		kfree(new_ns);
+		return ERR_PTR(ret);
+	}
+	atomic_set(&new_ns->count, 1);
+	new_ns->ns.ops = &cgroupns_operations;
+	return new_ns;
+}
+
+void free_cgroup_ns(struct cgroup_namespace *ns)
+{
+	put_css_set(ns->root_cset);
+	put_user_ns(ns->user_ns);
+	ns_free_inum(&ns->ns);
+	kfree(ns);
+}
+EXPORT_SYMBOL(free_cgroup_ns);
+
+struct cgroup_namespace *
+copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns,
+	       struct cgroup_namespace *old_ns)
+{
+	struct cgroup_namespace *new_ns;
+	struct css_set *cset;
+
+	BUG_ON(!old_ns);
+
+	if (!(flags & CLONE_NEWCGROUP)) {
+		get_cgroup_ns(old_ns);
+		return old_ns;
+	}
+
+	/* Allow only sysadmin to create cgroup namespace. */
+	if (!ns_capable(user_ns, CAP_SYS_ADMIN))
+		return ERR_PTR(-EPERM);
+
+	mutex_lock(&cgroup_mutex);
+	spin_lock_bh(&css_set_lock);
+
+	cset = task_css_set(current);
+	get_css_set(cset);
+
+	spin_unlock_bh(&css_set_lock);
+	mutex_unlock(&cgroup_mutex);
+
+	new_ns = alloc_cgroup_ns();
+	if (IS_ERR(new_ns)) {
+		put_css_set(cset);
+		return new_ns;
+	}
+
+	new_ns->user_ns = get_user_ns(user_ns);
+	new_ns->root_cset = cset;
+
+	return new_ns;
+}
+
+static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
+{
+	return container_of(ns, struct cgroup_namespace, ns);
+}
+
+static int cgroupns_install(struct nsproxy *nsproxy, struct ns_common *ns)
+{
+	struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
+
+	if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN) ||
+	    !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
+		return -EPERM;
+
+	/* Don't need to do anything if we are attaching to our own cgroupns. */
+	if (cgroup_ns == nsproxy->cgroup_ns)
+		return 0;
+
+	get_cgroup_ns(cgroup_ns);
+	put_cgroup_ns(nsproxy->cgroup_ns);
+	nsproxy->cgroup_ns = cgroup_ns;
+
+	return 0;
+}
+
+static struct ns_common *cgroupns_get(struct task_struct *task)
+{
+	struct cgroup_namespace *ns = NULL;
+	struct nsproxy *nsproxy;
+
+	task_lock(task);
+	nsproxy = task->nsproxy;
+	if (nsproxy) {
+		ns = nsproxy->cgroup_ns;
+		get_cgroup_ns(ns);
+	}
+	task_unlock(task);
+
+	return ns ? &ns->ns : NULL;
+}
+
+static void cgroupns_put(struct ns_common *ns)
+{
+	put_cgroup_ns(to_cg_ns(ns));
+}
+
+const struct proc_ns_operations cgroupns_operations = {
+	.name		= "cgroup",
+	.type		= CLONE_NEWCGROUP,
+	.get		= cgroupns_get,
+	.put		= cgroupns_put,
+	.install	= cgroupns_install,
+};
+
+static __init int cgroup_namespaces_init(void)
+{
+	return 0;
+}
+subsys_initcall(cgroup_namespaces_init);
+
 #ifdef CONFIG_CGROUP_DEBUG
 static struct cgroup_subsys_state *
 debug_css_alloc(struct cgroup_subsys_state *parent_css)
@@ -5872,7 +6242,7 @@
 	if (!name_buf)
 		return -ENOMEM;
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	rcu_read_lock();
 	cset = rcu_dereference(current->cgroups);
 	list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
@@ -5883,7 +6253,7 @@
 			   c->root->hierarchy_id, name_buf);
 	}
 	rcu_read_unlock();
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 	kfree(name_buf);
 	return 0;
 }
@@ -5894,7 +6264,7 @@
 	struct cgroup_subsys_state *css = seq_css(seq);
 	struct cgrp_cset_link *link;
 
-	spin_lock_bh(&css_set_lock);
+	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(link, &css->cgroup->cset_links, cset_link) {
 		struct css_set *cset = link->cset;
 		struct task_struct *task;
@@ -5917,7 +6287,7 @@
 	overflow:
 		seq_puts(seq, "  ...\n");
 	}
-	spin_unlock_bh(&css_set_lock);
+	spin_unlock_irq(&css_set_lock);
 	return 0;
 }
 
--- linux-4.4.0.orig/kernel/cgroup_pids.c
+++ linux-4.4.0/kernel/cgroup_pids.c
@@ -48,7 +48,7 @@
 	 * %PIDS_MAX = (%PID_MAX_LIMIT + 1).
 	 */
 	atomic64_t			counter;
-	int64_t				limit;
+	atomic64_t			limit;
 };
 
 static struct pids_cgroup *css_pids(struct cgroup_subsys_state *css)
@@ -70,8 +70,8 @@
 	if (!pids)
 		return ERR_PTR(-ENOMEM);
 
-	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->limit, PIDS_MAX);
 	return &pids->css;
 }
 
@@ -142,13 +142,14 @@
 
 	for (p = pids; parent_pids(p); p = parent_pids(p)) {
 		int64_t new = atomic64_add_return(num, &p->counter);
+		int64_t limit = atomic64_read(&p->limit);
 
 		/*
 		 * Since new is capped to the maximum number of pid_t, if
 		 * p->limit is %PIDS_MAX then we know that this test will never
 		 * fail.
 		 */
-		if (new > p->limit)
+		if (new > limit)
 			goto revert;
 	}
 
@@ -262,7 +263,7 @@
 	 * Limit updates don't need to be mutex'd, since it isn't
 	 * critical that any racing fork()s follow the new limit.
 	 */
-	pids->limit = limit;
+	atomic64_set(&pids->limit, limit);
 	return nbytes;
 }
 
@@ -270,7 +271,7 @@
 {
 	struct cgroup_subsys_state *css = seq_css(sf);
 	struct pids_cgroup *pids = css_pids(css);
-	int64_t limit = pids->limit;
+	int64_t limit = atomic64_read(&pids->limit);
 
 	if (limit >= PIDS_MAX)
 		seq_printf(sf, "%s\n", PIDS_MAX_STR);
--- linux-4.4.0.orig/kernel/configs/tiny.config
+++ linux-4.4.0/kernel/configs/tiny.config
@@ -1,4 +1,12 @@
+# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_KERNEL_XZ=y
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
 CONFIG_OPTIMIZE_INLINING=y
+# CONFIG_SLAB is not set
+# CONFIG_SLUB is not set
 CONFIG_SLOB=y
--- linux-4.4.0.orig/kernel/cpu.c
+++ linux-4.4.0/kernel/cpu.c
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/notifier.h>
 #include <linux/sched.h>
+#include <linux/sched/smt.h>
 #include <linux/unistd.h>
 #include <linux/cpu.h>
 #include <linux/oom.h>
@@ -30,6 +31,11 @@
 /* Serializes the updates to cpu_online_mask, cpu_present_mask */
 static DEFINE_MUTEX(cpu_add_remove_lock);
 
+#ifdef CONFIG_HOTPLUG_SMT
+static DECLARE_BITMAP(cpu_bootonce_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_bootonce_mask = to_cpumask(cpu_bootonce_bits);
+#endif
+
 /*
  * The following two APIs (cpu_maps_update_begin/done) must be used when
  * attempting to serialize the updates to cpu_online_mask & cpu_present_mask.
@@ -183,15 +189,89 @@
 }
 EXPORT_SYMBOL_GPL(cpu_hotplug_disable);
 
+static void __cpu_hotplug_enable(void)
+{
+	if (WARN_ONCE(!cpu_hotplug_disabled, "Unbalanced cpu hotplug enable\n"))
+		return;
+	cpu_hotplug_disabled--;
+}
+
 void cpu_hotplug_enable(void)
 {
 	cpu_maps_update_begin();
-	WARN_ON(--cpu_hotplug_disabled < 0);
+	__cpu_hotplug_enable();
 	cpu_maps_update_done();
 }
 EXPORT_SYMBOL_GPL(cpu_hotplug_enable);
 #endif	/* CONFIG_HOTPLUG_CPU */
 
+/*
+ * Architectures that need SMT-specific errata handling during SMT hotplug
+ * should override this.
+ */
+void __weak arch_smt_update(void) { }
+
+#ifdef CONFIG_HOTPLUG_SMT
+enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED;
+
+void __init cpu_smt_disable(bool force)
+{
+	if (!cpu_smt_possible())
+		return;
+
+	if (force) {
+		pr_info("SMT: Force disabled\n");
+		cpu_smt_control = CPU_SMT_FORCE_DISABLED;
+	} else {
+		cpu_smt_control = CPU_SMT_DISABLED;
+	}
+}
+
+/*
+ * The decision whether SMT is supported can only be done after the full
+ * CPU identification. Called from architecture code.
+ */
+void __init cpu_smt_check_topology(void)
+{
+	if (!topology_smt_supported())
+		cpu_smt_control = CPU_SMT_NOT_SUPPORTED;
+}
+
+static int __init smt_cmdline_disable(char *str)
+{
+	cpu_smt_disable(str && !strcmp(str, "force"));
+	return 0;
+}
+early_param("nosmt", smt_cmdline_disable);
+
+static inline bool cpu_smt_allowed(unsigned int cpu)
+{
+	if (cpu_smt_control == CPU_SMT_ENABLED)
+		return true;
+
+	if (topology_is_primary_thread(cpu))
+		return true;
+
+	/*
+	 * On x86 it's required to boot all logical CPUs at least once so
+	 * that the init code can get a chance to set CR4.MCE on each
+	 * CPU. Otherwise, a broadacasted MCE observing CR4.MCE=0b on any
+	 * core will shutdown the machine.
+	 */
+	return !cpumask_test_cpu(cpu, cpu_bootonce_mask);
+}
+
+/* Returns true if SMT is not supported of forcefully (irreversibly) disabled */
+bool cpu_smt_possible(void)
+{
+	return cpu_smt_control != CPU_SMT_FORCE_DISABLED &&
+		cpu_smt_control != CPU_SMT_NOT_SUPPORTED;
+}
+EXPORT_SYMBOL_GPL(cpu_smt_possible);
+#else
+static inline bool cpu_smt_allowed(unsigned int cpu) { return true; }
+#endif
+
 /* Need to know about CPUs going up/down? */
 int register_cpu_notifier(struct notifier_block *nb)
 {
@@ -223,12 +303,6 @@
 	return __cpu_notify(val, v, -1, NULL);
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-
-static void cpu_notify_nofail(unsigned long val, void *v)
-{
-	BUG_ON(cpu_notify(val, v));
-}
 EXPORT_SYMBOL(register_cpu_notifier);
 EXPORT_SYMBOL(__register_cpu_notifier);
 
@@ -246,6 +320,12 @@
 }
 EXPORT_SYMBOL(__unregister_cpu_notifier);
 
+#ifdef CONFIG_HOTPLUG_CPU
+static void cpu_notify_nofail(unsigned long val, void *v)
+{
+	BUG_ON(cpu_notify(val, v));
+}
+
 /**
  * clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU
  * @cpu: a CPU id
@@ -353,7 +433,6 @@
 		return -EINVAL;
 
 	cpu_hotplug_begin();
-
 	err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls);
 	if (err) {
 		nr_calls--;
@@ -427,23 +506,24 @@
 	cpu_hotplug_done();
 	if (!err)
 		cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu);
+	arch_smt_update();
 	return err;
 }
 
+int cpu_down_maps_locked(unsigned int cpu)
+{
+	if (cpu_hotplug_disabled)
+		return -EBUSY;
+	return _cpu_down(cpu, 0);
+}
+EXPORT_SYMBOL(cpu_down_maps_locked);
+
 int cpu_down(unsigned int cpu)
 {
 	int err;
 
 	cpu_maps_update_begin();
-
-	if (cpu_hotplug_disabled) {
-		err = -EBUSY;
-		goto out;
-	}
-
-	err = _cpu_down(cpu, 0);
-
-out:
+	err = cpu_down_maps_locked(cpu);
 	cpu_maps_update_done();
 	return err;
 }
@@ -517,9 +597,12 @@
 
 	/* Arch-specific enabling code. */
 	ret = __cpu_up(cpu, idle);
-
 	if (ret != 0)
 		goto out_notify;
+
+#ifdef CONFIG_HOTPLUG_SMT
+	cpumask_set_cpu(cpu, to_cpumask(cpu_bootonce_bits));
+#endif
 	BUG_ON(!cpu_online(cpu));
 
 	/* Now call notifier in preparation. */
@@ -530,7 +613,7 @@
 		__cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
 out:
 	cpu_hotplug_done();
-
+	arch_smt_update();
 	return ret;
 }
 
@@ -557,6 +640,10 @@
 		err = -EBUSY;
 		goto out;
 	}
+	if (!cpu_smt_allowed(cpu)) {
+		err = -EPERM;
+		goto out;
+	}
 
 	err = _cpu_up(cpu, 0);
 
@@ -626,7 +713,7 @@
 
 	/* Allow everyone to use the CPU hotplug again */
 	cpu_maps_update_begin();
-	WARN_ON(--cpu_hotplug_disabled < 0);
+	__cpu_hotplug_enable();
 	if (cpumask_empty(frozen_cpus))
 		goto out;
 
@@ -728,6 +815,169 @@
 	cpu_notify(val, (void *)(long)cpu);
 }
 
+#ifdef CONFIG_HOTPLUG_SMT
+
+static const char *smt_states[] = {
+	[CPU_SMT_ENABLED]		= "on",
+	[CPU_SMT_DISABLED]		= "off",
+	[CPU_SMT_FORCE_DISABLED]	= "forceoff",
+	[CPU_SMT_NOT_SUPPORTED]		= "notsupported",
+};
+
+static ssize_t
+show_smt_control(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE - 2, "%s\n", smt_states[cpu_smt_control]);
+}
+
+static void cpuhp_offline_cpu_device(unsigned int cpu)
+{
+	struct device *dev = get_cpu_device(cpu);
+
+	dev->offline = true;
+	/* Tell user space about the state change */
+	kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
+}
+
+static void cpuhp_online_cpu_device(unsigned int cpu)
+{
+	struct device *dev = get_cpu_device(cpu);
+
+	dev->offline = false;
+	/* Tell user space about the state change */
+	kobject_uevent(&dev->kobj, KOBJ_ONLINE);
+}
+
+static int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
+{
+	int cpu, ret = 0;
+
+	cpu_maps_update_begin();
+	for_each_online_cpu(cpu) {
+		if (topology_is_primary_thread(cpu))
+			continue;
+		ret = cpu_down_maps_locked(cpu);
+		if (ret)
+			break;
+		/*
+		 * As this needs to hold the cpu maps lock it's impossible
+		 * to call device_offline() because that ends up calling
+		 * cpu_down() which takes cpu maps lock. cpu maps lock
+		 * needs to be held as this might race against in kernel
+		 * abusers of the hotplug machinery (thermal management).
+		 *
+		 * So nothing would update device:offline state. That would
+		 * leave the sysfs entry stale and prevent onlining after
+		 * smt control has been changed to 'off' again. This is
+		 * called under the sysfs hotplug lock, so it is properly
+		 * serialized against the regular offline usage.
+		 */
+		cpuhp_offline_cpu_device(cpu);
+	}
+	if (!ret)
+		cpu_smt_control = ctrlval;
+	cpu_maps_update_done();
+	return ret;
+}
+
+static int cpuhp_smt_enable(void)
+{
+	int cpu, ret = 0;
+
+	cpu_maps_update_begin();
+	cpu_smt_control = CPU_SMT_ENABLED;
+	for_each_present_cpu(cpu) {
+		/* Skip online CPUs and CPUs on offline nodes */
+		if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))
+			continue;
+		ret = _cpu_up(cpu, 0);
+		if (ret)
+			break;
+		/* See comment in cpuhp_smt_disable() */
+		cpuhp_online_cpu_device(cpu);
+	}
+	cpu_maps_update_done();
+	return ret;
+}
+
+static ssize_t
+store_smt_control(struct device *dev, struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	int ctrlval, ret;
+
+	if (sysfs_streq(buf, "on"))
+		ctrlval = CPU_SMT_ENABLED;
+	else if (sysfs_streq(buf, "off"))
+		ctrlval = CPU_SMT_DISABLED;
+	else if (sysfs_streq(buf, "forceoff"))
+		ctrlval = CPU_SMT_FORCE_DISABLED;
+	else
+		return -EINVAL;
+
+	if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
+		return -EPERM;
+
+	if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
+		return -ENODEV;
+
+	ret = lock_device_hotplug_sysfs();
+	if (ret)
+		return ret;
+
+	if (ctrlval != cpu_smt_control) {
+		switch (ctrlval) {
+		case CPU_SMT_ENABLED:
+			ret = cpuhp_smt_enable();
+			break;
+		case CPU_SMT_DISABLED:
+		case CPU_SMT_FORCE_DISABLED:
+			ret = cpuhp_smt_disable(ctrlval);
+			break;
+		}
+	}
+
+	unlock_device_hotplug();
+	return ret ? ret : count;
+}
+static DEVICE_ATTR(control, 0644, show_smt_control, store_smt_control);
+
+static ssize_t
+show_smt_active(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	bool active = topology_max_smt_threads() > 1;
+
+	return snprintf(buf, PAGE_SIZE - 2, "%d\n", active);
+}
+static DEVICE_ATTR(active, 0444, show_smt_active, NULL);
+
+static struct attribute *cpuhp_smt_attrs[] = {
+	&dev_attr_control.attr,
+	&dev_attr_active.attr,
+	NULL
+};
+
+static const struct attribute_group cpuhp_smt_attr_group = {
+	.attrs = cpuhp_smt_attrs,
+	.name = "smt",
+	NULL
+};
+
+static int __init cpu_smt_state_init(void)
+{
+	return sysfs_create_group(&cpu_subsys.dev_root->kobj,
+				  &cpuhp_smt_attr_group);
+}
+
+#else
+static inline int cpu_smt_state_init(void) { return 0; }
+#endif /* CONFIG_HOTPLUG_SMT */
+
+static int __init cpuhp_sysfs_init(void)
+{
+	return cpu_smt_state_init();
+}
+device_initcall(cpuhp_sysfs_init);
 #endif /* CONFIG_SMP */
 
 /*
@@ -827,3 +1077,46 @@
 {
 	cpumask_copy(to_cpumask(cpu_online_bits), src);
 }
+
+/*
+ * These are used for a global "mitigations=" cmdline option for toggling
+ * optional CPU mitigations.
+ */
+enum cpu_mitigations {
+	CPU_MITIGATIONS_OFF,
+	CPU_MITIGATIONS_AUTO,
+	CPU_MITIGATIONS_AUTO_NOSMT,
+};
+
+static enum cpu_mitigations cpu_mitigations __ro_after_init =
+	CPU_MITIGATIONS_AUTO;
+
+static int __init mitigations_parse_cmdline(char *arg)
+{
+	if (!strcmp(arg, "off"))
+		cpu_mitigations = CPU_MITIGATIONS_OFF;
+	else if (!strcmp(arg, "auto"))
+		cpu_mitigations = CPU_MITIGATIONS_AUTO;
+	else if (!strcmp(arg, "auto,nosmt"))
+		cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT;
+	else
+		pr_crit("Unsupported mitigations=%s, system may still be vulnerable\n",
+			arg);
+
+	return 0;
+}
+early_param("mitigations", mitigations_parse_cmdline);
+
+/* mitigations=off */
+bool cpu_mitigations_off(void)
+{
+	return cpu_mitigations == CPU_MITIGATIONS_OFF;
+}
+EXPORT_SYMBOL_GPL(cpu_mitigations_off);
+
+/* mitigations=auto,nosmt */
+bool cpu_mitigations_auto_nosmt(void)
+{
+	return cpu_mitigations == CPU_MITIGATIONS_AUTO_NOSMT;
+}
+EXPORT_SYMBOL_GPL(cpu_mitigations_auto_nosmt);
--- linux-4.4.0.orig/kernel/cpu_pm.c
+++ linux-4.4.0/kernel/cpu_pm.c
@@ -97,7 +97,7 @@
  */
 int cpu_pm_enter(void)
 {
-	int nr_calls;
+	int nr_calls = 0;
 	int ret = 0;
 
 	read_lock(&cpu_pm_notifier_lock);
@@ -156,7 +156,7 @@
  */
 int cpu_cluster_pm_enter(void)
 {
-	int nr_calls;
+	int nr_calls = 0;
 	int ret = 0;
 
 	read_lock(&cpu_pm_notifier_lock);
--- linux-4.4.0.orig/kernel/cpuset.c
+++ linux-4.4.0/kernel/cpuset.c
@@ -57,10 +57,10 @@
 #include <asm/uaccess.h>
 #include <linux/atomic.h>
 #include <linux/mutex.h>
-#include <linux/workqueue.h>
 #include <linux/cgroup.h>
 #include <linux/wait.h>
 
+struct static_key cpusets_pre_enable_key __read_mostly = STATIC_KEY_INIT_FALSE;
 struct static_key cpusets_enabled_key __read_mostly = STATIC_KEY_INIT_FALSE;
 
 /* See "Frequency meter" comments, below. */
@@ -174,9 +174,9 @@
 } cpuset_flagbits_t;
 
 /* convenient tests for these bits */
-static inline bool is_cpuset_online(const struct cpuset *cs)
+static inline bool is_cpuset_online(struct cpuset *cs)
 {
-	return test_bit(CS_ONLINE, &cs->flags);
+	return test_bit(CS_ONLINE, &cs->flags) && !css_is_dying(&cs->css);
 }
 
 static inline int is_cpu_exclusive(const struct cpuset *cs)
@@ -286,6 +286,8 @@
 static DEFINE_MUTEX(cpuset_mutex);
 static DEFINE_SPINLOCK(callback_lock);
 
+static struct workqueue_struct *cpuset_migrate_mm_wq;
+
 /*
  * CPU / memory hotplug is handled asynchronously.
  */
@@ -323,8 +325,7 @@
 /*
  * Return in pmask the portion of a cpusets's cpus_allowed that
  * are online.  If none are online, walk up the cpuset hierarchy
- * until we find one that does have some online cpus.  The top
- * cpuset always has some cpus online.
+ * until we find one that does have some online cpus.
  *
  * One way or another, we guarantee to return some non-empty subset
  * of cpu_online_mask.
@@ -333,8 +334,20 @@
  */
 static void guarantee_online_cpus(struct cpuset *cs, struct cpumask *pmask)
 {
-	while (!cpumask_intersects(cs->effective_cpus, cpu_online_mask))
+	while (!cpumask_intersects(cs->effective_cpus, cpu_online_mask)) {
 		cs = parent_cs(cs);
+		if (unlikely(!cs)) {
+			/*
+			 * The top cpuset doesn't have any online cpu as a
+			 * consequence of a race between cpuset_hotplug_work
+			 * and cpu hotplug notifier.  But we know the top
+			 * cpuset's effective_cpus is on its way to to be
+			 * identical to cpu_online_mask.
+			 */
+			cpumask_copy(pmask, cpu_online_mask);
+			return;
+		}
+	}
 	cpumask_and(pmask, cs->effective_cpus, cpu_online_mask);
 }
 
@@ -971,31 +984,51 @@
 }
 
 /*
- * cpuset_migrate_mm
- *
- *    Migrate memory region from one set of nodes to another.
- *
- *    Temporarilly set tasks mems_allowed to target nodes of migration,
- *    so that the migration code can allocate pages on these nodes.
- *
- *    While the mm_struct we are migrating is typically from some
- *    other task, the task_struct mems_allowed that we are hacking
- *    is for our current task, which must allocate new pages for that
- *    migrating memory region.
+ * Migrate memory region from one set of nodes to another.  This is
+ * performed asynchronously as it can be called from process migration path
+ * holding locks involved in process management.  All mm migrations are
+ * performed in the queued order and can be waited for by flushing
+ * cpuset_migrate_mm_wq.
  */
 
+struct cpuset_migrate_mm_work {
+	struct work_struct	work;
+	struct mm_struct	*mm;
+	nodemask_t		from;
+	nodemask_t		to;
+};
+
+static void cpuset_migrate_mm_workfn(struct work_struct *work)
+{
+	struct cpuset_migrate_mm_work *mwork =
+		container_of(work, struct cpuset_migrate_mm_work, work);
+
+	/* on a wq worker, no need to worry about %current's mems_allowed */
+	do_migrate_pages(mwork->mm, &mwork->from, &mwork->to, MPOL_MF_MOVE_ALL);
+	mmput(mwork->mm);
+	kfree(mwork);
+}
+
 static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
 							const nodemask_t *to)
 {
-	struct task_struct *tsk = current;
-
-	tsk->mems_allowed = *to;
+	struct cpuset_migrate_mm_work *mwork;
 
-	do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
+	mwork = kzalloc(sizeof(*mwork), GFP_KERNEL);
+	if (mwork) {
+		mwork->mm = mm;
+		mwork->from = *from;
+		mwork->to = *to;
+		INIT_WORK(&mwork->work, cpuset_migrate_mm_workfn);
+		queue_work(cpuset_migrate_mm_wq, &mwork->work);
+	} else {
+		mmput(mm);
+	}
+}
 
-	rcu_read_lock();
-	guarantee_online_mems(task_cs(tsk), &tsk->mems_allowed);
-	rcu_read_unlock();
+static void cpuset_post_attach(void)
+{
+	flush_workqueue(cpuset_migrate_mm_wq);
 }
 
 /*
@@ -1096,7 +1129,8 @@
 		mpol_rebind_mm(mm, &cs->mems_allowed);
 		if (migrate)
 			cpuset_migrate_mm(mm, &cs->old_mems_allowed, &newmems);
-		mmput(mm);
+		else
+			mmput(mm);
 	}
 	css_task_iter_end(&it);
 
@@ -1541,11 +1575,11 @@
 			 * @old_mems_allowed is the right nodesets that we
 			 * migrate mm from.
 			 */
-			if (is_memory_migrate(cs)) {
+			if (is_memory_migrate(cs))
 				cpuset_migrate_mm(mm, &oldcs->old_mems_allowed,
 						  &cpuset_attach_nodemask_to);
-			}
-			mmput(mm);
+			else
+				mmput(mm);
 		}
 	}
 
@@ -1710,6 +1744,7 @@
 	mutex_unlock(&cpuset_mutex);
 	kernfs_unbreak_active_protection(of->kn);
 	css_put(&cs->css);
+	flush_workqueue(cpuset_migrate_mm_wq);
 	return retval ?: nbytes;
 }
 
@@ -1875,6 +1910,7 @@
 	{
 		.name = "memory_pressure",
 		.read_u64 = cpuset_read_u64,
+		.private = FILE_MEMORY_PRESSURE,
 	},
 
 	{
@@ -2051,6 +2087,20 @@
 	mutex_unlock(&cpuset_mutex);
 }
 
+/*
+ * Make sure the new task conform to the current state of its parent,
+ * which could have been changed by cpuset just after it inherits the
+ * state from the parent and before it sits on the cgroup's task list.
+ */
+void cpuset_fork(struct task_struct *task, void *priv)
+{
+	if (task_css_is_root(task, cpuset_cgrp_id))
+		return;
+
+	set_cpus_allowed_ptr(task, &current->cpus_allowed);
+	task->mems_allowed = current->mems_allowed;
+}
+
 struct cgroup_subsys cpuset_cgrp_subsys = {
 	.css_alloc	= cpuset_css_alloc,
 	.css_online	= cpuset_css_online,
@@ -2059,7 +2109,9 @@
 	.can_attach	= cpuset_can_attach,
 	.cancel_attach	= cpuset_cancel_attach,
 	.attach		= cpuset_attach,
+	.post_attach	= cpuset_post_attach,
 	.bind		= cpuset_bind,
+	.fork		= cpuset_fork,
 	.legacy_cftypes	= files,
 	.early_init	= 1,
 };
@@ -2229,6 +2281,13 @@
 	mutex_unlock(&cpuset_mutex);
 }
 
+static bool force_rebuild;
+
+void cpuset_force_rebuild(void)
+{
+	force_rebuild = true;
+}
+
 /**
  * cpuset_hotplug_workfn - handle CPU/memory hotunplug for a cpuset
  *
@@ -2303,8 +2362,10 @@
 	}
 
 	/* rebuild sched domains if cpus_allowed has changed */
-	if (cpus_updated)
+	if (cpus_updated || force_rebuild) {
+		force_rebuild = false;
 		rebuild_sched_domains();
+	}
 }
 
 void cpuset_update_active_cpus(bool cpu_online)
@@ -2323,6 +2384,11 @@
 	schedule_work(&cpuset_hotplug_work);
 }
 
+void cpuset_wait_for_hotplug(void)
+{
+	flush_work(&cpuset_hotplug_work);
+}
+
 /*
  * Keep top_cpuset.mems_allowed tracking node_states[N_MEMORY].
  * Call this routine anytime after node_states[N_MEMORY] changes.
@@ -2355,6 +2421,9 @@
 	top_cpuset.effective_mems = node_states[N_MEMORY];
 
 	register_hotmemory_notifier(&cpuset_track_online_nodes_nb);
+
+	cpuset_migrate_mm_wq = alloc_ordered_workqueue("cpuset_migrate_mm", 0);
+	BUG_ON(!cpuset_migrate_mm_wq);
 }
 
 /**
@@ -2683,10 +2752,10 @@
 		goto out;
 
 	retval = -ENAMETOOLONG;
-	rcu_read_lock();
-	css = task_css(tsk, cpuset_cgrp_id);
-	p = cgroup_path(css->cgroup, buf, PATH_MAX);
-	rcu_read_unlock();
+	css = task_get_css(tsk, cpuset_cgrp_id);
+	p = cgroup_path_ns(css->cgroup, buf, PATH_MAX,
+			   current->nsproxy->cgroup_ns);
+	css_put(css);
 	if (!p)
 		goto out_free;
 	seq_puts(m, p);
--- linux-4.4.0.orig/kernel/cred.c
+++ linux-4.4.0/kernel/cred.c
@@ -146,7 +146,10 @@
 	BUG_ON(cred == current->cred);
 	BUG_ON(cred == current->real_cred);
 
-	call_rcu(&cred->rcu, put_cred_rcu);
+	if (cred->non_rcu)
+		put_cred_rcu(&cred->rcu);
+	else
+		call_rcu(&cred->rcu, put_cred_rcu);
 }
 EXPORT_SYMBOL(__put_cred);
 
@@ -257,6 +260,7 @@
 	old = task->cred;
 	memcpy(new, old, sizeof(struct cred));
 
+	new->non_rcu = 0;
 	atomic_set(&new->usage, 1);
 	set_cred_subscribers(new, 0);
 	get_group_info(new->group_info);
@@ -447,6 +451,15 @@
 		if (task->mm)
 			set_dumpable(task->mm, suid_dumpable);
 		task->pdeath_signal = 0;
+		/*
+		 * If a task drops privileges and becomes nondumpable,
+		 * the dumpability change must become visible before
+		 * the credential change; otherwise, a __ptrace_may_access()
+		 * racing with this change may be able to attach to a task it
+		 * shouldn't be able to attach to (as if the task had dropped
+		 * privileges without becoming nondumpable).
+		 * Pairs with a read barrier in __ptrace_may_access().
+		 */
 		smp_wmb();
 	}
 
@@ -527,7 +540,19 @@
 
 	validate_creds(old);
 	validate_creds(new);
-	get_cred(new);
+
+	/*
+	 * NOTE! This uses 'get_new_cred()' rather than 'get_cred()'.
+	 *
+	 * That means that we do not clear the 'non_rcu' flag, since
+	 * we are only installing the cred into the thread-synchronous
+	 * '->cred' pointer, not the '->real_cred' pointer that is
+	 * visible to other threads under RCU.
+	 *
+	 * Also note that we did validate_creds() manually, not depending
+	 * on the validation in 'get_cred()'.
+	 */
+	get_new_cred((struct cred *)new);
 	alter_cred_subscribers(new, 1);
 	rcu_assign_pointer(current->cred, new);
 	alter_cred_subscribers(old, -1);
@@ -610,6 +635,7 @@
 	validate_creds(old);
 
 	*new = *old;
+	new->non_rcu = 0;
 	atomic_set(&new->usage, 1);
 	set_cred_subscribers(new, 0);
 	get_uid(new->user);
@@ -689,6 +715,8 @@
  */
 int set_create_files_as(struct cred *new, struct inode *inode)
 {
+	if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+		return -EINVAL;
 	new->fsuid = inode->i_uid;
 	new->fsgid = inode->i_gid;
 	return security_kernel_create_files_as(new, inode);
--- linux-4.4.0.orig/kernel/debug/debug_core.c
+++ linux-4.4.0/kernel/debug/debug_core.c
@@ -94,14 +94,6 @@
 /* Use kdb or gdbserver mode */
 int dbg_kdb_mode = 1;
 
-static int __init opt_kgdb_con(char *str)
-{
-	kgdb_use_con = 1;
-	return 0;
-}
-
-early_param("kgdbcon", opt_kgdb_con);
-
 module_param(kgdb_use_con, int, 0644);
 module_param(kgdbreboot, int, 0644);
 
@@ -443,6 +435,7 @@
 
 	if (exception_level > 1) {
 		dump_stack();
+		kgdb_io_module_registered = false;
 		panic("Recursive entry to debugger");
 	}
 
@@ -487,6 +480,7 @@
 		arch_kgdb_ops.disable_hw_break(regs);
 
 acquirelock:
+	rcu_read_lock();
 	/*
 	 * Interrupts will be restored by the 'trap return' code, except when
 	 * single stepping.
@@ -541,6 +535,7 @@
 			atomic_dec(&slaves_in_kgdb);
 			dbg_touch_watchdogs();
 			local_irq_restore(flags);
+			rcu_read_unlock();
 			return 0;
 		}
 		cpu_relax();
@@ -559,6 +554,7 @@
 		raw_spin_unlock(&dbg_master_lock);
 		dbg_touch_watchdogs();
 		local_irq_restore(flags);
+		rcu_read_unlock();
 
 		goto acquirelock;
 	}
@@ -598,11 +594,11 @@
 	/*
 	 * Wait for the other CPUs to be notified and be waiting for us:
 	 */
-	time_left = loops_per_jiffy * HZ;
+	time_left = MSEC_PER_SEC;
 	while (kgdb_do_roundup && --time_left &&
 	       (atomic_read(&masters_in_kgdb) + atomic_read(&slaves_in_kgdb)) !=
 		   online_cpus)
-		cpu_relax();
+		udelay(1000);
 	if (!time_left)
 		pr_crit("Timed out waiting for secondary CPUs.\n");
 
@@ -620,6 +616,8 @@
 
 	while (1) {
 cpu_master_loop:
+		if (secure_modules())
+			break;
 		if (dbg_kdb_mode) {
 			kgdb_connected = 1;
 			error = kdb_stub(ks);
@@ -676,6 +674,7 @@
 	raw_spin_unlock(&dbg_master_lock);
 	dbg_touch_watchdogs();
 	local_irq_restore(flags);
+	rcu_read_unlock();
 
 	return kgdb_info[cpu].ret_state;
 }
@@ -806,6 +805,20 @@
 	.index		= -1,
 };
 
+static int __init opt_kgdb_con(char *str)
+{
+	kgdb_use_con = 1;
+
+	if (kgdb_io_module_registered && !kgdb_con_registered) {
+		register_console(&kgdbcons);
+		kgdb_con_registered = 1;
+	}
+
+	return 0;
+}
+
+early_param("kgdbcon", opt_kgdb_con);
+
 #ifdef CONFIG_MAGIC_SYSRQ
 static void sysrq_handle_dbg(int key)
 {
--- linux-4.4.0.orig/kernel/debug/kdb/kdb_io.c
+++ linux-4.4.0/kernel/debug/kdb/kdb_io.c
@@ -215,7 +215,7 @@
 	int count;
 	int i;
 	int diag, dtab_count;
-	int key;
+	int key, buf_size, ret;
 
 
 	diag = kdbgetintenv("DTABCOUNT", &dtab_count);
@@ -335,9 +335,8 @@
 		else
 			p_tmp = tmpbuffer;
 		len = strlen(p_tmp);
-		count = kallsyms_symbol_complete(p_tmp,
-						 sizeof(tmpbuffer) -
-						 (p_tmp - tmpbuffer));
+		buf_size = sizeof(tmpbuffer) - (p_tmp - tmpbuffer);
+		count = kallsyms_symbol_complete(p_tmp, buf_size);
 		if (tab == 2 && count > 0) {
 			kdb_printf("\n%d symbols are found.", count);
 			if (count > dtab_count) {
@@ -349,9 +348,13 @@
 			}
 			kdb_printf("\n");
 			for (i = 0; i < count; i++) {
-				if (kallsyms_symbol_next(p_tmp, i) < 0)
+				ret = kallsyms_symbol_next(p_tmp, i, buf_size);
+				if (WARN_ON(!ret))
 					break;
-				kdb_printf("%s ", p_tmp);
+				if (ret != -E2BIG)
+					kdb_printf("%s ", p_tmp);
+				else
+					kdb_printf("%s... ", p_tmp);
 				*(p_tmp + len) = '\0';
 			}
 			if (i >= dtab_count)
@@ -680,12 +683,16 @@
 			size_avail = sizeof(kdb_buffer) - len;
 			goto kdb_print_out;
 		}
-		if (kdb_grepping_flag >= KDB_GREPPING_FLAG_SEARCH)
+		if (kdb_grepping_flag >= KDB_GREPPING_FLAG_SEARCH) {
 			/*
 			 * This was a interactive search (using '/' at more
-			 * prompt) and it has completed. Clear the flag.
+			 * prompt) and it has completed. Replace the \0 with
+			 * its original value to ensure multi-line strings
+			 * are handled properly, and return to normal mode.
 			 */
+			*cphold = replaced_byte;
 			kdb_grepping_flag = 0;
+		}
 		/*
 		 * at this point the string is a full line and
 		 * should be printed, up to the null.
--- linux-4.4.0.orig/kernel/debug/kdb/kdb_main.c
+++ linux-4.4.0/kernel/debug/kdb/kdb_main.c
@@ -1564,6 +1564,7 @@
 	int symbolic = 0;
 	int valid = 0;
 	int phys = 0;
+	int raw = 0;
 
 	kdbgetintenv("MDCOUNT", &mdcount);
 	kdbgetintenv("RADIX", &radix);
@@ -1573,9 +1574,10 @@
 	repeat = mdcount * 16 / bytesperword;
 
 	if (strcmp(argv[0], "mdr") == 0) {
-		if (argc != 2)
+		if (argc == 2 || (argc == 0 && last_addr != 0))
+			valid = raw = 1;
+		else
 			return KDB_ARGCOUNT;
-		valid = 1;
 	} else if (isdigit(argv[0][2])) {
 		bytesperword = (int)(argv[0][2] - '0');
 		if (bytesperword == 0) {
@@ -1611,7 +1613,10 @@
 		radix = last_radix;
 		bytesperword = last_bytesperword;
 		repeat = last_repeat;
-		mdcount = ((repeat * bytesperword) + 15) / 16;
+		if (raw)
+			mdcount = repeat;
+		else
+			mdcount = ((repeat * bytesperword) + 15) / 16;
 	}
 
 	if (argc) {
@@ -1628,7 +1633,10 @@
 			diag = kdbgetularg(argv[nextarg], &val);
 			if (!diag) {
 				mdcount = (int) val;
-				repeat = mdcount * 16 / bytesperword;
+				if (raw)
+					repeat = mdcount;
+				else
+					repeat = mdcount * 16 / bytesperword;
 			}
 		}
 		if (argc >= nextarg+1) {
@@ -1638,8 +1646,15 @@
 		}
 	}
 
-	if (strcmp(argv[0], "mdr") == 0)
-		return kdb_mdr(addr, mdcount);
+	if (strcmp(argv[0], "mdr") == 0) {
+		int ret;
+		last_addr = addr;
+		ret = kdb_mdr(addr, mdcount);
+		last_addr += mdcount;
+		last_repeat = mdcount;
+		last_bytesperword = bytesperword; // to make REPEAT happy
+		return ret;
+	}
 
 	switch (radix) {
 	case 10:
@@ -2021,7 +2036,7 @@
 			continue;
 
 		kdb_printf("%-20s%8u  0x%p ", mod->name,
-			   mod->core_size, (void *)mod);
+			   mod->core_layout.size, (void *)mod);
 #ifdef CONFIG_MODULE_UNLOAD
 		kdb_printf("%4d ", module_refcount(mod));
 #endif
@@ -2031,7 +2046,7 @@
 			kdb_printf(" (Loading)");
 		else
 			kdb_printf(" (Live)");
-		kdb_printf(" 0x%p", mod->module_core);
+		kdb_printf(" 0x%p", mod->core_layout.base);
 
 #ifdef CONFIG_MODULE_UNLOAD
 		{
@@ -2617,7 +2632,7 @@
 		diag = kdbgetularg(argv[3], &whichcpu);
 		if (diag)
 			return diag;
-		if (!cpu_online(whichcpu)) {
+		if (whichcpu >= nr_cpu_ids || !cpu_online(whichcpu)) {
 			kdb_printf("cpu %ld is not online\n", whichcpu);
 			return KDB_BADCPUNUM;
 		}
--- linux-4.4.0.orig/kernel/debug/kdb/kdb_private.h
+++ linux-4.4.0/kernel/debug/kdb/kdb_private.h
@@ -83,7 +83,7 @@
 		unsigned long sym_start;
 		unsigned long sym_end;
 		} kdb_symtab_t;
-extern int kallsyms_symbol_next(char *prefix_name, int flag);
+extern int kallsyms_symbol_next(char *prefix_name, int flag, int buf_size);
 extern int kallsyms_symbol_complete(char *prefix_name, int max_len);
 
 /* Exported Symbols for kernel loadable modules to use. */
@@ -234,7 +234,7 @@
 #define	kdb_do_each_thread(g, p) do_each_thread(g, p)
 #define	kdb_while_each_thread(g, p) while_each_thread(g, p)
 
-#define GFP_KDB (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
+#define GFP_KDB (in_dbg_master() ? GFP_ATOMIC : GFP_KERNEL)
 
 extern void *debug_kmalloc(size_t size, gfp_t flags);
 extern void debug_kfree(void *);
--- linux-4.4.0.orig/kernel/debug/kdb/kdb_support.c
+++ linux-4.4.0/kernel/debug/kdb/kdb_support.c
@@ -129,13 +129,13 @@
 		}
 		if (i >= ARRAY_SIZE(kdb_name_table)) {
 			debug_kfree(kdb_name_table[0]);
-			memcpy(kdb_name_table, kdb_name_table+1,
+			memmove(kdb_name_table, kdb_name_table+1,
 			       sizeof(kdb_name_table[0]) *
 			       (ARRAY_SIZE(kdb_name_table)-1));
 		} else {
 			debug_kfree(knt1);
 			knt1 = kdb_name_table[i];
-			memcpy(kdb_name_table+i, kdb_name_table+i+1,
+			memmove(kdb_name_table+i, kdb_name_table+i+1,
 			       sizeof(kdb_name_table[0]) *
 			       (ARRAY_SIZE(kdb_name_table)-i-1));
 		}
@@ -221,11 +221,13 @@
  * Parameters:
  *	prefix_name	prefix of a symbol name to lookup
  *	flag	0 means search from the head, 1 means continue search.
+ *	buf_size	maximum length that can be written to prefix_name
+ *			buffer
  * Returns:
  *	1 if a symbol matches the given prefix.
  *	0 if no string found
  */
-int kallsyms_symbol_next(char *prefix_name, int flag)
+int kallsyms_symbol_next(char *prefix_name, int flag, int buf_size)
 {
 	int prefix_len = strlen(prefix_name);
 	static loff_t pos;
@@ -235,10 +237,8 @@
 		pos = 0;
 
 	while ((name = kdb_walk_kallsyms(&pos))) {
-		if (strncmp(name, prefix_name, prefix_len) == 0) {
-			strncpy(prefix_name, name, strlen(name)+1);
-			return 1;
-		}
+		if (!strncmp(name, prefix_name, prefix_len))
+			return strscpy(prefix_name, name, buf_size);
 	}
 	return 0;
 }
--- linux-4.4.0.orig/kernel/events/callchain.c
+++ linux-4.4.0/kernel/events/callchain.c
@@ -107,14 +107,8 @@
 		goto exit;
 	}
 
-	if (count > 1) {
-		/* If the allocation failed, give up */
-		if (!callchain_cpus_entries)
-			err = -ENOMEM;
-		goto exit;
-	}
-
-	err = alloc_callchain_buffers();
+	if (count == 1)
+		err = alloc_callchain_buffers();
 exit:
 	if (err)
 		atomic_dec(&nr_callchain_events);
--- linux-4.4.0.orig/kernel/events/core.c
+++ linux-4.4.0/kernel/events/core.c
@@ -229,7 +229,7 @@
 				void __user *buffer, size_t *lenp,
 				loff_t *ppos)
 {
-	int ret = proc_dointvec(table, write, buffer, lenp, ppos);
+	int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 
 	if (ret || !write)
 		return ret;
@@ -419,9 +419,15 @@
 
 static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
 {
-	struct perf_cgroup *cgrp_out = cpuctx->cgrp;
-	if (cgrp_out)
-		__update_cgrp_time(cgrp_out);
+	struct perf_cgroup *cgrp = cpuctx->cgrp;
+	struct cgroup_subsys_state *css;
+
+	if (cgrp) {
+		for (css = &cgrp->css; css; css = css->parent) {
+			cgrp = container_of(css, struct perf_cgroup, css);
+			__update_cgrp_time(cgrp);
+		}
+	}
 }
 
 static inline void update_cgrp_time_from_event(struct perf_event *event)
@@ -449,6 +455,7 @@
 {
 	struct perf_cgroup *cgrp;
 	struct perf_cgroup_info *info;
+	struct cgroup_subsys_state *css;
 
 	/*
 	 * ctx->lock held by caller
@@ -459,8 +466,12 @@
 		return;
 
 	cgrp = perf_cgroup_from_task(task, ctx);
-	info = this_cpu_ptr(cgrp->info);
-	info->timestamp = ctx->timestamp;
+
+	for (css = &cgrp->css; css; css = css->parent) {
+		cgrp = container_of(css, struct perf_cgroup, css);
+		info = this_cpu_ptr(cgrp->info);
+		info->timestamp = ctx->timestamp;
+	}
 }
 
 #define PERF_CGROUP_SWOUT	0x1 /* cgroup switch out every event */
@@ -946,6 +957,7 @@
  * function.
  *
  * Lock order:
+ *    cred_guard_mutex
  *	task_struct::perf_event_mutex
  *	  perf_event_context::mutex
  *	    perf_event_context::lock
@@ -1253,28 +1265,31 @@
 					      PERF_EVENT_STATE_INACTIVE;
 }
 
-static void __perf_event_read_size(struct perf_event *event, int nr_siblings)
+static int __perf_event_read_size(u64 read_format, int nr_siblings)
 {
 	int entry = sizeof(u64); /* value */
 	int size = 0;
 	int nr = 1;
 
-	if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
 		size += sizeof(u64);
 
-	if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
 		size += sizeof(u64);
 
-	if (event->attr.read_format & PERF_FORMAT_ID)
+	if (read_format & PERF_FORMAT_ID)
 		entry += sizeof(u64);
 
-	if (event->attr.read_format & PERF_FORMAT_GROUP) {
+	if (read_format & PERF_FORMAT_GROUP) {
 		nr += nr_siblings;
 		size += sizeof(u64);
 	}
 
-	size += entry * nr;
-	event->read_size = size;
+	/*
+	 * Since perf_event_validate_size() limits this to 16k and inhibits
+	 * adding more siblings, this will never overflow.
+	 */
+	return size + nr * entry;
 }
 
 static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
@@ -1312,8 +1327,9 @@
  */
 static void perf_event__header_size(struct perf_event *event)
 {
-	__perf_event_read_size(event,
-			       event->group_leader->nr_siblings);
+	event->read_size =
+		__perf_event_read_size(event->attr.read_format,
+				       event->group_leader->nr_siblings);
 	__perf_event_header_size(event, event->attr.sample_type);
 }
 
@@ -1344,23 +1360,44 @@
 	event->id_header_size = size;
 }
 
+/*
+ * Check that adding an event to the group does not result in anybody
+ * overflowing the 64k event limit imposed by the output buffer.
+ *
+ * Specifically, check that the read_size for the event does not exceed 16k,
+ * read_size being the one term that grows with groups size. Since read_size
+ * depends on per-event read_format, also (re)check the existing events.
+ *
+ * This leaves 48k for the constant size fields and things like callchains,
+ * branch stacks and register sets.
+ */
 static bool perf_event_validate_size(struct perf_event *event)
 {
-	/*
-	 * The values computed here will be over-written when we actually
-	 * attach the event.
-	 */
-	__perf_event_read_size(event, event->group_leader->nr_siblings + 1);
-	__perf_event_header_size(event, event->attr.sample_type & ~PERF_SAMPLE_READ);
-	perf_event__id_header_size(event);
+	struct perf_event *sibling, *group_leader = event->group_leader;
+
+	if (__perf_event_read_size(event->attr.read_format,
+				   group_leader->nr_siblings + 1) > 16*1024)
+		return false;
+
+	if (__perf_event_read_size(group_leader->attr.read_format,
+				   group_leader->nr_siblings + 1) > 16*1024)
+		return false;
 
 	/*
-	 * Sum the lot; should not exceed the 64k limit we have on records.
-	 * Conservative limit to allow for callchains and other variable fields.
+	 * When creating a new group leader, group_leader->ctx is initialized
+	 * after the size has been validated, but we cannot safely use
+	 * for_each_sibling_event() until group_leader->ctx is set. A new group
+	 * leader cannot have any siblings yet, so we can safely skip checking
+	 * the non-existent siblings.
 	 */
-	if (event->read_size + event->header_size +
-	    event->id_header_size + sizeof(struct perf_event_header) >= 16*1024)
-		return false;
+	if (event == group_leader)
+		return true;
+
+	list_for_each_entry(sibling, &group_leader->sibling_list, group_entry) {
+		if (__perf_event_read_size(sibling->attr.read_format,
+					   group_leader->nr_siblings + 1) > 16*1024)
+			return false;
+	}
 
 	return true;
 }
@@ -1388,6 +1425,7 @@
 
 	list_add_tail(&event->group_entry, &group_leader->sibling_list);
 	group_leader->nr_siblings++;
+	group_leader->group_generation++;
 
 	perf_event__header_size(group_leader);
 
@@ -1470,6 +1508,7 @@
 	if (event->group_leader != event) {
 		list_del_init(&event->group_entry);
 		event->group_leader->nr_siblings--;
+		event->group_leader->group_generation++;
 		goto out;
 	}
 
@@ -1538,12 +1577,33 @@
 
 core_initcall(perf_workqueue_init);
 
-static inline int pmu_filter_match(struct perf_event *event)
+static inline int __pmu_filter_match(struct perf_event *event)
 {
 	struct pmu *pmu = event->pmu;
 	return pmu->filter_match ? pmu->filter_match(event) : 1;
 }
 
+/*
+ * Check whether we should attempt to schedule an event group based on
+ * PMU-specific filtering. An event group can consist of HW and SW events,
+ * potentially with a SW leader, so we must check all the filters, to
+ * determine whether a group is schedulable:
+ */
+static inline int pmu_filter_match(struct perf_event *event)
+{
+	struct perf_event *child;
+
+	if (!__pmu_filter_match(event))
+		return 0;
+
+	list_for_each_entry(child, &event->sibling_list, group_entry) {
+		if (!__pmu_filter_match(child))
+			return 0;
+	}
+
+	return 1;
+}
+
 static inline int
 event_filter_match(struct perf_event *event)
 {
@@ -1580,14 +1640,14 @@
 
 	perf_pmu_disable(event->pmu);
 
+	event->tstamp_stopped = tstamp;
+	event->pmu->del(event, 0);
+	event->oncpu = -1;
 	event->state = PERF_EVENT_STATE_INACTIVE;
 	if (event->pending_disable) {
 		event->pending_disable = 0;
 		event->state = PERF_EVENT_STATE_OFF;
 	}
-	event->tstamp_stopped = tstamp;
-	event->pmu->del(event, 0);
-	event->oncpu = -1;
 
 	if (!is_software_event(event))
 		cpuctx->active_oncpu--;
@@ -3418,7 +3478,6 @@
 find_lively_task_by_vpid(pid_t vpid)
 {
 	struct task_struct *task;
-	int err;
 
 	rcu_read_lock();
 	if (!vpid)
@@ -3432,16 +3491,7 @@
 	if (!task)
 		return ERR_PTR(-ESRCH);
 
-	/* Reuse ptrace permission checks for now. */
-	err = -EACCES;
-	if (!ptrace_may_access(task, PTRACE_MODE_READ))
-		goto errout;
-
 	return task;
-errout:
-	put_task_struct(task);
-	return ERR_PTR(err);
-
 }
 
 /*
@@ -3804,11 +3854,21 @@
 
 static void put_event(struct perf_event *event)
 {
-	struct perf_event_context *ctx;
+	struct perf_event_context *ctx = event->ctx;
 
 	if (!atomic_long_dec_and_test(&event->refcount))
 		return;
 
+	/*
+	 * If we got here through err_file: fput(event_file); we will not have
+	 * attached to a context yet.
+	 */
+	if (!ctx) {
+		WARN_ON_ONCE(event->attach_state &
+				(PERF_ATTACH_CONTEXT|PERF_ATTACH_GROUP));
+		goto no_ctx;
+	}
+
 	if (!is_kernel_event(event))
 		perf_remove_from_owner(event);
 
@@ -3829,6 +3889,7 @@
 	perf_remove_from_context(event, true);
 	perf_event_ctx_unlock(event, ctx);
 
+no_ctx:
 	_free_event(event);
 }
 
@@ -3917,7 +3978,9 @@
 static int __perf_read_group_add(struct perf_event *leader,
 					u64 read_format, u64 *values)
 {
-	struct perf_event *sub;
+	struct perf_event_context *ctx = leader->ctx;
+	struct perf_event *sub, *parent;
+	unsigned long flags;
 	int n = 1; /* skip @nr */
 	int ret;
 
@@ -3925,6 +3988,35 @@
 	if (ret)
 		return ret;
 
+	raw_spin_lock_irqsave(&ctx->lock, flags);
+	/*
+	 * Verify the grouping between the parent and child (inherited)
+	 * events is still in tact.
+	 *
+	 * Specifically:
+	 *  - leader->ctx->lock pins leader->sibling_list
+	 *  - parent->child_mutex pins parent->child_list
+	 *  - parent->ctx->mutex pins parent->sibling_list
+	 *
+	 * Because parent->ctx != leader->ctx (and child_list nests inside
+	 * ctx->mutex), group destruction is not atomic between children, also
+	 * see perf_event_release_kernel(). Additionally, parent can grow the
+	 * group.
+	 *
+	 * Therefore it is possible to have parent and child groups in a
+	 * different configuration and summing over such a beast makes no sense
+	 * what so ever.
+	 *
+	 * Reject this.
+	 */
+	parent = leader->parent;
+	if (parent &&
+	    (parent->group_generation != leader->group_generation ||
+	     parent->nr_siblings != leader->nr_siblings)) {
+		ret = -ECHILD;
+		goto unlock;
+	}
+
 	/*
 	 * Since we co-schedule groups, {enabled,running} times of siblings
 	 * will be identical to those of the leader, so we only publish one
@@ -3953,7 +4045,9 @@
 			values[n++] = primary_event_id(sub);
 	}
 
-	return 0;
+unlock:
+	raw_spin_unlock_irqrestore(&ctx->lock, flags);
+	return ret;
 }
 
 static int perf_read_group(struct perf_event *event,
@@ -3972,10 +4066,6 @@
 
 	values[0] = 1 + leader->nr_siblings;
 
-	/*
-	 * By locking the child_mutex of the leader we effectively
-	 * lock the child list of all siblings.. XXX explain how.
-	 */
 	mutex_lock(&leader->child_mutex);
 
 	ret = __perf_read_group_add(leader, read_format, values);
@@ -4636,11 +4726,11 @@
 static void perf_mmap_close(struct vm_area_struct *vma)
 {
 	struct perf_event *event = vma->vm_file->private_data;
-
 	struct ring_buffer *rb = ring_buffer_get(event);
 	struct user_struct *mmap_user = rb->mmap_user;
 	int mmap_locked = rb->mmap_locked;
 	unsigned long size = perf_data_size(rb);
+	bool detach_rest = false;
 
 	if (event->pmu->event_unmapped)
 		event->pmu->event_unmapped(event);
@@ -4659,7 +4749,8 @@
 		mutex_unlock(&event->mmap_mutex);
 	}
 
-	atomic_dec(&rb->mmap_count);
+	if (atomic_dec_and_test(&rb->mmap_count))
+		detach_rest = true;
 
 	if (!atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex))
 		goto out_put;
@@ -4668,7 +4759,7 @@
 	mutex_unlock(&event->mmap_mutex);
 
 	/* If there's still other mmap()s of this buffer, we're done. */
-	if (atomic_read(&rb->mmap_count))
+	if (!detach_rest)
 		goto out_put;
 
 	/*
@@ -4864,7 +4955,15 @@
 	 */
 	user_lock_limit *= num_online_cpus();
 
-	user_locked = atomic_long_read(&user->locked_vm) + user_extra;
+	user_locked = atomic_long_read(&user->locked_vm);
+
+	/*
+	 * sysctl_perf_event_mlock may have changed, so that
+	 *     user->locked_vm > user_lock_limit
+	 */
+	if (user_locked > user_lock_limit)
+		user_locked = user_lock_limit;
+	user_locked += user_extra;
 
 	if (user_locked > user_lock_limit)
 		extra = user_locked - user_lock_limit;
@@ -5055,7 +5154,7 @@
 	if (user_mode(regs)) {
 		regs_user->abi = perf_reg_abi(current);
 		regs_user->regs = regs;
-	} else if (current->mm) {
+	} else if (!(current->flags & PF_KTHREAD)) {
 		perf_get_regs_user(regs_user, regs, regs_user_copy);
 	} else {
 		regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
@@ -5259,9 +5358,6 @@
 	__output_copy(handle, values, n * sizeof(u64));
 }
 
-/*
- * XXX PERF_FORMAT_GROUP vs inherited events seems difficult.
- */
 static void perf_output_read_group(struct perf_output_handle *handle,
 			    struct perf_event *event,
 			    u64 enabled, u64 running)
@@ -5279,7 +5375,8 @@
 	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
 		values[n++] = running;
 
-	if (leader != event)
+	if ((leader != event) &&
+	    (leader->state == PERF_EVENT_STATE_ACTIVE))
 		leader->pmu->read(leader);
 
 	values[n++] = perf_event_count(leader);
@@ -5306,6 +5403,13 @@
 #define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\
 				 PERF_FORMAT_TOTAL_TIME_RUNNING)
 
+/*
+ * XXX PERF_SAMPLE_READ vs inherited events seems difficult.
+ *
+ * The problem is that its both hard and excessively expensive to iterate the
+ * child list, not to mention that its impossible to IPI the children running
+ * on another CPU, from interrupt/NMI context.
+ */
 static void perf_output_read(struct perf_output_handle *handle,
 			     struct perf_event *event)
 {
@@ -5774,10 +5878,17 @@
 		goto out;
 
 	task_event->event_id.pid = perf_event_pid(event, task);
-	task_event->event_id.ppid = perf_event_pid(event, current);
-
 	task_event->event_id.tid = perf_event_tid(event, task);
-	task_event->event_id.ptid = perf_event_tid(event, current);
+
+	if (task_event->event_id.header.type == PERF_RECORD_EXIT) {
+		task_event->event_id.ppid = perf_event_pid(event,
+							task->real_parent);
+		task_event->event_id.ptid = perf_event_pid(event,
+							task->real_parent);
+	} else {  /* PERF_RECORD_FORK */
+		task_event->event_id.ppid = perf_event_pid(event, current);
+		task_event->event_id.ptid = perf_event_tid(event, current);
+	}
 
 	task_event->event_id.time = perf_event_clock(event);
 
@@ -5970,6 +6081,7 @@
 	struct perf_output_handle handle;
 	struct perf_sample_data sample;
 	int size = mmap_event->event_id.header.size;
+	u32 type = mmap_event->event_id.header.type;
 	int ret;
 
 	if (!perf_event_mmap_match(event, data))
@@ -6013,6 +6125,7 @@
 	perf_output_end(&handle);
 out:
 	mmap_event->event_id.header.size = size;
+	mmap_event->event_id.header.type = type;
 }
 
 static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
@@ -6027,6 +6140,27 @@
 	char *buf = NULL;
 	char *name;
 
+	if (vma->vm_flags & VM_READ)
+		prot |= PROT_READ;
+	if (vma->vm_flags & VM_WRITE)
+		prot |= PROT_WRITE;
+	if (vma->vm_flags & VM_EXEC)
+		prot |= PROT_EXEC;
+
+	if (vma->vm_flags & VM_MAYSHARE)
+		flags = MAP_SHARED;
+	else
+		flags = MAP_PRIVATE;
+
+	if (vma->vm_flags & VM_DENYWRITE)
+		flags |= MAP_DENYWRITE;
+	if (vma->vm_flags & VM_MAYEXEC)
+		flags |= MAP_EXECUTABLE;
+	if (vma->vm_flags & VM_LOCKED)
+		flags |= MAP_LOCKED;
+	if (vma->vm_flags & VM_HUGETLB)
+		flags |= MAP_HUGETLB;
+
 	if (file) {
 		struct inode *inode;
 		dev_t dev;
@@ -6053,27 +6187,6 @@
 		maj = MAJOR(dev);
 		min = MINOR(dev);
 
-		if (vma->vm_flags & VM_READ)
-			prot |= PROT_READ;
-		if (vma->vm_flags & VM_WRITE)
-			prot |= PROT_WRITE;
-		if (vma->vm_flags & VM_EXEC)
-			prot |= PROT_EXEC;
-
-		if (vma->vm_flags & VM_MAYSHARE)
-			flags = MAP_SHARED;
-		else
-			flags = MAP_PRIVATE;
-
-		if (vma->vm_flags & VM_DENYWRITE)
-			flags |= MAP_DENYWRITE;
-		if (vma->vm_flags & VM_MAYEXEC)
-			flags |= MAP_EXECUTABLE;
-		if (vma->vm_flags & VM_LOCKED)
-			flags |= MAP_LOCKED;
-		if (vma->vm_flags & VM_HUGETLB)
-			flags |= MAP_HUGETLB;
-
 		goto got_name;
 	} else {
 		if (vma->vm_ops && vma->vm_ops->name) {
@@ -6990,6 +7103,8 @@
 			goto unlock;
 
 		list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
+			if (event->cpu != smp_processor_id())
+				continue;
 			if (event->attr.type != PERF_TYPE_TRACEPOINT)
 				continue;
 			if (event->attr.config != entry->type)
@@ -7096,6 +7211,7 @@
 	}
 
 	event->tp_event->prog = prog;
+	event->tp_event->bpf_prog_owner = event;
 
 	return 0;
 }
@@ -7108,7 +7224,7 @@
 		return;
 
 	prog = event->tp_event->prog;
-	if (prog) {
+	if (prog && event->tp_event->bpf_prog_owner == event) {
 		event->tp_event->prog = NULL;
 		bpf_prog_put(prog);
 	}
@@ -7945,9 +8061,10 @@
 	local64_set(&hwc->period_left, hwc->sample_period);
 
 	/*
-	 * we currently do not support PERF_FORMAT_GROUP on inherited events
+	 * We currently do not support PERF_SAMPLE_READ on inherited events.
+	 * See perf_output_read().
 	 */
-	if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP))
+	if (attr->inherit && (attr->sample_type & PERF_SAMPLE_READ))
 		goto err_ns;
 
 	if (!has_branch_stack(event))
@@ -7979,6 +8096,9 @@
 		}
 	}
 
+	/* symmetric to unaccount_event() in _free_event() */
+	account_event(event);
+
 	return event;
 
 err_per_task:
@@ -8112,9 +8232,9 @@
 		 * __u16 sample size limit.
 		 */
 		if (attr->sample_stack_user >= USHRT_MAX)
-			ret = -EINVAL;
+			return -EINVAL;
 		else if (!IS_ALIGNED(attr->sample_stack_user, sizeof(u64)))
-			ret = -EINVAL;
+			return -EINVAL;
 	}
 
 	if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
@@ -8235,6 +8355,37 @@
 	return 0;
 }
 
+/*
+ * Variation on perf_event_ctx_lock_nested(), except we take two context
+ * mutexes.
+ */
+static struct perf_event_context *
+__perf_event_ctx_lock_double(struct perf_event *group_leader,
+			     struct perf_event_context *ctx)
+{
+	struct perf_event_context *gctx;
+
+again:
+	rcu_read_lock();
+	gctx = READ_ONCE(group_leader->ctx);
+	if (!atomic_inc_not_zero(&gctx->refcount)) {
+		rcu_read_unlock();
+		goto again;
+	}
+	rcu_read_unlock();
+
+	mutex_lock_double(&gctx->mutex, &ctx->mutex);
+
+	if (group_leader->ctx != gctx) {
+		mutex_unlock(&ctx->mutex);
+		mutex_unlock(&gctx->mutex);
+		put_ctx(gctx);
+		goto again;
+	}
+
+	return gctx;
+}
+
 /**
  * sys_perf_event_open - open a performance event, associate it to a task/cpu
  *
@@ -8325,6 +8476,24 @@
 
 	get_online_cpus();
 
+	if (task) {
+		err = mutex_lock_interruptible(&task->signal->cred_guard_mutex);
+		if (err)
+			goto err_cpus;
+
+		/*
+		 * Reuse ptrace permission checks for now.
+		 *
+		 * We must hold cred_guard_mutex across this and any potential
+		 * perf_install_in_context() call for this new event to
+		 * serialize against exec() altering our credentials (and the
+		 * perf_event_exit_task() that could imply).
+		 */
+		err = -EACCES;
+		if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS))
+			goto err_cred;
+	}
+
 	if (flags & PERF_FLAG_PID_CGROUP)
 		cgroup_fd = pid;
 
@@ -8332,7 +8501,7 @@
 				 NULL, NULL, cgroup_fd);
 	if (IS_ERR(event)) {
 		err = PTR_ERR(event);
-		goto err_cpus;
+		goto err_cred;
 	}
 
 	if (is_sampling_event(event)) {
@@ -8342,8 +8511,6 @@
 		}
 	}
 
-	account_event(event);
-
 	/*
 	 * Special case software events and allow them to be part of
 	 * any hardware group.
@@ -8393,11 +8560,6 @@
 		goto err_context;
 	}
 
-	if (task) {
-		put_task_struct(task);
-		task = NULL;
-	}
-
 	/*
 	 * Look up the group leader (we will attach this event to it):
 	 */
@@ -8416,28 +8578,30 @@
 			goto err_context;
 
 		/*
-		 * Do not allow to attach to a group in a different
-		 * task or CPU context:
+		 * Make sure we're both events for the same CPU;
+		 * grouping events for different CPUs is broken; since
+		 * you can never concurrently schedule them anyhow.
 		 */
-		if (move_group) {
-			/*
-			 * Make sure we're both on the same task, or both
-			 * per-cpu events.
-			 */
-			if (group_leader->ctx->task != ctx->task)
-				goto err_context;
+		if (group_leader->cpu != event->cpu)
+			goto err_context;
 
-			/*
-			 * Make sure we're both events for the same CPU;
-			 * grouping events for different CPUs is broken; since
-			 * you can never concurrently schedule them anyhow.
-			 */
-			if (group_leader->cpu != event->cpu)
-				goto err_context;
-		} else {
-			if (group_leader->ctx != ctx)
-				goto err_context;
-		}
+		/*
+		 * Make sure we're both on the same task, or both
+		 * per-CPU events.
+		 */
+		if (group_leader->ctx->task != ctx->task)
+			goto err_context;
+
+		/*
+		 * Do not allow to attach to a group in a different task
+		 * or CPU context. If we're moving SW events, we'll fix
+		 * this up later, so allow that.
+		 *
+		 * Racy, not holding group_leader->ctx->mutex, see comment with
+		 * perf_event_ctx_lock().
+		 */
+		if (!move_group && group_leader->ctx != ctx)
+			goto err_context;
 
 		/*
 		 * Only a group leader can be exclusive or pinned
@@ -8456,15 +8620,45 @@
 					f_flags);
 	if (IS_ERR(event_file)) {
 		err = PTR_ERR(event_file);
+		event_file = NULL;
 		goto err_context;
 	}
 
 	if (move_group) {
-		gctx = group_leader->ctx;
-		mutex_lock_double(&gctx->mutex, &ctx->mutex);
+		gctx = __perf_event_ctx_lock_double(group_leader, ctx);
+
+		/*
+		 * Check if we raced against another sys_perf_event_open() call
+		 * moving the software group underneath us.
+		 */
+		if (!(group_leader->group_flags & PERF_GROUP_SOFTWARE)) {
+			/*
+			 * If someone moved the group out from under us, check
+			 * if this new event wound up on the same ctx, if so
+			 * its the regular !move_group case, otherwise fail.
+			 */
+			if (gctx != ctx) {
+				err = -EINVAL;
+				goto err_locked;
+			} else {
+				perf_event_ctx_unlock(group_leader, gctx);
+				move_group = 0;
+				goto not_move_group;
+			}
+		}
 	} else {
 		mutex_lock(&ctx->mutex);
+
+		/*
+		 * Now that we hold ctx->lock, (re)validate group_leader->ctx == ctx,
+		 * see the group_leader && !move_group test earlier.
+		 */
+		if (group_leader && group_leader->ctx != ctx) {
+			err = -EINVAL;
+			goto err_locked;
+		}
 	}
+not_move_group:
 
 	if (!perf_event_validate_size(event)) {
 		err = -E2BIG;
@@ -8485,6 +8679,11 @@
 
 	WARN_ON_ONCE(ctx->parent_ctx);
 
+	/*
+	 * This is the point on no return; we cannot fail hereafter. This is
+	 * where we start modifying current state.
+	 */
+
 	if (move_group) {
 		/*
 		 * See perf_event_ctx_lock() for comments on the details
@@ -8551,9 +8750,14 @@
 	perf_unpin_context(ctx);
 
 	if (move_group)
-		mutex_unlock(&gctx->mutex);
+		perf_event_ctx_unlock(group_leader, gctx);
 	mutex_unlock(&ctx->mutex);
 
+	if (task) {
+		mutex_unlock(&task->signal->cred_guard_mutex);
+		put_task_struct(task);
+	}
+
 	put_online_cpus();
 
 	event->owner = current;
@@ -8574,7 +8778,7 @@
 
 err_locked:
 	if (move_group)
-		mutex_unlock(&gctx->mutex);
+		perf_event_ctx_unlock(group_leader, gctx);
 	mutex_unlock(&ctx->mutex);
 /* err_file: */
 	fput(event_file);
@@ -8582,7 +8786,15 @@
 	perf_unpin_context(ctx);
 	put_ctx(ctx);
 err_alloc:
-	free_event(event);
+	/*
+	 * If event_file is set, the fput() above will have called ->release()
+	 * and that will take care of freeing the event.
+	 */
+	if (!event_file)
+		free_event(event);
+err_cred:
+	if (task)
+		mutex_unlock(&task->signal->cred_guard_mutex);
 err_cpus:
 	put_online_cpus();
 err_task:
@@ -8626,8 +8838,6 @@
 	/* Mark owner so we could distinguish it from user events. */
 	event->owner = EVENT_OWNER_KERNEL;
 
-	account_event(event);
-
 	ctx = find_get_context(event->pmu, task, event);
 	if (IS_ERR(ctx)) {
 		err = PTR_ERR(ctx);
@@ -8644,7 +8854,7 @@
 		goto err_free;
 	}
 
-	perf_install_in_context(ctx, event, cpu);
+	perf_install_in_context(ctx, event, event->cpu);
 	perf_unpin_context(ctx);
 	mutex_unlock(&ctx->mutex);
 
@@ -8864,6 +9074,9 @@
 
 /*
  * When a child task exits, feed back event values to parent events.
+ *
+ * Can be called with cred_guard_mutex held when called from
+ * install_exec_creds().
  */
 void perf_event_exit_task(struct task_struct *child)
 {
@@ -9098,6 +9311,7 @@
 		if (IS_ERR(child_ctr))
 			return PTR_ERR(child_ctr);
 	}
+	leader->group_generation = parent_event->group_generation;
 	return 0;
 }
 
@@ -9185,7 +9399,7 @@
 		ret = inherit_task_group(event, parent, parent_ctx,
 					 child, ctxn, &inherited_all);
 		if (ret)
-			break;
+			goto out_unlock;
 	}
 
 	/*
@@ -9201,7 +9415,7 @@
 		ret = inherit_task_group(event, parent, parent_ctx,
 					 child, ctxn, &inherited_all);
 		if (ret)
-			break;
+			goto out_unlock;
 	}
 
 	raw_spin_lock_irqsave(&parent_ctx->lock, flags);
@@ -9229,6 +9443,7 @@
 	}
 
 	raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
+out_unlock:
 	mutex_unlock(&parent_ctx->mutex);
 
 	perf_unpin_context(parent_ctx);
--- linux-4.4.0.orig/kernel/events/hw_breakpoint.c
+++ linux-4.4.0/kernel/events/hw_breakpoint.c
@@ -427,16 +427,9 @@
  * modify_user_hw_breakpoint - modify a user-space hardware breakpoint
  * @bp: the breakpoint structure to modify
  * @attr: new breakpoint attributes
- * @triggered: callback to trigger when we hit the breakpoint
- * @tsk: pointer to 'task_struct' of the process to which the address belongs
  */
 int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
 {
-	u64 old_addr = bp->attr.bp_addr;
-	u64 old_len = bp->attr.bp_len;
-	int old_type = bp->attr.bp_type;
-	int err = 0;
-
 	/*
 	 * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it
 	 * will not be possible to raise IPIs that invoke __perf_event_disable.
@@ -451,27 +444,18 @@
 	bp->attr.bp_addr = attr->bp_addr;
 	bp->attr.bp_type = attr->bp_type;
 	bp->attr.bp_len = attr->bp_len;
+	bp->attr.disabled = 1;
 
-	if (attr->disabled)
-		goto end;
-
-	err = validate_hw_breakpoint(bp);
-	if (!err)
-		perf_event_enable(bp);
+	if (!attr->disabled) {
+		int err = validate_hw_breakpoint(bp);
 
-	if (err) {
-		bp->attr.bp_addr = old_addr;
-		bp->attr.bp_type = old_type;
-		bp->attr.bp_len = old_len;
-		if (!bp->attr.disabled)
-			perf_event_enable(bp);
+		if (err)
+			return err;
 
-		return err;
+		perf_event_enable(bp);
+		bp->attr.disabled = 0;
 	}
 
-end:
-	bp->attr.disabled = attr->disabled;
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
--- linux-4.4.0.orig/kernel/events/internal.h
+++ linux-4.4.0/kernel/events/internal.h
@@ -193,7 +193,7 @@
 		rctx = 3;
 	else if (in_irq())
 		rctx = 2;
-	else if (in_softirq())
+	else if (in_serving_softirq())
 		rctx = 1;
 	else
 		rctx = 0;
--- linux-4.4.0.orig/kernel/events/ring_buffer.c
+++ linux-4.4.0/kernel/events/ring_buffer.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/circ_buf.h>
 #include <linux/poll.h>
+#include <linux/nospec.h>
 
 #include "internal.h"
 
@@ -48,14 +49,30 @@
 	unsigned long head;
 
 again:
+	/*
+	 * In order to avoid publishing a head value that goes backwards,
+	 * we must ensure the load of @rb->head happens after we've
+	 * incremented @rb->nest.
+	 *
+	 * Otherwise we can observe a @rb->head value before one published
+	 * by an IRQ/NMI happening between the load and the increment.
+	 */
+	barrier();
 	head = local_read(&rb->head);
 
 	/*
-	 * IRQ/NMI can happen here, which means we can miss a head update.
+	 * IRQ/NMI can happen here and advance @rb->head, causing our
+	 * load above to be stale.
 	 */
 
-	if (!local_dec_and_test(&rb->nest))
+	/*
+	 * If this isn't the outermost nesting, we don't have to update
+	 * @rb->user_page->data_head.
+	 */
+	if (local_read(&rb->nest) > 1) {
+		local_dec(&rb->nest);
 		goto out;
+	}
 
 	/*
 	 * Since the mmap() consumer (userspace) can run on a different CPU:
@@ -87,9 +104,18 @@
 	rb->user_page->data_head = head;
 
 	/*
-	 * Now check if we missed an update -- rely on previous implied
-	 * compiler barriers to force a re-read.
+	 * We must publish the head before decrementing the nest count,
+	 * otherwise an IRQ/NMI can publish a more recent head value and our
+	 * write will (temporarily) publish a stale value.
 	 */
+	barrier();
+	local_set(&rb->nest, 0);
+
+	/*
+	 * Ensure we decrement @rb->nest before we validate the @rb->head.
+	 * Otherwise we cannot be sure we caught the 'last' nested update.
+	 */
+	barrier();
 	if (unlikely(head != local_read(&rb->head))) {
 		local_inc(&rb->nest);
 		goto again;
@@ -288,6 +314,13 @@
 		goto err;
 
 	/*
+	 * If rb::aux_mmap_count is zero (and rb_has_aux() above went through),
+	 * the aux buffer is in perf_mmap_close(), about to get freed.
+	 */
+	if (!atomic_read(&rb->aux_mmap_count))
+		goto err;
+
+	/*
 	 * Nesting is not supported for AUX area, make sure nested
 	 * writers are caught early
 	 */
@@ -347,6 +380,7 @@
 			 bool truncated)
 {
 	struct ring_buffer *rb = handle->rb;
+	bool wakeup = truncated;
 	unsigned long aux_head;
 	u64 flags = 0;
 
@@ -375,9 +409,16 @@
 	aux_head = rb->user_page->aux_head = local_read(&rb->aux_head);
 
 	if (aux_head - local_read(&rb->aux_wakeup) >= rb->aux_watermark) {
-		perf_output_wakeup(handle);
+		wakeup = true;
 		local_add(rb->aux_watermark, &rb->aux_wakeup);
 	}
+
+	if (wakeup) {
+		if (truncated)
+			handle->event->pending_disable = 1;
+		perf_output_wakeup(handle);
+	}
+
 	handle->event = NULL;
 
 	local_set(&rb->aux_nest, 0);
@@ -459,6 +500,25 @@
 	__free_page(page);
 }
 
+static void __rb_free_aux(struct ring_buffer *rb)
+{
+	int pg;
+
+	if (rb->aux_priv) {
+		rb->free_aux(rb->aux_priv);
+		rb->free_aux = NULL;
+		rb->aux_priv = NULL;
+	}
+
+	if (rb->aux_nr_pages) {
+		for (pg = 0; pg < rb->aux_nr_pages; pg++)
+			rb_free_aux_page(rb, pg);
+
+		kfree(rb->aux_pages);
+		rb->aux_nr_pages = 0;
+	}
+}
+
 int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event,
 		 pgoff_t pgoff, int nr_pages, long watermark, int flags)
 {
@@ -547,30 +607,11 @@
 	if (!ret)
 		rb->aux_pgoff = pgoff;
 	else
-		rb_free_aux(rb);
+		__rb_free_aux(rb);
 
 	return ret;
 }
 
-static void __rb_free_aux(struct ring_buffer *rb)
-{
-	int pg;
-
-	if (rb->aux_priv) {
-		rb->free_aux(rb->aux_priv);
-		rb->free_aux = NULL;
-		rb->aux_priv = NULL;
-	}
-
-	if (rb->aux_nr_pages) {
-		for (pg = 0; pg < rb->aux_nr_pages; pg++)
-			rb_free_aux_page(rb, pg);
-
-		kfree(rb->aux_pages);
-		rb->aux_nr_pages = 0;
-	}
-}
-
 void rb_free_aux(struct ring_buffer *rb)
 {
 	if (atomic_dec_and_test(&rb->aux_refcount))
@@ -628,6 +669,9 @@
 	size = sizeof(struct ring_buffer);
 	size += nr_pages * sizeof(void *);
 
+	if (order_base_2(size) >= PAGE_SHIFT+MAX_ORDER)
+		goto fail;
+
 	rb = kzalloc(size, GFP_KERNEL);
 	if (!rb)
 		goto fail;
@@ -771,8 +815,10 @@
 			return NULL;
 
 		/* AUX space */
-		if (pgoff >= rb->aux_pgoff)
-			return virt_to_page(rb->aux_pages[pgoff - rb->aux_pgoff]);
+		if (pgoff >= rb->aux_pgoff) {
+			int aux_pgoff = array_index_nospec(pgoff - rb->aux_pgoff, rb->aux_nr_pages);
+			return virt_to_page(rb->aux_pages[aux_pgoff]);
+		}
 	}
 
 	return __perf_mmap_to_page(rb, pgoff);
--- linux-4.4.0.orig/kernel/events/uprobes.c
+++ linux-4.4.0/kernel/events/uprobes.c
@@ -171,8 +171,10 @@
 	mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
 	err = -EAGAIN;
 	ptep = page_check_address(page, mm, addr, &ptl, 0);
-	if (!ptep)
+	if (!ptep) {
+		mem_cgroup_cancel_charge(kpage, memcg);
 		goto unlock;
+	}
 
 	get_page(kpage);
 	page_add_new_anon_rmap(kpage, vma, addr);
@@ -199,7 +201,6 @@
 
 	err = 0;
  unlock:
-	mem_cgroup_cancel_charge(kpage, memcg);
 	mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
 	unlock_page(page);
 	return err;
@@ -298,7 +299,7 @@
 
 retry:
 	/* Read the page with vaddr into memory */
-	ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
+	ret = get_user_pages(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page, &vma);
 	if (ret <= 0)
 		return ret;
 
@@ -601,11 +602,7 @@
 	if (ret)
 		goto out;
 
-	/* uprobe_write_opcode() assumes we don't cross page boundary */
-	BUG_ON((uprobe->offset & ~PAGE_MASK) +
-			UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
-
-	smp_wmb(); /* pairs with rmb() in find_active_uprobe() */
+	smp_wmb(); /* pairs with the smp_rmb() in handle_swbp() */
 	set_bit(UPROBE_COPY_INSN, &uprobe->flags);
 
  out:
@@ -883,6 +880,13 @@
 	if (offset > i_size_read(inode))
 		return -EINVAL;
 
+	/*
+	 * This ensures that copy_from_page() and copy_to_page()
+	 * can't cross page boundary.
+	 */
+	if (!IS_ALIGNED(offset, UPROBE_SWBP_INSN_SIZE))
+		return -EINVAL;
+
  retry:
 	uprobe = alloc_uprobe(inode, offset);
 	if (!uprobe)
@@ -1691,6 +1695,9 @@
 	uprobe_opcode_t opcode;
 	int result;
 
+	if (WARN_ON_ONCE(!IS_ALIGNED(vaddr, UPROBE_SWBP_INSN_SIZE)))
+		return -EINVAL;
+
 	pagefault_disable();
 	result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr,
 							sizeof(opcode));
@@ -1699,7 +1706,7 @@
 	if (likely(result == 0))
 		goto out;
 
-	result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
+	result = get_user_pages(NULL, mm, vaddr, 1, FOLL_FORCE, &page, NULL);
 	if (result < 0)
 		return result;
 
@@ -1835,7 +1842,7 @@
 
  sigill:
 	uprobe_warn(current, "handle uretprobe, sending SIGILL.");
-	force_sig_info(SIGILL, SEND_SIG_FORCED, current);
+	force_sig(SIGILL, current);
 
 }
 
@@ -1868,7 +1875,7 @@
 	if (!uprobe) {
 		if (is_swbp > 0) {
 			/* No matching uprobe; signal SIGTRAP. */
-			send_sig(SIGTRAP, current, 0);
+			force_sig(SIGTRAP, current);
 		} else {
 			/*
 			 * Either we raced with uprobe_unregister() or we can't
@@ -1891,10 +1898,18 @@
 	 * After we hit the bp, _unregister + _register can install the
 	 * new and not-yet-analyzed uprobe at the same address, restart.
 	 */
-	smp_rmb(); /* pairs with wmb() in install_breakpoint() */
 	if (unlikely(!test_bit(UPROBE_COPY_INSN, &uprobe->flags)))
 		goto out;
 
+	/*
+	 * Pairs with the smp_wmb() in prepare_uprobe().
+	 *
+	 * Guarantees that if we see the UPROBE_COPY_INSN bit set, then
+	 * we must also see the stores to &uprobe->arch performed by the
+	 * prepare_uprobe() call.
+	 */
+	smp_rmb();
+
 	/* Tracing handlers use ->utask to communicate with fetch methods */
 	if (!get_utask())
 		goto out;
@@ -1943,7 +1958,7 @@
 
 	if (unlikely(err)) {
 		uprobe_warn(current, "execute the probed insn, sending SIGILL.");
-		force_sig_info(SIGILL, SEND_SIG_FORCED, current);
+		force_sig(SIGILL, current);
 	}
 }
 
--- linux-4.4.0.orig/kernel/exit.c
+++ linux-4.4.0/kernel/exit.c
@@ -389,7 +389,7 @@
 	struct mm_struct *mm = tsk->mm;
 	struct core_state *core_state;
 
-	mm_release(tsk, mm);
+	exit_mm_release(tsk, mm);
 	if (!mm)
 		return;
 	sync_mm_rss(mm);
@@ -408,7 +408,10 @@
 		up_read(&mm->mmap_sem);
 
 		self.task = tsk;
-		self.next = xchg(&core_state->dumper.next, &self);
+		if (self.task->flags & PF_SIGNALED)
+			self.next = xchg(&core_state->dumper.next, &self);
+		else
+			self.task = NULL;
 		/*
 		 * Implies mb(), the result of xchg() must be visible
 		 * to core_state->dumper.
@@ -450,12 +453,14 @@
 	return NULL;
 }
 
-static struct task_struct *find_child_reaper(struct task_struct *father)
+static struct task_struct *find_child_reaper(struct task_struct *father,
+						struct list_head *dead)
 	__releases(&tasklist_lock)
 	__acquires(&tasklist_lock)
 {
 	struct pid_namespace *pid_ns = task_active_pid_ns(father);
 	struct task_struct *reaper = pid_ns->child_reaper;
+	struct task_struct *p, *n;
 
 	if (likely(reaper != father))
 		return reaper;
@@ -471,6 +476,12 @@
 		panic("Attempted to kill init! exitcode=0x%08x\n",
 			father->signal->group_exit_code ?: father->exit_code);
 	}
+
+	list_for_each_entry_safe(p, n, dead, ptrace_entry) {
+		list_del_init(&p->ptrace_entry);
+		release_task(p);
+	}
+
 	zap_pid_ns_processes(pid_ns);
 	write_lock_irq(&tasklist_lock);
 
@@ -557,7 +568,7 @@
 		exit_ptrace(father, dead);
 
 	/* Can drop and reacquire tasklist_lock */
-	reaper = find_child_reaper(father);
+	reaper = find_child_reaper(father, dead);
 	if (list_empty(&father->children))
 		return;
 
@@ -684,27 +695,12 @@
 	 */
 	if (unlikely(tsk->flags & PF_EXITING)) {
 		pr_alert("Fixing recursive fault but reboot is needed!\n");
-		/*
-		 * We can do this unlocked here. The futex code uses
-		 * this flag just to verify whether the pi state
-		 * cleanup has been done or not. In the worst case it
-		 * loops once more. We pretend that the cleanup was
-		 * done as there is no way to return. Either the
-		 * OWNER_DIED bit is set by now or we push the blocked
-		 * task into the wait for ever nirwana as well.
-		 */
-		tsk->flags |= PF_EXITPIDONE;
+		futex_exit_recursive(tsk);
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule();
 	}
 
 	exit_signals(tsk);  /* sets PF_EXITING */
-	/*
-	 * tsk->flags are checked in the futex code to protect against
-	 * an exiting task cleaning up the robust pi futexes.
-	 */
-	smp_mb();
-	raw_spin_unlock_wait(&tsk->pi_lock);
 
 	if (unlikely(in_atomic())) {
 		pr_info("note: %s[%d] exited with preempt_count %d\n",
@@ -782,12 +778,6 @@
 	 * Make sure we are holding no locks:
 	 */
 	debug_check_no_locks_held();
-	/*
-	 * We can do this unlocked here. The futex code uses this flag
-	 * just to verify whether the pi state cleanup has been done
-	 * or not. In the worst case it loops once more.
-	 */
-	tsk->flags |= PF_EXITPIDONE;
 
 	if (tsk->io_context)
 		exit_io_context(tsk);
@@ -918,17 +908,28 @@
 		task_pid_type(p, wo->wo_type) == wo->wo_pid;
 }
 
-static int eligible_child(struct wait_opts *wo, struct task_struct *p)
+static int
+eligible_child(struct wait_opts *wo, bool ptrace, struct task_struct *p)
 {
 	if (!eligible_pid(wo, p))
 		return 0;
-	/* Wait for all children (clone and not) if __WALL is set;
-	 * otherwise, wait for clone children *only* if __WCLONE is
-	 * set; otherwise, wait for non-clone children *only*.  (Note:
-	 * A "clone" child here is one that reports to its parent
-	 * using a signal other than SIGCHLD.) */
-	if (((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE))
-	    && !(wo->wo_flags & __WALL))
+
+	/*
+	 * Wait for all children (clone and not) if __WALL is set or
+	 * if it is traced by us.
+	 */
+	if (ptrace || (wo->wo_flags & __WALL))
+		return 1;
+
+	/*
+	 * Otherwise, wait for clone children *only* if __WCLONE is set;
+	 * otherwise, wait for non-clone children *only*.
+	 *
+	 * Note: a "clone" child here is one that reports to its parent
+	 * using a signal other than SIGCHLD, or a non-leader thread which
+	 * we can only see if it is traced by us.
+	 */
+	if ((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE))
 		return 0;
 
 	return 1;
@@ -1301,7 +1302,7 @@
 	if (unlikely(exit_state == EXIT_DEAD))
 		return 0;
 
-	ret = eligible_child(wo, p);
+	ret = eligible_child(wo, ptrace, p);
 	if (!ret)
 		return ret;
 
@@ -1597,6 +1598,10 @@
 			__WNOTHREAD|__WCLONE|__WALL))
 		return -EINVAL;
 
+	/* -INT_MIN is not defined */
+	if (upid == INT_MIN)
+		return -ESRCH;
+
 	if (upid == -1)
 		type = PIDTYPE_MAX;
 	else if (upid < 0) {
--- linux-4.4.0.orig/kernel/extable.c
+++ linux-4.4.0/kernel/extable.c
@@ -66,7 +66,7 @@
 	return 0;
 }
 
-int core_kernel_text(unsigned long addr)
+int notrace core_kernel_text(unsigned long addr)
 {
 	if (addr >= (unsigned long)_stext &&
 	    addr < (unsigned long)_etext)
--- linux-4.4.0.orig/kernel/fork.c
+++ linux-4.4.0/kernel/fork.c
@@ -58,6 +58,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
 #include <linux/freezer.h>
+#include <linux/kaiser.h>
 #include <linux/delayacct.h>
 #include <linux/taskstats_kern.h>
 #include <linux/random.h>
@@ -87,6 +88,11 @@
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/task.h>
+#ifdef CONFIG_USER_NS
+extern int unprivileged_userns_clone;
+#else
+#define unprivileged_userns_clone 0
+#endif
 
 /*
  * Minimum number of threads to boot the kernel
@@ -169,6 +175,7 @@
 
 static inline void free_thread_info(struct thread_info *ti)
 {
+	kaiser_unmap_thread_stack(ti);
 	free_kmem_pages((unsigned long)ti, THREAD_SIZE_ORDER);
 }
 # else
@@ -252,7 +259,7 @@
 	WARN_ON(tsk == current);
 
 	cgroup_free(tsk);
-	task_numa_free(tsk);
+	task_numa_free(tsk, true);
 	security_task_free(tsk);
 	exit_creds(tsk);
 	delayacct_tsk_free(tsk);
@@ -331,13 +338,14 @@
 	*stackend = STACK_END_MAGIC;	/* for overflow detection */
 }
 
-static struct task_struct *dup_task_struct(struct task_struct *orig)
+static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
 {
 	struct task_struct *tsk;
 	struct thread_info *ti;
-	int node = tsk_fork_get_node(orig);
 	int err;
 
+	if (node == NUMA_NO_NODE)
+		node = tsk_fork_get_node(orig);
 	tsk = alloc_task_struct_node(node);
 	if (!tsk)
 		return NULL;
@@ -351,6 +359,10 @@
 		goto free_ti;
 
 	tsk->stack = ti;
+
+	err = kaiser_map_thread_stack(tsk->stack);
+	if (err)
+		goto free_ti;
 #ifdef CONFIG_SECCOMP
 	/*
 	 * We must handle setting up seccomp filters once we're under
@@ -367,7 +379,7 @@
 	set_task_stack_end_magic(tsk);
 
 #ifdef CONFIG_CC_STACKPROTECTOR
-	tsk->stack_canary = get_random_int();
+	tsk->stack_canary = get_random_long();
 #endif
 
 	/*
@@ -465,7 +477,7 @@
 			struct inode *inode = file_inode(file);
 			struct address_space *mapping = file->f_mapping;
 
-			get_file(file);
+			vma_get_file(tmp);
 			if (tmp->vm_flags & VM_DENYWRITE)
 				atomic_dec(&inode->i_writecount);
 			i_mmap_lock_write(mapping);
@@ -585,7 +597,8 @@
 #endif
 }
 
-static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p)
+static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
+	struct user_namespace *user_ns)
 {
 	mm->mmap = NULL;
 	mm->mm_rb = RB_ROOT;
@@ -625,6 +638,7 @@
 	if (init_new_context(p, mm))
 		goto fail_nocontext;
 
+	mm->user_ns = get_user_ns(user_ns);
 	return mm;
 
 fail_nocontext:
@@ -670,7 +684,7 @@
 		return NULL;
 
 	memset(mm, 0, sizeof(*mm));
-	return mm_init(mm, current);
+	return mm_init(mm, current, current_user_ns());
 }
 
 /*
@@ -685,6 +699,7 @@
 	destroy_context(mm);
 	mmu_notifier_mm_destroy(mm);
 	check_mm(mm);
+	put_user_ns(mm->user_ns);
 	free_mm(mm);
 }
 EXPORT_SYMBOL_GPL(__mmdrop);
@@ -764,6 +779,29 @@
 EXPORT_SYMBOL(get_mm_exe_file);
 
 /**
+ * get_task_exe_file - acquire a reference to the task's executable file
+ *
+ * Returns %NULL if task's mm (if any) has no associated executable file or
+ * this is a kernel thread with borrowed mm (see the comment above get_task_mm).
+ * User must release file via fput().
+ */
+struct file *get_task_exe_file(struct task_struct *task)
+{
+	struct file *exe_file = NULL;
+	struct mm_struct *mm;
+
+	task_lock(task);
+	mm = task->mm;
+	if (mm) {
+		if (!(task->flags & PF_KTHREAD))
+			exe_file = get_mm_exe_file(mm);
+	}
+	task_unlock(task);
+	return exe_file;
+}
+EXPORT_SYMBOL(get_task_exe_file);
+
+/**
  * get_task_mm - acquire a reference to the task's mm
  *
  * Returns %NULL if the task has no mm.  Checks PF_KTHREAD (meaning
@@ -854,38 +892,20 @@
  * restoring the old one. . .
  * Eric Biederman 10 January 1998
  */
-void mm_release(struct task_struct *tsk, struct mm_struct *mm)
+static void mm_release(struct task_struct *tsk, struct mm_struct *mm)
 {
-	/* Get rid of any futexes when releasing the mm */
-#ifdef CONFIG_FUTEX
-	if (unlikely(tsk->robust_list)) {
-		exit_robust_list(tsk);
-		tsk->robust_list = NULL;
-	}
-#ifdef CONFIG_COMPAT
-	if (unlikely(tsk->compat_robust_list)) {
-		compat_exit_robust_list(tsk);
-		tsk->compat_robust_list = NULL;
-	}
-#endif
-	if (unlikely(!list_empty(&tsk->pi_state_list)))
-		exit_pi_state_list(tsk);
-#endif
-
 	uprobe_free_utask(tsk);
 
 	/* Get rid of any cached register state */
 	deactivate_mm(tsk, mm);
 
 	/*
-	 * If we're exiting normally, clear a user-space tid field if
-	 * requested.  We leave this alone when dying by signal, to leave
-	 * the value intact in a core dump, and to save the unnecessary
-	 * trouble, say, a killed vfork parent shouldn't touch this mm.
-	 * Userland only wants this done for a sys_exit.
+	 * Signal userspace if we're not exiting with a core dump
+	 * because we want to leave the value intact for debugging
+	 * purposes.
 	 */
 	if (tsk->clear_child_tid) {
-		if (!(tsk->flags & PF_SIGNALED) &&
+		if (!(tsk->signal->flags & SIGNAL_GROUP_COREDUMP) &&
 		    atomic_read(&mm->mm_users) > 1) {
 			/*
 			 * We don't check the error code - if userspace has
@@ -906,6 +926,18 @@
 		complete_vfork_done(tsk);
 }
 
+void exit_mm_release(struct task_struct *tsk, struct mm_struct *mm)
+{
+	futex_exit_release(tsk);
+	mm_release(tsk, mm);
+}
+
+void exec_mm_release(struct task_struct *tsk, struct mm_struct *mm)
+{
+	futex_exec_release(tsk);
+	mm_release(tsk, mm);
+}
+
 /*
  * Allocate a new mm structure and copy contents from the
  * mm structure of the passed in task structure.
@@ -921,7 +953,7 @@
 
 	memcpy(mm, oldmm, sizeof(*mm));
 
-	if (!mm_init(mm, tsk))
+	if (!mm_init(mm, tsk, mm->user_ns))
 		goto fail_nomem;
 
 	err = dup_mmap(mm, oldmm);
@@ -1078,7 +1110,9 @@
 		return -ENOMEM;
 
 	atomic_set(&sig->count, 1);
+	spin_lock_irq(&current->sighand->siglock);
 	memcpy(sig->action, current->sighand->action, sizeof(sig->action));
+	spin_unlock_irq(&current->sighand->siglock);
 	return 0;
 }
 
@@ -1246,7 +1280,8 @@
 					int __user *child_tidptr,
 					struct pid *pid,
 					int trace,
-					unsigned long tls)
+					unsigned long tls,
+					int node)
 {
 	int retval;
 	struct task_struct *p;
@@ -1258,6 +1293,10 @@
 	if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
 		return ERR_PTR(-EINVAL);
 
+	if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone)
+		if (!capable(CAP_SYS_ADMIN))
+			return ERR_PTR(-EPERM);
+
 	/*
 	 * Thread groups must share signals as well, and detached threads
 	 * can only be started up within the thread group.
@@ -1299,10 +1338,22 @@
 		goto fork_out;
 
 	retval = -ENOMEM;
-	p = dup_task_struct(current);
+	p = dup_task_struct(current, node);
 	if (!p)
 		goto fork_out;
 
+	/*
+	 * This _must_ happen before we call free_task(), i.e. before we jump
+	 * to any of the bad_fork_* labels. This is to avoid freeing
+	 * p->set_child_tid which is (ab)used as a kthread's data pointer for
+	 * kernel threads (PF_KTHREAD).
+	 */
+	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
+	/*
+	 * Clear TID on mm_release()?
+	 */
+	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
+
 	ftrace_graph_init_task(p);
 
 	rt_mutex_init_task(p);
@@ -1365,11 +1416,8 @@
 
 	posix_cpu_timers_init(p);
 
-	p->start_time = ktime_get_ns();
-	p->real_start_time = ktime_get_boot_ns();
 	p->io_context = NULL;
 	p->audit_context = NULL;
-	threadgroup_change_begin(current);
 	cgroup_fork(p);
 #ifdef CONFIG_NUMA
 	p->mempolicy = mpol_dup(p->mempolicy);
@@ -1465,22 +1513,11 @@
 		}
 	}
 
-	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
-	/*
-	 * Clear TID on mm_release()?
-	 */
-	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
 #ifdef CONFIG_BLOCK
 	p->plug = NULL;
 #endif
-#ifdef CONFIG_FUTEX
-	p->robust_list = NULL;
-#ifdef CONFIG_COMPAT
-	p->compat_robust_list = NULL;
-#endif
-	INIT_LIST_HEAD(&p->pi_state_list);
-	p->pi_state_cache = NULL;
-#endif
+	futex_init_task(p);
+
 	/*
 	 * sigaltstack should be cleared when sharing the same VM
 	 */
@@ -1501,14 +1538,9 @@
 	/* ok, now we should be set up.. */
 	p->pid = pid_nr(pid);
 	if (clone_flags & CLONE_THREAD) {
-		p->exit_signal = -1;
 		p->group_leader = current->group_leader;
 		p->tgid = current->tgid;
 	} else {
-		if (clone_flags & CLONE_PARENT)
-			p->exit_signal = current->group_leader->exit_signal;
-		else
-			p->exit_signal = (clone_flags & CSIGNAL);
 		p->group_leader = p;
 		p->tgid = p->pid;
 	}
@@ -1521,6 +1553,7 @@
 	INIT_LIST_HEAD(&p->thread_group);
 	p->task_works = NULL;
 
+	threadgroup_change_begin(current);
 	/*
 	 * Ensure that the cgroup subsystem policies allow the new process to be
 	 * forked. It should be noted the the new process's css_set can be changed
@@ -1532,6 +1565,17 @@
 		goto bad_fork_free_pid;
 
 	/*
+	 * From this point on we must avoid any synchronous user-space
+	 * communication until we take the tasklist-lock. In particular, we do
+	 * not want user-space to be able to predict the process start-time by
+	 * stalling fork(2) after we recorded the start_time but before it is
+	 * visible to the system.
+	 */
+
+	p->start_time = ktime_get_ns();
+	p->real_start_time = ktime_get_boot_ns();
+
+	/*
 	 * Make it visible to the rest of the system, but dont wake it up yet.
 	 * Need tasklist lock for parent etc handling!
 	 */
@@ -1541,9 +1585,14 @@
 	if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) {
 		p->real_parent = current->real_parent;
 		p->parent_exec_id = current->parent_exec_id;
+		if (clone_flags & CLONE_THREAD)
+			p->exit_signal = -1;
+		else
+			p->exit_signal = current->group_leader->exit_signal;
 	} else {
 		p->real_parent = current;
 		p->parent_exec_id = current->self_exec_id;
+		p->exit_signal = (clone_flags & CSIGNAL);
 	}
 
 	spin_lock(&current->sighand->siglock);
@@ -1564,11 +1613,13 @@
 	*/
 	recalc_sigpending();
 	if (signal_pending(current)) {
-		spin_unlock(&current->sighand->siglock);
-		write_unlock_irq(&tasklist_lock);
 		retval = -ERESTARTNOINTR;
 		goto bad_fork_cancel_cgroup;
 	}
+	if (unlikely(!(ns_of_pid(pid)->nr_hashed & PIDNS_HASH_ADDING))) {
+		retval = -ENOMEM;
+		goto bad_fork_cancel_cgroup;
+	}
 
 	if (likely(p->pid)) {
 		ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
@@ -1619,8 +1670,11 @@
 	return p;
 
 bad_fork_cancel_cgroup:
+	spin_unlock(&current->sighand->siglock);
+	write_unlock_irq(&tasklist_lock);
 	cgroup_cancel_fork(p, cgrp_ss_priv);
 bad_fork_free_pid:
+	threadgroup_change_end(current);
 	if (pid != &init_struct_pid)
 		free_pid(pid);
 bad_fork_cleanup_io:
@@ -1651,7 +1705,6 @@
 	mpol_put(p->mempolicy);
 bad_fork_cleanup_threadgroup_lock:
 #endif
-	threadgroup_change_end(current);
 	delayacct_tsk_free(p);
 bad_fork_cleanup_count:
 	atomic_dec(&p->cred->user->processes);
@@ -1675,7 +1728,8 @@
 struct task_struct *fork_idle(int cpu)
 {
 	struct task_struct *task;
-	task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0, 0);
+	task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0, 0,
+			    cpu_to_node(cpu));
 	if (!IS_ERR(task)) {
 		init_idle_pids(task->pids);
 		init_idle(task, cpu);
@@ -1720,7 +1774,7 @@
 	}
 
 	p = copy_process(clone_flags, stack_start, stack_size,
-			 child_tidptr, NULL, trace, tls);
+			 child_tidptr, NULL, trace, tls, NUMA_NO_NODE);
 	/*
 	 * Do this prior waking up the new thread - the thread pointer
 	 * might get invalid after that point, if the thread exits quickly.
@@ -1882,7 +1936,7 @@
 	if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
 				CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
 				CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET|
-				CLONE_NEWUSER|CLONE_NEWPID))
+				CLONE_NEWUSER|CLONE_NEWPID|CLONE_NEWCGROUP))
 		return -EINVAL;
 	/*
 	 * Not implemented, but pretend it works if there is nothing
@@ -1984,6 +2038,12 @@
 	if (unshare_flags & CLONE_NEWNS)
 		unshare_flags |= CLONE_FS;
 
+	if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) {
+		err = -EPERM;
+		if (!capable(CAP_SYS_ADMIN))
+			goto bad_unshare_out;
+	}
+
 	err = check_unshare_flags(unshare_flags);
 	if (err)
 		goto bad_unshare_out;
@@ -2097,7 +2157,7 @@
 	struct ctl_table t;
 	int ret;
 	int threads = max_threads;
-	int min = MIN_THREADS;
+	int min = 1;
 	int max = MAX_THREADS;
 
 	t = *table;
@@ -2109,7 +2169,7 @@
 	if (ret || !write)
 		return ret;
 
-	set_max_threads(threads);
+	max_threads = threads;
 
 	return 0;
 }
--- linux-4.4.0.orig/kernel/futex.c
+++ linux-4.4.0/kernel/futex.c
@@ -44,6 +44,7 @@
  *  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/compat.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/fs.h>
@@ -171,8 +172,10 @@
  * double_lock_hb() and double_unlock_hb(), respectively.
  */
 
-#ifndef CONFIG_HAVE_FUTEX_CMPXCHG
-int __read_mostly futex_cmpxchg_enabled;
+#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
+#define futex_cmpxchg_enabled 1
+#else
+static int  __read_mostly futex_cmpxchg_enabled;
 #endif
 
 /*
@@ -328,6 +331,12 @@
 }
 #endif /* CONFIG_FAIL_FUTEX */
 
+#ifdef CONFIG_COMPAT
+static void compat_exit_robust_list(struct task_struct *curr);
+#else
+static inline void compat_exit_robust_list(struct task_struct *curr) { }
+#endif
+
 static inline void futex_get_mm(union futex_key *key)
 {
 	atomic_inc(&key->private.mm->mm_count);
@@ -378,9 +387,9 @@
  */
 static struct futex_hash_bucket *hash_futex(union futex_key *key)
 {
-	u32 hash = jhash2((u32*)&key->both.word,
-			  (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
+	u32 hash = jhash2((u32 *)key, offsetof(typeof(*key), both.offset) / 4,
 			  key->both.offset);
+
 	return &futex_queues[hash & (futex_hashsize - 1)];
 }
 
@@ -407,7 +416,7 @@
 
 	switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
 	case FUT_OFF_INODE:
-		ihold(key->shared.inode); /* implies MB (B) */
+		smp_mb();		/* explicit smp_mb(); (B) */
 		break;
 	case FUT_OFF_MMSHARED:
 		futex_get_mm(key); /* implies MB (B) */
@@ -438,7 +447,6 @@
 
 	switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
 	case FUT_OFF_INODE:
-		iput(key->shared.inode);
 		break;
 	case FUT_OFF_MMSHARED:
 		mmdrop(key->private.mm);
@@ -446,6 +454,46 @@
 	}
 }
 
+/*
+ * Generate a machine wide unique identifier for this inode.
+ *
+ * This relies on u64 not wrapping in the life-time of the machine; which with
+ * 1ns resolution means almost 585 years.
+ *
+ * This further relies on the fact that a well formed program will not unmap
+ * the file while it has a (shared) futex waiting on it. This mapping will have
+ * a file reference which pins the mount and inode.
+ *
+ * If for some reason an inode gets evicted and read back in again, it will get
+ * a new sequence number and will _NOT_ match, even though it is the exact same
+ * file.
+ *
+ * It is important that match_futex() will never have a false-positive, esp.
+ * for PI futexes that can mess up the state. The above argues that false-negatives
+ * are only possible for malformed programs.
+ */
+static u64 get_inode_sequence_number(struct inode *inode)
+{
+	static atomic64_t i_seq;
+	u64 old;
+
+	/* Does the inode already have a sequence number? */
+	old = atomic64_read(&inode->i_sequence);
+	if (likely(old))
+		return old;
+
+	for (;;) {
+		u64 new = atomic64_add_return(1, &i_seq);
+		if (WARN_ON_ONCE(!new))
+			continue;
+
+		old = atomic64_cmpxchg_relaxed(&inode->i_sequence, 0, new);
+		if (old)
+			return old;
+		return new;
+	}
+}
+
 /**
  * get_futex_key() - Get parameters which are the keys for a futex
  * @uaddr:	virtual address of the futex
@@ -458,9 +506,15 @@
  *
  * The key words are stored in *key on success.
  *
- * For shared mappings, it's (page->index, file_inode(vma->vm_file),
- * offset_within_page).  For private mappings, it's (uaddr, current->mm).
- * We can usually work out the index without swapping in the page.
+ * For shared mappings (when @fshared), the key is:
+ *   ( inode->i_sequence, page->index, offset_within_page )
+ * [ also see get_inode_sequence_number() ]
+ *
+ * For private mappings (or when !@fshared), the key is:
+ *   ( current->mm, address, 0 )
+ *
+ * This allows (cross process, where applicable) identification of the futex
+ * without keeping the page pinned for the duration of the FUTEX_WAIT.
  *
  * lock_page() might sleep, the caller should not hold a spinlock.
  */
@@ -470,6 +524,7 @@
 	unsigned long address = (unsigned long)uaddr;
 	struct mm_struct *mm = current->mm;
 	struct page *page, *page_head;
+	struct address_space *mapping;
 	int err, ro = 0;
 
 	/*
@@ -555,7 +610,19 @@
 	}
 #endif
 
-	lock_page(page_head);
+	/*
+	 * The treatment of mapping from this point on is critical. The page
+	 * lock protects many things but in this context the page lock
+	 * stabilizes mapping, prevents inode freeing in the shared
+	 * file-backed region case and guards against movement to swap cache.
+	 *
+	 * Strictly speaking the page lock is not needed in all cases being
+	 * considered here and page lock forces unnecessarily serialization
+	 * From this point on, mapping will be re-verified if necessary and
+	 * page lock will be acquired only if it is unavoidable
+	 */
+
+	mapping = READ_ONCE(page_head->mapping);
 
 	/*
 	 * If page_head->mapping is NULL, then it cannot be a PageAnon
@@ -572,18 +639,31 @@
 	 * shmem_writepage move it from filecache to swapcache beneath us:
 	 * an unlikely race, but we do need to retry for page_head->mapping.
 	 */
-	if (!page_head->mapping) {
-		int shmem_swizzled = PageSwapCache(page_head);
+	if (unlikely(!mapping)) {
+		int shmem_swizzled;
+
+		/*
+		 * Page lock is required to identify which special case above
+		 * applies. If this is really a shmem page then the page lock
+		 * will prevent unexpected transitions.
+		 */
+		lock_page(page_head);
+		shmem_swizzled = PageSwapCache(page_head) || page_head->mapping;
 		unlock_page(page_head);
 		put_page(page_head);
+
 		if (shmem_swizzled)
 			goto again;
+
 		return -EFAULT;
 	}
 
 	/*
 	 * Private mappings are handled in a simple way.
 	 *
+	 * If the futex key is stored on an anonymous page, then the associated
+	 * object is the mm which is implicitly pinned by the calling process.
+	 *
 	 * NOTE: When userspace waits on a MAP_SHARED mapping, even if
 	 * it's a read-only handle, it's expected that futexes attach to
 	 * the object not the particular process.
@@ -601,16 +681,47 @@
 		key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
 		key->private.mm = mm;
 		key->private.address = address;
+
 	} else {
+		struct inode *inode;
+
+		/*
+		 * The associated futex object in this case is the inode and
+		 * the page->mapping must be traversed. Ordinarily this should
+		 * be stabilised under page lock but it's not strictly
+		 * necessary in this case as we just want to pin the inode, not
+		 * update the radix tree or anything like that.
+		 *
+		 * The RCU read lock is taken as the inode is finally freed
+		 * under RCU. If the mapping still matches expectations then the
+		 * mapping->host can be safely accessed as being a valid inode.
+		 */
+		rcu_read_lock();
+
+		if (READ_ONCE(page_head->mapping) != mapping) {
+			rcu_read_unlock();
+			put_page(page_head);
+
+			goto again;
+		}
+
+		inode = READ_ONCE(mapping->host);
+		if (!inode) {
+			rcu_read_unlock();
+			put_page(page_head);
+
+			goto again;
+		}
+
 		key->both.offset |= FUT_OFF_INODE; /* inode-based key */
-		key->shared.inode = page_head->mapping->host;
+		key->shared.i_seq = get_inode_sequence_number(inode);
 		key->shared.pgoff = basepage_index(page);
+		rcu_read_unlock();
 	}
 
-	get_futex_key_refs(key); /* implies MB (B) */
+	get_futex_key_refs(key); /* implies smp_mb(); (B) */
 
 out:
-	unlock_page(page_head);
 	put_page(page_head);
 	return err;
 }
@@ -724,6 +835,29 @@
 	return pi_state;
 }
 
+static void pi_state_update_owner(struct futex_pi_state *pi_state,
+				  struct task_struct *new_owner)
+{
+	struct task_struct *old_owner = pi_state->owner;
+
+	lockdep_assert_held(&pi_state->pi_mutex.wait_lock);
+
+	if (old_owner) {
+		raw_spin_lock(&old_owner->pi_lock);
+		WARN_ON(list_empty(&pi_state->list));
+		list_del_init(&pi_state->list);
+		raw_spin_unlock(&old_owner->pi_lock);
+	}
+
+	if (new_owner) {
+		raw_spin_lock(&new_owner->pi_lock);
+		WARN_ON(!list_empty(&pi_state->list));
+		list_add(&pi_state->list, &new_owner->pi_state_list);
+		pi_state->owner = new_owner;
+		raw_spin_unlock(&new_owner->pi_lock);
+	}
+}
+
 /*
  * Must be called with the hb lock held.
  */
@@ -740,11 +874,10 @@
 	 * and has cleaned up the pi_state already
 	 */
 	if (pi_state->owner) {
-		raw_spin_lock_irq(&pi_state->owner->pi_lock);
-		list_del_init(&pi_state->list);
-		raw_spin_unlock_irq(&pi_state->owner->pi_lock);
-
-		rt_mutex_proxy_unlock(&pi_state->pi_mutex, pi_state->owner);
+		raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
+		pi_state_update_owner(pi_state, NULL);
+		raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
+		rt_mutex_proxy_unlock(&pi_state->pi_mutex);
 	}
 
 	if (current->pi_state_cache)
@@ -784,7 +917,7 @@
  * Kernel cleans up PI-state, but userspace is likely hosed.
  * (Robust-futex cleanup is separate and might save the day for userspace.)
  */
-void exit_pi_state_list(struct task_struct *curr)
+static void exit_pi_state_list(struct task_struct *curr)
 {
 	struct list_head *next, *head = &curr->pi_state_list;
 	struct futex_pi_state *pi_state;
@@ -825,7 +958,7 @@
 		pi_state->owner = NULL;
 		raw_spin_unlock_irq(&curr->pi_lock);
 
-		rt_mutex_unlock(&pi_state->pi_mutex);
+		rt_mutex_futex_unlock(&pi_state->pi_mutex);
 
 		spin_unlock(&hb->lock);
 
@@ -881,7 +1014,41 @@
  *	FUTEX_OWNER_DIED bit. See [4]
  *
  * [10] There is no transient state which leaves owner and user space
- *	TID out of sync.
+ *	TID out of sync. Except one error case where the kernel is denied
+ *	write access to the user address, see fixup_pi_state_owner().
+ *
+ *
+ * Serialization and lifetime rules:
+ *
+ * hb->lock:
+ *
+ *	hb -> futex_q, relation
+ *	futex_q -> pi_state, relation
+ *
+ *	(cannot be raw because hb can contain arbitrary amount
+ *	 of futex_q's)
+ *
+ * pi_mutex->wait_lock:
+ *
+ *	{uval, pi_state}
+ *
+ *	(and pi_mutex 'obviously')
+ *
+ * p->pi_lock:
+ *
+ *	p->pi_state_list -> pi_state->list, relation
+ *
+ * pi_state->refcount:
+ *
+ *	pi_state lifetime
+ *
+ *
+ * Lock order:
+ *
+ *   hb->lock
+ *     pi_mutex->wait_lock
+ *       p->pi_lock
+ *
  */
 
 /*
@@ -889,10 +1056,12 @@
  * the pi_state against the user space value. If correct, attach to
  * it.
  */
-static int attach_to_pi_state(u32 uval, struct futex_pi_state *pi_state,
+static int attach_to_pi_state(u32 __user *uaddr, u32 uval,
+			      struct futex_pi_state *pi_state,
 			      struct futex_pi_state **ps)
 {
 	pid_t pid = uval & FUTEX_TID_MASK;
+	int ret, uval2;
 
 	/*
 	 * Userspace might have messed up non-PI and PI futexes [3]
@@ -900,9 +1069,34 @@
 	if (unlikely(!pi_state))
 		return -EINVAL;
 
+	/*
+	 * We get here with hb->lock held, and having found a
+	 * futex_top_waiter(). This means that futex_lock_pi() of said futex_q
+	 * has dropped the hb->lock in between queue_me() and unqueue_me_pi(),
+	 * which in turn means that futex_lock_pi() still has a reference on
+	 * our pi_state.
+	 */
 	WARN_ON(!atomic_read(&pi_state->refcount));
 
 	/*
+	 * Now that we have a pi_state, we can acquire wait_lock
+	 * and do the state validation.
+	 */
+	raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
+
+	/*
+	 * Since {uval, pi_state} is serialized by wait_lock, and our current
+	 * uval was read without holding it, it can have changed. Verify it
+	 * still is what we expect it to be, otherwise retry the entire
+	 * operation.
+	 */
+	if (get_futex_value_locked(&uval2, uaddr))
+		goto out_efault;
+
+	if (uval != uval2)
+		goto out_eagain;
+
+	/*
 	 * Handle the owner died case:
 	 */
 	if (uval & FUTEX_OWNER_DIED) {
@@ -917,11 +1111,11 @@
 			 * is not 0. Inconsistent state. [5]
 			 */
 			if (pid)
-				return -EINVAL;
+				goto out_einval;
 			/*
 			 * Take a ref on the state and return success. [4]
 			 */
-			goto out_state;
+			goto out_attach;
 		}
 
 		/*
@@ -933,14 +1127,14 @@
 		 * Take a ref on the state and return success. [6]
 		 */
 		if (!pid)
-			goto out_state;
+			goto out_attach;
 	} else {
 		/*
 		 * If the owner died bit is not set, then the pi_state
 		 * must have an owner. [7]
 		 */
 		if (!pi_state->owner)
-			return -EINVAL;
+			goto out_einval;
 	}
 
 	/*
@@ -949,19 +1143,124 @@
 	 * user space TID. [9/10]
 	 */
 	if (pid != task_pid_vnr(pi_state->owner))
-		return -EINVAL;
-out_state:
+		goto out_einval;
+
+out_attach:
 	atomic_inc(&pi_state->refcount);
+	raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
 	*ps = pi_state;
 	return 0;
+
+out_einval:
+	ret = -EINVAL;
+	goto out_error;
+
+out_eagain:
+	ret = -EAGAIN;
+	goto out_error;
+
+out_efault:
+	ret = -EFAULT;
+	goto out_error;
+
+out_error:
+	raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
+	return ret;
+}
+
+/**
+ * wait_for_owner_exiting - Block until the owner has exited
+ * @exiting:	Pointer to the exiting task
+ *
+ * Caller must hold a refcount on @exiting.
+ */
+static void wait_for_owner_exiting(int ret, struct task_struct *exiting)
+{
+	if (ret != -EBUSY) {
+		WARN_ON_ONCE(exiting);
+		return;
+	}
+
+	if (WARN_ON_ONCE(ret == -EBUSY && !exiting))
+		return;
+
+	mutex_lock(&exiting->futex_exit_mutex);
+	/*
+	 * No point in doing state checking here. If the waiter got here
+	 * while the task was in exec()->exec_futex_release() then it can
+	 * have any FUTEX_STATE_* value when the waiter has acquired the
+	 * mutex. OK, if running, EXITING or DEAD if it reached exit()
+	 * already. Highly unlikely and not a problem. Just one more round
+	 * through the futex maze.
+	 */
+	mutex_unlock(&exiting->futex_exit_mutex);
+
+	put_task_struct(exiting);
+}
+
+static int handle_exit_race(u32 __user *uaddr, u32 uval,
+			    struct task_struct *tsk)
+{
+	u32 uval2;
+
+	/*
+	 * If the futex exit state is not yet FUTEX_STATE_DEAD, tell the
+	 * caller that the alleged owner is busy.
+	 */
+	if (tsk && tsk->futex_state != FUTEX_STATE_DEAD)
+		return -EBUSY;
+
+	/*
+	 * Reread the user space value to handle the following situation:
+	 *
+	 * CPU0				CPU1
+	 *
+	 * sys_exit()			sys_futex()
+	 *  do_exit()			 futex_lock_pi()
+	 *                                futex_lock_pi_atomic()
+	 *   exit_signals(tsk)		    No waiters:
+	 *    tsk->flags |= PF_EXITING;	    *uaddr == 0x00000PID
+	 *  mm_release(tsk)		    Set waiter bit
+	 *   exit_robust_list(tsk) {	    *uaddr = 0x80000PID;
+	 *      Set owner died		    attach_to_pi_owner() {
+	 *    *uaddr = 0xC0000000;	     tsk = get_task(PID);
+	 *   }				     if (!tsk->flags & PF_EXITING) {
+	 *  ...				       attach();
+	 *  tsk->futex_state =               } else {
+	 *	FUTEX_STATE_DEAD;              if (tsk->futex_state !=
+	 *					  FUTEX_STATE_DEAD)
+	 *				         return -EAGAIN;
+	 *				       return -ESRCH; <--- FAIL
+	 *				     }
+	 *
+	 * Returning ESRCH unconditionally is wrong here because the
+	 * user space value has been changed by the exiting task.
+	 *
+	 * The same logic applies to the case where the exiting task is
+	 * already gone.
+	 */
+	if (get_futex_value_locked(&uval2, uaddr))
+		return -EFAULT;
+
+	/* If the user space value has changed, try again. */
+	if (uval2 != uval)
+		return -EAGAIN;
+
+	/*
+	 * The exiting task did not have a robust list, the robust list was
+	 * corrupted or the user space value in *uaddr is simply bogus.
+	 * Give up and tell user space.
+	 */
+	return -ESRCH;
 }
 
 /*
  * Lookup the task for the TID provided from user space and attach to
  * it after doing proper sanity checks.
  */
-static int attach_to_pi_owner(u32 uval, union futex_key *key,
-			      struct futex_pi_state **ps)
+static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
+			      struct futex_pi_state **ps,
+			      struct task_struct **exiting)
 {
 	pid_t pid = uval & FUTEX_TID_MASK;
 	struct futex_pi_state *pi_state;
@@ -970,12 +1269,15 @@
 	/*
 	 * We are the first waiter - try to look up the real owner and attach
 	 * the new pi_state to it, but bail out when TID = 0 [1]
+	 *
+	 * The !pid check is paranoid. None of the call sites should end up
+	 * with pid == 0, but better safe than sorry. Let the caller retry
 	 */
 	if (!pid)
-		return -ESRCH;
+		return -EAGAIN;
 	p = futex_find_get_task(pid);
 	if (!p)
-		return -ESRCH;
+		return handle_exit_race(uaddr, uval, NULL);
 
 	if (unlikely(p->flags & PF_KTHREAD)) {
 		put_task_struct(p);
@@ -983,27 +1285,41 @@
 	}
 
 	/*
-	 * We need to look at the task state flags to figure out,
-	 * whether the task is exiting. To protect against the do_exit
-	 * change of the task flags, we do this protected by
-	 * p->pi_lock:
+	 * We need to look at the task state to figure out, whether the
+	 * task is exiting. To protect against the change of the task state
+	 * in futex_exit_release(), we do this protected by p->pi_lock:
 	 */
 	raw_spin_lock_irq(&p->pi_lock);
-	if (unlikely(p->flags & PF_EXITING)) {
+	if (unlikely(p->futex_state != FUTEX_STATE_OK)) {
 		/*
-		 * The task is on the way out. When PF_EXITPIDONE is
-		 * set, we know that the task has finished the
-		 * cleanup:
+		 * The task is on the way out. When the futex state is
+		 * FUTEX_STATE_DEAD, we know that the task has finished
+		 * the cleanup:
 		 */
-		int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN;
+		int ret = handle_exit_race(uaddr, uval, p);
 
 		raw_spin_unlock_irq(&p->pi_lock);
-		put_task_struct(p);
+		/*
+		 * If the owner task is between FUTEX_STATE_EXITING and
+		 * FUTEX_STATE_DEAD then store the task pointer and keep
+		 * the reference on the task struct. The calling code will
+		 * drop all locks, wait for the task to reach
+		 * FUTEX_STATE_DEAD and then drop the refcount. This is
+		 * required to prevent a live lock when the current task
+		 * preempted the exiting task between the two states.
+		 */
+		if (ret == -EBUSY)
+			*exiting = p;
+		else
+			put_task_struct(p);
 		return ret;
 	}
 
 	/*
 	 * No existing pi state. First waiter. [2]
+	 *
+	 * This creates pi_state, we have hb->lock held, this means nothing can
+	 * observe this state, wait_lock is irrelevant.
 	 */
 	pi_state = alloc_pi_state();
 
@@ -1028,8 +1344,10 @@
 	return 0;
 }
 
-static int lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
-			   union futex_key *key, struct futex_pi_state **ps)
+static int lookup_pi_state(u32 __user *uaddr, u32 uval,
+			   struct futex_hash_bucket *hb,
+			   union futex_key *key, struct futex_pi_state **ps,
+			   struct task_struct **exiting)
 {
 	struct futex_q *match = futex_top_waiter(hb, key);
 
@@ -1038,13 +1356,13 @@
 	 * attach to the pi_state when the validation succeeds.
 	 */
 	if (match)
-		return attach_to_pi_state(uval, match->pi_state, ps);
+		return attach_to_pi_state(uaddr, uval, match->pi_state, ps);
 
 	/*
 	 * We are the first waiter - try to look up the owner based on
 	 * @uval and attach to it.
 	 */
-	return attach_to_pi_owner(uval, key, ps);
+	return attach_to_pi_owner(uaddr, uval, key, ps, exiting);
 }
 
 static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
@@ -1057,7 +1375,7 @@
 	if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
 		return -EFAULT;
 
-	/*If user space value changed, let the caller retry */
+	/* If user space value changed, let the caller retry */
 	return curval != uval ? -EAGAIN : 0;
 }
 
@@ -1070,6 +1388,8 @@
  *			lookup
  * @task:		the task to perform the atomic lock work for.  This will
  *			be "current" except in the case of requeue pi.
+ * @exiting:		Pointer to store the task pointer of the owner task
+ *			which is in the middle of exiting
  * @set_waiters:	force setting the FUTEX_WAITERS bit (1) or not (0)
  *
  * Return:
@@ -1078,11 +1398,17 @@
  * <0 - error
  *
  * The hb->lock and futex_key refs shall be held by the caller.
+ *
+ * @exiting is only set when the return value is -EBUSY. If so, this holds
+ * a refcount on the exiting task on return and the caller needs to drop it
+ * after waiting for the exit to complete.
  */
 static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
 				union futex_key *key,
 				struct futex_pi_state **ps,
-				struct task_struct *task, int set_waiters)
+				struct task_struct *task,
+				struct task_struct **exiting,
+				int set_waiters)
 {
 	u32 uval, newval, vpid = task_pid_vnr(task);
 	struct futex_q *match;
@@ -1113,7 +1439,7 @@
 	 */
 	match = futex_top_waiter(hb, key);
 	if (match)
-		return attach_to_pi_state(uval, match->pi_state, ps);
+		return attach_to_pi_state(uaddr, uval, match->pi_state, ps);
 
 	/*
 	 * No waiter and user TID is 0. We are here because the
@@ -1152,7 +1478,7 @@
 	 * attach to the owner. If that fails, no harm done, we only
 	 * set the FUTEX_WAITERS bit in the user space variable.
 	 */
-	return attach_to_pi_owner(uval, key, ps);
+	return attach_to_pi_owner(uaddr, newval, key, ps, exiting);
 }
 
 /**
@@ -1223,16 +1549,23 @@
 	if (pi_state->owner != current)
 		return -EINVAL;
 
-	raw_spin_lock(&pi_state->pi_mutex.wait_lock);
+	raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
 	new_owner = rt_mutex_next_owner(&pi_state->pi_mutex);
 
 	/*
-	 * It is possible that the next waiter (the one that brought
-	 * this owner to the kernel) timed out and is no longer
-	 * waiting on the lock.
-	 */
-	if (!new_owner)
-		new_owner = this->task;
+	 * When we interleave with futex_lock_pi() where it does
+	 * rt_mutex_timed_futex_lock(), we might observe @this futex_q waiter,
+	 * but the rt_mutex's wait_list can be empty (either still, or again,
+	 * depending on which side we land).
+	 *
+	 * When this happens, give up our locks and try again, giving the
+	 * futex_lock_pi() instance time to complete, either by waiting on the
+	 * rtmutex or removing itself from the futex queue.
+	 */
+	if (!new_owner) {
+		raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
+		return -EAGAIN;
+	}
 
 	/*
 	 * We pass it to the next owner. The WAITERS bit is always
@@ -1244,40 +1577,39 @@
 	if (unlikely(should_fail_futex(true)))
 		ret = -EFAULT;
 
-	if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
+	if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) {
 		ret = -EFAULT;
-	else if (curval != uval)
-		ret = -EINVAL;
-	if (ret) {
-		raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
-		return ret;
-	}
-
-	raw_spin_lock_irq(&pi_state->owner->pi_lock);
-	WARN_ON(list_empty(&pi_state->list));
-	list_del_init(&pi_state->list);
-	raw_spin_unlock_irq(&pi_state->owner->pi_lock);
 
-	raw_spin_lock_irq(&new_owner->pi_lock);
-	WARN_ON(!list_empty(&pi_state->list));
-	list_add(&pi_state->list, &new_owner->pi_state_list);
-	pi_state->owner = new_owner;
-	raw_spin_unlock_irq(&new_owner->pi_lock);
-
-	raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
+	} else if (curval != uval) {
+		/*
+		 * If a unconditional UNLOCK_PI operation (user space did not
+		 * try the TID->0 transition) raced with a waiter setting the
+		 * FUTEX_WAITERS flag between get_user() and locking the hash
+		 * bucket lock, retry the operation.
+		 */
+		if ((FUTEX_TID_MASK & curval) == uval)
+			ret = -EAGAIN;
+		else
+			ret = -EINVAL;
+	}
 
-	deboost = rt_mutex_futex_unlock(&pi_state->pi_mutex, &wake_q);
+	if (!ret) {
+		/*
+		 * This is a point of no return; once we modified the uval
+		 * there is no going back and subsequent operations must
+		 * not fail.
+		 */
+		pi_state_update_owner(pi_state, new_owner);
+		deboost = __rt_mutex_futex_unlock(&pi_state->pi_mutex, &wake_q);
+	}
 
-	/*
-	 * First unlock HB so the waiter does not spin on it once he got woken
-	 * up. Second wake up the waiter before the priority is adjusted. If we
-	 * deboost first (and lose our higher priority), then the task might get
-	 * scheduled away before the wake up can take place.
-	 */
+	raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
 	spin_unlock(&hb->lock);
-	wake_up_q(&wake_q);
-	if (deboost)
+
+	if (deboost) {
+		wake_up_q(&wake_q);
 		rt_mutex_adjust_prio(current);
+	}
 
 	return 0;
 }
@@ -1358,6 +1690,53 @@
 	return ret;
 }
 
+static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr)
+{
+	unsigned int op =	  (encoded_op & 0x70000000) >> 28;
+	unsigned int cmp =	  (encoded_op & 0x0f000000) >> 24;
+	int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 11);
+	int cmparg = sign_extend32(encoded_op & 0x00000fff, 11);
+	int oldval, ret;
+
+	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
+		if (oparg < 0 || oparg > 31) {
+			char comm[sizeof(current->comm)];
+			/*
+			 * kill this print and return -EINVAL when userspace
+			 * is sane again
+			 */
+			pr_info_ratelimited("futex_wake_op: %s tries to shift op by %d; fix this program\n",
+					get_task_comm(comm, current), oparg);
+			oparg &= 31;
+		}
+		oparg = 1 << oparg;
+	}
+
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+		return -EFAULT;
+
+	ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr);
+	if (ret)
+		return ret;
+
+	switch (cmp) {
+	case FUTEX_OP_CMP_EQ:
+		return oldval == cmparg;
+	case FUTEX_OP_CMP_NE:
+		return oldval != cmparg;
+	case FUTEX_OP_CMP_LT:
+		return oldval < cmparg;
+	case FUTEX_OP_CMP_GE:
+		return oldval >= cmparg;
+	case FUTEX_OP_CMP_LE:
+		return oldval <= cmparg;
+	case FUTEX_OP_CMP_GT:
+		return oldval > cmparg;
+	default:
+		return -ENOSYS;
+	}
+}
+
 /*
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
@@ -1474,8 +1853,8 @@
 	if (likely(&hb1->chain != &hb2->chain)) {
 		plist_del(&q->list, &hb1->chain);
 		hb_waiters_dec(hb1);
-		plist_add(&q->list, &hb2->chain);
 		hb_waiters_inc(hb2);
+		plist_add(&q->list, &hb2->chain);
 		q->lock_ptr = &hb2->lock;
 	}
 	get_futex_key_refs(key2);
@@ -1521,6 +1900,8 @@
  * @key1:		the from futex key
  * @key2:		the to futex key
  * @ps:			address to store the pi_state pointer
+ * @exiting:		Pointer to store the task pointer of the owner task
+ *			which is in the middle of exiting
  * @set_waiters:	force setting the FUTEX_WAITERS bit (1) or not (0)
  *
  * Try and get the lock on behalf of the top waiter if we can do it atomically.
@@ -1528,16 +1909,20 @@
  * then direct futex_lock_pi_atomic() to force setting the FUTEX_WAITERS bit.
  * hb1 and hb2 must be held by the caller.
  *
+ * @exiting is only set when the return value is -EBUSY. If so, this holds
+ * a refcount on the exiting task on return and the caller needs to drop it
+ * after waiting for the exit to complete.
+ *
  * Return:
  *  0 - failed to acquire the lock atomically;
  * >0 - acquired the lock, return value is vpid of the top_waiter
  * <0 - error
  */
-static int futex_proxy_trylock_atomic(u32 __user *pifutex,
-				 struct futex_hash_bucket *hb1,
-				 struct futex_hash_bucket *hb2,
-				 union futex_key *key1, union futex_key *key2,
-				 struct futex_pi_state **ps, int set_waiters)
+static int
+futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,
+			   struct futex_hash_bucket *hb2, union futex_key *key1,
+			   union futex_key *key2, struct futex_pi_state **ps,
+			   struct task_struct **exiting, int set_waiters)
 {
 	struct futex_q *top_waiter = NULL;
 	u32 curval;
@@ -1574,7 +1959,7 @@
 	 */
 	vpid = task_pid_vnr(top_waiter->task);
 	ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task,
-				   set_waiters);
+				   exiting, set_waiters);
 	if (ret == 1) {
 		requeue_pi_wake_futex(top_waiter, key2, hb2);
 		return vpid;
@@ -1611,6 +1996,9 @@
 	struct futex_q *this, *next;
 	WAKE_Q(wake_q);
 
+	if (nr_wake < 0 || nr_requeue < 0)
+		return -EINVAL;
+
 	if (requeue_pi) {
 		/*
 		 * Requeue PI only works on two distinct uaddrs. This
@@ -1691,6 +2079,8 @@
 	}
 
 	if (requeue_pi && (task_count - nr_wake < nr_requeue)) {
+		struct task_struct *exiting = NULL;
+
 		/*
 		 * Attempt to acquire uaddr2 and wake the top waiter. If we
 		 * intend to requeue waiters, force setting the FUTEX_WAITERS
@@ -1698,7 +2088,8 @@
 		 * faults rather in the requeue loop below.
 		 */
 		ret = futex_proxy_trylock_atomic(uaddr2, hb1, hb2, &key1,
-						 &key2, &pi_state, nr_requeue);
+						 &key2, &pi_state,
+						 &exiting, nr_requeue);
 
 		/*
 		 * At this point the top_waiter has either taken uaddr2 or is
@@ -1722,7 +2113,8 @@
 			 * rereading and handing potential crap to
 			 * lookup_pi_state.
 			 */
-			ret = lookup_pi_state(ret, hb2, &key2, &pi_state);
+			ret = lookup_pi_state(uaddr2, ret, hb2, &key2,
+					      &pi_state, &exiting);
 		}
 
 		switch (ret) {
@@ -1739,12 +2131,13 @@
 			if (!ret)
 				goto retry;
 			goto out;
+		case -EBUSY:
 		case -EAGAIN:
 			/*
 			 * Two reasons for this:
-			 * - Owner is exiting and we just wait for the
+			 * - EBUSY: Owner is exiting and we just wait for the
 			 *   exit to complete.
-			 * - The user space value changed.
+			 * - EAGAIN: The user space value changed.
 			 */
 			free_pi_state(pi_state);
 			pi_state = NULL;
@@ -1752,6 +2145,12 @@
 			hb_waiters_dec(hb2);
 			put_futex_key(&key2);
 			put_futex_key(&key1);
+			/*
+			 * Handle the case where the owner is in the middle of
+			 * exiting. Wait for the exit to complete otherwise
+			 * this task might loop forever, aka. live lock.
+			 */
+			wait_for_owner_exiting(ret, exiting);
 			cond_resched();
 			goto retry;
 		default:
@@ -1929,8 +2328,12 @@
 
 	/* In the common case we don't take the spinlock, which is nice. */
 retry:
-	lock_ptr = q->lock_ptr;
-	barrier();
+	/*
+	 * q->lock_ptr can change between this read and the following spin_lock.
+	 * Use READ_ONCE to forbid the compiler from reloading q->lock_ptr and
+	 * optimizing lock_ptr out of the logic below.
+	 */
+	lock_ptr = READ_ONCE(q->lock_ptr);
 	if (lock_ptr != NULL) {
 		spin_lock(lock_ptr);
 		/*
@@ -1979,43 +2382,75 @@
 	spin_unlock(q->lock_ptr);
 }
 
-/*
- * Fixup the pi_state owner with the new owner.
- *
- * Must be called with hash bucket lock held and mm->sem held for non
- * private futexes.
- */
-static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
-				struct task_struct *newowner)
+static int __fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
+				  struct task_struct *argowner)
 {
-	u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
 	struct futex_pi_state *pi_state = q->pi_state;
-	struct task_struct *oldowner = pi_state->owner;
-	u32 uval, uninitialized_var(curval), newval;
-	int ret;
-
-	/* Owner died? */
-	if (!pi_state->owner)
-		newtid |= FUTEX_OWNER_DIED;
+	struct task_struct *oldowner, *newowner;
+	u32 uval, curval, newval, newtid;
+	int err = 0;
 
+	oldowner = pi_state->owner;
 	/*
-	 * We are here either because we stole the rtmutex from the
-	 * previous highest priority waiter or we are the highest priority
-	 * waiter but failed to get the rtmutex the first time.
-	 * We have to replace the newowner TID in the user space variable.
+	 * We are here because either:
+	 *
+	 *  - we stole the lock and pi_state->owner needs updating to reflect
+	 *    that (@argowner == current),
+	 *
+	 * or:
+	 *
+	 *  - someone stole our lock and we need to fix things to point to the
+	 *    new owner (@argowner == NULL).
+	 *
+	 * Either way, we have to replace the TID in the user space variable.
 	 * This must be atomic as we have to preserve the owner died bit here.
 	 *
 	 * Note: We write the user space value _before_ changing the pi_state
 	 * because we can fault here. Imagine swapped out pages or a fork
 	 * that marked all the anonymous memory readonly for cow.
 	 *
-	 * Modifying pi_state _before_ the user space value would
-	 * leave the pi_state in an inconsistent state when we fault
-	 * here, because we need to drop the hash bucket lock to
-	 * handle the fault. This might be observed in the PID check
-	 * in lookup_pi_state.
+	 * Modifying pi_state _before_ the user space value would leave the
+	 * pi_state in an inconsistent state when we fault here, because we
+	 * need to drop the locks to handle the fault. This might be observed
+	 * in the PID check in lookup_pi_state.
 	 */
 retry:
+	if (!argowner) {
+		if (oldowner != current) {
+			/*
+			 * We raced against a concurrent self; things are
+			 * already fixed up. Nothing to do.
+			 */
+			return 0;
+		}
+
+		if (__rt_mutex_futex_trylock(&pi_state->pi_mutex)) {
+			/* We got the lock. pi_state is correct. Tell caller */
+			return 1;
+		}
+
+		/*
+		 * Since we just failed the trylock; there must be an owner.
+		 */
+		newowner = rt_mutex_owner(&pi_state->pi_mutex);
+		BUG_ON(!newowner);
+	} else {
+		WARN_ON_ONCE(argowner != current);
+		if (oldowner == current) {
+			/*
+			 * We raced against a concurrent self; things are
+			 * already fixed up. Nothing to do.
+			 */
+			return 1;
+		}
+		newowner = argowner;
+	}
+
+	newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
+	/* Owner died? */
+	if (!pi_state->owner)
+		newtid |= FUTEX_OWNER_DIED;
+
 	if (get_futex_value_locked(&uval, uaddr))
 		goto handle_fault;
 
@@ -2033,48 +2468,75 @@
 	 * We fixed up user space. Now we need to fix the pi_state
 	 * itself.
 	 */
-	if (pi_state->owner != NULL) {
-		raw_spin_lock_irq(&pi_state->owner->pi_lock);
-		WARN_ON(list_empty(&pi_state->list));
-		list_del_init(&pi_state->list);
-		raw_spin_unlock_irq(&pi_state->owner->pi_lock);
-	}
+	pi_state_update_owner(pi_state, newowner);
 
-	pi_state->owner = newowner;
-
-	raw_spin_lock_irq(&newowner->pi_lock);
-	WARN_ON(!list_empty(&pi_state->list));
-	list_add(&pi_state->list, &newowner->pi_state_list);
-	raw_spin_unlock_irq(&newowner->pi_lock);
-	return 0;
+	return argowner == current;
 
 	/*
-	 * To handle the page fault we need to drop the hash bucket
-	 * lock here. That gives the other task (either the highest priority
-	 * waiter itself or the task which stole the rtmutex) the
-	 * chance to try the fixup of the pi_state. So once we are
-	 * back from handling the fault we need to check the pi_state
-	 * after reacquiring the hash bucket lock and before trying to
-	 * do another fixup. When the fixup has been done already we
-	 * simply return.
+	 * To handle the page fault we need to drop the locks here. That gives
+	 * the other task (either the highest priority waiter itself or the
+	 * task which stole the rtmutex) the chance to try the fixup of the
+	 * pi_state. So once we are back from handling the fault we need to
+	 * check the pi_state after reacquiring the locks and before trying to
+	 * do another fixup. When the fixup has been done already we simply
+	 * return.
+	 *
+	 * Note: we hold both hb->lock and pi_mutex->wait_lock. We can safely
+	 * drop hb->lock since the caller owns the hb -> futex_q relation.
+	 * Dropping the pi_mutex->wait_lock requires the state revalidate.
 	 */
 handle_fault:
+	raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
 	spin_unlock(q->lock_ptr);
 
-	ret = fault_in_user_writeable(uaddr);
+	err = fault_in_user_writeable(uaddr);
 
 	spin_lock(q->lock_ptr);
+	raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
 
 	/*
 	 * Check if someone else fixed it for us:
 	 */
 	if (pi_state->owner != oldowner)
-		return 0;
+		return argowner == current;
 
-	if (ret)
-		return ret;
+	/* Retry if err was -EAGAIN or the fault in succeeded */
+	if (!err)
+		goto retry;
 
-	goto retry;
+	/*
+	 * fault_in_user_writeable() failed so user state is immutable. At
+	 * best we can make the kernel state consistent but user state will
+	 * be most likely hosed and any subsequent unlock operation will be
+	 * rejected due to PI futex rule [10].
+	 *
+	 * Ensure that the rtmutex owner is also the pi_state owner despite
+	 * the user space value claiming something different. There is no
+	 * point in unlocking the rtmutex if current is the owner as it
+	 * would need to wait until the next waiter has taken the rtmutex
+	 * to guarantee consistent state. Keep it simple. Userspace asked
+	 * for this wreckaged state.
+	 *
+	 * The rtmutex has an owner - either current or some other
+	 * task. See the EAGAIN loop above.
+	 */
+	pi_state_update_owner(pi_state, rt_mutex_owner(&pi_state->pi_mutex));
+
+	return err;
+}
+
+static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
+				struct task_struct *argowner)
+{
+	struct futex_pi_state *pi_state = q->pi_state;
+	int ret;
+
+	lockdep_assert_held(q->lock_ptr);
+
+	raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
+	ret = __fixup_pi_state_owner(uaddr, q, argowner);
+	raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
+	return ret;
 }
 
 static long futex_wait_restart(struct restart_block *restart);
@@ -2096,60 +2558,39 @@
  */
 static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
 {
-	struct task_struct *owner;
-	int ret = 0;
-
 	if (locked) {
 		/*
 		 * Got the lock. We might not be the anticipated owner if we
 		 * did a lock-steal - fix up the PI-state in that case:
+		 *
+		 * Speculative pi_state->owner read (we don't hold wait_lock);
+		 * since we own the lock pi_state->owner == current is the
+		 * stable state, anything else needs more attention.
 		 */
 		if (q->pi_state->owner != current)
-			ret = fixup_pi_state_owner(uaddr, q, current);
-		goto out;
+			return fixup_pi_state_owner(uaddr, q, current);
+		return 1;
 	}
 
 	/*
-	 * Catch the rare case, where the lock was released when we were on the
-	 * way back before we locked the hash bucket.
+	 * If we didn't get the lock; check if anybody stole it from us. In
+	 * that case, we need to fix up the uval to point to them instead of
+	 * us, otherwise bad things happen. [10]
+	 *
+	 * Another speculative read; pi_state->owner == current is unstable
+	 * but needs our attention.
 	 */
-	if (q->pi_state->owner == current) {
-		/*
-		 * Try to get the rt_mutex now. This might fail as some other
-		 * task acquired the rt_mutex after we removed ourself from the
-		 * rt_mutex waiters list.
-		 */
-		if (rt_mutex_trylock(&q->pi_state->pi_mutex)) {
-			locked = 1;
-			goto out;
-		}
-
-		/*
-		 * pi_state is incorrect, some other task did a lock steal and
-		 * we returned due to timeout or signal without taking the
-		 * rt_mutex. Too late.
-		 */
-		raw_spin_lock(&q->pi_state->pi_mutex.wait_lock);
-		owner = rt_mutex_owner(&q->pi_state->pi_mutex);
-		if (!owner)
-			owner = rt_mutex_next_owner(&q->pi_state->pi_mutex);
-		raw_spin_unlock(&q->pi_state->pi_mutex.wait_lock);
-		ret = fixup_pi_state_owner(uaddr, q, owner);
-		goto out;
-	}
+	if (q->pi_state->owner == current)
+		return fixup_pi_state_owner(uaddr, q, NULL);
 
 	/*
 	 * Paranoia check. If we did not take the lock, then we should not be
-	 * the owner of the rt_mutex.
+	 * the owner of the rt_mutex. Warn and establish consistent state.
 	 */
-	if (rt_mutex_owner(&q->pi_state->pi_mutex) == current)
-		printk(KERN_ERR "fixup_owner: ret = %d pi-mutex: %p "
-				"pi-state %p\n", ret,
-				q->pi_state->pi_mutex.owner,
-				q->pi_state->owner);
+	if (WARN_ON_ONCE(rt_mutex_owner(&q->pi_state->pi_mutex) == current))
+		return fixup_pi_state_owner(uaddr, q, current);
 
-out:
-	return ret ? ret : locked;
+	return 0;
 }
 
 /**
@@ -2370,6 +2811,7 @@
 			 ktime_t *time, int trylock)
 {
 	struct hrtimer_sleeper timeout, *to = NULL;
+	struct task_struct *exiting = NULL;
 	struct futex_hash_bucket *hb;
 	struct futex_q q = futex_q_init;
 	int res, ret;
@@ -2393,7 +2835,8 @@
 retry_private:
 	hb = queue_lock(&q);
 
-	ret = futex_lock_pi_atomic(uaddr, hb, &q.key, &q.pi_state, current, 0);
+	ret = futex_lock_pi_atomic(uaddr, hb, &q.key, &q.pi_state, current,
+				   &exiting, 0);
 	if (unlikely(ret)) {
 		/*
 		 * Atomic work succeeded and we got the lock,
@@ -2406,15 +2849,22 @@
 			goto out_unlock_put_key;
 		case -EFAULT:
 			goto uaddr_faulted;
+		case -EBUSY:
 		case -EAGAIN:
 			/*
 			 * Two reasons for this:
-			 * - Task is exiting and we just wait for the
+			 * - EBUSY: Task is exiting and we just wait for the
 			 *   exit to complete.
-			 * - The user space value changed.
+			 * - EAGAIN: The user space value changed.
 			 */
 			queue_unlock(hb);
 			put_futex_key(&q.key);
+			/*
+			 * Handle the case where the owner is in the middle of
+			 * exiting. Wait for the exit to complete otherwise
+			 * this task might loop forever, aka. live lock.
+			 */
+			wait_for_owner_exiting(ret, exiting);
 			cond_resched();
 			goto retry;
 		default:
@@ -2434,7 +2884,7 @@
 	if (!trylock) {
 		ret = rt_mutex_timed_futex_lock(&q.pi_state->pi_mutex, to);
 	} else {
-		ret = rt_mutex_trylock(&q.pi_state->pi_mutex);
+		ret = rt_mutex_futex_trylock(&q.pi_state->pi_mutex);
 		/* Fixup the trylock return value: */
 		ret = ret ? 0 : -EWOULDBLOCK;
 	}
@@ -2452,13 +2902,6 @@
 	if (res)
 		ret = (res < 0) ? res : 0;
 
-	/*
-	 * If fixup_owner() faulted and was unable to handle the fault, unlock
-	 * it and return the fault to userspace.
-	 */
-	if (ret && (rt_mutex_owner(&q.pi_state->pi_mutex) == current))
-		rt_mutex_unlock(&q.pi_state->pi_mutex);
-
 	/* Unqueue and drop the lock */
 	unqueue_me_pi(&q);
 
@@ -2538,6 +2981,15 @@
 		if (ret == -EFAULT)
 			goto pi_faulted;
 		/*
+		 * A unconditional UNLOCK_PI op raced against a waiter
+		 * setting the FUTEX_WAITERS bit. Try again.
+		 */
+		if (ret == -EAGAIN) {
+			spin_unlock(&hb->lock);
+			put_futex_key(&key);
+			goto retry;
+		}
+		/*
 		 * wake_futex_pi has detected invalid state. Tell user
 		 * space.
 		 */
@@ -2671,7 +3123,6 @@
 {
 	struct hrtimer_sleeper timeout, *to = NULL;
 	struct rt_mutex_waiter rt_waiter;
-	struct rt_mutex *pi_mutex = NULL;
 	struct futex_hash_bucket *hb;
 	union futex_key key2 = FUTEX_KEY_INIT;
 	struct futex_q q = futex_q_init;
@@ -2755,9 +3206,21 @@
 		if (q.pi_state && (q.pi_state->owner != current)) {
 			spin_lock(q.lock_ptr);
 			ret = fixup_pi_state_owner(uaddr2, &q, current);
+			/*
+			 * Drop the reference to the pi state which
+			 * the requeue_pi() code acquired for us.
+			 */
+			free_pi_state(q.pi_state);
 			spin_unlock(q.lock_ptr);
+			/*
+			 * Adjust the return value. It's either -EFAULT or
+			 * success (1) but the caller expects 0 for success.
+			 */
+			ret = ret < 0 ? ret : 0;
 		}
 	} else {
+		struct rt_mutex *pi_mutex;
+
 		/*
 		 * We have been woken up by futex_unlock_pi(), a timeout, or a
 		 * signal.  futex_unlock_pi() will not destroy the lock_ptr nor
@@ -2765,10 +3228,13 @@
 		 */
 		WARN_ON(!q.pi_state);
 		pi_mutex = &q.pi_state->pi_mutex;
-		ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter);
-		debug_rt_mutex_free_waiter(&rt_waiter);
+		ret = rt_mutex_wait_proxy_lock(pi_mutex, to, &rt_waiter);
 
 		spin_lock(q.lock_ptr);
+		if (ret && !rt_mutex_cleanup_proxy_lock(pi_mutex, &rt_waiter))
+			ret = 0;
+
+		debug_rt_mutex_free_waiter(&rt_waiter);
 		/*
 		 * Fixup the pi_state owner and possibly acquire the lock if we
 		 * haven't already.
@@ -2785,14 +3251,7 @@
 		unqueue_me_pi(&q);
 	}
 
-	/*
-	 * If fixup_pi_state_owner() faulted and was unable to handle the
-	 * fault, unlock the rt_mutex and return the fault to userspace.
-	 */
-	if (ret == -EFAULT) {
-		if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
-			rt_mutex_unlock(pi_mutex);
-	} else if (ret == -EINTR) {
+	if (ret == -EINTR) {
 		/*
 		 * We've already been requeued, but cannot restart by calling
 		 * futex_lock_pi() directly. We could restart this syscall, but
@@ -2881,7 +3340,7 @@
 	}
 
 	ret = -EPERM;
-	if (!ptrace_may_access(p, PTRACE_MODE_READ))
+	if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
 		goto err_unlock;
 
 	head = p->robust_list;
@@ -2901,10 +3360,14 @@
  * Process a futex-list entry, check whether it's owned by the
  * dying task, and do notification if so:
  */
-int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
+static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
 {
 	u32 uval, uninitialized_var(nval), mval;
 
+	/* Futex address must be 32bit aligned */
+	if ((((unsigned long)uaddr) % sizeof(*uaddr)) != 0)
+		return -1;
+
 retry:
 	if (get_user(uval, uaddr))
 		return -1;
@@ -2972,7 +3435,7 @@
  *
  * We silently return on any sign of list-walking problem.
  */
-void exit_robust_list(struct task_struct *curr)
+static void exit_robust_list(struct task_struct *curr)
 {
 	struct robust_list_head __user *head = curr->robust_list;
 	struct robust_list __user *entry, *next_entry, *pending;
@@ -3035,6 +3498,114 @@
 				   curr, pip);
 }
 
+static void futex_cleanup(struct task_struct *tsk)
+{
+	if (unlikely(tsk->robust_list)) {
+		exit_robust_list(tsk);
+		tsk->robust_list = NULL;
+	}
+
+#ifdef CONFIG_COMPAT
+	if (unlikely(tsk->compat_robust_list)) {
+		compat_exit_robust_list(tsk);
+		tsk->compat_robust_list = NULL;
+	}
+#endif
+
+	if (unlikely(!list_empty(&tsk->pi_state_list)))
+		exit_pi_state_list(tsk);
+}
+
+/**
+ * futex_exit_recursive - Set the tasks futex state to FUTEX_STATE_DEAD
+ * @tsk:	task to set the state on
+ *
+ * Set the futex exit state of the task lockless. The futex waiter code
+ * observes that state when a task is exiting and loops until the task has
+ * actually finished the futex cleanup. The worst case for this is that the
+ * waiter runs through the wait loop until the state becomes visible.
+ *
+ * This is called from the recursive fault handling path in do_exit().
+ *
+ * This is best effort. Either the futex exit code has run already or
+ * not. If the OWNER_DIED bit has been set on the futex then the waiter can
+ * take it over. If not, the problem is pushed back to user space. If the
+ * futex exit code did not run yet, then an already queued waiter might
+ * block forever, but there is nothing which can be done about that.
+ */
+void futex_exit_recursive(struct task_struct *tsk)
+{
+	/* If the state is FUTEX_STATE_EXITING then futex_exit_mutex is held */
+	if (tsk->futex_state == FUTEX_STATE_EXITING)
+		mutex_unlock(&tsk->futex_exit_mutex);
+	tsk->futex_state = FUTEX_STATE_DEAD;
+}
+
+static void futex_cleanup_begin(struct task_struct *tsk)
+{
+	/*
+	 * Prevent various race issues against a concurrent incoming waiter
+	 * including live locks by forcing the waiter to block on
+	 * tsk->futex_exit_mutex when it observes FUTEX_STATE_EXITING in
+	 * attach_to_pi_owner().
+	 */
+	mutex_lock(&tsk->futex_exit_mutex);
+
+	/*
+	 * Switch the state to FUTEX_STATE_EXITING under tsk->pi_lock.
+	 *
+	 * This ensures that all subsequent checks of tsk->futex_state in
+	 * attach_to_pi_owner() must observe FUTEX_STATE_EXITING with
+	 * tsk->pi_lock held.
+	 *
+	 * It guarantees also that a pi_state which was queued right before
+	 * the state change under tsk->pi_lock by a concurrent waiter must
+	 * be observed in exit_pi_state_list().
+	 */
+	raw_spin_lock_irq(&tsk->pi_lock);
+	tsk->futex_state = FUTEX_STATE_EXITING;
+	raw_spin_unlock_irq(&tsk->pi_lock);
+}
+
+static void futex_cleanup_end(struct task_struct *tsk, int state)
+{
+	/*
+	 * Lockless store. The only side effect is that an observer might
+	 * take another loop until it becomes visible.
+	 */
+	tsk->futex_state = state;
+	/*
+	 * Drop the exit protection. This unblocks waiters which observed
+	 * FUTEX_STATE_EXITING to reevaluate the state.
+	 */
+	mutex_unlock(&tsk->futex_exit_mutex);
+}
+
+void futex_exec_release(struct task_struct *tsk)
+{
+	/*
+	 * The state handling is done for consistency, but in the case of
+	 * exec() there is no way to prevent futher damage as the PID stays
+	 * the same. But for the unlikely and arguably buggy case that a
+	 * futex is held on exec(), this provides at least as much state
+	 * consistency protection which is possible.
+	 */
+	futex_cleanup_begin(tsk);
+	futex_cleanup(tsk);
+	/*
+	 * Reset the state to FUTEX_STATE_OK. The task is alive and about
+	 * exec a new binary.
+	 */
+	futex_cleanup_end(tsk, FUTEX_STATE_OK);
+}
+
+void futex_exit_release(struct task_struct *tsk)
+{
+	futex_cleanup_begin(tsk);
+	futex_cleanup(tsk);
+	futex_cleanup_end(tsk, FUTEX_STATE_DEAD);
+}
+
 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 		u32 __user *uaddr2, u32 val2, u32 val3)
 {
@@ -3127,6 +3698,192 @@
 	return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
 }
 
+#ifdef CONFIG_COMPAT
+/*
+ * Fetch a robust-list pointer. Bit 0 signals PI futexes:
+ */
+static inline int
+compat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
+		   compat_uptr_t __user *head, unsigned int *pi)
+{
+	if (get_user(*uentry, head))
+		return -EFAULT;
+
+	*entry = compat_ptr((*uentry) & ~1);
+	*pi = (unsigned int)(*uentry) & 1;
+
+	return 0;
+}
+
+static void __user *futex_uaddr(struct robust_list __user *entry,
+				compat_long_t futex_offset)
+{
+	compat_uptr_t base = ptr_to_compat(entry);
+	void __user *uaddr = compat_ptr(base + futex_offset);
+
+	return uaddr;
+}
+
+/*
+ * Walk curr->robust_list (very carefully, it's a userspace list!)
+ * and mark any locks found there dead, and notify any waiters.
+ *
+ * We silently return on any sign of list-walking problem.
+ */
+void compat_exit_robust_list(struct task_struct *curr)
+{
+	struct compat_robust_list_head __user *head = curr->compat_robust_list;
+	struct robust_list __user *entry, *next_entry, *pending;
+	unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
+	unsigned int uninitialized_var(next_pi);
+	compat_uptr_t uentry, next_uentry, upending;
+	compat_long_t futex_offset;
+	int rc;
+
+	if (!futex_cmpxchg_enabled)
+		return;
+
+	/*
+	 * Fetch the list head (which was registered earlier, via
+	 * sys_set_robust_list()):
+	 */
+	if (compat_fetch_robust_entry(&uentry, &entry, &head->list.next, &pi))
+		return;
+	/*
+	 * Fetch the relative futex offset:
+	 */
+	if (get_user(futex_offset, &head->futex_offset))
+		return;
+	/*
+	 * Fetch any possibly pending lock-add first, and handle it
+	 * if it exists:
+	 */
+	if (compat_fetch_robust_entry(&upending, &pending,
+			       &head->list_op_pending, &pip))
+		return;
+
+	next_entry = NULL;	/* avoid warning with gcc */
+	while (entry != (struct robust_list __user *) &head->list) {
+		/*
+		 * Fetch the next entry in the list before calling
+		 * handle_futex_death:
+		 */
+		rc = compat_fetch_robust_entry(&next_uentry, &next_entry,
+			(compat_uptr_t __user *)&entry->next, &next_pi);
+		/*
+		 * A pending lock might already be on the list, so
+		 * dont process it twice:
+		 */
+		if (entry != pending) {
+			void __user *uaddr = futex_uaddr(entry, futex_offset);
+
+			if (handle_futex_death(uaddr, curr, pi))
+				return;
+		}
+		if (rc)
+			return;
+		uentry = next_uentry;
+		entry = next_entry;
+		pi = next_pi;
+		/*
+		 * Avoid excessively long or circular lists:
+		 */
+		if (!--limit)
+			break;
+
+		cond_resched();
+	}
+	if (pending) {
+		void __user *uaddr = futex_uaddr(pending, futex_offset);
+
+		handle_futex_death(uaddr, curr, pip);
+	}
+}
+
+COMPAT_SYSCALL_DEFINE2(set_robust_list,
+		struct compat_robust_list_head __user *, head,
+		compat_size_t, len)
+{
+	if (!futex_cmpxchg_enabled)
+		return -ENOSYS;
+
+	if (unlikely(len != sizeof(*head)))
+		return -EINVAL;
+
+	current->compat_robust_list = head;
+
+	return 0;
+}
+
+COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
+			compat_uptr_t __user *, head_ptr,
+			compat_size_t __user *, len_ptr)
+{
+	struct compat_robust_list_head __user *head;
+	unsigned long ret;
+	struct task_struct *p;
+
+	if (!futex_cmpxchg_enabled)
+		return -ENOSYS;
+
+	rcu_read_lock();
+
+	ret = -ESRCH;
+	if (!pid)
+		p = current;
+	else {
+		p = find_task_by_vpid(pid);
+		if (!p)
+			goto err_unlock;
+	}
+
+	ret = -EPERM;
+	if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
+		goto err_unlock;
+
+	head = p->compat_robust_list;
+	rcu_read_unlock();
+
+	if (put_user(sizeof(*head), len_ptr))
+		return -EFAULT;
+	return put_user(ptr_to_compat(head), head_ptr);
+
+err_unlock:
+	rcu_read_unlock();
+
+	return ret;
+}
+
+COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+		struct compat_timespec __user *, utime, u32 __user *, uaddr2,
+		u32, val3)
+{
+	struct timespec ts;
+	ktime_t t, *tp = NULL;
+	int val2 = 0;
+	int cmd = op & FUTEX_CMD_MASK;
+
+	if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+		      cmd == FUTEX_WAIT_BITSET ||
+		      cmd == FUTEX_WAIT_REQUEUE_PI)) {
+		if (compat_get_timespec(&ts, utime))
+			return -EFAULT;
+		if (!timespec_valid(&ts))
+			return -EINVAL;
+
+		t = timespec_to_ktime(ts);
+		if (cmd == FUTEX_WAIT)
+			t = ktime_add_safe(ktime_get(), t);
+		tp = &t;
+	}
+	if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
+	    cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
+		val2 = (int) (unsigned long) utime;
+
+	return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
+}
+#endif /* CONFIG_COMPAT */
+
 static void __init futex_detect_cmpxchg(void)
 {
 #ifndef CONFIG_HAVE_FUTEX_CMPXCHG
@@ -3175,4 +3932,4 @@
 
 	return 0;
 }
-__initcall(futex_init);
+core_initcall(futex_init);
--- linux-4.4.0.orig/kernel/gcov/Kconfig
+++ linux-4.4.0/kernel/gcov/Kconfig
@@ -37,6 +37,7 @@
 
 config GCOV_PROFILE_ALL
 	bool "Profile entire Kernel"
+	depends on !COMPILE_TEST
 	depends on GCOV_KERNEL
 	depends on ARCH_HAS_GCOV_PROFILE_ALL
 	default n
--- linux-4.4.0.orig/kernel/gcov/base.c
+++ linux-4.4.0/kernel/gcov/base.c
@@ -98,6 +98,12 @@
 }
 EXPORT_SYMBOL(__gcov_merge_icall_topn);
 
+void __gcov_exit(void)
+{
+	/* Unused. */
+}
+EXPORT_SYMBOL(__gcov_exit);
+
 /**
  * gcov_enable_events - enable event reporting through gcov_event()
  *
@@ -123,11 +129,6 @@
 }
 
 #ifdef CONFIG_MODULES
-static inline int within(void *addr, void *start, unsigned long size)
-{
-	return ((addr >= start) && (addr < start + size));
-}
-
 /* Update list and generate events when modules are unloaded. */
 static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
 				void *data)
@@ -142,7 +143,7 @@
 
 	/* Remove entries located in module from linked list. */
 	while ((info = gcov_info_next(info))) {
-		if (within(info, mod->module_core, mod->core_size)) {
+		if (within_module((unsigned long)info, mod)) {
 			gcov_info_unlink(prev, info);
 			if (gcov_events_enabled)
 				gcov_event(GCOV_REMOVE, info);
--- linux-4.4.0.orig/kernel/gcov/fs.c
+++ linux-4.4.0/kernel/gcov/fs.c
@@ -108,9 +108,9 @@
 {
 	struct gcov_iterator *iter = data;
 
+	(*pos)++;
 	if (gcov_iter_next(iter))
 		return NULL;
-	(*pos)++;
 
 	return iter;
 }
--- linux-4.4.0.orig/kernel/gcov/gcc_4_7.c
+++ linux-4.4.0/kernel/gcov/gcc_4_7.c
@@ -18,7 +18,11 @@
 #include <linux/vmalloc.h>
 #include "gcov.h"
 
-#if __GNUC__ == 5 && __GNUC_MINOR__ >= 1
+#if (__GNUC__ >= 10)
+#define GCOV_COUNTERS			8
+#elif (__GNUC__ >= 7)
+#define GCOV_COUNTERS			9
+#elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
 #define GCOV_COUNTERS			10
 #elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9
 #define GCOV_COUNTERS			9
--- linux-4.4.0.orig/kernel/groups.c
+++ linux-4.4.0/kernel/groups.c
@@ -101,7 +101,7 @@
 }
 
 /* a simple Shell sort */
-static void groups_sort(struct group_info *group_info)
+void groups_sort(struct group_info *group_info)
 {
 	int base, max, stride;
 	int gidsetsize = group_info->ngroups;
@@ -128,6 +128,7 @@
 		stride /= 3;
 	}
 }
+EXPORT_SYMBOL(groups_sort);
 
 /* a simple bsearch */
 int groups_search(const struct group_info *group_info, kgid_t grp)
@@ -159,7 +160,6 @@
 void set_groups(struct cred *new, struct group_info *group_info)
 {
 	put_group_info(new->group_info);
-	groups_sort(group_info);
 	get_group_info(group_info);
 	new->group_info = group_info;
 }
@@ -243,6 +243,7 @@
 		return retval;
 	}
 
+	groups_sort(group_info);
 	retval = set_current_groups(group_info);
 	put_group_info(group_info);
 
--- linux-4.4.0.orig/kernel/hung_task.c
+++ linux-4.4.0/kernel/hung_task.c
@@ -30,7 +30,7 @@
  * is disabled during the critical section. It also controls the size of
  * the RCU grace period. So it needs to be upper-bound.
  */
-#define HUNG_TASK_BATCHING 1024
+#define HUNG_TASK_LOCK_BREAK (HZ / 10)
 
 /*
  * Zero means infinite timeout - no checking done:
@@ -158,7 +158,7 @@
 static void check_hung_uninterruptible_tasks(unsigned long timeout)
 {
 	int max_count = sysctl_hung_task_check_count;
-	int batch_count = HUNG_TASK_BATCHING;
+	unsigned long last_break = jiffies;
 	struct task_struct *g, *t;
 
 	/*
@@ -172,10 +172,10 @@
 	for_each_process_thread(g, t) {
 		if (!max_count--)
 			goto unlock;
-		if (!--batch_count) {
-			batch_count = HUNG_TASK_BATCHING;
+		if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) {
 			if (!rcu_lock_break(g, t))
 				goto unlock;
+			last_break = jiffies;
 		}
 		/* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
 		if (t->state == TASK_UNINTERRUPTIBLE)
--- linux-4.4.0.orig/kernel/irq/Kconfig
+++ linux-4.4.0/kernel/irq/Kconfig
@@ -91,6 +91,10 @@
 config IRQ_FORCED_THREADING
        bool
 
+config IRQ_FORCED_THREADING_DEFAULT
+	bool "Use IRQ threading by default"
+	depends on IRQ_FORCED_THREADING
+
 config SPARSE_IRQ
 	bool "Support sparse irq numbering" if MAY_HAVE_SPARSE_IRQ
 	---help---
--- linux-4.4.0.orig/kernel/irq/chip.c
+++ linux-4.4.0/kernel/irq/chip.c
@@ -338,7 +338,6 @@
 	raw_spin_lock_irq(&desc->lock);
 
 	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
-	kstat_incr_irqs_this_cpu(desc);
 
 	action = desc->action;
 	if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) {
@@ -346,6 +345,7 @@
 		goto out_unlock;
 	}
 
+	kstat_incr_irqs_this_cpu(desc);
 	irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
 	raw_spin_unlock_irq(&desc->lock);
 
@@ -412,13 +412,13 @@
 		goto out_unlock;
 
 	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
-	kstat_incr_irqs_this_cpu(desc);
 
 	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
 		desc->istate |= IRQS_PENDING;
 		goto out_unlock;
 	}
 
+	kstat_incr_irqs_this_cpu(desc);
 	handle_irq_event(desc);
 
 out_unlock:
@@ -462,7 +462,6 @@
 		goto out_unlock;
 
 	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
-	kstat_incr_irqs_this_cpu(desc);
 
 	/*
 	 * If its disabled or no action available
@@ -473,6 +472,7 @@
 		goto out_unlock;
 	}
 
+	kstat_incr_irqs_this_cpu(desc);
 	handle_irq_event(desc);
 
 	cond_unmask_irq(desc);
@@ -532,7 +532,6 @@
 		goto out;
 
 	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
-	kstat_incr_irqs_this_cpu(desc);
 
 	/*
 	 * If its disabled or no action available
@@ -544,6 +543,7 @@
 		goto out;
 	}
 
+	kstat_incr_irqs_this_cpu(desc);
 	if (desc->istate & IRQS_ONESHOT)
 		mask_irq(desc);
 
@@ -810,8 +810,8 @@
 	if (!desc)
 		return;
 
-	__irq_do_set_handler(desc, handle, 1, NULL);
 	desc->irq_common_data.handler_data = data;
+	__irq_do_set_handler(desc, handle, 1, NULL);
 
 	irq_put_desc_busunlock(desc, flags);
 }
@@ -950,6 +950,7 @@
 	data = data->parent_data;
 	data->chip->irq_ack(data);
 }
+EXPORT_SYMBOL_GPL(irq_chip_ack_parent);
 
 /**
  * irq_chip_mask_parent - Mask the parent interrupt
@@ -1056,6 +1057,10 @@
 int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on)
 {
 	data = data->parent_data;
+
+	if (data->chip->flags & IRQCHIP_SKIP_SET_WAKE)
+		return 0;
+
 	if (data->chip->irq_set_wake)
 		return data->chip->irq_set_wake(data, on);
 
--- linux-4.4.0.orig/kernel/irq/generic-chip.c
+++ linux-4.4.0/kernel/irq/generic-chip.c
@@ -411,8 +411,29 @@
 }
 EXPORT_SYMBOL_GPL(irq_map_generic_chip);
 
+static void irq_unmap_generic_chip(struct irq_domain *d, unsigned int virq)
+{
+	struct irq_data *data = irq_domain_get_irq_data(d, virq);
+	struct irq_domain_chip_generic *dgc = d->gc;
+	unsigned int hw_irq = data->hwirq;
+	struct irq_chip_generic *gc;
+	int irq_idx;
+
+	gc = irq_get_domain_generic_chip(d, hw_irq);
+	if (!gc)
+		return;
+
+	irq_idx = hw_irq % dgc->irqs_per_chip;
+
+	clear_bit(irq_idx, &gc->installed);
+	irq_domain_set_info(d, virq, hw_irq, &no_irq_chip, NULL, NULL, NULL,
+			    NULL);
+
+}
+
 struct irq_domain_ops irq_generic_chip_ops = {
 	.map	= irq_map_generic_chip,
+	.unmap  = irq_unmap_generic_chip,
 	.xlate	= irq_domain_xlate_onetwocell,
 };
 EXPORT_SYMBOL_GPL(irq_generic_chip_ops);
--- linux-4.4.0.orig/kernel/irq/handle.c
+++ linux-4.4.0/kernel/irq/handle.c
@@ -138,7 +138,8 @@
 	unsigned int flags = 0, irq = desc->irq_data.irq;
 	struct irqaction *action = desc->action;
 
-	do {
+	/* action might have become NULL since we dropped the lock */
+	while (action) {
 		irqreturn_t res;
 
 		trace_irq_handler_entry(irq, action);
@@ -173,7 +174,7 @@
 
 		retval |= res;
 		action = action->next;
-	} while (action);
+	}
 
 	add_interrupt_randomness(irq, flags);
 
--- linux-4.4.0.orig/kernel/irq/irqdomain.c
+++ linux-4.4.0/kernel/irq/irqdomain.c
@@ -60,6 +60,7 @@
 	fwid->fwnode.type = FWNODE_IRQCHIP;
 	return &fwid->fwnode;
 }
+EXPORT_SYMBOL_GPL(irq_domain_alloc_fwnode);
 
 /**
  * irq_domain_free_fwnode - Free a non-OF-backed fwnode_handle
@@ -70,13 +71,14 @@
 {
 	struct irqchip_fwid *fwid;
 
-	if (WARN_ON(fwnode->type != FWNODE_IRQCHIP))
+	if (WARN_ON(!is_fwnode_irqchip(fwnode)))
 		return;
 
 	fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
 	kfree(fwid->name);
 	kfree(fwid);
 }
+EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
 
 /**
  * __irq_domain_add() - Allocate a new irq_domain data structure
@@ -1013,6 +1015,7 @@
 
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
 
 /**
  * irq_domain_set_hwirq_and_chip - Set hwirq and irqchip of @virq at @domain
@@ -1343,6 +1346,7 @@
 
 	return (irq_data && irq_data->domain == domain) ? irq_data : NULL;
 }
+EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
 
 /**
  * irq_domain_set_info - Set the complete data for a @virq in @domain
--- linux-4.4.0.orig/kernel/irq/manage.c
+++ linux-4.4.0/kernel/irq/manage.c
@@ -22,14 +22,20 @@
 #include "internals.h"
 
 #ifdef CONFIG_IRQ_FORCED_THREADING
-__read_mostly bool force_irqthreads;
+__read_mostly bool force_irqthreads = IS_ENABLED(CONFIG_IRQ_FORCED_THREADING_DEFAULT);
 
 static int __init setup_forced_irqthreads(char *arg)
 {
 	force_irqthreads = true;
 	return 0;
 }
+static int __init setup_no_irqthreads(char *arg)
+{
+	force_irqthreads = false;
+	return 0;
+}
 early_param("threadirqs", setup_forced_irqthreads);
+early_param("nothreadirqs", setup_no_irqthreads);
 #endif
 
 static void __synchronize_hardirq(struct irq_desc *desc)
@@ -220,7 +226,11 @@
 
 	if (desc->affinity_notify) {
 		kref_get(&desc->affinity_notify->kref);
-		schedule_work(&desc->affinity_notify->work);
+		if (!schedule_work(&desc->affinity_notify->work)) {
+			/* Work was already scheduled, drop our extra ref */
+			kref_put(&desc->affinity_notify->kref,
+				 desc->affinity_notify->release);
+		}
 	}
 	irqd_set(data, IRQD_AFFINITY_SET);
 
@@ -319,8 +329,13 @@
 	desc->affinity_notify = notify;
 	raw_spin_unlock_irqrestore(&desc->lock, flags);
 
-	if (old_notify)
+	if (old_notify) {
+		if (cancel_work_sync(&old_notify->work)) {
+			/* Pending work had a ref, put that one too */
+			kref_put(&old_notify->kref, old_notify->release);
+		}
 		kref_put(&old_notify->kref, old_notify->release);
+	}
 
 	return 0;
 }
@@ -836,7 +851,7 @@
 	 * This code is triggered unconditionally. Check the affinity
 	 * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out.
 	 */
-	if (desc->irq_common_data.affinity)
+	if (cpumask_available(desc->irq_common_data.affinity))
 		cpumask_copy(mask, desc->irq_common_data.affinity);
 	else
 		valid = false;
@@ -864,6 +879,9 @@
 
 	local_bh_disable();
 	ret = action->thread_fn(action->irq, action->dev_id);
+	if (ret == IRQ_HANDLED)
+		atomic_inc(&desc->threads_handled);
+
 	irq_finalize_oneshot(desc, action);
 	local_bh_enable();
 	return ret;
@@ -880,6 +898,9 @@
 	irqreturn_t ret;
 
 	ret = action->thread_fn(action->irq, action->dev_id);
+	if (ret == IRQ_HANDLED)
+		atomic_inc(&desc->threads_handled);
+
 	irq_finalize_oneshot(desc, action);
 	return ret;
 }
@@ -957,8 +978,6 @@
 		irq_thread_check_affinity(desc, action);
 
 		action_ret = handler_fn(desc, action);
-		if (action_ret == IRQ_HANDLED)
-			atomic_inc(&desc->threads_handled);
 		if (action_ret == IRQ_WAKE_THREAD)
 			irq_wake_secondary(desc, action);
 
@@ -1012,6 +1031,13 @@
 	if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT))
 		return 0;
 
+	/*
+	 * No further action required for interrupts which are requested as
+	 * threaded interrupts already
+	 */
+	if (new->handler == irq_default_primary_handler)
+		return 0;
+
 	new->flags |= IRQF_ONESHOT;
 
 	/*
@@ -1019,7 +1045,7 @@
 	 * thread handler. We force thread them as well by creating a
 	 * secondary action.
 	 */
-	if (new->handler != irq_default_primary_handler && new->thread_fn) {
+	if (new->handler && new->thread_fn) {
 		/* Allocate the secondary action */
 		new->secondary = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
 		if (!new->secondary)
@@ -1287,8 +1313,10 @@
 			ret = __irq_set_trigger(desc,
 						new->flags & IRQF_TRIGGER_MASK);
 
-			if (ret)
+			if (ret) {
+				irq_release_resources(desc);
 				goto out_mask;
+			}
 		}
 
 		desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
@@ -1303,7 +1331,8 @@
 		if (new->flags & IRQF_ONESHOT)
 			desc->istate |= IRQS_ONESHOT;
 
-		if (irq_settings_can_autoenable(desc))
+		if (!(new->flags & IRQF_NO_AUTOEN) &&
+		    irq_settings_can_autoenable(desc))
 			irq_startup(desc, true);
 		else
 			/* Undo nested disables: */
@@ -1615,10 +1644,15 @@
 	 * which interrupt is which (messes up the interrupt freeing
 	 * logic etc).
 	 *
+	 * Also shared interrupts do not go well with disabling auto enable.
+	 * The sharing interrupt might request it while it's still disabled
+	 * and then wait for interrupts forever.
+	 *
 	 * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and
 	 * it cannot be set along with IRQF_NO_SUSPEND.
 	 */
 	if (((irqflags & IRQF_SHARED) && !dev_id) ||
+	    ((irqflags & IRQF_SHARED) && (irqflags & IRQF_NO_AUTOEN)) ||
 	    (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||
 	    ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))
 		return -EINVAL;
--- linux-4.4.0.orig/kernel/irq/migration.c
+++ linux-4.4.0/kernel/irq/migration.c
@@ -7,17 +7,18 @@
 void irq_move_masked_irq(struct irq_data *idata)
 {
 	struct irq_desc *desc = irq_data_to_desc(idata);
-	struct irq_chip *chip = desc->irq_data.chip;
+	struct irq_data *data = &desc->irq_data;
+	struct irq_chip *chip = data->chip;
 
-	if (likely(!irqd_is_setaffinity_pending(&desc->irq_data)))
+	if (likely(!irqd_is_setaffinity_pending(data)))
 		return;
 
-	irqd_clr_move_pending(&desc->irq_data);
+	irqd_clr_move_pending(data);
 
 	/*
 	 * Paranoia: cpu-local interrupts shouldn't be calling in here anyway.
 	 */
-	if (irqd_is_per_cpu(&desc->irq_data)) {
+	if (irqd_is_per_cpu(data)) {
 		WARN_ON(1);
 		return;
 	}
@@ -42,9 +43,20 @@
 	 * For correct operation this depends on the caller
 	 * masking the irqs.
 	 */
-	if (cpumask_any_and(desc->pending_mask, cpu_online_mask) < nr_cpu_ids)
-		irq_do_set_affinity(&desc->irq_data, desc->pending_mask, false);
+	if (cpumask_any_and(desc->pending_mask, cpu_online_mask) < nr_cpu_ids) {
+		int ret;
 
+		ret = irq_do_set_affinity(data, desc->pending_mask, false);
+		/*
+		 * If the there is a cleanup pending in the underlying
+		 * vector management, reschedule the move for the next
+		 * interrupt. Leave desc->pending_mask intact.
+		 */
+		if (ret == -EBUSY) {
+			irqd_set_move_pending(data);
+			return;
+		}
+	}
 	cpumask_clear(desc->pending_mask);
 }
 
--- linux-4.4.0.orig/kernel/irq/msi.c
+++ linux-4.4.0/kernel/irq/msi.c
@@ -268,7 +268,7 @@
 	struct msi_domain_ops *ops = info->ops;
 	msi_alloc_info_t arg;
 	struct msi_desc *desc;
-	int i, ret, virq = -1;
+	int i, ret, virq;
 
 	ret = ops->msi_check(domain, info, dev);
 	if (ret == 0)
@@ -278,12 +278,8 @@
 
 	for_each_msi_entry(desc, dev) {
 		ops->set_desc(&arg, desc);
-		if (info->flags & MSI_FLAG_IDENTITY_MAP)
-			virq = (int)ops->get_hwirq(info, &arg);
-		else
-			virq = -1;
 
-		virq = __irq_domain_alloc_irqs(domain, virq, desc->nvec_used,
+		virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
 					       dev_to_node(dev), &arg, false);
 		if (virq < 0) {
 			ret = -ENOSPC;
@@ -302,11 +298,23 @@
 		ops->msi_finish(&arg, 0);
 
 	for_each_msi_entry(desc, dev) {
+		virq = desc->irq;
 		if (desc->nvec_used == 1)
 			dev_dbg(dev, "irq %d for MSI\n", virq);
 		else
 			dev_dbg(dev, "irq [%d-%d] for MSI\n",
 				virq, virq + desc->nvec_used - 1);
+		/*
+		 * This flag is set by the PCI layer as we need to activate
+		 * the MSI entries before the PCI layer enables MSI in the
+		 * card. Otherwise the card latches a random msi message.
+		 */
+		if (info->flags & MSI_FLAG_ACTIVATE_EARLY) {
+			struct irq_data *irq_data;
+
+			irq_data = irq_domain_get_irq_data(domain, desc->irq);
+			irq_domain_activate_irq(irq_data);
+		}
 	}
 
 	return 0;
--- linux-4.4.0.orig/kernel/irq/resend.c
+++ linux-4.4.0/kernel/irq/resend.c
@@ -37,6 +37,8 @@
 		irq = find_first_bit(irqs_resend, nr_irqs);
 		clear_bit(irq, irqs_resend);
 		desc = irq_to_desc(irq);
+		if (!desc)
+			continue;
 		local_irq_disable();
 		desc->handle_irq(desc);
 		local_irq_enable();
--- linux-4.4.0.orig/kernel/jump_label.c
+++ linux-4.4.0/kernel/jump_label.c
@@ -58,13 +58,36 @@
 
 void static_key_slow_inc(struct static_key *key)
 {
+	int v, v1;
+
 	STATIC_KEY_CHECK_USE();
-	if (atomic_inc_not_zero(&key->enabled))
-		return;
+
+	/*
+	 * Careful if we get concurrent static_key_slow_inc() calls;
+	 * later calls must wait for the first one to _finish_ the
+	 * jump_label_update() process.  At the same time, however,
+	 * the jump_label_update() call below wants to see
+	 * static_key_enabled(&key) for jumps to be updated properly.
+	 *
+	 * So give a special meaning to negative key->enabled: it sends
+	 * static_key_slow_inc() down the slow path, and it is non-zero
+	 * so it counts as "enabled" in jump_label_update().  Note that
+	 * atomic_inc_unless_negative() checks >= 0, so roll our own.
+	 */
+	for (v = atomic_read(&key->enabled); v > 0; v = v1) {
+		v1 = atomic_cmpxchg(&key->enabled, v, v + 1);
+		if (likely(v1 == v))
+			return;
+	}
 
 	jump_label_lock();
-	if (atomic_inc_return(&key->enabled) == 1)
+	if (atomic_read(&key->enabled) == 0) {
+		atomic_set(&key->enabled, -1);
 		jump_label_update(key);
+		atomic_set(&key->enabled, 1);
+	} else {
+		atomic_inc(&key->enabled);
+	}
 	jump_label_unlock();
 }
 EXPORT_SYMBOL_GPL(static_key_slow_inc);
@@ -72,6 +95,13 @@
 static void __static_key_slow_dec(struct static_key *key,
 		unsigned long rate_limit, struct delayed_work *work)
 {
+	/*
+	 * The negative count check is valid even when a negative
+	 * key->enabled is in use by static_key_slow_inc(); a
+	 * __static_key_slow_dec() before the first static_key_slow_inc()
+	 * returns is unbalanced, because all other static_key_slow_inc()
+	 * instances block while the update is in progress.
+	 */
 	if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) {
 		WARN(atomic_read(&key->enabled) < 0,
 		     "jump label: negative count!\n");
@@ -108,6 +138,13 @@
 }
 EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred);
 
+void static_key_deferred_flush(struct static_key_deferred *key)
+{
+	STATIC_KEY_CHECK_USE();
+	flush_delayed_work(&key->work);
+}
+EXPORT_SYMBOL_GPL(static_key_deferred_flush);
+
 void jump_label_rate_limit(struct static_key_deferred *key,
 		unsigned long rl)
 {
@@ -205,6 +242,9 @@
 	struct static_key *key = NULL;
 	struct jump_entry *iter;
 
+	if (static_key_initialized)
+		return;
+
 	jump_label_lock();
 	jump_label_sort_entries(iter_start, iter_stop);
 
@@ -516,7 +556,7 @@
 
 	return 0;
 }
-late_initcall(jump_label_test);
+early_initcall(jump_label_test);
 #endif /* STATIC_KEYS_SELFTEST */
 
 #endif /* HAVE_JUMP_LABEL */
--- linux-4.4.0.orig/kernel/kcmp.c
+++ linux-4.4.0/kernel/kcmp.c
@@ -122,8 +122,8 @@
 			&task2->signal->cred_guard_mutex);
 	if (ret)
 		goto err;
-	if (!ptrace_may_access(task1, PTRACE_MODE_READ) ||
-	    !ptrace_may_access(task2, PTRACE_MODE_READ)) {
+	if (!ptrace_may_access(task1, PTRACE_MODE_READ_REALCREDS) ||
+	    !ptrace_may_access(task2, PTRACE_MODE_READ_REALCREDS)) {
 		ret = -EPERM;
 		goto err_unlock;
 	}
--- linux-4.4.0.orig/kernel/kexec.c
+++ linux-4.4.0/kernel/kexec.c
@@ -17,6 +17,7 @@
 #include <linux/syscalls.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include "kexec_internal.h"
 
@@ -131,7 +132,7 @@
 	int result;
 
 	/* We only trust the superuser with rebooting the system. */
-	if (!capable(CAP_SYS_BOOT) || kexec_load_disabled)
+	if (!capable(CAP_SYS_BOOT) || kexec_load_disabled || secure_modules())
 		return -EPERM;
 
 	/*
--- linux-4.4.0.orig/kernel/kexec_file.c
+++ linux-4.4.0/kernel/kexec_file.c
@@ -317,6 +317,12 @@
 	if (!capable(CAP_SYS_BOOT) || kexec_load_disabled)
 		return -EPERM;
 
+	/* Don't permit images to be loaded into trusted kernels if we're not
+	 * going to verify the signature on them
+	 */
+	if (!IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG) && secure_modules())
+		return -EPERM;
+
 	/* Make sure we have a legal set of flags */
 	if (flags != (flags & KEXEC_FILE_FLAGS))
 		return -EINVAL;
@@ -934,7 +940,10 @@
 	return 0;
 out:
 	vfree(pi->sechdrs);
+	pi->sechdrs = NULL;
+
 	vfree(pi->purgatory_buf);
+	pi->purgatory_buf = NULL;
 	return ret;
 }
 
--- linux-4.4.0.orig/kernel/kmod.c
+++ linux-4.4.0/kernel/kmod.c
@@ -28,6 +28,7 @@
 #include <linux/cred.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
+#include <linux/fs_struct.h>
 #include <linux/workqueue.h>
 #include <linux/security.h>
 #include <linux/mount.h>
@@ -119,7 +120,7 @@
  * invoke it.
  *
  * If module auto-loading support is disabled then this function
- * becomes a no-operation.
+ * simply returns -ENOENT.
  */
 int __request_module(bool wait, const char *fmt, ...)
 {
@@ -140,7 +141,7 @@
 	WARN_ON_ONCE(wait && current_is_async());
 
 	if (!modprobe_path[0])
-		return 0;
+		return -ENOENT;
 
 	va_start(args, fmt);
 	ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
@@ -223,6 +224,14 @@
 	spin_unlock_irq(&current->sighand->siglock);
 
 	/*
+	 * Initial kernel threads share ther FS with init, in order to
+	 * get the init root directory. But we've now created a new
+	 * thread that is going to execve a user process and has its own
+	 * 'struct fs_struct'. Reset umask to the default.
+	 */
+	current->fs->umask = 0022;
+
+	/*
 	 * Our parent (unbound workqueue) runs with elevated scheduling
 	 * priority. Avoid propagating that into the userspace child.
 	 */
--- linux-4.4.0.orig/kernel/kprobes.c
+++ linux-4.4.0/kernel/kprobes.c
@@ -125,7 +125,7 @@
 	return module_alloc(PAGE_SIZE);
 }
 
-static void free_insn_page(void *page)
+void __weak free_insn_page(void *page)
 {
 	module_memfree(page);
 }
@@ -514,8 +514,14 @@
 	struct optimized_kprobe *op, *tmp;
 
 	list_for_each_entry_safe(op, tmp, &freeing_list, list) {
-		BUG_ON(!kprobe_unused(&op->kp));
 		list_del_init(&op->list);
+		if (WARN_ON_ONCE(!kprobe_unused(&op->kp))) {
+			/*
+			 * This must not happen, but if there is a kprobe
+			 * still in use, keep it on kprobes hash list.
+			 */
+			continue;
+		}
 		free_aggr_kprobe(&op->kp);
 	}
 }
@@ -555,15 +561,16 @@
 	do_free_cleaned_kprobes();
 
 	mutex_unlock(&module_mutex);
-	mutex_unlock(&kprobe_mutex);
 
 	/* Step 5: Kick optimizer again if needed */
 	if (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list))
 		kick_kprobe_optimizer();
+
+	mutex_unlock(&kprobe_mutex);
 }
 
 /* Wait for completing optimization and unoptimization */
-static void wait_for_kprobe_optimizer(void)
+void wait_for_kprobe_optimizer(void)
 {
 	mutex_lock(&kprobe_mutex);
 
@@ -665,7 +672,7 @@
 }
 
 /* Cancel unoptimizing for reusing */
-static void reuse_unused_kprobe(struct kprobe *ap)
+static int reuse_unused_kprobe(struct kprobe *ap)
 {
 	struct optimized_kprobe *op;
 
@@ -681,8 +688,11 @@
 	/* Enable the probe again */
 	ap->flags &= ~KPROBE_FLAG_DISABLED;
 	/* Optimize it again (remove from op->list) */
-	BUG_ON(!kprobe_optready(ap));
+	if (!kprobe_optready(ap))
+		return -EINVAL;
+
 	optimize_kprobe(ap);
+	return 0;
 }
 
 /* Remove optimized instructions */
@@ -894,11 +904,16 @@
 #define kprobe_disarmed(p)			kprobe_disabled(p)
 #define wait_for_kprobe_optimizer()		do {} while (0)
 
-/* There should be no unused kprobes can be reused without optimization */
-static void reuse_unused_kprobe(struct kprobe *ap)
+static int reuse_unused_kprobe(struct kprobe *ap)
 {
+	/*
+	 * If the optimized kprobe is NOT supported, the aggr kprobe is
+	 * released at the same time that the last aggregated kprobe is
+	 * unregistered.
+	 * Thus there should be no chance to reuse unused kprobe.
+	 */
 	printk(KERN_ERR "Error: There should be no unused kprobe here.\n");
-	BUG_ON(kprobe_unused(ap));
+	return -EINVAL;
 }
 
 static void free_aggr_kprobe(struct kprobe *p)
@@ -1135,6 +1150,26 @@
 }
 NOKPROBE_SYMBOL(kretprobe_table_unlock);
 
+struct kprobe kprobe_busy = {
+	.addr = (void *) get_kprobe,
+};
+
+void kprobe_busy_begin(void)
+{
+	struct kprobe_ctlblk *kcb;
+
+	preempt_disable();
+	__this_cpu_write(current_kprobe, &kprobe_busy);
+	kcb = get_kprobe_ctlblk();
+	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+}
+
+void kprobe_busy_end(void)
+{
+	__this_cpu_write(current_kprobe, NULL);
+	preempt_enable();
+}
+
 /*
  * This function is called from finish_task_switch when task tk becomes dead,
  * so that we can recycle any function-return probe instances associated
@@ -1152,6 +1187,8 @@
 		/* Early boot.  kretprobe_table_locks not yet initialized. */
 		return;
 
+	kprobe_busy_begin();
+
 	INIT_HLIST_HEAD(&empty_rp);
 	hash = hash_ptr(tk, KPROBE_HASH_BITS);
 	head = &kretprobe_inst_table[hash];
@@ -1165,6 +1202,8 @@
 		hlist_del(&ri->hlist);
 		kfree(ri);
 	}
+
+	kprobe_busy_end();
 }
 NOKPROBE_SYMBOL(kprobe_flush_task);
 
@@ -1276,9 +1315,12 @@
 			goto out;
 		}
 		init_aggr_kprobe(ap, orig_p);
-	} else if (kprobe_unused(ap))
+	} else if (kprobe_unused(ap)) {
 		/* This probe is going to die. Rescue it */
-		reuse_unused_kprobe(ap);
+		ret = reuse_unused_kprobe(ap);
+		if (ret)
+			goto out;
+	}
 
 	if (kprobe_gone(ap)) {
 		/*
@@ -1443,7 +1485,8 @@
 	/* Ensure it is not in reserved area nor out of text */
 	if (!kernel_text_address((unsigned long) p->addr) ||
 	    within_kprobe_blacklist((unsigned long) p->addr) ||
-	    jump_label_text_reserved(p->addr, p->addr)) {
+	    jump_label_text_reserved(p->addr, p->addr) ||
+	    find_bug((unsigned long)p->addr)) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1841,6 +1884,10 @@
 	int i;
 	void *addr;
 
+	/* If only rp->kp.addr is specified, check reregistering kprobes */
+	if (rp->kp.addr && check_kprobe_rereg(&rp->kp))
+		return -EINVAL;
+
 	if (kretprobe_blacklist_size) {
 		addr = kprobe_addr(&rp->kp);
 		if (IS_ERR(addr))
@@ -1969,6 +2016,9 @@
 {
 	struct kprobe *kp;
 
+	if (WARN_ON_ONCE(kprobe_gone(p)))
+		return;
+
 	p->flags |= KPROBE_FLAG_GONE;
 	if (kprobe_aggrprobe(p)) {
 		/*
@@ -1986,6 +2036,14 @@
 	 * the original probed function (which will be freed soon) any more.
 	 */
 	arch_remove_kprobe(p);
+
+	/*
+	 * The module is going away. We should disarm the kprobe which
+	 * is using ftrace, because ftrace framework is still available at
+	 * MODULE_STATE_GOING notification.
+	 */
+	if (kprobe_ftrace(p) && !kprobe_disabled(p) && !kprobes_all_disarmed)
+		disarm_kprobe_ftrace(p);
 }
 
 /* Disable one kprobe */
@@ -2104,7 +2162,10 @@
 	mutex_lock(&kprobe_mutex);
 	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
 		head = &kprobe_table[i];
-		hlist_for_each_entry_rcu(p, head, hlist)
+		hlist_for_each_entry_rcu(p, head, hlist) {
+			if (kprobe_gone(p))
+				continue;
+
 			if (within_module_init((unsigned long)p->addr, mod) ||
 			    (checkcore &&
 			     within_module_core((unsigned long)p->addr, mod))) {
@@ -2115,6 +2176,7 @@
 				 */
 				kill_kprobe(p);
 			}
+		}
 	}
 	mutex_unlock(&kprobe_mutex);
 	return NOTIFY_DONE;
@@ -2441,7 +2503,7 @@
 	if (!dir)
 		return -ENOMEM;
 
-	file = debugfs_create_file("list", 0444, dir, NULL,
+	file = debugfs_create_file("list", 0400, dir, NULL,
 				&debugfs_kprobes_operations);
 	if (!file)
 		goto error;
@@ -2451,7 +2513,7 @@
 	if (!file)
 		goto error;
 
-	file = debugfs_create_file("blacklist", 0444, dir, NULL,
+	file = debugfs_create_file("blacklist", 0400, dir, NULL,
 				&debugfs_kprobe_blacklist_ops);
 	if (!file)
 		goto error;
--- linux-4.4.0.orig/kernel/kthread.c
+++ linux-4.4.0/kernel/kthread.c
@@ -18,6 +18,7 @@
 #include <linux/freezer.h>
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
+#include <linux/cgroup.h>
 #include <trace/events/sched.h>
 
 static DEFINE_SPINLOCK(kthread_create_lock);
@@ -205,6 +206,7 @@
 	ret = -EINTR;
 
 	if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {
+		cgroup_kthread_ready();
 		__kthread_parkme(&self);
 		ret = threadfn(data);
 	}
@@ -295,6 +297,17 @@
 	 * new kernel thread.
 	 */
 	if (unlikely(wait_for_completion_killable(&done))) {
+		int i = 0;
+
+		/*
+		 * I got SIGKILL, but wait for 10 more seconds for completion
+		 * unless chosen by the OOM killer. This delay is there as a
+		 * workaround for boot failure caused by SIGKILL upon device
+		 * driver initialization timeout.
+		 */
+		while (i++ < 10 && !test_tsk_thread_flag(current, TIF_MEMDIE))
+			if (wait_for_completion_timeout(&done, HZ))
+				goto ready;
 		/*
 		 * If I was SIGKILLed before kthreadd (or new kernel thread)
 		 * calls complete(), leave the cleanup of this structure to
@@ -308,13 +321,20 @@
 		 */
 		wait_for_completion(&done);
 	}
+ready:
 	task = create->result;
 	if (!IS_ERR(task)) {
 		static const struct sched_param param = { .sched_priority = 0 };
+		char name[TASK_COMM_LEN];
 		va_list args;
 
 		va_start(args, namefmt);
-		vsnprintf(task->comm, sizeof(task->comm), namefmt, args);
+		/*
+		 * task is already visible to other tasks, so updating
+		 * COMM must be protected.
+		 */
+		vsnprintf(name, sizeof(name), namefmt, args);
+		set_task_comm(task, name);
 		va_end(args);
 		/*
 		 * root may have changed our (kthreadd's) priority or CPU mask.
@@ -510,6 +530,7 @@
 	set_mems_allowed(node_states[N_MEMORY]);
 
 	current->flags |= PF_NOFREEZE;
+	cgroup_init_kthreadd();
 
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
--- linux-4.4.0.orig/kernel/livepatch/core.c
+++ linux-4.4.0/kernel/livepatch/core.c
@@ -28,6 +28,7 @@
 #include <linux/list.h>
 #include <linux/kallsyms.h>
 #include <linux/livepatch.h>
+#include <asm/cacheflush.h>
 
 /**
  * struct klp_ops - structure for tracking registered ftrace ops structs
@@ -135,13 +136,8 @@
 	const char *objname;
 	const char *name;
 	unsigned long addr;
-	/*
-	 * If count == 0, the symbol was not found. If count == 1, a unique
-	 * match was found and addr is set.  If count > 1, there is
-	 * unresolvable ambiguity among "count" number of symbols with the same
-	 * name in the same object.
-	 */
 	unsigned long count;
+	unsigned long pos;
 };
 
 static int klp_find_callback(void *data, const char *name,
@@ -158,37 +154,48 @@
 	if (args->objname && strcmp(args->objname, mod->name))
 		return 0;
 
-	/*
-	 * args->addr might be overwritten if another match is found
-	 * but klp_find_object_symbol() handles this and only returns the
-	 * addr if count == 1.
-	 */
 	args->addr = addr;
 	args->count++;
 
+	/*
+	 * Finish the search when the symbol is found for the desired position
+	 * or the position is not defined for a non-unique symbol.
+	 */
+	if ((args->pos && (args->count == args->pos)) ||
+	    (!args->pos && (args->count > 1)))
+		return 1;
+
 	return 0;
 }
 
 static int klp_find_object_symbol(const char *objname, const char *name,
-				  unsigned long *addr)
+				  unsigned long sympos, unsigned long *addr)
 {
 	struct klp_find_arg args = {
 		.objname = objname,
 		.name = name,
 		.addr = 0,
-		.count = 0
+		.count = 0,
+		.pos = sympos,
 	};
 
 	mutex_lock(&module_mutex);
 	kallsyms_on_each_symbol(klp_find_callback, &args);
 	mutex_unlock(&module_mutex);
 
-	if (args.count == 0)
+	/*
+	 * Ensure an address was found. If sympos is 0, ensure symbol is unique;
+	 * otherwise ensure the symbol position count matches sympos.
+	 */
+	if (args.addr == 0)
 		pr_err("symbol '%s' not found in symbol table\n", name);
-	else if (args.count > 1)
+	else if (args.count > 1 && sympos == 0) {
 		pr_err("unresolvable ambiguity (%lu matches) on symbol '%s' in object '%s'\n",
 		       args.count, name, objname);
-	else {
+	} else if (sympos != args.count && sympos > 0) {
+		pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n",
+		       sympos, name, objname ? objname : "vmlinux");
+	} else {
 		*addr = args.addr;
 		return 0;
 	}
@@ -197,66 +204,6 @@
 	return -EINVAL;
 }
 
-struct klp_verify_args {
-	const char *name;
-	const unsigned long addr;
-};
-
-static int klp_verify_callback(void *data, const char *name,
-			       struct module *mod, unsigned long addr)
-{
-	struct klp_verify_args *args = data;
-
-	if (!mod &&
-	    !strcmp(args->name, name) &&
-	    args->addr == addr)
-		return 1;
-
-	return 0;
-}
-
-static int klp_verify_vmlinux_symbol(const char *name, unsigned long addr)
-{
-	struct klp_verify_args args = {
-		.name = name,
-		.addr = addr,
-	};
-	int ret;
-
-	mutex_lock(&module_mutex);
-	ret = kallsyms_on_each_symbol(klp_verify_callback, &args);
-	mutex_unlock(&module_mutex);
-
-	if (!ret) {
-		pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n",
-			name, addr);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int klp_find_verify_func_addr(struct klp_object *obj,
-				     struct klp_func *func)
-{
-	int ret;
-
-#if defined(CONFIG_RANDOMIZE_BASE)
-	/* If KASLR has been enabled, adjust old_addr accordingly */
-	if (kaslr_enabled() && func->old_addr)
-		func->old_addr += kaslr_offset();
-#endif
-
-	if (!func->old_addr || klp_is_module(obj))
-		ret = klp_find_object_symbol(obj->name, func->old_name,
-					     &func->old_addr);
-	else
-		ret = klp_verify_vmlinux_symbol(func->old_name,
-						func->old_addr);
-
-	return ret;
-}
-
 /*
  * external symbols are located outside the parent object (where the parent
  * object is either vmlinux or the kmod being patched).
@@ -276,14 +223,18 @@
 	}
 	preempt_enable();
 
-	/* otherwise check if it's in another .o within the patch module */
-	return klp_find_object_symbol(pmod->name, name, addr);
+	/*
+	 * Check if it's in another .o within the patch module. This also
+	 * checks that the external symbol is unique.
+	 */
+	return klp_find_object_symbol(pmod->name, name, 0, addr);
 }
 
 static int klp_write_object_relocations(struct module *pmod,
 					struct klp_object *obj)
 {
-	int ret;
+	int ret = 0;
+	unsigned long val;
 	struct klp_reloc *reloc;
 
 	if (WARN_ON(!klp_is_object_loaded(obj)))
@@ -292,41 +243,38 @@
 	if (WARN_ON(!obj->relocs))
 		return -EINVAL;
 
+	module_disable_ro(pmod);
+
 	for (reloc = obj->relocs; reloc->name; reloc++) {
-		if (!klp_is_module(obj)) {
+		/* discover the address of the referenced symbol */
+		if (reloc->external) {
+			if (reloc->sympos > 0) {
+				pr_err("non-zero sympos for external reloc symbol '%s' is not supported\n",
+				       reloc->name);
+				ret = -EINVAL;
+				goto out;
+			}
+			ret = klp_find_external_symbol(pmod, reloc->name, &val);
+		} else
+			ret = klp_find_object_symbol(obj->name,
+						     reloc->name,
+						     reloc->sympos,
+						     &val);
+		if (ret)
+			goto out;
 
-#if defined(CONFIG_RANDOMIZE_BASE)
-			/* If KASLR has been enabled, adjust old value accordingly */
-			if (kaslr_enabled())
-				reloc->val += kaslr_offset();
-#endif
-			ret = klp_verify_vmlinux_symbol(reloc->name,
-							reloc->val);
-			if (ret)
-				return ret;
-		} else {
-			/* module, reloc->val needs to be discovered */
-			if (reloc->external)
-				ret = klp_find_external_symbol(pmod,
-							       reloc->name,
-							       &reloc->val);
-			else
-				ret = klp_find_object_symbol(obj->mod->name,
-							     reloc->name,
-							     &reloc->val);
-			if (ret)
-				return ret;
-		}
 		ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc,
-					     reloc->val + reloc->addend);
+					     val + reloc->addend);
 		if (ret) {
 			pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n",
-			       reloc->name, reloc->val, ret);
-			return ret;
+			       reloc->name, val, ret);
+			goto out;
 		}
 	}
 
-	return 0;
+out:
+	module_enable_ro(pmod);
+	return ret;
 }
 
 static void notrace klp_ftrace_handler(unsigned long ip,
@@ -593,7 +541,7 @@
  * /sys/kernel/livepatch/<patch>
  * /sys/kernel/livepatch/<patch>/enabled
  * /sys/kernel/livepatch/<patch>/<object>
- * /sys/kernel/livepatch/<patch>/<object>/<func>
+ * /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
  */
 
 static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
@@ -738,8 +686,14 @@
 	INIT_LIST_HEAD(&func->stack_node);
 	func->state = KLP_DISABLED;
 
+	/* The format for the sysfs directory is <function,sympos> where sympos
+	 * is the nth occurrence of this symbol in kallsyms for the patched
+	 * object. If the user selects 0 for old_sympos, then 1 will be used
+	 * since a unique symbol will be the first occurrence.
+	 */
 	return kobject_init_and_add(&func->kobj, &klp_ktype_func,
-				    &obj->kobj, "%s", func->old_name);
+				    &obj->kobj, "%s,%lu", func->old_name,
+				    func->old_sympos ? func->old_sympos : 1);
 }
 
 /* parts of the initialization that is done only when the object is loaded */
@@ -756,7 +710,9 @@
 	}
 
 	klp_for_each_func(obj, func) {
-		ret = klp_find_verify_func_addr(obj, func);
+		ret = klp_find_object_symbol(obj->name, func->old_name,
+					     func->old_sympos,
+					     &func->old_addr);
 		if (ret)
 			return ret;
 	}
--- linux-4.4.0.orig/kernel/locking/lockdep.c
+++ linux-4.4.0/kernel/locking/lockdep.c
@@ -1264,11 +1264,13 @@
 	this.parent = NULL;
 	this.class = class;
 
-	local_irq_save(flags);
+	raw_local_irq_save(flags);
+	current->lockdep_recursion = 1;
 	arch_spin_lock(&lockdep_lock);
 	ret = __lockdep_count_forward_deps(&this);
 	arch_spin_unlock(&lockdep_lock);
-	local_irq_restore(flags);
+	current->lockdep_recursion = 0;
+	raw_local_irq_restore(flags);
 
 	return ret;
 }
@@ -1291,11 +1293,13 @@
 	this.parent = NULL;
 	this.class = class;
 
-	local_irq_save(flags);
+	raw_local_irq_save(flags);
+	current->lockdep_recursion = 1;
 	arch_spin_lock(&lockdep_lock);
 	ret = __lockdep_count_backward_deps(&this);
 	arch_spin_unlock(&lockdep_lock);
-	local_irq_restore(flags);
+	current->lockdep_recursion = 0;
+	raw_local_irq_restore(flags);
 
 	return ret;
 }
@@ -3128,10 +3132,17 @@
 	if (depth) {
 		hlock = curr->held_locks + depth - 1;
 		if (hlock->class_idx == class_idx && nest_lock) {
-			if (hlock->references)
+			if (!references)
+				references++;
+
+			if (!hlock->references)
 				hlock->references++;
-			else
-				hlock->references = 2;
+
+			hlock->references += references;
+
+			/* Overflow */
+			if (DEBUG_LOCKS_WARN_ON(hlock->references < references))
+				return 0;
 
 			return 1;
 		}
@@ -3307,6 +3318,9 @@
 	unsigned int depth;
 	int i;
 
+	if (unlikely(!debug_locks))
+		return 0;
+
 	depth = curr->lockdep_depth;
 	/*
 	 * This function is about (re)setting the class of a held lock,
@@ -3819,7 +3833,7 @@
 {
 	unsigned long flags;
 
-	if (unlikely(!lock_stat))
+	if (unlikely(!lock_stat || !debug_locks))
 		return;
 
 	if (unlikely(current->lockdep_recursion))
@@ -3839,7 +3853,7 @@
 {
 	unsigned long flags;
 
-	if (unlikely(!lock_stat))
+	if (unlikely(!lock_stat || !debug_locks))
 		return;
 
 	if (unlikely(current->lockdep_recursion))
@@ -4116,7 +4130,7 @@
 	if (unlikely(!debug_locks))
 		return;
 
-	local_irq_save(flags);
+	raw_local_irq_save(flags);
 	for (i = 0; i < curr->lockdep_depth; i++) {
 		hlock = curr->held_locks + i;
 
@@ -4127,7 +4141,7 @@
 		print_freed_lock_bug(curr, mem_from, mem_from + mem_len, hlock);
 		break;
 	}
-	local_irq_restore(flags);
+	raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(debug_check_no_locks_freed);
 
--- linux-4.4.0.orig/kernel/locking/lockdep_proc.c
+++ linux-4.4.0/kernel/locking/lockdep_proc.c
@@ -217,7 +217,6 @@
 
 static int lockdep_stats_show(struct seq_file *m, void *v)
 {
-	struct lock_class *class;
 	unsigned long nr_unused = 0, nr_uncategorized = 0,
 		      nr_irq_safe = 0, nr_irq_unsafe = 0,
 		      nr_softirq_safe = 0, nr_softirq_unsafe = 0,
@@ -227,6 +226,9 @@
 		      nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0,
 		      sum_forward_deps = 0;
 
+#ifdef CONFIG_PROVE_LOCKING
+	struct lock_class *class;
+
 	list_for_each_entry(class, &all_lock_classes, lock_entry) {
 
 		if (class->usage_mask == 0)
@@ -258,13 +260,13 @@
 		if (class->usage_mask & LOCKF_ENABLED_HARDIRQ_READ)
 			nr_hardirq_read_unsafe++;
 
-#ifdef CONFIG_PROVE_LOCKING
 		sum_forward_deps += lockdep_count_forward_deps(class);
-#endif
 	}
 #ifdef CONFIG_DEBUG_LOCKDEP
 	DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused);
 #endif
+
+#endif
 	seq_printf(m, " lock-classes:                  %11lu [max: %lu]\n",
 			nr_lock_classes, MAX_LOCKDEP_KEYS);
 	seq_printf(m, " direct dependencies:           %11lu [max: %lu]\n",
@@ -421,7 +423,7 @@
 	seq_time(m, lt->min);
 	seq_time(m, lt->max);
 	seq_time(m, lt->total);
-	seq_time(m, lt->nr ? div_s64(lt->total, lt->nr) : 0);
+	seq_time(m, lt->nr ? div64_u64(lt->total, lt->nr) : 0);
 }
 
 static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
--- linux-4.4.0.orig/kernel/locking/locktorture.c
+++ linux-4.4.0/kernel/locking/locktorture.c
@@ -655,10 +655,10 @@
 		if (statp[i].n_lock_fail)
 			fail = true;
 		sum += statp[i].n_lock_acquired;
-		if (max < statp[i].n_lock_fail)
-			max = statp[i].n_lock_fail;
-		if (min > statp[i].n_lock_fail)
-			min = statp[i].n_lock_fail;
+		if (max < statp[i].n_lock_acquired)
+			max = statp[i].n_lock_acquired;
+		if (min > statp[i].n_lock_acquired)
+			min = statp[i].n_lock_acquired;
 	}
 	page += sprintf(page,
 			"%s:  Total: %lld  Max/Min: %ld/%ld %s  Fail: %d %s\n",
@@ -776,6 +776,8 @@
 	else
 		lock_torture_print_module_parms(cxt.cur_ops,
 						"End of test: SUCCESS");
+	kfree(cxt.lwsa);
+	kfree(cxt.lrsa);
 	torture_cleanup_end();
 }
 
@@ -917,6 +919,8 @@
 				       GFP_KERNEL);
 		if (reader_tasks == NULL) {
 			VERBOSE_TOROUT_ERRSTRING("reader_tasks: Out of memory");
+			kfree(writer_tasks);
+			writer_tasks = NULL;
 			firsterr = -ENOMEM;
 			goto unwind;
 		}
--- linux-4.4.0.orig/kernel/locking/mcs_spinlock.h
+++ linux-4.4.0/kernel/locking/mcs_spinlock.h
@@ -67,7 +67,13 @@
 	node->locked = 0;
 	node->next   = NULL;
 
-	prev = xchg_acquire(lock, node);
+	/*
+	 * We rely on the full barrier with global transitivity implied by the
+	 * below xchg() to order the initialization stores above against any
+	 * observation of @node. And to provide the ACQUIRE ordering associated
+	 * with a LOCK primitive.
+	 */
+	prev = xchg(lock, node);
 	if (likely(prev == NULL)) {
 		/*
 		 * Lock acquired, don't need to set node->locked to 1. Threads
--- linux-4.4.0.orig/kernel/locking/mutex.c
+++ linux-4.4.0/kernel/locking/mutex.c
@@ -486,9 +486,6 @@
 	if (!hold_ctx)
 		return 0;
 
-	if (unlikely(ctx == hold_ctx))
-		return -EALREADY;
-
 	if (ctx->stamp - hold_ctx->stamp <= LONG_MAX &&
 	    (ctx->stamp != hold_ctx->stamp || ctx > hold_ctx)) {
 #ifdef CONFIG_DEBUG_MUTEXES
@@ -514,6 +511,12 @@
 	unsigned long flags;
 	int ret;
 
+	if (use_ww_ctx) {
+		struct ww_mutex *ww = container_of(lock, struct ww_mutex, base);
+		if (unlikely(ww_ctx == READ_ONCE(ww->ctx)))
+			return -EALREADY;
+	}
+
 	preempt_disable();
 	mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
 
@@ -716,6 +719,7 @@
 __mutex_unlock_common_slowpath(struct mutex *lock, int nested)
 {
 	unsigned long flags;
+	WAKE_Q(wake_q);
 
 	/*
 	 * As a performance measurement, release the lock before doing other
@@ -743,11 +747,11 @@
 					   struct mutex_waiter, list);
 
 		debug_mutex_wake_waiter(lock, waiter);
-
-		wake_up_process(waiter->task);
+		wake_q_add(&wake_q, waiter->task);
 	}
 
 	spin_unlock_mutex(&lock->wait_lock, flags);
+	wake_up_q(&wake_q);
 }
 
 /*
--- linux-4.4.0.orig/kernel/locking/osq_lock.c
+++ linux-4.4.0/kernel/locking/osq_lock.c
@@ -104,6 +104,19 @@
 
 	prev = decode_cpu(old);
 	node->prev = prev;
+
+	/*
+	 * osq_lock()			unqueue
+	 *
+	 * node->prev = prev		osq_wait_next()
+	 * WMB				MB
+	 * prev->next = node		next->prev = prev // unqueue-C
+	 *
+	 * Here 'node->prev' and 'next->prev' are the same variable and we need
+	 * to ensure these stores happen in-order to avoid corrupting the list.
+	 */
+	smp_wmb();
+
 	WRITE_ONCE(prev->next, node);
 
 	/*
--- linux-4.4.0.orig/kernel/locking/qspinlock.c
+++ linux-4.4.0/kernel/locking/qspinlock.c
@@ -255,6 +255,66 @@
 #define queued_spin_lock_slowpath	native_queued_spin_lock_slowpath
 #endif
 
+/*
+ * queued_spin_lock_slowpath() can (load-)ACQUIRE the lock before
+ * issuing an _unordered_ store to set _Q_LOCKED_VAL.
+ *
+ * This means that the store can be delayed, but no later than the
+ * store-release from the unlock. This means that simply observing
+ * _Q_LOCKED_VAL is not sufficient to determine if the lock is acquired.
+ *
+ * There are two paths that can issue the unordered store:
+ *
+ *  (1) clear_pending_set_locked():	*,1,0 -> *,0,1
+ *
+ *  (2) set_locked():			t,0,0 -> t,0,1 ; t != 0
+ *      atomic_cmpxchg_relaxed():	t,0,0 -> 0,0,1
+ *
+ * However, in both cases we have other !0 state we've set before to queue
+ * ourseves:
+ *
+ * For (1) we have the atomic_cmpxchg_acquire() that set _Q_PENDING_VAL, our
+ * load is constrained by that ACQUIRE to not pass before that, and thus must
+ * observe the store.
+ *
+ * For (2) we have a more intersting scenario. We enqueue ourselves using
+ * xchg_tail(), which ends up being a RELEASE. This in itself is not
+ * sufficient, however that is followed by an smp_cond_acquire() on the same
+ * word, giving a RELEASE->ACQUIRE ordering. This again constrains our load and
+ * guarantees we must observe that store.
+ *
+ * Therefore both cases have other !0 state that is observable before the
+ * unordered locked byte store comes through. This means we can use that to
+ * wait for the lock store, and then wait for an unlock.
+ */
+#ifndef queued_spin_unlock_wait
+void queued_spin_unlock_wait(struct qspinlock *lock)
+{
+	u32 val;
+
+	for (;;) {
+		val = atomic_read(&lock->val);
+
+		if (!val) /* not locked, we're done */
+			goto done;
+
+		if (val & _Q_LOCKED_MASK) /* locked, go wait for unlock */
+			break;
+
+		/* not locked, but pending, wait until we observe the lock */
+		cpu_relax();
+	}
+
+	/* any unlock is good */
+	while (atomic_read(&lock->val) & _Q_LOCKED_MASK)
+		cpu_relax();
+
+done:
+	smp_rmb(); /* CTRL + RMB -> ACQUIRE */
+}
+EXPORT_SYMBOL(queued_spin_unlock_wait);
+#endif
+
 #endif /* _GEN_PV_LOCK_SLOWPATH */
 
 /**
@@ -363,6 +423,14 @@
 	tail = encode_tail(smp_processor_id(), idx);
 
 	node += idx;
+
+	/*
+	 * Ensure that we increment the head node->count before initialising
+	 * the actual node. If the compiler is kind enough to reorder these
+	 * stores, then an IRQ could overwrite our assignments.
+	 */
+	barrier();
+
 	node->locked = 0;
 	node->next = NULL;
 	pv_init_node(node);
--- linux-4.4.0.orig/kernel/locking/rtmutex-debug.c
+++ linux-4.4.0/kernel/locking/rtmutex-debug.c
@@ -173,12 +173,3 @@
 	lock->name = name;
 }
 
-void
-rt_mutex_deadlock_account_lock(struct rt_mutex *lock, struct task_struct *task)
-{
-}
-
-void rt_mutex_deadlock_account_unlock(struct task_struct *task)
-{
-}
-
--- linux-4.4.0.orig/kernel/locking/rtmutex-debug.h
+++ linux-4.4.0/kernel/locking/rtmutex-debug.h
@@ -9,9 +9,6 @@
  * This file contains macros used solely by rtmutex.c. Debug version.
  */
 
-extern void
-rt_mutex_deadlock_account_lock(struct rt_mutex *lock, struct task_struct *task);
-extern void rt_mutex_deadlock_account_unlock(struct task_struct *task);
 extern void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter);
 extern void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter);
 extern void debug_rt_mutex_init(struct rt_mutex *lock, const char *name);
--- linux-4.4.0.orig/kernel/locking/rtmutex.c
+++ linux-4.4.0/kernel/locking/rtmutex.c
@@ -65,8 +65,72 @@
 
 static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
 {
-	if (!rt_mutex_has_waiters(lock))
-		clear_rt_mutex_waiters(lock);
+	unsigned long owner, *p = (unsigned long *) &lock->owner;
+
+	if (rt_mutex_has_waiters(lock))
+		return;
+
+	/*
+	 * The rbtree has no waiters enqueued, now make sure that the
+	 * lock->owner still has the waiters bit set, otherwise the
+	 * following can happen:
+	 *
+	 * CPU 0	CPU 1		CPU2
+	 * l->owner=T1
+	 *		rt_mutex_lock(l)
+	 *		lock(l->lock)
+	 *		l->owner = T1 | HAS_WAITERS;
+	 *		enqueue(T2)
+	 *		boost()
+	 *		  unlock(l->lock)
+	 *		block()
+	 *
+	 *				rt_mutex_lock(l)
+	 *				lock(l->lock)
+	 *				l->owner = T1 | HAS_WAITERS;
+	 *				enqueue(T3)
+	 *				boost()
+	 *				  unlock(l->lock)
+	 *				block()
+	 *		signal(->T2)	signal(->T3)
+	 *		lock(l->lock)
+	 *		dequeue(T2)
+	 *		deboost()
+	 *		  unlock(l->lock)
+	 *				lock(l->lock)
+	 *				dequeue(T3)
+	 *				 ==> wait list is empty
+	 *				deboost()
+	 *				 unlock(l->lock)
+	 *		lock(l->lock)
+	 *		fixup_rt_mutex_waiters()
+	 *		  if (wait_list_empty(l) {
+	 *		    l->owner = owner
+	 *		    owner = l->owner & ~HAS_WAITERS;
+	 *		      ==> l->owner = T1
+	 *		  }
+	 *				lock(l->lock)
+	 * rt_mutex_unlock(l)		fixup_rt_mutex_waiters()
+	 *				  if (wait_list_empty(l) {
+	 *				    owner = l->owner & ~HAS_WAITERS;
+	 * cmpxchg(l->owner, T1, NULL)
+	 *  ===> Success (l->owner = NULL)
+	 *
+	 *				    l->owner = owner
+	 *				      ==> l->owner = T1
+	 *				  }
+	 *
+	 * With the check for the waiter bit in place T3 on CPU2 will not
+	 * overwrite. All tasks fiddling with the waiters bit are
+	 * serialized by l->lock, so nothing else can modify the waiters
+	 * bit. If the bit is set then nothing can change l->owner either
+	 * so the simple RMW is safe. The cmpxchg() will simply fail if it
+	 * happens in the middle of the RMW because the waiters bit is
+	 * still set.
+	 */
+	owner = READ_ONCE(*p);
+	if (owner & RT_MUTEX_HAS_WAITERS)
+		WRITE_ONCE(*p, owner & ~RT_MUTEX_HAS_WAITERS);
 }
 
 /*
@@ -873,8 +937,6 @@
 	 */
 	rt_mutex_set_owner(lock, task);
 
-	rt_mutex_deadlock_account_lock(lock, task);
-
 	return 1;
 }
 
@@ -1222,6 +1284,19 @@
 	return ret;
 }
 
+static inline int __rt_mutex_slowtrylock(struct rt_mutex *lock)
+{
+	int ret = try_to_take_rt_mutex(lock, current, NULL);
+
+	/*
+	 * try_to_take_rt_mutex() sets the lock waiters bit
+	 * unconditionally. Clean this up.
+	 */
+	fixup_rt_mutex_waiters(lock);
+
+	return ret;
+}
+
 /*
  * Slow path try-lock function:
  */
@@ -1243,13 +1318,7 @@
 	 */
 	raw_spin_lock(&lock->wait_lock);
 
-	ret = try_to_take_rt_mutex(lock, current, NULL);
-
-	/*
-	 * try_to_take_rt_mutex() sets the lock waiters bit
-	 * unconditionally. Clean this up.
-	 */
-	fixup_rt_mutex_waiters(lock);
+	ret = __rt_mutex_slowtrylock(lock);
 
 	raw_spin_unlock(&lock->wait_lock);
 
@@ -1267,8 +1336,6 @@
 
 	debug_rt_mutex_unlock(lock);
 
-	rt_mutex_deadlock_account_unlock(current);
-
 	/*
 	 * We must be careful here if the fast path is enabled. If we
 	 * have no waiters queued we cannot set owner to NULL here
@@ -1334,11 +1401,10 @@
 				struct hrtimer_sleeper *timeout,
 				enum rtmutex_chainwalk chwalk))
 {
-	if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) {
-		rt_mutex_deadlock_account_lock(lock, current);
+	if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current)))
 		return 0;
-	} else
-		return slowfn(lock, state, NULL, RT_MUTEX_MIN_CHAINWALK);
+
+	return slowfn(lock, state, NULL, RT_MUTEX_MIN_CHAINWALK);
 }
 
 static inline int
@@ -1350,21 +1416,19 @@
 				      enum rtmutex_chainwalk chwalk))
 {
 	if (chwalk == RT_MUTEX_MIN_CHAINWALK &&
-	    likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) {
-		rt_mutex_deadlock_account_lock(lock, current);
+	    likely(rt_mutex_cmpxchg_acquire(lock, NULL, current)))
 		return 0;
-	} else
-		return slowfn(lock, state, timeout, chwalk);
+
+	return slowfn(lock, state, timeout, chwalk);
 }
 
 static inline int
 rt_mutex_fasttrylock(struct rt_mutex *lock,
 		     int (*slowfn)(struct rt_mutex *lock))
 {
-	if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) {
-		rt_mutex_deadlock_account_lock(lock, current);
+	if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current)))
 		return 1;
-	}
+
 	return slowfn(lock);
 }
 
@@ -1374,19 +1438,18 @@
 				   struct wake_q_head *wqh))
 {
 	WAKE_Q(wake_q);
+	bool deboost;
 
-	if (likely(rt_mutex_cmpxchg_release(lock, current, NULL))) {
-		rt_mutex_deadlock_account_unlock(current);
+	if (likely(rt_mutex_cmpxchg_release(lock, current, NULL)))
+		return;
 
-	} else {
-		bool deboost = slowfn(lock, &wake_q);
+	deboost = slowfn(lock, &wake_q);
 
-		wake_up_q(&wake_q);
+	wake_up_q(&wake_q);
 
-		/* Undo pi boosting if necessary: */
-		if (deboost)
-			rt_mutex_adjust_prio(current);
-	}
+	/* Undo pi boosting if necessary: */
+	if (deboost)
+		rt_mutex_adjust_prio(current);
 }
 
 /**
@@ -1421,15 +1484,28 @@
 
 /*
  * Futex variant with full deadlock detection.
+ * Futex variants must not use the fast-path, see __rt_mutex_futex_unlock().
  */
-int rt_mutex_timed_futex_lock(struct rt_mutex *lock,
+int __sched rt_mutex_timed_futex_lock(struct rt_mutex *lock,
 			      struct hrtimer_sleeper *timeout)
 {
 	might_sleep();
 
-	return rt_mutex_timed_fastlock(lock, TASK_INTERRUPTIBLE, timeout,
-				       RT_MUTEX_FULL_CHAINWALK,
-				       rt_mutex_slowlock);
+	return rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE,
+				 timeout, RT_MUTEX_FULL_CHAINWALK);
+}
+
+/*
+ * Futex variant, must not use fastpath.
+ */
+int __sched rt_mutex_futex_trylock(struct rt_mutex *lock)
+{
+	return rt_mutex_slowtrylock(lock);
+}
+
+int __sched __rt_mutex_futex_trylock(struct rt_mutex *lock)
+{
+	return __rt_mutex_slowtrylock(lock);
 }
 
 /**
@@ -1488,20 +1564,38 @@
 EXPORT_SYMBOL_GPL(rt_mutex_unlock);
 
 /**
- * rt_mutex_futex_unlock - Futex variant of rt_mutex_unlock
- * @lock: the rt_mutex to be unlocked
- *
- * Returns: true/false indicating whether priority adjustment is
- * required or not.
+ * Futex variant, that since futex variants do not use the fast-path, can be
+ * simple and will not need to retry.
  */
-bool __sched rt_mutex_futex_unlock(struct rt_mutex *lock,
-				   struct wake_q_head *wqh)
+bool __sched __rt_mutex_futex_unlock(struct rt_mutex *lock,
+				    struct wake_q_head *wake_q)
+{
+	lockdep_assert_held(&lock->wait_lock);
+
+	debug_rt_mutex_unlock(lock);
+
+	if (!rt_mutex_has_waiters(lock)) {
+		lock->owner = NULL;
+		return false; /* done */
+	}
+
+	mark_wakeup_next_waiter(wake_q, lock);
+	return true; /* deboost and wakeups */
+}
+
+void __sched rt_mutex_futex_unlock(struct rt_mutex *lock)
 {
-	if (likely(rt_mutex_cmpxchg_release(lock, current, NULL))) {
-		rt_mutex_deadlock_account_unlock(current);
-		return false;
+	WAKE_Q(wake_q);
+	bool deboost;
+
+	raw_spin_lock_irq(&lock->wait_lock);
+	deboost = __rt_mutex_futex_unlock(lock, &wake_q);
+	raw_spin_unlock_irq(&lock->wait_lock);
+
+	if (deboost) {
+		wake_up_q(&wake_q);
+		rt_mutex_adjust_prio(current);
 	}
-	return rt_mutex_slowunlock(lock, wqh);
 }
 
 /**
@@ -1558,7 +1652,6 @@
 	__rt_mutex_init(lock, NULL);
 	debug_rt_mutex_proxy_lock(lock, proxy_owner);
 	rt_mutex_set_owner(lock, proxy_owner);
-	rt_mutex_deadlock_account_lock(lock, proxy_owner);
 }
 
 /**
@@ -1569,12 +1662,10 @@
  * No locking. Caller has to do serializing itself
  * Special API call for PI-futex support
  */
-void rt_mutex_proxy_unlock(struct rt_mutex *lock,
-			   struct task_struct *proxy_owner)
+void rt_mutex_proxy_unlock(struct rt_mutex *lock)
 {
 	debug_rt_mutex_proxy_unlock(lock);
 	rt_mutex_set_owner(lock, NULL);
-	rt_mutex_deadlock_account_unlock(proxy_owner);
 }
 
 /**
@@ -1648,21 +1739,23 @@
 }
 
 /**
- * rt_mutex_finish_proxy_lock() - Complete lock acquisition
+ * rt_mutex_wait_proxy_lock() - Wait for lock acquisition
  * @lock:		the rt_mutex we were woken on
  * @to:			the timeout, null if none. hrtimer should already have
  *			been started.
  * @waiter:		the pre-initialized rt_mutex_waiter
  *
- * Complete the lock acquisition started our behalf by another thread.
+ * Wait for the the lock acquisition started on our behalf by
+ * rt_mutex_start_proxy_lock(). Upon failure, the caller must call
+ * rt_mutex_cleanup_proxy_lock().
  *
  * Returns:
  *  0 - success
  * <0 - error, one of -EINTR, -ETIMEDOUT
  *
- * Special API call for PI-futex requeue support
+ * Special API call for PI-futex support
  */
-int rt_mutex_finish_proxy_lock(struct rt_mutex *lock,
+int rt_mutex_wait_proxy_lock(struct rt_mutex *lock,
 			       struct hrtimer_sleeper *to,
 			       struct rt_mutex_waiter *waiter)
 {
@@ -1675,9 +1768,6 @@
 	/* sleep on the mutex */
 	ret = __rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE, to, waiter);
 
-	if (unlikely(ret))
-		remove_waiter(lock, waiter);
-
 	/*
 	 * try_to_take_rt_mutex() sets the waiter bit unconditionally. We might
 	 * have to fix that up.
@@ -1688,3 +1778,42 @@
 
 	return ret;
 }
+
+/**
+ * rt_mutex_cleanup_proxy_lock() - Cleanup failed lock acquisition
+ * @lock:		the rt_mutex we were woken on
+ * @waiter:		the pre-initialized rt_mutex_waiter
+ *
+ * Attempt to clean up after a failed rt_mutex_wait_proxy_lock().
+ *
+ * Unless we acquired the lock; we're still enqueued on the wait-list and can
+ * in fact still be granted ownership until we're removed. Therefore we can
+ * find we are in fact the owner and must disregard the
+ * rt_mutex_wait_proxy_lock() failure.
+ *
+ * Returns:
+ *  true  - did the cleanup, we done.
+ *  false - we acquired the lock after rt_mutex_wait_proxy_lock() returned,
+ *          caller should disregards its return value.
+ *
+ * Special API call for PI-futex support
+ */
+bool rt_mutex_cleanup_proxy_lock(struct rt_mutex *lock,
+				 struct rt_mutex_waiter *waiter)
+{
+	bool cleanup = false;
+
+	raw_spin_lock_irq(&lock->wait_lock);
+	/*
+	 * Unless we're the owner; we're still enqueued on the wait_list.
+	 * So check if we became owner, if not, take us off the wait_list.
+	 */
+	if (rt_mutex_owner(lock) != current) {
+		remove_waiter(lock, waiter);
+		fixup_rt_mutex_waiters(lock);
+		cleanup = true;
+	}
+	raw_spin_unlock_irq(&lock->wait_lock);
+
+	return cleanup;
+}
--- linux-4.4.0.orig/kernel/locking/rtmutex.h
+++ linux-4.4.0/kernel/locking/rtmutex.h
@@ -11,8 +11,6 @@
  */
 
 #define rt_mutex_deadlock_check(l)			(0)
-#define rt_mutex_deadlock_account_lock(m, t)		do { } while (0)
-#define rt_mutex_deadlock_account_unlock(l)		do { } while (0)
 #define debug_rt_mutex_init_waiter(w)			do { } while (0)
 #define debug_rt_mutex_free_waiter(w)			do { } while (0)
 #define debug_rt_mutex_lock(l)				do { } while (0)
--- linux-4.4.0.orig/kernel/locking/rtmutex_common.h
+++ linux-4.4.0/kernel/locking/rtmutex_common.h
@@ -75,8 +75,9 @@
 
 static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock)
 {
-	return (struct task_struct *)
-		((unsigned long)lock->owner & ~RT_MUTEX_OWNER_MASKALL);
+	unsigned long owner = (unsigned long) READ_ONCE(lock->owner);
+
+	return (struct task_struct *) (owner & ~RT_MUTEX_OWNER_MASKALL);
 }
 
 /*
@@ -100,17 +101,23 @@
 extern struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock);
 extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
 				       struct task_struct *proxy_owner);
-extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
-				  struct task_struct *proxy_owner);
+extern void rt_mutex_proxy_unlock(struct rt_mutex *lock);
 extern int rt_mutex_start_proxy_lock(struct rt_mutex *lock,
 				     struct rt_mutex_waiter *waiter,
 				     struct task_struct *task);
-extern int rt_mutex_finish_proxy_lock(struct rt_mutex *lock,
-				      struct hrtimer_sleeper *to,
-				      struct rt_mutex_waiter *waiter);
+extern int rt_mutex_wait_proxy_lock(struct rt_mutex *lock,
+			       struct hrtimer_sleeper *to,
+			       struct rt_mutex_waiter *waiter);
+extern bool rt_mutex_cleanup_proxy_lock(struct rt_mutex *lock,
+				 struct rt_mutex_waiter *waiter);
 extern int rt_mutex_timed_futex_lock(struct rt_mutex *l, struct hrtimer_sleeper *to);
-extern bool rt_mutex_futex_unlock(struct rt_mutex *lock,
-				  struct wake_q_head *wqh);
+extern int rt_mutex_futex_trylock(struct rt_mutex *l);
+extern int __rt_mutex_futex_trylock(struct rt_mutex *l);
+
+extern void rt_mutex_futex_unlock(struct rt_mutex *lock);
+extern bool __rt_mutex_futex_unlock(struct rt_mutex *lock,
+				 struct wake_q_head *wqh);
+
 extern void rt_mutex_adjust_prio(struct task_struct *task);
 
 #ifdef CONFIG_DEBUG_RT_MUTEXES
--- linux-4.4.0.orig/kernel/locking/rwsem-xadd.c
+++ linux-4.4.0/kernel/locking/rwsem-xadd.c
@@ -511,6 +511,33 @@
 	unsigned long flags;
 
 	/*
+	* __rwsem_down_write_failed_common(sem)
+	*   rwsem_optimistic_spin(sem)
+	*     osq_unlock(sem->osq)
+	*   ...
+	*   atomic_long_add_return(&sem->count)
+	*
+	*      - VS -
+	*
+	*              __up_write()
+	*                if (atomic_long_sub_return_release(&sem->count) < 0)
+	*                  rwsem_wake(sem)
+	*                    osq_is_locked(&sem->osq)
+	*
+	* And __up_write() must observe !osq_is_locked() when it observes the
+	* atomic_long_add_return() in order to not miss a wakeup.
+	*
+	* This boils down to:
+	*
+	* [S.rel] X = 1                [RmW] r0 = (Y += 0)
+	*         MB                         RMB
+	* [RmW]   Y += 1               [L]   r1 = X
+	*
+	* exists (r0=1 /\ r1=0)
+	*/
+	smp_rmb();
+
+	/*
 	 * If a spinner is present, it is not necessary to do the wakeup.
 	 * Try to do wakeup only if the trylock succeeds to minimize
 	 * spinlock contention which may introduce too much delay in the
--- linux-4.4.0.orig/kernel/locking/spinlock_debug.c
+++ linux-4.4.0/kernel/locking/spinlock_debug.c
@@ -51,19 +51,19 @@
 
 static void spin_dump(raw_spinlock_t *lock, const char *msg)
 {
-	struct task_struct *owner = NULL;
+	struct task_struct *owner = READ_ONCE(lock->owner);
 
-	if (lock->owner && lock->owner != SPINLOCK_OWNER_INIT)
-		owner = lock->owner;
+	if (owner == SPINLOCK_OWNER_INIT)
+		owner = NULL;
 	printk(KERN_EMERG "BUG: spinlock %s on CPU#%d, %s/%d\n",
 		msg, raw_smp_processor_id(),
 		current->comm, task_pid_nr(current));
 	printk(KERN_EMERG " lock: %pS, .magic: %08x, .owner: %s/%d, "
 			".owner_cpu: %d\n",
-		lock, lock->magic,
+		lock, READ_ONCE(lock->magic),
 		owner ? owner->comm : "<none>",
 		owner ? task_pid_nr(owner) : -1,
-		lock->owner_cpu);
+		READ_ONCE(lock->owner_cpu));
 	dump_stack();
 }
 
@@ -80,16 +80,16 @@
 static inline void
 debug_spin_lock_before(raw_spinlock_t *lock)
 {
-	SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic");
-	SPIN_BUG_ON(lock->owner == current, lock, "recursion");
-	SPIN_BUG_ON(lock->owner_cpu == raw_smp_processor_id(),
+	SPIN_BUG_ON(READ_ONCE(lock->magic) != SPINLOCK_MAGIC, lock, "bad magic");
+	SPIN_BUG_ON(READ_ONCE(lock->owner) == current, lock, "recursion");
+	SPIN_BUG_ON(READ_ONCE(lock->owner_cpu) == raw_smp_processor_id(),
 							lock, "cpu recursion");
 }
 
 static inline void debug_spin_lock_after(raw_spinlock_t *lock)
 {
-	lock->owner_cpu = raw_smp_processor_id();
-	lock->owner = current;
+	WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id());
+	WRITE_ONCE(lock->owner, current);
 }
 
 static inline void debug_spin_unlock(raw_spinlock_t *lock)
@@ -99,8 +99,8 @@
 	SPIN_BUG_ON(lock->owner != current, lock, "wrong owner");
 	SPIN_BUG_ON(lock->owner_cpu != raw_smp_processor_id(),
 							lock, "wrong CPU");
-	lock->owner = SPINLOCK_OWNER_INIT;
-	lock->owner_cpu = -1;
+	WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT);
+	WRITE_ONCE(lock->owner_cpu, -1);
 }
 
 static void __spin_lock_debug(raw_spinlock_t *lock)
@@ -233,8 +233,8 @@
 
 static inline void debug_write_lock_after(rwlock_t *lock)
 {
-	lock->owner_cpu = raw_smp_processor_id();
-	lock->owner = current;
+	WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id());
+	WRITE_ONCE(lock->owner, current);
 }
 
 static inline void debug_write_unlock(rwlock_t *lock)
@@ -243,8 +243,8 @@
 	RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner");
 	RWLOCK_BUG_ON(lock->owner_cpu != raw_smp_processor_id(),
 							lock, "wrong CPU");
-	lock->owner = SPINLOCK_OWNER_INIT;
-	lock->owner_cpu = -1;
+	WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT);
+	WRITE_ONCE(lock->owner_cpu, -1);
 }
 
 #if 0		/* This can cause lockups */
--- linux-4.4.0.orig/kernel/membarrier.c
+++ linux-4.4.0/kernel/membarrier.c
@@ -16,6 +16,7 @@
 
 #include <linux/syscalls.h>
 #include <linux/membarrier.h>
+#include <linux/tick.h>
 
 /*
  * Bitmask made from a "or" of all commands within enum membarrier_cmd,
@@ -51,6 +52,9 @@
  */
 SYSCALL_DEFINE2(membarrier, int, cmd, int, flags)
 {
+	/* MEMBARRIER_CMD_SHARED is not compatible with nohz_full. */
+	if (tick_nohz_full_enabled())
+		return -ENOSYS;
 	if (unlikely(flags))
 		return -EINVAL;
 	switch (cmd) {
--- linux-4.4.0.orig/kernel/memremap.c
+++ linux-4.4.0/kernel/memremap.c
@@ -111,7 +111,7 @@
 
 static void devm_memremap_release(struct device *dev, void *res)
 {
-	memunmap(res);
+	memunmap(*(void **)res);
 }
 
 static int devm_memremap_match(struct device *dev, void *res, void *match_data)
@@ -133,8 +133,10 @@
 	if (addr) {
 		*ptr = addr;
 		devres_add(dev, ptr);
-	} else
+	} else {
 		devres_free(ptr);
+		return ERR_PTR(-ENXIO);
+	}
 
 	return addr;
 }
@@ -157,7 +159,9 @@
 	struct page_map *page_map = res;
 
 	/* pages are dead and unused, undo the arch mapping */
+	mem_hotplug_begin();
 	arch_remove_memory(page_map->res.start, resource_size(&page_map->res));
+	mem_hotplug_done();
 }
 
 void *devm_memremap_pages(struct device *dev, struct resource *res)
@@ -167,15 +171,12 @@
 	struct page_map *page_map;
 	int error, nid;
 
-	if (is_ram == REGION_MIXED) {
-		WARN_ONCE(1, "%s attempted on mixed region %pr\n",
-				__func__, res);
+	if (is_ram != REGION_DISJOINT) {
+		WARN_ONCE(1, "%s attempted on %s region %pr\n", __func__,
+				is_ram == REGION_MIXED ? "mixed" : "ram", res);
 		return ERR_PTR(-ENXIO);
 	}
 
-	if (is_ram == REGION_INTERSECTS)
-		return __va(res->start);
-
 	page_map = devres_alloc_node(devm_memremap_pages_release,
 			sizeof(*page_map), GFP_KERNEL, dev_to_node(dev));
 	if (!page_map)
@@ -187,7 +188,9 @@
 	if (nid < 0)
 		nid = numa_mem_id();
 
+	mem_hotplug_begin();
 	error = arch_add_memory(nid, res->start, resource_size(res), true);
+	mem_hotplug_done();
 	if (error) {
 		devres_free(page_map);
 		return ERR_PTR(error);
@@ -196,5 +199,5 @@
 	devres_add(dev, page_map);
 	return __va(res->start);
 }
-EXPORT_SYMBOL(devm_memremap_pages);
+EXPORT_SYMBOL_GPL(devm_memremap_pages);
 #endif /* CONFIG_ZONE_DEVICE */
--- linux-4.4.0.orig/kernel/modsign_uefi.c
+++ linux-4.4.0/kernel/modsign_uefi.c
@@ -0,0 +1,114 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/err.h>
+#include <linux/efi.h>
+#include <linux/slab.h>
+#include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
+#include "module-internal.h"
+
+static __init int check_ignore_db(void)
+{
+	efi_status_t status;
+	unsigned int db = 0;
+	unsigned long size = sizeof(db);
+	efi_guid_t guid = EFI_SHIM_LOCK_GUID;
+
+	/* Check and see if the MokIgnoreDB variable exists.  If that fails
+	 * then we don't ignore DB.  If it succeeds, we do.
+	 */
+	status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db);
+	if (status != EFI_SUCCESS)
+		return 0;
+
+	return 1;
+}
+
+static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size)
+{
+	efi_status_t status;
+	unsigned long lsize = 4;
+	unsigned long tmpdb[4];
+	void *db = NULL;
+
+	status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
+	if (status != EFI_BUFFER_TOO_SMALL) {
+		pr_err("Couldn't get size: 0x%lx\n", status);
+		return NULL;
+	}
+
+	db = kmalloc(lsize, GFP_KERNEL);
+	if (!db) {
+		pr_err("Couldn't allocate memory for uefi cert list\n");
+		goto out;
+	}
+
+	status = efi.get_variable(name, guid, NULL, &lsize, db);
+	if (status != EFI_SUCCESS) {
+		kfree(db);
+		db = NULL;
+		pr_err("Error reading db var: 0x%lx\n", status);
+	}
+out:
+	*size = lsize;
+	return db;
+}
+
+/*
+ *  * Load the certs contained in the UEFI databases
+ *   */
+static int __init load_uefi_certs(void)
+{
+	efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
+	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
+	void *db = NULL, *dbx = NULL, *mok = NULL;
+	unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
+	int ignore_db, rc = 0;
+
+	/* Check if SB is enabled and just return if not */
+	if (!efi_enabled(EFI_SECURE_BOOT))
+		return 0;
+
+	/* See if the user has setup Ignore DB mode */
+	ignore_db = check_ignore_db();
+
+	/* Get db, MokListRT, and dbx.  They might not exist, so it isn't
+	 * an error if we can't get them.
+	 */
+	if (!ignore_db) {
+		db = get_cert_list(L"db", &secure_var, &dbsize);
+		if (!db) {
+			pr_err("MODSIGN: Couldn't get UEFI db list\n");
+		} else {
+			rc = parse_efi_signature_list(db, dbsize, system_trusted_keyring);
+			if (rc)
+				pr_err("Couldn't parse db signatures: %d\n", rc);
+			kfree(db);
+		}
+	}
+
+	mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
+	if (!mok) {
+		pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
+	} else {
+		rc = parse_efi_signature_list(mok, moksize, system_trusted_keyring);
+		if (rc)
+			pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
+		kfree(mok);
+	}
+
+	dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
+	if (!dbx) {
+		pr_info("MODSIGN: Couldn't get UEFI dbx list\n");
+	} else {
+		rc = parse_efi_signature_list(dbx, dbxsize,
+			system_blacklist_keyring);
+		if (rc)
+			pr_err("Couldn't parse dbx signatures: %d\n", rc);
+		kfree(dbx);
+	}
+
+	return rc;
+}
+late_initcall(load_uefi_certs);
--- linux-4.4.0.orig/kernel/module.c
+++ linux-4.4.0/kernel/module.c
@@ -80,15 +80,6 @@
 # define debug_align(X) (X)
 #endif
 
-/*
- * Given BASE and SIZE this macro calculates the number of pages the
- * memory regions occupies
- */
-#define MOD_NUMBER_OF_PAGES(BASE, SIZE) (((SIZE) > 0) ?		\
-		(PFN_DOWN((unsigned long)(BASE) + (SIZE) - 1) -	\
-			 PFN_DOWN((unsigned long)BASE) + 1)	\
-		: (0UL))
-
 /* If this is set, the section belongs in the init part of the module */
 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
 
@@ -108,13 +99,6 @@
  * Use a latched RB-tree for __module_address(); this allows us to use
  * RCU-sched lookups of the address from any context.
  *
- * Because modules have two address ranges: init and core, we need two
- * latch_tree_nodes entries. Therefore we need the back-pointer from
- * mod_tree_node.
- *
- * Because init ranges are short lived we mark them unlikely and have placed
- * them outside the critical cacheline in struct module.
- *
  * This is conditional on PERF_EVENTS || TRACING because those can really hit
  * __module_address() hard by doing a lot of stack unwinding; potentially from
  * NMI context.
@@ -122,24 +106,16 @@
 
 static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
 {
-	struct mod_tree_node *mtn = container_of(n, struct mod_tree_node, node);
-	struct module *mod = mtn->mod;
-
-	if (unlikely(mtn == &mod->mtn_init))
-		return (unsigned long)mod->module_init;
+	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
 
-	return (unsigned long)mod->module_core;
+	return (unsigned long)layout->base;
 }
 
 static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
 {
-	struct mod_tree_node *mtn = container_of(n, struct mod_tree_node, node);
-	struct module *mod = mtn->mod;
+	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
 
-	if (unlikely(mtn == &mod->mtn_init))
-		return (unsigned long)mod->init_size;
-
-	return (unsigned long)mod->core_size;
+	return (unsigned long)layout->size;
 }
 
 static __always_inline bool
@@ -197,23 +173,23 @@
  */
 static void mod_tree_insert(struct module *mod)
 {
-	mod->mtn_core.mod = mod;
-	mod->mtn_init.mod = mod;
+	mod->core_layout.mtn.mod = mod;
+	mod->init_layout.mtn.mod = mod;
 
-	__mod_tree_insert(&mod->mtn_core);
-	if (mod->init_size)
-		__mod_tree_insert(&mod->mtn_init);
+	__mod_tree_insert(&mod->core_layout.mtn);
+	if (mod->init_layout.size)
+		__mod_tree_insert(&mod->init_layout.mtn);
 }
 
 static void mod_tree_remove_init(struct module *mod)
 {
-	if (mod->init_size)
-		__mod_tree_remove(&mod->mtn_init);
+	if (mod->init_layout.size)
+		__mod_tree_remove(&mod->init_layout.mtn);
 }
 
 static void mod_tree_remove(struct module *mod)
 {
-	__mod_tree_remove(&mod->mtn_core);
+	__mod_tree_remove(&mod->core_layout.mtn);
 	mod_tree_remove_init(mod);
 }
 
@@ -267,9 +243,9 @@
 
 static void mod_update_bounds(struct module *mod)
 {
-	__mod_update_bounds(mod->module_core, mod->core_size);
-	if (mod->init_size)
-		__mod_update_bounds(mod->module_init, mod->init_size);
+	__mod_update_bounds(mod->core_layout.base, mod->core_layout.size);
+	if (mod->init_layout.size)
+		__mod_update_bounds(mod->init_layout.base, mod->init_layout.size);
 }
 
 #ifdef CONFIG_KGDB_KDB
@@ -327,6 +303,9 @@
 	struct _ddebug *debug;
 	unsigned int num_debug;
 	bool sig_ok;
+#ifdef CONFIG_KALLSYMS
+	unsigned long mod_kallsyms_init_off;
+#endif
 	struct {
 		unsigned int sym, str, mod, vers, info, pcpu;
 	} index;
@@ -1011,6 +990,8 @@
 	strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
 
 	free_module(mod);
+	/* someone could wait for the module in add_unformed_module() */
+	wake_up_all(&module_wq);
 	return 0;
 out:
 	mutex_unlock(&module_mutex);
@@ -1214,7 +1195,7 @@
 static ssize_t show_coresize(struct module_attribute *mattr,
 			     struct module_kobject *mk, char *buffer)
 {
-	return sprintf(buffer, "%u\n", mk->mod->core_size);
+	return sprintf(buffer, "%u\n", mk->mod->core_layout.size);
 }
 
 static struct module_attribute modinfo_coresize =
@@ -1223,7 +1204,7 @@
 static ssize_t show_initsize(struct module_attribute *mattr,
 			     struct module_kobject *mk, char *buffer)
 {
-	return sprintf(buffer, "%u\n", mk->mod->init_size);
+	return sprintf(buffer, "%u\n", mk->mod->init_layout.size);
 }
 
 static struct module_attribute modinfo_initsize =
@@ -1774,7 +1755,6 @@
 	if (err)
 		mod_kobject_put(mod);
 
-	/* delay uevent until full sysfs population */
 out:
 	return err;
 }
@@ -1808,7 +1788,6 @@
 	add_sect_attrs(mod, info);
 	add_notes_attrs(mod, info);
 
-	kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
 	return 0;
 
 out_unreg_param:
@@ -1873,64 +1852,75 @@
 /*
  * LKM RO/NX protection: protect module's text/ro-data
  * from modification and any data from execution.
+ *
+ * General layout of module is:
+ *          [text] [read-only-data] [writable data]
+ * text_size -----^                ^               ^
+ * ro_size ------------------------|               |
+ * size -------------------------------------------|
+ *
+ * These values are always page-aligned (as is base)
  */
-void set_page_attributes(void *start, void *end, int (*set)(unsigned long start, int num_pages))
+static void frob_text(const struct module_layout *layout,
+		      int (*set_memory)(unsigned long start, int num_pages))
 {
-	unsigned long begin_pfn = PFN_DOWN((unsigned long)start);
-	unsigned long end_pfn = PFN_DOWN((unsigned long)end);
+	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
+	BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
+	set_memory((unsigned long)layout->base,
+		   layout->text_size >> PAGE_SHIFT);
+}
 
-	if (end_pfn > begin_pfn)
-		set(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);
+static void frob_rodata(const struct module_layout *layout,
+			int (*set_memory)(unsigned long start, int num_pages))
+{
+	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
+	BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
+	BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
+	set_memory((unsigned long)layout->base + layout->text_size,
+		   (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
 }
 
-static void set_section_ro_nx(void *base,
-			unsigned long text_size,
-			unsigned long ro_size,
-			unsigned long total_size)
+static void frob_writable_data(const struct module_layout *layout,
+			       int (*set_memory)(unsigned long start, int num_pages))
 {
-	/* begin and end PFNs of the current subsection */
-	unsigned long begin_pfn;
-	unsigned long end_pfn;
+	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
+	BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
+	BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
+	set_memory((unsigned long)layout->base + layout->ro_size,
+		   (layout->size - layout->ro_size) >> PAGE_SHIFT);
+}
 
-	/*
-	 * Set RO for module text and RO-data:
-	 * - Always protect first page.
-	 * - Do not protect last partial page.
-	 */
-	if (ro_size > 0)
-		set_page_attributes(base, base + ro_size, set_memory_ro);
+/* livepatching wants to disable read-only so it can frob module. */
+void module_disable_ro(const struct module *mod)
+{
+	frob_text(&mod->core_layout, set_memory_rw);
+	frob_rodata(&mod->core_layout, set_memory_rw);
+	frob_text(&mod->init_layout, set_memory_rw);
+	frob_rodata(&mod->init_layout, set_memory_rw);
+}
 
-	/*
-	 * Set NX permissions for module data:
-	 * - Do not protect first partial page.
-	 * - Always protect last page.
-	 */
-	if (total_size > text_size) {
-		begin_pfn = PFN_UP((unsigned long)base + text_size);
-		end_pfn = PFN_UP((unsigned long)base + total_size);
-		if (end_pfn > begin_pfn)
-			set_memory_nx(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);
-	}
+void module_enable_ro(const struct module *mod)
+{
+	frob_text(&mod->core_layout, set_memory_ro);
+	frob_rodata(&mod->core_layout, set_memory_ro);
+	frob_text(&mod->init_layout, set_memory_ro);
+	frob_rodata(&mod->init_layout, set_memory_ro);
 }
 
-static void unset_module_core_ro_nx(struct module *mod)
+static void module_enable_nx(const struct module *mod)
 {
-	set_page_attributes(mod->module_core + mod->core_text_size,
-		mod->module_core + mod->core_size,
-		set_memory_x);
-	set_page_attributes(mod->module_core,
-		mod->module_core + mod->core_ro_size,
-		set_memory_rw);
+	frob_rodata(&mod->core_layout, set_memory_nx);
+	frob_writable_data(&mod->core_layout, set_memory_nx);
+	frob_rodata(&mod->init_layout, set_memory_nx);
+	frob_writable_data(&mod->init_layout, set_memory_nx);
 }
 
-static void unset_module_init_ro_nx(struct module *mod)
+static void module_disable_nx(const struct module *mod)
 {
-	set_page_attributes(mod->module_init + mod->init_text_size,
-		mod->module_init + mod->init_size,
-		set_memory_x);
-	set_page_attributes(mod->module_init,
-		mod->module_init + mod->init_ro_size,
-		set_memory_rw);
+	frob_rodata(&mod->core_layout, set_memory_x);
+	frob_writable_data(&mod->core_layout, set_memory_x);
+	frob_rodata(&mod->init_layout, set_memory_x);
+	frob_writable_data(&mod->init_layout, set_memory_x);
 }
 
 /* Iterate through all modules and set each module's text as RW */
@@ -1942,16 +1932,9 @@
 	list_for_each_entry_rcu(mod, &modules, list) {
 		if (mod->state == MODULE_STATE_UNFORMED)
 			continue;
-		if ((mod->module_core) && (mod->core_text_size)) {
-			set_page_attributes(mod->module_core,
-						mod->module_core + mod->core_text_size,
-						set_memory_rw);
-		}
-		if ((mod->module_init) && (mod->init_text_size)) {
-			set_page_attributes(mod->module_init,
-						mod->module_init + mod->init_text_size,
-						set_memory_rw);
-		}
+
+		frob_text(&mod->core_layout, set_memory_rw);
+		frob_text(&mod->init_layout, set_memory_rw);
 	}
 	mutex_unlock(&module_mutex);
 }
@@ -1965,23 +1948,25 @@
 	list_for_each_entry_rcu(mod, &modules, list) {
 		if (mod->state == MODULE_STATE_UNFORMED)
 			continue;
-		if ((mod->module_core) && (mod->core_text_size)) {
-			set_page_attributes(mod->module_core,
-						mod->module_core + mod->core_text_size,
-						set_memory_ro);
-		}
-		if ((mod->module_init) && (mod->init_text_size)) {
-			set_page_attributes(mod->module_init,
-						mod->module_init + mod->init_text_size,
-						set_memory_ro);
-		}
+
+		frob_text(&mod->core_layout, set_memory_ro);
+		frob_text(&mod->init_layout, set_memory_ro);
 	}
 	mutex_unlock(&module_mutex);
 }
+
+static void disable_ro_nx(const struct module_layout *layout)
+{
+	frob_text(layout, set_memory_rw);
+	frob_rodata(layout, set_memory_rw);
+	frob_rodata(layout, set_memory_x);
+	frob_writable_data(layout, set_memory_x);
+}
+
 #else
-static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
-static void unset_module_core_ro_nx(struct module *mod) { }
-static void unset_module_init_ro_nx(struct module *mod) { }
+static void disable_ro_nx(const struct module_layout *layout) { }
+static void module_enable_nx(const struct module *mod) { }
+static void module_disable_nx(const struct module *mod) { }
 #endif
 
 void __weak module_memfree(void *module_region)
@@ -2033,19 +2018,19 @@
 	synchronize_sched();
 	mutex_unlock(&module_mutex);
 
-	/* This may be NULL, but that's OK */
-	unset_module_init_ro_nx(mod);
+	/* This may be empty, but that's OK */
+	disable_ro_nx(&mod->init_layout);
 	module_arch_freeing_init(mod);
-	module_memfree(mod->module_init);
+	module_memfree(mod->init_layout.base);
 	kfree(mod->args);
 	percpu_modfree(mod);
 
 	/* Free lock-classes; relies on the preceding sync_rcu(). */
-	lockdep_free_key_range(mod->module_core, mod->core_size);
+	lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
 
 	/* Finally, free the core (containing the module structure) */
-	unset_module_core_ro_nx(mod);
-	module_memfree(mod->module_core);
+	disable_ro_nx(&mod->core_layout);
+	module_memfree(mod->core_layout.base);
 
 #ifdef CONFIG_MPU
 	update_protections(current->mm);
@@ -2104,6 +2089,21 @@
 	return 0;
 }
 
+static bool ignore_undef_symbol(Elf_Half emachine, const char *name)
+{
+	/*
+	 * On x86, PIC code and Clang non-PIC code may have call foo@PLT. GNU as
+	 * before 2.37 produces an unreferenced _GLOBAL_OFFSET_TABLE_ on x86-64.
+	 * i386 has a similar problem but may not deserve a fix.
+	 *
+	 * If we ever have to ignore many symbols, consider refactoring the code to
+	 * only warn if referenced by a relocation.
+	 */
+	if (emachine == EM_386 || emachine == EM_X86_64)
+		return !strcmp(name, "_GLOBAL_OFFSET_TABLE_");
+	return false;
+}
+
 /* Change all symbols so that st_value encodes the pointer directly. */
 static int simplify_symbols(struct module *mod, const struct load_info *info)
 {
@@ -2145,8 +2145,10 @@
 				break;
 			}
 
-			/* Ok if weak.  */
-			if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
+			/* Ok if weak or ignored.  */
+			if (!ksym &&
+			    (ELF_ST_BIND(sym[i].st_info) == STB_WEAK ||
+			     ignore_undef_symbol(info->hdr->e_machine, name)))
 				break;
 
 			pr_warn("%s: Unknown symbol %s (err %li)\n",
@@ -2248,20 +2250,20 @@
 			    || s->sh_entsize != ~0UL
 			    || strstarts(sname, ".init"))
 				continue;
-			s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
+			s->sh_entsize = get_offset(mod, &mod->core_layout.size, s, i);
 			pr_debug("\t%s\n", sname);
 		}
 		switch (m) {
 		case 0: /* executable */
-			mod->core_size = debug_align(mod->core_size);
-			mod->core_text_size = mod->core_size;
+			mod->core_layout.size = debug_align(mod->core_layout.size);
+			mod->core_layout.text_size = mod->core_layout.size;
 			break;
 		case 1: /* RO: text and ro-data */
-			mod->core_size = debug_align(mod->core_size);
-			mod->core_ro_size = mod->core_size;
+			mod->core_layout.size = debug_align(mod->core_layout.size);
+			mod->core_layout.ro_size = mod->core_layout.size;
 			break;
 		case 3: /* whole core */
-			mod->core_size = debug_align(mod->core_size);
+			mod->core_layout.size = debug_align(mod->core_layout.size);
 			break;
 		}
 	}
@@ -2277,21 +2279,21 @@
 			    || s->sh_entsize != ~0UL
 			    || !strstarts(sname, ".init"))
 				continue;
-			s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
+			s->sh_entsize = (get_offset(mod, &mod->init_layout.size, s, i)
 					 | INIT_OFFSET_MASK);
 			pr_debug("\t%s\n", sname);
 		}
 		switch (m) {
 		case 0: /* executable */
-			mod->init_size = debug_align(mod->init_size);
-			mod->init_text_size = mod->init_size;
+			mod->init_layout.size = debug_align(mod->init_layout.size);
+			mod->init_layout.text_size = mod->init_layout.size;
 			break;
 		case 1: /* RO: text and ro-data */
-			mod->init_size = debug_align(mod->init_size);
-			mod->init_ro_size = mod->init_size;
+			mod->init_layout.size = debug_align(mod->init_layout.size);
+			mod->init_layout.ro_size = mod->init_layout.size;
 			break;
 		case 3: /* whole init */
-			mod->init_size = debug_align(mod->init_size);
+			mod->init_layout.size = debug_align(mod->init_layout.size);
 			break;
 		}
 	}
@@ -2401,7 +2403,7 @@
 	}
 	if (sym->st_shndx == SHN_UNDEF)
 		return 'U';
-	if (sym->st_shndx == SHN_ABS)
+	if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
 		return 'a';
 	if (sym->st_shndx >= SHN_LORESERVE)
 		return '?';
@@ -2430,7 +2432,7 @@
 }
 
 static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
-			unsigned int shnum)
+			unsigned int shnum, unsigned int pcpundx)
 {
 	const Elf_Shdr *sec;
 
@@ -2439,6 +2441,11 @@
 	    || !src->st_name)
 		return false;
 
+#ifdef CONFIG_KALLSYMS_ALL
+	if (src->st_shndx == pcpundx)
+		return true;
+#endif
+
 	sec = sechdrs + src->st_shndx;
 	if (!(sec->sh_flags & SHF_ALLOC)
 #ifndef CONFIG_KALLSYMS_ALL
@@ -2466,7 +2473,7 @@
 
 	/* Put symbol section at end of init part of module. */
 	symsect->sh_flags |= SHF_ALLOC;
-	symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
+	symsect->sh_entsize = get_offset(mod, &mod->init_layout.size, symsect,
 					 info->index.sym) | INIT_OFFSET_MASK;
 	pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
 
@@ -2476,26 +2483,38 @@
 	/* Compute total space required for the core symbols' strtab. */
 	for (ndst = i = 0; i < nsrc; i++) {
 		if (i == 0 ||
-		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
+		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
+				   info->index.pcpu)) {
 			strtab_size += strlen(&info->strtab[src[i].st_name])+1;
 			ndst++;
 		}
 	}
 
 	/* Append room for core symbols at end of core part. */
-	info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
-	info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
-	mod->core_size += strtab_size;
-	mod->core_size = debug_align(mod->core_size);
+	info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
+	info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
+	mod->core_layout.size += strtab_size;
+	mod->core_layout.size = debug_align(mod->core_layout.size);
 
 	/* Put string table section at end of init part of module. */
 	strsect->sh_flags |= SHF_ALLOC;
-	strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
+	strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect,
 					 info->index.str) | INIT_OFFSET_MASK;
-	mod->init_size = debug_align(mod->init_size);
 	pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
+
+	/* We'll tack temporary mod_kallsyms on the end. */
+	mod->init_layout.size = ALIGN(mod->init_layout.size,
+				      __alignof__(struct mod_kallsyms));
+	info->mod_kallsyms_init_off = mod->init_layout.size;
+	mod->init_layout.size += sizeof(struct mod_kallsyms);
+	mod->init_layout.size = debug_align(mod->init_layout.size);
 }
 
+/*
+ * We use the full symtab and strtab which layout_symtab arranged to
+ * be appended to the init section.  Later we switch to the cut-down
+ * core-only ones.
+ */
 static void add_kallsyms(struct module *mod, const struct load_info *info)
 {
 	unsigned int i, ndst;
@@ -2504,28 +2523,34 @@
 	char *s;
 	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
 
-	mod->symtab = (void *)symsec->sh_addr;
-	mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+	/* Set up to point into init section. */
+	mod->kallsyms = mod->init_layout.base + info->mod_kallsyms_init_off;
+
+	mod->kallsyms->symtab = (void *)symsec->sh_addr;
+	mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
 	/* Make sure we get permanent strtab: don't use info->strtab. */
-	mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
+	mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
 
 	/* Set types up while we still have access to sections. */
-	for (i = 0; i < mod->num_symtab; i++)
-		mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
-
-	mod->core_symtab = dst = mod->module_core + info->symoffs;
-	mod->core_strtab = s = mod->module_core + info->stroffs;
-	src = mod->symtab;
-	for (ndst = i = 0; i < mod->num_symtab; i++) {
+	for (i = 0; i < mod->kallsyms->num_symtab; i++)
+		mod->kallsyms->symtab[i].st_info
+			= elf_type(&mod->kallsyms->symtab[i], info);
+
+	/* Now populate the cut down core kallsyms for after init. */
+	mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
+	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
+	src = mod->kallsyms->symtab;
+	for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
 		if (i == 0 ||
-		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
+		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
+				   info->index.pcpu)) {
 			dst[ndst] = src[i];
-			dst[ndst++].st_name = s - mod->core_strtab;
-			s += strlcpy(s, &mod->strtab[src[i].st_name],
+			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
+			s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
 				     KSYM_NAME_LEN) + 1;
 		}
 	}
-	mod->core_num_syms = ndst;
+	mod->core_kallsyms.num_symtab = ndst;
 }
 #else
 static inline void layout_symtab(struct module *mod, struct load_info *info)
@@ -2587,13 +2612,18 @@
 #endif
 
 #ifdef CONFIG_MODULE_SIG
-static int module_sig_check(struct load_info *info)
+static int module_sig_check(struct load_info *info, int flags)
 {
 	int err = -ENOKEY;
 	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
 	const void *mod = info->hdr;
 
-	if (info->len > markerlen &&
+	/*
+	 * Require flags == 0, as a module with version information
+	 * removed is no longer the module that was signed
+	 */
+	if (flags == 0 &&
+	    info->len > markerlen &&
 	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
 		/* We truncate the module to discard the signature */
 		info->len -= markerlen;
@@ -2612,7 +2642,7 @@
 	return err;
 }
 #else /* !CONFIG_MODULE_SIG */
-static int module_sig_check(struct load_info *info)
+static int module_sig_check(struct load_info *info, int flags)
 {
 	return 0;
 }
@@ -2838,6 +2868,15 @@
 	return mod;
 }
 
+static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
+{
+	if (retpoline_module_ok(get_modinfo(info, "retpoline")))
+		return;
+
+	pr_warn("%s: loading module not compiled with retpoline compiler.\n",
+		mod->name);
+}
+
 static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 {
 	const char *modmagic = get_modinfo(info, "vermagic");
@@ -2857,8 +2896,14 @@
 		return -ENOEXEC;
 	}
 
-	if (!get_modinfo(info, "intree"))
+	if (!get_modinfo(info, "intree")) {
+		if (!test_taint(TAINT_OOT_MODULE))
+			pr_warn("%s: loading out-of-tree module taints kernel.\n",
+				mod->name);
 		add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
+	}
+
+	check_modinfo_retpoline(mod, info);
 
 	if (get_modinfo(info, "staging")) {
 		add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
@@ -2964,7 +3009,7 @@
 	void *ptr;
 
 	/* Do the allocs. */
-	ptr = module_alloc(mod->core_size);
+	ptr = module_alloc(mod->core_layout.size);
 	/*
 	 * The pointer to this block is stored in the module structure
 	 * which is inside the block. Just mark it as not being a
@@ -2974,11 +3019,11 @@
 	if (!ptr)
 		return -ENOMEM;
 
-	memset(ptr, 0, mod->core_size);
-	mod->module_core = ptr;
+	memset(ptr, 0, mod->core_layout.size);
+	mod->core_layout.base = ptr;
 
-	if (mod->init_size) {
-		ptr = module_alloc(mod->init_size);
+	if (mod->init_layout.size) {
+		ptr = module_alloc(mod->init_layout.size);
 		/*
 		 * The pointer to this block is stored in the module structure
 		 * which is inside the block. This block doesn't need to be
@@ -2987,13 +3032,13 @@
 		 */
 		kmemleak_ignore(ptr);
 		if (!ptr) {
-			module_memfree(mod->module_core);
+			module_memfree(mod->core_layout.base);
 			return -ENOMEM;
 		}
-		memset(ptr, 0, mod->init_size);
-		mod->module_init = ptr;
+		memset(ptr, 0, mod->init_layout.size);
+		mod->init_layout.base = ptr;
 	} else
-		mod->module_init = NULL;
+		mod->init_layout.base = NULL;
 
 	/* Transfer each section which specifies SHF_ALLOC */
 	pr_debug("final section addresses:\n");
@@ -3005,10 +3050,10 @@
 			continue;
 
 		if (shdr->sh_entsize & INIT_OFFSET_MASK)
-			dest = mod->module_init
+			dest = mod->init_layout.base
 				+ (shdr->sh_entsize & ~INIT_OFFSET_MASK);
 		else
-			dest = mod->module_core + shdr->sh_entsize;
+			dest = mod->core_layout.base + shdr->sh_entsize;
 
 		if (shdr->sh_type != SHT_NOBITS)
 			memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
@@ -3023,6 +3068,8 @@
 
 static int check_module_license_and_versions(struct module *mod)
 {
+	int prev_taint = test_taint(TAINT_PROPRIETARY_MODULE);
+
 	/*
 	 * ndiswrapper is under GPL by itself, but loads proprietary modules.
 	 * Don't use add_taint_module(), as it would prevent ndiswrapper from
@@ -3041,6 +3088,9 @@
 		add_taint_module(mod, TAINT_PROPRIETARY_MODULE,
 				 LOCKDEP_NOW_UNRELIABLE);
 
+	if (!prev_taint && test_taint(TAINT_PROPRIETARY_MODULE))
+		pr_warn("%s: module license taints kernel.\n", mod->name);
+
 #ifdef CONFIG_MODVERSIONS
 	if ((mod->num_syms && !mod->crcs)
 	    || (mod->num_gpl_syms && !mod->gpl_crcs)
@@ -3070,12 +3120,12 @@
 	 * Do it before processing of module parameters, so the module
 	 * can provide parameter accessor functions of its own.
 	 */
-	if (mod->module_init)
-		flush_icache_range((unsigned long)mod->module_init,
-				   (unsigned long)mod->module_init
-				   + mod->init_size);
-	flush_icache_range((unsigned long)mod->module_core,
-			   (unsigned long)mod->module_core + mod->core_size);
+	if (mod->init_layout.base)
+		flush_icache_range((unsigned long)mod->init_layout.base,
+				   (unsigned long)mod->init_layout.base
+				   + mod->init_layout.size);
+	flush_icache_range((unsigned long)mod->core_layout.base,
+			   (unsigned long)mod->core_layout.base + mod->core_layout.size);
 
 	set_fs(old_fs);
 }
@@ -3133,8 +3183,8 @@
 {
 	percpu_modfree(mod);
 	module_arch_freeing_init(mod);
-	module_memfree(mod->module_init);
-	module_memfree(mod->module_core);
+	module_memfree(mod->init_layout.base);
+	module_memfree(mod->core_layout.base);
 }
 
 int __weak module_finalize(const Elf_Ehdr *hdr,
@@ -3174,8 +3224,7 @@
 	sched_annotate_sleep();
 	mutex_lock(&module_mutex);
 	mod = find_module_all(name, strlen(name), true);
-	ret = !mod || mod->state == MODULE_STATE_LIVE
-		|| mod->state == MODULE_STATE_GOING;
+	ret = !mod || mod->state == MODULE_STATE_LIVE;
 	mutex_unlock(&module_mutex);
 
 	return ret;
@@ -3221,7 +3270,7 @@
 		ret = -ENOMEM;
 		goto fail;
 	}
-	freeinit->module_init = mod->module_init;
+	freeinit->module_init = mod->init_layout.base;
 
 	/*
 	 * We want to find out whether @mod uses async during init.  Clear
@@ -3249,6 +3298,9 @@
 	blocking_notifier_call_chain(&module_notify_list,
 				     MODULE_STATE_LIVE, mod);
 
+	/* Delay uevent until module has finished its init routine */
+	kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
+
 	/*
 	 * We need to finish all async code before the module init sequence
 	 * is done.  This has potential to deadlock.  For example, a newly
@@ -3274,22 +3326,26 @@
 	module_put(mod);
 	trim_init_extable(mod);
 #ifdef CONFIG_KALLSYMS
-	mod->num_symtab = mod->core_num_syms;
-	mod->symtab = mod->core_symtab;
-	mod->strtab = mod->core_strtab;
+	/* Switch to core kallsyms now init is done: kallsyms may be walking! */
+	rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
 #endif
 	mod_tree_remove_init(mod);
-	unset_module_init_ro_nx(mod);
+	disable_ro_nx(&mod->init_layout);
 	module_arch_freeing_init(mod);
-	mod->module_init = NULL;
-	mod->init_size = 0;
-	mod->init_ro_size = 0;
-	mod->init_text_size = 0;
+	mod->init_layout.base = NULL;
+	mod->init_layout.size = 0;
+	mod->init_layout.ro_size = 0;
+	mod->init_layout.text_size = 0;
 	/*
 	 * We want to free module_init, but be aware that kallsyms may be
 	 * walking this with preempt disabled.  In all the failure paths, we
 	 * call synchronize_sched(), but we don't want to slow down the success
 	 * path, so use actual RCU here.
+	 * Note that module_alloc() on most architectures creates W+X page
+	 * mappings which won't be cleaned up until do_free_init() runs.  Any
+	 * code such as mark_rodata_ro() which depends on those mappings to
+	 * be cleaned up needs to sync with the queued work - ie
+	 * rcu_barrier_sched()
 	 */
 	call_rcu_sched(&freeinit->rcu, do_free_init);
 	mutex_unlock(&module_mutex);
@@ -3335,8 +3391,7 @@
 	mutex_lock(&module_mutex);
 	old = find_module_all(mod->name, strlen(mod->name), true);
 	if (old != NULL) {
-		if (old->state == MODULE_STATE_COMING
-		    || old->state == MODULE_STATE_UNFORMED) {
+		if (old->state != MODULE_STATE_LIVE) {
 			/* Wait in case it fails to load. */
 			mutex_unlock(&module_mutex);
 			err = wait_event_interruptible(module_wq,
@@ -3373,17 +3428,9 @@
 	/* This relies on module_mutex for list integrity. */
 	module_bug_finalize(info->hdr, info->sechdrs, mod);
 
-	/* Set RO and NX regions for core */
-	set_section_ro_nx(mod->module_core,
-				mod->core_text_size,
-				mod->core_ro_size,
-				mod->core_size);
-
-	/* Set RO and NX regions for init */
-	set_section_ro_nx(mod->module_init,
-				mod->init_text_size,
-				mod->init_ro_size,
-				mod->init_size);
+	/* Set RO and NX regions */
+	module_enable_ro(mod);
+	module_enable_nx(mod);
 
 	/* Mark state as coming so strong_try_module_get() ignores us,
 	 * but kallsyms etc. can see us. */
@@ -3426,7 +3473,7 @@
 	long err;
 	char *after_dashes;
 
-	err = module_sig_check(info);
+	err = module_sig_check(info, flags);
 	if (err)
 		goto free_copy;
 
@@ -3515,7 +3562,7 @@
 
 	/* Module is ready to execute: parsing args may do that. */
 	after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-				  -32768, 32767, NULL,
+				  -32768, 32767, mod,
 				  unknown_module_param_cb);
 	if (IS_ERR(after_dashes)) {
 		err = PTR_ERR(after_dashes);
@@ -3539,6 +3586,7 @@
 	return do_init_module(mod);
 
  bug_cleanup:
+	mod->state = MODULE_STATE_GOING;
 	/* module_bug_cleanup needs module_mutex protection */
 	mutex_lock(&module_mutex);
 	module_bug_cleanup(mod);
@@ -3548,8 +3596,8 @@
 				     MODULE_STATE_GOING, mod);
 
 	/* we can't deallocate the module until we clear memory protection */
-	unset_module_init_ro_nx(mod);
-	unset_module_core_ro_nx(mod);
+	module_disable_ro(mod);
+	module_disable_nx(mod);
 
  ddebug_cleanup:
 	dynamic_debug_remove(info->debug);
@@ -3578,7 +3626,7 @@
 	 */
 	ftrace_release_mod(mod);
 	/* Free lock-classes; relies on the preceding sync_rcu() */
-	lockdep_free_key_range(mod->module_core, mod->core_size);
+	lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
 
 	module_deallocate(mod, info);
  free_copy:
@@ -3646,6 +3694,11 @@
 	       && (str[2] == '\0' || str[2] == '.');
 }
 
+static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum)
+{
+	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
+}
+
 static const char *get_ksymbol(struct module *mod,
 			       unsigned long addr,
 			       unsigned long *size,
@@ -3653,41 +3706,42 @@
 {
 	unsigned int i, best = 0;
 	unsigned long nextval;
+	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
 
 	/* At worse, next value is at end of module */
 	if (within_module_init(addr, mod))
-		nextval = (unsigned long)mod->module_init+mod->init_text_size;
+		nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
 	else
-		nextval = (unsigned long)mod->module_core+mod->core_text_size;
+		nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
 
 	/* Scan for closest preceding symbol, and next symbol. (ELF
 	   starts real symbols at 1). */
-	for (i = 1; i < mod->num_symtab; i++) {
-		if (mod->symtab[i].st_shndx == SHN_UNDEF)
+	for (i = 1; i < kallsyms->num_symtab; i++) {
+		if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
 			continue;
 
 		/* We ignore unnamed symbols: they're uninformative
 		 * and inserted at a whim. */
-		if (mod->symtab[i].st_value <= addr
-		    && mod->symtab[i].st_value > mod->symtab[best].st_value
-		    && *(mod->strtab + mod->symtab[i].st_name) != '\0'
-		    && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))
+		if (*symname(kallsyms, i) == '\0'
+		    || is_arm_mapping_symbol(symname(kallsyms, i)))
+			continue;
+
+		if (kallsyms->symtab[i].st_value <= addr
+		    && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value)
 			best = i;
-		if (mod->symtab[i].st_value > addr
-		    && mod->symtab[i].st_value < nextval
-		    && *(mod->strtab + mod->symtab[i].st_name) != '\0'
-		    && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))
-			nextval = mod->symtab[i].st_value;
+		if (kallsyms->symtab[i].st_value > addr
+		    && kallsyms->symtab[i].st_value < nextval)
+			nextval = kallsyms->symtab[i].st_value;
 	}
 
 	if (!best)
 		return NULL;
 
 	if (size)
-		*size = nextval - mod->symtab[best].st_value;
+		*size = nextval - kallsyms->symtab[best].st_value;
 	if (offset)
-		*offset = addr - mod->symtab[best].st_value;
-	return mod->strtab + mod->symtab[best].st_name;
+		*offset = addr - kallsyms->symtab[best].st_value;
+	return symname(kallsyms, best);
 }
 
 /* For kallsyms to ask for address resolution.  NULL means not found.  Careful
@@ -3777,19 +3831,21 @@
 
 	preempt_disable();
 	list_for_each_entry_rcu(mod, &modules, list) {
+		struct mod_kallsyms *kallsyms;
+
 		if (mod->state == MODULE_STATE_UNFORMED)
 			continue;
-		if (symnum < mod->num_symtab) {
-			*value = mod->symtab[symnum].st_value;
-			*type = mod->symtab[symnum].st_info;
-			strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
-				KSYM_NAME_LEN);
+		kallsyms = rcu_dereference_sched(mod->kallsyms);
+		if (symnum < kallsyms->num_symtab) {
+			*value = kallsyms->symtab[symnum].st_value;
+			*type = kallsyms->symtab[symnum].st_info;
+			strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN);
 			strlcpy(module_name, mod->name, MODULE_NAME_LEN);
 			*exported = is_exported(name, *value, mod);
 			preempt_enable();
 			return 0;
 		}
-		symnum -= mod->num_symtab;
+		symnum -= kallsyms->num_symtab;
 	}
 	preempt_enable();
 	return -ERANGE;
@@ -3798,11 +3854,12 @@
 static unsigned long mod_find_symname(struct module *mod, const char *name)
 {
 	unsigned int i;
+	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
 
-	for (i = 0; i < mod->num_symtab; i++)
-		if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0 &&
-		    mod->symtab[i].st_info != 'U')
-			return mod->symtab[i].st_value;
+	for (i = 0; i < kallsyms->num_symtab; i++)
+		if (strcmp(name, symname(kallsyms, i)) == 0 &&
+		    kallsyms->symtab[i].st_shndx != SHN_UNDEF)
+			return kallsyms->symtab[i].st_value;
 	return 0;
 }
 
@@ -3841,11 +3898,18 @@
 	module_assert_mutex();
 
 	list_for_each_entry(mod, &modules, list) {
+		/* We hold module_mutex: no need for rcu_dereference_sched */
+		struct mod_kallsyms *kallsyms = mod->kallsyms;
+
 		if (mod->state == MODULE_STATE_UNFORMED)
 			continue;
-		for (i = 0; i < mod->num_symtab; i++) {
-			ret = fn(data, mod->strtab + mod->symtab[i].st_name,
-				 mod, mod->symtab[i].st_value);
+		for (i = 0; i < kallsyms->num_symtab; i++) {
+
+			if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
+				continue;
+
+			ret = fn(data, symname(kallsyms, i),
+				 mod, kallsyms->symtab[i].st_value);
 			if (ret != 0)
 				return ret;
 		}
@@ -3905,7 +3969,7 @@
 		return 0;
 
 	seq_printf(m, "%s %u",
-		   mod->name, mod->init_size + mod->core_size);
+		   mod->name, mod->init_layout.size + mod->core_layout.size);
 	print_unload_info(m, mod);
 
 	/* Informative for users. */
@@ -3914,7 +3978,7 @@
 		   mod->state == MODULE_STATE_COMING ? "Loading" :
 		   "Live");
 	/* Used by oprofile and other similar tools. */
-	seq_printf(m, " 0x%pK", mod->module_core);
+	seq_printf(m, " 0x%pK", mod->core_layout.base);
 
 	/* Taints info */
 	if (mod->taints)
@@ -4057,8 +4121,8 @@
 	struct module *mod = __module_address(addr);
 	if (mod) {
 		/* Make sure it's within the text section. */
-		if (!within(addr, mod->module_init, mod->init_text_size)
-		    && !within(addr, mod->module_core, mod->core_text_size))
+		if (!within(addr, mod->init_layout.base, mod->init_layout.text_size)
+		    && !within(addr, mod->core_layout.base, mod->core_layout.text_size))
 			mod = NULL;
 	}
 	return mod;
@@ -4097,3 +4161,20 @@
 }
 EXPORT_SYMBOL(module_layout);
 #endif
+
+#ifdef CONFIG_MODULE_SIG
+void enforce_signed_modules(void)
+{
+	sig_enforce = true;
+}
+#endif
+
+bool secure_modules(void)
+{
+#ifdef CONFIG_MODULE_SIG
+	return (sig_enforce || modules_disabled);
+#else
+	return modules_disabled;
+#endif
+}
+EXPORT_SYMBOL(secure_modules);
--- linux-4.4.0.orig/kernel/notifier.c
+++ linux-4.4.0/kernel/notifier.c
@@ -552,7 +552,7 @@
 
 int register_die_notifier(struct notifier_block *nb)
 {
-	vmalloc_sync_all();
+	vmalloc_sync_mappings();
 	return atomic_notifier_chain_register(&die_chain, nb);
 }
 EXPORT_SYMBOL_GPL(register_die_notifier);
--- linux-4.4.0.orig/kernel/nsproxy.c
+++ linux-4.4.0/kernel/nsproxy.c
@@ -25,6 +25,7 @@
 #include <linux/proc_ns.h>
 #include <linux/file.h>
 #include <linux/syscalls.h>
+#include <linux/cgroup.h>
 
 static struct kmem_cache *nsproxy_cachep;
 
@@ -39,6 +40,9 @@
 #ifdef CONFIG_NET
 	.net_ns			= &init_net,
 #endif
+#ifdef CONFIG_CGROUPS
+	.cgroup_ns		= &init_cgroup_ns,
+#endif
 };
 
 static inline struct nsproxy *create_nsproxy(void)
@@ -92,6 +96,13 @@
 		goto out_pid;
 	}
 
+	new_nsp->cgroup_ns = copy_cgroup_ns(flags, user_ns,
+					    tsk->nsproxy->cgroup_ns);
+	if (IS_ERR(new_nsp->cgroup_ns)) {
+		err = PTR_ERR(new_nsp->cgroup_ns);
+		goto out_cgroup;
+	}
+
 	new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
 	if (IS_ERR(new_nsp->net_ns)) {
 		err = PTR_ERR(new_nsp->net_ns);
@@ -101,6 +112,8 @@
 	return new_nsp;
 
 out_net:
+	put_cgroup_ns(new_nsp->cgroup_ns);
+out_cgroup:
 	if (new_nsp->pid_ns_for_children)
 		put_pid_ns(new_nsp->pid_ns_for_children);
 out_pid:
@@ -128,7 +141,8 @@
 	struct nsproxy *new_ns;
 
 	if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-			      CLONE_NEWPID | CLONE_NEWNET)))) {
+			      CLONE_NEWPID | CLONE_NEWNET |
+			      CLONE_NEWCGROUP)))) {
 		get_nsproxy(old_ns);
 		return 0;
 	}
@@ -165,6 +179,7 @@
 		put_ipc_ns(ns->ipc_ns);
 	if (ns->pid_ns_for_children)
 		put_pid_ns(ns->pid_ns_for_children);
+	put_cgroup_ns(ns->cgroup_ns);
 	put_net(ns->net_ns);
 	kmem_cache_free(nsproxy_cachep, ns);
 }
@@ -180,7 +195,7 @@
 	int err = 0;
 
 	if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-			       CLONE_NEWNET | CLONE_NEWPID)))
+			       CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP)))
 		return 0;
 
 	user_ns = new_cred ? new_cred->user_ns : current_user_ns();
--- linux-4.4.0.orig/kernel/padata.c
+++ linux-4.4.0/kernel/padata.c
@@ -33,6 +33,8 @@
 
 #define MAX_OBJ_NUM 1000
 
+static void padata_free_pd(struct parallel_data *pd);
+
 static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index)
 {
 	int cpu, target_cpu;
@@ -63,15 +65,11 @@
 static void padata_parallel_worker(struct work_struct *parallel_work)
 {
 	struct padata_parallel_queue *pqueue;
-	struct parallel_data *pd;
-	struct padata_instance *pinst;
 	LIST_HEAD(local_list);
 
 	local_bh_disable();
 	pqueue = container_of(parallel_work,
 			      struct padata_parallel_queue, work);
-	pd = pqueue->pd;
-	pinst = pd->pinst;
 
 	spin_lock(&pqueue->parallel.lock);
 	list_replace_init(&pqueue->parallel.list, &local_list);
@@ -134,6 +132,7 @@
 	padata->cb_cpu = cb_cpu;
 
 	target_cpu = padata_cpu_hash(pd);
+	padata->cpu = target_cpu;
 	queue = per_cpu_ptr(pd->pqueue, target_cpu);
 
 	spin_lock(&queue->parallel.lock);
@@ -157,8 +156,6 @@
  * A pointer to the control struct of the next object that needs
  * serialization, if present in one of the percpu reorder queues.
  *
- * NULL, if all percpu reorder queues are empty.
- *
  * -EINPROGRESS, if the next object that needs serialization will
  *  be parallel processed by another cpu and is not yet present in
  *  the cpu's reorder queue.
@@ -168,40 +165,29 @@
  */
 static struct padata_priv *padata_get_next(struct parallel_data *pd)
 {
-	int cpu, num_cpus;
-	unsigned int next_nr, next_index;
 	struct padata_parallel_queue *next_queue;
 	struct padata_priv *padata;
 	struct padata_list *reorder;
+	int cpu = pd->cpu;
 
-	num_cpus = cpumask_weight(pd->cpumask.pcpu);
-
-	/*
-	 * Calculate the percpu reorder queue and the sequence
-	 * number of the next object.
-	 */
-	next_nr = pd->processed;
-	next_index = next_nr % num_cpus;
-	cpu = padata_index_to_cpu(pd, next_index);
 	next_queue = per_cpu_ptr(pd->pqueue, cpu);
-
-	padata = NULL;
-
 	reorder = &next_queue->reorder;
 
+	spin_lock(&reorder->lock);
 	if (!list_empty(&reorder->list)) {
 		padata = list_entry(reorder->list.next,
 				    struct padata_priv, list);
 
-		spin_lock(&reorder->lock);
 		list_del_init(&padata->list);
 		atomic_dec(&pd->reorder_objects);
-		spin_unlock(&reorder->lock);
 
-		pd->processed++;
+		pd->cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu, -1,
+					    false);
 
+		spin_unlock(&reorder->lock);
 		goto out;
 	}
+	spin_unlock(&reorder->lock);
 
 	if (__this_cpu_read(pd->pqueue->cpu_index) == next_queue->cpu_index) {
 		padata = ERR_PTR(-ENODATA);
@@ -219,6 +205,7 @@
 	struct padata_priv *padata;
 	struct padata_serial_queue *squeue;
 	struct padata_instance *pinst = pd->pinst;
+	struct padata_parallel_queue *next_queue;
 
 	/*
 	 * We need to ensure that only one cpu can work on dequeueing of
@@ -237,12 +224,11 @@
 		padata = padata_get_next(pd);
 
 		/*
-		 * All reorder queues are empty, or the next object that needs
-		 * serialization is parallel processed by another cpu and is
-		 * still on it's way to the cpu's reorder queue, nothing to
-		 * do for now.
+		 * If the next object that needs serialization is parallel
+		 * processed by another cpu and is still on it's way to the
+		 * cpu's reorder queue, nothing to do for now.
 		 */
-		if (!padata || PTR_ERR(padata) == -EINPROGRESS)
+		if (PTR_ERR(padata) == -EINPROGRESS)
 			break;
 
 		/*
@@ -251,7 +237,6 @@
 		 * so exit immediately.
 		 */
 		if (PTR_ERR(padata) == -ENODATA) {
-			del_timer(&pd->timer);
 			spin_unlock_bh(&pd->lock);
 			return;
 		}
@@ -270,23 +255,27 @@
 
 	/*
 	 * The next object that needs serialization might have arrived to
-	 * the reorder queues in the meantime, we will be called again
-	 * from the timer function if no one else cares for it.
+	 * the reorder queues in the meantime.
+	 *
+	 * Ensure reorder queue is read after pd->lock is dropped so we see
+	 * new objects from another task in padata_do_serial.  Pairs with
+	 * smp_mb__after_atomic in padata_do_serial.
 	 */
-	if (atomic_read(&pd->reorder_objects)
-			&& !(pinst->flags & PADATA_RESET))
-		mod_timer(&pd->timer, jiffies + HZ);
-	else
-		del_timer(&pd->timer);
+	smp_mb();
 
-	return;
+	next_queue = per_cpu_ptr(pd->pqueue, pd->cpu);
+	if (!list_empty(&next_queue->reorder.list))
+		queue_work(pinst->wq, &pd->reorder_work);
 }
 
-static void padata_reorder_timer(unsigned long arg)
+static void invoke_padata_reorder(struct work_struct *work)
 {
-	struct parallel_data *pd = (struct parallel_data *)arg;
+	struct parallel_data *pd;
 
+	local_bh_disable();
+	pd = container_of(work, struct parallel_data, reorder_work);
 	padata_reorder(pd);
+	local_bh_enable();
 }
 
 static void padata_serial_worker(struct work_struct *serial_work)
@@ -294,6 +283,7 @@
 	struct padata_serial_queue *squeue;
 	struct parallel_data *pd;
 	LIST_HEAD(local_list);
+	int cnt;
 
 	local_bh_disable();
 	squeue = container_of(serial_work, struct padata_serial_queue, work);
@@ -303,6 +293,8 @@
 	list_replace_init(&squeue->serial.list, &local_list);
 	spin_unlock(&squeue->serial.lock);
 
+	cnt = 0;
+
 	while (!list_empty(&local_list)) {
 		struct padata_priv *padata;
 
@@ -312,9 +304,12 @@
 		list_del_init(&padata->list);
 
 		padata->serial(padata);
-		atomic_dec(&pd->refcnt);
+		cnt++;
 	}
 	local_bh_enable();
+
+	if (atomic_sub_and_test(cnt, &pd->refcnt))
+		padata_free_pd(pd);
 }
 
 /**
@@ -327,21 +322,21 @@
  */
 void padata_do_serial(struct padata_priv *padata)
 {
-	int cpu;
-	struct padata_parallel_queue *pqueue;
-	struct parallel_data *pd;
-
-	pd = padata->pd;
-
-	cpu = get_cpu();
-	pqueue = per_cpu_ptr(pd->pqueue, cpu);
+	struct parallel_data *pd = padata->pd;
+	struct padata_parallel_queue *pqueue = per_cpu_ptr(pd->pqueue,
+							   padata->cpu);
 
 	spin_lock(&pqueue->reorder.lock);
-	atomic_inc(&pd->reorder_objects);
 	list_add_tail(&padata->list, &pqueue->reorder.list);
+	atomic_inc(&pd->reorder_objects);
 	spin_unlock(&pqueue->reorder.lock);
 
-	put_cpu();
+	/*
+	 * Ensure the addition to the reorder list is ordered correctly
+	 * with the trylock of pd->lock in padata_reorder.  Pairs with smp_mb
+	 * in padata_reorder.
+	 */
+	smp_mb__after_atomic();
 
 	padata_reorder(pd);
 }
@@ -356,7 +351,7 @@
 
 	cpumask_and(pd->cpumask.pcpu, pcpumask, cpu_online_mask);
 	if (!alloc_cpumask_var(&pd->cpumask.cbcpu, GFP_KERNEL)) {
-		free_cpumask_var(pd->cpumask.cbcpu);
+		free_cpumask_var(pd->cpumask.pcpu);
 		return -ENOMEM;
 	}
 
@@ -391,9 +386,14 @@
 	struct padata_parallel_queue *pqueue;
 
 	cpu_index = 0;
-	for_each_cpu(cpu, pd->cpumask.pcpu) {
+	for_each_possible_cpu(cpu) {
 		pqueue = per_cpu_ptr(pd->pqueue, cpu);
-		pqueue->pd = pd;
+
+		if (!cpumask_test_cpu(cpu, pd->cpumask.pcpu)) {
+			pqueue->cpu_index = -1;
+			continue;
+		}
+
 		pqueue->cpu_index = cpu_index;
 		cpu_index++;
 
@@ -427,12 +427,13 @@
 
 	padata_init_pqueues(pd);
 	padata_init_squeues(pd);
-	setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd);
 	atomic_set(&pd->seq_nr, -1);
 	atomic_set(&pd->reorder_objects, 0);
-	atomic_set(&pd->refcnt, 0);
+	atomic_set(&pd->refcnt, 1);
 	pd->pinst = pinst;
 	spin_lock_init(&pd->lock);
+	pd->cpu = cpumask_first(pd->cpumask.pcpu);
+	INIT_WORK(&pd->reorder_work, invoke_padata_reorder);
 
 	return pd;
 
@@ -455,31 +456,6 @@
 	kfree(pd);
 }
 
-/* Flush all objects out of the padata queues. */
-static void padata_flush_queues(struct parallel_data *pd)
-{
-	int cpu;
-	struct padata_parallel_queue *pqueue;
-	struct padata_serial_queue *squeue;
-
-	for_each_cpu(cpu, pd->cpumask.pcpu) {
-		pqueue = per_cpu_ptr(pd->pqueue, cpu);
-		flush_work(&pqueue->work);
-	}
-
-	del_timer_sync(&pd->timer);
-
-	if (atomic_read(&pd->reorder_objects))
-		padata_reorder(pd);
-
-	for_each_cpu(cpu, pd->cpumask.cbcpu) {
-		squeue = per_cpu_ptr(pd->squeue, cpu);
-		flush_work(&squeue->work);
-	}
-
-	BUG_ON(atomic_read(&pd->refcnt) != 0);
-}
-
 static void __padata_start(struct padata_instance *pinst)
 {
 	pinst->flags |= PADATA_INIT;
@@ -493,10 +469,6 @@
 	pinst->flags &= ~PADATA_INIT;
 
 	synchronize_rcu();
-
-	get_online_cpus();
-	padata_flush_queues(pinst->pd);
-	put_online_cpus();
 }
 
 /* Replace the internal control structure with a new one. */
@@ -517,8 +489,8 @@
 	if (!cpumask_equal(pd_old->cpumask.cbcpu, pd_new->cpumask.cbcpu))
 		notification_mask |= PADATA_CPU_SERIAL;
 
-	padata_flush_queues(pd_old);
-	padata_free_pd(pd_old);
+	if (atomic_dec_and_test(&pd_old->refcnt))
+		padata_free_pd(pd_old);
 
 	if (notification_mask)
 		blocking_notifier_call_chain(&pinst->cpumask_change_notifier,
@@ -648,8 +620,8 @@
 	struct cpumask *serial_mask, *parallel_mask;
 	int err = -EINVAL;
 
-	mutex_lock(&pinst->lock);
 	get_online_cpus();
+	mutex_lock(&pinst->lock);
 
 	switch (cpumask_type) {
 	case PADATA_CPU_PARALLEL:
@@ -667,8 +639,8 @@
 	err =  __padata_set_cpumasks(pinst, parallel_mask, serial_mask);
 
 out:
-	put_online_cpus();
 	mutex_unlock(&pinst->lock);
+	put_online_cpus();
 
 	return err;
 }
--- linux-4.4.0.orig/kernel/panic.c
+++ linux-4.4.0/kernel/panic.c
@@ -84,6 +84,7 @@
 	 * after the panic_lock is acquired) from invoking panic again.
 	 */
 	local_irq_disable();
+	preempt_disable_notrace();
 
 	/*
 	 * It's possible to come here directly from a panic-assertion and
@@ -157,8 +158,7 @@
 	 * panic() is not being callled from OOPS.
 	 */
 	debug_locks_off();
-	console_trylock();
-	console_unlock();
+	console_flush_on_panic();
 
 	if (!panic_blink)
 		panic_blink = no_blink;
@@ -168,7 +168,7 @@
 		 * Delay timeout seconds before rebooting the machine.
 		 * We can't use the "normal" timers since we just panicked.
 		 */
-		pr_emerg("Rebooting in %d seconds..", panic_timeout);
+		pr_emerg("Rebooting in %d seconds..\n", panic_timeout);
 
 		for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) {
 			touch_nmi_watchdog();
--- linux-4.4.0.orig/kernel/params.c
+++ linux-4.4.0/kernel/params.c
@@ -108,13 +108,18 @@
 	return parameqn(a, b, strlen(a)+1);
 }
 
-static void param_check_unsafe(const struct kernel_param *kp)
+static bool param_check_unsafe(const struct kernel_param *kp,
+			       const char *doing)
 {
 	if (kp->flags & KERNEL_PARAM_FL_UNSAFE) {
 		pr_warn("Setting dangerous option %s - tainting kernel\n",
 			kp->name);
 		add_taint(TAINT_USER, LOCKDEP_STILL_OK);
 	}
+
+	if (kp->flags & KERNEL_PARAM_FL_HWPARAM && secure_modules())
+		return false;
+	return true;
 }
 
 static int parse_one(char *param,
@@ -144,8 +149,10 @@
 			pr_debug("handling %s with %p\n", param,
 				params[i].ops->set);
 			kernel_param_lock(params[i].mod);
-			param_check_unsafe(&params[i]);
-			err = params[i].ops->set(val, &params[i]);
+			if (param_check_unsafe(&params[i], doing))
+				err = params[i].ops->set(val, &params[i]);
+			else
+				err = -EPERM;
 			kernel_param_unlock(params[i].mod);
 			return err;
 		}
@@ -608,6 +615,12 @@
 	return count;
 }
 
+#ifdef CONFIG_MODULES
+#define mod_name(mod) (mod)->name
+#else
+#define mod_name(mod) "unknown"
+#endif
+
 /* sysfs always hands a nul-terminated string in buf.  We rely on that. */
 static ssize_t param_attr_store(struct module_attribute *mattr,
 				struct module_kobject *mk,
@@ -620,8 +633,10 @@
 		return -EPERM;
 
 	kernel_param_lock(mk->mod);
-	param_check_unsafe(attribute->param);
-	err = attribute->param->ops->set(buf, attribute->param);
+	if (param_check_unsafe(attribute->param, mod_name(mk->mod)))
+		err = attribute->param->ops->set(buf, attribute->param);
+	else
+		err = -EPERM;
 	kernel_param_unlock(mk->mod);
 	if (!err)
 		return len;
--- linux-4.4.0.orig/kernel/pid.c
+++ linux-4.4.0/kernel/pid.c
@@ -322,8 +322,10 @@
 	}
 
 	if (unlikely(is_child_reaper(pid))) {
-		if (pid_ns_prepare_proc(ns))
+		if (pid_ns_prepare_proc(ns)) {
+			disable_pid_allocation(ns);
 			goto out_free;
+		}
 	}
 
 	get_pid_ns(ns);
@@ -526,8 +528,11 @@
 	if (!ns)
 		ns = task_active_pid_ns(current);
 	if (likely(pid_alive(task))) {
-		if (type != PIDTYPE_PID)
+		if (type != PIDTYPE_PID) {
+			if (type == __PIDTYPE_TGID)
+				type = PIDTYPE_PID;
 			task = task->group_leader;
+		}
 		nr = pid_nr_ns(rcu_dereference(task->pids[type].pid), ns);
 	}
 	rcu_read_unlock();
@@ -536,12 +541,6 @@
 }
 EXPORT_SYMBOL(__task_pid_nr_ns);
 
-pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
-{
-	return pid_nr_ns(task_tgid(tsk), ns);
-}
-EXPORT_SYMBOL(task_tgid_nr_ns);
-
 struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
 {
 	return ns_of_pid(task_pid(tsk));
--- linux-4.4.0.orig/kernel/pid_namespace.c
+++ linux-4.4.0/kernel/pid_namespace.c
@@ -255,7 +255,7 @@
 	 * if reparented.
 	 */
 	for (;;) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
+		set_current_state(TASK_INTERRUPTIBLE);
 		if (pid_ns->nr_hashed == init_pids)
 			break;
 		schedule();
@@ -325,7 +325,7 @@
 	}
 
 	read_lock(&tasklist_lock);
-	force_sig(SIGKILL, pid_ns->child_reaper);
+	send_sig(SIGKILL, pid_ns->child_reaper, 1);
 	read_unlock(&tasklist_lock);
 
 	do_exit(0);
--- linux-4.4.0.orig/kernel/power/Kconfig
+++ linux-4.4.0/kernel/power/Kconfig
@@ -105,6 +105,7 @@
 	def_bool y
 	depends on SUSPEND || HIBERNATE_CALLBACKS
 	select PM
+	select SRCU
 
 config PM_SLEEP_SMP
 	def_bool y
--- linux-4.4.0.orig/kernel/power/hibernate.c
+++ linux-4.4.0/kernel/power/hibernate.c
@@ -29,6 +29,7 @@
 #include <linux/ctype.h>
 #include <linux/genhd.h>
 #include <linux/ktime.h>
+#include <linux/module.h>
 #include <trace/events/power.h>
 
 #include "power.h"
@@ -66,7 +67,7 @@
 
 bool hibernation_available(void)
 {
-	return (nohibernate == 0);
+	return ((nohibernate == 0) && !secure_modules());
 }
 
 /**
@@ -299,12 +300,12 @@
 	save_processor_state();
 	trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true);
 	error = swsusp_arch_suspend();
+	/* Restore control flow magically appears here */
+	restore_processor_state();
 	trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false);
 	if (error)
 		printk(KERN_ERR "PM: Error %d creating hibernation image\n",
 			error);
-	/* Restore control flow magically appears here */
-	restore_processor_state();
 	if (!in_suspend)
 		events_check_enabled = false;
 
@@ -339,6 +340,7 @@
 	pm_message_t msg;
 	int error;
 
+	pm_suspend_clear_flags();
 	error = platform_begin(platform_mode);
 	if (error)
 		goto Close;
@@ -408,6 +410,11 @@
 	goto Close;
 }
 
+int __weak hibernate_resume_nonboot_cpu_disable(void)
+{
+	return disable_nonboot_cpus();
+}
+
 /**
  * resume_target_kernel - Restore system state from a hibernation image.
  * @platform_mode: Whether or not to use the platform driver.
@@ -432,7 +439,7 @@
 	if (error)
 		goto Cleanup;
 
-	error = disable_nonboot_cpus();
+	error = hibernate_resume_nonboot_cpu_disable();
 	if (error)
 		goto Enable_cpus;
 
@@ -778,17 +785,6 @@
 
 	/* Check if the device is there */
 	swsusp_resume_device = name_to_dev_t(resume_file);
-
-	/*
-	 * name_to_dev_t is ineffective to verify parition if resume_file is in
-	 * integer format. (e.g. major:minor)
-	 */
-	if (isdigit(resume_file[0]) && resume_wait) {
-		int partno;
-		while (!get_gendisk(swsusp_resume_device, &partno))
-			msleep(10);
-	}
-
 	if (!swsusp_resume_device) {
 		/*
 		 * Some device discovery might still be in progress; we need
--- linux-4.4.0.orig/kernel/power/power.h
+++ linux-4.4.0/kernel/power/power.h
@@ -38,6 +38,8 @@
 }
 #endif /* CONFIG_ARCH_HIBERNATION_HEADER */
 
+extern int hibernate_resume_nonboot_cpu_disable(void);
+
 /*
  * Keep some memory free so that I/O operations can succeed without paging
  * [Might this be more than 4 MB?]
@@ -85,9 +87,6 @@
 extern dev_t swsusp_resume_device;
 extern sector_t swsusp_resume_block;
 
-extern asmlinkage int swsusp_arch_suspend(void);
-extern asmlinkage int swsusp_arch_resume(void);
-
 extern int create_basic_memory_bitmaps(void);
 extern void free_basic_memory_bitmaps(void);
 extern int hibernate_preallocate_memory(void);
--- linux-4.4.0.orig/kernel/power/process.c
+++ linux-4.4.0/kernel/power/process.c
@@ -18,8 +18,9 @@
 #include <linux/workqueue.h>
 #include <linux/kmod.h>
 #include <trace/events/power.h>
+#include <linux/cpuset.h>
 
-/* 
+/*
  * Timeout for stopping processes
  */
 unsigned int __read_mostly freeze_timeout_msecs = 20 * MSEC_PER_SEC;
@@ -198,6 +199,8 @@
 	__usermodehelper_set_disable_depth(UMH_FREEZING);
 	thaw_workqueues();
 
+	cpuset_wait_for_hotplug();
+
 	read_lock(&tasklist_lock);
 	for_each_process_thread(g, p) {
 		/* No other threads should have PF_SUSPEND_TASK set */
--- linux-4.4.0.orig/kernel/power/snapshot.c
+++ linux-4.4.0/kernel/power/snapshot.c
@@ -662,8 +662,14 @@
 	 * node for our pfn.
 	 */
 
+	/*
+	 * If the zone we wish to scan is the the current zone and the
+	 * pfn falls into the current node then we do not need to walk
+	 * the tree.
+	 */
 	node = bm->cur.node;
-	if (((pfn - zone->start_pfn) & ~BM_BLOCK_MASK) == bm->cur.node_pfn)
+	if (zone == bm->cur.zone &&
+	    ((pfn - zone->start_pfn) & ~BM_BLOCK_MASK) == bm->cur.node_pfn)
 		goto node_found;
 
 	node      = zone->rtree;
@@ -765,9 +771,9 @@
  */
 static bool rtree_next_node(struct memory_bitmap *bm)
 {
-	bm->cur.node = list_entry(bm->cur.node->list.next,
-				  struct rtree_node, list);
-	if (&bm->cur.node->list != &bm->cur.zone->leaves) {
+	if (!list_is_last(&bm->cur.node->list, &bm->cur.zone->leaves)) {
+		bm->cur.node = list_entry(bm->cur.node->list.next,
+					  struct rtree_node, list);
 		bm->cur.node_pfn += BM_BITS_PER_BLOCK;
 		bm->cur.node_bit  = 0;
 		touch_softlockup_watchdog();
@@ -775,9 +781,9 @@
 	}
 
 	/* No more nodes, goto next zone */
-	bm->cur.zone = list_entry(bm->cur.zone->list.next,
+	if (!list_is_last(&bm->cur.zone->list, &bm->zones)) {
+		bm->cur.zone = list_entry(bm->cur.zone->list.next,
 				  struct mem_zone_bm_rtree, list);
-	if (&bm->cur.zone->list != &bm->zones) {
 		bm->cur.node = list_entry(bm->cur.zone->leaves.next,
 					  struct rtree_node, list);
 		bm->cur.node_pfn = 0;
--- linux-4.4.0.orig/kernel/power/suspend_test.c
+++ linux-4.4.0/kernel/power/suspend_test.c
@@ -203,8 +203,10 @@
 
 	/* RTCs have initialized by now too ... can we use one? */
 	dev = class_find_device(rtc_class, NULL, NULL, has_wakealarm);
-	if (dev)
+	if (dev) {
 		rtc = rtc_class_open(dev_name(dev));
+		put_device(dev);
+	}
 	if (!rtc) {
 		printk(warn_no_rtc);
 		return 0;
--- linux-4.4.0.orig/kernel/power/swap.c
+++ linux-4.4.0/kernel/power/swap.c
@@ -37,6 +37,14 @@
 #define HIBERNATE_SIG	"S1SUSPEND"
 
 /*
+ * When reading an {un,}compressed image, we may restore pages in place,
+ * in which case some architectures need these pages cleaning before they
+ * can be executed. We don't know which pages these may be, so clean the lot.
+ */
+static bool clean_pages_on_read;
+static bool clean_pages_on_decompress;
+
+/*
  *	The swap map is a data structure used for keeping track of each page
  *	written to a swap partition.  It consists of many swap_map_page
  *	structures that contain each an array of MAP_PAGE_ENTRIES swap entries.
@@ -241,6 +249,9 @@
 
 	if (bio_data_dir(bio) == WRITE)
 		put_page(page);
+	else if (clean_pages_on_read)
+		flush_icache_range((unsigned long)page_address(page),
+				   (unsigned long)page_address(page) + PAGE_SIZE);
 
 	if (bio->bi_error && !hb->error)
 		hb->error = bio->bi_error;
@@ -1049,6 +1060,7 @@
 
 	hib_init_batch(&hb);
 
+	clean_pages_on_read = true;
 	printk(KERN_INFO "PM: Loading image data pages (%u pages)...\n",
 		nr_to_read);
 	m = nr_to_read / 10;
@@ -1124,6 +1136,10 @@
 		d->unc_len = LZO_UNC_SIZE;
 		d->ret = lzo1x_decompress_safe(d->cmp + LZO_HEADER, d->cmp_len,
 		                               d->unc, &d->unc_len);
+		if (clean_pages_on_decompress)
+			flush_icache_range((unsigned long)d->unc,
+					   (unsigned long)d->unc + d->unc_len);
+
 		atomic_set(&d->stop, 1);
 		wake_up(&d->done);
 	}
@@ -1189,6 +1205,8 @@
 	}
 	memset(crc, 0, offsetof(struct crc_data, go));
 
+	clean_pages_on_decompress = true;
+
 	/*
 	 * Start the decompression threads.
 	 */
--- linux-4.4.0.orig/kernel/power/user.c
+++ linux-4.4.0/kernel/power/user.c
@@ -184,6 +184,11 @@
 		res = PAGE_SIZE - pg_offp;
 	}
 
+	if (!data_of(data->handle)) {
+		res = -EINVAL;
+		goto unlock;
+	}
+
 	res = simple_write_to_buffer(data_of(data->handle), res, &pg_offp,
 			buf, count);
 	if (res > 0)
--- linux-4.4.0.orig/kernel/printk/braille.c
+++ linux-4.4.0/kernel/printk/braille.c
@@ -2,27 +2,28 @@
 
 #include <linux/kernel.h>
 #include <linux/console.h>
+#include <linux/errno.h>
 #include <linux/string.h>
 
 #include "console_cmdline.h"
 #include "braille.h"
 
-char *_braille_console_setup(char **str, char **brl_options)
+int _braille_console_setup(char **str, char **brl_options)
 {
-	if (!memcmp(*str, "brl,", 4)) {
+	if (!strncmp(*str, "brl,", 4)) {
 		*brl_options = "";
 		*str += 4;
-	} else if (!memcmp(str, "brl=", 4)) {
+	} else if (!strncmp(*str, "brl=", 4)) {
 		*brl_options = *str + 4;
 		*str = strchr(*brl_options, ',');
-		if (!*str)
+		if (!*str) {
 			pr_err("need port name after brl=\n");
-		else
-			*((*str)++) = 0;
-	} else
-		return NULL;
+			return -EINVAL;
+		}
+		*((*str)++) = 0;
+	}
 
-	return *str;
+	return 0;
 }
 
 int
--- linux-4.4.0.orig/kernel/printk/braille.h
+++ linux-4.4.0/kernel/printk/braille.h
@@ -9,7 +9,14 @@
 	c->brl_options = brl_options;
 }
 
-char *
+/*
+ * Setup console according to braille options.
+ * Return -EINVAL on syntax error, 0 on success (or no braille option was
+ * actually given).
+ * Modifies str to point to the serial options
+ * Sets brl_options to the parsed braille options.
+ */
+int
 _braille_console_setup(char **str, char **brl_options);
 
 int
@@ -25,10 +32,10 @@
 {
 }
 
-static inline char *
+static inline int
 _braille_console_setup(char **str, char **brl_options)
 {
-	return NULL;
+	return 0;
 }
 
 static inline int
--- linux-4.4.0.orig/kernel/printk/printk.c
+++ linux-4.4.0/kernel/printk/printk.c
@@ -279,6 +279,7 @@
 #define LOG_ALIGN __alignof__(struct printk_log)
 #endif
 #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
+#define LOG_BUF_LEN_MAX (u32)(1 << 31)
 static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
 static char *log_buf = __log_buf;
 static u32 log_buf_len = __LOG_BUF_LEN;
@@ -870,18 +871,28 @@
 static unsigned long __initdata new_log_buf_len;
 
 /* we practice scaling the ring buffer by powers of 2 */
-static void __init log_buf_len_update(unsigned size)
+static void __init log_buf_len_update(u64 size)
 {
+	if (size > (u64)LOG_BUF_LEN_MAX) {
+		size = (u64)LOG_BUF_LEN_MAX;
+		pr_err("log_buf over 2G is not supported.\n");
+	}
+
 	if (size)
 		size = roundup_pow_of_two(size);
 	if (size > log_buf_len)
-		new_log_buf_len = size;
+		new_log_buf_len = (unsigned long)size;
 }
 
 /* save requested log_buf_len since it's too early to process it */
 static int __init log_buf_len_setup(char *str)
 {
-	unsigned size = memparse(str, &str);
+	u64 size;
+
+	if (!str)
+		return -EINVAL;
+
+	size = memparse(str, &str);
 
 	log_buf_len_update(size);
 
@@ -926,7 +937,7 @@
 {
 	unsigned long flags;
 	char *new_log_buf;
-	int free;
+	unsigned int free;
 
 	if (log_buf != __log_buf)
 		return;
@@ -946,7 +957,7 @@
 	}
 
 	if (unlikely(!new_log_buf)) {
-		pr_err("log_buf_len: %ld bytes not available\n",
+		pr_err("log_buf_len: %lu bytes not available\n",
 			new_log_buf_len);
 		return;
 	}
@@ -959,8 +970,8 @@
 	memcpy(log_buf, __log_buf, __LOG_BUF_LEN);
 	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 
-	pr_info("log_buf_len: %d bytes\n", log_buf_len);
-	pr_info("early log buf free: %d(%d%%)\n",
+	pr_info("log_buf_len: %u bytes\n", log_buf_len);
+	pr_info("early log buf free: %u(%u%%)\n",
 		free, (free * 100) / __LOG_BUF_LEN);
 }
 
@@ -1436,7 +1447,7 @@
 {
 	struct console *con;
 
-	trace_console(text, len);
+	trace_console_rcuidle(text, len);
 
 	if (level >= console_loglevel && !ignore_loglevel)
 		return;
@@ -1809,20 +1820,12 @@
 	if (!in_sched) {
 		lockdep_off();
 		/*
-		 * Disable preemption to avoid being preempted while holding
-		 * console_sem which would prevent anyone from printing to
-		 * console
-		 */
-		preempt_disable();
-
-		/*
 		 * Try to acquire and then immediately release the console
 		 * semaphore.  The release will print out buffers and wake up
 		 * /dev/kmsg and syslog() users.
 		 */
 		if (console_trylock_for_printk())
 			console_unlock();
-		preempt_enable();
 		lockdep_on();
 	}
 
@@ -2021,6 +2024,9 @@
 	char *s, *options, *brl_options = NULL;
 	int idx;
 
+	if (str[0] == 0)
+		return 1;
+
 	if (_braille_console_setup(&str, &brl_options))
 		return 1;
 
@@ -2173,7 +2179,20 @@
 		return 0;
 	}
 	console_locked = 1;
-	console_may_schedule = 0;
+	/*
+	 * When PREEMPT_COUNT disabled we can't reliably detect if it's
+	 * safe to schedule (e.g. calling printk while holding a spin_lock),
+	 * because preempt_disable()/preempt_enable() are just barriers there
+	 * and preempt_count() is always 0.
+	 *
+	 * RCU read sections have a separate preemption counter when
+	 * PREEMPT_RCU enabled thus we must take extra care and check
+	 * rcu_preempt_depth(), otherwise RCU read sections modify
+	 * preempt_count().
+	 */
+	console_may_schedule = !oops_in_progress &&
+			preemptible() &&
+			!rcu_preempt_depth();
 	return 1;
 }
 EXPORT_SYMBOL(console_trylock);
@@ -2233,13 +2252,24 @@
 	static u64 seen_seq;
 	unsigned long flags;
 	bool wake_klogd = false;
-	bool retry;
+	bool do_cond_resched, retry;
 
 	if (console_suspended) {
 		up_console_sem();
 		return;
 	}
 
+	/*
+	 * Console drivers are called under logbuf_lock, so
+	 * @console_may_schedule should be cleared before; however, we may
+	 * end up dumping a lot of lines, for example, if called from
+	 * console registration path, and should invoke cond_resched()
+	 * between lines if allowable.  Not doing so can cause a very long
+	 * scheduling stall on a slow console leading to RCU stall and
+	 * softlockup warnings which exacerbate the issue with more
+	 * messages practically incapacitating the system.
+	 */
+	do_cond_resched = console_may_schedule;
 	console_may_schedule = 0;
 
 	/* flush buffered message fragment immediately to console */
@@ -2311,6 +2341,9 @@
 		call_console_drivers(level, ext_text, ext_len, text, len);
 		start_critical_timings();
 		local_irq_restore(flags);
+
+		if (do_cond_resched)
+			cond_resched();
 	}
 	console_locked = 0;
 
@@ -2378,6 +2411,25 @@
 	console_unlock();
 }
 
+/**
+ * console_flush_on_panic - flush console content on panic
+ *
+ * Immediately output all pending messages no matter what.
+ */
+void console_flush_on_panic(void)
+{
+	/*
+	 * If someone else is holding the console lock, trylock will fail
+	 * and may_schedule may be set.  Ignore and proceed to unlock so
+	 * that messages are flushed out.  As this can be called from any
+	 * context and we don't want to get preempted while flushing,
+	 * ensure may_schedule is cleared.
+	 */
+	console_trylock();
+	console_may_schedule = 0;
+	console_unlock();
+}
+
 /*
  * Return the console tty driver structure and its associated index
  */
@@ -3010,7 +3062,7 @@
 	seq = dumper->cur_seq;
 	idx = dumper->cur_idx;
 	prev = 0;
-	while (l > size && seq < dumper->next_seq) {
+	while (l >= size && seq < dumper->next_seq) {
 		struct printk_log *msg = log_from_idx(idx);
 
 		l -= msg_print_text(msg, prev, true, NULL, 0);
--- linux-4.4.0.orig/kernel/profile.c
+++ linux-4.4.0/kernel/profile.c
@@ -44,7 +44,7 @@
 EXPORT_SYMBOL_GPL(prof_on);
 
 static cpumask_var_t prof_cpu_mask;
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS)
 static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
 static DEFINE_PER_CPU(int, cpu_profile_flip);
 static DEFINE_MUTEX(profile_flip_mutex);
@@ -201,7 +201,7 @@
 }
 EXPORT_SYMBOL_GPL(profile_event_unregister);
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS)
 /*
  * Each cpu has a pair of open-addressed hashtables for pending
  * profile hits. read_profile() IPI's all cpus to request them
--- linux-4.4.0.orig/kernel/ptrace.c
+++ linux-4.4.0/kernel/ptrace.c
@@ -28,17 +28,24 @@
 #include <linux/compat.h>
 
 
+void __ptrace_link(struct task_struct *child, struct task_struct *new_parent,
+		   const struct cred *ptracer_cred)
+{
+	BUG_ON(!list_empty(&child->ptrace_entry));
+	list_add(&child->ptrace_entry, &new_parent->ptraced);
+	child->parent = new_parent;
+	child->ptracer_cred = get_cred(ptracer_cred);
+}
+
 /*
  * ptrace a task: make the debugger its new parent and
  * move it to the ptrace list.
  *
  * Must be called with the tasklist lock write-held.
  */
-void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
+static void ptrace_link(struct task_struct *child, struct task_struct *new_parent)
 {
-	BUG_ON(!list_empty(&child->ptrace_entry));
-	list_add(&child->ptrace_entry, &new_parent->ptraced);
-	child->parent = new_parent;
+	__ptrace_link(child, new_parent, current_cred());
 }
 
 /**
@@ -71,11 +78,15 @@
  */
 void __ptrace_unlink(struct task_struct *child)
 {
+	const struct cred *old_cred;
 	BUG_ON(!child->ptrace);
 
 	child->ptrace = 0;
 	child->parent = child->real_parent;
 	list_del_init(&child->ptrace_entry);
+	old_cred = child->ptracer_cred;
+	child->ptracer_cred = NULL;
+	put_cred(old_cred);
 
 	spin_lock(&child->sighand->siglock);
 
@@ -144,11 +155,17 @@
 
 	WARN_ON(!task->ptrace || task->parent != current);
 
+	/*
+	 * PTRACE_LISTEN can allow ptrace_trap_notify to wake us up remotely.
+	 * Recheck state under the lock to close this race.
+	 */
 	spin_lock_irq(&task->sighand->siglock);
-	if (__fatal_signal_pending(task))
-		wake_up_state(task, __TASK_TRACED);
-	else
-		task->state = TASK_TRACED;
+	if (task->state == __TASK_TRACED) {
+		if (__fatal_signal_pending(task))
+			wake_up_state(task, __TASK_TRACED);
+		else
+			task->state = TASK_TRACED;
+	}
 	spin_unlock_irq(&task->sighand->siglock);
 }
 
@@ -209,6 +226,9 @@
 
 static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
 {
+	if (mode & PTRACE_MODE_SCHED)
+		return false;
+
 	if (mode & PTRACE_MODE_NOAUDIT)
 		return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE);
 	else
@@ -219,6 +239,14 @@
 static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
 	const struct cred *cred = current_cred(), *tcred;
+	struct mm_struct *mm;
+	kuid_t caller_uid;
+	kgid_t caller_gid;
+
+	if (!(mode & PTRACE_MODE_FSCREDS) == !(mode & PTRACE_MODE_REALCREDS)) {
+		WARN(1, "denying ptrace access check without PTRACE_MODE_*CREDS\n");
+		return -EPERM;
+	}
 
 	/* May we inspect the given task?
 	 * This check is used both for attaching with ptrace
@@ -228,18 +256,33 @@
 	 * because setting up the necessary parent/child relationship
 	 * or halting the specified task is impossible.
 	 */
-	int dumpable = 0;
+
 	/* Don't let security modules deny introspection */
 	if (same_thread_group(task, current))
 		return 0;
 	rcu_read_lock();
+	if (mode & PTRACE_MODE_FSCREDS) {
+		caller_uid = cred->fsuid;
+		caller_gid = cred->fsgid;
+	} else {
+		/*
+		 * Using the euid would make more sense here, but something
+		 * in userland might rely on the old behavior, and this
+		 * shouldn't be a security problem since
+		 * PTRACE_MODE_REALCREDS implies that the caller explicitly
+		 * used a syscall that requests access to another process
+		 * (and not a filesystem syscall to procfs).
+		 */
+		caller_uid = cred->uid;
+		caller_gid = cred->gid;
+	}
 	tcred = __task_cred(task);
-	if (uid_eq(cred->uid, tcred->euid) &&
-	    uid_eq(cred->uid, tcred->suid) &&
-	    uid_eq(cred->uid, tcred->uid)  &&
-	    gid_eq(cred->gid, tcred->egid) &&
-	    gid_eq(cred->gid, tcred->sgid) &&
-	    gid_eq(cred->gid, tcred->gid))
+	if (uid_eq(caller_uid, tcred->euid) &&
+	    uid_eq(caller_uid, tcred->suid) &&
+	    uid_eq(caller_uid, tcred->uid)  &&
+	    gid_eq(caller_gid, tcred->egid) &&
+	    gid_eq(caller_gid, tcred->sgid) &&
+	    gid_eq(caller_gid, tcred->gid))
 		goto ok;
 	if (ptrace_has_cap(tcred->user_ns, mode))
 		goto ok;
@@ -247,20 +290,32 @@
 	return -EPERM;
 ok:
 	rcu_read_unlock();
+	/*
+	 * If a task drops privileges and becomes nondumpable (through a syscall
+	 * like setresuid()) while we are trying to access it, we must ensure
+	 * that the dumpability is read after the credentials; otherwise,
+	 * we may be able to attach to a task that we shouldn't be able to
+	 * attach to (as if the task had dropped privileges without becoming
+	 * nondumpable).
+	 * Pairs with a write barrier in commit_creds().
+	 */
 	smp_rmb();
-	if (task->mm)
-		dumpable = get_dumpable(task->mm);
-	rcu_read_lock();
-	if (dumpable != SUID_DUMP_USER &&
-	    !ptrace_has_cap(__task_cred(task)->user_ns, mode)) {
-		rcu_read_unlock();
-		return -EPERM;
-	}
-	rcu_read_unlock();
+	mm = task->mm;
+	if (mm &&
+	    ((get_dumpable(mm) != SUID_DUMP_USER) &&
+	     !ptrace_has_cap(mm->user_ns, mode)))
+	    return -EPERM;
 
+	if (mode & PTRACE_MODE_SCHED)
+		return 0;
 	return security_ptrace_access_check(task, mode);
 }
 
+bool ptrace_may_access_sched(struct task_struct *task, unsigned int mode)
+{
+	return __ptrace_may_access(task, mode | PTRACE_MODE_SCHED);
+}
+
 bool ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
 	int err;
@@ -270,6 +325,26 @@
 	return !err;
 }
 
+static int check_ptrace_options(unsigned long data)
+{
+	if (data & ~(unsigned long)PTRACE_O_MASK)
+		return -EINVAL;
+
+	if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) {
+		if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) ||
+		    !IS_ENABLED(CONFIG_SECCOMP))
+			return -EINVAL;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		if (seccomp_mode(&current->seccomp) != SECCOMP_MODE_DISABLED ||
+		    current->ptrace & PT_SUSPEND_SECCOMP)
+			return -EPERM;
+	}
+	return 0;
+}
+
 static int ptrace_attach(struct task_struct *task, long request,
 			 unsigned long addr,
 			 unsigned long flags)
@@ -281,8 +356,16 @@
 	if (seize) {
 		if (addr != 0)
 			goto out;
+		/*
+		 * This duplicates the check in check_ptrace_options() because
+		 * ptrace_attach() and ptrace_setoptions() have historically
+		 * used different error codes for unknown ptrace options.
+		 */
 		if (flags & ~(unsigned long)PTRACE_O_MASK)
 			goto out;
+		retval = check_ptrace_options(flags);
+		if (retval)
+			return retval;
 		flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT);
 	} else {
 		flags = PT_PTRACED;
@@ -306,7 +389,7 @@
 		goto out;
 
 	task_lock(task);
-	retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH);
+	retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS);
 	task_unlock(task);
 	if (retval)
 		goto unlock_creds;
@@ -320,13 +403,9 @@
 
 	if (seize)
 		flags |= PT_SEIZED;
-	rcu_read_lock();
-	if (ns_capable(__task_cred(task)->user_ns, CAP_SYS_PTRACE))
-		flags |= PT_PTRACE_CAP;
-	rcu_read_unlock();
 	task->ptrace = flags;
 
-	__ptrace_link(task, current);
+	ptrace_link(task, current);
 
 	/* SEIZE doesn't trap tracee on attach */
 	if (!seize)
@@ -393,7 +472,7 @@
 		 */
 		if (!ret && !(current->real_parent->flags & PF_EXITING)) {
 			current->ptrace = PT_PTRACED;
-			__ptrace_link(current, current->real_parent);
+			ptrace_link(current, current->real_parent);
 		}
 	}
 	write_unlock_irq(&tasklist_lock);
@@ -552,22 +631,11 @@
 static int ptrace_setoptions(struct task_struct *child, unsigned long data)
 {
 	unsigned flags;
+	int ret;
 
-	if (data & ~(unsigned long)PTRACE_O_MASK)
-		return -EINVAL;
-
-	if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) {
-		if (!config_enabled(CONFIG_CHECKPOINT_RESTORE) ||
-		    !config_enabled(CONFIG_SECCOMP))
-			return -EINVAL;
-
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-
-		if (seccomp_mode(&current->seccomp) != SECCOMP_MODE_DISABLED ||
-		    current->ptrace & PT_SUSPEND_SECCOMP)
-			return -EPERM;
-	}
+	ret = check_ptrace_options(data);
+	if (ret)
+		return ret;
 
 	/* Avoid intermediate state when all opts are cleared */
 	flags = child->ptrace;
@@ -630,6 +698,10 @@
 	if (arg.nr < 0)
 		return -EINVAL;
 
+	/* Ensure arg.off fits in an unsigned long */
+	if (arg.off > ULONG_MAX)
+		return 0;
+
 	if (arg.flags & PTRACE_PEEKSIGINFO_SHARED)
 		pending = &child->signal->shared_pending;
 	else
@@ -637,18 +709,20 @@
 
 	for (i = 0; i < arg.nr; ) {
 		siginfo_t info;
-		s32 off = arg.off + i;
+		unsigned long off = arg.off + i;
+		bool found = false;
 
 		spin_lock_irq(&child->sighand->siglock);
 		list_for_each_entry(q, &pending->list, list) {
 			if (!off--) {
+				found = true;
 				copy_siginfo(&info, &q->info);
 				break;
 			}
 		}
 		spin_unlock_irq(&child->sighand->siglock);
 
-		if (off >= 0) /* beyond the end of the list */
+		if (!found) /* beyond the end of the list */
 			break;
 
 #ifdef CONFIG_COMPAT
--- linux-4.4.0.orig/kernel/rcu/rcutorture.c
+++ linux-4.4.0/kernel/rcu/rcutorture.c
@@ -1603,6 +1603,10 @@
 			cur_ops->cb_barrier();
 		return;
 	}
+	if (!cur_ops) {
+		torture_cleanup_end();
+		return;
+	}
 
 	rcu_torture_barrier_cleanup();
 	torture_stop_kthread(rcu_torture_stall, stall_task);
@@ -1741,6 +1745,7 @@
 			pr_alert(" %s", torture_ops[i]->name);
 		pr_alert("\n");
 		firsterr = -EINVAL;
+		cur_ops = NULL;
 		goto unwind;
 	}
 	if (cur_ops->fqs == NULL && fqs_duration != 0) {
--- linux-4.4.0.orig/kernel/rcu/tree.c
+++ linux-4.4.0/kernel/rcu/tree.c
@@ -759,6 +759,12 @@
 
 	local_irq_save(flags);
 	rdtp = this_cpu_ptr(&rcu_dynticks);
+
+	/* Page faults can happen in NMI handlers, so check... */
+	if (READ_ONCE(rdtp->dynticks_nmi_nesting))
+		return;
+
+	RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_exit() invoked with irqs enabled!!!");
 	oldval = rdtp->dynticks_nesting;
 	rdtp->dynticks_nesting--;
 	WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -887,6 +893,12 @@
 
 	local_irq_save(flags);
 	rdtp = this_cpu_ptr(&rcu_dynticks);
+
+	/* Page faults can happen in NMI handlers, so check... */
+	if (READ_ONCE(rdtp->dynticks_nmi_nesting))
+		return;
+
+	RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_enter() invoked with irqs enabled!!!");
 	oldval = rdtp->dynticks_nesting;
 	rdtp->dynticks_nesting++;
 	WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -1599,15 +1611,23 @@
 }
 
 /*
- * Awaken the grace-period kthread for the specified flavor of RCU.
- * Don't do a self-awaken, and don't bother awakening when there is
- * nothing for the grace-period kthread to do (as in several CPUs
- * raced to awaken, and we lost), and finally don't try to awaken
- * a kthread that has not yet been created.
+ * Awaken the grace-period kthread.  Don't do a self-awaken (unless in
+ * an interrupt or softirq handler), and don't bother awakening when there
+ * is nothing for the grace-period kthread to do (as in several CPUs raced
+ * to awaken, and we lost), and finally don't try to awaken a kthread that
+ * has not yet been created.  If all those checks are passed, track some
+ * debug information and awaken.
+ *
+ * So why do the self-wakeup when in an interrupt or softirq handler
+ * in the grace-period kthread's context?  Because the kthread might have
+ * been interrupted just as it was going to sleep, and just after the final
+ * pre-sleep check of the awaken condition.  In this case, a wakeup really
+ * is required, and is therefore supplied.
  */
 static void rcu_gp_kthread_wake(struct rcu_state *rsp)
 {
-	if (current == rsp->gp_kthread ||
+	if ((current == rsp->gp_kthread &&
+	     !in_interrupt() && !in_serving_softirq()) ||
 	    !READ_ONCE(rsp->gp_flags) ||
 	    !rsp->gp_kthread)
 		return;
@@ -3805,7 +3825,7 @@
 					continue;
 				rdp = per_cpu_ptr(rsp->rda, cpu);
 				pr_cont(" %d-%c%c%c", cpu,
-					"O."[cpu_online(cpu)],
+					"O."[!!cpu_online(cpu)],
 					"o."[!!(rdp->grpmask & rnp->expmaskinit)],
 					"N."[!!(rdp->grpmask & rnp->expmaskinitnext)]);
 			}
--- linux-4.4.0.orig/kernel/rcu/tree_plugin.h
+++ linux-4.4.0/kernel/rcu/tree_plugin.h
@@ -2275,6 +2275,7 @@
 				cl++;
 			c++;
 			local_bh_enable();
+			cond_resched_rcu_qs();
 			list = next;
 		}
 		trace_rcu_batch_end(rdp->rsp->name, c, !!list, 0, 0, 1);
--- linux-4.4.0.orig/kernel/reboot.c
+++ linux-4.4.0/kernel/reboot.c
@@ -512,22 +512,22 @@
 			break;
 
 		case 's':
-		{
-			int rc;
-
-			if (isdigit(*(str+1))) {
-				rc = kstrtoint(str+1, 0, &reboot_cpu);
-				if (rc)
-					return rc;
-			} else if (str[1] == 'm' && str[2] == 'p' &&
-				   isdigit(*(str+3))) {
-				rc = kstrtoint(str+3, 0, &reboot_cpu);
-				if (rc)
-					return rc;
-			} else
+			if (isdigit(*(str+1)))
+				reboot_cpu = simple_strtoul(str+1, NULL, 0);
+			else if (str[1] == 'm' && str[2] == 'p' &&
+							isdigit(*(str+3)))
+				reboot_cpu = simple_strtoul(str+3, NULL, 0);
+			else
 				reboot_mode = REBOOT_SOFT;
+			if (reboot_cpu >= num_possible_cpus()) {
+				pr_err("Ignoring the CPU number in reboot= option. "
+				       "CPU %d exceeds possible cpu number %d\n",
+				       reboot_cpu, num_possible_cpus());
+				reboot_cpu = 0;
+				break;
+			}
 			break;
-		}
+
 		case 'g':
 			reboot_mode = REBOOT_GPIO;
 			break;
--- linux-4.4.0.orig/kernel/relay.c
+++ linux-4.4.0/kernel/relay.c
@@ -163,7 +163,7 @@
 {
 	struct rchan_buf *buf;
 
-	if (chan->n_subbufs > UINT_MAX / sizeof(size_t *))
+	if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t *))
 		return NULL;
 
 	buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
@@ -967,14 +967,14 @@
 /*
  *	relay_file_read_avail - boolean, are there unconsumed bytes available?
  */
-static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos)
+static int relay_file_read_avail(struct rchan_buf *buf)
 {
 	size_t subbuf_size = buf->chan->subbuf_size;
 	size_t n_subbufs = buf->chan->n_subbufs;
 	size_t produced = buf->subbufs_produced;
 	size_t consumed = buf->subbufs_consumed;
 
-	relay_file_read_consume(buf, read_pos, 0);
+	relay_file_read_consume(buf, 0, 0);
 
 	consumed = buf->subbufs_consumed;
 
@@ -1035,23 +1035,21 @@
 
 /**
  *	relay_file_read_start_pos - find the first available byte to read
- *	@read_pos: file read position
  *	@buf: relay channel buffer
  *
- *	If the @read_pos is in the middle of padding, return the
+ *	If the read_pos is in the middle of padding, return the
  *	position of the first actually available byte, otherwise
  *	return the original value.
  */
-static size_t relay_file_read_start_pos(size_t read_pos,
-					struct rchan_buf *buf)
+static size_t relay_file_read_start_pos(struct rchan_buf *buf)
 {
 	size_t read_subbuf, padding, padding_start, padding_end;
 	size_t subbuf_size = buf->chan->subbuf_size;
 	size_t n_subbufs = buf->chan->n_subbufs;
 	size_t consumed = buf->subbufs_consumed % n_subbufs;
+	size_t read_pos = (consumed * subbuf_size + buf->bytes_consumed)
+			% (n_subbufs * subbuf_size);
 
-	if (!read_pos)
-		read_pos = consumed * subbuf_size + buf->bytes_consumed;
 	read_subbuf = read_pos / subbuf_size;
 	padding = buf->padding[read_subbuf];
 	padding_start = (read_subbuf + 1) * subbuf_size - padding;
@@ -1135,10 +1133,10 @@
 
 	mutex_lock(&file_inode(filp)->i_mutex);
 	do {
-		if (!relay_file_read_avail(buf, *ppos))
+		if (!relay_file_read_avail(buf))
 			break;
 
-		read_start = relay_file_read_start_pos(*ppos, buf);
+		read_start = relay_file_read_start_pos(buf);
 		avail = relay_file_read_subbuf_avail(read_start, buf);
 		if (!avail)
 			break;
--- linux-4.4.0.orig/kernel/resource.c
+++ linux-4.4.0/kernel/resource.c
@@ -105,16 +105,25 @@
 {
 	struct resource *root = m->private;
 	struct resource *r = v, *p;
+	unsigned long long start, end;
 	int width = root->end < 0x10000 ? 4 : 8;
 	int depth;
 
 	for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
 		if (p->parent == root)
 			break;
+
+	if (file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN)) {
+		start = r->start;
+		end = r->end;
+	} else {
+		start = end = 0;
+	}
+
 	seq_printf(m, "%*s%0*llx-%0*llx : %s\n",
 			depth * 2, "",
-			width, (unsigned long long) r->start,
-			width, (unsigned long long) r->end,
+			width, start,
+			width, end,
 			r->name ? r->name : "<BAD>");
 	return 0;
 }
@@ -602,7 +611,8 @@
 			alloc.start = constraint->alignf(constraint->alignf_data, &avail,
 					size, constraint->align);
 			alloc.end = alloc.start + size - 1;
-			if (resource_contains(&avail, &alloc)) {
+			if (alloc.start <= alloc.end &&
+			    resource_contains(&avail, &alloc)) {
 				new->start = alloc.start;
 				new->end = alloc.end;
 				return 0;
@@ -1083,9 +1093,10 @@
 		if (!conflict)
 			break;
 		if (conflict != parent) {
-			parent = conflict;
-			if (!(conflict->flags & IORESOURCE_BUSY))
+			if (!(conflict->flags & IORESOURCE_BUSY)) {
+				parent = conflict;
 				continue;
+			}
 		}
 		if (conflict->flags & flags & IORESOURCE_MUXED) {
 			add_wait_queue(&muxed_resource_wait, &wait);
--- linux-4.4.0.orig/kernel/sched/auto_group.c
+++ linux-4.4.0/kernel/sched/auto_group.c
@@ -6,6 +6,7 @@
 #include <linux/utsname.h>
 #include <linux/security.h>
 #include <linux/export.h>
+#include <linux/nospec.h>
 
 unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1;
 static struct autogroup autogroup_default;
@@ -111,14 +112,11 @@
 {
 	if (tg != &root_task_group)
 		return false;
-
 	/*
-	 * We can only assume the task group can't go away on us if
-	 * autogroup_move_group() can see us on ->thread_group list.
+	 * If we race with autogroup_move_group() the caller can use the old
+	 * value of signal->autogroup but in this case sched_move_task() will
+	 * be called again before autogroup_kref_put().
 	 */
-	if (p->flags & PF_EXITING)
-		return false;
-
 	return true;
 }
 
@@ -138,13 +136,17 @@
 	}
 
 	p->signal->autogroup = autogroup_kref_get(ag);
-
-	if (!READ_ONCE(sysctl_sched_autogroup_enabled))
-		goto out;
-
+	/*
+	 * We can't avoid sched_move_task() after we changed signal->autogroup,
+	 * this process can already run with task_group() == prev->tg or we can
+	 * race with cgroup code which can read autogroup = prev under rq->lock.
+	 * In the latter case for_each_thread() can not miss a migrating thread,
+	 * cpu_cgroup_attach() must not be possible after cgroup_exit() and it
+	 * can't be removed from thread list, we hold ->siglock.
+	 */
 	for_each_thread(p, t)
 		sched_move_task(t);
-out:
+
 	unlock_task_sighand(p, &flags);
 	autogroup_kref_put(prev);
 }
@@ -192,7 +194,7 @@
 {
 	static unsigned long next = INITIAL_JIFFIES;
 	struct autogroup *ag;
-	int err;
+	int err, idx;
 
 	if (nice < MIN_NICE || nice > MAX_NICE)
 		return -EINVAL;
@@ -212,7 +214,9 @@
 	ag = autogroup_task_get(p);
 
 	down_write(&ag->lock);
-	err = sched_group_set_shares(ag->tg, prio_to_weight[nice + 20]);
+
+	idx = array_index_nospec(nice + 20, 40);
+	err = sched_group_set_shares(ag->tg, prio_to_weight[idx]);
 	if (!err)
 		ag->nice = nice;
 	up_write(&ag->lock);
--- linux-4.4.0.orig/kernel/sched/core.c
+++ linux-4.4.0/kernel/sched/core.c
@@ -32,7 +32,7 @@
 #include <linux/init.h>
 #include <linux/uaccess.h>
 #include <linux/highmem.h>
-#include <asm/mmu_context.h>
+#include <linux/mmu_context.h>
 #include <linux/interrupt.h>
 #include <linux/capability.h>
 #include <linux/completion.h>
@@ -600,9 +600,9 @@
 	struct rq *rq = cpu_rq(cpu);
 	unsigned long flags;
 
-	if (!raw_spin_trylock_irqsave(&rq->lock, flags))
-		return;
-	resched_curr(rq);
+	raw_spin_lock_irqsave(&rq->lock, flags);
+	if (cpu_online(cpu) || cpu == smp_processor_id())
+		resched_curr(rq);
 	raw_spin_unlock_irqrestore(&rq->lock, flags);
 }
 
@@ -627,7 +627,10 @@
 	rcu_read_lock();
 	for_each_domain(cpu, sd) {
 		for_each_cpu(i, sched_domain_span(sd)) {
-			if (!idle_cpu(i) && is_housekeeping_cpu(cpu)) {
+			if (cpu == i)
+				continue;
+
+			if (!idle_cpu(i) && is_housekeeping_cpu(i)) {
 				cpu = i;
 				goto unlock;
 			}
@@ -1942,6 +1945,28 @@
 	success = 1; /* we're going to change ->state */
 	cpu = task_cpu(p);
 
+	/*
+	 * Ensure we load p->on_rq _after_ p->state, otherwise it would
+	 * be possible to, falsely, observe p->on_rq == 0 and get stuck
+	 * in smp_cond_load_acquire() below.
+	 *
+	 * sched_ttwu_pending()                 try_to_wake_up()
+	 *   [S] p->on_rq = 1;                  [L] P->state
+	 *       UNLOCK rq->lock  -----.
+	 *                              \
+	 *				 +---   RMB
+	 * schedule()                   /
+	 *       LOCK rq->lock    -----'
+	 *       UNLOCK rq->lock
+	 *
+	 * [task p]
+	 *   [S] p->state = UNINTERRUPTIBLE     [L] p->on_rq
+	 *
+	 * Pairs with the UNLOCK+LOCK on rq->lock from the
+	 * last wakeup of our task and the schedule that got our task
+	 * current.
+	 */
+	smp_rmb();
 	if (p->on_rq && ttwu_remote(p, wake_flags))
 		goto stat;
 
@@ -2085,6 +2110,7 @@
 	dl_se->dl_period = 0;
 	dl_se->flags = 0;
 	dl_se->dl_bw = 0;
+	dl_se->dl_density = 0;
 
 	dl_se->dl_throttled = 0;
 	dl_se->dl_new = 1;
@@ -2684,7 +2710,7 @@
 		atomic_inc(&oldmm->mm_count);
 		enter_lazy_tlb(oldmm, next);
 	} else
-		switch_mm(oldmm, mm, next);
+		switch_mm_irqs_off(oldmm, mm, next);
 
 	if (!prev->mm) {
 		prev->active_mm = NULL;
@@ -3008,7 +3034,8 @@
 static inline void schedule_debug(struct task_struct *prev)
 {
 #ifdef CONFIG_SCHED_STACK_END_CHECK
-	BUG_ON(task_stack_end_corrupted(prev));
+	if (task_stack_end_corrupted(prev))
+		panic("corrupted stack end detected inside scheduler\n");
 #endif
 
 	if (unlikely(in_atomic_preempt_off())) {
@@ -3412,7 +3439,8 @@
 	if (dl_prio(prio)) {
 		struct task_struct *pi_task = rt_mutex_get_top_task(p);
 		if (!dl_prio(p->normal_prio) ||
-		    (pi_task && dl_entity_preempt(&pi_task->dl, &p->dl))) {
+		    (pi_task && dl_prio(pi_task->prio) &&
+		     dl_entity_preempt(&pi_task->dl, &p->dl))) {
 			p->dl.dl_boosted = 1;
 			enqueue_flag |= ENQUEUE_REPLENISH;
 		} else
@@ -3622,6 +3650,7 @@
 	dl_se->dl_period = attr->sched_period ?: dl_se->dl_deadline;
 	dl_se->flags = attr->sched_flags;
 	dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime);
+	dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime);
 
 	/*
 	 * Changing the parameters of a task is 'tricky' and we're not doing
@@ -3794,8 +3823,8 @@
 	struct rq *rq;
 	int reset_on_fork;
 
-	/* may grab non-irq protected spin_locks */
-	BUG_ON(in_interrupt());
+	/* The pi code expects interrupts enabled */
+	BUG_ON(pi && in_interrupt());
 recheck:
 	/* double check policy once rq lock held */
 	if (policy < 0) {
@@ -4950,14 +4979,16 @@
 		/*
 		 * reset the NMI-timeout, listing all files on a slow
 		 * console might take a lot of time:
+		 * Also, reset softlockup watchdogs on all CPUs, because
+		 * another CPU might be blocked waiting for us to process
+		 * an IPI.
 		 */
 		touch_nmi_watchdog();
+		touch_all_softlockup_watchdogs();
 		if (!state_filter || (p->state & state_filter))
 			sched_show_task(p);
 	}
 
-	touch_all_softlockup_watchdogs();
-
 #ifdef CONFIG_SCHED_DEBUG
 	sysrq_sched_debug_show();
 #endif
@@ -5591,6 +5622,14 @@
 		return NOTIFY_OK;
 
 	case CPU_ONLINE:
+#ifdef CONFIG_SCHED_SMT
+		/*
+		 * When going up, increment the number of cores with SMT
+		 * present.
+		 */
+		if (cpumask_weight(cpu_smt_mask(cpu)) == 2)
+			static_branch_inc(&sched_smt_present);
+#endif
 		/*
 		 * At this point a starting CPU has marked itself as online via
 		 * set_cpu_online(). But it might not yet have marked itself
@@ -5601,6 +5640,14 @@
 		return NOTIFY_OK;
 
 	case CPU_DOWN_FAILED:
+#ifdef CONFIG_SCHED_SMT
+		/*
+		 * Downing the CPU failed but we already decremented the number
+		 * of cores with SMT present so need to increment it again.
+		 */
+		if (cpumask_weight(cpu_smt_mask(cpu)) == 2)
+			static_branch_inc(&sched_smt_present);
+#endif
 		set_cpu_active(cpu, true);
 		return NOTIFY_OK;
 
@@ -5612,9 +5659,19 @@
 static int sched_cpu_inactive(struct notifier_block *nfb,
 					unsigned long action, void *hcpu)
 {
+	int cpu = (long)hcpu;
+
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_DOWN_PREPARE:
-		set_cpu_active((long)hcpu, false);
+#ifdef CONFIG_SCHED_SMT
+		/*
+		 * When going down, decrement the number of cores with SMT
+		 * present.
+		 */
+		if (cpumask_weight(cpu_smt_mask(cpu)) == 2)
+			static_branch_dec(&sched_smt_present);
+#endif
+		set_cpu_active(cpu, false);
 		return NOTIFY_OK;
 	default:
 		return NOTIFY_DONE;
@@ -5867,6 +5924,19 @@
 		call_rcu_sched(&old_rd->rcu, free_rootdomain);
 }
 
+void sched_get_rd(struct root_domain *rd)
+{
+	atomic_inc(&rd->refcount);
+}
+
+void sched_put_rd(struct root_domain *rd)
+{
+	if (!atomic_dec_and_test(&rd->refcount))
+		return;
+
+	call_rcu_sched(&rd->rcu, free_rootdomain);
+}
+
 static int init_rootdomain(struct root_domain *rd)
 {
 	memset(rd, 0, sizeof(*rd));
@@ -5880,6 +5950,12 @@
 	if (!zalloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
 		goto free_dlo_mask;
 
+#ifdef HAVE_RT_PUSH_IPI
+	rd->rto_cpu = -1;
+	raw_spin_lock_init(&rd->rto_lock);
+	init_irq_work(&rd->rto_push_work, rto_push_irq_work_func);
+#endif
+
 	init_dl_bw(&rd->dl_bw);
 	if (cpudl_init(&rd->cpudl) != 0)
 		goto free_dlo_mask;
@@ -6094,6 +6170,9 @@
  * Build an iteration mask that can exclude certain CPUs from the upwards
  * domain traversal.
  *
+ * Only CPUs that can arrive at this group should be considered to continue
+ * balancing.
+ *
  * Asymmetric node setups can result in situations where the domain tree is of
  * unequal depth, make sure to skip domains that already cover the entire
  * range.
@@ -6105,18 +6184,31 @@
  */
 static void build_group_mask(struct sched_domain *sd, struct sched_group *sg)
 {
-	const struct cpumask *span = sched_domain_span(sd);
+	const struct cpumask *sg_span = sched_group_cpus(sg);
 	struct sd_data *sdd = sd->private;
 	struct sched_domain *sibling;
 	int i;
 
-	for_each_cpu(i, span) {
+	for_each_cpu(i, sg_span) {
 		sibling = *per_cpu_ptr(sdd->sd, i);
-		if (!cpumask_test_cpu(i, sched_domain_span(sibling)))
+
+		/*
+		 * Can happen in the asymmetric case, where these siblings are
+		 * unused. The mask will not be empty because those CPUs that
+		 * do have the top domain _should_ span the domain.
+		 */
+		if (!sibling->child)
+			continue;
+
+		/* If we would not end up here, we can't continue from here */
+		if (!cpumask_equal(sg_span, sched_domain_span(sibling->child)))
 			continue;
 
 		cpumask_set_cpu(i, sched_group_mask(sg));
 	}
+
+	/* We must not have empty masks here */
+	WARN_ON_ONCE(cpumask_empty(sched_group_mask(sg)));
 }
 
 /*
@@ -6738,7 +6830,7 @@
 
 			sched_domains_numa_masks[i][j] = mask;
 
-			for (k = 0; k < nr_node_ids; k++) {
+			for_each_node(k) {
 				if (node_distance(j, k) > sched_domains_numa_distance[i])
 					continue;
 
@@ -7242,17 +7334,16 @@
 		 * 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);
+		partition_sched_domains(1, NULL, NULL);
+		if (--num_cpus_frozen)
 			break;
-		}
 
 		/*
 		 * This is the last CPU online operation. So fall through and
 		 * restore the original sched domains by considering the
 		 * cpuset configurations.
 		 */
+		cpuset_force_rebuild();
 
 	case CPU_ONLINE:
 		cpuset_update_active_cpus(true);
@@ -7433,6 +7524,7 @@
 #ifdef CONFIG_FAIR_GROUP_SCHED
 		root_task_group.shares = ROOT_TASK_GROUP_LOAD;
 		INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
+		rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
 		/*
 		 * How much cpu bandwidth does root_task_group get?
 		 *
@@ -7692,7 +7784,7 @@
 /* task_group_lock serializes the addition/removal of task groups */
 static DEFINE_SPINLOCK(task_group_lock);
 
-static void free_sched_group(struct task_group *tg)
+static void sched_free_group(struct task_group *tg)
 {
 	free_fair_sched_group(tg);
 	free_rt_sched_group(tg);
@@ -7718,7 +7810,7 @@
 	return tg;
 
 err:
-	free_sched_group(tg);
+	sched_free_group(tg);
 	return ERR_PTR(-ENOMEM);
 }
 
@@ -7738,27 +7830,24 @@
 }
 
 /* rcu callback to free various structures associated with a task group */
-static void free_sched_group_rcu(struct rcu_head *rhp)
+static void sched_free_group_rcu(struct rcu_head *rhp)
 {
 	/* now it should be safe to free those cfs_rqs */
-	free_sched_group(container_of(rhp, struct task_group, rcu));
+	sched_free_group(container_of(rhp, struct task_group, rcu));
 }
 
-/* Destroy runqueue etc associated with a task group */
 void sched_destroy_group(struct task_group *tg)
 {
 	/* wait for possible concurrent references to cfs_rqs complete */
-	call_rcu(&tg->rcu, free_sched_group_rcu);
+	call_rcu(&tg->rcu, sched_free_group_rcu);
 }
 
 void sched_offline_group(struct task_group *tg)
 {
 	unsigned long flags;
-	int i;
 
 	/* end participation in shares distribution */
-	for_each_possible_cpu(i)
-		unregister_fair_sched_group(tg, i);
+	unregister_fair_sched_group(tg);
 
 	spin_lock_irqsave(&task_group_lock, flags);
 	list_del_rcu(&tg->list);
@@ -8180,8 +8269,9 @@
 	/* make sure that internally we keep jiffies */
 	/* also, writing zero resets timeslice to default */
 	if (!ret && write) {
-		sched_rr_timeslice = sched_rr_timeslice <= 0 ?
-			RR_TIMESLICE : msecs_to_jiffies(sched_rr_timeslice);
+		sched_rr_timeslice =
+			sysctl_sched_rr_timeslice <= 0 ? RR_TIMESLICE :
+			msecs_to_jiffies(sysctl_sched_rr_timeslice);
 	}
 	mutex_unlock(&mutex);
 	return ret;
@@ -8212,6 +8302,7 @@
 	return &tg->css;
 }
 
+/* Expose task group only after completing cgroup initialization */
 static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
 {
 	struct task_group *tg = css_tg(css);
@@ -8222,18 +8313,21 @@
 	return 0;
 }
 
-static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
+static void cpu_cgroup_css_released(struct cgroup_subsys_state *css)
 {
 	struct task_group *tg = css_tg(css);
 
-	sched_destroy_group(tg);
+	sched_offline_group(tg);
 }
 
-static void cpu_cgroup_css_offline(struct cgroup_subsys_state *css)
+static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
 {
 	struct task_group *tg = css_tg(css);
 
-	sched_offline_group(tg);
+	/*
+	 * Relies on the RCU grace period between css_released() and this.
+	 */
+	sched_free_group(tg);
 }
 
 static void cpu_cgroup_fork(struct task_struct *task, void *private)
@@ -8250,10 +8344,6 @@
 #ifdef CONFIG_RT_GROUP_SCHED
 		if (!sched_rt_can_attach(css_tg(css), task))
 			return -EINVAL;
-#else
-		/* We don't support RT-tasks being in separate groups */
-		if (task->sched_class != &fair_sched_class)
-			return -EINVAL;
 #endif
 	}
 	return 0;
@@ -8272,6 +8362,8 @@
 static int cpu_shares_write_u64(struct cgroup_subsys_state *css,
 				struct cftype *cftype, u64 shareval)
 {
+	if (shareval > scale_load_down(ULONG_MAX))
+		shareval = MAX_SHARES;
 	return sched_group_set_shares(css_tg(css), scale_load(shareval));
 }
 
@@ -8371,8 +8463,10 @@
 	period = ktime_to_ns(tg->cfs_bandwidth.period);
 	if (cfs_quota_us < 0)
 		quota = RUNTIME_INF;
-	else
+	else if ((u64)cfs_quota_us <= U64_MAX / NSEC_PER_USEC)
 		quota = (u64)cfs_quota_us * NSEC_PER_USEC;
+	else
+		return -EINVAL;
 
 	return tg_set_cfs_bandwidth(tg, period, quota);
 }
@@ -8394,6 +8488,9 @@
 {
 	u64 quota, period;
 
+	if ((u64)cfs_period_us > U64_MAX / NSEC_PER_USEC)
+		return -EINVAL;
+
 	period = (u64)cfs_period_us * NSEC_PER_USEC;
 	quota = tg->cfs_bandwidth.quota;
 
@@ -8593,9 +8690,9 @@
 
 struct cgroup_subsys cpu_cgrp_subsys = {
 	.css_alloc	= cpu_cgroup_css_alloc,
-	.css_free	= cpu_cgroup_css_free,
 	.css_online	= cpu_cgroup_css_online,
-	.css_offline	= cpu_cgroup_css_offline,
+	.css_released	= cpu_cgroup_css_released,
+	.css_free	= cpu_cgroup_css_free,
 	.fork		= cpu_cgroup_fork,
 	.can_attach	= cpu_cgroup_can_attach,
 	.attach		= cpu_cgroup_attach,
--- linux-4.4.0.orig/kernel/sched/cpuacct.c
+++ linux-4.4.0/kernel/sched/cpuacct.c
@@ -235,23 +235,10 @@
 void cpuacct_charge(struct task_struct *tsk, u64 cputime)
 {
 	struct cpuacct *ca;
-	int cpu;
-
-	cpu = task_cpu(tsk);
 
 	rcu_read_lock();
-
-	ca = task_ca(tsk);
-
-	while (true) {
-		u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
-		*cpuusage += cputime;
-
-		ca = parent_ca(ca);
-		if (!ca)
-			break;
-	}
-
+	for (ca = task_ca(tsk); ca; ca = parent_ca(ca))
+		*this_cpu_ptr(ca->cpuusage) += cputime;
 	rcu_read_unlock();
 }
 
@@ -260,18 +247,13 @@
  *
  * Note: it's the caller that updates the account of the root cgroup.
  */
-void cpuacct_account_field(struct task_struct *p, int index, u64 val)
+void cpuacct_account_field(struct task_struct *tsk, int index, u64 val)
 {
-	struct kernel_cpustat *kcpustat;
 	struct cpuacct *ca;
 
 	rcu_read_lock();
-	ca = task_ca(p);
-	while (ca != &root_cpuacct) {
-		kcpustat = this_cpu_ptr(ca->cpustat);
-		kcpustat->cpustat[index] += val;
-		ca = parent_ca(ca);
-	}
+	for (ca = task_ca(tsk); ca != &root_cpuacct; ca = parent_ca(ca))
+		this_cpu_ptr(ca->cpustat)->cpustat[index] += val;
 	rcu_read_unlock();
 }
 
--- linux-4.4.0.orig/kernel/sched/cpuacct.h
+++ linux-4.4.0/kernel/sched/cpuacct.h
@@ -1,7 +1,7 @@
 #ifdef CONFIG_CGROUP_CPUACCT
 
 extern void cpuacct_charge(struct task_struct *tsk, u64 cputime);
-extern void cpuacct_account_field(struct task_struct *p, int index, u64 val);
+extern void cpuacct_account_field(struct task_struct *tsk, int index, u64 val);
 
 #else
 
@@ -10,7 +10,7 @@
 }
 
 static inline void
-cpuacct_account_field(struct task_struct *p, int index, u64 val)
+cpuacct_account_field(struct task_struct *tsk, int index, u64 val)
 {
 }
 
--- linux-4.4.0.orig/kernel/sched/cputime.c
+++ linux-4.4.0/kernel/sched/cputime.c
@@ -259,21 +259,21 @@
 #ifdef CONFIG_PARAVIRT
 	if (static_key_false(&paravirt_steal_enabled)) {
 		u64 steal;
-		cputime_t steal_ct;
+		unsigned long steal_jiffies;
 
 		steal = paravirt_steal_clock(smp_processor_id());
 		steal -= this_rq()->prev_steal_time;
 
 		/*
-		 * cputime_t may be less precise than nsecs (eg: if it's
-		 * based on jiffies). Lets cast the result to cputime
+		 * steal is in nsecs but our caller is expecting steal
+		 * time in jiffies. Lets cast the result to jiffies
 		 * granularity and account the rest on the next rounds.
 		 */
-		steal_ct = nsecs_to_cputime(steal);
-		this_rq()->prev_steal_time += cputime_to_nsecs(steal_ct);
+		steal_jiffies = nsecs_to_jiffies(steal);
+		this_rq()->prev_steal_time += jiffies_to_nsecs(steal_jiffies);
 
-		account_steal_time(steal_ct);
-		return steal_ct;
+		account_steal_time(jiffies_to_cputime(steal_jiffies));
+		return steal_jiffies;
 	}
 #endif
 	return false;
@@ -600,19 +600,25 @@
 	stime = curr->stime;
 	utime = curr->utime;
 
-	if (utime == 0) {
-		stime = rtime;
+	/*
+	 * If either stime or both stime and utime are 0, assume all runtime is
+	 * userspace. Once a task gets some ticks, the monotonicy code at
+	 * 'update' will ensure things converge to the observed ratio.
+	 */
+	if (stime == 0) {
+		utime = rtime;
 		goto update;
 	}
 
-	if (stime == 0) {
-		utime = rtime;
+	if (utime == 0) {
+		stime = rtime;
 		goto update;
 	}
 
 	stime = scale_stime((__force u64)stime, (__force u64)rtime,
 			    (__force u64)(stime + utime));
 
+update:
 	/*
 	 * Make sure stime doesn't go backwards; this preserves monotonicity
 	 * for utime because rtime is monotonic.
@@ -635,7 +641,6 @@
 		stime = rtime - utime;
 	}
 
-update:
 	prev->stime = stime;
 	prev->utime = utime;
 out:
--- linux-4.4.0.orig/kernel/sched/deadline.c
+++ linux-4.4.0/kernel/sched/deadline.c
@@ -441,13 +441,13 @@
  *
  * This function returns true if:
  *
- *   runtime / (deadline - t) > dl_runtime / dl_period ,
+ *   runtime / (deadline - t) > dl_runtime / dl_deadline ,
  *
  * IOW we can't recycle current parameters.
  *
- * Notice that the bandwidth check is done against the period. For
+ * Notice that the bandwidth check is done against the deadline. For
  * task with deadline equal to period this is the same of using
- * dl_deadline instead of dl_period in the equation above.
+ * dl_period instead of dl_deadline in the equation above.
  */
 static bool dl_entity_overflow(struct sched_dl_entity *dl_se,
 			       struct sched_dl_entity *pi_se, u64 t)
@@ -472,7 +472,7 @@
 	 * of anything below microseconds resolution is actually fiction
 	 * (but still we want to give the user that illusion >;).
 	 */
-	left = (pi_se->dl_period >> DL_SCALE) * (dl_se->runtime >> DL_SCALE);
+	left = (pi_se->dl_deadline >> DL_SCALE) * (dl_se->runtime >> DL_SCALE);
 	right = ((dl_se->deadline - t) >> DL_SCALE) *
 		(pi_se->dl_runtime >> DL_SCALE);
 
@@ -480,13 +480,84 @@
 }
 
 /*
- * When a -deadline entity is queued back on the runqueue, its runtime and
- * deadline might need updating.
+ * Revised wakeup rule [1]: For self-suspending tasks, rather then
+ * re-initializing task's runtime and deadline, the revised wakeup
+ * rule adjusts the task's runtime to avoid the task to overrun its
+ * density.
  *
- * The policy here is that we update the deadline of the entity only if:
- *  - the current deadline is in the past,
- *  - using the remaining runtime with the current deadline would make
- *    the entity exceed its bandwidth.
+ * Reasoning: a task may overrun the density if:
+ *    runtime / (deadline - t) > dl_runtime / dl_deadline
+ *
+ * Therefore, runtime can be adjusted to:
+ *     runtime = (dl_runtime / dl_deadline) * (deadline - t)
+ *
+ * In such way that runtime will be equal to the maximum density
+ * the task can use without breaking any rule.
+ *
+ * [1] Luca Abeni, Giuseppe Lipari, and Juri Lelli. 2015. Constant
+ * bandwidth server revisited. SIGBED Rev. 11, 4 (January 2015), 19-24.
+ */
+static void
+update_dl_revised_wakeup(struct sched_dl_entity *dl_se, struct rq *rq)
+{
+	u64 laxity = dl_se->deadline - rq_clock(rq);
+
+	/*
+	 * If the task has deadline < period, and the deadline is in the past,
+	 * it should already be throttled before this check.
+	 *
+	 * See update_dl_entity() comments for further details.
+	 */
+	WARN_ON(dl_time_before(dl_se->deadline, rq_clock(rq)));
+
+	dl_se->runtime = (dl_se->dl_density * laxity) >> 20;
+}
+
+/*
+ * Regarding the deadline, a task with implicit deadline has a relative
+ * deadline == relative period. A task with constrained deadline has a
+ * relative deadline <= relative period.
+ *
+ * We support constrained deadline tasks. However, there are some restrictions
+ * applied only for tasks which do not have an implicit deadline. See
+ * update_dl_entity() to know more about such restrictions.
+ *
+ * The dl_is_implicit() returns true if the task has an implicit deadline.
+ */
+static inline bool dl_is_implicit(struct sched_dl_entity *dl_se)
+{
+	return dl_se->dl_deadline == dl_se->dl_period;
+}
+
+/*
+ * When a deadline entity is placed in the runqueue, its runtime and deadline
+ * might need to be updated. This is done by a CBS wake up rule. There are two
+ * different rules: 1) the original CBS; and 2) the Revisited CBS.
+ *
+ * When the task is starting a new period, the Original CBS is used. In this
+ * case, the runtime is replenished and a new absolute deadline is set.
+ *
+ * When a task is queued before the begin of the next period, using the
+ * remaining runtime and deadline could make the entity to overflow, see
+ * dl_entity_overflow() to find more about runtime overflow. When such case
+ * is detected, the runtime and deadline need to be updated.
+ *
+ * If the task has an implicit deadline, i.e., deadline == period, the Original
+ * CBS is applied. the runtime is replenished and a new absolute deadline is
+ * set, as in the previous cases.
+ *
+ * However, the Original CBS does not work properly for tasks with
+ * deadline < period, which are said to have a constrained deadline. By
+ * applying the Original CBS, a constrained deadline task would be able to run
+ * runtime/deadline in a period. With deadline < period, the task would
+ * overrun the runtime/period allowed bandwidth, breaking the admission test.
+ *
+ * In order to prevent this misbehave, the Revisited CBS is used for
+ * constrained deadline tasks when a runtime overflow is detected. In the
+ * Revisited CBS, rather than replenishing & setting a new absolute deadline,
+ * the remaining runtime of the task is reduced to avoid runtime overflow.
+ * Please refer to the comments update_dl_revised_wakeup() function to find
+ * more about the Revised CBS rule.
  */
 static void update_dl_entity(struct sched_dl_entity *dl_se,
 			     struct sched_dl_entity *pi_se)
@@ -505,15 +576,28 @@
 
 	if (dl_time_before(dl_se->deadline, rq_clock(rq)) ||
 	    dl_entity_overflow(dl_se, pi_se, rq_clock(rq))) {
+
+		if (unlikely(!dl_is_implicit(dl_se) &&
+			     !dl_time_before(dl_se->deadline, rq_clock(rq)) &&
+			     !dl_se->dl_boosted)){
+			update_dl_revised_wakeup(dl_se, rq);
+			return;
+		}
+
 		dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline;
 		dl_se->runtime = pi_se->dl_runtime;
 	}
 }
 
+static inline u64 dl_next_period(struct sched_dl_entity *dl_se)
+{
+	return dl_se->deadline - dl_se->dl_deadline + dl_se->dl_period;
+}
+
 /*
  * If the entity depleted all its runtime, and if we want it to sleep
  * while waiting for some new execution time to become available, we
- * set the bandwidth enforcement timer to the replenishment instant
+ * set the bandwidth replenishment timer to the replenishment instant
  * and try to activate it.
  *
  * Notice that it is important for the caller to know if the timer
@@ -535,7 +619,7 @@
 	 * that it is actually coming from rq->clock and not from
 	 * hrtimer's time base reading.
 	 */
-	act = ns_to_ktime(dl_se->deadline);
+	act = ns_to_ktime(dl_next_period(dl_se));
 	now = hrtimer_cb_get_time(timer);
 	delta = ktime_to_ns(now) - rq_clock(rq);
 	act = ktime_add_ns(act, delta);
@@ -699,6 +783,39 @@
 	timer->function = dl_task_timer;
 }
 
+/*
+ * During the activation, CBS checks if it can reuse the current task's
+ * runtime and period. If the deadline of the task is in the past, CBS
+ * cannot use the runtime, and so it replenishes the task. This rule
+ * works fine for implicit deadline tasks (deadline == period), and the
+ * CBS was designed for implicit deadline tasks. However, a task with
+ * constrained deadline (deadine < period) might be awakened after the
+ * deadline, but before the next period. In this case, replenishing the
+ * task would allow it to run for runtime / deadline. As in this case
+ * deadline < period, CBS enables a task to run for more than the
+ * runtime / period. In a very loaded system, this can cause a domino
+ * effect, making other tasks miss their deadlines.
+ *
+ * To avoid this problem, in the activation of a constrained deadline
+ * task after the deadline but before the next period, throttle the
+ * task and set the replenishing timer to the begin of the next period,
+ * unless it is boosted.
+ */
+static inline void dl_check_constrained_dl(struct sched_dl_entity *dl_se)
+{
+	struct task_struct *p = dl_task_of(dl_se);
+	struct rq *rq = rq_of_dl_rq(dl_rq_of_se(dl_se));
+
+	if (dl_time_before(dl_se->deadline, rq_clock(rq)) &&
+	    dl_time_before(rq_clock(rq), dl_next_period(dl_se))) {
+		if (unlikely(dl_se->dl_boosted || !start_dl_timer(p)))
+			return;
+		dl_se->dl_throttled = 1;
+		if (dl_se->runtime > 0)
+			dl_se->runtime = 0;
+	}
+}
+
 static
 int dl_runtime_exceeded(struct sched_dl_entity *dl_se)
 {
@@ -979,6 +1096,15 @@
 	}
 
 	/*
+	 * Check if a constrained deadline task was activated
+	 * after the deadline but before the next period.
+	 * If that is the case, the task will be throttled and
+	 * the replenishment timer will be set to the next period.
+	 */
+	if (!p->dl.dl_throttled && !dl_is_implicit(&p->dl))
+		dl_check_constrained_dl(&p->dl);
+
+	/*
 	 * If p is throttled, we do nothing. In fact, if it exhausted
 	 * its budget it needs a replenishment and, since it now is on
 	 * its rq, the bandwidth timer callback (which clearly has not
@@ -1771,12 +1897,11 @@
 #ifdef CONFIG_SMP
 		if (p->nr_cpus_allowed > 1 && rq->dl.overloaded)
 			queue_push_tasks(rq);
-#else
+#endif
 		if (dl_task(rq->curr))
 			check_preempt_curr_dl(rq, p, 0);
 		else
 			resched_curr(rq);
-#endif
 	}
 }
 
--- linux-4.4.0.orig/kernel/sched/fair.c
+++ linux-4.4.0/kernel/sched/fair.c
@@ -283,39 +283,103 @@
 	return grp->my_q;
 }
 
-static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
+static inline bool list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
 {
-	if (!cfs_rq->on_list) {
+	struct rq *rq = rq_of(cfs_rq);
+	int cpu = cpu_of(rq);
+
+	if (cfs_rq->on_list)
+		return rq->tmp_alone_branch == &rq->leaf_cfs_rq_list;
+
+	cfs_rq->on_list = 1;
+
+	/*
+	 * Ensure we either appear before our parent (if already
+	 * enqueued) or force our parent to appear after us when it is
+	 * enqueued. The fact that we always enqueue bottom-up
+	 * reduces this to two cases and a special case for the root
+	 * cfs_rq. Furthermore, it also means that we will always reset
+	 * tmp_alone_branch either when the branch is connected
+	 * to a tree or when we reach the top of the tree
+	 */
+	if (cfs_rq->tg->parent &&
+	    cfs_rq->tg->parent->cfs_rq[cpu]->on_list) {
 		/*
-		 * Ensure we either appear before our parent (if already
-		 * enqueued) or force our parent to appear after us when it is
-		 * enqueued.  The fact that we always enqueue bottom-up
-		 * reduces this to two cases.
-		 */
-		if (cfs_rq->tg->parent &&
-		    cfs_rq->tg->parent->cfs_rq[cpu_of(rq_of(cfs_rq))]->on_list) {
-			list_add_rcu(&cfs_rq->leaf_cfs_rq_list,
-				&rq_of(cfs_rq)->leaf_cfs_rq_list);
-		} else {
-			list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
-				&rq_of(cfs_rq)->leaf_cfs_rq_list);
-		}
+		 * If parent is already on the list, we add the child
+		 * just before. Thanks to circular linked property of
+		 * the list, this means to put the child at the tail
+		 * of the list that starts by parent.
+		 */
+		list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
+			&(cfs_rq->tg->parent->cfs_rq[cpu]->leaf_cfs_rq_list));
+		/*
+		 * The branch is now connected to its tree so we can
+		 * reset tmp_alone_branch to the beginning of the
+		 * list.
+		 */
+		rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
+		return true;
+	}
 
-		cfs_rq->on_list = 1;
+	if (!cfs_rq->tg->parent) {
+		/*
+		 * cfs rq without parent should be put
+		 * at the tail of the list.
+		 */
+		list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
+			&rq->leaf_cfs_rq_list);
+		/*
+		 * We have reach the top of a tree so we can reset
+		 * tmp_alone_branch to the beginning of the list.
+		 */
+		rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
+		return true;
 	}
+
+	/*
+	 * The parent has not already been added so we want to
+	 * make sure that it will be put after us.
+	 * tmp_alone_branch points to the begin of the branch
+	 * where we will add parent.
+	 */
+	list_add_rcu(&cfs_rq->leaf_cfs_rq_list, rq->tmp_alone_branch);
+	/*
+	 * update tmp_alone_branch to points to the new begin
+	 * of the branch
+	 */
+	rq->tmp_alone_branch = &cfs_rq->leaf_cfs_rq_list;
+	return false;
 }
 
 static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
 {
 	if (cfs_rq->on_list) {
+		struct rq *rq = rq_of(cfs_rq);
+
+		/*
+		 * With cfs_rq being unthrottled/throttled during an enqueue,
+		 * it can happen the tmp_alone_branch points the a leaf that
+		 * we finally want to del. In this case, tmp_alone_branch moves
+		 * to the prev element but it will point to rq->leaf_cfs_rq_list
+		 * at the end of the enqueue.
+		 */
+		if (rq->tmp_alone_branch == &cfs_rq->leaf_cfs_rq_list)
+			rq->tmp_alone_branch = cfs_rq->leaf_cfs_rq_list.prev;
+
 		list_del_rcu(&cfs_rq->leaf_cfs_rq_list);
 		cfs_rq->on_list = 0;
 	}
 }
 
+static inline void assert_list_leaf_cfs_rq(struct rq *rq)
+{
+	WARN_ON_ONCE((rq->tmp_alone_branch != &rq->leaf_cfs_rq_list));
+}
+
 /* Iterate thr' all leaf cfs_rq's on a runqueue */
-#define for_each_leaf_cfs_rq(rq, cfs_rq) \
-	list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
+#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos)			\
+	list_for_each_entry_safe(cfs_rq, pos, &rq->leaf_cfs_rq_list,	\
+				 leaf_cfs_rq_list)
 
 /* Do the two (enqueued) entities belong to the same group ? */
 static inline struct cfs_rq *
@@ -400,16 +464,21 @@
 	return NULL;
 }
 
-static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
+static inline bool list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
 {
+	return true;
 }
 
 static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
 {
 }
 
-#define for_each_leaf_cfs_rq(rq, cfs_rq) \
-		for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
+static inline void assert_list_leaf_cfs_rq(struct rq *rq)
+{
+}
+
+#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos)	\
+		for (cfs_rq = &rq->cfs, pos = NULL; cfs_rq; cfs_rq = pos)
 
 static inline struct sched_entity *parent_entity(struct sched_entity *se)
 {
@@ -687,8 +756,6 @@
 	/* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */
 }
 
-static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq);
-static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq);
 #else
 void init_entity_runnable_average(struct sched_entity *se)
 {
@@ -1193,8 +1260,6 @@
 {
 	if (env->best_task)
 		put_task_struct(env->best_task);
-	if (p)
-		get_task_struct(p);
 
 	env->best_task = p;
 	env->best_imp = imp;
@@ -1262,20 +1327,30 @@
 	long imp = env->p->numa_group ? groupimp : taskimp;
 	long moveimp = imp;
 	int dist = env->dist;
+	bool assigned = false;
 
 	rcu_read_lock();
 
 	raw_spin_lock_irq(&dst_rq->lock);
 	cur = dst_rq->curr;
 	/*
-	 * No need to move the exiting task, and this ensures that ->curr
-	 * wasn't reaped and thus get_task_struct() in task_numa_assign()
-	 * is safe under RCU read lock.
-	 * Note that rcu_read_lock() itself can't protect from the final
-	 * put_task_struct() after the last schedule().
+	 * No need to move the exiting task or idle task.
 	 */
 	if ((cur->flags & PF_EXITING) || is_idle_task(cur))
 		cur = NULL;
+	else {
+		/*
+		 * The task_struct must be protected here to protect the
+		 * p->numa_faults access in the task_weight since the
+		 * numa_faults could already be freed in the following path:
+		 * finish_task_switch()
+		 *     --> put_task_struct()
+		 *         --> __put_task_struct()
+		 *             --> task_numa_free()
+		 */
+		get_task_struct(cur);
+	}
+
 	raw_spin_unlock_irq(&dst_rq->lock);
 
 	/*
@@ -1359,6 +1434,7 @@
 		 */
 		if (!load_too_imbalanced(src_load, dst_load, env)) {
 			imp = moveimp - 1;
+			put_task_struct(cur);
 			cur = NULL;
 			goto assign;
 		}
@@ -1384,9 +1460,16 @@
 		env->dst_cpu = select_idle_sibling(env->p, env->dst_cpu);
 
 assign:
+	assigned = true;
 	task_numa_assign(env, cur, imp);
 unlock:
 	rcu_read_unlock();
+	/*
+	 * The dst_rq->curr isn't assigned. The protection for task_struct is
+	 * finished.
+	 */
+	if (cur && !assigned)
+		put_task_struct(cur);
 }
 
 static void task_numa_find_cpu(struct task_numa_env *env,
@@ -1708,6 +1791,10 @@
 	if (p->last_task_numa_placement) {
 		delta = runtime - p->last_sum_exec_runtime;
 		*period = now - p->last_task_numa_placement;
+
+		/* Avoid time going backwards, prevent potential divide error: */
+		if (unlikely((s64)*period < 0))
+			*period = 0;
 	} else {
 		delta = p->se.avg.load_sum / p->se.load.weight;
 		*period = LOAD_AVG_MAX;
@@ -2036,13 +2123,23 @@
 	return;
 }
 
-void task_numa_free(struct task_struct *p)
+/*
+ * Get rid of NUMA staticstics associated with a task (either current or dead).
+ * If @final is set, the task is dead and has reached refcount zero, so we can
+ * safely free all relevant data structures. Otherwise, there might be
+ * concurrent reads from places like load balancing and procfs, and we should
+ * reset the data back to default state without freeing ->numa_faults.
+ */
+void task_numa_free(struct task_struct *p, bool final)
 {
 	struct numa_group *grp = p->numa_group;
-	void *numa_faults = p->numa_faults;
+	unsigned long *numa_faults = p->numa_faults;
 	unsigned long flags;
 	int i;
 
+	if (!numa_faults)
+		return;
+
 	if (grp) {
 		spin_lock_irqsave(&grp->lock, flags);
 		for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
@@ -2055,8 +2152,14 @@
 		put_numa_group(grp);
 	}
 
-	p->numa_faults = NULL;
-	kfree(numa_faults);
+	if (final) {
+		p->numa_faults = NULL;
+		kfree(numa_faults);
+	} else {
+		p->total_numa_faults = 0;
+		for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
+			numa_faults[i] = 0;
+	}
 }
 
 /*
@@ -2209,7 +2312,8 @@
 		return;
 
 
-	down_read(&mm->mmap_sem);
+	if (!down_read_trylock(&mm->mmap_sem))
+		return;
 	vma = find_vma(mm, start);
 	if (!vma) {
 		reset_ptenuma_scan(p);
@@ -2290,7 +2394,7 @@
 	/*
 	 * We don't care about NUMA placement if we don't have memory.
 	 */
-	if (!curr->mm || (curr->flags & PF_EXITING) || work->next != work)
+	if ((curr->flags & (PF_EXITING | PF_KTHREAD)) || work->next != work)
 		return;
 
 	/*
@@ -2359,28 +2463,22 @@
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 # ifdef CONFIG_SMP
-static inline long calc_tg_weight(struct task_group *tg, struct cfs_rq *cfs_rq)
+static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
 {
-	long tg_weight;
+	long tg_weight, load, shares;
 
 	/*
-	 * Use this CPU's real-time load instead of the last load contribution
-	 * as the updating of the contribution is delayed, and we will use the
-	 * the real-time load to calc the share. See update_tg_load_avg().
+	 * This really should be: cfs_rq->avg.load_avg, but instead we use
+	 * cfs_rq->load.weight, which is its upper bound. This helps ramp up
+	 * the shares for small weight interactive tasks.
 	 */
-	tg_weight = atomic_long_read(&tg->load_avg);
-	tg_weight -= cfs_rq->tg_load_avg_contrib;
-	tg_weight += cfs_rq->load.weight;
+	load = scale_load_down(cfs_rq->load.weight);
 
-	return tg_weight;
-}
-
-static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
-{
-	long tg_weight, load, shares;
+	tg_weight = atomic_long_read(&tg->load_avg);
 
-	tg_weight = calc_tg_weight(tg, cfs_rq);
-	load = cfs_rq->load.weight;
+	/* Ensure tg_weight >= load */
+	tg_weight -= cfs_rq->tg_load_avg_contrib;
+	tg_weight += load;
 
 	shares = (tg->shares * load);
 	if (tg_weight)
@@ -2399,6 +2497,7 @@
 	return tg->shares;
 }
 # endif /* CONFIG_SMP */
+
 static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
 			    unsigned long weight)
 {
@@ -2682,6 +2781,23 @@
 
 static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq);
 
+/*
+ * Unsigned subtract and clamp on underflow.
+ *
+ * Explicitly do a load-store to ensure the intermediate value never hits
+ * memory. This allows lockless observations without ever seeing the negative
+ * values.
+ */
+#define sub_positive(_ptr, _val) do {				\
+	typeof(_ptr) ptr = (_ptr);				\
+	typeof(*ptr) val = (_val);				\
+	typeof(*ptr) res, var = READ_ONCE(*ptr);		\
+	res = var - val;					\
+	if (res > var)						\
+		res = 0;					\
+	WRITE_ONCE(*ptr, res);					\
+} while (0)
+
 /* Group cfs_rq's load_avg is used for task_h_load and update_cfs_share */
 static inline int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
 {
@@ -2690,15 +2806,15 @@
 
 	if (atomic_long_read(&cfs_rq->removed_load_avg)) {
 		s64 r = atomic_long_xchg(&cfs_rq->removed_load_avg, 0);
-		sa->load_avg = max_t(long, sa->load_avg - r, 0);
-		sa->load_sum = max_t(s64, sa->load_sum - r * LOAD_AVG_MAX, 0);
+		sub_positive(&sa->load_avg, r);
+		sub_positive(&sa->load_sum, r * LOAD_AVG_MAX);
 		removed = 1;
 	}
 
 	if (atomic_long_read(&cfs_rq->removed_util_avg)) {
 		long r = atomic_long_xchg(&cfs_rq->removed_util_avg, 0);
-		sa->util_avg = max_t(long, sa->util_avg - r, 0);
-		sa->util_sum = max_t(s32, sa->util_sum - r * LOAD_AVG_MAX, 0);
+		sub_positive(&sa->util_avg, r);
+		sub_positive(&sa->util_sum, r * LOAD_AVG_MAX);
 	}
 
 	decayed = __update_load_avg(now, cpu_of(rq_of(cfs_rq)), sa,
@@ -2764,10 +2880,10 @@
 			  &se->avg, se->on_rq * scale_load_down(se->load.weight),
 			  cfs_rq->curr == se, NULL);
 
-	cfs_rq->avg.load_avg = max_t(long, cfs_rq->avg.load_avg - se->avg.load_avg, 0);
-	cfs_rq->avg.load_sum = max_t(s64,  cfs_rq->avg.load_sum - se->avg.load_sum, 0);
-	cfs_rq->avg.util_avg = max_t(long, cfs_rq->avg.util_avg - se->avg.util_avg, 0);
-	cfs_rq->avg.util_sum = max_t(s32,  cfs_rq->avg.util_sum - se->avg.util_sum, 0);
+	sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg);
+	sub_positive(&cfs_rq->avg.load_sum, se->avg.load_sum);
+	sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg);
+	sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum);
 }
 
 /* Add the load generated by se into cfs_rq's load average */
@@ -2809,27 +2925,45 @@
 		max_t(s64,  cfs_rq->runnable_load_sum - se->avg.load_sum, 0);
 }
 
-/*
- * Task first catches up with cfs_rq, and then subtract
- * itself from the cfs_rq (task must be off the queue now).
- */
-void remove_entity_load_avg(struct sched_entity *se)
-{
-	struct cfs_rq *cfs_rq = cfs_rq_of(se);
-	u64 last_update_time;
-
 #ifndef CONFIG_64BIT
+static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
+{
 	u64 last_update_time_copy;
+	u64 last_update_time;
 
 	do {
 		last_update_time_copy = cfs_rq->load_last_update_time_copy;
 		smp_rmb();
 		last_update_time = cfs_rq->avg.last_update_time;
 	} while (last_update_time != last_update_time_copy);
+
+	return last_update_time;
+}
 #else
-	last_update_time = cfs_rq->avg.last_update_time;
+static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
+{
+	return cfs_rq->avg.last_update_time;
+}
 #endif
 
+/*
+ * Task first catches up with cfs_rq, and then subtract
+ * itself from the cfs_rq (task must be off the queue now).
+ */
+void remove_entity_load_avg(struct sched_entity *se)
+{
+	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+	u64 last_update_time;
+
+	/*
+	 * Newly created task or never used group entity should not be removed
+	 * from its (source) cfs_rq
+	 */
+	if (se->avg.last_update_time == 0)
+		return;
+
+	last_update_time = cfs_rq_last_update_time(cfs_rq);
+
 	__update_load_avg(last_update_time, cpu_of(rq_of(cfs_rq)), &se->avg, 0, 0, NULL);
 	atomic_long_add(se->avg.load_avg, &cfs_rq->removed_load_avg);
 	atomic_long_add(se->avg.util_avg, &cfs_rq->removed_util_avg);
@@ -3533,6 +3667,10 @@
 		/* adjust cfs_rq_clock_task() */
 		cfs_rq->throttled_clock_task_time += rq_clock_task(rq) -
 					     cfs_rq->throttled_clock_task;
+
+		/* Add cfs_rq with already running entity in the list */
+		if (cfs_rq->nr_running >= 1)
+			list_add_leaf_cfs_rq(cfs_rq);
 	}
 #endif
 
@@ -3545,8 +3683,10 @@
 	struct cfs_rq *cfs_rq = tg->cfs_rq[cpu_of(rq)];
 
 	/* group is entering throttled state, stop time */
-	if (!cfs_rq->throttle_count)
+	if (!cfs_rq->throttle_count) {
 		cfs_rq->throttled_clock_task = rq_clock_task(rq);
+		list_del_leaf_cfs_rq(cfs_rq);
+	}
 	cfs_rq->throttle_count++;
 
 	return 0;
@@ -3592,9 +3732,13 @@
 
 	/*
 	 * Add to the _head_ of the list, so that an already-started
-	 * distribute_cfs_runtime will not see us
+	 * distribute_cfs_runtime will not see us. If disribute_cfs_runtime is
+	 * not running add to the tail so that later runqueues don't get starved.
 	 */
-	list_add_rcu(&cfs_rq->throttled_list, &cfs_b->throttled_cfs_rq);
+	if (cfs_b->distribute_running)
+		list_add_rcu(&cfs_rq->throttled_list, &cfs_b->throttled_cfs_rq);
+	else
+		list_add_tail_rcu(&cfs_rq->throttled_list, &cfs_b->throttled_cfs_rq);
 
 	/*
 	 * If we're the first throttled task, make sure the bandwidth
@@ -3645,6 +3789,8 @@
 			break;
 	}
 
+	assert_list_leaf_cfs_rq(rq);
+
 	if (!se)
 		add_nr_running(rq, task_delta);
 
@@ -3737,14 +3883,16 @@
 	 * in us over-using our runtime if it is all used during this loop, but
 	 * only by limited amounts in that extreme case.
 	 */
-	while (throttled && cfs_b->runtime > 0) {
+	while (throttled && cfs_b->runtime > 0 && !cfs_b->distribute_running) {
 		runtime = cfs_b->runtime;
+		cfs_b->distribute_running = 1;
 		raw_spin_unlock(&cfs_b->lock);
 		/* we can't nest cfs_b->lock while distributing bandwidth */
 		runtime = distribute_cfs_runtime(cfs_b, runtime,
 						 runtime_expires);
 		raw_spin_lock(&cfs_b->lock);
 
+		cfs_b->distribute_running = 0;
 		throttled = !list_empty(&cfs_b->throttled_cfs_rq);
 
 		cfs_b->runtime -= min(runtime, cfs_b->runtime);
@@ -3855,6 +4003,11 @@
 
 	/* confirm we're still not at a refresh boundary */
 	raw_spin_lock(&cfs_b->lock);
+	if (cfs_b->distribute_running) {
+		raw_spin_unlock(&cfs_b->lock);
+		return;
+	}
+
 	if (runtime_refresh_within(cfs_b, min_bandwidth_expiration)) {
 		raw_spin_unlock(&cfs_b->lock);
 		return;
@@ -3864,6 +4017,9 @@
 		runtime = cfs_b->runtime;
 
 	expires = cfs_b->runtime_expires;
+	if (runtime)
+		cfs_b->distribute_running = 1;
+
 	raw_spin_unlock(&cfs_b->lock);
 
 	if (!runtime)
@@ -3874,6 +4030,7 @@
 	raw_spin_lock(&cfs_b->lock);
 	if (expires == cfs_b->runtime_expires)
 		cfs_b->runtime -= min(runtime, cfs_b->runtime);
+	cfs_b->distribute_running = 0;
 	raw_spin_unlock(&cfs_b->lock);
 }
 
@@ -3887,6 +4044,26 @@
 	if (!cfs_bandwidth_used())
 		return;
 
+	/* Synchronize hierarchical throttle counter: */
+	if (unlikely(!cfs_rq->throttle_uptodate)) {
+		struct rq *rq = rq_of(cfs_rq);
+		struct cfs_rq *pcfs_rq;
+		struct task_group *tg;
+
+		cfs_rq->throttle_uptodate = 1;
+
+		/* Get closest up-to-date node, because leaves go first: */
+		for (tg = cfs_rq->tg->parent; tg; tg = tg->parent) {
+			pcfs_rq = tg->cfs_rq[cpu_of(rq)];
+			if (pcfs_rq->throttle_uptodate)
+				break;
+		}
+		if (tg) {
+			cfs_rq->throttle_count = pcfs_rq->throttle_count;
+			cfs_rq->throttled_clock_task = rq_clock_task(rq);
+		}
+	}
+
 	/* an active group must be handled by the update_curr()->put() path */
 	if (!cfs_rq->runtime_enabled || cfs_rq->curr)
 		return;
@@ -3931,12 +4108,15 @@
 	return HRTIMER_NORESTART;
 }
 
+extern const u64 max_cfs_quota_period;
+
 static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer)
 {
 	struct cfs_bandwidth *cfs_b =
 		container_of(timer, struct cfs_bandwidth, period_timer);
 	int overrun;
 	int idle = 0;
+	int count = 0;
 
 	raw_spin_lock(&cfs_b->lock);
 	for (;;) {
@@ -3944,6 +4124,36 @@
 		if (!overrun)
 			break;
 
+		if (++count > 3) {
+			u64 new, old = ktime_to_ns(cfs_b->period);
+
+			/*
+			 * Grow period by a factor of 2 to avoid losing precision.
+			 * Precision loss in the quota/period ratio can cause __cfs_schedulable
+			 * to fail.
+			 */
+			new = old * 2;
+			if (new < max_cfs_quota_period) {
+				cfs_b->period = ns_to_ktime(new);
+				cfs_b->quota *= 2;
+
+				pr_warn_ratelimited(
+	"cfs_period_timer[cpu%d]: period too short, scaling up (new cfs_period_us = %lld, cfs_quota_us = %lld)\n",
+					smp_processor_id(),
+					div_u64(new, NSEC_PER_USEC),
+					div_u64(cfs_b->quota, NSEC_PER_USEC));
+			} else {
+				pr_warn_ratelimited(
+	"cfs_period_timer[cpu%d]: period too short, but cannot scale up without losing precision (cfs_period_us = %lld, cfs_quota_us = %lld)\n",
+					smp_processor_id(),
+					div_u64(old, NSEC_PER_USEC),
+					div_u64(cfs_b->quota, NSEC_PER_USEC));
+			}
+
+			/* reset count so we don't come right back in here */
+			count = 0;
+		}
+
 		idle = do_sched_cfs_period_timer(cfs_b, overrun);
 	}
 	if (idle)
@@ -3965,6 +4175,7 @@
 	cfs_b->period_timer.function = sched_cfs_period_timer;
 	hrtimer_init(&cfs_b->slack_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	cfs_b->slack_timer.function = sched_cfs_slack_timer;
+	cfs_b->distribute_running = 0;
 }
 
 static void init_cfs_rq_runtime(struct cfs_rq *cfs_rq)
@@ -3996,9 +4207,9 @@
 
 static void __maybe_unused update_runtime_enabled(struct rq *rq)
 {
-	struct cfs_rq *cfs_rq;
+	struct cfs_rq *cfs_rq, *pos;
 
-	for_each_leaf_cfs_rq(rq, cfs_rq) {
+	for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) {
 		struct cfs_bandwidth *cfs_b = &cfs_rq->tg->cfs_bandwidth;
 
 		raw_spin_lock(&cfs_b->lock);
@@ -4009,9 +4220,9 @@
 
 static void __maybe_unused unthrottle_offline_cfs_rqs(struct rq *rq)
 {
-	struct cfs_rq *cfs_rq;
+	struct cfs_rq *cfs_rq, *pos;
 
-	for_each_leaf_cfs_rq(rq, cfs_rq) {
+	for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) {
 		if (!cfs_rq->runtime_enabled)
 			continue;
 
@@ -4032,6 +4243,12 @@
 }
 
 #else /* CONFIG_CFS_BANDWIDTH */
+
+static inline bool cfs_bandwidth_used(void)
+{
+	return false;
+}
+
 static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq)
 {
 	return rq_clock_task(rq_of(cfs_rq));
@@ -4202,15 +4419,14 @@
 
 		/* Don't dequeue parent if it has other entities besides us */
 		if (cfs_rq->load.weight) {
+			/* Avoid re-evaluating load for this entity: */
+			se = parent_entity(se);
 			/*
 			 * Bias pick_next to pick a task from this cfs_rq, as
 			 * p is sleeping when it is within its sched_slice.
 			 */
-			if (task_sleep && parent_entity(se))
-				set_next_buddy(parent_entity(se));
-
-			/* avoid re-evaluating load for this entity */
-			se = parent_entity(se);
+			if (task_sleep && se && !throttled_hierarchy(cfs_rq))
+				set_next_buddy(se);
 			break;
 		}
 		flags |= DEQUEUE_SLEEP;
@@ -4230,6 +4446,23 @@
 	if (!se)
 		sub_nr_running(rq, 1);
 
+	if (cfs_bandwidth_used()) {
+		/*
+		 * When bandwidth control is enabled; the cfs_rq_throttled()
+		 * breaks in the above iteration can result in incomplete
+		 * leaf list maintenance, resulting in triggering the assertion
+		 * below.
+		 */
+		for_each_sched_entity(se) {
+			cfs_rq = cfs_rq_of(se);
+
+			if (list_add_leaf_cfs_rq(cfs_rq))
+				break;
+		}
+	}
+
+	assert_list_leaf_cfs_rq(rq);
+
 	hrtick_update(rq);
 }
 
@@ -4577,19 +4810,24 @@
 		return wl;
 
 	for_each_sched_entity(se) {
-		long w, W;
+		struct cfs_rq *cfs_rq = se->my_q;
+		long W, w = cfs_rq_load_avg(cfs_rq);
 
-		tg = se->my_q->tg;
+		tg = cfs_rq->tg;
 
 		/*
 		 * W = @wg + \Sum rw_j
 		 */
-		W = wg + calc_tg_weight(tg, se->my_q);
+		W = wg + atomic_long_read(&tg->load_avg);
+
+		/* Ensure \Sum rw_j >= rw_i */
+		W -= cfs_rq->tg_load_avg_contrib;
+		W += w;
 
 		/*
 		 * w = rw_i + @wl
 		 */
-		w = cfs_rq_load_avg(se->my_q) + wl;
+		w += wl;
 
 		/*
 		 * wl = S * s'_i; see (2)
@@ -4831,6 +5069,11 @@
 	return shallowest_idle_cpu != -1 ? shallowest_idle_cpu : least_loaded_cpu;
 }
 
+#ifdef CONFIG_SCHED_SMT
+DEFINE_STATIC_KEY_FALSE(sched_smt_present);
+EXPORT_SYMBOL_GPL(sched_smt_present);
+#endif
+
 /*
  * Try and locate an idle CPU in the sched_domain.
  */
@@ -5801,7 +6044,15 @@
 		if (!can_migrate_task(p, env))
 			goto next;
 
-		load = task_h_load(p);
+		/*
+		 * Depending of the number of CPUs and tasks and the
+		 * cgroup hierarchy, task_h_load() can return a null
+		 * value. Make sure that env->imbalance decreases
+		 * otherwise detach_tasks() will stop only after
+		 * detaching up to loop_max tasks.
+		 */
+		load = max_t(unsigned long, task_h_load(p), 1);
+
 
 		if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed)
 			goto next;
@@ -5893,10 +6144,28 @@
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
+
+static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
+{
+	if (cfs_rq->load.weight)
+		return false;
+
+	if (cfs_rq->avg.load_sum)
+		return false;
+
+	if (cfs_rq->avg.util_sum)
+		return false;
+
+	if (cfs_rq->runnable_load_sum)
+		return false;
+
+	return true;
+}
+
 static void update_blocked_averages(int cpu)
 {
 	struct rq *rq = cpu_rq(cpu);
-	struct cfs_rq *cfs_rq;
+	struct cfs_rq *cfs_rq, *pos;
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&rq->lock, flags);
@@ -5906,13 +6175,16 @@
 	 * Iterates the task_group tree in a bottom up fashion, see
 	 * list_add_leaf_cfs_rq() for details.
 	 */
-	for_each_leaf_cfs_rq(rq, cfs_rq) {
-		/* throttled entities do not contribute to load */
-		if (throttled_hierarchy(cfs_rq))
-			continue;
-
+	for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) {
 		if (update_cfs_rq_load_avg(cfs_rq_clock_task(cfs_rq), cfs_rq))
 			update_tg_load_avg(cfs_rq, 0);
+		/*
+		 * There can be a lot of idle CPU cgroups.  Don't let fully
+		 * decayed cfs_rqs linger on the list.
+		 */
+		if (cfs_rq_is_decayed(cfs_rq))
+			list_del_leaf_cfs_rq(cfs_rq);
+
 	}
 	raw_spin_unlock_irqrestore(&rq->lock, flags);
 }
@@ -5932,10 +6204,10 @@
 	if (cfs_rq->last_h_load_update == now)
 		return;
 
-	cfs_rq->h_load_next = NULL;
+	WRITE_ONCE(cfs_rq->h_load_next, NULL);
 	for_each_sched_entity(se) {
 		cfs_rq = cfs_rq_of(se);
-		cfs_rq->h_load_next = se;
+		WRITE_ONCE(cfs_rq->h_load_next, se);
 		if (cfs_rq->last_h_load_update == now)
 			break;
 	}
@@ -5945,7 +6217,7 @@
 		cfs_rq->last_h_load_update = now;
 	}
 
-	while ((se = cfs_rq->h_load_next) != NULL) {
+	while ((se = READ_ONCE(cfs_rq->h_load_next)) != NULL) {
 		load = cfs_rq->h_load;
 		load = div64_ul(load * se->avg.load_avg,
 			cfs_rq_load_avg(cfs_rq) + 1);
@@ -7178,9 +7450,10 @@
 out_balanced:
 	/*
 	 * We reach balance although we may have faced some affinity
-	 * constraints. Clear the imbalance flag if it was set.
+	 * constraints. Clear the imbalance flag only if other tasks got
+	 * a chance to move and fix the imbalance.
 	 */
-	if (sd_parent) {
+	if (sd_parent && !(env.flags & LBF_ALL_PINNED)) {
 		int *group_imbalance = &sd_parent->groups->sgc->imbalance;
 
 		if (*group_imbalance)
@@ -7198,13 +7471,22 @@
 	sd->nr_balance_failed = 0;
 
 out_one_pinned:
+	ld_moved = 0;
+
+	/*
+	 * idle_balance() disregards balance intervals, so we could repeatedly
+	 * reach this code, which would lead to balance_interval skyrocketting
+	 * in a short amount of time. Skip the balance_interval increase logic
+	 * to avoid that.
+	 */
+	if (env.idle == CPU_NEWLY_IDLE)
+		goto out;
+
 	/* tune up the balancing interval */
 	if (((env.flags & LBF_ALL_PINNED) &&
 			sd->balance_interval < MAX_PINNED_INTERVAL) ||
 			(sd->balance_interval < sd->max_interval))
 		sd->balance_interval *= 2;
-
-	ld_moved = 0;
 out:
 	return ld_moved;
 }
@@ -8098,11 +8380,8 @@
 	for_each_possible_cpu(i) {
 		if (tg->cfs_rq)
 			kfree(tg->cfs_rq[i]);
-		if (tg->se) {
-			if (tg->se[i])
-				remove_entity_load_avg(tg->se[i]);
+		if (tg->se)
 			kfree(tg->se[i]);
-		}
 	}
 
 	kfree(tg->cfs_rq);
@@ -8150,21 +8429,29 @@
 	return 0;
 }
 
-void unregister_fair_sched_group(struct task_group *tg, int cpu)
+void unregister_fair_sched_group(struct task_group *tg)
 {
-	struct rq *rq = cpu_rq(cpu);
 	unsigned long flags;
+	struct rq *rq;
+	int cpu;
 
-	/*
-	* Only empty task groups can be destroyed; so we can speculatively
-	* check on_list without danger of it being re-added.
-	*/
-	if (!tg->cfs_rq[cpu]->on_list)
-		return;
+	for_each_possible_cpu(cpu) {
+		if (tg->se[cpu])
+			remove_entity_load_avg(tg->se[cpu]);
 
-	raw_spin_lock_irqsave(&rq->lock, flags);
-	list_del_leaf_cfs_rq(tg->cfs_rq[cpu]);
-	raw_spin_unlock_irqrestore(&rq->lock, flags);
+		/*
+		 * Only empty task groups can be destroyed; so we can speculatively
+		 * check on_list without danger of it being re-added.
+		 */
+		if (!tg->cfs_rq[cpu]->on_list)
+			continue;
+
+		rq = cpu_rq(cpu);
+
+		raw_spin_lock_irqsave(&rq->lock, flags);
+		list_del_leaf_cfs_rq(tg->cfs_rq[cpu]);
+		raw_spin_unlock_irqrestore(&rq->lock, flags);
+	}
 }
 
 void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
@@ -8246,7 +8533,7 @@
 	return 1;
 }
 
-void unregister_fair_sched_group(struct task_group *tg, int cpu) { }
+void unregister_fair_sched_group(struct task_group *tg) { }
 
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
@@ -8313,10 +8600,10 @@
 #ifdef CONFIG_SCHED_DEBUG
 void print_cfs_stats(struct seq_file *m, int cpu)
 {
-	struct cfs_rq *cfs_rq;
+	struct cfs_rq *cfs_rq, *pos;
 
 	rcu_read_lock();
-	for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq)
+	for_each_leaf_cfs_rq_safe(cpu_rq(cpu), cfs_rq, pos)
 		print_cfs_rq(m, cpu, cfs_rq);
 	rcu_read_unlock();
 }
--- linux-4.4.0.orig/kernel/sched/idle.c
+++ linux-4.4.0/kernel/sched/idle.c
@@ -132,7 +132,7 @@
  */
 static void cpuidle_idle_call(void)
 {
-	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+	struct cpuidle_device *dev = cpuidle_get_device();
 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
 	int next_state, entered_state;
 
@@ -219,6 +219,7 @@
 		 */
 
 		__current_set_polling();
+		quiet_vmstat();
 		tick_nohz_idle_enter();
 
 		while (!need_resched()) {
--- linux-4.4.0.orig/kernel/sched/loadavg.c
+++ linux-4.4.0/kernel/sched/loadavg.c
@@ -99,10 +99,13 @@
 static unsigned long
 calc_load(unsigned long load, unsigned long exp, unsigned long active)
 {
-	load *= exp;
-	load += active * (FIXED_1 - exp);
-	load += 1UL << (FSHIFT - 1);
-	return load >> FSHIFT;
+	unsigned long newload;
+
+	newload = load * exp + active * (FIXED_1 - exp);
+	if (active >= load)
+		newload += FIXED_1-1;
+
+	return newload / FIXED_1;
 }
 
 #ifdef CONFIG_NO_HZ_COMMON
@@ -198,8 +201,9 @@
 	struct rq *this_rq = this_rq();
 
 	/*
-	 * If we're still before the sample window, we're done.
+	 * If we're still before the pending sample window, we're done.
 	 */
+	this_rq->calc_load_update = calc_load_update;
 	if (time_before(jiffies, this_rq->calc_load_update))
 		return;
 
@@ -208,7 +212,6 @@
 	 * accounted through the nohz accounting, so skip the entire deal and
 	 * sync up for the next window.
 	 */
-	this_rq->calc_load_update = calc_load_update;
 	if (time_before(jiffies, this_rq->calc_load_update + 10))
 		this_rq->calc_load_update += LOAD_FREQ;
 }
--- linux-4.4.0.orig/kernel/sched/rt.c
+++ linux-4.4.0/kernel/sched/rt.c
@@ -9,6 +9,7 @@
 #include <linux/irq_work.h>
 
 int sched_rr_timeslice = RR_TIMESLICE;
+int sysctl_sched_rr_timeslice = (MSEC_PER_SEC / HZ) * RR_TIMESLICE;
 
 static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun);
 
@@ -64,10 +65,6 @@
 	raw_spin_unlock(&rt_b->rt_runtime_lock);
 }
 
-#if defined(CONFIG_SMP) && defined(HAVE_RT_PUSH_IPI)
-static void push_irq_work_func(struct irq_work *work);
-#endif
-
 void init_rt_rq(struct rt_rq *rt_rq)
 {
 	struct rt_prio_array *array;
@@ -87,13 +84,6 @@
 	rt_rq->rt_nr_migratory = 0;
 	rt_rq->overloaded = 0;
 	plist_head_init(&rt_rq->pushable_tasks);
-
-#ifdef HAVE_RT_PUSH_IPI
-	rt_rq->push_flags = 0;
-	rt_rq->push_cpu = nr_cpu_ids;
-	raw_spin_lock_init(&rt_rq->push_lock);
-	init_irq_work(&rt_rq->push_work, push_irq_work_func);
-#endif
 #endif /* CONFIG_SMP */
 	/* We start is dequeued state, because no RT tasks are queued */
 	rt_rq->rt_queued = 0;
@@ -833,6 +823,8 @@
 		struct rq *rq = rq_of_rt_rq(rt_rq);
 
 		raw_spin_lock(&rq->lock);
+		update_rq_clock(rq);
+
 		if (rt_rq->rt_time) {
 			u64 runtime;
 
@@ -1802,160 +1794,172 @@
 }
 
 #ifdef HAVE_RT_PUSH_IPI
+
 /*
- * The search for the next cpu always starts at rq->cpu and ends
- * when we reach rq->cpu again. It will never return rq->cpu.
- * This returns the next cpu to check, or nr_cpu_ids if the loop
- * is complete.
+ * When a high priority task schedules out from a CPU and a lower priority
+ * task is scheduled in, a check is made to see if there's any RT tasks
+ * on other CPUs that are waiting to run because a higher priority RT task
+ * is currently running on its CPU. In this case, the CPU with multiple RT
+ * tasks queued on it (overloaded) needs to be notified that a CPU has opened
+ * up that may be able to run one of its non-running queued RT tasks.
+ *
+ * All CPUs with overloaded RT tasks need to be notified as there is currently
+ * no way to know which of these CPUs have the highest priority task waiting
+ * to run. Instead of trying to take a spinlock on each of these CPUs,
+ * which has shown to cause large latency when done on machines with many
+ * CPUs, sending an IPI to the CPUs to have them push off the overloaded
+ * RT tasks waiting to run.
+ *
+ * Just sending an IPI to each of the CPUs is also an issue, as on large
+ * count CPU machines, this can cause an IPI storm on a CPU, especially
+ * if its the only CPU with multiple RT tasks queued, and a large number
+ * of CPUs scheduling a lower priority task at the same time.
+ *
+ * Each root domain has its own irq work function that can iterate over
+ * all CPUs with RT overloaded tasks. Since all CPUs with overloaded RT
+ * tassk must be checked if there's one or many CPUs that are lowering
+ * their priority, there's a single irq work iterator that will try to
+ * push off RT tasks that are waiting to run.
+ *
+ * When a CPU schedules a lower priority task, it will kick off the
+ * irq work iterator that will jump to each CPU with overloaded RT tasks.
+ * As it only takes the first CPU that schedules a lower priority task
+ * to start the process, the rto_start variable is incremented and if
+ * the atomic result is one, then that CPU will try to take the rto_lock.
+ * This prevents high contention on the lock as the process handles all
+ * CPUs scheduling lower priority tasks.
+ *
+ * All CPUs that are scheduling a lower priority task will increment the
+ * rt_loop_next variable. This will make sure that the irq work iterator
+ * checks all RT overloaded CPUs whenever a CPU schedules a new lower
+ * priority task, even if the iterator is in the middle of a scan. Incrementing
+ * the rt_loop_next will cause the iterator to perform another scan.
  *
- * rq->rt.push_cpu holds the last cpu returned by this function,
- * or if this is the first instance, it must hold rq->cpu.
  */
-static int rto_next_cpu(struct rq *rq)
+static int rto_next_cpu(struct root_domain *rd)
 {
-	int prev_cpu = rq->rt.push_cpu;
+	int next;
 	int cpu;
 
-	cpu = cpumask_next(prev_cpu, rq->rd->rto_mask);
-
 	/*
-	 * If the previous cpu is less than the rq's CPU, then it already
-	 * passed the end of the mask, and has started from the beginning.
-	 * We end if the next CPU is greater or equal to rq's CPU.
+	 * When starting the IPI RT pushing, the rto_cpu is set to -1,
+	 * rt_next_cpu() will simply return the first CPU found in
+	 * the rto_mask.
+	 *
+	 * If rto_next_cpu() is called with rto_cpu is a valid cpu, it
+	 * will return the next CPU found in the rto_mask.
+	 *
+	 * If there are no more CPUs left in the rto_mask, then a check is made
+	 * against rto_loop and rto_loop_next. rto_loop is only updated with
+	 * the rto_lock held, but any CPU may increment the rto_loop_next
+	 * without any locking.
 	 */
-	if (prev_cpu < rq->cpu) {
-		if (cpu >= rq->cpu)
-			return nr_cpu_ids;
+	for (;;) {
 
-	} else if (cpu >= nr_cpu_ids) {
-		/*
-		 * We passed the end of the mask, start at the beginning.
-		 * If the result is greater or equal to the rq's CPU, then
-		 * the loop is finished.
-		 */
-		cpu = cpumask_first(rq->rd->rto_mask);
-		if (cpu >= rq->cpu)
-			return nr_cpu_ids;
-	}
-	rq->rt.push_cpu = cpu;
+		/* When rto_cpu is -1 this acts like cpumask_first() */
+		cpu = cpumask_next(rd->rto_cpu, rd->rto_mask);
 
-	/* Return cpu to let the caller know if the loop is finished or not */
-	return cpu;
-}
+		rd->rto_cpu = cpu;
 
-static int find_next_push_cpu(struct rq *rq)
-{
-	struct rq *next_rq;
-	int cpu;
+		if (cpu < nr_cpu_ids)
+			return cpu;
 
-	while (1) {
-		cpu = rto_next_cpu(rq);
-		if (cpu >= nr_cpu_ids)
-			break;
-		next_rq = cpu_rq(cpu);
+		rd->rto_cpu = -1;
+
+		/*
+		 * ACQUIRE ensures we see the @rto_mask changes
+		 * made prior to the @next value observed.
+		 *
+		 * Matches WMB in rt_set_overload().
+		 */
+		next = atomic_read_acquire(&rd->rto_loop_next);
 
-		/* Make sure the next rq can push to this rq */
-		if (next_rq->rt.highest_prio.next < rq->rt.highest_prio.curr)
+		if (rd->rto_loop == next)
 			break;
+
+		rd->rto_loop = next;
 	}
 
-	return cpu;
+	return -1;
 }
 
-#define RT_PUSH_IPI_EXECUTING		1
-#define RT_PUSH_IPI_RESTART		2
+static inline bool rto_start_trylock(atomic_t *v)
+{
+	return !atomic_cmpxchg_acquire(v, 0, 1);
+}
 
-static void tell_cpu_to_push(struct rq *rq)
+static inline void rto_start_unlock(atomic_t *v)
 {
-	int cpu;
+	atomic_set_release(v, 0);
+}
 
-	if (rq->rt.push_flags & RT_PUSH_IPI_EXECUTING) {
-		raw_spin_lock(&rq->rt.push_lock);
-		/* Make sure it's still executing */
-		if (rq->rt.push_flags & RT_PUSH_IPI_EXECUTING) {
-			/*
-			 * Tell the IPI to restart the loop as things have
-			 * changed since it started.
-			 */
-			rq->rt.push_flags |= RT_PUSH_IPI_RESTART;
-			raw_spin_unlock(&rq->rt.push_lock);
-			return;
-		}
-		raw_spin_unlock(&rq->rt.push_lock);
-	}
+static void tell_cpu_to_push(struct rq *rq)
+{
+	int cpu = -1;
 
-	/* When here, there's no IPI going around */
+	/* Keep the loop going if the IPI is currently active */
+	atomic_inc(&rq->rd->rto_loop_next);
 
-	rq->rt.push_cpu = rq->cpu;
-	cpu = find_next_push_cpu(rq);
-	if (cpu >= nr_cpu_ids)
+	/* Only one CPU can initiate a loop at a time */
+	if (!rto_start_trylock(&rq->rd->rto_loop_start))
 		return;
 
-	rq->rt.push_flags = RT_PUSH_IPI_EXECUTING;
+	raw_spin_lock(&rq->rd->rto_lock);
+
+	/*
+	 * The rto_cpu is updated under the lock, if it has a valid cpu
+	 * then the IPI is still running and will continue due to the
+	 * update to loop_next, and nothing needs to be done here.
+	 * Otherwise it is finishing up and an ipi needs to be sent.
+	 */
+	if (rq->rd->rto_cpu < 0)
+		cpu = rto_next_cpu(rq->rd);
+
+	raw_spin_unlock(&rq->rd->rto_lock);
+
+	rto_start_unlock(&rq->rd->rto_loop_start);
 
-	irq_work_queue_on(&rq->rt.push_work, cpu);
+	if (cpu >= 0) {
+		/* Make sure the rd does not get freed while pushing */
+		sched_get_rd(rq->rd);
+		irq_work_queue_on(&rq->rd->rto_push_work, cpu);
+	}
 }
 
 /* Called from hardirq context */
-static void try_to_push_tasks(void *arg)
+void rto_push_irq_work_func(struct irq_work *work)
 {
-	struct rt_rq *rt_rq = arg;
-	struct rq *rq, *src_rq;
-	int this_cpu;
+	struct root_domain *rd =
+		container_of(work, struct root_domain, rto_push_work);
+	struct rq *rq;
 	int cpu;
 
-	this_cpu = rt_rq->push_cpu;
-
-	/* Paranoid check */
-	BUG_ON(this_cpu != smp_processor_id());
+	rq = this_rq();
 
-	rq = cpu_rq(this_cpu);
-	src_rq = rq_of_rt_rq(rt_rq);
-
-again:
+	/*
+	 * We do not need to grab the lock to check for has_pushable_tasks.
+	 * When it gets updated, a check is made if a push is possible.
+	 */
 	if (has_pushable_tasks(rq)) {
 		raw_spin_lock(&rq->lock);
-		push_rt_task(rq);
+		push_rt_tasks(rq);
 		raw_spin_unlock(&rq->lock);
 	}
 
-	/* Pass the IPI to the next rt overloaded queue */
-	raw_spin_lock(&rt_rq->push_lock);
-	/*
-	 * If the source queue changed since the IPI went out,
-	 * we need to restart the search from that CPU again.
-	 */
-	if (rt_rq->push_flags & RT_PUSH_IPI_RESTART) {
-		rt_rq->push_flags &= ~RT_PUSH_IPI_RESTART;
-		rt_rq->push_cpu = src_rq->cpu;
-	}
+	raw_spin_lock(&rd->rto_lock);
 
-	cpu = find_next_push_cpu(src_rq);
+	/* Pass the IPI to the next rt overloaded queue */
+	cpu = rto_next_cpu(rd);
 
-	if (cpu >= nr_cpu_ids)
-		rt_rq->push_flags &= ~RT_PUSH_IPI_EXECUTING;
-	raw_spin_unlock(&rt_rq->push_lock);
+	raw_spin_unlock(&rd->rto_lock);
 
-	if (cpu >= nr_cpu_ids)
+	if (cpu < 0) {
+		sched_put_rd(rd);
 		return;
-
-	/*
-	 * It is possible that a restart caused this CPU to be
-	 * chosen again. Don't bother with an IPI, just see if we
-	 * have more to push.
-	 */
-	if (unlikely(cpu == rq->cpu))
-		goto again;
+	}
 
 	/* Try the next RT overloaded CPU */
-	irq_work_queue_on(&rt_rq->push_work, cpu);
-}
-
-static void push_irq_work_func(struct irq_work *work)
-{
-	struct rt_rq *rt_rq = container_of(work, struct rt_rq, push_work);
-
-	try_to_push_tasks(rt_rq);
+	irq_work_queue_on(&rd->rto_push_work, cpu);
 }
 #endif /* HAVE_RT_PUSH_IPI */
 
@@ -1965,8 +1969,9 @@
 	bool resched = false;
 	struct task_struct *p;
 	struct rq *src_rq;
+	int rt_overload_count = rt_overloaded(this_rq);
 
-	if (likely(!rt_overloaded(this_rq)))
+	if (likely(!rt_overload_count))
 		return;
 
 	/*
@@ -1975,6 +1980,11 @@
 	 */
 	smp_rmb();
 
+	/* If we are the only overloaded CPU do nothing */
+	if (rt_overload_count == 1 &&
+	    cpumask_test_cpu(this_rq->cpu, this_rq->rd->rto_mask))
+		return;
+
 #ifdef HAVE_RT_PUSH_IPI
 	if (sched_feat(RT_PUSH_IPI)) {
 		tell_cpu_to_push(this_rq);
@@ -2136,10 +2146,9 @@
 #ifdef CONFIG_SMP
 		if (p->nr_cpus_allowed > 1 && rq->rt.overloaded)
 			queue_push_tasks(rq);
-#else
-		if (p->prio < rq->curr->prio)
-			resched_curr(rq);
 #endif /* CONFIG_SMP */
+		if (p->prio < rq->curr->prio && cpu_online(cpu_of(rq)))
+			resched_curr(rq);
 	}
 }
 
--- linux-4.4.0.orig/kernel/sched/sched.h
+++ linux-4.4.0/kernel/sched/sched.h
@@ -1,5 +1,6 @@
 
 #include <linux/sched.h>
+#include <linux/sched/smt.h>
 #include <linux/sched/sysctl.h>
 #include <linux/sched/rt.h>
 #include <linux/sched/deadline.h>
@@ -233,6 +234,8 @@
 	/* statistics */
 	int nr_periods, nr_throttled;
 	u64 throttled_time;
+
+	bool distribute_running;
 #endif
 };
 
@@ -308,7 +311,7 @@
 
 extern void free_fair_sched_group(struct task_group *tg);
 extern int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent);
-extern void unregister_fair_sched_group(struct task_group *tg, int cpu);
+extern void unregister_fair_sched_group(struct task_group *tg);
 extern void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
 			struct sched_entity *se, int cpu,
 			struct sched_entity *parent);
@@ -417,7 +420,7 @@
 
 	u64 throttled_clock, throttled_clock_task;
 	u64 throttled_clock_task_time;
-	int throttled, throttle_count;
+	int throttled, throttle_count, throttle_uptodate;
 	struct list_head throttled_list;
 #endif /* CONFIG_CFS_BANDWIDTH */
 #endif /* CONFIG_FAIR_GROUP_SCHED */
@@ -429,7 +432,7 @@
 }
 
 /* RT IPI pull logic requires IRQ_WORK */
-#ifdef CONFIG_IRQ_WORK
+#if defined(CONFIG_IRQ_WORK) && defined(CONFIG_SMP)
 # define HAVE_RT_PUSH_IPI
 #endif
 
@@ -450,12 +453,6 @@
 	unsigned long rt_nr_total;
 	int overloaded;
 	struct plist_head pushable_tasks;
-#ifdef HAVE_RT_PUSH_IPI
-	int push_flags;
-	int push_cpu;
-	struct irq_work push_work;
-	raw_spinlock_t push_lock;
-#endif
 #endif /* CONFIG_SMP */
 	int rt_queued;
 
@@ -537,6 +534,19 @@
 	struct dl_bw dl_bw;
 	struct cpudl cpudl;
 
+#ifdef HAVE_RT_PUSH_IPI
+	/*
+	 * For IPI pull requests, loop across the rto_mask.
+	 */
+	struct irq_work rto_push_work;
+	raw_spinlock_t rto_lock;
+	/* These are only updated and read within rto_lock */
+	int rto_loop;
+	int rto_cpu;
+	/* These atomics are updated outside of a lock */
+	atomic_t rto_loop_next;
+	atomic_t rto_loop_start;
+#endif
 	/*
 	 * The "RT overload" flag: it gets set if a CPU has more than
 	 * one runnable RT task.
@@ -546,7 +556,12 @@
 };
 
 extern struct root_domain def_root_domain;
+extern void sched_get_rd(struct root_domain *rd);
+extern void sched_put_rd(struct root_domain *rd);
 
+#ifdef HAVE_RT_PUSH_IPI
+extern void rto_push_irq_work_func(struct irq_work *work);
+#endif
 #endif /* CONFIG_SMP */
 
 /*
@@ -591,6 +606,7 @@
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	/* list of leaf cfs_rq on this cpu: */
 	struct list_head leaf_cfs_rq_list;
+	struct list_head *tmp_alone_branch;
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 	/*
@@ -963,7 +979,11 @@
 	 * per-task data have been completed by this moment.
 	 */
 	smp_wmb();
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+	p->cpu = cpu;
+#else
 	task_thread_info(p)->cpu = cpu;
+#endif
 	p->wake_cpu = cpu;
 #endif
 }
--- linux-4.4.0.orig/kernel/seccomp.c
+++ linux-4.4.0/kernel/seccomp.c
@@ -16,10 +16,14 @@
 #include <linux/atomic.h>
 #include <linux/audit.h>
 #include <linux/compat.h>
+#include <linux/kmemleak.h>
+#include <linux/nospec.h>
+#include <linux/prctl.h>
 #include <linux/sched.h>
 #include <linux/seccomp.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
+#include <linux/sysctl.h>
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
 #include <asm/syscall.h>
@@ -40,6 +44,7 @@
  *         get/put helpers should be used when accessing an instance
  *         outside of a lifetime-guarded section.  In general, this
  *         is only needed for handling filters shared across tasks.
+ * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged
  * @prev: points to a previously installed, or inherited, filter
  * @len: the number of instructions in the program
  * @insnsi: the BPF program instructions to evaluate
@@ -56,6 +61,7 @@
  */
 struct seccomp_filter {
 	atomic_t usage;
+	bool log;
 	struct seccomp_filter *prev;
 	struct bpf_prog *prog;
 };
@@ -170,10 +176,14 @@
 /**
  * seccomp_run_filters - evaluates all seccomp filters against @syscall
  * @syscall: number of the current system call
+ * @match: stores struct seccomp_filter that resulted in the return value,
+ *         unless filter returned SECCOMP_RET_ALLOW, in which case it will
+ *         be unchanged.
  *
  * Returns valid seccomp BPF response codes.
  */
-static u32 seccomp_run_filters(struct seccomp_data *sd)
+static u32 seccomp_run_filters(struct seccomp_data *sd,
+			       struct seccomp_filter **match)
 {
 	struct seccomp_data sd_local;
 	u32 ret = SECCOMP_RET_ALLOW;
@@ -197,8 +207,10 @@
 	for (; f; f = f->prev) {
 		u32 cur_ret = BPF_PROG_RUN(f->prog, (void *)sd);
 
-		if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
+		if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) {
 			ret = cur_ret;
+			*match = f;
+		}
 	}
 	return ret;
 }
@@ -214,8 +226,11 @@
 	return true;
 }
 
+void __weak arch_seccomp_spec_mitigate(struct task_struct *task) { }
+
 static inline void seccomp_assign_mode(struct task_struct *task,
-				       unsigned long seccomp_mode)
+				       unsigned long seccomp_mode,
+				       unsigned long flags)
 {
 	assert_spin_locked(&task->sighand->siglock);
 
@@ -225,6 +240,9 @@
 	 * filter) is set.
 	 */
 	smp_mb__before_atomic();
+	/* Assume default seccomp processes want spec flaw mitigation. */
+	if ((flags & SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 0)
+		arch_seccomp_spec_mitigate(task);
 	set_tsk_thread_flag(task, TIF_SECCOMP);
 }
 
@@ -292,7 +310,7 @@
  * without dropping the locks.
  *
  */
-static inline void seccomp_sync_threads(void)
+static inline void seccomp_sync_threads(unsigned long flags)
 {
 	struct task_struct *thread, *caller;
 
@@ -316,24 +334,25 @@
 		put_seccomp_filter(thread);
 		smp_store_release(&thread->seccomp.filter,
 				  caller->seccomp.filter);
+
+		/*
+		 * Don't let an unprivileged task work around
+		 * the no_new_privs restriction by creating
+		 * a thread that sets it up, enters seccomp,
+		 * then dies.
+		 */
+		if (task_no_new_privs(caller))
+			task_set_no_new_privs(thread);
+
 		/*
 		 * Opt the other thread into seccomp if needed.
 		 * As threads are considered to be trust-realm
 		 * equivalent (see ptrace_may_access), it is safe to
 		 * allow one thread to transition the other.
 		 */
-		if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) {
-			/*
-			 * Don't let an unprivileged task work around
-			 * the no_new_privs restriction by creating
-			 * a thread that sets it up, enters seccomp,
-			 * then dies.
-			 */
-			if (task_no_new_privs(caller))
-				task_set_no_new_privs(thread);
-
-			seccomp_assign_mode(thread, SECCOMP_MODE_FILTER);
-		}
+		if (thread->seccomp.mode == SECCOMP_MODE_DISABLED)
+			seccomp_assign_mode(thread, SECCOMP_MODE_FILTER,
+					    flags);
 	}
 }
 
@@ -443,6 +462,10 @@
 			return ret;
 	}
 
+	/* Set log flag, if present. */
+	if (flags & SECCOMP_FILTER_FLAG_LOG)
+		filter->log = true;
+
 	/*
 	 * If there is an existing filter, make it the prev and don't drop its
 	 * task reference.
@@ -452,19 +475,24 @@
 
 	/* Now that the new filter is in place, synchronize to all threads. */
 	if (flags & SECCOMP_FILTER_FLAG_TSYNC)
-		seccomp_sync_threads();
+		seccomp_sync_threads(flags);
 
 	return 0;
 }
 
+void __get_seccomp_filter(struct seccomp_filter *filter)
+{
+	/* Reference count is bounded by the number of total processes. */
+	atomic_inc(&filter->usage);
+}
+
 /* get_seccomp_filter - increments the reference count of the filter on @tsk */
 void get_seccomp_filter(struct task_struct *tsk)
 {
 	struct seccomp_filter *orig = tsk->seccomp.filter;
 	if (!orig)
 		return;
-	/* Reference count is bounded by the number of total processes. */
-	atomic_inc(&orig->usage);
+	__get_seccomp_filter(orig);
 }
 
 static inline void seccomp_filter_free(struct seccomp_filter *filter)
@@ -475,10 +503,8 @@
 	}
 }
 
-/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
-void put_seccomp_filter(struct task_struct *tsk)
+static void __put_seccomp_filter(struct seccomp_filter *orig)
 {
-	struct seccomp_filter *orig = tsk->seccomp.filter;
 	/* Clean up single-reference branches iteratively. */
 	while (orig && atomic_dec_and_test(&orig->usage)) {
 		struct seccomp_filter *freeme = orig;
@@ -487,6 +513,12 @@
 	}
 }
 
+/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
+void put_seccomp_filter(struct task_struct *tsk)
+{
+	__put_seccomp_filter(tsk->seccomp.filter);
+}
+
 /**
  * seccomp_send_sigsys - signals the task to allow in-process syscall emulation
  * @syscall: syscall number to send to userland
@@ -508,6 +540,58 @@
 }
 #endif	/* CONFIG_SECCOMP_FILTER */
 
+/* For use with seccomp_actions_logged */
+#define SECCOMP_LOG_KILL		(1 << 0)
+#define SECCOMP_LOG_TRAP		(1 << 2)
+#define SECCOMP_LOG_ERRNO		(1 << 3)
+#define SECCOMP_LOG_TRACE		(1 << 4)
+#define SECCOMP_LOG_LOG			(1 << 5)
+#define SECCOMP_LOG_ALLOW		(1 << 6)
+
+static u32 seccomp_actions_logged = SECCOMP_LOG_KILL  | SECCOMP_LOG_TRAP  |
+				    SECCOMP_LOG_ERRNO | SECCOMP_LOG_TRACE |
+				    SECCOMP_LOG_LOG;
+
+static inline void seccomp_log(unsigned long syscall, long signr, u32 action,
+			       bool requested)
+{
+	bool log = false;
+
+	switch (action) {
+	case SECCOMP_RET_ALLOW:
+		break;
+	case SECCOMP_RET_TRAP:
+		log = requested && seccomp_actions_logged & SECCOMP_LOG_TRAP;
+		break;
+	case SECCOMP_RET_ERRNO:
+		log = requested && seccomp_actions_logged & SECCOMP_LOG_ERRNO;
+		break;
+	case SECCOMP_RET_TRACE:
+		log = requested && seccomp_actions_logged & SECCOMP_LOG_TRACE;
+		break;
+	case SECCOMP_RET_LOG:
+		log = seccomp_actions_logged & SECCOMP_LOG_LOG;
+		break;
+	case SECCOMP_RET_KILL:
+	default:
+		log = seccomp_actions_logged & SECCOMP_LOG_KILL;
+	}
+
+	/*
+	 * Force an audit message to be emitted when the action is RET_KILL,
+	 * RET_LOG, or the FILTER_FLAG_LOG bit was set and the action is
+	 * allowed to be logged by the admin.
+	 */
+	if (log)
+		return __audit_seccomp(syscall, signr, action);
+
+	/*
+	 * Let the audit subsystem decide if the action should be audited based
+	 * on whether the current task itself is being audited.
+	 */
+	return audit_seccomp(syscall, signr, action);
+}
+
 /*
  * Secure computing mode 1 allows only read/write/exit/sigreturn.
  * To be fully secure this must be combined with rlimit
@@ -540,7 +624,7 @@
 #ifdef SECCOMP_DEBUG
 	dump_stack();
 #endif
-	audit_seccomp(this_syscall, SIGKILL, SECCOMP_RET_KILL);
+	seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL, true);
 	do_exit(SIGKILL);
 }
 
@@ -577,6 +661,7 @@
 static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
 {
 	u32 filter_ret, action;
+	struct seccomp_filter *match = NULL;
 	int data;
 
 	/*
@@ -585,7 +670,7 @@
 	 */
 	rmb();
 
-	filter_ret = seccomp_run_filters(sd);
+	filter_ret = seccomp_run_filters(sd, &match);
 	data = filter_ret & SECCOMP_RET_DATA;
 	action = filter_ret & SECCOMP_RET_ACTION;
 
@@ -608,19 +693,28 @@
 	case SECCOMP_RET_TRACE:
 		return filter_ret;  /* Save the rest for phase 2. */
 
+	case SECCOMP_RET_LOG:
+		seccomp_log(this_syscall, 0, action, true);
+		return SECCOMP_PHASE1_OK;
+
 	case SECCOMP_RET_ALLOW:
+		/*
+		 * Note that the "match" filter will always be NULL for
+		 * this action since SECCOMP_RET_ALLOW is the starting
+		 * state in seccomp_run_filters().
+		 */
 		return SECCOMP_PHASE1_OK;
 
 	case SECCOMP_RET_KILL:
 	default:
-		audit_seccomp(this_syscall, SIGSYS, action);
+		seccomp_log(this_syscall, SIGSYS, action, true);
 		do_exit(SIGSYS);
 	}
 
 	unreachable();
 
 skip:
-	audit_seccomp(this_syscall, 0, action);
+	seccomp_log(this_syscall, 0, action, match ? match->log : false);
 	return SECCOMP_PHASE1_SKIP;
 }
 #endif
@@ -687,7 +781,13 @@
 
 	BUG_ON(action != SECCOMP_RET_TRACE);
 
-	audit_seccomp(syscall_get_nr(current, regs), 0, action);
+	/* We don't have access to the filter that was matched in the phase1
+	 * stage in order to know if logging was requested when the filter was
+	 * loaded. Logging for SECCOMP_RET_TRACE isn't particularly useful so
+	 * hard-coding the _requested_ parameter of seccomp_log() to 'false'
+	 * will suffice for this backport.
+	 */
+	seccomp_log(syscall_get_nr(current, regs), 0, action, false);
 
 	/* Skip these calls if there is no tracer. */
 	if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
@@ -738,7 +838,7 @@
 #ifdef TIF_NOTSC
 	disable_TSC();
 #endif
-	seccomp_assign_mode(current, seccomp_mode);
+	seccomp_assign_mode(current, seccomp_mode, 0);
 	ret = 0;
 
 out:
@@ -796,7 +896,7 @@
 	/* Do not free the successfully attached filter. */
 	prepared = NULL;
 
-	seccomp_assign_mode(current, seccomp_mode);
+	seccomp_assign_mode(current, seccomp_mode, flags);
 out:
 	spin_unlock_irq(&current->sighand->siglock);
 	if (flags & SECCOMP_FILTER_FLAG_TSYNC)
@@ -813,6 +913,28 @@
 }
 #endif
 
+static long seccomp_get_action_avail(const char __user *uaction)
+{
+	u32 action;
+
+	if (copy_from_user(&action, uaction, sizeof(action)))
+		return -EFAULT;
+
+	switch (action) {
+	case SECCOMP_RET_KILL:
+	case SECCOMP_RET_TRAP:
+	case SECCOMP_RET_ERRNO:
+	case SECCOMP_RET_TRACE:
+	case SECCOMP_RET_LOG:
+	case SECCOMP_RET_ALLOW:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 /* Common entry point for both prctl and syscall. */
 static long do_seccomp(unsigned int op, unsigned int flags,
 		       const char __user *uargs)
@@ -824,6 +946,11 @@
 		return seccomp_set_mode_strict();
 	case SECCOMP_SET_MODE_FILTER:
 		return seccomp_set_mode_filter(flags, uargs);
+	case SECCOMP_GET_ACTION_AVAIL:
+		if (flags != 0)
+			return -EINVAL;
+
+		return seccomp_get_action_avail(uargs);
 	default:
 		return -EINVAL;
 	}
@@ -927,13 +1054,13 @@
 	if (!data)
 		goto out;
 
-	get_seccomp_filter(task);
+	__get_seccomp_filter(filter);
 	spin_unlock_irq(&task->sighand->siglock);
 
 	if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
 		ret = -EFAULT;
 
-	put_seccomp_filter(task);
+	__put_seccomp_filter(filter);
 	return ret;
 
 out:
@@ -941,3 +1068,181 @@
 	return ret;
 }
 #endif
+
+#ifdef CONFIG_SYSCTL
+
+/* Human readable action names for friendly sysctl interaction */
+#define SECCOMP_RET_KILL_NAME		"kill"
+#define SECCOMP_RET_TRAP_NAME		"trap"
+#define SECCOMP_RET_ERRNO_NAME		"errno"
+#define SECCOMP_RET_TRACE_NAME		"trace"
+#define SECCOMP_RET_LOG_NAME		"log"
+#define SECCOMP_RET_ALLOW_NAME		"allow"
+
+static const char seccomp_actions_avail[] = SECCOMP_RET_KILL_NAME	" "
+					    SECCOMP_RET_TRAP_NAME	" "
+					    SECCOMP_RET_ERRNO_NAME	" "
+					    SECCOMP_RET_TRACE_NAME	" "
+					    SECCOMP_RET_LOG_NAME	" "
+					    SECCOMP_RET_ALLOW_NAME;
+
+struct seccomp_log_name {
+	u32		log;
+	const char	*name;
+};
+
+static const struct seccomp_log_name seccomp_log_names[] = {
+	{ SECCOMP_LOG_KILL, SECCOMP_RET_KILL_NAME },
+	{ SECCOMP_LOG_TRAP, SECCOMP_RET_TRAP_NAME },
+	{ SECCOMP_LOG_ERRNO, SECCOMP_RET_ERRNO_NAME },
+	{ SECCOMP_LOG_TRACE, SECCOMP_RET_TRACE_NAME },
+	{ SECCOMP_LOG_LOG, SECCOMP_RET_LOG_NAME },
+	{ SECCOMP_LOG_ALLOW, SECCOMP_RET_ALLOW_NAME },
+	{ }
+};
+
+static bool seccomp_names_from_actions_logged(char *names, size_t size,
+					      u32 actions_logged)
+{
+	const struct seccomp_log_name *cur;
+	bool append_space = false;
+
+	for (cur = seccomp_log_names; cur->name && size; cur++) {
+		ssize_t ret;
+
+		if (!(actions_logged & cur->log))
+			continue;
+
+		if (append_space) {
+			ret = strscpy(names, " ", size);
+			if (ret < 0)
+				return false;
+
+			names += ret;
+			size -= ret;
+		} else
+			append_space = true;
+
+		ret = strscpy(names, cur->name, size);
+		if (ret < 0)
+			return false;
+
+		names += ret;
+		size -= ret;
+	}
+
+	return true;
+}
+
+static bool seccomp_action_logged_from_name(u32 *action_logged,
+					    const char *name)
+{
+	const struct seccomp_log_name *cur;
+
+	for (cur = seccomp_log_names; cur->name; cur++) {
+		if (!strcmp(cur->name, name)) {
+			*action_logged = cur->log;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static bool seccomp_actions_logged_from_names(u32 *actions_logged, char *names)
+{
+	char *name;
+
+	*actions_logged = 0;
+	while ((name = strsep(&names, " ")) && *name) {
+		u32 action_logged = 0;
+
+		if (!seccomp_action_logged_from_name(&action_logged, name))
+			return false;
+
+		*actions_logged |= action_logged;
+	}
+
+	return true;
+}
+
+static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write,
+					  void __user *buffer, size_t *lenp,
+					  loff_t *ppos)
+{
+	char names[sizeof(seccomp_actions_avail)];
+	struct ctl_table table;
+	int ret;
+
+	if (write && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	memset(names, 0, sizeof(names));
+
+	if (!write) {
+		if (!seccomp_names_from_actions_logged(names, sizeof(names),
+						       seccomp_actions_logged))
+			return -EINVAL;
+	}
+
+	table = *ro_table;
+	table.data = names;
+	table.maxlen = sizeof(names);
+	ret = proc_dostring(&table, write, buffer, lenp, ppos);
+	if (ret)
+		return ret;
+
+	if (write) {
+		u32 actions_logged;
+
+		if (!seccomp_actions_logged_from_names(&actions_logged,
+						       table.data))
+			return -EINVAL;
+
+		if (actions_logged & SECCOMP_LOG_ALLOW)
+			return -EINVAL;
+
+		seccomp_actions_logged = actions_logged;
+	}
+
+	return 0;
+}
+
+static struct ctl_path seccomp_sysctl_path[] = {
+	{ .procname = "kernel", },
+	{ .procname = "seccomp", },
+	{ }
+};
+
+static struct ctl_table seccomp_sysctl_table[] = {
+	{
+		.procname	= "actions_avail",
+		.data		= (void *) &seccomp_actions_avail,
+		.maxlen		= sizeof(seccomp_actions_avail),
+		.mode		= 0444,
+		.proc_handler	= proc_dostring,
+	},
+	{
+		.procname	= "actions_logged",
+		.mode		= 0644,
+		.proc_handler	= seccomp_actions_logged_handler,
+	},
+	{ }
+};
+
+static int __init seccomp_sysctl_init(void)
+{
+	struct ctl_table_header *hdr;
+
+	hdr = register_sysctl_paths(seccomp_sysctl_path, seccomp_sysctl_table);
+	if (!hdr)
+		pr_warn("seccomp: sysctl registration failed\n");
+	else
+		kmemleak_not_leak(hdr);
+
+	return 0;
+}
+
+device_initcall(seccomp_sysctl_init)
+
+#endif /* CONFIG_SYSCTL */
--- linux-4.4.0.orig/kernel/signal.c
+++ linux-4.4.0/kernel/signal.c
@@ -71,10 +71,19 @@
 
 	handler = sig_handler(t, sig);
 
+	/* SIGKILL and SIGSTOP may not be sent to the global init */
+	if (unlikely(is_global_init(t) && sig_kernel_only(sig)))
+		return true;
+
 	if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
-			handler == SIG_DFL && !force)
+	    handler == SIG_DFL && !(force && sig_kernel_only(sig)))
 		return 1;
 
+	/* Only allow kernel generated signals to this kthread */
+	if (unlikely((t->flags & PF_KTHREAD) &&
+		     (handler == SIG_KTHREAD_KERNEL) && !force))
+		return true;
+
 	return sig_handler_ignored(handler, sig);
 }
 
@@ -88,13 +97,15 @@
 	if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
 		return 0;
 
-	if (!sig_task_ignored(t, sig, force))
-		return 0;
-
 	/*
-	 * Tracers may want to know about even ignored signals.
+	 * Tracers may want to know about even ignored signal unless it
+	 * is SIGKILL which can't be reported anyway but can be ignored
+	 * by SIGNAL_UNKILLABLE task.
 	 */
-	return !t->ptrace;
+	if (t->ptrace && sig != SIGKILL)
+		return 0;
+
+	return sig_task_ignored(t, sig, force);
 }
 
 /*
@@ -346,7 +357,7 @@
 	 * fresh group stop.  Read comment in do_signal_stop() for details.
 	 */
 	if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) {
-		sig->flags = SIGNAL_STOP_STOPPED;
+		signal_set_stop_flags(sig, SIGNAL_STOP_STOPPED);
 		return true;
 	}
 	return false;
@@ -362,27 +373,32 @@
 {
 	struct sigqueue *q = NULL;
 	struct user_struct *user;
+	int sigpending;
 
 	/*
 	 * Protect access to @t credentials. This can go away when all
 	 * callers hold rcu read lock.
+	 *
+	 * NOTE! A pending signal will hold on to the user refcount,
+	 * and we get/put the refcount only when the sigpending count
+	 * changes from/to zero.
 	 */
 	rcu_read_lock();
-	user = get_uid(__task_cred(t)->user);
-	atomic_inc(&user->sigpending);
+	user = __task_cred(t)->user;
+	sigpending = atomic_inc_return(&user->sigpending);
+	if (sigpending == 1)
+		get_uid(user);
 	rcu_read_unlock();
 
-	if (override_rlimit ||
-	    atomic_read(&user->sigpending) <=
-			task_rlimit(t, RLIMIT_SIGPENDING)) {
+	if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
 		q = kmem_cache_alloc(sigqueue_cachep, flags);
 	} else {
 		print_dropped_signal(sig);
 	}
 
 	if (unlikely(q == NULL)) {
-		atomic_dec(&user->sigpending);
-		free_uid(user);
+		if (atomic_dec_and_test(&user->sigpending))
+			free_uid(user);
 	} else {
 		INIT_LIST_HEAD(&q->list);
 		q->flags = 0;
@@ -396,8 +412,8 @@
 {
 	if (q->flags & SIGQUEUE_PREALLOC)
 		return;
-	atomic_dec(&q->user->sigpending);
-	free_uid(q->user);
+	if (atomic_dec_and_test(&q->user->sigpending))
+		free_uid(q->user);
 	kmem_cache_free(sigqueue_cachep, q);
 }
 
@@ -503,7 +519,8 @@
 	return !tsk->ptrace;
 }
 
-static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
+static void collect_signal(int sig, struct sigpending *list, siginfo_t *info,
+			   bool *resched_timer)
 {
 	struct sigqueue *q, *first = NULL;
 
@@ -525,6 +542,12 @@
 still_pending:
 		list_del_init(&first->list);
 		copy_siginfo(info, &first->info);
+
+		*resched_timer =
+			(first->flags & SIGQUEUE_PREALLOC) &&
+			(info->si_code == SI_TIMER) &&
+			(info->si_sys_private);
+
 		__sigqueue_free(first);
 	} else {
 		/*
@@ -541,12 +564,12 @@
 }
 
 static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
-			siginfo_t *info)
+			siginfo_t *info, bool *resched_timer)
 {
 	int sig = next_signal(pending, mask);
 
 	if (sig)
-		collect_signal(sig, pending, info);
+		collect_signal(sig, pending, info, resched_timer);
 	return sig;
 }
 
@@ -558,15 +581,16 @@
  */
 int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
 {
+	bool resched_timer = false;
 	int signr;
 
 	/* We only dequeue private signals from ourselves, we don't let
 	 * signalfd steal them
 	 */
-	signr = __dequeue_signal(&tsk->pending, mask, info);
+	signr = __dequeue_signal(&tsk->pending, mask, info, &resched_timer);
 	if (!signr) {
 		signr = __dequeue_signal(&tsk->signal->shared_pending,
-					 mask, info);
+					 mask, info, &resched_timer);
 		/*
 		 * itimer signal ?
 		 *
@@ -611,7 +635,7 @@
 		 */
 		current->jobctl |= JOBCTL_STOP_DEQUEUED;
 	}
-	if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) {
+	if (resched_timer) {
 		/*
 		 * Release the siglock to ensure proper locking order
 		 * of timer locks outside of siglocks.  Note, we leave
@@ -686,6 +710,48 @@
 		(!is_si_special(info) && SI_FROMUSER(info));
 }
 
+static int dequeue_synchronous_signal(siginfo_t *info)
+{
+	struct task_struct *tsk = current;
+	struct sigpending *pending = &tsk->pending;
+	struct sigqueue *q, *sync = NULL;
+
+	/*
+	 * Might a synchronous signal be in the queue?
+	 */
+	if (!((pending->signal.sig[0] & ~tsk->blocked.sig[0]) & SYNCHRONOUS_MASK))
+		return 0;
+
+	/*
+	 * Return the first synchronous signal in the queue.
+	 */
+	list_for_each_entry(q, &pending->list, list) {
+		/* Synchronous signals have a postive si_code */
+		if ((q->info.si_code > SI_USER) &&
+		    (sigmask(q->info.si_signo) & SYNCHRONOUS_MASK)) {
+			sync = q;
+			goto next;
+		}
+	}
+	return 0;
+next:
+	/*
+	 * Check if there is another siginfo for the same signal.
+	 */
+	list_for_each_entry_continue(q, &pending->list, list) {
+		if (q->info.si_signo == sync->info.si_signo)
+			goto still_pending;
+	}
+
+	sigdelset(&pending->signal, sync->info.si_signo);
+	recalc_sigpending();
+still_pending:
+	list_del_init(&sync->list);
+	copy_siginfo(info, &sync->info);
+	__sigqueue_free(sync);
+	return info->si_signo;
+}
+
 /*
  * called with RCU read lock from check_kill_permission()
  */
@@ -837,7 +903,7 @@
 			 * will take ->siglock, notice SIGNAL_CLD_MASK, and
 			 * notify its parent. See get_signal_to_deliver().
 			 */
-			signal->flags = why | SIGNAL_STOP_CONTINUED;
+			signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED);
 			signal->group_stop_count = 0;
 			signal->group_exit_code = 0;
 		}
@@ -909,9 +975,9 @@
 	 * then start taking the whole group down immediately.
 	 */
 	if (sig_fatal(p, sig) &&
-	    !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
+	    !(signal->flags & SIGNAL_GROUP_EXIT) &&
 	    !sigismember(&t->real_blocked, sig) &&
-	    (sig == SIGKILL || !t->ptrace)) {
+	    (sig == SIGKILL || !p->ptrace)) {
 		/*
 		 * This signal will be fatal to the whole group.
 		 */
@@ -981,7 +1047,7 @@
 
 	result = TRACE_SIGNAL_IGNORED;
 	if (!prepare_signal(sig, t,
-			from_ancestor_ns || (info == SEND_SIG_FORCED)))
+			from_ancestor_ns || (info == SEND_SIG_PRIV) || (info == SEND_SIG_FORCED)))
 		goto ret;
 
 	pending = group ? &t->signal->shared_pending : &t->pending;
@@ -1382,6 +1448,10 @@
 		return ret;
 	}
 
+	/* -INT_MIN is undefined.  Exclude this case to avoid a UBSAN warning */
+	if (pid == INT_MIN)
+		return -ESRCH;
+
 	read_lock(&tasklist_lock);
 	if (pid != -1) {
 		ret = __kill_pgrp_info(sig, info,
@@ -1590,7 +1660,7 @@
 		 * This is only possible if parent == real_parent.
 		 * Check if it has changed security domain.
 		 */
-		if (tsk->parent_exec_id != tsk->parent->self_exec_id)
+		if (tsk->parent_exec_id != READ_ONCE(tsk->parent->self_exec_id))
 			sig = SIGCHLD;
 	}
 
@@ -2184,6 +2254,16 @@
 		goto relock;
 	}
 
+	/* Has this task already been marked for death? */
+	if (signal_group_exit(signal)) {
+		ksig->info.si_signo = signr = SIGKILL;
+		sigdelset(&current->pending.signal, SIGKILL);
+		trace_signal_deliver(SIGKILL, SEND_SIG_NOINFO,
+				&sighand->action[SIGKILL - 1]);
+		recalc_sigpending();
+		goto fatal;
+	}
+
 	for (;;) {
 		struct k_sigaction *ka;
 
@@ -2197,7 +2277,15 @@
 			goto relock;
 		}
 
-		signr = dequeue_signal(current, &current->blocked, &ksig->info);
+		/*
+		 * Signals generated by the execution of an instruction
+		 * need to be delivered before any other pending signals
+		 * so that the instruction pointer in the signal stack
+		 * frame points to the faulting instruction.
+		 */
+		signr = dequeue_synchronous_signal(&ksig->info);
+		if (!signr)
+			signr = dequeue_signal(current, &current->blocked, &ksig->info);
 
 		if (!signr)
 			break; /* will return 0 */
@@ -2279,6 +2367,7 @@
 			continue;
 		}
 
+	fatal:
 		spin_unlock_irq(&sighand->siglock);
 
 		/*
@@ -2485,6 +2574,13 @@
 {
 	struct task_struct *tsk = current;
 
+	/*
+	 * In case the signal mask hasn't changed, there is nothing we need
+	 * to do. The current->blocked shouldn't be modified by other task.
+	 */
+	if (sigequalsets(&tsk->blocked, newset))
+		return;
+
 	spin_lock_irq(&tsk->sighand->siglock);
 	__set_task_blocked(tsk, newset);
 	spin_unlock_irq(&tsk->sighand->siglock);
@@ -3088,7 +3184,8 @@
 }
 
 static int
-do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp)
+do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp,
+		size_t min_ss_size)
 {
 	stack_t oss;
 	int error;
@@ -3131,7 +3228,7 @@
 			ss_sp = NULL;
 		} else {
 			error = -ENOMEM;
-			if (ss_size < MINSIGSTKSZ)
+			if (ss_size < min_ss_size)
 				goto out;
 		}
 
@@ -3154,12 +3251,14 @@
 }
 SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
 {
-	return do_sigaltstack(uss, uoss, current_user_stack_pointer());
+	return do_sigaltstack(uss, uoss, current_user_stack_pointer(),
+			      MINSIGSTKSZ);
 }
 
 int restore_altstack(const stack_t __user *uss)
 {
-	int err = do_sigaltstack(uss, NULL, current_user_stack_pointer());
+	int err = do_sigaltstack(uss, NULL, current_user_stack_pointer(),
+				 MINSIGSTKSZ);
 	/* squash all but EFAULT for now */
 	return err == -EFAULT ? err : 0;
 }
@@ -3195,7 +3294,8 @@
 	set_fs(KERNEL_DS);
 	ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
 			     (stack_t __force __user *) &uoss,
-			     compat_user_stack_pointer());
+			     compat_user_stack_pointer(),
+			     COMPAT_MINSIGSTKSZ);
 	set_fs(seg);
 	if (ret >= 0 && uoss_ptr)  {
 		if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) ||
--- linux-4.4.0.orig/kernel/smp.c
+++ linux-4.4.0/kernel/smp.c
@@ -499,7 +499,6 @@
 unsigned int setup_max_cpus = NR_CPUS;
 EXPORT_SYMBOL(setup_max_cpus);
 
-
 /*
  * Setup routine for controlling SMP activation
  *
@@ -578,6 +577,24 @@
 			cpu_up(cpu);
 	}
 
+#ifdef CONFIG_HOTPLUG_SMT
+	/* Handle nosmt[=force] here */
+	if (cpu_smt_control == CPU_SMT_DISABLED ||
+	    cpu_smt_control == CPU_SMT_FORCE_DISABLED) {
+		int ret;
+
+		cpu_maps_update_begin();
+		for_each_online_cpu(cpu) {
+			if (topology_is_primary_thread(cpu))
+				continue;
+			ret = cpu_down_maps_locked(cpu);
+			if (ret)
+				break;
+		}
+		cpu_maps_update_done();
+	}
+#endif
+
 	/* Any cleanup work */
 	smp_announce();
 	smp_cpus_done(setup_max_cpus);
--- linux-4.4.0.orig/kernel/stop_machine.c
+++ linux-4.4.0/kernel/stop_machine.c
@@ -21,6 +21,7 @@
 #include <linux/smpboot.h>
 #include <linux/atomic.h>
 #include <linux/lglock.h>
+#include <linux/sched.h>
 
 /*
  * Structure to determine completion condition and record errors.  May
@@ -74,24 +75,30 @@
 }
 
 static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
-					struct cpu_stop_work *work)
+					struct cpu_stop_work *work,
+					struct wake_q_head *wakeq)
 {
 	list_add_tail(&work->list, &stopper->works);
-	wake_up_process(stopper->thread);
+	wake_q_add(wakeq, stopper->thread);
 }
 
 /* queue @work to @stopper.  if offline, @work is completed immediately */
 static void cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
 {
 	struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
+	WAKE_Q(wakeq);
 	unsigned long flags;
 
+	preempt_disable();
 	spin_lock_irqsave(&stopper->lock, flags);
 	if (stopper->enabled)
-		__cpu_stop_queue_work(stopper, work);
+		__cpu_stop_queue_work(stopper, work, &wakeq);
 	else
 		cpu_stop_signal_done(work->done, false);
 	spin_unlock_irqrestore(&stopper->lock, flags);
+
+	wake_up_q(&wakeq);
+	preempt_enable();
 }
 
 /**
@@ -221,6 +228,7 @@
 {
 	struct cpu_stopper *stopper1 = per_cpu_ptr(&cpu_stopper, cpu1);
 	struct cpu_stopper *stopper2 = per_cpu_ptr(&cpu_stopper, cpu2);
+	WAKE_Q(wakeq);
 	int err;
 
 	lg_double_lock(&stop_cpus_lock, cpu1, cpu2);
@@ -232,13 +240,27 @@
 		goto unlock;
 
 	err = 0;
-	__cpu_stop_queue_work(stopper1, work1);
-	__cpu_stop_queue_work(stopper2, work2);
+	__cpu_stop_queue_work(stopper1, work1, &wakeq);
+	__cpu_stop_queue_work(stopper2, work2, &wakeq);
+	/*
+	 * The waking up of stopper threads has to happen
+	 * in the same scheduling context as the queueing.
+	 * Otherwise, there is a possibility of one of the
+	 * above stoppers being woken up by another CPU,
+	 * and preempting us. This will cause us to n ot
+	 * wake up the other stopper forever.
+	 */
+	preempt_disable();
 unlock:
 	spin_unlock(&stopper2->lock);
 	spin_unlock_irq(&stopper1->lock);
 	lg_double_unlock(&stop_cpus_lock, cpu1, cpu2);
 
+	if (!err) {
+		wake_up_q(&wakeq);
+		preempt_enable();
+	}
+
 	return err;
 }
 /**
--- linux-4.4.0.orig/kernel/sys.c
+++ linux-4.4.0/kernel/sys.c
@@ -53,6 +53,8 @@
 #include <linux/uidgid.h>
 #include <linux/cred.h>
 
+#include <linux/nospec.h>
+
 #include <linux/kmsg_dump.h>
 /* Move somewhere else to avoid recompiling? */
 #include <generated/utsrelease.h>
@@ -1099,6 +1101,21 @@
 DECLARE_RWSEM(uts_sem);
 
 #ifdef COMPAT_UTS_MACHINE
+static char compat_uts_machine[__OLD_UTS_LEN+1] = COMPAT_UTS_MACHINE;
+
+static int __init parse_compat_uts_machine(char *arg)
+{
+	strncpy(compat_uts_machine, arg, __OLD_UTS_LEN);
+	compat_uts_machine[__OLD_UTS_LEN] = 0;
+	return 0;
+}
+early_param("compat_uts_machine", parse_compat_uts_machine);
+
+#undef COMPAT_UTS_MACHINE
+#define COMPAT_UTS_MACHINE compat_uts_machine
+#endif
+
+#ifdef COMPAT_UTS_MACHINE
 #define override_architecture(name) \
 	(personality(current->personality) == PER_LINUX32 && \
 	 copy_to_user(name->machine, COMPAT_UTS_MACHINE, \
@@ -1140,18 +1157,19 @@
 
 SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
 {
-	int errno = 0;
+	struct new_utsname tmp;
 
 	down_read(&uts_sem);
-	if (copy_to_user(name, utsname(), sizeof *name))
-		errno = -EFAULT;
+	memcpy(&tmp, utsname(), sizeof(tmp));
 	up_read(&uts_sem);
+	if (copy_to_user(name, &tmp, sizeof(tmp)))
+		return -EFAULT;
 
-	if (!errno && override_release(name->release, sizeof(name->release)))
-		errno = -EFAULT;
-	if (!errno && override_architecture(name))
-		errno = -EFAULT;
-	return errno;
+	if (override_release(name->release, sizeof(name->release)))
+		return -EFAULT;
+	if (override_architecture(name))
+		return -EFAULT;
+	return 0;
 }
 
 #ifdef __ARCH_WANT_SYS_OLD_UNAME
@@ -1160,55 +1178,48 @@
  */
 SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
 {
-	int error = 0;
+	struct old_utsname tmp;
 
 	if (!name)
 		return -EFAULT;
 
 	down_read(&uts_sem);
-	if (copy_to_user(name, utsname(), sizeof(*name)))
-		error = -EFAULT;
+	memcpy(&tmp, utsname(), sizeof(tmp));
 	up_read(&uts_sem);
+	if (copy_to_user(name, &tmp, sizeof(tmp)))
+		return -EFAULT;
 
-	if (!error && override_release(name->release, sizeof(name->release)))
-		error = -EFAULT;
-	if (!error && override_architecture(name))
-		error = -EFAULT;
-	return error;
+	if (override_release(name->release, sizeof(name->release)))
+		return -EFAULT;
+	if (override_architecture(name))
+		return -EFAULT;
+	return 0;
 }
 
 SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
 {
-	int error;
+	struct oldold_utsname tmp;
 
 	if (!name)
 		return -EFAULT;
-	if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
-		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
 
 	down_read(&uts_sem);
-	error = __copy_to_user(&name->sysname, &utsname()->sysname,
-			       __OLD_UTS_LEN);
-	error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
-	error |= __copy_to_user(&name->nodename, &utsname()->nodename,
-				__OLD_UTS_LEN);
-	error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
-	error |= __copy_to_user(&name->release, &utsname()->release,
-				__OLD_UTS_LEN);
-	error |= __put_user(0, name->release + __OLD_UTS_LEN);
-	error |= __copy_to_user(&name->version, &utsname()->version,
-				__OLD_UTS_LEN);
-	error |= __put_user(0, name->version + __OLD_UTS_LEN);
-	error |= __copy_to_user(&name->machine, &utsname()->machine,
-				__OLD_UTS_LEN);
-	error |= __put_user(0, name->machine + __OLD_UTS_LEN);
+	memcpy(&tmp.sysname, &utsname()->sysname, __OLD_UTS_LEN);
+	memcpy(&tmp.nodename, &utsname()->nodename, __OLD_UTS_LEN);
+	memcpy(&tmp.release, &utsname()->release, __OLD_UTS_LEN);
+	memcpy(&tmp.version, &utsname()->version, __OLD_UTS_LEN);
+	memcpy(&tmp.machine, &utsname()->machine, __OLD_UTS_LEN);
 	up_read(&uts_sem);
+	if (copy_to_user(name, &tmp, sizeof(tmp)))
+		return -EFAULT;
 
-	if (!error && override_architecture(name))
-		error = -EFAULT;
-	if (!error && override_release(name->release, sizeof(name->release)))
-		error = -EFAULT;
-	return error ? -EFAULT : 0;
+	if (override_architecture(name))
+		return -EFAULT;
+	if (override_release(name->release, sizeof(name->release)))
+		return -EFAULT;
+	return 0;
 }
 #endif
 
@@ -1222,17 +1233,18 @@
 
 	if (len < 0 || len > __NEW_UTS_LEN)
 		return -EINVAL;
-	down_write(&uts_sem);
 	errno = -EFAULT;
 	if (!copy_from_user(tmp, name, len)) {
-		struct new_utsname *u = utsname();
+		struct new_utsname *u;
 
+		down_write(&uts_sem);
+		u = utsname();
 		memcpy(u->nodename, tmp, len);
 		memset(u->nodename + len, 0, sizeof(u->nodename) - len);
 		errno = 0;
 		uts_proc_notify(UTS_PROC_HOSTNAME);
+		up_write(&uts_sem);
 	}
-	up_write(&uts_sem);
 	return errno;
 }
 
@@ -1240,8 +1252,9 @@
 
 SYSCALL_DEFINE2(gethostname, char __user *, name, int, len)
 {
-	int i, errno;
+	int i;
 	struct new_utsname *u;
+	char tmp[__NEW_UTS_LEN + 1];
 
 	if (len < 0)
 		return -EINVAL;
@@ -1250,11 +1263,11 @@
 	i = 1 + strlen(u->nodename);
 	if (i > len)
 		i = len;
-	errno = 0;
-	if (copy_to_user(name, u->nodename, i))
-		errno = -EFAULT;
+	memcpy(tmp, u->nodename, i);
 	up_read(&uts_sem);
-	return errno;
+	if (copy_to_user(name, tmp, i))
+		return -EFAULT;
+	return 0;
 }
 
 #endif
@@ -1273,17 +1286,18 @@
 	if (len < 0 || len > __NEW_UTS_LEN)
 		return -EINVAL;
 
-	down_write(&uts_sem);
 	errno = -EFAULT;
 	if (!copy_from_user(tmp, name, len)) {
-		struct new_utsname *u = utsname();
+		struct new_utsname *u;
 
+		down_write(&uts_sem);
+		u = utsname();
 		memcpy(u->domainname, tmp, len);
 		memset(u->domainname + len, 0, sizeof(u->domainname) - len);
 		errno = 0;
 		uts_proc_notify(UTS_PROC_DOMAINNAME);
+		up_write(&uts_sem);
 	}
-	up_write(&uts_sem);
 	return errno;
 }
 
@@ -1311,6 +1325,7 @@
 	if (resource >= RLIM_NLIMITS)
 		return -EINVAL;
 
+	resource = array_index_nospec(resource, RLIM_NLIMITS);
 	task_lock(current->group_leader);
 	x = current->signal->rlim[resource];
 	task_unlock(current->group_leader);
@@ -1365,6 +1380,8 @@
 
 	if (resource >= RLIM_NLIMITS)
 		return -EINVAL;
+	resource = array_index_nospec(resource, RLIM_NLIMITS);
+
 	if (new_rlim) {
 		if (new_rlim->rlim_cur > new_rlim->rlim_max)
 			return -EINVAL;
@@ -1764,7 +1781,7 @@
 	((unsigned long)prctl_map->__m1 __op				\
 	 (unsigned long)prctl_map->__m2) ? 0 : -EINVAL
 	error  = __prctl_check_order(start_code, <, end_code);
-	error |= __prctl_check_order(start_data, <, end_data);
+	error |= __prctl_check_order(start_data,<=, end_data);
 	error |= __prctl_check_order(start_brk, <=, brk);
 	error |= __prctl_check_order(arg_start, <=, arg_end);
 	error |= __prctl_check_order(env_start, <=, env_end);
@@ -1853,11 +1870,13 @@
 		user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL;
 	}
 
-	if (prctl_map.exe_fd != (u32)-1)
+	if (prctl_map.exe_fd != (u32)-1) {
 		error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd);
-	down_read(&mm->mmap_sem);
-	if (error)
-		goto out;
+		if (error)
+			return error;
+	}
+
+	down_write(&mm->mmap_sem);
 
 	/*
 	 * We don't validate if these members are pointing to
@@ -1894,10 +1913,8 @@
 	if (prctl_map.auxv_size)
 		memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv));
 
-	error = 0;
-out:
-	up_read(&mm->mmap_sem);
-	return error;
+	up_write(&mm->mmap_sem);
+	return 0;
 }
 #endif /* CONFIG_CHECKPOINT_RESTORE */
 
@@ -1963,7 +1980,7 @@
 
 	error = -EINVAL;
 
-	down_read(&mm->mmap_sem);
+	down_write(&mm->mmap_sem);
 	vma = find_vma(mm, addr);
 
 	prctl_map.start_code	= mm->start_code;
@@ -2056,7 +2073,7 @@
 
 	error = 0;
 out:
-	up_read(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 	return error;
 }
 
@@ -2072,6 +2089,17 @@
 }
 #endif
 
+int __weak arch_prctl_spec_ctrl_get(struct task_struct *t, unsigned long which)
+{
+	return -EINVAL;
+}
+
+int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which,
+				    unsigned long ctrl)
+{
+	return -EINVAL;
+}
+
 SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 		unsigned long, arg4, unsigned long, arg5)
 {
@@ -2266,6 +2294,16 @@
 	case PR_GET_FP_MODE:
 		error = GET_FP_MODE(me);
 		break;
+	case PR_GET_SPECULATION_CTRL:
+		if (arg3 || arg4 || arg5)
+			return -EINVAL;
+		error = arch_prctl_spec_ctrl_get(me, arg2);
+		break;
+	case PR_SET_SPECULATION_CTRL:
+		if (arg4 || arg5)
+			return -EINVAL;
+		error = arch_prctl_spec_ctrl_set(me, arg2, arg3);
+		break;
 	default:
 		error = -EINVAL;
 		break;
--- linux-4.4.0.orig/kernel/sysctl.c
+++ linux-4.4.0/kernel/sysctl.c
@@ -65,14 +65,21 @@
 #include <linux/sched/sysctl.h>
 #include <linux/kexec.h>
 #include <linux/bpf.h>
+#include <linux/efi.h>
+#include <linux/mount.h>
+
+#include "../lib/kstrtox.h"
 
 #include <asm/uaccess.h>
+#include <linux/mutex.h>
 #include <asm/processor.h>
 
 #ifdef CONFIG_X86
+#include <asm/msr.h>
 #include <asm/nmi.h>
 #include <asm/stacktrace.h>
 #include <asm/io.h>
+#include <asm/spec-ctrl.h>
 #endif
 #ifdef CONFIG_SPARC
 #include <asm/setup.h>
@@ -103,6 +110,9 @@
 extern char core_pattern[];
 extern unsigned int core_pipe_limit;
 #endif
+#ifdef CONFIG_USER_NS
+extern int unprivileged_userns_clone;
+#endif
 extern int pid_max;
 extern int pid_max_min, pid_max_max;
 extern int percpu_pagelist_fraction;
@@ -124,7 +134,9 @@
 static int __maybe_unused one = 1;
 static int __maybe_unused two = 2;
 static int __maybe_unused four = 4;
+static unsigned long zero_ul;
 static unsigned long one_ul = 1;
+static unsigned long long_max = LONG_MAX;
 static int one_hundred = 100;
 #ifdef CONFIG_PRINTK
 static int ten_thousand = 10000;
@@ -173,7 +185,7 @@
 #define SYSCTL_WRITES_WARN	 0
 #define SYSCTL_WRITES_STRICT	 1
 
-static int sysctl_writes_strict = SYSCTL_WRITES_WARN;
+static int sysctl_writes_strict = SYSCTL_WRITES_STRICT;
 
 static int proc_do_cad_pid(struct ctl_table *table, int write,
 		  void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -193,6 +205,123 @@
 		void __user *buffer, size_t *lenp, loff_t *ppos);
 #endif
 
+#ifdef CONFIG_X86
+/* Mutex to serialize IBPB and IBRS runtime control changes */
+DEFINE_MUTEX(ubuntu_spec_ctrl_mutex);
+
+unsigned int ibpb_enabled = 0;
+EXPORT_SYMBOL(ibpb_enabled);   /* Required in some modules */
+
+static unsigned int __ibpb_enabled = 0;   /* procfs shadow variable */
+
+int set_ibpb_enabled(unsigned int val)
+{
+	int error = 0;
+	unsigned int prev = ibpb_enabled;
+
+	mutex_lock(&ubuntu_spec_ctrl_mutex);
+
+	/* Only enable/disable IBPB if the CPU supports it */
+	if (boot_cpu_has(X86_FEATURE_USE_IBPB)) {
+		ibpb_enabled = val;
+		if (ibpb_enabled != prev)
+			pr_info("Spectre V2 : mitigation: %s "
+				"Indirect Branch Prediction Barrier\n",
+				ibpb_enabled ? "Enabling kernel" : "Disabling kernel");
+	} else {
+		ibpb_enabled = 0;
+		if (val) {
+			/* IBPB is not supported but we try to turn it on */
+			error = -EINVAL;
+		}
+	}
+
+	/* Update the shadow variable */
+	__ibpb_enabled = ibpb_enabled;
+
+	mutex_unlock(&ubuntu_spec_ctrl_mutex);
+
+	return error;
+}
+
+static int ibpb_enabled_handler(struct ctl_table *table, int write,
+				void __user *buffer, size_t *lenp,
+				loff_t *ppos)
+{
+	int error;
+
+	error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+	if (error)
+		return error;
+
+	return set_ibpb_enabled(__ibpb_enabled);
+}
+
+unsigned int ibrs_enabled = 0;
+EXPORT_SYMBOL(ibrs_enabled);   /* Required in some modules */
+
+static unsigned int __ibrs_enabled = 0;   /* procfs shadow variable */
+
+int set_ibrs_enabled(unsigned int val)
+{
+	int error = 0;
+	unsigned int cpu;
+	unsigned int prev = ibrs_enabled;
+
+	mutex_lock(&ubuntu_spec_ctrl_mutex);
+
+	/* Only enable/disable IBRS if the CPU supports it */
+	if (boot_cpu_has(X86_FEATURE_USE_IBRS_FW)) {
+		ibrs_enabled = val;
+		if (ibrs_enabled != prev)
+			pr_info("Spectre V2 : mitigation: %s "
+				"Indirect Branch Restricted Speculation\n",
+				ibrs_enabled == 2 ? "Enabling kernel+user" :
+				ibrs_enabled ? "Enabling kernel" : "Disabling");
+
+		if (ibrs_enabled == 0) {
+			/* Always disable IBRS */
+			u64 val = x86_spec_ctrl_base;
+
+			for_each_online_cpu(cpu)
+				wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, val);
+		} else if (ibrs_enabled == 2) {
+			/* Always enable IBRS, even in user space */
+			u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;
+
+			for_each_online_cpu(cpu)
+				wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, val);
+		}
+	} else {
+		ibrs_enabled = 0;
+		if (val) {
+			/* IBRS is not supported but we try to turn it on */
+			error = -EINVAL;
+		}
+	}
+
+	/* Update the shadow variable */
+	__ibrs_enabled = ibrs_enabled;
+
+	mutex_unlock(&ubuntu_spec_ctrl_mutex);
+
+	return error;
+}
+
+static int ibrs_enabled_handler(struct ctl_table *table, int write,
+                               void __user *buffer, size_t *lenp,
+                               loff_t *ppos)
+{
+	int error;
+
+	error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+	if (error)
+		return error;
+
+	return set_ibrs_enabled(__ibrs_enabled);
+}
+#endif
+
 #ifdef CONFIG_MAGIC_SYSRQ
 /* Note: sysrq code uses it's own private copy */
 static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
@@ -215,6 +344,28 @@
 
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int bpf_unpriv_handler(struct ctl_table *table, int write,
+                             void *buffer, size_t *lenp, loff_t *ppos)
+{
+	int ret, unpriv_enable = *(int *)table->data;
+	bool locked_state = unpriv_enable == 1;
+	struct ctl_table tmp = *table;
+
+	if (write && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	tmp.data = &unpriv_enable;
+	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
+	if (write && !ret) {
+		if (locked_state && unpriv_enable != 1)
+			return -EPERM;
+		*(int *)table->data = unpriv_enable;
+	}
+	return ret;
+}
+#endif
+
 static struct ctl_table kern_table[];
 static struct ctl_table vm_table[];
 static struct ctl_table fs_table[];
@@ -276,8 +427,38 @@
 static int max_extfrag_threshold = 1000;
 #endif
 
+static unsigned int secure_boot_enabled;
+int secure_boot_proc_handler(struct ctl_table *table, int write,
+	void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	secure_boot_enabled = efi_enabled(EFI_SECURE_BOOT);
+	return proc_dointvec(table, write, buffer, lenp, ppos);
+}
+
+static unsigned int moksbstate_disabled;
+int moksbstate_disabled_proc_handler(struct ctl_table *table, int write,
+	void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	moksbstate_disabled = efi_enabled(EFI_MOKSBSTATE_DISABLED);
+	return proc_dointvec(table, write, buffer, lenp, ppos);
+}
+
 static struct ctl_table kern_table[] = {
 	{
+		.procname   = "secure_boot",
+		.data       = &secure_boot_enabled,
+		.maxlen     = sizeof(unsigned int),
+		.mode       = 0444,
+		.proc_handler   = secure_boot_proc_handler,
+	},
+	{
+		.procname   = "moksbstate_disabled",
+		.data       = &moksbstate_disabled,
+		.maxlen     = sizeof(unsigned int),
+		.mode       = 0444,
+		.proc_handler   = moksbstate_disabled_proc_handler,
+	},
+	{
 		.procname	= "sched_child_runs_first",
 		.data		= &sysctl_sched_child_runs_first,
 		.maxlen		= sizeof(unsigned int),
@@ -341,7 +522,8 @@
 		.data		= &sysctl_sched_time_avg,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &one,
 	},
 	{
 		.procname	= "sched_shares_window_ns",
@@ -408,7 +590,7 @@
 	},
 	{
 		.procname	= "sched_rr_timeslice_ms",
-		.data		= &sched_rr_timeslice,
+		.data		= &sysctl_sched_rr_timeslice,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= sched_rr_handler,
@@ -482,6 +664,15 @@
 		.proc_handler	= proc_dointvec,
 	},
 #endif
+#ifdef CONFIG_USER_NS
+	{
+		.procname	= "unprivileged_userns_clone",
+		.data		= &unprivileged_userns_clone,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+#endif
 #ifdef CONFIG_PROC_SYSCTL
 	{
 		.procname	= "tainted",
@@ -1158,6 +1349,8 @@
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= timer_migration_handler,
+		.extra1		= &zero,
+		.extra2		= &one,
 	},
 #endif
 #ifdef CONFIG_BPF_SYSCALL
@@ -1166,9 +1359,28 @@
 		.data		= &sysctl_unprivileged_bpf_disabled,
 		.maxlen		= sizeof(sysctl_unprivileged_bpf_disabled),
 		.mode		= 0644,
-		/* only handle a transition from default "0" to "1" */
-		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &one,
+		.proc_handler	= bpf_unpriv_handler,
+		.extra1		= &zero,
+		.extra2		= &two,
+	},
+#endif
+#ifdef CONFIG_X86
+	{
+		.procname       = "ibrs_enabled",
+		.data           = &__ibrs_enabled,
+		.maxlen         = sizeof(unsigned int),
+		.mode           = 0644,
+		.proc_handler   = ibrs_enabled_handler,
+		.extra1         = &zero,
+		.extra2         = &two,
+	},
+	{
+		.procname	= "ibpb_enabled",
+		.data		= &__ibpb_enabled,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler   = ibpb_enabled_handler,
+		.extra1		= &zero,
 		.extra2		= &one,
 	},
 #endif
@@ -1351,7 +1563,7 @@
 		.procname	= "drop_caches",
 		.data		= &sysctl_drop_caches,
 		.maxlen		= sizeof(int),
-		.mode		= 0644,
+		.mode		= 0200,
 		.proc_handler	= drop_caches_sysctl_handler,
 		.extra1		= &one,
 		.extra2		= &four,
@@ -1599,6 +1811,8 @@
 		.maxlen		= sizeof(files_stat.max_files),
 		.mode		= 0644,
 		.proc_handler	= proc_doulongvec_minmax,
+		.extra1		= &zero_ul,
+		.extra2		= &long_max,
 	},
 	{
 		.procname	= "nr_open",
@@ -1712,6 +1926,24 @@
 		.extra2		= &one,
 	},
 	{
+		.procname	= "protected_fifos",
+		.data		= &sysctl_protected_fifos,
+		.maxlen		= sizeof(int),
+		.mode		= 0600,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &two,
+	},
+	{
+		.procname	= "protected_regular",
+		.data		= &sysctl_protected_regular,
+		.maxlen		= sizeof(int),
+		.mode		= 0600,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &two,
+	},
+	{
 		.procname	= "suid_dumpable",
 		.data		= &suid_dumpable,
 		.maxlen		= sizeof(int),
@@ -1735,6 +1967,28 @@
 		.proc_handler	= &pipe_proc_fn,
 		.extra1		= &pipe_min_size,
 	},
+	{
+		.procname	= "pipe-user-pages-hard",
+		.data		= &pipe_user_pages_hard,
+		.maxlen		= sizeof(pipe_user_pages_hard),
+		.mode		= 0644,
+		.proc_handler	= proc_doulongvec_minmax,
+	},
+	{
+		.procname	= "pipe-user-pages-soft",
+		.data		= &pipe_user_pages_soft,
+		.maxlen		= sizeof(pipe_user_pages_soft),
+		.mode		= 0644,
+		.proc_handler	= proc_doulongvec_minmax,
+	},
+	{
+		.procname	= "mount-max",
+		.data		= &sysctl_mount_max,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &one,
+	},
 	{ }
 };
 
@@ -1904,6 +2158,41 @@
 	}
 }
 
+/**
+ * strtoul_lenient - parse an ASCII formatted integer from a buffer and only
+ *                   fail on overflow
+ *
+ * @cp: kernel buffer containing the string to parse
+ * @endp: pointer to store the trailing characters
+ * @base: the base to use
+ * @res: where the parsed integer will be stored
+ *
+ * In case of success 0 is returned and @res will contain the parsed integer,
+ * @endp will hold any trailing characters.
+ * This function will fail the parse on overflow. If there wasn't an overflow
+ * the function will defer the decision what characters count as invalid to the
+ * caller.
+ */
+static int strtoul_lenient(const char *cp, char **endp, unsigned int base,
+			   unsigned long *res)
+{
+	unsigned long long result;
+	unsigned int rv;
+
+	cp = _parse_integer_fixup_radix(cp, &base);
+	rv = _parse_integer(cp, base, &result);
+	if ((rv & KSTRTOX_OVERFLOW) || (result != (unsigned long)result))
+		return -ERANGE;
+
+	cp += rv;
+
+	if (endp)
+		*endp = (char *)cp;
+
+	*res = (unsigned long)result;
+	return 0;
+}
+
 #define TMPBUFLEN 22
 /**
  * proc_get_long - reads an ASCII formatted integer from a user buffer
@@ -1947,7 +2236,8 @@
 	if (!isdigit(*p))
 		return -EINVAL;
 
-	*val = simple_strtoul(p, &p, 0);
+	if (strtoul_lenient(p, &p, 0, val))
+		return -EINVAL;
 
 	len = p - tmp;
 
@@ -2037,6 +2327,24 @@
 	return 0;
 }
 
+static int do_proc_douintvec_conv(bool *negp, unsigned long *lvalp,
+				 int *valp,
+				 int write, void *data)
+{
+	if (write) {
+		if (*negp)
+			return -EINVAL;
+		if (*lvalp > UINT_MAX)
+			return -EINVAL;
+		*valp = *lvalp;
+	} else {
+		unsigned int val = *valp;
+		*negp = false;
+		*lvalp = (unsigned long)val;
+	}
+	return 0;
+}
+
 static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
 
 static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
@@ -2164,8 +2472,27 @@
 int proc_dointvec(struct ctl_table *table, int write,
 		     void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-    return do_proc_dointvec(table,write,buffer,lenp,ppos,
-		    	    NULL,NULL);
+	return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL);
+}
+
+/**
+ * proc_douintvec - read a vector of unsigned integers
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
+ * values from/to the user buffer, treated as an ASCII string.
+ *
+ * Returns 0 on success.
+ */
+int proc_douintvec(struct ctl_table *table, int write,
+		     void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	return do_proc_dointvec(table, write, buffer, lenp, ppos,
+				do_proc_douintvec_conv, NULL);
 }
 
 /*
@@ -2225,7 +2552,16 @@
 {
 	struct do_proc_dointvec_minmax_conv_param *param = data;
 	if (write) {
-		int val = *negp ? -*lvalp : *lvalp;
+		int val;
+		if (*negp) {
+			if (*lvalp > (unsigned long) INT_MAX + 1)
+				return -EINVAL;
+			val = -*lvalp;
+		} else {
+			if (*lvalp > (unsigned long) INT_MAX)
+				return -EINVAL;
+			val = *lvalp;
+		}
 		if ((param->min && *param->min > val) ||
 		    (param->max && *param->max < val))
 			return -EINVAL;
@@ -2366,8 +2702,11 @@
 				break;
 			if (neg)
 				continue;
-			if ((min && val < *min) || (max && val > *max))
-				continue;
+			val = convmul * val / convdiv;
+			if ((min && val < *min) || (max && val > *max)) {
+				err = -EINVAL;
+				break;
+			}
 			*i = val;
 		} else {
 			val = convdiv * (*i) / convmul;
@@ -2778,6 +3117,12 @@
 	return -ENOSYS;
 }
 
+int proc_douintvec(struct ctl_table *table, int write,
+		  void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	return -ENOSYS;
+}
+
 int proc_dointvec_minmax(struct ctl_table *table, int write,
 		    void __user *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -2823,6 +3168,7 @@
  * exception granted :-)
  */
 EXPORT_SYMBOL(proc_dointvec);
+EXPORT_SYMBOL(proc_douintvec);
 EXPORT_SYMBOL(proc_dointvec_jiffies);
 EXPORT_SYMBOL(proc_dointvec_minmax);
 EXPORT_SYMBOL(proc_dointvec_userhz_jiffies);
--- linux-4.4.0.orig/kernel/sysctl_binary.c
+++ linux-4.4.0/kernel/sysctl_binary.c
@@ -1321,7 +1321,7 @@
 	}
 
 	mnt = task_active_pid_ns(current)->proc_mnt;
-	file = file_open_root(mnt->mnt_root, mnt, pathname, flags);
+	file = file_open_root(mnt->mnt_root, mnt, pathname, flags, 0);
 	result = PTR_ERR(file);
 	if (IS_ERR(file))
 		goto out_putname;
--- linux-4.4.0.orig/kernel/taskstats.c
+++ linux-4.4.0/kernel/taskstats.c
@@ -582,25 +582,33 @@
 static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
 {
 	struct signal_struct *sig = tsk->signal;
-	struct taskstats *stats;
+	struct taskstats *stats_new, *stats;
 
-	if (sig->stats || thread_group_empty(tsk))
-		goto ret;
+	/* Pairs with smp_store_release() below. */
+	stats = smp_load_acquire(&sig->stats);
+	if (stats || thread_group_empty(tsk))
+		return stats;
 
 	/* No problem if kmem_cache_zalloc() fails */
-	stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
+	stats_new = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
 
 	spin_lock_irq(&tsk->sighand->siglock);
-	if (!sig->stats) {
-		sig->stats = stats;
-		stats = NULL;
+	stats = sig->stats;
+	if (!stats) {
+		/*
+		 * Pairs with smp_store_release() above and order the
+		 * kmem_cache_zalloc().
+		 */
+		smp_store_release(&sig->stats, stats_new);
+		stats = stats_new;
+		stats_new = NULL;
 	}
 	spin_unlock_irq(&tsk->sighand->siglock);
 
-	if (stats)
-		kmem_cache_free(taskstats_cache, stats);
-ret:
-	return sig->stats;
+	if (stats_new)
+		kmem_cache_free(taskstats_cache, stats_new);
+
+	return stats;
 }
 
 /* Send pid data out on exit */
--- linux-4.4.0.orig/kernel/time/Makefile
+++ linux-4.4.0/kernel/time/Makefile
@@ -9,6 +9,5 @@
 endif
 obj-$(CONFIG_GENERIC_SCHED_CLOCK)		+= sched_clock.o
 obj-$(CONFIG_TICK_ONESHOT)			+= tick-oneshot.o tick-sched.o
-obj-$(CONFIG_TIMER_STATS)			+= timer_stats.o
 obj-$(CONFIG_DEBUG_FS)				+= timekeeping_debug.o
 obj-$(CONFIG_TEST_UDELAY)			+= test_udelay.o
--- linux-4.4.0.orig/kernel/time/alarmtimer.c
+++ linux-4.4.0/kernel/time/alarmtimer.c
@@ -339,7 +339,7 @@
 {
 	struct alarm_base *base = &alarm_bases[alarm->type];
 
-	start = ktime_add(start, base->gettime());
+	start = ktime_add_safe(start, base->gettime());
 	alarm_start(alarm, start);
 }
 EXPORT_SYMBOL_GPL(alarm_start_relative);
@@ -425,7 +425,7 @@
 		overrun++;
 	}
 
-	alarm->node.expires = ktime_add(alarm->node.expires, interval);
+	alarm->node.expires = ktime_add_safe(alarm->node.expires, interval);
 	return overrun;
 }
 EXPORT_SYMBOL_GPL(alarm_forward);
@@ -530,7 +530,7 @@
 	struct alarm_base *base;
 
 	if (!alarmtimer_get_rtcdev())
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	if (!capable(CAP_WAKE_ALARM))
 		return -EPERM;
@@ -573,7 +573,7 @@
 static int alarm_timer_del(struct k_itimer *timr)
 {
 	if (!rtcdev)
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0)
 		return TIMER_RETRY;
@@ -597,7 +597,7 @@
 	ktime_t exp;
 
 	if (!rtcdev)
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	if (flags & ~TIMER_ABSTIME)
 		return -EINVAL;
@@ -611,13 +611,22 @@
 
 	/* start the timer */
 	timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval);
+
+	/*
+	 * Rate limit to the tick as a hot fix to prevent DOS. Will be
+	 * mopped up later.
+	 */
+	if (timr->it.alarm.interval.tv64 &&
+			ktime_to_ns(timr->it.alarm.interval) < TICK_NSEC)
+		timr->it.alarm.interval = ktime_set(0, TICK_NSEC);
+
 	exp = timespec_to_ktime(new_setting->it_value);
 	/* Convert (if necessary) to absolute time */
 	if (flags != TIMER_ABSTIME) {
 		ktime_t now;
 
 		now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime();
-		exp = ktime_add(now, exp);
+		exp = ktime_add_safe(now, exp);
 	}
 
 	alarm_start(&timr->it.alarm.alarmtimer, exp);
@@ -750,7 +759,7 @@
 	struct restart_block *restart;
 
 	if (!alarmtimer_get_rtcdev())
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	if (flags & ~TIMER_ABSTIME)
 		return -EINVAL;
@@ -764,7 +773,8 @@
 	/* Convert (if necessary) to absolute time */
 	if (flags != TIMER_ABSTIME) {
 		ktime_t now = alarm_bases[type].gettime();
-		exp = ktime_add(now, exp);
+
+		exp = ktime_add_safe(now, exp);
 	}
 
 	if (alarmtimer_do_nsleep(&alarm, exp))
--- linux-4.4.0.orig/kernel/time/clocksource.c
+++ linux-4.4.0/kernel/time/clocksource.c
@@ -272,8 +272,15 @@
 	next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask);
 	if (next_cpu >= nr_cpu_ids)
 		next_cpu = cpumask_first(cpu_online_mask);
-	watchdog_timer.expires += WATCHDOG_INTERVAL;
-	add_timer_on(&watchdog_timer, next_cpu);
+
+	/*
+	 * Arm timer if not already pending: could race with concurrent
+	 * pair clocksource_stop_watchdog() clocksource_start_watchdog().
+	 */
+	if (!timer_pending(&watchdog_timer)) {
+		watchdog_timer.expires += WATCHDOG_INTERVAL;
+		add_timer_on(&watchdog_timer, next_cpu);
+	}
 out:
 	spin_unlock(&watchdog_lock);
 }
@@ -323,13 +330,42 @@
 		/* cs is a watchdog. */
 		if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
 			cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
+	}
+	spin_unlock_irqrestore(&watchdog_lock, flags);
+}
+
+static void clocksource_select_watchdog(bool fallback)
+{
+	struct clocksource *cs, *old_wd;
+	unsigned long flags;
+
+	spin_lock_irqsave(&watchdog_lock, flags);
+	/* save current watchdog */
+	old_wd = watchdog;
+	if (fallback)
+		watchdog = NULL;
+
+	list_for_each_entry(cs, &clocksource_list, list) {
+		/* cs is a clocksource to be watched. */
+		if (cs->flags & CLOCK_SOURCE_MUST_VERIFY)
+			continue;
+
+		/* Skip current if we were requested for a fallback. */
+		if (fallback && cs == old_wd)
+			continue;
+
 		/* Pick the best watchdog. */
-		if (!watchdog || cs->rating > watchdog->rating) {
+		if (!watchdog || cs->rating > watchdog->rating)
 			watchdog = cs;
-			/* Reset watchdog cycles */
-			clocksource_reset_watchdog();
-		}
 	}
+	/* If we failed to find a fallback restore the old one. */
+	if (!watchdog)
+		watchdog = old_wd;
+
+	/* If we changed the watchdog we need to reset cycles. */
+	if (watchdog != old_wd)
+		clocksource_reset_watchdog();
+
 	/* Check if the watchdog timer needs to be started. */
 	clocksource_start_watchdog();
 	spin_unlock_irqrestore(&watchdog_lock, flags);
@@ -404,6 +440,7 @@
 		cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
 }
 
+static void clocksource_select_watchdog(bool fallback) { }
 static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { }
 static inline void clocksource_resume_watchdog(void) { }
 static inline int __clocksource_watchdog_kthread(void) { return 0; }
@@ -570,9 +607,18 @@
 		 */
 		if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && oneshot) {
 			/* Override clocksource cannot be used. */
-			pr_warn("Override clocksource %s is not HRT compatible - cannot switch while in HRT/NOHZ mode\n",
-				cs->name);
-			override_name[0] = 0;
+			if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
+				pr_warn("Override clocksource %s is unstable and not HRT compatible - cannot switch while in HRT/NOHZ mode\n",
+					cs->name);
+				override_name[0] = 0;
+			} else {
+				/*
+				 * The override cannot be currently verified.
+				 * Deferring to let the watchdog check.
+				 */
+				pr_info("Override clocksource %s is not currently HRT compatible - deferring\n",
+					cs->name);
+			}
 		} else
 			/* Override clocksource can be used. */
 			best = cs;
@@ -736,6 +782,7 @@
 	clocksource_enqueue(cs);
 	clocksource_enqueue_watchdog(cs);
 	clocksource_select();
+	clocksource_select_watchdog(false);
 	mutex_unlock(&clocksource_mutex);
 	return 0;
 }
@@ -758,6 +805,7 @@
 	mutex_lock(&clocksource_mutex);
 	__clocksource_change_rating(cs, rating);
 	clocksource_select();
+	clocksource_select_watchdog(false);
 	mutex_unlock(&clocksource_mutex);
 }
 EXPORT_SYMBOL(clocksource_change_rating);
@@ -767,12 +815,12 @@
  */
 static int clocksource_unbind(struct clocksource *cs)
 {
-	/*
-	 * I really can't convince myself to support this on hardware
-	 * designed by lobotomized monkeys.
-	 */
-	if (clocksource_is_watchdog(cs))
-		return -EBUSY;
+	if (clocksource_is_watchdog(cs)) {
+		/* Select and try to install a replacement watchdog. */
+		clocksource_select_watchdog(true);
+		if (clocksource_is_watchdog(cs))
+			return -EBUSY;
+	}
 
 	if (cs == curr_clocksource) {
 		/* Select and try to install a replacement clock source */
--- linux-4.4.0.orig/kernel/time/hrtimer.c
+++ linux-4.4.0/kernel/time/hrtimer.c
@@ -307,7 +307,7 @@
  */
 ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs)
 {
-	ktime_t res = ktime_add(lhs, rhs);
+	ktime_t res = ktime_add_unsafe(lhs, rhs);
 
 	/*
 	 * We use KTIME_SEC_MAX here, the maximum timeout which we can
@@ -664,7 +664,9 @@
 static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
 {
 	base->expires_next.tv64 = KTIME_MAX;
+	base->hang_detected = 0;
 	base->hres_active = 0;
+	base->next_timer = NULL;
 }
 
 /*
@@ -776,34 +778,6 @@
 	clock_was_set_delayed();
 }
 
-static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer)
-{
-#ifdef CONFIG_TIMER_STATS
-	if (timer->start_site)
-		return;
-	timer->start_site = __builtin_return_address(0);
-	memcpy(timer->start_comm, current->comm, TASK_COMM_LEN);
-	timer->start_pid = current->pid;
-#endif
-}
-
-static inline void timer_stats_hrtimer_clear_start_info(struct hrtimer *timer)
-{
-#ifdef CONFIG_TIMER_STATS
-	timer->start_site = NULL;
-#endif
-}
-
-static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
-{
-#ifdef CONFIG_TIMER_STATS
-	if (likely(!timer_stats_active))
-		return;
-	timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
-				 timer->function, timer->start_comm, 0);
-#endif
-}
-
 /*
  * Counterpart to lock_hrtimer_base above:
  */
@@ -880,7 +854,8 @@
 
 	base->cpu_base->active_bases |= 1 << base->index;
 
-	timer->state = HRTIMER_STATE_ENQUEUED;
+	/* Pairs with the lockless read in hrtimer_is_queued() */
+	WRITE_ONCE(timer->state, HRTIMER_STATE_ENQUEUED);
 
 	return timerqueue_add(&base->active, &timer->node);
 }
@@ -897,12 +872,13 @@
  */
 static void __remove_hrtimer(struct hrtimer *timer,
 			     struct hrtimer_clock_base *base,
-			     unsigned long newstate, int reprogram)
+			     u8 newstate, int reprogram)
 {
 	struct hrtimer_cpu_base *cpu_base = base->cpu_base;
-	unsigned int state = timer->state;
+	u8 state = timer->state;
 
-	timer->state = newstate;
+	/* Pairs with the lockless read in hrtimer_is_queued() */
+	WRITE_ONCE(timer->state, newstate);
 	if (!(state & HRTIMER_STATE_ENQUEUED))
 		return;
 
@@ -929,8 +905,9 @@
 static inline int
 remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool restart)
 {
-	if (hrtimer_is_queued(timer)) {
-		unsigned long state = timer->state;
+	u8 state = timer->state;
+
+	if (state & HRTIMER_STATE_ENQUEUED) {
 		int reprogram;
 
 		/*
@@ -942,7 +919,6 @@
 		 * rare case and less expensive than a smp call.
 		 */
 		debug_deactivate(timer);
-		timer_stats_hrtimer_clear_start_info(timer);
 		reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases);
 
 		if (!restart)
@@ -954,6 +930,22 @@
 	return 0;
 }
 
+static inline ktime_t hrtimer_update_lowres(struct hrtimer *timer, ktime_t tim,
+					    const enum hrtimer_mode mode)
+{
+#ifdef CONFIG_TIME_LOW_RES
+	/*
+	 * CONFIG_TIME_LOW_RES indicates that the system has no way to return
+	 * granular time values. For relative timers we add hrtimer_resolution
+	 * (i.e. one jiffie) to prevent short timeouts.
+	 */
+	timer->is_rel = mode & HRTIMER_MODE_REL;
+	if (timer->is_rel)
+		tim = ktime_add_safe(tim, ktime_set(0, hrtimer_resolution));
+#endif
+	return tim;
+}
+
 /**
  * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
  * @timer:	the timer to be added
@@ -974,27 +966,16 @@
 	/* Remove an active timer from the queue: */
 	remove_hrtimer(timer, base, true);
 
-	if (mode & HRTIMER_MODE_REL) {
+	if (mode & HRTIMER_MODE_REL)
 		tim = ktime_add_safe(tim, base->get_time());
-		/*
-		 * CONFIG_TIME_LOW_RES is a temporary way for architectures
-		 * to signal that they simply return xtime in
-		 * do_gettimeoffset(). In this case we want to round up by
-		 * resolution when starting a relative timer, to avoid short
-		 * timeouts. This will go away with the GTOD framework.
-		 */
-#ifdef CONFIG_TIME_LOW_RES
-		tim = ktime_add_safe(tim, ktime_set(0, hrtimer_resolution));
-#endif
-	}
+
+	tim = hrtimer_update_lowres(timer, tim, mode);
 
 	hrtimer_set_expires_range_ns(timer, tim, delta_ns);
 
 	/* Switch the timer base, if necessary: */
 	new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
 
-	timer_stats_hrtimer_set_start_info(timer);
-
 	leftmost = enqueue_hrtimer(timer, new_base);
 	if (!leftmost)
 		goto unlock;
@@ -1074,19 +1055,23 @@
 /**
  * hrtimer_get_remaining - get remaining time for the timer
  * @timer:	the timer to read
+ * @adjust:	adjust relative timers when CONFIG_TIME_LOW_RES=y
  */
-ktime_t hrtimer_get_remaining(const struct hrtimer *timer)
+ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust)
 {
 	unsigned long flags;
 	ktime_t rem;
 
 	lock_hrtimer_base(timer, &flags);
-	rem = hrtimer_expires_remaining(timer);
+	if (IS_ENABLED(CONFIG_TIME_LOW_RES) && adjust)
+		rem = hrtimer_expires_remaining_adjusted(timer);
+	else
+		rem = hrtimer_expires_remaining(timer);
 	unlock_hrtimer_base(timer, &flags);
 
 	return rem;
 }
-EXPORT_SYMBOL_GPL(hrtimer_get_remaining);
+EXPORT_SYMBOL_GPL(__hrtimer_get_remaining);
 
 #ifdef CONFIG_NO_HZ_COMMON
 /**
@@ -1121,18 +1106,17 @@
 
 	cpu_base = raw_cpu_ptr(&hrtimer_bases);
 
-	if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS)
+	/*
+	 * POSIX magic: Relative CLOCK_REALTIME timers are not affected by
+	 * clock modifications, so they needs to become CLOCK_MONOTONIC to
+	 * ensure POSIX compliance.
+	 */
+	if (clock_id == CLOCK_REALTIME && mode & HRTIMER_MODE_REL)
 		clock_id = CLOCK_MONOTONIC;
 
 	base = hrtimer_clockid_to_base(clock_id);
 	timer->base = &cpu_base->clock_base[base];
 	timerqueue_init(&timer->node);
-
-#ifdef CONFIG_TIMER_STATS
-	timer->start_site = NULL;
-	timer->start_pid = -1;
-	memset(timer->start_comm, 0, TASK_COMM_LEN);
-#endif
 }
 
 /**
@@ -1216,10 +1200,17 @@
 	raw_write_seqcount_barrier(&cpu_base->seq);
 
 	__remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, 0);
-	timer_stats_account_hrtimer(timer);
 	fn = timer->function;
 
 	/*
+	 * Clear the 'is relative' flag for the TIME_LOW_RES case. If the
+	 * timer is restarted with a period then it becomes an absolute
+	 * timer. If its not restarted it does not matter.
+	 */
+	if (IS_ENABLED(CONFIG_TIME_LOW_RES))
+		timer->is_rel = false;
+
+	/*
 	 * Because we run timers from hardirq context, there is no chance
 	 * they get migrated to another cpu, therefore its safe to unlock
 	 * the timer base.
@@ -1591,6 +1582,7 @@
 		timerqueue_init_head(&cpu_base->clock_base[i].active);
 	}
 
+	cpu_base->active_bases = 0;
 	cpu_base->cpu = cpu;
 	hrtimer_init_hres(cpu_base);
 }
--- linux-4.4.0.orig/kernel/time/itimer.c
+++ linux-4.4.0/kernel/time/itimer.c
@@ -26,7 +26,7 @@
  */
 static struct timeval itimer_get_remtime(struct hrtimer *timer)
 {
-	ktime_t rem = hrtimer_get_remaining(timer);
+	ktime_t rem = __hrtimer_get_remaining(timer, true);
 
 	/*
 	 * Racy but safe: if the itimer expires after the above
--- linux-4.4.0.orig/kernel/time/ntp.c
+++ linux-4.4.0/kernel/time/ntp.c
@@ -39,6 +39,7 @@
 #define MAX_TICKADJ		500LL		/* usecs */
 #define MAX_TICKADJ_SCALED \
 	(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
+#define MAX_TAI_OFFSET		100000
 
 /*
  * phase-lock loop variables
@@ -633,7 +634,8 @@
 		time_constant = max(time_constant, 0l);
 	}
 
-	if (txc->modes & ADJ_TAI && txc->constant > 0)
+	if (txc->modes & ADJ_TAI &&
+			txc->constant >= 0 && txc->constant <= MAX_TAI_OFFSET)
 		*time_tai = txc->constant;
 
 	if (txc->modes & ADJ_OFFSET)
@@ -674,8 +676,24 @@
 			return -EINVAL;
 	}
 
-	if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
-		return -EPERM;
+	if (txc->modes & ADJ_SETOFFSET) {
+		/* In order to inject time, you gotta be super-user! */
+		if (!capable(CAP_SYS_TIME))
+			return -EPERM;
+
+		if (txc->modes & ADJ_NANO) {
+			struct timespec ts;
+
+			ts.tv_sec = txc->time.tv_sec;
+			ts.tv_nsec = txc->time.tv_usec;
+			if (!timespec_inject_offset_valid(&ts))
+				return -EINVAL;
+
+		} else {
+			if (!timeval_inject_offset_valid(&txc->time))
+				return -EINVAL;
+		}
+	}
 
 	/*
 	 * Check for potential multiplication overflows that can
--- linux-4.4.0.orig/kernel/time/posix-clock.c
+++ linux-4.4.0/kernel/time/posix-clock.c
@@ -25,8 +25,6 @@
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
 
-static void delete_clock(struct kref *kref);
-
 /*
  * Returns NULL if the posix_clock instance attached to 'fp' is old and stale.
  */
@@ -69,10 +67,10 @@
 static unsigned int posix_clock_poll(struct file *fp, poll_table *wait)
 {
 	struct posix_clock *clk = get_posix_clock(fp);
-	int result = 0;
+	unsigned int result = 0;
 
 	if (!clk)
-		return -ENODEV;
+		return POLLERR;
 
 	if (clk->ops.poll)
 		result = clk->ops.poll(clk, fp, wait);
@@ -168,7 +166,7 @@
 		err = 0;
 
 	if (!err) {
-		kref_get(&clk->kref);
+		get_device(clk->dev);
 		fp->private_data = clk;
 	}
 out:
@@ -184,7 +182,7 @@
 	if (clk->ops.release)
 		err = clk->ops.release(clk);
 
-	kref_put(&clk->kref, delete_clock);
+	put_device(clk->dev);
 
 	fp->private_data = NULL;
 
@@ -206,38 +204,35 @@
 #endif
 };
 
-int posix_clock_register(struct posix_clock *clk, dev_t devid)
+int posix_clock_register(struct posix_clock *clk, struct device *dev)
 {
 	int err;
 
-	kref_init(&clk->kref);
 	init_rwsem(&clk->rwsem);
 
 	cdev_init(&clk->cdev, &posix_clock_file_operations);
+	err = cdev_device_add(&clk->cdev, dev);
+	if (err) {
+		pr_err("%s unable to add device %d:%d\n",
+			dev_name(dev), MAJOR(dev->devt), MINOR(dev->devt));
+		return err;
+	}
 	clk->cdev.owner = clk->ops.owner;
-	err = cdev_add(&clk->cdev, devid, 1);
+	clk->dev = dev;
 
-	return err;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(posix_clock_register);
 
-static void delete_clock(struct kref *kref)
-{
-	struct posix_clock *clk = container_of(kref, struct posix_clock, kref);
-
-	if (clk->release)
-		clk->release(clk);
-}
-
 void posix_clock_unregister(struct posix_clock *clk)
 {
-	cdev_del(&clk->cdev);
+	cdev_device_del(&clk->cdev, clk->dev);
 
 	down_write(&clk->rwsem);
 	clk->zombie = true;
 	up_write(&clk->rwsem);
 
-	kref_put(&clk->kref, delete_clock);
+	put_device(clk->dev);
 }
 EXPORT_SYMBOL_GPL(posix_clock_unregister);
 
@@ -300,14 +295,17 @@
 static int pc_clock_gettime(clockid_t id, struct timespec *ts)
 {
 	struct posix_clock_desc cd;
+	struct timespec64 ts64;
 	int err;
 
 	err = get_clock_desc(id, &cd);
 	if (err)
 		return err;
 
-	if (cd.clk->ops.clock_gettime)
-		err = cd.clk->ops.clock_gettime(cd.clk, ts);
+	if (cd.clk->ops.clock_gettime) {
+		err = cd.clk->ops.clock_gettime(cd.clk, &ts64);
+		*ts = timespec64_to_timespec(ts64);
+	}
 	else
 		err = -EOPNOTSUPP;
 
@@ -319,14 +317,17 @@
 static int pc_clock_getres(clockid_t id, struct timespec *ts)
 {
 	struct posix_clock_desc cd;
+	struct timespec64 ts64;
 	int err;
 
 	err = get_clock_desc(id, &cd);
 	if (err)
 		return err;
 
-	if (cd.clk->ops.clock_getres)
-		err = cd.clk->ops.clock_getres(cd.clk, ts);
+	if (cd.clk->ops.clock_getres) {
+		err = cd.clk->ops.clock_getres(cd.clk, &ts64);
+		*ts = timespec64_to_timespec(ts64);
+	}
 	else
 		err = -EOPNOTSUPP;
 
@@ -337,9 +338,13 @@
 
 static int pc_clock_settime(clockid_t id, const struct timespec *ts)
 {
+	struct timespec64 ts64 = timespec_to_timespec64(*ts);
 	struct posix_clock_desc cd;
 	int err;
 
+	if (!timespec64_valid_strict(ts))
+		return -EINVAL;
+
 	err = get_clock_desc(id, &cd);
 	if (err)
 		return err;
@@ -350,7 +355,7 @@
 	}
 
 	if (cd.clk->ops.clock_settime)
-		err = cd.clk->ops.clock_settime(cd.clk, ts);
+		err = cd.clk->ops.clock_settime(cd.clk, &ts64);
 	else
 		err = -EOPNOTSUPP;
 out:
@@ -403,29 +408,36 @@
 {
 	clockid_t id = kit->it_clock;
 	struct posix_clock_desc cd;
+	struct itimerspec64 ts64;
 
 	if (get_clock_desc(id, &cd))
 		return;
 
-	if (cd.clk->ops.timer_gettime)
-		cd.clk->ops.timer_gettime(cd.clk, kit, ts);
-
+	if (cd.clk->ops.timer_gettime) {
+		cd.clk->ops.timer_gettime(cd.clk, kit, &ts64);
+		*ts = itimerspec64_to_itimerspec(&ts64);
+	}
 	put_clock_desc(&cd);
 }
 
 static int pc_timer_settime(struct k_itimer *kit, int flags,
 			    struct itimerspec *ts, struct itimerspec *old)
 {
+	struct itimerspec64 ts64 = itimerspec_to_itimerspec64(ts);
 	clockid_t id = kit->it_clock;
 	struct posix_clock_desc cd;
+	struct itimerspec64 old64;
 	int err;
 
 	err = get_clock_desc(id, &cd);
 	if (err)
 		return err;
 
-	if (cd.clk->ops.timer_settime)
-		err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old);
+	if (cd.clk->ops.timer_settime) {
+		err = cd.clk->ops.timer_settime(cd.clk, kit, flags, &ts64, &old64);
+		if (old)
+			*old = itimerspec64_to_itimerspec(&old64);
+	}
 	else
 		err = -EOPNOTSUPP;
 
--- linux-4.4.0.orig/kernel/time/posix-cpu-timers.c
+++ linux-4.4.0/kernel/time/posix-cpu-timers.c
@@ -103,7 +103,7 @@
 			continue;
 
 		timer->it.cpu.expires += incr;
-		timer->it_overrun += 1 << i;
+		timer->it_overrun += 1LL << i;
 		delta -= incr;
 	}
 }
@@ -808,6 +808,7 @@
 			timer->it.cpu.expires = 0;
 			sample_to_timespec(timer->it_clock, timer->it.cpu.expires,
 					   &itp->it_value);
+			return;
 		} else {
 			cpu_timer_sample_group(timer->it_clock, p, &now);
 			unlock_task_sighand(p, &flags);
@@ -1191,6 +1192,15 @@
 	WARN_ON_ONCE(!irqs_disabled());
 
 	/*
+	 * Ensure that release_task(tsk) can't happen while
+	 * handle_posix_cpu_timers() is running. Otherwise, a concurrent
+	 * posix_cpu_timer_del() may fail to lock_task_sighand(tsk) and
+	 * miss timer->it.cpu.firing != 0.
+	 */
+	if (tsk->exit_state)
+		return;
+
+	/*
 	 * The fast path checks that there are no expired thread or thread
 	 * group timers.  If that's so, just return.
 	 */
--- linux-4.4.0.orig/kernel/time/posix-timers.c
+++ linux-4.4.0/kernel/time/posix-timers.c
@@ -48,6 +48,7 @@
 #include <linux/workqueue.h>
 #include <linux/export.h>
 #include <linux/hashtable.h>
+#include <linux/nospec.h>
 
 #include "timekeeping.h"
 
@@ -354,6 +355,16 @@
 }
 
 __initcall(init_posix_timers);
+/*
+ * The siginfo si_overrun field and the return value of timer_getoverrun(2)
+ * are of type int. Clamp the overrun value to INT_MAX
+ */
+static inline int timer_overrun_to_int(struct k_itimer *timr, int baseval)
+{
+	s64 sum = timr->it_overrun_last + (s64)baseval;
+
+	return sum > (s64)INT_MAX ? INT_MAX : (int)sum;
+}
 
 static void schedule_next_timer(struct k_itimer *timr)
 {
@@ -362,8 +373,7 @@
 	if (timr->it.real.interval.tv64 == 0)
 		return;
 
-	timr->it_overrun += (unsigned int) hrtimer_forward(timer,
-						timer->base->get_time(),
+	timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(),
 						timr->it.real.interval);
 
 	timr->it_overrun_last = timr->it_overrun;
@@ -396,7 +406,7 @@
 		else
 			schedule_next_timer(timr);
 
-		info->si_overrun += timr->it_overrun_last;
+		info->si_overrun = timer_overrun_to_int(timr, info->si_overrun);
 	}
 
 	if (timr)
@@ -491,8 +501,7 @@
 					now = ktime_add(now, kj);
 			}
 #endif
-			timr->it_overrun += (unsigned int)
-				hrtimer_forward(timer, now,
+			timr->it_overrun += hrtimer_forward(timer, now,
 						timr->it.real.interval);
 			ret = HRTIMER_RESTART;
 			++timr->it_requeue_pending;
@@ -507,17 +516,22 @@
 {
 	struct task_struct *rtn = current->group_leader;
 
-	if ((event->sigev_notify & SIGEV_THREAD_ID ) &&
-		(!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) ||
-		 !same_thread_group(rtn, current) ||
-		 (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL))
-		return NULL;
-
-	if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) &&
-	    ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX)))
+	switch (event->sigev_notify) {
+	case SIGEV_SIGNAL | SIGEV_THREAD_ID:
+		rtn = find_task_by_vpid(event->sigev_notify_thread_id);
+		if (!rtn || !same_thread_group(rtn, current))
+			return NULL;
+		/* FALLTHRU */
+	case SIGEV_SIGNAL:
+	case SIGEV_THREAD:
+		if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX)
+			return NULL;
+		/* FALLTHRU */
+	case SIGEV_NONE:
+		return task_pid(rtn);
+	default:
 		return NULL;
-
-	return task_pid(rtn);
+	}
 }
 
 void posix_timers_register_clock(const clockid_t clock_id,
@@ -582,13 +596,21 @@
 
 static struct k_clock *clockid_to_kclock(const clockid_t id)
 {
-	if (id < 0)
+	clockid_t idx = id;
+
+	if (id < 0) {
 		return (id & CLOCKFD_MASK) == CLOCKFD ?
 			&clock_posix_dynamic : &clock_posix_cpu;
+	}
 
-	if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres)
+	if (id >= MAX_CLOCKS)
 		return NULL;
-	return &posix_clocks[id];
+
+	idx = array_index_nospec(idx, MAX_CLOCKS);
+	if (!posix_clocks[idx].clock_getres)
+		return NULL;
+
+	return &posix_clocks[idx];
 }
 
 static int common_timer_create(struct k_itimer *new_timer)
@@ -628,7 +650,7 @@
 	it_id_set = IT_ID_SET;
 	new_timer->it_id = (timer_t) new_timer_id;
 	new_timer->it_clock = which_clock;
-	new_timer->it_overrun = -1;
+	new_timer->it_overrun = -1LL;
 
 	if (timer_event_spec) {
 		if (copy_from_user(&event, timer_event_spec, sizeof (event))) {
@@ -745,8 +767,7 @@
 	/* interval timer ? */
 	if (iv.tv64)
 		cur_setting->it_interval = ktime_to_timespec(iv);
-	else if (!hrtimer_active(timer) &&
-		 (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+	else if (!hrtimer_active(timer) && timr->it_sigev_notify != SIGEV_NONE)
 		return;
 
 	now = timer->base->get_time();
@@ -757,17 +778,17 @@
 	 * expiry is > now.
 	 */
 	if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
-	    (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
-		timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
+			timr->it_sigev_notify == SIGEV_NONE))
+		timr->it_overrun += hrtimer_forward(timer, now, iv);
 
-	remaining = ktime_sub(hrtimer_get_expires(timer), now);
+	remaining = __hrtimer_expires_remaining_adjusted(timer, now);
 	/* Return 0 only, when the timer is expired and not pending */
 	if (remaining.tv64 <= 0) {
 		/*
 		 * A single shot SIGEV_NONE timer must return 0, when
 		 * it is expired !
 		 */
-		if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+		if (timr->it_sigev_notify != SIGEV_NONE)
 			cur_setting->it_value.tv_nsec = 1;
 	} else
 		cur_setting->it_value = ktime_to_timespec(remaining);
@@ -820,7 +841,7 @@
 	if (!timr)
 		return -EINVAL;
 
-	overrun = timr->it_overrun_last;
+	overrun = timer_overrun_to_int(timr, 0);
 	unlock_timer(timr, flags);
 
 	return overrun;
@@ -865,7 +886,7 @@
 	timr->it.real.interval = timespec_to_ktime(new_setting->it_interval);
 
 	/* SIGEV_NONE timers are not queued ! See common_timer_get */
-	if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) {
+	if (timr->it_sigev_notify == SIGEV_NONE) {
 		/* Setup correct expiry time for relative timers */
 		if (mode == HRTIMER_MODE_REL) {
 			hrtimer_add_expires(timer, timer->base->get_time());
--- linux-4.4.0.orig/kernel/time/sched_clock.c
+++ linux-4.4.0/kernel/time/sched_clock.c
@@ -205,6 +205,11 @@
 
 	update_clock_read_data(&rd);
 
+	if (sched_clock_timer.function != NULL) {
+		/* update timeout for clock wrap */
+		hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
+	}
+
 	r = rate;
 	if (r >= 4000000) {
 		r /= 1000000;
--- linux-4.4.0.orig/kernel/time/tick-broadcast.c
+++ linux-4.4.0/kernel/time/tick-broadcast.c
@@ -610,6 +610,14 @@
 	now = ktime_get();
 	/* Find all expired events */
 	for_each_cpu(cpu, tick_broadcast_oneshot_mask) {
+		/*
+		 * Required for !SMP because for_each_cpu() reports
+		 * unconditionally CPU0 as set on UP kernels.
+		 */
+		if (!IS_ENABLED(CONFIG_SMP) &&
+		    cpumask_empty(tick_broadcast_oneshot_mask))
+			break;
+
 		td = &per_cpu(tick_cpu_device, cpu);
 		if (td->evtdev->next_event.tv64 <= now.tv64) {
 			cpumask_set_cpu(cpu, tmpmask);
@@ -871,6 +879,9 @@
 {
 	int cpu = smp_processor_id();
 
+	if (!bc)
+		return;
+
 	/* Set it up only once ! */
 	if (bc->event_handler != tick_handle_oneshot_broadcast) {
 		int was_periodic = clockevent_state_periodic(bc);
--- linux-4.4.0.orig/kernel/time/tick-sched.c
+++ linux-4.4.0/kernel/time/tick-sched.c
@@ -568,6 +568,11 @@
 		tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
 }
 
+static inline bool local_timer_softirq_pending(void)
+{
+	return local_softirq_pending() & BIT(TIMER_SOFTIRQ);
+}
+
 static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
 					 ktime_t now, int cpu)
 {
@@ -584,8 +589,18 @@
 	} while (read_seqretry(&jiffies_lock, seq));
 	ts->last_jiffies = basejiff;
 
-	if (rcu_needs_cpu(basemono, &next_rcu) ||
-	    arch_needs_cpu() || irq_work_needs_cpu()) {
+	/*
+	 * Keep the periodic tick, when RCU, architecture or irq_work
+	 * requests it.
+	 * Aside of that check whether the local timer softirq is
+	 * pending. If so its a bad idea to call get_next_timer_interrupt()
+	 * because there is an already expired timer, so it will request
+	 * immeditate expiry, which rearms the hardware timer with a
+	 * minimal delta which brings us back to this place
+	 * immediately. Lather, rinse and repeat...
+	 */
+	if (rcu_needs_cpu(basemono, &next_rcu) || arch_needs_cpu() ||
+	    irq_work_needs_cpu() || local_timer_softirq_pending()) {
 		next_tick = basemono + TICK_NSEC;
 	} else {
 		/*
@@ -977,9 +992,9 @@
 	/* Get the next period */
 	next = tick_init_jiffy_update();
 
-	hrtimer_forward_now(&ts->sched_timer, tick_period);
 	hrtimer_set_expires(&ts->sched_timer, next);
-	tick_program_event(next, 1);
+	hrtimer_forward_now(&ts->sched_timer, tick_period);
+	tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
 	tick_nohz_activate(ts, NOHZ_MODE_LOWRES);
 }
 
--- linux-4.4.0.orig/kernel/time/time.c
+++ linux-4.4.0/kernel/time/time.c
@@ -28,6 +28,7 @@
  */
 
 #include <linux/export.h>
+#include <linux/kernel.h>
 #include <linux/timex.h>
 #include <linux/capability.h>
 #include <linux/timekeeper_internal.h>
@@ -258,9 +259,10 @@
 	return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
 #else
 # if BITS_PER_LONG == 32
-	return (HZ_TO_MSEC_MUL32 * j) >> HZ_TO_MSEC_SHR32;
+	return (HZ_TO_MSEC_MUL32 * j + (1ULL << HZ_TO_MSEC_SHR32) - 1) >>
+	       HZ_TO_MSEC_SHR32;
 # else
-	return (j * HZ_TO_MSEC_NUM) / HZ_TO_MSEC_DEN;
+	return DIV_ROUND_UP(j * HZ_TO_MSEC_NUM, HZ_TO_MSEC_DEN);
 # endif
 #endif
 }
@@ -695,6 +697,16 @@
 #endif
 }
 
+u64 jiffies64_to_nsecs(u64 j)
+{
+#if !(NSEC_PER_SEC % HZ)
+	return (NSEC_PER_SEC / HZ) * j;
+# else
+	return div_u64(j * HZ_TO_NSEC_NUM, HZ_TO_NSEC_DEN);
+#endif
+}
+EXPORT_SYMBOL(jiffies64_to_nsecs);
+
 /**
  * nsecs_to_jiffies64 - Convert nsecs in u64 to jiffies64
  *
--- linux-4.4.0.orig/kernel/time/timeconst.bc
+++ linux-4.4.0/kernel/time/timeconst.bc
@@ -98,6 +98,12 @@
 		print "#define HZ_TO_USEC_DEN\t\t", hz/cd, "\n"
 		print "#define USEC_TO_HZ_NUM\t\t", hz/cd, "\n"
 		print "#define USEC_TO_HZ_DEN\t\t", 1000000/cd, "\n"
+
+		cd=gcd(hz,1000000000)
+		print "#define HZ_TO_NSEC_NUM\t\t", 1000000000/cd, "\n"
+		print "#define HZ_TO_NSEC_DEN\t\t", hz/cd, "\n"
+		print "#define NSEC_TO_HZ_NUM\t\t", hz/cd, "\n"
+		print "#define NSEC_TO_HZ_DEN\t\t", 1000000000/cd, "\n"
 		print "\n"
 
 		print "#endif /* KERNEL_TIMECONST_H */\n"
--- linux-4.4.0.orig/kernel/time/timekeeping.c
+++ linux-4.4.0/kernel/time/timekeeping.c
@@ -39,7 +39,9 @@
 static struct {
 	seqcount_t		seq;
 	struct timekeeper	timekeeper;
-} tk_core ____cacheline_aligned;
+} tk_core ____cacheline_aligned = {
+	.seq = SEQCNT_ZERO(tk_core.seq),
+};
 
 static DEFINE_RAW_SPINLOCK(timekeeper_lock);
 static struct timekeeper shadow_timekeeper;
@@ -116,6 +118,26 @@
 	tk->offs_boot = ktime_add(tk->offs_boot, delta);
 }
 
+/*
+ * tk_clock_read - atomic clocksource read() helper
+ *
+ * This helper is necessary to use in the read paths because, while the
+ * seqlock ensures we don't return a bad value while structures are updated,
+ * it doesn't protect from potential crashes. There is the possibility that
+ * the tkr's clocksource may change between the read reference, and the
+ * clock reference passed to the read function.  This can cause crashes if
+ * the wrong clocksource is passed to the wrong read function.
+ * This isn't necessary to use when holding the timekeeper_lock or doing
+ * a read of the fast-timekeeper tkrs (which is protected by its own locking
+ * and update logic).
+ */
+static inline u64 tk_clock_read(struct tk_read_base *tkr)
+{
+	struct clocksource *clock = READ_ONCE(tkr->clock);
+
+	return clock->read(clock);
+}
+
 #ifdef CONFIG_DEBUG_TIMEKEEPING
 #define WARNING_FREQ (HZ*300) /* 5 minute rate-limiting */
 
@@ -173,7 +195,7 @@
 	 */
 	do {
 		seq = read_seqcount_begin(&tk_core.seq);
-		now = tkr->read(tkr->clock);
+		now = tk_clock_read(tkr);
 		last = tkr->cycle_last;
 		mask = tkr->mask;
 		max = tkr->clock->max_cycles;
@@ -207,7 +229,7 @@
 	cycle_t cycle_now, delta;
 
 	/* read clocksource */
-	cycle_now = tkr->read(tkr->clock);
+	cycle_now = tk_clock_read(tkr);
 
 	/* calculate the delta since the last update_wall_time */
 	delta = clocksource_delta(cycle_now, tkr->cycle_last, tkr->mask);
@@ -233,14 +255,13 @@
 	u64 tmp, ntpinterval;
 	struct clocksource *old_clock;
 
+	++tk->cs_was_changed_seq;
 	old_clock = tk->tkr_mono.clock;
 	tk->tkr_mono.clock = clock;
-	tk->tkr_mono.read = clock->read;
 	tk->tkr_mono.mask = clock->mask;
-	tk->tkr_mono.cycle_last = tk->tkr_mono.read(clock);
+	tk->tkr_mono.cycle_last = tk_clock_read(&tk->tkr_mono);
 
 	tk->tkr_raw.clock = clock;
-	tk->tkr_raw.read = clock->read;
 	tk->tkr_raw.mask = clock->mask;
 	tk->tkr_raw.cycle_last = tk->tkr_mono.cycle_last;
 
@@ -259,8 +280,7 @@
 	/* Go back from cycles -> shifted ns */
 	tk->xtime_interval = (u64) interval * clock->mult;
 	tk->xtime_remainder = ntpinterval - tk->xtime_interval;
-	tk->raw_interval =
-		((u64) interval * clock->mult) >> clock->shift;
+	tk->raw_interval = interval * clock->mult;
 
 	 /* if changing clocks, convert xtime_nsec shift units */
 	if (old_clock) {
@@ -298,12 +318,10 @@
 static inline u32 arch_gettimeoffset(void) { return 0; }
 #endif
 
-static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
+static inline u64 timekeeping_delta_to_ns(struct tk_read_base *tkr,
+					  cycle_t delta)
 {
-	cycle_t delta;
-	s64 nsec;
-
-	delta = timekeeping_get_delta(tkr);
+	u64 nsec;
 
 	nsec = delta * tkr->mult + tkr->xtime_nsec;
 	nsec >>= tkr->shift;
@@ -312,6 +330,24 @@
 	return nsec + arch_gettimeoffset();
 }
 
+static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
+{
+	cycle_t delta;
+
+	delta = timekeeping_get_delta(tkr);
+	return timekeeping_delta_to_ns(tkr, delta);
+}
+
+static inline s64 timekeeping_cycles_to_ns(struct tk_read_base *tkr,
+					    cycle_t cycles)
+{
+	cycle_t delta;
+
+	/* calculate the delta since the last update_wall_time */
+	delta = clocksource_delta(cycles, tkr->cycle_last, tkr->mask);
+	return timekeeping_delta_to_ns(tkr, delta);
+}
+
 /**
  * update_fast_timekeeper - Update the fast and NMI safe monotonic timekeeper.
  * @tkr: Timekeeping readout base from which we take the update
@@ -384,7 +420,13 @@
 	do {
 		seq = raw_read_seqcount_latch(&tkf->seq);
 		tkr = tkf->base + (seq & 0x01);
-		now = ktime_to_ns(tkr->base) + timekeeping_get_ns(tkr);
+		now = ktime_to_ns(tkr->base);
+
+		now += timekeeping_delta_to_ns(tkr,
+				clocksource_delta(
+					tk_clock_read(tkr),
+					tkr->cycle_last,
+					tkr->mask));
 	} while (read_seqcount_retry(&tkf->seq, seq));
 
 	return now;
@@ -410,6 +452,10 @@
 	return cycles_at_suspend;
 }
 
+static struct clocksource dummy_clock = {
+	.read = dummy_clock_read,
+};
+
 /**
  * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource.
  * @tk: Timekeeper to snapshot.
@@ -426,13 +472,13 @@
 	struct tk_read_base *tkr = &tk->tkr_mono;
 
 	memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy));
-	cycles_at_suspend = tkr->read(tkr->clock);
-	tkr_dummy.read = dummy_clock_read;
+	cycles_at_suspend = tk_clock_read(tkr);
+	tkr_dummy.clock = &dummy_clock;
 	update_fast_timekeeper(&tkr_dummy, &tk_fast_mono);
 
 	tkr = &tk->tkr_raw;
 	memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy));
-	tkr_dummy.read = dummy_clock_read;
+	tkr_dummy.clock = &dummy_clock;
 	update_fast_timekeeper(&tkr_dummy, &tk_fast_raw);
 }
 
@@ -596,11 +642,10 @@
  */
 static void timekeeping_forward_now(struct timekeeper *tk)
 {
-	struct clocksource *clock = tk->tkr_mono.clock;
 	cycle_t cycle_now, delta;
 	s64 nsec;
 
-	cycle_now = tk->tkr_mono.read(clock);
+	cycle_now = tk_clock_read(&tk->tkr_mono);
 	delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
 	tk->tkr_mono.cycle_last = cycle_now;
 	tk->tkr_raw.cycle_last  = cycle_now;
@@ -846,43 +891,274 @@
 }
 EXPORT_SYMBOL_GPL(ktime_get_real_seconds);
 
-#ifdef CONFIG_NTP_PPS
+/**
+ * __ktime_get_real_seconds - The same as ktime_get_real_seconds
+ * but without the sequence counter protect. This internal function
+ * is called just when timekeeping lock is already held.
+ */
+time64_t __ktime_get_real_seconds(void)
+{
+	struct timekeeper *tk = &tk_core.timekeeper;
+
+	return tk->xtime_sec;
+}
 
 /**
- * ktime_get_raw_and_real_ts64 - get day and raw monotonic time in timespec format
- * @ts_raw:	pointer to the timespec to be set to raw monotonic time
- * @ts_real:	pointer to the timespec to be set to the time of day
- *
- * This function reads both the time of day and raw monotonic time at the
- * same time atomically and stores the resulting timestamps in timespec
- * format.
+ * ktime_get_snapshot - snapshots the realtime/monotonic raw clocks with counter
+ * @systime_snapshot:	pointer to struct receiving the system time snapshot
  */
-void ktime_get_raw_and_real_ts64(struct timespec64 *ts_raw, struct timespec64 *ts_real)
+void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
 {
 	struct timekeeper *tk = &tk_core.timekeeper;
 	unsigned long seq;
-	s64 nsecs_raw, nsecs_real;
+	ktime_t base_raw;
+	ktime_t base_real;
+	s64 nsec_raw;
+	s64 nsec_real;
+	cycle_t now;
 
 	WARN_ON_ONCE(timekeeping_suspended);
 
 	do {
 		seq = read_seqcount_begin(&tk_core.seq);
 
-		*ts_raw = tk->raw_time;
-		ts_real->tv_sec = tk->xtime_sec;
-		ts_real->tv_nsec = 0;
+		now = tk_clock_read(&tk->tkr_mono);
+		systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq;
+		systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq;
+		base_real = ktime_add(tk->tkr_mono.base,
+				      tk_core.timekeeper.offs_real);
+		base_raw = tk->tkr_raw.base;
+		nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, now);
+		nsec_raw  = timekeeping_cycles_to_ns(&tk->tkr_raw, now);
+	} while (read_seqcount_retry(&tk_core.seq, seq));
 
-		nsecs_raw  = timekeeping_get_ns(&tk->tkr_raw);
-		nsecs_real = timekeeping_get_ns(&tk->tkr_mono);
+	systime_snapshot->cycles = now;
+	systime_snapshot->real = ktime_add_ns(base_real, nsec_real);
+	systime_snapshot->raw = ktime_add_ns(base_raw, nsec_raw);
+}
+EXPORT_SYMBOL_GPL(ktime_get_snapshot);
 
-	} while (read_seqcount_retry(&tk_core.seq, seq));
+/* Scale base by mult/div checking for overflow */
+static int scale64_check_overflow(u64 mult, u64 div, u64 *base)
+{
+	u64 tmp, rem;
 
-	timespec64_add_ns(ts_raw, nsecs_raw);
-	timespec64_add_ns(ts_real, nsecs_real);
+	tmp = div64_u64_rem(*base, div, &rem);
+
+	if (((int)sizeof(u64)*8 - fls64(mult) < fls64(tmp)) ||
+	    ((int)sizeof(u64)*8 - fls64(mult) < fls64(rem)))
+		return -EOVERFLOW;
+	tmp *= mult;
+	rem *= mult;
+
+	do_div(rem, div);
+	*base = tmp + rem;
+	return 0;
 }
-EXPORT_SYMBOL(ktime_get_raw_and_real_ts64);
 
-#endif /* CONFIG_NTP_PPS */
+/**
+ * adjust_historical_crosststamp - adjust crosstimestamp previous to current interval
+ * @history:			Snapshot representing start of history
+ * @partial_history_cycles:	Cycle offset into history (fractional part)
+ * @total_history_cycles:	Total history length in cycles
+ * @discontinuity:		True indicates clock was set on history period
+ * @ts:				Cross timestamp that should be adjusted using
+ *	partial/total ratio
+ *
+ * Helper function used by get_device_system_crosststamp() to correct the
+ * crosstimestamp corresponding to the start of the current interval to the
+ * system counter value (timestamp point) provided by the driver. The
+ * total_history_* quantities are the total history starting at the provided
+ * reference point and ending at the start of the current interval. The cycle
+ * count between the driver timestamp point and the start of the current
+ * interval is partial_history_cycles.
+ */
+static int adjust_historical_crosststamp(struct system_time_snapshot *history,
+					 cycle_t partial_history_cycles,
+					 cycle_t total_history_cycles,
+					 bool discontinuity,
+					 struct system_device_crosststamp *ts)
+{
+	struct timekeeper *tk = &tk_core.timekeeper;
+	u64 corr_raw, corr_real;
+	bool interp_forward;
+	int ret;
+
+	if (total_history_cycles == 0 || partial_history_cycles == 0)
+		return 0;
+
+	/* Interpolate shortest distance from beginning or end of history */
+	interp_forward = partial_history_cycles > total_history_cycles/2 ?
+		true : false;
+	partial_history_cycles = interp_forward ?
+		total_history_cycles - partial_history_cycles :
+		partial_history_cycles;
+
+	/*
+	 * Scale the monotonic raw time delta by:
+	 *	partial_history_cycles / total_history_cycles
+	 */
+	corr_raw = (u64)ktime_to_ns(
+		ktime_sub(ts->sys_monoraw, history->raw));
+	ret = scale64_check_overflow(partial_history_cycles,
+				     total_history_cycles, &corr_raw);
+	if (ret)
+		return ret;
+
+	/*
+	 * If there is a discontinuity in the history, scale monotonic raw
+	 *	correction by:
+	 *	mult(real)/mult(raw) yielding the realtime correction
+	 * Otherwise, calculate the realtime correction similar to monotonic
+	 *	raw calculation
+	 */
+	if (discontinuity) {
+		corr_real = mul_u64_u32_div
+			(corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult);
+	} else {
+		corr_real = (u64)ktime_to_ns(
+			ktime_sub(ts->sys_realtime, history->real));
+		ret = scale64_check_overflow(partial_history_cycles,
+					     total_history_cycles, &corr_real);
+		if (ret)
+			return ret;
+	}
+
+	/* Fixup monotonic raw and real time time values */
+	if (interp_forward) {
+		ts->sys_monoraw = ktime_add_ns(history->raw, corr_raw);
+		ts->sys_realtime = ktime_add_ns(history->real, corr_real);
+	} else {
+		ts->sys_monoraw = ktime_sub_ns(ts->sys_monoraw, corr_raw);
+		ts->sys_realtime = ktime_sub_ns(ts->sys_realtime, corr_real);
+	}
+
+	return 0;
+}
+
+/*
+ * cycle_between - true if test occurs chronologically between before and after
+ */
+static bool cycle_between(cycle_t before, cycle_t test, cycle_t after)
+{
+	if (test > before && test < after)
+		return true;
+	if (test < before && before > after)
+		return true;
+	return false;
+}
+
+/**
+ * get_device_system_crosststamp - Synchronously capture system/device timestamp
+ * @get_time_fn:	Callback to get simultaneous device time and
+ *	system counter from the device driver
+ * @ctx:		Context passed to get_time_fn()
+ * @history_begin:	Historical reference point used to interpolate system
+ *	time when counter provided by the driver is before the current interval
+ * @xtstamp:		Receives simultaneously captured system and device time
+ *
+ * Reads a timestamp from a device and correlates it to system time
+ */
+int get_device_system_crosststamp(int (*get_time_fn)
+				  (ktime_t *device_time,
+				   struct system_counterval_t *sys_counterval,
+				   void *ctx),
+				  void *ctx,
+				  struct system_time_snapshot *history_begin,
+				  struct system_device_crosststamp *xtstamp)
+{
+	struct system_counterval_t system_counterval;
+	struct timekeeper *tk = &tk_core.timekeeper;
+	cycle_t cycles, now, interval_start;
+	unsigned int clock_was_set_seq = 0;
+	ktime_t base_real, base_raw;
+	s64 nsec_real, nsec_raw;
+	u8 cs_was_changed_seq;
+	unsigned long seq;
+	bool do_interp;
+	int ret;
+
+	do {
+		seq = read_seqcount_begin(&tk_core.seq);
+		/*
+		 * Try to synchronously capture device time and a system
+		 * counter value calling back into the device driver
+		 */
+		ret = get_time_fn(&xtstamp->device, &system_counterval, ctx);
+		if (ret)
+			return ret;
+
+		/*
+		 * Verify that the clocksource associated with the captured
+		 * system counter value is the same as the currently installed
+		 * timekeeper clocksource
+		 */
+		if (tk->tkr_mono.clock != system_counterval.cs)
+			return -ENODEV;
+		cycles = system_counterval.cycles;
+
+		/*
+		 * Check whether the system counter value provided by the
+		 * device driver is on the current timekeeping interval.
+		 */
+		now = tk_clock_read(&tk->tkr_mono);
+		interval_start = tk->tkr_mono.cycle_last;
+		if (!cycle_between(interval_start, cycles, now)) {
+			clock_was_set_seq = tk->clock_was_set_seq;
+			cs_was_changed_seq = tk->cs_was_changed_seq;
+			cycles = interval_start;
+			do_interp = true;
+		} else {
+			do_interp = false;
+		}
+
+		base_real = ktime_add(tk->tkr_mono.base,
+				      tk_core.timekeeper.offs_real);
+		base_raw = tk->tkr_raw.base;
+
+		nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono,
+						     system_counterval.cycles);
+		nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw,
+						    system_counterval.cycles);
+	} while (read_seqcount_retry(&tk_core.seq, seq));
+
+	xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real);
+	xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw);
+
+	/*
+	 * Interpolate if necessary, adjusting back from the start of the
+	 * current interval
+	 */
+	if (do_interp) {
+		cycle_t partial_history_cycles, total_history_cycles;
+		bool discontinuity;
+
+		/*
+		 * Check that the counter value occurs after the provided
+		 * history reference and that the history doesn't cross a
+		 * clocksource change
+		 */
+		if (!history_begin ||
+		    !cycle_between(history_begin->cycles,
+				   system_counterval.cycles, cycles) ||
+		    history_begin->cs_was_changed_seq != cs_was_changed_seq)
+			return -EINVAL;
+		partial_history_cycles = cycles - system_counterval.cycles;
+		total_history_cycles = cycles - history_begin->cycles;
+		discontinuity =
+			history_begin->clock_was_set_seq != clock_was_set_seq;
+
+		ret = adjust_historical_crosststamp(history_begin,
+						    partial_history_cycles,
+						    total_history_cycles,
+						    discontinuity, xtstamp);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
 
 /**
  * do_gettimeofday - Returns the time of day in a timeval
@@ -959,7 +1235,7 @@
 	struct timespec64 ts64, tmp;
 	int ret = 0;
 
-	if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
+	if (!timespec_inject_offset_valid(ts))
 		return -EINVAL;
 
 	ts64 = timespec_to_timespec64(*ts);
@@ -1383,7 +1659,7 @@
 	 * The less preferred source will only be tried if there is no better
 	 * usable source. The rtc part is handled separately in rtc core code.
 	 */
-	cycle_now = tk->tkr_mono.read(clock);
+	cycle_now = tk_clock_read(&tk->tkr_mono);
 	if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
 		cycle_now > tk->tkr_mono.cycle_last) {
 		u64 num, max = ULLONG_MAX;
@@ -1592,9 +1868,12 @@
 {
 	s64 interval = tk->cycle_interval;
 	s64 xinterval = tk->xtime_interval;
+	u32 base = tk->tkr_mono.clock->mult;
+	u32 max = tk->tkr_mono.clock->maxadj;
+	u32 cur_adj = tk->tkr_mono.mult;
 	s64 tick_error;
 	bool negative;
-	u32 adj;
+	u32 adj_scale;
 
 	/* Remove any current error adj from freq calculation */
 	if (tk->ntp_err_mult)
@@ -1613,13 +1892,33 @@
 	/* preserve the direction of correction */
 	negative = (tick_error < 0);
 
-	/* Sort out the magnitude of the correction */
+	/* If any adjustment would pass the max, just return */
+	if (negative && (cur_adj - 1) <= (base - max))
+		return;
+	if (!negative && (cur_adj + 1) >= (base + max))
+		return;
+	/*
+	 * Sort out the magnitude of the correction, but
+	 * avoid making so large a correction that we go
+	 * over the max adjustment.
+	 */
+	adj_scale = 0;
 	tick_error = abs(tick_error);
-	for (adj = 0; tick_error > interval; adj++)
+	while (tick_error > interval) {
+		u32 adj = 1 << (adj_scale + 1);
+
+		/* Check if adjustment gets us within 1 unit from the max */
+		if (negative && (cur_adj - adj) <= (base - max))
+			break;
+		if (!negative && (cur_adj + adj) >= (base + max))
+			break;
+
+		adj_scale++;
 		tick_error >>= 1;
+	}
 
 	/* scale the corrections */
-	timekeeping_apply_adjustment(tk, offset, negative, adj);
+	timekeeping_apply_adjustment(tk, offset, negative, adj_scale);
 }
 
 /*
@@ -1724,7 +2023,7 @@
 						unsigned int *clock_set)
 {
 	cycle_t interval = tk->cycle_interval << shift;
-	u64 raw_nsecs;
+	u64 snsec_per_sec;
 
 	/* If the offset is smaller than a shifted interval, do nothing */
 	if (offset < interval)
@@ -1739,14 +2038,15 @@
 	*clock_set |= accumulate_nsecs_to_secs(tk);
 
 	/* Accumulate raw time */
-	raw_nsecs = (u64)tk->raw_interval << shift;
-	raw_nsecs += tk->raw_time.tv_nsec;
-	if (raw_nsecs >= NSEC_PER_SEC) {
-		u64 raw_secs = raw_nsecs;
-		raw_nsecs = do_div(raw_secs, NSEC_PER_SEC);
-		tk->raw_time.tv_sec += raw_secs;
+	tk->tkr_raw.xtime_nsec += (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift;
+	tk->tkr_raw.xtime_nsec += tk->raw_interval << shift;
+	snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift;
+	while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) {
+		tk->tkr_raw.xtime_nsec -= snsec_per_sec;
+		tk->raw_time.tv_sec++;
 	}
-	tk->raw_time.tv_nsec = raw_nsecs;
+	tk->raw_time.tv_nsec = tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift;
+	tk->tkr_raw.xtime_nsec -= (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift;
 
 	/* Accumulate error between NTP and clock interval */
 	tk->ntp_error += tk->ntp_tick << shift;
@@ -1778,7 +2078,7 @@
 #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
 	offset = real_tk->cycle_interval;
 #else
-	offset = clocksource_delta(tk->tkr_mono.read(tk->tkr_mono.clock),
+	offset = clocksource_delta(tk_clock_read(&tk->tkr_mono),
 				   tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
 #endif
 
--- linux-4.4.0.orig/kernel/time/timekeeping_debug.c
+++ linux-4.4.0/kernel/time/timekeeping_debug.c
@@ -23,7 +23,9 @@
 
 #include "timekeeping_internal.h"
 
-static unsigned int sleep_time_bin[32] = {0};
+#define NUM_BINS 32
+
+static unsigned int sleep_time_bin[NUM_BINS] = {0};
 
 static int tk_debug_show_sleep_time(struct seq_file *s, void *data)
 {
@@ -69,6 +71,9 @@
 
 void tk_debug_account_sleep_time(struct timespec64 *t)
 {
-	sleep_time_bin[fls(t->tv_sec)]++;
+	/* Cap bin index so we don't overflow the array */
+	int bin = min(fls(t->tv_sec), NUM_BINS-1);
+
+	sleep_time_bin[bin]++;
 }
 
--- linux-4.4.0.orig/kernel/time/timekeeping_internal.h
+++ linux-4.4.0/kernel/time/timekeeping_internal.h
@@ -17,7 +17,11 @@
 {
 	cycle_t ret = (now - last) & mask;
 
-	return (s64) ret > 0 ? ret : 0;
+	/*
+	 * Prevent time going backwards by checking the MSB of mask in
+	 * the result. If set, return 0.
+	 */
+	return ret & ~(mask >> 1) ? 0 : ret;
 }
 #else
 static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
@@ -26,4 +30,6 @@
 }
 #endif
 
+extern time64_t __ktime_get_real_seconds(void);
+
 #endif /* _TIMEKEEPING_INTERNAL_H */
--- linux-4.4.0.orig/kernel/time/timer.c
+++ linux-4.4.0/kernel/time/timer.c
@@ -42,6 +42,7 @@
 #include <linux/sched/sysctl.h>
 #include <linux/slab.h>
 #include <linux/compat.h>
+#include <linux/random.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -127,7 +128,7 @@
 	int ret;
 
 	mutex_lock(&mutex);
-	ret = proc_dointvec(table, write, buffer, lenp, ppos);
+	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 	if (!ret && write)
 		timers_update_migration(false);
 	mutex_unlock(&mutex);
@@ -448,38 +449,6 @@
 	}
 }
 
-#ifdef CONFIG_TIMER_STATS
-void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
-{
-	if (timer->start_site)
-		return;
-
-	timer->start_site = addr;
-	memcpy(timer->start_comm, current->comm, TASK_COMM_LEN);
-	timer->start_pid = current->pid;
-}
-
-static void timer_stats_account_timer(struct timer_list *timer)
-{
-	void *site;
-
-	/*
-	 * start_site can be concurrently reset by
-	 * timer_stats_timer_clear_start_info()
-	 */
-	site = READ_ONCE(timer->start_site);
-	if (likely(!site))
-		return;
-
-	timer_stats_update_stats(timer, timer->start_pid, site,
-				 timer->function, timer->start_comm,
-				 timer->flags);
-}
-
-#else
-static void timer_stats_account_timer(struct timer_list *timer) {}
-#endif
-
 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
 
 static struct debug_obj_descr timer_debug_descr;
@@ -682,11 +651,6 @@
 	timer->entry.pprev = NULL;
 	timer->flags = flags | raw_smp_processor_id();
 	timer->slack = -1;
-#ifdef CONFIG_TIMER_STATS
-	timer->start_site = NULL;
-	timer->start_pid = -1;
-	memset(timer->start_comm, 0, TASK_COMM_LEN);
-#endif
 	lockdep_init_map(&timer->lockdep_map, name, key, 0);
 }
 
@@ -764,8 +728,15 @@
 	__acquires(timer->base->lock)
 {
 	for (;;) {
-		u32 tf = timer->flags;
 		struct tvec_base *base;
+		u32 tf;
+
+		/*
+		 * We need to use READ_ONCE() here, otherwise the compiler
+		 * might re-read @tf between the check for TIMER_MIGRATING
+		 * and spin_lock().
+		 */
+		tf = READ_ONCE(timer->flags);
 
 		if (!(tf & TIMER_MIGRATING)) {
 			base = per_cpu_ptr(&tvec_bases, tf & TIMER_CPUMASK);
@@ -786,7 +757,6 @@
 	unsigned long flags;
 	int ret = 0;
 
-	timer_stats_timer_set_start_info(timer);
 	BUG_ON(!timer->function);
 
 	base = lock_timer_base(timer, &flags);
@@ -981,7 +951,6 @@
 	struct tvec_base *base;
 	unsigned long flags;
 
-	timer_stats_timer_set_start_info(timer);
 	BUG_ON(timer_pending(timer) || !timer->function);
 
 	/*
@@ -1025,7 +994,6 @@
 
 	debug_assert_init(timer);
 
-	timer_stats_timer_clear_start_info(timer);
 	if (timer_pending(timer)) {
 		base = lock_timer_base(timer, &flags);
 		ret = detach_if_pending(timer, base, true);
@@ -1053,10 +1021,9 @@
 
 	base = lock_timer_base(timer, &flags);
 
-	if (base->running_timer != timer) {
-		timer_stats_timer_clear_start_info(timer);
+	if (base->running_timer != timer)
 		ret = detach_if_pending(timer, base, true);
-	}
+
 	spin_unlock_irqrestore(&base->lock, flags);
 
 	return ret;
@@ -1240,8 +1207,6 @@
 			data = timer->data;
 			irqsafe = timer->flags & TIMER_IRQSAFE;
 
-			timer_stats_account_timer(timer);
-
 			base->running_timer = timer;
 			detach_expired_timer(timer, base);
 
@@ -1661,7 +1626,6 @@
 void __init init_timers(void)
 {
 	init_timer_cpus();
-	init_timer_stats();
 	timer_register_cpu_notifier();
 	open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
 }
--- linux-4.4.0.orig/kernel/time/timer_list.c
+++ linux-4.4.0/kernel/time/timer_list.c
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/kallsyms.h>
+#include <linux/nmi.h>
 
 #include <asm/uaccess.h>
 
@@ -62,21 +63,11 @@
 print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer,
 	    int idx, u64 now)
 {
-#ifdef CONFIG_TIMER_STATS
-	char tmp[TASK_COMM_LEN + 1];
-#endif
 	SEQ_printf(m, " #%d: ", idx);
 	print_name_offset(m, taddr);
 	SEQ_printf(m, ", ");
 	print_name_offset(m, timer->function);
-	SEQ_printf(m, ", S:%02lx", timer->state);
-#ifdef CONFIG_TIMER_STATS
-	SEQ_printf(m, ", ");
-	print_name_offset(m, timer->start_site);
-	memcpy(tmp, timer->start_comm, TASK_COMM_LEN);
-	tmp[TASK_COMM_LEN] = 0;
-	SEQ_printf(m, ", %s/%d", tmp, timer->start_pid);
-#endif
+	SEQ_printf(m, ", S:%02x", timer->state);
 	SEQ_printf(m, "\n");
 	SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs]\n",
 		(unsigned long long)ktime_to_ns(hrtimer_get_softexpires(timer)),
@@ -96,6 +87,9 @@
 
 next_one:
 	i = 0;
+
+	touch_nmi_watchdog();
+
 	raw_spin_lock_irqsave(&base->cpu_base->lock, flags);
 
 	curr = timerqueue_getnext(&base->active);
@@ -207,6 +201,8 @@
 {
 	struct clock_event_device *dev = td->evtdev;
 
+	touch_nmi_watchdog();
+
 	SEQ_printf(m, "Tick Device: mode:     %d\n", td->mode);
 	if (cpu < 0)
 		SEQ_printf(m, "Broadcast device\n");
@@ -293,23 +289,6 @@
 	SEQ_printf(m, "\n");
 }
 
-static int timer_list_show(struct seq_file *m, void *v)
-{
-	struct timer_list_iter *iter = v;
-
-	if (iter->cpu == -1 && !iter->second_pass)
-		timer_list_header(m, iter->now);
-	else if (!iter->second_pass)
-		print_cpu(m, iter->cpu, iter->now);
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-	else if (iter->cpu == -1 && iter->second_pass)
-		timer_list_show_tickdevices_header(m);
-	else
-		print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu);
-#endif
-	return 0;
-}
-
 void sysrq_timer_list_show(void)
 {
 	u64 now = ktime_to_ns(ktime_get());
@@ -328,6 +307,24 @@
 	return;
 }
 
+#ifdef CONFIG_PROC_FS
+static int timer_list_show(struct seq_file *m, void *v)
+{
+	struct timer_list_iter *iter = v;
+
+	if (iter->cpu == -1 && !iter->second_pass)
+		timer_list_header(m, iter->now);
+	else if (!iter->second_pass)
+		print_cpu(m, iter->cpu, iter->now);
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+	else if (iter->cpu == -1 && iter->second_pass)
+		timer_list_show_tickdevices_header(m);
+	else
+		print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu);
+#endif
+	return 0;
+}
+
 static void *move_iter(struct timer_list_iter *iter, loff_t offset)
 {
 	for (; offset; offset--) {
@@ -393,9 +390,10 @@
 {
 	struct proc_dir_entry *pe;
 
-	pe = proc_create("timer_list", 0444, NULL, &timer_list_fops);
+	pe = proc_create("timer_list", 0400, NULL, &timer_list_fops);
 	if (!pe)
 		return -ENOMEM;
 	return 0;
 }
 __initcall(init_timer_list_procfs);
+#endif
--- linux-4.4.0.orig/kernel/trace/Makefile
+++ linux-4.4.0/kernel/trace/Makefile
@@ -1,4 +1,8 @@
 
+# We are fully aware of the dangers of __builtin_return_address()
+FRAME_CFLAGS := $(call cc-disable-warning,frame-address)
+KBUILD_CFLAGS += $(FRAME_CFLAGS)
+
 # Do not instrument the tracer itself:
 
 ifdef CONFIG_FUNCTION_TRACER
--- linux-4.4.0.orig/kernel/trace/blktrace.c
+++ linux-4.4.0/kernel/trace/blktrace.c
@@ -15,6 +15,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/blkdev.h>
 #include <linux/blktrace_api.h>
@@ -57,7 +60,8 @@
 };
 
 /* Global reference count of probes */
-static atomic_t blk_probes_ref = ATOMIC_INIT(0);
+static DEFINE_MUTEX(blk_probe_mutex);
+static int blk_probes_ref;
 
 static void blk_register_tracepoints(void);
 static void blk_unregister_tracepoints(void);
@@ -300,14 +304,30 @@
 	kfree(bt);
 }
 
+static void get_probe_ref(void)
+{
+	mutex_lock(&blk_probe_mutex);
+	if (++blk_probes_ref == 1)
+		blk_register_tracepoints();
+	mutex_unlock(&blk_probe_mutex);
+}
+
+static void put_probe_ref(void)
+{
+	mutex_lock(&blk_probe_mutex);
+	if (!--blk_probes_ref)
+		blk_unregister_tracepoints();
+	mutex_unlock(&blk_probe_mutex);
+}
+
 static void blk_trace_cleanup(struct blk_trace *bt)
 {
+	synchronize_rcu();
 	blk_trace_free(bt);
-	if (atomic_dec_and_test(&blk_probes_ref))
-		blk_unregister_tracepoints();
+	put_probe_ref();
 }
 
-int blk_trace_remove(struct request_queue *q)
+static int __blk_trace_remove(struct request_queue *q)
 {
 	struct blk_trace *bt;
 
@@ -320,6 +340,17 @@
 
 	return 0;
 }
+
+int blk_trace_remove(struct request_queue *q)
+{
+	int ret;
+
+	mutex_lock(&q->blk_trace_mutex);
+	ret = __blk_trace_remove(q);
+	mutex_unlock(&q->blk_trace_mutex);
+
+	return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_remove);
 
 static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
@@ -453,6 +484,16 @@
 	 */
 	strreplace(buts->name, '/', '_');
 
+	/*
+	 * bdev can be NULL, as with scsi-generic, this is a helpful as
+	 * we can be.
+	 */
+	if (q->blk_trace) {
+		pr_warn("Concurrent blktraces are not allowed on %s\n",
+			buts->name);
+		return -EBUSY;
+	}
+
 	bt = kzalloc(sizeof(*bt), GFP_KERNEL);
 	if (!bt)
 		return -ENOMEM;
@@ -522,8 +563,7 @@
 	if (cmpxchg(&q->blk_trace, NULL, bt))
 		goto err;
 
-	if (atomic_inc_return(&blk_probes_ref) == 1)
-		blk_register_tracepoints();
+	get_probe_ref();
 
 	return 0;
 err:
@@ -531,9 +571,8 @@
 	return ret;
 }
 
-int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
-		    struct block_device *bdev,
-		    char __user *arg)
+static int __blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+			     struct block_device *bdev, char __user *arg)
 {
 	struct blk_user_trace_setup buts;
 	int ret;
@@ -547,11 +586,24 @@
 		return ret;
 
 	if (copy_to_user(arg, &buts, sizeof(buts))) {
-		blk_trace_remove(q);
+		__blk_trace_remove(q);
 		return -EFAULT;
 	}
 	return 0;
 }
+
+int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+		    struct block_device *bdev,
+		    char __user *arg)
+{
+	int ret;
+
+	mutex_lock(&q->blk_trace_mutex);
+	ret = __blk_trace_setup(q, name, dev, bdev, arg);
+	mutex_unlock(&q->blk_trace_mutex);
+
+	return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_setup);
 
 #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
@@ -580,7 +632,7 @@
 		return ret;
 
 	if (copy_to_user(arg, &buts.name, ARRAY_SIZE(buts.name))) {
-		blk_trace_remove(q);
+		__blk_trace_remove(q);
 		return -EFAULT;
 	}
 
@@ -588,11 +640,13 @@
 }
 #endif
 
-int blk_trace_startstop(struct request_queue *q, int start)
+int __blk_trace_startstop(struct request_queue *q, int start)
 {
 	int ret;
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 
+	bt = rcu_dereference_protected(q->blk_trace,
+				       lockdep_is_held(&q->blk_trace_mutex));
 	if (bt == NULL)
 		return -EINVAL;
 
@@ -627,8 +681,25 @@
 
 	return ret;
 }
+
+int blk_trace_startstop(struct request_queue *q, int start)
+{
+	int ret;
+
+	mutex_lock(&q->blk_trace_mutex);
+	ret = __blk_trace_startstop(q, start);
+	mutex_unlock(&q->blk_trace_mutex);
+
+	return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_startstop);
 
+/*
+ * When reading or writing the blktrace sysfs files, the references to the
+ * opened sysfs or device files should prevent the underlying block device
+ * from being removed. So no further delete protection is really needed.
+ */
+
 /**
  * blk_trace_ioctl: - handle the ioctls associated with tracing
  * @bdev:	the block device
@@ -646,12 +717,12 @@
 	if (!q)
 		return -ENXIO;
 
-	mutex_lock(&bdev->bd_mutex);
+	mutex_lock(&q->blk_trace_mutex);
 
 	switch (cmd) {
 	case BLKTRACESETUP:
 		bdevname(bdev, b);
-		ret = blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
+		ret = __blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
 		break;
 #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
 	case BLKTRACESETUP32:
@@ -662,17 +733,17 @@
 	case BLKTRACESTART:
 		start = 1;
 	case BLKTRACESTOP:
-		ret = blk_trace_startstop(q, start);
+		ret = __blk_trace_startstop(q, start);
 		break;
 	case BLKTRACETEARDOWN:
-		ret = blk_trace_remove(q);
+		ret = __blk_trace_remove(q);
 		break;
 	default:
 		ret = -ENOTTY;
 		break;
 	}
 
-	mutex_unlock(&bdev->bd_mutex);
+	mutex_unlock(&q->blk_trace_mutex);
 	return ret;
 }
 
@@ -683,10 +754,15 @@
  **/
 void blk_trace_shutdown(struct request_queue *q)
 {
-	if (q->blk_trace) {
-		blk_trace_startstop(q, 0);
-		blk_trace_remove(q);
+	mutex_lock(&q->blk_trace_mutex);
+
+	if (rcu_dereference_protected(q->blk_trace,
+				      lockdep_is_held(&q->blk_trace_mutex))) {
+		__blk_trace_startstop(q, 0);
+		__blk_trace_remove(q);
 	}
+
+	mutex_unlock(&q->blk_trace_mutex);
 }
 
 /*
@@ -707,10 +783,14 @@
 static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
 			     unsigned int nr_bytes, u32 what)
 {
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 
-	if (likely(!bt))
+	rcu_read_lock();
+	bt = rcu_dereference(rq->q->blk_trace);
+	if (likely(!bt)) {
+		rcu_read_unlock();
 		return;
+	}
 
 	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
 		what |= BLK_TC_ACT(BLK_TC_PC);
@@ -721,6 +801,7 @@
 		__blk_add_trace(bt, blk_rq_pos(rq), nr_bytes,
 				rq->cmd_flags, what, rq->errors, 0, NULL);
 	}
+	rcu_read_unlock();
 }
 
 static void blk_add_trace_rq_abort(void *ignore,
@@ -770,13 +851,18 @@
 static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
 			      u32 what, int error)
 {
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 
-	if (likely(!bt))
+	rcu_read_lock();
+	bt = rcu_dereference(q->blk_trace);
+	if (likely(!bt)) {
+		rcu_read_unlock();
 		return;
+	}
 
 	__blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
 			bio->bi_rw, what, error, 0, NULL);
+	rcu_read_unlock();
 }
 
 static void blk_add_trace_bio_bounce(void *ignore,
@@ -821,10 +907,13 @@
 	if (bio)
 		blk_add_trace_bio(q, bio, BLK_TA_GETRQ, 0);
 	else {
-		struct blk_trace *bt = q->blk_trace;
+		struct blk_trace *bt;
 
+		rcu_read_lock();
+		bt = rcu_dereference(q->blk_trace);
 		if (bt)
 			__blk_add_trace(bt, 0, 0, rw, BLK_TA_GETRQ, 0, 0, NULL);
+		rcu_read_unlock();
 	}
 }
 
@@ -836,27 +925,35 @@
 	if (bio)
 		blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ, 0);
 	else {
-		struct blk_trace *bt = q->blk_trace;
+		struct blk_trace *bt;
 
+		rcu_read_lock();
+		bt = rcu_dereference(q->blk_trace);
 		if (bt)
 			__blk_add_trace(bt, 0, 0, rw, BLK_TA_SLEEPRQ,
 					0, 0, NULL);
+		rcu_read_unlock();
 	}
 }
 
 static void blk_add_trace_plug(void *ignore, struct request_queue *q)
 {
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 
+	rcu_read_lock();
+	bt = rcu_dereference(q->blk_trace);
 	if (bt)
 		__blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL);
+	rcu_read_unlock();
 }
 
 static void blk_add_trace_unplug(void *ignore, struct request_queue *q,
 				    unsigned int depth, bool explicit)
 {
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 
+	rcu_read_lock();
+	bt = rcu_dereference(q->blk_trace);
 	if (bt) {
 		__be64 rpdu = cpu_to_be64(depth);
 		u32 what;
@@ -868,14 +965,17 @@
 
 		__blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu);
 	}
+	rcu_read_unlock();
 }
 
 static void blk_add_trace_split(void *ignore,
 				struct request_queue *q, struct bio *bio,
 				unsigned int pdu)
 {
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 
+	rcu_read_lock();
+	bt = rcu_dereference(q->blk_trace);
 	if (bt) {
 		__be64 rpdu = cpu_to_be64(pdu);
 
@@ -883,6 +983,7 @@
 				bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT,
 				bio->bi_error, sizeof(rpdu), &rpdu);
 	}
+	rcu_read_unlock();
 }
 
 /**
@@ -902,11 +1003,15 @@
 				    struct request_queue *q, struct bio *bio,
 				    dev_t dev, sector_t from)
 {
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 	struct blk_io_trace_remap r;
 
-	if (likely(!bt))
+	rcu_read_lock();
+	bt = rcu_dereference(q->blk_trace);
+	if (likely(!bt)) {
+		rcu_read_unlock();
 		return;
+	}
 
 	r.device_from = cpu_to_be32(dev);
 	r.device_to   = cpu_to_be32(bio->bi_bdev->bd_dev);
@@ -915,6 +1020,7 @@
 	__blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
 			bio->bi_rw, BLK_TA_REMAP, bio->bi_error,
 			sizeof(r), &r);
+	rcu_read_unlock();
 }
 
 /**
@@ -935,11 +1041,15 @@
 				   struct request *rq, dev_t dev,
 				   sector_t from)
 {
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 	struct blk_io_trace_remap r;
 
-	if (likely(!bt))
+	rcu_read_lock();
+	bt = rcu_dereference(q->blk_trace);
+	if (likely(!bt)) {
+		rcu_read_unlock();
 		return;
+	}
 
 	r.device_from = cpu_to_be32(dev);
 	r.device_to   = cpu_to_be32(disk_devt(rq->rq_disk));
@@ -948,6 +1058,7 @@
 	__blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq),
 			rq_data_dir(rq), BLK_TA_REMAP, !!rq->errors,
 			sizeof(r), &r);
+	rcu_read_unlock();
 }
 
 /**
@@ -965,10 +1076,14 @@
 			 struct request *rq,
 			 void *data, size_t len)
 {
-	struct blk_trace *bt = q->blk_trace;
+	struct blk_trace *bt;
 
-	if (likely(!bt))
+	rcu_read_lock();
+	bt = rcu_dereference(q->blk_trace);
+	if (likely(!bt)) {
+		rcu_read_unlock();
 		return;
+	}
 
 	if (rq->cmd_type == REQ_TYPE_BLOCK_PC)
 		__blk_add_trace(bt, 0, blk_rq_bytes(rq), 0,
@@ -976,6 +1091,7 @@
 	else
 		__blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0,
 				BLK_TA_DRV_DATA, rq->errors, len, data);
+	rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(blk_add_driver_data);
 
@@ -1466,9 +1582,8 @@
 	if (bt == NULL)
 		return -EINVAL;
 
-	if (atomic_dec_and_test(&blk_probes_ref))
-		blk_unregister_tracepoints();
-
+	put_probe_ref();
+	synchronize_rcu();
 	blk_trace_free(bt);
 	return 0;
 }
@@ -1499,8 +1614,7 @@
 	if (cmpxchg(&q->blk_trace, NULL, bt))
 		goto free_bt;
 
-	if (atomic_inc_return(&blk_probes_ref) == 1)
-		blk_register_tracepoints();
+	get_probe_ref();
 	return 0;
 
 free_bt:
@@ -1630,6 +1744,7 @@
 	struct hd_struct *p = dev_to_part(dev);
 	struct request_queue *q;
 	struct block_device *bdev;
+	struct blk_trace *bt;
 	ssize_t ret = -ENXIO;
 
 	bdev = bdget(part_devt(p));
@@ -1640,26 +1755,28 @@
 	if (q == NULL)
 		goto out_bdput;
 
-	mutex_lock(&bdev->bd_mutex);
+	mutex_lock(&q->blk_trace_mutex);
 
+	bt = rcu_dereference_protected(q->blk_trace,
+				       lockdep_is_held(&q->blk_trace_mutex));
 	if (attr == &dev_attr_enable) {
-		ret = sprintf(buf, "%u\n", !!q->blk_trace);
+		ret = sprintf(buf, "%u\n", !!bt);
 		goto out_unlock_bdev;
 	}
 
-	if (q->blk_trace == NULL)
+	if (bt == NULL)
 		ret = sprintf(buf, "disabled\n");
 	else if (attr == &dev_attr_act_mask)
-		ret = blk_trace_mask2str(buf, q->blk_trace->act_mask);
+		ret = blk_trace_mask2str(buf, bt->act_mask);
 	else if (attr == &dev_attr_pid)
-		ret = sprintf(buf, "%u\n", q->blk_trace->pid);
+		ret = sprintf(buf, "%u\n", bt->pid);
 	else if (attr == &dev_attr_start_lba)
-		ret = sprintf(buf, "%llu\n", q->blk_trace->start_lba);
+		ret = sprintf(buf, "%llu\n", bt->start_lba);
 	else if (attr == &dev_attr_end_lba)
-		ret = sprintf(buf, "%llu\n", q->blk_trace->end_lba);
+		ret = sprintf(buf, "%llu\n", bt->end_lba);
 
 out_unlock_bdev:
-	mutex_unlock(&bdev->bd_mutex);
+	mutex_unlock(&q->blk_trace_mutex);
 out_bdput:
 	bdput(bdev);
 out:
@@ -1673,6 +1790,7 @@
 	struct block_device *bdev;
 	struct request_queue *q;
 	struct hd_struct *p;
+	struct blk_trace *bt;
 	u64 value;
 	ssize_t ret = -EINVAL;
 
@@ -1701,9 +1819,16 @@
 	if (q == NULL)
 		goto out_bdput;
 
-	mutex_lock(&bdev->bd_mutex);
+	mutex_lock(&q->blk_trace_mutex);
+
+	bt = rcu_dereference_protected(q->blk_trace,
+				       lockdep_is_held(&q->blk_trace_mutex));
 
 	if (attr == &dev_attr_enable) {
+		if (!!value == !!bt) {
+			ret = 0;
+			goto out_unlock_bdev;
+		}
 		if (value)
 			ret = blk_trace_setup_queue(q, bdev);
 		else
@@ -1712,22 +1837,25 @@
 	}
 
 	ret = 0;
-	if (q->blk_trace == NULL)
+	if (bt == NULL) {
 		ret = blk_trace_setup_queue(q, bdev);
+		bt = rcu_dereference_protected(q->blk_trace,
+				lockdep_is_held(&q->blk_trace_mutex));
+	}
 
 	if (ret == 0) {
 		if (attr == &dev_attr_act_mask)
-			q->blk_trace->act_mask = value;
+			bt->act_mask = value;
 		else if (attr == &dev_attr_pid)
-			q->blk_trace->pid = value;
+			bt->pid = value;
 		else if (attr == &dev_attr_start_lba)
-			q->blk_trace->start_lba = value;
+			bt->start_lba = value;
 		else if (attr == &dev_attr_end_lba)
-			q->blk_trace->end_lba = value;
+			bt->end_lba = value;
 	}
 
 out_unlock_bdev:
-	mutex_unlock(&bdev->bd_mutex);
+	mutex_unlock(&q->blk_trace_mutex);
 out_bdput:
 	bdput(bdev);
 out:
--- linux-4.4.0.orig/kernel/trace/bpf_trace.c
+++ linux-4.4.0/kernel/trace/bpf_trace.c
@@ -119,11 +119,13 @@
 			i++;
 		} else if (fmt[i] == 'p' || fmt[i] == 's') {
 			mod[fmt_cnt]++;
-			i++;
-			if (!isspace(fmt[i]) && !ispunct(fmt[i]) && fmt[i] != 0)
+			/* disallow any further format extensions */
+			if (fmt[i + 1] != 0 &&
+			    !isspace(fmt[i + 1]) &&
+			    !ispunct(fmt[i + 1]))
 				return -EINVAL;
 			fmt_cnt++;
-			if (fmt[i - 1] == 's') {
+			if (fmt[i] == 's') {
 				if (str_seen)
 					/* allow only one '%s' per fmt string */
 					return -EINVAL;
@@ -204,6 +206,10 @@
 	    event->pmu->count)
 		return -EINVAL;
 
+	if (unlikely(event->attr.type != PERF_TYPE_HARDWARE &&
+		     event->attr.type != PERF_TYPE_RAW))
+		return -EINVAL;
+
 	/*
 	 * we don't know if the function is run successfully by the
 	 * return value. It can be judged in other places, such as
--- linux-4.4.0.orig/kernel/trace/ftrace.c
+++ linux-4.4.0/kernel/trace/ftrace.c
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/hash.h>
 #include <linux/rcupdate.h>
+#include <linux/kprobes.h>
 
 #include <trace/events/sched.h>
 
@@ -636,8 +637,7 @@
 	}
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-	avg = rec->time;
-	do_div(avg, rec->counter);
+	avg = div64_ul(rec->time, rec->counter);
 	if (tracing_thresh && (avg < tracing_thresh))
 		goto out;
 #endif
@@ -663,7 +663,8 @@
 		 * Divide only 1000 for ns^2 -> us^2 conversion.
 		 * trace_print_graph_duration will divide 1000 again.
 		 */
-		do_div(stddev, rec->counter * (rec->counter - 1) * 1000);
+		stddev = div64_ul(stddev,
+				  rec->counter * (rec->counter - 1) * 1000);
 	}
 
 	trace_seq_init(&s);
@@ -2667,13 +2668,14 @@
 
 	if (!command || !ftrace_enabled) {
 		/*
-		 * If these are control ops, they still need their
-		 * per_cpu field freed. Since, function tracing is
+		 * If these are dynamic or control ops, they still
+		 * need their data freed. Since, function tracing is
 		 * not currently active, we can just free them
 		 * without synchronizing all CPUs.
 		 */
-		if (ops->flags & FTRACE_OPS_FL_CONTROL)
-			control_ops_free(ops);
+		if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | FTRACE_OPS_FL_CONTROL))
+			goto free_ops;
+
 		return 0;
 	}
 
@@ -2728,6 +2730,7 @@
 	if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | FTRACE_OPS_FL_CONTROL)) {
 		schedule_on_each_cpu(ftrace_sync);
 
+ free_ops:
 		arch_ftrace_trampoline_free(ops);
 
 		if (ops->flags & FTRACE_OPS_FL_CONTROL)
@@ -2820,8 +2823,11 @@
 	int cnt = 0;
 
 	for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) {
-		if (ops_references_rec(ops, rec))
-		    cnt++;
+		if (ops_references_rec(ops, rec)) {
+			cnt++;
+			if (ops->flags & FTRACE_OPS_FL_SAVE_REGS)
+				rec->flags |= FTRACE_FL_REGS;
+		}
 	}
 
 	return cnt;
@@ -2871,7 +2877,7 @@
 			p = &pg->records[i];
 			if (test)
 				cnt += referenced_filters(p);
-			p->flags = cnt;
+			p->flags += cnt;
 
 			/*
 			 * Do the initial record conversion from mcount jump
@@ -3535,7 +3541,7 @@
 	int exclude_mod = 0;
 	int found = 0;
 	int ret;
-	int clear_filter;
+	int clear_filter = 0;
 
 	if (func) {
 		func_g.type = filter_parse_regex(func, len, &func_g.search,
@@ -3677,23 +3683,24 @@
 	ftrace_probe_registered = 1;
 }
 
-static void __disable_ftrace_function_probe(void)
+static bool __disable_ftrace_function_probe(void)
 {
 	int i;
 
 	if (!ftrace_probe_registered)
-		return;
+		return false;
 
 	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
 		struct hlist_head *hhd = &ftrace_func_hash[i];
 		if (hhd->first)
-			return;
+			return false;
 	}
 
 	/* no more funcs left */
 	ftrace_shutdown(&trace_probe_ops, 0);
 
 	ftrace_probe_registered = 0;
+	return true;
 }
 
 
@@ -3820,6 +3827,7 @@
 __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 				  void *data, int flags)
 {
+	struct ftrace_ops_hash old_hash_ops;
 	struct ftrace_func_entry *rec_entry;
 	struct ftrace_func_probe *entry;
 	struct ftrace_func_probe *p;
@@ -3831,6 +3839,7 @@
 	struct hlist_node *tmp;
 	char str[KSYM_SYMBOL_LEN];
 	int i, ret;
+	bool disabled;
 
 	if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
 		func_g.search = NULL;
@@ -3840,7 +3849,6 @@
 		func_g.type = filter_parse_regex(glob, strlen(glob),
 						 &func_g.search, &not);
 		func_g.len = strlen(func_g.search);
-		func_g.search = glob;
 
 		/* we do not support '!' for function probes */
 		if (WARN_ON(not))
@@ -3849,6 +3857,10 @@
 
 	mutex_lock(&trace_probe_ops.func_hash->regex_lock);
 
+	old_hash_ops.filter_hash = old_hash;
+	/* Probes only have filters */
+	old_hash_ops.notrace_hash = NULL;
+
 	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
 	if (!hash)
 		/* Hmm, should report this somehow */
@@ -3886,12 +3898,17 @@
 		}
 	}
 	mutex_lock(&ftrace_lock);
-	__disable_ftrace_function_probe();
+	disabled = __disable_ftrace_function_probe();
 	/*
 	 * Remove after the disable is called. Otherwise, if the last
 	 * probe is removed, a null hash means *all enabled*.
 	 */
 	ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+
+	/* still need to update the function call sites */
+	if (ftrace_enabled && !disabled)
+		ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
+				       &old_hash_ops);
 	synchronize_sched();
 	if (!ret)
 		free_ftrace_hash_rcu(old_hash);
@@ -4301,9 +4318,6 @@
 static char ftrace_graph_notrace_buf[FTRACE_FILTER_SIZE] __initdata;
 static int ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer);
 
-static unsigned long save_global_trampoline;
-static unsigned long save_global_flags;
-
 static int __init set_graph_function(char *str)
 {
 	strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE);
@@ -4757,6 +4771,7 @@
 	if (ops->flags & FTRACE_OPS_FL_ENABLED)
 		ftrace_shutdown(ops, 0);
 	ops->flags |= FTRACE_OPS_FL_DELETED;
+	ftrace_free_filter(ops);
 	mutex_unlock(&ftrace_lock);
 }
 
@@ -5154,7 +5169,7 @@
 	INIT_OPS_HASH(control_ops)
 };
 
-static inline void
+static nokprobe_inline void
 __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *ignored, struct pt_regs *regs)
 {
@@ -5203,11 +5218,13 @@
 {
 	__ftrace_ops_list_func(ip, parent_ip, NULL, regs);
 }
+NOKPROBE_SYMBOL(ftrace_ops_list_func);
 #else
 static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip)
 {
 	__ftrace_ops_list_func(ip, parent_ip, NULL, NULL);
 }
+NOKPROBE_SYMBOL(ftrace_ops_no_ops);
 #endif
 
 /*
@@ -5228,6 +5245,7 @@
 
 	trace_clear_recursion(bit);
 }
+NOKPROBE_SYMBOL(ftrace_ops_recurs_func);
 
 /**
  * ftrace_ops_get_func - get the function a trampoline should call
@@ -5690,7 +5708,6 @@
 		}
 
 		if (t->ret_stack == NULL) {
-			atomic_set(&t->tracing_graph_pause, 0);
 			atomic_set(&t->trace_overrun, 0);
 			t->curr_ret_stack = -1;
 			/* Make sure the tasks see the -1 first: */
@@ -5893,17 +5910,6 @@
 	unregister_pm_notifier(&ftrace_suspend_notifier);
 	unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
 
-#ifdef CONFIG_DYNAMIC_FTRACE
-	/*
-	 * Function graph does not allocate the trampoline, but
-	 * other global_ops do. We need to reset the ALLOC_TRAMP flag
-	 * if one was used.
-	 */
-	global_ops.trampoline = save_global_trampoline;
-	if (save_global_flags & FTRACE_OPS_FL_ALLOC_TRAMP)
-		global_ops.flags |= FTRACE_OPS_FL_ALLOC_TRAMP;
-#endif
-
  out:
 	mutex_unlock(&ftrace_lock);
 }
@@ -5913,7 +5919,6 @@
 static void
 graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack)
 {
-	atomic_set(&t->tracing_graph_pause, 0);
 	atomic_set(&t->trace_overrun, 0);
 	t->ftrace_timestamp = 0;
 	/* make curr_ret_stack visible before we add the ret_stack */
--- linux-4.4.0.orig/kernel/trace/power-traces.c
+++ linux-4.4.0/kernel/trace/power-traces.c
@@ -15,4 +15,5 @@
 
 EXPORT_TRACEPOINT_SYMBOL_GPL(suspend_resume);
 EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_idle);
+EXPORT_TRACEPOINT_SYMBOL_GPL(powernv_throttle);
 
--- linux-4.4.0.orig/kernel/trace/ring_buffer.c
+++ linux-4.4.0/kernel/trace/ring_buffer.c
@@ -280,6 +280,8 @@
 /* Missed count stored at end */
 #define RB_MISSED_STORED	(1 << 30)
 
+#define RB_MISSED_FLAGS		(RB_MISSED_EVENTS|RB_MISSED_STORED)
+
 struct buffer_data_page {
 	u64		 time_stamp;	/* page time stamp */
 	local_t		 commit;	/* write committed index */
@@ -331,7 +333,9 @@
  */
 size_t ring_buffer_page_len(void *page)
 {
-	return local_read(&((struct buffer_data_page *)page)->commit)
+	struct buffer_data_page *bpage = page;
+
+	return (local_read(&bpage->commit) & ~RB_MISSED_FLAGS)
 		+ BUF_PAGE_HDR_SIZE;
 }
 
@@ -412,14 +416,16 @@
 
 /*
  * Used for which event context the event is in.
- *  NMI     = 0
- *  IRQ     = 1
- *  SOFTIRQ = 2
- *  NORMAL  = 3
+ *  TRANSITION = 0
+ *  NMI     = 1
+ *  IRQ     = 2
+ *  SOFTIRQ = 3
+ *  NORMAL  = 4
  *
  * See trace_recursive_lock() comment below for more details.
  */
 enum {
+	RB_CTX_TRANSITION,
 	RB_CTX_NMI,
 	RB_CTX_IRQ,
 	RB_CTX_SOFTIRQ,
@@ -437,7 +443,7 @@
 	raw_spinlock_t			reader_lock;	/* serialize readers */
 	arch_spinlock_t			lock;
 	struct lock_class_key		lock_key;
-	unsigned int			nr_pages;
+	unsigned long			nr_pages;
 	unsigned int			current_context;
 	struct list_head		*pages;
 	struct buffer_page		*head_page;	/* read from head */
@@ -458,7 +464,7 @@
 	u64				write_stamp;
 	u64				read_stamp;
 	/* ring buffer pages to update, > 0 to add, < 0 to remove */
-	int				nr_pages_to_update;
+	long				nr_pages_to_update;
 	struct list_head		new_pages; /* new pages to add */
 	struct work_struct		update_pages_work;
 	struct completion		update_done;
@@ -697,7 +703,7 @@
 
 	preempt_disable_notrace();
 	time = rb_time_stamp(buffer);
-	preempt_enable_no_resched_notrace();
+	preempt_enable_notrace();
 
 	return time;
 }
@@ -1137,10 +1143,10 @@
 	return 0;
 }
 
-static int __rb_allocate_pages(int nr_pages, struct list_head *pages, int cpu)
+static int __rb_allocate_pages(long nr_pages, struct list_head *pages, int cpu)
 {
-	int i;
 	struct buffer_page *bpage, *tmp;
+	long i;
 
 	for (i = 0; i < nr_pages; i++) {
 		struct page *page;
@@ -1177,7 +1183,7 @@
 }
 
 static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
-			     unsigned nr_pages)
+			     unsigned long nr_pages)
 {
 	LIST_HEAD(pages);
 
@@ -1202,7 +1208,7 @@
 }
 
 static struct ring_buffer_per_cpu *
-rb_allocate_cpu_buffer(struct ring_buffer *buffer, int nr_pages, int cpu)
+rb_allocate_cpu_buffer(struct ring_buffer *buffer, long nr_pages, int cpu)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
 	struct buffer_page *bpage;
@@ -1302,8 +1308,9 @@
 					struct lock_class_key *key)
 {
 	struct ring_buffer *buffer;
+	long nr_pages;
 	int bsize;
-	int cpu, nr_pages;
+	int cpu;
 
 	/* keep it in its own cache line */
 	buffer = kzalloc(ALIGN(sizeof(*buffer), cache_line_size()),
@@ -1429,12 +1436,12 @@
 }
 
 static int
-rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned int nr_pages)
+rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned long nr_pages)
 {
 	struct list_head *tail_page, *to_remove, *next_page;
 	struct buffer_page *to_remove_page, *tmp_iter_page;
 	struct buffer_page *last_page, *first_page;
-	unsigned int nr_removed;
+	unsigned long nr_removed;
 	unsigned long head_bit;
 	int page_entries;
 
@@ -1508,6 +1515,8 @@
 	tmp_iter_page = first_page;
 
 	do {
+		cond_resched();
+
 		to_remove_page = tmp_iter_page;
 		rb_inc_page(cpu_buffer, &tmp_iter_page);
 
@@ -1651,28 +1660,27 @@
 			int cpu_id)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
-	unsigned nr_pages;
-	int cpu, err = 0;
+	unsigned long nr_pages;
+	int cpu, err;
 
 	/*
 	 * Always succeed at resizing a non-existent buffer:
 	 */
 	if (!buffer)
-		return size;
+		return 0;
 
 	/* Make sure the requested buffer exists */
 	if (cpu_id != RING_BUFFER_ALL_CPUS &&
 	    !cpumask_test_cpu(cpu_id, buffer->cpumask))
-		return size;
+		return 0;
 
-	size = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
-	size *= BUF_PAGE_SIZE;
+	nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
 
 	/* we need a minimum of two pages */
-	if (size < BUF_PAGE_SIZE * 2)
-		size = BUF_PAGE_SIZE * 2;
+	if (nr_pages < 2)
+		nr_pages = 2;
 
-	nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
+	size = nr_pages * BUF_PAGE_SIZE;
 
 	/*
 	 * Don't succeed if resizing is disabled, as a reader might be
@@ -1804,7 +1812,7 @@
 	}
 
 	mutex_unlock(&buffer->mutex);
-	return size;
+	return 0;
 
  out_err:
 	for_each_buffer_cpu(buffer, cpu) {
@@ -2579,10 +2587,10 @@
  * a bit of overhead in something as critical as function tracing,
  * we use a bitmask trick.
  *
- *  bit 0 =  NMI context
- *  bit 1 =  IRQ context
- *  bit 2 =  SoftIRQ context
- *  bit 3 =  normal context.
+ *  bit 1 =  NMI context
+ *  bit 2 =  IRQ context
+ *  bit 3 =  SoftIRQ context
+ *  bit 4 =  normal context.
  *
  * This works because this is the order of contexts that can
  * preempt other contexts. A SoftIRQ never preempts an IRQ
@@ -2605,6 +2613,30 @@
  * The least significant bit can be cleared this way, and it
  * just so happens that it is the same bit corresponding to
  * the current context.
+ *
+ * Now the TRANSITION bit breaks the above slightly. The TRANSITION bit
+ * is set when a recursion is detected at the current context, and if
+ * the TRANSITION bit is already set, it will fail the recursion.
+ * This is needed because there's a lag between the changing of
+ * interrupt context and updating the preempt count. In this case,
+ * a false positive will be found. To handle this, one extra recursion
+ * is allowed, and this is done by the TRANSITION bit. If the TRANSITION
+ * bit is already set, then it is considered a recursion and the function
+ * ends. Otherwise, the TRANSITION bit is set, and that bit is returned.
+ *
+ * On the trace_recursive_unlock(), the TRANSITION bit will be the first
+ * to be cleared. Even if it wasn't the context that set it. That is,
+ * if an interrupt comes in while NORMAL bit is set and the ring buffer
+ * is called before preempt_count() is updated, since the check will
+ * be on the NORMAL bit, the TRANSITION bit will then be set. If an
+ * NMI then comes in, it will set the NMI bit, but when the NMI code
+ * does the trace_recursive_unlock() it will clear the TRANSTION bit
+ * and leave the NMI bit set. But this is fine, because the interrupt
+ * code that set the TRANSITION bit will then clear the NMI bit when it
+ * calls trace_recursive_unlock(). If another NMI comes in, it will
+ * set the TRANSITION bit and continue.
+ *
+ * Note: The TRANSITION bit only handles a single transition between context.
  */
 
 static __always_inline int
@@ -2623,8 +2655,16 @@
 	} else
 		bit = RB_CTX_NORMAL;
 
-	if (unlikely(val & (1 << bit)))
-		return 1;
+	if (unlikely(val & (1 << bit))) {
+		/*
+		 * It is possible that this was called by transitioning
+		 * between interrupt context, and preempt_count() has not
+		 * been updated yet. In this case, use the TRANSITION bit.
+		 */
+		bit = RB_CTX_TRANSITION;
+		if (val & (1 << bit))
+			return 1;
+	}
 
 	val |= (1 << bit);
 	cpu_buffer->current_context = val;
@@ -3046,10 +3086,30 @@
 	if (unlikely(!head))
 		return true;
 
-	return reader->read == rb_page_commit(reader) &&
-		(commit == reader ||
-		 (commit == head &&
-		  head->read == rb_page_commit(commit)));
+	/* Reader should exhaust content in reader page */
+	if (reader->read != rb_page_commit(reader))
+		return false;
+
+	/*
+	 * If writers are committing on the reader page, knowing all
+	 * committed content has been read, the ring buffer is empty.
+	 */
+	if (commit == reader)
+		return true;
+
+	/*
+	 * If writers are committing on a page other than reader page
+	 * and head page, there should always be content to read.
+	 */
+	if (commit != head)
+		return false;
+
+	/*
+	 * Writers are committing on the head page, we just need
+	 * to care about there're committed data, and the reader will
+	 * swap reader page with head page when it is to read data.
+	 */
+	return rb_page_commit(commit) == 0;
 }
 
 /**
@@ -3138,6 +3198,22 @@
 }
 
 /**
+ * ring_buffer_record_is_set_on - return true if the ring buffer is set writable
+ * @buffer: The ring buffer to see if write is set enabled
+ *
+ * Returns true if the ring buffer is set writable by ring_buffer_record_on().
+ * Note that this does NOT mean it is in a writable state.
+ *
+ * It may return true when the ring buffer has been disabled by
+ * ring_buffer_record_disable(), as that is a temporary disabling of
+ * the ring buffer.
+ */
+int ring_buffer_record_is_set_on(struct ring_buffer *buffer)
+{
+	return !(atomic_read(&buffer->record_disabled) & RB_BUFFER_OFF);
+}
+
+/**
  * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer
  * @buffer: The ring buffer to stop writes to.
  * @cpu: The CPU buffer to stop
@@ -3440,11 +3516,23 @@
 int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
+	struct buffer_page *reader;
+	struct buffer_page *head_page;
+	struct buffer_page *commit_page;
+	unsigned commit;
 
 	cpu_buffer = iter->cpu_buffer;
 
-	return iter->head_page == cpu_buffer->commit_page &&
-		iter->head == rb_commit_index(cpu_buffer);
+	/* Remember, trace recording is off when iterator is in use */
+	reader = cpu_buffer->reader_page;
+	head_page = cpu_buffer->head_page;
+	commit_page = cpu_buffer->commit_page;
+	commit = rb_page_commit(commit_page);
+
+	return ((iter->head_page == commit_page && iter->head == commit) ||
+		(iter->head_page == reader && commit_page == head_page &&
+		 head_page->read == commit &&
+		 iter->head == rb_page_commit(cpu_buffer->reader_page)));
 }
 EXPORT_SYMBOL_GPL(ring_buffer_iter_empty);
 
@@ -4008,6 +4096,7 @@
  * ring_buffer_read_prepare - Prepare for a non consuming read of the buffer
  * @buffer: The ring buffer to read from
  * @cpu: The cpu buffer to iterate over
+ * @flags: gfp flags to use for memory allocation
  *
  * This performs the initial preparations necessary to iterate
  * through the buffer.  Memory is allocated, buffer recording
@@ -4025,7 +4114,7 @@
  * This overall must be paired with ring_buffer_read_finish.
  */
 struct ring_buffer_iter *
-ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu)
+ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu, gfp_t flags)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
 	struct ring_buffer_iter *iter;
@@ -4033,7 +4122,7 @@
 	if (!cpumask_test_cpu(cpu, buffer->cpumask))
 		return NULL;
 
-	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
+	iter = kmalloc(sizeof(*iter), flags);
 	if (!iter)
 		return NULL;
 
@@ -4225,6 +4314,8 @@
 
 	if (!cpumask_test_cpu(cpu, buffer->cpumask))
 		return;
+	/* prevent another thread from changing buffer sizes */
+	mutex_lock(&buffer->mutex);
 
 	atomic_inc(&buffer->resize_disabled);
 	atomic_inc(&cpu_buffer->record_disabled);
@@ -4248,6 +4339,8 @@
 
 	atomic_dec(&cpu_buffer->record_disabled);
 	atomic_dec(&buffer->resize_disabled);
+
+	mutex_unlock(&buffer->mutex);
 }
 EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu);
 
@@ -4645,8 +4738,9 @@
 	struct ring_buffer *buffer =
 		container_of(self, struct ring_buffer, cpu_notify);
 	long cpu = (long)hcpu;
-	int cpu_i, nr_pages_same;
-	unsigned int nr_pages;
+	long nr_pages_same;
+	int cpu_i;
+	unsigned long nr_pages;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
@@ -4874,9 +4968,9 @@
 		rb_data[cpu].cnt = cpu;
 		rb_threads[cpu] = kthread_create(rb_test, &rb_data[cpu],
 						 "rbtester/%d", cpu);
-		if (WARN_ON(!rb_threads[cpu])) {
+		if (WARN_ON(IS_ERR(rb_threads[cpu]))) {
 			pr_cont("FAILED\n");
-			ret = -1;
+			ret = PTR_ERR(rb_threads[cpu]);
 			goto out_free;
 		}
 
@@ -4886,9 +4980,9 @@
 
 	/* Now create the rb hammer! */
 	rb_hammer = kthread_run(rb_hammer_test, NULL, "rbhammer");
-	if (WARN_ON(!rb_hammer)) {
+	if (WARN_ON(IS_ERR(rb_hammer))) {
 		pr_cont("FAILED\n");
-		ret = -1;
+		ret = PTR_ERR(rb_hammer);
 		goto out_free;
 	}
 
--- linux-4.4.0.orig/kernel/trace/trace.c
+++ linux-4.4.0/kernel/trace/trace.c
@@ -1088,6 +1088,12 @@
 
 	arch_spin_lock(&tr->max_lock);
 
+	/* Inherit the recordable setting from trace_buffer */
+	if (ring_buffer_record_is_set_on(tr->trace_buffer.buffer))
+		ring_buffer_record_on(tr->max_buffer.buffer);
+	else
+		ring_buffer_record_off(tr->max_buffer.buffer);
+
 	buf = tr->trace_buffer.buffer;
 	tr->trace_buffer.buffer = tr->max_buffer.buffer;
 	tr->max_buffer.buffer = buf;
@@ -1617,7 +1623,7 @@
 
 	map = savedcmd->map_pid_to_cmdline[pid];
 	if (map != NO_CMDLINE_MAP)
-		strcpy(comm, get_saved_cmdlines(map));
+		strlcpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN);
 	else
 		strcpy(comm, "<...>");
 }
@@ -1660,7 +1666,7 @@
 		TRACE_FLAG_IRQS_NOSUPPORT |
 #endif
 		((pc & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) |
-		((pc & SOFTIRQ_MASK) ? TRACE_FLAG_SOFTIRQ : 0) |
+		((pc & SOFTIRQ_OFFSET) ? TRACE_FLAG_SOFTIRQ : 0) |
 		(tif_need_resched() ? TRACE_FLAG_NEED_RESCHED : 0) |
 		(test_preempt_need_resched() ? TRACE_FLAG_PREEMPT_RESCHED : 0);
 }
@@ -1700,7 +1706,7 @@
 	__buffer_unlock_commit(buffer, event);
 
 	ftrace_trace_stack(tr, buffer, flags, 6, pc, NULL);
-	ftrace_trace_userstack(buffer, flags, pc);
+	ftrace_trace_userstack(tr, buffer, flags, pc);
 }
 EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
 
@@ -1751,8 +1757,18 @@
 {
 	__buffer_unlock_commit(buffer, event);
 
-	ftrace_trace_stack(tr, buffer, flags, 6, pc, regs);
-	ftrace_trace_userstack(buffer, flags, pc);
+	/*
+	 * If regs is not set, then skip the following callers:
+	 *   trace_buffer_unlock_commit_regs
+	 *   event_trigger_unlock_commit
+	 *   trace_event_buffer_commit
+	 *   trace_event_raw_event_sched_switch
+	 * Note, we can still get here via blktrace, wakeup tracer
+	 * and mmiotrace, but that's ok if they lose a function or
+	 * two. They are that meaningful.
+	 */
+	ftrace_trace_stack(tr, buffer, flags, regs ? 0 : 4, pc, regs);
+	ftrace_trace_userstack(tr, buffer, flags, pc);
 }
 EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit_regs);
 
@@ -1810,6 +1826,13 @@
 	trace.skip		= skip;
 
 	/*
+	 * Add two, for this function and the call to save_stack_trace()
+	 * If regs is set, then these functions will not be in the way.
+	 */
+	if (!regs)
+		trace.skip += 2;
+
+	/*
 	 * Since events can happen in NMIs there's no safe way to
 	 * use the per cpu ftrace_stacks. We reserve it and if an interrupt
 	 * or NMI comes in, it will just have to use the default
@@ -1918,14 +1941,15 @@
 static DEFINE_PER_CPU(int, user_stack_count);
 
 void
-ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc)
+ftrace_trace_userstack(struct trace_array *tr,
+		       struct ring_buffer *buffer, unsigned long flags, int pc)
 {
 	struct trace_event_call *call = &event_user_stack;
 	struct ring_buffer_event *event;
 	struct userstack_entry *entry;
 	struct stack_trace trace;
 
-	if (!(global_trace.trace_flags & TRACE_ITER_USERSTACKTRACE))
+	if (!(tr->trace_flags & TRACE_ITER_USERSTACKTRACE))
 		return;
 
 	/*
@@ -2180,6 +2204,7 @@
 }
 EXPORT_SYMBOL_GPL(trace_vbprintk);
 
+__printf(3, 0)
 static int
 __trace_array_vprintk(struct ring_buffer *buffer,
 		      unsigned long ip, const char *fmt, va_list args)
@@ -2230,12 +2255,14 @@
 	return len;
 }
 
+__printf(3, 0)
 int trace_array_vprintk(struct trace_array *tr,
 			unsigned long ip, const char *fmt, va_list args)
 {
 	return __trace_array_vprintk(tr->trace_buffer.buffer, ip, fmt, args);
 }
 
+__printf(3, 0)
 int trace_array_printk(struct trace_array *tr,
 		       unsigned long ip, const char *fmt, ...)
 {
@@ -2245,12 +2272,16 @@
 	if (!(global_trace.trace_flags & TRACE_ITER_PRINTK))
 		return 0;
 
+	if (!tr)
+		return -ENOENT;
+
 	va_start(ap, fmt);
 	ret = trace_array_vprintk(tr, ip, fmt, ap);
 	va_end(ap);
 	return ret;
 }
 
+__printf(3, 4)
 int trace_array_printk_buf(struct ring_buffer *buffer,
 			   unsigned long ip, const char *fmt, ...)
 {
@@ -2266,6 +2297,7 @@
 	return ret;
 }
 
+__printf(2, 0)
 int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
 {
 	return trace_array_vprintk(&global_trace, ip, fmt, args);
@@ -3094,7 +3126,8 @@
 	if (iter->cpu_file == RING_BUFFER_ALL_CPUS) {
 		for_each_tracing_cpu(cpu) {
 			iter->buffer_iter[cpu] =
-				ring_buffer_read_prepare(iter->trace_buffer->buffer, cpu);
+				ring_buffer_read_prepare(iter->trace_buffer->buffer,
+							 cpu, GFP_KERNEL);
 		}
 		ring_buffer_read_prepare_sync();
 		for_each_tracing_cpu(cpu) {
@@ -3104,7 +3137,8 @@
 	} else {
 		cpu = iter->cpu_file;
 		iter->buffer_iter[cpu] =
-			ring_buffer_read_prepare(iter->trace_buffer->buffer, cpu);
+			ring_buffer_read_prepare(iter->trace_buffer->buffer,
+						 cpu, GFP_KERNEL);
 		ring_buffer_read_prepare_sync();
 		ring_buffer_read_start(iter->buffer_iter[cpu]);
 		tracing_iter_reset(iter, cpu);
@@ -3226,11 +3260,17 @@
 	/* If this file was open for write, then erase contents */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
 		int cpu = tracing_get_cpu(inode);
+		struct trace_buffer *trace_buf = &tr->trace_buffer;
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+		if (tr->current_trace->print_max)
+			trace_buf = &tr->max_buffer;
+#endif
 
 		if (cpu == RING_BUFFER_ALL_CPUS)
-			tracing_reset_online_cpus(&tr->trace_buffer);
+			tracing_reset_online_cpus(trace_buf);
 		else
-			tracing_reset(&tr->trace_buffer, cpu);
+			tracing_reset(trace_buf, cpu);
 	}
 
 	if (file->f_mode & FMODE_READ) {
@@ -3334,9 +3374,14 @@
 	if (tracing_disabled)
 		return -ENODEV;
 
+	if (trace_array_get(tr) < 0)
+		return -ENODEV;
+
 	ret = seq_open(file, &show_traces_seq_ops);
-	if (ret)
+	if (ret) {
+		trace_array_put(tr);
 		return ret;
+	}
 
 	m = file->private_data;
 	m->private = tr;
@@ -3344,6 +3389,14 @@
 	return 0;
 }
 
+static int show_traces_release(struct inode *inode, struct file *file)
+{
+	struct trace_array *tr = inode->i_private;
+
+	trace_array_put(tr);
+	return seq_release(inode, file);
+}
+
 static ssize_t
 tracing_write_stub(struct file *filp, const char __user *ubuf,
 		   size_t count, loff_t *ppos)
@@ -3374,41 +3427,34 @@
 static const struct file_operations show_traces_fops = {
 	.open		= show_traces_open,
 	.read		= seq_read,
-	.release	= seq_release,
 	.llseek		= seq_lseek,
+	.release	= show_traces_release,
 };
 
-/*
- * The tracer itself will not take this lock, but still we want
- * to provide a consistent cpumask to user-space:
- */
-static DEFINE_MUTEX(tracing_cpumask_update_lock);
-
-/*
- * Temporary storage for the character representation of the
- * CPU bitmask (and one more byte for the newline):
- */
-static char mask_str[NR_CPUS + 1];
-
 static ssize_t
 tracing_cpumask_read(struct file *filp, char __user *ubuf,
 		     size_t count, loff_t *ppos)
 {
 	struct trace_array *tr = file_inode(filp)->i_private;
+	char *mask_str;
 	int len;
 
-	mutex_lock(&tracing_cpumask_update_lock);
+	len = snprintf(NULL, 0, "%*pb\n",
+		       cpumask_pr_args(tr->tracing_cpumask)) + 1;
+	mask_str = kmalloc(len, GFP_KERNEL);
+	if (!mask_str)
+		return -ENOMEM;
 
-	len = snprintf(mask_str, count, "%*pb\n",
+	len = snprintf(mask_str, len, "%*pb\n",
 		       cpumask_pr_args(tr->tracing_cpumask));
 	if (len >= count) {
 		count = -EINVAL;
 		goto out_err;
 	}
-	count = simple_read_from_buffer(ubuf, count, ppos, mask_str, NR_CPUS+1);
+	count = simple_read_from_buffer(ubuf, count, ppos, mask_str, len);
 
 out_err:
-	mutex_unlock(&tracing_cpumask_update_lock);
+	kfree(mask_str);
 
 	return count;
 }
@@ -3428,8 +3474,6 @@
 	if (err)
 		goto err_unlock;
 
-	mutex_lock(&tracing_cpumask_update_lock);
-
 	local_irq_disable();
 	arch_spin_lock(&tr->max_lock);
 	for_each_tracing_cpu(cpu) {
@@ -3452,8 +3496,6 @@
 	local_irq_enable();
 
 	cpumask_copy(tr->tracing_cpumask, tracing_cpumask_new);
-
-	mutex_unlock(&tracing_cpumask_update_lock);
 	free_cpumask_var(tracing_cpumask_new);
 
 	return count;
@@ -4623,7 +4665,6 @@
 	return ret;
 
 fail:
-	kfree(iter->trace);
 	kfree(iter);
 	__trace_array_put(tr);
 	mutex_unlock(&trace_types_lock);
@@ -4701,7 +4742,7 @@
 		 *
 		 * iter->pos will be 0 if we haven't read anything.
 		 */
-		if (!tracing_is_on() && iter->pos)
+		if (!tracer_tracing_is_on(iter->tr) && iter->pos)
 			break;
 
 		mutex_unlock(&iter->mutex);
@@ -4727,19 +4768,20 @@
 	struct trace_iterator *iter = filp->private_data;
 	ssize_t sret;
 
-	/* return any leftover data */
-	sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
-	if (sret != -EBUSY)
-		return sret;
-
-	trace_seq_init(&iter->seq);
-
 	/*
 	 * Avoid more than one consumer on a single file descriptor
 	 * This is just a matter of traces coherency, the ring buffer itself
 	 * is protected.
 	 */
 	mutex_lock(&iter->mutex);
+
+	/* return any leftover data */
+	sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
+	if (sret != -EBUSY)
+		goto out;
+
+	trace_seq_init(&iter->seq);
+
 	if (iter->trace->read) {
 		sret = iter->trace->read(iter, filp, ubuf, cnt, ppos);
 		if (sret)
@@ -4765,6 +4807,7 @@
 	       sizeof(struct trace_iterator) -
 	       offsetof(struct trace_iterator, seq));
 	cpumask_clear(iter->started);
+	trace_seq_init(&iter->seq);
 	iter->pos = -1;
 
 	trace_event_read_lock();
@@ -4949,7 +4992,10 @@
 
 	spd.nr_pages = i;
 
-	ret = splice_to_pipe(pipe, &spd);
+	if (i)
+		ret = splice_to_pipe(pipe, &spd);
+	else
+		ret = 0;
 out:
 	splice_shrink_spd(&spd);
 	return ret;
@@ -5233,7 +5279,7 @@
 	tracing_reset_online_cpus(&tr->trace_buffer);
 
 #ifdef CONFIG_TRACER_MAX_TRACE
-	if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
+	if (tr->max_buffer.buffer)
 		ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
 	tracing_reset_online_cpus(&tr->max_buffer);
 #endif
@@ -5378,11 +5424,15 @@
 			break;
 		}
 #endif
-		if (!tr->allocated_snapshot) {
+		if (!tr->allocated_snapshot)
+			ret = resize_buffer_duplicate_size(&tr->max_buffer,
+				&tr->trace_buffer, iter->cpu_file);
+		else
 			ret = alloc_snapshot(tr);
-			if (ret < 0)
-				break;
-		}
+
+		if (ret < 0)
+			break;
+
 		local_irq_disable();
 		/* Now, we're going to swap */
 		if (iter->cpu_file == RING_BUFFER_ALL_CPUS)
@@ -5703,12 +5753,16 @@
 	buf->private = 0;
 }
 
-static void buffer_pipe_buf_get(struct pipe_inode_info *pipe,
+static bool buffer_pipe_buf_get(struct pipe_inode_info *pipe,
 				struct pipe_buffer *buf)
 {
 	struct buffer_ref *ref = (struct buffer_ref *)buf->private;
 
+	if (ref->ref > INT_MAX/2)
+		return false;
+
 	ref->ref++;
+	return true;
 }
 
 /* Pipe buffer operations for a buffer. */
@@ -5755,7 +5809,7 @@
 		.spd_release	= buffer_spd_release,
 	};
 	struct buffer_ref *ref;
-	int entries, size, i;
+	int entries, i;
 	ssize_t ret = 0;
 
 #ifdef CONFIG_TRACER_MAX_TRACE
@@ -5763,9 +5817,6 @@
 		return -EBUSY;
 #endif
 
-	if (splice_grow_spd(pipe, &spd))
-		return -ENOMEM;
-
 	if (*ppos & (PAGE_SIZE - 1))
 		return -EINVAL;
 
@@ -5775,6 +5826,9 @@
 		len &= PAGE_MASK;
 	}
 
+	if (splice_grow_spd(pipe, &spd))
+		return -ENOMEM;
+
  again:
 	trace_access_lock(iter->cpu_file);
 	entries = ring_buffer_entries_cpu(iter->trace_buffer->buffer, iter->cpu_file);
@@ -5806,14 +5860,6 @@
 			break;
 		}
 
-		/*
-		 * zero out any left over data, this is going to
-		 * user land.
-		 */
-		size = ring_buffer_page_len(ref->page);
-		if (size < PAGE_SIZE)
-			memset(ref->page + size, 0, PAGE_SIZE - size);
-
 		page = virt_to_page(ref->page);
 
 		spd.pages[i] = page;
@@ -5832,19 +5878,21 @@
 	/* did we read anything? */
 	if (!spd.nr_pages) {
 		if (ret)
-			return ret;
+			goto out;
 
+		ret = -EAGAIN;
 		if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK))
-			return -EAGAIN;
+			goto out;
 
 		ret = wait_on_pipe(iter, true);
 		if (ret)
-			return ret;
+			goto out;
 
 		goto again;
 	}
 
 	ret = splice_to_pipe(pipe, &spd);
+out:
 	splice_shrink_spd(&spd);
 
 	return ret;
@@ -6054,11 +6102,13 @@
 		return ret;
 
  out_reg:
-	ret = register_ftrace_function_probe(glob, ops, count);
+	ret = alloc_snapshot(&global_trace);
+	if (ret < 0)
+		goto out;
 
-	if (ret >= 0)
-		alloc_snapshot(&global_trace);
+	ret = register_ftrace_function_probe(glob, ops, count);
 
+ out:
 	return ret < 0 ? ret : 0;
 }
 
@@ -6490,7 +6540,9 @@
 
 	if (buffer) {
 		mutex_lock(&trace_types_lock);
-		if (val) {
+		if (!!val == tracer_tracing_is_on(tr)) {
+			val = 0; /* do nothing */
+		} else if (val) {
 			tracer_tracing_on(tr);
 			if (tr->current_trace->start)
 				tr->current_trace->start(tr);
@@ -6536,6 +6588,7 @@
 	buf->data = alloc_percpu(struct trace_array_cpu);
 	if (!buf->data) {
 		ring_buffer_free(buf->buffer);
+		buf->buffer = NULL;
 		return -ENOMEM;
 	}
 
@@ -6559,7 +6612,9 @@
 				    allocate_snapshot ? size : 1);
 	if (WARN_ON(ret)) {
 		ring_buffer_free(tr->trace_buffer.buffer);
+		tr->trace_buffer.buffer = NULL;
 		free_percpu(tr->trace_buffer.data);
+		tr->trace_buffer.data = NULL;
 		return -ENOMEM;
 	}
 	tr->allocated_snapshot = allocate_snapshot;
@@ -6729,6 +6784,7 @@
 	}
 	kfree(tr->topts);
 
+	free_cpumask_var(tr->tracing_cpumask);
 	kfree(tr->name);
 	kfree(tr);
 
@@ -6810,7 +6866,7 @@
 
 }
 
-static struct vfsmount *trace_automount(void *ingore)
+static struct vfsmount *trace_automount(struct dentry *mntpt, void *ingore)
 {
 	struct vfsmount *mnt;
 	struct file_system_type *type;
@@ -6823,7 +6879,7 @@
 	type = get_fs_type("tracefs");
 	if (!type)
 		return NULL;
-	mnt = vfs_kern_mount(type, 0, "tracefs", NULL);
+	mnt = vfs_submount(mntpt, type, "tracefs", NULL);
 	put_filesystem(type);
 	if (IS_ERR(mnt))
 		return NULL;
@@ -7159,12 +7215,8 @@
 
 		cnt++;
 
-		/* reset all but tr, trace, and overruns */
-		memset(&iter.seq, 0,
-		       sizeof(struct trace_iterator) -
-		       offsetof(struct trace_iterator, seq));
+		trace_iterator_reset(&iter);
 		iter.iter_flags |= TRACE_FILE_LAT_FMT;
-		iter.pos = -1;
 
 		if (trace_find_next_entry_inc(&iter) != NULL) {
 			int ret;
@@ -7212,7 +7264,7 @@
 		goto out_free_buffer_mask;
 
 	/* Only allocate trace_printk buffers if a trace_printk exists */
-	if (__stop___trace_bprintk_fmt != __start___trace_bprintk_fmt)
+	if (&__stop___trace_bprintk_fmt != &__start___trace_bprintk_fmt)
 		/* Must be called before global_trace.buffer is allocated */
 		trace_printk_init_buffers();
 
--- linux-4.4.0.orig/kernel/trace/trace.h
+++ linux-4.4.0/kernel/trace/trace.h
@@ -478,6 +478,12 @@
  * can only be modified by current, we can reuse trace_recursion.
  */
 	TRACE_IRQ_BIT,
+
+	/*
+	 * When transitioning between context, the preempt_count() may
+	 * not be correct. Allow for a single recursion to cover this case.
+	 */
+	TRACE_TRANSITION_BIT,
 };
 
 #define trace_recursion_set(bit)	do { (current)->trace_recursion |= (1<<(bit)); } while (0)
@@ -522,14 +528,27 @@
 		return 0;
 
 	bit = trace_get_context_bit() + start;
-	if (unlikely(val & (1 << bit)))
-		return -1;
+	if (unlikely(val & (1 << bit))) {
+		/*
+		 * It could be that preempt_count has not been updated during
+		 * a switch between contexts. Allow for a single recursion.
+		 */
+		bit = TRACE_TRANSITION_BIT;
+		if (trace_recursion_test(bit))
+			return -1;
+		trace_recursion_set(bit);
+		barrier();
+		return bit + 1;
+	}
+
+	/* Normal check passed, clear the transition to allow it again */
+	trace_recursion_clear(TRACE_TRANSITION_BIT);
 
 	val |= 1 << bit;
 	current->trace_recursion = val;
 	barrier();
 
-	return bit;
+	return bit + 1;
 }
 
 static __always_inline void trace_clear_recursion(int bit)
@@ -539,6 +558,7 @@
 	if (!bit)
 		return;
 
+	bit--;
 	bit = 1 << bit;
 	val &= ~bit;
 
@@ -636,13 +656,15 @@
 #endif /* CONFIG_TRACER_MAX_TRACE */
 
 #ifdef CONFIG_STACKTRACE
-void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags,
+void ftrace_trace_userstack(struct trace_array *tr,
+			    struct ring_buffer *buffer, unsigned long flags,
 			    int pc);
 
 void __trace_stack(struct trace_array *tr, unsigned long flags, int skip,
 		   int pc);
 #else
-static inline void ftrace_trace_userstack(struct ring_buffer *buffer,
+static inline void ftrace_trace_userstack(struct trace_array *tr,
+					  struct ring_buffer *buffer,
 					  unsigned long flags, int pc)
 {
 }
@@ -1381,4 +1403,22 @@
 
 extern struct trace_iterator *tracepoint_print_iter;
 
+/*
+ * Reset the state of the trace_iterator so that it can read consumed data.
+ * Normally, the trace_iterator is used for reading the data when it is not
+ * consumed, and must retain state.
+ */
+static __always_inline void trace_iterator_reset(struct trace_iterator *iter)
+{
+	const size_t offset = offsetof(struct trace_iterator, seq);
+
+	/*
+	 * Keep gcc from complaining about overwriting more than just one
+	 * member in the structure.
+	 */
+	memset((char *)iter + offset, 0, sizeof(struct trace_iterator) - offset);
+
+	iter->pos = -1;
+}
+
 #endif /* _LINUX_KERNEL_TRACE_H */
--- linux-4.4.0.orig/kernel/trace/trace_clock.c
+++ linux-4.4.0/kernel/trace/trace_clock.c
@@ -93,33 +93,49 @@
 {
 	unsigned long flags;
 	int this_cpu;
-	u64 now;
+	u64 now, prev_time;
 
 	local_irq_save(flags);
 
 	this_cpu = raw_smp_processor_id();
-	now = sched_clock_cpu(this_cpu);
+
 	/*
-	 * If in an NMI context then dont risk lockups and return the
-	 * cpu_clock() time:
+	 * The global clock "guarantees" that the events are ordered
+	 * between CPUs. But if two events on two different CPUS call
+	 * trace_clock_global at roughly the same time, it really does
+	 * not matter which one gets the earlier time. Just make sure
+	 * that the same CPU will always show a monotonic clock.
+	 *
+	 * Use a read memory barrier to get the latest written
+	 * time that was recorded.
 	 */
-	if (unlikely(in_nmi()))
-		goto out;
+	smp_rmb();
+	prev_time = READ_ONCE(trace_clock_struct.prev_time);
+	now = sched_clock_cpu(this_cpu);
 
-	arch_spin_lock(&trace_clock_struct.lock);
+	/* Make sure that now is always greater than or equal to prev_time */
+	if ((s64)(now - prev_time) < 0)
+		now = prev_time;
 
 	/*
-	 * TODO: if this happens often then maybe we should reset
-	 * my_scd->clock to prev_time+1, to make sure
-	 * we start ticking with the local clock from now on?
+	 * If in an NMI context then dont risk lockups and simply return
+	 * the current time.
 	 */
-	if ((s64)(now - trace_clock_struct.prev_time) < 0)
-		now = trace_clock_struct.prev_time + 1;
-
-	trace_clock_struct.prev_time = now;
-
-	arch_spin_unlock(&trace_clock_struct.lock);
+	if (unlikely(in_nmi()))
+		goto out;
 
+	/* Tracing can cause strange recursion, always use a try lock */
+	if (arch_spin_trylock(&trace_clock_struct.lock)) {
+		/* Reread prev_time in case it was already updated */
+		prev_time = READ_ONCE(trace_clock_struct.prev_time);
+		if ((s64)(now - prev_time) < 0)
+			now = prev_time;
+
+		trace_clock_struct.prev_time = now;
+
+		/* The unlock acts as the wmb for the above rmb */
+		arch_spin_unlock(&trace_clock_struct.lock);
+	}
  out:
 	local_irq_restore(flags);
 
--- linux-4.4.0.orig/kernel/trace/trace_entries.h
+++ linux-4.4.0/kernel/trace/trace_entries.h
@@ -178,7 +178,7 @@
 
 	F_STRUCT(
 		__field(	int,		size	)
-		__dynamic_array(unsigned long,	caller	)
+		__array(	unsigned long,	caller,	FTRACE_STACK_ENTRIES	)
 	),
 
 	F_printk("\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n"
--- linux-4.4.0.orig/kernel/trace/trace_events.c
+++ linux-4.4.0/kernel/trace/trace_events.c
@@ -97,16 +97,16 @@
 	struct ftrace_event_field *field;
 	struct list_head *head;
 
-	field = __find_event_field(&ftrace_generic_fields, name);
+	head = trace_get_fields(call);
+	field = __find_event_field(head, name);
 	if (field)
 		return field;
 
-	field = __find_event_field(&ftrace_common_fields, name);
+	field = __find_event_field(&ftrace_generic_fields, name);
 	if (field)
 		return field;
 
-	head = trace_get_fields(call);
-	return __find_event_field(head, name);
+	return __find_event_field(&ftrace_common_fields, name);
 }
 
 static int __trace_define_field(struct list_head *head, const char *type,
@@ -171,8 +171,10 @@
 {
 	int ret;
 
-	__generic_field(int, cpu, FILTER_OTHER);
-	__generic_field(char *, comm, FILTER_PTR_STRING);
+	__generic_field(int, CPU, FILTER_CPU);
+	__generic_field(int, cpu, FILTER_CPU);
+	__generic_field(char *, COMM, FILTER_COMM);
+	__generic_field(char *, comm, FILTER_COMM);
 
 	return ret;
 }
@@ -753,6 +755,8 @@
 	char *event = NULL, *sub = NULL, *match;
 	int ret;
 
+	if (!tr)
+		return -ENOENT;
 	/*
 	 * The buf format can be <subsystem>:<event-name>
 	 *  *:<event-name> means any event by that name.
@@ -869,7 +873,8 @@
 		 * The ftrace subsystem is for showing formats only.
 		 * They can not be enabled or disabled via the event files.
 		 */
-		if (call->class && call->class->reg)
+		if (call->class && call->class->reg &&
+		    !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
 			return file;
 	}
 
@@ -1078,7 +1083,8 @@
 	mutex_lock(&event_mutex);
 	list_for_each_entry(file, &tr->events, list) {
 		call = file->event_call;
-		if (!trace_event_name(call) || !call->class || !call->class->reg)
+		if ((call->flags & TRACE_EVENT_FL_IGNORE_ENABLE) ||
+		    !trace_event_name(call) || !call->class || !call->class->reg)
 			continue;
 
 		if (system && strcmp(call->class->system, system->name) != 0)
@@ -1285,9 +1291,6 @@
 	char buf[32];
 	int len;
 
-	if (*ppos)
-		return 0;
-
 	if (unlikely(!id))
 		return -ENODEV;
 
@@ -2104,8 +2107,13 @@
 	trace_create_file("filter", 0644, file->dir, file,
 			  &ftrace_event_filter_fops);
 
-	trace_create_file("trigger", 0644, file->dir, file,
-			  &event_trigger_fops);
+	/*
+	 * Only event directories that can be enabled should have
+	 * triggers.
+	 */
+	if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
+		trace_create_file("trigger", 0644, file->dir, file,
+				  &event_trigger_fops);
 
 	trace_create_file("format", 0444, file->dir, call,
 			  &ftrace_event_format_fops);
@@ -2292,6 +2300,7 @@
 {
 	struct trace_event_call *call, *p;
 	const char *last_system = NULL;
+	bool first = false;
 	int last_i;
 	int i;
 
@@ -2299,15 +2308,28 @@
 	list_for_each_entry_safe(call, p, &ftrace_events, list) {
 		/* events are usually grouped together with systems */
 		if (!last_system || call->class->system != last_system) {
+			first = true;
 			last_i = 0;
 			last_system = call->class->system;
 		}
 
+		/*
+		 * Since calls are grouped by systems, the likelyhood that the
+		 * next call in the iteration belongs to the same system as the
+		 * previous call is high. As an optimization, we skip seaching
+		 * for a map[] that matches the call's system if the last call
+		 * was from the same system. That's what last_i is for. If the
+		 * call has the same system as the previous call, then last_i
+		 * will be the index of the first map[] that has a matching
+		 * system.
+		 */
 		for (i = last_i; i < len; i++) {
 			if (call->class->system == map[i]->system) {
 				/* Save the first system if need be */
-				if (!last_i)
+				if (first) {
 					last_i = i;
+					first = false;
+				}
 				update_event_printk(call, map[i]);
 			}
 		}
--- linux-4.4.0.orig/kernel/trace/trace_events_filter.c
+++ linux-4.4.0/kernel/trace/trace_events_filter.c
@@ -322,6 +322,9 @@
 
 static int regex_match_front(char *str, struct regex *r, int len)
 {
+	if (len < r->len)
+		return 0;
+
 	if (strncmp(str, r->pattern, r->len) == 0)
 		return 1;
 	return 0;
@@ -1043,13 +1046,14 @@
 		return -EINVAL;
 	}
 
-	if (is_string_field(field)) {
+	if (field->filter_type == FILTER_COMM) {
+		filter_build_regex(pred);
+		fn = filter_pred_comm;
+		pred->regex.field_len = TASK_COMM_LEN;
+	} else if (is_string_field(field)) {
 		filter_build_regex(pred);
 
-		if (!strcmp(field->name, "comm")) {
-			fn = filter_pred_comm;
-			pred->regex.field_len = TASK_COMM_LEN;
-		} else if (field->filter_type == FILTER_STATIC_STRING) {
+		if (field->filter_type == FILTER_STATIC_STRING) {
 			fn = filter_pred_string;
 			pred->regex.field_len = field->size;
 		} else if (field->filter_type == FILTER_DYN_STRING)
@@ -1072,7 +1076,7 @@
 		}
 		pred->val = val;
 
-		if (!strcmp(field->name, "cpu"))
+		if (field->filter_type == FILTER_CPU)
 			fn = filter_pred_cpu;
 		else
 			fn = select_comparison_fn(pred->op, field->size,
@@ -1978,6 +1982,10 @@
 		if (err && set_str)
 			append_filter_err(ps, filter);
 	}
+	if (err && !set_str) {
+		free_event_filter(filter);
+		filter = NULL;
+	}
 	create_filter_finish(ps);
 
 	*filterp = filter;
--- linux-4.4.0.orig/kernel/trace/trace_events_trigger.c
+++ linux-4.4.0/kernel/trace/trace_events_trigger.c
@@ -121,9 +121,10 @@
 {
 	struct trace_event_file *event_file = event_file_data(m->private);
 
-	if (t == SHOW_AVAILABLE_TRIGGERS)
+	if (t == SHOW_AVAILABLE_TRIGGERS) {
+		(*pos)++;
 		return NULL;
-
+	}
 	return seq_list_next(t, &event_file->triggers, pos);
 }
 
@@ -203,11 +204,17 @@
 
 static int trigger_process_regex(struct trace_event_file *file, char *buff)
 {
-	char *command, *next = buff;
+	char *command, *next;
 	struct event_command *p;
 	int ret = -EINVAL;
 
+	next = buff = skip_spaces(buff);
 	command = strsep(&next, ": \t");
+	if (next) {
+		next = skip_spaces(next);
+		if (!*next)
+			next = NULL;
+	}
 	command = (command[0] != '!') ? command : command + 1;
 
 	mutex_lock(&trigger_cmd_mutex);
@@ -469,9 +476,10 @@
 	struct trace_event_file *file;
 
 	list_for_each_entry(file, &tr->events, list) {
-		struct event_trigger_data *data;
-		list_for_each_entry_rcu(data, &file->triggers, list) {
+		struct event_trigger_data *data, *n;
+		list_for_each_entry_safe(data, n, &file->triggers, list) {
 			trace_event_trigger_enable_disable(file, 0);
+			list_del_rcu(&data->list);
 			if (data->ops->free)
 				data->ops->free(data->ops, data);
 		}
@@ -613,8 +621,14 @@
 	int ret;
 
 	/* separate the trigger from the filter (t:n [if filter]) */
-	if (param && isdigit(param[0]))
+	if (param && isdigit(param[0])) {
 		trigger = strsep(&param, " \t");
+		if (param) {
+			param = skip_spaces(param);
+			if (!*param)
+				param = NULL;
+		}
+	}
 
 	trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
 
@@ -662,6 +676,8 @@
 		goto out_free;
 
  out_reg:
+	/* Up the trigger_data count to make sure reg doesn't free it on failure */
+	event_trigger_init(trigger_ops, trigger_data);
 	ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file);
 	/*
 	 * The above returns on success the # of functions enabled,
@@ -669,11 +685,13 @@
 	 * Consider no functions a failure too.
 	 */
 	if (!ret) {
+		cmd_ops->unreg(glob, trigger_ops, trigger_data, file);
 		ret = -ENOENT;
-		goto out_free;
-	} else if (ret < 0)
-		goto out_free;
-	ret = 0;
+	} else if (ret > 0)
+		ret = 0;
+
+	/* Down the counter of trigger_data or free it if not used anymore */
+	event_trigger_free(trigger_ops, trigger_data);
  out:
 	return ret;
 
@@ -722,8 +740,10 @@
 
 	/* The filter is for the 'trigger' event, not the triggered event */
 	ret = create_event_filter(file->event_call, filter_str, false, &filter);
-	if (ret)
-		goto out;
+	/*
+	 * If create_event_filter() fails, filter still needs to be freed.
+	 * Which the calling code will do with data->filter.
+	 */
  assign:
 	tmp = rcu_access_pointer(data->filter);
 
@@ -902,14 +922,10 @@
 			  struct event_trigger_data *data,
 			  struct trace_event_file *file)
 {
-	int ret = register_trigger(glob, ops, data, file);
-
-	if (ret > 0 && tracing_alloc_snapshot() != 0) {
-		unregister_trigger(glob, ops, data, file);
-		ret = 0;
-	}
+	if (tracing_alloc_snapshot() != 0)
+		return 0;
 
-	return ret;
+	return register_trigger(glob, ops, data, file);
 }
 
 static int
@@ -1181,6 +1197,11 @@
 	trigger = strsep(&param, " \t");
 	if (!trigger)
 		return -EINVAL;
+	if (param) {
+		param = skip_spaces(param);
+		if (!*param)
+			param = NULL;
+	}
 
 	system = strsep(&trigger, ":");
 	if (!trigger)
@@ -1226,6 +1247,9 @@
 		goto out;
 	}
 
+	/* Up the trigger_data count to make sure nothing frees it on failure */
+	event_trigger_init(trigger_ops, trigger_data);
+
 	if (trigger) {
 		number = strsep(&trigger, ":");
 
@@ -1276,6 +1300,7 @@
 		goto out_disable;
 	/* Just return zero, not the number of enabled functions */
 	ret = 0;
+	event_trigger_free(trigger_ops, trigger_data);
  out:
 	return ret;
 
@@ -1286,7 +1311,7 @@
  out_free:
 	if (cmd_ops->set_filter)
 		cmd_ops->set_filter(NULL, trigger_data, NULL);
-	kfree(trigger_data);
+	event_trigger_free(trigger_ops, trigger_data);
 	kfree(enable_data);
 	goto out;
 }
--- linux-4.4.0.orig/kernel/trace/trace_functions_graph.c
+++ linux-4.4.0/kernel/trace/trace_functions_graph.c
@@ -768,6 +768,7 @@
 	struct ftrace_graph_ret *graph_ret;
 	struct ftrace_graph_ent *call;
 	unsigned long long duration;
+	int cpu = iter->cpu;
 	int i;
 
 	graph_ret = &ret_entry->ret;
@@ -776,10 +777,13 @@
 
 	if (data) {
 		struct fgraph_cpu_data *cpu_data;
-		int cpu = iter->cpu;
 
 		cpu_data = per_cpu_ptr(data->cpu_data, cpu);
 
+		/* If a graph tracer ignored set_graph_notrace */
+		if (call->depth < -1)
+			call->depth += FTRACE_NOTRACE_DEPTH;
+
 		/*
 		 * Comments display at + 1 to depth. Since
 		 * this is a leaf function, keep the comments
@@ -788,7 +792,8 @@
 		cpu_data->depth = call->depth - 1;
 
 		/* No need to keep this function around for this depth */
-		if (call->depth < FTRACE_RETFUNC_DEPTH)
+		if (call->depth < FTRACE_RETFUNC_DEPTH &&
+		    !WARN_ON_ONCE(call->depth < 0))
 			cpu_data->enter_funcs[call->depth] = 0;
 	}
 
@@ -801,6 +806,9 @@
 
 	trace_seq_printf(s, "%ps();\n", (void *)call->func);
 
+	print_graph_irq(iter, graph_ret->func, TRACE_GRAPH_RET,
+			cpu, iter->ent->pid, flags);
+
 	return trace_handle_return(s);
 }
 
@@ -818,11 +826,16 @@
 		struct fgraph_cpu_data *cpu_data;
 		int cpu = iter->cpu;
 
+		/* If a graph tracer ignored set_graph_notrace */
+		if (call->depth < -1)
+			call->depth += FTRACE_NOTRACE_DEPTH;
+
 		cpu_data = per_cpu_ptr(data->cpu_data, cpu);
 		cpu_data->depth = call->depth;
 
 		/* Save this function pointer to see if the exit matches */
-		if (call->depth < FTRACE_RETFUNC_DEPTH)
+		if (call->depth < FTRACE_RETFUNC_DEPTH &&
+		    !WARN_ON_ONCE(call->depth < 0))
 			cpu_data->enter_funcs[call->depth] = call->func;
 	}
 
@@ -1052,7 +1065,8 @@
 		 */
 		cpu_data->depth = trace->depth - 1;
 
-		if (trace->depth < FTRACE_RETFUNC_DEPTH) {
+		if (trace->depth < FTRACE_RETFUNC_DEPTH &&
+		    !WARN_ON_ONCE(trace->depth < 0)) {
 			if (cpu_data->enter_funcs[trace->depth] != trace->func)
 				func_match = 0;
 			cpu_data->enter_funcs[trace->depth] = 0;
--- linux-4.4.0.orig/kernel/trace/trace_irqsoff.c
+++ linux-4.4.0/kernel/trace/trace_irqsoff.c
@@ -109,8 +109,12 @@
 		return 0;
 
 	local_save_flags(*flags);
-	/* slight chance to get a false positive on tracing_cpu */
-	if (!irqs_disabled_flags(*flags))
+	/*
+	 * Slight chance to get a false positive on tracing_cpu,
+	 * although I'm starting to think there isn't a chance.
+	 * Leave this for now just to be paranoid.
+	 */
+	if (!irqs_disabled_flags(*flags) && !preempt_count())
 		return 0;
 
 	*data = per_cpu_ptr(tr->trace_buffer.data, cpu);
--- linux-4.4.0.orig/kernel/trace/trace_kdb.c
+++ linux-4.4.0/kernel/trace/trace_kdb.c
@@ -40,24 +40,22 @@
 
 	kdb_printf("Dumping ftrace buffer:\n");
 
-	/* reset all but tr, trace, and overruns */
-	memset(&iter.seq, 0,
-		   sizeof(struct trace_iterator) -
-		   offsetof(struct trace_iterator, seq));
+	trace_iterator_reset(&iter);
 	iter.iter_flags |= TRACE_FILE_LAT_FMT;
-	iter.pos = -1;
 
 	if (cpu_file == RING_BUFFER_ALL_CPUS) {
 		for_each_tracing_cpu(cpu) {
 			iter.buffer_iter[cpu] =
-			ring_buffer_read_prepare(iter.trace_buffer->buffer, cpu);
+			ring_buffer_read_prepare(iter.trace_buffer->buffer,
+						 cpu, GFP_ATOMIC);
 			ring_buffer_read_start(iter.buffer_iter[cpu]);
 			tracing_iter_reset(&iter, cpu);
 		}
 	} else {
 		iter.cpu_file = cpu_file;
 		iter.buffer_iter[cpu_file] =
-			ring_buffer_read_prepare(iter.trace_buffer->buffer, cpu_file);
+			ring_buffer_read_prepare(iter.trace_buffer->buffer,
+						 cpu_file, GFP_ATOMIC);
 		ring_buffer_read_start(iter.buffer_iter[cpu_file]);
 		tracing_iter_reset(&iter, cpu_file);
 	}
--- linux-4.4.0.orig/kernel/trace/trace_kprobe.c
+++ linux-4.4.0/kernel/trace/trace_kprobe.c
@@ -349,11 +349,10 @@
 static int
 enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 {
+	struct event_file_link *link = NULL;
 	int ret = 0;
 
 	if (file) {
-		struct event_file_link *link;
-
 		link = kmalloc(sizeof(*link), GFP_KERNEL);
 		if (!link) {
 			ret = -ENOMEM;
@@ -373,6 +372,18 @@
 		else
 			ret = enable_kprobe(&tk->rp.kp);
 	}
+
+	if (ret) {
+		if (file) {
+			/* Notice the if is true on not WARN() */
+			if (!WARN_ON_ONCE(!link))
+				list_del_rcu(&link->list);
+			kfree(link);
+			tk->tp.flags &= ~TP_FLAG_TRACE;
+		} else {
+			tk->tp.flags &= ~TP_FLAG_PROFILE;
+		}
+	}
  out:
 	return ret;
 }
@@ -599,7 +610,7 @@
 	bool is_return = false, is_delete = false;
 	char *symbol = NULL, *event = NULL, *group = NULL;
 	char *arg;
-	unsigned long offset = 0;
+	long offset = 0;
 	void *addr = NULL;
 	char buf[MAX_EVENT_NAME_LEN];
 
@@ -659,30 +670,25 @@
 		pr_info("Probe point is not specified.\n");
 		return -EINVAL;
 	}
-	if (isdigit(argv[1][0])) {
-		if (is_return) {
-			pr_info("Return probe point must be a symbol.\n");
-			return -EINVAL;
-		}
-		/* an address specified */
-		ret = kstrtoul(&argv[1][0], 0, (unsigned long *)&addr);
-		if (ret) {
-			pr_info("Failed to parse address.\n");
-			return ret;
-		}
-	} else {
+
+	/* try to parse an address. if that fails, try to read the
+	 * input as a symbol. */
+	if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) {
 		/* a symbol specified */
 		symbol = argv[1];
 		/* TODO: support .init module functions */
 		ret = traceprobe_split_symbol_offset(symbol, &offset);
-		if (ret) {
-			pr_info("Failed to parse symbol.\n");
+		if (ret || offset < 0 || offset > UINT_MAX) {
+			pr_info("Failed to parse either an address or a symbol.\n");
 			return ret;
 		}
 		if (offset && is_return) {
 			pr_info("Return probe must be used without offset.\n");
 			return -EINVAL;
 		}
+	} else if (is_return) {
+		pr_info("Return probe point must be a symbol.\n");
+		return -EINVAL;
 	}
 	argc -= 2; argv += 2;
 
@@ -1471,6 +1477,11 @@
 
 end:
 	release_all_trace_kprobes();
+	/*
+	 * Wait for the optimizer work to finish. Otherwise it might fiddle
+	 * with probes in already freed __init text.
+	 */
+	wait_for_kprobe_optimizer();
 	if (warn)
 		pr_cont("NG: Some tests are failed. Please check them.\n");
 	else
--- linux-4.4.0.orig/kernel/trace/trace_printk.c
+++ linux-4.4.0/kernel/trace/trace_printk.c
@@ -36,6 +36,10 @@
 static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
 {
 	struct trace_bprintk_fmt *pos;
+
+	if (!fmt)
+		return ERR_PTR(-EINVAL);
+
 	list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
 		if (!strcmp(pos->fmt, fmt))
 			return pos;
@@ -57,7 +61,8 @@
 	for (iter = start; iter < end; iter++) {
 		struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
 		if (tb_fmt) {
-			*iter = tb_fmt->fmt;
+			if (!IS_ERR(tb_fmt))
+				*iter = tb_fmt->fmt;
 			continue;
 		}
 
@@ -296,6 +301,9 @@
 	const char *str = *fmt;
 	int i;
 
+	if (!*fmt)
+		return 0;
+
 	seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
 
 	/*
--- linux-4.4.0.orig/kernel/trace/trace_probe.c
+++ linux-4.4.0/kernel/trace/trace_probe.c
@@ -293,7 +293,7 @@
 }
 
 /* Split symbol and offset. */
-int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)
+int traceprobe_split_symbol_offset(char *symbol, long *offset)
 {
 	char *tmp;
 	int ret;
@@ -301,13 +301,11 @@
 	if (!offset)
 		return -EINVAL;
 
-	tmp = strchr(symbol, '+');
+	tmp = strpbrk(symbol, "+-");
 	if (tmp) {
-		/* skip sign because kstrtoul doesn't accept '+' */
-		ret = kstrtoul(tmp + 1, 0, offset);
+		ret = kstrtol(tmp, 0, offset);
 		if (ret)
 			return ret;
-
 		*tmp = '\0';
 	} else
 		*offset = 0;
--- linux-4.4.0.orig/kernel/trace/trace_probe.h
+++ linux-4.4.0/kernel/trace/trace_probe.h
@@ -335,7 +335,7 @@
 extern void traceprobe_update_arg(struct probe_arg *arg);
 extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 
-extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset);
+extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
 
 extern ssize_t traceprobe_probes_write(struct file *file,
 		const char __user *buffer, size_t count, loff_t *ppos,
--- linux-4.4.0.orig/kernel/trace/trace_sched_wakeup.c
+++ linux-4.4.0/kernel/trace/trace_sched_wakeup.c
@@ -625,7 +625,7 @@
 	if (ret) {
 		pr_info("wakeup trace: Couldn't activate tracepoint"
 			" probe to kernel_sched_migrate_task\n");
-		return;
+		goto fail_deprobe_sched_switch;
 	}
 
 	wakeup_reset(tr);
@@ -643,6 +643,8 @@
 		printk(KERN_ERR "failed to start wakeup tracer\n");
 
 	return;
+fail_deprobe_sched_switch:
+	unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL);
 fail_deprobe_wake_new:
 	unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
 fail_deprobe:
--- linux-4.4.0.orig/kernel/trace/trace_selftest.c
+++ linux-4.4.0/kernel/trace/trace_selftest.c
@@ -272,7 +272,7 @@
 		goto out_free;
 	if (cnt > 1) {
 		if (trace_selftest_test_global_cnt == 0)
-			goto out;
+			goto out_free;
 	}
 	if (trace_selftest_test_dyn_cnt == 0)
 		goto out_free;
@@ -490,8 +490,13 @@
 	unregister_ftrace_function(&test_rec_probe);
 
 	ret = -1;
-	if (trace_selftest_recursion_cnt != 1) {
-		pr_cont("*callback not called once (%d)* ",
+	/*
+	 * Recursion allows for transitions between context,
+	 * and may call the callback twice.
+	 */
+	if (trace_selftest_recursion_cnt != 1 &&
+	    trace_selftest_recursion_cnt != 2) {
+		pr_cont("*callback not called once (or twice) (%d)* ",
 			trace_selftest_recursion_cnt);
 		goto out;
 	}
--- linux-4.4.0.orig/kernel/trace/trace_stack.c
+++ linux-4.4.0/kernel/trace/trace_stack.c
@@ -126,6 +126,13 @@
 	}
 
 	/*
+	 * Some archs may not have the passed in ip in the dump.
+	 * If that happens, we need to show everything.
+	 */
+	if (i == stack_trace_max.nr_entries)
+		i = 0;
+
+	/*
 	 * Now find where in the stack these are.
 	 */
 	x = 0;
@@ -190,6 +197,11 @@
 	local_irq_restore(flags);
 }
 
+/* Some archs may not define MCOUNT_INSN_SIZE */
+#ifndef MCOUNT_INSN_SIZE
+# define MCOUNT_INSN_SIZE 0
+#endif
+
 static void
 stack_trace_call(unsigned long ip, unsigned long parent_ip,
 		 struct ftrace_ops *op, struct pt_regs *pt_regs)
--- linux-4.4.0.orig/kernel/trace/trace_stat.c
+++ linux-4.4.0/kernel/trace/trace_stat.c
@@ -302,7 +302,7 @@
 int register_stat_tracer(struct tracer_stat *trace)
 {
 	struct stat_session *session, *node;
-	int ret;
+	int ret = -EINVAL;
 
 	if (!trace)
 		return -EINVAL;
@@ -313,17 +313,15 @@
 	/* Already registered? */
 	mutex_lock(&all_stat_sessions_mutex);
 	list_for_each_entry(node, &all_stat_sessions, session_list) {
-		if (node->ts == trace) {
-			mutex_unlock(&all_stat_sessions_mutex);
-			return -EINVAL;
-		}
+		if (node->ts == trace)
+			goto out;
 	}
-	mutex_unlock(&all_stat_sessions_mutex);
 
+	ret = -ENOMEM;
 	/* Init the session */
 	session = kzalloc(sizeof(*session), GFP_KERNEL);
 	if (!session)
-		return -ENOMEM;
+		goto out;
 
 	session->ts = trace;
 	INIT_LIST_HEAD(&session->session_list);
@@ -332,15 +330,16 @@
 	ret = init_stat_file(session);
 	if (ret) {
 		destroy_session(session);
-		return ret;
+		goto out;
 	}
 
+	ret = 0;
 	/* Register */
-	mutex_lock(&all_stat_sessions_mutex);
 	list_add_tail(&session->session_list, &all_stat_sessions);
+ out:
 	mutex_unlock(&all_stat_sessions_mutex);
 
-	return 0;
+	return ret;
 }
 
 void unregister_stat_tracer(struct tracer_stat *trace)
--- linux-4.4.0.orig/kernel/trace/trace_uprobe.c
+++ linux-4.4.0/kernel/trace/trace_uprobe.c
@@ -149,6 +149,15 @@
 		return;
 
 	ret = strncpy_from_user(dst, src, maxlen);
+	if (ret == maxlen)
+		dst[ret - 1] = '\0';
+	else if (ret >= 0)
+		/*
+		 * Include the terminating null byte. In this case it
+		 * was copied by strncpy_from_user but not accounted
+		 * for in ret.
+		 */
+		ret++;
 
 	if (ret < 0) {	/* Failed to fetch string */
 		((u8 *)get_rloc_data(dest))[0] = '\0';
@@ -693,9 +702,11 @@
 struct uprobe_cpu_buffer {
 	struct mutex mutex;
 	void *buf;
+	int dsize;
 };
 static struct uprobe_cpu_buffer __percpu *uprobe_cpu_buffer;
 static int uprobe_buffer_refcnt;
+#define MAX_UCB_BUFFER_SIZE PAGE_SIZE
 
 static int uprobe_buffer_init(void)
 {
@@ -782,9 +793,31 @@
 	mutex_unlock(&ucb->mutex);
 }
 
+static struct uprobe_cpu_buffer *prepare_uprobe_buffer(struct trace_uprobe *tu,
+						       struct pt_regs *regs)
+{
+	struct uprobe_cpu_buffer *ucb;
+	int dsize, esize;
+
+	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
+	dsize = __get_data_size(&tu->tp, regs);
+
+	ucb = uprobe_buffer_get();
+	ucb->dsize = tu->tp.size + dsize;
+
+	if (WARN_ON_ONCE(ucb->dsize > MAX_UCB_BUFFER_SIZE)) {
+		ucb->dsize = MAX_UCB_BUFFER_SIZE;
+		dsize = MAX_UCB_BUFFER_SIZE - tu->tp.size;
+	}
+
+	store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
+
+	return ucb;
+}
+
 static void __uprobe_trace_func(struct trace_uprobe *tu,
 				unsigned long func, struct pt_regs *regs,
-				struct uprobe_cpu_buffer *ucb, int dsize,
+				struct uprobe_cpu_buffer *ucb,
 				struct trace_event_file *trace_file)
 {
 	struct uprobe_trace_entry_head *entry;
@@ -796,14 +829,11 @@
 
 	WARN_ON(call != trace_file->event_call);
 
-	if (WARN_ON_ONCE(tu->tp.size + dsize > PAGE_SIZE))
-		return;
-
 	if (trace_trigger_soft_disabled(trace_file))
 		return;
 
 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
-	size = esize + tu->tp.size + dsize;
+	size = esize + ucb->dsize;
 	event = trace_event_buffer_lock_reserve(&buffer, trace_file,
 						call->event.type, size, 0, 0);
 	if (!event)
@@ -819,14 +849,14 @@
 		data = DATAOF_TRACE_ENTRY(entry, false);
 	}
 
-	memcpy(data, ucb->buf, tu->tp.size + dsize);
+	memcpy(data, ucb->buf, ucb->dsize);
 
 	event_trigger_unlock_commit(trace_file, buffer, event, entry, 0, 0);
 }
 
 /* uprobe handler */
 static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
-			     struct uprobe_cpu_buffer *ucb, int dsize)
+			     struct uprobe_cpu_buffer *ucb)
 {
 	struct event_file_link *link;
 
@@ -835,7 +865,7 @@
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(link, &tu->tp.files, list)
-		__uprobe_trace_func(tu, 0, regs, ucb, dsize, link->file);
+		__uprobe_trace_func(tu, 0, regs, ucb, link->file);
 	rcu_read_unlock();
 
 	return 0;
@@ -843,13 +873,13 @@
 
 static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
 				 struct pt_regs *regs,
-				 struct uprobe_cpu_buffer *ucb, int dsize)
+				 struct uprobe_cpu_buffer *ucb)
 {
 	struct event_file_link *link;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(link, &tu->tp.files, list)
-		__uprobe_trace_func(tu, func, regs, ucb, dsize, link->file);
+		__uprobe_trace_func(tu, func, regs, ucb, link->file);
 	rcu_read_unlock();
 }
 
@@ -967,7 +997,7 @@
 
 		list_del_rcu(&link->list);
 		/* synchronize with u{,ret}probe_trace_func */
-		synchronize_sched();
+		synchronize_rcu();
 		kfree(link);
 
 		if (!list_empty(&tu->tp.files))
@@ -1106,7 +1136,7 @@
 
 static void __uprobe_perf_func(struct trace_uprobe *tu,
 			       unsigned long func, struct pt_regs *regs,
-			       struct uprobe_cpu_buffer *ucb, int dsize)
+			       struct uprobe_cpu_buffer *ucb)
 {
 	struct trace_event_call *call = &tu->tp.call;
 	struct uprobe_trace_entry_head *entry;
@@ -1121,7 +1151,7 @@
 
 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
 
-	size = esize + tu->tp.size + dsize;
+	size = esize + ucb->dsize;
 	size = ALIGN(size + sizeof(u32), sizeof(u64)) - sizeof(u32);
 	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
 		return;
@@ -1144,13 +1174,10 @@
 		data = DATAOF_TRACE_ENTRY(entry, false);
 	}
 
-	memcpy(data, ucb->buf, tu->tp.size + dsize);
+	memcpy(data, ucb->buf, ucb->dsize);
 
-	if (size - esize > tu->tp.size + dsize) {
-		int len = tu->tp.size + dsize;
-
-		memset(data + len, 0, size - esize - len);
-	}
+	if (size - esize > ucb->dsize)
+		memset(data + ucb->dsize, 0, size - esize - ucb->dsize);
 
 	perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL);
  out:
@@ -1159,21 +1186,21 @@
 
 /* uprobe profile handler */
 static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs,
-			    struct uprobe_cpu_buffer *ucb, int dsize)
+			    struct uprobe_cpu_buffer *ucb)
 {
 	if (!uprobe_perf_filter(&tu->consumer, 0, current->mm))
 		return UPROBE_HANDLER_REMOVE;
 
 	if (!is_ret_probe(tu))
-		__uprobe_perf_func(tu, 0, regs, ucb, dsize);
+		__uprobe_perf_func(tu, 0, regs, ucb);
 	return 0;
 }
 
 static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func,
 				struct pt_regs *regs,
-				struct uprobe_cpu_buffer *ucb, int dsize)
+				struct uprobe_cpu_buffer *ucb)
 {
-	__uprobe_perf_func(tu, func, regs, ucb, dsize);
+	__uprobe_perf_func(tu, func, regs, ucb);
 }
 #endif	/* CONFIG_PERF_EVENTS */
 
@@ -1218,10 +1245,8 @@
 	struct trace_uprobe *tu;
 	struct uprobe_dispatch_data udd;
 	struct uprobe_cpu_buffer *ucb;
-	int dsize, esize;
 	int ret = 0;
 
-
 	tu = container_of(con, struct trace_uprobe, consumer);
 	tu->nhit++;
 
@@ -1233,18 +1258,14 @@
 	if (WARN_ON_ONCE(!uprobe_cpu_buffer))
 		return 0;
 
-	dsize = __get_data_size(&tu->tp, regs);
-	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
-
-	ucb = uprobe_buffer_get();
-	store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
+	ucb = prepare_uprobe_buffer(tu, regs);
 
 	if (tu->tp.flags & TP_FLAG_TRACE)
-		ret |= uprobe_trace_func(tu, regs, ucb, dsize);
+		ret |= uprobe_trace_func(tu, regs, ucb);
 
 #ifdef CONFIG_PERF_EVENTS
 	if (tu->tp.flags & TP_FLAG_PROFILE)
-		ret |= uprobe_perf_func(tu, regs, ucb, dsize);
+		ret |= uprobe_perf_func(tu, regs, ucb);
 #endif
 	uprobe_buffer_put(ucb);
 	return ret;
@@ -1256,7 +1277,6 @@
 	struct trace_uprobe *tu;
 	struct uprobe_dispatch_data udd;
 	struct uprobe_cpu_buffer *ucb;
-	int dsize, esize;
 
 	tu = container_of(con, struct trace_uprobe, consumer);
 
@@ -1268,18 +1288,14 @@
 	if (WARN_ON_ONCE(!uprobe_cpu_buffer))
 		return 0;
 
-	dsize = __get_data_size(&tu->tp, regs);
-	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
-
-	ucb = uprobe_buffer_get();
-	store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
+	ucb = prepare_uprobe_buffer(tu, regs);
 
 	if (tu->tp.flags & TP_FLAG_TRACE)
-		uretprobe_trace_func(tu, func, regs, ucb, dsize);
+		uretprobe_trace_func(tu, func, regs, ucb);
 
 #ifdef CONFIG_PERF_EVENTS
 	if (tu->tp.flags & TP_FLAG_PROFILE)
-		uretprobe_perf_func(tu, func, regs, ucb, dsize);
+		uretprobe_perf_func(tu, func, regs, ucb);
 #endif
 	uprobe_buffer_put(ucb);
 	return 0;
--- linux-4.4.0.orig/kernel/tracepoint.c
+++ linux-4.4.0/kernel/tracepoint.c
@@ -59,6 +59,12 @@
 	struct tracepoint_func probes[0];
 };
 
+/* Called in removal of a func but failed to allocate a new tp_funcs */
+static void tp_stub_func(void)
+{
+	return;
+}
+
 static inline void *allocate_probes(int count)
 {
 	struct tp_probes *p  = kmalloc(count * sizeof(struct tracepoint_func)
@@ -97,6 +103,7 @@
 {
 	struct tracepoint_func *old, *new;
 	int nr_probes = 0;
+	int stub_funcs = 0;
 	int pos = -1;
 
 	if (WARN_ON(!tp_func->func))
@@ -113,14 +120,34 @@
 			if (old[nr_probes].func == tp_func->func &&
 			    old[nr_probes].data == tp_func->data)
 				return ERR_PTR(-EEXIST);
+			if (old[nr_probes].func == tp_stub_func)
+				stub_funcs++;
 		}
 	}
-	/* + 2 : one for new probe, one for NULL func */
-	new = allocate_probes(nr_probes + 2);
+	/* + 2 : one for new probe, one for NULL func - stub functions */
+	new = allocate_probes(nr_probes + 2 - stub_funcs);
 	if (new == NULL)
 		return ERR_PTR(-ENOMEM);
 	if (old) {
-		if (pos < 0) {
+		if (stub_funcs) {
+			/* Need to copy one at a time to remove stubs */
+			int probes = 0;
+
+			pos = -1;
+			for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
+				if (old[nr_probes].func == tp_stub_func)
+					continue;
+				if (pos < 0 && old[nr_probes].prio < prio)
+					pos = probes++;
+				new[probes++] = old[nr_probes];
+			}
+			nr_probes = probes;
+			if (pos < 0)
+				pos = probes;
+			else
+				nr_probes--; /* Account for insertion */
+
+		} else if (pos < 0) {
 			pos = nr_probes;
 			memcpy(new, old, nr_probes * sizeof(struct tracepoint_func));
 		} else {
@@ -154,8 +181,9 @@
 	/* (N -> M), (N > 1, M >= 0) probes */
 	if (tp_func->func) {
 		for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
-			if (old[nr_probes].func == tp_func->func &&
-			     old[nr_probes].data == tp_func->data)
+			if ((old[nr_probes].func == tp_func->func &&
+			     old[nr_probes].data == tp_func->data) ||
+			    old[nr_probes].func == tp_stub_func)
 				nr_del++;
 		}
 	}
@@ -174,14 +202,32 @@
 		/* N -> M, (N > 1, M > 0) */
 		/* + 1 for NULL */
 		new = allocate_probes(nr_probes - nr_del + 1);
-		if (new == NULL)
-			return ERR_PTR(-ENOMEM);
-		for (i = 0; old[i].func; i++)
-			if (old[i].func != tp_func->func
-					|| old[i].data != tp_func->data)
-				new[j++] = old[i];
-		new[nr_probes - nr_del].func = NULL;
-		*funcs = new;
+		if (new) {
+			for (i = 0; old[i].func; i++)
+				if ((old[i].func != tp_func->func
+				     || old[i].data != tp_func->data)
+				    && old[i].func != tp_stub_func)
+					new[j++] = old[i];
+			new[nr_probes - nr_del].func = NULL;
+			*funcs = new;
+		} else {
+			/*
+			 * Failed to allocate, replace the old function
+			 * with calls to tp_stub_func.
+			 */
+			for (i = 0; old[i].func; i++)
+				if (old[i].func == tp_func->func &&
+				    old[i].data == tp_func->data) {
+					old[i].func = tp_stub_func;
+					/* Set the prio to the next event. */
+					if (old[i + 1].func)
+						old[i].prio =
+							old[i + 1].prio;
+					else
+						old[i].prio = -1;
+				}
+			*funcs = old;
+		}
 	}
 	debug_print_probes(*funcs);
 	return old;
@@ -202,7 +248,7 @@
 			lockdep_is_held(&tracepoints_mutex));
 	old = func_add(&tp_funcs, func, prio);
 	if (IS_ERR(old)) {
-		WARN_ON_ONCE(1);
+		WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM);
 		return PTR_ERR(old);
 	}
 
@@ -234,10 +280,12 @@
 	tp_funcs = rcu_dereference_protected(tp->funcs,
 			lockdep_is_held(&tracepoints_mutex));
 	old = func_remove(&tp_funcs, func);
-	if (IS_ERR(old)) {
-		WARN_ON_ONCE(1);
+	if (WARN_ON_ONCE(IS_ERR(old)))
 		return PTR_ERR(old);
-	}
+
+	if (tp_funcs == old)
+		/* Failed allocating new tp_funcs, replaced func with stub */
+		return 0;
 
 	if (!tp_funcs) {
 		/* Removed last function */
--- linux-4.4.0.orig/kernel/uid16.c
+++ linux-4.4.0/kernel/uid16.c
@@ -190,6 +190,7 @@
 		return retval;
 	}
 
+	groups_sort(group_info);
 	retval = set_current_groups(group_info);
 	put_group_info(group_info);
 
--- linux-4.4.0.orig/kernel/user_namespace.c
+++ linux-4.4.0/kernel/user_namespace.c
@@ -22,6 +22,13 @@
 #include <linux/ctype.h>
 #include <linux/projid.h>
 #include <linux/fs_struct.h>
+#include <linux/nospec.h>
+
+/*
+ * sysctl determining whether unprivileged users may unshare a new
+ * userns.  Allowed by default
+ */
+int unprivileged_userns_clone = 1;
 
 static struct kmem_cache *user_ns_cachep __read_mostly;
 static DEFINE_MUTEX(userns_state_mutex);
@@ -496,8 +503,10 @@
 	struct uid_gid_extent *extent = NULL;
 	loff_t pos = *ppos;
 
-	if (pos < map->nr_extents)
+	if (pos < map->nr_extents) {
+		pos = array_index_nospec((unsigned long)pos, map->nr_extents); /* needed? */
 		extent = &map->extent[pos];
+	}
 
 	return extent;
 }
@@ -602,9 +611,26 @@
 	struct uid_gid_map new_map;
 	unsigned idx;
 	struct uid_gid_extent *extent = NULL;
-	unsigned long page = 0;
+	unsigned long page;
 	char *kbuf, *pos, *next_line;
-	ssize_t ret = -EINVAL;
+	ssize_t ret;
+
+	/* Only allow < page size writes at the beginning of the file */
+	if ((*ppos != 0) || (count >= PAGE_SIZE))
+		return -EINVAL;
+
+	/* Get a buffer */
+	page = __get_free_page(GFP_TEMPORARY);
+	kbuf = (char *) page;
+	if (!page)
+		return -ENOMEM;
+
+	/* Slurp in the user data */
+	if (copy_from_user(kbuf, buf, count)) {
+		free_page(page);
+		return -EFAULT;
+	}
+	kbuf[count] = '\0';
 
 	/*
 	 * The userns_state_mutex serializes all writes to any given map.
@@ -638,24 +664,6 @@
 	if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN))
 		goto out;
 
-	/* Get a buffer */
-	ret = -ENOMEM;
-	page = __get_free_page(GFP_TEMPORARY);
-	kbuf = (char *) page;
-	if (!page)
-		goto out;
-
-	/* Only allow < page size writes at the beginning of the file */
-	ret = -EINVAL;
-	if ((*ppos != 0) || (count >= PAGE_SIZE))
-		goto out;
-
-	/* Slurp in the user data */
-	ret = -EFAULT;
-	if (copy_from_user(kbuf, buf, count))
-		goto out;
-	kbuf[count] = '\0';
-
 	/* Parse the user data */
 	ret = -EINVAL;
 	pos = kbuf;
@@ -945,6 +953,21 @@
 	return allowed;
 }
 
+/*
+ * Returns true if @ns is the same namespace as or a descendant of
+ * @target_ns.
+ */
+bool current_in_userns(const struct user_namespace *target_ns)
+{
+	struct user_namespace *ns;
+	for (ns = current_user_ns(); ns; ns = ns->parent) {
+		if (ns == target_ns)
+			return true;
+	}
+	return false;
+}
+EXPORT_SYMBOL(current_in_userns);
+
 static inline struct user_namespace *to_user_ns(struct ns_common *ns)
 {
 	return container_of(ns, struct user_namespace, ns);
--- linux-4.4.0.orig/kernel/utsname_sysctl.c
+++ linux-4.4.0/kernel/utsname_sysctl.c
@@ -17,7 +17,7 @@
 
 #ifdef CONFIG_PROC_SYSCTL
 
-static void *get_uts(struct ctl_table *table, int write)
+static void *get_uts(struct ctl_table *table)
 {
 	char *which = table->data;
 	struct uts_namespace *uts_ns;
@@ -25,21 +25,9 @@
 	uts_ns = current->nsproxy->uts_ns;
 	which = (which - (char *)&init_uts_ns) + (char *)uts_ns;
 
-	if (!write)
-		down_read(&uts_sem);
-	else
-		down_write(&uts_sem);
 	return which;
 }
 
-static void put_uts(struct ctl_table *table, int write, void *which)
-{
-	if (!write)
-		up_read(&uts_sem);
-	else
-		up_write(&uts_sem);
-}
-
 /*
  *	Special case of dostring for the UTS structure. This has locks
  *	to observe. Should this be in kernel/sys.c ????
@@ -49,13 +37,34 @@
 {
 	struct ctl_table uts_table;
 	int r;
+	char tmp_data[__NEW_UTS_LEN + 1];
+
 	memcpy(&uts_table, table, sizeof(uts_table));
-	uts_table.data = get_uts(table, write);
+	uts_table.data = tmp_data;
+
+	/*
+	 * Buffer the value in tmp_data so that proc_dostring() can be called
+	 * without holding any locks.
+	 * We also need to read the original value in the write==1 case to
+	 * support partial writes.
+	 */
+	down_read(&uts_sem);
+	memcpy(tmp_data, get_uts(table), sizeof(tmp_data));
+	up_read(&uts_sem);
 	r = proc_dostring(&uts_table, write, buffer, lenp, ppos);
-	put_uts(table, write, uts_table.data);
 
-	if (write)
+	if (write) {
+		/*
+		 * Write back the new value.
+		 * Note that, since we dropped uts_sem, the result can
+		 * theoretically be incorrect if there are two parallel writes
+		 * at non-zero offsets to the same sysctl.
+		 */
+		down_write(&uts_sem);
+		memcpy(get_uts(table), tmp_data, sizeof(tmp_data));
+		up_write(&uts_sem);
 		proc_sys_poll_notify(table->poll);
+	}
 
 	return r;
 }
--- linux-4.4.0.orig/kernel/watchdog.c
+++ linux-4.4.0/kernel/watchdog.c
@@ -328,7 +328,6 @@
 	 */
 	if (is_hardlockup()) {
 		int this_cpu = smp_processor_id();
-		struct pt_regs *regs = get_irq_regs();
 
 		/* only print hardlockups once */
 		if (__this_cpu_read(hard_watchdog_warn) == true)
@@ -907,6 +906,9 @@
 		 * both lockup detectors are disabled if proc_watchdog_update()
 		 * returns an error.
 		 */
+		if (old == new)
+			goto out;
+
 		err = proc_watchdog_update();
 	}
 out:
@@ -951,7 +953,7 @@
 int proc_watchdog_thresh(struct ctl_table *table, int write,
 			 void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-	int err, old;
+	int err, old, new;
 
 	get_online_cpus();
 	mutex_lock(&watchdog_proc_mutex);
@@ -971,6 +973,10 @@
 	/*
 	 * Update the sample period. Restore on failure.
 	 */
+	new = ACCESS_ONCE(watchdog_thresh);
+	if (old == new)
+		goto out;
+
 	set_sample_period();
 	err = proc_watchdog_update();
 	if (err) {
--- linux-4.4.0.orig/kernel/workqueue.c
+++ linux-4.4.0/kernel/workqueue.c
@@ -68,6 +68,7 @@
 	 * attach_mutex to avoid changing binding state while
 	 * worker_attach_to_pool() is in progress.
 	 */
+	POOL_MANAGER_ACTIVE	= 1 << 0,	/* being managed */
 	POOL_DISASSOCIATED	= 1 << 2,	/* cpu can't serve workers */
 
 	/* worker flags */
@@ -163,7 +164,6 @@
 						/* L: hash of busy workers */
 
 	/* see manage_workers() for details on the two manager mutexes */
-	struct mutex		manager_arb;	/* manager arbitration */
 	struct worker		*manager;	/* L: purely informational */
 	struct mutex		attach_mutex;	/* attach/detach exclusion */
 	struct list_head	workers;	/* A: attached workers */
@@ -295,6 +295,7 @@
 
 static DEFINE_MUTEX(wq_pool_mutex);	/* protects pools and workqueues list */
 static DEFINE_SPINLOCK(wq_mayday_lock);	/* protects wq->maydays list */
+static DECLARE_WAIT_QUEUE_HEAD(wq_manager_wait); /* wait for manager to go away */
 
 static LIST_HEAD(workqueues);		/* PR: list of all workqueues */
 static bool workqueue_freezing;		/* PL: have wqs started freezing? */
@@ -568,6 +569,16 @@
 						  int node)
 {
 	assert_rcu_or_wq_mutex_or_pool_mutex(wq);
+
+	/*
+	 * XXX: @node can be NUMA_NO_NODE if CPU goes offline while a
+	 * delayed item is pending.  The plan is to keep CPU -> NODE
+	 * mapping valid and stable across CPU on/offlines.  Once that
+	 * happens, this workaround can be removed.
+	 */
+	if (unlikely(node == NUMA_NO_NODE))
+		return wq->dfl_pwq;
+
 	return rcu_dereference_raw(wq->numa_pwq_tbl[node]);
 }
 
@@ -639,6 +650,35 @@
 	 */
 	smp_wmb();
 	set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT, 0);
+	/*
+	 * The following mb guarantees that previous clear of a PENDING bit
+	 * will not be reordered with any speculative LOADS or STORES from
+	 * work->current_func, which is executed afterwards.  This possible
+	 * reordering can lead to a missed execution on attempt to qeueue
+	 * the same @work.  E.g. consider this case:
+	 *
+	 *   CPU#0                         CPU#1
+	 *   ----------------------------  --------------------------------
+	 *
+	 * 1  STORE event_indicated
+	 * 2  queue_work_on() {
+	 * 3    test_and_set_bit(PENDING)
+	 * 4 }                             set_..._and_clear_pending() {
+	 * 5                                 set_work_data() # clear bit
+	 * 6                                 smp_mb()
+	 * 7                               work->current_func() {
+	 * 8				      LOAD event_indicated
+	 *				   }
+	 *
+	 * Without an explicit full barrier speculative LOAD on line 8 can
+	 * be executed before CPU#0 does STORE on line 1.  If that happens,
+	 * CPU#0 observes the PENDING bit is still set and new execution of
+	 * a @work is not queued in a hope, that CPU#1 will eventually
+	 * finish the queued @work.  Meanwhile CPU#1 does not see
+	 * event_indicated is set, because speculative LOAD was executed
+	 * before actual STORE.
+	 */
+	smp_mb();
 }
 
 static void clear_work_data(struct work_struct *work)
@@ -769,7 +809,7 @@
 /* Do we have too many workers and should some go away? */
 static bool too_many_workers(struct worker_pool *pool)
 {
-	bool managing = mutex_is_locked(&pool->manager_arb);
+	bool managing = pool->flags & POOL_MANAGER_ACTIVE;
 	int nr_idle = pool->nr_idle + managing; /* manager is considered idle */
 	int nr_busy = pool->nr_workers - nr_idle;
 
@@ -1439,6 +1479,7 @@
 	struct timer_list *timer = &dwork->timer;
 	struct work_struct *work = &dwork->work;
 
+	WARN_ON_ONCE(!wq);
 	WARN_ON_ONCE(timer->function != delayed_work_timer_fn ||
 		     timer->data != (unsigned long)dwork);
 	WARN_ON_ONCE(timer_pending(timer));
@@ -1455,16 +1496,14 @@
 		return;
 	}
 
-	timer_stats_timer_set_start_info(&dwork->timer);
-
 	dwork->wq = wq;
-	/* timer isn't guaranteed to run in this cpu, record earlier */
-	if (cpu == WORK_CPU_UNBOUND)
-		cpu = raw_smp_processor_id();
 	dwork->cpu = cpu;
 	timer->expires = jiffies + delay;
 
-	add_timer_on(timer, cpu);
+	if (unlikely(cpu != WORK_CPU_UNBOUND))
+		add_timer_on(timer, cpu);
+	else
+		add_timer(timer);
 }
 
 /**
@@ -1913,24 +1952,17 @@
 {
 	struct worker_pool *pool = worker->pool;
 
-	/*
-	 * Anyone who successfully grabs manager_arb wins the arbitration
-	 * and becomes the manager.  mutex_trylock() on pool->manager_arb
-	 * failure while holding pool->lock reliably indicates that someone
-	 * else is managing the pool and the worker which failed trylock
-	 * can proceed to executing work items.  This means that anyone
-	 * grabbing manager_arb is responsible for actually performing
-	 * manager duties.  If manager_arb is grabbed and released without
-	 * actual management, the pool may stall indefinitely.
-	 */
-	if (!mutex_trylock(&pool->manager_arb))
+	if (pool->flags & POOL_MANAGER_ACTIVE)
 		return false;
+
+	pool->flags |= POOL_MANAGER_ACTIVE;
 	pool->manager = worker;
 
 	maybe_create_worker(pool);
 
 	pool->manager = NULL;
-	mutex_unlock(&pool->manager_arb);
+	pool->flags &= ~POOL_MANAGER_ACTIVE;
+	wake_up(&wq_manager_wait);
 	return true;
 }
 
@@ -2274,8 +2306,14 @@
 			 */
 			if (need_to_create_worker(pool)) {
 				spin_lock(&wq_mayday_lock);
-				get_pwq(pwq);
-				list_move_tail(&pwq->mayday_node, &wq->maydays);
+				/*
+				 * Queue iff we aren't racing destruction
+				 * and somebody else hasn't queued it already.
+				 */
+				if (wq->rescuer && list_empty(&pwq->mayday_node)) {
+					get_pwq(pwq);
+					list_add_tail(&pwq->mayday_node, &wq->maydays);
+				}
 				spin_unlock(&wq_mayday_lock);
 			}
 		}
@@ -3080,7 +3118,6 @@
 	setup_timer(&pool->mayday_timer, pool_mayday_timeout,
 		    (unsigned long)pool);
 
-	mutex_init(&pool->manager_arb);
 	mutex_init(&pool->attach_mutex);
 	INIT_LIST_HEAD(&pool->workers);
 
@@ -3150,13 +3187,15 @@
 	hash_del(&pool->hash_node);
 
 	/*
-	 * Become the manager and destroy all workers.  Grabbing
-	 * manager_arb prevents @pool's workers from blocking on
-	 * attach_mutex.
+	 * Become the manager and destroy all workers.  This prevents
+	 * @pool's workers from blocking on attach_mutex.  We're the last
+	 * manager and @pool gets freed with the flag set.
 	 */
-	mutex_lock(&pool->manager_arb);
-
 	spin_lock_irq(&pool->lock);
+	wait_event_lock_irq(wq_manager_wait,
+			    !(pool->flags & POOL_MANAGER_ACTIVE), pool->lock);
+	pool->flags |= POOL_MANAGER_ACTIVE;
+
 	while ((worker = first_idle_worker(pool)))
 		destroy_worker(worker);
 	WARN_ON(pool->nr_workers || pool->nr_idle);
@@ -3170,8 +3209,6 @@
 	if (pool->detach_completion)
 		wait_for_completion(pool->detach_completion);
 
-	mutex_unlock(&pool->manager_arb);
-
 	/* shut down the timers */
 	del_timer_sync(&pool->idle_timer);
 	del_timer_sync(&pool->mayday_timer);
@@ -3322,17 +3359,24 @@
 	 * is updated and visible.
 	 */
 	if (!freezable || !workqueue_freezing) {
+		bool kick = false;
+
 		pwq->max_active = wq->saved_max_active;
 
 		while (!list_empty(&pwq->delayed_works) &&
-		       pwq->nr_active < pwq->max_active)
+		       pwq->nr_active < pwq->max_active) {
 			pwq_activate_first_delayed(pwq);
+			kick = true;
+		}
 
 		/*
 		 * Need to kick a worker after thawed or an unbound wq's
-		 * max_active is bumped.  It's a slow path.  Do it always.
+		 * max_active is bumped. In realtime scenarios, always kicking a
+		 * worker will cause interference on the isolated cpu cores, so
+		 * let's kick iff work items were activated.
 		 */
-		wake_up_worker(pwq->pool);
+		if (kick)
+			wake_up_worker(pwq->pool);
 	} else {
 		pwq->max_active = 0;
 	}
@@ -3608,8 +3652,12 @@
 		return -EINVAL;
 
 	/* creating multiple pwqs breaks ordering guarantee */
-	if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs)))
-		return -EINVAL;
+	if (!list_empty(&wq->pwqs)) {
+		if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
+			return -EINVAL;
+
+		wq->flags &= ~__WQ_ORDERED;
+	}
 
 	ctx = apply_wqattrs_prepare(wq, attrs);
 
@@ -3795,6 +3843,16 @@
 	struct workqueue_struct *wq;
 	struct pool_workqueue *pwq;
 
+	/*
+	 * Unbound && max_active == 1 used to imply ordered, which is no
+	 * longer the case on NUMA machines due to per-node pools.  While
+	 * alloc_ordered_workqueue() is the right way to create an ordered
+	 * workqueue, keep the previous behavior to avoid subtle breakages
+	 * on NUMA.
+	 */
+	if ((flags & WQ_UNBOUND) && max_active == 1)
+		flags |= __WQ_ORDERED;
+
 	/* see the comment above the definition of WQ_POWER_EFFICIENT */
 	if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient)
 		flags |= WQ_UNBOUND;
@@ -3902,9 +3960,29 @@
 	struct pool_workqueue *pwq;
 	int node;
 
+	/*
+	 * Remove it from sysfs first so that sanity check failure doesn't
+	 * lead to sysfs name conflicts.
+	 */
+	workqueue_sysfs_unregister(wq);
+
 	/* drain it before proceeding with destruction */
 	drain_workqueue(wq);
 
+	/* kill rescuer, if sanity checks fail, leave it w/o rescuer */
+	if (wq->rescuer) {
+		struct worker *rescuer = wq->rescuer;
+
+		/* this prevents new queueing */
+		spin_lock_irq(&wq_mayday_lock);
+		wq->rescuer = NULL;
+		spin_unlock_irq(&wq_mayday_lock);
+
+		/* rescuer will empty maydays list before exiting */
+		kthread_stop(rescuer->task);
+		kfree(rescuer);
+	}
+
 	/* sanity checks */
 	mutex_lock(&wq->mutex);
 	for_each_pwq(pwq, wq) {
@@ -3934,11 +4012,6 @@
 	list_del_rcu(&wq->list);
 	mutex_unlock(&wq_pool_mutex);
 
-	workqueue_sysfs_unregister(wq);
-
-	if (wq->rescuer)
-		kthread_stop(wq->rescuer->task);
-
 	if (!(wq->flags & WQ_UNBOUND)) {
 		/*
 		 * The base ref is never dropped on per-cpu pwqs.  Directly
@@ -3983,13 +4056,14 @@
 	struct pool_workqueue *pwq;
 
 	/* disallow meddling with max_active for ordered workqueues */
-	if (WARN_ON(wq->flags & __WQ_ORDERED))
+	if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
 		return;
 
 	max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
 
 	mutex_lock(&wq->mutex);
 
+	wq->flags &= ~__WQ_ORDERED;
 	wq->saved_max_active = max_active;
 
 	for_each_pwq(pwq, wq)
@@ -4000,6 +4074,22 @@
 EXPORT_SYMBOL_GPL(workqueue_set_max_active);
 
 /**
+ * current_work - retrieve %current task's work struct
+ *
+ * Determine if %current task is a workqueue worker and what it's working on.
+ * Useful to find out the context that the %current task is running in.
+ *
+ * Return: work struct if %current task is a workqueue worker, %NULL otherwise.
+ */
+struct work_struct *current_work(void)
+{
+	struct worker *worker = current_wq_worker();
+
+	return worker ? worker->current_work : NULL;
+}
+EXPORT_SYMBOL(current_work);
+
+/**
  * current_is_workqueue_rescuer - is %current workqueue rescuer?
  *
  * Determine whether %current is a workqueue rescuer.  Can be used from
@@ -4198,7 +4288,8 @@
 	pr_info("  pwq %d:", pool->id);
 	pr_cont_pool_info(pool);
 
-	pr_cont(" active=%d/%d%s\n", pwq->nr_active, pwq->max_active,
+	pr_cont(" active=%d/%d refcnt=%d%s\n",
+		pwq->nr_active, pwq->max_active, pwq->refcnt,
 		!list_empty(&pwq->mayday_node) ? " MAYDAY" : "");
 
 	hash_for_each(pool->busy_hash, bkt, worker, hentry) {
@@ -4418,6 +4509,17 @@
 						  pool->attrs->cpumask) < 0);
 
 	spin_lock_irq(&pool->lock);
+
+	/*
+	 * XXX: CPU hotplug notifiers are weird and can call DOWN_FAILED
+	 * w/o preceding DOWN_PREPARE.  Work around it.  CPU hotplug is
+	 * being reworked and this can go away in time.
+	 */
+	if (!(pool->flags & POOL_DISASSOCIATED)) {
+		spin_unlock_irq(&pool->lock);
+		return;
+	}
+
 	pool->flags &= ~POOL_DISASSOCIATED;
 
 	for_each_pool_worker(worker, pool) {
@@ -5104,7 +5206,7 @@
 	 * attributes breaks ordering guarantee.  Disallow exposing ordered
 	 * workqueues.
 	 */
-	if (WARN_ON(wq->flags & __WQ_ORDERED))
+	if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
 		return -EINVAL;
 
 	wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL);
@@ -5124,7 +5226,7 @@
 
 	ret = device_register(&wq_dev->dev);
 	if (ret) {
-		kfree(wq_dev);
+		put_device(&wq_dev->dev);
 		wq->wq_dev = NULL;
 		return ret;
 	}
--- linux-4.4.0.orig/kernel/workqueue_internal.h
+++ linux-4.4.0/kernel/workqueue_internal.h
@@ -9,6 +9,7 @@
 
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
+#include <linux/preempt.h>
 
 struct worker_pool;
 
@@ -59,7 +60,7 @@
  */
 static inline struct worker *current_wq_worker(void)
 {
-	if (current->flags & PF_WQ_WORKER)
+	if (in_task() && (current->flags & PF_WQ_WORKER))
 		return kthread_data(current);
 	return NULL;
 }
--- linux-4.4.0.orig/lib/842/842.h
+++ linux-4.4.0/lib/842/842.h
@@ -76,7 +76,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
-#include <linux/crc32.h>
 #include <asm/unaligned.h>
 
 #include <linux/sw842.h>
@@ -99,7 +98,6 @@
 #define I2_BITS		(8)
 #define I4_BITS		(9)
 #define I8_BITS		(8)
-#define CRC_BITS	(32)
 
 #define REPEAT_BITS_MAX		(0x3f)
 #define SHORT_DATA_BITS_MAX	(0x7)
--- linux-4.4.0.orig/lib/842/842_compress.c
+++ linux-4.4.0/lib/842/842_compress.c
@@ -490,7 +490,6 @@
 	int ret;
 	u64 last, next, pad, total;
 	u8 repeat_count = 0;
-	u32 crc;
 
 	BUILD_BUG_ON(sizeof(*p) > SW842_MEM_COMPRESS);
 
@@ -581,18 +580,6 @@
 	if (ret)
 		return ret;
 
-	/*
-	 * crc(0:31) is appended to target data starting with the next
-	 * bit after End of stream template.
-	 * nx842 calculates CRC for data in big-endian format. So doing
-	 * same here so that sw842 decompression can be used for both
-	 * compressed data.
-	 */
-	crc = crc32_be(0, in, ilen);
-	ret = add_bits(p, crc, CRC_BITS);
-	if (ret)
-		return ret;
-
 	if (p->bit) {
 		p->out++;
 		p->olen--;
--- linux-4.4.0.orig/lib/842/842_decompress.c
+++ linux-4.4.0/lib/842/842_decompress.c
@@ -285,7 +285,6 @@
 	struct sw842_param p;
 	int ret;
 	u64 op, rep, tmp, bytes, total;
-	u64 crc;
 
 	p.in = (u8 *)in;
 	p.bit = 0;
@@ -376,22 +375,6 @@
 		}
 	} while (op != OP_END);
 
-	/*
-	 * crc(0:31) is saved in compressed data starting with the
-	 * next bit after End of stream template.
-	 */
-	ret = next_bits(&p, &crc, CRC_BITS);
-	if (ret)
-		return ret;
-
-	/*
-	 * Validate CRC saved in compressed data.
-	 */
-	if (crc != (u64)crc32_be(0, out, total - p.olen)) {
-		pr_debug("CRC mismatch for decompression\n");
-		return -EINVAL;
-	}
-
 	if (unlikely((total - p.olen) > UINT_MAX))
 		return -ENOSPC;
 
--- linux-4.4.0.orig/lib/Kconfig
+++ linux-4.4.0/lib/Kconfig
@@ -210,9 +210,11 @@
 # compression support is select'ed if needed
 #
 config 842_COMPRESS
+	select CRC32
 	tristate
 
 config 842_DECOMPRESS
+	select CRC32
 	tristate
 
 config ZLIB_INFLATE
@@ -493,6 +495,14 @@
 	  Digital signature verification. Currently only RSA is supported.
 	  Implementation is done using GnuPG MPI library
 
+config DIMLIB
+	bool "DIM library"
+	default y
+	help
+	  Dynamic Interrupt Moderation library.
+	  Implements an algorithm for dynamically change CQ modertion values
+	  according to run time performance.
+
 #
 # libfdt files, only selected if needed.
 #
--- linux-4.4.0.orig/lib/Kconfig.debug
+++ linux-4.4.0/lib/Kconfig.debug
@@ -145,7 +145,7 @@
 
 config DEBUG_INFO_SPLIT
 	bool "Produce split debuginfo in .dwo files"
-	depends on DEBUG_INFO
+	depends on DEBUG_INFO && !FRV
 	help
 	  Generate debug info into separate .dwo files. This significantly
 	  reduces the build directory size for builds with DEBUG_INFO,
@@ -197,7 +197,7 @@
 config FRAME_WARN
 	int "Warn for stack frames larger than (needs gcc 4.4)"
 	range 0 8192
-	default 0 if KASAN
+	default 2048 if GCC_PLUGIN_LATENT_ENTROPY
 	default 1024 if !64BIT
 	default 2048 if 64BIT
 	help
@@ -257,6 +257,7 @@
 
 config DEBUG_FS
 	bool "Debug Filesystem"
+	select SRCU
 	help
 	  debugfs is a virtual file system that kernel developers use to put
 	  debugging files into.  Enable this option to be able to read and
@@ -521,7 +522,7 @@
 	int "Maximum kmemleak early log entries"
 	depends on DEBUG_KMEMLEAK
 	range 200 40000
-	default 400
+	default 16000
 	help
 	  Kmemleak must track all the memory allocations to avoid
 	  reporting false positives. Since memory may be allocated or
@@ -893,20 +894,6 @@
 
 	  If unsure, say N.
 
-config TIMER_STATS
-	bool "Collect kernel timers statistics"
-	depends on DEBUG_KERNEL && PROC_FS
-	help
-	  If you say Y here, additional code will be inserted into the
-	  timer routines to collect statistics about kernel timers being
-	  reprogrammed. The statistics can be read from /proc/timer_stats.
-	  The statistics collection is started by writing 1 to /proc/timer_stats,
-	  writing 0 stops it. This feature is useful to collect information
-	  about timer usage patterns in kernel and userspace. This feature
-	  is lightweight if enabled in the kernel config but not activated
-	  (it defaults to deactivated on bootup and will only be activated
-	  if some application like powertop activates it explicitly).
-
 config DEBUG_PREEMPT
 	bool "Debug preemptible kernel"
 	depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
@@ -1706,6 +1693,17 @@
 
 	  If unsure, say N.
 
+config TEST_HASH
+	tristate "Perform selftest on hash functions"
+	default n
+	help
+	  Enable this option to test the kernel's integer (<linux/hash.h>),
+	  string (<linux/stringhash.h>), and siphash (<linux/siphash.h>)
+	  hash functions on boot (or module load).
+
+	  This is intended to help people writing architecture-specific
+	  optimized versions.  If unsure, say N.
+
 endmenu # runtime tests
 
 config PROVIDE_OHCI1394_DMA_INIT
--- linux-4.4.0.orig/lib/Makefile
+++ linux-4.4.0/lib/Makefile
@@ -13,7 +13,7 @@
 	 sha1.o md5.o irq_regs.o argv_split.o \
 	 proportions.o flex_proportions.o ratelimit.o show_mem.o \
 	 is_single_threaded.o plist.o decompress.o kobject_uevent.o \
-	 earlycpio.o seq_buf.o nmi_backtrace.o
+	 earlycpio.o seq_buf.o nmi_backtrace.o siphash.o
 
 obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o
 lib-$(CONFIG_MMU) += ioremap.o
@@ -35,6 +35,7 @@
 obj-y += kstrtox.o
 obj-$(CONFIG_TEST_BPF) += test_bpf.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
+obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o
 obj-$(CONFIG_TEST_KASAN) += test_kasan.o
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
 obj-$(CONFIG_TEST_LKM) += test_module.o
@@ -58,8 +59,6 @@
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
 obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
 
-GCOV_PROFILE_hweight.o := n
-CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
 obj-$(CONFIG_BTREE) += btree.o
@@ -151,6 +150,7 @@
 obj-$(CONFIG_GLOB) += glob.o
 
 obj-$(CONFIG_MPILIB) += mpi/
+obj-$(CONFIG_DIMLIB) += dim/
 obj-$(CONFIG_SIGNATURE) += digsig.o
 
 obj-$(CONFIG_CLZ_TAB) += clz_tab.o
--- linux-4.4.0.orig/lib/asn1_decoder.c
+++ linux-4.4.0/lib/asn1_decoder.c
@@ -74,7 +74,7 @@
 
 	/* Extract a tag from the data */
 	tag = data[dp++];
-	if (tag == 0) {
+	if (tag == ASN1_EOC) {
 		/* It appears to be an EOC. */
 		if (data[dp++] != 0)
 			goto invalid_eoc;
@@ -96,10 +96,8 @@
 
 	/* Extract the length */
 	len = data[dp++];
-	if (len <= 0x7f) {
-		dp += len;
-		goto next_tag;
-	}
+	if (len <= 0x7f)
+		goto check_length;
 
 	if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
 		/* Indefinite length */
@@ -110,14 +108,18 @@
 	}
 
 	n = len - 0x80;
-	if (unlikely(n > sizeof(size_t) - 1))
+	if (unlikely(n > sizeof(len) - 1))
 		goto length_too_long;
 	if (unlikely(n > datalen - dp))
 		goto data_overrun_error;
-	for (len = 0; n > 0; n--) {
+	len = 0;
+	for (; n > 0; n--) {
 		len <<= 8;
 		len |= data[dp++];
 	}
+check_length:
+	if (len > datalen - dp)
+		goto data_overrun_error;
 	dp += len;
 	goto next_tag;
 
@@ -225,7 +227,7 @@
 		hdr = 2;
 
 		/* Extract a tag from the data */
-		if (unlikely(dp >= datalen - 1))
+		if (unlikely(datalen - dp < 2))
 			goto data_overrun_error;
 		tag = data[dp++];
 		if (unlikely((tag & 0x1f) == ASN1_LONG_TAG))
@@ -271,7 +273,7 @@
 				int n = len - 0x80;
 				if (unlikely(n > 2))
 					goto length_too_long;
-				if (unlikely(dp >= datalen - n))
+				if (unlikely(n > datalen - dp))
 					goto data_overrun_error;
 				hdr += n;
 				for (len = 0; n > 0; n--) {
@@ -281,6 +283,9 @@
 				if (unlikely(len > datalen - dp))
 					goto data_overrun_error;
 			}
+		} else {
+			if (unlikely(len > datalen - dp))
+				goto data_overrun_error;
 		}
 
 		if (flags & FLAG_CONS) {
@@ -307,42 +312,47 @@
 
 	/* Decide how to handle the operation */
 	switch (op) {
-	case ASN1_OP_MATCH_ANY_ACT:
-	case ASN1_OP_MATCH_ANY_ACT_OR_SKIP:
-	case ASN1_OP_COND_MATCH_ANY_ACT:
-	case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP:
-		ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len);
-		if (ret < 0)
-			return ret;
-		goto skip_data;
-
-	case ASN1_OP_MATCH_ACT:
-	case ASN1_OP_MATCH_ACT_OR_SKIP:
-	case ASN1_OP_COND_MATCH_ACT_OR_SKIP:
-		ret = actions[machine[pc + 2]](context, hdr, tag, data + dp, len);
-		if (ret < 0)
-			return ret;
-		goto skip_data;
-
 	case ASN1_OP_MATCH:
 	case ASN1_OP_MATCH_OR_SKIP:
+	case ASN1_OP_MATCH_ACT:
+	case ASN1_OP_MATCH_ACT_OR_SKIP:
 	case ASN1_OP_MATCH_ANY:
 	case ASN1_OP_MATCH_ANY_OR_SKIP:
+	case ASN1_OP_MATCH_ANY_ACT:
+	case ASN1_OP_MATCH_ANY_ACT_OR_SKIP:
 	case ASN1_OP_COND_MATCH_OR_SKIP:
+	case ASN1_OP_COND_MATCH_ACT_OR_SKIP:
 	case ASN1_OP_COND_MATCH_ANY:
 	case ASN1_OP_COND_MATCH_ANY_OR_SKIP:
-	skip_data:
+	case ASN1_OP_COND_MATCH_ANY_ACT:
+	case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP:
+
 		if (!(flags & FLAG_CONS)) {
 			if (flags & FLAG_INDEFINITE_LENGTH) {
+				size_t tmp = dp;
+
 				ret = asn1_find_indefinite_length(
-					data, datalen, &dp, &len, &errmsg);
+					data, datalen, &tmp, &len, &errmsg);
 				if (ret < 0)
 					goto error;
-			} else {
-				dp += len;
 			}
 			pr_debug("- LEAF: %zu\n", len);
 		}
+
+		if (op & ASN1_OP_MATCH__ACT) {
+			unsigned char act;
+
+			if (op & ASN1_OP_MATCH__ANY)
+				act = machine[pc + 1];
+			else
+				act = machine[pc + 2];
+			ret = actions[act](context, hdr, tag, data + dp, len);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (!(flags & FLAG_CONS))
+			dp += len;
 		pc += asn1_op_lengths[op];
 		goto next_op;
 
@@ -428,6 +438,8 @@
 			else
 				act = machine[pc + 1];
 			ret = actions[act](context, hdr, 0, data + tdp, len);
+			if (ret < 0)
+				return ret;
 		}
 		pc += asn1_op_lengths[op];
 		goto next_op;
--- linux-4.4.0.orig/lib/assoc_array.c
+++ linux-4.4.0/lib/assoc_array.c
@@ -524,7 +524,9 @@
 			free_slot = i;
 			continue;
 		}
-		if (ops->compare_object(assoc_array_ptr_to_leaf(ptr), index_key)) {
+		if (assoc_array_ptr_is_leaf(ptr) &&
+		    ops->compare_object(assoc_array_ptr_to_leaf(ptr),
+					index_key)) {
 			pr_devel("replace in slot %d\n", i);
 			edit->leaf_p = &node->slots[i];
 			edit->dead_leaf = node->slots[i];
@@ -596,21 +598,31 @@
 		if ((edit->segment_cache[ASSOC_ARRAY_FAN_OUT] ^ base_seg) == 0)
 			goto all_leaves_cluster_together;
 
-		/* Otherwise we can just insert a new node ahead of the old
-		 * one.
+		/* Otherwise all the old leaves cluster in the same slot, but
+		 * the new leaf wants to go into a different slot - so we
+		 * create a new node (n0) to hold the new leaf and a pointer to
+		 * a new node (n1) holding all the old leaves.
+		 *
+		 * This can be done by falling through to the node splitting
+		 * path.
 		 */
-		goto present_leaves_cluster_but_not_new_leaf;
+		pr_devel("present leaves cluster but not new leaf\n");
 	}
 
 split_node:
 	pr_devel("split node\n");
 
-	/* We need to split the current node; we know that the node doesn't
-	 * simply contain a full set of leaves that cluster together (it
-	 * contains meta pointers and/or non-clustering leaves).
+	/* We need to split the current node.  The node must contain anything
+	 * from a single leaf (in the one leaf case, this leaf will cluster
+	 * with the new leaf) and the rest meta-pointers, to all leaves, some
+	 * of which may cluster.
+	 *
+	 * It won't contain the case in which all the current leaves plus the
+	 * new leaves want to cluster in the same slot.
 	 *
 	 * We need to expel at least two leaves out of a set consisting of the
-	 * leaves in the node and the new leaf.
+	 * leaves in the node and the new leaf.  The current meta pointers can
+	 * just be copied as they shouldn't cluster with any of the leaves.
 	 *
 	 * We need a new node (n0) to replace the current one and a new node to
 	 * take the expelled nodes (n1).
@@ -715,33 +727,6 @@
 	pr_devel("<--%s() = ok [split node]\n", __func__);
 	return true;
 
-present_leaves_cluster_but_not_new_leaf:
-	/* All the old leaves cluster in the same slot, but the new leaf wants
-	 * to go into a different slot, so we create a new node to hold the new
-	 * leaf and a pointer to a new node holding all the old leaves.
-	 */
-	pr_devel("present leaves cluster but not new leaf\n");
-
-	new_n0->back_pointer = node->back_pointer;
-	new_n0->parent_slot = node->parent_slot;
-	new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch;
-	new_n1->back_pointer = assoc_array_node_to_ptr(new_n0);
-	new_n1->parent_slot = edit->segment_cache[0];
-	new_n1->nr_leaves_on_branch = node->nr_leaves_on_branch;
-	edit->adjust_count_on = new_n0;
-
-	for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++)
-		new_n1->slots[i] = node->slots[i];
-
-	new_n0->slots[edit->segment_cache[0]] = assoc_array_node_to_ptr(new_n0);
-	edit->leaf_p = &new_n0->slots[edit->segment_cache[ASSOC_ARRAY_FAN_OUT]];
-
-	edit->set[0].ptr = &assoc_array_ptr_to_node(node->back_pointer)->slots[node->parent_slot];
-	edit->set[0].to = assoc_array_node_to_ptr(new_n0);
-	edit->excised_meta[0] = assoc_array_node_to_ptr(node);
-	pr_devel("<--%s() = ok [insert node before]\n", __func__);
-	return true;
-
 all_leaves_cluster_together:
 	/* All the leaves, new and old, want to cluster together in this node
 	 * in the same slot, so we have to replace this node with a shortcut to
@@ -796,9 +781,11 @@
 		new_s0->index_key[i] =
 			ops->get_key_chunk(index_key, i * ASSOC_ARRAY_KEY_CHUNK_SIZE);
 
-	blank = ULONG_MAX << (level & ASSOC_ARRAY_KEY_CHUNK_MASK);
-	pr_devel("blank off [%zu] %d: %lx\n", keylen - 1, level, blank);
-	new_s0->index_key[keylen - 1] &= ~blank;
+	if (level & ASSOC_ARRAY_KEY_CHUNK_MASK) {
+		blank = ULONG_MAX << (level & ASSOC_ARRAY_KEY_CHUNK_MASK);
+		pr_devel("blank off [%zu] %d: %lx\n", keylen - 1, level, blank);
+		new_s0->index_key[keylen - 1] &= ~blank;
+	}
 
 	/* This now reduces to a node splitting exercise for which we'll need
 	 * to regenerate the disparity table.
--- linux-4.4.0.orig/lib/atomic64_test.c
+++ linux-4.4.0/lib/atomic64_test.c
@@ -16,6 +16,10 @@
 #include <linux/kernel.h>
 #include <linux/atomic.h>
 
+#ifdef CONFIG_X86
+#include <asm/cpufeature.h>	/* for boot_cpu_has below */
+#endif
+
 #define TEST(bit, op, c_op, val)				\
 do {								\
 	atomic##bit##_set(&v, v0);				\
--- linux-4.4.0.orig/lib/bitmap.c
+++ linux-4.4.0/lib/bitmap.c
@@ -12,6 +12,9 @@
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
@@ -1060,6 +1063,93 @@
 EXPORT_SYMBOL(bitmap_allocate_region);
 
 /**
+ * bitmap_from_u32array - copy the contents of a u32 array of bits to bitmap
+ *	@bitmap: array of unsigned longs, the destination bitmap, non NULL
+ *	@nbits: number of bits in @bitmap
+ *	@buf: array of u32 (in host byte order), the source bitmap, non NULL
+ *	@nwords: number of u32 words in @buf
+ *
+ * copy min(nbits, 32*nwords) bits from @buf to @bitmap, remaining
+ * bits between nword and nbits in @bitmap (if any) are cleared. In
+ * last word of @bitmap, the bits beyond nbits (if any) are kept
+ * unchanged.
+ *
+ * Return the number of bits effectively copied.
+ */
+unsigned int
+bitmap_from_u32array(unsigned long *bitmap, unsigned int nbits,
+		     const u32 *buf, unsigned int nwords)
+{
+	unsigned int dst_idx, src_idx;
+
+	for (src_idx = dst_idx = 0; dst_idx < BITS_TO_LONGS(nbits); ++dst_idx) {
+		unsigned long part = 0;
+
+		if (src_idx < nwords)
+			part = buf[src_idx++];
+
+#if BITS_PER_LONG == 64
+		if (src_idx < nwords)
+			part |= ((unsigned long) buf[src_idx++]) << 32;
+#endif
+
+		if (dst_idx < nbits/BITS_PER_LONG)
+			bitmap[dst_idx] = part;
+		else {
+			unsigned long mask = BITMAP_LAST_WORD_MASK(nbits);
+
+			bitmap[dst_idx] = (bitmap[dst_idx] & ~mask)
+				| (part & mask);
+		}
+	}
+
+	return min_t(unsigned int, nbits, 32*nwords);
+}
+EXPORT_SYMBOL(bitmap_from_u32array);
+
+/**
+ * bitmap_to_u32array - copy the contents of bitmap to a u32 array of bits
+ *	@buf: array of u32 (in host byte order), the dest bitmap, non NULL
+ *	@nwords: number of u32 words in @buf
+ *	@bitmap: array of unsigned longs, the source bitmap, non NULL
+ *	@nbits: number of bits in @bitmap
+ *
+ * copy min(nbits, 32*nwords) bits from @bitmap to @buf. Remaining
+ * bits after nbits in @buf (if any) are cleared.
+ *
+ * Return the number of bits effectively copied.
+ */
+unsigned int
+bitmap_to_u32array(u32 *buf, unsigned int nwords,
+		   const unsigned long *bitmap, unsigned int nbits)
+{
+	unsigned int dst_idx = 0, src_idx = 0;
+
+	while (dst_idx < nwords) {
+		unsigned long part = 0;
+
+		if (src_idx < BITS_TO_LONGS(nbits)) {
+			part = bitmap[src_idx];
+			if (src_idx >= nbits/BITS_PER_LONG)
+				part &= BITMAP_LAST_WORD_MASK(nbits);
+			src_idx++;
+		}
+
+		buf[dst_idx++] = part & 0xffffffffUL;
+
+#if BITS_PER_LONG == 64
+		if (dst_idx < nwords) {
+			part >>= 32;
+			buf[dst_idx++] = part & 0xffffffffUL;
+		}
+#endif
+	}
+
+	return min_t(unsigned int, nbits, 32*nwords);
+}
+EXPORT_SYMBOL(bitmap_to_u32array);
+
+/**
  * bitmap_copy_le - copy a bitmap, putting the bits into little-endian order.
  * @dst:   destination buffer
  * @src:   bitmap to copy
@@ -1081,3 +1171,22 @@
 }
 EXPORT_SYMBOL(bitmap_copy_le);
 #endif
+
+unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags)
+{
+	return kmalloc_array(BITS_TO_LONGS(nbits), sizeof(unsigned long),
+			     flags);
+}
+EXPORT_SYMBOL(bitmap_alloc);
+
+unsigned long *bitmap_zalloc(unsigned int nbits, gfp_t flags)
+{
+	return bitmap_alloc(nbits, flags | __GFP_ZERO);
+}
+EXPORT_SYMBOL(bitmap_zalloc);
+
+void bitmap_free(const unsigned long *bitmap)
+{
+	kfree(bitmap);
+}
+EXPORT_SYMBOL(bitmap_free);
--- linux-4.4.0.orig/lib/bsearch.c
+++ linux-4.4.0/lib/bsearch.c
@@ -11,6 +11,7 @@
 
 #include <linux/export.h>
 #include <linux/bsearch.h>
+#include <linux/kprobes.h>
 
 /*
  * bsearch - binary search an array of elements
@@ -51,3 +52,4 @@
 	return NULL;
 }
 EXPORT_SYMBOL(bsearch);
+NOKPROBE_SYMBOL(bsearch);
--- linux-4.4.0.orig/lib/cmdline.c
+++ linux-4.4.0/lib/cmdline.c
@@ -22,14 +22,14 @@
  *	the values[M, M+1, ..., N] into the ints array in get_options.
  */
 
-static int get_range(char **str, int *pint)
+static int get_range(char **str, int *pint, int n)
 {
 	int x, inc_counter, upper_range;
 
 	(*str)++;
 	upper_range = simple_strtol((*str), NULL, 0);
 	inc_counter = upper_range - *pint;
-	for (x = *pint; x < upper_range; x++)
+	for (x = *pint; n && x < upper_range; x++, n--)
 		*pint++ = x;
 	return inc_counter;
 }
@@ -96,7 +96,7 @@
 			break;
 		if (res == 3) {
 			int range_nums;
-			range_nums = get_range((char **)&str, ints + i);
+			range_nums = get_range((char **)&str, ints + i, nints - i);
 			if (range_nums < 0)
 				break;
 			/*
--- linux-4.4.0.orig/lib/cpumask.c
+++ linux-4.4.0/lib/cpumask.c
@@ -42,6 +42,38 @@
 	return i;
 }
 
+/**
+ * cpumask_next_wrap - helper to implement for_each_cpu_wrap
+ * @n: the cpu prior to the place to search
+ * @mask: the cpumask pointer
+ * @start: the start point of the iteration
+ * @wrap: assume @n crossing @start terminates the iteration
+ *
+ * Returns >= nr_cpu_ids on completion
+ *
+ * Note: the @wrap argument is required for the start condition when
+ * we cannot assume @start is set in @mask.
+ */
+int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap)
+{
+	int next;
+
+again:
+	next = cpumask_next(n, mask);
+
+	if (wrap && n < start && next >= start) {
+		return nr_cpumask_bits;
+
+	} else if (next >= nr_cpumask_bits) {
+		wrap = true;
+		n = -1;
+		goto again;
+	}
+
+	return next;
+}
+EXPORT_SYMBOL(cpumask_next_wrap);
+
 /* These are not inline because of header tangles. */
 #ifdef CONFIG_CPUMASK_OFFSTACK
 /**
--- linux-4.4.0.orig/lib/crc32.c
+++ linux-4.4.0/lib/crc32.c
@@ -327,7 +327,7 @@
 	return crc;
 }
 
-#if CRC_LE_BITS == 1
+#if CRC_BE_BITS == 1
 u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
 {
 	return crc32_be_generic(crc, p, len, NULL, CRCPOLY_BE);
--- linux-4.4.0.orig/lib/debug_locks.c
+++ linux-4.4.0/lib/debug_locks.c
@@ -37,7 +37,7 @@
  */
 int debug_locks_off(void)
 {
-	if (__debug_locks_off()) {
+	if (debug_locks && __debug_locks_off()) {
 		if (!debug_locks_silent) {
 			console_verbose();
 			return 1;
--- linux-4.4.0.orig/lib/debugobjects.c
+++ linux-4.4.0/lib/debugobjects.c
@@ -295,9 +295,12 @@
 
 	limit++;
 	if (is_on_stack)
-		pr_warn("object is on stack, but not annotated\n");
+		pr_warn("object %p is on stack %p, but NOT annotated.\n", addr,
+			 task_stack_page(current));
 	else
-		pr_warn("object is not on stack, but annotated\n");
+		pr_warn("object %p is NOT on stack %p, but annotated.\n", addr,
+			 task_stack_page(current));
+
 	WARN_ON(1);
 }
 
@@ -1085,7 +1088,8 @@
 
 	obj_cache = kmem_cache_create("debug_objects_cache",
 				      sizeof (struct debug_obj), 0,
-				      SLAB_DEBUG_OBJECTS, NULL);
+				      SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE,
+				      NULL);
 
 	if (!obj_cache || debug_objects_replace_static_objects()) {
 		debug_objects_enabled = 0;
--- linux-4.4.0.orig/lib/devres.c
+++ linux-4.4.0/lib/devres.c
@@ -131,7 +131,8 @@
  *	if (IS_ERR(base))
  *		return PTR_ERR(base);
  */
-void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
+void __iomem *devm_ioremap_resource(struct device *dev,
+				    const struct resource *res)
 {
 	resource_size_t size;
 	const char *name;
--- linux-4.4.0.orig/lib/digsig.c
+++ linux-4.4.0/lib/digsig.c
@@ -87,6 +87,12 @@
 	down_read(&key->sem);
 	ukp = user_key_payload(key);
 
+	if (!ukp) {
+		/* key was revoked before we acquired its semaphore */
+		err = -EKEYREVOKED;
+		goto err1;
+	}
+
 	if (ukp->datalen < sizeof(*pkh))
 		goto err1;
 
--- linux-4.4.0.orig/lib/dim/Makefile
+++ linux-4.4.0/lib/dim/Makefile
@@ -0,0 +1,7 @@
+#
+# DIM Dynamic Interrupt Moderation library
+#
+
+obj-$(CONFIG_DIMLIB) += dimlib.o
+
+dimlib-y := dim.o net_dim.o rdma_dim.o
--- linux-4.4.0.orig/lib/dim/dim.c
+++ linux-4.4.0/lib/dim/dim.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2019, Mellanox Technologies inc.  All rights reserved.
+ */
+
+#include <linux/dim.h>
+
+bool dim_on_top(struct dim *dim)
+{
+	switch (dim->tune_state) {
+	case DIM_PARKING_ON_TOP:
+	case DIM_PARKING_TIRED:
+		return true;
+	case DIM_GOING_RIGHT:
+		return (dim->steps_left > 1) && (dim->steps_right == 1);
+	default: /* DIM_GOING_LEFT */
+		return (dim->steps_right > 1) && (dim->steps_left == 1);
+	}
+}
+EXPORT_SYMBOL(dim_on_top);
+
+void dim_turn(struct dim *dim)
+{
+	switch (dim->tune_state) {
+	case DIM_PARKING_ON_TOP:
+	case DIM_PARKING_TIRED:
+		break;
+	case DIM_GOING_RIGHT:
+		dim->tune_state = DIM_GOING_LEFT;
+		dim->steps_left = 0;
+		break;
+	case DIM_GOING_LEFT:
+		dim->tune_state = DIM_GOING_RIGHT;
+		dim->steps_right = 0;
+		break;
+	}
+}
+EXPORT_SYMBOL(dim_turn);
+
+void dim_park_on_top(struct dim *dim)
+{
+	dim->steps_right  = 0;
+	dim->steps_left   = 0;
+	dim->tired        = 0;
+	dim->tune_state   = DIM_PARKING_ON_TOP;
+}
+EXPORT_SYMBOL(dim_park_on_top);
+
+void dim_park_tired(struct dim *dim)
+{
+	dim->steps_right  = 0;
+	dim->steps_left   = 0;
+	dim->tune_state   = DIM_PARKING_TIRED;
+}
+EXPORT_SYMBOL(dim_park_tired);
+
+void dim_calc_stats(struct dim_sample *start, struct dim_sample *end,
+		    struct dim_stats *curr_stats)
+{
+	/* u32 holds up to 71 minutes, should be enough */
+	u32 delta_us = ktime_us_delta(end->time, start->time);
+	u32 npkts = BIT_GAP(BITS_PER_TYPE(u32), end->pkt_ctr, start->pkt_ctr);
+	u32 nbytes = BIT_GAP(BITS_PER_TYPE(u32), end->byte_ctr,
+			     start->byte_ctr);
+	u32 ncomps = BIT_GAP(BITS_PER_TYPE(u32), end->comp_ctr,
+			     start->comp_ctr);
+
+	if (!delta_us)
+		return;
+
+	curr_stats->ppms = DIV_ROUND_UP(npkts * USEC_PER_MSEC, delta_us);
+	curr_stats->bpms = DIV_ROUND_UP(nbytes * USEC_PER_MSEC, delta_us);
+	curr_stats->epms = DIV_ROUND_UP(DIM_NEVENTS * USEC_PER_MSEC,
+					delta_us);
+	curr_stats->cpms = DIV_ROUND_UP(ncomps * USEC_PER_MSEC, delta_us);
+	if (curr_stats->epms != 0)
+		curr_stats->cpe_ratio = DIV_ROUND_DOWN_ULL(
+			curr_stats->cpms * 100, curr_stats->epms);
+	else
+		curr_stats->cpe_ratio = 0;
+
+}
+EXPORT_SYMBOL(dim_calc_stats);
--- linux-4.4.0.orig/lib/dim/net_dim.c
+++ linux-4.4.0/lib/dim/net_dim.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2018, Mellanox Technologies inc.  All rights reserved.
+ */
+
+#include <linux/dim.h>
+
+/*
+ * Net DIM profiles:
+ *        There are different set of profiles for each CQ period mode.
+ *        There are different set of profiles for RX/TX CQs.
+ *        Each profile size must be of NET_DIM_PARAMS_NUM_PROFILES
+ */
+#define NET_DIM_PARAMS_NUM_PROFILES 5
+#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
+#define NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE 128
+#define NET_DIM_DEF_PROFILE_CQE 1
+#define NET_DIM_DEF_PROFILE_EQE 1
+
+#define NET_DIM_RX_EQE_PROFILES { \
+	{1,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+	{8,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+	{64,  NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+	{128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+	{256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+}
+
+#define NET_DIM_RX_CQE_PROFILES { \
+	{2,  256},             \
+	{8,  128},             \
+	{16, 64},              \
+	{32, 64},              \
+	{64, 64}               \
+}
+
+#define NET_DIM_TX_EQE_PROFILES { \
+	{1,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+	{8,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+	{32,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+	{64,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+	{128, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}   \
+}
+
+#define NET_DIM_TX_CQE_PROFILES { \
+	{5,  128},  \
+	{8,  64},  \
+	{16, 32},  \
+	{32, 32},  \
+	{64, 32}   \
+}
+
+static const struct dim_cq_moder
+rx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
+	NET_DIM_RX_EQE_PROFILES,
+	NET_DIM_RX_CQE_PROFILES,
+};
+
+static const struct dim_cq_moder
+tx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
+	NET_DIM_TX_EQE_PROFILES,
+	NET_DIM_TX_CQE_PROFILES,
+};
+
+struct dim_cq_moder
+net_dim_get_rx_moderation(u8 cq_period_mode, int ix)
+{
+	struct dim_cq_moder cq_moder = rx_profile[cq_period_mode][ix];
+
+	cq_moder.cq_period_mode = cq_period_mode;
+	return cq_moder;
+}
+EXPORT_SYMBOL(net_dim_get_rx_moderation);
+
+struct dim_cq_moder
+net_dim_get_def_rx_moderation(u8 cq_period_mode)
+{
+	u8 profile_ix = cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
+			NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
+
+	return net_dim_get_rx_moderation(cq_period_mode, profile_ix);
+}
+EXPORT_SYMBOL(net_dim_get_def_rx_moderation);
+
+struct dim_cq_moder
+net_dim_get_tx_moderation(u8 cq_period_mode, int ix)
+{
+	struct dim_cq_moder cq_moder = tx_profile[cq_period_mode][ix];
+
+	cq_moder.cq_period_mode = cq_period_mode;
+	return cq_moder;
+}
+EXPORT_SYMBOL(net_dim_get_tx_moderation);
+
+struct dim_cq_moder
+net_dim_get_def_tx_moderation(u8 cq_period_mode)
+{
+	u8 profile_ix = cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
+			NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
+
+	return net_dim_get_tx_moderation(cq_period_mode, profile_ix);
+}
+EXPORT_SYMBOL(net_dim_get_def_tx_moderation);
+
+static int net_dim_step(struct dim *dim)
+{
+	if (dim->tired == (NET_DIM_PARAMS_NUM_PROFILES * 2))
+		return DIM_TOO_TIRED;
+
+	switch (dim->tune_state) {
+	case DIM_PARKING_ON_TOP:
+	case DIM_PARKING_TIRED:
+		break;
+	case DIM_GOING_RIGHT:
+		if (dim->profile_ix == (NET_DIM_PARAMS_NUM_PROFILES - 1))
+			return DIM_ON_EDGE;
+		dim->profile_ix++;
+		dim->steps_right++;
+		break;
+	case DIM_GOING_LEFT:
+		if (dim->profile_ix == 0)
+			return DIM_ON_EDGE;
+		dim->profile_ix--;
+		dim->steps_left++;
+		break;
+	}
+
+	dim->tired++;
+	return DIM_STEPPED;
+}
+
+static void net_dim_exit_parking(struct dim *dim)
+{
+	dim->tune_state = dim->profile_ix ? DIM_GOING_LEFT : DIM_GOING_RIGHT;
+	net_dim_step(dim);
+}
+
+static int net_dim_stats_compare(struct dim_stats *curr,
+				 struct dim_stats *prev)
+{
+	if (!prev->bpms)
+		return curr->bpms ? DIM_STATS_BETTER : DIM_STATS_SAME;
+
+	if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
+		return (curr->bpms > prev->bpms) ? DIM_STATS_BETTER :
+						   DIM_STATS_WORSE;
+
+	if (!prev->ppms)
+		return curr->ppms ? DIM_STATS_BETTER :
+				    DIM_STATS_SAME;
+
+	if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
+		return (curr->ppms > prev->ppms) ? DIM_STATS_BETTER :
+						   DIM_STATS_WORSE;
+
+	if (!prev->epms)
+		return DIM_STATS_SAME;
+
+	if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
+		return (curr->epms < prev->epms) ? DIM_STATS_BETTER :
+						   DIM_STATS_WORSE;
+
+	return DIM_STATS_SAME;
+}
+
+static bool net_dim_decision(struct dim_stats *curr_stats, struct dim *dim)
+{
+	int prev_state = dim->tune_state;
+	int prev_ix = dim->profile_ix;
+	int stats_res;
+	int step_res;
+
+	switch (dim->tune_state) {
+	case DIM_PARKING_ON_TOP:
+		stats_res = net_dim_stats_compare(curr_stats,
+						  &dim->prev_stats);
+		if (stats_res != DIM_STATS_SAME)
+			net_dim_exit_parking(dim);
+		break;
+
+	case DIM_PARKING_TIRED:
+		dim->tired--;
+		if (!dim->tired)
+			net_dim_exit_parking(dim);
+		break;
+
+	case DIM_GOING_RIGHT:
+	case DIM_GOING_LEFT:
+		stats_res = net_dim_stats_compare(curr_stats,
+						  &dim->prev_stats);
+		if (stats_res != DIM_STATS_BETTER)
+			dim_turn(dim);
+
+		if (dim_on_top(dim)) {
+			dim_park_on_top(dim);
+			break;
+		}
+
+		step_res = net_dim_step(dim);
+		switch (step_res) {
+		case DIM_ON_EDGE:
+			dim_park_on_top(dim);
+			break;
+		case DIM_TOO_TIRED:
+			dim_park_tired(dim);
+			break;
+		}
+
+		break;
+	}
+
+	if (prev_state != DIM_PARKING_ON_TOP ||
+	    dim->tune_state != DIM_PARKING_ON_TOP)
+		dim->prev_stats = *curr_stats;
+
+	return dim->profile_ix != prev_ix;
+}
+
+void net_dim(struct dim *dim, struct dim_sample end_sample)
+{
+	struct dim_stats curr_stats;
+	u16 nevents;
+
+	switch (dim->state) {
+	case DIM_MEASURE_IN_PROGRESS:
+		nevents = BIT_GAP(BITS_PER_TYPE(u16),
+				  end_sample.event_ctr,
+				  dim->start_sample.event_ctr);
+		if (nevents < DIM_NEVENTS)
+			break;
+		dim_calc_stats(&dim->start_sample, &end_sample, &curr_stats);
+		if (net_dim_decision(&curr_stats, dim)) {
+			dim->state = DIM_APPLY_NEW_PROFILE;
+			schedule_work(&dim->work);
+			break;
+		}
+		/* fall through */
+	case DIM_START_MEASURE:
+		dim_update_sample(end_sample.event_ctr, end_sample.pkt_ctr,
+				  end_sample.byte_ctr, &dim->start_sample);
+		dim->state = DIM_MEASURE_IN_PROGRESS;
+		break;
+	case DIM_APPLY_NEW_PROFILE:
+		break;
+	}
+}
+EXPORT_SYMBOL(net_dim);
--- linux-4.4.0.orig/lib/dim/rdma_dim.c
+++ linux-4.4.0/lib/dim/rdma_dim.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2019, Mellanox Technologies inc.  All rights reserved.
+ */
+
+#include <linux/dim.h>
+
+static int rdma_dim_step(struct dim *dim)
+{
+	if (dim->tune_state == DIM_GOING_RIGHT) {
+		if (dim->profile_ix == (RDMA_DIM_PARAMS_NUM_PROFILES - 1))
+			return DIM_ON_EDGE;
+		dim->profile_ix++;
+		dim->steps_right++;
+	}
+	if (dim->tune_state == DIM_GOING_LEFT) {
+		if (dim->profile_ix == 0)
+			return DIM_ON_EDGE;
+		dim->profile_ix--;
+		dim->steps_left++;
+	}
+
+	return DIM_STEPPED;
+}
+
+static int rdma_dim_stats_compare(struct dim_stats *curr,
+				  struct dim_stats *prev)
+{
+	/* first stat */
+	if (!prev->cpms)
+		return DIM_STATS_SAME;
+
+	if (IS_SIGNIFICANT_DIFF(curr->cpms, prev->cpms))
+		return (curr->cpms > prev->cpms) ? DIM_STATS_BETTER :
+						DIM_STATS_WORSE;
+
+	if (IS_SIGNIFICANT_DIFF(curr->cpe_ratio, prev->cpe_ratio))
+		return (curr->cpe_ratio > prev->cpe_ratio) ? DIM_STATS_BETTER :
+						DIM_STATS_WORSE;
+
+	return DIM_STATS_SAME;
+}
+
+static bool rdma_dim_decision(struct dim_stats *curr_stats, struct dim *dim)
+{
+	int prev_ix = dim->profile_ix;
+	u8 state = dim->tune_state;
+	int stats_res;
+	int step_res;
+
+	if (state != DIM_PARKING_ON_TOP && state != DIM_PARKING_TIRED) {
+		stats_res = rdma_dim_stats_compare(curr_stats,
+						   &dim->prev_stats);
+
+		switch (stats_res) {
+		case DIM_STATS_SAME:
+			if (curr_stats->cpe_ratio <= 50 * prev_ix)
+				dim->profile_ix = 0;
+			break;
+		case DIM_STATS_WORSE:
+			dim_turn(dim);
+			/* fall through */
+		case DIM_STATS_BETTER:
+			step_res = rdma_dim_step(dim);
+			if (step_res == DIM_ON_EDGE)
+				dim_turn(dim);
+			break;
+		}
+	}
+
+	dim->prev_stats = *curr_stats;
+
+	return dim->profile_ix != prev_ix;
+}
+
+void rdma_dim(struct dim *dim, u64 completions)
+{
+	struct dim_sample *curr_sample = &dim->measuring_sample;
+	struct dim_stats curr_stats;
+	u32 nevents;
+
+	dim_update_sample_with_comps(curr_sample->event_ctr + 1, 0, 0,
+				     curr_sample->comp_ctr + completions,
+				     &dim->measuring_sample);
+
+	switch (dim->state) {
+	case DIM_MEASURE_IN_PROGRESS:
+		nevents = curr_sample->event_ctr - dim->start_sample.event_ctr;
+		if (nevents < DIM_NEVENTS)
+			break;
+		dim_calc_stats(&dim->start_sample, curr_sample, &curr_stats);
+		if (rdma_dim_decision(&curr_stats, dim)) {
+			dim->state = DIM_APPLY_NEW_PROFILE;
+			schedule_work(&dim->work);
+			break;
+		}
+		/* fall through */
+	case DIM_START_MEASURE:
+		dim->state = DIM_MEASURE_IN_PROGRESS;
+		dim_update_sample_with_comps(curr_sample->event_ctr, 0, 0,
+					     curr_sample->comp_ctr,
+					     &dim->start_sample);
+		break;
+	case DIM_APPLY_NEW_PROFILE:
+		break;
+	}
+}
+EXPORT_SYMBOL(rdma_dim);
--- linux-4.4.0.orig/lib/div64.c
+++ linux-4.4.0/lib/div64.c
@@ -100,7 +100,7 @@
 		quot = div_u64_rem(dividend, divisor, &rem32);
 		*remainder = rem32;
 	} else {
-		int n = 1 + fls(high);
+		int n = fls(high);
 		quot = div_u64(dividend >> n, divisor >> n);
 
 		if (quot != 0)
@@ -138,7 +138,7 @@
 	if (high == 0) {
 		quot = div_u64(dividend, divisor);
 	} else {
-		int n = 1 + fls(high);
+		int n = fls(high);
 		quot = div_u64(dividend >> n, divisor >> n);
 
 		if (quot != 0)
--- linux-4.4.0.orig/lib/dma-debug.c
+++ linux-4.4.0/lib/dma-debug.c
@@ -427,6 +427,7 @@
 		}
 
 		spin_unlock_irqrestore(&bucket->lock, flags);
+		cond_resched();
 	}
 }
 EXPORT_SYMBOL(debug_dma_dump_mappings);
@@ -657,9 +658,9 @@
 	spin_lock_irqsave(&free_entries_lock, flags);
 
 	if (list_empty(&free_entries)) {
-		pr_err("DMA-API: debugging out of memory - disabling\n");
 		global_disable = true;
 		spin_unlock_irqrestore(&free_entries_lock, flags);
+		pr_err("DMA-API: debugging out of memory - disabling\n");
 		return NULL;
 	}
 
@@ -1181,7 +1182,7 @@
 
 static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len)
 {
-	if (overlap(addr, len, _text, _etext) ||
+	if (overlap(addr, len, _stext, _etext) ||
 	    overlap(addr, len, __start_rodata, __end_rodata))
 		err_printk(dev, NULL, "DMA-API: device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len);
 }
--- linux-4.4.0.orig/lib/dump_stack.c
+++ linux-4.4.0/lib/dump_stack.c
@@ -25,6 +25,7 @@
 
 asmlinkage __visible void dump_stack(void)
 {
+	unsigned long flags;
 	int was_locked;
 	int old;
 	int cpu;
@@ -33,9 +34,8 @@
 	 * Permit this cpu to perform nested stack dumps while serialising
 	 * against other CPUs
 	 */
-	preempt_disable();
-
 retry:
+	local_irq_save(flags);
 	cpu = smp_processor_id();
 	old = atomic_cmpxchg(&dump_lock, -1, cpu);
 	if (old == -1) {
@@ -43,7 +43,13 @@
 	} else if (old == cpu) {
 		was_locked = 1;
 	} else {
-		cpu_relax();
+		local_irq_restore(flags);
+		/*
+		 * Wait for the lock to release before jumping to
+		 * atomic_cmpxchg() in order to mitigate the thundering herd
+		 * problem.
+		 */
+		do { cpu_relax(); } while (atomic_read(&dump_lock) != -1);
 		goto retry;
 	}
 
@@ -52,7 +58,7 @@
 	if (!was_locked)
 		atomic_set(&dump_lock, -1);
 
-	preempt_enable();
+	local_irq_restore(flags);
 }
 #else
 asmlinkage __visible void dump_stack(void)
--- linux-4.4.0.orig/lib/dynamic_debug.c
+++ linux-4.4.0/lib/dynamic_debug.c
@@ -85,22 +85,22 @@
 	{ _DPRINTK_FLAGS_NONE, '_' },
 };
 
+struct flagsbuf { char buf[ARRAY_SIZE(opt_array)+1]; };
+
 /* format a string into buf[] which describes the _ddebug's flags */
-static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
-				    size_t maxlen)
+static char *ddebug_describe_flags(unsigned int flags, struct flagsbuf *fb)
 {
-	char *p = buf;
+	char *p = fb->buf;
 	int i;
 
-	BUG_ON(maxlen < 6);
 	for (i = 0; i < ARRAY_SIZE(opt_array); ++i)
-		if (dp->flags & opt_array[i].flag)
+		if (flags & opt_array[i].flag)
 			*p++ = opt_array[i].opt_char;
-	if (p == buf)
+	if (p == fb->buf)
 		*p++ = '_';
 	*p = '\0';
 
-	return buf;
+	return fb->buf;
 }
 
 #define vpr_info(fmt, ...)					\
@@ -142,7 +142,7 @@
 	struct ddebug_table *dt;
 	unsigned int newflags;
 	unsigned int nfound = 0;
-	char flagbuf[10];
+	struct flagsbuf fbuf;
 
 	/* search for matching ddebugs */
 	mutex_lock(&ddebug_lock);
@@ -192,8 +192,7 @@
 			vpr_info("changed %s:%d [%s]%s =%s\n",
 				 trim_prefix(dp->filename), dp->lineno,
 				 dt->mod_name, dp->function,
-				 ddebug_describe_flags(dp, flagbuf,
-						       sizeof(flagbuf)));
+				 ddebug_describe_flags(dp->flags, &fbuf));
 		}
 	}
 	mutex_unlock(&ddebug_lock);
@@ -353,6 +352,10 @@
 				if (parse_lineno(last, &query->last_lineno) < 0)
 					return -EINVAL;
 
+				/* special case for last lineno not specified */
+				if (query->last_lineno == 0)
+					query->last_lineno = UINT_MAX;
+
 				if (query->last_lineno < query->first_lineno) {
 					pr_err("last-line:%d < 1st-line:%d\n",
 						query->last_lineno,
@@ -773,7 +776,7 @@
 {
 	struct ddebug_iter *iter = m->private;
 	struct _ddebug *dp = p;
-	char flagsbuf[10];
+	struct flagsbuf flags;
 
 	vpr_info("called m=%p p=%p\n", m, p);
 
@@ -786,7 +789,7 @@
 	seq_printf(m, "%s:%u [%s]%s =%s \"",
 		   trim_prefix(dp->filename), dp->lineno,
 		   iter->table->mod_name, dp->function,
-		   ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));
+		   ddebug_describe_flags(dp->flags, &flags));
 	seq_escape(m, dp->format, "\t\r\n\"");
 	seq_puts(m, "\"\n");
 
--- linux-4.4.0.orig/lib/fonts/Kconfig
+++ linux-4.4.0/lib/fonts/Kconfig
@@ -87,6 +87,14 @@
 	  embedded devices with a 320x240 screen, to get a reasonable number
 	  of characters (53x24) that are still at a readable size.
 
+config FONT_10x18
+	bool "console 10x18 font (not supported by all drivers)" if FONTS
+	depends on FRAMEBUFFER_CONSOLE
+	help
+	  This is a high resolution console font for machines with very
+	  big letters. It fits between the sun 12x22 and the normal 8x16 font.
+	  If other fonts are too big or too small for you, say Y, otherwise say N.
+
 config FONT_SUN8x16
 	bool "Sparc console 8x16 font"
 	depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)
@@ -101,13 +109,14 @@
 	  big letters (like the letters used in the SPARC PROM). If the
 	  standard font is unreadable for you, say Y, otherwise say N.
 
-config FONT_10x18
-	bool "console 10x18 font (not supported by all drivers)" if FONTS
-	depends on FRAMEBUFFER_CONSOLE
+config FONT_TER16x32
+	bool "Terminus 16x32 font (not supported by all drivers)"
+	depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)
 	help
-	  This is a high resolution console font for machines with very
-	  big letters. It fits between the sun 12x22 and the normal 8x16 font.
-	  If other fonts are too big or too small for you, say Y, otherwise say N.
+	  Terminus Font is a clean, fixed width bitmap font, designed
+	  for long (8 and more hours per day) work with computers.
+	  This is the high resolution, large version for use with HiDPI screens.
+	  If the standard font is unreadable for you, say Y, otherwise say N.
 
 config FONT_AUTOSELECT
 	def_bool y
@@ -121,6 +130,7 @@
 	depends on !FONT_SUN8x16
 	depends on !FONT_SUN12x22
 	depends on !FONT_10x18
+	depends on !FONT_TER16x32
 	select FONT_8x16
 
 endif # FONT_SUPPORT
--- linux-4.4.0.orig/lib/fonts/Makefile
+++ linux-4.4.0/lib/fonts/Makefile
@@ -13,6 +13,7 @@
 font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
 font-objs-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
 font-objs-$(CONFIG_FONT_6x10)      += font_6x10.o
+font-objs-$(CONFIG_FONT_TER16x32)  += font_ter16x32.o
 
 font-objs += $(font-objs-y)
 
--- linux-4.4.0.orig/lib/fonts/font_10x18.c
+++ linux-4.4.0/lib/fonts/font_10x18.c
@@ -7,8 +7,8 @@
 
 #define FONTDATAMAX 9216
 
-static const unsigned char fontdata_10x18[FONTDATAMAX] = {
-
+static const struct font_data fontdata_10x18 = {
+	{ 0, 0, FONTDATAMAX, 0 }, {
 	/* 0 0x00 '^@' */
 	0x00, 0x00, /* 0000000000 */
 	0x00, 0x00, /* 0000000000 */
@@ -5128,8 +5128,7 @@
 	0x00, 0x00, /* 0000000000 */
 	0x00, 0x00, /* 0000000000 */
 	0x00, 0x00, /* 0000000000 */
-
-};
+} };
 
 
 const struct font_desc font_10x18 = {
@@ -5137,7 +5136,7 @@
 	.name	= "10x18",
 	.width	= 10,
 	.height	= 18,
-	.data	= fontdata_10x18,
+	.data	= fontdata_10x18.data,
 #ifdef __sparc__
 	.pref	= 5,
 #else
--- linux-4.4.0.orig/lib/fonts/font_6x10.c
+++ linux-4.4.0/lib/fonts/font_6x10.c
@@ -1,7 +1,9 @@
 #include <linux/font.h>
 
-static const unsigned char fontdata_6x10[] = {
+#define FONTDATAMAX 2560
 
+static const struct font_data fontdata_6x10 = {
+	{ 0, 0, FONTDATAMAX, 0 }, {
 	/* 0 0x00 '^@' */
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
@@ -3073,14 +3075,13 @@
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
-
-};
+} };
 
 const struct font_desc font_6x10 = {
 	.idx	= FONT6x10_IDX,
 	.name	= "6x10",
 	.width	= 6,
 	.height	= 10,
-	.data	= fontdata_6x10,
+	.data	= fontdata_6x10.data,
 	.pref	= 0,
 };
--- linux-4.4.0.orig/lib/fonts/font_6x11.c
+++ linux-4.4.0/lib/fonts/font_6x11.c
@@ -8,8 +8,8 @@
 
 #define FONTDATAMAX (11*256)
 
-static const unsigned char fontdata_6x11[FONTDATAMAX] = {
-
+static const struct font_data fontdata_6x11 = {
+	{ 0, 0, FONTDATAMAX, 0 }, {
 	/* 0 0x00 '^@' */
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
@@ -3337,8 +3337,7 @@
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
-
-};
+} };
 
 
 const struct font_desc font_vga_6x11 = {
@@ -3346,7 +3345,7 @@
 	.name	= "ProFont6x11",
 	.width	= 6,
 	.height	= 11,
-	.data	= fontdata_6x11,
+	.data	= fontdata_6x11.data,
 	/* Try avoiding this font if possible unless on MAC */
 	.pref	= -2000,
 };
--- linux-4.4.0.orig/lib/fonts/font_7x14.c
+++ linux-4.4.0/lib/fonts/font_7x14.c
@@ -7,8 +7,8 @@
 
 #define FONTDATAMAX 3584
 
-static const unsigned char fontdata_7x14[FONTDATAMAX] = {
-
+static const struct font_data fontdata_7x14 = {
+	{ 0, 0, FONTDATAMAX, 0 }, {
 	/* 0 0x00 '^@' */
 	0x00, /* 0000000 */
 	0x00, /* 0000000 */
@@ -4104,8 +4104,7 @@
 	0x00, /* 0000000 */
 	0x00, /* 0000000 */
 	0x00, /* 0000000 */
-
-};
+} };
 
 
 const struct font_desc font_7x14 = {
@@ -4113,6 +4112,6 @@
 	.name	= "7x14",
 	.width	= 7,
 	.height	= 14,
-	.data	= fontdata_7x14,
+	.data	= fontdata_7x14.data,
 	.pref	= 0,
 };
--- linux-4.4.0.orig/lib/fonts/font_8x16.c
+++ linux-4.4.0/lib/fonts/font_8x16.c
@@ -9,8 +9,8 @@
 
 #define FONTDATAMAX 4096
 
-static const unsigned char fontdata_8x16[FONTDATAMAX] = {
-
+static const struct font_data fontdata_8x16 = {
+	{ 0, 0, FONTDATAMAX, 0 }, {
 	/* 0 0x00 '^@' */
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
@@ -4618,8 +4618,7 @@
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
-
-};
+} };
 
 
 const struct font_desc font_vga_8x16 = {
@@ -4627,7 +4626,7 @@
 	.name	= "VGA8x16",
 	.width	= 8,
 	.height	= 16,
-	.data	= fontdata_8x16,
+	.data	= fontdata_8x16.data,
 	.pref	= 0,
 };
 EXPORT_SYMBOL(font_vga_8x16);
--- linux-4.4.0.orig/lib/fonts/font_8x8.c
+++ linux-4.4.0/lib/fonts/font_8x8.c
@@ -8,8 +8,8 @@
 
 #define FONTDATAMAX 2048
 
-static const unsigned char fontdata_8x8[FONTDATAMAX] = {
-
+static const struct font_data fontdata_8x8 = {
+	{ 0, 0, FONTDATAMAX, 0 }, {
 	/* 0 0x00 '^@' */
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
@@ -2569,8 +2569,7 @@
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
 	0x00, /* 00000000 */
-
-};
+} };
 
 
 const struct font_desc font_vga_8x8 = {
@@ -2578,6 +2577,6 @@
 	.name	= "VGA8x8",
 	.width	= 8,
 	.height	= 8,
-	.data	= fontdata_8x8,
+	.data	= fontdata_8x8.data,
 	.pref	= 0,
 };
--- linux-4.4.0.orig/lib/fonts/font_acorn_8x8.c
+++ linux-4.4.0/lib/fonts/font_acorn_8x8.c
@@ -2,7 +2,10 @@
 
 #include <linux/font.h>
 
-static const unsigned char acorndata_8x8[] = {
+#define FONTDATAMAX 2048
+
+static const struct font_data acorndata_8x8 = {
+{ 0, 0, FONTDATAMAX, 0 }, {
 /* 00 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */
 /* 01 */  0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */
 /* 02 */  0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */
@@ -259,14 +262,14 @@
 /* FD */  0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00,
 /* FE */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
 /* FF */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
+} };
 
 const struct font_desc font_acorn_8x8 = {
 	.idx	= ACORN8x8_IDX,
 	.name	= "Acorn8x8",
 	.width	= 8,
 	.height	= 8,
-	.data	= acorndata_8x8,
+	.data	= acorndata_8x8.data,
 #ifdef CONFIG_ARCH_ACORN
 	.pref	= 20,
 #else
--- linux-4.4.0.orig/lib/fonts/font_mini_4x6.c
+++ linux-4.4.0/lib/fonts/font_mini_4x6.c
@@ -43,8 +43,8 @@
 
 #define FONTDATAMAX 1536
 
-static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
-
+static const struct font_data fontdata_mini_4x6 = {
+	{ 0, 0, FONTDATAMAX, 0 }, {
 	/*{*/
 	  	/*   Char 0: ' '  */
 	0xee,	/*=  [*** ]       */
@@ -2145,14 +2145,14 @@
 	0xee,	/*=   [*** ]        */
 	0x00,	/*=   [    ]        */
 	/*}*/
-};
+} };
 
 const struct font_desc font_mini_4x6 = {
 	.idx	= MINI4x6_IDX,
 	.name	= "MINI4x6",
 	.width	= 4,
 	.height	= 6,
-	.data	= fontdata_mini_4x6,
+	.data	= fontdata_mini_4x6.data,
 	.pref	= 3,
 };
 
--- linux-4.4.0.orig/lib/fonts/font_pearl_8x8.c
+++ linux-4.4.0/lib/fonts/font_pearl_8x8.c
@@ -13,8 +13,8 @@
 
 #define FONTDATAMAX 2048
 
-static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
-
+static const struct font_data fontdata_pearl8x8 = {
+   { 0, 0, FONTDATAMAX, 0 }, {
    /* 0 0x00 '^@' */
    0x00, /* 00000000 */
    0x00, /* 00000000 */
@@ -2574,14 +2574,13 @@
    0x00, /* 00000000 */
    0x00, /* 00000000 */
    0x00, /* 00000000 */
-
-};
+} };
 
 const struct font_desc font_pearl_8x8 = {
 	.idx	= PEARL8x8_IDX,
 	.name	= "PEARL8x8",
 	.width	= 8,
 	.height	= 8,
-	.data	= fontdata_pearl8x8,
+	.data	= fontdata_pearl8x8.data,
 	.pref	= 2,
 };
--- linux-4.4.0.orig/lib/fonts/font_sun12x22.c
+++ linux-4.4.0/lib/fonts/font_sun12x22.c
@@ -2,8 +2,8 @@
 
 #define FONTDATAMAX 11264
 
-static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
-
+static const struct font_data fontdata_sun12x22 = {
+	{ 0, 0, FONTDATAMAX, 0 }, {
 	/* 0 0x00 '^@' */
 	0x00, 0x00, /* 000000000000 */
 	0x00, 0x00, /* 000000000000 */
@@ -6147,8 +6147,7 @@
 	0x00, 0x00, /* 000000000000 */
 	0x00, 0x00, /* 000000000000 */
 	0x00, 0x00, /* 000000000000 */
-
-};
+} };
 
 
 const struct font_desc font_sun_12x22 = {
@@ -6156,7 +6155,7 @@
 	.name	= "SUN12x22",
 	.width	= 12,
 	.height	= 22,
-	.data	= fontdata_sun12x22,
+	.data	= fontdata_sun12x22.data,
 #ifdef __sparc__
 	.pref	= 5,
 #else
--- linux-4.4.0.orig/lib/fonts/font_sun8x16.c
+++ linux-4.4.0/lib/fonts/font_sun8x16.c
@@ -2,7 +2,8 @@
 
 #define FONTDATAMAX 4096
 
-static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
+static const struct font_data fontdata_sun8x16 = {
+{ 0, 0, FONTDATAMAX, 0 }, {
 /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
@@ -259,14 +260,14 @@
 /* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-};
+} };
 
 const struct font_desc font_sun_8x16 = {
 	.idx	= SUN8x16_IDX,
 	.name	= "SUN8x16",
 	.width	= 8,
 	.height	= 16,
-	.data	= fontdata_sun8x16,
+	.data	= fontdata_sun8x16.data,
 #ifdef __sparc__
 	.pref	= 10,
 #else
--- linux-4.4.0.orig/lib/fonts/font_ter16x32.c
+++ linux-4.4.0/lib/fonts/font_ter16x32.c
@@ -0,0 +1,2072 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/font.h>
+#include <linux/module.h>
+
+#define FONTDATAMAX 16384
+
+static const unsigned char fontdata_ter16x32[FONTDATAMAX] = {
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x7f, 0xfc,
+	0xf0, 0x1e, 0xe0, 0x0e, 0xe0, 0x0e, 0xe0, 0x0e,
+	0xee, 0xee, 0xee, 0xee, 0xe0, 0x0e, 0xe0, 0x0e,
+	0xe0, 0x0e, 0xe0, 0x0e, 0xef, 0xee, 0xe7, 0xce,
+	0xe0, 0x0e, 0xe0, 0x0e, 0xe0, 0x0e, 0xf0, 0x1e,
+	0x7f, 0xfc, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 1 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x7f, 0xfc,
+	0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe,
+	0xe3, 0x8e, 0xe3, 0x8e, 0xff, 0xfe, 0xff, 0xfe,
+	0xff, 0xfe, 0xff, 0xfe, 0xe0, 0x0e, 0xf0, 0x1e,
+	0xf8, 0x3e, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe,
+	0x7f, 0xfc, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 2 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x78, 0x3c, 0xfc, 0x7e, 0xfe, 0xfe, 0xff, 0xfe,
+	0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0,
+	0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 3 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x03, 0x80, 0x07, 0xc0, 0x0f, 0xe0,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x7f, 0xfc, 0xff, 0xfe,
+	0xff, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0,
+	0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 4 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x0f, 0xe0,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0,
+	0x07, 0xc0, 0x03, 0x80, 0x3b, 0xb8, 0x7f, 0xfc,
+	0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe,
+	0x7f, 0xfc, 0x3b, 0xb8, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 5 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x07, 0xc0, 0x0f, 0xe0, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x7f, 0xfc, 0x7f, 0xfc, 0xff, 0xfe, 0xff, 0xfe,
+	0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7b, 0xbc,
+	0x3b, 0xb8, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 6 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0,
+	0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 7 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xf0, 0x0f,
+	0xf0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 8 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0xc0, 0x07, 0xe0, 0x0e, 0x70, 0x0c, 0x30,
+	0x0c, 0x30, 0x0e, 0x70, 0x07, 0xe0, 0x03, 0xc0,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 9 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xfc, 0x3f, 0xf8, 0x1f, 0xf1, 0x8f, 0xf3, 0xcf,
+	0xf3, 0xcf, 0xf1, 0x8f, 0xf8, 0x1f, 0xfc, 0x3f,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 10 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x03, 0xfe,
+	0x00, 0x1e, 0x00, 0x3e, 0x00, 0x76, 0x00, 0xe6,
+	0x01, 0xc6, 0x03, 0x86, 0x3f, 0xe0, 0x7f, 0xf0,
+	0xf0, 0x78, 0xe0, 0x38, 0xe0, 0x38, 0xe0, 0x38,
+	0xe0, 0x38, 0xe0, 0x38, 0xe0, 0x38, 0xf0, 0x78,
+	0x7f, 0xf0, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 11 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c, 0x3f, 0xf8,
+	0x1f, 0xf0, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 12 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc,
+	0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c,
+	0x3f, 0xfc, 0x3f, 0xfc, 0x38, 0x00, 0x38, 0x00,
+	0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
+	0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
+	0xf8, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 13 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfe,
+	0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e,
+	0x7f, 0xfe, 0x7f, 0xfe, 0x70, 0x0e, 0x70, 0x0e,
+	0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e,
+	0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x3e,
+	0xf0, 0x3c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 14 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x73, 0x9c, 0x73, 0x9c,
+	0x3b, 0xb8, 0x1f, 0xf0, 0x0f, 0xe0, 0x7c, 0x7c,
+	0x7c, 0x7c, 0x0f, 0xe0, 0x1f, 0xf0, 0x3b, 0xb8,
+	0x73, 0x9c, 0x73, 0x9c, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 15 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xc0, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xff, 0x00,
+	0xff, 0xc0, 0xff, 0xf0, 0xff, 0xfc, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xc0,
+	0xff, 0x00, 0xfc, 0x00, 0xf0, 0x00, 0xc0, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 16 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x00, 0x0f, 0x00, 0x3f, 0x00, 0xff,
+	0x03, 0xff, 0x0f, 0xff, 0x3f, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x3f, 0xff, 0x0f, 0xff, 0x03, 0xff,
+	0x00, 0xff, 0x00, 0x3f, 0x00, 0x0f, 0x00, 0x03,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0f, 0xe0, 0x1f, 0xf0, 0x3b, 0xb8, 0x73, 0x9c,
+	0x63, 0x8c, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x63, 0x8c,
+	0x73, 0x9c, 0x3b, 0xb8, 0x1f, 0xf0, 0x0f, 0xe0,
+	0x07, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 18 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 19 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xfe, 0x3f, 0xfe,
+	0x79, 0xce, 0x71, 0xce, 0x71, 0xce, 0x71, 0xce,
+	0x71, 0xce, 0x71, 0xce, 0x79, 0xce, 0x3f, 0xce,
+	0x1f, 0xce, 0x01, 0xce, 0x01, 0xce, 0x01, 0xce,
+	0x01, 0xce, 0x01, 0xce, 0x01, 0xce, 0x01, 0xce,
+	0x01, 0xce, 0x01, 0xce, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 20 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x07, 0xe0, 0x0f, 0xf0, 0x1e, 0x78, 0x1c, 0x38,
+	0x1c, 0x00, 0x1e, 0x00, 0x0f, 0xc0, 0x0f, 0xe0,
+	0x1c, 0xf0, 0x1c, 0x78, 0x1c, 0x38, 0x1c, 0x38,
+	0x1c, 0x38, 0x1e, 0x38, 0x0f, 0x38, 0x07, 0xf0,
+	0x03, 0xf0, 0x00, 0x78, 0x00, 0x38, 0x1c, 0x38,
+	0x1e, 0x78, 0x0f, 0xf0, 0x07, 0xe0, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 21 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfe,
+	0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe,
+	0x7f, 0xfe, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 22 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0f, 0xe0, 0x1f, 0xf0, 0x3b, 0xb8, 0x73, 0x9c,
+	0x63, 0x8c, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x63, 0x8c, 0x73, 0x9c, 0x3b, 0xb8,
+	0x1f, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 23 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0f, 0xe0, 0x1f, 0xf0, 0x3b, 0xb8, 0x73, 0x9c,
+	0x63, 0x8c, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 24 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x63, 0x8c,
+	0x73, 0x9c, 0x3b, 0xb8, 0x1f, 0xf0, 0x0f, 0xe0,
+	0x07, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 25 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xc0, 0x00, 0xe0, 0x00, 0x70,
+	0x00, 0x38, 0x00, 0x1c, 0x7f, 0xfe, 0x7f, 0xfe,
+	0x7f, 0xfe, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70,
+	0x00, 0xe0, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 26 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00,
+	0x1c, 0x00, 0x38, 0x00, 0x7f, 0xfe, 0x7f, 0xfe,
+	0x7f, 0xfe, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 28 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x06, 0x60, 0x0e, 0x70, 0x1c, 0x38,
+	0x38, 0x1c, 0x70, 0x0e, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x70, 0x0e, 0x38, 0x1c, 0x1c, 0x38,
+	0x0e, 0x70, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 29 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x80, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0,
+	0x07, 0xe0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0,
+	0x1f, 0xf8, 0x1f, 0xf8, 0x3f, 0xfc, 0x3f, 0xfc,
+	0x7f, 0xfe, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 30 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfe,
+	0x3f, 0xfc, 0x3f, 0xfc, 0x1f, 0xf8, 0x1f, 0xf8,
+	0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x07, 0xe0,
+	0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x01, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 31 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 32 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 33 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 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, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 34 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 35 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x1f, 0xf0,
+	0x3f, 0xf8, 0x7b, 0xbc, 0x73, 0x9c, 0x73, 0x80,
+	0x73, 0x80, 0x73, 0x80, 0x7b, 0x80, 0x3f, 0xf0,
+	0x1f, 0xf8, 0x03, 0xbc, 0x03, 0x9c, 0x03, 0x9c,
+	0x03, 0x9c, 0x73, 0x9c, 0x7b, 0xbc, 0x3f, 0xf8,
+	0x1f, 0xf0, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 36 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0x1c, 0x3f, 0x9c,
+	0x3b, 0xb8, 0x3b, 0xb8, 0x3f, 0xf0, 0x1f, 0x70,
+	0x00, 0xe0, 0x00, 0xe0, 0x01, 0xc0, 0x01, 0xc0,
+	0x03, 0x80, 0x03, 0x80, 0x07, 0x00, 0x07, 0x00,
+	0x0e, 0xf8, 0x0f, 0xfc, 0x1d, 0xdc, 0x1d, 0xdc,
+	0x39, 0xfc, 0x38, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xe0,
+	0x38, 0x70, 0x38, 0x70, 0x38, 0x70, 0x38, 0x70,
+	0x38, 0x70, 0x1c, 0xe0, 0x0f, 0xc0, 0x0f, 0x80,
+	0x1f, 0xce, 0x38, 0xee, 0x70, 0x7c, 0x70, 0x38,
+	0x70, 0x38, 0x70, 0x38, 0x70, 0x38, 0x78, 0x7c,
+	0x3f, 0xee, 0x1f, 0xce, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 38 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 39 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xc0,
+	0x03, 0x80, 0x07, 0x00, 0x07, 0x00, 0x0e, 0x00,
+	0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
+	0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
+	0x0e, 0x00, 0x07, 0x00, 0x07, 0x00, 0x03, 0x80,
+	0x01, 0xc0, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 40 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x07, 0x00,
+	0x03, 0x80, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0xe0,
+	0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0,
+	0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0,
+	0x00, 0xe0, 0x01, 0xc0, 0x01, 0xc0, 0x03, 0x80,
+	0x07, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 41 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x1c, 0x70,
+	0x0e, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x03, 0x80, 0x07, 0xc0, 0x0e, 0xe0,
+	0x1c, 0x70, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 42 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 43 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 44 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 45 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 46 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x70,
+	0x00, 0xe0, 0x00, 0xe0, 0x01, 0xc0, 0x01, 0xc0,
+	0x03, 0x80, 0x03, 0x80, 0x07, 0x00, 0x07, 0x00,
+	0x0e, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x1c, 0x00,
+	0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x3c,
+	0x70, 0x7c, 0x70, 0xfc, 0x71, 0xdc, 0x73, 0x9c,
+	0x77, 0x1c, 0x7e, 0x1c, 0x7c, 0x1c, 0x78, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 48 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0x80,
+	0x0f, 0x80, 0x1f, 0x80, 0x1f, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x1f, 0xf0, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 49 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70,
+	0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00,
+	0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 50 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x00, 0x1c, 0x00, 0x3c, 0x0f, 0xf8,
+	0x0f, 0xf8, 0x00, 0x3c, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 51 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x3c,
+	0x00, 0x7c, 0x00, 0xfc, 0x01, 0xdc, 0x03, 0x9c,
+	0x07, 0x1c, 0x0e, 0x1c, 0x1c, 0x1c, 0x38, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 52 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x7f, 0xf0, 0x7f, 0xf8,
+	0x00, 0x3c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x00, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 53 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x3f, 0xf8,
+	0x78, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x7f, 0xf0, 0x7f, 0xf8,
+	0x70, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 54 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x38,
+	0x00, 0x38, 0x00, 0x70, 0x00, 0x70, 0x00, 0xe0,
+	0x00, 0xe0, 0x01, 0xc0, 0x01, 0xc0, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 55 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c, 0x3f, 0xf8,
+	0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 56 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x3c,
+	0x3f, 0xf8, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 58 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 59 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x38,
+	0x00, 0x70, 0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80,
+	0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00,
+	0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00,
+	0x03, 0x80, 0x01, 0xc0, 0x00, 0xe0, 0x00, 0x70,
+	0x00, 0x38, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 60 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 61 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x1c, 0x00,
+	0x0e, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xc0,
+	0x00, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c,
+	0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x00, 0xe0,
+	0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00,
+	0x1c, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 62 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x00, 0xe0,
+	0x01, 0xc0, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 63 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x3f, 0xfc,
+	0x78, 0x0e, 0x70, 0x06, 0x71, 0xfe, 0x73, 0xfe,
+	0x77, 0x8e, 0x77, 0x0e, 0x77, 0x0e, 0x77, 0x0e,
+	0x77, 0x0e, 0x77, 0x0e, 0x77, 0x0e, 0x77, 0x9e,
+	0x73, 0xfe, 0x71, 0xf6, 0x70, 0x00, 0x78, 0x00,
+	0x3f, 0xfe, 0x1f, 0xfe, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 64 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 65 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x7f, 0xf8,
+	0x70, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x38, 0x7f, 0xf0, 0x7f, 0xf0,
+	0x70, 0x38, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x3c,
+	0x7f, 0xf8, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 66 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x7f, 0xf0,
+	0x70, 0x78, 0x70, 0x38, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x38, 0x70, 0x78,
+	0x7f, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 68 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x7f, 0xe0,
+	0x7f, 0xe0, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 69 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x7f, 0xe0,
+	0x7f, 0xe0, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 70 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x71, 0xfc,
+	0x71, 0xfc, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 71 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 72 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x0f, 0xe0,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 73 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0xfe,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+	0x70, 0x38, 0x70, 0x38, 0x70, 0x38, 0x78, 0x78,
+	0x3f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 74 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x0c, 0x70, 0x1c,
+	0x70, 0x38, 0x70, 0x70, 0x70, 0xe0, 0x71, 0xc0,
+	0x73, 0x80, 0x77, 0x00, 0x7e, 0x00, 0x7c, 0x00,
+	0x7c, 0x00, 0x7e, 0x00, 0x77, 0x00, 0x73, 0x80,
+	0x71, 0xc0, 0x70, 0xe0, 0x70, 0x70, 0x70, 0x38,
+	0x70, 0x1c, 0x70, 0x0c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 75 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 76 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x70, 0x0e,
+	0x78, 0x1e, 0x7c, 0x3e, 0x7e, 0x7e, 0x7e, 0x7e,
+	0x77, 0xee, 0x73, 0xce, 0x73, 0xce, 0x71, 0x8e,
+	0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e,
+	0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e,
+	0x70, 0x0e, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x7c, 0x1c, 0x7e, 0x1c, 0x77, 0x1c, 0x73, 0x9c,
+	0x71, 0xdc, 0x70, 0xfc, 0x70, 0x7c, 0x70, 0x3c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 78 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 79 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x7f, 0xf8,
+	0x70, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x3c,
+	0x7f, 0xf8, 0x7f, 0xf0, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 80 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x73, 0x9c, 0x79, 0xfc,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x38, 0x00, 0x1c,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 81 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x7f, 0xf8,
+	0x70, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x3c,
+	0x7f, 0xf8, 0x7f, 0xf0, 0x7e, 0x00, 0x77, 0x00,
+	0x73, 0x80, 0x71, 0xc0, 0x70, 0xe0, 0x70, 0x70,
+	0x70, 0x38, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 82 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x78, 0x00, 0x3f, 0xf0,
+	0x1f, 0xf8, 0x00, 0x3c, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 83 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 84 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 85 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x38, 0x38,
+	0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+	0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x0e, 0xe0, 0x0e, 0xe0, 0x0e, 0xe0, 0x07, 0xc0,
+	0x07, 0xc0, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 86 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x70, 0x0e,
+	0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e,
+	0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e,
+	0x71, 0x8e, 0x73, 0xce, 0x73, 0xce, 0x77, 0xee,
+	0x7e, 0x7e, 0x7e, 0x7e, 0x7c, 0x3e, 0x78, 0x1e,
+	0x70, 0x0e, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x38, 0x38, 0x38, 0x38, 0x1c, 0x70, 0x1c, 0x70,
+	0x0e, 0xe0, 0x0e, 0xe0, 0x07, 0xc0, 0x07, 0xc0,
+	0x07, 0xc0, 0x07, 0xc0, 0x0e, 0xe0, 0x0e, 0xe0,
+	0x1c, 0x70, 0x1c, 0x70, 0x38, 0x38, 0x38, 0x38,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 88 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x38, 0x38, 0x38, 0x38, 0x1c, 0x70,
+	0x1c, 0x70, 0x0e, 0xe0, 0x0e, 0xe0, 0x07, 0xc0,
+	0x07, 0xc0, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 89 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x38,
+	0x00, 0x70, 0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80,
+	0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 90 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x0f, 0xf0,
+	0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
+	0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
+	0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
+	0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
+	0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 91 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00,
+	0x1c, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x07, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x01, 0xc0, 0x01, 0xc0, 0x00, 0xe0, 0x00, 0xe0,
+	0x00, 0x70, 0x00, 0x70, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 92 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x0f, 0xf0,
+	0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
+	0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
+	0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
+	0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
+	0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 93 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x80, 0x07, 0xc0, 0x0e, 0xe0, 0x1c, 0x70,
+	0x38, 0x38, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 94 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 95 */
+	0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00,
+	0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 96 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x3f, 0xf0, 0x3f, 0xf8, 0x00, 0x3c, 0x00, 0x1c,
+	0x00, 0x1c, 0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x7f, 0xf0, 0x7f, 0xf8, 0x70, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x3c,
+	0x7f, 0xf8, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 98 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 99 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c,
+	0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 100 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 101 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe,
+	0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x3f, 0xf8, 0x3f, 0xf8, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 102 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x3c, 0x3f, 0xf8, 0x3f, 0xf0, 0x00, 0x00,	/* 103 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x7f, 0xf0, 0x7f, 0xf8, 0x70, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 104 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x0f, 0x80, 0x0f, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 105 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xf8, 0x00, 0xf8, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x38, 0x00, 0x38, 0x38, 0x38, 0x38, 0x38,
+	0x3c, 0x78, 0x1f, 0xf0, 0x0f, 0xe0, 0x00, 0x00,	/* 106 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00,
+	0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
+	0x38, 0x1c, 0x38, 0x38, 0x38, 0x70, 0x38, 0xe0,
+	0x39, 0xc0, 0x3b, 0x80, 0x3f, 0x00, 0x3f, 0x00,
+	0x3b, 0x80, 0x39, 0xc0, 0x38, 0xe0, 0x38, 0x70,
+	0x38, 0x38, 0x38, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 107 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x0f, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 108 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xf0, 0x7f, 0xf8, 0x73, 0xbc, 0x73, 0x9c,
+	0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c,
+	0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c,
+	0x73, 0x9c, 0x73, 0x9c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 109 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xf0, 0x7f, 0xf8, 0x70, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 110 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 111 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xf0, 0x7f, 0xf8, 0x70, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x3c,
+	0x7f, 0xf8, 0x7f, 0xf0, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00,	/* 112 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00,	/* 113 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x73, 0xfc, 0x77, 0xfc, 0x7e, 0x00, 0x7c, 0x00,
+	0x78, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 114 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x00,
+	0x70, 0x00, 0x78, 0x00, 0x3f, 0xf0, 0x1f, 0xf8,
+	0x00, 0x3c, 0x00, 0x1c, 0x00, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 115 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00,
+	0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00,
+	0x7f, 0xf0, 0x7f, 0xf0, 0x07, 0x00, 0x07, 0x00,
+	0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00,
+	0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x80,
+	0x03, 0xfc, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 116 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 117 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x38, 0x38,
+	0x38, 0x38, 0x38, 0x38, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x0e, 0xe0, 0x0e, 0xe0, 0x07, 0xc0,
+	0x07, 0xc0, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 118 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c,
+	0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c, 0x7b, 0xbc,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 119 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x38, 0x38,
+	0x1c, 0x70, 0x0e, 0xe0, 0x07, 0xc0, 0x07, 0xc0,
+	0x0e, 0xe0, 0x1c, 0x70, 0x38, 0x38, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 120 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x3c, 0x3f, 0xf8, 0x3f, 0xf0, 0x00, 0x00,	/* 121 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x38, 0x00, 0x70,
+	0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00,
+	0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 122 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x03, 0xf0,
+	0x07, 0x80, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00,
+	0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x3e, 0x00,
+	0x3e, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00,
+	0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x80,
+	0x03, 0xf0, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 123 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 124 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3f, 0x00,
+	0x07, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x01, 0xf0,
+	0x01, 0xf0, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x07, 0x80,
+	0x3f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 125 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1e, 0x1c, 0x3f, 0x1c, 0x77, 0x9c, 0x73, 0xdc,
+	0x71, 0xf8, 0x70, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 126 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0f, 0xe0, 0x1e, 0xf0, 0x3c, 0x78, 0x78, 0x3c,
+	0xf0, 0x1e, 0xe0, 0x0e, 0xe0, 0x0e, 0xe0, 0x0e,
+	0xe0, 0x0e, 0xe0, 0x0e, 0xe0, 0x0e, 0xe0, 0x0e,
+	0xff, 0xfe, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 127 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00,	/* 128 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 129 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xe0,
+	0x01, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 130 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0e, 0xe0, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x3f, 0xf0, 0x3f, 0xf8, 0x00, 0x3c, 0x00, 0x1c,
+	0x00, 0x1c, 0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 131 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x3f, 0xf0, 0x3f, 0xf8, 0x00, 0x3c, 0x00, 0x1c,
+	0x00, 0x1c, 0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 132 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x3f, 0xf0, 0x3f, 0xf8, 0x00, 0x3c, 0x00, 0x1c,
+	0x00, 0x1c, 0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 133 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x0e, 0xe0,
+	0x0e, 0xe0, 0x0e, 0xe0, 0x07, 0xc0, 0x00, 0x00,
+	0x3f, 0xf0, 0x3f, 0xf8, 0x00, 0x3c, 0x00, 0x1c,
+	0x00, 0x1c, 0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 134 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00,	/* 135 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0e, 0xe0, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 136 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 137 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 138 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x0f, 0x80, 0x0f, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 139 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0e, 0xe0, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x0f, 0x80, 0x0f, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 140 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x0f, 0x80, 0x0f, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 141 */
+	0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 142 */
+	0x00, 0x00, 0x07, 0xc0, 0x0e, 0xe0, 0x0e, 0xe0,
+	0x0e, 0xe0, 0x07, 0xc0, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 143 */
+	0x00, 0x00, 0x00, 0x70, 0x00, 0xe0, 0x01, 0xc0,
+	0x03, 0x80, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x7f, 0xe0,
+	0x7f, 0xe0, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 144 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xf8, 0x7f, 0xfc, 0x03, 0x9e, 0x03, 0x8e,
+	0x03, 0x8e, 0x3f, 0x8e, 0x7f, 0xfe, 0xf3, 0xfe,
+	0xe3, 0x80, 0xe3, 0x80, 0xe3, 0x80, 0xf3, 0xce,
+	0x7f, 0xfe, 0x3e, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 145 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x7f, 0xfe,
+	0xf1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0,
+	0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xff, 0xfe,
+	0xff, 0xfe, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0,
+	0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0,
+	0xe1, 0xfe, 0xe1, 0xfe, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 146 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0e, 0xe0, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 147 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 148 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 149 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0,
+	0x0e, 0xe0, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 150 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 151 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x3c, 0x3f, 0xf8, 0x3f, 0xf0, 0x00, 0x00,	/* 152 */
+	0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 153 */
+	0x00, 0x00, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 154 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x7b, 0xbc, 0x73, 0x9c,
+	0x73, 0x80, 0x73, 0x80, 0x73, 0x80, 0x73, 0x80,
+	0x73, 0x80, 0x73, 0x80, 0x73, 0x9c, 0x7b, 0xbc,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 155 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x0f, 0xf0,
+	0x1e, 0x78, 0x1c, 0x38, 0x1c, 0x00, 0x1c, 0x00,
+	0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x7f, 0xe0,
+	0x7f, 0xe0, 0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00,
+	0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x1c, 0x1c, 0x1c,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 156 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x38, 0x38, 0x38, 0x38, 0x1c, 0x70, 0x1c, 0x70,
+	0x0e, 0xe0, 0x0e, 0xe0, 0x07, 0xc0, 0x07, 0xc0,
+	0x03, 0x80, 0x03, 0x80, 0x3f, 0xf8, 0x3f, 0xf8,
+	0x03, 0x80, 0x03, 0x80, 0x3f, 0xf8, 0x3f, 0xf8,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 157 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80,
+	0xe3, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0, 0xe1, 0xc0,
+	0xe1, 0xc0, 0xe1, 0xc0, 0xe3, 0xc0, 0xff, 0xf0,
+	0xff, 0x70, 0xe0, 0x70, 0xe3, 0xfe, 0xe3, 0xfe,
+	0xe0, 0x70, 0xe0, 0x70, 0xe0, 0x70, 0xe0, 0x70,
+	0xe0, 0x7e, 0xe0, 0x3e, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 158 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x03, 0xfc,
+	0x03, 0x9c, 0x03, 0x9c, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x1f, 0xf0, 0x1f, 0xf0,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x73, 0x80, 0x73, 0x80,
+	0x7f, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 159 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xe0,
+	0x01, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x3f, 0xf0, 0x3f, 0xf8, 0x00, 0x3c, 0x00, 0x1c,
+	0x00, 0x1c, 0x1f, 0xfc, 0x3f, 0xfc, 0x78, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 160 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xe0,
+	0x01, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x0f, 0x80, 0x0f, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 161 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xe0,
+	0x01, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x78, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 162 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xe0,
+	0x01, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x3f, 0xfc, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 163 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0x38, 0x3b, 0xb8,
+	0x3b, 0xb8, 0x39, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xf0, 0x7f, 0xf8, 0x70, 0x3c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 164 */
+	0x00, 0x00, 0x1f, 0x38, 0x3b, 0xb8, 0x3b, 0xb8,
+	0x39, 0xf0, 0x00, 0x00, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x1c,
+	0x7c, 0x1c, 0x7e, 0x1c, 0x77, 0x1c, 0x73, 0x9c,
+	0x71, 0xdc, 0x70, 0xfc, 0x70, 0x7c, 0x70, 0x3c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 165 */
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x1f, 0xf0,
+	0x00, 0x38, 0x00, 0x38, 0x0f, 0xf8, 0x1f, 0xf8,
+	0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x1f, 0xf8,
+	0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8,
+	0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 166 */
+	0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x1f, 0xf0,
+	0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+	0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x1f, 0xf0,
+	0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8,
+	0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 167 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x07, 0x00,
+	0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 168 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 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,	/* 169 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 170 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x3c, 0x00,
+	0x7c, 0x06, 0x1c, 0x0e, 0x1c, 0x1c, 0x1c, 0x38,
+	0x1c, 0x70, 0x1c, 0xe0, 0x1d, 0xc0, 0x03, 0x80,
+	0x07, 0x00, 0x0e, 0xfc, 0x1d, 0xfe, 0x39, 0xce,
+	0x71, 0xce, 0x60, 0x1c, 0x00, 0x38, 0x00, 0x70,
+	0x00, 0xfe, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 171 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1e, 0x00,
+	0x3e, 0x00, 0x0e, 0x00, 0x0e, 0x06, 0x0e, 0x0e,
+	0x0e, 0x1c, 0x0e, 0x38, 0x0e, 0x70, 0x00, 0xe0,
+	0x01, 0xce, 0x03, 0x9e, 0x07, 0x3e, 0x0e, 0x7e,
+	0x1c, 0xee, 0x39, 0xce, 0x73, 0xfe, 0x63, 0xfe,
+	0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 172 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 173 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0xce, 0x03, 0x9c, 0x07, 0x38, 0x0e, 0x70,
+	0x1c, 0xe0, 0x39, 0xc0, 0x73, 0x80, 0x73, 0x80,
+	0x39, 0xc0, 0x1c, 0xe0, 0x0e, 0x70, 0x07, 0x38,
+	0x03, 0x9c, 0x01, 0xce, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 174 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x73, 0x80, 0x39, 0xc0, 0x1c, 0xe0, 0x0e, 0x70,
+	0x07, 0x38, 0x03, 0x9c, 0x01, 0xce, 0x01, 0xce,
+	0x03, 0x9c, 0x07, 0x38, 0x0e, 0x70, 0x1c, 0xe0,
+	0x39, 0xc0, 0x73, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 175 */
+	0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
+	0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
+	0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
+	0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
+	0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
+	0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
+	0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
+	0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,	/* 176 */
+	0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55,
+	0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55,
+	0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55,
+	0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55,
+	0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55,
+	0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55,
+	0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55,
+	0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55,	/* 177 */
+	0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, 0xaa, 0xaa,
+	0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, 0xaa, 0xaa,
+	0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, 0xaa, 0xaa,
+	0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, 0xaa, 0xaa,
+	0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, 0xaa, 0xaa,
+	0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, 0xaa, 0xaa,
+	0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, 0xaa, 0xaa,
+	0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, 0xaa, 0xaa,	/* 178 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 179 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0xff, 0x80, 0xff, 0x80,
+	0xff, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 180 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 181 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0xfe, 0x70, 0xfe, 0x70,
+	0xfe, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 182 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0xff, 0xf0,
+	0xff, 0xf0, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 183 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 184 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0xfe, 0x70, 0xfe, 0x70, 0xfe, 0x70, 0x00, 0x70,
+	0x00, 0x70, 0xfe, 0x70, 0xfe, 0x70, 0xfe, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 185 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 186 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf0, 0x00, 0x70,
+	0x00, 0x70, 0xfe, 0x70, 0xfe, 0x70, 0xfe, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 187 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0xfe, 0x70, 0xfe, 0x70, 0xfe, 0x70, 0x00, 0x70,
+	0x00, 0x70, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf0,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 188 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0xff, 0xf0, 0xff, 0xf0,
+	0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 189 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 190 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0xff, 0x80,
+	0xff, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 191 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0xff, 0x03, 0xff,
+	0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 192 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 193 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 194 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0xff, 0x03, 0xff,
+	0x03, 0xff, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 195 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 196 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 197 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 198 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x7f, 0x0e, 0x7f,
+	0x0e, 0x7f, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 199 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x00,
+	0x0e, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0xff,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 200 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x0f, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0e, 0x00,
+	0x0e, 0x00, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 201 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0x00, 0x00,
+	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 202 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+	0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 203 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x00,
+	0x0e, 0x00, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 204 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 205 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0x00, 0x00,
+	0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 206 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 207 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 208 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 209 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 210 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0f, 0xff, 0x0f, 0xff,
+	0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 211 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 212 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 213 */
+	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, 0x0f, 0xff, 0x0f, 0xff,
+	0x0f, 0xff, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 214 */
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,
+	0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70, 0x0e, 0x70,	/* 215 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x80,
+	0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 216 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0xff, 0x80, 0xff, 0x80,
+	0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 217 */
+	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, 0x03, 0xff, 0x03, 0xff,
+	0x03, 0xff, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 218 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 219 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 220 */
+	0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+	0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+	0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+	0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+	0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+	0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+	0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+	0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,	/* 221 */
+	0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+	0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+	0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+	0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+	0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+	0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+	0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+	0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,	/* 222 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 223 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xee, 0x3f, 0xfe, 0x78, 0x3c, 0x70, 0x38,
+	0x70, 0x38, 0x70, 0x38, 0x70, 0x38, 0x70, 0x38,
+	0x70, 0x38, 0x70, 0x38, 0x70, 0x38, 0x78, 0x3c,
+	0x3f, 0xfe, 0x1f, 0xee, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 224 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x7f, 0xf0,
+	0x70, 0x78, 0x70, 0x38, 0x70, 0x38, 0x70, 0x38,
+	0x70, 0x38, 0x70, 0x70, 0x7f, 0xf0, 0x7f, 0xf0,
+	0x70, 0x38, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x3c,
+	0x7f, 0xf8, 0x7f, 0xf0, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00,	/* 225 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 226 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 227 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+	0x70, 0x00, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0xe0,
+	0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00,
+	0x0e, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x70, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 228 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xfe, 0x3f, 0xfe, 0x78, 0xf0, 0x70, 0x78,
+	0x70, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 229 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x3c, 0x70, 0x7c, 0x70, 0xfc,
+	0x7f, 0xdc, 0x7f, 0x9c, 0x70, 0x00, 0x70, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00,	/* 230 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0xc0,
+	0x01, 0xf8, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 231 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x1f, 0xf0, 0x3f, 0xf8, 0x7b, 0xbc, 0x73, 0x9c,
+	0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c,
+	0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c, 0x73, 0x9c,
+	0x73, 0x9c, 0x7b, 0xbc, 0x3f, 0xf8, 0x1f, 0xf0,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 232 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x77, 0xdc,
+	0x77, 0xdc, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 233 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x3f, 0xf8,
+	0x78, 0x3c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x38, 0x38, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70,
+	0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 234 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x1f, 0xf0,
+	0x0e, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xc0,
+	0x0f, 0xe0, 0x1f, 0xf0, 0x38, 0x38, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x78, 0x3c,
+	0x3f, 0xf8, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 235 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xf8,
+	0x7f, 0xfc, 0xe7, 0xce, 0xe3, 0x8e, 0xe3, 0x8e,
+	0xe3, 0x8e, 0xe3, 0x8e, 0xe7, 0xce, 0x7f, 0xfc,
+	0x3e, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 236 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1c,
+	0x00, 0x38, 0x00, 0x38, 0x0f, 0xf0, 0x1f, 0xf8,
+	0x38, 0xfc, 0x38, 0xfc, 0x39, 0xdc, 0x39, 0xdc,
+	0x3b, 0x9c, 0x3b, 0x9c, 0x3f, 0x1c, 0x3f, 0x1c,
+	0x1f, 0xf8, 0x0f, 0xf0, 0x1c, 0x00, 0x1c, 0x00,
+	0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 237 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x07, 0xfc, 0x1f, 0xfc, 0x3c, 0x00,
+	0x38, 0x00, 0x70, 0x00, 0x70, 0x00, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x70, 0x00, 0x70, 0x00, 0x38, 0x00,
+	0x3c, 0x00, 0x1f, 0xfc, 0x07, 0xfc, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 238 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x1f, 0xf0,
+	0x3c, 0x78, 0x38, 0x38, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+	0x70, 0x1c, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 239 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 240 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 241 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0xe0,
+	0x00, 0x70, 0x00, 0x38, 0x00, 0x38, 0x00, 0x70,
+	0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00,
+	0x0e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 242 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x70,
+	0x00, 0xe0, 0x01, 0xc0, 0x03, 0x80, 0x07, 0x00,
+	0x0e, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x0e, 0x00,
+	0x07, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00, 0xe0,
+	0x00, 0x70, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00,
+	0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 243 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x03, 0xfc,
+	0x03, 0x9c, 0x03, 0x9c, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,	/* 244 */
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x73, 0x80, 0x73, 0x80,
+	0x7f, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 245 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc,
+	0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 246 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x1c,
+	0x7f, 0xbc, 0x7b, 0xfc, 0x70, 0xf8, 0x00, 0x00,
+	0x00, 0x00, 0x3e, 0x1c, 0x7f, 0xbc, 0x7b, 0xfc,
+	0x70, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 247 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x0f, 0xe0, 0x1f, 0xf0, 0x1c, 0x70, 0x1c, 0x70,
+	0x1c, 0x70, 0x1c, 0x70, 0x1f, 0xf0, 0x0f, 0xe0,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 248 */
+	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, 0x03, 0xc0, 0x07, 0xe0, 0x07, 0xe0,
+	0x07, 0xe0, 0x07, 0xe0, 0x03, 0xc0, 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,	/* 249 */
+	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, 0x03, 0x80, 0x03, 0x80,
+	0x03, 0x80, 0x03, 0x80, 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,	/* 250 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
+	0x00, 0x3e, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+	0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x70, 0x38,
+	0x70, 0x38, 0x70, 0x38, 0x78, 0x38, 0x3c, 0x38,
+	0x1e, 0x38, 0x0f, 0x38, 0x07, 0xb8, 0x03, 0xf8,
+	0x01, 0xf8, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 251 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0xe0, 0x1f, 0xf0, 0x1c, 0x38, 0x1c, 0x38,
+	0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x38,
+	0x1c, 0x38, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 252 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0,
+	0x1f, 0xf0, 0x1c, 0x70, 0x1c, 0x70, 0x00, 0xe0,
+	0x01, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x0e, 0x00,
+	0x1f, 0xf0, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 253 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x1f, 0xf8,
+	0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8,
+	0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8,
+	0x1f, 0xf8, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 254 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 255 */
+
+};
+
+
+const struct font_desc font_ter_16x32 = {
+	.idx	= TER16x32_IDX,
+	.name	= "TER16x32",
+	.width	= 16,
+	.height = 32,
+	.data	= fontdata_ter16x32,
+#ifdef __sparc__
+	.pref	= 5,
+#else
+	.pref	= -1,
+#endif
+};
--- linux-4.4.0.orig/lib/fonts/fonts.c
+++ linux-4.4.0/lib/fonts/fonts.c
@@ -25,47 +25,51 @@
 static const struct font_desc *fonts[] = {
 #ifdef CONFIG_FONT_8x8
 #undef NO_FONTS
-    &font_vga_8x8,
+	&font_vga_8x8,
 #endif
 #ifdef CONFIG_FONT_8x16
 #undef NO_FONTS
-    &font_vga_8x16,
+	&font_vga_8x16,
 #endif
 #ifdef CONFIG_FONT_6x11
 #undef NO_FONTS
-    &font_vga_6x11,
+	&font_vga_6x11,
 #endif
 #ifdef CONFIG_FONT_7x14
 #undef NO_FONTS
-    &font_7x14,
+	&font_7x14,
 #endif
 #ifdef CONFIG_FONT_SUN8x16
 #undef NO_FONTS
-    &font_sun_8x16,
+	&font_sun_8x16,
 #endif
 #ifdef CONFIG_FONT_SUN12x22
 #undef NO_FONTS
-    &font_sun_12x22,
+	&font_sun_12x22,
 #endif
 #ifdef CONFIG_FONT_10x18
 #undef NO_FONTS
-    &font_10x18,
+	&font_10x18,
 #endif
 #ifdef CONFIG_FONT_ACORN_8x8
 #undef NO_FONTS
-    &font_acorn_8x8,
+	&font_acorn_8x8,
 #endif
 #ifdef CONFIG_FONT_PEARL_8x8
 #undef NO_FONTS
-    &font_pearl_8x8,
+	&font_pearl_8x8,
 #endif
 #ifdef CONFIG_FONT_MINI_4x6
 #undef NO_FONTS
-    &font_mini_4x6,
+	&font_mini_4x6,
 #endif
 #ifdef CONFIG_FONT_6x10
 #undef NO_FONTS
-    &font_6x10,
+	&font_6x10,
+#endif
+#ifdef CONFIG_FONT_TER16x32
+#undef NO_FONTS
+	&font_ter_16x32,
 #endif
 };
 
@@ -86,16 +90,16 @@
  *	specified font.
  *
  */
-
 const struct font_desc *find_font(const char *name)
 {
-   unsigned int i;
+	unsigned int i;
 
-   for (i = 0; i < num_fonts; i++)
-      if (!strcmp(fonts[i]->name, name))
-	  return fonts[i];
-   return NULL;
+	for (i = 0; i < num_fonts; i++)
+		if (!strcmp(fonts[i]->name, name))
+			return fonts[i];
+	return NULL;
 }
+EXPORT_SYMBOL(find_font);
 
 
 /**
@@ -112,44 +116,46 @@
  *	chosen font.
  *
  */
-
 const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
 					 u32 font_h)
 {
-    int i, c, cc;
-    const struct font_desc *f, *g;
+	int i, c, cc, res;
+	const struct font_desc *f, *g;
 
-    g = NULL;
-    cc = -10000;
-    for(i=0; i<num_fonts; i++) {
-	f = fonts[i];
-	c = f->pref;
+	g = NULL;
+	cc = -10000;
+	for (i = 0; i < num_fonts; i++) {
+		f = fonts[i];
+		c = f->pref;
 #if defined(__mc68000__)
 #ifdef CONFIG_FONT_PEARL_8x8
-	if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
-	    c = 100;
+		if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
+			c = 100;
 #endif
 #ifdef CONFIG_FONT_6x11
-	if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX)
-	    c = 100;
+		if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX)
+			c = 100;
 #endif
 #endif
-	if ((yres < 400) == (f->height <= 8))
-	    c += 1000;
-
-	if ((font_w & (1 << (f->width - 1))) &&
-	    (font_h & (1 << (f->height - 1))))
-	    c += 1000;
+		if ((yres < 400) == (f->height <= 8))
+			c += 1000;
 
-	if (c > cc) {
-	    cc = c;
-	    g = f;
+		/* prefer a bigger font for high resolution */
+		res = (xres / f->width) * (yres / f->height) / 1000;
+		if (res > 20)
+			c += 20 - res;
+
+		if ((font_w & (1 << (f->width - 1))) &&
+		    (font_h & (1 << (f->height - 1))))
+			c += 1000;
+
+		if (c > cc) {
+			cc = c;
+			g = f;
+		}
 	}
-    }
-    return g;
+	return g;
 }
-
-EXPORT_SYMBOL(find_font);
 EXPORT_SYMBOL(get_default_font);
 
 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
--- linux-4.4.0.orig/lib/genalloc.c
+++ linux-4.4.0/lib/genalloc.c
@@ -35,6 +35,7 @@
 #include <linux/interrupt.h>
 #include <linux/genalloc.h>
 #include <linux/of_device.h>
+#include <linux/vmalloc.h>
 
 static inline size_t chunk_size(const struct gen_pool_chunk *chunk)
 {
@@ -82,14 +83,14 @@
  * users set the same bit, one user will return remain bits, otherwise
  * return 0.
  */
-static int bitmap_set_ll(unsigned long *map, int start, int nr)
+static int bitmap_set_ll(unsigned long *map, unsigned long start, unsigned long nr)
 {
 	unsigned long *p = map + BIT_WORD(start);
-	const int size = start + nr;
+	const unsigned long size = start + nr;
 	int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
 	unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
 
-	while (nr - bits_to_set >= 0) {
+	while (nr >= bits_to_set) {
 		if (set_bits_ll(p, mask_to_set))
 			return nr;
 		nr -= bits_to_set;
@@ -117,14 +118,15 @@
  * users clear the same bit, one user will return remain bits,
  * otherwise return 0.
  */
-static int bitmap_clear_ll(unsigned long *map, int start, int nr)
+static unsigned long
+bitmap_clear_ll(unsigned long *map, unsigned long start, unsigned long nr)
 {
 	unsigned long *p = map + BIT_WORD(start);
-	const int size = start + nr;
+	const unsigned long size = start + nr;
 	int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
 	unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
 
-	while (nr - bits_to_clear >= 0) {
+	while (nr >= bits_to_clear) {
 		if (clear_bits_ll(p, mask_to_clear))
 			return nr;
 		nr -= bits_to_clear;
@@ -183,18 +185,18 @@
 		 size_t size, int nid)
 {
 	struct gen_pool_chunk *chunk;
-	int nbits = size >> pool->min_alloc_order;
-	int nbytes = sizeof(struct gen_pool_chunk) +
+	unsigned long nbits = size >> pool->min_alloc_order;
+	unsigned long nbytes = sizeof(struct gen_pool_chunk) +
 				BITS_TO_LONGS(nbits) * sizeof(long);
 
-	chunk = kzalloc_node(nbytes, GFP_KERNEL, nid);
+	chunk = vzalloc_node(nbytes, nid);
 	if (unlikely(chunk == NULL))
 		return -ENOMEM;
 
 	chunk->phys_addr = phys;
 	chunk->start_addr = virt;
 	chunk->end_addr = virt + size - 1;
-	atomic_set(&chunk->avail, size);
+	atomic_long_set(&chunk->avail, size);
 
 	spin_lock(&pool->lock);
 	list_add_rcu(&chunk->next_chunk, &pool->chunks);
@@ -241,7 +243,7 @@
 	struct list_head *_chunk, *_next_chunk;
 	struct gen_pool_chunk *chunk;
 	int order = pool->min_alloc_order;
-	int bit, end_bit;
+	unsigned long bit, end_bit;
 
 	list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
 		chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
@@ -251,7 +253,7 @@
 		bit = find_next_bit(chunk->bits, end_bit, 0);
 		BUG_ON(bit < end_bit);
 
-		kfree(chunk);
+		vfree(chunk);
 	}
 	kfree_const(pool->name);
 	kfree(pool);
@@ -273,7 +275,7 @@
 	struct gen_pool_chunk *chunk;
 	unsigned long addr = 0;
 	int order = pool->min_alloc_order;
-	int nbits, start_bit = 0, end_bit, remain;
+	unsigned long nbits, start_bit, end_bit, remain;
 
 #ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
 	BUG_ON(in_nmi());
@@ -285,9 +287,10 @@
 	nbits = (size + (1UL << order) - 1) >> order;
 	rcu_read_lock();
 	list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
-		if (size > atomic_read(&chunk->avail))
+		if (size > atomic_long_read(&chunk->avail))
 			continue;
 
+		start_bit = 0;
 		end_bit = chunk_size(chunk) >> order;
 retry:
 		start_bit = pool->algo(chunk->bits, end_bit, start_bit, nbits,
@@ -304,7 +307,7 @@
 
 		addr = chunk->start_addr + ((unsigned long)start_bit << order);
 		size = nbits << order;
-		atomic_sub(size, &chunk->avail);
+		atomic_long_sub(size, &chunk->avail);
 		break;
 	}
 	rcu_read_unlock();
@@ -355,7 +358,7 @@
 {
 	struct gen_pool_chunk *chunk;
 	int order = pool->min_alloc_order;
-	int start_bit, nbits, remain;
+	unsigned long start_bit, nbits, remain;
 
 #ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
 	BUG_ON(in_nmi());
@@ -370,7 +373,7 @@
 			remain = bitmap_clear_ll(chunk->bits, start_bit, nbits);
 			BUG_ON(remain);
 			size = nbits << order;
-			atomic_add(size, &chunk->avail);
+			atomic_long_add(size, &chunk->avail);
 			rcu_read_unlock();
 			return;
 		}
@@ -444,7 +447,7 @@
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk)
-		avail += atomic_read(&chunk->avail);
+		avail += atomic_long_read(&chunk->avail);
 	rcu_read_unlock();
 	return avail;
 }
@@ -551,7 +554,7 @@
 	index = bitmap_find_next_zero_area(map, size, start, nr, 0);
 
 	while (index < size) {
-		int next_bit = find_next_bit(map, size, index + nr);
+		unsigned long next_bit = find_next_bit(map, size, index + nr);
 		if ((next_bit - index) < len) {
 			len = next_bit - index;
 			start_bit = index;
--- linux-4.4.0.orig/lib/hweight.c
+++ linux-4.4.0/lib/hweight.c
@@ -9,6 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
+#ifndef __HAVE_ARCH_SW_HWEIGHT
 unsigned int __sw_hweight32(unsigned int w)
 {
 #ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER
@@ -25,6 +26,7 @@
 #endif
 }
 EXPORT_SYMBOL(__sw_hweight32);
+#endif
 
 unsigned int __sw_hweight16(unsigned int w)
 {
@@ -43,6 +45,7 @@
 }
 EXPORT_SYMBOL(__sw_hweight8);
 
+#ifndef __HAVE_ARCH_SW_HWEIGHT
 unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
@@ -65,3 +68,4 @@
 #endif
 }
 EXPORT_SYMBOL(__sw_hweight64);
+#endif
--- linux-4.4.0.orig/lib/int_sqrt.c
+++ linux-4.4.0/lib/int_sqrt.c
@@ -7,6 +7,7 @@
 
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <linux/bitops.h>
 
 /**
  * int_sqrt - rough approximation to sqrt
@@ -21,7 +22,7 @@
 	if (x <= 1)
 		return x;
 
-	m = 1UL << (BITS_PER_LONG - 2);
+	m = 1UL << (__fls(x) & ~1UL);
 	while (m != 0) {
 		b = y + m;
 		y >>= 1;
--- linux-4.4.0.orig/lib/interval_tree_test.c
+++ linux-4.4.0/lib/interval_tree_test.c
@@ -1,27 +1,38 @@
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/interval_tree.h>
 #include <linux/random.h>
+#include <linux/slab.h>
 #include <asm/timex.h>
 
-#define NODES        100
-#define PERF_LOOPS   100000
-#define SEARCHES     100
-#define SEARCH_LOOPS 10000
+#define __param(type, name, init, msg)		\
+	static type name = init;		\
+	module_param(name, type, 0444);		\
+	MODULE_PARM_DESC(name, msg);
+
+__param(int, nnodes, 100, "Number of nodes in the interval tree");
+__param(int, perf_loops, 1000, "Number of iterations modifying the tree");
+
+__param(int, nsearches, 100, "Number of searches to the interval tree");
+__param(int, search_loops, 1000, "Number of iterations searching the tree");
+__param(bool, search_all, false, "Searches will iterate all nodes in the tree");
+
+__param(uint, max_endpoint, ~0, "Largest value for the interval's endpoint");
 
 static struct rb_root root = RB_ROOT;
-static struct interval_tree_node nodes[NODES];
-static u32 queries[SEARCHES];
+static struct interval_tree_node *nodes = NULL;
+static u32 *queries = NULL;
 
 static struct rnd_state rnd;
 
 static inline unsigned long
-search(unsigned long query, struct rb_root *root)
+search(struct rb_root *root, unsigned long start, unsigned long last)
 {
 	struct interval_tree_node *node;
 	unsigned long results = 0;
 
-	for (node = interval_tree_iter_first(root, query, query); node;
-	     node = interval_tree_iter_next(node, query, query))
+	for (node = interval_tree_iter_first(root, start, last); node;
+	     node = interval_tree_iter_next(node, start, last))
 		results++;
 	return results;
 }
@@ -29,19 +40,22 @@
 static void init(void)
 {
 	int i;
-	for (i = 0; i < NODES; i++) {
-		u32 a = prandom_u32_state(&rnd);
-		u32 b = prandom_u32_state(&rnd);
-		if (a <= b) {
-			nodes[i].start = a;
-			nodes[i].last = b;
-		} else {
-			nodes[i].start = b;
-			nodes[i].last = a;
-		}
+
+	for (i = 0; i < nnodes; i++) {
+		u32 b = (prandom_u32_state(&rnd) >> 4) % max_endpoint;
+		u32 a = (prandom_u32_state(&rnd) >> 4) % b;
+
+		nodes[i].start = a;
+		nodes[i].last = b;
 	}
-	for (i = 0; i < SEARCHES; i++)
-		queries[i] = prandom_u32_state(&rnd);
+
+	/*
+	 * Limit the search scope to what the user defined.
+	 * Otherwise we are merely measuring empty walks,
+	 * which is pointless.
+	 */
+	for (i = 0; i < nsearches; i++)
+		queries[i] = (prandom_u32_state(&rnd) >> 4) % max_endpoint;
 }
 
 static int interval_tree_test_init(void)
@@ -50,6 +64,16 @@
 	unsigned long results;
 	cycles_t time1, time2, time;
 
+	nodes = kmalloc(nnodes * sizeof(struct interval_tree_node), GFP_KERNEL);
+	if (!nodes)
+		return -ENOMEM;
+
+	queries = kmalloc(nsearches * sizeof(int), GFP_KERNEL);
+	if (!queries) {
+		kfree(nodes);
+		return -ENOMEM;
+	}
+
 	printk(KERN_ALERT "interval tree insert/remove");
 
 	prandom_seed_state(&rnd, 3141592653589793238ULL);
@@ -57,39 +81,46 @@
 
 	time1 = get_cycles();
 
-	for (i = 0; i < PERF_LOOPS; i++) {
-		for (j = 0; j < NODES; j++)
+	for (i = 0; i < perf_loops; i++) {
+		for (j = 0; j < nnodes; j++)
 			interval_tree_insert(nodes + j, &root);
-		for (j = 0; j < NODES; j++)
+		for (j = 0; j < nnodes; j++)
 			interval_tree_remove(nodes + j, &root);
 	}
 
 	time2 = get_cycles();
 	time = time2 - time1;
 
-	time = div_u64(time, PERF_LOOPS);
+	time = div_u64(time, perf_loops);
 	printk(" -> %llu cycles\n", (unsigned long long)time);
 
 	printk(KERN_ALERT "interval tree search");
 
-	for (j = 0; j < NODES; j++)
+	for (j = 0; j < nnodes; j++)
 		interval_tree_insert(nodes + j, &root);
 
 	time1 = get_cycles();
 
 	results = 0;
-	for (i = 0; i < SEARCH_LOOPS; i++)
-		for (j = 0; j < SEARCHES; j++)
-			results += search(queries[j], &root);
+	for (i = 0; i < search_loops; i++)
+		for (j = 0; j < nsearches; j++) {
+			unsigned long start = search_all ? 0 : queries[j];
+			unsigned long last = search_all ? max_endpoint : queries[j];
+
+			results += search(&root, start, last);
+		}
 
 	time2 = get_cycles();
 	time = time2 - time1;
 
-	time = div_u64(time, SEARCH_LOOPS);
-	results = div_u64(results, SEARCH_LOOPS);
+	time = div_u64(time, search_loops);
+	results = div_u64(results, search_loops);
 	printk(" -> %llu cycles (%lu results)\n",
 	       (unsigned long long)time, results);
 
+	kfree(queries);
+	kfree(nodes);
+
 	return -EAGAIN; /* Fail will directly unload the module */
 }
 
--- linux-4.4.0.orig/lib/ioremap.c
+++ linux-4.4.0/lib/ioremap.c
@@ -83,7 +83,8 @@
 
 		if (ioremap_pmd_enabled() &&
 		    ((next - addr) == PMD_SIZE) &&
-		    IS_ALIGNED(phys_addr + addr, PMD_SIZE)) {
+		    IS_ALIGNED(phys_addr + addr, PMD_SIZE) &&
+		    pmd_free_pte_page(pmd, addr)) {
 			if (pmd_set_huge(pmd, phys_addr + addr, prot))
 				continue;
 		}
@@ -109,7 +110,8 @@
 
 		if (ioremap_pud_enabled() &&
 		    ((next - addr) == PUD_SIZE) &&
-		    IS_ALIGNED(phys_addr + addr, PUD_SIZE)) {
+		    IS_ALIGNED(phys_addr + addr, PUD_SIZE) &&
+		    pud_free_pmd_page(pud, addr)) {
 			if (pud_set_huge(pud, phys_addr + addr, prot))
 				continue;
 		}
--- linux-4.4.0.orig/lib/iov_iter.c
+++ linux-4.4.0/lib/iov_iter.c
@@ -298,33 +298,13 @@
 }
 
 /*
- * Fault in the first iovec of the given iov_iter, to a maximum length
- * of bytes. Returns 0 on success, or non-zero if the memory could not be
- * accessed (ie. because it is an invalid address).
- *
- * writev-intensive code may want this to prefault several iovecs -- that
- * would be possible (callers must not rely on the fact that _only_ the
- * first iovec will be faulted with the current implementation).
- */
-int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
-{
-	if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
-		char __user *buf = i->iov->iov_base + i->iov_offset;
-		bytes = min(bytes, i->iov->iov_len - i->iov_offset);
-		return fault_in_pages_readable(buf, bytes);
-	}
-	return 0;
-}
-EXPORT_SYMBOL(iov_iter_fault_in_readable);
-
-/*
  * Fault in one or more iovecs of the given iov_iter, to a maximum length of
  * bytes.  For each iovec, fault in each page that constitutes the iovec.
  *
  * Return 0 on success, or non-zero if the memory could not be accessed (i.e.
  * because it is an invalid address).
  */
-int iov_iter_fault_in_multipages_readable(struct iov_iter *i, size_t bytes)
+int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
 {
 	size_t skip = i->iov_offset;
 	const struct iovec *iov;
@@ -341,7 +321,7 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL(iov_iter_fault_in_multipages_readable);
+EXPORT_SYMBOL(iov_iter_fault_in_readable);
 
 void iov_iter_init(struct iov_iter *i, int direction,
 			const struct iovec *iov, unsigned long nr_segs,
--- linux-4.4.0.orig/lib/kfifo.c
+++ linux-4.4.0/lib/kfifo.c
@@ -82,7 +82,8 @@
 {
 	size /= esize;
 
-	size = roundup_pow_of_two(size);
+	if (!is_power_of_2(size))
+		size = rounddown_pow_of_two(size);
 
 	fifo->in = 0;
 	fifo->out = 0;
--- linux-4.4.0.orig/lib/klist.c
+++ linux-4.4.0/lib/klist.c
@@ -282,9 +282,9 @@
 			  struct klist_node *n)
 {
 	i->i_klist = k;
-	i->i_cur = n;
-	if (n)
-		kref_get(&n->n_ref);
+	i->i_cur = NULL;
+	if (n && kref_get_unless_zero(&n->n_ref))
+		i->i_cur = n;
 }
 EXPORT_SYMBOL_GPL(klist_iter_init_node);
 
@@ -336,8 +336,9 @@
 	void (*put)(struct klist_node *) = i->i_klist->put;
 	struct klist_node *last = i->i_cur;
 	struct klist_node *prev;
+	unsigned long flags;
 
-	spin_lock(&i->i_klist->k_lock);
+	spin_lock_irqsave(&i->i_klist->k_lock, flags);
 
 	if (last) {
 		prev = to_klist_node(last->n_node.prev);
@@ -356,7 +357,7 @@
 		prev = to_klist_node(prev->n_node.prev);
 	}
 
-	spin_unlock(&i->i_klist->k_lock);
+	spin_unlock_irqrestore(&i->i_klist->k_lock, flags);
 
 	if (put && last)
 		put(last);
@@ -377,8 +378,9 @@
 	void (*put)(struct klist_node *) = i->i_klist->put;
 	struct klist_node *last = i->i_cur;
 	struct klist_node *next;
+	unsigned long flags;
 
-	spin_lock(&i->i_klist->k_lock);
+	spin_lock_irqsave(&i->i_klist->k_lock, flags);
 
 	if (last) {
 		next = to_klist_node(last->n_node.next);
@@ -397,7 +399,7 @@
 		next = to_klist_node(next->n_node.next);
 	}
 
-	spin_unlock(&i->i_klist->k_lock);
+	spin_unlock_irqrestore(&i->i_klist->k_lock, flags);
 
 	if (put && last)
 		put(last);
--- linux-4.4.0.orig/lib/kobject.c
+++ linux-4.4.0/lib/kobject.c
@@ -118,7 +118,7 @@
 	return length;
 }
 
-static void fill_kobj_path(struct kobject *kobj, char *path, int length)
+static int fill_kobj_path(struct kobject *kobj, char *path, int length)
 {
 	struct kobject *parent;
 
@@ -127,12 +127,16 @@
 		int cur = strlen(kobject_name(parent));
 		/* back up enough to print this name with '/' */
 		length -= cur;
-		strncpy(path + length, kobject_name(parent), cur);
+		if (length <= 0)
+			return -EINVAL;
+		memcpy(path + length, kobject_name(parent), cur);
 		*(path + --length) = '/';
 	}
 
 	pr_debug("kobject: '%s' (%p): %s: path = '%s'\n", kobject_name(kobj),
 		 kobj, __func__, path);
+
+	return 0;
 }
 
 /**
@@ -148,13 +152,17 @@
 	char *path;
 	int len;
 
+retry:
 	len = get_kobj_path_length(kobj);
 	if (len == 0)
 		return NULL;
 	path = kzalloc(len, gfp_mask);
 	if (!path)
 		return NULL;
-	fill_kobj_path(kobj, path, len);
+	if (fill_kobj_path(kobj, path, len)) {
+		kfree(path);
+		goto retry;
+	}
 
 	return path;
 }
@@ -234,14 +242,12 @@
 
 		/* be noisy on error issues */
 		if (error == -EEXIST)
-			WARN(1, "%s failed for %s with "
-			     "-EEXIST, don't try to register things with "
-			     "the same name in the same directory.\n",
-			     __func__, kobject_name(kobj));
+			pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n",
+			       __func__, kobject_name(kobj));
 		else
-			WARN(1, "%s failed for %s (error: %d parent: %s)\n",
-			     __func__, kobject_name(kobj), error,
-			     parent ? kobject_name(parent) : "'none'");
+			pr_err("%s failed for %s (error: %d parent: %s)\n",
+			       __func__, kobject_name(kobj), error,
+			       parent ? kobject_name(parent) : "'none'");
 	} else
 		kobj->state_in_sysfs = 1;
 
@@ -601,12 +607,15 @@
 }
 EXPORT_SYMBOL(kobject_get);
 
-static struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj)
+struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj)
 {
+	if (!kobj)
+		return NULL;
 	if (!kref_get_unless_zero(&kobj->kref))
 		kobj = NULL;
 	return kobj;
 }
+EXPORT_SYMBOL(kobject_get_unless_zero);
 
 /*
  * kobject_cleanup - free kobject resources.
--- linux-4.4.0.orig/lib/kstrtox.c
+++ linux-4.4.0/lib/kstrtox.c
@@ -321,6 +321,70 @@
 }
 EXPORT_SYMBOL(kstrtos8);
 
+/**
+ * kstrtobool - convert common user inputs into boolean values
+ * @s: input string
+ * @res: result
+ *
+ * This routine returns 0 iff the first character is one of 'Yy1Nn0', or
+ * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL.  Value
+ * pointed to by res is updated upon finding a match.
+ */
+int kstrtobool(const char *s, bool *res)
+{
+	if (!s)
+		return -EINVAL;
+
+	switch (s[0]) {
+	case 'y':
+	case 'Y':
+	case '1':
+		*res = true;
+		return 0;
+	case 'n':
+	case 'N':
+	case '0':
+		*res = false;
+		return 0;
+	case 'o':
+	case 'O':
+		switch (s[1]) {
+		case 'n':
+		case 'N':
+			*res = true;
+			return 0;
+		case 'f':
+		case 'F':
+			*res = false;
+			return 0;
+		default:
+			break;
+		}
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(kstrtobool);
+
+/*
+ * Since "base" would be a nonsense argument, this open-codes the
+ * _from_user helper instead of using the helper macro below.
+ */
+int kstrtobool_from_user(const char __user *s, size_t count, bool *res)
+{
+	/* Longest string needed to differentiate, newline, terminator */
+	char buf[4];
+
+	count = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, s, count))
+		return -EFAULT;
+	buf[count] = '\0';
+	return kstrtobool(buf, res);
+}
+EXPORT_SYMBOL(kstrtobool_from_user);
+
 #define kstrto_from_user(f, g, type)					\
 int f(const char __user *s, size_t count, unsigned int base, type *res)	\
 {									\
--- linux-4.4.0.orig/lib/libcrc32c.c
+++ linux-4.4.0/lib/libcrc32c.c
@@ -74,3 +74,4 @@
 MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
 MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations");
 MODULE_LICENSE("GPL");
+MODULE_SOFTDEP("pre: crc32c");
--- linux-4.4.0.orig/lib/lz4/lz4defs.h
+++ linux-4.4.0/lib/lz4/lz4defs.h
@@ -11,8 +11,7 @@
 /*
  * Detects 64 bits mode
  */
-#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) \
-	|| defined(__ppc64__) || defined(__LP64__))
+#if defined(CONFIG_64BIT)
 #define LZ4_ARCH64 1
 #else
 #define LZ4_ARCH64 0
@@ -35,6 +34,10 @@
 
 #define PUT4(s, d) (A32(d) = A32(s))
 #define PUT8(s, d) (A64(d) = A64(s))
+
+#define LZ4_READ_LITTLEENDIAN_16(d, s, p)	\
+	(d = s - A16(p))
+
 #define LZ4_WRITE_LITTLEENDIAN_16(p, v)	\
 	do {	\
 		A16(p) = v; \
@@ -51,10 +54,13 @@
 #define PUT8(s, d) \
 	put_unaligned(get_unaligned((const u64 *) s), (u64 *) d)
 
-#define LZ4_WRITE_LITTLEENDIAN_16(p, v)	\
-	do {	\
-		put_unaligned(v, (u16 *)(p)); \
-		p += 2; \
+#define LZ4_READ_LITTLEENDIAN_16(d, s, p)	\
+	(d = s - get_unaligned_le16(p))
+
+#define LZ4_WRITE_LITTLEENDIAN_16(p, v)			\
+	do {						\
+		put_unaligned_le16(v, (u16 *)(p));	\
+		p += 2;					\
 	} while (0)
 #endif
 
@@ -140,9 +146,6 @@
 
 #endif
 
-#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
-	(d = s - get_unaligned_le16(p))
-
 #define LZ4_WILDCOPY(s, d, e)		\
 	do {				\
 		LZ4_COPYPACKET(s, d);	\
--- linux-4.4.0.orig/lib/mpi/longlong.h
+++ linux-4.4.0/lib/mpi/longlong.h
@@ -671,7 +671,23 @@
 	**************  MIPS/64  **************
 	***************************************/
 #if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64
-#if (__GNUC__ >= 5) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 4)
+#if defined(__mips_isa_rev) && __mips_isa_rev >= 6 && defined(CONFIG_CC_IS_GCC)
+/*
+ * GCC ends up emitting a __multi3 intrinsic call for MIPS64r6 with the plain C
+ * code below, so we special case MIPS64r6 until the compiler can do better.
+ */
+#define umul_ppmm(w1, w0, u, v)						\
+do {									\
+	__asm__ ("dmulu %0,%1,%2"					\
+		 : "=d" ((UDItype)(w0))					\
+		 : "d" ((UDItype)(u)),					\
+		   "d" ((UDItype)(v)));					\
+	__asm__ ("dmuhu %0,%1,%2"					\
+		 : "=d" ((UDItype)(w1))					\
+		 : "d" ((UDItype)(u)),					\
+		   "d" ((UDItype)(v)));					\
+} while (0)
+#elif (__GNUC__ >= 5) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 4)
 #define umul_ppmm(w1, w0, u, v) \
 do {									\
 	typedef unsigned int __ll_UTItype __attribute__((mode(TI)));	\
@@ -740,22 +756,22 @@
 do { \
 	if (__builtin_constant_p(bh) && (bh) == 0) \
 		__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
-		: "=r" ((USItype)(sh)), \
-		"=&r" ((USItype)(sl)) \
+		: "=r" (sh), \
+		"=&r" (sl) \
 		: "%r" ((USItype)(ah)), \
 		"%r" ((USItype)(al)), \
 		"rI" ((USItype)(bl))); \
 	else if (__builtin_constant_p(bh) && (bh) == ~(USItype) 0) \
 		__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
-		: "=r" ((USItype)(sh)), \
-		"=&r" ((USItype)(sl)) \
+		: "=r" (sh), \
+		"=&r" (sl) \
 		: "%r" ((USItype)(ah)), \
 		"%r" ((USItype)(al)), \
 		"rI" ((USItype)(bl))); \
 	else \
 		__asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
-		: "=r" ((USItype)(sh)), \
-		"=&r" ((USItype)(sl)) \
+		: "=r" (sh), \
+		"=&r" (sl) \
 		: "%r" ((USItype)(ah)), \
 		"r" ((USItype)(bh)), \
 		"%r" ((USItype)(al)), \
@@ -765,36 +781,36 @@
 do { \
 	if (__builtin_constant_p(ah) && (ah) == 0) \
 		__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
-		: "=r" ((USItype)(sh)), \
-		"=&r" ((USItype)(sl)) \
+		: "=r" (sh), \
+		"=&r" (sl) \
 		: "r" ((USItype)(bh)), \
 		"rI" ((USItype)(al)), \
 		"r" ((USItype)(bl))); \
 	else if (__builtin_constant_p(ah) && (ah) == ~(USItype) 0) \
 		__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
-		: "=r" ((USItype)(sh)), \
-		"=&r" ((USItype)(sl)) \
+		: "=r" (sh), \
+		"=&r" (sl) \
 		: "r" ((USItype)(bh)), \
 		"rI" ((USItype)(al)), \
 		"r" ((USItype)(bl))); \
 	else if (__builtin_constant_p(bh) && (bh) == 0) \
 		__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
-		: "=r" ((USItype)(sh)), \
-		"=&r" ((USItype)(sl)) \
+		: "=r" (sh), \
+		"=&r" (sl) \
 		: "r" ((USItype)(ah)), \
 		"rI" ((USItype)(al)), \
 		"r" ((USItype)(bl))); \
 	else if (__builtin_constant_p(bh) && (bh) == ~(USItype) 0) \
 		__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
-		: "=r" ((USItype)(sh)), \
-		"=&r" ((USItype)(sl)) \
+		: "=r" (sh), \
+		"=&r" (sl) \
 		: "r" ((USItype)(ah)), \
 		"rI" ((USItype)(al)), \
 		"r" ((USItype)(bl))); \
 	else \
 		__asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
-		: "=r" ((USItype)(sh)), \
-		"=&r" ((USItype)(sl)) \
+		: "=r" (sh), \
+		"=&r" (sl) \
 		: "r" ((USItype)(ah)), \
 		"r" ((USItype)(bh)), \
 		"rI" ((USItype)(al)), \
@@ -805,7 +821,7 @@
 do { \
 	USItype __m0 = (m0), __m1 = (m1); \
 	__asm__ ("mulhwu %0,%1,%2" \
-	: "=r" ((USItype) ph) \
+	: "=r" (ph) \
 	: "%r" (__m0), \
 	"r" (__m1)); \
 	(pl) = __m0 * __m1; \
--- linux-4.4.0.orig/lib/mpi/mpi-pow.c
+++ linux-4.4.0/lib/mpi/mpi-pow.c
@@ -26,6 +26,7 @@
  *	 however I decided to publish this code under the plain GPL.
  */
 
+#include <linux/sched.h>
 #include <linux/string.h>
 #include "mpi-internal.h"
 #include "longlong.h"
@@ -36,6 +37,7 @@
 int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
 {
 	mpi_ptr_t mp_marker = NULL, bp_marker = NULL, ep_marker = NULL;
+	struct karatsuba_ctx karactx = {};
 	mpi_ptr_t xp_marker = NULL;
 	mpi_ptr_t tspace = NULL;
 	mpi_ptr_t rp, ep, mp, bp;
@@ -64,8 +66,13 @@
 	if (!esize) {
 		/* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
 		 * depending on if MOD equals 1.  */
-		rp[0] = 1;
 		res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1;
+		if (res->nlimbs) {
+			if (mpi_resize(res, 1) < 0)
+				goto enomem;
+			rp = res->d;
+			rp[0] = 1;
+		}
 		res->sign = 0;
 		goto leave;
 	}
@@ -158,13 +165,11 @@
 		int c;
 		mpi_limb_t e;
 		mpi_limb_t carry_limb;
-		struct karatsuba_ctx karactx;
 
 		xp = xp_marker = mpi_alloc_limb_space(2 * (msize + 1));
 		if (!xp)
 			goto enomem;
 
-		memset(&karactx, 0, sizeof karactx);
 		negative_result = (ep[0] & 1) && base->sign;
 
 		i = esize - 1;
@@ -251,6 +256,7 @@
 				}
 				e <<= 1;
 				c--;
+				cond_resched();
 			}
 
 			i--;
@@ -288,8 +294,6 @@
 		if (mod_shift_cnt)
 			mpihelp_rshift(rp, rp, rsize, mod_shift_cnt);
 		MPN_NORMALIZE(rp, rsize);
-
-		mpihelp_release_karatsuba_ctx(&karactx);
 	}
 
 	if (negative_result && rsize) {
@@ -306,6 +310,7 @@
 leave:
 	rc = 0;
 enomem:
+	mpihelp_release_karatsuba_ctx(&karactx);
 	if (assign_rp)
 		mpi_assign_limb_space(res, rp, size);
 	if (mp_marker)
--- linux-4.4.0.orig/lib/mpi/mpicoder.c
+++ linux-4.4.0/lib/mpi/mpicoder.c
@@ -128,6 +128,23 @@
 }
 EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
 
+static int count_lzeros(MPI a)
+{
+	mpi_limb_t alimb;
+	int i, lzeros = 0;
+
+	for (i = a->nlimbs - 1; i >= 0; i--) {
+		alimb = a->d[i];
+		if (alimb == 0) {
+			lzeros += sizeof(mpi_limb_t);
+		} else {
+			lzeros += count_leading_zeros(alimb) / 8;
+			break;
+		}
+	}
+	return lzeros;
+}
+
 /**
  * mpi_read_buffer() - read MPI to a bufer provided by user (msb first)
  *
@@ -146,7 +163,7 @@
 	uint8_t *p;
 	mpi_limb_t alimb;
 	unsigned int n = mpi_get_size(a);
-	int i, lzeros = 0;
+	int i, lzeros;
 
 	if (buf_len < n || !buf || !nbytes)
 		return -EINVAL;
@@ -154,14 +171,7 @@
 	if (sign)
 		*sign = a->sign;
 
-	p = (void *)&a->d[a->nlimbs] - 1;
-
-	for (i = a->nlimbs * sizeof(alimb) - 1; i >= 0; i--, p--) {
-		if (!*p)
-			lzeros++;
-		else
-			break;
-	}
+	lzeros = count_lzeros(a);
 
 	p = buf;
 	*nbytes = n - lzeros;
@@ -343,7 +353,7 @@
 	u8 *p, *p2;
 	mpi_limb_t alimb, alimb2;
 	unsigned int n = mpi_get_size(a);
-	int i, x, y = 0, lzeros = 0, buf_len;
+	int i, x, y = 0, lzeros, buf_len;
 
 	if (!nbytes || *nbytes < n)
 		return -EINVAL;
@@ -351,20 +361,15 @@
 	if (sign)
 		*sign = a->sign;
 
-	p = (void *)&a->d[a->nlimbs] - 1;
-
-	for (i = a->nlimbs * sizeof(alimb) - 1; i >= 0; i--, p--) {
-		if (!*p)
-			lzeros++;
-		else
-			break;
-	}
+	lzeros = count_lzeros(a);
 
 	*nbytes = n - lzeros;
 	buf_len = sgl->length;
 	p2 = sg_virt(sgl);
 
-	for (i = a->nlimbs - 1; i >= 0; i--) {
+	for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB,
+			lzeros %= BYTES_PER_MPI_LIMB;
+		i >= 0; i--) {
 		alimb = a->d[i];
 		p = (u8 *)&alimb2;
 #if BYTES_PER_MPI_LIMB == 4
@@ -385,17 +390,12 @@
 #error please implement for this limb size.
 #endif
 		if (lzeros > 0) {
-			if (lzeros >= sizeof(alimb)) {
-				p -= sizeof(alimb);
-				continue;
-			} else {
-				mpi_limb_t *limb1 = (void *)p - sizeof(alimb);
-				mpi_limb_t *limb2 = (void *)p - sizeof(alimb)
-							+ lzeros;
-				*limb1 = *limb2;
-				p -= lzeros;
-				y = lzeros;
-			}
+			mpi_limb_t *limb1 = (void *)p - sizeof(alimb);
+			mpi_limb_t *limb2 = (void *)p - sizeof(alimb)
+				+ lzeros;
+			*limb1 = *limb2;
+			p -= lzeros;
+			y = lzeros;
 			lzeros -= sizeof(alimb);
 		}
 
--- linux-4.4.0.orig/lib/oid_registry.c
+++ linux-4.4.0/lib/oid_registry.c
@@ -116,7 +116,7 @@
 	int count;
 
 	if (v >= end)
-		return -EBADMSG;
+		goto bad;
 
 	n = *v++;
 	ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
@@ -134,7 +134,7 @@
 			num = n & 0x7f;
 			do {
 				if (v >= end)
-					return -EBADMSG;
+					goto bad;
 				n = *v++;
 				num <<= 7;
 				num |= n & 0x7f;
@@ -148,6 +148,10 @@
 	}
 
 	return ret;
+
+bad:
+	snprintf(buffer, bufsize, "(bad)");
+	return -EBADMSG;
 }
 EXPORT_SYMBOL_GPL(sprint_oid);
 
--- linux-4.4.0.orig/lib/radix-tree.c
+++ linux-4.4.0/lib/radix-tree.c
@@ -1019,9 +1019,13 @@
 		return 0;
 
 	radix_tree_for_each_slot(slot, root, &iter, first_index) {
-		results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot));
+		results[ret] = rcu_dereference_raw(*slot);
 		if (!results[ret])
 			continue;
+		if (radix_tree_is_indirect_ptr(results[ret])) {
+			slot = radix_tree_iter_retry(&iter);
+			continue;
+		}
 		if (++ret == max_items)
 			break;
 	}
@@ -1098,9 +1102,13 @@
 		return 0;
 
 	radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) {
-		results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot));
+		results[ret] = rcu_dereference_raw(*slot);
 		if (!results[ret])
 			continue;
+		if (radix_tree_is_indirect_ptr(results[ret])) {
+			slot = radix_tree_iter_retry(&iter);
+			continue;
+		}
 		if (++ret == max_items)
 			break;
 	}
--- linux-4.4.0.orig/lib/raid6/Makefile
+++ linux-4.4.0/lib/raid6/Makefile
@@ -23,7 +23,7 @@
 ifeq ($(CONFIG_KERNEL_MODE_NEON),y)
 NEON_FLAGS := -ffreestanding
 ifeq ($(ARCH),arm)
-NEON_FLAGS += -mfloat-abi=softfp -mfpu=neon
+NEON_FLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=neon
 endif
 ifeq ($(ARCH),arm64)
 CFLAGS_REMOVE_neon1.o += -mgeneral-regs-only
--- linux-4.4.0.orig/lib/raid6/altivec.uc
+++ linux-4.4.0/lib/raid6/altivec.uc
@@ -101,6 +101,7 @@
 
 	raid6_altivec$#_gen_syndrome_real(disks, bytes, ptrs);
 
+	disable_kernel_altivec();
 	preempt_enable();
 }
 
--- linux-4.4.0.orig/lib/raid6/test/Makefile
+++ linux-4.4.0/lib/raid6/test/Makefile
@@ -26,7 +26,7 @@
         CFLAGS += -I../../../arch/arm/include -mfpu=neon
         HAS_NEON = yes
 endif
-ifeq ($(ARCH),arm64)
+ifeq ($(ARCH),aarch64)
         CFLAGS += -I../../../arch/arm64/include
         HAS_NEON = yes
 endif
@@ -37,7 +37,7 @@
                     gcc -c -x assembler - >&/dev/null &&	\
                     rm ./-.o && echo -DCONFIG_AS_AVX2=1)
 else ifeq ($(HAS_NEON),yes)
-        OBJS   += neon.o neon1.o neon2.o neon4.o neon8.o
+        OBJS   += neon.o neon1.o neon2.o neon4.o neon8.o recov_neon.o recov_neon_inner.o
         CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1
 else
         HAS_ALTIVEC := $(shell printf '\#include <altivec.h>\nvector int a;\n' |\
--- linux-4.4.0.orig/lib/raid6/unroll.awk
+++ linux-4.4.0/lib/raid6/unroll.awk
@@ -13,7 +13,7 @@
 	for (i = 0; i < rep; ++i) {
 		tmp = $0
 		gsub(/\$\$/, i, tmp)
-		gsub(/\$\#/, n, tmp)
+		gsub(/\$#/, n, tmp)
 		gsub(/\$\*/, "$", tmp)
 		print tmp
 	}
--- linux-4.4.0.orig/lib/random32.c
+++ linux-4.4.0/lib/random32.c
@@ -39,16 +39,6 @@
 #include <linux/sched.h>
 #include <asm/unaligned.h>
 
-#ifdef CONFIG_RANDOM32_SELFTEST
-static void __init prandom_state_selftest(void);
-#else
-static inline void prandom_state_selftest(void)
-{
-}
-#endif
-
-static DEFINE_PER_CPU(struct rnd_state, net_rand_state);
-
 /**
  *	prandom_u32_state - seeded pseudo-random number generator.
  *	@state: pointer to state structure holding seeded state.
@@ -69,25 +59,6 @@
 EXPORT_SYMBOL(prandom_u32_state);
 
 /**
- *	prandom_u32 - pseudo random number generator
- *
- *	A 32 bit pseudo-random number is generated using a fast
- *	algorithm suitable for simulation. This algorithm is NOT
- *	considered safe for cryptographic use.
- */
-u32 prandom_u32(void)
-{
-	struct rnd_state *state = &get_cpu_var(net_rand_state);
-	u32 res;
-
-	res = prandom_u32_state(state);
-	put_cpu_var(state);
-
-	return res;
-}
-EXPORT_SYMBOL(prandom_u32);
-
-/**
  *	prandom_bytes_state - get the requested number of pseudo-random bytes
  *
  *	@state: pointer to state structure holding seeded state.
@@ -118,20 +89,6 @@
 }
 EXPORT_SYMBOL(prandom_bytes_state);
 
-/**
- *	prandom_bytes - get the requested number of pseudo-random bytes
- *	@buf: where to copy the pseudo-random bytes to
- *	@bytes: the requested number of bytes
- */
-void prandom_bytes(void *buf, size_t bytes)
-{
-	struct rnd_state *state = &get_cpu_var(net_rand_state);
-
-	prandom_bytes_state(state, buf, bytes);
-	put_cpu_var(state);
-}
-EXPORT_SYMBOL(prandom_bytes);
-
 static void prandom_warmup(struct rnd_state *state)
 {
 	/* Calling RNG ten times to satisfy recurrence condition */
@@ -147,97 +104,6 @@
 	prandom_u32_state(state);
 }
 
-static u32 __extract_hwseed(void)
-{
-	unsigned int val = 0;
-
-	(void)(arch_get_random_seed_int(&val) ||
-	       arch_get_random_int(&val));
-
-	return val;
-}
-
-static void prandom_seed_early(struct rnd_state *state, u32 seed,
-			       bool mix_with_hwseed)
-{
-#define LCG(x)	 ((x) * 69069U)	/* super-duper LCG */
-#define HWSEED() (mix_with_hwseed ? __extract_hwseed() : 0)
-	state->s1 = __seed(HWSEED() ^ LCG(seed),        2U);
-	state->s2 = __seed(HWSEED() ^ LCG(state->s1),   8U);
-	state->s3 = __seed(HWSEED() ^ LCG(state->s2),  16U);
-	state->s4 = __seed(HWSEED() ^ LCG(state->s3), 128U);
-}
-
-/**
- *	prandom_seed - add entropy to pseudo random number generator
- *	@seed: seed value
- *
- *	Add some additional seeding to the prandom pool.
- */
-void prandom_seed(u32 entropy)
-{
-	int i;
-	/*
-	 * No locking on the CPUs, but then somewhat random results are, well,
-	 * expected.
-	 */
-	for_each_possible_cpu(i) {
-		struct rnd_state *state = &per_cpu(net_rand_state, i);
-
-		state->s1 = __seed(state->s1 ^ entropy, 2U);
-		prandom_warmup(state);
-	}
-}
-EXPORT_SYMBOL(prandom_seed);
-
-/*
- *	Generate some initially weak seeding values to allow
- *	to start the prandom_u32() engine.
- */
-static int __init prandom_init(void)
-{
-	int i;
-
-	prandom_state_selftest();
-
-	for_each_possible_cpu(i) {
-		struct rnd_state *state = &per_cpu(net_rand_state, i);
-		u32 weak_seed = (i + jiffies) ^ random_get_entropy();
-
-		prandom_seed_early(state, weak_seed, true);
-		prandom_warmup(state);
-	}
-
-	return 0;
-}
-core_initcall(prandom_init);
-
-static void __prandom_timer(unsigned long dontcare);
-
-static DEFINE_TIMER(seed_timer, __prandom_timer, 0, 0);
-
-static void __prandom_timer(unsigned long dontcare)
-{
-	u32 entropy;
-	unsigned long expires;
-
-	get_random_bytes(&entropy, sizeof(entropy));
-	prandom_seed(entropy);
-
-	/* reseed every ~60 seconds, in [40 .. 80) interval with slack */
-	expires = 40 + prandom_u32_max(40);
-	seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC);
-
-	add_timer(&seed_timer);
-}
-
-static void __init __prandom_start_seed_timer(void)
-{
-	set_timer_slack(&seed_timer, HZ);
-	seed_timer.expires = jiffies + msecs_to_jiffies(40 * MSEC_PER_SEC);
-	add_timer(&seed_timer);
-}
-
 void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
 {
 	int i;
@@ -256,51 +122,6 @@
 	}
 }
 
-/*
- *	Generate better values after random number generator
- *	is fully initialized.
- */
-static void __prandom_reseed(bool late)
-{
-	unsigned long flags;
-	static bool latch = false;
-	static DEFINE_SPINLOCK(lock);
-
-	/* Asking for random bytes might result in bytes getting
-	 * moved into the nonblocking pool and thus marking it
-	 * as initialized. In this case we would double back into
-	 * this function and attempt to do a late reseed.
-	 * Ignore the pointless attempt to reseed again if we're
-	 * already waiting for bytes when the nonblocking pool
-	 * got initialized.
-	 */
-
-	/* only allow initial seeding (late == false) once */
-	if (!spin_trylock_irqsave(&lock, flags))
-		return;
-
-	if (latch && !late)
-		goto out;
-
-	latch = true;
-	prandom_seed_full_state(&net_rand_state);
-out:
-	spin_unlock_irqrestore(&lock, flags);
-}
-
-void prandom_reseed_late(void)
-{
-	__prandom_reseed(true);
-}
-
-static int __init prandom_reseed(void)
-{
-	__prandom_reseed(false);
-	__prandom_start_seed_timer();
-	return 0;
-}
-late_initcall(prandom_reseed);
-
 #ifdef CONFIG_RANDOM32_SELFTEST
 static struct prandom_test1 {
 	u32 seed;
@@ -420,7 +241,28 @@
 	{  407983964U, 921U,  728767059U },
 };
 
-static void __init prandom_state_selftest(void)
+static u32 __extract_hwseed(void)
+{
+	unsigned int val = 0;
+
+	(void)(arch_get_random_seed_int(&val) ||
+	       arch_get_random_int(&val));
+
+	return val;
+}
+
+static void prandom_seed_early(struct rnd_state *state, u32 seed,
+			       bool mix_with_hwseed)
+{
+#define LCG(x)	 ((x) * 69069U)	/* super-duper LCG */
+#define HWSEED() (mix_with_hwseed ? __extract_hwseed() : 0)
+	state->s1 = __seed(HWSEED() ^ LCG(seed),        2U);
+	state->s2 = __seed(HWSEED() ^ LCG(state->s1),   8U);
+	state->s3 = __seed(HWSEED() ^ LCG(state->s2),  16U);
+	state->s4 = __seed(HWSEED() ^ LCG(state->s3), 128U);
+}
+
+static int __init prandom_state_selftest(void)
 {
 	int i, j, errors = 0, runs = 0;
 	bool error = false;
@@ -460,5 +302,266 @@
 		pr_warn("prandom: %d/%d self tests failed\n", errors, runs);
 	else
 		pr_info("prandom: %d self tests passed\n", runs);
+	return 0;
+}
+core_initcall(prandom_state_selftest);
+#endif
+
+/*
+ * The prandom_u32() implementation is now completely separate from the
+ * prandom_state() functions, which are retained (for now) for compatibility.
+ *
+ * Because of (ab)use in the networking code for choosing random TCP/UDP port
+ * numbers, which open DoS possibilities if guessable, we want something
+ * stronger than a standard PRNG.  But the performance requirements of
+ * the network code do not allow robust crypto for this application.
+ *
+ * So this is a homebrew Junior Spaceman implementation, based on the
+ * lowest-latency trustworthy crypto primitive available, SipHash.
+ * (The authors of SipHash have not been consulted about this abuse of
+ * their work.)
+ *
+ * Standard SipHash-2-4 uses 2n+4 rounds to hash n words of input to
+ * one word of output.  This abbreviated version uses 2 rounds per word
+ * of output.
+ */
+
+struct siprand_state {
+	unsigned long v0;
+	unsigned long v1;
+	unsigned long v2;
+	unsigned long v3;
+};
+
+static DEFINE_PER_CPU(struct siprand_state, net_rand_state);
+
+/*
+ * This is the core CPRNG function.  As "pseudorandom", this is not used
+ * for truly valuable things, just intended to be a PITA to guess.
+ * For maximum speed, we do just two SipHash rounds per word.  This is
+ * the same rate as 4 rounds per 64 bits that SipHash normally uses,
+ * so hopefully it's reasonably secure.
+ *
+ * There are two changes from the official SipHash finalization:
+ * - We omit some constants XORed with v2 in the SipHash spec as irrelevant;
+ *   they are there only to make the output rounds distinct from the input
+ *   rounds, and this application has no input rounds.
+ * - Rather than returning v0^v1^v2^v3, return v1+v3.
+ *   If you look at the SipHash round, the last operation on v3 is
+ *   "v3 ^= v0", so "v0 ^ v3" just undoes that, a waste of time.
+ *   Likewise "v1 ^= v2".  (The rotate of v2 makes a difference, but
+ *   it still cancels out half of the bits in v2 for no benefit.)
+ *   Second, since the last combining operation was xor, continue the
+ *   pattern of alternating xor/add for a tiny bit of extra non-linearity.
+ */
+static inline u32 siprand_u32(struct siprand_state *s)
+{
+	unsigned long v0 = s->v0, v1 = s->v1, v2 = s->v2, v3 = s->v3;
+
+	PRND_SIPROUND(v0, v1, v2, v3);
+	PRND_SIPROUND(v0, v1, v2, v3);
+	s->v0 = v0;  s->v1 = v1;  s->v2 = v2;  s->v3 = v3;
+	return v1 + v3;
+}
+
+
+/**
+ *	prandom_u32 - pseudo random number generator
+ *
+ *	A 32 bit pseudo-random number is generated using a fast
+ *	algorithm suitable for simulation. This algorithm is NOT
+ *	considered safe for cryptographic use.
+ */
+u32 prandom_u32(void)
+{
+	struct siprand_state *state = get_cpu_ptr(&net_rand_state);
+	u32 res = siprand_u32(state);
+
+	put_cpu_ptr(&net_rand_state);
+	return res;
+}
+EXPORT_SYMBOL(prandom_u32);
+
+/**
+ *	prandom_bytes - get the requested number of pseudo-random bytes
+ *	@buf: where to copy the pseudo-random bytes to
+ *	@bytes: the requested number of bytes
+ */
+void prandom_bytes(void *buf, size_t bytes)
+{
+	struct siprand_state *state = get_cpu_ptr(&net_rand_state);
+	u8 *ptr = buf;
+
+	while (bytes >= sizeof(u32)) {
+		put_unaligned(siprand_u32(state), (u32 *)ptr);
+		ptr += sizeof(u32);
+		bytes -= sizeof(u32);
+	}
+
+	if (bytes > 0) {
+		u32 rem = siprand_u32(state);
+
+		do {
+			*ptr++ = (u8)rem;
+			rem >>= BITS_PER_BYTE;
+		} while (--bytes > 0);
+	}
+	put_cpu_ptr(&net_rand_state);
 }
+EXPORT_SYMBOL(prandom_bytes);
+
+/**
+ *	prandom_seed - add entropy to pseudo random number generator
+ *	@entropy: entropy value
+ *
+ *	Add some additional seed material to the prandom pool.
+ *	The "entropy" is actually our IP address (the only caller is
+ *	the network code), not for unpredictability, but to ensure that
+ *	different machines are initialized differently.
+ */
+void prandom_seed(u32 entropy)
+{
+	int i;
+
+	add_device_randomness(&entropy, sizeof(entropy));
+
+	for_each_possible_cpu(i) {
+		struct siprand_state *state = per_cpu_ptr(&net_rand_state, i);
+		unsigned long v0 = state->v0, v1 = state->v1;
+		unsigned long v2 = state->v2, v3 = state->v3;
+
+		do {
+			v3 ^= entropy;
+			PRND_SIPROUND(v0, v1, v2, v3);
+			PRND_SIPROUND(v0, v1, v2, v3);
+			v0 ^= entropy;
+		} while (unlikely(!v0 || !v1 || !v2 || !v3));
+
+		WRITE_ONCE(state->v0, v0);
+		WRITE_ONCE(state->v1, v1);
+		WRITE_ONCE(state->v2, v2);
+		WRITE_ONCE(state->v3, v3);
+	}
+}
+EXPORT_SYMBOL(prandom_seed);
+
+/*
+ *	Generate some initially weak seeding values to allow
+ *	the prandom_u32() engine to be started.
+ */
+static int __init prandom_init_early(void)
+{
+	int i;
+	unsigned long v0, v1, v2, v3;
+
+	if (!arch_get_random_long(&v0))
+		v0 = jiffies;
+	if (!arch_get_random_long(&v1))
+		v1 = random_get_entropy();
+	v2 = v0 ^ PRND_K0;
+	v3 = v1 ^ PRND_K1;
+
+	for_each_possible_cpu(i) {
+		struct siprand_state *state;
+
+		v3 ^= i;
+		PRND_SIPROUND(v0, v1, v2, v3);
+		PRND_SIPROUND(v0, v1, v2, v3);
+		v0 ^= i;
+
+		state = per_cpu_ptr(&net_rand_state, i);
+		state->v0 = v0;  state->v1 = v1;
+		state->v2 = v2;  state->v3 = v3;
+	}
+
+	return 0;
+}
+core_initcall(prandom_init_early);
+
+
+/* Stronger reseeding when available, and periodically thereafter. */
+static void prandom_reseed(unsigned long dontcare);
+
+static DEFINE_TIMER(seed_timer, prandom_reseed, 0, 0);
+
+static void prandom_reseed(unsigned long dontcare)
+{
+	unsigned long expires;
+	int i;
+
+	/*
+	 * Reinitialize each CPU's PRNG with 128 bits of key.
+	 * No locking on the CPUs, but then somewhat random results are,
+	 * well, expected.
+	 */
+	for_each_possible_cpu(i) {
+		struct siprand_state *state;
+		unsigned long v0 = get_random_long(), v2 = v0 ^ PRND_K0;
+		unsigned long v1 = get_random_long(), v3 = v1 ^ PRND_K1;
+#if BITS_PER_LONG == 32
+		int j;
+
+		/*
+		 * On 32-bit machines, hash in two extra words to
+		 * approximate 128-bit key length.  Not that the hash
+		 * has that much security, but this prevents a trivial
+		 * 64-bit brute force.
+		 */
+		for (j = 0; j < 2; j++) {
+			unsigned long m = get_random_long();
+
+			v3 ^= m;
+			PRND_SIPROUND(v0, v1, v2, v3);
+			PRND_SIPROUND(v0, v1, v2, v3);
+			v0 ^= m;
+		}
 #endif
+		/*
+		 * Probably impossible in practice, but there is a
+		 * theoretical risk that a race between this reseeding
+		 * and the target CPU writing its state back could
+		 * create the all-zero SipHash fixed point.
+		 *
+		 * To ensure that never happens, ensure the state
+		 * we write contains no zero words.
+		 */
+		state = per_cpu_ptr(&net_rand_state, i);
+		WRITE_ONCE(state->v0, v0 ? v0 : -1ul);
+		WRITE_ONCE(state->v1, v1 ? v1 : -1ul);
+		WRITE_ONCE(state->v2, v2 ? v2 : -1ul);
+		WRITE_ONCE(state->v3, v3 ? v3 : -1ul);
+	}
+
+	/* reseed every ~60 seconds, in [40 .. 80) interval with slack */
+	expires = round_jiffies(jiffies + 40 * HZ + prandom_u32_max(40 * HZ));
+	mod_timer(&seed_timer, expires);
+}
+
+/*
+ * The random ready callback can be called from almost any interrupt.
+ * To avoid worrying about whether it's safe to delay that interrupt
+ * long enough to seed all CPUs, just schedule an immediate timer event.
+ */
+static void prandom_timer_start(struct random_ready_callback *unused)
+{
+	mod_timer(&seed_timer, jiffies);
+}
+
+/*
+ * Start periodic full reseeding as soon as strong
+ * random numbers are available.
+ */
+static int __init prandom_init_late(void)
+{
+	static struct random_ready_callback random_ready = {
+		.func = prandom_timer_start
+	};
+	int ret = add_random_ready_callback(&random_ready);
+
+	if (ret == -EALREADY) {
+		prandom_timer_start(&random_ready);
+		ret = 0;
+	}
+	return ret;
+}
+late_initcall(prandom_init_late);
--- linux-4.4.0.orig/lib/rbtree.c
+++ linux-4.4.0/lib/rbtree.c
@@ -95,10 +95,14 @@
 
 static __always_inline void
 __rb_insert(struct rb_node *node, struct rb_root *root,
+	    bool newleft, struct rb_node **leftmost,
 	    void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
 {
 	struct rb_node *parent = rb_red_parent(node), *gparent, *tmp;
 
+	if (newleft)
+		*leftmost = node;
+
 	while (true) {
 		/*
 		 * Loop invariant: node is red
@@ -417,19 +421,38 @@
 
 void rb_insert_color(struct rb_node *node, struct rb_root *root)
 {
-	__rb_insert(node, root, dummy_rotate);
+	__rb_insert(node, root, false, NULL, dummy_rotate);
 }
 EXPORT_SYMBOL(rb_insert_color);
 
 void rb_erase(struct rb_node *node, struct rb_root *root)
 {
 	struct rb_node *rebalance;
-	rebalance = __rb_erase_augmented(node, root, &dummy_callbacks);
+	rebalance = __rb_erase_augmented(node, root,
+					 NULL, &dummy_callbacks);
 	if (rebalance)
 		____rb_erase_color(rebalance, root, dummy_rotate);
 }
 EXPORT_SYMBOL(rb_erase);
 
+void rb_insert_color_cached(struct rb_node *node,
+			    struct rb_root_cached *root, bool leftmost)
+{
+	__rb_insert(node, &root->rb_root, leftmost,
+		    &root->rb_leftmost, dummy_rotate);
+}
+EXPORT_SYMBOL(rb_insert_color_cached);
+
+void rb_erase_cached(struct rb_node *node, struct rb_root_cached *root)
+{
+	struct rb_node *rebalance;
+	rebalance = __rb_erase_augmented(node, &root->rb_root,
+					 &root->rb_leftmost, &dummy_callbacks);
+	if (rebalance)
+		____rb_erase_color(rebalance, &root->rb_root, dummy_rotate);
+}
+EXPORT_SYMBOL(rb_erase_cached);
+
 /*
  * Augmented rbtree manipulation functions.
  *
@@ -438,9 +461,10 @@
  */
 
 void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
+			   bool newleft, struct rb_node **leftmost,
 	void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
 {
-	__rb_insert(node, root, augment_rotate);
+	__rb_insert(node, root, newleft, leftmost, augment_rotate);
 }
 EXPORT_SYMBOL(__rb_insert_augmented);
 
@@ -485,7 +509,7 @@
 	 * as we can.
 	 */
 	if (node->rb_right) {
-		node = node->rb_right; 
+		node = node->rb_right;
 		while (node->rb_left)
 			node=node->rb_left;
 		return (struct rb_node *)node;
@@ -517,7 +541,7 @@
 	 * as we can.
 	 */
 	if (node->rb_left) {
-		node = node->rb_left; 
+		node = node->rb_left;
 		while (node->rb_right)
 			node=node->rb_right;
 		return (struct rb_node *)node;
--- linux-4.4.0.orig/lib/rbtree_test.c
+++ linux-4.4.0/lib/rbtree_test.c
@@ -1,11 +1,18 @@
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/rbtree_augmented.h>
 #include <linux/random.h>
+#include <linux/slab.h>
 #include <asm/timex.h>
 
-#define NODES       100
-#define PERF_LOOPS  100000
-#define CHECK_LOOPS 100
+#define __param(type, name, init, msg)		\
+	static type name = init;		\
+	module_param(name, type, 0444);		\
+	MODULE_PARM_DESC(name, msg);
+
+__param(int, nnodes, 100, "Number of nodes in the rb-tree");
+__param(int, perf_loops, 1000, "Number of iterations modifying the rb-tree");
+__param(int, check_loops, 100, "Number of iterations modifying and verifying the rb-tree");
 
 struct test_node {
 	u32 key;
@@ -17,7 +24,7 @@
 };
 
 static struct rb_root root = RB_ROOT;
-static struct test_node nodes[NODES];
+static struct test_node *nodes = NULL;
 
 static struct rnd_state rnd;
 
@@ -95,7 +102,7 @@
 static void init(void)
 {
 	int i;
-	for (i = 0; i < NODES; i++) {
+	for (i = 0; i < nnodes; i++) {
 		nodes[i].key = prandom_u32_state(&rnd);
 		nodes[i].val = prandom_u32_state(&rnd);
 	}
@@ -177,6 +184,10 @@
 	int i, j;
 	cycles_t time1, time2, time;
 
+	nodes = kmalloc(nnodes * sizeof(*nodes), GFP_KERNEL);
+	if (!nodes)
+		return -ENOMEM;
+
 	printk(KERN_ALERT "rbtree testing");
 
 	prandom_seed_state(&rnd, 3141592653589793238ULL);
@@ -184,27 +195,27 @@
 
 	time1 = get_cycles();
 
-	for (i = 0; i < PERF_LOOPS; i++) {
-		for (j = 0; j < NODES; j++)
+	for (i = 0; i < perf_loops; i++) {
+		for (j = 0; j < nnodes; j++)
 			insert(nodes + j, &root);
-		for (j = 0; j < NODES; j++)
+		for (j = 0; j < nnodes; j++)
 			erase(nodes + j, &root);
 	}
 
 	time2 = get_cycles();
 	time = time2 - time1;
 
-	time = div_u64(time, PERF_LOOPS);
+	time = div_u64(time, perf_loops);
 	printk(" -> %llu cycles\n", (unsigned long long)time);
 
-	for (i = 0; i < CHECK_LOOPS; i++) {
+	for (i = 0; i < check_loops; i++) {
 		init();
-		for (j = 0; j < NODES; j++) {
+		for (j = 0; j < nnodes; j++) {
 			check(j);
 			insert(nodes + j, &root);
 		}
-		for (j = 0; j < NODES; j++) {
-			check(NODES - j);
+		for (j = 0; j < nnodes; j++) {
+			check(nnodes - j);
 			erase(nodes + j, &root);
 		}
 		check(0);
@@ -216,32 +227,34 @@
 
 	time1 = get_cycles();
 
-	for (i = 0; i < PERF_LOOPS; i++) {
-		for (j = 0; j < NODES; j++)
+	for (i = 0; i < perf_loops; i++) {
+		for (j = 0; j < nnodes; j++)
 			insert_augmented(nodes + j, &root);
-		for (j = 0; j < NODES; j++)
+		for (j = 0; j < nnodes; j++)
 			erase_augmented(nodes + j, &root);
 	}
 
 	time2 = get_cycles();
 	time = time2 - time1;
 
-	time = div_u64(time, PERF_LOOPS);
+	time = div_u64(time, perf_loops);
 	printk(" -> %llu cycles\n", (unsigned long long)time);
 
-	for (i = 0; i < CHECK_LOOPS; i++) {
+	for (i = 0; i < check_loops; i++) {
 		init();
-		for (j = 0; j < NODES; j++) {
+		for (j = 0; j < nnodes; j++) {
 			check_augmented(j);
 			insert_augmented(nodes + j, &root);
 		}
-		for (j = 0; j < NODES; j++) {
-			check_augmented(NODES - j);
+		for (j = 0; j < nnodes; j++) {
+			check_augmented(nnodes - j);
 			erase_augmented(nodes + j, &root);
 		}
 		check_augmented(0);
 	}
 
+	kfree(nodes);
+
 	return -EAGAIN; /* Fail will directly unload the module */
 }
 
--- linux-4.4.0.orig/lib/reed_solomon/decode_rs.c
+++ linux-4.4.0/lib/reed_solomon/decode_rs.c
@@ -42,8 +42,18 @@
 	BUG_ON(pad < 0 || pad >= nn);
 
 	/* Does the caller provide the syndrome ? */
-	if (s != NULL)
-		goto decode;
+	if (s != NULL) {
+		for (i = 0; i < nroots; i++) {
+			/* The syndrome is in index form,
+			 * so nn represents zero
+			 */
+			if (s[i] != nn)
+				goto decode;
+		}
+
+		/* syndrome is zero, no errors to correct  */
+		return 0;
+	}
 
 	/* form the syndromes; i.e., evaluate data(x) at roots of
 	 * g(x) */
@@ -99,9 +109,9 @@
 	if (no_eras > 0) {
 		/* Init lambda to be the erasure locator polynomial */
 		lambda[1] = alpha_to[rs_modnn(rs,
-					      prim * (nn - 1 - eras_pos[0]))];
+					prim * (nn - 1 - (eras_pos[0] + pad)))];
 		for (i = 1; i < no_eras; i++) {
-			u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
+			u = rs_modnn(rs, prim * (nn - 1 - (eras_pos[i] + pad)));
 			for (j = i + 1; j > 0; j--) {
 				tmp = index_of[lambda[j - 1]];
 				if (tmp != nn) {
--- linux-4.4.0.orig/lib/rhashtable.c
+++ linux-4.4.0/lib/rhashtable.c
@@ -250,8 +250,10 @@
 	if (!new_tbl)
 		return 0;
 
-	for (old_hash = 0; old_hash < old_tbl->size; old_hash++)
+	for (old_hash = 0; old_hash < old_tbl->size; old_hash++) {
 		rhashtable_rehash_chain(ht, old_hash);
+		cond_resched();
+	}
 
 	/* Publish the new table pointer. */
 	rcu_assign_pointer(ht->tbl, new_tbl);
@@ -441,7 +443,8 @@
 struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
 					    const void *key,
 					    struct rhash_head *obj,
-					    struct bucket_table *tbl)
+					    struct bucket_table *tbl,
+					    void **data)
 {
 	struct rhash_head *head;
 	unsigned int hash;
@@ -452,8 +455,11 @@
 	spin_lock_nested(rht_bucket_lock(tbl, hash), SINGLE_DEPTH_NESTING);
 
 	err = -EEXIST;
-	if (key && rhashtable_lookup_fast(ht, key, ht->p))
-		goto exit;
+	if (key) {
+		*data = rhashtable_lookup_fast(ht, key, ht->p);
+		if (*data)
+			goto exit;
+	}
 
 	err = -E2BIG;
 	if (unlikely(rht_grow_above_max(ht, tbl)))
@@ -670,8 +676,16 @@
 
 static size_t rounded_hashtable_size(const struct rhashtable_params *params)
 {
-	return max(roundup_pow_of_two(params->nelem_hint * 4 / 3),
-		   (unsigned long)params->min_size);
+	size_t retsize;
+
+	if (params->nelem_hint)
+		retsize = max(roundup_pow_of_two(params->nelem_hint * 4 / 3),
+			      (unsigned long)params->min_size);
+	else
+		retsize = max(HASH_DEFAULT_SIZE,
+			      (unsigned long)params->min_size);
+
+	return retsize;
 }
 
 static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
@@ -728,8 +742,6 @@
 	struct bucket_table *tbl;
 	size_t size;
 
-	size = HASH_DEFAULT_SIZE;
-
 	if ((!params->key_len && !params->obj_hashfn) ||
 	    (params->obj_hashfn && !params->obj_cmpfn))
 		return -EINVAL;
@@ -756,8 +768,7 @@
 
 	ht->p.min_size = max(ht->p.min_size, HASH_MIN_SIZE);
 
-	if (params->nelem_hint)
-		size = rounded_hashtable_size(&ht->p);
+	size = rounded_hashtable_size(&ht->p);
 
 	/* The maximum (not average) chain length grows with the
 	 * size of the hash table, at a rate of (log N)/(log log N).
@@ -833,6 +844,7 @@
 		for (i = 0; i < tbl->size; i++) {
 			struct rhash_head *pos, *next;
 
+			cond_resched();
 			for (pos = rht_dereference(tbl->buckets[i], ht),
 			     next = !rht_is_a_nulls(pos) ?
 					rht_dereference(pos->next, ht) : NULL;
--- linux-4.4.0.orig/lib/scatterlist.c
+++ linux-4.4.0/lib/scatterlist.c
@@ -317,7 +317,7 @@
 			if (prv)
 				table->nents = ++table->orig_nents;
 
- 			return -ENOMEM;
+			return -ENOMEM;
 		}
 
 		sg_init_table(sg, alloc_size);
@@ -496,17 +496,18 @@
 {
 	if (!miter->__remaining) {
 		struct scatterlist *sg;
-		unsigned long pgoffset;
 
 		if (!__sg_page_iter_next(&miter->piter))
 			return false;
 
 		sg = miter->piter.sg;
-		pgoffset = miter->piter.sg_pgoffset;
 
-		miter->__offset = pgoffset ? 0 : sg->offset;
+		miter->__offset = miter->piter.sg_pgoffset ? 0 : sg->offset;
+		miter->piter.sg_pgoffset += miter->__offset >> PAGE_SHIFT;
+		miter->__offset &= PAGE_SIZE - 1;
 		miter->__remaining = sg->offset + sg->length -
-				(pgoffset << PAGE_SHIFT) - miter->__offset;
+				     (miter->piter.sg_pgoffset << PAGE_SHIFT) -
+				     miter->__offset;
 		miter->__remaining = min_t(unsigned long, miter->__remaining,
 					   PAGE_SIZE - miter->__offset);
 	}
--- linux-4.4.0.orig/lib/seq_buf.c
+++ linux-4.4.0/lib/seq_buf.c
@@ -143,9 +143,13 @@
 
 	WARN_ON(s->size == 0);
 
+	/* Add 1 to len for the trailing null byte which must be there */
+	len += 1;
+
 	if (seq_buf_can_fit(s, len)) {
 		memcpy(s->buffer + s->len, str, len);
-		s->len += len;
+		/* Don't count the trailing null byte against the capacity */
+		s->len += len - 1;
 		return 0;
 	}
 	seq_buf_set_overflow(s);
--- linux-4.4.0.orig/lib/siphash.c
+++ linux-4.4.0/lib/siphash.c
@@ -0,0 +1,551 @@
+/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.
+ *
+ * SipHash: a fast short-input PRF
+ * https://131002.net/siphash/
+ *
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
+ */
+
+#include <linux/siphash.h>
+#include <asm/unaligned.h>
+
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+#include <linux/dcache.h>
+#include <asm/word-at-a-time.h>
+#endif
+
+#define SIPROUND \
+	do { \
+	v0 += v1; v1 = rol64(v1, 13); v1 ^= v0; v0 = rol64(v0, 32); \
+	v2 += v3; v3 = rol64(v3, 16); v3 ^= v2; \
+	v0 += v3; v3 = rol64(v3, 21); v3 ^= v0; \
+	v2 += v1; v1 = rol64(v1, 17); v1 ^= v2; v2 = rol64(v2, 32); \
+	} while (0)
+
+#define PREAMBLE(len) \
+	u64 v0 = 0x736f6d6570736575ULL; \
+	u64 v1 = 0x646f72616e646f6dULL; \
+	u64 v2 = 0x6c7967656e657261ULL; \
+	u64 v3 = 0x7465646279746573ULL; \
+	u64 b = ((u64)(len)) << 56; \
+	v3 ^= key->key[1]; \
+	v2 ^= key->key[0]; \
+	v1 ^= key->key[1]; \
+	v0 ^= key->key[0];
+
+#define POSTAMBLE \
+	v3 ^= b; \
+	SIPROUND; \
+	SIPROUND; \
+	v0 ^= b; \
+	v2 ^= 0xff; \
+	SIPROUND; \
+	SIPROUND; \
+	SIPROUND; \
+	SIPROUND; \
+	return (v0 ^ v1) ^ (v2 ^ v3);
+
+u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key)
+{
+	const u8 *end = data + len - (len % sizeof(u64));
+	const u8 left = len & (sizeof(u64) - 1);
+	u64 m;
+	PREAMBLE(len)
+	for (; data != end; data += sizeof(u64)) {
+		m = le64_to_cpup(data);
+		v3 ^= m;
+		SIPROUND;
+		SIPROUND;
+		v0 ^= m;
+	}
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+	if (left)
+		b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+						  bytemask_from_count(left)));
+#else
+	switch (left) {
+	case 7: b |= ((u64)end[6]) << 48;
+	case 6: b |= ((u64)end[5]) << 40;
+	case 5: b |= ((u64)end[4]) << 32;
+	case 4: b |= le32_to_cpup(data); break;
+	case 3: b |= ((u64)end[2]) << 16;
+	case 2: b |= le16_to_cpup(data); break;
+	case 1: b |= end[0];
+	}
+#endif
+	POSTAMBLE
+}
+EXPORT_SYMBOL(__siphash_aligned);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key)
+{
+	const u8 *end = data + len - (len % sizeof(u64));
+	const u8 left = len & (sizeof(u64) - 1);
+	u64 m;
+	PREAMBLE(len)
+	for (; data != end; data += sizeof(u64)) {
+		m = get_unaligned_le64(data);
+		v3 ^= m;
+		SIPROUND;
+		SIPROUND;
+		v0 ^= m;
+	}
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+	if (left)
+		b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+						  bytemask_from_count(left)));
+#else
+	switch (left) {
+	case 7: b |= ((u64)end[6]) << 48;
+	case 6: b |= ((u64)end[5]) << 40;
+	case 5: b |= ((u64)end[4]) << 32;
+	case 4: b |= get_unaligned_le32(end); break;
+	case 3: b |= ((u64)end[2]) << 16;
+	case 2: b |= get_unaligned_le16(end); break;
+	case 1: b |= end[0];
+	}
+#endif
+	POSTAMBLE
+}
+EXPORT_SYMBOL(__siphash_unaligned);
+#endif
+
+/**
+ * siphash_1u64 - compute 64-bit siphash PRF value of a u64
+ * @first: first u64
+ * @key: the siphash key
+ */
+u64 siphash_1u64(const u64 first, const siphash_key_t *key)
+{
+	PREAMBLE(8)
+	v3 ^= first;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= first;
+	POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_1u64);
+
+/**
+ * siphash_2u64 - compute 64-bit siphash PRF value of 2 u64
+ * @first: first u64
+ * @second: second u64
+ * @key: the siphash key
+ */
+u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key)
+{
+	PREAMBLE(16)
+	v3 ^= first;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= first;
+	v3 ^= second;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= second;
+	POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_2u64);
+
+/**
+ * siphash_3u64 - compute 64-bit siphash PRF value of 3 u64
+ * @first: first u64
+ * @second: second u64
+ * @third: third u64
+ * @key: the siphash key
+ */
+u64 siphash_3u64(const u64 first, const u64 second, const u64 third,
+		 const siphash_key_t *key)
+{
+	PREAMBLE(24)
+	v3 ^= first;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= first;
+	v3 ^= second;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= second;
+	v3 ^= third;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= third;
+	POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_3u64);
+
+/**
+ * siphash_4u64 - compute 64-bit siphash PRF value of 4 u64
+ * @first: first u64
+ * @second: second u64
+ * @third: third u64
+ * @forth: forth u64
+ * @key: the siphash key
+ */
+u64 siphash_4u64(const u64 first, const u64 second, const u64 third,
+		 const u64 forth, const siphash_key_t *key)
+{
+	PREAMBLE(32)
+	v3 ^= first;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= first;
+	v3 ^= second;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= second;
+	v3 ^= third;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= third;
+	v3 ^= forth;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= forth;
+	POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_4u64);
+
+u64 siphash_1u32(const u32 first, const siphash_key_t *key)
+{
+	PREAMBLE(4)
+	b |= first;
+	POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_1u32);
+
+u64 siphash_3u32(const u32 first, const u32 second, const u32 third,
+		 const siphash_key_t *key)
+{
+	u64 combined = (u64)second << 32 | first;
+	PREAMBLE(12)
+	v3 ^= combined;
+	SIPROUND;
+	SIPROUND;
+	v0 ^= combined;
+	b |= third;
+	POSTAMBLE
+}
+EXPORT_SYMBOL(siphash_3u32);
+
+#if BITS_PER_LONG == 64
+/* Note that on 64-bit, we make HalfSipHash1-3 actually be SipHash1-3, for
+ * performance reasons. On 32-bit, below, we actually implement HalfSipHash1-3.
+ */
+
+#define HSIPROUND SIPROUND
+#define HPREAMBLE(len) PREAMBLE(len)
+#define HPOSTAMBLE \
+	v3 ^= b; \
+	HSIPROUND; \
+	v0 ^= b; \
+	v2 ^= 0xff; \
+	HSIPROUND; \
+	HSIPROUND; \
+	HSIPROUND; \
+	return (v0 ^ v1) ^ (v2 ^ v3);
+
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
+{
+	const u8 *end = data + len - (len % sizeof(u64));
+	const u8 left = len & (sizeof(u64) - 1);
+	u64 m;
+	HPREAMBLE(len)
+	for (; data != end; data += sizeof(u64)) {
+		m = le64_to_cpup(data);
+		v3 ^= m;
+		HSIPROUND;
+		v0 ^= m;
+	}
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+	if (left)
+		b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+						  bytemask_from_count(left)));
+#else
+	switch (left) {
+	case 7: b |= ((u64)end[6]) << 48;
+	case 6: b |= ((u64)end[5]) << 40;
+	case 5: b |= ((u64)end[4]) << 32;
+	case 4: b |= le32_to_cpup(data); break;
+	case 3: b |= ((u64)end[2]) << 16;
+	case 2: b |= le16_to_cpup(data); break;
+	case 1: b |= end[0];
+	}
+#endif
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_aligned);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len,
+			 const hsiphash_key_t *key)
+{
+	const u8 *end = data + len - (len % sizeof(u64));
+	const u8 left = len & (sizeof(u64) - 1);
+	u64 m;
+	HPREAMBLE(len)
+	for (; data != end; data += sizeof(u64)) {
+		m = get_unaligned_le64(data);
+		v3 ^= m;
+		HSIPROUND;
+		v0 ^= m;
+	}
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+	if (left)
+		b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+						  bytemask_from_count(left)));
+#else
+	switch (left) {
+	case 7: b |= ((u64)end[6]) << 48;
+	case 6: b |= ((u64)end[5]) << 40;
+	case 5: b |= ((u64)end[4]) << 32;
+	case 4: b |= get_unaligned_le32(end); break;
+	case 3: b |= ((u64)end[2]) << 16;
+	case 2: b |= get_unaligned_le16(end); break;
+	case 1: b |= end[0];
+	}
+#endif
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_unaligned);
+#endif
+
+/**
+ * hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32
+ * @first: first u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key)
+{
+	HPREAMBLE(4)
+	b |= first;
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_1u32);
+
+/**
+ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
+ * @first: first u32
+ * @second: second u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key)
+{
+	u64 combined = (u64)second << 32 | first;
+	HPREAMBLE(8)
+	v3 ^= combined;
+	HSIPROUND;
+	v0 ^= combined;
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_2u32);
+
+/**
+ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
+		  const hsiphash_key_t *key)
+{
+	u64 combined = (u64)second << 32 | first;
+	HPREAMBLE(12)
+	v3 ^= combined;
+	HSIPROUND;
+	v0 ^= combined;
+	b |= third;
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_3u32);
+
+/**
+ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @forth: forth u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
+		  const u32 forth, const hsiphash_key_t *key)
+{
+	u64 combined = (u64)second << 32 | first;
+	HPREAMBLE(16)
+	v3 ^= combined;
+	HSIPROUND;
+	v0 ^= combined;
+	combined = (u64)forth << 32 | third;
+	v3 ^= combined;
+	HSIPROUND;
+	v0 ^= combined;
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_4u32);
+#else
+#define HSIPROUND \
+	do { \
+	v0 += v1; v1 = rol32(v1, 5); v1 ^= v0; v0 = rol32(v0, 16); \
+	v2 += v3; v3 = rol32(v3, 8); v3 ^= v2; \
+	v0 += v3; v3 = rol32(v3, 7); v3 ^= v0; \
+	v2 += v1; v1 = rol32(v1, 13); v1 ^= v2; v2 = rol32(v2, 16); \
+	} while (0)
+
+#define HPREAMBLE(len) \
+	u32 v0 = 0; \
+	u32 v1 = 0; \
+	u32 v2 = 0x6c796765U; \
+	u32 v3 = 0x74656462U; \
+	u32 b = ((u32)(len)) << 24; \
+	v3 ^= key->key[1]; \
+	v2 ^= key->key[0]; \
+	v1 ^= key->key[1]; \
+	v0 ^= key->key[0];
+
+#define HPOSTAMBLE \
+	v3 ^= b; \
+	HSIPROUND; \
+	v0 ^= b; \
+	v2 ^= 0xff; \
+	HSIPROUND; \
+	HSIPROUND; \
+	HSIPROUND; \
+	return v1 ^ v3;
+
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
+{
+	const u8 *end = data + len - (len % sizeof(u32));
+	const u8 left = len & (sizeof(u32) - 1);
+	u32 m;
+	HPREAMBLE(len)
+	for (; data != end; data += sizeof(u32)) {
+		m = le32_to_cpup(data);
+		v3 ^= m;
+		HSIPROUND;
+		v0 ^= m;
+	}
+	switch (left) {
+	case 3: b |= ((u32)end[2]) << 16;
+	case 2: b |= le16_to_cpup(data); break;
+	case 1: b |= end[0];
+	}
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_aligned);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len,
+			 const hsiphash_key_t *key)
+{
+	const u8 *end = data + len - (len % sizeof(u32));
+	const u8 left = len & (sizeof(u32) - 1);
+	u32 m;
+	HPREAMBLE(len)
+	for (; data != end; data += sizeof(u32)) {
+		m = get_unaligned_le32(data);
+		v3 ^= m;
+		HSIPROUND;
+		v0 ^= m;
+	}
+	switch (left) {
+	case 3: b |= ((u32)end[2]) << 16;
+	case 2: b |= get_unaligned_le16(end); break;
+	case 1: b |= end[0];
+	}
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_unaligned);
+#endif
+
+/**
+ * hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32
+ * @first: first u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key)
+{
+	HPREAMBLE(4)
+	v3 ^= first;
+	HSIPROUND;
+	v0 ^= first;
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_1u32);
+
+/**
+ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
+ * @first: first u32
+ * @second: second u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key)
+{
+	HPREAMBLE(8)
+	v3 ^= first;
+	HSIPROUND;
+	v0 ^= first;
+	v3 ^= second;
+	HSIPROUND;
+	v0 ^= second;
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_2u32);
+
+/**
+ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
+		  const hsiphash_key_t *key)
+{
+	HPREAMBLE(12)
+	v3 ^= first;
+	HSIPROUND;
+	v0 ^= first;
+	v3 ^= second;
+	HSIPROUND;
+	v0 ^= second;
+	v3 ^= third;
+	HSIPROUND;
+	v0 ^= third;
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_3u32);
+
+/**
+ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @forth: forth u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
+		  const u32 forth, const hsiphash_key_t *key)
+{
+	HPREAMBLE(16)
+	v3 ^= first;
+	HSIPROUND;
+	v0 ^= first;
+	v3 ^= second;
+	HSIPROUND;
+	v0 ^= second;
+	v3 ^= third;
+	HSIPROUND;
+	v0 ^= third;
+	v3 ^= forth;
+	HSIPROUND;
+	v0 ^= forth;
+	HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_4u32);
+#endif
--- linux-4.4.0.orig/lib/string.c
+++ linux-4.4.0/lib/string.c
@@ -157,11 +157,9 @@
  * @src: Where to copy the string from
  * @count: Size of destination buffer
  *
- * Copy the string, or as much of it as fits, into the dest buffer.
- * The routine returns the number of characters copied (not including
- * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough.
- * The behavior is undefined if the string buffers overlap.
- * The destination buffer is always NUL terminated, unless it's zero-sized.
+ * Copy the string, or as much of it as fits, into the dest buffer.  The
+ * behavior is undefined if the string buffers overlap.  The destination
+ * buffer is always NUL terminated, unless it's zero-sized.
  *
  * Preferred to strlcpy() since the API doesn't require reading memory
  * from the src string beyond the specified "count" bytes, and since
@@ -171,8 +169,10 @@
  *
  * Preferred to strncpy() since it always returns a valid string, and
  * doesn't unnecessarily force the tail of the destination buffer to be
- * zeroed.  If the zeroing is desired, it's likely cleaner to use strscpy()
- * with an overflow test, then just memset() the tail of the dest buffer.
+ * zeroed.  If zeroing is desired please use strscpy_pad().
+ *
+ * Return: The number of characters copied (not including the trailing
+ *         %NUL) or -E2BIG if the destination buffer wasn't big enough.
  */
 ssize_t strscpy(char *dest, const char *src, size_t count)
 {
@@ -202,7 +202,7 @@
 	while (max >= sizeof(unsigned long)) {
 		unsigned long c, data;
 
-		c = *(unsigned long *)(src+res);
+		c = read_word_at_a_time(src+res);
 		if (has_zero(c, &data, &constants)) {
 			data = prep_zero_mask(c, data, &constants);
 			data = create_zero_mask(data);
@@ -235,6 +235,63 @@
 EXPORT_SYMBOL(strscpy);
 #endif
 
+/**
+ * stpcpy - copy a string from src to dest returning a pointer to the new end
+ *          of dest, including src's %NUL-terminator. May overrun dest.
+ * @dest: pointer to end of string being copied into. Must be large enough
+ *        to receive copy.
+ * @src: pointer to the beginning of string being copied from. Must not overlap
+ *       dest.
+ *
+ * stpcpy differs from strcpy in a key way: the return value is a pointer
+ * to the new %NUL-terminating character in @dest. (For strcpy, the return
+ * value is a pointer to the start of @dest). This interface is considered
+ * unsafe as it doesn't perform bounds checking of the inputs. As such it's
+ * not recommended for usage. Instead, its definition is provided in case
+ * the compiler lowers other libcalls to stpcpy.
+ */
+char *stpcpy(char *__restrict__ dest, const char *__restrict__ src);
+char *stpcpy(char *__restrict__ dest, const char *__restrict__ src)
+{
+	while ((*dest++ = *src++) != '\0')
+		/* nothing */;
+	return --dest;
+}
+EXPORT_SYMBOL(stpcpy);
+
+/**
+ * strscpy_pad() - Copy a C-string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: Size of destination buffer
+ *
+ * Copy the string, or as much of it as fits, into the dest buffer.  The
+ * behavior is undefined if the string buffers overlap.  The destination
+ * buffer is always %NUL terminated, unless it's zero-sized.
+ *
+ * If the source string is shorter than the destination buffer, zeros
+ * the tail of the destination buffer.
+ *
+ * For full explanation of why you may want to consider using the
+ * 'strscpy' functions please see the function docstring for strscpy().
+ *
+ * Return: The number of characters copied (not including the trailing
+ *         %NUL) or -E2BIG if the destination buffer wasn't big enough.
+ */
+ssize_t strscpy_pad(char *dest, const char *src, size_t count)
+{
+	ssize_t written;
+
+	written = strscpy(dest, src, count);
+	if (written < 0 || written == count - 1)
+		return written;
+
+	memset(dest + written + 1, 0, count - written - 1);
+
+	return written;
+}
+EXPORT_SYMBOL(strscpy_pad);
+
 #ifndef __HAVE_ARCH_STRCAT
 /**
  * strcat - Append one %NUL-terminated string to another
@@ -630,35 +687,6 @@
 }
 EXPORT_SYMBOL(sysfs_streq);
 
-/**
- * strtobool - convert common user inputs into boolean values
- * @s: input string
- * @res: result
- *
- * This routine returns 0 iff the first character is one of 'Yy1Nn0'.
- * Otherwise it will return -EINVAL.  Value pointed to by res is
- * updated upon finding a match.
- */
-int strtobool(const char *s, bool *res)
-{
-	switch (s[0]) {
-	case 'y':
-	case 'Y':
-	case '1':
-		*res = true;
-		break;
-	case 'n':
-	case 'N':
-	case '0':
-		*res = false;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-EXPORT_SYMBOL(strtobool);
-
 #ifndef __HAVE_ARCH_MEMSET
 /**
  * memset - Fill a region of memory with the given value
@@ -775,6 +803,26 @@
 EXPORT_SYMBOL(memcmp);
 #endif
 
+#ifndef __HAVE_ARCH_BCMP
+/**
+ * bcmp - returns 0 if and only if the buffers have identical contents.
+ * @a: pointer to first buffer.
+ * @b: pointer to second buffer.
+ * @len: size of buffers.
+ *
+ * The sign or magnitude of a non-zero return value has no particular
+ * meaning, and architectures may implement their own more efficient bcmp(). So
+ * while this particular implementation is a simple (tail) call to memcmp, do
+ * not rely on anything but whether the return value is zero or non-zero.
+ */
+#undef bcmp
+int bcmp(const void *a, const void *b, size_t len)
+{
+	return memcmp(a, b, len);
+}
+EXPORT_SYMBOL(bcmp);
+#endif
+
 #ifndef __HAVE_ARCH_MEMSCAN
 /**
  * memscan - Find a character in an area of memory.
--- linux-4.4.0.orig/lib/string_helpers.c
+++ linux-4.4.0/lib/string_helpers.c
@@ -43,50 +43,73 @@
 		[STRING_UNITS_10] = 1000,
 		[STRING_UNITS_2] = 1024,
 	};
-	int i, j;
-	u32 remainder = 0, sf_cap, exp;
+	static const unsigned int rounding[] = { 500, 50, 5 };
+	int i = 0, j;
+	u32 remainder = 0, sf_cap;
 	char tmp[8];
 	const char *unit;
 
 	tmp[0] = '\0';
-	i = 0;
-	if (!size)
+
+	if (blk_size == 0)
+		size = 0;
+	if (size == 0)
 		goto out;
 
-	while (blk_size >= divisor[units]) {
-		remainder = do_div(blk_size, divisor[units]);
+	/* This is Napier's algorithm.  Reduce the original block size to
+	 *
+	 * coefficient * divisor[units]^i
+	 *
+	 * we do the reduction so both coefficients are just under 32 bits so
+	 * that multiplying them together won't overflow 64 bits and we keep
+	 * as much precision as possible in the numbers.
+	 *
+	 * Note: it's safe to throw away the remainders here because all the
+	 * precision is in the coefficients.
+	 */
+	while (blk_size >> 32) {
+		do_div(blk_size, divisor[units]);
 		i++;
 	}
 
-	exp = divisor[units] / (u32)blk_size;
-	/*
-	 * size must be strictly greater than exp here to ensure that remainder
-	 * is greater than divisor[units] coming out of the if below.
-	 */
-	if (size > exp) {
-		remainder = do_div(size, divisor[units]);
-		remainder *= blk_size;
+	while (size >> 32) {
+		do_div(size, divisor[units]);
 		i++;
-	} else {
-		remainder *= size;
 	}
 
+	/* now perform the actual multiplication keeping i as the sum of the
+	 * two logarithms */
 	size *= blk_size;
-	size += remainder / divisor[units];
-	remainder %= divisor[units];
 
+	/* and logarithmically reduce it until it's just under the divisor */
 	while (size >= divisor[units]) {
 		remainder = do_div(size, divisor[units]);
 		i++;
 	}
 
+	/* work out in j how many digits of precision we need from the
+	 * remainder */
 	sf_cap = size;
 	for (j = 0; sf_cap*10 < 1000; j++)
 		sf_cap *= 10;
 
-	if (j) {
+	if (units == STRING_UNITS_2) {
+		/* express the remainder as a decimal.  It's currently the
+		 * numerator of a fraction whose denominator is
+		 * divisor[units], which is 1 << 10 for STRING_UNITS_2 */
 		remainder *= 1000;
-		remainder /= divisor[units];
+		remainder >>= 10;
+	}
+
+	/* add a 5 to the digit below what will be printed to ensure
+	 * an arithmetical round up and carry it through to size */
+	remainder += rounding[j];
+	if (remainder >= 1000) {
+		remainder -= 1000;
+		size += 1;
+	}
+
+	if (j) {
 		snprintf(tmp, sizeof(tmp), ".%03u", remainder);
 		tmp[j+1] = '\0';
 	}
--- linux-4.4.0.orig/lib/strncpy_from_user.c
+++ linux-4.4.0/lib/strncpy_from_user.c
@@ -20,10 +20,11 @@
  * hit it), 'max' is the address space maximum (and we return
  * -EFAULT if we hit it).
  */
-static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
+static inline long do_strncpy_from_user(char *dst, const char __user *src,
+					unsigned long count, unsigned long max)
 {
 	const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
-	long res = 0;
+	unsigned long res = 0;
 
 	/*
 	 * Truncate 'max' to the user-specified limit, so that
--- linux-4.4.0.orig/lib/strnlen_user.c
+++ linux-4.4.0/lib/strnlen_user.c
@@ -27,7 +27,7 @@
 static inline long do_strnlen_user(const char __user *src, unsigned long count, unsigned long max)
 {
 	const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
-	long align, res = 0;
+	unsigned long align, res = 0;
 	unsigned long c;
 
 	/*
@@ -41,7 +41,7 @@
 	 * Do everything aligned. But that means that we
 	 * need to also expand the maximum..
 	 */
-	align = (sizeof(long) - 1) & (unsigned long)src;
+	align = (sizeof(unsigned long) - 1) & (unsigned long)src;
 	src -= align;
 	max += align;
 
--- linux-4.4.0.orig/lib/swiotlb.c
+++ linux-4.4.0/lib/swiotlb.c
@@ -17,6 +17,8 @@
  * 08/12/11 beckyb	Add highmem support
  */
 
+#define pr_fmt(fmt) "software IO TLB: " fmt
+
 #include <linux/cache.h>
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
@@ -143,20 +145,16 @@
 void swiotlb_print_info(void)
 {
 	unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT;
-	unsigned char *vstart, *vend;
 
 	if (no_iotlb_memory) {
-		pr_warn("software IO TLB: No low mem\n");
+		pr_warn("No low mem\n");
 		return;
 	}
 
-	vstart = phys_to_virt(io_tlb_start);
-	vend = phys_to_virt(io_tlb_end);
-
-	printk(KERN_INFO "software IO TLB [mem %#010llx-%#010llx] (%luMB) mapped at [%p-%p]\n",
+	pr_info("mapped [mem %#010llx-%#010llx] (%luMB)\n",
 	       (unsigned long long)io_tlb_start,
 	       (unsigned long long)io_tlb_end,
-	       bytes >> 20, vstart, vend - 1);
+	       bytes >> 20);
 }
 
 int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
@@ -197,6 +195,7 @@
 		io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
 	}
 	io_tlb_index = 0;
+	no_iotlb_memory = false;
 
 	if (verbose)
 		swiotlb_print_info();
@@ -227,10 +226,12 @@
 	if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose))
 		return;
 
-	if (io_tlb_start)
+	if (io_tlb_start) {
 		memblock_free_early(io_tlb_start,
 				    PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
-	pr_warn("Cannot allocate SWIOTLB buffer");
+		io_tlb_start = 0;
+	}
+	pr_warn("Cannot allocate buffer");
 	no_iotlb_memory = true;
 }
 
@@ -272,8 +273,8 @@
 		return -ENOMEM;
 	}
 	if (order != get_order(bytes)) {
-		printk(KERN_WARNING "Warning: only able to allocate %ld MB "
-		       "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
+		pr_warn("only able to allocate %ld MB\n",
+			(PAGE_SIZE << order) >> 20);
 		io_tlb_nslabs = SLABS_PER_PAGE << order;
 	}
 	rc = swiotlb_late_init_with_tbl(vstart, io_tlb_nslabs);
@@ -328,6 +329,7 @@
 		io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
 	}
 	io_tlb_index = 0;
+	no_iotlb_memory = false;
 
 	swiotlb_print_info();
 
@@ -452,11 +454,11 @@
 		    : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
 
 	/*
-	 * For mappings greater than a page, we limit the stride (and
-	 * hence alignment) to a page size.
+	 * For mappings greater than or equal to a page, we limit the stride
+	 * (and hence alignment) to a page size.
 	 */
 	nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
-	if (size > PAGE_SIZE)
+	if (size >= PAGE_SIZE)
 		stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
 	else
 		stride = 1;
@@ -680,7 +682,7 @@
 	return ret;
 
 err_warn:
-	pr_warn("swiotlb: coherent allocation failed for device %s size=%zu\n",
+	pr_warn("coherent allocation failed for device %s size=%zu\n",
 		dev_name(hwdev), size);
 	dump_stack();
 
--- linux-4.4.0.orig/lib/test-hexdump.c
+++ linux-4.4.0/lib/test-hexdump.c
@@ -81,7 +81,7 @@
 		const char *q = *result++;
 		size_t amount = strlen(q);
 
-		strncpy(p, q, amount);
+		memcpy(p, q, amount);
 		p += amount + 1;
 	}
 	if (i)
--- linux-4.4.0.orig/lib/test-string_helpers.c
+++ linux-4.4.0/lib/test-string_helpers.c
@@ -327,36 +327,67 @@
 }
 
 #define string_get_size_maxbuf 16
-#define test_string_get_size_one(size, blk_size, units, exp_result)            \
+#define test_string_get_size_one(size, blk_size, exp_result10, exp_result2)    \
 	do {                                                                   \
-		BUILD_BUG_ON(sizeof(exp_result) >= string_get_size_maxbuf);    \
-		__test_string_get_size((size), (blk_size), (units),            \
-				       (exp_result));                          \
+		BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf);  \
+		BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf);   \
+		__test_string_get_size((size), (blk_size), (exp_result10),     \
+				       (exp_result2));                         \
 	} while (0)
 
 
-static __init void __test_string_get_size(const u64 size, const u64 blk_size,
-					  const enum string_size_units units,
-					  const char *exp_result)
+static __init void test_string_get_size_check(const char *units,
+					      const char *exp,
+					      char *res,
+					      const u64 size,
+					      const u64 blk_size)
 {
-	char buf[string_get_size_maxbuf];
-
-	string_get_size(size, blk_size, units, buf, sizeof(buf));
-	if (!memcmp(buf, exp_result, strlen(exp_result) + 1))
+	if (!memcmp(res, exp, strlen(exp) + 1))
 		return;
 
-	buf[sizeof(buf) - 1] = '\0';
-	pr_warn("Test 'test_string_get_size_one' failed!\n");
-	pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %d\n",
+	res[string_get_size_maxbuf - 1] = '\0';
+
+	pr_warn("Test 'test_string_get_size' failed!\n");
+	pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n",
 		size, blk_size, units);
-	pr_warn("expected: '%s', got '%s'\n", exp_result, buf);
+	pr_warn("expected: '%s', got '%s'\n", exp, res);
+}
+
+static __init void __test_string_get_size(const u64 size, const u64 blk_size,
+					  const char *exp_result10,
+					  const char *exp_result2)
+{
+	char buf10[string_get_size_maxbuf];
+	char buf2[string_get_size_maxbuf];
+
+	string_get_size(size, blk_size, STRING_UNITS_10, buf10, sizeof(buf10));
+	string_get_size(size, blk_size, STRING_UNITS_2, buf2, sizeof(buf2));
+
+	test_string_get_size_check("STRING_UNITS_10", exp_result10, buf10,
+				   size, blk_size);
+
+	test_string_get_size_check("STRING_UNITS_2", exp_result2, buf2,
+				   size, blk_size);
 }
 
 static __init void test_string_get_size(void)
 {
-	test_string_get_size_one(16384, 512, STRING_UNITS_2, "8.00 MiB");
-	test_string_get_size_one(8192, 4096, STRING_UNITS_10, "32.7 MB");
-	test_string_get_size_one(1, 512, STRING_UNITS_10, "512 B");
+	/* small values */
+	test_string_get_size_one(0, 512, "0 B", "0 B");
+	test_string_get_size_one(1, 512, "512 B", "512 B");
+	test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB");
+
+	/* normal values */
+	test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB");
+	test_string_get_size_one(500118192, 512, "256 GB", "238 GiB");
+	test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB");
+
+	/* weird block sizes */
+	test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB");
+
+	/* huge values */
+	test_string_get_size_one(U64_MAX, 4096, "75.6 ZB", "64.0 ZiB");
+	test_string_get_size_one(4096, U64_MAX, "75.6 ZB", "64.0 ZiB");
 }
 
 static int __init test_string_helpers_init(void)
--- linux-4.4.0.orig/lib/test_bpf.c
+++ linux-4.4.0/lib/test_bpf.c
@@ -83,6 +83,7 @@
 		__u32 result;
 	} test[MAX_SUBTESTS];
 	int (*fill_helper)(struct bpf_test *self);
+	int expected_errcode; /* used when FLAG_EXPECTED_FAIL is set in the aux */
 	__u8 frag_data[MAX_DATA];
 };
 
@@ -1780,7 +1781,9 @@
 		},
 		CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
 		{ },
-		{ }
+		{ },
+		.fill_helper = NULL,
+		.expected_errcode = -EINVAL,
 	},
 	{
 		"check: div_k_0",
@@ -1790,7 +1793,9 @@
 		},
 		CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
 		{ },
-		{ }
+		{ },
+		.fill_helper = NULL,
+		.expected_errcode = -EINVAL,
 	},
 	{
 		"check: unknown insn",
@@ -1801,7 +1806,9 @@
 		},
 		CLASSIC | FLAG_EXPECTED_FAIL,
 		{ },
-		{ }
+		{ },
+		.fill_helper = NULL,
+		.expected_errcode = -EINVAL,
 	},
 	{
 		"check: out of range spill/fill",
@@ -1811,7 +1818,9 @@
 		},
 		CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
 		{ },
-		{ }
+		{ },
+		.fill_helper = NULL,
+		.expected_errcode = -EINVAL,
 	},
 	{
 		"JUMPS + HOLES",
@@ -1903,6 +1912,8 @@
 		CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
 		{ },
 		{ },
+		.fill_helper = NULL,
+		.expected_errcode = -EINVAL,
 	},
 	{
 		"check: LDX + RET X",
@@ -1913,6 +1924,8 @@
 		CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
 		{ },
 		{ },
+		.fill_helper = NULL,
+		.expected_errcode = -EINVAL,
 	},
 	{	/* Mainly checking JIT here. */
 		"M[]: alt STX + LDX",
@@ -2087,6 +2100,8 @@
 		CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
 		{ },
 		{ },
+		.fill_helper = NULL,
+		.expected_errcode = -EINVAL,
 	},
 	{	/* Passes checker but fails during runtime. */
 		"LD [SKF_AD_OFF-1]",
@@ -4315,6 +4330,51 @@
 		{ },
 		{ { 0, 1 } },
 	},
+	{
+		/* Mainly testing JIT + imm64 here. */
+		"JMP_JGE_X: ldimm64 test 1",
+		.u.insns_int = {
+			BPF_ALU32_IMM(BPF_MOV, R0, 0),
+			BPF_LD_IMM64(R1, 3),
+			BPF_LD_IMM64(R2, 2),
+			BPF_JMP_REG(BPF_JGE, R1, R2, 2),
+			BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
+			BPF_LD_IMM64(R0, 0xeeeeeeeeeeeeeeeeUL),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 0xeeeeeeeeU } },
+	},
+	{
+		"JMP_JGE_X: ldimm64 test 2",
+		.u.insns_int = {
+			BPF_ALU32_IMM(BPF_MOV, R0, 0),
+			BPF_LD_IMM64(R1, 3),
+			BPF_LD_IMM64(R2, 2),
+			BPF_JMP_REG(BPF_JGE, R1, R2, 0),
+			BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 0xffffffffU } },
+	},
+	{
+		"JMP_JGE_X: ldimm64 test 3",
+		.u.insns_int = {
+			BPF_ALU32_IMM(BPF_MOV, R0, 1),
+			BPF_LD_IMM64(R1, 3),
+			BPF_LD_IMM64(R2, 2),
+			BPF_JMP_REG(BPF_JGE, R1, R2, 4),
+			BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
+			BPF_LD_IMM64(R0, 0xeeeeeeeeeeeeeeeeUL),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	/* BPF_JMP | BPF_JNE | BPF_X */
 	{
 		"JMP_JNE_X: if (3 != 2) return 1",
@@ -4417,6 +4477,7 @@
 		{ },
 		{ },
 		.fill_helper = bpf_fill_maxinsns4,
+		.expected_errcode = -EINVAL,
 	},
 	{	/* Mainly checking JIT here. */
 		"BPF_MAXINSNS: Very long jump",
@@ -4429,21 +4490,31 @@
 	{	/* Mainly checking JIT here. */
 		"BPF_MAXINSNS: Ctx heavy transformations",
 		{ },
+#if defined(CONFIG_BPF_JIT_ALWAYS_ON) && defined(CONFIG_S390)
+		CLASSIC | FLAG_EXPECTED_FAIL,
+#else
 		CLASSIC,
+#endif
 		{ },
 		{
 			{  1, !!(SKB_VLAN_TCI & VLAN_TAG_PRESENT) },
 			{ 10, !!(SKB_VLAN_TCI & VLAN_TAG_PRESENT) }
 		},
 		.fill_helper = bpf_fill_maxinsns6,
+		.expected_errcode = -ENOTSUPP,
 	},
 	{	/* Mainly checking JIT here. */
 		"BPF_MAXINSNS: Call heavy transformations",
 		{ },
+#if defined(CONFIG_BPF_JIT_ALWAYS_ON) && defined(CONFIG_S390)
+		CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
+#else
 		CLASSIC | FLAG_NO_DATA,
+#endif
 		{ },
 		{ { 1, 0 }, { 10, 0 } },
 		.fill_helper = bpf_fill_maxinsns7,
+		.expected_errcode = -ENOTSUPP,
 	},
 	{	/* Mainly checking JIT here. */
 		"BPF_MAXINSNS: Jump heavy test",
@@ -4472,25 +4543,35 @@
 	{
 		"BPF_MAXINSNS: Jump, gap, jump, ...",
 		{ },
+#if defined(CONFIG_BPF_JIT_ALWAYS_ON) && defined(CONFIG_X86)
+		CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
+#else
 		CLASSIC | FLAG_NO_DATA,
+#endif
 		{ },
 		{ { 0, 0xababcbac } },
 		.fill_helper = bpf_fill_maxinsns11,
+		.expected_errcode = -ENOTSUPP,
 	},
 	{
 		"BPF_MAXINSNS: ld_abs+get_processor_id",
 		{ },
+#if defined(CONFIG_BPF_JIT_ALWAYS_ON) && defined(CONFIG_S390)
+		CLASSIC | FLAG_EXPECTED_FAIL,
+#else
 		CLASSIC,
+#endif
 		{ },
 		{ { 1, 0xbee } },
 		.fill_helper = bpf_fill_ld_abs_get_processor_id,
+		.expected_errcode = -ENOTSUPP,
 	},
 	{
 		"BPF_MAXINSNS: ld_abs+vlan_push/pop",
 		{ },
 		INTERNAL,
 		{ 0x34 },
-		{ { 1, 0xbef } },
+		{ { ETH_HLEN, 0xbef } },
 		.fill_helper = bpf_fill_ld_abs_vlan_push_pop,
 	},
 	/*
@@ -5245,7 +5326,7 @@
 
 		*err = bpf_prog_create(&fp, &fprog);
 		if (tests[which].aux & FLAG_EXPECTED_FAIL) {
-			if (*err == -EINVAL) {
+			if (*err == tests[which].expected_errcode) {
 				pr_cont("PASS\n");
 				/* Verifier rejected filter as expected. */
 				*err = 0;
@@ -5259,9 +5340,8 @@
 				return NULL;
 			}
 		}
-		/* We don't expect to fail. */
 		if (*err) {
-			pr_cont("FAIL to attach err=%d len=%d\n",
+			pr_cont("FAIL to prog_create err=%d len=%d\n",
 				*err, fprog.len);
 			return NULL;
 		}
@@ -5280,7 +5360,14 @@
 		fp->type = BPF_PROG_TYPE_SOCKET_FILTER;
 		memcpy(fp->insnsi, fptr, fp->len * sizeof(struct bpf_insn));
 
-		bpf_prog_select_runtime(fp);
+		/* We cannot error here as we don't need type compatibility
+		 * checks.
+		 */
+		fp = bpf_prog_select_runtime(fp, err);
+		if (*err) {
+			pr_cont("FAIL to select_runtime err=%d\n", *err);
+			return NULL;
+		}
 		break;
 	}
 
@@ -5466,8 +5553,8 @@
 				pass_cnt++;
 				continue;
 			}
-
-			return err;
+			err_cnt++;
+			continue;
 		}
 
 		pr_cont("jited:%u ", fp->jited);
--- linux-4.4.0.orig/lib/test_firmware.c
+++ linux-4.4.0/lib/test_firmware.c
@@ -65,14 +65,19 @@
 	release_firmware(test_firmware);
 	test_firmware = NULL;
 	rc = request_firmware(&test_firmware, name, dev);
-	if (rc)
+	if (rc) {
 		pr_info("load of '%s' failed: %d\n", name, rc);
-	pr_info("loaded: %zu\n", test_firmware ? test_firmware->size : 0);
+		goto out;
+	}
+	pr_info("loaded: %zu\n", test_firmware->size);
+	rc = count;
+
+out:
 	mutex_unlock(&test_fw_mutex);
 
 	kfree(name);
 
-	return count;
+	return rc;
 }
 static DEVICE_ATTR_WO(trigger_request);
 
--- linux-4.4.0.orig/lib/test_kasan.c
+++ linux-4.4.0/lib/test_kasan.c
@@ -93,6 +93,7 @@
 	if (!ptr1 || !ptr2) {
 		pr_err("Allocation failed\n");
 		kfree(ptr1);
+		kfree(ptr2);
 		return;
 	}
 
--- linux-4.4.0.orig/lib/test_siphash.c
+++ linux-4.4.0/lib/test_siphash.c
@@ -0,0 +1,223 @@
+/* Test cases for siphash.c
+ *
+ * Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.
+ *
+ * SipHash: a fast short-input PRF
+ * https://131002.net/siphash/
+ *
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/siphash.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+
+/* Test vectors taken from reference source available at:
+ *     https://github.com/veorq/SipHash
+ */
+
+static const siphash_key_t test_key_siphash =
+	{{ 0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL }};
+
+static const u64 test_vectors_siphash[64] = {
+	0x726fdb47dd0e0e31ULL, 0x74f839c593dc67fdULL, 0x0d6c8009d9a94f5aULL,
+	0x85676696d7fb7e2dULL, 0xcf2794e0277187b7ULL, 0x18765564cd99a68dULL,
+	0xcbc9466e58fee3ceULL, 0xab0200f58b01d137ULL, 0x93f5f5799a932462ULL,
+	0x9e0082df0ba9e4b0ULL, 0x7a5dbbc594ddb9f3ULL, 0xf4b32f46226bada7ULL,
+	0x751e8fbc860ee5fbULL, 0x14ea5627c0843d90ULL, 0xf723ca908e7af2eeULL,
+	0xa129ca6149be45e5ULL, 0x3f2acc7f57c29bdbULL, 0x699ae9f52cbe4794ULL,
+	0x4bc1b3f0968dd39cULL, 0xbb6dc91da77961bdULL, 0xbed65cf21aa2ee98ULL,
+	0xd0f2cbb02e3b67c7ULL, 0x93536795e3a33e88ULL, 0xa80c038ccd5ccec8ULL,
+	0xb8ad50c6f649af94ULL, 0xbce192de8a85b8eaULL, 0x17d835b85bbb15f3ULL,
+	0x2f2e6163076bcfadULL, 0xde4daaaca71dc9a5ULL, 0xa6a2506687956571ULL,
+	0xad87a3535c49ef28ULL, 0x32d892fad841c342ULL, 0x7127512f72f27cceULL,
+	0xa7f32346f95978e3ULL, 0x12e0b01abb051238ULL, 0x15e034d40fa197aeULL,
+	0x314dffbe0815a3b4ULL, 0x027990f029623981ULL, 0xcadcd4e59ef40c4dULL,
+	0x9abfd8766a33735cULL, 0x0e3ea96b5304a7d0ULL, 0xad0c42d6fc585992ULL,
+	0x187306c89bc215a9ULL, 0xd4a60abcf3792b95ULL, 0xf935451de4f21df2ULL,
+	0xa9538f0419755787ULL, 0xdb9acddff56ca510ULL, 0xd06c98cd5c0975ebULL,
+	0xe612a3cb9ecba951ULL, 0xc766e62cfcadaf96ULL, 0xee64435a9752fe72ULL,
+	0xa192d576b245165aULL, 0x0a8787bf8ecb74b2ULL, 0x81b3e73d20b49b6fULL,
+	0x7fa8220ba3b2eceaULL, 0x245731c13ca42499ULL, 0xb78dbfaf3a8d83bdULL,
+	0xea1ad565322a1a0bULL, 0x60e61c23a3795013ULL, 0x6606d7e446282b93ULL,
+	0x6ca4ecb15c5f91e1ULL, 0x9f626da15c9625f3ULL, 0xe51b38608ef25f57ULL,
+	0x958a324ceb064572ULL
+};
+
+#if BITS_PER_LONG == 64
+static const hsiphash_key_t test_key_hsiphash =
+	{{ 0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL }};
+
+static const u32 test_vectors_hsiphash[64] = {
+	0x050fc4dcU, 0x7d57ca93U, 0x4dc7d44dU,
+	0xe7ddf7fbU, 0x88d38328U, 0x49533b67U,
+	0xc59f22a7U, 0x9bb11140U, 0x8d299a8eU,
+	0x6c063de4U, 0x92ff097fU, 0xf94dc352U,
+	0x57b4d9a2U, 0x1229ffa7U, 0xc0f95d34U,
+	0x2a519956U, 0x7d908b66U, 0x63dbd80cU,
+	0xb473e63eU, 0x8d297d1cU, 0xa6cce040U,
+	0x2b45f844U, 0xa320872eU, 0xdae6c123U,
+	0x67349c8cU, 0x705b0979U, 0xca9913a5U,
+	0x4ade3b35U, 0xef6cd00dU, 0x4ab1e1f4U,
+	0x43c5e663U, 0x8c21d1bcU, 0x16a7b60dU,
+	0x7a8ff9bfU, 0x1f2a753eU, 0xbf186b91U,
+	0xada26206U, 0xa3c33057U, 0xae3a36a1U,
+	0x7b108392U, 0x99e41531U, 0x3f1ad944U,
+	0xc8138825U, 0xc28949a6U, 0xfaf8876bU,
+	0x9f042196U, 0x68b1d623U, 0x8b5114fdU,
+	0xdf074c46U, 0x12cc86b3U, 0x0a52098fU,
+	0x9d292f9aU, 0xa2f41f12U, 0x43a71ed0U,
+	0x73f0bce6U, 0x70a7e980U, 0x243c6d75U,
+	0xfdb71513U, 0xa67d8a08U, 0xb7e8f148U,
+	0xf7a644eeU, 0x0f1837f2U, 0x4b6694e0U,
+	0xb7bbb3a8U
+};
+#else
+static const hsiphash_key_t test_key_hsiphash =
+	{{ 0x03020100U, 0x07060504U }};
+
+static const u32 test_vectors_hsiphash[64] = {
+	0x5814c896U, 0xe7e864caU, 0xbc4b0e30U,
+	0x01539939U, 0x7e059ea6U, 0x88e3d89bU,
+	0xa0080b65U, 0x9d38d9d6U, 0x577999b1U,
+	0xc839caedU, 0xe4fa32cfU, 0x959246eeU,
+	0x6b28096cU, 0x66dd9cd6U, 0x16658a7cU,
+	0xd0257b04U, 0x8b31d501U, 0x2b1cd04bU,
+	0x06712339U, 0x522aca67U, 0x911bb605U,
+	0x90a65f0eU, 0xf826ef7bU, 0x62512debU,
+	0x57150ad7U, 0x5d473507U, 0x1ec47442U,
+	0xab64afd3U, 0x0a4100d0U, 0x6d2ce652U,
+	0x2331b6a3U, 0x08d8791aU, 0xbc6dda8dU,
+	0xe0f6c934U, 0xb0652033U, 0x9b9851ccU,
+	0x7c46fb7fU, 0x732ba8cbU, 0xf142997aU,
+	0xfcc9aa1bU, 0x05327eb2U, 0xe110131cU,
+	0xf9e5e7c0U, 0xa7d708a6U, 0x11795ab1U,
+	0x65671619U, 0x9f5fff91U, 0xd89c5267U,
+	0x007783ebU, 0x95766243U, 0xab639262U,
+	0x9c7e1390U, 0xc368dda6U, 0x38ddc455U,
+	0xfa13d379U, 0x979ea4e8U, 0x53ecd77eU,
+	0x2ee80657U, 0x33dbb66aU, 0xae3f0577U,
+	0x88b4c4ccU, 0x3e7f480bU, 0x74c1ebf8U,
+	0x87178304U
+};
+#endif
+
+static int __init siphash_test_init(void)
+{
+	u8 in[64] __aligned(SIPHASH_ALIGNMENT);
+	u8 in_unaligned[65] __aligned(SIPHASH_ALIGNMENT);
+	u8 i;
+	int ret = 0;
+
+	for (i = 0; i < 64; ++i) {
+		in[i] = i;
+		in_unaligned[i + 1] = i;
+		if (siphash(in, i, &test_key_siphash) !=
+						test_vectors_siphash[i]) {
+			pr_info("siphash self-test aligned %u: FAIL\n", i + 1);
+			ret = -EINVAL;
+		}
+		if (siphash(in_unaligned + 1, i, &test_key_siphash) !=
+						test_vectors_siphash[i]) {
+			pr_info("siphash self-test unaligned %u: FAIL\n", i + 1);
+			ret = -EINVAL;
+		}
+		if (hsiphash(in, i, &test_key_hsiphash) !=
+						test_vectors_hsiphash[i]) {
+			pr_info("hsiphash self-test aligned %u: FAIL\n", i + 1);
+			ret = -EINVAL;
+		}
+		if (hsiphash(in_unaligned + 1, i, &test_key_hsiphash) !=
+						test_vectors_hsiphash[i]) {
+			pr_info("hsiphash self-test unaligned %u: FAIL\n", i + 1);
+			ret = -EINVAL;
+		}
+	}
+	if (siphash_1u64(0x0706050403020100ULL, &test_key_siphash) !=
+						test_vectors_siphash[8]) {
+		pr_info("siphash self-test 1u64: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
+			 &test_key_siphash) != test_vectors_siphash[16]) {
+		pr_info("siphash self-test 2u64: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (siphash_3u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
+			 0x1716151413121110ULL, &test_key_siphash) !=
+						test_vectors_siphash[24]) {
+		pr_info("siphash self-test 3u64: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (siphash_4u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
+			 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL,
+			 &test_key_siphash) != test_vectors_siphash[32]) {
+		pr_info("siphash self-test 4u64: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (siphash_1u32(0x03020100U, &test_key_siphash) !=
+						test_vectors_siphash[4]) {
+		pr_info("siphash self-test 1u32: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (siphash_2u32(0x03020100U, 0x07060504U, &test_key_siphash) !=
+						test_vectors_siphash[8]) {
+		pr_info("siphash self-test 2u32: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (siphash_3u32(0x03020100U, 0x07060504U,
+			 0x0b0a0908U, &test_key_siphash) !=
+						test_vectors_siphash[12]) {
+		pr_info("siphash self-test 3u32: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (siphash_4u32(0x03020100U, 0x07060504U,
+			 0x0b0a0908U, 0x0f0e0d0cU, &test_key_siphash) !=
+						test_vectors_siphash[16]) {
+		pr_info("siphash self-test 4u32: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (hsiphash_1u32(0x03020100U, &test_key_hsiphash) !=
+						test_vectors_hsiphash[4]) {
+		pr_info("hsiphash self-test 1u32: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (hsiphash_2u32(0x03020100U, 0x07060504U, &test_key_hsiphash) !=
+						test_vectors_hsiphash[8]) {
+		pr_info("hsiphash self-test 2u32: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (hsiphash_3u32(0x03020100U, 0x07060504U,
+			  0x0b0a0908U, &test_key_hsiphash) !=
+						test_vectors_hsiphash[12]) {
+		pr_info("hsiphash self-test 3u32: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (hsiphash_4u32(0x03020100U, 0x07060504U,
+			  0x0b0a0908U, 0x0f0e0d0cU, &test_key_hsiphash) !=
+						test_vectors_hsiphash[16]) {
+		pr_info("hsiphash self-test 4u32: FAIL\n");
+		ret = -EINVAL;
+	}
+	if (!ret)
+		pr_info("self-tests: pass\n");
+	return ret;
+}
+
+static void __exit siphash_test_exit(void)
+{
+}
+
+module_init(siphash_test_init);
+module_exit(siphash_test_exit);
+
+MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
+MODULE_LICENSE("Dual BSD/GPL");
--- linux-4.4.0.orig/lib/test_user_copy.c
+++ linux-4.4.0/lib/test_user_copy.c
@@ -58,7 +58,9 @@
 	usermem = (char __user *)user_addr;
 	bad_usermem = (char *)user_addr;
 
-	/* Legitimate usage: none of these should fail. */
+	/*
+	 * Legitimate usage: none of these copies should fail.
+	 */
 	ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
 		    "legitimate copy_from_user failed");
 	ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
@@ -68,19 +70,33 @@
 	ret |= test(put_user(value, (unsigned long __user *)usermem),
 		    "legitimate put_user failed");
 
-	/* Invalid usage: none of these should succeed. */
+	/*
+	 * Invalid usage: none of these copies should succeed.
+	 */
+
+	/* Reject kernel-to-kernel copies through copy_from_user(). */
 	ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
 				    PAGE_SIZE),
 		    "illegal all-kernel copy_from_user passed");
+
+#if 0
+	/*
+	 * When running with SMAP/PAN/etc, this will Oops the kernel
+	 * due to the zeroing of userspace memory on failure. This needs
+	 * to be tested in LKDTM instead, since this test module does not
+	 * expect to explode.
+	 */
 	ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
 				    PAGE_SIZE),
 		    "illegal reversed copy_from_user passed");
+#endif
 	ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
 				  PAGE_SIZE),
 		    "illegal all-kernel copy_to_user passed");
 	ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
 				  PAGE_SIZE),
 		    "illegal reversed copy_to_user passed");
+
 	ret |= test(!get_user(value, (unsigned long __user *)kmem),
 		    "illegal get_user passed");
 	ret |= test(!put_user(value, (unsigned long __user *)kmem),
--- linux-4.4.0.orig/lib/timerqueue.c
+++ linux-4.4.0/lib/timerqueue.c
@@ -38,9 +38,10 @@
  */
 bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node)
 {
-	struct rb_node **p = &head->head.rb_node;
+	struct rb_node **p = &head->rb_root.rb_root.rb_node;
 	struct rb_node *parent = NULL;
-	struct timerqueue_node  *ptr;
+	struct timerqueue_node *ptr;
+	bool leftmost = true;
 
 	/* Make sure we don't add nodes that are already added */
 	WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node));
@@ -48,19 +49,17 @@
 	while (*p) {
 		parent = *p;
 		ptr = rb_entry(parent, struct timerqueue_node, node);
-		if (node->expires.tv64 < ptr->expires.tv64)
+		if (node->expires.tv64 < ptr->expires.tv64) {
 			p = &(*p)->rb_left;
-		else
+		} else {
 			p = &(*p)->rb_right;
+			leftmost = false;
+		}
 	}
 	rb_link_node(&node->node, parent, p);
-	rb_insert_color(&node->node, &head->head);
+	rb_insert_color_cached(&node->node, &head->rb_root, leftmost);
 
-	if (!head->next || node->expires.tv64 < head->next->expires.tv64) {
-		head->next = node;
-		return true;
-	}
-	return false;
+	return leftmost;
 }
 EXPORT_SYMBOL_GPL(timerqueue_add);
 
@@ -76,16 +75,10 @@
 {
 	WARN_ON_ONCE(RB_EMPTY_NODE(&node->node));
 
-	/* update next pointer */
-	if (head->next == node) {
-		struct rb_node *rbn = rb_next(&node->node);
-
-		head->next = rbn ?
-			rb_entry(rbn, struct timerqueue_node, node) : NULL;
-	}
-	rb_erase(&node->node, &head->head);
+	rb_erase_cached(&node->node, &head->rb_root);
 	RB_CLEAR_NODE(&node->node);
-	return head->next != NULL;
+
+	return !RB_EMPTY_ROOT(&head->rb_root.rb_root);
 }
 EXPORT_SYMBOL_GPL(timerqueue_del);
 
--- linux-4.4.0.orig/lib/ucs2_string.c
+++ linux-4.4.0/lib/ucs2_string.c
@@ -49,3 +49,65 @@
         }
 }
 EXPORT_SYMBOL(ucs2_strncmp);
+
+unsigned long
+ucs2_utf8size(const ucs2_char_t *src)
+{
+	unsigned long i;
+	unsigned long j = 0;
+
+	for (i = 0; i < ucs2_strlen(src); i++) {
+		u16 c = src[i];
+
+		if (c >= 0x800)
+			j += 3;
+		else if (c >= 0x80)
+			j += 2;
+		else
+			j += 1;
+	}
+
+	return j;
+}
+EXPORT_SYMBOL(ucs2_utf8size);
+
+/*
+ * copy at most maxlength bytes of whole utf8 characters to dest from the
+ * ucs2 string src.
+ *
+ * The return value is the number of characters copied, not including the
+ * final NUL character.
+ */
+unsigned long
+ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength)
+{
+	unsigned int i;
+	unsigned long j = 0;
+	unsigned long limit = ucs2_strnlen(src, maxlength);
+
+	for (i = 0; maxlength && i < limit; i++) {
+		u16 c = src[i];
+
+		if (c >= 0x800) {
+			if (maxlength < 3)
+				break;
+			maxlength -= 3;
+			dest[j++] = 0xe0 | (c & 0xf000) >> 12;
+			dest[j++] = 0x80 | (c & 0x0fc0) >> 6;
+			dest[j++] = 0x80 | (c & 0x003f);
+		} else if (c >= 0x80) {
+			if (maxlength < 2)
+				break;
+			maxlength -= 2;
+			dest[j++] = 0xc0 | (c & 0x7c0) >> 6;
+			dest[j++] = 0x80 | (c & 0x03f);
+		} else {
+			maxlength -= 1;
+			dest[j++] = c & 0x7f;
+		}
+	}
+	if (maxlength)
+		dest[j] = '\0';
+	return j;
+}
+EXPORT_SYMBOL(ucs2_as_utf8);
--- linux-4.4.0.orig/lib/vsprintf.c
+++ linux-4.4.0/lib/vsprintf.c
@@ -1345,9 +1345,6 @@
 		return string(buf, end, NULL, spec);
 
 	switch (fmt[1]) {
-	case 'r':
-		return number(buf, end, clk_get_rate(clk), spec);
-
 	case 'n':
 	default:
 #ifdef CONFIG_COMMON_CLK
--- linux-4.4.0.orig/lib/zlib_inflate/inffast.c
+++ linux-4.4.0/lib/zlib_inflate/inffast.c
@@ -10,17 +10,6 @@
 
 #ifndef ASMINF
 
-/* Allow machine dependent optimization for post-increment or pre-increment.
-   Based on testing to date,
-   Pre-increment preferred for:
-   - PowerPC G3 (Adler)
-   - MIPS R5000 (Randers-Pehrson)
-   Post-increment preferred for:
-   - none
-   No measurable difference:
-   - Pentium III (Anderson)
-   - M68060 (Nikl)
- */
 union uu {
 	unsigned short us;
 	unsigned char b[2];
@@ -38,16 +27,6 @@
 	return mm.us;
 }
 
-#ifdef POSTINC
-#  define OFF 0
-#  define PUP(a) *(a)++
-#  define UP_UNALIGNED(a) get_unaligned16((a)++)
-#else
-#  define OFF 1
-#  define PUP(a) *++(a)
-#  define UP_UNALIGNED(a) get_unaligned16(++(a))
-#endif
-
 /*
    Decode literal, length, and distance codes and write out the resulting
    literal and match bytes until either not enough input or output is
@@ -115,9 +94,9 @@
 
     /* copy state to local variables */
     state = (struct inflate_state *)strm->state;
-    in = strm->next_in - OFF;
+    in = strm->next_in;
     last = in + (strm->avail_in - 5);
-    out = strm->next_out - OFF;
+    out = strm->next_out;
     beg = out - (start - strm->avail_out);
     end = out + (strm->avail_out - 257);
 #ifdef INFLATE_STRICT
@@ -138,9 +117,9 @@
        input data or output space */
     do {
         if (bits < 15) {
-            hold += (unsigned long)(PUP(in)) << bits;
+            hold += (unsigned long)(*in++) << bits;
             bits += 8;
-            hold += (unsigned long)(PUP(in)) << bits;
+            hold += (unsigned long)(*in++) << bits;
             bits += 8;
         }
         this = lcode[hold & lmask];
@@ -150,14 +129,14 @@
         bits -= op;
         op = (unsigned)(this.op);
         if (op == 0) {                          /* literal */
-            PUP(out) = (unsigned char)(this.val);
+            *out++ = (unsigned char)(this.val);
         }
         else if (op & 16) {                     /* length base */
             len = (unsigned)(this.val);
             op &= 15;                           /* number of extra bits */
             if (op) {
                 if (bits < op) {
-                    hold += (unsigned long)(PUP(in)) << bits;
+                    hold += (unsigned long)(*in++) << bits;
                     bits += 8;
                 }
                 len += (unsigned)hold & ((1U << op) - 1);
@@ -165,9 +144,9 @@
                 bits -= op;
             }
             if (bits < 15) {
-                hold += (unsigned long)(PUP(in)) << bits;
+                hold += (unsigned long)(*in++) << bits;
                 bits += 8;
-                hold += (unsigned long)(PUP(in)) << bits;
+                hold += (unsigned long)(*in++) << bits;
                 bits += 8;
             }
             this = dcode[hold & dmask];
@@ -180,10 +159,10 @@
                 dist = (unsigned)(this.val);
                 op &= 15;                       /* number of extra bits */
                 if (bits < op) {
-                    hold += (unsigned long)(PUP(in)) << bits;
+                    hold += (unsigned long)(*in++) << bits;
                     bits += 8;
                     if (bits < op) {
-                        hold += (unsigned long)(PUP(in)) << bits;
+                        hold += (unsigned long)(*in++) << bits;
                         bits += 8;
                     }
                 }
@@ -205,13 +184,13 @@
                         state->mode = BAD;
                         break;
                     }
-                    from = window - OFF;
+                    from = window;
                     if (write == 0) {           /* very common case */
                         from += wsize - op;
                         if (op < len) {         /* some from window */
                             len -= op;
                             do {
-                                PUP(out) = PUP(from);
+                                *out++ = *from++;
                             } while (--op);
                             from = out - dist;  /* rest from output */
                         }
@@ -222,14 +201,14 @@
                         if (op < len) {         /* some from end of window */
                             len -= op;
                             do {
-                                PUP(out) = PUP(from);
+                                *out++ = *from++;
                             } while (--op);
-                            from = window - OFF;
+                            from = window;
                             if (write < len) {  /* some from start of window */
                                 op = write;
                                 len -= op;
                                 do {
-                                    PUP(out) = PUP(from);
+                                    *out++ = *from++;
                                 } while (--op);
                                 from = out - dist;      /* rest from output */
                             }
@@ -240,21 +219,21 @@
                         if (op < len) {         /* some from window */
                             len -= op;
                             do {
-                                PUP(out) = PUP(from);
+                                *out++ = *from++;
                             } while (--op);
                             from = out - dist;  /* rest from output */
                         }
                     }
                     while (len > 2) {
-                        PUP(out) = PUP(from);
-                        PUP(out) = PUP(from);
-                        PUP(out) = PUP(from);
+                        *out++ = *from++;
+                        *out++ = *from++;
+                        *out++ = *from++;
                         len -= 3;
                     }
                     if (len) {
-                        PUP(out) = PUP(from);
+                        *out++ = *from++;
                         if (len > 1)
-                            PUP(out) = PUP(from);
+                            *out++ = *from++;
                     }
                 }
                 else {
@@ -264,29 +243,29 @@
                     from = out - dist;          /* copy direct from output */
 		    /* minimum length is three */
 		    /* Align out addr */
-		    if (!((long)(out - 1 + OFF) & 1)) {
-			PUP(out) = PUP(from);
+		    if (!((long)(out - 1) & 1)) {
+			*out++ = *from++;
 			len--;
 		    }
-		    sout = (unsigned short *)(out - OFF);
+		    sout = (unsigned short *)(out);
 		    if (dist > 2) {
 			unsigned short *sfrom;
 
-			sfrom = (unsigned short *)(from - OFF);
+			sfrom = (unsigned short *)(from);
 			loops = len >> 1;
 			do
 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-			    PUP(sout) = PUP(sfrom);
+			    *sout++ = *sfrom++;
 #else
-			    PUP(sout) = UP_UNALIGNED(sfrom);
+			    *sout++ = get_unaligned16(sfrom++);
 #endif
 			while (--loops);
-			out = (unsigned char *)sout + OFF;
-			from = (unsigned char *)sfrom + OFF;
+			out = (unsigned char *)sout;
+			from = (unsigned char *)sfrom;
 		    } else { /* dist == 1 or dist == 2 */
 			unsigned short pat16;
 
-			pat16 = *(sout-1+OFF);
+			pat16 = *(sout-1);
 			if (dist == 1) {
 				union uu mm;
 				/* copy one char pattern to both bytes */
@@ -296,12 +275,12 @@
 			}
 			loops = len >> 1;
 			do
-			    PUP(sout) = pat16;
+			    *sout++ = pat16;
 			while (--loops);
-			out = (unsigned char *)sout + OFF;
+			out = (unsigned char *)sout;
 		    }
 		    if (len & 1)
-			PUP(out) = PUP(from);
+			*out++ = *from++;
                 }
             }
             else if ((op & 64) == 0) {          /* 2nd level distance code */
@@ -336,8 +315,8 @@
     hold &= (1U << bits) - 1;
 
     /* update state and return */
-    strm->next_in = in + OFF;
-    strm->next_out = out + OFF;
+    strm->next_in = in;
+    strm->next_out = out;
     strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
     strm->avail_out = (unsigned)(out < end ?
                                  257 + (end - out) : 257 - (out - end));
--- linux-4.4.0.orig/mm/Kconfig
+++ linux-4.4.0/mm/Kconfig
@@ -628,6 +628,7 @@
 	default n
 	depends on ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT
 	depends on MEMORY_HOTPLUG
+	depends on !NEED_PER_CPU_KM
 	help
 	  Ordinarily all struct pages are initialised during early boot in a
 	  single thread. On very large machines this can take a considerable
@@ -651,8 +652,6 @@
 
 config ZONE_DEVICE
 	bool "Device memory (pmem, etc...) hotplug support" if EXPERT
-	default !ZONE_DMA
-	depends on !ZONE_DMA
 	depends on MEMORY_HOTPLUG
 	depends on MEMORY_HOTREMOVE
 	depends on X86_64 #arch_add_memory() comprehends device memory
--- linux-4.4.0.orig/mm/Makefile
+++ linux-4.4.0/mm/Makefile
@@ -21,7 +21,7 @@
 			   mm_init.o mmu_context.o percpu.o slab_common.o \
 			   compaction.o vmacache.o \
 			   interval_tree.o list_lru.o workingset.o \
-			   debug.o $(mmu-y)
+			   prfile.o debug.o $(mmu-y)
 
 obj-y += init-mm.o
 
--- linux-4.4.0.orig/mm/backing-dev.c
+++ linux-4.4.0/mm/backing-dev.c
@@ -21,6 +21,7 @@
 EXPORT_SYMBOL_GPL(noop_backing_dev_info);
 
 static struct class *bdi_class;
+const char *bdi_unknown_name = "(unknown)";
 
 /*
  * bdi_lock protects updates to bdi_list. bdi_list has RCU reader side
@@ -237,6 +238,7 @@
 
 	bdi_class->dev_groups = bdi_dev_groups;
 	bdi_debug_init();
+
 	return 0;
 }
 postcore_initcall(bdi_class_init);
@@ -293,6 +295,8 @@
 
 	memset(wb, 0, sizeof(*wb));
 
+	if (wb != &bdi->wb)
+		bdi_get(bdi);
 	wb->bdi = bdi;
 	wb->last_old_flush = jiffies;
 	INIT_LIST_HEAD(&wb->b_dirty);
@@ -312,8 +316,10 @@
 	INIT_DELAYED_WORK(&wb->dwork, wb_workfn);
 
 	wb->congested = wb_congested_get_create(bdi, blkcg_id, gfp);
-	if (!wb->congested)
-		return -ENOMEM;
+	if (!wb->congested) {
+		err = -ENOMEM;
+		goto out_put_bdi;
+	}
 
 	err = fprop_local_init_percpu(&wb->completions, gfp);
 	if (err)
@@ -333,9 +339,14 @@
 	fprop_local_destroy_percpu(&wb->completions);
 out_put_cong:
 	wb_congested_put(wb->congested);
+out_put_bdi:
+	if (wb != &bdi->wb)
+		bdi_put(bdi);
 	return err;
 }
 
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb);
+
 /*
  * Remove bdi from the global list and shutdown any threads we have running
  */
@@ -345,10 +356,18 @@
 	spin_lock_bh(&wb->work_lock);
 	if (!test_and_clear_bit(WB_registered, &wb->state)) {
 		spin_unlock_bh(&wb->work_lock);
+		/*
+		 * Wait for wb shutdown to finish if someone else is just
+		 * running wb_shutdown(). Otherwise we could proceed to wb /
+		 * bdi destruction before wb_shutdown() is finished.
+		 */
+		wait_on_bit(&wb->state, WB_shutting_down, TASK_UNINTERRUPTIBLE);
 		return;
 	}
+	set_bit(WB_shutting_down, &wb->state);
 	spin_unlock_bh(&wb->work_lock);
 
+	cgwb_remove_from_bdi_list(wb);
 	/*
 	 * Drain work list and shutdown the delayed_work.  !WB_registered
 	 * tells wb_workfn() that @wb is dying and its work_list needs to
@@ -357,6 +376,12 @@
 	mod_delayed_work(bdi_wq, &wb->dwork, 0);
 	flush_delayed_work(&wb->dwork);
 	WARN_ON(!list_empty(&wb->work_list));
+	/*
+	 * Make sure bit gets cleared after shutdown is finished. Matches with
+	 * the barrier provided by test_and_clear_bit() above.
+	 */
+	smp_wmb();
+	clear_bit(WB_shutting_down, &wb->state);
 }
 
 static void wb_exit(struct bdi_writeback *wb)
@@ -370,6 +395,8 @@
 
 	fprop_local_destroy_percpu(&wb->completions);
 	wb_congested_put(wb->congested);
+	if (wb != &wb->bdi->wb)
+		bdi_put(wb->bdi);
 }
 
 #ifdef CONFIG_CGROUP_WRITEBACK
@@ -379,11 +406,9 @@
 /*
  * cgwb_lock protects bdi->cgwb_tree, bdi->cgwb_congested_tree,
  * blkcg->cgwb_list, and memcg->cgwb_list.  bdi->cgwb_tree is also RCU
- * protected.  cgwb_release_wait is used to wait for the completion of cgwb
- * releases from bdi destruction path.
+ * protected.
  */
 static DEFINE_SPINLOCK(cgwb_lock);
-static DECLARE_WAIT_QUEUE_HEAD(cgwb_release_wait);
 
 /**
  * wb_congested_get_create - get or create a wb_congested
@@ -436,7 +461,7 @@
 		return NULL;
 
 	atomic_set(&new_congested->refcnt, 0);
-	new_congested->bdi = bdi;
+	new_congested->__bdi = bdi;
 	new_congested->blkcg_id = blkcg_id;
 	goto retry;
 
@@ -464,10 +489,10 @@
 	}
 
 	/* bdi might already have been destroyed leaving @congested unlinked */
-	if (congested->bdi) {
+	if (congested->__bdi) {
 		rb_erase(&congested->rb_node,
-			 &congested->bdi->cgwb_congested_tree);
-		congested->bdi = NULL;
+			 &congested->__bdi->cgwb_congested_tree);
+		congested->__bdi = NULL;
 	}
 
 	spin_unlock_irqrestore(&cgwb_lock, flags);
@@ -478,11 +503,6 @@
 {
 	struct bdi_writeback *wb = container_of(work, struct bdi_writeback,
 						release_work);
-	struct backing_dev_info *bdi = wb->bdi;
-
-	spin_lock_irq(&cgwb_lock);
-	list_del_rcu(&wb->bdi_node);
-	spin_unlock_irq(&cgwb_lock);
 
 	wb_shutdown(wb);
 
@@ -493,9 +513,6 @@
 	percpu_ref_exit(&wb->refcnt);
 	wb_exit(wb);
 	kfree_rcu(wb, rcu);
-
-	if (atomic_dec_and_test(&bdi->usage_cnt))
-		wake_up_all(&cgwb_release_wait);
 }
 
 static void cgwb_release(struct percpu_ref *refcnt)
@@ -515,6 +532,13 @@
 	percpu_ref_kill(&wb->refcnt);
 }
 
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb)
+{
+	spin_lock_irq(&cgwb_lock);
+	list_del_rcu(&wb->bdi_node);
+	spin_unlock_irq(&cgwb_lock);
+}
+
 static int cgwb_create(struct backing_dev_info *bdi,
 		       struct cgroup_subsys_state *memcg_css, gfp_t gfp)
 {
@@ -578,7 +602,6 @@
 		/* we might have raced another instance of this function */
 		ret = radix_tree_insert(&bdi->cgwb_tree, memcg_css->id, wb);
 		if (!ret) {
-			atomic_inc(&bdi->usage_cnt);
 			list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list);
 			list_add(&wb->memcg_node, memcg_cgwb_list);
 			list_add(&wb->blkcg_node, blkcg_cgwb_list);
@@ -668,7 +691,7 @@
 
 	INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC);
 	bdi->cgwb_congested_tree = RB_ROOT;
-	atomic_set(&bdi->usage_cnt, 1);
+	init_rwsem(&bdi->wb_switch_rwsem);
 
 	ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
 	if (!ret) {
@@ -678,36 +701,26 @@
 	return ret;
 }
 
-static void cgwb_bdi_destroy(struct backing_dev_info *bdi)
+static void cgwb_bdi_unregister(struct backing_dev_info *bdi)
 {
 	struct radix_tree_iter iter;
-	struct rb_node *rbn;
 	void **slot;
+	struct bdi_writeback *wb;
 
 	WARN_ON(test_bit(WB_registered, &bdi->wb.state));
 
 	spin_lock_irq(&cgwb_lock);
-
 	radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0)
 		cgwb_kill(*slot);
 
-	while ((rbn = rb_first(&bdi->cgwb_congested_tree))) {
-		struct bdi_writeback_congested *congested =
-			rb_entry(rbn, struct bdi_writeback_congested, rb_node);
-
-		rb_erase(rbn, &bdi->cgwb_congested_tree);
-		congested->bdi = NULL;	/* mark @congested unlinked */
+	while (!list_empty(&bdi->wb_list)) {
+		wb = list_first_entry(&bdi->wb_list, struct bdi_writeback,
+				      bdi_node);
+		spin_unlock_irq(&cgwb_lock);
+		wb_shutdown(wb);
+		spin_lock_irq(&cgwb_lock);
 	}
-
 	spin_unlock_irq(&cgwb_lock);
-
-	/*
-	 * All cgwb's and their congested states must be shutdown and
-	 * released before returning.  Drain the usage counter to wait for
-	 * all cgwb's and cgwb_congested's ever created on @bdi.
-	 */
-	atomic_dec(&bdi->usage_cnt);
-	wait_event(cgwb_release_wait, !atomic_read(&bdi->usage_cnt));
 }
 
 /**
@@ -747,6 +760,28 @@
 	spin_unlock_irq(&cgwb_lock);
 }
 
+static void cgwb_bdi_exit(struct backing_dev_info *bdi)
+{
+	struct rb_node *rbn;
+
+	spin_lock_irq(&cgwb_lock);
+	while ((rbn = rb_first(&bdi->cgwb_congested_tree))) {
+		struct bdi_writeback_congested *congested =
+			rb_entry(rbn, struct bdi_writeback_congested, rb_node);
+
+		rb_erase(rbn, &bdi->cgwb_congested_tree);
+		congested->__bdi = NULL;	/* mark @congested unlinked */
+	}
+	spin_unlock_irq(&cgwb_lock);
+}
+
+static void cgwb_bdi_register(struct backing_dev_info *bdi)
+{
+	spin_lock_irq(&cgwb_lock);
+	list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
+	spin_unlock_irq(&cgwb_lock);
+}
+
 #else	/* CONFIG_CGROUP_WRITEBACK */
 
 static int cgwb_bdi_init(struct backing_dev_info *bdi)
@@ -757,15 +792,32 @@
 	if (!bdi->wb_congested)
 		return -ENOMEM;
 
+	atomic_set(&bdi->wb_congested->refcnt, 1);
+
 	err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
 	if (err) {
-		kfree(bdi->wb_congested);
+		wb_congested_put(bdi->wb_congested);
 		return err;
 	}
 	return 0;
 }
 
-static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { }
+static void cgwb_bdi_unregister(struct backing_dev_info *bdi) { }
+
+static void cgwb_bdi_exit(struct backing_dev_info *bdi)
+{
+	wb_congested_put(bdi->wb_congested);
+}
+
+static void cgwb_bdi_register(struct backing_dev_info *bdi)
+{
+	list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
+}
+
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb)
+{
+	list_del_rcu(&wb->bdi_node);
+}
 
 #endif	/* CONFIG_CGROUP_WRITEBACK */
 
@@ -775,6 +827,7 @@
 
 	bdi->dev = NULL;
 
+	kref_init(&bdi->refcnt);
 	bdi->min_ratio = 0;
 	bdi->max_ratio = 100;
 	bdi->max_prop_frac = FPROP_FRAC_BASE;
@@ -784,12 +837,26 @@
 
 	ret = cgwb_bdi_init(bdi);
 
-	list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
-
 	return ret;
 }
 EXPORT_SYMBOL(bdi_init);
 
+struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id)
+{
+	struct backing_dev_info *bdi;
+
+	bdi = kmalloc_node(sizeof(struct backing_dev_info),
+			   gfp_mask | __GFP_ZERO, node_id);
+	if (!bdi)
+		return NULL;
+
+	if (bdi_init(bdi)) {
+		kfree(bdi);
+		return NULL;
+	}
+	return bdi;
+}
+
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
 		const char *fmt, ...)
 {
@@ -805,6 +872,7 @@
 	if (IS_ERR(dev))
 		return PTR_ERR(dev);
 
+	cgwb_bdi_register(bdi);
 	bdi->dev = dev;
 
 	bdi_debug_register(bdi, dev_name(dev));
@@ -825,6 +893,22 @@
 }
 EXPORT_SYMBOL(bdi_register_dev);
 
+int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner)
+{
+	int rc;
+
+	rc = bdi_register(bdi, NULL, "%u:%u", MAJOR(owner->devt),
+			MINOR(owner->devt));
+	if (rc)
+		return rc;
+	/* Leaking owner reference... */
+	WARN_ON(bdi->owner);
+	bdi->owner = owner;
+	get_device(owner);
+	return 0;
+}
+EXPORT_SYMBOL(bdi_register_owner);
+
 /*
  * Remove bdi from bdi_list, and ensure that it is no longer visible
  */
@@ -842,19 +926,39 @@
 	/* make sure nobody finds us on the bdi_list anymore */
 	bdi_remove_from_list(bdi);
 	wb_shutdown(&bdi->wb);
-	cgwb_bdi_destroy(bdi);
+	cgwb_bdi_unregister(bdi);
 
 	if (bdi->dev) {
 		bdi_debug_unregister(bdi);
 		device_unregister(bdi->dev);
 		bdi->dev = NULL;
 	}
+
+	if (bdi->owner) {
+		put_device(bdi->owner);
+		bdi->owner = NULL;
+	}
 }
 
-void bdi_exit(struct backing_dev_info *bdi)
+static void bdi_exit(struct backing_dev_info *bdi)
 {
 	WARN_ON_ONCE(bdi->dev);
 	wb_exit(&bdi->wb);
+	cgwb_bdi_exit(bdi);
+}
+
+static void release_bdi(struct kref *ref)
+{
+	struct backing_dev_info *bdi =
+			container_of(ref, struct backing_dev_info, refcnt);
+
+	bdi_exit(bdi);
+	kfree(bdi);
+}
+
+void bdi_put(struct backing_dev_info *bdi)
+{
+	kref_put(&bdi->refcnt, release_bdi);
 }
 
 void bdi_destroy(struct backing_dev_info *bdi)
@@ -898,7 +1002,7 @@
 void clear_wb_congested(struct bdi_writeback_congested *congested, int sync)
 {
 	wait_queue_head_t *wqh = &congestion_wqh[sync];
-	enum wb_state bit;
+	enum wb_congested_state bit;
 
 	bit = sync ? WB_sync_congested : WB_async_congested;
 	if (test_and_clear_bit(bit, &congested->state))
@@ -911,7 +1015,7 @@
 
 void set_wb_congested(struct bdi_writeback_congested *congested, int sync)
 {
-	enum wb_state bit;
+	enum wb_congested_state bit;
 
 	bit = sync ? WB_sync_congested : WB_async_congested;
 	if (!test_and_set_bit(bit, &congested->state))
@@ -957,9 +1061,8 @@
  * jiffies for either a BDI to exit congestion of the given @sync queue
  * or a write to complete.
  *
- * In the absence of zone congestion, a short sleep or a cond_resched is
- * performed to yield the processor and to allow other subsystems to make
- * a forward progress.
+ * In the absence of zone congestion, cond_resched() is called to yield
+ * the processor if necessary but otherwise does not sleep.
  *
  * The return value is 0 if the sleep is for the full timeout. Otherwise,
  * it is the number of jiffies that were still remaining when the function
@@ -979,20 +1082,7 @@
 	 */
 	if (atomic_read(&nr_wb_congested[sync]) == 0 ||
 	    !test_bit(ZONE_CONGESTED, &zone->flags)) {
-
-		/*
-		 * Memory allocation/reclaim might be called from a WQ
-		 * context and the current implementation of the WQ
-		 * concurrency control doesn't recognize that a particular
-		 * WQ is congested if the worker thread is looping without
-		 * ever sleeping. Therefore we have to do a short sleep
-		 * here rather than calling cond_resched().
-		 */
-		if (current->flags & PF_WQ_WORKER)
-			schedule_timeout(1);
-		else
-			cond_resched();
-
+		cond_resched();
 		/* In case we scheduled, work out time remaining */
 		ret = timeout - (jiffies - start);
 		if (ret < 0)
--- linux-4.4.0.orig/mm/balloon_compaction.c
+++ linux-4.4.0/mm/balloon_compaction.c
@@ -61,6 +61,7 @@
 	bool dequeued_page;
 
 	dequeued_page = false;
+	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
 	list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) {
 		/*
 		 * Block others from accessing the 'page' while we get around
@@ -75,15 +76,14 @@
 				continue;
 			}
 #endif
-			spin_lock_irqsave(&b_dev_info->pages_lock, flags);
 			balloon_page_delete(page);
 			__count_vm_event(BALLOON_DEFLATE);
-			spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
 			unlock_page(page);
 			dequeued_page = true;
 			break;
 		}
 	}
+	spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
 
 	if (!dequeued_page) {
 		/*
--- linux-4.4.0.orig/mm/cma.c
+++ linux-4.4.0/mm/cma.c
@@ -54,7 +54,7 @@
 }
 
 static unsigned long cma_bitmap_aligned_mask(const struct cma *cma,
-					     int align_order)
+					     unsigned int align_order)
 {
 	if (align_order <= cma->order_per_bit)
 		return 0;
@@ -62,17 +62,14 @@
 }
 
 /*
- * Find a PFN aligned to the specified order and return an offset represented in
- * order_per_bits.
+ * Find the offset of the base PFN from the specified align_order.
+ * The value returned is represented in order_per_bits.
  */
 static unsigned long cma_bitmap_aligned_offset(const struct cma *cma,
-					       int align_order)
+					       unsigned int align_order)
 {
-	if (align_order <= cma->order_per_bit)
-		return 0;
-
-	return (ALIGN(cma->base_pfn, (1UL << align_order))
-		- cma->base_pfn) >> cma->order_per_bit;
+	return (cma->base_pfn & ((1UL << align_order) - 1))
+		>> cma->order_per_bit;
 }
 
 static unsigned long cma_bitmap_pages_to_bits(const struct cma *cma,
@@ -103,8 +100,10 @@
 
 	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
 
-	if (!cma->bitmap)
+	if (!cma->bitmap) {
+		cma->count = 0;
 		return -ENOMEM;
+	}
 
 	WARN_ON_ONCE(!pfn_valid(pfn));
 	zone = page_zone(pfn_to_page(pfn));
@@ -183,7 +182,8 @@
 		return -EINVAL;
 
 	/* ensure minimal alignment required by mm core */
-	alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
+	alignment = PAGE_SIZE <<
+			max_t(unsigned long, MAX_ORDER - 1, pageblock_order);
 
 	/* alignment should be aligned with order_per_bit */
 	if (!IS_ALIGNED(alignment >> PAGE_SHIFT, 1 << order_per_bit))
@@ -266,8 +266,14 @@
 	 * migratetype page by page allocator's buddy algorithm. In the case,
 	 * you couldn't get a contiguous memory, which is not what we want.
 	 */
-	alignment = max(alignment,
-		(phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
+	alignment = max(alignment,  (phys_addr_t)PAGE_SIZE <<
+			  max_t(unsigned long, MAX_ORDER - 1, pageblock_order));
+	if (fixed && base & (alignment - 1)) {
+		ret = -EINVAL;
+		pr_err("Region at %pa must be aligned to %pa bytes\n",
+			&base, &alignment);
+		goto err;
+	}
 	base = ALIGN(base, alignment);
 	size = ALIGN(size, alignment);
 	limit &= ~(alignment - 1);
@@ -298,6 +304,13 @@
 	if (limit == 0 || limit > memblock_end)
 		limit = memblock_end;
 
+	if (base + size > limit) {
+		ret = -EINVAL;
+		pr_err("Size (%pa) of region at %pa exceeds limit (%pa)\n",
+			&size, &base, &limit);
+		goto err;
+	}
+
 	/* Reserve memory */
 	if (fixed) {
 		if (memblock_is_region_reserved(base, size) ||
@@ -341,12 +354,14 @@
 
 	ret = cma_init_reserved_mem(base, size, order_per_bit, res_cma);
 	if (ret)
-		goto err;
+		goto free_mem;
 
 	pr_info("Reserved %ld MiB at %pa\n", (unsigned long)size / SZ_1M,
 		&base);
 	return 0;
 
+free_mem:
+	memblock_free(base, size);
 err:
 	pr_err("Failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
 	return ret;
--- linux-4.4.0.orig/mm/cma_debug.c
+++ linux-4.4.0/mm/cma_debug.c
@@ -57,7 +57,7 @@
 	mutex_lock(&cma->lock);
 	for (;;) {
 		start = find_next_zero_bit(cma->bitmap, bitmap_maxno, end);
-		if (start >= cma->count)
+		if (start >= bitmap_maxno)
 			break;
 		end = find_next_bit(cma->bitmap, bitmap_maxno, start);
 		maxchunk = max(end - start, maxchunk);
--- linux-4.4.0.orig/mm/compaction.c
+++ linux-4.4.0/mm/compaction.c
@@ -200,7 +200,8 @@
 {
 	zone->compact_cached_migrate_pfn[0] = zone->zone_start_pfn;
 	zone->compact_cached_migrate_pfn[1] = zone->zone_start_pfn;
-	zone->compact_cached_free_pfn = zone_end_pfn(zone);
+	zone->compact_cached_free_pfn =
+			round_down(zone_end_pfn(zone) - 1, pageblock_nr_pages);
 }
 
 /*
@@ -475,25 +476,23 @@
 
 		/* Found a free page, break it into order-0 pages */
 		isolated = split_free_page(page);
+		if (!isolated)
+			break;
+
 		total_isolated += isolated;
+		cc->nr_freepages += isolated;
 		for (i = 0; i < isolated; i++) {
 			list_add(&page->lru, freelist);
 			page++;
 		}
-
-		/* If a page was split, advance to the end of it */
-		if (isolated) {
-			cc->nr_freepages += isolated;
-			if (!strict &&
-				cc->nr_migratepages <= cc->nr_freepages) {
-				blockpfn += isolated;
-				break;
-			}
-
-			blockpfn += isolated - 1;
-			cursor += isolated - 1;
-			continue;
+		if (!strict && cc->nr_migratepages <= cc->nr_freepages) {
+			blockpfn += isolated;
+			break;
 		}
+		/* Advance to the end of split page */
+		blockpfn += isolated - 1;
+		cursor += isolated - 1;
+		continue;
 
 isolate_fail:
 		if (strict)
@@ -503,6 +502,9 @@
 
 	}
 
+	if (locked)
+		spin_unlock_irqrestore(&cc->zone->lock, flags);
+
 	/*
 	 * There is a tiny chance that we have read bogus compound_order(),
 	 * so be careful to not go outside of the pageblock.
@@ -524,9 +526,6 @@
 	if (strict && blockpfn < end_pfn)
 		total_isolated = 0;
 
-	if (locked)
-		spin_unlock_irqrestore(&cc->zone->lock, flags);
-
 	/* Update the pageblock-skip if the whole pageblock was scanned */
 	if (blockpfn == end_pfn)
 		update_pageblock_skip(cc, valid_page, total_isolated, false);
@@ -554,13 +553,17 @@
 isolate_freepages_range(struct compact_control *cc,
 			unsigned long start_pfn, unsigned long end_pfn)
 {
-	unsigned long isolated, pfn, block_end_pfn;
+	unsigned long isolated, pfn, block_start_pfn, block_end_pfn;
 	LIST_HEAD(freelist);
 
 	pfn = start_pfn;
+	block_start_pfn = pfn & ~(pageblock_nr_pages - 1);
+	if (block_start_pfn < cc->zone->zone_start_pfn)
+		block_start_pfn = cc->zone->zone_start_pfn;
 	block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
 
 	for (; pfn < end_pfn; pfn += isolated,
+				block_start_pfn = block_end_pfn,
 				block_end_pfn += pageblock_nr_pages) {
 		/* Protect pfn from changing by isolate_freepages_block */
 		unsigned long isolate_start_pfn = pfn;
@@ -573,11 +576,13 @@
 		 * scanning range to right one.
 		 */
 		if (pfn >= block_end_pfn) {
+			block_start_pfn = pfn & ~(pageblock_nr_pages - 1);
 			block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
 			block_end_pfn = min(block_end_pfn, end_pfn);
 		}
 
-		if (!pageblock_pfn_to_page(pfn, block_end_pfn, cc->zone))
+		if (!pageblock_pfn_to_page(block_start_pfn,
+					block_end_pfn, cc->zone))
 			break;
 
 		isolated = isolate_freepages_block(cc, &isolate_start_pfn,
@@ -863,33 +868,30 @@
 isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn,
 							unsigned long end_pfn)
 {
-	unsigned long pfn, block_end_pfn;
+	unsigned long pfn, block_start_pfn, block_end_pfn;
 
 	/* Scan block by block. First and last block may be incomplete */
 	pfn = start_pfn;
+	block_start_pfn = pfn & ~(pageblock_nr_pages - 1);
+	if (block_start_pfn < cc->zone->zone_start_pfn)
+		block_start_pfn = cc->zone->zone_start_pfn;
 	block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
 
 	for (; pfn < end_pfn; pfn = block_end_pfn,
+				block_start_pfn = block_end_pfn,
 				block_end_pfn += pageblock_nr_pages) {
 
 		block_end_pfn = min(block_end_pfn, end_pfn);
 
-		if (!pageblock_pfn_to_page(pfn, block_end_pfn, cc->zone))
+		if (!pageblock_pfn_to_page(block_start_pfn,
+					block_end_pfn, cc->zone))
 			continue;
 
 		pfn = isolate_migratepages_block(cc, pfn, block_end_pfn,
 							ISOLATE_UNEVICTABLE);
 
-		/*
-		 * In case of fatal failure, release everything that might
-		 * have been isolated in the previous iteration, and signal
-		 * the failure back to caller.
-		 */
-		if (!pfn) {
-			putback_movable_pages(&cc->migratepages);
-			cc->nr_migratepages = 0;
+		if (!pfn)
 			break;
-		}
 
 		if (cc->nr_migratepages == COMPACT_CLUSTER_MAX)
 			break;
@@ -974,7 +976,6 @@
 				block_end_pfn = block_start_pfn,
 				block_start_pfn -= pageblock_nr_pages,
 				isolate_start_pfn = block_start_pfn) {
-
 		/*
 		 * This can iterate a massively long zone without finding any
 		 * suitable migration targets, so periodically check if we need
@@ -998,32 +999,30 @@
 			continue;
 
 		/* Found a block suitable for isolating free pages from. */
-		isolate_freepages_block(cc, &isolate_start_pfn,
-					block_end_pfn, freelist, false);
+		isolate_freepages_block(cc, &isolate_start_pfn, block_end_pfn,
+					freelist, false);
 
 		/*
-		 * If we isolated enough freepages, or aborted due to async
-		 * compaction being contended, terminate the loop.
-		 * Remember where the free scanner should restart next time,
-		 * which is where isolate_freepages_block() left off.
-		 * But if it scanned the whole pageblock, isolate_start_pfn
-		 * now points at block_end_pfn, which is the start of the next
-		 * pageblock.
-		 * In that case we will however want to restart at the start
-		 * of the previous pageblock.
+		 * If we isolated enough freepages, or aborted due to lock
+		 * contention, terminate.
 		 */
 		if ((cc->nr_freepages >= cc->nr_migratepages)
 							|| cc->contended) {
-			if (isolate_start_pfn >= block_end_pfn)
+			if (isolate_start_pfn >= block_end_pfn) {
+				/*
+				 * Restart at previous pageblock if more
+				 * freepages can be isolated next time.
+				 */
 				isolate_start_pfn =
 					block_start_pfn - pageblock_nr_pages;
+			}
 			break;
-		} else {
+		} else if (isolate_start_pfn < block_end_pfn) {
 			/*
-			 * isolate_freepages_block() should not terminate
-			 * prematurely unless contended, or isolated enough
+			 * If isolation failed early, do not continue
+			 * needlessly.
 			 */
-			VM_BUG_ON(isolate_start_pfn < block_end_pfn);
+			break;
 		}
 	}
 
@@ -1103,7 +1102,9 @@
 static isolate_migrate_t isolate_migratepages(struct zone *zone,
 					struct compact_control *cc)
 {
-	unsigned long low_pfn, end_pfn;
+	unsigned long block_start_pfn;
+	unsigned long block_end_pfn;
+	unsigned long low_pfn;
 	unsigned long isolate_start_pfn;
 	struct page *page;
 	const isolate_mode_t isolate_mode =
@@ -1115,16 +1116,21 @@
 	 * initialized by compact_zone()
 	 */
 	low_pfn = cc->migrate_pfn;
+	block_start_pfn = cc->migrate_pfn & ~(pageblock_nr_pages - 1);
+	if (block_start_pfn < zone->zone_start_pfn)
+		block_start_pfn = zone->zone_start_pfn;
 
 	/* Only scan within a pageblock boundary */
-	end_pfn = ALIGN(low_pfn + 1, pageblock_nr_pages);
+	block_end_pfn = ALIGN(low_pfn + 1, pageblock_nr_pages);
 
 	/*
 	 * Iterate over whole pageblocks until we find the first suitable.
 	 * Do not cross the free scanner.
 	 */
-	for (; end_pfn <= cc->free_pfn;
-			low_pfn = end_pfn, end_pfn += pageblock_nr_pages) {
+	for (; block_end_pfn <= cc->free_pfn;
+			low_pfn = block_end_pfn,
+			block_start_pfn = block_end_pfn,
+			block_end_pfn += pageblock_nr_pages) {
 
 		/*
 		 * This can potentially iterate a massively long zone with
@@ -1135,7 +1141,8 @@
 						&& compact_should_abort(cc))
 			break;
 
-		page = pageblock_pfn_to_page(low_pfn, end_pfn, zone);
+		page = pageblock_pfn_to_page(block_start_pfn, block_end_pfn,
+									zone);
 		if (!page)
 			continue;
 
@@ -1154,8 +1161,8 @@
 
 		/* Perform the isolation */
 		isolate_start_pfn = low_pfn;
-		low_pfn = isolate_migratepages_block(cc, low_pfn, end_pfn,
-								isolate_mode);
+		low_pfn = isolate_migratepages_block(cc, low_pfn,
+						block_end_pfn, isolate_mode);
 
 		if (!low_pfn || cc->contended) {
 			acct_isolated(zone, cc);
@@ -1195,7 +1202,7 @@
 	return order == -1;
 }
 
-static int __compact_finished(struct zone *zone, struct compact_control *cc,
+static enum compact_result __compact_finished(struct zone *zone, struct compact_control *cc,
 			    const int migratetype)
 {
 	unsigned int order;
@@ -1218,7 +1225,10 @@
 		if (!current_is_kswapd())
 			zone->compact_blockskip_flush = true;
 
-		return COMPACT_COMPLETE;
+		if (cc->whole_zone)
+			return COMPACT_COMPLETE;
+		else
+			return COMPACT_PARTIAL_SKIPPED;
 	}
 
 	if (is_via_compact_memory(cc->order))
@@ -1258,8 +1268,9 @@
 	return COMPACT_NO_SUITABLE_PAGE;
 }
 
-static int compact_finished(struct zone *zone, struct compact_control *cc,
-			    const int migratetype)
+static enum compact_result compact_finished(struct zone *zone,
+			struct compact_control *cc,
+			const int migratetype)
 {
 	int ret;
 
@@ -1278,8 +1289,10 @@
  *   COMPACT_PARTIAL  - If the allocation would succeed without compaction
  *   COMPACT_CONTINUE - If compaction should run now
  */
-static unsigned long __compaction_suitable(struct zone *zone, int order,
-					int alloc_flags, int classzone_idx)
+static enum compact_result __compaction_suitable(struct zone *zone, int order,
+					unsigned int alloc_flags,
+					int classzone_idx,
+					unsigned long wmark_target)
 {
 	int fragindex;
 	unsigned long watermark;
@@ -1302,7 +1315,8 @@
 	 * allocated and for a short time, the footprint is higher
 	 */
 	watermark += (2UL << order);
-	if (!zone_watermark_ok(zone, 0, watermark, classzone_idx, alloc_flags))
+	if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx,
+				 alloc_flags, wmark_target))
 		return COMPACT_SKIPPED;
 
 	/*
@@ -1323,12 +1337,14 @@
 	return COMPACT_CONTINUE;
 }
 
-unsigned long compaction_suitable(struct zone *zone, int order,
-					int alloc_flags, int classzone_idx)
+enum compact_result compaction_suitable(struct zone *zone, int order,
+					unsigned int alloc_flags,
+					int classzone_idx)
 {
-	unsigned long ret;
+	enum compact_result ret;
 
-	ret = __compaction_suitable(zone, order, alloc_flags, classzone_idx);
+	ret = __compaction_suitable(zone, order, alloc_flags, classzone_idx,
+				    zone_page_state(zone, NR_FREE_PAGES));
 	trace_mm_compaction_suitable(zone, order, ret);
 	if (ret == COMPACT_NOT_SUITABLE_ZONE)
 		ret = COMPACT_SKIPPED;
@@ -1336,9 +1352,42 @@
 	return ret;
 }
 
-static int compact_zone(struct zone *zone, struct compact_control *cc)
+bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
+		int alloc_flags)
 {
-	int ret;
+	struct zone *zone;
+	struct zoneref *z;
+
+	/*
+	 * Make sure at least one zone would pass __compaction_suitable if we continue
+	 * retrying the reclaim.
+	 */
+	for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
+					ac->nodemask) {
+		unsigned long available;
+		enum compact_result compact_result;
+
+		/*
+		 * Do not consider all the reclaimable memory because we do not
+		 * want to trash just for a single high order allocation which
+		 * is even not guaranteed to appear even if __compaction_suitable
+		 * is happy about the watermark check.
+		 */
+		available = zone_reclaimable_pages(zone) / order;
+		available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
+		compact_result = __compaction_suitable(zone, order, alloc_flags,
+				ac->classzone_idx, available);
+		if (compact_result != COMPACT_SKIPPED &&
+				compact_result != COMPACT_NOT_SUITABLE_ZONE)
+			return true;
+	}
+
+	return false;
+}
+
+static enum compact_result compact_zone(struct zone *zone, struct compact_control *cc)
+{
+	enum compact_result ret;
 	unsigned long start_pfn = zone->zone_start_pfn;
 	unsigned long end_pfn = zone_end_pfn(zone);
 	const int migratetype = gfpflags_to_migratetype(cc->gfp_mask);
@@ -1371,15 +1420,19 @@
 	 */
 	cc->migrate_pfn = zone->compact_cached_migrate_pfn[sync];
 	cc->free_pfn = zone->compact_cached_free_pfn;
-	if (cc->free_pfn < start_pfn || cc->free_pfn > end_pfn) {
-		cc->free_pfn = end_pfn & ~(pageblock_nr_pages-1);
+	if (cc->free_pfn < start_pfn || cc->free_pfn >= end_pfn) {
+		cc->free_pfn = round_down(end_pfn - 1, pageblock_nr_pages);
 		zone->compact_cached_free_pfn = cc->free_pfn;
 	}
-	if (cc->migrate_pfn < start_pfn || cc->migrate_pfn > end_pfn) {
+	if (cc->migrate_pfn < start_pfn || cc->migrate_pfn >= end_pfn) {
 		cc->migrate_pfn = start_pfn;
 		zone->compact_cached_migrate_pfn[0] = cc->migrate_pfn;
 		zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn;
 	}
+
+	if (cc->migrate_pfn == start_pfn)
+		cc->whole_zone = true;
+
 	cc->last_migrated_pfn = 0;
 
 	trace_mm_compaction_begin(start_pfn, cc->migrate_pfn,
@@ -1483,11 +1536,11 @@
 	return ret;
 }
 
-static unsigned long compact_zone_order(struct zone *zone, int order,
+static enum compact_result compact_zone_order(struct zone *zone, int order,
 		gfp_t gfp_mask, enum migrate_mode mode, int *contended,
-		int alloc_flags, int classzone_idx)
+		unsigned int alloc_flags, int classzone_idx)
 {
-	unsigned long ret;
+	enum compact_result ret;
 	struct compact_control cc = {
 		.nr_freepages = 0,
 		.nr_migratepages = 0,
@@ -1524,15 +1577,15 @@
  *
  * This is the main entry point for direct page compaction.
  */
-unsigned long try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
-			int alloc_flags, const struct alloc_context *ac,
-			enum migrate_mode mode, int *contended)
+enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
+		unsigned int alloc_flags, const struct alloc_context *ac,
+		enum migrate_mode mode, int *contended)
 {
 	int may_enter_fs = gfp_mask & __GFP_FS;
 	int may_perform_io = gfp_mask & __GFP_IO;
 	struct zoneref *z;
 	struct zone *zone;
-	int rc = COMPACT_DEFERRED;
+	enum compact_result rc = COMPACT_SKIPPED;
 	int all_zones_contended = COMPACT_CONTENDED_LOCK; /* init for &= op */
 
 	*contended = COMPACT_CONTENDED_NONE;
@@ -1546,11 +1599,13 @@
 	/* Compact each zone in the list */
 	for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
 								ac->nodemask) {
-		int status;
+		enum compact_result status;
 		int zone_contended;
 
-		if (compaction_deferred(zone, order))
+		if (compaction_deferred(zone, order)) {
+			rc = max_t(enum compact_result, COMPACT_DEFERRED, rc);
 			continue;
+		}
 
 		status = compact_zone_order(zone, order, gfp_mask, mode,
 				&zone_contended, alloc_flags,
@@ -1586,7 +1641,8 @@
 			goto break_loop;
 		}
 
-		if (mode != MIGRATE_ASYNC && status == COMPACT_COMPLETE) {
+		if (mode != MIGRATE_ASYNC && (status == COMPACT_COMPLETE ||
+					status == COMPACT_PARTIAL_SKIPPED)) {
 			/*
 			 * We think that allocation won't succeed in this zone
 			 * so we defer compaction there. If it ends up
@@ -1621,7 +1677,7 @@
 	 * If at least one zone wasn't deferred or skipped, we report if all
 	 * zones that were tried were lock contended.
 	 */
-	if (rc > COMPACT_SKIPPED && all_zones_contended)
+	if (rc > COMPACT_INACTIVE && all_zones_contended)
 		*contended = COMPACT_CONTENDED_LOCK;
 
 	return rc;
--- linux-4.4.0.orig/mm/debug-pagealloc.c
+++ linux-4.4.0/mm/debug-pagealloc.c
@@ -34,6 +34,8 @@
 	struct page_ext *page_ext;
 
 	page_ext = lookup_page_ext(page);
+	if (!page_ext)
+		return;
 	__set_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
 }
 
@@ -42,6 +44,8 @@
 	struct page_ext *page_ext;
 
 	page_ext = lookup_page_ext(page);
+	if (!page_ext)
+		return;
 	__clear_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
 }
 
@@ -50,6 +54,8 @@
 	struct page_ext *page_ext;
 
 	page_ext = lookup_page_ext(page);
+	if (!page_ext)
+		return false;
 	return test_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
 }
 
--- linux-4.4.0.orig/mm/debug.c
+++ linux-4.4.0/mm/debug.c
@@ -168,7 +168,7 @@
 
 void dump_mm(const struct mm_struct *mm)
 {
-	pr_emerg("mm %p mmap %p seqnum %d task_size %lu\n"
+	pr_emerg("mm %p mmap %p seqnum %llu task_size %lu\n"
 #ifdef CONFIG_MMU
 		"get_unmapped_area %p\n"
 #endif
@@ -198,7 +198,7 @@
 #endif
 		"%s",	/* This is here to hold the comma */
 
-		mm, mm->mmap, mm->vmacache_seqnum, mm->task_size,
+		mm, mm->mmap, (long long) mm->vmacache_seqnum, mm->task_size,
 #ifdef CONFIG_MMU
 		mm->get_unmapped_area,
 #endif
--- linux-4.4.0.orig/mm/early_ioremap.c
+++ linux-4.4.0/mm/early_ioremap.c
@@ -103,7 +103,7 @@
 	enum fixed_addresses idx;
 	int i, slot;
 
-	WARN_ON(system_state != SYSTEM_BOOTING);
+	WARN_ON(system_state >= SYSTEM_RUNNING);
 
 	slot = -1;
 	for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
--- linux-4.4.0.orig/mm/fadvise.c
+++ linux-4.4.0/mm/fadvise.c
@@ -68,8 +68,12 @@
 		goto out;
 	}
 
-	/* Careful about overflows. Len == 0 means "as much as possible" */
-	endbyte = offset + len;
+	/*
+	 * Careful about overflows. Len == 0 means "as much as possible".  Use
+	 * unsigned math because signed overflows are undefined and UBSan
+	 * complains.
+	 */
+	endbyte = (u64)offset + (u64)len;
 	if (!len || endbyte < len)
 		endbyte = -1;
 	else
--- linux-4.4.0.orig/mm/filemap.c
+++ linux-4.4.0/mm/filemap.c
@@ -109,6 +109,48 @@
  *   ->tasklist_lock            (memory_failure, collect_procs_ao)
  */
 
+static int page_cache_tree_insert(struct address_space *mapping,
+				  struct page *page, void **shadowp)
+{
+	struct radix_tree_node *node;
+	void **slot;
+	int error;
+
+	error = __radix_tree_create(&mapping->page_tree, page->index,
+				    &node, &slot);
+	if (error)
+		return error;
+	if (*slot) {
+		void *p;
+
+		p = radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
+		if (!radix_tree_exceptional_entry(p))
+			return -EEXIST;
+		if (shadowp)
+			*shadowp = p;
+		mapping->nrshadows--;
+		if (node)
+			workingset_node_shadows_dec(node);
+	}
+	radix_tree_replace_slot(slot, page);
+	mapping->nrpages++;
+	if (node) {
+		workingset_node_pages_inc(node);
+		/*
+		 * Don't track node that contains actual pages.
+		 *
+		 * Avoid acquiring the list_lru lock if already
+		 * untracked.  The list_empty() test is safe as
+		 * node->private_list is protected by
+		 * mapping->tree_lock.
+		 */
+		if (!list_empty(&node->private_list))
+			list_lru_del(&workingset_shadow_nodes,
+				     &node->private_list);
+	}
+	return 0;
+}
+
 static void page_cache_tree_delete(struct address_space *mapping,
 				   struct page *page, void *shadow)
 {
@@ -122,6 +164,14 @@
 
 	__radix_tree_lookup(&mapping->page_tree, page->index, &node, &slot);
 
+	if (!node) {
+		/*
+		 * We need a node to properly account shadow
+		 * entries. Don't plant any without. XXX
+		 */
+		shadow = NULL;
+	}
+
 	if (shadow) {
 		mapping->nrshadows++;
 		/*
@@ -290,7 +340,8 @@
 		.range_end = end,
 	};
 
-	if (!mapping_cap_writeback_dirty(mapping))
+	if (!mapping_cap_writeback_dirty(mapping) ||
+	    !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
 		return 0;
 
 	wbc_attach_fdatawrite_inode(&wbc, mapping->host);
@@ -521,7 +572,7 @@
 	VM_BUG_ON_PAGE(!PageLocked(new), new);
 	VM_BUG_ON_PAGE(new->mapping, new);
 
-	error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
+	error = radix_tree_preload(gfp_mask & GFP_RECLAIM_MASK);
 	if (!error) {
 		struct address_space *mapping = old->mapping;
 		void (*freepage)(struct page *);
@@ -538,9 +589,8 @@
 		memcg = mem_cgroup_begin_page_stat(old);
 		spin_lock_irqsave(&mapping->tree_lock, flags);
 		__delete_from_page_cache(old, NULL, memcg);
-		error = radix_tree_insert(&mapping->page_tree, offset, new);
+		error = page_cache_tree_insert(mapping, new, NULL);
 		BUG_ON(error);
-		mapping->nrpages++;
 
 		/*
 		 * hugetlb pages do not participate in page cache accounting.
@@ -562,48 +612,6 @@
 }
 EXPORT_SYMBOL_GPL(replace_page_cache_page);
 
-static int page_cache_tree_insert(struct address_space *mapping,
-				  struct page *page, void **shadowp)
-{
-	struct radix_tree_node *node;
-	void **slot;
-	int error;
-
-	error = __radix_tree_create(&mapping->page_tree, page->index,
-				    &node, &slot);
-	if (error)
-		return error;
-	if (*slot) {
-		void *p;
-
-		p = radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
-		if (!radix_tree_exceptional_entry(p))
-			return -EEXIST;
-		if (shadowp)
-			*shadowp = p;
-		mapping->nrshadows--;
-		if (node)
-			workingset_node_shadows_dec(node);
-	}
-	radix_tree_replace_slot(slot, page);
-	mapping->nrpages++;
-	if (node) {
-		workingset_node_pages_inc(node);
-		/*
-		 * Don't track node that contains actual pages.
-		 *
-		 * Avoid acquiring the list_lru lock if already
-		 * untracked.  The list_empty() test is safe as
-		 * node->private_list is protected by
-		 * mapping->tree_lock.
-		 */
-		if (!list_empty(&node->private_list))
-			list_lru_del(&workingset_shadow_nodes,
-				     &node->private_list);
-	}
-	return 0;
-}
-
 static int __add_to_page_cache_locked(struct page *page,
 				      struct address_space *mapping,
 				      pgoff_t offset, gfp_t gfp_mask,
@@ -623,7 +631,7 @@
 			return error;
 	}
 
-	error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM);
+	error = radix_tree_maybe_preload(gfp_mask & GFP_RECLAIM_MASK);
 	if (error) {
 		if (!huge)
 			mem_cgroup_cancel_charge(page, memcg);
@@ -858,9 +866,12 @@
 		unlock_page(page);
 	} else { /* rw == WRITE */
 		if (err) {
+			struct address_space *mapping;
+
 			SetPageError(page);
-			if (page->mapping)
-				mapping_set_error(page->mapping, err);
+			mapping = page_mapping(page);
+			if (mapping)
+				mapping_set_error(mapping, err);
 		}
 		end_page_writeback(page);
 	}
@@ -1182,8 +1193,7 @@
 		if (fgp_flags & FGP_ACCESSED)
 			__SetPageReferenced(page);
 
-		err = add_to_page_cache_lru(page, mapping, offset,
-				gfp_mask & GFP_RECLAIM_MASK);
+		err = add_to_page_cache_lru(page, mapping, offset, gfp_mask);
 		if (unlikely(err)) {
 			page_cache_release(page);
 			page = NULL;
@@ -1552,6 +1562,11 @@
 
 		cond_resched();
 find_page:
+		if (fatal_signal_pending(current)) {
+			error = -EINTR;
+			goto out;
+		}
+
 		page = find_get_page(mapping, index);
 		if (!page) {
 			page_cache_sync_readahead(mapping,
@@ -1567,6 +1582,15 @@
 					index, last_index - index);
 		}
 		if (!PageUptodate(page)) {
+			/*
+			 * See comment in do_read_cache_page on why
+			 * wait_on_page_locked is used to avoid unnecessarily
+			 * serialisations and why it's safe.
+			 */
+			wait_on_page_locked_killable(page);
+			if (PageUptodate(page))
+				goto page_ok;
+
 			if (inode->i_blkbits == PAGE_CACHE_SHIFT ||
 					!mapping->a_ops->is_partially_uptodate)
 				goto page_not_up_to_date;
@@ -1812,19 +1836,18 @@
  * This adds the requested page to the page cache if it isn't already there,
  * and schedules an I/O to read in its contents from disk.
  */
-static int page_cache_read(struct file *file, pgoff_t offset)
+static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask)
 {
 	struct address_space *mapping = file->f_mapping;
 	struct page *page;
 	int ret;
 
 	do {
-		page = page_cache_alloc_cold(mapping);
+		page = __page_cache_alloc(gfp_mask|__GFP_COLD);
 		if (!page)
 			return -ENOMEM;
 
-		ret = add_to_page_cache_lru(page, mapping, offset,
-				mapping_gfp_constraint(mapping, GFP_KERNEL));
+		ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask);
 		if (ret == 0)
 			ret = mapping->a_ops->readpage(file, page);
 		else if (ret == -EEXIST)
@@ -2005,7 +2028,7 @@
 	 * We're only likely to ever get here if MADV_RANDOM is in
 	 * effect.
 	 */
-	error = page_cache_read(file, offset);
+	error = page_cache_read(file, offset, vmf->gfp_mask);
 
 	/*
 	 * The page we want has now been added to the page cache.
@@ -2128,7 +2151,7 @@
 	int ret = VM_FAULT_LOCKED;
 
 	sb_start_pagefault(inode->i_sb);
-	file_update_time(vma->vm_file);
+	vma_file_update_time(vma);
 	lock_page(page);
 	if (page->mapping != inode->i_mapping) {
 		unlock_page(page);
@@ -2202,7 +2225,7 @@
 	return page;
 }
 
-static struct page *__read_cache_page(struct address_space *mapping,
+static struct page *do_read_cache_page(struct address_space *mapping,
 				pgoff_t index,
 				int (*filler)(void *, struct page *),
 				void *data,
@@ -2224,53 +2247,82 @@
 			/* Presumably ENOMEM for radix tree node */
 			return ERR_PTR(err);
 		}
+
+filler:
 		err = filler(data, page);
 		if (err < 0) {
 			page_cache_release(page);
-			page = ERR_PTR(err);
-		} else {
-			page = wait_on_page_read(page);
+			return ERR_PTR(err);
 		}
-	}
-	return page;
-}
 
-static struct page *do_read_cache_page(struct address_space *mapping,
-				pgoff_t index,
-				int (*filler)(void *, struct page *),
-				void *data,
-				gfp_t gfp)
-
-{
-	struct page *page;
-	int err;
+		page = wait_on_page_read(page);
+		if (IS_ERR(page))
+			return page;
+		goto out;
+	}
+	if (PageUptodate(page))
+		goto out;
 
-retry:
-	page = __read_cache_page(mapping, index, filler, data, gfp);
-	if (IS_ERR(page))
-		return page;
+	/*
+	 * Page is not up to date and may be locked due one of the following
+	 * case a: Page is being filled and the page lock is held
+	 * case b: Read/write error clearing the page uptodate status
+	 * case c: Truncation in progress (page locked)
+	 * case d: Reclaim in progress
+	 *
+	 * Case a, the page will be up to date when the page is unlocked.
+	 *    There is no need to serialise on the page lock here as the page
+	 *    is pinned so the lock gives no additional protection. Even if the
+	 *    the page is truncated, the data is still valid if PageUptodate as
+	 *    it's a race vs truncate race.
+	 * Case b, the page will not be up to date
+	 * Case c, the page may be truncated but in itself, the data may still
+	 *    be valid after IO completes as it's a read vs truncate race. The
+	 *    operation must restart if the page is not uptodate on unlock but
+	 *    otherwise serialising on page lock to stabilise the mapping gives
+	 *    no additional guarantees to the caller as the page lock is
+	 *    released before return.
+	 * Case d, similar to truncation. If reclaim holds the page lock, it
+	 *    will be a race with remove_mapping that determines if the mapping
+	 *    is valid on unlock but otherwise the data is valid and there is
+	 *    no need to serialise with page lock.
+	 *
+	 * As the page lock gives no additional guarantee, we optimistically
+	 * wait on the page to be unlocked and check if it's up to date and
+	 * use the page if it is. Otherwise, the page lock is required to
+	 * distinguish between the different cases. The motivation is that we
+	 * avoid spurious serialisations and wakeups when multiple processes
+	 * wait on the same page for IO to complete.
+	 */
+	wait_on_page_locked(page);
 	if (PageUptodate(page))
 		goto out;
 
+	/* Distinguish between all the cases under the safety of the lock */
 	lock_page(page);
+
+	/* Case c or d, restart the operation */
 	if (!page->mapping) {
 		unlock_page(page);
 		page_cache_release(page);
-		goto retry;
+		goto repeat;
 	}
+
+	/* Someone else locked and filled the page in a very small window */
 	if (PageUptodate(page)) {
 		unlock_page(page);
 		goto out;
 	}
-	err = filler(data, page);
-	if (err < 0) {
-		page_cache_release(page);
-		return ERR_PTR(err);
-	} else {
-		page = wait_on_page_read(page);
-		if (IS_ERR(page))
-			return page;
-	}
+
+	/*
+	 * A previous I/O error may have been due to temporary
+	 * failures.
+	 * Clear page error before actual read, PG_error will be
+	 * set again if read page fails.
+	 */
+	ClearPageError(page);
+	goto filler;
+
 out:
 	mark_page_accessed(page);
 	return page;
--- linux-4.4.0.orig/mm/frame_vector.c
+++ linux-4.4.0/mm/frame_vector.c
@@ -11,10 +11,7 @@
  * get_vaddr_frames() - map virtual addresses to pfns
  * @start:	starting user address
  * @nr_frames:	number of pages / pfns from start to map
- * @write:	whether pages will be written to by the caller
- * @force:	whether to force write access even if user mapping is
- *		readonly. See description of the same argument of
-		get_user_pages().
+ * @gup_flags:	flags modifying lookup behaviour
  * @vec:	structure which receives pages / pfns of the addresses mapped.
  *		It should have space for at least nr_frames entries.
  *
@@ -34,7 +31,7 @@
  * This function takes care of grabbing mmap_sem as necessary.
  */
 int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
-		     bool write, bool force, struct frame_vector *vec)
+		     unsigned int gup_flags, struct frame_vector *vec)
 {
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma;
@@ -59,7 +56,7 @@
 		vec->got_ref = true;
 		vec->is_pfns = false;
 		ret = get_user_pages_locked(current, mm, start, nr_frames,
-			write, force, (struct page **)(vec->ptrs), &locked);
+			gup_flags, (struct page **)(vec->ptrs), &locked);
 		goto out;
 	}
 
--- linux-4.4.0.orig/mm/gup.c
+++ linux-4.4.0/mm/gup.c
@@ -58,6 +58,25 @@
 	return -EEXIST;
 }
 
+/*
+ * FOLL_FORCE or a forced COW break can write even to unwritable pte's,
+ * but only after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
+{
+	return pte_write(pte) || ((flags & FOLL_COW) && pte_dirty(pte));
+}
+
+/*
+ * A (separate) COW fault might break the page the other way and
+ * get_user_pages() would return the page from what is now the wrong
+ * VM. So we need to force a COW break at GUP time even for reads.
+ */
+static inline bool should_force_cow_break(struct vm_area_struct *vma, unsigned int flags)
+{
+	return is_cow_mapping(vma->vm_flags) && (flags & (FOLL_GET));
+}
+
 static struct page *follow_page_pte(struct vm_area_struct *vma,
 		unsigned long address, pmd_t *pmd, unsigned int flags)
 {
@@ -92,7 +111,7 @@
 	}
 	if ((flags & FOLL_NUMA) && pte_protnone(pte))
 		goto no_page;
-	if ((flags & FOLL_WRITE) && !pte_write(pte)) {
+	if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
 		pte_unmap_unlock(ptep, ptl);
 		return NULL;
 	}
@@ -116,8 +135,12 @@
 		}
 	}
 
-	if (flags & FOLL_GET)
-		get_page_foll(page);
+	if (flags & FOLL_GET) {
+		if (unlikely(!try_get_page(page))) {
+			page = ERR_PTR(-ENOMEM);
+			goto out;
+		}
+	}
 	if (flags & FOLL_TOUCH) {
 		if ((flags & FOLL_WRITE) &&
 		    !pte_dirty(pte) && !PageDirty(page))
@@ -279,7 +302,10 @@
 			goto unmap;
 		*page = pte_page(*pte);
 	}
-	get_page(*page);
+	if (unlikely(!try_get_page(*page))) {
+		ret = -ENOMEM;
+		goto unmap;
+	}
 out:
 	ret = 0;
 unmap:
@@ -302,11 +328,6 @@
 	/* mlock all present pages, but do not fault in new pages */
 	if ((*flags & (FOLL_POPULATE | FOLL_MLOCK)) == FOLL_MLOCK)
 		return -ENOENT;
-	/* For mm_populate(), just skip the stack guard page. */
-	if ((*flags & FOLL_POPULATE) &&
-			(stack_guard_page_start(vma, address) ||
-			 stack_guard_page_end(vma, address + PAGE_SIZE)))
-		return -ENOENT;
 	if (*flags & FOLL_WRITE)
 		fault_flags |= FAULT_FLAG_WRITE;
 	if (nonblocking)
@@ -352,7 +373,7 @@
 	 * reCOWed by userspace write).
 	 */
 	if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
-		*flags &= ~FOLL_WRITE;
+	        *flags |= FOLL_COW;
 	return 0;
 }
 
@@ -363,6 +384,9 @@
 	if (vm_flags & (VM_IO | VM_PFNMAP))
 		return -EFAULT;
 
+	if (gup_flags & FOLL_ANON && !vma_is_anonymous(vma))
+		return -EFAULT;
+
 	if (gup_flags & FOLL_WRITE) {
 		if (!(vm_flags & VM_WRITE)) {
 			if (!(gup_flags & FOLL_FORCE))
@@ -494,12 +518,18 @@
 			if (!vma || check_vma_flags(vma, gup_flags))
 				return i ? : -EFAULT;
 			if (is_vm_hugetlb_page(vma)) {
+				if (should_force_cow_break(vma, foll_flags))
+					foll_flags |= FOLL_WRITE;
 				i = follow_hugetlb_page(mm, vma, pages, vmas,
 						&start, &nr_pages, i,
-						gup_flags);
+						foll_flags);
 				continue;
 			}
 		}
+
+		if (should_force_cow_break(vma, foll_flags))
+			foll_flags |= FOLL_WRITE;
+
 retry:
 		/*
 		 * If we have a pending SIGKILL, don't keep faulting pages and
@@ -617,12 +647,12 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(fixup_user_fault);
 
 static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
 						struct mm_struct *mm,
 						unsigned long start,
 						unsigned long nr_pages,
-						int write, int force,
 						struct page **pages,
 						struct vm_area_struct **vmas,
 						int *locked, bool notify_drop,
@@ -640,10 +670,6 @@
 
 	if (pages)
 		flags |= FOLL_GET;
-	if (write)
-		flags |= FOLL_WRITE;
-	if (force)
-		flags |= FOLL_FORCE;
 
 	pages_done = 0;
 	lock_dropped = false;
@@ -737,11 +763,12 @@
  */
 long get_user_pages_locked(struct task_struct *tsk, struct mm_struct *mm,
 			   unsigned long start, unsigned long nr_pages,
-			   int write, int force, struct page **pages,
+			   unsigned int gup_flags, struct page **pages,
 			   int *locked)
 {
-	return __get_user_pages_locked(tsk, mm, start, nr_pages, write, force,
-				       pages, NULL, locked, true, FOLL_TOUCH);
+	return __get_user_pages_locked(tsk, mm, start, nr_pages,
+				       pages, NULL, locked, true,
+				       gup_flags | FOLL_TOUCH);
 }
 EXPORT_SYMBOL(get_user_pages_locked);
 
@@ -757,14 +784,14 @@
  */
 __always_inline long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
 					       unsigned long start, unsigned long nr_pages,
-					       int write, int force, struct page **pages,
-					       unsigned int gup_flags)
+					       struct page **pages, unsigned int gup_flags)
 {
 	long ret;
 	int locked = 1;
+
 	down_read(&mm->mmap_sem);
-	ret = __get_user_pages_locked(tsk, mm, start, nr_pages, write, force,
-				      pages, NULL, &locked, false, gup_flags);
+	ret = __get_user_pages_locked(tsk, mm, start, nr_pages, pages, NULL,
+				      &locked, false, gup_flags);
 	if (locked)
 		up_read(&mm->mmap_sem);
 	return ret;
@@ -790,10 +817,10 @@
  */
 long get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
 			     unsigned long start, unsigned long nr_pages,
-			     int write, int force, struct page **pages)
+			     struct page **pages, unsigned int gup_flags)
 {
-	return __get_user_pages_unlocked(tsk, mm, start, nr_pages, write,
-					 force, pages, FOLL_TOUCH);
+	return __get_user_pages_unlocked(tsk, mm, start, nr_pages,
+					 pages, gup_flags | FOLL_TOUCH);
 }
 EXPORT_SYMBOL(get_user_pages_unlocked);
 
@@ -853,11 +880,13 @@
  * FAULT_FLAG_ALLOW_RETRY to handle_mm_fault.
  */
 long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-		unsigned long start, unsigned long nr_pages, int write,
-		int force, struct page **pages, struct vm_area_struct **vmas)
+		unsigned long start, unsigned long nr_pages,
+		unsigned int gup_flags, struct page **pages,
+		struct vm_area_struct **vmas)
 {
-	return __get_user_pages_locked(tsk, mm, start, nr_pages, write, force,
-				       pages, vmas, NULL, false, FOLL_TOUCH);
+	return __get_user_pages_locked(tsk, mm, start, nr_pages,
+				       pages, vmas, NULL, false,
+				       gup_flags | FOLL_TOUCH);
 }
 EXPORT_SYMBOL(get_user_pages);
 
@@ -935,8 +964,6 @@
 	int locked = 0;
 	long ret = 0;
 
-	VM_BUG_ON(start & ~PAGE_MASK);
-	VM_BUG_ON(len != PAGE_ALIGN(len));
 	end = start + len;
 
 	for (nstart = start; nstart < end; nstart = nend) {
@@ -1012,6 +1039,20 @@
 #endif /* CONFIG_ELF_CORE */
 
 /*
+ * Return the compund head page with ref appropriately incremented,
+ * or NULL if that failed.
+ */
+static inline struct page *try_get_compound_head(struct page *page, int refs)
+{
+	struct page *head = compound_head(page);
+	if (WARN_ON_ONCE(atomic_read(&page->_count) < 0))
+		return NULL;
+	if (unlikely(!page_cache_add_speculative(head, refs)))
+		return NULL;
+	return head;
+}
+
+/*
  * Generic RCU Fast GUP
  *
  * get_user_pages_fast attempts to pin user pages by walking the page
@@ -1066,7 +1107,7 @@
 		 * for an example see gup_get_pte in arch/x86/mm/gup.c
 		 */
 		pte_t pte = READ_ONCE(*ptep);
-		struct page *page;
+		struct page *head, *page;
 
 		/*
 		 * Similar to the PMD case below, NUMA hinting must take slow
@@ -1079,7 +1120,8 @@
 		VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
 		page = pte_page(pte);
 
-		if (!page_cache_get_speculative(page))
+		head = try_get_compound_head(page, 1);
+		if (!head)
 			goto pte_unmap;
 
 		if (unlikely(pte_val(pte) != pte_val(*ptep))) {
@@ -1126,18 +1168,17 @@
 		return 0;
 
 	refs = 0;
-	head = pmd_page(orig);
-	page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+	page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
 	tail = page;
 	do {
-		VM_BUG_ON_PAGE(compound_head(page) != head, page);
 		pages[*nr] = page;
 		(*nr)++;
 		page++;
 		refs++;
 	} while (addr += PAGE_SIZE, addr != end);
 
-	if (!page_cache_add_speculative(head, refs)) {
+	head = try_get_compound_head(pmd_page(orig), refs);
+	if (!head) {
 		*nr -= refs;
 		return 0;
 	}
@@ -1173,18 +1214,17 @@
 		return 0;
 
 	refs = 0;
-	head = pud_page(orig);
-	page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
 	tail = page;
+	page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
 	do {
-		VM_BUG_ON_PAGE(compound_head(page) != head, page);
 		pages[*nr] = page;
 		(*nr)++;
 		page++;
 		refs++;
 	} while (addr += PAGE_SIZE, addr != end);
 
-	if (!page_cache_add_speculative(head, refs)) {
+	head = try_get_compound_head(pud_page(orig), refs);
+	if (!head) {
 		*nr -= refs;
 		return 0;
 	}
@@ -1216,18 +1256,17 @@
 		return 0;
 
 	refs = 0;
-	head = pgd_page(orig);
-	page = head + ((addr & ~PGDIR_MASK) >> PAGE_SHIFT);
 	tail = page;
+	page = pgd_page(orig) + ((addr & ~PGDIR_MASK) >> PAGE_SHIFT);
 	do {
-		VM_BUG_ON_PAGE(compound_head(page) != head, page);
 		pages[*nr] = page;
 		(*nr)++;
 		page++;
 		refs++;
 	} while (addr += PAGE_SIZE, addr != end);
 
-	if (!page_cache_add_speculative(head, refs)) {
+	head = try_get_compound_head(pgd_page(orig), refs);
+	if (!head) {
 		*nr -= refs;
 		return 0;
 	}
@@ -1321,6 +1360,10 @@
 /*
  * Like get_user_pages_fast() except it's IRQ-safe in that it won't fall back to
  * the regular GUP. It will only return non-negative values.
+ *
+ * Careful, careful! COW breaking can go either way, so a non-write
+ * access can get ambiguous page results. If you call this function without
+ * 'write' set, you'd better be sure that you're ok with that ambiguity.
  */
 int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
 			  struct page **pages)
@@ -1350,6 +1393,12 @@
 	 *
 	 * We do not adopt an rcu_read_lock(.) here as we also want to
 	 * block IPIs that come from THPs splitting.
+	 *
+	 * NOTE! We allow read-only gup_fast() here, but you'd better be
+	 * careful about possible COW pages. You'll get _a_ COW page, but
+	 * not necessarily the one you intended to get depending on what
+	 * COW event happens after this. COW may break the page copy in a
+	 * random direction.
 	 */
 
 	local_irq_save(flags);
@@ -1399,7 +1448,14 @@
 	int nr, ret;
 
 	start &= PAGE_MASK;
-	nr = __get_user_pages_fast(start, nr_pages, write, pages);
+	/*
+	 * The FAST_GUP case requires FOLL_WRITE even for pure reads,
+	 * because get_user_pages() may need to cause an early COW in
+	 * order to avoid confusing the normal COW routines. So only
+	 * targets that are already writable are safe to do by just
+	 * looking at the page tables.
+	 */
+	nr = __get_user_pages_fast(start, nr_pages, 1, pages);
 	ret = nr;
 
 	if (nr < nr_pages) {
@@ -1408,7 +1464,8 @@
 		pages += nr;
 
 		ret = get_user_pages_unlocked(current, mm, start,
-					      nr_pages - nr, write, 0, pages);
+					      nr_pages - nr, pages,
+					      write ? FOLL_WRITE : 0);
 
 		/* Have to be a bit careful with return values */
 		if (nr > 0) {
--- linux-4.4.0.orig/mm/huge_memory.c
+++ linux-4.4.0/mm/huge_memory.c
@@ -824,7 +824,6 @@
 		spinlock_t *ptl;
 		pgtable_t pgtable;
 		struct page *zero_page;
-		bool set;
 		int ret;
 		pgtable = pte_alloc_one(mm, haddr);
 		if (unlikely(!pgtable))
@@ -837,10 +836,11 @@
 		}
 		ptl = pmd_lock(mm, pmd);
 		ret = 0;
-		set = false;
 		if (pmd_none(*pmd)) {
 			if (userfaultfd_missing(vma)) {
 				spin_unlock(ptl);
+				pte_free(mm, pgtable);
+				put_huge_zero_page();
 				ret = handle_userfault(vma, address, flags,
 						       VM_UFFD_MISSING);
 				VM_BUG_ON(ret & VM_FAULT_FALLBACK);
@@ -849,11 +849,9 @@
 						   haddr, pmd,
 						   zero_page);
 				spin_unlock(ptl);
-				set = true;
 			}
-		} else
+		} else {
 			spin_unlock(ptl);
-		if (!set) {
 			pte_free(mm, pgtable);
 			put_huge_zero_page();
 		}
@@ -1269,6 +1267,15 @@
 	return ret;
 }
 
+/*
+ * FOLL_FORCE or a forced COW break can write even to unwritable pmd's,
+ * but only after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pmd(pmd_t pmd, unsigned int flags)
+{
+	return pmd_write(pmd) || ((flags & FOLL_COW) && pmd_dirty(pmd));
+}
+
 struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
 				   unsigned long addr,
 				   pmd_t *pmd,
@@ -1279,7 +1286,7 @@
 
 	assert_spin_locked(pmd_lockptr(mm, pmd));
 
-	if (flags & FOLL_WRITE && !pmd_write(*pmd))
+	if (flags & FOLL_WRITE && !can_follow_write_pmd(*pmd, flags))
 		goto out;
 
 	/* Avoid dumping huge zero page */
@@ -1294,17 +1301,11 @@
 	VM_BUG_ON_PAGE(!PageHead(page), page);
 	if (flags & FOLL_TOUCH) {
 		pmd_t _pmd;
-		/*
-		 * We should set the dirty bit only for FOLL_WRITE but
-		 * for now the dirty bit in the pmd is meaningless.
-		 * And if the dirty bit will become meaningful and
-		 * we'll only set it with FOLL_WRITE, an atomic
-		 * set_bit will be required on the pmd to set the
-		 * young bit, instead of the current set_pmd_at.
-		 */
-		_pmd = pmd_mkyoung(pmd_mkdirty(*pmd));
+		_pmd = pmd_mkyoung(*pmd);
+		if (flags & FOLL_WRITE)
+			_pmd = pmd_mkdirty(_pmd);
 		if (pmdp_set_access_flags(vma, addr & HPAGE_PMD_MASK,
-					  pmd, _pmd,  1))
+					  pmd, _pmd, flags & FOLL_WRITE))
 			update_mmu_cache_pmd(vma, addr, pmd);
 	}
 	if ((flags & FOLL_MLOCK) && (vma->vm_flags & VM_LOCKED)) {
@@ -1339,9 +1340,6 @@
 	bool was_writable;
 	int flags = 0;
 
-	/* A PROT_NONE fault should not end up here */
-	BUG_ON(!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)));
-
 	ptl = pmd_lock(mm, pmdp);
 	if (unlikely(!pmd_same(pmd, *pmdp)))
 		goto out_unlock;
@@ -1353,8 +1351,11 @@
 	 */
 	if (unlikely(pmd_trans_migrating(*pmdp))) {
 		page = pmd_page(*pmdp);
+		if (!get_page_unless_zero(page))
+			goto out_unlock;
 		spin_unlock(ptl);
 		wait_on_page_locked(page);
+		put_page(page);
 		goto out;
 	}
 
@@ -1386,9 +1387,12 @@
 
 	/* Migration could have started since the pmd_trans_migrating check */
 	if (!page_locked) {
+		page_nid = -1;
+		if (!get_page_unless_zero(page))
+			goto out_unlock;
 		spin_unlock(ptl);
 		wait_on_page_locked(page);
-		page_nid = -1;
+		put_page(page);
 		goto out;
 	}
 
@@ -1501,7 +1505,7 @@
 	spinlock_t *old_ptl, *new_ptl;
 	int ret = 0;
 	pmd_t pmd;
-
+	bool force_flush = false;
 	struct mm_struct *mm = vma->vm_mm;
 
 	if ((old_addr & ~HPAGE_PMD_MASK) ||
@@ -1529,6 +1533,8 @@
 		if (new_ptl != old_ptl)
 			spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
 		pmd = pmdp_huge_get_and_clear(mm, old_addr, old_pmd);
+		if (pmd_present(pmd))
+			force_flush = true;
 		VM_BUG_ON(!pmd_none(*new_pmd));
 
 		if (pmd_move_must_withdraw(new_ptl, old_ptl)) {
@@ -1537,6 +1543,8 @@
 			pgtable_trans_huge_deposit(mm, new_pmd, pgtable);
 		}
 		set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd));
+		if (force_flush)
+			flush_tlb_range(vma, old_addr, old_addr + PMD_SIZE);
 		if (new_ptl != old_ptl)
 			spin_unlock(new_ptl);
 		spin_unlock(old_ptl);
@@ -1556,35 +1564,69 @@
 {
 	struct mm_struct *mm = vma->vm_mm;
 	spinlock_t *ptl;
+	pmd_t entry;
+	bool preserve_write;
+
 	int ret = 0;
 
-	if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
-		pmd_t entry;
-		bool preserve_write = prot_numa && pmd_write(*pmd);
-		ret = 1;
+	if (__pmd_trans_huge_lock(pmd, vma, &ptl) != 1)
+		return 0;
 
-		/*
-		 * Avoid trapping faults against the zero page. The read-only
-		 * data is likely to be read-cached on the local CPU and
-		 * local/remote hits to the zero page are not interesting.
-		 */
-		if (prot_numa && is_huge_zero_pmd(*pmd)) {
-			spin_unlock(ptl);
-			return ret;
-		}
+	preserve_write = prot_numa && pmd_write(*pmd);
+	ret = 1;
 
-		if (!prot_numa || !pmd_protnone(*pmd)) {
-			entry = pmdp_huge_get_and_clear_notify(mm, addr, pmd);
-			entry = pmd_modify(entry, newprot);
-			if (preserve_write)
-				entry = pmd_mkwrite(entry);
-			ret = HPAGE_PMD_NR;
-			set_pmd_at(mm, addr, pmd, entry);
-			BUG_ON(!preserve_write && pmd_write(entry));
-		}
-		spin_unlock(ptl);
-	}
+	/*
+	 * Avoid trapping faults against the zero page. The read-only
+	 * data is likely to be read-cached on the local CPU and
+	 * local/remote hits to the zero page are not interesting.
+	 */
+	if (prot_numa && is_huge_zero_pmd(*pmd))
+		goto unlock;
 
+	if (prot_numa && pmd_protnone(*pmd))
+		goto unlock;
+
+	/*
+	 * In case prot_numa, we are under down_read(mmap_sem). It's critical
+	 * to not clear pmd intermittently to avoid race with MADV_DONTNEED
+	 * which is also under down_read(mmap_sem):
+	 *
+	 *	CPU0:				CPU1:
+	 *				change_huge_pmd(prot_numa=1)
+	 *				 pmdp_huge_get_and_clear_notify()
+	 * madvise_dontneed()
+	 *  zap_pmd_range()
+	 *   pmd_trans_huge(*pmd) == 0 (without ptl)
+	 *   // skip the pmd
+	 *				 set_pmd_at();
+	 *				 // pmd is re-established
+	 *
+	 * The race makes MADV_DONTNEED miss the huge pmd and don't clear it
+	 * which may break userspace.
+	 *
+	 * pmdp_invalidate() is required to make sure we don't miss
+	 * dirty/young flags set by hardware.
+	 */
+	entry = *pmd;
+	pmdp_invalidate(vma, addr, pmd);
+
+	/*
+	 * Recover dirty/young flags.  It relies on pmdp_invalidate to not
+	 * corrupt them.
+	 */
+	if (pmd_dirty(*pmd))
+		entry = pmd_mkdirty(entry);
+	if (pmd_young(*pmd))
+		entry = pmd_mkyoung(entry);
+
+	entry = pmd_modify(entry, newprot);
+	if (preserve_write)
+		entry = pmd_mkwrite(entry);
+	ret = HPAGE_PMD_NR;
+	set_pmd_at(mm, addr, pmd, entry);
+	BUG_ON(!preserve_write && pmd_write(entry));
+unlock:
+	spin_unlock(ptl);
 	return ret;
 }
 
@@ -2088,7 +2130,7 @@
 
 static inline int khugepaged_test_exit(struct mm_struct *mm)
 {
-	return atomic_read(&mm->mm_users) == 0;
+	return atomic_read(&mm->mm_users) == 0 || !mmget_still_valid(mm);
 }
 
 int __khugepaged_enter(struct mm_struct *mm)
@@ -2101,7 +2143,7 @@
 		return -ENOMEM;
 
 	/* __khugepaged_exit() must not run from under us */
-	VM_BUG_ON_MM(khugepaged_test_exit(mm), mm);
+	VM_BUG_ON_MM(atomic_read(&mm->mm_users) == 0, mm);
 	if (unlikely(test_and_set_bit(MMF_VM_HUGEPAGE, &mm->flags))) {
 		free_mm_slot(mm_slot);
 		return 0;
@@ -2134,10 +2176,9 @@
 		 * page fault if needed.
 		 */
 		return 0;
-	if (vma->vm_ops)
+	if (vma->vm_ops || (vm_flags & VM_NO_THP))
 		/* khugepaged not yet working on file or special mappings */
 		return 0;
-	VM_BUG_ON_VMA(vm_flags & VM_NO_THP, vma);
 	hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
 	hend = vma->vm_end & HPAGE_PMD_MASK;
 	if (hstart < hend)
@@ -2498,8 +2539,7 @@
 		return false;
 	if (is_vma_temporary_stack(vma))
 		return false;
-	VM_BUG_ON_VMA(vma->vm_flags & VM_NO_THP, vma);
-	return true;
+	return !(vma->vm_flags & VM_NO_THP);
 }
 
 static void collapse_huge_page(struct mm_struct *mm,
--- linux-4.4.0.orig/mm/hugetlb.c
+++ linux-4.4.0/mm/hugetlb.c
@@ -66,6 +66,21 @@
 static int num_fault_mutexes;
 struct mutex *hugetlb_fault_mutex_table ____cacheline_aligned_in_smp;
 
+static inline bool PageHugeFreed(struct page *head)
+{
+	return page_private(head + 4) == -1UL;
+}
+
+static inline void SetPageHugeFreed(struct page *head)
+{
+	set_page_private(head + 4, -1UL);
+}
+
+static inline void ClearPageHugeFreed(struct page *head)
+{
+	set_page_private(head + 4, 0);
+}
+
 /* Forward declaration */
 static int hugetlb_acct_memory(struct hstate *h, long delta);
 
@@ -841,6 +856,7 @@
 	list_move(&page->lru, &h->hugepage_freelists[nid]);
 	h->free_huge_pages++;
 	h->free_huge_pages_node[nid]++;
+	SetPageHugeFreed(page);
 }
 
 static struct page *dequeue_huge_page_node(struct hstate *h, int nid)
@@ -858,6 +874,7 @@
 		return NULL;
 	list_move(&page->lru, &h->hugepage_activelist);
 	set_page_refcounted(page);
+	ClearPageHugeFreed(page);
 	h->free_huge_pages--;
 	h->free_huge_pages_node[nid]--;
 	return page;
@@ -1142,14 +1159,16 @@
 static void update_and_free_page(struct hstate *h, struct page *page)
 {
 	int i;
+	struct page *subpage = page;
 
 	if (hstate_is_gigantic(h) && !gigantic_page_supported())
 		return;
 
 	h->nr_huge_pages--;
 	h->nr_huge_pages_node[page_to_nid(page)]--;
-	for (i = 0; i < pages_per_huge_page(h); i++) {
-		page[i].flags &= ~(1 << PG_locked | 1 << PG_error |
+	for (i = 0; i < pages_per_huge_page(h);
+	     i++, subpage = mem_map_next(subpage, page, i)) {
+		subpage->flags &= ~(1 << PG_locked | 1 << PG_error |
 				1 << PG_referenced | 1 << PG_dirty |
 				1 << PG_active | 1 << PG_private |
 				1 << PG_writeback);
@@ -1184,12 +1203,11 @@
  */
 bool page_huge_active(struct page *page)
 {
-	VM_BUG_ON_PAGE(!PageHuge(page), page);
-	return PageHead(page) && PagePrivate(&page[1]);
+	return PageHeadHuge(page) && PagePrivate(&page[1]);
 }
 
 /* never called for tail page */
-static void set_page_huge_active(struct page *page)
+void set_page_huge_active(struct page *page)
 {
 	VM_BUG_ON_PAGE(!PageHeadHuge(page), page);
 	SetPagePrivate(&page[1]);
@@ -1221,12 +1239,23 @@
 	ClearPagePrivate(page);
 
 	/*
-	 * A return code of zero implies that the subpool will be under its
-	 * minimum size if the reservation is not restored after page is free.
-	 * Therefore, force restore_reserve operation.
+	 * If PagePrivate() was set on page, page allocation consumed a
+	 * reservation.  If the page was associated with a subpool, there
+	 * would have been a page reserved in the subpool before allocation
+	 * via hugepage_subpool_get_pages().  Since we are 'restoring' the
+	 * reservtion, do not call hugepage_subpool_put_pages() as this will
+	 * remove the reserved page from the subpool.
 	 */
-	if (hugepage_subpool_put_pages(spool, 1) == 0)
-		restore_reserve = true;
+	if (!restore_reserve) {
+		/*
+		 * A return code of zero implies that the subpool will be
+		 * under its minimum size if the reservation is not restored
+		 * after page is free.  Therefore, force restore_reserve
+		 * operation.
+		 */
+		if (hugepage_subpool_put_pages(spool, 1) == 0)
+			restore_reserve = true;
+	}
 
 	spin_lock(&hugetlb_lock);
 	clear_page_huge_active(page);
@@ -1256,6 +1285,7 @@
 	set_hugetlb_cgroup(page, NULL);
 	h->nr_huge_pages++;
 	h->nr_huge_pages_node[nid]++;
+	ClearPageHugeFreed(page);
 	spin_unlock(&hugetlb_lock);
 	put_page(page); /* free it into the hugepage allocator */
 }
@@ -1414,14 +1444,36 @@
  */
 static void dissolve_free_huge_page(struct page *page)
 {
+retry:
 	spin_lock(&hugetlb_lock);
 	if (PageHuge(page) && !page_count(page)) {
-		struct hstate *h = page_hstate(page);
-		int nid = page_to_nid(page);
-		list_del(&page->lru);
+		struct page *head = compound_head(page);
+		struct hstate *h = page_hstate(head);
+		int nid = page_to_nid(head);
+
+		/*
+		 * We should make sure that the page is already on the free list
+		 * when it is dissolved.
+		 */
+		if (unlikely(!PageHugeFreed(head))) {
+			spin_unlock(&hugetlb_lock);
+			cond_resched();
+
+			/*
+			 * Theoretically, we should return -EBUSY when we
+			 * encounter this race. In fact, we have a chance
+			 * to successfully dissolve the page if we do a
+			 * retry. Because the race window is quite small.
+			 * If we seize this opportunity, it is an optimization
+			 * for increasing the success rate of dissolving page.
+			 */
+			goto retry;
+		}
+
+		list_del(&head->lru);
 		h->free_huge_pages--;
 		h->free_huge_pages_node[nid]--;
-		update_and_free_page(h, page);
+		update_and_free_page(h, head);
 	}
 	spin_unlock(&hugetlb_lock);
 }
@@ -1429,7 +1481,8 @@
 /*
  * Dissolve free hugepages in a given pfn range. Used by memory hotplug to
  * make specified memory blocks removable from the system.
- * Note that start_pfn should aligned with (minimum) hugepage size.
+ * Note that this will dissolve a free gigantic hugepage completely, if any
+ * part of it lies within the given range.
  */
 void dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
 {
@@ -1438,7 +1491,6 @@
 	if (!hugepages_supported())
 		return;
 
-	VM_BUG_ON(!IS_ALIGNED(start_pfn, 1 << minimum_order));
 	for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order)
 		dissolve_free_huge_page(pfn_to_page(pfn));
 }
@@ -1722,23 +1774,32 @@
 }
 
 /*
- * When releasing a hugetlb pool reservation, any surplus pages that were
- * allocated to satisfy the reservation must be explicitly freed if they were
- * never used.
- * Called with hugetlb_lock held.
+ * This routine has two main purposes:
+ * 1) Decrement the reservation count (resv_huge_pages) by the value passed
+ *    in unused_resv_pages.  This corresponds to the prior adjustments made
+ *    to the associated reservation map.
+ * 2) Free any unused surplus pages that may have been allocated to satisfy
+ *    the reservation.  As many as unused_resv_pages may be freed.
+ *
+ * Called with hugetlb_lock held.  However, the lock could be dropped (and
+ * reacquired) during calls to cond_resched_lock.  Whenever dropping the lock,
+ * we must make sure nobody else can claim pages we are in the process of
+ * freeing.  Do this by ensuring resv_huge_page always is greater than the
+ * number of huge pages we plan to free when dropping the lock.
  */
 static void return_unused_surplus_pages(struct hstate *h,
 					unsigned long unused_resv_pages)
 {
 	unsigned long nr_pages;
 
-	/* Uncommit the reservation */
-	h->resv_huge_pages -= unused_resv_pages;
-
 	/* Cannot return gigantic pages currently */
 	if (hstate_is_gigantic(h))
-		return;
+		goto out;
 
+	/*
+	 * Part (or even all) of the reservation could have been backed
+	 * by pre-allocated pages. Only free surplus pages.
+	 */
 	nr_pages = min(unused_resv_pages, h->surplus_huge_pages);
 
 	/*
@@ -1748,12 +1809,22 @@
 	 * when the nodes with surplus pages have no free pages.
 	 * free_pool_huge_page() will balance the the freed pages across the
 	 * on-line nodes with memory and will handle the hstate accounting.
+	 *
+	 * Note that we decrement resv_huge_pages as we free the pages.  If
+	 * we drop the lock, resv_huge_pages will still be sufficiently large
+	 * to cover subsequent pages we may free.
 	 */
 	while (nr_pages--) {
+		h->resv_huge_pages--;
+		unused_resv_pages--;
 		if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1))
-			break;
+			goto out;
 		cond_resched_lock(&hugetlb_lock);
 	}
+
+out:
+	/* Fully uncommit the reservation */
+	h->resv_huge_pages -= unused_resv_pages;
 }
 
 
@@ -2018,6 +2089,7 @@
 		 */
 		if (hstate_is_gigantic(h))
 			adjust_managed_page_count(page, 1 << h->order);
+		cond_resched();
 	}
 }
 
@@ -2170,6 +2242,10 @@
 		 * and reducing the surplus.
 		 */
 		spin_unlock(&hugetlb_lock);
+
+		/* yield cpu to avoid soft lockup */
+		cond_resched();
+
 		if (hstate_is_gigantic(h))
 			ret = alloc_fresh_gigantic_page(h, nodes_allowed);
 		else
@@ -2450,8 +2526,10 @@
 		return -ENOMEM;
 
 	retval = sysfs_create_group(hstate_kobjs[hi], hstate_attr_group);
-	if (retval)
+	if (retval) {
 		kobject_put(hstate_kobjs[hi]);
+		hstate_kobjs[hi] = NULL;
+	}
 
 	return retval;
 }
@@ -2776,6 +2854,22 @@
 }
 
 #ifdef CONFIG_SYSCTL
+static int proc_hugetlb_doulongvec_minmax(struct ctl_table *table, int write,
+					  void *buffer, size_t *length,
+					  loff_t *ppos, unsigned long *out)
+{
+	struct ctl_table dup_table;
+
+	/*
+	 * In order to avoid races with __do_proc_doulongvec_minmax(), we
+	 * can duplicate the @table and alter the duplicate of it.
+	 */
+	dup_table = *table;
+	dup_table.data = out;
+
+	return proc_doulongvec_minmax(&dup_table, write, buffer, length, ppos);
+}
+
 static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
 			 struct ctl_table *table, int write,
 			 void __user *buffer, size_t *length, loff_t *ppos)
@@ -2787,9 +2881,8 @@
 	if (!hugepages_supported())
 		return -ENOTSUPP;
 
-	table->data = &tmp;
-	table->maxlen = sizeof(unsigned long);
-	ret = proc_doulongvec_minmax(table, write, buffer, length, ppos);
+	ret = proc_hugetlb_doulongvec_minmax(table, write, buffer, length, ppos,
+					     &tmp);
 	if (ret)
 		goto out;
 
@@ -2833,9 +2926,8 @@
 	if (write && hstate_is_gigantic(h))
 		return -EINVAL;
 
-	table->data = &tmp;
-	table->maxlen = sizeof(unsigned long);
-	ret = proc_doulongvec_minmax(table, write, buffer, length, ppos);
+	ret = proc_hugetlb_doulongvec_minmax(table, write, buffer, length, ppos,
+					     &tmp);
 	if (ret)
 		goto out;
 
@@ -3078,7 +3170,7 @@
 int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
 			    struct vm_area_struct *vma)
 {
-	pte_t *src_pte, *dst_pte, entry;
+	pte_t *src_pte, *dst_pte, entry, dst_entry;
 	struct page *ptepage;
 	unsigned long addr;
 	int cow;
@@ -3106,15 +3198,30 @@
 			break;
 		}
 
-		/* If the pagetables are shared don't copy or take references */
-		if (dst_pte == src_pte)
+		/*
+		 * If the pagetables are shared don't copy or take references.
+		 * dst_pte == src_pte is the common case of src/dest sharing.
+		 *
+		 * However, src could have 'unshared' and dst shares with
+		 * another vma.  If dst_pte !none, this implies sharing.
+		 * Check here before taking page table lock, and once again
+		 * after taking the lock below.
+		 */
+		dst_entry = huge_ptep_get(dst_pte);
+		if ((dst_pte == src_pte) || !huge_pte_none(dst_entry))
 			continue;
 
 		dst_ptl = huge_pte_lock(h, dst, dst_pte);
 		src_ptl = huge_pte_lockptr(h, src, src_pte);
 		spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
 		entry = huge_ptep_get(src_pte);
-		if (huge_pte_none(entry)) { /* skip none entry */
+		dst_entry = huge_ptep_get(dst_pte);
+		if (huge_pte_none(entry) || !huge_pte_none(dst_entry)) {
+			/*
+			 * Skip if src entry none.  Also, skip in the
+			 * unlikely case dst entry !none as this implies
+			 * sharing with another vma.
+			 */
 			;
 		} else if (unlikely(is_hugetlb_entry_migration(entry) ||
 				    is_hugetlb_entry_hwpoisoned(entry))) {
@@ -3183,8 +3290,11 @@
 			continue;
 
 		ptl = huge_pte_lock(h, mm, ptep);
-		if (huge_pmd_unshare(mm, &address, ptep))
+		if (huge_pmd_unshare(mm, &address, ptep)) {
+			tlb_flush_pmd_range(tlb, address & PUD_MASK, PUD_SIZE);
+			force_flush = 1;
 			goto unlock;
+		}
 
 		pte = huge_ptep_get(ptep);
 		if (huge_pte_none(pte))
@@ -3432,7 +3542,6 @@
 	copy_user_huge_page(new_page, old_page, address, vma,
 			    pages_per_huge_page(h));
 	__SetPageUptodate(new_page);
-	set_page_huge_active(new_page);
 
 	mmun_start = address & huge_page_mask(h);
 	mmun_end = mmun_start + huge_page_size(h);
@@ -3454,6 +3563,7 @@
 				make_huge_pte(vma, new_page, 1));
 		page_remove_rmap(old_page);
 		hugepage_add_new_anon_rmap(new_page, vma, address);
+		set_page_huge_active(new_page);
 		/* Make the old page be freed below */
 		new_page = old_page;
 	}
@@ -3512,6 +3622,12 @@
 		return err;
 	ClearPagePrivate(page);
 
+	/*
+	 * set page dirty so that it will not be removed from cache/file
+	 * by non-hugetlbfs specific code paths.
+	 */
+	set_page_dirty(page);
+
 	spin_lock(&inode->i_lock);
 	inode->i_blocks += blocks_per_huge_page(h);
 	spin_unlock(&inode->i_lock);
@@ -3529,6 +3645,7 @@
 	struct page *page;
 	pte_t new_pte;
 	spinlock_t *ptl;
+	bool new_page = false;
 
 	/*
 	 * Currently, we are forced to kill the process in the event the
@@ -3562,7 +3679,7 @@
 		}
 		clear_huge_page(page, address, pages_per_huge_page(h));
 		__SetPageUptodate(page);
-		set_page_huge_active(page);
+		new_page = true;
 
 		if (vma->vm_flags & VM_MAYSHARE) {
 			int err = huge_add_to_page_cache(page, mapping, idx);
@@ -3587,7 +3704,7 @@
 		 * So we need to block hugepage fault by PG_hwpoison bit check.
 		 */
 		if (unlikely(PageHWPoison(page))) {
-			ret = VM_FAULT_HWPOISON |
+			ret = VM_FAULT_HWPOISON_LARGE |
 				VM_FAULT_SET_HINDEX(hstate_index(h));
 			goto backout_unlocked;
 		}
@@ -3634,6 +3751,15 @@
 	}
 
 	spin_unlock(ptl);
+
+	/*
+	 * Only make newly allocated pages active.  Existing pages found
+	 * in the pagecache could be !page_huge_active() if they have been
+	 * isolated for migration.
+	 */
+	if (new_page)
+		set_page_huge_active(page);
+
 	unlock_page(page);
 out:
 	return ret;
@@ -3647,21 +3773,14 @@
 }
 
 #ifdef CONFIG_SMP
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
-			    struct vm_area_struct *vma,
-			    struct address_space *mapping,
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
 			    pgoff_t idx, unsigned long address)
 {
 	unsigned long key[2];
 	u32 hash;
 
-	if (vma->vm_flags & VM_SHARED) {
-		key[0] = (unsigned long) mapping;
-		key[1] = idx;
-	} else {
-		key[0] = (unsigned long) mm;
-		key[1] = address >> huge_page_shift(h);
-	}
+	key[0] = (unsigned long) mapping;
+	key[1] = idx;
 
 	hash = jhash2((u32 *)&key, sizeof(key)/sizeof(u32), 0);
 
@@ -3672,9 +3791,7 @@
  * For uniprocesor systems we always use a single mutex, so just
  * return 0 and avoid the hashing overhead.
  */
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
-			    struct vm_area_struct *vma,
-			    struct address_space *mapping,
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
 			    pgoff_t idx, unsigned long address)
 {
 	return 0;
@@ -3720,7 +3837,7 @@
 	 * get spurious allocation failures if two CPUs race to instantiate
 	 * the same page in the page cache.
 	 */
-	hash = hugetlb_fault_mutex_hash(h, mm, vma, mapping, idx, address);
+	hash = hugetlb_fault_mutex_hash(h, mapping, idx, address);
 	mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
 	entry = huge_ptep_get(ptep);
@@ -3828,6 +3945,7 @@
 	unsigned long vaddr = *position;
 	unsigned long remainder = *nr_pages;
 	struct hstate *h = hstate_vma(vma);
+	int err = -EFAULT;
 
 	while (vaddr < vma->vm_end && remainder) {
 		pte_t *pte;
@@ -3899,6 +4017,19 @@
 
 		pfn_offset = (vaddr & ~huge_page_mask(h)) >> PAGE_SHIFT;
 		page = pte_page(huge_ptep_get(pte));
+
+		/*
+		 * Instead of doing 'try_get_page()' below in the same_page
+		 * loop, just check the count once here.
+		 */
+		if (unlikely(page_count(page) <= 0)) {
+			if (pages) {
+				spin_unlock(ptl);
+				remainder = 0;
+				err = -ENOMEM;
+				break;
+			}
+		}
 same_page:
 		if (pages) {
 			pages[i] = mem_map_offset(page, pfn_offset);
@@ -3925,7 +4056,7 @@
 	*nr_pages = remainder;
 	*position = vaddr;
 
-	return i ? i : -EFAULT;
+	return i ? i : err;
 }
 
 unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
@@ -4007,6 +4138,14 @@
 	struct resv_map *resv_map;
 	long gbl_reserve;
 
+	/* This should never happen */
+	if (from > to) {
+#ifdef CONFIG_DEBUG_VM
+		WARN(1, "%s called with a negative range\n", __func__);
+#endif
+		return -EINVAL;
+	}
+
 	/*
 	 * Only apply hugepage reservation if asked. At fault time, an
 	 * attempt will be made for VM_NORESERVE to allocate a page
@@ -4096,7 +4235,9 @@
 	return 0;
 out_err:
 	if (!vma || vma->vm_flags & VM_MAYSHARE)
-		region_abort(resv_map, from, to);
+		/* Don't call region_abort if region_chg failed */
+		if (chg >= 0)
+			region_abort(resv_map, from, to);
 	if (vma && is_vma_resv_set(vma, HPAGE_RESV_OWNER))
 		kref_put(&resv_map->refs, resv_map_release);
 	return ret;
@@ -4170,12 +4311,39 @@
 	/*
 	 * check on proper vm_flags and page table alignment
 	 */
-	if (vma->vm_flags & VM_MAYSHARE &&
-	    vma->vm_start <= base && end <= vma->vm_end)
+	if (vma->vm_flags & VM_MAYSHARE && range_in_vma(vma, base, end))
 		return true;
 	return false;
 }
 
+#define ALIGN_DOWN(x, a)	__ALIGN_KERNEL((x) - ((a) - 1), (a))
+/*
+ * Determine if start,end range within vma could be mapped by shared pmd.
+ * If yes, adjust start and end to cover range associated with possible
+ * shared pmd mappings.
+ */
+void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma,
+				unsigned long *start, unsigned long *end)
+{
+	unsigned long v_start = ALIGN(vma->vm_start, PUD_SIZE),
+		v_end = ALIGN_DOWN(vma->vm_end, PUD_SIZE);
+
+	/*
+	 * vma need span at least one aligned PUD size and the start,end range
+	 * must at least partialy within it.
+	 */
+	if (!(vma->vm_flags & VM_MAYSHARE) || !(v_end > v_start) ||
+		(*end <= v_start) || (*start >= v_end))
+		return;
+
+	/* Extend the range to be PUD aligned for a worst case scenario */
+	if (*start > v_start)
+		*start = ALIGN_DOWN(*start, PUD_SIZE);
+
+	if (*end < v_end)
+		*end = ALIGN(*end, PUD_SIZE);
+}
+
 /*
  * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc()
  * and returns the corresponding pte. While this is not necessary for the
@@ -4209,7 +4377,6 @@
 		if (saddr) {
 			spte = huge_pte_offset(svma->vm_mm, saddr);
 			if (spte) {
-				mm_inc_nr_pmds(mm);
 				get_page(virt_to_page(spte));
 				break;
 			}
@@ -4224,9 +4391,9 @@
 	if (pud_none(*pud)) {
 		pud_populate(mm, pud,
 				(pmd_t *)((unsigned long)spte & PAGE_MASK));
+		mm_inc_nr_pmds(mm);
 	} else {
 		put_page(virt_to_page(spte));
-		mm_inc_nr_pmds(mm);
 	}
 	spin_unlock(ptl);
 out:
@@ -4273,6 +4440,11 @@
 {
 	return 0;
 }
+
+void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma,
+				unsigned long *start, unsigned long *end)
+{
+}
 #define want_pmd_share()	(0)
 #endif /* CONFIG_ARCH_WANT_HUGE_PMD_SHARE */
 
@@ -4339,6 +4511,7 @@
 {
 	struct page *page = NULL;
 	spinlock_t *ptl;
+	pte_t pte;
 retry:
 	ptl = pmd_lockptr(mm, pmd);
 	spin_lock(ptl);
@@ -4348,12 +4521,13 @@
 	 */
 	if (!pmd_huge(*pmd))
 		goto out;
-	if (pmd_present(*pmd)) {
+	pte = huge_ptep_get((pte_t *)pmd);
+	if (pte_present(pte)) {
 		page = pmd_page(*pmd) + ((address & ~PMD_MASK) >> PAGE_SHIFT);
 		if (flags & FOLL_GET)
 			get_page(page);
 	} else {
-		if (is_hugetlb_entry_migration(huge_ptep_get((pte_t *)pmd))) {
+		if (is_hugetlb_entry_migration(pte)) {
 			spin_unlock(ptl);
 			__migration_entry_wait(mm, (pte_t *)pmd, ptl);
 			goto retry;
@@ -4417,9 +4591,9 @@
 {
 	bool ret = true;
 
-	VM_BUG_ON_PAGE(!PageHead(page), page);
 	spin_lock(&hugetlb_lock);
-	if (!page_huge_active(page) || !get_page_unless_zero(page)) {
+	if (!PageHeadHuge(page) || !page_huge_active(page) ||
+	    !get_page_unless_zero(page)) {
 		ret = false;
 		goto unlock;
 	}
--- linux-4.4.0.orig/mm/hugetlb_cgroup.c
+++ linux-4.4.0/mm/hugetlb_cgroup.c
@@ -180,7 +180,7 @@
 again:
 	rcu_read_lock();
 	h_cg = hugetlb_cgroup_from_task(current);
-	if (!css_tryget_online(&h_cg->css)) {
+	if (!css_tryget(&h_cg->css)) {
 		rcu_read_unlock();
 		goto again;
 	}
--- linux-4.4.0.orig/mm/init-mm.c
+++ linux-4.4.0/mm/init-mm.c
@@ -6,6 +6,7 @@
 #include <linux/cpumask.h>
 
 #include <linux/atomic.h>
+#include <linux/user_namespace.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 
@@ -21,5 +22,6 @@
 	.mmap_sem	= __RWSEM_INITIALIZER(init_mm.mmap_sem),
 	.page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
 	.mmlist		= LIST_HEAD_INIT(init_mm.mmlist),
+	.user_ns	= &init_user_ns,
 	INIT_MM_CONTEXT(init_mm)
 };
--- linux-4.4.0.orig/mm/internal.h
+++ linux-4.4.0/mm/internal.h
@@ -22,7 +22,8 @@
  */
 #define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\
 			__GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\
-			__GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC)
+			__GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\
+			__GFP_ATOMIC)
 
 /* The GFP flags allowed during early boot */
 #define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS))
@@ -80,7 +81,8 @@
 	 * speculative page access (like in
 	 * page_cache_get_speculative()) on tail pages.
 	 */
-	VM_BUG_ON_PAGE(atomic_read(&compound_head(page)->_count) <= 0, page);
+	VM_BUG_ON_PAGE(page_ref_zero_or_close_to_overflow(compound_head(page)),
+		       page);
 	if (get_page_head)
 		atomic_inc(&compound_head(page)->_count);
 	get_huge_page_tail(page);
@@ -105,7 +107,7 @@
 		 * Getting a normal page or the head of a compound page
 		 * requires to already have an elevated page->_count.
 		 */
-		VM_BUG_ON_PAGE(atomic_read(&page->_count) <= 0, page);
+		VM_BUG_ON_PAGE(page_ref_zero_or_close_to_overflow(page), page);
 		atomic_inc(&page->_count);
 	}
 }
@@ -205,9 +207,10 @@
 	unsigned long last_migrated_pfn;/* Not yet flushed page being freed */
 	enum migrate_mode mode;		/* Async or sync migration mode */
 	bool ignore_skip_hint;		/* Scan blocks even if marked skip */
+	bool whole_zone;		/* Whole zone has been scanned */
 	int order;			/* order a direct compactor needs */
 	const gfp_t gfp_mask;		/* gfp mask of a direct compactor */
-	const int alloc_flags;		/* alloc flags of a direct compactor */
+	const unsigned int alloc_flags;	/* alloc flags of a direct compactor */
 	const int classzone_idx;	/* zone index of a direct compactor */
 	struct zone *zone;
 	int contended;			/* Signal need_sched() or lock
@@ -254,11 +257,6 @@
  */
 #define page_order_unsafe(page)		READ_ONCE(page_private(page))
 
-static inline bool is_cow_mapping(vm_flags_t flags)
-{
-	return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
-}
-
 /* mm/util.c */
 void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
 		struct vm_area_struct *prev, struct rb_node *rb_parent);
@@ -452,6 +450,7 @@
 #ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
 void try_to_unmap_flush(void);
 void try_to_unmap_flush_dirty(void);
+void flush_tlb_batched_pending(struct mm_struct *mm);
 #else
 static inline void try_to_unmap_flush(void)
 {
@@ -459,6 +458,8 @@
 static inline void try_to_unmap_flush_dirty(void)
 {
 }
-
+static inline void flush_tlb_batched_pending(struct mm_struct *mm)
+{
+}
 #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
 #endif	/* __MM_INTERNAL_H */
--- linux-4.4.0.orig/mm/kasan/kasan.c
+++ linux-4.4.0/mm/kasan/kasan.c
@@ -252,32 +252,48 @@
 	return memory_is_poisoned_n(addr, size);
 }
 
-
-static __always_inline void check_memory_region(unsigned long addr,
-						size_t size, bool write)
+static __always_inline void check_memory_region_inline(unsigned long addr,
+						size_t size, bool write,
+						unsigned long ret_ip)
 {
 	if (unlikely(size == 0))
 		return;
 
 	if (unlikely((void *)addr <
 		kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) {
-		kasan_report(addr, size, write, _RET_IP_);
+		kasan_report(addr, size, write, ret_ip);
 		return;
 	}
 
 	if (likely(!memory_is_poisoned(addr, size)))
 		return;
 
-	kasan_report(addr, size, write, _RET_IP_);
+	kasan_report(addr, size, write, ret_ip);
 }
 
-void __asan_loadN(unsigned long addr, size_t size);
-void __asan_storeN(unsigned long addr, size_t size);
+static void check_memory_region(unsigned long addr,
+				size_t size, bool write,
+				unsigned long ret_ip)
+{
+	check_memory_region_inline(addr, size, write, ret_ip);
+}
+
+void kasan_check_read(const void *p, unsigned int size)
+{
+	check_memory_region((unsigned long)p, size, false, _RET_IP_);
+}
+EXPORT_SYMBOL(kasan_check_read);
+
+void kasan_check_write(const void *p, unsigned int size)
+{
+	check_memory_region((unsigned long)p, size, true, _RET_IP_);
+}
+EXPORT_SYMBOL(kasan_check_write);
 
 #undef memset
 void *memset(void *addr, int c, size_t len)
 {
-	__asan_storeN((unsigned long)addr, len);
+	check_memory_region((unsigned long)addr, len, true, _RET_IP_);
 
 	return __memset(addr, c, len);
 }
@@ -285,8 +301,8 @@
 #undef memmove
 void *memmove(void *dest, const void *src, size_t len)
 {
-	__asan_loadN((unsigned long)src, len);
-	__asan_storeN((unsigned long)dest, len);
+	check_memory_region((unsigned long)src, len, false, _RET_IP_);
+	check_memory_region((unsigned long)dest, len, true, _RET_IP_);
 
 	return __memmove(dest, src, len);
 }
@@ -294,8 +310,8 @@
 #undef memcpy
 void *memcpy(void *dest, const void *src, size_t len)
 {
-	__asan_loadN((unsigned long)src, len);
-	__asan_storeN((unsigned long)dest, len);
+	check_memory_region((unsigned long)src, len, false, _RET_IP_);
+	check_memory_region((unsigned long)dest, len, true, _RET_IP_);
 
 	return __memcpy(dest, src, len);
 }
@@ -427,12 +443,13 @@
 int kasan_module_alloc(void *addr, size_t size)
 {
 	void *ret;
+	size_t scaled_size;
 	size_t shadow_size;
 	unsigned long shadow_start;
 
 	shadow_start = (unsigned long)kasan_mem_to_shadow(addr);
-	shadow_size = round_up(size >> KASAN_SHADOW_SCALE_SHIFT,
-			PAGE_SIZE);
+	scaled_size = (size + KASAN_SHADOW_MASK) >> KASAN_SHADOW_SCALE_SHIFT;
+	shadow_size = round_up(scaled_size, PAGE_SIZE);
 
 	if (WARN_ON(!PAGE_ALIGNED(shadow_start)))
 		return -EINVAL;
@@ -483,22 +500,22 @@
 }
 EXPORT_SYMBOL(__asan_unregister_globals);
 
-#define DEFINE_ASAN_LOAD_STORE(size)				\
-	void __asan_load##size(unsigned long addr)		\
-	{							\
-		check_memory_region(addr, size, false);		\
-	}							\
-	EXPORT_SYMBOL(__asan_load##size);			\
-	__alias(__asan_load##size)				\
-	void __asan_load##size##_noabort(unsigned long);	\
-	EXPORT_SYMBOL(__asan_load##size##_noabort);		\
-	void __asan_store##size(unsigned long addr)		\
-	{							\
-		check_memory_region(addr, size, true);		\
-	}							\
-	EXPORT_SYMBOL(__asan_store##size);			\
-	__alias(__asan_store##size)				\
-	void __asan_store##size##_noabort(unsigned long);	\
+#define DEFINE_ASAN_LOAD_STORE(size)					\
+	void __asan_load##size(unsigned long addr)			\
+	{								\
+		check_memory_region_inline(addr, size, false, _RET_IP_);\
+	}								\
+	EXPORT_SYMBOL(__asan_load##size);				\
+	__alias(__asan_load##size)					\
+	void __asan_load##size##_noabort(unsigned long);		\
+	EXPORT_SYMBOL(__asan_load##size##_noabort);			\
+	void __asan_store##size(unsigned long addr)			\
+	{								\
+		check_memory_region_inline(addr, size, true, _RET_IP_);	\
+	}								\
+	EXPORT_SYMBOL(__asan_store##size);				\
+	__alias(__asan_store##size)					\
+	void __asan_store##size##_noabort(unsigned long);		\
 	EXPORT_SYMBOL(__asan_store##size##_noabort)
 
 DEFINE_ASAN_LOAD_STORE(1);
@@ -509,7 +526,7 @@
 
 void __asan_loadN(unsigned long addr, size_t size)
 {
-	check_memory_region(addr, size, false);
+	check_memory_region(addr, size, false, _RET_IP_);
 }
 EXPORT_SYMBOL(__asan_loadN);
 
@@ -519,7 +536,7 @@
 
 void __asan_storeN(unsigned long addr, size_t size)
 {
-	check_memory_region(addr, size, true);
+	check_memory_region(addr, size, true, _RET_IP_);
 }
 EXPORT_SYMBOL(__asan_storeN);
 
@@ -548,5 +565,5 @@
 	return 0;
 }
 
-module_init(kasan_memhotplug_init);
+core_initcall(kasan_memhotplug_init);
 #endif
--- linux-4.4.0.orig/mm/kasan/kasan.h
+++ linux-4.4.0/mm/kasan/kasan.h
@@ -52,6 +52,9 @@
 #if KASAN_ABI_VERSION >= 4
 	struct kasan_source_location *location;
 #endif
+#if KASAN_ABI_VERSION >= 5
+	char *odr_indicator;
+#endif
 };
 
 static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
--- linux-4.4.0.orig/mm/kasan/report.c
+++ linux-4.4.0/mm/kasan/report.c
@@ -13,6 +13,7 @@
  *
  */
 
+#include <linux/ftrace.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/printk.h>
@@ -251,6 +252,8 @@
 	if (likely(!kasan_report_enabled()))
 		return;
 
+	disable_trace_on_warning();
+
 	info.access_addr = (void *)addr;
 	info.access_size = size;
 	info.is_write = is_write;
--- linux-4.4.0.orig/mm/kmemleak.c
+++ linux-4.4.0/mm/kmemleak.c
@@ -566,7 +566,7 @@
 	if (in_irq()) {
 		object->pid = 0;
 		strncpy(object->comm, "hardirq", sizeof(object->comm));
-	} else if (in_softirq()) {
+	} else if (in_serving_softirq()) {
 		object->pid = 0;
 		strncpy(object->comm, "softirq", sizeof(object->comm));
 	} else {
@@ -1394,6 +1394,8 @@
 			if (page_count(page) == 0)
 				continue;
 			scan_block(page, page + 1, NULL);
+			if (!(pfn % (MAX_SCAN_SIZE / sizeof(*page))))
+				cond_resched();
 		}
 	}
 	put_online_mems();
@@ -1522,8 +1524,7 @@
 }
 
 /*
- * Stop the automatic memory scanning thread. This function must be called
- * with the scan_mutex held.
+ * Stop the automatic memory scanning thread.
  */
 static void stop_scan_thread(void)
 {
@@ -1786,12 +1787,15 @@
 {
 	stop_scan_thread();
 
+	mutex_lock(&scan_mutex);
 	/*
-	 * Once the scan thread has stopped, it is safe to no longer track
-	 * object freeing. Ordering of the scan thread stopping and the memory
-	 * accesses below is guaranteed by the kthread_stop() function.
+	 * Once it is made sure that kmemleak_scan has stopped, it is safe to no
+	 * longer track object freeing. Ordering of the scan thread stopping and
+	 * the memory accesses below is guaranteed by the kthread_stop()
+	 * function.
 	 */
 	kmemleak_free_enabled = 0;
+	mutex_unlock(&scan_mutex);
 
 	if (!kmemleak_found_leaks)
 		__kmemleak_do_cleanup();
--- linux-4.4.0.orig/mm/ksm.c
+++ linux-4.4.0/mm/ksm.c
@@ -126,9 +126,12 @@
  * struct stable_node - node of the stable rbtree
  * @node: rb node of this ksm page in the stable tree
  * @head: (overlaying parent) &migrate_nodes indicates temporarily on that list
+ * @hlist_dup: linked into the stable_node->hlist with a stable_node chain
  * @list: linked into migrate_nodes, pending placement in the proper node tree
  * @hlist: hlist head of rmap_items using this ksm page
  * @kpfn: page frame number of this ksm page (perhaps temporarily on wrong nid)
+ * @chain_prune_time: time of the last full garbage collection
+ * @rmap_hlist_len: number of rmap_item entries in hlist or STABLE_NODE_CHAIN
  * @nid: NUMA node id of stable tree in which linked (may not match kpfn)
  */
 struct stable_node {
@@ -136,11 +139,24 @@
 		struct rb_node node;	/* when node of stable tree */
 		struct {		/* when listed for migration */
 			struct list_head *head;
-			struct list_head list;
+			struct {
+				struct hlist_node hlist_dup;
+				struct list_head list;
+			};
 		};
 	};
 	struct hlist_head hlist;
-	unsigned long kpfn;
+	union {
+		unsigned long kpfn;
+		unsigned long chain_prune_time;
+	};
+	/*
+	 * STABLE_NODE_CHAIN can be any negative number in
+	 * rmap_hlist_len negative range, but better not -1 to be able
+	 * to reliably detect underflows.
+	 */
+#define STABLE_NODE_CHAIN -1024
+	int rmap_hlist_len;
 #ifdef CONFIG_NUMA
 	int nid;
 #endif
@@ -190,6 +206,7 @@
 
 /* Recently migrated nodes of stable tree, pending proper placement */
 static LIST_HEAD(migrate_nodes);
+#define STABLE_NODE_DUP_HEAD ((struct list_head *)&migrate_nodes.prev)
 
 #define MM_SLOTS_HASH_BITS 10
 static DEFINE_HASHTABLE(mm_slots_hash, MM_SLOTS_HASH_BITS);
@@ -217,6 +234,18 @@
 /* The number of rmap_items in use: to calculate pages_volatile */
 static unsigned long ksm_rmap_items;
 
+/* The number of stable_node chains */
+static unsigned long ksm_stable_node_chains;
+
+/* The number of stable_node dups linked to the stable_node chains */
+static unsigned long ksm_stable_node_dups;
+
+/* Delay in pruning stale stable_node_dups in the stable_node_chains */
+static int ksm_stable_node_chains_prune_millisecs = 2000;
+
+/* Maximum number of page slots sharing a stable node */
+static int ksm_max_page_sharing = 256;
+
 /* Number of pages ksmd should scan in one batch */
 static unsigned int ksm_thread_pages_to_scan = 100;
 
@@ -279,11 +308,51 @@
 	mm_slot_cache = NULL;
 }
 
+static __always_inline bool is_stable_node_chain(struct stable_node *chain)
+{
+	return chain->rmap_hlist_len == STABLE_NODE_CHAIN;
+}
+
+static __always_inline bool is_stable_node_dup(struct stable_node *dup)
+{
+	return dup->head == STABLE_NODE_DUP_HEAD;
+}
+
+static inline void stable_node_chain_add_dup(struct stable_node *dup,
+					     struct stable_node *chain)
+{
+	VM_BUG_ON(is_stable_node_dup(dup));
+	dup->head = STABLE_NODE_DUP_HEAD;
+	VM_BUG_ON(!is_stable_node_chain(chain));
+	hlist_add_head(&dup->hlist_dup, &chain->hlist);
+	ksm_stable_node_dups++;
+}
+
+static inline void __stable_node_dup_del(struct stable_node *dup)
+{
+	VM_BUG_ON(!is_stable_node_dup(dup));
+	hlist_del(&dup->hlist_dup);
+	ksm_stable_node_dups--;
+}
+
+static inline void stable_node_dup_del(struct stable_node *dup)
+{
+	VM_BUG_ON(is_stable_node_chain(dup));
+	if (is_stable_node_dup(dup))
+		__stable_node_dup_del(dup);
+	else
+		rb_erase(&dup->node, root_stable_tree + NUMA(dup->nid));
+#ifdef CONFIG_DEBUG_VM
+	dup->head = NULL;
+#endif
+}
+
 static inline struct rmap_item *alloc_rmap_item(void)
 {
 	struct rmap_item *rmap_item;
 
-	rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL);
+	rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL |
+						__GFP_NORETRY | __GFP_NOWARN);
 	if (rmap_item)
 		ksm_rmap_items++;
 	return rmap_item;
@@ -303,6 +372,8 @@
 
 static inline void free_stable_node(struct stable_node *stable_node)
 {
+	VM_BUG_ON(stable_node->rmap_hlist_len &&
+		  !is_stable_node_chain(stable_node));
 	kmem_cache_free(stable_node_cache, stable_node);
 }
 
@@ -493,25 +564,82 @@
 	return ksm_merge_across_nodes ? 0 : NUMA(pfn_to_nid(kpfn));
 }
 
+static struct stable_node *alloc_stable_node_chain(struct stable_node *dup,
+						   struct rb_root *root)
+{
+	struct stable_node *chain = alloc_stable_node();
+	VM_BUG_ON(is_stable_node_chain(dup));
+	if (likely(chain)) {
+		INIT_HLIST_HEAD(&chain->hlist);
+		chain->chain_prune_time = jiffies;
+		chain->rmap_hlist_len = STABLE_NODE_CHAIN;
+#if defined (CONFIG_DEBUG_VM) && defined(CONFIG_NUMA)
+		chain->nid = -1; /* debug */
+#endif
+		ksm_stable_node_chains++;
+
+		/*
+		 * Put the stable node chain in the first dimension of
+		 * the stable tree and at the same time remove the old
+		 * stable node.
+		 */
+		rb_replace_node(&dup->node, &chain->node, root);
+
+		/*
+		 * Move the old stable node to the second dimension
+		 * queued in the hlist_dup. The invariant is that all
+		 * dup stable_nodes in the chain->hlist point to pages
+		 * that are wrprotected and have the exact same
+		 * content.
+		 */
+		stable_node_chain_add_dup(dup, chain);
+	}
+	return chain;
+}
+
+static inline void free_stable_node_chain(struct stable_node *chain,
+					  struct rb_root *root)
+{
+	rb_erase(&chain->node, root);
+	free_stable_node(chain);
+	ksm_stable_node_chains--;
+}
+
 static void remove_node_from_stable_tree(struct stable_node *stable_node)
 {
 	struct rmap_item *rmap_item;
 
+	/* check it's not STABLE_NODE_CHAIN or negative */
+	BUG_ON(stable_node->rmap_hlist_len < 0);
+
 	hlist_for_each_entry(rmap_item, &stable_node->hlist, hlist) {
 		if (rmap_item->hlist.next)
 			ksm_pages_sharing--;
 		else
 			ksm_pages_shared--;
+		VM_BUG_ON(stable_node->rmap_hlist_len <= 0);
+		stable_node->rmap_hlist_len--;
 		put_anon_vma(rmap_item->anon_vma);
 		rmap_item->address &= PAGE_MASK;
 		cond_resched();
 	}
 
+	/*
+	 * We need the second aligned pointer of the migrate_nodes
+	 * list_head to stay clear from the rb_parent_color union
+	 * (aligned and different than any node) and also different
+	 * from &migrate_nodes. This will verify that future list.h changes
+	 * don't break STABLE_NODE_DUP_HEAD.
+	 */
+#if GCC_VERSION >= 40903 /* only recent gcc can handle it */
+	BUILD_BUG_ON(STABLE_NODE_DUP_HEAD <= &migrate_nodes);
+	BUILD_BUG_ON(STABLE_NODE_DUP_HEAD >= &migrate_nodes + 1);
+#endif
+
 	if (stable_node->head == &migrate_nodes)
 		list_del(&stable_node->list);
 	else
-		rb_erase(&stable_node->node,
-			 root_stable_tree + NUMA(stable_node->nid));
+		stable_node_dup_del(stable_node);
 	free_stable_node(stable_node);
 }
 
@@ -630,6 +758,8 @@
 			ksm_pages_sharing--;
 		else
 			ksm_pages_shared--;
+		VM_BUG_ON(stable_node->rmap_hlist_len <= 0);
+		stable_node->rmap_hlist_len--;
 
 		put_anon_vma(rmap_item->anon_vma);
 		rmap_item->address &= PAGE_MASK;
@@ -713,13 +843,13 @@
 		return 0;
 	}
 
-	if (WARN_ON_ONCE(page_mapped(page))) {
-		/*
-		 * This should not happen: but if it does, just refuse to let
-		 * merge_across_nodes be switched - there is no need to panic.
-		 */
-		err = -EBUSY;
-	} else {
+	/*
+	 * Page could be still mapped if this races with __mmput() running in
+	 * between ksm_exit() and exit_mmap(). Just refuse to let
+	 * merge_across_nodes/max_page_sharing be switched.
+	 */
+	err = -EBUSY;
+	if (!page_mapped(page)) {
 		/*
 		 * The stable node did not yet appear stale to get_ksm_page(),
 		 * since that allows for an unmapped ksm page to be recognized
@@ -738,6 +868,31 @@
 	return err;
 }
 
+static int remove_stable_node_chain(struct stable_node *stable_node,
+				    struct rb_root *root)
+{
+	struct stable_node *dup;
+	struct hlist_node *hlist_safe;
+
+	if (!is_stable_node_chain(stable_node)) {
+		VM_BUG_ON(is_stable_node_dup(stable_node));
+		if (remove_stable_node(stable_node))
+			return true;
+		else
+			return false;
+	}
+
+	hlist_for_each_entry_safe(dup, hlist_safe,
+				  &stable_node->hlist, hlist_dup) {
+		VM_BUG_ON(!is_stable_node_dup(dup));
+		if (remove_stable_node(dup))
+			return true;
+	}
+	BUG_ON(!hlist_empty(&stable_node->hlist));
+	free_stable_node_chain(stable_node, root);
+	return false;
+}
+
 static int remove_all_stable_nodes(void)
 {
 	struct stable_node *stable_node;
@@ -749,7 +904,8 @@
 		while (root_stable_tree[nid].rb_node) {
 			stable_node = rb_entry(root_stable_tree[nid].rb_node,
 						struct stable_node, node);
-			if (remove_stable_node(stable_node)) {
+			if (remove_stable_node_chain(stable_node,
+						     root_stable_tree + nid)) {
 				err = -EBUSY;
 				break;	/* proceed to next nid */
 			}
@@ -1136,6 +1292,214 @@
 	return err ? NULL : page;
 }
 
+static __always_inline
+bool __is_page_sharing_candidate(struct stable_node *stable_node, int offset)
+{
+	VM_BUG_ON(stable_node->rmap_hlist_len < 0);
+	/*
+	 * Check that at least one mapping still exists, otherwise
+	 * there's no much point to merge and share with this
+	 * stable_node, as the underlying tree_page of the other
+	 * sharer is going to be freed soon.
+	 */
+	return stable_node->rmap_hlist_len &&
+		stable_node->rmap_hlist_len + offset < ksm_max_page_sharing;
+}
+
+static __always_inline
+bool is_page_sharing_candidate(struct stable_node *stable_node)
+{
+	return __is_page_sharing_candidate(stable_node, 0);
+}
+
+struct page *stable_node_dup(struct stable_node **_stable_node_dup,
+			     struct stable_node **_stable_node,
+			     struct rb_root *root,
+			     bool prune_stale_stable_nodes)
+{
+	struct stable_node *dup, *found = NULL, *stable_node = *_stable_node;
+	struct hlist_node *hlist_safe;
+	struct page *_tree_page, *tree_page = NULL;
+	int nr = 0;
+	int found_rmap_hlist_len;
+
+	if (!prune_stale_stable_nodes ||
+	    time_before(jiffies, stable_node->chain_prune_time +
+			msecs_to_jiffies(
+				ksm_stable_node_chains_prune_millisecs)))
+		prune_stale_stable_nodes = false;
+	else
+		stable_node->chain_prune_time = jiffies;
+
+	hlist_for_each_entry_safe(dup, hlist_safe,
+				  &stable_node->hlist, hlist_dup) {
+		cond_resched();
+		/*
+		 * We must walk all stable_node_dup to prune the stale
+		 * stable nodes during lookup.
+		 *
+		 * get_ksm_page can drop the nodes from the
+		 * stable_node->hlist if they point to freed pages
+		 * (that's why we do a _safe walk). The "dup"
+		 * stable_node parameter itself will be freed from
+		 * under us if it returns NULL.
+		 */
+		_tree_page = get_ksm_page(dup, false);
+		if (!_tree_page)
+			continue;
+		nr += 1;
+		if (is_page_sharing_candidate(dup)) {
+			if (!found ||
+			    dup->rmap_hlist_len > found_rmap_hlist_len) {
+				if (found)
+					put_page(tree_page);
+				found = dup;
+				found_rmap_hlist_len = found->rmap_hlist_len;
+				tree_page = _tree_page;
+
+				/* skip put_page for found dup */
+				if (!prune_stale_stable_nodes)
+					break;
+				continue;
+			}
+		}
+		put_page(_tree_page);
+	}
+
+	if (found) {
+		/*
+		 * nr is counting all dups in the chain only if
+		 * prune_stale_stable_nodes is true, otherwise we may
+		 * break the loop at nr == 1 even if there are
+		 * multiple entries.
+		 */
+		if (prune_stale_stable_nodes && nr == 1) {
+			/*
+			 * If there's not just one entry it would
+			 * corrupt memory, better BUG_ON. In KSM
+			 * context with no lock held it's not even
+			 * fatal.
+			 */
+			BUG_ON(stable_node->hlist.first->next);
+
+			/*
+			 * There's just one entry and it is below the
+			 * deduplication limit so drop the chain.
+			 */
+			rb_replace_node(&stable_node->node, &found->node,
+					root);
+			free_stable_node(stable_node);
+			ksm_stable_node_chains--;
+			ksm_stable_node_dups--;
+			/*
+			 * NOTE: the caller depends on the stable_node
+			 * to be equal to stable_node_dup if the chain
+			 * was collapsed.
+			 */
+			*_stable_node = found;
+			/*
+			 * Just for robustneess as stable_node is
+			 * otherwise left as a stable pointer, the
+			 * compiler shall optimize it away at build
+			 * time.
+			 */
+			stable_node = NULL;
+		} else if (stable_node->hlist.first != &found->hlist_dup &&
+			   __is_page_sharing_candidate(found, 1)) {
+			/*
+			 * If the found stable_node dup can accept one
+			 * more future merge (in addition to the one
+			 * that is underway) and is not at the head of
+			 * the chain, put it there so next search will
+			 * be quicker in the !prune_stale_stable_nodes
+			 * case.
+			 *
+			 * NOTE: it would be inaccurate to use nr > 1
+			 * instead of checking the hlist.first pointer
+			 * directly, because in the
+			 * prune_stale_stable_nodes case "nr" isn't
+			 * the position of the found dup in the chain,
+			 * but the total number of dups in the chain.
+			 */
+			hlist_del(&found->hlist_dup);
+			hlist_add_head(&found->hlist_dup,
+				       &stable_node->hlist);
+		}
+	}
+
+	*_stable_node_dup = found;
+	return tree_page;
+}
+
+static struct stable_node *stable_node_dup_any(struct stable_node *stable_node,
+					       struct rb_root *root)
+{
+	if (!is_stable_node_chain(stable_node))
+		return stable_node;
+	if (hlist_empty(&stable_node->hlist)) {
+		free_stable_node_chain(stable_node, root);
+		return NULL;
+	}
+	return hlist_entry(stable_node->hlist.first,
+			   typeof(*stable_node), hlist_dup);
+}
+
+/*
+ * Like for get_ksm_page, this function can free the *_stable_node and
+ * *_stable_node_dup if the returned tree_page is NULL.
+ *
+ * It can also free and overwrite *_stable_node with the found
+ * stable_node_dup if the chain is collapsed (in which case
+ * *_stable_node will be equal to *_stable_node_dup like if the chain
+ * never existed). It's up to the caller to verify tree_page is not
+ * NULL before dereferencing *_stable_node or *_stable_node_dup.
+ *
+ * *_stable_node_dup is really a second output parameter of this
+ * function and will be overwritten in all cases, the caller doesn't
+ * need to initialize it.
+ */
+static struct page *__stable_node_chain(struct stable_node **_stable_node_dup,
+					struct stable_node **_stable_node,
+					struct rb_root *root,
+					bool prune_stale_stable_nodes)
+{
+	struct stable_node *stable_node = *_stable_node;
+	if (!is_stable_node_chain(stable_node)) {
+		if (is_page_sharing_candidate(stable_node)) {
+			*_stable_node_dup = stable_node;
+			return get_ksm_page(stable_node, false);
+		}
+		/*
+		 * _stable_node_dup set to NULL means the stable_node
+		 * reached the ksm_max_page_sharing limit.
+		 */
+		*_stable_node_dup = NULL;
+		return NULL;
+	}
+	return stable_node_dup(_stable_node_dup, _stable_node, root,
+			       prune_stale_stable_nodes);
+}
+
+static __always_inline struct page *chain_prune(struct stable_node **s_n_d,
+						struct stable_node **s_n,
+						struct rb_root *root)
+{
+	return __stable_node_chain(s_n_d, s_n, root, true);
+}
+
+static __always_inline struct page *chain(struct stable_node **s_n_d,
+					  struct stable_node *s_n,
+					  struct rb_root *root)
+{
+	struct stable_node *old_stable_node = s_n;
+	struct page *tree_page;
+
+	tree_page = __stable_node_chain(s_n_d, &s_n, root, false);
+	/* not pruning dups so s_n cannot have changed */
+	VM_BUG_ON(s_n != old_stable_node);
+	return tree_page;
+}
+
 /*
  * stable_tree_search - search for page inside the stable tree
  *
@@ -1151,7 +1515,7 @@
 	struct rb_root *root;
 	struct rb_node **new;
 	struct rb_node *parent;
-	struct stable_node *stable_node;
+	struct stable_node *stable_node, *stable_node_dup, *stable_node_any;
 	struct stable_node *page_node;
 
 	page_node = page_stable_node(page);
@@ -1173,7 +1537,44 @@
 
 		cond_resched();
 		stable_node = rb_entry(*new, struct stable_node, node);
-		tree_page = get_ksm_page(stable_node, false);
+		stable_node_any = NULL;
+		tree_page = chain_prune(&stable_node_dup, &stable_node,	root);
+		/*
+		 * NOTE: stable_node may have been freed by
+		 * chain_prune() if the returned stable_node_dup is
+		 * not NULL. stable_node_dup may have been inserted in
+		 * the rbtree instead as a regular stable_node (in
+		 * order to collapse the stable_node chain if a single
+		 * stable_node dup was found in it). In such case the
+		 * stable_node is overwritten by the calleee to point
+		 * to the stable_node_dup that was collapsed in the
+		 * stable rbtree and stable_node will be equal to
+		 * stable_node_dup like if the chain never existed.
+		 */
+		if (!stable_node_dup) {
+			/*
+			 * Either all stable_node dups were full in
+			 * this stable_node chain, or this chain was
+			 * empty and should be rb_erased.
+			 */
+			stable_node_any = stable_node_dup_any(stable_node,
+							      root);
+			if (!stable_node_any) {
+				/* rb_erase just run */
+				goto again;
+			}
+			/*
+			 * Take any of the stable_node dups page of
+			 * this stable_node chain to let the tree walk
+			 * continue. All KSM pages belonging to the
+			 * stable_node dups in a stable_node chain
+			 * have the same content and they're
+			 * wrprotected at all times. Any will work
+			 * fine to continue the walk.
+			 */
+			tree_page = get_ksm_page(stable_node_any, false);
+		}
+		VM_BUG_ON(!stable_node_dup ^ !!stable_node_any);
 		if (!tree_page) {
 			/*
 			 * If we walked over a stale stable_node,
@@ -1196,6 +1597,34 @@
 		else if (ret > 0)
 			new = &parent->rb_right;
 		else {
+			if (page_node) {
+				VM_BUG_ON(page_node->head != &migrate_nodes);
+				/*
+				 * Test if the migrated page should be merged
+				 * into a stable node dup. If the mapcount is
+				 * 1 we can migrate it with another KSM page
+				 * without adding it to the chain.
+				 */
+				if (page_mapcount(page) > 1)
+					goto chain_append;
+			}
+
+			if (!stable_node_dup) {
+				/*
+				 * If the stable_node is a chain and
+				 * we got a payload match in memcmp
+				 * but we cannot merge the scanned
+				 * page in any of the existing
+				 * stable_node dups because they're
+				 * all full, we need to wait the
+				 * scanned page to find itself a match
+				 * in the unstable tree to create a
+				 * brand new KSM page to add later to
+				 * the dups of this stable_node.
+				 */
+				return NULL;
+			}
+
 			/*
 			 * Lock and unlock the stable_node's page (which
 			 * might already have been migrated) so that page
@@ -1203,23 +1632,21 @@
 			 * It would be more elegant to return stable_node
 			 * than kpage, but that involves more changes.
 			 */
-			tree_page = get_ksm_page(stable_node, true);
-			if (tree_page) {
-				unlock_page(tree_page);
-				if (get_kpfn_nid(stable_node->kpfn) !=
-						NUMA(stable_node->nid)) {
-					put_page(tree_page);
-					goto replace;
-				}
-				return tree_page;
-			}
-			/*
-			 * There is now a place for page_node, but the tree may
-			 * have been rebalanced, so re-evaluate parent and new.
-			 */
-			if (page_node)
+			tree_page = get_ksm_page(stable_node_dup, true);
+			if (unlikely(!tree_page))
+				/*
+				 * The tree may have been rebalanced,
+				 * so re-evaluate parent and new.
+				 */
 				goto again;
-			return NULL;
+			unlock_page(tree_page);
+
+			if (get_kpfn_nid(stable_node_dup->kpfn) !=
+			    NUMA(stable_node_dup->nid)) {
+				put_page(tree_page);
+				goto replace;
+			}
+			return tree_page;
 		}
 	}
 
@@ -1230,22 +1657,95 @@
 	DO_NUMA(page_node->nid = nid);
 	rb_link_node(&page_node->node, parent, new);
 	rb_insert_color(&page_node->node, root);
-	get_page(page);
-	return page;
+out:
+	if (is_page_sharing_candidate(page_node)) {
+		get_page(page);
+		return page;
+	} else
+		return NULL;
 
 replace:
-	if (page_node) {
-		list_del(&page_node->list);
-		DO_NUMA(page_node->nid = nid);
-		rb_replace_node(&stable_node->node, &page_node->node, root);
-		get_page(page);
+	/*
+	 * If stable_node was a chain and chain_prune collapsed it,
+	 * stable_node has been updated to be the new regular
+	 * stable_node. A collapse of the chain is indistinguishable
+	 * from the case there was no chain in the stable
+	 * rbtree. Otherwise stable_node is the chain and
+	 * stable_node_dup is the dup to replace.
+	 */
+	if (stable_node_dup == stable_node) {
+		VM_BUG_ON(is_stable_node_chain(stable_node_dup));
+		VM_BUG_ON(is_stable_node_dup(stable_node_dup));
+		/* there is no chain */
+		if (page_node) {
+			VM_BUG_ON(page_node->head != &migrate_nodes);
+			list_del(&page_node->list);
+			DO_NUMA(page_node->nid = nid);
+			rb_replace_node(&stable_node_dup->node,
+					&page_node->node,
+					root);
+			if (is_page_sharing_candidate(page_node))
+				get_page(page);
+			else
+				page = NULL;
+		} else {
+			rb_erase(&stable_node_dup->node, root);
+			page = NULL;
+		}
 	} else {
-		rb_erase(&stable_node->node, root);
-		page = NULL;
+		VM_BUG_ON(!is_stable_node_chain(stable_node));
+		__stable_node_dup_del(stable_node_dup);
+		if (page_node) {
+			VM_BUG_ON(page_node->head != &migrate_nodes);
+			list_del(&page_node->list);
+			DO_NUMA(page_node->nid = nid);
+			stable_node_chain_add_dup(page_node, stable_node);
+			if (is_page_sharing_candidate(page_node))
+				get_page(page);
+			else
+				page = NULL;
+		} else {
+			page = NULL;
+		}
 	}
-	stable_node->head = &migrate_nodes;
-	list_add(&stable_node->list, stable_node->head);
+	stable_node_dup->head = &migrate_nodes;
+	list_add(&stable_node_dup->list, stable_node_dup->head);
 	return page;
+
+chain_append:
+	/* stable_node_dup could be null if it reached the limit */
+	if (!stable_node_dup)
+		stable_node_dup = stable_node_any;
+	/*
+	 * If stable_node was a chain and chain_prune collapsed it,
+	 * stable_node has been updated to be the new regular
+	 * stable_node. A collapse of the chain is indistinguishable
+	 * from the case there was no chain in the stable
+	 * rbtree. Otherwise stable_node is the chain and
+	 * stable_node_dup is the dup to replace.
+	 */
+	if (stable_node_dup == stable_node) {
+		VM_BUG_ON(is_stable_node_chain(stable_node_dup));
+		VM_BUG_ON(is_stable_node_dup(stable_node_dup));
+		/* chain is missing so create it */
+		stable_node = alloc_stable_node_chain(stable_node_dup,
+						      root);
+		if (!stable_node)
+			return NULL;
+	}
+	/*
+	 * Add this stable_node dup that was
+	 * migrated to the stable_node chain
+	 * of the current nid for this page
+	 * content.
+	 */
+	VM_BUG_ON(!is_stable_node_chain(stable_node));
+	VM_BUG_ON(!is_stable_node_dup(stable_node_dup));
+	VM_BUG_ON(page_node->head != &migrate_nodes);
+	list_del(&page_node->list);
+	DO_NUMA(page_node->nid = nid);
+	stable_node_chain_add_dup(page_node, stable_node);
+	goto out;
 }
 
 /*
@@ -1262,7 +1762,8 @@
 	struct rb_root *root;
 	struct rb_node **new;
 	struct rb_node *parent;
-	struct stable_node *stable_node;
+	struct stable_node *stable_node, *stable_node_dup, *stable_node_any;
+	bool need_chain = false;
 
 	kpfn = page_to_pfn(kpage);
 	nid = get_kpfn_nid(kpfn);
@@ -1277,7 +1778,32 @@
 
 		cond_resched();
 		stable_node = rb_entry(*new, struct stable_node, node);
-		tree_page = get_ksm_page(stable_node, false);
+		stable_node_any = NULL;
+		tree_page = chain(&stable_node_dup, stable_node, root);
+		if (!stable_node_dup) {
+			/*
+			 * Either all stable_node dups were full in
+			 * this stable_node chain, or this chain was
+			 * empty and should be rb_erased.
+			 */
+			stable_node_any = stable_node_dup_any(stable_node,
+							      root);
+			if (!stable_node_any) {
+				/* rb_erase just run */
+				goto again;
+			}
+			/*
+			 * Take any of the stable_node dups page of
+			 * this stable_node chain to let the tree walk
+			 * continue. All KSM pages belonging to the
+			 * stable_node dups in a stable_node chain
+			 * have the same content and they're
+			 * wrprotected at all times. Any will work
+			 * fine to continue the walk.
+			 */
+			tree_page = get_ksm_page(stable_node_any, false);
+		}
+		VM_BUG_ON(!stable_node_dup ^ !!stable_node_any);
 		if (!tree_page) {
 			/*
 			 * If we walked over a stale stable_node,
@@ -1300,27 +1826,37 @@
 		else if (ret > 0)
 			new = &parent->rb_right;
 		else {
-			/*
-			 * It is not a bug that stable_tree_search() didn't
-			 * find this node: because at that time our page was
-			 * not yet write-protected, so may have changed since.
-			 */
-			return NULL;
+			need_chain = true;
+			break;
 		}
 	}
 
-	stable_node = alloc_stable_node();
-	if (!stable_node)
+	stable_node_dup = alloc_stable_node();
+	if (!stable_node_dup)
 		return NULL;
 
-	INIT_HLIST_HEAD(&stable_node->hlist);
-	stable_node->kpfn = kpfn;
-	set_page_stable_node(kpage, stable_node);
-	DO_NUMA(stable_node->nid = nid);
-	rb_link_node(&stable_node->node, parent, new);
-	rb_insert_color(&stable_node->node, root);
+	INIT_HLIST_HEAD(&stable_node_dup->hlist);
+	stable_node_dup->kpfn = kpfn;
+	set_page_stable_node(kpage, stable_node_dup);
+	stable_node_dup->rmap_hlist_len = 0;
+	DO_NUMA(stable_node_dup->nid = nid);
+	if (!need_chain) {
+		rb_link_node(&stable_node_dup->node, parent, new);
+		rb_insert_color(&stable_node_dup->node, root);
+	} else {
+		if (!is_stable_node_chain(stable_node)) {
+			struct stable_node *orig = stable_node;
+			/* chain is missing so create it */
+			stable_node = alloc_stable_node_chain(orig, root);
+			if (!stable_node) {
+				free_stable_node(stable_node_dup);
+				return NULL;
+			}
+		}
+		stable_node_chain_add_dup(stable_node_dup, stable_node);
+	}
 
-	return stable_node;
+	return stable_node_dup;
 }
 
 /*
@@ -1410,8 +1946,27 @@
  * the same ksm page.
  */
 static void stable_tree_append(struct rmap_item *rmap_item,
-			       struct stable_node *stable_node)
+			       struct stable_node *stable_node,
+			       bool max_page_sharing_bypass)
 {
+	/*
+	 * rmap won't find this mapping if we don't insert the
+	 * rmap_item in the right stable_node
+	 * duplicate. page_migration could break later if rmap breaks,
+	 * so we can as well crash here. We really need to check for
+	 * rmap_hlist_len == STABLE_NODE_CHAIN, but we can as well check
+	 * for other negative values as an undeflow if detected here
+	 * for the first time (and not when decreasing rmap_hlist_len)
+	 * would be sign of memory corruption in the stable_node.
+	 */
+	BUG_ON(stable_node->rmap_hlist_len < 0);
+
+	stable_node->rmap_hlist_len++;
+	if (!max_page_sharing_bypass)
+		/* possibly non fatal but unexpected overflow, only warn */
+		WARN_ON_ONCE(stable_node->rmap_hlist_len >
+			     ksm_max_page_sharing);
+
 	rmap_item->head = stable_node;
 	rmap_item->address |= STABLE_FLAG;
 	hlist_add_head(&rmap_item->hlist, &stable_node->hlist);
@@ -1439,19 +1994,26 @@
 	struct page *kpage;
 	unsigned int checksum;
 	int err;
+	bool max_page_sharing_bypass = false;
 
 	stable_node = page_stable_node(page);
 	if (stable_node) {
 		if (stable_node->head != &migrate_nodes &&
-		    get_kpfn_nid(stable_node->kpfn) != NUMA(stable_node->nid)) {
-			rb_erase(&stable_node->node,
-				 root_stable_tree + NUMA(stable_node->nid));
+		    get_kpfn_nid(READ_ONCE(stable_node->kpfn)) !=
+		    NUMA(stable_node->nid)) {
+			stable_node_dup_del(stable_node);
 			stable_node->head = &migrate_nodes;
 			list_add(&stable_node->list, stable_node->head);
 		}
 		if (stable_node->head != &migrate_nodes &&
 		    rmap_item->head == stable_node)
 			return;
+		/*
+		 * If it's a KSM fork, allow it to go over the sharing limit
+		 * without warnings.
+		 */
+		if (!is_page_sharing_candidate(stable_node))
+			max_page_sharing_bypass = true;
 	}
 
 	/* We first start with searching the page inside the stable tree */
@@ -1471,7 +2033,8 @@
 			 * add its rmap_item to the stable tree.
 			 */
 			lock_page(kpage);
-			stable_tree_append(rmap_item, page_stable_node(kpage));
+			stable_tree_append(rmap_item, page_stable_node(kpage),
+					   max_page_sharing_bypass);
 			unlock_page(kpage);
 		}
 		put_page(kpage);
@@ -1493,8 +2056,22 @@
 	tree_rmap_item =
 		unstable_tree_search_insert(rmap_item, page, &tree_page);
 	if (tree_rmap_item) {
+		bool split;
+
 		kpage = try_to_merge_two_pages(rmap_item, page,
 						tree_rmap_item, tree_page);
+		/*
+		 * If both pages we tried to merge belong to the same compound
+		 * page, then we actually ended up increasing the reference
+		 * count of the same compound page twice, and split_huge_page
+		 * failed.
+		 * Here we set a flag if that happened, and we use it later to
+		 * try split_huge_page again. Since we call put_page right
+		 * afterwards, the reference count will be correct and
+		 * split_huge_page should succeed.
+		 */
+		split = PageTransCompound(page)
+			&& compound_head(page) == compound_head(tree_page);
 		put_page(tree_page);
 		if (kpage) {
 			/*
@@ -1504,8 +2081,10 @@
 			lock_page(kpage);
 			stable_node = stable_tree_insert(kpage);
 			if (stable_node) {
-				stable_tree_append(tree_rmap_item, stable_node);
-				stable_tree_append(rmap_item, stable_node);
+				stable_tree_append(tree_rmap_item, stable_node,
+						   false);
+				stable_tree_append(rmap_item, stable_node,
+						   false);
 			}
 			unlock_page(kpage);
 
@@ -1519,6 +2098,20 @@
 				break_cow(tree_rmap_item);
 				break_cow(rmap_item);
 			}
+		} else if (split) {
+			/*
+			 * We are here if we tried to merge two pages and
+			 * failed because they both belonged to the same
+			 * compound page. We will split the page now, but no
+			 * merging will take place.
+			 * We do not want to add the cost of a full lock; if
+			 * the page is locked, it is better to skip it and
+			 * perhaps try again later.
+			 */
+			if (!trylock_page(page))
+				return;
+			split_huge_page(page);
+			unlock_page(page);
 		}
 	}
 }
@@ -2009,6 +2602,48 @@
 	}
 }
 
+static bool stable_node_dup_remove_range(struct stable_node *stable_node,
+					 unsigned long start_pfn,
+					 unsigned long end_pfn)
+{
+	if (stable_node->kpfn >= start_pfn &&
+	    stable_node->kpfn < end_pfn) {
+		/*
+		 * Don't get_ksm_page, page has already gone:
+		 * which is why we keep kpfn instead of page*
+		 */
+		remove_node_from_stable_tree(stable_node);
+		return true;
+	}
+	return false;
+}
+
+static bool stable_node_chain_remove_range(struct stable_node *stable_node,
+					   unsigned long start_pfn,
+					   unsigned long end_pfn,
+					   struct rb_root *root)
+{
+	struct stable_node *dup;
+	struct hlist_node *hlist_safe;
+
+	if (!is_stable_node_chain(stable_node)) {
+		VM_BUG_ON(is_stable_node_dup(stable_node));
+		return stable_node_dup_remove_range(stable_node, start_pfn,
+						    end_pfn);
+	}
+
+	hlist_for_each_entry_safe(dup, hlist_safe,
+				  &stable_node->hlist, hlist_dup) {
+		VM_BUG_ON(!is_stable_node_dup(dup));
+		stable_node_dup_remove_range(dup, start_pfn, end_pfn);
+	}
+	if (hlist_empty(&stable_node->hlist)) {
+		free_stable_node_chain(stable_node, root);
+		return true; /* notify caller that tree was rebalanced */
+	} else
+		return false;
+}
+
 static void ksm_check_stable_tree(unsigned long start_pfn,
 				  unsigned long end_pfn)
 {
@@ -2021,15 +2656,12 @@
 		node = rb_first(root_stable_tree + nid);
 		while (node) {
 			stable_node = rb_entry(node, struct stable_node, node);
-			if (stable_node->kpfn >= start_pfn &&
-			    stable_node->kpfn < end_pfn) {
-				/*
-				 * Don't get_ksm_page, page has already gone:
-				 * which is why we keep kpfn instead of page*
-				 */
-				remove_node_from_stable_tree(stable_node);
+			if (stable_node_chain_remove_range(stable_node,
+							   start_pfn, end_pfn,
+							   root_stable_tree +
+							   nid))
 				node = rb_first(root_stable_tree + nid);
-			} else
+			else
 				node = rb_next(node);
 			cond_resched();
 		}
@@ -2254,6 +2886,47 @@
 KSM_ATTR(merge_across_nodes);
 #endif
 
+static ssize_t max_page_sharing_show(struct kobject *kobj,
+				     struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", ksm_max_page_sharing);
+}
+
+static ssize_t max_page_sharing_store(struct kobject *kobj,
+				      struct kobj_attribute *attr,
+				      const char *buf, size_t count)
+{
+	int err;
+	int knob;
+
+	err = kstrtoint(buf, 10, &knob);
+	if (err)
+		return err;
+	/*
+	 * When a KSM page is created it is shared by 2 mappings. This
+	 * being a signed comparison, it implicitly verifies it's not
+	 * negative.
+	 */
+	if (knob < 2)
+		return -EINVAL;
+
+	if (READ_ONCE(ksm_max_page_sharing) == knob)
+		return count;
+
+	mutex_lock(&ksm_thread_mutex);
+	wait_while_offlining();
+	if (ksm_max_page_sharing != knob) {
+		if (ksm_pages_shared || remove_all_stable_nodes())
+			err = -EBUSY;
+		else
+			ksm_max_page_sharing = knob;
+	}
+	mutex_unlock(&ksm_thread_mutex);
+
+	return err ? err : count;
+}
+KSM_ATTR(max_page_sharing);
+
 static ssize_t pages_shared_show(struct kobject *kobj,
 				 struct kobj_attribute *attr, char *buf)
 {
@@ -2292,6 +2965,46 @@
 }
 KSM_ATTR_RO(pages_volatile);
 
+static ssize_t stable_node_dups_show(struct kobject *kobj,
+				     struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%lu\n", ksm_stable_node_dups);
+}
+KSM_ATTR_RO(stable_node_dups);
+
+static ssize_t stable_node_chains_show(struct kobject *kobj,
+				       struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%lu\n", ksm_stable_node_chains);
+}
+KSM_ATTR_RO(stable_node_chains);
+
+static ssize_t
+stable_node_chains_prune_millisecs_show(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					char *buf)
+{
+	return sprintf(buf, "%u\n", ksm_stable_node_chains_prune_millisecs);
+}
+
+static ssize_t
+stable_node_chains_prune_millisecs_store(struct kobject *kobj,
+					 struct kobj_attribute *attr,
+					 const char *buf, size_t count)
+{
+	unsigned long msecs;
+	int err;
+
+	err = kstrtoul(buf, 10, &msecs);
+	if (err || msecs > UINT_MAX)
+		return -EINVAL;
+
+	ksm_stable_node_chains_prune_millisecs = msecs;
+
+	return count;
+}
+KSM_ATTR(stable_node_chains_prune_millisecs);
+
 static ssize_t full_scans_show(struct kobject *kobj,
 			       struct kobj_attribute *attr, char *buf)
 {
@@ -2311,6 +3024,10 @@
 #ifdef CONFIG_NUMA
 	&merge_across_nodes_attr.attr,
 #endif
+	&max_page_sharing_attr.attr,
+	&stable_node_chains_attr.attr,
+	&stable_node_dups_attr.attr,
+	&stable_node_chains_prune_millisecs_attr.attr,
 	NULL,
 };
 
--- linux-4.4.0.orig/mm/list_lru.c
+++ linux-4.4.0/mm/list_lru.c
@@ -42,11 +42,7 @@
 #ifdef CONFIG_MEMCG_KMEM
 static inline bool list_lru_memcg_aware(struct list_lru *lru)
 {
-	/*
-	 * This needs node 0 to be always present, even
-	 * in the systems supporting sparse numa ids.
-	 */
-	return !!lru->node[0].memcg_lrus;
+	return lru->memcg_aware;
 }
 
 static inline struct list_lru_one *
@@ -117,6 +113,7 @@
 		l = list_lru_from_kmem(nlru, item);
 		list_add_tail(item, &l->list);
 		l->nr_items++;
+		nlru->nr_items++;
 		spin_unlock(&nlru->lock);
 		return true;
 	}
@@ -136,6 +133,7 @@
 		l = list_lru_from_kmem(nlru, item);
 		list_del_init(item);
 		l->nr_items--;
+		nlru->nr_items--;
 		spin_unlock(&nlru->lock);
 		return true;
 	}
@@ -183,15 +181,10 @@
 
 unsigned long list_lru_count_node(struct list_lru *lru, int nid)
 {
-	long count = 0;
-	int memcg_idx;
+	struct list_lru_node *nlru;
 
-	count += __list_lru_count_one(lru, nid, -1);
-	if (list_lru_memcg_aware(lru)) {
-		for_each_memcg_cache_index(memcg_idx)
-			count += __list_lru_count_one(lru, nid, memcg_idx);
-	}
-	return count;
+	nlru = &lru->node[nid];
+	return nlru->nr_items;
 }
 EXPORT_SYMBOL_GPL(list_lru_count_node);
 
@@ -226,6 +219,7 @@
 			assert_spin_locked(&nlru->lock);
 		case LRU_REMOVED:
 			isolated++;
+			nlru->nr_items--;
 			/*
 			 * If the lru lock has been dropped, our list
 			 * traversal is now invalid and so we have to
@@ -319,7 +313,7 @@
 	}
 	return 0;
 fail:
-	__memcg_destroy_list_lru_node(memcg_lrus, begin, i - 1);
+	__memcg_destroy_list_lru_node(memcg_lrus, begin, i);
 	return -ENOMEM;
 }
 
@@ -391,6 +385,8 @@
 {
 	int i;
 
+	lru->memcg_aware = memcg_aware;
+
 	if (!memcg_aware)
 		return 0;
 
@@ -554,6 +550,8 @@
 	err = memcg_init_list_lru(lru, memcg_aware);
 	if (err) {
 		kfree(lru->node);
+		/* Do this so a list_lru_destroy() doesn't crash: */
+		lru->node = NULL;
 		goto out;
 	}
 
--- linux-4.4.0.orig/mm/maccess.c
+++ linux-4.4.0/mm/maccess.c
@@ -5,8 +5,32 @@
 #include <linux/mm.h>
 #include <linux/uaccess.h>
 
+static __always_inline long
+probe_read_common(void *dst, const void __user *src, size_t size)
+{
+	long ret;
+
+	pagefault_disable();
+	ret = __copy_from_user_inatomic(dst, src, size);
+	pagefault_enable();
+
+	return ret ? -EFAULT : 0;
+}
+
+static __always_inline long
+probe_write_common(void __user *dst, const void *src, size_t size)
+{
+	long ret;
+
+	pagefault_disable();
+	ret = __copy_to_user_inatomic(dst, src, size);
+	pagefault_enable();
+
+	return ret ? -EFAULT : 0;
+}
+
 /**
- * probe_kernel_read(): safely attempt to read from a location
+ * probe_kernel_read(): safely attempt to read from a kernel-space location
  * @dst: pointer to the buffer that shall take the data
  * @src: address to read from
  * @size: size of the data chunk
@@ -29,17 +53,41 @@
 	mm_segment_t old_fs = get_fs();
 
 	set_fs(KERNEL_DS);
-	pagefault_disable();
-	ret = __copy_from_user_inatomic(dst,
-			(__force const void __user *)src, size);
-	pagefault_enable();
+	ret = probe_read_common(dst, (__force const void __user *)src, size);
 	set_fs(old_fs);
 
-	return ret ? -EFAULT : 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(probe_kernel_read);
 
 /**
+ * probe_user_read(): safely attempt to read from a user-space location
+ * @dst: pointer to the buffer that shall take the data
+ * @src: address to read from. This must be a user address.
+ * @size: size of the data chunk
+ *
+ * Safely read from user address @src to the buffer at @dst. If a kernel fault
+ * happens, handle that and return -EFAULT.
+ */
+
+long __weak probe_user_read(void *dst, const void __user *src, size_t size)
+    __attribute__((alias("__probe_user_read")));
+
+long __probe_user_read(void *dst, const void __user *src, size_t size)
+{
+	long ret = -EFAULT;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(USER_DS);
+	if (access_ok(VERIFY_READ, src, size))
+		ret = probe_read_common(dst, src, size);
+	set_fs(old_fs);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(probe_user_read);
+
+/**
  * probe_kernel_write(): safely attempt to write to a location
  * @dst: address to write to
  * @src: pointer to the data that shall be written
@@ -48,6 +96,7 @@
  * Safely write to address @dst from the buffer at @src.  If a kernel fault
  * happens, handle that and return -EFAULT.
  */
+
 long __weak probe_kernel_write(void *dst, const void *src, size_t size)
     __attribute__((alias("__probe_kernel_write")));
 
@@ -57,16 +106,41 @@
 	mm_segment_t old_fs = get_fs();
 
 	set_fs(KERNEL_DS);
-	pagefault_disable();
-	ret = __copy_to_user_inatomic((__force void __user *)dst, src, size);
-	pagefault_enable();
+	ret = probe_write_common((__force void __user *)dst, src, size);
 	set_fs(old_fs);
 
-	return ret ? -EFAULT : 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(probe_kernel_write);
 
 /**
+ * probe_user_write(): safely attempt to write to a user-space location
+ * @dst: address to write to
+ * @src: pointer to the data that shall be written
+ * @size: size of the data chunk
+ *
+ * Safely write to address @dst from the buffer at @src.  If a kernel fault
+ * happens, handle that and return -EFAULT.
+ */
+
+long __weak probe_user_write(void __user *dst, const void *src, size_t size)
+    __attribute__((alias("__probe_user_write")));
+
+long __probe_user_write(void __user *dst, const void *src, size_t size)
+{
+	long ret = -EFAULT;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(USER_DS);
+	if (access_ok(VERIFY_WRITE, dst, size))
+		ret = probe_write_common(dst, src, size);
+	set_fs(old_fs);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(probe_user_write);
+
+/**
  * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address.
  * @dst:   Destination address, in kernel space.  This buffer must be at
  *         least @count bytes long.
@@ -106,3 +180,76 @@
 
 	return ret ? -EFAULT : src - unsafe_addr;
 }
+
+/**
+ * strncpy_from_unsafe_user: - Copy a NUL terminated string from unsafe user
+ *				address.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @unsafe_addr: Unsafe user address.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from unsafe user address to kernel buffer.
+ *
+ * On success, returns the length of the string INCLUDING the trailing NUL.
+ *
+ * If access fails, returns -EFAULT (some data may have been copied
+ * and the trailing NUL added).
+ *
+ * If @count is smaller than the length of the string, copies @count-1 bytes,
+ * sets the last byte of @dst buffer to NUL and returns @count.
+ */
+long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
+			      long count)
+{
+	mm_segment_t old_fs = get_fs();
+	long ret;
+
+	if (unlikely(count <= 0))
+		return 0;
+
+	set_fs(USER_DS);
+	pagefault_disable();
+	ret = strncpy_from_user(dst, unsafe_addr, count);
+	pagefault_enable();
+	set_fs(old_fs);
+
+	if (ret >= count) {
+		ret = count;
+		dst[ret - 1] = '\0';
+	} else if (ret > 0) {
+		ret++;
+	}
+
+	return ret;
+}
+
+/**
+ * strnlen_unsafe_user: - Get the size of a user string INCLUDING final NUL.
+ * @unsafe_addr: The string to measure.
+ * @count: Maximum count (including NUL)
+ *
+ * Get the size of a NUL-terminated string in user space without pagefault.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ *
+ * If the string is too long, returns a number larger than @count. User
+ * has to check the return value against "> count".
+ * On exception (or invalid count), returns 0.
+ *
+ * Unlike strnlen_user, this can be used from IRQ handler etc. because
+ * it disables pagefaults.
+ */
+long strnlen_unsafe_user(const void __user *unsafe_addr, long count)
+{
+	mm_segment_t old_fs = get_fs();
+	int ret;
+
+	set_fs(USER_DS);
+	pagefault_disable();
+	ret = strnlen_user(unsafe_addr, count);
+	pagefault_enable();
+	set_fs(old_fs);
+
+	return ret;
+}
--- linux-4.4.0.orig/mm/madvise.c
+++ linux-4.4.0/mm/madvise.c
@@ -76,7 +76,7 @@
 		new_flags |= VM_DONTDUMP;
 		break;
 	case MADV_DODUMP:
-		if (new_flags & VM_SPECIAL) {
+		if (!is_vm_hugetlb_page(vma) && new_flags & VM_SPECIAL) {
 			error = -EINVAL;
 			goto out;
 		}
@@ -223,15 +223,14 @@
 {
 	struct file *file = vma->vm_file;
 
+	*prev = vma;
 #ifdef CONFIG_SWAP
 	if (!file) {
-		*prev = vma;
 		force_swapin_readahead(vma, start, end);
 		return 0;
 	}
 
 	if (shmem_mapping(file->f_mapping)) {
-		*prev = vma;
 		force_shm_swapin_readahead(vma, start, end,
 					file->f_mapping);
 		return 0;
@@ -246,7 +245,6 @@
 		return 0;
 	}
 
-	*prev = vma;
 	start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
 	if (end > vma->vm_end)
 		end = vma->vm_end;
--- linux-4.4.0.orig/mm/memblock.c
+++ linux-4.4.0/mm/memblock.c
@@ -189,14 +189,6 @@
  *
  * Find @size free area aligned to @align in the specified range and node.
  *
- * When allocation direction is bottom-up, the @start should be greater
- * than the end of the kernel image. Otherwise, it will be trimmed. The
- * reason is that we want the bottom-up allocation just near the kernel
- * image so it is highly likely that the allocated memory and the kernel
- * will reside in the same node.
- *
- * If bottom-up allocation failed, will try to allocate memory top-down.
- *
  * RETURNS:
  * Found address on success, 0 on failure.
  */
@@ -204,8 +196,6 @@
 					phys_addr_t align, phys_addr_t start,
 					phys_addr_t end, int nid, ulong flags)
 {
-	phys_addr_t kernel_end, ret;
-
 	/* pump up @end */
 	if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
 		end = memblock.current_limit;
@@ -213,40 +203,13 @@
 	/* avoid allocating the first page */
 	start = max_t(phys_addr_t, start, PAGE_SIZE);
 	end = max(start, end);
-	kernel_end = __pa_symbol(_end);
-
-	/*
-	 * try bottom-up allocation only when bottom-up mode
-	 * is set and @end is above the kernel image.
-	 */
-	if (memblock_bottom_up() && end > kernel_end) {
-		phys_addr_t bottom_up_start;
-
-		/* make sure we will allocate above the kernel */
-		bottom_up_start = max(start, kernel_end);
-
-		/* ok, try bottom-up allocation first */
-		ret = __memblock_find_range_bottom_up(bottom_up_start, end,
-						      size, align, nid, flags);
-		if (ret)
-			return ret;
-
-		/*
-		 * we always limit bottom-up allocation above the kernel,
-		 * but top-down allocation doesn't have the limit, so
-		 * retrying top-down allocation may succeed when bottom-up
-		 * allocation failed.
-		 *
-		 * bottom-up allocation is expected to be fail very rarely,
-		 * so we use WARN_ONCE() here to see the stack trace if
-		 * fail happens.
-		 */
-		WARN_ONCE(1, "memblock: bottom-up allocation failed, "
-			     "memory hotunplug may be affected\n");
-	}
 
-	return __memblock_find_range_top_down(start, end, size, align, nid,
-					      flags);
+	if (memblock_bottom_up())
+		return __memblock_find_range_bottom_up(start, end, size, align,
+						       nid, flags);
+	else
+		return __memblock_find_range_top_down(start, end, size, align,
+						      nid, flags);
 }
 
 /**
@@ -1634,6 +1597,30 @@
 	}
 }
 
+extern unsigned long __init_memblock
+memblock_reserved_memory_within(phys_addr_t start_addr, phys_addr_t end_addr)
+{
+	struct memblock_type *type = &memblock.reserved;
+	unsigned long size = 0;
+	int idx;
+
+	for (idx = 0; idx < type->cnt; idx++) {
+		struct memblock_region *rgn = &type->regions[idx];
+		phys_addr_t start, end;
+
+		if (rgn->base + rgn->size < start_addr)
+			continue;
+		if (rgn->base > end_addr)
+			continue;
+
+		start = rgn->base;
+		end = start + rgn->size;
+		size += end - start;
+	}
+
+	return size;
+}
+
 void __init_memblock __memblock_dump_all(void)
 {
 	pr_info("MEMBLOCK configuration:\n");
--- linux-4.4.0.orig/mm/memcontrol.c
+++ linux-4.4.0/mm/memcontrol.c
@@ -196,6 +196,7 @@
 /* "mc" and its members are protected by cgroup_mutex */
 static struct move_charge_struct {
 	spinlock_t	  lock; /* for from, to */
+	struct mm_struct  *mm;
 	struct mem_cgroup *from;
 	struct mem_cgroup *to;
 	unsigned long flags;
@@ -271,21 +272,7 @@
 
 static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
 {
-	return memcg->css.id;
-}
-
-/*
- * A helper function to get mem_cgroup from ID. must be called under
- * rcu_read_lock().  The caller is responsible for calling
- * css_tryget_online() if the mem_cgroup is used for charging. (dropping
- * refcnt from swap can be called against removed memcg.)
- */
-static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
-{
-	struct cgroup_subsys_state *css;
-
-	css = css_from_id(id, &memory_cgrp_subsys);
-	return mem_cgroup_from_css(css);
+	return memcg->id.id;
 }
 
 /* Writing them here to avoid exposing memcg's inner layout */
@@ -846,7 +833,7 @@
 			if (unlikely(!memcg))
 				memcg = root_mem_cgroup;
 		}
-	} while (!css_tryget_online(&memcg->css));
+	} while (!css_tryget(&memcg->css));
 	rcu_read_unlock();
 	return memcg;
 }
@@ -1001,28 +988,47 @@
 		css_put(&prev->css);
 }
 
-static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
+static void __invalidate_reclaim_iterators(struct mem_cgroup *from,
+					struct mem_cgroup *dead_memcg)
 {
-	struct mem_cgroup *memcg = dead_memcg;
 	struct mem_cgroup_reclaim_iter *iter;
 	struct mem_cgroup_per_zone *mz;
 	int nid, zid;
 	int i;
 
-	while ((memcg = parent_mem_cgroup(memcg))) {
-		for_each_node(nid) {
-			for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-				mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-				for (i = 0; i <= DEF_PRIORITY; i++) {
-					iter = &mz->iter[i];
-					cmpxchg(&iter->position,
-						dead_memcg, NULL);
-				}
+	for_each_node(nid) {
+		for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+			mz = &from->nodeinfo[nid]->zoneinfo[zid];
+			for (i = 0; i <= DEF_PRIORITY; i++) {
+				iter = &mz->iter[i];
+				cmpxchg(&iter->position,
+					dead_memcg, NULL);
 			}
 		}
 	}
 }
 
+static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
+{
+	struct mem_cgroup *memcg = dead_memcg;
+	struct mem_cgroup *last;
+
+	do {
+		__invalidate_reclaim_iterators(memcg, dead_memcg);
+		last = memcg;
+	} while ((memcg = parent_mem_cgroup(memcg)));
+
+	/*
+	 * When cgruop1 non-hierarchy mode is used,
+	 * parent_mem_cgroup() does not walk all the way up to the
+	 * cgroup root (root_mem_cgroup). So we have to handle
+	 * dead_memcg from cgroup root separately.
+	 */
+	if (last != root_mem_cgroup)
+		__invalidate_reclaim_iterators(root_mem_cgroup,
+						dead_memcg);
+}
+
 /*
  * Iteration constructs for visiting all cgroups (under a tree).  If
  * loops are exited prematurely (break), mem_cgroup_iter_break() must
@@ -1332,7 +1338,7 @@
 	return limit;
 }
 
-static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
+static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
 				     int order)
 {
 	struct oom_control oc = {
@@ -1410,6 +1416,7 @@
 	}
 unlock:
 	mutex_unlock(&oom_lock);
+	return chosen;
 }
 
 #if MAX_NUMNODES > 1
@@ -2067,6 +2074,15 @@
 		     current->flags & PF_EXITING))
 		goto force;
 
+	/*
+	 * Prevent unbounded recursion when reclaim operations need to
+	 * allocate memory. This might exceed the limits temporarily,
+	 * but we prefer facilitating memory reclaim and getting back
+	 * under the limit over triggering OOM kills in these cases.
+	 */
+	if (unlikely(current->flags & PF_MEMALLOC))
+		goto force;
+
 	if (unlikely(task_in_memcg_oom(current)))
 		goto nomem;
 
@@ -3464,7 +3480,7 @@
 	struct mem_cgroup_thresholds *thresholds;
 	struct mem_cgroup_threshold_ary *new;
 	unsigned long usage;
-	int i, j, size;
+	int i, j, size, entries;
 
 	mutex_lock(&memcg->thresholds_lock);
 
@@ -3484,14 +3500,20 @@
 	__mem_cgroup_threshold(memcg, type == _MEMSWAP);
 
 	/* Calculate new number of threshold */
-	size = 0;
+	size = entries = 0;
 	for (i = 0; i < thresholds->primary->size; i++) {
 		if (thresholds->primary->entries[i].eventfd != eventfd)
 			size++;
+		else
+			entries++;
 	}
 
 	new = thresholds->spare;
 
+	/* If no items related to eventfd have been cleared, nothing to do */
+	if (!entries)
+		goto unlock;
+
 	/* Set thresholds array to NULL if we don't have thresholds */
 	if (!size) {
 		kfree(new);
@@ -3522,16 +3544,17 @@
 swap_buffers:
 	/* Swap primary and spare array */
 	thresholds->spare = thresholds->primary;
-	/* If all events are unregistered, free the spare array */
-	if (!new) {
-		kfree(thresholds->spare);
-		thresholds->spare = NULL;
-	}
 
 	rcu_assign_pointer(thresholds->primary, new);
 
 	/* To be sure that nobody uses thresholds */
 	synchronize_rcu();
+
+	/* If all events are unregistered, free the spare array */
+	if (!new) {
+		kfree(thresholds->spare);
+		thresholds->spare = NULL;
+	}
 unlock:
 	mutex_unlock(&memcg->thresholds_lock);
 }
@@ -3658,6 +3681,7 @@
 	 * ordering is imposed by list_lru_node->lock taken by
 	 * memcg_drain_all_list_lrus().
 	 */
+	rcu_read_lock(); /* can be called from css_free w/o cgroup_mutex */
 	css_for_each_descendant_pre(css, &memcg->css) {
 		child = mem_cgroup_from_css(css);
 		BUG_ON(child->kmemcg_id != kmemcg_id);
@@ -3665,6 +3689,8 @@
 		if (!memcg->use_hierarchy)
 			break;
 	}
+	rcu_read_unlock();
+
 	memcg_drain_all_list_lrus(kmemcg_id, parent->kmemcg_id);
 
 	memcg_free_cache_id(kmemcg_id);
@@ -3899,9 +3925,12 @@
 	buf = endp + 1;
 
 	cfd = simple_strtoul(buf, &endp, 10);
-	if ((*endp != ' ') && (*endp != '\0'))
+	if (*endp == '\0')
+		buf = endp;
+	else if (*endp == ' ')
+		buf = endp + 1;
+	else
 		return -EINVAL;
-	buf = endp + 1;
 
 	event = kzalloc(sizeof(*event), GFP_KERNEL);
 	if (!event)
@@ -4118,6 +4147,94 @@
 	{ },	/* terminate */
 };
 
+/*
+ * Private memory cgroup IDR
+ *
+ * Swap-out records and page cache shadow entries need to store memcg
+ * references in constrained space, so we maintain an ID space that is
+ * limited to 16 bit (MEM_CGROUP_ID_MAX), limiting the total number of
+ * memory-controlled cgroups to 64k.
+ *
+ * However, there usually are many references to the oflline CSS after
+ * the cgroup has been destroyed, such as page cache or reclaimable
+ * slab objects, that don't need to hang on to the ID. We want to keep
+ * those dead CSS from occupying IDs, or we might quickly exhaust the
+ * relatively small ID space and prevent the creation of new cgroups
+ * even when there are much fewer than 64k cgroups - possibly none.
+ *
+ * Maintain a private 16-bit ID space for memcg, and allow the ID to
+ * be freed and recycled when it's no longer needed, which is usually
+ * when the CSS is offlined.
+ *
+ * The only exception to that are records of swapped out tmpfs/shmem
+ * pages that need to be attributed to live ancestors on swapin. But
+ * those references are manageable from userspace.
+ */
+
+static DEFINE_IDR(mem_cgroup_idr);
+static DEFINE_SPINLOCK(memcg_idr_lock);
+
+static int mem_cgroup_alloc_id(void)
+{
+	int ret;
+
+	idr_preload(GFP_KERNEL);
+	spin_lock(&memcg_idr_lock);
+	ret = idr_alloc(&mem_cgroup_idr, NULL, 1, MEM_CGROUP_ID_MAX + 1,
+			GFP_NOWAIT);
+	spin_unlock(&memcg_idr_lock);
+	idr_preload_end();
+	return ret;
+}
+
+static void mem_cgroup_id_remove(struct mem_cgroup *memcg)
+{
+	if (memcg->id.id > 0) {
+		spin_lock(&memcg_idr_lock);
+		idr_remove(&mem_cgroup_idr, memcg->id.id);
+		spin_unlock(&memcg_idr_lock);
+
+		memcg->id.id = 0;
+	}
+}
+
+static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n)
+{
+	atomic_add(n, &memcg->id.ref);
+}
+
+static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n)
+{
+	if (atomic_sub_and_test(n, &memcg->id.ref)) {
+		mem_cgroup_id_remove(memcg);
+
+		/* Memcg ID pins CSS */
+		css_put(&memcg->css);
+	}
+}
+
+static inline void mem_cgroup_id_get(struct mem_cgroup *memcg)
+{
+	mem_cgroup_id_get_many(memcg, 1);
+}
+
+static inline void mem_cgroup_id_put(struct mem_cgroup *memcg)
+{
+	mem_cgroup_id_put_many(memcg, 1);
+}
+
+/**
+ * mem_cgroup_from_id - look up a memcg from a memcg id
+ * @id: the memcg id to look up
+ *
+ * Caller must hold rcu_read_lock().
+ */
+struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
+{
+	WARN_ON_ONCE(!rcu_read_lock_held());
+	return idr_find(&mem_cgroup_idr, id);
+}
+
 static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
 {
 	struct mem_cgroup_per_node *pn;
@@ -4172,6 +4289,10 @@
 	if (memcg_wb_domain_init(memcg, GFP_KERNEL))
 		goto out_free_stat;
 
+	memcg->id.id = mem_cgroup_alloc_id();
+	if (memcg->id.id < 0)
+		goto out_free_stat;
+
 	return memcg;
 
 out_free_stat:
@@ -4257,9 +4378,13 @@
 #ifdef CONFIG_CGROUP_WRITEBACK
 	INIT_LIST_HEAD(&memcg->cgwb_list);
 #endif
+	spin_lock(&memcg_idr_lock);
+	idr_replace(&mem_cgroup_idr, memcg, memcg->id.id);
+	spin_unlock(&memcg_idr_lock);
 	return &memcg->css;
 
 free_out:
+	mem_cgroup_id_remove(memcg);
 	__mem_cgroup_free(memcg);
 	return ERR_PTR(error);
 }
@@ -4271,8 +4396,9 @@
 	struct mem_cgroup *parent = mem_cgroup_from_css(css->parent);
 	int ret;
 
-	if (css->id > MEM_CGROUP_ID_MAX)
-		return -ENOSPC;
+	/* Online state pins memcg ID, memcg ID pins CSS */
+	mem_cgroup_id_get(mem_cgroup_from_css(css));
+	css_get(css);
 
 	if (!parent)
 		return 0;
@@ -4346,6 +4472,8 @@
 	memcg_deactivate_kmem(memcg);
 
 	wb_memcg_offline(memcg);
+
+	mem_cgroup_id_put(memcg);
 }
 
 static void mem_cgroup_css_released(struct cgroup_subsys_state *css)
@@ -4402,9 +4530,9 @@
 		return ret;
 	}
 
-	/* Try charges one by one with reclaim */
+	/* Try charges one by one with reclaim, but do not retry */
 	while (count--) {
-		ret = try_charge(mc.to, GFP_KERNEL & ~__GFP_NORETRY, 1);
+		ret = try_charge(mc.to, GFP_KERNEL | __GFP_NORETRY, 1);
 		if (ret)
 			return ret;
 		mc.precharge++;
@@ -4779,6 +4907,8 @@
 		if (!mem_cgroup_is_root(mc.from))
 			page_counter_uncharge(&mc.from->memsw, mc.moved_swap);
 
+		mem_cgroup_id_put_many(mc.from, mc.moved_swap);
+
 		/*
 		 * we charged both to->memory and to->memsw, so we
 		 * should uncharge to->memory.
@@ -4786,9 +4916,8 @@
 		if (!mem_cgroup_is_root(mc.to))
 			page_counter_uncharge(&mc.to->memory, mc.moved_swap);
 
-		css_put_many(&mc.from->css, mc.moved_swap);
+		css_put_many(&mc.to->css, mc.moved_swap);
 
-		/* we've already done css_get(mc.to) */
 		mc.moved_swap = 0;
 	}
 	memcg_oom_recover(from);
@@ -4798,6 +4927,8 @@
 
 static void mem_cgroup_clear_mc(void)
 {
+	struct mm_struct *mm = mc.mm;
+
 	/*
 	 * we must clear moving_task before waking up waiters at the end of
 	 * task migration.
@@ -4807,7 +4938,10 @@
 	spin_lock(&mc.lock);
 	mc.from = NULL;
 	mc.to = NULL;
+	mc.mm = NULL;
 	spin_unlock(&mc.lock);
+
+	mmput(mm);
 }
 
 static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
@@ -4864,6 +4998,7 @@
 		VM_BUG_ON(mc.moved_swap);
 
 		spin_lock(&mc.lock);
+		mc.mm = mm;
 		mc.from = from;
 		mc.to = memcg;
 		mc.flags = move_flags;
@@ -4873,8 +5008,9 @@
 		ret = mem_cgroup_precharge_mc(mm);
 		if (ret)
 			mem_cgroup_clear_mc();
+	} else {
+		mmput(mm);
 	}
-	mmput(mm);
 	return ret;
 }
 
@@ -4957,7 +5093,8 @@
 			ent = target.ent;
 			if (!mem_cgroup_move_swap_account(ent, mc.from, mc.to)) {
 				mc.precharge--;
-				/* we fixup refcnts and charges later. */
+				mem_cgroup_id_get_many(mc.to, 1);
+				/* we fixup other refcnts and charges later. */
 				mc.moved_swap++;
 			}
 			break;
@@ -4983,11 +5120,11 @@
 	return ret;
 }
 
-static void mem_cgroup_move_charge(struct mm_struct *mm)
+static void mem_cgroup_move_charge(void)
 {
 	struct mm_walk mem_cgroup_move_charge_walk = {
 		.pmd_entry = mem_cgroup_move_charge_pte_range,
-		.mm = mm,
+		.mm = mc.mm,
 	};
 
 	lru_add_drain_all();
@@ -4999,7 +5136,7 @@
 	atomic_inc(&mc.from->moving_account);
 	synchronize_rcu();
 retry:
-	if (unlikely(!down_read_trylock(&mm->mmap_sem))) {
+	if (unlikely(!down_read_trylock(&mc.mm->mmap_sem))) {
 		/*
 		 * Someone who are holding the mmap_sem might be waiting in
 		 * waitq. So we cancel all extra charges, wake up all waiters,
@@ -5016,23 +5153,16 @@
 	 * additional charge, the page walk just aborts.
 	 */
 	walk_page_range(0, ~0UL, &mem_cgroup_move_charge_walk);
-	up_read(&mm->mmap_sem);
+	up_read(&mc.mm->mmap_sem);
 	atomic_dec(&mc.from->moving_account);
 }
 
-static void mem_cgroup_move_task(struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(void)
 {
-	struct cgroup_subsys_state *css;
-	struct task_struct *p = cgroup_taskset_first(tset, &css);
-	struct mm_struct *mm = get_task_mm(p);
-
-	if (mm) {
-		if (mc.to)
-			mem_cgroup_move_charge(mm);
-		mmput(mm);
-	}
-	if (mc.to)
+	if (mc.to) {
+		mem_cgroup_move_charge();
 		mem_cgroup_clear_mc();
+	}
 }
 #else	/* !CONFIG_MMU */
 static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
@@ -5042,7 +5172,7 @@
 static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
 {
 }
-static void mem_cgroup_move_task(struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(void)
 {
 }
 #endif
@@ -5120,6 +5250,7 @@
 				 char *buf, size_t nbytes, loff_t off)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
+	unsigned long nr_pages;
 	unsigned long high;
 	int err;
 
@@ -5130,6 +5261,11 @@
 
 	memcg->high = high;
 
+	nr_pages = page_counter_read(&memcg->memory);
+	if (nr_pages > high)
+		try_to_free_mem_cgroup_pages(memcg, nr_pages - high,
+					     GFP_KERNEL, true);
+
 	memcg_wb_domain_size_changed(memcg);
 	return nbytes;
 }
@@ -5151,6 +5287,8 @@
 				char *buf, size_t nbytes, loff_t off)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
+	unsigned int nr_reclaims = MEM_CGROUP_RECLAIM_RETRIES;
+	bool drained = false;
 	unsigned long max;
 	int err;
 
@@ -5159,9 +5297,36 @@
 	if (err)
 		return err;
 
-	err = mem_cgroup_resize_limit(memcg, max);
-	if (err)
-		return err;
+	xchg(&memcg->memory.limit, max);
+
+	for (;;) {
+		unsigned long nr_pages = page_counter_read(&memcg->memory);
+
+		if (nr_pages <= max)
+			break;
+
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+
+		if (!drained) {
+			drain_all_stock(memcg);
+			drained = true;
+			continue;
+		}
+
+		if (nr_reclaims) {
+			if (!try_to_free_mem_cgroup_pages(memcg, nr_pages - max,
+							  GFP_KERNEL, true))
+				nr_reclaims--;
+			continue;
+		}
+
+		mem_cgroup_events(memcg, MEMCG_OOM, 1);
+		if (!mem_cgroup_out_of_memory(memcg, GFP_KERNEL, 0))
+			break;
+	}
 
 	memcg_wb_domain_size_changed(memcg);
 	return nbytes;
@@ -5221,7 +5386,7 @@
 	.css_reset = mem_cgroup_css_reset,
 	.can_attach = mem_cgroup_can_attach,
 	.cancel_attach = mem_cgroup_cancel_attach,
-	.attach = mem_cgroup_move_task,
+	.post_attach = mem_cgroup_move_task,
 	.bind = mem_cgroup_bind,
 	.dfl_cftypes = memory_files,
 	.legacy_cftypes = mem_cgroup_legacy_files,
@@ -5463,7 +5628,7 @@
 		next = page->lru.next;
 
 		VM_BUG_ON_PAGE(PageLRU(page), page);
-		VM_BUG_ON_PAGE(page_count(page), page);
+		VM_BUG_ON_PAGE(!PageHWPoison(page) && page_count(page), page);
 
 		if (!page->mem_cgroup)
 			continue;
@@ -5620,6 +5785,24 @@
 subsys_initcall(mem_cgroup_init);
 
 #ifdef CONFIG_MEMCG_SWAP
+static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
+{
+	while (!atomic_inc_not_zero(&memcg->id.ref)) {
+		/*
+		 * The root cgroup cannot be destroyed, so it's refcount must
+		 * always be >= 1.
+		 */
+		if (WARN_ON_ONCE(memcg == root_mem_cgroup)) {
+			VM_BUG_ON(1);
+			break;
+		}
+		memcg = parent_mem_cgroup(memcg);
+		if (!memcg)
+			memcg = root_mem_cgroup;
+	}
+	return memcg;
+}
+
 /**
  * mem_cgroup_swapout - transfer a memsw charge to swap
  * @page: page whose memsw charge to transfer
@@ -5629,7 +5812,7 @@
  */
 void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
 {
-	struct mem_cgroup *memcg;
+	struct mem_cgroup *memcg, *swap_memcg;
 	unsigned short oldid;
 
 	VM_BUG_ON_PAGE(PageLRU(page), page);
@@ -5644,15 +5827,27 @@
 	if (!memcg)
 		return;
 
-	oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
+	/*
+	 * In case the memcg owning these pages has been offlined and doesn't
+	 * have an ID allocated to it anymore, charge the closest online
+	 * ancestor for the swap instead and transfer the memory+swap charge.
+	 */
+	swap_memcg = mem_cgroup_id_get_online(memcg);
+	oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg));
 	VM_BUG_ON_PAGE(oldid, page);
-	mem_cgroup_swap_statistics(memcg, true);
+	mem_cgroup_swap_statistics(swap_memcg, true);
 
 	page->mem_cgroup = NULL;
 
 	if (!mem_cgroup_is_root(memcg))
 		page_counter_uncharge(&memcg->memory, 1);
 
+	if (memcg != swap_memcg) {
+		if (!mem_cgroup_is_root(swap_memcg))
+			page_counter_charge(&swap_memcg->memsw, 1);
+		page_counter_uncharge(&memcg->memsw, 1);
+	}
+
 	/*
 	 * Interrupts should be disabled here because the caller holds the
 	 * mapping->tree_lock lock which is taken with interrupts-off. It is
@@ -5662,6 +5857,9 @@
 	VM_BUG_ON(!irqs_disabled());
 	mem_cgroup_charge_statistics(memcg, page, -1);
 	memcg_check_events(memcg, page);
+
+	if (!mem_cgroup_is_root(memcg))
+		css_put(&memcg->css);
 }
 
 /**
@@ -5685,7 +5883,7 @@
 		if (!mem_cgroup_is_root(memcg))
 			page_counter_uncharge(&memcg->memsw, 1);
 		mem_cgroup_swap_statistics(memcg, false);
-		css_put(&memcg->css);
+		mem_cgroup_id_put(memcg);
 	}
 	rcu_read_unlock();
 }
--- linux-4.4.0.orig/mm/memory-failure.c
+++ linux-4.4.0/mm/memory-failure.c
@@ -539,6 +539,13 @@
 		 */
 		ClearPageActive(p);
 		ClearPageUnevictable(p);
+
+		/*
+		 * Poisoned page might never drop its ref count to 0 so we have
+		 * to uncharge it manually from its memcg.
+		 */
+		mem_cgroup_uncharge(p);
+
 		/*
 		 * drop the page count elevated by isolate_lru_page()
 		 */
@@ -1208,7 +1215,10 @@
 	 * page_remove_rmap() in try_to_unmap_one(). So to determine page status
 	 * correctly, we save a copy of the page flags at this time.
 	 */
-	page_flags = p->flags;
+	if (PageHuge(p))
+		page_flags = hpage->flags;
+	else
+		page_flags = p->flags;
 
 	/*
 	 * unpoison always clear PG_hwpoison inside page lock
@@ -1572,7 +1582,7 @@
 		 * Did it turn free?
 		 */
 		ret = __get_any_page(page, pfn, 0);
-		if (!PageLRU(page)) {
+		if (ret == 1 && !PageLRU(page)) {
 			/* Drop page reference which is from __get_any_page() */
 			put_hwpoison_page(page);
 			pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
@@ -1619,12 +1629,8 @@
 	if (ret) {
 		pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
 			pfn, ret, page->flags);
-		/*
-		 * We know that soft_offline_huge_page() tries to migrate
-		 * only one hugepage pointed to by hpage, so we need not
-		 * run through the pagelist here.
-		 */
-		putback_active_hugepage(hpage);
+		if (!list_empty(&pagelist))
+			putback_movable_pages(&pagelist);
 		if (ret > 0)
 			ret = -EIO;
 	} else {
--- linux-4.4.0.orig/mm/memory.c
+++ linux-4.4.0/mm/memory.c
@@ -72,7 +72,7 @@
 
 #include "internal.h"
 
-#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+#if defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) && !defined(CONFIG_COMPILE_TEST)
 #warning Unfortunate NUMA and NUMA Balancing config, growing page-frame for last_cpupid.
 #endif
 
@@ -361,15 +361,6 @@
 {
 	struct mmu_table_batch **batch = &tlb->batch;
 
-	/*
-	 * When there's less then two users of this mm there cannot be a
-	 * concurrent page-table walk.
-	 */
-	if (atomic_read(&tlb->mm->mm_users) < 2) {
-		__tlb_remove_table(table);
-		return;
-	}
-
 	if (*batch == NULL) {
 		*batch = (struct mmu_table_batch *)__get_free_page(GFP_NOWAIT | __GFP_NOWARN);
 		if (*batch == NULL) {
@@ -797,6 +788,46 @@
 	return pfn_to_page(pfn);
 }
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
+				pmd_t pmd)
+{
+	unsigned long pfn = pmd_pfn(pmd);
+
+	/*
+	 * There is no pmd_special() but there may be special pmds, e.g.
+	 * in a direct-access (dax) mapping, so let's just replicate the
+	 * !HAVE_PTE_SPECIAL case from vm_normal_page() here.
+	 */
+	if (unlikely(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))) {
+		if (vma->vm_flags & VM_MIXEDMAP) {
+			if (!pfn_valid(pfn))
+				return NULL;
+			goto out;
+		} else {
+			unsigned long off;
+			off = (addr - vma->vm_start) >> PAGE_SHIFT;
+			if (pfn == vma->vm_pgoff + off)
+				return NULL;
+			if (!is_cow_mapping(vma->vm_flags))
+				return NULL;
+		}
+	}
+
+	if (is_zero_pfn(pfn))
+		return NULL;
+	if (unlikely(pfn > highest_memmap_pfn))
+		return NULL;
+
+	/*
+	 * NOTE! We still have PageReserved() pages in the page tables.
+	 * eg. VDSO mappings can cause them to exist.
+	 */
+out:
+	return pfn_to_page(pfn);
+}
+#endif
+
 /*
  * copy one vm_area from one task to the other. Assumes the page tables
  * already present in the new task to be cleared in the whole range
@@ -1087,6 +1118,7 @@
 	init_rss_vec(rss);
 	start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
 	pte = start_pte;
+	flush_tlb_batched_pending(mm);
 	arch_enter_lazy_mmu_mode();
 	do {
 		pte_t ptent = *pte;
@@ -1564,8 +1596,29 @@
 int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
 			unsigned long pfn)
 {
+	return vm_insert_pfn_prot(vma, addr, pfn, vma->vm_page_prot);
+}
+EXPORT_SYMBOL(vm_insert_pfn);
+
+/**
+ * vm_insert_pfn_prot - insert single pfn into user vma with specified pgprot
+ * @vma: user vma to map to
+ * @addr: target user address of this page
+ * @pfn: source kernel pfn
+ * @pgprot: pgprot flags for the inserted page
+ *
+ * This is exactly like vm_insert_pfn, except that it allows drivers to
+ * to override pgprot on a per-page basis.
+ *
+ * This only makes sense for IO mappings, and it makes no sense for
+ * cow mappings.  In general, using multiple vmas is preferable;
+ * vm_insert_pfn_prot should only be used if using multiple VMAs is
+ * impractical.
+ */
+int vm_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr,
+			unsigned long pfn, pgprot_t pgprot)
+{
 	int ret;
-	pgprot_t pgprot = vma->vm_page_prot;
 	/*
 	 * Technically, architectures with pte_special can avoid all these
 	 * restrictions (same for remap_pfn_range).  However we would like
@@ -1580,6 +1633,9 @@
 
 	if (addr < vma->vm_start || addr >= vma->vm_end)
 		return -EFAULT;
+	if (!pfn_modify_allowed(pfn, pgprot))
+		return -EACCES;
+
 	if (track_pfn_insert(vma, &pgprot, pfn))
 		return -EINVAL;
 
@@ -1587,15 +1643,22 @@
 
 	return ret;
 }
-EXPORT_SYMBOL(vm_insert_pfn);
+EXPORT_SYMBOL(vm_insert_pfn_prot);
 
 int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
 			unsigned long pfn)
 {
+	pgprot_t pgprot = vma->vm_page_prot;
+
 	BUG_ON(!(vma->vm_flags & VM_MIXEDMAP));
 
 	if (addr < vma->vm_start || addr >= vma->vm_end)
 		return -EFAULT;
+	if (track_pfn_insert(vma, &pgprot, pfn))
+		return -EINVAL;
+
+	if (!pfn_modify_allowed(pfn, vma->vm_page_prot))
+		return -EACCES;
 
 	/*
 	 * If we don't have pte special, then we have to use the pfn_valid()
@@ -1608,9 +1671,10 @@
 		struct page *page;
 
 		page = pfn_to_page(pfn);
-		return insert_page(vma, addr, page, vma->vm_page_prot);
+		return insert_page(vma, addr, page, pgprot);
 	}
-	return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+
+	return insert_pfn(vma, addr, pfn, pgprot);
 }
 EXPORT_SYMBOL(vm_insert_mixed);
 
@@ -1623,21 +1687,26 @@
 			unsigned long addr, unsigned long end,
 			unsigned long pfn, pgprot_t prot)
 {
-	pte_t *pte;
+	pte_t *pte, *mapped_pte;
 	spinlock_t *ptl;
+	int err = 0;
 
-	pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
+	mapped_pte = pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
 	if (!pte)
 		return -ENOMEM;
 	arch_enter_lazy_mmu_mode();
 	do {
 		BUG_ON(!pte_none(*pte));
+		if (!pfn_modify_allowed(pfn, prot)) {
+			err = -EACCES;
+			break;
+		}
 		set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));
 		pfn++;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
 	arch_leave_lazy_mmu_mode();
-	pte_unmap_unlock(pte - 1, ptl);
-	return 0;
+	pte_unmap_unlock(mapped_pte, ptl);
+	return err;
 }
 
 static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
@@ -1646,6 +1715,7 @@
 {
 	pmd_t *pmd;
 	unsigned long next;
+	int err;
 
 	pfn -= addr >> PAGE_SHIFT;
 	pmd = pmd_alloc(mm, pud, addr);
@@ -1654,9 +1724,10 @@
 	VM_BUG_ON(pmd_trans_huge(*pmd));
 	do {
 		next = pmd_addr_end(addr, end);
-		if (remap_pte_range(mm, pmd, addr, next,
-				pfn + (addr >> PAGE_SHIFT), prot))
-			return -ENOMEM;
+		err = remap_pte_range(mm, pmd, addr, next,
+				pfn + (addr >> PAGE_SHIFT), prot);
+		if (err)
+			return err;
 	} while (pmd++, addr = next, addr != end);
 	return 0;
 }
@@ -1667,6 +1738,7 @@
 {
 	pud_t *pud;
 	unsigned long next;
+	int err;
 
 	pfn -= addr >> PAGE_SHIFT;
 	pud = pud_alloc(mm, pgd, addr);
@@ -1674,9 +1746,10 @@
 		return -ENOMEM;
 	do {
 		next = pud_addr_end(addr, end);
-		if (remap_pmd_range(mm, pud, addr, next,
-				pfn + (addr >> PAGE_SHIFT), prot))
-			return -ENOMEM;
+		err = remap_pmd_range(mm, pud, addr, next,
+				pfn + (addr >> PAGE_SHIFT), prot);
+		if (err)
+			return err;
 	} while (pud++, addr = next, addr != end);
 	return 0;
 }
@@ -1949,6 +2022,20 @@
 		copy_user_highpage(dst, src, va, vma);
 }
 
+static gfp_t __get_fault_gfp_mask(struct vm_area_struct *vma)
+{
+	struct file *vm_file = vma->vm_file;
+
+	if (vm_file)
+		return mapping_gfp_mask(vm_file->f_mapping) | __GFP_FS | __GFP_IO;
+
+	/*
+	 * Special mappings (e.g. VDSO) do not have any file so fake
+	 * a default GFP_KERNEL for them.
+	 */
+	return GFP_KERNEL;
+}
+
 /*
  * Notify the address space that the page is about to become writable so that
  * it can prohibit this or wait for the page to get into an appropriate state.
@@ -1964,6 +2051,7 @@
 	vmf.virtual_address = (void __user *)(address & PAGE_MASK);
 	vmf.pgoff = page->index;
 	vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
+	vmf.gfp_mask = __get_fault_gfp_mask(vma);
 	vmf.page = page;
 	vmf.cow_page = NULL;
 
@@ -2035,7 +2123,7 @@
 		}
 
 		if (!page_mkwrite)
-			file_update_time(vma->vm_file);
+			vma_file_update_time(vma);
 	}
 
 	return VM_FAULT_WRITE;
@@ -2622,40 +2710,6 @@
 }
 
 /*
- * This is like a special single-page "expand_{down|up}wards()",
- * except we must first make sure that 'address{-|+}PAGE_SIZE'
- * doesn't hit another vma.
- */
-static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address)
-{
-	address &= PAGE_MASK;
-	if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) {
-		struct vm_area_struct *prev = vma->vm_prev;
-
-		/*
-		 * Is there a mapping abutting this one below?
-		 *
-		 * That's only ok if it's the same stack mapping
-		 * that has gotten split..
-		 */
-		if (prev && prev->vm_end == address)
-			return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
-
-		return expand_downwards(vma, address - PAGE_SIZE);
-	}
-	if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {
-		struct vm_area_struct *next = vma->vm_next;
-
-		/* As VM_GROWSDOWN but s/below/above/ */
-		if (next && next->vm_start == address + PAGE_SIZE)
-			return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM;
-
-		return expand_upwards(vma, address + PAGE_SIZE);
-	}
-	return 0;
-}
-
-/*
  * We enter with non-exclusive mmap_sem (to exclude vma changes,
  * but allow concurrent faults), and pte mapped but not yet locked.
  * We return with mmap_sem still held, but pte unmapped and unlocked.
@@ -2675,10 +2729,6 @@
 	if (vma->vm_flags & VM_SHARED)
 		return VM_FAULT_SIGBUS;
 
-	/* Check if we need to add a guard page to the stack */
-	if (check_stack_guard_page(vma, address) < 0)
-		return VM_FAULT_SIGSEGV;
-
 	/* Use the zero-page for reads */
 	if (!(flags & FAULT_FLAG_WRITE) && !mm_forbids_zeropage(mm)) {
 		entry = pte_mkspecial(pfn_pte(my_zero_pfn(address),
@@ -2767,6 +2817,7 @@
 	vmf.pgoff = pgoff;
 	vmf.flags = flags;
 	vmf.page = NULL;
+	vmf.gfp_mask = __get_fault_gfp_mask(vma);
 	vmf.cow_page = cow_page;
 
 	ret = vma->vm_ops->fault(vma, &vmf);
@@ -2933,6 +2984,7 @@
 	vmf.pgoff = pgoff;
 	vmf.max_pgoff = max_pgoff;
 	vmf.flags = flags;
+	vmf.gfp_mask = __get_fault_gfp_mask(vma);
 	vma->vm_ops->map_pages(vma, &vmf);
 }
 
@@ -3158,9 +3210,6 @@
 	bool was_writable = pte_write(pte);
 	int flags = 0;
 
-	/* A PROT_NONE fault should not end up here */
-	BUG_ON(!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)));
-
 	/*
 	* The "pte" at this point cannot be used safely without
 	* validation through pte_unmap_same(). It's of NUMA type but
@@ -3253,6 +3302,11 @@
 	return VM_FAULT_FALLBACK;
 }
 
+static inline bool vma_is_accessible(struct vm_area_struct *vma)
+{
+	return vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE);
+}
+
 /*
  * These routines also need to handle stuff like marking pages dirty
  * and/or accessed for architectures that don't do it in hardware (most
@@ -3299,7 +3353,7 @@
 					pte, pmd, flags, entry);
 	}
 
-	if (pte_protnone(entry))
+	if (pte_protnone(entry) && vma_is_accessible(vma))
 		return do_numa_page(mm, vma, address, entry, pte, pmd);
 
 	ptl = pte_lockptr(mm, pmd);
@@ -3374,7 +3428,7 @@
 			if (pmd_trans_splitting(orig_pmd))
 				return 0;
 
-			if (pmd_protnone(orig_pmd))
+			if (pmd_protnone(orig_pmd) && vma_is_accessible(vma))
 				return do_huge_pmd_numa_page(mm, vma, address,
 							     orig_pmd, pmd);
 
@@ -3399,8 +3453,18 @@
 	if (unlikely(pmd_none(*pmd)) &&
 	    unlikely(__pte_alloc(mm, vma, pmd, address)))
 		return VM_FAULT_OOM;
-	/* if an huge pmd materialized from under us just retry later */
-	if (unlikely(pmd_trans_huge(*pmd)))
+	/*
+	 * If a huge pmd materialized under us just retry later.  Use
+	 * pmd_trans_unstable() instead of pmd_trans_huge() to ensure the pmd
+	 * didn't become pmd_trans_huge under us and then back to pmd_none, as
+	 * a result of MADV_DONTNEED running immediately after a huge pmd fault
+	 * in a different thread of this mm, in turn leading to a misleading
+	 * pmd_trans_huge() retval.  All we have to ensure is that it is a
+	 * regular pmd that we can walk with pte_offset_map() and we can do that
+	 * through an atomic read in C, which is what pmd_trans_unstable()
+	 * provides.
+	 */
+	if (unlikely(pmd_trans_unstable(pmd)))
 		return 0;
 	/*
 	 * A regular pmd is established and it can't morph into a huge pmd
@@ -3606,6 +3670,10 @@
 		goto out;
 	pte = *ptep;
 
+	/* Never return PFNs of anon pages in COW mappings. */
+	if (vm_normal_page(vma, address, pte))
+		goto unlock;
+
 	if ((flags & FOLL_WRITE) && !pte_write(pte))
 		goto unlock;
 
@@ -3631,6 +3699,9 @@
 		return -EINVAL;
 
 	maddr = ioremap_prot(phys_addr, PAGE_ALIGN(len + offset), prot);
+	if (!maddr)
+		return -ENOMEM;
+
 	if (write)
 		memcpy_toio(maddr + offset, buf, len);
 	else
@@ -3647,10 +3718,11 @@
  * given task for page fault accounting.
  */
 static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
-		unsigned long addr, void *buf, int len, int write)
+		unsigned long addr, void *buf, int len, unsigned int gup_flags)
 {
 	struct vm_area_struct *vma;
 	void *old_buf = buf;
+	int write = gup_flags & FOLL_WRITE;
 
 	down_read(&mm->mmap_sem);
 	/* ignore errors, just check how much was successfully transferred */
@@ -3660,7 +3732,7 @@
 		struct page *page = NULL;
 
 		ret = get_user_pages(tsk, mm, addr, 1,
-				write, 1, &page, &vma);
+				gup_flags, &page, &vma);
 		if (ret <= 0) {
 #ifndef CONFIG_HAVE_IOREMAP_PROT
 			break;
@@ -3712,14 +3784,14 @@
  * @addr:	start address to access
  * @buf:	source or destination buffer
  * @len:	number of bytes to transfer
- * @write:	whether the access is a write
+ * @gup_flags:	flags modifying lookup behaviour
  *
  * The caller must hold a reference on @mm.
  */
 int access_remote_vm(struct mm_struct *mm, unsigned long addr,
-		void *buf, int len, int write)
+		void *buf, int len, unsigned int gup_flags)
 {
-	return __access_remote_vm(NULL, mm, addr, buf, len, write);
+	return __access_remote_vm(NULL, mm, addr, buf, len, gup_flags);
 }
 
 /*
@@ -3732,12 +3804,17 @@
 {
 	struct mm_struct *mm;
 	int ret;
+	unsigned int flags = FOLL_FORCE;
 
 	mm = get_task_mm(tsk);
 	if (!mm)
 		return 0;
 
-	ret = __access_remote_vm(tsk, mm, addr, buf, len, write);
+	if (write)
+		flags |= FOLL_WRITE;
+
+	ret = __access_remote_vm(tsk, mm, addr, buf, len, flags);
+
 	mmput(mm);
 
 	return ret;
--- linux-4.4.0.orig/mm/memory_hotplug.c
+++ linux-4.4.0/mm/memory_hotplug.c
@@ -32,6 +32,7 @@
 #include <linux/hugetlb.h>
 #include <linux/memblock.h>
 #include <linux/bootmem.h>
+#include <linux/rmap.h>
 
 #include <asm/tlbflush.h>
 
@@ -76,6 +77,9 @@
 #define memhp_lock_acquire()      lock_map_acquire(&mem_hotplug.dep_map)
 #define memhp_lock_release()      lock_map_release(&mem_hotplug.dep_map)
 
+bool memhp_auto_online;
+EXPORT_SYMBOL_GPL(memhp_auto_online);
+
 void get_online_mems(void)
 {
 	might_sleep();
@@ -1231,8 +1235,13 @@
 	return zone_default;
 }
 
+static int online_memory_block(struct memory_block *mem, void *arg)
+{
+	return memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
+}
+
 /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
-int __ref add_memory_resource(int nid, struct resource *res)
+int __ref add_memory_resource(int nid, struct resource *res, bool online)
 {
 	u64 start, size;
 	pg_data_t *pgdat = NULL;
@@ -1292,6 +1301,11 @@
 	/* create new memmap entry */
 	firmware_map_add_hotplug(start, start + size, "System RAM");
 
+	/* online pages if requested */
+	if (online)
+		walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1),
+				  NULL, online_memory_block);
+
 	goto out;
 
 error:
@@ -1315,7 +1329,7 @@
 	if (!res)
 		return -EEXIST;
 
-	ret = add_memory_resource(nid, res);
+	ret = add_memory_resource(nid, res, memhp_auto_online);
 	if (ret < 0)
 		release_memory_resource(res);
 	return ret;
@@ -1357,7 +1371,8 @@
 int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
 {
 	struct page *page = pfn_to_page(start_pfn);
-	struct page *end_page = page + nr_pages;
+	unsigned long end_pfn = min(start_pfn + nr_pages, zone_end_pfn(page_zone(page)));
+	struct page *end_page = pfn_to_page(end_pfn);
 
 	/* Check the starting page of each pageblock within the range */
 	for (; page < end_page; page = next_active_pageblock(page)) {
@@ -1371,17 +1386,20 @@
 }
 
 /*
- * Confirm all pages in a range [start, end) is belongs to the same zone.
+ * Confirm all pages in a range [start, end) belong to the same zone.
+ * When true, return its valid [start, end).
  */
-int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
+int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
+			 unsigned long *valid_start, unsigned long *valid_end)
 {
 	unsigned long pfn, sec_end_pfn;
+	unsigned long start, end;
 	struct zone *zone = NULL;
 	struct page *page;
 	int i;
-	for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
+	for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn + 1);
 	     pfn < end_pfn;
-	     pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
+	     pfn = sec_end_pfn, sec_end_pfn += PAGES_PER_SECTION) {
 		/* Make sure the memory section is present first */
 		if (!present_section_nr(pfn_to_section_nr(pfn)))
 			continue;
@@ -1392,15 +1410,28 @@
 			while ((i < MAX_ORDER_NR_PAGES) &&
 				!pfn_valid_within(pfn + i))
 				i++;
-			if (i == MAX_ORDER_NR_PAGES)
+			if (i == MAX_ORDER_NR_PAGES || pfn + i >= end_pfn)
 				continue;
+			/* Check if we got outside of the zone */
+			if (zone && !zone_spans_pfn(zone, pfn + i))
+				return 0;
 			page = pfn_to_page(pfn + i);
 			if (zone && page_zone(page) != zone)
 				return 0;
+			if (!zone)
+				start = pfn + i;
 			zone = page_zone(page);
+			end = pfn + MAX_ORDER_NR_PAGES;
 		}
 	}
-	return 1;
+
+	if (zone) {
+		*valid_start = start;
+		*valid_end = min(end, end_pfn);
+		return 1;
+	} else {
+		return 0;
+	}
 }
 
 /*
@@ -1458,6 +1489,21 @@
 			continue;
 		}
 
+		/*
+		 * HWPoison pages have elevated reference counts so the migration would
+		 * fail on them. It also doesn't make any sense to migrate them in the
+		 * first place. Still try to unmap such a page in case it is still mapped
+		 * (e.g. current hwpoison implementation doesn't unmap KSM pages but keep
+		 * the unmap as the catch all safety net).
+		 */
+		if (PageHWPoison(page)) {
+			if (WARN_ON(PageLRU(page)))
+				isolate_lru_page(page);
+			if (page_mapped(page))
+				try_to_unmap(page, TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS);
+			continue;
+		}
+
 		if (!get_page_unless_zero(page))
 			continue;
 		/*
@@ -1718,6 +1764,7 @@
 	long offlined_pages;
 	int ret, drain, retry_max, node;
 	unsigned long flags;
+	unsigned long valid_start, valid_end;
 	struct zone *zone;
 	struct memory_notify arg;
 
@@ -1728,10 +1775,10 @@
 		return -EINVAL;
 	/* This makes hotplug much easier...and readable.
 	   we assume this for now. .*/
-	if (!test_pages_in_a_zone(start_pfn, end_pfn))
+	if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end))
 		return -EINVAL;
 
-	zone = page_zone(pfn_to_page(start_pfn));
+	zone = page_zone(pfn_to_page(valid_start));
 	node = zone_to_nid(zone);
 	nr_pages = end_pfn - start_pfn;
 
--- linux-4.4.0.orig/mm/mempolicy.c
+++ linux-4.4.0/mm/mempolicy.c
@@ -490,14 +490,14 @@
 	struct queue_pages *qp = walk->private;
 	unsigned long flags = qp->flags;
 	int nid;
-	pte_t *pte;
+	pte_t *pte, *mapped_pte;
 	spinlock_t *ptl;
 
 	split_huge_page_pmd(vma, addr, pmd);
 	if (pmd_trans_unstable(pmd))
 		return 0;
 
-	pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
+	mapped_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
 	for (; addr != end; pte++, addr += PAGE_SIZE) {
 		if (!pte_present(*pte))
 			continue;
@@ -514,12 +514,16 @@
 		if (node_isset(nid, *qp->nmask) == !!(flags & MPOL_MF_INVERT))
 			continue;
 
-		if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
+		if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
+			if (!vma_migratable(vma))
+				break;
 			migrate_page_add(page, qp->pagelist, flags);
+		} else
+			break;
 	}
-	pte_unmap_unlock(pte - 1, ptl);
+	pte_unmap_unlock(mapped_pte, ptl);
 	cond_resched();
-	return 0;
+	return addr != end ? -EIO : 0;
 }
 
 static int queue_pages_hugetlb(pte_t *pte, unsigned long hmask,
@@ -818,7 +822,7 @@
 	struct page *p;
 	int err;
 
-	err = get_user_pages(current, mm, addr & PAGE_MASK, 1, 0, 0, &p, NULL);
+	err = get_user_pages(current, mm, addr & PAGE_MASK, 1, 0, &p, NULL);
 	if (err >= 0) {
 		err = page_to_nid(p);
 		put_page(p);
@@ -894,11 +898,6 @@
 		*policy |= (pol->flags & MPOL_MODE_FLAGS);
 	}
 
-	if (vma) {
-		up_read(&current->mm->mmap_sem);
-		vma = NULL;
-	}
-
 	err = 0;
 	if (nmask) {
 		if (mpol_store_user_nodemask(pol)) {
@@ -1237,6 +1236,7 @@
 		     unsigned long maxnode)
 {
 	unsigned long k;
+	unsigned long t;
 	unsigned long nlongs;
 	unsigned long endmask;
 
@@ -1253,13 +1253,19 @@
 	else
 		endmask = (1UL << (maxnode % BITS_PER_LONG)) - 1;
 
-	/* When the user specified more nodes than supported just check
-	   if the non supported part is all zero. */
+	/*
+	 * When the user specified more nodes than supported just check
+	 * if the non supported part is all zero.
+	 *
+	 * If maxnode have more longs than MAX_NUMNODES, check
+	 * the bits in that area first. And then go through to
+	 * check the rest bits which equal or bigger than MAX_NUMNODES.
+	 * Otherwise, just check bits [MAX_NUMNODES, maxnode).
+	 */
 	if (nlongs > BITS_TO_LONGS(MAX_NUMNODES)) {
 		if (nlongs > PAGE_SIZE/sizeof(long))
 			return -EINVAL;
 		for (k = BITS_TO_LONGS(MAX_NUMNODES); k < nlongs; k++) {
-			unsigned long t;
 			if (get_user(t, nmask + k))
 				return -EFAULT;
 			if (k == nlongs - 1) {
@@ -1272,6 +1278,16 @@
 		endmask = ~0UL;
 	}
 
+	if (maxnode > MAX_NUMNODES && MAX_NUMNODES % BITS_PER_LONG != 0) {
+		unsigned long valid_mask = endmask;
+
+		valid_mask &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1);
+		if (get_user(t, nmask + nlongs - 1))
+			return -EFAULT;
+		if (t & valid_mask)
+			return -EINVAL;
+	}
+
 	if (copy_from_user(nodes_addr(*nodes), nmask, nlongs*sizeof(unsigned long)))
 		return -EFAULT;
 	nodes_addr(*nodes)[nlongs-1] &= endmask;
@@ -1283,7 +1299,7 @@
 			      nodemask_t *nodes)
 {
 	unsigned long copy = ALIGN(maxnode-1, 64) / 8;
-	const int nbytes = BITS_TO_LONGS(MAX_NUMNODES) * sizeof(long);
+	unsigned int nbytes = BITS_TO_LONGS(nr_node_ids) * sizeof(long);
 
 	if (copy > nbytes) {
 		if (copy > PAGE_SIZE)
@@ -1398,10 +1414,14 @@
 		goto out_put;
 	}
 
-	if (!nodes_subset(*new, node_states[N_MEMORY])) {
-		err = -EINVAL;
+	task_nodes = cpuset_mems_allowed(current);
+	nodes_and(*new, *new, task_nodes);
+	if (nodes_empty(*new))
+		goto out_put;
+
+	nodes_and(*new, *new, node_states[N_MEMORY]);
+	if (nodes_empty(*new))
 		goto out_put;
-	}
 
 	err = security_task_movememory(task);
 	if (err)
@@ -1440,7 +1460,7 @@
 	int uninitialized_var(pval);
 	nodemask_t nodes;
 
-	if (nmask != NULL && maxnode < MAX_NUMNODES)
+	if (nmask != NULL && maxnode < nr_node_ids)
 		return -EINVAL;
 
 	err = do_get_mempolicy(&pval, &nodes, addr, flags);
@@ -1469,7 +1489,7 @@
 	unsigned long nr_bits, alloc_size;
 	DECLARE_BITMAP(bm, MAX_NUMNODES);
 
-	nr_bits = min_t(unsigned long, maxnode-1, MAX_NUMNODES);
+	nr_bits = min_t(unsigned long, maxnode-1, nr_node_ids);
 	alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
 
 	if (nmask)
@@ -1492,7 +1512,6 @@
 COMPAT_SYSCALL_DEFINE3(set_mempolicy, int, mode, compat_ulong_t __user *, nmask,
 		       compat_ulong_t, maxnode)
 {
-	long err = 0;
 	unsigned long __user *nm = NULL;
 	unsigned long nr_bits, alloc_size;
 	DECLARE_BITMAP(bm, MAX_NUMNODES);
@@ -1501,14 +1520,13 @@
 	alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
 
 	if (nmask) {
-		err = compat_get_bitmap(bm, nmask, nr_bits);
+		if (compat_get_bitmap(bm, nmask, nr_bits))
+			return -EFAULT;
 		nm = compat_alloc_user_space(alloc_size);
-		err |= copy_to_user(nm, bm, alloc_size);
+		if (copy_to_user(nm, bm, alloc_size))
+			return -EFAULT;
 	}
 
-	if (err)
-		return -EFAULT;
-
 	return sys_set_mempolicy(mode, nm, nr_bits+1);
 }
 
@@ -1516,7 +1534,6 @@
 		       compat_ulong_t, mode, compat_ulong_t __user *, nmask,
 		       compat_ulong_t, maxnode, compat_ulong_t, flags)
 {
-	long err = 0;
 	unsigned long __user *nm = NULL;
 	unsigned long nr_bits, alloc_size;
 	nodemask_t bm;
@@ -1525,14 +1542,13 @@
 	alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
 
 	if (nmask) {
-		err = compat_get_bitmap(nodes_addr(bm), nmask, nr_bits);
+		if (compat_get_bitmap(nodes_addr(bm), nmask, nr_bits))
+			return -EFAULT;
 		nm = compat_alloc_user_space(alloc_size);
-		err |= copy_to_user(nm, nodes_addr(bm), alloc_size);
+		if (copy_to_user(nm, nodes_addr(bm), alloc_size))
+			return -EFAULT;
 	}
 
-	if (err)
-		return -EFAULT;
-
 	return sys_mbind(start, len, mode, nm, nr_bits+1, flags);
 }
 
@@ -1998,16 +2014,44 @@
 		nmask = policy_nodemask(gfp, pol);
 		if (!nmask || node_isset(hpage_node, *nmask)) {
 			mpol_cond_put(pol);
-			page = __alloc_pages_node(hpage_node,
-						gfp | __GFP_THISNODE, order);
+			/*
+			 * We cannot invoke reclaim if __GFP_THISNODE
+			 * is set. Invoking reclaim with
+			 * __GFP_THISNODE set, would cause THP
+			 * allocations to trigger heavy swapping
+			 * despite there may be tons of free memory
+			 * (including potentially plenty of THP
+			 * already available in the buddy) on all the
+			 * other NUMA nodes.
+			 *
+			 * At most we could invoke compaction when
+			 * __GFP_THISNODE is set (but we would need to
+			 * refrain from invoking reclaim even if
+			 * compaction returned COMPACT_SKIPPED because
+			 * there wasn't not enough memory to succeed
+			 * compaction). For now just avoid
+			 * __GFP_THISNODE instead of limiting the
+			 * allocation path to a strict and single
+			 * compaction invocation.
+			 *
+			 * Supposedly if direct reclaim was enabled by
+			 * the caller, the app prefers THP regardless
+			 * of the node it comes from so this would be
+			 * more desiderable behavior than only
+			 * providing THP originated from the local
+			 * node in such case.
+			 */
+			if (!(gfp & __GFP_DIRECT_RECLAIM))
+				gfp |= __GFP_THISNODE;
+			page = __alloc_pages_node(hpage_node, gfp, order);
 			goto out;
 		}
 	}
 
 	nmask = policy_nodemask(gfp, pol);
 	zl = policy_zonelist(gfp, pol, node);
-	mpol_cond_put(pol);
 	page = __alloc_pages_nodemask(gfp, order, zl, nmask);
+	mpol_cond_put(pol);
 out:
 	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
 		goto retry_cpuset;
@@ -2130,6 +2174,9 @@
 	case MPOL_INTERLEAVE:
 		return !!nodes_equal(a->v.nodes, b->v.nodes);
 	case MPOL_PREFERRED:
+		/* a's ->flags is the same as b's */
+		if (a->flags & MPOL_F_LOCAL)
+			return true;
 		return a->v.preferred_node == b->v.preferred_node;
 	default:
 		BUG();
@@ -2654,6 +2701,9 @@
 	char *flags = strchr(str, '=');
 	int err = 1;
 
+	if (flags)
+		*flags++ = '\0';	/* terminate mode string */
+
 	if (nodelist) {
 		/* NUL-terminate mode or flags string */
 		*nodelist++ = '\0';
@@ -2664,9 +2714,6 @@
 	} else
 		nodes_clear(nodes);
 
-	if (flags)
-		*flags++ = '\0';	/* terminate mode string */
-
 	for (mode = 0; mode < MPOL_MAX; mode++) {
 		if (!strcmp(str, policy_modes[mode])) {
 			break;
@@ -2678,7 +2725,9 @@
 	switch (mode) {
 	case MPOL_PREFERRED:
 		/*
-		 * Insist on a nodelist of one node only
+		 * Insist on a nodelist of one node only, although later
+		 * we use first_node(nodes) to grab a single node, so here
+		 * nodelist (or nodes) cannot be empty.
 		 */
 		if (nodelist) {
 			char *rest = nodelist;
@@ -2686,6 +2735,8 @@
 				rest++;
 			if (*rest)
 				goto out;
+			if (nodes_empty(nodes))
+				goto out;
 		}
 		break;
 	case MPOL_INTERLEAVE:
--- linux-4.4.0.orig/mm/mempool.c
+++ linux-4.4.0/mm/mempool.c
@@ -135,8 +135,8 @@
 	void *element = pool->elements[--pool->curr_nr];
 
 	BUG_ON(pool->curr_nr < 0);
-	check_element(pool, element);
 	kasan_unpoison_element(pool, element);
+	check_element(pool, element);
 	return element;
 }
 
--- linux-4.4.0.orig/mm/migrate.c
+++ linux-4.4.0/mm/migrate.c
@@ -38,6 +38,7 @@
 #include <linux/balloon_compaction.h>
 #include <linux/mmu_notifier.h>
 #include <linux/page_idle.h>
+#include <linux/ptrace.h>
 
 #include <asm/tlbflush.h>
 
@@ -429,6 +430,7 @@
 
 	return MIGRATEPAGE_SUCCESS;
 }
+EXPORT_SYMBOL(migrate_page_move_mapping);
 
 /*
  * The expected number of remaining references is the same as that
@@ -579,6 +581,7 @@
 	if (PageWriteback(newpage))
 		end_page_writeback(newpage);
 }
+EXPORT_SYMBOL(migrate_page_copy);
 
 /************************************************************
  *                    Migration functions
@@ -933,6 +936,7 @@
 	int rc = MIGRATEPAGE_SUCCESS;
 	int *result = NULL;
 	struct page *newpage;
+	bool is_lru = !isolated_balloon_page(page);
 
 	newpage = get_new_page(page, private, &result);
 	if (!newpage)
@@ -963,7 +967,13 @@
 		dec_zone_page_state(page, NR_ISOLATED_ANON +
 				page_is_file_cache(page));
 		/* Soft-offlined page shouldn't go through lru cache list */
-		if (reason == MR_MEMORY_FAILURE) {
+		if (reason == MR_MEMORY_FAILURE && rc == MIGRATEPAGE_SUCCESS) {
+			/*
+			 * With this release, we free successfully migrated
+			 * page and set PG_HWPoison on just freed page
+			 * intentionally. Although it's rather weird, it's how
+			 * HWPoison flag works at the moment.
+			 */
 			put_page(page);
 			if (!test_set_page_hwpoison(page))
 				num_poisoned_pages_inc();
@@ -974,11 +984,13 @@
 	/*
 	 * If migration was not successful and there's a freeing callback, use
 	 * it.  Otherwise, putback_lru_page() will drop the reference grabbed
-	 * during isolation.
+	 * during isolation. Use the old state of the isolated source page to
+	 * determine if we migrated a LRU page. newpage was already unlocked
+	 * and possibly modified by its owner - don't rely on the page state.
 	 */
 	if (put_new_page)
 		put_new_page(newpage, private);
-	else if (unlikely(__is_movable_balloon_page(newpage))) {
+	else if (rc == MIGRATEPAGE_SUCCESS && unlikely(!is_lru)) {
 		/* drop our reference, page already in the balloon */
 		put_page(newpage);
 	} else
@@ -1044,6 +1056,16 @@
 		lock_page(hpage);
 	}
 
+	/*
+	 * Check for pages which are in the process of being freed.  Without
+	 * page_mapping() set, hugetlbfs specific move page routine will not
+	 * be called and we could leak usage counts for subpools.
+	 */
+	if (page_private(hpage) && !page_mapping(hpage)) {
+		rc = -EBUSY;
+		goto out_unlock;
+	}
+
 	if (PageAnon(hpage))
 		anon_vma = page_get_anon_vma(hpage);
 
@@ -1074,6 +1096,7 @@
 		put_new_page = NULL;
 	}
 
+out_unlock:
 	unlock_page(hpage);
 out:
 	if (rc != -EAGAIN)
@@ -1475,7 +1498,6 @@
 		const int __user *, nodes,
 		int __user *, status, int, flags)
 {
-	const struct cred *cred = current_cred(), *tcred;
 	struct task_struct *task;
 	struct mm_struct *mm;
 	int err;
@@ -1499,14 +1521,9 @@
 
 	/*
 	 * Check if this process has the right to modify the specified
-	 * process. The right exists if the process has administrative
-	 * capabilities, superuser privileges or the same
-	 * userid as the target process.
-	 */
-	tcred = __task_cred(task);
-	if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
-	    !uid_eq(cred->uid,  tcred->suid) && !uid_eq(cred->uid,  tcred->uid) &&
-	    !capable(CAP_SYS_NICE)) {
+	 * process. Use the regular "ptrace_may_access()" checks.
+	 */
+	if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {
 		rcu_read_unlock();
 		err = -EPERM;
 		goto out;
@@ -1578,7 +1595,7 @@
 					 (GFP_HIGHUSER_MOVABLE |
 					  __GFP_THISNODE | __GFP_NOMEMALLOC |
 					  __GFP_NORETRY | __GFP_NOWARN) &
-					 ~(__GFP_IO | __GFP_FS), 0);
+					 ~__GFP_RECLAIM, 0);
 
 	return newpage;
 }
--- linux-4.4.0.orig/mm/mincore.c
+++ linux-4.4.0/mm/mincore.c
@@ -165,6 +165,22 @@
 	return 0;
 }
 
+static inline bool can_do_mincore(struct vm_area_struct *vma)
+{
+	if (vma_is_anonymous(vma))
+		return true;
+	if (!vma->vm_file)
+		return false;
+	/*
+	 * Reveal pagecache information only for non-anonymous mappings that
+	 * correspond to the files the calling process could (if tried) open
+	 * for writing; otherwise we'd be including shared non-exclusive
+	 * mappings, which opens a side channel.
+	 */
+	return inode_owner_or_capable(file_inode(vma->vm_file)) ||
+		inode_permission(file_inode(vma->vm_file), MAY_WRITE) == 0;
+}
+
 /*
  * Do a chunk of "sys_mincore()". We've already checked
  * all the arguments, we hold the mmap semaphore: we should
@@ -185,8 +201,13 @@
 	vma = find_vma(current->mm, addr);
 	if (!vma || addr < vma->vm_start)
 		return -ENOMEM;
-	mincore_walk.mm = vma->vm_mm;
 	end = min(vma->vm_end, addr + (pages << PAGE_SHIFT));
+	if (!can_do_mincore(vma)) {
+		unsigned long pages = DIV_ROUND_UP(end - addr, PAGE_SIZE);
+		memset(vec, 1, pages);
+		return pages;
+	}
+	mincore_walk.mm = vma->vm_mm;
 	err = walk_page_range(addr, end, &mincore_walk);
 	if (err < 0)
 		return err;
--- linux-4.4.0.orig/mm/mlock.c
+++ linux-4.4.0/mm/mlock.c
@@ -172,7 +172,7 @@
  */
 unsigned int munlock_vma_page(struct page *page)
 {
-	unsigned int nr_pages;
+	int nr_pages;
 	struct zone *zone = page_zone(page);
 
 	/* For try_to_munlock() and to serialize with page migration */
@@ -277,7 +277,7 @@
 {
 	int i;
 	int nr = pagevec_count(pvec);
-	int delta_munlocked;
+	int delta_munlocked = -nr;
 	struct pagevec pvec_putback;
 	int pgrescued = 0;
 
@@ -297,6 +297,8 @@
 				continue;
 			else
 				__munlock_isolation_failed(page);
+		} else {
+			delta_munlocked++;
 		}
 
 		/*
@@ -308,7 +310,6 @@
 		pagevec_add(&pvec_putback, pvec->pages[i]);
 		pvec->pages[i] = NULL;
 	}
-	delta_munlocked = -nr + pagevec_count(&pvec_putback);
 	__mod_zone_page_state(zone, NR_MLOCK, delta_munlocked);
 	spin_unlock_irq(&zone->lru_lock);
 
@@ -503,6 +504,7 @@
 	int nr_pages;
 	int ret = 0;
 	int lock = !!(newflags & VM_LOCKED);
+	vm_flags_t old_flags = vma->vm_flags;
 
 	if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) ||
 	    is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm))
@@ -537,6 +539,8 @@
 	nr_pages = (end - start) >> PAGE_SHIFT;
 	if (!lock)
 		nr_pages = -nr_pages;
+	else if (old_flags & VM_LOCKED)
+		nr_pages = 0;
 	mm->locked_vm += nr_pages;
 
 	/*
--- linux-4.4.0.orig/mm/mmap.c
+++ linux-4.4.0/mm/mmap.c
@@ -42,6 +42,7 @@
 #include <linux/memory.h>
 #include <linux/printk.h>
 #include <linux/userfaultfd_k.h>
+#include <linux/mm.h>
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -275,7 +276,7 @@
 	if (vma->vm_ops && vma->vm_ops->close)
 		vma->vm_ops->close(vma);
 	if (vma->vm_file)
-		fput(vma->vm_file);
+		vma_fput(vma);
 	mpol_put(vma_policy(vma));
 	kmem_cache_free(vm_area_cachep, vma);
 	return next;
@@ -288,6 +289,7 @@
 	unsigned long retval;
 	unsigned long newbrk, oldbrk;
 	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *next;
 	unsigned long min_brk;
 	bool populate;
 
@@ -332,7 +334,8 @@
 	}
 
 	/* Check against existing mmap mappings. */
-	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
+	next = find_vma(mm, oldbrk);
+	if (next && newbrk + PAGE_SIZE > vm_start_gap(next))
 		goto out;
 
 	/* Ok, looks good - let it rip. */
@@ -355,10 +358,22 @@
 
 static long vma_compute_subtree_gap(struct vm_area_struct *vma)
 {
-	unsigned long max, subtree_gap;
-	max = vma->vm_start;
-	if (vma->vm_prev)
-		max -= vma->vm_prev->vm_end;
+	unsigned long max, prev_end, subtree_gap;
+
+	/*
+	 * Note: in the rare case of a VM_GROWSDOWN above a VM_GROWSUP, we
+	 * allow two stack_guard_gaps between them here, and when choosing
+	 * an unmapped area; whereas when expanding we only require one.
+	 * That's a little inconsistent, but keeps the code here simpler.
+	 */
+	max = vm_start_gap(vma);
+	if (vma->vm_prev) {
+		prev_end = vm_end_gap(vma->vm_prev);
+		if (max > prev_end)
+			max -= prev_end;
+		else
+			max = 0;
+	}
 	if (vma->vm_rb.rb_left) {
 		subtree_gap = rb_entry(vma->vm_rb.rb_left,
 				struct vm_area_struct, vm_rb)->rb_subtree_gap;
@@ -441,13 +456,17 @@
 	struct vm_area_struct *vma = mm->mmap;
 
 	while (vma) {
+		struct anon_vma *anon_vma = vma->anon_vma;
 		struct anon_vma_chain *avc;
 
-		vma_lock_anon_vma(vma);
-		list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
-			anon_vma_interval_tree_verify(avc);
-		vma_unlock_anon_vma(vma);
-		highest_address = vma->vm_end;
+		if (anon_vma) {
+			anon_vma_lock_read(anon_vma);
+			list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
+				anon_vma_interval_tree_verify(avc);
+			anon_vma_unlock_read(anon_vma);
+		}
+
+		highest_address = vm_end_gap(vma);
 		vma = vma->vm_next;
 		i++;
 	}
@@ -616,7 +635,7 @@
 	if (vma->vm_next)
 		vma_gap_update(vma->vm_next);
 	else
-		mm->highest_vm_end = vma->vm_end;
+		mm->highest_vm_end = vm_end_gap(vma);
 
 	/*
 	 * vma->vm_prev wasn't known when we followed the rbtree to find the
@@ -862,7 +881,7 @@
 			vma_gap_update(vma);
 		if (end_changed) {
 			if (!next)
-				mm->highest_vm_end = end;
+				mm->highest_vm_end = vm_end_gap(vma);
 			else if (!adjust_next)
 				vma_gap_update(next);
 		}
@@ -887,7 +906,7 @@
 	if (remove_next) {
 		if (file) {
 			uprobe_munmap(next, next->vm_start, next->vm_end);
-			fput(file);
+			vma_fput(vma);
 		}
 		if (next->anon_vma)
 			anon_vma_merge(vma, next);
@@ -904,8 +923,28 @@
 			goto again;
 		else if (next)
 			vma_gap_update(next);
-		else
-			mm->highest_vm_end = end;
+		else {
+			/*
+			 * If remove_next == 2 we obviously can't
+			 * reach this path.
+			 *
+			 * If remove_next == 3 we can't reach this
+			 * path because pre-swap() next is always not
+			 * NULL. pre-swap() "next" is not being
+			 * removed and its next->vm_end is not altered
+			 * (and furthermore "end" already matches
+			 * next->vm_end in remove_next == 3).
+			 *
+			 * We reach this only in the remove_next == 1
+			 * case if the "next" vma that was removed was
+			 * the highest vma of the mm. However in such
+			 * case next->vm_end == "end" and the extended
+			 * "vma" has vma->vm_end == next->vm_end so
+			 * mm->highest_vm_end doesn't need any update
+			 * in remove_next == 1 case.
+			 */
+			VM_WARN_ON(mm->highest_vm_end != vm_end_gap(vma));
+		}
 	}
 	if (insert && file)
 		uprobe_mmap(insert);
@@ -1257,6 +1296,35 @@
 	return 0;
 }
 
+static inline u64 file_mmap_size_max(struct file *file, struct inode *inode)
+{
+	if (S_ISREG(inode->i_mode))
+		return MAX_LFS_FILESIZE;
+
+	if (S_ISBLK(inode->i_mode))
+		return MAX_LFS_FILESIZE;
+
+	/* Special "we do even unsigned file positions" case */
+	if (file->f_mode & FMODE_UNSIGNED_OFFSET)
+		return 0;
+
+	/* Yes, random drivers might want more. But I'm tired of buggy drivers */
+	return ULONG_MAX;
+}
+
+static inline bool file_mmap_ok(struct file *file, struct inode *inode,
+				unsigned long pgoff, unsigned long len)
+{
+	u64 maxsize = file_mmap_size_max(file, inode);
+
+	if (maxsize && len > maxsize)
+		return false;
+	maxsize -= len;
+	if (pgoff > maxsize >> PAGE_SHIFT)
+		return false;
+	return true;
+}
+
 /*
  * The caller must hold down_write(&current->mm->mmap_sem).
  */
@@ -1322,6 +1390,9 @@
 	if (file) {
 		struct inode *inode = file_inode(file);
 
+		if (!file_mmap_ok(file, inode, pgoff, len))
+			return -EOVERFLOW;
+
 		switch (flags & MAP_TYPE) {
 		case MAP_SHARED:
 			if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE))
@@ -1681,8 +1752,8 @@
 	return addr;
 
 unmap_and_free_vma:
+	vma_fput(vma);
 	vma->vm_file = NULL;
-	fput(file);
 
 	/* Undo any partial mapping done by a device driver. */
 	unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
@@ -1737,7 +1808,7 @@
 
 	while (true) {
 		/* Visit left subtree if it looks promising */
-		gap_end = vma->vm_start;
+		gap_end = vm_start_gap(vma);
 		if (gap_end >= low_limit && vma->vm_rb.rb_left) {
 			struct vm_area_struct *left =
 				rb_entry(vma->vm_rb.rb_left,
@@ -1748,12 +1819,13 @@
 			}
 		}
 
-		gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0;
+		gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
 check_current:
 		/* Check if current node has a suitable gap */
 		if (gap_start > high_limit)
 			return -ENOMEM;
-		if (gap_end >= low_limit && gap_end - gap_start >= length)
+		if (gap_end >= low_limit &&
+		    gap_end > gap_start && gap_end - gap_start >= length)
 			goto found;
 
 		/* Visit right subtree if it looks promising */
@@ -1775,8 +1847,8 @@
 			vma = rb_entry(rb_parent(prev),
 				       struct vm_area_struct, vm_rb);
 			if (prev == vma->vm_rb.rb_left) {
-				gap_start = vma->vm_prev->vm_end;
-				gap_end = vma->vm_start;
+				gap_start = vm_end_gap(vma->vm_prev);
+				gap_end = vm_start_gap(vma);
 				goto check_current;
 			}
 		}
@@ -1840,7 +1912,7 @@
 
 	while (true) {
 		/* Visit right subtree if it looks promising */
-		gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0;
+		gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
 		if (gap_start <= high_limit && vma->vm_rb.rb_right) {
 			struct vm_area_struct *right =
 				rb_entry(vma->vm_rb.rb_right,
@@ -1853,10 +1925,11 @@
 
 check_current:
 		/* Check if current node has a suitable gap */
-		gap_end = vma->vm_start;
+		gap_end = vm_start_gap(vma);
 		if (gap_end < low_limit)
 			return -ENOMEM;
-		if (gap_start <= high_limit && gap_end - gap_start >= length)
+		if (gap_start <= high_limit &&
+		    gap_end > gap_start && gap_end - gap_start >= length)
 			goto found;
 
 		/* Visit left subtree if it looks promising */
@@ -1879,7 +1952,7 @@
 				       struct vm_area_struct, vm_rb);
 			if (prev == vma->vm_rb.rb_right) {
 				gap_start = vma->vm_prev ?
-					vma->vm_prev->vm_end : 0;
+					vm_end_gap(vma->vm_prev) : 0;
 				goto check_current;
 			}
 		}
@@ -1917,7 +1990,7 @@
 		unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
+	struct vm_area_struct *vma, *prev;
 	struct vm_unmapped_area_info info;
 
 	if (len > TASK_SIZE - mmap_min_addr)
@@ -1928,9 +2001,10 @@
 
 	if (addr) {
 		addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
+		vma = find_vma_prev(mm, addr, &prev);
 		if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
-		    (!vma || addr + len <= vma->vm_start))
+		    (!vma || addr + len <= vm_start_gap(vma)) &&
+		    (!prev || addr >= vm_end_gap(prev)))
 			return addr;
 	}
 
@@ -1939,6 +2013,7 @@
 	info.low_limit = mm->mmap_base;
 	info.high_limit = TASK_SIZE;
 	info.align_mask = 0;
+	info.align_offset = 0;
 	return vm_unmapped_area(&info);
 }
 #endif
@@ -1953,7 +2028,7 @@
 			  const unsigned long len, const unsigned long pgoff,
 			  const unsigned long flags)
 {
-	struct vm_area_struct *vma;
+	struct vm_area_struct *vma, *prev;
 	struct mm_struct *mm = current->mm;
 	unsigned long addr = addr0;
 	struct vm_unmapped_area_info info;
@@ -1968,9 +2043,10 @@
 	/* requesting a specific address */
 	if (addr) {
 		addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
+		vma = find_vma_prev(mm, addr, &prev);
 		if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
-				(!vma || addr + len <= vma->vm_start))
+				(!vma || addr + len <= vm_start_gap(vma)) &&
+				(!prev || addr >= vm_end_gap(prev)))
 			return addr;
 	}
 
@@ -1979,6 +2055,7 @@
 	info.low_limit = max(PAGE_SIZE, mmap_min_addr);
 	info.high_limit = mm->mmap_base;
 	info.align_mask = 0;
+	info.align_offset = 0;
 	addr = vm_unmapped_area(&info);
 
 	/*
@@ -2095,21 +2172,19 @@
  * update accounting. This is shared with both the
  * grow-up and grow-down cases.
  */
-static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow)
+static int acct_stack_growth(struct vm_area_struct *vma,
+			     unsigned long size, unsigned long grow)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	struct rlimit *rlim = current->signal->rlim;
-	unsigned long new_start, actual_size;
+	unsigned long new_start;
 
 	/* address space limit tests */
 	if (!may_expand_vm(mm, grow))
 		return -ENOMEM;
 
 	/* Stack limit test */
-	actual_size = size;
-	if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN)))
-		actual_size -= PAGE_SIZE;
-	if (actual_size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur))
+	if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur))
 		return -ENOMEM;
 
 	/* mlock limit tests */
@@ -2147,32 +2222,44 @@
 int expand_upwards(struct vm_area_struct *vma, unsigned long address)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	int error;
+	struct vm_area_struct *next;
+	unsigned long gap_addr;
+	int error = 0;
 
 	if (!(vma->vm_flags & VM_GROWSUP))
 		return -EFAULT;
 
-	/*
-	 * We must make sure the anon_vma is allocated
-	 * so that the anon_vma locking is not a noop.
-	 */
+	/* Guard against exceeding limits of the address space. */
+	address &= PAGE_MASK;
+	if (address >= (TASK_SIZE & PAGE_MASK))
+		return -ENOMEM;
+	address += PAGE_SIZE;
+
+	/* Enforce stack_guard_gap */
+	gap_addr = address + stack_guard_gap;
+
+	/* Guard against overflow */
+	if (gap_addr < address || gap_addr > TASK_SIZE)
+		gap_addr = TASK_SIZE;
+
+	next = vma->vm_next;
+	if (next && next->vm_start < gap_addr &&
+			(next->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
+		if (!(next->vm_flags & VM_GROWSUP))
+			return -ENOMEM;
+		/* Check that both stack segments have the same anon_vma? */
+	}
+
+	/* We must make sure the anon_vma is allocated. */
 	if (unlikely(anon_vma_prepare(vma)))
 		return -ENOMEM;
-	vma_lock_anon_vma(vma);
 
 	/*
 	 * vma->vm_start/vm_end cannot change under us because the caller
 	 * is required to hold the mmap_sem in read mode.  We need the
 	 * anon_vma lock to serialize against concurrent expand_stacks.
-	 * Also guard against wrapping around to address 0.
 	 */
-	if (address < PAGE_ALIGN(address+4))
-		address = PAGE_ALIGN(address+4);
-	else {
-		vma_unlock_anon_vma(vma);
-		return -ENOMEM;
-	}
-	error = 0;
+	anon_vma_lock_write(vma->anon_vma);
 
 	/* Somebody else might have raced and expanded it already */
 	if (address > vma->vm_end) {
@@ -2190,7 +2277,7 @@
 				 * updates, but we only hold a shared mmap_sem
 				 * lock here, so we need to protect against
 				 * concurrent vma expansions.
-				 * vma_lock_anon_vma() doesn't help here, as
+				 * anon_vma_lock_write() doesn't help here, as
 				 * we don't guarantee that all growable vmas
 				 * in a mm share the same root anon vma.
 				 * So, we reuse mm->page_table_lock to guard
@@ -2207,14 +2294,14 @@
 				if (vma->vm_next)
 					vma_gap_update(vma->vm_next);
 				else
-					mm->highest_vm_end = address;
+					mm->highest_vm_end = vm_end_gap(vma);
 				spin_unlock(&mm->page_table_lock);
 
 				perf_event_mmap(vma);
 			}
 		}
 	}
-	vma_unlock_anon_vma(vma);
+	anon_vma_unlock_write(vma->anon_vma);
 	khugepaged_enter_vma_merge(vma, vma->vm_flags);
 	validate_mm(mm);
 	return error;
@@ -2228,27 +2315,32 @@
 				   unsigned long address)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	int error;
-
-	/*
-	 * We must make sure the anon_vma is allocated
-	 * so that the anon_vma locking is not a noop.
-	 */
-	if (unlikely(anon_vma_prepare(vma)))
-		return -ENOMEM;
+	struct vm_area_struct *prev;
+	int error = 0;
 
 	address &= PAGE_MASK;
-	error = security_mmap_addr(address);
-	if (error)
-		return error;
+	if (address < mmap_min_addr)
+		return -EPERM;
 
-	vma_lock_anon_vma(vma);
+	/* Enforce stack_guard_gap */
+	prev = vma->vm_prev;
+	/* Check that both stack segments have the same anon_vma? */
+	if (prev && !(prev->vm_flags & VM_GROWSDOWN) &&
+			(prev->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
+		if (address - prev->vm_end < stack_guard_gap)
+			return -ENOMEM;
+	}
+
+	/* We must make sure the anon_vma is allocated. */
+	if (unlikely(anon_vma_prepare(vma)))
+		return -ENOMEM;
 
 	/*
 	 * vma->vm_start/vm_end cannot change under us because the caller
 	 * is required to hold the mmap_sem in read mode.  We need the
 	 * anon_vma lock to serialize against concurrent expand_stacks.
 	 */
+	anon_vma_lock_write(vma->anon_vma);
 
 	/* Somebody else might have raced and expanded it already */
 	if (address < vma->vm_start) {
@@ -2266,7 +2358,7 @@
 				 * updates, but we only hold a shared mmap_sem
 				 * lock here, so we need to protect against
 				 * concurrent vma expansions.
-				 * vma_lock_anon_vma() doesn't help here, as
+				 * anon_vma_lock_write() doesn't help here, as
 				 * we don't guarantee that all growable vmas
 				 * in a mm share the same root anon vma.
 				 * So, we reuse mm->page_table_lock to guard
@@ -2288,34 +2380,31 @@
 			}
 		}
 	}
-	vma_unlock_anon_vma(vma);
+	anon_vma_unlock_write(vma->anon_vma);
 	khugepaged_enter_vma_merge(vma, vma->vm_flags);
 	validate_mm(mm);
 	return error;
 }
 
-/*
- * Note how expand_stack() refuses to expand the stack all the way to
- * abut the next virtual mapping, *unless* that mapping itself is also
- * a stack mapping. We want to leave room for a guard page, after all
- * (the guard page itself is not added here, that is done by the
- * actual page faulting logic)
- *
- * This matches the behavior of the guard page logic (see mm/memory.c:
- * check_stack_guard_page()), which only allows the guard page to be
- * removed under these circumstances.
- */
+/* enforced gap between the expanding stack and other mappings. */
+unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
+
+static int __init cmdline_parse_stack_guard_gap(char *p)
+{
+	unsigned long val;
+	char *endptr;
+
+	val = simple_strtoul(p, &endptr, 10);
+	if (!*endptr)
+		stack_guard_gap = val << PAGE_SHIFT;
+
+	return 0;
+}
+__setup("stack_guard_gap=", cmdline_parse_stack_guard_gap);
+
 #ifdef CONFIG_STACK_GROWSUP
 int expand_stack(struct vm_area_struct *vma, unsigned long address)
 {
-	struct vm_area_struct *next;
-
-	address &= PAGE_MASK;
-	next = vma->vm_next;
-	if (next && next->vm_start == address + PAGE_SIZE) {
-		if (!(next->vm_flags & VM_GROWSUP))
-			return -ENOMEM;
-	}
 	return expand_upwards(vma, address);
 }
 
@@ -2328,7 +2417,8 @@
 	vma = find_vma_prev(mm, addr, &prev);
 	if (vma && (vma->vm_start <= addr))
 		return vma;
-	if (!prev || expand_stack(prev, addr))
+	/* don't alter vm_end if the coredump is running */
+	if (!prev || !mmget_still_valid(mm) || expand_stack(prev, addr))
 		return NULL;
 	if (prev->vm_flags & VM_LOCKED)
 		populate_vma_page_range(prev, addr, prev->vm_end, NULL);
@@ -2337,14 +2427,6 @@
 #else
 int expand_stack(struct vm_area_struct *vma, unsigned long address)
 {
-	struct vm_area_struct *prev;
-
-	address &= PAGE_MASK;
-	prev = vma->vm_prev;
-	if (prev && prev->vm_end == address) {
-		if (!(prev->vm_flags & VM_GROWSDOWN))
-			return -ENOMEM;
-	}
 	return expand_downwards(vma, address);
 }
 
@@ -2362,6 +2444,9 @@
 		return vma;
 	if (!(vma->vm_flags & VM_GROWSDOWN))
 		return NULL;
+	/* don't alter vm_start if the coredump is running */
+	if (!mmget_still_valid(mm))
+		return NULL;
 	start = vma->vm_start;
 	if (expand_stack(vma, addr))
 		return NULL;
@@ -2408,11 +2493,28 @@
 {
 	struct vm_area_struct *next = prev ? prev->vm_next : mm->mmap;
 	struct mmu_gather tlb;
+	struct vm_area_struct *cur_vma;
 
 	lru_add_drain();
 	tlb_gather_mmu(&tlb, mm, start, end);
 	update_hiwater_rss(mm);
 	unmap_vmas(&tlb, vma, start, end);
+
+	/*
+	 * Ensure we have no stale TLB entries by the time this mapping is
+	 * removed from the rmap.
+	 * Note that we don't have to worry about nested flushes here because
+	 * we're holding the mm semaphore for removing the mapping - so any
+	 * concurrent flush in this region has to be coming through the rmap,
+	 * and we synchronize against that using the rmap lock.
+	 */
+	for (cur_vma = vma; cur_vma; cur_vma = cur_vma->vm_next) {
+		if ((cur_vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) != 0) {
+			tlb_flush_mmu(&tlb);
+			break;
+		}
+	}
+
 	free_pgtables(&tlb, vma, prev ? prev->vm_end : FIRST_USER_ADDRESS,
 				 next ? next->vm_start : USER_PGTABLES_CEILING);
 	tlb_finish_mmu(&tlb, start, end);
@@ -2442,7 +2544,7 @@
 		vma->vm_prev = prev;
 		vma_gap_update(vma);
 	} else
-		mm->highest_vm_end = prev ? prev->vm_end : 0;
+		mm->highest_vm_end = prev ? vm_end_gap(prev) : 0;
 	tail_vma->vm_next = NULL;
 
 	/* Kill the cache */
@@ -2488,7 +2590,7 @@
 		goto out_free_mpol;
 
 	if (new->vm_file)
-		get_file(new->vm_file);
+		vma_get_file(new);
 
 	if (new->vm_ops && new->vm_ops->open)
 		new->vm_ops->open(new);
@@ -2507,7 +2609,7 @@
 	if (new->vm_ops && new->vm_ops->close)
 		new->vm_ops->close(new);
 	if (new->vm_file)
-		fput(new->vm_file);
+		vma_fput(new);
 	unlink_anon_vmas(new);
  out_free_mpol:
 	mpol_put(vma_policy(new));
@@ -2649,7 +2751,7 @@
 	struct vm_area_struct *vma;
 	unsigned long populate = 0;
 	unsigned long ret = -EINVAL;
-	struct file *file;
+	struct file *file, *prfile;
 
 	pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. "
 			"See Documentation/vm/remap_file_pages.txt.\n",
@@ -2673,12 +2775,29 @@
 	if (!vma || !(vma->vm_flags & VM_SHARED))
 		goto out;
 
-	if (start < vma->vm_start || start + size > vma->vm_end)
+	if (start < vma->vm_start)
 		goto out;
 
-	if (pgoff == linear_page_index(vma, start)) {
-		ret = 0;
-		goto out;
+	if (start + size > vma->vm_end) {
+		struct vm_area_struct *next;
+
+		for (next = vma->vm_next; next; next = next->vm_next) {
+			/* hole between vmas ? */
+			if (next->vm_start != next->vm_prev->vm_end)
+				goto out;
+
+			if (next->vm_file != vma->vm_file)
+				goto out;
+
+			if (next->vm_flags != vma->vm_flags)
+				goto out;
+
+			if (start + size <= next->vm_end)
+				break;
+		}
+
+		if (!next)
+			goto out;
 	}
 
 	prot |= vma->vm_flags & VM_READ ? PROT_READ : 0;
@@ -2688,15 +2807,39 @@
 	flags &= MAP_NONBLOCK;
 	flags |= MAP_SHARED | MAP_FIXED | MAP_POPULATE;
 	if (vma->vm_flags & VM_LOCKED) {
+		struct vm_area_struct *tmp;
 		flags |= MAP_LOCKED;
+
 		/* drop PG_Mlocked flag for over-mapped range */
-		munlock_vma_pages_range(vma, start, start + size);
+		for (tmp = vma; tmp->vm_start >= start + size;
+				tmp = tmp->vm_next) {
+			munlock_vma_pages_range(tmp,
+					max(tmp->vm_start, start),
+					min(tmp->vm_end, start + size));
+		}
 	}
 
-	file = get_file(vma->vm_file);
+	vma_get_file(vma);
+	file = vma->vm_file;
+	prfile = vma->vm_prfile;
 	ret = do_mmap_pgoff(vma->vm_file, start, size,
 			prot, flags, pgoff, &populate);
+	if (!IS_ERR_VALUE(ret) && file && prfile) {
+		struct vm_area_struct *new_vma;
+
+		new_vma = find_vma(mm, ret);
+		if (!new_vma->vm_prfile)
+			new_vma->vm_prfile = prfile;
+		if (new_vma != vma)
+			get_file(prfile);
+	}
+	/*
+	 * two fput()s instead of vma_fput(vma),
+	 * coz vma may not be available anymore.
+	 */
 	fput(file);
+	if (prfile)
+		fput(prfile);
 out:
 	up_write(&mm->mmap_sem);
 	if (populate)
@@ -2730,10 +2873,6 @@
 	pgoff_t pgoff = addr >> PAGE_SHIFT;
 	int error;
 
-	len = PAGE_ALIGN(len);
-	if (!len)
-		return addr;
-
 	flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
 
 	error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
@@ -2801,12 +2940,19 @@
 	return addr;
 }
 
-unsigned long vm_brk(unsigned long addr, unsigned long len)
+unsigned long vm_brk(unsigned long addr, unsigned long request)
 {
 	struct mm_struct *mm = current->mm;
+	unsigned long len;
 	unsigned long ret;
 	bool populate;
 
+	len = PAGE_ALIGN(request);
+	if (len < request)
+		return -ENOMEM;
+	if (!len)
+		return addr;
+
 	down_write(&mm->mmap_sem);
 	ret = do_brk(addr, len);
 	populate = ((mm->def_flags & VM_LOCKED) != 0);
@@ -2860,6 +3006,7 @@
 		if (vma->vm_flags & VM_ACCOUNT)
 			nr_accounted += vma_pages(vma);
 		vma = remove_vma(vma);
+		cond_resched();
 	}
 	vm_unacct_memory(nr_accounted);
 }
@@ -2966,7 +3113,7 @@
 		if (anon_vma_clone(new_vma, vma))
 			goto out_free_mempol;
 		if (new_vma->vm_file)
-			get_file(new_vma->vm_file);
+			vma_get_file(new_vma);
 		if (new_vma->vm_ops && new_vma->vm_ops->open)
 			new_vma->vm_ops->open(new_vma);
 		vma_link(mm, new_vma, prev, rb_link, rb_parent);
--- linux-4.4.0.orig/mm/mmu_context.c
+++ linux-4.4.0/mm/mmu_context.c
@@ -4,9 +4,9 @@
  */
 
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/mmu_context.h>
 #include <linux/export.h>
-#include <linux/sched.h>
 
 #include <asm/mmu_context.h>
 
--- linux-4.4.0.orig/mm/mmu_notifier.c
+++ linux-4.4.0/mm/mmu_notifier.c
@@ -286,7 +286,7 @@
 	 * thanks to mm_take_all_locks().
 	 */
 	spin_lock(&mm->mmu_notifier_mm->lock);
-	hlist_add_head(&mn->hlist, &mm->mmu_notifier_mm->list);
+	hlist_add_head_rcu(&mn->hlist, &mm->mmu_notifier_mm->list);
 	spin_unlock(&mm->mmu_notifier_mm->lock);
 
 	mm_drop_all_locks(mm);
--- linux-4.4.0.orig/mm/mprotect.c
+++ linux-4.4.0/mm/mprotect.c
@@ -72,6 +72,7 @@
 	if (!pte)
 		return 0;
 
+	flush_tlb_batched_pending(vma->vm_mm);
 	arch_enter_lazy_mmu_mode();
 	do {
 		oldpte = *pte;
@@ -254,6 +255,42 @@
 	return pages;
 }
 
+static int prot_none_pte_entry(pte_t *pte, unsigned long addr,
+			       unsigned long next, struct mm_walk *walk)
+{
+	return pfn_modify_allowed(pte_pfn(*pte), *(pgprot_t *)(walk->private)) ?
+		0 : -EACCES;
+}
+
+static int prot_none_hugetlb_entry(pte_t *pte, unsigned long hmask,
+				   unsigned long addr, unsigned long next,
+				   struct mm_walk *walk)
+{
+	return pfn_modify_allowed(pte_pfn(*pte), *(pgprot_t *)(walk->private)) ?
+		0 : -EACCES;
+}
+
+static int prot_none_test(unsigned long addr, unsigned long next,
+			  struct mm_walk *walk)
+{
+	return 0;
+}
+
+static int prot_none_walk(struct vm_area_struct *vma, unsigned long start,
+			   unsigned long end, unsigned long newflags)
+{
+	pgprot_t new_pgprot = vm_get_page_prot(newflags);
+	struct mm_walk prot_none_walk = {
+		.pte_entry = prot_none_pte_entry,
+		.hugetlb_entry = prot_none_hugetlb_entry,
+		.test_walk = prot_none_test,
+		.mm = current->mm,
+		.private = &new_pgprot,
+	};
+
+	return walk_page_range(start, end, &prot_none_walk);
+}
+
 int
 mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
 	unsigned long start, unsigned long end, unsigned long newflags)
@@ -272,6 +309,19 @@
 	}
 
 	/*
+	 * Do PROT_NONE PFN permission checks here when we can still
+	 * bail out without undoing a lot of state. This is a rather
+	 * uncommon case, so doesn't need to be very optimized.
+	 */
+	if (arch_has_pfn_modify_check() &&
+	    (vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) &&
+	    (newflags & (VM_READ|VM_WRITE|VM_EXEC)) == 0) {
+		error = prot_none_walk(vma, start, end, newflags);
+		if (error)
+			return error;
+	}
+
+	/*
 	 * If we make a private mapping writable we increase our commit;
 	 * but (without finer accounting) cannot reduce our commit if we
 	 * make it unwritable again. hugetlb mapping were accounted for
--- linux-4.4.0.orig/mm/mremap.c
+++ linux-4.4.0/mm/mremap.c
@@ -96,6 +96,8 @@
 	struct mm_struct *mm = vma->vm_mm;
 	pte_t *old_pte, *new_pte, pte;
 	spinlock_t *old_ptl, *new_ptl;
+	bool force_flush = false;
+	unsigned long len = old_end - old_addr;
 
 	/*
 	 * When need_rmap_locks is true, we take the i_mmap_rwsem and anon_vma
@@ -135,6 +137,7 @@
 	new_ptl = pte_lockptr(mm, new_pmd);
 	if (new_ptl != old_ptl)
 		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+	flush_tlb_batched_pending(vma->vm_mm);
 	arch_enter_lazy_mmu_mode();
 
 	for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE,
@@ -142,12 +145,26 @@
 		if (pte_none(*old_pte))
 			continue;
 		pte = ptep_get_and_clear(mm, old_addr, old_pte);
+		/*
+		 * If we are remapping a valid PTE, make sure
+		 * to flush TLB before we drop the PTL for the PTE.
+		 *
+		 * NOTE! Both old and new PTL matter: the old one
+		 * for racing with page_mkclean(), the new one to
+		 * make sure the physical page stays valid until
+		 * the TLB entry for the old mapping has been
+		 * flushed.
+		 */
+		if (pte_present(pte))
+			force_flush = true;
 		pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr);
 		pte = move_soft_dirty_pte(pte);
 		set_pte_at(mm, new_addr, new_pte, pte);
 	}
 
 	arch_leave_lazy_mmu_mode();
+	if (force_flush)
+		flush_tlb_range(vma, old_end - len, old_end);
 	if (new_ptl != old_ptl)
 		spin_unlock(new_ptl);
 	pte_unmap(new_pte - 1);
@@ -167,7 +184,6 @@
 {
 	unsigned long extent, next, old_end;
 	pmd_t *old_pmd, *new_pmd;
-	bool need_flush = false;
 	unsigned long mmun_start;	/* For mmu_notifiers */
 	unsigned long mmun_end;		/* For mmu_notifiers */
 
@@ -206,7 +222,6 @@
 					anon_vma_unlock_write(vma->anon_vma);
 			}
 			if (err > 0) {
-				need_flush = true;
 				continue;
 			} else if (!err) {
 				split_huge_page_pmd(vma, old_addr, old_pmd);
@@ -223,10 +238,7 @@
 			extent = LATENCY_LIMIT;
 		move_ptes(vma, old_pmd, old_addr, old_addr + extent,
 			  new_vma, new_pmd, new_addr, need_rmap_locks);
-		need_flush = true;
 	}
-	if (likely(need_flush))
-		flush_tlb_range(vma, old_end-len, old_addr);
 
 	mmu_notifier_invalidate_range_end(vma->vm_mm, mmun_start, mmun_end);
 
--- linux-4.4.0.orig/mm/nommu.c
+++ linux-4.4.0/mm/nommu.c
@@ -184,40 +184,32 @@
  */
 long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 		    unsigned long start, unsigned long nr_pages,
-		    int write, int force, struct page **pages,
+		    unsigned int gup_flags, struct page **pages,
 		    struct vm_area_struct **vmas)
 {
-	int flags = 0;
-
-	if (write)
-		flags |= FOLL_WRITE;
-	if (force)
-		flags |= FOLL_FORCE;
-
-	return __get_user_pages(tsk, mm, start, nr_pages, flags, pages, vmas,
-				NULL);
+	return __get_user_pages(tsk, mm, start, nr_pages,
+				gup_flags, pages, vmas, NULL);
 }
 EXPORT_SYMBOL(get_user_pages);
 
 long get_user_pages_locked(struct task_struct *tsk, struct mm_struct *mm,
 			   unsigned long start, unsigned long nr_pages,
-			   int write, int force, struct page **pages,
+			   unsigned int gup_flags, struct page **pages,
 			   int *locked)
 {
-	return get_user_pages(tsk, mm, start, nr_pages, write, force,
+	return get_user_pages(tsk, mm, start, nr_pages, gup_flags,
 			      pages, NULL);
 }
 EXPORT_SYMBOL(get_user_pages_locked);
 
 long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
 			       unsigned long start, unsigned long nr_pages,
-			       int write, int force, struct page **pages,
-			       unsigned int gup_flags)
+			       struct page **pages, unsigned int gup_flags)
 {
 	long ret;
 	down_read(&mm->mmap_sem);
-	ret = get_user_pages(tsk, mm, start, nr_pages, write, force,
-			     pages, NULL);
+	ret = __get_user_pages(tsk, mm, start, nr_pages, gup_flags, pages,
+			       NULL, NULL);
 	up_read(&mm->mmap_sem);
 	return ret;
 }
@@ -225,10 +217,10 @@
 
 long get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
 			     unsigned long start, unsigned long nr_pages,
-			     int write, int force, struct page **pages)
+			     struct page **pages, unsigned int gup_flags)
 {
-	return __get_user_pages_unlocked(tsk, mm, start, nr_pages, write,
-					 force, pages, 0);
+	return __get_user_pages_unlocked(tsk, mm, start, nr_pages,
+					 pages, gup_flags);
 }
 EXPORT_SYMBOL(get_user_pages_unlocked);
 
@@ -480,10 +472,14 @@
 EXPORT_SYMBOL_GPL(vm_unmap_aliases);
 
 /*
- * Implement a stub for vmalloc_sync_all() if the architecture chose not to
- * have one.
+ * Implement a stub for vmalloc_sync_[un]mapping() if the architecture
+ * chose not to have one.
  */
-void __weak vmalloc_sync_all(void)
+void __weak vmalloc_sync_mappings(void)
+{
+}
+
+void __weak vmalloc_sync_unmappings(void)
 {
 }
 
@@ -671,7 +667,7 @@
 		up_write(&nommu_region_sem);
 
 		if (region->vm_file)
-			fput(region->vm_file);
+			vmr_fput(region);
 
 		/* IO memory and memory shared directly out of the pagecache
 		 * from ramfs/tmpfs mustn't be released here */
@@ -829,7 +825,7 @@
 	if (vma->vm_ops && vma->vm_ops->close)
 		vma->vm_ops->close(vma);
 	if (vma->vm_file)
-		fput(vma->vm_file);
+		vma_fput(vma);
 	put_nommu_region(vma->vm_region);
 	kmem_cache_free(vm_area_cachep, vma);
 }
@@ -1355,7 +1351,7 @@
 					goto error_just_free;
 				}
 			}
-			fput(region->vm_file);
+			vmr_fput(region);
 			kmem_cache_free(vm_region_jar, region);
 			region = pregion;
 			result = start;
@@ -1430,10 +1426,10 @@
 	up_write(&nommu_region_sem);
 error:
 	if (region->vm_file)
-		fput(region->vm_file);
+		vmr_fput(region);
 	kmem_cache_free(vm_region_jar, region);
 	if (vma->vm_file)
-		fput(vma->vm_file);
+		vma_fput(vma);
 	kmem_cache_free(vm_area_cachep, vma);
 	return ret;
 
@@ -1937,9 +1933,10 @@
 EXPORT_SYMBOL(filemap_map_pages);
 
 static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
-		unsigned long addr, void *buf, int len, int write)
+		unsigned long addr, void *buf, int len, unsigned int gup_flags)
 {
 	struct vm_area_struct *vma;
+	int write = gup_flags & FOLL_WRITE;
 
 	down_read(&mm->mmap_sem);
 
@@ -1974,14 +1971,14 @@
  * @addr:	start address to access
  * @buf:	source or destination buffer
  * @len:	number of bytes to transfer
- * @write:	whether the access is a write
+ * @gup_flags:	flags modifying lookup behaviour
  *
  * The caller must hold a reference on @mm.
  */
 int access_remote_vm(struct mm_struct *mm, unsigned long addr,
-		void *buf, int len, int write)
+		void *buf, int len, unsigned int gup_flags)
 {
-	return __access_remote_vm(NULL, mm, addr, buf, len, write);
+	return __access_remote_vm(NULL, mm, addr, buf, len, gup_flags);
 }
 
 /*
@@ -1999,7 +1996,8 @@
 	if (!mm)
 		return 0;
 
-	len = __access_remote_vm(tsk, mm, addr, buf, len, write);
+	len = __access_remote_vm(tsk, mm, addr, buf, len,
+			write ? FOLL_WRITE : 0);
 
 	mmput(mm);
 	return len;
--- linux-4.4.0.orig/mm/oom_kill.c
+++ linux-4.4.0/mm/oom_kill.c
@@ -544,6 +544,13 @@
 	 * still freeing memory.
 	 */
 	read_lock(&tasklist_lock);
+
+	/*
+	 * The task 'p' might have already exited before reaching here. The
+	 * put_task_struct() will free task_struct 'p' while the loop still try
+	 * to access the field of 'p', so, get an extra reference.
+	 */
+	get_task_struct(p);
 	for_each_thread(p, t) {
 		list_for_each_entry(child, &t->children, sibling) {
 			unsigned int child_points;
@@ -563,6 +570,7 @@
 			}
 		}
 	}
+	put_task_struct(p);
 	read_unlock(&tasklist_lock);
 
 	p = find_lock_task_mm(victim);
--- linux-4.4.0.orig/mm/page-writeback.c
+++ linux-4.4.0/mm/page-writeback.c
@@ -200,11 +200,11 @@
 	if (this_bw < tot_bw) {
 		if (min) {
 			min *= this_bw;
-			do_div(min, tot_bw);
+			min = div64_ul(min, tot_bw);
 		}
 		if (max < 100) {
 			max *= this_bw;
-			do_div(max, tot_bw);
+			max = div64_ul(max, tot_bw);
 		}
 	}
 
@@ -359,8 +359,9 @@
 	struct dirty_throttle_control *gdtc = mdtc_gdtc(dtc);
 	unsigned long bytes = vm_dirty_bytes;
 	unsigned long bg_bytes = dirty_background_bytes;
-	unsigned long ratio = vm_dirty_ratio;
-	unsigned long bg_ratio = dirty_background_ratio;
+	/* convert ratios to per-PAGE_SIZE for higher precision */
+	unsigned long ratio = (vm_dirty_ratio * PAGE_SIZE) / 100;
+	unsigned long bg_ratio = (dirty_background_ratio * PAGE_SIZE) / 100;
 	unsigned long thresh;
 	unsigned long bg_thresh;
 	struct task_struct *tsk;
@@ -372,26 +373,28 @@
 		/*
 		 * The byte settings can't be applied directly to memcg
 		 * domains.  Convert them to ratios by scaling against
-		 * globally available memory.
+		 * globally available memory.  As the ratios are in
+		 * per-PAGE_SIZE, they can be obtained by dividing bytes by
+		 * number of pages.
 		 */
 		if (bytes)
-			ratio = min(DIV_ROUND_UP(bytes, PAGE_SIZE) * 100 /
-				    global_avail, 100UL);
+			ratio = min(DIV_ROUND_UP(bytes, global_avail),
+				    PAGE_SIZE);
 		if (bg_bytes)
-			bg_ratio = min(DIV_ROUND_UP(bg_bytes, PAGE_SIZE) * 100 /
-				       global_avail, 100UL);
+			bg_ratio = min(DIV_ROUND_UP(bg_bytes, global_avail),
+				       PAGE_SIZE);
 		bytes = bg_bytes = 0;
 	}
 
 	if (bytes)
 		thresh = DIV_ROUND_UP(bytes, PAGE_SIZE);
 	else
-		thresh = (ratio * available_memory) / 100;
+		thresh = (ratio * available_memory) / PAGE_SIZE;
 
 	if (bg_bytes)
 		bg_thresh = DIV_ROUND_UP(bg_bytes, PAGE_SIZE);
 	else
-		bg_thresh = (bg_ratio * available_memory) / 100;
+		bg_thresh = (bg_ratio * available_memory) / PAGE_SIZE;
 
 	if (bg_thresh >= thresh)
 		bg_thresh = thresh / 2;
@@ -1159,6 +1162,7 @@
 	unsigned long balanced_dirty_ratelimit;
 	unsigned long step;
 	unsigned long x;
+	unsigned long shift;
 
 	/*
 	 * The dirty rate will match the writeout rate in long term, except
@@ -1283,11 +1287,11 @@
 	 * rate itself is constantly fluctuating. So decrease the track speed
 	 * when it gets close to the target. Helps eliminate pointless tremors.
 	 */
-	step >>= dirty_ratelimit / (2 * step + 1);
-	/*
-	 * Limit the tracking speed to avoid overshooting.
-	 */
-	step = (step + 7) / 8;
+	shift = dirty_ratelimit / (2 * step + 1);
+	if (shift < BITS_PER_LONG)
+		step = DIV_ROUND_UP(step >> shift, 8);
+	else
+		step = 0;
 
 	if (dirty_ratelimit < balanced_dirty_ratelimit)
 		dirty_ratelimit += step;
@@ -1488,7 +1492,7 @@
 	 */
 	dtc->wb_thresh = __wb_calc_thresh(dtc);
 	dtc->wb_bg_thresh = dtc->thresh ?
-		div_u64((u64)dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0;
+		div64_u64(dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0;
 
 	/*
 	 * In order to avoid the stacked BDI deadlock we need
@@ -1899,7 +1903,8 @@
 	if (gdtc->dirty > gdtc->bg_thresh)
 		return true;
 
-	if (wb_stat(wb, WB_RECLAIMABLE) > __wb_calc_thresh(gdtc))
+	if (wb_stat(wb, WB_RECLAIMABLE) >
+	    wb_calc_thresh(gdtc->wb, gdtc->bg_thresh))
 		return true;
 
 	if (mdtc) {
@@ -1913,7 +1918,8 @@
 		if (mdtc->dirty > mdtc->bg_thresh)
 			return true;
 
-		if (wb_stat(wb, WB_RECLAIMABLE) > __wb_calc_thresh(mdtc))
+		if (wb_stat(wb, WB_RECLAIMABLE) >
+		    wb_calc_thresh(mdtc->wb, mdtc->bg_thresh))
 			return true;
 	}
 
@@ -1972,11 +1978,11 @@
 	 * We want to write everything out, not just down to the dirty
 	 * threshold
 	 */
-	if (!bdi_has_dirty_io(&q->backing_dev_info))
+	if (!bdi_has_dirty_io(q->backing_dev_info))
 		return;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(wb, &q->backing_dev_info.wb_list, bdi_node)
+	list_for_each_entry_rcu(wb, &q->backing_dev_info->wb_list, bdi_node)
 		if (wb_has_dirty_io(wb))
 			wb_start_writeback(wb, nr_pages, true,
 					   WB_REASON_LAPTOP_TIMER);
@@ -2138,6 +2144,13 @@
  * not miss some pages (e.g., because some other process has cleared TOWRITE
  * tag we set). The rule we follow is that TOWRITE tag can be cleared only
  * by the process clearing the DIRTY tag (and submitting the page for IO).
+ *
+ * To avoid deadlocks between range_cyclic writeback and callers that hold
+ * pages in PageWriteback to aggregate IO until write_cache_pages() returns,
+ * we do not loop back to the start of the file. Doing so causes a page
+ * lock/page writeback access order inversion - we should only ever lock
+ * multiple pages in ascending page->index order, and looping back to the start
+ * of the file violates that rule and causes deadlocks.
  */
 int write_cache_pages(struct address_space *mapping,
 		      struct writeback_control *wbc, writepage_t writepage,
@@ -2145,13 +2158,13 @@
 {
 	int ret = 0;
 	int done = 0;
+	int error;
 	struct pagevec pvec;
 	int nr_pages;
 	pgoff_t uninitialized_var(writeback_index);
 	pgoff_t index;
 	pgoff_t end;		/* Inclusive */
 	pgoff_t done_index;
-	int cycled;
 	int range_whole = 0;
 	int tag;
 
@@ -2159,23 +2172,17 @@
 	if (wbc->range_cyclic) {
 		writeback_index = mapping->writeback_index; /* prev offset */
 		index = writeback_index;
-		if (index == 0)
-			cycled = 1;
-		else
-			cycled = 0;
 		end = -1;
 	} else {
 		index = wbc->range_start >> PAGE_CACHE_SHIFT;
 		end = wbc->range_end >> PAGE_CACHE_SHIFT;
 		if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
 			range_whole = 1;
-		cycled = 1; /* ignore range_cyclic tests */
 	}
 	if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
 		tag = PAGECACHE_TAG_TOWRITE;
 	else
 		tag = PAGECACHE_TAG_DIRTY;
-retry:
 	if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
 		tag_pages_for_writeback(mapping, index, end);
 	done_index = index;
@@ -2241,25 +2248,31 @@
 				goto continue_unlock;
 
 			trace_wbc_writepage(wbc, inode_to_bdi(mapping->host));
-			ret = (*writepage)(page, wbc, data);
-			if (unlikely(ret)) {
-				if (ret == AOP_WRITEPAGE_ACTIVATE) {
+			error = (*writepage)(page, wbc, data);
+			if (unlikely(error)) {
+				/*
+				 * Handle errors according to the type of
+				 * writeback. There's no need to continue for
+				 * background writeback. Just push done_index
+				 * past this page so media errors won't choke
+				 * writeout for the entire file. For integrity
+				 * writeback, we must process the entire dirty
+				 * set regardless of errors because the fs may
+				 * still have state to clear for each page. In
+				 * that case we continue processing and return
+				 * the first error.
+				 */
+				if (error == AOP_WRITEPAGE_ACTIVATE) {
 					unlock_page(page);
-					ret = 0;
-				} else {
-					/*
-					 * done_index is set past this page,
-					 * so media errors will not choke
-					 * background writeout for the entire
-					 * file. This has consequences for
-					 * range_cyclic semantics (ie. it may
-					 * not be suitable for data integrity
-					 * writeout).
-					 */
+					error = 0;
+				} else if (wbc->sync_mode != WB_SYNC_ALL) {
+					ret = error;
 					done_index = page->index + 1;
 					done = 1;
 					break;
 				}
+				if (!ret)
+					ret = error;
 			}
 
 			/*
@@ -2277,17 +2290,14 @@
 		pagevec_release(&pvec);
 		cond_resched();
 	}
-	if (!cycled && !done) {
-		/*
-		 * range_cyclic:
-		 * We hit the last page and there is more work to be done: wrap
-		 * back to the start of the file
-		 */
-		cycled = 1;
-		index = 0;
-		end = writeback_index - 1;
-		goto retry;
-	}
+
+	/*
+	 * If we hit the last page and there is more work to be done: wrap
+	 * back the index back to the start of the file for the next
+	 * time we are called.
+	 */
+	if (wbc->range_cyclic && !done)
+		done_index = 0;
 	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
 		mapping->writeback_index = done_index;
 
@@ -2504,13 +2514,13 @@
 	if (mapping && mapping_cap_account_dirty(mapping)) {
 		struct inode *inode = mapping->host;
 		struct bdi_writeback *wb;
-		bool locked;
+		struct wb_lock_cookie cookie = {};
 
-		wb = unlocked_inode_to_wb_begin(inode, &locked);
+		wb = unlocked_inode_to_wb_begin(inode, &cookie);
 		current->nr_dirtied--;
 		dec_zone_page_state(page, NR_DIRTIED);
 		dec_wb_stat(wb, WB_DIRTIED);
-		unlocked_inode_to_wb_end(inode, locked);
+		unlocked_inode_to_wb_end(inode, &cookie);
 	}
 }
 EXPORT_SYMBOL(account_page_redirty);
@@ -2616,15 +2626,15 @@
 		struct inode *inode = mapping->host;
 		struct bdi_writeback *wb;
 		struct mem_cgroup *memcg;
-		bool locked;
+		struct wb_lock_cookie cookie = {};
 
 		memcg = mem_cgroup_begin_page_stat(page);
-		wb = unlocked_inode_to_wb_begin(inode, &locked);
+		wb = unlocked_inode_to_wb_begin(inode, &cookie);
 
 		if (TestClearPageDirty(page))
 			account_page_cleaned(page, mapping, memcg, wb);
 
-		unlocked_inode_to_wb_end(inode, locked);
+		unlocked_inode_to_wb_end(inode, &cookie);
 		mem_cgroup_end_page_stat(memcg);
 	} else {
 		ClearPageDirty(page);
@@ -2657,7 +2667,7 @@
 		struct inode *inode = mapping->host;
 		struct bdi_writeback *wb;
 		struct mem_cgroup *memcg;
-		bool locked;
+		struct wb_lock_cookie cookie = {};
 
 		/*
 		 * Yes, Virginia, this is indeed insane.
@@ -2695,14 +2705,14 @@
 		 * exclusion.
 		 */
 		memcg = mem_cgroup_begin_page_stat(page);
-		wb = unlocked_inode_to_wb_begin(inode, &locked);
+		wb = unlocked_inode_to_wb_begin(inode, &cookie);
 		if (TestClearPageDirty(page)) {
 			mem_cgroup_dec_page_stat(memcg, MEM_CGROUP_STAT_DIRTY);
 			dec_zone_page_state(page, NR_FILE_DIRTY);
 			dec_wb_stat(wb, WB_RECLAIMABLE);
 			ret = 1;
 		}
-		unlocked_inode_to_wb_end(inode, locked);
+		unlocked_inode_to_wb_end(inode, &cookie);
 		mem_cgroup_end_page_stat(memcg);
 		return ret;
 	}
--- linux-4.4.0.orig/mm/page_alloc.c
+++ linux-4.4.0/mm/page_alloc.c
@@ -267,15 +267,46 @@
 int page_group_by_mobility_disabled __read_mostly;
 
 #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
+
+/*
+ * Determine how many pages need to be initialized durig early boot
+ * (non-deferred initialization).
+ * The value of first_deferred_pfn will be set later, once non-deferred pages
+ * are initialized, but for now set it ULONG_MAX.
+ */
 static inline void reset_deferred_meminit(pg_data_t *pgdat)
 {
+	phys_addr_t start_addr, end_addr;
+	unsigned long max_pgcnt;
+	unsigned long reserved;
+
+	/*
+	 * Initialise at least 2G of a node but also take into account that
+	 * two large system hashes that can take up 1GB for 0.25TB/node.
+	 */
+	max_pgcnt = max(2UL << (30 - PAGE_SHIFT),
+			(pgdat->node_spanned_pages >> 8));
+
+	/*
+	 * Compensate the all the memblock reservations (e.g. crash kernel)
+	 * from the initial estimation to make sure we will initialize enough
+	 * memory to boot.
+	 */
+	start_addr = PFN_PHYS(pgdat->node_start_pfn);
+	end_addr = PFN_PHYS(pgdat->node_start_pfn + max_pgcnt);
+	reserved = memblock_reserved_memory_within(start_addr, end_addr);
+	max_pgcnt += PHYS_PFN(reserved);
+
+	pgdat->static_init_pgcnt = min(max_pgcnt, pgdat->node_spanned_pages);
 	pgdat->first_deferred_pfn = ULONG_MAX;
 }
 
 /* Returns true if the struct page for the pfn is uninitialised */
 static inline bool __meminit early_page_uninitialised(unsigned long pfn)
 {
-	if (pfn >= NODE_DATA(early_pfn_to_nid(pfn))->first_deferred_pfn)
+	int nid = early_pfn_to_nid(pfn);
+
+	if (node_online(nid) && pfn >= NODE_DATA(nid)->first_deferred_pfn)
 		return true;
 
 	return false;
@@ -300,10 +331,9 @@
 	/* Always populate low zones for address-contrained allocations */
 	if (zone_end < pgdat_end_pfn(pgdat))
 		return true;
-
 	/* Initialise at least 2G of the highest zone */
 	(*nr_initialised)++;
-	if (*nr_initialised > (2UL << (30 - PAGE_SHIFT)) &&
+	if ((*nr_initialised > pgdat->static_init_pgcnt) &&
 	    (pfn & (PAGES_PER_SECTION - 1)) == 0) {
 		pgdat->first_deferred_pfn = pfn;
 		return false;
@@ -539,6 +569,9 @@
 		return;
 
 	page_ext = lookup_page_ext(page);
+	if (unlikely(!page_ext))
+		return;
+
 	__set_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags);
 
 	INIT_LIST_HEAD(&page->lru);
@@ -556,6 +589,9 @@
 		return;
 
 	page_ext = lookup_page_ext(page);
+	if (unlikely(!page_ext))
+		return;
+
 	__clear_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags);
 
 	set_page_private(page, 0);
@@ -662,34 +698,28 @@
 	unsigned long combined_idx;
 	unsigned long uninitialized_var(buddy_idx);
 	struct page *buddy;
-	unsigned int max_order = MAX_ORDER;
+	unsigned int max_order;
+
+	max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
 
 	VM_BUG_ON(!zone_is_initialized(zone));
 	VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page);
 
 	VM_BUG_ON(migratetype == -1);
-	if (is_migrate_isolate(migratetype)) {
-		/*
-		 * We restrict max order of merging to prevent merge
-		 * between freepages on isolate pageblock and normal
-		 * pageblock. Without this, pageblock isolation
-		 * could cause incorrect freepage accounting.
-		 */
-		max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
-	} else {
+	if (likely(!is_migrate_isolate(migratetype)))
 		__mod_zone_freepage_state(zone, 1 << order, migratetype);
-	}
 
-	page_idx = pfn & ((1 << max_order) - 1);
+	page_idx = pfn & ((1 << MAX_ORDER) - 1);
 
 	VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page);
 	VM_BUG_ON_PAGE(bad_range(zone, page), page);
 
+continue_merging:
 	while (order < max_order - 1) {
 		buddy_idx = __find_buddy_index(page_idx, order);
 		buddy = page + (buddy_idx - page_idx);
 		if (!page_is_buddy(page, buddy, order))
-			break;
+			goto done_merging;
 		/*
 		 * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
 		 * merge with it and move up one order.
@@ -706,6 +736,32 @@
 		page_idx = combined_idx;
 		order++;
 	}
+	if (max_order < MAX_ORDER) {
+		/* If we are here, it means order is >= pageblock_order.
+		 * We want to prevent merge between freepages on isolate
+		 * pageblock and normal pageblock. Without this, pageblock
+		 * isolation could cause incorrect freepage or CMA accounting.
+		 *
+		 * We don't want to hit this code for the more frequent
+		 * low-order merging.
+		 */
+		if (unlikely(has_isolate_pageblock(zone))) {
+			int buddy_mt;
+
+			buddy_idx = __find_buddy_index(page_idx, order);
+			buddy = page + (buddy_idx - page_idx);
+			buddy_mt = get_pageblock_migratetype(buddy);
+
+			if (migratetype != buddy_mt
+					&& (is_migrate_isolate(migratetype) ||
+						is_migrate_isolate(buddy_mt)))
+				goto done_merging;
+		}
+		max_order++;
+		goto continue_merging;
+	}
+
+done_merging:
 	set_page_order(page, order);
 
 	/*
@@ -779,7 +835,6 @@
 {
 	int migratetype = 0;
 	int batch_free = 0;
-	int to_free = count;
 	unsigned long nr_scanned;
 
 	spin_lock(&zone->lock);
@@ -787,7 +842,12 @@
 	if (nr_scanned)
 		__mod_zone_page_state(zone, NR_PAGES_SCANNED, -nr_scanned);
 
-	while (to_free) {
+	/*
+	 * Ensure proper count is passed which otherwise would stuck in the
+	 * below while (list_empty(list)) loop.
+	 */
+	count = min(pcp->count, count);
+	while (count) {
 		struct page *page;
 		struct list_head *list;
 
@@ -807,7 +867,7 @@
 
 		/* This is the only non-empty list. Free them all. */
 		if (batch_free == MIGRATE_PCPTYPES)
-			batch_free = to_free;
+			batch_free = count;
 
 		do {
 			int mt;	/* migratetype of the to-be-freed page */
@@ -825,7 +885,7 @@
 
 			__free_one_page(page, page_to_pfn(page), zone, 0, mt);
 			trace_mm_page_pcpu_drain(page, 0, mt);
-		} while (--to_free && --batch_free && !list_empty(list));
+		} while (--count && --batch_free && !list_empty(list));
 	}
 	spin_unlock(&zone->lock);
 }
@@ -931,7 +991,7 @@
  * marks the pages PageReserved. The remaining valid pages are later
  * sent to the buddy page allocator.
  */
-void __meminit reserve_bootmem_region(unsigned long start, unsigned long end)
+void __meminit reserve_bootmem_region(phys_addr_t start, phys_addr_t end)
 {
 	unsigned long start_pfn = PFN_DOWN(start);
 	unsigned long end_pfn = PFN_UP(end);
@@ -1037,7 +1097,7 @@
 	spin_lock(&early_pfn_lock);
 	nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache);
 	if (nid < 0)
-		nid = 0;
+		nid = first_online_node;
 	spin_unlock(&early_pfn_lock);
 
 	return nid;
@@ -1362,7 +1422,7 @@
 }
 
 static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
-								int alloc_flags)
+							unsigned int alloc_flags)
 {
 	int i;
 
@@ -1486,14 +1546,14 @@
 #endif
 
 	for (page = start_page; page <= end_page;) {
-		/* Make sure we are not inadvertently changing nodes */
-		VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
-
 		if (!pfn_valid_within(page_to_pfn(page))) {
 			page++;
 			continue;
 		}
 
+		/* Make sure we are not inadvertently changing nodes */
+		VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
+
 		if (!PageBuddy(page)) {
 			page++;
 			continue;
@@ -1707,13 +1767,25 @@
 						struct page, lru);
 
 			/*
-			 * It should never happen but changes to locking could
-			 * inadvertently allow a per-cpu drain to add pages
-			 * to MIGRATE_HIGHATOMIC while unreserving so be safe
-			 * and watch for underflows.
+			 * In page freeing path, migratetype change is racy so
+			 * we can counter several free pages in a pageblock
+			 * in this loop althoug we changed the pageblock type
+			 * from highatomic to ac->migratetype. So we should
+			 * adjust the count once.
 			 */
-			zone->nr_reserved_highatomic -= min(pageblock_nr_pages,
-				zone->nr_reserved_highatomic);
+			if (get_pageblock_migratetype(page) ==
+							MIGRATE_HIGHATOMIC) {
+				/*
+				 * It should never happen but changes to
+				 * locking could inadvertently allow a per-cpu
+				 * drain to add pages to MIGRATE_HIGHATOMIC
+				 * while unreserving so be safe and watch for
+				 * underflows.
+				 */
+				zone->nr_reserved_highatomic -= min(
+						pageblock_nr_pages,
+						zone->nr_reserved_highatomic);
+			}
 
 			/*
 			 * Convert to ac->migratetype and avoid the normal
@@ -2190,7 +2262,8 @@
 static inline
 struct page *buffered_rmqueue(struct zone *preferred_zone,
 			struct zone *zone, unsigned int order,
-			gfp_t gfp_flags, int alloc_flags, int migratetype)
+			gfp_t gfp_flags, unsigned int alloc_flags,
+			int migratetype)
 {
 	unsigned long flags;
 	struct page *page;
@@ -2350,13 +2423,13 @@
  * one free page of a suitable size. Checking now avoids taking the zone lock
  * to check in the allocation paths if no pages are free.
  */
-static bool __zone_watermark_ok(struct zone *z, unsigned int order,
-			unsigned long mark, int classzone_idx, int alloc_flags,
-			long free_pages)
+bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
+			 int classzone_idx, unsigned int alloc_flags,
+			 long free_pages)
 {
 	long min = mark;
 	int o;
-	const int alloc_harder = (alloc_flags & ALLOC_HARDER);
+	const bool alloc_harder = (alloc_flags & ALLOC_HARDER);
 
 	/* free_pages may go negative - that's OK */
 	free_pages -= (1 << order) - 1;
@@ -2400,9 +2473,6 @@
 		if (!area->nr_free)
 			continue;
 
-		if (alloc_harder)
-			return true;
-
 		for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) {
 			if (!list_empty(&area->free_list[mt]))
 				return true;
@@ -2414,12 +2484,15 @@
 			return true;
 		}
 #endif
+		if (alloc_harder &&
+			!list_empty(&area->free_list[MIGRATE_HIGHATOMIC]))
+			return true;
 	}
 	return false;
 }
 
 bool zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
-		      int classzone_idx, int alloc_flags)
+		      int classzone_idx, unsigned int alloc_flags)
 {
 	return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
 					zone_page_state(z, NR_FREE_PAGES));
@@ -2445,7 +2518,7 @@
 
 static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
 {
-	return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <
+	return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <=
 				RECLAIM_DISTANCE;
 }
 #else	/* CONFIG_NUMA */
@@ -2747,34 +2820,33 @@
 	return page;
 }
 
+
+/*
+ * Maximum number of compaction retries wit a progress before OOM
+ * killer is consider as the only way to move forward.
+ */
+#define MAX_COMPACT_RETRIES 16
+
 #ifdef CONFIG_COMPACTION
 /* Try memory compaction for high-order allocations before reclaim */
 static struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
-		int alloc_flags, const struct alloc_context *ac,
-		enum migrate_mode mode, int *contended_compaction,
-		bool *deferred_compaction)
+		unsigned int alloc_flags, const struct alloc_context *ac,
+		enum migrate_mode mode, enum compact_result *compact_result)
 {
-	unsigned long compact_result;
 	struct page *page;
+	int contended_compaction;
 
 	if (!order)
 		return NULL;
 
 	current->flags |= PF_MEMALLOC;
-	compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac,
-						mode, contended_compaction);
+	*compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac,
+						mode, &contended_compaction);
 	current->flags &= ~PF_MEMALLOC;
 
-	switch (compact_result) {
-	case COMPACT_DEFERRED:
-		*deferred_compaction = true;
-		/* fall-through */
-	case COMPACT_SKIPPED:
+	if (*compact_result <= COMPACT_INACTIVE)
 		return NULL;
-	default:
-		break;
-	}
 
 	/*
 	 * At least in one zone compaction wasn't deferred or skipped, so let's
@@ -2800,6 +2872,24 @@
 	 */
 	count_vm_event(COMPACTFAIL);
 
+	/*
+	 * In all zones where compaction was attempted (and not
+	 * deferred or skipped), lock contention has been detected.
+	 * For THP allocation we do not want to disrupt the others
+	 * so we fallback to base pages instead.
+	 */
+	if (contended_compaction == COMPACT_CONTENDED_LOCK)
+		*compact_result = COMPACT_CONTENDED;
+
+	/*
+	 * If compaction was aborted due to need_resched(), we do not
+	 * want to further increase allocation latency, unless it is
+	 * khugepaged trying to collapse.
+	 */
+	if (contended_compaction == COMPACT_CONTENDED_SCHED
+		&& !(current->flags & PF_KTHREAD))
+		*compact_result = COMPACT_CONTENDED;
+
 	cond_resched();
 
 	return NULL;
@@ -2807,14 +2897,42 @@
 #else
 static inline struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
-		int alloc_flags, const struct alloc_context *ac,
-		enum migrate_mode mode, int *contended_compaction,
-		bool *deferred_compaction)
+		unsigned int alloc_flags, const struct alloc_context *ac,
+		enum migrate_mode mode, enum compact_result *compact_result)
 {
+	*compact_result = COMPACT_SKIPPED;
 	return NULL;
 }
+
 #endif /* CONFIG_COMPACTION */
 
+static inline bool
+should_compact_retry(struct alloc_context *ac, unsigned int order, int alloc_flags,
+		     enum compact_result compact_result,
+		     enum migrate_mode *migrate_mode,
+		     int compaction_retries)
+{
+	struct zone *zone;
+	struct zoneref *z;
+
+	if (!order || order > PAGE_ALLOC_COSTLY_ORDER)
+		return false;
+
+	/*
+	 * There are setups with compaction disabled which would prefer to loop
+	 * inside the allocator rather than hit the oom killer prematurely.
+	 * Let's give them a good hope and keep retrying while the order-0
+	 * watermarks are OK.
+	 */
+	for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
+					ac->nodemask) {
+		if (zone_watermark_ok(zone, 0, min_wmark_pages(zone),
+					ac->classzone_idx, alloc_flags))
+			return true;
+	}
+	return false;
+}
+
 /* Perform direct synchronous page reclaim */
 static int
 __perform_reclaim(gfp_t gfp_mask, unsigned int order,
@@ -2847,7 +2965,7 @@
 /* The really slow allocator path where we enter direct reclaim */
 static inline struct page *
 __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,
-		int alloc_flags, const struct alloc_context *ac,
+		unsigned int alloc_flags, const struct alloc_context *ac,
 		unsigned long *did_some_progress)
 {
 	struct page *page = NULL;
@@ -2908,10 +3026,10 @@
 		wakeup_kswapd(zone, order, zone_idx(ac->preferred_zone));
 }
 
-static inline int
+static inline unsigned int
 gfp_to_alloc_flags(gfp_t gfp_mask)
 {
-	int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET;
+	unsigned int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET;
 
 	/* __GFP_HIGH is assumed to be the same as ALLOC_HIGH to save a branch. */
 	BUILD_BUG_ON(__GFP_HIGH != (__force gfp_t) ALLOC_HIGH);
@@ -2966,18 +3084,113 @@
 	return (gfp_mask & (GFP_TRANSHUGE | __GFP_KSWAPD_RECLAIM)) == GFP_TRANSHUGE;
 }
 
+/*
+ * Maximum number of reclaim retries without any progress before OOM killer
+ * is consider as the only way to move forward.
+ */
+#define MAX_RECLAIM_RETRIES 16
+
+/*
+ * Checks whether it makes sense to retry the reclaim to make a forward progress
+ * for the given allocation request.
+ * The reclaim feedback represented by did_some_progress (any progress during
+ * the last reclaim round) and no_progress_loops (number of reclaim rounds without
+ * any progress in a row) is considered as well as the reclaimable pages on the
+ * applicable zone list (with a backoff mechanism which is a function of
+ * no_progress_loops).
+ *
+ * Returns true if a retry is viable or false to enter the oom path.
+ */
+static inline bool
+should_reclaim_retry(gfp_t gfp_mask, unsigned order,
+		     struct alloc_context *ac, int alloc_flags,
+		     bool did_some_progress, int no_progress_loops)
+{
+	struct zone *zone;
+	struct zoneref *z;
+
+	/*
+	 * Make sure we converge to OOM if we cannot make any progress
+	 * several times in the row.
+	 */
+	if (no_progress_loops > MAX_RECLAIM_RETRIES)
+		return false;
+
+	/*
+	 * Keep reclaiming pages while there is a chance this will lead somewhere.
+	 * If none of the target zones can satisfy our allocation request even
+	 * if all reclaimable pages are considered then we are screwed and have
+	 * to go OOM.
+	 */
+	for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
+					ac->nodemask) {
+		unsigned long available;
+		unsigned long reclaimable;
+
+		available = reclaimable = zone_reclaimable_pages(zone);
+		available -= DIV_ROUND_UP(no_progress_loops * available,
+					  MAX_RECLAIM_RETRIES);
+		available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
+
+		/*
+		 * Would the allocation succeed if we reclaimed the whole
+		 * available?
+		 */
+		if (__zone_watermark_ok(zone, order, min_wmark_pages(zone),
+				ac->classzone_idx, alloc_flags, available)) {
+			/*
+			 * If we didn't make any progress and have a lot of
+			 * dirty + writeback pages then we should wait for
+			 * an IO to complete to slow down the reclaim and
+			 * prevent from pre mature OOM
+			 */
+			if (!did_some_progress) {
+				unsigned long writeback;
+				unsigned long dirty;
+
+				writeback = zone_page_state_snapshot(zone,
+								     NR_WRITEBACK);
+				dirty = zone_page_state_snapshot(zone, NR_FILE_DIRTY);
+
+				if (2*(writeback + dirty) > reclaimable) {
+					congestion_wait(BLK_RW_ASYNC, HZ/10);
+					return true;
+				}
+			}
+
+			/*
+			 * Memory allocation/reclaim might be called from a WQ
+			 * context and the current implementation of the WQ
+			 * concurrency control doesn't recognize that
+			 * a particular WQ is congested if the worker thread is
+			 * looping without ever sleeping. Therefore we have to
+			 * do a short sleep here rather than calling
+			 * cond_resched().
+			 */
+			if (current->flags & PF_WQ_WORKER)
+				schedule_timeout_uninterruptible(1);
+			else
+				cond_resched();
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
 static inline struct page *
 __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
 						struct alloc_context *ac)
 {
 	bool can_direct_reclaim = gfp_mask & __GFP_DIRECT_RECLAIM;
 	struct page *page = NULL;
-	int alloc_flags;
-	unsigned long pages_reclaimed = 0;
+	unsigned int alloc_flags;
 	unsigned long did_some_progress;
 	enum migrate_mode migration_mode = MIGRATE_ASYNC;
-	bool deferred_compaction = false;
-	int contended_compaction = COMPACT_CONTENDED_NONE;
+	enum compact_result compact_result;
+	int compaction_retries = 0;
+	int no_progress_loops = 0;
 
 	/*
 	 * In the slowpath, we sanity check order to avoid ever trying to
@@ -3041,8 +3254,6 @@
 		 * the allocation is high priority and these type of
 		 * allocations are system rather than user orientated
 		 */
-		ac->zonelist = node_zonelist(numa_node_id(), gfp_mask);
-
 		page = __alloc_pages_high_priority(gfp_mask, order, ac);
 
 		if (page) {
@@ -3075,8 +3286,7 @@
 	 */
 	page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,
 					migration_mode,
-					&contended_compaction,
-					&deferred_compaction);
+					&compact_result);
 	if (page)
 		goto got_pg;
 
@@ -3089,35 +3299,19 @@
 		 * to heavily disrupt the system, so we fail the allocation
 		 * instead of entering direct reclaim.
 		 */
-		if (deferred_compaction)
-			goto nopage;
-
-		/*
-		 * In all zones where compaction was attempted (and not
-		 * deferred or skipped), lock contention has been detected.
-		 * For THP allocation we do not want to disrupt the others
-		 * so we fallback to base pages instead.
-		 */
-		if (contended_compaction == COMPACT_CONTENDED_LOCK)
+		if (compact_result == COMPACT_DEFERRED)
 			goto nopage;
 
 		/*
-		 * If compaction was aborted due to need_resched(), we do not
-		 * want to further increase allocation latency, unless it is
-		 * khugepaged trying to collapse.
+		 * Compaction is contended so rather back off than cause
+		 * excessive stalls.
 		 */
-		if (contended_compaction == COMPACT_CONTENDED_SCHED
-			&& !(current->flags & PF_KTHREAD))
+		if(compact_result == COMPACT_CONTENDED)
 			goto nopage;
 	}
 
-	/*
-	 * It can become very expensive to allocate transparent hugepages at
-	 * fault, so use asynchronous memory compaction for THP unless it is
-	 * khugepaged trying to collapse.
-	 */
-	if (!is_thp_gfp_mask(gfp_mask) || (current->flags & PF_KTHREAD))
-		migration_mode = MIGRATE_SYNC_LIGHT;
+	if (order && compaction_made_progress(compact_result))
+		compaction_retries++;
 
 	/* Try direct reclaim and then allocating */
 	page = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac,
@@ -3129,14 +3323,38 @@
 	if (gfp_mask & __GFP_NORETRY)
 		goto noretry;
 
-	/* Keep reclaiming pages as long as there is reasonable progress */
-	pages_reclaimed += did_some_progress;
-	if ((did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER) ||
-	    ((gfp_mask & __GFP_REPEAT) && pages_reclaimed < (1 << order))) {
-		/* Wait for some write requests to complete then retry */
-		wait_iff_congested(ac->preferred_zone, BLK_RW_ASYNC, HZ/50);
+	/*
+	 * Do not retry costly high order allocations unless they are
+	 * __GFP_REPEAT
+	 */
+	if (order > PAGE_ALLOC_COSTLY_ORDER && !(gfp_mask & __GFP_REPEAT))
+		goto noretry;
+
+	/*
+	 * Costly allocations might have made a progress but this doesn't mean
+	 * their order will become available due to high fragmentation so
+	 * always increment the no progress counter for them
+	 */
+	if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER)
+		no_progress_loops = 0;
+	else
+		no_progress_loops++;
+
+	if (should_reclaim_retry(gfp_mask, order, ac, alloc_flags,
+				 did_some_progress > 0, no_progress_loops))
+		goto retry;
+
+	/*
+	 * It doesn't make any sense to retry for the compaction if the order-0
+	 * reclaim is not able to make any progress because the current
+	 * implementation of the compaction depends on the sufficient amount
+	 * of free memory (see __compaction_suitable)
+	 */
+	if (did_some_progress > 0 &&
+			should_compact_retry(ac, order, alloc_flags,
+				compact_result, &migration_mode,
+				compaction_retries))
 		goto retry;
-	}
 
 	/* Reclaim has failed us, start killing things */
 	page = __alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress);
@@ -3144,19 +3362,28 @@
 		goto got_pg;
 
 	/* Retry as long as the OOM killer is making progress */
-	if (did_some_progress)
+	if (did_some_progress) {
+		no_progress_loops = 0;
 		goto retry;
+	}
 
 noretry:
 	/*
-	 * High-order allocations do not necessarily loop after
-	 * direct reclaim and reclaim/compaction depends on compaction
-	 * being called after reclaim so call directly if necessary
+	 * High-order allocations do not necessarily loop after direct reclaim
+	 * and reclaim/compaction depends on compaction being called after
+	 * reclaim so call directly if necessary.
+	 * It can become very expensive to allocate transparent hugepages at
+	 * fault, so use asynchronous memory compaction for THP unless it is
+	 * khugepaged trying to collapse. All other requests should tolerate
+	 * at least light sync migration.
 	 */
+	if (is_thp_gfp_mask(gfp_mask) && !(current->flags & PF_KTHREAD))
+		migration_mode = MIGRATE_ASYNC;
+	else
+		migration_mode = MIGRATE_SYNC_LIGHT;
 	page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags,
 					    ac, migration_mode,
-					    &contended_compaction,
-					    &deferred_compaction);
+					    &compact_result);
 	if (page)
 		goto got_pg;
 nopage:
@@ -3175,7 +3402,7 @@
 	struct zoneref *preferred_zoneref;
 	struct page *page = NULL;
 	unsigned int cpuset_mems_cookie;
-	int alloc_flags = ALLOC_WMARK_LOW|ALLOC_CPUSET|ALLOC_FAIR;
+	unsigned int alloc_flags = ALLOC_WMARK_LOW|ALLOC_CPUSET|ALLOC_FAIR;
 	gfp_t alloc_mask; /* The gfp_t that was actually used for allocation */
 	struct alloc_context ac = {
 		.high_zoneidx = gfp_zone(gfp_mask),
@@ -3584,6 +3811,49 @@
 		printk("Node %d ", zone_to_nid(zone));
 }
 
+long si_mem_available(void)
+{
+	long available;
+	unsigned long pagecache;
+	unsigned long wmark_low = 0;
+	unsigned long pages[NR_LRU_LISTS];
+	struct zone *zone;
+	int lru;
+
+	for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
+		pages[lru] = global_page_state(NR_LRU_BASE + lru);
+
+	for_each_zone(zone)
+		wmark_low += zone->watermark[WMARK_LOW];
+
+	/*
+	 * Estimate the amount of memory available for userspace allocations,
+	 * without causing swapping.
+	 */
+	available = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
+
+	/*
+	 * Not all the page cache can be freed, otherwise the system will
+	 * start swapping. Assume at least half of the page cache, or the
+	 * low watermark worth of cache, needs to stay.
+	 */
+	pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE];
+	pagecache -= min(pagecache / 2, wmark_low);
+	available += pagecache;
+
+	/*
+	 * Part of the reclaimable slab consists of items that are in use,
+	 * and cannot be freed. Cap this estimate at the low watermark.
+	 */
+	available += global_page_state(NR_SLAB_RECLAIMABLE) -
+		     min(global_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low);
+
+	if (available < 0)
+		available = 0;
+	return available;
+}
+EXPORT_SYMBOL_GPL(si_mem_available);
+
 void si_meminfo(struct sysinfo *val)
 {
 	val->totalram = totalram_pages;
@@ -5321,7 +5591,6 @@
 	/* pg_data_t should be reset to zero when it's allocated */
 	WARN_ON(pgdat->nr_zones || pgdat->classzone_idx);
 
-	reset_deferred_meminit(pgdat);
 	pgdat->node_id = nid;
 	pgdat->node_start_pfn = node_start_pfn;
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
@@ -5340,6 +5609,7 @@
 		(unsigned long)pgdat->node_mem_map);
 #endif
 
+	reset_deferred_meminit(pgdat);
 	free_area_init_core(pgdat);
 }
 
@@ -5674,15 +5944,18 @@
 				sizeof(arch_zone_lowest_possible_pfn));
 	memset(arch_zone_highest_possible_pfn, 0,
 				sizeof(arch_zone_highest_possible_pfn));
-	arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions();
-	arch_zone_highest_possible_pfn[0] = max_zone_pfn[0];
-	for (i = 1; i < MAX_NR_ZONES; i++) {
+
+	start_pfn = find_min_pfn_with_active_regions();
+
+	for (i = 0; i < MAX_NR_ZONES; i++) {
 		if (i == ZONE_MOVABLE)
 			continue;
-		arch_zone_lowest_possible_pfn[i] =
-			arch_zone_highest_possible_pfn[i-1];
-		arch_zone_highest_possible_pfn[i] =
-			max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]);
+
+		end_pfn = max(max_zone_pfn[i], start_pfn);
+		arch_zone_lowest_possible_pfn[i] = start_pfn;
+		arch_zone_highest_possible_pfn[i] = end_pfn;
+
+		start_pfn = end_pfn;
 	}
 	arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0;
 	arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0;
@@ -5803,8 +6076,8 @@
 	}
 
 	if (pages && s)
-		pr_info("Freeing %s memory: %ldK (%p - %p)\n",
-			s, pages << (PAGE_SHIFT - 10), start, end);
+		pr_info("Freeing %s memory: %ldK\n",
+			s, pages << (PAGE_SHIFT - 10));
 
 	return pages;
 }
@@ -6173,7 +6446,7 @@
 	setup_per_zone_inactive_ratio();
 	return 0;
 }
-module_init(init_per_zone_wmark_min)
+postcore_initcall(init_per_zone_wmark_min)
 
 /*
  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
@@ -6322,6 +6595,7 @@
 	unsigned long long max = high_limit;
 	unsigned long log2qty, size;
 	void *table = NULL;
+	gfp_t gfp_flags;
 
 	/* allow the kernel cmdline to have a say */
 	if (!numentries) {
@@ -6365,12 +6639,17 @@
 
 	log2qty = ilog2(numentries);
 
+	/*
+	 * memblock allocator returns zeroed memory already, so HASH_ZERO is
+	 * currently not used when HASH_EARLY is specified.
+	 */
+	gfp_flags = (flags & HASH_ZERO) ? GFP_ATOMIC | __GFP_ZERO : GFP_ATOMIC;
 	do {
 		size = bucketsize << log2qty;
 		if (flags & HASH_EARLY)
 			table = memblock_virt_alloc_nopanic(size, 0);
 		else if (hashdist)
-			table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
+			table = __vmalloc(size, gfp_flags, PAGE_KERNEL);
 		else {
 			/*
 			 * If bucketsize is not a power-of-two, we may free
@@ -6378,8 +6657,8 @@
 			 * alloc_pages_exact() automatically does
 			 */
 			if (get_order(size) < MAX_ORDER) {
-				table = alloc_pages_exact(size, GFP_ATOMIC);
-				kmemleak_alloc(table, size, 1, GFP_ATOMIC);
+				table = alloc_pages_exact(size, gfp_flags);
+				kmemleak_alloc(table, size, 1, gfp_flags);
 			}
 		}
 	} while (!table && size > PAGE_SIZE && --log2qty);
@@ -6760,7 +7039,7 @@
 
 	/* Make sure the range is really isolated. */
 	if (test_pages_isolated(outer_start, end, false)) {
-		pr_info("%s: [%lx, %lx) PFNs busy\n",
+		pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
 			__func__, outer_start, end);
 		ret = -EBUSY;
 		goto done;
--- linux-4.4.0.orig/mm/page_ext.c
+++ linux-4.4.0/mm/page_ext.c
@@ -106,7 +106,6 @@
 	struct page_ext *base;
 
 	base = NODE_DATA(page_to_nid(page))->node_page_ext;
-#ifdef CONFIG_DEBUG_VM
 	/*
 	 * The sanity checks the page allocator does upon freeing a
 	 * page can reach here before the page_ext arrays are
@@ -115,7 +114,6 @@
 	 */
 	if (unlikely(!base))
 		return NULL;
-#endif
 	offset = pfn - round_down(node_start_pfn(page_to_nid(page)),
 					MAX_ORDER_NR_PAGES);
 	return base + offset;
@@ -180,7 +178,6 @@
 {
 	unsigned long pfn = page_to_pfn(page);
 	struct mem_section *section = __pfn_to_section(pfn);
-#ifdef CONFIG_DEBUG_VM
 	/*
 	 * The sanity checks the page allocator does upon freeing a
 	 * page can reach here before the page_ext arrays are
@@ -189,7 +186,6 @@
 	 */
 	if (!section->page_ext)
 		return NULL;
-#endif
 	return section->page_ext + pfn;
 }
 
@@ -259,6 +255,7 @@
 		table_size = sizeof(struct page_ext) * PAGES_PER_SECTION;
 
 		BUG_ON(PageReserved(page));
+		kmemleak_free(addr);
 		free_pages_exact(addr, table_size);
 	}
 }
--- linux-4.4.0.orig/mm/page_idle.c
+++ linux-4.4.0/mm/page_idle.c
@@ -130,7 +130,7 @@
 
 	end_pfn = pfn + count * BITS_PER_BYTE;
 	if (end_pfn > max_pfn)
-		end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS);
+		end_pfn = max_pfn;
 
 	for (; pfn < end_pfn; pfn++) {
 		bit = pfn % BITMAP_CHUNK_BITS;
@@ -175,7 +175,7 @@
 
 	end_pfn = pfn + count * BITS_PER_BYTE;
 	if (end_pfn > max_pfn)
-		end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS);
+		end_pfn = max_pfn;
 
 	for (; pfn < end_pfn; pfn++) {
 		bit = pfn % BITMAP_CHUNK_BITS;
--- linux-4.4.0.orig/mm/page_io.c
+++ linux-4.4.0/mm/page_io.c
@@ -32,7 +32,6 @@
 	bio = bio_alloc(gfp_flags, 1);
 	if (bio) {
 		bio->bi_iter.bi_sector = map_swap_page(page, &bio->bi_bdev);
-		bio->bi_iter.bi_sector <<= PAGE_SHIFT - 9;
 		bio->bi_end_io = end_io;
 
 		bio_add_page(bio, page, PAGE_SIZE, 0);
@@ -244,11 +243,6 @@
 	return ret;
 }
 
-static sector_t swap_page_sector(struct page *page)
-{
-	return (sector_t)__page_file_index(page) << (PAGE_CACHE_SHIFT - 9);
-}
-
 int __swap_writepage(struct page *page, struct writeback_control *wbc,
 		bio_end_io_t end_write_func)
 {
@@ -297,7 +291,8 @@
 		return ret;
 	}
 
-	ret = bdev_write_page(sis->bdev, swap_page_sector(page), page, wbc);
+	ret = bdev_write_page(sis->bdev, map_swap_page(page, &sis->bdev),
+			      page, wbc);
 	if (!ret) {
 		count_vm_event(PSWPOUT);
 		return 0;
@@ -345,7 +340,7 @@
 		return ret;
 	}
 
-	ret = bdev_read_page(sis->bdev, swap_page_sector(page), page);
+	ret = bdev_read_page(sis->bdev, map_swap_page(page, &sis->bdev), page);
 	if (!ret) {
 		count_vm_event(PSWPIN);
 		return 0;
--- linux-4.4.0.orig/mm/page_isolation.c
+++ linux-4.4.0/mm/page_isolation.c
@@ -283,11 +283,11 @@
 	 * now as a simple work-around, we use the next node for destination.
 	 */
 	if (PageHuge(page)) {
-		nodemask_t src = nodemask_of_node(page_to_nid(page));
-		nodemask_t dst;
-		nodes_complement(dst, src);
+		int node = next_online_node(page_to_nid(page));
+		if (node == MAX_NUMNODES)
+			node = first_online_node;
 		return alloc_huge_page_node(page_hstate(compound_head(page)),
-					    next_node(page_to_nid(page), dst));
+					    node);
 	}
 
 	if (PageHighMem(page))
--- linux-4.4.0.orig/mm/page_owner.c
+++ linux-4.4.0/mm/page_owner.c
@@ -53,6 +53,8 @@
 
 	for (i = 0; i < (1 << order); i++) {
 		page_ext = lookup_page_ext(page + i);
+		if (unlikely(!page_ext))
+			continue;
 		__clear_bit(PAGE_EXT_OWNER, &page_ext->flags);
 	}
 }
@@ -60,6 +62,7 @@
 void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask)
 {
 	struct page_ext *page_ext = lookup_page_ext(page);
+
 	struct stack_trace trace = {
 		.nr_entries = 0,
 		.max_entries = ARRAY_SIZE(page_ext->trace_entries),
@@ -67,6 +70,9 @@
 		.skip = 3,
 	};
 
+	if (unlikely(!page_ext))
+		return;
+
 	save_stack_trace(&trace);
 
 	page_ext->order = order;
@@ -79,6 +85,12 @@
 gfp_t __get_page_owner_gfp(struct page *page)
 {
 	struct page_ext *page_ext = lookup_page_ext(page);
+	if (unlikely(!page_ext))
+		/*
+		 * The caller just returns 0 if no valid gfp
+		 * So return 0 here too.
+		 */
+		return 0;
 
 	return page_ext->gfp_mask;
 }
@@ -194,6 +206,8 @@
 		}
 
 		page_ext = lookup_page_ext(page);
+		if (unlikely(!page_ext))
+			continue;
 
 		/*
 		 * Some pages could be missed by concurrent allocation or free,
@@ -257,6 +271,8 @@
 				continue;
 
 			page_ext = lookup_page_ext(page);
+			if (unlikely(!page_ext))
+				continue;
 
 			/* Maybe overraping zone */
 			if (test_bit(PAGE_EXT_OWNER, &page_ext->flags))
--- linux-4.4.0.orig/mm/pagewalk.c
+++ linux-4.4.0/mm/pagewalk.c
@@ -14,9 +14,9 @@
 		err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, walk);
 		if (err)
 		       break;
-		addr += PAGE_SIZE;
-		if (addr == end)
+		if (addr >= end - PAGE_SIZE)
 			break;
+		addr += PAGE_SIZE;
 		pte++;
 	}
 
@@ -142,8 +142,12 @@
 	do {
 		next = hugetlb_entry_end(h, addr, end);
 		pte = huge_pte_offset(walk->mm, addr & hmask);
-		if (pte && walk->hugetlb_entry)
+
+		if (pte)
 			err = walk->hugetlb_entry(pte, hmask, addr, next, walk);
+		else if (walk->pte_hole)
+			err = walk->pte_hole(addr, next, walk);
+
 		if (err)
 			break;
 	} while (addr = next, addr != end);
--- linux-4.4.0.orig/mm/percpu.c
+++ linux-4.4.0/mm/percpu.c
@@ -68,6 +68,7 @@
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
 #include <linux/kmemleak.h>
+#include <linux/sched.h>
 
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
@@ -110,7 +111,7 @@
 	int			map_used;	/* # of map entries used before the sentry */
 	int			map_alloc;	/* # of map entries allocated */
 	int			*map;		/* allocation map */
-	struct work_struct	map_extend_work;/* async ->map[] extension */
+	struct list_head	map_extend_list;/* on pcpu_map_extend_chunks */
 
 	void			*data;		/* chunk data */
 	int			first_free;	/* no free below this */
@@ -160,10 +161,13 @@
 static int pcpu_reserved_chunk_limit;
 
 static DEFINE_SPINLOCK(pcpu_lock);	/* all internal data structures */
-static DEFINE_MUTEX(pcpu_alloc_mutex);	/* chunk create/destroy, [de]pop */
+static DEFINE_MUTEX(pcpu_alloc_mutex);	/* chunk create/destroy, [de]pop, map ext */
 
 static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */
 
+/* chunks which need their map areas extended, protected by pcpu_lock */
+static LIST_HEAD(pcpu_map_extend_chunks);
+
 /*
  * The number of empty populated pages, protected by pcpu_lock.  The
  * reserved chunk doesn't contribute to the count.
@@ -397,13 +401,19 @@
 {
 	int margin, new_alloc;
 
+	lockdep_assert_held(&pcpu_lock);
+
 	if (is_atomic) {
 		margin = 3;
 
 		if (chunk->map_alloc <
-		    chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW &&
-		    pcpu_async_enabled)
-			schedule_work(&chunk->map_extend_work);
+		    chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW) {
+			if (list_empty(&chunk->map_extend_list)) {
+				list_add_tail(&chunk->map_extend_list,
+					      &pcpu_map_extend_chunks);
+				pcpu_schedule_balance_work();
+			}
+		}
 	} else {
 		margin = PCPU_ATOMIC_MAP_MARGIN_HIGH;
 	}
@@ -437,6 +447,8 @@
 	size_t old_size = 0, new_size = new_alloc * sizeof(new[0]);
 	unsigned long flags;
 
+	lockdep_assert_held(&pcpu_alloc_mutex);
+
 	new = pcpu_mem_zalloc(new_size);
 	if (!new)
 		return -ENOMEM;
@@ -469,20 +481,6 @@
 	return 0;
 }
 
-static void pcpu_map_extend_workfn(struct work_struct *work)
-{
-	struct pcpu_chunk *chunk = container_of(work, struct pcpu_chunk,
-						map_extend_work);
-	int new_alloc;
-
-	spin_lock_irq(&pcpu_lock);
-	new_alloc = pcpu_need_to_extend(chunk, false);
-	spin_unlock_irq(&pcpu_lock);
-
-	if (new_alloc)
-		pcpu_extend_area_map(chunk, new_alloc);
-}
-
 /**
  * pcpu_fit_in_area - try to fit the requested allocation in a candidate area
  * @chunk: chunk the candidate area belongs to
@@ -742,7 +740,7 @@
 	chunk->map_used = 1;
 
 	INIT_LIST_HEAD(&chunk->list);
-	INIT_WORK(&chunk->map_extend_work, pcpu_map_extend_workfn);
+	INIT_LIST_HEAD(&chunk->map_extend_list);
 	chunk->free_size = pcpu_unit_size;
 	chunk->contig_hint = pcpu_unit_size;
 
@@ -897,6 +895,9 @@
 		return NULL;
 	}
 
+	if (!is_atomic)
+		mutex_lock(&pcpu_alloc_mutex);
+
 	spin_lock_irqsave(&pcpu_lock, flags);
 
 	/* serve reserved allocations from the reserved chunk if available */
@@ -969,12 +970,9 @@
 	if (is_atomic)
 		goto fail;
 
-	mutex_lock(&pcpu_alloc_mutex);
-
 	if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) {
 		chunk = pcpu_create_chunk();
 		if (!chunk) {
-			mutex_unlock(&pcpu_alloc_mutex);
 			err = "failed to allocate new chunk";
 			goto fail;
 		}
@@ -985,7 +983,6 @@
 		spin_lock_irqsave(&pcpu_lock, flags);
 	}
 
-	mutex_unlock(&pcpu_alloc_mutex);
 	goto restart;
 
 area_found:
@@ -995,8 +992,6 @@
 	if (!is_atomic) {
 		int page_start, page_end, rs, re;
 
-		mutex_lock(&pcpu_alloc_mutex);
-
 		page_start = PFN_DOWN(off);
 		page_end = PFN_UP(off + size);
 
@@ -1007,7 +1002,6 @@
 
 			spin_lock_irqsave(&pcpu_lock, flags);
 			if (ret) {
-				mutex_unlock(&pcpu_alloc_mutex);
 				pcpu_free_area(chunk, off, &occ_pages);
 				err = "failed to populate";
 				goto fail_unlock;
@@ -1019,8 +1013,11 @@
 		mutex_unlock(&pcpu_alloc_mutex);
 	}
 
-	if (chunk != pcpu_reserved_chunk)
+	if (chunk != pcpu_reserved_chunk) {
+		spin_lock_irqsave(&pcpu_lock, flags);
 		pcpu_nr_empty_pop_pages -= occ_pages;
+		spin_unlock_irqrestore(&pcpu_lock, flags);
+	}
 
 	if (pcpu_nr_empty_pop_pages < PCPU_EMPTY_POP_PAGES_LOW)
 		pcpu_schedule_balance_work();
@@ -1047,6 +1044,8 @@
 		/* see the flag handling in pcpu_blance_workfn() */
 		pcpu_atomic_alloc_failed = true;
 		pcpu_schedule_balance_work();
+	} else {
+		mutex_unlock(&pcpu_alloc_mutex);
 	}
 	return NULL;
 }
@@ -1131,6 +1130,7 @@
 		if (chunk == list_first_entry(free_head, struct pcpu_chunk, list))
 			continue;
 
+		list_del_init(&chunk->map_extend_list);
 		list_move(&chunk->list, &to_free);
 	}
 
@@ -1148,6 +1148,25 @@
 		pcpu_destroy_chunk(chunk);
 	}
 
+	/* service chunks which requested async area map extension */
+	do {
+		int new_alloc = 0;
+
+		spin_lock_irq(&pcpu_lock);
+
+		chunk = list_first_entry_or_null(&pcpu_map_extend_chunks,
+					struct pcpu_chunk, map_extend_list);
+		if (chunk) {
+			list_del_init(&chunk->map_extend_list);
+			new_alloc = pcpu_need_to_extend(chunk, false);
+		}
+
+		spin_unlock_irq(&pcpu_lock);
+
+		if (new_alloc)
+			pcpu_extend_area_map(chunk, new_alloc);
+	} while (chunk);
+
 	/*
 	 * Ensure there are certain number of free populated pages for
 	 * atomic allocs.  Fill up from the most packed so that atomic
@@ -1646,7 +1665,7 @@
 	 */
 	schunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0);
 	INIT_LIST_HEAD(&schunk->list);
-	INIT_WORK(&schunk->map_extend_work, pcpu_map_extend_workfn);
+	INIT_LIST_HEAD(&schunk->map_extend_list);
 	schunk->base_addr = base_addr;
 	schunk->map = smap;
 	schunk->map_alloc = ARRAY_SIZE(smap);
@@ -1675,7 +1694,7 @@
 	if (dyn_size) {
 		dchunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0);
 		INIT_LIST_HEAD(&dchunk->list);
-		INIT_WORK(&dchunk->map_extend_work, pcpu_map_extend_workfn);
+		INIT_LIST_HEAD(&dchunk->map_extend_list);
 		dchunk->base_addr = base_addr;
 		dchunk->map = dmap;
 		dchunk->map_alloc = ARRAY_SIZE(dmap);
@@ -2030,8 +2049,8 @@
 #endif
 	}
 
-	pr_info("PERCPU: Embedded %zu pages/cpu @%p s%zu r%zu d%zu u%zu\n",
-		PFN_DOWN(size_sum), base, ai->static_size, ai->reserved_size,
+	pr_info("PERCPU: Embedded %zu pages/cpu s%zu r%zu d%zu u%zu\n",
+		PFN_DOWN(size_sum), ai->static_size, ai->reserved_size,
 		ai->dyn_size, ai->unit_size);
 
 	rc = pcpu_setup_first_chunk(ai, base);
@@ -2144,8 +2163,8 @@
 	}
 
 	/* we're ready, commit */
-	pr_info("PERCPU: %d %s pages/cpu @%p s%zu r%zu d%zu\n",
-		unit_pages, psize_str, vm.addr, ai->static_size,
+	pr_info("PERCPU: %d %s pages/cpu s%zu r%zu d%zu\n",
+		unit_pages, psize_str, ai->static_size,
 		ai->reserved_size, ai->dyn_size);
 
 	rc = pcpu_setup_first_chunk(ai, vm.addr);
--- linux-4.4.0.orig/mm/pgtable-generic.c
+++ linux-4.4.0/mm/pgtable-generic.c
@@ -210,7 +210,9 @@
 	VM_BUG_ON(address & ~HPAGE_PMD_MASK);
 	VM_BUG_ON(pmd_trans_huge(*pmdp));
 	pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
-	flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
+
+	/* collapse entails shooting down ptes not pmd */
+	flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
 	return pmd;
 }
 #endif
--- linux-4.4.0.orig/mm/prfile.c
+++ linux-4.4.0/mm/prfile.c
@@ -0,0 +1,86 @@
+/*
+ * Mainly for aufs which mmap(2) diffrent file and wants to print different path
+ * in /proc/PID/maps.
+ * Call these functions via macros defined in linux/mm.h.
+ *
+ * See Documentation/filesystems/aufs/design/06mmap.txt
+ *
+ * Copyright (c) 2014 Junjro R. Okajima
+ * Copyright (c) 2014 Ian Campbell
+ */
+
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+
+/* #define PRFILE_TRACE */
+static inline void prfile_trace(struct file *f, struct file *pr,
+			      const char func[], int line, const char func2[])
+{
+#ifdef PRFILE_TRACE
+	if (pr)
+		pr_info("%s:%d: %s, %s\n", func, line, func2,
+			f ? (char *)f->f_path.dentry->d_name.name : "(null)");
+#endif
+}
+
+void vma_do_file_update_time(struct vm_area_struct *vma, const char func[],
+			     int line)
+{
+	struct file *f = vma->vm_file, *pr = vma->vm_prfile;
+
+	prfile_trace(f, pr, func, line, __func__);
+	file_update_time(f);
+	if (f && pr)
+		file_update_time(pr);
+}
+
+struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[],
+			       int line)
+{
+	struct file *f = vma->vm_file, *pr = vma->vm_prfile;
+
+	prfile_trace(f, pr, func, line, __func__);
+	return (f && pr) ? pr : f;
+}
+
+void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line)
+{
+	struct file *f = vma->vm_file, *pr = vma->vm_prfile;
+
+	prfile_trace(f, pr, func, line, __func__);
+	get_file(f);
+	if (f && pr)
+		get_file(pr);
+}
+
+void vma_do_fput(struct vm_area_struct *vma, const char func[], int line)
+{
+	struct file *f = vma->vm_file, *pr = vma->vm_prfile;
+
+	prfile_trace(f, pr, func, line, __func__);
+	fput(f);
+	if (f && pr)
+		fput(pr);
+}
+
+#ifndef CONFIG_MMU
+struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[],
+			       int line)
+{
+	struct file *f = region->vm_file, *pr = region->vm_prfile;
+
+	prfile_trace(f, pr, func, line, __func__);
+	return (f && pr) ? pr : f;
+}
+
+void vmr_do_fput(struct vm_region *region, const char func[], int line)
+{
+	struct file *f = region->vm_file, *pr = region->vm_prfile;
+
+	prfile_trace(f, pr, func, line, __func__);
+	fput(f);
+	if (f && pr)
+		fput(pr);
+}
+#endif /* !CONFIG_MMU */
--- linux-4.4.0.orig/mm/process_vm_access.c
+++ linux-4.4.0/mm/process_vm_access.c
@@ -88,19 +88,23 @@
 	ssize_t rc = 0;
 	unsigned long max_pages_per_loop = PVM_MAX_KMALLOC_PAGES
 		/ sizeof(struct pages *);
+	unsigned int flags = 0;
 
 	/* Work out address and page range required */
 	if (len == 0)
 		return 0;
 	nr_pages = (addr + len - 1) / PAGE_SIZE - addr / PAGE_SIZE + 1;
 
+	if (vm_write)
+		flags |= FOLL_WRITE;
+
 	while (!rc && nr_pages && iov_iter_count(iter)) {
 		int pages = min(nr_pages, max_pages_per_loop);
 		size_t bytes;
 
 		/* Get the pages we're interested in */
 		pages = get_user_pages_unlocked(task, mm, pa, pages,
-						vm_write, 0, process_pages);
+						process_pages, flags);
 		if (pages <= 0)
 			return -EFAULT;
 
@@ -194,7 +198,7 @@
 		goto free_proc_pages;
 	}
 
-	mm = mm_access(task, PTRACE_MODE_ATTACH);
+	mm = mm_access(task, PTRACE_MODE_ATTACH_REALCREDS);
 	if (!mm || IS_ERR(mm)) {
 		rc = IS_ERR(mm) ? PTR_ERR(mm) : -ESRCH;
 		/*
--- linux-4.4.0.orig/mm/rmap.c
+++ linux-4.4.0/mm/rmap.c
@@ -77,7 +77,8 @@
 	anon_vma = kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL);
 	if (anon_vma) {
 		atomic_set(&anon_vma->refcount, 1);
-		anon_vma->degree = 1;	/* Reference for first vma */
+		anon_vma->num_children = 0;
+		anon_vma->num_active_vmas = 0;
 		anon_vma->parent = anon_vma;
 		/*
 		 * Initialise the anon_vma root to point to itself. If called
@@ -140,14 +141,15 @@
 }
 
 /**
- * anon_vma_prepare - attach an anon_vma to a memory region
+ * __anon_vma_prepare - attach an anon_vma to a memory region
  * @vma: the memory region in question
  *
  * This makes sure the memory mapping described by 'vma' has
  * an 'anon_vma' attached to it, so that we can associate the
  * anonymous pages mapped into it with that anon_vma.
  *
- * The common case will be that we already have one, but if
+ * The common case will be that we already have one, which
+ * is handled inline by anon_vma_prepare(). But if
  * not we either need to find an adjacent mapping that we
  * can re-use the anon_vma from (very common when the only
  * reason for splitting a vma has been mprotect()), or we
@@ -166,48 +168,46 @@
  *
  * This must be called with the mmap_sem held for reading.
  */
-int anon_vma_prepare(struct vm_area_struct *vma)
+int __anon_vma_prepare(struct vm_area_struct *vma)
 {
-	struct anon_vma *anon_vma = vma->anon_vma;
+	struct mm_struct *mm = vma->vm_mm;
+	struct anon_vma *anon_vma, *allocated;
 	struct anon_vma_chain *avc;
 
 	might_sleep();
-	if (unlikely(!anon_vma)) {
-		struct mm_struct *mm = vma->vm_mm;
-		struct anon_vma *allocated;
-
-		avc = anon_vma_chain_alloc(GFP_KERNEL);
-		if (!avc)
-			goto out_enomem;
 
-		anon_vma = find_mergeable_anon_vma(vma);
-		allocated = NULL;
-		if (!anon_vma) {
-			anon_vma = anon_vma_alloc();
-			if (unlikely(!anon_vma))
-				goto out_enomem_free_avc;
-			allocated = anon_vma;
-		}
+	avc = anon_vma_chain_alloc(GFP_KERNEL);
+	if (!avc)
+		goto out_enomem;
 
-		anon_vma_lock_write(anon_vma);
-		/* page_table_lock to protect against threads */
-		spin_lock(&mm->page_table_lock);
-		if (likely(!vma->anon_vma)) {
-			vma->anon_vma = anon_vma;
-			anon_vma_chain_link(vma, avc, anon_vma);
-			/* vma reference or self-parent link for new root */
-			anon_vma->degree++;
-			allocated = NULL;
-			avc = NULL;
-		}
-		spin_unlock(&mm->page_table_lock);
-		anon_vma_unlock_write(anon_vma);
+	anon_vma = find_mergeable_anon_vma(vma);
+	allocated = NULL;
+	if (!anon_vma) {
+		anon_vma = anon_vma_alloc();
+		if (unlikely(!anon_vma))
+			goto out_enomem_free_avc;
+		anon_vma->num_children++; /* self-parent link for new root */
+		allocated = anon_vma;
+	}
 
-		if (unlikely(allocated))
-			put_anon_vma(allocated);
-		if (unlikely(avc))
-			anon_vma_chain_free(avc);
+	anon_vma_lock_write(anon_vma);
+	/* page_table_lock to protect against threads */
+	spin_lock(&mm->page_table_lock);
+	if (likely(!vma->anon_vma)) {
+		vma->anon_vma = anon_vma;
+		anon_vma_chain_link(vma, avc, anon_vma);
+		anon_vma->num_active_vmas++;
+		allocated = NULL;
+		avc = NULL;
 	}
+	spin_unlock(&mm->page_table_lock);
+	anon_vma_unlock_write(anon_vma);
+
+	if (unlikely(allocated))
+		put_anon_vma(allocated);
+	if (unlikely(avc))
+		anon_vma_chain_free(avc);
+
 	return 0;
 
  out_enomem_free_avc:
@@ -246,13 +246,19 @@
  * Attach the anon_vmas from src to dst.
  * Returns 0 on success, -ENOMEM on failure.
  *
- * If dst->anon_vma is NULL this function tries to find and reuse existing
- * anon_vma which has no vmas and only one child anon_vma. This prevents
- * degradation of anon_vma hierarchy to endless linear chain in case of
- * constantly forking task. On the other hand, an anon_vma with more than one
- * child isn't reused even if there was no alive vma, thus rmap walker has a
- * good chance of avoiding scanning the whole hierarchy when it searches where
- * page is mapped.
+ * anon_vma_clone() is called by __vma_split(), __split_vma(), copy_vma() and
+ * anon_vma_fork(). The first three want an exact copy of src, while the last
+ * one, anon_vma_fork(), may try to reuse an existing anon_vma to prevent
+ * endless growth of anon_vma. Since dst->anon_vma is set to NULL before call,
+ * we can identify this case by checking (!dst->anon_vma && src->anon_vma).
+ *
+ * If (!dst->anon_vma && src->anon_vma) is true, this function tries to find
+ * and reuse existing anon_vma which has no vmas and only one child anon_vma.
+ * This prevents degradation of anon_vma hierarchy to endless linear chain in
+ * case of constantly forking task. On the other hand, an anon_vma with more
+ * than one child isn't reused even if there was no alive vma, thus rmap
+ * walker has a good chance of avoiding scanning the whole hierarchy when it
+ * searches where page is mapped.
  */
 int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
 {
@@ -275,19 +281,19 @@
 		anon_vma_chain_link(dst, avc, anon_vma);
 
 		/*
-		 * Reuse existing anon_vma if its degree lower than two,
-		 * that means it has no vma and only one anon_vma child.
+		 * Reuse existing anon_vma if it has no vma and only one
+		 * anon_vma child.
 		 *
-		 * Do not chose parent anon_vma, otherwise first child
-		 * will always reuse it. Root anon_vma is never reused:
+		 * Root anon_vma is never reused:
 		 * it has self-parent reference and at least one child.
 		 */
-		if (!dst->anon_vma && anon_vma != src->anon_vma &&
-				anon_vma->degree < 2)
+		if (!dst->anon_vma && src->anon_vma &&
+		    anon_vma->num_children < 2 &&
+		    anon_vma->num_active_vmas == 0)
 			dst->anon_vma = anon_vma;
 	}
 	if (dst->anon_vma)
-		dst->anon_vma->degree++;
+		dst->anon_vma->num_active_vmas++;
 	unlock_anon_vma_root(root);
 	return 0;
 
@@ -337,6 +343,7 @@
 	anon_vma = anon_vma_alloc();
 	if (!anon_vma)
 		goto out_error;
+	anon_vma->num_active_vmas++;
 	avc = anon_vma_chain_alloc(GFP_KERNEL);
 	if (!avc)
 		goto out_error_free_anon_vma;
@@ -357,7 +364,7 @@
 	vma->anon_vma = anon_vma;
 	anon_vma_lock_write(anon_vma);
 	anon_vma_chain_link(vma, avc, anon_vma);
-	anon_vma->parent->degree++;
+	anon_vma->parent->num_children++;
 	anon_vma_unlock_write(anon_vma);
 
 	return 0;
@@ -389,15 +396,22 @@
 		 * to free them outside the lock.
 		 */
 		if (RB_EMPTY_ROOT(&anon_vma->rb_root)) {
-			anon_vma->parent->degree--;
+			anon_vma->parent->num_children--;
 			continue;
 		}
 
 		list_del(&avc->same_vma);
 		anon_vma_chain_free(avc);
 	}
-	if (vma->anon_vma)
-		vma->anon_vma->degree--;
+	if (vma->anon_vma) {
+		vma->anon_vma->num_active_vmas--;
+
+		/*
+		 * vma would still be needed after unlink, and anon_vma will be prepared
+		 * when handle fault.
+		 */
+		vma->anon_vma = NULL;
+	}
 	unlock_anon_vma_root(root);
 
 	/*
@@ -408,7 +422,8 @@
 	list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
 		struct anon_vma *anon_vma = avc->anon_vma;
 
-		BUG_ON(anon_vma->degree);
+		VM_WARN_ON(anon_vma->num_children);
+		VM_WARN_ON(anon_vma->num_active_vmas);
 		put_anon_vma(anon_vma);
 
 		list_del(&avc->same_vma);
@@ -587,19 +602,6 @@
 }
 
 #ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
-static void percpu_flush_tlb_batch_pages(void *data)
-{
-	/*
-	 * All TLB entries are flushed on the assumption that it is
-	 * cheaper to flush all TLBs and let them be refilled than
-	 * flushing individual PFNs. Note that we do not track mm's
-	 * to flush as that might simply be multiple full TLB flushes
-	 * for no gain.
-	 */
-	count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
-	flush_tlb_local();
-}
-
 /*
  * Flush TLB entries for recently unmapped pages from remote CPUs. It is
  * important if a PTE was dirty when it was unmapped that it's flushed
@@ -616,15 +618,14 @@
 
 	cpu = get_cpu();
 
-	trace_tlb_flush(TLB_REMOTE_SHOOTDOWN, -1UL);
-
-	if (cpumask_test_cpu(cpu, &tlb_ubc->cpumask))
-		percpu_flush_tlb_batch_pages(&tlb_ubc->cpumask);
-
-	if (cpumask_any_but(&tlb_ubc->cpumask, cpu) < nr_cpu_ids) {
-		smp_call_function_many(&tlb_ubc->cpumask,
-			percpu_flush_tlb_batch_pages, (void *)tlb_ubc, true);
+	if (cpumask_test_cpu(cpu, &tlb_ubc->cpumask)) {
+		count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
+		local_flush_tlb();
+		trace_tlb_flush(TLB_LOCAL_SHOOTDOWN, TLB_FLUSH_ALL);
 	}
+
+	if (cpumask_any_but(&tlb_ubc->cpumask, cpu) < nr_cpu_ids)
+		flush_tlb_others(&tlb_ubc->cpumask, NULL, 0, TLB_FLUSH_ALL);
 	cpumask_clear(&tlb_ubc->cpumask);
 	tlb_ubc->flush_required = false;
 	tlb_ubc->writable = false;
@@ -649,6 +650,13 @@
 	tlb_ubc->flush_required = true;
 
 	/*
+	 * Ensure compiler does not re-order the setting of tlb_flush_batched
+	 * before the PTE is cleared.
+	 */
+	barrier();
+	mm->tlb_flush_batched = true;
+
+	/*
 	 * If the PTE was dirty then it's best to assume it's writable. The
 	 * caller must use try_to_unmap_flush_dirty() or try_to_unmap_flush()
 	 * before the page is queued for IO.
@@ -675,6 +683,35 @@
 
 	return should_defer;
 }
+
+/*
+ * Reclaim unmaps pages under the PTL but do not flush the TLB prior to
+ * releasing the PTL if TLB flushes are batched. It's possible for a parallel
+ * operation such as mprotect or munmap to race between reclaim unmapping
+ * the page and flushing the page. If this race occurs, it potentially allows
+ * access to data via a stale TLB entry. Tracking all mm's that have TLB
+ * batching in flight would be expensive during reclaim so instead track
+ * whether TLB batching occurred in the past and if so then do a flush here
+ * if required. This will cost one additional flush per reclaim cycle paid
+ * by the first operation at risk such as mprotect and mumap.
+ *
+ * This must be called under the PTL so that an access to tlb_flush_batched
+ * that is potentially a "reclaim vs mprotect/munmap/etc" race will synchronise
+ * via the PTL.
+ */
+void flush_tlb_batched_pending(struct mm_struct *mm)
+{
+	if (mm->tlb_flush_batched) {
+		flush_tlb_mm(mm);
+
+		/*
+		 * Do not allow the compiler to re-order the clearing of
+		 * tlb_flush_batched before the tlb is flushed.
+		 */
+		barrier();
+		mm->tlb_flush_batched = false;
+	}
+}
 #else
 static void set_tlb_ubc_flush_pending(struct mm_struct *mm,
 		struct page *page, bool writable)
@@ -1302,12 +1339,41 @@
 	pte_t pteval;
 	spinlock_t *ptl;
 	int ret = SWAP_AGAIN;
+	unsigned long sh_address;
+	bool pmd_sharing_possible = false;
+	unsigned long spmd_start, spmd_end;
 	enum ttu_flags flags = (enum ttu_flags)arg;
 
 	/* munlock has nothing to gain from examining un-locked vmas */
 	if ((flags & TTU_MUNLOCK) && !(vma->vm_flags & VM_LOCKED))
 		goto out;
 
+	/*
+	 * Only use the range_start/end mmu notifiers if huge pmd sharing
+	 * is possible.  In the normal case, mmu_notifier_invalidate_page
+	 * is sufficient as we only unmap a page.  However, if we unshare
+	 * a pmd, we will unmap a PUD_SIZE range.
+	 */
+	if (PageHuge(page)) {
+		spmd_start = address;
+		spmd_end = spmd_start + vma_mmu_pagesize(vma);
+
+		/*
+		 * Check if pmd sharing is possible.  If possible, we could
+		 * unmap a PUD_SIZE range.  spmd_start/spmd_end will be
+		 * modified if sharing is possible.
+		 */
+		adjust_range_if_pmd_sharing_possible(vma, &spmd_start,
+								&spmd_end);
+		if (spmd_end - spmd_start != vma_mmu_pagesize(vma)) {
+			sh_address = address;
+
+			pmd_sharing_possible = true;
+			mmu_notifier_invalidate_range_start(vma->vm_mm,
+							spmd_start, spmd_end);
+		}
+	}
+
 	pte = page_check_address(page, mm, address, &ptl, 0);
 	if (!pte)
 		goto out;
@@ -1334,6 +1400,30 @@
 		}
   	}
 
+	/*
+	 * Call huge_pmd_unshare to potentially unshare a huge pmd.  Pass
+	 * sh_address as it will be modified if unsharing is successful.
+	 */
+	if (PageHuge(page) && huge_pmd_unshare(mm, &sh_address, pte)) {
+		/*
+		 * huge_pmd_unshare unmapped an entire PMD page.  There is
+		 * no way of knowing exactly which PMDs may be cached for
+		 * this mm, so flush them all.  spmd_start/spmd_end cover
+		 * this PUD_SIZE range.
+		 */
+		flush_cache_range(vma, spmd_start, spmd_end);
+		flush_tlb_range(vma, spmd_start, spmd_end);
+
+		/*
+		 * The ref count of the PMD page was dropped which is part
+		 * of the way map counting is done for shared PMDs.  When
+		 * there is no other sharing, huge_pmd_unshare returns false
+		 * and we will unmap the actual page and drop map count
+		 * to zero.
+		 */
+		goto out_unmap;
+	}
+
 	/* Nuke the page table entry. */
 	flush_cache_page(vma, address, page_to_pfn(page));
 	if (should_defer_flush(mm, flags)) {
@@ -1428,6 +1518,9 @@
 	if (ret != SWAP_FAIL && ret != SWAP_MLOCK && !(flags & TTU_MUNLOCK))
 		mmu_notifier_invalidate_page(mm, address);
 out:
+	if (pmd_sharing_possible)
+		mmu_notifier_invalidate_range_end(vma->vm_mm,
+							spmd_start, spmd_end);
 	return ret;
 }
 
--- linux-4.4.0.orig/mm/shmem.c
+++ linux-4.4.0/mm/shmem.c
@@ -112,9 +112,13 @@
 	return totalram_pages / 2;
 }
 
-static unsigned long shmem_default_max_inodes(void)
+static int shmem_default_max_inodes(void)
 {
-	return min(totalram_pages - totalhigh_pages, totalram_pages / 2);
+	unsigned long ul;
+
+	ul = INT_MAX;
+	ul = min3(ul, totalram_pages - totalhigh_pages, totalram_pages / 2);
+	return ul;
 }
 #endif
 
@@ -565,7 +569,7 @@
 	struct shmem_inode_info *info = SHMEM_I(inode);
 	int error;
 
-	error = inode_change_ok(inode, attr);
+	error = setattr_prepare(dentry, attr);
 	if (error)
 		return error;
 
@@ -610,6 +614,7 @@
 static void shmem_evict_inode(struct inode *inode)
 {
 	struct shmem_inode_info *info = SHMEM_I(inode);
+	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
 
 	if (inode->i_mapping->a_ops == &shmem_aops) {
 		shmem_unacct_size(info->flags, inode->i_size);
@@ -620,11 +625,15 @@
 			list_del_init(&info->swaplist);
 			mutex_unlock(&shmem_swaplist_mutex);
 		}
-	} else
-		kfree(info->symlink);
+	}
 
 	simple_xattrs_free(&info->xattrs);
 	WARN_ON(inode->i_blocks);
+	if (!sbinfo->idr_nouse && inode->i_ino) {
+		mutex_lock(&sbinfo->idr_lock);
+		idr_remove(&sbinfo->idr, inode->i_ino);
+		mutex_unlock(&sbinfo->idr_lock);
+	}
 	shmem_free_inode(inode->i_sb);
 	clear_inode(inode);
 }
@@ -1418,13 +1427,13 @@
 	struct inode *inode;
 	struct shmem_inode_info *info;
 	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+	int ino;
 
 	if (shmem_reserve_inode(sb))
 		return NULL;
 
 	inode = new_inode(sb);
 	if (inode) {
-		inode->i_ino = get_next_ino();
 		inode_init_owner(inode, dir, mode);
 		inode->i_blocks = 0;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -1465,6 +1474,27 @@
 			mpol_shared_policy_init(&info->policy, NULL);
 			break;
 		}
+
+		if (!sbinfo->idr_nouse) {
+			/* inum 0 and 1 are unused */
+			mutex_lock(&sbinfo->idr_lock);
+			ino = idr_alloc(&sbinfo->idr, inode, 2, INT_MAX,
+					GFP_NOFS);
+			if (ino > 0) {
+				inode->i_ino = ino;
+				mutex_unlock(&sbinfo->idr_lock);
+				__insert_inode_hash(inode, inode->i_ino);
+			} else {
+				inode->i_ino = 0;
+				mutex_unlock(&sbinfo->idr_lock);
+				iput(inode);
+				/* shmem_free_inode() will be called */
+				inode = NULL;
+			}
+		} else
+			inode->i_ino = get_next_ino();
+
+		lockdep_annotate_inode_mutex_key(inode);
 	} else
 		shmem_free_inode(sb);
 	return inode;
@@ -1817,9 +1847,7 @@
 	mutex_lock(&inode->i_mutex);
 	/* We're holding i_mutex so we can access i_size directly */
 
-	if (offset < 0)
-		offset = -EINVAL;
-	else if (offset >= inode->i_size)
+	if (offset < 0 || offset >= inode->i_size)
 		offset = -ENXIO;
 	else {
 		start = offset >> PAGE_CACHE_SHIFT;
@@ -1855,31 +1883,33 @@
 	void **slot;
 	pgoff_t start;
 	struct page *page;
+	unsigned int tagged = 0;
 
 	lru_add_drain();
 	start = 0;
-	rcu_read_lock();
 
+	spin_lock_irq(&mapping->tree_lock);
 restart:
 	radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
-		page = radix_tree_deref_slot(slot);
+		page = radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
 		if (!page || radix_tree_exception(page)) {
 			if (radix_tree_deref_retry(page))
 				goto restart;
 		} else if (page_count(page) - page_mapcount(page) > 1) {
-			spin_lock_irq(&mapping->tree_lock);
 			radix_tree_tag_set(&mapping->page_tree, iter.index,
 					   SHMEM_TAG_PINNED);
-			spin_unlock_irq(&mapping->tree_lock);
 		}
 
-		if (need_resched()) {
-			cond_resched_rcu();
-			start = iter.index + 1;
-			goto restart;
-		}
+		if (++tagged % 1024)
+			continue;
+
+		spin_unlock_irq(&mapping->tree_lock);
+		cond_resched();
+		start = iter.index + 1;
+		spin_lock_irq(&mapping->tree_lock);
+		goto restart;
 	}
-	rcu_read_unlock();
+	spin_unlock_irq(&mapping->tree_lock);
 }
 
 /*
@@ -2091,7 +2121,7 @@
 		}
 
 		shmem_falloc.waitq = &shmem_falloc_waitq;
-		shmem_falloc.start = unmap_start >> PAGE_SHIFT;
+		shmem_falloc.start = (u64)unmap_start >> PAGE_SHIFT;
 		shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT;
 		spin_lock(&inode->i_lock);
 		inode->i_private = &shmem_falloc;
@@ -2154,9 +2184,11 @@
 									NULL);
 		if (error) {
 			/* Remove the !PageUptodate pages we added */
-			shmem_undo_range(inode,
-				(loff_t)start << PAGE_CACHE_SHIFT,
-				(loff_t)index << PAGE_CACHE_SHIFT, true);
+			if (index > start) {
+				shmem_undo_range(inode,
+				 (loff_t)start << PAGE_CACHE_SHIFT,
+				 ((loff_t)index << PAGE_CACHE_SHIFT) - 1, true);
+			}
 			goto undone;
 		}
 
@@ -2292,16 +2324,20 @@
 static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = d_inode(old_dentry);
-	int ret;
+	int ret = 0;
 
 	/*
 	 * No ordinary (disk based) filesystem counts links as inodes;
 	 * but each new link needs a new dentry, pinning lowmem, and
 	 * tmpfs dentries cannot be pruned until they are unlinked.
+	 * But if an O_TMPFILE file is linked into the tmpfs, the
+	 * first link must skip that, to get the accounting right.
 	 */
-	ret = shmem_reserve_inode(inode->i_sb);
-	if (ret)
-		goto out;
+	if (inode->i_nlink) {
+		ret = shmem_reserve_inode(inode->i_sb);
+		if (ret)
+			goto out;
+	}
 
 	dir->i_size += BOGO_DIRENT_SIZE;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -2462,13 +2498,12 @@
 	info = SHMEM_I(inode);
 	inode->i_size = len-1;
 	if (len <= SHORT_SYMLINK_LEN) {
-		info->symlink = kmemdup(symname, len, GFP_KERNEL);
-		if (!info->symlink) {
+		inode->i_link = kmemdup(symname, len, GFP_KERNEL);
+		if (!inode->i_link) {
 			iput(inode);
 			return -ENOMEM;
 		}
 		inode->i_op = &shmem_short_symlink_operations;
-		inode->i_link = info->symlink;
 	} else {
 		error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
 		if (error) {
@@ -2682,8 +2717,7 @@
 static int shmem_match(struct inode *ino, void *vfh)
 {
 	__u32 *fh = vfh;
-	__u64 inum = fh[2];
-	inum = (inum << 32) | fh[1];
+	__u64 inum = fh[1];
 	return ino->i_ino == inum && fh[0] == ino->i_generation;
 }
 
@@ -2694,14 +2728,11 @@
 	struct dentry *dentry = NULL;
 	u64 inum;
 
-	if (fh_len < 3)
+	if (fh_len < 2)
 		return NULL;
 
-	inum = fid->raw[2];
-	inum = (inum << 32) | fid->raw[1];
-
-	inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
-			shmem_match, fid->raw);
+	inum = fid->raw[1];
+	inode = ilookup5(sb, inum, shmem_match, fid->raw);
 	if (inode) {
 		dentry = d_find_alias(inode);
 		iput(inode);
@@ -2713,30 +2744,15 @@
 static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len,
 				struct inode *parent)
 {
-	if (*len < 3) {
-		*len = 3;
+	if (*len < 2) {
+		*len = 2;
 		return FILEID_INVALID;
 	}
 
-	if (inode_unhashed(inode)) {
-		/* Unfortunately insert_inode_hash is not idempotent,
-		 * so as we hash inodes here rather than at creation
-		 * time, we need a lock to ensure we only try
-		 * to do it once
-		 */
-		static DEFINE_SPINLOCK(lock);
-		spin_lock(&lock);
-		if (inode_unhashed(inode))
-			__insert_inode_hash(inode,
-					    inode->i_ino + inode->i_generation);
-		spin_unlock(&lock);
-	}
-
 	fh[0] = inode->i_generation;
 	fh[1] = inode->i_ino;
-	fh[2] = ((__u64)inode->i_ino) >> 32;
 
-	*len = 3;
+	*len = 2;
 	return 1;
 }
 
@@ -2801,7 +2817,7 @@
 				goto bad_val;
 		} else if (!strcmp(this_char,"nr_inodes")) {
 			sbinfo->max_inodes = memparse(value, &rest);
-			if (*rest)
+			if (*rest || sbinfo->max_inodes < 2)
 				goto bad_val;
 		} else if (!strcmp(this_char,"mode")) {
 			if (remount)
@@ -2854,7 +2870,7 @@
 {
 	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 	struct shmem_sb_info config = *sbinfo;
-	unsigned long inodes;
+	int inodes;
 	int error = -EINVAL;
 
 	config.mpol = NULL;
@@ -2902,7 +2918,7 @@
 		seq_printf(seq, ",size=%luk",
 			sbinfo->max_blocks << (PAGE_CACHE_SHIFT - 10));
 	if (sbinfo->max_inodes != shmem_default_max_inodes())
-		seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
+		seq_printf(seq, ",nr_inodes=%d", sbinfo->max_inodes);
 	if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
 		seq_printf(seq, ",mode=%03ho", sbinfo->mode);
 	if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
@@ -2991,6 +3007,8 @@
 {
 	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 
+	if (!sbinfo->idr_nouse)
+		idr_destroy(&sbinfo->idr);
 	percpu_counter_destroy(&sbinfo->used_blocks);
 	mpol_put(sbinfo->mpol);
 	kfree(sbinfo);
@@ -3009,6 +3027,8 @@
 	if (!sbinfo)
 		return -ENOMEM;
 
+	mutex_init(&sbinfo->idr_lock);
+	idr_init(&sbinfo->idr);
 	sbinfo->mode = S_IRWXUGO | S_ISVTX;
 	sbinfo->uid = current_fsuid();
 	sbinfo->gid = current_fsgid();
@@ -3083,6 +3103,7 @@
 static void shmem_destroy_callback(struct rcu_head *head)
 {
 	struct inode *inode = container_of(head, struct inode, i_rcu);
+	kfree(inode->i_link);
 	kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
 }
 
@@ -3112,6 +3133,15 @@
 	kmem_cache_destroy(shmem_inode_cachep);
 }
 
+static __init void shmem_no_idr(struct super_block *sb)
+{
+	struct shmem_sb_info *sbinfo;
+
+	sbinfo = SHMEM_SB(sb);
+	sbinfo->idr_nouse = true;
+	idr_destroy(&sbinfo->idr);
+}
+
 static const struct address_space_operations shmem_aops = {
 	.writepage	= shmem_writepage,
 	.set_page_dirty	= __set_page_dirty_no_writeback,
@@ -3248,6 +3278,7 @@
 		printk(KERN_ERR "Could not kern_mount tmpfs\n");
 		goto out1;
 	}
+	shmem_no_idr(shm_mnt->mnt_sb);
 	return 0;
 
 out1:
--- linux-4.4.0.orig/mm/slab.c
+++ linux-4.4.0/mm/slab.c
@@ -660,14 +660,6 @@
 
 static void init_arraycache(struct array_cache *ac, int limit, int batch)
 {
-	/*
-	 * The array_cache structures contain pointers to free object.
-	 * However, when such objects are allocated or transferred to another
-	 * cache the pointers are not cleared and they could be counted as
-	 * valid references during a kmemleak scan. Therefore, kmemleak must
-	 * not scan such objects.
-	 */
-	kmemleak_no_scan(ac);
 	if (ac) {
 		ac->avail = 0;
 		ac->limit = limit;
@@ -683,6 +675,14 @@
 	struct array_cache *ac = NULL;
 
 	ac = kmalloc_node(memsize, gfp, node);
+	/*
+	 * The array_cache structures contain pointers to free object.
+	 * However, when such objects are allocated or transferred to another
+	 * cache the pointers are not cleared and they could be counted as
+	 * valid references during a kmemleak scan. Therefore, kmemleak must
+	 * not scan such objects.
+	 */
+	kmemleak_no_scan(ac);
 	init_arraycache(ac, entries, batchcount);
 	return ac;
 }
@@ -875,8 +875,11 @@
 	struct alien_cache *alc = NULL;
 
 	alc = kmalloc_node(memsize, gfp, node);
-	init_arraycache(&alc->ac, entries, batch);
-	spin_lock_init(&alc->lock);
+	if (alc) {
+		kmemleak_no_scan(alc);
+		init_arraycache(&alc->ac, entries, batch);
+		spin_lock_init(&alc->lock);
+	}
 	return alc;
 }
 
@@ -3915,7 +3918,8 @@
 	next_reap_node();
 out:
 	/* Set up the next iteration */
-	schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_AC));
+	schedule_delayed_work_on(smp_processor_id(), work,
+				round_jiffies_relative(REAPTIMEOUT_AC));
 }
 
 #ifdef CONFIG_SLABINFO
--- linux-4.4.0.orig/mm/slab_common.c
+++ linux-4.4.0/mm/slab_common.c
@@ -250,7 +250,7 @@
 {
 	struct kmem_cache *s;
 
-	if (slab_nomerge || (flags & SLAB_NEVER_MERGE))
+	if (slab_nomerge)
 		return NULL;
 
 	if (ctor)
@@ -261,6 +261,9 @@
 	size = ALIGN(size, align);
 	flags = kmem_cache_flags(size, flags, name, NULL);
 
+	if (flags & SLAB_NEVER_MERGE)
+		return NULL;
+
 	list_for_each_entry_reverse(s, &slab_caches, list) {
 		if (slab_unmergeable(s))
 			continue;
@@ -521,8 +524,8 @@
 		goto out_unlock;
 
 	cgroup_name(css->cgroup, memcg_name_buf, sizeof(memcg_name_buf));
-	cache_name = kasprintf(GFP_KERNEL, "%s(%d:%s)", root_cache->name,
-			       css->id, memcg_name_buf);
+	cache_name = kasprintf(GFP_KERNEL, "%s(%llu:%s)", root_cache->name,
+			       css->serial_nr, memcg_name_buf);
 	if (!cache_name)
 		goto out_unlock;
 
@@ -1266,7 +1269,7 @@
 	if (unlikely(ZERO_OR_NULL_PTR(mem)))
 		return;
 	ks = ksize(mem);
-	memset(mem, 0, ks);
+	memzero_explicit(mem, ks);
 	kfree(mem);
 }
 EXPORT_SYMBOL(kzfree);
--- linux-4.4.0.orig/mm/slub.c
+++ linux-4.4.0/mm/slub.c
@@ -659,7 +659,7 @@
 	print_trailer(s, page, object);
 }
 
-static void slab_err(struct kmem_cache *s, struct page *page,
+static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page,
 			const char *fmt, ...)
 {
 	va_list args;
@@ -1661,7 +1661,7 @@
 {
 	struct page *page, *page2;
 	void *object = NULL;
-	int available = 0;
+	unsigned int available = 0;
 	int objects;
 
 	/*
@@ -1777,8 +1777,6 @@
 
 	if (node == NUMA_NO_NODE)
 		searchnode = numa_mem_id();
-	else if (!node_present_pages(node))
-		searchnode = node_to_mem_node(node);
 
 	object = get_partial_node(s, get_node(s, searchnode), c, flags);
 	if (object || node != NUMA_NO_NODE)
@@ -2355,17 +2353,27 @@
 	struct page *page;
 
 	page = c->page;
-	if (!page)
+	if (!page) {
+		/*
+		 * if the node is not online or has no normal memory, just
+		 * ignore the node constraint
+		 */
+		if (unlikely(node != NUMA_NO_NODE &&
+			     !node_state(node, N_NORMAL_MEMORY)))
+			node = NUMA_NO_NODE;
 		goto new_slab;
+	}
 redo:
 
 	if (unlikely(!node_match(page, node))) {
-		int searchnode = node;
-
-		if (node != NUMA_NO_NODE && !node_present_pages(node))
-			searchnode = node_to_mem_node(node);
-
-		if (unlikely(!node_match(page, searchnode))) {
+		/*
+		 * same as above but node_match() being false already
+		 * implies node != NUMA_NO_NODE
+		 */
+		if (!node_state(node, N_NORMAL_MEMORY)) {
+			node = NUMA_NO_NODE;
+			goto redo;
+		} else {
 			stat(s, ALLOC_NODE_MISMATCH);
 			deactivate_slab(s, page, c->freelist);
 			c->page = NULL;
@@ -2788,11 +2796,13 @@
 	barrier();
 
 	if (likely(page == c->page)) {
-		set_freepointer(s, tail_obj, c->freelist);
+		void **freelist = READ_ONCE(c->freelist);
+
+		set_freepointer(s, tail_obj, freelist);
 
 		if (unlikely(!this_cpu_cmpxchg_double(
 				s->cpu_slab->freelist, s->cpu_slab->tid,
-				c->freelist, tid,
+				freelist, tid,
 				head, next_tid(tid)))) {
 
 			note_cmpxchg_failure("slab_free", s, tid);
@@ -2819,6 +2829,7 @@
 	void *tail;
 	void *freelist;
 	int cnt;
+	struct kmem_cache *s;
 };
 
 /*
@@ -2833,8 +2844,9 @@
  * synchronization primitive.  Look ahead in the array is limited due
  * to performance reasons.
  */
-static int build_detached_freelist(struct kmem_cache *s, size_t size,
-				   void **p, struct detached_freelist *df)
+static inline
+int build_detached_freelist(struct kmem_cache *s, size_t size,
+			    void **p, struct detached_freelist *df)
 {
 	size_t first_skipped_index = 0;
 	int lookahead = 3;
@@ -2850,8 +2862,11 @@
 	if (!object)
 		return 0;
 
+	/* Support for memcg, compiler can optimize this out */
+	df->s = cache_from_obj(s, object);
+
 	/* Start new detached freelist */
-	set_freepointer(s, object, NULL);
+	set_freepointer(df->s, object, NULL);
 	df->page = virt_to_head_page(object);
 	df->tail = object;
 	df->freelist = object;
@@ -2866,7 +2881,7 @@
 		/* df->page is always set at this point */
 		if (df->page == virt_to_head_page(object)) {
 			/* Opportunity build freelist */
-			set_freepointer(s, object, df->freelist);
+			set_freepointer(df->s, object, df->freelist);
 			df->freelist = object;
 			df->cnt++;
 			p[size] = NULL; /* mark object processed */
@@ -2885,25 +2900,20 @@
 	return first_skipped_index;
 }
 
-
 /* Note that interrupts must be enabled when calling this function. */
-void kmem_cache_free_bulk(struct kmem_cache *orig_s, size_t size, void **p)
+void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
 {
 	if (WARN_ON(!size))
 		return;
 
 	do {
 		struct detached_freelist df;
-		struct kmem_cache *s;
-
-		/* Support for memcg */
-		s = cache_from_obj(orig_s, p[size - 1]);
 
 		size = build_detached_freelist(s, size, p, &df);
 		if (unlikely(!df.page))
 			continue;
 
-		slab_free(s, df.page, df.freelist, df.tail, df.cnt, _RET_IP_);
+		slab_free(df.s, df.page, df.freelist, df.tail, df.cnt,_RET_IP_);
 	} while (likely(size));
 }
 EXPORT_SYMBOL(kmem_cache_free_bulk);
@@ -2932,6 +2942,15 @@
 
 		if (unlikely(!object)) {
 			/*
+			 * We may have removed an object from c->freelist using
+			 * the fastpath in the previous iteration; in that case,
+			 * c->tid has not been bumped yet.
+			 * Since ___slab_alloc() may reenable interrupts while
+			 * allocating memory, we should bump c->tid now.
+			 */
+			c->tid = next_tid(c->tid);
+
+			/*
 			 * Invoking slow path likely have side-effect
 			 * of re-populating per CPU c->freelist
 			 */
@@ -4522,7 +4541,17 @@
 		}
 	}
 
-	get_online_mems();
+	/*
+	 * It is impossible to take "mem_hotplug_lock" here with "kernfs_mutex"
+	 * already held which will conflict with an existing lock order:
+	 *
+	 * mem_hotplug_lock->slab_mutex->kernfs_mutex
+	 *
+	 * We don't really need mem_hotplug_lock (to hold off
+	 * slab_mem_going_offline_callback) here because slab's memory hot
+	 * unplug code doesn't destroy the kmem_cache->node[] data.
+	 */
+
 #ifdef CONFIG_SLUB_DEBUG
 	if (flags & SO_ALL) {
 		struct kmem_cache_node *n;
@@ -4563,7 +4592,6 @@
 			x += sprintf(buf + x, " N%d=%lu",
 					node, nodes[node]);
 #endif
-	put_online_mems();
 	kfree(nodes);
 	return x + sprintf(buf + x, "\n");
 }
@@ -4674,10 +4702,10 @@
 static ssize_t cpu_partial_store(struct kmem_cache *s, const char *buf,
 				 size_t length)
 {
-	unsigned long objects;
+	unsigned int objects;
 	int err;
 
-	err = kstrtoul(buf, 10, &objects);
+	err = kstrtouint(buf, 10, &objects);
 	if (err)
 		return err;
 	if (objects && !kmem_cache_has_cpu_partial(s))
@@ -5261,6 +5289,7 @@
 		char mbuf[64];
 		char *buf;
 		struct slab_attribute *attr = to_slab_attr(slab_attrs[i]);
+		ssize_t len;
 
 		if (!attr || !attr->store || !attr->show)
 			continue;
@@ -5276,7 +5305,8 @@
 		 */
 		if (buffer)
 			buf = buffer;
-		else if (root_cache->max_attr_size < ARRAY_SIZE(mbuf))
+		else if (root_cache->max_attr_size < ARRAY_SIZE(mbuf) &&
+			 !IS_ENABLED(CONFIG_SLUB_STATS))
 			buf = mbuf;
 		else {
 			buffer = (char *) get_zeroed_page(GFP_KERNEL);
@@ -5285,8 +5315,9 @@
 			buf = buffer;
 		}
 
-		attr->show(root_cache, buf);
-		attr->store(s, buf, strlen(buf));
+		len = attr->show(root_cache, buf);
+		if (len > 0)
+			attr->store(s, buf, len);
 	}
 
 	if (buffer)
@@ -5344,7 +5375,8 @@
 	char *name = kmalloc(ID_STR_LENGTH, GFP_KERNEL);
 	char *p = name;
 
-	BUG_ON(!name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
 
 	*p++ = ':';
 	/*
@@ -5390,6 +5422,8 @@
 		 * for the symlinks.
 		 */
 		name = create_unique_id(s);
+		if (IS_ERR(name))
+			return PTR_ERR(name);
 	}
 
 	s->kobj.kset = cache_kset(s);
--- linux-4.4.0.orig/mm/swap_cgroup.c
+++ linux-4.4.0/mm/swap_cgroup.c
@@ -48,6 +48,9 @@
 		if (!page)
 			goto not_enough_page;
 		ctrl->map[idx] = page;
+
+		if (!(idx % SWAP_CLUSTER_MAX))
+			cond_resched();
 	}
 	return 0;
 not_enough_page:
@@ -202,6 +205,8 @@
 			struct page *page = map[i];
 			if (page)
 				__free_page(page);
+			if (!(i % SWAP_CLUSTER_MAX))
+				cond_resched();
 		}
 		vfree(map);
 	}
--- linux-4.4.0.orig/mm/swap_state.c
+++ linux-4.4.0/mm/swap_state.c
@@ -19,6 +19,7 @@
 #include <linux/migrate.h>
 
 #include <asm/pgtable.h>
+#include "internal.h"
 
 /*
  * swapper_space is a fiction, retained to simplify the path through
@@ -319,7 +320,7 @@
 		/*
 		 * call radix_tree_preload() while we can wait.
 		 */
-		err = radix_tree_maybe_preload(gfp_mask & GFP_KERNEL);
+		err = radix_tree_maybe_preload(gfp_mask & GFP_RECLAIM_MASK);
 		if (err)
 			break;
 
--- linux-4.4.0.orig/mm/swapfile.c
+++ linux-4.4.0/mm/swapfile.c
@@ -48,6 +48,12 @@
 DEFINE_SPINLOCK(swap_lock);
 static unsigned int nr_swapfiles;
 atomic_long_t nr_swap_pages;
+/*
+ * Some modules use swappable objects and may try to swap them out under
+ * memory pressure (via the shrinker). Before doing so, they may wish to
+ * check to see if any swap space is available.
+ */
+EXPORT_SYMBOL_GPL(nr_swap_pages);
 /* protected with swap_lock. reading in vm_swap_full() doesn't need lock */
 long total_swap_pages;
 static int least_priority;
@@ -1653,7 +1659,7 @@
 {
 	swp_entry_t entry;
 	entry.val = page_private(page);
-	return map_swap_entry(entry, bdev);
+	return map_swap_entry(entry, bdev) << (PAGE_SHIFT - 9);
 }
 
 /*
@@ -2206,6 +2212,35 @@
 	return 0;
 }
 
+
+/*
+ * Find out how many pages are allowed for a single swap device. There
+ * are two limiting factors:
+ * 1) the number of bits for the swap offset in the swp_entry_t type, and
+ * 2) the number of bits in the swap pte, as defined by the different
+ * architectures.
+ *
+ * In order to find the largest possible bit mask, a swap entry with
+ * swap type 0 and swap offset ~0UL is created, encoded to a swap pte,
+ * decoded to a swp_entry_t again, and finally the swap offset is
+ * extracted.
+ *
+ * This will mask all the bits from the initial ~0UL mask that can't
+ * be encoded in either the swp_entry_t or the architecture definition
+ * of a swap pte.
+ */
+unsigned long generic_max_swapfile_size(void)
+{
+	return swp_offset(pte_to_swp_entry(
+			swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1;
+}
+
+/* Can be overridden by an architecture for additional checks. */
+__weak unsigned long max_swapfile_size(void)
+{
+	return generic_max_swapfile_size();
+}
+
 static unsigned long read_swap_header(struct swap_info_struct *p,
 					union swap_header *swap_header,
 					struct inode *inode)
@@ -2225,6 +2260,8 @@
 		swab32s(&swap_header->info.version);
 		swab32s(&swap_header->info.last_page);
 		swab32s(&swap_header->info.nr_badpages);
+		if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
+			return 0;
 		for (i = 0; i < swap_header->info.nr_badpages; i++)
 			swab32s(&swap_header->info.badpages[i]);
 	}
@@ -2239,23 +2276,12 @@
 	p->cluster_next = 1;
 	p->cluster_nr = 0;
 
-	/*
-	 * Find out how many pages are allowed for a single swap
-	 * device. There are two limiting factors: 1) the number
-	 * of bits for the swap offset in the swp_entry_t type, and
-	 * 2) the number of bits in the swap pte as defined by the
-	 * different architectures. In order to find the
-	 * largest possible bit mask, a swap entry with swap type 0
-	 * and swap offset ~0UL is created, encoded to a swap pte,
-	 * decoded to a swp_entry_t again, and finally the swap
-	 * offset is extracted. This will mask all the bits from
-	 * the initial ~0UL mask that can't be encoded in either
-	 * the swp_entry_t or the architecture definition of a
-	 * swap pte.
-	 */
-	maxpages = swp_offset(pte_to_swp_entry(
-			swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1;
+	maxpages = max_swapfile_size();
 	last_page = swap_header->info.last_page;
+	if (!last_page) {
+		pr_warn("Empty swap-file\n");
+		return 0;
+	}
 	if (last_page > maxpages) {
 		pr_warn("Truncating oversized swap area, only using %luk out of %luk\n",
 			maxpages << (PAGE_SHIFT - 10),
--- linux-4.4.0.orig/mm/truncate.c
+++ linux-4.4.0/mm/truncate.c
@@ -432,9 +432,13 @@
 		 */
 		spin_lock_irq(&mapping->tree_lock);
 		spin_unlock_irq(&mapping->tree_lock);
-
-		truncate_inode_pages(mapping, 0);
 	}
+
+	/*
+	 * Cleancache needs notification even if there are no pages or shadow
+	 * entries.
+	 */
+	truncate_inode_pages(mapping, 0);
 }
 EXPORT_SYMBOL(truncate_inode_pages_final);
 
@@ -732,7 +736,7 @@
  */
 void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to)
 {
-	int bsize = 1 << inode->i_blkbits;
+	int bsize = i_blocksize(inode);
 	loff_t rounded_from;
 	struct page *page;
 	pgoff_t index;
--- linux-4.4.0.orig/mm/userfaultfd.c
+++ linux-4.4.0/mm/userfaultfd.c
@@ -221,22 +221,23 @@
 		}
 
 		dst_pmdval = pmd_read_atomic(dst_pmd);
-		/*
-		 * If the dst_pmd is mapped as THP don't
-		 * override it and just be strict.
-		 */
-		if (unlikely(pmd_trans_huge(dst_pmdval))) {
-			err = -EEXIST;
-			break;
-		}
 		if (unlikely(pmd_none(dst_pmdval)) &&
 		    unlikely(__pte_alloc(dst_mm, dst_vma, dst_pmd,
 					 dst_addr))) {
 			err = -ENOMEM;
 			break;
 		}
-		/* If an huge pmd materialized from under us fail */
-		if (unlikely(pmd_trans_huge(*dst_pmd))) {
+		dst_pmdval = pmd_read_atomic(dst_pmd);
+		/*
+		 * If the dst_pmd is THP don't override it and just be strict.
+		 * (This includes the case where the PMD used to be THP and
+		 * changed back to none after __pte_alloc().)
+		 */
+		if (unlikely(!pmd_present(dst_pmdval) || pmd_trans_huge(dst_pmdval) )) {
+			err = -EEXIST;
+			break;
+		}
+		if (unlikely(pmd_bad(dst_pmdval))) {
 			err = -EFAULT;
 			break;
 		}
--- linux-4.4.0.orig/mm/util.c
+++ linux-4.4.0/mm/util.c
@@ -80,6 +80,8 @@
  * @s: the string to duplicate
  * @max: read at most @max chars from @s
  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Note: Use kmemdup_nul() instead if the size is known exactly.
  */
 char *kstrndup(const char *s, size_t max, gfp_t gfp)
 {
@@ -118,6 +120,28 @@
 EXPORT_SYMBOL(kmemdup);
 
 /**
+ * kmemdup_nul - Create a NUL-terminated string from unterminated data
+ * @s: The data to stringify
+ * @len: The size of the data
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
+{
+	char *buf;
+
+	if (!s)
+		return NULL;
+
+	buf = kmalloc_track_caller(len + 1, gfp);
+	if (buf) {
+		memcpy(buf, s, len);
+		buf[len] = '\0';
+	}
+	return buf;
+}
+EXPORT_SYMBOL(kmemdup_nul);
+
+/**
  * memdup_user - duplicate memory region from user space
  *
  * @src: source address in user space
@@ -176,6 +200,37 @@
 }
 EXPORT_SYMBOL(strndup_user);
 
+/**
+ * memdup_user_nul - duplicate memory region from user space and NUL-terminate
+ *
+ * @src: source address in user space
+ * @len: number of bytes to copy
+ *
+ * Returns an ERR_PTR() on failure.
+ */
+void *memdup_user_nul(const void __user *src, size_t len)
+{
+	char *p;
+
+	/*
+	 * Always use GFP_KERNEL, since copy_from_user() can sleep and
+	 * cause pagefault, which makes it pointless to use GFP_NOFS
+	 * or GFP_ATOMIC.
+	 */
+	p = kmalloc_track_caller(len + 1, GFP_KERNEL);
+	if (!p)
+		return ERR_PTR(-ENOMEM);
+
+	if (copy_from_user(p, src, len)) {
+		kfree(p);
+		return ERR_PTR(-EFAULT);
+	}
+	p[len] = '\0';
+
+	return p;
+}
+EXPORT_SYMBOL(memdup_user_nul);
+
 void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
 		struct vm_area_struct *prev, struct rb_node *rb_parent)
 {
@@ -199,36 +254,11 @@
 }
 
 /* Check if the vma is being used as a stack by this task */
-static int vm_is_stack_for_task(struct task_struct *t,
-				struct vm_area_struct *vma)
+int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t)
 {
 	return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t));
 }
 
-/*
- * Check if the vma is being used as a stack.
- * If is_group is non-zero, check in the entire thread group or else
- * just check in the current task. Returns the task_struct of the task
- * that the vma is stack for. Must be called under rcu_read_lock().
- */
-struct task_struct *task_of_stack(struct task_struct *task,
-				struct vm_area_struct *vma, bool in_group)
-{
-	if (vm_is_stack_for_task(task, vma))
-		return task;
-
-	if (in_group) {
-		struct task_struct *t;
-
-		for_each_thread(task, t) {
-			if (vm_is_stack_for_task(t, vma))
-				return t;
-		}
-	}
-
-	return NULL;
-}
-
 #if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
 void arch_pick_mmap_layout(struct mm_struct *mm)
 {
@@ -279,7 +309,7 @@
 {
 	struct mm_struct *mm = current->mm;
 	return get_user_pages_unlocked(current, mm, start, nr_pages,
-				       write, 0, pages);
+				       pages, write ? FOLL_WRITE : 0);
 }
 EXPORT_SYMBOL_GPL(get_user_pages_fast);
 
@@ -429,17 +459,25 @@
 	int res = 0;
 	unsigned int len;
 	struct mm_struct *mm = get_task_mm(task);
+	unsigned long arg_start, arg_end, env_start, env_end;
 	if (!mm)
 		goto out;
 	if (!mm->arg_end)
 		goto out_mm;	/* Shh! No looking before we're done */
 
-	len = mm->arg_end - mm->arg_start;
+	down_read(&mm->mmap_sem);
+	arg_start = mm->arg_start;
+	arg_end = mm->arg_end;
+	env_start = mm->env_start;
+	env_end = mm->env_end;
+	up_read(&mm->mmap_sem);
+
+	len = arg_end - arg_start;
 
 	if (len > buflen)
 		len = buflen;
 
-	res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+	res = access_process_vm(task, arg_start, buffer, len, 0);
 
 	/*
 	 * If the nul at the end of args has been overwritten, then
@@ -450,10 +488,10 @@
 		if (len < res) {
 			res = len;
 		} else {
-			len = mm->env_end - mm->env_start;
+			len = env_end - env_start;
 			if (len > buflen - res)
 				len = buflen - res;
-			res += access_process_vm(task, mm->env_start,
+			res += access_process_vm(task, env_start,
 						 buffer+res, len, 0);
 			res = strnlen(buffer, res);
 		}
--- linux-4.4.0.orig/mm/vmacache.c
+++ linux-4.4.0/mm/vmacache.c
@@ -6,44 +6,6 @@
 #include <linux/vmacache.h>
 
 /*
- * Flush vma caches for threads that share a given mm.
- *
- * The operation is safe because the caller holds the mmap_sem
- * exclusively and other threads accessing the vma cache will
- * have mmap_sem held at least for read, so no extra locking
- * is required to maintain the vma cache.
- */
-void vmacache_flush_all(struct mm_struct *mm)
-{
-	struct task_struct *g, *p;
-
-	count_vm_vmacache_event(VMACACHE_FULL_FLUSHES);
-
-	/*
-	 * Single threaded tasks need not iterate the entire
-	 * list of process. We can avoid the flushing as well
-	 * since the mm's seqnum was increased and don't have
-	 * to worry about other threads' seqnum. Current's
-	 * flush will occur upon the next lookup.
-	 */
-	if (atomic_read(&mm->mm_users) == 1)
-		return;
-
-	rcu_read_lock();
-	for_each_process_thread(g, p) {
-		/*
-		 * Only flush the vmacache pointers as the
-		 * mm seqnum is already set and curr's will
-		 * be set upon invalidation when the next
-		 * lookup is done.
-		 */
-		if (mm == p->mm)
-			vmacache_flush(p);
-	}
-	rcu_read_unlock();
-}
-
-/*
  * This task may be accessing a foreign mm via (for example)
  * get_user_pages()->find_vma().  The vmacache is task-local and this
  * task's vmacache pertains to a different mm (ie, its own).  There is
--- linux-4.4.0.orig/mm/vmalloc.c
+++ linux-4.4.0/mm/vmalloc.c
@@ -446,7 +446,11 @@
 	}
 
 found:
-	if (addr + size > vend)
+	/*
+	 * Check also calculated address against the vstart,
+	 * because it can be 0 because of big align request.
+	 */
+	if (addr + size > vend || addr < vstart)
 		goto overflow;
 
 	va->va_start = addr;
@@ -1460,7 +1464,7 @@
 			addr))
 		return;
 
-	area = remove_vm_area(addr);
+	area = find_vm_area(addr);
 	if (unlikely(!area)) {
 		WARN(1, KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n",
 				addr);
@@ -1470,6 +1474,7 @@
 	debug_check_no_locks_freed(addr, get_vm_area_size(area));
 	debug_check_no_obj_freed(addr, get_vm_area_size(area));
 
+	remove_vm_area(addr);
 	if (deallocate_pages) {
 		int i;
 
@@ -1673,6 +1678,12 @@
 		return NULL;
 
 	/*
+	 * First make sure the mappings are removed from all page-tables
+	 * before they are freed.
+	 */
+	vmalloc_sync_unmappings();
+
+	/*
 	 * In this function, newly allocated vm_struct has VM_UNINITIALIZED
 	 * flag. It means that vm_struct is not fully initialized.
 	 * Now, it is fully initialized, so remove this flag here.
@@ -2161,7 +2172,7 @@
 	if (!(area->flags & VM_USERMAP))
 		return -EINVAL;
 
-	if (kaddr + size > area->addr + area->size)
+	if (kaddr + size > area->addr + get_vm_area_size(area))
 		return -EINVAL;
 
 	do {
@@ -2207,13 +2218,19 @@
 EXPORT_SYMBOL(remap_vmalloc_range);
 
 /*
- * Implement a stub for vmalloc_sync_all() if the architecture chose not to
- * have one.
+ * Implement stubs for vmalloc_sync_[un]mappings () if the architecture chose
+ * not to have one.
+ *
+ * The purpose of this function is to make sure the vmalloc area
+ * mappings are identical in all page-tables in the system.
  */
-void __weak vmalloc_sync_all(void)
+void __weak vmalloc_sync_mappings(void)
 {
 }
 
+void __weak vmalloc_sync_unmappings(void)
+{
+}
 
 static int f(pte_t *pte, pgtable_t table, unsigned long addr, void *data)
 {
--- linux-4.4.0.orig/mm/vmpressure.c
+++ linux-4.4.0/mm/vmpressure.c
@@ -112,9 +112,16 @@
 						    unsigned long reclaimed)
 {
 	unsigned long scale = scanned + reclaimed;
-	unsigned long pressure;
+	unsigned long pressure = 0;
 
 	/*
+	 * reclaimed can be greater than scanned in cases
+	 * like THP, where the scanned is 1 and reclaimed
+	 * could be 512
+	 */
+	if (reclaimed >= scanned)
+		goto out;
+	/*
 	 * We calculate the ratio (in percents) of how many pages were
 	 * scanned vs. reclaimed in a given time frame (window). Note that
 	 * time is in VM reclaimer's "ticks", i.e. number of pages
@@ -124,6 +131,7 @@
 	pressure = scale - (reclaimed * scale / scanned);
 	pressure = pressure * 100 / scale;
 
+out:
 	pr_debug("%s: %3lu  (s: %lu  r: %lu)\n", __func__, pressure,
 		 scanned, reclaimed);
 
--- linux-4.4.0.orig/mm/vmscan.c
+++ linux-4.4.0/mm/vmscan.c
@@ -192,7 +192,7 @@
 }
 #endif
 
-static unsigned long zone_reclaimable_pages(struct zone *zone)
+unsigned long zone_reclaimable_pages(struct zone *zone)
 {
 	unsigned long nr;
 
@@ -254,10 +254,13 @@
  */
 void unregister_shrinker(struct shrinker *shrinker)
 {
+	if (!shrinker->nr_deferred)
+		return;
 	down_write(&shrinker_rwsem);
 	list_del(&shrinker->list);
 	up_write(&shrinker_rwsem);
 	kfree(shrinker->nr_deferred);
+	shrinker->nr_deferred = NULL;
 }
 EXPORT_SYMBOL(unregister_shrinker);
 
@@ -277,6 +280,7 @@
 	int nid = shrinkctl->nid;
 	long batch_size = shrinker->batch ? shrinker->batch
 					  : SHRINK_BATCH;
+	long scanned = 0, next_deferred;
 
 	freeable = shrinker->count_objects(shrinker, shrinkctl);
 	if (freeable == 0)
@@ -298,7 +302,9 @@
 		pr_err("shrink_slab: %pF negative objects to delete nr=%ld\n",
 		       shrinker->scan_objects, total_scan);
 		total_scan = freeable;
-	}
+		next_deferred = nr;
+	} else
+		next_deferred = total_scan;
 
 	/*
 	 * We need to avoid excessive windup on filesystem shrinkers
@@ -355,17 +361,22 @@
 
 		count_vm_events(SLABS_SCANNED, nr_to_scan);
 		total_scan -= nr_to_scan;
+		scanned += nr_to_scan;
 
 		cond_resched();
 	}
 
+	if (next_deferred >= scanned)
+		next_deferred -= scanned;
+	else
+		next_deferred = 0;
 	/*
 	 * move the unused scan count back into the shrinker in a
 	 * manner that handles concurrent updates. If we exhausted the
 	 * scan, there is no need to do an update.
 	 */
-	if (total_scan > 0)
-		new_nr = atomic_long_add_return(total_scan,
+	if (next_deferred > 0)
+		new_nr = atomic_long_add_return(next_deferred,
 						&shrinker->nr_deferred[nid]);
 	else
 		new_nr = atomic_long_read(&shrinker->nr_deferred[nid]);
@@ -442,6 +453,15 @@
 			sc.nid = 0;
 
 		freed += do_shrink_slab(&sc, shrinker, nr_scanned, nr_eligible);
+		/*
+		 * Bail out if someone want to register a new shrinker to
+		 * prevent the regsitration from being stalled for long periods
+		 * by parallel ongoing shrinking.
+		 */
+		if (rwsem_is_contended(&shrinker_rwsem)) {
+			freed = freed ? : 1;
+			break;
+		}
 	}
 
 	up_read(&shrinker_rwsem);
@@ -1301,6 +1321,7 @@
 
 		if (PageDirty(page)) {
 			struct address_space *mapping;
+			bool migrate_dirty;
 
 			/* ISOLATE_CLEAN means only clean pages */
 			if (mode & ISOLATE_CLEAN)
@@ -1309,10 +1330,19 @@
 			/*
 			 * Only pages without mappings or that have a
 			 * ->migratepage callback are possible to migrate
-			 * without blocking
+			 * without blocking. However, we can be racing with
+			 * truncation so it's necessary to lock the page
+			 * to stabilise the mapping as truncation holds
+			 * the page lock until after the page is removed
+			 * from the page cache.
 			 */
+			if (!trylock_page(page))
+				return ret;
+
 			mapping = page_mapping(page);
-			if (mapping && !mapping->a_ops->migratepage)
+			migrate_dirty = !mapping || mapping->a_ops->migratepage;
+			unlock_page(page);
+			if (!migrate_dirty)
 				return ret;
 		}
 	}
@@ -2046,10 +2076,16 @@
 	}
 
 	/*
-	 * There is enough inactive page cache, do not reclaim
-	 * anything from the anonymous working set right now.
+	 * If there is enough inactive page cache, i.e. if the size of the
+	 * inactive list is greater than that of the active list *and* the
+	 * inactive list actually has some pages to scan on this priority, we
+	 * do not reclaim anything from the anonymous working set right now.
+	 * Without the second condition we could end up never scanning an
+	 * lruvec even if it has plenty of old anonymous pages unless the
+	 * system is under heavy pressure.
 	 */
-	if (!inactive_file_is_low(lruvec)) {
+	if (!inactive_file_is_low(lruvec) &&
+	    get_lru_size(lruvec, LRU_INACTIVE_FILE) >> sc->priority) {
 		scan_balance = SCAN_FILE;
 		goto out;
 	}
@@ -2159,23 +2195,6 @@
 	}
 }
 
-#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
-static void init_tlb_ubc(void)
-{
-	/*
-	 * This deliberately does not clear the cpumask as it's expensive
-	 * and unnecessary. If there happens to be data in there then the
-	 * first SWAP_CLUSTER_MAX pages will send an unnecessary IPI and
-	 * then will be cleared.
-	 */
-	current->tlb_ubc.flush_required = false;
-}
-#else
-static inline void init_tlb_ubc(void)
-{
-}
-#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
-
 /*
  * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
  */
@@ -2210,8 +2229,6 @@
 	scan_adjusted = (global_reclaim(sc) && !current_is_kswapd() &&
 			 sc->priority == DEF_PRIORITY);
 
-	init_tlb_ubc();
-
 	blk_start_plug(&plug);
 	while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
 					nr[LRU_INACTIVE_FILE]) {
@@ -2511,10 +2528,8 @@
  *
  * If a zone is deemed to be full of pinned pages then just give it a light
  * scan then give up on it.
- *
- * Returns true if a zone was reclaimable.
  */
-static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
+static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
 {
 	struct zoneref *z;
 	struct zone *zone;
@@ -2522,7 +2537,6 @@
 	unsigned long nr_soft_scanned;
 	gfp_t orig_mask;
 	enum zone_type requested_highidx = gfp_zone(sc->gfp_mask);
-	bool reclaimable = false;
 
 	/*
 	 * If the number of buffer_heads in the machine exceeds the maximum
@@ -2534,13 +2548,13 @@
 		sc->gfp_mask |= __GFP_HIGHMEM;
 
 	for_each_zone_zonelist_nodemask(zone, z, zonelist,
-					requested_highidx, sc->nodemask) {
+					gfp_zone(sc->gfp_mask), sc->nodemask) {
 		enum zone_type classzone_idx;
 
 		if (!populated_zone(zone))
 			continue;
 
-		classzone_idx = requested_highidx;
+		classzone_idx = gfp_zone(sc->gfp_mask);
 		while (!populated_zone(zone->zone_pgdat->node_zones +
 							classzone_idx))
 			classzone_idx--;
@@ -2587,17 +2601,10 @@
 						&nr_soft_scanned);
 			sc->nr_reclaimed += nr_soft_reclaimed;
 			sc->nr_scanned += nr_soft_scanned;
-			if (nr_soft_reclaimed)
-				reclaimable = true;
 			/* need some check for avoid more shrink_zone() */
 		}
 
-		if (shrink_zone(zone, sc, zone_idx(zone) == classzone_idx))
-			reclaimable = true;
-
-		if (global_reclaim(sc) &&
-		    !reclaimable && zone_reclaimable(zone))
-			reclaimable = true;
+		shrink_zone(zone, sc, zone_idx(zone) == classzone_idx);
 	}
 
 	/*
@@ -2605,8 +2612,6 @@
 	 * promoted it to __GFP_HIGHMEM.
 	 */
 	sc->gfp_mask = orig_mask;
-
-	return reclaimable;
 }
 
 /*
@@ -2631,7 +2636,6 @@
 	int initial_priority = sc->priority;
 	unsigned long total_scanned = 0;
 	unsigned long writeback_threshold;
-	bool zones_reclaimable;
 retry:
 	delayacct_freepages_start();
 
@@ -2642,7 +2646,7 @@
 		vmpressure_prio(sc->gfp_mask, sc->target_mem_cgroup,
 				sc->priority);
 		sc->nr_scanned = 0;
-		zones_reclaimable = shrink_zones(zonelist, sc);
+		shrink_zones(zonelist, sc);
 
 		total_scanned += sc->nr_scanned;
 		if (sc->nr_reclaimed >= sc->nr_to_reclaim)
@@ -2689,10 +2693,6 @@
 		goto retry;
 	}
 
-	/* Any of the zones still reclaimable?  Don't OOM. */
-	if (zones_reclaimable)
-		return 1;
-
 	return 0;
 }
 
@@ -2929,7 +2929,9 @@
 					    sc.may_writepage,
 					    sc.gfp_mask);
 
+	current->flags |= PF_MEMALLOC;
 	nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
+	current->flags &= ~PF_MEMALLOC;
 
 	trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
 
@@ -2959,6 +2961,13 @@
 static bool zone_balanced(struct zone *zone, int order,
 			  unsigned long balance_gap, int classzone_idx)
 {
+	/*
+	 * if zone is so small that watermarks are the same, don't bother trying
+	 * to balance; kswapd would just spin continuously trying to balance it.
+	 */
+	if (low_wmark_pages(zone) == high_wmark_pages(zone))
+		return true;
+
 	if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone) +
 				    balance_gap, classzone_idx))
 		return false;
@@ -3831,7 +3840,13 @@
  */
 int page_evictable(struct page *page)
 {
-	return !mapping_unevictable(page_mapping(page)) && !PageMlocked(page);
+	int ret;
+
+	/* Prevent address_space of inode and swap cache from being freed */
+	rcu_read_lock();
+	ret = !mapping_unevictable(page_mapping(page)) && !PageMlocked(page);
+	rcu_read_unlock();
+	return ret;
 }
 
 #ifdef CONFIG_SHMEM
--- linux-4.4.0.orig/mm/vmstat.c
+++ linux-4.4.0/mm/vmstat.c
@@ -460,7 +460,7 @@
  *
  * The function returns the number of global counters updated.
  */
-static int refresh_cpu_vm_stats(void)
+static int refresh_cpu_vm_stats(bool do_pagesets)
 {
 	struct zone *zone;
 	int i;
@@ -484,33 +484,35 @@
 #endif
 			}
 		}
-		cond_resched();
 #ifdef CONFIG_NUMA
-		/*
-		 * Deal with draining the remote pageset of this
-		 * processor
-		 *
-		 * Check if there are pages remaining in this pageset
-		 * if not then there is nothing to expire.
-		 */
-		if (!__this_cpu_read(p->expire) ||
+		if (do_pagesets) {
+			cond_resched();
+			/*
+			 * Deal with draining the remote pageset of this
+			 * processor
+			 *
+			 * Check if there are pages remaining in this pageset
+			 * if not then there is nothing to expire.
+			 */
+			if (!__this_cpu_read(p->expire) ||
 			       !__this_cpu_read(p->pcp.count))
-			continue;
+				continue;
 
-		/*
-		 * We never drain zones local to this processor.
-		 */
-		if (zone_to_nid(zone) == numa_node_id()) {
-			__this_cpu_write(p->expire, 0);
-			continue;
-		}
+			/*
+			 * We never drain zones local to this processor.
+			 */
+			if (zone_to_nid(zone) == numa_node_id()) {
+				__this_cpu_write(p->expire, 0);
+				continue;
+			}
 
-		if (__this_cpu_dec_return(p->expire))
-			continue;
+			if (__this_cpu_dec_return(p->expire))
+				continue;
 
-		if (__this_cpu_read(p->pcp.count)) {
-			drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
-			changes++;
+			if (__this_cpu_read(p->pcp.count)) {
+				drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
+				changes++;
+			}
 		}
 #endif
 	}
@@ -736,6 +738,7 @@
 	"nr_slab_unreclaimable",
 	"nr_page_table_pages",
 	"nr_kernel_stack",
+	"nr_overhead",
 	"nr_unstable",
 	"nr_bounce",
 	"nr_vmscan_write",
@@ -854,10 +857,8 @@
 #endif
 #endif /* CONFIG_MEMORY_BALLOON */
 #ifdef CONFIG_DEBUG_TLBFLUSH
-#ifdef CONFIG_SMP
 	"nr_tlb_remote_flush",
 	"nr_tlb_remote_flush_received",
-#endif /* CONFIG_SMP */
 	"nr_tlb_local_flush_all",
 	"nr_tlb_local_flush_one",
 #endif /* CONFIG_DEBUG_TLBFLUSH */
@@ -865,7 +866,6 @@
 #ifdef CONFIG_DEBUG_VM_VMACACHE
 	"vmacache_find_calls",
 	"vmacache_find_hits",
-	"vmacache_full_flushes",
 #endif
 #endif /* CONFIG_VM_EVENTS_COUNTERS */
 };
@@ -1091,6 +1091,8 @@
 				continue;
 
 			page_ext = lookup_page_ext(page);
+			if (unlikely(!page_ext))
+				continue;
 
 			if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
 				continue;
@@ -1348,7 +1350,9 @@
 	unsigned long *l = arg;
 	unsigned long off = l - (unsigned long *)m->private;
 
-	seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
+	seq_puts(m, vmstat_text[off]);
+	seq_put_decimal_ull(m, ' ', *l);
+	seq_putc(m, '\n');
 	return 0;
 }
 
@@ -1386,15 +1390,20 @@
 
 static void vmstat_update(struct work_struct *w)
 {
-	if (refresh_cpu_vm_stats()) {
+	if (refresh_cpu_vm_stats(true)) {
 		/*
 		 * Counters were updated so we expect more updates
 		 * to occur in the future. Keep on running the
 		 * update worker thread.
+		 * If we were marked on cpu_stat_off clear the flag
+		 * so that vmstat_shepherd doesn't schedule us again.
 		 */
-		queue_delayed_work_on(smp_processor_id(), vmstat_wq,
-			this_cpu_ptr(&vmstat_work),
-			round_jiffies_relative(sysctl_stat_interval));
+		if (!cpumask_test_and_clear_cpu(smp_processor_id(),
+						cpu_stat_off)) {
+			queue_delayed_work_on(smp_processor_id(), vmstat_wq,
+				this_cpu_ptr(&vmstat_work),
+				round_jiffies_relative(sysctl_stat_interval));
+		}
 	} else {
 		/*
 		 * We did not update any counters so the app may be in
@@ -1403,21 +1412,16 @@
 		 * Defer the checking for differentials to the
 		 * shepherd thread on a different processor.
 		 */
-		int r;
-		/*
-		 * Shepherd work thread does not race since it never
-		 * changes the bit if its zero but the cpu
-		 * online / off line code may race if
-		 * worker threads are still allowed during
-		 * shutdown / startup.
-		 */
-		r = cpumask_test_and_set_cpu(smp_processor_id(),
-			cpu_stat_off);
-		VM_BUG_ON(r);
+		cpumask_set_cpu(smp_processor_id(), cpu_stat_off);
 	}
 }
 
 /*
+ * Switch off vmstat processing and then fold all the remaining differentials
+ * until the diffs stay at zero. The function is used by NOHZ and can only be
+ * invoked when tick processing is not active.
+ */
+/*
  * Check if the diffs for a certain cpu indicate that
  * an update is needed.
  */
@@ -1440,6 +1444,30 @@
 	return false;
 }
 
+void quiet_vmstat(void)
+{
+	if (system_state != SYSTEM_RUNNING)
+		return;
+
+	/*
+	 * If we are already in hands of the shepherd then there
+	 * is nothing for us to do here.
+	 */
+	if (cpumask_test_and_set_cpu(smp_processor_id(), cpu_stat_off))
+		return;
+
+	if (!need_update(smp_processor_id()))
+		return;
+
+	/*
+	 * Just refresh counters and do not care about the pending delayed
+	 * vmstat_update. It doesn't fire that often to matter and canceling
+	 * it would be too expensive from this path.
+	 * vmstat_shepherd will take care about that for us.
+	 */
+	refresh_cpu_vm_stats(false);
+}
+
 
 /*
  * Shepherd worker thread that checks the
@@ -1449,7 +1477,7 @@
  */
 static void vmstat_shepherd(struct work_struct *w);
 
-static DECLARE_DELAYED_WORK(shepherd, vmstat_shepherd);
+static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
 
 static void vmstat_shepherd(struct work_struct *w)
 {
@@ -1457,18 +1485,25 @@
 
 	get_online_cpus();
 	/* Check processors whose vmstat worker threads have been disabled */
-	for_each_cpu(cpu, cpu_stat_off)
-		if (need_update(cpu) &&
-			cpumask_test_and_clear_cpu(cpu, cpu_stat_off))
-
-			queue_delayed_work_on(cpu, vmstat_wq,
-				&per_cpu(vmstat_work, cpu), 0);
+	for_each_cpu(cpu, cpu_stat_off) {
+		struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
 
+		if (need_update(cpu)) {
+			if (cpumask_test_and_clear_cpu(cpu, cpu_stat_off))
+				queue_delayed_work_on(cpu, vmstat_wq, dw, 0);
+		} else {
+			/*
+			 * Cancel the work if quiet_vmstat has put this
+			 * cpu on cpu_stat_off because the work item might
+			 * be still scheduled
+			 */
+			cancel_delayed_work(dw);
+		}
+	}
 	put_online_cpus();
 
 	schedule_delayed_work(&shepherd,
 		round_jiffies_relative(sysctl_stat_interval));
-
 }
 
 static void __init start_shepherd_timer(void)
@@ -1554,7 +1589,7 @@
 #endif
 #ifdef CONFIG_PROC_FS
 	proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
-	proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
+	proc_create("pagetypeinfo", 0400, NULL, &pagetypeinfo_file_ops);
 	proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
 	proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
 #endif
--- linux-4.4.0.orig/mm/workingset.c
+++ linux-4.4.0/mm/workingset.c
@@ -341,21 +341,19 @@
 	 * no pages, so we expect to be able to remove them all and
 	 * delete and free the empty node afterwards.
 	 */
-
-	BUG_ON(!node->count);
-	BUG_ON(node->count & RADIX_TREE_COUNT_MASK);
+	BUG_ON(!workingset_node_shadows(node));
+	BUG_ON(workingset_node_pages(node));
 
 	for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) {
 		if (node->slots[i]) {
 			BUG_ON(!radix_tree_exceptional_entry(node->slots[i]));
 			node->slots[i] = NULL;
-			BUG_ON(node->count < (1U << RADIX_TREE_COUNT_SHIFT));
-			node->count -= 1U << RADIX_TREE_COUNT_SHIFT;
+			workingset_node_shadows_dec(node);
 			BUG_ON(!mapping->nrshadows);
 			mapping->nrshadows--;
 		}
 	}
-	BUG_ON(node->count);
+	BUG_ON(workingset_node_shadows(node));
 	inc_zone_state(page_zone(virt_to_page(node)), WORKINGSET_NODERECLAIM);
 	if (!__radix_tree_delete_node(&mapping->page_tree, node))
 		BUG();
--- linux-4.4.0.orig/mm/zsmalloc.c
+++ linux-4.4.0/mm/zsmalloc.c
@@ -309,7 +309,12 @@
 
 static void record_obj(unsigned long handle, unsigned long obj)
 {
-	*(unsigned long *)handle = obj;
+	/*
+	 * lsb of @obj represents handle lock while other bits
+	 * represent object value the handle is pointing so
+	 * updating shouldn't do store tearing.
+	 */
+	WRITE_ONCE(*(unsigned long *)handle, obj);
 }
 
 /* zpool driver */
@@ -1635,6 +1640,13 @@
 		free_obj = obj_malloc(d_page, class, handle);
 		zs_object_copy(free_obj, used_obj, class);
 		index++;
+		/*
+		 * record_obj updates handle's value to free_obj and it will
+		 * invalidate lock bit(ie, HANDLE_PIN_BIT) of handle, which
+		 * breaks synchronization using pin_tag(e,g, zs_free) so
+		 * let's keep the lock bit.
+		 */
+		free_obj |= BIT(HANDLE_PIN_BIT);
 		record_obj(handle, free_obj);
 		unpin_tag(handle);
 		obj_free(pool, class, used_obj);
@@ -1720,21 +1732,26 @@
 static unsigned long zs_can_compact(struct size_class *class)
 {
 	unsigned long obj_wasted;
+	unsigned long obj_allocated = zs_stat_get(class, OBJ_ALLOCATED);
+	unsigned long obj_used = zs_stat_get(class, OBJ_USED);
 
-	obj_wasted = zs_stat_get(class, OBJ_ALLOCATED) -
-		zs_stat_get(class, OBJ_USED);
+	if (obj_allocated <= obj_used)
+		return 0;
 
+	obj_wasted = obj_allocated - obj_used;
 	obj_wasted /= get_maxobj_per_zspage(class->size,
 			class->pages_per_zspage);
 
 	return obj_wasted * class->pages_per_zspage;
 }
 
-static void __zs_compact(struct zs_pool *pool, struct size_class *class)
+static unsigned long __zs_compact(struct zs_pool *pool,
+				   struct size_class *class)
 {
 	struct zs_compact_control cc;
 	struct page *src_page;
 	struct page *dst_page = NULL;
+	unsigned long pages_freed = 0;
 
 	spin_lock(&class->lock);
 	while ((src_page = isolate_source_page(class))) {
@@ -1765,7 +1782,7 @@
 
 		putback_zspage(pool, class, dst_page);
 		if (putback_zspage(pool, class, src_page) == ZS_EMPTY)
-			pool->stats.pages_compacted += class->pages_per_zspage;
+			pages_freed += class->pages_per_zspage;
 		spin_unlock(&class->lock);
 		cond_resched();
 		spin_lock(&class->lock);
@@ -1775,12 +1792,15 @@
 		putback_zspage(pool, class, src_page);
 
 	spin_unlock(&class->lock);
+
+	return pages_freed;
 }
 
 unsigned long zs_compact(struct zs_pool *pool)
 {
 	int i;
 	struct size_class *class;
+	unsigned long pages_freed = 0;
 
 	for (i = zs_size_classes - 1; i >= 0; i--) {
 		class = pool->size_class[i];
@@ -1788,10 +1808,11 @@
 			continue;
 		if (class->index != i)
 			continue;
-		__zs_compact(pool, class);
+		pages_freed += __zs_compact(pool, class);
 	}
+	atomic_long_add(pages_freed, &pool->stats.pages_compacted);
 
-	return pool->stats.pages_compacted;
+	return pages_freed;
 }
 EXPORT_SYMBOL_GPL(zs_compact);
 
@@ -1808,13 +1829,12 @@
 	struct zs_pool *pool = container_of(shrinker, struct zs_pool,
 			shrinker);
 
-	pages_freed = pool->stats.pages_compacted;
 	/*
 	 * Compact classes and calculate compaction delta.
 	 * Can run concurrently with a manually triggered
 	 * (by user) compaction.
 	 */
-	pages_freed = zs_compact(pool) - pages_freed;
+	pages_freed = zs_compact(pool);
 
 	return pages_freed ? pages_freed : SHRINK_STOP;
 }
--- linux-4.4.0.orig/mm/zswap.c
+++ linux-4.4.0/mm/zswap.c
@@ -78,7 +78,13 @@
 
 /* Enable/disable zswap (disabled by default) */
 static bool zswap_enabled;
-module_param_named(enabled, zswap_enabled, bool, 0644);
+static int zswap_enabled_param_set(const char *,
+				   const struct kernel_param *);
+static struct kernel_param_ops zswap_enabled_param_ops = {
+	.set =		zswap_enabled_param_set,
+	.get =		param_get_bool,
+};
+module_param_cb(enabled, &zswap_enabled_param_ops, &zswap_enabled, 0644);
 
 /* Crypto compressor to use */
 #define ZSWAP_COMPRESSOR_DEFAULT "lzo"
@@ -117,7 +123,7 @@
 	struct crypto_comp * __percpu *tfm;
 	struct kref kref;
 	struct list_head list;
-	struct rcu_head rcu_head;
+	struct work_struct work;
 	struct notifier_block notifier;
 	char tfm_name[CRYPTO_MAX_ALG_NAME];
 };
@@ -170,10 +176,15 @@
 static LIST_HEAD(zswap_pools);
 /* protects zswap_pools list modification */
 static DEFINE_SPINLOCK(zswap_pools_lock);
+/* pool counter to provide unique names to zpool */
+static atomic_t zswap_pools_count = ATOMIC_INIT(0);
 
 /* used by param callback function */
 static bool zswap_init_started;
 
+/* fatal error during init */
+static bool zswap_init_failed;
+
 /*********************************
 * helpers and fwd declarations
 **********************************/
@@ -565,6 +576,7 @@
 static struct zswap_pool *zswap_pool_create(char *type, char *compressor)
 {
 	struct zswap_pool *pool;
+	char name[38]; /* 'zswap' + 32 char (max) num + \0 */
 	gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM;
 
 	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
@@ -573,7 +585,10 @@
 		return NULL;
 	}
 
-	pool->zpool = zpool_create_pool(type, "zswap", gfp, &zswap_zpool_ops);
+	/* unique name for each pool specifically required by zsmalloc */
+	snprintf(name, 38, "zswap%x", atomic_inc_return(&zswap_pools_count));
+
+	pool->zpool = zpool_create_pool(type, name, gfp, &zswap_zpool_ops);
 	if (!pool->zpool) {
 		pr_err("%s zpool not available\n", type);
 		goto error;
@@ -652,9 +667,11 @@
 	return kref_get_unless_zero(&pool->kref);
 }
 
-static void __zswap_pool_release(struct rcu_head *head)
+static void __zswap_pool_release(struct work_struct *work)
 {
-	struct zswap_pool *pool = container_of(head, typeof(*pool), rcu_head);
+	struct zswap_pool *pool = container_of(work, typeof(*pool), work);
+
+	synchronize_rcu();
 
 	/* nobody should have been able to get a kref... */
 	WARN_ON(kref_get_unless_zero(&pool->kref));
@@ -674,7 +691,9 @@
 	WARN_ON(pool == zswap_pool_current());
 
 	list_del_rcu(&pool->list);
-	call_rcu(&pool->rcu_head, __zswap_pool_release);
+
+	INIT_WORK(&pool->work, __zswap_pool_release);
+	schedule_work(&pool->work);
 
 	spin_unlock(&zswap_pools_lock);
 }
@@ -696,6 +715,11 @@
 	char *s = strstrip((char *)val);
 	int ret;
 
+	if (zswap_init_failed) {
+		pr_err("can't set param, initialization failed\n");
+		return -ENODEV;
+	}
+
 	/* no change required */
 	if (!strcmp(s, *(char **)kp->arg))
 		return 0;
@@ -728,18 +752,22 @@
 	pool = zswap_pool_find_get(type, compressor);
 	if (pool) {
 		zswap_pool_debug("using existing", pool);
+		WARN_ON(pool == zswap_pool_current());
 		list_del_rcu(&pool->list);
-	} else {
-		spin_unlock(&zswap_pools_lock);
-		pool = zswap_pool_create(type, compressor);
-		spin_lock(&zswap_pools_lock);
 	}
 
+	spin_unlock(&zswap_pools_lock);
+
+	if (!pool)
+		pool = zswap_pool_create(type, compressor);
+
 	if (pool)
 		ret = param_set_charp(s, kp);
 	else
 		ret = -EINVAL;
 
+	spin_lock(&zswap_pools_lock);
+
 	if (!ret) {
 		put_pool = zswap_pool_current();
 		list_add_rcu(&pool->list, &zswap_pools);
@@ -775,6 +803,17 @@
 	return __zswap_param_set(val, kp, NULL, zswap_compressor);
 }
 
+static int zswap_enabled_param_set(const char *val,
+				   const struct kernel_param *kp)
+{
+	if (zswap_init_failed) {
+		pr_err("can't enable, initialization failed\n");
+		return -ENODEV;
+	}
+
+	return param_set_bool(val, kp);
+}
+
 /*********************************
 * writeback code
 **********************************/
@@ -979,6 +1018,15 @@
 			ret = -ENOMEM;
 			goto reject;
 		}
+
+		/* A second zswap_is_full() check after
+		 * zswap_shrink() to make sure it's now
+		 * under the max_pool_percent
+		 */
+		if (zswap_is_full()) {
+			ret = -ENOMEM;
+			goto reject;
+		}
 	}
 
 	/* allocate entry */
@@ -1261,6 +1309,9 @@
 dstmem_fail:
 	zswap_entry_cache_destroy();
 cache_fail:
+	/* if built-in, we aren't unloaded on failure; don't allow use */
+	zswap_init_failed = true;
+	zswap_enabled = false;
 	return -ENOMEM;
 }
 /* must be late so crypto has time to come up */
--- linux-4.4.0.orig/net/6lowpan/iphc.c
+++ linux-4.4.0/net/6lowpan/iphc.c
@@ -569,6 +569,7 @@
 		hdr.hop_limit, &hdr.daddr);
 
 	skb_push(skb, sizeof(hdr));
+	skb_reset_mac_header(skb);
 	skb_reset_network_header(skb);
 	skb_copy_to_linear_data(skb, &hdr, sizeof(hdr));
 
--- linux-4.4.0.orig/net/6lowpan/nhc.c
+++ linux-4.4.0/net/6lowpan/nhc.c
@@ -18,7 +18,7 @@
 #include "nhc.h"
 
 static struct rb_root rb_root = RB_ROOT;
-static struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX];
+static struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX + 1];
 static DEFINE_SPINLOCK(lowpan_nhc_lock);
 
 static int lowpan_nhc_insert(struct lowpan_nhc *nhc)
--- linux-4.4.0.orig/net/8021q/vlan.c
+++ linux-4.4.0/net/8021q/vlan.c
@@ -111,12 +111,7 @@
 		vlan_gvrp_uninit_applicant(real_dev);
 	}
 
-	/* Take it out of our own structures, but be sure to interlock with
-	 * HW accelerating devices or SW vlan input packet processing if
-	 * VLAN is not 0 (leave it there for 802.1p).
-	 */
-	if (vlan_id)
-		vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id);
+	vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id);
 
 	/* Get rid of the vlan's reference to real_dev */
 	dev_put(real_dev);
@@ -278,7 +273,8 @@
 	return 0;
 
 out_free_newdev:
-	free_netdev(new_dev);
+	if (new_dev->reg_state == NETREG_UNINITIALIZED)
+		free_netdev(new_dev);
 	return err;
 }
 
@@ -291,6 +287,10 @@
 	if (ether_addr_equal(vlan->real_dev_addr, dev->dev_addr))
 		return;
 
+	/* vlan continues to inherit address of lower device */
+	if (vlan_dev_inherit_address(vlandev, dev))
+		goto out;
+
 	/* vlan address was different from the old address and is equal to
 	 * the new address */
 	if (!ether_addr_equal(vlandev->dev_addr, vlan->real_dev_addr) &&
@@ -303,6 +303,7 @@
 	    !ether_addr_equal(vlandev->dev_addr, dev->dev_addr))
 		dev_uc_add(dev, vlandev->dev_addr);
 
+out:
 	ether_addr_copy(vlan->real_dev_addr, dev->dev_addr);
 }
 
@@ -370,6 +371,9 @@
 			dev->name);
 		vlan_vid_add(dev, htons(ETH_P_8021Q), 0);
 	}
+	if (event == NETDEV_DOWN &&
+	    (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
+		vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
 
 	vlan_info = rtnl_dereference(dev->vlan_info);
 	if (!vlan_info)
@@ -417,9 +421,6 @@
 		struct net_device *tmp;
 		LIST_HEAD(close_list);
 
-		if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
-			vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
-
 		/* Put all VLANs for this dev in the down state too.  */
 		vlan_group_for_each_dev(grp, i, vlandev) {
 			flgs = vlandev->flags;
@@ -659,7 +660,7 @@
 
 	skb_gro_pull(skb, sizeof(*vhdr));
 	skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
-	pp = ptype->callbacks.gro_receive(head, skb);
+	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
 
 out_unlock:
 	rcu_read_unlock();
--- linux-4.4.0.orig/net/8021q/vlan.h
+++ linux-4.4.0/net/8021q/vlan.h
@@ -109,6 +109,9 @@
 void vlan_setup(struct net_device *dev);
 int register_vlan_dev(struct net_device *dev);
 void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
+void vlan_dev_uninit(struct net_device *dev);
+bool vlan_dev_inherit_address(struct net_device *dev,
+			      struct net_device *real_dev);
 
 static inline u32 vlan_get_ingress_priority(struct net_device *dev,
 					    u16 vlan_tci)
--- linux-4.4.0.orig/net/8021q/vlan_dev.c
+++ linux-4.4.0/net/8021q/vlan_dev.c
@@ -29,6 +29,7 @@
 #include <linux/net_tstamp.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/phy.h>
 #include <net/arp.h>
 
 #include "vlan.h"
@@ -244,6 +245,17 @@
 	strncpy(result, vlan_dev_priv(dev)->real_dev->name, 23);
 }
 
+bool vlan_dev_inherit_address(struct net_device *dev,
+			      struct net_device *real_dev)
+{
+	if (dev->addr_assign_type != NET_ADDR_STOLEN)
+		return false;
+
+	ether_addr_copy(dev->dev_addr, real_dev->dev_addr);
+	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+	return true;
+}
+
 static int vlan_dev_open(struct net_device *dev)
 {
 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
@@ -254,7 +266,8 @@
 	    !(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
 		return -ENETDOWN;
 
-	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) {
+	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) &&
+	    !vlan_dev_inherit_address(dev, real_dev)) {
 		err = dev_uc_add(real_dev, dev->dev_addr);
 		if (err < 0)
 			goto out;
@@ -350,10 +363,12 @@
 	ifrr.ifr_ifru = ifr->ifr_ifru;
 
 	switch (cmd) {
+	case SIOCSHWTSTAMP:
+		if (!net_eq(dev_net(dev), &init_net))
+			break;
 	case SIOCGMIIPHY:
 	case SIOCGMIIREG:
 	case SIOCSMIIREG:
-	case SIOCSHWTSTAMP:
 	case SIOCGHWTSTAMP:
 		if (netif_device_present(real_dev) && ops->ndo_do_ioctl)
 			err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd);
@@ -544,11 +559,10 @@
 
 	dev->hw_features = NETIF_F_ALL_CSUM | NETIF_F_SG |
 			   NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE |
-			   NETIF_F_HIGHDMA | NETIF_F_SCTP_CSUM |
+			   NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC |
 			   NETIF_F_ALL_FCOE;
 
-	dev->features |= real_dev->vlan_features | NETIF_F_LLTX |
-			 NETIF_F_GSO_SOFTWARE;
+	dev->features |= dev->hw_features | NETIF_F_LLTX;
 	dev->gso_max_size = real_dev->gso_max_size;
 	if (dev->features & NETIF_F_VLAN_FEATURES)
 		netdev_warn(real_dev, "VLAN features are set incorrectly.  Q-in-Q configurations may not work correctly.\n");
@@ -558,8 +572,10 @@
 	/* ipv6 shared card related stuff */
 	dev->dev_id = real_dev->dev_id;
 
-	if (is_zero_ether_addr(dev->dev_addr))
-		eth_hw_addr_inherit(dev, real_dev);
+	if (is_zero_ether_addr(dev->dev_addr)) {
+		ether_addr_copy(dev->dev_addr, real_dev->dev_addr);
+		dev->addr_assign_type = NET_ADDR_STOLEN;
+	}
 	if (is_zero_ether_addr(dev->broadcast))
 		memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
 
@@ -590,7 +606,8 @@
 	return 0;
 }
 
-static void vlan_dev_uninit(struct net_device *dev)
+/* Note: this function might be called multiple times for the same device. */
+void vlan_dev_uninit(struct net_device *dev)
 {
 	struct vlan_priority_tci_mapping *pm;
 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
@@ -641,8 +658,11 @@
 {
 	const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
 	const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops;
+	struct phy_device *phydev = vlan->real_dev->phydev;
 
-	if (ops->get_ts_info) {
+	if (phydev && phydev->drv && phydev->drv->ts_info) {
+		 return phydev->drv->ts_info(phydev, info);
+	} else if (ops->get_ts_info) {
 		return ops->get_ts_info(vlan->real_dev, info);
 	} else {
 		info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
--- linux-4.4.0.orig/net/8021q/vlan_netlink.c
+++ linux-4.4.0/net/8021q/vlan_netlink.c
@@ -92,11 +92,13 @@
 	struct ifla_vlan_flags *flags;
 	struct ifla_vlan_qos_mapping *m;
 	struct nlattr *attr;
-	int rem;
+	int rem, err;
 
 	if (data[IFLA_VLAN_FLAGS]) {
 		flags = nla_data(data[IFLA_VLAN_FLAGS]);
-		vlan_dev_change_flags(dev, flags->flags, flags->mask);
+		err = vlan_dev_change_flags(dev, flags->flags, flags->mask);
+		if (err)
+			return err;
 	}
 	if (data[IFLA_VLAN_INGRESS_QOS]) {
 		nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
@@ -107,7 +109,9 @@
 	if (data[IFLA_VLAN_EGRESS_QOS]) {
 		nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
 			m = nla_data(attr);
-			vlan_dev_set_egress_priority(dev, m->from, m->to);
+			err = vlan_dev_set_egress_priority(dev, m->from, m->to);
+			if (err)
+				return err;
 		}
 	}
 	return 0;
@@ -150,10 +154,11 @@
 		return -EINVAL;
 
 	err = vlan_changelink(dev, tb, data);
-	if (err < 0)
-		return err;
-
-	return register_vlan_dev(dev);
+	if (!err)
+		err = register_vlan_dev(dev);
+	if (err)
+		vlan_dev_uninit(dev);
+	return err;
 }
 
 static inline size_t vlan_qos_map_size(unsigned int n)
--- linux-4.4.0.orig/net/9p/client.c
+++ linux-4.4.0/net/9p/client.c
@@ -156,6 +156,12 @@
 				ret = r;
 				continue;
 			}
+			if (option < 4096) {
+				p9_debug(P9_DEBUG_ERROR,
+					 "msize should be at least 4k\n");
+				ret = -EINVAL;
+				continue;
+			}
 			clnt->msize = option;
 			break;
 		case Opt_trans:
@@ -213,6 +219,8 @@
 		return NULL;
 	fc->capacity = alloc_msize;
 	fc->sdata = (char *) fc + sizeof(struct p9_fcall);
+	fc->id = 0;
+	fc->tag = P9_NOTAG;
 	return fc;
 }
 
@@ -749,8 +757,7 @@
 	}
 again:
 	/* Wait for the response */
-	err = wait_event_interruptible(*req->wq,
-				       req->status >= REQ_STATUS_RCVD);
+	err = wait_event_killable(*req->wq, req->status >= REQ_STATUS_RCVD);
 
 	/*
 	 * Make sure our req is coherent with regard to updates in other
@@ -932,7 +939,7 @@
 {
 	int err = 0;
 	struct p9_req_t *req;
-	char *version;
+	char *version = NULL;
 	int msize;
 
 	p9_debug(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
@@ -973,10 +980,18 @@
 	else if (!strncmp(version, "9P2000", 6))
 		c->proto_version = p9_proto_legacy;
 	else {
+		p9_debug(P9_DEBUG_ERROR,
+			 "server returned an unknown version: %s\n", version);
 		err = -EREMOTEIO;
 		goto error;
 	}
 
+	if (msize < 4096) {
+		p9_debug(P9_DEBUG_ERROR,
+			 "server returned a msize < 4096: %d\n", msize);
+		err = -EREMOTEIO;
+		goto error;
+	}
 	if (msize < c->msize)
 		c->msize = msize;
 
@@ -1041,6 +1056,13 @@
 	if (clnt->msize > clnt->trans_mod->maxsize)
 		clnt->msize = clnt->trans_mod->maxsize;
 
+	if (clnt->msize < 4096) {
+		p9_debug(P9_DEBUG_ERROR,
+			 "Please specify a msize of at least 4k\n");
+		err = -EINVAL;
+		goto close_trans;
+	}
+
 	err = p9_client_version(clnt);
 	if (err)
 		goto close_trans;
@@ -2101,6 +2123,10 @@
 		trace_9p_protocol_dump(clnt, req->rc);
 		goto free_and_error;
 	}
+	if (rsize < count) {
+		pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize);
+		count = rsize;
+	}
 
 	p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
 
--- linux-4.4.0.orig/net/9p/protocol.c
+++ linux-4.4.0/net/9p/protocol.c
@@ -46,10 +46,15 @@
 void p9stat_free(struct p9_wstat *stbuf)
 {
 	kfree(stbuf->name);
+	stbuf->name = NULL;
 	kfree(stbuf->uid);
+	stbuf->uid = NULL;
 	kfree(stbuf->gid);
+	stbuf->gid = NULL;
 	kfree(stbuf->muid);
+	stbuf->muid = NULL;
 	kfree(stbuf->extension);
+	stbuf->extension = NULL;
 }
 EXPORT_SYMBOL(p9stat_free);
 
@@ -565,9 +570,10 @@
 	if (ret) {
 		p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
 		trace_9p_protocol_dump(clnt, &fake_pdu);
+		return ret;
 	}
 
-	return ret;
+	return fake_pdu.offset;
 }
 EXPORT_SYMBOL(p9stat_read);
 
@@ -616,13 +622,19 @@
 	if (ret) {
 		p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
 		trace_9p_protocol_dump(clnt, &fake_pdu);
-		goto out;
+		return ret;
 	}
 
-	strcpy(dirent->d_name, nameptr);
+	ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
+	if (ret < 0) {
+		p9_debug(P9_DEBUG_ERROR,
+			 "On the wire dirent name too long: %s\n",
+			 nameptr);
+		kfree(nameptr);
+		return ret;
+	}
 	kfree(nameptr);
 
-out:
 	return fake_pdu.offset;
 }
 EXPORT_SYMBOL(p9dirent_read);
--- linux-4.4.0.orig/net/9p/trans_common.c
+++ linux-4.4.0/net/9p/trans_common.c
@@ -14,6 +14,7 @@
 
 #include <linux/mm.h>
 #include <linux/module.h>
+#include "trans_common.h"
 
 /**
  *  p9_release_req_pages - Release pages after the transaction.
--- linux-4.4.0.orig/net/9p/trans_fd.c
+++ linux-4.4.0/net/9p/trans_fd.c
@@ -185,6 +185,8 @@
 	spin_lock_irqsave(&p9_poll_lock, flags);
 	list_del_init(&m->poll_pending_link);
 	spin_unlock_irqrestore(&p9_poll_lock, flags);
+
+	flush_work(&p9_poll_work);
 }
 
 /**
@@ -791,20 +793,28 @@
 		return -ENOMEM;
 
 	ts->rd = fget(rfd);
+	if (!ts->rd)
+		goto out_free_ts;
+	if (!(ts->rd->f_mode & FMODE_READ))
+		goto out_put_rd;
 	ts->wr = fget(wfd);
-	if (!ts->rd || !ts->wr) {
-		if (ts->rd)
-			fput(ts->rd);
-		if (ts->wr)
-			fput(ts->wr);
-		kfree(ts);
-		return -EIO;
-	}
+	if (!ts->wr)
+		goto out_put_rd;
+	if (!(ts->wr->f_mode & FMODE_WRITE))
+		goto out_put_wr;
 
 	client->trans = ts;
 	client->status = Connected;
 
 	return 0;
+
+out_put_wr:
+	fput(ts->wr);
+out_put_rd:
+	fput(ts->rd);
+out_free_ts:
+	kfree(ts);
+	return -EIO;
 }
 
 static int p9_socket_open(struct p9_client *client, struct socket *csocket)
@@ -933,7 +943,7 @@
 	if (err < 0)
 		return err;
 
-	if (valid_ipaddr4(addr) < 0)
+	if (addr == NULL || valid_ipaddr4(addr) < 0)
 		return -EINVAL;
 
 	csocket = NULL;
@@ -981,6 +991,9 @@
 
 	csocket = NULL;
 
+	if (!addr || !strlen(addr))
+		return -EINVAL;
+
 	if (strlen(addr) >= UNIX_PATH_MAX) {
 		pr_err("%s (%d): address too long: %s\n",
 		       __func__, task_pid_nr(current), addr);
--- linux-4.4.0.orig/net/9p/trans_rdma.c
+++ linux-4.4.0/net/9p/trans_rdma.c
@@ -255,8 +255,7 @@
 	case RDMA_CM_EVENT_DISCONNECTED:
 		if (rdma)
 			rdma->state = P9_RDMA_CLOSED;
-		if (c)
-			c->status = Disconnected;
+		c->status = Disconnected;
 		break;
 
 	case RDMA_CM_EVENT_TIMEWAIT_EXIT:
@@ -476,7 +475,7 @@
 
 	err = post_recv(client, rpl_context);
 	if (err) {
-		p9_debug(P9_DEBUG_FCALL, "POST RECV failed\n");
+		p9_debug(P9_DEBUG_ERROR, "POST RECV failed: %d\n", err);
 		goto recv_error;
 	}
 	/* remove posted receive buffer from request structure */
@@ -544,7 +543,7 @@
  recv_error:
 	kfree(rpl_context);
 	spin_lock_irqsave(&rdma->req_lock, flags);
-	if (rdma->state < P9_RDMA_CLOSING) {
+	if (err != -EINTR && rdma->state < P9_RDMA_CLOSING) {
 		rdma->state = P9_RDMA_CLOSING;
 		spin_unlock_irqrestore(&rdma->req_lock, flags);
 		rdma_disconnect(rdma->cm_id);
@@ -644,6 +643,9 @@
 	struct ib_qp_init_attr qp_attr;
 	struct ib_cq_init_attr cq_attr = {};
 
+	if (addr == NULL)
+		return -EINVAL;
+
 	/* Parse the transport specific mount options */
 	err = parse_opts(args, &opts);
 	if (err < 0)
--- linux-4.4.0.orig/net/9p/trans_virtio.c
+++ linux-4.4.0/net/9p/trans_virtio.c
@@ -192,7 +192,7 @@
 		s = rest_of_page(data);
 		if (s > count)
 			s = count;
-		BUG_ON(index > limit);
+		BUG_ON(index >= limit);
 		/* Make sure we don't terminate early. */
 		sg_unmark_end(&sg[index]);
 		sg_set_buf(&sg[index++], data, s);
@@ -237,6 +237,7 @@
 		s = PAGE_SIZE - data_off;
 		if (s > count)
 			s = count;
+		BUG_ON(index >= limit);
 		/* Make sure we don't terminate early. */
 		sg_unmark_end(&sg[index]);
 		sg_set_page(&sg[index++], pdata[i++], s, data_off);
@@ -290,8 +291,8 @@
 		if (err == -ENOSPC) {
 			chan->ring_bufs_avail = 0;
 			spin_unlock_irqrestore(&chan->lock, flags);
-			err = wait_event_interruptible(*chan->vc_wq,
-							chan->ring_bufs_avail);
+			err = wait_event_killable(*chan->vc_wq,
+						  chan->ring_bufs_avail);
 			if (err  == -ERESTARTSYS)
 				return err;
 
@@ -331,7 +332,7 @@
 		 * Other zc request to finish here
 		 */
 		if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
-			err = wait_event_interruptible(vp_wq,
+			err = wait_event_killable(vp_wq,
 			      (atomic_read(&vp_pinned) < chan->p9_max_pages));
 			if (err == -ERESTARTSYS)
 				return err;
@@ -409,6 +410,7 @@
 	p9_debug(P9_DEBUG_TRANS, "virtio request\n");
 
 	if (uodata) {
+		__le32 sz;
 		int n = p9_get_mapped_pages(chan, &out_pages, uodata,
 					    outlen, &offs, &need_drop);
 		if (n < 0)
@@ -419,6 +421,12 @@
 			memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4);
 			outlen = n;
 		}
+		/* The size field of the message must include the length of the
+		 * header and the length of the data.  We didn't actually know
+		 * the length of the data until this point so add it in now.
+		 */
+		sz = cpu_to_le32(req->tc->size + outlen);
+		memcpy(&req->tc->sdata[0], &sz, sizeof(sz));
 	} else if (uidata) {
 		int n = p9_get_mapped_pages(chan, &in_pages, uidata,
 					    inlen, &offs, &need_drop);
@@ -475,8 +483,8 @@
 		if (err == -ENOSPC) {
 			chan->ring_bufs_avail = 0;
 			spin_unlock_irqrestore(&chan->lock, flags);
-			err = wait_event_interruptible(*chan->vc_wq,
-						       chan->ring_bufs_avail);
+			err = wait_event_killable(*chan->vc_wq,
+						  chan->ring_bufs_avail);
 			if (err  == -ERESTARTSYS)
 				goto err_out;
 
@@ -493,8 +501,7 @@
 	virtqueue_kick(chan->vq);
 	spin_unlock_irqrestore(&chan->lock, flags);
 	p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
-	err = wait_event_interruptible(*req->wq,
-				       req->status >= REQ_STATUS_RCVD);
+	err = wait_event_killable(*req->wq, req->status >= REQ_STATUS_RCVD);
 	/*
 	 * Non kernel buffers are pinned, unpin them
 	 */
@@ -567,7 +574,7 @@
 	chan->vq = virtio_find_single_vq(vdev, req_done, "requests");
 	if (IS_ERR(chan->vq)) {
 		err = PTR_ERR(chan->vq);
-		goto out_free_vq;
+		goto out_free_chan;
 	}
 	chan->vq->vdev->priv = chan;
 	spin_lock_init(&chan->lock);
@@ -620,6 +627,7 @@
 	kfree(tag);
 out_free_vq:
 	vdev->config->del_vqs(vdev);
+out_free_chan:
 	kfree(chan);
 fail:
 	return err;
@@ -647,6 +655,9 @@
 	int ret = -ENOENT;
 	int found = 0;
 
+	if (devname == NULL)
+		return -EINVAL;
+
 	mutex_lock(&virtio_9p_lock);
 	list_for_each_entry(chan, &virtio_chan_list, chan_list) {
 		if (!strncmp(devname, chan->tag, chan->tag_len) &&
@@ -756,10 +767,16 @@
 /* The standard init function */
 static int __init p9_virtio_init(void)
 {
+	int rc;
+
 	INIT_LIST_HEAD(&virtio_chan_list);
 
 	v9fs_register_trans(&p9_virtio_trans);
-	return register_virtio_driver(&p9_virtio_drv);
+	rc = register_virtio_driver(&p9_virtio_drv);
+	if (rc)
+		v9fs_unregister_trans(&p9_virtio_trans);
+
+	return rc;
 }
 
 static void __exit p9_virtio_cleanup(void)
--- linux-4.4.0.orig/net/Kconfig
+++ linux-4.4.0/net/Kconfig
@@ -282,8 +282,11 @@
 	  Berkeley Packet Filter filtering capabilities are normally handled
 	  by an interpreter. This option allows kernel to generate a native
 	  code when filter is loaded in memory. This should speedup
-	  packet sniffing (libpcap/tcpdump). Note : Admin should enable
-	  this feature changing /proc/sys/net/core/bpf_jit_enable
+	  packet sniffing (libpcap/tcpdump).
+
+	  Note, admin should enable this feature changing:
+	  /proc/sys/net/core/bpf_jit_enable
+	  /proc/sys/net/core/bpf_jit_harden (optional)
 
 config NET_FLOW_LIMIT
 	bool
@@ -383,8 +386,15 @@
 	  weight tunnel endpoint. Tunnel encapsulation parameters are stored
 	  with light weight tunnel state associated with fib routes.
 
+config DST_CACHE
+	bool
+	default n
+
 endif   # if NET
 
 # Used by archs to tell that they support BPF_JIT
 config HAVE_BPF_JIT
 	bool
+
+config HAVE_EBPF_JIT
+	bool
--- linux-4.4.0.orig/net/Makefile
+++ linux-4.4.0/net/Makefile
@@ -16,7 +16,7 @@
 obj-$(CONFIG_NETFILTER)		+= netfilter/
 obj-$(CONFIG_INET)		+= ipv4/
 obj-$(CONFIG_XFRM)		+= xfrm/
-obj-$(CONFIG_UNIX)		+= unix/
+obj-$(CONFIG_UNIX_SCM)		+= unix/
 obj-$(CONFIG_NET)		+= ipv6/
 obj-$(CONFIG_PACKET)		+= packet/
 obj-$(CONFIG_NET_KEY)		+= key/
--- linux-4.4.0.orig/net/appletalk/aarp.c
+++ linux-4.4.0/net/appletalk/aarp.c
@@ -41,6 +41,7 @@
 #include <linux/seq_file.h>
 #include <linux/export.h>
 #include <linux/etherdevice.h>
+#include <linux/atomic.h>
 
 int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
 int sysctl_aarp_tick_time = AARP_TICK_TIME;
@@ -50,17 +51,19 @@
 /* Lists of aarp entries */
 /**
  *	struct aarp_entry - AARP entry
- *	@last_sent - Last time we xmitted the aarp request
- *	@packet_queue - Queue of frames wait for resolution
- *	@status - Used for proxy AARP
- *	expires_at - Entry expiry time
- *	target_addr - DDP Address
- *	dev - Device to use
- *	hwaddr - Physical i/f address of target/router
- *	xmit_count - When this hits 10 we give up
- *	next - Next entry in chain
+ *	@refcnt: Reference count
+ *	@last_sent: Last time we xmitted the aarp request
+ *	@packet_queue: Queue of frames wait for resolution
+ *	@status: Used for proxy AARP
+ *	@expires_at: Entry expiry time
+ *	@target_addr: DDP Address
+ *	@dev:  Device to use
+ *	@hwaddr:  Physical i/f address of target/router
+ *	@xmit_count:  When this hits 10 we give up
+ *	@next: Next entry in chain
  */
 struct aarp_entry {
+	atomic_t		refcnt;
 	/* These first two are only used for unresolved entries */
 	unsigned long		last_sent;
 	struct sk_buff_head	packet_queue;
@@ -85,6 +88,17 @@
 /* Used to walk the list and purge/kick entries.  */
 static struct timer_list aarp_timer;
 
+static inline void aarp_entry_get(struct aarp_entry *a)
+{
+	atomic_inc(&a->refcnt);
+}
+
+static inline void aarp_entry_put(struct aarp_entry *a)
+{
+	if (atomic_dec_and_test(&a->refcnt))
+		kfree(a);
+}
+
 /*
  *	Delete an aarp queue
  *
@@ -93,7 +107,7 @@
 static void __aarp_expire(struct aarp_entry *a)
 {
 	skb_queue_purge(&a->packet_queue);
-	kfree(a);
+	aarp_entry_put(a);
 }
 
 /*
@@ -386,9 +400,11 @@
 static struct aarp_entry *aarp_alloc(void)
 {
 	struct aarp_entry *a = kmalloc(sizeof(*a), GFP_ATOMIC);
+	if (!a)
+		return NULL;
 
-	if (a)
-		skb_queue_head_init(&a->packet_queue);
+	atomic_set(&a->refcnt, 1);
+	skb_queue_head_init(&a->packet_queue);
 	return a;
 }
 
@@ -514,6 +530,7 @@
 	entry->dev = atif->dev;
 
 	write_lock_bh(&aarp_lock);
+	aarp_entry_get(entry);
 
 	hash = sa->s_node % (AARP_HASH_SIZE - 1);
 	entry->next = proxies[hash];
@@ -539,6 +556,7 @@
 		retval = 1;
 	}
 
+	aarp_entry_put(entry);
 	write_unlock_bh(&aarp_lock);
 out:
 	return retval;
@@ -879,15 +897,24 @@
 
 static unsigned char aarp_snap_id[] = { 0x00, 0x00, 0x00, 0x80, 0xF3 };
 
-void __init aarp_proto_init(void)
+int __init aarp_proto_init(void)
 {
+	int rc;
+
 	aarp_dl = register_snap_client(aarp_snap_id, aarp_rcv);
-	if (!aarp_dl)
+	if (!aarp_dl) {
 		printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
+		return -ENOMEM;
+	}
 	setup_timer(&aarp_timer, aarp_expire_timeout, 0);
 	aarp_timer.expires  = jiffies + sysctl_aarp_expiry_time;
 	add_timer(&aarp_timer);
-	register_netdevice_notifier(&aarp_notifier);
+	rc = register_netdevice_notifier(&aarp_notifier);
+	if (rc) {
+		del_timer_sync(&aarp_timer);
+		unregister_snap_client(aarp_dl);
+	}
+	return rc;
 }
 
 /* Remove the AARP entries associated with a device. */
--- linux-4.4.0.orig/net/appletalk/atalk_proc.c
+++ linux-4.4.0/net/appletalk/atalk_proc.c
@@ -293,7 +293,7 @@
 	goto out;
 }
 
-void __exit atalk_proc_exit(void)
+void atalk_proc_exit(void)
 {
 	remove_proc_entry("interface", atalk_proc_dir);
 	remove_proc_entry("route", atalk_proc_dir);
--- linux-4.4.0.orig/net/appletalk/ddp.c
+++ linux-4.4.0/net/appletalk/ddp.c
@@ -1029,6 +1029,11 @@
 	 */
 	if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
 		goto out;
+
+	rc = -EPERM;
+	if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
+		goto out;
+
 	rc = -ENOMEM;
 	sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto, kern);
 	if (!sk)
@@ -1401,9 +1406,10 @@
 
 /**
  *	atalk_rcv - Receive a packet (in skb) from device dev
- *	@skb - packet received
- *	@dev - network device where the packet comes from
- *	@pt - packet type
+ *	@skb: packet received
+ *	@dev: network device where the packet comes from
+ *	@pt: packet type
+ *	@orig_dev: the original receive net device
  *
  *	Receive a packet (in skb) from device dev. This has come from the SNAP
  *	decoder, and on entry skb->transport_header is the DDP header, skb->len
@@ -1796,15 +1802,14 @@
 		break;
 	}
 	case TIOCINQ: {
-		/*
-		 * These two are safe on a single CPU system as only
-		 * user tasks fiddle here
-		 */
-		struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
+		struct sk_buff *skb;
 		long amount = 0;
 
+		spin_lock_irq(&sk->sk_receive_queue.lock);
+		skb = skb_peek(&sk->sk_receive_queue);
 		if (skb)
 			amount = skb->len - sizeof(struct ddpehdr);
+		spin_unlock_irq(&sk->sk_receive_queue.lock);
 		rc = put_user(amount, (int __user *)argp);
 		break;
 	}
@@ -1906,31 +1911,61 @@
 EXPORT_SYMBOL(atrtr_get_dev);
 EXPORT_SYMBOL(atalk_find_dev_addr);
 
-static const char atalk_err_snap[] __initconst =
-	KERN_CRIT "Unable to register DDP with SNAP.\n";
-
 /* Called by proto.c on kernel start up */
 static int __init atalk_init(void)
 {
-	int rc = proto_register(&ddp_proto, 0);
+	int rc;
 
-	if (rc != 0)
+	rc = proto_register(&ddp_proto, 0);
+	if (rc)
 		goto out;
 
-	(void)sock_register(&atalk_family_ops);
+	rc = sock_register(&atalk_family_ops);
+	if (rc)
+		goto out_proto;
+
 	ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv);
-	if (!ddp_dl)
-		printk(atalk_err_snap);
+	if (!ddp_dl) {
+		pr_crit("Unable to register DDP with SNAP.\n");
+		rc = -ENOMEM;
+		goto out_sock;
+	}
 
 	dev_add_pack(&ltalk_packet_type);
 	dev_add_pack(&ppptalk_packet_type);
 
-	register_netdevice_notifier(&ddp_notifier);
-	aarp_proto_init();
-	atalk_proc_init();
-	atalk_register_sysctl();
+	rc = register_netdevice_notifier(&ddp_notifier);
+	if (rc)
+		goto out_snap;
+
+	rc = aarp_proto_init();
+	if (rc)
+		goto out_dev;
+
+	rc = atalk_proc_init();
+	if (rc)
+		goto out_aarp;
+
+	rc = atalk_register_sysctl();
+	if (rc)
+		goto out_proc;
 out:
 	return rc;
+out_proc:
+	atalk_proc_exit();
+out_aarp:
+	aarp_cleanup_module();
+out_dev:
+	unregister_netdevice_notifier(&ddp_notifier);
+out_snap:
+	dev_remove_pack(&ppptalk_packet_type);
+	dev_remove_pack(&ltalk_packet_type);
+	unregister_snap_client(ddp_dl);
+out_sock:
+	sock_unregister(PF_APPLETALK);
+out_proto:
+	proto_unregister(&ddp_proto);
+	goto out;
 }
 module_init(atalk_init);
 
--- linux-4.4.0.orig/net/appletalk/sysctl_net_atalk.c
+++ linux-4.4.0/net/appletalk/sysctl_net_atalk.c
@@ -44,9 +44,12 @@
 
 static struct ctl_table_header *atalk_table_header;
 
-void atalk_register_sysctl(void)
+int __init atalk_register_sysctl(void)
 {
 	atalk_table_header = register_net_sysctl(&init_net, "net/appletalk", atalk_table);
+	if (!atalk_table_header)
+		return -ENOMEM;
+	return 0;
 }
 
 void atalk_unregister_sysctl(void)
--- linux-4.4.0.orig/net/atm/ioctl.c
+++ linux-4.4.0/net/atm/ioctl.c
@@ -70,14 +70,17 @@
 	case SIOCINQ:
 	{
 		struct sk_buff *skb;
+		int amount;
 
 		if (sock->state != SS_CONNECTED) {
 			error = -EINVAL;
 			goto done;
 		}
+		spin_lock_irq(&sk->sk_receive_queue.lock);
 		skb = skb_peek(&sk->sk_receive_queue);
-		error = put_user(skb ? skb->len : 0,
-				 (int __user *)argp) ? -EFAULT : 0;
+		amount = skb ? skb->len : 0;
+		spin_unlock_irq(&sk->sk_receive_queue.lock);
+		error = put_user(amount, (int __user *)argp) ? -EFAULT : 0;
 		goto done;
 	}
 	case SIOCGSTAMP: /* borrowed from IP */
--- linux-4.4.0.orig/net/atm/lec.c
+++ linux-4.4.0/net/atm/lec.c
@@ -41,6 +41,9 @@
 #include <linux/module.h>
 #include <linux/init.h>
 
+/* Hardening for Spectre-v1 */
+#include <linux/nospec.h>
+
 #include "lec.h"
 #include "lec_arpc.h"
 #include "resources.h"
@@ -697,8 +700,10 @@
 	bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
 	if (bytes_left != 0)
 		pr_info("copy from user failed for %d bytes\n", bytes_left);
-	if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
-	    !dev_lec[ioc_data.dev_num])
+	if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF)
+		return -EINVAL;
+	ioc_data.dev_num = array_index_nospec(ioc_data.dev_num, MAX_LEC_ITF);
+	if (!dev_lec[ioc_data.dev_num])
 		return -EINVAL;
 	vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
 	if (!vpriv)
@@ -716,7 +721,10 @@
 
 static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
 {
-	if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
+	if (arg < 0 || arg >= MAX_LEC_ITF)
+		return -EINVAL;
+	arg = array_index_nospec(arg, MAX_LEC_ITF);
+	if (!dev_lec[arg])
 		return -EINVAL;
 	vcc->proto_data = dev_lec[arg];
 	return lec_mcast_make(netdev_priv(dev_lec[arg]), vcc);
@@ -734,6 +742,7 @@
 		i = arg;
 	if (arg >= MAX_LEC_ITF)
 		return -EINVAL;
+	i = array_index_nospec(arg, MAX_LEC_ITF);
 	if (!dev_lec[i]) {
 		int size;
 
@@ -1281,6 +1290,12 @@
 		entry->vcc = NULL;
 	}
 	if (entry->recv_vcc) {
+		struct atm_vcc *vcc = entry->recv_vcc;
+		struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
+
+		kfree(vpriv);
+		vcc->user_back = NULL;
+
 		entry->recv_vcc->push = entry->old_recv_push;
 		vcc_release_async(entry->recv_vcc, -EPIPE);
 		entry->recv_vcc = NULL;
--- linux-4.4.0.orig/net/ax25/af_ax25.c
+++ linux-4.4.0/net/ax25/af_ax25.c
@@ -65,12 +65,12 @@
  */
 static void ax25_cb_del(ax25_cb *ax25)
 {
+	spin_lock_bh(&ax25_list_lock);
 	if (!hlist_unhashed(&ax25->ax25_node)) {
-		spin_lock_bh(&ax25_list_lock);
 		hlist_del_init(&ax25->ax25_node);
-		spin_unlock_bh(&ax25_list_lock);
 		ax25_cb_put(ax25);
 	}
+	spin_unlock_bh(&ax25_list_lock);
 }
 
 /*
@@ -80,19 +80,38 @@
 {
 	ax25_dev *ax25_dev;
 	ax25_cb *s;
+	struct sock *sk;
 
 	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
 		return;
+	ax25_dev->device_up = false;
 
 	spin_lock_bh(&ax25_list_lock);
 again:
 	ax25_for_each(s, &ax25_list) {
 		if (s->ax25_dev == ax25_dev) {
-			s->ax25_dev = NULL;
+			sk = s->sk;
+			if (!sk) {
+				spin_unlock_bh(&ax25_list_lock);
+				ax25_disconnect(s, ENETUNREACH);
+				s->ax25_dev = NULL;
+				ax25_cb_del(s);
+				spin_lock_bh(&ax25_list_lock);
+				goto again;
+			}
+			sock_hold(sk);
 			spin_unlock_bh(&ax25_list_lock);
+			lock_sock(sk);
 			ax25_disconnect(s, ENETUNREACH);
+			s->ax25_dev = NULL;
+			if (sk->sk_socket) {
+				dev_put(ax25_dev->dev);
+				ax25_dev_put(ax25_dev);
+			}
+			ax25_cb_del(s);
+			release_sock(sk);
 			spin_lock_bh(&ax25_list_lock);
-
+			sock_put(sk);
 			/* The entry could have been deleted from the
 			 * list meanwhile and thus the next pointer is
 			 * no longer valid.  Play it safe and restart
@@ -357,21 +376,25 @@
 	if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
 		return -EFAULT;
 
-	if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
-		return -ENODEV;
-
 	if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
 		return -EINVAL;
 
 	if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
 		return -EINVAL;
 
+	ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr);
+	if (!ax25_dev)
+		return -ENODEV;
+
 	digi.ndigi = ax25_ctl.digi_count;
 	for (k = 0; k < digi.ndigi; k++)
 		digi.calls[k] = ax25_ctl.digi_addr[k];
 
-	if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL)
+	ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev);
+	if (!ax25) {
+		ax25_dev_put(ax25_dev);
 		return -ENOTCONN;
+	}
 
 	switch (ax25_ctl.cmd) {
 	case AX25_KILL:
@@ -438,6 +461,7 @@
 	  }
 
 out_put:
+	ax25_dev_put(ax25_dev);
 	ax25_cb_put(ax25);
 	return ret;
 
@@ -639,8 +663,10 @@
 		break;
 
 	case SO_BINDTODEVICE:
-		if (optlen > IFNAMSIZ)
-			optlen = IFNAMSIZ;
+		if (optlen > IFNAMSIZ - 1)
+			optlen = IFNAMSIZ - 1;
+
+		memset(devname, 0, sizeof(devname));
 
 		if (copy_from_user(devname, optval, optlen)) {
 			res = -EFAULT;
@@ -654,15 +680,22 @@
 			break;
 		}
 
-		dev = dev_get_by_name(&init_net, devname);
+		rtnl_lock();
+		dev = __dev_get_by_name(&init_net, devname);
 		if (!dev) {
+			rtnl_unlock();
 			res = -ENODEV;
 			break;
 		}
 
 		ax25->ax25_dev = ax25_dev_ax25dev(dev);
+		if (!ax25->ax25_dev) {
+			rtnl_unlock();
+			res = -ENODEV;
+			break;
+		}
 		ax25_fillin_cb(ax25, ax25->ax25_dev);
-		dev_put(dev);
+		rtnl_unlock();
 		break;
 
 	default:
@@ -852,6 +885,8 @@
 		break;
 
 	case SOCK_RAW:
+		if (!capable(CAP_NET_RAW))
+			return -EPERM;
 		break;
 	default:
 		return -ESOCKTNOSUPPORT;
@@ -952,21 +987,25 @@
 {
 	struct sock *sk = sock->sk;
 	ax25_cb *ax25;
+	ax25_dev *ax25_dev;
 
 	if (sk == NULL)
 		return 0;
 
 	sock_hold(sk);
-	sock_orphan(sk);
 	lock_sock(sk);
+	sock_orphan(sk);
 	ax25 = sk_to_ax25(sk);
+	ax25_dev = ax25->ax25_dev;
 
 	if (sk->sk_type == SOCK_SEQPACKET) {
 		switch (ax25->state) {
 		case AX25_STATE_0:
-			release_sock(sk);
-			ax25_disconnect(ax25, 0);
-			lock_sock(sk);
+			if (!sock_flag(ax25->sk, SOCK_DEAD)) {
+				release_sock(sk);
+				ax25_disconnect(ax25, 0);
+				lock_sock(sk);
+			}
 			ax25_destroy_socket(ax25);
 			break;
 
@@ -976,7 +1015,8 @@
 			release_sock(sk);
 			ax25_disconnect(ax25, 0);
 			lock_sock(sk);
-			ax25_destroy_socket(ax25);
+			if (!sock_flag(ax25->sk, SOCK_DESTROY))
+				ax25_destroy_socket(ax25);
 			break;
 
 		case AX25_STATE_3:
@@ -1020,6 +1060,17 @@
 		sk->sk_state_change(sk);
 		ax25_destroy_socket(ax25);
 	}
+	if (ax25_dev) {
+		if (!ax25_dev->device_up) {
+			del_timer_sync(&ax25->timer);
+			del_timer_sync(&ax25->t1timer);
+			del_timer_sync(&ax25->t2timer);
+			del_timer_sync(&ax25->t3timer);
+			del_timer_sync(&ax25->idletimer);
+		}
+		dev_put(ax25_dev->dev);
+		ax25_dev_put(ax25_dev);
+	}
 
 	sock->sk   = NULL;
 	release_sock(sk);
@@ -1096,8 +1147,10 @@
 		}
 	}
 
-	if (ax25_dev != NULL)
+	if (ax25_dev) {
 		ax25_fillin_cb(ax25, ax25_dev);
+		dev_hold(ax25_dev->dev);
+	}
 
 done:
 	ax25_cb_add(ax25);
@@ -1179,7 +1232,10 @@
 	if (addr_len > sizeof(struct sockaddr_ax25) &&
 	    fsa->fsa_ax25.sax25_ndigis != 0) {
 		/* Valid number of digipeaters ? */
-		if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) {
+		if (fsa->fsa_ax25.sax25_ndigis < 1 ||
+		    fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS ||
+		    addr_len < sizeof(struct sockaddr_ax25) +
+		    sizeof(ax25_address) * fsa->fsa_ax25.sax25_ndigis) {
 			err = -EINVAL;
 			goto out_release;
 		}
@@ -1323,8 +1379,10 @@
 {
 	struct sk_buff *skb;
 	struct sock *newsk;
+	ax25_dev *ax25_dev;
 	DEFINE_WAIT(wait);
 	struct sock *sk;
+	ax25_cb *ax25;
 	int err = 0;
 
 	if (sock->state != SS_UNCONNECTED)
@@ -1379,6 +1437,10 @@
 	kfree_skb(skb);
 	sk->sk_ack_backlog--;
 	newsock->state = SS_CONNECTED;
+	ax25 = sk_to_ax25(newsk);
+	ax25_dev = ax25->ax25_dev;
+	dev_hold(ax25_dev->dev);
+	ax25_dev_hold(ax25_dev);
 
 out:
 	release_sock(sk);
@@ -1498,7 +1560,10 @@
 			struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;
 
 			/* Valid number of digipeaters ? */
-			if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) {
+			if (usax->sax25_ndigis < 1 ||
+			    usax->sax25_ndigis > AX25_MAX_DIGIS ||
+			    addr_len < sizeof(struct sockaddr_ax25) +
+			    sizeof(ax25_address) * usax->sax25_ndigis) {
 				err = -EINVAL;
 				goto out;
 			}
--- linux-4.4.0.orig/net/ax25/ax25_dev.c
+++ linux-4.4.0/net/ax25/ax25_dev.c
@@ -40,6 +40,8 @@
 	for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
 		if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) {
 			res = ax25_dev;
+			ax25_dev_hold(ax25_dev);
+			break;
 		}
 	spin_unlock_bh(&ax25_dev_lock);
 
@@ -59,10 +61,12 @@
 		return;
 	}
 
+	atomic_set(&ax25_dev->refcount, 1);
 	dev->ax25_ptr     = ax25_dev;
 	ax25_dev->dev     = dev;
 	dev_hold(dev);
 	ax25_dev->forward = NULL;
+	ax25_dev->device_up = true;
 
 	ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
 	ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
@@ -116,8 +120,9 @@
 	if ((s = ax25_dev_list) == ax25_dev) {
 		ax25_dev_list = s->next;
 		spin_unlock_bh(&ax25_dev_lock);
+		dev->ax25_ptr = NULL;
 		dev_put(dev);
-		kfree(ax25_dev);
+		ax25_dev_put(ax25_dev);
 		return;
 	}
 
@@ -125,8 +130,9 @@
 		if (s->next == ax25_dev) {
 			s->next = ax25_dev->next;
 			spin_unlock_bh(&ax25_dev_lock);
+			dev->ax25_ptr = NULL;
 			dev_put(dev);
-			kfree(ax25_dev);
+			ax25_dev_put(ax25_dev);
 			return;
 		}
 
@@ -134,6 +140,7 @@
 	}
 	spin_unlock_bh(&ax25_dev_lock);
 	dev->ax25_ptr = NULL;
+	ax25_dev_put(ax25_dev);
 }
 
 int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
@@ -145,20 +152,32 @@
 
 	switch (cmd) {
 	case SIOCAX25ADDFWD:
-		if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
+		fwd_dev = ax25_addr_ax25dev(&fwd->port_to);
+		if (!fwd_dev) {
+			ax25_dev_put(ax25_dev);
 			return -EINVAL;
-		if (ax25_dev->forward != NULL)
+		}
+		if (ax25_dev->forward) {
+			ax25_dev_put(fwd_dev);
+			ax25_dev_put(ax25_dev);
 			return -EINVAL;
+		}
 		ax25_dev->forward = fwd_dev->dev;
+		ax25_dev_put(fwd_dev);
+		ax25_dev_put(ax25_dev);
 		break;
 
 	case SIOCAX25DELFWD:
-		if (ax25_dev->forward == NULL)
+		if (!ax25_dev->forward) {
+			ax25_dev_put(ax25_dev);
 			return -EINVAL;
+		}
 		ax25_dev->forward = NULL;
+		ax25_dev_put(ax25_dev);
 		break;
 
 	default:
+		ax25_dev_put(ax25_dev);
 		return -EINVAL;
 	}
 
--- linux-4.4.0.orig/net/ax25/ax25_ds_timer.c
+++ linux-4.4.0/net/ax25/ax25_ds_timer.c
@@ -102,6 +102,7 @@
 	switch (ax25->state) {
 
 	case AX25_STATE_0:
+	case AX25_STATE_2:
 		/* Magic here: If we listen() and a new link dies before it
 		   is accepted() it isn't 'dead' so doesn't get removed. */
 		if (!sk || sock_flag(sk, SOCK_DESTROY) ||
@@ -111,6 +112,7 @@
 				sock_hold(sk);
 				ax25_destroy_socket(ax25);
 				bh_unlock_sock(sk);
+				/* Ungrab socket and destroy it */
 				sock_put(sk);
 			} else
 				ax25_destroy_socket(ax25);
@@ -213,7 +215,8 @@
 	case AX25_STATE_2:
 		if (ax25->n2count == ax25->n2) {
 			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-			ax25_disconnect(ax25, ETIMEDOUT);
+			if (!sock_flag(ax25->sk, SOCK_DESTROY))
+				ax25_disconnect(ax25, ETIMEDOUT);
 			return;
 		} else {
 			ax25->n2count++;
--- linux-4.4.0.orig/net/ax25/ax25_ip.c
+++ linux-4.4.0/net/ax25/ax25_ip.c
@@ -114,6 +114,7 @@
 	dst = (ax25_address *)(bp + 1);
 	src = (ax25_address *)(bp + 8);
 
+	ax25_route_lock_use();
 	route = ax25_get_route(dst, NULL);
 	if (route) {
 		digipeat = route->digipeat;
@@ -206,9 +207,8 @@
 	ax25_queue_xmit(skb, dev);
 
 put:
-	if (route)
-		ax25_put_route(route);
 
+	ax25_route_lock_unuse();
 	return NETDEV_TX_OK;
 }
 
@@ -228,8 +228,23 @@
 }
 #endif
 
+static bool ax25_validate_header(const char *header, unsigned int len)
+{
+	ax25_digi digi;
+
+	if (!len)
+		return false;
+
+	if (header[0])
+		return true;
+
+	return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
+			       NULL);
+}
+
 const struct header_ops ax25_header_ops = {
 	.create = ax25_hard_header,
+	.validate = ax25_validate_header,
 };
 
 EXPORT_SYMBOL(ax25_header_ops);
--- linux-4.4.0.orig/net/ax25/ax25_route.c
+++ linux-4.4.0/net/ax25/ax25_route.c
@@ -40,7 +40,7 @@
 #include <linux/export.h>
 
 static ax25_route *ax25_route_list;
-static DEFINE_RWLOCK(ax25_route_lock);
+DEFINE_RWLOCK(ax25_route_lock);
 
 void ax25_rt_device_down(struct net_device *dev)
 {
@@ -78,11 +78,13 @@
 	ax25_dev *ax25_dev;
 	int i;
 
-	if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
-		return -EINVAL;
 	if (route->digi_count > AX25_MAX_DIGIS)
 		return -EINVAL;
 
+	ax25_dev = ax25_addr_ax25dev(&route->port_addr);
+	if (!ax25_dev)
+		return -EINVAL;
+
 	write_lock_bh(&ax25_route_lock);
 
 	ax25_rt = ax25_route_list;
@@ -94,6 +96,7 @@
 			if (route->digi_count != 0) {
 				if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 					write_unlock_bh(&ax25_route_lock);
+					ax25_dev_put(ax25_dev);
 					return -ENOMEM;
 				}
 				ax25_rt->digipeat->lastrepeat = -1;
@@ -104,6 +107,7 @@
 				}
 			}
 			write_unlock_bh(&ax25_route_lock);
+			ax25_dev_put(ax25_dev);
 			return 0;
 		}
 		ax25_rt = ax25_rt->next;
@@ -111,6 +115,7 @@
 
 	if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
 		write_unlock_bh(&ax25_route_lock);
+		ax25_dev_put(ax25_dev);
 		return -ENOMEM;
 	}
 
@@ -123,6 +128,7 @@
 		if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 			write_unlock_bh(&ax25_route_lock);
 			kfree(ax25_rt);
+			ax25_dev_put(ax25_dev);
 			return -ENOMEM;
 		}
 		ax25_rt->digipeat->lastrepeat = -1;
@@ -135,6 +141,7 @@
 	ax25_rt->next   = ax25_route_list;
 	ax25_route_list = ax25_rt;
 	write_unlock_bh(&ax25_route_lock);
+	ax25_dev_put(ax25_dev);
 
 	return 0;
 }
@@ -176,6 +183,7 @@
 		}
 	}
 	write_unlock_bh(&ax25_route_lock);
+	ax25_dev_put(ax25_dev);
 
 	return 0;
 }
@@ -218,6 +226,7 @@
 
 out:
 	write_unlock_bh(&ax25_route_lock);
+	ax25_dev_put(ax25_dev);
 	return err;
 }
 
@@ -349,6 +358,7 @@
  *	Find AX.25 route
  *
  *	Only routes with a reference count of zero can be destroyed.
+ *	Must be called with ax25_route_lock read locked.
  */
 ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
 {
@@ -356,7 +366,6 @@
 	ax25_route *ax25_def_rt = NULL;
 	ax25_route *ax25_rt;
 
-	read_lock(&ax25_route_lock);
 	/*
 	 *	Bind to the physical interface we heard them on, or the default
 	 *	route if none is found;
@@ -379,11 +388,6 @@
 	if (ax25_spe_rt != NULL)
 		ax25_rt = ax25_spe_rt;
 
-	if (ax25_rt != NULL)
-		ax25_hold_route(ax25_rt);
-
-	read_unlock(&ax25_route_lock);
-
 	return ax25_rt;
 }
 
@@ -414,9 +418,12 @@
 	ax25_route *ax25_rt;
 	int err = 0;
 
-	if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
+	ax25_route_lock_use();
+	ax25_rt = ax25_get_route(addr, NULL);
+	if (!ax25_rt) {
+		ax25_route_lock_unuse();
 		return -EHOSTUNREACH;
-
+	}
 	if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
 		err = -EHOSTUNREACH;
 		goto put;
@@ -445,14 +452,15 @@
 	}
 
 	if (ax25->sk != NULL) {
+		local_bh_disable();
 		bh_lock_sock(ax25->sk);
 		sock_reset_flag(ax25->sk, SOCK_ZAPPED);
 		bh_unlock_sock(ax25->sk);
+		local_bh_enable();
 	}
 
 put:
-	ax25_put_route(ax25_rt);
-
+	ax25_route_lock_unuse();
 	return err;
 }
 
--- linux-4.4.0.orig/net/ax25/ax25_std_timer.c
+++ linux-4.4.0/net/ax25/ax25_std_timer.c
@@ -38,6 +38,7 @@
 
 	switch (ax25->state) {
 	case AX25_STATE_0:
+	case AX25_STATE_2:
 		/* Magic here: If we listen() and a new link dies before it
 		   is accepted() it isn't 'dead' so doesn't get removed. */
 		if (!sk || sock_flag(sk, SOCK_DESTROY) ||
@@ -47,6 +48,7 @@
 				sock_hold(sk);
 				ax25_destroy_socket(ax25);
 				bh_unlock_sock(sk);
+				/* Ungrab socket and destroy it */
 				sock_put(sk);
 			} else
 				ax25_destroy_socket(ax25);
@@ -144,7 +146,8 @@
 	case AX25_STATE_2:
 		if (ax25->n2count == ax25->n2) {
 			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-			ax25_disconnect(ax25, ETIMEDOUT);
+			if (!sock_flag(ax25->sk, SOCK_DESTROY))
+				ax25_disconnect(ax25, ETIMEDOUT);
 			return;
 		} else {
 			ax25->n2count++;
--- linux-4.4.0.orig/net/ax25/ax25_subr.c
+++ linux-4.4.0/net/ax25/ax25_subr.c
@@ -264,11 +264,20 @@
 {
 	ax25_clear_queues(ax25);
 
-	ax25_stop_heartbeat(ax25);
-	ax25_stop_t1timer(ax25);
-	ax25_stop_t2timer(ax25);
-	ax25_stop_t3timer(ax25);
-	ax25_stop_idletimer(ax25);
+	if (reason == ENETUNREACH) {
+		del_timer_sync(&ax25->timer);
+		del_timer_sync(&ax25->t1timer);
+		del_timer_sync(&ax25->t2timer);
+		del_timer_sync(&ax25->t3timer);
+		del_timer_sync(&ax25->idletimer);
+	} else {
+		if (ax25->sk && !sock_flag(ax25->sk, SOCK_DESTROY))
+			ax25_stop_heartbeat(ax25);
+		ax25_stop_t1timer(ax25);
+		ax25_stop_t2timer(ax25);
+		ax25_stop_t3timer(ax25);
+		ax25_stop_idletimer(ax25);
+	}
 
 	ax25->state = AX25_STATE_0;
 
--- linux-4.4.0.orig/net/batman-adv/bat_iv_ogm.c
+++ linux-4.4.0/net/batman-adv/bat_iv_ogm.c
@@ -135,7 +135,7 @@
  * Returns 0 on success, a negative error code otherwise.
  */
 static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node,
-				     int max_if_num)
+				     unsigned int max_if_num)
 {
 	void *data_ptr;
 	size_t old_size;
@@ -155,10 +155,8 @@
 	orig_node->bat_iv.bcast_own = data_ptr;
 
 	data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC);
-	if (!data_ptr) {
-		kfree(orig_node->bat_iv.bcast_own);
+	if (!data_ptr)
 		goto unlock;
-	}
 
 	memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum,
 	       (max_if_num - 1) * sizeof(u8));
@@ -183,9 +181,11 @@
  * Returns 0 on success, a negative error code otherwise.
  */
 static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node,
-				     int max_if_num, int del_if_num)
+				     unsigned int max_if_num,
+				     unsigned int del_if_num)
 {
-	int chunk_size,  ret = -ENOMEM, if_offset;
+	int ret = -ENOMEM;
+	size_t chunk_size, if_offset;
 	void *data_ptr = NULL;
 
 	spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
@@ -203,8 +203,9 @@
 	memcpy(data_ptr, orig_node->bat_iv.bcast_own, del_if_num * chunk_size);
 
 	/* copy second part */
+	if_offset = (del_if_num + 1) * chunk_size;
 	memcpy((char *)data_ptr + del_if_num * chunk_size,
-	       orig_node->bat_iv.bcast_own + ((del_if_num + 1) * chunk_size),
+	       (uint8_t *)orig_node->bat_iv.bcast_own + if_offset,
 	       (max_if_num - del_if_num) * chunk_size);
 
 free_bcast_own:
@@ -252,7 +253,8 @@
 batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
 {
 	struct batadv_orig_node *orig_node;
-	int size, hash_added;
+	int hash_added;
+	size_t size;
 
 	orig_node = batadv_orig_hash_find(bat_priv, addr);
 	if (orig_node)
@@ -314,14 +316,18 @@
 	unsigned char *ogm_buff;
 	u32 random_seqno;
 
+	mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
+
 	/* randomize initial seqno to avoid collision */
 	get_random_bytes(&random_seqno, sizeof(random_seqno));
 	atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
 
 	hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN;
 	ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC);
-	if (!ogm_buff)
+	if (!ogm_buff) {
+		mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
 		return -ENOMEM;
+	}
 
 	hard_iface->bat_iv.ogm_buff = ogm_buff;
 
@@ -333,36 +339,60 @@
 	batadv_ogm_packet->reserved = 0;
 	batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE;
 
+	mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
+
 	return 0;
 }
 
 static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
 {
+	mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
+
 	kfree(hard_iface->bat_iv.ogm_buff);
 	hard_iface->bat_iv.ogm_buff = NULL;
+
+	mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
 }
 
 static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
 {
 	struct batadv_ogm_packet *batadv_ogm_packet;
-	unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
+	void *ogm_buff;
 
-	batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
+	mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
+
+	ogm_buff = hard_iface->bat_iv.ogm_buff;
+	if (!ogm_buff)
+		goto unlock;
+
+	batadv_ogm_packet = ogm_buff;
 	ether_addr_copy(batadv_ogm_packet->orig,
 			hard_iface->net_dev->dev_addr);
 	ether_addr_copy(batadv_ogm_packet->prev_sender,
 			hard_iface->net_dev->dev_addr);
+
+unlock:
+	mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
 }
 
 static void
 batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
 {
 	struct batadv_ogm_packet *batadv_ogm_packet;
-	unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
+	void *ogm_buff;
 
-	batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
+	mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
+
+	ogm_buff = hard_iface->bat_iv.ogm_buff;
+	if (!ogm_buff)
+		goto unlock;
+
+	batadv_ogm_packet = ogm_buff;
 	batadv_ogm_packet->flags = BATADV_PRIMARIES_FIRST_HOP;
 	batadv_ogm_packet->ttl = BATADV_TTL;
+
+unlock:
+	mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
 }
 
 /* when do we schedule our own ogm to be sent */
@@ -395,14 +425,19 @@
 	return new_tq;
 }
 
-/* is there another aggregated packet here? */
-static bool batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
-				      __be16 tvlv_len)
+static bool
+batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
+			  const struct batadv_ogm_packet *ogm_packet)
 {
 	int next_buff_pos = 0;
 
-	next_buff_pos += buff_pos + BATADV_OGM_HLEN;
-	next_buff_pos += ntohs(tvlv_len);
+	/* check if there is enough space for the header */
+	next_buff_pos += buff_pos + sizeof(*ogm_packet);
+	if (next_buff_pos > packet_len)
+		return false;
+
+	/* check if there is enough space for the optional TVLV */
+	next_buff_pos += ntohs(ogm_packet->tvlv_len);
 
 	return (next_buff_pos <= packet_len) &&
 	       (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
@@ -430,7 +465,7 @@
 
 	/* adjust all flags and log packets */
 	while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
-					 batadv_ogm_packet->tvlv_len)) {
+					 batadv_ogm_packet)) {
 		/* we might have aggregated direct link packets with an
 		 * ordinary base packet
 		 */
@@ -871,7 +906,7 @@
 	u32 i;
 	size_t word_index;
 	u8 *w;
-	int if_num;
+	unsigned int if_num;
 
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
@@ -892,7 +927,11 @@
 	}
 }
 
-static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
+/**
+ * batadv_iv_ogm_schedule_buff() - schedule submission of hardif ogm buffer
+ * @hard_iface: interface whose ogm buffer should be transmitted
+ */
+static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
 {
 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 	unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
@@ -903,6 +942,12 @@
 	u16 tvlv_len = 0;
 	unsigned long send_time;
 
+	lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
+
+	/* interface already disabled by batadv_iv_ogm_iface_disable */
+	if (!*ogm_buff)
+		return;
+
 	primary_if = batadv_primary_if_get_selected(bat_priv);
 
 	if (hard_iface == primary_if) {
@@ -954,6 +999,17 @@
 		batadv_hardif_free_ref(primary_if);
 }
 
+static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
+{
+	if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
+	    hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
+		return;
+
+	mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
+	batadv_iv_ogm_schedule_buff(hard_iface);
+	mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
+}
+
 /**
  * batadv_iv_ogm_orig_update - use OGM to update corresponding data in an
  *  originator
@@ -982,7 +1038,7 @@
 	struct batadv_neigh_node *tmp_neigh_node = NULL;
 	struct batadv_neigh_node *router = NULL;
 	struct batadv_orig_node *orig_node_tmp;
-	int if_num;
+	unsigned int if_num;
 	u8 sum_orig, sum_neigh;
 	u8 *neigh_addr;
 	